diff options
Diffstat (limited to 'drivers/gpu/drm/radeon')
22 files changed, 266 insertions, 44 deletions
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index 9a0aee2..88661ea 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -1301,8 +1301,11 @@ struct atom_context *atom_parse(struct card_info *card, void *bios) int atom_asic_init(struct atom_context *ctx) { + struct radeon_device *rdev = ctx->card->dev->dev_private; int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR); uint32_t ps[16]; + int ret; + memset(ps, 0, 64); ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR)); @@ -1312,7 +1315,17 @@ int atom_asic_init(struct atom_context *ctx) if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT)) return 1; - return atom_execute_table(ctx, ATOM_CMD_INIT, ps); + ret = atom_execute_table(ctx, ATOM_CMD_INIT, ps); + if (ret) + return ret; + + memset(ps, 0, 64); + + if (rdev->family < CHIP_R600) { + if (CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_SPDFANCNTL)) + atom_execute_table(ctx, ATOM_CMD_SPDFANCNTL, ps); + } + return ret; } void atom_destroy(struct atom_context *ctx) diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h index 93cfe20..25fea63 100644 --- a/drivers/gpu/drm/radeon/atom.h +++ b/drivers/gpu/drm/radeon/atom.h @@ -44,6 +44,7 @@ #define ATOM_CMD_SETSCLK 0x0A #define ATOM_CMD_SETMCLK 0x0B #define ATOM_CMD_SETPCLK 0x0C +#define ATOM_CMD_SPDFANCNTL 0x39 #define ATOM_DATA_FWI_PTR 0xC #define ATOM_DATA_IIO_PTR 0x32 diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 9541995..071ded1 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1173,7 +1173,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, - crtc->mode.vdisplay); + target_fb->height); x &= ~3; y &= ~1; WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, @@ -1342,7 +1342,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, - crtc->mode.vdisplay); + target_fb->height); x &= ~3; y &= ~1; WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 79e8ebc..3b77ad6 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -283,7 +283,7 @@ int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, } } - DRM_ERROR("aux i2c too many retries, giving up\n"); + DRM_DEBUG_KMS("aux i2c too many retries, giving up\n"); return -EREMOTEIO; } @@ -553,6 +553,7 @@ static void radeon_dp_set_panel_mode(struct drm_encoder *encoder, { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; if (!ASIC_IS_DCE4(rdev)) @@ -560,10 +561,20 @@ static void radeon_dp_set_panel_mode(struct drm_encoder *encoder, if (radeon_connector_encoder_is_dp_bridge(connector)) panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE; + else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + u8 tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); + if (tmp & 1) + panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; + } atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP_PANEL_MODE, panel_mode); + + if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) && + (panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)) { + radeon_write_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_SET, 1); + } } void radeon_dp_set_link_config(struct drm_connector *connector, diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index ea7a24e..fe052c6 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -82,6 +82,7 @@ u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; u32 tmp = RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset); + int i; /* Lock the graphics update lock */ tmp |= EVERGREEN_GRPH_UPDATE_LOCK; @@ -99,7 +100,11 @@ u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) (u32)crtc_base); /* Wait for update_pending to go high. */ - while (!(RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING)); + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING) + break; + udelay(1); + } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); /* Unlock the lock, so double-buffering can take place inside vblank */ @@ -353,6 +358,7 @@ void evergreen_hpd_init(struct radeon_device *rdev) default: break; } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) evergreen_irq_set(rdev); @@ -3251,6 +3257,18 @@ int evergreen_init(struct radeon_device *rdev) rdev->accel_working = false; } } + + /* Don't start up if the MC ucode is missing on BTC parts. + * The default clocks and voltages before the MC ucode + * is loaded are not suffient for advanced operations. + */ + if (ASIC_IS_DCE5(rdev)) { + if (!rdev->mc_fw && !(rdev->flags & RADEON_IS_IGP)) { + DRM_ERROR("radeon: MC ucode required for NI+.\n"); + return -EINVAL; + } + } + return 0; } diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 7fcdbbb..d94f440 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -84,13 +84,18 @@ u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK; + int i; /* Lock the graphics update lock */ /* update the scanout addresses */ WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp); /* Wait for update_pending to go high. */ - while (!(RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET)); + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET) + break; + udelay(1); + } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); /* Unlock the lock, so double-buffering can take place inside vblank */ @@ -434,6 +439,7 @@ void r100_hpd_init(struct radeon_device *rdev) default: break; } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) r100_irq_set(rdev); @@ -675,9 +681,7 @@ int r100_irq_process(struct radeon_device *rdev) 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); + WREG32(RADEON_MSI_REARM_EN, RV370_MSI_REARM_EN); break; } } @@ -2063,6 +2067,7 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev) void r100_bm_disable(struct radeon_device *rdev) { u32 tmp; + u16 tmp16; /* disable bus mastering */ tmp = RREG32(R_000030_BUS_CNTL); @@ -2073,8 +2078,8 @@ void r100_bm_disable(struct radeon_device *rdev) WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040); tmp = RREG32(RADEON_BUS_CNTL); mdelay(1); - pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp); - pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB); + pci_read_config_word(rdev->pdev, 0x4, &tmp16); + pci_write_config_word(rdev->pdev, 0x4, tmp16 & 0xFFFB); mdelay(1); } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 1dea9d6..1a4ed43 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -762,13 +762,14 @@ void r600_hpd_init(struct radeon_device *rdev) struct drm_device *dev = rdev->ddev; struct drm_connector *connector; - if (ASIC_IS_DCE3(rdev)) { - u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) | DC_HPDx_RX_INT_TIMER(0xfa); - if (ASIC_IS_DCE32(rdev)) - tmp |= DC_HPDx_EN; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + + if (ASIC_IS_DCE3(rdev)) { + u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) | DC_HPDx_RX_INT_TIMER(0xfa); + if (ASIC_IS_DCE32(rdev)) + tmp |= DC_HPDx_EN; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); switch (radeon_connector->hpd.hpd) { case RADEON_HPD_1: WREG32(DC_HPD1_CONTROL, tmp); @@ -798,10 +799,7 @@ void r600_hpd_init(struct radeon_device *rdev) default: break; } - } - } else { - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); + } else { switch (radeon_connector->hpd.hpd) { case RADEON_HPD_1: WREG32(DC_HOT_PLUG_DETECT1_CONTROL, DC_HOT_PLUG_DETECTx_EN); @@ -819,6 +817,7 @@ void r600_hpd_init(struct radeon_device *rdev) break; } } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) r600_irq_set(rdev); diff --git a/drivers/gpu/drm/radeon/r600_blit_shaders.c b/drivers/gpu/drm/radeon/r600_blit_shaders.c index 2d1f6c5..73e2c7c 100644 --- a/drivers/gpu/drm/radeon/r600_blit_shaders.c +++ b/drivers/gpu/drm/radeon/r600_blit_shaders.c @@ -314,6 +314,10 @@ const u32 r6xx_default_state[] = 0x00000000, /* VGT_VTX_CNT_EN */ 0xc0016900, + 0x000000d4, + 0x00000000, /* SX_MISC */ + + 0xc0016900, 0x000002c8, 0x00000000, /* VGT_STRMOUT_BUFFER_EN */ @@ -626,6 +630,10 @@ const u32 r7xx_default_state[] = 0x00000000, /* VGT_VTX_CNT_EN */ 0xc0016900, + 0x000000d4, + 0x00000000, /* SX_MISC */ + + 0xc0016900, 0x000002c8, 0x00000000, /* VGT_STRMOUT_BUFFER_EN */ diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index f5ac7e7..c45d921 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -196,6 +196,13 @@ static void r600_hdmi_videoinfoframe( frame[0xD] = (right_bar >> 8); r600_hdmi_infoframe_checksum(0x82, 0x02, 0x0D, frame); + /* Our header values (type, version, length) should be alright, Intel + * is using the same. Checksum function also seems to be OK, it works + * fine for audio infoframe. However calculated value is always lower + * by 2 in comparison to fglrx. It breaks displaying anything in case + * of TVs that strictly check the checksum. Hack it manually here to + * workaround this issue. */ + frame[0x0] += 2; WREG32(offset+R600_HDMI_VIDEOINFOFRAME_0, frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 0bb4ddf..59d72d0 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -93,6 +93,7 @@ extern int radeon_audio; extern int radeon_disp_priority; extern int radeon_hw_i2c; extern int radeon_pcie_gen2; +extern int radeon_msi; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index bf2b615..a324564 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -85,6 +85,18 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev for (i = 0; i < num_indices; i++) { gpio = &i2c_info->asGPIO_Info[i]; + /* r4xx mask is technically not used by the hw, so patch in the legacy mask bits */ + if ((rdev->family == CHIP_R420) || + (rdev->family == CHIP_R423) || + (rdev->family == CHIP_RV410)) { + if ((le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0018) || + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0019) || + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x001a)) { + gpio->ucClkMaskShift = 0x19; + gpio->ucDataMaskShift = 0x18; + } + } + /* some evergreen boards have bad data for this entry */ if (ASIC_IS_DCE4(rdev)) { if ((i == 7) && @@ -169,6 +181,18 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev) gpio = &i2c_info->asGPIO_Info[i]; i2c.valid = false; + /* r4xx mask is technically not used by the hw, so patch in the legacy mask bits */ + if ((rdev->family == CHIP_R420) || + (rdev->family == CHIP_R423) || + (rdev->family == CHIP_RV410)) { + if ((le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0018) || + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0019) || + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x001a)) { + gpio->ucClkMaskShift = 0x19; + gpio->ucDataMaskShift = 0x18; + } + } + /* some evergreen boards have bad data for this entry */ if (ASIC_IS_DCE4(rdev)) { if ((i == 7) && @@ -460,6 +484,20 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, struct radeon_device *rdev = dev->dev_private; *i2c_bus = radeon_lookup_i2c_gpio(rdev, 0x93); } + + /* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */ + if ((dev->pdev->device == 0x9802) && + (dev->pdev->subsystem_vendor == 0x1734) && + (dev->pdev->subsystem_device == 0x11bd)) { + if (*connector_type == DRM_MODE_CONNECTOR_VGA) { + *connector_type = DRM_MODE_CONNECTOR_DVII; + *line_mux = 0x3103; + } else if (*connector_type == DRM_MODE_CONNECTOR_DVID) { + *connector_type = DRM_MODE_CONNECTOR_DVII; + } + } + + return true; } @@ -2544,7 +2582,11 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; rdev->pm.current_clock_mode_index = 0; - rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; + if (rdev->pm.default_power_state_index >= 0) + rdev->pm.current_vddc = + rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; + else + rdev->pm.current_vddc = 0; } void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index cd3c86c..859df6b 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -620,8 +620,8 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde i2c.y_data_mask = 0x80; } else { /* default masks for ddc pads */ - i2c.mask_clk_mask = RADEON_GPIO_EN_1; - i2c.mask_data_mask = RADEON_GPIO_EN_0; + i2c.mask_clk_mask = RADEON_GPIO_MASK_1; + i2c.mask_data_mask = RADEON_GPIO_MASK_0; i2c.a_clk_mask = RADEON_GPIO_A_1; i2c.a_data_mask = RADEON_GPIO_A_0; i2c.en_clk_mask = RADEON_GPIO_EN_1; diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 05b8b2c..6ceb3c8 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -715,6 +715,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force) dret = radeon_ddc_probe(radeon_connector, radeon_connector->requires_extended_probe); if (dret) { + radeon_connector->detected_by_load = false; if (radeon_connector->edid) { kfree(radeon_connector->edid); radeon_connector->edid = NULL; @@ -741,12 +742,21 @@ radeon_vga_detect(struct drm_connector *connector, bool force) } else { /* if we aren't forcing don't do destructive polling */ - if (!force) - return connector->status; + if (!force) { + /* only return the previous status if we last + * detected a monitor via load. + */ + if (radeon_connector->detected_by_load) + return connector->status; + else + return ret; + } if (radeon_connector->dac_load_detect && encoder) { encoder_funcs = encoder->helper_private; ret = encoder_funcs->detect(encoder, connector); + if (ret != connector_status_disconnected) + radeon_connector->detected_by_load = true; } } @@ -888,6 +898,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) dret = radeon_ddc_probe(radeon_connector, radeon_connector->requires_extended_probe); if (dret) { + radeon_connector->detected_by_load = false; if (radeon_connector->edid) { kfree(radeon_connector->edid); radeon_connector->edid = NULL; @@ -950,8 +961,18 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) if ((ret == connector_status_connected) && (radeon_connector->use_digital == true)) goto out; + /* DVI-D and HDMI-A are digital only */ + if ((connector->connector_type == DRM_MODE_CONNECTOR_DVID) || + (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)) + goto out; + + /* if we aren't forcing don't do destructive polling */ if (!force) { - ret = connector->status; + /* only return the previous status if we last + * detected a monitor via load. + */ + if (radeon_connector->detected_by_load) + ret = connector->status; goto out; } @@ -969,6 +990,10 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) encoder = obj_to_encoder(obj); + if (encoder->encoder_type != DRM_MODE_ENCODER_DAC || + encoder->encoder_type != DRM_MODE_ENCODER_TVDAC) + continue; + encoder_funcs = encoder->helper_private; if (encoder_funcs->detect) { if (ret != connector_status_connected) { @@ -976,6 +1001,8 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) if (ret == connector_status_connected) { radeon_connector->use_digital = false; } + if (ret != connector_status_disconnected) + radeon_connector->detected_by_load = true; } break; } diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index f59a682..3fb2226 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -151,7 +151,9 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc, uint32_t height) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct radeon_device *rdev = crtc->dev->dev_private; struct drm_gem_object *obj; + struct radeon_bo *robj; uint64_t gpu_addr; int ret; @@ -173,7 +175,15 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc, return -ENOENT; } - ret = radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &gpu_addr); + robj = gem_to_radeon_bo(obj); + ret = radeon_bo_reserve(robj, false); + if (unlikely(ret != 0)) + goto fail; + /* Only 27 bit offset for legacy cursor */ + ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM, + ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, + &gpu_addr); + radeon_bo_unreserve(robj); if (ret) goto fail; @@ -181,7 +191,6 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc, radeon_crtc->cursor_height = height; radeon_lock_cursor(crtc, true); - /* XXX only 27 bit offset for legacy cursor */ radeon_set_cursor(crtc, obj, gpu_addr); radeon_show_cursor(crtc); radeon_lock_cursor(crtc, false); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 440e6ec..e87893c 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -223,8 +223,11 @@ int radeon_wb_init(struct radeon_device *rdev) if (radeon_no_wb == 1) rdev->wb.enabled = false; else { - /* often unreliable on AGP */ if (rdev->flags & RADEON_IS_AGP) { + /* often unreliable on AGP */ + rdev->wb.enabled = false; + } else if (rdev->family < CHIP_R300) { + /* often unreliable on pre-r300 */ rdev->wb.enabled = false; } else { rdev->wb.enabled = true; @@ -854,6 +857,8 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; + drm_kms_helper_poll_disable(dev); + /* turn off display hw */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); @@ -940,6 +945,8 @@ int radeon_resume_kms(struct drm_device *dev) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); } + + drm_kms_helper_poll_enable(dev); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 73dfbe8..60e1605 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -117,6 +117,7 @@ int radeon_audio = 0; int radeon_disp_priority = 0; int radeon_hw_i2c = 0; int radeon_pcie_gen2 = 0; +int radeon_msi = -1; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -163,6 +164,9 @@ module_param_named(hw_i2c, radeon_hw_i2c, int, 0444); MODULE_PARM_DESC(pcie_gen2, "PCIE Gen2 mode (1 = enable)"); module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444); +MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)"); +module_param_named(msi, radeon_msi, int, 0444); + static int radeon_suspend(struct drm_device *dev, pm_message_t state) { drm_radeon_private_t *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 9ec830c..5feb6e9 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -108,6 +108,52 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) radeon_irq_set(rdev); } +static bool radeon_msi_ok(struct radeon_device *rdev) +{ + /* RV370/RV380 was first asic with MSI support */ + if (rdev->family < CHIP_RV380) + return false; + + /* MSIs don't work on AGP */ + if (rdev->flags & RADEON_IS_AGP) + return false; + + /* force MSI on */ + if (radeon_msi == 1) + return true; + else if (radeon_msi == 0) + return false; + + /* Quirks */ + /* HP RS690 only seems to work with MSIs. */ + if ((rdev->pdev->device == 0x791f) && + (rdev->pdev->subsystem_vendor == 0x103c) && + (rdev->pdev->subsystem_device == 0x30c2)) + return true; + + /* Dell RS690 only seems to work with MSIs. */ + if ((rdev->pdev->device == 0x791f) && + (rdev->pdev->subsystem_vendor == 0x1028) && + (rdev->pdev->subsystem_device == 0x01fc)) + return true; + + /* Dell RS690 only seems to work with MSIs. */ + if ((rdev->pdev->device == 0x791f) && + (rdev->pdev->subsystem_vendor == 0x1028) && + (rdev->pdev->subsystem_device == 0x01fd)) + return true; + + if (rdev->flags & RADEON_IS_IGP) { + /* APUs work fine with MSIs */ + if (rdev->family >= CHIP_PALM) + return true; + /* lots of IGPs have problems with MSIs */ + return false; + } + + return true; +} + int radeon_irq_kms_init(struct radeon_device *rdev) { int i; @@ -124,12 +170,8 @@ int radeon_irq_kms_init(struct radeon_device *rdev) } /* enable msi */ rdev->msi_enabled = 0; - /* MSIs don't seem to work reliably on all IGP - * chips. Disable MSI on them for now. - */ - if ((rdev->family >= CHIP_RV380) && - ((!(rdev->flags & RADEON_IS_IGP)) || (rdev->family >= CHIP_PALM)) && - (!(rdev->flags & RADEON_IS_AGP))) { + + if (radeon_msi_ok(rdev)) { int ret = pci_enable_msi(rdev->pdev); if (!ret) { rdev->msi_enabled = 1; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 68820f5..ed0178f 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -447,6 +447,7 @@ struct radeon_connector { struct edid *edid; void *con_priv; bool dac_load_detect; + bool detected_by_load; /* if the connection status was determined by load */ uint16_t connector_object_id; struct radeon_hpd hpd; struct radeon_router router; diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 976c3b1..35da1b4 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -204,7 +204,8 @@ void radeon_bo_unref(struct radeon_bo **bo) *bo = NULL; } -int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr) +int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset, + u64 *gpu_addr) { int r, i; @@ -212,6 +213,7 @@ int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr) bo->pin_count++; if (gpu_addr) *gpu_addr = radeon_bo_gpu_offset(bo); + WARN_ON_ONCE(max_offset != 0); return 0; } radeon_ttm_placement_from_domain(bo, domain); @@ -219,6 +221,15 @@ int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr) /* force to pin into visible video ram */ bo->placement.lpfn = bo->rdev->mc.visible_vram_size >> PAGE_SHIFT; } + if (max_offset) { + u64 lpfn = max_offset >> PAGE_SHIFT; + + if (!bo->placement.lpfn) + bo->placement.lpfn = bo->rdev->mc.gtt_size >> PAGE_SHIFT; + + if (lpfn < bo->placement.lpfn) + bo->placement.lpfn = lpfn; + } for (i = 0; i < bo->placement.num_placement; i++) bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false, false); @@ -232,6 +243,11 @@ int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr) return r; } +int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr) +{ + return radeon_bo_pin_restricted(bo, domain, 0, gpu_addr); +} + int radeon_bo_unpin(struct radeon_bo *bo) { int r, i; diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index ede6c13..7199c6a 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -144,6 +144,8 @@ extern int radeon_bo_kmap(struct radeon_bo *bo, void **ptr); extern void radeon_bo_kunmap(struct radeon_bo *bo); extern void radeon_bo_unref(struct radeon_bo **bo); extern int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr); +extern int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, + u64 max_offset, u64 *gpu_addr); extern int radeon_bo_unpin(struct radeon_bo *bo); extern int radeon_bo_evict_vram(struct radeon_device *rdev); extern void radeon_bo_force_delete(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 1f5850e..2026c2d 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -62,6 +62,7 @@ u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); + int i; /* Lock the graphics update lock */ tmp |= AVIVO_D1GRPH_UPDATE_LOCK; @@ -74,7 +75,11 @@ u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) (u32)crtc_base); /* Wait for update_pending to go high. */ - while (!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING)); + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING) + break; + udelay(1); + } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); /* Unlock the lock, so double-buffering can take place inside vblank */ @@ -287,6 +292,7 @@ void rs600_hpd_init(struct radeon_device *rdev) default: break; } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) rs600_irq_set(rdev); @@ -318,10 +324,10 @@ void rs600_hpd_fini(struct radeon_device *rdev) void rs600_bm_disable(struct radeon_device *rdev) { - u32 tmp; + u16 tmp; /* disable bus mastering */ - pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp); + pci_read_config_word(rdev->pdev, 0x4, &tmp); pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB); mdelay(1); } @@ -692,9 +698,7 @@ int rs600_irq_process(struct radeon_device *rdev) 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); + WREG32(RADEON_MSI_REARM_EN, RV370_MSI_REARM_EN); break; } } diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index f2516e6..84cf82f 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -47,6 +47,7 @@ u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); + int i; /* Lock the graphics update lock */ tmp |= AVIVO_D1GRPH_UPDATE_LOCK; @@ -66,7 +67,11 @@ u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) (u32)crtc_base); /* Wait for update_pending to go high. */ - while (!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING)); + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING) + break; + udelay(1); + } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); /* Unlock the lock, so double-buffering can take place inside vblank */ |