linux/drivers/firmware/google/framebuffer-coreboot.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * framebuffer-coreboot.c
   4 *
   5 * Memory based framebuffer accessed through coreboot table.
   6 *
   7 * Copyright 2012-2013 David Herrmann <dh.herrmann@gmail.com>
   8 * Copyright 2017 Google Inc.
   9 * Copyright 2017 Samuel Holland <samuel@sholland.org>
  10 */
  11
  12#include <linux/device.h>
  13#include <linux/kernel.h>
  14#include <linux/mm.h>
  15#include <linux/module.h>
  16#include <linux/platform_data/simplefb.h>
  17#include <linux/platform_device.h>
  18
  19#include "coreboot_table.h"
  20
  21#define CB_TAG_FRAMEBUFFER 0x12
  22
  23static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
  24
  25static int framebuffer_probe(struct coreboot_device *dev)
  26{
  27        int i;
  28        u32 length;
  29        struct lb_framebuffer *fb = &dev->framebuffer;
  30        struct platform_device *pdev;
  31        struct resource res;
  32        struct simplefb_platform_data pdata = {
  33                .width = fb->x_resolution,
  34                .height = fb->y_resolution,
  35                .stride = fb->bytes_per_line,
  36                .format = NULL,
  37        };
  38
  39        for (i = 0; i < ARRAY_SIZE(formats); ++i) {
  40                if (fb->bits_per_pixel     == formats[i].bits_per_pixel &&
  41                    fb->red_mask_pos       == formats[i].red.offset &&
  42                    fb->red_mask_size      == formats[i].red.length &&
  43                    fb->green_mask_pos     == formats[i].green.offset &&
  44                    fb->green_mask_size    == formats[i].green.length &&
  45                    fb->blue_mask_pos      == formats[i].blue.offset &&
  46                    fb->blue_mask_size     == formats[i].blue.length &&
  47                    fb->reserved_mask_pos  == formats[i].transp.offset &&
  48                    fb->reserved_mask_size == formats[i].transp.length)
  49                        pdata.format = formats[i].name;
  50        }
  51        if (!pdata.format)
  52                return -ENODEV;
  53
  54        memset(&res, 0, sizeof(res));
  55        res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
  56        res.name = "Coreboot Framebuffer";
  57        res.start = fb->physical_address;
  58        length = PAGE_ALIGN(fb->y_resolution * fb->bytes_per_line);
  59        res.end = res.start + length - 1;
  60        if (res.end <= res.start)
  61                return -EINVAL;
  62
  63        pdev = platform_device_register_resndata(&dev->dev,
  64                                                 "simple-framebuffer", 0,
  65                                                 &res, 1, &pdata,
  66                                                 sizeof(pdata));
  67        if (IS_ERR(pdev))
  68                pr_warn("coreboot: could not register framebuffer\n");
  69        else
  70                dev_set_drvdata(&dev->dev, pdev);
  71
  72        return PTR_ERR_OR_ZERO(pdev);
  73}
  74
  75static void framebuffer_remove(struct coreboot_device *dev)
  76{
  77        struct platform_device *pdev = dev_get_drvdata(&dev->dev);
  78
  79        platform_device_unregister(pdev);
  80}
  81
  82static struct coreboot_driver framebuffer_driver = {
  83        .probe = framebuffer_probe,
  84        .remove = framebuffer_remove,
  85        .drv = {
  86                .name = "framebuffer",
  87        },
  88        .tag = CB_TAG_FRAMEBUFFER,
  89};
  90module_coreboot_driver(framebuffer_driver);
  91
  92MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
  93MODULE_LICENSE("GPL");
  94