From e33497aaaef5ec9998cf7b007b13d74bb41be74e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 12 Oct 2009 13:32:38 +1000 Subject: [PATCH 01/46] drm/radeon/kms: don't refuse LUT because no framebuffer. The fb binding might be happening in a subsequent crtc setup call. gets rid of some lut issues. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_display.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 3655d91993a6..b8f234497aca 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -137,9 +137,6 @@ static void radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, if (size != 256) { return; } - if (crtc->fb == NULL) { - return; - } /* userspace palettes are always correct as is */ for (i = 0; i < 256; i++) { @@ -147,7 +144,6 @@ static void radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, radeon_crtc->lut_g[i] = green[i] >> 6; radeon_crtc->lut_b[i] = blue[i] >> 6; } - radeon_crtc_load_lut(crtc); } From f30f37def4c72e5df8d949022b806e5a4e99bbcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 8 Oct 2009 10:44:09 +0200 Subject: [PATCH 02/46] drm/radeon/kms: Update memory bandwidth requirements in mode_set_base hook. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hook may change the number of bytes per pixel being scanned out, which affects the CRTC memory bandwidth requirements. E.g. booting in 8bpp and then running X in 32bpp would result in the bandwidth requirements being underestimated for the latter and consequently in CRTC FIFO underruns causing visible artifacts with 3D intensive workloads. ATOM changes only compile-tested. Signed-off-by: Michel Dänzer Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 5 ++++- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 14fa9701aeb3..38a87cc6eb12 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -563,6 +563,10 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, radeon_fb = to_radeon_framebuffer(old_fb); radeon_gem_object_unpin(radeon_fb->obj); } + + /* Bytes per pixel may have changed */ + radeon_bandwidth_update(rdev); + return 0; } @@ -701,7 +705,6 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, } atombios_overscan_setup(crtc, mode, adjusted_mode); atombios_scaler_setup(crtc); - radeon_bandwidth_update(rdev); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 36410f85d705..ec2df739c119 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -532,6 +532,10 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, radeon_fb = to_radeon_framebuffer(old_fb); radeon_gem_object_unpin(radeon_fb->obj); } + + /* Bytes per pixel may have changed */ + radeon_bandwidth_update(rdev); + return 0; } @@ -1015,14 +1019,11 @@ static int radeon_crtc_mode_set(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - struct drm_device *dev = crtc->dev; - struct radeon_device *rdev = dev->dev_private; /* TODO TV */ radeon_crtc_set_base(crtc, x, y, old_fb); radeon_set_crtc_timing(crtc, adjusted_mode); radeon_set_pll(crtc, adjusted_mode); - radeon_bandwidth_update(rdev); if (radeon_crtc->crtc_id == 0) { radeon_legacy_rmx_mode_set(crtc, mode, adjusted_mode); } else { From b5fc901002db0519093ec723fd98969bc03cd629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 8 Oct 2009 10:44:10 +0200 Subject: [PATCH 03/46] drm/radeon/kms: Fix apparent typo in legacy CRTC memory bandwidth calculation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While investigating the cause of CRTC FIFO underruns, I noticed that when converting the memory bandwidth calculation from the userspace X driver code, an instance of '8.0' was apparently accidentally converted to '80'. Signed-off-by: Michel Dänzer Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 374ecacc6183..33198dd5706c 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2350,7 +2350,7 @@ void r100_bandwidth_update(struct radeon_device *rdev) /* Find the total latency for the display data. */ - disp_latency_overhead.full = rfixed_const(80); + disp_latency_overhead.full = rfixed_const(8); disp_latency_overhead.full = rfixed_div(disp_latency_overhead, sclk_ff); mc_latency_mclk.full += disp_latency_overhead.full + cur_latency_mclk.full; mc_latency_sclk.full += disp_latency_overhead.full + cur_latency_sclk.full; From 2ffb842948ba64b03986f4064140a74c1780c44b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 8 Oct 2009 13:02:19 -0400 Subject: [PATCH 04/46] drm/radeon/kms: make sure LVDS panel is valid in detect() If the panel data is bogus this can lead to problems later when the hardware trys to set the mode. If the data is invalid, report LVDS as disconnected. Should fix fdo bug 24247. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index e376be47a4a0..466f6010a2e4 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -415,8 +415,20 @@ static int radeon_lvds_mode_valid(struct drm_connector *connector, static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector) { - enum drm_connector_status ret = connector_status_connected; + enum drm_connector_status ret = connector_status_disconnected; + struct drm_encoder *encoder = radeon_best_single_encoder(connector); + + if (encoder) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_native_mode *native_mode = &radeon_encoder->native_mode; + + /* check if panel is valid */ + if (native_mode->panel_xres >= 320 && native_mode->panel_yres >= 240) + ret = connector_status_connected; + + } /* check acpi lid status ??? */ + radeon_connector_update_scratch_regs(connector, ret); return ret; } From 5f9a0eb5af16906cd31fc3e02746aa3d61fd3aa9 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 8 Oct 2009 13:08:29 -0400 Subject: [PATCH 05/46] drm/radeon/kms/atom: reorder crtc dpms Based on recommendation from bios docs. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 38a87cc6eb12..0a5082af3cd3 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -248,18 +248,18 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) switch (mode) { case DRM_MODE_DPMS_ON: + atombios_enable_crtc(crtc, 1); if (ASIC_IS_DCE3(rdev)) atombios_enable_crtc_memreq(crtc, 1); - atombios_enable_crtc(crtc, 1); atombios_blank_crtc(crtc, 0); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: atombios_blank_crtc(crtc, 1); - atombios_enable_crtc(crtc, 0); if (ASIC_IS_DCE3(rdev)) atombios_enable_crtc_memreq(crtc, 0); + atombios_enable_crtc(crtc, 0); break; } From 2606c88608122339cbd5c6b5c149a2eb74ccfe9e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 8 Oct 2009 13:36:21 -0400 Subject: [PATCH 06/46] drm/radeon/kms/atom: add support for AdjustDisplayPll DCE3+ has an AdjustDisplayPll that will adjust the pixel clock accordingly based on the encoder/transmitter to handle special hw requirements. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 36 +++++++++++++++++++++----- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 0a5082af3cd3..d5e6f3da116c 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -333,12 +333,13 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) struct drm_encoder *encoder = NULL; struct radeon_encoder *radeon_encoder = NULL; uint8_t frev, crev; - int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); + int index; SET_PIXEL_CLOCK_PS_ALLOCATION args; PIXEL_CLOCK_PARAMETERS *spc1_ptr; PIXEL_CLOCK_PARAMETERS_V2 *spc2_ptr; PIXEL_CLOCK_PARAMETERS_V3 *spc3_ptr; - uint32_t sclock = mode->clock; + uint32_t pll_clock = mode->clock; + uint32_t adjusted_clock; uint32_t ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; struct radeon_pll *pll; int pll_flags = 0; @@ -393,12 +394,34 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) } } + /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock + * accordingly based on the encoder/transmitter to work around + * special hw requirements. + */ + if (ASIC_IS_DCE3(rdev)) { + ADJUST_DISPLAY_PLL_PS_ALLOCATION adjust_pll_args; + + if (!encoder) + return; + + memset(&adjust_pll_args, 0, sizeof(adjust_pll_args)); + adjust_pll_args.usPixelClock = cpu_to_le16(mode->clock / 10); + adjust_pll_args.ucTransmitterID = radeon_encoder->encoder_id; + adjust_pll_args.ucEncodeMode = atombios_get_encoder_mode(encoder); + + index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); + atom_execute_table(rdev->mode_info.atom_context, + index, (uint32_t *)&adjust_pll_args); + adjusted_clock = le16_to_cpu(adjust_pll_args.usPixelClock) * 10; + } else + adjusted_clock = mode->clock; + if (radeon_crtc->crtc_id == 0) pll = &rdev->clock.p1pll; else pll = &rdev->clock.p2pll; - radeon_compute_pll(pll, mode->clock, &sclock, &fb_div, &frac_fb_div, + radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, &ref_div, &post_div, pll_flags); atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, @@ -409,7 +432,7 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) switch (crev) { case 1: spc1_ptr = (PIXEL_CLOCK_PARAMETERS *) & args.sPCLKInput; - spc1_ptr->usPixelClock = cpu_to_le16(sclock); + spc1_ptr->usPixelClock = cpu_to_le16(mode->clock / 10); spc1_ptr->usRefDiv = cpu_to_le16(ref_div); spc1_ptr->usFbDiv = cpu_to_le16(fb_div); spc1_ptr->ucFracFbDiv = frac_fb_div; @@ -422,7 +445,7 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) case 2: spc2_ptr = (PIXEL_CLOCK_PARAMETERS_V2 *) & args.sPCLKInput; - spc2_ptr->usPixelClock = cpu_to_le16(sclock); + spc2_ptr->usPixelClock = cpu_to_le16(mode->clock / 10); spc2_ptr->usRefDiv = cpu_to_le16(ref_div); spc2_ptr->usFbDiv = cpu_to_le16(fb_div); spc2_ptr->ucFracFbDiv = frac_fb_div; @@ -437,7 +460,7 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) return; spc3_ptr = (PIXEL_CLOCK_PARAMETERS_V3 *) & args.sPCLKInput; - spc3_ptr->usPixelClock = cpu_to_le16(sclock); + spc3_ptr->usPixelClock = cpu_to_le16(mode->clock / 10); spc3_ptr->usRefDiv = cpu_to_le16(ref_div); spc3_ptr->usFbDiv = cpu_to_le16(fb_div); spc3_ptr->ucFracFbDiv = frac_fb_div; @@ -460,6 +483,7 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) } printk("executing set pll\n"); + index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } From 5a9bcacc0a56f0d9577494e834519480018a6cc3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 8 Oct 2009 15:09:31 -0400 Subject: [PATCH 07/46] drm/radeon/kms/atom: rework crtc modeset - clean up tv timing handling - unify SetCRTC_Timing and SetCRTC_UsingDTDTiming Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 221 +++++++---------------- drivers/gpu/drm/radeon/radeon_atombios.c | 85 ++++++--- drivers/gpu/drm/radeon/radeon_encoders.c | 18 ++ 3 files changed, 144 insertions(+), 180 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index d5e6f3da116c..7522af1b9e46 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -270,59 +270,89 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) static void atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, - SET_CRTC_USING_DTD_TIMING_PARAMETERS * crtc_param) + struct drm_display_mode *mode) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; - SET_CRTC_USING_DTD_TIMING_PARAMETERS conv_param; + SET_CRTC_USING_DTD_TIMING_PARAMETERS args; int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); + u16 misc = 0; - conv_param.usH_Size = cpu_to_le16(crtc_param->usH_Size); - conv_param.usH_Blanking_Time = - cpu_to_le16(crtc_param->usH_Blanking_Time); - conv_param.usV_Size = cpu_to_le16(crtc_param->usV_Size); - conv_param.usV_Blanking_Time = - cpu_to_le16(crtc_param->usV_Blanking_Time); - conv_param.usH_SyncOffset = cpu_to_le16(crtc_param->usH_SyncOffset); - conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth); - conv_param.usV_SyncOffset = cpu_to_le16(crtc_param->usV_SyncOffset); - conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth); - conv_param.susModeMiscInfo.usAccess = - cpu_to_le16(crtc_param->susModeMiscInfo.usAccess); - conv_param.ucCRTC = crtc_param->ucCRTC; + memset(&args, 0, sizeof(args)); + args.usH_Size = cpu_to_le16(mode->crtc_hdisplay); + args.usH_Blanking_Time = + cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay); + args.usV_Size = cpu_to_le16(mode->crtc_vdisplay); + args.usV_Blanking_Time = + cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay); + args.usH_SyncOffset = + cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay); + args.usH_SyncWidth = + cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); + args.usV_SyncOffset = + cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay); + args.usV_SyncWidth = + cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); + /*args.ucH_Border = mode->hborder;*/ + /*args.ucV_Border = mode->vborder;*/ + + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + misc |= ATOM_VSYNC_POLARITY; + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + misc |= ATOM_HSYNC_POLARITY; + if (mode->flags & DRM_MODE_FLAG_CSYNC) + misc |= ATOM_COMPOSITESYNC; + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + misc |= ATOM_INTERLACE; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + misc |= ATOM_DOUBLE_CLOCK_MODE; + + args.susModeMiscInfo.usAccess = cpu_to_le16(misc); + args.ucCRTC = radeon_crtc->crtc_id; printk("executing set crtc dtd timing\n"); - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&conv_param); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } -void atombios_crtc_set_timing(struct drm_crtc *crtc, - SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION * - crtc_param) +static void atombios_crtc_set_timing(struct drm_crtc *crtc, + struct drm_display_mode *mode) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; - SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION conv_param; + SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); + u16 misc = 0; - conv_param.usH_Total = cpu_to_le16(crtc_param->usH_Total); - conv_param.usH_Disp = cpu_to_le16(crtc_param->usH_Disp); - conv_param.usH_SyncStart = cpu_to_le16(crtc_param->usH_SyncStart); - conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth); - conv_param.usV_Total = cpu_to_le16(crtc_param->usV_Total); - conv_param.usV_Disp = cpu_to_le16(crtc_param->usV_Disp); - conv_param.usV_SyncStart = cpu_to_le16(crtc_param->usV_SyncStart); - conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth); - conv_param.susModeMiscInfo.usAccess = - cpu_to_le16(crtc_param->susModeMiscInfo.usAccess); - conv_param.ucCRTC = crtc_param->ucCRTC; - conv_param.ucOverscanRight = crtc_param->ucOverscanRight; - conv_param.ucOverscanLeft = crtc_param->ucOverscanLeft; - conv_param.ucOverscanBottom = crtc_param->ucOverscanBottom; - conv_param.ucOverscanTop = crtc_param->ucOverscanTop; - conv_param.ucReserved = crtc_param->ucReserved; + memset(&args, 0, sizeof(args)); + args.usH_Total = cpu_to_le16(mode->crtc_htotal); + args.usH_Disp = cpu_to_le16(mode->crtc_hdisplay); + args.usH_SyncStart = cpu_to_le16(mode->crtc_hsync_start); + args.usH_SyncWidth = + cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); + args.usV_Total = cpu_to_le16(mode->crtc_vtotal); + args.usV_Disp = cpu_to_le16(mode->crtc_vdisplay); + args.usV_SyncStart = cpu_to_le16(mode->crtc_vsync_start); + args.usV_SyncWidth = + cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); + + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + misc |= ATOM_VSYNC_POLARITY; + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + misc |= ATOM_HSYNC_POLARITY; + if (mode->flags & DRM_MODE_FLAG_CSYNC) + misc |= ATOM_COMPOSITESYNC; + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + misc |= ATOM_INTERLACE; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + misc |= ATOM_DOUBLE_CLOCK_MODE; + + args.susModeMiscInfo.usAccess = cpu_to_le16(misc); + args.ucCRTC = radeon_crtc->crtc_id; printk("executing set crtc timing\n"); - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&conv_param); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) @@ -602,128 +632,17 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; 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)); - - 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; - 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; - - 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_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_DBLSCAN) - crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE; - } atombios_crtc_set_pll(crtc, adjusted_mode); - atombios_crtc_set_timing(crtc, &crtc_timing); + atombios_crtc_set_timing(crtc, adjusted_mode); if (ASIC_IS_AVIVO(rdev)) atombios_crtc_set_base(crtc, x, y, old_fb); else { - if (radeon_crtc->crtc_id == 0) { - SET_CRTC_USING_DTD_TIMING_PARAMETERS crtc_dtd_timing; - memset(&crtc_dtd_timing, 0, sizeof(crtc_dtd_timing)); - - /* setup FP shadow regs on R4xx */ - crtc_dtd_timing.ucCRTC = radeon_crtc->crtc_id; - crtc_dtd_timing.usH_Size = adjusted_mode->crtc_hdisplay; - crtc_dtd_timing.usV_Size = adjusted_mode->crtc_vdisplay; - crtc_dtd_timing.usH_Blanking_Time = - adjusted_mode->crtc_hblank_end - - adjusted_mode->crtc_hdisplay; - crtc_dtd_timing.usV_Blanking_Time = - adjusted_mode->crtc_vblank_end - - adjusted_mode->crtc_vdisplay; - crtc_dtd_timing.usH_SyncOffset = - adjusted_mode->crtc_hsync_start - - adjusted_mode->crtc_hdisplay; - crtc_dtd_timing.usV_SyncOffset = - adjusted_mode->crtc_vsync_start - - adjusted_mode->crtc_vdisplay; - crtc_dtd_timing.usH_SyncWidth = - adjusted_mode->crtc_hsync_end - - adjusted_mode->crtc_hsync_start; - crtc_dtd_timing.usV_SyncWidth = - adjusted_mode->crtc_vsync_end - - adjusted_mode->crtc_vsync_start; - /* crtc_dtd_timing.ucH_Border = adjusted_mode->crtc_hborder; */ - /* crtc_dtd_timing.ucV_Border = adjusted_mode->crtc_vborder; */ - - if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) - crtc_dtd_timing.susModeMiscInfo.usAccess |= - ATOM_VSYNC_POLARITY; - - if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) - crtc_dtd_timing.susModeMiscInfo.usAccess |= - ATOM_HSYNC_POLARITY; - - if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC) - crtc_dtd_timing.susModeMiscInfo.usAccess |= - ATOM_COMPOSITESYNC; - - if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) - crtc_dtd_timing.susModeMiscInfo.usAccess |= - ATOM_INTERLACE; - - if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) - crtc_dtd_timing.susModeMiscInfo.usAccess |= - ATOM_DOUBLE_CLOCK_MODE; - - atombios_set_crtc_dtd_timing(crtc, &crtc_dtd_timing); - } + if (radeon_crtc->crtc_id == 0) + atombios_set_crtc_dtd_timing(crtc, adjusted_mode); radeon_crtc_set_base(crtc, x, y, old_fb); radeon_legacy_atom_set_surface(crtc); } diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 5b6c08cee40e..979ddfdf209c 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -857,8 +857,7 @@ radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder) } 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 drm_display_mode *mode) { struct radeon_mode_info *mode_info = &rdev->mode_info; ATOM_ANALOG_TV_INFO *tv_info; @@ -866,7 +865,7 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, ATOM_DTD_FORMAT *dtd_timings; int data_index = GetIndexIntoMasterTable(DATA, AnalogTV_Info); u8 frev, crev; - uint16_t data_offset; + u16 data_offset, misc; atom_parse_data_header(mode_info->atom_context, data_index, NULL, &frev, &crev, &data_offset); @@ -876,28 +875,37 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, 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); + mode->crtc_htotal = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total); + mode->crtc_hdisplay = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Disp); + mode->crtc_hsync_start = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart); + mode->crtc_hsync_end = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart) + + 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); + mode->crtc_vtotal = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Total); + mode->crtc_vdisplay = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Disp); + mode->crtc_vsync_start = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart); + mode->crtc_vsync_end = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart) + + le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncWidth); - crtc_timing->susModeMiscInfo = tv_info->aModeTimings[index].susModeMiscInfo; + mode->flags = 0; + misc = le16_to_cpu(tv_info->aModeTimings[index].susModeMiscInfo.usAccess); + if (misc & ATOM_VSYNC_POLARITY) + mode->flags |= DRM_MODE_FLAG_NVSYNC; + if (misc & ATOM_HSYNC_POLARITY) + mode->flags |= DRM_MODE_FLAG_NHSYNC; + if (misc & ATOM_COMPOSITESYNC) + mode->flags |= DRM_MODE_FLAG_CSYNC; + if (misc & ATOM_INTERLACE) + mode->flags |= DRM_MODE_FLAG_INTERLACE; + if (misc & ATOM_DOUBLE_CLOCK_MODE) + mode->flags |= DRM_MODE_FLAG_DBLSCAN; - 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; + mode->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; + mode->crtc_htotal -= 1; + mode->crtc_vtotal -= 1; } break; case 2: @@ -906,17 +914,36 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, 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); + mode->crtc_htotal = le16_to_cpu(dtd_timings->usHActive) + + le16_to_cpu(dtd_timings->usHBlanking_Time); + mode->crtc_hdisplay = le16_to_cpu(dtd_timings->usHActive); + mode->crtc_hsync_start = le16_to_cpu(dtd_timings->usHActive) + + le16_to_cpu(dtd_timings->usHSyncOffset); + mode->crtc_hsync_end = mode->crtc_hsync_start + + le16_to_cpu(dtd_timings->usHSyncWidth); - crtc_timing->susModeMiscInfo.usAccess = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess); - *pixel_clock = le16_to_cpu(dtd_timings->usPixClk) * 10; + mode->crtc_vtotal = le16_to_cpu(dtd_timings->usVActive) + + le16_to_cpu(dtd_timings->usVBlanking_Time); + mode->crtc_vdisplay = le16_to_cpu(dtd_timings->usVActive); + mode->crtc_vsync_start = le16_to_cpu(dtd_timings->usVActive) + + le16_to_cpu(dtd_timings->usVSyncOffset); + mode->crtc_vsync_end = mode->crtc_vsync_start + + le16_to_cpu(dtd_timings->usVSyncWidth); + + mode->flags = 0; + misc = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess); + if (misc & ATOM_VSYNC_POLARITY) + mode->flags |= DRM_MODE_FLAG_NVSYNC; + if (misc & ATOM_HSYNC_POLARITY) + mode->flags |= DRM_MODE_FLAG_NHSYNC; + if (misc & ATOM_COMPOSITESYNC) + mode->flags |= DRM_MODE_FLAG_CSYNC; + if (misc & ATOM_INTERLACE) + mode->flags |= DRM_MODE_FLAG_INTERLACE; + if (misc & ATOM_DOUBLE_CLOCK_MODE) + mode->flags |= DRM_MODE_FLAG_DBLSCAN; + + mode->clock = le16_to_cpu(dtd_timings->usPixClk) * 10; break; } return true; diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index a65ab1a0dad2..3e58c6eccea5 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -31,6 +31,10 @@ extern int atom_debug; +/* evil but including atombios.h is much worse */ +bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, + struct drm_display_mode *mode); + uint32_t radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t dac) { @@ -219,6 +223,8 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; drm_mode_set_crtcinfo(adjusted_mode, 0); @@ -230,6 +236,18 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; + 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) + radeon_atom_get_tv_timings(rdev, 0, adjusted_mode); + else + radeon_atom_get_tv_timings(rdev, 1, adjusted_mode); + } + } + return true; } From de2103e452ec7f2db5db7c44279735688608381d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 9 Oct 2009 15:14:30 -0400 Subject: [PATCH 08/46] drm/radeon/kms: use drm_mode directly for panel modes This reduces the number of mode format conversions needed and makes native panel mode support cleaner. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 32 ++++++----- drivers/gpu/drm/radeon/radeon_combios.c | 62 ++++++++++----------- drivers/gpu/drm/radeon/radeon_connectors.c | 55 +++++++----------- drivers/gpu/drm/radeon/radeon_display.c | 6 +- drivers/gpu/drm/radeon/radeon_encoders.c | 48 +++------------- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 30 +++++----- drivers/gpu/drm/radeon/radeon_mode.h | 19 ++----- 7 files changed, 95 insertions(+), 157 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 979ddfdf209c..79d4b771c770 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -798,27 +798,29 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct if (!lvds) return NULL; - lvds->native_mode.dotclock = + lvds->native_mode.clock = le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10; - lvds->native_mode.panel_xres = + lvds->native_mode.hdisplay = le16_to_cpu(lvds_info->info.sLCDTiming.usHActive); - lvds->native_mode.panel_yres = + lvds->native_mode.vdisplay = le16_to_cpu(lvds_info->info.sLCDTiming.usVActive); - lvds->native_mode.hblank = - le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time); - lvds->native_mode.hoverplus = - le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset); - lvds->native_mode.hsync_width = - le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth); - lvds->native_mode.vblank = - le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time); - lvds->native_mode.voverplus = - le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset); - lvds->native_mode.vsync_width = - le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); + lvds->native_mode.htotal = lvds->native_mode.hdisplay + + le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time); + lvds->native_mode.hsync_start = lvds->native_mode.hdisplay + + le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset); + lvds->native_mode.hsync_end = lvds->native_mode.hsync_start + + le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth); + lvds->native_mode.vtotal = lvds->native_mode.vdisplay + + le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time); + lvds->native_mode.vsync_start = lvds->native_mode.vdisplay + + le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); + lvds->native_mode.vsync_end = lvds->native_mode.vsync_start + + le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); lvds->panel_pwr_delay = le16_to_cpu(lvds_info->info.usOffDelayInMs); lvds->lvds_misc = lvds_info->info.ucLVDS_Misc; + /* set crtc values */ + drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V); encoder->native_mode = lvds->native_mode; } diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 748265a105b3..e91aba8530b6 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -808,25 +808,25 @@ static struct radeon_encoder_lvds *radeon_legacy_get_lvds_info_from_regs(struct lvds->panel_blon_delay = (lvds_ss_gen_cntl >> RADEON_LVDS_PWRSEQ_DELAY2_SHIFT) & 0xf; if (fp_vert_stretch & RADEON_VERT_STRETCH_ENABLE) - lvds->native_mode.panel_yres = + lvds->native_mode.vdisplay = ((fp_vert_stretch & RADEON_VERT_PANEL_SIZE) >> RADEON_VERT_PANEL_SHIFT) + 1; else - lvds->native_mode.panel_yres = + lvds->native_mode.vdisplay = (RREG32(RADEON_CRTC_V_TOTAL_DISP) >> 16) + 1; if (fp_horz_stretch & RADEON_HORZ_STRETCH_ENABLE) - lvds->native_mode.panel_xres = + lvds->native_mode.hdisplay = (((fp_horz_stretch & RADEON_HORZ_PANEL_SIZE) >> RADEON_HORZ_PANEL_SHIFT) + 1) * 8; else - lvds->native_mode.panel_xres = + lvds->native_mode.hdisplay = ((RREG32(RADEON_CRTC_H_TOTAL_DISP) >> 16) + 1) * 8; - if ((lvds->native_mode.panel_xres < 640) || - (lvds->native_mode.panel_yres < 480)) { - lvds->native_mode.panel_xres = 640; - lvds->native_mode.panel_yres = 480; + if ((lvds->native_mode.hdisplay < 640) || + (lvds->native_mode.vdisplay < 480)) { + lvds->native_mode.hdisplay = 640; + lvds->native_mode.vdisplay = 480; } ppll_div_sel = RREG8(RADEON_CLOCK_CNTL_INDEX + 1) & 0x3; @@ -846,8 +846,8 @@ static struct radeon_encoder_lvds *radeon_legacy_get_lvds_info_from_regs(struct lvds->panel_vcc_delay = 200; DRM_INFO("Panel info derived from registers\n"); - DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.panel_xres, - lvds->native_mode.panel_yres); + DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.hdisplay, + lvds->native_mode.vdisplay); return lvds; } @@ -882,11 +882,11 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder DRM_INFO("Panel ID String: %s\n", stmp); - lvds->native_mode.panel_xres = RBIOS16(lcd_info + 0x19); - lvds->native_mode.panel_yres = RBIOS16(lcd_info + 0x1b); + lvds->native_mode.hdisplay = RBIOS16(lcd_info + 0x19); + lvds->native_mode.vdisplay = RBIOS16(lcd_info + 0x1b); - DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.panel_xres, - lvds->native_mode.panel_yres); + DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.hdisplay, + lvds->native_mode.vdisplay); lvds->panel_vcc_delay = RBIOS16(lcd_info + 0x2c); if (lvds->panel_vcc_delay > 2000 || lvds->panel_vcc_delay < 0) @@ -944,27 +944,25 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder if (tmp == 0) break; - if ((RBIOS16(tmp) == lvds->native_mode.panel_xres) && + if ((RBIOS16(tmp) == lvds->native_mode.hdisplay) && (RBIOS16(tmp + 2) == - lvds->native_mode.panel_yres)) { - lvds->native_mode.hblank = - (RBIOS16(tmp + 17) - RBIOS16(tmp + 19)) * 8; - lvds->native_mode.hoverplus = - (RBIOS16(tmp + 21) - RBIOS16(tmp + 19) - - 1) * 8; - lvds->native_mode.hsync_width = - RBIOS8(tmp + 23) * 8; + lvds->native_mode.vdisplay)) { + lvds->native_mode.htotal = RBIOS16(tmp + 17) * 8; + lvds->native_mode.hsync_start = RBIOS16(tmp + 21) * 8; + lvds->native_mode.hsync_end = (RBIOS8(tmp + 23) + + RBIOS16(tmp + 21)) * 8; - lvds->native_mode.vblank = (RBIOS16(tmp + 24) - - RBIOS16(tmp + 26)); - lvds->native_mode.voverplus = - ((RBIOS16(tmp + 28) & 0x7ff) - - RBIOS16(tmp + 26)); - lvds->native_mode.vsync_width = - ((RBIOS16(tmp + 28) & 0xf800) >> 11); - lvds->native_mode.dotclock = - RBIOS16(tmp + 9) * 10; + lvds->native_mode.vtotal = RBIOS16(tmp + 24); + lvds->native_mode.vsync_start = RBIOS16(tmp + 28) & 0x7ff; + lvds->native_mode.vsync_end = + ((RBIOS16(tmp + 28) & 0xf800) >> 11) + + (RBIOS16(tmp + 28) & 0x7ff); + + lvds->native_mode.clock = RBIOS16(tmp + 9) * 10; lvds->native_mode.flags = 0; + /* set crtc values */ + drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V); + } } } else { diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 466f6010a2e4..da3a049e3640 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -178,25 +178,13 @@ static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encode struct drm_device *dev = encoder->dev; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct drm_display_mode *mode = NULL; - struct radeon_native_mode *native_mode = &radeon_encoder->native_mode; + struct drm_display_mode *native_mode = &radeon_encoder->native_mode; - if (native_mode->panel_xres != 0 && - native_mode->panel_yres != 0 && - native_mode->dotclock != 0) { + if (native_mode->hdisplay != 0 && + native_mode->vdisplay != 0 && + native_mode->clock != 0) { mode = drm_mode_create(dev); - - mode->hdisplay = native_mode->panel_xres; - mode->vdisplay = native_mode->panel_yres; - - mode->htotal = mode->hdisplay + native_mode->hblank; - mode->hsync_start = mode->hdisplay + native_mode->hoverplus; - mode->hsync_end = mode->hsync_start + native_mode->hsync_width; - mode->vtotal = mode->vdisplay + native_mode->vblank; - mode->vsync_start = mode->vdisplay + native_mode->voverplus; - mode->vsync_end = mode->vsync_start + native_mode->vsync_width; - mode->clock = native_mode->dotclock; - mode->flags = 0; - + *mode = *native_mode; mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; drm_mode_set_name(mode); @@ -210,7 +198,7 @@ static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_conn struct drm_device *dev = encoder->dev; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct drm_display_mode *mode = NULL; - struct radeon_native_mode *native_mode = &radeon_encoder->native_mode; + struct drm_display_mode *native_mode = &radeon_encoder->native_mode; int i; struct mode_size { int w; @@ -237,10 +225,10 @@ static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_conn for (i = 0; i < 17; i++) { if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - if (common_modes[i].w > native_mode->panel_xres || - common_modes[i].h > native_mode->panel_yres || - (common_modes[i].w == native_mode->panel_xres && - common_modes[i].h == native_mode->panel_yres)) + if (common_modes[i].w > native_mode->hdisplay || + common_modes[i].h > native_mode->vdisplay || + (common_modes[i].w == native_mode->hdisplay && + common_modes[i].h == native_mode->vdisplay)) continue; } if (common_modes[i].w < 320 || common_modes[i].h < 200) @@ -344,28 +332,23 @@ static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder, struct drm_connector *connector) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_native_mode *native_mode = &radeon_encoder->native_mode; + struct drm_display_mode *native_mode = &radeon_encoder->native_mode; /* Try to get native mode details from EDID if necessary */ - if (!native_mode->dotclock) { + if (!native_mode->clock) { struct drm_display_mode *t, *mode; list_for_each_entry_safe(mode, t, &connector->probed_modes, head) { - if (mode->hdisplay == native_mode->panel_xres && - mode->vdisplay == native_mode->panel_yres) { - native_mode->hblank = mode->htotal - mode->hdisplay; - native_mode->hoverplus = mode->hsync_start - mode->hdisplay; - native_mode->hsync_width = mode->hsync_end - mode->hsync_start; - native_mode->vblank = mode->vtotal - mode->vdisplay; - native_mode->voverplus = mode->vsync_start - mode->vdisplay; - native_mode->vsync_width = mode->vsync_end - mode->vsync_start; - native_mode->dotclock = mode->clock; + if (mode->hdisplay == native_mode->hdisplay && + mode->vdisplay == native_mode->vdisplay) { + *native_mode = *mode; + drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V); DRM_INFO("Determined LVDS native mode details from EDID\n"); break; } } } - if (!native_mode->dotclock) { + if (!native_mode->clock) { DRM_INFO("No LVDS native mode details, disabling RMX\n"); radeon_encoder->rmx_type = RMX_OFF; } @@ -420,10 +403,10 @@ static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connec if (encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_native_mode *native_mode = &radeon_encoder->native_mode; + struct drm_display_mode *native_mode = &radeon_encoder->native_mode; /* check if panel is valid */ - if (native_mode->panel_xres >= 320 && native_mode->panel_yres >= 240) + if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) ret = connector_status_connected; } diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index b8f234497aca..a20bf43389b3 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -761,7 +761,7 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, radeon_crtc->rmx_type = radeon_encoder->rmx_type; memcpy(&radeon_crtc->native_mode, &radeon_encoder->native_mode, - sizeof(struct radeon_native_mode)); + sizeof(struct drm_display_mode)); first = false; } else { if (radeon_crtc->rmx_type != radeon_encoder->rmx_type) { @@ -779,10 +779,10 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, if (radeon_crtc->rmx_type != RMX_OFF) { fixed20_12 a, b; a.full = rfixed_const(crtc->mode.vdisplay); - b.full = rfixed_const(radeon_crtc->native_mode.panel_xres); + b.full = rfixed_const(radeon_crtc->native_mode.hdisplay); radeon_crtc->vsc.full = rfixed_div(a, b); a.full = rfixed_const(crtc->mode.hdisplay); - b.full = rfixed_const(radeon_crtc->native_mode.panel_yres); + b.full = rfixed_const(radeon_crtc->native_mode.vdisplay); radeon_crtc->hsc.full = rfixed_div(a, b); } else { radeon_crtc->vsc.full = rfixed_const(1); diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 3e58c6eccea5..a9d4e0ab049a 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -171,49 +171,15 @@ void radeon_rmx_mode_fixup(struct drm_encoder *encoder, struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; - struct radeon_native_mode *native_mode = &radeon_encoder->native_mode; + struct drm_display_mode *native_mode = &radeon_encoder->native_mode; - if (mode->hdisplay < native_mode->panel_xres || - mode->vdisplay < native_mode->panel_yres) { - if (ASIC_IS_AVIVO(rdev)) { - adjusted_mode->hdisplay = native_mode->panel_xres; - adjusted_mode->vdisplay = native_mode->panel_yres; - adjusted_mode->htotal = native_mode->panel_xres + native_mode->hblank; - adjusted_mode->hsync_start = native_mode->panel_xres + native_mode->hoverplus; - adjusted_mode->hsync_end = adjusted_mode->hsync_start + native_mode->hsync_width; - adjusted_mode->vtotal = native_mode->panel_yres + native_mode->vblank; - adjusted_mode->vsync_start = native_mode->panel_yres + native_mode->voverplus; - adjusted_mode->vsync_end = adjusted_mode->vsync_start + native_mode->vsync_width; - /* update crtc values */ - drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); - /* adjust crtc values */ - adjusted_mode->crtc_hdisplay = native_mode->panel_xres; - adjusted_mode->crtc_vdisplay = native_mode->panel_yres; - adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + native_mode->hblank; - adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + native_mode->hoverplus; - adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + native_mode->hsync_width; - adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + native_mode->vblank; - adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + native_mode->voverplus; - adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + native_mode->vsync_width; - } else { - adjusted_mode->htotal = native_mode->panel_xres + native_mode->hblank; - adjusted_mode->hsync_start = native_mode->panel_xres + native_mode->hoverplus; - adjusted_mode->hsync_end = adjusted_mode->hsync_start + native_mode->hsync_width; - adjusted_mode->vtotal = native_mode->panel_yres + native_mode->vblank; - adjusted_mode->vsync_start = native_mode->panel_yres + native_mode->voverplus; - adjusted_mode->vsync_end = adjusted_mode->vsync_start + native_mode->vsync_width; - /* update crtc values */ - drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); - /* adjust crtc values */ - adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + native_mode->hblank; - adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + native_mode->hoverplus; - adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + native_mode->hsync_width; - adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + native_mode->vblank; - adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + native_mode->voverplus; - adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + native_mode->vsync_width; + if (mode->hdisplay < native_mode->hdisplay || + mode->vdisplay < native_mode->vdisplay) { + *adjusted_mode = *native_mode; + if (!ASIC_IS_AVIVO(rdev)) { + adjusted_mode->hdisplay = mode->hdisplay; + adjusted_mode->vdisplay = mode->vdisplay; } - adjusted_mode->flags = native_mode->flags; - adjusted_mode->clock = native_mode->dotclock; } } diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index ec2df739c119..d22a195cf152 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -48,7 +48,7 @@ static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc, u32 fp_horz_stretch, fp_vert_stretch, fp_horz_vert_active; u32 fp_h_sync_strt_wid, fp_crtc_h_total_disp; u32 fp_v_sync_strt_wid, fp_crtc_v_total_disp; - struct radeon_native_mode *native_mode = &radeon_crtc->native_mode; + struct drm_display_mode *native_mode = &radeon_crtc->native_mode; fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH) & (RADEON_VERT_STRETCH_RESERVED | @@ -95,19 +95,19 @@ static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc, fp_horz_vert_active = 0; - if (native_mode->panel_xres == 0 || - native_mode->panel_yres == 0) { + if (native_mode->hdisplay == 0 || + native_mode->vdisplay == 0) { hscale = false; vscale = false; } else { - if (xres > native_mode->panel_xres) - xres = native_mode->panel_xres; - if (yres > native_mode->panel_yres) - yres = native_mode->panel_yres; + if (xres > native_mode->hdisplay) + xres = native_mode->hdisplay; + if (yres > native_mode->vdisplay) + yres = native_mode->vdisplay; - if (xres == native_mode->panel_xres) + if (xres == native_mode->hdisplay) hscale = false; - if (yres == native_mode->panel_yres) + if (yres == native_mode->vdisplay) vscale = false; } @@ -119,11 +119,11 @@ static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc, else { inc = (fp_horz_stretch & RADEON_HORZ_AUTO_RATIO_INC) ? 1 : 0; scale = ((xres + inc) * RADEON_HORZ_STRETCH_RATIO_MAX) - / native_mode->panel_xres + 1; + / native_mode->hdisplay + 1; fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) | RADEON_HORZ_STRETCH_BLEND | RADEON_HORZ_STRETCH_ENABLE | - ((native_mode->panel_xres/8-1) << 16)); + ((native_mode->hdisplay/8-1) << 16)); } if (!vscale) @@ -131,11 +131,11 @@ static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc, else { inc = (fp_vert_stretch & RADEON_VERT_AUTO_RATIO_INC) ? 1 : 0; scale = ((yres + inc) * RADEON_VERT_STRETCH_RATIO_MAX) - / native_mode->panel_yres + 1; + / native_mode->vdisplay + 1; fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) | RADEON_VERT_STRETCH_ENABLE | RADEON_VERT_STRETCH_BLEND | - ((native_mode->panel_yres-1) << 12)); + ((native_mode->vdisplay-1) << 12)); } break; case RMX_CENTER: @@ -175,8 +175,8 @@ static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc, ? RADEON_CRTC_V_SYNC_POL : 0))); - fp_horz_vert_active = (((native_mode->panel_yres) & 0xfff) | - (((native_mode->panel_xres / 8) & 0x1ff) << 16)); + fp_horz_vert_active = (((native_mode->vdisplay) & 0xfff) | + (((native_mode->hdisplay / 8) & 0x1ff) << 16)); break; case RMX_OFF: default: diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index e61226817ccf..3d2631be073c 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -186,17 +186,6 @@ struct radeon_mode_info { }; -struct radeon_native_mode { - /* preferred mode */ - uint32_t panel_xres, panel_yres; - uint32_t hoverplus, hsync_width; - uint32_t hblank; - uint32_t voverplus, vsync_width; - uint32_t vblank; - uint32_t dotclock; - uint32_t flags; -}; - #define MAX_H_CODE_TIMING_LEN 32 #define MAX_V_CODE_TIMING_LEN 32 @@ -228,7 +217,7 @@ struct radeon_crtc { enum radeon_rmx_type rmx_type; fixed20_12 vsc; fixed20_12 hsc; - struct radeon_native_mode native_mode; + struct drm_display_mode native_mode; }; struct radeon_encoder_primary_dac { @@ -248,7 +237,7 @@ struct radeon_encoder_lvds { bool use_bios_dividers; uint32_t lvds_gen_cntl; /* panel mode */ - struct radeon_native_mode native_mode; + struct drm_display_mode native_mode; }; struct radeon_encoder_tv_dac { @@ -279,7 +268,7 @@ struct radeon_encoder_atom_dig { uint32_t lvds_misc; uint16_t panel_pwr_delay; /* panel mode */ - struct radeon_native_mode native_mode; + struct drm_display_mode native_mode; }; struct radeon_encoder_atom_dac { @@ -294,7 +283,7 @@ struct radeon_encoder { uint32_t flags; uint32_t pixel_clock; enum radeon_rmx_type rmx_type; - struct radeon_native_mode native_mode; + struct drm_display_mode native_mode; void *enc_priv; }; From 0549a061b545d232d12836f98c7c4965dd83f837 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 9 Oct 2009 18:41:19 -0400 Subject: [PATCH 09/46] drm/radeon/kms: also check for edid in lvds detect In case the system has bad native mode info but valid edid. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index da3a049e3640..17d5659cff03 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -398,8 +398,10 @@ static int radeon_lvds_mode_valid(struct drm_connector *connector, static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector) { - enum drm_connector_status ret = connector_status_disconnected; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder = radeon_best_single_encoder(connector); + enum drm_connector_status ret = connector_status_disconnected; + bool dret; if (encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -410,6 +412,15 @@ static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connec ret = connector_status_connected; } + + /* check for edid as well */ + if (radeon_connector->ddc_bus) { + 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; + } /* check acpi lid status ??? */ radeon_connector_update_scratch_regs(connector, ret); From ceeb50279b3d05eb7ea2b67e90acb2110d09325f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 12 Oct 2009 13:54:10 +1000 Subject: [PATCH 10/46] drm/radeon: Revert "drm/r600: avoid assigning vb twice in blit code" This reverts commit 49c458e544ae14514209ed80ea6829ca1b18ddf0. It seems to have some side effects in the non-kms cases. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_blit.c | 10 +++++++--- drivers/gpu/drm/radeon/r600_blit_kms.c | 3 +-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_blit.c b/drivers/gpu/drm/radeon/r600_blit.c index dec501081608..d988eece0187 100644 --- a/drivers/gpu/drm/radeon/r600_blit.c +++ b/drivers/gpu/drm/radeon/r600_blit.c @@ -582,6 +582,8 @@ r600_blit_copy(struct drm_device *dev, 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; @@ -617,8 +619,8 @@ r600_blit_copy(struct drm_device *dev, if (!dev_priv->blit_vb) return; set_shaders(dev); + vb = r600_nomm_get_vb_ptr(dev); } - vb = r600_nomm_get_vb_ptr(dev); vb[0] = i2f(dst_x); vb[1] = 0; @@ -706,8 +708,8 @@ r600_blit_copy(struct drm_device *dev, return; set_shaders(dev); + vb = r600_nomm_get_vb_ptr(dev); } - vb = r600_nomm_get_vb_ptr(dev); vb[0] = i2f(dst_x / 4); vb[1] = 0; @@ -775,6 +777,8 @@ r600_blit_swap(struct drm_device *dev, u64 vb_addr; u32 *vb; + vb = r600_nomm_get_vb_ptr(dev); + if ((dev_priv->blit_vb->used + 48) > dev_priv->blit_vb->total) { r600_nomm_put_vb(dev); @@ -783,8 +787,8 @@ r600_blit_swap(struct drm_device *dev, return; set_shaders(dev); + vb = r600_nomm_get_vb_ptr(dev); } - vb = r600_nomm_get_vb_ptr(dev); if (cpp == 4) { cb_format = COLOR_8_8_8_8; diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c index 93108bb31d1d..acae33e2ad51 100644 --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -610,6 +610,7 @@ void r600_kms_blit_copy(struct radeon_device *rdev, 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; @@ -652,7 +653,6 @@ void r600_kms_blit_copy(struct radeon_device *rdev, vb = r600_nomm_get_vb_ptr(dev); #endif } - vb = (u32 *)(rdev->r600_blit.vb_ib->ptr + rdev->r600_blit.vb_used); vb[0] = i2f(dst_x); vb[1] = 0; @@ -747,7 +747,6 @@ void r600_kms_blit_copy(struct radeon_device *rdev, vb = r600_nomm_get_vb_ptr(dev); } #endif - vb = (u32 *)(rdev->r600_blit.vb_ib->ptr + rdev->r600_blit.vb_used); vb[0] = i2f(dst_x / 4); vb[1] = 0; From 39deb2d67515086f08a672e7574716ca0d3883a5 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 12 Oct 2009 14:21:19 +1000 Subject: [PATCH 11/46] drm/radeon/kms: fix use of index before proper initialisation. With the adjust table introduction, we need to fill out index before getting the table version. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 7522af1b9e46..3409aa3cbee4 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -454,6 +454,7 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, &ref_div, &post_div, pll_flags); + index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); @@ -513,7 +514,6 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) } printk("executing set pll\n"); - index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } From fb06ca8f8c61dfd7cbfa2092756577ff78a26dcd Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 12 Oct 2009 11:25:05 -0400 Subject: [PATCH 12/46] drm/radeon/kms: properly handle mode id with native mode changes drm modes are objects with indentifiers. Make sure to preserve the mode id when copying mode params. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 3 +-- drivers/gpu/drm/radeon/radeon_encoders.c | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 17d5659cff03..729207a1e83e 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -183,8 +183,7 @@ static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encode if (native_mode->hdisplay != 0 && native_mode->vdisplay != 0 && native_mode->clock != 0) { - mode = drm_mode_create(dev); - *mode = *native_mode; + mode = drm_mode_duplicate(dev, native_mode); mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; drm_mode_set_name(mode); diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index a9d4e0ab049a..10845f39124a 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -175,11 +175,13 @@ void radeon_rmx_mode_fixup(struct drm_encoder *encoder, if (mode->hdisplay < native_mode->hdisplay || mode->vdisplay < native_mode->vdisplay) { + int mode_id = adjusted_mode->base.id; *adjusted_mode = *native_mode; if (!ASIC_IS_AVIVO(rdev)) { adjusted_mode->hdisplay = mode->hdisplay; adjusted_mode->vdisplay = mode->vdisplay; } + adjusted_mode->base.id = mode_id; } } From 8c2a6d730400e14bf28ccfa11b9bbf453db775ec Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 14 Oct 2009 02:00:42 -0400 Subject: [PATCH 13/46] drm/radeon/kms: move active_device setup into encoder fixup() radeon_encoder->active_device defines the active routing between the encoder and connector. The encoder fixup and dpms functions need to know the active_device to function properly. Setting active_device in the prepare hook was too late in some cases. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 19 ++++++------------- .../gpu/drm/radeon/radeon_legacy_encoders.c | 17 ++++++++--------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 10845f39124a..6cdef27be99d 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -194,6 +194,8 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; + /* set the active encoder to connector routing */ + radeon_encoder_set_active_device(encoder); drm_mode_set_crtcinfo(adjusted_mode, 0); if (radeon_encoder->rmx_type != RMX_OFF) @@ -860,16 +862,9 @@ 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_DEBUG("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n", radeon_encoder->encoder_id, mode, radeon_encoder->devices, radeon_encoder->active_device); @@ -900,18 +895,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 (devices & (ATOM_DEVICE_TV_SUPPORT)) + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); - else if (devices & (ATOM_DEVICE_CV_SUPPORT)) + else if (radeon_encoder->active_device & (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 (devices & (ATOM_DEVICE_TV_SUPPORT)) + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); - else if (devices & (ATOM_DEVICE_CV_SUPPORT)) + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); else index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); @@ -1254,8 +1249,6 @@ 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) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 6ceb958fd194..3a75b5b6009b 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -107,8 +107,6 @@ 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) @@ -192,6 +190,8 @@ static bool radeon_legacy_lvds_mode_fixup(struct drm_encoder *encoder, { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + /* set the active encoder to connector routing */ + radeon_encoder_set_active_device(encoder); drm_mode_set_crtcinfo(adjusted_mode, 0); if (radeon_encoder->rmx_type != RMX_OFF) @@ -218,7 +218,8 @@ static bool radeon_legacy_primary_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - + /* set the active encoder to connector routing */ + radeon_encoder_set_active_device(encoder); drm_mode_set_crtcinfo(adjusted_mode, 0); return true; @@ -272,7 +273,6 @@ 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) @@ -468,7 +468,6 @@ 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) @@ -593,7 +592,8 @@ static bool radeon_legacy_tmds_ext_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - + /* set the active encoder to connector routing */ + radeon_encoder_set_active_device(encoder); drm_mode_set_crtcinfo(adjusted_mode, 0); return true; @@ -636,7 +636,6 @@ 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) @@ -735,7 +734,8 @@ static bool radeon_legacy_tv_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - + /* set the active encoder to connector routing */ + radeon_encoder_set_active_device(encoder); drm_mode_set_crtcinfo(adjusted_mode, 0); return true; @@ -839,7 +839,6 @@ 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) From 1b4d7d75ccff38008ccd40f8e2d74e33a087caaa Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 15 Oct 2009 01:33:35 -0400 Subject: [PATCH 14/46] drm/radeon/kms: fix internal tmds setup on legacy display engine - crtc 0 routing was wrong - need to clear various timing bits in FP_GEN_CNTL - need to set FP_H/V2_SYNC_STRT_WID regs for crtc 1 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 3 +++ drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index d22a195cf152..8d0b7aa87fa4 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -668,6 +668,9 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod WREG32(RADEON_DISP2_MERGE_CNTL, disp2_merge_cntl); WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + + WREG32(RADEON_FP_H2_SYNC_STRT_WID, crtc_h_sync_strt_wid); + WREG32(RADEON_FP_V2_SYNC_STRT_WID, crtc_v_sync_strt_wid); } else { uint32_t crtc_gen_cntl; uint32_t crtc_ext_cntl; diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 3a75b5b6009b..00382122869b 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -542,6 +542,14 @@ static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder, fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); + fp_gen_cntl &= ~(RADEON_FP_RMX_HVSYNC_CONTROL_EN | + RADEON_FP_DFP_SYNC_SEL | + RADEON_FP_CRT_SYNC_SEL | + RADEON_FP_CRTC_LOCK_8DOT | + RADEON_FP_USE_SHADOW_EN | + RADEON_FP_CRTC_USE_SHADOW_VEND | + RADEON_FP_CRT_SYNC_ALT); + if (1) /* FIXME rgbBits == 8 */ fp_gen_cntl |= RADEON_FP_PANEL_FORMAT; /* 24 bit format */ else @@ -555,7 +563,7 @@ static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder, else fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1; } else - fp_gen_cntl |= RADEON_FP_SEL_CRTC1; + fp_gen_cntl &= ~RADEON_FP_SEL_CRTC2; } else { if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) { fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; From 0294cf4f7f895ddcf284b1ce7cf27a2c9d7106f7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 15 Oct 2009 16:16:35 -0400 Subject: [PATCH 15/46] drm/radeon/kms: fix connector edid handling Based partly on a patch from Christian Koenig - fix several memory leaks in radeon_connector->edid handling - store edid in radeon_connector->edid in detect() or get_modes() - switch hdmi detect code to use radeon_connector->edid - add support for oem boards multiple connectors that share a ddc line. - short circuit lvds_detect() if have a stored edid Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 75 ++++++++++++++++++---- drivers/gpu/drm/radeon/radeon_display.c | 18 ++---- drivers/gpu/drm/radeon/radeon_encoders.c | 10 +-- drivers/gpu/drm/radeon/radeon_mode.h | 2 + 4 files changed, 73 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 729207a1e83e..5b6067aa08bd 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -400,7 +400,6 @@ static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connec struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder = radeon_best_single_encoder(connector); enum drm_connector_status ret = connector_status_disconnected; - bool dret; if (encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -413,12 +412,17 @@ static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connec } /* check for edid as well */ - if (radeon_connector->ddc_bus) { - 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; + if (radeon_connector->edid) + ret = connector_status_connected; + else { + if (radeon_connector->ddc_bus) { + 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) + ret = connector_status_connected; + } } /* check acpi lid status ??? */ @@ -432,6 +436,8 @@ static void radeon_connector_destroy(struct drm_connector *connector) if (radeon_connector->ddc_bus) radeon_i2c_destroy(radeon_connector->ddc_bus); + if (radeon_connector->edid) + kfree(radeon_connector->edid); kfree(radeon_connector->con_priv); drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); @@ -519,9 +525,32 @@ static enum drm_connector_status radeon_vga_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 { + if (dret) { + if (radeon_connector->edid) { + kfree(radeon_connector->edid); + radeon_connector->edid = NULL; + } + 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); + + /* some oems have boards with separate digital and analog connectors + * with a shared ddc line (often vga + hdmi) + */ + if (radeon_connector->use_digital && radeon_connector->shared_ddc) { + kfree(radeon_connector->edid); + radeon_connector->edid = NULL; + ret = connector_status_disconnected; + } else + ret = connector_status_connected; + } + } else { if (radeon_connector->dac_load_detect) { encoder_funcs = encoder->helper_private; ret = encoder_funcs->detect(encoder, connector); @@ -649,6 +678,10 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect dret = radeon_ddc_probe(radeon_connector); radeon_i2c_do_lock(radeon_connector, 0); if (dret) { + if (radeon_connector->edid) { + kfree(radeon_connector->edid); + radeon_connector->edid = NULL; + } 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); @@ -659,10 +692,15 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect } 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; + /* some oems have boards with separate digital and analog connectors + * with a shared ddc line (often vga + hdmi) + */ + if ((!radeon_connector->use_digital) && radeon_connector->shared_ddc) { + kfree(radeon_connector->edid); + radeon_connector->edid = NULL; + ret = connector_status_disconnected; + } else + ret = connector_status_connected; } } @@ -787,6 +825,7 @@ radeon_add_atom_connector(struct drm_device *dev, struct radeon_connector *radeon_connector; struct radeon_connector_atom_dig *radeon_dig_connector; uint32_t subpixel_order = SubPixelNone; + bool shared_ddc = false; int ret; /* fixme - tv/cv/din */ @@ -800,6 +839,13 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_connector->devices |= supported_device; return; } + if (radeon_connector->ddc_bus && i2c_bus->valid) { + if (memcmp(&radeon_connector->ddc_bus->rec, i2c_bus, + sizeof(struct radeon_i2c_bus_rec)) == 0) { + radeon_connector->shared_ddc = true; + shared_ddc = true; + } + } } radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL); @@ -810,6 +856,7 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_connector->connector_id = connector_id; radeon_connector->devices = supported_device; + radeon_connector->shared_ddc = shared_ddc; switch (connector_type) { case DRM_MODE_CONNECTOR_VGA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index a20bf43389b3..c85df4afcb7a 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -334,27 +334,19 @@ static bool radeon_setup_enc_conn(struct drm_device *dev) int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) { - struct edid *edid; int ret = 0; if (!radeon_connector->ddc_bus) return -1; if (!radeon_connector->edid) { radeon_i2c_do_lock(radeon_connector, 1); - edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); + radeon_connector->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) - radeon_connector->use_digital = 1; - else - radeon_connector->use_digital = 0; - drm_mode_connector_update_edid_property(&radeon_connector->base, edid); - ret = drm_add_edid_modes(&radeon_connector->base, edid); - kfree(edid); + if (radeon_connector->edid) { + drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); + ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); return ret; } drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 6cdef27be99d..b70440e8d179 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -449,7 +449,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) case 1: args.v1.ucMisc = 0; args.v1.ucAction = action; - if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr)) + if (drm_detect_hdmi_monitor(radeon_connector->edid)) args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { @@ -474,7 +474,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) if (dig->coherent_mode) args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; } - if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr)) + if (drm_detect_hdmi_monitor(radeon_connector->edid)) args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); args.v2.ucTruncate = 0; @@ -532,7 +532,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) switch (connector->connector_type) { case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ - if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr)) + if (drm_detect_hdmi_monitor(radeon_connector->edid)) return ATOM_ENCODER_MODE_HDMI; else if (radeon_connector->use_digital) return ATOM_ENCODER_MODE_DVI; @@ -542,7 +542,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) case DRM_MODE_CONNECTOR_DVID: case DRM_MODE_CONNECTOR_HDMIA: default: - if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr)) + if (drm_detect_hdmi_monitor(radeon_connector->edid)) return ATOM_ENCODER_MODE_HDMI; else return ATOM_ENCODER_MODE_DVI; @@ -554,7 +554,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) /*if (radeon_output->MonType == MT_DP) return ATOM_ENCODER_MODE_DP; else*/ - if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr)) + if (drm_detect_hdmi_monitor(radeon_connector->edid)) return ATOM_ENCODER_MODE_HDMI; else return ATOM_ENCODER_MODE_DVI; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 3d2631be073c..b6868fbe7346 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -297,6 +297,8 @@ struct radeon_connector { uint32_t connector_id; uint32_t devices; struct radeon_i2c_chan *ddc_bus; + /* some systems have a an hdmi and vga port with a shared ddc line */ + bool shared_ddc; bool use_digital; /* we need to mind the EDID between detect and get modes due to analog/digital/tvencoder */ From ceefedd8e8a80b743fa0b6d6b1992be7029a9efb Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 13 Oct 2009 23:57:47 -0400 Subject: [PATCH 16/46] drm/radeon/kms/atom: fix tv-out D1MODE_INTERLEAVE_EN was getting set in some cases in the encoder quirks function due to the changes in 5a9bcacc0a56f0d9577494e834519480018a6cc3 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 4 ---- drivers/gpu/drm/radeon/radeon_encoders.c | 9 ++++++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 3409aa3cbee4..f7dcb6916837 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -31,10 +31,6 @@ #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) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index b70440e8d179..2aa5994a29d5 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -206,7 +206,7 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; - if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) { + 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 || @@ -1085,8 +1085,11 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder, } /* set scaler clears this on some chips */ - if (ASIC_IS_AVIVO(rdev) && (mode->flags & DRM_MODE_FLAG_INTERLACE)) - WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, AVIVO_D1MODE_INTERLEAVE_EN); + if (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))) { + if (ASIC_IS_AVIVO(rdev) && (mode->flags & DRM_MODE_FLAG_INTERLACE)) + WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, + AVIVO_D1MODE_INTERLEAVE_EN); + } } static void From dfdd646773941bb6b22c3898a26a109e57c872a2 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 13 Oct 2009 12:48:44 -0400 Subject: [PATCH 17/46] drm/radeon/kms: limit default tv modes to <= 1024x768 fixes fdo bug 24496 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 5b6067aa08bd..ce3a785a633b 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -223,6 +223,11 @@ static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_conn }; for (i = 0; i < 17; i++) { + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) { + if (common_modes[i].w > 1024 || + common_modes[i].h > 768) + continue; + } if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { if (common_modes[i].w > native_mode->hdisplay || common_modes[i].h > native_mode->vdisplay || From a77f171843d466d4af0d527bcb2d314fafa8afd7 Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Wed, 14 Oct 2009 00:34:41 -0400 Subject: [PATCH 18/46] drm/radeon/kms: use RADEON_GPU_PAGE_SIZE instead of 4096 Signed-off-by: Matt Turner Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 2 +- drivers/gpu/drm/radeon/r300.c | 2 +- drivers/gpu/drm/radeon/r600.c | 10 +++++----- drivers/gpu/drm/radeon/radeon.h | 2 ++ drivers/gpu/drm/radeon/radeon_benchmark.c | 4 ++-- drivers/gpu/drm/radeon/radeon_gart.c | 20 ++++++++++---------- drivers/gpu/drm/radeon/radeon_test.c | 6 +++--- 7 files changed, 24 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 33198dd5706c..c22adff179a9 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -240,7 +240,7 @@ int r100_wb_init(struct radeon_device *rdev) int r; if (rdev->wb.wb_obj == NULL) { - r = radeon_object_create(rdev, NULL, 4096, + r = radeon_object_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, false, &rdev->wb.wb_obj); diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index e08c4a8974ca..2f43ee8e4048 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -113,7 +113,7 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev) tmp = RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, rdev->mc.gtt_location); - tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 4096; + tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - RADEON_GPU_PAGE_SIZE; WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, tmp); WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0); WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 6b43a95a5fb2..1b5aa1fd368b 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1269,9 +1269,9 @@ int r600_cp_resume(struct radeon_device *rdev) 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); + (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz); #else - WREG32(CP_RB_CNTL, RB_NO_UPDATE | (drm_order(4096/8) << 8) | rb_bufsz); + WREG32(CP_RB_CNTL, RB_NO_UPDATE | (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz); #endif WREG32(CP_SEM_WAIT_TIMER, 0x4); @@ -1400,7 +1400,7 @@ int r600_wb_enable(struct radeon_device *rdev) int r; if (rdev->wb.wb_obj == NULL) { - r = radeon_object_create(rdev, NULL, 4096, true, + r = radeon_object_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, false, &rdev->wb.wb_obj); if (r) { dev_warn(rdev->dev, "failed to create WB buffer (%d).\n", r); @@ -1450,8 +1450,8 @@ 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_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE); + r600_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE); r600_blit_done_copy(rdev, fence); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 3598adca034a..8b60e36b20ba 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -276,6 +276,8 @@ union radeon_gart_table { struct radeon_gart_table_vram vram; }; +#define RADEON_GPU_PAGE_SIZE 4096 + struct radeon_gart { dma_addr_t table_addr; unsigned num_gpu_pages; diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c index 2e938f7496fb..10bd50a7db87 100644 --- a/drivers/gpu/drm/radeon/radeon_benchmark.c +++ b/drivers/gpu/drm/radeon/radeon_benchmark.c @@ -63,7 +63,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize, if (r) { goto out_cleanup; } - r = radeon_copy_dma(rdev, saddr, daddr, size / 4096, fence); + r = radeon_copy_dma(rdev, saddr, daddr, size / RADEON_GPU_PAGE_SIZE, fence); if (r) { goto out_cleanup; } @@ -88,7 +88,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize, if (r) { goto out_cleanup; } - r = radeon_copy_blit(rdev, saddr, daddr, size / 4096, fence); + r = radeon_copy_blit(rdev, saddr, daddr, size / RADEON_GPU_PAGE_SIZE, fence); if (r) { goto out_cleanup; } diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index a931af065dd4..a68d7566178c 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -140,15 +140,15 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, WARN(1, "trying to unbind memory to unitialized GART !\n"); return; } - t = offset / 4096; - p = t / (PAGE_SIZE / 4096); + t = offset / RADEON_GPU_PAGE_SIZE; + p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); for (i = 0; i < pages; i++, p++) { if (rdev->gart.pages[p]) { pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p], PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); rdev->gart.pages[p] = NULL; rdev->gart.pages_addr[p] = 0; - for (j = 0; j < (PAGE_SIZE / 4096); j++, t++) { + for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { radeon_gart_set_page(rdev, t, 0); } } @@ -169,8 +169,8 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, DRM_ERROR("trying to bind memory to unitialized GART !\n"); return -EINVAL; } - t = offset / 4096; - p = t / (PAGE_SIZE / 4096); + t = offset / RADEON_GPU_PAGE_SIZE; + p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); for (i = 0; i < pages; i++, p++) { /* we need to support large memory configurations */ @@ -185,9 +185,9 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, } rdev->gart.pages[p] = pagelist[i]; page_base = rdev->gart.pages_addr[p]; - for (j = 0; j < (PAGE_SIZE / 4096); j++, t++) { + for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { radeon_gart_set_page(rdev, t, page_base); - page_base += 4096; + page_base += RADEON_GPU_PAGE_SIZE; } } mb(); @@ -200,14 +200,14 @@ int radeon_gart_init(struct radeon_device *rdev) if (rdev->gart.pages) { return 0; } - /* We need PAGE_SIZE >= 4096 */ - if (PAGE_SIZE < 4096) { + /* We need PAGE_SIZE >= RADEON_GPU_PAGE_SIZE */ + if (PAGE_SIZE < RADEON_GPU_PAGE_SIZE) { DRM_ERROR("Page size is smaller than GPU page size!\n"); return -EINVAL; } /* Compute table size */ rdev->gart.num_cpu_pages = rdev->mc.gtt_size / PAGE_SIZE; - rdev->gart.num_gpu_pages = rdev->mc.gtt_size / 4096; + rdev->gart.num_gpu_pages = rdev->mc.gtt_size / RADEON_GPU_PAGE_SIZE; DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n", rdev->gart.num_cpu_pages, rdev->gart.num_gpu_pages); /* Allocate pages table */ diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c index 03c33cf4e14c..f8a465d9a1cf 100644 --- a/drivers/gpu/drm/radeon/radeon_test.c +++ b/drivers/gpu/drm/radeon/radeon_test.c @@ -42,7 +42,7 @@ void radeon_test_moves(struct radeon_device *rdev) /* Number of tests = * (Total GTT - IB pool - writeback page - ring buffer) / test size */ - n = (rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - 4096 - + n = (rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - RADEON_GPU_PAGE_SIZE - rdev->cp.ring_size) / size; gtt_obj = kzalloc(n * sizeof(*gtt_obj), GFP_KERNEL); @@ -102,7 +102,7 @@ void radeon_test_moves(struct radeon_device *rdev) goto out_cleanup; } - r = radeon_copy(rdev, gtt_addr, vram_addr, size / 4096, fence); + r = radeon_copy(rdev, gtt_addr, vram_addr, size / RADEON_GPU_PAGE_SIZE, fence); if (r) { DRM_ERROR("Failed GTT->VRAM copy %d\n", i); goto out_cleanup; @@ -145,7 +145,7 @@ void radeon_test_moves(struct radeon_device *rdev) goto out_cleanup; } - r = radeon_copy(rdev, vram_addr, gtt_addr, size / 4096, fence); + r = radeon_copy(rdev, vram_addr, gtt_addr, size / RADEON_GPU_PAGE_SIZE, fence); if (r) { DRM_ERROR("Failed VRAM->GTT copy %d\n", i); goto out_cleanup; From f059d2ad69b056aeabad4460f706a3df2f77ce50 Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Wed, 14 Oct 2009 09:11:25 +0800 Subject: [PATCH 19/46] drm: Add the basic check for the detailed timing in EDID Sometimes we will get the incorrect display modeline when parsing the detailed timing in EDID. For example: >hsync/vsync width is zero >sync is beyond the blank. So add the basic check for the detailed timing in EDID to avoid the incorrect display modeline. Signed-off-by: Zhao Yakui Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_edid.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 3c0d2b3aed76..cea665d86dd3 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -626,6 +626,12 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, return NULL; } + /* it is incorrect if hsync/vsync width is zero */ + if (!hsync_pulse_width || !vsync_pulse_width) { + DRM_DEBUG_KMS("Incorrect Detailed timing. " + "Wrong Hsync/Vsync pulse width\n"); + return NULL; + } mode = drm_mode_create(dev); if (!mode) return NULL; @@ -647,6 +653,15 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, mode->vsync_end = mode->vsync_start + vsync_pulse_width; mode->vtotal = mode->vdisplay + vblank; + /* perform the basic check for the detailed timing */ + if (mode->hsync_end > mode->htotal || + mode->vsync_end > mode->vtotal) { + drm_mode_destroy(dev, mode); + DRM_DEBUG_KMS("Incorrect detailed timing. " + "Sync is beyond the blank.\n"); + return NULL; + } + drm_mode_set_name(mode); if (pt->misc & DRM_EDID_PT_INTERLACED) From 2d152c6ba81c8a7776103b517fa454b8da0419aa Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 15 Oct 2009 23:08:05 -0400 Subject: [PATCH 20/46] drm/radeon/kms: fix legacy quirk handling Need to check the return type for the quirk function to decide whether we add the connectors and encoders. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_combios.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index e91aba8530b6..3c402b957f07 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -1626,8 +1626,9 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) break; } - radeon_apply_legacy_quirks(dev, i, &connector, - &ddc_i2c); + if (!radeon_apply_legacy_quirks(dev, i, &connector, + &ddc_i2c)) + continue; switch (connector) { case CONNECTOR_PROPRIETARY_LEGACY: From d0c403e950d449c8c413a1fbf05dfec45ce03e55 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 15 Oct 2009 23:38:32 -0400 Subject: [PATCH 21/46] drm/radeon/kms: fix support for original r100 Original radeon didn't have a connector table in the bios. Check for the CRT table and if we have one, add a VGA connector. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_combios.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 3c402b957f07..8298c990be7a 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -1773,8 +1773,25 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) DRM_MODE_CONNECTOR_DVII, &ddc_i2c); } else { - DRM_DEBUG("No connector info found\n"); - return false; + uint16_t crt_info = + combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE); + DRM_DEBUG("Found CRT table, assuming VGA connector\n"); + if (crt_info) { + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_CRT1_SUPPORT, + 1), + ATOM_DEVICE_CRT1_SUPPORT); + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + radeon_add_legacy_connector(dev, + 0, + ATOM_DEVICE_CRT1_SUPPORT, + DRM_MODE_CONNECTOR_VGA, + &ddc_i2c); + } else { + DRM_DEBUG("No connector info found\n"); + return false; + } } } From c850cb782626fda78e5e9e5baf18a5bd806a225c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 23 Oct 2009 18:49:03 +1000 Subject: [PATCH 22/46] drm/kms: fix kms/fbdev colormap support properly. This sets the fbcon to use TRUECOLOR by default, it then only modifies the pseudo palette for fbcon, and only touches the real palette when in 8-bit pseudo color mode. Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 42 +++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 23dc9c115fd9..9c924614c418 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -454,22 +454,39 @@ out_free: } EXPORT_SYMBOL(drm_fb_helper_init_crtc_count); -static void setcolreg(struct drm_crtc *crtc, u16 red, u16 green, +static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, u16 regno, struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; struct drm_framebuffer *fb = fb_helper->fb; int pindex; + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 *palette; + u32 value; + /* place color in psuedopalette */ + if (regno > 16) + return -EINVAL; + palette = (u32 *)info->pseudo_palette; + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + value = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + palette[regno] = value; + return 0; + } + pindex = regno; if (fb->bits_per_pixel == 16) { pindex = regno << 3; if (fb->depth == 16 && regno > 63) - return; + return -EINVAL; if (fb->depth == 15 && regno > 31) - return; + return -EINVAL; if (fb->depth == 16) { u16 r, g, b; @@ -493,13 +510,7 @@ static void setcolreg(struct drm_crtc *crtc, u16 red, u16 green, if (fb->depth != 16) fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex); - - if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) { - ((u32 *) fb->pseudo_palette)[regno] = - (regno << info->var.red.offset) | - (regno << info->var.green.offset) | - (regno << info->var.blue.offset); - } + return 0; } int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) @@ -536,7 +547,9 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) if (transp) htransp = *transp++; - setcolreg(crtc, hred, hgreen, hblue, start++, info); + rc = setcolreg(crtc, hred, hgreen, hblue, start++, info); + if (rc) + return rc; } crtc_funcs->load_lut(crtc); } @@ -555,6 +568,7 @@ int drm_fb_helper_setcolreg(unsigned regno, struct drm_device *dev = fb_helper->dev; struct drm_crtc *crtc; int i; + int ret; if (regno > 255) return 1; @@ -568,8 +582,10 @@ int drm_fb_helper_setcolreg(unsigned regno, if (i == fb_helper->crtc_count) continue; + ret = setcolreg(crtc, red, green, blue, regno, info); + if (ret) + return ret; - setcolreg(crtc, red, green, blue, regno, info); crtc_funcs->load_lut(crtc); } return 0; @@ -928,7 +944,7 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, { info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR : - FB_VISUAL_DIRECTCOLOR; + FB_VISUAL_TRUECOLOR; info->fix.type_aux = 0; info->fix.xpanstep = 1; /* doing it in hw */ info->fix.ypanstep = 1; /* doing it in hw */ From ceb776bc87280eb8d13f38e4d7afae757e95af44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20Fr=C3=B6hlich?= Date: Mon, 19 Oct 2009 12:50:41 -0400 Subject: [PATCH 23/46] drm/radeon/kms: fix cs parser tex bit 11 check The problem boils down to the order when the bit11 of the texture size is or'ed to the original width. In the end each mipmap level has the same width or height because of that 11 bit is ored to the scaled down lod with and thus blows up the size again to the full size or more due to the power of two rounding afterwards. The attached patch changes this order so that the texture sizes are computed correct. Also the on error the yet missing inputs to the size computation are printed which helped me to find out where it really breaks. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index c22adff179a9..ed5e983d21e9 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2548,8 +2548,11 @@ void r100_bandwidth_update(struct radeon_device *rdev) static inline void r100_cs_track_texture_print(struct r100_cs_track_texture *t) { DRM_ERROR("pitch %d\n", t->pitch); + DRM_ERROR("use_pitch %d\n", t->use_pitch); DRM_ERROR("width %d\n", t->width); + DRM_ERROR("width_11 %d\n", t->width_11); DRM_ERROR("height %d\n", t->height); + DRM_ERROR("height_11 %d\n", t->height_11); DRM_ERROR("num levels %d\n", t->num_levels); DRM_ERROR("depth %d\n", t->txdepth); DRM_ERROR("bpp %d\n", t->cpp); @@ -2609,15 +2612,17 @@ static int r100_cs_track_texture_check(struct radeon_device *rdev, else w = track->textures[u].pitch / (1 << i); } else { - w = track->textures[u].width / (1 << i); + w = track->textures[u].width; if (rdev->family >= CHIP_RV515) w |= track->textures[u].width_11; + w = w / (1 << i); if (track->textures[u].roundup_w) w = roundup_pow_of_two(w); } - h = track->textures[u].height / (1 << i); + h = track->textures[u].height; if (rdev->family >= CHIP_RV515) h |= track->textures[u].height_11; + h = h / (1 << i); if (track->textures[u].roundup_h) h = roundup_pow_of_two(h); size += w * h; From 5885b7a9f4d2a0405b7e42d44eab4ed2302a8239 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 19 Oct 2009 17:23:33 -0400 Subject: [PATCH 24/46] drm/radeon/kms: fix vram_width calculation on r6xx/r7xx Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 29 +++++++++++++++++------------ drivers/gpu/drm/radeon/r600d.h | 4 ++++ drivers/gpu/drm/radeon/rv770.c | 30 ++++++++++++++++++++++++++---- drivers/gpu/drm/radeon/rv770d.h | 5 +++++ 4 files changed, 52 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 1b5aa1fd368b..e87475c87d52 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -339,11 +339,10 @@ int r600_mc_init(struct radeon_device *rdev) { fixed20_12 a; u32 tmp; - int chansize; + int chansize, numchan; int r; /* Get VRAM informations */ - rdev->mc.vram_width = 128; rdev->mc.vram_is_ddr = true; tmp = RREG32(RAMCFG); if (tmp & CHANSIZE_OVERRIDE) { @@ -353,17 +352,23 @@ int r600_mc_init(struct radeon_device *rdev) } else { chansize = 32; } - if (rdev->family == CHIP_R600) { - rdev->mc.vram_width = 8 * chansize; - } else if (rdev->family == CHIP_RV670) { - rdev->mc.vram_width = 4 * chansize; - } else if ((rdev->family == CHIP_RV610) || - (rdev->family == CHIP_RV620)) { - rdev->mc.vram_width = chansize; - } else if ((rdev->family == CHIP_RV630) || - (rdev->family == CHIP_RV635)) { - rdev->mc.vram_width = 2 * chansize; + tmp = RREG32(CHMAP); + switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) { + case 0: + default: + numchan = 1; + break; + case 1: + numchan = 2; + break; + case 2: + numchan = 4; + break; + case 3: + numchan = 8; + break; } + rdev->mc.vram_width = numchan * 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); diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 5084595eb919..cf238bf5700f 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -270,6 +270,10 @@ #define PCIE_PORT_INDEX 0x0038 #define PCIE_PORT_DATA 0x003C +#define CHMAP 0x2004 +#define NOOFCHAN_SHIFT 12 +#define NOOFCHAN_MASK 0x00003000 + #define RAMCFG 0x2408 #define NOOFBANK_SHIFT 0 #define NOOFBANK_MASK 0x00000001 diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 595ac638039d..40553913b928 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -774,14 +774,36 @@ int rv770_mc_init(struct radeon_device *rdev) { fixed20_12 a; u32 tmp; + int chansize, numchan; 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; + tmp = RREG32(MC_ARB_RAMCFG); + if (tmp & CHANSIZE_OVERRIDE) { + chansize = 16; + } else if (tmp & CHANSIZE_MASK) { + chansize = 64; + } else { + chansize = 32; + } + tmp = RREG32(MC_SHARED_CHMAP); + switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) { + case 0: + default: + numchan = 1; + break; + case 1: + numchan = 2; + break; + case 2: + numchan = 4; + break; + case 3: + numchan = 8; + break; + } + rdev->mc.vram_width = numchan * 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); diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index 4b9c3d6396ff..a1367ab6f261 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -129,6 +129,10 @@ #define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0 #define HDP_TILING_CONFIG 0x2F3C +#define MC_SHARED_CHMAP 0x2004 +#define NOOFCHAN_SHIFT 12 +#define NOOFCHAN_MASK 0x00003000 + #define MC_ARB_RAMCFG 0x2760 #define NOOFBANK_SHIFT 0 #define NOOFBANK_MASK 0x00000003 @@ -142,6 +146,7 @@ #define CHANSIZE_MASK 0x00000100 #define BURSTLENGTH_SHIFT 9 #define BURSTLENGTH_MASK 0x00000200 +#define CHANSIZE_OVERRIDE (1 << 11) #define MC_VM_AGP_TOP 0x2028 #define MC_VM_AGP_BOT 0x202C #define MC_VM_AGP_BASE 0x2030 From 790cfb34ad645be3bf69265cb05d824aeabcfa11 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 15 Oct 2009 23:26:09 -0400 Subject: [PATCH 25/46] drm/radeon/kms: add quirk for acer 5102 doesn't have a tv-out port Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_combios.c | 33 +++++++++++++++++-------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 8298c990be7a..fcb9371bf057 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -1579,6 +1579,17 @@ static bool radeon_apply_legacy_quirks(struct drm_device *dev, return true; } +static bool radeon_apply_legacy_tv_quirks(struct drm_device *dev) +{ + /* Acer 5102 has non-existent TV port */ + if (dev->pdev->device == 0x5975 && + dev->pdev->subsystem_vendor == 0x1025 && + dev->pdev->subsystem_device == 0x009f) + return false; + + return true; +} + bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) { struct radeon_device *rdev = dev->dev_private; @@ -1896,16 +1907,18 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE); if (tv_info) { if (RBIOS8(tv_info + 6) == 'T') { - radeon_add_legacy_encoder(dev, - radeon_get_encoder_id - (dev, - ATOM_DEVICE_TV1_SUPPORT, - 2), - ATOM_DEVICE_TV1_SUPPORT); - radeon_add_legacy_connector(dev, 6, - ATOM_DEVICE_TV1_SUPPORT, - DRM_MODE_CONNECTOR_SVIDEO, - &ddc_i2c); + if (radeon_apply_legacy_tv_quirks(dev)) { + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id + (dev, + ATOM_DEVICE_TV1_SUPPORT, + 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, 6, + ATOM_DEVICE_TV1_SUPPORT, + DRM_MODE_CONNECTOR_SVIDEO, + &ddc_i2c); + } } } } From bc293e58cb4095f2ad43fe672ae269e31d1a18e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20Fr=C3=B6hlich?= Date: Mon, 19 Oct 2009 17:49:49 -0400 Subject: [PATCH 26/46] drm/radeon/kms/atom: get better min pixel clock info Where supported use ulMinPixelClockPLL_Output rather than usMinPixelClockPLL_Output for pll_out_min. This seems to improve pll selection on some boards. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 79d4b771c770..cec67917179f 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -641,8 +641,12 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) le16_to_cpu(firmware_info->info.usReferenceClock); p1pll->reference_div = 0; - p1pll->pll_out_min = - le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output); + if (crev < 2) + p1pll->pll_out_min = + le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output); + else + p1pll->pll_out_min = + le32_to_cpu(firmware_info->info_12.ulMinPixelClockPLL_Output); p1pll->pll_out_max = le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output); From c54b1820d69a1043acaf50d084852e628266e0e2 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Tue, 20 Oct 2009 08:11:36 -0500 Subject: [PATCH 27/46] drm/radeon/r600: Replace repeated calculations with variable. - Reduce the chance of error and avoid a bit of overhead. - Use switch to assign color and format Signed-off-by: Robert Noland Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_blit.c | 52 ++++++++++++++++++------------ 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_blit.c b/drivers/gpu/drm/radeon/r600_blit.c index d988eece0187..626a9ab7075a 100644 --- a/drivers/gpu/drm/radeon/r600_blit.c +++ b/drivers/gpu/drm/radeon/r600_blit.c @@ -774,6 +774,7 @@ r600_blit_swap(struct drm_device *dev, { drm_radeon_private_t *dev_priv = dev->dev_private; int cb_format, tex_format; + int sx2, sy2, dx2, dy2; u64 vb_addr; u32 *vb; @@ -790,16 +791,10 @@ r600_blit_swap(struct drm_device *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; - } + sx2 = sx + w; + sy2 = sy + h; + dx2 = dx + w; + dy2 = dy + h; vb[0] = i2f(dx); vb[1] = i2f(dy); @@ -807,31 +802,46 @@ r600_blit_swap(struct drm_device *dev, vb[3] = i2f(sy); vb[4] = i2f(dx); - vb[5] = i2f(dy + h); + vb[5] = i2f(dy2); vb[6] = i2f(sx); - vb[7] = i2f(sy + h); + vb[7] = i2f(sy2); - vb[8] = i2f(dx + w); - vb[9] = i2f(dy + h); - vb[10] = i2f(sx + w); - vb[11] = i2f(sy + h); + vb[8] = i2f(dx2); + vb[9] = i2f(dy2); + vb[10] = i2f(sx2); + vb[11] = i2f(sy2); + + switch(cpp) { + case 4: + cb_format = COLOR_8_8_8_8; + tex_format = FMT_8_8_8_8; + break; + case 2: + cb_format = COLOR_5_6_5; + tex_format = FMT_5_6_5; + break; + default: + cb_format = COLOR_8; + tex_format = FMT_8; + break; + } /* src */ set_tex_resource(dev_priv, tex_format, src_pitch / cpp, - sy + h, src_pitch / cpp, + sy2, src_pitch / cpp, src_gpu_addr); cp_set_surface_sync(dev_priv, - R600_TC_ACTION_ENA, (src_pitch * (sy + h)), src_gpu_addr); + R600_TC_ACTION_ENA, src_pitch * sy2, src_gpu_addr); /* dst */ set_render_target(dev_priv, cb_format, - dst_pitch / cpp, dy + h, + dst_pitch / cpp, dy2, dst_gpu_addr); /* scissors */ - set_scissors(dev_priv, dx, dy, dx + w, dy + h); + set_scissors(dev_priv, dx, dy, dx2, dy2); /* Vertex buffer setup */ vb_addr = dev_priv->gart_buffers_offset + @@ -844,7 +854,7 @@ r600_blit_swap(struct drm_device *dev, cp_set_surface_sync(dev_priv, R600_CB_ACTION_ENA | R600_CB0_DEST_BASE_ENA, - dst_pitch * (dy + h), dst_gpu_addr); + dst_pitch * dy2, dst_gpu_addr); dev_priv->blit_vb->used += 12 * 4; } From 33fdb15c99aac20d238af487fa363d3e5c7ed197 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Tue, 20 Oct 2009 13:07:38 -0500 Subject: [PATCH 28/46] drm/radeon/r600: only assign vb after we know space is available. This patch only changes this is the swap path, where it doesn't loop. Signed-off-by: Robert Noland Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_blit.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_blit.c b/drivers/gpu/drm/radeon/r600_blit.c index 626a9ab7075a..5ea432347589 100644 --- a/drivers/gpu/drm/radeon/r600_blit.c +++ b/drivers/gpu/drm/radeon/r600_blit.c @@ -778,8 +778,6 @@ r600_blit_swap(struct drm_device *dev, u64 vb_addr; u32 *vb; - vb = r600_nomm_get_vb_ptr(dev); - if ((dev_priv->blit_vb->used + 48) > dev_priv->blit_vb->total) { r600_nomm_put_vb(dev); @@ -788,8 +786,8 @@ r600_blit_swap(struct drm_device *dev, return; set_shaders(dev); - vb = r600_nomm_get_vb_ptr(dev); } + vb = r600_nomm_get_vb_ptr(dev); sx2 = sx + w; sy2 = sy + h; From c290dadf4cac25cc91529d84004795ab43fc0821 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 22 Oct 2009 16:12:34 -0400 Subject: [PATCH 29/46] drm/radeon/kms/r7xx: add regs for 40 bit CUR/GRPH addresses The *_HIGH regs are reversed. The secondary ones are in the primary block and vice versa. We currently only use a 32 bit internal address, so these are 0 for now. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 10 ++++++++++ drivers/gpu/drm/radeon/r500_reg.h | 9 +++++++++ drivers/gpu/drm/radeon/radeon_cursor.c | 10 ++++++++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index f7dcb6916837..9c26e538a1e0 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -577,6 +577,16 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, WREG32(AVIVO_D1VGA_CONTROL, 0); else WREG32(AVIVO_D2VGA_CONTROL, 0); + + if (rdev->family >= CHIP_RV770) { + if (radeon_crtc->crtc_id) { + WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0); + WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0); + } else { + WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0); + WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0); + } + } WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, (u32) fb_location); WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h index 868add6e166d..7baa73955563 100644 --- a/drivers/gpu/drm/radeon/r500_reg.h +++ b/drivers/gpu/drm/radeon/r500_reg.h @@ -384,9 +384,16 @@ # define AVIVO_D1GRPH_TILED (1 << 20) # define AVIVO_D1GRPH_MACRO_ADDRESS_MODE (1 << 21) +/* The R7xx *_HIGH surface regs are backwards; the D1 regs are in the D2 + * block and vice versa. This applies to GRPH, CUR, etc. + */ #define AVIVO_D1GRPH_LUT_SEL 0x6108 #define AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110 +#define R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6914 +#define R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6114 #define AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS 0x6118 +#define R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x691c +#define R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x611c #define AVIVO_D1GRPH_PITCH 0x6120 #define AVIVO_D1GRPH_SURFACE_OFFSET_X 0x6124 #define AVIVO_D1GRPH_SURFACE_OFFSET_Y 0x6128 @@ -404,6 +411,8 @@ # define AVIVO_D1CURSOR_MODE_MASK (3 << 8) # define AVIVO_D1CURSOR_MODE_24BPP 2 #define AVIVO_D1CUR_SURFACE_ADDRESS 0x6408 +#define R700_D1CUR_SURFACE_ADDRESS_HIGH 0x6c0c +#define R700_D2CUR_SURFACE_ADDRESS_HIGH 0x640c #define AVIVO_D1CUR_SIZE 0x6410 #define AVIVO_D1CUR_POSITION 0x6414 #define AVIVO_D1CUR_HOT_SPOT 0x6418 diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index b13c79e38bc0..28772a37009c 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -109,9 +109,15 @@ static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj, struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_device *rdev = crtc->dev->dev_private; - if (ASIC_IS_AVIVO(rdev)) + if (ASIC_IS_AVIVO(rdev)) { + if (rdev->family >= CHIP_RV770) { + if (radeon_crtc->crtc_id) + WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, 0); + else + WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, 0); + } WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, gpu_addr); - else { + } else { radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr; /* offset is from DISP(2)_BASE_ADDRESS */ WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset); From ebbe1cb936dfc96d809ccf4d64a9755f8ba0c0ff Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 16 Oct 2009 11:15:25 -0400 Subject: [PATCH 30/46] drm/radeon/kms/atom: add support for spread spectrum (v2) Spread spectrum is a periodic disturbance added to the feedback divider to change the pixel clock periodically to reduce interference. Only enabled on LVDS. v2: add support for r4xx and fix DCE 3 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios.h | 2 +- drivers/gpu/drm/radeon/atombios_crtc.c | 68 ++++++++++++++++++++---- drivers/gpu/drm/radeon/radeon_atombios.c | 42 +++++++++++++++ drivers/gpu/drm/radeon/radeon_mode.h | 11 ++++ 4 files changed, 111 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index 5d402086bc47..c11ddddfb3b6 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h @@ -2314,7 +2314,7 @@ typedef struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT { UCHAR ucSS_Step; UCHAR ucSS_Delay; UCHAR ucSS_Id; - UCHAR ucRecommandedRef_Div; + UCHAR ucRecommendedRef_Div; UCHAR ucSS_Range; /* it was reserved for V11 */ } ATOM_SPREAD_SPECTRUM_ASSIGNMENT; diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 9c26e538a1e0..e5a3c301b7a9 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -351,6 +351,61 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc, atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } +static void atombios_set_ss(struct drm_crtc *crtc, int enable) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct drm_encoder *encoder = NULL; + struct radeon_encoder *radeon_encoder = NULL; + struct radeon_encoder_atom_dig *dig = NULL; + int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); + ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION args; + ENABLE_LVDS_SS_PARAMETERS legacy_args; + uint16_t percentage = 0; + uint8_t type = 0, step = 0, delay = 0, range = 0; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + radeon_encoder = to_radeon_encoder(encoder); + dig = radeon_encoder->enc_priv; + /* only enable spread spectrum on LVDS */ + if (dig && dig->ss) { + percentage = dig->ss->percentage; + type = dig->ss->type; + step = dig->ss->step; + delay = dig->ss->delay; + range = dig->ss->range; + } else if (enable) + return; + break; + } + } + + if (!radeon_encoder) + return; + + if (ASIC_IS_AVIVO(rdev)) { + memset(&args, 0, sizeof(args)); + args.usSpreadSpectrumPercentage = percentage; + args.ucSpreadSpectrumType = type; + args.ucSpreadSpectrumStep = step; + args.ucSpreadSpectrumDelay = delay; + args.ucSpreadSpectrumRange = range; + args.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; + args.ucEnable = enable; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + } else { + memset(&legacy_args, 0, sizeof(legacy_args)); + legacy_args.usSpreadSpectrumPercentage = percentage; + legacy_args.ucSpreadSpectrumType = type; + legacy_args.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2; + legacy_args.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4; + legacy_args.ucEnable = enable; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&legacy_args); + } +} + void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); @@ -373,8 +428,6 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) memset(&args, 0, sizeof(args)); if (ASIC_IS_AVIVO(rdev)) { - uint32_t ss_cntl; - if ((rdev->family == CHIP_RS600) || (rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) @@ -385,15 +438,6 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; else pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; - - /* disable spread spectrum clocking for now -- thanks Hedy Lamarr */ - if (radeon_crtc->crtc_id == 0) { - ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL); - WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl & ~1); - } else { - ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL); - WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl & ~1); - } } else { pll_flags |= RADEON_PLL_LEGACY; @@ -641,7 +685,9 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, /* TODO color tiling */ + atombios_set_ss(crtc, 0); atombios_crtc_set_pll(crtc, adjusted_mode); + atombios_set_ss(crtc, 1); atombios_crtc_set_timing(crtc, adjusted_mode); if (ASIC_IS_AVIVO(rdev)) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index cec67917179f..18729259c2fc 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -771,6 +771,46 @@ bool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder, return false; } +static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct + radeon_encoder + *encoder, + int id) +{ + struct drm_device *dev = encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_mode_info *mode_info = &rdev->mode_info; + int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info); + uint16_t data_offset; + struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info; + uint8_t frev, crev; + struct radeon_atom_ss *ss = NULL; + + if (id > ATOM_MAX_SS_ENTRY) + return NULL; + + atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, + &crev, &data_offset); + + ss_info = + (struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset); + + if (ss_info) { + ss = + kzalloc(sizeof(struct radeon_atom_ss), GFP_KERNEL); + + if (!ss) + return NULL; + + ss->percentage = le16_to_cpu(ss_info->asSS_Info[id].usSpreadSpectrumPercentage); + ss->type = ss_info->asSS_Info[id].ucSpreadSpectrumType; + ss->step = ss_info->asSS_Info[id].ucSS_Step; + ss->delay = ss_info->asSS_Info[id].ucSS_Delay; + ss->range = ss_info->asSS_Info[id].ucSS_Range; + ss->refdiv = ss_info->asSS_Info[id].ucRecommendedRef_Div; + } + return ss; +} + union lvds_info { struct _ATOM_LVDS_INFO info; struct _ATOM_LVDS_INFO_V12 info_12; @@ -826,6 +866,8 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct /* set crtc values */ drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V); + lvds->ss = radeon_atombios_get_ss_info(encoder, lvds_info->info.ucSS_Id); + encoder->native_mode = lvds->native_mode; } return lvds; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index b6868fbe7346..2ea5707c018c 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -260,6 +260,16 @@ struct radeon_encoder_int_tmds { struct radeon_tmds_pll tmds_pll[4]; }; +/* spread spectrum */ +struct radeon_atom_ss { + uint16_t percentage; + uint8_t type; + uint8_t step; + uint8_t delay; + uint8_t range; + uint8_t refdiv; +}; + struct radeon_encoder_atom_dig { /* atom dig */ bool coherent_mode; @@ -267,6 +277,7 @@ struct radeon_encoder_atom_dig { /* atom lvds */ uint32_t lvds_misc; uint16_t panel_pwr_delay; + struct radeon_atom_ss *ss; /* panel mode */ struct drm_display_mode native_mode; }; From 3e5cb98dfe87cc61d0a1119dd8aa2b1e4cfab424 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 16 Oct 2009 12:21:24 -0400 Subject: [PATCH 31/46] drm/radeon/kms: add support for msi Try to enable msi on chips that support it. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 17 ++++++++++++++++- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_irq_kms.c | 9 +++++++++ drivers/gpu/drm/radeon/radeon_reg.h | 6 ++++++ drivers/gpu/drm/radeon/rs600.c | 18 +++++++++++++++++- 5 files changed, 49 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index ed5e983d21e9..b438b520ee7f 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -186,7 +186,7 @@ static inline uint32_t r100_irq_ack(struct radeon_device *rdev) int r100_irq_process(struct radeon_device *rdev) { - uint32_t status; + uint32_t status, msi_rearm; status = r100_irq_ack(rdev); if (!status) { @@ -209,6 +209,21 @@ int r100_irq_process(struct radeon_device *rdev) } status = r100_irq_ack(rdev); } + if (rdev->msi_enabled) { + switch (rdev->family) { + case CHIP_RS400: + case CHIP_RS480: + msi_rearm = RREG32(RADEON_AIC_CNTL) & ~RS400_MSI_REARM; + WREG32(RADEON_AIC_CNTL, msi_rearm); + WREG32(RADEON_AIC_CNTL, msi_rearm | RS400_MSI_REARM); + break; + default: + msi_rearm = RREG32(RADEON_MSI_REARM_EN) & ~RV370_MSI_REARM_EN; + WREG32(RADEON_MSI_REARM_EN, msi_rearm); + WREG32(RADEON_MSI_REARM_EN, msi_rearm | RV370_MSI_REARM_EN); + break; + } + } return IRQ_HANDLED; } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 8b60e36b20ba..ea3efd7ae85b 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -784,6 +784,7 @@ struct radeon_device { const struct firmware *me_fw; /* all family ME firmware */ const struct firmware *pfp_fw; /* r6/700 PFP firmware */ struct r600_blit r600_blit; + int msi_enabled; /* msi enabled */ }; int radeon_device_init(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 8e0a8759e428..a0fe6232dcb6 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -92,6 +92,13 @@ int radeon_irq_kms_init(struct radeon_device *rdev) if (r) { return r; } + /* enable msi */ + rdev->msi_enabled = 0; + if (rdev->family >= CHIP_RV380) { + int ret = pci_enable_msi(rdev->pdev); + if (!ret) + rdev->msi_enabled = 1; + } drm_irq_install(rdev->ddev); rdev->irq.installed = true; DRM_INFO("radeon: irq initialized.\n"); @@ -103,5 +110,7 @@ void radeon_irq_kms_fini(struct radeon_device *rdev) if (rdev->irq.installed) { rdev->irq.installed = false; drm_irq_uninstall(rdev->ddev); + if (rdev->msi_enabled) + pci_disable_msi(rdev->pdev); } } diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index bfa1ab9c93e1..29ab75903ec1 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -290,6 +290,8 @@ #define RADEON_BUS_CNTL 0x0030 # define RADEON_BUS_MASTER_DIS (1 << 6) # define RADEON_BUS_BIOS_DIS_ROM (1 << 12) +# define RS600_BUS_MASTER_DIS (1 << 14) +# define RS600_MSI_REARM (1 << 20) /* rs600/rs690/rs740 */ # define RADEON_BUS_RD_DISCARD_EN (1 << 24) # define RADEON_BUS_RD_ABORT_EN (1 << 25) # define RADEON_BUS_MSTR_DISCONNECT_EN (1 << 28) @@ -297,6 +299,9 @@ # define RADEON_BUS_READ_BURST (1 << 30) #define RADEON_BUS_CNTL1 0x0034 # define RADEON_BUS_WAIT_ON_LOCK_EN (1 << 4) +/* rv370/rv380, rv410, r423/r430/r480, r5xx */ +#define RADEON_MSI_REARM_EN 0x0160 +# define RV370_MSI_REARM_EN (1 << 0) /* #define RADEON_PCIE_INDEX 0x0030 */ /* #define RADEON_PCIE_DATA 0x0034 */ @@ -3311,6 +3316,7 @@ #define RADEON_AIC_CNTL 0x01d0 # define RADEON_PCIGART_TRANSLATE_EN (1 << 0) # define RADEON_DIS_OUT_OF_PCI_GART_ACCESS (1 << 1) +# define RS400_MSI_REARM (1 << 3) /* rs400/rs480 */ #define RADEON_AIC_LO_ADDR 0x01dc #define RADEON_AIC_PT_BASE 0x01d8 #define RADEON_AIC_HI_ADDR 0x01e0 diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 10dfa78762da..942754c39be9 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -242,7 +242,7 @@ void rs600_irq_disable(struct radeon_device *rdev) int rs600_irq_process(struct radeon_device *rdev) { - uint32_t status; + uint32_t status, msi_rearm; uint32_t r500_disp_int; status = rs600_irq_ack(rdev, &r500_disp_int); @@ -260,6 +260,22 @@ int rs600_irq_process(struct radeon_device *rdev) drm_handle_vblank(rdev->ddev, 1); status = rs600_irq_ack(rdev, &r500_disp_int); } + if (rdev->msi_enabled) { + switch (rdev->family) { + case CHIP_RS600: + case CHIP_RS690: + case CHIP_RS740: + msi_rearm = RREG32(RADEON_BUS_CNTL) & ~RS600_MSI_REARM; + WREG32(RADEON_BUS_CNTL, msi_rearm); + WREG32(RADEON_BUS_CNTL, msi_rearm | RS600_MSI_REARM); + break; + default: + msi_rearm = RREG32(RADEON_MSI_REARM_EN) & ~RV370_MSI_REARM_EN; + WREG32(RADEON_MSI_REARM_EN, msi_rearm); + WREG32(RADEON_MSI_REARM_EN, msi_rearm | RV370_MSI_REARM_EN); + break; + } + } return IRQ_HANDLED; } From 0a5c1e61dbaceb6ce56281a3128a6912b0dcd043 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Tue, 20 Oct 2009 07:23:07 -0500 Subject: [PATCH 32/46] drm/radeon: A bit of cleanup work on radeon_freelist_get() Fix the main loop to search all buffers before sleeping. Remove dead code Signed-off-by: Robert Noland Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_cp.c | 45 +++--------------------------- 1 file changed, 4 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index 4f7afc79dd82..0b2f9c2ad2c1 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c @@ -1941,8 +1941,8 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev) for (t = 0; t < dev_priv->usec_timeout; t++) { u32 done_age = GET_SCRATCH(dev_priv, 1); DRM_DEBUG("done_age = %d\n", done_age); - for (i = start; i < dma->buf_count; i++) { - buf = dma->buflist[i]; + for (i = 0; i < dma->buf_count; i++) { + buf = dma->buflist[start]; buf_priv = buf->dev_private; if (buf->file_priv == NULL || (buf->pending && buf_priv->age <= @@ -1951,7 +1951,8 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev) buf->pending = 0; return buf; } - start = 0; + if (++start >= dma->buf_count) + start = 0; } if (t) { @@ -1960,47 +1961,9 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev) } } - DRM_DEBUG("returning NULL!\n"); return NULL; } -#if 0 -struct drm_buf *radeon_freelist_get(struct drm_device * dev) -{ - struct drm_device_dma *dma = dev->dma; - drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_buf_priv_t *buf_priv; - struct drm_buf *buf; - int i, t; - int start; - u32 done_age; - - done_age = radeon_read_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1)); - if (++dev_priv->last_buf >= dma->buf_count) - dev_priv->last_buf = 0; - - start = dev_priv->last_buf; - dev_priv->stats.freelist_loops++; - - for (t = 0; t < 2; t++) { - for (i = start; i < dma->buf_count; i++) { - buf = dma->buflist[i]; - buf_priv = buf->dev_private; - if (buf->file_priv == 0 || (buf->pending && - buf_priv->age <= - done_age)) { - dev_priv->stats.requested_bufs++; - buf->pending = 0; - return buf; - } - } - start = 0; - } - - return NULL; -} -#endif - void radeon_freelist_reset(struct drm_device * dev) { struct drm_device_dma *dma = dev->dma; From c182be37ed7cb04c344501b88b8fdb747016e6cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Sat, 12 Sep 2009 04:33:34 +1000 Subject: [PATCH 33/46] drm: Add async event synchronization for drmWaitVblank MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a new flag to the drmWaitVblank ioctl, which asks the drm to return immediately and notify userspace when the specified vblank sequence happens by sending an event back on the drm fd. The event mechanism works with the other flags supported by the ioctls, specifically, the vblank sequence can be specified relatively or absolutely, and works for primary and seconday crtc. The signal field of the vblank request is used to provide user data, which will be sent back to user space in the vblank event. Signed-off-by: Kristian Høgsberg Reviewed-by: Jesse Barnes Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fops.c | 98 ++++++++++++++++++++++++++++++++- drivers/gpu/drm/drm_irq.c | 95 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_stub.c | 2 + drivers/gpu/drm/i915/i915_drv.c | 1 + include/drm/drm.h | 33 ++++++++++- include/drm/drmP.h | 26 +++++++++ 6 files changed, 251 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 251bc0e3b5ec..8ac7fbf6b2b7 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -257,6 +257,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp, INIT_LIST_HEAD(&priv->lhead); INIT_LIST_HEAD(&priv->fbs); + INIT_LIST_HEAD(&priv->event_list); + init_waitqueue_head(&priv->event_wait); + priv->event_space = 4096; /* set aside 4k for event buffer */ if (dev->driver->driver_features & DRIVER_GEM) drm_gem_open(dev, priv); @@ -413,6 +416,30 @@ static void drm_master_release(struct drm_device *dev, struct file *filp) } } +static void drm_events_release(struct drm_file *file_priv) +{ + struct drm_device *dev = file_priv->minor->dev; + struct drm_pending_event *e, *et; + struct drm_pending_vblank_event *v, *vt; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + + /* Remove pending flips */ + list_for_each_entry_safe(v, vt, &dev->vblank_event_list, base.link) + if (v->base.file_priv == file_priv) { + list_del(&v->base.link); + drm_vblank_put(dev, v->pipe); + v->base.destroy(&v->base); + } + + /* Remove unconsumed events */ + list_for_each_entry_safe(e, et, &file_priv->event_list, link) + e->destroy(e); + + spin_unlock_irqrestore(&dev->event_lock, flags); +} + /** * Release file. * @@ -451,6 +478,8 @@ int drm_release(struct inode *inode, struct file *filp) if (file_priv->minor->master) drm_master_release(dev, filp); + drm_events_release(file_priv); + if (dev->driver->driver_features & DRIVER_GEM) drm_gem_release(dev, file_priv); @@ -544,9 +573,74 @@ int drm_release(struct inode *inode, struct file *filp) } EXPORT_SYMBOL(drm_release); -/** No-op. */ +static bool +drm_dequeue_event(struct drm_file *file_priv, + size_t total, size_t max, struct drm_pending_event **out) +{ + struct drm_device *dev = file_priv->minor->dev; + struct drm_pending_event *e; + unsigned long flags; + bool ret = false; + + spin_lock_irqsave(&dev->event_lock, flags); + + *out = NULL; + if (list_empty(&file_priv->event_list)) + goto out; + e = list_first_entry(&file_priv->event_list, + struct drm_pending_event, link); + if (e->event->length + total > max) + goto out; + + file_priv->event_space += e->event->length; + list_del(&e->link); + *out = e; + ret = true; + +out: + spin_unlock_irqrestore(&dev->event_lock, flags); + return ret; +} + +ssize_t drm_read(struct file *filp, char __user *buffer, + size_t count, loff_t *offset) +{ + struct drm_file *file_priv = filp->private_data; + struct drm_pending_event *e; + size_t total; + ssize_t ret; + + ret = wait_event_interruptible(file_priv->event_wait, + !list_empty(&file_priv->event_list)); + if (ret < 0) + return ret; + + total = 0; + while (drm_dequeue_event(file_priv, total, count, &e)) { + if (copy_to_user(buffer + total, + e->event, e->event->length)) { + total = -EFAULT; + break; + } + + total += e->event->length; + e->destroy(e); + } + + return total; +} +EXPORT_SYMBOL(drm_read); + unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) { - return 0; + struct drm_file *file_priv = filp->private_data; + unsigned int mask = 0; + + poll_wait(filp, &file_priv->event_wait, wait); + + if (!list_empty(&file_priv->event_list)) + mask |= POLLIN | POLLRDNORM; + + return mask; } EXPORT_SYMBOL(drm_poll); diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index f85aaf21e783..d9af7964f81c 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -523,6 +523,62 @@ out: return ret; } +static int drm_queue_vblank_event(struct drm_device *dev, int pipe, + union drm_wait_vblank *vblwait, + struct drm_file *file_priv) +{ + struct drm_pending_vblank_event *e; + struct timeval now; + unsigned long flags; + unsigned int seq; + + e = kzalloc(sizeof *e, GFP_KERNEL); + if (e == NULL) + return -ENOMEM; + + e->pipe = pipe; + e->event.base.type = DRM_EVENT_VBLANK; + e->event.base.length = sizeof e->event; + e->event.user_data = vblwait->request.signal; + e->base.event = &e->event.base; + e->base.file_priv = file_priv; + e->base.destroy = (void (*) (struct drm_pending_event *)) kfree; + + do_gettimeofday(&now); + spin_lock_irqsave(&dev->event_lock, flags); + + if (file_priv->event_space < sizeof e->event) { + spin_unlock_irqrestore(&dev->event_lock, flags); + kfree(e); + return -ENOMEM; + } + + file_priv->event_space -= sizeof e->event; + seq = drm_vblank_count(dev, pipe); + if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) && + (seq - vblwait->request.sequence) <= (1 << 23)) { + vblwait->request.sequence = seq + 1; + } + + DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n", + vblwait->request.sequence, seq, pipe); + + e->event.sequence = vblwait->request.sequence; + if ((seq - vblwait->request.sequence) <= (1 << 23)) { + e->event.tv_sec = now.tv_sec; + e->event.tv_usec = now.tv_usec; + drm_vblank_put(dev, e->pipe); + list_add_tail(&e->base.link, &e->base.file_priv->event_list); + wake_up_interruptible(&e->base.file_priv->event_wait); + } else { + list_add_tail(&e->base.link, &dev->vblank_event_list); + } + + spin_unlock_irqrestore(&dev->event_lock, flags); + + return 0; +} + /** * Wait for VBLANK. * @@ -582,6 +638,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, goto done; } + if (flags & _DRM_VBLANK_EVENT) + return drm_queue_vblank_event(dev, crtc, vblwait, file_priv); + if ((flags & _DRM_VBLANK_NEXTONMISS) && (seq - vblwait->request.sequence) <= (1<<23)) { vblwait->request.sequence = seq + 1; @@ -614,6 +673,38 @@ done: return ret; } +void drm_handle_vblank_events(struct drm_device *dev, int crtc) +{ + struct drm_pending_vblank_event *e, *t; + struct timeval now; + unsigned long flags; + unsigned int seq; + + do_gettimeofday(&now); + seq = drm_vblank_count(dev, crtc); + + spin_lock_irqsave(&dev->event_lock, flags); + + list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { + if (e->pipe != crtc) + continue; + if ((seq - e->event.sequence) > (1<<23)) + continue; + + DRM_DEBUG("vblank event on %d, current %d\n", + e->event.sequence, seq); + + e->event.sequence = seq; + e->event.tv_sec = now.tv_sec; + e->event.tv_usec = now.tv_usec; + drm_vblank_put(dev, e->pipe); + list_move_tail(&e->base.link, &e->base.file_priv->event_list); + wake_up_interruptible(&e->base.file_priv->event_wait); + } + + spin_unlock_irqrestore(&dev->event_lock, flags); +} + /** * drm_handle_vblank - handle a vblank event * @dev: DRM device @@ -624,7 +715,11 @@ done: */ void drm_handle_vblank(struct drm_device *dev, int crtc) { + if (!dev->num_crtcs) + return; + atomic_inc(&dev->_vblank_count[crtc]); DRM_WAKEUP(&dev->vbl_queue[crtc]); + drm_handle_vblank_events(dev, crtc); } EXPORT_SYMBOL(drm_handle_vblank); diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 55bb8a82d612..adb864dfef3e 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -220,9 +220,11 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, INIT_LIST_HEAD(&dev->ctxlist); INIT_LIST_HEAD(&dev->vmalist); INIT_LIST_HEAD(&dev->maplist); + INIT_LIST_HEAD(&dev->vblank_event_list); spin_lock_init(&dev->count_lock); spin_lock_init(&dev->drw_lock); + spin_lock_init(&dev->event_lock); init_timer(&dev->timer); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index dbe568c9327b..b81305e33c79 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -206,6 +206,7 @@ static struct drm_driver driver = { .mmap = drm_gem_mmap, .poll = drm_poll, .fasync = drm_fasync, + .read = drm_read, #ifdef CONFIG_COMPAT .compat_ioctl = i915_compat_ioctl, #endif diff --git a/include/drm/drm.h b/include/drm/drm.h index 7cb50bdde46d..fa6d9155873d 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h @@ -454,6 +454,7 @@ struct drm_irq_busid { enum drm_vblank_seq_type { _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + _DRM_VBLANK_EVENT = 0x4000000, /**< Send event instead of blocking */ _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ @@ -461,8 +462,8 @@ enum drm_vblank_seq_type { }; #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) -#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY | \ - _DRM_VBLANK_NEXTONMISS) +#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_EVENT | _DRM_VBLANK_SIGNAL | \ + _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS) struct drm_wait_vblank_request { enum drm_vblank_seq_type type; @@ -698,6 +699,34 @@ struct drm_gem_open { #define DRM_COMMAND_BASE 0x40 #define DRM_COMMAND_END 0xA0 +/** + * Header for events written back to userspace on the drm fd. The + * type defines the type of event, the length specifies the total + * length of the event (including the header), and user_data is + * typically a 64 bit value passed with the ioctl that triggered the + * event. A read on the drm fd will always only return complete + * events, that is, if for example the read buffer is 100 bytes, and + * there are two 64 byte events pending, only one will be returned. + * + * Event types 0 - 0x7fffffff are generic drm events, 0x80000000 and + * up are chipset specific. + */ +struct drm_event { + __u32 type; + __u32 length; +}; + +#define DRM_EVENT_VBLANK 0x01 + +struct drm_event_vblank { + struct drm_event base; + __u64 user_data; + __u32 tv_sec; + __u32 tv_usec; + __u32 sequence; + __u32 reserved; +}; + /* typedef area */ #ifndef __KERNEL__ typedef struct drm_clip_rect drm_clip_rect_t; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index eeefb6369e19..fe52254df60c 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -426,6 +426,14 @@ struct drm_buf_entry { struct drm_freelist freelist; }; +/* Event queued up for userspace to read */ +struct drm_pending_event { + struct drm_event *event; + struct list_head link; + struct drm_file *file_priv; + void (*destroy)(struct drm_pending_event *event); +}; + /** File private data */ struct drm_file { int authenticated; @@ -449,6 +457,10 @@ struct drm_file { struct drm_master *master; /* master this node is currently associated with N.B. not always minor->master */ struct list_head fbs; + + wait_queue_head_t event_wait; + struct list_head event_list; + int event_space; }; /** Wait queue */ @@ -897,6 +909,12 @@ struct drm_minor { struct drm_mode_group mode_group; }; +struct drm_pending_vblank_event { + struct drm_pending_event base; + int pipe; + struct drm_event_vblank event; +}; + /** * DRM device structure. This structure represent a complete card that * may contain multiple heads. @@ -996,6 +1014,12 @@ struct drm_device { u32 max_vblank_count; /**< size of vblank counter register */ + /** + * List of events + */ + struct list_head vblank_event_list; + spinlock_t event_lock; + /*@} */ cycles_t ctx_start; cycles_t lck_start; @@ -1132,6 +1156,8 @@ extern int drm_lastclose(struct drm_device *dev); extern int drm_open(struct inode *inode, struct file *filp); extern int drm_stub_open(struct inode *inode, struct file *filp); extern int drm_fasync(int fd, struct file *filp, int on); +extern ssize_t drm_read(struct file *filp, char __user *buffer, + size_t count, loff_t *offset); extern int drm_release(struct inode *inode, struct file *filp); /* Mapping support (drm_vm.h) */ From 8f552a66a40bcc6e903e91310f42fe140e0342c4 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 27 Oct 2009 11:16:09 -0400 Subject: [PATCH 34/46] drm/radeon/kms/atom: loosen pll min output limits Limiting the pll output range is a good thing generally as it limits the number of possible pll combinations for a given frequency presumably to the ones that work best on each card. That's why the limits are in the bios tables. However, certain duallink DVI monitors seem to like pll combinations that would be limited by this at least on pre-DCE 3.0 r6xx hardware. This might need to be adjusted per family or per clock range in the future. See fdo bug 24727. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 18729259c2fc..1c9a9c461762 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -655,6 +655,16 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) p1pll->pll_out_min = 64800; else p1pll->pll_out_min = 20000; + } else if (p1pll->pll_out_min > 64800) { + /* Limiting the pll output range is a good thing generally as + * it limits the number of possible pll combinations for a given + * frequency presumably to the ones that work best on each card. + * However, certain duallink DVI monitors seem to like + * pll combinations that would be limited by this at least on + * pre-DCE 3.0 r6xx hardware. This might need to be adjusted per + * family. + */ + p1pll->pll_out_min = 64800; } p1pll->pll_in_min = From d56ef9c8fd34ed29ffae27598a864b4a9a82521b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 27 Oct 2009 12:11:09 -0400 Subject: [PATCH 35/46] drm/radeon/kms/atom: Fix DVO support DVO in 12 bit mode (which seems to be the most common config) requires 2x ppll. Fixes fdo bug 21857. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index e5a3c301b7a9..8516e1b2329a 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -483,8 +483,14 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&adjust_pll_args); adjusted_clock = le16_to_cpu(adjust_pll_args.usPixelClock) * 10; - } else - adjusted_clock = mode->clock; + } else { + /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ + if (ASIC_IS_AVIVO(rdev) && + (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)) + adjusted_clock = mode->clock * 2; + else + adjusted_clock = mode->clock; + } if (radeon_crtc->crtc_id == 0) pll = &rdev->clock.p1pll; From 61c4b24b3e3bb83bfe29f24fe566281b4f722237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20Fr=C3=B6hlich?= Date: Tue, 27 Oct 2009 15:08:01 -0400 Subject: [PATCH 36/46] drm/radeon/kms/atom: Make card_info per device Make the struct card_info, which is a per struct radeon_device dataset, a struct member of the radeon device instead of a static per kernel module value. This should avoid potential problems with two radeon cards installed in one system. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_device.c | 29 +++++++++++++++----------- drivers/gpu/drm/radeon/radeon_mode.h | 1 + 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index d1cdda9b5586..88c19070247f 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -443,20 +443,24 @@ static uint32_t cail_reg_read(struct card_info *info, uint32_t reg) return r; } -static struct card_info atom_card_info = { - .dev = NULL, - .reg_read = cail_reg_read, - .reg_write = cail_reg_write, - .mc_read = cail_mc_read, - .mc_write = cail_mc_write, - .pll_read = cail_pll_read, - .pll_write = cail_pll_write, -}; - int radeon_atombios_init(struct radeon_device *rdev) { - atom_card_info.dev = rdev->ddev; - rdev->mode_info.atom_context = atom_parse(&atom_card_info, rdev->bios); + struct card_info *atom_card_info = + kzalloc(sizeof(struct card_info), GFP_KERNEL); + + if (!atom_card_info) + return -ENOMEM; + + rdev->mode_info.atom_card_info = atom_card_info; + atom_card_info->dev = rdev->ddev; + atom_card_info->reg_read = cail_reg_read; + atom_card_info->reg_write = cail_reg_write; + atom_card_info->mc_read = cail_mc_read; + atom_card_info->mc_write = cail_mc_write; + atom_card_info->pll_read = cail_pll_read; + atom_card_info->pll_write = cail_pll_write; + + rdev->mode_info.atom_context = atom_parse(atom_card_info, rdev->bios); radeon_atom_initialize_bios_scratch_regs(rdev->ddev); return 0; } @@ -464,6 +468,7 @@ int radeon_atombios_init(struct radeon_device *rdev) void radeon_atombios_fini(struct radeon_device *rdev) { kfree(rdev->mode_info.atom_context); + kfree(rdev->mode_info.atom_card_info); } int radeon_combios_init(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 2ea5707c018c..ccb783868ad6 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -172,6 +172,7 @@ enum radeon_connector_table { struct radeon_mode_info { struct atom_context *atom_context; + struct card_info *atom_card_info; enum radeon_connector_table connector_table; bool mode_config_initialized; struct radeon_crtc *crtcs[2]; From a2d49ae7df5b96fba3c63710df61412587fc6a24 Mon Sep 17 00:00:00 2001 From: James Simmons Date: Tue, 27 Oct 2009 21:09:24 +0000 Subject: [PATCH 37/46] drm/kms: typo fix I believe this is a typo. Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 9c924614c418..dc8e374a0b55 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -707,7 +707,7 @@ int drm_fb_helper_set_par(struct fb_info *info) if (crtc->fb == fb_helper->crtc_info[i].mode_set.fb) { mutex_lock(&dev->mode_config.mutex); - ret = crtc->funcs->set_config(&fb_helper->crtc_info->mode_set); + ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set); mutex_unlock(&dev->mode_config.mutex); if (ret) return ret; From d11aa88b33b071d55181a7a482b9e7494888c10e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 28 Oct 2009 00:51:20 -0400 Subject: [PATCH 38/46] drm/radeon/kms/atom: fix potential oops in spread spectrum code Make sure we have an LVDS encoder before casting enc_priv. [airlied: also fix two missing cpu_to_le16 casts we noticed on irc] Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 8516e1b2329a..c15287a590ff 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -368,14 +368,17 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc == crtc) { radeon_encoder = to_radeon_encoder(encoder); - dig = radeon_encoder->enc_priv; /* only enable spread spectrum on LVDS */ - if (dig && dig->ss) { - percentage = dig->ss->percentage; - type = dig->ss->type; - step = dig->ss->step; - delay = dig->ss->delay; - range = dig->ss->range; + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + dig = radeon_encoder->enc_priv; + if (dig && dig->ss) { + percentage = dig->ss->percentage; + type = dig->ss->type; + step = dig->ss->step; + delay = dig->ss->delay; + range = dig->ss->range; + } else if (enable) + return; } else if (enable) return; break; @@ -387,7 +390,7 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable) if (ASIC_IS_AVIVO(rdev)) { memset(&args, 0, sizeof(args)); - args.usSpreadSpectrumPercentage = percentage; + args.usSpreadSpectrumPercentage = cpu_to_le16(percentage); args.ucSpreadSpectrumType = type; args.ucSpreadSpectrumStep = step; args.ucSpreadSpectrumDelay = delay; @@ -397,7 +400,7 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable) atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } else { memset(&legacy_args, 0, sizeof(legacy_args)); - legacy_args.usSpreadSpectrumPercentage = percentage; + legacy_args.usSpreadSpectrumPercentage = cpu_to_le16(percentage); legacy_args.ucSpreadSpectrumType = type; legacy_args.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2; legacy_args.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4; From fc7f7119d2ed97fff1aaddad6bf7d61ed446cf37 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 28 Oct 2009 01:46:54 -0400 Subject: [PATCH 39/46] drm/radeon/kms: add quirk for hp dc5750 Doesn't have a tv-out port Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_combios.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index fcb9371bf057..a36ede002ee4 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -1587,6 +1587,12 @@ static bool radeon_apply_legacy_tv_quirks(struct drm_device *dev) dev->pdev->subsystem_device == 0x009f) return false; + /* HP dc5750 has non-existent TV port */ + if (dev->pdev->device == 0x5974 && + dev->pdev->subsystem_vendor == 0x103c && + dev->pdev->subsystem_device == 0x280a) + return false; + return true; } From ea1495a6274c9542a168337536f8ce74d1173f23 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 27 Oct 2009 11:57:53 +1100 Subject: [PATCH 40/46] drm/radeon/kms: fix rc410 suspend/resume. This fixes suspend/resume on my rc410 motherboard, it restores the memory controller setup before posting the GPU, since it seems to need the MC_FB_LOCATION setup correctly. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/rs400.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index a769c296f6a6..ca037160a582 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -418,6 +418,8 @@ int rs400_resume(struct radeon_device *rdev) rs400_gart_disable(rdev); /* Resume clock before doing reset */ r300_clock_startup(rdev); + /* setup MC before calling post tables */ + rs400_mc_program(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ if (radeon_gpu_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", From df67bed92fa86ef926da8b62a6da68722388ff72 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 Oct 2009 13:31:26 +1000 Subject: [PATCH 41/46] drm/radeon/kms: fix coherency issues on AGP cards. When we are evicting from VRAM->RAM we allocate the ttm object, but we don't set the caching policy on it before blitting into it. This means on AGP we end up blitting into cached pages, and the CPU later flushes out on top of them. This was mostly seen as font corruption. The other question is why we don't evict VRAM->GTT in a lot of cases, this would save us some cache transitions since a lot of objects that are evicted from VRAM will probably end up being pulled back in a few operations later, and evicting them to system memory involves 2 unnecessary cache transitions. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_ttm.c | 6 ++++++ drivers/gpu/drm/ttm/ttm_tt.c | 1 + 2 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index c729cd1a7506..f489c0de6f13 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -295,6 +295,12 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo, if (unlikely(r)) { return r; } + + r = ttm_tt_set_placement_caching(bo->ttm, tmp_mem.placement); + if (unlikely(r)) { + goto out_cleanup; + } + r = ttm_tt_bind(bo->ttm, &tmp_mem); if (unlikely(r)) { goto out_cleanup; diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index a55ee1a56c16..7bcb89f39ce8 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -279,6 +279,7 @@ int ttm_tt_set_placement_caching(struct ttm_tt *ttm, uint32_t placement) return ttm_tt_set_caching(ttm, state); } +EXPORT_SYMBOL(ttm_tt_set_placement_caching); static void ttm_tt_free_alloced_pages(struct ttm_tt *ttm) { From d6f28938d9426d12eea1578949f1d73d24ad37ec Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 2 Nov 2009 16:01:27 -0500 Subject: [PATCH 42/46] drm/radeon/kms: Don't RMW CP_RB_CNTL Immediate readback seems faulty on some chips. I suspect it takes a while to get through the fifo to the actual register backbone. There's no need to read it back, so, just write the driver's copy of the register's value directly. Should fix bug 24535 and possibly 24218 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 12 ++++++------ drivers/gpu/drm/radeon/r600.c | 8 +++----- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index b438b520ee7f..5e821a313a8c 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -578,19 +578,19 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size) indirect1_start = 16; /* cp setup */ WREG32(0x718, pre_write_timer | (pre_write_limit << 28)); - WREG32(RADEON_CP_RB_CNTL, -#ifdef __BIG_ENDIAN - RADEON_BUF_SWAP_32BIT | -#endif - REG_SET(RADEON_RB_BUFSZ, rb_bufsz) | + tmp = (REG_SET(RADEON_RB_BUFSZ, rb_bufsz) | REG_SET(RADEON_RB_BLKSZ, rb_blksz) | REG_SET(RADEON_MAX_FETCH, max_fetch) | RADEON_RB_NO_UPDATE); +#ifdef __BIG_ENDIAN + tmp |= RADEON_BUF_SWAP_32BIT; +#endif + WREG32(RADEON_CP_RB_CNTL, tmp); + /* Set ring address */ DRM_INFO("radeon: ring at 0x%016lX\n", (unsigned long)rdev->cp.gpu_addr); WREG32(RADEON_CP_RB_BASE, rdev->cp.gpu_addr); /* Force read & write ptr to 0 */ - tmp = RREG32(RADEON_CP_RB_CNTL); WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA); WREG32(RADEON_CP_RB_RPTR_WR, 0); WREG32(RADEON_CP_RB_WPTR, 0); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index e87475c87d52..60fbb236edfd 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1272,19 +1272,17 @@ int r600_cp_resume(struct radeon_device *rdev) /* Set ring buffer size */ rb_bufsz = drm_order(rdev->cp.ring_size / 8); + tmp = RB_NO_UPDATE | (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; #ifdef __BIG_ENDIAN - WREG32(CP_RB_CNTL, BUF_SWAP_32BIT | RB_NO_UPDATE | - (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz); -#else - WREG32(CP_RB_CNTL, RB_NO_UPDATE | (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz); + tmp |= BUF_SWAP_32BIT; #endif + WREG32(CP_RB_CNTL, tmp); 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); From 8a9832e89ff1bc7a039c8f966f07101570be3d5e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 3 Nov 2009 13:23:15 +1000 Subject: [PATCH 43/46] drm/radeon/kms: disable D1VGA and D2VGA if enabled Once kms is enabled we don't need these, and it causes a problem with the Lenovo W500 ACPI brightness implementation, it hangs in a loop inside an SMI. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/rv515.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 41a34c23e6d8..03c052d892c0 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -137,6 +137,8 @@ int rv515_mc_wait_for_idle(struct radeon_device *rdev) void rv515_vga_render_disable(struct radeon_device *rdev) { + WREG32(R_000330_D1VGA_CONTROL, 0); + WREG32(R_000338_D2VGA_CONTROL, 0); WREG32(R_000300_VGA_RENDER_CONTROL, RREG32(R_000300_VGA_RENDER_CONTROL) & C_000300_VGA_VSTATUS_CNTL); } From 4d357abb895ec51f1cbdebb1fbbf4d4576900a2e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 3 Nov 2009 14:54:36 +1000 Subject: [PATCH 44/46] drm/radeon/kms: stop putting VRAM at 0 in MC space on r600s. The Lenovo W500 laptop hangs inside an SMI on brightness changes, I thought it just needed the VGA disable but it turned out to require slightly more work, setting the MC locations up just like the IGP chip requirements seems to make it all happy again and I can boot and play with brightness. We should probably just do this for all chips and give up the VRAM at 0x0 idea, it never seems to buy us anything but pain. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 48 +++++++++++++++-------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 60fbb236edfd..3e5703f324bd 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -409,35 +409,29 @@ int r600_mc_init(struct radeon_device *rdev) 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; + rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + rdev->mc.vram_location = (RREG32(MC_VM_FB_LOCATION) & + 0xFFFF) << 24; + 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 { - rdev->mc.vram_location = 0x00000000UL; - rdev->mc.gtt_location = rdev->mc.mc_vram_size; - rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + /* 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; } rdev->mc.vram_start = rdev->mc.vram_location; rdev->mc.vram_end = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1; From 6fa8d66af83710b3610bd3b2581f051074f2b416 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 3 Nov 2009 16:10:36 -0500 Subject: [PATCH 45/46] drm/radeon/kms: remove some misleading debugging output Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_bios.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 34a9b9119518..906921740c60 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -50,19 +50,16 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev) vram_base = drm_get_resource_start(rdev->ddev, 0); bios = ioremap(vram_base, size); if (!bios) { - DRM_ERROR("Unable to mmap vram\n"); return false; } if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) { iounmap(bios); - DRM_ERROR("bad rom signature\n"); return false; } rdev->bios = kmalloc(size, GFP_KERNEL); if (rdev->bios == NULL) { iounmap(bios); - DRM_ERROR("kmalloc failed\n"); return false; } memcpy(rdev->bios, bios, size); From e29649db3bd5620499bf9bdcd63c5cf12edbd26e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 3 Nov 2009 10:04:01 -0500 Subject: [PATCH 46/46] drm/radeon/kms/r700: fix some typos in chip init Noticed by Andre on IRC. Also fix up some minor whitespace issues. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/rv770.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 40553913b928..ae074fdf804d 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -529,11 +529,11 @@ static void rv770_gpu_init(struct radeon_device *rdev) 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 |= BANK_TILING((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT); gb_tiling_config |= GROUP_SIZE(0); - if (((mc_arb_ramcfg & NOOFROWS_MASK) & NOOFROWS_SHIFT) > 3) { + if (((mc_arb_ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT) > 3) { gb_tiling_config |= ROW_TILING(3); gb_tiling_config |= SAMPLE_SPLIT(3); } else { @@ -579,14 +579,14 @@ static void rv770_gpu_init(struct radeon_device *rdev) /* set HW defaults for 3D engine */ WREG32(CP_QUEUE_THRESHOLDS, (ROQ_IB1_START(0x16) | - ROQ_IB2_START(0x2b))); + ROQ_IB2_START(0x2b))); WREG32(CP_MEQ_THRESHOLDS, STQ_SPLIT(0x30)); WREG32(TA_CNTL_AUX, (DISABLE_CUBE_ANISO | - SYNC_GRADIENT | - SYNC_WALKER | - SYNC_ALIGNER)); + SYNC_GRADIENT | + SYNC_WALKER | + SYNC_ALIGNER)); sx_debug_1 = RREG32(SX_DEBUG_1); sx_debug_1 |= ENABLE_NEW_SMX_ADDRESS; @@ -598,9 +598,9 @@ static void rv770_gpu_init(struct radeon_device *rdev) 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)); + GS_FLUSH_CTL(4) | + ACK_FLUSH_CTL(3) | + SYNC_FLUSH_CTL)); if (rdev->family == CHIP_RV770) WREG32(DB_DEBUG3, DB_CLK_OFF_DELAY(0x1f)); @@ -611,12 +611,12 @@ static void rv770_gpu_init(struct radeon_device *rdev) } 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))); + 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))); + 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);