aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/mgag200
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/mgag200')
-rw-r--r--drivers/gpu/drm/mgag200/Kconfig1
-rw-r--r--drivers/gpu/drm/mgag200/Makefile2
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_cursor.c277
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.c6
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.h48
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_fb.c12
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_main.c53
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c144
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_reg.h6
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_ttm.c48
10 files changed, 505 insertions, 92 deletions
diff --git a/drivers/gpu/drm/mgag200/Kconfig b/drivers/gpu/drm/mgag200/Kconfig
index b487cdec5ee..3a1c5fbae54 100644
--- a/drivers/gpu/drm/mgag200/Kconfig
+++ b/drivers/gpu/drm/mgag200/Kconfig
@@ -5,6 +5,7 @@ config DRM_MGAG200
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
select DRM_KMS_HELPER
+ select DRM_KMS_FB_HELPER
select DRM_TTM
help
This is a KMS driver for the MGA G200 server chips, it
diff --git a/drivers/gpu/drm/mgag200/Makefile b/drivers/gpu/drm/mgag200/Makefile
index 7db592eedbf..a9a0300f09f 100644
--- a/drivers/gpu/drm/mgag200/Makefile
+++ b/drivers/gpu/drm/mgag200/Makefile
@@ -1,5 +1,5 @@
ccflags-y := -Iinclude/drm
-mgag200-y := mgag200_main.o mgag200_mode.o \
+mgag200-y := mgag200_main.o mgag200_mode.o mgag200_cursor.o \
mgag200_drv.o mgag200_fb.o mgag200_i2c.o mgag200_ttm.o
obj-$(CONFIG_DRM_MGAG200) += mgag200.o
diff --git a/drivers/gpu/drm/mgag200/mgag200_cursor.c b/drivers/gpu/drm/mgag200/mgag200_cursor.c
new file mode 100644
index 00000000000..9f9780b7ddf
--- /dev/null
+++ b/drivers/gpu/drm/mgag200/mgag200_cursor.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2013 Matrox Graphics
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Author: Christopher Harvey <charvey@matrox.com>
+ */
+
+#include <drm/drmP.h>
+#include "mgag200_drv.h"
+
+static bool warn_transparent = true;
+static bool warn_palette = true;
+
+/*
+ Hide the cursor off screen. We can't disable the cursor hardware because it
+ takes too long to re-activate and causes momentary corruption
+*/
+static void mga_hide_cursor(struct mga_device *mdev)
+{
+ WREG8(MGA_CURPOSXL, 0);
+ WREG8(MGA_CURPOSXH, 0);
+ if (mdev->cursor.pixels_1->pin_count)
+ mgag200_bo_unpin(mdev->cursor.pixels_1);
+ if (mdev->cursor.pixels_2->pin_count)
+ mgag200_bo_unpin(mdev->cursor.pixels_2);
+}
+
+int mga_crtc_cursor_set(struct drm_crtc *crtc,
+ struct drm_file *file_priv,
+ uint32_t handle,
+ uint32_t width,
+ uint32_t height)
+{
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = (struct mga_device *)dev->dev_private;
+ struct mgag200_bo *pixels_1 = mdev->cursor.pixels_1;
+ struct mgag200_bo *pixels_2 = mdev->cursor.pixels_2;
+ struct mgag200_bo *pixels_current = mdev->cursor.pixels_current;
+ struct mgag200_bo *pixels_prev = mdev->cursor.pixels_prev;
+ struct drm_gem_object *obj;
+ struct mgag200_bo *bo = NULL;
+ int ret = 0;
+ unsigned int i, row, col;
+ uint32_t colour_set[16];
+ uint32_t *next_space = &colour_set[0];
+ uint32_t *palette_iter;
+ uint32_t this_colour;
+ bool found = false;
+ int colour_count = 0;
+ u64 gpu_addr;
+ u8 reg_index;
+ u8 this_row[48];
+
+ if (!pixels_1 || !pixels_2) {
+ WREG8(MGA_CURPOSXL, 0);
+ WREG8(MGA_CURPOSXH, 0);
+ return -ENOTSUPP; /* Didn't allocate space for cursors */
+ }
+
+ if ((width != 64 || height != 64) && handle) {
+ WREG8(MGA_CURPOSXL, 0);
+ WREG8(MGA_CURPOSXH, 0);
+ return -EINVAL;
+ }
+
+ BUG_ON(pixels_1 != pixels_current && pixels_1 != pixels_prev);
+ BUG_ON(pixels_2 != pixels_current && pixels_2 != pixels_prev);
+ BUG_ON(pixels_current == pixels_prev);
+
+ ret = mgag200_bo_reserve(pixels_1, true);
+ if (ret) {
+ WREG8(MGA_CURPOSXL, 0);
+ WREG8(MGA_CURPOSXH, 0);
+ return ret;
+ }
+ ret = mgag200_bo_reserve(pixels_2, true);
+ if (ret) {
+ WREG8(MGA_CURPOSXL, 0);
+ WREG8(MGA_CURPOSXH, 0);
+ mgag200_bo_unreserve(pixels_1);
+ return ret;
+ }
+
+ if (!handle) {
+ mga_hide_cursor(mdev);
+ ret = 0;
+ goto out1;
+ }
+
+ /* Move cursor buffers into VRAM if they aren't already */
+ if (!pixels_1->pin_count) {
+ ret = mgag200_bo_pin(pixels_1, TTM_PL_FLAG_VRAM,
+ &mdev->cursor.pixels_1_gpu_addr);
+ if (ret)
+ goto out1;
+ }
+ if (!pixels_2->pin_count) {
+ ret = mgag200_bo_pin(pixels_2, TTM_PL_FLAG_VRAM,
+ &mdev->cursor.pixels_2_gpu_addr);
+ if (ret) {
+ mgag200_bo_unpin(pixels_1);
+ goto out1;
+ }
+ }
+
+ mutex_lock(&dev->struct_mutex);
+ obj = drm_gem_object_lookup(dev, file_priv, handle);
+ if (!obj) {
+ mutex_unlock(&dev->struct_mutex);
+ ret = -ENOENT;
+ goto out1;
+ }
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+
+ bo = gem_to_mga_bo(obj);
+ ret = mgag200_bo_reserve(bo, true);
+ if (ret) {
+ dev_err(&dev->pdev->dev, "failed to reserve user bo\n");
+ goto out1;
+ }
+ if (!bo->kmap.virtual) {
+ ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+ if (ret) {
+ dev_err(&dev->pdev->dev, "failed to kmap user buffer updates\n");
+ goto out2;
+ }
+ }
+
+ memset(&colour_set[0], 0, sizeof(uint32_t)*16);
+ /* width*height*4 = 16384 */
+ for (i = 0; i < 16384; i += 4) {
+ this_colour = ioread32(bo->kmap.virtual + i);
+ /* No transparency */
+ if (this_colour>>24 != 0xff &&
+ this_colour>>24 != 0x0) {
+ if (warn_transparent) {
+ dev_info(&dev->pdev->dev, "Video card doesn't support cursors with partial transparency.\n");
+ dev_info(&dev->pdev->dev, "Not enabling hardware cursor.\n");
+ warn_transparent = false; /* Only tell the user once. */
+ }
+ ret = -EINVAL;
+ goto out3;
+ }
+ /* Don't need to store transparent pixels as colours */
+ if (this_colour>>24 == 0x0)
+ continue;
+ found = false;
+ for (palette_iter = &colour_set[0]; palette_iter != next_space; palette_iter++) {
+ if (*palette_iter == this_colour) {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ continue;
+ /* We only support 4bit paletted cursors */
+ if (colour_count >= 16) {
+ if (warn_palette) {
+ dev_info(&dev->pdev->dev, "Video card only supports cursors with up to 16 colours.\n");
+ dev_info(&dev->pdev->dev, "Not enabling hardware cursor.\n");
+ warn_palette = false; /* Only tell the user once. */
+ }
+ ret = -EINVAL;
+ goto out3;
+ }
+ *next_space = this_colour;
+ next_space++;
+ colour_count++;
+ }
+
+ /* Program colours from cursor icon into palette */
+ for (i = 0; i < colour_count; i++) {
+ if (i <= 2)
+ reg_index = 0x8 + i*0x4;
+ else
+ reg_index = 0x60 + i*0x3;
+ WREG_DAC(reg_index, colour_set[i] & 0xff);
+ WREG_DAC(reg_index+1, colour_set[i]>>8 & 0xff);
+ WREG_DAC(reg_index+2, colour_set[i]>>16 & 0xff);
+ BUG_ON((colour_set[i]>>24 & 0xff) != 0xff);
+ }
+
+ /* Map up-coming buffer to write colour indices */
+ if (!pixels_prev->kmap.virtual) {
+ ret = ttm_bo_kmap(&pixels_prev->bo, 0,
+ pixels_prev->bo.num_pages,
+ &pixels_prev->kmap);
+ if (ret) {
+ dev_err(&dev->pdev->dev, "failed to kmap cursor updates\n");
+ goto out3;
+ }
+ }
+
+ /* now write colour indices into hardware cursor buffer */
+ for (row = 0; row < 64; row++) {
+ memset(&this_row[0], 0, 48);
+ for (col = 0; col < 64; col++) {
+ this_colour = ioread32(bo->kmap.virtual + 4*(col + 64*row));
+ /* write transparent pixels */
+ if (this_colour>>24 == 0x0) {
+ this_row[47 - col/8] |= 0x80>>(col%8);
+ continue;
+ }
+
+ /* write colour index here */
+ for (i = 0; i < colour_count; i++) {
+ if (colour_set[i] == this_colour) {
+ if (col % 2)
+ this_row[col/2] |= i<<4;
+ else
+ this_row[col/2] |= i;
+ break;
+ }
+ }
+ }
+ memcpy_toio(pixels_prev->kmap.virtual + row*48, &this_row[0], 48);
+ }
+
+ /* Program gpu address of cursor buffer */
+ if (pixels_prev == pixels_1)
+ gpu_addr = mdev->cursor.pixels_1_gpu_addr;
+ else
+ gpu_addr = mdev->cursor.pixels_2_gpu_addr;
+ WREG_DAC(MGA1064_CURSOR_BASE_ADR_LOW, (u8)((gpu_addr>>10) & 0xff));
+ WREG_DAC(MGA1064_CURSOR_BASE_ADR_HI, (u8)((gpu_addr>>18) & 0x3f));
+
+ /* Adjust cursor control register to turn on the cursor */
+ WREG_DAC(MGA1064_CURSOR_CTL, 4); /* 16-colour palletized cursor mode */
+
+ /* Now swap internal buffer pointers */
+ if (mdev->cursor.pixels_1 == mdev->cursor.pixels_prev) {
+ mdev->cursor.pixels_prev = mdev->cursor.pixels_2;
+ mdev->cursor.pixels_current = mdev->cursor.pixels_1;
+ } else if (mdev->cursor.pixels_1 == mdev->cursor.pixels_current) {
+ mdev->cursor.pixels_prev = mdev->cursor.pixels_1;
+ mdev->cursor.pixels_current = mdev->cursor.pixels_2;
+ } else {
+ BUG();
+ }
+ ret = 0;
+
+ ttm_bo_kunmap(&pixels_prev->kmap);
+ out3:
+ ttm_bo_kunmap(&bo->kmap);
+ out2:
+ mgag200_bo_unreserve(bo);
+ out1:
+ if (ret)
+ mga_hide_cursor(mdev);
+ mgag200_bo_unreserve(pixels_1);
+ mgag200_bo_unreserve(pixels_2);
+ return ret;
+}
+
+int mga_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
+{
+ struct mga_device *mdev = (struct mga_device *)crtc->dev->dev_private;
+ /* Our origin is at (64,64) */
+ x += 64;
+ y += 64;
+
+ BUG_ON(x <= 0);
+ BUG_ON(y <= 0);
+ BUG_ON(x & ~0xffff);
+ BUG_ON(y & ~0xffff);
+
+ WREG8(MGA_CURPOSXL, x & 0xff);
+ WREG8(MGA_CURPOSXH, (x>>8) & 0xff);
+
+ WREG8(MGA_CURPOSYL, y & 0xff);
+ WREG8(MGA_CURPOSYH, (y>>8) & 0xff);
+ return 0;
+}
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
index 122b571ccc7..f15ea3c4a90 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -81,7 +81,6 @@ static const struct file_operations mgag200_driver_fops = {
.unlocked_ioctl = drm_ioctl,
.mmap = mgag200_mmap,
.poll = drm_poll,
- .fasync = drm_fasync,
#ifdef CONFIG_COMPAT
.compat_ioctl = drm_compat_ioctl,
#endif
@@ -89,7 +88,7 @@ static const struct file_operations mgag200_driver_fops = {
};
static struct drm_driver driver = {
- .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_USE_MTRR,
+ .driver_features = DRIVER_GEM | DRIVER_MODESET,
.load = mgag200_driver_load,
.unload = mgag200_driver_unload,
.fops = &mgag200_driver_fops,
@@ -100,11 +99,10 @@ static struct drm_driver driver = {
.minor = DRIVER_MINOR,
.patchlevel = DRIVER_PATCHLEVEL,
- .gem_init_object = mgag200_gem_init_object,
.gem_free_object = mgag200_gem_free_object,
.dumb_create = mgag200_dumb_create,
.dumb_map_offset = mgag200_dumb_mmap_offset,
- .dumb_destroy = mgag200_dumb_destroy,
+ .dumb_destroy = drm_gem_dumb_destroy,
};
static struct pci_driver mgag200_pci_driver = {
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
index bf29b2f4d68..cf11ee68a6d 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -149,6 +149,21 @@ struct mga_connector {
struct mga_i2c_chan *i2c;
};
+struct mga_cursor {
+ /*
+ We have to have 2 buffers for the cursor to avoid occasional
+ corruption while switching cursor icons.
+ If either of these is NULL, then don't do hardware cursors, and
+ fall back to software.
+ */
+ struct mgag200_bo *pixels_1;
+ struct mgag200_bo *pixels_2;
+ u64 pixels_1_gpu_addr, pixels_2_gpu_addr;
+ /* The currently displayed icon, this points to one of pixels_1, or pixels_2 */
+ struct mgag200_bo *pixels_current;
+ /* The previously displayed icon */
+ struct mgag200_bo *pixels_prev;
+};
struct mga_mc {
resource_size_t vram_size;
@@ -181,6 +196,7 @@ struct mga_device {
struct mga_mode_info mode_info;
struct mga_fbdev *mfbdev;
+ struct mga_cursor cursor;
bool suspended;
int num_crtc;
@@ -198,7 +214,8 @@ struct mga_device {
struct ttm_bo_device bdev;
} ttm;
- u32 reg_1e24; /* SE model number */
+ /* SE model number stored in reg 0x1e24 */
+ u32 unique_rev_id;
};
@@ -243,13 +260,9 @@ int mgag200_driver_unload(struct drm_device *dev);
int mgag200_gem_create(struct drm_device *dev,
u32 size, bool iskernel,
struct drm_gem_object **obj);
-int mgag200_gem_init_object(struct drm_gem_object *obj);
int mgag200_dumb_create(struct drm_file *file,
struct drm_device *dev,
struct drm_mode_create_dumb *args);
-int mgag200_dumb_destroy(struct drm_file *file,
- struct drm_device *dev,
- uint32_t handle);
void mgag200_gem_free_object(struct drm_gem_object *obj);
int
mgag200_dumb_mmap_offset(struct drm_file *file,
@@ -263,8 +276,24 @@ void mgag200_i2c_destroy(struct mga_i2c_chan *i2c);
#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
void mgag200_ttm_placement(struct mgag200_bo *bo, int domain);
-int mgag200_bo_reserve(struct mgag200_bo *bo, bool no_wait);
-void mgag200_bo_unreserve(struct mgag200_bo *bo);
+static inline int mgag200_bo_reserve(struct mgag200_bo *bo, bool no_wait)
+{
+ int ret;
+
+ ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
+ if (ret) {
+ if (ret != -ERESTARTSYS && ret != -EBUSY)
+ DRM_ERROR("reserve failed %p\n", bo);
+ return ret;
+ }
+ return 0;
+}
+
+static inline void mgag200_bo_unreserve(struct mgag200_bo *bo)
+{
+ ttm_bo_unreserve(&bo->bo);
+}
+
int mgag200_bo_create(struct drm_device *dev, int size, int align,
uint32_t flags, struct mgag200_bo **pastbo);
int mgag200_mm_init(struct mga_device *mdev);
@@ -273,4 +302,9 @@ int mgag200_mmap(struct file *filp, struct vm_area_struct *vma);
int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr);
int mgag200_bo_unpin(struct mgag200_bo *bo);
int mgag200_bo_push_sysram(struct mgag200_bo *bo);
+ /* mgag200_cursor.c */
+int mga_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
+ uint32_t handle, uint32_t width, uint32_t height);
+int mga_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);
+
#endif /* __MGAG200_DRV_H__ */
diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c
index 5da824ce9ba..13b7dd83faa 100644
--- a/drivers/gpu/drm/mgag200/mgag200_fb.c
+++ b/drivers/gpu/drm/mgag200/mgag200_fb.c
@@ -27,7 +27,7 @@ static void mga_dirty_update(struct mga_fbdev *mfbdev,
struct mgag200_bo *bo;
int src_offset, dst_offset;
int bpp = (mfbdev->mfb.base.bits_per_pixel + 7)/8;
- int ret;
+ int ret = -EBUSY;
bool unmap = false;
bool store_for_later = false;
int x2, y2;
@@ -41,7 +41,8 @@ static void mga_dirty_update(struct mga_fbdev *mfbdev,
* then the BO is being moved and we should
* store up the damage until later.
*/
- ret = mgag200_bo_reserve(bo, true);
+ if (drm_can_sleep())
+ ret = mgag200_bo_reserve(bo, true);
if (ret) {
if (ret != -EBUSY)
return;
@@ -281,6 +282,11 @@ int mgag200_fbdev_init(struct mga_device *mdev)
{
struct mga_fbdev *mfbdev;
int ret;
+ int bpp_sel = 32;
+
+ /* prefer 16bpp on low end gpus with limited VRAM */
+ if (IS_G200_SE(mdev) && mdev->mc.vram_size < (2048*1024))
+ bpp_sel = 16;
mfbdev = devm_kzalloc(mdev->dev->dev, sizeof(struct mga_fbdev), GFP_KERNEL);
if (!mfbdev)
@@ -300,7 +306,7 @@ int mgag200_fbdev_init(struct mga_device *mdev)
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(mdev->dev);
- drm_fb_helper_initial_config(&mfbdev->helper, 32);
+ drm_fb_helper_initial_config(&mfbdev->helper, bpp_sel);
return 0;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c
index 99059237da3..f6b283b8375 100644
--- a/drivers/gpu/drm/mgag200/mgag200_main.c
+++ b/drivers/gpu/drm/mgag200/mgag200_main.c
@@ -176,7 +176,7 @@ static int mgag200_device_init(struct drm_device *dev,
/* stash G200 SE model number for later use */
if (IS_G200_SE(mdev))
- mdev->reg_1e24 = RREG32(0x1e24);
+ mdev->unique_rev_id = RREG32(0x1e24);
ret = mga_vram_init(mdev);
if (ret)
@@ -209,7 +209,7 @@ int mgag200_driver_load(struct drm_device *dev, unsigned long flags)
r = mgag200_device_init(dev, flags);
if (r) {
dev_err(&dev->pdev->dev, "Fatal error during GPU init: %d\n", r);
- goto out;
+ return r;
}
r = mgag200_mm_init(mdev);
if (r)
@@ -217,12 +217,34 @@ int mgag200_driver_load(struct drm_device *dev, unsigned long flags)
drm_mode_config_init(dev);
dev->mode_config.funcs = (void *)&mga_mode_funcs;
- dev->mode_config.preferred_depth = 24;
+ if (IS_G200_SE(mdev) && mdev->mc.vram_size < (2048*1024))
+ dev->mode_config.preferred_depth = 16;
+ else
+ dev->mode_config.preferred_depth = 24;
dev->mode_config.prefer_shadow = 1;
r = mgag200_modeset_init(mdev);
- if (r)
+ if (r) {
dev_err(&dev->pdev->dev, "Fatal error during modeset init: %d\n", r);
+ goto out;
+ }
+
+ /* Make small buffers to store a hardware cursor (double buffered icon updates) */
+ mgag200_bo_create(dev, roundup(48*64, PAGE_SIZE), 0, 0,
+ &mdev->cursor.pixels_1);
+ mgag200_bo_create(dev, roundup(48*64, PAGE_SIZE), 0, 0,
+ &mdev->cursor.pixels_2);
+ if (!mdev->cursor.pixels_2 || !mdev->cursor.pixels_1)
+ goto cursor_nospace;
+ mdev->cursor.pixels_current = mdev->cursor.pixels_1;
+ mdev->cursor.pixels_prev = mdev->cursor.pixels_2;
+ goto cursor_done;
+ cursor_nospace:
+ mdev->cursor.pixels_1 = NULL;
+ mdev->cursor.pixels_2 = NULL;
+ dev_warn(&dev->pdev->dev, "Could not allocate space for cursors. Not doing hardware cursors.\n");
+ cursor_done:
+
out:
if (r)
mgag200_driver_unload(dev);
@@ -291,20 +313,7 @@ int mgag200_dumb_create(struct drm_file *file,
return 0;
}
-int mgag200_dumb_destroy(struct drm_file *file,
- struct drm_device *dev,
- uint32_t handle)
-{
- return drm_gem_handle_delete(file, handle);
-}
-
-int mgag200_gem_init_object(struct drm_gem_object *obj)
-{
- BUG();
- return 0;
-}
-
-void mgag200_bo_unref(struct mgag200_bo **bo)
+static void mgag200_bo_unref(struct mgag200_bo **bo)
{
struct ttm_buffer_object *tbo;
@@ -313,24 +322,20 @@ void mgag200_bo_unref(struct mgag200_bo **bo)
tbo = &((*bo)->bo);
ttm_bo_unref(&tbo);
- if (tbo == NULL)
- *bo = NULL;
-
+ *bo = NULL;
}
void mgag200_gem_free_object(struct drm_gem_object *obj)
{
struct mgag200_bo *mgag200_bo = gem_to_mga_bo(obj);
- if (!mgag200_bo)
- return;
mgag200_bo_unref(&mgag200_bo);
}
static inline u64 mgag200_bo_mmap_offset(struct mgag200_bo *bo)
{
- return bo->bo.addr_space_offset;
+ return drm_vma_node_offset_addr(&bo->bo.vma_node);
}
int
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index ee66badc8bb..a034ed40825 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -29,6 +29,7 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct mga_device *mdev = dev->dev_private;
+ struct drm_framebuffer *fb = crtc->primary->fb;
int i;
if (!crtc->enabled)
@@ -36,6 +37,28 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
WREG8(DAC_INDEX + MGA1064_INDEX, 0);
+ if (fb && fb->bits_per_pixel == 16) {
+ int inc = (fb->depth == 15) ? 8 : 4;
+ u8 r, b;
+ for (i = 0; i < MGAG200_LUT_SIZE; i += inc) {
+ if (fb->depth == 16) {
+ if (i > (MGAG200_LUT_SIZE >> 1)) {
+ r = b = 0;
+ } else {
+ r = mga_crtc->lut_r[i << 1];
+ b = mga_crtc->lut_b[i << 1];
+ }
+ } else {
+ r = mga_crtc->lut_r[i];
+ b = mga_crtc->lut_b[i];
+ }
+ /* VGA registers */
+ WREG8(DAC_INDEX + MGA1064_COL_PAL, r);
+ WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_g[i]);
+ WREG8(DAC_INDEX + MGA1064_COL_PAL, b);
+ }
+ return;
+ }
for (i = 0; i < MGAG200_LUT_SIZE; i++) {
/* VGA registers */
WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_r[i]);
@@ -668,7 +691,7 @@ static void mga_g200wb_commit(struct drm_crtc *crtc)
CRTCEXT0 has to be programmed last to trigger an update and make the
new addr variable take effect.
*/
-void mga_set_start_address(struct drm_crtc *crtc, unsigned offset)
+static void mga_set_start_address(struct drm_crtc *crtc, unsigned offset)
{
struct mga_device *mdev = crtc->dev->dev_private;
u32 addr;
@@ -719,7 +742,7 @@ static int mga_crtc_do_set_base(struct drm_crtc *crtc,
mgag200_bo_unreserve(bo);
}
- mga_fb = to_mga_framebuffer(crtc->fb);
+ mga_fb = to_mga_framebuffer(crtc->primary->fb);
obj = mga_fb->obj;
bo = gem_to_mga_bo(obj);
@@ -742,8 +765,6 @@ static int mga_crtc_do_set_base(struct drm_crtc *crtc,
}
mgag200_bo_unreserve(bo);
- DRM_INFO("mga base %llx\n", gpu_addr);
-
mga_set_start_address(crtc, (u32)gpu_addr);
return 0;
@@ -784,7 +805,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
/* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0
};
- bppshift = mdev->bpp_shifts[(crtc->fb->bits_per_pixel >> 3) - 1];
+ bppshift = mdev->bpp_shifts[(crtc->primary->fb->bits_per_pixel >> 3) - 1];
switch (mdev->type) {
case G200_SE_A:
@@ -822,12 +843,12 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
break;
}
- switch (crtc->fb->bits_per_pixel) {
+ switch (crtc->primary->fb->bits_per_pixel) {
case 8:
dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_8bits;
break;
case 16:
- if (crtc->fb->depth == 15)
+ if (crtc->primary->fb->depth == 15)
dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_15bits;
else
dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_16bits;
@@ -875,9 +896,9 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
WREG_SEQ(3, 0);
WREG_SEQ(4, 0xe);
- pitch = crtc->fb->pitches[0] / (crtc->fb->bits_per_pixel / 8);
- if (crtc->fb->bits_per_pixel == 24)
- pitch = pitch >> (4 - bppshift);
+ pitch = crtc->primary->fb->pitches[0] / (crtc->primary->fb->bits_per_pixel / 8);
+ if (crtc->primary->fb->bits_per_pixel == 24)
+ pitch = (pitch * 3) >> (4 - bppshift);
else
pitch = pitch >> (4 - bppshift);
@@ -953,7 +974,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
((vdisplay & 0xc00) >> 7) |
((vsyncstart & 0xc00) >> 5) |
((vdisplay & 0x400) >> 3);
- if (crtc->fb->bits_per_pixel == 24)
+ if (crtc->primary->fb->bits_per_pixel == 24)
ext_vga[3] = (((1 << bppshift) * 3) - 1) | 0x80;
else
ext_vga[3] = ((1 << bppshift) - 1) | 0x80;
@@ -1008,14 +1029,14 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
if (IS_G200_SE(mdev)) {
- if (mdev->reg_1e24 >= 0x02) {
+ if (mdev->unique_rev_id >= 0x02) {
u8 hi_pri_lvl;
u32 bpp;
u32 mb;
- if (crtc->fb->bits_per_pixel > 16)
+ if (crtc->primary->fb->bits_per_pixel > 16)
bpp = 32;
- else if (crtc->fb->bits_per_pixel > 8)
+ else if (crtc->primary->fb->bits_per_pixel > 8)
bpp = 16;
else
bpp = 8;
@@ -1038,7 +1059,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
WREG8(MGAREG_CRTCEXT_DATA, hi_pri_lvl);
} else {
WREG8(MGAREG_CRTCEXT_INDEX, 0x06);
- if (mdev->reg_1e24 >= 0x01)
+ if (mdev->unique_rev_id >= 0x01)
WREG8(MGAREG_CRTCEXT_DATA, 0x03);
else
WREG8(MGAREG_CRTCEXT_DATA, 0x04);
@@ -1251,14 +1272,35 @@ static void mga_crtc_destroy(struct drm_crtc *crtc)
kfree(mga_crtc);
}
+static void mga_crtc_disable(struct drm_crtc *crtc)
+{
+ int ret;
+ DRM_DEBUG_KMS("\n");
+ mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+ if (crtc->primary->fb) {
+ struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->primary->fb);
+ struct drm_gem_object *obj = mga_fb->obj;
+ struct mgag200_bo *bo = gem_to_mga_bo(obj);
+ ret = mgag200_bo_reserve(bo, false);
+ if (ret)
+ return;
+ mgag200_bo_push_sysram(bo);
+ mgag200_bo_unreserve(bo);
+ }
+ crtc->primary->fb = NULL;
+}
+
/* These provide the minimum set of functions required to handle a CRTC */
static const struct drm_crtc_funcs mga_crtc_funcs = {
+ .cursor_set = mga_crtc_cursor_set,
+ .cursor_move = mga_crtc_cursor_move,
.gamma_set = mga_crtc_gamma_set,
.set_config = drm_crtc_helper_set_config,
.destroy = mga_crtc_destroy,
};
static const struct drm_crtc_helper_funcs mga_helper_funcs = {
+ .disable = mga_crtc_disable,
.dpms = mga_crtc_dpms,
.mode_fixup = mga_crtc_mode_fixup,
.mode_set = mga_crtc_mode_set,
@@ -1356,7 +1398,7 @@ static void mga_encoder_commit(struct drm_encoder *encoder)
{
}
-void mga_encoder_destroy(struct drm_encoder *encoder)
+static void mga_encoder_destroy(struct drm_encoder *encoder)
{
struct mga_encoder *mga_encoder = to_mga_encoder(encoder);
drm_encoder_cleanup(encoder);
@@ -1410,6 +1452,32 @@ static int mga_vga_get_modes(struct drm_connector *connector)
return ret;
}
+static uint32_t mga_vga_calculate_mode_bandwidth(struct drm_display_mode *mode,
+ int bits_per_pixel)
+{
+ uint32_t total_area, divisor;
+ int64_t active_area, pixels_per_second, bandwidth;
+ uint64_t bytes_per_pixel = (bits_per_pixel + 7) / 8;
+
+ divisor = 1024;
+
+ if (!mode->htotal || !mode->vtotal || !mode->clock)
+ return 0;
+
+ active_area = mode->hdisplay * mode->vdisplay;
+ total_area = mode->htotal * mode->vtotal;
+
+ pixels_per_second = active_area * mode->clock * 1000;
+ do_div(pixels_per_second, total_area);
+
+ bandwidth = pixels_per_second * bytes_per_pixel * 100;
+ do_div(bandwidth, divisor);
+
+ return (uint32_t)(bandwidth);
+}
+
+#define MODE_BANDWIDTH MODE_BAD
+
static int mga_vga_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
@@ -1421,7 +1489,45 @@ static int mga_vga_mode_valid(struct drm_connector *connector,
int bpp = 32;
int i = 0;
- /* FIXME: Add bandwidth and g200se limitations */
+ if (IS_G200_SE(mdev)) {
+ if (mdev->unique_rev_id == 0x01) {
+ if (mode->hdisplay > 1600)
+ return MODE_VIRTUAL_X;
+ if (mode->vdisplay > 1200)
+ return MODE_VIRTUAL_Y;
+ if (mga_vga_calculate_mode_bandwidth(mode, bpp)
+ > (24400 * 1024))
+ return MODE_BANDWIDTH;
+ } else if (mdev->unique_rev_id >= 0x02) {
+ if (mode->hdisplay > 1920)
+ return MODE_VIRTUAL_X;
+ if (mode->vdisplay > 1200)
+ return MODE_VIRTUAL_Y;
+ if (mga_vga_calculate_mode_bandwidth(mode, bpp)
+ > (30100 * 1024))
+ return MODE_BANDWIDTH;
+ }
+ } else if (mdev->type == G200_WB) {
+ if (mode->hdisplay > 1280)
+ return MODE_VIRTUAL_X;
+ if (mode->vdisplay > 1024)
+ return MODE_VIRTUAL_Y;
+ if (mga_vga_calculate_mode_bandwidth(mode,
+ bpp > (31877 * 1024)))
+ return MODE_BANDWIDTH;
+ } else if (mdev->type == G200_EV &&
+ (mga_vga_calculate_mode_bandwidth(mode, bpp)
+ > (32700 * 1024))) {
+ return MODE_BANDWIDTH;
+ } else if (mdev->type == G200_EH &&
+ (mga_vga_calculate_mode_bandwidth(mode, bpp)
+ > (37500 * 1024))) {
+ return MODE_BANDWIDTH;
+ } else if (mdev->type == G200_ER &&
+ (mga_vga_calculate_mode_bandwidth(mode,
+ bpp) > (55000 * 1024))) {
+ return MODE_BANDWIDTH;
+ }
if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 ||
mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 ||
@@ -1452,7 +1558,7 @@ static int mga_vga_mode_valid(struct drm_connector *connector,
return MODE_OK;
}
-struct drm_encoder *mga_connector_best_encoder(struct drm_connector
+static struct drm_encoder *mga_connector_best_encoder(struct drm_connector
*connector)
{
int enc_id = connector->encoder_ids[0];
@@ -1515,6 +1621,8 @@ static struct drm_connector *mga_vga_init(struct drm_device *dev)
drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs);
+ drm_sysfs_connector_add(connector);
+
mga_connector->i2c = mgag200_i2c_create(dev);
if (!mga_connector->i2c)
DRM_ERROR("failed to add ddc bus\n");
diff --git a/drivers/gpu/drm/mgag200/mgag200_reg.h b/drivers/gpu/drm/mgag200/mgag200_reg.h
index fb24d8655fe..3ae442a64bd 100644
--- a/drivers/gpu/drm/mgag200/mgag200_reg.h
+++ b/drivers/gpu/drm/mgag200/mgag200_reg.h
@@ -235,7 +235,11 @@
#define MGAREG_CRTCEXT_INDEX 0x1fde
#define MGAREG_CRTCEXT_DATA 0x1fdf
-
+/* Cursor X and Y position */
+#define MGA_CURPOSXL 0x3c0c
+#define MGA_CURPOSXH 0x3c0d
+#define MGA_CURPOSYL 0x3c0e
+#define MGA_CURPOSYH 0x3c0f
/* MGA bits for registers PCI_OPTION_REG */
#define MGA1064_OPT_SYS_CLK_PCI ( 0x00 << 0 )
diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c
index 401c9891d3a..5a00e90696d 100644
--- a/drivers/gpu/drm/mgag200/mgag200_ttm.c
+++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c
@@ -80,7 +80,7 @@ static int mgag200_ttm_global_init(struct mga_device *ast)
return 0;
}
-void
+static void
mgag200_ttm_global_release(struct mga_device *ast)
{
if (ast->ttm.mem_global_ref.release == NULL)
@@ -102,7 +102,7 @@ static void mgag200_bo_ttm_destroy(struct ttm_buffer_object *tbo)
kfree(bo);
}
-bool mgag200_ttm_bo_is_mgag200_bo(struct ttm_buffer_object *bo)
+static bool mgag200_ttm_bo_is_mgag200_bo(struct ttm_buffer_object *bo)
{
if (bo->destroy == &mgag200_bo_ttm_destroy)
return true;
@@ -148,7 +148,9 @@ mgag200_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
static int mgag200_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
{
- return 0;
+ struct mgag200_bo *mgabo = mgag200_bo(bo);
+
+ return drm_vma_node_verify_access(&mgabo->gem.vma_node, filp);
}
static int mgag200_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
@@ -206,7 +208,7 @@ static struct ttm_backend_func mgag200_tt_backend_func = {
};
-struct ttm_tt *mgag200_ttm_tt_create(struct ttm_bo_device *bdev,
+static struct ttm_tt *mgag200_ttm_tt_create(struct ttm_bo_device *bdev,
unsigned long size, uint32_t page_flags,
struct page *dummy_read_page)
{
@@ -257,7 +259,9 @@ int mgag200_mm_init(struct mga_device *mdev)
ret = ttm_bo_device_init(&mdev->ttm.bdev,
mdev->ttm.bo_global_ref.ref.object,
- &mgag200_bo_driver, DRM_FILE_PAGE_OFFSET,
+ &mgag200_bo_driver,
+ dev->anon_inode->i_mapping,
+ DRM_FILE_PAGE_OFFSET,
true);
if (ret) {
DRM_ERROR("Error initialising bo driver; %d\n", ret);
@@ -270,26 +274,20 @@ int mgag200_mm_init(struct mga_device *mdev)
return ret;
}
- mdev->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0),
- pci_resource_len(dev->pdev, 0),
- DRM_MTRR_WC);
+ mdev->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0));
return 0;
}
void mgag200_mm_fini(struct mga_device *mdev)
{
- struct drm_device *dev = mdev->dev;
ttm_bo_device_release(&mdev->ttm.bdev);
mgag200_ttm_global_release(mdev);
- if (mdev->fb_mtrr >= 0) {
- drm_mtrr_del(mdev->fb_mtrr,
- pci_resource_start(dev->pdev, 0),
- pci_resource_len(dev->pdev, 0), DRM_MTRR_WC);
- mdev->fb_mtrr = -1;
- }
+ arch_phys_wc_del(mdev->fb_mtrr);
+ mdev->fb_mtrr = 0;
}
void mgag200_ttm_placement(struct mgag200_bo *bo, int domain)
@@ -309,24 +307,6 @@ void mgag200_ttm_placement(struct mgag200_bo *bo, int domain)
bo->placement.num_busy_placement = c;
}
-int mgag200_bo_reserve(struct mgag200_bo *bo, bool no_wait)
-{
- int ret;
-
- ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
- if (ret) {
- if (ret != -ERESTARTSYS && ret != -EBUSY)
- DRM_ERROR("reserve failed %p %d\n", bo, ret);
- return ret;
- }
- return 0;
-}
-
-void mgag200_bo_unreserve(struct mgag200_bo *bo)
-{
- ttm_bo_unreserve(&bo->bo);
-}
-
int mgag200_bo_create(struct drm_device *dev, int size, int align,
uint32_t flags, struct mgag200_bo **pmgabo)
{
@@ -345,7 +325,6 @@ int mgag200_bo_create(struct drm_device *dev, int size, int align,
return ret;
}
- mgabo->gem.driver_private = NULL;
mgabo->bo.bdev = &mdev->ttm.bdev;
mgag200_ttm_placement(mgabo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
@@ -377,6 +356,7 @@ int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr)
bo->pin_count++;
if (gpu_addr)
*gpu_addr = mgag200_bo_gpu_offset(bo);
+ return 0;
}
mgag200_ttm_placement(bo, pl_flag);