diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_state.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 378 |
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"); |