Commit 4a16dd9d authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/kms: switch to drm fbdev helpers

This removes support for accelerated fbcon rendering, and fixes a number
of races/crashes/issues around suspend/resume/module unload etc.

Losing HW accelerated rendering isn't ideal, but it's been significantly
reduced in performance since the removal of accelerated scrolling in the
kernel anyway - not to mention, can be racey (skips cpu<->gpu sync) from
certain contexts.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 99d0701a
......@@ -54,10 +54,6 @@ nouveau-y += nouveau_bios.o
nouveau-y += nouveau_connector.o
nouveau-y += nouveau_display.o
nouveau-y += nouveau_dp.o
nouveau-y += nouveau_fbcon.o
nouveau-y += nv04_fbcon.o
nouveau-y += nv50_fbcon.o
nouveau-y += nvc0_fbcon.o
include $(src)/dispnv04/Kbuild
include $(src)/dispnv50/Kbuild
......
......@@ -23,6 +23,7 @@
* DEALINGS IN THE SOFTWARE.
*/
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_vblank.h>
......@@ -37,7 +38,6 @@
#include "nouveau_crtc.h"
#include "hw.h"
#include "nvreg.h"
#include "nouveau_fbcon.h"
#include "disp.h"
#include "nouveau_dma.h"
......@@ -915,14 +915,6 @@ nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
int x, int y, enum mode_set_atomic state)
{
struct nouveau_drm *drm = nouveau_drm(crtc->dev);
struct drm_device *dev = drm->dev;
if (state == ENTER_ATOMIC_MODE_SET)
nouveau_fbcon_accel_save_disable(dev);
else
nouveau_fbcon_accel_restore(dev);
return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true);
}
......
......@@ -64,7 +64,6 @@
#include "nouveau_connector.h"
#include "nouveau_encoder.h"
#include "nouveau_fence.h"
#include "nouveau_fbcon.h"
#include <subdev/bios/dp.h>
......@@ -2446,7 +2445,7 @@ nv50_disp_atomic_state_alloc(struct drm_device *dev)
static const struct drm_mode_config_funcs
nv50_disp_func = {
.fb_create = nouveau_user_framebuffer_create,
.output_poll_changed = nouveau_fbcon_output_poll_changed,
.output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = nv50_disp_atomic_check,
.atomic_commit = nv50_disp_atomic_commit,
.atomic_state_alloc = nv50_disp_atomic_state_alloc,
......
......@@ -35,7 +35,6 @@
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "nouveau_fbcon.h"
#include "nouveau_crtc.h"
#include "nouveau_gem.h"
#include "nouveau_connector.h"
......@@ -392,7 +391,7 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
.fb_create = nouveau_user_framebuffer_create,
.output_poll_changed = nouveau_fbcon_output_poll_changed,
.output_poll_changed = drm_fb_helper_output_poll_changed,
};
......@@ -788,6 +787,9 @@ nouveau_display_suspend(struct drm_device *dev, bool runtime)
{
struct nouveau_display *disp = nouveau_display(dev);
/* Disable console. */
drm_fb_helper_set_suspend_unlocked(dev->fb_helper, true);
if (drm_drv_uses_atomic_modeset(dev)) {
if (!runtime) {
disp->suspend = drm_atomic_helper_suspend(dev);
......@@ -815,8 +817,10 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
drm_atomic_helper_resume(dev, disp->suspend);
disp->suspend = NULL;
}
return;
}
/* Enable console. */
drm_fb_helper_set_suspend_unlocked(dev->fb_helper, false);
}
int
......
......@@ -33,6 +33,7 @@
#include <drm/drm_aperture.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_ttm_helper.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_vblank.h>
......@@ -62,7 +63,6 @@
#include "nouveau_bios.h"
#include "nouveau_ioctl.h"
#include "nouveau_abi16.h"
#include "nouveau_fbcon.h"
#include "nouveau_fence.h"
#include "nouveau_debugfs.h"
#include "nouveau_usif.h"
......@@ -611,7 +611,6 @@ nouveau_drm_device_init(struct drm_device *dev)
nouveau_hwmon_init(dev);
nouveau_svm_init(drm);
nouveau_dmem_init(drm);
nouveau_fbcon_init(dev);
nouveau_led_init(dev);
if (nouveau_pmops_runtime()) {
......@@ -655,7 +654,6 @@ nouveau_drm_device_fini(struct drm_device *dev)
}
nouveau_led_fini(dev);
nouveau_fbcon_fini(dev);
nouveau_dmem_fini(drm);
nouveau_svm_fini(drm);
nouveau_hwmon_fini(dev);
......@@ -809,6 +807,11 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
if (ret)
goto fail_drm_dev_init;
if (nouveau_drm(drm_dev)->client.device.info.ram_size <= 32 * 1024 * 1024)
drm_fbdev_generic_setup(drm_dev, 8);
else
drm_fbdev_generic_setup(drm_dev, 32);
quirk_broken_nv_runpm(pdev);
return 0;
......@@ -865,8 +868,6 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
nouveau_led_suspend(dev);
if (dev->mode_config.num_crtc) {
NV_DEBUG(drm, "suspending console...\n");
nouveau_fbcon_set_suspend(dev, 1);
NV_DEBUG(drm, "suspending display...\n");
ret = nouveau_display_suspend(dev, runtime);
if (ret)
......@@ -940,8 +941,6 @@ nouveau_do_resume(struct drm_device *dev, bool runtime)
if (dev->mode_config.num_crtc) {
NV_DEBUG(drm, "resuming display...\n");
nouveau_display_resume(dev, runtime);
NV_DEBUG(drm, "resuming console...\n");
nouveau_fbcon_set_suspend(dev, 0);
}
nouveau_led_resume(dev);
......@@ -1296,7 +1295,6 @@ static void nouveau_display_options(void)
DRM_DEBUG_DRIVER("... tv_disable : %d\n", nouveau_tv_disable);
DRM_DEBUG_DRIVER("... ignorelid : %d\n", nouveau_ignorelid);
DRM_DEBUG_DRIVER("... duallink : %d\n", nouveau_duallink);
DRM_DEBUG_DRIVER("... nofbaccel : %d\n", nouveau_nofbaccel);
DRM_DEBUG_DRIVER("... config : %s\n", nouveau_config);
DRM_DEBUG_DRIVER("... debug : %s\n", nouveau_debug);
DRM_DEBUG_DRIVER("... noaccel : %d\n", nouveau_noaccel);
......
......@@ -183,7 +183,6 @@ struct nouveau_drm {
struct nouveau_channel *cechan;
struct nouveau_channel *channel;
struct nvkm_gpuobj *notify;
struct nouveau_fbdev *fbcon;
struct nvif_object ntfy;
/* nv10-nv40 tiling regions */
......@@ -198,8 +197,6 @@ struct nouveau_drm {
struct work_struct hpd_work;
spinlock_t hpd_lock;
u32 hpd_pending;
struct work_struct fbcon_work;
int fbcon_new_state;
#ifdef CONFIG_ACPI
struct notifier_block acpi_nb;
#endif
......
This diff is collapsed.
/*
* Copyright (C) 2008 Maarten Maathuis.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __NOUVEAU_FBCON_H__
#define __NOUVEAU_FBCON_H__
#include <drm/drm_fb_helper.h>
#include "nouveau_display.h"
struct nouveau_vma;
struct nouveau_fbdev {
struct drm_fb_helper helper; /* must be first */
unsigned int saved_flags;
struct nvif_object surf2d;
struct nvif_object clip;
struct nvif_object rop;
struct nvif_object patt;
struct nvif_object gdi;
struct nvif_object blit;
struct nvif_object twod;
struct nouveau_vma *vma;
struct mutex hotplug_lock;
bool hotplug_waiting;
};
void nouveau_fbcon_restore(void);
int nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
int nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
int nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nv04_fbcon_accel_init(struct fb_info *info);
int nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
int nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
int nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nv50_fbcon_accel_init(struct fb_info *info);
int nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
int nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
int nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nvc0_fbcon_accel_init(struct fb_info *info);
void nouveau_fbcon_gpu_lockup(struct fb_info *info);
int nouveau_fbcon_init(struct drm_device *dev);
void nouveau_fbcon_fini(struct drm_device *dev);
void nouveau_fbcon_set_suspend(struct drm_device *dev, int state);
void nouveau_fbcon_accel_save_disable(struct drm_device *dev);
void nouveau_fbcon_accel_restore(struct drm_device *dev);
void nouveau_fbcon_output_poll_changed(struct drm_device *dev);
void nouveau_fbcon_hotplug_resume(struct nouveau_fbdev *fbcon);
extern int nouveau_nofbaccel;
#endif /* __NV50_FBCON_H__ */
......@@ -7,7 +7,6 @@
#include "nouveau_drv.h"
#include "nouveau_acpi.h"
#include "nouveau_fbcon.h"
#include "nouveau_vga.h"
static unsigned int
......
/*
* Copyright 2009 Ben Skeggs
* Copyright 2008 Stuart Bennett
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#define NVIF_DEBUG_PRINT_DISABLE
#include "nouveau_drv.h"
#include "nouveau_dma.h"
#include "nouveau_fbcon.h"
#include <nvif/push006c.h>
int
nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
int ret;
ret = PUSH_WAIT(push, 4);
if (ret)
return ret;
PUSH_NVSQ(push, NV05F, 0x0300, (region->sy << 16) | region->sx,
0x0304, (region->dy << 16) | region->dx,
0x0308, (region->height << 16) | region->width);
PUSH_KICK(push);
return 0;
}
int
nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
int ret;
ret = PUSH_WAIT(push, 7);
if (ret)
return ret;
PUSH_NVSQ(push, NV04A, 0x02fc, (rect->rop != ROP_COPY) ? 1 : 3);
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR)
PUSH_NVSQ(push, NV04A, 0x03fc, ((uint32_t *)info->pseudo_palette)[rect->color]);
else
PUSH_NVSQ(push, NV04A, 0x03fc, rect->color);
PUSH_NVSQ(push, NV04A, 0x0400, (rect->dx << 16) | rect->dy,
0x0404, (rect->width << 16) | rect->height);
PUSH_KICK(push);
return 0;
}
int
nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
uint32_t fg;
uint32_t bg;
uint32_t dsize;
uint32_t *data = (uint32_t *)image->data;
int ret;
if (image->depth != 1)
return -ENODEV;
ret = PUSH_WAIT(push, 8);
if (ret)
return ret;
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
fg = ((uint32_t *) info->pseudo_palette)[image->fg_color];
bg = ((uint32_t *) info->pseudo_palette)[image->bg_color];
} else {
fg = image->fg_color;
bg = image->bg_color;
}
PUSH_NVSQ(push, NV04A, 0x0be4, (image->dy << 16) | (image->dx & 0xffff),
0x0be8, ((image->dy + image->height) << 16) |
((image->dx + image->width) & 0xffff),
0x0bec, bg,
0x0bf0, fg,
0x0bf4, (image->height << 16) | ALIGN(image->width, 8),
0x0bf8, (image->height << 16) | image->width,
0x0bfc, (image->dy << 16) | (image->dx & 0xffff));
dsize = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
while (dsize) {
int iter_len = dsize > 128 ? 128 : dsize;
ret = PUSH_WAIT(push, iter_len + 1);
if (ret)
return ret;
PUSH_NVSQ(push, NV04A, 0x0c00, data, iter_len);
data += iter_len;
dsize -= iter_len;
}
PUSH_KICK(push);
return 0;
}
int
nv04_fbcon_accel_init(struct fb_info *info)
{
struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->helper.dev;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_device *device = &drm->client.device;
struct nvif_push *push = chan->chan.push;
struct nvkm_device *nvkm_device = nvxx_device(&drm->client.device);
resource_size_t fb_base = nvkm_device->func->resource_addr(nvkm_device, 1);
int surface_fmt, pattern_fmt, rect_fmt;
int ret;
switch (info->var.bits_per_pixel) {
case 8:
surface_fmt = 1;
pattern_fmt = 3;
rect_fmt = 3;
break;
case 16:
surface_fmt = 4;
pattern_fmt = 1;
rect_fmt = 1;
break;
case 32:
switch (info->var.transp.length) {
case 0: /* depth 24 */
case 8: /* depth 32 */
break;
default:
return -EINVAL;
}
surface_fmt = 6;
pattern_fmt = 3;
rect_fmt = 3;
break;
default:
return -EINVAL;
}
ret = nvif_object_ctor(&chan->user, "fbconCtxSurf2d", 0x0062,
device->info.family >= NV_DEVICE_INFO_V0_CELSIUS ?
0x0062 : 0x0042, NULL, 0, &nfbdev->surf2d);
if (ret)
return ret;
ret = nvif_object_ctor(&chan->user, "fbconCtxClip", 0x0019, 0x0019,
NULL, 0, &nfbdev->clip);
if (ret)
return ret;
ret = nvif_object_ctor(&chan->user, "fbconCtxRop", 0x0043, 0x0043,
NULL, 0, &nfbdev->rop);
if (ret)
return ret;
ret = nvif_object_ctor(&chan->user, "fbconCtxPatt", 0x0044, 0x0044,
NULL, 0, &nfbdev->patt);
if (ret)
return ret;
ret = nvif_object_ctor(&chan->user, "fbconGdiRectText", 0x004a, 0x004a,
NULL, 0, &nfbdev->gdi);
if (ret)
return ret;
ret = nvif_object_ctor(&chan->user, "fbconImageBlit", 0x005f,
device->info.chipset >= 0x11 ? 0x009f : 0x005f,
NULL, 0, &nfbdev->blit);
if (ret)
return ret;
if (PUSH_WAIT(push, 49 + (device->info.chipset >= 0x11 ? 4 : 0))) {
nouveau_fbcon_gpu_lockup(info);
return 0;
}
PUSH_NVSQ(push, NV042, 0x0000, nfbdev->surf2d.handle);
PUSH_NVSQ(push, NV042, 0x0184, chan->vram.handle,
0x0188, chan->vram.handle);
PUSH_NVSQ(push, NV042, 0x0300, surface_fmt,
0x0304, info->fix.line_length | (info->fix.line_length << 16),
0x0308, info->fix.smem_start - fb_base,
0x030c, info->fix.smem_start - fb_base);
PUSH_NVSQ(push, NV043, 0x0000, nfbdev->rop.handle);
PUSH_NVSQ(push, NV043, 0x0300, 0x55);
PUSH_NVSQ(push, NV044, 0x0000, nfbdev->patt.handle);
PUSH_NVSQ(push, NV044, 0x0300, pattern_fmt,
#ifdef __BIG_ENDIAN
0x0304, 2,
#else
0x0304, 1,
#endif
0x0308, 0,
0x030c, 1,
0x0310, ~0,
0x0314, ~0,
0x0318, ~0,
0x031c, ~0);
PUSH_NVSQ(push, NV019, 0x0000, nfbdev->clip.handle);
PUSH_NVSQ(push, NV019, 0x0300, 0,
0x0304, (info->var.yres_virtual << 16) | info->var.xres_virtual);
PUSH_NVSQ(push, NV05F, 0x0000, nfbdev->blit.handle);
PUSH_NVSQ(push, NV05F, 0x019c, nfbdev->surf2d.handle);
PUSH_NVSQ(push, NV05F, 0x02fc, 3);
if (nfbdev->blit.oclass == 0x009f) {
PUSH_NVSQ(push, NV09F, 0x0120, 0,
0x0124, 1,
0x0128, 2);
}
PUSH_NVSQ(push, NV04A, 0x0000, nfbdev->gdi.handle);
PUSH_NVSQ(push, NV04A, 0x0198, nfbdev->surf2d.handle);
PUSH_NVSQ(push, NV04A, 0x0188, nfbdev->patt.handle,
0x018c, nfbdev->rop.handle);
PUSH_NVSQ(push, NV04A, 0x0304, 1);
PUSH_NVSQ(push, NV04A, 0x0300, rect_fmt);
PUSH_NVSQ(push, NV04A, 0x02fc, 3);
PUSH_KICK(push);
return 0;
}
/*
* Copyright 2010 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#define NVIF_DEBUG_PRINT_DISABLE
#include "nouveau_drv.h"
#include "nouveau_dma.h"
#include "nouveau_fbcon.h"
#include "nouveau_vmm.h"
#include <nvif/push206e.h>
#include <nvhw/class/cl502d.h>
int
nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
u32 colour;
int ret;
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR)
colour = ((uint32_t *)info->pseudo_palette)[rect->color];
else
colour = rect->color;
ret = PUSH_WAIT(push, rect->rop == ROP_COPY ? 7 : 11);
if (ret)
return ret;
if (rect->rop != ROP_COPY) {
PUSH_MTHD(push, NV502D, SET_OPERATION,
NVDEF(NV502D, SET_OPERATION, V, ROP_AND));
}
PUSH_MTHD(push, NV502D, SET_RENDER_SOLID_PRIM_COLOR, colour);
PUSH_MTHD(push, NV502D, RENDER_SOLID_PRIM_POINT_SET_X(0), rect->dx,
RENDER_SOLID_PRIM_POINT_Y(0), rect->dy,
RENDER_SOLID_PRIM_POINT_SET_X(1), rect->dx + rect->width,
RENDER_SOLID_PRIM_POINT_Y(1), rect->dy + rect->height);
if (rect->rop != ROP_COPY) {
PUSH_MTHD(push, NV502D, SET_OPERATION,
NVDEF(NV502D, SET_OPERATION, V, SRCCOPY));
}
PUSH_KICK(push);
return 0;
}
int
nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
int ret;
ret = PUSH_WAIT(push, 12);
if (ret)
return ret;
PUSH_MTHD(push, NV502D, WAIT_FOR_IDLE, 0);
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_DST_X0, region->dx,
SET_PIXELS_FROM_MEMORY_DST_Y0, region->dy,
SET_PIXELS_FROM_MEMORY_DST_WIDTH, region->width,
SET_PIXELS_FROM_MEMORY_DST_HEIGHT, region->height);
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_SRC_X0_FRAC, 0,
SET_PIXELS_FROM_MEMORY_SRC_X0_INT, region->sx,
SET_PIXELS_FROM_MEMORY_SRC_Y0_FRAC, 0,
PIXELS_FROM_MEMORY_SRC_Y0_INT, region->sy);
PUSH_KICK(push);
return 0;
}
int
nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
uint32_t dwords, *data = (uint32_t *)image->data;
uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
uint32_t *palette = info->pseudo_palette, bg, fg;
int ret;
if (image->depth != 1)
return -ENODEV;
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
bg = palette[image->bg_color] | mask;
fg = palette[image->fg_color] | mask;
} else {
bg = image->bg_color;
fg = image->fg_color;
}
ret = PUSH_WAIT(push, 11);
if (ret)
return ret;
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_COLOR0, bg,
SET_PIXELS_FROM_CPU_COLOR1, fg);
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_SRC_WIDTH, image->width,
SET_PIXELS_FROM_CPU_SRC_HEIGHT, image->height);
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_DST_X0_FRAC, 0,
SET_PIXELS_FROM_CPU_DST_X0_INT, image->dx,
SET_PIXELS_FROM_CPU_DST_Y0_FRAC, 0,
SET_PIXELS_FROM_CPU_DST_Y0_INT, image->dy);
dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
while (dwords) {
int count = dwords > 2047 ? 2047 : dwords;
ret = PUSH_WAIT(push, count + 1);
if (ret)
return ret;
dwords -= count;
PUSH_NINC(push, NV502D, PIXELS_FROM_CPU_DATA, data, count);
data += count;
}
PUSH_KICK(push);
return 0;
}
int
nv50_fbcon_accel_init(struct fb_info *info)
{
struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->helper.dev;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
int ret, format;
switch (info->var.bits_per_pixel) {
case 8:
format = NV502D_SET_DST_FORMAT_V_Y8;
break;
case 15:
format = NV502D_SET_DST_FORMAT_V_X1R5G5B5;
break;
case 16:
format = NV502D_SET_DST_FORMAT_V_R5G6B5;
break;
case 32:
switch (info->var.transp.length) {
case 0: /* depth 24 */
case 8: /* depth 32, just use 24.. */
format = NV502D_SET_DST_FORMAT_V_X8R8G8B8;
break;
case 2: /* depth 30 */
format = NV502D_SET_DST_FORMAT_V_A2B10G10R10;
break;
default:
return -EINVAL;
}
break;
default:
return -EINVAL;
}
ret = nvif_object_ctor(&chan->user, "fbconTwoD", 0x502d, 0x502d,
NULL, 0, &nfbdev->twod);
if (ret)
return ret;
ret = PUSH_WAIT(push, 56);
if (ret) {
nouveau_fbcon_gpu_lockup(info);
return ret;
}
PUSH_MTHD(push, NV502D, SET_OBJECT, nfbdev->twod.handle);
PUSH_MTHD(push, NV502D, SET_DST_CONTEXT_DMA, chan->vram.handle,
SET_SRC_CONTEXT_DMA, chan->vram.handle,
SET_SEMAPHORE_CONTEXT_DMA, chan->vram.handle);
PUSH_MTHD(push, NV502D, SET_DST_FORMAT,
NVVAL(NV502D, SET_DST_FORMAT, V, format),
SET_DST_MEMORY_LAYOUT,
NVDEF(NV502D, SET_DST_MEMORY_LAYOUT, V, PITCH));
PUSH_MTHD(push, NV502D, SET_DST_PITCH, info->fix.line_length,
SET_DST_WIDTH, info->var.xres_virtual,
SET_DST_HEIGHT, info->var.yres_virtual,
SET_DST_OFFSET_UPPER,
NVVAL(NV502D, SET_DST_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
SET_DST_OFFSET_LOWER,
NVVAL(NV502D, SET_DST_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
PUSH_MTHD(push, NV502D, SET_SRC_FORMAT,
NVVAL(NV502D, SET_SRC_FORMAT, V, format),
SET_SRC_MEMORY_LAYOUT,
NVDEF(NV502D, SET_SRC_MEMORY_LAYOUT, V, PITCH));
PUSH_MTHD(push, NV502D, SET_SRC_PITCH, info->fix.line_length,
SET_SRC_WIDTH, info->var.xres_virtual,
SET_SRC_HEIGHT, info->var.yres_virtual,
SET_SRC_OFFSET_UPPER,
NVVAL(NV502D, SET_SRC_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
SET_SRC_OFFSET_LOWER,
NVVAL(NV502D, SET_SRC_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
PUSH_MTHD(push, NV502D, SET_CLIP_ENABLE,
NVDEF(NV502D, SET_CLIP_ENABLE, V, FALSE));
PUSH_MTHD(push, NV502D, SET_ROP,
NVVAL(NV502D, SET_ROP, V, 0x55));
PUSH_MTHD(push, NV502D, SET_OPERATION,
NVDEF(NV502D, SET_OPERATION, V, SRCCOPY));
PUSH_MTHD(push, NV502D, SET_MONOCHROME_PATTERN_COLOR_FORMAT,
NVDEF(NV502D, SET_MONOCHROME_PATTERN_COLOR_FORMAT, V, A8R8G8B8),
SET_MONOCHROME_PATTERN_FORMAT,
NVDEF(NV502D, SET_MONOCHROME_PATTERN_FORMAT, V, LE_M1));
PUSH_MTHD(push, NV502D, RENDER_SOLID_PRIM_MODE,
NVDEF(NV502D, RENDER_SOLID_PRIM_MODE, V, RECTS),
SET_RENDER_SOLID_PRIM_COLOR_FORMAT,
NVVAL(NV502D, SET_RENDER_SOLID_PRIM_COLOR_FORMAT, V, format));
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_DATA_TYPE,
NVDEF(NV502D, SET_PIXELS_FROM_CPU_DATA_TYPE, V, INDEX),
SET_PIXELS_FROM_CPU_COLOR_FORMAT,
NVVAL(NV502D, SET_PIXELS_FROM_CPU_COLOR_FORMAT, V, format),
SET_PIXELS_FROM_CPU_INDEX_FORMAT,
NVDEF(NV502D, SET_PIXELS_FROM_CPU_INDEX_FORMAT, V, I1),
SET_PIXELS_FROM_CPU_MONO_FORMAT,
NVDEF(NV502D, SET_PIXELS_FROM_CPU_MONO_FORMAT, V, CGA6_M1),
SET_PIXELS_FROM_CPU_WRAP,
NVDEF(NV502D, SET_PIXELS_FROM_CPU_WRAP, V, WRAP_BYTE));
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_MONO_OPACITY,
NVDEF(NV502D, SET_PIXELS_FROM_CPU_MONO_OPACITY, V, OPAQUE));
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_DX_DU_FRAC, 0,
SET_PIXELS_FROM_CPU_DX_DU_INT, 1,
SET_PIXELS_FROM_CPU_DY_DV_FRAC, 0,
SET_PIXELS_FROM_CPU_DY_DV_INT, 1);
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP,
NVDEF(NV502D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP, V, TRUE));
PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_DU_DX_FRAC, 0,
SET_PIXELS_FROM_MEMORY_DU_DX_INT, 1,
SET_PIXELS_FROM_MEMORY_DV_DY_FRAC, 0,
SET_PIXELS_FROM_MEMORY_DV_DY_INT, 1);
PUSH_KICK(push);
return 0;
}
/*
* Copyright 2010 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#define NVIF_DEBUG_PRINT_DISABLE
#include "nouveau_drv.h"
#include "nouveau_dma.h"
#include "nouveau_fbcon.h"
#include "nouveau_vmm.h"
#include <nvif/push906f.h>
#include <nvhw/class/cl902d.h>
int
nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
u32 colour;
int ret;
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR)
colour = ((uint32_t *)info->pseudo_palette)[rect->color];
else
colour = rect->color;
ret = PUSH_WAIT(push, rect->rop == ROP_COPY ? 7 : 9);
if (ret)
return ret;
if (rect->rop != ROP_COPY) {
PUSH_IMMD(push, NV902D, SET_OPERATION,
NVDEF(NV902D, SET_OPERATION, V, ROP_AND));
}
PUSH_MTHD(push, NV902D, SET_RENDER_SOLID_PRIM_COLOR, colour);
PUSH_MTHD(push, NV902D, RENDER_SOLID_PRIM_POINT_SET_X(0), rect->dx,
RENDER_SOLID_PRIM_POINT_Y(0), rect->dy,
RENDER_SOLID_PRIM_POINT_SET_X(1), rect->dx + rect->width,
RENDER_SOLID_PRIM_POINT_Y(1), rect->dy + rect->height);
if (rect->rop != ROP_COPY) {
PUSH_IMMD(push, NV902D, SET_OPERATION,
NVDEF(NV902D, SET_OPERATION, V, SRCCOPY));
}
PUSH_KICK(push);
return 0;
}
int
nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
int ret;
ret = PUSH_WAIT(push, 11);
if (ret)
return ret;
PUSH_IMMD(push, NV902D, WAIT_FOR_IDLE, 0);
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_DST_X0, region->dx,
SET_PIXELS_FROM_MEMORY_DST_Y0, region->dy,
SET_PIXELS_FROM_MEMORY_DST_WIDTH, region->width,
SET_PIXELS_FROM_MEMORY_DST_HEIGHT, region->height);
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_SRC_X0_FRAC, 0,
SET_PIXELS_FROM_MEMORY_SRC_X0_INT, region->sx,
SET_PIXELS_FROM_MEMORY_SRC_Y0_FRAC, 0,
PIXELS_FROM_MEMORY_SRC_Y0_INT, region->sy);
PUSH_KICK(push);
return 0;
}
int
nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct nouveau_fbdev *nfbdev = info->par;
struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
uint32_t dwords, *data = (uint32_t *)image->data;
uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
uint32_t *palette = info->pseudo_palette, bg, fg;
int ret;
if (image->depth != 1)
return -ENODEV;
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
bg = palette[image->bg_color] | mask;
fg = palette[image->fg_color] | mask;
} else {
bg = image->bg_color;
fg = image->fg_color;
}
ret = PUSH_WAIT(push, 11);
if (ret)
return ret;
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_COLOR0, bg,
SET_PIXELS_FROM_CPU_COLOR1, fg);
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_SRC_WIDTH, image->width,
SET_PIXELS_FROM_CPU_SRC_HEIGHT, image->height);
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_DST_X0_FRAC, 0,
SET_PIXELS_FROM_CPU_DST_X0_INT, image->dx,
SET_PIXELS_FROM_CPU_DST_Y0_FRAC, 0,
SET_PIXELS_FROM_CPU_DST_Y0_INT, image->dy);
dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
while (dwords) {
int count = dwords > 2047 ? 2047 : dwords;
ret = PUSH_WAIT(push, count + 1);
if (ret)
return ret;
dwords -= count;
PUSH_NINC(push, NV902D, PIXELS_FROM_CPU_DATA, data, count);
data += count;
}
PUSH_KICK(push);
return 0;
}
int
nvc0_fbcon_accel_init(struct fb_info *info)
{
struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = nfbdev->helper.dev;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_channel *chan = drm->channel;
struct nvif_push *push = chan->chan.push;
int ret, format;
ret = nvif_object_ctor(&chan->user, "fbconTwoD", 0x902d, 0x902d,
NULL, 0, &nfbdev->twod);
if (ret)
return ret;
switch (info->var.bits_per_pixel) {
case 8:
format = NV902D_SET_DST_FORMAT_V_Y8;
break;
case 15:
format = NV902D_SET_DST_FORMAT_V_X1R5G5B5;
break;
case 16:
format = NV902D_SET_DST_FORMAT_V_R5G6B5;
break;
case 32:
switch (info->var.transp.length) {
case 0: /* depth 24 */
case 8: /* depth 32, just use 24.. */
format = NV902D_SET_DST_FORMAT_V_X8R8G8B8;
break;
case 2: /* depth 30 */
format = NV902D_SET_DST_FORMAT_V_A2B10G10R10;
break;
default:
return -EINVAL;
}
break;
default:
return -EINVAL;
}
ret = PUSH_WAIT(push, 52);
if (ret) {
WARN_ON(1);
nouveau_fbcon_gpu_lockup(info);
return ret;
}
PUSH_MTHD(push, NV902D, SET_OBJECT, nfbdev->twod.handle);
PUSH_MTHD(push, NV902D, SET_DST_FORMAT,
NVVAL(NV902D, SET_DST_FORMAT, V, format),
SET_DST_MEMORY_LAYOUT,
NVDEF(NV902D, SET_DST_MEMORY_LAYOUT, V, PITCH));
PUSH_MTHD(push, NV902D, SET_DST_PITCH, info->fix.line_length,
SET_DST_WIDTH, info->var.xres_virtual,
SET_DST_HEIGHT, info->var.yres_virtual,
SET_DST_OFFSET_UPPER,
NVVAL(NV902D, SET_DST_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
SET_DST_OFFSET_LOWER,
NVVAL(NV902D, SET_DST_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
PUSH_MTHD(push, NV902D, SET_SRC_FORMAT,
NVVAL(NV902D, SET_SRC_FORMAT, V, format),
SET_SRC_MEMORY_LAYOUT,
NVDEF(NV902D, SET_SRC_MEMORY_LAYOUT, V, PITCH));
PUSH_MTHD(push, NV902D, SET_SRC_PITCH, info->fix.line_length,
SET_SRC_WIDTH, info->var.xres_virtual,
SET_SRC_HEIGHT, info->var.yres_virtual,
SET_SRC_OFFSET_UPPER,
NVVAL(NV902D, SET_SRC_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
SET_SRC_OFFSET_LOWER,
NVVAL(NV902D, SET_SRC_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
PUSH_IMMD(push, NV902D, SET_CLIP_ENABLE,
NVDEF(NV902D, SET_CLIP_ENABLE, V, FALSE));
PUSH_IMMD(push, NV902D, SET_ROP,
NVVAL(NV902D, SET_ROP, V, 0x55));
PUSH_IMMD(push, NV902D, SET_OPERATION,
NVDEF(NV902D, SET_OPERATION, V, SRCCOPY));
PUSH_MTHD(push, NV902D, SET_MONOCHROME_PATTERN_COLOR_FORMAT,
NVDEF(NV902D, SET_MONOCHROME_PATTERN_COLOR_FORMAT, V, A8R8G8B8),
SET_MONOCHROME_PATTERN_FORMAT,
NVDEF(NV902D, SET_MONOCHROME_PATTERN_FORMAT, V, LE_M1));
PUSH_MTHD(push, NV902D, RENDER_SOLID_PRIM_MODE,
NVDEF(NV902D, RENDER_SOLID_PRIM_MODE, V, RECTS),
SET_RENDER_SOLID_PRIM_COLOR_FORMAT,
NVVAL(NV902D, SET_RENDER_SOLID_PRIM_COLOR_FORMAT, V, format));
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_DATA_TYPE,
NVDEF(NV902D, SET_PIXELS_FROM_CPU_DATA_TYPE, V, INDEX),
SET_PIXELS_FROM_CPU_COLOR_FORMAT,
NVVAL(NV902D, SET_PIXELS_FROM_CPU_COLOR_FORMAT, V, format),
SET_PIXELS_FROM_CPU_INDEX_FORMAT,
NVDEF(NV902D, SET_PIXELS_FROM_CPU_INDEX_FORMAT, V, I1),
SET_PIXELS_FROM_CPU_MONO_FORMAT,
NVDEF(NV902D, SET_PIXELS_FROM_CPU_MONO_FORMAT, V, CGA6_M1),
SET_PIXELS_FROM_CPU_WRAP,
NVDEF(NV902D, SET_PIXELS_FROM_CPU_WRAP, V, WRAP_BYTE));
PUSH_IMMD(push, NV902D, SET_PIXELS_FROM_CPU_MONO_OPACITY,
NVDEF(NV902D, SET_PIXELS_FROM_CPU_MONO_OPACITY, V, OPAQUE));
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_DX_DU_FRAC, 0,
SET_PIXELS_FROM_CPU_DX_DU_INT, 1,
SET_PIXELS_FROM_CPU_DY_DV_FRAC, 0,
SET_PIXELS_FROM_CPU_DY_DV_INT, 1);
PUSH_IMMD(push, NV902D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP,
NVDEF(NV902D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP, V, TRUE));
PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_DU_DX_FRAC, 0,
SET_PIXELS_FROM_MEMORY_DU_DX_INT, 1,
SET_PIXELS_FROM_MEMORY_DV_DY_FRAC, 0,
SET_PIXELS_FROM_MEMORY_DV_DY_INT, 1);
PUSH_KICK(push);
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment