^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /**************************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2007-2011, Intel Corporation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * All Rights Reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) **************************************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/pfn_t.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/tty.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <drm/drm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <drm/drm_crtc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <drm/drm_fb_helper.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <drm/drm_fourcc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <drm/drm_gem_framebuffer_helper.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include "framebuffer.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include "gtt.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include "psb_drv.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include "psb_intel_drv.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include "psb_intel_reg.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static const struct drm_framebuffer_funcs psb_fb_funcs = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) .destroy = drm_gem_fb_destroy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) .create_handle = drm_gem_fb_create_handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define CMAP_TOHW(_val, _width) ((((_val) << (_width)) + 0x7FFF - (_val)) >> 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static int psbfb_setcolreg(unsigned regno, unsigned red, unsigned green,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) unsigned blue, unsigned transp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct drm_fb_helper *fb_helper = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct drm_framebuffer *fb = fb_helper->fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) uint32_t v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (!fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (regno > 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) red = CMAP_TOHW(red, info->var.red.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) blue = CMAP_TOHW(blue, info->var.blue.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) green = CMAP_TOHW(green, info->var.green.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) transp = CMAP_TOHW(transp, info->var.transp.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) v = (red << info->var.red.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) (green << info->var.green.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) (blue << info->var.blue.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) (transp << info->var.transp.offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (regno < 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) switch (fb->format->cpp[0] * 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) ((uint32_t *) info->pseudo_palette)[regno] = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) ((uint32_t *) info->pseudo_palette)[regno] = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static int psbfb_pan(struct fb_var_screeninfo *var, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct drm_fb_helper *fb_helper = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct drm_framebuffer *fb = fb_helper->fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct drm_device *dev = fb->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct gtt_range *gtt = to_gtt_range(fb->obj[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * We have to poke our nose in here. The core fb code assumes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * panning is part of the hardware that can be invoked before
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * the actual fb is mapped. In our case that isn't quite true.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (gtt->npage) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /* GTT roll shifts in 4K pages, we need to shift the right
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) number of pages */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) int pages = info->fix.line_length >> 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) psb_gtt_roll(dev, gtt, var->yoffset * pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static vm_fault_t psbfb_vm_fault(struct vm_fault *vmf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) struct vm_area_struct *vma = vmf->vma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct drm_framebuffer *fb = vma->vm_private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct drm_device *dev = fb->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) struct drm_psb_private *dev_priv = dev->dev_private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) struct gtt_range *gtt = to_gtt_range(fb->obj[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) int page_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) unsigned long address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) vm_fault_t ret = VM_FAULT_SIGBUS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) unsigned long pfn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) unsigned long phys_addr = (unsigned long)dev_priv->stolen_base +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) gtt->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) page_num = vma_pages(vma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) address = vmf->address - (vmf->pgoff << PAGE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) for (i = 0; i < page_num; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) pfn = (phys_addr >> PAGE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) ret = vmf_insert_mixed(vma, address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) __pfn_to_pfn_t(pfn, PFN_DEV));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (unlikely(ret & VM_FAULT_ERROR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) address += PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) phys_addr += PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static void psbfb_vm_open(struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) static void psbfb_vm_close(struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static const struct vm_operations_struct psbfb_vm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) .fault = psbfb_vm_fault,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) .open = psbfb_vm_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) .close = psbfb_vm_close
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static int psbfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) struct drm_fb_helper *fb_helper = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) struct drm_framebuffer *fb = fb_helper->fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (vma->vm_pgoff != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * If this is a GEM object then info->screen_base is the virtual
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * kernel remapping of the object. FIXME: Review if this is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * suitable for our mmap work
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) vma->vm_ops = &psbfb_vm_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) vma->vm_private_data = (void *)fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static const struct fb_ops psbfb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) DRM_FB_HELPER_DEFAULT_OPS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) .fb_setcolreg = psbfb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) .fb_fillrect = drm_fb_helper_cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) .fb_copyarea = psbfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) .fb_imageblit = drm_fb_helper_cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) .fb_mmap = psbfb_mmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .fb_sync = psbfb_sync,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static const struct fb_ops psbfb_roll_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) DRM_FB_HELPER_DEFAULT_OPS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) .fb_setcolreg = psbfb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) .fb_fillrect = drm_fb_helper_cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) .fb_copyarea = drm_fb_helper_cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) .fb_imageblit = drm_fb_helper_cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) .fb_pan_display = psbfb_pan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) .fb_mmap = psbfb_mmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) static const struct fb_ops psbfb_unaccel_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) DRM_FB_HELPER_DEFAULT_OPS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) .fb_setcolreg = psbfb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) .fb_fillrect = drm_fb_helper_cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) .fb_copyarea = drm_fb_helper_cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) .fb_imageblit = drm_fb_helper_cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) .fb_mmap = psbfb_mmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * psb_framebuffer_init - initialize a framebuffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) * @dev: our DRM device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * @fb: framebuffer to set up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) * @mode_cmd: mode description
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * @gt: backing object
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * Configure and fill in the boilerplate for our frame buffer. Return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * 0 on success or an error code if we fail.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static int psb_framebuffer_init(struct drm_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) struct drm_framebuffer *fb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) const struct drm_mode_fb_cmd2 *mode_cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) struct drm_gem_object *obj)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) const struct drm_format_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * Reject unknown formats, YUV formats, and formats with more than
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * 4 bytes per pixel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) info = drm_get_format_info(dev, mode_cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) if (!info || !info->depth || info->cpp[0] > 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (mode_cmd->pitches[0] & 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) fb->obj[0] = obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) ret = drm_framebuffer_init(dev, fb, &psb_fb_funcs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) dev_err(dev->dev, "framebuffer init failed: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * psb_framebuffer_create - create a framebuffer backed by gt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * @dev: our DRM device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) * @mode_cmd: the description of the requested mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * @gt: the backing object
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * Create a framebuffer object backed by the gt, and fill in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * boilerplate required
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) * TODO: review object references
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static struct drm_framebuffer *psb_framebuffer_create
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) (struct drm_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) const struct drm_mode_fb_cmd2 *mode_cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) struct drm_gem_object *obj)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) struct drm_framebuffer *fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) fb = kzalloc(sizeof(*fb), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) if (!fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) ret = psb_framebuffer_init(dev, fb, mode_cmd, obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) kfree(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) * psbfb_alloc - allocate frame buffer memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * @dev: the DRM device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) * @aligned_size: space needed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) * Allocate the frame buffer. In the usual case we get a GTT range that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) * is stolen memory backed and life is simple. If there isn't sufficient
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) * we fail as we don't have the virtual mapping space to really vmap it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) * and the kernel console code can't handle non linear framebuffers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) * Re-address this as and if the framebuffer layer grows this ability.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) static struct gtt_range *psbfb_alloc(struct drm_device *dev, int aligned_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) struct gtt_range *backing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) /* Begin by trying to use stolen memory backing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) backing = psb_gtt_alloc_range(dev, aligned_size, "fb", 1, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (backing) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) drm_gem_private_object_init(dev, &backing->gem, aligned_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return backing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) * psbfb_create - create a framebuffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) * @fbdev: the framebuffer device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) * @sizes: specification of the layout
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) * Create a framebuffer to the specifications provided
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) static int psbfb_create(struct drm_fb_helper *fb_helper,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) struct drm_fb_helper_surface_size *sizes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) struct drm_device *dev = fb_helper->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) struct drm_psb_private *dev_priv = dev->dev_private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) struct drm_framebuffer *fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) struct drm_mode_fb_cmd2 mode_cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) int size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) struct gtt_range *backing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) u32 bpp, depth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) int gtt_roll = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) int pitch_lines = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) mode_cmd.width = sizes->surface_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) mode_cmd.height = sizes->surface_height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) bpp = sizes->surface_bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) depth = sizes->surface_depth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) /* No 24bit packed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) if (bpp == 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) bpp = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) * Acceleration via the GTT requires pitch to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) * power of two aligned. Preferably page but less
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) * is ok with some fonts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 7) / 8), 4096 >> pitch_lines);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) size = mode_cmd.pitches[0] * mode_cmd.height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) size = ALIGN(size, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) /* Allocate the fb in the GTT with stolen page backing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) backing = psbfb_alloc(dev, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) if (pitch_lines)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) pitch_lines *= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) pitch_lines = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) gtt_roll++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) } while (backing == NULL && pitch_lines <= 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) /* The final pitch we accepted if we succeeded */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) pitch_lines /= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (backing == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) * We couldn't get the space we wanted, fall back to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) * display engine requirement instead. The HW requires
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) * the pitch to be 64 byte aligned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) gtt_roll = 0; /* Don't use GTT accelerated scrolling */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) pitch_lines = 64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 7) / 8), 64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) size = mode_cmd.pitches[0] * mode_cmd.height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) size = ALIGN(size, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) /* Allocate the framebuffer in the GTT with stolen page backing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) backing = psbfb_alloc(dev, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) if (backing == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) memset(dev_priv->vram_addr + backing->offset, 0, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) info = drm_fb_helper_alloc_fbi(fb_helper);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (IS_ERR(info)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) ret = PTR_ERR(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) fb = psb_framebuffer_create(dev, &mode_cmd, &backing->gem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) if (IS_ERR(fb)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) ret = PTR_ERR(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) fb_helper->fb = fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) if (dev_priv->ops->accel_2d && pitch_lines > 8) /* 2D engine */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) info->fbops = &psbfb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) else if (gtt_roll) { /* GTT rolling seems best */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) info->fbops = &psbfb_roll_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) info->flags |= FBINFO_HWACCEL_YPAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) } else /* Software */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) info->fbops = &psbfb_unaccel_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) info->fix.smem_start = dev->mode_config.fb_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) info->fix.smem_len = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) info->fix.ywrapstep = gtt_roll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) info->fix.ypanstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) /* Accessed stolen memory directly */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) info->screen_base = dev_priv->vram_addr + backing->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) info->screen_size = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (dev_priv->gtt.stolen_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) info->apertures->ranges[0].base = dev->mode_config.fb_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) info->apertures->ranges[0].size = dev_priv->gtt.stolen_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) drm_fb_helper_fill_info(info, fb_helper, sizes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) info->fix.mmio_start = pci_resource_start(dev->pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) info->fix.mmio_len = pci_resource_len(dev->pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) dev_dbg(dev->dev, "allocated %dx%d fb\n", fb->width, fb->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) psb_gtt_free_range(dev, backing);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) * psb_user_framebuffer_create - create framebuffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * @dev: our DRM device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * @filp: client file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * @cmd: mode request
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) * Create a new framebuffer backed by a userspace GEM object
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) static struct drm_framebuffer *psb_user_framebuffer_create
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) (struct drm_device *dev, struct drm_file *filp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) const struct drm_mode_fb_cmd2 *cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) struct drm_gem_object *obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) struct drm_framebuffer *fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) * Find the GEM object and thus the gtt range object that is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) * to back this space
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) obj = drm_gem_object_lookup(filp, cmd->handles[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) if (obj == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) return ERR_PTR(-ENOENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) /* Let the core code do all the work */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) fb = psb_framebuffer_create(dev, cmd, obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (IS_ERR(fb))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) drm_gem_object_put(obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) return fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) static int psbfb_probe(struct drm_fb_helper *fb_helper,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) struct drm_fb_helper_surface_size *sizes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) struct drm_device *dev = fb_helper->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) struct drm_psb_private *dev_priv = dev->dev_private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) unsigned int fb_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) int bytespp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) bytespp = sizes->surface_bpp / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) if (bytespp == 3) /* no 24bit packed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) bytespp = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) /* If the mode will not fit in 32bit then switch to 16bit to get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) a console on full resolution. The X mode setting server will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) allocate its own 32bit GEM framebuffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) fb_size = ALIGN(sizes->surface_width * bytespp, 64) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) sizes->surface_height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) fb_size = ALIGN(fb_size, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) if (fb_size > dev_priv->vram_stolen_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) sizes->surface_bpp = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) sizes->surface_depth = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) return psbfb_create(fb_helper, sizes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) static const struct drm_fb_helper_funcs psb_fb_helper_funcs = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) .fb_probe = psbfb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) static int psb_fbdev_destroy(struct drm_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) struct drm_fb_helper *fb_helper)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) struct drm_framebuffer *fb = fb_helper->fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) drm_fb_helper_unregister_fbi(fb_helper);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) drm_fb_helper_fini(fb_helper);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) drm_framebuffer_unregister_private(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) drm_framebuffer_cleanup(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) if (fb->obj[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) drm_gem_object_put(fb->obj[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) kfree(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) int psb_fbdev_init(struct drm_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) struct drm_fb_helper *fb_helper;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) struct drm_psb_private *dev_priv = dev->dev_private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) if (!fb_helper) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) dev_err(dev->dev, "no memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) dev_priv->fb_helper = fb_helper;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) drm_fb_helper_prepare(dev, fb_helper, &psb_fb_helper_funcs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) ret = drm_fb_helper_init(dev, fb_helper);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) goto free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) /* disable all the possible outputs/crtcs before entering KMS mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) drm_helper_disable_unused_functions(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) ret = drm_fb_helper_initial_config(fb_helper, 32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) goto fini;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) fini:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) drm_fb_helper_fini(fb_helper);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) kfree(fb_helper);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) static void psb_fbdev_fini(struct drm_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) struct drm_psb_private *dev_priv = dev->dev_private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) if (!dev_priv->fb_helper)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) psb_fbdev_destroy(dev, dev_priv->fb_helper);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) kfree(dev_priv->fb_helper);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) dev_priv->fb_helper = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) static const struct drm_mode_config_funcs psb_mode_funcs = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) .fb_create = psb_user_framebuffer_create,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) .output_poll_changed = drm_fb_helper_output_poll_changed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) static void psb_setup_outputs(struct drm_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) struct drm_psb_private *dev_priv = dev->dev_private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) struct drm_connector *connector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) drm_mode_create_scaling_mode_property(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) /* It is ok for this to fail - we just don't get backlight control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) if (!dev_priv->backlight_property)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) dev_priv->backlight_property = drm_property_create_range(dev, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) "backlight", 0, 100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) dev_priv->ops->output_init(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) list_for_each_entry(connector, &dev->mode_config.connector_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) head) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) struct drm_encoder *encoder = &gma_encoder->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) int crtc_mask = 0, clone_mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) /* valid crtcs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) switch (gma_encoder->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) case INTEL_OUTPUT_ANALOG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) crtc_mask = (1 << 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) clone_mask = (1 << INTEL_OUTPUT_ANALOG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) case INTEL_OUTPUT_SDVO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) crtc_mask = dev_priv->ops->sdvo_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) clone_mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) case INTEL_OUTPUT_LVDS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) crtc_mask = dev_priv->ops->lvds_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) clone_mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) case INTEL_OUTPUT_MIPI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) crtc_mask = (1 << 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) clone_mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) case INTEL_OUTPUT_MIPI2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) crtc_mask = (1 << 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) clone_mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) case INTEL_OUTPUT_HDMI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) crtc_mask = dev_priv->ops->hdmi_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) clone_mask = (1 << INTEL_OUTPUT_HDMI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) case INTEL_OUTPUT_DISPLAYPORT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) crtc_mask = (1 << 0) | (1 << 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) clone_mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) case INTEL_OUTPUT_EDP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) crtc_mask = (1 << 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) clone_mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) encoder->possible_crtcs = crtc_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) encoder->possible_clones =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) gma_connector_clones(dev, clone_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) void psb_modeset_init(struct drm_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) struct drm_psb_private *dev_priv = dev->dev_private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) drm_mode_config_init(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) dev->mode_config.min_width = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) dev->mode_config.min_height = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) dev->mode_config.funcs = &psb_mode_funcs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) /* set memory base */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) /* Oaktrail and Poulsbo should use BAR 2*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) pci_read_config_dword(dev->pdev, PSB_BSM, (u32 *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) &(dev->mode_config.fb_base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) /* num pipes is 2 for PSB but 1 for Mrst */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) for (i = 0; i < dev_priv->num_pipe; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) psb_intel_crtc_init(dev, i, mode_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) dev->mode_config.max_width = 4096;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) dev->mode_config.max_height = 4096;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) psb_setup_outputs(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) if (dev_priv->ops->errata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) dev_priv->ops->errata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) dev_priv->modeset = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) void psb_modeset_cleanup(struct drm_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) struct drm_psb_private *dev_priv = dev->dev_private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) if (dev_priv->modeset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) drm_kms_helper_poll_fini(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) psb_fbdev_fini(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) drm_mode_config_cleanup(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) }