diff options
Diffstat (limited to 'drivers/gpu/drm/mgag200')
-rw-r--r-- | drivers/gpu/drm/mgag200/Kconfig | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_cursor.c | 319 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_drv.c | 204 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_drv.h | 62 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_main.c | 160 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_mm.c | 127 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_mode.c | 995 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_reg.h | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_ttm.c | 70 |
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; -} |