Commit dc87eaf1 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm-nouveau-next' of...

Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next

* 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6: (50 commits)
  drm/nv50: flesh out ZCULL init and match nvidia on later chipsets
  drm/nv50: support for compression
  drm/nv50-nvc0: delay GART binding until move_notify time
  drm/nouveau: rename nouveau_vram to nouveau_mem
  drm/nvc0: allow creation of buffers with any non-compressed memtype
  drm/nv50-nvc0: unmap buffers from the vm when they're evicted
  drm/nv50-nvc0: move vm bind/unbind to move_notify hook
  drm/nv50-nvc0: restrict memtype to those specified at creation time
  drm/nouveau: pass domain rather than ttm flags to gem_new()
  drm/nv50: simplify bo moves now that they're all through the vm
  drm/nouveau: remove no_vm/mappable flags from nouveau_bo
  drm/nouveau: Fix pageflip event
  drm/nouveau/vbios: parse more gpio tag bits from connector table
  drm/nouveau: decode PFIFO DMA_PUSHER error codes
  drm/nv50: fix typos in CCACHE error reporting
  drm/nvc0: support for sw methods + enable page flipping
  drm/nv50: enable page flipping
  drm/nv50-nvc0: activate/update ds channel's framebuffer on modesets
  drm/nv50-nvc0: initialise display sync channels
  drm/nv50-nvc0: precalculate some fb state when creating them
  ...
parents a2c06ee2 562af10c
...@@ -282,7 +282,7 @@ static void still_alive(void) ...@@ -282,7 +282,7 @@ static void still_alive(void)
{ {
#if 0 #if 0
sync(); sync();
msleep(2); mdelay(2);
#endif #endif
} }
...@@ -1904,7 +1904,7 @@ init_condition_time(struct nvbios *bios, uint16_t offset, ...@@ -1904,7 +1904,7 @@ init_condition_time(struct nvbios *bios, uint16_t offset,
BIOSLOG(bios, "0x%04X: " BIOSLOG(bios, "0x%04X: "
"Condition not met, sleeping for 20ms\n", "Condition not met, sleeping for 20ms\n",
offset); offset);
msleep(20); mdelay(20);
} }
} }
...@@ -1938,7 +1938,7 @@ init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ...@@ -1938,7 +1938,7 @@ init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X milliseconds\n", BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X milliseconds\n",
offset, time); offset, time);
msleep(time); mdelay(time);
return 3; return 3;
} }
...@@ -2962,7 +2962,7 @@ init_time(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ...@@ -2962,7 +2962,7 @@ init_time(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
if (time < 1000) if (time < 1000)
udelay(time); udelay(time);
else else
msleep((time + 900) / 1000); mdelay((time + 900) / 1000);
return 3; return 3;
} }
...@@ -3856,7 +3856,7 @@ static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_entr ...@@ -3856,7 +3856,7 @@ static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_entr
if (script == LVDS_PANEL_OFF) { if (script == LVDS_PANEL_OFF) {
/* off-on delay in ms */ /* off-on delay in ms */
msleep(ROM16(bios->data[bios->fp.xlated_entry + 7])); mdelay(ROM16(bios->data[bios->fp.xlated_entry + 7]));
} }
#ifdef __powerpc__ #ifdef __powerpc__
/* Powerbook specific quirks */ /* Powerbook specific quirks */
...@@ -5950,6 +5950,11 @@ apply_dcb_connector_quirks(struct nvbios *bios, int idx) ...@@ -5950,6 +5950,11 @@ apply_dcb_connector_quirks(struct nvbios *bios, int idx)
} }
} }
static const u8 hpd_gpio[16] = {
0xff, 0x07, 0x08, 0xff, 0xff, 0x51, 0x52, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x5f, 0x60,
};
static void static void
parse_dcb_connector_table(struct nvbios *bios) parse_dcb_connector_table(struct nvbios *bios)
{ {
...@@ -5986,23 +5991,9 @@ parse_dcb_connector_table(struct nvbios *bios) ...@@ -5986,23 +5991,9 @@ parse_dcb_connector_table(struct nvbios *bios)
cte->type = (cte->entry & 0x000000ff) >> 0; cte->type = (cte->entry & 0x000000ff) >> 0;
cte->index2 = (cte->entry & 0x00000f00) >> 8; cte->index2 = (cte->entry & 0x00000f00) >> 8;
switch (cte->entry & 0x00033000) {
case 0x00001000: cte->gpio_tag = ffs((cte->entry & 0x07033000) >> 12);
cte->gpio_tag = 0x07; cte->gpio_tag = hpd_gpio[cte->gpio_tag];
break;
case 0x00002000:
cte->gpio_tag = 0x08;
break;
case 0x00010000:
cte->gpio_tag = 0x51;
break;
case 0x00020000:
cte->gpio_tag = 0x52;
break;
default:
cte->gpio_tag = 0xff;
break;
}
if (cte->type == 0xff) if (cte->type == 0xff)
continue; continue;
...@@ -6228,7 +6219,7 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb, ...@@ -6228,7 +6219,7 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb,
entry->tvconf.has_component_output = false; entry->tvconf.has_component_output = false;
break; break;
case OUTPUT_LVDS: case OUTPUT_LVDS:
if ((conn & 0x00003f00) != 0x10) if ((conn & 0x00003f00) >> 8 != 0x10)
entry->lvdsconf.use_straps_for_mode = true; entry->lvdsconf.use_straps_for_mode = true;
entry->lvdsconf.use_power_scripts = true; entry->lvdsconf.use_power_scripts = true;
break; break;
...@@ -6702,11 +6693,11 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table, ...@@ -6702,11 +6693,11 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
struct nvbios *bios = &dev_priv->vbios; struct nvbios *bios = &dev_priv->vbios;
struct init_exec iexec = { true, false }; struct init_exec iexec = { true, false };
mutex_lock(&bios->lock); spin_lock_bh(&bios->lock);
bios->display.output = dcbent; bios->display.output = dcbent;
parse_init_table(bios, table, &iexec); parse_init_table(bios, table, &iexec);
bios->display.output = NULL; bios->display.output = NULL;
mutex_unlock(&bios->lock); spin_unlock_bh(&bios->lock);
} }
static bool NVInitVBIOS(struct drm_device *dev) static bool NVInitVBIOS(struct drm_device *dev)
...@@ -6715,7 +6706,7 @@ static bool NVInitVBIOS(struct drm_device *dev) ...@@ -6715,7 +6706,7 @@ static bool NVInitVBIOS(struct drm_device *dev)
struct nvbios *bios = &dev_priv->vbios; struct nvbios *bios = &dev_priv->vbios;
memset(bios, 0, sizeof(struct nvbios)); memset(bios, 0, sizeof(struct nvbios));
mutex_init(&bios->lock); spin_lock_init(&bios->lock);
bios->dev = dev; bios->dev = dev;
if (!NVShadowVBIOS(dev, bios->data)) if (!NVShadowVBIOS(dev, bios->data))
......
...@@ -251,7 +251,7 @@ struct nvbios { ...@@ -251,7 +251,7 @@ struct nvbios {
uint8_t digital_min_front_porch; uint8_t digital_min_front_porch;
bool fp_no_ddc; bool fp_no_ddc;
struct mutex lock; spinlock_t lock;
uint8_t data[NV_PROM_SIZE]; uint8_t data[NV_PROM_SIZE];
unsigned int length; unsigned int length;
......
This diff is collapsed.
...@@ -35,7 +35,7 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan) ...@@ -35,7 +35,7 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_bo *pb = chan->pushbuf_bo; struct nouveau_bo *pb = chan->pushbuf_bo;
struct nouveau_gpuobj *pushbuf = NULL; struct nouveau_gpuobj *pushbuf = NULL;
int ret; int ret = 0;
if (dev_priv->card_type >= NV_50) { if (dev_priv->card_type >= NV_50) {
if (dev_priv->card_type < NV_C0) { if (dev_priv->card_type < NV_C0) {
...@@ -90,8 +90,7 @@ nouveau_channel_user_pushbuf_alloc(struct drm_device *dev) ...@@ -90,8 +90,7 @@ nouveau_channel_user_pushbuf_alloc(struct drm_device *dev)
else else
location = TTM_PL_FLAG_TT; location = TTM_PL_FLAG_TT;
ret = nouveau_bo_new(dev, NULL, 65536, 0, location, 0, 0x0000, false, ret = nouveau_bo_new(dev, NULL, 65536, 0, location, 0, 0x0000, &pushbuf);
true, &pushbuf);
if (ret) { if (ret) {
NV_ERROR(dev, "error allocating DMA push buffer: %d\n", ret); NV_ERROR(dev, "error allocating DMA push buffer: %d\n", ret);
return NULL; return NULL;
......
...@@ -507,6 +507,7 @@ nouveau_connector_native_mode(struct drm_connector *connector) ...@@ -507,6 +507,7 @@ nouveau_connector_native_mode(struct drm_connector *connector)
int high_w = 0, high_h = 0, high_v = 0; int high_w = 0, high_h = 0, high_v = 0;
list_for_each_entry(mode, &nv_connector->base.probed_modes, head) { list_for_each_entry(mode, &nv_connector->base.probed_modes, head) {
mode->vrefresh = drm_mode_vrefresh(mode);
if (helper->mode_valid(connector, mode) != MODE_OK || if (helper->mode_valid(connector, mode) != MODE_OK ||
(mode->flags & DRM_MODE_FLAG_INTERLACE)) (mode->flags & DRM_MODE_FLAG_INTERLACE))
continue; continue;
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "nouveau_hw.h" #include "nouveau_hw.h"
#include "nouveau_crtc.h" #include "nouveau_crtc.h"
#include "nouveau_dma.h" #include "nouveau_dma.h"
#include "nv50_display.h"
static void static void
nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
...@@ -61,18 +62,59 @@ static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = { ...@@ -61,18 +62,59 @@ static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = {
}; };
int int
nouveau_framebuffer_init(struct drm_device *dev, struct nouveau_framebuffer *nouveau_fb, nouveau_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd *mode_cmd, struct nouveau_bo *nvbo) struct nouveau_framebuffer *nv_fb,
struct drm_mode_fb_cmd *mode_cmd,
struct nouveau_bo *nvbo)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = &nv_fb->base;
int ret; int ret;
ret = drm_framebuffer_init(dev, &nouveau_fb->base, &nouveau_framebuffer_funcs); ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs);
if (ret) { if (ret) {
return ret; return ret;
} }
drm_helper_mode_fill_fb_struct(&nouveau_fb->base, mode_cmd); drm_helper_mode_fill_fb_struct(fb, mode_cmd);
nouveau_fb->nvbo = nvbo; nv_fb->nvbo = nvbo;
if (dev_priv->card_type >= NV_50) {
u32 tile_flags = nouveau_bo_tile_layout(nvbo);
if (tile_flags == 0x7a00 ||
tile_flags == 0xfe00)
nv_fb->r_dma = NvEvoFB32;
else
if (tile_flags == 0x7000)
nv_fb->r_dma = NvEvoFB16;
else
nv_fb->r_dma = NvEvoVRAM_LP;
switch (fb->depth) {
case 8: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_8; break;
case 15: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_15; break;
case 16: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_16; break;
case 24:
case 32: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_24; break;
case 30: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_30; break;
default:
NV_ERROR(dev, "unknown depth %d\n", fb->depth);
return -EINVAL;
}
if (dev_priv->chipset == 0x50)
nv_fb->r_format |= (tile_flags << 8);
if (!tile_flags)
nv_fb->r_pitch = 0x00100000 | fb->pitch;
else {
u32 mode = nvbo->tile_mode;
if (dev_priv->card_type >= NV_C0)
mode >>= 4;
nv_fb->r_pitch = ((fb->pitch / 4) << 4) | mode;
}
}
return 0; return 0;
} }
...@@ -182,6 +224,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan, ...@@ -182,6 +224,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan,
struct nouveau_page_flip_state *s, struct nouveau_page_flip_state *s,
struct nouveau_fence **pfence) struct nouveau_fence **pfence)
{ {
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct drm_device *dev = chan->dev; struct drm_device *dev = chan->dev;
unsigned long flags; unsigned long flags;
int ret; int ret;
...@@ -201,9 +244,12 @@ nouveau_page_flip_emit(struct nouveau_channel *chan, ...@@ -201,9 +244,12 @@ nouveau_page_flip_emit(struct nouveau_channel *chan,
if (ret) if (ret)
goto fail; goto fail;
BEGIN_RING(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); if (dev_priv->card_type < NV_C0)
OUT_RING(chan, 0); BEGIN_RING(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
FIRE_RING(chan); else
BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0500, 1);
OUT_RING (chan, 0);
FIRE_RING (chan);
ret = nouveau_fence_new(chan, pfence, true); ret = nouveau_fence_new(chan, pfence, true);
if (ret) if (ret)
...@@ -244,7 +290,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, ...@@ -244,7 +290,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
/* Initialize a page flip struct */ /* Initialize a page flip struct */
*s = (struct nouveau_page_flip_state) *s = (struct nouveau_page_flip_state)
{ { }, s->event, nouveau_crtc(crtc)->index, { { }, event, nouveau_crtc(crtc)->index,
fb->bits_per_pixel, fb->pitch, crtc->x, crtc->y, fb->bits_per_pixel, fb->pitch, crtc->x, crtc->y,
new_bo->bo.offset }; new_bo->bo.offset };
...@@ -255,6 +301,14 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, ...@@ -255,6 +301,14 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
mutex_lock(&chan->mutex); mutex_lock(&chan->mutex);
/* Emit a page flip */ /* Emit a page flip */
if (dev_priv->card_type >= NV_50) {
ret = nv50_display_flip_next(crtc, fb, chan);
if (ret) {
nouveau_channel_put(&chan);
goto fail_unreserve;
}
}
ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
nouveau_channel_put(&chan); nouveau_channel_put(&chan);
if (ret) if (ret)
...@@ -305,7 +359,8 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, ...@@ -305,7 +359,8 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
} }
list_del(&s->head); list_del(&s->head);
*ps = *s; if (ps)
*ps = *s;
kfree(s); kfree(s);
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&dev->event_lock, flags);
......
...@@ -96,13 +96,15 @@ nouveau_dma_init(struct nouveau_channel *chan) ...@@ -96,13 +96,15 @@ nouveau_dma_init(struct nouveau_channel *chan)
OUT_RING(chan, 0); OUT_RING(chan, 0);
/* Initialise NV_MEMORY_TO_MEMORY_FORMAT */ /* Initialise NV_MEMORY_TO_MEMORY_FORMAT */
ret = RING_SPACE(chan, 4); ret = RING_SPACE(chan, 6);
if (ret) if (ret)
return ret; return ret;
BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NAME, 1); BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NAME, 1);
OUT_RING(chan, NvM2MF); OUT_RING (chan, NvM2MF);
BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1); BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 3);
OUT_RING(chan, NvNotify0); OUT_RING (chan, NvNotify0);
OUT_RING (chan, chan->vram_handle);
OUT_RING (chan, chan->gart_handle);
/* Sit back and pray the channel works.. */ /* Sit back and pray the channel works.. */
FIRE_RING(chan); FIRE_RING(chan);
......
...@@ -61,8 +61,6 @@ enum { ...@@ -61,8 +61,6 @@ enum {
NvM2MF = 0x80000001, NvM2MF = 0x80000001,
NvDmaFB = 0x80000002, NvDmaFB = 0x80000002,
NvDmaTT = 0x80000003, NvDmaTT = 0x80000003,
NvDmaVRAM = 0x80000004,
NvDmaGART = 0x80000005,
NvNotify0 = 0x80000006, NvNotify0 = 0x80000006,
Nv2D = 0x80000007, Nv2D = 0x80000007,
NvCtxSurf2D = 0x80000008, NvCtxSurf2D = 0x80000008,
...@@ -73,12 +71,15 @@ enum { ...@@ -73,12 +71,15 @@ enum {
NvImageBlit = 0x8000000d, NvImageBlit = 0x8000000d,
NvSw = 0x8000000e, NvSw = 0x8000000e,
NvSema = 0x8000000f, NvSema = 0x8000000f,
NvEvoSema0 = 0x80000010,
NvEvoSema1 = 0x80000011,
/* G80+ display objects */ /* G80+ display objects */
NvEvoVRAM = 0x01000000, NvEvoVRAM = 0x01000000,
NvEvoFB16 = 0x01000001, NvEvoFB16 = 0x01000001,
NvEvoFB32 = 0x01000002, NvEvoFB32 = 0x01000002,
NvEvoVRAM_LP = 0x01000003 NvEvoVRAM_LP = 0x01000003,
NvEvoSync = 0xcafe0000
}; };
#define NV_MEMORY_TO_MEMORY_FORMAT 0x00000039 #define NV_MEMORY_TO_MEMORY_FORMAT 0x00000039
......
...@@ -175,7 +175,6 @@ nouveau_dp_link_train_adjust(struct drm_encoder *encoder, uint8_t *config) ...@@ -175,7 +175,6 @@ nouveau_dp_link_train_adjust(struct drm_encoder *encoder, uint8_t *config)
{ {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct bit_displayport_encoder_table_entry *dpse;
struct bit_displayport_encoder_table *dpe; struct bit_displayport_encoder_table *dpe;
int ret, i, dpe_headerlen, vs = 0, pre = 0; int ret, i, dpe_headerlen, vs = 0, pre = 0;
uint8_t request[2]; uint8_t request[2];
...@@ -183,7 +182,6 @@ nouveau_dp_link_train_adjust(struct drm_encoder *encoder, uint8_t *config) ...@@ -183,7 +182,6 @@ nouveau_dp_link_train_adjust(struct drm_encoder *encoder, uint8_t *config)
dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
if (!dpe) if (!dpe)
return false; return false;
dpse = (void *)((char *)dpe + dpe_headerlen);
ret = auxch_rd(encoder, DP_ADJUST_REQUEST_LANE0_1, request, 2); ret = auxch_rd(encoder, DP_ADJUST_REQUEST_LANE0_1, request, 2);
if (ret) if (ret)
......
...@@ -57,7 +57,7 @@ struct nouveau_fpriv { ...@@ -57,7 +57,7 @@ struct nouveau_fpriv {
#include "nouveau_util.h" #include "nouveau_util.h"
struct nouveau_grctx; struct nouveau_grctx;
struct nouveau_vram; struct nouveau_mem;
#include "nouveau_vm.h" #include "nouveau_vm.h"
#define MAX_NUM_DCB_ENTRIES 16 #define MAX_NUM_DCB_ENTRIES 16
...@@ -65,13 +65,16 @@ struct nouveau_vram; ...@@ -65,13 +65,16 @@ struct nouveau_vram;
#define NOUVEAU_MAX_CHANNEL_NR 128 #define NOUVEAU_MAX_CHANNEL_NR 128
#define NOUVEAU_MAX_TILE_NR 15 #define NOUVEAU_MAX_TILE_NR 15
struct nouveau_vram { struct nouveau_mem {
struct drm_device *dev; struct drm_device *dev;
struct nouveau_vma bar_vma; struct nouveau_vma bar_vma;
struct nouveau_vma tmp_vma;
u8 page_shift; u8 page_shift;
struct drm_mm_node *tag;
struct list_head regions; struct list_head regions;
dma_addr_t *pages;
u32 memtype; u32 memtype;
u64 offset; u64 offset;
u64 size; u64 size;
...@@ -90,6 +93,7 @@ struct nouveau_tile_reg { ...@@ -90,6 +93,7 @@ struct nouveau_tile_reg {
struct nouveau_bo { struct nouveau_bo {
struct ttm_buffer_object bo; struct ttm_buffer_object bo;
struct ttm_placement placement; struct ttm_placement placement;
u32 valid_domains;
u32 placements[3]; u32 placements[3];
u32 busy_placements[3]; u32 busy_placements[3];
struct ttm_bo_kmap_obj kmap; struct ttm_bo_kmap_obj kmap;
...@@ -104,8 +108,6 @@ struct nouveau_bo { ...@@ -104,8 +108,6 @@ struct nouveau_bo {
struct nouveau_channel *channel; struct nouveau_channel *channel;
struct nouveau_vma vma; struct nouveau_vma vma;
bool mappable;
bool no_vm;
uint32_t tile_mode; uint32_t tile_mode;
uint32_t tile_flags; uint32_t tile_flags;
...@@ -387,6 +389,7 @@ struct nouveau_pgraph_engine { ...@@ -387,6 +389,7 @@ struct nouveau_pgraph_engine {
}; };
struct nouveau_display_engine { struct nouveau_display_engine {
void *priv;
int (*early_init)(struct drm_device *); int (*early_init)(struct drm_device *);
void (*late_takedown)(struct drm_device *); void (*late_takedown)(struct drm_device *);
int (*create)(struct drm_device *); int (*create)(struct drm_device *);
...@@ -509,8 +512,8 @@ struct nouveau_crypt_engine { ...@@ -509,8 +512,8 @@ struct nouveau_crypt_engine {
struct nouveau_vram_engine { struct nouveau_vram_engine {
int (*init)(struct drm_device *); int (*init)(struct drm_device *);
int (*get)(struct drm_device *, u64, u32 align, u32 size_nc, int (*get)(struct drm_device *, u64, u32 align, u32 size_nc,
u32 type, struct nouveau_vram **); u32 type, struct nouveau_mem **);
void (*put)(struct drm_device *, struct nouveau_vram **); void (*put)(struct drm_device *, struct nouveau_mem **);
bool (*flags_valid)(struct drm_device *, u32 tile_flags); bool (*flags_valid)(struct drm_device *, u32 tile_flags);
}; };
...@@ -652,8 +655,6 @@ struct drm_nouveau_private { ...@@ -652,8 +655,6 @@ struct drm_nouveau_private {
/* interrupt handling */ /* interrupt handling */
void (*irq_handler[32])(struct drm_device *); void (*irq_handler[32])(struct drm_device *);
bool msi_enabled; bool msi_enabled;
struct workqueue_struct *wq;
struct work_struct irq_work;
struct list_head vbl_waiting; struct list_head vbl_waiting;
...@@ -691,15 +692,22 @@ struct drm_nouveau_private { ...@@ -691,15 +692,22 @@ struct drm_nouveau_private {
struct { struct {
enum { enum {
NOUVEAU_GART_NONE = 0, NOUVEAU_GART_NONE = 0,
NOUVEAU_GART_AGP, NOUVEAU_GART_AGP, /* AGP */
NOUVEAU_GART_SGDMA NOUVEAU_GART_PDMA, /* paged dma object */
NOUVEAU_GART_HW /* on-chip gart/vm */
} type; } type;
uint64_t aper_base; uint64_t aper_base;
uint64_t aper_size; uint64_t aper_size;
uint64_t aper_free; uint64_t aper_free;
struct ttm_backend_func *func;
struct {
struct page *page;
dma_addr_t addr;
} dummy;
struct nouveau_gpuobj *sg_ctxdma; struct nouveau_gpuobj *sg_ctxdma;
struct nouveau_vma vma;
} gart_info; } gart_info;
/* nv10-nv40 tiling regions */ /* nv10-nv40 tiling regions */
...@@ -740,14 +748,6 @@ struct drm_nouveau_private { ...@@ -740,14 +748,6 @@ struct drm_nouveau_private {
struct backlight_device *backlight; struct backlight_device *backlight;
struct nouveau_channel *evo;
u32 evo_alloc;
struct {
struct dcb_entry *dcb;
u16 script;
u32 pclk;
} evo_irq;
struct { struct {
struct dentry *channel_root; struct dentry *channel_root;
} debugfs; } debugfs;
...@@ -847,6 +847,7 @@ extern void nv10_mem_put_tile_region(struct drm_device *dev, ...@@ -847,6 +847,7 @@ extern void nv10_mem_put_tile_region(struct drm_device *dev,
struct nouveau_tile_reg *tile, struct nouveau_tile_reg *tile,
struct nouveau_fence *fence); struct nouveau_fence *fence);
extern const struct ttm_mem_type_manager_func nouveau_vram_manager; extern const struct ttm_mem_type_manager_func nouveau_vram_manager;
extern const struct ttm_mem_type_manager_func nouveau_gart_manager;
/* nouveau_notifier.c */ /* nouveau_notifier.c */
extern int nouveau_notifier_init_channel(struct nouveau_channel *); extern int nouveau_notifier_init_channel(struct nouveau_channel *);
...@@ -1294,7 +1295,7 @@ extern struct ttm_bo_driver nouveau_bo_driver; ...@@ -1294,7 +1295,7 @@ extern struct ttm_bo_driver nouveau_bo_driver;
extern int nouveau_bo_new(struct drm_device *, struct nouveau_channel *, extern int nouveau_bo_new(struct drm_device *, struct nouveau_channel *,
int size, int align, uint32_t flags, int size, int align, uint32_t flags,
uint32_t tile_mode, uint32_t tile_flags, uint32_t tile_mode, uint32_t tile_flags,
bool no_vm, bool mappable, struct nouveau_bo **); struct nouveau_bo **);
extern int nouveau_bo_pin(struct nouveau_bo *, uint32_t flags); extern int nouveau_bo_pin(struct nouveau_bo *, uint32_t flags);
extern int nouveau_bo_unpin(struct nouveau_bo *); extern int nouveau_bo_unpin(struct nouveau_bo *);
extern int nouveau_bo_map(struct nouveau_bo *); extern int nouveau_bo_map(struct nouveau_bo *);
...@@ -1355,9 +1356,9 @@ static inline struct nouveau_fence *nouveau_fence_ref(struct nouveau_fence *obj) ...@@ -1355,9 +1356,9 @@ static inline struct nouveau_fence *nouveau_fence_ref(struct nouveau_fence *obj)
/* nouveau_gem.c */ /* nouveau_gem.c */
extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *, extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *,
int size, int align, uint32_t flags, int size, int align, uint32_t domain,
uint32_t tile_mode, uint32_t tile_flags, uint32_t tile_mode, uint32_t tile_flags,
bool no_vm, bool mappable, struct nouveau_bo **); struct nouveau_bo **);
extern int nouveau_gem_object_new(struct drm_gem_object *); extern int nouveau_gem_object_new(struct drm_gem_object *);
extern void nouveau_gem_object_del(struct drm_gem_object *); extern void nouveau_gem_object_del(struct drm_gem_object *);
extern int nouveau_gem_ioctl_new(struct drm_device *, void *, extern int nouveau_gem_ioctl_new(struct drm_device *, void *,
......
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
struct nouveau_framebuffer { struct nouveau_framebuffer {
struct drm_framebuffer base; struct drm_framebuffer base;
struct nouveau_bo *nvbo; struct nouveau_bo *nvbo;
u32 r_dma;
u32 r_format;
u32 r_pitch;
}; };
static inline struct nouveau_framebuffer * static inline struct nouveau_framebuffer *
......
...@@ -296,8 +296,8 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, ...@@ -296,8 +296,8 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
size = mode_cmd.pitch * mode_cmd.height; size = mode_cmd.pitch * mode_cmd.height;
size = roundup(size, PAGE_SIZE); size = roundup(size, PAGE_SIZE);
ret = nouveau_gem_new(dev, dev_priv->channel, size, 0, TTM_PL_FLAG_VRAM, ret = nouveau_gem_new(dev, dev_priv->channel, size, 0,
0, 0x0000, false, true, &nvbo); NOUVEAU_GEM_DOMAIN_VRAM, 0, 0x0000, &nvbo);
if (ret) { if (ret) {
NV_ERROR(dev, "failed to allocate framebuffer\n"); NV_ERROR(dev, "failed to allocate framebuffer\n");
goto out; goto out;
......
...@@ -32,8 +32,7 @@ ...@@ -32,8 +32,7 @@
#include "nouveau_dma.h" #include "nouveau_dma.h"
#define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10) #define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10)
#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17 && \ #define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17)
nouveau_private(dev)->card_type < NV_C0)
struct nouveau_fence { struct nouveau_fence {
struct nouveau_channel *channel; struct nouveau_channel *channel;
...@@ -259,11 +258,12 @@ __nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr) ...@@ -259,11 +258,12 @@ __nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
} }
static struct nouveau_semaphore * static struct nouveau_semaphore *
alloc_semaphore(struct drm_device *dev) semaphore_alloc(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_semaphore *sema; struct nouveau_semaphore *sema;
int ret; int size = (dev_priv->chipset < 0x84) ? 4 : 16;
int ret, i;
if (!USE_SEMA(dev)) if (!USE_SEMA(dev))
return NULL; return NULL;
...@@ -277,9 +277,9 @@ alloc_semaphore(struct drm_device *dev) ...@@ -277,9 +277,9 @@ alloc_semaphore(struct drm_device *dev)
goto fail; goto fail;
spin_lock(&dev_priv->fence.lock); spin_lock(&dev_priv->fence.lock);
sema->mem = drm_mm_search_free(&dev_priv->fence.heap, 4, 0, 0); sema->mem = drm_mm_search_free(&dev_priv->fence.heap, size, 0, 0);
if (sema->mem) if (sema->mem)
sema->mem = drm_mm_get_block_atomic(sema->mem, 4, 0); sema->mem = drm_mm_get_block_atomic(sema->mem, size, 0);
spin_unlock(&dev_priv->fence.lock); spin_unlock(&dev_priv->fence.lock);
if (!sema->mem) if (!sema->mem)
...@@ -287,7 +287,8 @@ alloc_semaphore(struct drm_device *dev) ...@@ -287,7 +287,8 @@ alloc_semaphore(struct drm_device *dev)
kref_init(&sema->ref); kref_init(&sema->ref);
sema->dev = dev; sema->dev = dev;
nouveau_bo_wr32(dev_priv->fence.bo, sema->mem->start / 4, 0); for (i = sema->mem->start; i < sema->mem->start + size; i += 4)
nouveau_bo_wr32(dev_priv->fence.bo, i / 4, 0);
return sema; return sema;
fail: fail:
...@@ -296,7 +297,7 @@ alloc_semaphore(struct drm_device *dev) ...@@ -296,7 +297,7 @@ alloc_semaphore(struct drm_device *dev)
} }
static void static void
free_semaphore(struct kref *ref) semaphore_free(struct kref *ref)
{ {
struct nouveau_semaphore *sema = struct nouveau_semaphore *sema =
container_of(ref, struct nouveau_semaphore, ref); container_of(ref, struct nouveau_semaphore, ref);
...@@ -318,61 +319,107 @@ semaphore_work(void *priv, bool signalled) ...@@ -318,61 +319,107 @@ semaphore_work(void *priv, bool signalled)
if (unlikely(!signalled)) if (unlikely(!signalled))
nouveau_bo_wr32(dev_priv->fence.bo, sema->mem->start / 4, 1); nouveau_bo_wr32(dev_priv->fence.bo, sema->mem->start / 4, 1);
kref_put(&sema->ref, free_semaphore); kref_put(&sema->ref, semaphore_free);
} }
static int static int
emit_semaphore(struct nouveau_channel *chan, int method, semaphore_acquire(struct nouveau_channel *chan, struct nouveau_semaphore *sema)
struct nouveau_semaphore *sema)
{ {
struct drm_nouveau_private *dev_priv = sema->dev->dev_private; struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct nouveau_fence *fence; struct nouveau_fence *fence = NULL;
bool smart = (dev_priv->card_type >= NV_50);
int ret; int ret;
ret = RING_SPACE(chan, smart ? 8 : 4); if (dev_priv->chipset < 0x84) {
ret = RING_SPACE(chan, 3);
if (ret)
return ret;
BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 2);
OUT_RING (chan, sema->mem->start);
OUT_RING (chan, 1);
} else
if (dev_priv->chipset < 0xc0) {
struct nouveau_vma *vma = &dev_priv->fence.bo->vma;
u64 offset = vma->offset + sema->mem->start;
ret = RING_SPACE(chan, 5);
if (ret)
return ret;
BEGIN_RING(chan, NvSubSw, 0x0010, 4);
OUT_RING (chan, upper_32_bits(offset));
OUT_RING (chan, lower_32_bits(offset));
OUT_RING (chan, 1);
OUT_RING (chan, 1); /* ACQUIRE_EQ */
} else {
struct nouveau_vma *vma = &dev_priv->fence.bo->vma;
u64 offset = vma->offset + sema->mem->start;
ret = RING_SPACE(chan, 5);
if (ret)
return ret;
BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4);
OUT_RING (chan, upper_32_bits(offset));
OUT_RING (chan, lower_32_bits(offset));
OUT_RING (chan, 1);
OUT_RING (chan, 0x1001); /* ACQUIRE_EQ */
}
/* Delay semaphore destruction until its work is done */
ret = nouveau_fence_new(chan, &fence, true);
if (ret) if (ret)
return ret; return ret;
if (smart) { kref_get(&sema->ref);
BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1); nouveau_fence_work(fence, semaphore_work, sema);
OUT_RING(chan, NvSema); nouveau_fence_unref(&fence);
} return 0;
BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 1); }
OUT_RING(chan, sema->mem->start);
static int
if (smart && method == NV_SW_SEMAPHORE_ACQUIRE) { semaphore_release(struct nouveau_channel *chan, struct nouveau_semaphore *sema)
/* {
* NV50 tries to be too smart and context-switch struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
* between semaphores instead of doing a "first come, struct nouveau_fence *fence = NULL;
* first served" strategy like previous cards int ret;
* do.
* if (dev_priv->chipset < 0x84) {
* That's bad because the ACQUIRE latency can get as ret = RING_SPACE(chan, 4);
* large as the PFIFO context time slice in the if (ret)
* typical DRI2 case where you have several return ret;
* outstanding semaphores at the same moment.
* BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 1);
* If we're going to ACQUIRE, force the card to OUT_RING (chan, sema->mem->start);
* context switch before, just in case the matching BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_RELEASE, 1);
* RELEASE is already scheduled to be executed in OUT_RING (chan, 1);
* another channel. } else
*/ if (dev_priv->chipset < 0xc0) {
BEGIN_RING(chan, NvSubSw, NV_SW_YIELD, 1); struct nouveau_vma *vma = &dev_priv->fence.bo->vma;
OUT_RING(chan, 0); u64 offset = vma->offset + sema->mem->start;
}
BEGIN_RING(chan, NvSubSw, method, 1); ret = RING_SPACE(chan, 5);
OUT_RING(chan, 1); if (ret)
return ret;
if (smart && method == NV_SW_SEMAPHORE_RELEASE) {
/* BEGIN_RING(chan, NvSubSw, 0x0010, 4);
* Force the card to context switch, there may be OUT_RING (chan, upper_32_bits(offset));
* another channel waiting for the semaphore we just OUT_RING (chan, lower_32_bits(offset));
* released. OUT_RING (chan, 1);
*/ OUT_RING (chan, 2); /* RELEASE */
BEGIN_RING(chan, NvSubSw, NV_SW_YIELD, 1); } else {
OUT_RING(chan, 0); struct nouveau_vma *vma = &dev_priv->fence.bo->vma;
u64 offset = vma->offset + sema->mem->start;
ret = RING_SPACE(chan, 5);
if (ret)
return ret;
BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4);
OUT_RING (chan, upper_32_bits(offset));
OUT_RING (chan, lower_32_bits(offset));
OUT_RING (chan, 1);
OUT_RING (chan, 0x1002); /* RELEASE */
} }
/* Delay semaphore destruction until its work is done */ /* Delay semaphore destruction until its work is done */
...@@ -383,7 +430,6 @@ emit_semaphore(struct nouveau_channel *chan, int method, ...@@ -383,7 +430,6 @@ emit_semaphore(struct nouveau_channel *chan, int method,
kref_get(&sema->ref); kref_get(&sema->ref);
nouveau_fence_work(fence, semaphore_work, sema); nouveau_fence_work(fence, semaphore_work, sema);
nouveau_fence_unref(&fence); nouveau_fence_unref(&fence);
return 0; return 0;
} }
...@@ -400,7 +446,7 @@ nouveau_fence_sync(struct nouveau_fence *fence, ...@@ -400,7 +446,7 @@ nouveau_fence_sync(struct nouveau_fence *fence,
nouveau_fence_signalled(fence))) nouveau_fence_signalled(fence)))
goto out; goto out;
sema = alloc_semaphore(dev); sema = semaphore_alloc(dev);
if (!sema) { if (!sema) {
/* Early card or broken userspace, fall back to /* Early card or broken userspace, fall back to
* software sync. */ * software sync. */
...@@ -418,17 +464,17 @@ nouveau_fence_sync(struct nouveau_fence *fence, ...@@ -418,17 +464,17 @@ nouveau_fence_sync(struct nouveau_fence *fence,
} }
/* Make wchan wait until it gets signalled */ /* Make wchan wait until it gets signalled */
ret = emit_semaphore(wchan, NV_SW_SEMAPHORE_ACQUIRE, sema); ret = semaphore_acquire(wchan, sema);
if (ret) if (ret)
goto out_unlock; goto out_unlock;
/* Signal the semaphore from chan */ /* Signal the semaphore from chan */
ret = emit_semaphore(chan, NV_SW_SEMAPHORE_RELEASE, sema); ret = semaphore_release(chan, sema);
out_unlock: out_unlock:
mutex_unlock(&chan->mutex); mutex_unlock(&chan->mutex);
out_unref: out_unref:
kref_put(&sema->ref, free_semaphore); kref_put(&sema->ref, semaphore_free);
out: out:
if (chan) if (chan)
nouveau_channel_put_unlocked(&chan); nouveau_channel_put_unlocked(&chan);
...@@ -449,22 +495,23 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) ...@@ -449,22 +495,23 @@ nouveau_fence_channel_init(struct nouveau_channel *chan)
struct nouveau_gpuobj *obj = NULL; struct nouveau_gpuobj *obj = NULL;
int ret; int ret;
if (dev_priv->card_type >= NV_C0)
goto out_initialised;
/* Create an NV_SW object for various sync purposes */ /* Create an NV_SW object for various sync purposes */
ret = nouveau_gpuobj_gr_new(chan, NvSw, NV_SW); ret = nouveau_gpuobj_gr_new(chan, NvSw, NV_SW);
if (ret) if (ret)
return ret; return ret;
/* we leave subchannel empty for nvc0 */ /* we leave subchannel empty for nvc0 */
if (dev_priv->card_type < NV_C0) { ret = RING_SPACE(chan, 2);
ret = RING_SPACE(chan, 2); if (ret)
if (ret) return ret;
return ret; BEGIN_RING(chan, NvSubSw, 0, 1);
BEGIN_RING(chan, NvSubSw, 0, 1); OUT_RING(chan, NvSw);
OUT_RING(chan, NvSw);
}
/* Create a DMA object for the shared cross-channel sync area. */ /* Create a DMA object for the shared cross-channel sync area. */
if (USE_SEMA(dev)) { if (USE_SEMA(dev) && dev_priv->chipset < 0x84) {
struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem; struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem;
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
...@@ -484,14 +531,20 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) ...@@ -484,14 +531,20 @@ nouveau_fence_channel_init(struct nouveau_channel *chan)
return ret; return ret;
BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1); BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1);
OUT_RING(chan, NvSema); OUT_RING(chan, NvSema);
} else {
ret = RING_SPACE(chan, 2);
if (ret)
return ret;
BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1);
OUT_RING (chan, chan->vram_handle); /* whole VM */
} }
FIRE_RING(chan); FIRE_RING(chan);
out_initialised:
INIT_LIST_HEAD(&chan->fence.pending); INIT_LIST_HEAD(&chan->fence.pending);
spin_lock_init(&chan->fence.lock); spin_lock_init(&chan->fence.lock);
atomic_set(&chan->fence.last_sequence_irq, 0); atomic_set(&chan->fence.last_sequence_irq, 0);
return 0; return 0;
} }
...@@ -519,12 +572,13 @@ int ...@@ -519,12 +572,13 @@ int
nouveau_fence_init(struct drm_device *dev) nouveau_fence_init(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
int size = (dev_priv->chipset < 0x84) ? 4096 : 16384;
int ret; int ret;
/* Create a shared VRAM heap for cross-channel sync. */ /* Create a shared VRAM heap for cross-channel sync. */
if (USE_SEMA(dev)) { if (USE_SEMA(dev)) {
ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM, ret = nouveau_bo_new(dev, NULL, size, 0, TTM_PL_FLAG_VRAM,
0, 0, false, true, &dev_priv->fence.bo); 0, 0, &dev_priv->fence.bo);
if (ret) if (ret)
return ret; return ret;
......
...@@ -61,19 +61,36 @@ nouveau_gem_object_del(struct drm_gem_object *gem) ...@@ -61,19 +61,36 @@ nouveau_gem_object_del(struct drm_gem_object *gem)
int int
nouveau_gem_new(struct drm_device *dev, struct nouveau_channel *chan, nouveau_gem_new(struct drm_device *dev, struct nouveau_channel *chan,
int size, int align, uint32_t flags, uint32_t tile_mode, int size, int align, uint32_t domain, uint32_t tile_mode,
uint32_t tile_flags, bool no_vm, bool mappable, uint32_t tile_flags, struct nouveau_bo **pnvbo)
struct nouveau_bo **pnvbo)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_bo *nvbo; struct nouveau_bo *nvbo;
u32 flags = 0;
int ret; int ret;
if (domain & NOUVEAU_GEM_DOMAIN_VRAM)
flags |= TTM_PL_FLAG_VRAM;
if (domain & NOUVEAU_GEM_DOMAIN_GART)
flags |= TTM_PL_FLAG_TT;
if (!flags || domain & NOUVEAU_GEM_DOMAIN_CPU)
flags |= TTM_PL_FLAG_SYSTEM;
ret = nouveau_bo_new(dev, chan, size, align, flags, tile_mode, ret = nouveau_bo_new(dev, chan, size, align, flags, tile_mode,
tile_flags, no_vm, mappable, pnvbo); tile_flags, pnvbo);
if (ret) if (ret)
return ret; return ret;
nvbo = *pnvbo; nvbo = *pnvbo;
/* we restrict allowed domains on nv50+ to only the types
* that were requested at creation time. not possibly on
* earlier chips without busting the ABI.
*/
nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_VRAM |
NOUVEAU_GEM_DOMAIN_GART;
if (dev_priv->card_type >= NV_50)
nvbo->valid_domains &= domain;
nvbo->gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size); nvbo->gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size);
if (!nvbo->gem) { if (!nvbo->gem) {
nouveau_bo_ref(NULL, pnvbo); nouveau_bo_ref(NULL, pnvbo);
...@@ -97,7 +114,7 @@ nouveau_gem_info(struct drm_gem_object *gem, struct drm_nouveau_gem_info *rep) ...@@ -97,7 +114,7 @@ nouveau_gem_info(struct drm_gem_object *gem, struct drm_nouveau_gem_info *rep)
rep->size = nvbo->bo.mem.num_pages << PAGE_SHIFT; rep->size = nvbo->bo.mem.num_pages << PAGE_SHIFT;
rep->offset = nvbo->bo.offset; rep->offset = nvbo->bo.offset;
rep->map_handle = nvbo->mappable ? nvbo->bo.addr_space_offset : 0; rep->map_handle = nvbo->bo.addr_space_offset;
rep->tile_mode = nvbo->tile_mode; rep->tile_mode = nvbo->tile_mode;
rep->tile_flags = nvbo->tile_flags; rep->tile_flags = nvbo->tile_flags;
return 0; return 0;
...@@ -111,19 +128,11 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, ...@@ -111,19 +128,11 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
struct drm_nouveau_gem_new *req = data; struct drm_nouveau_gem_new *req = data;
struct nouveau_bo *nvbo = NULL; struct nouveau_bo *nvbo = NULL;
struct nouveau_channel *chan = NULL; struct nouveau_channel *chan = NULL;
uint32_t flags = 0;
int ret = 0; int ret = 0;
if (unlikely(dev_priv->ttm.bdev.dev_mapping == NULL)) if (unlikely(dev_priv->ttm.bdev.dev_mapping == NULL))
dev_priv->ttm.bdev.dev_mapping = dev_priv->dev->dev_mapping; dev_priv->ttm.bdev.dev_mapping = dev_priv->dev->dev_mapping;
if (req->info.domain & NOUVEAU_GEM_DOMAIN_VRAM)
flags |= TTM_PL_FLAG_VRAM;
if (req->info.domain & NOUVEAU_GEM_DOMAIN_GART)
flags |= TTM_PL_FLAG_TT;
if (!flags || req->info.domain & NOUVEAU_GEM_DOMAIN_CPU)
flags |= TTM_PL_FLAG_SYSTEM;
if (!dev_priv->engine.vram.flags_valid(dev, req->info.tile_flags)) { if (!dev_priv->engine.vram.flags_valid(dev, req->info.tile_flags)) {
NV_ERROR(dev, "bad page flags: 0x%08x\n", req->info.tile_flags); NV_ERROR(dev, "bad page flags: 0x%08x\n", req->info.tile_flags);
return -EINVAL; return -EINVAL;
...@@ -135,10 +144,9 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, ...@@ -135,10 +144,9 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
return PTR_ERR(chan); return PTR_ERR(chan);
} }
ret = nouveau_gem_new(dev, chan, req->info.size, req->align, flags, ret = nouveau_gem_new(dev, chan, req->info.size, req->align,
req->info.tile_mode, req->info.tile_flags, false, req->info.domain, req->info.tile_mode,
(req->info.domain & NOUVEAU_GEM_DOMAIN_MAPPABLE), req->info.tile_flags, &nvbo);
&nvbo);
if (chan) if (chan)
nouveau_channel_put(&chan); nouveau_channel_put(&chan);
if (ret) if (ret)
...@@ -161,7 +169,7 @@ nouveau_gem_set_domain(struct drm_gem_object *gem, uint32_t read_domains, ...@@ -161,7 +169,7 @@ nouveau_gem_set_domain(struct drm_gem_object *gem, uint32_t read_domains,
{ {
struct nouveau_bo *nvbo = gem->driver_private; struct nouveau_bo *nvbo = gem->driver_private;
struct ttm_buffer_object *bo = &nvbo->bo; struct ttm_buffer_object *bo = &nvbo->bo;
uint32_t domains = valid_domains & uint32_t domains = valid_domains & nvbo->valid_domains &
(write_domains ? write_domains : read_domains); (write_domains ? write_domains : read_domains);
uint32_t pref_flags = 0, valid_flags = 0; uint32_t pref_flags = 0, valid_flags = 0;
......
...@@ -152,7 +152,6 @@ nouveau_mem_vram_fini(struct drm_device *dev) ...@@ -152,7 +152,6 @@ nouveau_mem_vram_fini(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
nouveau_bo_unpin(dev_priv->vga_ram);
nouveau_bo_ref(NULL, &dev_priv->vga_ram); nouveau_bo_ref(NULL, &dev_priv->vga_ram);
ttm_bo_device_release(&dev_priv->ttm.bdev); ttm_bo_device_release(&dev_priv->ttm.bdev);
...@@ -393,11 +392,17 @@ nouveau_mem_vram_init(struct drm_device *dev) ...@@ -393,11 +392,17 @@ nouveau_mem_vram_init(struct drm_device *dev)
struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
int ret, dma_bits; int ret, dma_bits;
if (dev_priv->card_type >= NV_50 && dma_bits = 32;
pci_dma_supported(dev->pdev, DMA_BIT_MASK(40))) if (dev_priv->card_type >= NV_50) {
dma_bits = 40; if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(40)))
else dma_bits = 40;
dma_bits = 32; } else
if (drm_pci_device_is_pcie(dev) &&
dev_priv->chipset != 0x40 &&
dev_priv->chipset != 0x45) {
if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(39)))
dma_bits = 39;
}
ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(dma_bits)); ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(dma_bits));
if (ret) if (ret)
...@@ -455,13 +460,17 @@ nouveau_mem_vram_init(struct drm_device *dev) ...@@ -455,13 +460,17 @@ nouveau_mem_vram_init(struct drm_device *dev)
return ret; return ret;
} }
ret = nouveau_bo_new(dev, NULL, 256*1024, 0, TTM_PL_FLAG_VRAM, if (dev_priv->card_type < NV_50) {
0, 0, true, true, &dev_priv->vga_ram); ret = nouveau_bo_new(dev, NULL, 256*1024, 0, TTM_PL_FLAG_VRAM,
if (ret == 0) 0, 0, &dev_priv->vga_ram);
ret = nouveau_bo_pin(dev_priv->vga_ram, TTM_PL_FLAG_VRAM); if (ret == 0)
if (ret) { ret = nouveau_bo_pin(dev_priv->vga_ram,
NV_WARN(dev, "failed to reserve VGA memory\n"); TTM_PL_FLAG_VRAM);
nouveau_bo_ref(NULL, &dev_priv->vga_ram);
if (ret) {
NV_WARN(dev, "failed to reserve VGA memory\n");
nouveau_bo_ref(NULL, &dev_priv->vga_ram);
}
} }
dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1), dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1),
...@@ -666,13 +675,14 @@ nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long p_size ...@@ -666,13 +675,14 @@ nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long p_size
{ {
struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev); struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev);
struct nouveau_mm *mm; struct nouveau_mm *mm;
u32 b_size; u64 size, block, rsvd;
int ret; int ret;
p_size = (p_size << PAGE_SHIFT) >> 12; rsvd = (256 * 1024); /* vga memory */
b_size = dev_priv->vram_rblock_size >> 12; size = (p_size << PAGE_SHIFT) - rsvd;
block = dev_priv->vram_rblock_size;
ret = nouveau_mm_init(&mm, 0, p_size, b_size); ret = nouveau_mm_init(&mm, rsvd >> 12, size >> 12, block >> 12);
if (ret) if (ret)
return ret; return ret;
...@@ -700,9 +710,15 @@ nouveau_vram_manager_del(struct ttm_mem_type_manager *man, ...@@ -700,9 +710,15 @@ nouveau_vram_manager_del(struct ttm_mem_type_manager *man,
{ {
struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev); struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev);
struct nouveau_vram_engine *vram = &dev_priv->engine.vram; struct nouveau_vram_engine *vram = &dev_priv->engine.vram;
struct nouveau_mem *node = mem->mm_node;
struct drm_device *dev = dev_priv->dev; struct drm_device *dev = dev_priv->dev;
vram->put(dev, (struct nouveau_vram **)&mem->mm_node); if (node->tmp_vma.node) {
nouveau_vm_unmap(&node->tmp_vma);
nouveau_vm_put(&node->tmp_vma);
}
vram->put(dev, (struct nouveau_mem **)&mem->mm_node);
} }
static int static int
...@@ -715,7 +731,7 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man, ...@@ -715,7 +731,7 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
struct nouveau_vram_engine *vram = &dev_priv->engine.vram; struct nouveau_vram_engine *vram = &dev_priv->engine.vram;
struct drm_device *dev = dev_priv->dev; struct drm_device *dev = dev_priv->dev;
struct nouveau_bo *nvbo = nouveau_bo(bo); struct nouveau_bo *nvbo = nouveau_bo(bo);
struct nouveau_vram *node; struct nouveau_mem *node;
u32 size_nc = 0; u32 size_nc = 0;
int ret; int ret;
...@@ -724,7 +740,7 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man, ...@@ -724,7 +740,7 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
ret = vram->get(dev, mem->num_pages << PAGE_SHIFT, ret = vram->get(dev, mem->num_pages << PAGE_SHIFT,
mem->page_alignment << PAGE_SHIFT, size_nc, mem->page_alignment << PAGE_SHIFT, size_nc,
(nvbo->tile_flags >> 8) & 0xff, &node); (nvbo->tile_flags >> 8) & 0x3ff, &node);
if (ret) if (ret)
return ret; return ret;
...@@ -769,3 +785,84 @@ const struct ttm_mem_type_manager_func nouveau_vram_manager = { ...@@ -769,3 +785,84 @@ const struct ttm_mem_type_manager_func nouveau_vram_manager = {
nouveau_vram_manager_del, nouveau_vram_manager_del,
nouveau_vram_manager_debug nouveau_vram_manager_debug
}; };
static int
nouveau_gart_manager_init(struct ttm_mem_type_manager *man, unsigned long psize)
{
return 0;
}
static int
nouveau_gart_manager_fini(struct ttm_mem_type_manager *man)
{
return 0;
}
static void
nouveau_gart_manager_del(struct ttm_mem_type_manager *man,
struct ttm_mem_reg *mem)
{
struct nouveau_mem *node = mem->mm_node;
if (node->tmp_vma.node) {
nouveau_vm_unmap(&node->tmp_vma);
nouveau_vm_put(&node->tmp_vma);
}
mem->mm_node = NULL;
}
static int
nouveau_gart_manager_new(struct ttm_mem_type_manager *man,
struct ttm_buffer_object *bo,
struct ttm_placement *placement,
struct ttm_mem_reg *mem)
{
struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct nouveau_vma *vma = &nvbo->vma;
struct nouveau_vm *vm = vma->vm;
struct nouveau_mem *node;
int ret;
if (unlikely((mem->num_pages << PAGE_SHIFT) >=
dev_priv->gart_info.aper_size))
return -ENOMEM;
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node)
return -ENOMEM;
/* This node must be for evicting large-paged VRAM
* to system memory. Due to a nv50 limitation of
* not being able to mix large/small pages within
* the same PDE, we need to create a temporary
* small-paged VMA for the eviction.
*/
if (vma->node->type != vm->spg_shift) {
ret = nouveau_vm_get(vm, (u64)vma->node->length << 12,
vm->spg_shift, NV_MEM_ACCESS_RW,
&node->tmp_vma);
if (ret) {
kfree(node);
return ret;
}
}
node->page_shift = nvbo->vma.node->type;
mem->mm_node = node;
mem->start = 0;
return 0;
}
void
nouveau_gart_manager_debug(struct ttm_mem_type_manager *man, const char *prefix)
{
}
const struct ttm_mem_type_manager_func nouveau_gart_manager = {
nouveau_gart_manager_init,
nouveau_gart_manager_fini,
nouveau_gart_manager_new,
nouveau_gart_manager_del,
nouveau_gart_manager_debug
};
...@@ -53,13 +53,13 @@ void nouveau_mm_put(struct nouveau_mm *, struct nouveau_mm_node *); ...@@ -53,13 +53,13 @@ void nouveau_mm_put(struct nouveau_mm *, struct nouveau_mm_node *);
int nv50_vram_init(struct drm_device *); int nv50_vram_init(struct drm_device *);
int nv50_vram_new(struct drm_device *, u64 size, u32 align, u32 size_nc, int nv50_vram_new(struct drm_device *, u64 size, u32 align, u32 size_nc,
u32 memtype, struct nouveau_vram **); u32 memtype, struct nouveau_mem **);
void nv50_vram_del(struct drm_device *, struct nouveau_vram **); void nv50_vram_del(struct drm_device *, struct nouveau_mem **);
bool nv50_vram_flags_valid(struct drm_device *, u32 tile_flags); bool nv50_vram_flags_valid(struct drm_device *, u32 tile_flags);
int nvc0_vram_init(struct drm_device *); int nvc0_vram_init(struct drm_device *);
int nvc0_vram_new(struct drm_device *, u64 size, u32 align, u32 ncmin, int nvc0_vram_new(struct drm_device *, u64 size, u32 align, u32 ncmin,
u32 memtype, struct nouveau_vram **); u32 memtype, struct nouveau_mem **);
bool nvc0_vram_flags_valid(struct drm_device *, u32 tile_flags); bool nvc0_vram_flags_valid(struct drm_device *, u32 tile_flags);
#endif #endif
...@@ -39,12 +39,11 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan) ...@@ -39,12 +39,11 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan)
int ret; int ret;
if (nouveau_vram_notify) if (nouveau_vram_notify)
flags = TTM_PL_FLAG_VRAM; flags = NOUVEAU_GEM_DOMAIN_VRAM;
else else
flags = TTM_PL_FLAG_TT; flags = NOUVEAU_GEM_DOMAIN_GART;
ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, flags, ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, flags, 0, 0, &ntfy);
0, 0x0000, false, true, &ntfy);
if (ret) if (ret)
return ret; return ret;
...@@ -99,6 +98,7 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, ...@@ -99,6 +98,7 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
int size, uint32_t *b_offset) int size, uint32_t *b_offset)
{ {
struct drm_device *dev = chan->dev; struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *nobj = NULL; struct nouveau_gpuobj *nobj = NULL;
struct drm_mm_node *mem; struct drm_mm_node *mem;
uint32_t offset; uint32_t offset;
...@@ -112,11 +112,16 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, ...@@ -112,11 +112,16 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
return -ENOMEM; return -ENOMEM;
} }
if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM) if (dev_priv->card_type < NV_50) {
target = NV_MEM_TARGET_VRAM; if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM)
else target = NV_MEM_TARGET_VRAM;
target = NV_MEM_TARGET_GART; else
offset = chan->notifier_bo->bo.mem.start << PAGE_SHIFT; target = NV_MEM_TARGET_GART;
offset = chan->notifier_bo->bo.mem.start << PAGE_SHIFT;
} else {
target = NV_MEM_TARGET_VM;
offset = chan->notifier_bo->vma.offset;
}
offset += mem->start; offset += mem->start;
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, offset, ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, offset,
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "nouveau_drm.h" #include "nouveau_drm.h"
#include "nouveau_ramht.h" #include "nouveau_ramht.h"
#include "nouveau_vm.h" #include "nouveau_vm.h"
#include "nv50_display.h"
struct nouveau_gpuobj_method { struct nouveau_gpuobj_method {
struct list_head head; struct list_head head;
...@@ -490,16 +491,22 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base, ...@@ -490,16 +491,22 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base,
} }
if (target == NV_MEM_TARGET_GART) { if (target == NV_MEM_TARGET_GART) {
if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) { struct nouveau_gpuobj *gart = dev_priv->gart_info.sg_ctxdma;
target = NV_MEM_TARGET_PCI_NOSNOOP;
base += dev_priv->gart_info.aper_base; if (dev_priv->gart_info.type == NOUVEAU_GART_PDMA) {
} else if (base == 0) {
if (base != 0) { nouveau_gpuobj_ref(gart, pobj);
base = nouveau_sgdma_get_physical(dev, base); return 0;
}
base = nouveau_sgdma_get_physical(dev, base);
target = NV_MEM_TARGET_PCI; target = NV_MEM_TARGET_PCI;
} else { } else {
nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, pobj); base += dev_priv->gart_info.aper_base;
return 0; if (dev_priv->gart_info.type == NOUVEAU_GART_AGP)
target = NV_MEM_TARGET_PCI_NOSNOOP;
else
target = NV_MEM_TARGET_PCI;
} }
} }
...@@ -776,7 +783,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, ...@@ -776,7 +783,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
struct drm_device *dev = chan->dev; struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *vram = NULL, *tt = NULL; struct nouveau_gpuobj *vram = NULL, *tt = NULL;
int ret; int ret, i;
NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h); NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
...@@ -841,6 +848,25 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, ...@@ -841,6 +848,25 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
nouveau_gpuobj_ref(NULL, &ramht); nouveau_gpuobj_ref(NULL, &ramht);
if (ret) if (ret)
return ret; return ret;
/* dma objects for display sync channel semaphore blocks */
for (i = 0; i < 2; i++) {
struct nouveau_gpuobj *sem = NULL;
struct nv50_display_crtc *dispc =
&nv50_display(dev)->crtc[i];
u64 offset = dispc->sem.bo->bo.mem.start << PAGE_SHIFT;
ret = nouveau_gpuobj_dma_new(chan, 0x3d, offset, 0xfff,
NV_MEM_ACCESS_RW,
NV_MEM_TARGET_VRAM, &sem);
if (ret)
return ret;
ret = nouveau_ramht_insert(chan, NvEvoSema0 + i, sem);
nouveau_gpuobj_ref(NULL, &sem);
if (ret)
return ret;
}
} }
/* VRAM ctxdma */ /* VRAM ctxdma */
......
...@@ -543,7 +543,7 @@ nouveau_pm_resume(struct drm_device *dev) ...@@ -543,7 +543,7 @@ nouveau_pm_resume(struct drm_device *dev)
struct nouveau_pm_engine *pm = &dev_priv->engine.pm; struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
struct nouveau_pm_level *perflvl; struct nouveau_pm_level *perflvl;
if (pm->cur == &pm->boot) if (!pm->cur || pm->cur == &pm->boot)
return; return;
perflvl = pm->cur; perflvl = pm->cur;
......
...@@ -114,7 +114,9 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle, ...@@ -114,7 +114,9 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
(gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
} else { } else {
if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) { if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) {
ctx = (gpuobj->cinst << 10) | chan->id; ctx = (gpuobj->cinst << 10) |
(chan->id << 28) |
chan->id; /* HASH_TAG */
} else { } else {
ctx = (gpuobj->cinst >> 4) | ctx = (gpuobj->cinst >> 4) |
((gpuobj->engine << ((gpuobj->engine <<
......
This diff is collapsed.
...@@ -544,7 +544,6 @@ static int ...@@ -544,7 +544,6 @@ static int
nouveau_card_init_channel(struct drm_device *dev) nouveau_card_init_channel(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *gpuobj = NULL;
int ret; int ret;
ret = nouveau_channel_alloc(dev, &dev_priv->channel, ret = nouveau_channel_alloc(dev, &dev_priv->channel,
...@@ -552,41 +551,8 @@ nouveau_card_init_channel(struct drm_device *dev) ...@@ -552,41 +551,8 @@ nouveau_card_init_channel(struct drm_device *dev)
if (ret) if (ret)
return ret; return ret;
/* no dma objects on fermi... */
if (dev_priv->card_type >= NV_C0)
goto out_done;
ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY,
0, dev_priv->vram_size,
NV_MEM_ACCESS_RW, NV_MEM_TARGET_VRAM,
&gpuobj);
if (ret)
goto out_err;
ret = nouveau_ramht_insert(dev_priv->channel, NvDmaVRAM, gpuobj);
nouveau_gpuobj_ref(NULL, &gpuobj);
if (ret)
goto out_err;
ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY,
0, dev_priv->gart_info.aper_size,
NV_MEM_ACCESS_RW, NV_MEM_TARGET_GART,
&gpuobj);
if (ret)
goto out_err;
ret = nouveau_ramht_insert(dev_priv->channel, NvDmaGART, gpuobj);
nouveau_gpuobj_ref(NULL, &gpuobj);
if (ret)
goto out_err;
out_done:
mutex_unlock(&dev_priv->channel->mutex); mutex_unlock(&dev_priv->channel->mutex);
return 0; return 0;
out_err:
nouveau_channel_put(&dev_priv->channel);
return ret;
} }
static void nouveau_switcheroo_set_state(struct pci_dev *pdev, static void nouveau_switcheroo_set_state(struct pci_dev *pdev,
...@@ -929,12 +895,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) ...@@ -929,12 +895,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n", NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n",
dev->pci_vendor, dev->pci_device, dev->pdev->class); dev->pci_vendor, dev->pci_device, dev->pdev->class);
dev_priv->wq = create_workqueue("nouveau");
if (!dev_priv->wq) {
ret = -EINVAL;
goto err_priv;
}
/* resource 0 is mmio regs */ /* resource 0 is mmio regs */
/* resource 1 is linear FB */ /* resource 1 is linear FB */
/* resource 2 is RAMIN (mmio regs + 0x1000000) */ /* resource 2 is RAMIN (mmio regs + 0x1000000) */
...@@ -947,7 +907,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) ...@@ -947,7 +907,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
NV_ERROR(dev, "Unable to initialize the mmio mapping. " NV_ERROR(dev, "Unable to initialize the mmio mapping. "
"Please report your setup to " DRIVER_EMAIL "\n"); "Please report your setup to " DRIVER_EMAIL "\n");
ret = -EINVAL; ret = -EINVAL;
goto err_wq; goto err_priv;
} }
NV_DEBUG(dev, "regs mapped ok at 0x%llx\n", NV_DEBUG(dev, "regs mapped ok at 0x%llx\n",
(unsigned long long)mmio_start_offs); (unsigned long long)mmio_start_offs);
...@@ -1054,8 +1014,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) ...@@ -1054,8 +1014,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
iounmap(dev_priv->ramin); iounmap(dev_priv->ramin);
err_mmio: err_mmio:
iounmap(dev_priv->mmio); iounmap(dev_priv->mmio);
err_wq:
destroy_workqueue(dev_priv->wq);
err_priv: err_priv:
kfree(dev_priv); kfree(dev_priv);
dev->dev_private = NULL; dev->dev_private = NULL;
...@@ -1126,7 +1084,7 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, ...@@ -1126,7 +1084,7 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
getparam->value = 1; getparam->value = 1;
break; break;
case NOUVEAU_GETPARAM_HAS_PAGEFLIP: case NOUVEAU_GETPARAM_HAS_PAGEFLIP:
getparam->value = (dev_priv->card_type < NV_50); getparam->value = 1;
break; break;
case NOUVEAU_GETPARAM_GRAPH_UNITS: case NOUVEAU_GETPARAM_GRAPH_UNITS:
/* NV40 and NV50 versions are quite different, but register /* NV40 and NV50 versions are quite different, but register
......
...@@ -239,11 +239,9 @@ static bool ...@@ -239,11 +239,9 @@ static bool
probe_monitoring_device(struct nouveau_i2c_chan *i2c, probe_monitoring_device(struct nouveau_i2c_chan *i2c,
struct i2c_board_info *info) struct i2c_board_info *info)
{ {
char modalias[16] = "i2c:";
struct i2c_client *client; struct i2c_client *client;
strlcat(modalias, info->type, sizeof(modalias)); request_module("%s%s", I2C_MODULE_PREFIX, info->type);
request_module(modalias);
client = i2c_new_device(&i2c->adapter, info); client = i2c_new_device(&i2c->adapter, info);
if (!client) if (!client)
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "nouveau_vm.h" #include "nouveau_vm.h"
void void
nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_vram *vram) nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_mem *node)
{ {
struct nouveau_vm *vm = vma->vm; struct nouveau_vm *vm = vma->vm;
struct nouveau_mm_node *r; struct nouveau_mm_node *r;
...@@ -40,7 +40,8 @@ nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_vram *vram) ...@@ -40,7 +40,8 @@ nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_vram *vram)
u32 max = 1 << (vm->pgt_bits - bits); u32 max = 1 << (vm->pgt_bits - bits);
u32 end, len; u32 end, len;
list_for_each_entry(r, &vram->regions, rl_entry) { delta = 0;
list_for_each_entry(r, &node->regions, rl_entry) {
u64 phys = (u64)r->offset << 12; u64 phys = (u64)r->offset << 12;
u32 num = r->length >> bits; u32 num = r->length >> bits;
...@@ -52,7 +53,7 @@ nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_vram *vram) ...@@ -52,7 +53,7 @@ nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_vram *vram)
end = max; end = max;
len = end - pte; len = end - pte;
vm->map(vma, pgt, vram, pte, len, phys); vm->map(vma, pgt, node, pte, len, phys, delta);
num -= len; num -= len;
pte += len; pte += len;
...@@ -60,6 +61,8 @@ nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_vram *vram) ...@@ -60,6 +61,8 @@ nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_vram *vram)
pde++; pde++;
pte = 0; pte = 0;
} }
delta += (u64)len << vma->node->type;
} }
} }
...@@ -67,14 +70,14 @@ nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_vram *vram) ...@@ -67,14 +70,14 @@ nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_vram *vram)
} }
void void
nouveau_vm_map(struct nouveau_vma *vma, struct nouveau_vram *vram) nouveau_vm_map(struct nouveau_vma *vma, struct nouveau_mem *node)
{ {
nouveau_vm_map_at(vma, 0, vram); nouveau_vm_map_at(vma, 0, node);
} }
void void
nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length, nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length,
dma_addr_t *list) struct nouveau_mem *mem, dma_addr_t *list)
{ {
struct nouveau_vm *vm = vma->vm; struct nouveau_vm *vm = vma->vm;
int big = vma->node->type != vm->spg_shift; int big = vma->node->type != vm->spg_shift;
...@@ -94,7 +97,7 @@ nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length, ...@@ -94,7 +97,7 @@ nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length,
end = max; end = max;
len = end - pte; len = end - pte;
vm->map_sg(vma, pgt, pte, list, len); vm->map_sg(vma, pgt, mem, pte, len, list);
num -= len; num -= len;
pte += len; pte += len;
......
...@@ -67,9 +67,10 @@ struct nouveau_vm { ...@@ -67,9 +67,10 @@ struct nouveau_vm {
void (*map_pgt)(struct nouveau_gpuobj *pgd, u32 pde, void (*map_pgt)(struct nouveau_gpuobj *pgd, u32 pde,
struct nouveau_gpuobj *pgt[2]); struct nouveau_gpuobj *pgt[2]);
void (*map)(struct nouveau_vma *, struct nouveau_gpuobj *, void (*map)(struct nouveau_vma *, struct nouveau_gpuobj *,
struct nouveau_vram *, u32 pte, u32 cnt, u64 phys); struct nouveau_mem *, u32 pte, u32 cnt,
u64 phys, u64 delta);
void (*map_sg)(struct nouveau_vma *, struct nouveau_gpuobj *, void (*map_sg)(struct nouveau_vma *, struct nouveau_gpuobj *,
u32 pte, dma_addr_t *, u32 cnt); struct nouveau_mem *, u32 pte, u32 cnt, dma_addr_t *);
void (*unmap)(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt); void (*unmap)(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt);
void (*flush)(struct nouveau_vm *); void (*flush)(struct nouveau_vm *);
}; };
...@@ -82,20 +83,20 @@ int nouveau_vm_ref(struct nouveau_vm *, struct nouveau_vm **, ...@@ -82,20 +83,20 @@ int nouveau_vm_ref(struct nouveau_vm *, struct nouveau_vm **,
int nouveau_vm_get(struct nouveau_vm *, u64 size, u32 page_shift, int nouveau_vm_get(struct nouveau_vm *, u64 size, u32 page_shift,
u32 access, struct nouveau_vma *); u32 access, struct nouveau_vma *);
void nouveau_vm_put(struct nouveau_vma *); void nouveau_vm_put(struct nouveau_vma *);
void nouveau_vm_map(struct nouveau_vma *, struct nouveau_vram *); void nouveau_vm_map(struct nouveau_vma *, struct nouveau_mem *);
void nouveau_vm_map_at(struct nouveau_vma *, u64 offset, struct nouveau_vram *); void nouveau_vm_map_at(struct nouveau_vma *, u64 offset, struct nouveau_mem *);
void nouveau_vm_unmap(struct nouveau_vma *); void nouveau_vm_unmap(struct nouveau_vma *);
void nouveau_vm_unmap_at(struct nouveau_vma *, u64 offset, u64 length); void nouveau_vm_unmap_at(struct nouveau_vma *, u64 offset, u64 length);
void nouveau_vm_map_sg(struct nouveau_vma *, u64 offset, u64 length, void nouveau_vm_map_sg(struct nouveau_vma *, u64 offset, u64 length,
dma_addr_t *); struct nouveau_mem *, dma_addr_t *);
/* nv50_vm.c */ /* nv50_vm.c */
void nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, void nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde,
struct nouveau_gpuobj *pgt[2]); struct nouveau_gpuobj *pgt[2]);
void nv50_vm_map(struct nouveau_vma *, struct nouveau_gpuobj *, void nv50_vm_map(struct nouveau_vma *, struct nouveau_gpuobj *,
struct nouveau_vram *, u32 pte, u32 cnt, u64 phys); struct nouveau_mem *, u32 pte, u32 cnt, u64 phys, u64 delta);
void nv50_vm_map_sg(struct nouveau_vma *, struct nouveau_gpuobj *, void nv50_vm_map_sg(struct nouveau_vma *, struct nouveau_gpuobj *,
u32 pte, dma_addr_t *, u32 cnt); struct nouveau_mem *, u32 pte, u32 cnt, dma_addr_t *);
void nv50_vm_unmap(struct nouveau_gpuobj *, u32 pte, u32 cnt); void nv50_vm_unmap(struct nouveau_gpuobj *, u32 pte, u32 cnt);
void nv50_vm_flush(struct nouveau_vm *); void nv50_vm_flush(struct nouveau_vm *);
void nv50_vm_flush_engine(struct drm_device *, int engine); void nv50_vm_flush_engine(struct drm_device *, int engine);
...@@ -104,9 +105,9 @@ void nv50_vm_flush_engine(struct drm_device *, int engine); ...@@ -104,9 +105,9 @@ void nv50_vm_flush_engine(struct drm_device *, int engine);
void nvc0_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, void nvc0_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde,
struct nouveau_gpuobj *pgt[2]); struct nouveau_gpuobj *pgt[2]);
void nvc0_vm_map(struct nouveau_vma *, struct nouveau_gpuobj *, void nvc0_vm_map(struct nouveau_vma *, struct nouveau_gpuobj *,
struct nouveau_vram *, u32 pte, u32 cnt, u64 phys); struct nouveau_mem *, u32 pte, u32 cnt, u64 phys, u64 delta);
void nvc0_vm_map_sg(struct nouveau_vma *, struct nouveau_gpuobj *, void nvc0_vm_map_sg(struct nouveau_vma *, struct nouveau_gpuobj *,
u32 pte, dma_addr_t *, u32 cnt); struct nouveau_mem *, u32 pte, u32 cnt, dma_addr_t *);
void nvc0_vm_unmap(struct nouveau_gpuobj *, u32 pte, u32 cnt); void nvc0_vm_unmap(struct nouveau_gpuobj *, u32 pte, u32 cnt);
void nvc0_vm_flush(struct nouveau_vm *); void nvc0_vm_flush(struct nouveau_vm *);
......
...@@ -1031,7 +1031,7 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num) ...@@ -1031,7 +1031,7 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num)
drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256); drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256);
ret = nouveau_bo_new(dev, NULL, 64*64*4, 0x100, TTM_PL_FLAG_VRAM, ret = nouveau_bo_new(dev, NULL, 64*64*4, 0x100, TTM_PL_FLAG_VRAM,
0, 0x0000, false, true, &nv_crtc->cursor.nvbo); 0, 0x0000, &nv_crtc->cursor.nvbo);
if (!ret) { if (!ret) {
ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
if (!ret) if (!ret)
......
...@@ -342,8 +342,8 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder, ...@@ -342,8 +342,8 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder,
if (nv_encoder->dcb->type == OUTPUT_LVDS) { if (nv_encoder->dcb->type == OUTPUT_LVDS) {
bool duallink, dummy; bool duallink, dummy;
nouveau_bios_parse_lvds_table(dev, nv_connector->native_mode-> nouveau_bios_parse_lvds_table(dev, output_mode->clock,
clock, &duallink, &dummy); &duallink, &dummy);
if (duallink) if (duallink)
regp->fp_control |= (8 << 28); regp->fp_control |= (8 << 28);
} else } else
...@@ -518,8 +518,6 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) ...@@ -518,8 +518,6 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode)
return; return;
if (nv_encoder->dcb->lvdsconf.use_power_scripts) { if (nv_encoder->dcb->lvdsconf.use_power_scripts) {
struct nouveau_connector *nv_connector = nouveau_encoder_connector_get(nv_encoder);
/* when removing an output, crtc may not be set, but PANEL_OFF /* when removing an output, crtc may not be set, but PANEL_OFF
* must still be run * must still be run
*/ */
...@@ -527,12 +525,8 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) ...@@ -527,12 +525,8 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode)
nv04_dfp_get_bound_head(dev, nv_encoder->dcb); nv04_dfp_get_bound_head(dev, nv_encoder->dcb);
if (mode == DRM_MODE_DPMS_ON) { if (mode == DRM_MODE_DPMS_ON) {
if (!nv_connector->native_mode) {
NV_ERROR(dev, "Not turning on LVDS without native mode\n");
return;
}
call_lvds_script(dev, nv_encoder->dcb, head, call_lvds_script(dev, nv_encoder->dcb, head,
LVDS_PANEL_ON, nv_connector->native_mode->clock); LVDS_PANEL_ON, nv_encoder->mode.clock);
} else } else
/* pxclk of 0 is fine for PANEL_OFF, and for a /* pxclk of 0 is fine for PANEL_OFF, and for a
* disconnected LVDS encoder there is no native_mode * disconnected LVDS encoder there is no native_mode
......
...@@ -379,6 +379,15 @@ nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data) ...@@ -379,6 +379,15 @@ nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data)
return handled; return handled;
} }
static const char *nv_dma_state_err(u32 state)
{
static const char * const desc[] = {
"NONE", "CALL_SUBR_ACTIVE", "INVALID_MTHD", "RET_SUBR_INACTIVE",
"INVALID_CMD", "IB_EMPTY"/* NV50+ */, "MEM_FAULT", "UNK"
};
return desc[(state >> 29) & 0x7];
}
void void
nv04_fifo_isr(struct drm_device *dev) nv04_fifo_isr(struct drm_device *dev)
{ {
...@@ -460,9 +469,10 @@ nv04_fifo_isr(struct drm_device *dev) ...@@ -460,9 +469,10 @@ nv04_fifo_isr(struct drm_device *dev)
if (nouveau_ratelimit()) if (nouveau_ratelimit())
NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
"Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
"State 0x%08x Push 0x%08x\n", "State 0x%08x (err: %s) Push 0x%08x\n",
chid, ho_get, dma_get, ho_put, chid, ho_get, dma_get, ho_put,
dma_put, ib_get, ib_put, state, dma_put, ib_get, ib_put, state,
nv_dma_state_err(state),
push); push);
/* METHOD_COUNT, in DMA_STATE on earlier chipsets */ /* METHOD_COUNT, in DMA_STATE on earlier chipsets */
...@@ -476,8 +486,9 @@ nv04_fifo_isr(struct drm_device *dev) ...@@ -476,8 +486,9 @@ nv04_fifo_isr(struct drm_device *dev)
} }
} else { } else {
NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x " NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x "
"Put 0x%08x State 0x%08x Push 0x%08x\n", "Put 0x%08x State 0x%08x (err: %s) Push 0x%08x\n",
chid, dma_get, dma_put, state, push); chid, dma_get, dma_put, state,
nv_dma_state_err(state), push);
if (dma_get != dma_put) if (dma_get != dma_put)
nv_wr32(dev, 0x003244, dma_put); nv_wr32(dev, 0x003244, dma_put);
......
...@@ -24,6 +24,53 @@ nv40_fb_set_tile_region(struct drm_device *dev, int i) ...@@ -24,6 +24,53 @@ nv40_fb_set_tile_region(struct drm_device *dev, int i)
} }
} }
static void
nv40_fb_init_gart(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *gart = dev_priv->gart_info.sg_ctxdma;
if (dev_priv->gart_info.type != NOUVEAU_GART_HW) {
nv_wr32(dev, 0x100800, 0x00000001);
return;
}
nv_wr32(dev, 0x100800, gart->pinst | 0x00000002);
nv_mask(dev, 0x10008c, 0x00000100, 0x00000100);
nv_wr32(dev, 0x100820, 0x00000000);
}
static void
nv44_fb_init_gart(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *gart = dev_priv->gart_info.sg_ctxdma;
u32 vinst;
if (dev_priv->gart_info.type != NOUVEAU_GART_HW) {
nv_wr32(dev, 0x100850, 0x80000000);
nv_wr32(dev, 0x100800, 0x00000001);
return;
}
/* calculate vram address of this PRAMIN block, object
* must be allocated on 512KiB alignment, and not exceed
* a total size of 512KiB for this to work correctly
*/
vinst = nv_rd32(dev, 0x10020c);
vinst -= ((gart->pinst >> 19) + 1) << 19;
nv_wr32(dev, 0x100850, 0x80000000);
nv_wr32(dev, 0x100818, dev_priv->gart_info.dummy.addr);
nv_wr32(dev, 0x100804, dev_priv->gart_info.aper_size);
nv_wr32(dev, 0x100850, 0x00008000);
nv_mask(dev, 0x10008c, 0x00000200, 0x00000200);
nv_wr32(dev, 0x100820, 0x00000000);
nv_wr32(dev, 0x10082c, 0x00000001);
nv_wr32(dev, 0x100800, vinst | 0x00000010);
}
int int
nv40_fb_init(struct drm_device *dev) nv40_fb_init(struct drm_device *dev)
{ {
...@@ -32,12 +79,12 @@ nv40_fb_init(struct drm_device *dev) ...@@ -32,12 +79,12 @@ nv40_fb_init(struct drm_device *dev)
uint32_t tmp; uint32_t tmp;
int i; int i;
/* This is strictly a NV4x register (don't know about NV5x). */ if (dev_priv->chipset != 0x40 && dev_priv->chipset != 0x45) {
/* The blob sets these to all kinds of values, and they mess up our setup. */ if (nv44_graph_class(dev))
/* I got value 0x52802 instead. For some cards the blob even sets it back to 0x1. */ nv44_fb_init_gart(dev);
/* Note: the blob doesn't read this value, so i'm pretty sure this is safe for all cards. */ else
/* Any idea what this is? */ nv40_fb_init_gart(dev);
nv_wr32(dev, NV40_PFB_UNK_800, 0x1); }
switch (dev_priv->chipset) { switch (dev_priv->chipset) {
case 0x40: case 0x40:
......
...@@ -211,18 +211,32 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i) ...@@ -211,18 +211,32 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i)
struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
switch (dev_priv->chipset) { switch (dev_priv->chipset) {
case 0x40:
case 0x41: /* guess */
case 0x42:
case 0x43:
case 0x45: /* guess */
case 0x4e:
nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch);
nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
break;
case 0x44: case 0x44:
case 0x4a: case 0x4a:
case 0x4e:
nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
break; break;
case 0x46: case 0x46:
case 0x47: case 0x47:
case 0x49: case 0x49:
case 0x4b: case 0x4b:
case 0x4c:
case 0x67:
default:
nv_wr32(dev, NV47_PGRAPH_TSIZE(i), tile->pitch); nv_wr32(dev, NV47_PGRAPH_TSIZE(i), tile->pitch);
nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), tile->limit); nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), tile->limit);
nv_wr32(dev, NV47_PGRAPH_TILE(i), tile->addr); nv_wr32(dev, NV47_PGRAPH_TILE(i), tile->addr);
...@@ -230,15 +244,6 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i) ...@@ -230,15 +244,6 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i)
nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
break; break;
default:
nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch);
nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
break;
} }
} }
...@@ -396,17 +401,20 @@ nv40_graph_init(struct drm_device *dev) ...@@ -396,17 +401,20 @@ nv40_graph_init(struct drm_device *dev)
break; break;
default: default:
switch (dev_priv->chipset) { switch (dev_priv->chipset) {
case 0x46: case 0x41:
case 0x47: case 0x42:
case 0x49: case 0x43:
case 0x4b: case 0x45:
nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0)); case 0x4e:
nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1)); case 0x44:
break; case 0x4a:
default:
nv_wr32(dev, 0x4009F0, nv_rd32(dev, NV04_PFB_CFG0)); nv_wr32(dev, 0x4009F0, nv_rd32(dev, NV04_PFB_CFG0));
nv_wr32(dev, 0x4009F4, nv_rd32(dev, NV04_PFB_CFG1)); nv_wr32(dev, 0x4009F4, nv_rd32(dev, NV04_PFB_CFG1));
break; break;
default:
nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0));
nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1));
break;
} }
nv_wr32(dev, 0x4069F0, nv_rd32(dev, NV04_PFB_CFG0)); nv_wr32(dev, 0x4069F0, nv_rd32(dev, NV04_PFB_CFG0));
nv_wr32(dev, 0x4069F4, nv_rd32(dev, NV04_PFB_CFG1)); nv_wr32(dev, 0x4069F4, nv_rd32(dev, NV04_PFB_CFG1));
......
...@@ -65,7 +65,7 @@ nv50_crtc_blank(struct nouveau_crtc *nv_crtc, bool blanked) ...@@ -65,7 +65,7 @@ nv50_crtc_blank(struct nouveau_crtc *nv_crtc, bool blanked)
{ {
struct drm_device *dev = nv_crtc->base.dev; struct drm_device *dev = nv_crtc->base.dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = dev_priv->evo; struct nouveau_channel *evo = nv50_display(dev)->master;
int index = nv_crtc->index, ret; int index = nv_crtc->index, ret;
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
...@@ -135,8 +135,7 @@ static int ...@@ -135,8 +135,7 @@ static int
nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool on, bool update) nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool on, bool update)
{ {
struct drm_device *dev = nv_crtc->base.dev; struct drm_device *dev = nv_crtc->base.dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *evo = nv50_display(dev)->master;
struct nouveau_channel *evo = dev_priv->evo;
int ret; int ret;
NV_DEBUG_KMS(dev, "\n"); NV_DEBUG_KMS(dev, "\n");
...@@ -186,8 +185,7 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, int scaling_mode, bool update) ...@@ -186,8 +185,7 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, int scaling_mode, bool update)
struct nouveau_connector *nv_connector = struct nouveau_connector *nv_connector =
nouveau_crtc_connector_get(nv_crtc); nouveau_crtc_connector_get(nv_crtc);
struct drm_device *dev = nv_crtc->base.dev; struct drm_device *dev = nv_crtc->base.dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *evo = nv50_display(dev)->master;
struct nouveau_channel *evo = dev_priv->evo;
struct drm_display_mode *native_mode = NULL; struct drm_display_mode *native_mode = NULL;
struct drm_display_mode *mode = &nv_crtc->base.mode; struct drm_display_mode *mode = &nv_crtc->base.mode;
uint32_t outX, outY, horiz, vert; uint32_t outX, outY, horiz, vert;
...@@ -445,6 +443,42 @@ nv50_crtc_dpms(struct drm_crtc *crtc, int mode) ...@@ -445,6 +443,42 @@ nv50_crtc_dpms(struct drm_crtc *crtc, int mode)
{ {
} }
static int
nv50_crtc_wait_complete(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
struct nv50_display *disp = nv50_display(dev);
struct nouveau_channel *evo = disp->master;
u64 start;
int ret;
ret = RING_SPACE(evo, 6);
if (ret)
return ret;
BEGIN_RING(evo, 0, 0x0084, 1);
OUT_RING (evo, 0x80000000);
BEGIN_RING(evo, 0, 0x0080, 1);
OUT_RING (evo, 0);
BEGIN_RING(evo, 0, 0x0084, 1);
OUT_RING (evo, 0x00000000);
nv_wo32(disp->ntfy, 0x000, 0x00000000);
FIRE_RING (evo);
start = ptimer->read(dev);
do {
nv_wr32(dev, 0x61002c, 0x370);
nv_wr32(dev, 0x000140, 1);
if (nv_ro32(disp->ntfy, 0x000))
return 0;
} while (ptimer->read(dev) - start < 2000000000ULL);
return -EBUSY;
}
static void static void
nv50_crtc_prepare(struct drm_crtc *crtc) nv50_crtc_prepare(struct drm_crtc *crtc)
{ {
...@@ -453,6 +487,7 @@ nv50_crtc_prepare(struct drm_crtc *crtc) ...@@ -453,6 +487,7 @@ nv50_crtc_prepare(struct drm_crtc *crtc)
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
nv50_display_flip_stop(crtc);
drm_vblank_pre_modeset(dev, nv_crtc->index); drm_vblank_pre_modeset(dev, nv_crtc->index);
nv50_crtc_blank(nv_crtc, true); nv50_crtc_blank(nv_crtc, true);
} }
...@@ -461,24 +496,14 @@ static void ...@@ -461,24 +496,14 @@ static void
nv50_crtc_commit(struct drm_crtc *crtc) nv50_crtc_commit(struct drm_crtc *crtc)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = dev_priv->evo;
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
int ret;
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
nv50_crtc_blank(nv_crtc, false); nv50_crtc_blank(nv_crtc, false);
drm_vblank_post_modeset(dev, nv_crtc->index); drm_vblank_post_modeset(dev, nv_crtc->index);
nv50_crtc_wait_complete(crtc);
ret = RING_SPACE(evo, 2); nv50_display_flip_next(crtc, crtc->fb, NULL);
if (ret) {
NV_ERROR(dev, "no space while committing crtc\n");
return;
}
BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
OUT_RING (evo, 0);
FIRE_RING (evo);
} }
static bool static bool
...@@ -491,15 +516,15 @@ nv50_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, ...@@ -491,15 +516,15 @@ nv50_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
static int static int
nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
struct drm_framebuffer *passed_fb, struct drm_framebuffer *passed_fb,
int x, int y, bool update, bool atomic) int x, int y, bool atomic)
{ {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_device *dev = nv_crtc->base.dev; struct drm_device *dev = nv_crtc->base.dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = dev_priv->evo; struct nouveau_channel *evo = nv50_display(dev)->master;
struct drm_framebuffer *drm_fb = nv_crtc->base.fb; struct drm_framebuffer *drm_fb = nv_crtc->base.fb;
struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
int ret, format; int ret;
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
...@@ -525,28 +550,6 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, ...@@ -525,28 +550,6 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
} }
} }
switch (drm_fb->depth) {
case 8:
format = NV50_EVO_CRTC_FB_DEPTH_8;
break;
case 15:
format = NV50_EVO_CRTC_FB_DEPTH_15;
break;
case 16:
format = NV50_EVO_CRTC_FB_DEPTH_16;
break;
case 24:
case 32:
format = NV50_EVO_CRTC_FB_DEPTH_24;
break;
case 30:
format = NV50_EVO_CRTC_FB_DEPTH_30;
break;
default:
NV_ERROR(dev, "unknown depth %d\n", drm_fb->depth);
return -EINVAL;
}
nv_crtc->fb.offset = fb->nvbo->bo.mem.start << PAGE_SHIFT; nv_crtc->fb.offset = fb->nvbo->bo.mem.start << PAGE_SHIFT;
nv_crtc->fb.tile_flags = nouveau_bo_tile_layout(fb->nvbo); nv_crtc->fb.tile_flags = nouveau_bo_tile_layout(fb->nvbo);
nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8; nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8;
...@@ -556,14 +559,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, ...@@ -556,14 +559,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
return ret; return ret;
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_DMA), 1); BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_DMA), 1);
if (nv_crtc->fb.tile_flags == 0x7a00 || OUT_RING (evo, fb->r_dma);
nv_crtc->fb.tile_flags == 0xfe00)
OUT_RING(evo, NvEvoFB32);
else
if (nv_crtc->fb.tile_flags == 0x7000)
OUT_RING(evo, NvEvoFB16);
else
OUT_RING(evo, NvEvoVRAM_LP);
} }
ret = RING_SPACE(evo, 12); ret = RING_SPACE(evo, 12);
...@@ -571,45 +567,26 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, ...@@ -571,45 +567,26 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
return ret; return ret;
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_OFFSET), 5); BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_OFFSET), 5);
OUT_RING(evo, nv_crtc->fb.offset >> 8); OUT_RING (evo, nv_crtc->fb.offset >> 8);
OUT_RING(evo, 0); OUT_RING (evo, 0);
OUT_RING(evo, (drm_fb->height << 16) | drm_fb->width); OUT_RING (evo, (drm_fb->height << 16) | drm_fb->width);
if (!nv_crtc->fb.tile_flags) { OUT_RING (evo, fb->r_pitch);
OUT_RING(evo, drm_fb->pitch | (1 << 20)); OUT_RING (evo, fb->r_format);
} else {
u32 tile_mode = fb->nvbo->tile_mode;
if (dev_priv->card_type >= NV_C0)
tile_mode >>= 4;
OUT_RING(evo, ((drm_fb->pitch / 4) << 4) | tile_mode);
}
if (dev_priv->chipset == 0x50)
OUT_RING(evo, (nv_crtc->fb.tile_flags << 8) | format);
else
OUT_RING(evo, format);
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CLUT_MODE), 1); BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CLUT_MODE), 1);
OUT_RING(evo, fb->base.depth == 8 ? OUT_RING (evo, fb->base.depth == 8 ?
NV50_EVO_CRTC_CLUT_MODE_OFF : NV50_EVO_CRTC_CLUT_MODE_ON); NV50_EVO_CRTC_CLUT_MODE_OFF : NV50_EVO_CRTC_CLUT_MODE_ON);
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, COLOR_CTRL), 1); BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, COLOR_CTRL), 1);
OUT_RING(evo, NV50_EVO_CRTC_COLOR_CTRL_COLOR); OUT_RING (evo, NV50_EVO_CRTC_COLOR_CTRL_COLOR);
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_POS), 1); BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_POS), 1);
OUT_RING(evo, (y << 16) | x); OUT_RING (evo, (y << 16) | x);
if (nv_crtc->lut.depth != fb->base.depth) { if (nv_crtc->lut.depth != fb->base.depth) {
nv_crtc->lut.depth = fb->base.depth; nv_crtc->lut.depth = fb->base.depth;
nv50_crtc_lut_load(crtc); nv50_crtc_lut_load(crtc);
} }
if (update) {
ret = RING_SPACE(evo, 2);
if (ret)
return ret;
BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
OUT_RING(evo, 0);
FIRE_RING(evo);
}
return 0; return 0;
} }
...@@ -619,8 +596,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, ...@@ -619,8 +596,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_framebuffer *old_fb) struct drm_framebuffer *old_fb)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *evo = nv50_display(dev)->master;
struct nouveau_channel *evo = dev_priv->evo;
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct nouveau_connector *nv_connector = NULL; struct nouveau_connector *nv_connector = NULL;
uint32_t hsync_dur, vsync_dur, hsync_start_to_end, vsync_start_to_end; uint32_t hsync_dur, vsync_dur, hsync_start_to_end, vsync_start_to_end;
...@@ -700,14 +676,25 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, ...@@ -700,14 +676,25 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
nv_crtc->set_dither(nv_crtc, nv_connector->use_dithering, false); nv_crtc->set_dither(nv_crtc, nv_connector->use_dithering, false);
nv_crtc->set_scale(nv_crtc, nv_connector->scaling_mode, false); nv_crtc->set_scale(nv_crtc, nv_connector->scaling_mode, false);
return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false, false); return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
} }
static int static int
nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb) struct drm_framebuffer *old_fb)
{ {
return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, true, false); int ret;
nv50_display_flip_stop(crtc);
ret = nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
if (ret)
return ret;
ret = nv50_crtc_wait_complete(crtc);
if (ret)
return ret;
return nv50_display_flip_next(crtc, crtc->fb, NULL);
} }
static int static int
...@@ -715,7 +702,14 @@ nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc, ...@@ -715,7 +702,14 @@ nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
struct drm_framebuffer *fb, struct drm_framebuffer *fb,
int x, int y, enum mode_set_atomic state) int x, int y, enum mode_set_atomic state)
{ {
return nv50_crtc_do_mode_set_base(crtc, fb, x, y, true, true); int ret;
nv50_display_flip_stop(crtc);
ret = nv50_crtc_do_mode_set_base(crtc, fb, x, y, true);
if (ret)
return ret;
return nv50_crtc_wait_complete(crtc);
} }
static const struct drm_crtc_helper_funcs nv50_crtc_helper_funcs = { static const struct drm_crtc_helper_funcs nv50_crtc_helper_funcs = {
...@@ -758,7 +752,7 @@ nv50_crtc_create(struct drm_device *dev, int index) ...@@ -758,7 +752,7 @@ nv50_crtc_create(struct drm_device *dev, int index)
nv_crtc->lut.depth = 0; nv_crtc->lut.depth = 0;
ret = nouveau_bo_new(dev, NULL, 4096, 0x100, TTM_PL_FLAG_VRAM, ret = nouveau_bo_new(dev, NULL, 4096, 0x100, TTM_PL_FLAG_VRAM,
0, 0x0000, false, true, &nv_crtc->lut.nvbo); 0, 0x0000, &nv_crtc->lut.nvbo);
if (!ret) { if (!ret) {
ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM); ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM);
if (!ret) if (!ret)
...@@ -784,7 +778,7 @@ nv50_crtc_create(struct drm_device *dev, int index) ...@@ -784,7 +778,7 @@ nv50_crtc_create(struct drm_device *dev, int index)
drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256); drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256);
ret = nouveau_bo_new(dev, NULL, 64*64*4, 0x100, TTM_PL_FLAG_VRAM, ret = nouveau_bo_new(dev, NULL, 64*64*4, 0x100, TTM_PL_FLAG_VRAM,
0, 0x0000, false, true, &nv_crtc->cursor.nvbo); 0, 0x0000, &nv_crtc->cursor.nvbo);
if (!ret) { if (!ret) {
ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
if (!ret) if (!ret)
......
...@@ -36,9 +36,9 @@ ...@@ -36,9 +36,9 @@
static void static void
nv50_cursor_show(struct nouveau_crtc *nv_crtc, bool update) nv50_cursor_show(struct nouveau_crtc *nv_crtc, bool update)
{ {
struct drm_nouveau_private *dev_priv = nv_crtc->base.dev->dev_private;
struct nouveau_channel *evo = dev_priv->evo;
struct drm_device *dev = nv_crtc->base.dev; struct drm_device *dev = nv_crtc->base.dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = nv50_display(dev)->master;
int ret; int ret;
NV_DEBUG_KMS(dev, "\n"); NV_DEBUG_KMS(dev, "\n");
...@@ -71,9 +71,9 @@ nv50_cursor_show(struct nouveau_crtc *nv_crtc, bool update) ...@@ -71,9 +71,9 @@ nv50_cursor_show(struct nouveau_crtc *nv_crtc, bool update)
static void static void
nv50_cursor_hide(struct nouveau_crtc *nv_crtc, bool update) nv50_cursor_hide(struct nouveau_crtc *nv_crtc, bool update)
{ {
struct drm_nouveau_private *dev_priv = nv_crtc->base.dev->dev_private;
struct nouveau_channel *evo = dev_priv->evo;
struct drm_device *dev = nv_crtc->base.dev; struct drm_device *dev = nv_crtc->base.dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = nv50_display(dev)->master;
int ret; int ret;
NV_DEBUG_KMS(dev, "\n"); NV_DEBUG_KMS(dev, "\n");
......
...@@ -41,8 +41,7 @@ nv50_dac_disconnect(struct drm_encoder *encoder) ...@@ -41,8 +41,7 @@ nv50_dac_disconnect(struct drm_encoder *encoder)
{ {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *evo = nv50_display(dev)->master;
struct nouveau_channel *evo = dev_priv->evo;
int ret; int ret;
if (!nv_encoder->crtc) if (!nv_encoder->crtc)
...@@ -216,8 +215,7 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, ...@@ -216,8 +215,7 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
{ {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *evo = nv50_display(dev)->master;
struct nouveau_channel *evo = dev_priv->evo;
struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc); struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc);
uint32_t mode_ctl = 0, mode_ctl2 = 0; uint32_t mode_ctl = 0, mode_ctl2 = 0;
int ret; int ret;
......
This diff is collapsed.
...@@ -35,7 +35,36 @@ ...@@ -35,7 +35,36 @@
#include "nouveau_crtc.h" #include "nouveau_crtc.h"
#include "nv50_evo.h" #include "nv50_evo.h"
void nv50_display_irq_handler_bh(struct work_struct *work); struct nv50_display_crtc {
struct nouveau_channel *sync;
struct {
struct nouveau_bo *bo;
u32 offset;
u16 value;
} sem;
};
struct nv50_display {
struct nouveau_channel *master;
struct nouveau_gpuobj *ntfy;
struct nv50_display_crtc crtc[2];
struct tasklet_struct tasklet;
struct {
struct dcb_entry *dcb;
u16 script;
u32 pclk;
} irq;
};
static inline struct nv50_display *
nv50_display(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
return dev_priv->engine.display.priv;
}
int nv50_display_early_init(struct drm_device *dev); int nv50_display_early_init(struct drm_device *dev);
void nv50_display_late_takedown(struct drm_device *dev); void nv50_display_late_takedown(struct drm_device *dev);
int nv50_display_create(struct drm_device *dev); int nv50_display_create(struct drm_device *dev);
...@@ -44,4 +73,15 @@ void nv50_display_destroy(struct drm_device *dev); ...@@ -44,4 +73,15 @@ void nv50_display_destroy(struct drm_device *dev);
int nv50_crtc_blank(struct nouveau_crtc *, bool blank); int nv50_crtc_blank(struct nouveau_crtc *, bool blank);
int nv50_crtc_set_clock(struct drm_device *, int head, int pclk); int nv50_crtc_set_clock(struct drm_device *, int head, int pclk);
int nv50_display_flip_next(struct drm_crtc *, struct drm_framebuffer *,
struct nouveau_channel *chan);
void nv50_display_flip_stop(struct drm_crtc *);
int nv50_evo_init(struct drm_device *dev);
void nv50_evo_fini(struct drm_device *dev);
void nv50_evo_dmaobj_init(struct nouveau_gpuobj *, u32 memtype, u64 base,
u64 size);
int nv50_evo_dmaobj_new(struct nouveau_channel *, u32 handle, u32 memtype,
u64 base, u64 size, struct nouveau_gpuobj **);
#endif /* __NV50_DISPLAY_H__ */ #endif /* __NV50_DISPLAY_H__ */
This diff is collapsed.
...@@ -27,12 +27,6 @@ ...@@ -27,12 +27,6 @@
#ifndef __NV50_EVO_H__ #ifndef __NV50_EVO_H__
#define __NV50_EVO_H__ #define __NV50_EVO_H__
int nv50_evo_init(struct drm_device *dev);
void nv50_evo_fini(struct drm_device *dev);
int nv50_evo_dmaobj_new(struct nouveau_channel *, u32 class, u32 name,
u32 tile_flags, u32 magic_flags,
u32 offset, u32 limit);
#define NV50_EVO_UPDATE 0x00000080 #define NV50_EVO_UPDATE 0x00000080
#define NV50_EVO_UNK84 0x00000084 #define NV50_EVO_UNK84 0x00000084
#define NV50_EVO_UNK84_NOTIFY 0x40000000 #define NV50_EVO_UNK84_NOTIFY 0x40000000
...@@ -119,5 +113,7 @@ int nv50_evo_dmaobj_new(struct nouveau_channel *, u32 class, u32 name, ...@@ -119,5 +113,7 @@ int nv50_evo_dmaobj_new(struct nouveau_channel *, u32 class, u32 name,
/* Both of these are needed, otherwise nothing happens. */ /* Both of these are needed, otherwise nothing happens. */
#define NV50_EVO_CRTC_SCALE_RES1 0x000008d8 #define NV50_EVO_CRTC_SCALE_RES1 0x000008d8
#define NV50_EVO_CRTC_SCALE_RES2 0x000008dc #define NV50_EVO_CRTC_SCALE_RES2 0x000008dc
#define NV50_EVO_CRTC_UNK900 0x00000900
#define NV50_EVO_CRTC_UNK904 0x00000904
#endif #endif
...@@ -8,31 +8,61 @@ struct nv50_fb_priv { ...@@ -8,31 +8,61 @@ struct nv50_fb_priv {
dma_addr_t r100c08; dma_addr_t r100c08;
}; };
static void
nv50_fb_destroy(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
struct nv50_fb_priv *priv = pfb->priv;
if (drm_mm_initialized(&pfb->tag_heap))
drm_mm_takedown(&pfb->tag_heap);
if (priv->r100c08_page) {
pci_unmap_page(dev->pdev, priv->r100c08, PAGE_SIZE,
PCI_DMA_BIDIRECTIONAL);
__free_page(priv->r100c08_page);
}
kfree(priv);
pfb->priv = NULL;
}
static int static int
nv50_fb_create(struct drm_device *dev) nv50_fb_create(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
struct nv50_fb_priv *priv; struct nv50_fb_priv *priv;
u32 tagmem;
int ret;
priv = kzalloc(sizeof(*priv), GFP_KERNEL); priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
pfb->priv = priv;
priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (!priv->r100c08_page) { if (!priv->r100c08_page) {
kfree(priv); nv50_fb_destroy(dev);
return -ENOMEM; return -ENOMEM;
} }
priv->r100c08 = pci_map_page(dev->pdev, priv->r100c08_page, 0, priv->r100c08 = pci_map_page(dev->pdev, priv->r100c08_page, 0,
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
if (pci_dma_mapping_error(dev->pdev, priv->r100c08)) { if (pci_dma_mapping_error(dev->pdev, priv->r100c08)) {
__free_page(priv->r100c08_page); nv50_fb_destroy(dev);
kfree(priv);
return -EFAULT; return -EFAULT;
} }
dev_priv->engine.fb.priv = priv; tagmem = nv_rd32(dev, 0x100320);
NV_DEBUG(dev, "%d tags available\n", tagmem);
ret = drm_mm_init(&pfb->tag_heap, 0, tagmem);
if (ret) {
nv50_fb_destroy(dev);
return ret;
}
return 0; return 0;
} }
...@@ -81,18 +111,7 @@ nv50_fb_init(struct drm_device *dev) ...@@ -81,18 +111,7 @@ nv50_fb_init(struct drm_device *dev)
void void
nv50_fb_takedown(struct drm_device *dev) nv50_fb_takedown(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; nv50_fb_destroy(dev);
struct nv50_fb_priv *priv;
priv = dev_priv->engine.fb.priv;
if (!priv)
return;
dev_priv->engine.fb.priv = NULL;
pci_unmap_page(dev->pdev, priv->r100c08, PAGE_SIZE,
PCI_DMA_BIDIRECTIONAL);
__free_page(priv->r100c08_page);
kfree(priv);
} }
void void
......
...@@ -149,6 +149,7 @@ nv50_fifo_init_regs(struct drm_device *dev) ...@@ -149,6 +149,7 @@ nv50_fifo_init_regs(struct drm_device *dev)
nv_wr32(dev, 0x3204, 0); nv_wr32(dev, 0x3204, 0);
nv_wr32(dev, 0x3210, 0); nv_wr32(dev, 0x3210, 0);
nv_wr32(dev, 0x3270, 0); nv_wr32(dev, 0x3270, 0);
nv_wr32(dev, 0x2044, 0x01003fff);
/* Enable dummy channels setup by nv50_instmem.c */ /* Enable dummy channels setup by nv50_instmem.c */
nv50_fifo_channel_enable(dev, 0); nv50_fifo_channel_enable(dev, 0);
...@@ -273,7 +274,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan) ...@@ -273,7 +274,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
nv_wo32(ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | nv_wo32(ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
(4 << 24) /* SEARCH_FULL */ | (4 << 24) /* SEARCH_FULL */ |
(chan->ramht->gpuobj->cinst >> 4)); (chan->ramht->gpuobj->cinst >> 4));
nv_wo32(ramfc, 0x44, 0x2101ffff); nv_wo32(ramfc, 0x44, 0x01003fff);
nv_wo32(ramfc, 0x60, 0x7fffffff); nv_wo32(ramfc, 0x60, 0x7fffffff);
nv_wo32(ramfc, 0x40, 0x00000000); nv_wo32(ramfc, 0x40, 0x00000000);
nv_wo32(ramfc, 0x7c, 0x30000001); nv_wo32(ramfc, 0x7c, 0x30000001);
......
...@@ -137,6 +137,7 @@ nv50_gpio_irq_unregister(struct drm_device *dev, enum dcb_gpio_tag tag, ...@@ -137,6 +137,7 @@ nv50_gpio_irq_unregister(struct drm_device *dev, enum dcb_gpio_tag tag,
struct nv50_gpio_priv *priv = pgpio->priv; struct nv50_gpio_priv *priv = pgpio->priv;
struct nv50_gpio_handler *gpioh, *tmp; struct nv50_gpio_handler *gpioh, *tmp;
struct dcb_gpio_entry *gpio; struct dcb_gpio_entry *gpio;
LIST_HEAD(tofree);
unsigned long flags; unsigned long flags;
gpio = nouveau_bios_gpio_entry(dev, tag); gpio = nouveau_bios_gpio_entry(dev, tag);
...@@ -149,10 +150,14 @@ nv50_gpio_irq_unregister(struct drm_device *dev, enum dcb_gpio_tag tag, ...@@ -149,10 +150,14 @@ nv50_gpio_irq_unregister(struct drm_device *dev, enum dcb_gpio_tag tag,
gpioh->handler != handler || gpioh->handler != handler ||
gpioh->data != data) gpioh->data != data)
continue; continue;
list_del(&gpioh->head); list_move(&gpioh->head, &tofree);
kfree(gpioh);
} }
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
list_for_each_entry_safe(gpioh, tmp, &tofree, head) {
flush_work_sync(&gpioh->work);
kfree(gpioh);
}
} }
bool bool
...@@ -205,7 +210,6 @@ nv50_gpio_init(struct drm_device *dev) ...@@ -205,7 +210,6 @@ nv50_gpio_init(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
struct nv50_gpio_priv *priv;
int ret; int ret;
if (!pgpio->priv) { if (!pgpio->priv) {
...@@ -213,7 +217,6 @@ nv50_gpio_init(struct drm_device *dev) ...@@ -213,7 +217,6 @@ nv50_gpio_init(struct drm_device *dev)
if (ret) if (ret)
return ret; return ret;
} }
priv = pgpio->priv;
/* disable, and ack any pending gpio interrupts */ /* disable, and ack any pending gpio interrupts */
nv_wr32(dev, 0xe050, 0x00000000); nv_wr32(dev, 0xe050, 0x00000000);
...@@ -293,7 +296,7 @@ nv50_gpio_isr(struct drm_device *dev) ...@@ -293,7 +296,7 @@ nv50_gpio_isr(struct drm_device *dev)
continue; continue;
gpioh->inhibit = true; gpioh->inhibit = true;
queue_work(dev_priv->wq, &gpioh->work); schedule_work(&gpioh->work);
} }
spin_unlock(&priv->lock); spin_unlock(&priv->lock);
} }
...@@ -95,13 +95,41 @@ nv50_graph_init_regs__nv(struct drm_device *dev) ...@@ -95,13 +95,41 @@ nv50_graph_init_regs__nv(struct drm_device *dev)
} }
static void static void
nv50_graph_init_regs(struct drm_device *dev) nv50_graph_init_zcull(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private;
int i;
NV_DEBUG(dev, "\n"); NV_DEBUG(dev, "\n");
nv_wr32(dev, NV04_PGRAPH_DEBUG_3, switch (dev_priv->chipset & 0xf0) {
(1 << 2) /* HW_CONTEXT_SWITCH_ENABLED */); case 0x50:
nv_wr32(dev, 0x402ca8, 0x800); case 0x80:
case 0x90:
nv_wr32(dev, 0x402ca8, 0x00000800);
break;
case 0xa0:
default:
nv_wr32(dev, 0x402cc0, 0x00000000);
if (dev_priv->chipset == 0xa0 ||
dev_priv->chipset == 0xaa ||
dev_priv->chipset == 0xac) {
nv_wr32(dev, 0x402ca8, 0x00000802);
} else {
nv_wr32(dev, 0x402cc0, 0x00000000);
nv_wr32(dev, 0x402ca8, 0x00000002);
}
break;
}
/* zero out zcull regions */
for (i = 0; i < 8; i++) {
nv_wr32(dev, 0x402c20 + (i * 8), 0x00000000);
nv_wr32(dev, 0x402c24 + (i * 8), 0x00000000);
nv_wr32(dev, 0x402c28 + (i * 8), 0x00000000);
nv_wr32(dev, 0x402c2c + (i * 8), 0x00000000);
}
} }
static int static int
...@@ -136,6 +164,7 @@ nv50_graph_init_ctxctl(struct drm_device *dev) ...@@ -136,6 +164,7 @@ nv50_graph_init_ctxctl(struct drm_device *dev)
} }
kfree(cp); kfree(cp);
nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */
nv_wr32(dev, 0x400320, 4); nv_wr32(dev, 0x400320, 4);
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0); nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0);
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, 0); nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, 0);
...@@ -151,7 +180,7 @@ nv50_graph_init(struct drm_device *dev) ...@@ -151,7 +180,7 @@ nv50_graph_init(struct drm_device *dev)
nv50_graph_init_reset(dev); nv50_graph_init_reset(dev);
nv50_graph_init_regs__nv(dev); nv50_graph_init_regs__nv(dev);
nv50_graph_init_regs(dev); nv50_graph_init_zcull(dev);
ret = nv50_graph_init_ctxctl(dev); ret = nv50_graph_init_ctxctl(dev);
if (ret) if (ret)
...@@ -409,12 +438,7 @@ static int ...@@ -409,12 +438,7 @@ static int
nv50_graph_nvsw_mthd_page_flip(struct nouveau_channel *chan, nv50_graph_nvsw_mthd_page_flip(struct nouveau_channel *chan,
u32 class, u32 mthd, u32 data) u32 class, u32 mthd, u32 data)
{ {
struct nouveau_page_flip_state s; nouveau_finish_page_flip(chan, NULL);
if (!nouveau_finish_page_flip(chan, &s)) {
/* XXX - Do something here */
}
return 0; return 0;
} }
...@@ -912,10 +936,10 @@ nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid ...@@ -912,10 +936,10 @@ nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid
printk("\n"); printk("\n");
NV_INFO(dev, "PGRAPH - TRAP_CCACHE %08x %08x %08x %08x" NV_INFO(dev, "PGRAPH - TRAP_CCACHE %08x %08x %08x %08x"
" %08x %08x %08x\n", " %08x %08x %08x\n",
nv_rd32(dev, 0x405800), nv_rd32(dev, 0x405804), nv_rd32(dev, 0x405000), nv_rd32(dev, 0x405004),
nv_rd32(dev, 0x405808), nv_rd32(dev, 0x40580c), nv_rd32(dev, 0x405008), nv_rd32(dev, 0x40500c),
nv_rd32(dev, 0x405810), nv_rd32(dev, 0x405814), nv_rd32(dev, 0x405010), nv_rd32(dev, 0x405014),
nv_rd32(dev, 0x40581c)); nv_rd32(dev, 0x40501c));
} }
......
...@@ -300,7 +300,7 @@ nv50_instmem_resume(struct drm_device *dev) ...@@ -300,7 +300,7 @@ nv50_instmem_resume(struct drm_device *dev)
} }
struct nv50_gpuobj_node { struct nv50_gpuobj_node {
struct nouveau_vram *vram; struct nouveau_mem *vram;
struct nouveau_vma chan_vma; struct nouveau_vma chan_vma;
u32 align; u32 align;
}; };
......
...@@ -41,8 +41,7 @@ nv50_sor_disconnect(struct drm_encoder *encoder) ...@@ -41,8 +41,7 @@ nv50_sor_disconnect(struct drm_encoder *encoder)
{ {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *evo = nv50_display(dev)->master;
struct nouveau_channel *evo = dev_priv->evo;
int ret; int ret;
if (!nv_encoder->crtc) if (!nv_encoder->crtc)
...@@ -184,8 +183,7 @@ static void ...@@ -184,8 +183,7 @@ static void
nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
{ {
struct drm_nouveau_private *dev_priv = encoder->dev->dev_private; struct nouveau_channel *evo = nv50_display(encoder->dev)->master;
struct nouveau_channel *evo = dev_priv->evo;
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc); struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc);
......
...@@ -31,7 +31,6 @@ void ...@@ -31,7 +31,6 @@ void
nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde,
struct nouveau_gpuobj *pgt[2]) struct nouveau_gpuobj *pgt[2])
{ {
struct drm_nouveau_private *dev_priv = pgd->dev->dev_private;
u64 phys = 0xdeadcafe00000000ULL; u64 phys = 0xdeadcafe00000000ULL;
u32 coverage = 0; u32 coverage = 0;
...@@ -58,10 +57,9 @@ nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, ...@@ -58,10 +57,9 @@ nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde,
} }
static inline u64 static inline u64
nv50_vm_addr(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, nv50_vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target)
u64 phys, u32 memtype, u32 target)
{ {
struct drm_nouveau_private *dev_priv = pgt->dev->dev_private; struct drm_nouveau_private *dev_priv = vma->vm->dev->dev_private;
phys |= 1; /* present */ phys |= 1; /* present */
phys |= (u64)memtype << 40; phys |= (u64)memtype << 40;
...@@ -85,12 +83,13 @@ nv50_vm_addr(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, ...@@ -85,12 +83,13 @@ nv50_vm_addr(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
void void
nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
struct nouveau_vram *mem, u32 pte, u32 cnt, u64 phys) struct nouveau_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta)
{ {
u32 comp = (mem->memtype & 0x180) >> 7;
u32 block; u32 block;
int i; int i;
phys = nv50_vm_addr(vma, pgt, phys, mem->memtype, 0); phys = nv50_vm_addr(vma, phys, mem->memtype, 0);
pte <<= 3; pte <<= 3;
cnt <<= 3; cnt <<= 3;
...@@ -107,6 +106,11 @@ nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, ...@@ -107,6 +106,11 @@ nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
phys += block << (vma->node->type - 3); phys += block << (vma->node->type - 3);
cnt -= block; cnt -= block;
if (comp) {
u32 tag = mem->tag->start + ((delta >> 16) * comp);
offset_h |= (tag << 17);
delta += block << (vma->node->type - 3);
}
while (block) { while (block) {
nv_wo32(pgt, pte + 0, offset_l); nv_wo32(pgt, pte + 0, offset_l);
...@@ -119,11 +123,11 @@ nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, ...@@ -119,11 +123,11 @@ nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
void void
nv50_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, nv50_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
u32 pte, dma_addr_t *list, u32 cnt) struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
{ {
pte <<= 3; pte <<= 3;
while (cnt--) { while (cnt--) {
u64 phys = nv50_vm_addr(vma, pgt, (u64)*list++, 0, 2); u64 phys = nv50_vm_addr(vma, (u64)*list++, mem->memtype, 2);
nv_wo32(pgt, pte + 0, lower_32_bits(phys)); nv_wo32(pgt, pte + 0, lower_32_bits(phys));
nv_wo32(pgt, pte + 4, upper_32_bits(phys)); nv_wo32(pgt, pte + 4, upper_32_bits(phys));
pte += 8; pte += 8;
......
...@@ -48,42 +48,49 @@ nv50_vram_flags_valid(struct drm_device *dev, u32 tile_flags) ...@@ -48,42 +48,49 @@ nv50_vram_flags_valid(struct drm_device *dev, u32 tile_flags)
} }
void void
nv50_vram_del(struct drm_device *dev, struct nouveau_vram **pvram) nv50_vram_del(struct drm_device *dev, struct nouveau_mem **pmem)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM]; struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM];
struct nouveau_mm *mm = man->priv; struct nouveau_mm *mm = man->priv;
struct nouveau_mm_node *this; struct nouveau_mm_node *this;
struct nouveau_vram *vram; struct nouveau_mem *mem;
vram = *pvram; mem = *pmem;
*pvram = NULL; *pmem = NULL;
if (unlikely(vram == NULL)) if (unlikely(mem == NULL))
return; return;
mutex_lock(&mm->mutex); mutex_lock(&mm->mutex);
while (!list_empty(&vram->regions)) { while (!list_empty(&mem->regions)) {
this = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry); this = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
list_del(&this->rl_entry); list_del(&this->rl_entry);
nouveau_mm_put(mm, this); nouveau_mm_put(mm, this);
} }
if (mem->tag) {
drm_mm_put_block(mem->tag);
mem->tag = NULL;
}
mutex_unlock(&mm->mutex); mutex_unlock(&mm->mutex);
kfree(vram); kfree(mem);
} }
int int
nv50_vram_new(struct drm_device *dev, u64 size, u32 align, u32 size_nc, nv50_vram_new(struct drm_device *dev, u64 size, u32 align, u32 size_nc,
u32 type, struct nouveau_vram **pvram) u32 memtype, struct nouveau_mem **pmem)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM]; struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM];
struct nouveau_mm *mm = man->priv; struct nouveau_mm *mm = man->priv;
struct nouveau_mm_node *r; struct nouveau_mm_node *r;
struct nouveau_vram *vram; struct nouveau_mem *mem;
int comp = (memtype & 0x300) >> 8;
int type = (memtype & 0x07f);
int ret; int ret;
if (!types[type]) if (!types[type])
...@@ -92,32 +99,46 @@ nv50_vram_new(struct drm_device *dev, u64 size, u32 align, u32 size_nc, ...@@ -92,32 +99,46 @@ nv50_vram_new(struct drm_device *dev, u64 size, u32 align, u32 size_nc,
align >>= 12; align >>= 12;
size_nc >>= 12; size_nc >>= 12;
vram = kzalloc(sizeof(*vram), GFP_KERNEL); mem = kzalloc(sizeof(*mem), GFP_KERNEL);
if (!vram) if (!mem)
return -ENOMEM; return -ENOMEM;
INIT_LIST_HEAD(&vram->regions);
vram->dev = dev_priv->dev;
vram->memtype = type;
vram->size = size;
mutex_lock(&mm->mutex); mutex_lock(&mm->mutex);
if (comp) {
if (align == 16) {
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
int n = (size >> 4) * comp;
mem->tag = drm_mm_search_free(&pfb->tag_heap, n, 0, 0);
if (mem->tag)
mem->tag = drm_mm_get_block(mem->tag, n, 0);
}
if (unlikely(!mem->tag))
comp = 0;
}
INIT_LIST_HEAD(&mem->regions);
mem->dev = dev_priv->dev;
mem->memtype = (comp << 7) | type;
mem->size = size;
do { do {
ret = nouveau_mm_get(mm, types[type], size, size_nc, align, &r); ret = nouveau_mm_get(mm, types[type], size, size_nc, align, &r);
if (ret) { if (ret) {
mutex_unlock(&mm->mutex); mutex_unlock(&mm->mutex);
nv50_vram_del(dev, &vram); nv50_vram_del(dev, &mem);
return ret; return ret;
} }
list_add_tail(&r->rl_entry, &vram->regions); list_add_tail(&r->rl_entry, &mem->regions);
size -= r->length; size -= r->length;
} while (size); } while (size);
mutex_unlock(&mm->mutex); mutex_unlock(&mm->mutex);
r = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry); r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
vram->offset = (u64)r->offset << 12; mem->offset = (u64)r->offset << 12;
*pvram = vram; *pmem = mem;
return 0; return 0;
} }
......
...@@ -116,7 +116,7 @@ nvc0_fifo_create_context(struct nouveau_channel *chan) ...@@ -116,7 +116,7 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
/* allocate vram for control regs, map into polling area */ /* allocate vram for control regs, map into polling area */
ret = nouveau_bo_new(dev, NULL, 0x1000, 0, TTM_PL_FLAG_VRAM, ret = nouveau_bo_new(dev, NULL, 0x1000, 0, TTM_PL_FLAG_VRAM,
0, 0, true, true, &fifoch->user); 0, 0, &fifoch->user);
if (ret) if (ret)
goto error; goto error;
...@@ -418,6 +418,12 @@ nvc0_fifo_isr(struct drm_device *dev) ...@@ -418,6 +418,12 @@ nvc0_fifo_isr(struct drm_device *dev)
{ {
u32 stat = nv_rd32(dev, 0x002100); u32 stat = nv_rd32(dev, 0x002100);
if (stat & 0x00000100) {
NV_INFO(dev, "PFIFO: unknown status 0x00000100\n");
nv_wr32(dev, 0x002100, 0x00000100);
stat &= ~0x00000100;
}
if (stat & 0x10000000) { if (stat & 0x10000000) {
u32 units = nv_rd32(dev, 0x00259c); u32 units = nv_rd32(dev, 0x00259c);
u32 u = units; u32 u = units;
...@@ -446,10 +452,15 @@ nvc0_fifo_isr(struct drm_device *dev) ...@@ -446,10 +452,15 @@ nvc0_fifo_isr(struct drm_device *dev)
stat &= ~0x20000000; stat &= ~0x20000000;
} }
if (stat & 0x40000000) {
NV_INFO(dev, "PFIFO: unknown status 0x40000000\n");
nv_mask(dev, 0x002a00, 0x00000000, 0x00000000);
stat &= ~0x40000000;
}
if (stat) { if (stat) {
NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat); NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat);
nv_wr32(dev, 0x002100, stat); nv_wr32(dev, 0x002100, stat);
nv_wr32(dev, 0x002140, 0);
} }
nv_wr32(dev, 0x2140, 0);
} }
...@@ -298,6 +298,14 @@ nvc0_graph_takedown(struct drm_device *dev) ...@@ -298,6 +298,14 @@ nvc0_graph_takedown(struct drm_device *dev)
nvc0_graph_destroy(dev); nvc0_graph_destroy(dev);
} }
static int
nvc0_graph_mthd_page_flip(struct nouveau_channel *chan,
u32 class, u32 mthd, u32 data)
{
nouveau_finish_page_flip(chan, NULL);
return 0;
}
static int static int
nvc0_graph_create(struct drm_device *dev) nvc0_graph_create(struct drm_device *dev)
{ {
...@@ -395,6 +403,7 @@ nvc0_graph_create(struct drm_device *dev) ...@@ -395,6 +403,7 @@ nvc0_graph_create(struct drm_device *dev)
nouveau_irq_register(dev, 25, nvc0_runk140_isr); nouveau_irq_register(dev, 25, nvc0_runk140_isr);
NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */ NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */ NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip);
NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */ NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */ NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */
return 0; return 0;
...@@ -640,7 +649,6 @@ nvc0_graph_init(struct drm_device *dev) ...@@ -640,7 +649,6 @@ nvc0_graph_init(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nvc0_graph_priv *priv;
int ret; int ret;
dev_priv->engine.graph.accel_blocked = true; dev_priv->engine.graph.accel_blocked = true;
...@@ -665,7 +673,6 @@ nvc0_graph_init(struct drm_device *dev) ...@@ -665,7 +673,6 @@ nvc0_graph_init(struct drm_device *dev)
if (ret) if (ret)
return ret; return ret;
} }
priv = pgraph->priv;
nvc0_graph_init_obj418880(dev); nvc0_graph_init_obj418880(dev);
nvc0_graph_init_regs(dev); nvc0_graph_init_regs(dev);
...@@ -730,9 +737,12 @@ nvc0_graph_isr(struct drm_device *dev) ...@@ -730,9 +737,12 @@ nvc0_graph_isr(struct drm_device *dev)
u32 class = nv_rd32(dev, 0x404200 + (subc * 4)); u32 class = nv_rd32(dev, 0x404200 + (subc * 4));
if (stat & 0x00000010) { if (stat & 0x00000010) {
NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] subc %d " if (nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) {
"class 0x%04x mthd 0x%04x data 0x%08x\n", NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] "
chid, inst, subc, class, mthd, data); "subc %d class 0x%04x mthd 0x%04x "
"data 0x%08x\n",
chid, inst, subc, class, mthd, data);
}
nv_wr32(dev, 0x400100, 0x00000010); nv_wr32(dev, 0x400100, 0x00000010);
stat &= ~0x00000010; stat &= ~0x00000010;
} }
......
...@@ -59,7 +59,7 @@ nvc0_vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target) ...@@ -59,7 +59,7 @@ nvc0_vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target)
void void
nvc0_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, nvc0_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
struct nouveau_vram *mem, u32 pte, u32 cnt, u64 phys) struct nouveau_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta)
{ {
u32 next = 1 << (vma->node->type - 8); u32 next = 1 << (vma->node->type - 8);
...@@ -75,11 +75,11 @@ nvc0_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, ...@@ -75,11 +75,11 @@ nvc0_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
void void
nvc0_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, nvc0_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
u32 pte, dma_addr_t *list, u32 cnt) struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
{ {
pte <<= 3; pte <<= 3;
while (cnt--) { while (cnt--) {
u64 phys = nvc0_vm_addr(vma, *list++, 0, 5); u64 phys = nvc0_vm_addr(vma, *list++, mem->memtype, 5);
nv_wo32(pgt, pte + 0, lower_32_bits(phys)); nv_wo32(pgt, pte + 0, lower_32_bits(phys));
nv_wo32(pgt, pte + 4, upper_32_bits(phys)); nv_wo32(pgt, pte + 4, upper_32_bits(phys));
pte += 8; pte += 8;
......
...@@ -26,64 +26,78 @@ ...@@ -26,64 +26,78 @@
#include "nouveau_drv.h" #include "nouveau_drv.h"
#include "nouveau_mm.h" #include "nouveau_mm.h"
/* 0 = unsupported
* 1 = non-compressed
* 3 = compressed
*/
static const u8 types[256] = {
1, 1, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3,
3, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3,
3, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 3, 0, 3,
3, 0, 3, 3, 3, 3, 3, 0, 0, 3, 0, 3, 0, 3, 3, 0,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 1, 1, 0
};
bool bool
nvc0_vram_flags_valid(struct drm_device *dev, u32 tile_flags) nvc0_vram_flags_valid(struct drm_device *dev, u32 tile_flags)
{ {
switch (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) { u8 memtype = (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) >> 8;
case 0x0000: return likely((types[memtype] == 1));
case 0xfe00:
case 0xdb00:
case 0x1100:
return true;
default:
break;
}
return false;
} }
int int
nvc0_vram_new(struct drm_device *dev, u64 size, u32 align, u32 ncmin, nvc0_vram_new(struct drm_device *dev, u64 size, u32 align, u32 ncmin,
u32 type, struct nouveau_vram **pvram) u32 type, struct nouveau_mem **pmem)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM]; struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM];
struct nouveau_mm *mm = man->priv; struct nouveau_mm *mm = man->priv;
struct nouveau_mm_node *r; struct nouveau_mm_node *r;
struct nouveau_vram *vram; struct nouveau_mem *mem;
int ret; int ret;
size >>= 12; size >>= 12;
align >>= 12; align >>= 12;
ncmin >>= 12; ncmin >>= 12;
vram = kzalloc(sizeof(*vram), GFP_KERNEL); mem = kzalloc(sizeof(*mem), GFP_KERNEL);
if (!vram) if (!mem)
return -ENOMEM; return -ENOMEM;
INIT_LIST_HEAD(&vram->regions); INIT_LIST_HEAD(&mem->regions);
vram->dev = dev_priv->dev; mem->dev = dev_priv->dev;
vram->memtype = type; mem->memtype = (type & 0xff);
vram->size = size; mem->size = size;
mutex_lock(&mm->mutex); mutex_lock(&mm->mutex);
do { do {
ret = nouveau_mm_get(mm, 1, size, ncmin, align, &r); ret = nouveau_mm_get(mm, 1, size, ncmin, align, &r);
if (ret) { if (ret) {
mutex_unlock(&mm->mutex); mutex_unlock(&mm->mutex);
nv50_vram_del(dev, &vram); nv50_vram_del(dev, &mem);
return ret; return ret;
} }
list_add_tail(&r->rl_entry, &vram->regions); list_add_tail(&r->rl_entry, &mem->regions);
size -= r->length; size -= r->length;
} while (size); } while (size);
mutex_unlock(&mm->mutex); mutex_unlock(&mm->mutex);
r = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry); r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
vram->offset = (u64)r->offset << 12; mem->offset = (u64)r->offset << 12;
*pvram = vram; *pmem = mem;
return 0; return 0;
} }
......
...@@ -94,6 +94,7 @@ struct drm_nouveau_setparam { ...@@ -94,6 +94,7 @@ struct drm_nouveau_setparam {
#define NOUVEAU_GEM_DOMAIN_GART (1 << 2) #define NOUVEAU_GEM_DOMAIN_GART (1 << 2)
#define NOUVEAU_GEM_DOMAIN_MAPPABLE (1 << 3) #define NOUVEAU_GEM_DOMAIN_MAPPABLE (1 << 3)
#define NOUVEAU_GEM_TILE_COMP 0x00030000 /* nv50-only */
#define NOUVEAU_GEM_TILE_LAYOUT_MASK 0x0000ff00 #define NOUVEAU_GEM_TILE_LAYOUT_MASK 0x0000ff00
#define NOUVEAU_GEM_TILE_16BPP 0x00000001 #define NOUVEAU_GEM_TILE_16BPP 0x00000001
#define NOUVEAU_GEM_TILE_32BPP 0x00000002 #define NOUVEAU_GEM_TILE_32BPP 0x00000002
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment