mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 05:41:55 +00:00
6ee738610f
This adds a drm/kms staging non-API stable driver for GPUs from NVIDIA. This driver is a KMS-based driver and requires a compatible nouveau userspace libdrm and nouveau X.org driver. This driver requires firmware files not available in this kernel tree, interested parties can find them via the nouveau project git archive. This driver is reverse engineered, and is in no way supported by nVidia. Support for nearly the complete range of nvidia hw from nv04->g80 (nv50) is available, and the kms driver should support driving nearly all output types (displayport is under development still) along with supporting suspend/resume. This work is all from the upstream nouveau project found at nouveau.freedesktop.org. The original authors list from nouveau git tree is: Anssi Hannula <anssi.hannula@iki.fi> Ben Skeggs <bskeggs@redhat.com> Francisco Jerez <currojerez@riseup.net> Maarten Maathuis <madman2003@gmail.com> Marcin Kościelnicki <koriakin@0x04.net> Matthew Garrett <mjg@redhat.com> Matt Parnell <mparnell@gmail.com> Patrice Mandin <patmandin@gmail.com> Pekka Paalanen <pq@iki.fi> Xavier Chantry <shiningxc@gmail.com> along with project founder Stephane Marchesin <marchesin@icps.u-strasbg.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
209 lines
5.1 KiB
C
209 lines
5.1 KiB
C
#include "drmP.h"
|
|
#include "drm.h"
|
|
#include "nouveau_drv.h"
|
|
|
|
/* returns the size of fifo context */
|
|
static int
|
|
nouveau_fifo_ctx_size(struct drm_device *dev)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
|
|
if (dev_priv->chipset >= 0x40)
|
|
return 128;
|
|
else
|
|
if (dev_priv->chipset >= 0x17)
|
|
return 64;
|
|
|
|
return 32;
|
|
}
|
|
|
|
static void
|
|
nv04_instmem_determine_amount(struct drm_device *dev)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
int i;
|
|
|
|
/* Figure out how much instance memory we need */
|
|
if (dev_priv->card_type >= NV_40) {
|
|
/* We'll want more instance memory than this on some NV4x cards.
|
|
* There's a 16MB aperture to play with that maps onto the end
|
|
* of vram. For now, only reserve a small piece until we know
|
|
* more about what each chipset requires.
|
|
*/
|
|
switch (dev_priv->chipset & 0xf0) {
|
|
case 0x40:
|
|
case 0x47:
|
|
case 0x49:
|
|
case 0x4b:
|
|
dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024);
|
|
break;
|
|
default:
|
|
dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024);
|
|
break;
|
|
}
|
|
} else {
|
|
/*XXX: what *are* the limits on <NV40 cards?
|
|
*/
|
|
dev_priv->ramin_rsvd_vram = (512 * 1024);
|
|
}
|
|
NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10);
|
|
|
|
/* Clear all of it, except the BIOS image that's in the first 64KiB */
|
|
dev_priv->engine.instmem.prepare_access(dev, true);
|
|
for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4)
|
|
nv_wi32(dev, i, 0x00000000);
|
|
dev_priv->engine.instmem.finish_access(dev);
|
|
}
|
|
|
|
static void
|
|
nv04_instmem_configure_fixed_tables(struct drm_device *dev)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_engine *engine = &dev_priv->engine;
|
|
|
|
/* FIFO hash table (RAMHT)
|
|
* use 4k hash table at RAMIN+0x10000
|
|
* TODO: extend the hash table
|
|
*/
|
|
dev_priv->ramht_offset = 0x10000;
|
|
dev_priv->ramht_bits = 9;
|
|
dev_priv->ramht_size = (1 << dev_priv->ramht_bits); /* nr entries */
|
|
dev_priv->ramht_size *= 8; /* 2 32-bit values per entry in RAMHT */
|
|
NV_DEBUG(dev, "RAMHT offset=0x%x, size=%d\n", dev_priv->ramht_offset,
|
|
dev_priv->ramht_size);
|
|
|
|
/* FIFO runout table (RAMRO) - 512k at 0x11200 */
|
|
dev_priv->ramro_offset = 0x11200;
|
|
dev_priv->ramro_size = 512;
|
|
NV_DEBUG(dev, "RAMRO offset=0x%x, size=%d\n", dev_priv->ramro_offset,
|
|
dev_priv->ramro_size);
|
|
|
|
/* FIFO context table (RAMFC)
|
|
* NV40 : Not sure exactly how to position RAMFC on some cards,
|
|
* 0x30002 seems to position it at RAMIN+0x20000 on these
|
|
* cards. RAMFC is 4kb (32 fifos, 128byte entries).
|
|
* Others: Position RAMFC at RAMIN+0x11400
|
|
*/
|
|
dev_priv->ramfc_size = engine->fifo.channels *
|
|
nouveau_fifo_ctx_size(dev);
|
|
switch (dev_priv->card_type) {
|
|
case NV_40:
|
|
dev_priv->ramfc_offset = 0x20000;
|
|
break;
|
|
case NV_30:
|
|
case NV_20:
|
|
case NV_10:
|
|
case NV_04:
|
|
default:
|
|
dev_priv->ramfc_offset = 0x11400;
|
|
break;
|
|
}
|
|
NV_DEBUG(dev, "RAMFC offset=0x%x, size=%d\n", dev_priv->ramfc_offset,
|
|
dev_priv->ramfc_size);
|
|
}
|
|
|
|
int nv04_instmem_init(struct drm_device *dev)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
uint32_t offset;
|
|
int ret = 0;
|
|
|
|
nv04_instmem_determine_amount(dev);
|
|
nv04_instmem_configure_fixed_tables(dev);
|
|
|
|
/* Create a heap to manage RAMIN allocations, we don't allocate
|
|
* the space that was reserved for RAMHT/FC/RO.
|
|
*/
|
|
offset = dev_priv->ramfc_offset + dev_priv->ramfc_size;
|
|
|
|
/* It appears RAMRO (or something?) is controlled by 0x2220/0x2230
|
|
* on certain NV4x chipsets as well as RAMFC. When 0x2230 == 0
|
|
* ("new style" control) the upper 16-bits of 0x2220 points at this
|
|
* other mysterious table that's clobbering important things.
|
|
*
|
|
* We're now pointing this at RAMIN+0x30000 to avoid RAMFC getting
|
|
* smashed to pieces on us, so reserve 0x30000-0x40000 too..
|
|
*/
|
|
if (dev_priv->card_type >= NV_40) {
|
|
if (offset < 0x40000)
|
|
offset = 0x40000;
|
|
}
|
|
|
|
ret = nouveau_mem_init_heap(&dev_priv->ramin_heap,
|
|
offset, dev_priv->ramin_rsvd_vram - offset);
|
|
if (ret) {
|
|
dev_priv->ramin_heap = NULL;
|
|
NV_ERROR(dev, "Failed to init RAMIN heap\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
nv04_instmem_takedown(struct drm_device *dev)
|
|
{
|
|
}
|
|
|
|
int
|
|
nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, uint32_t *sz)
|
|
{
|
|
if (gpuobj->im_backing)
|
|
return -EINVAL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
nv04_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
|
|
if (gpuobj && gpuobj->im_backing) {
|
|
if (gpuobj->im_bound)
|
|
dev_priv->engine.instmem.unbind(dev, gpuobj);
|
|
gpuobj->im_backing = NULL;
|
|
}
|
|
}
|
|
|
|
int
|
|
nv04_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
|
|
{
|
|
if (!gpuobj->im_pramin || gpuobj->im_bound)
|
|
return -EINVAL;
|
|
|
|
gpuobj->im_bound = 1;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
|
|
{
|
|
if (gpuobj->im_bound == 0)
|
|
return -EINVAL;
|
|
|
|
gpuobj->im_bound = 0;
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
nv04_instmem_prepare_access(struct drm_device *dev, bool write)
|
|
{
|
|
}
|
|
|
|
void
|
|
nv04_instmem_finish_access(struct drm_device *dev)
|
|
{
|
|
}
|
|
|
|
int
|
|
nv04_instmem_suspend(struct drm_device *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
nv04_instmem_resume(struct drm_device *dev)
|
|
{
|
|
}
|
|
|