From 50f153036c9d9e4ae1768d5ca9c2ad4184f7a0b7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 21 Aug 2009 13:21:01 +1000 Subject: drm/radeon/kms: generate the safe register tables. Previously we just made these offline and included them, but no reason we can't generate them at build time. TODO: add rs690 + r100/r200 when done. should we do rs480/rs690 no tcl version? Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/rv515.c | 64 ++---------------------------------------- 1 file changed, 3 insertions(+), 61 deletions(-) (limited to 'drivers/gpu/drm/radeon/rv515.c') diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 31a7f668ae5a..60a194f1d9a8 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -31,6 +31,7 @@ #include "radeon.h" #include "radeon_share.h" +#include "rv515_reg_safe.h" /* rv515 depends on : */ void r100_hdp_reset(struct radeon_device *rdev); int r100_cp_reset(struct radeon_device *rdev); @@ -464,72 +465,13 @@ int rv515_debugfs_ga_info_init(struct radeon_device *rdev) #endif } - /* * Asic initialization */ -static const unsigned r500_reg_safe_bm[219] = { - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0x17FF1FFF, 0xFFFFFFFC, 0xFFFFFFFF, 0xFF30FFBF, - 0xFFFFFFF8, 0xC3E6FFFF, 0xFFFFF6DF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF03F, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFEFCE, 0xF00EBFFF, 0x007C0000, - 0xF0000038, 0xFF000009, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 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, - 0xFFFFF7FF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0x1FFFFC78, 0xFFFFE000, 0xFFFFFFFE, 0xFFFFFFFF, - 0x38CF8F50, 0xFFF88082, 0xFF0000FC, 0xFAE009FF, - 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, - 0xFFFF8CFC, 0xFFFFC1FF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF80FFFF, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x0003FC01, 0x3FFFFCF8, 0xFE800B19, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -}; - int rv515_init(struct radeon_device *rdev) { - rdev->config.r300.reg_safe_bm = r500_reg_safe_bm; - rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r500_reg_safe_bm); + rdev->config.r300.reg_safe_bm = rv515_reg_safe_bm; + rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(rv515_reg_safe_bm); return 0; } -- cgit v1.2.3-59-g8ed1b From 4ce001abafafe77e5dd943d1480fc9f87894e96f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 13 Aug 2009 16:32:14 +1000 Subject: drm/radeon/kms: add initial radeon tv-out support. This ports the tv-out code from the DDX to KMS. adds a radeon.tv module option, radeon.tv=0 to disable tv Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/Makefile | 2 +- drivers/gpu/drm/radeon/atombios.h | 11 + drivers/gpu/drm/radeon/atombios_crtc.c | 99 ++- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_atombios.c | 75 +- drivers/gpu/drm/radeon/radeon_connectors.c | 215 +++++- drivers/gpu/drm/radeon/radeon_display.c | 13 +- drivers/gpu/drm/radeon/radeon_drv.c | 4 + drivers/gpu/drm/radeon/radeon_encoders.c | 116 ++- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 44 +- drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 339 +++++++-- drivers/gpu/drm/radeon/radeon_legacy_tv.c | 904 ++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_mode.h | 50 +- drivers/gpu/drm/radeon/radeon_reg.h | 4 +- drivers/gpu/drm/radeon/rv515.c | 452 ++++++------ 15 files changed, 1941 insertions(+), 388 deletions(-) create mode 100644 drivers/gpu/drm/radeon/radeon_legacy_tv.c (limited to 'drivers/gpu/drm/radeon/rv515.c') diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 6fb842962490..c5db0c4fe788 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -47,7 +47,7 @@ radeon-$(CONFIG_DRM_RADEON_KMS) += radeon_device.o radeon_kms.o \ radeon_clocks.o radeon_fb.o radeon_gem.o radeon_ring.o radeon_irq_kms.o \ radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \ rs400.o rs600.o rs690.o rv515.o r520.o r600.o rs780.o rv770.o \ - radeon_test.o r200.o + radeon_test.o r200.o radeon_legacy_tv.o radeon-$(CONFIG_COMPAT) += radeon_ioc32.o diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index cf67928abbc8..5d402086bc47 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h @@ -2374,6 +2374,17 @@ typedef struct _ATOM_ANALOG_TV_INFO { ATOM_MODE_TIMING aModeTimings[MAX_SUPPORTED_TV_TIMING]; } ATOM_ANALOG_TV_INFO; +#define MAX_SUPPORTED_TV_TIMING_V1_2 3 + +typedef struct _ATOM_ANALOG_TV_INFO_V1_2 { + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucTV_SupportedStandard; + UCHAR ucTV_BootUpDefaultStandard; + UCHAR ucExt_TV_ASIC_ID; + UCHAR ucExt_TV_ASIC_SlaveAddr; + ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_TV_TIMING]; +} ATOM_ANALOG_TV_INFO_V1_2; + /**************************************************************************/ /* VRAM usage and their defintions */ diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 74d034f77c6b..8e31e992ec53 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -31,6 +31,10 @@ #include "atom.h" #include "atom-bits.h" +/* evil but including atombios.h is much worse */ +bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, + SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION *crtc_timing, + int32_t *pixel_clock); static void atombios_overscan_setup(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -89,17 +93,32 @@ static void atombios_scaler_setup(struct drm_crtc *crtc) struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); ENABLE_SCALER_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); + /* fixme - fill in enc_priv for atom dac */ enum radeon_tv_std tv_std = TV_STD_NTSC; + bool is_tv = false, is_cv = false; + struct drm_encoder *encoder; if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id) return; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + /* find tv std */ + if (encoder->crtc == crtc) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) { + struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; + tv_std = tv_dac->tv_std; + is_tv = true; + } + } + } + memset(&args, 0, sizeof(args)); args.ucScaler = radeon_crtc->crtc_id; - if (radeon_crtc->devices & (ATOM_DEVICE_TV_SUPPORT)) { + if (is_tv) { switch (tv_std) { case TV_STD_NTSC: default: @@ -128,7 +147,7 @@ static void atombios_scaler_setup(struct drm_crtc *crtc) break; } args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; - } else if (radeon_crtc->devices & (ATOM_DEVICE_CV_SUPPORT)) { + } else if (is_cv) { args.ucTVStandard = ATOM_TV_CV; args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; } else { @@ -151,9 +170,9 @@ static void atombios_scaler_setup(struct drm_crtc *crtc) } } atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - if (radeon_crtc->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT) - && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_RV570) { - atom_rv515_force_tv_scaler(rdev); + if ((is_tv || is_cv) + && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_R580) { + atom_rv515_force_tv_scaler(rdev, radeon_crtc); } } @@ -551,42 +570,68 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, struct radeon_device *rdev = dev->dev_private; struct drm_encoder *encoder; SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION crtc_timing; + int need_tv_timings = 0; + bool ret; /* TODO color tiling */ memset(&crtc_timing, 0, sizeof(crtc_timing)); - /* TODO tv */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - + /* find tv std */ + if (encoder->crtc == crtc) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + 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 || + tv_dac->tv_std == TV_STD_NTSC_J || + tv_dac->tv_std == TV_STD_PAL_M) + need_tv_timings = 1; + else + need_tv_timings = 2; + break; + } + } + } } crtc_timing.ucCRTC = radeon_crtc->crtc_id; - crtc_timing.usH_Total = adjusted_mode->crtc_htotal; - crtc_timing.usH_Disp = adjusted_mode->crtc_hdisplay; - crtc_timing.usH_SyncStart = adjusted_mode->crtc_hsync_start; - crtc_timing.usH_SyncWidth = - adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; + if (need_tv_timings) { + ret = radeon_atom_get_tv_timings(rdev, need_tv_timings - 1, + &crtc_timing, &adjusted_mode->clock); + if (ret == false) + need_tv_timings = 0; + } + + if (!need_tv_timings) { + crtc_timing.usH_Total = adjusted_mode->crtc_htotal; + crtc_timing.usH_Disp = adjusted_mode->crtc_hdisplay; + crtc_timing.usH_SyncStart = adjusted_mode->crtc_hsync_start; + crtc_timing.usH_SyncWidth = + adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; - crtc_timing.usV_Total = adjusted_mode->crtc_vtotal; - crtc_timing.usV_Disp = adjusted_mode->crtc_vdisplay; - crtc_timing.usV_SyncStart = adjusted_mode->crtc_vsync_start; - crtc_timing.usV_SyncWidth = - adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start; + crtc_timing.usV_Total = adjusted_mode->crtc_vtotal; + crtc_timing.usV_Disp = adjusted_mode->crtc_vdisplay; + crtc_timing.usV_SyncStart = adjusted_mode->crtc_vsync_start; + crtc_timing.usV_SyncWidth = + adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start; - if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) - crtc_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY; + if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY; - if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) - crtc_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY; + if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY; - if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC) - crtc_timing.susModeMiscInfo.usAccess |= ATOM_COMPOSITESYNC; + if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_COMPOSITESYNC; - if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) - crtc_timing.susModeMiscInfo.usAccess |= ATOM_INTERLACE; + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_INTERLACE; - if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE; + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE; + } atombios_crtc_set_pll(crtc, adjusted_mode); atombios_crtc_set_timing(crtc, &crtc_timing); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 6c35c3c29191..e47f2fc294ce 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -66,6 +66,7 @@ extern int radeon_gart_size; extern int radeon_benchmarking; extern int radeon_testing; extern int radeon_connector_table; +extern int radeon_tv; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index fcfe5c02d744..bba9b4bd8f5c 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -471,11 +471,6 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct continue; } - if (i == ATOM_DEVICE_TV1_INDEX) { - DRM_DEBUG("Skipping TV Out\n"); - continue; - } - bios_connectors[i].connector_type = supported_devices_connector_convert[ci.sucConnectorInfo. sbfAccess. @@ -858,6 +853,72 @@ radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder) return p_dac; } +bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, + SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION *crtc_timing, + int32_t *pixel_clock) +{ + struct radeon_mode_info *mode_info = &rdev->mode_info; + ATOM_ANALOG_TV_INFO *tv_info; + ATOM_ANALOG_TV_INFO_V1_2 *tv_info_v1_2; + ATOM_DTD_FORMAT *dtd_timings; + int data_index = GetIndexIntoMasterTable(DATA, AnalogTV_Info); + u8 frev, crev; + uint16_t data_offset; + + atom_parse_data_header(mode_info->atom_context, data_index, NULL, &frev, &crev, &data_offset); + + switch (crev) { + case 1: + tv_info = (ATOM_ANALOG_TV_INFO *)(mode_info->atom_context->bios + data_offset); + if (index > MAX_SUPPORTED_TV_TIMING) + return false; + + crtc_timing->usH_Total = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total); + crtc_timing->usH_Disp = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Disp); + crtc_timing->usH_SyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart); + crtc_timing->usH_SyncWidth = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncWidth); + + crtc_timing->usV_Total = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Total); + crtc_timing->usV_Disp = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Disp); + crtc_timing->usV_SyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart); + crtc_timing->usV_SyncWidth = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncWidth); + + crtc_timing->susModeMiscInfo = tv_info->aModeTimings[index].susModeMiscInfo; + + crtc_timing->ucOverscanRight = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanRight); + crtc_timing->ucOverscanLeft = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanLeft); + crtc_timing->ucOverscanBottom = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanBottom); + crtc_timing->ucOverscanTop = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanTop); + *pixel_clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10; + + if (index == 1) { + /* PAL timings appear to have wrong values for totals */ + crtc_timing->usH_Total -= 1; + crtc_timing->usV_Total -= 1; + } + break; + case 2: + tv_info_v1_2 = (ATOM_ANALOG_TV_INFO_V1_2 *)(mode_info->atom_context->bios + data_offset); + if (index > MAX_SUPPORTED_TV_TIMING_V1_2) + return false; + + dtd_timings = &tv_info_v1_2->aModeTimings[index]; + crtc_timing->usH_Total = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHBlanking_Time); + crtc_timing->usH_Disp = le16_to_cpu(dtd_timings->usHActive); + crtc_timing->usH_SyncStart = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHSyncOffset); + crtc_timing->usH_SyncWidth = le16_to_cpu(dtd_timings->usHSyncWidth); + crtc_timing->usV_Total = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVBlanking_Time); + crtc_timing->usV_Disp = le16_to_cpu(dtd_timings->usVActive); + crtc_timing->usV_SyncStart = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVSyncOffset); + crtc_timing->usV_SyncWidth = le16_to_cpu(dtd_timings->usVSyncWidth); + + crtc_timing->susModeMiscInfo.usAccess = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess); + *pixel_clock = le16_to_cpu(dtd_timings->usPixClk) * 10; + break; + } + return true; +} + struct radeon_encoder_tv_dac * radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder) { @@ -948,10 +1009,10 @@ void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev) uint32_t bios_2_scratch, bios_6_scratch; if (rdev->family >= CHIP_R600) { - bios_2_scratch = RREG32(R600_BIOS_0_SCRATCH); + bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH); bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH); } else { - bios_2_scratch = RREG32(RADEON_BIOS_0_SCRATCH); + bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH); bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH); } diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 70ede6a52d4e..6a2b0296adff 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -94,6 +94,54 @@ struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) return NULL; } + +/* + * radeon_connector_analog_encoder_conflict_solve + * - search for other connectors sharing this encoder + * if priority is true, then set them disconnected if this is connected + * if priority is false, set us disconnected if they are connected + */ +static enum drm_connector_status +radeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector, + struct drm_encoder *encoder, + enum drm_connector_status current_status, + bool priority) +{ + struct drm_device *dev = connector->dev; + struct drm_connector *conflict; + int i; + + list_for_each_entry(conflict, &dev->mode_config.connector_list, head) { + if (conflict == connector) + continue; + + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (conflict->encoder_ids[i] == 0) + break; + + /* if the IDs match */ + if (conflict->encoder_ids[i] == encoder->base.id) { + if (conflict->status != connector_status_connected) + continue; + + if (priority == true) { + DRM_INFO("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict)); + DRM_INFO("in favor of %s\n", drm_get_connector_name(connector)); + conflict->status = connector_status_disconnected; + radeon_connector_update_scratch_regs(conflict, connector_status_disconnected); + } else { + DRM_INFO("2: conflicting encoders switching off %s\n", drm_get_connector_name(connector)); + DRM_INFO("in favor of %s\n", drm_get_connector_name(conflict)); + current_status = connector_status_disconnected; + } + break; + } + } + } + return current_status; + +} + static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; @@ -213,7 +261,6 @@ static int radeon_vga_get_modes(struct drm_connector *connector) static int radeon_vga_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - return MODE_OK; } @@ -225,22 +272,22 @@ static enum drm_connector_status radeon_vga_detect(struct drm_connector *connect bool dret; enum drm_connector_status ret = connector_status_disconnected; + encoder = radeon_best_single_encoder(connector); + if (!encoder) + ret = connector_status_disconnected; + radeon_i2c_do_lock(radeon_connector, 1); dret = radeon_ddc_probe(radeon_connector); radeon_i2c_do_lock(radeon_connector, 0); if (dret) ret = connector_status_connected; else { - /* if EDID fails to a load detect */ - encoder = radeon_best_single_encoder(connector); - if (!encoder) - ret = connector_status_disconnected; - else { - encoder_funcs = encoder->helper_private; - ret = encoder_funcs->detect(encoder, connector); - } + encoder_funcs = encoder->helper_private; + ret = encoder_funcs->detect(encoder, connector); } + if (ret == connector_status_connected) + ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true); radeon_connector_update_scratch_regs(connector, ret); return ret; } @@ -259,21 +306,87 @@ struct drm_connector_funcs radeon_vga_connector_funcs = { .set_property = radeon_connector_set_property, }; +static struct drm_display_mode tv_fixed_mode = { + DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 38250, 800, 832, + 912, 1024, 0, 600, 603, 607, 624, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC), +}; + +static int radeon_tv_get_modes(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_display_mode *tv_mode; + + tv_mode = drm_mode_duplicate(dev, &tv_fixed_mode); + tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + + drm_mode_probed_add(connector, tv_mode); + + return 1; +} + +static int radeon_tv_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static enum drm_connector_status radeon_tv_detect(struct drm_connector *connector) +{ + struct drm_encoder *encoder; + struct drm_encoder_helper_funcs *encoder_funcs; + int ret; + + encoder = radeon_best_single_encoder(connector); + if (!encoder) + ret = connector_status_disconnected; + else { + encoder_funcs = encoder->helper_private; + ret = encoder_funcs->detect(encoder, connector); + } + if (ret == connector_status_connected) + ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false); + radeon_connector_update_scratch_regs(connector, ret); + return ret; +} + +struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = { + .get_modes = radeon_tv_get_modes, + .mode_valid = radeon_tv_mode_valid, + .best_encoder = radeon_best_single_encoder, +}; + +struct drm_connector_funcs radeon_tv_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .detect = radeon_tv_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = radeon_connector_destroy, + .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); - /* reset scratch regs here since radeon_dvi_detect doesn't check digital bit */ - radeon_connector_update_scratch_regs(connector, connector_status_connected); return ret; } +/* + * DVI is complicated + * Do a DDC probe, if DDC probe passes, get the full EDID so + * we can do analog/digital monitor detection at this point. + * If the monitor is an analog monitor or we got no DDC, + * we need to find the DAC encoder object for this connector. + * If we got no DDC, we do load detection on the DAC encoder object. + * If we got analog DDC or load detection passes on the DAC encoder + * we have to check if this analog encoder is shared with anyone else (TV) + * if its shared we have to set the other connector to disconnected. + */ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct drm_encoder *encoder; + struct drm_encoder *encoder = NULL; struct drm_encoder_helper_funcs *encoder_funcs; struct drm_mode_object *obj; int i; @@ -283,32 +396,58 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect radeon_i2c_do_lock(radeon_connector, 1); dret = radeon_ddc_probe(radeon_connector); radeon_i2c_do_lock(radeon_connector, 0); - if (dret) - ret = connector_status_connected; - else { - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; + if (dret) { + radeon_i2c_do_lock(radeon_connector, 1); + radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); + radeon_i2c_do_lock(radeon_connector, 0); + + if (!radeon_connector->edid) { + DRM_ERROR("DDC responded but not EDID found for %s\n", + drm_get_connector_name(connector)); + } else { + radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); + + /* if this isn't a digital monitor + then we need to make sure we don't have any + TV conflicts */ + ret = connector_status_connected; + } + } + + if ((ret == connector_status_connected) && (radeon_connector->use_digital == true)) + goto out; + + /* find analog encoder */ + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] == 0) + break; - obj = drm_mode_object_find(connector->dev, - connector->encoder_ids[i], - DRM_MODE_OBJECT_ENCODER); - if (!obj) - continue; + obj = drm_mode_object_find(connector->dev, + connector->encoder_ids[i], + DRM_MODE_OBJECT_ENCODER); + if (!obj) + continue; - encoder = obj_to_encoder(obj); + encoder = obj_to_encoder(obj); - encoder_funcs = encoder->helper_private; - if (encoder_funcs->detect) { + encoder_funcs = encoder->helper_private; + if (encoder_funcs->detect) { + if (ret != connector_status_connected) { ret = encoder_funcs->detect(encoder, connector); if (ret == connector_status_connected) { - radeon_connector->use_digital = 0; - break; + radeon_connector->use_digital = false; } } + break; } } + if ((ret == connector_status_connected) && (radeon_connector->use_digital == false) && + encoder) { + ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true); + } + +out: /* updated in get modes as well since we need to know if it's analog or digital */ radeon_connector_update_scratch_regs(connector, ret); return ret; @@ -332,7 +471,7 @@ struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector) encoder = obj_to_encoder(obj); - if (radeon_connector->use_digital) { + if (radeon_connector->use_digital == true) { if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) return encoder; } else { @@ -385,10 +524,7 @@ radeon_add_atom_connector(struct drm_device *dev, uint32_t subpixel_order = SubPixelNone; /* fixme - tv/cv/din */ - if ((connector_type == DRM_MODE_CONNECTOR_Unknown) || - (connector_type == DRM_MODE_CONNECTOR_SVIDEO) || - (connector_type == DRM_MODE_CONNECTOR_Composite) || - (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) + if (connector_type == DRM_MODE_CONNECTOR_Unknown) return; /* see if we already added it */ @@ -480,6 +616,10 @@ radeon_add_atom_connector(struct drm_device *dev, case DRM_MODE_CONNECTOR_SVIDEO: case DRM_MODE_CONNECTOR_Composite: case DRM_MODE_CONNECTOR_9PinDIN: + if (radeon_tv == 1) { + drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); + } break; case DRM_MODE_CONNECTOR_LVDS: radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); @@ -522,10 +662,7 @@ radeon_add_legacy_connector(struct drm_device *dev, uint32_t subpixel_order = SubPixelNone; /* fixme - tv/cv/din */ - if ((connector_type == DRM_MODE_CONNECTOR_Unknown) || - (connector_type == DRM_MODE_CONNECTOR_SVIDEO) || - (connector_type == DRM_MODE_CONNECTOR_Composite) || - (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) + if (connector_type == DRM_MODE_CONNECTOR_Unknown) return; /* see if we already added it */ @@ -578,6 +715,10 @@ radeon_add_legacy_connector(struct drm_device *dev, case DRM_MODE_CONNECTOR_SVIDEO: case DRM_MODE_CONNECTOR_Composite: case DRM_MODE_CONNECTOR_9PinDIN: + if (radeon_tv == 1) { + drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); + } break; case DRM_MODE_CONNECTOR_LVDS: drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index af035605d147..9d817a62e7f1 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -312,7 +312,7 @@ static void radeon_print_display_setup(struct drm_device *dev) } } -bool radeon_setup_enc_conn(struct drm_device *dev) +static bool radeon_setup_enc_conn(struct drm_device *dev) { struct radeon_device *rdev = dev->dev_private; struct drm_connector *drm_connector; @@ -346,9 +346,13 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) if (!radeon_connector->ddc_bus) return -1; - radeon_i2c_do_lock(radeon_connector, 1); - edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); - radeon_i2c_do_lock(radeon_connector, 0); + if (!radeon_connector->edid) { + radeon_i2c_do_lock(radeon_connector, 1); + edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); + radeon_i2c_do_lock(radeon_connector, 0); + } else + edid = radeon_connector->edid; + if (edid) { /* update digital bits here */ if (edid->input & DRM_EDID_INPUT_DIGITAL) @@ -677,7 +681,6 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, continue; if (first) { radeon_crtc->rmx_type = radeon_encoder->rmx_type; - radeon_crtc->devices = radeon_encoder->devices; memcpy(&radeon_crtc->native_mode, &radeon_encoder->native_mode, sizeof(struct radeon_native_mode)); diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 0bd5879a4957..133e975dbf0c 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -91,6 +91,7 @@ int radeon_gart_size = 512; /* default gart size */ int radeon_benchmarking = 0; int radeon_testing = 0; int radeon_connector_table = 0; +int radeon_tv = 1; #endif MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); @@ -123,6 +124,9 @@ module_param_named(test, radeon_testing, int, 0444); MODULE_PARM_DESC(connector_table, "Force connector table"); module_param_named(connector_table, radeon_connector_table, int, 0444); + +MODULE_PARM_DESC(tv, "TV enable (0 = disable)"); +module_param_named(tv, radeon_tv, int, 0444); #endif static int radeon_suspend(struct drm_device *dev, pm_message_t state) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 0a92706eac19..5c4ede7c9901 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -126,6 +126,23 @@ radeon_link_encoder_connector(struct drm_device *dev) } } +void radeon_encoder_set_active_device(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_connector *connector; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder == encoder) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + radeon_encoder->active_device = radeon_encoder->devices & radeon_connector->devices; + DRM_INFO("setting active device to %08x from %08x %08x for encoder %d\n", + radeon_encoder->active_device, radeon_encoder->devices, + radeon_connector->devices, encoder->encoder_type); + } + } +} + static struct drm_connector * radeon_get_connector_for_encoder(struct drm_encoder *encoder) { @@ -244,9 +261,9 @@ atombios_dac_setup(struct drm_encoder *encoder, int action) args.ucAction = action; - if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) + if (radeon_encoder->active_device & (ATOM_DEVICE_CRT_SUPPORT)) args.ucDacStandard = ATOM_DAC1_PS2; - else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) args.ucDacStandard = ATOM_DAC1_CV; else { switch (tv_std) { @@ -288,7 +305,7 @@ atombios_tv_setup(struct drm_encoder *encoder, int action) args.sTVEncoder.ucAction = action; - if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) args.sTVEncoder.ucTvStandard = ATOM_TV_CV; else { switch (tv_std) { @@ -825,10 +842,10 @@ atombios_yuv_setup(struct drm_encoder *encoder, bool enable) /* XXX: fix up scratch reg handling */ temp = RREG32(reg); - if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) WREG32(reg, (ATOM_S3_TV1_ACTIVE | (radeon_crtc->crtc_id << 18))); - else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) WREG32(reg, (ATOM_S3_CV_ACTIVE | (radeon_crtc->crtc_id << 24))); else WREG32(reg, 0); @@ -851,9 +868,19 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; int index = 0; bool is_dig = false; + int devices; memset(&args, 0, sizeof(args)); + /* on DPMS off we have no idea if active device is meaningful */ + if (mode != DRM_MODE_DPMS_ON && !radeon_encoder->active_device) + devices = radeon_encoder->devices; + else + devices = radeon_encoder->active_device; + + DRM_INFO("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n", + radeon_encoder->encoder_id, mode, radeon_encoder->devices, + radeon_encoder->active_device); switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_TMDS1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: @@ -881,18 +908,18 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) break; case ENCODER_OBJECT_ID_INTERNAL_DAC1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + if (devices & (ATOM_DEVICE_TV_SUPPORT)) index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); - else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + else if (devices & (ATOM_DEVICE_CV_SUPPORT)) index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); else index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); break; case ENCODER_OBJECT_ID_INTERNAL_DAC2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + if (devices & (ATOM_DEVICE_TV_SUPPORT)) index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); - else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + else if (devices & (ATOM_DEVICE_CV_SUPPORT)) index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); else index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); @@ -979,18 +1006,18 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) break; case ENCODER_OBJECT_ID_INTERNAL_DAC1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; - else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; else args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX; break; case ENCODER_OBJECT_ID_INTERNAL_DAC2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; - else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; else args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX; @@ -1019,17 +1046,17 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; break; case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; - else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; else args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID; break; case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; - else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; else args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID; @@ -1097,7 +1124,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, atombios_set_encoder_crtc_source(encoder); if (ASIC_IS_AVIVO(rdev)) { - if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) + if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) atombios_yuv_setup(encoder, true); else atombios_yuv_setup(encoder, false); @@ -1135,7 +1162,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, case ENCODER_OBJECT_ID_INTERNAL_DAC2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: atombios_dac_setup(encoder, ATOM_ENABLE); - if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) atombios_tv_setup(encoder, ATOM_ENABLE); break; } @@ -1143,11 +1170,12 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, } static bool -atombios_dac_load_detect(struct drm_encoder *encoder) +atombios_dac_load_detect(struct drm_encoder *encoder, struct drm_connector *connector) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_connector *radeon_connector = to_radeon_connector(connector); if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT | @@ -1168,15 +1196,15 @@ atombios_dac_load_detect(struct drm_encoder *encoder) else args.sDacload.ucDacType = ATOM_DAC_B; - if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) + if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); - else if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) + else if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); - else if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) { + else if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); if (crev >= 3) args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; - } else if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { + } else if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); if (crev >= 3) args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; @@ -1195,9 +1223,10 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_connector *radeon_connector = to_radeon_connector(connector); uint32_t bios_0_scratch; - if (!atombios_dac_load_detect(encoder)) { + if (!atombios_dac_load_detect(encoder, connector)) { DRM_DEBUG("detect returned false \n"); return connector_status_unknown; } @@ -1207,17 +1236,20 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec else bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH); - DRM_DEBUG("Bios 0 scratch %x\n", bios_0_scratch); - if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) { + DRM_DEBUG("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); + if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { if (bios_0_scratch & ATOM_S0_CRT1_MASK) return connector_status_connected; - } else if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) { + } + if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { if (bios_0_scratch & ATOM_S0_CRT2_MASK) return connector_status_connected; - } else if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) { + } + if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) return connector_status_connected; - } else if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { + } + if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) return connector_status_connected; /* CTV */ else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) @@ -1230,6 +1262,8 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) { radeon_atom_output_lock(encoder, true); radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + + radeon_encoder_set_active_device(encoder); } static void radeon_atom_encoder_commit(struct drm_encoder *encoder) @@ -1238,12 +1272,21 @@ static void radeon_atom_encoder_commit(struct drm_encoder *encoder) radeon_atom_output_lock(encoder, false); } +static void radeon_atom_encoder_disable(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + DRM_INFO("setting active device to 0 for encoder %d\n", encoder->encoder_type); + radeon_encoder->active_device = 0; +} + static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { .dpms = radeon_atom_encoder_dpms, .mode_fixup = radeon_atom_mode_fixup, .prepare = radeon_atom_encoder_prepare, .mode_set = radeon_atom_encoder_mode_set, .commit = radeon_atom_encoder_commit, + .disable = radeon_atom_encoder_disable, /* no detect for TMDS/LVDS yet */ }; @@ -1268,6 +1311,18 @@ static const struct drm_encoder_funcs radeon_atom_enc_funcs = { .destroy = radeon_enc_destroy, }; +struct radeon_encoder_atom_dac * +radeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder) +{ + struct radeon_encoder_atom_dac *dac = kzalloc(sizeof(struct radeon_encoder_atom_dac), GFP_KERNEL); + + if (!dac) + return NULL; + + dac->tv_std = TV_STD_NTSC; + return dac; +} + struct radeon_encoder_atom_dig * radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) { @@ -1336,6 +1391,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TVDAC); + radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder); drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); break; case ENCODER_OBJECT_ID_INTERNAL_DVO1: diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 0da72f18fd3a..0d29d15aa62b 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -28,6 +28,7 @@ #include #include "radeon_fixed.h" #include "radeon.h" +#include "atom.h" static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, @@ -501,6 +502,7 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_encoder *encoder; int format; int hsync_start; int hsync_wid; @@ -509,8 +511,19 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod uint32_t crtc_h_sync_strt_wid; uint32_t crtc_v_total_disp; uint32_t crtc_v_sync_strt_wid; + bool is_tv = false; DRM_DEBUG("\n"); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) { + is_tv = true; + DRM_INFO("crtc %d is connected to a TV\n", radeon_crtc->crtc_id); + break; + } + } + } switch (crtc->fb->bits_per_pixel) { case 15: /* 555 */ @@ -642,6 +655,11 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); } + if (is_tv) + radeon_legacy_tv_adjust_crtc_reg(encoder, &crtc_h_total_disp, + &crtc_h_sync_strt_wid, &crtc_v_total_disp, + &crtc_v_sync_strt_wid); + WREG32(RADEON_CRTC_H_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_h_total_disp); WREG32(RADEON_CRTC_H_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_h_sync_strt_wid); WREG32(RADEON_CRTC_V_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_v_total_disp); @@ -668,7 +686,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) uint32_t pll_ref_div = 0; uint32_t pll_fb_post_div = 0; uint32_t htotal_cntl = 0; - + bool is_tv = false; struct radeon_pll *pll; struct { @@ -703,6 +721,13 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc == crtc) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) { + is_tv = true; + break; + } + if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) { @@ -766,6 +791,12 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) ~(RADEON_PIX2CLK_SRC_SEL_MASK)) | RADEON_PIX2CLK_SRC_SEL_P2PLLCLK); + if (is_tv) { + radeon_legacy_tv_adjust_pll2(encoder, &htotal_cntl, + &pll_ref_div, &pll_fb_post_div, + &pixclks_cntl); + } + WREG32_PLL_P(RADEON_PIXCLKS_CNTL, RADEON_PIX2CLK_SRC_SEL_CPUCLK, ~(RADEON_PIX2CLK_SRC_SEL_MASK)); @@ -820,6 +851,15 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); } else { + uint32_t pixclks_cntl; + + + if (is_tv) { + pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL); + radeon_legacy_tv_adjust_pll1(encoder, &htotal_cntl, &pll_ref_div, + &pll_fb_post_div, &pixclks_cntl); + } + if (rdev->flags & RADEON_IS_MOBILITY) { /* A temporal workaround for the occational blanking on certain laptop panels. This appears to related to the PLL divider registers (fail to lock?). @@ -914,6 +954,8 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) RADEON_VCLK_SRC_SEL_PPLLCLK, ~(RADEON_VCLK_SRC_SEL_MASK)); + if (is_tv) + WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); } } diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 9322675ef6d0..0aaafcd2089f 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -29,6 +29,15 @@ #include "radeon.h" #include "atom.h" +static void radeon_legacy_encoder_disable(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder_helper_funcs *encoder_funcs; + + encoder_funcs = encoder->helper_private; + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); + radeon_encoder->active_device = 0; +} static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) { @@ -98,6 +107,8 @@ static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder) else radeon_combios_output_lock(encoder, true); radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_OFF); + + radeon_encoder_set_active_device(encoder); } static void radeon_legacy_lvds_commit(struct drm_encoder *encoder) @@ -195,6 +206,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = { .prepare = radeon_legacy_lvds_prepare, .mode_set = radeon_legacy_lvds_mode_set, .commit = radeon_legacy_lvds_commit, + .disable = radeon_legacy_encoder_disable, }; @@ -260,6 +272,7 @@ static void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder) else radeon_combios_output_lock(encoder, true); radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_OFF); + radeon_encoder_set_active_device(encoder); } static void radeon_legacy_primary_dac_commit(struct drm_encoder *encoder) @@ -402,6 +415,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_primary_dac_helper_fu .mode_set = radeon_legacy_primary_dac_mode_set, .commit = radeon_legacy_primary_dac_commit, .detect = radeon_legacy_primary_dac_detect, + .disable = radeon_legacy_encoder_disable, }; @@ -454,6 +468,7 @@ static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder) else radeon_combios_output_lock(encoder, true); radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_OFF); + radeon_encoder_set_active_device(encoder); } static void radeon_legacy_tmds_int_commit(struct drm_encoder *encoder) @@ -566,6 +581,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_tmds_int_helper_funcs .prepare = radeon_legacy_tmds_int_prepare, .mode_set = radeon_legacy_tmds_int_mode_set, .commit = radeon_legacy_tmds_int_commit, + .disable = radeon_legacy_encoder_disable, }; @@ -620,6 +636,7 @@ static void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder) else radeon_combios_output_lock(encoder, true); radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_OFF); + radeon_encoder_set_active_device(encoder); } static void radeon_legacy_tmds_ext_commit(struct drm_encoder *encoder) @@ -706,6 +723,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_tmds_ext_helper_funcs .prepare = radeon_legacy_tmds_ext_prepare, .mode_set = radeon_legacy_tmds_ext_mode_set, .commit = radeon_legacy_tmds_ext_commit, + .disable = radeon_legacy_encoder_disable, }; @@ -727,17 +745,21 @@ static void radeon_legacy_tv_dac_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); uint32_t fp2_gen_cntl = 0, crtc2_gen_cntl = 0, tv_dac_cntl = 0; - /* uint32_t tv_master_cntl = 0; */ - + uint32_t tv_master_cntl = 0; + bool is_tv; DRM_DEBUG("\n"); + is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false; + if (rdev->family == CHIP_R200) fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); else { - crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); - /* FIXME TV */ - /* tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL); */ + if (is_tv) + tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL); + else + crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); } @@ -746,20 +768,23 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) if (rdev->family == CHIP_R200) { fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); } else { - crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON; - /* tv_master_cntl |= RADEON_TV_ON; */ + if (is_tv) + tv_master_cntl |= RADEON_TV_ON; + else + crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON; + if (rdev->family == CHIP_R420 || - rdev->family == CHIP_R423 || - rdev->family == CHIP_RV410) + rdev->family == CHIP_R423 || + rdev->family == CHIP_RV410) tv_dac_cntl &= ~(R420_TV_DAC_RDACPD | - R420_TV_DAC_GDACPD | - R420_TV_DAC_BDACPD | - RADEON_TV_DAC_BGSLEEP); + R420_TV_DAC_GDACPD | + R420_TV_DAC_BDACPD | + RADEON_TV_DAC_BGSLEEP); else tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD | - RADEON_TV_DAC_GDACPD | - RADEON_TV_DAC_BDACPD | - RADEON_TV_DAC_BGSLEEP); + RADEON_TV_DAC_GDACPD | + RADEON_TV_DAC_BDACPD | + RADEON_TV_DAC_BGSLEEP); } break; case DRM_MODE_DPMS_STANDBY: @@ -768,8 +793,11 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) if (rdev->family == CHIP_R200) fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); else { - crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON; - /* tv_master_cntl &= ~RADEON_TV_ON; */ + if (is_tv) + tv_master_cntl &= ~RADEON_TV_ON; + else + crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON; + if (rdev->family == CHIP_R420 || rdev->family == CHIP_R423 || rdev->family == CHIP_RV410) @@ -789,8 +817,10 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) if (rdev->family == CHIP_R200) { WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); } else { - WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); - /* WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); */ + if (is_tv) + WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); + else + WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); } @@ -809,6 +839,7 @@ static void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder) else radeon_combios_output_lock(encoder, true); radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_OFF); + radeon_encoder_set_active_device(encoder); } static void radeon_legacy_tv_dac_commit(struct drm_encoder *encoder) @@ -831,11 +862,15 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, struct radeon_device *rdev = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; uint32_t tv_dac_cntl, gpiopad_a = 0, dac2_cntl, disp_output_cntl = 0; - uint32_t disp_hw_debug = 0, fp2_gen_cntl = 0; + uint32_t disp_hw_debug = 0, fp2_gen_cntl = 0, disp_tv_out_cntl = 0; + bool is_tv = false; DRM_DEBUG("\n"); + is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false; + if (rdev->family != CHIP_R200) { tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); if (rdev->family == CHIP_R420 || @@ -858,7 +893,7 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, } /* FIXME TV */ - if (radeon_encoder->enc_priv) { + if (tv_dac) { struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD | @@ -875,44 +910,93 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, if (ASIC_IS_R300(rdev)) { gpiopad_a = RREG32(RADEON_GPIOPAD_A) | 1; disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); - } else if (rdev->family == CHIP_R200) - fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); + } + + if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) + disp_tv_out_cntl = RREG32(RADEON_DISP_TV_OUT_CNTL); else disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); - dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC2_CLK_SEL; + if (rdev->family == CHIP_R200) + fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); - if (radeon_crtc->crtc_id == 0) { - if (ASIC_IS_R300(rdev)) { - disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; - disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC; - } else if (rdev->family == CHIP_R200) { - fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | - RADEON_FP2_DVO_RATE_SEL_SDR); - } else - disp_hw_debug |= RADEON_CRT2_DISP1_SEL; + if (is_tv) { + uint32_t dac_cntl; + + dac_cntl = RREG32(RADEON_DAC_CNTL); + dac_cntl &= ~RADEON_DAC_TVO_EN; + WREG32(RADEON_DAC_CNTL, dac_cntl); + + if (ASIC_IS_R300(rdev)) + gpiopad_a = RREG32(RADEON_GPIOPAD_A) & ~1; + + dac2_cntl = RREG32(RADEON_DAC_CNTL2) & ~RADEON_DAC2_DAC2_CLK_SEL; + if (radeon_crtc->crtc_id == 0) { + if (ASIC_IS_R300(rdev)) { + disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; + disp_output_cntl |= (RADEON_DISP_TVDAC_SOURCE_CRTC | + RADEON_DISP_TV_SOURCE_CRTC); + } + if (rdev->family >= CHIP_R200) { + disp_tv_out_cntl &= ~RADEON_DISP_TV_PATH_SRC_CRTC2; + } else { + disp_hw_debug |= RADEON_CRT2_DISP1_SEL; + } + } else { + if (ASIC_IS_R300(rdev)) { + disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; + disp_output_cntl |= RADEON_DISP_TV_SOURCE_CRTC; + } + if (rdev->family >= CHIP_R200) { + disp_tv_out_cntl |= RADEON_DISP_TV_PATH_SRC_CRTC2; + } else { + disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; + } + } + WREG32(RADEON_DAC_CNTL2, dac2_cntl); } else { - if (ASIC_IS_R300(rdev)) { - disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; - disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC2; - } else if (rdev->family == CHIP_R200) { - fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | - RADEON_FP2_DVO_RATE_SEL_SDR); - fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2; - } else - disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; - } - WREG32(RADEON_DAC_CNTL2, dac2_cntl); + dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC2_CLK_SEL; + + if (radeon_crtc->crtc_id == 0) { + if (ASIC_IS_R300(rdev)) { + disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; + disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC; + } else if (rdev->family == CHIP_R200) { + fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | + RADEON_FP2_DVO_RATE_SEL_SDR); + } else + disp_hw_debug |= RADEON_CRT2_DISP1_SEL; + } else { + if (ASIC_IS_R300(rdev)) { + disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; + disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC2; + } else if (rdev->family == CHIP_R200) { + fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | + RADEON_FP2_DVO_RATE_SEL_SDR); + fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2; + } else + disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; + } + WREG32(RADEON_DAC_CNTL2, dac2_cntl); + } if (ASIC_IS_R300(rdev)) { WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); - WREG32(RADEON_DISP_TV_OUT_CNTL, disp_output_cntl); - } else if (rdev->family == CHIP_R200) - WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); + } + + if (rdev->family >= CHIP_R200) + WREG32(RADEON_DISP_TV_OUT_CNTL, disp_tv_out_cntl); else WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); + if (rdev->family == CHIP_R200) + WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + + if (is_tv) + radeon_legacy_tv_mode_set(encoder, mode, adjusted_mode); + if (rdev->is_atom_bios) radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); else @@ -920,6 +1004,141 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, } +static bool r300_legacy_tv_detect(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl; + uint32_t disp_output_cntl, gpiopad_a, tmp; + bool found = false; + + /* save regs needed */ + gpiopad_a = RREG32(RADEON_GPIOPAD_A); + dac_cntl2 = RREG32(RADEON_DAC_CNTL2); + crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); + dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL); + tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); + disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); + + WREG32_P(RADEON_GPIOPAD_A, 0, ~1); + + WREG32(RADEON_DAC_CNTL2, RADEON_DAC2_DAC2_CLK_SEL); + + WREG32(RADEON_CRTC2_GEN_CNTL, + RADEON_CRTC2_CRT2_ON | RADEON_CRTC2_VSYNC_TRISTAT); + + tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK; + tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2; + WREG32(RADEON_DISP_OUTPUT_CNTL, tmp); + + WREG32(RADEON_DAC_EXT_CNTL, + RADEON_DAC2_FORCE_BLANK_OFF_EN | + RADEON_DAC2_FORCE_DATA_EN | + RADEON_DAC_FORCE_DATA_SEL_RGB | + (0xec << RADEON_DAC_FORCE_DATA_SHIFT)); + + WREG32(RADEON_TV_DAC_CNTL, + RADEON_TV_DAC_STD_NTSC | + (8 << RADEON_TV_DAC_BGADJ_SHIFT) | + (6 << RADEON_TV_DAC_DACADJ_SHIFT)); + + RREG32(RADEON_TV_DAC_CNTL); + mdelay(4); + + WREG32(RADEON_TV_DAC_CNTL, + RADEON_TV_DAC_NBLANK | + RADEON_TV_DAC_NHOLD | + RADEON_TV_MONITOR_DETECT_EN | + RADEON_TV_DAC_STD_NTSC | + (8 << RADEON_TV_DAC_BGADJ_SHIFT) | + (6 << RADEON_TV_DAC_DACADJ_SHIFT)); + + RREG32(RADEON_TV_DAC_CNTL); + mdelay(6); + + tmp = RREG32(RADEON_TV_DAC_CNTL); + if ((tmp & RADEON_TV_DAC_GDACDET) != 0) { + found = true; + DRM_DEBUG("S-video TV connection detected\n"); + } else if ((tmp & RADEON_TV_DAC_BDACDET) != 0) { + found = true; + DRM_DEBUG("Composite TV connection detected\n"); + } + + WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); + WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl); + WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); + WREG32(RADEON_DAC_CNTL2, dac_cntl2); + WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); + return found; +} + +static bool radeon_legacy_tv_detect(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t tv_dac_cntl, dac_cntl2; + uint32_t config_cntl, tv_pre_dac_mux_cntl, tv_master_cntl, tmp; + bool found = false; + + if (ASIC_IS_R300(rdev)) + return r300_legacy_tv_detect(encoder, connector); + + dac_cntl2 = RREG32(RADEON_DAC_CNTL2); + tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL); + tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); + config_cntl = RREG32(RADEON_CONFIG_CNTL); + tv_pre_dac_mux_cntl = RREG32(RADEON_TV_PRE_DAC_MUX_CNTL); + + tmp = dac_cntl2 & ~RADEON_DAC2_DAC2_CLK_SEL; + WREG32(RADEON_DAC_CNTL2, tmp); + + tmp = tv_master_cntl | RADEON_TV_ON; + tmp &= ~(RADEON_TV_ASYNC_RST | + RADEON_RESTART_PHASE_FIX | + RADEON_CRT_FIFO_CE_EN | + RADEON_TV_FIFO_CE_EN | + RADEON_RE_SYNC_NOW_SEL_MASK); + tmp |= RADEON_TV_FIFO_ASYNC_RST | RADEON_CRT_ASYNC_RST; + WREG32(RADEON_TV_MASTER_CNTL, tmp); + + tmp = RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD | + RADEON_TV_MONITOR_DETECT_EN | RADEON_TV_DAC_STD_NTSC | + (8 << RADEON_TV_DAC_BGADJ_SHIFT); + + if (config_cntl & RADEON_CFG_ATI_REV_ID_MASK) + tmp |= (4 << RADEON_TV_DAC_DACADJ_SHIFT); + else + tmp |= (8 << RADEON_TV_DAC_DACADJ_SHIFT); + WREG32(RADEON_TV_DAC_CNTL, tmp); + + tmp = RADEON_C_GRN_EN | RADEON_CMP_BLU_EN | + RADEON_RED_MX_FORCE_DAC_DATA | + RADEON_GRN_MX_FORCE_DAC_DATA | + RADEON_BLU_MX_FORCE_DAC_DATA | + (0x109 << RADEON_TV_FORCE_DAC_DATA_SHIFT); + WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, tmp); + + mdelay(3); + tmp = RREG32(RADEON_TV_DAC_CNTL); + if (tmp & RADEON_TV_DAC_GDACDET) { + found = true; + DRM_DEBUG("S-video TV connection detected\n"); + } else if ((tmp & RADEON_TV_DAC_BDACDET) != 0) { + found = true; + DRM_DEBUG("Composite TV connection detected\n"); + } + + WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, tv_pre_dac_mux_cntl); + WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); + WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); + WREG32(RADEON_DAC_CNTL2, dac_cntl2); + return found; +} + static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { @@ -928,9 +1147,29 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl; uint32_t disp_hw_debug, disp_output_cntl, gpiopad_a, pixclks_cntl, tmp; enum drm_connector_status found = connector_status_disconnected; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; bool color = true; - /* FIXME tv */ + if (connector->connector_type == DRM_MODE_CONNECTOR_SVIDEO || + connector->connector_type == DRM_MODE_CONNECTOR_Composite || + connector->connector_type == DRM_MODE_CONNECTOR_9PinDIN) { + bool tv_detect; + + if (radeon_encoder->active_device && !(radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT)) + return connector_status_disconnected; + + tv_detect = radeon_legacy_tv_detect(encoder, connector); + if (tv_detect && tv_dac) + found = connector_status_connected; + return found; + } + + /* don't probe if the encoder is being used for something else not CRT related */ + if (radeon_encoder->active_device && !(radeon_encoder->active_device & ATOM_DEVICE_CRT_SUPPORT)) { + DRM_INFO("not detecting due to %08x\n", radeon_encoder->active_device); + return connector_status_disconnected; + } /* save the regs we need */ pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL); @@ -1013,8 +1252,7 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder } WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); - /* return found; */ - return connector_status_disconnected; + return found; } @@ -1025,6 +1263,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_tv_dac_helper_funcs = .mode_set = radeon_legacy_tv_dac_mode_set, .commit = radeon_legacy_tv_dac_commit, .detect = radeon_legacy_tv_dac_detect, + .disable = radeon_legacy_encoder_disable, }; diff --git a/drivers/gpu/drm/radeon/radeon_legacy_tv.c b/drivers/gpu/drm/radeon/radeon_legacy_tv.c new file mode 100644 index 000000000000..3a12bb0c0563 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_legacy_tv.c @@ -0,0 +1,904 @@ +#include "drmP.h" +#include "drm_crtc_helper.h" +#include "radeon.h" + +/* + * Integrated TV out support based on the GATOS code by + * Federico Ulivi + */ + + +/* + * Limits of h/v positions (hPos & vPos) + */ +#define MAX_H_POSITION 5 /* Range: [-5..5], negative is on the left, 0 is default, positive is on the right */ +#define MAX_V_POSITION 5 /* Range: [-5..5], negative is up, 0 is default, positive is down */ + +/* + * Unit for hPos (in TV clock periods) + */ +#define H_POS_UNIT 10 + +/* + * Indexes in h. code timing table for horizontal line position adjustment + */ +#define H_TABLE_POS1 6 +#define H_TABLE_POS2 8 + +/* + * Limits of hor. size (hSize) + */ +#define MAX_H_SIZE 5 /* Range: [-5..5], negative is smaller, positive is larger */ + +/* tv standard constants */ +#define NTSC_TV_CLOCK_T 233 +#define NTSC_TV_VFTOTAL 1 +#define NTSC_TV_LINES_PER_FRAME 525 +#define NTSC_TV_ZERO_H_SIZE 479166 +#define NTSC_TV_H_SIZE_UNIT 9478 + +#define PAL_TV_CLOCK_T 188 +#define PAL_TV_VFTOTAL 3 +#define PAL_TV_LINES_PER_FRAME 625 +#define PAL_TV_ZERO_H_SIZE 473200 +#define PAL_TV_H_SIZE_UNIT 9360 + +/* tv pll setting for 27 mhz ref clk */ +#define NTSC_TV_PLL_M_27 22 +#define NTSC_TV_PLL_N_27 175 +#define NTSC_TV_PLL_P_27 5 + +#define PAL_TV_PLL_M_27 113 +#define PAL_TV_PLL_N_27 668 +#define PAL_TV_PLL_P_27 3 + +/* tv pll setting for 14 mhz ref clk */ +#define NTSC_TV_PLL_M_14 33 +#define NTSC_TV_PLL_N_14 693 +#define NTSC_TV_PLL_P_14 7 + +#define VERT_LEAD_IN_LINES 2 +#define FRAC_BITS 0xe +#define FRAC_MASK 0x3fff + +struct radeon_tv_mode_constants { + uint16_t hor_resolution; + uint16_t ver_resolution; + enum radeon_tv_std standard; + uint16_t hor_total; + uint16_t ver_total; + uint16_t hor_start; + uint16_t hor_syncstart; + uint16_t ver_syncstart; + unsigned def_restart; + uint16_t crtcPLL_N; + uint8_t crtcPLL_M; + uint8_t crtcPLL_post_div; + unsigned pix_to_tv; +}; + +static const uint16_t hor_timing_NTSC[] = { + 0x0007, + 0x003f, + 0x0263, + 0x0a24, + 0x2a6b, + 0x0a36, + 0x126d, /* H_TABLE_POS1 */ + 0x1bfe, + 0x1a8f, /* H_TABLE_POS2 */ + 0x1ec7, + 0x3863, + 0x1bfe, + 0x1bfe, + 0x1a2a, + 0x1e95, + 0x0e31, + 0x201b, + 0 +}; + +static const uint16_t vert_timing_NTSC[] = { + 0x2001, + 0x200d, + 0x1006, + 0x0c06, + 0x1006, + 0x1818, + 0x21e3, + 0x1006, + 0x0c06, + 0x1006, + 0x1817, + 0x21d4, + 0x0002, + 0 +}; + +static const uint16_t hor_timing_PAL[] = { + 0x0007, + 0x0058, + 0x027c, + 0x0a31, + 0x2a77, + 0x0a95, + 0x124f, /* H_TABLE_POS1 */ + 0x1bfe, + 0x1b22, /* H_TABLE_POS2 */ + 0x1ef9, + 0x387c, + 0x1bfe, + 0x1bfe, + 0x1b31, + 0x1eb5, + 0x0e43, + 0x201b, + 0 +}; + +static const uint16_t vert_timing_PAL[] = { + 0x2001, + 0x200c, + 0x1005, + 0x0c05, + 0x1005, + 0x1401, + 0x1821, + 0x2240, + 0x1005, + 0x0c05, + 0x1005, + 0x1401, + 0x1822, + 0x2230, + 0x0002, + 0 +}; + +/********************************************************************** + * + * availableModes + * + * Table of all allowed modes for tv output + * + **********************************************************************/ +static const struct radeon_tv_mode_constants available_tv_modes[] = { + { /* NTSC timing for 27 Mhz ref clk */ + 800, /* horResolution */ + 600, /* verResolution */ + TV_STD_NTSC, /* standard */ + 990, /* horTotal */ + 740, /* verTotal */ + 813, /* horStart */ + 824, /* horSyncStart */ + 632, /* verSyncStart */ + 625592, /* defRestart */ + 592, /* crtcPLL_N */ + 91, /* crtcPLL_M */ + 4, /* crtcPLL_postDiv */ + 1022, /* pixToTV */ + }, + { /* PAL timing for 27 Mhz ref clk */ + 800, /* horResolution */ + 600, /* verResolution */ + TV_STD_PAL, /* standard */ + 1144, /* horTotal */ + 706, /* verTotal */ + 812, /* horStart */ + 824, /* horSyncStart */ + 669, /* verSyncStart */ + 696700, /* defRestart */ + 1382, /* crtcPLL_N */ + 231, /* crtcPLL_M */ + 4, /* crtcPLL_postDiv */ + 759, /* pixToTV */ + }, + { /* NTSC timing for 14 Mhz ref clk */ + 800, /* horResolution */ + 600, /* verResolution */ + TV_STD_NTSC, /* standard */ + 1018, /* horTotal */ + 727, /* verTotal */ + 813, /* horStart */ + 840, /* horSyncStart */ + 633, /* verSyncStart */ + 630627, /* defRestart */ + 347, /* crtcPLL_N */ + 14, /* crtcPLL_M */ + 8, /* crtcPLL_postDiv */ + 1022, /* pixToTV */ + }, +}; + +#define N_AVAILABLE_MODES ARRAY_SIZE(available_tv_modes) + +static const struct radeon_tv_mode_constants *radeon_legacy_tv_get_std_mode(struct radeon_encoder *radeon_encoder, + uint16_t *pll_ref_freq) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc; + struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; + const struct radeon_tv_mode_constants *const_ptr; + struct radeon_pll *pll; + + radeon_crtc = to_radeon_crtc(radeon_encoder->base.crtc); + if (radeon_crtc->crtc_id == 1) + pll = &rdev->clock.p2pll; + else + pll = &rdev->clock.p1pll; + + if (pll_ref_freq) + *pll_ref_freq = pll->reference_freq; + + if (tv_dac->tv_std == TV_STD_NTSC || + tv_dac->tv_std == TV_STD_NTSC_J || + tv_dac->tv_std == TV_STD_PAL_M) { + if (pll->reference_freq == 2700) + const_ptr = &available_tv_modes[0]; + else + const_ptr = &available_tv_modes[2]; + } else { + if (pll->reference_freq == 2700) + const_ptr = &available_tv_modes[1]; + else + const_ptr = &available_tv_modes[1]; /* FIX ME */ + } + return const_ptr; +} + +static long YCOEF_value[5] = { 2, 2, 0, 4, 0 }; +static long YCOEF_EN_value[5] = { 1, 1, 0, 1, 0 }; +static long SLOPE_value[5] = { 1, 2, 2, 4, 8 }; +static long SLOPE_limit[5] = { 6, 5, 4, 3, 2 }; + +static void radeon_wait_pll_lock(struct drm_encoder *encoder, unsigned n_tests, + unsigned n_wait_loops, unsigned cnt_threshold) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t save_pll_test; + unsigned int i, j; + + WREG32(RADEON_TEST_DEBUG_MUX, (RREG32(RADEON_TEST_DEBUG_MUX) & 0xffff60ff) | 0x100); + save_pll_test = RREG32_PLL(RADEON_PLL_TEST_CNTL); + WREG32_PLL(RADEON_PLL_TEST_CNTL, save_pll_test & ~RADEON_PLL_MASK_READ_B); + + WREG8(RADEON_CLOCK_CNTL_INDEX, RADEON_PLL_TEST_CNTL); + for (i = 0; i < n_tests; i++) { + WREG8(RADEON_CLOCK_CNTL_DATA + 3, 0); + for (j = 0; j < n_wait_loops; j++) + if (RREG8(RADEON_CLOCK_CNTL_DATA + 3) >= cnt_threshold) + break; + } + WREG32_PLL(RADEON_PLL_TEST_CNTL, save_pll_test); + WREG32(RADEON_TEST_DEBUG_MUX, RREG32(RADEON_TEST_DEBUG_MUX) & 0xffffe0ff); +} + + +static void radeon_legacy_tv_write_fifo(struct radeon_encoder *radeon_encoder, + uint16_t addr, uint32_t value) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t tmp; + int i = 0; + + WREG32(RADEON_TV_HOST_WRITE_DATA, value); + + WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr); + WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_WT); + + do { + tmp = RREG32(RADEON_TV_HOST_RD_WT_CNTL); + if ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0) + break; + i++; + } while (i < 10000); + WREG32(RADEON_TV_HOST_RD_WT_CNTL, 0); +} + +#if 0 /* included for completeness */ +static uint32_t radeon_legacy_tv_read_fifo(struct radeon_encoder *radeon_encoder, uint16_t addr) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t tmp; + int i = 0; + + WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr); + WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_RD); + + do { + tmp = RREG32(RADEON_TV_HOST_RD_WT_CNTL); + if ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0) + break; + i++; + } while (i < 10000); + WREG32(RADEON_TV_HOST_RD_WT_CNTL, 0); + return RREG32(RADEON_TV_HOST_READ_DATA); +} +#endif + +static uint16_t radeon_get_htiming_tables_addr(uint32_t tv_uv_adr) +{ + uint16_t h_table; + + switch ((tv_uv_adr & RADEON_HCODE_TABLE_SEL_MASK) >> RADEON_HCODE_TABLE_SEL_SHIFT) { + case 0: + h_table = RADEON_TV_MAX_FIFO_ADDR_INTERNAL; + break; + case 1: + h_table = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2; + break; + case 2: + h_table = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2; + break; + default: + h_table = 0; + break; + } + return h_table; +} + +static uint16_t radeon_get_vtiming_tables_addr(uint32_t tv_uv_adr) +{ + uint16_t v_table; + + switch ((tv_uv_adr & RADEON_VCODE_TABLE_SEL_MASK) >> RADEON_VCODE_TABLE_SEL_SHIFT) { + case 0: + v_table = ((tv_uv_adr & RADEON_MAX_UV_ADR_MASK) >> RADEON_MAX_UV_ADR_SHIFT) * 2 + 1; + break; + case 1: + v_table = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2 + 1; + break; + case 2: + v_table = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2 + 1; + break; + default: + v_table = 0; + break; + } + return v_table; +} + +static void radeon_restore_tv_timing_tables(struct radeon_encoder *radeon_encoder) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; + uint16_t h_table, v_table; + uint32_t tmp; + int i; + + WREG32(RADEON_TV_UV_ADR, tv_dac->tv.tv_uv_adr); + h_table = radeon_get_htiming_tables_addr(tv_dac->tv.tv_uv_adr); + v_table = radeon_get_vtiming_tables_addr(tv_dac->tv.tv_uv_adr); + + for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2, h_table--) { + tmp = ((uint32_t)tv_dac->tv.h_code_timing[i] << 14) | ((uint32_t)tv_dac->tv.h_code_timing[i+1]); + radeon_legacy_tv_write_fifo(radeon_encoder, h_table, tmp); + if (tv_dac->tv.h_code_timing[i] == 0 || tv_dac->tv.h_code_timing[i + 1] == 0) + break; + } + for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2, v_table++) { + tmp = ((uint32_t)tv_dac->tv.v_code_timing[i+1] << 14) | ((uint32_t)tv_dac->tv.v_code_timing[i]); + radeon_legacy_tv_write_fifo(radeon_encoder, v_table, tmp); + if (tv_dac->tv.v_code_timing[i] == 0 || tv_dac->tv.v_code_timing[i + 1] == 0) + break; + } +} + +static void radeon_legacy_write_tv_restarts(struct radeon_encoder *radeon_encoder) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; + WREG32(RADEON_TV_FRESTART, tv_dac->tv.frestart); + WREG32(RADEON_TV_HRESTART, tv_dac->tv.hrestart); + WREG32(RADEON_TV_VRESTART, tv_dac->tv.vrestart); +} + +static bool radeon_legacy_tv_init_restarts(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_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; + struct radeon_crtc *radeon_crtc; + int restart; + unsigned int h_total, v_total, f_total; + int v_offset, h_offset; + u16 p1, p2, h_inc; + bool h_changed; + const struct radeon_tv_mode_constants *const_ptr; + struct radeon_pll *pll; + + radeon_crtc = to_radeon_crtc(radeon_encoder->base.crtc); + if (radeon_crtc->crtc_id == 1) + pll = &rdev->clock.p2pll; + else + pll = &rdev->clock.p1pll; + + const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL); + if (!const_ptr) + return false; + + h_total = const_ptr->hor_total; + v_total = const_ptr->ver_total; + + if (tv_dac->tv_std == TV_STD_NTSC || + tv_dac->tv_std == TV_STD_NTSC_J || + tv_dac->tv_std == TV_STD_PAL_M || + tv_dac->tv_std == TV_STD_PAL_60) + f_total = NTSC_TV_VFTOTAL + 1; + else + f_total = PAL_TV_VFTOTAL + 1; + + /* adjust positions 1&2 in hor. cod timing table */ + h_offset = tv_dac->h_pos * H_POS_UNIT; + + if (tv_dac->tv_std == TV_STD_NTSC || + tv_dac->tv_std == TV_STD_NTSC_J || + tv_dac->tv_std == TV_STD_PAL_M) { + h_offset -= 50; + p1 = hor_timing_NTSC[H_TABLE_POS1]; + p2 = hor_timing_NTSC[H_TABLE_POS2]; + } else { + p1 = hor_timing_PAL[H_TABLE_POS1]; + p2 = hor_timing_PAL[H_TABLE_POS2]; + } + + p1 = (u16)((int)p1 + h_offset); + p2 = (u16)((int)p2 - h_offset); + + h_changed = (p1 != tv_dac->tv.h_code_timing[H_TABLE_POS1] || + p2 != tv_dac->tv.h_code_timing[H_TABLE_POS2]); + + tv_dac->tv.h_code_timing[H_TABLE_POS1] = p1; + tv_dac->tv.h_code_timing[H_TABLE_POS2] = p2; + + /* Convert hOffset from n. of TV clock periods to n. of CRTC clock periods (CRTC pixels) */ + h_offset = (h_offset * (int)(const_ptr->pix_to_tv)) / 1000; + + /* adjust restart */ + restart = const_ptr->def_restart; + + /* + * convert v_pos TV lines to n. of CRTC pixels + */ + if (tv_dac->tv_std == TV_STD_NTSC || + tv_dac->tv_std == TV_STD_NTSC_J || + tv_dac->tv_std == TV_STD_PAL_M || + tv_dac->tv_std == TV_STD_PAL_60) + v_offset = ((int)(v_total * h_total) * 2 * tv_dac->v_pos) / (int)(NTSC_TV_LINES_PER_FRAME); + else + v_offset = ((int)(v_total * h_total) * 2 * tv_dac->v_pos) / (int)(PAL_TV_LINES_PER_FRAME); + + restart -= v_offset + h_offset; + + DRM_DEBUG("compute_restarts: def = %u h = %d v = %d, p1 = %04x, p2 = %04x, restart = %d\n", + const_ptr->def_restart, tv_dac->h_pos, tv_dac->v_pos, p1, p2, restart); + + tv_dac->tv.hrestart = restart % h_total; + restart /= h_total; + tv_dac->tv.vrestart = restart % v_total; + restart /= v_total; + tv_dac->tv.frestart = restart % f_total; + + DRM_DEBUG("compute_restart: F/H/V=%u,%u,%u\n", + (unsigned)tv_dac->tv.frestart, + (unsigned)tv_dac->tv.vrestart, + (unsigned)tv_dac->tv.hrestart); + + /* compute h_inc from hsize */ + if (tv_dac->tv_std == TV_STD_NTSC || + tv_dac->tv_std == TV_STD_NTSC_J || + tv_dac->tv_std == TV_STD_PAL_M) + h_inc = (u16)((int)(const_ptr->hor_resolution * 4096 * NTSC_TV_CLOCK_T) / + (tv_dac->h_size * (int)(NTSC_TV_H_SIZE_UNIT) + (int)(NTSC_TV_ZERO_H_SIZE))); + else + h_inc = (u16)((int)(const_ptr->hor_resolution * 4096 * PAL_TV_CLOCK_T) / + (tv_dac->h_size * (int)(PAL_TV_H_SIZE_UNIT) + (int)(PAL_TV_ZERO_H_SIZE))); + + tv_dac->tv.timing_cntl = (tv_dac->tv.timing_cntl & ~RADEON_H_INC_MASK) | + ((u32)h_inc << RADEON_H_INC_SHIFT); + + DRM_DEBUG("compute_restart: h_size = %d h_inc = %d\n", tv_dac->h_size, h_inc); + + return h_changed; +} + +void radeon_legacy_tv_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_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_tv_dac *tv_dac = radeon_encoder->enc_priv; + const struct radeon_tv_mode_constants *const_ptr; + struct radeon_crtc *radeon_crtc; + int i; + uint16_t pll_ref_freq; + uint32_t vert_space, flicker_removal, tmp; + uint32_t tv_master_cntl, tv_rgb_cntl, tv_dac_cntl; + uint32_t tv_modulator_cntl1, tv_modulator_cntl2; + uint32_t tv_vscaler_cntl1, tv_vscaler_cntl2; + uint32_t tv_pll_cntl, tv_pll_cntl1, tv_ftotal; + uint32_t tv_y_fall_cntl, tv_y_rise_cntl, tv_y_saw_tooth_cntl; + uint32_t m, n, p; + const uint16_t *hor_timing; + const uint16_t *vert_timing; + + const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, &pll_ref_freq); + if (!const_ptr) + return; + + radeon_crtc = to_radeon_crtc(encoder->crtc); + + tv_master_cntl = (RADEON_VIN_ASYNC_RST | + RADEON_CRT_FIFO_CE_EN | + RADEON_TV_FIFO_CE_EN | + RADEON_TV_ON); + + if (!ASIC_IS_R300(rdev)) + tv_master_cntl |= RADEON_TVCLK_ALWAYS_ONb; + + if (tv_dac->tv_std == TV_STD_NTSC || + tv_dac->tv_std == TV_STD_NTSC_J) + tv_master_cntl |= RADEON_RESTART_PHASE_FIX; + + tv_modulator_cntl1 = (RADEON_SLEW_RATE_LIMIT | + RADEON_SYNC_TIP_LEVEL | + RADEON_YFLT_EN | + RADEON_UVFLT_EN | + (6 << RADEON_CY_FILT_BLEND_SHIFT)); + + if (tv_dac->tv_std == TV_STD_NTSC || + tv_dac->tv_std == TV_STD_NTSC_J) { + tv_modulator_cntl1 |= (0x46 << RADEON_SET_UP_LEVEL_SHIFT) | + (0x3b << RADEON_BLANK_LEVEL_SHIFT); + tv_modulator_cntl2 = (-111 & RADEON_TV_U_BURST_LEVEL_MASK) | + ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); + } else if (tv_dac->tv_std == TV_STD_SCART_PAL) { + tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN; + tv_modulator_cntl2 = (0 & RADEON_TV_U_BURST_LEVEL_MASK) | + ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); + } else { + tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN | + (0x3b << RADEON_SET_UP_LEVEL_SHIFT) | + (0x3b << RADEON_BLANK_LEVEL_SHIFT); + tv_modulator_cntl2 = (-78 & RADEON_TV_U_BURST_LEVEL_MASK) | + ((62 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); + } + + + tv_rgb_cntl = (RADEON_RGB_DITHER_EN + | RADEON_TVOUT_SCALE_EN + | (0x0b << RADEON_UVRAM_READ_MARGIN_SHIFT) + | (0x07 << RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT) + | RADEON_RGB_ATTEN_SEL(0x3) + | RADEON_RGB_ATTEN_VAL(0xc)); + + if (radeon_crtc->crtc_id == 1) + tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC2; + else { + if (radeon_crtc->rmx_type != RMX_OFF) + tv_rgb_cntl |= RADEON_RGB_SRC_SEL_RMX; + else + tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC1; + } + + if (tv_dac->tv_std == TV_STD_NTSC || + tv_dac->tv_std == TV_STD_NTSC_J || + tv_dac->tv_std == TV_STD_PAL_M || + tv_dac->tv_std == TV_STD_PAL_60) + vert_space = const_ptr->ver_total * 2 * 10000 / NTSC_TV_LINES_PER_FRAME; + else + vert_space = const_ptr->ver_total * 2 * 10000 / PAL_TV_LINES_PER_FRAME; + + tmp = RREG32(RADEON_TV_VSCALER_CNTL1); + tmp &= 0xe3ff0000; + tmp |= (vert_space * (1 << FRAC_BITS) / 10000); + tv_vscaler_cntl1 = tmp; + + if (pll_ref_freq == 2700) + tv_vscaler_cntl1 |= RADEON_RESTART_FIELD; + + if (const_ptr->hor_resolution == 1024) + tv_vscaler_cntl1 |= (4 << RADEON_Y_DEL_W_SIG_SHIFT); + else + tv_vscaler_cntl1 |= (2 << RADEON_Y_DEL_W_SIG_SHIFT); + + /* scale up for int divide */ + tmp = const_ptr->ver_total * 2 * 1000; + if (tv_dac->tv_std == TV_STD_NTSC || + tv_dac->tv_std == TV_STD_NTSC_J || + tv_dac->tv_std == TV_STD_PAL_M || + tv_dac->tv_std == TV_STD_PAL_60) { + tmp /= NTSC_TV_LINES_PER_FRAME; + } else { + tmp /= PAL_TV_LINES_PER_FRAME; + } + flicker_removal = (tmp + 500) / 1000; + + if (flicker_removal < 3) + flicker_removal = 3; + for (i = 0; i < 6; ++i) { + if (flicker_removal == SLOPE_limit[i]) + break; + } + + tv_y_saw_tooth_cntl = (vert_space * SLOPE_value[i] * (1 << (FRAC_BITS - 1)) + + 5001) / 10000 / 8 | ((SLOPE_value[i] * + (1 << (FRAC_BITS - 1)) / 8) << 16); + tv_y_fall_cntl = + (YCOEF_EN_value[i] << 17) | ((YCOEF_value[i] * (1 << 8) / 8) << 24) | + RADEON_Y_FALL_PING_PONG | (272 * SLOPE_value[i] / 8) * (1 << (FRAC_BITS - 1)) / + 1024; + tv_y_rise_cntl = RADEON_Y_RISE_PING_PONG| + (flicker_removal * 1024 - 272) * SLOPE_value[i] / 8 * (1 << (FRAC_BITS - 1)) / 1024; + + tv_vscaler_cntl2 = RREG32(RADEON_TV_VSCALER_CNTL2) & 0x00fffff0; + tv_vscaler_cntl2 |= (0x10 << 24) | + RADEON_DITHER_MODE | + RADEON_Y_OUTPUT_DITHER_EN | + RADEON_UV_OUTPUT_DITHER_EN | + RADEON_UV_TO_BUF_DITHER_EN; + + tmp = (tv_vscaler_cntl1 >> RADEON_UV_INC_SHIFT) & RADEON_UV_INC_MASK; + tmp = ((16384 * 256 * 10) / tmp + 5) / 10; + tmp = (tmp << RADEON_UV_OUTPUT_POST_SCALE_SHIFT) | 0x000b0000; + tv_dac->tv.timing_cntl = tmp; + + if (tv_dac->tv_std == TV_STD_NTSC || + tv_dac->tv_std == TV_STD_NTSC_J || + tv_dac->tv_std == TV_STD_PAL_M || + tv_dac->tv_std == TV_STD_PAL_60) + tv_dac_cntl = tv_dac->ntsc_tvdac_adj; + else + tv_dac_cntl = tv_dac->pal_tvdac_adj; + + tv_dac_cntl |= RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD; + + if (tv_dac->tv_std == TV_STD_NTSC || + tv_dac->tv_std == TV_STD_NTSC_J) + tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC; + else + tv_dac_cntl |= RADEON_TV_DAC_STD_PAL; + + if (tv_dac->tv_std == TV_STD_NTSC || + tv_dac->tv_std == TV_STD_NTSC_J) { + if (pll_ref_freq == 2700) { + m = NTSC_TV_PLL_M_27; + n = NTSC_TV_PLL_N_27; + p = NTSC_TV_PLL_P_27; + } else { + m = NTSC_TV_PLL_M_14; + n = NTSC_TV_PLL_N_14; + p = NTSC_TV_PLL_P_14; + } + } else { + if (pll_ref_freq == 2700) { + m = PAL_TV_PLL_M_27; + n = PAL_TV_PLL_N_27; + p = PAL_TV_PLL_P_27; + } else { + m = PAL_TV_PLL_M_27; + n = PAL_TV_PLL_N_27; + p = PAL_TV_PLL_P_27; + } + } + + tv_pll_cntl = (m & RADEON_TV_M0LO_MASK) | + (((m >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) | + ((n & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) | + (((n >> 9) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) | + ((p & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT); + + tv_pll_cntl1 = (((4 & RADEON_TVPCP_MASK) << RADEON_TVPCP_SHIFT) | + ((4 & RADEON_TVPVG_MASK) << RADEON_TVPVG_SHIFT) | + ((1 & RADEON_TVPDC_MASK) << RADEON_TVPDC_SHIFT) | + RADEON_TVCLK_SRC_SEL_TVPLL | + RADEON_TVPLL_TEST_DIS); + + tv_dac->tv.tv_uv_adr = 0xc8; + + if (tv_dac->tv_std == TV_STD_NTSC || + tv_dac->tv_std == TV_STD_NTSC_J || + tv_dac->tv_std == TV_STD_PAL_M || + tv_dac->tv_std == TV_STD_PAL_60) { + tv_ftotal = NTSC_TV_VFTOTAL; + hor_timing = hor_timing_NTSC; + vert_timing = vert_timing_NTSC; + } else { + hor_timing = hor_timing_PAL; + vert_timing = vert_timing_PAL; + tv_ftotal = PAL_TV_VFTOTAL; + } + + for (i = 0; i < MAX_H_CODE_TIMING_LEN; i++) { + if ((tv_dac->tv.h_code_timing[i] = hor_timing[i]) == 0) + break; + } + + for (i = 0; i < MAX_V_CODE_TIMING_LEN; i++) { + if ((tv_dac->tv.v_code_timing[i] = vert_timing[i]) == 0) + break; + } + + radeon_legacy_tv_init_restarts(encoder); + + /* play with DAC_CNTL */ + /* play with GPIOPAD_A */ + /* DISP_OUTPUT_CNTL */ + /* use reference freq */ + + /* program the TV registers */ + WREG32(RADEON_TV_MASTER_CNTL, (tv_master_cntl | RADEON_TV_ASYNC_RST | + RADEON_CRT_ASYNC_RST | RADEON_TV_FIFO_ASYNC_RST)); + + tmp = RREG32(RADEON_TV_DAC_CNTL); + tmp &= ~RADEON_TV_DAC_NBLANK; + tmp |= RADEON_TV_DAC_BGSLEEP | + RADEON_TV_DAC_RDACPD | + RADEON_TV_DAC_GDACPD | + RADEON_TV_DAC_BDACPD; + WREG32(RADEON_TV_DAC_CNTL, tmp); + + /* TV PLL */ + WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVCLK_SRC_SEL_TVPLL); + WREG32_PLL(RADEON_TV_PLL_CNTL, tv_pll_cntl); + WREG32_PLL_P(RADEON_TV_PLL_CNTL1, RADEON_TVPLL_RESET, ~RADEON_TVPLL_RESET); + + radeon_wait_pll_lock(encoder, 200, 800, 135); + + WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_RESET); + + radeon_wait_pll_lock(encoder, 300, 160, 27); + radeon_wait_pll_lock(encoder, 200, 800, 135); + + WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~0xf); + WREG32_PLL_P(RADEON_TV_PLL_CNTL1, RADEON_TVCLK_SRC_SEL_TVPLL, ~RADEON_TVCLK_SRC_SEL_TVPLL); + + WREG32_PLL_P(RADEON_TV_PLL_CNTL1, (1 << RADEON_TVPDC_SHIFT), ~RADEON_TVPDC_MASK); + WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_SLEEP); + + /* TV HV */ + WREG32(RADEON_TV_RGB_CNTL, tv_rgb_cntl); + WREG32(RADEON_TV_HTOTAL, const_ptr->hor_total - 1); + WREG32(RADEON_TV_HDISP, const_ptr->hor_resolution - 1); + WREG32(RADEON_TV_HSTART, const_ptr->hor_start); + + WREG32(RADEON_TV_VTOTAL, const_ptr->ver_total - 1); + WREG32(RADEON_TV_VDISP, const_ptr->ver_resolution - 1); + WREG32(RADEON_TV_FTOTAL, tv_ftotal); + WREG32(RADEON_TV_VSCALER_CNTL1, tv_vscaler_cntl1); + WREG32(RADEON_TV_VSCALER_CNTL2, tv_vscaler_cntl2); + + WREG32(RADEON_TV_Y_FALL_CNTL, tv_y_fall_cntl); + WREG32(RADEON_TV_Y_RISE_CNTL, tv_y_rise_cntl); + WREG32(RADEON_TV_Y_SAW_TOOTH_CNTL, tv_y_saw_tooth_cntl); + + WREG32(RADEON_TV_MASTER_CNTL, (tv_master_cntl | RADEON_TV_ASYNC_RST | + RADEON_CRT_ASYNC_RST)); + + /* TV restarts */ + radeon_legacy_write_tv_restarts(radeon_encoder); + + /* tv timings */ + radeon_restore_tv_timing_tables(radeon_encoder); + + WREG32(RADEON_TV_MASTER_CNTL, (tv_master_cntl | RADEON_TV_ASYNC_RST)); + + /* tv std */ + WREG32(RADEON_TV_SYNC_CNTL, (RADEON_SYNC_PUB | RADEON_TV_SYNC_IO_DRIVE)); + WREG32(RADEON_TV_TIMING_CNTL, tv_dac->tv.timing_cntl); + WREG32(RADEON_TV_MODULATOR_CNTL1, tv_modulator_cntl1); + WREG32(RADEON_TV_MODULATOR_CNTL2, tv_modulator_cntl2); + WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, (RADEON_Y_RED_EN | + RADEON_C_GRN_EN | + RADEON_CMP_BLU_EN | + RADEON_DAC_DITHER_EN)); + + WREG32(RADEON_TV_CRC_CNTL, 0); + + WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); + + WREG32(RADEON_TV_GAIN_LIMIT_SETTINGS, ((0x17f << RADEON_UV_GAIN_LIMIT_SHIFT) | + (0x5ff << RADEON_Y_GAIN_LIMIT_SHIFT))); + WREG32(RADEON_TV_LINEAR_GAIN_SETTINGS, ((0x100 << RADEON_UV_GAIN_SHIFT) | + (0x100 << RADEON_Y_GAIN_SHIFT))); + + WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); + +} + +void radeon_legacy_tv_adjust_crtc_reg(struct drm_encoder *encoder, + uint32_t *h_total_disp, uint32_t *h_sync_strt_wid, + uint32_t *v_total_disp, uint32_t *v_sync_strt_wid) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + const struct radeon_tv_mode_constants *const_ptr; + uint32_t tmp; + + const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL); + if (!const_ptr) + return; + + *h_total_disp = (((const_ptr->hor_resolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) | + (((const_ptr->hor_total / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT); + + tmp = *h_sync_strt_wid; + tmp &= ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR); + tmp |= (((const_ptr->hor_syncstart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) | + (const_ptr->hor_syncstart & 7); + *h_sync_strt_wid = tmp; + + *v_total_disp = ((const_ptr->ver_resolution - 1) << RADEON_CRTC_V_DISP_SHIFT) | + ((const_ptr->ver_total - 1) << RADEON_CRTC_V_TOTAL_SHIFT); + + tmp = *v_sync_strt_wid; + tmp &= ~RADEON_CRTC_V_SYNC_STRT; + tmp |= ((const_ptr->ver_syncstart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT); + *v_sync_strt_wid = tmp; +} + +static inline int get_post_div(int value) +{ + int post_div; + switch (value) { + case 1: post_div = 0; break; + case 2: post_div = 1; break; + case 3: post_div = 4; break; + case 4: post_div = 2; break; + case 6: post_div = 6; break; + case 8: post_div = 3; break; + case 12: post_div = 7; break; + case 16: + default: post_div = 5; break; + } + return post_div; +} + +void radeon_legacy_tv_adjust_pll1(struct drm_encoder *encoder, + uint32_t *htotal_cntl, uint32_t *ppll_ref_div, + uint32_t *ppll_div_3, uint32_t *pixclks_cntl) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + const struct radeon_tv_mode_constants *const_ptr; + + const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL); + if (!const_ptr) + return; + + *htotal_cntl = (const_ptr->hor_total & 0x7) | RADEON_HTOT_CNTL_VGA_EN; + + *ppll_ref_div = const_ptr->crtcPLL_M; + + *ppll_div_3 = (const_ptr->crtcPLL_N & 0x7ff) | (get_post_div(const_ptr->crtcPLL_post_div) << 16); + *pixclks_cntl &= ~(RADEON_PIX2CLK_SRC_SEL_MASK | RADEON_PIXCLK_TV_SRC_SEL); + *pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK; +} + +void radeon_legacy_tv_adjust_pll2(struct drm_encoder *encoder, + uint32_t *htotal2_cntl, uint32_t *p2pll_ref_div, + uint32_t *p2pll_div_0, uint32_t *pixclks_cntl) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + const struct radeon_tv_mode_constants *const_ptr; + + const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL); + if (!const_ptr) + return; + + *htotal2_cntl = (const_ptr->hor_total & 0x7); + + *p2pll_ref_div = const_ptr->crtcPLL_M; + + *p2pll_div_0 = (const_ptr->crtcPLL_N & 0x7ff) | (get_post_div(const_ptr->crtcPLL_post_div) << 16); + *pixclks_cntl &= ~RADEON_PIX2CLK_SRC_SEL_MASK; + *pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK | RADEON_PIXCLK_TV_SRC_SEL; +} + diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 20e9509a7130..523d6cbd4f08 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -188,6 +188,21 @@ struct radeon_native_mode { uint32_t flags; }; +#define MAX_H_CODE_TIMING_LEN 32 +#define MAX_V_CODE_TIMING_LEN 32 + +/* need to store these as reading + back code tables is excessive */ +struct radeon_tv_regs { + uint32_t tv_uv_adr; + uint32_t timing_cntl; + uint32_t hrestart; + uint32_t vrestart; + uint32_t frestart; + uint16_t h_code_timing[MAX_H_CODE_TIMING_LEN]; + uint16_t v_code_timing[MAX_V_CODE_TIMING_LEN]; +}; + struct radeon_crtc { struct drm_crtc base; int crtc_id; @@ -202,7 +217,6 @@ struct radeon_crtc { uint32_t legacy_display_base_addr; uint32_t legacy_cursor_offset; enum radeon_rmx_type rmx_type; - uint32_t devices; fixed20_12 vsc; fixed20_12 hsc; struct radeon_native_mode native_mode; @@ -234,7 +248,13 @@ struct radeon_encoder_tv_dac { uint32_t ntsc_tvdac_adj; uint32_t pal_tvdac_adj; + int h_pos; + int v_pos; + int h_size; + int supported_tv_stds; + bool tv_on; enum radeon_tv_std tv_std; + struct radeon_tv_regs tv; }; struct radeon_encoder_int_tmds { @@ -253,10 +273,15 @@ struct radeon_encoder_atom_dig { struct radeon_native_mode native_mode; }; +struct radeon_encoder_atom_dac { + enum radeon_tv_std tv_std; +}; + struct radeon_encoder { struct drm_encoder base; uint32_t encoder_id; uint32_t devices; + uint32_t active_device; uint32_t flags; uint32_t pixel_clock; enum radeon_rmx_type rmx_type; @@ -274,7 +299,10 @@ struct radeon_connector { uint32_t connector_id; uint32_t devices; struct radeon_i2c_chan *ddc_bus; - int use_digital; + bool use_digital; + /* we need to mind the EDID between detect + and get modes due to analog/digital/tvencoder */ + struct edid *edid; void *con_priv; }; @@ -308,6 +336,7 @@ struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, i struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index); extern void atombios_external_tmds_setup(struct drm_encoder *encoder, int action); extern int atombios_get_encoder_mode(struct drm_encoder *encoder); +extern void radeon_encoder_set_active_device(struct drm_encoder *encoder); extern void radeon_crtc_load_lut(struct drm_crtc *crtc); extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, @@ -394,6 +423,19 @@ extern int radeon_static_clocks_init(struct drm_device *dev); bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); -void atom_rv515_force_tv_scaler(struct radeon_device *rdev); - +void atom_rv515_force_tv_scaler(struct radeon_device *rdev, struct radeon_crtc *radeon_crtc); + +/* legacy tv */ +void radeon_legacy_tv_adjust_crtc_reg(struct drm_encoder *encoder, + uint32_t *h_total_disp, uint32_t *h_sync_strt_wid, + uint32_t *v_total_disp, uint32_t *v_sync_strt_wid); +void radeon_legacy_tv_adjust_pll1(struct drm_encoder *encoder, + uint32_t *htotal_cntl, uint32_t *ppll_ref_div, + uint32_t *ppll_div_3, uint32_t *pixclks_cntl); +void radeon_legacy_tv_adjust_pll2(struct drm_encoder *encoder, + uint32_t *htotal2_cntl, uint32_t *p2pll_ref_div, + uint32_t *p2pll_div_0, uint32_t *pixclks_cntl); +void radeon_legacy_tv_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); #endif diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index 404b39bf3430..28be2f1165cb 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -3462,7 +3462,9 @@ # define RADEON_RGB_CONVERT_BY_PASS (1 << 10) # define RADEON_UVRAM_READ_MARGIN_SHIFT 16 # define RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT 20 -# define RADEON_TVOUT_SCALE_EN (1 << 26) +# define RADEON_RGB_ATTEN_SEL(x) ((x) << 24) +# define RADEON_TVOUT_SCALE_EN (1 << 26) +# define RADEON_RGB_ATTEN_VAL(x) ((x) << 28) #define RADEON_TV_SYNC_CNTL 0x0808 # define RADEON_SYNC_OE (1 << 0) # define RADEON_SYNC_OUT (1 << 1) diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 60a194f1d9a8..97965c430c1f 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -475,232 +475,234 @@ int rv515_init(struct radeon_device *rdev) return 0; } -void atom_rv515_force_tv_scaler(struct radeon_device *rdev) +void atom_rv515_force_tv_scaler(struct radeon_device *rdev, struct radeon_crtc *crtc) { - - WREG32(0x659C, 0x0); - WREG32(0x6594, 0x705); - WREG32(0x65A4, 0x10001); - WREG32(0x65D8, 0x0); - WREG32(0x65B0, 0x0); - WREG32(0x65C0, 0x0); - WREG32(0x65D4, 0x0); - WREG32(0x6578, 0x0); - WREG32(0x657C, 0x841880A8); - WREG32(0x6578, 0x1); - WREG32(0x657C, 0x84208680); - WREG32(0x6578, 0x2); - WREG32(0x657C, 0xBFF880B0); - WREG32(0x6578, 0x100); - WREG32(0x657C, 0x83D88088); - WREG32(0x6578, 0x101); - WREG32(0x657C, 0x84608680); - WREG32(0x6578, 0x102); - WREG32(0x657C, 0xBFF080D0); - WREG32(0x6578, 0x200); - WREG32(0x657C, 0x83988068); - WREG32(0x6578, 0x201); - WREG32(0x657C, 0x84A08680); - WREG32(0x6578, 0x202); - WREG32(0x657C, 0xBFF080F8); - WREG32(0x6578, 0x300); - WREG32(0x657C, 0x83588058); - WREG32(0x6578, 0x301); - WREG32(0x657C, 0x84E08660); - WREG32(0x6578, 0x302); - WREG32(0x657C, 0xBFF88120); - WREG32(0x6578, 0x400); - WREG32(0x657C, 0x83188040); - WREG32(0x6578, 0x401); - WREG32(0x657C, 0x85008660); - WREG32(0x6578, 0x402); - WREG32(0x657C, 0xBFF88150); - WREG32(0x6578, 0x500); - WREG32(0x657C, 0x82D88030); - WREG32(0x6578, 0x501); - WREG32(0x657C, 0x85408640); - WREG32(0x6578, 0x502); - WREG32(0x657C, 0xBFF88180); - WREG32(0x6578, 0x600); - WREG32(0x657C, 0x82A08018); - WREG32(0x6578, 0x601); - WREG32(0x657C, 0x85808620); - WREG32(0x6578, 0x602); - WREG32(0x657C, 0xBFF081B8); - WREG32(0x6578, 0x700); - WREG32(0x657C, 0x82608010); - WREG32(0x6578, 0x701); - WREG32(0x657C, 0x85A08600); - WREG32(0x6578, 0x702); - WREG32(0x657C, 0x800081F0); - WREG32(0x6578, 0x800); - WREG32(0x657C, 0x8228BFF8); - WREG32(0x6578, 0x801); - WREG32(0x657C, 0x85E085E0); - WREG32(0x6578, 0x802); - WREG32(0x657C, 0xBFF88228); - WREG32(0x6578, 0x10000); - WREG32(0x657C, 0x82A8BF00); - WREG32(0x6578, 0x10001); - WREG32(0x657C, 0x82A08CC0); - WREG32(0x6578, 0x10002); - WREG32(0x657C, 0x8008BEF8); - WREG32(0x6578, 0x10100); - WREG32(0x657C, 0x81F0BF28); - WREG32(0x6578, 0x10101); - WREG32(0x657C, 0x83608CA0); - WREG32(0x6578, 0x10102); - WREG32(0x657C, 0x8018BED0); - WREG32(0x6578, 0x10200); - WREG32(0x657C, 0x8148BF38); - WREG32(0x6578, 0x10201); - WREG32(0x657C, 0x84408C80); - WREG32(0x6578, 0x10202); - WREG32(0x657C, 0x8008BEB8); - WREG32(0x6578, 0x10300); - WREG32(0x657C, 0x80B0BF78); - WREG32(0x6578, 0x10301); - WREG32(0x657C, 0x85008C20); - WREG32(0x6578, 0x10302); - WREG32(0x657C, 0x8020BEA0); - WREG32(0x6578, 0x10400); - WREG32(0x657C, 0x8028BF90); - WREG32(0x6578, 0x10401); - WREG32(0x657C, 0x85E08BC0); - WREG32(0x6578, 0x10402); - WREG32(0x657C, 0x8018BE90); - WREG32(0x6578, 0x10500); - WREG32(0x657C, 0xBFB8BFB0); - WREG32(0x6578, 0x10501); - WREG32(0x657C, 0x86C08B40); - WREG32(0x6578, 0x10502); - WREG32(0x657C, 0x8010BE90); - WREG32(0x6578, 0x10600); - WREG32(0x657C, 0xBF58BFC8); - WREG32(0x6578, 0x10601); - WREG32(0x657C, 0x87A08AA0); - WREG32(0x6578, 0x10602); - WREG32(0x657C, 0x8010BE98); - WREG32(0x6578, 0x10700); - WREG32(0x657C, 0xBF10BFF0); - WREG32(0x6578, 0x10701); - WREG32(0x657C, 0x886089E0); - WREG32(0x6578, 0x10702); - WREG32(0x657C, 0x8018BEB0); - WREG32(0x6578, 0x10800); - WREG32(0x657C, 0xBED8BFE8); - WREG32(0x6578, 0x10801); - WREG32(0x657C, 0x89408940); - WREG32(0x6578, 0x10802); - WREG32(0x657C, 0xBFE8BED8); - WREG32(0x6578, 0x20000); - WREG32(0x657C, 0x80008000); - WREG32(0x6578, 0x20001); - WREG32(0x657C, 0x90008000); - WREG32(0x6578, 0x20002); - WREG32(0x657C, 0x80008000); - WREG32(0x6578, 0x20003); - WREG32(0x657C, 0x80008000); - WREG32(0x6578, 0x20100); - WREG32(0x657C, 0x80108000); - WREG32(0x6578, 0x20101); - WREG32(0x657C, 0x8FE0BF70); - WREG32(0x6578, 0x20102); - WREG32(0x657C, 0xBFE880C0); - WREG32(0x6578, 0x20103); - WREG32(0x657C, 0x80008000); - WREG32(0x6578, 0x20200); - WREG32(0x657C, 0x8018BFF8); - WREG32(0x6578, 0x20201); - WREG32(0x657C, 0x8F80BF08); - WREG32(0x6578, 0x20202); - WREG32(0x657C, 0xBFD081A0); - WREG32(0x6578, 0x20203); - WREG32(0x657C, 0xBFF88000); - WREG32(0x6578, 0x20300); - WREG32(0x657C, 0x80188000); - WREG32(0x6578, 0x20301); - WREG32(0x657C, 0x8EE0BEC0); - WREG32(0x6578, 0x20302); - WREG32(0x657C, 0xBFB082A0); - WREG32(0x6578, 0x20303); - WREG32(0x657C, 0x80008000); - WREG32(0x6578, 0x20400); - WREG32(0x657C, 0x80188000); - WREG32(0x6578, 0x20401); - WREG32(0x657C, 0x8E00BEA0); - WREG32(0x6578, 0x20402); - WREG32(0x657C, 0xBF8883C0); - WREG32(0x6578, 0x20403); - WREG32(0x657C, 0x80008000); - WREG32(0x6578, 0x20500); - WREG32(0x657C, 0x80188000); - WREG32(0x6578, 0x20501); - WREG32(0x657C, 0x8D00BE90); - WREG32(0x6578, 0x20502); - WREG32(0x657C, 0xBF588500); - WREG32(0x6578, 0x20503); - WREG32(0x657C, 0x80008008); - WREG32(0x6578, 0x20600); - WREG32(0x657C, 0x80188000); - WREG32(0x6578, 0x20601); - WREG32(0x657C, 0x8BC0BE98); - WREG32(0x6578, 0x20602); - WREG32(0x657C, 0xBF308660); - WREG32(0x6578, 0x20603); - WREG32(0x657C, 0x80008008); - WREG32(0x6578, 0x20700); - WREG32(0x657C, 0x80108000); - WREG32(0x6578, 0x20701); - WREG32(0x657C, 0x8A80BEB0); - WREG32(0x6578, 0x20702); - WREG32(0x657C, 0xBF0087C0); - WREG32(0x6578, 0x20703); - WREG32(0x657C, 0x80008008); - WREG32(0x6578, 0x20800); - WREG32(0x657C, 0x80108000); - WREG32(0x6578, 0x20801); - WREG32(0x657C, 0x8920BED0); - WREG32(0x6578, 0x20802); - WREG32(0x657C, 0xBED08920); - WREG32(0x6578, 0x20803); - WREG32(0x657C, 0x80008010); - WREG32(0x6578, 0x30000); - WREG32(0x657C, 0x90008000); - WREG32(0x6578, 0x30001); - WREG32(0x657C, 0x80008000); - WREG32(0x6578, 0x30100); - WREG32(0x657C, 0x8FE0BF90); - WREG32(0x6578, 0x30101); - WREG32(0x657C, 0xBFF880A0); - WREG32(0x6578, 0x30200); - WREG32(0x657C, 0x8F60BF40); - WREG32(0x6578, 0x30201); - WREG32(0x657C, 0xBFE88180); - WREG32(0x6578, 0x30300); - WREG32(0x657C, 0x8EC0BF00); - WREG32(0x6578, 0x30301); - WREG32(0x657C, 0xBFC88280); - WREG32(0x6578, 0x30400); - WREG32(0x657C, 0x8DE0BEE0); - WREG32(0x6578, 0x30401); - WREG32(0x657C, 0xBFA083A0); - WREG32(0x6578, 0x30500); - WREG32(0x657C, 0x8CE0BED0); - WREG32(0x6578, 0x30501); - WREG32(0x657C, 0xBF7884E0); - WREG32(0x6578, 0x30600); - WREG32(0x657C, 0x8BA0BED8); - WREG32(0x6578, 0x30601); - WREG32(0x657C, 0xBF508640); - WREG32(0x6578, 0x30700); - WREG32(0x657C, 0x8A60BEE8); - WREG32(0x6578, 0x30701); - WREG32(0x657C, 0xBF2087A0); - WREG32(0x6578, 0x30800); - WREG32(0x657C, 0x8900BF00); - WREG32(0x6578, 0x30801); - WREG32(0x657C, 0xBF008900); + int index_reg = 0x6578 + crtc->crtc_offset; + int data_reg = 0x657c + crtc->crtc_offset; + + WREG32(0x659C + crtc->crtc_offset, 0x0); + WREG32(0x6594 + crtc->crtc_offset, 0x705); + WREG32(0x65A4 + crtc->crtc_offset, 0x10001); + WREG32(0x65D8 + crtc->crtc_offset, 0x0); + WREG32(0x65B0 + crtc->crtc_offset, 0x0); + WREG32(0x65C0 + crtc->crtc_offset, 0x0); + WREG32(0x65D4 + crtc->crtc_offset, 0x0); + WREG32(index_reg, 0x0); + WREG32(data_reg, 0x841880A8); + WREG32(index_reg, 0x1); + WREG32(data_reg, 0x84208680); + WREG32(index_reg, 0x2); + WREG32(data_reg, 0xBFF880B0); + WREG32(index_reg, 0x100); + WREG32(data_reg, 0x83D88088); + WREG32(index_reg, 0x101); + WREG32(data_reg, 0x84608680); + WREG32(index_reg, 0x102); + WREG32(data_reg, 0xBFF080D0); + WREG32(index_reg, 0x200); + WREG32(data_reg, 0x83988068); + WREG32(index_reg, 0x201); + WREG32(data_reg, 0x84A08680); + WREG32(index_reg, 0x202); + WREG32(data_reg, 0xBFF080F8); + WREG32(index_reg, 0x300); + WREG32(data_reg, 0x83588058); + WREG32(index_reg, 0x301); + WREG32(data_reg, 0x84E08660); + WREG32(index_reg, 0x302); + WREG32(data_reg, 0xBFF88120); + WREG32(index_reg, 0x400); + WREG32(data_reg, 0x83188040); + WREG32(index_reg, 0x401); + WREG32(data_reg, 0x85008660); + WREG32(index_reg, 0x402); + WREG32(data_reg, 0xBFF88150); + WREG32(index_reg, 0x500); + WREG32(data_reg, 0x82D88030); + WREG32(index_reg, 0x501); + WREG32(data_reg, 0x85408640); + WREG32(index_reg, 0x502); + WREG32(data_reg, 0xBFF88180); + WREG32(index_reg, 0x600); + WREG32(data_reg, 0x82A08018); + WREG32(index_reg, 0x601); + WREG32(data_reg, 0x85808620); + WREG32(index_reg, 0x602); + WREG32(data_reg, 0xBFF081B8); + WREG32(index_reg, 0x700); + WREG32(data_reg, 0x82608010); + WREG32(index_reg, 0x701); + WREG32(data_reg, 0x85A08600); + WREG32(index_reg, 0x702); + WREG32(data_reg, 0x800081F0); + WREG32(index_reg, 0x800); + WREG32(data_reg, 0x8228BFF8); + WREG32(index_reg, 0x801); + WREG32(data_reg, 0x85E085E0); + WREG32(index_reg, 0x802); + WREG32(data_reg, 0xBFF88228); + WREG32(index_reg, 0x10000); + WREG32(data_reg, 0x82A8BF00); + WREG32(index_reg, 0x10001); + WREG32(data_reg, 0x82A08CC0); + WREG32(index_reg, 0x10002); + WREG32(data_reg, 0x8008BEF8); + WREG32(index_reg, 0x10100); + WREG32(data_reg, 0x81F0BF28); + WREG32(index_reg, 0x10101); + WREG32(data_reg, 0x83608CA0); + WREG32(index_reg, 0x10102); + WREG32(data_reg, 0x8018BED0); + WREG32(index_reg, 0x10200); + WREG32(data_reg, 0x8148BF38); + WREG32(index_reg, 0x10201); + WREG32(data_reg, 0x84408C80); + WREG32(index_reg, 0x10202); + WREG32(data_reg, 0x8008BEB8); + WREG32(index_reg, 0x10300); + WREG32(data_reg, 0x80B0BF78); + WREG32(index_reg, 0x10301); + WREG32(data_reg, 0x85008C20); + WREG32(index_reg, 0x10302); + WREG32(data_reg, 0x8020BEA0); + WREG32(index_reg, 0x10400); + WREG32(data_reg, 0x8028BF90); + WREG32(index_reg, 0x10401); + WREG32(data_reg, 0x85E08BC0); + WREG32(index_reg, 0x10402); + WREG32(data_reg, 0x8018BE90); + WREG32(index_reg, 0x10500); + WREG32(data_reg, 0xBFB8BFB0); + WREG32(index_reg, 0x10501); + WREG32(data_reg, 0x86C08B40); + WREG32(index_reg, 0x10502); + WREG32(data_reg, 0x8010BE90); + WREG32(index_reg, 0x10600); + WREG32(data_reg, 0xBF58BFC8); + WREG32(index_reg, 0x10601); + WREG32(data_reg, 0x87A08AA0); + WREG32(index_reg, 0x10602); + WREG32(data_reg, 0x8010BE98); + WREG32(index_reg, 0x10700); + WREG32(data_reg, 0xBF10BFF0); + WREG32(index_reg, 0x10701); + WREG32(data_reg, 0x886089E0); + WREG32(index_reg, 0x10702); + WREG32(data_reg, 0x8018BEB0); + WREG32(index_reg, 0x10800); + WREG32(data_reg, 0xBED8BFE8); + WREG32(index_reg, 0x10801); + WREG32(data_reg, 0x89408940); + WREG32(index_reg, 0x10802); + WREG32(data_reg, 0xBFE8BED8); + WREG32(index_reg, 0x20000); + WREG32(data_reg, 0x80008000); + WREG32(index_reg, 0x20001); + WREG32(data_reg, 0x90008000); + WREG32(index_reg, 0x20002); + WREG32(data_reg, 0x80008000); + WREG32(index_reg, 0x20003); + WREG32(data_reg, 0x80008000); + WREG32(index_reg, 0x20100); + WREG32(data_reg, 0x80108000); + WREG32(index_reg, 0x20101); + WREG32(data_reg, 0x8FE0BF70); + WREG32(index_reg, 0x20102); + WREG32(data_reg, 0xBFE880C0); + WREG32(index_reg, 0x20103); + WREG32(data_reg, 0x80008000); + WREG32(index_reg, 0x20200); + WREG32(data_reg, 0x8018BFF8); + WREG32(index_reg, 0x20201); + WREG32(data_reg, 0x8F80BF08); + WREG32(index_reg, 0x20202); + WREG32(data_reg, 0xBFD081A0); + WREG32(index_reg, 0x20203); + WREG32(data_reg, 0xBFF88000); + WREG32(index_reg, 0x20300); + WREG32(data_reg, 0x80188000); + WREG32(index_reg, 0x20301); + WREG32(data_reg, 0x8EE0BEC0); + WREG32(index_reg, 0x20302); + WREG32(data_reg, 0xBFB082A0); + WREG32(index_reg, 0x20303); + WREG32(data_reg, 0x80008000); + WREG32(index_reg, 0x20400); + WREG32(data_reg, 0x80188000); + WREG32(index_reg, 0x20401); + WREG32(data_reg, 0x8E00BEA0); + WREG32(index_reg, 0x20402); + WREG32(data_reg, 0xBF8883C0); + WREG32(index_reg, 0x20403); + WREG32(data_reg, 0x80008000); + WREG32(index_reg, 0x20500); + WREG32(data_reg, 0x80188000); + WREG32(index_reg, 0x20501); + WREG32(data_reg, 0x8D00BE90); + WREG32(index_reg, 0x20502); + WREG32(data_reg, 0xBF588500); + WREG32(index_reg, 0x20503); + WREG32(data_reg, 0x80008008); + WREG32(index_reg, 0x20600); + WREG32(data_reg, 0x80188000); + WREG32(index_reg, 0x20601); + WREG32(data_reg, 0x8BC0BE98); + WREG32(index_reg, 0x20602); + WREG32(data_reg, 0xBF308660); + WREG32(index_reg, 0x20603); + WREG32(data_reg, 0x80008008); + WREG32(index_reg, 0x20700); + WREG32(data_reg, 0x80108000); + WREG32(index_reg, 0x20701); + WREG32(data_reg, 0x8A80BEB0); + WREG32(index_reg, 0x20702); + WREG32(data_reg, 0xBF0087C0); + WREG32(index_reg, 0x20703); + WREG32(data_reg, 0x80008008); + WREG32(index_reg, 0x20800); + WREG32(data_reg, 0x80108000); + WREG32(index_reg, 0x20801); + WREG32(data_reg, 0x8920BED0); + WREG32(index_reg, 0x20802); + WREG32(data_reg, 0xBED08920); + WREG32(index_reg, 0x20803); + WREG32(data_reg, 0x80008010); + WREG32(index_reg, 0x30000); + WREG32(data_reg, 0x90008000); + WREG32(index_reg, 0x30001); + WREG32(data_reg, 0x80008000); + WREG32(index_reg, 0x30100); + WREG32(data_reg, 0x8FE0BF90); + WREG32(index_reg, 0x30101); + WREG32(data_reg, 0xBFF880A0); + WREG32(index_reg, 0x30200); + WREG32(data_reg, 0x8F60BF40); + WREG32(index_reg, 0x30201); + WREG32(data_reg, 0xBFE88180); + WREG32(index_reg, 0x30300); + WREG32(data_reg, 0x8EC0BF00); + WREG32(index_reg, 0x30301); + WREG32(data_reg, 0xBFC88280); + WREG32(index_reg, 0x30400); + WREG32(data_reg, 0x8DE0BEE0); + WREG32(index_reg, 0x30401); + WREG32(data_reg, 0xBFA083A0); + WREG32(index_reg, 0x30500); + WREG32(data_reg, 0x8CE0BED0); + WREG32(index_reg, 0x30501); + WREG32(data_reg, 0xBF7884E0); + WREG32(index_reg, 0x30600); + WREG32(data_reg, 0x8BA0BED8); + WREG32(index_reg, 0x30601); + WREG32(data_reg, 0xBF508640); + WREG32(index_reg, 0x30700); + WREG32(data_reg, 0x8A60BEE8); + WREG32(index_reg, 0x30701); + WREG32(data_reg, 0xBF2087A0); + WREG32(index_reg, 0x30800); + WREG32(data_reg, 0x8900BF00); + WREG32(index_reg, 0x30801); + WREG32(data_reg, 0xBF008900); } struct rv515_watermark { -- cgit v1.2.3-59-g8ed1b From 3ce0a23d2d253185df24e22e3d5f89800bb3dd1c Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 8 Sep 2009 10:10:24 +1000 Subject: drm/radeon/kms: add r600 KMS support This adds the r600 KMS + CS support to the Linux kernel. The r600 TTM support is quite basic and still needs more work esp around using interrupts, but the polled fencing should work okay for now. Also currently TTM is using memcpy to do VRAM moves, the code is here to use a 3D blit to do this, but isn't fully debugged yet. Authors: Alex Deucher Dave Airlie Jerome Glisse Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/Makefile | 5 +- drivers/gpu/drm/radeon/atombios_crtc.c | 1 + drivers/gpu/drm/radeon/avivod.h | 60 + drivers/gpu/drm/radeon/r100.c | 135 ++- drivers/gpu/drm/radeon/r100d.h | 76 ++ drivers/gpu/drm/radeon/r300.c | 3 +- drivers/gpu/drm/radeon/r300.h | 36 - drivers/gpu/drm/radeon/r300d.h | 76 ++ drivers/gpu/drm/radeon/r600.c | 1714 ++++++++++++++++++++++++++-- drivers/gpu/drm/radeon/r600_blit.c | 855 ++++++++++++++ drivers/gpu/drm/radeon/r600_blit_kms.c | 777 +++++++++++++ drivers/gpu/drm/radeon/r600_blit_shaders.c | 1072 +++++++++++++++++ drivers/gpu/drm/radeon/r600_blit_shaders.h | 14 + drivers/gpu/drm/radeon/r600_cp.c | 252 +++- drivers/gpu/drm/radeon/r600_cs.c | 658 +++++++++++ drivers/gpu/drm/radeon/r600d.h | 661 +++++++++++ drivers/gpu/drm/radeon/radeon.h | 120 +- drivers/gpu/drm/radeon/radeon_asic.h | 156 ++- drivers/gpu/drm/radeon/radeon_atombios.c | 4 - drivers/gpu/drm/radeon/radeon_clocks.c | 10 +- drivers/gpu/drm/radeon/radeon_device.c | 340 +++--- drivers/gpu/drm/radeon/radeon_drv.h | 141 ++- drivers/gpu/drm/radeon/radeon_fence.c | 54 +- drivers/gpu/drm/radeon/radeon_reg.h | 18 + drivers/gpu/drm/radeon/radeon_ring.c | 119 +- drivers/gpu/drm/radeon/radeon_share.h | 77 ++ drivers/gpu/drm/radeon/radeon_state.c | 18 +- drivers/gpu/drm/radeon/radeon_ttm.c | 7 +- drivers/gpu/drm/radeon/rs400.c | 2 +- drivers/gpu/drm/radeon/rs780.c | 102 -- drivers/gpu/drm/radeon/rv515.c | 2 +- drivers/gpu/drm/radeon/rv515d.h | 220 ++++ drivers/gpu/drm/radeon/rv515r.h | 170 --- drivers/gpu/drm/radeon/rv770.c | 987 +++++++++++++++- drivers/gpu/drm/radeon/rv770d.h | 341 ++++++ 35 files changed, 8483 insertions(+), 800 deletions(-) create mode 100644 drivers/gpu/drm/radeon/avivod.h create mode 100644 drivers/gpu/drm/radeon/r100d.h delete mode 100644 drivers/gpu/drm/radeon/r300.h create mode 100644 drivers/gpu/drm/radeon/r300d.h create mode 100644 drivers/gpu/drm/radeon/r600_blit.c create mode 100644 drivers/gpu/drm/radeon/r600_blit_kms.c create mode 100644 drivers/gpu/drm/radeon/r600_blit_shaders.c create mode 100644 drivers/gpu/drm/radeon/r600_blit_shaders.h create mode 100644 drivers/gpu/drm/radeon/r600_cs.c create mode 100644 drivers/gpu/drm/radeon/r600d.h delete mode 100644 drivers/gpu/drm/radeon/rs780.c create mode 100644 drivers/gpu/drm/radeon/rv515d.h delete mode 100644 drivers/gpu/drm/radeon/rv515r.h create mode 100644 drivers/gpu/drm/radeon/rv770d.h (limited to 'drivers/gpu/drm/radeon/rv515.c') diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index c5db0c4fe788..14c3fe692723 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -46,8 +46,9 @@ radeon-$(CONFIG_DRM_RADEON_KMS) += radeon_device.o radeon_kms.o \ radeon_encoders.o radeon_display.o radeon_cursor.o radeon_i2c.o \ radeon_clocks.o radeon_fb.o radeon_gem.o radeon_ring.o radeon_irq_kms.o \ radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \ - rs400.o rs600.o rs690.o rv515.o r520.o r600.o rs780.o rv770.o \ - radeon_test.o r200.o radeon_legacy_tv.o + rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \ + r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \ + r600_blit_kms.o radeon-$(CONFIG_COMPAT) += radeon_ioc32.o diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 8e31e992ec53..a7edd0f2ac37 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -389,6 +389,7 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) pll_flags |= RADEON_PLL_USE_REF_DIV; } radeon_encoder = to_radeon_encoder(encoder); + break; } } diff --git a/drivers/gpu/drm/radeon/avivod.h b/drivers/gpu/drm/radeon/avivod.h new file mode 100644 index 000000000000..d4e6e6e4a938 --- /dev/null +++ b/drivers/gpu/drm/radeon/avivod.h @@ -0,0 +1,60 @@ +/* + * Copyright 2009 Advanced Micro Devices, Inc. + * Copyright 2009 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 + * Jerome Glisse + */ +#ifndef AVIVOD_H +#define AVIVOD_H + + +#define D1CRTC_CONTROL 0x6080 +#define CRTC_EN (1 << 0) +#define D1CRTC_UPDATE_LOCK 0x60E8 +#define D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110 +#define D1GRPH_SECONDARY_SURFACE_ADDRESS 0x6118 + +#define D2CRTC_CONTROL 0x6880 +#define D2CRTC_UPDATE_LOCK 0x68E8 +#define D2GRPH_PRIMARY_SURFACE_ADDRESS 0x6910 +#define D2GRPH_SECONDARY_SURFACE_ADDRESS 0x6918 + +#define D1VGA_CONTROL 0x0330 +#define DVGA_CONTROL_MODE_ENABLE (1 << 0) +#define DVGA_CONTROL_TIMING_SELECT (1 << 8) +#define DVGA_CONTROL_SYNC_POLARITY_SELECT (1 << 9) +#define DVGA_CONTROL_OVERSCAN_TIMING_SELECT (1 << 10) +#define DVGA_CONTROL_OVERSCAN_COLOR_EN (1 << 16) +#define DVGA_CONTROL_ROTATE (1 << 24) +#define D2VGA_CONTROL 0x0338 + +#define VGA_HDP_CONTROL 0x328 +#define VGA_MEM_PAGE_SELECT_EN (1 << 0) +#define VGA_MEMORY_DISABLE (1 << 4) +#define VGA_RBBM_LOCK_DISABLE (1 << 8) +#define VGA_SOFT_RESET (1 << 16) +#define VGA_MEMORY_BASE_ADDRESS 0x0310 +#define VGA_RENDER_CONTROL 0x0300 +#define VGA_VSTATUS_CNTL_MASK 0x00030000 + +#endif diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index ee3ab62417e2..5708c07ce733 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -31,6 +31,8 @@ #include "radeon_drm.h" #include "radeon_reg.h" #include "radeon.h" +#include "r100d.h" + #include #include @@ -391,9 +393,9 @@ int r100_wb_init(struct radeon_device *rdev) return r; } } - WREG32(0x774, rdev->wb.gpu_addr); - WREG32(0x70C, rdev->wb.gpu_addr + 1024); - WREG32(0x770, 0xff); + WREG32(RADEON_SCRATCH_ADDR, rdev->wb.gpu_addr); + WREG32(RADEON_CP_RB_RPTR_ADDR, rdev->wb.gpu_addr + 1024); + WREG32(RADEON_SCRATCH_UMSK, 0xff); return 0; } @@ -559,18 +561,18 @@ static int r100_cp_init_microcode(struct radeon_device *rdev) fw_name = FIRMWARE_R520; } - err = request_firmware(&rdev->fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); platform_device_unregister(pdev); if (err) { printk(KERN_ERR "radeon_cp: Failed to load firmware \"%s\"\n", fw_name); - } else if (rdev->fw->size % 8) { + } else if (rdev->me_fw->size % 8) { printk(KERN_ERR "radeon_cp: Bogus length %zu in firmware \"%s\"\n", - rdev->fw->size, fw_name); + rdev->me_fw->size, fw_name); err = -EINVAL; - release_firmware(rdev->fw); - rdev->fw = NULL; + release_firmware(rdev->me_fw); + rdev->me_fw = NULL; } return err; } @@ -584,9 +586,9 @@ static void r100_cp_load_microcode(struct radeon_device *rdev) "programming pipes. Bad things might happen.\n"); } - if (rdev->fw) { - size = rdev->fw->size / 4; - fw_data = (const __be32 *)&rdev->fw->data[0]; + if (rdev->me_fw) { + size = rdev->me_fw->size / 4; + fw_data = (const __be32 *)&rdev->me_fw->data[0]; WREG32(RADEON_CP_ME_RAM_ADDR, 0); for (i = 0; i < size; i += 2) { WREG32(RADEON_CP_ME_RAM_DATAH, @@ -632,7 +634,7 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size) DRM_INFO("radeon: cp idle (0x%08X)\n", tmp); } - if (!rdev->fw) { + if (!rdev->me_fw) { r = r100_cp_init_microcode(rdev); if (r) { DRM_ERROR("Failed to load firmware!\n"); @@ -765,6 +767,12 @@ int r100_cp_reset(struct radeon_device *rdev) return -1; } +void r100_cp_commit(struct radeon_device *rdev) +{ + WREG32(RADEON_CP_RB_WPTR, rdev->cp.wptr); + (void)RREG32(RADEON_CP_RB_WPTR); +} + /* * CS functions @@ -2954,3 +2962,106 @@ void r100_cs_track_clear(struct radeon_device *rdev, struct r100_cs_track *track } } } + +int r100_ring_test(struct radeon_device *rdev) +{ + 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, 2); + if (r) { + DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r); + radeon_scratch_free(rdev, scratch); + return r; + } + radeon_ring_write(rdev, PACKET0(scratch, 0)); + radeon_ring_write(rdev, 0xDEADBEEF); + radeon_ring_unlock_commit(rdev); + 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 succeeded in %d usecs\n", i); + } else { + DRM_ERROR("radeon: ring test failed (sracth(0x%04X)=0x%08X)\n", + scratch, tmp); + r = -EINVAL; + } + radeon_scratch_free(rdev, scratch); + return r; +} + +void r100_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) +{ + radeon_ring_write(rdev, PACKET0(RADEON_CP_IB_BASE, 1)); + radeon_ring_write(rdev, ib->gpu_addr); + radeon_ring_write(rdev, ib->length_dw); +} + +int r100_ib_test(struct radeon_device *rdev) +{ + 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, &ib); + if (r) { + return r; + } + ib->ptr[0] = PACKET0(scratch, 0); + ib->ptr[1] = 0xDEADBEEF; + ib->ptr[2] = PACKET2(0); + ib->ptr[3] = PACKET2(0); + ib->ptr[4] = PACKET2(0); + ib->ptr[5] = PACKET2(0); + ib->ptr[6] = PACKET2(0); + ib->ptr[7] = PACKET2(0); + ib->length_dw = 8; + r = radeon_ib_schedule(rdev, ib); + if (r) { + radeon_scratch_free(rdev, scratch); + radeon_ib_free(rdev, &ib); + return r; + } + r = radeon_fence_wait(ib->fence, false); + if (r) { + 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 succeeded in %u usecs\n", i); + } else { + DRM_ERROR("radeon: ib test failed (sracth(0x%04X)=0x%08X)\n", + scratch, tmp); + r = -EINVAL; + } + radeon_scratch_free(rdev, scratch); + radeon_ib_free(rdev, &ib); + return r; +} diff --git a/drivers/gpu/drm/radeon/r100d.h b/drivers/gpu/drm/radeon/r100d.h new file mode 100644 index 000000000000..6da7d92c321c --- /dev/null +++ b/drivers/gpu/drm/radeon/r100d.h @@ -0,0 +1,76 @@ +/* + * 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 + */ +#ifndef __R100D_H__ +#define __R100D_H__ + +#define CP_PACKET0 0x00000000 +#define PACKET0_BASE_INDEX_SHIFT 0 +#define PACKET0_BASE_INDEX_MASK (0x1ffff << 0) +#define PACKET0_COUNT_SHIFT 16 +#define PACKET0_COUNT_MASK (0x3fff << 16) +#define CP_PACKET1 0x40000000 +#define CP_PACKET2 0x80000000 +#define PACKET2_PAD_SHIFT 0 +#define PACKET2_PAD_MASK (0x3fffffff << 0) +#define CP_PACKET3 0xC0000000 +#define PACKET3_IT_OPCODE_SHIFT 8 +#define PACKET3_IT_OPCODE_MASK (0xff << 8) +#define PACKET3_COUNT_SHIFT 16 +#define PACKET3_COUNT_MASK (0x3fff << 16) +/* PACKET3 op code */ +#define PACKET3_NOP 0x10 +#define PACKET3_3D_DRAW_VBUF 0x28 +#define PACKET3_3D_DRAW_IMMD 0x29 +#define PACKET3_3D_DRAW_INDX 0x2A +#define PACKET3_3D_LOAD_VBPNTR 0x2F +#define PACKET3_INDX_BUFFER 0x33 +#define PACKET3_3D_DRAW_VBUF_2 0x34 +#define PACKET3_3D_DRAW_IMMD_2 0x35 +#define PACKET3_3D_DRAW_INDX_2 0x36 +#define PACKET3_BITBLT_MULTI 0x9B + +#define PACKET0(reg, n) (CP_PACKET0 | \ + REG_SET(PACKET0_BASE_INDEX, (reg) >> 2) | \ + REG_SET(PACKET0_COUNT, (n))) +#define PACKET2(v) (CP_PACKET2 | REG_SET(PACKET2_PAD, (v))) +#define PACKET3(op, n) (CP_PACKET3 | \ + REG_SET(PACKET3_IT_OPCODE, (op)) | \ + REG_SET(PACKET3_COUNT, (n))) + +#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) & 0x1FFF) << 2) +#define CP_PACKET0_GET_ONE_REG_WR(h) (((h) >> 15) & 1) +#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF) + +#endif diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 33a2c557eac4..a5f82f7beed6 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -33,6 +33,7 @@ #include "radeon_drm.h" #include "radeon_share.h" #include "r100_track.h" +#include "r300d.h" #include "r300_reg_safe.h" @@ -127,7 +128,7 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev) WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); rv370_pcie_gart_tlb_flush(rdev); DRM_INFO("PCIE GART of %uM enabled (table at 0x%08X).\n", - rdev->mc.gtt_size >> 20, table_addr); + (unsigned)(rdev->mc.gtt_size >> 20), table_addr); rdev->gart.ready = true; return 0; } diff --git a/drivers/gpu/drm/radeon/r300.h b/drivers/gpu/drm/radeon/r300.h deleted file mode 100644 index 8486b4da9d69..000000000000 --- a/drivers/gpu/drm/radeon/r300.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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 - */ -#ifndef R300_H -#define R300_H - -struct r300_asic { - const unsigned *reg_safe_bm; - unsigned reg_safe_bm_size; -}; - -#endif diff --git a/drivers/gpu/drm/radeon/r300d.h b/drivers/gpu/drm/radeon/r300d.h new file mode 100644 index 000000000000..63ec076f2cd4 --- /dev/null +++ b/drivers/gpu/drm/radeon/r300d.h @@ -0,0 +1,76 @@ +/* + * 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 + */ +#ifndef __R300D_H__ +#define __R300D_H__ + +#define CP_PACKET0 0x00000000 +#define PACKET0_BASE_INDEX_SHIFT 0 +#define PACKET0_BASE_INDEX_MASK (0x1ffff << 0) +#define PACKET0_COUNT_SHIFT 16 +#define PACKET0_COUNT_MASK (0x3fff << 16) +#define CP_PACKET1 0x40000000 +#define CP_PACKET2 0x80000000 +#define PACKET2_PAD_SHIFT 0 +#define PACKET2_PAD_MASK (0x3fffffff << 0) +#define CP_PACKET3 0xC0000000 +#define PACKET3_IT_OPCODE_SHIFT 8 +#define PACKET3_IT_OPCODE_MASK (0xff << 8) +#define PACKET3_COUNT_SHIFT 16 +#define PACKET3_COUNT_MASK (0x3fff << 16) +/* PACKET3 op code */ +#define PACKET3_NOP 0x10 +#define PACKET3_3D_DRAW_VBUF 0x28 +#define PACKET3_3D_DRAW_IMMD 0x29 +#define PACKET3_3D_DRAW_INDX 0x2A +#define PACKET3_3D_LOAD_VBPNTR 0x2F +#define PACKET3_INDX_BUFFER 0x33 +#define PACKET3_3D_DRAW_VBUF_2 0x34 +#define PACKET3_3D_DRAW_IMMD_2 0x35 +#define PACKET3_3D_DRAW_INDX_2 0x36 +#define PACKET3_BITBLT_MULTI 0x9B + +#define PACKET0(reg, n) (CP_PACKET0 | \ + REG_SET(PACKET0_BASE_INDEX, (reg) >> 2) | \ + REG_SET(PACKET0_COUNT, (n))) +#define PACKET2(v) (CP_PACKET2 | REG_SET(PACKET2_PAD, (v))) +#define PACKET3(op, n) (CP_PACKET3 | \ + REG_SET(PACKET3_IT_OPCODE, (op)) | \ + REG_SET(PACKET3_COUNT, (n))) + +#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) & 0x1FFF) << 2) +#define CP_PACKET0_GET_ONE_REG_WR(h) (((h) >> 15) & 1) +#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF) + +#endif diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 538cd907df69..d8fcef44a69f 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -25,12 +25,46 @@ * Alex Deucher * Jerome Glisse */ +#include +#include +#include #include "drmP.h" -#include "radeon_reg.h" +#include "radeon_drm.h" #include "radeon.h" +#include "radeon_mode.h" +#include "radeon_share.h" +#include "r600d.h" +#include "avivod.h" +#include "atom.h" -/* r600,rv610,rv630,rv620,rv635,rv670 depends on : */ -void rs600_mc_disable_clients(struct radeon_device *rdev); +#define PFP_UCODE_SIZE 576 +#define PM4_UCODE_SIZE 1792 +#define R700_PFP_UCODE_SIZE 848 +#define R700_PM4_UCODE_SIZE 1360 + +/* Firmware Names */ +MODULE_FIRMWARE("radeon/R600_pfp.bin"); +MODULE_FIRMWARE("radeon/R600_me.bin"); +MODULE_FIRMWARE("radeon/RV610_pfp.bin"); +MODULE_FIRMWARE("radeon/RV610_me.bin"); +MODULE_FIRMWARE("radeon/RV630_pfp.bin"); +MODULE_FIRMWARE("radeon/RV630_me.bin"); +MODULE_FIRMWARE("radeon/RV620_pfp.bin"); +MODULE_FIRMWARE("radeon/RV620_me.bin"); +MODULE_FIRMWARE("radeon/RV635_pfp.bin"); +MODULE_FIRMWARE("radeon/RV635_me.bin"); +MODULE_FIRMWARE("radeon/RV670_pfp.bin"); +MODULE_FIRMWARE("radeon/RV670_me.bin"); +MODULE_FIRMWARE("radeon/RS780_pfp.bin"); +MODULE_FIRMWARE("radeon/RS780_me.bin"); +MODULE_FIRMWARE("radeon/RV770_pfp.bin"); +MODULE_FIRMWARE("radeon/RV770_me.bin"); +MODULE_FIRMWARE("radeon/RV730_pfp.bin"); +MODULE_FIRMWARE("radeon/RV730_me.bin"); +MODULE_FIRMWARE("radeon/RV710_pfp.bin"); +MODULE_FIRMWARE("radeon/RV710_me.bin"); + +int r600_debugfs_mc_info_init(struct radeon_device *rdev); /* This files gather functions specifics to: * r600,rv610,rv630,rv620,rv635,rv670 @@ -39,87 +73,270 @@ void rs600_mc_disable_clients(struct radeon_device *rdev); */ int r600_mc_wait_for_idle(struct radeon_device *rdev); void r600_gpu_init(struct radeon_device *rdev); +void r600_fini(struct radeon_device *rdev); /* - * MC + * R600 PCIE GART */ -int r600_mc_init(struct radeon_device *rdev) +int r600_gart_clear_page(struct radeon_device *rdev, int i) { - uint32_t tmp; + void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + u64 pte; - r600_gpu_init(rdev); + if (i < 0 || i > rdev->gart.num_gpu_pages) + return -EINVAL; + pte = 0; + writeq(pte, ((void __iomem *)ptr) + (i * 8)); + return 0; +} - /* setup the gart before changing location so we can ask to - * discard unmapped mc request - */ - /* FIXME: disable out of gart access */ - tmp = rdev->mc.gtt_location / 4096; - tmp = REG_SET(R600_LOGICAL_PAGE_NUMBER, tmp); - WREG32(R600_MC_VM_SYSTEM_APERTURE_LOW_ADDR, tmp); - tmp = (rdev->mc.gtt_location + rdev->mc.gtt_size) / 4096; - tmp = REG_SET(R600_LOGICAL_PAGE_NUMBER, tmp); - WREG32(R600_MC_VM_SYSTEM_APERTURE_HIGH_ADDR, tmp); - - rs600_mc_disable_clients(rdev); - if (r600_mc_wait_for_idle(rdev)) { - printk(KERN_WARNING "Failed to wait MC idle while " - "programming pipes. Bad things might happen.\n"); +void r600_pcie_gart_tlb_flush(struct radeon_device *rdev) +{ + unsigned i; + u32 tmp; + + WREG32(VM_CONTEXT0_INVALIDATION_LOW_ADDR, rdev->mc.gtt_start >> 12); + WREG32(VM_CONTEXT0_INVALIDATION_HIGH_ADDR, (rdev->mc.gtt_end - 1) >> 12); + WREG32(VM_CONTEXT0_REQUEST_RESPONSE, REQUEST_TYPE(1)); + for (i = 0; i < rdev->usec_timeout; i++) { + /* read MC_STATUS */ + tmp = RREG32(VM_CONTEXT0_REQUEST_RESPONSE); + tmp = (tmp & RESPONSE_TYPE_MASK) >> RESPONSE_TYPE_SHIFT; + if (tmp == 2) { + printk(KERN_WARNING "[drm] r600 flush TLB failed\n"); + return; + } + if (tmp) { + return; + } + udelay(1); + } +} + +int r600_pcie_gart_enable(struct radeon_device *rdev) +{ + u32 tmp; + int r, i; + + /* Initialize common gart structure */ + r = radeon_gart_init(rdev); + if (r) { + return r; + } + rdev->gart.table_size = rdev->gart.num_gpu_pages * 8; + r = radeon_gart_table_vram_alloc(rdev); + if (r) { + return r; } + for (i = 0; i < rdev->gart.num_gpu_pages; i++) + r600_gart_clear_page(rdev, i); + /* Setup L2 cache */ + WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING | + ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE | + EFFECTIVE_L2_QUEUE_SIZE(7)); + WREG32(VM_L2_CNTL2, 0); + WREG32(VM_L2_CNTL3, BANK_SELECT_0(0) | BANK_SELECT_1(1)); + /* Setup TLB control */ + tmp = ENABLE_L1_TLB | ENABLE_L1_FRAGMENT_PROCESSING | + SYSTEM_ACCESS_MODE_NOT_IN_SYS | + EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5) | + ENABLE_WAIT_L2_QUERY; + WREG32(MC_VM_L1_TLB_MCB_RD_SYS_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_WR_SYS_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_RD_HDP_CNTL, tmp | ENABLE_L1_STRICT_ORDERING); + WREG32(MC_VM_L1_TLB_MCB_WR_HDP_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCD_RD_A_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCD_WR_A_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCD_RD_B_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCD_WR_B_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_RD_GFX_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_WR_GFX_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_RD_PDMA_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_WR_PDMA_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_RD_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE); + WREG32(MC_VM_L1_TLB_MCB_WR_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE); + WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12); + WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, (rdev->mc.gtt_end - 1) >> 12); + WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12); + WREG32(VM_CONTEXT0_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) | + RANGE_PROTECTION_FAULT_ENABLE_DEFAULT); + WREG32(VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, + (u32)(rdev->dummy_page.addr >> 12)); + for (i = 1; i < 7; i++) + WREG32(VM_CONTEXT0_CNTL + (i * 4), 0); - tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1; - tmp = REG_SET(R600_MC_FB_TOP, tmp >> 24); - tmp |= REG_SET(R600_MC_FB_BASE, rdev->mc.vram_location >> 24); - WREG32(R600_MC_VM_FB_LOCATION, tmp); - tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; - tmp = REG_SET(R600_MC_AGP_TOP, tmp >> 22); - WREG32(R600_MC_VM_AGP_TOP, tmp); - tmp = REG_SET(R600_MC_AGP_BOT, rdev->mc.gtt_location >> 22); - WREG32(R600_MC_VM_AGP_BOT, tmp); + r600_pcie_gart_tlb_flush(rdev); + rdev->gart.ready = true; return 0; } -void r600_mc_fini(struct radeon_device *rdev) +void r600_pcie_gart_disable(struct radeon_device *rdev) { - /* FIXME: implement */ -} + u32 tmp; + int i; + /* Clear ptes*/ + for (i = 0; i < rdev->gart.num_gpu_pages; i++) + r600_gart_clear_page(rdev, i); + r600_pcie_gart_tlb_flush(rdev); + /* Disable all tables */ + for (i = 0; i < 7; i++) + WREG32(VM_CONTEXT0_CNTL + (i * 4), 0); -/* - * Global GPU functions - */ -void r600_errata(struct radeon_device *rdev) -{ - rdev->pll_errata = 0; + /* Disable L2 cache */ + WREG32(VM_L2_CNTL, ENABLE_L2_FRAGMENT_PROCESSING | + EFFECTIVE_L2_QUEUE_SIZE(7)); + WREG32(VM_L2_CNTL3, BANK_SELECT_0(0) | BANK_SELECT_1(1)); + /* Setup L1 TLB control */ + tmp = EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5) | + ENABLE_WAIT_L2_QUERY; + WREG32(MC_VM_L1_TLB_MCD_RD_A_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCD_WR_A_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCD_RD_B_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCD_WR_B_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_RD_GFX_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_WR_GFX_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_RD_PDMA_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_WR_PDMA_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_RD_SEM_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_WR_SEM_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_RD_SYS_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_WR_SYS_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_RD_HDP_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_WR_HDP_CNTL, tmp); } int r600_mc_wait_for_idle(struct radeon_device *rdev) { - /* FIXME: implement */ - return 0; + unsigned i; + u32 tmp; + + for (i = 0; i < rdev->usec_timeout; i++) { + /* read MC_STATUS */ + tmp = RREG32(R_000E50_SRBM_STATUS) & 0x3F00; + if (!tmp) + return 0; + udelay(1); + } + return -1; } -void r600_gpu_init(struct radeon_device *rdev) +static void r600_mc_resume(struct radeon_device *rdev) { - /* FIXME: implement */ -} + u32 d1vga_control, d2vga_control; + u32 vga_render_control, vga_hdp_control; + u32 d1crtc_control, d2crtc_control; + u32 new_d1grph_primary, new_d1grph_secondary; + u32 new_d2grph_primary, new_d2grph_secondary; + u64 old_vram_start; + 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); -/* - * VRAM info - */ -void r600_vram_get_type(struct radeon_device *rdev) + d1vga_control = RREG32(D1VGA_CONTROL); + d2vga_control = RREG32(D2VGA_CONTROL); + vga_render_control = RREG32(VGA_RENDER_CONTROL); + vga_hdp_control = RREG32(VGA_HDP_CONTROL); + d1crtc_control = RREG32(D1CRTC_CONTROL); + d2crtc_control = RREG32(D2CRTC_CONTROL); + old_vram_start = (u64)(RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24; + new_d1grph_primary = RREG32(D1GRPH_PRIMARY_SURFACE_ADDRESS); + new_d1grph_secondary = RREG32(D1GRPH_SECONDARY_SURFACE_ADDRESS); + new_d1grph_primary += rdev->mc.vram_start - old_vram_start; + new_d1grph_secondary += rdev->mc.vram_start - old_vram_start; + new_d2grph_primary = RREG32(D2GRPH_PRIMARY_SURFACE_ADDRESS); + new_d2grph_secondary = RREG32(D2GRPH_SECONDARY_SURFACE_ADDRESS); + new_d2grph_primary += rdev->mc.vram_start - old_vram_start; + new_d2grph_secondary += rdev->mc.vram_start - old_vram_start; + + /* Stop all video */ + WREG32(D1VGA_CONTROL, 0); + WREG32(D2VGA_CONTROL, 0); + WREG32(VGA_RENDER_CONTROL, 0); + WREG32(D1CRTC_UPDATE_LOCK, 1); + WREG32(D2CRTC_UPDATE_LOCK, 1); + WREG32(D1CRTC_CONTROL, 0); + WREG32(D2CRTC_CONTROL, 0); + WREG32(D1CRTC_UPDATE_LOCK, 0); + WREG32(D2CRTC_UPDATE_LOCK, 0); + + mdelay(1); + if (r600_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "[drm] MC not idle !\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 - 1) >> 12); + WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0); + tmp = (((rdev->mc.vram_end - 1) >> 24) & 0xFFFF) << 16; + tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); + WREG32(MC_VM_FB_LOCATION, tmp); + WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8)); + WREG32(HDP_NONSURFACE_INFO, (2 << 7)); + WREG32(HDP_NONSURFACE_SIZE, (rdev->mc.mc_vram_size - 1) | 0x3FF); + if (rdev->flags & RADEON_IS_AGP) { + WREG32(MC_VM_AGP_TOP, (rdev->mc.gtt_end - 1) >> 16); + WREG32(MC_VM_AGP_BOT, rdev->mc.gtt_start >> 16); + WREG32(MC_VM_AGP_BASE, rdev->mc.agp_base >> 22); + } else { + WREG32(MC_VM_AGP_BASE, 0); + WREG32(MC_VM_AGP_TOP, 0x0FFFFFFF); + WREG32(MC_VM_AGP_BOT, 0x0FFFFFFF); + } + WREG32(D1GRPH_PRIMARY_SURFACE_ADDRESS, new_d1grph_primary); + WREG32(D1GRPH_SECONDARY_SURFACE_ADDRESS, new_d1grph_secondary); + WREG32(D2GRPH_PRIMARY_SURFACE_ADDRESS, new_d2grph_primary); + WREG32(D2GRPH_SECONDARY_SURFACE_ADDRESS, new_d2grph_secondary); + WREG32(VGA_MEMORY_BASE_ADDRESS, rdev->mc.vram_start); + + /* Unlock host access */ + WREG32(VGA_HDP_CONTROL, vga_hdp_control); + + mdelay(1); + if (r600_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "[drm] MC not idle !\n"); + } + + /* Restore video state */ + WREG32(D1CRTC_UPDATE_LOCK, 1); + WREG32(D2CRTC_UPDATE_LOCK, 1); + WREG32(D1CRTC_CONTROL, d1crtc_control); + WREG32(D2CRTC_CONTROL, d2crtc_control); + WREG32(D1CRTC_UPDATE_LOCK, 0); + WREG32(D2CRTC_UPDATE_LOCK, 0); + WREG32(D1VGA_CONTROL, d1vga_control); + WREG32(D2VGA_CONTROL, d2vga_control); + WREG32(VGA_RENDER_CONTROL, vga_render_control); +} + +int r600_mc_init(struct radeon_device *rdev) { - uint32_t tmp; + fixed20_12 a; + u32 tmp; int chansize; + int r; + /* Get VRAM informations */ rdev->mc.vram_width = 128; rdev->mc.vram_is_ddr = true; - - tmp = RREG32(R600_RAMCFG); - if (tmp & R600_CHANSIZE_OVERRIDE) { + tmp = RREG32(RAMCFG); + if (tmp & CHANSIZE_OVERRIDE) { chansize = 16; - } else if (tmp & R600_CHANSIZE) { + } else if (tmp & CHANSIZE_MASK) { chansize = 64; } else { chansize = 32; @@ -135,36 +352,1391 @@ void r600_vram_get_type(struct radeon_device *rdev) (rdev->family == CHIP_RV635)) { rdev->mc.vram_width = 2 * chansize; } + /* Could aper size report 0 ? */ + rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); + rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); + /* Setup GPU memory space */ + rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE); + rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE); + if (rdev->flags & RADEON_IS_AGP) { + r = radeon_agp_init(rdev); + if (r) + return r; + /* gtt_size is setup by radeon_agp_init */ + rdev->mc.gtt_location = rdev->mc.agp_base; + tmp = 0xFFFFFFFFUL - rdev->mc.agp_base - rdev->mc.gtt_size; + /* Try to put vram before or after AGP because we + * we want SYSTEM_APERTURE to cover both VRAM and + * AGP so that GPU can catch out of VRAM/AGP access + */ + if (rdev->mc.gtt_location > rdev->mc.mc_vram_size) { + /* Enought place before */ + rdev->mc.vram_location = rdev->mc.gtt_location - + rdev->mc.mc_vram_size; + } else if (tmp > rdev->mc.mc_vram_size) { + /* Enought place after */ + rdev->mc.vram_location = rdev->mc.gtt_location + + rdev->mc.gtt_size; + } else { + /* Try to setup VRAM then AGP might not + * not work on some card + */ + rdev->mc.vram_location = 0x00000000UL; + rdev->mc.gtt_location = rdev->mc.mc_vram_size; + } + } else { + if (rdev->family == CHIP_RS780 || rdev->family == CHIP_RS880) { + rdev->mc.vram_location = (RREG32(MC_VM_FB_LOCATION) & + 0xFFFF) << 24; + rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size; + if ((0xFFFFFFFFUL - tmp) >= rdev->mc.gtt_size) { + /* Enough place after vram */ + rdev->mc.gtt_location = tmp; + } else if (rdev->mc.vram_location >= rdev->mc.gtt_size) { + /* Enough place before vram */ + rdev->mc.gtt_location = 0; + } else { + /* Not enough place after or before shrink + * gart size + */ + if (rdev->mc.vram_location > (0xFFFFFFFFUL - tmp)) { + rdev->mc.gtt_location = 0; + rdev->mc.gtt_size = rdev->mc.vram_location; + } else { + rdev->mc.gtt_location = tmp; + rdev->mc.gtt_size = 0xFFFFFFFFUL - tmp; + } + } + rdev->mc.gtt_location = rdev->mc.mc_vram_size; + } else { + rdev->mc.vram_location = 0x00000000UL; + rdev->mc.gtt_location = rdev->mc.mc_vram_size; + rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + } + } + rdev->mc.vram_start = rdev->mc.vram_location; + rdev->mc.vram_end = rdev->mc.vram_location + rdev->mc.mc_vram_size; + rdev->mc.gtt_start = rdev->mc.gtt_location; + rdev->mc.gtt_end = rdev->mc.gtt_location + rdev->mc.gtt_size; + /* FIXME: we should enforce default clock in case GPU is not in + * default setup + */ + a.full = rfixed_const(100); + rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk); + rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); + return 0; } -void r600_vram_info(struct radeon_device *rdev) +/* We doesn't check that the GPU really needs a reset we simply do the + * reset, it's up to the caller to determine if the GPU needs one. We + * might add an helper function to check that. + */ +int r600_gpu_soft_reset(struct radeon_device *rdev) { - r600_vram_get_type(rdev); - rdev->mc.real_vram_size = RREG32(R600_CONFIG_MEMSIZE); - rdev->mc.mc_vram_size = rdev->mc.real_vram_size; + u32 grbm_busy_mask = S_008010_VC_BUSY(1) | S_008010_VGT_BUSY_NO_DMA(1) | + S_008010_VGT_BUSY(1) | S_008010_TA03_BUSY(1) | + S_008010_TC_BUSY(1) | S_008010_SX_BUSY(1) | + S_008010_SH_BUSY(1) | S_008010_SPI03_BUSY(1) | + S_008010_SMX_BUSY(1) | S_008010_SC_BUSY(1) | + S_008010_PA_BUSY(1) | S_008010_DB03_BUSY(1) | + S_008010_CR_BUSY(1) | S_008010_CB03_BUSY(1) | + S_008010_GUI_ACTIVE(1); + u32 grbm2_busy_mask = S_008014_SPI0_BUSY(1) | S_008014_SPI1_BUSY(1) | + S_008014_SPI2_BUSY(1) | S_008014_SPI3_BUSY(1) | + S_008014_TA0_BUSY(1) | S_008014_TA1_BUSY(1) | + S_008014_TA2_BUSY(1) | S_008014_TA3_BUSY(1) | + S_008014_DB0_BUSY(1) | S_008014_DB1_BUSY(1) | + S_008014_DB2_BUSY(1) | S_008014_DB3_BUSY(1) | + S_008014_CB0_BUSY(1) | S_008014_CB1_BUSY(1) | + S_008014_CB2_BUSY(1) | S_008014_CB3_BUSY(1); + u32 srbm_reset = 0; - /* Could aper size report 0 ? */ - rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); - rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); + /* Disable CP parsing/prefetching */ + WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(0xff)); + /* Check if any of the rendering block is busy and reset it */ + if ((RREG32(R_008010_GRBM_STATUS) & grbm_busy_mask) || + (RREG32(R_008014_GRBM_STATUS2) & grbm2_busy_mask)) { + WREG32(R_008020_GRBM_SOFT_RESET, S_008020_SOFT_RESET_CR(1) | + S_008020_SOFT_RESET_DB(1) | + S_008020_SOFT_RESET_CB(1) | + S_008020_SOFT_RESET_PA(1) | + S_008020_SOFT_RESET_SC(1) | + S_008020_SOFT_RESET_SMX(1) | + S_008020_SOFT_RESET_SPI(1) | + S_008020_SOFT_RESET_SX(1) | + S_008020_SOFT_RESET_SH(1) | + S_008020_SOFT_RESET_TC(1) | + S_008020_SOFT_RESET_TA(1) | + S_008020_SOFT_RESET_VC(1) | + S_008020_SOFT_RESET_VGT(1)); + (void)RREG32(R_008020_GRBM_SOFT_RESET); + udelay(50); + WREG32(R_008020_GRBM_SOFT_RESET, 0); + (void)RREG32(R_008020_GRBM_SOFT_RESET); + } + /* Reset CP (we always reset CP) */ + WREG32(R_008020_GRBM_SOFT_RESET, S_008020_SOFT_RESET_CP(1)); + (void)RREG32(R_008020_GRBM_SOFT_RESET); + udelay(50); + WREG32(R_008020_GRBM_SOFT_RESET, 0); + (void)RREG32(R_008020_GRBM_SOFT_RESET); + /* Reset others GPU block if necessary */ + if (G_000E50_RLC_BUSY(RREG32(R_000E50_SRBM_STATUS))) + srbm_reset |= S_000E60_SOFT_RESET_RLC(1); + if (G_000E50_GRBM_RQ_PENDING(RREG32(R_000E50_SRBM_STATUS))) + srbm_reset |= S_000E60_SOFT_RESET_GRBM(1); + if (G_000E50_HI_RQ_PENDING(RREG32(R_000E50_SRBM_STATUS))) + srbm_reset |= S_000E60_SOFT_RESET_IH(1); + if (G_000E50_VMC_BUSY(RREG32(R_000E50_SRBM_STATUS))) + srbm_reset |= S_000E60_SOFT_RESET_VMC(1); + if (G_000E50_MCB_BUSY(RREG32(R_000E50_SRBM_STATUS))) + srbm_reset |= S_000E60_SOFT_RESET_MC(1); + if (G_000E50_MCDZ_BUSY(RREG32(R_000E50_SRBM_STATUS))) + srbm_reset |= S_000E60_SOFT_RESET_MC(1); + if (G_000E50_MCDY_BUSY(RREG32(R_000E50_SRBM_STATUS))) + srbm_reset |= S_000E60_SOFT_RESET_MC(1); + if (G_000E50_MCDX_BUSY(RREG32(R_000E50_SRBM_STATUS))) + srbm_reset |= S_000E60_SOFT_RESET_MC(1); + if (G_000E50_MCDW_BUSY(RREG32(R_000E50_SRBM_STATUS))) + srbm_reset |= S_000E60_SOFT_RESET_MC(1); + if (G_000E50_RLC_BUSY(RREG32(R_000E50_SRBM_STATUS))) + srbm_reset |= S_000E60_SOFT_RESET_RLC(1); + if (G_000E50_SEM_BUSY(RREG32(R_000E50_SRBM_STATUS))) + srbm_reset |= S_000E60_SOFT_RESET_SEM(1); + WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset); + (void)RREG32(R_000E60_SRBM_SOFT_RESET); + udelay(50); + WREG32(R_000E60_SRBM_SOFT_RESET, 0); + (void)RREG32(R_000E60_SRBM_SOFT_RESET); + /* Wait a little for things to settle down */ + udelay(50); + return 0; +} + +int r600_gpu_reset(struct radeon_device *rdev) +{ + return r600_gpu_soft_reset(rdev); +} + +static u32 r600_get_tile_pipe_to_backend_map(u32 num_tile_pipes, + u32 num_backends, + u32 backend_disable_mask) +{ + u32 backend_map = 0; + u32 enabled_backends_mask; + u32 enabled_backends_count; + u32 cur_pipe; + u32 swizzle_pipe[R6XX_MAX_PIPES]; + u32 cur_backend; + u32 i; + + if (num_tile_pipes > R6XX_MAX_PIPES) + num_tile_pipes = R6XX_MAX_PIPES; + if (num_tile_pipes < 1) + num_tile_pipes = 1; + if (num_backends > R6XX_MAX_BACKENDS) + num_backends = R6XX_MAX_BACKENDS; + if (num_backends < 1) + num_backends = 1; + + enabled_backends_mask = 0; + enabled_backends_count = 0; + for (i = 0; i < R6XX_MAX_BACKENDS; ++i) { + if (((backend_disable_mask >> i) & 1) == 0) { + enabled_backends_mask |= (1 << i); + ++enabled_backends_count; + } + if (enabled_backends_count == num_backends) + break; + } + + if (enabled_backends_count == 0) { + enabled_backends_mask = 1; + enabled_backends_count = 1; + } + + if (enabled_backends_count != num_backends) + num_backends = enabled_backends_count; + + memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * R6XX_MAX_PIPES); + switch (num_tile_pipes) { + case 1: + swizzle_pipe[0] = 0; + break; + case 2: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + break; + case 3: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + break; + case 4: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + break; + case 5: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + swizzle_pipe[4] = 4; + break; + case 6: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 5; + swizzle_pipe[4] = 1; + swizzle_pipe[5] = 3; + break; + case 7: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 6; + swizzle_pipe[4] = 1; + swizzle_pipe[5] = 3; + swizzle_pipe[6] = 5; + break; + case 8: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 6; + swizzle_pipe[4] = 1; + swizzle_pipe[5] = 3; + swizzle_pipe[6] = 5; + swizzle_pipe[7] = 7; + break; + } + + cur_backend = 0; + for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) { + while (((1 << cur_backend) & enabled_backends_mask) == 0) + cur_backend = (cur_backend + 1) % R6XX_MAX_BACKENDS; + + backend_map |= (u32)(((cur_backend & 3) << (swizzle_pipe[cur_pipe] * 2))); + + cur_backend = (cur_backend + 1) % R6XX_MAX_BACKENDS; + } + + return backend_map; +} + +int r600_count_pipe_bits(uint32_t val) +{ + int i, ret = 0; + + for (i = 0; i < 32; i++) { + ret += val & 1; + val >>= 1; + } + return ret; } +void r600_gpu_init(struct radeon_device *rdev) +{ + u32 tiling_config; + u32 ramcfg; + u32 tmp; + int i, j; + u32 sq_config; + u32 sq_gpr_resource_mgmt_1 = 0; + u32 sq_gpr_resource_mgmt_2 = 0; + u32 sq_thread_resource_mgmt = 0; + u32 sq_stack_resource_mgmt_1 = 0; + u32 sq_stack_resource_mgmt_2 = 0; + + /* FIXME: implement */ + switch (rdev->family) { + case CHIP_R600: + rdev->config.r600.max_pipes = 4; + rdev->config.r600.max_tile_pipes = 8; + rdev->config.r600.max_simds = 4; + rdev->config.r600.max_backends = 4; + rdev->config.r600.max_gprs = 256; + rdev->config.r600.max_threads = 192; + rdev->config.r600.max_stack_entries = 256; + rdev->config.r600.max_hw_contexts = 8; + rdev->config.r600.max_gs_threads = 16; + rdev->config.r600.sx_max_export_size = 128; + rdev->config.r600.sx_max_export_pos_size = 16; + rdev->config.r600.sx_max_export_smx_size = 128; + rdev->config.r600.sq_num_cf_insts = 2; + break; + case CHIP_RV630: + case CHIP_RV635: + rdev->config.r600.max_pipes = 2; + rdev->config.r600.max_tile_pipes = 2; + rdev->config.r600.max_simds = 3; + rdev->config.r600.max_backends = 1; + rdev->config.r600.max_gprs = 128; + rdev->config.r600.max_threads = 192; + rdev->config.r600.max_stack_entries = 128; + rdev->config.r600.max_hw_contexts = 8; + rdev->config.r600.max_gs_threads = 4; + rdev->config.r600.sx_max_export_size = 128; + rdev->config.r600.sx_max_export_pos_size = 16; + rdev->config.r600.sx_max_export_smx_size = 128; + rdev->config.r600.sq_num_cf_insts = 2; + break; + case CHIP_RV610: + case CHIP_RV620: + case CHIP_RS780: + case CHIP_RS880: + rdev->config.r600.max_pipes = 1; + rdev->config.r600.max_tile_pipes = 1; + rdev->config.r600.max_simds = 2; + rdev->config.r600.max_backends = 1; + rdev->config.r600.max_gprs = 128; + rdev->config.r600.max_threads = 192; + rdev->config.r600.max_stack_entries = 128; + rdev->config.r600.max_hw_contexts = 4; + rdev->config.r600.max_gs_threads = 4; + rdev->config.r600.sx_max_export_size = 128; + rdev->config.r600.sx_max_export_pos_size = 16; + rdev->config.r600.sx_max_export_smx_size = 128; + rdev->config.r600.sq_num_cf_insts = 1; + break; + case CHIP_RV670: + rdev->config.r600.max_pipes = 4; + rdev->config.r600.max_tile_pipes = 4; + rdev->config.r600.max_simds = 4; + rdev->config.r600.max_backends = 4; + rdev->config.r600.max_gprs = 192; + rdev->config.r600.max_threads = 192; + rdev->config.r600.max_stack_entries = 256; + rdev->config.r600.max_hw_contexts = 8; + rdev->config.r600.max_gs_threads = 16; + rdev->config.r600.sx_max_export_size = 128; + rdev->config.r600.sx_max_export_pos_size = 16; + rdev->config.r600.sx_max_export_smx_size = 128; + rdev->config.r600.sq_num_cf_insts = 2; + break; + default: + 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)); + + /* Setup tiling */ + tiling_config = 0; + ramcfg = RREG32(RAMCFG); + switch (rdev->config.r600.max_tile_pipes) { + case 1: + tiling_config |= PIPE_TILING(0); + break; + case 2: + tiling_config |= PIPE_TILING(1); + break; + case 4: + tiling_config |= PIPE_TILING(2); + break; + case 8: + tiling_config |= PIPE_TILING(3); + break; + default: + break; + } + tiling_config |= BANK_TILING((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT); + tiling_config |= GROUP_SIZE(0); + tmp = (ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT; + if (tmp > 3) { + tiling_config |= ROW_TILING(3); + tiling_config |= SAMPLE_SPLIT(3); + } else { + tiling_config |= ROW_TILING(tmp); + tiling_config |= SAMPLE_SPLIT(tmp); + } + tiling_config |= BANK_SWAPS(1); + tmp = r600_get_tile_pipe_to_backend_map(rdev->config.r600.max_tile_pipes, + rdev->config.r600.max_backends, + (0xff << rdev->config.r600.max_backends) & 0xff); + tiling_config |= BACKEND_MAP(tmp); + WREG32(GB_TILING_CONFIG, tiling_config); + WREG32(DCP_TILING_CONFIG, tiling_config & 0xffff); + WREG32(HDP_TILING_CONFIG, tiling_config & 0xffff); + + tmp = BACKEND_DISABLE((R6XX_MAX_BACKENDS_MASK << rdev->config.r600.max_backends) & R6XX_MAX_BACKENDS_MASK); + WREG32(CC_RB_BACKEND_DISABLE, tmp); + + /* Setup pipes */ + tmp = INACTIVE_QD_PIPES((R6XX_MAX_PIPES_MASK << rdev->config.r600.max_pipes) & R6XX_MAX_PIPES_MASK); + tmp |= INACTIVE_SIMDS((R6XX_MAX_SIMDS_MASK << rdev->config.r600.max_simds) & R6XX_MAX_SIMDS_MASK); + WREG32(CC_GC_SHADER_PIPE_CONFIG, tmp); + WREG32(GC_USER_SHADER_PIPE_CONFIG, tmp); + + tmp = R6XX_MAX_BACKENDS - r600_count_pipe_bits(tmp & INACTIVE_QD_PIPES_MASK); + WREG32(VGT_OUT_DEALLOC_CNTL, (tmp * 4) & DEALLOC_DIST_MASK); + WREG32(VGT_VERTEX_REUSE_BLOCK_CNTL, ((tmp * 4) - 2) & VTX_REUSE_DEPTH_MASK); + + /* Setup some CP states */ + WREG32(CP_QUEUE_THRESHOLDS, (ROQ_IB1_START(0x16) | ROQ_IB2_START(0x2b))); + WREG32(CP_MEQ_THRESHOLDS, (MEQ_END(0x40) | ROQ_END(0x40))); + + WREG32(TA_CNTL_AUX, (DISABLE_CUBE_ANISO | SYNC_GRADIENT | + SYNC_WALKER | SYNC_ALIGNER)); + /* Setup various GPU states */ + if (rdev->family == CHIP_RV670) + WREG32(ARB_GDEC_RD_CNTL, 0x00000021); + + tmp = RREG32(SX_DEBUG_1); + tmp |= SMX_EVENT_RELEASE; + if ((rdev->family > CHIP_R600)) + tmp |= ENABLE_NEW_SMX_ADDRESS; + WREG32(SX_DEBUG_1, tmp); + + if (((rdev->family) == CHIP_R600) || + ((rdev->family) == CHIP_RV630) || + ((rdev->family) == CHIP_RV610) || + ((rdev->family) == CHIP_RV620) || + ((rdev->family) == CHIP_RS780)) { + WREG32(DB_DEBUG, PREZ_MUST_WAIT_FOR_POSTZ_DONE); + } else { + WREG32(DB_DEBUG, 0); + } + WREG32(DB_WATERMARKS, (DEPTH_FREE(4) | DEPTH_CACHELINE_FREE(16) | + DEPTH_FLUSH(16) | DEPTH_PENDING_FREE(4))); + + WREG32(PA_SC_MULTI_CHIP_CNTL, 0); + WREG32(VGT_NUM_INSTANCES, 0); + + WREG32(SPI_CONFIG_CNTL, GPR_WRITE_PRIORITY(0)); + WREG32(SPI_CONFIG_CNTL_1, VTX_DONE_DELAY(0)); + + tmp = RREG32(SQ_MS_FIFO_SIZES); + if (((rdev->family) == CHIP_RV610) || + ((rdev->family) == CHIP_RV620) || + ((rdev->family) == CHIP_RS780)) { + tmp = (CACHE_FIFO_SIZE(0xa) | + FETCH_FIFO_HIWATER(0xa) | + DONE_FIFO_HIWATER(0xe0) | + ALU_UPDATE_FIFO_HIWATER(0x8)); + } else if (((rdev->family) == CHIP_R600) || + ((rdev->family) == CHIP_RV630)) { + tmp &= ~DONE_FIFO_HIWATER(0xff); + tmp |= DONE_FIFO_HIWATER(0x4); + } + WREG32(SQ_MS_FIFO_SIZES, tmp); + + /* SQ_CONFIG, SQ_GPR_RESOURCE_MGMT, SQ_THREAD_RESOURCE_MGMT, SQ_STACK_RESOURCE_MGMT + * should be adjusted as needed by the 2D/3D drivers. This just sets default values + */ + sq_config = RREG32(SQ_CONFIG); + sq_config &= ~(PS_PRIO(3) | + VS_PRIO(3) | + GS_PRIO(3) | + ES_PRIO(3)); + sq_config |= (DX9_CONSTS | + VC_ENABLE | + PS_PRIO(0) | + VS_PRIO(1) | + GS_PRIO(2) | + ES_PRIO(3)); + + if ((rdev->family) == CHIP_R600) { + sq_gpr_resource_mgmt_1 = (NUM_PS_GPRS(124) | + NUM_VS_GPRS(124) | + NUM_CLAUSE_TEMP_GPRS(4)); + sq_gpr_resource_mgmt_2 = (NUM_GS_GPRS(0) | + NUM_ES_GPRS(0)); + sq_thread_resource_mgmt = (NUM_PS_THREADS(136) | + NUM_VS_THREADS(48) | + NUM_GS_THREADS(4) | + NUM_ES_THREADS(4)); + sq_stack_resource_mgmt_1 = (NUM_PS_STACK_ENTRIES(128) | + NUM_VS_STACK_ENTRIES(128)); + sq_stack_resource_mgmt_2 = (NUM_GS_STACK_ENTRIES(0) | + NUM_ES_STACK_ENTRIES(0)); + } else if (((rdev->family) == CHIP_RV610) || + ((rdev->family) == CHIP_RV620) || + ((rdev->family) == CHIP_RS780)) { + /* no vertex cache */ + sq_config &= ~VC_ENABLE; + + sq_gpr_resource_mgmt_1 = (NUM_PS_GPRS(44) | + NUM_VS_GPRS(44) | + NUM_CLAUSE_TEMP_GPRS(2)); + sq_gpr_resource_mgmt_2 = (NUM_GS_GPRS(17) | + NUM_ES_GPRS(17)); + sq_thread_resource_mgmt = (NUM_PS_THREADS(79) | + NUM_VS_THREADS(78) | + NUM_GS_THREADS(4) | + NUM_ES_THREADS(31)); + sq_stack_resource_mgmt_1 = (NUM_PS_STACK_ENTRIES(40) | + NUM_VS_STACK_ENTRIES(40)); + sq_stack_resource_mgmt_2 = (NUM_GS_STACK_ENTRIES(32) | + NUM_ES_STACK_ENTRIES(16)); + } else if (((rdev->family) == CHIP_RV630) || + ((rdev->family) == CHIP_RV635)) { + sq_gpr_resource_mgmt_1 = (NUM_PS_GPRS(44) | + NUM_VS_GPRS(44) | + NUM_CLAUSE_TEMP_GPRS(2)); + sq_gpr_resource_mgmt_2 = (NUM_GS_GPRS(18) | + NUM_ES_GPRS(18)); + sq_thread_resource_mgmt = (NUM_PS_THREADS(79) | + NUM_VS_THREADS(78) | + NUM_GS_THREADS(4) | + NUM_ES_THREADS(31)); + sq_stack_resource_mgmt_1 = (NUM_PS_STACK_ENTRIES(40) | + NUM_VS_STACK_ENTRIES(40)); + sq_stack_resource_mgmt_2 = (NUM_GS_STACK_ENTRIES(32) | + NUM_ES_STACK_ENTRIES(16)); + } else if ((rdev->family) == CHIP_RV670) { + sq_gpr_resource_mgmt_1 = (NUM_PS_GPRS(44) | + NUM_VS_GPRS(44) | + NUM_CLAUSE_TEMP_GPRS(2)); + sq_gpr_resource_mgmt_2 = (NUM_GS_GPRS(17) | + NUM_ES_GPRS(17)); + sq_thread_resource_mgmt = (NUM_PS_THREADS(79) | + NUM_VS_THREADS(78) | + NUM_GS_THREADS(4) | + NUM_ES_THREADS(31)); + sq_stack_resource_mgmt_1 = (NUM_PS_STACK_ENTRIES(64) | + NUM_VS_STACK_ENTRIES(64)); + sq_stack_resource_mgmt_2 = (NUM_GS_STACK_ENTRIES(64) | + NUM_ES_STACK_ENTRIES(64)); + } + + WREG32(SQ_CONFIG, sq_config); + WREG32(SQ_GPR_RESOURCE_MGMT_1, sq_gpr_resource_mgmt_1); + WREG32(SQ_GPR_RESOURCE_MGMT_2, sq_gpr_resource_mgmt_2); + WREG32(SQ_THREAD_RESOURCE_MGMT, sq_thread_resource_mgmt); + WREG32(SQ_STACK_RESOURCE_MGMT_1, sq_stack_resource_mgmt_1); + WREG32(SQ_STACK_RESOURCE_MGMT_2, sq_stack_resource_mgmt_2); + + if (((rdev->family) == CHIP_RV610) || + ((rdev->family) == CHIP_RV620) || + ((rdev->family) == CHIP_RS780)) { + WREG32(VGT_CACHE_INVALIDATION, CACHE_INVALIDATION(TC_ONLY)); + } else { + WREG32(VGT_CACHE_INVALIDATION, CACHE_INVALIDATION(VC_AND_TC)); + } + + /* More default values. 2D/3D driver should adjust as needed */ + WREG32(PA_SC_AA_SAMPLE_LOCS_2S, (S0_X(0xc) | S0_Y(0x4) | + S1_X(0x4) | S1_Y(0xc))); + WREG32(PA_SC_AA_SAMPLE_LOCS_4S, (S0_X(0xe) | S0_Y(0xe) | + S1_X(0x2) | S1_Y(0x2) | + S2_X(0xa) | S2_Y(0x6) | + S3_X(0x6) | S3_Y(0xa))); + WREG32(PA_SC_AA_SAMPLE_LOCS_8S_WD0, (S0_X(0xe) | S0_Y(0xb) | + S1_X(0x4) | S1_Y(0xc) | + S2_X(0x1) | S2_Y(0x6) | + S3_X(0xa) | S3_Y(0xe))); + WREG32(PA_SC_AA_SAMPLE_LOCS_8S_WD1, (S4_X(0x6) | S4_Y(0x1) | + S5_X(0x0) | S5_Y(0x0) | + S6_X(0xb) | S6_Y(0x4) | + S7_X(0x7) | S7_Y(0x8))); + + WREG32(VGT_STRMOUT_EN, 0); + tmp = rdev->config.r600.max_pipes * 16; + switch (rdev->family) { + case CHIP_RV610: + case CHIP_RS780: + case CHIP_RV620: + tmp += 32; + break; + case CHIP_RV670: + tmp += 128; + break; + default: + break; + } + if (tmp > 256) { + tmp = 256; + } + WREG32(VGT_ES_PER_GS, 128); + WREG32(VGT_GS_PER_ES, tmp); + WREG32(VGT_GS_PER_VS, 2); + WREG32(VGT_GS_VERTEX_REUSE, 16); + + /* more default values. 2D/3D driver should adjust as needed */ + WREG32(PA_SC_LINE_STIPPLE_STATE, 0); + WREG32(VGT_STRMOUT_EN, 0); + WREG32(SX_MISC, 0); + WREG32(PA_SC_MODE_CNTL, 0); + WREG32(PA_SC_AA_CONFIG, 0); + WREG32(PA_SC_LINE_STIPPLE, 0); + WREG32(SPI_INPUT_Z, 0); + WREG32(SPI_PS_IN_CONTROL_0, NUM_INTERP(2)); + WREG32(CB_COLOR7_FRAG, 0); + + /* Clear render buffer base addresses */ + WREG32(CB_COLOR0_BASE, 0); + WREG32(CB_COLOR1_BASE, 0); + WREG32(CB_COLOR2_BASE, 0); + WREG32(CB_COLOR3_BASE, 0); + WREG32(CB_COLOR4_BASE, 0); + WREG32(CB_COLOR5_BASE, 0); + WREG32(CB_COLOR6_BASE, 0); + WREG32(CB_COLOR7_BASE, 0); + WREG32(CB_COLOR7_FRAG, 0); + + switch (rdev->family) { + case CHIP_RV610: + case CHIP_RS780: + case CHIP_RV620: + tmp = TC_L2_SIZE(8); + break; + case CHIP_RV630: + case CHIP_RV635: + tmp = TC_L2_SIZE(4); + break; + case CHIP_R600: + tmp = TC_L2_SIZE(0) | L2_DISABLE_LATE_HIT; + break; + default: + tmp = TC_L2_SIZE(0); + break; + } + WREG32(TC_CNTL, tmp); + + tmp = RREG32(HDP_HOST_PATH_CNTL); + WREG32(HDP_HOST_PATH_CNTL, tmp); + + tmp = RREG32(ARB_POP); + tmp |= ENABLE_TC128; + WREG32(ARB_POP, tmp); + + WREG32(PA_SC_MULTI_CHIP_CNTL, 0); + WREG32(PA_CL_ENHANCE, (CLIP_VTX_REORDER_ENA | + NUM_CLIP_SEQ(3))); + WREG32(PA_SC_ENHANCE, FORCE_EOV_MAX_CLK_CNT(4095)); +} + + /* * Indirect registers accessor */ -uint32_t r600_pciep_rreg(struct radeon_device *rdev, uint32_t reg) +u32 r600_pciep_rreg(struct radeon_device *rdev, u32 reg) +{ + u32 r; + + WREG32(PCIE_PORT_INDEX, ((reg) & 0xff)); + (void)RREG32(PCIE_PORT_INDEX); + r = RREG32(PCIE_PORT_DATA); + return r; +} + +void r600_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v) +{ + WREG32(PCIE_PORT_INDEX, ((reg) & 0xff)); + (void)RREG32(PCIE_PORT_INDEX); + WREG32(PCIE_PORT_DATA, (v)); + (void)RREG32(PCIE_PORT_DATA); +} + + +/* + * CP & Ring + */ +void r600_cp_stop(struct radeon_device *rdev) +{ + WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1)); +} + +int r600_cp_init_microcode(struct radeon_device *rdev) +{ + struct platform_device *pdev; + const char *chip_name; + size_t pfp_req_size, me_req_size; + 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"; break; + case CHIP_RV610: chip_name = "RV610"; break; + case CHIP_RV630: chip_name = "RV630"; break; + case CHIP_RV620: chip_name = "RV620"; break; + case CHIP_RV635: chip_name = "RV635"; break; + case CHIP_RV670: chip_name = "RV670"; break; + case CHIP_RS780: + case CHIP_RS880: chip_name = "RS780"; break; + case CHIP_RV770: chip_name = "RV770"; break; + case CHIP_RV730: + case CHIP_RV740: chip_name = "RV730"; break; + case CHIP_RV710: chip_name = "RV710"; break; + default: BUG(); + } + + if (rdev->family >= CHIP_RV770) { + pfp_req_size = R700_PFP_UCODE_SIZE * 4; + me_req_size = R700_PM4_UCODE_SIZE * 4; + } else { + pfp_req_size = PFP_UCODE_SIZE * 4; + me_req_size = PM4_UCODE_SIZE * 12; + } + + DRM_INFO("Loading %s CP 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); + if (err) + goto out; + if (rdev->pfp_fw->size != pfp_req_size) { + printk(KERN_ERR + "r600_cp: Bogus length %zu in firmware \"%s\"\n", + rdev->pfp_fw->size, fw_name); + err = -EINVAL; + goto out; + } + + snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); + err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); + if (err) + goto out; + if (rdev->me_fw->size != me_req_size) { + printk(KERN_ERR + "r600_cp: Bogus length %zu in firmware \"%s\"\n", + rdev->me_fw->size, fw_name); + err = -EINVAL; + } +out: + platform_device_unregister(pdev); + + if (err) { + if (err != -EINVAL) + printk(KERN_ERR + "r600_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; + } + return err; +} + +static int r600_cp_load_microcode(struct radeon_device *rdev) +{ + const __be32 *fw_data; + int i; + + if (!rdev->me_fw || !rdev->pfp_fw) + return -EINVAL; + + r600_cp_stop(rdev); + + WREG32(CP_RB_CNTL, RB_NO_UPDATE | RB_BLKSZ(15) | RB_BUFSZ(3)); + + /* Reset cp */ + WREG32(GRBM_SOFT_RESET, SOFT_RESET_CP); + RREG32(GRBM_SOFT_RESET); + mdelay(15); + WREG32(GRBM_SOFT_RESET, 0); + + WREG32(CP_ME_RAM_WADDR, 0); + + fw_data = (const __be32 *)rdev->me_fw->data; + WREG32(CP_ME_RAM_WADDR, 0); + for (i = 0; i < 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++) + WREG32(CP_PFP_UCODE_DATA, + be32_to_cpup(fw_data++)); + + WREG32(CP_PFP_UCODE_ADDR, 0); + WREG32(CP_ME_RAM_WADDR, 0); + WREG32(CP_ME_RAM_RADDR, 0); + return 0; +} + +int r600_cp_start(struct radeon_device *rdev) +{ + int r; + uint32_t cp_me; + + r = radeon_ring_lock(rdev, 7); + if (r) { + DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r); + return r; + } + radeon_ring_write(rdev, PACKET3(PACKET3_ME_INITIALIZE, 5)); + radeon_ring_write(rdev, 0x1); + if (rdev->family < CHIP_RV770) { + radeon_ring_write(rdev, 0x3); + radeon_ring_write(rdev, rdev->config.r600.max_hw_contexts - 1); + } else { + radeon_ring_write(rdev, 0x0); + radeon_ring_write(rdev, rdev->config.rv770.max_hw_contexts - 1); + } + radeon_ring_write(rdev, PACKET3_ME_INITIALIZE_DEVICE_ID(1)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, 0); + radeon_ring_unlock_commit(rdev); + + cp_me = 0xff; + WREG32(R_0086D8_CP_ME_CNTL, cp_me); + return 0; +} + +int r600_cp_resume(struct radeon_device *rdev) +{ + u32 tmp; + u32 rb_bufsz; + int r; + + /* Reset cp */ + WREG32(GRBM_SOFT_RESET, SOFT_RESET_CP); + RREG32(GRBM_SOFT_RESET); + mdelay(15); + WREG32(GRBM_SOFT_RESET, 0); + + /* Set ring buffer size */ + rb_bufsz = drm_order(rdev->cp.ring_size / 8); +#ifdef __BIG_ENDIAN + WREG32(CP_RB_CNTL, BUF_SWAP_32BIT | RB_NO_UPDATE | + (drm_order(4096/8) << 8) | rb_bufsz); +#else + WREG32(CP_RB_CNTL, RB_NO_UPDATE | (drm_order(4096/8) << 8) | rb_bufsz); +#endif + WREG32(CP_SEM_WAIT_TIMER, 0x4); + + /* Set the write pointer delay */ + WREG32(CP_RB_WPTR_DELAY, 0); + + /* Initialize the ring buffer's read and write pointers */ + tmp = RREG32(CP_RB_CNTL); + WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA); + WREG32(CP_RB_RPTR_WR, 0); + WREG32(CP_RB_WPTR, 0); + WREG32(CP_RB_RPTR_ADDR, rdev->cp.gpu_addr & 0xFFFFFFFF); + WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->cp.gpu_addr)); + mdelay(1); + WREG32(CP_RB_CNTL, tmp); + + WREG32(CP_RB_BASE, rdev->cp.gpu_addr >> 8); + WREG32(CP_DEBUG, (1 << 27) | (1 << 28)); + + rdev->cp.rptr = RREG32(CP_RB_RPTR); + rdev->cp.wptr = RREG32(CP_RB_WPTR); + + r600_cp_start(rdev); + rdev->cp.ready = true; + r = radeon_ring_test(rdev); + if (r) { + rdev->cp.ready = false; + return r; + } + return 0; +} + +void r600_cp_commit(struct radeon_device *rdev) +{ + WREG32(CP_RB_WPTR, rdev->cp.wptr); + (void)RREG32(CP_RB_WPTR); +} + +void r600_ring_init(struct radeon_device *rdev, unsigned ring_size) +{ + u32 rb_bufsz; + + /* Align ring size */ + rb_bufsz = drm_order(ring_size / 8); + ring_size = (1 << (rb_bufsz + 1)) * 4; + rdev->cp.ring_size = ring_size; + rdev->cp.align_mask = 16 - 1; +} + + +/* + * GPU scratch registers helpers function. + */ +void r600_scratch_init(struct radeon_device *rdev) +{ + int i; + + rdev->scratch.num_reg = 7; + for (i = 0; i < rdev->scratch.num_reg; i++) { + rdev->scratch.free[i] = true; + rdev->scratch.reg[i] = SCRATCH_REG0 + (i * 4); + } +} + +int r600_ring_test(struct radeon_device *rdev) +{ + 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, 3); + if (r) { + DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r); + radeon_scratch_free(rdev, scratch); + return r; + } + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1)); + radeon_ring_write(rdev, ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2)); + radeon_ring_write(rdev, 0xDEADBEEF); + radeon_ring_unlock_commit(rdev); + 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 succeeded in %d usecs\n", i); + } else { + DRM_ERROR("radeon: ring test failed (scratch(0x%04X)=0x%08X)\n", + scratch, tmp); + r = -EINVAL; + } + radeon_scratch_free(rdev, scratch); + return r; +} + +/* + * Writeback + */ +int r600_wb_init(struct radeon_device *rdev) +{ + int r; + + if (rdev->wb.wb_obj == NULL) { + r = radeon_object_create(rdev, NULL, 4096, + true, + RADEON_GEM_DOMAIN_GTT, + false, &rdev->wb.wb_obj); + if (r) { + DRM_ERROR("radeon: failed to create WB buffer (%d).\n", r); + return r; + } + r = radeon_object_pin(rdev->wb.wb_obj, + RADEON_GEM_DOMAIN_GTT, + &rdev->wb.gpu_addr); + if (r) { + DRM_ERROR("radeon: failed to pin WB buffer (%d).\n", r); + return r; + } + r = radeon_object_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb); + if (r) { + DRM_ERROR("radeon: failed to map WB buffer (%d).\n", r); + return r; + } + } + WREG32(SCRATCH_ADDR, (rdev->wb.gpu_addr >> 8) & 0xFFFFFFFF); + WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + 1024) & 0xFFFFFFFC); + WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + 1024) & 0xFF); + WREG32(SCRATCH_UMSK, 0xff); + return 0; +} + +void r600_wb_fini(struct radeon_device *rdev) +{ + if (rdev->wb.wb_obj) { + radeon_object_kunmap(rdev->wb.wb_obj); + radeon_object_unpin(rdev->wb.wb_obj); + radeon_object_unref(&rdev->wb.wb_obj); + rdev->wb.wb = NULL; + rdev->wb.wb_obj = NULL; + } +} + + +/* + * CS + */ +void r600_fence_ring_emit(struct radeon_device *rdev, + struct radeon_fence *fence) +{ + /* Emit fence sequence & fire IRQ */ + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1)); + radeon_ring_write(rdev, ((rdev->fence_drv.scratch_reg - PACKET3_SET_CONFIG_REG_OFFSET) >> 2)); + radeon_ring_write(rdev, fence->seq); +} + +int r600_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_pages, + struct radeon_fence *fence) +{ + /* FIXME: implement */ + return 0; +} + +int r600_copy_blit(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_pages, struct radeon_fence *fence) +{ + r600_blit_prepare_copy(rdev, num_pages * 4096); + r600_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * 4096); + r600_blit_done_copy(rdev, fence); + return 0; +} + +int r600_irq_process(struct radeon_device *rdev) +{ + /* FIXME: implement */ + return 0; +} + +int r600_irq_set(struct radeon_device *rdev) +{ + /* FIXME: implement */ + return 0; +} + +int r600_set_surface_reg(struct radeon_device *rdev, int reg, + uint32_t tiling_flags, uint32_t pitch, + uint32_t offset, uint32_t obj_size) +{ + /* FIXME: implement */ + return 0; +} + +void r600_clear_surface_reg(struct radeon_device *rdev, int reg) +{ + /* FIXME: implement */ +} + + +bool r600_card_posted(struct radeon_device *rdev) +{ + uint32_t reg; + + /* first check CRTCs */ + reg = RREG32(D1CRTC_CONTROL) | + RREG32(D2CRTC_CONTROL); + if (reg & CRTC_EN) + return true; + + /* then check MEM_SIZE, in case the crtcs are off */ + if (RREG32(CONFIG_MEMSIZE)) + return true; + + return false; +} + +int r600_resume(struct radeon_device *rdev) +{ + int r; + + r600_gpu_reset(rdev); + r600_mc_resume(rdev); + r = r600_pcie_gart_enable(rdev); + if (r) + return r; + r600_gpu_init(rdev); + r = radeon_ring_init(rdev, rdev->cp.ring_size); + if (r) + return r; + r = r600_cp_load_microcode(rdev); + if (r) + return r; + r = r600_cp_resume(rdev); + if (r) + return r; + r = r600_wb_init(rdev); + if (r) + return r; + return 0; +} + +int r600_suspend(struct radeon_device *rdev) +{ + /* FIXME: we should wait for ring to be empty */ + r600_cp_stop(rdev); + 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. + */ +int r600_init(struct radeon_device *rdev) { - uint32_t r; + int r; - WREG32(R600_PCIE_PORT_INDEX, ((reg) & 0xff)); - (void)RREG32(R600_PCIE_PORT_INDEX); - r = RREG32(R600_PCIE_PORT_DATA); + rdev->new_init_path = true; + r = radeon_dummy_page_init(rdev); + if (r) + return r; + if (r600_debugfs_mc_info_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for mc !\n"); + } + /* This don't do much */ + r = radeon_gem_init(rdev); + if (r) + return r; + /* Read BIOS */ + if (!radeon_get_bios(rdev)) { + if (ASIC_IS_AVIVO(rdev)) + return -EINVAL; + } + /* Must be an ATOMBIOS */ + if (!rdev->is_atom_bios) + return -EINVAL; + r = radeon_atombios_init(rdev); + if (r) + return r; + /* Post card if necessary */ + if (!r600_card_posted(rdev) && rdev->bios) { + DRM_INFO("GPU not posted. posting now...\n"); + atom_asic_init(rdev->mode_info.atom_context); + } + /* Initialize scratch registers */ + r600_scratch_init(rdev); + /* Initialize surface registers */ + radeon_surface_init(rdev); + r = radeon_clocks_init(rdev); + if (r) + return r; + /* Fence driver */ + r = radeon_fence_driver_init(rdev); + if (r) + return r; + r = r600_mc_init(rdev); + if (r) { + if (rdev->flags & RADEON_IS_AGP) { + /* Retry with disabling AGP */ + r600_fini(rdev); + rdev->flags &= ~RADEON_IS_AGP; + return r600_init(rdev); + } + return r; + } + /* Memory manager */ + r = radeon_object_init(rdev); + if (r) + return r; + rdev->cp.ring_obj = NULL; + r600_ring_init(rdev, 1024 * 1024); + + if (!rdev->me_fw || !rdev->pfp_fw) { + r = r600_cp_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + + r = r600_resume(rdev); + if (r) { + if (rdev->flags & RADEON_IS_AGP) { + /* Retry with disabling AGP */ + r600_fini(rdev); + rdev->flags &= ~RADEON_IS_AGP; + return r600_init(rdev); + } + return r; + } + r = radeon_ib_pool_init(rdev); + if (r) { + DRM_ERROR("radeon: failled initializing IB pool (%d).\n", r); + return r; + } + r = r600_blit_init(rdev); + if (r) { + DRM_ERROR("radeon: failled blitter (%d).\n", r); + return r; + } + r = radeon_ib_test(rdev); + if (r) { + DRM_ERROR("radeon: failled testing IB (%d).\n", r); + return r; + } + return 0; +} + +void r600_fini(struct radeon_device *rdev) +{ + /* Suspend operations */ + r600_suspend(rdev); + + r600_blit_fini(rdev); + radeon_ring_fini(rdev); + r600_pcie_gart_disable(rdev); + radeon_gart_table_vram_free(rdev); + radeon_gart_fini(rdev); + radeon_gem_fini(rdev); + radeon_fence_driver_fini(rdev); + radeon_clocks_fini(rdev); +#if __OS_HAS_AGP + if (rdev->flags & RADEON_IS_AGP) + radeon_agp_fini(rdev); +#endif + radeon_object_fini(rdev); + if (rdev->is_atom_bios) + radeon_atombios_fini(rdev); + else + radeon_combios_fini(rdev); + kfree(rdev->bios); + rdev->bios = NULL; + radeon_dummy_page_fini(rdev); +} + + +/* + * CS stuff + */ +void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) +{ + /* FIXME: implement */ + radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); + radeon_ring_write(rdev, ib->gpu_addr & 0xFFFFFFFC); + radeon_ring_write(rdev, upper_32_bits(ib->gpu_addr) & 0xFF); + radeon_ring_write(rdev, ib->length_dw); +} + +int r600_ib_test(struct radeon_device *rdev) +{ + 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, &ib); + if (r) { + DRM_ERROR("radeon: failed to get ib (%d).\n", r); + return r; + } + ib->ptr[0] = PACKET3(PACKET3_SET_CONFIG_REG, 1); + ib->ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2); + ib->ptr[2] = 0xDEADBEEF; + ib->ptr[3] = PACKET2(0); + ib->ptr[4] = PACKET2(0); + ib->ptr[5] = PACKET2(0); + ib->ptr[6] = PACKET2(0); + ib->ptr[7] = PACKET2(0); + ib->ptr[8] = PACKET2(0); + ib->ptr[9] = PACKET2(0); + ib->ptr[10] = PACKET2(0); + ib->ptr[11] = PACKET2(0); + ib->ptr[12] = PACKET2(0); + ib->ptr[13] = PACKET2(0); + ib->ptr[14] = PACKET2(0); + ib->ptr[15] = PACKET2(0); + ib->length_dw = 16; + r = radeon_ib_schedule(rdev, ib); + 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); + 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 succeeded in %u usecs\n", i); + } else { + DRM_ERROR("radeon: ib test failed (sracth(0x%04X)=0x%08X)\n", + scratch, tmp); + r = -EINVAL; + } + radeon_scratch_free(rdev, scratch); + radeon_ib_free(rdev, &ib); return r; } -void r600_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) + + + +/* + * Debugfs info + */ +#if defined(CONFIG_DEBUG_FS) + +static int r600_debugfs_cp_ring_info(struct seq_file *m, void *data) { - WREG32(R600_PCIE_PORT_INDEX, ((reg) & 0xff)); - (void)RREG32(R600_PCIE_PORT_INDEX); - WREG32(R600_PCIE_PORT_DATA, (v)); - (void)RREG32(R600_PCIE_PORT_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; + uint32_t rdp, wdp; + unsigned count, i, j; + + radeon_ring_free_size(rdev); + rdp = RREG32(CP_RB_RPTR); + wdp = RREG32(CP_RB_WPTR); + count = (rdp + rdev->cp.ring_size - wdp) & rdev->cp.ptr_mask; + seq_printf(m, "CP_STAT 0x%08x\n", RREG32(CP_STAT)); + seq_printf(m, "CP_RB_WPTR 0x%08x\n", wdp); + seq_printf(m, "CP_RB_RPTR 0x%08x\n", rdp); + seq_printf(m, "%u free dwords in ring\n", rdev->cp.ring_free_dw); + seq_printf(m, "%u dwords in ring\n", count); + for (j = 0; j <= count; j++) { + i = (rdp + j) & rdev->cp.ptr_mask; + seq_printf(m, "r[%04d]=0x%08x\n", i, rdev->cp.ring[i]); + } + return 0; +} + +static int r600_debugfs_mc_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; + + DREG32_SYS(m, rdev, R_000E50_SRBM_STATUS); + DREG32_SYS(m, rdev, VM_L2_STATUS); + return 0; +} + +static struct drm_info_list r600_mc_info_list[] = { + {"r600_mc_info", r600_debugfs_mc_info, 0, NULL}, + {"r600_ring_info", r600_debugfs_cp_ring_info, 0, NULL}, +}; +#endif + +int r600_debugfs_mc_info_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + return radeon_debugfs_add_files(rdev, r600_mc_info_list, ARRAY_SIZE(r600_mc_info_list)); +#else + return 0; +#endif } diff --git a/drivers/gpu/drm/radeon/r600_blit.c b/drivers/gpu/drm/radeon/r600_blit.c new file mode 100644 index 000000000000..c51402e92493 --- /dev/null +++ b/drivers/gpu/drm/radeon/r600_blit.c @@ -0,0 +1,855 @@ +/* + * Copyright 2009 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 + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +#include "r600_blit_shaders.h" + +#define DI_PT_RECTLIST 0x11 +#define DI_INDEX_SIZE_16_BIT 0x0 +#define DI_SRC_SEL_AUTO_INDEX 0x2 + +#define FMT_8 0x1 +#define FMT_5_6_5 0x8 +#define FMT_8_8_8_8 0x1a +#define COLOR_8 0x1 +#define COLOR_5_6_5 0x8 +#define COLOR_8_8_8_8 0x1a + +static inline void +set_render_target(drm_radeon_private_t *dev_priv, int format, int w, int h, u64 gpu_addr) +{ + u32 cb_color_info; + int pitch, slice; + RING_LOCALS; + DRM_DEBUG("\n"); + + h = (h + 7) & ~7; + if (h < 8) + h = 8; + + cb_color_info = ((format << 2) | (1 << 27)); + pitch = (w / 8) - 1; + slice = ((w * h) / 64) - 1; + + if (((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_R600) && + ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_RV770)) { + BEGIN_RING(21 + 2); + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1)); + OUT_RING((R600_CB_COLOR0_BASE - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING(gpu_addr >> 8); + OUT_RING(CP_PACKET3(R600_IT_SURFACE_BASE_UPDATE, 0)); + OUT_RING(2 << 0); + } else { + BEGIN_RING(21); + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1)); + OUT_RING((R600_CB_COLOR0_BASE - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING(gpu_addr >> 8); + } + + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1)); + OUT_RING((R600_CB_COLOR0_SIZE - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING((pitch << 0) | (slice << 10)); + + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1)); + OUT_RING((R600_CB_COLOR0_VIEW - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING(0); + + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1)); + OUT_RING((R600_CB_COLOR0_INFO - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING(cb_color_info); + + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1)); + OUT_RING((R600_CB_COLOR0_TILE - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING(0); + + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1)); + OUT_RING((R600_CB_COLOR0_FRAG - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING(0); + + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1)); + OUT_RING((R600_CB_COLOR0_MASK - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING(0); + + ADVANCE_RING(); +} + +static inline void +cp_set_surface_sync(drm_radeon_private_t *dev_priv, + u32 sync_type, u32 size, u64 mc_addr) +{ + u32 cp_coher_size; + RING_LOCALS; + DRM_DEBUG("\n"); + + if (size == 0xffffffff) + cp_coher_size = 0xffffffff; + else + cp_coher_size = ((size + 255) >> 8); + + BEGIN_RING(5); + OUT_RING(CP_PACKET3(R600_IT_SURFACE_SYNC, 3)); + OUT_RING(sync_type); + OUT_RING(cp_coher_size); + OUT_RING((mc_addr >> 8)); + OUT_RING(10); /* poll interval */ + ADVANCE_RING(); +} + +static inline void +set_shaders(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + u64 gpu_addr; + int shader_size, i; + u32 *vs, *ps; + uint32_t sq_pgm_resources; + RING_LOCALS; + DRM_DEBUG("\n"); + + /* load shaders */ + vs = (u32 *) ((char *)dev->agp_buffer_map->handle + dev_priv->blit_vb->offset); + ps = (u32 *) ((char *)dev->agp_buffer_map->handle + dev_priv->blit_vb->offset + 256); + + shader_size = r6xx_vs_size; + for (i = 0; i < shader_size; i++) + vs[i] = r6xx_vs[i]; + shader_size = r6xx_ps_size; + for (i = 0; i < shader_size; i++) + ps[i] = r6xx_ps[i]; + + dev_priv->blit_vb->used = 512; + + gpu_addr = dev_priv->gart_buffers_offset + dev_priv->blit_vb->offset; + + /* setup shader regs */ + sq_pgm_resources = (1 << 0); + + BEGIN_RING(9 + 12); + /* VS */ + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1)); + OUT_RING((R600_SQ_PGM_START_VS - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING(gpu_addr >> 8); + + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1)); + OUT_RING((R600_SQ_PGM_RESOURCES_VS - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING(sq_pgm_resources); + + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1)); + OUT_RING((R600_SQ_PGM_CF_OFFSET_VS - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING(0); + + /* PS */ + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1)); + OUT_RING((R600_SQ_PGM_START_PS - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING((gpu_addr + 256) >> 8); + + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1)); + OUT_RING((R600_SQ_PGM_RESOURCES_PS - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING(sq_pgm_resources | (1 << 28)); + + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1)); + OUT_RING((R600_SQ_PGM_EXPORTS_PS - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING(2); + + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 1)); + OUT_RING((R600_SQ_PGM_CF_OFFSET_PS - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING(0); + ADVANCE_RING(); + + cp_set_surface_sync(dev_priv, + R600_SH_ACTION_ENA, 512, gpu_addr); +} + +static inline void +set_vtx_resource(drm_radeon_private_t *dev_priv, u64 gpu_addr) +{ + uint32_t sq_vtx_constant_word2; + RING_LOCALS; + DRM_DEBUG("\n"); + + sq_vtx_constant_word2 = (((gpu_addr >> 32) & 0xff) | (16 << 8)); + + BEGIN_RING(9); + OUT_RING(CP_PACKET3(R600_IT_SET_RESOURCE, 7)); + OUT_RING(0x460); + OUT_RING(gpu_addr & 0xffffffff); + OUT_RING(48 - 1); + OUT_RING(sq_vtx_constant_word2); + OUT_RING(1 << 0); + OUT_RING(0); + OUT_RING(0); + OUT_RING(R600_SQ_TEX_VTX_VALID_BUFFER << 30); + ADVANCE_RING(); + + if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV710)) + cp_set_surface_sync(dev_priv, + R600_TC_ACTION_ENA, 48, gpu_addr); + else + cp_set_surface_sync(dev_priv, + R600_VC_ACTION_ENA, 48, gpu_addr); +} + +static inline void +set_tex_resource(drm_radeon_private_t *dev_priv, + int format, int w, int h, int pitch, u64 gpu_addr) +{ + uint32_t sq_tex_resource_word0, sq_tex_resource_word1, sq_tex_resource_word4; + RING_LOCALS; + DRM_DEBUG("\n"); + + if (h < 1) + h = 1; + + sq_tex_resource_word0 = (1 << 0); + sq_tex_resource_word0 |= ((((pitch >> 3) - 1) << 8) | + ((w - 1) << 19)); + + sq_tex_resource_word1 = (format << 26); + sq_tex_resource_word1 |= ((h - 1) << 0); + + sq_tex_resource_word4 = ((1 << 14) | + (0 << 16) | + (1 << 19) | + (2 << 22) | + (3 << 25)); + + BEGIN_RING(9); + OUT_RING(CP_PACKET3(R600_IT_SET_RESOURCE, 7)); + OUT_RING(0); + OUT_RING(sq_tex_resource_word0); + OUT_RING(sq_tex_resource_word1); + OUT_RING(gpu_addr >> 8); + OUT_RING(gpu_addr >> 8); + OUT_RING(sq_tex_resource_word4); + OUT_RING(0); + OUT_RING(R600_SQ_TEX_VTX_VALID_TEXTURE << 30); + ADVANCE_RING(); + +} + +static inline void +set_scissors(drm_radeon_private_t *dev_priv, int x1, int y1, int x2, int y2) +{ + RING_LOCALS; + DRM_DEBUG("\n"); + + BEGIN_RING(12); + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 2)); + OUT_RING((R600_PA_SC_SCREEN_SCISSOR_TL - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING((x1 << 0) | (y1 << 16)); + OUT_RING((x2 << 0) | (y2 << 16)); + + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 2)); + OUT_RING((R600_PA_SC_GENERIC_SCISSOR_TL - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING((x1 << 0) | (y1 << 16) | (1 << 31)); + OUT_RING((x2 << 0) | (y2 << 16)); + + OUT_RING(CP_PACKET3(R600_IT_SET_CONTEXT_REG, 2)); + OUT_RING((R600_PA_SC_WINDOW_SCISSOR_TL - R600_SET_CONTEXT_REG_OFFSET) >> 2); + OUT_RING((x1 << 0) | (y1 << 16) | (1 << 31)); + OUT_RING((x2 << 0) | (y2 << 16)); + ADVANCE_RING(); +} + +static inline void +draw_auto(drm_radeon_private_t *dev_priv) +{ + RING_LOCALS; + DRM_DEBUG("\n"); + + BEGIN_RING(10); + OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1)); + OUT_RING((R600_VGT_PRIMITIVE_TYPE - R600_SET_CONFIG_REG_OFFSET) >> 2); + OUT_RING(DI_PT_RECTLIST); + + OUT_RING(CP_PACKET3(R600_IT_INDEX_TYPE, 0)); + OUT_RING(DI_INDEX_SIZE_16_BIT); + + OUT_RING(CP_PACKET3(R600_IT_NUM_INSTANCES, 0)); + OUT_RING(1); + + OUT_RING(CP_PACKET3(R600_IT_DRAW_INDEX_AUTO, 1)); + OUT_RING(3); + OUT_RING(DI_SRC_SEL_AUTO_INDEX); + + ADVANCE_RING(); + COMMIT_RING(); +} + +static inline void +set_default_state(drm_radeon_private_t *dev_priv) +{ + int default_state_dw, i; + u32 sq_config, sq_gpr_resource_mgmt_1, sq_gpr_resource_mgmt_2; + u32 sq_thread_resource_mgmt, sq_stack_resource_mgmt_1, sq_stack_resource_mgmt_2; + int num_ps_gprs, num_vs_gprs, num_temp_gprs, num_gs_gprs, num_es_gprs; + int num_ps_threads, num_vs_threads, num_gs_threads, num_es_threads; + int num_ps_stack_entries, num_vs_stack_entries, num_gs_stack_entries, num_es_stack_entries; + RING_LOCALS; + + switch ((dev_priv->flags & RADEON_FAMILY_MASK)) { + case CHIP_R600: + num_ps_gprs = 192; + num_vs_gprs = 56; + num_temp_gprs = 4; + num_gs_gprs = 0; + num_es_gprs = 0; + num_ps_threads = 136; + num_vs_threads = 48; + num_gs_threads = 4; + num_es_threads = 4; + num_ps_stack_entries = 128; + num_vs_stack_entries = 128; + num_gs_stack_entries = 0; + num_es_stack_entries = 0; + break; + case CHIP_RV630: + case CHIP_RV635: + num_ps_gprs = 84; + num_vs_gprs = 36; + num_temp_gprs = 4; + num_gs_gprs = 0; + num_es_gprs = 0; + num_ps_threads = 144; + num_vs_threads = 40; + num_gs_threads = 4; + num_es_threads = 4; + num_ps_stack_entries = 40; + num_vs_stack_entries = 40; + num_gs_stack_entries = 32; + num_es_stack_entries = 16; + break; + case CHIP_RV610: + case CHIP_RV620: + case CHIP_RS780: + case CHIP_RS880: + default: + num_ps_gprs = 84; + num_vs_gprs = 36; + num_temp_gprs = 4; + num_gs_gprs = 0; + num_es_gprs = 0; + num_ps_threads = 136; + num_vs_threads = 48; + num_gs_threads = 4; + num_es_threads = 4; + num_ps_stack_entries = 40; + num_vs_stack_entries = 40; + num_gs_stack_entries = 32; + num_es_stack_entries = 16; + break; + case CHIP_RV670: + num_ps_gprs = 144; + num_vs_gprs = 40; + num_temp_gprs = 4; + num_gs_gprs = 0; + num_es_gprs = 0; + num_ps_threads = 136; + num_vs_threads = 48; + num_gs_threads = 4; + num_es_threads = 4; + num_ps_stack_entries = 40; + num_vs_stack_entries = 40; + num_gs_stack_entries = 32; + num_es_stack_entries = 16; + break; + case CHIP_RV770: + num_ps_gprs = 192; + num_vs_gprs = 56; + num_temp_gprs = 4; + num_gs_gprs = 0; + num_es_gprs = 0; + num_ps_threads = 188; + num_vs_threads = 60; + num_gs_threads = 0; + num_es_threads = 0; + num_ps_stack_entries = 256; + num_vs_stack_entries = 256; + num_gs_stack_entries = 0; + num_es_stack_entries = 0; + break; + case CHIP_RV730: + case CHIP_RV740: + num_ps_gprs = 84; + num_vs_gprs = 36; + num_temp_gprs = 4; + num_gs_gprs = 0; + num_es_gprs = 0; + num_ps_threads = 188; + num_vs_threads = 60; + num_gs_threads = 0; + num_es_threads = 0; + num_ps_stack_entries = 128; + num_vs_stack_entries = 128; + num_gs_stack_entries = 0; + num_es_stack_entries = 0; + break; + case CHIP_RV710: + num_ps_gprs = 192; + num_vs_gprs = 56; + num_temp_gprs = 4; + num_gs_gprs = 0; + num_es_gprs = 0; + num_ps_threads = 144; + num_vs_threads = 48; + num_gs_threads = 0; + num_es_threads = 0; + num_ps_stack_entries = 128; + num_vs_stack_entries = 128; + num_gs_stack_entries = 0; + num_es_stack_entries = 0; + break; + } + + if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV710)) + sq_config = 0; + else + sq_config = R600_VC_ENABLE; + + sq_config |= (R600_DX9_CONSTS | + R600_ALU_INST_PREFER_VECTOR | + R600_PS_PRIO(0) | + R600_VS_PRIO(1) | + R600_GS_PRIO(2) | + R600_ES_PRIO(3)); + + sq_gpr_resource_mgmt_1 = (R600_NUM_PS_GPRS(num_ps_gprs) | + R600_NUM_VS_GPRS(num_vs_gprs) | + R600_NUM_CLAUSE_TEMP_GPRS(num_temp_gprs)); + sq_gpr_resource_mgmt_2 = (R600_NUM_GS_GPRS(num_gs_gprs) | + R600_NUM_ES_GPRS(num_es_gprs)); + sq_thread_resource_mgmt = (R600_NUM_PS_THREADS(num_ps_threads) | + R600_NUM_VS_THREADS(num_vs_threads) | + R600_NUM_GS_THREADS(num_gs_threads) | + R600_NUM_ES_THREADS(num_es_threads)); + sq_stack_resource_mgmt_1 = (R600_NUM_PS_STACK_ENTRIES(num_ps_stack_entries) | + R600_NUM_VS_STACK_ENTRIES(num_vs_stack_entries)); + sq_stack_resource_mgmt_2 = (R600_NUM_GS_STACK_ENTRIES(num_gs_stack_entries) | + R600_NUM_ES_STACK_ENTRIES(num_es_stack_entries)); + + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) { + default_state_dw = r7xx_default_size * 4; + BEGIN_RING(default_state_dw + 10); + for (i = 0; i < default_state_dw; i++) + OUT_RING(r7xx_default_state[i]); + } else { + default_state_dw = r6xx_default_size * 4; + BEGIN_RING(default_state_dw + 10); + for (i = 0; i < default_state_dw; i++) + OUT_RING(r6xx_default_state[i]); + } + OUT_RING(CP_PACKET3(R600_IT_EVENT_WRITE, 0)); + OUT_RING(R600_CACHE_FLUSH_AND_INV_EVENT); + /* SQ config */ + OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 6)); + OUT_RING((R600_SQ_CONFIG - R600_SET_CONFIG_REG_OFFSET) >> 2); + OUT_RING(sq_config); + OUT_RING(sq_gpr_resource_mgmt_1); + OUT_RING(sq_gpr_resource_mgmt_2); + OUT_RING(sq_thread_resource_mgmt); + OUT_RING(sq_stack_resource_mgmt_1); + OUT_RING(sq_stack_resource_mgmt_2); + ADVANCE_RING(); +} + +static inline uint32_t i2f(uint32_t input) +{ + u32 result, i, exponent, fraction; + + if ((input & 0x3fff) == 0) + result = 0; /* 0 is a special case */ + else { + exponent = 140; /* exponent biased by 127; */ + fraction = (input & 0x3fff) << 10; /* cheat and only + handle numbers below 2^^15 */ + for (i = 0; i < 14; i++) { + if (fraction & 0x800000) + break; + else { + fraction = fraction << 1; /* keep + shifting left until top bit = 1 */ + exponent = exponent - 1; + } + } + result = exponent << 23 | (fraction & 0x7fffff); /* mask + off top bit; assumed 1 */ + } + return result; +} + + +int r600_nomm_get_vb(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + dev_priv->blit_vb = radeon_freelist_get(dev); + if (!dev_priv->blit_vb) { + DRM_ERROR("Unable to allocate vertex buffer for blit\n"); + return -EAGAIN; + } + return 0; +} + +void r600_nomm_put_vb(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + dev_priv->blit_vb->used = 0; + radeon_cp_discard_buffer(dev, dev_priv->blit_vb->file_priv->master, dev_priv->blit_vb); +} + +void *r600_nomm_get_vb_ptr(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + return (((char *)dev->agp_buffer_map->handle + + dev_priv->blit_vb->offset + dev_priv->blit_vb->used)); +} + +int +r600_prepare_blit_copy(struct drm_device *dev, struct drm_file *file_priv) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + DRM_DEBUG("\n"); + + r600_nomm_get_vb(dev); + + dev_priv->blit_vb->file_priv = file_priv; + + set_default_state(dev_priv); + set_shaders(dev); + + return 0; +} + + +void +r600_done_blit_copy(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + DRM_DEBUG("\n"); + + BEGIN_RING(5); + OUT_RING(CP_PACKET3(R600_IT_EVENT_WRITE, 0)); + OUT_RING(R600_CACHE_FLUSH_AND_INV_EVENT); + /* wait for 3D idle clean */ + OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1)); + OUT_RING((R600_WAIT_UNTIL - R600_SET_CONFIG_REG_OFFSET) >> 2); + OUT_RING(RADEON_WAIT_3D_IDLE | RADEON_WAIT_3D_IDLECLEAN); + + ADVANCE_RING(); + COMMIT_RING(); + + r600_nomm_put_vb(dev); +} + +void +r600_blit_copy(struct drm_device *dev, + uint64_t src_gpu_addr, uint64_t dst_gpu_addr, + int size_bytes) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int max_bytes; + u64 vb_addr; + u32 *vb; + + vb = r600_nomm_get_vb_ptr(dev); + + if ((size_bytes & 3) || (src_gpu_addr & 3) || (dst_gpu_addr & 3)) { + max_bytes = 8192; + + while (size_bytes) { + int cur_size = size_bytes; + int src_x = src_gpu_addr & 255; + int dst_x = dst_gpu_addr & 255; + int h = 1; + src_gpu_addr = src_gpu_addr & ~255; + dst_gpu_addr = dst_gpu_addr & ~255; + + if (!src_x && !dst_x) { + h = (cur_size / max_bytes); + if (h > 8192) + h = 8192; + if (h == 0) + h = 1; + else + cur_size = max_bytes; + } else { + if (cur_size > max_bytes) + cur_size = max_bytes; + if (cur_size > (max_bytes - dst_x)) + cur_size = (max_bytes - dst_x); + if (cur_size > (max_bytes - src_x)) + cur_size = (max_bytes - src_x); + } + + if ((dev_priv->blit_vb->used + 48) > dev_priv->blit_vb->total) { + + r600_nomm_put_vb(dev); + r600_nomm_get_vb(dev); + if (!dev_priv->blit_vb) + return; + set_shaders(dev); + vb = r600_nomm_get_vb_ptr(dev); + } + + vb[0] = i2f(dst_x); + vb[1] = 0; + vb[2] = i2f(src_x); + vb[3] = 0; + + vb[4] = i2f(dst_x); + vb[5] = i2f(h); + vb[6] = i2f(src_x); + vb[7] = i2f(h); + + vb[8] = i2f(dst_x + cur_size); + vb[9] = i2f(h); + vb[10] = i2f(src_x + cur_size); + vb[11] = i2f(h); + + /* src */ + set_tex_resource(dev_priv, FMT_8, + src_x + cur_size, h, src_x + cur_size, + src_gpu_addr); + + cp_set_surface_sync(dev_priv, + R600_TC_ACTION_ENA, (src_x + cur_size * h), src_gpu_addr); + + /* dst */ + set_render_target(dev_priv, COLOR_8, + dst_x + cur_size, h, + dst_gpu_addr); + + /* scissors */ + set_scissors(dev_priv, dst_x, 0, dst_x + cur_size, h); + + /* Vertex buffer setup */ + vb_addr = dev_priv->gart_buffers_offset + + dev_priv->blit_vb->offset + + dev_priv->blit_vb->used; + set_vtx_resource(dev_priv, vb_addr); + + /* draw */ + draw_auto(dev_priv); + + cp_set_surface_sync(dev_priv, + R600_CB_ACTION_ENA | R600_CB0_DEST_BASE_ENA, + cur_size * h, dst_gpu_addr); + + vb += 12; + dev_priv->blit_vb->used += 12 * 4; + + src_gpu_addr += cur_size * h; + dst_gpu_addr += cur_size * h; + size_bytes -= cur_size * h; + } + } else { + max_bytes = 8192 * 4; + + while (size_bytes) { + int cur_size = size_bytes; + int src_x = (src_gpu_addr & 255); + int dst_x = (dst_gpu_addr & 255); + int h = 1; + src_gpu_addr = src_gpu_addr & ~255; + dst_gpu_addr = dst_gpu_addr & ~255; + + if (!src_x && !dst_x) { + h = (cur_size / max_bytes); + if (h > 8192) + h = 8192; + if (h == 0) + h = 1; + else + cur_size = max_bytes; + } else { + if (cur_size > max_bytes) + cur_size = max_bytes; + if (cur_size > (max_bytes - dst_x)) + cur_size = (max_bytes - dst_x); + if (cur_size > (max_bytes - src_x)) + cur_size = (max_bytes - src_x); + } + + if ((dev_priv->blit_vb->used + 48) > dev_priv->blit_vb->total) { + r600_nomm_put_vb(dev); + r600_nomm_get_vb(dev); + if (!dev_priv->blit_vb) + return; + + set_shaders(dev); + vb = r600_nomm_get_vb_ptr(dev); + } + + vb[0] = i2f(dst_x / 4); + vb[1] = 0; + vb[2] = i2f(src_x / 4); + vb[3] = 0; + + vb[4] = i2f(dst_x / 4); + vb[5] = i2f(h); + vb[6] = i2f(src_x / 4); + vb[7] = i2f(h); + + vb[8] = i2f((dst_x + cur_size) / 4); + vb[9] = i2f(h); + vb[10] = i2f((src_x + cur_size) / 4); + vb[11] = i2f(h); + + /* src */ + set_tex_resource(dev_priv, FMT_8_8_8_8, + (src_x + cur_size) / 4, + h, (src_x + cur_size) / 4, + src_gpu_addr); + + cp_set_surface_sync(dev_priv, + R600_TC_ACTION_ENA, (src_x + cur_size * h), src_gpu_addr); + + /* dst */ + set_render_target(dev_priv, COLOR_8_8_8_8, + dst_x + cur_size, h, + dst_gpu_addr); + + /* scissors */ + set_scissors(dev_priv, (dst_x / 4), 0, (dst_x + cur_size / 4), h); + + /* Vertex buffer setup */ + vb_addr = dev_priv->gart_buffers_offset + + dev_priv->blit_vb->offset + + dev_priv->blit_vb->used; + set_vtx_resource(dev_priv, vb_addr); + + /* draw */ + draw_auto(dev_priv); + + cp_set_surface_sync(dev_priv, + R600_CB_ACTION_ENA | R600_CB0_DEST_BASE_ENA, + cur_size * h, dst_gpu_addr); + + vb += 12; + dev_priv->blit_vb->used += 12 * 4; + + src_gpu_addr += cur_size * h; + dst_gpu_addr += cur_size * h; + size_bytes -= cur_size * h; + } + } +} + +void +r600_blit_swap(struct drm_device *dev, + uint64_t src_gpu_addr, uint64_t dst_gpu_addr, + int sx, int sy, int dx, int dy, + int w, int h, int src_pitch, int dst_pitch, int cpp) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int cb_format, tex_format; + u64 vb_addr; + u32 *vb; + + vb = (u32 *) ((char *)dev->agp_buffer_map->handle + + dev_priv->blit_vb->offset + dev_priv->blit_vb->used); + + if ((dev_priv->blit_vb->used + 48) > dev_priv->blit_vb->total) { + + r600_nomm_put_vb(dev); + r600_nomm_get_vb(dev); + if (!dev_priv->blit_vb) + return; + + set_shaders(dev); + vb = r600_nomm_get_vb_ptr(dev); + } + + if (cpp == 4) { + cb_format = COLOR_8_8_8_8; + tex_format = FMT_8_8_8_8; + } else if (cpp == 2) { + cb_format = COLOR_5_6_5; + tex_format = FMT_5_6_5; + } else { + cb_format = COLOR_8; + tex_format = FMT_8; + } + + vb[0] = i2f(dx); + vb[1] = i2f(dy); + vb[2] = i2f(sx); + vb[3] = i2f(sy); + + vb[4] = i2f(dx); + vb[5] = i2f(dy + h); + vb[6] = i2f(sx); + vb[7] = i2f(sy + h); + + vb[8] = i2f(dx + w); + vb[9] = i2f(dy + h); + vb[10] = i2f(sx + w); + vb[11] = i2f(sy + h); + + /* src */ + set_tex_resource(dev_priv, tex_format, + src_pitch / cpp, + sy + h, src_pitch / cpp, + src_gpu_addr); + + cp_set_surface_sync(dev_priv, + R600_TC_ACTION_ENA, (src_pitch * (sy + h)), src_gpu_addr); + + /* dst */ + set_render_target(dev_priv, cb_format, + dst_pitch / cpp, dy + h, + dst_gpu_addr); + + /* scissors */ + set_scissors(dev_priv, dx, dy, dx + w, dy + h); + + /* Vertex buffer setup */ + vb_addr = dev_priv->gart_buffers_offset + + dev_priv->blit_vb->offset + + dev_priv->blit_vb->used; + set_vtx_resource(dev_priv, vb_addr); + + /* draw */ + draw_auto(dev_priv); + + cp_set_surface_sync(dev_priv, + R600_CB_ACTION_ENA | R600_CB0_DEST_BASE_ENA, + dst_pitch * (dy + h), dst_gpu_addr); + + dev_priv->blit_vb->used += 12 * 4; +} diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c new file mode 100644 index 000000000000..5755647e688a --- /dev/null +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -0,0 +1,777 @@ +#include "drmP.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon.h" + +#include "r600d.h" +#include "r600_blit_shaders.h" + +#define DI_PT_RECTLIST 0x11 +#define DI_INDEX_SIZE_16_BIT 0x0 +#define DI_SRC_SEL_AUTO_INDEX 0x2 + +#define FMT_8 0x1 +#define FMT_5_6_5 0x8 +#define FMT_8_8_8_8 0x1a +#define COLOR_8 0x1 +#define COLOR_5_6_5 0x8 +#define COLOR_8_8_8_8 0x1a + +/* emits 21 on rv770+, 23 on r600 */ +static void +set_render_target(struct radeon_device *rdev, int format, + int w, int h, u64 gpu_addr) +{ + u32 cb_color_info; + int pitch, slice; + + h = (h + 7) & ~7; + if (h < 8) + h = 8; + + cb_color_info = ((format << 2) | (1 << 27)); + pitch = (w / 8) - 1; + slice = ((w * h) / 64) - 1; + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 1)); + radeon_ring_write(rdev, (CB_COLOR0_BASE - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, gpu_addr >> 8); + + if (rdev->family > CHIP_R600 && rdev->family < CHIP_RV770) { + radeon_ring_write(rdev, PACKET3(PACKET3_SURFACE_BASE_UPDATE, 0)); + radeon_ring_write(rdev, 2 << 0); + } + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 1)); + radeon_ring_write(rdev, (CB_COLOR0_SIZE - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, (pitch << 0) | (slice << 10)); + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 1)); + radeon_ring_write(rdev, (CB_COLOR0_VIEW - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, 0); + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 1)); + radeon_ring_write(rdev, (CB_COLOR0_INFO - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, cb_color_info); + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 1)); + radeon_ring_write(rdev, (CB_COLOR0_TILE - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, 0); + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 1)); + radeon_ring_write(rdev, (CB_COLOR0_FRAG - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, 0); + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 1)); + radeon_ring_write(rdev, (CB_COLOR0_MASK - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, 0); +} + +/* emits 5dw */ +static void +cp_set_surface_sync(struct radeon_device *rdev, + u32 sync_type, u32 size, + u64 mc_addr) +{ + u32 cp_coher_size; + + if (size == 0xffffffff) + cp_coher_size = 0xffffffff; + else + cp_coher_size = ((size + 255) >> 8); + + radeon_ring_write(rdev, PACKET3(PACKET3_SURFACE_SYNC, 3)); + radeon_ring_write(rdev, sync_type); + radeon_ring_write(rdev, cp_coher_size); + radeon_ring_write(rdev, mc_addr >> 8); + radeon_ring_write(rdev, 10); /* poll interval */ +} + +/* emits 21dw + 1 surface sync = 26dw */ +static void +set_shaders(struct radeon_device *rdev) +{ + u64 gpu_addr; + u32 sq_pgm_resources; + + /* setup shader regs */ + sq_pgm_resources = (1 << 0); + + /* VS */ + gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.vs_offset; + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 1)); + radeon_ring_write(rdev, (SQ_PGM_START_VS - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, gpu_addr >> 8); + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 1)); + radeon_ring_write(rdev, (SQ_PGM_RESOURCES_VS - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, sq_pgm_resources); + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 1)); + radeon_ring_write(rdev, (SQ_PGM_CF_OFFSET_VS - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, 0); + + /* PS */ + gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.ps_offset; + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 1)); + radeon_ring_write(rdev, (SQ_PGM_START_PS - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, gpu_addr >> 8); + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 1)); + radeon_ring_write(rdev, (SQ_PGM_RESOURCES_PS - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, sq_pgm_resources | (1 << 28)); + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 1)); + radeon_ring_write(rdev, (SQ_PGM_EXPORTS_PS - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, 2); + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 1)); + radeon_ring_write(rdev, (SQ_PGM_CF_OFFSET_PS - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, 0); + + cp_set_surface_sync(rdev, PACKET3_SH_ACTION_ENA, 512, gpu_addr); +} + +/* emits 9 + 1 sync (5) = 14*/ +static void +set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr) +{ + u32 sq_vtx_constant_word2; + + sq_vtx_constant_word2 = ((upper_32_bits(gpu_addr) & 0xff) | (16 << 8)); + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_RESOURCE, 7)); + radeon_ring_write(rdev, 0x460); + radeon_ring_write(rdev, gpu_addr & 0xffffffff); + radeon_ring_write(rdev, 48 - 1); + radeon_ring_write(rdev, sq_vtx_constant_word2); + radeon_ring_write(rdev, 1 << 0); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, SQ_TEX_VTX_VALID_BUFFER << 30); + + if ((rdev->family == CHIP_RV610) || + (rdev->family == CHIP_RV620) || + (rdev->family == CHIP_RS780) || + (rdev->family == CHIP_RS880) || + (rdev->family == CHIP_RV710)) + cp_set_surface_sync(rdev, + PACKET3_TC_ACTION_ENA, 48, gpu_addr); + else + cp_set_surface_sync(rdev, + PACKET3_VC_ACTION_ENA, 48, gpu_addr); +} + +/* emits 9 */ +static void +set_tex_resource(struct radeon_device *rdev, + int format, int w, int h, int pitch, + u64 gpu_addr) +{ + uint32_t sq_tex_resource_word0, sq_tex_resource_word1, sq_tex_resource_word4; + + if (h < 1) + h = 1; + + sq_tex_resource_word0 = (1 << 0); + sq_tex_resource_word0 |= ((((pitch >> 3) - 1) << 8) | + ((w - 1) << 19)); + + sq_tex_resource_word1 = (format << 26); + sq_tex_resource_word1 |= ((h - 1) << 0); + + sq_tex_resource_word4 = ((1 << 14) | + (0 << 16) | + (1 << 19) | + (2 << 22) | + (3 << 25)); + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_RESOURCE, 7)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, sq_tex_resource_word0); + radeon_ring_write(rdev, sq_tex_resource_word1); + radeon_ring_write(rdev, gpu_addr >> 8); + radeon_ring_write(rdev, gpu_addr >> 8); + radeon_ring_write(rdev, sq_tex_resource_word4); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, SQ_TEX_VTX_VALID_TEXTURE << 30); +} + +/* emits 12 */ +static void +set_scissors(struct radeon_device *rdev, int x1, int y1, + int x2, int y2) +{ + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2)); + radeon_ring_write(rdev, (PA_SC_SCREEN_SCISSOR_TL - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, (x1 << 0) | (y1 << 16)); + radeon_ring_write(rdev, (x2 << 0) | (y2 << 16)); + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2)); + radeon_ring_write(rdev, (PA_SC_GENERIC_SCISSOR_TL - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, (x1 << 0) | (y1 << 16) | (1 << 31)); + radeon_ring_write(rdev, (x2 << 0) | (y2 << 16)); + + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2)); + radeon_ring_write(rdev, (PA_SC_WINDOW_SCISSOR_TL - PACKET3_SET_CONTEXT_REG_OFFSET) >> 2); + radeon_ring_write(rdev, (x1 << 0) | (y1 << 16) | (1 << 31)); + radeon_ring_write(rdev, (x2 << 0) | (y2 << 16)); +} + +/* emits 10 */ +static void +draw_auto(struct radeon_device *rdev) +{ + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1)); + radeon_ring_write(rdev, (VGT_PRIMITIVE_TYPE - PACKET3_SET_CONFIG_REG_OFFSET) >> 2); + radeon_ring_write(rdev, DI_PT_RECTLIST); + + radeon_ring_write(rdev, PACKET3(PACKET3_INDEX_TYPE, 0)); + radeon_ring_write(rdev, DI_INDEX_SIZE_16_BIT); + + radeon_ring_write(rdev, PACKET3(PACKET3_NUM_INSTANCES, 0)); + radeon_ring_write(rdev, 1); + + radeon_ring_write(rdev, PACKET3(PACKET3_DRAW_INDEX_AUTO, 1)); + radeon_ring_write(rdev, 3); + radeon_ring_write(rdev, DI_SRC_SEL_AUTO_INDEX); + +} + +/* emits 14 */ +static void +set_default_state(struct radeon_device *rdev) +{ + u32 sq_config, sq_gpr_resource_mgmt_1, sq_gpr_resource_mgmt_2; + u32 sq_thread_resource_mgmt, sq_stack_resource_mgmt_1, sq_stack_resource_mgmt_2; + int num_ps_gprs, num_vs_gprs, num_temp_gprs, num_gs_gprs, num_es_gprs; + int num_ps_threads, num_vs_threads, num_gs_threads, num_es_threads; + int num_ps_stack_entries, num_vs_stack_entries, num_gs_stack_entries, num_es_stack_entries; + u64 gpu_addr; + + switch (rdev->family) { + case CHIP_R600: + num_ps_gprs = 192; + num_vs_gprs = 56; + num_temp_gprs = 4; + num_gs_gprs = 0; + num_es_gprs = 0; + num_ps_threads = 136; + num_vs_threads = 48; + num_gs_threads = 4; + num_es_threads = 4; + num_ps_stack_entries = 128; + num_vs_stack_entries = 128; + num_gs_stack_entries = 0; + num_es_stack_entries = 0; + break; + case CHIP_RV630: + case CHIP_RV635: + num_ps_gprs = 84; + num_vs_gprs = 36; + num_temp_gprs = 4; + num_gs_gprs = 0; + num_es_gprs = 0; + num_ps_threads = 144; + num_vs_threads = 40; + num_gs_threads = 4; + num_es_threads = 4; + num_ps_stack_entries = 40; + num_vs_stack_entries = 40; + num_gs_stack_entries = 32; + num_es_stack_entries = 16; + break; + case CHIP_RV610: + case CHIP_RV620: + case CHIP_RS780: + case CHIP_RS880: + default: + num_ps_gprs = 84; + num_vs_gprs = 36; + num_temp_gprs = 4; + num_gs_gprs = 0; + num_es_gprs = 0; + num_ps_threads = 136; + num_vs_threads = 48; + num_gs_threads = 4; + num_es_threads = 4; + num_ps_stack_entries = 40; + num_vs_stack_entries = 40; + num_gs_stack_entries = 32; + num_es_stack_entries = 16; + break; + case CHIP_RV670: + num_ps_gprs = 144; + num_vs_gprs = 40; + num_temp_gprs = 4; + num_gs_gprs = 0; + num_es_gprs = 0; + num_ps_threads = 136; + num_vs_threads = 48; + num_gs_threads = 4; + num_es_threads = 4; + num_ps_stack_entries = 40; + num_vs_stack_entries = 40; + num_gs_stack_entries = 32; + num_es_stack_entries = 16; + break; + case CHIP_RV770: + num_ps_gprs = 192; + num_vs_gprs = 56; + num_temp_gprs = 4; + num_gs_gprs = 0; + num_es_gprs = 0; + num_ps_threads = 188; + num_vs_threads = 60; + num_gs_threads = 0; + num_es_threads = 0; + num_ps_stack_entries = 256; + num_vs_stack_entries = 256; + num_gs_stack_entries = 0; + num_es_stack_entries = 0; + break; + case CHIP_RV730: + case CHIP_RV740: + num_ps_gprs = 84; + num_vs_gprs = 36; + num_temp_gprs = 4; + num_gs_gprs = 0; + num_es_gprs = 0; + num_ps_threads = 188; + num_vs_threads = 60; + num_gs_threads = 0; + num_es_threads = 0; + num_ps_stack_entries = 128; + num_vs_stack_entries = 128; + num_gs_stack_entries = 0; + num_es_stack_entries = 0; + break; + case CHIP_RV710: + num_ps_gprs = 192; + num_vs_gprs = 56; + num_temp_gprs = 4; + num_gs_gprs = 0; + num_es_gprs = 0; + num_ps_threads = 144; + num_vs_threads = 48; + num_gs_threads = 0; + num_es_threads = 0; + num_ps_stack_entries = 128; + num_vs_stack_entries = 128; + num_gs_stack_entries = 0; + num_es_stack_entries = 0; + break; + } + + if ((rdev->family == CHIP_RV610) || + (rdev->family == CHIP_RV620) || + (rdev->family == CHIP_RS780) || + (rdev->family == CHIP_RS780) || + (rdev->family == CHIP_RV710)) + sq_config = 0; + else + sq_config = VC_ENABLE; + + sq_config |= (DX9_CONSTS | + ALU_INST_PREFER_VECTOR | + PS_PRIO(0) | + VS_PRIO(1) | + GS_PRIO(2) | + ES_PRIO(3)); + + sq_gpr_resource_mgmt_1 = (NUM_PS_GPRS(num_ps_gprs) | + NUM_VS_GPRS(num_vs_gprs) | + NUM_CLAUSE_TEMP_GPRS(num_temp_gprs)); + sq_gpr_resource_mgmt_2 = (NUM_GS_GPRS(num_gs_gprs) | + NUM_ES_GPRS(num_es_gprs)); + sq_thread_resource_mgmt = (NUM_PS_THREADS(num_ps_threads) | + NUM_VS_THREADS(num_vs_threads) | + NUM_GS_THREADS(num_gs_threads) | + NUM_ES_THREADS(num_es_threads)); + sq_stack_resource_mgmt_1 = (NUM_PS_STACK_ENTRIES(num_ps_stack_entries) | + NUM_VS_STACK_ENTRIES(num_vs_stack_entries)); + sq_stack_resource_mgmt_2 = (NUM_GS_STACK_ENTRIES(num_gs_stack_entries) | + NUM_ES_STACK_ENTRIES(num_es_stack_entries)); + + /* emit an IB pointing at default state */ + gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.state_offset; + radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); + radeon_ring_write(rdev, gpu_addr & 0xFFFFFFFC); + radeon_ring_write(rdev, upper_32_bits(gpu_addr) & 0xFF); + radeon_ring_write(rdev, (rdev->r600_blit.state_len / 4)); + + radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0)); + radeon_ring_write(rdev, CACHE_FLUSH_AND_INV_EVENT); + /* SQ config */ + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 6)); + radeon_ring_write(rdev, (SQ_CONFIG - PACKET3_SET_CONFIG_REG_OFFSET) >> 2); + radeon_ring_write(rdev, sq_config); + radeon_ring_write(rdev, sq_gpr_resource_mgmt_1); + radeon_ring_write(rdev, sq_gpr_resource_mgmt_2); + radeon_ring_write(rdev, sq_thread_resource_mgmt); + radeon_ring_write(rdev, sq_stack_resource_mgmt_1); + radeon_ring_write(rdev, sq_stack_resource_mgmt_2); +} + +static inline uint32_t i2f(uint32_t input) +{ + u32 result, i, exponent, fraction; + + if ((input & 0x3fff) == 0) + result = 0; /* 0 is a special case */ + else { + exponent = 140; /* exponent biased by 127; */ + fraction = (input & 0x3fff) << 10; /* cheat and only + handle numbers below 2^^15 */ + for (i = 0; i < 14; i++) { + if (fraction & 0x800000) + break; + else { + fraction = fraction << 1; /* keep + shifting left until top bit = 1 */ + exponent = exponent - 1; + } + } + result = exponent << 23 | (fraction & 0x7fffff); /* mask + off top bit; assumed 1 */ + } + return result; +} + +int r600_blit_init(struct radeon_device *rdev) +{ + u32 obj_size; + int r; + void *ptr; + + rdev->r600_blit.state_offset = 0; + + if (rdev->family >= CHIP_RV770) + rdev->r600_blit.state_len = r7xx_default_size * 4; + else + rdev->r600_blit.state_len = r6xx_default_size * 4; + + obj_size = rdev->r600_blit.state_len; + obj_size = ALIGN(obj_size, 256); + + rdev->r600_blit.vs_offset = obj_size; + obj_size += r6xx_vs_size * 4; + obj_size = ALIGN(obj_size, 256); + + rdev->r600_blit.ps_offset = obj_size; + obj_size += r6xx_ps_size * 4; + obj_size = ALIGN(obj_size, 256); + + r = radeon_object_create(rdev, NULL, obj_size, + true, RADEON_GEM_DOMAIN_VRAM, + false, &rdev->r600_blit.shader_obj); + if (r) { + DRM_ERROR("r600 failed to allocate shader\n"); + return r; + } + + r = radeon_object_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM, + &rdev->r600_blit.shader_gpu_addr); + if (r) { + DRM_ERROR("failed to pin blit object %d\n", r); + return r; + } + + DRM_DEBUG("r6xx blit allocated bo @ 0x%16llx %08x vs %08x ps %08x\n", + rdev->r600_blit.shader_gpu_addr, obj_size, + rdev->r600_blit.vs_offset, rdev->r600_blit.ps_offset); + + r = radeon_object_kmap(rdev->r600_blit.shader_obj, &ptr); + if (r) { + DRM_ERROR("failed to map blit object %d\n", r); + return r; + } + + if (rdev->family >= CHIP_RV770) + memcpy_toio(ptr + rdev->r600_blit.state_offset, r7xx_default_state, rdev->r600_blit.state_len); + else + memcpy_toio(ptr + rdev->r600_blit.state_offset, r6xx_default_state, rdev->r600_blit.state_len); + + memcpy(ptr + rdev->r600_blit.vs_offset, r6xx_vs, r6xx_vs_size * 4); + memcpy(ptr + rdev->r600_blit.ps_offset, r6xx_ps, r6xx_ps_size * 4); + + radeon_object_kunmap(rdev->r600_blit.shader_obj); + return 0; +} + +void r600_blit_fini(struct radeon_device *rdev) +{ + radeon_object_unpin(rdev->r600_blit.shader_obj); + radeon_object_unref(&rdev->r600_blit.shader_obj); +} + +int r600_vb_ib_get(struct radeon_device *rdev) +{ + int r; + r = radeon_ib_get(rdev, &rdev->r600_blit.vb_ib); + if (r) { + DRM_ERROR("failed to get IB for vertex buffer\n"); + return r; + } + + rdev->r600_blit.vb_total = 64*1024; + rdev->r600_blit.vb_used = 0; + return 0; +} + +void r600_vb_ib_put(struct radeon_device *rdev) +{ + mutex_lock(&rdev->ib_pool.mutex); + radeon_fence_emit(rdev, rdev->r600_blit.vb_ib->fence); + list_add_tail(&rdev->r600_blit.vb_ib->list, &rdev->ib_pool.scheduled_ibs); + mutex_unlock(&rdev->ib_pool.mutex); + radeon_ib_free(rdev, &rdev->r600_blit.vb_ib); +} + +int r600_blit_prepare_copy(struct radeon_device *rdev, int size_bytes) +{ + int r; + int ring_size; + const int max_size = 8192*8192; + + r = r600_vb_ib_get(rdev); + WARN_ON(r); + + /* loops of emits 64 + fence emit possible */ + ring_size = ((size_bytes + max_size) / max_size) * 78; + /* set default + shaders */ + ring_size += 40; /* shaders + def state */ + ring_size += 3; /* fence emit for VB IB */ + ring_size += 5; /* done copy */ + ring_size += 3; /* fence emit for done copy */ + r = radeon_ring_lock(rdev, ring_size); + WARN_ON(r); + + set_default_state(rdev); /* 14 */ + set_shaders(rdev); /* 26 */ + return 0; +} + +void r600_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence) +{ + int r; + + radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0)); + radeon_ring_write(rdev, CACHE_FLUSH_AND_INV_EVENT); + /* wait for 3D idle clean */ + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1)); + radeon_ring_write(rdev, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2); + radeon_ring_write(rdev, WAIT_3D_IDLE_bit | WAIT_3D_IDLECLEAN_bit); + + if (rdev->r600_blit.vb_ib) + r600_vb_ib_put(rdev); + + if (fence) + r = radeon_fence_emit(rdev, fence); + + radeon_ring_unlock_commit(rdev); +} + +void r600_kms_blit_copy(struct radeon_device *rdev, + u64 src_gpu_addr, u64 dst_gpu_addr, + int size_bytes) +{ + int max_bytes; + u64 vb_gpu_addr; + u32 *vb; + + DRM_DEBUG("emitting copy %16llx %16llx %d %d\n", src_gpu_addr, dst_gpu_addr, + size_bytes, rdev->r600_blit.vb_used); + vb = (u32 *)(rdev->r600_blit.vb_ib->ptr + rdev->r600_blit.vb_used); + if ((size_bytes & 3) || (src_gpu_addr & 3) || (dst_gpu_addr & 3)) { + max_bytes = 8192; + + while (size_bytes) { + int cur_size = size_bytes; + int src_x = src_gpu_addr & 255; + int dst_x = dst_gpu_addr & 255; + int h = 1; + src_gpu_addr = src_gpu_addr & ~255; + dst_gpu_addr = dst_gpu_addr & ~255; + + if (!src_x && !dst_x) { + h = (cur_size / max_bytes); + if (h > 8192) + h = 8192; + if (h == 0) + h = 1; + else + cur_size = max_bytes; + } else { + if (cur_size > max_bytes) + cur_size = max_bytes; + if (cur_size > (max_bytes - dst_x)) + cur_size = (max_bytes - dst_x); + if (cur_size > (max_bytes - src_x)) + cur_size = (max_bytes - src_x); + } + + if ((rdev->r600_blit.vb_used + 48) > rdev->r600_blit.vb_total) { + WARN_ON(1); + +#if 0 + r600_vb_ib_put(rdev); + + r600_nomm_put_vb(dev); + r600_nomm_get_vb(dev); + if (!dev_priv->blit_vb) + return; + set_shaders(dev); + vb = r600_nomm_get_vb_ptr(dev); +#endif + } + + vb[0] = i2f(dst_x); + vb[1] = 0; + vb[2] = i2f(src_x); + vb[3] = 0; + + vb[4] = i2f(dst_x); + vb[5] = i2f(h); + vb[6] = i2f(src_x); + vb[7] = i2f(h); + + vb[8] = i2f(dst_x + cur_size); + vb[9] = i2f(h); + vb[10] = i2f(src_x + cur_size); + vb[11] = i2f(h); + + /* src 9 */ + set_tex_resource(rdev, FMT_8, + src_x + cur_size, h, src_x + cur_size, + src_gpu_addr); + + /* 5 */ + cp_set_surface_sync(rdev, + PACKET3_TC_ACTION_ENA, (src_x + cur_size * h), src_gpu_addr); + + /* dst 23 */ + set_render_target(rdev, COLOR_8, + dst_x + cur_size, h, + dst_gpu_addr); + + /* scissors 12 */ + set_scissors(rdev, dst_x, 0, dst_x + cur_size, h); + + /* 14 */ + vb_gpu_addr = rdev->r600_blit.vb_ib->gpu_addr + rdev->r600_blit.vb_used; + set_vtx_resource(rdev, vb_gpu_addr); + + /* draw 10 */ + draw_auto(rdev); + + /* 5 */ + cp_set_surface_sync(rdev, + PACKET3_CB_ACTION_ENA | PACKET3_CB0_DEST_BASE_ENA, + cur_size * h, dst_gpu_addr); + + vb += 12; + rdev->r600_blit.vb_used += 12 * 4; + + src_gpu_addr += cur_size * h; + dst_gpu_addr += cur_size * h; + size_bytes -= cur_size * h; + } + } else { + max_bytes = 8192 * 4; + + while (size_bytes) { + int cur_size = size_bytes; + int src_x = (src_gpu_addr & 255); + int dst_x = (dst_gpu_addr & 255); + int h = 1; + src_gpu_addr = src_gpu_addr & ~255; + dst_gpu_addr = dst_gpu_addr & ~255; + + if (!src_x && !dst_x) { + h = (cur_size / max_bytes); + if (h > 8192) + h = 8192; + if (h == 0) + h = 1; + else + cur_size = max_bytes; + } else { + if (cur_size > max_bytes) + cur_size = max_bytes; + if (cur_size > (max_bytes - dst_x)) + cur_size = (max_bytes - dst_x); + if (cur_size > (max_bytes - src_x)) + cur_size = (max_bytes - src_x); + } + + if ((rdev->r600_blit.vb_used + 48) > rdev->r600_blit.vb_total) { + WARN_ON(1); + } +#if 0 + if ((rdev->blit_vb->used + 48) > rdev->blit_vb->total) { + r600_nomm_put_vb(dev); + r600_nomm_get_vb(dev); + if (!rdev->blit_vb) + return; + + set_shaders(dev); + vb = r600_nomm_get_vb_ptr(dev); + } +#endif + + vb[0] = i2f(dst_x / 4); + vb[1] = 0; + vb[2] = i2f(src_x / 4); + vb[3] = 0; + + vb[4] = i2f(dst_x / 4); + vb[5] = i2f(h); + vb[6] = i2f(src_x / 4); + vb[7] = i2f(h); + + vb[8] = i2f((dst_x + cur_size) / 4); + vb[9] = i2f(h); + vb[10] = i2f((src_x + cur_size) / 4); + vb[11] = i2f(h); + + /* src 9 */ + set_tex_resource(rdev, FMT_8_8_8_8, + (src_x + cur_size) / 4, + h, (src_x + cur_size) / 4, + src_gpu_addr); + /* 5 */ + cp_set_surface_sync(rdev, + PACKET3_TC_ACTION_ENA, (src_x + cur_size * h), src_gpu_addr); + + /* dst 23 */ + set_render_target(rdev, COLOR_8_8_8_8, + dst_x + cur_size, h, + dst_gpu_addr); + + /* scissors 12 */ + set_scissors(rdev, (dst_x / 4), 0, (dst_x + cur_size / 4), h); + + /* Vertex buffer setup 14 */ + vb_gpu_addr = rdev->r600_blit.vb_ib->gpu_addr + rdev->r600_blit.vb_used; + set_vtx_resource(rdev, vb_gpu_addr); + + /* draw 10 */ + draw_auto(rdev); + + /* 5 */ + cp_set_surface_sync(rdev, + PACKET3_CB_ACTION_ENA | PACKET3_CB0_DEST_BASE_ENA, + cur_size * h, dst_gpu_addr); + + /* 78 ring dwords per loop */ + vb += 12; + rdev->r600_blit.vb_used += 12 * 4; + + src_gpu_addr += cur_size * h; + dst_gpu_addr += cur_size * h; + size_bytes -= cur_size * h; + } + } +} + diff --git a/drivers/gpu/drm/radeon/r600_blit_shaders.c b/drivers/gpu/drm/radeon/r600_blit_shaders.c new file mode 100644 index 000000000000..d745e815c2e8 --- /dev/null +++ b/drivers/gpu/drm/radeon/r600_blit_shaders.c @@ -0,0 +1,1072 @@ + +#include +#include + +const u32 r6xx_default_state[] = +{ + 0xc0002400, + 0x00000000, + 0xc0012800, + 0x80000000, + 0x80000000, + 0xc0004600, + 0x00000016, + 0xc0016800, + 0x00000010, + 0x00028000, + 0xc0016800, + 0x00000010, + 0x00008000, + 0xc0016800, + 0x00000542, + 0x07000003, + 0xc0016800, + 0x000005c5, + 0x00000000, + 0xc0016800, + 0x00000363, + 0x00000000, + 0xc0016800, + 0x0000060c, + 0x82000000, + 0xc0016800, + 0x0000060e, + 0x01020204, + 0xc0016f00, + 0x00000000, + 0x00000000, + 0xc0016f00, + 0x00000001, + 0x00000000, + 0xc0096900, + 0x0000022a, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xc0016900, + 0x00000004, + 0x00000000, + 0xc0016900, + 0x0000000a, + 0x00000000, + 0xc0016900, + 0x0000000b, + 0x00000000, + 0xc0016900, + 0x0000010c, + 0x00000000, + 0xc0016900, + 0x0000010d, + 0x00000000, + 0xc0016900, + 0x00000200, + 0x00000000, + 0xc0016900, + 0x00000343, + 0x00000060, + 0xc0016900, + 0x00000344, + 0x00000040, + 0xc0016900, + 0x00000351, + 0x0000aa00, + 0xc0016900, + 0x00000104, + 0x00000000, + 0xc0016900, + 0x0000010e, + 0x00000000, + 0xc0046900, + 0x00000105, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xc0036900, + 0x00000109, + 0x00000000, + 0x00000000, + 0x00000000, + 0xc0046900, + 0x0000030c, + 0x01000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xc0046900, + 0x00000048, + 0x3f800000, + 0x00000000, + 0x3f800000, + 0x3f800000, + 0xc0016900, + 0x0000008e, + 0x0000000f, + 0xc0016900, + 0x00000080, + 0x00000000, + 0xc0016900, + 0x00000083, + 0x0000ffff, + 0xc0016900, + 0x00000084, + 0x00000000, + 0xc0016900, + 0x00000085, + 0x20002000, + 0xc0016900, + 0x00000086, + 0x00000000, + 0xc0016900, + 0x00000087, + 0x20002000, + 0xc0016900, + 0x00000088, + 0x00000000, + 0xc0016900, + 0x00000089, + 0x20002000, + 0xc0016900, + 0x0000008a, + 0x00000000, + 0xc0016900, + 0x0000008b, + 0x20002000, + 0xc0016900, + 0x0000008c, + 0x00000000, + 0xc0016900, + 0x00000094, + 0x80000000, + 0xc0016900, + 0x00000095, + 0x20002000, + 0xc0026900, + 0x000000b4, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x00000096, + 0x80000000, + 0xc0016900, + 0x00000097, + 0x20002000, + 0xc0026900, + 0x000000b6, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x00000098, + 0x80000000, + 0xc0016900, + 0x00000099, + 0x20002000, + 0xc0026900, + 0x000000b8, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x0000009a, + 0x80000000, + 0xc0016900, + 0x0000009b, + 0x20002000, + 0xc0026900, + 0x000000ba, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x0000009c, + 0x80000000, + 0xc0016900, + 0x0000009d, + 0x20002000, + 0xc0026900, + 0x000000bc, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x0000009e, + 0x80000000, + 0xc0016900, + 0x0000009f, + 0x20002000, + 0xc0026900, + 0x000000be, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000a0, + 0x80000000, + 0xc0016900, + 0x000000a1, + 0x20002000, + 0xc0026900, + 0x000000c0, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000a2, + 0x80000000, + 0xc0016900, + 0x000000a3, + 0x20002000, + 0xc0026900, + 0x000000c2, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000a4, + 0x80000000, + 0xc0016900, + 0x000000a5, + 0x20002000, + 0xc0026900, + 0x000000c4, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000a6, + 0x80000000, + 0xc0016900, + 0x000000a7, + 0x20002000, + 0xc0026900, + 0x000000c6, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000a8, + 0x80000000, + 0xc0016900, + 0x000000a9, + 0x20002000, + 0xc0026900, + 0x000000c8, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000aa, + 0x80000000, + 0xc0016900, + 0x000000ab, + 0x20002000, + 0xc0026900, + 0x000000ca, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000ac, + 0x80000000, + 0xc0016900, + 0x000000ad, + 0x20002000, + 0xc0026900, + 0x000000cc, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000ae, + 0x80000000, + 0xc0016900, + 0x000000af, + 0x20002000, + 0xc0026900, + 0x000000ce, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000b0, + 0x80000000, + 0xc0016900, + 0x000000b1, + 0x20002000, + 0xc0026900, + 0x000000d0, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000b2, + 0x80000000, + 0xc0016900, + 0x000000b3, + 0x20002000, + 0xc0026900, + 0x000000d2, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x00000293, + 0x00004010, + 0xc0016900, + 0x00000300, + 0x00000000, + 0xc0016900, + 0x00000301, + 0x00000000, + 0xc0016900, + 0x00000312, + 0xffffffff, + 0xc0016900, + 0x00000307, + 0x00000000, + 0xc0016900, + 0x00000308, + 0x00000000, + 0xc0016900, + 0x00000283, + 0x00000000, + 0xc0016900, + 0x00000292, + 0x00000000, + 0xc0066900, + 0x0000010f, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xc0016900, + 0x00000206, + 0x00000000, + 0xc0016900, + 0x00000207, + 0x00000000, + 0xc0016900, + 0x00000208, + 0x00000000, + 0xc0046900, + 0x00000303, + 0x3f800000, + 0x3f800000, + 0x3f800000, + 0x3f800000, + 0xc0016900, + 0x00000205, + 0x00000004, + 0xc0016900, + 0x00000280, + 0x00000000, + 0xc0016900, + 0x00000281, + 0x00000000, + 0xc0016900, + 0x0000037e, + 0x00000000, + 0xc0016900, + 0x00000382, + 0x00000000, + 0xc0016900, + 0x00000380, + 0x00000000, + 0xc0016900, + 0x00000383, + 0x00000000, + 0xc0016900, + 0x00000381, + 0x00000000, + 0xc0016900, + 0x00000282, + 0x00000008, + 0xc0016900, + 0x00000302, + 0x0000002d, + 0xc0016900, + 0x0000037f, + 0x00000000, + 0xc0016900, + 0x000001b2, + 0x00000000, + 0xc0016900, + 0x000001b6, + 0x00000000, + 0xc0016900, + 0x000001b7, + 0x00000000, + 0xc0016900, + 0x000001b8, + 0x00000000, + 0xc0016900, + 0x000001b9, + 0x00000000, + 0xc0016900, + 0x00000225, + 0x00000000, + 0xc0016900, + 0x00000229, + 0x00000000, + 0xc0016900, + 0x00000237, + 0x00000000, + 0xc0016900, + 0x00000100, + 0x00000800, + 0xc0016900, + 0x00000101, + 0x00000000, + 0xc0016900, + 0x00000102, + 0x00000000, + 0xc0016900, + 0x000002a8, + 0x00000000, + 0xc0016900, + 0x000002a9, + 0x00000000, + 0xc0016900, + 0x00000103, + 0x00000000, + 0xc0016900, + 0x00000284, + 0x00000000, + 0xc0016900, + 0x00000290, + 0x00000000, + 0xc0016900, + 0x00000285, + 0x00000000, + 0xc0016900, + 0x00000286, + 0x00000000, + 0xc0016900, + 0x00000287, + 0x00000000, + 0xc0016900, + 0x00000288, + 0x00000000, + 0xc0016900, + 0x00000289, + 0x00000000, + 0xc0016900, + 0x0000028a, + 0x00000000, + 0xc0016900, + 0x0000028b, + 0x00000000, + 0xc0016900, + 0x0000028c, + 0x00000000, + 0xc0016900, + 0x0000028d, + 0x00000000, + 0xc0016900, + 0x0000028e, + 0x00000000, + 0xc0016900, + 0x0000028f, + 0x00000000, + 0xc0016900, + 0x000002a1, + 0x00000000, + 0xc0016900, + 0x000002a5, + 0x00000000, + 0xc0016900, + 0x000002ac, + 0x00000000, + 0xc0016900, + 0x000002ad, + 0x00000000, + 0xc0016900, + 0x000002ae, + 0x00000000, + 0xc0016900, + 0x000002c8, + 0x00000000, + 0xc0016900, + 0x00000206, + 0x00000100, + 0xc0016900, + 0x00000204, + 0x00010000, + 0xc0036e00, + 0x00000000, + 0x00000012, + 0x00000000, + 0x00000000, + 0xc0016900, + 0x0000008f, + 0x0000000f, + 0xc0016900, + 0x000001e8, + 0x00000001, + 0xc0016900, + 0x00000202, + 0x00cc0000, + 0xc0016900, + 0x00000205, + 0x00000244, + 0xc0016900, + 0x00000203, + 0x00000210, + 0xc0016900, + 0x000001b1, + 0x00000000, + 0xc0016900, + 0x00000185, + 0x00000000, + 0xc0016900, + 0x000001b3, + 0x00000001, + 0xc0016900, + 0x000001b4, + 0x00000000, + 0xc0016900, + 0x00000191, + 0x00000b00, + 0xc0016900, + 0x000001b5, + 0x00000000, +}; + +const u32 r7xx_default_state[] = +{ + 0xc0012800, + 0x80000000, + 0x80000000, + 0xc0004600, + 0x00000016, + 0xc0016800, + 0x00000010, + 0x00028000, + 0xc0016800, + 0x00000010, + 0x00008000, + 0xc0016800, + 0x00000542, + 0x07000002, + 0xc0016800, + 0x000005c5, + 0x00000000, + 0xc0016800, + 0x00000363, + 0x00004000, + 0xc0016800, + 0x0000060c, + 0x00000000, + 0xc0016800, + 0x0000060e, + 0x00420204, + 0xc0016f00, + 0x00000000, + 0x00000000, + 0xc0016f00, + 0x00000001, + 0x00000000, + 0xc0096900, + 0x0000022a, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xc0016900, + 0x00000004, + 0x00000000, + 0xc0016900, + 0x0000000a, + 0x00000000, + 0xc0016900, + 0x0000000b, + 0x00000000, + 0xc0016900, + 0x0000010c, + 0x00000000, + 0xc0016900, + 0x0000010d, + 0x00000000, + 0xc0016900, + 0x00000200, + 0x00000000, + 0xc0016900, + 0x00000343, + 0x00000060, + 0xc0016900, + 0x00000344, + 0x00000000, + 0xc0016900, + 0x00000351, + 0x0000aa00, + 0xc0016900, + 0x00000104, + 0x00000000, + 0xc0016900, + 0x0000010e, + 0x00000000, + 0xc0046900, + 0x00000105, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xc0046900, + 0x0000030c, + 0x01000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xc0016900, + 0x0000008e, + 0x0000000f, + 0xc0016900, + 0x00000080, + 0x00000000, + 0xc0016900, + 0x00000083, + 0x0000ffff, + 0xc0016900, + 0x00000084, + 0x00000000, + 0xc0016900, + 0x00000085, + 0x20002000, + 0xc0016900, + 0x00000086, + 0x00000000, + 0xc0016900, + 0x00000087, + 0x20002000, + 0xc0016900, + 0x00000088, + 0x00000000, + 0xc0016900, + 0x00000089, + 0x20002000, + 0xc0016900, + 0x0000008a, + 0x00000000, + 0xc0016900, + 0x0000008b, + 0x20002000, + 0xc0016900, + 0x0000008c, + 0xaaaaaaaa, + 0xc0016900, + 0x00000094, + 0x80000000, + 0xc0016900, + 0x00000095, + 0x20002000, + 0xc0026900, + 0x000000b4, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x00000096, + 0x80000000, + 0xc0016900, + 0x00000097, + 0x20002000, + 0xc0026900, + 0x000000b6, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x00000098, + 0x80000000, + 0xc0016900, + 0x00000099, + 0x20002000, + 0xc0026900, + 0x000000b8, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x0000009a, + 0x80000000, + 0xc0016900, + 0x0000009b, + 0x20002000, + 0xc0026900, + 0x000000ba, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x0000009c, + 0x80000000, + 0xc0016900, + 0x0000009d, + 0x20002000, + 0xc0026900, + 0x000000bc, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x0000009e, + 0x80000000, + 0xc0016900, + 0x0000009f, + 0x20002000, + 0xc0026900, + 0x000000be, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000a0, + 0x80000000, + 0xc0016900, + 0x000000a1, + 0x20002000, + 0xc0026900, + 0x000000c0, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000a2, + 0x80000000, + 0xc0016900, + 0x000000a3, + 0x20002000, + 0xc0026900, + 0x000000c2, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000a4, + 0x80000000, + 0xc0016900, + 0x000000a5, + 0x20002000, + 0xc0026900, + 0x000000c4, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000a6, + 0x80000000, + 0xc0016900, + 0x000000a7, + 0x20002000, + 0xc0026900, + 0x000000c6, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000a8, + 0x80000000, + 0xc0016900, + 0x000000a9, + 0x20002000, + 0xc0026900, + 0x000000c8, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000aa, + 0x80000000, + 0xc0016900, + 0x000000ab, + 0x20002000, + 0xc0026900, + 0x000000ca, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000ac, + 0x80000000, + 0xc0016900, + 0x000000ad, + 0x20002000, + 0xc0026900, + 0x000000cc, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000ae, + 0x80000000, + 0xc0016900, + 0x000000af, + 0x20002000, + 0xc0026900, + 0x000000ce, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000b0, + 0x80000000, + 0xc0016900, + 0x000000b1, + 0x20002000, + 0xc0026900, + 0x000000d0, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x000000b2, + 0x80000000, + 0xc0016900, + 0x000000b3, + 0x20002000, + 0xc0026900, + 0x000000d2, + 0x00000000, + 0x3f800000, + 0xc0016900, + 0x00000293, + 0x00514000, + 0xc0016900, + 0x00000300, + 0x00000000, + 0xc0016900, + 0x00000301, + 0x00000000, + 0xc0016900, + 0x00000312, + 0xffffffff, + 0xc0016900, + 0x00000307, + 0x00000000, + 0xc0016900, + 0x00000308, + 0x00000000, + 0xc0016900, + 0x00000283, + 0x00000000, + 0xc0016900, + 0x00000292, + 0x00000000, + 0xc0066900, + 0x0000010f, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xc0016900, + 0x00000206, + 0x00000000, + 0xc0016900, + 0x00000207, + 0x00000000, + 0xc0016900, + 0x00000208, + 0x00000000, + 0xc0046900, + 0x00000303, + 0x3f800000, + 0x3f800000, + 0x3f800000, + 0x3f800000, + 0xc0016900, + 0x00000205, + 0x00000004, + 0xc0016900, + 0x00000280, + 0x00000000, + 0xc0016900, + 0x00000281, + 0x00000000, + 0xc0016900, + 0x0000037e, + 0x00000000, + 0xc0016900, + 0x00000382, + 0x00000000, + 0xc0016900, + 0x00000380, + 0x00000000, + 0xc0016900, + 0x00000383, + 0x00000000, + 0xc0016900, + 0x00000381, + 0x00000000, + 0xc0016900, + 0x00000282, + 0x00000008, + 0xc0016900, + 0x00000302, + 0x0000002d, + 0xc0016900, + 0x0000037f, + 0x00000000, + 0xc0016900, + 0x000001b2, + 0x00000001, + 0xc0016900, + 0x000001b6, + 0x00000000, + 0xc0016900, + 0x000001b7, + 0x00000000, + 0xc0016900, + 0x000001b8, + 0x00000000, + 0xc0016900, + 0x000001b9, + 0x00000000, + 0xc0016900, + 0x00000225, + 0x00000000, + 0xc0016900, + 0x00000229, + 0x00000000, + 0xc0016900, + 0x00000237, + 0x00000000, + 0xc0016900, + 0x00000100, + 0x00000800, + 0xc0016900, + 0x00000101, + 0x00000000, + 0xc0016900, + 0x00000102, + 0x00000000, + 0xc0016900, + 0x000002a8, + 0x00000000, + 0xc0016900, + 0x000002a9, + 0x00000000, + 0xc0016900, + 0x00000103, + 0x00000000, + 0xc0016900, + 0x00000284, + 0x00000000, + 0xc0016900, + 0x00000290, + 0x00000000, + 0xc0016900, + 0x00000285, + 0x00000000, + 0xc0016900, + 0x00000286, + 0x00000000, + 0xc0016900, + 0x00000287, + 0x00000000, + 0xc0016900, + 0x00000288, + 0x00000000, + 0xc0016900, + 0x00000289, + 0x00000000, + 0xc0016900, + 0x0000028a, + 0x00000000, + 0xc0016900, + 0x0000028b, + 0x00000000, + 0xc0016900, + 0x0000028c, + 0x00000000, + 0xc0016900, + 0x0000028d, + 0x00000000, + 0xc0016900, + 0x0000028e, + 0x00000000, + 0xc0016900, + 0x0000028f, + 0x00000000, + 0xc0016900, + 0x000002a1, + 0x00000000, + 0xc0016900, + 0x000002a5, + 0x00000000, + 0xc0016900, + 0x000002ac, + 0x00000000, + 0xc0016900, + 0x000002ad, + 0x00000000, + 0xc0016900, + 0x000002ae, + 0x00000000, + 0xc0016900, + 0x000002c8, + 0x00000000, + 0xc0016900, + 0x00000206, + 0x00000100, + 0xc0016900, + 0x00000204, + 0x00010000, + 0xc0036e00, + 0x00000000, + 0x00000012, + 0x00000000, + 0x00000000, + 0xc0016900, + 0x0000008f, + 0x0000000f, + 0xc0016900, + 0x000001e8, + 0x00000001, + 0xc0016900, + 0x00000202, + 0x00cc0000, + 0xc0016900, + 0x00000205, + 0x00000244, + 0xc0016900, + 0x00000203, + 0x00000210, + 0xc0016900, + 0x000001b1, + 0x00000000, + 0xc0016900, + 0x00000185, + 0x00000000, + 0xc0016900, + 0x000001b3, + 0x00000001, + 0xc0016900, + 0x000001b4, + 0x00000000, + 0xc0016900, + 0x00000191, + 0x00000b00, + 0xc0016900, + 0x000001b5, + 0x00000000, +}; + +/* same for r6xx/r7xx */ +const u32 r6xx_vs[] = +{ + 0x00000004, + 0x81000000, + 0x0000203c, + 0x94000b08, + 0x00004000, + 0x14200b1a, + 0x00000000, + 0x00000000, + 0x3c000000, + 0x68cd1000, + 0x00080000, + 0x00000000, +}; + +const u32 r6xx_ps[] = +{ + 0x00000002, + 0x80800000, + 0x00000000, + 0x94200688, + 0x00000010, + 0x000d1000, + 0xb0800000, + 0x00000000, +}; + +const u32 r6xx_ps_size = ARRAY_SIZE(r6xx_ps); +const u32 r6xx_vs_size = ARRAY_SIZE(r6xx_vs); +const u32 r6xx_default_size = ARRAY_SIZE(r6xx_default_state); +const u32 r7xx_default_size = ARRAY_SIZE(r7xx_default_state); diff --git a/drivers/gpu/drm/radeon/r600_blit_shaders.h b/drivers/gpu/drm/radeon/r600_blit_shaders.h new file mode 100644 index 000000000000..fdc3b378cbb0 --- /dev/null +++ b/drivers/gpu/drm/radeon/r600_blit_shaders.h @@ -0,0 +1,14 @@ + +#ifndef R600_BLIT_SHADERS_H +#define R600_BLIT_SHADERS_H + +extern const u32 r6xx_ps[]; +extern const u32 r6xx_vs[]; +extern const u32 r7xx_default_state[]; +extern const u32 r6xx_default_state[]; + + +extern const u32 r6xx_ps_size, r6xx_vs_size; +extern const u32 r6xx_default_size, r7xx_default_size; + +#endif diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c index 8327912de964..6d5a711c2e91 100644 --- a/drivers/gpu/drm/radeon/r600_cp.c +++ b/drivers/gpu/drm/radeon/r600_cp.c @@ -58,6 +58,12 @@ MODULE_FIRMWARE("radeon/RV730_me.bin"); MODULE_FIRMWARE("radeon/RV710_pfp.bin"); MODULE_FIRMWARE("radeon/RV710_me.bin"); + +int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp, + unsigned family, u32 *ib, int *l); +void r600_cs_legacy_init(void); + + # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ # define ATI_PCIGART_PAGE_MASK (~(ATI_PCIGART_PAGE_SIZE-1)) @@ -1857,6 +1863,8 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, DRM_DEBUG("\n"); + mutex_init(&dev_priv->cs_mutex); + r600_cs_legacy_init(); /* if we require new memory map but we don't have it fail */ if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) { DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n"); @@ -1888,7 +1896,7 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, /* Enable vblank on CRTC1 for older X servers */ dev_priv->vblank_crtc = DRM_RADEON_VBLANK_CRTC1; - + dev_priv->do_boxes = 0; dev_priv->cp_mode = init->cp_mode; /* We don't support anything other than bus-mastering ring mode, @@ -1974,11 +1982,11 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, } else #endif { - dev_priv->cp_ring->handle = (void *)dev_priv->cp_ring->offset; + dev_priv->cp_ring->handle = (void *)(unsigned long)dev_priv->cp_ring->offset; dev_priv->ring_rptr->handle = - (void *)dev_priv->ring_rptr->offset; + (void *)(unsigned long)dev_priv->ring_rptr->offset; dev->agp_buffer_map->handle = - (void *)dev->agp_buffer_map->offset; + (void *)(unsigned long)dev->agp_buffer_map->offset; DRM_DEBUG("dev_priv->cp_ring->handle %p\n", dev_priv->cp_ring->handle); @@ -2282,3 +2290,239 @@ int r600_cp_dispatch_indirect(struct drm_device *dev, return 0; } + +void r600_cp_dispatch_swap(struct drm_device *dev, struct drm_file *file_priv) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_master *master = file_priv->master; + struct drm_radeon_master_private *master_priv = master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; + int nbox = sarea_priv->nbox; + struct drm_clip_rect *pbox = sarea_priv->boxes; + int i, cpp, src_pitch, dst_pitch; + uint64_t src, dst; + RING_LOCALS; + DRM_DEBUG("\n"); + + if (dev_priv->color_fmt == RADEON_COLOR_FORMAT_ARGB8888) + cpp = 4; + else + cpp = 2; + + if (sarea_priv->pfCurrentPage == 0) { + src_pitch = dev_priv->back_pitch; + dst_pitch = dev_priv->front_pitch; + src = dev_priv->back_offset + dev_priv->fb_location; + dst = dev_priv->front_offset + dev_priv->fb_location; + } else { + src_pitch = dev_priv->front_pitch; + dst_pitch = dev_priv->back_pitch; + src = dev_priv->front_offset + dev_priv->fb_location; + dst = dev_priv->back_offset + dev_priv->fb_location; + } + + if (r600_prepare_blit_copy(dev, file_priv)) { + DRM_ERROR("unable to allocate vertex buffer for swap buffer\n"); + return; + } + for (i = 0; i < nbox; i++) { + int x = pbox[i].x1; + int y = pbox[i].y1; + int w = pbox[i].x2 - x; + int h = pbox[i].y2 - y; + + DRM_DEBUG("%d,%d-%d,%d\n", x, y, w, h); + + r600_blit_swap(dev, + src, dst, + x, y, x, y, w, h, + src_pitch, dst_pitch, cpp); + } + r600_done_blit_copy(dev); + + /* Increment the frame counter. The client-side 3D driver must + * throttle the framerate by waiting for this value before + * performing the swapbuffer ioctl. + */ + sarea_priv->last_frame++; + + BEGIN_RING(3); + R600_FRAME_AGE(sarea_priv->last_frame); + ADVANCE_RING(); +} + +int r600_cp_dispatch_texture(struct drm_device *dev, + struct drm_file *file_priv, + drm_radeon_texture_t *tex, + drm_radeon_tex_image_t *image) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_buf *buf; + u32 *buffer; + const u8 __user *data; + int size, pass_size; + u64 src_offset, dst_offset; + + if (!radeon_check_offset(dev_priv, tex->offset)) { + DRM_ERROR("Invalid destination offset\n"); + return -EINVAL; + } + + /* this might fail for zero-sized uploads - are those illegal? */ + if (!radeon_check_offset(dev_priv, tex->offset + tex->height * tex->pitch - 1)) { + DRM_ERROR("Invalid final destination offset\n"); + return -EINVAL; + } + + size = tex->height * tex->pitch; + + if (size == 0) + return 0; + + dst_offset = tex->offset; + + if (r600_prepare_blit_copy(dev, file_priv)) { + DRM_ERROR("unable to allocate vertex buffer for swap buffer\n"); + return -EAGAIN; + } + do { + data = (const u8 __user *)image->data; + pass_size = size; + + buf = radeon_freelist_get(dev); + if (!buf) { + DRM_DEBUG("EAGAIN\n"); + if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image))) + return -EFAULT; + return -EAGAIN; + } + + if (pass_size > buf->total) + pass_size = buf->total; + + /* Dispatch the indirect buffer. + */ + buffer = + (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset); + + if (DRM_COPY_FROM_USER(buffer, data, pass_size)) { + DRM_ERROR("EFAULT on pad, %d bytes\n", pass_size); + return -EFAULT; + } + + buf->file_priv = file_priv; + buf->used = pass_size; + src_offset = dev_priv->gart_buffers_offset + buf->offset; + + r600_blit_copy(dev, src_offset, dst_offset, pass_size); + + radeon_cp_discard_buffer(dev, file_priv->master, buf); + + /* Update the input parameters for next time */ + image->data = (const u8 __user *)image->data + pass_size; + dst_offset += pass_size; + size -= pass_size; + } while (size > 0); + r600_done_blit_copy(dev); + + return 0; +} + +/* + * Legacy cs ioctl + */ +static u32 radeon_cs_id_get(struct drm_radeon_private *radeon) +{ + /* FIXME: check if wrap affect last reported wrap & sequence */ + radeon->cs_id_scnt = (radeon->cs_id_scnt + 1) & 0x00FFFFFF; + if (!radeon->cs_id_scnt) { + /* increment wrap counter */ + radeon->cs_id_wcnt += 0x01000000; + /* valid sequence counter start at 1 */ + radeon->cs_id_scnt = 1; + } + return (radeon->cs_id_scnt | radeon->cs_id_wcnt); +} + +static void r600_cs_id_emit(drm_radeon_private_t *dev_priv, u32 *id) +{ + RING_LOCALS; + + *id = radeon_cs_id_get(dev_priv); + + /* SCRATCH 2 */ + BEGIN_RING(3); + R600_CLEAR_AGE(*id); + ADVANCE_RING(); + COMMIT_RING(); +} + +static int r600_ib_get(struct drm_device *dev, + struct drm_file *fpriv, + struct drm_buf **buffer) +{ + struct drm_buf *buf; + + *buffer = NULL; + buf = radeon_freelist_get(dev); + if (!buf) { + return -EBUSY; + } + buf->file_priv = fpriv; + *buffer = buf; + return 0; +} + +static void r600_ib_free(struct drm_device *dev, struct drm_buf *buf, + struct drm_file *fpriv, int l, int r) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + if (buf) { + if (!r) + r600_cp_dispatch_indirect(dev, buf, 0, l * 4); + radeon_cp_discard_buffer(dev, fpriv->master, buf); + COMMIT_RING(); + } +} + +int r600_cs_legacy_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_radeon_cs *cs = data; + struct drm_buf *buf; + unsigned family; + int l, r = 0; + u32 *ib, cs_id = 0; + + if (dev_priv == NULL) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + family = dev_priv->flags & RADEON_FAMILY_MASK; + if (family < CHIP_R600) { + DRM_ERROR("cs ioctl valid only for R6XX & R7XX in legacy mode\n"); + return -EINVAL; + } + mutex_lock(&dev_priv->cs_mutex); + /* get ib */ + r = r600_ib_get(dev, fpriv, &buf); + if (r) { + DRM_ERROR("ib_get failed\n"); + goto out; + } + ib = dev->agp_buffer_map->handle + buf->offset; + /* now parse command stream */ + r = r600_cs_legacy(dev, data, fpriv, family, ib, &l); + if (r) { + goto out; + } + +out: + r600_ib_free(dev, buf, fpriv, l, r); + /* emit cs id sequence */ + r600_cs_id_emit(dev_priv, &cs_id); + cs->cs_id = cs_id; + mutex_unlock(&dev_priv->cs_mutex); + return r; +} diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c new file mode 100644 index 000000000000..39bf6349351b --- /dev/null +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -0,0 +1,658 @@ +/* + * 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 "drmP.h" +#include "radeon.h" +#include "radeon_share.h" +#include "r600d.h" +#include "avivod.h" + +static int r600_cs_packet_next_reloc_mm(struct radeon_cs_parser *p, + struct radeon_cs_reloc **cs_reloc); +static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p, + struct radeon_cs_reloc **cs_reloc); +typedef int (*next_reloc_t)(struct radeon_cs_parser*, struct radeon_cs_reloc**); +static next_reloc_t r600_cs_packet_next_reloc = &r600_cs_packet_next_reloc_mm; + +/** + * r600_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 r600_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 = ib_chunk->kdata[idx]; + pkt->idx = idx; + pkt->type = CP_PACKET_GET_TYPE(header); + pkt->count = CP_PACKET_GET_COUNT(header); + pkt->one_reg_wr = 0; + switch (pkt->type) { + case PACKET_TYPE0: + pkt->reg = CP_PACKET0_GET_REG(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; +} + +/** + * r600_cs_packet_next_reloc_mm() - parse next packet which should be reloc packet3 + * @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 next packet is relocation packet3, do bo validation and compute + * GPU offset using the provided start. + **/ +static int r600_cs_packet_next_reloc_mm(struct radeon_cs_parser *p, + struct radeon_cs_reloc **cs_reloc) +{ + struct radeon_cs_chunk *ib_chunk; + 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; + ib_chunk = &p->chunks[p->chunk_ib_idx]; + relocs_chunk = &p->chunks[p->chunk_relocs_idx]; + r = r600_cs_packet_parse(p, &p3reloc, p->idx); + if (r) { + return r; + } + p->idx += p3reloc.count + 2; + if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) { + DRM_ERROR("No packet3 for relocation for packet at %d.\n", + p3reloc.idx); + return -EINVAL; + } + idx = ib_chunk->kdata[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); + return -EINVAL; + } + /* FIXME: we assume reloc size is 4 dwords */ + *cs_reloc = p->relocs_ptr[(idx / 4)]; + return 0; +} + +/** + * r600_cs_packet_next_reloc_nomm() - parse next packet which should be reloc packet3 + * @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 next packet is relocation packet3, do bo validation and compute + * GPU offset using the provided start. + **/ +static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p, + struct radeon_cs_reloc **cs_reloc) +{ + struct radeon_cs_chunk *ib_chunk; + 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; + ib_chunk = &p->chunks[p->chunk_ib_idx]; + relocs_chunk = &p->chunks[p->chunk_relocs_idx]; + r = r600_cs_packet_parse(p, &p3reloc, p->idx); + if (r) { + return r; + } + p->idx += p3reloc.count + 2; + if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) { + DRM_ERROR("No packet3 for relocation for packet at %d.\n", + p3reloc.idx); + return -EINVAL; + } + idx = ib_chunk->kdata[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); + return -EINVAL; + } + *cs_reloc = &p->relocs[0]; + (*cs_reloc)->lobj.gpu_offset = (u64)relocs_chunk->kdata[idx + 3] << 32; + (*cs_reloc)->lobj.gpu_offset |= relocs_chunk->kdata[idx + 0]; + return 0; +} + +static int r600_packet0_check(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + unsigned idx, unsigned reg) +{ + switch (reg) { + case AVIVO_D1MODE_VLINE_START_END: + case AVIVO_D2MODE_VLINE_START_END: + 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; +} + +static int r600_packet3_check(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt) +{ + struct radeon_cs_chunk *ib_chunk; + struct radeon_cs_reloc *reloc; + volatile u32 *ib; + unsigned idx; + unsigned i; + unsigned start_reg, end_reg, reg; + int r; + + ib = p->ib->ptr; + ib_chunk = &p->chunks[p->chunk_ib_idx]; + idx = pkt->idx + 1; + switch (pkt->opcode) { + 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: + if (pkt->count != 3) { + DRM_ERROR("bad DRAW_INDEX\n"); + return -EINVAL; + } + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad DRAW_INDEX\n"); + return -EINVAL; + } + ib[idx+0] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+1] = upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + break; + case PACKET3_DRAW_INDEX_AUTO: + if (pkt->count != 1) { + DRM_ERROR("bad DRAW_INDEX_AUTO\n"); + return -EINVAL; + } + 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; + } + 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 (ib_chunk->kdata[idx+0] & 0x10) { + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad WAIT_REG_MEM\n"); + return -EINVAL; + } + ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+2] = upper_32_bits(reloc->lobj.gpu_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 (ib_chunk->kdata[idx+1] != 0xffffffff || + ib_chunk->kdata[idx+2] != 0) { + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SURFACE_SYNC\n"); + return -EINVAL; + } + ib[idx+2] += (u32)((reloc->lobj.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) { + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad EVENT_WRITE\n"); + return -EINVAL; + } + ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+2] |= upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + } + break; + case PACKET3_EVENT_WRITE_EOP: + if (pkt->count != 4) { + DRM_ERROR("bad EVENT_WRITE_EOP\n"); + return -EINVAL; + } + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad EVENT_WRITE\n"); + return -EINVAL; + } + ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+2] |= upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + break; + case PACKET3_SET_CONFIG_REG: + start_reg = (ib[idx+0] << 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); + switch (reg) { + case CP_COHER_BASE: + /* use PACKET3_SURFACE_SYNC */ + return -EINVAL; + default: + break; + } + } + break; + case PACKET3_SET_CONTEXT_REG: + start_reg = (ib[idx+0] << 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); + switch (reg) { + case DB_DEPTH_BASE: + 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: + 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: + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + break; + case VGT_DMA_BASE: + case VGT_DMA_BASE_HI: + /* These should be handled by DRAW_INDEX packet 3 */ + case VGT_STRMOUT_BASE_OFFSET_0: + case VGT_STRMOUT_BASE_OFFSET_1: + case VGT_STRMOUT_BASE_OFFSET_2: + case VGT_STRMOUT_BASE_OFFSET_3: + case VGT_STRMOUT_BASE_OFFSET_HI_0: + case VGT_STRMOUT_BASE_OFFSET_HI_1: + case VGT_STRMOUT_BASE_OFFSET_HI_2: + case VGT_STRMOUT_BASE_OFFSET_HI_3: + case VGT_STRMOUT_BUFFER_BASE_0: + case VGT_STRMOUT_BUFFER_BASE_1: + case VGT_STRMOUT_BUFFER_BASE_2: + case VGT_STRMOUT_BUFFER_BASE_3: + case VGT_STRMOUT_BUFFER_OFFSET_0: + case VGT_STRMOUT_BUFFER_OFFSET_1: + case VGT_STRMOUT_BUFFER_OFFSET_2: + case VGT_STRMOUT_BUFFER_OFFSET_3: + /* These should be handled by STRMOUT_BUFFER packet 3 */ + DRM_ERROR("bad context reg: 0x%08x\n", reg); + return -EINVAL; + default: + break; + } + } + break; + case PACKET3_SET_RESOURCE: + if (pkt->count % 7) { + DRM_ERROR("bad SET_RESOURCE\n"); + return -EINVAL; + } + start_reg = (ib[idx+0] << 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++) { + switch (G__SQ_VTX_CONSTANT_TYPE(ib[idx+(i*7)+6+1])) { + case SQ_TEX_VTX_VALID_TEXTURE: + /* tex base */ + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SET_RESOURCE\n"); + return -EINVAL; + } + ib[idx+1+(i*7)+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + /* tex mip base */ + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SET_RESOURCE\n"); + return -EINVAL; + } + ib[idx+1+(i*7)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + break; + case SQ_TEX_VTX_VALID_BUFFER: + /* vtx base */ + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SET_RESOURCE\n"); + return -EINVAL; + } + ib[idx+1+(i*7)+0] += (u32)((reloc->lobj.gpu_offset) & 0xffffffff); + ib[idx+1+(i*7)+2] |= upper_32_bits(reloc->lobj.gpu_offset) & 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: + start_reg = (ib[idx+0] << 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 = (ib[idx+0] << 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 = (ib[idx+0] << 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 = (ib[idx+0] << 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 = (ib[idx+0] << 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_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_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; + int r; + + do { + r = r600_cs_packet_parse(p, &pkt, p->idx); + if (r) { + return r; + } + p->idx += pkt.count + 2; + switch (pkt.type) { + case PACKET_TYPE0: + r = r600_cs_parse_packet0(p, &pkt); + break; + case PACKET_TYPE2: + break; + case PACKET_TYPE3: + r = r600_packet3_check(p, &pkt); + break; + default: + DRM_ERROR("Unknown packet type %d !\n", pkt.type); + return -EINVAL; + } + if (r) { + 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 + return 0; +} + +static int r600_cs_parser_relocs_legacy(struct radeon_cs_parser *p) +{ + if (p->chunk_relocs_idx == -1) { + return 0; + } + p->relocs = kcalloc(1, sizeof(struct radeon_cs_reloc), GFP_KERNEL); + if (p->relocs == NULL) { + return -ENOMEM; + } + return 0; +} + +/** + * 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++) { + kfree(parser->chunks[i].kdata); + } + kfree(parser->chunks); + kfree(parser->chunks_array); +} + +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 radeon_ib fake_ib; + int r; + + /* initialize parser */ + memset(&parser, 0, sizeof(struct radeon_cs_parser)); + parser.filp = filp; + parser.rdev = NULL; + parser.family = family; + parser.ib = &fake_ib; + fake_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; + memcpy((void *)parser.ib->ptr, ib_chunk->kdata, ib_chunk->length_dw*4); + *l = parser.ib->length_dw; + 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_cs_packet_next_reloc = &r600_cs_packet_next_reloc_nomm; +} diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h new file mode 100644 index 000000000000..723295f59281 --- /dev/null +++ b/drivers/gpu/drm/radeon/r600d.h @@ -0,0 +1,661 @@ +/* + * Copyright 2009 Advanced Micro Devices, Inc. + * Copyright 2009 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 + * Jerome Glisse + */ +#ifndef R600D_H +#define R600D_H + +#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 R6XX_MAX_SH_GPRS 256 +#define R6XX_MAX_TEMP_GPRS 16 +#define R6XX_MAX_SH_THREADS 256 +#define R6XX_MAX_SH_STACK_ENTRIES 4096 +#define R6XX_MAX_BACKENDS 8 +#define R6XX_MAX_BACKENDS_MASK 0xff +#define R6XX_MAX_SIMDS 8 +#define R6XX_MAX_SIMDS_MASK 0xff +#define R6XX_MAX_PIPES 8 +#define R6XX_MAX_PIPES_MASK 0xff + +/* PTE flags */ +#define PTE_VALID (1 << 0) +#define PTE_SYSTEM (1 << 1) +#define PTE_SNOOPED (1 << 2) +#define PTE_READABLE (1 << 5) +#define PTE_WRITEABLE (1 << 6) + +/* Registers */ +#define ARB_POP 0x2418 +#define ENABLE_TC128 (1 << 30) +#define ARB_GDEC_RD_CNTL 0x246C + +#define CC_GC_SHADER_PIPE_CONFIG 0x8950 +#define CC_RB_BACKEND_DISABLE 0x98F4 +#define BACKEND_DISABLE(x) ((x) << 16) + +#define CB_COLOR0_BASE 0x28040 +#define CB_COLOR1_BASE 0x28044 +#define CB_COLOR2_BASE 0x28048 +#define CB_COLOR3_BASE 0x2804C +#define CB_COLOR4_BASE 0x28050 +#define CB_COLOR5_BASE 0x28054 +#define CB_COLOR6_BASE 0x28058 +#define CB_COLOR7_BASE 0x2805C +#define CB_COLOR7_FRAG 0x280FC + +#define CB_COLOR0_SIZE 0x28060 +#define CB_COLOR0_VIEW 0x28080 +#define CB_COLOR0_INFO 0x280a0 +#define CB_COLOR0_TILE 0x280c0 +#define CB_COLOR0_FRAG 0x280e0 +#define CB_COLOR0_MASK 0x28100 + +#define CONFIG_MEMSIZE 0x5428 +#define CP_STAT 0x8680 +#define CP_COHER_BASE 0x85F8 +#define CP_DEBUG 0xC1FC +#define R_0086D8_CP_ME_CNTL 0x86D8 +#define S_0086D8_CP_ME_HALT(x) (((x) & 1)<<28) +#define C_0086D8_CP_ME_HALT(x) ((x) & 0xEFFFFFFF) +#define CP_ME_RAM_DATA 0xC160 +#define CP_ME_RAM_RADDR 0xC158 +#define CP_ME_RAM_WADDR 0xC15C +#define CP_MEQ_THRESHOLDS 0x8764 +#define MEQ_END(x) ((x) << 16) +#define ROQ_END(x) ((x) << 24) +#define CP_PERFMON_CNTL 0x87FC +#define CP_PFP_UCODE_ADDR 0xC150 +#define CP_PFP_UCODE_DATA 0xC154 +#define CP_QUEUE_THRESHOLDS 0x8760 +#define ROQ_IB1_START(x) ((x) << 0) +#define ROQ_IB2_START(x) ((x) << 8) +#define CP_RB_BASE 0xC100 +#define CP_RB_CNTL 0xC104 +#define RB_BUFSZ(x) ((x)<<0) +#define RB_BLKSZ(x) ((x)<<8) +#define RB_NO_UPDATE (1<<27) +#define RB_RPTR_WR_ENA (1<<31) +#define BUF_SWAP_32BIT (2 << 16) +#define CP_RB_RPTR 0x8700 +#define CP_RB_RPTR_ADDR 0xC10C +#define CP_RB_RPTR_ADDR_HI 0xC110 +#define CP_RB_RPTR_WR 0xC108 +#define CP_RB_WPTR 0xC114 +#define CP_RB_WPTR_ADDR 0xC118 +#define CP_RB_WPTR_ADDR_HI 0xC11C +#define CP_RB_WPTR_DELAY 0x8704 +#define CP_ROQ_IB1_STAT 0x8784 +#define CP_ROQ_IB2_STAT 0x8788 +#define CP_SEM_WAIT_TIMER 0x85BC + +#define DB_DEBUG 0x9830 +#define PREZ_MUST_WAIT_FOR_POSTZ_DONE (1 << 31) +#define DB_DEPTH_BASE 0x2800C +#define DB_WATERMARKS 0x9838 +#define DEPTH_FREE(x) ((x) << 0) +#define DEPTH_FLUSH(x) ((x) << 5) +#define DEPTH_PENDING_FREE(x) ((x) << 15) +#define DEPTH_CACHELINE_FREE(x) ((x) << 20) + +#define DCP_TILING_CONFIG 0x6CA0 +#define PIPE_TILING(x) ((x) << 1) +#define BANK_TILING(x) ((x) << 4) +#define GROUP_SIZE(x) ((x) << 6) +#define ROW_TILING(x) ((x) << 8) +#define BANK_SWAPS(x) ((x) << 11) +#define SAMPLE_SPLIT(x) ((x) << 14) +#define BACKEND_MAP(x) ((x) << 16) + +#define GB_TILING_CONFIG 0x98F0 + +#define GC_USER_SHADER_PIPE_CONFIG 0x8954 +#define INACTIVE_QD_PIPES(x) ((x) << 8) +#define INACTIVE_QD_PIPES_MASK 0x0000FF00 +#define INACTIVE_SIMDS(x) ((x) << 16) +#define INACTIVE_SIMDS_MASK 0x00FF0000 + +#define SQ_CONFIG 0x8c00 +# define VC_ENABLE (1 << 0) +# define EXPORT_SRC_C (1 << 1) +# define DX9_CONSTS (1 << 2) +# define ALU_INST_PREFER_VECTOR (1 << 3) +# define DX10_CLAMP (1 << 4) +# define CLAUSE_SEQ_PRIO(x) ((x) << 8) +# define PS_PRIO(x) ((x) << 24) +# define VS_PRIO(x) ((x) << 26) +# define GS_PRIO(x) ((x) << 28) +# define ES_PRIO(x) ((x) << 30) +#define SQ_GPR_RESOURCE_MGMT_1 0x8c04 +# define NUM_PS_GPRS(x) ((x) << 0) +# define NUM_VS_GPRS(x) ((x) << 16) +# define NUM_CLAUSE_TEMP_GPRS(x) ((x) << 28) +#define SQ_GPR_RESOURCE_MGMT_2 0x8c08 +# define NUM_GS_GPRS(x) ((x) << 0) +# define NUM_ES_GPRS(x) ((x) << 16) +#define SQ_THREAD_RESOURCE_MGMT 0x8c0c +# define NUM_PS_THREADS(x) ((x) << 0) +# define NUM_VS_THREADS(x) ((x) << 8) +# define NUM_GS_THREADS(x) ((x) << 16) +# define NUM_ES_THREADS(x) ((x) << 24) +#define SQ_STACK_RESOURCE_MGMT_1 0x8c10 +# define NUM_PS_STACK_ENTRIES(x) ((x) << 0) +# define NUM_VS_STACK_ENTRIES(x) ((x) << 16) +#define SQ_STACK_RESOURCE_MGMT_2 0x8c14 +# define NUM_GS_STACK_ENTRIES(x) ((x) << 0) +# define NUM_ES_STACK_ENTRIES(x) ((x) << 16) + +#define GRBM_CNTL 0x8000 +# define GRBM_READ_TIMEOUT(x) ((x) << 0) +#define GRBM_STATUS 0x8010 +#define CMDFIFO_AVAIL_MASK 0x0000001F +#define GUI_ACTIVE (1<<31) +#define GRBM_STATUS2 0x8014 +#define GRBM_SOFT_RESET 0x8020 +#define SOFT_RESET_CP (1<<0) + +#define HDP_HOST_PATH_CNTL 0x2C00 +#define HDP_NONSURFACE_BASE 0x2C04 +#define HDP_NONSURFACE_INFO 0x2C08 +#define HDP_NONSURFACE_SIZE 0x2C0C +#define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0 +#define HDP_TILING_CONFIG 0x2F3C + +#define MC_VM_AGP_TOP 0x2184 +#define MC_VM_AGP_BOT 0x2188 +#define MC_VM_AGP_BASE 0x218C +#define MC_VM_FB_LOCATION 0x2180 +#define MC_VM_L1_TLB_MCD_RD_A_CNTL 0x219C +#define ENABLE_L1_TLB (1 << 0) +#define ENABLE_L1_FRAGMENT_PROCESSING (1 << 1) +#define ENABLE_L1_STRICT_ORDERING (1 << 2) +#define SYSTEM_ACCESS_MODE_MASK 0x000000C0 +#define SYSTEM_ACCESS_MODE_SHIFT 6 +#define SYSTEM_ACCESS_MODE_PA_ONLY (0 << 6) +#define SYSTEM_ACCESS_MODE_USE_SYS_MAP (1 << 6) +#define SYSTEM_ACCESS_MODE_IN_SYS (2 << 6) +#define SYSTEM_ACCESS_MODE_NOT_IN_SYS (3 << 6) +#define SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU (0 << 8) +#define SYSTEM_APERTURE_UNMAPPED_ACCESS_DEFAULT_PAGE (1 << 8) +#define ENABLE_SEMAPHORE_MODE (1 << 10) +#define ENABLE_WAIT_L2_QUERY (1 << 11) +#define EFFECTIVE_L1_TLB_SIZE(x) (((x) & 7) << 12) +#define EFFECTIVE_L1_TLB_SIZE_MASK 0x00007000 +#define EFFECTIVE_L1_TLB_SIZE_SHIFT 12 +#define EFFECTIVE_L1_QUEUE_SIZE(x) (((x) & 7) << 15) +#define EFFECTIVE_L1_QUEUE_SIZE_MASK 0x00038000 +#define EFFECTIVE_L1_QUEUE_SIZE_SHIFT 15 +#define MC_VM_L1_TLB_MCD_RD_B_CNTL 0x21A0 +#define MC_VM_L1_TLB_MCB_RD_GFX_CNTL 0x21FC +#define MC_VM_L1_TLB_MCB_RD_HDP_CNTL 0x2204 +#define MC_VM_L1_TLB_MCB_RD_PDMA_CNTL 0x2208 +#define MC_VM_L1_TLB_MCB_RD_SEM_CNTL 0x220C +#define MC_VM_L1_TLB_MCB_RD_SYS_CNTL 0x2200 +#define MC_VM_L1_TLB_MCD_WR_A_CNTL 0x21A4 +#define MC_VM_L1_TLB_MCD_WR_B_CNTL 0x21A8 +#define MC_VM_L1_TLB_MCB_WR_GFX_CNTL 0x2210 +#define MC_VM_L1_TLB_MCB_WR_HDP_CNTL 0x2218 +#define MC_VM_L1_TLB_MCB_WR_PDMA_CNTL 0x221C +#define MC_VM_L1_TLB_MCB_WR_SEM_CNTL 0x2220 +#define MC_VM_L1_TLB_MCB_WR_SYS_CNTL 0x2214 +#define MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2190 +#define LOGICAL_PAGE_NUMBER_MASK 0x000FFFFF +#define LOGICAL_PAGE_NUMBER_SHIFT 0 +#define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2194 +#define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x2198 + +#define PA_CL_ENHANCE 0x8A14 +#define CLIP_VTX_REORDER_ENA (1 << 0) +#define NUM_CLIP_SEQ(x) ((x) << 1) +#define PA_SC_AA_CONFIG 0x28C04 +#define PA_SC_AA_SAMPLE_LOCS_2S 0x8B40 +#define PA_SC_AA_SAMPLE_LOCS_4S 0x8B44 +#define PA_SC_AA_SAMPLE_LOCS_8S_WD0 0x8B48 +#define PA_SC_AA_SAMPLE_LOCS_8S_WD1 0x8B4C +#define S0_X(x) ((x) << 0) +#define S0_Y(x) ((x) << 4) +#define S1_X(x) ((x) << 8) +#define S1_Y(x) ((x) << 12) +#define S2_X(x) ((x) << 16) +#define S2_Y(x) ((x) << 20) +#define S3_X(x) ((x) << 24) +#define S3_Y(x) ((x) << 28) +#define S4_X(x) ((x) << 0) +#define S4_Y(x) ((x) << 4) +#define S5_X(x) ((x) << 8) +#define S5_Y(x) ((x) << 12) +#define S6_X(x) ((x) << 16) +#define S6_Y(x) ((x) << 20) +#define S7_X(x) ((x) << 24) +#define S7_Y(x) ((x) << 28) +#define PA_SC_CLIPRECT_RULE 0x2820c +#define PA_SC_ENHANCE 0x8BF0 +#define FORCE_EOV_MAX_CLK_CNT(x) ((x) << 0) +#define FORCE_EOV_MAX_TILE_CNT(x) ((x) << 12) +#define PA_SC_LINE_STIPPLE 0x28A0C +#define PA_SC_LINE_STIPPLE_STATE 0x8B10 +#define PA_SC_MODE_CNTL 0x28A4C +#define PA_SC_MULTI_CHIP_CNTL 0x8B20 + +#define PA_SC_SCREEN_SCISSOR_TL 0x28030 +#define PA_SC_GENERIC_SCISSOR_TL 0x28240 +#define PA_SC_WINDOW_SCISSOR_TL 0x28204 + +#define PCIE_PORT_INDEX 0x0038 +#define PCIE_PORT_DATA 0x003C + +#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 SCRATCH_REG0 0x8500 +#define SCRATCH_REG1 0x8504 +#define SCRATCH_REG2 0x8508 +#define SCRATCH_REG3 0x850C +#define SCRATCH_REG4 0x8510 +#define SCRATCH_REG5 0x8514 +#define SCRATCH_REG6 0x8518 +#define SCRATCH_REG7 0x851C +#define SCRATCH_UMSK 0x8540 +#define SCRATCH_ADDR 0x8544 + +#define SPI_CONFIG_CNTL 0x9100 +#define GPR_WRITE_PRIORITY(x) ((x) << 0) +#define DISABLE_INTERP_1 (1 << 5) +#define SPI_CONFIG_CNTL_1 0x913C +#define VTX_DONE_DELAY(x) ((x) << 0) +#define INTERP_ONE_PRIM_PER_ROW (1 << 4) +#define SPI_INPUT_Z 0x286D8 +#define SPI_PS_IN_CONTROL_0 0x286CC +#define NUM_INTERP(x) ((x)<<0) +#define POSITION_ENA (1<<8) +#define POSITION_CENTROID (1<<9) +#define POSITION_ADDR(x) ((x)<<10) +#define PARAM_GEN(x) ((x)<<15) +#define PARAM_GEN_ADDR(x) ((x)<<19) +#define BARYC_SAMPLE_CNTL(x) ((x)<<26) +#define PERSP_GRADIENT_ENA (1<<28) +#define LINEAR_GRADIENT_ENA (1<<29) +#define POSITION_SAMPLE (1<<30) +#define BARYC_AT_SAMPLE_ENA (1<<31) +#define SPI_PS_IN_CONTROL_1 0x286D0 +#define GEN_INDEX_PIX (1<<0) +#define GEN_INDEX_PIX_ADDR(x) ((x)<<1) +#define FRONT_FACE_ENA (1<<8) +#define FRONT_FACE_CHAN(x) ((x)<<9) +#define FRONT_FACE_ALL_BITS (1<<11) +#define FRONT_FACE_ADDR(x) ((x)<<12) +#define FOG_ADDR(x) ((x)<<17) +#define FIXED_PT_POSITION_ENA (1<<24) +#define FIXED_PT_POSITION_ADDR(x) ((x)<<25) + +#define SQ_MS_FIFO_SIZES 0x8CF0 +#define CACHE_FIFO_SIZE(x) ((x) << 0) +#define FETCH_FIFO_HIWATER(x) ((x) << 8) +#define DONE_FIFO_HIWATER(x) ((x) << 16) +#define ALU_UPDATE_FIFO_HIWATER(x) ((x) << 24) +#define SQ_PGM_START_ES 0x28880 +#define SQ_PGM_START_FS 0x28894 +#define SQ_PGM_START_GS 0x2886C +#define SQ_PGM_START_PS 0x28840 +#define SQ_PGM_RESOURCES_PS 0x28850 +#define SQ_PGM_EXPORTS_PS 0x28854 +#define SQ_PGM_CF_OFFSET_PS 0x288cc +#define SQ_PGM_START_VS 0x28858 +#define SQ_PGM_RESOURCES_VS 0x28868 +#define SQ_PGM_CF_OFFSET_VS 0x288d0 +#define SQ_VTX_CONSTANT_WORD6_0 0x38018 +#define S__SQ_VTX_CONSTANT_TYPE(x) (((x) & 3) << 30) +#define G__SQ_VTX_CONSTANT_TYPE(x) (((x) >> 30) & 3) +#define SQ_TEX_VTX_INVALID_TEXTURE 0x0 +#define SQ_TEX_VTX_INVALID_BUFFER 0x1 +#define SQ_TEX_VTX_VALID_TEXTURE 0x2 +#define SQ_TEX_VTX_VALID_BUFFER 0x3 + + +#define SX_MISC 0x28350 +#define SX_DEBUG_1 0x9054 +#define SMX_EVENT_RELEASE (1 << 0) +#define ENABLE_NEW_SMX_ADDRESS (1 << 16) + +#define TA_CNTL_AUX 0x9508 +#define DISABLE_CUBE_WRAP (1 << 0) +#define DISABLE_CUBE_ANISO (1 << 1) +#define SYNC_GRADIENT (1 << 24) +#define SYNC_WALKER (1 << 25) +#define SYNC_ALIGNER (1 << 26) +#define BILINEAR_PRECISION_6_BIT (0 << 31) +#define BILINEAR_PRECISION_8_BIT (1 << 31) + +#define TC_CNTL 0x9608 +#define TC_L2_SIZE(x) ((x)<<5) +#define L2_DISABLE_LATE_HIT (1<<9) + + +#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 VGT_DMA_BASE 0x287E8 +#define VGT_DMA_BASE_HI 0x287E4 +#define VGT_ES_PER_GS 0x88CC +#define VGT_GS_PER_ES 0x88C8 +#define VGT_GS_PER_VS 0x88E8 +#define VGT_GS_VERTEX_REUSE 0x88D4 +#define VGT_PRIMITIVE_TYPE 0x8958 +#define VGT_NUM_INSTANCES 0x8974 +#define VGT_OUT_DEALLOC_CNTL 0x28C5C +#define DEALLOC_DIST_MASK 0x0000007F +#define VGT_STRMOUT_BASE_OFFSET_0 0x28B10 +#define VGT_STRMOUT_BASE_OFFSET_1 0x28B14 +#define VGT_STRMOUT_BASE_OFFSET_2 0x28B18 +#define VGT_STRMOUT_BASE_OFFSET_3 0x28B1c +#define VGT_STRMOUT_BASE_OFFSET_HI_0 0x28B44 +#define VGT_STRMOUT_BASE_OFFSET_HI_1 0x28B48 +#define VGT_STRMOUT_BASE_OFFSET_HI_2 0x28B4c +#define VGT_STRMOUT_BASE_OFFSET_HI_3 0x28B50 +#define VGT_STRMOUT_BUFFER_BASE_0 0x28AD8 +#define VGT_STRMOUT_BUFFER_BASE_1 0x28AE8 +#define VGT_STRMOUT_BUFFER_BASE_2 0x28AF8 +#define VGT_STRMOUT_BUFFER_BASE_3 0x28B08 +#define VGT_STRMOUT_BUFFER_OFFSET_0 0x28ADC +#define VGT_STRMOUT_BUFFER_OFFSET_1 0x28AEC +#define VGT_STRMOUT_BUFFER_OFFSET_2 0x28AFC +#define VGT_STRMOUT_BUFFER_OFFSET_3 0x28B0C +#define VGT_STRMOUT_EN 0x28AB0 +#define VGT_VERTEX_REUSE_BLOCK_CNTL 0x28C58 +#define VTX_REUSE_DEPTH_MASK 0x000000FF +#define VGT_EVENT_INITIATOR 0x28a90 +# define CACHE_FLUSH_AND_INV_EVENT (0x16 << 0) + +#define VM_CONTEXT0_CNTL 0x1410 +#define ENABLE_CONTEXT (1 << 0) +#define PAGE_TABLE_DEPTH(x) (((x) & 3) << 1) +#define RANGE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 4) +#define VM_CONTEXT0_INVALIDATION_LOW_ADDR 0x1490 +#define VM_CONTEXT0_INVALIDATION_HIGH_ADDR 0x14B0 +#define VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 0x1574 +#define VM_CONTEXT0_PAGE_TABLE_START_ADDR 0x1594 +#define VM_CONTEXT0_PAGE_TABLE_END_ADDR 0x15B4 +#define VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR 0x1554 +#define VM_CONTEXT0_REQUEST_RESPONSE 0x1470 +#define REQUEST_TYPE(x) (((x) & 0xf) << 0) +#define RESPONSE_TYPE_MASK 0x000000F0 +#define RESPONSE_TYPE_SHIFT 4 +#define VM_L2_CNTL 0x1400 +#define ENABLE_L2_CACHE (1 << 0) +#define ENABLE_L2_FRAGMENT_PROCESSING (1 << 1) +#define ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE (1 << 9) +#define EFFECTIVE_L2_QUEUE_SIZE(x) (((x) & 7) << 13) +#define VM_L2_CNTL2 0x1404 +#define INVALIDATE_ALL_L1_TLBS (1 << 0) +#define INVALIDATE_L2_CACHE (1 << 1) +#define VM_L2_CNTL3 0x1408 +#define BANK_SELECT_0(x) (((x) & 0x1f) << 0) +#define BANK_SELECT_1(x) (((x) & 0x1f) << 5) +#define L2_CACHE_UPDATE_MODE(x) (((x) & 3) << 10) +#define VM_L2_STATUS 0x140C +#define L2_BUSY (1 << 0) + +#define WAIT_UNTIL 0x8040 +#define WAIT_2D_IDLE_bit (1 << 14) +#define WAIT_3D_IDLE_bit (1 << 15) +#define WAIT_2D_IDLECLEAN_bit (1 << 16) +#define WAIT_3D_IDLECLEAN_bit (1 << 17) + + + +/* + * 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 PACKET3(op, n) ((PACKET_TYPE3 << 30) | \ + (((op) & 0xFF) << 8) | \ + ((n) & 0x3FFF) << 16) + +/* Packet 3 types */ +#define PACKET3_NOP 0x10 +#define PACKET3_INDIRECT_BUFFER_END 0x17 +#define PACKET3_SET_PREDICATION 0x20 +#define PACKET3_REG_RMW 0x21 +#define PACKET3_COND_EXEC 0x22 +#define PACKET3_PRED_EXEC 0x23 +#define PACKET3_START_3D_CMDBUF 0x24 +#define PACKET3_DRAW_INDEX_2 0x27 +#define PACKET3_CONTEXT_CONTROL 0x28 +#define PACKET3_DRAW_INDEX_IMMD_BE 0x29 +#define PACKET3_INDEX_TYPE 0x2A +#define PACKET3_DRAW_INDEX 0x2B +#define PACKET3_DRAW_INDEX_AUTO 0x2D +#define PACKET3_DRAW_INDEX_IMMD 0x2E +#define PACKET3_NUM_INSTANCES 0x2F +#define PACKET3_STRMOUT_BUFFER_UPDATE 0x34 +#define PACKET3_INDIRECT_BUFFER_MP 0x38 +#define PACKET3_MEM_SEMAPHORE 0x39 +#define PACKET3_MPEG_INDEX 0x3A +#define PACKET3_WAIT_REG_MEM 0x3C +#define PACKET3_MEM_WRITE 0x3D +#define PACKET3_INDIRECT_BUFFER 0x32 +#define PACKET3_CP_INTERRUPT 0x40 +#define PACKET3_SURFACE_SYNC 0x43 +# define PACKET3_CB0_DEST_BASE_ENA (1 << 6) +# define PACKET3_TC_ACTION_ENA (1 << 23) +# define PACKET3_VC_ACTION_ENA (1 << 24) +# define PACKET3_CB_ACTION_ENA (1 << 25) +# define PACKET3_DB_ACTION_ENA (1 << 26) +# define PACKET3_SH_ACTION_ENA (1 << 27) +# define PACKET3_SMX_ACTION_ENA (1 << 28) +#define PACKET3_ME_INITIALIZE 0x44 +#define PACKET3_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16) +#define PACKET3_COND_WRITE 0x45 +#define PACKET3_EVENT_WRITE 0x46 +#define PACKET3_EVENT_WRITE_EOP 0x47 +#define PACKET3_ONE_REG_WRITE 0x57 +#define PACKET3_SET_CONFIG_REG 0x68 +#define PACKET3_SET_CONFIG_REG_OFFSET 0x00008000 +#define PACKET3_SET_CONFIG_REG_END 0x0000ac00 +#define PACKET3_SET_CONTEXT_REG 0x69 +#define PACKET3_SET_CONTEXT_REG_OFFSET 0x00028000 +#define PACKET3_SET_CONTEXT_REG_END 0x00029000 +#define PACKET3_SET_ALU_CONST 0x6A +#define PACKET3_SET_ALU_CONST_OFFSET 0x00030000 +#define PACKET3_SET_ALU_CONST_END 0x00032000 +#define PACKET3_SET_BOOL_CONST 0x6B +#define PACKET3_SET_BOOL_CONST_OFFSET 0x0003e380 +#define PACKET3_SET_BOOL_CONST_END 0x00040000 +#define PACKET3_SET_LOOP_CONST 0x6C +#define PACKET3_SET_LOOP_CONST_OFFSET 0x0003e200 +#define PACKET3_SET_LOOP_CONST_END 0x0003e380 +#define PACKET3_SET_RESOURCE 0x6D +#define PACKET3_SET_RESOURCE_OFFSET 0x00038000 +#define PACKET3_SET_RESOURCE_END 0x0003c000 +#define PACKET3_SET_SAMPLER 0x6E +#define PACKET3_SET_SAMPLER_OFFSET 0x0003c000 +#define PACKET3_SET_SAMPLER_END 0x0003cff0 +#define PACKET3_SET_CTL_CONST 0x6F +#define PACKET3_SET_CTL_CONST_OFFSET 0x0003cff0 +#define PACKET3_SET_CTL_CONST_END 0x0003e200 +#define PACKET3_SURFACE_BASE_UPDATE 0x73 + + +#define R_008020_GRBM_SOFT_RESET 0x8020 +#define S_008020_SOFT_RESET_CP(x) (((x) & 1) << 0) +#define S_008020_SOFT_RESET_CB(x) (((x) & 1) << 1) +#define S_008020_SOFT_RESET_CR(x) (((x) & 1) << 2) +#define S_008020_SOFT_RESET_DB(x) (((x) & 1) << 3) +#define S_008020_SOFT_RESET_PA(x) (((x) & 1) << 5) +#define S_008020_SOFT_RESET_SC(x) (((x) & 1) << 6) +#define S_008020_SOFT_RESET_SMX(x) (((x) & 1) << 7) +#define S_008020_SOFT_RESET_SPI(x) (((x) & 1) << 8) +#define S_008020_SOFT_RESET_SH(x) (((x) & 1) << 9) +#define S_008020_SOFT_RESET_SX(x) (((x) & 1) << 10) +#define S_008020_SOFT_RESET_TC(x) (((x) & 1) << 11) +#define S_008020_SOFT_RESET_TA(x) (((x) & 1) << 12) +#define S_008020_SOFT_RESET_VC(x) (((x) & 1) << 13) +#define S_008020_SOFT_RESET_VGT(x) (((x) & 1) << 14) +#define R_008010_GRBM_STATUS 0x8010 +#define S_008010_CMDFIFO_AVAIL(x) (((x) & 0x1F) << 0) +#define S_008010_CP_RQ_PENDING(x) (((x) & 1) << 6) +#define S_008010_CF_RQ_PENDING(x) (((x) & 1) << 7) +#define S_008010_PF_RQ_PENDING(x) (((x) & 1) << 8) +#define S_008010_GRBM_EE_BUSY(x) (((x) & 1) << 10) +#define S_008010_VC_BUSY(x) (((x) & 1) << 11) +#define S_008010_DB03_CLEAN(x) (((x) & 1) << 12) +#define S_008010_CB03_CLEAN(x) (((x) & 1) << 13) +#define S_008010_VGT_BUSY_NO_DMA(x) (((x) & 1) << 16) +#define S_008010_VGT_BUSY(x) (((x) & 1) << 17) +#define S_008010_TA03_BUSY(x) (((x) & 1) << 18) +#define S_008010_TC_BUSY(x) (((x) & 1) << 19) +#define S_008010_SX_BUSY(x) (((x) & 1) << 20) +#define S_008010_SH_BUSY(x) (((x) & 1) << 21) +#define S_008010_SPI03_BUSY(x) (((x) & 1) << 22) +#define S_008010_SMX_BUSY(x) (((x) & 1) << 23) +#define S_008010_SC_BUSY(x) (((x) & 1) << 24) +#define S_008010_PA_BUSY(x) (((x) & 1) << 25) +#define S_008010_DB03_BUSY(x) (((x) & 1) << 26) +#define S_008010_CR_BUSY(x) (((x) & 1) << 27) +#define S_008010_CP_COHERENCY_BUSY(x) (((x) & 1) << 28) +#define S_008010_CP_BUSY(x) (((x) & 1) << 29) +#define S_008010_CB03_BUSY(x) (((x) & 1) << 30) +#define S_008010_GUI_ACTIVE(x) (((x) & 1) << 31) +#define G_008010_CMDFIFO_AVAIL(x) (((x) >> 0) & 0x1F) +#define G_008010_CP_RQ_PENDING(x) (((x) >> 6) & 1) +#define G_008010_CF_RQ_PENDING(x) (((x) >> 7) & 1) +#define G_008010_PF_RQ_PENDING(x) (((x) >> 8) & 1) +#define G_008010_GRBM_EE_BUSY(x) (((x) >> 10) & 1) +#define G_008010_VC_BUSY(x) (((x) >> 11) & 1) +#define G_008010_DB03_CLEAN(x) (((x) >> 12) & 1) +#define G_008010_CB03_CLEAN(x) (((x) >> 13) & 1) +#define G_008010_VGT_BUSY_NO_DMA(x) (((x) >> 16) & 1) +#define G_008010_VGT_BUSY(x) (((x) >> 17) & 1) +#define G_008010_TA03_BUSY(x) (((x) >> 18) & 1) +#define G_008010_TC_BUSY(x) (((x) >> 19) & 1) +#define G_008010_SX_BUSY(x) (((x) >> 20) & 1) +#define G_008010_SH_BUSY(x) (((x) >> 21) & 1) +#define G_008010_SPI03_BUSY(x) (((x) >> 22) & 1) +#define G_008010_SMX_BUSY(x) (((x) >> 23) & 1) +#define G_008010_SC_BUSY(x) (((x) >> 24) & 1) +#define G_008010_PA_BUSY(x) (((x) >> 25) & 1) +#define G_008010_DB03_BUSY(x) (((x) >> 26) & 1) +#define G_008010_CR_BUSY(x) (((x) >> 27) & 1) +#define G_008010_CP_COHERENCY_BUSY(x) (((x) >> 28) & 1) +#define G_008010_CP_BUSY(x) (((x) >> 29) & 1) +#define G_008010_CB03_BUSY(x) (((x) >> 30) & 1) +#define G_008010_GUI_ACTIVE(x) (((x) >> 31) & 1) +#define R_008014_GRBM_STATUS2 0x8014 +#define S_008014_CR_CLEAN(x) (((x) & 1) << 0) +#define S_008014_SMX_CLEAN(x) (((x) & 1) << 1) +#define S_008014_SPI0_BUSY(x) (((x) & 1) << 8) +#define S_008014_SPI1_BUSY(x) (((x) & 1) << 9) +#define S_008014_SPI2_BUSY(x) (((x) & 1) << 10) +#define S_008014_SPI3_BUSY(x) (((x) & 1) << 11) +#define S_008014_TA0_BUSY(x) (((x) & 1) << 12) +#define S_008014_TA1_BUSY(x) (((x) & 1) << 13) +#define S_008014_TA2_BUSY(x) (((x) & 1) << 14) +#define S_008014_TA3_BUSY(x) (((x) & 1) << 15) +#define S_008014_DB0_BUSY(x) (((x) & 1) << 16) +#define S_008014_DB1_BUSY(x) (((x) & 1) << 17) +#define S_008014_DB2_BUSY(x) (((x) & 1) << 18) +#define S_008014_DB3_BUSY(x) (((x) & 1) << 19) +#define S_008014_CB0_BUSY(x) (((x) & 1) << 20) +#define S_008014_CB1_BUSY(x) (((x) & 1) << 21) +#define S_008014_CB2_BUSY(x) (((x) & 1) << 22) +#define S_008014_CB3_BUSY(x) (((x) & 1) << 23) +#define G_008014_CR_CLEAN(x) (((x) >> 0) & 1) +#define G_008014_SMX_CLEAN(x) (((x) >> 1) & 1) +#define G_008014_SPI0_BUSY(x) (((x) >> 8) & 1) +#define G_008014_SPI1_BUSY(x) (((x) >> 9) & 1) +#define G_008014_SPI2_BUSY(x) (((x) >> 10) & 1) +#define G_008014_SPI3_BUSY(x) (((x) >> 11) & 1) +#define G_008014_TA0_BUSY(x) (((x) >> 12) & 1) +#define G_008014_TA1_BUSY(x) (((x) >> 13) & 1) +#define G_008014_TA2_BUSY(x) (((x) >> 14) & 1) +#define G_008014_TA3_BUSY(x) (((x) >> 15) & 1) +#define G_008014_DB0_BUSY(x) (((x) >> 16) & 1) +#define G_008014_DB1_BUSY(x) (((x) >> 17) & 1) +#define G_008014_DB2_BUSY(x) (((x) >> 18) & 1) +#define G_008014_DB3_BUSY(x) (((x) >> 19) & 1) +#define G_008014_CB0_BUSY(x) (((x) >> 20) & 1) +#define G_008014_CB1_BUSY(x) (((x) >> 21) & 1) +#define G_008014_CB2_BUSY(x) (((x) >> 22) & 1) +#define G_008014_CB3_BUSY(x) (((x) >> 23) & 1) +#define R_000E50_SRBM_STATUS 0x0E50 +#define G_000E50_RLC_RQ_PENDING(x) (((x) >> 3) & 1) +#define G_000E50_RCU_RQ_PENDING(x) (((x) >> 4) & 1) +#define G_000E50_GRBM_RQ_PENDING(x) (((x) >> 5) & 1) +#define G_000E50_HI_RQ_PENDING(x) (((x) >> 6) & 1) +#define G_000E50_IO_EXTERN_SIGNAL(x) (((x) >> 7) & 1) +#define G_000E50_VMC_BUSY(x) (((x) >> 8) & 1) +#define G_000E50_MCB_BUSY(x) (((x) >> 9) & 1) +#define G_000E50_MCDZ_BUSY(x) (((x) >> 10) & 1) +#define G_000E50_MCDY_BUSY(x) (((x) >> 11) & 1) +#define G_000E50_MCDX_BUSY(x) (((x) >> 12) & 1) +#define G_000E50_MCDW_BUSY(x) (((x) >> 13) & 1) +#define G_000E50_SEM_BUSY(x) (((x) >> 14) & 1) +#define G_000E50_RLC_BUSY(x) (((x) >> 15) & 1) +#define R_000E60_SRBM_SOFT_RESET 0x0E60 +#define S_000E60_SOFT_RESET_BIF(x) (((x) & 1) << 1) +#define S_000E60_SOFT_RESET_CG(x) (((x) & 1) << 2) +#define S_000E60_SOFT_RESET_CMC(x) (((x) & 1) << 3) +#define S_000E60_SOFT_RESET_CSC(x) (((x) & 1) << 4) +#define S_000E60_SOFT_RESET_DC(x) (((x) & 1) << 5) +#define S_000E60_SOFT_RESET_GRBM(x) (((x) & 1) << 8) +#define S_000E60_SOFT_RESET_HDP(x) (((x) & 1) << 9) +#define S_000E60_SOFT_RESET_IH(x) (((x) & 1) << 10) +#define S_000E60_SOFT_RESET_MC(x) (((x) & 1) << 11) +#define S_000E60_SOFT_RESET_RLC(x) (((x) & 1) << 13) +#define S_000E60_SOFT_RESET_ROM(x) (((x) & 1) << 14) +#define S_000E60_SOFT_RESET_SEM(x) (((x) & 1) << 15) +#define S_000E60_SOFT_RESET_TSC(x) (((x) & 1) << 16) +#define S_000E60_SOFT_RESET_VMC(x) (((x) & 1) << 17) + +#endif diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index e47f2fc294ce..3299733ac300 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -50,8 +50,8 @@ #include #include "radeon_mode.h" +#include "radeon_share.h" #include "radeon_reg.h" -#include "r300.h" /* * Modules parameters. @@ -112,10 +112,11 @@ enum radeon_family { CHIP_RV635, CHIP_RV670, CHIP_RS780, + CHIP_RS880, CHIP_RV770, CHIP_RV730, CHIP_RV710, - CHIP_RS880, + CHIP_RV740, CHIP_LAST, }; @@ -152,10 +153,21 @@ struct radeon_device; */ bool radeon_get_bios(struct radeon_device *rdev); + /* - * Clocks + * Dummy page */ +struct radeon_dummy_page { + struct page *page; + dma_addr_t addr; +}; +int radeon_dummy_page_init(struct radeon_device *rdev); +void radeon_dummy_page_fini(struct radeon_device *rdev); + +/* + * Clocks + */ struct radeon_clock { struct radeon_pll p1pll; struct radeon_pll p2pll; @@ -166,6 +178,7 @@ struct radeon_clock { uint32_t default_sclk; }; + /* * Fences. */ @@ -332,14 +345,18 @@ struct radeon_mc { resource_size_t aper_size; resource_size_t aper_base; resource_size_t agp_base; - unsigned gtt_location; - unsigned gtt_size; - unsigned vram_location; /* for some chips with <= 32MB we need to lie * about vram size near mc fb location */ - unsigned mc_vram_size; + u64 mc_vram_size; + u64 gtt_location; + u64 gtt_size; + u64 gtt_start; + u64 gtt_end; + u64 vram_location; + u64 vram_start; + u64 vram_end; unsigned vram_width; - unsigned real_vram_size; + u64 real_vram_size; int vram_mtrr; bool vram_is_ddr; }; @@ -411,6 +428,16 @@ struct radeon_cp { bool ready; }; +struct r600_blit { + struct radeon_object *shader_obj; + u64 shader_gpu_addr; + u32 vs_offset, ps_offset; + u32 state_offset; + u32 state_len; + u32 vb_used, vb_total; + struct radeon_ib *vb_ib; +}; + int radeon_ib_get(struct radeon_device *rdev, struct radeon_ib **ib); void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib); int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib); @@ -463,6 +490,7 @@ struct radeon_cs_parser { int chunk_relocs_idx; struct radeon_ib *ib; void *track; + unsigned family; }; struct radeon_cs_packet { @@ -559,6 +587,9 @@ int r100_debugfs_cp_init(struct radeon_device *rdev); */ struct radeon_asic { int (*init)(struct radeon_device *rdev); + void (*fini)(struct radeon_device *rdev); + int (*resume)(struct radeon_device *rdev); + int (*suspend)(struct radeon_device *rdev); void (*errata)(struct radeon_device *rdev); void (*vram_info)(struct radeon_device *rdev); int (*gpu_reset)(struct radeon_device *rdev); @@ -573,7 +604,11 @@ struct radeon_asic { int (*cp_init)(struct radeon_device *rdev, unsigned ring_size); void (*cp_fini)(struct radeon_device *rdev); void (*cp_disable)(struct radeon_device *rdev); + void (*cp_commit)(struct radeon_device *rdev); void (*ring_start)(struct radeon_device *rdev); + int (*ring_test)(struct radeon_device *rdev); + void (*ring_ib_execute)(struct radeon_device *rdev, struct radeon_ib *ib); + int (*ib_test)(struct radeon_device *rdev); int (*irq_set)(struct radeon_device *rdev); int (*irq_process)(struct radeon_device *rdev); u32 (*get_vblank_counter)(struct radeon_device *rdev, int crtc); @@ -613,6 +648,8 @@ struct r100_asic { union radeon_asic_config { struct r300_asic r300; struct r100_asic r100; + struct r600_asic r600; + struct rv770_asic rv770; }; @@ -698,12 +735,16 @@ struct radeon_device { struct radeon_pm pm; struct mutex cs_mutex; struct radeon_wb wb; + struct radeon_dummy_page dummy_page; bool gpu_lockup; bool shutdown; bool suspend; bool need_dma32; + bool new_init_path; struct radeon_surface_reg surface_regs[RADEON_GEM_MAX_SURFACES]; - const struct firmware *fw; /* firmware */ + const struct firmware *me_fw; /* all family ME firmware */ + const struct firmware *pfp_fw; /* r6/700 PFP firmware */ + struct r600_blit r600_blit; }; int radeon_device_init(struct radeon_device *rdev, @@ -713,6 +754,13 @@ int radeon_device_init(struct radeon_device *rdev, void radeon_device_fini(struct radeon_device *rdev); int radeon_gpu_wait_for_idle(struct radeon_device *rdev); +/* r600 blit */ +int r600_blit_prepare_copy(struct radeon_device *rdev, int size_bytes); +void r600_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence); +void r600_kms_blit_copy(struct radeon_device *rdev, + u64 src_gpu_addr, u64 dst_gpu_addr, + int size_bytes); + static inline uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg) { if (reg < 0x10000) @@ -740,6 +788,7 @@ static inline void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32 #define RREG8(reg) readb(((void __iomem *)rdev->rmmio) + (reg)) #define WREG8(reg, v) writeb(v, ((void __iomem *)rdev->rmmio) + (reg)) #define RREG32(reg) r100_mm_rreg(rdev, (reg)) +#define DREG32(reg) printk(KERN_INFO "REGISTER: " #reg " : 0x%08X\n", r100_mm_rreg(rdev, (reg))) #define WREG32(reg, v) r100_mm_wreg(rdev, (reg), (v)) #define REG_SET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK) #define REG_GET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK) @@ -763,6 +812,7 @@ static inline void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32 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))) /* * Indirect registers accessor @@ -827,51 +877,6 @@ void radeon_atombios_fini(struct radeon_device *rdev); /* * RING helpers. */ -#define CP_PACKET0 0x00000000 -#define PACKET0_BASE_INDEX_SHIFT 0 -#define PACKET0_BASE_INDEX_MASK (0x1ffff << 0) -#define PACKET0_COUNT_SHIFT 16 -#define PACKET0_COUNT_MASK (0x3fff << 16) -#define CP_PACKET1 0x40000000 -#define CP_PACKET2 0x80000000 -#define PACKET2_PAD_SHIFT 0 -#define PACKET2_PAD_MASK (0x3fffffff << 0) -#define CP_PACKET3 0xC0000000 -#define PACKET3_IT_OPCODE_SHIFT 8 -#define PACKET3_IT_OPCODE_MASK (0xff << 8) -#define PACKET3_COUNT_SHIFT 16 -#define PACKET3_COUNT_MASK (0x3fff << 16) -/* PACKET3 op code */ -#define PACKET3_NOP 0x10 -#define PACKET3_3D_DRAW_VBUF 0x28 -#define PACKET3_3D_DRAW_IMMD 0x29 -#define PACKET3_3D_DRAW_INDX 0x2A -#define PACKET3_3D_LOAD_VBPNTR 0x2F -#define PACKET3_INDX_BUFFER 0x33 -#define PACKET3_3D_DRAW_VBUF_2 0x34 -#define PACKET3_3D_DRAW_IMMD_2 0x35 -#define PACKET3_3D_DRAW_INDX_2 0x36 -#define PACKET3_BITBLT_MULTI 0x9B - -#define PACKET0(reg, n) (CP_PACKET0 | \ - REG_SET(PACKET0_BASE_INDEX, (reg) >> 2) | \ - REG_SET(PACKET0_COUNT, (n))) -#define PACKET2(v) (CP_PACKET2 | REG_SET(PACKET2_PAD, (v))) -#define PACKET3(op, n) (CP_PACKET3 | \ - REG_SET(PACKET3_IT_OPCODE, (op)) | \ - REG_SET(PACKET3_COUNT, (n))) - -#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) & 0x1FFF) << 2) -#define CP_PACKET0_GET_ONE_REG_WR(h) (((h) >> 15) & 1) -#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF) - static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) { #if DRM_DEBUG_CODE @@ -890,6 +895,9 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) * ASICs macro. */ #define radeon_init(rdev) (rdev)->asic->init((rdev)) +#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(p) rdev->asic->cs_parse((p)) #define radeon_errata(rdev) (rdev)->asic->errata((rdev)) #define radeon_vram_info(rdev) (rdev)->asic->vram_info((rdev)) @@ -905,7 +913,11 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_cp_init(rdev,rsize) (rdev)->asic->cp_init((rdev), (rsize)) #define radeon_cp_fini(rdev) (rdev)->asic->cp_fini((rdev)) #define radeon_cp_disable(rdev) (rdev)->asic->cp_disable((rdev)) +#define radeon_cp_commit(rdev) (rdev)->asic->cp_commit((rdev)) #define radeon_ring_start(rdev) (rdev)->asic->ring_start((rdev)) +#define radeon_ring_test(rdev) (rdev)->asic->ring_test((rdev)) +#define radeon_ring_ib_execute(rdev, ib) (rdev)->asic->ring_ib_execute((rdev), (ib)) +#define radeon_ib_test(rdev) (rdev)->asic->ib_test((rdev)) #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->get_vblank_counter((rdev), (crtc)) diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index c9cbd8ae1f95..e87bb915a6de 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -60,6 +60,7 @@ int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); int r100_cp_init(struct radeon_device *rdev, unsigned ring_size); void r100_cp_fini(struct radeon_device *rdev); void r100_cp_disable(struct radeon_device *rdev); +void r100_cp_commit(struct radeon_device *rdev); void r100_ring_start(struct radeon_device *rdev); int r100_irq_set(struct radeon_device *rdev); int r100_irq_process(struct radeon_device *rdev); @@ -78,6 +79,9 @@ int r100_set_surface_reg(struct radeon_device *rdev, int reg, uint32_t offset, uint32_t obj_size); int r100_clear_surface_reg(struct radeon_device *rdev, int reg); void r100_bandwidth_update(struct radeon_device *rdev); +void r100_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); +int r100_ib_test(struct radeon_device *rdev); +int r100_ring_test(struct radeon_device *rdev); static struct radeon_asic r100_asic = { .init = &r100_init, @@ -95,7 +99,11 @@ static struct radeon_asic r100_asic = { .cp_init = &r100_cp_init, .cp_fini = &r100_cp_fini, .cp_disable = &r100_cp_disable, + .cp_commit = &r100_cp_commit, .ring_start = &r100_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .ib_test = &r100_ib_test, .irq_set = &r100_irq_set, .irq_process = &r100_irq_process, .get_vblank_counter = &r100_get_vblank_counter, @@ -156,7 +164,11 @@ static struct radeon_asic r300_asic = { .cp_init = &r100_cp_init, .cp_fini = &r100_cp_fini, .cp_disable = &r100_cp_disable, + .cp_commit = &r100_cp_commit, .ring_start = &r300_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .ib_test = &r100_ib_test, .irq_set = &r100_irq_set, .irq_process = &r100_irq_process, .get_vblank_counter = &r100_get_vblank_counter, @@ -197,7 +209,11 @@ static struct radeon_asic r420_asic = { .cp_init = &r100_cp_init, .cp_fini = &r100_cp_fini, .cp_disable = &r100_cp_disable, + .cp_commit = &r100_cp_commit, .ring_start = &r300_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .ib_test = &r100_ib_test, .irq_set = &r100_irq_set, .irq_process = &r100_irq_process, .get_vblank_counter = &r100_get_vblank_counter, @@ -245,7 +261,11 @@ static struct radeon_asic rs400_asic = { .cp_init = &r100_cp_init, .cp_fini = &r100_cp_fini, .cp_disable = &r100_cp_disable, + .cp_commit = &r100_cp_commit, .ring_start = &r300_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .ib_test = &r100_ib_test, .irq_set = &r100_irq_set, .irq_process = &r100_irq_process, .get_vblank_counter = &r100_get_vblank_counter, @@ -298,7 +318,11 @@ static struct radeon_asic rs600_asic = { .cp_init = &r100_cp_init, .cp_fini = &r100_cp_fini, .cp_disable = &r100_cp_disable, + .cp_commit = &r100_cp_commit, .ring_start = &r300_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .ib_test = &r100_ib_test, .irq_set = &rs600_irq_set, .irq_process = &rs600_irq_process, .get_vblank_counter = &rs600_get_vblank_counter, @@ -341,7 +365,11 @@ static struct radeon_asic rs690_asic = { .cp_init = &r100_cp_init, .cp_fini = &r100_cp_fini, .cp_disable = &r100_cp_disable, + .cp_commit = &r100_cp_commit, .ring_start = &r300_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .ib_test = &r100_ib_test, .irq_set = &rs600_irq_set, .irq_process = &rs600_irq_process, .get_vblank_counter = &rs600_get_vblank_counter, @@ -391,7 +419,11 @@ static struct radeon_asic rv515_asic = { .cp_init = &r100_cp_init, .cp_fini = &r100_cp_fini, .cp_disable = &r100_cp_disable, + .cp_commit = &r100_cp_commit, .ring_start = &rv515_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .ib_test = &r100_ib_test, .irq_set = &rs600_irq_set, .irq_process = &rs600_irq_process, .get_vblank_counter = &rs600_get_vblank_counter, @@ -434,7 +466,11 @@ static struct radeon_asic r520_asic = { .cp_init = &r100_cp_init, .cp_fini = &r100_cp_fini, .cp_disable = &r100_cp_disable, + .cp_commit = &r100_cp_commit, .ring_start = &rv515_ring_start, + .ring_test = &r100_ring_test, + .ring_ib_execute = &r100_ring_ib_execute, + .ib_test = &r100_ib_test, .irq_set = &rs600_irq_set, .irq_process = &rs600_irq_process, .get_vblank_counter = &rs600_get_vblank_counter, @@ -453,9 +489,127 @@ static struct radeon_asic r520_asic = { }; /* - * r600,rv610,rv630,rv620,rv635,rv670,rs780,rv770,rv730,rv710 + * r600,rv610,rv630,rv620,rv635,rv670,rs780,rs880 */ +int r600_init(struct radeon_device *rdev); +void r600_fini(struct radeon_device *rdev); +int r600_suspend(struct radeon_device *rdev); +int r600_resume(struct radeon_device *rdev); +int r600_wb_init(struct radeon_device *rdev); +void r600_wb_fini(struct radeon_device *rdev); +void r600_cp_commit(struct radeon_device *rdev); +void r600_pcie_gart_tlb_flush(struct radeon_device *rdev); uint32_t r600_pciep_rreg(struct radeon_device *rdev, uint32_t reg); void r600_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); +int r600_cs_parse(struct radeon_cs_parser *p); +void r600_fence_ring_emit(struct radeon_device *rdev, + struct radeon_fence *fence); +int r600_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_pages, + struct radeon_fence *fence); +int r600_irq_process(struct radeon_device *rdev); +int r600_irq_set(struct radeon_device *rdev); +int r600_gpu_reset(struct radeon_device *rdev); +int r600_set_surface_reg(struct radeon_device *rdev, int reg, + uint32_t tiling_flags, uint32_t pitch, + uint32_t offset, uint32_t obj_size); +int r600_clear_surface_reg(struct radeon_device *rdev, int reg); +void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); +int r600_ib_test(struct radeon_device *rdev); +int r600_ring_test(struct radeon_device *rdev); +int r600_copy_blit(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_pages, struct radeon_fence *fence); + +static struct radeon_asic r600_asic = { + .errata = NULL, + .init = &r600_init, + .fini = &r600_fini, + .suspend = &r600_suspend, + .resume = &r600_resume, + .cp_commit = &r600_cp_commit, + .vram_info = NULL, + .gpu_reset = &r600_gpu_reset, + .mc_init = NULL, + .mc_fini = NULL, + .wb_init = &r600_wb_init, + .wb_fini = &r600_wb_fini, + .gart_enable = NULL, + .gart_disable = NULL, + .gart_tlb_flush = &r600_pcie_gart_tlb_flush, + .gart_set_page = &rs600_gart_set_page, + .cp_init = NULL, + .cp_fini = NULL, + .cp_disable = NULL, + .ring_start = NULL, + .ring_test = &r600_ring_test, + .ring_ib_execute = &r600_ring_ib_execute, + .ib_test = &r600_ib_test, + .irq_set = &r600_irq_set, + .irq_process = &r600_irq_process, + .fence_ring_emit = &r600_fence_ring_emit, + .cs_parse = &r600_cs_parse, + .copy_blit = &r600_copy_blit, + .copy_dma = &r600_copy_blit, + .copy = NULL, + .set_engine_clock = &radeon_atom_set_engine_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .set_pcie_lanes = NULL, + .set_clock_gating = &radeon_atom_set_clock_gating, + .set_surface_reg = r600_set_surface_reg, + .clear_surface_reg = r600_clear_surface_reg, + .bandwidth_update = &r520_bandwidth_update, +}; + +/* + * rv770,rv730,rv710,rv740 + */ +int rv770_init(struct radeon_device *rdev); +void rv770_fini(struct radeon_device *rdev); +int rv770_suspend(struct radeon_device *rdev); +int rv770_resume(struct radeon_device *rdev); +int rv770_gpu_reset(struct radeon_device *rdev); + +static struct radeon_asic rv770_asic = { + .errata = NULL, + .init = &rv770_init, + .fini = &rv770_fini, + .suspend = &rv770_suspend, + .resume = &rv770_resume, + .cp_commit = &r600_cp_commit, + .vram_info = NULL, + .gpu_reset = &rv770_gpu_reset, + .mc_init = NULL, + .mc_fini = NULL, + .wb_init = &r600_wb_init, + .wb_fini = &r600_wb_fini, + .gart_enable = NULL, + .gart_disable = NULL, + .gart_tlb_flush = &r600_pcie_gart_tlb_flush, + .gart_set_page = &rs600_gart_set_page, + .cp_init = NULL, + .cp_fini = NULL, + .cp_disable = NULL, + .ring_start = NULL, + .ring_test = &r600_ring_test, + .ring_ib_execute = &r600_ring_ib_execute, + .ib_test = &r600_ib_test, + .irq_set = &r600_irq_set, + .irq_process = &r600_irq_process, + .fence_ring_emit = &r600_fence_ring_emit, + .cs_parse = &r600_cs_parse, + .copy_blit = &r600_copy_blit, + .copy_dma = &r600_copy_blit, + .copy = NULL, + .set_engine_clock = &radeon_atom_set_engine_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .set_pcie_lanes = NULL, + .set_clock_gating = &radeon_atom_set_clock_gating, + .set_surface_reg = r600_set_surface_reg, + .clear_surface_reg = r600_clear_surface_reg, + .bandwidth_update = &r520_bandwidth_update, +}; #endif diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index bba9b4bd8f5c..a8fb392c9cd6 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -370,10 +370,6 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) && record-> ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) { - DRM_ERROR - ("record type %d\n", - record-> - ucRecordType); switch (record-> ucRecordType) { case ATOM_I2C_RECORD_TYPE: diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c index a37cbce53181..152eef13197a 100644 --- a/drivers/gpu/drm/radeon/radeon_clocks.c +++ b/drivers/gpu/drm/radeon/radeon_clocks.c @@ -102,10 +102,12 @@ void radeon_get_clock_info(struct drm_device *dev) p1pll->reference_div = 12; if (p2pll->reference_div < 2) p2pll->reference_div = 12; - if (spll->reference_div < 2) - spll->reference_div = - RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) & - RADEON_M_SPLL_REF_DIV_MASK; + if (rdev->family < CHIP_RS600) { + if (spll->reference_div < 2) + spll->reference_div = + RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) & + RADEON_M_SPLL_REF_DIV_MASK; + } if (mpll->reference_div < 2) mpll->reference_div = spll->reference_div; } else { diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 7693f7c67bd3..f2469c511789 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -37,7 +37,7 @@ /* * Clear GPU surface registers. */ -static void radeon_surface_init(struct radeon_device *rdev) +void radeon_surface_init(struct radeon_device *rdev) { /* FIXME: check this out */ if (rdev->family < CHIP_R600) { @@ -56,7 +56,7 @@ static void radeon_surface_init(struct radeon_device *rdev) /* * GPU scratch registers helpers function. */ -static void radeon_scratch_init(struct radeon_device *rdev) +void radeon_scratch_init(struct radeon_device *rdev) { int i; @@ -156,16 +156,14 @@ int radeon_mc_setup(struct radeon_device *rdev) tmp = (tmp + rdev->mc.gtt_size - 1) & ~(rdev->mc.gtt_size - 1); rdev->mc.gtt_location = tmp; } - DRM_INFO("radeon: VRAM %uM\n", rdev->mc.real_vram_size >> 20); + DRM_INFO("radeon: VRAM %uM\n", (unsigned)(rdev->mc.mc_vram_size >> 20)); DRM_INFO("radeon: VRAM from 0x%08X to 0x%08X\n", - rdev->mc.vram_location, - rdev->mc.vram_location + rdev->mc.mc_vram_size - 1); - if (rdev->mc.real_vram_size != rdev->mc.mc_vram_size) - DRM_INFO("radeon: VRAM less than aperture workaround enabled\n"); - DRM_INFO("radeon: GTT %uM\n", rdev->mc.gtt_size >> 20); + (unsigned)rdev->mc.vram_location, + (unsigned)(rdev->mc.vram_location + rdev->mc.mc_vram_size - 1)); + DRM_INFO("radeon: GTT %uM\n", (unsigned)(rdev->mc.gtt_size >> 20)); DRM_INFO("radeon: GTT from 0x%08X to 0x%08X\n", - rdev->mc.gtt_location, - rdev->mc.gtt_location + rdev->mc.gtt_size - 1); + (unsigned)rdev->mc.gtt_location, + (unsigned)(rdev->mc.gtt_location + rdev->mc.gtt_size - 1)); return 0; } @@ -205,6 +203,31 @@ static bool radeon_card_posted(struct radeon_device *rdev) } +int radeon_dummy_page_init(struct radeon_device *rdev) +{ + rdev->dummy_page.page = alloc_page(GFP_DMA32 | GFP_KERNEL | __GFP_ZERO); + if (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); + if (!rdev->dummy_page.addr) { + __free_page(rdev->dummy_page.page); + rdev->dummy_page.page = NULL; + return -ENOMEM; + } + return 0; +} + +void radeon_dummy_page_fini(struct radeon_device *rdev) +{ + if (rdev->dummy_page.page == NULL) + return; + pci_unmap_page(rdev->pdev, rdev->dummy_page.addr, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + __free_page(rdev->dummy_page.page); + rdev->dummy_page.page = NULL; +} + /* * Registers accessors functions. @@ -323,9 +346,15 @@ int radeon_asic_init(struct radeon_device *rdev) case CHIP_RV635: case CHIP_RV670: case CHIP_RS780: + case CHIP_RS880: + rdev->asic = &r600_asic; + break; case CHIP_RV770: case CHIP_RV730: case CHIP_RV710: + case CHIP_RV740: + rdev->asic = &rv770_asic; + break; default: /* FIXME: not supported yet */ return -EINVAL; @@ -448,7 +477,7 @@ int radeon_device_init(struct radeon_device *rdev, struct pci_dev *pdev, uint32_t flags) { - int r, ret; + int r, ret = 0; int dma_bits; DRM_INFO("radeon: Initializing kernel modesetting.\n"); @@ -487,10 +516,6 @@ int radeon_device_init(struct radeon_device *rdev, if (r) { return r; } - r = radeon_init(rdev); - if (r) { - return r; - } /* set DMA mask + need_dma32 flags. * PCIE - can handle 40-bits. @@ -521,111 +546,118 @@ int radeon_device_init(struct radeon_device *rdev, DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base); DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size); - /* Setup errata flags */ - radeon_errata(rdev); - /* Initialize scratch registers */ - radeon_scratch_init(rdev); - /* Initialize surface registers */ - radeon_surface_init(rdev); - - /* TODO: disable VGA need to use VGA request */ - /* BIOS*/ - if (!radeon_get_bios(rdev)) { - if (ASIC_IS_AVIVO(rdev)) - return -EINVAL; - } - if (rdev->is_atom_bios) { - r = radeon_atombios_init(rdev); + rdev->new_init_path = false; + r = radeon_init(rdev); + if (r) { + return r; + } + if (!rdev->new_init_path) { + /* Setup errata flags */ + radeon_errata(rdev); + /* Initialize scratch registers */ + radeon_scratch_init(rdev); + /* Initialize surface registers */ + radeon_surface_init(rdev); + + /* TODO: disable VGA need to use VGA request */ + /* BIOS*/ + if (!radeon_get_bios(rdev)) { + if (ASIC_IS_AVIVO(rdev)) + return -EINVAL; + } + if (rdev->is_atom_bios) { + r = radeon_atombios_init(rdev); + if (r) { + return r; + } + } else { + r = radeon_combios_init(rdev); + if (r) { + return r; + } + } + /* Reset gpu before posting otherwise ATOM will enter infinite loop */ + if (radeon_gpu_reset(rdev)) { + /* FIXME: what do we want to do here ? */ + } + /* check if cards are posted or not */ + if (!radeon_card_posted(rdev) && rdev->bios) { + DRM_INFO("GPU not posted. posting now...\n"); + if (rdev->is_atom_bios) { + atom_asic_init(rdev->mode_info.atom_context); + } else { + radeon_combios_asic_init(rdev->ddev); + } + } + /* Initialize clocks */ + r = radeon_clocks_init(rdev); if (r) { return r; } - } else { - r = radeon_combios_init(rdev); + /* Get vram informations */ + radeon_vram_info(rdev); + + /* Add an MTRR for the VRAM */ + rdev->mc.vram_mtrr = mtrr_add(rdev->mc.aper_base, rdev->mc.aper_size, + MTRR_TYPE_WRCOMB, 1); + DRM_INFO("Detected VRAM RAM=%uM, BAR=%uM\n", + (unsigned)(rdev->mc.mc_vram_size >> 20), + (unsigned)(rdev->mc.aper_size >> 20)); + DRM_INFO("RAM width %dbits %cDR\n", + rdev->mc.vram_width, rdev->mc.vram_is_ddr ? 'D' : 'S'); + /* Initialize memory controller (also test AGP) */ + r = radeon_mc_init(rdev); if (r) { return r; } - } - /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { - /* FIXME: what do we want to do here ? */ - } - /* check if cards are posted or not */ - if (!radeon_card_posted(rdev) && rdev->bios) { - DRM_INFO("GPU not posted. posting now...\n"); - if (rdev->is_atom_bios) { - atom_asic_init(rdev->mode_info.atom_context); - } else { - radeon_combios_asic_init(rdev->ddev); - } - } - /* Initialize clocks */ - r = radeon_clocks_init(rdev); - if (r) { - return r; - } - /* Get vram informations */ - radeon_vram_info(rdev); - - /* Add an MTRR for the VRAM */ - rdev->mc.vram_mtrr = mtrr_add(rdev->mc.aper_base, rdev->mc.aper_size, - MTRR_TYPE_WRCOMB, 1); - DRM_INFO("Detected VRAM RAM=%uM, BAR=%uM\n", - rdev->mc.real_vram_size >> 20, - (unsigned)rdev->mc.aper_size >> 20); - DRM_INFO("RAM width %dbits %cDR\n", - rdev->mc.vram_width, rdev->mc.vram_is_ddr ? 'D' : 'S'); - /* Initialize memory controller (also test AGP) */ - r = radeon_mc_init(rdev); - if (r) { - return r; - } - /* Fence driver */ - r = radeon_fence_driver_init(rdev); - if (r) { - return r; - } - r = radeon_irq_kms_init(rdev); - if (r) { - return r; - } - /* Memory manager */ - r = radeon_object_init(rdev); - if (r) { - return r; - } - /* Initialize GART (initialize after TTM so we can allocate - * memory through TTM but finalize after TTM) */ - r = radeon_gart_enable(rdev); - if (!r) { - r = radeon_gem_init(rdev); - } - - /* 1M ring buffer */ - if (!r) { - r = radeon_cp_init(rdev, 1024 * 1024); - } - if (!r) { - r = radeon_wb_init(rdev); + /* Fence driver */ + r = radeon_fence_driver_init(rdev); if (r) { - DRM_ERROR("radeon: failled initializing WB (%d).\n", r); return r; } - } - if (!r) { - r = radeon_ib_pool_init(rdev); + r = radeon_irq_kms_init(rdev); if (r) { - DRM_ERROR("radeon: failled initializing IB pool (%d).\n", r); return r; } - } - if (!r) { - r = radeon_ib_test(rdev); + /* Memory manager */ + r = radeon_object_init(rdev); if (r) { - DRM_ERROR("radeon: failled testing IB (%d).\n", r); return r; } + /* Initialize GART (initialize after TTM so we can allocate + * memory through TTM but finalize after TTM) */ + r = radeon_gart_enable(rdev); + if (!r) { + r = radeon_gem_init(rdev); + } + + /* 1M ring buffer */ + if (!r) { + r = radeon_cp_init(rdev, 1024 * 1024); + } + if (!r) { + r = radeon_wb_init(rdev); + if (r) { + DRM_ERROR("radeon: failled initializing WB (%d).\n", r); + return r; + } + } + if (!r) { + r = radeon_ib_pool_init(rdev); + if (r) { + DRM_ERROR("radeon: failled initializing IB pool (%d).\n", r); + return r; + } + } + if (!r) { + r = radeon_ib_test(rdev); + if (r) { + DRM_ERROR("radeon: failled testing IB (%d).\n", r); + return r; + } + } + ret = r; } - ret = r; r = radeon_modeset_init(rdev); if (r) { return r; @@ -651,26 +683,29 @@ void radeon_device_fini(struct radeon_device *rdev) rdev->shutdown = true; /* Order matter so becarefull if you rearrange anythings */ radeon_modeset_fini(rdev); - radeon_ib_pool_fini(rdev); - radeon_cp_fini(rdev); - radeon_wb_fini(rdev); - radeon_gem_fini(rdev); - radeon_object_fini(rdev); - /* mc_fini must be after object_fini */ - radeon_mc_fini(rdev); + if (!rdev->new_init_path) { + radeon_ib_pool_fini(rdev); + radeon_cp_fini(rdev); + radeon_wb_fini(rdev); + radeon_gem_fini(rdev); + radeon_mc_fini(rdev); #if __OS_HAS_AGP - radeon_agp_fini(rdev); + radeon_agp_fini(rdev); #endif - radeon_irq_kms_fini(rdev); - radeon_fence_driver_fini(rdev); - radeon_clocks_fini(rdev); - if (rdev->is_atom_bios) { - radeon_atombios_fini(rdev); + radeon_irq_kms_fini(rdev); + radeon_fence_driver_fini(rdev); + radeon_clocks_fini(rdev); + radeon_object_fini(rdev); + if (rdev->is_atom_bios) { + radeon_atombios_fini(rdev); + } else { + radeon_combios_fini(rdev); + } + kfree(rdev->bios); + rdev->bios = NULL; } else { - radeon_combios_fini(rdev); + radeon_fini(rdev); } - kfree(rdev->bios); - rdev->bios = NULL; iounmap(rdev->rmmio); rdev->rmmio = NULL; } @@ -708,9 +743,12 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) /* wait for gpu to finish processing current batch */ radeon_fence_wait_last(rdev); - radeon_cp_disable(rdev); - radeon_gart_disable(rdev); - + if (!rdev->new_init_path) { + radeon_cp_disable(rdev); + radeon_gart_disable(rdev); + } else { + radeon_suspend(rdev); + } /* evict remaining vram memory */ radeon_object_evict_vram(rdev); @@ -746,33 +784,37 @@ int radeon_resume_kms(struct drm_device *dev) if (radeon_gpu_reset(rdev)) { /* FIXME: what do we want to do here ? */ } - /* post card */ - if (rdev->is_atom_bios) { - atom_asic_init(rdev->mode_info.atom_context); + if (!rdev->new_init_path) { + /* post card */ + if (rdev->is_atom_bios) { + atom_asic_init(rdev->mode_info.atom_context); + } else { + radeon_combios_asic_init(rdev->ddev); + } + /* Initialize clocks */ + r = radeon_clocks_init(rdev); + if (r) { + release_console_sem(); + return r; + } + /* Enable IRQ */ + rdev->irq.sw_int = true; + radeon_irq_set(rdev); + /* Initialize GPU Memory Controller */ + r = radeon_mc_init(rdev); + if (r) { + goto out; + } + r = radeon_gart_enable(rdev); + if (r) { + goto out; + } + r = radeon_cp_init(rdev, rdev->cp.ring_size); + if (r) { + goto out; + } } else { - radeon_combios_asic_init(rdev->ddev); - } - /* Initialize clocks */ - r = radeon_clocks_init(rdev); - if (r) { - release_console_sem(); - return r; - } - /* Enable IRQ */ - rdev->irq.sw_int = true; - radeon_irq_set(rdev); - /* Initialize GPU Memory Controller */ - r = radeon_mc_init(rdev); - if (r) { - goto out; - } - r = radeon_gart_enable(rdev); - if (r) { - goto out; - } - r = radeon_cp_init(rdev, rdev->cp.ring_size); - if (r) { - goto out; + radeon_resume(rdev); } out: fb_set_suspend(rdev->fbdev_info, 0); diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index 40294a07976f..c7b185924f6c 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -356,6 +356,12 @@ typedef struct drm_radeon_private { int r700_sc_hiz_tile_fifo_size; int r700_sc_earlyz_tile_fifo_fize; + struct mutex cs_mutex; + u32 cs_id_scnt; + u32 cs_id_wcnt; + /* r6xx/r7xx drm blit vertex buffer */ + struct drm_buf *blit_vb; + /* firmware */ const struct firmware *me_fw, *pfp_fw; } drm_radeon_private_t; @@ -396,6 +402,9 @@ static __inline__ int radeon_check_offset(drm_radeon_private_t *dev_priv, (off >= gart_start && off <= gart_end)); } +/* radeon_state.c */ +extern void radeon_cp_discard_buffer(struct drm_device *dev, struct drm_master *master, struct drm_buf *buf); + /* radeon_cp.c */ extern int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -487,6 +496,22 @@ extern int r600_cp_dispatch_indirect(struct drm_device *dev, struct drm_buf *buf, int start, int end); extern int r600_page_table_init(struct drm_device *dev); extern void r600_page_table_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info); +extern int r600_cs_legacy_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv); +extern void r600_cp_dispatch_swap(struct drm_device *dev, struct drm_file *file_priv); +extern int r600_cp_dispatch_texture(struct drm_device *dev, + struct drm_file *file_priv, + drm_radeon_texture_t *tex, + drm_radeon_tex_image_t *image); +/* r600_blit.c */ +extern int r600_prepare_blit_copy(struct drm_device *dev, struct drm_file *file_priv); +extern void r600_done_blit_copy(struct drm_device *dev); +extern void r600_blit_copy(struct drm_device *dev, + uint64_t src_gpu_addr, uint64_t dst_gpu_addr, + int size_bytes); +extern void r600_blit_swap(struct drm_device *dev, + uint64_t src_gpu_addr, uint64_t dst_gpu_addr, + int sx, int sy, int dx, int dy, + int w, int h, int src_pitch, int dst_pitch, int cpp); /* Flags for stats.boxes */ @@ -1114,13 +1139,71 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index); # define RADEON_CNTL_BITBLT_MULTI 0x00009B00 # define RADEON_CNTL_SET_SCISSORS 0xC0001E00 -# define R600_IT_INDIRECT_BUFFER 0x00003200 -# define R600_IT_ME_INITIALIZE 0x00004400 +# define R600_IT_INDIRECT_BUFFER_END 0x00001700 +# define R600_IT_SET_PREDICATION 0x00002000 +# define R600_IT_REG_RMW 0x00002100 +# define R600_IT_COND_EXEC 0x00002200 +# define R600_IT_PRED_EXEC 0x00002300 +# define R600_IT_START_3D_CMDBUF 0x00002400 +# define R600_IT_DRAW_INDEX_2 0x00002700 +# define R600_IT_CONTEXT_CONTROL 0x00002800 +# define R600_IT_DRAW_INDEX_IMMD_BE 0x00002900 +# define R600_IT_INDEX_TYPE 0x00002A00 +# define R600_IT_DRAW_INDEX 0x00002B00 +# define R600_IT_DRAW_INDEX_AUTO 0x00002D00 +# define R600_IT_DRAW_INDEX_IMMD 0x00002E00 +# define R600_IT_NUM_INSTANCES 0x00002F00 +# define R600_IT_STRMOUT_BUFFER_UPDATE 0x00003400 +# define R600_IT_INDIRECT_BUFFER_MP 0x00003800 +# define R600_IT_MEM_SEMAPHORE 0x00003900 +# define R600_IT_MPEG_INDEX 0x00003A00 +# define R600_IT_WAIT_REG_MEM 0x00003C00 +# define R600_IT_MEM_WRITE 0x00003D00 +# define R600_IT_INDIRECT_BUFFER 0x00003200 +# define R600_IT_CP_INTERRUPT 0x00004000 +# define R600_IT_SURFACE_SYNC 0x00004300 +# define R600_CB0_DEST_BASE_ENA (1 << 6) +# define R600_TC_ACTION_ENA (1 << 23) +# define R600_VC_ACTION_ENA (1 << 24) +# define R600_CB_ACTION_ENA (1 << 25) +# define R600_DB_ACTION_ENA (1 << 26) +# define R600_SH_ACTION_ENA (1 << 27) +# define R600_SMX_ACTION_ENA (1 << 28) +# define R600_IT_ME_INITIALIZE 0x00004400 # define R600_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16) -# define R600_IT_EVENT_WRITE 0x00004600 -# define R600_IT_SET_CONFIG_REG 0x00006800 -# define R600_SET_CONFIG_REG_OFFSET 0x00008000 -# define R600_SET_CONFIG_REG_END 0x0000ac00 +# define R600_IT_COND_WRITE 0x00004500 +# define R600_IT_EVENT_WRITE 0x00004600 +# define R600_IT_EVENT_WRITE_EOP 0x00004700 +# define R600_IT_ONE_REG_WRITE 0x00005700 +# define R600_IT_SET_CONFIG_REG 0x00006800 +# define R600_SET_CONFIG_REG_OFFSET 0x00008000 +# define R600_SET_CONFIG_REG_END 0x0000ac00 +# define R600_IT_SET_CONTEXT_REG 0x00006900 +# define R600_SET_CONTEXT_REG_OFFSET 0x00028000 +# define R600_SET_CONTEXT_REG_END 0x00029000 +# define R600_IT_SET_ALU_CONST 0x00006A00 +# define R600_SET_ALU_CONST_OFFSET 0x00030000 +# define R600_SET_ALU_CONST_END 0x00032000 +# define R600_IT_SET_BOOL_CONST 0x00006B00 +# define R600_SET_BOOL_CONST_OFFSET 0x0003e380 +# define R600_SET_BOOL_CONST_END 0x00040000 +# define R600_IT_SET_LOOP_CONST 0x00006C00 +# define R600_SET_LOOP_CONST_OFFSET 0x0003e200 +# define R600_SET_LOOP_CONST_END 0x0003e380 +# define R600_IT_SET_RESOURCE 0x00006D00 +# define R600_SET_RESOURCE_OFFSET 0x00038000 +# define R600_SET_RESOURCE_END 0x0003c000 +# define R600_SQ_TEX_VTX_INVALID_TEXTURE 0x0 +# define R600_SQ_TEX_VTX_INVALID_BUFFER 0x1 +# define R600_SQ_TEX_VTX_VALID_TEXTURE 0x2 +# define R600_SQ_TEX_VTX_VALID_BUFFER 0x3 +# define R600_IT_SET_SAMPLER 0x00006E00 +# define R600_SET_SAMPLER_OFFSET 0x0003c000 +# define R600_SET_SAMPLER_END 0x0003cff0 +# define R600_IT_SET_CTL_CONST 0x00006F00 +# define R600_SET_CTL_CONST_OFFSET 0x0003cff0 +# define R600_SET_CTL_CONST_END 0x0003e200 +# define R600_IT_SURFACE_BASE_UPDATE 0x00007300 #define RADEON_CP_PACKET_MASK 0xC0000000 #define RADEON_CP_PACKET_COUNT_MASK 0x3fff0000 @@ -1598,6 +1681,52 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index); #define R600_CB_COLOR7_BASE 0x2805c #define R600_CB_COLOR7_FRAG 0x280fc +#define R600_CB_COLOR0_SIZE 0x28060 +#define R600_CB_COLOR0_VIEW 0x28080 +#define R600_CB_COLOR0_INFO 0x280a0 +#define R600_CB_COLOR0_TILE 0x280c0 +#define R600_CB_COLOR0_FRAG 0x280e0 +#define R600_CB_COLOR0_MASK 0x28100 + +#define AVIVO_D1MODE_VLINE_START_END 0x6538 +#define AVIVO_D2MODE_VLINE_START_END 0x6d38 +#define R600_CP_COHER_BASE 0x85f8 +#define R600_DB_DEPTH_BASE 0x2800c +#define R600_SQ_PGM_START_FS 0x28894 +#define R600_SQ_PGM_START_ES 0x28880 +#define R600_SQ_PGM_START_VS 0x28858 +#define R600_SQ_PGM_RESOURCES_VS 0x28868 +#define R600_SQ_PGM_CF_OFFSET_VS 0x288d0 +#define R600_SQ_PGM_START_GS 0x2886c +#define R600_SQ_PGM_START_PS 0x28840 +#define R600_SQ_PGM_RESOURCES_PS 0x28850 +#define R600_SQ_PGM_EXPORTS_PS 0x28854 +#define R600_SQ_PGM_CF_OFFSET_PS 0x288cc +#define R600_VGT_DMA_BASE 0x287e8 +#define R600_VGT_DMA_BASE_HI 0x287e4 +#define R600_VGT_STRMOUT_BASE_OFFSET_0 0x28b10 +#define R600_VGT_STRMOUT_BASE_OFFSET_1 0x28b14 +#define R600_VGT_STRMOUT_BASE_OFFSET_2 0x28b18 +#define R600_VGT_STRMOUT_BASE_OFFSET_3 0x28b1c +#define R600_VGT_STRMOUT_BASE_OFFSET_HI_0 0x28b44 +#define R600_VGT_STRMOUT_BASE_OFFSET_HI_1 0x28b48 +#define R600_VGT_STRMOUT_BASE_OFFSET_HI_2 0x28b4c +#define R600_VGT_STRMOUT_BASE_OFFSET_HI_3 0x28b50 +#define R600_VGT_STRMOUT_BUFFER_BASE_0 0x28ad8 +#define R600_VGT_STRMOUT_BUFFER_BASE_1 0x28ae8 +#define R600_VGT_STRMOUT_BUFFER_BASE_2 0x28af8 +#define R600_VGT_STRMOUT_BUFFER_BASE_3 0x28b08 +#define R600_VGT_STRMOUT_BUFFER_OFFSET_0 0x28adc +#define R600_VGT_STRMOUT_BUFFER_OFFSET_1 0x28aec +#define R600_VGT_STRMOUT_BUFFER_OFFSET_2 0x28afc +#define R600_VGT_STRMOUT_BUFFER_OFFSET_3 0x28b0c + +#define R600_VGT_PRIMITIVE_TYPE 0x8958 + +#define R600_PA_SC_SCREEN_SCISSOR_TL 0x28030 +#define R600_PA_SC_GENERIC_SCISSOR_TL 0x28240 +#define R600_PA_SC_WINDOW_SCISSOR_TL 0x28204 + #define R600_TC_CNTL 0x9608 # define R600_TC_L2_SIZE(x) ((x) << 5) # define R600_L2_DISABLE_LATE_HIT (1 << 9) diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index b4e48dd2e859..506dd4dd3a24 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -53,9 +53,9 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) * away */ WREG32(rdev->fence_drv.scratch_reg, fence->seq); - } else { + } else radeon_fence_ring_emit(rdev, fence); - } + fence->emited = true; fence->timeout = jiffies + ((2000 * HZ) / 1000); list_del(&fence->list); @@ -168,7 +168,47 @@ bool radeon_fence_signaled(struct radeon_fence *fence) return signaled; } -int radeon_fence_wait(struct radeon_fence *fence, bool interruptible) +int r600_fence_wait(struct radeon_fence *fence, bool intr, bool lazy) +{ + struct radeon_device *rdev; + unsigned long cur_jiffies; + unsigned long timeout; + int ret = 0; + + cur_jiffies = jiffies; + timeout = HZ / 100; + + if (time_after(fence->timeout, cur_jiffies)) { + timeout = fence->timeout - cur_jiffies; + } + + rdev = fence->rdev; + + __set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); + + while (1) { + if (radeon_fence_signaled(fence)) + break; + + if (time_after_eq(jiffies, timeout)) { + ret = -EBUSY; + break; + } + + if (lazy) + schedule_timeout(1); + + if (intr && signal_pending(current)) { + ret = -ERESTART; + break; + } + } + __set_current_state(TASK_RUNNING); + return ret; +} + + +int radeon_fence_wait(struct radeon_fence *fence, bool intr) { struct radeon_device *rdev; unsigned long cur_jiffies; @@ -176,7 +216,6 @@ int radeon_fence_wait(struct radeon_fence *fence, bool interruptible) bool expired = false; int r; - if (fence == NULL) { WARN(1, "Querying an invalid fence : %p !\n", fence); return 0; @@ -185,13 +224,18 @@ int radeon_fence_wait(struct radeon_fence *fence, bool interruptible) if (radeon_fence_signaled(fence)) { return 0; } + + if (rdev->family >= CHIP_R600) + return r600_fence_wait(fence, intr, 0); + retry: cur_jiffies = jiffies; timeout = HZ / 100; if (time_after(fence->timeout, cur_jiffies)) { timeout = fence->timeout - cur_jiffies; } - if (interruptible) { + + if (intr) { r = wait_event_interruptible_timeout(rdev->fence_drv.queue, radeon_fence_signaled(fence), timeout); if (unlikely(r == -ERESTARTSYS)) { diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index 28be2f1165cb..21da871a793c 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -3255,6 +3255,24 @@ #define RADEON_CP_RB_WPTR 0x0714 #define RADEON_CP_RB_RPTR_WR 0x071c +#define RADEON_SCRATCH_UMSK 0x0770 +#define RADEON_SCRATCH_ADDR 0x0774 + +#define R600_CP_RB_BASE 0xc100 +#define R600_CP_RB_CNTL 0xc104 +# define R600_RB_BUFSZ(x) ((x) << 0) +# define R600_RB_BLKSZ(x) ((x) << 8) +# define R600_RB_NO_UPDATE (1 << 27) +# define R600_RB_RPTR_WR_ENA (1 << 31) +#define R600_CP_RB_RPTR_WR 0xc108 +#define R600_CP_RB_RPTR_ADDR 0xc10c +#define R600_CP_RB_RPTR_ADDR_HI 0xc110 +#define R600_CP_RB_WPTR 0xc114 +#define R600_CP_RB_WPTR_ADDR 0xc118 +#define R600_CP_RB_WPTR_ADDR_HI 0xc11c +#define R600_CP_RB_RPTR 0x8700 +#define R600_CP_RB_WPTR_DELAY 0x8704 + #define RADEON_CP_IB_BASE 0x0738 #define RADEON_CP_IB_BUFSZ 0x073c diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 60d159308b88..aa9837a6aa75 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -110,7 +110,6 @@ void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib) return; } list_del(&tmp->list); - INIT_LIST_HEAD(&tmp->list); if (tmp->fence) { radeon_fence_unref(&tmp->fence); } @@ -119,19 +118,11 @@ void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib) mutex_unlock(&rdev->ib_pool.mutex); } -static void radeon_ib_align(struct radeon_device *rdev, struct radeon_ib *ib) -{ - while ((ib->length_dw & rdev->cp.align_mask)) { - ib->ptr[ib->length_dw++] = PACKET2(0); - } -} - int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib) { int r = 0; mutex_lock(&rdev->ib_pool.mutex); - radeon_ib_align(rdev, ib); if (!ib->length_dw || !rdev->cp.ready) { /* TODO: Nothings in the ib we should report. */ mutex_unlock(&rdev->ib_pool.mutex); @@ -145,9 +136,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib) mutex_unlock(&rdev->ib_pool.mutex); return r; } - radeon_ring_write(rdev, PACKET0(RADEON_CP_IB_BASE, 1)); - radeon_ring_write(rdev, ib->gpu_addr); - radeon_ring_write(rdev, ib->length_dw); + radeon_ring_ib_execute(rdev, ib); radeon_fence_emit(rdev, ib->fence); radeon_ring_unlock_commit(rdev); list_add_tail(&ib->list, &rdev->ib_pool.scheduled_ibs); @@ -215,69 +204,16 @@ void radeon_ib_pool_fini(struct radeon_device *rdev) mutex_unlock(&rdev->ib_pool.mutex); } -int radeon_ib_test(struct radeon_device *rdev) -{ - 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, &ib); - if (r) { - return r; - } - ib->ptr[0] = PACKET0(scratch, 0); - ib->ptr[1] = 0xDEADBEEF; - ib->ptr[2] = PACKET2(0); - ib->ptr[3] = PACKET2(0); - ib->ptr[4] = PACKET2(0); - ib->ptr[5] = PACKET2(0); - ib->ptr[6] = PACKET2(0); - ib->ptr[7] = PACKET2(0); - ib->length_dw = 8; - r = radeon_ib_schedule(rdev, ib); - if (r) { - radeon_scratch_free(rdev, scratch); - radeon_ib_free(rdev, &ib); - return r; - } - r = radeon_fence_wait(ib->fence, false); - if (r) { - 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 succeeded in %u usecs\n", i); - } else { - DRM_ERROR("radeon: ib test failed (sracth(0x%04X)=0x%08X)\n", - scratch, tmp); - r = -EINVAL; - } - radeon_scratch_free(rdev, scratch); - radeon_ib_free(rdev, &ib); - return r; -} - /* * Ring. */ void radeon_ring_free_size(struct radeon_device *rdev) { - rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR); + if (rdev->family >= CHIP_R600) + rdev->cp.rptr = RREG32(R600_CP_RB_RPTR); + else + rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR); /* This works because ring_size is a power of 2 */ rdev->cp.ring_free_dw = (rdev->cp.rptr + (rdev->cp.ring_size / 4)); rdev->cp.ring_free_dw -= rdev->cp.wptr; @@ -320,11 +256,10 @@ void radeon_ring_unlock_commit(struct radeon_device *rdev) count_dw_pad = (rdev->cp.align_mask + 1) - (rdev->cp.wptr & rdev->cp.align_mask); for (i = 0; i < count_dw_pad; i++) { - radeon_ring_write(rdev, PACKET2(0)); + radeon_ring_write(rdev, 2 << 30); } DRM_MEMORYBARRIER(); - WREG32(RADEON_CP_RB_WPTR, rdev->cp.wptr); - (void)RREG32(RADEON_CP_RB_WPTR); + radeon_cp_commit(rdev); mutex_unlock(&rdev->cp.mutex); } @@ -334,46 +269,6 @@ void radeon_ring_unlock_undo(struct radeon_device *rdev) mutex_unlock(&rdev->cp.mutex); } -int radeon_ring_test(struct radeon_device *rdev) -{ - 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, 2); - if (r) { - DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r); - radeon_scratch_free(rdev, scratch); - return r; - } - radeon_ring_write(rdev, PACKET0(scratch, 0)); - radeon_ring_write(rdev, 0xDEADBEEF); - radeon_ring_unlock_commit(rdev); - 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 succeeded in %d usecs\n", i); - } else { - DRM_ERROR("radeon: ring test failed (sracth(0x%04X)=0x%08X)\n", - scratch, tmp); - r = -EINVAL; - } - radeon_scratch_free(rdev, scratch); - return r; -} - int radeon_ring_init(struct radeon_device *rdev, unsigned ring_size) { int r; diff --git a/drivers/gpu/drm/radeon/radeon_share.h b/drivers/gpu/drm/radeon/radeon_share.h index 63a773578f17..5f9e358ab506 100644 --- a/drivers/gpu/drm/radeon/radeon_share.h +++ b/drivers/gpu/drm/radeon/radeon_share.h @@ -28,12 +28,89 @@ #ifndef __RADEON_SHARE_H__ #define __RADEON_SHARE_H__ +/* Common */ +struct radeon_device; +struct radeon_cs_parser; +int radeon_clocks_init(struct radeon_device *rdev); +void radeon_clocks_fini(struct radeon_device *rdev); +void radeon_scratch_init(struct radeon_device *rdev); +void radeon_surface_init(struct radeon_device *rdev); +int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data); + + +/* R100, RV100, RS100, RV200, RS200, R200, RV250, RS300, RV280 */ void r100_vram_init_sizes(struct radeon_device *rdev); + +/* R300, R350, RV350, RV380 */ +struct r300_asic { + const unsigned *reg_safe_bm; + unsigned reg_safe_bm_size; +}; + + +/* RS690, RS740 */ void rs690_line_buffer_adjust(struct radeon_device *rdev, struct drm_display_mode *mode1, struct drm_display_mode *mode2); + +/* RV515 */ void rv515_bandwidth_avivo_update(struct radeon_device *rdev); + +/* R600, RV610, RV630, RV620, RV635, RV670, RS780, RS880 */ +bool r600_card_posted(struct radeon_device *rdev); +void r600_cp_stop(struct radeon_device *rdev); +void r600_ring_init(struct radeon_device *rdev, unsigned ring_size); +int r600_cp_resume(struct radeon_device *rdev); +int r600_count_pipe_bits(uint32_t val); +int r600_gart_clear_page(struct radeon_device *rdev, int i); +int r600_mc_wait_for_idle(struct radeon_device *rdev); +void r600_pcie_gart_tlb_flush(struct radeon_device *rdev); +int r600_ib_test(struct radeon_device *rdev); +int r600_ring_test(struct radeon_device *rdev); +int r600_wb_init(struct radeon_device *rdev); +void r600_wb_fini(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_cp_init_microcode(struct radeon_device *rdev); +struct r600_asic { + unsigned max_pipes; + unsigned max_tile_pipes; + unsigned max_simds; + unsigned max_backends; + unsigned max_gprs; + unsigned max_threads; + unsigned max_stack_entries; + unsigned max_hw_contexts; + unsigned max_gs_threads; + unsigned sx_max_export_size; + unsigned sx_max_export_pos_size; + unsigned sx_max_export_smx_size; + unsigned sq_num_cf_insts; +}; + +/* RV770, RV7300, RV710 */ +struct rv770_asic { + unsigned max_pipes; + unsigned max_tile_pipes; + unsigned max_simds; + unsigned max_backends; + unsigned max_gprs; + unsigned max_threads; + unsigned max_stack_entries; + unsigned max_hw_contexts; + unsigned max_gs_threads; + unsigned sx_max_export_size; + unsigned sx_max_export_pos_size; + unsigned sx_max_export_smx_size; + unsigned sq_num_cf_insts; + unsigned sx_num_of_sets; + unsigned sc_prim_fifo_size; + unsigned sc_hiz_tile_fifo_size; + unsigned sc_earlyz_tile_fifo_fize; +}; + #endif diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c index 2882f40d5ec5..aad0c6fafcf4 100644 --- a/drivers/gpu/drm/radeon/radeon_state.c +++ b/drivers/gpu/drm/radeon/radeon_state.c @@ -1546,7 +1546,7 @@ static void radeon_cp_dispatch_vertex(struct drm_device * dev, } while (i < nbox); } -static void radeon_cp_discard_buffer(struct drm_device *dev, struct drm_master *master, struct drm_buf *buf) +void radeon_cp_discard_buffer(struct drm_device *dev, struct drm_master *master, struct drm_buf *buf) { drm_radeon_private_t *dev_priv = dev->dev_private; struct drm_radeon_master_private *master_priv = master->driver_priv; @@ -2213,7 +2213,10 @@ static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *f if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; - radeon_cp_dispatch_swap(dev, file_priv->master); + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) + r600_cp_dispatch_swap(dev, file_priv); + else + radeon_cp_dispatch_swap(dev, file_priv->master); sarea_priv->ctx_owner = 0; COMMIT_RING(); @@ -2412,7 +2415,10 @@ static int radeon_cp_texture(struct drm_device *dev, void *data, struct drm_file RING_SPACE_TEST_WITH_RETURN(dev_priv); VB_AGE_TEST_WITH_RETURN(dev_priv); - ret = radeon_cp_dispatch_texture(dev, file_priv, tex, &image); + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) + ret = r600_cp_dispatch_texture(dev, file_priv, tex, &image); + else + ret = radeon_cp_dispatch_texture(dev, file_priv, tex, &image); return ret; } @@ -2495,8 +2501,9 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end); } - if (indirect->discard) + if (indirect->discard) { radeon_cp_discard_buffer(dev, file_priv->master, buf); + } COMMIT_RING(); return 0; @@ -3227,7 +3234,8 @@ struct drm_ioctl_desc radeon_ioctls[] = { DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH) + DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_CS, r600_cs_legacy_ioctl, DRM_AUTH) }; int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls); diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index dc7a44274ea8..acd889c94549 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -376,9 +376,8 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, radeon_move_null(bo, new_mem); return 0; } - if (!rdev->cp.ready) { + if (!rdev->cp.ready || rdev->asic->copy == NULL) { /* use memcpy */ - DRM_ERROR("CP is not ready use memcpy.\n"); goto memcpy; } @@ -495,7 +494,7 @@ int radeon_ttm_init(struct radeon_device *rdev) return r; } DRM_INFO("radeon: %uM of VRAM memory ready\n", - 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, 0, ((rdev->mc.gtt_size) >> PAGE_SHIFT)); if (r) { @@ -503,7 +502,7 @@ int radeon_ttm_init(struct radeon_device *rdev) return r; } DRM_INFO("radeon: %uM of GTT memory ready.\n", - rdev->mc.gtt_size / (1024 * 1024)); + (unsigned)(rdev->mc.gtt_size / (1024 * 1024))); if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) { rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping; } diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index b29affd9c5d8..8c3ea7e36060 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -63,7 +63,7 @@ void rs400_gart_adjust_size(struct radeon_device *rdev) break; default: DRM_ERROR("Unable to use IGP GART size %uM\n", - rdev->mc.gtt_size >> 20); + (unsigned)(rdev->mc.gtt_size >> 20)); DRM_ERROR("Valid GART size for IGP are 32M,64M,128M,256M,512M,1G,2G\n"); DRM_ERROR("Forcing to 32M GART size\n"); rdev->mc.gtt_size = 32 * 1024 * 1024; diff --git a/drivers/gpu/drm/radeon/rs780.c b/drivers/gpu/drm/radeon/rs780.c deleted file mode 100644 index 0affcff81825..000000000000 --- a/drivers/gpu/drm/radeon/rs780.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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 "drmP.h" -#include "radeon_reg.h" -#include "radeon.h" - -/* rs780 depends on : */ -void rs600_mc_disable_clients(struct radeon_device *rdev); - -/* This files gather functions specifics to: - * rs780 - * - * Some of these functions might be used by newer ASICs. - */ -int rs780_mc_wait_for_idle(struct radeon_device *rdev); -void rs780_gpu_init(struct radeon_device *rdev); - - -/* - * MC - */ -int rs780_mc_init(struct radeon_device *rdev) -{ - rs780_gpu_init(rdev); - /* FIXME: implement */ - - rs600_mc_disable_clients(rdev); - if (rs780_mc_wait_for_idle(rdev)) { - printk(KERN_WARNING "Failed to wait MC idle while " - "programming pipes. Bad things might happen.\n"); - } - return 0; -} - -void rs780_mc_fini(struct radeon_device *rdev) -{ - /* FIXME: implement */ -} - - -/* - * Global GPU functions - */ -void rs780_errata(struct radeon_device *rdev) -{ - rdev->pll_errata = 0; -} - -int rs780_mc_wait_for_idle(struct radeon_device *rdev) -{ - /* FIXME: implement */ - return 0; -} - -void rs780_gpu_init(struct radeon_device *rdev) -{ - /* FIXME: implement */ -} - - -/* - * VRAM info - */ -void rs780_vram_get_type(struct radeon_device *rdev) -{ - /* FIXME: implement */ -} - -void rs780_vram_info(struct radeon_device *rdev) -{ - rs780_vram_get_type(rdev); - - /* FIXME: implement */ - /* Could aper size report 0 ? */ - rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); - rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); -} diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 97965c430c1f..99e397f16384 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -27,7 +27,7 @@ */ #include #include "drmP.h" -#include "rv515r.h" +#include "rv515d.h" #include "radeon.h" #include "radeon_share.h" diff --git a/drivers/gpu/drm/radeon/rv515d.h b/drivers/gpu/drm/radeon/rv515d.h new file mode 100644 index 000000000000..a65e17ec1c08 --- /dev/null +++ b/drivers/gpu/drm/radeon/rv515d.h @@ -0,0 +1,220 @@ +/* + * 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 + */ +#ifndef __RV515D_H__ +#define __RV515D_H__ + +/* + * RV515 registers + */ +#define PCIE_INDEX 0x0030 +#define PCIE_DATA 0x0034 +#define MC_IND_INDEX 0x0070 +#define MC_IND_WR_EN (1 << 24) +#define MC_IND_DATA 0x0074 +#define RBBM_SOFT_RESET 0x00F0 +#define CONFIG_MEMSIZE 0x00F8 +#define HDP_FB_LOCATION 0x0134 +#define CP_CSQ_CNTL 0x0740 +#define CP_CSQ_MODE 0x0744 +#define CP_CSQ_ADDR 0x07F0 +#define CP_CSQ_DATA 0x07F4 +#define CP_CSQ_STAT 0x07F8 +#define CP_CSQ2_STAT 0x07FC +#define RBBM_STATUS 0x0E40 +#define DST_PIPE_CONFIG 0x170C +#define WAIT_UNTIL 0x1720 +#define WAIT_2D_IDLE (1 << 14) +#define WAIT_3D_IDLE (1 << 15) +#define WAIT_2D_IDLECLEAN (1 << 16) +#define WAIT_3D_IDLECLEAN (1 << 17) +#define ISYNC_CNTL 0x1724 +#define ISYNC_ANY2D_IDLE3D (1 << 0) +#define ISYNC_ANY3D_IDLE2D (1 << 1) +#define ISYNC_TRIG2D_IDLE3D (1 << 2) +#define ISYNC_TRIG3D_IDLE2D (1 << 3) +#define ISYNC_WAIT_IDLEGUI (1 << 4) +#define ISYNC_CPSCRATCH_IDLEGUI (1 << 5) +#define VAP_INDEX_OFFSET 0x208C +#define VAP_PVS_STATE_FLUSH_REG 0x2284 +#define GB_ENABLE 0x4008 +#define GB_MSPOS0 0x4010 +#define MS_X0_SHIFT 0 +#define MS_Y0_SHIFT 4 +#define MS_X1_SHIFT 8 +#define MS_Y1_SHIFT 12 +#define MS_X2_SHIFT 16 +#define MS_Y2_SHIFT 20 +#define MSBD0_Y_SHIFT 24 +#define MSBD0_X_SHIFT 28 +#define GB_MSPOS1 0x4014 +#define MS_X3_SHIFT 0 +#define MS_Y3_SHIFT 4 +#define MS_X4_SHIFT 8 +#define MS_Y4_SHIFT 12 +#define MS_X5_SHIFT 16 +#define MS_Y5_SHIFT 20 +#define MSBD1_SHIFT 24 +#define GB_TILE_CONFIG 0x4018 +#define ENABLE_TILING (1 << 0) +#define PIPE_COUNT_MASK 0x0000000E +#define PIPE_COUNT_SHIFT 1 +#define TILE_SIZE_8 (0 << 4) +#define TILE_SIZE_16 (1 << 4) +#define TILE_SIZE_32 (2 << 4) +#define SUBPIXEL_1_12 (0 << 16) +#define SUBPIXEL_1_16 (1 << 16) +#define GB_SELECT 0x401C +#define GB_AA_CONFIG 0x4020 +#define GB_PIPE_SELECT 0x402C +#define GA_ENHANCE 0x4274 +#define GA_DEADLOCK_CNTL (1 << 0) +#define GA_FASTSYNC_CNTL (1 << 1) +#define GA_POLY_MODE 0x4288 +#define FRONT_PTYPE_POINT (0 << 4) +#define FRONT_PTYPE_LINE (1 << 4) +#define FRONT_PTYPE_TRIANGE (2 << 4) +#define BACK_PTYPE_POINT (0 << 7) +#define BACK_PTYPE_LINE (1 << 7) +#define BACK_PTYPE_TRIANGE (2 << 7) +#define GA_ROUND_MODE 0x428C +#define GEOMETRY_ROUND_TRUNC (0 << 0) +#define GEOMETRY_ROUND_NEAREST (1 << 0) +#define COLOR_ROUND_TRUNC (0 << 2) +#define COLOR_ROUND_NEAREST (1 << 2) +#define SU_REG_DEST 0x42C8 +#define RB3D_DSTCACHE_CTLSTAT 0x4E4C +#define RB3D_DC_FLUSH (2 << 0) +#define RB3D_DC_FREE (2 << 2) +#define RB3D_DC_FINISH (1 << 4) +#define ZB_ZCACHE_CTLSTAT 0x4F18 +#define ZC_FLUSH (1 << 0) +#define ZC_FREE (1 << 1) +#define DC_LB_MEMORY_SPLIT 0x6520 +#define DC_LB_MEMORY_SPLIT_MASK 0x00000003 +#define DC_LB_MEMORY_SPLIT_SHIFT 0 +#define DC_LB_MEMORY_SPLIT_D1HALF_D2HALF 0 +#define DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q 1 +#define DC_LB_MEMORY_SPLIT_D1_ONLY 2 +#define DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q 3 +#define DC_LB_MEMORY_SPLIT_SHIFT_MODE (1 << 2) +#define DC_LB_DISP1_END_ADR_SHIFT 4 +#define DC_LB_DISP1_END_ADR_MASK 0x00007FF0 +#define D1MODE_PRIORITY_A_CNT 0x6548 +#define MODE_PRIORITY_MARK_MASK 0x00007FFF +#define MODE_PRIORITY_OFF (1 << 16) +#define MODE_PRIORITY_ALWAYS_ON (1 << 20) +#define MODE_PRIORITY_FORCE_MASK (1 << 24) +#define D1MODE_PRIORITY_B_CNT 0x654C +#define LB_MAX_REQ_OUTSTANDING 0x6D58 +#define LB_D1_MAX_REQ_OUTSTANDING_MASK 0x0000000F +#define LB_D1_MAX_REQ_OUTSTANDING_SHIFT 0 +#define LB_D2_MAX_REQ_OUTSTANDING_MASK 0x000F0000 +#define LB_D2_MAX_REQ_OUTSTANDING_SHIFT 16 +#define D2MODE_PRIORITY_A_CNT 0x6D48 +#define D2MODE_PRIORITY_B_CNT 0x6D4C + +/* ix[MC] registers */ +#define MC_FB_LOCATION 0x01 +#define MC_FB_START_MASK 0x0000FFFF +#define MC_FB_START_SHIFT 0 +#define MC_FB_TOP_MASK 0xFFFF0000 +#define MC_FB_TOP_SHIFT 16 +#define MC_AGP_LOCATION 0x02 +#define MC_AGP_START_MASK 0x0000FFFF +#define MC_AGP_START_SHIFT 0 +#define MC_AGP_TOP_MASK 0xFFFF0000 +#define MC_AGP_TOP_SHIFT 16 +#define MC_AGP_BASE 0x03 +#define MC_AGP_BASE_2 0x04 +#define MC_CNTL 0x5 +#define MEM_NUM_CHANNELS_MASK 0x00000003 +#define MC_STATUS 0x08 +#define MC_STATUS_IDLE (1 << 4) +#define MC_MISC_LAT_TIMER 0x09 +#define MC_CPR_INIT_LAT_MASK 0x0000000F +#define MC_VF_INIT_LAT_MASK 0x000000F0 +#define MC_DISP0R_INIT_LAT_MASK 0x00000F00 +#define MC_DISP0R_INIT_LAT_SHIFT 8 +#define MC_DISP1R_INIT_LAT_MASK 0x0000F000 +#define MC_DISP1R_INIT_LAT_SHIFT 12 +#define MC_FIXED_INIT_LAT_MASK 0x000F0000 +#define MC_E2R_INIT_LAT_MASK 0x00F00000 +#define SAME_PAGE_PRIO_MASK 0x0F000000 +#define MC_GLOBW_INIT_LAT_MASK 0xF0000000 + + +/* + * PM4 packet + */ +#define CP_PACKET0 0x00000000 +#define PACKET0_BASE_INDEX_SHIFT 0 +#define PACKET0_BASE_INDEX_MASK (0x1ffff << 0) +#define PACKET0_COUNT_SHIFT 16 +#define PACKET0_COUNT_MASK (0x3fff << 16) +#define CP_PACKET1 0x40000000 +#define CP_PACKET2 0x80000000 +#define PACKET2_PAD_SHIFT 0 +#define PACKET2_PAD_MASK (0x3fffffff << 0) +#define CP_PACKET3 0xC0000000 +#define PACKET3_IT_OPCODE_SHIFT 8 +#define PACKET3_IT_OPCODE_MASK (0xff << 8) +#define PACKET3_COUNT_SHIFT 16 +#define PACKET3_COUNT_MASK (0x3fff << 16) +/* PACKET3 op code */ +#define PACKET3_NOP 0x10 +#define PACKET3_3D_DRAW_VBUF 0x28 +#define PACKET3_3D_DRAW_IMMD 0x29 +#define PACKET3_3D_DRAW_INDX 0x2A +#define PACKET3_3D_LOAD_VBPNTR 0x2F +#define PACKET3_INDX_BUFFER 0x33 +#define PACKET3_3D_DRAW_VBUF_2 0x34 +#define PACKET3_3D_DRAW_IMMD_2 0x35 +#define PACKET3_3D_DRAW_INDX_2 0x36 +#define PACKET3_BITBLT_MULTI 0x9B + +#define PACKET0(reg, n) (CP_PACKET0 | \ + REG_SET(PACKET0_BASE_INDEX, (reg) >> 2) | \ + REG_SET(PACKET0_COUNT, (n))) +#define PACKET2(v) (CP_PACKET2 | REG_SET(PACKET2_PAD, (v))) +#define PACKET3(op, n) (CP_PACKET3 | \ + REG_SET(PACKET3_IT_OPCODE, (op)) | \ + REG_SET(PACKET3_COUNT, (n))) + +#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) & 0x1FFF) << 2) +#define CP_PACKET0_GET_ONE_REG_WR(h) (((h) >> 15) & 1) +#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF) + +#endif + diff --git a/drivers/gpu/drm/radeon/rv515r.h b/drivers/gpu/drm/radeon/rv515r.h deleted file mode 100644 index f3cf84039906..000000000000 --- a/drivers/gpu/drm/radeon/rv515r.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * 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 - */ -#ifndef RV515R_H -#define RV515R_H - -/* RV515 registers */ -#define PCIE_INDEX 0x0030 -#define PCIE_DATA 0x0034 -#define MC_IND_INDEX 0x0070 -#define MC_IND_WR_EN (1 << 24) -#define MC_IND_DATA 0x0074 -#define RBBM_SOFT_RESET 0x00F0 -#define CONFIG_MEMSIZE 0x00F8 -#define HDP_FB_LOCATION 0x0134 -#define CP_CSQ_CNTL 0x0740 -#define CP_CSQ_MODE 0x0744 -#define CP_CSQ_ADDR 0x07F0 -#define CP_CSQ_DATA 0x07F4 -#define CP_CSQ_STAT 0x07F8 -#define CP_CSQ2_STAT 0x07FC -#define RBBM_STATUS 0x0E40 -#define DST_PIPE_CONFIG 0x170C -#define WAIT_UNTIL 0x1720 -#define WAIT_2D_IDLE (1 << 14) -#define WAIT_3D_IDLE (1 << 15) -#define WAIT_2D_IDLECLEAN (1 << 16) -#define WAIT_3D_IDLECLEAN (1 << 17) -#define ISYNC_CNTL 0x1724 -#define ISYNC_ANY2D_IDLE3D (1 << 0) -#define ISYNC_ANY3D_IDLE2D (1 << 1) -#define ISYNC_TRIG2D_IDLE3D (1 << 2) -#define ISYNC_TRIG3D_IDLE2D (1 << 3) -#define ISYNC_WAIT_IDLEGUI (1 << 4) -#define ISYNC_CPSCRATCH_IDLEGUI (1 << 5) -#define VAP_INDEX_OFFSET 0x208C -#define VAP_PVS_STATE_FLUSH_REG 0x2284 -#define GB_ENABLE 0x4008 -#define GB_MSPOS0 0x4010 -#define MS_X0_SHIFT 0 -#define MS_Y0_SHIFT 4 -#define MS_X1_SHIFT 8 -#define MS_Y1_SHIFT 12 -#define MS_X2_SHIFT 16 -#define MS_Y2_SHIFT 20 -#define MSBD0_Y_SHIFT 24 -#define MSBD0_X_SHIFT 28 -#define GB_MSPOS1 0x4014 -#define MS_X3_SHIFT 0 -#define MS_Y3_SHIFT 4 -#define MS_X4_SHIFT 8 -#define MS_Y4_SHIFT 12 -#define MS_X5_SHIFT 16 -#define MS_Y5_SHIFT 20 -#define MSBD1_SHIFT 24 -#define GB_TILE_CONFIG 0x4018 -#define ENABLE_TILING (1 << 0) -#define PIPE_COUNT_MASK 0x0000000E -#define PIPE_COUNT_SHIFT 1 -#define TILE_SIZE_8 (0 << 4) -#define TILE_SIZE_16 (1 << 4) -#define TILE_SIZE_32 (2 << 4) -#define SUBPIXEL_1_12 (0 << 16) -#define SUBPIXEL_1_16 (1 << 16) -#define GB_SELECT 0x401C -#define GB_AA_CONFIG 0x4020 -#define GB_PIPE_SELECT 0x402C -#define GA_ENHANCE 0x4274 -#define GA_DEADLOCK_CNTL (1 << 0) -#define GA_FASTSYNC_CNTL (1 << 1) -#define GA_POLY_MODE 0x4288 -#define FRONT_PTYPE_POINT (0 << 4) -#define FRONT_PTYPE_LINE (1 << 4) -#define FRONT_PTYPE_TRIANGE (2 << 4) -#define BACK_PTYPE_POINT (0 << 7) -#define BACK_PTYPE_LINE (1 << 7) -#define BACK_PTYPE_TRIANGE (2 << 7) -#define GA_ROUND_MODE 0x428C -#define GEOMETRY_ROUND_TRUNC (0 << 0) -#define GEOMETRY_ROUND_NEAREST (1 << 0) -#define COLOR_ROUND_TRUNC (0 << 2) -#define COLOR_ROUND_NEAREST (1 << 2) -#define SU_REG_DEST 0x42C8 -#define RB3D_DSTCACHE_CTLSTAT 0x4E4C -#define RB3D_DC_FLUSH (2 << 0) -#define RB3D_DC_FREE (2 << 2) -#define RB3D_DC_FINISH (1 << 4) -#define ZB_ZCACHE_CTLSTAT 0x4F18 -#define ZC_FLUSH (1 << 0) -#define ZC_FREE (1 << 1) -#define DC_LB_MEMORY_SPLIT 0x6520 -#define DC_LB_MEMORY_SPLIT_MASK 0x00000003 -#define DC_LB_MEMORY_SPLIT_SHIFT 0 -#define DC_LB_MEMORY_SPLIT_D1HALF_D2HALF 0 -#define DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q 1 -#define DC_LB_MEMORY_SPLIT_D1_ONLY 2 -#define DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q 3 -#define DC_LB_MEMORY_SPLIT_SHIFT_MODE (1 << 2) -#define DC_LB_DISP1_END_ADR_SHIFT 4 -#define DC_LB_DISP1_END_ADR_MASK 0x00007FF0 -#define D1MODE_PRIORITY_A_CNT 0x6548 -#define MODE_PRIORITY_MARK_MASK 0x00007FFF -#define MODE_PRIORITY_OFF (1 << 16) -#define MODE_PRIORITY_ALWAYS_ON (1 << 20) -#define MODE_PRIORITY_FORCE_MASK (1 << 24) -#define D1MODE_PRIORITY_B_CNT 0x654C -#define LB_MAX_REQ_OUTSTANDING 0x6D58 -#define LB_D1_MAX_REQ_OUTSTANDING_MASK 0x0000000F -#define LB_D1_MAX_REQ_OUTSTANDING_SHIFT 0 -#define LB_D2_MAX_REQ_OUTSTANDING_MASK 0x000F0000 -#define LB_D2_MAX_REQ_OUTSTANDING_SHIFT 16 -#define D2MODE_PRIORITY_A_CNT 0x6D48 -#define D2MODE_PRIORITY_B_CNT 0x6D4C - -/* ix[MC] registers */ -#define MC_FB_LOCATION 0x01 -#define MC_FB_START_MASK 0x0000FFFF -#define MC_FB_START_SHIFT 0 -#define MC_FB_TOP_MASK 0xFFFF0000 -#define MC_FB_TOP_SHIFT 16 -#define MC_AGP_LOCATION 0x02 -#define MC_AGP_START_MASK 0x0000FFFF -#define MC_AGP_START_SHIFT 0 -#define MC_AGP_TOP_MASK 0xFFFF0000 -#define MC_AGP_TOP_SHIFT 16 -#define MC_AGP_BASE 0x03 -#define MC_AGP_BASE_2 0x04 -#define MC_CNTL 0x5 -#define MEM_NUM_CHANNELS_MASK 0x00000003 -#define MC_STATUS 0x08 -#define MC_STATUS_IDLE (1 << 4) -#define MC_MISC_LAT_TIMER 0x09 -#define MC_CPR_INIT_LAT_MASK 0x0000000F -#define MC_VF_INIT_LAT_MASK 0x000000F0 -#define MC_DISP0R_INIT_LAT_MASK 0x00000F00 -#define MC_DISP0R_INIT_LAT_SHIFT 8 -#define MC_DISP1R_INIT_LAT_MASK 0x0000F000 -#define MC_DISP1R_INIT_LAT_SHIFT 12 -#define MC_FIXED_INIT_LAT_MASK 0x000F0000 -#define MC_E2R_INIT_LAT_MASK 0x00F00000 -#define SAME_PAGE_PRIO_MASK 0x0F000000 -#define MC_GLOBW_INIT_LAT_MASK 0xF0000000 - - -#endif - diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 21d8ffd57308..57765f6d5b20 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -25,100 +25,975 @@ * Alex Deucher * Jerome Glisse */ +#include +#include #include "drmP.h" -#include "radeon_reg.h" #include "radeon.h" +#include "radeon_share.h" +#include "rv770d.h" +#include "avivod.h" +#include "atom.h" -/* rv770,rv730,rv710 depends on : */ -void rs600_mc_disable_clients(struct radeon_device *rdev); +#define R700_PFP_UCODE_SIZE 848 +#define R700_PM4_UCODE_SIZE 1360 -/* This files gather functions specifics to: - * rv770,rv730,rv710 - * - * Some of these functions might be used by newer ASICs. - */ -int rv770_mc_wait_for_idle(struct radeon_device *rdev); -void rv770_gpu_init(struct radeon_device *rdev); +static void rv770_gpu_init(struct radeon_device *rdev); +void rv770_fini(struct radeon_device *rdev); /* - * MC + * GART */ -int rv770_mc_init(struct radeon_device *rdev) +int rv770_pcie_gart_enable(struct radeon_device *rdev) { - uint32_t tmp; + u32 tmp; + int r, i; - rv770_gpu_init(rdev); + /* Initialize common gart structure */ + r = radeon_gart_init(rdev); + if (r) { + return r; + } + rdev->gart.table_size = rdev->gart.num_gpu_pages * 8; + r = radeon_gart_table_vram_alloc(rdev); + if (r) { + return r; + } + for (i = 0; i < rdev->gart.num_gpu_pages; i++) + r600_gart_clear_page(rdev, i); + /* Setup L2 cache */ + WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING | + ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE | + EFFECTIVE_L2_QUEUE_SIZE(7)); + WREG32(VM_L2_CNTL2, 0); + WREG32(VM_L2_CNTL3, BANK_SELECT(0) | CACHE_UPDATE_MODE(2)); + /* Setup TLB control */ + tmp = ENABLE_L1_TLB | ENABLE_L1_FRAGMENT_PROCESSING | + SYSTEM_ACCESS_MODE_NOT_IN_SYS | + SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU | + EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5); + WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); + WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); + WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); + WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp); + WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); + WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); + WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp); + WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12); + WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, (rdev->mc.gtt_end - 1) >> 12); + WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12); + WREG32(VM_CONTEXT0_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) | + RANGE_PROTECTION_FAULT_ENABLE_DEFAULT); + WREG32(VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, + (u32)(rdev->dummy_page.addr >> 12)); + for (i = 1; i < 7; i++) + WREG32(VM_CONTEXT0_CNTL + (i * 4), 0); - /* setup the gart before changing location so we can ask to - * discard unmapped mc request - */ - /* FIXME: disable out of gart access */ - tmp = rdev->mc.gtt_location / 4096; - tmp = REG_SET(R700_LOGICAL_PAGE_NUMBER, tmp); - WREG32(R700_MC_VM_SYSTEM_APERTURE_LOW_ADDR, tmp); - tmp = (rdev->mc.gtt_location + rdev->mc.gtt_size) / 4096; - tmp = REG_SET(R700_LOGICAL_PAGE_NUMBER, tmp); - WREG32(R700_MC_VM_SYSTEM_APERTURE_HIGH_ADDR, tmp); - - rs600_mc_disable_clients(rdev); - if (rv770_mc_wait_for_idle(rdev)) { - printk(KERN_WARNING "Failed to wait MC idle while " - "programming pipes. Bad things might happen.\n"); - } - - tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1; - tmp = REG_SET(R700_MC_FB_TOP, tmp >> 24); - tmp |= REG_SET(R700_MC_FB_BASE, rdev->mc.vram_location >> 24); - WREG32(R700_MC_VM_FB_LOCATION, tmp); - tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; - tmp = REG_SET(R700_MC_AGP_TOP, tmp >> 22); - WREG32(R700_MC_VM_AGP_TOP, tmp); - tmp = REG_SET(R700_MC_AGP_BOT, rdev->mc.gtt_location >> 22); - WREG32(R700_MC_VM_AGP_BOT, tmp); + r600_pcie_gart_tlb_flush(rdev); + rdev->gart.ready = true; return 0; } -void rv770_mc_fini(struct radeon_device *rdev) +void rv770_pcie_gart_disable(struct radeon_device *rdev) { - /* FIXME: implement */ + u32 tmp; + int i; + + /* Clear ptes*/ + for (i = 0; i < rdev->gart.num_gpu_pages; i++) + r600_gart_clear_page(rdev, i); + r600_pcie_gart_tlb_flush(rdev); + /* Disable all tables */ + for (i = 0; i < 7; i++) + WREG32(VM_CONTEXT0_CNTL + (i * 4), 0); + + /* Setup L2 cache */ + WREG32(VM_L2_CNTL, ENABLE_L2_FRAGMENT_PROCESSING | + EFFECTIVE_L2_QUEUE_SIZE(7)); + WREG32(VM_L2_CNTL2, 0); + WREG32(VM_L2_CNTL3, BANK_SELECT(0) | CACHE_UPDATE_MODE(2)); + /* Setup TLB control */ + tmp = EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5); + WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); + WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); + WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); + WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp); + WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); + WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); + WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp); } /* - * Global GPU functions + * MC */ -void rv770_errata(struct radeon_device *rdev) +static void rv770_mc_resume(struct radeon_device *rdev) { - rdev->pll_errata = 0; + u32 d1vga_control, d2vga_control; + u32 vga_render_control, vga_hdp_control; + u32 d1crtc_control, d2crtc_control; + u32 new_d1grph_primary, new_d1grph_secondary; + u32 new_d2grph_primary, new_d2grph_secondary; + u64 old_vram_start; + 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); + + d1vga_control = RREG32(D1VGA_CONTROL); + d2vga_control = RREG32(D2VGA_CONTROL); + vga_render_control = RREG32(VGA_RENDER_CONTROL); + vga_hdp_control = RREG32(VGA_HDP_CONTROL); + d1crtc_control = RREG32(D1CRTC_CONTROL); + d2crtc_control = RREG32(D2CRTC_CONTROL); + old_vram_start = (u64)(RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24; + new_d1grph_primary = RREG32(D1GRPH_PRIMARY_SURFACE_ADDRESS); + new_d1grph_secondary = RREG32(D1GRPH_SECONDARY_SURFACE_ADDRESS); + new_d1grph_primary += rdev->mc.vram_start - old_vram_start; + new_d1grph_secondary += rdev->mc.vram_start - old_vram_start; + new_d2grph_primary = RREG32(D2GRPH_PRIMARY_SURFACE_ADDRESS); + new_d2grph_secondary = RREG32(D2GRPH_SECONDARY_SURFACE_ADDRESS); + new_d2grph_primary += rdev->mc.vram_start - old_vram_start; + new_d2grph_secondary += rdev->mc.vram_start - old_vram_start; + + /* Stop all video */ + WREG32(D1VGA_CONTROL, 0); + WREG32(D2VGA_CONTROL, 0); + WREG32(VGA_RENDER_CONTROL, 0); + WREG32(D1CRTC_UPDATE_LOCK, 1); + WREG32(D2CRTC_UPDATE_LOCK, 1); + WREG32(D1CRTC_CONTROL, 0); + WREG32(D2CRTC_CONTROL, 0); + WREG32(D1CRTC_UPDATE_LOCK, 0); + WREG32(D2CRTC_UPDATE_LOCK, 0); + + mdelay(1); + if (r600_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "[drm] MC not idle !\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 - 1) >> 12); + WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0); + tmp = (((rdev->mc.vram_end - 1) >> 24) & 0xFFFF) << 16; + tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); + WREG32(MC_VM_FB_LOCATION, tmp); + WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8)); + WREG32(HDP_NONSURFACE_INFO, (2 << 7)); + WREG32(HDP_NONSURFACE_SIZE, (rdev->mc.mc_vram_size - 1) | 0x3FF); + if (rdev->flags & RADEON_IS_AGP) { + WREG32(MC_VM_AGP_TOP, (rdev->mc.gtt_end - 1) >> 16); + WREG32(MC_VM_AGP_BOT, rdev->mc.gtt_start >> 16); + WREG32(MC_VM_AGP_BASE, rdev->mc.agp_base >> 22); + } else { + WREG32(MC_VM_AGP_BASE, 0); + WREG32(MC_VM_AGP_TOP, 0x0FFFFFFF); + WREG32(MC_VM_AGP_BOT, 0x0FFFFFFF); + } + WREG32(D1GRPH_PRIMARY_SURFACE_ADDRESS, new_d1grph_primary); + WREG32(D1GRPH_SECONDARY_SURFACE_ADDRESS, new_d1grph_secondary); + WREG32(D2GRPH_PRIMARY_SURFACE_ADDRESS, new_d2grph_primary); + WREG32(D2GRPH_SECONDARY_SURFACE_ADDRESS, new_d2grph_secondary); + WREG32(VGA_MEMORY_BASE_ADDRESS, rdev->mc.vram_start); + + /* Unlock host access */ + WREG32(VGA_HDP_CONTROL, vga_hdp_control); + + mdelay(1); + if (r600_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "[drm] MC not idle !\n"); + } + + /* Restore video state */ + WREG32(D1CRTC_UPDATE_LOCK, 1); + WREG32(D2CRTC_UPDATE_LOCK, 1); + WREG32(D1CRTC_CONTROL, d1crtc_control); + WREG32(D2CRTC_CONTROL, d2crtc_control); + WREG32(D1CRTC_UPDATE_LOCK, 0); + WREG32(D2CRTC_UPDATE_LOCK, 0); + WREG32(D1VGA_CONTROL, d1vga_control); + WREG32(D2VGA_CONTROL, d2vga_control); + WREG32(VGA_RENDER_CONTROL, vga_render_control); } -int rv770_mc_wait_for_idle(struct radeon_device *rdev) + +/* + * CP. + */ +void r700_cp_stop(struct radeon_device *rdev) { - /* FIXME: implement */ - return 0; + WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT)); } -void rv770_gpu_init(struct radeon_device *rdev) + +static int rv770_cp_load_microcode(struct radeon_device *rdev) { - /* FIXME: implement */ + const __be32 *fw_data; + int i; + + if (!rdev->me_fw || !rdev->pfp_fw) + return -EINVAL; + + r700_cp_stop(rdev); + WREG32(CP_RB_CNTL, RB_NO_UPDATE | (15 << 8) | (3 << 0)); + + /* Reset cp */ + WREG32(GRBM_SOFT_RESET, SOFT_RESET_CP); + RREG32(GRBM_SOFT_RESET); + mdelay(15); + WREG32(GRBM_SOFT_RESET, 0); + + fw_data = (const __be32 *)rdev->pfp_fw->data; + WREG32(CP_PFP_UCODE_ADDR, 0); + for (i = 0; i < R700_PFP_UCODE_SIZE; i++) + WREG32(CP_PFP_UCODE_DATA, be32_to_cpup(fw_data++)); + WREG32(CP_PFP_UCODE_ADDR, 0); + + fw_data = (const __be32 *)rdev->me_fw->data; + WREG32(CP_ME_RAM_WADDR, 0); + for (i = 0; i < R700_PM4_UCODE_SIZE; i++) + WREG32(CP_ME_RAM_DATA, be32_to_cpup(fw_data++)); + + WREG32(CP_PFP_UCODE_ADDR, 0); + WREG32(CP_ME_RAM_WADDR, 0); + WREG32(CP_ME_RAM_RADDR, 0); + return 0; } /* - * VRAM info + * Core functions */ -void rv770_vram_get_type(struct radeon_device *rdev) +static u32 r700_get_tile_pipe_to_backend_map(u32 num_tile_pipes, + u32 num_backends, + u32 backend_disable_mask) { - /* FIXME: implement */ + u32 backend_map = 0; + u32 enabled_backends_mask; + u32 enabled_backends_count; + u32 cur_pipe; + u32 swizzle_pipe[R7XX_MAX_PIPES]; + u32 cur_backend; + u32 i; + + if (num_tile_pipes > R7XX_MAX_PIPES) + num_tile_pipes = R7XX_MAX_PIPES; + if (num_tile_pipes < 1) + num_tile_pipes = 1; + if (num_backends > R7XX_MAX_BACKENDS) + num_backends = R7XX_MAX_BACKENDS; + if (num_backends < 1) + num_backends = 1; + + enabled_backends_mask = 0; + enabled_backends_count = 0; + for (i = 0; i < R7XX_MAX_BACKENDS; ++i) { + if (((backend_disable_mask >> i) & 1) == 0) { + enabled_backends_mask |= (1 << i); + ++enabled_backends_count; + } + if (enabled_backends_count == num_backends) + break; + } + + if (enabled_backends_count == 0) { + enabled_backends_mask = 1; + enabled_backends_count = 1; + } + + if (enabled_backends_count != num_backends) + num_backends = enabled_backends_count; + + memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * R7XX_MAX_PIPES); + switch (num_tile_pipes) { + case 1: + swizzle_pipe[0] = 0; + break; + case 2: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + break; + case 3: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 1; + break; + case 4: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 3; + swizzle_pipe[3] = 1; + break; + case 5: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 1; + swizzle_pipe[4] = 3; + break; + case 6: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 5; + swizzle_pipe[4] = 3; + swizzle_pipe[5] = 1; + break; + case 7: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 6; + swizzle_pipe[4] = 3; + swizzle_pipe[5] = 1; + swizzle_pipe[6] = 5; + break; + case 8: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 6; + swizzle_pipe[4] = 3; + swizzle_pipe[5] = 1; + swizzle_pipe[6] = 7; + swizzle_pipe[7] = 5; + break; + } + + cur_backend = 0; + for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) { + while (((1 << cur_backend) & enabled_backends_mask) == 0) + cur_backend = (cur_backend + 1) % R7XX_MAX_BACKENDS; + + backend_map |= (u32)(((cur_backend & 3) << (swizzle_pipe[cur_pipe] * 2))); + + cur_backend = (cur_backend + 1) % R7XX_MAX_BACKENDS; + } + + return backend_map; } -void rv770_vram_info(struct radeon_device *rdev) +static void rv770_gpu_init(struct radeon_device *rdev) { - rv770_vram_get_type(rdev); + int i, j, num_qd_pipes; + u32 sx_debug_1; + u32 smx_dc_ctl0; + u32 num_gs_verts_per_thread; + u32 vgt_gs_per_es; + u32 gs_prim_buffer_depth = 0; + u32 sq_ms_fifo_sizes; + u32 sq_config; + u32 sq_thread_resource_mgmt; + u32 hdp_host_path_cntl; + u32 sq_dyn_gpr_size_simd_ab_0; + u32 backend_map; + 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; - /* FIXME: implement */ + /* setup chip specs */ + switch (rdev->family) { + case CHIP_RV770: + rdev->config.rv770.max_pipes = 4; + rdev->config.rv770.max_tile_pipes = 8; + rdev->config.rv770.max_simds = 10; + rdev->config.rv770.max_backends = 4; + rdev->config.rv770.max_gprs = 256; + rdev->config.rv770.max_threads = 248; + rdev->config.rv770.max_stack_entries = 512; + rdev->config.rv770.max_hw_contexts = 8; + rdev->config.rv770.max_gs_threads = 16 * 2; + rdev->config.rv770.sx_max_export_size = 128; + rdev->config.rv770.sx_max_export_pos_size = 16; + rdev->config.rv770.sx_max_export_smx_size = 112; + rdev->config.rv770.sq_num_cf_insts = 2; + + rdev->config.rv770.sx_num_of_sets = 7; + rdev->config.rv770.sc_prim_fifo_size = 0xF9; + rdev->config.rv770.sc_hiz_tile_fifo_size = 0x30; + rdev->config.rv770.sc_earlyz_tile_fifo_fize = 0x130; + break; + case CHIP_RV730: + rdev->config.rv770.max_pipes = 2; + rdev->config.rv770.max_tile_pipes = 4; + rdev->config.rv770.max_simds = 8; + rdev->config.rv770.max_backends = 2; + rdev->config.rv770.max_gprs = 128; + rdev->config.rv770.max_threads = 248; + rdev->config.rv770.max_stack_entries = 256; + rdev->config.rv770.max_hw_contexts = 8; + rdev->config.rv770.max_gs_threads = 16 * 2; + rdev->config.rv770.sx_max_export_size = 256; + rdev->config.rv770.sx_max_export_pos_size = 32; + rdev->config.rv770.sx_max_export_smx_size = 224; + rdev->config.rv770.sq_num_cf_insts = 2; + + rdev->config.rv770.sx_num_of_sets = 7; + rdev->config.rv770.sc_prim_fifo_size = 0xf9; + rdev->config.rv770.sc_hiz_tile_fifo_size = 0x30; + rdev->config.rv770.sc_earlyz_tile_fifo_fize = 0x130; + if (rdev->config.rv770.sx_max_export_pos_size > 16) { + rdev->config.rv770.sx_max_export_pos_size -= 16; + rdev->config.rv770.sx_max_export_smx_size += 16; + } + break; + case CHIP_RV710: + rdev->config.rv770.max_pipes = 2; + rdev->config.rv770.max_tile_pipes = 2; + rdev->config.rv770.max_simds = 2; + rdev->config.rv770.max_backends = 1; + rdev->config.rv770.max_gprs = 256; + rdev->config.rv770.max_threads = 192; + rdev->config.rv770.max_stack_entries = 256; + rdev->config.rv770.max_hw_contexts = 4; + rdev->config.rv770.max_gs_threads = 8 * 2; + rdev->config.rv770.sx_max_export_size = 128; + rdev->config.rv770.sx_max_export_pos_size = 16; + rdev->config.rv770.sx_max_export_smx_size = 112; + rdev->config.rv770.sq_num_cf_insts = 1; + + rdev->config.rv770.sx_num_of_sets = 7; + rdev->config.rv770.sc_prim_fifo_size = 0x40; + rdev->config.rv770.sc_hiz_tile_fifo_size = 0x30; + rdev->config.rv770.sc_earlyz_tile_fifo_fize = 0x130; + break; + case CHIP_RV740: + rdev->config.rv770.max_pipes = 4; + rdev->config.rv770.max_tile_pipes = 4; + rdev->config.rv770.max_simds = 8; + rdev->config.rv770.max_backends = 4; + rdev->config.rv770.max_gprs = 256; + rdev->config.rv770.max_threads = 248; + rdev->config.rv770.max_stack_entries = 512; + rdev->config.rv770.max_hw_contexts = 8; + rdev->config.rv770.max_gs_threads = 16 * 2; + rdev->config.rv770.sx_max_export_size = 256; + rdev->config.rv770.sx_max_export_pos_size = 32; + rdev->config.rv770.sx_max_export_smx_size = 224; + rdev->config.rv770.sq_num_cf_insts = 2; + + rdev->config.rv770.sx_num_of_sets = 7; + rdev->config.rv770.sc_prim_fifo_size = 0x100; + rdev->config.rv770.sc_hiz_tile_fifo_size = 0x30; + rdev->config.rv770.sc_earlyz_tile_fifo_fize = 0x130; + + if (rdev->config.rv770.sx_max_export_pos_size > 16) { + rdev->config.rv770.sx_max_export_pos_size -= 16; + rdev->config.rv770.sx_max_export_smx_size += 16; + } + break; + default: + break; + } + + /* Initialize HDP */ + j = 0; + for (i = 0; i < 32; i++) { + WREG32((0x2c14 + j), 0x00000000); + WREG32((0x2c18 + j), 0x00000000); + WREG32((0x2c1c + j), 0x00000000); + WREG32((0x2c20 + j), 0x00000000); + WREG32((0x2c24 + j), 0x00000000); + j += 0x18; + } + + WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff)); + + /* setup tiling, simd, pipe config */ + mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); + + switch (rdev->config.rv770.max_tile_pipes) { + case 1: + gb_tiling_config |= PIPE_TILING(0); + break; + case 2: + gb_tiling_config |= PIPE_TILING(1); + break; + case 4: + gb_tiling_config |= PIPE_TILING(2); + break; + case 8: + gb_tiling_config |= PIPE_TILING(3); + break; + default: + break; + } + + if (rdev->family == CHIP_RV770) + gb_tiling_config |= BANK_TILING(1); + else + gb_tiling_config |= BANK_TILING((mc_arb_ramcfg & NOOFBANK_SHIFT) >> NOOFBANK_MASK); + + gb_tiling_config |= GROUP_SIZE(0); + + if (((mc_arb_ramcfg & NOOFROWS_MASK) & NOOFROWS_SHIFT) > 3) { + gb_tiling_config |= ROW_TILING(3); + gb_tiling_config |= SAMPLE_SPLIT(3); + } else { + gb_tiling_config |= + ROW_TILING(((mc_arb_ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT)); + gb_tiling_config |= + SAMPLE_SPLIT(((mc_arb_ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT)); + } + + gb_tiling_config |= BANK_SWAPS(1); + + backend_map = r700_get_tile_pipe_to_backend_map(rdev->config.rv770.max_tile_pipes, + rdev->config.rv770.max_backends, + (0xff << rdev->config.rv770.max_backends) & 0xff); + gb_tiling_config |= BACKEND_MAP(backend_map); + + cc_gc_shader_pipe_config = + INACTIVE_QD_PIPES((R7XX_MAX_PIPES_MASK << rdev->config.rv770.max_pipes) & R7XX_MAX_PIPES_MASK); + cc_gc_shader_pipe_config |= + INACTIVE_SIMDS((R7XX_MAX_SIMDS_MASK << rdev->config.rv770.max_simds) & R7XX_MAX_SIMDS_MASK); + + cc_rb_backend_disable = + BACKEND_DISABLE((R7XX_MAX_BACKENDS_MASK << rdev->config.rv770.max_backends) & R7XX_MAX_BACKENDS_MASK); + + WREG32(GB_TILING_CONFIG, gb_tiling_config); + WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff)); + WREG32(HDP_TILING_CONFIG, (gb_tiling_config & 0xffff)); + + WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); + WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); + WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); + + WREG32(CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable); + WREG32(CGTS_SYS_TCC_DISABLE, 0); + WREG32(CGTS_TCC_DISABLE, 0); + WREG32(CGTS_USER_SYS_TCC_DISABLE, 0); + WREG32(CGTS_USER_TCC_DISABLE, 0); + + num_qd_pipes = + R7XX_MAX_BACKENDS - r600_count_pipe_bits(cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK); + WREG32(VGT_OUT_DEALLOC_CNTL, (num_qd_pipes * 4) & DEALLOC_DIST_MASK); + WREG32(VGT_VERTEX_REUSE_BLOCK_CNTL, ((num_qd_pipes * 4) - 2) & VTX_REUSE_DEPTH_MASK); + + /* set HW defaults for 3D engine */ + WREG32(CP_QUEUE_THRESHOLDS, (ROQ_IB1_START(0x16) | + ROQ_IB2_START(0x2b))); + + WREG32(CP_MEQ_THRESHOLDS, STQ_SPLIT(0x30)); + + WREG32(TA_CNTL_AUX, (DISABLE_CUBE_ANISO | + SYNC_GRADIENT | + SYNC_WALKER | + SYNC_ALIGNER)); + + sx_debug_1 = RREG32(SX_DEBUG_1); + sx_debug_1 |= ENABLE_NEW_SMX_ADDRESS; + WREG32(SX_DEBUG_1, sx_debug_1); + + smx_dc_ctl0 = RREG32(SMX_DC_CTL0); + smx_dc_ctl0 &= ~CACHE_DEPTH(0x1ff); + smx_dc_ctl0 |= CACHE_DEPTH((rdev->config.rv770.sx_num_of_sets * 64) - 1); + WREG32(SMX_DC_CTL0, smx_dc_ctl0); + + WREG32(SMX_EVENT_CTL, (ES_FLUSH_CTL(4) | + GS_FLUSH_CTL(4) | + ACK_FLUSH_CTL(3) | + SYNC_FLUSH_CTL)); + + if (rdev->family == CHIP_RV770) + WREG32(DB_DEBUG3, DB_CLK_OFF_DELAY(0x1f)); + else { + db_debug4 = RREG32(DB_DEBUG4); + db_debug4 |= DISABLE_TILE_COVERED_FOR_PS_ITER; + WREG32(DB_DEBUG4, db_debug4); + } + + WREG32(SX_EXPORT_BUFFER_SIZES, (COLOR_BUFFER_SIZE((rdev->config.rv770.sx_max_export_size / 4) - 1) | + POSITION_BUFFER_SIZE((rdev->config.rv770.sx_max_export_pos_size / 4) - 1) | + SMX_BUFFER_SIZE((rdev->config.rv770.sx_max_export_smx_size / 4) - 1))); + + WREG32(PA_SC_FIFO_SIZE, (SC_PRIM_FIFO_SIZE(rdev->config.rv770.sc_prim_fifo_size) | + SC_HIZ_TILE_FIFO_SIZE(rdev->config.rv770.sc_hiz_tile_fifo_size) | + SC_EARLYZ_TILE_FIFO_SIZE(rdev->config.rv770.sc_earlyz_tile_fifo_fize))); + + WREG32(PA_SC_MULTI_CHIP_CNTL, 0); + + WREG32(VGT_NUM_INSTANCES, 1); + + WREG32(SPI_CONFIG_CNTL, GPR_WRITE_PRIORITY(0)); + + WREG32(SPI_CONFIG_CNTL_1, VTX_DONE_DELAY(4)); + + WREG32(CP_PERFMON_CNTL, 0); + + sq_ms_fifo_sizes = (CACHE_FIFO_SIZE(16 * rdev->config.rv770.sq_num_cf_insts) | + DONE_FIFO_HIWATER(0xe0) | + ALU_UPDATE_FIFO_HIWATER(0x8)); + switch (rdev->family) { + case CHIP_RV770: + sq_ms_fifo_sizes |= FETCH_FIFO_HIWATER(0x1); + break; + case CHIP_RV730: + case CHIP_RV710: + case CHIP_RV740: + default: + sq_ms_fifo_sizes |= FETCH_FIFO_HIWATER(0x4); + break; + } + WREG32(SQ_MS_FIFO_SIZES, sq_ms_fifo_sizes); + + /* SQ_CONFIG, SQ_GPR_RESOURCE_MGMT, SQ_THREAD_RESOURCE_MGMT, SQ_STACK_RESOURCE_MGMT + * should be adjusted as needed by the 2D/3D drivers. This just sets default values + */ + sq_config = RREG32(SQ_CONFIG); + sq_config &= ~(PS_PRIO(3) | + VS_PRIO(3) | + GS_PRIO(3) | + ES_PRIO(3)); + sq_config |= (DX9_CONSTS | + VC_ENABLE | + EXPORT_SRC_C | + PS_PRIO(0) | + VS_PRIO(1) | + GS_PRIO(2) | + ES_PRIO(3)); + if (rdev->family == CHIP_RV710) + /* no vertex cache */ + sq_config &= ~VC_ENABLE; + + WREG32(SQ_CONFIG, sq_config); + + WREG32(SQ_GPR_RESOURCE_MGMT_1, (NUM_PS_GPRS((rdev->config.rv770.max_gprs * 24)/64) | + NUM_VS_GPRS((rdev->config.rv770.max_gprs * 24)/64) | + NUM_CLAUSE_TEMP_GPRS(((rdev->config.rv770.max_gprs * 24)/64)/2))); + + WREG32(SQ_GPR_RESOURCE_MGMT_2, (NUM_GS_GPRS((rdev->config.rv770.max_gprs * 7)/64) | + NUM_ES_GPRS((rdev->config.rv770.max_gprs * 7)/64))); + + sq_thread_resource_mgmt = (NUM_PS_THREADS((rdev->config.rv770.max_threads * 4)/8) | + NUM_VS_THREADS((rdev->config.rv770.max_threads * 2)/8) | + NUM_ES_THREADS((rdev->config.rv770.max_threads * 1)/8)); + if (((rdev->config.rv770.max_threads * 1) / 8) > rdev->config.rv770.max_gs_threads) + sq_thread_resource_mgmt |= NUM_GS_THREADS(rdev->config.rv770.max_gs_threads); + else + sq_thread_resource_mgmt |= NUM_GS_THREADS((rdev->config.rv770.max_gs_threads * 1)/8); + WREG32(SQ_THREAD_RESOURCE_MGMT, sq_thread_resource_mgmt); + + WREG32(SQ_STACK_RESOURCE_MGMT_1, (NUM_PS_STACK_ENTRIES((rdev->config.rv770.max_stack_entries * 1)/4) | + NUM_VS_STACK_ENTRIES((rdev->config.rv770.max_stack_entries * 1)/4))); + + WREG32(SQ_STACK_RESOURCE_MGMT_2, (NUM_GS_STACK_ENTRIES((rdev->config.rv770.max_stack_entries * 1)/4) | + NUM_ES_STACK_ENTRIES((rdev->config.rv770.max_stack_entries * 1)/4))); + + sq_dyn_gpr_size_simd_ab_0 = (SIMDA_RING0((rdev->config.rv770.max_gprs * 38)/64) | + SIMDA_RING1((rdev->config.rv770.max_gprs * 38)/64) | + SIMDB_RING0((rdev->config.rv770.max_gprs * 38)/64) | + SIMDB_RING1((rdev->config.rv770.max_gprs * 38)/64)); + + WREG32(SQ_DYN_GPR_SIZE_SIMD_AB_0, sq_dyn_gpr_size_simd_ab_0); + WREG32(SQ_DYN_GPR_SIZE_SIMD_AB_1, sq_dyn_gpr_size_simd_ab_0); + WREG32(SQ_DYN_GPR_SIZE_SIMD_AB_2, sq_dyn_gpr_size_simd_ab_0); + WREG32(SQ_DYN_GPR_SIZE_SIMD_AB_3, sq_dyn_gpr_size_simd_ab_0); + WREG32(SQ_DYN_GPR_SIZE_SIMD_AB_4, sq_dyn_gpr_size_simd_ab_0); + WREG32(SQ_DYN_GPR_SIZE_SIMD_AB_5, sq_dyn_gpr_size_simd_ab_0); + WREG32(SQ_DYN_GPR_SIZE_SIMD_AB_6, sq_dyn_gpr_size_simd_ab_0); + WREG32(SQ_DYN_GPR_SIZE_SIMD_AB_7, sq_dyn_gpr_size_simd_ab_0); + + WREG32(PA_SC_FORCE_EOV_MAX_CNTS, (FORCE_EOV_MAX_CLK_CNT(4095) | + FORCE_EOV_MAX_REZ_CNT(255))); + + if (rdev->family == CHIP_RV710) + WREG32(VGT_CACHE_INVALIDATION, (CACHE_INVALIDATION(TC_ONLY) | + AUTO_INVLD_EN(ES_AND_GS_AUTO))); + else + WREG32(VGT_CACHE_INVALIDATION, (CACHE_INVALIDATION(VC_AND_TC) | + AUTO_INVLD_EN(ES_AND_GS_AUTO))); + + switch (rdev->family) { + case CHIP_RV770: + case CHIP_RV730: + case CHIP_RV740: + gs_prim_buffer_depth = 384; + break; + case CHIP_RV710: + gs_prim_buffer_depth = 128; + break; + default: + break; + } + + num_gs_verts_per_thread = rdev->config.rv770.max_pipes * 16; + vgt_gs_per_es = gs_prim_buffer_depth + num_gs_verts_per_thread; + /* Max value for this is 256 */ + if (vgt_gs_per_es > 256) + vgt_gs_per_es = 256; + + WREG32(VGT_ES_PER_GS, 128); + WREG32(VGT_GS_PER_ES, vgt_gs_per_es); + WREG32(VGT_GS_PER_VS, 2); + + /* more default values. 2D/3D driver should adjust as needed */ + WREG32(VGT_GS_VERTEX_REUSE, 16); + WREG32(PA_SC_LINE_STIPPLE_STATE, 0); + WREG32(VGT_STRMOUT_EN, 0); + WREG32(SX_MISC, 0); + WREG32(PA_SC_MODE_CNTL, 0); + WREG32(PA_SC_EDGERULE, 0xaaaaaaaa); + WREG32(PA_SC_AA_CONFIG, 0); + WREG32(PA_SC_CLIPRECT_RULE, 0xffff); + WREG32(PA_SC_LINE_STIPPLE, 0); + WREG32(SPI_INPUT_Z, 0); + WREG32(SPI_PS_IN_CONTROL_0, NUM_INTERP(2)); + WREG32(CB_COLOR7_FRAG, 0); + + /* clear render buffer base addresses */ + WREG32(CB_COLOR0_BASE, 0); + WREG32(CB_COLOR1_BASE, 0); + WREG32(CB_COLOR2_BASE, 0); + WREG32(CB_COLOR3_BASE, 0); + WREG32(CB_COLOR4_BASE, 0); + WREG32(CB_COLOR5_BASE, 0); + WREG32(CB_COLOR6_BASE, 0); + WREG32(CB_COLOR7_BASE, 0); + + WREG32(TCP_CNTL, 0); + + hdp_host_path_cntl = RREG32(HDP_HOST_PATH_CNTL); + WREG32(HDP_HOST_PATH_CNTL, hdp_host_path_cntl); + + WREG32(PA_SC_MULTI_CHIP_CNTL, 0); + + WREG32(PA_CL_ENHANCE, (CLIP_VTX_REORDER_ENA | + NUM_CLIP_SEQ(3))); + +} + +int rv770_mc_init(struct radeon_device *rdev) +{ + fixed20_12 a; + u32 tmp; + int r; + + /* Get VRAM informations */ + /* FIXME: Don't know how to determine vram width, need to check + * vram_width usage + */ + rdev->mc.vram_width = 128; + rdev->mc.vram_is_ddr = true; /* Could aper size report 0 ? */ rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); + /* Setup GPU memory space */ + rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE); + rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE); + if (rdev->flags & RADEON_IS_AGP) { + r = radeon_agp_init(rdev); + if (r) + return r; + /* gtt_size is setup by radeon_agp_init */ + rdev->mc.gtt_location = rdev->mc.agp_base; + tmp = 0xFFFFFFFFUL - rdev->mc.agp_base - rdev->mc.gtt_size; + /* Try to put vram before or after AGP because we + * we want SYSTEM_APERTURE to cover both VRAM and + * AGP so that GPU can catch out of VRAM/AGP access + */ + if (rdev->mc.gtt_location > rdev->mc.mc_vram_size) { + /* Enought place before */ + rdev->mc.vram_location = rdev->mc.gtt_location - + rdev->mc.mc_vram_size; + } else if (tmp > rdev->mc.mc_vram_size) { + /* Enought place after */ + rdev->mc.vram_location = rdev->mc.gtt_location + + rdev->mc.gtt_size; + } else { + /* Try to setup VRAM then AGP might not + * not work on some card + */ + rdev->mc.vram_location = 0x00000000UL; + rdev->mc.gtt_location = rdev->mc.mc_vram_size; + } + } else { + rdev->mc.vram_location = 0x00000000UL; + rdev->mc.gtt_location = rdev->mc.mc_vram_size; + rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + } + rdev->mc.vram_start = rdev->mc.vram_location; + rdev->mc.vram_end = rdev->mc.vram_location + rdev->mc.mc_vram_size; + rdev->mc.gtt_start = rdev->mc.gtt_location; + rdev->mc.gtt_end = rdev->mc.gtt_location + rdev->mc.gtt_size; + /* FIXME: we should enforce default clock in case GPU is not in + * default setup + */ + a.full = rfixed_const(100); + rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk); + rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); + return 0; +} +int rv770_gpu_reset(struct radeon_device *rdev) +{ + /* FIXME: implement */ + return 0; +} + +int rv770_resume(struct radeon_device *rdev) +{ + int r; + + rv770_mc_resume(rdev); + r = rv770_pcie_gart_enable(rdev); + if (r) + return r; + rv770_gpu_init(rdev); + r = radeon_ring_init(rdev, rdev->cp.ring_size); + if (r) + return r; + r = rv770_cp_load_microcode(rdev); + if (r) + return r; + r = r600_cp_resume(rdev); + if (r) + return r; + r = r600_wb_init(rdev); + if (r) + return r; + return 0; +} + +int rv770_suspend(struct radeon_device *rdev) +{ + /* FIXME: we should wait for ring to be empty */ + r700_cp_stop(rdev); + 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. + */ +int rv770_init(struct radeon_device *rdev) +{ + int r; + + rdev->new_init_path = true; + r = radeon_dummy_page_init(rdev); + if (r) + return r; + /* This don't do much */ + r = radeon_gem_init(rdev); + if (r) + return r; + /* Read BIOS */ + if (!radeon_get_bios(rdev)) { + if (ASIC_IS_AVIVO(rdev)) + return -EINVAL; + } + /* Must be an ATOMBIOS */ + if (!rdev->is_atom_bios) + return -EINVAL; + r = radeon_atombios_init(rdev); + if (r) + return r; + /* Post card if necessary */ + if (!r600_card_posted(rdev) && rdev->bios) { + DRM_INFO("GPU not posted. posting now...\n"); + atom_asic_init(rdev->mode_info.atom_context); + } + /* Initialize scratch registers */ + r600_scratch_init(rdev); + /* Initialize surface registers */ + radeon_surface_init(rdev); + r = radeon_clocks_init(rdev); + if (r) + return r; + /* Fence driver */ + r = radeon_fence_driver_init(rdev); + if (r) + return r; + r = rv770_mc_init(rdev); + if (r) { + if (rdev->flags & RADEON_IS_AGP) { + /* Retry with disabling AGP */ + rv770_fini(rdev); + rdev->flags &= ~RADEON_IS_AGP; + return rv770_init(rdev); + } + return r; + } + /* Memory manager */ + r = radeon_object_init(rdev); + if (r) + return r; + rdev->cp.ring_obj = NULL; + r600_ring_init(rdev, 1024 * 1024); + + if (!rdev->me_fw || !rdev->pfp_fw) { + r = r600_cp_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + + r = rv770_resume(rdev); + if (r) { + if (rdev->flags & RADEON_IS_AGP) { + /* Retry with disabling AGP */ + rv770_fini(rdev); + rdev->flags &= ~RADEON_IS_AGP; + return rv770_init(rdev); + } + return r; + } + r = r600_blit_init(rdev); + if (r) { + DRM_ERROR("radeon: failled blitter (%d).\n", r); + return r; + } + r = radeon_ib_pool_init(rdev); + if (r) { + DRM_ERROR("radeon: failled initializing IB pool (%d).\n", r); + return r; + } + r = radeon_ib_test(rdev); + if (r) { + DRM_ERROR("radeon: failled testing IB (%d).\n", r); + return r; + } + return 0; +} + +void rv770_fini(struct radeon_device *rdev) +{ + r600_blit_fini(rdev); + radeon_ring_fini(rdev); + rv770_pcie_gart_disable(rdev); + radeon_gart_table_vram_free(rdev); + radeon_gart_fini(rdev); + radeon_gem_fini(rdev); + radeon_fence_driver_fini(rdev); + radeon_clocks_fini(rdev); +#if __OS_HAS_AGP + if (rdev->flags & RADEON_IS_AGP) + radeon_agp_fini(rdev); +#endif + radeon_object_fini(rdev); + if (rdev->is_atom_bios) { + radeon_atombios_fini(rdev); + } else { + radeon_combios_fini(rdev); + } + kfree(rdev->bios); + rdev->bios = NULL; + radeon_dummy_page_fini(rdev); } diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h new file mode 100644 index 000000000000..4b9c3d6396ff --- /dev/null +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -0,0 +1,341 @@ +/* + * Copyright 2009 Advanced Micro Devices, Inc. + * Copyright 2009 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 + * Jerome Glisse + */ +#ifndef RV770_H +#define RV770_H + +#define R7XX_MAX_SH_GPRS 256 +#define R7XX_MAX_TEMP_GPRS 16 +#define R7XX_MAX_SH_THREADS 256 +#define R7XX_MAX_SH_STACK_ENTRIES 4096 +#define R7XX_MAX_BACKENDS 8 +#define R7XX_MAX_BACKENDS_MASK 0xff +#define R7XX_MAX_SIMDS 16 +#define R7XX_MAX_SIMDS_MASK 0xffff +#define R7XX_MAX_PIPES 8 +#define R7XX_MAX_PIPES_MASK 0xff + +/* Registers */ +#define CB_COLOR0_BASE 0x28040 +#define CB_COLOR1_BASE 0x28044 +#define CB_COLOR2_BASE 0x28048 +#define CB_COLOR3_BASE 0x2804C +#define CB_COLOR4_BASE 0x28050 +#define CB_COLOR5_BASE 0x28054 +#define CB_COLOR6_BASE 0x28058 +#define CB_COLOR7_BASE 0x2805C +#define CB_COLOR7_FRAG 0x280FC + +#define CC_GC_SHADER_PIPE_CONFIG 0x8950 +#define CC_RB_BACKEND_DISABLE 0x98F4 +#define BACKEND_DISABLE(x) ((x) << 16) +#define CC_SYS_RB_BACKEND_DISABLE 0x3F88 + +#define CGTS_SYS_TCC_DISABLE 0x3F90 +#define CGTS_TCC_DISABLE 0x9148 +#define CGTS_USER_SYS_TCC_DISABLE 0x3F94 +#define CGTS_USER_TCC_DISABLE 0x914C + +#define CONFIG_MEMSIZE 0x5428 + +#define CP_ME_CNTL 0x86D8 +#define CP_ME_HALT (1<<28) +#define CP_PFP_HALT (1<<26) +#define CP_ME_RAM_DATA 0xC160 +#define CP_ME_RAM_RADDR 0xC158 +#define CP_ME_RAM_WADDR 0xC15C +#define CP_MEQ_THRESHOLDS 0x8764 +#define STQ_SPLIT(x) ((x) << 0) +#define CP_PERFMON_CNTL 0x87FC +#define CP_PFP_UCODE_ADDR 0xC150 +#define CP_PFP_UCODE_DATA 0xC154 +#define CP_QUEUE_THRESHOLDS 0x8760 +#define ROQ_IB1_START(x) ((x) << 0) +#define ROQ_IB2_START(x) ((x) << 8) +#define CP_RB_CNTL 0xC104 +#define RB_BUFSZ(x) ((x)<<0) +#define RB_BLKSZ(x) ((x)<<8) +#define RB_NO_UPDATE (1<<27) +#define RB_RPTR_WR_ENA (1<<31) +#define BUF_SWAP_32BIT (2 << 16) +#define CP_RB_RPTR 0x8700 +#define CP_RB_RPTR_ADDR 0xC10C +#define CP_RB_RPTR_ADDR_HI 0xC110 +#define CP_RB_RPTR_WR 0xC108 +#define CP_RB_WPTR 0xC114 +#define CP_RB_WPTR_ADDR 0xC118 +#define CP_RB_WPTR_ADDR_HI 0xC11C +#define CP_RB_WPTR_DELAY 0x8704 +#define CP_SEM_WAIT_TIMER 0x85BC + +#define DB_DEBUG3 0x98B0 +#define DB_CLK_OFF_DELAY(x) ((x) << 11) +#define DB_DEBUG4 0x9B8C +#define DISABLE_TILE_COVERED_FOR_PS_ITER (1 << 6) + +#define DCP_TILING_CONFIG 0x6CA0 +#define PIPE_TILING(x) ((x) << 1) +#define BANK_TILING(x) ((x) << 4) +#define GROUP_SIZE(x) ((x) << 6) +#define ROW_TILING(x) ((x) << 8) +#define BANK_SWAPS(x) ((x) << 11) +#define SAMPLE_SPLIT(x) ((x) << 14) +#define BACKEND_MAP(x) ((x) << 16) + +#define GB_TILING_CONFIG 0x98F0 + +#define GC_USER_SHADER_PIPE_CONFIG 0x8954 +#define INACTIVE_QD_PIPES(x) ((x) << 8) +#define INACTIVE_QD_PIPES_MASK 0x0000FF00 +#define INACTIVE_SIMDS(x) ((x) << 16) +#define INACTIVE_SIMDS_MASK 0x00FF0000 + +#define GRBM_CNTL 0x8000 +#define GRBM_READ_TIMEOUT(x) ((x) << 0) +#define GRBM_SOFT_RESET 0x8020 +#define SOFT_RESET_CP (1<<0) +#define GRBM_STATUS 0x8010 +#define CMDFIFO_AVAIL_MASK 0x0000000F +#define GUI_ACTIVE (1<<31) +#define GRBM_STATUS2 0x8014 + +#define HDP_HOST_PATH_CNTL 0x2C00 +#define HDP_NONSURFACE_BASE 0x2C04 +#define HDP_NONSURFACE_INFO 0x2C08 +#define HDP_NONSURFACE_SIZE 0x2C0C +#define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0 +#define HDP_TILING_CONFIG 0x2F3C + +#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 BURSTLENGTH_SHIFT 9 +#define BURSTLENGTH_MASK 0x00000200 +#define MC_VM_AGP_TOP 0x2028 +#define MC_VM_AGP_BOT 0x202C +#define MC_VM_AGP_BASE 0x2030 +#define MC_VM_FB_LOCATION 0x2024 +#define MC_VM_MB_L1_TLB0_CNTL 0x2234 +#define MC_VM_MB_L1_TLB1_CNTL 0x2238 +#define MC_VM_MB_L1_TLB2_CNTL 0x223C +#define MC_VM_MB_L1_TLB3_CNTL 0x2240 +#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 EFFECTIVE_L1_TLB_SIZE(x) ((x)<<15) +#define EFFECTIVE_L1_QUEUE_SIZE(x) ((x)<<18) +#define MC_VM_MD_L1_TLB0_CNTL 0x2654 +#define MC_VM_MD_L1_TLB1_CNTL 0x2658 +#define MC_VM_MD_L1_TLB2_CNTL 0x265C +#define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x203C +#define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2038 +#define MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2034 + +#define PA_CL_ENHANCE 0x8A14 +#define CLIP_VTX_REORDER_ENA (1 << 0) +#define NUM_CLIP_SEQ(x) ((x) << 1) +#define PA_SC_AA_CONFIG 0x28C04 +#define PA_SC_CLIPRECT_RULE 0x2820C +#define PA_SC_EDGERULE 0x28230 +#define PA_SC_FIFO_SIZE 0x8BCC +#define SC_PRIM_FIFO_SIZE(x) ((x) << 0) +#define SC_HIZ_TILE_FIFO_SIZE(x) ((x) << 12) +#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_LINE_STIPPLE 0x28A0C +#define PA_SC_LINE_STIPPLE_STATE 0x8B10 +#define PA_SC_MODE_CNTL 0x28A4C +#define PA_SC_MULTI_CHIP_CNTL 0x8B20 +#define SC_EARLYZ_TILE_FIFO_SIZE(x) ((x) << 20) + +#define SCRATCH_REG0 0x8500 +#define SCRATCH_REG1 0x8504 +#define SCRATCH_REG2 0x8508 +#define SCRATCH_REG3 0x850C +#define SCRATCH_REG4 0x8510 +#define SCRATCH_REG5 0x8514 +#define SCRATCH_REG6 0x8518 +#define SCRATCH_REG7 0x851C +#define SCRATCH_UMSK 0x8540 +#define SCRATCH_ADDR 0x8544 + +#define SMX_DC_CTL0 0xA020 +#define USE_HASH_FUNCTION (1 << 0) +#define CACHE_DEPTH(x) ((x) << 1) +#define FLUSH_ALL_ON_EVENT (1 << 10) +#define STALL_ON_EVENT (1 << 11) +#define SMX_EVENT_CTL 0xA02C +#define ES_FLUSH_CTL(x) ((x) << 0) +#define GS_FLUSH_CTL(x) ((x) << 3) +#define ACK_FLUSH_CTL(x) ((x) << 6) +#define SYNC_FLUSH_CTL (1 << 8) + +#define SPI_CONFIG_CNTL 0x9100 +#define GPR_WRITE_PRIORITY(x) ((x) << 0) +#define DISABLE_INTERP_1 (1 << 5) +#define SPI_CONFIG_CNTL_1 0x913C +#define VTX_DONE_DELAY(x) ((x) << 0) +#define INTERP_ONE_PRIM_PER_ROW (1 << 4) +#define SPI_INPUT_Z 0x286D8 +#define SPI_PS_IN_CONTROL_0 0x286CC +#define NUM_INTERP(x) ((x)<<0) +#define POSITION_ENA (1<<8) +#define POSITION_CENTROID (1<<9) +#define POSITION_ADDR(x) ((x)<<10) +#define PARAM_GEN(x) ((x)<<15) +#define PARAM_GEN_ADDR(x) ((x)<<19) +#define BARYC_SAMPLE_CNTL(x) ((x)<<26) +#define PERSP_GRADIENT_ENA (1<<28) +#define LINEAR_GRADIENT_ENA (1<<29) +#define POSITION_SAMPLE (1<<30) +#define BARYC_AT_SAMPLE_ENA (1<<31) + +#define SQ_CONFIG 0x8C00 +#define VC_ENABLE (1 << 0) +#define EXPORT_SRC_C (1 << 1) +#define DX9_CONSTS (1 << 2) +#define ALU_INST_PREFER_VECTOR (1 << 3) +#define DX10_CLAMP (1 << 4) +#define CLAUSE_SEQ_PRIO(x) ((x) << 8) +#define PS_PRIO(x) ((x) << 24) +#define VS_PRIO(x) ((x) << 26) +#define GS_PRIO(x) ((x) << 28) +#define SQ_DYN_GPR_SIZE_SIMD_AB_0 0x8DB0 +#define SIMDA_RING0(x) ((x)<<0) +#define SIMDA_RING1(x) ((x)<<8) +#define SIMDB_RING0(x) ((x)<<16) +#define SIMDB_RING1(x) ((x)<<24) +#define SQ_DYN_GPR_SIZE_SIMD_AB_1 0x8DB4 +#define SQ_DYN_GPR_SIZE_SIMD_AB_2 0x8DB8 +#define SQ_DYN_GPR_SIZE_SIMD_AB_3 0x8DBC +#define SQ_DYN_GPR_SIZE_SIMD_AB_4 0x8DC0 +#define SQ_DYN_GPR_SIZE_SIMD_AB_5 0x8DC4 +#define SQ_DYN_GPR_SIZE_SIMD_AB_6 0x8DC8 +#define SQ_DYN_GPR_SIZE_SIMD_AB_7 0x8DCC +#define ES_PRIO(x) ((x) << 30) +#define SQ_GPR_RESOURCE_MGMT_1 0x8C04 +#define NUM_PS_GPRS(x) ((x) << 0) +#define NUM_VS_GPRS(x) ((x) << 16) +#define DYN_GPR_ENABLE (1 << 27) +#define NUM_CLAUSE_TEMP_GPRS(x) ((x) << 28) +#define SQ_GPR_RESOURCE_MGMT_2 0x8C08 +#define NUM_GS_GPRS(x) ((x) << 0) +#define NUM_ES_GPRS(x) ((x) << 16) +#define SQ_MS_FIFO_SIZES 0x8CF0 +#define CACHE_FIFO_SIZE(x) ((x) << 0) +#define FETCH_FIFO_HIWATER(x) ((x) << 8) +#define DONE_FIFO_HIWATER(x) ((x) << 16) +#define ALU_UPDATE_FIFO_HIWATER(x) ((x) << 24) +#define SQ_STACK_RESOURCE_MGMT_1 0x8C10 +#define NUM_PS_STACK_ENTRIES(x) ((x) << 0) +#define NUM_VS_STACK_ENTRIES(x) ((x) << 16) +#define SQ_STACK_RESOURCE_MGMT_2 0x8C14 +#define NUM_GS_STACK_ENTRIES(x) ((x) << 0) +#define NUM_ES_STACK_ENTRIES(x) ((x) << 16) +#define SQ_THREAD_RESOURCE_MGMT 0x8C0C +#define NUM_PS_THREADS(x) ((x) << 0) +#define NUM_VS_THREADS(x) ((x) << 8) +#define NUM_GS_THREADS(x) ((x) << 16) +#define NUM_ES_THREADS(x) ((x) << 24) + +#define SX_DEBUG_1 0x9058 +#define ENABLE_NEW_SMX_ADDRESS (1 << 16) +#define SX_EXPORT_BUFFER_SIZES 0x900C +#define COLOR_BUFFER_SIZE(x) ((x) << 0) +#define POSITION_BUFFER_SIZE(x) ((x) << 8) +#define SMX_BUFFER_SIZE(x) ((x) << 16) +#define SX_MISC 0x28350 + +#define TA_CNTL_AUX 0x9508 +#define DISABLE_CUBE_WRAP (1 << 0) +#define DISABLE_CUBE_ANISO (1 << 1) +#define SYNC_GRADIENT (1 << 24) +#define SYNC_WALKER (1 << 25) +#define SYNC_ALIGNER (1 << 26) +#define BILINEAR_PRECISION_6_BIT (0 << 31) +#define BILINEAR_PRECISION_8_BIT (1 << 31) + +#define TCP_CNTL 0x9610 + +#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_ES_PER_GS 0x88CC +#define VGT_GS_PER_ES 0x88C8 +#define VGT_GS_PER_VS 0x88E8 +#define VGT_GS_VERTEX_REUSE 0x88D4 +#define VGT_NUM_INSTANCES 0x8974 +#define VGT_OUT_DEALLOC_CNTL 0x28C5C +#define DEALLOC_DIST_MASK 0x0000007F +#define VGT_STRMOUT_EN 0x28AB0 +#define VGT_VERTEX_REUSE_BLOCK_CNTL 0x28C58 +#define VTX_REUSE_DEPTH_MASK 0x000000FF + +#define VM_CONTEXT0_CNTL 0x1410 +#define ENABLE_CONTEXT (1 << 0) +#define PAGE_TABLE_DEPTH(x) (((x) & 3) << 1) +#define RANGE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 4) +#define VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 0x153C +#define VM_CONTEXT0_PAGE_TABLE_END_ADDR 0x157C +#define VM_CONTEXT0_PAGE_TABLE_START_ADDR 0x155C +#define VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR 0x1518 +#define VM_L2_CNTL 0x1400 +#define ENABLE_L2_CACHE (1 << 0) +#define ENABLE_L2_FRAGMENT_PROCESSING (1 << 1) +#define ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE (1 << 9) +#define EFFECTIVE_L2_QUEUE_SIZE(x) (((x) & 7) << 14) +#define VM_L2_CNTL2 0x1404 +#define INVALIDATE_ALL_L1_TLBS (1 << 0) +#define INVALIDATE_L2_CACHE (1 << 1) +#define VM_L2_CNTL3 0x1408 +#define BANK_SELECT(x) ((x) << 0) +#define CACHE_UPDATE_MODE(x) ((x) << 6) +#define VM_L2_STATUS 0x140C +#define L2_BUSY (1 << 0) + +#define WAIT_UNTIL 0x8040 + +#endif -- cgit v1.2.3-59-g8ed1b From 21f9a437222e92adb3abc68584a5f04801b92739 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 11 Sep 2009 15:55:33 +0200 Subject: drm/radeon/kms: cleanup - remove radeon_share.h radeon_share.h was begining to give problem with include order in respect of radeon.h. It's easier and also i think cleaner to move what was in radeon_share.h into radeon.h. At the same time use the extern keyword for function shared accross the module. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r300.c | 1 - drivers/gpu/drm/radeon/r520.c | 1 - drivers/gpu/drm/radeon/r600.c | 1 - drivers/gpu/drm/radeon/r600_cs.c | 1 - drivers/gpu/drm/radeon/radeon.h | 93 ++++++++++++++++++++++++--- drivers/gpu/drm/radeon/radeon_share.h | 116 ---------------------------------- drivers/gpu/drm/radeon/rs400.c | 1 - drivers/gpu/drm/radeon/rv515.c | 1 - drivers/gpu/drm/radeon/rv770.c | 1 - 9 files changed, 84 insertions(+), 132 deletions(-) delete mode 100644 drivers/gpu/drm/radeon/radeon_share.h (limited to 'drivers/gpu/drm/radeon/rv515.c') diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 92f9cb74a7d2..ced3322bd5fb 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -31,7 +31,6 @@ #include "radeon_reg.h" #include "radeon.h" #include "radeon_drm.h" -#include "radeon_share.h" #include "r100_track.h" #include "r300d.h" diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index ebd6b0f7bdff..0e1686d1c873 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -28,7 +28,6 @@ #include "drmP.h" #include "radeon_reg.h" #include "radeon.h" -#include "radeon_share.h" /* r520,rv530,rv560,rv570,r580 depends on : */ void r100_hdp_reset(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index d8fcef44a69f..1bc25678986b 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -32,7 +32,6 @@ #include "radeon_drm.h" #include "radeon.h" #include "radeon_mode.h" -#include "radeon_share.h" #include "r600d.h" #include "avivod.h" #include "atom.h" diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 39bf6349351b..33b89cd8743e 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -27,7 +27,6 @@ */ #include "drmP.h" #include "radeon.h" -#include "radeon_share.h" #include "r600d.h" #include "avivod.h" diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index e314756dacc3..8cec5bf2922b 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -50,7 +50,6 @@ #include #include "radeon_mode.h" -#include "radeon_share.h" #include "radeon_reg.h" /* @@ -640,11 +639,55 @@ struct radeon_asic { void (*bandwidth_update)(struct radeon_device *rdev); }; +/* + * Asic structures + */ struct r100_asic { const unsigned *reg_safe_bm; unsigned reg_safe_bm_size; }; +struct r300_asic { + const unsigned *reg_safe_bm; + unsigned reg_safe_bm_size; +}; + +struct r600_asic { + unsigned max_pipes; + unsigned max_tile_pipes; + unsigned max_simds; + unsigned max_backends; + unsigned max_gprs; + unsigned max_threads; + unsigned max_stack_entries; + unsigned max_hw_contexts; + unsigned max_gs_threads; + unsigned sx_max_export_size; + unsigned sx_max_export_pos_size; + unsigned sx_max_export_smx_size; + unsigned sq_num_cf_insts; +}; + +struct rv770_asic { + unsigned max_pipes; + unsigned max_tile_pipes; + unsigned max_simds; + unsigned max_backends; + unsigned max_gprs; + unsigned max_threads; + unsigned max_stack_entries; + unsigned max_hw_contexts; + unsigned max_gs_threads; + unsigned sx_max_export_size; + unsigned sx_max_export_pos_size; + unsigned sx_max_export_smx_size; + unsigned sq_num_cf_insts; + unsigned sx_num_of_sets; + unsigned sc_prim_fifo_size; + unsigned sc_hiz_tile_fifo_size; + unsigned sc_earlyz_tile_fifo_fize; +}; + union radeon_asic_config { struct r300_asic r300; struct r100_asic r100; @@ -935,9 +978,14 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_bandwidth_update(rdev) (rdev)->asic->bandwidth_update((rdev)) /* Common functions */ -int radeon_modeset_init(struct radeon_device *rdev); -void radeon_modeset_fini(struct radeon_device *rdev); +extern int radeon_modeset_init(struct radeon_device *rdev); +extern void radeon_modeset_fini(struct radeon_device *rdev); extern bool radeon_card_posted(struct radeon_device *rdev); +extern int radeon_clocks_init(struct radeon_device *rdev); +extern void radeon_clocks_fini(struct radeon_device *rdev); +extern void radeon_scratch_init(struct radeon_device *rdev); +extern void radeon_surface_init(struct radeon_device *rdev); +extern int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data); /* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ struct r100_mc_save { @@ -951,10 +999,10 @@ struct r100_mc_save { extern void r100_cp_disable(struct radeon_device *rdev); extern int r100_cp_init(struct radeon_device *rdev, unsigned ring_size); extern void r100_cp_fini(struct radeon_device *rdev); -void r100_pci_gart_tlb_flush(struct radeon_device *rdev); -int r100_pci_gart_enable(struct radeon_device *rdev); -void r100_pci_gart_disable(struct radeon_device *rdev); -int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); +extern void r100_pci_gart_tlb_flush(struct radeon_device *rdev); +extern int r100_pci_gart_enable(struct radeon_device *rdev); +extern void r100_pci_gart_disable(struct radeon_device *rdev); +extern int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); extern int r100_debugfs_mc_info_init(struct radeon_device *rdev); extern int r100_gui_wait_for_idle(struct radeon_device *rdev); extern void r100_ib_fini(struct radeon_device *rdev); @@ -963,6 +1011,7 @@ extern void r100_irq_disable(struct radeon_device *rdev); extern int r100_irq_set(struct radeon_device *rdev); extern void r100_mc_stop(struct radeon_device *rdev, struct r100_mc_save *save); extern void r100_mc_resume(struct radeon_device *rdev, struct r100_mc_save *save); +extern void r100_vram_init_sizes(struct radeon_device *rdev); extern void r100_wb_disable(struct radeon_device *rdev); extern void r100_wb_fini(struct radeon_device *rdev); extern int r100_wb_init(struct radeon_device *rdev); @@ -974,8 +1023,34 @@ extern void r300_vram_info(struct radeon_device *rdev); extern void rv370_pcie_gart_disable(struct radeon_device *rdev); /* r420,r423,rv410 */ -u32 r420_mc_rreg(struct radeon_device *rdev, u32 reg); -void r420_mc_wreg(struct radeon_device *rdev, u32 reg, u32 v); +extern u32 r420_mc_rreg(struct radeon_device *rdev, u32 reg); +extern void r420_mc_wreg(struct radeon_device *rdev, u32 reg, u32 v); extern int r420_debugfs_pipes_info_init(struct radeon_device *rdev); +/* rv515 */ +extern void rv515_bandwidth_avivo_update(struct radeon_device *rdev); + +/* rs690, rs740 */ +extern void rs690_line_buffer_adjust(struct radeon_device *rdev, + struct drm_display_mode *mode1, + struct drm_display_mode *mode2); + +/* r600, rv610, rv630, rv620, rv635, rv670, rs780, rs880 */ +extern bool r600_card_posted(struct radeon_device *rdev); +extern void r600_cp_stop(struct radeon_device *rdev); +extern void r600_ring_init(struct radeon_device *rdev, unsigned ring_size); +extern int r600_cp_resume(struct radeon_device *rdev); +extern int r600_count_pipe_bits(uint32_t val); +extern int r600_gart_clear_page(struct radeon_device *rdev, int i); +extern int r600_mc_wait_for_idle(struct radeon_device *rdev); +extern void r600_pcie_gart_tlb_flush(struct radeon_device *rdev); +extern int r600_ib_test(struct radeon_device *rdev); +extern int r600_ring_test(struct radeon_device *rdev); +extern int r600_wb_init(struct radeon_device *rdev); +extern void r600_wb_fini(struct radeon_device *rdev); +extern void r600_scratch_init(struct radeon_device *rdev); +extern int r600_blit_init(struct radeon_device *rdev); +extern void r600_blit_fini(struct radeon_device *rdev); +extern int r600_cp_init_microcode(struct radeon_device *rdev); + #endif diff --git a/drivers/gpu/drm/radeon/radeon_share.h b/drivers/gpu/drm/radeon/radeon_share.h deleted file mode 100644 index 5f9e358ab506..000000000000 --- a/drivers/gpu/drm/radeon/radeon_share.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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 - */ -#ifndef __RADEON_SHARE_H__ -#define __RADEON_SHARE_H__ - -/* Common */ -struct radeon_device; -struct radeon_cs_parser; -int radeon_clocks_init(struct radeon_device *rdev); -void radeon_clocks_fini(struct radeon_device *rdev); -void radeon_scratch_init(struct radeon_device *rdev); -void radeon_surface_init(struct radeon_device *rdev); -int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data); - - -/* R100, RV100, RS100, RV200, RS200, R200, RV250, RS300, RV280 */ -void r100_vram_init_sizes(struct radeon_device *rdev); - - -/* R300, R350, RV350, RV380 */ -struct r300_asic { - const unsigned *reg_safe_bm; - unsigned reg_safe_bm_size; -}; - - -/* RS690, RS740 */ -void rs690_line_buffer_adjust(struct radeon_device *rdev, - struct drm_display_mode *mode1, - struct drm_display_mode *mode2); - - -/* RV515 */ -void rv515_bandwidth_avivo_update(struct radeon_device *rdev); - - -/* R600, RV610, RV630, RV620, RV635, RV670, RS780, RS880 */ -bool r600_card_posted(struct radeon_device *rdev); -void r600_cp_stop(struct radeon_device *rdev); -void r600_ring_init(struct radeon_device *rdev, unsigned ring_size); -int r600_cp_resume(struct radeon_device *rdev); -int r600_count_pipe_bits(uint32_t val); -int r600_gart_clear_page(struct radeon_device *rdev, int i); -int r600_mc_wait_for_idle(struct radeon_device *rdev); -void r600_pcie_gart_tlb_flush(struct radeon_device *rdev); -int r600_ib_test(struct radeon_device *rdev); -int r600_ring_test(struct radeon_device *rdev); -int r600_wb_init(struct radeon_device *rdev); -void r600_wb_fini(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_cp_init_microcode(struct radeon_device *rdev); -struct r600_asic { - unsigned max_pipes; - unsigned max_tile_pipes; - unsigned max_simds; - unsigned max_backends; - unsigned max_gprs; - unsigned max_threads; - unsigned max_stack_entries; - unsigned max_hw_contexts; - unsigned max_gs_threads; - unsigned sx_max_export_size; - unsigned sx_max_export_pos_size; - unsigned sx_max_export_smx_size; - unsigned sq_num_cf_insts; -}; - -/* RV770, RV7300, RV710 */ -struct rv770_asic { - unsigned max_pipes; - unsigned max_tile_pipes; - unsigned max_simds; - unsigned max_backends; - unsigned max_gprs; - unsigned max_threads; - unsigned max_stack_entries; - unsigned max_hw_contexts; - unsigned max_gs_threads; - unsigned sx_max_export_size; - unsigned sx_max_export_pos_size; - unsigned sx_max_export_smx_size; - unsigned sq_num_cf_insts; - unsigned sx_num_of_sets; - unsigned sc_prim_fifo_size; - unsigned sc_hiz_tile_fifo_size; - unsigned sc_earlyz_tile_fifo_fize; -}; - -#endif diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 8c3ea7e36060..e1e4ce427828 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -29,7 +29,6 @@ #include #include "radeon_reg.h" #include "radeon.h" -#include "radeon_share.h" /* rs400,rs480 depends on : */ void r100_hdp_reset(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 99e397f16384..03d490269ed0 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -29,7 +29,6 @@ #include "drmP.h" #include "rv515d.h" #include "radeon.h" -#include "radeon_share.h" #include "rv515_reg_safe.h" /* rv515 depends on : */ diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 57765f6d5b20..5ba5204091ec 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -29,7 +29,6 @@ #include #include "drmP.h" #include "radeon.h" -#include "radeon_share.h" #include "rv770d.h" #include "avivod.h" #include "atom.h" -- cgit v1.2.3-59-g8ed1b From 4aac047323e3082d0866b8ad3784236632105af4 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 14 Sep 2009 18:29:49 +0200 Subject: drm/radeon/kms: clear confusion in GART init/deinit path GART static one time initialization was mixed up with GART enabling/disabling which could happen several time for instance during suspend/resume cycles. This patch splits all GART handling into 4 differents function. gart_init is for one time initialization, gart_deinit is called upon module unload to free resources allocated by gart_init, gart_enable enable the GART and is intented to be call after first initialization and at each resume cycle or reset cycle. Finaly gart_disable stop the GART and is intended to be call at suspend time or when unloading the module. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 40 ++++++------ drivers/gpu/drm/radeon/r300.c | 108 ++++++++++++++------------------- drivers/gpu/drm/radeon/r420.c | 57 ++++++++++------- drivers/gpu/drm/radeon/r520.c | 5 -- drivers/gpu/drm/radeon/r600.c | 53 +++++++++++----- drivers/gpu/drm/radeon/radeon.h | 11 ++++ drivers/gpu/drm/radeon/radeon_asic.h | 38 +++++++++--- drivers/gpu/drm/radeon/radeon_device.c | 36 +++++++++-- drivers/gpu/drm/radeon/radeon_gart.c | 9 ++- drivers/gpu/drm/radeon/rs400.c | 53 ++++++++++------ drivers/gpu/drm/radeon/rs600.c | 41 +++++++++---- drivers/gpu/drm/radeon/rs690.c | 3 - drivers/gpu/drm/radeon/rv515.c | 5 -- drivers/gpu/drm/radeon/rv770.c | 37 ++++++----- 14 files changed, 306 insertions(+), 190 deletions(-) (limited to 'drivers/gpu/drm/radeon/rv515.c') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 47263d3ede98..fa0fdc1e3457 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -84,23 +84,28 @@ void r100_pci_gart_tlb_flush(struct radeon_device *rdev) * could end up in wrong address. */ } -int r100_pci_gart_enable(struct radeon_device *rdev) +int r100_pci_gart_init(struct radeon_device *rdev) { - uint32_t tmp; int r; + if (rdev->gart.table.ram.ptr) { + WARN(1, "R100 PCI GART already initialized.\n"); + return 0; + } /* Initialize common gart structure */ r = radeon_gart_init(rdev); - if (r) { + if (r) return r; - } - if (rdev->gart.table.ram.ptr == NULL) { - rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; - r = radeon_gart_table_ram_alloc(rdev); - if (r) { - return r; - } - } + rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; + rdev->asic->gart_tlb_flush = &r100_pci_gart_tlb_flush; + rdev->asic->gart_set_page = &r100_pci_gart_set_page; + return radeon_gart_table_ram_alloc(rdev); +} + +int r100_pci_gart_enable(struct radeon_device *rdev) +{ + uint32_t tmp; + /* discard memory request outside of configured range */ tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS; WREG32(RADEON_AIC_CNTL, tmp); @@ -140,13 +145,11 @@ int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) return 0; } -int r100_gart_enable(struct radeon_device *rdev) +void r100_pci_gart_fini(struct radeon_device *rdev) { - if (rdev->flags & RADEON_IS_AGP) { - r100_pci_gart_disable(rdev); - return 0; - } - return r100_pci_gart_enable(rdev); + r100_pci_gart_disable(rdev); + radeon_gart_table_ram_free(rdev); + radeon_gart_fini(rdev); } @@ -273,9 +276,6 @@ int r100_mc_init(struct radeon_device *rdev) void r100_mc_fini(struct radeon_device *rdev) { - r100_pci_gart_disable(rdev); - radeon_gart_table_ram_free(rdev); - radeon_gart_fini(rdev); } diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index ced3322bd5fb..bb151ecdf8fc 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -42,7 +42,6 @@ int r100_cp_reset(struct radeon_device *rdev); int r100_rb2d_reset(struct radeon_device *rdev); int r100_cp_init(struct radeon_device *rdev, unsigned ring_size); int r100_pci_gart_enable(struct radeon_device *rdev); -void r100_pci_gart_disable(struct radeon_device *rdev); void r100_mc_setup(struct radeon_device *rdev); void r100_mc_disable_clients(struct radeon_device *rdev); int r100_gui_wait_for_idle(struct radeon_device *rdev); @@ -86,26 +85,57 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev) mb(); } -int rv370_pcie_gart_enable(struct radeon_device *rdev) +int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) +{ + void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + + if (i < 0 || i > rdev->gart.num_gpu_pages) { + return -EINVAL; + } + addr = (lower_32_bits(addr) >> 8) | + ((upper_32_bits(addr) & 0xff) << 24) | + 0xc; + /* 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) { - uint32_t table_addr; - uint32_t tmp; int r; + if (rdev->gart.table.vram.robj) { + WARN(1, "RV370 PCIE GART already initialized.\n"); + return 0; + } /* Initialize common gart structure */ r = radeon_gart_init(rdev); - if (r) { + if (r) return r; - } r = rv370_debugfs_pcie_gart_info_init(rdev); - if (r) { + if (r) DRM_ERROR("Failed to register debugfs file for PCIE gart !\n"); - } rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; - r = radeon_gart_table_vram_alloc(rdev); - if (r) { - return r; + rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush; + rdev->asic->gart_set_page = &rv370_pcie_gart_set_page; + return radeon_gart_table_vram_alloc(rdev); +} + +int rv370_pcie_gart_enable(struct radeon_device *rdev) +{ + uint32_t table_addr; + uint32_t tmp; + int r; + + if (rdev->gart.table.vram.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; /* discard memory request outside of configured range */ tmp = RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); @@ -145,51 +175,13 @@ void rv370_pcie_gart_disable(struct radeon_device *rdev) } } -int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) -{ - void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; - - if (i < 0 || i > rdev->gart.num_gpu_pages) { - return -EINVAL; - } - addr = (lower_32_bits(addr) >> 8) | - ((upper_32_bits(addr) & 0xff) << 24) | - 0xc; - /* 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 r300_gart_enable(struct radeon_device *rdev) +void rv370_pcie_gart_fini(struct radeon_device *rdev) { -#if __OS_HAS_AGP - if (rdev->flags & RADEON_IS_AGP) { - if (rdev->family > CHIP_RV350) { - rv370_pcie_gart_disable(rdev); - } else { - r100_pci_gart_disable(rdev); - } - return 0; - } -#endif - if (rdev->flags & RADEON_IS_PCIE) { - rdev->asic->gart_disable = &rv370_pcie_gart_disable; - rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush; - rdev->asic->gart_set_page = &rv370_pcie_gart_set_page; - return rv370_pcie_gart_enable(rdev); - } - if (rdev->flags & RADEON_IS_PCI) { - rdev->asic->gart_disable = &r100_pci_gart_disable; - rdev->asic->gart_tlb_flush = &r100_pci_gart_tlb_flush; - rdev->asic->gart_set_page = &r100_pci_gart_set_page; - return r100_pci_gart_enable(rdev); - } - return r100_pci_gart_enable(rdev); + rv370_pcie_gart_disable(rdev); + radeon_gart_table_vram_free(rdev); + radeon_gart_fini(rdev); } - /* * MC */ @@ -237,14 +229,6 @@ int r300_mc_init(struct radeon_device *rdev) void r300_mc_fini(struct radeon_device *rdev) { - if (rdev->flags & RADEON_IS_PCIE) { - rv370_pcie_gart_disable(rdev); - radeon_gart_table_vram_free(rdev); - } else { - r100_pci_gart_disable(rdev); - radeon_gart_table_ram_free(rdev); - } - radeon_gart_fini(rdev); } @@ -1299,8 +1283,6 @@ void r300_mc_program(struct radeon_device *rdev) /* Stops all mc clients */ r100_mc_stop(rdev, &save); - /* Shutdown PCI/PCIE GART */ - radeon_gart_disable(rdev); if (rdev->flags & RADEON_IS_AGP) { WREG32(R_00014C_MC_AGP_LOCATION, S_00014C_MC_AGP_START(rdev->mc.gtt_start >> 16) | diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index e57b9ba4aaf3..33a25a4377b8 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -161,6 +161,11 @@ int r420_resume(struct radeon_device *rdev) { int r; + /* Make sur GART are not working */ + if (rdev->flags & RADEON_IS_PCIE) + rv370_pcie_gart_disable(rdev); + if (rdev->flags & RADEON_IS_PCI) + r100_pci_gart_disable(rdev); /* Resume clock before doing reset */ r420_clock_resume(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ @@ -180,10 +185,15 @@ int r420_resume(struct radeon_device *rdev) r300_mc_program(rdev); /* Initialize GART (initialize after TTM so we can allocate * memory through TTM but finalize after TTM) */ - r = radeon_gart_enable(rdev); - if (r) { - dev_err(rdev->dev, "failled initializing GART (%d).\n", r); - return r; + if (rdev->flags & RADEON_IS_PCIE) { + r = rv370_pcie_gart_enable(rdev); + if (r) + return r; + } + if (rdev->flags & RADEON_IS_PCI) { + r = r100_pci_gart_enable(rdev); + if (r) + return r; } r420_pipes_init(rdev); /* Enable IRQ */ @@ -212,7 +222,10 @@ int r420_suspend(struct radeon_device *rdev) r100_cp_disable(rdev); r100_wb_disable(rdev); r100_irq_disable(rdev); - radeon_gart_disable(rdev); + if (rdev->flags & RADEON_IS_PCIE) + rv370_pcie_gart_disable(rdev); + if (rdev->flags & RADEON_IS_PCI) + r100_pci_gart_disable(rdev); return 0; } @@ -222,14 +235,10 @@ void r420_fini(struct radeon_device *rdev) r100_wb_fini(rdev); r100_ib_fini(rdev); radeon_gem_fini(rdev); - if (rdev->flags & RADEON_IS_PCIE) { - rv370_pcie_gart_disable(rdev); - radeon_gart_table_vram_free(rdev); - } else { - r100_pci_gart_disable(rdev); - radeon_gart_table_ram_free(rdev); - } - radeon_gart_fini(rdev); + if (rdev->flags & RADEON_IS_PCIE) + rv370_pcie_gart_fini(rdev); + if (rdev->flags & RADEON_IS_PCI) + r100_pci_gart_fini(rdev); radeon_agp_fini(rdev); radeon_irq_kms_fini(rdev); radeon_fence_driver_fini(rdev); @@ -309,6 +318,16 @@ int r420_init(struct radeon_device *rdev) if (r) { return r; } + if (rdev->flags & RADEON_IS_PCIE) { + r = rv370_pcie_gart_init(rdev); + if (r) + return r; + } + if (rdev->flags & RADEON_IS_PCI) { + r = r100_pci_gart_init(rdev); + if (r) + return r; + } r300_set_reg_safe(rdev); r = r420_resume(rdev); if (r) { @@ -318,14 +337,10 @@ int r420_init(struct radeon_device *rdev) r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); - if (rdev->flags & RADEON_IS_PCIE) { - rv370_pcie_gart_disable(rdev); - radeon_gart_table_vram_free(rdev); - } else { - r100_pci_gart_disable(rdev); - radeon_gart_table_ram_free(rdev); - } - radeon_gart_fini(rdev); + if (rdev->flags & RADEON_IS_PCIE) + rv370_pcie_gart_fini(rdev); + if (rdev->flags & RADEON_IS_PCI) + r100_pci_gart_fini(rdev); radeon_agp_fini(rdev); radeon_irq_kms_fini(rdev); } diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 0e1686d1c873..d4b0b9d2e39b 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -31,8 +31,6 @@ /* r520,rv530,rv560,rv570,r580 depends on : */ void r100_hdp_reset(struct radeon_device *rdev); -int rv370_pcie_gart_enable(struct radeon_device *rdev); -void rv370_pcie_gart_disable(struct radeon_device *rdev); void r420_pipes_init(struct radeon_device *rdev); void rs600_mc_disable_clients(struct radeon_device *rdev); void rs600_disable_vga(struct radeon_device *rdev); @@ -118,9 +116,6 @@ int r520_mc_init(struct radeon_device *rdev) void r520_mc_fini(struct radeon_device *rdev) { - rv370_pcie_gart_disable(rdev); - radeon_gart_table_vram_free(rdev); - radeon_gart_fini(rdev); } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 1bc25678986b..65699e9f2025 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -113,21 +113,34 @@ void r600_pcie_gart_tlb_flush(struct radeon_device *rdev) } } -int r600_pcie_gart_enable(struct radeon_device *rdev) +int r600_pcie_gart_init(struct radeon_device *rdev) { - u32 tmp; - int r, i; + int r; + if (rdev->gart.table.vram.robj) { + WARN(1, "R600 PCIE GART already initialized.\n"); + return 0; + } /* Initialize common gart structure */ r = radeon_gart_init(rdev); - if (r) { + if (r) return r; - } rdev->gart.table_size = rdev->gart.num_gpu_pages * 8; - r = radeon_gart_table_vram_alloc(rdev); - if (r) { - return r; + return radeon_gart_table_vram_alloc(rdev); +} + +int r600_pcie_gart_enable(struct radeon_device *rdev) +{ + u32 tmp; + int r, i; + + if (rdev->gart.table.vram.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; for (i = 0; i < rdev->gart.num_gpu_pages; i++) r600_gart_clear_page(rdev, i); /* Setup L2 cache */ @@ -175,10 +188,6 @@ void r600_pcie_gart_disable(struct radeon_device *rdev) u32 tmp; int i; - /* Clear ptes*/ - for (i = 0; i < rdev->gart.num_gpu_pages; i++) - r600_gart_clear_page(rdev, i); - r600_pcie_gart_tlb_flush(rdev); /* Disable all tables */ for (i = 0; i < 7; i++) WREG32(VM_CONTEXT0_CNTL + (i * 4), 0); @@ -204,6 +213,17 @@ void r600_pcie_gart_disable(struct radeon_device *rdev) WREG32(MC_VM_L1_TLB_MCB_WR_SYS_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_RD_HDP_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_WR_HDP_CNTL, tmp); + if (rdev->gart.table.vram.robj) { + radeon_object_kunmap(rdev->gart.table.vram.robj); + radeon_object_unpin(rdev->gart.table.vram.robj); + } +} + +void r600_pcie_gart_fini(struct radeon_device *rdev) +{ + r600_pcie_gart_disable(rdev); + radeon_gart_table_vram_free(rdev); + radeon_gart_fini(rdev); } int r600_mc_wait_for_idle(struct radeon_device *rdev) @@ -1472,6 +1492,7 @@ int r600_suspend(struct radeon_device *rdev) { /* FIXME: we should wait for ring to be empty */ r600_cp_stop(rdev); + r600_pcie_gart_disable(rdev); return 0; } @@ -1548,6 +1569,10 @@ int r600_init(struct radeon_device *rdev) } } + r = r600_pcie_gart_init(rdev); + if (r) + return r; + r = r600_resume(rdev); if (r) { if (rdev->flags & RADEON_IS_AGP) { @@ -1583,9 +1608,7 @@ void r600_fini(struct radeon_device *rdev) r600_blit_fini(rdev); radeon_ring_fini(rdev); - r600_pcie_gart_disable(rdev); - radeon_gart_table_vram_free(rdev); - radeon_gart_fini(rdev); + r600_pcie_gart_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); radeon_clocks_fini(rdev); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 8cec5bf2922b..99292be8bc99 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -596,6 +596,8 @@ struct radeon_asic { void (*mc_fini)(struct radeon_device *rdev); int (*wb_init)(struct radeon_device *rdev); void (*wb_fini)(struct radeon_device *rdev); + int (*gart_init)(struct radeon_device *rdev); + void (*gart_fini)(struct radeon_device *rdev); int (*gart_enable)(struct radeon_device *rdev); void (*gart_disable)(struct radeon_device *rdev); void (*gart_tlb_flush)(struct radeon_device *rdev); @@ -950,6 +952,8 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_mc_fini(rdev) (rdev)->asic->mc_fini((rdev)) #define radeon_wb_init(rdev) (rdev)->asic->wb_init((rdev)) #define radeon_wb_fini(rdev) (rdev)->asic->wb_fini((rdev)) +#define radeon_gpu_gart_init(rdev) (rdev)->asic->gart_init((rdev)) +#define radeon_gpu_gart_fini(rdev) (rdev)->asic->gart_fini((rdev)) #define radeon_gart_enable(rdev) (rdev)->asic->gart_enable((rdev)) #define radeon_gart_disable(rdev) (rdev)->asic->gart_disable((rdev)) #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart_tlb_flush((rdev)) @@ -978,6 +982,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_bandwidth_update(rdev) (rdev)->asic->bandwidth_update((rdev)) /* Common functions */ +extern int radeon_gart_table_vram_pin(struct radeon_device *rdev); extern int radeon_modeset_init(struct radeon_device *rdev); extern void radeon_modeset_fini(struct radeon_device *rdev); extern bool radeon_card_posted(struct radeon_device *rdev); @@ -1000,6 +1005,8 @@ extern void r100_cp_disable(struct radeon_device *rdev); extern int r100_cp_init(struct radeon_device *rdev, unsigned ring_size); extern void r100_cp_fini(struct radeon_device *rdev); extern void r100_pci_gart_tlb_flush(struct radeon_device *rdev); +extern int r100_pci_gart_init(struct radeon_device *rdev); +extern void r100_pci_gart_fini(struct radeon_device *rdev); extern int r100_pci_gart_enable(struct radeon_device *rdev); extern void r100_pci_gart_disable(struct radeon_device *rdev); extern int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); @@ -1020,6 +1027,9 @@ extern int r100_wb_init(struct radeon_device *rdev); extern void r300_set_reg_safe(struct radeon_device *rdev); extern void r300_mc_program(struct radeon_device *rdev); extern void r300_vram_info(struct radeon_device *rdev); +extern int rv370_pcie_gart_init(struct radeon_device *rdev); +extern void rv370_pcie_gart_fini(struct radeon_device *rdev); +extern int rv370_pcie_gart_enable(struct radeon_device *rdev); extern void rv370_pcie_gart_disable(struct radeon_device *rdev); /* r420,r423,rv410 */ @@ -1043,6 +1053,7 @@ extern int r600_cp_resume(struct radeon_device *rdev); extern int r600_count_pipe_bits(uint32_t val); extern int r600_gart_clear_page(struct radeon_device *rdev, int i); extern int r600_mc_wait_for_idle(struct radeon_device *rdev); +extern int r600_pcie_gart_init(struct radeon_device *rdev); extern void r600_pcie_gart_tlb_flush(struct radeon_device *rdev); extern int r600_ib_test(struct radeon_device *rdev); extern int r600_ring_test(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 8f27be31e094..5f2a9e6f12c5 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -53,7 +53,9 @@ void r100_mc_fini(struct radeon_device *rdev); u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc); int r100_wb_init(struct radeon_device *rdev); void r100_wb_fini(struct radeon_device *rdev); -int r100_gart_enable(struct radeon_device *rdev); +int r100_pci_gart_init(struct radeon_device *rdev); +void r100_pci_gart_fini(struct radeon_device *rdev); +int r100_pci_gart_enable(struct radeon_device *rdev); void r100_pci_gart_disable(struct radeon_device *rdev); 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); @@ -92,7 +94,9 @@ static struct radeon_asic r100_asic = { .mc_fini = &r100_mc_fini, .wb_init = &r100_wb_init, .wb_fini = &r100_wb_fini, - .gart_enable = &r100_gart_enable, + .gart_init = &r100_pci_gart_init, + .gart_fini = &r100_pci_gart_fini, + .gart_enable = &r100_pci_gart_enable, .gart_disable = &r100_pci_gart_disable, .gart_tlb_flush = &r100_pci_gart_tlb_flush, .gart_set_page = &r100_pci_gart_set_page, @@ -135,7 +139,9 @@ void r300_ring_start(struct radeon_device *rdev); void r300_fence_ring_emit(struct radeon_device *rdev, struct radeon_fence *fence); int r300_cs_parse(struct radeon_cs_parser *p); -int r300_gart_enable(struct radeon_device *rdev); +int rv370_pcie_gart_init(struct radeon_device *rdev); +void rv370_pcie_gart_fini(struct radeon_device *rdev); +int rv370_pcie_gart_enable(struct radeon_device *rdev); void rv370_pcie_gart_disable(struct radeon_device *rdev); void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev); int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); @@ -157,7 +163,9 @@ static struct radeon_asic r300_asic = { .mc_fini = &r300_mc_fini, .wb_init = &r100_wb_init, .wb_fini = &r100_wb_fini, - .gart_enable = &r300_gart_enable, + .gart_init = &r100_pci_gart_init, + .gart_fini = &r100_pci_gart_fini, + .gart_enable = &r100_pci_gart_enable, .gart_disable = &r100_pci_gart_disable, .gart_tlb_flush = &r100_pci_gart_tlb_flush, .gart_set_page = &r100_pci_gart_set_page, @@ -205,8 +213,8 @@ static struct radeon_asic r420_asic = { .mc_fini = NULL, .wb_init = NULL, .wb_fini = NULL, - .gart_enable = &r300_gart_enable, - .gart_disable = &rv370_pcie_gart_disable, + .gart_enable = NULL, + .gart_disable = NULL, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, .cp_init = NULL, @@ -242,6 +250,8 @@ void rs400_errata(struct radeon_device *rdev); void rs400_vram_info(struct radeon_device *rdev); int rs400_mc_init(struct radeon_device *rdev); void rs400_mc_fini(struct radeon_device *rdev); +int rs400_gart_init(struct radeon_device *rdev); +void rs400_gart_fini(struct radeon_device *rdev); int rs400_gart_enable(struct radeon_device *rdev); void rs400_gart_disable(struct radeon_device *rdev); void rs400_gart_tlb_flush(struct radeon_device *rdev); @@ -257,6 +267,8 @@ static struct radeon_asic rs400_asic = { .mc_fini = &rs400_mc_fini, .wb_init = &r100_wb_init, .wb_fini = &r100_wb_fini, + .gart_init = &rs400_gart_init, + .gart_fini = &rs400_gart_fini, .gart_enable = &rs400_gart_enable, .gart_disable = &rs400_gart_disable, .gart_tlb_flush = &rs400_gart_tlb_flush, @@ -298,6 +310,8 @@ void rs600_mc_fini(struct radeon_device *rdev); int rs600_irq_set(struct radeon_device *rdev); int rs600_irq_process(struct radeon_device *rdev); u32 rs600_get_vblank_counter(struct radeon_device *rdev, int crtc); +int rs600_gart_init(struct radeon_device *rdev); +void rs600_gart_fini(struct radeon_device *rdev); int rs600_gart_enable(struct radeon_device *rdev); void rs600_gart_disable(struct radeon_device *rdev); void rs600_gart_tlb_flush(struct radeon_device *rdev); @@ -314,6 +328,8 @@ static struct radeon_asic rs600_asic = { .mc_fini = &rs600_mc_fini, .wb_init = &r100_wb_init, .wb_fini = &r100_wb_fini, + .gart_init = &rs600_gart_init, + .gart_fini = &rs600_gart_fini, .gart_enable = &rs600_gart_enable, .gart_disable = &rs600_gart_disable, .gart_tlb_flush = &rs600_gart_tlb_flush, @@ -361,6 +377,8 @@ static struct radeon_asic rs690_asic = { .mc_fini = &rs690_mc_fini, .wb_init = &r100_wb_init, .wb_fini = &r100_wb_fini, + .gart_init = &rs400_gart_init, + .gart_fini = &rs400_gart_fini, .gart_enable = &rs400_gart_enable, .gart_disable = &rs400_gart_disable, .gart_tlb_flush = &rs400_gart_tlb_flush, @@ -415,7 +433,9 @@ static struct radeon_asic rv515_asic = { .mc_fini = &rv515_mc_fini, .wb_init = &r100_wb_init, .wb_fini = &r100_wb_fini, - .gart_enable = &r300_gart_enable, + .gart_init = &rv370_pcie_gart_init, + .gart_fini = &rv370_pcie_gart_fini, + .gart_enable = &rv370_pcie_gart_enable, .gart_disable = &rv370_pcie_gart_disable, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, @@ -462,7 +482,9 @@ static struct radeon_asic r520_asic = { .mc_fini = &r520_mc_fini, .wb_init = &r100_wb_init, .wb_fini = &r100_wb_fini, - .gart_enable = &r300_gart_enable, + .gart_init = &rv370_pcie_gart_init, + .gart_fini = &rv370_pcie_gart_fini, + .gart_enable = &rv370_pcie_gart_enable, .gart_disable = &rv370_pcie_gart_disable, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index ece097c3e079..7b6d0b1a5962 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -320,6 +320,14 @@ int radeon_asic_init(struct radeon_device *rdev) case CHIP_RV350: case CHIP_RV380: rdev->asic = &r300_asic; + if (rdev->flags & RADEON_IS_PCIE) { + rdev->asic->gart_init = &rv370_pcie_gart_init; + rdev->asic->gart_fini = &rv370_pcie_gart_fini; + rdev->asic->gart_enable = &rv370_pcie_gart_enable; + rdev->asic->gart_disable = &rv370_pcie_gart_disable; + rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush; + rdev->asic->gart_set_page = &rv370_pcie_gart_set_page; + } break; case CHIP_R420: case CHIP_R423: @@ -504,6 +512,12 @@ int radeon_device_init(struct radeon_device *rdev, rwlock_init(&rdev->fence_drv.lock); INIT_LIST_HEAD(&rdev->gem.objects); + /* Set asic functions */ + r = radeon_asic_init(rdev); + if (r) { + return r; + } + if (radeon_agpmode == -1) { rdev->flags &= ~RADEON_IS_AGP; if (rdev->family >= CHIP_RV515 || @@ -512,18 +526,24 @@ int radeon_device_init(struct radeon_device *rdev, rdev->family == CHIP_R423) { DRM_INFO("Forcing AGP to PCIE mode\n"); rdev->flags |= RADEON_IS_PCIE; + rdev->asic->gart_init = &rv370_pcie_gart_init; + rdev->asic->gart_fini = &rv370_pcie_gart_fini; + rdev->asic->gart_enable = &rv370_pcie_gart_enable; + rdev->asic->gart_disable = &rv370_pcie_gart_disable; + rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush; + rdev->asic->gart_set_page = &rv370_pcie_gart_set_page; } else { DRM_INFO("Forcing AGP to PCI mode\n"); rdev->flags |= RADEON_IS_PCI; + rdev->asic->gart_init = &r100_pci_gart_init; + rdev->asic->gart_fini = &r100_pci_gart_fini; + rdev->asic->gart_enable = &r100_pci_gart_enable; + rdev->asic->gart_disable = &r100_pci_gart_disable; + rdev->asic->gart_tlb_flush = &r100_pci_gart_tlb_flush; + rdev->asic->gart_set_page = &r100_pci_gart_set_page; } } - /* Set asic functions */ - r = radeon_asic_init(rdev); - if (r) { - return r; - } - /* set DMA mask + need_dma32 flags. * PCIE - can handle 40-bits. * IGP - can handle 40-bits (in theory) @@ -623,6 +643,9 @@ int radeon_device_init(struct radeon_device *rdev, if (r) { return r; } + r = radeon_gpu_gart_init(rdev); + if (r) + return r; /* Initialize GART (initialize after TTM so we can allocate * memory through TTM but finalize after TTM) */ r = radeon_gart_enable(rdev); @@ -675,6 +698,7 @@ void radeon_device_fini(struct radeon_device *rdev) radeon_ib_pool_fini(rdev); radeon_cp_fini(rdev); radeon_wb_fini(rdev); + radeon_gpu_gart_fini(rdev); radeon_gem_fini(rdev); radeon_mc_fini(rdev); #if __OS_HAS_AGP diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 2977539880fb..a931af065dd4 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -75,7 +75,6 @@ void radeon_gart_table_ram_free(struct radeon_device *rdev) int radeon_gart_table_vram_alloc(struct radeon_device *rdev) { - uint64_t gpu_addr; int r; if (rdev->gart.table.vram.robj == NULL) { @@ -88,6 +87,14 @@ int radeon_gart_table_vram_alloc(struct radeon_device *rdev) return r; } } + return 0; +} + +int radeon_gart_table_vram_pin(struct radeon_device *rdev) +{ + uint64_t gpu_addr; + int r; + r = radeon_object_pin(rdev->gart.table.vram.robj, RADEON_GEM_DOMAIN_VRAM, &gpu_addr); if (r) { diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index e1e4ce427828..a3fbdad938c7 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -92,20 +92,41 @@ void rs400_gart_tlb_flush(struct radeon_device *rdev) WREG32_MC(RS480_GART_CACHE_CNTRL, 0); } -int rs400_gart_enable(struct radeon_device *rdev) +int rs400_gart_init(struct radeon_device *rdev) { - uint32_t size_reg; - uint32_t tmp; int r; + if (rdev->gart.table.ram.ptr) { + WARN(1, "RS400 GART already initialized.\n"); + return 0; + } + /* Check gart size */ + switch(rdev->mc.gtt_size / (1024 * 1024)) { + case 32: + case 64: + case 128: + case 256: + case 512: + case 1024: + case 2048: + break; + default: + return -EINVAL; + } /* Initialize common gart structure */ r = radeon_gart_init(rdev); - if (r) { + if (r) return r; - } - if (rs400_debugfs_pcie_gart_info_init(rdev)) { + if (rs400_debugfs_pcie_gart_info_init(rdev)) DRM_ERROR("Failed to register debugfs file for RS400 GART !\n"); - } + rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; + return radeon_gart_table_ram_alloc(rdev); +} + +int rs400_gart_enable(struct radeon_device *rdev) +{ + uint32_t size_reg; + uint32_t tmp; tmp = RREG32_MC(RS690_AIC_CTRL_SCRATCH); tmp |= RS690_DIS_OUT_OF_PCI_GART_ACCESS; @@ -136,13 +157,6 @@ int rs400_gart_enable(struct radeon_device *rdev) default: return -EINVAL; } - if (rdev->gart.table.ram.ptr == NULL) { - rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; - r = radeon_gart_table_ram_alloc(rdev); - if (r) { - return r; - } - } /* It should be fine to program it to max value */ if (rdev->family == CHIP_RS690 || (rdev->family == CHIP_RS740)) { WREG32_MC(RS690_MCCFG_AGP_BASE, 0xFFFFFFFF); @@ -201,6 +215,13 @@ void rs400_gart_disable(struct radeon_device *rdev) WREG32_MC(RS480_AGP_ADDRESS_SPACE_SIZE, 0); } +void rs400_gart_fini(struct radeon_device *rdev) +{ + rs400_gart_disable(rdev); + radeon_gart_table_ram_free(rdev); + radeon_gart_fini(rdev); +} + int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) { uint32_t entry; @@ -255,14 +276,12 @@ int rs400_mc_init(struct radeon_device *rdev) (void)RREG32(RADEON_HOST_PATH_CNTL); WREG32(RADEON_HOST_PATH_CNTL, tmp); (void)RREG32(RADEON_HOST_PATH_CNTL); + return 0; } void rs400_mc_fini(struct radeon_device *rdev) { - rs400_gart_disable(rdev); - radeon_gart_table_ram_free(rdev); - radeon_gart_fini(rdev); } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 1b8d62f5e73c..c31bd8439259 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -68,22 +68,35 @@ void rs600_gart_tlb_flush(struct radeon_device *rdev) tmp = RREG32_MC(RS600_MC_PT0_CNTL); } -int rs600_gart_enable(struct radeon_device *rdev) +int rs600_gart_init(struct radeon_device *rdev) { - uint32_t tmp; - int i; int r; + if (rdev->gart.table.vram.robj) { + WARN(1, "RS600 GART already initialized.\n"); + return 0; + } /* Initialize common gart structure */ r = radeon_gart_init(rdev); if (r) { return r; } rdev->gart.table_size = rdev->gart.num_gpu_pages * 8; - r = radeon_gart_table_vram_alloc(rdev); - if (r) { - return r; + return radeon_gart_table_vram_alloc(rdev); +} + +int rs600_gart_enable(struct radeon_device *rdev) +{ + uint32_t tmp; + int r, i; + + if (rdev->gart.table.vram.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; /* FIXME: setup default page */ WREG32_MC(RS600_MC_PT0_CNTL, (RS600_EFFECTIVE_L2_CACHE_SIZE(6) | @@ -138,8 +151,17 @@ void rs600_gart_disable(struct radeon_device *rdev) tmp = RREG32_MC(RS600_MC_CNTL1); tmp &= ~RS600_ENABLE_PAGE_TABLES; WREG32_MC(RS600_MC_CNTL1, tmp); - radeon_object_kunmap(rdev->gart.table.vram.robj); - radeon_object_unpin(rdev->gart.table.vram.robj); + if (rdev->gart.table.vram.robj) { + radeon_object_kunmap(rdev->gart.table.vram.robj); + radeon_object_unpin(rdev->gart.table.vram.robj); + } +} + +void rs600_gart_fini(struct radeon_device *rdev) +{ + rs600_gart_disable(rdev); + radeon_gart_table_vram_free(rdev); + radeon_gart_fini(rdev); } #define R600_PTE_VALID (1 << 0) @@ -235,9 +257,6 @@ int rs600_mc_init(struct radeon_device *rdev) void rs600_mc_fini(struct radeon_device *rdev) { - rs600_gart_disable(rdev); - radeon_gart_table_vram_free(rdev); - radeon_gart_fini(rdev); } diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index 839595b00728..0f585ca8276d 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -94,9 +94,6 @@ int rs690_mc_init(struct radeon_device *rdev) void rs690_mc_fini(struct radeon_device *rdev) { - rs400_gart_disable(rdev); - radeon_gart_table_ram_free(rdev); - radeon_gart_fini(rdev); } diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 03d490269ed0..fd799748e7d8 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -37,8 +37,6 @@ int r100_cp_reset(struct radeon_device *rdev); int r100_rb2d_reset(struct radeon_device *rdev); int r100_gui_wait_for_idle(struct radeon_device *rdev); int r100_cp_init(struct radeon_device *rdev, unsigned ring_size); -int rv370_pcie_gart_enable(struct radeon_device *rdev); -void rv370_pcie_gart_disable(struct radeon_device *rdev); void r420_pipes_init(struct radeon_device *rdev); void rs600_mc_disable_clients(struct radeon_device *rdev); void rs600_disable_vga(struct radeon_device *rdev); @@ -126,9 +124,6 @@ int rv515_mc_init(struct radeon_device *rdev) void rv515_mc_fini(struct radeon_device *rdev) { - rv370_pcie_gart_disable(rdev); - radeon_gart_table_vram_free(rdev); - radeon_gart_fini(rdev); } diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 5ba5204091ec..4f2098bc7974 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -48,16 +48,13 @@ int rv770_pcie_gart_enable(struct radeon_device *rdev) u32 tmp; int r, i; - /* Initialize common gart structure */ - r = radeon_gart_init(rdev); - if (r) { - return r; + if (rdev->gart.table.vram.robj == NULL) { + dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); + return -EINVAL; } - rdev->gart.table_size = rdev->gart.num_gpu_pages * 8; - r = radeon_gart_table_vram_alloc(rdev); - if (r) { + r = radeon_gart_table_vram_pin(rdev); + if (r) return r; - } for (i = 0; i < rdev->gart.num_gpu_pages; i++) r600_gart_clear_page(rdev, i); /* Setup L2 cache */ @@ -98,10 +95,6 @@ void rv770_pcie_gart_disable(struct radeon_device *rdev) u32 tmp; int i; - /* Clear ptes*/ - for (i = 0; i < rdev->gart.num_gpu_pages; i++) - r600_gart_clear_page(rdev, i); - r600_pcie_gart_tlb_flush(rdev); /* Disable all tables */ for (i = 0; i < 7; i++) WREG32(VM_CONTEXT0_CNTL + (i * 4), 0); @@ -120,6 +113,17 @@ void rv770_pcie_gart_disable(struct radeon_device *rdev) WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp); + if (rdev->gart.table.vram.robj) { + radeon_object_kunmap(rdev->gart.table.vram.robj); + radeon_object_unpin(rdev->gart.table.vram.robj); + } +} + +void rv770_pcie_gart_fini(struct radeon_device *rdev) +{ + rv770_pcie_gart_disable(rdev); + radeon_gart_table_vram_free(rdev); + radeon_gart_fini(rdev); } @@ -871,6 +875,7 @@ int rv770_suspend(struct radeon_device *rdev) { /* FIXME: we should wait for ring to be empty */ r700_cp_stop(rdev); + rv770_pcie_gart_disable(rdev); return 0; } @@ -944,6 +949,10 @@ int rv770_init(struct radeon_device *rdev) } } + r = r600_pcie_gart_init(rdev); + if (r) + return r; + r = rv770_resume(rdev); if (r) { if (rdev->flags & RADEON_IS_AGP) { @@ -976,9 +985,7 @@ void rv770_fini(struct radeon_device *rdev) { r600_blit_fini(rdev); radeon_ring_fini(rdev); - rv770_pcie_gart_disable(rdev); - radeon_gart_table_vram_free(rdev); - radeon_gart_fini(rdev); + rv770_pcie_gart_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); radeon_clocks_fini(rdev); -- cgit v1.2.3-59-g8ed1b