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