diff options
Diffstat (limited to 'drivers/gpu/drm/radeon')
32 files changed, 747 insertions, 240 deletions
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index 8e421f644a54..05efb5b9f13e 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -112,6 +112,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, base += 3; break; case ATOM_IIO_WRITE: + (void)ctx->card->ioreg_read(ctx->card, CU16(base + 1)); ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp); base += 3; break; diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index df2b6f2b35f8..9fbabaa6ee44 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -253,7 +253,8 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); - atombios_blank_crtc(crtc, ATOM_ENABLE); + if (radeon_crtc->enabled) + atombios_blank_crtc(crtc, ATOM_ENABLE); if (ASIC_IS_DCE3(rdev)) atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); atombios_enable_crtc(crtc, ATOM_DISABLE); @@ -530,7 +531,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, dp_clock = dig_connector->dp_clock; } } - +#if 0 /* doesn't work properly on some laptops */ /* use recommended ref_div for ss */ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { if (ss_enabled) { @@ -540,7 +541,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, } } } - +#endif if (ASIC_IS_AVIVO(rdev)) { /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 488c36c8f5e6..7b337c361a12 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -748,6 +748,8 @@ void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev) unsigned i; u32 tmp; + WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); + WREG32(VM_CONTEXT0_REQUEST_RESPONSE, REQUEST_TYPE(1)); for (i = 0; i < rdev->usec_timeout; i++) { /* read MC_STATUS */ @@ -1650,7 +1652,36 @@ static void evergreen_gpu_init(struct radeon_device *rdev) } } - rdev->config.evergreen.tile_config = gb_addr_config; + /* setup tiling info dword. gb_addr_config is not adequate since it does + * not have bank info, so create a custom tiling dword. + * bits 3:0 num_pipes + * bits 7:4 num_banks + * bits 11:8 group_size + * bits 15:12 row_size + */ + rdev->config.evergreen.tile_config = 0; + switch (rdev->config.evergreen.max_tile_pipes) { + case 1: + default: + rdev->config.evergreen.tile_config |= (0 << 0); + break; + case 2: + rdev->config.evergreen.tile_config |= (1 << 0); + break; + case 4: + rdev->config.evergreen.tile_config |= (2 << 0); + break; + case 8: + rdev->config.evergreen.tile_config |= (3 << 0); + break; + } + rdev->config.evergreen.tile_config |= + ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4; + rdev->config.evergreen.tile_config |= + ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) << 8; + rdev->config.evergreen.tile_config |= + ((gb_addr_config & 0x30000000) >> 28) << 12; + WREG32(GB_BACKEND_MAP, gb_backend_map); WREG32(GB_ADDR_CONFIG, gb_addr_config); WREG32(DMIF_ADDR_CONFIG, gb_addr_config); @@ -1893,7 +1924,6 @@ bool evergreen_gpu_is_lockup(struct radeon_device *rdev) static int evergreen_gpu_soft_reset(struct radeon_device *rdev) { struct evergreen_mc_save save; - u32 srbm_reset = 0; u32 grbm_reset = 0; dev_info(rdev->dev, "GPU softreset \n"); @@ -1932,16 +1962,6 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev) udelay(50); WREG32(GRBM_SOFT_RESET, 0); (void)RREG32(GRBM_SOFT_RESET); - - /* reset all the system blocks */ - srbm_reset = SRBM_SOFT_RESET_ALL_MASK; - - dev_info(rdev->dev, " SRBM_SOFT_RESET=0x%08X\n", srbm_reset); - WREG32(SRBM_SOFT_RESET, srbm_reset); - (void)RREG32(SRBM_SOFT_RESET); - udelay(50); - WREG32(SRBM_SOFT_RESET, 0); - (void)RREG32(SRBM_SOFT_RESET); /* Wait a little for things to settle down */ udelay(50); dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n", @@ -1952,10 +1972,6 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev) RREG32(GRBM_STATUS_SE1)); dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n", RREG32(SRBM_STATUS)); - /* After reset we need to reinit the asic as GPU often endup in an - * incoherent state. - */ - atom_asic_init(rdev->mode_info.atom_context); evergreen_mc_resume(rdev, &save); return 0; } @@ -2567,6 +2583,11 @@ int evergreen_resume(struct radeon_device *rdev) { int r; + /* reset the asic, the gfx blocks are often in a bad state + * after the driver is unloaded or after a resume + */ + if (radeon_asic_reset(rdev)) + dev_warn(rdev->dev, "GPU reset failed !\n"); /* Do not reset GPU before posting, on rv770 hw unlike on r500 hw, * posting will perform necessary task to bring back GPU into good * shape. @@ -2683,6 +2704,11 @@ int evergreen_init(struct radeon_device *rdev) r = radeon_atombios_init(rdev); if (r) return r; + /* reset the asic, the gfx blocks are often in a bad state + * after the driver is unloaded or after a resume + */ + if (radeon_asic_reset(rdev)) + dev_warn(rdev->dev, "GPU reset failed !\n"); /* Post card if necessary */ if (!evergreen_card_posted(rdev)) { if (!rdev->bios) { diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c index ac3b6dde23db..e0e590110dd4 100644 --- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c +++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c @@ -459,7 +459,7 @@ int evergreen_blit_init(struct radeon_device *rdev) obj_size += evergreen_ps_size * 4; obj_size = ALIGN(obj_size, 256); - r = radeon_bo_create(rdev, NULL, obj_size, true, RADEON_GEM_DOMAIN_VRAM, + r = radeon_bo_create(rdev, NULL, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, &rdev->r600_blit.shader_obj); if (r) { DRM_ERROR("evergreen failed to allocate shader\n"); diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 113c70cc8b39..a73b53c44359 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -174,6 +174,7 @@ #define HDP_NONSURFACE_BASE 0x2C04 #define HDP_NONSURFACE_INFO 0x2C08 #define HDP_NONSURFACE_SIZE 0x2C0C +#define HDP_MEM_COHERENCY_FLUSH_CNTL 0x5480 #define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0 #define HDP_TILING_CONFIG 0x2F3C diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 0f806cc7dc75..9c92db7c896b 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -878,12 +878,15 @@ void r600_pcie_gart_tlb_flush(struct radeon_device *rdev) u32 tmp; /* flush hdp cache so updates hit vram */ - if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) { + if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740) && + !(rdev->flags & RADEON_IS_AGP)) { void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; u32 tmp; /* r7xx hw bug. write to HDP_DEBUG1 followed by fb read * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL + * This seems to cause problems on some AGP cards. Just use the old + * method for them. */ WREG32(HDP_DEBUG1, 0); tmp = readl((void __iomem *)ptr); @@ -1195,8 +1198,10 @@ void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) mc->vram_end, mc->real_vram_size >> 20); } else { u64 base = 0; - if (rdev->flags & RADEON_IS_IGP) - base = (RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24; + if (rdev->flags & RADEON_IS_IGP) { + base = RREG32(MC_VM_FB_LOCATION) & 0xFFFF; + base <<= 24; + } radeon_vram_location(rdev, &rdev->mc, base); rdev->mc.gtt_base_align = 0; radeon_gtt_location(rdev, mc); @@ -1337,13 +1342,19 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev) u32 srbm_status; u32 grbm_status; u32 grbm_status2; + struct r100_gpu_lockup *lockup; int r; + if (rdev->family >= CHIP_RV770) + lockup = &rdev->config.rv770.lockup; + else + lockup = &rdev->config.r600.lockup; + srbm_status = RREG32(R_000E50_SRBM_STATUS); grbm_status = RREG32(R_008010_GRBM_STATUS); grbm_status2 = RREG32(R_008014_GRBM_STATUS2); if (!G_008010_GUI_ACTIVE(grbm_status)) { - r100_gpu_lockup_update(&rdev->config.r300.lockup, &rdev->cp); + r100_gpu_lockup_update(lockup, &rdev->cp); return false; } /* force CP activities */ @@ -1355,7 +1366,7 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev) radeon_ring_unlock_commit(rdev); } rdev->cp.rptr = RREG32(R600_CP_RB_RPTR); - return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp); + return r100_gpu_cp_is_lockup(rdev, lockup, &rdev->cp); } int r600_asic_reset(struct radeon_device *rdev) @@ -2718,7 +2729,7 @@ static int r600_ih_ring_alloc(struct radeon_device *rdev) /* Allocate ring buffer */ if (rdev->ih.ring_obj == NULL) { r = radeon_bo_create(rdev, NULL, rdev->ih.ring_size, - true, + PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, &rdev->ih.ring_obj); if (r) { @@ -3483,10 +3494,12 @@ int r600_debugfs_mc_info_init(struct radeon_device *rdev) void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo) { /* r7xx hw bug. write to HDP_DEBUG1 followed by fb read - * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL + * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL. + * This seems to cause problems on some AGP cards. Just use the old + * method for them. */ if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740) && - rdev->vram_scratch.ptr) { + rdev->vram_scratch.ptr && !(rdev->flags & RADEON_IS_AGP)) { void __iomem *ptr = (void *)rdev->vram_scratch.ptr; u32 tmp; diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c index 8362974ef41a..86e5aa07f0db 100644 --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -501,7 +501,7 @@ int r600_blit_init(struct radeon_device *rdev) obj_size += r6xx_ps_size * 4; obj_size = ALIGN(obj_size, 256); - r = radeon_bo_create(rdev, NULL, obj_size, true, RADEON_GEM_DOMAIN_VRAM, + r = radeon_bo_create(rdev, NULL, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, &rdev->r600_blit.shader_obj); if (r) { DRM_ERROR("r600 failed to allocate shader\n"); diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 37cc2aa9f923..7831e0890210 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -50,6 +50,7 @@ struct r600_cs_track { u32 nsamples; u32 cb_color_base_last[8]; struct radeon_bo *cb_color_bo[8]; + u64 cb_color_bo_mc[8]; u32 cb_color_bo_offset[8]; struct radeon_bo *cb_color_frag_bo[8]; struct radeon_bo *cb_color_tile_bo[8]; @@ -67,6 +68,7 @@ struct r600_cs_track { u32 db_depth_size; u32 db_offset; struct radeon_bo *db_bo; + u64 db_bo_mc; }; static inline int r600_bpe_from_format(u32 *bpe, u32 format) @@ -140,6 +142,68 @@ static inline int r600_bpe_from_format(u32 *bpe, u32 format) return 0; } +struct array_mode_checker { + int array_mode; + u32 group_size; + u32 nbanks; + u32 npipes; + u32 nsamples; + u32 bpe; +}; + +/* returns alignment in pixels for pitch/height/depth and bytes for base */ +static inline int r600_get_array_mode_alignment(struct array_mode_checker *values, + u32 *pitch_align, + u32 *height_align, + u32 *depth_align, + u64 *base_align) +{ + u32 tile_width = 8; + u32 tile_height = 8; + u32 macro_tile_width = values->nbanks; + u32 macro_tile_height = values->npipes; + u32 tile_bytes = tile_width * tile_height * values->bpe * values->nsamples; + u32 macro_tile_bytes = macro_tile_width * macro_tile_height * tile_bytes; + + switch (values->array_mode) { + case ARRAY_LINEAR_GENERAL: + /* technically tile_width/_height for pitch/height */ + *pitch_align = 1; /* tile_width */ + *height_align = 1; /* tile_height */ + *depth_align = 1; + *base_align = 1; + break; + case ARRAY_LINEAR_ALIGNED: + *pitch_align = max((u32)64, (u32)(values->group_size / values->bpe)); + *height_align = tile_height; + *depth_align = 1; + *base_align = values->group_size; + break; + case ARRAY_1D_TILED_THIN1: + *pitch_align = max((u32)tile_width, + (u32)(values->group_size / + (tile_height * values->bpe * values->nsamples))); + *height_align = tile_height; + *depth_align = 1; + *base_align = values->group_size; + break; + case ARRAY_2D_TILED_THIN1: + *pitch_align = max((u32)macro_tile_width, + (u32)(((values->group_size / tile_height) / + (values->bpe * values->nsamples)) * + values->nbanks)) * tile_width; + *height_align = macro_tile_height * tile_height; + *depth_align = 1; + *base_align = max(macro_tile_bytes, + (*pitch_align) * values->bpe * (*height_align) * values->nsamples); + break; + default: + return -EINVAL; + } + + return 0; +} + static void r600_cs_track_init(struct r600_cs_track *track) { int i; @@ -153,10 +217,12 @@ static void r600_cs_track_init(struct r600_cs_track *track) track->cb_color_info[i] = 0; track->cb_color_bo[i] = NULL; track->cb_color_bo_offset[i] = 0xFFFFFFFF; + track->cb_color_bo_mc[i] = 0xFFFFFFFF; } track->cb_target_mask = 0xFFFFFFFF; track->cb_shader_mask = 0xFFFFFFFF; track->db_bo = NULL; + track->db_bo_mc = 0xFFFFFFFF; /* assume the biggest format and that htile is enabled */ track->db_depth_info = 7 | (1 << 25); track->db_depth_view = 0xFFFFC000; @@ -168,7 +234,10 @@ static void r600_cs_track_init(struct r600_cs_track *track) static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) { struct r600_cs_track *track = p->track; - u32 bpe = 0, pitch, slice_tile_max, size, tmp, height, pitch_align; + u32 bpe = 0, slice_tile_max, size, tmp; + u32 height, height_align, pitch, pitch_align, depth_align; + u64 base_offset, base_align; + struct array_mode_checker array_check; volatile u32 *ib = p->ib->ptr; unsigned array_mode; @@ -183,60 +252,40 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) i, track->cb_color_info[i]); return -EINVAL; } - /* pitch is the number of 8x8 tiles per row */ - pitch = G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1; + /* pitch in pixels */ + pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) * 8; slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1; slice_tile_max *= 64; - height = slice_tile_max / (pitch * 8); + height = slice_tile_max / pitch; if (height > 8192) height = 8192; array_mode = G_0280A0_ARRAY_MODE(track->cb_color_info[i]); + + base_offset = track->cb_color_bo_mc[i] + track->cb_color_bo_offset[i]; + array_check.array_mode = array_mode; + array_check.group_size = track->group_size; + array_check.nbanks = track->nbanks; + array_check.npipes = track->npipes; + array_check.nsamples = track->nsamples; + array_check.bpe = bpe; + if (r600_get_array_mode_alignment(&array_check, + &pitch_align, &height_align, &depth_align, &base_align)) { + dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__, + G_0280A0_ARRAY_MODE(track->cb_color_info[i]), i, + track->cb_color_info[i]); + return -EINVAL; + } switch (array_mode) { case V_0280A0_ARRAY_LINEAR_GENERAL: - /* technically height & 0x7 */ break; case V_0280A0_ARRAY_LINEAR_ALIGNED: - pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - if (!IS_ALIGNED(height, 8)) { - dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; case V_0280A0_ARRAY_1D_TILED_THIN1: - pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe * track->nsamples))) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } /* avoid breaking userspace */ if (height > 7) height &= ~0x7; - if (!IS_ALIGNED(height, 8)) { - dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; case V_0280A0_ARRAY_2D_TILED_THIN1: - pitch_align = max((u32)track->nbanks, - (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - if (!IS_ALIGNED((height / 8), track->npipes)) { - dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; default: dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__, @@ -244,31 +293,42 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) track->cb_color_info[i]); return -EINVAL; } + + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + if (!IS_ALIGNED(height, height_align)) { + dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", + __func__, __LINE__, height); + return -EINVAL; + } + if (!IS_ALIGNED(base_offset, base_align)) { + dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset); + return -EINVAL; + } + /* check offset */ - tmp = height * pitch * 8 * bpe; + tmp = height * pitch * bpe; if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) { if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) { /* the initial DDX does bad things with the CB size occasionally */ /* it rounds up height too far for slice tile max but the BO is smaller */ - tmp = (height - 7) * 8 * bpe; - if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) { - dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i])); - return -EINVAL; - } + /* r600c,g also seem to flush at bad times in some apps resulting in + * bogus values here. So for linear just allow anything to avoid breaking + * broken userspace. + */ } else { dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i])); return -EINVAL; } } - if (!IS_ALIGNED(track->cb_color_bo_offset[i], track->group_size)) { - dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->cb_color_bo_offset[i]); - return -EINVAL; - } /* limit max tile */ - tmp = (height * pitch * 8) >> 6; + tmp = (height * pitch) >> 6; if (tmp < slice_tile_max) slice_tile_max = tmp; - tmp = S_028060_PITCH_TILE_MAX(pitch - 1) | + tmp = S_028060_PITCH_TILE_MAX((pitch / 8) - 1) | S_028060_SLICE_TILE_MAX(slice_tile_max - 1); ib[track->cb_color_size_idx[i]] = tmp; return 0; @@ -310,7 +370,12 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) /* Check depth buffer */ if (G_028800_STENCIL_ENABLE(track->db_depth_control) || G_028800_Z_ENABLE(track->db_depth_control)) { - u32 nviews, bpe, ntiles, pitch, pitch_align, height, size, slice_tile_max; + u32 nviews, bpe, ntiles, size, slice_tile_max; + u32 height, height_align, pitch, pitch_align, depth_align; + u64 base_offset, base_align; + struct array_mode_checker array_check; + int array_mode; + if (track->db_bo == NULL) { dev_warn(p->dev, "z/stencil with no depth buffer\n"); return -EINVAL; @@ -353,41 +418,34 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF); } else { size = radeon_bo_size(track->db_bo); - pitch = G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1; + /* pitch in pixels */ + pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8; slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1; slice_tile_max *= 64; - height = slice_tile_max / (pitch * 8); + height = slice_tile_max / pitch; if (height > 8192) height = 8192; - switch (G_028010_ARRAY_MODE(track->db_depth_info)) { + base_offset = track->db_bo_mc + track->db_offset; + array_mode = G_028010_ARRAY_MODE(track->db_depth_info); + array_check.array_mode = array_mode; + array_check.group_size = track->group_size; + array_check.nbanks = track->nbanks; + array_check.npipes = track->npipes; + array_check.nsamples = track->nsamples; + array_check.bpe = bpe; + if (r600_get_array_mode_alignment(&array_check, + &pitch_align, &height_align, &depth_align, &base_align)) { + dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, + G_028010_ARRAY_MODE(track->db_depth_info), + track->db_depth_info); + return -EINVAL; + } + switch (array_mode) { case V_028010_ARRAY_1D_TILED_THIN1: - pitch_align = (max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8); - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } /* don't break userspace */ height &= ~0x7; - if (!IS_ALIGNED(height, 8)) { - dev_warn(p->dev, "%s:%d db height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; case V_028010_ARRAY_2D_TILED_THIN1: - pitch_align = max((u32)track->nbanks, - (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - if (!IS_ALIGNED((height / 8), track->npipes)) { - dev_warn(p->dev, "%s:%d db height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; default: dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, @@ -395,15 +453,27 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) track->db_depth_info); return -EINVAL; } - if (!IS_ALIGNED(track->db_offset, track->group_size)) { - dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->db_offset); + + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + if (!IS_ALIGNED(height, height_align)) { + dev_warn(p->dev, "%s:%d db height (%d) invalid\n", + __func__, __LINE__, height); return -EINVAL; } + if (!IS_ALIGNED(base_offset, base_align)) { + dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset); + return -EINVAL; + } + ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1; nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1; tmp = ntiles * bpe * 64 * nviews; if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) { - dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %d have %ld)\n", + dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %u have %lu)\n", track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset, radeon_bo_size(track->db_bo)); return -EINVAL; @@ -954,6 +1024,7 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); track->cb_color_base_last[tmp] = ib[idx]; track->cb_color_bo[tmp] = reloc->robj; + track->cb_color_bo_mc[tmp] = reloc->lobj.gpu_offset; break; case DB_DEPTH_BASE: r = r600_cs_packet_next_reloc(p, &reloc); @@ -965,6 +1036,7 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx track->db_offset = radeon_get_ib_value(p, idx) << 8; ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); track->db_bo = reloc->robj; + track->db_bo_mc = reloc->lobj.gpu_offset; break; case DB_HTILE_DATA_BASE: case SQ_PGM_START_FS: @@ -1086,16 +1158,25 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx, struct radeon_bo *texture, struct radeon_bo *mipmap, + u64 base_offset, + u64 mip_offset, u32 tiling_flags) { struct r600_cs_track *track = p->track; u32 nfaces, nlevels, blevel, w0, h0, d0, bpe = 0; - u32 word0, word1, l0_size, mipmap_size, pitch, pitch_align; + u32 word0, word1, l0_size, mipmap_size; + u32 height_align, pitch, pitch_align, depth_align; + u64 base_align; + struct array_mode_checker array_check; /* on legacy kernel we don't perform advanced check */ if (p->rdev == NULL) return 0; + /* convert to bytes */ + base_offset <<= 8; + mip_offset <<= 8; + word0 = radeon_get_ib_value(p, idx + 0); if (tiling_flags & RADEON_TILING_MACRO) word0 |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1); @@ -1128,46 +1209,38 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 i return -EINVAL; } - pitch = G_038000_PITCH(word0) + 1; - switch (G_038000_TILE_MODE(word0)) { - case V_038000_ARRAY_LINEAR_GENERAL: - pitch_align = 1; - /* XXX check height align */ - break; - case V_038000_ARRAY_LINEAR_ALIGNED: - pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - /* XXX check height align */ - break; - case V_038000_ARRAY_1D_TILED_THIN1: - pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - /* XXX check height align */ - break; - case V_038000_ARRAY_2D_TILED_THIN1: - pitch_align = max((u32)track->nbanks, - (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - /* XXX check height align */ - break; - default: - dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, - G_038000_TILE_MODE(word0), word0); + /* pitch in texels */ + pitch = (G_038000_PITCH(word0) + 1) * 8; + array_check.array_mode = G_038000_TILE_MODE(word0); + array_check.group_size = track->group_size; + array_check.nbanks = track->nbanks; + array_check.npipes = track->npipes; + array_check.nsamples = 1; + array_check.bpe = bpe; + if (r600_get_array_mode_alignment(&array_check, + &pitch_align, &height_align, &depth_align, &base_align)) { + dev_warn(p->dev, "%s:%d tex array mode (%d) invalid\n", + __func__, __LINE__, G_038000_TILE_MODE(word0)); + return -EINVAL; + } + + /* XXX check height as well... */ + + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + if (!IS_ALIGNED(base_offset, base_align)) { + dev_warn(p->dev, "%s:%d tex base offset (0x%llx) invalid\n", + __func__, __LINE__, base_offset); + return -EINVAL; + } + if (!IS_ALIGNED(mip_offset, base_align)) { + dev_warn(p->dev, "%s:%d tex mip offset (0x%llx) invalid\n", + __func__, __LINE__, mip_offset); return -EINVAL; } - /* XXX check offset align */ word0 = radeon_get_ib_value(p, idx + 4); word1 = radeon_get_ib_value(p, idx + 5); @@ -1402,7 +1475,10 @@ static int r600_packet3_check(struct radeon_cs_parser *p, mip_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); mipmap = reloc->robj; r = r600_check_texture_resource(p, idx+(i*7)+1, - texture, mipmap, reloc->lobj.tiling_flags); + texture, mipmap, + base_offset + radeon_get_ib_value(p, idx+1+(i*7)+2), + mip_offset + radeon_get_ib_value(p, idx+1+(i*7)+3), + reloc->lobj.tiling_flags); if (r) return r; ib[idx+1+(i*7)+2] += base_offset; diff --git a/drivers/gpu/drm/radeon/r600_reg.h b/drivers/gpu/drm/radeon/r600_reg.h index d84612ae47e0..33cda016b083 100644 --- a/drivers/gpu/drm/radeon/r600_reg.h +++ b/drivers/gpu/drm/radeon/r600_reg.h @@ -86,6 +86,7 @@ #define R600_HDP_NONSURFACE_BASE 0x2c04 #define R600_BUS_CNTL 0x5420 +# define R600_BIOS_ROM_DIS (1 << 1) #define R600_CONFIG_CNTL 0x5424 #define R600_CONFIG_MEMSIZE 0x5428 #define R600_CONFIG_F0_BASE 0x542C diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 966a793e225b..bff4dc4f410f 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -51,6 +51,12 @@ #define PTE_READABLE (1 << 5) #define PTE_WRITEABLE (1 << 6) +/* tiling bits */ +#define ARRAY_LINEAR_GENERAL 0x00000000 +#define ARRAY_LINEAR_ALIGNED 0x00000001 +#define ARRAY_1D_TILED_THIN1 0x00000002 +#define ARRAY_2D_TILED_THIN1 0x00000004 + /* Registers */ #define ARB_POP 0x2418 #define ENABLE_TC128 (1 << 30) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 73f600d39ad4..3a7095743d44 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1262,6 +1262,10 @@ void r100_pll_errata_after_index(struct radeon_device *rdev); (rdev->family == CHIP_RS400) || \ (rdev->family == CHIP_RS480)) #define ASIC_IS_AVIVO(rdev) ((rdev->family >= CHIP_RS600)) +#define ASIC_IS_DCE2(rdev) ((rdev->family == CHIP_RS600) || \ + (rdev->family == CHIP_RS690) || \ + (rdev->family == CHIP_RS740) || \ + (rdev->family >= CHIP_R600)) #define ASIC_IS_DCE3(rdev) ((rdev->family >= CHIP_RV620)) #define ASIC_IS_DCE32(rdev) ((rdev->family >= CHIP_RV730)) #define ASIC_IS_DCE4(rdev) ((rdev->family >= CHIP_CEDAR)) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 87ead090c7d5..bc5a2c3382d9 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -98,6 +98,14 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev } } + /* some DCE3 boards have bad data for this entry */ + if (ASIC_IS_DCE3(rdev)) { + if ((i == 4) && + (gpio->usClkMaskRegisterIndex == 0x1fda) && + (gpio->sucI2cId.ucAccess == 0x94)) + gpio->sucI2cId.ucAccess = 0x14; + } + if (gpio->sucI2cId.ucAccess == id) { i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4; i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4; @@ -174,6 +182,14 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev) } } + /* some DCE3 boards have bad data for this entry */ + if (ASIC_IS_DCE3(rdev)) { + if ((i == 4) && + (gpio->usClkMaskRegisterIndex == 0x1fda) && + (gpio->sucI2cId.ucAccess == 0x94)) + gpio->sucI2cId.ucAccess = 0x14; + } + i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4; i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4; i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4; diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c index 7932dc4d6b90..c558685cc637 100644 --- a/drivers/gpu/drm/radeon/radeon_benchmark.c +++ b/drivers/gpu/drm/radeon/radeon_benchmark.c @@ -41,7 +41,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize, size = bsize; n = 1024; - r = radeon_bo_create(rdev, NULL, size, true, sdomain, &sobj); + r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, sdomain, &sobj); if (r) { goto out_cleanup; } @@ -53,7 +53,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize, if (r) { goto out_cleanup; } - r = radeon_bo_create(rdev, NULL, size, true, ddomain, &dobj); + r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, ddomain, &dobj); if (r) { goto out_cleanup; } diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 654787ec43f4..8f2c7b50dcf5 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -130,6 +130,7 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev) } return true; } + static bool r700_read_disabled_bios(struct radeon_device *rdev) { uint32_t viph_control; @@ -143,7 +144,7 @@ static bool r700_read_disabled_bios(struct radeon_device *rdev) bool r; viph_control = RREG32(RADEON_VIPH_CONTROL); - bus_cntl = RREG32(RADEON_BUS_CNTL); + bus_cntl = RREG32(R600_BUS_CNTL); d1vga_control = RREG32(AVIVO_D1VGA_CONTROL); d2vga_control = RREG32(AVIVO_D2VGA_CONTROL); vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL); @@ -152,7 +153,7 @@ static bool r700_read_disabled_bios(struct radeon_device *rdev) /* disable VIP */ WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); /* enable the rom */ - WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); + WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS)); /* Disable VGA mode */ WREG32(AVIVO_D1VGA_CONTROL, (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | @@ -191,7 +192,7 @@ static bool r700_read_disabled_bios(struct radeon_device *rdev) cg_spll_status = RREG32(R600_CG_SPLL_STATUS); } WREG32(RADEON_VIPH_CONTROL, viph_control); - WREG32(RADEON_BUS_CNTL, bus_cntl); + WREG32(R600_BUS_CNTL, bus_cntl); WREG32(AVIVO_D1VGA_CONTROL, d1vga_control); WREG32(AVIVO_D2VGA_CONTROL, d2vga_control); WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control); @@ -216,7 +217,7 @@ static bool r600_read_disabled_bios(struct radeon_device *rdev) bool r; viph_control = RREG32(RADEON_VIPH_CONTROL); - bus_cntl = RREG32(RADEON_BUS_CNTL); + bus_cntl = RREG32(R600_BUS_CNTL); d1vga_control = RREG32(AVIVO_D1VGA_CONTROL); d2vga_control = RREG32(AVIVO_D2VGA_CONTROL); vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL); @@ -231,7 +232,7 @@ static bool r600_read_disabled_bios(struct radeon_device *rdev) /* disable VIP */ WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); /* enable the rom */ - WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); + WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS)); /* Disable VGA mode */ WREG32(AVIVO_D1VGA_CONTROL, (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | @@ -262,7 +263,7 @@ static bool r600_read_disabled_bios(struct radeon_device *rdev) /* restore regs */ WREG32(RADEON_VIPH_CONTROL, viph_control); - WREG32(RADEON_BUS_CNTL, bus_cntl); + WREG32(R600_BUS_CNTL, bus_cntl); WREG32(AVIVO_D1VGA_CONTROL, d1vga_control); WREG32(AVIVO_D2VGA_CONTROL, d2vga_control); WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control); diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 7b7ea269549c..137b8075f6e7 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -571,6 +571,7 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde } if (clk_mask && data_mask) { + /* system specific masks */ i2c.mask_clk_mask = clk_mask; i2c.mask_data_mask = data_mask; i2c.a_clk_mask = clk_mask; @@ -579,7 +580,19 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde i2c.en_data_mask = data_mask; i2c.y_clk_mask = clk_mask; i2c.y_data_mask = data_mask; + } else if ((ddc_line == RADEON_GPIOPAD_MASK) || + (ddc_line == RADEON_MDGPIO_MASK)) { + /* default gpiopad masks */ + i2c.mask_clk_mask = (0x20 << 8); + i2c.mask_data_mask = 0x80; + i2c.a_clk_mask = (0x20 << 8); + i2c.a_data_mask = 0x80; + i2c.en_clk_mask = (0x20 << 8); + i2c.en_data_mask = 0x80; + i2c.y_clk_mask = (0x20 << 8); + 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.a_clk_mask = RADEON_GPIO_A_1; @@ -716,7 +729,7 @@ void radeon_combios_i2c_init(struct radeon_device *rdev) clk = RBIOS8(offset + 3 + (i * 5) + 3); data = RBIOS8(offset + 3 + (i * 5) + 4); i2c = combios_setup_i2c_bus(rdev, DDC_MONID, - clk, data); + (1 << clk), (1 << data)); rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK"); break; } diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index fe6c74780f18..8afaf7a7459e 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1008,9 +1008,21 @@ static void radeon_dp_connector_destroy(struct drm_connector *connector) static int radeon_dp_get_modes(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; int ret; + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + if (!radeon_dig_connector->edp_on) + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_ON); + } ret = radeon_ddc_get_modes(radeon_connector); + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + if (!radeon_dig_connector->edp_on) + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_OFF); + } + return ret; } @@ -1029,8 +1041,14 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { /* eDP is always DP */ radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; + if (!radeon_dig_connector->edp_on) + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_ON); if (radeon_dp_getdpcd(radeon_connector)) ret = connector_status_connected; + if (!radeon_dig_connector->edp_on) + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_OFF); } else { radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector); if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { @@ -1157,6 +1175,8 @@ radeon_add_atom_connector(struct drm_device *dev, /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; connector->polled = DRM_CONNECTOR_POLL_CONNECT; + connector->interlace_allowed = true; + connector->doublescan_allowed = true; break; case DRM_MODE_CONNECTOR_DVIA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); @@ -1172,6 +1192,8 @@ radeon_add_atom_connector(struct drm_device *dev, 1); /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; + connector->interlace_allowed = true; + connector->doublescan_allowed = true; break; case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_DVID: @@ -1208,6 +1230,11 @@ radeon_add_atom_connector(struct drm_device *dev, rdev->mode_info.load_detect_property, 1); } + connector->interlace_allowed = true; + if (connector_type == DRM_MODE_CONNECTOR_DVII) + connector->doublescan_allowed = true; + else + connector->doublescan_allowed = false; break; case DRM_MODE_CONNECTOR_HDMIA: case DRM_MODE_CONNECTOR_HDMIB: @@ -1238,6 +1265,11 @@ radeon_add_atom_connector(struct drm_device *dev, 0); } subpixel_order = SubPixelHorizontalRGB; + connector->interlace_allowed = true; + if (connector_type == DRM_MODE_CONNECTOR_HDMIB) + connector->doublescan_allowed = true; + else + connector->doublescan_allowed = false; break; case DRM_MODE_CONNECTOR_DisplayPort: case DRM_MODE_CONNECTOR_eDP: @@ -1275,6 +1307,9 @@ radeon_add_atom_connector(struct drm_device *dev, rdev->mode_info.underscan_vborder_property, 0); } + connector->interlace_allowed = true; + /* in theory with a DP to VGA converter... */ + connector->doublescan_allowed = false; break; case DRM_MODE_CONNECTOR_SVIDEO: case DRM_MODE_CONNECTOR_Composite: @@ -1290,6 +1325,8 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_atombios_get_tv_info(rdev)); /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; break; case DRM_MODE_CONNECTOR_LVDS: radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); @@ -1308,6 +1345,8 @@ radeon_add_atom_connector(struct drm_device *dev, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_FULLSCREEN); subpixel_order = SubPixelHorizontalRGB; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; break; } @@ -1385,6 +1424,8 @@ radeon_add_legacy_connector(struct drm_device *dev, /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; connector->polled = DRM_CONNECTOR_POLL_CONNECT; + connector->interlace_allowed = true; + connector->doublescan_allowed = true; break; case DRM_MODE_CONNECTOR_DVIA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); @@ -1400,6 +1441,8 @@ radeon_add_legacy_connector(struct drm_device *dev, 1); /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; + connector->interlace_allowed = true; + connector->doublescan_allowed = true; break; case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_DVID: @@ -1417,6 +1460,11 @@ radeon_add_legacy_connector(struct drm_device *dev, 1); } subpixel_order = SubPixelHorizontalRGB; + connector->interlace_allowed = true; + if (connector_type == DRM_MODE_CONNECTOR_DVII) + connector->doublescan_allowed = true; + else + connector->doublescan_allowed = false; break; case DRM_MODE_CONNECTOR_SVIDEO: case DRM_MODE_CONNECTOR_Composite: @@ -1439,6 +1487,8 @@ radeon_add_legacy_connector(struct drm_device *dev, radeon_combios_get_tv_info(rdev)); /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; break; case DRM_MODE_CONNECTOR_LVDS: drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); @@ -1452,6 +1502,8 @@ radeon_add_legacy_connector(struct drm_device *dev, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_FULLSCREEN); subpixel_order = SubPixelHorizontalRGB; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; break; } diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 8adfedfe547f..501966a13f48 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -180,7 +180,7 @@ int radeon_wb_init(struct radeon_device *rdev) int r; if (rdev->wb.wb_obj == NULL) { - r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true, + r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, &rdev->wb.wb_obj); if (r) { dev_warn(rdev->dev, "(%d) create WB bo failed\n", r); @@ -286,7 +286,7 @@ void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 mc->mc_vram_size = mc->aper_size; } mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; - dev_info(rdev->dev, "VRAM: %lluM 0x%08llX - 0x%08llX (%lluM used)\n", + dev_info(rdev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n", mc->mc_vram_size >> 20, mc->vram_start, mc->vram_end, mc->real_vram_size >> 20); } @@ -323,7 +323,7 @@ void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) mc->gtt_start = (mc->vram_end + 1 + mc->gtt_base_align) & ~mc->gtt_base_align; } mc->gtt_end = mc->gtt_start + mc->gtt_size - 1; - dev_info(rdev->dev, "GTT: %lluM 0x%08llX - 0x%08llX\n", + dev_info(rdev->dev, "GTT: %lluM 0x%016llX - 0x%016llX\n", mc->gtt_size >> 20, mc->gtt_start, mc->gtt_end); } @@ -910,11 +910,6 @@ int radeon_resume_kms(struct drm_device *dev) radeon_pm_resume(rdev); radeon_restore_bios_scratch_regs(rdev); - /* turn on display hw */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); - } - radeon_fbdev_set_suspend(rdev, 0); release_console_sem(); @@ -922,6 +917,10 @@ int radeon_resume_kms(struct drm_device *dev) radeon_hpd_init(rdev); /* blat the mode back in */ drm_helper_resume_force_mode(dev); + /* turn on display hw */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); + } return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 88e4ea925900..60e689f2d048 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -232,9 +232,28 @@ static struct drm_driver driver_old = { static struct drm_driver kms_driver; +static void radeon_kick_out_firmware_fb(struct pci_dev *pdev) +{ + struct apertures_struct *ap; + bool primary = false; + + ap = alloc_apertures(1); + ap->ranges[0].base = pci_resource_start(pdev, 0); + ap->ranges[0].size = pci_resource_len(pdev, 0); + +#ifdef CONFIG_X86 + primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; +#endif + remove_conflicting_framebuffers(ap, "radeondrmfb", primary); + kfree(ap); +} + static int __devinit radeon_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + /* Get rid of things like offb */ + radeon_kick_out_firmware_fb(pdev); + return drm_get_pci_dev(pdev, ent, &kms_driver); } diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index f678257c42e6..041943df966b 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -176,6 +176,7 @@ static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder) return false; } } + void radeon_link_encoder_connector(struct drm_device *dev) { @@ -228,6 +229,27 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder) return NULL; } +struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *other_encoder; + struct radeon_encoder *other_radeon_encoder; + + if (radeon_encoder->is_ext_encoder) + return NULL; + + list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) { + if (other_encoder == encoder) + continue; + other_radeon_encoder = to_radeon_encoder(other_encoder); + if (other_radeon_encoder->is_ext_encoder && + (radeon_encoder->devices & other_radeon_encoder->devices)) + return other_encoder; + } + return NULL; +} + void radeon_panel_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { @@ -426,52 +448,49 @@ atombios_tv_setup(struct drm_encoder *encoder, int action) } -void -atombios_external_tmds_setup(struct drm_encoder *encoder, int action) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION args; - int index = 0; - - memset(&args, 0, sizeof(args)); - - index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); - - args.sXTmdsEncoder.ucEnable = action; - - if (radeon_encoder->pixel_clock > 165000) - args.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL; - - /*if (pScrn->rgbBits == 8)*/ - args.sXTmdsEncoder.ucMisc |= (1 << 1); - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - -} +union dvo_encoder_control { + ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds; + DVO_ENCODER_CONTROL_PS_ALLOCATION dvo; + DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3; +}; -static void -atombios_ddia_setup(struct drm_encoder *encoder, int action) +void +atombios_dvo_setup(struct drm_encoder *encoder, int action) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - DVO_ENCODER_CONTROL_PS_ALLOCATION args; - int index = 0; + union dvo_encoder_control args; + int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); memset(&args, 0, sizeof(args)); - index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); + if (ASIC_IS_DCE3(rdev)) { + /* DCE3+ */ + args.dvo_v3.ucAction = action; + args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.dvo_v3.ucDVOConfig = 0; /* XXX */ + } else if (ASIC_IS_DCE2(rdev)) { + /* DCE2 (pre-DCE3 R6xx, RS600/690/740 */ + args.dvo.sDVOEncoder.ucAction = action; + args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + /* DFP1, CRT1, TV1 depending on the type of port */ + args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX; + + if (radeon_encoder->pixel_clock > 165000) + args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL; + } else { + /* R4xx, R5xx */ + args.ext_tmds.sXTmdsEncoder.ucEnable = action; - args.sDVOEncoder.ucAction = action; - args.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + if (radeon_encoder->pixel_clock > 165000) + args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL; - if (radeon_encoder->pixel_clock > 165000) - args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL; + /*if (pScrn->rgbBits == 8)*/ + args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB; + } atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - } union lvds_encoder_control { @@ -532,14 +551,14 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) - args.v1.ucMisc |= (1 << 1); + args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; } else { if (dig->linkb) args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; if (radeon_encoder->pixel_clock > 165000) args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; /*if (pScrn->rgbBits == 8) */ - args.v1.ucMisc |= (1 << 1); + args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; } break; case 2: @@ -595,6 +614,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) int atombios_get_encoder_mode(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 drm_connector *connector; @@ -602,9 +622,20 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) struct radeon_connector_atom_dig *dig_connector; connector = radeon_get_connector_for_encoder(encoder); - if (!connector) - return 0; - + if (!connector) { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + return ATOM_ENCODER_MODE_DVI; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + default: + return ATOM_ENCODER_MODE_CRT; + } + } radeon_connector = to_radeon_connector(connector); switch (connector->connector_type) { @@ -834,6 +865,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t memset(&args, 0, sizeof(args)); switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: @@ -978,6 +1012,105 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } +void +atombios_set_edp_panel_power(struct drm_connector *connector, int action) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_device *dev = radeon_connector->base.dev; + struct radeon_device *rdev = dev->dev_private; + union dig_transmitter_control args; + int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); + uint8_t frev, crev; + + if (connector->connector_type != DRM_MODE_CONNECTOR_eDP) + return; + + if (!ASIC_IS_DCE4(rdev)) + return; + + if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) || + (action != ATOM_TRANSMITTER_ACTION_POWER_OFF)) + return; + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + memset(&args, 0, sizeof(args)); + + args.v1.ucAction = action; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +union external_encoder_control { + EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1; +}; + +static void +atombios_external_encoder_setup(struct drm_encoder *encoder, + struct drm_encoder *ext_encoder, + int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + union external_encoder_control args; + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl); + u8 frev, crev; + int dp_clock = 0; + int dp_lane_count = 0; + int connector_object_id = 0; + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + dp_clock = dig_connector->dp_clock; + dp_lane_count = dig_connector->dp_lane_count; + connector_object_id = + (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + } + + memset(&args, 0, sizeof(args)); + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (frev) { + case 1: + /* no params on frev 1 */ + break; + case 2: + switch (crev) { + case 1: + case 2: + args.v1.sDigEncoder.ucAction = action; + args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (args.v1.sDigEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) { + if (dp_clock == 270000) + args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; + args.v1.sDigEncoder.ucLaneNum = dp_lane_count; + } else if (radeon_encoder->pixel_clock > 165000) + args.v1.sDigEncoder.ucLaneNum = 8; + else + args.v1.sDigEncoder.ucLaneNum = 4; + break; + default: + DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); + return; + } + break; + default: + DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); + return; + } + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + static void atombios_yuv_setup(struct drm_encoder *encoder, bool enable) { @@ -1021,6 +1154,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; int index = 0; bool is_dig = false; @@ -1043,9 +1177,14 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) break; case ENCODER_OBJECT_ID_INTERNAL_DVO1: case ENCODER_OBJECT_ID_INTERNAL_DDI: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + if (ASIC_IS_DCE3(rdev)) + is_dig = true; + else + index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + break; case ENCODER_OBJECT_ID_INTERNAL_LVDS: index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); break; @@ -1082,34 +1221,85 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + if (connector && + (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *radeon_dig_connector = + radeon_connector->con_priv; + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_ON); + radeon_dig_connector->edp_on = true; + } dp_link_train(encoder, connector); if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON); } + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF); + if (connector && + (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *radeon_dig_connector = + radeon_connector->con_priv; + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_OFF); + radeon_dig_connector->edp_on = false; + } } + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); break; } } else { switch (mode) { case DRM_MODE_DPMS_ON: args.ucAction = ATOM_ENABLE; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + args.ucAction = ATOM_LCD_BLON; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + } break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: args.ucAction = ATOM_DISABLE; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + args.ucAction = ATOM_LCD_BLOFF; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + } break; } - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } + + if (ext_encoder) { + int action; + + switch (mode) { + case DRM_MODE_DPMS_ON: + default: + action = ATOM_ENABLE; + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + action = ATOM_DISABLE; + break; + } + atombios_external_encoder_setup(encoder, ext_encoder, action); + } + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); } @@ -1242,7 +1432,7 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) break; default: DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); - break; + return; } atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); @@ -1357,6 +1547,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); radeon_encoder->pixel_clock = adjusted_mode->clock; @@ -1400,11 +1591,9 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, } break; case ENCODER_OBJECT_ID_INTERNAL_DDI: - atombios_ddia_setup(encoder, ATOM_ENABLE); - break; case ENCODER_OBJECT_ID_INTERNAL_DVO1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - atombios_external_tmds_setup(encoder, ATOM_ENABLE); + atombios_dvo_setup(encoder, ATOM_ENABLE); break; case ENCODER_OBJECT_ID_INTERNAL_DAC1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: @@ -1419,6 +1608,11 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, } break; } + + if (ext_encoder) { + atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); + } + atombios_apply_encoder_quirks(encoder, adjusted_mode); if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { @@ -1595,11 +1789,9 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder) } break; case ENCODER_OBJECT_ID_INTERNAL_DDI: - atombios_ddia_setup(encoder, ATOM_DISABLE); - break; case ENCODER_OBJECT_ID_INTERNAL_DVO1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - atombios_external_tmds_setup(encoder, ATOM_DISABLE); + atombios_dvo_setup(encoder, ATOM_DISABLE); break; case ENCODER_OBJECT_ID_INTERNAL_DAC1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: @@ -1621,6 +1813,53 @@ disable_done: radeon_encoder->active_device = 0; } +/* these are handled by the primary encoders */ +static void radeon_atom_ext_prepare(struct drm_encoder *encoder) +{ + +} + +static void radeon_atom_ext_commit(struct drm_encoder *encoder) +{ + +} + +static void +radeon_atom_ext_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + +} + +static void radeon_atom_ext_disable(struct drm_encoder *encoder) +{ + +} + +static void +radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode) +{ + +} + +static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = { + .dpms = radeon_atom_ext_dpms, + .mode_fixup = radeon_atom_ext_mode_fixup, + .prepare = radeon_atom_ext_prepare, + .mode_set = radeon_atom_ext_mode_set, + .commit = radeon_atom_ext_commit, + .disable = radeon_atom_ext_disable, + /* no detect for TMDS/LVDS yet */ +}; + static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { .dpms = radeon_atom_encoder_dpms, .mode_fixup = radeon_atom_mode_fixup, @@ -1730,6 +1969,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t radeon_encoder->devices = supported_device; radeon_encoder->rmx_type = RMX_OFF; radeon_encoder->underscan_type = UNDERSCAN_OFF; + radeon_encoder->is_ext_encoder = false; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_LVDS: @@ -1771,6 +2011,9 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t radeon_encoder->rmx_type = RMX_FULL; drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); + } else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) { + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); + radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); } else { drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); @@ -1779,5 +2022,22 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t } drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); break; + case ENCODER_OBJECT_ID_SI170B: + case ENCODER_OBJECT_ID_CH7303: + case ENCODER_OBJECT_ID_EXTERNAL_SDVOA: + case ENCODER_OBJECT_ID_EXTERNAL_SDVOB: + case ENCODER_OBJECT_ID_TITFP513: + case ENCODER_OBJECT_ID_VT1623: + case ENCODER_OBJECT_ID_HDMI_SI1930: + /* these are handled by the primary encoders */ + radeon_encoder->is_ext_encoder = true; + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); + else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); + else + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs); + break; } } diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index efa211898fe6..6abea32be5e8 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -245,7 +245,7 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev, goto out_unref; } info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base; - info->apertures->ranges[0].size = rdev->mc.real_vram_size; + info->apertures->ranges[0].size = rdev->mc.aper_size; info->fix.mmio_start = 0; info->fix.mmio_len = 0; diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index e65b90317fab..65016117d95f 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -79,8 +79,8 @@ int radeon_gart_table_vram_alloc(struct radeon_device *rdev) if (rdev->gart.table.vram.robj == NULL) { r = radeon_bo_create(rdev, NULL, rdev->gart.table_size, - true, RADEON_GEM_DOMAIN_VRAM, - &rdev->gart.table.vram.robj); + PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, + &rdev->gart.table.vram.robj); if (r) { return r; } diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index d1e595d91723..df95eb83dac6 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -67,7 +67,7 @@ int radeon_gem_object_create(struct radeon_device *rdev, int size, if (alignment < PAGE_SIZE) { alignment = PAGE_SIZE; } - r = radeon_bo_create(rdev, gobj, size, kernel, initial_domain, &robj); + r = radeon_bo_create(rdev, gobj, size, alignment, kernel, initial_domain, &robj); if (r) { if (r != -ERESTARTSYS) DRM_ERROR("Failed to allocate GEM object (%d, %d, %u, %d)\n", diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 0cfbba02c4d0..ded2a45bc95c 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -896,7 +896,8 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, ((rdev->family <= CHIP_RS480) || ((rdev->family >= CHIP_RV515) && (rdev->family <= CHIP_R580))))) { /* set the radeon hw i2c adapter */ - sprintf(i2c->adapter.name, "Radeon i2c hw bus %s", name); + snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), + "Radeon i2c hw bus %s", name); i2c->adapter.algo = &radeon_i2c_algo; ret = i2c_add_adapter(&i2c->adapter); if (ret) { @@ -905,7 +906,8 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, } } else { /* set the radeon bit adapter */ - sprintf(i2c->adapter.name, "Radeon i2c bit bus %s", name); + snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), + "Radeon i2c bit bus %s", name); i2c->adapter.algo_data = &i2c->algo.bit; i2c->algo.bit.pre_xfer = pre_xfer; i2c->algo.bit.post_xfer = post_xfer; @@ -946,6 +948,8 @@ struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, i2c->rec = *rec; i2c->adapter.owner = THIS_MODULE; i2c->dev = dev; + snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), + "Radeon aux bus %s", name); i2c_set_adapdata(&i2c->adapter, i2c); i2c->adapter.algo_data = &i2c->algo.dp; i2c->algo.dp.aux_ch = radeon_dp_i2c_aux_ch; diff --git a/drivers/gpu/drm/radeon/radeon_irq.c b/drivers/gpu/drm/radeon/radeon_irq.c index 2f349a300195..465746bd51b7 100644 --- a/drivers/gpu/drm/radeon/radeon_irq.c +++ b/drivers/gpu/drm/radeon/radeon_irq.c @@ -76,7 +76,7 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc) default: DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", crtc); - return EINVAL; + return -EINVAL; } } else { switch (crtc) { @@ -89,7 +89,7 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc) default: DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", crtc); - return EINVAL; + return -EINVAL; } } diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 0b8397000f4c..59f834ba283d 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -670,7 +670,7 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder, if (rdev->is_atom_bios) { radeon_encoder->pixel_clock = adjusted_mode->clock; - atombios_external_tmds_setup(encoder, ATOM_ENABLE); + atombios_dvo_setup(encoder, ATOM_ENABLE); fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); } else { fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 680f57644e86..e301c6f9e059 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -375,6 +375,7 @@ struct radeon_encoder { int hdmi_config_offset; int hdmi_audio_workaround; int hdmi_buffer_status; + bool is_ext_encoder; }; struct radeon_connector_atom_dig { @@ -385,6 +386,7 @@ struct radeon_connector_atom_dig { u8 dp_sink_type; int dp_clock; int dp_lane_count; + bool edp_on; }; struct radeon_gpio_rec { @@ -523,9 +525,10 @@ struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int bios_index, int with_tv); struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index); struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index); -extern void atombios_external_tmds_setup(struct drm_encoder *encoder, int action); +extern void atombios_dvo_setup(struct drm_encoder *encoder, int action); extern void atombios_digital_setup(struct drm_encoder *encoder, int action); extern int atombios_get_encoder_mode(struct drm_encoder *encoder); +extern void atombios_set_edp_panel_power(struct drm_connector *connector, int action); extern void radeon_encoder_set_active_device(struct drm_encoder *encoder); extern void radeon_crtc_load_lut(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 8eb183466015..a598d0049aa5 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -69,7 +69,7 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) u32 c = 0; rbo->placement.fpfn = 0; - rbo->placement.lpfn = rbo->rdev->mc.active_vram_size >> PAGE_SHIFT; + rbo->placement.lpfn = 0; rbo->placement.placement = rbo->placements; rbo->placement.busy_placement = rbo->placements; if (domain & RADEON_GEM_DOMAIN_VRAM) @@ -86,11 +86,13 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) } int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj, - unsigned long size, bool kernel, u32 domain, - struct radeon_bo **bo_ptr) + unsigned long size, int byte_align, bool kernel, u32 domain, + struct radeon_bo **bo_ptr) { struct radeon_bo *bo; enum ttm_bo_type type; + unsigned long page_align = roundup(byte_align, PAGE_SIZE) >> PAGE_SHIFT; + unsigned long max_size = 0; int r; if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) { @@ -103,6 +105,14 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj, } *bo_ptr = NULL; + /* maximun bo size is the minimun btw visible vram and gtt size */ + max_size = min(rdev->mc.visible_vram_size, rdev->mc.gtt_size); + if ((page_align << PAGE_SHIFT) >= max_size) { + printk(KERN_WARNING "%s:%d alloc size %ldM bigger than %ldMb limit\n", + __func__, __LINE__, page_align >> (20 - PAGE_SHIFT), max_size >> 20); + return -ENOMEM; + } + retry: bo = kzalloc(sizeof(struct radeon_bo), GFP_KERNEL); if (bo == NULL) @@ -115,7 +125,7 @@ retry: /* Kernel allocation are uninterruptible */ mutex_lock(&rdev->vram_mutex); r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type, - &bo->placement, 0, 0, !kernel, NULL, size, + &bo->placement, page_align, 0, !kernel, NULL, size, &radeon_ttm_bo_destroy); mutex_unlock(&rdev->vram_mutex); if (unlikely(r != 0)) { diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 3481bc7f6f58..d143702b244a 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -137,9 +137,10 @@ static inline int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, } extern int radeon_bo_create(struct radeon_device *rdev, - struct drm_gem_object *gobj, unsigned long size, - bool kernel, u32 domain, - struct radeon_bo **bo_ptr); + struct drm_gem_object *gobj, unsigned long size, + int byte_align, + bool kernel, u32 domain, + struct radeon_bo **bo_ptr); extern int radeon_bo_kmap(struct radeon_bo *bo, void **ptr); extern void radeon_bo_kunmap(struct radeon_bo *bo); extern void radeon_bo_unref(struct radeon_bo **bo); diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 6ea798ce8218..06e79822a2bf 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -176,8 +176,8 @@ int radeon_ib_pool_init(struct radeon_device *rdev) INIT_LIST_HEAD(&rdev->ib_pool.bogus_ib); /* Allocate 1M object buffer */ r = radeon_bo_create(rdev, NULL, RADEON_IB_POOL_SIZE*64*1024, - true, RADEON_GEM_DOMAIN_GTT, - &rdev->ib_pool.robj); + PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, + &rdev->ib_pool.robj); if (r) { DRM_ERROR("radeon: failed to ib pool (%d).\n", r); return r; @@ -332,7 +332,7 @@ int radeon_ring_init(struct radeon_device *rdev, unsigned ring_size) rdev->cp.ring_size = ring_size; /* Allocate ring buffer */ if (rdev->cp.ring_obj == NULL) { - r = radeon_bo_create(rdev, NULL, rdev->cp.ring_size, true, + r = radeon_bo_create(rdev, NULL, rdev->cp.ring_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, &rdev->cp.ring_obj); if (r) { diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c index 313c96bc09da..5b44f652145c 100644 --- a/drivers/gpu/drm/radeon/radeon_test.c +++ b/drivers/gpu/drm/radeon/radeon_test.c @@ -52,7 +52,7 @@ void radeon_test_moves(struct radeon_device *rdev) goto out_cleanup; } - r = radeon_bo_create(rdev, NULL, size, true, RADEON_GEM_DOMAIN_VRAM, + r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, &vram_obj); if (r) { DRM_ERROR("Failed to create VRAM object\n"); @@ -71,7 +71,7 @@ void radeon_test_moves(struct radeon_device *rdev) void **gtt_start, **gtt_end; void **vram_start, **vram_end; - r = radeon_bo_create(rdev, NULL, size, true, + r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, gtt_obj + i); if (r) { DRM_ERROR("Failed to create GTT object %d\n", i); diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 01c2c736a1da..1272e4b6a1d4 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -529,7 +529,7 @@ int radeon_ttm_init(struct radeon_device *rdev) DRM_ERROR("Failed initializing VRAM heap.\n"); return r; } - r = radeon_bo_create(rdev, NULL, 256 * 1024, true, + r = radeon_bo_create(rdev, NULL, 256 * 1024, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, &rdev->stollen_vga_memory); if (r) { diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 245374e2b778..4dfead8cee33 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -915,8 +915,8 @@ static int rv770_vram_scratch_init(struct radeon_device *rdev) if (rdev->vram_scratch.robj == NULL) { r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, - true, RADEON_GEM_DOMAIN_VRAM, - &rdev->vram_scratch.robj); + PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, + &rdev->vram_scratch.robj); if (r) { return r; } |