From 0dd8c3f093e3d0cab2cc967f9620b41a125f1f56 Mon Sep 17 00:00:00 2001 From: Marcin Kościelnicki Date: Wed, 17 Mar 2010 00:58:47 +0000 Subject: drm/nv50: Fix NEWCTX_DONE flag number Signed-off-by: Marcin Kościelnicki Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_grctx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c index 546b31949a30..3c3cc4606a03 100644 --- a/drivers/gpu/drm/nouveau/nv50_grctx.c +++ b/drivers/gpu/drm/nouveau/nv50_grctx.c @@ -55,12 +55,12 @@ #define CP_FLAG_AUTO_LOAD ((2 * 32) + 5) #define CP_FLAG_AUTO_LOAD_NOT_PENDING 0 #define CP_FLAG_AUTO_LOAD_PENDING 1 +#define CP_FLAG_NEWCTX ((2 * 32) + 10) +#define CP_FLAG_NEWCTX_BUSY 0 +#define CP_FLAG_NEWCTX_DONE 1 #define CP_FLAG_XFER ((2 * 32) + 11) #define CP_FLAG_XFER_IDLE 0 #define CP_FLAG_XFER_BUSY 1 -#define CP_FLAG_NEWCTX ((2 * 32) + 12) -#define CP_FLAG_NEWCTX_BUSY 0 -#define CP_FLAG_NEWCTX_DONE 1 #define CP_FLAG_ALWAYS ((2 * 32) + 13) #define CP_FLAG_ALWAYS_FALSE 0 #define CP_FLAG_ALWAYS_TRUE 1 -- cgit v1.2.3 From 0c324971986f1498ccd289cb2b4927a6fd3efbe5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 16 Mar 2010 13:20:58 +1000 Subject: drm/nv50: fix fbcon when framebuffer above 4GiB mark This can't actually happen right now, but lets fix it anyway. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_fbcon.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index 25a3cd8794f9..a8c70e7e9184 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -157,8 +157,11 @@ nv50_fbcon_accel_init(struct fb_info *info) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; struct nouveau_gpuobj *eng2d = NULL; + uint64_t fb; int ret, format; + fb = info->fix.smem_start - dev_priv->fb_phys + dev_priv->vm_vram_base; + switch (info->var.bits_per_pixel) { case 8: format = 0xf3; @@ -248,9 +251,8 @@ nv50_fbcon_accel_init(struct fb_info *info) OUT_RING(chan, info->fix.line_length); OUT_RING(chan, info->var.xres_virtual); OUT_RING(chan, info->var.yres_virtual); - OUT_RING(chan, 0); - OUT_RING(chan, info->fix.smem_start - dev_priv->fb_phys + - dev_priv->vm_vram_base); + OUT_RING(chan, upper_32_bits(fb)); + OUT_RING(chan, lower_32_bits(fb)); BEGIN_RING(chan, NvSub2D, 0x0230, 2); OUT_RING(chan, format); OUT_RING(chan, 1); @@ -258,9 +260,8 @@ nv50_fbcon_accel_init(struct fb_info *info) OUT_RING(chan, info->fix.line_length); OUT_RING(chan, info->var.xres_virtual); OUT_RING(chan, info->var.yres_virtual); - OUT_RING(chan, 0); - OUT_RING(chan, info->fix.smem_start - dev_priv->fb_phys + - dev_priv->vm_vram_base); + OUT_RING(chan, upper_32_bits(fb)); + OUT_RING(chan, lower_32_bits(fb)); return 0; } -- cgit v1.2.3 From 40b2a687bd92827ca144d3623cf48377d8f7680d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 15 Mar 2010 16:43:47 +1000 Subject: drm/nv50: add more 0x100c80 flushy magic Fixes the !vbo_fifo path in the 3D driver on certain chipsets. Still not really any good idea of what exactly the magic achieves, but it makes things work. While we're at it, in the PCIEGART path, flush on unbinding also. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_mem.c | 28 ++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_sgdma.c | 18 ++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 2dc09dbd817d..a4d5ecc6ed5a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -347,6 +347,20 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, return -EBUSY; } + nv_wr32(dev, 0x100c80, 0x00040001); + if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { + NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); + NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); + return -EBUSY; + } + + nv_wr32(dev, 0x100c80, 0x00060001); + if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { + NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); + NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); + return -EBUSY; + } + return 0; } @@ -384,6 +398,20 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) } nv_wr32(dev, 0x100c80, 0x00000001); + if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { + NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); + NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); + return; + } + + nv_wr32(dev, 0x100c80, 0x00040001); + if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { + NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); + NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); + return; + } + + nv_wr32(dev, 0x100c80, 0x00060001); if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index ed1590577b6c..554fb45730c1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -171,6 +171,24 @@ nouveau_sgdma_unbind(struct ttm_backend *be) } dev_priv->engine.instmem.finish_access(nvbe->dev); + if (dev_priv->card_type == NV_50) { + nv_wr32(dev, 0x100c80, 0x00050001); + if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { + NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); + NV_ERROR(dev, "0x100c80 = 0x%08x\n", + nv_rd32(dev, 0x100c80)); + return -EBUSY; + } + + nv_wr32(dev, 0x100c80, 0x00000001); + if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { + NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); + NV_ERROR(dev, "0x100c80 = 0x%08x\n", + nv_rd32(dev, 0x100c80)); + return -EBUSY; + } + } + nvbe->bound = false; return 0; } -- cgit v1.2.3 From 78ad0f7bf2bb667729581f099781fc0b7ae58fcc Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 18 Mar 2010 13:07:47 +0100 Subject: drm/nouveau: Make use of TTM busy_placements. Previously we were filling it the same as "placements", but in some cases there're valid alternatives that we were ignoring completely. Keeping a back-up memory type helps on several low-mem situations. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 61 +++++++++++++++++++---------------- drivers/gpu/drm/nouveau/nouveau_drv.h | 4 ++- drivers/gpu/drm/nouveau/nouveau_gem.c | 55 ++++++++++++++----------------- 3 files changed, 61 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 026612471c92..418d881050a0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -153,7 +153,7 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, nvbo->placement.fpfn = 0; nvbo->placement.lpfn = mappable ? dev_priv->fb_mappable_pages : 0; - nouveau_bo_placement_set(nvbo, flags); + nouveau_bo_placement_set(nvbo, flags, 0); nvbo->channel = chan; ret = ttm_bo_init(&dev_priv->ttm.bdev, &nvbo->bo, size, @@ -172,26 +172,33 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, return 0; } +static void +set_placement_list(uint32_t *pl, unsigned *n, uint32_t type, uint32_t flags) +{ + *n = 0; + + if (type & TTM_PL_FLAG_VRAM) + pl[(*n)++] = TTM_PL_FLAG_VRAM | flags; + if (type & TTM_PL_FLAG_TT) + pl[(*n)++] = TTM_PL_FLAG_TT | flags; + if (type & TTM_PL_FLAG_SYSTEM) + pl[(*n)++] = TTM_PL_FLAG_SYSTEM | flags; +} + void -nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t memtype) +nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy) { - int n = 0; - - if (memtype & TTM_PL_FLAG_VRAM) - nvbo->placements[n++] = TTM_PL_FLAG_VRAM | TTM_PL_MASK_CACHING; - if (memtype & TTM_PL_FLAG_TT) - nvbo->placements[n++] = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING; - if (memtype & TTM_PL_FLAG_SYSTEM) - nvbo->placements[n++] = TTM_PL_FLAG_SYSTEM | TTM_PL_MASK_CACHING; - nvbo->placement.placement = nvbo->placements; - nvbo->placement.busy_placement = nvbo->placements; - nvbo->placement.num_placement = n; - nvbo->placement.num_busy_placement = n; - - if (nvbo->pin_refcnt) { - while (n--) - nvbo->placements[n] |= TTM_PL_FLAG_NO_EVICT; - } + struct ttm_placement *pl = &nvbo->placement; + uint32_t flags = TTM_PL_MASK_CACHING | + (nvbo->pin_refcnt ? TTM_PL_FLAG_NO_EVICT : 0); + + pl->placement = nvbo->placements; + set_placement_list(nvbo->placements, &pl->num_placement, + type, flags); + + pl->busy_placement = nvbo->busy_placements; + set_placement_list(nvbo->busy_placements, &pl->num_busy_placement, + type | busy, flags); } int @@ -199,7 +206,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype) { struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev); struct ttm_buffer_object *bo = &nvbo->bo; - int ret, i; + int ret; if (nvbo->pin_refcnt && !(memtype & (1 << bo->mem.mem_type))) { NV_ERROR(nouveau_bdev(bo->bdev)->dev, @@ -215,9 +222,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype) if (ret) goto out; - nouveau_bo_placement_set(nvbo, memtype); - for (i = 0; i < nvbo->placement.num_placement; i++) - nvbo->placements[i] |= TTM_PL_FLAG_NO_EVICT; + nouveau_bo_placement_set(nvbo, memtype, 0); ret = ttm_bo_validate(bo, &nvbo->placement, false, false); if (ret == 0) { @@ -244,7 +249,7 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo) { struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev); struct ttm_buffer_object *bo = &nvbo->bo; - int ret, i; + int ret; if (--nvbo->pin_refcnt) return 0; @@ -253,8 +258,7 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo) if (ret) return ret; - for (i = 0; i < nvbo->placement.num_placement; i++) - nvbo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; + nouveau_bo_placement_set(nvbo, bo->mem.placement, 0); ret = ttm_bo_validate(bo, &nvbo->placement, false, false); if (ret == 0) { @@ -439,10 +443,11 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) switch (bo->mem.mem_type) { case TTM_PL_VRAM: - nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT); + nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT, + TTM_PL_FLAG_SYSTEM); break; default: - nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_SYSTEM); + nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_SYSTEM, 0); break; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index d8b559011777..fd17fae9369c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -76,6 +76,7 @@ struct nouveau_bo { struct ttm_buffer_object bo; struct ttm_placement placement; u32 placements[3]; + u32 busy_placements[3]; struct ttm_bo_kmap_obj kmap; struct list_head head; @@ -1124,7 +1125,8 @@ extern int nouveau_bo_pin(struct nouveau_bo *, uint32_t flags); extern int nouveau_bo_unpin(struct nouveau_bo *); extern int nouveau_bo_map(struct nouveau_bo *); extern void nouveau_bo_unmap(struct nouveau_bo *); -extern void nouveau_bo_placement_set(struct nouveau_bo *, uint32_t memtype); +extern void nouveau_bo_placement_set(struct nouveau_bo *, uint32_t type, + uint32_t busy); extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index); extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val); extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index); diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 0d22f66f1c79..1bc0b38a5167 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -180,40 +180,35 @@ nouveau_gem_set_domain(struct drm_gem_object *gem, uint32_t read_domains, { struct nouveau_bo *nvbo = gem->driver_private; struct ttm_buffer_object *bo = &nvbo->bo; - uint64_t flags; + uint32_t domains = valid_domains & + (write_domains ? write_domains : read_domains); + uint32_t pref_flags = 0, valid_flags = 0; - if (!valid_domains || (!read_domains && !write_domains)) + if (!domains) return -EINVAL; - if (write_domains) { - if ((valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) && - (write_domains & NOUVEAU_GEM_DOMAIN_VRAM)) - flags = TTM_PL_FLAG_VRAM; - else - if ((valid_domains & NOUVEAU_GEM_DOMAIN_GART) && - (write_domains & NOUVEAU_GEM_DOMAIN_GART)) - flags = TTM_PL_FLAG_TT; - else - return -EINVAL; - } else { - if ((valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) && - (read_domains & NOUVEAU_GEM_DOMAIN_VRAM) && - bo->mem.mem_type == TTM_PL_VRAM) - flags = TTM_PL_FLAG_VRAM; - else - if ((valid_domains & NOUVEAU_GEM_DOMAIN_GART) && - (read_domains & NOUVEAU_GEM_DOMAIN_GART) && - bo->mem.mem_type == TTM_PL_TT) - flags = TTM_PL_FLAG_TT; - else - if ((valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) && - (read_domains & NOUVEAU_GEM_DOMAIN_VRAM)) - flags = TTM_PL_FLAG_VRAM; - else - flags = TTM_PL_FLAG_TT; - } + if (valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) + valid_flags |= TTM_PL_FLAG_VRAM; + + if (valid_domains & NOUVEAU_GEM_DOMAIN_GART) + valid_flags |= TTM_PL_FLAG_TT; + + if ((domains & NOUVEAU_GEM_DOMAIN_VRAM) && + bo->mem.mem_type == TTM_PL_VRAM) + pref_flags |= TTM_PL_FLAG_VRAM; + + else if ((domains & NOUVEAU_GEM_DOMAIN_GART) && + bo->mem.mem_type == TTM_PL_TT) + pref_flags |= TTM_PL_FLAG_TT; + + else if (domains & NOUVEAU_GEM_DOMAIN_VRAM) + pref_flags |= TTM_PL_FLAG_VRAM; + + else + pref_flags |= TTM_PL_FLAG_TT; + + nouveau_bo_placement_set(nvbo, pref_flags, valid_flags); - nouveau_bo_placement_set(nvbo, flags); return 0; } -- cgit v1.2.3 From 952eb63543552deb1bf1113739d59d29172d7755 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 18 Mar 2010 09:23:19 +1000 Subject: drm/nouveau: remove some unused members from drm_nouveau_private Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 2 -- drivers/gpu/drm/nouveau/nouveau_drv.h | 9 --------- 2 files changed, 11 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 6dfb425cbae9..1fc57ef58295 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -142,7 +142,6 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, GFP_KERNEL); if (!dev_priv->fifos[channel]) return -ENOMEM; - dev_priv->fifo_alloc_count++; chan = dev_priv->fifos[channel]; INIT_LIST_HEAD(&chan->nvsw.vbl_wait); INIT_LIST_HEAD(&chan->fence.pending); @@ -321,7 +320,6 @@ nouveau_channel_free(struct nouveau_channel *chan) iounmap(chan->user); dev_priv->fifos[chan->id] = NULL; - dev_priv->fifo_alloc_count--; kfree(chan); } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index fd17fae9369c..5d3618e4520d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -534,7 +534,6 @@ struct drm_nouveau_private { struct fb_info *fbdev_info; - int fifo_alloc_count; struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR]; struct nouveau_engine engine; @@ -573,10 +572,6 @@ struct drm_nouveau_private { struct nouveau_gpuobj *sg_ctxdma; struct page *sg_dummy_page; dma_addr_t sg_dummy_bus; - - /* nottm hack */ - struct drm_ttm_backend *sg_be; - unsigned long sg_handle; } gart_info; /* nv10-nv40 tiling regions */ @@ -615,11 +610,7 @@ struct drm_nouveau_private { uint32_t dac_users[4]; struct nouveau_suspend_resume { - uint32_t fifo_mode; - uint32_t graph_ctx_control; - uint32_t graph_state; uint32_t *ramin_copy; - uint64_t ramin_size; } susres; struct backlight_device *backlight; -- cgit v1.2.3 From a76fb4e8ffe42144529e21fe1e609b762e8eb5cc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 18 Mar 2010 09:45:20 +1000 Subject: drm/nouveau: detect vram amount once, and save the value As opposed to repeatedly reading the amount back from the GPU every time we need to know the VRAM size. We should now fail to load gracefully on detecting no VRAM, rather than something potentially messy happening. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 6 +- drivers/gpu/drm/nouveau/nouveau_debugfs.c | 5 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 22 +++---- drivers/gpu/drm/nouveau/nouveau_mem.c | 96 +++++++++++++++---------------- drivers/gpu/drm/nouveau/nouveau_state.c | 6 +- drivers/gpu/drm/nouveau/nv40_fifo.c | 2 +- drivers/gpu/drm/nouveau/nv50_display.c | 4 +- drivers/gpu/drm/nouveau/nv50_instmem.c | 9 +-- 8 files changed, 74 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 418d881050a0..eeab3fb27083 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -71,7 +71,7 @@ nouveau_bo_fixup_align(struct drm_device *dev, * many small buffers. */ if (dev_priv->card_type == NV_50) { - uint32_t block_size = nouveau_mem_fb_amount(dev) >> 15; + uint32_t block_size = dev_priv->vram_size >> 15; int i; switch (tile_flags) { @@ -399,8 +399,8 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->io_addr = NULL; man->io_offset = drm_get_resource_start(dev, 1); man->io_size = drm_get_resource_len(dev, 1); - if (man->io_size > nouveau_mem_fb_amount(dev)) - man->io_size = nouveau_mem_fb_amount(dev); + if (man->io_size > dev_priv->vram_size) + man->io_size = dev_priv->vram_size; man->gpu_offset = dev_priv->vm_vram_base; break; diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c index 8ff9ef5d4b47..a251886a0ce6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c +++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c @@ -137,10 +137,9 @@ nouveau_debugfs_memory_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_minor *minor = node->minor; - struct drm_device *dev = minor->dev; + struct drm_nouveau_private *dev_priv = minor->dev->dev_private; - seq_printf(m, "VRAM total: %dKiB\n", - (int)(nouveau_mem_fb_amount(dev) >> 10)); + seq_printf(m, "VRAM total: %dKiB\n", (int)(dev_priv->vram_size >> 10)); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 5d3618e4520d..f7d4d2a10052 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -553,12 +553,6 @@ struct drm_nouveau_private { uint32_t ramro_offset; uint32_t ramro_size; - /* base physical addresses */ - uint64_t fb_phys; - uint64_t fb_available_size; - uint64_t fb_mappable_pages; - uint64_t fb_aper_free; - struct { enum { NOUVEAU_GART_NONE = 0, @@ -580,6 +574,16 @@ struct drm_nouveau_private { spinlock_t lock; } tile; + /* VRAM/fb configuration */ + uint64_t vram_size; + uint64_t vram_sys_base; + + uint64_t fb_phys; + uint64_t fb_available_size; + uint64_t fb_mappable_pages; + uint64_t fb_aper_free; + int fb_mtrr; + /* G8x/G9x virtual address space */ uint64_t vm_gart_base; uint64_t vm_gart_size; @@ -588,10 +592,6 @@ struct drm_nouveau_private { uint64_t vm_end; struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR]; int vm_vram_pt_nr; - uint64_t vram_sys_base; - - /* the mtrr covering the FB */ - int fb_mtrr; struct mem_block *ramin_heap; @@ -709,7 +709,7 @@ extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *, struct drm_file *, int tail); extern void nouveau_mem_takedown(struct mem_block **heap); extern void nouveau_mem_free_block(struct mem_block *); -extern uint64_t nouveau_mem_fb_amount(struct drm_device *); +extern int nouveau_mem_detect(struct drm_device *dev); extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap); extern int nouveau_mem_init(struct drm_device *); extern int nouveau_mem_init_agp(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index a4d5ecc6ed5a..775a7017af64 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -477,9 +477,30 @@ void nouveau_mem_close(struct drm_device *dev) } } -/*XXX won't work on BSD because of pci_read_config_dword */ static uint32_t -nouveau_mem_fb_amount_igp(struct drm_device *dev) +nouveau_mem_detect_nv04(struct drm_device *dev) +{ + uint32_t boot0 = nv_rd32(dev, NV03_BOOT_0); + + if (boot0 & 0x00000100) + return (((boot0 >> 12) & 0xf) * 2 + 2) * 1024 * 1024; + + switch (boot0 & NV03_BOOT_0_RAM_AMOUNT) { + case NV04_BOOT_0_RAM_AMOUNT_32MB: + return 32 * 1024 * 1024; + case NV04_BOOT_0_RAM_AMOUNT_16MB: + return 16 * 1024 * 1024; + case NV04_BOOT_0_RAM_AMOUNT_8MB: + return 8 * 1024 * 1024; + case NV04_BOOT_0_RAM_AMOUNT_4MB: + return 4 * 1024 * 1024; + } + + return 0; +} + +static uint32_t +nouveau_mem_detect_nforce(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct pci_dev *bridge; @@ -491,11 +512,11 @@ nouveau_mem_fb_amount_igp(struct drm_device *dev) return 0; } - if (dev_priv->flags&NV_NFORCE) { + if (dev_priv->flags & NV_NFORCE) { pci_read_config_dword(bridge, 0x7C, &mem); return (uint64_t)(((mem >> 6) & 31) + 1)*1024*1024; } else - if (dev_priv->flags&NV_NFORCE2) { + if (dev_priv->flags & NV_NFORCE2) { pci_read_config_dword(bridge, 0x84, &mem); return (uint64_t)(((mem >> 4) & 127) + 1)*1024*1024; } @@ -505,50 +526,32 @@ nouveau_mem_fb_amount_igp(struct drm_device *dev) } /* returns the amount of FB ram in bytes */ -uint64_t nouveau_mem_fb_amount(struct drm_device *dev) +int +nouveau_mem_detect(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t boot0; - - switch (dev_priv->card_type) { - case NV_04: - boot0 = nv_rd32(dev, NV03_BOOT_0); - if (boot0 & 0x00000100) - return (((boot0 >> 12) & 0xf) * 2 + 2) * 1024 * 1024; - - switch (boot0 & NV03_BOOT_0_RAM_AMOUNT) { - case NV04_BOOT_0_RAM_AMOUNT_32MB: - return 32 * 1024 * 1024; - case NV04_BOOT_0_RAM_AMOUNT_16MB: - return 16 * 1024 * 1024; - case NV04_BOOT_0_RAM_AMOUNT_8MB: - return 8 * 1024 * 1024; - case NV04_BOOT_0_RAM_AMOUNT_4MB: - return 4 * 1024 * 1024; - } - break; - case NV_10: - case NV_20: - case NV_30: - case NV_40: - case NV_50: - default: - if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) { - return nouveau_mem_fb_amount_igp(dev); - } else { - uint64_t mem; - mem = (nv_rd32(dev, NV04_FIFO_DATA) & - NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK) >> - NV10_FIFO_DATA_RAM_AMOUNT_MB_SHIFT; - return mem * 1024 * 1024; - } - break; + + if (dev_priv->card_type == NV_04) { + dev_priv->vram_size = nouveau_mem_detect_nv04(dev); + } else + if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) { + dev_priv->vram_size = nouveau_mem_detect_nforce(dev); + } else { + dev_priv->vram_size = nv_rd32(dev, NV04_FIFO_DATA); + dev_priv->vram_size &= NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK; + if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) + dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10) << 12; } - NV_ERROR(dev, - "Unable to detect video ram size. Please report your setup to " - DRIVER_EMAIL "\n"); - return 0; + NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20)); + if (dev_priv->vram_sys_base) { + NV_INFO(dev, "Stolen system memory at: 0x%010llx\n", + dev_priv->vram_sys_base); + } + + if (dev_priv->vram_size) + return 0; + return -ENOMEM; } #if __OS_HAS_AGP @@ -659,15 +662,12 @@ nouveau_mem_init(struct drm_device *dev) spin_lock_init(&dev_priv->ttm.bo_list_lock); spin_lock_init(&dev_priv->tile.lock); - dev_priv->fb_available_size = nouveau_mem_fb_amount(dev); - + dev_priv->fb_available_size = dev_priv->vram_size; dev_priv->fb_mappable_pages = dev_priv->fb_available_size; if (dev_priv->fb_mappable_pages > drm_get_resource_len(dev, 1)) dev_priv->fb_mappable_pages = drm_get_resource_len(dev, 1); dev_priv->fb_mappable_pages >>= PAGE_SHIFT; - NV_INFO(dev, "%d MiB VRAM\n", (int)(dev_priv->fb_available_size >> 20)); - /* remove reserved space at end of vram from available amount */ dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram; dev_priv->fb_aper_free = dev_priv->fb_available_size; diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 58b46807de23..1ee2b65d72e9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -340,7 +340,7 @@ nouveau_card_init_channel(struct drm_device *dev) gpuobj = NULL; ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY, - 0, nouveau_mem_fb_amount(dev), + 0, dev_priv->vram_size, NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM, &gpuobj); if (ret) @@ -426,6 +426,10 @@ nouveau_card_init(struct drm_device *dev) goto out; } + ret = nouveau_mem_detect(dev); + if (ret) + goto out_bios; + ret = nouveau_gpuobj_early_init(dev); if (ret) goto out_bios; diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c index 6b2ef4a9fce1..500ccfd3a0b8 100644 --- a/drivers/gpu/drm/nouveau/nv40_fifo.c +++ b/drivers/gpu/drm/nouveau/nv40_fifo.c @@ -278,7 +278,7 @@ nv40_fifo_init_ramxx(struct drm_device *dev) default: nv_wr32(dev, 0x2230, 0); nv_wr32(dev, NV40_PFIFO_RAMFC, - ((nouveau_mem_fb_amount(dev) - 512 * 1024 + + ((dev_priv->vram_size - 512 * 1024 + dev_priv->ramfc_offset) >> 16) | (3 << 16)); break; } diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index fac6c88a2b1f..bd99986a1146 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -143,7 +143,7 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) } ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoVRAM, 0, 0x19, - 0, nouveau_mem_fb_amount(dev)); + 0, dev_priv->vram_size); if (ret) { nv50_evo_channel_del(pchan); return ret; @@ -231,7 +231,7 @@ nv50_display_init(struct drm_device *dev) /* This used to be in crtc unblank, but seems out of place there. */ nv_wr32(dev, NV50_PDISPLAY_UNK_380, 0); /* RAM is clamped to 256 MiB. */ - ram_amount = nouveau_mem_fb_amount(dev); + ram_amount = dev_priv->vram_size; NV_DEBUG_KMS(dev, "ram_amount %d\n", ram_amount); if (ram_amount > 256*1024*1024) ram_amount = 256*1024*1024; diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index de1f5b0062c5..34280eb31df3 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -76,17 +76,12 @@ nv50_instmem_init(struct drm_device *dev) for (i = 0x1700; i <= 0x1710; i += 4) priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i); - if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) - dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10) << 12; - else - dev_priv->vram_sys_base = 0; - /* Reserve the last MiB of VRAM, we should probably try to avoid * setting up the below tables over the top of the VBIOS image at * some point. */ dev_priv->ramin_rsvd_vram = 1 << 20; - c_offset = nouveau_mem_fb_amount(dev) - dev_priv->ramin_rsvd_vram; + c_offset = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; c_size = 128 << 10; c_vmpd = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x1400 : 0x200; c_ramfc = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x0 : 0x20; @@ -106,7 +101,7 @@ nv50_instmem_init(struct drm_device *dev) dev_priv->vm_gart_size = NV50_VM_BLOCK; dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size; - dev_priv->vm_vram_size = nouveau_mem_fb_amount(dev); + dev_priv->vm_vram_size = dev_priv->vram_size; if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM) dev_priv->vm_vram_size = NV50_VM_MAX_VRAM; dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK); -- cgit v1.2.3 From f3bbb9ccbf2a0362363ce6d7e4e57dbf34a5cef1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 18 Mar 2010 12:05:43 +1000 Subject: drm/nv40: rework lvds table parsing All indications seem to be that the version 0x30 table should be handled the same way as 0x40 (as used on G80), at least for the parts that we currently try use. This commit cleans up the parsing to make it clearer about what we're actually trying to achieve, and unifies the 0x30/0x40 parsing. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 44 +++++++++++++--------------------- drivers/gpu/drm/nouveau/nouveau_bios.h | 1 - 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index b5a9336a2e88..075eb894648f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -3198,7 +3198,6 @@ static int run_lvds_table(struct drm_device *dev, struct dcb_entry *dcbent, int struct nvbios *bios = &dev_priv->vbios; unsigned int outputset = (dcbent->or == 4) ? 1 : 0; uint16_t scriptptr = 0, clktable; - uint8_t clktableptr = 0; /* * For now we assume version 3.0 table - g80 support will need some @@ -3217,26 +3216,29 @@ static int run_lvds_table(struct drm_device *dev, struct dcb_entry *dcbent, int scriptptr = ROM16(bios->data[bios->fp.lvdsmanufacturerpointer + 11 + outputset * 2]); break; case LVDS_RESET: + clktable = bios->fp.lvdsmanufacturerpointer + 15; + if (dcbent->or == 4) + clktable += 8; + if (dcbent->lvdsconf.use_straps_for_mode) { if (bios->fp.dual_link) - clktableptr += 2; - if (bios->fp.BITbit1) - clktableptr++; + clktable += 4; + if (bios->fp.if_is_24bit) + clktable += 2; } else { /* using EDID */ - uint8_t fallback = bios->data[bios->fp.lvdsmanufacturerpointer + 4]; - int fallbackcmpval = (dcbent->or == 4) ? 4 : 1; + int cmpval_24bit = (dcbent->or == 4) ? 4 : 1; if (bios->fp.dual_link) { - clktableptr += 2; - fallbackcmpval *= 2; + clktable += 4; + cmpval_24bit <<= 1; } - if (fallbackcmpval & fallback) - clktableptr++; + + if (bios->fp.strapless_is_24bit & cmpval_24bit) + clktable += 2; } - /* adding outputset * 8 may not be correct */ - clktable = ROM16(bios->data[bios->fp.lvdsmanufacturerpointer + 15 + clktableptr * 2 + outputset * 8]); + clktable = ROM16(bios->data[clktable]); if (!clktable) { NV_ERROR(dev, "Pixel clock comparison table not found\n"); return -ENOENT; @@ -3638,31 +3640,19 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b *if_is_24bit = bios->data[lvdsofs] & 16; break; case 0x30: - /* - * My money would be on there being a 24 bit interface bit in - * this table, but I have no example of a laptop bios with a - * 24 bit panel to confirm that. Hence we shout loudly if any - * bit other than bit 0 is set (I've not even seen bit 1) - */ - if (bios->data[lvdsofs] > 1) - NV_ERROR(dev, - "You have a very unusual laptop display; please report it\n"); + case 0x40: /* * No sign of the "power off for reset" or "reset for panel * on" bits, but it's safer to assume we should */ bios->fp.power_off_for_reset = true; bios->fp.reset_after_pclk_change = true; + /* * It's ok lvdsofs is wrong for nv4x edid case; dual_link is - * over-written, and BITbit1 isn't used + * over-written, and if_is_24bit isn't used */ bios->fp.dual_link = bios->data[lvdsofs] & 1; - bios->fp.BITbit1 = bios->data[lvdsofs] & 2; - bios->fp.duallink_transition_clk = ROM16(bios->data[bios->fp.lvdsmanufacturerpointer + 5]) * 10; - break; - case 0x40: - bios->fp.dual_link = bios->data[lvdsofs] & 1; bios->fp.if_is_24bit = bios->data[lvdsofs] & 2; bios->fp.strapless_is_24bit = bios->data[bios->fp.lvdsmanufacturerpointer + 4]; bios->fp.duallink_transition_clk = ROM16(bios->data[bios->fp.lvdsmanufacturerpointer + 5]) * 10; diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index 4f88e6924d27..fd6274a90148 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h @@ -267,7 +267,6 @@ struct nvbios { bool reset_after_pclk_change; bool dual_link; bool link_c_increment; - bool BITbit1; bool if_is_24bit; int duallink_transition_clk; uint8_t strapless_is_24bit; -- cgit v1.2.3 From 2eb92c80074ecfbc691741720382007417f64523 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 18 Mar 2010 13:38:04 +1000 Subject: drm/nv40: add LVDS table quirk for Dell Latitude D620 Should fix: https://bugzilla.redhat.com/show_bug.cgi?id=505132 https://bugzilla.redhat.com/show_bug.cgi?id=543091 https://bugzilla.redhat.com/show_bug.cgi?id=530425 https://bugs.edge.launchpad.net/ubuntu/+source/xserver-xorg-video-nouveau/ +bug/539730 Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 075eb894648f..ad6c2d4520ae 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -3659,6 +3659,21 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b break; } + /* Dell Latitude D620 reports a too-high value for the dual-link + * transition freq, causing us to program the panel incorrectly. + * + * It doesn't appear the VBIOS actually uses its transition freq + * (90000kHz), instead it uses the "Number of LVDS channels" field + * out of the panel ID structure (http://www.spwg.org/). + * + * For the moment, a quirk will do :) + */ + if ((dev->pdev->device == 0x01d7) && + (dev->pdev->subsystem_vendor == 0x1028) && + (dev->pdev->subsystem_device == 0x01c2)) { + bios->fp.duallink_transition_clk = 80000; + } + /* set dual_link flag for EDID case */ if (pxclk && (chip_version < 0x25 || chip_version > 0x28)) bios->fp.dual_link = (pxclk >= bios->fp.duallink_transition_clk); -- cgit v1.2.3 From 494ab824f179ddeb2022cbb1d25aee41ab46ee9b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 Mar 2010 12:49:59 +1000 Subject: drm/nv50: fix instmem init on IGPs if stolen mem crosses 4GiB mark Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_instmem.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 34280eb31df3..5f21df31f3aa 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -63,9 +63,10 @@ nv50_instmem_init(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan; uint32_t c_offset, c_size, c_ramfc, c_vmpd, c_base, pt_size; + uint32_t save_nv001700; + uint64_t v; struct nv50_instmem_priv *priv; int ret, i; - uint32_t v, save_nv001700; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) @@ -184,8 +185,8 @@ nv50_instmem_init(struct drm_device *dev) i = 0; while (v < dev_priv->vram_sys_base + c_offset + c_size) { - BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, v); - BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, 0x00000000); + BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, lower_32_bits(v)); + BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, upper_32_bits(v)); v += 0x1000; i += 8; } -- cgit v1.2.3 From 78bb35129e9400fb50580e971d964563fc8e0218 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 25 Mar 2010 16:00:09 +1000 Subject: drm/nouveau: fixup the init failure paths some more Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_state.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 1ee2b65d72e9..a9e9cf35429c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -505,7 +505,7 @@ nouveau_card_init(struct drm_device *dev) else ret = nv04_display_create(dev); if (ret) - goto out_irq; + goto out_channel; } ret = nouveau_backlight_init(dev); @@ -519,6 +519,11 @@ nouveau_card_init(struct drm_device *dev) return 0; +out_channel: + if (dev_priv->channel) { + nouveau_channel_free(dev_priv->channel); + dev_priv->channel = NULL; + } out_irq: drm_irq_uninstall(dev); out_fifo: @@ -536,6 +541,7 @@ out_mc: out_gpuobj: nouveau_gpuobj_takedown(dev); out_mem: + nouveau_sgdma_takedown(dev); nouveau_mem_close(dev); out_instmem: engine->instmem.takedown(dev); -- cgit v1.2.3 From a1663ed3412f4b94edcf30b271c9db3ace533605 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 25 Mar 2010 16:01:04 +1000 Subject: drm/nv50: cleanup properly if PDISPLAY init fails Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index bd99986a1146..fd00f4000f14 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -529,8 +529,10 @@ int nv50_display_create(struct drm_device *dev) } ret = nv50_display_init(dev); - if (ret) + if (ret) { + nv50_display_destroy(dev); return ret; + } return 0; } -- cgit v1.2.3 From d327dd4e771b5820743aeba0622116c5c8806388 Mon Sep 17 00:00:00 2001 From: Marcin Kościelnicki Date: Wed, 24 Mar 2010 13:43:16 +0000 Subject: drm/nv50: Allow using the NVA3 new compute class. Signed-off-by: Marcin Kościelnicki Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_graph.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index c62b33a02f88..b203d06f601f 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -410,9 +410,10 @@ struct nouveau_pgraph_object_class nv50_graph_grclass[] = { { 0x5039, false, NULL }, /* m2mf */ { 0x502d, false, NULL }, /* 2d */ { 0x50c0, false, NULL }, /* compute */ + { 0x85c0, false, NULL }, /* compute (nva3, nva5, nva8) */ { 0x5097, false, NULL }, /* tesla (nv50) */ - { 0x8297, false, NULL }, /* tesla (nv80/nv90) */ - { 0x8397, false, NULL }, /* tesla (nva0) */ - { 0x8597, false, NULL }, /* tesla (nva8) */ + { 0x8297, false, NULL }, /* tesla (nv8x/nv9x) */ + { 0x8397, false, NULL }, /* tesla (nva0, nvaa, nvac) */ + { 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */ {} }; -- cgit v1.2.3 From 6f335a7afa6bc57603f39430dc6f9e57de288a91 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 29 Mar 2010 10:06:09 +1000 Subject: drm/nv50: preserve an unknown SOR_MODECTRL value for DP encoders This value interacts with some registers we don't currently know how to program properly ourselves. The default of 5 that we were using matches what the VBIOS on early DP cards do, but later ones use 6, which would cause nouveau to program an incorrect mode on these chips. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_encoder.h | 1 + drivers/gpu/drm/nouveau/nv50_sor.c | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index bc4a24029ed1..9f28b94e479b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -47,6 +47,7 @@ struct nouveau_encoder { union { struct { + int mc_unknown; int dpcd_version; int link_nr; int link_bw; diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c index c2fff543b06f..e31ba312c2ff 100644 --- a/drivers/gpu/drm/nouveau/nv50_sor.c +++ b/drivers/gpu/drm/nouveau/nv50_sor.c @@ -211,7 +211,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, mode_ctl = 0x0200; break; case OUTPUT_DP: - mode_ctl |= 0x00050000; + mode_ctl |= (nv_encoder->dp.mc_unknown << 16); if (nv_encoder->dcb->sorconf.link & 1) mode_ctl |= 0x00000800; else @@ -274,6 +274,7 @@ static const struct drm_encoder_funcs nv50_sor_encoder_funcs = { int nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry) { + struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_encoder *nv_encoder = NULL; struct drm_encoder *encoder; bool dum; @@ -319,5 +320,24 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry) encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; + if (nv_encoder->dcb->type == OUTPUT_DP) { + uint32_t mc, or = nv_encoder->or; + + if (dev_priv->chipset < 0x90 || + dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0) + mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(or)); + else + mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(or)); + + switch ((mc & 0x00000f00) >> 8) { + case 8: + case 9: + nv_encoder->dp.mc_unknown = (mc & 0x000f0000) >> 16; + break; + default: + break; + } + } + return 0; } -- cgit v1.2.3 From a5acac66685397a73bed8638114262520565e41c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 30 Mar 2010 15:14:41 +1000 Subject: drm/nv50: punt hotplug irq handling out to workqueue On DP outputs we'll likely end up running vbios init tables here, which may sleep. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nouveau_irq.c | 1 + drivers/gpu/drm/nouveau/nv50_display.c | 14 +++++++++----- drivers/gpu/drm/nouveau/nv50_display.h | 1 + 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index f7d4d2a10052..c4f5658b9e49 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -520,6 +520,7 @@ struct drm_nouveau_private { struct workqueue_struct *wq; struct work_struct irq_work; + struct work_struct hpd_work; struct list_head vbl_waiting; diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 2bd59a92fee5..13e73cee4c44 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -51,6 +51,7 @@ nouveau_irq_preinstall(struct drm_device *dev) if (dev_priv->card_type == NV_50) { INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh); + INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh); INIT_LIST_HEAD(&dev_priv->vbl_waiting); } } diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index fd00f4000f14..649db4c1b690 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -887,10 +887,12 @@ nv50_display_error_handler(struct drm_device *dev) nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR, 0x90000000); } -static void -nv50_display_irq_hotplug(struct drm_device *dev) +void +nv50_display_irq_hotplug_bh(struct work_struct *work) { - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_nouveau_private *dev_priv = + container_of(work, struct drm_nouveau_private, hpd_work); + struct drm_device *dev = dev_priv->dev; struct drm_connector *connector; const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; uint32_t unplug_mask, plug_mask, change_mask; @@ -951,8 +953,10 @@ nv50_display_irq_handler(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t delayed = 0; - while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG) - nv50_display_irq_hotplug(dev); + if (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG) { + if (!work_pending(&dev_priv->hpd_work)) + queue_work(dev_priv->wq, &dev_priv->hpd_work); + } while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) { uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0); diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h index 3ae8d0725f63..581d405ac014 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.h +++ b/drivers/gpu/drm/nouveau/nv50_display.h @@ -37,6 +37,7 @@ void nv50_display_irq_handler(struct drm_device *dev); void nv50_display_irq_handler_bh(struct work_struct *work); +void nv50_display_irq_hotplug_bh(struct work_struct *work); int nv50_display_init(struct drm_device *dev); int nv50_display_create(struct drm_device *dev); int nv50_display_destroy(struct drm_device *dev); -- cgit v1.2.3 From e60a9df3a8e60e5f16707897467b36702e8c4cdc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 30 Mar 2010 16:01:41 +1000 Subject: drm/nv50: another dodgy DP hack Allows *some* DP cards to keep working in some corner cases that most people shouldn't hit. I hit it all the time with development, so this can stay for now. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_sor.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c index e31ba312c2ff..0c68698f23df 100644 --- a/drivers/gpu/drm/nouveau/nv50_sor.c +++ b/drivers/gpu/drm/nouveau/nv50_sor.c @@ -337,6 +337,9 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry) default: break; } + + if (!nv_encoder->dp.mc_unknown) + nv_encoder->dp.mc_unknown = 5; } return 0; -- cgit v1.2.3 From eaeefba154a19aeab9037b1d29478e5303a992fe Mon Sep 17 00:00:00 2001 From: Marcin Kościelnicki Date: Fri, 2 Apr 2010 10:28:18 +0000 Subject: drm/nv50: Add NVA3 support in ctxprog/ctxvals generator. Signed-off-by: Marcin Kościelnicki Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_grctx.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c index 3c3cc4606a03..42a8fb20c1e6 100644 --- a/drivers/gpu/drm/nouveau/nv50_grctx.c +++ b/drivers/gpu/drm/nouveau/nv50_grctx.c @@ -177,6 +177,7 @@ nv50_grctx_init(struct nouveau_grctx *ctx) case 0x96: case 0x98: case 0xa0: + case 0xa3: case 0xa5: case 0xa8: case 0xaa: @@ -364,6 +365,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) case 0xac: gr_def(ctx, 0x401c00, 0x042500df); break; + case 0xa3: case 0xa5: case 0xa8: gr_def(ctx, 0x401c00, 0x142500df); @@ -418,6 +420,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) break; case 0x84: case 0xa0: + case 0xa3: case 0xa5: case 0xa8: case 0xaa: @@ -792,6 +795,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) case 0xa5: gr_def(ctx, offset + 0x1c, 0x310c0000); break; + case 0xa3: case 0xa8: case 0xaa: case 0xac: @@ -859,6 +863,8 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) else gr_def(ctx, offset + 0x8, 0x05010202); gr_def(ctx, offset + 0xc, 0x00030201); + if (dev_priv->chipset == 0xa3) + cp_ctx(ctx, base + 0x36c, 1); cp_ctx(ctx, base + 0x400, 2); gr_def(ctx, base + 0x404, 0x00000040); @@ -1159,7 +1165,9 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx) nv50_graph_construct_gene_unk8(ctx); if (dev_priv->chipset == 0xa0) xf_emit(ctx, 0x189, 0); - else if (dev_priv->chipset < 0xa8) + else if (dev_priv->chipset == 0xa3) + xf_emit(ctx, 0xd5, 0); + else if (dev_priv->chipset == 0xa5) xf_emit(ctx, 0x99, 0); else if (dev_priv->chipset == 0xaa) xf_emit(ctx, 0x65, 0); @@ -1197,6 +1205,8 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx) ctx->ctxvals_pos = offset + 4; if (dev_priv->chipset == 0xa0) xf_emit(ctx, 0xa80, 0); + else if (dev_priv->chipset == 0xa3) + xf_emit(ctx, 0xa7c, 0); else xf_emit(ctx, 0xa7a, 0); xf_emit(ctx, 1, 0x3fffff); @@ -1341,6 +1351,7 @@ nv50_graph_construct_gene_unk1(struct nouveau_grctx *ctx) xf_emit(ctx, 0x942, 0); break; case 0xa0: + case 0xa3: xf_emit(ctx, 0x2042, 0); break; case 0xa5: -- cgit v1.2.3 From 2295e17a4a0c339ca8507deb2cab5f339007e5e5 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Tue, 6 Apr 2010 21:11:58 +0200 Subject: drm/nv40: Init some tiling-related PGRAPH state. Fixes garbled 3D on an nv46 card. Reported-by: Francesco Marella Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv40_graph.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index 53e8afe1dcd1..0616c96e4b67 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -335,6 +335,27 @@ nv40_graph_init(struct drm_device *dev) nv_wr32(dev, 0x400b38, 0x2ffff800); nv_wr32(dev, 0x400b3c, 0x00006000); + /* Tiling related stuff. */ + switch (dev_priv->chipset) { + case 0x44: + case 0x4a: + nv_wr32(dev, 0x400bc4, 0x1003d888); + nv_wr32(dev, 0x400bbc, 0xb7a7b500); + break; + case 0x46: + nv_wr32(dev, 0x400bc4, 0x0000e024); + nv_wr32(dev, 0x400bbc, 0xb7a7b520); + break; + case 0x4c: + case 0x4e: + case 0x67: + nv_wr32(dev, 0x400bc4, 0x1003d888); + nv_wr32(dev, 0x400bbc, 0xb7a7b540); + break; + default: + break; + } + /* Turn all the tiling regions off. */ for (i = 0; i < pfb->num_tiles; i++) nv40_graph_set_region_tiling(dev, i, 0, 0, 0); -- cgit v1.2.3 From 2535d71c80b3d79090c9d44ec6d35342e2d258f0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 7 Apr 2010 12:00:14 +1000 Subject: drm/nouveau: store raw gpio table entry in bios gpio structs And use our own version of the GPIO table for the INIT_GPIO opcode. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 48 ++++++++++++++-------------------- drivers/gpu/drm/nouveau/nouveau_bios.h | 1 + 2 files changed, 21 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index ad6c2d4520ae..84b03e0a3865 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -2573,48 +2573,38 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) * each GPIO according to various values listed in each entry */ + struct drm_nouveau_private *dev_priv = bios->dev->dev_private; const uint32_t nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; - const uint8_t *gpio_table = &bios->data[bios->dcb.gpio_table_ptr]; - const uint8_t *gpio_entry; int i; - if (!iexec->execute) - return 1; - - if (bios->dcb.version != 0x40) { - NV_ERROR(bios->dev, "DCB table not version 4.0\n"); - return 0; - } - - if (!bios->dcb.gpio_table_ptr) { - NV_WARN(bios->dev, "Invalid pointer to INIT_8E table\n"); - return 0; + if (dev_priv->card_type != NV_50) { + NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n"); + return -ENODEV; } - gpio_entry = gpio_table + gpio_table[1]; - for (i = 0; i < gpio_table[2]; i++, gpio_entry += gpio_table[3]) { - uint32_t entry = ROM32(gpio_entry[0]), r, s, v; - int line = (entry & 0x0000001f); + if (!iexec->execute) + return 1; - BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, entry); + for (i = 0; i < bios->dcb.gpio.entries; i++) { + struct dcb_gpio_entry *gpio = &bios->dcb.gpio.entry[i]; + uint32_t r, s, v; - if ((entry & 0x0000ff00) == 0x0000ff00) - continue; + BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry); - r = nv50_gpio_reg[line >> 3]; - s = (line & 0x07) << 2; + r = nv50_gpio_reg[gpio->line >> 3]; + s = (gpio->line & 0x07) << 2; v = bios_rd32(bios, r) & ~(0x00000003 << s); - if (entry & 0x01000000) - v |= (((entry & 0x60000000) >> 29) ^ 2) << s; + if (gpio->entry & 0x01000000) + v |= (((gpio->entry & 0x60000000) >> 29) ^ 2) << s; else - v |= (((entry & 0x18000000) >> 27) ^ 2) << s; + v |= (((gpio->entry & 0x18000000) >> 27) ^ 2) << s; bios_wr32(bios, r, v); - r = nv50_gpio_ctl[line >> 4]; - s = (line & 0x0f); + r = nv50_gpio_ctl[gpio->line >> 4]; + s = (gpio->line & 0x0f); v = bios_rd32(bios, r) & ~(0x00010001 << s); - switch ((entry & 0x06000000) >> 25) { + switch ((gpio->entry & 0x06000000) >> 25) { case 1: v |= (0x00000001 << s); break; @@ -5082,6 +5072,7 @@ parse_dcb30_gpio_entry(struct nvbios *bios, uint16_t offset) gpio->tag = tag; gpio->line = line; gpio->invert = flags != 4; + gpio->entry = ent; } static void @@ -5101,6 +5092,7 @@ parse_dcb40_gpio_entry(struct nvbios *bios, uint16_t offset) * point. */ gpio->tag = tag; gpio->line = line; + gpio->entry = ent; } static void diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index fd6274a90148..3706493c014d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h @@ -49,6 +49,7 @@ struct dcb_gpio_entry { enum dcb_gpio_tag tag; int line; bool invert; + uint32_t entry; }; struct dcb_gpio_table { -- cgit v1.2.3 From 02faec09b2814b6ad3fd202e2f28b3c4b712a3f1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 7 Apr 2010 12:05:32 +1000 Subject: drm/nv50: parse/use some more de-magiced parts of gpio table entries Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 23 +++++++++-------------- drivers/gpu/drm/nouveau/nouveau_bios.h | 2 ++ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 84b03e0a3865..70a51fc2323e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -2595,10 +2595,7 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) r = nv50_gpio_reg[gpio->line >> 3]; s = (gpio->line & 0x07) << 2; v = bios_rd32(bios, r) & ~(0x00000003 << s); - if (gpio->entry & 0x01000000) - v |= (((gpio->entry & 0x60000000) >> 29) ^ 2) << s; - else - v |= (((gpio->entry & 0x18000000) >> 27) ^ 2) << s; + v |= (gpio->state[gpio->state_default] ^ 2) << s; bios_wr32(bios, r, v); r = nv50_gpio_ctl[gpio->line >> 4]; @@ -5078,21 +5075,19 @@ parse_dcb30_gpio_entry(struct nvbios *bios, uint16_t offset) static void parse_dcb40_gpio_entry(struct nvbios *bios, uint16_t offset) { + uint32_t entry = ROM32(bios->data[offset]); struct dcb_gpio_entry *gpio; - uint32_t ent = ROM32(bios->data[offset]); - uint8_t line = ent & 0x1f, - tag = ent >> 8 & 0xff; - if (tag == 0xff) + if ((entry & 0x0000ff00) == 0x0000ff00) return; gpio = new_gpio_entry(bios); - - /* Currently unused, we may need more fields parsed at some - * point. */ - gpio->tag = tag; - gpio->line = line; - gpio->entry = ent; + gpio->tag = (entry & 0x0000ff00) >> 8; + gpio->line = (entry & 0x0000001f) >> 0; + gpio->state_default = (entry & 0x01000000) >> 24; + gpio->state[0] = (entry & 0x18000000) >> 27; + gpio->state[1] = (entry & 0x60000000) >> 29; + gpio->entry = entry; } static void diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index 3706493c014d..c0d7b0a3ece0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h @@ -50,6 +50,8 @@ struct dcb_gpio_entry { int line; bool invert; uint32_t entry; + uint8_t state_default; + uint8_t state[2]; }; struct dcb_gpio_table { -- cgit v1.2.3 From 4528416291e26456e68f7217576e40e589d276bf Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 7 Apr 2010 12:57:35 +1000 Subject: drm/nv50: implement gpio set/get routines Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/Makefile | 2 +- drivers/gpu/drm/nouveau/nouveau_bios.c | 11 +++-- drivers/gpu/drm/nouveau/nouveau_drv.h | 4 ++ drivers/gpu/drm/nouveau/nv50_gpio.c | 76 ++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nv50_gpio.c diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 7f0d807a0d0d..453df3f6053f 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -22,7 +22,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nv50_cursor.o nv50_display.o nv50_fbcon.o \ nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \ nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \ - nv17_gpio.o + nv17_gpio.o nv50_gpio.o nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 70a51fc2323e..abc382a9918b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -2574,7 +2574,6 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) */ struct drm_nouveau_private *dev_priv = bios->dev->dev_private; - const uint32_t nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; int i; @@ -2592,12 +2591,12 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry); - r = nv50_gpio_reg[gpio->line >> 3]; - s = (gpio->line & 0x07) << 2; - v = bios_rd32(bios, r) & ~(0x00000003 << s); - v |= (gpio->state[gpio->state_default] ^ 2) << s; - bios_wr32(bios, r, v); + nv50_gpio_set(bios->dev, gpio->tag, gpio->state_default); + /* The NVIDIA binary driver doesn't appear to actually do + * any of this, my VBIOS does however. + */ + /* Not a clue, needs de-magicing */ r = nv50_gpio_ctl[gpio->line >> 4]; s = (gpio->line & 0x0f); v = bios_rd32(bios, r) & ~(0x00010001 << s); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index c4f5658b9e49..ace630aa89e1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1162,6 +1162,10 @@ extern int nouveau_gem_ioctl_info(struct drm_device *, void *, int nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); int nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); +/* nv50_gpio.c */ +int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); +int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); + #ifndef ioread32_native #ifdef __BIG_ENDIAN #define ioread16_native ioread16be diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c new file mode 100644 index 000000000000..c61782b314e7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nv50_gpio.c @@ -0,0 +1,76 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" +#include "nouveau_drv.h" +#include "nouveau_hw.h" + +static int +nv50_gpio_location(struct dcb_gpio_entry *gpio, uint32_t *reg, uint32_t *shift) +{ + const uint32_t nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; + + if (gpio->line > 32) + return -EINVAL; + + *reg = nv50_gpio_reg[gpio->line >> 3]; + *shift = (gpio->line & 7) << 2; + return 0; +} + +int +nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag) +{ + struct dcb_gpio_entry *gpio; + uint32_t r, s, v; + + gpio = nouveau_bios_gpio_entry(dev, tag); + if (!gpio) + return -ENOENT; + + if (nv50_gpio_location(gpio, &r, &s)) + return -EINVAL; + + v = nv_rd32(dev, r) >> (s + 2); + return ((v & 1) == (gpio->state[1] & 1)); +} + +int +nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) +{ + struct dcb_gpio_entry *gpio; + uint32_t r, s, v; + + gpio = nouveau_bios_gpio_entry(dev, tag); + if (!gpio) + return -ENOENT; + + if (nv50_gpio_location(gpio, &r, &s)) + return -EINVAL; + + v = nv_rd32(dev, r) & ~(0x3 << s); + v |= (gpio->state[state] ^ 2) << s; + nv_wr32(dev, r, v); + return 0; +} -- cgit v1.2.3 From 8e024f13142fbbca5fbe14a6926516a45bd70c3a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 16 Mar 2010 08:45:07 +1000 Subject: drm/nouveau: bail out of auxch transaction if we repeatedly recieve defers There's one known case where we never stop recieving DEFER, and loop here forever. Lets not do that.. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_dp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index f954ad93e81f..deeb21c6865c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -483,7 +483,7 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, ctrl |= (cmd << NV50_AUXCH_CTRL_CMD_SHIFT); ctrl |= ((data_nr - 1) << NV50_AUXCH_CTRL_LEN_SHIFT); - for (;;) { + for (i = 0; i < 16; i++) { nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x80000000); nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl); nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x00010000); @@ -502,6 +502,12 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, break; } + if (i == 16) { + NV_ERROR(dev, "auxch DEFER too many times, bailing\n"); + ret = -EREMOTEIO; + goto out; + } + if (cmd & 1) { if ((stat & NV50_AUXCH_STAT_COUNT) != data_nr) { ret = -EREMOTEIO; -- cgit v1.2.3