summaryrefslogtreecommitdiff
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/Kconfig4
-rw-r--r--drivers/gpu/drm/mgag200/Makefile3
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_cursor.c319
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.c204
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.h62
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_main.c160
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mm.c127
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c995
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_reg.h22
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_ttm.c70
10 files changed, 801 insertions, 1165 deletions
diff --git a/drivers/gpu/drm/mgag200/Kconfig b/drivers/gpu/drm/mgag200/Kconfig
index d60aa4b9ccd4..93be766715c9 100644
--- a/drivers/gpu/drm/mgag200/Kconfig
+++ b/drivers/gpu/drm/mgag200/Kconfig
@@ -2,10 +2,8 @@
config DRM_MGAG200
tristate "Kernel modesetting driver for MGA G200 server engines"
depends on DRM && PCI && MMU
+ select DRM_GEM_SHMEM_HELPER
select DRM_KMS_HELPER
- select DRM_VRAM_HELPER
- select DRM_TTM
- select DRM_TTM_HELPER
help
This is a KMS driver for the MGA G200 server chips, it
does not support the original MGA G200 or any of the desktop
diff --git a/drivers/gpu/drm/mgag200/Makefile b/drivers/gpu/drm/mgag200/Makefile
index 04b281bcf655..42fedef53882 100644
--- a/drivers/gpu/drm/mgag200/Makefile
+++ b/drivers/gpu/drm/mgag200/Makefile
@@ -1,5 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-mgag200-y := mgag200_main.o mgag200_mode.o mgag200_cursor.o \
- mgag200_drv.o mgag200_i2c.o mgag200_ttm.o
+mgag200-y := mgag200_drv.o mgag200_i2c.o mgag200_mm.o mgag200_mode.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
deleted file mode 100644
index aebc9ce43d55..000000000000
--- a/drivers/gpu/drm/mgag200/mgag200_cursor.c
+++ /dev/null
@@ -1,319 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright 2013 Matrox Graphics
- *
- * Author: Christopher Harvey <charvey@matrox.com>
- */
-
-#include <linux/pci.h>
-
-#include "mgag200_drv.h"
-
-static bool warn_transparent = true;
-static bool warn_palette = true;
-
-static int mgag200_cursor_update(struct mga_device *mdev, void *dst, void *src,
- unsigned int width, unsigned int height)
-{
- struct drm_device *dev = mdev->dev;
- 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;
- u8 reg_index;
- u8 this_row[48];
-
- memset(&colour_set[0], 0, sizeof(uint32_t)*16);
- /* width*height*4 = 16384 */
- for (i = 0; i < 16384; i += 4) {
- this_colour = ioread32(src + 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. */
- }
- return -EINVAL;
- }
- /* 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. */
- }
- return -EINVAL;
- }
- *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);
- }
-
- /* 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(src + 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(dst + row*48, &this_row[0], 48);
- }
-
- return 0;
-}
-
-static void mgag200_cursor_set_base(struct mga_device *mdev, u64 address)
-{
- u8 addrl = (address >> 10) & 0xff;
- u8 addrh = (address >> 18) & 0x3f;
-
- /* Program gpu address of cursor buffer */
- WREG_DAC(MGA1064_CURSOR_BASE_ADR_LOW, addrl);
- WREG_DAC(MGA1064_CURSOR_BASE_ADR_HI, addrh);
-}
-
-static int mgag200_show_cursor(struct mga_device *mdev, void *src,
- unsigned int width, unsigned int height)
-{
- struct drm_device *dev = mdev->dev;
- struct drm_gem_vram_object *gbo;
- void *dst;
- s64 off;
- int ret;
-
- gbo = mdev->cursor.gbo[mdev->cursor.next_index];
- if (!gbo) {
- WREG8(MGA_CURPOSXL, 0);
- WREG8(MGA_CURPOSXH, 0);
- return -ENOTSUPP; /* Didn't allocate space for cursors */
- }
- dst = drm_gem_vram_vmap(gbo);
- if (IS_ERR(dst)) {
- ret = PTR_ERR(dst);
- dev_err(&dev->pdev->dev,
- "failed to map cursor updates: %d\n", ret);
- return ret;
- }
- off = drm_gem_vram_offset(gbo);
- if (off < 0) {
- ret = (int)off;
- dev_err(&dev->pdev->dev,
- "failed to get cursor scanout address: %d\n", ret);
- goto err_drm_gem_vram_vunmap;
- }
-
- ret = mgag200_cursor_update(mdev, dst, src, width, height);
- if (ret)
- goto err_drm_gem_vram_vunmap;
- mgag200_cursor_set_base(mdev, off);
-
- /* Adjust cursor control register to turn on the cursor */
- WREG_DAC(MGA1064_CURSOR_CTL, 4); /* 16-colour palletized cursor mode */
-
- drm_gem_vram_vunmap(gbo, dst);
-
- ++mdev->cursor.next_index;
- mdev->cursor.next_index %= ARRAY_SIZE(mdev->cursor.gbo);
-
- return 0;
-
-err_drm_gem_vram_vunmap:
- drm_gem_vram_vunmap(gbo, dst);
- return ret;
-}
-
-/*
- * 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 mgag200_hide_cursor(struct mga_device *mdev)
-{
- WREG8(MGA_CURPOSXL, 0);
- WREG8(MGA_CURPOSXH, 0);
-}
-
-static void mgag200_move_cursor(struct mga_device *mdev, int x, int y)
-{
- if (WARN_ON(x <= 0))
- return;
- if (WARN_ON(y <= 0))
- return;
- if (WARN_ON(x & ~0xffff))
- return;
- if (WARN_ON(y & ~0xffff))
- return;
-
- WREG8(MGA_CURPOSXL, x & 0xff);
- WREG8(MGA_CURPOSXH, (x>>8) & 0xff);
-
- WREG8(MGA_CURPOSYL, y & 0xff);
- WREG8(MGA_CURPOSYH, (y>>8) & 0xff);
-}
-
-int mgag200_cursor_init(struct mga_device *mdev)
-{
- struct drm_device *dev = mdev->dev;
- size_t ncursors = ARRAY_SIZE(mdev->cursor.gbo);
- size_t size;
- int ret;
- size_t i;
- struct drm_gem_vram_object *gbo;
-
- size = roundup(64 * 48, PAGE_SIZE);
- if (size * ncursors > mdev->vram_fb_available)
- return -ENOMEM;
-
- for (i = 0; i < ncursors; ++i) {
- gbo = drm_gem_vram_create(dev, size, 0);
- if (IS_ERR(gbo)) {
- ret = PTR_ERR(gbo);
- goto err_drm_gem_vram_put;
- }
- ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM |
- DRM_GEM_VRAM_PL_FLAG_TOPDOWN);
- if (ret) {
- drm_gem_vram_put(gbo);
- goto err_drm_gem_vram_put;
- }
-
- mdev->cursor.gbo[i] = gbo;
- }
-
- /*
- * At the high end of video memory, we reserve space for
- * buffer objects. The cursor plane uses this memory to store
- * a double-buffered image of the current cursor. Hence, it's
- * not available for framebuffers.
- */
- mdev->vram_fb_available -= ncursors * size;
-
- return 0;
-
-err_drm_gem_vram_put:
- while (i) {
- --i;
- gbo = mdev->cursor.gbo[i];
- drm_gem_vram_unpin(gbo);
- drm_gem_vram_put(gbo);
- mdev->cursor.gbo[i] = NULL;
- }
- return ret;
-}
-
-void mgag200_cursor_fini(struct mga_device *mdev)
-{
- size_t i;
- struct drm_gem_vram_object *gbo;
-
- for (i = 0; i < ARRAY_SIZE(mdev->cursor.gbo); ++i) {
- gbo = mdev->cursor.gbo[i];
- drm_gem_vram_unpin(gbo);
- drm_gem_vram_put(gbo);
- }
-}
-
-int mgag200_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 = to_mga_device(dev);
- struct drm_gem_object *obj;
- struct drm_gem_vram_object *gbo = NULL;
- int ret;
- u8 *src;
-
- if (!handle || !file_priv) {
- mgag200_hide_cursor(mdev);
- return 0;
- }
-
- if (width != 64 || height != 64) {
- WREG8(MGA_CURPOSXL, 0);
- WREG8(MGA_CURPOSXH, 0);
- return -EINVAL;
- }
-
- obj = drm_gem_object_lookup(file_priv, handle);
- if (!obj)
- return -ENOENT;
- gbo = drm_gem_vram_of_gem(obj);
- src = drm_gem_vram_vmap(gbo);
- if (IS_ERR(src)) {
- ret = PTR_ERR(src);
- dev_err(&dev->pdev->dev,
- "failed to map user buffer updates\n");
- goto err_drm_gem_object_put_unlocked;
- }
-
- ret = mgag200_show_cursor(mdev, src, width, height);
- if (ret)
- goto err_drm_gem_vram_vunmap;
-
- /* Now update internal buffer pointers */
- drm_gem_vram_vunmap(gbo, src);
- drm_gem_object_put_unlocked(obj);
-
- return 0;
-err_drm_gem_vram_vunmap:
- drm_gem_vram_vunmap(gbo, src);
-err_drm_gem_object_put_unlocked:
- drm_gem_object_put_unlocked(obj);
- return ret;
-}
-
-int mgag200_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
-{
- struct mga_device *mdev = to_mga_device(crtc->dev);
-
- /* Our origin is at (64,64) */
- x += 64;
- y += 64;
-
- mgag200_move_cursor(mdev, x, y);
-
- return 0;
-}
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
index c2f0e4b40b05..e19660f4a637 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -17,23 +17,105 @@
#include "mgag200_drv.h"
-/*
- * This is the generic driver code. This binds the driver to the drm core,
- * which then performs further device association and calls our graphics init
- * functions
- */
int mgag200_modeset = -1;
-
MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
module_param_named(modeset, mgag200_modeset, int, 0400);
-int mgag200_hw_bug_no_startadd = -1;
-MODULE_PARM_DESC(modeset, "HW does not interpret scanout-buffer start address correctly");
-module_param_named(hw_bug_no_startadd, mgag200_hw_bug_no_startadd, int, 0400);
+/*
+ * DRM driver
+ */
+
+DEFINE_DRM_GEM_FOPS(mgag200_driver_fops);
+
+static struct drm_driver mgag200_driver = {
+ .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
+ .fops = &mgag200_driver_fops,
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+ .patchlevel = DRIVER_PATCHLEVEL,
+ DRM_GEM_SHMEM_DRIVER_OPS,
+};
+
+/*
+ * DRM device
+ */
+
+static int mgag200_device_init(struct mga_device *mdev, unsigned long flags)
+{
+ struct drm_device *dev = &mdev->base;
+ int ret, option;
+
+ mdev->flags = mgag200_flags_from_driver_data(flags);
+ mdev->type = mgag200_type_from_driver_data(flags);
+
+ pci_read_config_dword(dev->pdev, PCI_MGA_OPTION, &option);
+ mdev->has_sdram = !(option & (1 << 14));
+
+ /* BAR 0 is the framebuffer, BAR 1 contains registers */
+ mdev->rmmio_base = pci_resource_start(dev->pdev, 1);
+ mdev->rmmio_size = pci_resource_len(dev->pdev, 1);
+
+ if (!devm_request_mem_region(dev->dev, mdev->rmmio_base,
+ mdev->rmmio_size, "mgadrmfb_mmio")) {
+ drm_err(dev, "can't reserve mmio registers\n");
+ return -ENOMEM;
+ }
+
+ mdev->rmmio = pcim_iomap(dev->pdev, 1, 0);
+ if (mdev->rmmio == NULL)
+ return -ENOMEM;
+
+ /* stash G200 SE model number for later use */
+ if (IS_G200_SE(mdev)) {
+ mdev->unique_rev_id = RREG32(0x1e24);
+ drm_dbg(dev, "G200 SE unique revision id is 0x%x\n",
+ mdev->unique_rev_id);
+ }
+
+ ret = mgag200_mm_init(mdev);
+ if (ret)
+ return ret;
+
+ ret = mgag200_modeset_init(mdev);
+ if (ret) {
+ drm_err(dev, "Fatal error during modeset init: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct mga_device *
+mgag200_device_create(struct pci_dev *pdev, unsigned long flags)
+{
+ struct drm_device *dev;
+ struct mga_device *mdev;
+ int ret;
+
+ mdev = devm_drm_dev_alloc(&pdev->dev, &mgag200_driver,
+ struct mga_device, base);
+ if (IS_ERR(mdev))
+ return mdev;
+ dev = &mdev->base;
+
+ dev->pdev = pdev;
+ pci_set_drvdata(pdev, dev);
-static struct drm_driver driver;
+ ret = mgag200_device_init(mdev, flags);
+ if (ret)
+ return ERR_PTR(ret);
-static const struct pci_device_id pciidlist[] = {
+ return mdev;
+}
+
+/*
+ * PCI driver
+ */
+
+static const struct pci_device_id mgag200_pciidlist[] = {
{ PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
G200_SE_A | MGAG200_FLAG_HW_BUG_NO_STARTADD},
{ PCI_VENDOR_ID_MATROX, 0x524, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_B },
@@ -46,119 +128,47 @@ static const struct pci_device_id pciidlist[] = {
{0,}
};
-MODULE_DEVICE_TABLE(pci, pciidlist);
-
+MODULE_DEVICE_TABLE(pci, mgag200_pciidlist);
-static int mga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int
+mgag200_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
+ struct mga_device *mdev;
struct drm_device *dev;
int ret;
drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "mgag200drmfb");
- ret = pci_enable_device(pdev);
+ ret = pcim_enable_device(pdev);
if (ret)
return ret;
- dev = drm_dev_alloc(&driver, &pdev->dev);
- if (IS_ERR(dev)) {
- ret = PTR_ERR(dev);
- goto err_pci_disable_device;
- }
-
- dev->pdev = pdev;
- pci_set_drvdata(pdev, dev);
-
- ret = mgag200_driver_load(dev, ent->driver_data);
- if (ret)
- goto err_drm_dev_put;
+ mdev = mgag200_device_create(pdev, ent->driver_data);
+ if (IS_ERR(mdev))
+ return PTR_ERR(mdev);
+ dev = &mdev->base;
ret = drm_dev_register(dev, ent->driver_data);
if (ret)
- goto err_mgag200_driver_unload;
+ return ret;
drm_fbdev_generic_setup(dev, 0);
return 0;
-
-err_mgag200_driver_unload:
- mgag200_driver_unload(dev);
-err_drm_dev_put:
- drm_dev_put(dev);
-err_pci_disable_device:
- pci_disable_device(pdev);
- return ret;
}
-static void mga_pci_remove(struct pci_dev *pdev)
+static void mgag200_pci_remove(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
drm_dev_unregister(dev);
- mgag200_driver_unload(dev);
- drm_dev_put(dev);
-}
-
-DEFINE_DRM_GEM_FOPS(mgag200_driver_fops);
-
-static bool mgag200_pin_bo_at_0(const struct mga_device *mdev)
-{
- if (mgag200_hw_bug_no_startadd > 0) {
- DRM_WARN_ONCE("Option hw_bug_no_startradd is enabled. Please "
- "report the output of 'lspci -vvnn' to "
- "<dri-devel@lists.freedesktop.org> if this "
- "option is required to make mgag200 work "
- "correctly on your system.\n");
- return true;
- } else if (!mgag200_hw_bug_no_startadd) {
- return false;
- }
- return mdev->flags & MGAG200_FLAG_HW_BUG_NO_STARTADD;
}
-int mgag200_driver_dumb_create(struct drm_file *file,
- struct drm_device *dev,
- struct drm_mode_create_dumb *args)
-{
- struct mga_device *mdev = to_mga_device(dev);
- unsigned long pg_align;
-
- if (WARN_ONCE(!dev->vram_mm, "VRAM MM not initialized"))
- return -EINVAL;
-
- pg_align = 0ul;
-
- /*
- * Aligning scanout buffers to the size of the video ram forces
- * placement at offset 0. Works around a bug where HW does not
- * respect 'startadd' field.
- */
- if (mgag200_pin_bo_at_0(mdev))
- pg_align = PFN_UP(mdev->mc.vram_size);
-
- return drm_gem_vram_fill_create_dumb(file, dev, pg_align, 0, args);
-}
-
-static struct drm_driver driver = {
- .driver_features = DRIVER_GEM | DRIVER_MODESET,
- .fops = &mgag200_driver_fops,
- .name = DRIVER_NAME,
- .desc = DRIVER_DESC,
- .date = DRIVER_DATE,
- .major = DRIVER_MAJOR,
- .minor = DRIVER_MINOR,
- .patchlevel = DRIVER_PATCHLEVEL,
- .debugfs_init = drm_vram_mm_debugfs_init,
- .dumb_create = mgag200_driver_dumb_create,
- .dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset,
- .gem_prime_mmap = drm_gem_prime_mmap,
-};
-
static struct pci_driver mgag200_pci_driver = {
.name = DRIVER_NAME,
- .id_table = pciidlist,
- .probe = mga_pci_probe,
- .remove = mga_pci_remove,
+ .id_table = mgag200_pciidlist,
+ .probe = mgag200_pci_probe,
+ .remove = mgag200_pci_remove,
};
static int __init mgag200_init(void)
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
index d9b7e96b214f..3817520bfefc 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -18,7 +18,8 @@
#include <drm/drm_encoder.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem.h>
-#include <drm/drm_gem_vram_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_simple_kms_helper.h>
#include "mgag200_reg.h"
@@ -32,8 +33,6 @@
#define DRIVER_MINOR 0
#define DRIVER_PATCHLEVEL 0
-#define MGAG200FB_CONN_LIMIT 1
-
#define RREG8(reg) ioread8(((void __iomem *)mdev->rmmio) + (reg))
#define WREG8(reg, v) iowrite8(v, ((void __iomem *)mdev->rmmio) + (reg))
#define RREG32(reg) ioread32(((void __iomem *)mdev->rmmio) + (reg))
@@ -49,18 +48,35 @@
WREG8(ATTR_DATA, v); \
} while (0) \
+#define RREG_SEQ(reg, v) \
+ do { \
+ WREG8(MGAREG_SEQ_INDEX, reg); \
+ v = RREG8(MGAREG_SEQ_DATA); \
+ } while (0) \
+
#define WREG_SEQ(reg, v) \
do { \
WREG8(MGAREG_SEQ_INDEX, reg); \
WREG8(MGAREG_SEQ_DATA, v); \
} while (0) \
+#define RREG_CRT(reg, v) \
+ do { \
+ WREG8(MGAREG_CRTC_INDEX, reg); \
+ v = RREG8(MGAREG_CRTC_DATA); \
+ } while (0) \
+
#define WREG_CRT(reg, v) \
do { \
WREG8(MGAREG_CRTC_INDEX, reg); \
WREG8(MGAREG_CRTC_DATA, v); \
} while (0) \
+#define RREG_ECRT(reg, v) \
+ do { \
+ WREG8(MGAREG_CRTCEXT_INDEX, reg); \
+ v = RREG8(MGAREG_CRTCEXT_DATA); \
+ } while (0) \
#define WREG_ECRT(reg, v) \
do { \
@@ -92,18 +108,8 @@
#define MGAG200_MAX_FB_HEIGHT 4096
#define MGAG200_MAX_FB_WIDTH 4096
-#define MATROX_DPMS_CLEARED (-1)
-
-#define to_mga_crtc(x) container_of(x, struct mga_crtc, base)
#define to_mga_connector(x) container_of(x, struct mga_connector, base)
-struct mga_crtc {
- struct drm_crtc base;
- u8 lut_r[256], lut_g[256], lut_b[256];
- int last_dpms;
- bool enabled;
-};
-
struct mga_i2c_chan {
struct i2c_adapter adapter;
struct drm_device *dev;
@@ -116,11 +122,6 @@ struct mga_connector {
struct mga_i2c_chan *i2c;
};
-struct mga_cursor {
- struct drm_gem_vram_object *gbo[2];
- unsigned int next_index;
-};
-
struct mga_mc {
resource_size_t vram_size;
resource_size_t vram_base;
@@ -147,7 +148,7 @@ enum mga_type {
#define IS_G200_SE(mdev) (mdev->type == G200_SE_A || mdev->type == G200_SE_B)
struct mga_device {
- struct drm_device *dev;
+ struct drm_device base;
unsigned long flags;
resource_size_t rmmio_base;
@@ -156,11 +157,9 @@ struct mga_device {
struct mga_mc mc;
- struct mga_cursor cursor;
+ void __iomem *vram;
+ size_t vram_fb_available;
- size_t vram_fb_available;
-
- bool suspended;
enum mga_type type;
int has_sdram;
@@ -172,12 +171,12 @@ struct mga_device {
u32 unique_rev_id;
struct mga_connector connector;
- struct drm_encoder encoder;
+ struct drm_simple_display_pipe display_pipe;
};
static inline struct mga_device *to_mga_device(struct drm_device *dev)
{
- return dev->dev_private;
+ return container_of(dev, struct mga_device, base);
}
static inline enum mga_type
@@ -195,22 +194,11 @@ mgag200_flags_from_driver_data(kernel_ulong_t driver_data)
/* mgag200_mode.c */
int mgag200_modeset_init(struct mga_device *mdev);
- /* mgag200_main.c */
-int mgag200_driver_load(struct drm_device *dev, unsigned long flags);
-void mgag200_driver_unload(struct drm_device *dev);
-
/* mgag200_i2c.c */
struct mga_i2c_chan *mgag200_i2c_create(struct drm_device *dev);
void mgag200_i2c_destroy(struct mga_i2c_chan *i2c);
+ /* mgag200_mm.c */
int mgag200_mm_init(struct mga_device *mdev);
-void mgag200_mm_fini(struct mga_device *mdev);
-int mgag200_mmap(struct file *filp, struct vm_area_struct *vma);
-
-int mgag200_cursor_init(struct mga_device *mdev);
-void mgag200_cursor_fini(struct mga_device *mdev);
-int mgag200_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
- uint32_t handle, uint32_t width, uint32_t height);
-int mgag200_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);
#endif /* __MGAG200_DRV_H__ */
diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c
deleted file mode 100644
index 86df799fd38c..000000000000
--- a/drivers/gpu/drm/mgag200/mgag200_main.c
+++ /dev/null
@@ -1,160 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright 2010 Matt Turner.
- * Copyright 2012 Red Hat
- *
- * Authors: Matthew Garrett
- * Matt Turner
- * Dave Airlie
- */
-
-#include <linux/pci.h>
-
-#include "mgag200_drv.h"
-
-static int mga_probe_vram(struct mga_device *mdev, void __iomem *mem)
-{
- int offset;
- int orig;
- int test1, test2;
- int orig1, orig2;
- unsigned int vram_size;
-
- /* Probe */
- orig = ioread16(mem);
- iowrite16(0, mem);
-
- vram_size = mdev->mc.vram_window;
-
- if ((mdev->type == G200_EW3) && (vram_size >= 0x1000000)) {
- vram_size = vram_size - 0x400000;
- }
-
- for (offset = 0x100000; offset < vram_size; offset += 0x4000) {
- orig1 = ioread8(mem + offset);
- orig2 = ioread8(mem + offset + 0x100);
-
- iowrite16(0xaa55, mem + offset);
- iowrite16(0xaa55, mem + offset + 0x100);
-
- test1 = ioread16(mem + offset);
- test2 = ioread16(mem);
-
- iowrite16(orig1, mem + offset);
- iowrite16(orig2, mem + offset + 0x100);
-
- if (test1 != 0xaa55) {
- break;
- }
-
- if (test2) {
- break;
- }
- }
-
- iowrite16(orig, mem);
- return offset - 65536;
-}
-
-/* Map the framebuffer from the card and configure the core */
-static int mga_vram_init(struct mga_device *mdev)
-{
- struct drm_device *dev = mdev->dev;
- void __iomem *mem;
-
- /* BAR 0 is VRAM */
- mdev->mc.vram_base = pci_resource_start(dev->pdev, 0);
- mdev->mc.vram_window = pci_resource_len(dev->pdev, 0);
-
- if (!devm_request_mem_region(dev->dev, mdev->mc.vram_base,
- mdev->mc.vram_window, "mgadrmfb_vram")) {
- DRM_ERROR("can't reserve VRAM\n");
- return -ENXIO;
- }
-
- mem = pci_iomap(dev->pdev, 0, 0);
- if (!mem)
- return -ENOMEM;
-
- mdev->mc.vram_size = mga_probe_vram(mdev, mem);
-
- pci_iounmap(dev->pdev, mem);
-
- return 0;
-}
-
-int mgag200_driver_load(struct drm_device *dev, unsigned long flags)
-{
- struct mga_device *mdev;
- int ret, option;
-
- mdev = devm_kzalloc(dev->dev, sizeof(struct mga_device), GFP_KERNEL);
- if (mdev == NULL)
- return -ENOMEM;
- dev->dev_private = (void *)mdev;
- mdev->dev = dev;
-
- mdev->flags = mgag200_flags_from_driver_data(flags);
- mdev->type = mgag200_type_from_driver_data(flags);
-
- pci_read_config_dword(dev->pdev, PCI_MGA_OPTION, &option);
- mdev->has_sdram = !(option & (1 << 14));
-
- /* BAR 0 is the framebuffer, BAR 1 contains registers */
- mdev->rmmio_base = pci_resource_start(dev->pdev, 1);
- mdev->rmmio_size = pci_resource_len(dev->pdev, 1);
-
- if (!devm_request_mem_region(dev->dev, mdev->rmmio_base,
- mdev->rmmio_size, "mgadrmfb_mmio")) {
- drm_err(dev, "can't reserve mmio registers\n");
- return -ENOMEM;
- }
-
- mdev->rmmio = pcim_iomap(dev->pdev, 1, 0);
- if (mdev->rmmio == NULL)
- return -ENOMEM;
-
- /* stash G200 SE model number for later use */
- if (IS_G200_SE(mdev)) {
- mdev->unique_rev_id = RREG32(0x1e24);
- drm_dbg(dev, "G200 SE unique revision id is 0x%x\n",
- mdev->unique_rev_id);
- }
-
- ret = mga_vram_init(mdev);
- if (ret)
- return ret;
-
- ret = mgag200_mm_init(mdev);
- if (ret)
- goto err_mm;
-
- ret = mgag200_modeset_init(mdev);
- if (ret) {
- drm_err(dev, "Fatal error during modeset init: %d\n", ret);
- goto err_mgag200_mm_fini;
- }
-
- ret = mgag200_cursor_init(mdev);
- if (ret)
- drm_err(dev, "Could not initialize cursors. Not doing hardware cursors.\n");
-
- return 0;
-
-err_mgag200_mm_fini:
- mgag200_mm_fini(mdev);
-err_mm:
- dev->dev_private = NULL;
- return ret;
-}
-
-void mgag200_driver_unload(struct drm_device *dev)
-{
- struct mga_device *mdev = to_mga_device(dev);
-
- if (mdev == NULL)
- return;
- mgag200_cursor_fini(mdev);
- mgag200_mm_fini(mdev);
- dev->dev_private = NULL;
-}
diff --git a/drivers/gpu/drm/mgag200/mgag200_mm.c b/drivers/gpu/drm/mgag200/mgag200_mm.c
new file mode 100644
index 000000000000..7b69392bcb89
--- /dev/null
+++ b/drivers/gpu/drm/mgag200/mgag200_mm.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2012 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+
+#include <linux/pci.h>
+
+#include <drm/drm_managed.h>
+
+#include "mgag200_drv.h"
+
+static size_t mgag200_probe_vram(struct mga_device *mdev, void __iomem *mem,
+ size_t size)
+{
+ int offset;
+ int orig;
+ int test1, test2;
+ int orig1, orig2;
+ size_t vram_size;
+
+ /* Probe */
+ orig = ioread16(mem);
+ iowrite16(0, mem);
+
+ vram_size = size;
+
+ if ((mdev->type == G200_EW3) && (vram_size >= 0x1000000))
+ vram_size = vram_size - 0x400000;
+
+ for (offset = 0x100000; offset < vram_size; offset += 0x4000) {
+ orig1 = ioread8(mem + offset);
+ orig2 = ioread8(mem + offset + 0x100);
+
+ iowrite16(0xaa55, mem + offset);
+ iowrite16(0xaa55, mem + offset + 0x100);
+
+ test1 = ioread16(mem + offset);
+ test2 = ioread16(mem);
+
+ iowrite16(orig1, mem + offset);
+ iowrite16(orig2, mem + offset + 0x100);
+
+ if (test1 != 0xaa55)
+ break;
+
+ if (test2)
+ break;
+ }
+
+ iowrite16(orig, mem);
+
+ return offset - 65536;
+}
+
+static void mgag200_mm_release(struct drm_device *dev, void *ptr)
+{
+ struct mga_device *mdev = to_mga_device(dev);
+
+ mdev->vram_fb_available = 0;
+ iounmap(mdev->vram);
+ arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0));
+ arch_phys_wc_del(mdev->fb_mtrr);
+ mdev->fb_mtrr = 0;
+}
+
+int mgag200_mm_init(struct mga_device *mdev)
+{
+ struct drm_device *dev = &mdev->base;
+ resource_size_t start, len;
+ int ret;
+
+ /* BAR 0 is VRAM */
+ start = pci_resource_start(dev->pdev, 0);
+ len = pci_resource_len(dev->pdev, 0);
+
+ if (!devm_request_mem_region(dev->dev, start, len, "mgadrmfb_vram")) {
+ drm_err(dev, "can't reserve VRAM\n");
+ return -ENXIO;
+ }
+
+ arch_io_reserve_memtype_wc(start, len);
+
+ mdev->fb_mtrr = arch_phys_wc_add(start, len);
+
+ mdev->vram = ioremap(start, len);
+ if (!mdev->vram) {
+ ret = -ENOMEM;
+ goto err_arch_phys_wc_del;
+ }
+
+ mdev->mc.vram_size = mgag200_probe_vram(mdev, mdev->vram, len);
+ mdev->mc.vram_base = start;
+ mdev->mc.vram_window = len;
+
+ mdev->vram_fb_available = mdev->mc.vram_size;
+
+ return drmm_add_action_or_reset(dev, mgag200_mm_release, NULL);
+
+err_arch_phys_wc_del:
+ arch_phys_wc_del(mdev->fb_mtrr);
+ arch_io_free_memtype_wc(start, len);
+ return ret;
+}
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 5f4ac36a9776..e0d037a7413c 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -11,10 +11,15 @@
#include <linux/delay.h>
#include <linux/pci.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_format_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
@@ -30,13 +35,18 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct mga_device *mdev = to_mga_device(dev);
- struct drm_framebuffer *fb = crtc->primary->fb;
+ struct drm_framebuffer *fb;
u16 *r_ptr, *g_ptr, *b_ptr;
int i;
if (!crtc->enabled)
return;
+ if (!mdev->display_pipe.plane.state)
+ return;
+
+ fb = mdev->display_pipe.plane.state->fb;
+
r_ptr = crtc->gamma_store;
g_ptr = r_ptr + crtc->gamma_size;
b_ptr = g_ptr + crtc->gamma_size;
@@ -702,8 +712,10 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock)
return 0;
}
-static int mga_crtc_set_plls(struct mga_device *mdev, long clock)
+static int mgag200_crtc_set_plls(struct mga_device *mdev, long clock)
{
+ u8 misc;
+
switch(mdev->type) {
case G200_SE_A:
case G200_SE_B:
@@ -724,12 +736,17 @@ static int mga_crtc_set_plls(struct mga_device *mdev, long clock)
return mga_g200er_set_plls(mdev, clock);
break;
}
+
+ misc = RREG8(MGA_MISC_IN);
+ misc &= ~MGAREG_MISC_CLK_SEL_MASK;
+ misc |= MGAREG_MISC_CLK_SEL_MGA_MSK;
+ WREG8(MGA_MISC_OUT, misc);
+
return 0;
}
-static void mga_g200wb_prepare(struct drm_crtc *crtc)
+static void mgag200_g200wb_hold_bmc(struct mga_device *mdev)
{
- struct mga_device *mdev = to_mga_device(crtc->dev);
u8 tmp;
int iter_max;
@@ -781,10 +798,9 @@ static void mga_g200wb_prepare(struct drm_crtc *crtc)
}
}
-static void mga_g200wb_commit(struct drm_crtc *crtc)
+static void mgag200_g200wb_release_bmc(struct mga_device *mdev)
{
u8 tmp;
- struct mga_device *mdev = to_mga_device(crtc->dev);
/* 1- The first step is to ensure that the vrsten and hrsten are set */
WREG8(MGAREG_CRTCEXT_INDEX, 1);
@@ -819,102 +835,91 @@ static void mga_g200wb_commit(struct drm_crtc *crtc)
}
/*
- This is how the framebuffer base address is stored in g200 cards:
- * Assume @offset is the gpu_addr variable of the framebuffer object
- * Then addr is the number of _pixels_ (not bytes) from the start of
- VRAM to the first pixel we want to display. (divided by 2 for 32bit
- framebuffers)
- * addr is stored in the CRTCEXT0, CRTCC and CRTCD registers
- addr<20> -> CRTCEXT0<6>
- addr<19-16> -> CRTCEXT0<3-0>
- addr<15-8> -> CRTCC<7-0>
- addr<7-0> -> CRTCD<7-0>
- CRTCEXT0 has to be programmed last to trigger an update and make the
- new addr variable take effect.
+ * This is how the framebuffer base address is stored in g200 cards:
+ * * Assume @offset is the gpu_addr variable of the framebuffer object
+ * * Then addr is the number of _pixels_ (not bytes) from the start of
+ * VRAM to the first pixel we want to display. (divided by 2 for 32bit
+ * framebuffers)
+ * * addr is stored in the CRTCEXT0, CRTCC and CRTCD registers
+ * addr<20> -> CRTCEXT0<6>
+ * addr<19-16> -> CRTCEXT0<3-0>
+ * addr<15-8> -> CRTCC<7-0>
+ * addr<7-0> -> CRTCD<7-0>
+ *
+ * CRTCEXT0 has to be programmed last to trigger an update and make the
+ * new addr variable take effect.
*/
-static void mga_set_start_address(struct drm_crtc *crtc, unsigned offset)
+static void mgag200_set_startadd(struct mga_device *mdev,
+ unsigned long offset)
{
- struct mga_device *mdev = to_mga_device(crtc->dev);
- u32 addr;
- int count;
- u8 crtcext0;
-
- while (RREG8(0x1fda) & 0x08);
- while (!(RREG8(0x1fda) & 0x08));
-
- count = RREG8(MGAREG_VCOUNT) + 2;
- while (RREG8(MGAREG_VCOUNT) < count);
-
- WREG8(MGAREG_CRTCEXT_INDEX, 0);
- crtcext0 = RREG8(MGAREG_CRTCEXT_DATA);
- crtcext0 &= 0xB0;
- addr = offset / 8;
- /* Can't store addresses any higher than that...
- but we also don't have more than 16MB of memory, so it should be fine. */
- WARN_ON(addr > 0x1fffff);
- crtcext0 |= (!!(addr & (1<<20)))<<6;
- WREG_CRT(0x0d, (u8)(addr & 0xff));
- WREG_CRT(0x0c, (u8)(addr >> 8) & 0xff);
- WREG_ECRT(0x0, ((u8)(addr >> 16) & 0xf) | crtcext0);
-}
+ struct drm_device *dev = &mdev->base;
+ u32 startadd;
+ u8 crtcc, crtcd, crtcext0;
-static int mga_crtc_do_set_base(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- int x, int y, int atomic)
-{
- struct drm_gem_vram_object *gbo;
- int ret;
- s64 gpu_addr;
-
- if (!atomic && fb) {
- gbo = drm_gem_vram_of_gem(fb->obj[0]);
- drm_gem_vram_unpin(gbo);
- }
+ startadd = offset / 8;
- gbo = drm_gem_vram_of_gem(crtc->primary->fb->obj[0]);
+ /*
+ * Can't store addresses any higher than that, but we also
+ * don't have more than 16 MiB of memory, so it should be fine.
+ */
+ drm_WARN_ON(dev, startadd > 0x1fffff);
- ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM);
- if (ret)
- return ret;
- gpu_addr = drm_gem_vram_offset(gbo);
- if (gpu_addr < 0) {
- ret = (int)gpu_addr;
- goto err_drm_gem_vram_unpin;
- }
+ RREG_ECRT(0x00, crtcext0);
- mga_set_start_address(crtc, (u32)gpu_addr);
+ crtcc = (startadd >> 8) & 0xff;
+ crtcd = startadd & 0xff;
+ crtcext0 &= 0xb0;
+ crtcext0 |= ((startadd >> 14) & BIT(6)) |
+ ((startadd >> 16) & 0x0f);
- return 0;
-
-err_drm_gem_vram_unpin:
- drm_gem_vram_unpin(gbo);
- return ret;
+ WREG_CRT(0x0c, crtcc);
+ WREG_CRT(0x0d, crtcd);
+ WREG_ECRT(0x00, crtcext0);
}
-static int mga_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
+static void mgag200_set_pci_regs(struct mga_device *mdev)
{
- return mga_crtc_do_set_base(crtc, old_fb, x, y, 0);
+ uint32_t option = 0, option2 = 0;
+ struct drm_device *dev = &mdev->base;
+
+ switch (mdev->type) {
+ case G200_SE_A:
+ case G200_SE_B:
+ if (mdev->has_sdram)
+ option = 0x40049120;
+ else
+ option = 0x4004d120;
+ option2 = 0x00008000;
+ break;
+ case G200_WB:
+ case G200_EW3:
+ option = 0x41049120;
+ option2 = 0x0000b000;
+ break;
+ case G200_EV:
+ option = 0x00000120;
+ option2 = 0x0000b000;
+ break;
+ case G200_EH:
+ case G200_EH3:
+ option = 0x00000120;
+ option2 = 0x0000b000;
+ break;
+ case G200_ER:
+ break;
+ }
+
+ if (option)
+ pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option);
+
+ if (option2)
+ pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2);
}
-static int mga_crtc_mode_set(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
- int x, int y, struct drm_framebuffer *old_fb)
+static void mgag200_set_dac_regs(struct mga_device *mdev)
{
- struct drm_device *dev = crtc->dev;
- struct mga_device *mdev = to_mga_device(dev);
- const struct drm_framebuffer *fb = crtc->primary->fb;
- int hdisplay, hsyncstart, hsyncend, htotal;
- int vdisplay, vsyncstart, vsyncend, vtotal;
- int pitch;
- int option = 0, option2 = 0;
- int i;
- unsigned char misc = 0;
- unsigned char ext_vga[6];
- u8 bppshift;
-
- static unsigned char dacvalue[] = {
+ size_t i;
+ u8 dacvalue[] = {
/* 0x00: */ 0, 0, 0, 0, 0, 0, 0x00, 0,
/* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x10: */ 0, 0, 0, 0, 0, 0, 0, 0,
@@ -927,8 +932,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
/* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0
};
- bppshift = mdev->bpp_shifts[fb->format->cpp[0] - 1];
-
switch (mdev->type) {
case G200_SE_A:
case G200_SE_B:
@@ -937,61 +940,26 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_DAC_EN |
MGA1064_MISC_CTL_VGA8 |
MGA1064_MISC_CTL_DAC_RAM_CS;
- if (mdev->has_sdram)
- option = 0x40049120;
- else
- option = 0x4004d120;
- option2 = 0x00008000;
break;
case G200_WB:
case G200_EW3:
dacvalue[MGA1064_VREF_CTL] = 0x07;
- option = 0x41049120;
- option2 = 0x0000b000;
break;
case G200_EV:
dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL;
dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 |
MGA1064_MISC_CTL_DAC_RAM_CS;
- option = 0x00000120;
- option2 = 0x0000b000;
break;
case G200_EH:
case G200_EH3:
dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 |
MGA1064_MISC_CTL_DAC_RAM_CS;
- option = 0x00000120;
- option2 = 0x0000b000;
break;
case G200_ER:
break;
}
- switch (fb->format->cpp[0] * 8) {
- case 8:
- dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_8bits;
- break;
- case 16:
- if (fb->format->depth == 15)
- dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_15bits;
- else
- dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_16bits;
- break;
- case 24:
- dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_24bits;
- break;
- case 32:
- dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_32_24bits;
- break;
- }
-
- if (mode->flags & DRM_MODE_FLAG_NHSYNC)
- misc |= 0x40;
- if (mode->flags & DRM_MODE_FLAG_NVSYNC)
- misc |= 0x80;
-
-
- for (i = 0; i < sizeof(dacvalue); i++) {
+ for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
if ((i <= 0x17) ||
(i == 0x1b) ||
(i == 0x1c) ||
@@ -1014,21 +982,59 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
if (mdev->type == G200_ER)
WREG_DAC(0x90, 0);
+}
- if (option)
- pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option);
- if (option2)
- pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2);
+static void mgag200_init_regs(struct mga_device *mdev)
+{
+ u8 crtc11, crtcext3, crtcext4, misc;
- WREG_SEQ(2, 0xf);
- WREG_SEQ(3, 0);
- WREG_SEQ(4, 0xe);
+ mgag200_set_pci_regs(mdev);
+ mgag200_set_dac_regs(mdev);
- pitch = fb->pitches[0] / fb->format->cpp[0];
- if (fb->format->cpp[0] * 8 == 24)
- pitch = (pitch * 3) >> (4 - bppshift);
- else
- pitch = pitch >> (4 - bppshift);
+ WREG_SEQ(2, 0x0f);
+ WREG_SEQ(3, 0x00);
+ WREG_SEQ(4, 0x0e);
+
+ WREG_CRT(10, 0);
+ WREG_CRT(11, 0);
+ WREG_CRT(12, 0);
+ WREG_CRT(13, 0);
+ WREG_CRT(14, 0);
+ WREG_CRT(15, 0);
+
+ RREG_ECRT(0x03, crtcext3);
+
+ crtcext3 |= BIT(7); /* enable MGA mode */
+ crtcext4 = 0x00;
+
+ WREG_ECRT(0x03, crtcext3);
+ WREG_ECRT(0x04, crtcext4);
+
+ RREG_CRT(0x11, crtc11);
+ crtc11 &= ~(MGAREG_CRTC11_CRTCPROTECT |
+ MGAREG_CRTC11_VINTEN |
+ MGAREG_CRTC11_VINTCLR);
+ WREG_CRT(0x11, crtc11);
+
+ if (mdev->type == G200_ER)
+ WREG_ECRT(0x24, 0x5);
+
+ if (mdev->type == G200_EW3)
+ WREG_ECRT(0x34, 0x5);
+
+ misc = RREG8(MGA_MISC_IN);
+ misc |= MGAREG_MISC_IOADSEL |
+ MGAREG_MISC_RAMMAPEN |
+ MGAREG_MISC_HIGH_PG_SEL;
+ WREG8(MGA_MISC_OUT, misc);
+}
+
+static void mgag200_set_mode_regs(struct mga_device *mdev,
+ const struct drm_display_mode *mode)
+{
+ unsigned int hdisplay, hsyncstart, hsyncend, htotal;
+ unsigned int vdisplay, vsyncstart, vsyncend, vtotal;
+ u8 misc, crtcext1, crtcext2, crtcext5;
hdisplay = mode->hdisplay / 8 - 1;
hsyncstart = mode->hsync_start / 8 - 1;
@@ -1044,15 +1050,32 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
vsyncend = mode->vsync_end - 1;
vtotal = mode->vtotal - 2;
- WREG_GFX(0, 0);
- WREG_GFX(1, 0);
- WREG_GFX(2, 0);
- WREG_GFX(3, 0);
- WREG_GFX(4, 0);
- WREG_GFX(5, 0x40);
- WREG_GFX(6, 0x5);
- WREG_GFX(7, 0xf);
- WREG_GFX(8, 0xf);
+ misc = RREG8(MGA_MISC_IN);
+
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ misc |= MGAREG_MISC_HSYNCPOL;
+ else
+ misc &= ~MGAREG_MISC_HSYNCPOL;
+
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ misc |= MGAREG_MISC_VSYNCPOL;
+ else
+ misc &= ~MGAREG_MISC_VSYNCPOL;
+
+ crtcext1 = (((htotal - 4) & 0x100) >> 8) |
+ ((hdisplay & 0x100) >> 7) |
+ ((hsyncstart & 0x100) >> 6) |
+ (htotal & 0x40);
+ if (mdev->type == G200_WB || mdev->type == G200_EW3)
+ crtcext1 |= BIT(7) | /* vrsten */
+ BIT(3); /* hrsten */
+
+ crtcext2 = ((vtotal & 0xc00) >> 10) |
+ ((vdisplay & 0x400) >> 8) |
+ ((vdisplay & 0xc00) >> 7) |
+ ((vsyncstart & 0xc00) >> 5) |
+ ((vdisplay & 0x400) >> 3);
+ crtcext5 = 0x00;
WREG_CRT(0, htotal - 4);
WREG_CRT(1, hdisplay);
@@ -1066,386 +1089,250 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
((vsyncstart & 0x100) >> 6) |
((vdisplay & 0x100) >> 5) |
((vdisplay & 0x100) >> 4) | /* linecomp */
- ((vtotal & 0x200) >> 4)|
+ ((vtotal & 0x200) >> 4) |
((vdisplay & 0x200) >> 3) |
((vsyncstart & 0x200) >> 2));
WREG_CRT(9, ((vdisplay & 0x200) >> 4) |
((vdisplay & 0x200) >> 3));
- WREG_CRT(10, 0);
- WREG_CRT(11, 0);
- WREG_CRT(12, 0);
- WREG_CRT(13, 0);
- WREG_CRT(14, 0);
- WREG_CRT(15, 0);
WREG_CRT(16, vsyncstart & 0xFF);
WREG_CRT(17, (vsyncend & 0x0F) | 0x20);
WREG_CRT(18, vdisplay & 0xFF);
- WREG_CRT(19, pitch & 0xFF);
WREG_CRT(20, 0);
WREG_CRT(21, vdisplay & 0xFF);
WREG_CRT(22, (vtotal + 1) & 0xFF);
WREG_CRT(23, 0xc3);
WREG_CRT(24, vdisplay & 0xFF);
- ext_vga[0] = 0;
- ext_vga[5] = 0;
-
- /* TODO interlace */
-
- ext_vga[0] |= (pitch & 0x300) >> 4;
- ext_vga[1] = (((htotal - 4) & 0x100) >> 8) |
- ((hdisplay & 0x100) >> 7) |
- ((hsyncstart & 0x100) >> 6) |
- (htotal & 0x40);
- ext_vga[2] = ((vtotal & 0xc00) >> 10) |
- ((vdisplay & 0x400) >> 8) |
- ((vdisplay & 0xc00) >> 7) |
- ((vsyncstart & 0xc00) >> 5) |
- ((vdisplay & 0x400) >> 3);
- if (fb->format->cpp[0] * 8 == 24)
- ext_vga[3] = (((1 << bppshift) * 3) - 1) | 0x80;
- else
- ext_vga[3] = ((1 << bppshift) - 1) | 0x80;
- ext_vga[4] = 0;
- if (mdev->type == G200_WB || mdev->type == G200_EW3)
- ext_vga[1] |= 0x88;
-
- /* Set pixel clocks */
- misc = 0x2d;
- WREG8(MGA_MISC_OUT, misc);
-
- mga_crtc_set_plls(mdev, mode->clock);
-
- for (i = 0; i < 6; i++) {
- WREG_ECRT(i, ext_vga[i]);
- }
-
- if (mdev->type == G200_ER)
- WREG_ECRT(0x24, 0x5);
-
- if (mdev->type == G200_EW3)
- WREG_ECRT(0x34, 0x5);
-
- if (mdev->type == G200_EV) {
- WREG_ECRT(6, 0);
- }
-
- WREG_ECRT(0, ext_vga[0]);
- /* Enable mga pixel clock */
- misc = 0x2d;
+ WREG_ECRT(0x01, crtcext1);
+ WREG_ECRT(0x02, crtcext2);
+ WREG_ECRT(0x05, crtcext5);
WREG8(MGA_MISC_OUT, misc);
+}
- mga_crtc_do_set_base(crtc, old_fb, x, y, 0);
-
- /* reset tagfifo */
- if (mdev->type == G200_ER) {
- u32 mem_ctl = RREG32(MGAREG_MEMCTL);
- u8 seq1;
-
- /* screen off */
- WREG8(MGAREG_SEQ_INDEX, 0x01);
- seq1 = RREG8(MGAREG_SEQ_DATA) | 0x20;
- WREG8(MGAREG_SEQ_DATA, seq1);
-
- WREG32(MGAREG_MEMCTL, mem_ctl | 0x00200000);
- udelay(1000);
- WREG32(MGAREG_MEMCTL, mem_ctl & ~0x00200000);
-
- WREG8(MGAREG_SEQ_DATA, seq1 & ~0x20);
- }
+static u8 mgag200_get_bpp_shift(struct mga_device *mdev,
+ const struct drm_format_info *format)
+{
+ return mdev->bpp_shifts[format->cpp[0] - 1];
+}
+/*
+ * Calculates the HW offset value from the framebuffer's pitch. The
+ * offset is a multiple of the pixel size and depends on the display
+ * format.
+ */
+static u32 mgag200_calculate_offset(struct mga_device *mdev,
+ const struct drm_framebuffer *fb)
+{
+ u32 offset = fb->pitches[0] / fb->format->cpp[0];
+ u8 bppshift = mgag200_get_bpp_shift(mdev, fb->format);
- if (IS_G200_SE(mdev)) {
- if (mdev->unique_rev_id >= 0x04) {
- WREG8(MGAREG_CRTCEXT_INDEX, 0x06);
- WREG8(MGAREG_CRTCEXT_DATA, 0);
- } else if (mdev->unique_rev_id >= 0x02) {
- u8 hi_pri_lvl;
- u32 bpp;
- u32 mb;
-
- if (fb->format->cpp[0] * 8 > 16)
- bpp = 32;
- else if (fb->format->cpp[0] * 8 > 8)
- bpp = 16;
- else
- bpp = 8;
-
- mb = (mode->clock * bpp) / 1000;
- if (mb > 3100)
- hi_pri_lvl = 0;
- else if (mb > 2600)
- hi_pri_lvl = 1;
- else if (mb > 1900)
- hi_pri_lvl = 2;
- else if (mb > 1160)
- hi_pri_lvl = 3;
- else if (mb > 440)
- hi_pri_lvl = 4;
- else
- hi_pri_lvl = 5;
+ if (fb->format->cpp[0] * 8 == 24)
+ offset = (offset * 3) >> (4 - bppshift);
+ else
+ offset = offset >> (4 - bppshift);
- WREG8(MGAREG_CRTCEXT_INDEX, 0x06);
- WREG8(MGAREG_CRTCEXT_DATA, hi_pri_lvl);
- } else {
- WREG8(MGAREG_CRTCEXT_INDEX, 0x06);
- if (mdev->unique_rev_id >= 0x01)
- WREG8(MGAREG_CRTCEXT_DATA, 0x03);
- else
- WREG8(MGAREG_CRTCEXT_DATA, 0x04);
- }
- }
- return 0;
+ return offset;
}
-#if 0 /* code from mjg to attempt D3 on crtc dpms off - revisit later */
-static int mga_suspend(struct drm_crtc *crtc)
+static void mgag200_set_offset(struct mga_device *mdev,
+ const struct drm_framebuffer *fb)
{
- struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
- struct drm_device *dev = crtc->dev;
- struct mga_device *mdev = dev->dev_private;
- struct pci_dev *pdev = dev->pdev;
- int option;
-
- if (mdev->suspended)
- return 0;
+ u8 crtc13, crtcext0;
+ u32 offset = mgag200_calculate_offset(mdev, fb);
- WREG_SEQ(1, 0x20);
- WREG_ECRT(1, 0x30);
- /* Disable the pixel clock */
- WREG_DAC(0x1a, 0x05);
- /* Power down the DAC */
- WREG_DAC(0x1e, 0x18);
- /* Power down the pixel PLL */
- WREG_DAC(0x1a, 0x0d);
+ RREG_ECRT(0, crtcext0);
- /* Disable PLLs and clocks */
- pci_read_config_dword(pdev, PCI_MGA_OPTION, &option);
- option &= ~(0x1F8024);
- pci_write_config_dword(pdev, PCI_MGA_OPTION, option);
- pci_set_power_state(pdev, PCI_D3hot);
- pci_disable_device(pdev);
+ crtc13 = offset & 0xff;
- mdev->suspended = true;
+ crtcext0 &= ~MGAREG_CRTCEXT0_OFFSET_MASK;
+ crtcext0 |= (offset >> 4) & MGAREG_CRTCEXT0_OFFSET_MASK;
- return 0;
+ WREG_CRT(0x13, crtc13);
+ WREG_ECRT(0x00, crtcext0);
}
-static int mga_resume(struct drm_crtc *crtc)
+static void mgag200_set_format_regs(struct mga_device *mdev,
+ const struct drm_framebuffer *fb)
{
- struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
- struct drm_device *dev = crtc->dev;
- struct mga_device *mdev = dev->dev_private;
- struct pci_dev *pdev = dev->pdev;
- int option;
+ struct drm_device *dev = &mdev->base;
+ const struct drm_format_info *format = fb->format;
+ unsigned int bpp, bppshift, scale;
+ u8 crtcext3, xmulctrl;
- if (!mdev->suspended)
- return 0;
-
- pci_set_power_state(pdev, PCI_D0);
- pci_enable_device(pdev);
-
- /* Disable sysclk */
- pci_read_config_dword(pdev, PCI_MGA_OPTION, &option);
- option &= ~(0x4);
- pci_write_config_dword(pdev, PCI_MGA_OPTION, option);
+ bpp = format->cpp[0] * 8;
- mdev->suspended = false;
-
- return 0;
-}
-
-#endif
+ bppshift = mgag200_get_bpp_shift(mdev, format);
+ switch (bpp) {
+ case 24:
+ scale = ((1 << bppshift) * 3) - 1;
+ break;
+ default:
+ scale = (1 << bppshift) - 1;
+ break;
+ }
-static void mga_crtc_dpms(struct drm_crtc *crtc, int mode)
-{
- struct drm_device *dev = crtc->dev;
- struct mga_device *mdev = to_mga_device(dev);
- u8 seq1 = 0, crtcext1 = 0;
+ RREG_ECRT(3, crtcext3);
- switch (mode) {
- case DRM_MODE_DPMS_ON:
- seq1 = 0;
- crtcext1 = 0;
- mga_crtc_load_lut(crtc);
+ switch (bpp) {
+ case 8:
+ xmulctrl = MGA1064_MUL_CTL_8bits;
break;
- case DRM_MODE_DPMS_STANDBY:
- seq1 = 0x20;
- crtcext1 = 0x10;
+ case 16:
+ if (format->depth == 15)
+ xmulctrl = MGA1064_MUL_CTL_15bits;
+ else
+ xmulctrl = MGA1064_MUL_CTL_16bits;
break;
- case DRM_MODE_DPMS_SUSPEND:
- seq1 = 0x20;
- crtcext1 = 0x20;
+ case 24:
+ xmulctrl = MGA1064_MUL_CTL_24bits;
break;
- case DRM_MODE_DPMS_OFF:
- seq1 = 0x20;
- crtcext1 = 0x30;
+ case 32:
+ xmulctrl = MGA1064_MUL_CTL_32_24bits;
break;
+ default:
+ /* BUG: We should have caught this problem already. */
+ drm_WARN_ON(dev, "invalid format depth\n");
+ return;
}
-#if 0
- if (mode == DRM_MODE_DPMS_OFF) {
- mga_suspend(crtc);
- }
-#endif
- WREG8(MGAREG_SEQ_INDEX, 0x01);
- seq1 |= RREG8(MGAREG_SEQ_DATA) & ~0x20;
- mga_wait_vsync(mdev);
- mga_wait_busy(mdev);
- WREG8(MGAREG_SEQ_DATA, seq1);
- msleep(20);
- WREG8(MGAREG_CRTCEXT_INDEX, 0x01);
- crtcext1 |= RREG8(MGAREG_CRTCEXT_DATA) & ~0x30;
- WREG8(MGAREG_CRTCEXT_DATA, crtcext1);
-
-#if 0
- if (mode == DRM_MODE_DPMS_ON && mdev->suspended == true) {
- mga_resume(crtc);
- drm_helper_resume_force_mode(dev);
- }
-#endif
-}
+ crtcext3 &= ~GENMASK(2, 0);
+ crtcext3 |= scale;
-/*
- * This is called before a mode is programmed. A typical use might be to
- * enable DPMS during the programming to avoid seeing intermediate stages,
- * but that's not relevant to us
- */
-static void mga_crtc_prepare(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct mga_device *mdev = to_mga_device(dev);
- u8 tmp;
+ WREG_DAC(MGA1064_MUL_CTL, xmulctrl);
- /* mga_resume(crtc);*/
+ WREG_GFX(0, 0x00);
+ WREG_GFX(1, 0x00);
+ WREG_GFX(2, 0x00);
+ WREG_GFX(3, 0x00);
+ WREG_GFX(4, 0x00);
+ WREG_GFX(5, 0x40);
+ WREG_GFX(6, 0x05);
+ WREG_GFX(7, 0x0f);
+ WREG_GFX(8, 0x0f);
- WREG8(MGAREG_CRTC_INDEX, 0x11);
- tmp = RREG8(MGAREG_CRTC_DATA);
- WREG_CRT(0x11, tmp | 0x80);
+ WREG_ECRT(3, crtcext3);
+}
- if (mdev->type == G200_SE_A || mdev->type == G200_SE_B) {
- WREG_SEQ(0, 1);
- msleep(50);
- WREG_SEQ(1, 0x20);
- msleep(20);
- } else {
- WREG8(MGAREG_SEQ_INDEX, 0x1);
- tmp = RREG8(MGAREG_SEQ_DATA);
+static void mgag200_g200er_reset_tagfifo(struct mga_device *mdev)
+{
+ static uint32_t RESET_FLAG = 0x00200000; /* undocumented magic value */
+ u32 memctl;
- /* start sync reset */
- WREG_SEQ(0, 1);
- WREG_SEQ(1, tmp | 0x20);
- }
+ memctl = RREG32(MGAREG_MEMCTL);
- if (mdev->type == G200_WB || mdev->type == G200_EW3)
- mga_g200wb_prepare(crtc);
+ memctl |= RESET_FLAG;
+ WREG32(MGAREG_MEMCTL, memctl);
- WREG_CRT(17, 0);
+ udelay(1000);
+
+ memctl &= ~RESET_FLAG;
+ WREG32(MGAREG_MEMCTL, memctl);
}
-/*
- * This is called after a mode is programmed. It should reverse anything done
- * by the prepare function
- */
-static void mga_crtc_commit(struct drm_crtc *crtc)
+static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev,
+ const struct drm_display_mode *mode,
+ const struct drm_framebuffer *fb)
{
- struct drm_device *dev = crtc->dev;
- struct mga_device *mdev = to_mga_device(dev);
- const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
- u8 tmp;
-
- if (mdev->type == G200_WB || mdev->type == G200_EW3)
- mga_g200wb_commit(crtc);
+ unsigned int hiprilvl;
+ u8 crtcext6;
+
+ if (mdev->unique_rev_id >= 0x04) {
+ hiprilvl = 0;
+ } else if (mdev->unique_rev_id >= 0x02) {
+ unsigned int bpp;
+ unsigned long mb;
+
+ if (fb->format->cpp[0] * 8 > 16)
+ bpp = 32;
+ else if (fb->format->cpp[0] * 8 > 8)
+ bpp = 16;
+ else
+ bpp = 8;
+
+ mb = (mode->clock * bpp) / 1000;
+ if (mb > 3100)
+ hiprilvl = 0;
+ else if (mb > 2600)
+ hiprilvl = 1;
+ else if (mb > 1900)
+ hiprilvl = 2;
+ else if (mb > 1160)
+ hiprilvl = 3;
+ else if (mb > 440)
+ hiprilvl = 4;
+ else
+ hiprilvl = 5;
- if (mdev->type == G200_SE_A || mdev->type == G200_SE_B) {
- msleep(50);
- WREG_SEQ(1, 0x0);
- msleep(20);
- WREG_SEQ(0, 0x3);
+ } else if (mdev->unique_rev_id >= 0x01) {
+ hiprilvl = 3;
} else {
- WREG8(MGAREG_SEQ_INDEX, 0x1);
- tmp = RREG8(MGAREG_SEQ_DATA);
-
- tmp &= ~0x20;
- WREG_SEQ(0x1, tmp);
- WREG_SEQ(0, 3);
+ hiprilvl = 4;
}
- crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
-}
-/*
- * The core can pass us a set of gamma values to program. We actually only
- * use this for 8-bit mode so can't perform smooth fades on deeper modes,
- * but it's a requirement that we provide the function
- */
-static int mga_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
- u16 *blue, uint32_t size,
- struct drm_modeset_acquire_ctx *ctx)
-{
- mga_crtc_load_lut(crtc);
+ crtcext6 = hiprilvl; /* implicitly sets maxhipri to 0 */
- return 0;
+ WREG_ECRT(0x06, crtcext6);
}
-/* Simple cleanup function */
-static void mga_crtc_destroy(struct drm_crtc *crtc)
+static void mgag200_g200ev_set_hiprilvl(struct mga_device *mdev)
{
- struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
-
- drm_crtc_cleanup(crtc);
- kfree(mga_crtc);
+ WREG_ECRT(0x06, 0x00);
}
-static void mga_crtc_disable(struct drm_crtc *crtc)
+static void mgag200_enable_display(struct mga_device *mdev)
{
- DRM_DEBUG_KMS("\n");
- mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
- if (crtc->primary->fb) {
- struct drm_framebuffer *fb = crtc->primary->fb;
- struct drm_gem_vram_object *gbo =
- drm_gem_vram_of_gem(fb->obj[0]);
- drm_gem_vram_unpin(gbo);
- }
- crtc->primary->fb = NULL;
-}
+ u8 seq0, seq1, crtcext1;
-/* These provide the minimum set of functions required to handle a CRTC */
-static const struct drm_crtc_funcs mga_crtc_funcs = {
- .cursor_set = mgag200_crtc_cursor_set,
- .cursor_move = mgag200_crtc_cursor_move,
- .gamma_set = mga_crtc_gamma_set,
- .set_config = drm_crtc_helper_set_config,
- .destroy = mga_crtc_destroy,
-};
+ RREG_SEQ(0x00, seq0);
+ seq0 |= MGAREG_SEQ0_SYNCRST |
+ MGAREG_SEQ0_ASYNCRST;
+ WREG_SEQ(0x00, seq0);
-static const struct drm_crtc_helper_funcs mga_helper_funcs = {
- .disable = mga_crtc_disable,
- .dpms = mga_crtc_dpms,
- .mode_set = mga_crtc_mode_set,
- .mode_set_base = mga_crtc_mode_set_base,
- .prepare = mga_crtc_prepare,
- .commit = mga_crtc_commit,
-};
+ /*
+ * TODO: replace busy waiting with vblank IRQ; put
+ * msleep(50) before changing SCROFF
+ */
+ mga_wait_vsync(mdev);
+ mga_wait_busy(mdev);
+
+ RREG_SEQ(0x01, seq1);
+ seq1 &= ~MGAREG_SEQ1_SCROFF;
+ WREG_SEQ(0x01, seq1);
+
+ msleep(20);
-/* CRTC setup */
-static void mga_crtc_init(struct mga_device *mdev)
+ RREG_ECRT(0x01, crtcext1);
+ crtcext1 &= ~MGAREG_CRTCEXT1_VSYNCOFF;
+ crtcext1 &= ~MGAREG_CRTCEXT1_HSYNCOFF;
+ WREG_ECRT(0x01, crtcext1);
+}
+
+static void mgag200_disable_display(struct mga_device *mdev)
{
- struct drm_device *dev = mdev->dev;
- struct mga_crtc *mga_crtc;
+ u8 seq0, seq1, crtcext1;
- mga_crtc = kzalloc(sizeof(struct mga_crtc) +
- (MGAG200FB_CONN_LIMIT * sizeof(struct drm_connector *)),
- GFP_KERNEL);
+ RREG_SEQ(0x00, seq0);
+ seq0 &= ~MGAREG_SEQ0_SYNCRST;
+ WREG_SEQ(0x00, seq0);
- if (mga_crtc == NULL)
- return;
+ /*
+ * TODO: replace busy waiting with vblank IRQ; put
+ * msleep(50) before changing SCROFF
+ */
+ mga_wait_vsync(mdev);
+ mga_wait_busy(mdev);
- drm_crtc_init(dev, &mga_crtc->base, &mga_crtc_funcs);
+ RREG_SEQ(0x01, seq1);
+ seq1 |= MGAREG_SEQ1_SCROFF;
+ WREG_SEQ(0x01, seq1);
- drm_mode_crtc_set_gamma_size(&mga_crtc->base, MGAG200_LUT_SIZE);
+ msleep(20);
- drm_crtc_helper_add(&mga_crtc->base, &mga_helper_funcs);
+ RREG_ECRT(0x01, crtcext1);
+ crtcext1 |= MGAREG_CRTCEXT1_VSYNCOFF |
+ MGAREG_CRTCEXT1_HSYNCOFF;
+ WREG_ECRT(0x01, crtcext1);
}
/*
@@ -1579,19 +1466,21 @@ static void mga_connector_destroy(struct drm_connector *connector)
}
static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = {
- .get_modes = mga_vga_get_modes,
+ .get_modes = mga_vga_get_modes,
.mode_valid = mga_vga_mode_valid,
};
static const struct drm_connector_funcs mga_vga_connector_funcs = {
- .dpms = drm_helper_connector_dpms,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = mga_connector_destroy,
+ .reset = drm_atomic_helper_connector_reset,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = mga_connector_destroy,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int mgag200_vga_connector_init(struct mga_device *mdev)
{
- struct drm_device *dev = mdev->dev;
+ struct drm_device *dev = &mdev->base;
struct mga_connector *mconnector = &mdev->connector;
struct drm_connector *connector = &mconnector->base;
struct mga_i2c_chan *i2c;
@@ -1618,8 +1507,155 @@ err_mgag200_i2c_destroy:
return ret;
}
+/*
+ * Simple Display Pipe
+ */
+
+static enum drm_mode_status
+mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
+ const struct drm_display_mode *mode)
+{
+ return MODE_OK;
+}
+
+static void
+mgag200_handle_damage(struct mga_device *mdev, struct drm_framebuffer *fb,
+ struct drm_rect *clip)
+{
+ struct drm_device *dev = &mdev->base;
+ void *vmap;
+
+ vmap = drm_gem_shmem_vmap(fb->obj[0]);
+ if (drm_WARN_ON(dev, !vmap))
+ return; /* BUG: SHMEM BO should always be vmapped */
+
+ drm_fb_memcpy_dstclip(mdev->vram, vmap, fb, clip);
+
+ drm_gem_shmem_vunmap(fb->obj[0], vmap);
+
+ /* Always scanout image at VRAM offset 0 */
+ mgag200_set_startadd(mdev, (u32)0);
+ mgag200_set_offset(mdev, fb);
+}
+
+static void
+mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
+ struct drm_crtc_state *crtc_state,
+ struct drm_plane_state *plane_state)
+{
+ struct drm_crtc *crtc = &pipe->crtc;
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
+ struct drm_framebuffer *fb = plane_state->fb;
+ struct drm_rect fullscreen = {
+ .x1 = 0,
+ .x2 = fb->width,
+ .y1 = 0,
+ .y2 = fb->height,
+ };
+
+ if (mdev->type == G200_WB || mdev->type == G200_EW3)
+ mgag200_g200wb_hold_bmc(mdev);
+
+ mgag200_set_format_regs(mdev, fb);
+ mgag200_set_mode_regs(mdev, adjusted_mode);
+ mgag200_crtc_set_plls(mdev, adjusted_mode->clock);
+
+ if (mdev->type == G200_ER)
+ mgag200_g200er_reset_tagfifo(mdev);
+
+ if (IS_G200_SE(mdev))
+ mgag200_g200se_set_hiprilvl(mdev, adjusted_mode, fb);
+ else if (mdev->type == G200_EV)
+ mgag200_g200ev_set_hiprilvl(mdev);
+
+ if (mdev->type == G200_WB || mdev->type == G200_EW3)
+ mgag200_g200wb_release_bmc(mdev);
+
+ mga_crtc_load_lut(crtc);
+ mgag200_enable_display(mdev);
+
+ mgag200_handle_damage(mdev, fb, &fullscreen);
+}
+
+static void
+mgag200_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
+{
+ struct drm_crtc *crtc = &pipe->crtc;
+ struct mga_device *mdev = to_mga_device(crtc->dev);
+
+ mgag200_disable_display(mdev);
+}
+
+static int
+mgag200_simple_display_pipe_check(struct drm_simple_display_pipe *pipe,
+ struct drm_plane_state *plane_state,
+ struct drm_crtc_state *crtc_state)
+{
+ struct drm_plane *plane = plane_state->plane;
+ struct drm_framebuffer *new_fb = plane_state->fb;
+ struct drm_framebuffer *fb = NULL;
+
+ if (!new_fb)
+ return 0;
+
+ if (plane->state)
+ fb = plane->state->fb;
+
+ if (!fb || (fb->format != new_fb->format))
+ crtc_state->mode_changed = true; /* update PLL settings */
+
+ return 0;
+}
+
+static void
+mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
+ struct drm_plane_state *old_state)
+{
+ struct drm_plane *plane = &pipe->plane;
+ struct drm_device *dev = plane->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_rect damage;
+
+ if (!fb)
+ return;
+
+ if (drm_atomic_helper_damage_merged(old_state, state, &damage))
+ mgag200_handle_damage(mdev, fb, &damage);
+}
+
+static const struct drm_simple_display_pipe_funcs
+mgag200_simple_display_pipe_funcs = {
+ .mode_valid = mgag200_simple_display_pipe_mode_valid,
+ .enable = mgag200_simple_display_pipe_enable,
+ .disable = mgag200_simple_display_pipe_disable,
+ .check = mgag200_simple_display_pipe_check,
+ .update = mgag200_simple_display_pipe_update,
+ .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
+};
+
+static const uint32_t mgag200_simple_display_pipe_formats[] = {
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_RGB888,
+};
+
+static const uint64_t mgag200_simple_display_pipe_fmtmods[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID
+};
+
+/*
+ * Mode config
+ */
+
static const struct drm_mode_config_funcs mgag200_mode_config_funcs = {
- .fb_create = drm_gem_fb_create
+ .fb_create = drm_gem_fb_create_with_dirty,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
};
static unsigned int mgag200_preferred_depth(struct mga_device *mdev)
@@ -1632,9 +1668,10 @@ static unsigned int mgag200_preferred_depth(struct mga_device *mdev)
int mgag200_modeset_init(struct mga_device *mdev)
{
- struct drm_device *dev = mdev->dev;
- struct drm_encoder *encoder = &mdev->encoder;
+ struct drm_device *dev = &mdev->base;
struct drm_connector *connector = &mdev->connector.base;
+ struct drm_simple_display_pipe *pipe = &mdev->display_pipe;
+ size_t format_count = ARRAY_SIZE(mgag200_simple_display_pipe_formats);
int ret;
mdev->bpp_shifts[0] = 0;
@@ -1642,6 +1679,8 @@ int mgag200_modeset_init(struct mga_device *mdev)
mdev->bpp_shifts[2] = 0;
mdev->bpp_shifts[3] = 2;
+ mgag200_init_regs(mdev);
+
ret = drmm_mode_config_init(dev);
if (ret) {
drm_err(dev, "drmm_mode_config_init() failed, error %d\n",
@@ -1653,32 +1692,36 @@ int mgag200_modeset_init(struct mga_device *mdev)
dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT;
dev->mode_config.preferred_depth = mgag200_preferred_depth(mdev);
- dev->mode_config.prefer_shadow = 1;
dev->mode_config.fb_base = mdev->mc.vram_base;
dev->mode_config.funcs = &mgag200_mode_config_funcs;
- mga_crtc_init(mdev);
-
- ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_DAC);
+ ret = mgag200_vga_connector_init(mdev);
if (ret) {
drm_err(dev,
- "drm_simple_encoder_init() failed, error %d\n",
+ "mgag200_vga_connector_init() failed, error %d\n",
ret);
return ret;
}
- encoder->possible_crtcs = 0x1;
- ret = mgag200_vga_connector_init(mdev);
+ ret = drm_simple_display_pipe_init(dev, pipe,
+ &mgag200_simple_display_pipe_funcs,
+ mgag200_simple_display_pipe_formats,
+ format_count,
+ mgag200_simple_display_pipe_fmtmods,
+ connector);
if (ret) {
drm_err(dev,
- "mgag200_vga_connector_init() failed, error %d\n",
+ "drm_simple_display_pipe_init() failed, error %d\n",
ret);
return ret;
}
- drm_connector_attach_encoder(connector, encoder);
+ /* FIXME: legacy gamma tables; convert to CRTC state */
+ drm_mode_crtc_set_gamma_size(&pipe->crtc, MGAG200_LUT_SIZE);
+
+ drm_mode_config_reset(dev);
return 0;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_reg.h b/drivers/gpu/drm/mgag200/mgag200_reg.h
index c096a9d6bcbc..c3b7bcad52ed 100644
--- a/drivers/gpu/drm/mgag200/mgag200_reg.h
+++ b/drivers/gpu/drm/mgag200/mgag200_reg.h
@@ -16,10 +16,11 @@
* MGA1064SG Mystique register file
*/
-
#ifndef _MGA_REG_H_
#define _MGA_REG_H_
+#include <linux/bits.h>
+
#define MGAREG_DWGCTL 0x1c00
#define MGAREG_MACCESS 0x1c04
/* the following is a mystique only register */
@@ -221,21 +222,40 @@
#define MGAREG_MISC_IOADSEL (0x1 << 0)
#define MGAREG_MISC_RAMMAPEN (0x1 << 1)
+#define MGAREG_MISC_CLK_SEL_MASK GENMASK(3, 2)
#define MGAREG_MISC_CLK_SEL_VGA25 (0x0 << 2)
#define MGAREG_MISC_CLK_SEL_VGA28 (0x1 << 2)
#define MGAREG_MISC_CLK_SEL_MGA_PIX (0x2 << 2)
#define MGAREG_MISC_CLK_SEL_MGA_MSK (0x3 << 2)
#define MGAREG_MISC_VIDEO_DIS (0x1 << 4)
#define MGAREG_MISC_HIGH_PG_SEL (0x1 << 5)
+#define MGAREG_MISC_HSYNCPOL BIT(6)
+#define MGAREG_MISC_VSYNCPOL BIT(7)
/* MMIO VGA registers */
#define MGAREG_SEQ_INDEX 0x1fc4
#define MGAREG_SEQ_DATA 0x1fc5
+
+#define MGAREG_SEQ0_ASYNCRST BIT(0)
+#define MGAREG_SEQ0_SYNCRST BIT(1)
+
+#define MGAREG_SEQ1_SCROFF BIT(5)
+
#define MGAREG_CRTC_INDEX 0x1fd4
#define MGAREG_CRTC_DATA 0x1fd5
+
+#define MGAREG_CRTC11_VINTCLR BIT(4)
+#define MGAREG_CRTC11_VINTEN BIT(5)
+#define MGAREG_CRTC11_CRTCPROTECT BIT(7)
+
#define MGAREG_CRTCEXT_INDEX 0x1fde
#define MGAREG_CRTCEXT_DATA 0x1fdf
+#define MGAREG_CRTCEXT0_OFFSET_MASK GENMASK(5, 4)
+
+#define MGAREG_CRTCEXT1_VSYNCOFF BIT(5)
+#define MGAREG_CRTCEXT1_HSYNCOFF BIT(4)
+
/* Cursor X and Y position */
#define MGA_CURPOSXL 0x3c0c
#define MGA_CURPOSXH 0x3c0d
diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c
deleted file mode 100644
index e89657630ea7..000000000000
--- a/drivers/gpu/drm/mgag200/mgag200_ttm.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2012 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS 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.
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- */
-/*
- * Authors: Dave Airlie <airlied@redhat.com>
- */
-
-#include <linux/pci.h>
-
-#include "mgag200_drv.h"
-
-int mgag200_mm_init(struct mga_device *mdev)
-{
- struct drm_vram_mm *vmm;
- int ret;
- struct drm_device *dev = mdev->dev;
-
- vmm = drm_vram_helper_alloc_mm(dev, pci_resource_start(dev->pdev, 0),
- mdev->mc.vram_size);
- if (IS_ERR(vmm)) {
- ret = PTR_ERR(vmm);
- DRM_ERROR("Error initializing VRAM MM; %d\n", ret);
- return ret;
- }
-
- arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0),
- pci_resource_len(dev->pdev, 0));
-
- mdev->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
- pci_resource_len(dev->pdev, 0));
-
- mdev->vram_fb_available = mdev->mc.vram_size;
-
- return 0;
-}
-
-void mgag200_mm_fini(struct mga_device *mdev)
-{
- struct drm_device *dev = mdev->dev;
-
- mdev->vram_fb_available = 0;
-
- drm_vram_helper_release_mm(dev);
-
- arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
- pci_resource_len(dev->pdev, 0));
- arch_phys_wc_del(mdev->fb_mtrr);
- mdev->fb_mtrr = 0;
-}