From da3bd8203082794d26de3a0a6a7d1ee639d07eb1 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 5 Oct 2010 15:07:33 +0200 Subject: drm/nouveau: ratelimit IRQ messages There are two messages in the ISR of nouveau which might be printed out hundred times in a second. Ratelimit them. (We need to move nouveau_ratelimit to the top of the file.) Signed-off-by: Jiri Slaby Reviewed-by: Marcin Slusarz Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_irq.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 6fd51a51c608..b9e1ffed8557 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -42,6 +42,13 @@ #include "nouveau_connector.h" #include "nv50_display.h" +static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20); + +static int nouveau_ratelimit(void) +{ + return __ratelimit(&nouveau_ratelimit_state); +} + void nouveau_irq_preinstall(struct drm_device *dev) { @@ -213,11 +220,12 @@ nouveau_fifo_irq_handler(struct drm_device *dev) u32 ib_get = nv_rd32(dev, 0x003334); u32 ib_put = nv_rd32(dev, 0x003330); - NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " + if (nouveau_ratelimit()) + NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " "State 0x%08x Push 0x%08x\n", - chid, ho_get, get, ho_put, put, ib_get, ib_put, - state, push); + chid, ho_get, get, ho_put, put, + ib_get, ib_put, state, push); /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ nv_wr32(dev, 0x003364, 0x00000000); @@ -266,8 +274,9 @@ nouveau_fifo_irq_handler(struct drm_device *dev) } if (status) { - NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", - status, chid); + if (nouveau_ratelimit()) + NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", + status, chid); nv_wr32(dev, NV03_PFIFO_INTR_0, status); status = 0; } @@ -544,13 +553,6 @@ nouveau_pgraph_intr_notify(struct drm_device *dev, uint32_t nsource) nouveau_graph_dump_trap_info(dev, "PGRAPH_NOTIFY", &trap); } -static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20); - -static int nouveau_ratelimit(void) -{ - return __ratelimit(&nouveau_ratelimit_state); -} - static inline void nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource) -- cgit v1.2.3 From 907af60b93045ae33b450553167aa8f684252de3 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 9 Oct 2010 04:02:09 +0200 Subject: drm/nouveau: Fix sleep while atomic in the semaphore code. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fence.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 441b12420bb1..ab1bbfbf266e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -249,6 +249,7 @@ alloc_semaphore(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_semaphore *sema; + int ret; if (!USE_SEMA(dev)) return NULL; @@ -257,10 +258,14 @@ alloc_semaphore(struct drm_device *dev) if (!sema) goto fail; + ret = drm_mm_pre_get(&dev_priv->fence.heap); + if (ret) + goto fail; + spin_lock(&dev_priv->fence.lock); sema->mem = drm_mm_search_free(&dev_priv->fence.heap, 4, 0, 0); if (sema->mem) - sema->mem = drm_mm_get_block(sema->mem, 4, 0); + sema->mem = drm_mm_get_block_atomic(sema->mem, 4, 0); spin_unlock(&dev_priv->fence.lock); if (!sema->mem) -- cgit v1.2.3 From 1f5bd44354c878cf8bb0e28a7cb27677e3640c45 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 2 Oct 2010 16:00:35 +0200 Subject: drm/nouveau: Reject modes exceeding the integrated TMDS maximum bandwidth. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: Grzesiek Sójka Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 0871495096fa..6208eedc0970 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -641,11 +641,28 @@ nouveau_connector_get_modes(struct drm_connector *connector) return ret; } +static unsigned +get_tmds_link_bandwidth(struct drm_connector *connector) +{ + struct nouveau_connector *nv_connector = nouveau_connector(connector); + struct drm_nouveau_private *dev_priv = connector->dev->dev_private; + struct dcb_entry *dcb = nv_connector->detected_encoder->dcb; + + if (dcb->location != DCB_LOC_ON_CHIP || + dev_priv->chipset >= 0x46) + return 165000; + else if (dev_priv->chipset >= 0x40) + return 155000; + else if (dev_priv->chipset >= 0x18) + return 135000; + else + return 112000; +} + static int nouveau_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct drm_nouveau_private *dev_priv = connector->dev->dev_private; struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; struct drm_encoder *encoder = to_drm_encoder(nv_encoder); @@ -663,11 +680,9 @@ nouveau_connector_mode_valid(struct drm_connector *connector, max_clock = 400000; break; case OUTPUT_TMDS: - if ((dev_priv->card_type >= NV_50 && !nouveau_duallink) || - !nv_encoder->dcb->duallink_possible) - max_clock = 165000; - else - max_clock = 330000; + max_clock = get_tmds_link_bandwidth(connector); + if (nouveau_duallink && nv_encoder->dcb->duallink_possible) + max_clock *= 2; break; case OUTPUT_ANALOG: max_clock = nv_encoder->dcb->crtconf.maxfreq; -- cgit v1.2.3 From 327ceae6643ddafb0c514183f00e7fc8ca6b6e99 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 10 Oct 2010 05:21:59 +0200 Subject: drm/nv04-nv40: Fall back to panel rescaling if we have no usable native mode. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows the user to set a mode larger than the native one, useful if we had trouble finding the actual native mode (e.g. because it goes above the hardware bandwidth limits). Reported-by: Grzesiek Sójka Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_dfp.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index c936403b26e2..ef23550407b5 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -185,14 +185,15 @@ static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder, struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_connector *nv_connector = nouveau_encoder_connector_get(nv_encoder); - /* For internal panels and gpu scaling on DVI we need the native mode */ - if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) { - if (!nv_connector->native_mode) - return false; + if (!nv_connector->native_mode || + nv_connector->scaling_mode == DRM_MODE_SCALE_NONE || + mode->hdisplay > nv_connector->native_mode->hdisplay || + mode->vdisplay > nv_connector->native_mode->vdisplay) { + nv_encoder->mode = *adjusted_mode; + + } else { nv_encoder->mode = *nv_connector->native_mode; adjusted_mode->clock = nv_connector->native_mode->clock; - } else { - nv_encoder->mode = *adjusted_mode; } return true; -- cgit v1.2.3 From 5eb94fbba39e71f04d629f8197343273b56e25eb Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 7 Oct 2010 03:33:15 +0200 Subject: drm/nv11: Fix bad PLL detection false positive. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_hw.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c index bed669a54a2d..b9672a05c411 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hw.c +++ b/drivers/gpu/drm/nouveau/nouveau_hw.c @@ -519,11 +519,11 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head) struct pll_lims pll_lim; struct nouveau_pll_vals pv; - uint32_t pllreg = head ? NV_RAMDAC_VPLL2 : NV_PRAMDAC_VPLL_COEFF; + enum pll_types pll = head ? PLL_VPLL1 : PLL_VPLL0; - if (get_pll_limits(dev, pllreg, &pll_lim)) + if (get_pll_limits(dev, pll, &pll_lim)) return; - nouveau_hw_get_pllvals(dev, pllreg, &pv); + nouveau_hw_get_pllvals(dev, pll, &pv); if (pv.M1 >= pll_lim.vco1.min_m && pv.M1 <= pll_lim.vco1.max_m && pv.N1 >= pll_lim.vco1.min_n && pv.N1 <= pll_lim.vco1.max_n && @@ -536,7 +536,7 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head) pv.M1 = pll_lim.vco1.max_m; pv.N1 = pll_lim.vco1.min_n; pv.log2P = pll_lim.max_usable_log2p; - nouveau_hw_setpll(dev, pllreg, &pv); + nouveau_hw_setpll(dev, pll_lim.reg, &pv); } /* -- cgit v1.2.3 From cbab95db84f2a444d99bec77bac8b9b6ef20d11c Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 11 Oct 2010 03:43:58 +0200 Subject: drm/nouveau: Some random cleanups. Remove some unused/duplicated definitions and make sparse happy again. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 41 +++-------------------------------- drivers/gpu/drm/nouveau/nouveau_irq.c | 19 ++++++++-------- drivers/gpu/drm/nouveau/nouveau_mem.c | 6 ++--- 3 files changed, 16 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 3a07e580d27a..135594c44167 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -485,13 +485,13 @@ enum nv04_fp_display_regs { }; struct nv04_crtc_reg { - unsigned char MiscOutReg; /* */ + unsigned char MiscOutReg; uint8_t CRTC[0xa0]; uint8_t CR58[0x10]; uint8_t Sequencer[5]; uint8_t Graphics[9]; uint8_t Attribute[21]; - unsigned char DAC[768]; /* Internal Colorlookuptable */ + unsigned char DAC[768]; /* PCRTC regs */ uint32_t fb_start; @@ -539,43 +539,9 @@ struct nv04_output_reg { }; struct nv04_mode_state { - uint32_t bpp; - uint32_t width; - uint32_t height; - uint32_t interlace; - uint32_t repaint0; - uint32_t repaint1; - uint32_t screen; - uint32_t scale; - uint32_t dither; - uint32_t extra; - uint32_t fifo; - uint32_t pixel; - uint32_t horiz; - int arbitration0; - int arbitration1; - uint32_t pll; - uint32_t pllB; - uint32_t vpll; - uint32_t vpll2; - uint32_t vpllB; - uint32_t vpll2B; + struct nv04_crtc_reg crtc_reg[2]; uint32_t pllsel; uint32_t sel_clk; - uint32_t general; - uint32_t crtcOwner; - uint32_t head; - uint32_t head2; - uint32_t cursorConfig; - uint32_t cursor0; - uint32_t cursor1; - uint32_t cursor2; - uint32_t timingH; - uint32_t timingV; - uint32_t displayV; - uint32_t crtcSync; - - struct nv04_crtc_reg crtc_reg[2]; }; enum nouveau_card_type { @@ -1239,7 +1205,6 @@ 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); extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val); -extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *); /* nouveau_fence.c */ struct nouveau_fence; diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index b9e1ffed8557..e2f2d59be3ea 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -209,8 +209,8 @@ nouveau_fifo_irq_handler(struct drm_device *dev) } if (status & NV_PFIFO_INTR_DMA_PUSHER) { - u32 get = nv_rd32(dev, 0x003244); - u32 put = nv_rd32(dev, 0x003240); + u32 dma_get = nv_rd32(dev, 0x003244); + u32 dma_put = nv_rd32(dev, 0x003240); u32 push = nv_rd32(dev, 0x003220); u32 state = nv_rd32(dev, 0x003228); @@ -224,13 +224,14 @@ nouveau_fifo_irq_handler(struct drm_device *dev) NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " "State 0x%08x Push 0x%08x\n", - chid, ho_get, get, ho_put, put, - ib_get, ib_put, state, push); + chid, ho_get, dma_get, ho_put, + dma_put, ib_get, ib_put, state, + push); /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ nv_wr32(dev, 0x003364, 0x00000000); - if (get != put || ho_get != ho_put) { - nv_wr32(dev, 0x003244, put); + if (dma_get != dma_put || ho_get != ho_put) { + nv_wr32(dev, 0x003244, dma_put); nv_wr32(dev, 0x003328, ho_put); } else if (ib_get != ib_put) { @@ -239,10 +240,10 @@ nouveau_fifo_irq_handler(struct drm_device *dev) } else { NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x " "Put 0x%08x State 0x%08x Push 0x%08x\n", - chid, get, put, state, push); + chid, dma_get, dma_put, state, push); - if (get != put) - nv_wr32(dev, 0x003244, put); + if (dma_get != dma_put) + nv_wr32(dev, 0x003244, dma_put); } nv_wr32(dev, 0x003228, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index a163c7c612e7..1165c3e68200 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -33,9 +33,9 @@ #include "drmP.h" #include "drm.h" #include "drm_sarea.h" -#include "nouveau_drv.h" -#define MIN(a,b) a < b ? a : b +#include "nouveau_drv.h" +#include "nouveau_pm.h" /* * NV10-NV40 tiling helpers @@ -719,7 +719,7 @@ nouveau_mem_timing_init(struct drm_device *dev) tUNK_19 = 1; tUNK_20 = 0; tUNK_21 = 0; - switch (MIN(recordlen,21)) { + switch (min(recordlen, 21)) { case 21: tUNK_21 = entry[21]; case 20: -- cgit v1.2.3 From 7bb94d26ad62ca1d6b5e11db6e26425785cc46ac Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 11 Oct 2010 03:37:32 +0200 Subject: drm/nouveau: Avoid lock dependency between ramht and ramin spinlocks. The ramht code called some gpuobj functions with the HARDIRQ-safe RAMHT spinlock held, this could potentially lead to a dead lock because ramin_lock is HARDIRQ-unsafe. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_ramht.c | 71 ++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.c b/drivers/gpu/drm/nouveau/nouveau_ramht.c index 7f16697cc96c..2d8580927ca4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ramht.c +++ b/drivers/gpu/drm/nouveau/nouveau_ramht.c @@ -153,26 +153,42 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle, return -ENOMEM; } +static struct nouveau_ramht_entry * +nouveau_ramht_remove_entry(struct nouveau_channel *chan, u32 handle) +{ + struct nouveau_ramht *ramht = chan ? chan->ramht : NULL; + struct nouveau_ramht_entry *entry; + unsigned long flags; + + if (!ramht) + return NULL; + + spin_lock_irqsave(&ramht->lock, flags); + list_for_each_entry(entry, &ramht->entries, head) { + if (entry->channel == chan && + (!handle || entry->handle == handle)) { + list_del(&entry->head); + spin_unlock_irqrestore(&ramht->lock, flags); + + return entry; + } + } + spin_unlock_irqrestore(&ramht->lock, flags); + + return NULL; +} + static void -nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle) +nouveau_ramht_remove_hash(struct nouveau_channel *chan, u32 handle) { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; struct nouveau_gpuobj *ramht = chan->ramht->gpuobj; - struct nouveau_ramht_entry *entry, *tmp; + unsigned long flags; u32 co, ho; - list_for_each_entry_safe(entry, tmp, &chan->ramht->entries, head) { - if (entry->channel != chan || entry->handle != handle) - continue; - - nouveau_gpuobj_ref(NULL, &entry->gpuobj); - list_del(&entry->head); - kfree(entry); - break; - } - + spin_lock_irqsave(&chan->ramht->lock, flags); co = ho = nouveau_ramht_hash_handle(chan, handle); do { if (nouveau_ramht_entry_valid(dev, ramht, co) && @@ -184,7 +200,7 @@ nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle) nv_wo32(ramht, co + 0, 0x00000000); nv_wo32(ramht, co + 4, 0x00000000); instmem->flush(dev); - return; + goto out; } co += 8; @@ -194,17 +210,22 @@ nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle) NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n", chan->id, handle); +out: + spin_unlock_irqrestore(&chan->ramht->lock, flags); } void nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle) { - struct nouveau_ramht *ramht = chan->ramht; - unsigned long flags; + struct nouveau_ramht_entry *entry; - spin_lock_irqsave(&ramht->lock, flags); - nouveau_ramht_remove_locked(chan, handle); - spin_unlock_irqrestore(&ramht->lock, flags); + entry = nouveau_ramht_remove_entry(chan, handle); + if (!entry) + return; + + nouveau_ramht_remove_hash(chan, entry->handle); + nouveau_gpuobj_ref(NULL, &entry->gpuobj); + kfree(entry); } struct nouveau_gpuobj * @@ -265,23 +286,19 @@ void nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr, struct nouveau_channel *chan) { - struct nouveau_ramht_entry *entry, *tmp; + struct nouveau_ramht_entry *entry; struct nouveau_ramht *ramht; - unsigned long flags; if (ref) kref_get(&ref->refcount); ramht = *ptr; if (ramht) { - spin_lock_irqsave(&ramht->lock, flags); - list_for_each_entry_safe(entry, tmp, &ramht->entries, head) { - if (entry->channel != chan) - continue; - - nouveau_ramht_remove_locked(chan, entry->handle); + while ((entry = nouveau_ramht_remove_entry(chan, 0))) { + nouveau_ramht_remove_hash(chan, entry->handle); + nouveau_gpuobj_ref(NULL, &entry->gpuobj); + kfree(entry); } - spin_unlock_irqrestore(&ramht->lock, flags); kref_put(&ramht->refcount, nouveau_ramht_del); } -- cgit v1.2.3 From 1397b42b5a2e5b3b982078c89f3594c123e3c2b3 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Tue, 12 Oct 2010 03:17:43 +0200 Subject: drm/nouveau: Reduce severity of the unknown getparam error. Signed-off-by: Francisco Jerez Acked-by: Ben Skeggs Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_state.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index ed7757f14083..af2bec36d91b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -1051,7 +1051,7 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, } /* FALLTHRU */ default: - NV_ERROR(dev, "unknown parameter %lld\n", getparam->param); + NV_DEBUG(dev, "unknown parameter %lld\n", getparam->param); return -EINVAL; } @@ -1066,7 +1066,7 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data, switch (setparam->param) { default: - NV_ERROR(dev, "unknown parameter %lld\n", setparam->param); + NV_DEBUG(dev, "unknown parameter %lld\n", setparam->param); return -EINVAL; } -- cgit v1.2.3 From f13b32630dda7e583a84a8c535880cff7e4a9bdd Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 10 Oct 2010 06:01:08 +0200 Subject: drm/nouveau: Expose some BO usage flags to userspace. This will be needed for Z compression and to take smarter placement decisions. Signed-off-by: Francisco Jerez Acked-by: Ben Skeggs Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 15 +++++++++----- drivers/gpu/drm/nouveau/nouveau_drv.h | 3 +++ drivers/gpu/drm/nouveau/nouveau_gem.c | 36 +++++++++++++++++++-------------- drivers/gpu/drm/nouveau/nouveau_state.c | 3 +++ drivers/gpu/drm/nouveau/nv50_crtc.c | 4 ++-- 5 files changed, 39 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 80353e2b8409..f55dd9145b7c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -144,7 +144,8 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, nvbo->tile_mode = tile_mode; nvbo->tile_flags = tile_flags; - nouveau_bo_fixup_align(dev, tile_mode, tile_flags, &align, &size); + nouveau_bo_fixup_align(dev, tile_mode, nouveau_bo_tile_layout(nvbo), + &align, &size); align >>= PAGE_SHIFT; nouveau_bo_placement_set(nvbo, flags, 0); @@ -525,7 +526,8 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, stride = 16 * 4; height = amount / stride; - if (new_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) { + if (new_mem->mem_type == TTM_PL_VRAM && + nouveau_bo_tile_layout(nvbo)) { ret = RING_SPACE(chan, 8); if (ret) return ret; @@ -546,7 +548,8 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, BEGIN_RING(chan, NvSubM2MF, 0x0200, 1); OUT_RING (chan, 1); } - if (old_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) { + if (old_mem->mem_type == TTM_PL_VRAM && + nouveau_bo_tile_layout(nvbo)) { ret = RING_SPACE(chan, 8); if (ret) return ret; @@ -753,7 +756,8 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem, if (dev_priv->card_type == NV_50) { ret = nv50_mem_vm_bind_linear(dev, offset + dev_priv->vm_vram_base, - new_mem->size, nvbo->tile_flags, + new_mem->size, + nouveau_bo_tile_layout(nvbo), offset); if (ret) return ret; @@ -894,7 +898,8 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) * nothing to do here. */ if (bo->mem.mem_type != TTM_PL_VRAM) { - if (dev_priv->card_type < NV_50 || !nvbo->tile_flags) + if (dev_priv->card_type < NV_50 || + !nouveau_bo_tile_layout(nvbo)) return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 135594c44167..60a54fae90c1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -100,6 +100,9 @@ struct nouveau_bo { int pin_refcnt; }; +#define nouveau_bo_tile_layout(nvbo) \ + ((nvbo)->tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) + static inline struct nouveau_bo * nouveau_bo(struct ttm_buffer_object *bo) { diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 5c4c929d7f74..9a1fdcf400c2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -107,23 +107,29 @@ nouveau_gem_info(struct drm_gem_object *gem, struct drm_nouveau_gem_info *rep) } static bool -nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags) { - switch (tile_flags) { - case 0x0000: - case 0x1800: - case 0x2800: - case 0x4800: - case 0x7000: - case 0x7400: - case 0x7a00: - case 0xe000: - break; - default: - NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags); - return false; +nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (dev_priv->card_type >= NV_50) { + switch (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) { + case 0x0000: + case 0x1800: + case 0x2800: + case 0x4800: + case 0x7000: + case 0x7400: + case 0x7a00: + case 0xe000: + return true; + } + } else { + if (!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK)) + return true; } - return true; + NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags); + return false; } int diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index af2bec36d91b..ea3452194cd6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -1041,6 +1041,9 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, case NOUVEAU_GETPARAM_PTIMER_TIME: getparam->value = dev_priv->engine.timer.read(dev); break; + case NOUVEAU_GETPARAM_HAS_BO_USAGE: + getparam->value = 1; + break; case NOUVEAU_GETPARAM_GRAPH_UNITS: /* NV40 and NV50 versions are quite different, but register * address is the same. User is supposed to know the card diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index 16380d52cd88..56476d0c6de8 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -546,7 +546,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, } nv_crtc->fb.offset = fb->nvbo->bo.offset - dev_priv->vm_vram_base; - nv_crtc->fb.tile_flags = fb->nvbo->tile_flags; + nv_crtc->fb.tile_flags = nouveau_bo_tile_layout(fb->nvbo); nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8; if (!nv_crtc->fb.blanked && dev_priv->chipset != 0x50) { ret = RING_SPACE(evo, 2); @@ -578,7 +578,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, fb->nvbo->tile_mode); } if (dev_priv->chipset == 0x50) - OUT_RING(evo, (fb->nvbo->tile_flags << 8) | format); + OUT_RING(evo, (nv_crtc->fb.tile_flags << 8) | format); else OUT_RING(evo, format); -- cgit v1.2.3 From 699ddfd98061b725c52fd34ff1c4346e5b4824d4 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 10 Oct 2010 06:07:32 +0200 Subject: drm/nv10: Balance RTs expected to be accessed simultaneously by the 3d engine. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index f55dd9145b7c..c41e1c200ef5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -143,6 +143,7 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, nvbo->no_vm = no_vm; nvbo->tile_mode = tile_mode; nvbo->tile_flags = tile_flags; + nvbo->bo.bdev = &dev_priv->ttm.bdev; nouveau_bo_fixup_align(dev, tile_mode, nouveau_bo_tile_layout(nvbo), &align, &size); @@ -177,6 +178,31 @@ set_placement_list(uint32_t *pl, unsigned *n, uint32_t type, uint32_t flags) pl[(*n)++] = TTM_PL_FLAG_SYSTEM | flags; } +static void +set_placement_range(struct nouveau_bo *nvbo, uint32_t type) +{ + struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev); + + if (dev_priv->card_type == NV_10 && + nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM)) { + /* + * Make sure that the color and depth buffers are handled + * by independent memory controller units. Up to a 9x + * speed up when alpha-blending and depth-test are enabled + * at the same time. + */ + int vram_pages = dev_priv->vram_size >> PAGE_SHIFT; + + if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) { + nvbo->placement.fpfn = vram_pages / 2; + nvbo->placement.lpfn = ~0; + } else { + nvbo->placement.fpfn = 0; + nvbo->placement.lpfn = vram_pages / 2; + } + } +} + void nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy) { @@ -191,6 +217,8 @@ nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy) pl->busy_placement = nvbo->busy_placements; set_placement_list(nvbo->busy_placements, &pl->num_busy_placement, type | busy, flags); + + set_placement_range(nvbo, type); } int -- cgit v1.2.3 From 2a56a0b913a8d7314c2c10fdd57d667b599232b4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 1 Oct 2010 14:39:37 +1000 Subject: drm/nva3: fix overflow in fixed point math used for pll calculation And a slight tweak which gets us closer to VBIOS-calculated numbers. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_calc.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv50_calc.c b/drivers/gpu/drm/nouveau/nv50_calc.c index 2cdc2bfe7179..de81151648f8 100644 --- a/drivers/gpu/drm/nouveau/nv50_calc.c +++ b/drivers/gpu/drm/nouveau/nv50_calc.c @@ -51,24 +51,28 @@ nv50_calc_pll2(struct drm_device *dev, struct pll_lims *pll, int clk, int *N, int *fN, int *M, int *P) { fixed20_12 fb_div, a, b; + u32 refclk = pll->refclk / 10; + u32 max_vco_freq = pll->vco1.maxfreq / 10; + u32 max_vco_inputfreq = pll->vco1.max_inputfreq / 10; + clk /= 10; - *P = pll->vco1.maxfreq / clk; + *P = max_vco_freq / clk; if (*P > pll->max_p) *P = pll->max_p; if (*P < pll->min_p) *P = pll->min_p; - /* *M = ceil(refclk / pll->vco.max_inputfreq); */ - a.full = dfixed_const(pll->refclk); - b.full = dfixed_const(pll->vco1.max_inputfreq); + /* *M = floor((refclk + max_vco_inputfreq) / max_vco_inputfreq); */ + a.full = dfixed_const(refclk + max_vco_inputfreq); + b.full = dfixed_const(max_vco_inputfreq); a.full = dfixed_div(a, b); - a.full = dfixed_ceil(a); + a.full = dfixed_floor(a); *M = dfixed_trunc(a); /* fb_div = (vco * *M) / refclk; */ fb_div.full = dfixed_const(clk * *P); fb_div.full = dfixed_mul(fb_div, a); - a.full = dfixed_const(pll->refclk); + a.full = dfixed_const(refclk); fb_div.full = dfixed_div(fb_div, a); /* *N = floor(fb_div); */ -- cgit v1.2.3 From 3c29f9e74591d2f365b159cf59193b19a2f65640 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 15 Oct 2010 22:22:59 +0200 Subject: drm/nouveau: fix nv40 pcie gart size Nouveau sets the PCIE GART size to 64MiB for all cards before nv50, but nv40 has enough RAMIN space to support 512MiB GART size. This patch fixes this value to make use of this hardware capability. Signed-off-by: Lucas Stach Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 288bacac7e5a..15f358404645 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -224,7 +224,11 @@ nouveau_sgdma_init(struct drm_device *dev) int i, ret; if (dev_priv->card_type < NV_50) { - aper_size = (64 * 1024 * 1024); + if(dev_priv->card_type < NV_40) { + aper_size = (64 * 1024 * 1024); + } else { + aper_size = (512 * 1024 * 1024); + } obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4; obj_size += 8; /* ctxdma header */ } else { -- cgit v1.2.3 From 5794b5fdb579abf7be2c27c6e0d6106f391a26e4 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Fri, 22 Oct 2010 04:39:14 +0200 Subject: drm/nv04: Fix scanout over the 16MB mark. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_hw.h | 19 +++++++++++++++++++ drivers/gpu/drm/nouveau/nv04_crtc.c | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.h b/drivers/gpu/drm/nouveau/nouveau_hw.h index 869130f83602..2989090b9434 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hw.h +++ b/drivers/gpu/drm/nouveau/nouveau_hw.h @@ -415,6 +415,25 @@ nv_fix_nv40_hw_cursor(struct drm_device *dev, int head) NVWriteRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS, curpos); } +static inline void +nv_set_crtc_base(struct drm_device *dev, int head, uint32_t offset) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + NVWriteCRTC(dev, head, NV_PCRTC_START, offset); + + if (dev_priv->card_type == NV_04) { + /* + * Hilarious, the 24th bit doesn't want to stick to + * PCRTC_START... + */ + int cre_heb = NVReadVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX); + + NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX, + (cre_heb & ~0x40) | ((offset >> 18) & 0x40)); + } +} + static inline void nv_show_cursor(struct drm_device *dev, int head, bool show) { diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index c71abc2a34d5..5b49cec528ee 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -831,7 +831,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, /* Update the framebuffer location. */ regp->fb_start = nv_crtc->fb.offset & ~3; regp->fb_start += (y * drm_fb->pitch) + (x * drm_fb->bits_per_pixel / 8); - NVWriteCRTC(dev, nv_crtc->index, NV_PCRTC_START, regp->fb_start); + nv_set_crtc_base(dev, nv_crtc->index, regp->fb_start); /* Update the arbitration parameters. */ nouveau_calc_arb(dev, crtc->mode.clock, drm_fb->bits_per_pixel, -- cgit v1.2.3 From 01db363979e96115a895f35c823303660f0f328d Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 21 Oct 2010 17:43:08 +0200 Subject: drm/nouveau: Use "force" to decide if analog load detection is ok or not. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 69 ++++++++++++----------------- drivers/gpu/drm/nouveau/nouveau_connector.h | 3 -- drivers/gpu/drm/nouveau/nv04_crtc.c | 5 --- 3 files changed, 28 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 6208eedc0970..9ec2b8a81344 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -213,6 +213,24 @@ nouveau_connector_set_encoder(struct drm_connector *connector, } } +static bool +nouveau_connector_poll_allowed(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + bool spare_crtc = false; + + if (dev_priv->card_type >= NV_50) { + return true; + } else { + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + spare_crtc |= !crtc->enabled; + + return spare_crtc; + } +} + static enum drm_connector_status nouveau_connector_detect(struct drm_connector *connector, bool force) { @@ -281,7 +299,8 @@ detect_analog: nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG); if (!nv_encoder && !nouveau_tv_disable) nv_encoder = find_encoder_by_type(connector, OUTPUT_TV); - if (nv_encoder) { + if (nv_encoder && + (force || nouveau_connector_poll_allowed(connector))) { struct drm_encoder *encoder = to_drm_encoder(nv_encoder); struct drm_encoder_helper_funcs *helper = encoder->helper_private; @@ -724,44 +743,6 @@ nouveau_connector_best_encoder(struct drm_connector *connector) return NULL; } -void -nouveau_connector_set_polling(struct drm_connector *connector) -{ - struct drm_device *dev = connector->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; - bool spare_crtc = false; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) - spare_crtc |= !crtc->enabled; - - connector->polled = 0; - - switch (connector->connector_type) { - case DRM_MODE_CONNECTOR_VGA: - case DRM_MODE_CONNECTOR_TV: - if (dev_priv->card_type >= NV_50 || - (nv_gf4_disp_arch(dev) && spare_crtc)) - connector->polled = DRM_CONNECTOR_POLL_CONNECT; - break; - - case DRM_MODE_CONNECTOR_DVII: - case DRM_MODE_CONNECTOR_DVID: - case DRM_MODE_CONNECTOR_HDMIA: - case DRM_MODE_CONNECTOR_DisplayPort: - case DRM_MODE_CONNECTOR_eDP: - if (dev_priv->card_type >= NV_50) - connector->polled = DRM_CONNECTOR_POLL_HPD; - else if (connector->connector_type == DRM_MODE_CONNECTOR_DVID || - spare_crtc) - connector->polled = DRM_CONNECTOR_POLL_CONNECT; - break; - - default: - break; - } -} - static const struct drm_connector_helper_funcs nouveau_connector_helper_funcs = { .get_modes = nouveau_connector_get_modes, @@ -892,6 +873,9 @@ nouveau_connector_create(struct drm_device *dev, int index) case DCB_CONNECTOR_TV_1: case DCB_CONNECTOR_TV_3: nv_connector->scaling_mode = DRM_MODE_SCALE_NONE; + + if (nv_gf4_disp_arch(dev)) + connector->polled = DRM_CONNECTOR_POLL_CONNECT; break; default: nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN; @@ -903,11 +887,14 @@ nouveau_connector_create(struct drm_device *dev, int index) dev->mode_config.dithering_mode_property, nv_connector->use_dithering ? DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF); + + if (dev_priv->card_type >= NV_50) + connector->polled = DRM_CONNECTOR_POLL_HPD; + else + connector->polled = DRM_CONNECTOR_POLL_CONNECT; break; } - nouveau_connector_set_polling(connector); - drm_sysfs_connector_add(connector); dcb->drm = connector; return dcb->drm; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index c21ed6b16f88..711b1e9203af 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -52,9 +52,6 @@ static inline struct nouveau_connector *nouveau_connector( struct drm_connector * nouveau_connector_create(struct drm_device *, int index); -void -nouveau_connector_set_polling(struct drm_connector *); - int nouveau_connector_bpp(struct drm_connector *); diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index 5b49cec528ee..40e180741629 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -158,7 +158,6 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct drm_device *dev = crtc->dev; - struct drm_connector *connector; unsigned char seq1 = 0, crtc17 = 0; unsigned char crtc1A; @@ -213,10 +212,6 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode) NVVgaSeqReset(dev, nv_crtc->index, false); NVWriteVgaCrtc(dev, nv_crtc->index, NV_CIO_CRE_RPC1_INDEX, crtc1A); - - /* Update connector polling modes */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) - nouveau_connector_set_polling(connector); } static bool -- cgit v1.2.3 From 06ef3e61dd44f76fef89d8e7ad5d6c845f3f345e Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 23 Oct 2010 23:12:37 +0200 Subject: drm/nouveau: Don't poll LVDS outputs. Reported-by: Xavier Chantry Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 9ec2b8a81344..1dd52dbfad46 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -888,10 +888,12 @@ nouveau_connector_create(struct drm_device *dev, int index) nv_connector->use_dithering ? DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF); - if (dev_priv->card_type >= NV_50) - connector->polled = DRM_CONNECTOR_POLL_HPD; - else - connector->polled = DRM_CONNECTOR_POLL_CONNECT; + if (dcb->type != DCB_CONNECTOR_LVDS) { + if (dev_priv->card_type >= NV_50) + connector->polled = DRM_CONNECTOR_POLL_HPD; + else + connector->polled = DRM_CONNECTOR_POLL_CONNECT; + } break; } -- cgit v1.2.3 From 56ac7475350ee646f5f7316abcdf65d3be94da1c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 22 Oct 2010 10:26:24 +1000 Subject: drm/nv50: implement possible workaround for NV86 PGRAPH TLB flush hang Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 5 ++++ drivers/gpu/drm/nouveau/nouveau_mem.c | 14 ++++----- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 8 ++--- drivers/gpu/drm/nouveau/nouveau_state.c | 10 +++++++ drivers/gpu/drm/nouveau/nv50_fifo.c | 5 ++++ drivers/gpu/drm/nouveau/nv50_graph.c | 52 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nv50_instmem.c | 1 - 7 files changed, 82 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 60a54fae90c1..10a8d4e78e58 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -307,6 +307,7 @@ struct nouveau_fifo_engine { void (*destroy_context)(struct nouveau_channel *); int (*load_context)(struct nouveau_channel *); int (*unload_context)(struct drm_device *); + void (*tlb_flush)(struct drm_device *dev); }; struct nouveau_pgraph_object_method { @@ -339,6 +340,7 @@ struct nouveau_pgraph_engine { void (*destroy_context)(struct nouveau_channel *); int (*load_context)(struct nouveau_channel *); int (*unload_context)(struct drm_device *); + void (*tlb_flush)(struct drm_device *dev); void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr, uint32_t size, uint32_t pitch); @@ -1014,6 +1016,7 @@ extern int nv50_fifo_create_context(struct nouveau_channel *); extern void nv50_fifo_destroy_context(struct nouveau_channel *); extern int nv50_fifo_load_context(struct nouveau_channel *); extern int nv50_fifo_unload_context(struct drm_device *); +extern void nv50_fifo_tlb_flush(struct drm_device *dev); /* nvc0_fifo.c */ extern int nvc0_fifo_init(struct drm_device *); @@ -1091,6 +1094,8 @@ extern int nv50_graph_load_context(struct nouveau_channel *); extern int nv50_graph_unload_context(struct drm_device *); extern void nv50_graph_context_switch(struct drm_device *); extern int nv50_grctx_init(struct nouveau_grctx *); +extern void nv50_graph_tlb_flush(struct drm_device *dev); +extern void nv86_graph_tlb_flush(struct drm_device *dev); /* nvc0_graph.c */ extern int nvc0_graph_init(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 1165c3e68200..ac3bec024fd5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -175,11 +175,10 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, } } } - dev_priv->engine.instmem.flush(dev); - nv50_vm_flush(dev, 5); - nv50_vm_flush(dev, 0); - nv50_vm_flush(dev, 4); + dev_priv->engine.instmem.flush(dev); + dev_priv->engine.fifo.tlb_flush(dev); + dev_priv->engine.graph.tlb_flush(dev); nv50_vm_flush(dev, 6); return 0; } @@ -209,11 +208,10 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) pte++; } } - dev_priv->engine.instmem.flush(dev); - nv50_vm_flush(dev, 5); - nv50_vm_flush(dev, 0); - nv50_vm_flush(dev, 4); + dev_priv->engine.instmem.flush(dev); + dev_priv->engine.fifo.tlb_flush(dev); + dev_priv->engine.graph.tlb_flush(dev); nv50_vm_flush(dev, 6); } diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 15f358404645..0b309c1cc3d7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -120,8 +120,8 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) dev_priv->engine.instmem.flush(nvbe->dev); if (dev_priv->card_type == NV_50) { - nv50_vm_flush(dev, 5); /* PGRAPH */ - nv50_vm_flush(dev, 0); /* PFIFO */ + dev_priv->engine.fifo.tlb_flush(dev); + dev_priv->engine.graph.tlb_flush(dev); } nvbe->bound = true; @@ -162,8 +162,8 @@ nouveau_sgdma_unbind(struct ttm_backend *be) dev_priv->engine.instmem.flush(nvbe->dev); if (dev_priv->card_type == NV_50) { - nv50_vm_flush(dev, 5); - nv50_vm_flush(dev, 0); + dev_priv->engine.fifo.tlb_flush(dev); + dev_priv->engine.graph.tlb_flush(dev); } nvbe->bound = false; diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index ea3452194cd6..049f755567e5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -354,6 +354,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.destroy_context = nv50_graph_destroy_context; engine->graph.load_context = nv50_graph_load_context; engine->graph.unload_context = nv50_graph_unload_context; + if (dev_priv->chipset != 0x86) + engine->graph.tlb_flush = nv50_graph_tlb_flush; + else { + /* from what i can see nvidia do this on every + * pre-NVA3 board except NVAC, but, we've only + * ever seen problems on NV86 + */ + engine->graph.tlb_flush = nv86_graph_tlb_flush; + } engine->fifo.channels = 128; engine->fifo.init = nv50_fifo_init; engine->fifo.takedown = nv50_fifo_takedown; @@ -365,6 +374,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.destroy_context = nv50_fifo_destroy_context; engine->fifo.load_context = nv50_fifo_load_context; engine->fifo.unload_context = nv50_fifo_unload_context; + engine->fifo.tlb_flush = nv50_fifo_tlb_flush; engine->display.early_init = nv50_display_early_init; engine->display.late_takedown = nv50_display_late_takedown; engine->display.create = nv50_display_create; diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index a46a961102f3..1da65bd60c10 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c @@ -464,3 +464,8 @@ nv50_fifo_unload_context(struct drm_device *dev) return 0; } +void +nv50_fifo_tlb_flush(struct drm_device *dev) +{ + nv50_vm_flush(dev, 5); +} diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index cbf5ae2f67d4..8b669d0af610 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -402,3 +402,55 @@ struct nouveau_pgraph_object_class nv50_graph_grclass[] = { { 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */ {} }; + +void +nv50_graph_tlb_flush(struct drm_device *dev) +{ + nv50_vm_flush(dev, 0); +} + +void +nv86_graph_tlb_flush(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; + bool idle, timeout = false; + unsigned long flags; + u64 start; + u32 tmp; + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + nv_mask(dev, 0x400500, 0x00000001, 0x00000000); + + start = ptimer->read(dev); + do { + idle = true; + + for (tmp = nv_rd32(dev, 0x400380); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + + for (tmp = nv_rd32(dev, 0x400384); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + + for (tmp = nv_rd32(dev, 0x400388); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + } while (!idle && !(timeout = ptimer->read(dev) - start > 2000000000)); + + if (timeout) { + NV_ERROR(dev, "PGRAPH TLB flush idle timeout fail: " + "0x%08x 0x%08x 0x%08x 0x%08x\n", + nv_rd32(dev, 0x400700), nv_rd32(dev, 0x400380), + nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388)); + } + + nv50_vm_flush(dev, 0); + + nv_mask(dev, 0x400500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +} diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index a53fc974332b..b773229b7647 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -402,7 +402,6 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) } dev_priv->engine.instmem.flush(dev); - nv50_vm_flush(dev, 4); nv50_vm_flush(dev, 6); gpuobj->im_bound = 1; -- cgit v1.2.3 From 63d6fd32889c46fa40cd1631fb2a0162187311ab Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 25 Oct 2010 02:13:21 +0200 Subject: drm/nv10-nv20: Fix instability after MPLL changes. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_pm.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c index 6a6eb697d38e..eb1c70dd82ed 100644 --- a/drivers/gpu/drm/nouveau/nv04_pm.c +++ b/drivers/gpu/drm/nouveau/nv04_pm.c @@ -76,6 +76,15 @@ nv04_pm_clock_set(struct drm_device *dev, void *pre_state) reg += 4; nouveau_hw_setpll(dev, reg, &state->calc); + + if (dev_priv->card_type < NV_30 && reg == NV_PRAMDAC_MPLL_COEFF) { + if (dev_priv->card_type == NV_20) + nv_mask(dev, 0x1002c4, 0, 1 << 20); + + /* Reset the DLLs */ + nv_mask(dev, 0x1002c0, 0, 1 << 8); + } + kfree(state); } -- cgit v1.2.3 From 84b8081c2baf84b52ac9bf79f07edcea975ab0b5 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Tue, 26 Oct 2010 02:17:56 +0200 Subject: drm/nouveau: Don't use load detection for connector polling. Analog output polling makes GL programs jerky when pageflip is being used because it's carried out with the mode_config mutex held. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 1dd52dbfad46..52c356e9a3d1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -213,24 +213,6 @@ nouveau_connector_set_encoder(struct drm_connector *connector, } } -static bool -nouveau_connector_poll_allowed(struct drm_connector *connector) -{ - struct drm_device *dev = connector->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; - bool spare_crtc = false; - - if (dev_priv->card_type >= NV_50) { - return true; - } else { - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) - spare_crtc |= !crtc->enabled; - - return spare_crtc; - } -} - static enum drm_connector_status nouveau_connector_detect(struct drm_connector *connector, bool force) { @@ -299,8 +281,7 @@ detect_analog: nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG); if (!nv_encoder && !nouveau_tv_disable) nv_encoder = find_encoder_by_type(connector, OUTPUT_TV); - if (nv_encoder && - (force || nouveau_connector_poll_allowed(connector))) { + if (nv_encoder && force) { struct drm_encoder *encoder = to_drm_encoder(nv_encoder); struct drm_encoder_helper_funcs *helper = encoder->helper_private; @@ -868,14 +849,12 @@ nouveau_connector_create(struct drm_device *dev, int index) dev->mode_config.scaling_mode_property, nv_connector->scaling_mode); } + connector->polled = DRM_CONNECTOR_POLL_CONNECT; /* fall-through */ case DCB_CONNECTOR_TV_0: case DCB_CONNECTOR_TV_1: case DCB_CONNECTOR_TV_3: nv_connector->scaling_mode = DRM_MODE_SCALE_NONE; - - if (nv_gf4_disp_arch(dev)) - connector->polled = DRM_CONNECTOR_POLL_CONNECT; break; default: nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN; -- cgit v1.2.3 From b54262f3c828ee17e27632d0d60255281c02e1a5 Mon Sep 17 00:00:00 2001 From: Martin Peres Date: Tue, 26 Oct 2010 12:48:28 +0200 Subject: drm/nouveau: Fix compilation issues in nouveau_pm when CONFIG_HWMON is not set Signed-off-by: Martin Peres Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_pm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index 1c99c55d6d46..9f7b158f5825 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -284,6 +284,7 @@ nouveau_sysfs_fini(struct drm_device *dev) } } +#ifdef CONFIG_HWMON static ssize_t nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) { @@ -395,10 +396,12 @@ static struct attribute *hwmon_attributes[] = { static const struct attribute_group hwmon_attrgroup = { .attrs = hwmon_attributes, }; +#endif static int nouveau_hwmon_init(struct drm_device *dev) { +#ifdef CONFIG_HWMON struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_engine *pm = &dev_priv->engine.pm; struct device *hwmon_dev; @@ -425,13 +428,14 @@ nouveau_hwmon_init(struct drm_device *dev) } pm->hwmon = hwmon_dev; - +#endif return 0; } static void nouveau_hwmon_fini(struct drm_device *dev) { +#ifdef CONFIG_HWMON struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_engine *pm = &dev_priv->engine.pm; @@ -439,6 +443,7 @@ nouveau_hwmon_fini(struct drm_device *dev) sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup); hwmon_device_unregister(pm->hwmon); } +#endif } int -- cgit v1.2.3 From dd661e5f4e87609e7a9b4cbdff305dca7f494e7b Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 1 Nov 2010 18:06:28 +0100 Subject: drm/nouveau: Return error from nouveau_gpuobj_new if we're out of RAMIN. Reported-by: Tomas Miljenovic Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 896cf8634144..dd572adca02a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -129,7 +129,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, if (ramin == NULL) { spin_unlock(&dev_priv->ramin_lock); nouveau_gpuobj_ref(NULL, &gpuobj); - return ret; + return -ENOMEM; } ramin = drm_mm_get_block_atomic(ramin, size, align); -- cgit v1.2.3 From 9d5a6c4353eeac1e0095e731a0a746254f23af83 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 1 Nov 2010 18:08:26 +0100 Subject: drm/nouveau: Make PCIE GART size depend on the available RAMIN space. Reported-by: Tomas Miljenovic Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 0b309c1cc3d7..d4ac97007038 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -224,11 +224,11 @@ nouveau_sgdma_init(struct drm_device *dev) int i, ret; if (dev_priv->card_type < NV_50) { - if(dev_priv->card_type < NV_40) { - aper_size = (64 * 1024 * 1024); - } else { - aper_size = (512 * 1024 * 1024); - } + if(dev_priv->ramin_rsvd_vram < 2 * 1024 * 1024) + aper_size = 64 * 1024 * 1024; + else + aper_size = 512 * 1024 * 1024; + obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4; obj_size += 8; /* ctxdma header */ } else { -- cgit v1.2.3 From cac8f05b4294d18cfa940511c286ca03aa6590ad Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Wed, 20 Oct 2010 01:09:56 +0200 Subject: drm/nouveau/pm: improve memtiming mappings Improvements: - Fix bug in switch statement - Add parts of 0x10022c, 0x10023c - Clean up 0x100234 - Comment out assumption in 0x100228 until verified Signed-off-by: Roy Spliet Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_mem.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index ac3bec024fd5..fe4a30dc4b42 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -651,6 +651,7 @@ nouveau_mem_gart_init(struct drm_device *dev) void nouveau_mem_timing_init(struct drm_device *dev) { + /* cards < NVC0 only */ struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_engine *pm = &dev_priv->engine.pm; struct nouveau_pm_memtimings *memtimings = &pm->memtimings; @@ -717,14 +718,14 @@ nouveau_mem_timing_init(struct drm_device *dev) tUNK_19 = 1; tUNK_20 = 0; tUNK_21 = 0; - switch (min(recordlen, 21)) { - case 21: + switch (min(recordlen, 22)) { + case 22: tUNK_21 = entry[21]; - case 20: + case 21: tUNK_20 = entry[20]; - case 19: + case 20: tUNK_19 = entry[19]; - case 18: + case 19: tUNK_18 = entry[18]; default: tUNK_0 = entry[0]; @@ -754,24 +755,30 @@ nouveau_mem_timing_init(struct drm_device *dev) timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10); if(recordlen > 19) { timing->reg_100228 += (tUNK_19 - 1) << 24; - } else { + }/* I cannot back-up this else-statement right now + else { timing->reg_100228 += tUNK_12 << 24; - } + }*/ /* XXX: reg_10022c */ + timing->reg_10022c = tUNK_2 - 1; timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 | tUNK_13 << 8 | tUNK_13); /* XXX: +6? */ timing->reg_100234 = (tRAS << 24 | (tUNK_19 + 6) << 8 | tRC); - if(tUNK_10 > tUNK_11) { - timing->reg_100234 += tUNK_10 << 16; - } else { - timing->reg_100234 += tUNK_11 << 16; + timing->reg_100234 += max(tUNK_10,tUNK_11) << 16; + + /* XXX; reg_100238, reg_10023c + * reg: 0x00?????? + * reg_10023c: + * 0 for pre-NV50 cards + * 0x????0202 for NV50+ cards (empirical evidence) */ + if(dev_priv->card_type >= NV_50) { + timing->reg_10023c = 0x202; } - /* XXX; reg_100238, reg_10023c */ NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i, timing->reg_100220, timing->reg_100224, timing->reg_100228, timing->reg_10022c); -- cgit v1.2.3 From 5bead799d3f8f1500c4b59301b8a2732a92f559f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 4 Nov 2010 09:56:12 +1000 Subject: drm/nouveau: don't expose backlight control when available through ACPI Avoid confusing userspace by not publishing backlight controls if ACPI equivalents are available. Reported-by: Aaron Sowry Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_backlight.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 406228f4a2a0..b14c81110575 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -31,6 +31,7 @@ */ #include +#include #include "drmP.h" #include "nouveau_drv.h" @@ -136,6 +137,14 @@ int nouveau_backlight_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; +#ifdef CONFIG_ACPI + if (acpi_video_backlight_support()) { + NV_INFO(dev, "ACPI backlight interface available, " + "not registering our own\n"); + return 0; + } +#endif + switch (dev_priv->card_type) { case NV_40: return nouveau_nv40_backlight_init(dev); -- cgit v1.2.3 From c1b60ece91460214b5135360a375f3f6fbb59608 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 11 Nov 2010 00:56:37 +0100 Subject: drm/nouveau: Fix a few confusions between "chipset" and "card_type". Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 2 +- drivers/gpu/drm/nouveau/nouveau_i2c.c | 2 +- drivers/gpu/drm/nouveau/nouveau_temp.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 5f21030a293b..b2293576f278 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6829,7 +6829,7 @@ nouveau_bios_posted(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; unsigned htotal; - if (dev_priv->chipset >= NV_50) { + if (dev_priv->card_type >= NV_50) { if (NVReadVgaCrtc(dev, 0, 0x00) == 0 && NVReadVgaCrtc(dev, 0, 0x1a) == 0) return false; diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index fdd7e3de79c8..cb389d014326 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -256,7 +256,7 @@ nouveau_i2c_find(struct drm_device *dev, int index) if (index >= DCB_MAX_NUM_I2C_ENTRIES) return NULL; - if (dev_priv->chipset >= NV_50 && (i2c->entry & 0x00000100)) { + if (dev_priv->card_type >= NV_50 && (i2c->entry & 0x00000100)) { uint32_t reg = 0xe500, val; if (i2c->port_type == 6) { diff --git a/drivers/gpu/drm/nouveau/nouveau_temp.c b/drivers/gpu/drm/nouveau/nouveau_temp.c index 16bbbf1eff63..7ecc4adc1e45 100644 --- a/drivers/gpu/drm/nouveau/nouveau_temp.c +++ b/drivers/gpu/drm/nouveau/nouveau_temp.c @@ -191,7 +191,7 @@ nv40_temp_get(struct drm_device *dev) int offset = sensor->offset_mult / sensor->offset_div; int core_temp; - if (dev_priv->chipset >= 0x50) { + if (dev_priv->card_type >= NV_50) { core_temp = nv_rd32(dev, 0x20008); } else { core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff; -- cgit v1.2.3 From ab838338a2a9e0cb8346eb0cab9977be13e8dce5 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 16 Nov 2010 18:40:52 -0500 Subject: nouveau: Acknowledge HPD irq in handler, not bottom half The old code generated an interrupt storm bad enough to completely take down my system. Signed-off-by: Andy Lutomirski Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 6 ++++++ drivers/gpu/drm/nouveau/nouveau_irq.c | 1 + drivers/gpu/drm/nouveau/nv50_display.c | 35 +++++++++++++++++++++++++--------- 3 files changed, 33 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 10a8d4e78e58..1c7db64c03bf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -584,6 +584,12 @@ struct drm_nouveau_private { struct work_struct irq_work; struct work_struct hpd_work; + struct { + spinlock_t lock; + uint32_t hpd0_bits; + uint32_t hpd1_bits; + } hpd_state; + struct list_head vbl_waiting; struct { diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index e2f2d59be3ea..7bfd9e6c9d67 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -60,6 +60,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); + spin_lock_init(&dev_priv->hpd_state.lock); 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 55c9663ef2bf..f624c611ddea 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1032,11 +1032,18 @@ nv50_display_irq_hotplug_bh(struct work_struct *work) struct drm_connector *connector; const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; uint32_t unplug_mask, plug_mask, change_mask; - uint32_t hpd0, hpd1 = 0; + uint32_t hpd0, hpd1; - hpd0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050); + spin_lock_irq(&dev_priv->hpd_state.lock); + hpd0 = dev_priv->hpd_state.hpd0_bits; + dev_priv->hpd_state.hpd0_bits = 0; + hpd1 = dev_priv->hpd_state.hpd1_bits; + dev_priv->hpd_state.hpd1_bits = 0; + spin_unlock_irq(&dev_priv->hpd_state.lock); + + hpd0 &= nv_rd32(dev, 0xe050); if (dev_priv->chipset >= 0x90) - hpd1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070); + hpd1 &= nv_rd32(dev, 0xe070); plug_mask = (hpd0 & 0x0000ffff) | (hpd1 << 16); unplug_mask = (hpd0 >> 16) | (hpd1 & 0xffff0000); @@ -1078,10 +1085,6 @@ nv50_display_irq_hotplug_bh(struct work_struct *work) helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF); } - nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054)); - if (dev_priv->chipset >= 0x90) - nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074)); - drm_helper_hpd_irq_event(dev); } @@ -1092,8 +1095,22 @@ nv50_display_irq_handler(struct drm_device *dev) uint32_t delayed = 0; 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); + uint32_t hpd0_bits, hpd1_bits = 0; + + hpd0_bits = nv_rd32(dev, 0xe054); + nv_wr32(dev, 0xe054, hpd0_bits); + + if (dev_priv->chipset >= 0x90) { + hpd1_bits = nv_rd32(dev, 0xe074); + nv_wr32(dev, 0xe074, hpd1_bits); + } + + spin_lock(&dev_priv->hpd_state.lock); + dev_priv->hpd_state.hpd0_bits |= hpd0_bits; + dev_priv->hpd_state.hpd1_bits |= hpd1_bits; + spin_unlock(&dev_priv->hpd_state.lock); + + queue_work(dev_priv->wq, &dev_priv->hpd_work); } while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) { -- cgit v1.2.3 From 16790569eddf4d406a16a65f4750f405fa669c52 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 14 Nov 2010 20:24:35 -0500 Subject: drm/radeon/kms: fix and unify tiled buffer alignment checking for r6xx/7xx Tiled buffers have the same alignment requirements regardless of whether the surface is for db, cb, or textures. Previously, the calculations where inconsistent for each buffer type. - Unify the alignment calculations in a common function - Standardize the alignment units (pixels for pitch/height/depth, bytes for base) - properly check the buffer base alignments Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_cs.c | 309 ++++++++++++++++++++++++--------------- drivers/gpu/drm/radeon/r600d.h | 6 + 2 files changed, 199 insertions(+), 116 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 37cc2aa9f923..0f90fc3482ce 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,8 +293,24 @@ 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 */ @@ -260,15 +325,11 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int 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 +371,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 +419,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 +454,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 +1025,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 +1037,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 +1159,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 +1210,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 +1476,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/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) -- cgit v1.2.3 From 21e2eae4daaecf2f2a391e4f4b596c800f198edf Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Sun, 14 Nov 2010 23:08:27 +0300 Subject: drm: radeon: fix error value sign enable_vblank implementations should use negative result to indicate error. radeon_enable_vblank() returns EINVAL in this case. Change this to -EINVAL. Signed-off-by: Vasiliy Kulikov Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') 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; } } -- cgit v1.2.3 From d33ef52d9db8a36900dd53f2e32db9a521ace259 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 16 Nov 2010 16:53:14 -0500 Subject: drm/radeon/kms: fix typo in r600 cs checker Looks like a typo in: drm/radeon/r600: fix tiling issues in CS checker. (f30df2fad0c901e74ac9a52a488a54c69a373a41) Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 0f90fc3482ce..9bebac1ec006 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -315,7 +315,7 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int 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; + tmp = (height - 7) * pitch * 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; -- cgit v1.2.3 From ba251bde9ab8bdce8fbd3f60dbb71b36cc4c9adf Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 16 Nov 2010 12:09:39 -0500 Subject: drm/radeon/kms: turn the backlight off explicitly for dpms Seems some newer systems require this explicitly. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index f678257c42e6..d55cb58283a9 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -1086,6 +1086,8 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) 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: @@ -1095,20 +1097,31 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF); } + 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); } radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); -- cgit v1.2.3 From c7a71fc761551dc8be8543f14a90d08cda4e77f9 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Nov 2010 02:49:40 -0500 Subject: drm/radeon/kms/atom: set sane defaults in atombios_get_encoder_mode() If there was no connector mapped to the encoder, atombios_get_encoder_mode() returned 0 which is the id for DP. Return something sane instead based on the encoder id. This avoids hitting the DP paths on non-DP encoders. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index d55cb58283a9..c6981dfd9156 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -595,6 +595,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 +603,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) { -- cgit v1.2.3 From 8b834852d705af75ba942b040ca28533329ff13c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Nov 2010 02:54:42 -0500 Subject: drm/radeon/kms: properly power up/down the eDP panel as needed (v4) The eDP panel must be powered up for aux transactions, so power it up for detect and mode probe functions, otherwise power it up or down based on dpms. v2: - only mess with eDP panel on DCE4+ - only mess with eDP panel on eDP connectors, not all DP connectors v3: - be extra careful to only mess with eDP panels on eDP connectors v4: - avoid possible null derefernce if a connector has not been assigned to the encoder Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 18 +++++++++++ drivers/gpu/drm/radeon/radeon_encoders.c | 50 ++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_mode.h | 2 ++ 3 files changed, 70 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index fe6c74780f18..3bef9f6d66fd 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) { diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index c6981dfd9156..63f4964e8d2d 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -990,6 +990,36 @@ 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); +} + static void atombios_yuv_setup(struct drm_encoder *encoder, bool enable) { @@ -1094,6 +1124,15 @@ 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); @@ -1106,8 +1145,19 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) 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); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 680f57644e86..ef588835201f 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -385,6 +385,7 @@ struct radeon_connector_atom_dig { u8 dp_sink_type; int dp_clock; int dp_lane_count; + bool edp_on; }; struct radeon_gpio_rec { @@ -526,6 +527,7 @@ struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, i extern void atombios_external_tmds_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); -- cgit v1.2.3 From 99999aaa091bdb3e16b5eed22f3a9a567f84f0fe Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 16 Nov 2010 12:09:41 -0500 Subject: drm/radeon/kms/atom: cleanup and unify DVO handling Handle all the various asic family specific things for DVO. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 4 ++ drivers/gpu/drm/radeon/radeon_encoders.c | 90 +++++++++++++------------ drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 2 +- drivers/gpu/drm/radeon/radeon_mode.h | 2 +- 4 files changed, 52 insertions(+), 46 deletions(-) (limited to 'drivers') 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_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 63f4964e8d2d..07df990a897b 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) { @@ -426,52 +427,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 +530,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: @@ -846,6 +844,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: @@ -1085,9 +1086,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; @@ -1317,7 +1323,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); @@ -1475,11 +1481,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: @@ -1670,11 +1674,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: 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 ef588835201f..663bc51cf99e 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -524,7 +524,7 @@ 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); -- cgit v1.2.3 From 3e4b99828d1c8abefefd37474503605c811c1b51 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 16 Nov 2010 12:09:42 -0500 Subject: drm/radeon/kms/atom: add proper external encoders support These are external encoder chips connected via DVO or DP. The actual external encoder programming is handled by the kms encoder functions for primary encoder. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 183 +++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_mode.h | 1 + 2 files changed, 184 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 07df990a897b..041943df966b 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -229,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) { @@ -1021,6 +1042,75 @@ atombios_set_edp_panel_power(struct drm_connector *connector, int 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) { @@ -1064,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; @@ -1191,6 +1282,24 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) break; } } + + 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); } @@ -1438,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; @@ -1498,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) { @@ -1698,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, @@ -1807,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: @@ -1848,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); @@ -1856,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_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 663bc51cf99e..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 { -- cgit v1.2.3 From a5193fe50e7f21c26d22c17c8196420fac1a3ca7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Nov 2010 17:56:49 -0500 Subject: drm/radeon/kms: register an i2c adapter name for the dp aux bus This causes the connector to not be added since i2c init fails for the adapter. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=31688 Noticed by Ari Savolainen. Signed-off-by: Alex Deucher Cc: Ari Savolainen Cc: Jean Delvare Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_i2c.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 0cfbba02c4d0..d263bd1a0d80 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -946,6 +946,7 @@ struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, i2c->rec = *rec; i2c->adapter.owner = THIS_MODULE; i2c->dev = dev; + sprintf(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; -- cgit v1.2.3 From 2f5993cca67f9c80dcd390feef13695ca072b8a5 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 17 Nov 2010 13:24:48 +0100 Subject: drm/vmwgfx: Fix up an error path during bo creation Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 36e129f0023f..5408b1b7996f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -862,7 +862,7 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, &vmw_vram_sys_placement, true, &vmw_user_dmabuf_destroy); if (unlikely(ret != 0)) - return ret; + goto out_no_dmabuf; tmp = ttm_bo_reference(&vmw_user_bo->dma.base); ret = ttm_base_object_init(vmw_fpriv(file_priv)->tfile, @@ -870,19 +870,21 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, false, ttm_buffer_type, &vmw_user_dmabuf_release, NULL); - if (unlikely(ret != 0)) { - ttm_bo_unref(&tmp); - } else { + if (unlikely(ret != 0)) + goto out_no_base_object; + else { rep->handle = vmw_user_bo->base.hash.key; rep->map_handle = vmw_user_bo->dma.base.addr_space_offset; rep->cur_gmr_id = vmw_user_bo->base.hash.key; rep->cur_gmr_offset = 0; } - ttm_bo_unref(&tmp); +out_no_base_object: + ttm_bo_unref(&tmp); +out_no_dmabuf: ttm_read_unlock(&vmaster->lock); - return 0; + return ret; } int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data, -- cgit v1.2.3 From 268b2510de14f62134d87ba9b4981816192db386 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Nov 2010 19:00:26 -0500 Subject: drm/radeon/kms: fix alignment when allocating buffers We were previously dropping alignment requests on the floor when allocating buffers so we always ended up page aligned. Certain tiling modes on 6xx+ require larger alignment which wasn't happening before. Signed-off-by: Alex Deucher Cc: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen_blit_kms.c | 2 +- drivers/gpu/drm/radeon/r600.c | 2 +- drivers/gpu/drm/radeon/r600_blit_kms.c | 2 +- drivers/gpu/drm/radeon/radeon_benchmark.c | 4 ++-- drivers/gpu/drm/radeon/radeon_device.c | 2 +- drivers/gpu/drm/radeon/radeon_gart.c | 4 ++-- drivers/gpu/drm/radeon/radeon_gem.c | 2 +- drivers/gpu/drm/radeon/radeon_object.c | 7 ++++--- drivers/gpu/drm/radeon/radeon_object.h | 7 ++++--- drivers/gpu/drm/radeon/radeon_ring.c | 6 +++--- drivers/gpu/drm/radeon/radeon_test.c | 4 ++-- drivers/gpu/drm/radeon/radeon_ttm.c | 2 +- drivers/gpu/drm/radeon/rv770.c | 4 ++-- 13 files changed, 25 insertions(+), 23 deletions(-) (limited to 'drivers') 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/r600.c b/drivers/gpu/drm/radeon/r600.c index 0f806cc7dc75..a3552594ccc4 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2718,7 +2718,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) { 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/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_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 8adfedfe547f..d8ac1849180d 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); 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_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 8eb183466015..1d067743fee0 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -86,11 +86,12 @@ 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; + int page_align = roundup(byte_align, PAGE_SIZE) >> PAGE_SHIFT; int r; if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) { @@ -115,7 +116,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; } -- cgit v1.2.3 From 1aa52bd3bc839064d5a3e4de406850f4a3aa5378 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Nov 2010 12:11:03 -0500 Subject: drm/radeon/kms: fix tiling info on evergreen We aren't currently using tiling in userspace on evergreen, but the info we currently return for the tiling info query (gb_addr_config) is no adequate for userspace tiling alignment calculations. It does not contain the bank info. Create a custom tiling info dword with all the necessary info (num channels, num banks, group size, row size). Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 488c36c8f5e6..4dc5b4714c5a 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1650,7 +1650,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); -- cgit v1.2.3 From 95ccb0f3bdc4438bf470c25450e6a8a6090ca253 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 11 Nov 2010 10:04:53 +0100 Subject: drm/ttm: Fix up a theoretical deadlock A process suspended waiting for a higher sequence or no sequence to unreserve, a bo may be beaten to the reservation by a process with a lower sequence. In that case the first process should give up trying to reserve and return -EAGAIN. In order for that to happen, we must wake waiting processes when we change sequence, so that they have a chance to detect the new sequence. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 3ca77dc03915..148a322d8f5d 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -224,6 +224,9 @@ int ttm_bo_reserve_locked(struct ttm_buffer_object *bo, int ret; while (unlikely(atomic_cmpxchg(&bo->reserved, 0, 1) != 0)) { + /** + * Deadlock avoidance for multi-bo reserving. + */ if (use_sequence && bo->seq_valid && (sequence - bo->val_seq < (1 << 31))) { return -EAGAIN; @@ -241,6 +244,14 @@ int ttm_bo_reserve_locked(struct ttm_buffer_object *bo, } if (use_sequence) { + /** + * Wake up waiters that may need to recheck for deadlock, + * if we decreased the sequence number. + */ + if (unlikely((bo->val_seq - sequence < (1 << 31)) + || !bo->seq_valid)) + wake_up_all(&bo->event_queue); + bo->val_seq = sequence; bo->seq_valid = true; } else { -- cgit v1.2.3 From be66305718bee9927e6acc6b75618ce3cd745718 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 18 Nov 2010 17:18:08 -0500 Subject: drm/radeon/kms: fix i2c pad masks on rs4xx These got lost in the last i2c cleanup. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=23222 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_combios.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 7b7ea269549c..3bddea5b5295 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; -- cgit v1.2.3 From 164bcb94bc821fcbac752e809b4ac7c6f15d13b5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 18 Nov 2010 11:37:18 -0500 Subject: drm/radeon/kms: i2c s/sprintf/snprintf/g for safety As per advice from Jean Delvare. Signed-off-by: Alex Deucher Acked-by: Jean Delvare Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_i2c.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index d263bd1a0d80..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,7 +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; - sprintf(i2c->adapter.name, "Radeon aux bus %s", name); + 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; -- cgit v1.2.3