xref: /openbmc/linux/drivers/video/fbdev/efifb.c (revision bbecb07f)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Framebuffer driver for EFI/UEFI based system
4  *
5  * (c) 2006 Edgar Hucek <gimli@dark-green.com>
6  * Original efi driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
7  *
8  */
9 
10 #include <linux/kernel.h>
11 #include <linux/efi.h>
12 #include <linux/errno.h>
13 #include <linux/fb.h>
14 #include <linux/pci.h>
15 #include <linux/platform_device.h>
16 #include <linux/screen_info.h>
17 #include <video/vga.h>
18 #include <asm/efi.h>
19 
20 static bool request_mem_succeeded = false;
21 static bool nowc = false;
22 
23 static struct fb_var_screeninfo efifb_defined = {
24 	.activate		= FB_ACTIVATE_NOW,
25 	.height			= -1,
26 	.width			= -1,
27 	.right_margin		= 32,
28 	.upper_margin		= 16,
29 	.lower_margin		= 4,
30 	.vsync_len		= 4,
31 	.vmode			= FB_VMODE_NONINTERLACED,
32 };
33 
34 static struct fb_fix_screeninfo efifb_fix = {
35 	.id			= "EFI VGA",
36 	.type			= FB_TYPE_PACKED_PIXELS,
37 	.accel			= FB_ACCEL_NONE,
38 	.visual			= FB_VISUAL_TRUECOLOR,
39 };
40 
41 static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
42 			   unsigned blue, unsigned transp,
43 			   struct fb_info *info)
44 {
45 	/*
46 	 *  Set a single color register. The values supplied are
47 	 *  already rounded down to the hardware's capabilities
48 	 *  (according to the entries in the `var' structure). Return
49 	 *  != 0 for invalid regno.
50 	 */
51 
52 	if (regno >= info->cmap.len)
53 		return 1;
54 
55 	if (regno < 16) {
56 		red   >>= 16 - info->var.red.length;
57 		green >>= 16 - info->var.green.length;
58 		blue  >>= 16 - info->var.blue.length;
59 		((u32 *)(info->pseudo_palette))[regno] =
60 			(red   << info->var.red.offset)   |
61 			(green << info->var.green.offset) |
62 			(blue  << info->var.blue.offset);
63 	}
64 	return 0;
65 }
66 
67 static void efifb_destroy(struct fb_info *info)
68 {
69 	if (info->screen_base)
70 		iounmap(info->screen_base);
71 	if (request_mem_succeeded)
72 		release_mem_region(info->apertures->ranges[0].base,
73 				   info->apertures->ranges[0].size);
74 	fb_dealloc_cmap(&info->cmap);
75 }
76 
77 static struct fb_ops efifb_ops = {
78 	.owner		= THIS_MODULE,
79 	.fb_destroy	= efifb_destroy,
80 	.fb_setcolreg	= efifb_setcolreg,
81 	.fb_fillrect	= cfb_fillrect,
82 	.fb_copyarea	= cfb_copyarea,
83 	.fb_imageblit	= cfb_imageblit,
84 };
85 
86 static int efifb_setup(char *options)
87 {
88 	char *this_opt;
89 
90 	if (options && *options) {
91 		while ((this_opt = strsep(&options, ",")) != NULL) {
92 			if (!*this_opt) continue;
93 
94 			efifb_setup_from_dmi(&screen_info, this_opt);
95 
96 			if (!strncmp(this_opt, "base:", 5))
97 				screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
98 			else if (!strncmp(this_opt, "stride:", 7))
99 				screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
100 			else if (!strncmp(this_opt, "height:", 7))
101 				screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
102 			else if (!strncmp(this_opt, "width:", 6))
103 				screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
104 			else if (!strcmp(this_opt, "nowc"))
105 				nowc = true;
106 		}
107 	}
108 
109 	return 0;
110 }
111 
112 static inline bool fb_base_is_valid(void)
113 {
114 	if (screen_info.lfb_base)
115 		return true;
116 
117 	if (!(screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE))
118 		return false;
119 
120 	if (screen_info.ext_lfb_base)
121 		return true;
122 
123 	return false;
124 }
125 
126 #define efifb_attr_decl(name, fmt)					\
127 static ssize_t name##_show(struct device *dev,				\
128 			   struct device_attribute *attr,		\
129 			   char *buf)					\
130 {									\
131 	return sprintf(buf, fmt "\n", (screen_info.lfb_##name));	\
132 }									\
133 static DEVICE_ATTR_RO(name)
134 
135 efifb_attr_decl(base, "0x%x");
136 efifb_attr_decl(linelength, "%u");
137 efifb_attr_decl(height, "%u");
138 efifb_attr_decl(width, "%u");
139 efifb_attr_decl(depth, "%u");
140 
141 static struct attribute *efifb_attrs[] = {
142 	&dev_attr_base.attr,
143 	&dev_attr_linelength.attr,
144 	&dev_attr_width.attr,
145 	&dev_attr_height.attr,
146 	&dev_attr_depth.attr,
147 	NULL
148 };
149 ATTRIBUTE_GROUPS(efifb);
150 
151 static bool pci_dev_disabled;	/* FB base matches BAR of a disabled device */
152 
153 static struct pci_dev *efifb_pci_dev;	/* dev with BAR covering the efifb */
154 static struct resource *bar_resource;
155 static u64 bar_offset;
156 
157 static int efifb_probe(struct platform_device *dev)
158 {
159 	struct fb_info *info;
160 	int err;
161 	unsigned int size_vmode;
162 	unsigned int size_remap;
163 	unsigned int size_total;
164 	char *option = NULL;
165 
166 	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
167 		return -ENODEV;
168 
169 	if (fb_get_options("efifb", &option))
170 		return -ENODEV;
171 	efifb_setup(option);
172 
173 	/* We don't get linelength from UGA Draw Protocol, only from
174 	 * EFI Graphics Protocol.  So if it's not in DMI, and it's not
175 	 * passed in from the user, we really can't use the framebuffer.
176 	 */
177 	if (!screen_info.lfb_linelength)
178 		return -ENODEV;
179 
180 	if (!screen_info.lfb_depth)
181 		screen_info.lfb_depth = 32;
182 	if (!screen_info.pages)
183 		screen_info.pages = 1;
184 	if (!fb_base_is_valid()) {
185 		printk(KERN_DEBUG "efifb: invalid framebuffer address\n");
186 		return -ENODEV;
187 	}
188 	printk(KERN_INFO "efifb: probing for efifb\n");
189 
190 	/* just assume they're all unset if any are */
191 	if (!screen_info.blue_size) {
192 		screen_info.blue_size = 8;
193 		screen_info.blue_pos = 0;
194 		screen_info.green_size = 8;
195 		screen_info.green_pos = 8;
196 		screen_info.red_size = 8;
197 		screen_info.red_pos = 16;
198 		screen_info.rsvd_size = 8;
199 		screen_info.rsvd_pos = 24;
200 	}
201 
202 	efifb_fix.smem_start = screen_info.lfb_base;
203 
204 	if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) {
205 		u64 ext_lfb_base;
206 
207 		ext_lfb_base = (u64)(unsigned long)screen_info.ext_lfb_base << 32;
208 		efifb_fix.smem_start |= ext_lfb_base;
209 	}
210 
211 	if (bar_resource &&
212 	    bar_resource->start + bar_offset != efifb_fix.smem_start) {
213 		dev_info(&efifb_pci_dev->dev,
214 			 "BAR has moved, updating efifb address\n");
215 		efifb_fix.smem_start = bar_resource->start + bar_offset;
216 	}
217 
218 	efifb_defined.bits_per_pixel = screen_info.lfb_depth;
219 	efifb_defined.xres = screen_info.lfb_width;
220 	efifb_defined.yres = screen_info.lfb_height;
221 	efifb_fix.line_length = screen_info.lfb_linelength;
222 
223 	/*   size_vmode -- that is the amount of memory needed for the
224 	 *                 used video mode, i.e. the minimum amount of
225 	 *                 memory we need. */
226 	size_vmode = efifb_defined.yres * efifb_fix.line_length;
227 
228 	/*   size_total -- all video memory we have. Used for
229 	 *                 entries, ressource allocation and bounds
230 	 *                 checking. */
231 	size_total = screen_info.lfb_size;
232 	if (size_total < size_vmode)
233 		size_total = size_vmode;
234 
235 	/*   size_remap -- the amount of video memory we are going to
236 	 *                 use for efifb.  With modern cards it is no
237 	 *                 option to simply use size_total as that
238 	 *                 wastes plenty of kernel address space. */
239 	size_remap  = size_vmode * 2;
240 	if (size_remap > size_total)
241 		size_remap = size_total;
242 	if (size_remap % PAGE_SIZE)
243 		size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE);
244 	efifb_fix.smem_len = size_remap;
245 
246 	if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) {
247 		request_mem_succeeded = true;
248 	} else {
249 		/* We cannot make this fatal. Sometimes this comes from magic
250 		   spaces our resource handlers simply don't know about */
251 		pr_warn("efifb: cannot reserve video memory at 0x%lx\n",
252 			efifb_fix.smem_start);
253 	}
254 
255 	info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
256 	if (!info) {
257 		pr_err("efifb: cannot allocate framebuffer\n");
258 		err = -ENOMEM;
259 		goto err_release_mem;
260 	}
261 	platform_set_drvdata(dev, info);
262 	info->pseudo_palette = info->par;
263 	info->par = NULL;
264 
265 	info->apertures = alloc_apertures(1);
266 	if (!info->apertures) {
267 		err = -ENOMEM;
268 		goto err_release_fb;
269 	}
270 	info->apertures->ranges[0].base = efifb_fix.smem_start;
271 	info->apertures->ranges[0].size = size_remap;
272 
273 	if (nowc)
274 		info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
275 	else
276 		info->screen_base = ioremap_wc(efifb_fix.smem_start, efifb_fix.smem_len);
277 	if (!info->screen_base) {
278 		pr_err("efifb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n",
279 			efifb_fix.smem_len, efifb_fix.smem_start);
280 		err = -EIO;
281 		goto err_release_fb;
282 	}
283 
284 	pr_info("efifb: framebuffer at 0x%lx, using %dk, total %dk\n",
285 	       efifb_fix.smem_start, size_remap/1024, size_total/1024);
286 	pr_info("efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
287 	       efifb_defined.xres, efifb_defined.yres,
288 	       efifb_defined.bits_per_pixel, efifb_fix.line_length,
289 	       screen_info.pages);
290 
291 	efifb_defined.xres_virtual = efifb_defined.xres;
292 	efifb_defined.yres_virtual = efifb_fix.smem_len /
293 					efifb_fix.line_length;
294 	pr_info("efifb: scrolling: redraw\n");
295 	efifb_defined.yres_virtual = efifb_defined.yres;
296 
297 	/* some dummy values for timing to make fbset happy */
298 	efifb_defined.pixclock     = 10000000 / efifb_defined.xres *
299 					1000 / efifb_defined.yres;
300 	efifb_defined.left_margin  = (efifb_defined.xres / 8) & 0xf8;
301 	efifb_defined.hsync_len    = (efifb_defined.xres / 8) & 0xf8;
302 
303 	efifb_defined.red.offset    = screen_info.red_pos;
304 	efifb_defined.red.length    = screen_info.red_size;
305 	efifb_defined.green.offset  = screen_info.green_pos;
306 	efifb_defined.green.length  = screen_info.green_size;
307 	efifb_defined.blue.offset   = screen_info.blue_pos;
308 	efifb_defined.blue.length   = screen_info.blue_size;
309 	efifb_defined.transp.offset = screen_info.rsvd_pos;
310 	efifb_defined.transp.length = screen_info.rsvd_size;
311 
312 	pr_info("efifb: %s: "
313 	       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
314 	       "Truecolor",
315 	       screen_info.rsvd_size,
316 	       screen_info.red_size,
317 	       screen_info.green_size,
318 	       screen_info.blue_size,
319 	       screen_info.rsvd_pos,
320 	       screen_info.red_pos,
321 	       screen_info.green_pos,
322 	       screen_info.blue_pos);
323 
324 	efifb_fix.ypanstep  = 0;
325 	efifb_fix.ywrapstep = 0;
326 
327 	info->fbops = &efifb_ops;
328 	info->var = efifb_defined;
329 	info->fix = efifb_fix;
330 	info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
331 
332 	err = sysfs_create_groups(&dev->dev.kobj, efifb_groups);
333 	if (err) {
334 		pr_err("efifb: cannot add sysfs attrs\n");
335 		goto err_unmap;
336 	}
337 	err = fb_alloc_cmap(&info->cmap, 256, 0);
338 	if (err < 0) {
339 		pr_err("efifb: cannot allocate colormap\n");
340 		goto err_groups;
341 	}
342 	err = register_framebuffer(info);
343 	if (err < 0) {
344 		pr_err("efifb: cannot register framebuffer\n");
345 		goto err_fb_dealoc;
346 	}
347 	fb_info(info, "%s frame buffer device\n", info->fix.id);
348 	return 0;
349 
350 err_fb_dealoc:
351 	fb_dealloc_cmap(&info->cmap);
352 err_groups:
353 	sysfs_remove_groups(&dev->dev.kobj, efifb_groups);
354 err_unmap:
355 	iounmap(info->screen_base);
356 err_release_fb:
357 	framebuffer_release(info);
358 err_release_mem:
359 	if (request_mem_succeeded)
360 		release_mem_region(efifb_fix.smem_start, size_total);
361 	return err;
362 }
363 
364 static int efifb_remove(struct platform_device *pdev)
365 {
366 	struct fb_info *info = platform_get_drvdata(pdev);
367 
368 	unregister_framebuffer(info);
369 	sysfs_remove_groups(&pdev->dev.kobj, efifb_groups);
370 	framebuffer_release(info);
371 
372 	return 0;
373 }
374 
375 static struct platform_driver efifb_driver = {
376 	.driver = {
377 		.name = "efi-framebuffer",
378 	},
379 	.probe = efifb_probe,
380 	.remove = efifb_remove,
381 };
382 
383 builtin_platform_driver(efifb_driver);
384 
385 #if defined(CONFIG_PCI)
386 
387 static void record_efifb_bar_resource(struct pci_dev *dev, int idx, u64 offset)
388 {
389 	u16 word;
390 
391 	efifb_pci_dev = dev;
392 
393 	pci_read_config_word(dev, PCI_COMMAND, &word);
394 	if (!(word & PCI_COMMAND_MEMORY)) {
395 		pci_dev_disabled = true;
396 		dev_err(&dev->dev,
397 			"BAR %d: assigned to efifb but device is disabled!\n",
398 			idx);
399 		return;
400 	}
401 
402 	bar_resource = &dev->resource[idx];
403 	bar_offset = offset;
404 
405 	dev_info(&dev->dev, "BAR %d: assigned to efifb\n", idx);
406 }
407 
408 static void efifb_fixup_resources(struct pci_dev *dev)
409 {
410 	u64 base = screen_info.lfb_base;
411 	u64 size = screen_info.lfb_size;
412 	int i;
413 
414 	if (efifb_pci_dev || screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
415 		return;
416 
417 	if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
418 		base |= (u64)screen_info.ext_lfb_base << 32;
419 
420 	if (!base)
421 		return;
422 
423 	for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
424 		struct resource *res = &dev->resource[i];
425 
426 		if (!(res->flags & IORESOURCE_MEM))
427 			continue;
428 
429 		if (res->start <= base && res->end >= base + size - 1) {
430 			record_efifb_bar_resource(dev, i, base - res->start);
431 			break;
432 		}
433 	}
434 }
435 DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY,
436 			       16, efifb_fixup_resources);
437 
438 #endif
439