18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Framebuffer driver for EFI/UEFI based system
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * (c) 2006 Edgar Hucek <gimli@dark-green.com>
68c2ecf20Sopenharmony_ci * Original efi driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/efi.h>
128c2ecf20Sopenharmony_ci#include <linux/efi-bgrt.h>
138c2ecf20Sopenharmony_ci#include <linux/errno.h>
148c2ecf20Sopenharmony_ci#include <linux/fb.h>
158c2ecf20Sopenharmony_ci#include <linux/pci.h>
168c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
178c2ecf20Sopenharmony_ci#include <linux/printk.h>
188c2ecf20Sopenharmony_ci#include <linux/screen_info.h>
198c2ecf20Sopenharmony_ci#include <video/vga.h>
208c2ecf20Sopenharmony_ci#include <asm/efi.h>
218c2ecf20Sopenharmony_ci#include <drm/drm_utils.h> /* For drm_get_panel_orientation_quirk */
228c2ecf20Sopenharmony_ci#include <drm/drm_connector.h>  /* For DRM_MODE_PANEL_ORIENTATION_* */
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistruct bmp_file_header {
258c2ecf20Sopenharmony_ci	u16 id;
268c2ecf20Sopenharmony_ci	u32 file_size;
278c2ecf20Sopenharmony_ci	u32 reserved;
288c2ecf20Sopenharmony_ci	u32 bitmap_offset;
298c2ecf20Sopenharmony_ci} __packed;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistruct bmp_dib_header {
328c2ecf20Sopenharmony_ci	u32 dib_header_size;
338c2ecf20Sopenharmony_ci	s32 width;
348c2ecf20Sopenharmony_ci	s32 height;
358c2ecf20Sopenharmony_ci	u16 planes;
368c2ecf20Sopenharmony_ci	u16 bpp;
378c2ecf20Sopenharmony_ci	u32 compression;
388c2ecf20Sopenharmony_ci	u32 bitmap_size;
398c2ecf20Sopenharmony_ci	u32 horz_resolution;
408c2ecf20Sopenharmony_ci	u32 vert_resolution;
418c2ecf20Sopenharmony_ci	u32 colors_used;
428c2ecf20Sopenharmony_ci	u32 colors_important;
438c2ecf20Sopenharmony_ci} __packed;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic bool use_bgrt = true;
468c2ecf20Sopenharmony_cistatic bool request_mem_succeeded = false;
478c2ecf20Sopenharmony_cistatic u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic struct fb_var_screeninfo efifb_defined = {
508c2ecf20Sopenharmony_ci	.activate		= FB_ACTIVATE_NOW,
518c2ecf20Sopenharmony_ci	.height			= -1,
528c2ecf20Sopenharmony_ci	.width			= -1,
538c2ecf20Sopenharmony_ci	.right_margin		= 32,
548c2ecf20Sopenharmony_ci	.upper_margin		= 16,
558c2ecf20Sopenharmony_ci	.lower_margin		= 4,
568c2ecf20Sopenharmony_ci	.vsync_len		= 4,
578c2ecf20Sopenharmony_ci	.vmode			= FB_VMODE_NONINTERLACED,
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic struct fb_fix_screeninfo efifb_fix = {
618c2ecf20Sopenharmony_ci	.id			= "EFI VGA",
628c2ecf20Sopenharmony_ci	.type			= FB_TYPE_PACKED_PIXELS,
638c2ecf20Sopenharmony_ci	.accel			= FB_ACCEL_NONE,
648c2ecf20Sopenharmony_ci	.visual			= FB_VISUAL_TRUECOLOR,
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
688c2ecf20Sopenharmony_ci			   unsigned blue, unsigned transp,
698c2ecf20Sopenharmony_ci			   struct fb_info *info)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	/*
728c2ecf20Sopenharmony_ci	 *  Set a single color register. The values supplied are
738c2ecf20Sopenharmony_ci	 *  already rounded down to the hardware's capabilities
748c2ecf20Sopenharmony_ci	 *  (according to the entries in the `var' structure). Return
758c2ecf20Sopenharmony_ci	 *  != 0 for invalid regno.
768c2ecf20Sopenharmony_ci	 */
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (regno >= info->cmap.len)
798c2ecf20Sopenharmony_ci		return 1;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	if (regno < 16) {
828c2ecf20Sopenharmony_ci		red   >>= 16 - info->var.red.length;
838c2ecf20Sopenharmony_ci		green >>= 16 - info->var.green.length;
848c2ecf20Sopenharmony_ci		blue  >>= 16 - info->var.blue.length;
858c2ecf20Sopenharmony_ci		((u32 *)(info->pseudo_palette))[regno] =
868c2ecf20Sopenharmony_ci			(red   << info->var.red.offset)   |
878c2ecf20Sopenharmony_ci			(green << info->var.green.offset) |
888c2ecf20Sopenharmony_ci			(blue  << info->var.blue.offset);
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci	return 0;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci/*
948c2ecf20Sopenharmony_ci * If fbcon deffered console takeover is configured, the intent is for the
958c2ecf20Sopenharmony_ci * framebuffer to show the boot graphics (e.g. vendor logo) until there is some
968c2ecf20Sopenharmony_ci * (error) message to display. But the boot graphics may have been destroyed by
978c2ecf20Sopenharmony_ci * e.g. option ROM output, detect this and restore the boot graphics.
988c2ecf20Sopenharmony_ci */
998c2ecf20Sopenharmony_ci#if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \
1008c2ecf20Sopenharmony_ci    defined CONFIG_ACPI_BGRT
1018c2ecf20Sopenharmony_cistatic void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	u8 r, g, b;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	while (width--) {
1068c2ecf20Sopenharmony_ci		b = *src++;
1078c2ecf20Sopenharmony_ci		g = *src++;
1088c2ecf20Sopenharmony_ci		r = *src++;
1098c2ecf20Sopenharmony_ci		*dst++ = (r << si->red_pos)   |
1108c2ecf20Sopenharmony_ci			 (g << si->green_pos) |
1118c2ecf20Sopenharmony_ci			 (b << si->blue_pos);
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
1168c2ecf20Sopenharmony_ci/*
1178c2ecf20Sopenharmony_ci * On x86 some firmwares use a low non native resolution for the display when
1188c2ecf20Sopenharmony_ci * they have shown some text messages. While keeping the bgrt filled with info
1198c2ecf20Sopenharmony_ci * for the native resolution. If the bgrt image intended for the native
1208c2ecf20Sopenharmony_ci * resolution still fits, it will be displayed very close to the right edge of
1218c2ecf20Sopenharmony_ci * the display looking quite bad. This function checks for this.
1228c2ecf20Sopenharmony_ci */
1238c2ecf20Sopenharmony_cistatic bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	/*
1268c2ecf20Sopenharmony_ci	 * All x86 firmwares horizontally center the image (the yoffset
1278c2ecf20Sopenharmony_ci	 * calculations differ between boards, but xoffset is predictable).
1288c2ecf20Sopenharmony_ci	 */
1298c2ecf20Sopenharmony_ci	u32 expected_xoffset = (si->lfb_width - bmp_width) / 2;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return bgrt_tab.image_offset_x == expected_xoffset;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci#else
1348c2ecf20Sopenharmony_cistatic bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	return true;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci#endif
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic void efifb_show_boot_graphics(struct fb_info *info)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	u32 bmp_width, bmp_height, bmp_pitch, screen_pitch, dst_x, y, src_y;
1438c2ecf20Sopenharmony_ci	struct screen_info *si = &screen_info;
1448c2ecf20Sopenharmony_ci	struct bmp_file_header *file_header;
1458c2ecf20Sopenharmony_ci	struct bmp_dib_header *dib_header;
1468c2ecf20Sopenharmony_ci	void *bgrt_image = NULL;
1478c2ecf20Sopenharmony_ci	u8 *dst = info->screen_base;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	if (!use_bgrt)
1508c2ecf20Sopenharmony_ci		return;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	if (!bgrt_tab.image_address) {
1538c2ecf20Sopenharmony_ci		pr_info("efifb: No BGRT, not showing boot graphics\n");
1548c2ecf20Sopenharmony_ci		return;
1558c2ecf20Sopenharmony_ci	}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (bgrt_tab.status & 0x06) {
1588c2ecf20Sopenharmony_ci		pr_info("efifb: BGRT rotation bits set, not showing boot graphics\n");
1598c2ecf20Sopenharmony_ci		return;
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	/* Avoid flashing the logo if we're going to print std probe messages */
1638c2ecf20Sopenharmony_ci	if (console_loglevel > CONSOLE_LOGLEVEL_QUIET)
1648c2ecf20Sopenharmony_ci		return;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/* bgrt_tab.status is unreliable, so we don't check it */
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	if (si->lfb_depth != 32) {
1698c2ecf20Sopenharmony_ci		pr_info("efifb: not 32 bits, not showing boot graphics\n");
1708c2ecf20Sopenharmony_ci		return;
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	bgrt_image = memremap(bgrt_tab.image_address, bgrt_image_size,
1748c2ecf20Sopenharmony_ci			      MEMREMAP_WB);
1758c2ecf20Sopenharmony_ci	if (!bgrt_image) {
1768c2ecf20Sopenharmony_ci		pr_warn("efifb: Ignoring BGRT: failed to map image memory\n");
1778c2ecf20Sopenharmony_ci		return;
1788c2ecf20Sopenharmony_ci	}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	if (bgrt_image_size < (sizeof(*file_header) + sizeof(*dib_header)))
1818c2ecf20Sopenharmony_ci		goto error;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	file_header = bgrt_image;
1848c2ecf20Sopenharmony_ci	if (file_header->id != 0x4d42 || file_header->reserved != 0)
1858c2ecf20Sopenharmony_ci		goto error;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	dib_header = bgrt_image + sizeof(*file_header);
1888c2ecf20Sopenharmony_ci	if (dib_header->dib_header_size != 40 || dib_header->width < 0 ||
1898c2ecf20Sopenharmony_ci	    dib_header->planes != 1 || dib_header->bpp != 24 ||
1908c2ecf20Sopenharmony_ci	    dib_header->compression != 0)
1918c2ecf20Sopenharmony_ci		goto error;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	bmp_width = dib_header->width;
1948c2ecf20Sopenharmony_ci	bmp_height = abs(dib_header->height);
1958c2ecf20Sopenharmony_ci	bmp_pitch = round_up(3 * bmp_width, 4);
1968c2ecf20Sopenharmony_ci	screen_pitch = si->lfb_linelength;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if ((file_header->bitmap_offset + bmp_pitch * bmp_height) >
1998c2ecf20Sopenharmony_ci				bgrt_image_size)
2008c2ecf20Sopenharmony_ci		goto error;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	if ((bgrt_tab.image_offset_x + bmp_width) > si->lfb_width ||
2038c2ecf20Sopenharmony_ci	    (bgrt_tab.image_offset_y + bmp_height) > si->lfb_height)
2048c2ecf20Sopenharmony_ci		goto error;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	if (!efifb_bgrt_sanity_check(si, bmp_width))
2078c2ecf20Sopenharmony_ci		goto error;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	pr_info("efifb: showing boot graphics\n");
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	for (y = 0; y < si->lfb_height; y++, dst += si->lfb_linelength) {
2128c2ecf20Sopenharmony_ci		/* Only background? */
2138c2ecf20Sopenharmony_ci		if (y < bgrt_tab.image_offset_y ||
2148c2ecf20Sopenharmony_ci		    y >= (bgrt_tab.image_offset_y + bmp_height)) {
2158c2ecf20Sopenharmony_ci			memset(dst, 0, 4 * si->lfb_width);
2168c2ecf20Sopenharmony_ci			continue;
2178c2ecf20Sopenharmony_ci		}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci		src_y = y - bgrt_tab.image_offset_y;
2208c2ecf20Sopenharmony_ci		/* Positive header height means upside down row order */
2218c2ecf20Sopenharmony_ci		if (dib_header->height > 0)
2228c2ecf20Sopenharmony_ci			src_y = (bmp_height - 1) - src_y;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci		memset(dst, 0, bgrt_tab.image_offset_x * 4);
2258c2ecf20Sopenharmony_ci		dst_x = bgrt_tab.image_offset_x;
2268c2ecf20Sopenharmony_ci		efifb_copy_bmp(bgrt_image + file_header->bitmap_offset +
2278c2ecf20Sopenharmony_ci					    src_y * bmp_pitch,
2288c2ecf20Sopenharmony_ci			       (u32 *)dst + dst_x, bmp_width, si);
2298c2ecf20Sopenharmony_ci		dst_x += bmp_width;
2308c2ecf20Sopenharmony_ci		memset((u32 *)dst + dst_x, 0, (si->lfb_width - dst_x) * 4);
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	memunmap(bgrt_image);
2348c2ecf20Sopenharmony_ci	return;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cierror:
2378c2ecf20Sopenharmony_ci	memunmap(bgrt_image);
2388c2ecf20Sopenharmony_ci	pr_warn("efifb: Ignoring BGRT: unexpected or invalid BMP data\n");
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci#else
2418c2ecf20Sopenharmony_cistatic inline void efifb_show_boot_graphics(struct fb_info *info) {}
2428c2ecf20Sopenharmony_ci#endif
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic void efifb_destroy(struct fb_info *info)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	if (info->screen_base) {
2478c2ecf20Sopenharmony_ci		if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
2488c2ecf20Sopenharmony_ci			iounmap(info->screen_base);
2498c2ecf20Sopenharmony_ci		else
2508c2ecf20Sopenharmony_ci			memunmap(info->screen_base);
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci	if (request_mem_succeeded)
2538c2ecf20Sopenharmony_ci		release_mem_region(info->apertures->ranges[0].base,
2548c2ecf20Sopenharmony_ci				   info->apertures->ranges[0].size);
2558c2ecf20Sopenharmony_ci	fb_dealloc_cmap(&info->cmap);
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic const struct fb_ops efifb_ops = {
2598c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
2608c2ecf20Sopenharmony_ci	.fb_destroy	= efifb_destroy,
2618c2ecf20Sopenharmony_ci	.fb_setcolreg	= efifb_setcolreg,
2628c2ecf20Sopenharmony_ci	.fb_fillrect	= cfb_fillrect,
2638c2ecf20Sopenharmony_ci	.fb_copyarea	= cfb_copyarea,
2648c2ecf20Sopenharmony_ci	.fb_imageblit	= cfb_imageblit,
2658c2ecf20Sopenharmony_ci};
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistatic int efifb_setup(char *options)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	char *this_opt;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (options && *options) {
2728c2ecf20Sopenharmony_ci		while ((this_opt = strsep(&options, ",")) != NULL) {
2738c2ecf20Sopenharmony_ci			if (!*this_opt) continue;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci			efifb_setup_from_dmi(&screen_info, this_opt);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci			if (!strncmp(this_opt, "base:", 5))
2788c2ecf20Sopenharmony_ci				screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
2798c2ecf20Sopenharmony_ci			else if (!strncmp(this_opt, "stride:", 7))
2808c2ecf20Sopenharmony_ci				screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
2818c2ecf20Sopenharmony_ci			else if (!strncmp(this_opt, "height:", 7))
2828c2ecf20Sopenharmony_ci				screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
2838c2ecf20Sopenharmony_ci			else if (!strncmp(this_opt, "width:", 6))
2848c2ecf20Sopenharmony_ci				screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
2858c2ecf20Sopenharmony_ci			else if (!strcmp(this_opt, "nowc"))
2868c2ecf20Sopenharmony_ci				mem_flags &= ~EFI_MEMORY_WC;
2878c2ecf20Sopenharmony_ci			else if (!strcmp(this_opt, "nobgrt"))
2888c2ecf20Sopenharmony_ci				use_bgrt = false;
2898c2ecf20Sopenharmony_ci		}
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	return 0;
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic inline bool fb_base_is_valid(void)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	if (screen_info.lfb_base)
2988c2ecf20Sopenharmony_ci		return true;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	if (!(screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE))
3018c2ecf20Sopenharmony_ci		return false;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	if (screen_info.ext_lfb_base)
3048c2ecf20Sopenharmony_ci		return true;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	return false;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci#define efifb_attr_decl(name, fmt)					\
3108c2ecf20Sopenharmony_cistatic ssize_t name##_show(struct device *dev,				\
3118c2ecf20Sopenharmony_ci			   struct device_attribute *attr,		\
3128c2ecf20Sopenharmony_ci			   char *buf)					\
3138c2ecf20Sopenharmony_ci{									\
3148c2ecf20Sopenharmony_ci	return sprintf(buf, fmt "\n", (screen_info.lfb_##name));	\
3158c2ecf20Sopenharmony_ci}									\
3168c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(name)
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ciefifb_attr_decl(base, "0x%x");
3198c2ecf20Sopenharmony_ciefifb_attr_decl(linelength, "%u");
3208c2ecf20Sopenharmony_ciefifb_attr_decl(height, "%u");
3218c2ecf20Sopenharmony_ciefifb_attr_decl(width, "%u");
3228c2ecf20Sopenharmony_ciefifb_attr_decl(depth, "%u");
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic struct attribute *efifb_attrs[] = {
3258c2ecf20Sopenharmony_ci	&dev_attr_base.attr,
3268c2ecf20Sopenharmony_ci	&dev_attr_linelength.attr,
3278c2ecf20Sopenharmony_ci	&dev_attr_width.attr,
3288c2ecf20Sopenharmony_ci	&dev_attr_height.attr,
3298c2ecf20Sopenharmony_ci	&dev_attr_depth.attr,
3308c2ecf20Sopenharmony_ci	NULL
3318c2ecf20Sopenharmony_ci};
3328c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(efifb);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic bool pci_dev_disabled;	/* FB base matches BAR of a disabled device */
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic struct pci_dev *efifb_pci_dev;	/* dev with BAR covering the efifb */
3378c2ecf20Sopenharmony_cistatic struct resource *bar_resource;
3388c2ecf20Sopenharmony_cistatic u64 bar_offset;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic int efifb_probe(struct platform_device *dev)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	struct fb_info *info;
3438c2ecf20Sopenharmony_ci	int err, orientation;
3448c2ecf20Sopenharmony_ci	unsigned int size_vmode;
3458c2ecf20Sopenharmony_ci	unsigned int size_remap;
3468c2ecf20Sopenharmony_ci	unsigned int size_total;
3478c2ecf20Sopenharmony_ci	char *option = NULL;
3488c2ecf20Sopenharmony_ci	efi_memory_desc_t md;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
3518c2ecf20Sopenharmony_ci		return -ENODEV;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	if (fb_get_options("efifb", &option))
3548c2ecf20Sopenharmony_ci		return -ENODEV;
3558c2ecf20Sopenharmony_ci	efifb_setup(option);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	/* We don't get linelength from UGA Draw Protocol, only from
3588c2ecf20Sopenharmony_ci	 * EFI Graphics Protocol.  So if it's not in DMI, and it's not
3598c2ecf20Sopenharmony_ci	 * passed in from the user, we really can't use the framebuffer.
3608c2ecf20Sopenharmony_ci	 */
3618c2ecf20Sopenharmony_ci	if (!screen_info.lfb_linelength)
3628c2ecf20Sopenharmony_ci		return -ENODEV;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	if (!screen_info.lfb_depth)
3658c2ecf20Sopenharmony_ci		screen_info.lfb_depth = 32;
3668c2ecf20Sopenharmony_ci	if (!screen_info.pages)
3678c2ecf20Sopenharmony_ci		screen_info.pages = 1;
3688c2ecf20Sopenharmony_ci	if (!fb_base_is_valid()) {
3698c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "efifb: invalid framebuffer address\n");
3708c2ecf20Sopenharmony_ci		return -ENODEV;
3718c2ecf20Sopenharmony_ci	}
3728c2ecf20Sopenharmony_ci	printk(KERN_INFO "efifb: probing for efifb\n");
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	/* just assume they're all unset if any are */
3758c2ecf20Sopenharmony_ci	if (!screen_info.blue_size) {
3768c2ecf20Sopenharmony_ci		screen_info.blue_size = 8;
3778c2ecf20Sopenharmony_ci		screen_info.blue_pos = 0;
3788c2ecf20Sopenharmony_ci		screen_info.green_size = 8;
3798c2ecf20Sopenharmony_ci		screen_info.green_pos = 8;
3808c2ecf20Sopenharmony_ci		screen_info.red_size = 8;
3818c2ecf20Sopenharmony_ci		screen_info.red_pos = 16;
3828c2ecf20Sopenharmony_ci		screen_info.rsvd_size = 8;
3838c2ecf20Sopenharmony_ci		screen_info.rsvd_pos = 24;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	efifb_fix.smem_start = screen_info.lfb_base;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) {
3898c2ecf20Sopenharmony_ci		u64 ext_lfb_base;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci		ext_lfb_base = (u64)(unsigned long)screen_info.ext_lfb_base << 32;
3928c2ecf20Sopenharmony_ci		efifb_fix.smem_start |= ext_lfb_base;
3938c2ecf20Sopenharmony_ci	}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (bar_resource &&
3968c2ecf20Sopenharmony_ci	    bar_resource->start + bar_offset != efifb_fix.smem_start) {
3978c2ecf20Sopenharmony_ci		dev_info(&efifb_pci_dev->dev,
3988c2ecf20Sopenharmony_ci			 "BAR has moved, updating efifb address\n");
3998c2ecf20Sopenharmony_ci		efifb_fix.smem_start = bar_resource->start + bar_offset;
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	efifb_defined.bits_per_pixel = screen_info.lfb_depth;
4038c2ecf20Sopenharmony_ci	efifb_defined.xres = screen_info.lfb_width;
4048c2ecf20Sopenharmony_ci	efifb_defined.yres = screen_info.lfb_height;
4058c2ecf20Sopenharmony_ci	efifb_fix.line_length = screen_info.lfb_linelength;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	/*   size_vmode -- that is the amount of memory needed for the
4088c2ecf20Sopenharmony_ci	 *                 used video mode, i.e. the minimum amount of
4098c2ecf20Sopenharmony_ci	 *                 memory we need. */
4108c2ecf20Sopenharmony_ci	size_vmode = efifb_defined.yres * efifb_fix.line_length;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	/*   size_total -- all video memory we have. Used for
4138c2ecf20Sopenharmony_ci	 *                 entries, ressource allocation and bounds
4148c2ecf20Sopenharmony_ci	 *                 checking. */
4158c2ecf20Sopenharmony_ci	size_total = screen_info.lfb_size;
4168c2ecf20Sopenharmony_ci	if (size_total < size_vmode)
4178c2ecf20Sopenharmony_ci		size_total = size_vmode;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	/*   size_remap -- the amount of video memory we are going to
4208c2ecf20Sopenharmony_ci	 *                 use for efifb.  With modern cards it is no
4218c2ecf20Sopenharmony_ci	 *                 option to simply use size_total as that
4228c2ecf20Sopenharmony_ci	 *                 wastes plenty of kernel address space. */
4238c2ecf20Sopenharmony_ci	size_remap  = size_vmode * 2;
4248c2ecf20Sopenharmony_ci	if (size_remap > size_total)
4258c2ecf20Sopenharmony_ci		size_remap = size_total;
4268c2ecf20Sopenharmony_ci	if (size_remap % PAGE_SIZE)
4278c2ecf20Sopenharmony_ci		size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE);
4288c2ecf20Sopenharmony_ci	efifb_fix.smem_len = size_remap;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) {
4318c2ecf20Sopenharmony_ci		request_mem_succeeded = true;
4328c2ecf20Sopenharmony_ci	} else {
4338c2ecf20Sopenharmony_ci		/* We cannot make this fatal. Sometimes this comes from magic
4348c2ecf20Sopenharmony_ci		   spaces our resource handlers simply don't know about */
4358c2ecf20Sopenharmony_ci		pr_warn("efifb: cannot reserve video memory at 0x%lx\n",
4368c2ecf20Sopenharmony_ci			efifb_fix.smem_start);
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
4408c2ecf20Sopenharmony_ci	if (!info) {
4418c2ecf20Sopenharmony_ci		err = -ENOMEM;
4428c2ecf20Sopenharmony_ci		goto err_release_mem;
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci	platform_set_drvdata(dev, info);
4458c2ecf20Sopenharmony_ci	info->pseudo_palette = info->par;
4468c2ecf20Sopenharmony_ci	info->par = NULL;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	info->apertures = alloc_apertures(1);
4498c2ecf20Sopenharmony_ci	if (!info->apertures) {
4508c2ecf20Sopenharmony_ci		err = -ENOMEM;
4518c2ecf20Sopenharmony_ci		goto err_release_fb;
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci	info->apertures->ranges[0].base = efifb_fix.smem_start;
4548c2ecf20Sopenharmony_ci	info->apertures->ranges[0].size = size_remap;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	if (efi_enabled(EFI_MEMMAP) &&
4578c2ecf20Sopenharmony_ci	    !efi_mem_desc_lookup(efifb_fix.smem_start, &md)) {
4588c2ecf20Sopenharmony_ci		if ((efifb_fix.smem_start + efifb_fix.smem_len) >
4598c2ecf20Sopenharmony_ci		    (md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT))) {
4608c2ecf20Sopenharmony_ci			pr_err("efifb: video memory @ 0x%lx spans multiple EFI memory regions\n",
4618c2ecf20Sopenharmony_ci			       efifb_fix.smem_start);
4628c2ecf20Sopenharmony_ci			err = -EIO;
4638c2ecf20Sopenharmony_ci			goto err_release_fb;
4648c2ecf20Sopenharmony_ci		}
4658c2ecf20Sopenharmony_ci		/*
4668c2ecf20Sopenharmony_ci		 * If the UEFI memory map covers the efifb region, we may only
4678c2ecf20Sopenharmony_ci		 * remap it using the attributes the memory map prescribes.
4688c2ecf20Sopenharmony_ci		 */
4698c2ecf20Sopenharmony_ci		md.attribute &= EFI_MEMORY_UC | EFI_MEMORY_WC |
4708c2ecf20Sopenharmony_ci				EFI_MEMORY_WT | EFI_MEMORY_WB;
4718c2ecf20Sopenharmony_ci		if (md.attribute) {
4728c2ecf20Sopenharmony_ci			mem_flags |= EFI_MEMORY_WT | EFI_MEMORY_WB;
4738c2ecf20Sopenharmony_ci			mem_flags &= md.attribute;
4748c2ecf20Sopenharmony_ci		}
4758c2ecf20Sopenharmony_ci	}
4768c2ecf20Sopenharmony_ci	if (mem_flags & EFI_MEMORY_WC)
4778c2ecf20Sopenharmony_ci		info->screen_base = ioremap_wc(efifb_fix.smem_start,
4788c2ecf20Sopenharmony_ci					       efifb_fix.smem_len);
4798c2ecf20Sopenharmony_ci	else if (mem_flags & EFI_MEMORY_UC)
4808c2ecf20Sopenharmony_ci		info->screen_base = ioremap(efifb_fix.smem_start,
4818c2ecf20Sopenharmony_ci					    efifb_fix.smem_len);
4828c2ecf20Sopenharmony_ci	else if (mem_flags & EFI_MEMORY_WT)
4838c2ecf20Sopenharmony_ci		info->screen_base = memremap(efifb_fix.smem_start,
4848c2ecf20Sopenharmony_ci					     efifb_fix.smem_len, MEMREMAP_WT);
4858c2ecf20Sopenharmony_ci	else if (mem_flags & EFI_MEMORY_WB)
4868c2ecf20Sopenharmony_ci		info->screen_base = memremap(efifb_fix.smem_start,
4878c2ecf20Sopenharmony_ci					     efifb_fix.smem_len, MEMREMAP_WB);
4888c2ecf20Sopenharmony_ci	if (!info->screen_base) {
4898c2ecf20Sopenharmony_ci		pr_err("efifb: abort, cannot remap video memory 0x%x @ 0x%lx\n",
4908c2ecf20Sopenharmony_ci			efifb_fix.smem_len, efifb_fix.smem_start);
4918c2ecf20Sopenharmony_ci		err = -EIO;
4928c2ecf20Sopenharmony_ci		goto err_release_fb;
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	efifb_show_boot_graphics(info);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	pr_info("efifb: framebuffer at 0x%lx, using %dk, total %dk\n",
4988c2ecf20Sopenharmony_ci	       efifb_fix.smem_start, size_remap/1024, size_total/1024);
4998c2ecf20Sopenharmony_ci	pr_info("efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
5008c2ecf20Sopenharmony_ci	       efifb_defined.xres, efifb_defined.yres,
5018c2ecf20Sopenharmony_ci	       efifb_defined.bits_per_pixel, efifb_fix.line_length,
5028c2ecf20Sopenharmony_ci	       screen_info.pages);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	efifb_defined.xres_virtual = efifb_defined.xres;
5058c2ecf20Sopenharmony_ci	efifb_defined.yres_virtual = efifb_fix.smem_len /
5068c2ecf20Sopenharmony_ci					efifb_fix.line_length;
5078c2ecf20Sopenharmony_ci	pr_info("efifb: scrolling: redraw\n");
5088c2ecf20Sopenharmony_ci	efifb_defined.yres_virtual = efifb_defined.yres;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	/* some dummy values for timing to make fbset happy */
5118c2ecf20Sopenharmony_ci	efifb_defined.pixclock     = 10000000 / efifb_defined.xres *
5128c2ecf20Sopenharmony_ci					1000 / efifb_defined.yres;
5138c2ecf20Sopenharmony_ci	efifb_defined.left_margin  = (efifb_defined.xres / 8) & 0xf8;
5148c2ecf20Sopenharmony_ci	efifb_defined.hsync_len    = (efifb_defined.xres / 8) & 0xf8;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	efifb_defined.red.offset    = screen_info.red_pos;
5178c2ecf20Sopenharmony_ci	efifb_defined.red.length    = screen_info.red_size;
5188c2ecf20Sopenharmony_ci	efifb_defined.green.offset  = screen_info.green_pos;
5198c2ecf20Sopenharmony_ci	efifb_defined.green.length  = screen_info.green_size;
5208c2ecf20Sopenharmony_ci	efifb_defined.blue.offset   = screen_info.blue_pos;
5218c2ecf20Sopenharmony_ci	efifb_defined.blue.length   = screen_info.blue_size;
5228c2ecf20Sopenharmony_ci	efifb_defined.transp.offset = screen_info.rsvd_pos;
5238c2ecf20Sopenharmony_ci	efifb_defined.transp.length = screen_info.rsvd_size;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	pr_info("efifb: %s: "
5268c2ecf20Sopenharmony_ci	       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
5278c2ecf20Sopenharmony_ci	       "Truecolor",
5288c2ecf20Sopenharmony_ci	       screen_info.rsvd_size,
5298c2ecf20Sopenharmony_ci	       screen_info.red_size,
5308c2ecf20Sopenharmony_ci	       screen_info.green_size,
5318c2ecf20Sopenharmony_ci	       screen_info.blue_size,
5328c2ecf20Sopenharmony_ci	       screen_info.rsvd_pos,
5338c2ecf20Sopenharmony_ci	       screen_info.red_pos,
5348c2ecf20Sopenharmony_ci	       screen_info.green_pos,
5358c2ecf20Sopenharmony_ci	       screen_info.blue_pos);
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	efifb_fix.ypanstep  = 0;
5388c2ecf20Sopenharmony_ci	efifb_fix.ywrapstep = 0;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	info->fbops = &efifb_ops;
5418c2ecf20Sopenharmony_ci	info->var = efifb_defined;
5428c2ecf20Sopenharmony_ci	info->fix = efifb_fix;
5438c2ecf20Sopenharmony_ci	info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	orientation = drm_get_panel_orientation_quirk(efifb_defined.xres,
5468c2ecf20Sopenharmony_ci						      efifb_defined.yres);
5478c2ecf20Sopenharmony_ci	switch (orientation) {
5488c2ecf20Sopenharmony_ci	default:
5498c2ecf20Sopenharmony_ci		info->fbcon_rotate_hint = FB_ROTATE_UR;
5508c2ecf20Sopenharmony_ci		break;
5518c2ecf20Sopenharmony_ci	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
5528c2ecf20Sopenharmony_ci		info->fbcon_rotate_hint = FB_ROTATE_UD;
5538c2ecf20Sopenharmony_ci		break;
5548c2ecf20Sopenharmony_ci	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
5558c2ecf20Sopenharmony_ci		info->fbcon_rotate_hint = FB_ROTATE_CCW;
5568c2ecf20Sopenharmony_ci		break;
5578c2ecf20Sopenharmony_ci	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
5588c2ecf20Sopenharmony_ci		info->fbcon_rotate_hint = FB_ROTATE_CW;
5598c2ecf20Sopenharmony_ci		break;
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	err = sysfs_create_groups(&dev->dev.kobj, efifb_groups);
5638c2ecf20Sopenharmony_ci	if (err) {
5648c2ecf20Sopenharmony_ci		pr_err("efifb: cannot add sysfs attrs\n");
5658c2ecf20Sopenharmony_ci		goto err_unmap;
5668c2ecf20Sopenharmony_ci	}
5678c2ecf20Sopenharmony_ci	err = fb_alloc_cmap(&info->cmap, 256, 0);
5688c2ecf20Sopenharmony_ci	if (err < 0) {
5698c2ecf20Sopenharmony_ci		pr_err("efifb: cannot allocate colormap\n");
5708c2ecf20Sopenharmony_ci		goto err_groups;
5718c2ecf20Sopenharmony_ci	}
5728c2ecf20Sopenharmony_ci	err = register_framebuffer(info);
5738c2ecf20Sopenharmony_ci	if (err < 0) {
5748c2ecf20Sopenharmony_ci		pr_err("efifb: cannot register framebuffer\n");
5758c2ecf20Sopenharmony_ci		goto err_fb_dealoc;
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci	fb_info(info, "%s frame buffer device\n", info->fix.id);
5788c2ecf20Sopenharmony_ci	return 0;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_cierr_fb_dealoc:
5818c2ecf20Sopenharmony_ci	fb_dealloc_cmap(&info->cmap);
5828c2ecf20Sopenharmony_cierr_groups:
5838c2ecf20Sopenharmony_ci	sysfs_remove_groups(&dev->dev.kobj, efifb_groups);
5848c2ecf20Sopenharmony_cierr_unmap:
5858c2ecf20Sopenharmony_ci	if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
5868c2ecf20Sopenharmony_ci		iounmap(info->screen_base);
5878c2ecf20Sopenharmony_ci	else
5888c2ecf20Sopenharmony_ci		memunmap(info->screen_base);
5898c2ecf20Sopenharmony_cierr_release_fb:
5908c2ecf20Sopenharmony_ci	framebuffer_release(info);
5918c2ecf20Sopenharmony_cierr_release_mem:
5928c2ecf20Sopenharmony_ci	if (request_mem_succeeded)
5938c2ecf20Sopenharmony_ci		release_mem_region(efifb_fix.smem_start, size_total);
5948c2ecf20Sopenharmony_ci	return err;
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic int efifb_remove(struct platform_device *pdev)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	struct fb_info *info = platform_get_drvdata(pdev);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	unregister_framebuffer(info);
6028c2ecf20Sopenharmony_ci	sysfs_remove_groups(&pdev->dev.kobj, efifb_groups);
6038c2ecf20Sopenharmony_ci	framebuffer_release(info);
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	return 0;
6068c2ecf20Sopenharmony_ci}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistatic struct platform_driver efifb_driver = {
6098c2ecf20Sopenharmony_ci	.driver = {
6108c2ecf20Sopenharmony_ci		.name = "efi-framebuffer",
6118c2ecf20Sopenharmony_ci	},
6128c2ecf20Sopenharmony_ci	.probe = efifb_probe,
6138c2ecf20Sopenharmony_ci	.remove = efifb_remove,
6148c2ecf20Sopenharmony_ci};
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_cibuiltin_platform_driver(efifb_driver);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci#if defined(CONFIG_PCI)
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_cistatic void record_efifb_bar_resource(struct pci_dev *dev, int idx, u64 offset)
6218c2ecf20Sopenharmony_ci{
6228c2ecf20Sopenharmony_ci	u16 word;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	efifb_pci_dev = dev;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	pci_read_config_word(dev, PCI_COMMAND, &word);
6278c2ecf20Sopenharmony_ci	if (!(word & PCI_COMMAND_MEMORY)) {
6288c2ecf20Sopenharmony_ci		pci_dev_disabled = true;
6298c2ecf20Sopenharmony_ci		dev_err(&dev->dev,
6308c2ecf20Sopenharmony_ci			"BAR %d: assigned to efifb but device is disabled!\n",
6318c2ecf20Sopenharmony_ci			idx);
6328c2ecf20Sopenharmony_ci		return;
6338c2ecf20Sopenharmony_ci	}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	bar_resource = &dev->resource[idx];
6368c2ecf20Sopenharmony_ci	bar_offset = offset;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	dev_info(&dev->dev, "BAR %d: assigned to efifb\n", idx);
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_cistatic void efifb_fixup_resources(struct pci_dev *dev)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	u64 base = screen_info.lfb_base;
6448c2ecf20Sopenharmony_ci	u64 size = screen_info.lfb_size;
6458c2ecf20Sopenharmony_ci	int i;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	if (efifb_pci_dev || screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
6488c2ecf20Sopenharmony_ci		return;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
6518c2ecf20Sopenharmony_ci		base |= (u64)screen_info.ext_lfb_base << 32;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	if (!base)
6548c2ecf20Sopenharmony_ci		return;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
6578c2ecf20Sopenharmony_ci		struct resource *res = &dev->resource[i];
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci		if (!(res->flags & IORESOURCE_MEM))
6608c2ecf20Sopenharmony_ci			continue;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci		if (res->start <= base && res->end >= base + size - 1) {
6638c2ecf20Sopenharmony_ci			record_efifb_bar_resource(dev, i, base - res->start);
6648c2ecf20Sopenharmony_ci			break;
6658c2ecf20Sopenharmony_ci		}
6668c2ecf20Sopenharmony_ci	}
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY,
6698c2ecf20Sopenharmony_ci			       16, efifb_fixup_resources);
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci#endif
672