Path: blob/master/drivers/firmware/google/framebuffer-coreboot.c
26428 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* framebuffer-coreboot.c3*4* Memory based framebuffer accessed through coreboot table.5*6* Copyright 2012-2013 David Herrmann <[email protected]>7* Copyright 2017 Google Inc.8* Copyright 2017 Samuel Holland <[email protected]>9*/1011#include <linux/device.h>12#include <linux/kernel.h>13#include <linux/mm.h>14#include <linux/module.h>15#include <linux/platform_data/simplefb.h>16#include <linux/platform_device.h>17#include <linux/sysfb.h>1819#include "coreboot_table.h"2021#define CB_TAG_FRAMEBUFFER 0x122223static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;2425static int framebuffer_probe(struct coreboot_device *dev)26{27int i;28u32 length;29struct lb_framebuffer *fb = &dev->framebuffer;30struct platform_device *pdev;31struct resource res;32struct simplefb_platform_data pdata = {33.width = fb->x_resolution,34.height = fb->y_resolution,35.stride = fb->bytes_per_line,36.format = NULL,37};3839/*40* On coreboot systems, the advertised LB_TAG_FRAMEBUFFER entry41* in the coreboot table should only be used if the payload did42* not pass a framebuffer information to the Linux kernel.43*44* If the global screen_info data has been filled, the Generic45* System Framebuffers (sysfb) will already register a platform46* device and pass that screen_info as platform_data to a driver47* that can scan-out using the system provided framebuffer.48*/49if (sysfb_handles_screen_info())50return -ENODEV;5152if (!fb->physical_address)53return -ENODEV;5455for (i = 0; i < ARRAY_SIZE(formats); ++i) {56if (fb->bits_per_pixel == formats[i].bits_per_pixel &&57fb->red_mask_pos == formats[i].red.offset &&58fb->red_mask_size == formats[i].red.length &&59fb->green_mask_pos == formats[i].green.offset &&60fb->green_mask_size == formats[i].green.length &&61fb->blue_mask_pos == formats[i].blue.offset &&62fb->blue_mask_size == formats[i].blue.length)63pdata.format = formats[i].name;64}65if (!pdata.format)66return -ENODEV;6768memset(&res, 0, sizeof(res));69res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;70res.name = "Coreboot Framebuffer";71res.start = fb->physical_address;72length = PAGE_ALIGN(fb->y_resolution * fb->bytes_per_line);73res.end = res.start + length - 1;74if (res.end <= res.start)75return -EINVAL;7677pdev = platform_device_register_resndata(&dev->dev,78"simple-framebuffer", 0,79&res, 1, &pdata,80sizeof(pdata));81if (IS_ERR(pdev))82pr_warn("coreboot: could not register framebuffer\n");83else84dev_set_drvdata(&dev->dev, pdev);8586return PTR_ERR_OR_ZERO(pdev);87}8889static void framebuffer_remove(struct coreboot_device *dev)90{91struct platform_device *pdev = dev_get_drvdata(&dev->dev);9293platform_device_unregister(pdev);94}9596static const struct coreboot_device_id framebuffer_ids[] = {97{ .tag = CB_TAG_FRAMEBUFFER },98{ /* sentinel */ }99};100MODULE_DEVICE_TABLE(coreboot, framebuffer_ids);101102static struct coreboot_driver framebuffer_driver = {103.probe = framebuffer_probe,104.remove = framebuffer_remove,105.drv = {106.name = "framebuffer",107},108.id_table = framebuffer_ids,109};110module_coreboot_driver(framebuffer_driver);111112MODULE_AUTHOR("Samuel Holland <[email protected]>");113MODULE_DESCRIPTION("Memory based framebuffer accessed through coreboot table");114MODULE_LICENSE("GPL");115116117