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