On Wed, Apr 3, 2019 at 9:23 AM Gerd Hoffmann <kraxel@xxxxxxxxxx> wrote: > > Time to kill some bad sample code people are copying from ;) > > This is a complete rewrite of the cirrus driver. The cirrus_mode_set() > function is pretty much the only function which is carried over largely > unmodified. Everything else is upside down. > > It is a single monster patch. But given that it does some pretty > fundamental changes to the drivers workflow and also reduces the code > size by roughly 70% I think it'll still be alot easier to review than a > longish baby-step patch series. > > Changes summary: > - Given the small amout of video memory (4 MB) the cirrus device has > the rewritten driver doesn't try to manage buffers there. Instead > it will blit (memcpy) the active framebuffer to video memory. > - All gem objects are stored in main memory and are manged using the > new shmem helpers. ttm is out. > - Only DRM_FORMAT_RGB565 (depth 16) is supported. The old driver does > that too by default. There was a module parameter which enables 24/32 > bpp support and disables higher resolutions (due to cirrus hardware > constrains). That parameter wasn't reimplemented. > - The simple display pipeline is used. > - The generic fbdev emulation is used. > - It's a atomic driver now. Sounds all awesome. Some tiny comments below, with those addressed looks all good and gets my Acked-by: Daniel Vetter <daniel.vetter@xxxxxxxx> -Daniel > Signed-off-by: Gerd Hoffmann <kraxel@xxxxxxxxxx> > --- > drivers/gpu/drm/cirrus/cirrus_drv.h | 251 ----------- > drivers/gpu/drm/cirrus/cirrus.c | 602 +++++++++++++++++++++++++ > drivers/gpu/drm/cirrus/cirrus_drv.c | 161 ------- > drivers/gpu/drm/cirrus/cirrus_fbdev.c | 309 ------------- > drivers/gpu/drm/cirrus/cirrus_main.c | 328 -------------- > drivers/gpu/drm/cirrus/cirrus_mode.c | 617 -------------------------- > drivers/gpu/drm/cirrus/cirrus_ttm.c | 343 -------------- > drivers/gpu/drm/cirrus/Kconfig | 2 +- > drivers/gpu/drm/cirrus/Makefile | 3 - > 9 files changed, 603 insertions(+), 2013 deletions(-) > delete mode 100644 drivers/gpu/drm/cirrus/cirrus_drv.h > create mode 100644 drivers/gpu/drm/cirrus/cirrus.c > delete mode 100644 drivers/gpu/drm/cirrus/cirrus_drv.c > delete mode 100644 drivers/gpu/drm/cirrus/cirrus_fbdev.c > delete mode 100644 drivers/gpu/drm/cirrus/cirrus_main.c > delete mode 100644 drivers/gpu/drm/cirrus/cirrus_mode.c > delete mode 100644 drivers/gpu/drm/cirrus/cirrus_ttm.c > > 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.c b/drivers/gpu/drm/cirrus/cirrus.c > new file mode 100644 > index 000000000000..e27bb13fc777 > --- /dev/null > +++ b/drivers/gpu/drm/cirrus/cirrus.c > @@ -0,0 +1,602 @@ > +/* > + * 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@xxxxxxxxx> > + */ > + > +#include <linux/module.h> > +#include <linux/pci.h> > +#include <linux/console.h> > + > +#include <video/vga.h> > +#include <video/cirrus.h> > + > +#include <drm/drm_drv.h> > +#include <drm/drm_file.h> > +#include <drm/drm_ioctl.h> > +#include <drm/drm_vblank.h> > +#include <drm/drm_connector.h> > + > +#include <drm/drm_fb_helper.h> > +#include <drm/drm_probe_helper.h> > +#include <drm/drm_simple_kms_helper.h> > +#include <drm/drm_gem_shmem_helper.h> > +#include <drm/drm_gem_framebuffer_helper.h> > +#include <drm/drm_modeset_helper_vtables.h> > +#include <drm/drm_damage_helper.h> > +#include <drm/drm_atomic_helper.h> > +#include <drm/drm_atomic_state_helper.h> > + > +#define DRIVER_NAME "cirrus" > +#define DRIVER_DESC "qemu cirrus vga" > +#define DRIVER_DATE "2019" > +#define DRIVER_MAJOR 2 > +#define DRIVER_MINOR 0 > + > +struct cirrus_device { > + struct drm_device *dev; Why not embed drm_device? It's the latest rage :-) > + struct drm_simple_display_pipe pipe; > + struct drm_connector conn; > + unsigned int bpp; > + 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 RREG8(reg) ioread8(((void __iomem *)cirrus->mmio) + (reg)) > +#define WREG8(reg, v) iowrite8(v, ((void __iomem *)cirrus->mmio) + (reg)) > +#define RREG32(reg) ioread32(((void __iomem *)cirrus->mmio) + (reg)) > +#define WREG32(reg, v) iowrite32(v, ((void __iomem *)cirrus->mmio) + (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) \ > + > +#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) \ > + > + > +static int cirrus_mode_set(struct cirrus_device *cirrus, > + struct drm_crtc_state *crtc_state) > +{ > + struct drm_display_mode *mode = &crtc_state->mode; > + 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; > + > + cirrus->bpp = cirrus->dev->mode_config.preferred_depth; > + switch (cirrus->bpp) { > + 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 */ > + cirrus->pitch = mode->hdisplay * cirrus->bpp / 8; > + tmp = cirrus->pitch / 8; > + WREG_CRT(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(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; > +} > + > +static int cirrus_fb_blit_clips(struct drm_framebuffer *fb, > + struct drm_clip_rect *clips, > + unsigned int num_clips) > +{ > + struct cirrus_device *cirrus = fb->dev->dev_private; > + unsigned i, y, xoff, xlen, src, dst; > + void *vmap; > + > + vmap = drm_gem_shmem_vmap(fb->obj[0]); > + if (!vmap) > + return -ENOMEM; > + > + for (i = 0; i < num_clips; i++) { > + xoff = clips[i].x1 * cirrus->bpp / 8; > + xlen = (clips[i].x2 - clips[i].x1) * cirrus->bpp / 8; > + for (y = clips[i].y1; y < clips[i].y2; y++) { > + src = xoff + y * fb->pitches[0]; > + dst = xoff + y * cirrus->pitch; > + memcpy_toio(cirrus->vram + dst, vmap + src, xlen); > + } > + } > + > + drm_gem_shmem_vunmap(fb->obj[0], vmap); > + return 0; > +} > + > +static int cirrus_fb_blit_rect(struct drm_framebuffer *fb, > + struct drm_rect *rect) > +{ > + struct drm_clip_rect clip_rect = { > + .x1 = rect->x1, > + .x2 = rect->x2, > + .y1 = rect->y1, > + .y2 = rect->y2, > + }; > + return cirrus_fb_blit_clips(fb, &clip_rect, 1); > +} > + > +static int cirrus_fb_blit_fullscreen(struct drm_framebuffer *fb) > +{ > + struct drm_clip_rect fullscreen = { > + .x1 = 0, > + .x2 = fb->width, > + .y1 = 0, > + .y2 = fb->height, > + }; > + return cirrus_fb_blit_clips(fb, &fullscreen, 1); > +} > + > +static int cirrus_check_size(int width, int height) > +{ > + static const int max_pitch = 0x1FF << 3; /* (4096 - 1) & ~111b bytes */ > + static const int max_size = 4 * 1024 * 1024; /* 4 MB */ > + int bytes_pp = 2; /* depth 16 */ > + > + if (width * bytes_pp > max_pitch) > + return -EINVAL; > + if (width * height * bytes_pp > max_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 */ > + > +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) < 0) > + return MODE_BAD; > + return MODE_OK; > +} > + > +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); > +} > + > +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); > + cirrus_fb_blit_fullscreen(plane_state->fb); > +} > + > +void cirrus_pipe_update(struct drm_simple_display_pipe *pipe, > + struct drm_plane_state *old_state) > +{ > + struct drm_plane_state *state = pipe->plane.state; > + struct drm_crtc *crtc = &pipe->crtc; > + struct drm_rect rect; > + > + 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); > + spin_unlock_irq(&crtc->dev->event_lock); > + crtc->state->event = NULL; > + } > +} > + > +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, > +}; > + > +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), > + NULL, > + &cirrus->conn); > +} > + > +/* ------------------------------------------------------------------ */ > +/* cirrus framebuffers & mode config */ > + > +static int cirrus_fb_dirty(struct drm_framebuffer *fb, > + struct drm_file *file_priv, > + unsigned int flags, unsigned int color, > + struct drm_clip_rect *clips, > + unsigned int num_clips) > +{ > + struct cirrus_device *cirrus = fb->dev->dev_private; > + > + if (cirrus->pipe.plane.state->fb != fb) > + return 0; > + > + if (num_clips) > + cirrus_fb_blit_clips(fb, clips, num_clips); > + else > + cirrus_fb_blit_fullscreen(fb); > + return 0; > +} Why not use the dirty helpers and implement dirty rect support in your main plane update function? Would be nice since then cirrus would be a really nice template for old fbdev drivers. And you already have all the dirty rect upload code anyway. > +static const struct drm_framebuffer_funcs cirrus_fb_funcs = { > + .destroy = drm_gem_fb_destroy, > + .create_handle = drm_gem_fb_create_handle, > + .dirty = cirrus_fb_dirty, > +}; > + > +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) > + return ERR_PTR(-EINVAL); > + if (cirrus_check_size(mode_cmd->width, mode_cmd->height) < 0) > + return ERR_PTR(-EINVAL); > + return drm_gem_fb_create_with_funcs(dev, file_priv, mode_cmd, > + &cirrus_fb_funcs); > +} > + > +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 = 1600; > + 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; > + > + dev = drm_dev_alloc(&cirrus_driver, &pdev->dev); > + if (IS_ERR(dev)) > + return PTR_ERR(dev); > + > + ret = pci_enable_device(pdev); > + if (ret) > + goto err_free_dev; > + > + ret = pci_request_regions(pdev, DRIVER_NAME); > + if (ret) > + goto err_free_dev; > + > + ret = -ENOMEM; > + cirrus = kzalloc(sizeof(*cirrus), GFP_KERNEL); > + if (cirrus == NULL) > + goto err_pci_release; > + dev->dev_private = cirrus; > + cirrus->dev = dev; > + > + cirrus->vram = ioremap(pci_resource_start(pdev, 0), > + pci_resource_len(pdev, 0)); > + if (cirrus->vram == NULL) > + goto err_free_cirrus; > + > + 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_free_cirrus: > + kfree(cirrus); > +err_pci_release: > + pci_release_regions(pdev); > +err_free_dev: > + drm_dev_put(dev); > + 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); > + kfree(cirrus); > + pci_release_regions(pdev); > + drm_dev_put(dev); > +} > + > +/* 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 }, > + { /* 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@xxxxxxxxxx> > - * > - * 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_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@xxxxxxxxx> > - */ > -#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@xxxxxxxxxx> > - */ > -#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); > -} > 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 > -- > 2.18.1 > -- Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch _______________________________________________ Virtualization mailing list Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linuxfoundation.org/mailman/listinfo/virtualization