Hi, Here's a first crack at radeon support for kdb/kms. It's working here on a Mobility FireGL V5200 running Fedora 13/Rawhide on a Thinkpad T60p. The patch applies to the kgdb-next branch of ~jwessel/linux-2.6-kgdb.
I have some issues with it, but I haven't used the intel driver version, so I don't know which of these are unique to this patch: * If X is running, I only make it to a kdb prompt if X was started with -sharevts. * When switching from X -sharevts to kdb, I'm seeing a sleeping function called from invalid context BUG(), full dmesg at: http://dev.laptop.org/~cjb/radeon-kms-kdb-bug * I've only tested the avivo path, because I don't have any pre-avivo radeon hardware handy. It'd be excellent if someone could volunteer to test that, else I'll try harder to find hardware to test locally. I don't know the DRM code well, so I'd appreciate a careful review. Thanks! Signed-off-by: Chris Ball <c...@laptop.org> CC: Jason Wessel <jason.wes...@windriver.com> CC: Jesse Barnes <jbar...@virtuousgeek.org> CC: David Airlie <airl...@linux.ie> --- drivers/gpu/drm/radeon/atombios_crtc.c | 126 +++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 148 +++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_mode.h | 6 + 3 files changed, 280 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index af464e3..7282046 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -618,6 +618,118 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } +/* Assume fb object is pinned & idle & fenced and just update base pointers */ +static int avivo_crtc_set_base_atomic(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int x, int y) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_framebuffer *radeon_fb; + struct drm_gem_object *obj; + struct radeon_bo *rbo; + uint64_t fb_location; + uint32_t fb_format, fb_pitch_pixels, tiling_flags; + int r; + + radeon_fb = to_radeon_framebuffer(fb); + obj = radeon_fb->obj; + rbo = obj->driver_private; + fb_location = radeon_bo_gpu_offset(rbo); + + r = radeon_bo_reserve(rbo, false); + if (unlikely(r != 0)) + return r; + radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); + radeon_bo_unreserve(rbo); + + switch (fb->bits_per_pixel) { + case 8: + fb_format = + AVIVO_D1GRPH_CONTROL_DEPTH_8BPP | + AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; + break; + case 15: + fb_format = + AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | + AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; + break; + case 16: + fb_format = + AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | + AVIVO_D1GRPH_CONTROL_16BPP_RGB565; + break; + case 24: + case 32: + fb_format = + AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | + AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; + break; + default: + DRM_ERROR("Unsupported screen depth %d\n", + fb->bits_per_pixel); + return -EINVAL; + } + + if (tiling_flags & RADEON_TILING_MACRO) + fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; + + if (tiling_flags & RADEON_TILING_MICRO) + fb_format |= AVIVO_D1GRPH_TILED; + + if (radeon_crtc->crtc_id == 0) + WREG32(AVIVO_D1VGA_CONTROL, 0); + else + WREG32(AVIVO_D2VGA_CONTROL, 0); + + if (rdev->family >= CHIP_RV770) { + if (radeon_crtc->crtc_id) { + WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0); + WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0); + } else { + WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0); + WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0); + } + } + WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + (u32) fb_location); + WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + + radeon_crtc->crtc_offset, (u32) fb_location); + WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); + + WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); + WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); + WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); + WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); + WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, fb->width); + WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, fb->height); + + fb_pitch_pixels = fb->pitch / (fb->bits_per_pixel / 8); + WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); + WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); + + WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, + crtc->mode.vdisplay); + x &= ~3; + y &= ~1; + WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, + (x << 16) | y); + WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, + (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); + + if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) + WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, + AVIVO_D1MODE_INTERLEAVE_EN); + else + WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); + + /* Bytes per pixel may have changed */ + radeon_bandwidth_update(rdev); + + return 0; +} + static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { @@ -761,6 +873,19 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, return radeon_crtc_set_base(crtc, x, y, old_fb); } +int atombios_crtc_set_base_atomic(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + + if (ASIC_IS_AVIVO(rdev)) + return avivo_crtc_set_base_atomic(crtc, fb, x, y); + else + return radeon_crtc_set_base_atomic(crtc, fb, x, y); +} + /* properly set additional regs when using atombios */ static void radeon_legacy_atom_fixup(struct drm_crtc *crtc) { @@ -840,6 +965,7 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = { .mode_fixup = atombios_crtc_mode_fixup, .mode_set = atombios_crtc_mode_set, .mode_set_base = atombios_crtc_set_base, + .mode_set_base_atomic = atombios_crtc_set_base_atomic, .prepare = atombios_crtc_prepare, .commit = atombios_crtc_commit, .load_lut = radeon_crtc_load_lut, diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index b6d8081..9c83e3e 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -339,6 +339,153 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) } } +/* Assume fb object is pinned & idle & fenced and just update base pointers */ +int radeon_crtc_set_base_atomic(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct radeon_framebuffer *radeon_fb; + struct drm_gem_object *obj; + struct radeon_bo *rbo; + uint64_t base; + uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0; + uint32_t crtc_pitch, pitch_pixels; + uint32_t tiling_flags; + int format; + uint32_t gen_cntl_reg, gen_cntl_val; + int r; + + radeon_fb = to_radeon_framebuffer(fb); + obj = radeon_fb->obj; + rbo = obj->driver_private; + base = radeon_bo_gpu_offset(rbo); + + r = radeon_bo_reserve(rbo, false); + if (unlikely(r != 0)) + return r; + radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); + radeon_bo_unreserve(rbo); + + switch (fb->bits_per_pixel) { + case 8: + format = 2; + break; + case 15: /* 555 */ + format = 3; + break; + case 16: /* 565 */ + format = 4; + break; + case 24: /* RGB */ + format = 5; + break; + case 32: /* xRGB */ + format = 6; + break; + default: + return false; + } + + if (tiling_flags & RADEON_TILING_MICRO) + DRM_ERROR("trying to scanout microtiled buffer\n"); + + /* if scanout was in GTT this really wouldn't work */ + /* crtc offset is from display base addr not FB location */ + radeon_crtc->legacy_display_base_addr = rdev->mc.vram_location; + + base -= radeon_crtc->legacy_display_base_addr; + + crtc_offset_cntl = 0; + + pitch_pixels = fb->pitch / (fb->bits_per_pixel / 8); + crtc_pitch = (((pitch_pixels * fb->bits_per_pixel) + + ((fb->bits_per_pixel * 8) - 1)) / + (fb->bits_per_pixel * 8)); + crtc_pitch |= crtc_pitch << 16; + + if (tiling_flags & RADEON_TILING_MACRO) { + if (ASIC_IS_R300(rdev)) + crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN | + R300_CRTC_MICRO_TILE_BUFFER_DIS | + R300_CRTC_MACRO_TILE_EN); + else + crtc_offset_cntl |= RADEON_CRTC_TILE_EN; + } else { + if (ASIC_IS_R300(rdev)) + crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN | + R300_CRTC_MICRO_TILE_BUFFER_DIS | + R300_CRTC_MACRO_TILE_EN); + else + crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN; + } + + if (tiling_flags & RADEON_TILING_MACRO) { + if (ASIC_IS_R300(rdev)) { + crtc_tile_x0_y0 = x | (y << 16); + base &= ~0x7ff; + } else { + int byteshift = fb->bits_per_pixel >> 4; + int tile_addr = (((y >> 3) * pitch_pixels + x) >> (8 - byteshift)) << 11; + base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8); + crtc_offset_cntl |= (y % 16); + } + } else { + int offset = y * pitch_pixels + x; + switch (fb->bits_per_pixel) { + case 8: + offset *= 1; + break; + case 15: + case 16: + offset *= 2; + break; + case 24: + offset *= 3; + break; + case 32: + offset *= 4; + break; + default: + return false; + } + base += offset; + } + + base &= ~7; + + if (radeon_crtc->crtc_id == 1) + gen_cntl_reg = RADEON_CRTC2_GEN_CNTL; + else + gen_cntl_reg = RADEON_CRTC_GEN_CNTL; + + gen_cntl_val = RREG32(gen_cntl_reg); + gen_cntl_val &= ~(0xf << 8); + gen_cntl_val |= (format << 8); + WREG32(gen_cntl_reg, gen_cntl_val); + + crtc_offset = (u32)base; + + WREG32(RADEON_DISPLAY_BASE_ADDR + radeon_crtc->crtc_offset, radeon_crtc->legacy_display_base_addr); + + if (ASIC_IS_R300(rdev)) { + if (radeon_crtc->crtc_id) + WREG32(R300_CRTC2_TILE_X0_Y0, crtc_tile_x0_y0); + else + WREG32(R300_CRTC_TILE_X0_Y0, crtc_tile_x0_y0); + } + WREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset, crtc_offset_cntl); + WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset); + WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch); + + /* Bytes per pixel may have changed */ + radeon_bandwidth_update(rdev); + + return 0; +} + int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { @@ -1039,6 +1186,7 @@ static const struct drm_crtc_helper_funcs legacy_helper_funcs = { .mode_fixup = radeon_crtc_mode_fixup, .mode_set = radeon_crtc_mode_set, .mode_set_base = radeon_crtc_set_base, + .mode_set_base_atomic = radeon_crtc_set_base_atomic, .prepare = radeon_crtc_prepare, .commit = radeon_crtc_commit, .load_lut = radeon_crtc_load_lut, diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index e81b2ae..dae9c71 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -455,6 +455,9 @@ extern void radeon_encoder_set_active_device(struct drm_encoder *encoder); extern void radeon_crtc_load_lut(struct drm_crtc *crtc); extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb); +extern int atombios_crtc_set_base_atomic(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int x, int y); extern int atombios_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -464,6 +467,9 @@ extern void atombios_crtc_dpms(struct drm_crtc *crtc, int mode); extern int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb); +extern int radeon_crtc_set_base_atomic(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int x, int y); extern int radeon_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, -- 1.6.6 -- Chris Ball <c...@laptop.org> One Laptop Per Child ------------------------------------------------------------------------------ SOLARIS 10 is the OS for Data Centers - provides features such as DTrace, Predictive Self Healing and Award Winning ZFS. Get Solaris 10 NOW http://p.sf.net/sfu/solaris-dev2dev _______________________________________________ Kgdb-bugreport mailing list Kgdb-bugreport@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kgdb-bugreport