diff options
Diffstat (limited to 'drivers/gpu/drm/cirrus')
-rw-r--r-- | drivers/gpu/drm/cirrus/Kconfig | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/cirrus.c | 657 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/cirrus_drv.c | 161 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/cirrus_drv.h | 251 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/cirrus_fbdev.c | 309 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/cirrus_main.c | 328 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/cirrus_mode.c | 617 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/cirrus_ttm.c | 343 |
9 files changed, 658 insertions, 2013 deletions
diff --git a/drivers/gpu/drm/cirrus/Kconfig b/drivers/gpu/drm/cirrus/Kconfig index fc78c90ee931..dd4f52a0bc1c 100644 --- a/drivers/gpu/drm/cirrus/Kconfig +++ b/drivers/gpu/drm/cirrus/Kconfig @@ -2,7 +2,7 @@ config DRM_CIRRUS_QEMU tristate "Cirrus driver for QEMU emulated device" depends on DRM && PCI && MMU select DRM_KMS_HELPER - select DRM_TTM + select DRM_GEM_SHMEM_HELPER help This is a KMS driver for emulated cirrus device in qemu. It is *NOT* intended for real cirrus devices. This requires diff --git a/drivers/gpu/drm/cirrus/Makefile b/drivers/gpu/drm/cirrus/Makefile index 919c0a336c97..acf8971d37a1 100644 --- a/drivers/gpu/drm/cirrus/Makefile +++ b/drivers/gpu/drm/cirrus/Makefile @@ -1,4 +1 @@ -cirrus-y := cirrus_main.o cirrus_mode.o \ - cirrus_drv.o cirrus_fbdev.o cirrus_ttm.o - obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o diff --git a/drivers/gpu/drm/cirrus/cirrus.c b/drivers/gpu/drm/cirrus/cirrus.c new file mode 100644 index 000000000000..5095b8ce52c2 --- /dev/null +++ b/drivers/gpu/drm/cirrus/cirrus.c @@ -0,0 +1,657 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2012-2019 Red Hat + * + * This file is subject to the terms and conditions of the GNU General + * Public License version 2. See the file COPYING in the main + * directory of this archive for more details. + * + * Authors: Matthew Garrett + * Dave Airlie + * Gerd Hoffmann + * + * Portions of this code derived from cirrusfb.c: + * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets + * + * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com> + */ + +#include <linux/console.h> +#include <linux/module.h> +#include <linux/pci.h> + +#include <video/cirrus.h> +#include <video/vga.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_atomic_state_helper.h> +#include <drm/drm_connector.h> +#include <drm/drm_damage_helper.h> +#include <drm/drm_drv.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_file.h> +#include <drm/drm_format_helper.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_gem_shmem_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_ioctl.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_simple_kms_helper.h> +#include <drm/drm_vblank.h> + +#define DRIVER_NAME "cirrus" +#define DRIVER_DESC "qemu cirrus vga" +#define DRIVER_DATE "2019" +#define DRIVER_MAJOR 2 +#define DRIVER_MINOR 0 + +#define CIRRUS_MAX_PITCH (0x1FF << 3) /* (4096 - 1) & ~111b bytes */ +#define CIRRUS_VRAM_SIZE (4 * 1024 * 1024) /* 4 MB */ + +struct cirrus_device { + struct drm_device dev; + struct drm_simple_display_pipe pipe; + struct drm_connector conn; + unsigned int cpp; + unsigned int pitch; + void __iomem *vram; + void __iomem *mmio; +}; + +/* ------------------------------------------------------------------ */ +/* + * The meat of this driver. The core passes us a mode and we have to program + * it. The modesetting here is the bare minimum required to satisfy the qemu + * emulation of this hardware, and running this against a real device is + * likely to result in an inadequately programmed mode. We've already had + * the opportunity to modify the mode, so whatever we receive here should + * be something that can be correctly programmed and displayed + */ + +#define SEQ_INDEX 4 +#define SEQ_DATA 5 + +static u8 rreg_seq(struct cirrus_device *cirrus, u8 reg) +{ + iowrite8(reg, cirrus->mmio + SEQ_INDEX); + return ioread8(cirrus->mmio + SEQ_DATA); +} + +static void wreg_seq(struct cirrus_device *cirrus, u8 reg, u8 val) +{ + iowrite8(reg, cirrus->mmio + SEQ_INDEX); + iowrite8(val, cirrus->mmio + SEQ_DATA); +} + +#define CRT_INDEX 0x14 +#define CRT_DATA 0x15 + +static u8 rreg_crt(struct cirrus_device *cirrus, u8 reg) +{ + iowrite8(reg, cirrus->mmio + CRT_INDEX); + return ioread8(cirrus->mmio + CRT_DATA); +} + +static void wreg_crt(struct cirrus_device *cirrus, u8 reg, u8 val) +{ + iowrite8(reg, cirrus->mmio + CRT_INDEX); + iowrite8(val, cirrus->mmio + CRT_DATA); +} + +#define GFX_INDEX 0xe +#define GFX_DATA 0xf + +static void wreg_gfx(struct cirrus_device *cirrus, u8 reg, u8 val) +{ + iowrite8(reg, cirrus->mmio + GFX_INDEX); + iowrite8(val, cirrus->mmio + GFX_DATA); +} + +#define VGA_DAC_MASK 0x06 + +static void wreg_hdr(struct cirrus_device *cirrus, u8 val) +{ + ioread8(cirrus->mmio + VGA_DAC_MASK); + ioread8(cirrus->mmio + VGA_DAC_MASK); + ioread8(cirrus->mmio + VGA_DAC_MASK); + ioread8(cirrus->mmio + VGA_DAC_MASK); + iowrite8(val, cirrus->mmio + VGA_DAC_MASK); +} + +static int cirrus_convert_to(struct drm_framebuffer *fb) +{ + if (fb->format->cpp[0] == 4 && fb->pitches[0] > CIRRUS_MAX_PITCH) { + if (fb->width * 3 <= CIRRUS_MAX_PITCH) + /* convert from XR24 to RG24 */ + return 3; + else + /* convert from XR24 to RG16 */ + return 2; + } + return 0; +} + +static int cirrus_cpp(struct drm_framebuffer *fb) +{ + int convert_cpp = cirrus_convert_to(fb); + + if (convert_cpp) + return convert_cpp; + return fb->format->cpp[0]; +} + +static int cirrus_pitch(struct drm_framebuffer *fb) +{ + int convert_cpp = cirrus_convert_to(fb); + + if (convert_cpp) + return convert_cpp * fb->width; + return fb->pitches[0]; +} + +static void cirrus_set_start_address(struct cirrus_device *cirrus, u32 offset) +{ + u32 addr; + u8 tmp; + + addr = offset >> 2; + wreg_crt(cirrus, 0x0c, (u8)((addr >> 8) & 0xff)); + wreg_crt(cirrus, 0x0d, (u8)(addr & 0xff)); + + tmp = rreg_crt(cirrus, 0x1b); + tmp &= 0xf2; + tmp |= (addr >> 16) & 0x01; + tmp |= (addr >> 15) & 0x0c; + wreg_crt(cirrus, 0x1b, tmp); + + tmp = rreg_crt(cirrus, 0x1d); + tmp &= 0x7f; + tmp |= (addr >> 12) & 0x80; + wreg_crt(cirrus, 0x1d, tmp); +} + +static int cirrus_mode_set(struct cirrus_device *cirrus, + struct drm_display_mode *mode, + struct drm_framebuffer *fb) +{ + int hsyncstart, hsyncend, htotal, hdispend; + int vtotal, vdispend; + int tmp; + int sr07 = 0, hdr = 0; + + htotal = mode->htotal / 8; + hsyncend = mode->hsync_end / 8; + hsyncstart = mode->hsync_start / 8; + hdispend = mode->hdisplay / 8; + + vtotal = mode->vtotal; + vdispend = mode->vdisplay; + + vdispend -= 1; + vtotal -= 2; + + htotal -= 5; + hdispend -= 1; + hsyncstart += 1; + hsyncend += 1; + + wreg_crt(cirrus, VGA_CRTC_V_SYNC_END, 0x20); + wreg_crt(cirrus, VGA_CRTC_H_TOTAL, htotal); + wreg_crt(cirrus, VGA_CRTC_H_DISP, hdispend); + wreg_crt(cirrus, VGA_CRTC_H_SYNC_START, hsyncstart); + wreg_crt(cirrus, VGA_CRTC_H_SYNC_END, hsyncend); + wreg_crt(cirrus, VGA_CRTC_V_TOTAL, vtotal & 0xff); + wreg_crt(cirrus, VGA_CRTC_V_DISP_END, vdispend & 0xff); + + tmp = 0x40; + if ((vdispend + 1) & 512) + tmp |= 0x20; + wreg_crt(cirrus, VGA_CRTC_MAX_SCAN, tmp); + + /* + * Overflow bits for values that don't fit in the standard registers + */ + tmp = 0x10; + if (vtotal & 0x100) + tmp |= 0x01; + if (vdispend & 0x100) + tmp |= 0x02; + if ((vdispend + 1) & 0x100) + tmp |= 0x08; + if (vtotal & 0x200) + tmp |= 0x20; + if (vdispend & 0x200) + tmp |= 0x40; + wreg_crt(cirrus, VGA_CRTC_OVERFLOW, tmp); + + tmp = 0; + + /* More overflow bits */ + + if ((htotal + 5) & 0x40) + tmp |= 0x10; + if ((htotal + 5) & 0x80) + tmp |= 0x20; + if (vtotal & 0x100) + tmp |= 0x40; + if (vtotal & 0x200) + tmp |= 0x80; + + wreg_crt(cirrus, CL_CRT1A, tmp); + + /* Disable Hercules/CGA compatibility */ + wreg_crt(cirrus, VGA_CRTC_MODE, 0x03); + + sr07 = rreg_seq(cirrus, 0x07); + sr07 &= 0xe0; + hdr = 0; + + cirrus->cpp = cirrus_cpp(fb); + switch (cirrus->cpp * 8) { + case 8: + sr07 |= 0x11; + break; + case 16: + sr07 |= 0x17; + hdr = 0xc1; + break; + case 24: + sr07 |= 0x15; + hdr = 0xc5; + break; + case 32: + sr07 |= 0x19; + hdr = 0xc5; + break; + default: + return -1; + } + + wreg_seq(cirrus, 0x7, sr07); + + /* Program the pitch */ + cirrus->pitch = cirrus_pitch(fb); + tmp = cirrus->pitch / 8; + wreg_crt(cirrus, VGA_CRTC_OFFSET, tmp); + + /* Enable extended blanking and pitch bits, and enable full memory */ + tmp = 0x22; + tmp |= (cirrus->pitch >> 7) & 0x10; + tmp |= (cirrus->pitch >> 6) & 0x40; + wreg_crt(cirrus, 0x1b, tmp); + + /* Enable high-colour modes */ + wreg_gfx(cirrus, VGA_GFX_MODE, 0x40); + + /* And set graphics mode */ + wreg_gfx(cirrus, VGA_GFX_MISC, 0x01); + + wreg_hdr(cirrus, hdr); + + cirrus_set_start_address(cirrus, 0); + + /* Unblank (needed on S3 resume, vgabios doesn't do it then) */ + outb(0x20, 0x3c0); + return 0; +} + +static int cirrus_fb_blit_rect(struct drm_framebuffer *fb, + struct drm_rect *rect) +{ + struct cirrus_device *cirrus = fb->dev->dev_private; + void *vmap; + + vmap = drm_gem_shmem_vmap(fb->obj[0]); + if (!vmap) + return -ENOMEM; + + if (cirrus->cpp == fb->format->cpp[0]) + drm_fb_memcpy_dstclip(__io_virt(cirrus->vram), + vmap, fb, rect); + + else if (fb->format->cpp[0] == 4 && cirrus->cpp == 2) + drm_fb_xrgb8888_to_rgb565_dstclip(__io_virt(cirrus->vram), + cirrus->pitch, + vmap, fb, rect, false); + + else if (fb->format->cpp[0] == 4 && cirrus->cpp == 3) + drm_fb_xrgb8888_to_rgb888_dstclip(__io_virt(cirrus->vram), + cirrus->pitch, + vmap, fb, rect); + + else + WARN_ON_ONCE("cpp mismatch"); + + drm_gem_shmem_vunmap(fb->obj[0], vmap); + return 0; +} + +static int cirrus_fb_blit_fullscreen(struct drm_framebuffer *fb) +{ + struct drm_rect fullscreen = { + .x1 = 0, + .x2 = fb->width, + .y1 = 0, + .y2 = fb->height, + }; + return cirrus_fb_blit_rect(fb, &fullscreen); +} + +static int cirrus_check_size(int width, int height, + struct drm_framebuffer *fb) +{ + int pitch = width * 2; + + if (fb) + pitch = cirrus_pitch(fb); + + if (pitch > CIRRUS_MAX_PITCH) + return -EINVAL; + if (pitch * height > CIRRUS_VRAM_SIZE) + return -EINVAL; + return 0; +} + +/* ------------------------------------------------------------------ */ +/* cirrus connector */ + +static int cirrus_conn_get_modes(struct drm_connector *conn) +{ + int count; + + count = drm_add_modes_noedid(conn, + conn->dev->mode_config.max_width, + conn->dev->mode_config.max_height); + drm_set_preferred_mode(conn, 1024, 768); + return count; +} + +static const struct drm_connector_helper_funcs cirrus_conn_helper_funcs = { + .get_modes = cirrus_conn_get_modes, +}; + +static const struct drm_connector_funcs cirrus_conn_funcs = { + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int cirrus_conn_init(struct cirrus_device *cirrus) +{ + drm_connector_helper_add(&cirrus->conn, &cirrus_conn_helper_funcs); + return drm_connector_init(&cirrus->dev, &cirrus->conn, + &cirrus_conn_funcs, DRM_MODE_CONNECTOR_VGA); + +} + +/* ------------------------------------------------------------------ */ +/* cirrus (simple) display pipe */ + +static enum drm_mode_status cirrus_pipe_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) +{ + if (cirrus_check_size(mode->hdisplay, mode->vdisplay, NULL) < 0) + return MODE_BAD; + return MODE_OK; +} + +static int cirrus_pipe_check(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *plane_state, + struct drm_crtc_state *crtc_state) +{ + struct drm_framebuffer *fb = plane_state->fb; + + if (!fb) + return 0; + return cirrus_check_size(fb->width, fb->height, fb); +} + +static void cirrus_pipe_enable(struct drm_simple_display_pipe *pipe, + struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state) +{ + struct cirrus_device *cirrus = pipe->crtc.dev->dev_private; + + cirrus_mode_set(cirrus, &crtc_state->mode, plane_state->fb); + cirrus_fb_blit_fullscreen(plane_state->fb); +} + +static void cirrus_pipe_update(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *old_state) +{ + struct cirrus_device *cirrus = pipe->crtc.dev->dev_private; + struct drm_plane_state *state = pipe->plane.state; + struct drm_crtc *crtc = &pipe->crtc; + struct drm_rect rect; + + if (pipe->plane.state->fb && + cirrus->cpp != cirrus_cpp(pipe->plane.state->fb)) + cirrus_mode_set(cirrus, &crtc->mode, + pipe->plane.state->fb); + + if (drm_atomic_helper_damage_merged(old_state, state, &rect)) + cirrus_fb_blit_rect(pipe->plane.state->fb, &rect); + + if (crtc->state->event) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + crtc->state->event = NULL; + spin_unlock_irq(&crtc->dev->event_lock); + } +} + +static const struct drm_simple_display_pipe_funcs cirrus_pipe_funcs = { + .mode_valid = cirrus_pipe_mode_valid, + .check = cirrus_pipe_check, + .enable = cirrus_pipe_enable, + .update = cirrus_pipe_update, +}; + +static const uint32_t cirrus_formats[] = { + DRM_FORMAT_RGB565, + DRM_FORMAT_RGB888, + DRM_FORMAT_XRGB8888, +}; + +static const uint64_t cirrus_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static int cirrus_pipe_init(struct cirrus_device *cirrus) +{ + return drm_simple_display_pipe_init(&cirrus->dev, + &cirrus->pipe, + &cirrus_pipe_funcs, + cirrus_formats, + ARRAY_SIZE(cirrus_formats), + cirrus_modifiers, + &cirrus->conn); +} + +/* ------------------------------------------------------------------ */ +/* cirrus framebuffers & mode config */ + +static struct drm_framebuffer* +cirrus_fb_create(struct drm_device *dev, struct drm_file *file_priv, + const struct drm_mode_fb_cmd2 *mode_cmd) +{ + if (mode_cmd->pixel_format != DRM_FORMAT_RGB565 && + mode_cmd->pixel_format != DRM_FORMAT_RGB888 && + mode_cmd->pixel_format != DRM_FORMAT_XRGB8888) + return ERR_PTR(-EINVAL); + if (cirrus_check_size(mode_cmd->width, mode_cmd->height, NULL) < 0) + return ERR_PTR(-EINVAL); + return drm_gem_fb_create_with_dirty(dev, file_priv, mode_cmd); +} + +static const struct drm_mode_config_funcs cirrus_mode_config_funcs = { + .fb_create = cirrus_fb_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static void cirrus_mode_config_init(struct cirrus_device *cirrus) +{ + struct drm_device *dev = &cirrus->dev; + + drm_mode_config_init(dev); + dev->mode_config.min_width = 0; + dev->mode_config.min_height = 0; + dev->mode_config.max_width = CIRRUS_MAX_PITCH / 2; + dev->mode_config.max_height = 1024; + dev->mode_config.preferred_depth = 16; + dev->mode_config.prefer_shadow = 0; + dev->mode_config.funcs = &cirrus_mode_config_funcs; +} + +/* ------------------------------------------------------------------ */ + +DEFINE_DRM_GEM_SHMEM_FOPS(cirrus_fops); + +static struct drm_driver cirrus_driver = { + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC | DRIVER_PRIME, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + + .fops = &cirrus_fops, + DRM_GEM_SHMEM_DRIVER_OPS, +}; + +static int cirrus_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct drm_device *dev; + struct cirrus_device *cirrus; + int ret; + + ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "cirrusdrmfb"); + if (ret) + return ret; + + ret = pci_enable_device(pdev); + if (ret) + return ret; + + ret = pci_request_regions(pdev, DRIVER_NAME); + if (ret) + return ret; + + ret = -ENOMEM; + cirrus = kzalloc(sizeof(*cirrus), GFP_KERNEL); + if (cirrus == NULL) + goto err_pci_release; + + dev = &cirrus->dev; + ret = drm_dev_init(dev, &cirrus_driver, &pdev->dev); + if (ret) + goto err_free_cirrus; + dev->dev_private = cirrus; + + ret = -ENOMEM; + cirrus->vram = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (cirrus->vram == NULL) + goto err_dev_put; + + cirrus->mmio = ioremap(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); + if (cirrus->mmio == NULL) + goto err_unmap_vram; + + cirrus_mode_config_init(cirrus); + + ret = cirrus_conn_init(cirrus); + if (ret < 0) + goto err_cleanup; + + ret = cirrus_pipe_init(cirrus); + if (ret < 0) + goto err_cleanup; + + drm_mode_config_reset(dev); + + dev->pdev = pdev; + pci_set_drvdata(pdev, dev); + ret = drm_dev_register(dev, 0); + if (ret) + goto err_cleanup; + + drm_fbdev_generic_setup(dev, dev->mode_config.preferred_depth); + return 0; + +err_cleanup: + drm_mode_config_cleanup(dev); + iounmap(cirrus->mmio); +err_unmap_vram: + iounmap(cirrus->vram); +err_dev_put: + drm_dev_put(dev); +err_free_cirrus: + kfree(cirrus); +err_pci_release: + pci_release_regions(pdev); + return ret; +} + +static void cirrus_pci_remove(struct pci_dev *pdev) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + struct cirrus_device *cirrus = dev->dev_private; + + drm_dev_unregister(dev); + drm_mode_config_cleanup(dev); + iounmap(cirrus->mmio); + iounmap(cirrus->vram); + drm_dev_put(dev); + kfree(cirrus); + pci_release_regions(pdev); +} + +static const struct pci_device_id pciidlist[] = { + { + .vendor = PCI_VENDOR_ID_CIRRUS, + .device = PCI_DEVICE_ID_CIRRUS_5446, + /* only bind to the cirrus chip in qemu */ + .subvendor = PCI_SUBVENDOR_ID_REDHAT_QUMRANET, + .subdevice = PCI_SUBDEVICE_ID_QEMU, + }, { + .vendor = PCI_VENDOR_ID_CIRRUS, + .device = PCI_DEVICE_ID_CIRRUS_5446, + .subvendor = PCI_VENDOR_ID_XEN, + .subdevice = 0x0001, + }, + { /* end if list */ } +}; + +static struct pci_driver cirrus_pci_driver = { + .name = DRIVER_NAME, + .id_table = pciidlist, + .probe = cirrus_pci_probe, + .remove = cirrus_pci_remove, +}; + +static int __init cirrus_init(void) +{ + if (vgacon_text_force()) + return -EINVAL; + return pci_register_driver(&cirrus_pci_driver); +} + +static void __exit cirrus_exit(void) +{ + pci_unregister_driver(&cirrus_pci_driver); +} + +module_init(cirrus_init); +module_exit(cirrus_exit); + +MODULE_DEVICE_TABLE(pci, pciidlist); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c deleted file mode 100644 index 8ec880f3a322..000000000000 --- a/drivers/gpu/drm/cirrus/cirrus_drv.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2012 Red Hat <mjg@redhat.com> - * - * This file is subject to the terms and conditions of the GNU General - * Public License version 2. See the file COPYING in the main - * directory of this archive for more details. - * - * Authors: Matthew Garrett - * Dave Airlie - */ -#include <linux/module.h> -#include <linux/console.h> -#include <drm/drmP.h> -#include <drm/drm_crtc_helper.h> -#include <drm/drm_probe_helper.h> - -#include "cirrus_drv.h" - -int cirrus_modeset = -1; -int cirrus_bpp = 16; - -MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); -module_param_named(modeset, cirrus_modeset, int, 0400); -MODULE_PARM_DESC(bpp, "Max bits-per-pixel (default:16)"); -module_param_named(bpp, cirrus_bpp, int, 0400); - -/* - * 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 - */ - -static struct drm_driver driver; - -/* only bind to the cirrus chip in qemu */ -static const struct pci_device_id pciidlist[] = { - { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, - PCI_SUBVENDOR_ID_REDHAT_QUMRANET, PCI_SUBDEVICE_ID_QEMU, - 0, 0, 0 }, - { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, PCI_VENDOR_ID_XEN, - 0x0001, 0, 0, 0 }, - {0,} -}; - - -static int cirrus_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int ret; - - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "cirrusdrmfb"); - if (ret) - return ret; - - return drm_get_pci_dev(pdev, ent, &driver); -} - -static void cirrus_pci_remove(struct pci_dev *pdev) -{ - struct drm_device *dev = pci_get_drvdata(pdev); - - drm_put_dev(dev); -} - -#ifdef CONFIG_PM_SLEEP -static int cirrus_pm_suspend(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); - struct cirrus_device *cdev = drm_dev->dev_private; - - drm_kms_helper_poll_disable(drm_dev); - - if (cdev->mode_info.gfbdev) { - console_lock(); - drm_fb_helper_set_suspend(&cdev->mode_info.gfbdev->helper, 1); - console_unlock(); - } - - return 0; -} - -static int cirrus_pm_resume(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); - struct cirrus_device *cdev = drm_dev->dev_private; - - drm_helper_resume_force_mode(drm_dev); - - if (cdev->mode_info.gfbdev) { - console_lock(); - drm_fb_helper_set_suspend(&cdev->mode_info.gfbdev->helper, 0); - console_unlock(); - } - - drm_kms_helper_poll_enable(drm_dev); - return 0; -} -#endif - -static const struct file_operations cirrus_driver_fops = { - .owner = THIS_MODULE, - .open = drm_open, - .release = drm_release, - .unlocked_ioctl = drm_ioctl, - .mmap = cirrus_mmap, - .poll = drm_poll, - .compat_ioctl = drm_compat_ioctl, -}; -static struct drm_driver driver = { - .driver_features = DRIVER_MODESET | DRIVER_GEM, - .load = cirrus_driver_load, - .unload = cirrus_driver_unload, - .fops = &cirrus_driver_fops, - .name = DRIVER_NAME, - .desc = DRIVER_DESC, - .date = DRIVER_DATE, - .major = DRIVER_MAJOR, - .minor = DRIVER_MINOR, - .patchlevel = DRIVER_PATCHLEVEL, - .gem_free_object_unlocked = cirrus_gem_free_object, - .dumb_create = cirrus_dumb_create, - .dumb_map_offset = cirrus_dumb_mmap_offset, -}; - -static const struct dev_pm_ops cirrus_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(cirrus_pm_suspend, - cirrus_pm_resume) -}; - -static struct pci_driver cirrus_pci_driver = { - .name = DRIVER_NAME, - .id_table = pciidlist, - .probe = cirrus_pci_probe, - .remove = cirrus_pci_remove, - .driver.pm = &cirrus_pm_ops, -}; - -static int __init cirrus_init(void) -{ - if (vgacon_text_force() && cirrus_modeset == -1) - return -EINVAL; - - if (cirrus_modeset == 0) - return -EINVAL; - return pci_register_driver(&cirrus_pci_driver); -} - -static void __exit cirrus_exit(void) -{ - pci_unregister_driver(&cirrus_pci_driver); -} - -module_init(cirrus_init); -module_exit(cirrus_exit); - -MODULE_DEVICE_TABLE(pci, pciidlist); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h deleted file mode 100644 index 828b150cdb20..000000000000 --- a/drivers/gpu/drm/cirrus/cirrus_drv.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2012 Red Hat - * - * This file is subject to the terms and conditions of the GNU General - * Public License version 2. See the file COPYING in the main - * directory of this archive for more details. - * - * Authors: Matthew Garrett - * Dave Airlie - */ -#ifndef __CIRRUS_DRV_H__ -#define __CIRRUS_DRV_H__ - -#include <video/vga.h> - -#include <drm/drm_encoder.h> -#include <drm/drm_fb_helper.h> - -#include <drm/ttm/ttm_bo_api.h> -#include <drm/ttm/ttm_bo_driver.h> -#include <drm/ttm/ttm_placement.h> -#include <drm/ttm/ttm_memory.h> -#include <drm/ttm/ttm_module.h> - -#include <drm/drm_gem.h> - -#define DRIVER_AUTHOR "Matthew Garrett" - -#define DRIVER_NAME "cirrus" -#define DRIVER_DESC "qemu Cirrus emulation" -#define DRIVER_DATE "20110418" - -#define DRIVER_MAJOR 1 -#define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 0 - -#define CIRRUSFB_CONN_LIMIT 1 - -#define RREG8(reg) ioread8(((void __iomem *)cdev->rmmio) + (reg)) -#define WREG8(reg, v) iowrite8(v, ((void __iomem *)cdev->rmmio) + (reg)) -#define RREG32(reg) ioread32(((void __iomem *)cdev->rmmio) + (reg)) -#define WREG32(reg, v) iowrite32(v, ((void __iomem *)cdev->rmmio) + (reg)) - -#define SEQ_INDEX 4 -#define SEQ_DATA 5 - -#define WREG_SEQ(reg, v) \ - do { \ - WREG8(SEQ_INDEX, reg); \ - WREG8(SEQ_DATA, v); \ - } while (0) \ - -#define CRT_INDEX 0x14 -#define CRT_DATA 0x15 - -#define WREG_CRT(reg, v) \ - do { \ - WREG8(CRT_INDEX, reg); \ - WREG8(CRT_DATA, v); \ - } while (0) \ - -#define GFX_INDEX 0xe -#define GFX_DATA 0xf - -#define WREG_GFX(reg, v) \ - do { \ - WREG8(GFX_INDEX, reg); \ - WREG8(GFX_DATA, v); \ - } while (0) \ - -/* - * Cirrus has a "hidden" DAC register that can be accessed by writing to - * the pixel mask register to reset the state, then reading from the register - * four times. The next write will then pass to the DAC - */ -#define VGA_DAC_MASK 0x6 - -#define WREG_HDR(v) \ - do { \ - RREG8(VGA_DAC_MASK); \ - RREG8(VGA_DAC_MASK); \ - RREG8(VGA_DAC_MASK); \ - RREG8(VGA_DAC_MASK); \ - WREG8(VGA_DAC_MASK, v); \ - } while (0) \ - - -#define CIRRUS_MAX_FB_HEIGHT 4096 -#define CIRRUS_MAX_FB_WIDTH 4096 - -#define CIRRUS_DPMS_CLEARED (-1) - -#define to_cirrus_crtc(x) container_of(x, struct cirrus_crtc, base) -#define to_cirrus_encoder(x) container_of(x, struct cirrus_encoder, base) - -struct cirrus_crtc { - struct drm_crtc base; - int last_dpms; - bool enabled; -}; - -struct cirrus_fbdev; -struct cirrus_mode_info { - struct cirrus_crtc *crtc; - /* pointer to fbdev info structure */ - struct cirrus_fbdev *gfbdev; -}; - -struct cirrus_encoder { - struct drm_encoder base; - int last_dpms; -}; - -struct cirrus_connector { - struct drm_connector base; -}; - -struct cirrus_mc { - resource_size_t vram_size; - resource_size_t vram_base; -}; - -struct cirrus_device { - struct drm_device *dev; - unsigned long flags; - - resource_size_t rmmio_base; - resource_size_t rmmio_size; - void __iomem *rmmio; - - struct cirrus_mc mc; - struct cirrus_mode_info mode_info; - - int num_crtc; - int fb_mtrr; - - struct { - struct ttm_bo_device bdev; - } ttm; - bool mm_inited; -}; - - -struct cirrus_fbdev { - struct drm_fb_helper helper; /* must be first */ - struct drm_framebuffer *gfb; - void *sysram; - int size; - int x1, y1, x2, y2; /* dirty rect */ - spinlock_t dirty_lock; -}; - -struct cirrus_bo { - struct ttm_buffer_object bo; - struct ttm_placement placement; - struct ttm_bo_kmap_obj kmap; - struct drm_gem_object gem; - struct ttm_place placements[3]; - int pin_count; -}; -#define gem_to_cirrus_bo(gobj) container_of((gobj), struct cirrus_bo, gem) - -static inline struct cirrus_bo * -cirrus_bo(struct ttm_buffer_object *bo) -{ - return container_of(bo, struct cirrus_bo, bo); -} - - -#define to_cirrus_obj(x) container_of(x, struct cirrus_gem_object, base) -#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT) - - /* cirrus_main.c */ -int cirrus_device_init(struct cirrus_device *cdev, - struct drm_device *ddev, - struct pci_dev *pdev, - uint32_t flags); -void cirrus_device_fini(struct cirrus_device *cdev); -void cirrus_gem_free_object(struct drm_gem_object *obj); -int cirrus_dumb_mmap_offset(struct drm_file *file, - struct drm_device *dev, - uint32_t handle, - uint64_t *offset); -int cirrus_gem_create(struct drm_device *dev, - u32 size, bool iskernel, - struct drm_gem_object **obj); -int cirrus_dumb_create(struct drm_file *file, - struct drm_device *dev, - struct drm_mode_create_dumb *args); - -int cirrus_framebuffer_init(struct drm_device *dev, - struct drm_framebuffer *gfb, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj); - -bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height, - int bpp, int pitch); - - /* cirrus_display.c */ -int cirrus_modeset_init(struct cirrus_device *cdev); -void cirrus_modeset_fini(struct cirrus_device *cdev); - - /* cirrus_fbdev.c */ -int cirrus_fbdev_init(struct cirrus_device *cdev); -void cirrus_fbdev_fini(struct cirrus_device *cdev); - - - - /* cirrus_irq.c */ -void cirrus_driver_irq_preinstall(struct drm_device *dev); -int cirrus_driver_irq_postinstall(struct drm_device *dev); -void cirrus_driver_irq_uninstall(struct drm_device *dev); -irqreturn_t cirrus_driver_irq_handler(int irq, void *arg); - - /* cirrus_kms.c */ -int cirrus_driver_load(struct drm_device *dev, unsigned long flags); -void cirrus_driver_unload(struct drm_device *dev); -extern struct drm_ioctl_desc cirrus_ioctls[]; -extern int cirrus_max_ioctl; - -int cirrus_mm_init(struct cirrus_device *cirrus); -void cirrus_mm_fini(struct cirrus_device *cirrus); -void cirrus_ttm_placement(struct cirrus_bo *bo, int domain); -int cirrus_bo_create(struct drm_device *dev, int size, int align, - uint32_t flags, struct cirrus_bo **pcirrusbo); -int cirrus_mmap(struct file *filp, struct vm_area_struct *vma); - -static inline int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait) -{ - int ret; - - ret = ttm_bo_reserve(&bo->bo, true, no_wait, NULL); - if (ret) { - if (ret != -ERESTARTSYS && ret != -EBUSY) - DRM_ERROR("reserve failed %p\n", bo); - return ret; - } - return 0; -} - -static inline void cirrus_bo_unreserve(struct cirrus_bo *bo) -{ - ttm_bo_unreserve(&bo->bo); -} - -int cirrus_bo_push_sysram(struct cirrus_bo *bo); -int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr); - -extern int cirrus_bpp; - -#endif /* __CIRRUS_DRV_H__ */ diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c deleted file mode 100644 index 2e6128069fc3..000000000000 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright 2012 Red Hat - * - * This file is subject to the terms and conditions of the GNU General - * Public License version 2. See the file COPYING in the main - * directory of this archive for more details. - * - * Authors: Matthew Garrett - * Dave Airlie - */ -#include <linux/module.h> -#include <drm/drmP.h> -#include <drm/drm_util.h> -#include <drm/drm_fb_helper.h> -#include <drm/drm_crtc_helper.h> - -#include "cirrus_drv.h" - -static void cirrus_dirty_update(struct cirrus_fbdev *afbdev, - int x, int y, int width, int height) -{ - int i; - struct drm_gem_object *obj; - struct cirrus_bo *bo; - int src_offset, dst_offset; - int bpp = afbdev->gfb->format->cpp[0]; - int ret = -EBUSY; - bool unmap = false; - bool store_for_later = false; - int x2, y2; - unsigned long flags; - - obj = afbdev->gfb->obj[0]; - bo = gem_to_cirrus_bo(obj); - - /* - * try and reserve the BO, if we fail with busy - * then the BO is being moved and we should - * store up the damage until later. - */ - if (drm_can_sleep()) - ret = cirrus_bo_reserve(bo, true); - if (ret) { - if (ret != -EBUSY) - return; - store_for_later = true; - } - - x2 = x + width - 1; - y2 = y + height - 1; - spin_lock_irqsave(&afbdev->dirty_lock, flags); - - if (afbdev->y1 < y) - y = afbdev->y1; - if (afbdev->y2 > y2) - y2 = afbdev->y2; - if (afbdev->x1 < x) - x = afbdev->x1; - if (afbdev->x2 > x2) - x2 = afbdev->x2; - - if (store_for_later) { - afbdev->x1 = x; - afbdev->x2 = x2; - afbdev->y1 = y; - afbdev->y2 = y2; - spin_unlock_irqrestore(&afbdev->dirty_lock, flags); - return; - } - - afbdev->x1 = afbdev->y1 = INT_MAX; - afbdev->x2 = afbdev->y2 = 0; - spin_unlock_irqrestore(&afbdev->dirty_lock, flags); - - if (!bo->kmap.virtual) { - ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); - if (ret) { - DRM_ERROR("failed to kmap fb updates\n"); - cirrus_bo_unreserve(bo); - return; - } - unmap = true; - } - for (i = y; i < y + height; i++) { - /* assume equal stride for now */ - src_offset = dst_offset = i * afbdev->gfb->pitches[0] + (x * bpp); - memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp); - - } - if (unmap) - ttm_bo_kunmap(&bo->kmap); - - cirrus_bo_unreserve(bo); -} - -static void cirrus_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - struct cirrus_fbdev *afbdev = info->par; - drm_fb_helper_sys_fillrect(info, rect); - cirrus_dirty_update(afbdev, rect->dx, rect->dy, rect->width, - rect->height); -} - -static void cirrus_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - struct cirrus_fbdev *afbdev = info->par; - drm_fb_helper_sys_copyarea(info, area); - cirrus_dirty_update(afbdev, area->dx, area->dy, area->width, - area->height); -} - -static void cirrus_imageblit(struct fb_info *info, - const struct fb_image *image) -{ - struct cirrus_fbdev *afbdev = info->par; - drm_fb_helper_sys_imageblit(info, image); - cirrus_dirty_update(afbdev, image->dx, image->dy, image->width, - image->height); -} - - -static struct fb_ops cirrusfb_ops = { - .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, - .fb_fillrect = cirrus_fillrect, - .fb_copyarea = cirrus_copyarea, - .fb_imageblit = cirrus_imageblit, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, -}; - -static int cirrusfb_create_object(struct cirrus_fbdev *afbdev, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object **gobj_p) -{ - struct drm_device *dev = afbdev->helper.dev; - struct cirrus_device *cdev = dev->dev_private; - u32 bpp; - u32 size; - struct drm_gem_object *gobj; - int ret = 0; - - bpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0) * 8; - - if (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height, - bpp, mode_cmd->pitches[0])) - return -EINVAL; - - size = mode_cmd->pitches[0] * mode_cmd->height; - ret = cirrus_gem_create(dev, size, true, &gobj); - if (ret) - return ret; - - *gobj_p = gobj; - return ret; -} - -static int cirrusfb_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct cirrus_fbdev *gfbdev = - container_of(helper, struct cirrus_fbdev, helper); - struct cirrus_device *cdev = gfbdev->helper.dev->dev_private; - struct fb_info *info; - struct drm_framebuffer *fb; - struct drm_mode_fb_cmd2 mode_cmd; - void *sysram; - struct drm_gem_object *gobj = NULL; - int size, ret; - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8); - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - size = mode_cmd.pitches[0] * mode_cmd.height; - - ret = cirrusfb_create_object(gfbdev, &mode_cmd, &gobj); - if (ret) { - DRM_ERROR("failed to create fbcon backing object %d\n", ret); - return ret; - } - - sysram = vmalloc(size); - if (!sysram) - return -ENOMEM; - - info = drm_fb_helper_alloc_fbi(helper); - if (IS_ERR(info)) { - ret = PTR_ERR(info); - goto err_vfree; - } - - fb = kzalloc(sizeof(*fb), GFP_KERNEL); - if (!fb) { - ret = -ENOMEM; - goto err_drm_gem_object_put_unlocked; - } - - ret = cirrus_framebuffer_init(cdev->dev, fb, &mode_cmd, gobj); - if (ret) - goto err_kfree; - - gfbdev->sysram = sysram; - gfbdev->size = size; - gfbdev->gfb = fb; - - /* setup helper */ - gfbdev->helper.fb = fb; - - info->fbops = &cirrusfb_ops; - - drm_fb_helper_fill_info(info, &gfbdev->helper, sizes); - - /* setup aperture base/size for vesafb takeover */ - info->apertures->ranges[0].base = cdev->dev->mode_config.fb_base; - info->apertures->ranges[0].size = cdev->mc.vram_size; - - info->fix.smem_start = cdev->dev->mode_config.fb_base; - info->fix.smem_len = cdev->mc.vram_size; - - info->screen_base = sysram; - info->screen_size = size; - - info->fix.mmio_start = 0; - info->fix.mmio_len = 0; - - DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); - DRM_INFO("vram aper at 0x%lX\n", (unsigned long)info->fix.smem_start); - DRM_INFO("size %lu\n", (unsigned long)info->fix.smem_len); - DRM_INFO("fb depth is %d\n", fb->format->depth); - DRM_INFO(" pitch is %d\n", fb->pitches[0]); - - return 0; - -err_kfree: - kfree(fb); -err_drm_gem_object_put_unlocked: - drm_gem_object_put_unlocked(gobj); -err_vfree: - vfree(sysram); - return ret; -} - -static int cirrus_fbdev_destroy(struct drm_device *dev, - struct cirrus_fbdev *gfbdev) -{ - struct drm_framebuffer *gfb = gfbdev->gfb; - - drm_helper_force_disable_all(dev); - - drm_fb_helper_unregister_fbi(&gfbdev->helper); - - vfree(gfbdev->sysram); - drm_fb_helper_fini(&gfbdev->helper); - if (gfb) - drm_framebuffer_put(gfb); - - return 0; -} - -static const struct drm_fb_helper_funcs cirrus_fb_helper_funcs = { - .fb_probe = cirrusfb_create, -}; - -int cirrus_fbdev_init(struct cirrus_device *cdev) -{ - struct cirrus_fbdev *gfbdev; - int ret; - - /*bpp_sel = 8;*/ - gfbdev = kzalloc(sizeof(struct cirrus_fbdev), GFP_KERNEL); - if (!gfbdev) - return -ENOMEM; - - cdev->mode_info.gfbdev = gfbdev; - spin_lock_init(&gfbdev->dirty_lock); - - drm_fb_helper_prepare(cdev->dev, &gfbdev->helper, - &cirrus_fb_helper_funcs); - - ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper, - CIRRUSFB_CONN_LIMIT); - if (ret) - return ret; - - ret = drm_fb_helper_single_add_all_connectors(&gfbdev->helper); - if (ret) - return ret; - - /* disable all the possible outputs/crtcs before entering KMS mode */ - drm_helper_disable_unused_functions(cdev->dev); - - return drm_fb_helper_initial_config(&gfbdev->helper, cirrus_bpp); -} - -void cirrus_fbdev_fini(struct cirrus_device *cdev) -{ - if (!cdev->mode_info.gfbdev) - return; - - cirrus_fbdev_destroy(cdev->dev, cdev->mode_info.gfbdev); - kfree(cdev->mode_info.gfbdev); - cdev->mode_info.gfbdev = NULL; -} diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c deleted file mode 100644 index 57f8fe6d020b..000000000000 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright 2012 Red Hat - * - * This file is subject to the terms and conditions of the GNU General - * Public License version 2. See the file COPYING in the main - * directory of this archive for more details. - * - * Authors: Matthew Garrett - * Dave Airlie - */ -#include <drm/drmP.h> -#include <drm/drm_crtc_helper.h> -#include <drm/drm_gem_framebuffer_helper.h> - -#include "cirrus_drv.h" - -static const struct drm_framebuffer_funcs cirrus_fb_funcs = { - .create_handle = drm_gem_fb_create_handle, - .destroy = drm_gem_fb_destroy, -}; - -int cirrus_framebuffer_init(struct drm_device *dev, - struct drm_framebuffer *gfb, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj) -{ - int ret; - - drm_helper_mode_fill_fb_struct(dev, gfb, mode_cmd); - gfb->obj[0] = obj; - ret = drm_framebuffer_init(dev, gfb, &cirrus_fb_funcs); - if (ret) { - DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); - return ret; - } - return 0; -} - -static struct drm_framebuffer * -cirrus_user_framebuffer_create(struct drm_device *dev, - struct drm_file *filp, - const struct drm_mode_fb_cmd2 *mode_cmd) -{ - struct cirrus_device *cdev = dev->dev_private; - struct drm_gem_object *obj; - struct drm_framebuffer *fb; - u32 bpp; - int ret; - - bpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0) * 8; - - if (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height, - bpp, mode_cmd->pitches[0])) - return ERR_PTR(-EINVAL); - - obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]); - if (obj == NULL) - return ERR_PTR(-ENOENT); - - fb = kzalloc(sizeof(*fb), GFP_KERNEL); - if (!fb) { - drm_gem_object_put_unlocked(obj); - return ERR_PTR(-ENOMEM); - } - - ret = cirrus_framebuffer_init(dev, fb, mode_cmd, obj); - if (ret) { - drm_gem_object_put_unlocked(obj); - kfree(fb); - return ERR_PTR(ret); - } - return fb; -} - -static const struct drm_mode_config_funcs cirrus_mode_funcs = { - .fb_create = cirrus_user_framebuffer_create, -}; - -/* Unmap the framebuffer from the core and release the memory */ -static void cirrus_vram_fini(struct cirrus_device *cdev) -{ - iounmap(cdev->rmmio); - cdev->rmmio = NULL; - if (cdev->mc.vram_base) - release_mem_region(cdev->mc.vram_base, cdev->mc.vram_size); -} - -/* Map the framebuffer from the card and configure the core */ -static int cirrus_vram_init(struct cirrus_device *cdev) -{ - /* BAR 0 is VRAM */ - cdev->mc.vram_base = pci_resource_start(cdev->dev->pdev, 0); - cdev->mc.vram_size = pci_resource_len(cdev->dev->pdev, 0); - - if (!request_mem_region(cdev->mc.vram_base, cdev->mc.vram_size, - "cirrusdrmfb_vram")) { - DRM_ERROR("can't reserve VRAM\n"); - return -ENXIO; - } - - return 0; -} - -/* - * Our emulated hardware has two sets of memory. One is video RAM and can - * simply be used as a linear framebuffer - the other provides mmio access - * to the display registers. The latter can also be accessed via IO port - * access, but we map the range and use mmio to program them instead - */ - -int cirrus_device_init(struct cirrus_device *cdev, - struct drm_device *ddev, - struct pci_dev *pdev, uint32_t flags) -{ - int ret; - - cdev->dev = ddev; - cdev->flags = flags; - - /* Hardcode the number of CRTCs to 1 */ - cdev->num_crtc = 1; - - /* BAR 0 is the framebuffer, BAR 1 contains registers */ - cdev->rmmio_base = pci_resource_start(cdev->dev->pdev, 1); - cdev->rmmio_size = pci_resource_len(cdev->dev->pdev, 1); - - if (!request_mem_region(cdev->rmmio_base, cdev->rmmio_size, - "cirrusdrmfb_mmio")) { - DRM_ERROR("can't reserve mmio registers\n"); - return -ENOMEM; - } - - cdev->rmmio = ioremap(cdev->rmmio_base, cdev->rmmio_size); - - if (cdev->rmmio == NULL) - return -ENOMEM; - - ret = cirrus_vram_init(cdev); - if (ret) { - release_mem_region(cdev->rmmio_base, cdev->rmmio_size); - return ret; - } - - return 0; -} - -void cirrus_device_fini(struct cirrus_device *cdev) -{ - release_mem_region(cdev->rmmio_base, cdev->rmmio_size); - cirrus_vram_fini(cdev); -} - -/* - * Functions here will be called by the core once it's bound the driver to - * a PCI device - */ - -int cirrus_driver_load(struct drm_device *dev, unsigned long flags) -{ - struct cirrus_device *cdev; - int r; - - cdev = kzalloc(sizeof(struct cirrus_device), GFP_KERNEL); - if (cdev == NULL) - return -ENOMEM; - dev->dev_private = (void *)cdev; - - r = cirrus_device_init(cdev, dev, dev->pdev, flags); - if (r) { - dev_err(&dev->pdev->dev, "Fatal error during GPU init: %d\n", r); - goto out; - } - - r = cirrus_mm_init(cdev); - if (r) { - dev_err(&dev->pdev->dev, "fatal err on mm init\n"); - goto out; - } - - /* - * cirrus_modeset_init() is initializing/registering the emulated fbdev - * and DRM internals can access/test some of the fields in - * mode_config->funcs as part of the fbdev registration process. - * Make sure dev->mode_config.funcs is properly set to avoid - * dereferencing a NULL pointer. - * FIXME: mode_config.funcs assignment should probably be done in - * cirrus_modeset_init() (that's a common pattern seen in other DRM - * drivers). - */ - dev->mode_config.funcs = &cirrus_mode_funcs; - r = cirrus_modeset_init(cdev); - if (r) { - dev_err(&dev->pdev->dev, "Fatal error during modeset init: %d\n", r); - goto out; - } - - return 0; -out: - cirrus_driver_unload(dev); - return r; -} - -void cirrus_driver_unload(struct drm_device *dev) -{ - struct cirrus_device *cdev = dev->dev_private; - - if (cdev == NULL) - return; - cirrus_modeset_fini(cdev); - cirrus_mm_fini(cdev); - cirrus_device_fini(cdev); - kfree(cdev); - dev->dev_private = NULL; -} - -int cirrus_gem_create(struct drm_device *dev, - u32 size, bool iskernel, - struct drm_gem_object **obj) -{ - struct cirrus_bo *cirrusbo; - int ret; - - *obj = NULL; - - size = roundup(size, PAGE_SIZE); - if (size == 0) - return -EINVAL; - - ret = cirrus_bo_create(dev, size, 0, 0, &cirrusbo); - if (ret) { - if (ret != -ERESTARTSYS) - DRM_ERROR("failed to allocate GEM object\n"); - return ret; - } - *obj = &cirrusbo->gem; - return 0; -} - -int cirrus_dumb_create(struct drm_file *file, - struct drm_device *dev, - struct drm_mode_create_dumb *args) -{ - int ret; - struct drm_gem_object *gobj; - u32 handle; - - args->pitch = args->width * ((args->bpp + 7) / 8); - args->size = args->pitch * args->height; - - ret = cirrus_gem_create(dev, args->size, false, - &gobj); - if (ret) - return ret; - - ret = drm_gem_handle_create(file, gobj, &handle); - drm_gem_object_put_unlocked(gobj); - if (ret) - return ret; - - args->handle = handle; - return 0; -} - -static void cirrus_bo_unref(struct cirrus_bo **bo) -{ - struct ttm_buffer_object *tbo; - - if ((*bo) == NULL) - return; - - tbo = &((*bo)->bo); - ttm_bo_put(tbo); - *bo = NULL; -} - -void cirrus_gem_free_object(struct drm_gem_object *obj) -{ - struct cirrus_bo *cirrus_bo = gem_to_cirrus_bo(obj); - - cirrus_bo_unref(&cirrus_bo); -} - - -static inline u64 cirrus_bo_mmap_offset(struct cirrus_bo *bo) -{ - return drm_vma_node_offset_addr(&bo->bo.vma_node); -} - -int -cirrus_dumb_mmap_offset(struct drm_file *file, - struct drm_device *dev, - uint32_t handle, - uint64_t *offset) -{ - struct drm_gem_object *obj; - struct cirrus_bo *bo; - - obj = drm_gem_object_lookup(file, handle); - if (obj == NULL) - return -ENOENT; - - bo = gem_to_cirrus_bo(obj); - *offset = cirrus_bo_mmap_offset(bo); - - drm_gem_object_put_unlocked(obj); - - return 0; -} - -bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height, - int bpp, int pitch) -{ - const int max_pitch = 0x1FF << 3; /* (4096 - 1) & ~111b bytes */ - const int max_size = cdev->mc.vram_size; - - if (bpp > cirrus_bpp) - return false; - if (bpp > 32) - return false; - - if (pitch > max_pitch) - return false; - - if (pitch * height > max_size) - return false; - - return true; -} diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c deleted file mode 100644 index b109cd71426f..000000000000 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ /dev/null @@ -1,617 +0,0 @@ - -/* - * Copyright 2012 Red Hat - * - * This file is subject to the terms and conditions of the GNU General - * Public License version 2. See the file COPYING in the main - * directory of this archive for more details. - * - * Authors: Matthew Garrett - * Dave Airlie - * - * Portions of this code derived from cirrusfb.c: - * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets - * - * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com> - */ -#include <drm/drmP.h> -#include <drm/drm_crtc_helper.h> -#include <drm/drm_plane_helper.h> -#include <drm/drm_probe_helper.h> - -#include <video/cirrus.h> - -#include "cirrus_drv.h" - -#define CIRRUS_LUT_SIZE 256 - -#define PALETTE_INDEX 0x8 -#define PALETTE_DATA 0x9 - -/* - * This file contains setup code for the CRTC. - */ - -/* - * The DRM core requires DPMS functions, but they make little sense in our - * case and so are just stubs - */ - -static void cirrus_crtc_dpms(struct drm_crtc *crtc, int mode) -{ - struct drm_device *dev = crtc->dev; - struct cirrus_device *cdev = dev->dev_private; - u8 sr01, gr0e; - - switch (mode) { - case DRM_MODE_DPMS_ON: - sr01 = 0x00; - gr0e = 0x00; - break; - case DRM_MODE_DPMS_STANDBY: - sr01 = 0x20; - gr0e = 0x02; - break; - case DRM_MODE_DPMS_SUSPEND: - sr01 = 0x20; - gr0e = 0x04; - break; - case DRM_MODE_DPMS_OFF: - sr01 = 0x20; - gr0e = 0x06; - break; - default: - return; - } - - WREG8(SEQ_INDEX, 0x1); - sr01 |= RREG8(SEQ_DATA) & ~0x20; - WREG_SEQ(0x1, sr01); - - WREG8(GFX_INDEX, 0xe); - gr0e |= RREG8(GFX_DATA) & ~0x06; - WREG_GFX(0xe, gr0e); -} - -static void cirrus_set_start_address(struct drm_crtc *crtc, unsigned offset) -{ - struct cirrus_device *cdev = crtc->dev->dev_private; - u32 addr; - u8 tmp; - - addr = offset >> 2; - WREG_CRT(0x0c, (u8)((addr >> 8) & 0xff)); - WREG_CRT(0x0d, (u8)(addr & 0xff)); - - WREG8(CRT_INDEX, 0x1b); - tmp = RREG8(CRT_DATA); - tmp &= 0xf2; - tmp |= (addr >> 16) & 0x01; - tmp |= (addr >> 15) & 0x0c; - WREG_CRT(0x1b, tmp); - WREG8(CRT_INDEX, 0x1d); - tmp = RREG8(CRT_DATA); - tmp &= 0x7f; - tmp |= (addr >> 12) & 0x80; - WREG_CRT(0x1d, tmp); -} - -/* cirrus is different - we will force move buffers out of VRAM */ -static int cirrus_crtc_do_set_base(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int x, int y, int atomic) -{ - struct cirrus_device *cdev = crtc->dev->dev_private; - struct cirrus_bo *bo; - int ret; - u64 gpu_addr; - - /* push the previous fb to system ram */ - if (!atomic && fb) { - bo = gem_to_cirrus_bo(fb->obj[0]); - ret = cirrus_bo_reserve(bo, false); - if (ret) - return ret; - cirrus_bo_push_sysram(bo); - cirrus_bo_unreserve(bo); - } - - bo = gem_to_cirrus_bo(crtc->primary->fb->obj[0]); - - ret = cirrus_bo_reserve(bo, false); - if (ret) - return ret; - - ret = cirrus_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); - if (ret) { - cirrus_bo_unreserve(bo); - return ret; - } - - if (cdev->mode_info.gfbdev->gfb == crtc->primary->fb) { - /* if pushing console in kmap it */ - ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); - if (ret) - DRM_ERROR("failed to kmap fbcon\n"); - } - cirrus_bo_unreserve(bo); - - cirrus_set_start_address(crtc, (u32)gpu_addr); - return 0; -} - -static int cirrus_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb) -{ - return cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0); -} - -/* - * The meat of this driver. The core passes us a mode and we have to program - * it. The modesetting here is the bare minimum required to satisfy the qemu - * emulation of this hardware, and running this against a real device is - * likely to result in an inadequately programmed mode. We've already had - * the opportunity to modify the mode, so whatever we receive here should - * be something that can be correctly programmed and displayed - */ -static int cirrus_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) -{ - struct drm_device *dev = crtc->dev; - struct cirrus_device *cdev = dev->dev_private; - const struct drm_framebuffer *fb = crtc->primary->fb; - int hsyncstart, hsyncend, htotal, hdispend; - int vtotal, vdispend; - int tmp; - int sr07 = 0, hdr = 0; - - htotal = mode->htotal / 8; - hsyncend = mode->hsync_end / 8; - hsyncstart = mode->hsync_start / 8; - hdispend = mode->hdisplay / 8; - - vtotal = mode->vtotal; - vdispend = mode->vdisplay; - - vdispend -= 1; - vtotal -= 2; - - htotal -= 5; - hdispend -= 1; - hsyncstart += 1; - hsyncend += 1; - - WREG_CRT(VGA_CRTC_V_SYNC_END, 0x20); - WREG_CRT(VGA_CRTC_H_TOTAL, htotal); - WREG_CRT(VGA_CRTC_H_DISP, hdispend); - WREG_CRT(VGA_CRTC_H_SYNC_START, hsyncstart); - WREG_CRT(VGA_CRTC_H_SYNC_END, hsyncend); - WREG_CRT(VGA_CRTC_V_TOTAL, vtotal & 0xff); - WREG_CRT(VGA_CRTC_V_DISP_END, vdispend & 0xff); - - tmp = 0x40; - if ((vdispend + 1) & 512) - tmp |= 0x20; - WREG_CRT(VGA_CRTC_MAX_SCAN, tmp); - - /* - * Overflow bits for values that don't fit in the standard registers - */ - tmp = 16; - if (vtotal & 256) - tmp |= 1; - if (vdispend & 256) - tmp |= 2; - if ((vdispend + 1) & 256) - tmp |= 8; - if (vtotal & 512) - tmp |= 32; - if (vdispend & 512) - tmp |= 64; - WREG_CRT(VGA_CRTC_OVERFLOW, tmp); - - tmp = 0; - - /* More overflow bits */ - - if ((htotal + 5) & 64) - tmp |= 16; - if ((htotal + 5) & 128) - tmp |= 32; - if (vtotal & 256) - tmp |= 64; - if (vtotal & 512) - tmp |= 128; - - WREG_CRT(CL_CRT1A, tmp); - - /* Disable Hercules/CGA compatibility */ - WREG_CRT(VGA_CRTC_MODE, 0x03); - - WREG8(SEQ_INDEX, 0x7); - sr07 = RREG8(SEQ_DATA); - sr07 &= 0xe0; - hdr = 0; - switch (fb->format->cpp[0] * 8) { - case 8: - sr07 |= 0x11; - break; - case 16: - sr07 |= 0x17; - hdr = 0xc1; - break; - case 24: - sr07 |= 0x15; - hdr = 0xc5; - break; - case 32: - sr07 |= 0x19; - hdr = 0xc5; - break; - default: - return -1; - } - - WREG_SEQ(0x7, sr07); - - /* Program the pitch */ - tmp = fb->pitches[0] / 8; - WREG_CRT(VGA_CRTC_OFFSET, tmp); - - /* Enable extended blanking and pitch bits, and enable full memory */ - tmp = 0x22; - tmp |= (fb->pitches[0] >> 7) & 0x10; - tmp |= (fb->pitches[0] >> 6) & 0x40; - WREG_CRT(0x1b, tmp); - - /* Enable high-colour modes */ - WREG_GFX(VGA_GFX_MODE, 0x40); - - /* And set graphics mode */ - WREG_GFX(VGA_GFX_MISC, 0x01); - - WREG_HDR(hdr); - cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0); - - /* Unblank (needed on S3 resume, vgabios doesn't do it then) */ - outb(0x20, 0x3c0); - return 0; -} - -/* - * 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 cirrus_crtc_prepare(struct drm_crtc *crtc) -{ -} - -static void cirrus_crtc_load_lut(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct cirrus_device *cdev = dev->dev_private; - u16 *r, *g, *b; - int i; - - if (!crtc->enabled) - return; - - r = crtc->gamma_store; - g = r + crtc->gamma_size; - b = g + crtc->gamma_size; - - for (i = 0; i < CIRRUS_LUT_SIZE; i++) { - /* VGA registers */ - WREG8(PALETTE_INDEX, i); - WREG8(PALETTE_DATA, *r++ >> 8); - WREG8(PALETTE_DATA, *g++ >> 8); - WREG8(PALETTE_DATA, *b++ >> 8); - } -} - -/* - * This is called after a mode is programmed. It should reverse anything done - * by the prepare function - */ -static void cirrus_crtc_commit(struct drm_crtc *crtc) -{ - cirrus_crtc_load_lut(crtc); -} - -/* - * 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 cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size, - struct drm_modeset_acquire_ctx *ctx) -{ - cirrus_crtc_load_lut(crtc); - - return 0; -} - -/* Simple cleanup function */ -static void cirrus_crtc_destroy(struct drm_crtc *crtc) -{ - struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc); - - drm_crtc_cleanup(crtc); - kfree(cirrus_crtc); -} - -/* These provide the minimum set of functions required to handle a CRTC */ -static const struct drm_crtc_funcs cirrus_crtc_funcs = { - .gamma_set = cirrus_crtc_gamma_set, - .set_config = drm_crtc_helper_set_config, - .destroy = cirrus_crtc_destroy, -}; - -static const struct drm_crtc_helper_funcs cirrus_helper_funcs = { - .dpms = cirrus_crtc_dpms, - .mode_set = cirrus_crtc_mode_set, - .mode_set_base = cirrus_crtc_mode_set_base, - .prepare = cirrus_crtc_prepare, - .commit = cirrus_crtc_commit, -}; - -/* CRTC setup */ -static const uint32_t cirrus_formats_16[] = { - DRM_FORMAT_RGB565, -}; - -static const uint32_t cirrus_formats_24[] = { - DRM_FORMAT_RGB888, - DRM_FORMAT_RGB565, -}; - -static const uint32_t cirrus_formats_32[] = { - DRM_FORMAT_XRGB8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_RGB888, - DRM_FORMAT_RGB565, -}; - -static struct drm_plane *cirrus_primary_plane(struct drm_device *dev) -{ - const uint32_t *formats; - uint32_t nformats; - struct drm_plane *primary; - int ret; - - switch (cirrus_bpp) { - case 16: - formats = cirrus_formats_16; - nformats = ARRAY_SIZE(cirrus_formats_16); - break; - case 24: - formats = cirrus_formats_24; - nformats = ARRAY_SIZE(cirrus_formats_24); - break; - case 32: - formats = cirrus_formats_32; - nformats = ARRAY_SIZE(cirrus_formats_32); - break; - default: - return NULL; - } - - primary = kzalloc(sizeof(*primary), GFP_KERNEL); - if (primary == NULL) { - DRM_DEBUG_KMS("Failed to allocate primary plane\n"); - return NULL; - } - - ret = drm_universal_plane_init(dev, primary, 0, - &drm_primary_helper_funcs, - formats, nformats, - NULL, - DRM_PLANE_TYPE_PRIMARY, NULL); - if (ret) { - kfree(primary); - primary = NULL; - } - - return primary; -} - -static void cirrus_crtc_init(struct drm_device *dev) -{ - struct cirrus_device *cdev = dev->dev_private; - struct cirrus_crtc *cirrus_crtc; - struct drm_plane *primary; - - cirrus_crtc = kzalloc(sizeof(struct cirrus_crtc) + - (CIRRUSFB_CONN_LIMIT * sizeof(struct drm_connector *)), - GFP_KERNEL); - - if (cirrus_crtc == NULL) - return; - - primary = cirrus_primary_plane(dev); - if (primary == NULL) { - kfree(cirrus_crtc); - return; - } - - drm_crtc_init_with_planes(dev, &cirrus_crtc->base, - primary, NULL, - &cirrus_crtc_funcs, NULL); - - drm_mode_crtc_set_gamma_size(&cirrus_crtc->base, CIRRUS_LUT_SIZE); - cdev->mode_info.crtc = cirrus_crtc; - - drm_crtc_helper_add(&cirrus_crtc->base, &cirrus_helper_funcs); -} - -static void cirrus_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ -} - -static void cirrus_encoder_dpms(struct drm_encoder *encoder, int state) -{ - return; -} - -static void cirrus_encoder_prepare(struct drm_encoder *encoder) -{ -} - -static void cirrus_encoder_commit(struct drm_encoder *encoder) -{ -} - -static void cirrus_encoder_destroy(struct drm_encoder *encoder) -{ - struct cirrus_encoder *cirrus_encoder = to_cirrus_encoder(encoder); - drm_encoder_cleanup(encoder); - kfree(cirrus_encoder); -} - -static const struct drm_encoder_helper_funcs cirrus_encoder_helper_funcs = { - .dpms = cirrus_encoder_dpms, - .mode_set = cirrus_encoder_mode_set, - .prepare = cirrus_encoder_prepare, - .commit = cirrus_encoder_commit, -}; - -static const struct drm_encoder_funcs cirrus_encoder_encoder_funcs = { - .destroy = cirrus_encoder_destroy, -}; - -static struct drm_encoder *cirrus_encoder_init(struct drm_device *dev) -{ - struct drm_encoder *encoder; - struct cirrus_encoder *cirrus_encoder; - - cirrus_encoder = kzalloc(sizeof(struct cirrus_encoder), GFP_KERNEL); - if (!cirrus_encoder) - return NULL; - - encoder = &cirrus_encoder->base; - encoder->possible_crtcs = 0x1; - - drm_encoder_init(dev, encoder, &cirrus_encoder_encoder_funcs, - DRM_MODE_ENCODER_DAC, NULL); - drm_encoder_helper_add(encoder, &cirrus_encoder_helper_funcs); - - return encoder; -} - - -static int cirrus_vga_get_modes(struct drm_connector *connector) -{ - int count; - - /* Just add a static list of modes */ - if (cirrus_bpp <= 24) { - count = drm_add_modes_noedid(connector, 1280, 1024); - drm_set_preferred_mode(connector, 1024, 768); - } else { - count = drm_add_modes_noedid(connector, 800, 600); - drm_set_preferred_mode(connector, 800, 600); - } - return count; -} - -static struct drm_encoder *cirrus_connector_best_encoder(struct drm_connector - *connector) -{ - int enc_id = connector->encoder_ids[0]; - /* pick the encoder ids */ - if (enc_id) - return drm_encoder_find(connector->dev, NULL, enc_id); - return NULL; -} - -static void cirrus_connector_destroy(struct drm_connector *connector) -{ - drm_connector_cleanup(connector); - kfree(connector); -} - -static const struct drm_connector_helper_funcs cirrus_vga_connector_helper_funcs = { - .get_modes = cirrus_vga_get_modes, - .best_encoder = cirrus_connector_best_encoder, -}; - -static const struct drm_connector_funcs cirrus_vga_connector_funcs = { - .dpms = drm_helper_connector_dpms, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = cirrus_connector_destroy, -}; - -static struct drm_connector *cirrus_vga_init(struct drm_device *dev) -{ - struct drm_connector *connector; - struct cirrus_connector *cirrus_connector; - - cirrus_connector = kzalloc(sizeof(struct cirrus_connector), GFP_KERNEL); - if (!cirrus_connector) - return NULL; - - connector = &cirrus_connector->base; - - drm_connector_init(dev, connector, - &cirrus_vga_connector_funcs, DRM_MODE_CONNECTOR_VGA); - - drm_connector_helper_add(connector, &cirrus_vga_connector_helper_funcs); - - drm_connector_register(connector); - return connector; -} - - -int cirrus_modeset_init(struct cirrus_device *cdev) -{ - struct drm_encoder *encoder; - struct drm_connector *connector; - int ret; - - drm_mode_config_init(cdev->dev); - - cdev->dev->mode_config.max_width = CIRRUS_MAX_FB_WIDTH; - cdev->dev->mode_config.max_height = CIRRUS_MAX_FB_HEIGHT; - - cdev->dev->mode_config.fb_base = cdev->mc.vram_base; - cdev->dev->mode_config.preferred_depth = cirrus_bpp; - /* don't prefer a shadow on virt GPU */ - cdev->dev->mode_config.prefer_shadow = 0; - - cirrus_crtc_init(cdev->dev); - - encoder = cirrus_encoder_init(cdev->dev); - if (!encoder) { - DRM_ERROR("cirrus_encoder_init failed\n"); - return -1; - } - - connector = cirrus_vga_init(cdev->dev); - if (!connector) { - DRM_ERROR("cirrus_vga_init failed\n"); - return -1; - } - - drm_connector_attach_encoder(connector, encoder); - - ret = cirrus_fbdev_init(cdev); - if (ret) { - DRM_ERROR("cirrus_fbdev_init failed\n"); - return ret; - } - - return 0; -} - -void cirrus_modeset_fini(struct cirrus_device *cdev) -{ - cirrus_fbdev_fini(cdev); - drm_helper_force_disable_all(cdev->dev); - drm_mode_config_cleanup(cdev->dev); -} diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c deleted file mode 100644 index e075810b4bd4..000000000000 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ /dev/null @@ -1,343 +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 <drm/drmP.h> -#include <drm/ttm/ttm_page_alloc.h> - -#include "cirrus_drv.h" - -static inline struct cirrus_device * -cirrus_bdev(struct ttm_bo_device *bd) -{ - return container_of(bd, struct cirrus_device, ttm.bdev); -} - -static void cirrus_bo_ttm_destroy(struct ttm_buffer_object *tbo) -{ - struct cirrus_bo *bo; - - bo = container_of(tbo, struct cirrus_bo, bo); - - drm_gem_object_release(&bo->gem); - kfree(bo); -} - -static bool cirrus_ttm_bo_is_cirrus_bo(struct ttm_buffer_object *bo) -{ - if (bo->destroy == &cirrus_bo_ttm_destroy) - return true; - return false; -} - -static int -cirrus_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, - struct ttm_mem_type_manager *man) -{ - switch (type) { - case TTM_PL_SYSTEM: - man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; - man->available_caching = TTM_PL_MASK_CACHING; - man->default_caching = TTM_PL_FLAG_CACHED; - break; - case TTM_PL_VRAM: - man->func = &ttm_bo_manager_func; - man->flags = TTM_MEMTYPE_FLAG_FIXED | - TTM_MEMTYPE_FLAG_MAPPABLE; - man->available_caching = TTM_PL_FLAG_UNCACHED | - TTM_PL_FLAG_WC; - man->default_caching = TTM_PL_FLAG_WC; - break; - default: - DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); - return -EINVAL; - } - return 0; -} - -static void -cirrus_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) -{ - struct cirrus_bo *cirrusbo = cirrus_bo(bo); - - if (!cirrus_ttm_bo_is_cirrus_bo(bo)) - return; - - cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_SYSTEM); - *pl = cirrusbo->placement; -} - -static int cirrus_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) -{ - struct cirrus_bo *cirrusbo = cirrus_bo(bo); - - return drm_vma_node_verify_access(&cirrusbo->gem.vma_node, - filp->private_data); -} - -static int cirrus_ttm_io_mem_reserve(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem) -{ - struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; - struct cirrus_device *cirrus = cirrus_bdev(bdev); - - mem->bus.addr = NULL; - mem->bus.offset = 0; - mem->bus.size = mem->num_pages << PAGE_SHIFT; - mem->bus.base = 0; - mem->bus.is_iomem = false; - if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) - return -EINVAL; - switch (mem->mem_type) { - case TTM_PL_SYSTEM: - /* system memory */ - return 0; - case TTM_PL_VRAM: - mem->bus.offset = mem->start << PAGE_SHIFT; - mem->bus.base = pci_resource_start(cirrus->dev->pdev, 0); - mem->bus.is_iomem = true; - break; - default: - return -EINVAL; - break; - } - return 0; -} - -static void cirrus_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) -{ -} - -static void cirrus_ttm_backend_destroy(struct ttm_tt *tt) -{ - ttm_tt_fini(tt); - kfree(tt); -} - -static struct ttm_backend_func cirrus_tt_backend_func = { - .destroy = &cirrus_ttm_backend_destroy, -}; - - -static struct ttm_tt *cirrus_ttm_tt_create(struct ttm_buffer_object *bo, - uint32_t page_flags) -{ - struct ttm_tt *tt; - - tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL); - if (tt == NULL) - return NULL; - tt->func = &cirrus_tt_backend_func; - if (ttm_tt_init(tt, bo, page_flags)) { - kfree(tt); - return NULL; - } - return tt; -} - -struct ttm_bo_driver cirrus_bo_driver = { - .ttm_tt_create = cirrus_ttm_tt_create, - .init_mem_type = cirrus_bo_init_mem_type, - .eviction_valuable = ttm_bo_eviction_valuable, - .evict_flags = cirrus_bo_evict_flags, - .move = NULL, - .verify_access = cirrus_bo_verify_access, - .io_mem_reserve = &cirrus_ttm_io_mem_reserve, - .io_mem_free = &cirrus_ttm_io_mem_free, -}; - -int cirrus_mm_init(struct cirrus_device *cirrus) -{ - int ret; - struct drm_device *dev = cirrus->dev; - struct ttm_bo_device *bdev = &cirrus->ttm.bdev; - - ret = ttm_bo_device_init(&cirrus->ttm.bdev, - &cirrus_bo_driver, - dev->anon_inode->i_mapping, - DRM_FILE_PAGE_OFFSET, - true); - if (ret) { - DRM_ERROR("Error initialising bo driver; %d\n", ret); - return ret; - } - - ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, - cirrus->mc.vram_size >> PAGE_SHIFT); - if (ret) { - DRM_ERROR("Failed ttm VRAM init: %d\n", ret); - return ret; - } - - arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0), - pci_resource_len(dev->pdev, 0)); - - cirrus->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0), - pci_resource_len(dev->pdev, 0)); - - cirrus->mm_inited = true; - return 0; -} - -void cirrus_mm_fini(struct cirrus_device *cirrus) -{ - struct drm_device *dev = cirrus->dev; - - if (!cirrus->mm_inited) - return; - - ttm_bo_device_release(&cirrus->ttm.bdev); - - arch_phys_wc_del(cirrus->fb_mtrr); - cirrus->fb_mtrr = 0; - arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0), - pci_resource_len(dev->pdev, 0)); -} - -void cirrus_ttm_placement(struct cirrus_bo *bo, int domain) -{ - u32 c = 0; - unsigned i; - bo->placement.placement = bo->placements; - bo->placement.busy_placement = bo->placements; - if (domain & TTM_PL_FLAG_VRAM) - bo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; - if (domain & TTM_PL_FLAG_SYSTEM) - bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; - if (!c) - bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; - bo->placement.num_placement = c; - bo->placement.num_busy_placement = c; - for (i = 0; i < c; ++i) { - bo->placements[i].fpfn = 0; - bo->placements[i].lpfn = 0; - } -} - -int cirrus_bo_create(struct drm_device *dev, int size, int align, - uint32_t flags, struct cirrus_bo **pcirrusbo) -{ - struct cirrus_device *cirrus = dev->dev_private; - struct cirrus_bo *cirrusbo; - size_t acc_size; - int ret; - - cirrusbo = kzalloc(sizeof(struct cirrus_bo), GFP_KERNEL); - if (!cirrusbo) - return -ENOMEM; - - ret = drm_gem_object_init(dev, &cirrusbo->gem, size); - if (ret) { - kfree(cirrusbo); - return ret; - } - - cirrusbo->bo.bdev = &cirrus->ttm.bdev; - - cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); - - acc_size = ttm_bo_dma_acc_size(&cirrus->ttm.bdev, size, - sizeof(struct cirrus_bo)); - - ret = ttm_bo_init(&cirrus->ttm.bdev, &cirrusbo->bo, size, - ttm_bo_type_device, &cirrusbo->placement, - align >> PAGE_SHIFT, false, acc_size, - NULL, NULL, cirrus_bo_ttm_destroy); - if (ret) - return ret; - - *pcirrusbo = cirrusbo; - return 0; -} - -static inline u64 cirrus_bo_gpu_offset(struct cirrus_bo *bo) -{ - return bo->bo.offset; -} - -int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr) -{ - struct ttm_operation_ctx ctx = { false, false }; - int i, ret; - - if (bo->pin_count) { - bo->pin_count++; - if (gpu_addr) - *gpu_addr = cirrus_bo_gpu_offset(bo); - } - - cirrus_ttm_placement(bo, pl_flag); - for (i = 0; i < bo->placement.num_placement; i++) - bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; - ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); - if (ret) - return ret; - - bo->pin_count = 1; - if (gpu_addr) - *gpu_addr = cirrus_bo_gpu_offset(bo); - return 0; -} - -int cirrus_bo_push_sysram(struct cirrus_bo *bo) -{ - struct ttm_operation_ctx ctx = { false, false }; - int i, ret; - if (!bo->pin_count) { - DRM_ERROR("unpin bad %p\n", bo); - return 0; - } - bo->pin_count--; - if (bo->pin_count) - return 0; - - if (bo->kmap.virtual) - ttm_bo_kunmap(&bo->kmap); - - cirrus_ttm_placement(bo, TTM_PL_FLAG_SYSTEM); - for (i = 0; i < bo->placement.num_placement ; i++) - bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; - - ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); - if (ret) { - DRM_ERROR("pushing to VRAM failed\n"); - return ret; - } - return 0; -} - -int cirrus_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct drm_file *file_priv; - struct cirrus_device *cirrus; - - if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) - return -EINVAL; - - file_priv = filp->private_data; - cirrus = file_priv->minor->dev->dev_private; - return ttm_bo_mmap(filp, vma, &cirrus->ttm.bdev); -} |