summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nouveau_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_state.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c378
1 files changed, 246 insertions, 132 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index f80c5e0762ff..c2a8511e855a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -87,7 +87,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clocks_get = nv04_pm_clocks_get;
engine->pm.clocks_pre = nv04_pm_clocks_pre;
engine->pm.clocks_set = nv04_pm_clocks_set;
- engine->vram.init = nouveau_mem_detect;
+ engine->vram.init = nv04_fb_vram_init;
engine->vram.takedown = nouveau_stub_takedown;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -134,7 +134,11 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clocks_get = nv04_pm_clocks_get;
engine->pm.clocks_pre = nv04_pm_clocks_pre;
engine->pm.clocks_set = nv04_pm_clocks_set;
- engine->vram.init = nouveau_mem_detect;
+ if (dev_priv->chipset == 0x1a ||
+ dev_priv->chipset == 0x1f)
+ engine->vram.init = nv1a_fb_vram_init;
+ else
+ engine->vram.init = nv10_fb_vram_init;
engine->vram.takedown = nouveau_stub_takedown;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -153,11 +157,11 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.init = nv04_timer_init;
engine->timer.read = nv04_timer_read;
engine->timer.takedown = nv04_timer_takedown;
- engine->fb.init = nv10_fb_init;
- engine->fb.takedown = nv10_fb_takedown;
- engine->fb.init_tile_region = nv10_fb_init_tile_region;
- engine->fb.set_tile_region = nv10_fb_set_tile_region;
- engine->fb.free_tile_region = nv10_fb_free_tile_region;
+ engine->fb.init = nv20_fb_init;
+ engine->fb.takedown = nv20_fb_takedown;
+ engine->fb.init_tile_region = nv20_fb_init_tile_region;
+ engine->fb.set_tile_region = nv20_fb_set_tile_region;
+ engine->fb.free_tile_region = nv20_fb_free_tile_region;
engine->fifo.channels = 32;
engine->fifo.init = nv10_fifo_init;
engine->fifo.takedown = nv04_fifo_fini;
@@ -181,7 +185,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clocks_get = nv04_pm_clocks_get;
engine->pm.clocks_pre = nv04_pm_clocks_pre;
engine->pm.clocks_set = nv04_pm_clocks_set;
- engine->vram.init = nouveau_mem_detect;
+ engine->vram.init = nv20_fb_vram_init;
engine->vram.takedown = nouveau_stub_takedown;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -230,7 +234,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clocks_set = nv04_pm_clocks_set;
engine->pm.voltage_get = nouveau_voltage_gpio_get;
engine->pm.voltage_set = nouveau_voltage_gpio_set;
- engine->vram.init = nouveau_mem_detect;
+ engine->vram.init = nv20_fb_vram_init;
engine->vram.takedown = nouveau_stub_takedown;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -286,7 +290,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.temp_get = nv40_temp_get;
engine->pm.pwm_get = nv40_pm_pwm_get;
engine->pm.pwm_set = nv40_pm_pwm_set;
- engine->vram.init = nouveau_mem_detect;
+ engine->vram.init = nv40_fb_vram_init;
engine->vram.takedown = nouveau_stub_takedown;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -475,6 +479,47 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.voltage_get = nouveau_voltage_gpio_get;
engine->pm.voltage_set = nouveau_voltage_gpio_set;
break;
+ case 0xe0:
+ engine->instmem.init = nvc0_instmem_init;
+ engine->instmem.takedown = nvc0_instmem_takedown;
+ engine->instmem.suspend = nvc0_instmem_suspend;
+ engine->instmem.resume = nvc0_instmem_resume;
+ engine->instmem.get = nv50_instmem_get;
+ engine->instmem.put = nv50_instmem_put;
+ engine->instmem.map = nv50_instmem_map;
+ engine->instmem.unmap = nv50_instmem_unmap;
+ engine->instmem.flush = nv84_instmem_flush;
+ engine->mc.init = nv50_mc_init;
+ engine->mc.takedown = nv50_mc_takedown;
+ engine->timer.init = nv04_timer_init;
+ engine->timer.read = nv04_timer_read;
+ engine->timer.takedown = nv04_timer_takedown;
+ engine->fb.init = nvc0_fb_init;
+ engine->fb.takedown = nvc0_fb_takedown;
+ engine->fifo.channels = 0;
+ engine->fifo.init = nouveau_stub_init;
+ engine->fifo.takedown = nouveau_stub_takedown;
+ engine->fifo.disable = nvc0_fifo_disable;
+ engine->fifo.enable = nvc0_fifo_enable;
+ engine->fifo.reassign = nvc0_fifo_reassign;
+ engine->fifo.unload_context = nouveau_stub_init;
+ engine->display.early_init = nouveau_stub_init;
+ engine->display.late_takedown = nouveau_stub_takedown;
+ engine->display.create = nvd0_display_create;
+ engine->display.destroy = nvd0_display_destroy;
+ engine->display.init = nvd0_display_init;
+ engine->display.fini = nvd0_display_fini;
+ engine->gpio.init = nv50_gpio_init;
+ engine->gpio.fini = nv50_gpio_fini;
+ engine->gpio.drive = nvd0_gpio_drive;
+ engine->gpio.sense = nvd0_gpio_sense;
+ engine->gpio.irq_enable = nv50_gpio_irq_enable;
+ engine->vram.init = nvc0_vram_init;
+ engine->vram.takedown = nv50_vram_fini;
+ engine->vram.get = nvc0_vram_new;
+ engine->vram.put = nv50_vram_del;
+ engine->vram.flags_valid = nvc0_vram_flags_valid;
+ break;
default:
NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset);
return 1;
@@ -548,6 +593,75 @@ static bool nouveau_switcheroo_can_switch(struct pci_dev *pdev)
return can_switch;
}
+static void
+nouveau_card_channel_fini(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->channel)
+ nouveau_channel_put_unlocked(&dev_priv->channel);
+}
+
+static int
+nouveau_card_channel_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_channel *chan;
+ int ret, oclass;
+
+ ret = nouveau_channel_alloc(dev, &chan, NULL, NvDmaFB, NvDmaTT);
+ dev_priv->channel = chan;
+ if (ret)
+ return ret;
+
+ mutex_unlock(&dev_priv->channel->mutex);
+
+ if (dev_priv->card_type <= NV_50) {
+ if (dev_priv->card_type < NV_50)
+ oclass = 0x0039;
+ else
+ oclass = 0x5039;
+
+ ret = nouveau_gpuobj_gr_new(chan, NvM2MF, oclass);
+ if (ret)
+ goto error;
+
+ ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000,
+ &chan->m2mf_ntfy);
+ if (ret)
+ goto error;
+
+ ret = RING_SPACE(chan, 6);
+ if (ret)
+ goto error;
+
+ BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NAME, 1);
+ OUT_RING (chan, NvM2MF);
+ BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 3);
+ OUT_RING (chan, NvNotify0);
+ OUT_RING (chan, chan->vram_handle);
+ OUT_RING (chan, chan->gart_handle);
+ } else
+ if (dev_priv->card_type <= NV_D0) {
+ ret = nouveau_gpuobj_gr_new(chan, 0x9039, 0x9039);
+ if (ret)
+ goto error;
+
+ ret = RING_SPACE(chan, 2);
+ if (ret)
+ goto error;
+
+ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0000, 1);
+ OUT_RING (chan, 0x00009039);
+ }
+
+ FIRE_RING (chan);
+error:
+ if (ret)
+ nouveau_card_channel_fini(dev);
+ return ret;
+}
+
int
nouveau_card_init(struct drm_device *dev)
{
@@ -588,47 +702,45 @@ nouveau_card_init(struct drm_device *dev)
nv_mask(dev, 0x00088080, 0x00000800, 0x00000000);
}
- nouveau_pm_init(dev);
-
- ret = engine->vram.init(dev);
+ /* PMC */
+ ret = engine->mc.init(dev);
if (ret)
goto out_bios;
- ret = nouveau_gpuobj_init(dev);
+ /* PTIMER */
+ ret = engine->timer.init(dev);
if (ret)
- goto out_vram;
+ goto out_mc;
- ret = engine->instmem.init(dev);
+ /* PFB */
+ ret = engine->fb.init(dev);
if (ret)
- goto out_gpuobj;
+ goto out_timer;
- ret = nouveau_mem_vram_init(dev);
+ ret = engine->vram.init(dev);
if (ret)
- goto out_instmem;
+ goto out_fb;
- ret = nouveau_mem_gart_init(dev);
+ /* PGPIO */
+ ret = nouveau_gpio_create(dev);
if (ret)
- goto out_ttmvram;
+ goto out_vram;
- /* PMC */
- ret = engine->mc.init(dev);
+ ret = nouveau_gpuobj_init(dev);
if (ret)
- goto out_gart;
+ goto out_gpio;
- /* PGPIO */
- ret = nouveau_gpio_create(dev);
+ ret = engine->instmem.init(dev);
if (ret)
- goto out_mc;
+ goto out_gpuobj;
- /* PTIMER */
- ret = engine->timer.init(dev);
+ ret = nouveau_mem_vram_init(dev);
if (ret)
- goto out_gpio;
+ goto out_instmem;
- /* PFB */
- ret = engine->fb.init(dev);
+ ret = nouveau_mem_gart_init(dev);
if (ret)
- goto out_timer;
+ goto out_ttmvram;
if (!dev_priv->noaccel) {
switch (dev_priv->card_type) {
@@ -734,18 +846,16 @@ nouveau_card_init(struct drm_device *dev)
goto out_irq;
nouveau_backlight_init(dev);
+ nouveau_pm_init(dev);
- if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
- ret = nouveau_fence_init(dev);
- if (ret)
- goto out_disp;
+ ret = nouveau_fence_init(dev);
+ if (ret)
+ goto out_pm;
- ret = nouveau_channel_alloc(dev, &dev_priv->channel, NULL,
- NvDmaFB, NvDmaTT);
+ if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
+ ret = nouveau_card_channel_init(dev);
if (ret)
goto out_fence;
-
- mutex_unlock(&dev_priv->channel->mutex);
}
if (dev->mode_config.num_crtc) {
@@ -759,10 +869,11 @@ nouveau_card_init(struct drm_device *dev)
return 0;
out_chan:
- nouveau_channel_put_unlocked(&dev_priv->channel);
+ nouveau_card_channel_fini(dev);
out_fence:
nouveau_fence_fini(dev);
-out_disp:
+out_pm:
+ nouveau_pm_fini(dev);
nouveau_backlight_exit(dev);
nouveau_display_destroy(dev);
out_irq:
@@ -779,15 +890,6 @@ out_engine:
dev_priv->eng[e]->destroy(dev,e );
}
}
-
- engine->fb.takedown(dev);
-out_timer:
- engine->timer.takedown(dev);
-out_gpio:
- nouveau_gpio_destroy(dev);
-out_mc:
- engine->mc.takedown(dev);
-out_gart:
nouveau_mem_gart_fini(dev);
out_ttmvram:
nouveau_mem_vram_fini(dev);
@@ -795,10 +897,17 @@ out_instmem:
engine->instmem.takedown(dev);
out_gpuobj:
nouveau_gpuobj_takedown(dev);
+out_gpio:
+ nouveau_gpio_destroy(dev);
out_vram:
engine->vram.takedown(dev);
+out_fb:
+ engine->fb.takedown(dev);
+out_timer:
+ engine->timer.takedown(dev);
+out_mc:
+ engine->mc.takedown(dev);
out_bios:
- nouveau_pm_fini(dev);
nouveau_bios_takedown(dev);
out_display_early:
engine->display.late_takedown(dev);
@@ -818,11 +927,9 @@ static void nouveau_card_takedown(struct drm_device *dev)
nouveau_display_fini(dev);
}
- if (dev_priv->channel) {
- nouveau_channel_put_unlocked(&dev_priv->channel);
- nouveau_fence_fini(dev);
- }
-
+ nouveau_card_channel_fini(dev);
+ nouveau_fence_fini(dev);
+ nouveau_pm_fini(dev);
nouveau_backlight_exit(dev);
nouveau_display_destroy(dev);
@@ -835,11 +942,6 @@ static void nouveau_card_takedown(struct drm_device *dev)
}
}
}
- engine->fb.takedown(dev);
- engine->timer.takedown(dev);
- nouveau_gpio_destroy(dev);
- engine->mc.takedown(dev);
- engine->display.late_takedown(dev);
if (dev_priv->vga_ram) {
nouveau_bo_unpin(dev_priv->vga_ram);
@@ -855,12 +957,17 @@ static void nouveau_card_takedown(struct drm_device *dev)
engine->instmem.takedown(dev);
nouveau_gpuobj_takedown(dev);
- engine->vram.takedown(dev);
- nouveau_irq_fini(dev);
+ nouveau_gpio_destroy(dev);
+ engine->vram.takedown(dev);
+ engine->fb.takedown(dev);
+ engine->timer.takedown(dev);
+ engine->mc.takedown(dev);
- nouveau_pm_fini(dev);
nouveau_bios_takedown(dev);
+ engine->display.late_takedown(dev);
+
+ nouveau_irq_fini(dev);
vga_client_register(dev->pdev, NULL, NULL, NULL);
}
@@ -990,8 +1097,8 @@ static int nouveau_remove_conflicting_drivers(struct drm_device *dev)
int nouveau_load(struct drm_device *dev, unsigned long flags)
{
struct drm_nouveau_private *dev_priv;
- uint32_t reg0, strap;
- resource_size_t mmio_start_offs;
+ unsigned long long offset, length;
+ uint32_t reg0 = ~0, strap;
int ret;
dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
@@ -1002,83 +1109,90 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
dev->dev_private = dev_priv;
dev_priv->dev = dev;
+ pci_set_master(dev->pdev);
+
dev_priv->flags = flags & NOUVEAU_FLAGS;
NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n",
dev->pci_vendor, dev->pci_device, dev->pdev->class);
- /* resource 0 is mmio regs */
- /* resource 1 is linear FB */
- /* resource 2 is RAMIN (mmio regs + 0x1000000) */
- /* resource 6 is bios */
+ /* first up, map the start of mmio and determine the chipset */
+ dev_priv->mmio = ioremap(pci_resource_start(dev->pdev, 0), PAGE_SIZE);
+ if (dev_priv->mmio) {
+#ifdef __BIG_ENDIAN
+ /* put the card into big-endian mode if it's not */
+ if (nv_rd32(dev, NV03_PMC_BOOT_1) != 0x01000001)
+ nv_wr32(dev, NV03_PMC_BOOT_1, 0x01000001);
+ DRM_MEMORYBARRIER();
+#endif
- /* map the mmio regs */
- mmio_start_offs = pci_resource_start(dev->pdev, 0);
- dev_priv->mmio = ioremap(mmio_start_offs, 0x00800000);
- if (!dev_priv->mmio) {
- NV_ERROR(dev, "Unable to initialize the mmio mapping. "
- "Please report your setup to " DRIVER_EMAIL "\n");
+ /* determine chipset and derive architecture from it */
+ reg0 = nv_rd32(dev, NV03_PMC_BOOT_0);
+ if ((reg0 & 0x0f000000) > 0) {
+ dev_priv->chipset = (reg0 & 0xff00000) >> 20;
+ switch (dev_priv->chipset & 0xf0) {
+ case 0x10:
+ case 0x20:
+ case 0x30:
+ dev_priv->card_type = dev_priv->chipset & 0xf0;
+ break;
+ case 0x40:
+ case 0x60:
+ dev_priv->card_type = NV_40;
+ break;
+ case 0x50:
+ case 0x80:
+ case 0x90:
+ case 0xa0:
+ dev_priv->card_type = NV_50;
+ break;
+ case 0xc0:
+ dev_priv->card_type = NV_C0;
+ break;
+ case 0xd0:
+ dev_priv->card_type = NV_D0;
+ break;
+ case 0xe0:
+ dev_priv->card_type = NV_E0;
+ break;
+ default:
+ break;
+ }
+ } else
+ if ((reg0 & 0xff00fff0) == 0x20004000) {
+ if (reg0 & 0x00f00000)
+ dev_priv->chipset = 0x05;
+ else
+ dev_priv->chipset = 0x04;
+ dev_priv->card_type = NV_04;
+ }
+
+ iounmap(dev_priv->mmio);
+ }
+
+ if (!dev_priv->card_type) {
+ NV_ERROR(dev, "unsupported chipset 0x%08x\n", reg0);
ret = -EINVAL;
goto err_priv;
}
- NV_DEBUG(dev, "regs mapped ok at 0x%llx\n",
- (unsigned long long)mmio_start_offs);
-
-#ifdef __BIG_ENDIAN
- /* Put the card in BE mode if it's not */
- if (nv_rd32(dev, NV03_PMC_BOOT_1) != 0x01000001)
- nv_wr32(dev, NV03_PMC_BOOT_1, 0x01000001);
- DRM_MEMORYBARRIER();
-#endif
+ NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
+ dev_priv->card_type, reg0);
- /* Time to determine the card architecture */
- reg0 = nv_rd32(dev, NV03_PMC_BOOT_0);
-
- /* We're dealing with >=NV10 */
- if ((reg0 & 0x0f000000) > 0) {
- /* Bit 27-20 contain the architecture in hex */
- dev_priv->chipset = (reg0 & 0xff00000) >> 20;
- /* NV04 or NV05 */
- } else if ((reg0 & 0xff00fff0) == 0x20004000) {
- if (reg0 & 0x00f00000)
- dev_priv->chipset = 0x05;
- else
- dev_priv->chipset = 0x04;
- } else
- dev_priv->chipset = 0xff;
+ /* map the mmio regs, limiting the amount to preserve vmap space */
+ offset = pci_resource_start(dev->pdev, 0);
+ length = pci_resource_len(dev->pdev, 0);
+ if (dev_priv->card_type < NV_E0)
+ length = min(length, (unsigned long long)0x00800000);
- switch (dev_priv->chipset & 0xf0) {
- case 0x00:
- case 0x10:
- case 0x20:
- case 0x30:
- dev_priv->card_type = dev_priv->chipset & 0xf0;
- break;
- case 0x40:
- case 0x60:
- dev_priv->card_type = NV_40;
- break;
- case 0x50:
- case 0x80:
- case 0x90:
- case 0xa0:
- dev_priv->card_type = NV_50;
- break;
- case 0xc0:
- dev_priv->card_type = NV_C0;
- break;
- case 0xd0:
- dev_priv->card_type = NV_D0;
- break;
- default:
- NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0);
+ dev_priv->mmio = ioremap(offset, length);
+ if (!dev_priv->mmio) {
+ NV_ERROR(dev, "Unable to initialize the mmio mapping. "
+ "Please report your setup to " DRIVER_EMAIL "\n");
ret = -EINVAL;
- goto err_mmio;
+ goto err_priv;
}
-
- NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
- dev_priv->card_type, reg0);
+ NV_DEBUG(dev, "regs mapped ok at 0x%llx\n", offset);
/* determine frequency of timing crystal */
strap = nv_rd32(dev, 0x101000);
@@ -1136,7 +1250,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
}
} else {
dev_priv->ramin_size = 1 * 1024 * 1024;
- dev_priv->ramin = ioremap(mmio_start_offs + NV_RAMIN,
+ dev_priv->ramin = ioremap(offset + NV_RAMIN,
dev_priv->ramin_size);
if (!dev_priv->ramin) {
NV_ERROR(dev, "Failed to map BAR0 PRAMIN.\n");