Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  1/*
  2 * Generic System Framebuffers on x86
  3 * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
  4 *
  5 * This program is free software; you can redistribute it and/or modify it
  6 * under the terms of the GNU General Public License as published by the Free
  7 * Software Foundation; either version 2 of the License, or (at your option)
  8 * any later version.
  9 */
 10
 11/*
 12 * simple-framebuffer probing
 13 * Try to convert "screen_info" into a "simple-framebuffer" compatible mode.
 14 * If the mode is incompatible, we return "false" and let the caller create
 15 * legacy nodes instead.
 16 */
 17
 18#include <linux/err.h>
 19#include <linux/init.h>
 20#include <linux/kernel.h>
 21#include <linux/mm.h>
 22#include <linux/platform_data/simplefb.h>
 23#include <linux/platform_device.h>
 24#include <linux/screen_info.h>
 25#include <asm/sysfb.h>
 26
 27static const char simplefb_resname[] = "BOOTFB";
 28static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
 29
 30/* try parsing x86 screen_info into a simple-framebuffer mode struct */
 31__init bool parse_mode(const struct screen_info *si,
 32		       struct simplefb_platform_data *mode)
 33{
 34	const struct simplefb_format *f;
 35	__u8 type;
 36	unsigned int i;
 37
 38	type = si->orig_video_isVGA;
 39	if (type != VIDEO_TYPE_VLFB && type != VIDEO_TYPE_EFI)
 40		return false;
 41
 42	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
 43		f = &formats[i];
 44		if (si->lfb_depth == f->bits_per_pixel &&
 45		    si->red_size == f->red.length &&
 46		    si->red_pos == f->red.offset &&
 47		    si->green_size == f->green.length &&
 48		    si->green_pos == f->green.offset &&
 49		    si->blue_size == f->blue.length &&
 50		    si->blue_pos == f->blue.offset &&
 51		    si->rsvd_size == f->transp.length &&
 52		    si->rsvd_pos == f->transp.offset) {
 53			mode->format = f->name;
 54			mode->width = si->lfb_width;
 55			mode->height = si->lfb_height;
 56			mode->stride = si->lfb_linelength;
 57			return true;
 58		}
 59	}
 60
 61	return false;
 62}
 63
 64__init int create_simplefb(const struct screen_info *si,
 65			   const struct simplefb_platform_data *mode)
 66{
 67	struct platform_device *pd;
 68	struct resource res;
 69	u64 base, size;
 70	u32 length;
 71
 72	/*
 73	 * If the 64BIT_BASE capability is set, ext_lfb_base will contain the
 74	 * upper half of the base address. Assemble the address, then make sure
 75	 * it is valid and we can actually access it.
 76	 */
 77	base = si->lfb_base;
 78	if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE)
 79		base |= (u64)si->ext_lfb_base << 32;
 80	if (!base || (u64)(resource_size_t)base != base) {
 81		printk(KERN_DEBUG "sysfb: inaccessible VRAM base\n");
 82		return -EINVAL;
 83	}
 84
 85	/*
 86	 * Don't use lfb_size as IORESOURCE size, since it may contain the
 87	 * entire VMEM, and thus require huge mappings. Use just the part we
 88	 * need, that is, the part where the framebuffer is located. But verify
 89	 * that it does not exceed the advertised VMEM.
 90	 * Note that in case of VBE, the lfb_size is shifted by 16 bits for
 91	 * historical reasons.
 92	 */
 93	size = si->lfb_size;
 94	if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
 95		size <<= 16;
 96	length = mode->height * mode->stride;
 97	length = PAGE_ALIGN(length);
 98	if (length > size) {
 99		printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
100		return -EINVAL;
101	}
102
103	/* setup IORESOURCE_MEM as framebuffer memory */
104	memset(&res, 0, sizeof(res));
105	res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
106	res.name = simplefb_resname;
107	res.start = base;
108	res.end = res.start + length - 1;
109	if (res.end <= res.start)
110		return -EINVAL;
111
112	pd = platform_device_register_resndata(NULL, "simple-framebuffer", 0,
113					       &res, 1, mode, sizeof(*mode));
114	return PTR_ERR_OR_ZERO(pd);
115}