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