Path: blob/master/drivers/gpu/drm/nouveau/nouveau_state.c
15112 views
/*1* Copyright 2005 Stephane Marchesin2* Copyright 2008 Stuart Bennett3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the "Software"),7* to deal in the Software without restriction, including without limitation8* the rights to use, copy, modify, merge, publish, distribute, sublicense,9* and/or sell copies of the Software, and to permit persons to whom the10* Software is furnished to do so, subject to the following conditions:11*12* The above copyright notice and this permission notice (including the next13* paragraph) shall be included in all copies or substantial portions of the14* Software.15*16* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR17* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,18* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL19* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR20* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,21* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER22* DEALINGS IN THE SOFTWARE.23*/2425#include <linux/swab.h>26#include <linux/slab.h>27#include "drmP.h"28#include "drm.h"29#include "drm_sarea.h"30#include "drm_crtc_helper.h"31#include <linux/vgaarb.h>32#include <linux/vga_switcheroo.h>3334#include "nouveau_drv.h"35#include "nouveau_drm.h"36#include "nouveau_fbcon.h"37#include "nouveau_ramht.h"38#include "nouveau_pm.h"39#include "nv50_display.h"4041static void nouveau_stub_takedown(struct drm_device *dev) {}42static int nouveau_stub_init(struct drm_device *dev) { return 0; }4344static int nouveau_init_engine_ptrs(struct drm_device *dev)45{46struct drm_nouveau_private *dev_priv = dev->dev_private;47struct nouveau_engine *engine = &dev_priv->engine;4849switch (dev_priv->chipset & 0xf0) {50case 0x00:51engine->instmem.init = nv04_instmem_init;52engine->instmem.takedown = nv04_instmem_takedown;53engine->instmem.suspend = nv04_instmem_suspend;54engine->instmem.resume = nv04_instmem_resume;55engine->instmem.get = nv04_instmem_get;56engine->instmem.put = nv04_instmem_put;57engine->instmem.map = nv04_instmem_map;58engine->instmem.unmap = nv04_instmem_unmap;59engine->instmem.flush = nv04_instmem_flush;60engine->mc.init = nv04_mc_init;61engine->mc.takedown = nv04_mc_takedown;62engine->timer.init = nv04_timer_init;63engine->timer.read = nv04_timer_read;64engine->timer.takedown = nv04_timer_takedown;65engine->fb.init = nv04_fb_init;66engine->fb.takedown = nv04_fb_takedown;67engine->fifo.channels = 16;68engine->fifo.init = nv04_fifo_init;69engine->fifo.takedown = nv04_fifo_fini;70engine->fifo.disable = nv04_fifo_disable;71engine->fifo.enable = nv04_fifo_enable;72engine->fifo.reassign = nv04_fifo_reassign;73engine->fifo.cache_pull = nv04_fifo_cache_pull;74engine->fifo.channel_id = nv04_fifo_channel_id;75engine->fifo.create_context = nv04_fifo_create_context;76engine->fifo.destroy_context = nv04_fifo_destroy_context;77engine->fifo.load_context = nv04_fifo_load_context;78engine->fifo.unload_context = nv04_fifo_unload_context;79engine->display.early_init = nv04_display_early_init;80engine->display.late_takedown = nv04_display_late_takedown;81engine->display.create = nv04_display_create;82engine->display.init = nv04_display_init;83engine->display.destroy = nv04_display_destroy;84engine->gpio.init = nouveau_stub_init;85engine->gpio.takedown = nouveau_stub_takedown;86engine->gpio.get = NULL;87engine->gpio.set = NULL;88engine->gpio.irq_enable = NULL;89engine->pm.clock_get = nv04_pm_clock_get;90engine->pm.clock_pre = nv04_pm_clock_pre;91engine->pm.clock_set = nv04_pm_clock_set;92engine->vram.init = nouveau_mem_detect;93engine->vram.flags_valid = nouveau_mem_flags_valid;94break;95case 0x10:96engine->instmem.init = nv04_instmem_init;97engine->instmem.takedown = nv04_instmem_takedown;98engine->instmem.suspend = nv04_instmem_suspend;99engine->instmem.resume = nv04_instmem_resume;100engine->instmem.get = nv04_instmem_get;101engine->instmem.put = nv04_instmem_put;102engine->instmem.map = nv04_instmem_map;103engine->instmem.unmap = nv04_instmem_unmap;104engine->instmem.flush = nv04_instmem_flush;105engine->mc.init = nv04_mc_init;106engine->mc.takedown = nv04_mc_takedown;107engine->timer.init = nv04_timer_init;108engine->timer.read = nv04_timer_read;109engine->timer.takedown = nv04_timer_takedown;110engine->fb.init = nv10_fb_init;111engine->fb.takedown = nv10_fb_takedown;112engine->fb.init_tile_region = nv10_fb_init_tile_region;113engine->fb.set_tile_region = nv10_fb_set_tile_region;114engine->fb.free_tile_region = nv10_fb_free_tile_region;115engine->fifo.channels = 32;116engine->fifo.init = nv10_fifo_init;117engine->fifo.takedown = nv04_fifo_fini;118engine->fifo.disable = nv04_fifo_disable;119engine->fifo.enable = nv04_fifo_enable;120engine->fifo.reassign = nv04_fifo_reassign;121engine->fifo.cache_pull = nv04_fifo_cache_pull;122engine->fifo.channel_id = nv10_fifo_channel_id;123engine->fifo.create_context = nv10_fifo_create_context;124engine->fifo.destroy_context = nv04_fifo_destroy_context;125engine->fifo.load_context = nv10_fifo_load_context;126engine->fifo.unload_context = nv10_fifo_unload_context;127engine->display.early_init = nv04_display_early_init;128engine->display.late_takedown = nv04_display_late_takedown;129engine->display.create = nv04_display_create;130engine->display.init = nv04_display_init;131engine->display.destroy = nv04_display_destroy;132engine->gpio.init = nouveau_stub_init;133engine->gpio.takedown = nouveau_stub_takedown;134engine->gpio.get = nv10_gpio_get;135engine->gpio.set = nv10_gpio_set;136engine->gpio.irq_enable = NULL;137engine->pm.clock_get = nv04_pm_clock_get;138engine->pm.clock_pre = nv04_pm_clock_pre;139engine->pm.clock_set = nv04_pm_clock_set;140engine->vram.init = nouveau_mem_detect;141engine->vram.flags_valid = nouveau_mem_flags_valid;142break;143case 0x20:144engine->instmem.init = nv04_instmem_init;145engine->instmem.takedown = nv04_instmem_takedown;146engine->instmem.suspend = nv04_instmem_suspend;147engine->instmem.resume = nv04_instmem_resume;148engine->instmem.get = nv04_instmem_get;149engine->instmem.put = nv04_instmem_put;150engine->instmem.map = nv04_instmem_map;151engine->instmem.unmap = nv04_instmem_unmap;152engine->instmem.flush = nv04_instmem_flush;153engine->mc.init = nv04_mc_init;154engine->mc.takedown = nv04_mc_takedown;155engine->timer.init = nv04_timer_init;156engine->timer.read = nv04_timer_read;157engine->timer.takedown = nv04_timer_takedown;158engine->fb.init = nv10_fb_init;159engine->fb.takedown = nv10_fb_takedown;160engine->fb.init_tile_region = nv10_fb_init_tile_region;161engine->fb.set_tile_region = nv10_fb_set_tile_region;162engine->fb.free_tile_region = nv10_fb_free_tile_region;163engine->fifo.channels = 32;164engine->fifo.init = nv10_fifo_init;165engine->fifo.takedown = nv04_fifo_fini;166engine->fifo.disable = nv04_fifo_disable;167engine->fifo.enable = nv04_fifo_enable;168engine->fifo.reassign = nv04_fifo_reassign;169engine->fifo.cache_pull = nv04_fifo_cache_pull;170engine->fifo.channel_id = nv10_fifo_channel_id;171engine->fifo.create_context = nv10_fifo_create_context;172engine->fifo.destroy_context = nv04_fifo_destroy_context;173engine->fifo.load_context = nv10_fifo_load_context;174engine->fifo.unload_context = nv10_fifo_unload_context;175engine->display.early_init = nv04_display_early_init;176engine->display.late_takedown = nv04_display_late_takedown;177engine->display.create = nv04_display_create;178engine->display.init = nv04_display_init;179engine->display.destroy = nv04_display_destroy;180engine->gpio.init = nouveau_stub_init;181engine->gpio.takedown = nouveau_stub_takedown;182engine->gpio.get = nv10_gpio_get;183engine->gpio.set = nv10_gpio_set;184engine->gpio.irq_enable = NULL;185engine->pm.clock_get = nv04_pm_clock_get;186engine->pm.clock_pre = nv04_pm_clock_pre;187engine->pm.clock_set = nv04_pm_clock_set;188engine->vram.init = nouveau_mem_detect;189engine->vram.flags_valid = nouveau_mem_flags_valid;190break;191case 0x30:192engine->instmem.init = nv04_instmem_init;193engine->instmem.takedown = nv04_instmem_takedown;194engine->instmem.suspend = nv04_instmem_suspend;195engine->instmem.resume = nv04_instmem_resume;196engine->instmem.get = nv04_instmem_get;197engine->instmem.put = nv04_instmem_put;198engine->instmem.map = nv04_instmem_map;199engine->instmem.unmap = nv04_instmem_unmap;200engine->instmem.flush = nv04_instmem_flush;201engine->mc.init = nv04_mc_init;202engine->mc.takedown = nv04_mc_takedown;203engine->timer.init = nv04_timer_init;204engine->timer.read = nv04_timer_read;205engine->timer.takedown = nv04_timer_takedown;206engine->fb.init = nv30_fb_init;207engine->fb.takedown = nv30_fb_takedown;208engine->fb.init_tile_region = nv30_fb_init_tile_region;209engine->fb.set_tile_region = nv10_fb_set_tile_region;210engine->fb.free_tile_region = nv30_fb_free_tile_region;211engine->fifo.channels = 32;212engine->fifo.init = nv10_fifo_init;213engine->fifo.takedown = nv04_fifo_fini;214engine->fifo.disable = nv04_fifo_disable;215engine->fifo.enable = nv04_fifo_enable;216engine->fifo.reassign = nv04_fifo_reassign;217engine->fifo.cache_pull = nv04_fifo_cache_pull;218engine->fifo.channel_id = nv10_fifo_channel_id;219engine->fifo.create_context = nv10_fifo_create_context;220engine->fifo.destroy_context = nv04_fifo_destroy_context;221engine->fifo.load_context = nv10_fifo_load_context;222engine->fifo.unload_context = nv10_fifo_unload_context;223engine->display.early_init = nv04_display_early_init;224engine->display.late_takedown = nv04_display_late_takedown;225engine->display.create = nv04_display_create;226engine->display.init = nv04_display_init;227engine->display.destroy = nv04_display_destroy;228engine->gpio.init = nouveau_stub_init;229engine->gpio.takedown = nouveau_stub_takedown;230engine->gpio.get = nv10_gpio_get;231engine->gpio.set = nv10_gpio_set;232engine->gpio.irq_enable = NULL;233engine->pm.clock_get = nv04_pm_clock_get;234engine->pm.clock_pre = nv04_pm_clock_pre;235engine->pm.clock_set = nv04_pm_clock_set;236engine->pm.voltage_get = nouveau_voltage_gpio_get;237engine->pm.voltage_set = nouveau_voltage_gpio_set;238engine->vram.init = nouveau_mem_detect;239engine->vram.flags_valid = nouveau_mem_flags_valid;240break;241case 0x40:242case 0x60:243engine->instmem.init = nv04_instmem_init;244engine->instmem.takedown = nv04_instmem_takedown;245engine->instmem.suspend = nv04_instmem_suspend;246engine->instmem.resume = nv04_instmem_resume;247engine->instmem.get = nv04_instmem_get;248engine->instmem.put = nv04_instmem_put;249engine->instmem.map = nv04_instmem_map;250engine->instmem.unmap = nv04_instmem_unmap;251engine->instmem.flush = nv04_instmem_flush;252engine->mc.init = nv40_mc_init;253engine->mc.takedown = nv40_mc_takedown;254engine->timer.init = nv04_timer_init;255engine->timer.read = nv04_timer_read;256engine->timer.takedown = nv04_timer_takedown;257engine->fb.init = nv40_fb_init;258engine->fb.takedown = nv40_fb_takedown;259engine->fb.init_tile_region = nv30_fb_init_tile_region;260engine->fb.set_tile_region = nv40_fb_set_tile_region;261engine->fb.free_tile_region = nv30_fb_free_tile_region;262engine->fifo.channels = 32;263engine->fifo.init = nv40_fifo_init;264engine->fifo.takedown = nv04_fifo_fini;265engine->fifo.disable = nv04_fifo_disable;266engine->fifo.enable = nv04_fifo_enable;267engine->fifo.reassign = nv04_fifo_reassign;268engine->fifo.cache_pull = nv04_fifo_cache_pull;269engine->fifo.channel_id = nv10_fifo_channel_id;270engine->fifo.create_context = nv40_fifo_create_context;271engine->fifo.destroy_context = nv04_fifo_destroy_context;272engine->fifo.load_context = nv40_fifo_load_context;273engine->fifo.unload_context = nv40_fifo_unload_context;274engine->display.early_init = nv04_display_early_init;275engine->display.late_takedown = nv04_display_late_takedown;276engine->display.create = nv04_display_create;277engine->display.init = nv04_display_init;278engine->display.destroy = nv04_display_destroy;279engine->gpio.init = nouveau_stub_init;280engine->gpio.takedown = nouveau_stub_takedown;281engine->gpio.get = nv10_gpio_get;282engine->gpio.set = nv10_gpio_set;283engine->gpio.irq_enable = NULL;284engine->pm.clock_get = nv04_pm_clock_get;285engine->pm.clock_pre = nv04_pm_clock_pre;286engine->pm.clock_set = nv04_pm_clock_set;287engine->pm.voltage_get = nouveau_voltage_gpio_get;288engine->pm.voltage_set = nouveau_voltage_gpio_set;289engine->pm.temp_get = nv40_temp_get;290engine->vram.init = nouveau_mem_detect;291engine->vram.flags_valid = nouveau_mem_flags_valid;292break;293case 0x50:294case 0x80: /* gotta love NVIDIA's consistency.. */295case 0x90:296case 0xA0:297engine->instmem.init = nv50_instmem_init;298engine->instmem.takedown = nv50_instmem_takedown;299engine->instmem.suspend = nv50_instmem_suspend;300engine->instmem.resume = nv50_instmem_resume;301engine->instmem.get = nv50_instmem_get;302engine->instmem.put = nv50_instmem_put;303engine->instmem.map = nv50_instmem_map;304engine->instmem.unmap = nv50_instmem_unmap;305if (dev_priv->chipset == 0x50)306engine->instmem.flush = nv50_instmem_flush;307else308engine->instmem.flush = nv84_instmem_flush;309engine->mc.init = nv50_mc_init;310engine->mc.takedown = nv50_mc_takedown;311engine->timer.init = nv04_timer_init;312engine->timer.read = nv04_timer_read;313engine->timer.takedown = nv04_timer_takedown;314engine->fb.init = nv50_fb_init;315engine->fb.takedown = nv50_fb_takedown;316engine->fifo.channels = 128;317engine->fifo.init = nv50_fifo_init;318engine->fifo.takedown = nv50_fifo_takedown;319engine->fifo.disable = nv04_fifo_disable;320engine->fifo.enable = nv04_fifo_enable;321engine->fifo.reassign = nv04_fifo_reassign;322engine->fifo.channel_id = nv50_fifo_channel_id;323engine->fifo.create_context = nv50_fifo_create_context;324engine->fifo.destroy_context = nv50_fifo_destroy_context;325engine->fifo.load_context = nv50_fifo_load_context;326engine->fifo.unload_context = nv50_fifo_unload_context;327engine->fifo.tlb_flush = nv50_fifo_tlb_flush;328engine->display.early_init = nv50_display_early_init;329engine->display.late_takedown = nv50_display_late_takedown;330engine->display.create = nv50_display_create;331engine->display.init = nv50_display_init;332engine->display.destroy = nv50_display_destroy;333engine->gpio.init = nv50_gpio_init;334engine->gpio.takedown = nv50_gpio_fini;335engine->gpio.get = nv50_gpio_get;336engine->gpio.set = nv50_gpio_set;337engine->gpio.irq_register = nv50_gpio_irq_register;338engine->gpio.irq_unregister = nv50_gpio_irq_unregister;339engine->gpio.irq_enable = nv50_gpio_irq_enable;340switch (dev_priv->chipset) {341case 0x84:342case 0x86:343case 0x92:344case 0x94:345case 0x96:346case 0x98:347case 0xa0:348case 0xaa:349case 0xac:350case 0x50:351engine->pm.clock_get = nv50_pm_clock_get;352engine->pm.clock_pre = nv50_pm_clock_pre;353engine->pm.clock_set = nv50_pm_clock_set;354break;355default:356engine->pm.clock_get = nva3_pm_clock_get;357engine->pm.clock_pre = nva3_pm_clock_pre;358engine->pm.clock_set = nva3_pm_clock_set;359break;360}361engine->pm.voltage_get = nouveau_voltage_gpio_get;362engine->pm.voltage_set = nouveau_voltage_gpio_set;363if (dev_priv->chipset >= 0x84)364engine->pm.temp_get = nv84_temp_get;365else366engine->pm.temp_get = nv40_temp_get;367engine->vram.init = nv50_vram_init;368engine->vram.get = nv50_vram_new;369engine->vram.put = nv50_vram_del;370engine->vram.flags_valid = nv50_vram_flags_valid;371break;372case 0xC0:373engine->instmem.init = nvc0_instmem_init;374engine->instmem.takedown = nvc0_instmem_takedown;375engine->instmem.suspend = nvc0_instmem_suspend;376engine->instmem.resume = nvc0_instmem_resume;377engine->instmem.get = nv50_instmem_get;378engine->instmem.put = nv50_instmem_put;379engine->instmem.map = nv50_instmem_map;380engine->instmem.unmap = nv50_instmem_unmap;381engine->instmem.flush = nv84_instmem_flush;382engine->mc.init = nv50_mc_init;383engine->mc.takedown = nv50_mc_takedown;384engine->timer.init = nv04_timer_init;385engine->timer.read = nv04_timer_read;386engine->timer.takedown = nv04_timer_takedown;387engine->fb.init = nvc0_fb_init;388engine->fb.takedown = nvc0_fb_takedown;389engine->fifo.channels = 128;390engine->fifo.init = nvc0_fifo_init;391engine->fifo.takedown = nvc0_fifo_takedown;392engine->fifo.disable = nvc0_fifo_disable;393engine->fifo.enable = nvc0_fifo_enable;394engine->fifo.reassign = nvc0_fifo_reassign;395engine->fifo.channel_id = nvc0_fifo_channel_id;396engine->fifo.create_context = nvc0_fifo_create_context;397engine->fifo.destroy_context = nvc0_fifo_destroy_context;398engine->fifo.load_context = nvc0_fifo_load_context;399engine->fifo.unload_context = nvc0_fifo_unload_context;400engine->display.early_init = nv50_display_early_init;401engine->display.late_takedown = nv50_display_late_takedown;402engine->display.create = nv50_display_create;403engine->display.init = nv50_display_init;404engine->display.destroy = nv50_display_destroy;405engine->gpio.init = nv50_gpio_init;406engine->gpio.takedown = nouveau_stub_takedown;407engine->gpio.get = nv50_gpio_get;408engine->gpio.set = nv50_gpio_set;409engine->gpio.irq_register = nv50_gpio_irq_register;410engine->gpio.irq_unregister = nv50_gpio_irq_unregister;411engine->gpio.irq_enable = nv50_gpio_irq_enable;412engine->vram.init = nvc0_vram_init;413engine->vram.get = nvc0_vram_new;414engine->vram.put = nv50_vram_del;415engine->vram.flags_valid = nvc0_vram_flags_valid;416break;417default:418NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset);419return 1;420}421422return 0;423}424425static unsigned int426nouveau_vga_set_decode(void *priv, bool state)427{428struct drm_device *dev = priv;429struct drm_nouveau_private *dev_priv = dev->dev_private;430431if (dev_priv->chipset >= 0x40)432nv_wr32(dev, 0x88054, state);433else434nv_wr32(dev, 0x1854, state);435436if (state)437return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |438VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;439else440return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;441}442443static int444nouveau_card_init_channel(struct drm_device *dev)445{446struct drm_nouveau_private *dev_priv = dev->dev_private;447int ret;448449ret = nouveau_channel_alloc(dev, &dev_priv->channel,450(struct drm_file *)-2, NvDmaFB, NvDmaTT);451if (ret)452return ret;453454mutex_unlock(&dev_priv->channel->mutex);455return 0;456}457458static void nouveau_switcheroo_set_state(struct pci_dev *pdev,459enum vga_switcheroo_state state)460{461struct drm_device *dev = pci_get_drvdata(pdev);462pm_message_t pmm = { .event = PM_EVENT_SUSPEND };463if (state == VGA_SWITCHEROO_ON) {464printk(KERN_ERR "VGA switcheroo: switched nouveau on\n");465dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;466nouveau_pci_resume(pdev);467drm_kms_helper_poll_enable(dev);468dev->switch_power_state = DRM_SWITCH_POWER_ON;469} else {470printk(KERN_ERR "VGA switcheroo: switched nouveau off\n");471dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;472drm_kms_helper_poll_disable(dev);473nouveau_pci_suspend(pdev, pmm);474dev->switch_power_state = DRM_SWITCH_POWER_OFF;475}476}477478static void nouveau_switcheroo_reprobe(struct pci_dev *pdev)479{480struct drm_device *dev = pci_get_drvdata(pdev);481nouveau_fbcon_output_poll_changed(dev);482}483484static bool nouveau_switcheroo_can_switch(struct pci_dev *pdev)485{486struct drm_device *dev = pci_get_drvdata(pdev);487bool can_switch;488489spin_lock(&dev->count_lock);490can_switch = (dev->open_count == 0);491spin_unlock(&dev->count_lock);492return can_switch;493}494495int496nouveau_card_init(struct drm_device *dev)497{498struct drm_nouveau_private *dev_priv = dev->dev_private;499struct nouveau_engine *engine;500int ret, e = 0;501502vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);503vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,504nouveau_switcheroo_reprobe,505nouveau_switcheroo_can_switch);506507/* Initialise internal driver API hooks */508ret = nouveau_init_engine_ptrs(dev);509if (ret)510goto out;511engine = &dev_priv->engine;512spin_lock_init(&dev_priv->channels.lock);513spin_lock_init(&dev_priv->tile.lock);514spin_lock_init(&dev_priv->context_switch_lock);515spin_lock_init(&dev_priv->vm_lock);516517/* Make the CRTCs and I2C buses accessible */518ret = engine->display.early_init(dev);519if (ret)520goto out;521522/* Parse BIOS tables / Run init tables if card not POSTed */523ret = nouveau_bios_init(dev);524if (ret)525goto out_display_early;526527nouveau_pm_init(dev);528529ret = nouveau_mem_vram_init(dev);530if (ret)531goto out_bios;532533ret = nouveau_gpuobj_init(dev);534if (ret)535goto out_vram;536537ret = engine->instmem.init(dev);538if (ret)539goto out_gpuobj;540541ret = nouveau_mem_gart_init(dev);542if (ret)543goto out_instmem;544545/* PMC */546ret = engine->mc.init(dev);547if (ret)548goto out_gart;549550/* PGPIO */551ret = engine->gpio.init(dev);552if (ret)553goto out_mc;554555/* PTIMER */556ret = engine->timer.init(dev);557if (ret)558goto out_gpio;559560/* PFB */561ret = engine->fb.init(dev);562if (ret)563goto out_timer;564565if (!nouveau_noaccel) {566switch (dev_priv->card_type) {567case NV_04:568nv04_graph_create(dev);569break;570case NV_10:571nv10_graph_create(dev);572break;573case NV_20:574case NV_30:575nv20_graph_create(dev);576break;577case NV_40:578nv40_graph_create(dev);579break;580case NV_50:581nv50_graph_create(dev);582break;583case NV_C0:584nvc0_graph_create(dev);585break;586default:587break;588}589590switch (dev_priv->chipset) {591case 0x84:592case 0x86:593case 0x92:594case 0x94:595case 0x96:596case 0xa0:597nv84_crypt_create(dev);598break;599}600601switch (dev_priv->card_type) {602case NV_50:603switch (dev_priv->chipset) {604case 0xa3:605case 0xa5:606case 0xa8:607case 0xaf:608nva3_copy_create(dev);609break;610}611break;612case NV_C0:613nvc0_copy_create(dev, 0);614nvc0_copy_create(dev, 1);615break;616default:617break;618}619620if (dev_priv->card_type == NV_40)621nv40_mpeg_create(dev);622else623if (dev_priv->card_type == NV_50 &&624(dev_priv->chipset < 0x98 || dev_priv->chipset == 0xa0))625nv50_mpeg_create(dev);626627for (e = 0; e < NVOBJ_ENGINE_NR; e++) {628if (dev_priv->eng[e]) {629ret = dev_priv->eng[e]->init(dev, e);630if (ret)631goto out_engine;632}633}634635/* PFIFO */636ret = engine->fifo.init(dev);637if (ret)638goto out_engine;639}640641ret = engine->display.create(dev);642if (ret)643goto out_fifo;644645ret = drm_vblank_init(dev, nv_two_heads(dev) ? 2 : 1);646if (ret)647goto out_vblank;648649ret = nouveau_irq_init(dev);650if (ret)651goto out_vblank;652653/* what about PVIDEO/PCRTC/PRAMDAC etc? */654655if (dev_priv->eng[NVOBJ_ENGINE_GR]) {656ret = nouveau_fence_init(dev);657if (ret)658goto out_irq;659660ret = nouveau_card_init_channel(dev);661if (ret)662goto out_fence;663}664665nouveau_fbcon_init(dev);666drm_kms_helper_poll_init(dev);667return 0;668669out_fence:670nouveau_fence_fini(dev);671out_irq:672nouveau_irq_fini(dev);673out_vblank:674drm_vblank_cleanup(dev);675engine->display.destroy(dev);676out_fifo:677if (!nouveau_noaccel)678engine->fifo.takedown(dev);679out_engine:680if (!nouveau_noaccel) {681for (e = e - 1; e >= 0; e--) {682if (!dev_priv->eng[e])683continue;684dev_priv->eng[e]->fini(dev, e);685dev_priv->eng[e]->destroy(dev,e );686}687}688689engine->fb.takedown(dev);690out_timer:691engine->timer.takedown(dev);692out_gpio:693engine->gpio.takedown(dev);694out_mc:695engine->mc.takedown(dev);696out_gart:697nouveau_mem_gart_fini(dev);698out_instmem:699engine->instmem.takedown(dev);700out_gpuobj:701nouveau_gpuobj_takedown(dev);702out_vram:703nouveau_mem_vram_fini(dev);704out_bios:705nouveau_pm_fini(dev);706nouveau_bios_takedown(dev);707out_display_early:708engine->display.late_takedown(dev);709out:710vga_client_register(dev->pdev, NULL, NULL, NULL);711return ret;712}713714static void nouveau_card_takedown(struct drm_device *dev)715{716struct drm_nouveau_private *dev_priv = dev->dev_private;717struct nouveau_engine *engine = &dev_priv->engine;718int e;719720if (dev_priv->channel) {721nouveau_fence_fini(dev);722nouveau_channel_put_unlocked(&dev_priv->channel);723}724725if (!nouveau_noaccel) {726engine->fifo.takedown(dev);727for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {728if (dev_priv->eng[e]) {729dev_priv->eng[e]->fini(dev, e);730dev_priv->eng[e]->destroy(dev,e );731}732}733}734engine->fb.takedown(dev);735engine->timer.takedown(dev);736engine->gpio.takedown(dev);737engine->mc.takedown(dev);738engine->display.late_takedown(dev);739740if (dev_priv->vga_ram) {741nouveau_bo_unpin(dev_priv->vga_ram);742nouveau_bo_ref(NULL, &dev_priv->vga_ram);743}744745mutex_lock(&dev->struct_mutex);746ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);747ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);748mutex_unlock(&dev->struct_mutex);749nouveau_mem_gart_fini(dev);750751engine->instmem.takedown(dev);752nouveau_gpuobj_takedown(dev);753nouveau_mem_vram_fini(dev);754755nouveau_irq_fini(dev);756drm_vblank_cleanup(dev);757758nouveau_pm_fini(dev);759nouveau_bios_takedown(dev);760761vga_client_register(dev->pdev, NULL, NULL, NULL);762}763764/* here a client dies, release the stuff that was allocated for its765* file_priv */766void nouveau_preclose(struct drm_device *dev, struct drm_file *file_priv)767{768nouveau_channel_cleanup(dev, file_priv);769}770771/* first module load, setup the mmio/fb mapping */772/* KMS: we need mmio at load time, not when the first drm client opens. */773int nouveau_firstopen(struct drm_device *dev)774{775return 0;776}777778/* if we have an OF card, copy vbios to RAMIN */779static void nouveau_OF_copy_vbios_to_ramin(struct drm_device *dev)780{781#if defined(__powerpc__)782int size, i;783const uint32_t *bios;784struct device_node *dn = pci_device_to_OF_node(dev->pdev);785if (!dn) {786NV_INFO(dev, "Unable to get the OF node\n");787return;788}789790bios = of_get_property(dn, "NVDA,BMP", &size);791if (bios) {792for (i = 0; i < size; i += 4)793nv_wi32(dev, i, bios[i/4]);794NV_INFO(dev, "OF bios successfully copied (%d bytes)\n", size);795} else {796NV_INFO(dev, "Unable to get the OF bios\n");797}798#endif799}800801static struct apertures_struct *nouveau_get_apertures(struct drm_device *dev)802{803struct pci_dev *pdev = dev->pdev;804struct apertures_struct *aper = alloc_apertures(3);805if (!aper)806return NULL;807808aper->ranges[0].base = pci_resource_start(pdev, 1);809aper->ranges[0].size = pci_resource_len(pdev, 1);810aper->count = 1;811812if (pci_resource_len(pdev, 2)) {813aper->ranges[aper->count].base = pci_resource_start(pdev, 2);814aper->ranges[aper->count].size = pci_resource_len(pdev, 2);815aper->count++;816}817818if (pci_resource_len(pdev, 3)) {819aper->ranges[aper->count].base = pci_resource_start(pdev, 3);820aper->ranges[aper->count].size = pci_resource_len(pdev, 3);821aper->count++;822}823824return aper;825}826827static int nouveau_remove_conflicting_drivers(struct drm_device *dev)828{829struct drm_nouveau_private *dev_priv = dev->dev_private;830bool primary = false;831dev_priv->apertures = nouveau_get_apertures(dev);832if (!dev_priv->apertures)833return -ENOMEM;834835#ifdef CONFIG_X86836primary = dev->pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;837#endif838839remove_conflicting_framebuffers(dev_priv->apertures, "nouveaufb", primary);840return 0;841}842843int nouveau_load(struct drm_device *dev, unsigned long flags)844{845struct drm_nouveau_private *dev_priv;846uint32_t reg0;847resource_size_t mmio_start_offs;848int ret;849850dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);851if (!dev_priv) {852ret = -ENOMEM;853goto err_out;854}855dev->dev_private = dev_priv;856dev_priv->dev = dev;857858dev_priv->flags = flags & NOUVEAU_FLAGS;859860NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n",861dev->pci_vendor, dev->pci_device, dev->pdev->class);862863/* resource 0 is mmio regs */864/* resource 1 is linear FB */865/* resource 2 is RAMIN (mmio regs + 0x1000000) */866/* resource 6 is bios */867868/* map the mmio regs */869mmio_start_offs = pci_resource_start(dev->pdev, 0);870dev_priv->mmio = ioremap(mmio_start_offs, 0x00800000);871if (!dev_priv->mmio) {872NV_ERROR(dev, "Unable to initialize the mmio mapping. "873"Please report your setup to " DRIVER_EMAIL "\n");874ret = -EINVAL;875goto err_priv;876}877NV_DEBUG(dev, "regs mapped ok at 0x%llx\n",878(unsigned long long)mmio_start_offs);879880#ifdef __BIG_ENDIAN881/* Put the card in BE mode if it's not */882if (nv_rd32(dev, NV03_PMC_BOOT_1) != 0x01000001)883nv_wr32(dev, NV03_PMC_BOOT_1, 0x01000001);884885DRM_MEMORYBARRIER();886#endif887888/* Time to determine the card architecture */889reg0 = nv_rd32(dev, NV03_PMC_BOOT_0);890dev_priv->stepping = 0; /* XXX: add stepping for pre-NV10? */891892/* We're dealing with >=NV10 */893if ((reg0 & 0x0f000000) > 0) {894/* Bit 27-20 contain the architecture in hex */895dev_priv->chipset = (reg0 & 0xff00000) >> 20;896dev_priv->stepping = (reg0 & 0xff);897/* NV04 or NV05 */898} else if ((reg0 & 0xff00fff0) == 0x20004000) {899if (reg0 & 0x00f00000)900dev_priv->chipset = 0x05;901else902dev_priv->chipset = 0x04;903} else904dev_priv->chipset = 0xff;905906switch (dev_priv->chipset & 0xf0) {907case 0x00:908case 0x10:909case 0x20:910case 0x30:911dev_priv->card_type = dev_priv->chipset & 0xf0;912break;913case 0x40:914case 0x60:915dev_priv->card_type = NV_40;916break;917case 0x50:918case 0x80:919case 0x90:920case 0xa0:921dev_priv->card_type = NV_50;922break;923case 0xc0:924dev_priv->card_type = NV_C0;925break;926default:927NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0);928ret = -EINVAL;929goto err_mmio;930}931932NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",933dev_priv->card_type, reg0);934935ret = nouveau_remove_conflicting_drivers(dev);936if (ret)937goto err_mmio;938939/* Map PRAMIN BAR, or on older cards, the aperture within BAR0 */940if (dev_priv->card_type >= NV_40) {941int ramin_bar = 2;942if (pci_resource_len(dev->pdev, ramin_bar) == 0)943ramin_bar = 3;944945dev_priv->ramin_size = pci_resource_len(dev->pdev, ramin_bar);946dev_priv->ramin =947ioremap(pci_resource_start(dev->pdev, ramin_bar),948dev_priv->ramin_size);949if (!dev_priv->ramin) {950NV_ERROR(dev, "Failed to PRAMIN BAR");951ret = -ENOMEM;952goto err_mmio;953}954} else {955dev_priv->ramin_size = 1 * 1024 * 1024;956dev_priv->ramin = ioremap(mmio_start_offs + NV_RAMIN,957dev_priv->ramin_size);958if (!dev_priv->ramin) {959NV_ERROR(dev, "Failed to map BAR0 PRAMIN.\n");960ret = -ENOMEM;961goto err_mmio;962}963}964965nouveau_OF_copy_vbios_to_ramin(dev);966967/* Special flags */968if (dev->pci_device == 0x01a0)969dev_priv->flags |= NV_NFORCE;970else if (dev->pci_device == 0x01f0)971dev_priv->flags |= NV_NFORCE2;972973/* For kernel modesetting, init card now and bring up fbcon */974ret = nouveau_card_init(dev);975if (ret)976goto err_ramin;977978return 0;979980err_ramin:981iounmap(dev_priv->ramin);982err_mmio:983iounmap(dev_priv->mmio);984err_priv:985kfree(dev_priv);986dev->dev_private = NULL;987err_out:988return ret;989}990991void nouveau_lastclose(struct drm_device *dev)992{993vga_switcheroo_process_delayed_switch();994}995996int nouveau_unload(struct drm_device *dev)997{998struct drm_nouveau_private *dev_priv = dev->dev_private;999struct nouveau_engine *engine = &dev_priv->engine;10001001drm_kms_helper_poll_fini(dev);1002nouveau_fbcon_fini(dev);1003engine->display.destroy(dev);1004nouveau_card_takedown(dev);10051006iounmap(dev_priv->mmio);1007iounmap(dev_priv->ramin);10081009kfree(dev_priv);1010dev->dev_private = NULL;1011return 0;1012}10131014int nouveau_ioctl_getparam(struct drm_device *dev, void *data,1015struct drm_file *file_priv)1016{1017struct drm_nouveau_private *dev_priv = dev->dev_private;1018struct drm_nouveau_getparam *getparam = data;10191020switch (getparam->param) {1021case NOUVEAU_GETPARAM_CHIPSET_ID:1022getparam->value = dev_priv->chipset;1023break;1024case NOUVEAU_GETPARAM_PCI_VENDOR:1025getparam->value = dev->pci_vendor;1026break;1027case NOUVEAU_GETPARAM_PCI_DEVICE:1028getparam->value = dev->pci_device;1029break;1030case NOUVEAU_GETPARAM_BUS_TYPE:1031if (drm_pci_device_is_agp(dev))1032getparam->value = NV_AGP;1033else if (drm_pci_device_is_pcie(dev))1034getparam->value = NV_PCIE;1035else1036getparam->value = NV_PCI;1037break;1038case NOUVEAU_GETPARAM_FB_SIZE:1039getparam->value = dev_priv->fb_available_size;1040break;1041case NOUVEAU_GETPARAM_AGP_SIZE:1042getparam->value = dev_priv->gart_info.aper_size;1043break;1044case NOUVEAU_GETPARAM_VM_VRAM_BASE:1045getparam->value = 0; /* deprecated */1046break;1047case NOUVEAU_GETPARAM_PTIMER_TIME:1048getparam->value = dev_priv->engine.timer.read(dev);1049break;1050case NOUVEAU_GETPARAM_HAS_BO_USAGE:1051getparam->value = 1;1052break;1053case NOUVEAU_GETPARAM_HAS_PAGEFLIP:1054getparam->value = 1;1055break;1056case NOUVEAU_GETPARAM_GRAPH_UNITS:1057/* NV40 and NV50 versions are quite different, but register1058* address is the same. User is supposed to know the card1059* family anyway... */1060if (dev_priv->chipset >= 0x40) {1061getparam->value = nv_rd32(dev, NV40_PMC_GRAPH_UNITS);1062break;1063}1064/* FALLTHRU */1065default:1066NV_DEBUG(dev, "unknown parameter %lld\n", getparam->param);1067return -EINVAL;1068}10691070return 0;1071}10721073int1074nouveau_ioctl_setparam(struct drm_device *dev, void *data,1075struct drm_file *file_priv)1076{1077struct drm_nouveau_setparam *setparam = data;10781079switch (setparam->param) {1080default:1081NV_DEBUG(dev, "unknown parameter %lld\n", setparam->param);1082return -EINVAL;1083}10841085return 0;1086}10871088/* Wait until (value(reg) & mask) == val, up until timeout has hit */1089bool1090nouveau_wait_eq(struct drm_device *dev, uint64_t timeout,1091uint32_t reg, uint32_t mask, uint32_t val)1092{1093struct drm_nouveau_private *dev_priv = dev->dev_private;1094struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;1095uint64_t start = ptimer->read(dev);10961097do {1098if ((nv_rd32(dev, reg) & mask) == val)1099return true;1100} while (ptimer->read(dev) - start < timeout);11011102return false;1103}11041105/* Wait until (value(reg) & mask) != val, up until timeout has hit */1106bool1107nouveau_wait_ne(struct drm_device *dev, uint64_t timeout,1108uint32_t reg, uint32_t mask, uint32_t val)1109{1110struct drm_nouveau_private *dev_priv = dev->dev_private;1111struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;1112uint64_t start = ptimer->read(dev);11131114do {1115if ((nv_rd32(dev, reg) & mask) != val)1116return true;1117} while (ptimer->read(dev) - start < timeout);11181119return false;1120}11211122/* Waits for PGRAPH to go completely idle */1123bool nouveau_wait_for_idle(struct drm_device *dev)1124{1125struct drm_nouveau_private *dev_priv = dev->dev_private;1126uint32_t mask = ~0;11271128if (dev_priv->card_type == NV_40)1129mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL;11301131if (!nv_wait(dev, NV04_PGRAPH_STATUS, mask, 0)) {1132NV_ERROR(dev, "PGRAPH idle timed out with status 0x%08x\n",1133nv_rd32(dev, NV04_PGRAPH_STATUS));1134return false;1135}11361137return true;1138}1139114011411142