mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-18 15:27:57 +07: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>
274 lines
6.9 KiB
C
274 lines
6.9 KiB
C
#include "drmP.h"
|
|
#include "nouveau_drv.h"
|
|
#include "nouveau_dma.h"
|
|
#include "nouveau_fbcon.h"
|
|
|
|
static void
|
|
nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
|
|
{
|
|
struct nouveau_fbcon_par *par = info->par;
|
|
struct drm_device *dev = par->dev;
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_channel *chan = dev_priv->channel;
|
|
|
|
if (info->state != FBINFO_STATE_RUNNING)
|
|
return;
|
|
|
|
if (!(info->flags & FBINFO_HWACCEL_DISABLED) &&
|
|
RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11)) {
|
|
NV_ERROR(dev, "GPU lockup - switching to software fbcon\n");
|
|
|
|
info->flags |= FBINFO_HWACCEL_DISABLED;
|
|
}
|
|
|
|
if (info->flags & FBINFO_HWACCEL_DISABLED) {
|
|
cfb_fillrect(info, rect);
|
|
return;
|
|
}
|
|
|
|
if (rect->rop != ROP_COPY) {
|
|
BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
|
|
OUT_RING(chan, 1);
|
|
}
|
|
BEGIN_RING(chan, NvSub2D, 0x0588, 1);
|
|
OUT_RING(chan, rect->color);
|
|
BEGIN_RING(chan, NvSub2D, 0x0600, 4);
|
|
OUT_RING(chan, rect->dx);
|
|
OUT_RING(chan, rect->dy);
|
|
OUT_RING(chan, rect->dx + rect->width);
|
|
OUT_RING(chan, rect->dy + rect->height);
|
|
if (rect->rop != ROP_COPY) {
|
|
BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
|
|
OUT_RING(chan, 3);
|
|
}
|
|
FIRE_RING(chan);
|
|
}
|
|
|
|
static void
|
|
nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
|
|
{
|
|
struct nouveau_fbcon_par *par = info->par;
|
|
struct drm_device *dev = par->dev;
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_channel *chan = dev_priv->channel;
|
|
|
|
if (info->state != FBINFO_STATE_RUNNING)
|
|
return;
|
|
|
|
if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 12)) {
|
|
NV_ERROR(dev, "GPU lockup - switching to software fbcon\n");
|
|
|
|
info->flags |= FBINFO_HWACCEL_DISABLED;
|
|
}
|
|
|
|
if (info->flags & FBINFO_HWACCEL_DISABLED) {
|
|
cfb_copyarea(info, region);
|
|
return;
|
|
}
|
|
|
|
BEGIN_RING(chan, NvSub2D, 0x0110, 1);
|
|
OUT_RING(chan, 0);
|
|
BEGIN_RING(chan, NvSub2D, 0x08b0, 4);
|
|
OUT_RING(chan, region->dx);
|
|
OUT_RING(chan, region->dy);
|
|
OUT_RING(chan, region->width);
|
|
OUT_RING(chan, region->height);
|
|
BEGIN_RING(chan, NvSub2D, 0x08d0, 4);
|
|
OUT_RING(chan, 0);
|
|
OUT_RING(chan, region->sx);
|
|
OUT_RING(chan, 0);
|
|
OUT_RING(chan, region->sy);
|
|
FIRE_RING(chan);
|
|
}
|
|
|
|
static void
|
|
nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
|
|
{
|
|
struct nouveau_fbcon_par *par = info->par;
|
|
struct drm_device *dev = par->dev;
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_channel *chan = dev_priv->channel;
|
|
uint32_t width, dwords, *data = (uint32_t *)image->data;
|
|
uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
|
|
uint32_t *palette = info->pseudo_palette;
|
|
|
|
if (info->state != FBINFO_STATE_RUNNING)
|
|
return;
|
|
|
|
if (image->depth != 1) {
|
|
cfb_imageblit(info, image);
|
|
return;
|
|
}
|
|
|
|
if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 11)) {
|
|
NV_ERROR(dev, "GPU lockup - switching to software fbcon\n");
|
|
info->flags |= FBINFO_HWACCEL_DISABLED;
|
|
}
|
|
|
|
if (info->flags & FBINFO_HWACCEL_DISABLED) {
|
|
cfb_imageblit(info, image);
|
|
return;
|
|
}
|
|
|
|
width = (image->width + 31) & ~31;
|
|
dwords = (width * image->height) >> 5;
|
|
|
|
BEGIN_RING(chan, NvSub2D, 0x0814, 2);
|
|
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
|
|
info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
|
|
OUT_RING(chan, palette[image->bg_color] | mask);
|
|
OUT_RING(chan, palette[image->fg_color] | mask);
|
|
} else {
|
|
OUT_RING(chan, image->bg_color);
|
|
OUT_RING(chan, image->fg_color);
|
|
}
|
|
BEGIN_RING(chan, NvSub2D, 0x0838, 2);
|
|
OUT_RING(chan, image->width);
|
|
OUT_RING(chan, image->height);
|
|
BEGIN_RING(chan, NvSub2D, 0x0850, 4);
|
|
OUT_RING(chan, 0);
|
|
OUT_RING(chan, image->dx);
|
|
OUT_RING(chan, 0);
|
|
OUT_RING(chan, image->dy);
|
|
|
|
while (dwords) {
|
|
int push = dwords > 2047 ? 2047 : dwords;
|
|
|
|
if (RING_SPACE(chan, push + 1)) {
|
|
NV_ERROR(dev,
|
|
"GPU lockup - switching to software fbcon\n");
|
|
info->flags |= FBINFO_HWACCEL_DISABLED;
|
|
cfb_imageblit(info, image);
|
|
return;
|
|
}
|
|
|
|
dwords -= push;
|
|
|
|
BEGIN_RING(chan, NvSub2D, 0x40000860, push);
|
|
OUT_RINGp(chan, data, push);
|
|
data += push;
|
|
}
|
|
|
|
FIRE_RING(chan);
|
|
}
|
|
|
|
int
|
|
nv50_fbcon_accel_init(struct fb_info *info)
|
|
{
|
|
struct nouveau_fbcon_par *par = info->par;
|
|
struct drm_device *dev = par->dev;
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_channel *chan = dev_priv->channel;
|
|
struct nouveau_gpuobj *eng2d = NULL;
|
|
int ret, format;
|
|
|
|
switch (info->var.bits_per_pixel) {
|
|
case 8:
|
|
format = 0xf3;
|
|
break;
|
|
case 15:
|
|
format = 0xf8;
|
|
break;
|
|
case 16:
|
|
format = 0xe8;
|
|
break;
|
|
case 32:
|
|
switch (info->var.transp.length) {
|
|
case 0: /* depth 24 */
|
|
case 8: /* depth 32, just use 24.. */
|
|
format = 0xe6;
|
|
break;
|
|
case 2: /* depth 30 */
|
|
format = 0xd1;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = nouveau_gpuobj_gr_new(dev_priv->channel, 0x502d, &eng2d);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, Nv2D, eng2d, NULL);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = RING_SPACE(chan, 59);
|
|
if (ret) {
|
|
NV_ERROR(dev, "GPU lockup - switching to software fbcon\n");
|
|
return ret;
|
|
}
|
|
|
|
BEGIN_RING(chan, NvSub2D, 0x0000, 1);
|
|
OUT_RING(chan, Nv2D);
|
|
BEGIN_RING(chan, NvSub2D, 0x0180, 4);
|
|
OUT_RING(chan, NvNotify0);
|
|
OUT_RING(chan, chan->vram_handle);
|
|
OUT_RING(chan, chan->vram_handle);
|
|
OUT_RING(chan, chan->vram_handle);
|
|
BEGIN_RING(chan, NvSub2D, 0x0290, 1);
|
|
OUT_RING(chan, 0);
|
|
BEGIN_RING(chan, NvSub2D, 0x0888, 1);
|
|
OUT_RING(chan, 1);
|
|
BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
|
|
OUT_RING(chan, 3);
|
|
BEGIN_RING(chan, NvSub2D, 0x02a0, 1);
|
|
OUT_RING(chan, 0x55);
|
|
BEGIN_RING(chan, NvSub2D, 0x08c0, 4);
|
|
OUT_RING(chan, 0);
|
|
OUT_RING(chan, 1);
|
|
OUT_RING(chan, 0);
|
|
OUT_RING(chan, 1);
|
|
BEGIN_RING(chan, NvSub2D, 0x0580, 2);
|
|
OUT_RING(chan, 4);
|
|
OUT_RING(chan, format);
|
|
BEGIN_RING(chan, NvSub2D, 0x02e8, 2);
|
|
OUT_RING(chan, 2);
|
|
OUT_RING(chan, 1);
|
|
BEGIN_RING(chan, NvSub2D, 0x0804, 1);
|
|
OUT_RING(chan, format);
|
|
BEGIN_RING(chan, NvSub2D, 0x0800, 1);
|
|
OUT_RING(chan, 1);
|
|
BEGIN_RING(chan, NvSub2D, 0x0808, 3);
|
|
OUT_RING(chan, 0);
|
|
OUT_RING(chan, 0);
|
|
OUT_RING(chan, 0);
|
|
BEGIN_RING(chan, NvSub2D, 0x081c, 1);
|
|
OUT_RING(chan, 1);
|
|
BEGIN_RING(chan, NvSub2D, 0x0840, 4);
|
|
OUT_RING(chan, 0);
|
|
OUT_RING(chan, 1);
|
|
OUT_RING(chan, 0);
|
|
OUT_RING(chan, 1);
|
|
BEGIN_RING(chan, NvSub2D, 0x0200, 2);
|
|
OUT_RING(chan, format);
|
|
OUT_RING(chan, 1);
|
|
BEGIN_RING(chan, NvSub2D, 0x0214, 5);
|
|
OUT_RING(chan, info->fix.line_length);
|
|
OUT_RING(chan, info->var.xres_virtual);
|
|
OUT_RING(chan, info->var.yres_virtual);
|
|
OUT_RING(chan, 0);
|
|
OUT_RING(chan, info->fix.smem_start - dev_priv->fb_phys +
|
|
dev_priv->vm_vram_base);
|
|
BEGIN_RING(chan, NvSub2D, 0x0230, 2);
|
|
OUT_RING(chan, format);
|
|
OUT_RING(chan, 1);
|
|
BEGIN_RING(chan, NvSub2D, 0x0244, 5);
|
|
OUT_RING(chan, info->fix.line_length);
|
|
OUT_RING(chan, info->var.xres_virtual);
|
|
OUT_RING(chan, info->var.yres_virtual);
|
|
OUT_RING(chan, 0);
|
|
OUT_RING(chan, info->fix.smem_start - dev_priv->fb_phys +
|
|
dev_priv->vm_vram_base);
|
|
|
|
info->fbops->fb_fillrect = nv50_fbcon_fillrect;
|
|
info->fbops->fb_copyarea = nv50_fbcon_copyarea;
|
|
info->fbops->fb_imageblit = nv50_fbcon_imageblit;
|
|
return 0;
|
|
}
|
|
|