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

Reply via email to