0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/err.h>
0015 #include <linux/init.h>
0016 #include <linux/kernel.h>
0017 #include <linux/mm.h>
0018 #include <linux/platform_data/simplefb.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/screen_info.h>
0021 #include <linux/sysfb.h>
0022
0023 static const char simplefb_resname[] = "BOOTFB";
0024 static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
0025
0026
0027 __init bool sysfb_parse_mode(const struct screen_info *si,
0028 struct simplefb_platform_data *mode)
0029 {
0030 const struct simplefb_format *f;
0031 __u8 type;
0032 unsigned int i;
0033
0034 type = si->orig_video_isVGA;
0035 if (type != VIDEO_TYPE_VLFB && type != VIDEO_TYPE_EFI)
0036 return false;
0037
0038 for (i = 0; i < ARRAY_SIZE(formats); ++i) {
0039 f = &formats[i];
0040 if (si->lfb_depth == f->bits_per_pixel &&
0041 si->red_size == f->red.length &&
0042 si->red_pos == f->red.offset &&
0043 si->green_size == f->green.length &&
0044 si->green_pos == f->green.offset &&
0045 si->blue_size == f->blue.length &&
0046 si->blue_pos == f->blue.offset &&
0047 si->rsvd_size == f->transp.length &&
0048 si->rsvd_pos == f->transp.offset) {
0049 mode->format = f->name;
0050 mode->width = si->lfb_width;
0051 mode->height = si->lfb_height;
0052 mode->stride = si->lfb_linelength;
0053 return true;
0054 }
0055 }
0056
0057 return false;
0058 }
0059
0060 __init struct platform_device *sysfb_create_simplefb(const struct screen_info *si,
0061 const struct simplefb_platform_data *mode)
0062 {
0063 struct platform_device *pd;
0064 struct resource res;
0065 u64 base, size;
0066 u32 length;
0067 int ret;
0068
0069
0070
0071
0072
0073
0074 base = si->lfb_base;
0075 if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE)
0076 base |= (u64)si->ext_lfb_base << 32;
0077 if (!base || (u64)(resource_size_t)base != base) {
0078 printk(KERN_DEBUG "sysfb: inaccessible VRAM base\n");
0079 return ERR_PTR(-EINVAL);
0080 }
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090 size = si->lfb_size;
0091 if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
0092 size <<= 16;
0093 length = mode->height * mode->stride;
0094 if (length > size) {
0095 printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
0096 return ERR_PTR(-EINVAL);
0097 }
0098 length = PAGE_ALIGN(length);
0099
0100
0101 memset(&res, 0, sizeof(res));
0102 res.flags = IORESOURCE_MEM;
0103 res.name = simplefb_resname;
0104 res.start = base;
0105 res.end = res.start + length - 1;
0106 if (res.end <= res.start)
0107 return ERR_PTR(-EINVAL);
0108
0109 pd = platform_device_alloc("simple-framebuffer", 0);
0110 if (!pd)
0111 return ERR_PTR(-ENOMEM);
0112
0113 sysfb_apply_efi_quirks(pd);
0114
0115 ret = platform_device_add_resources(pd, &res, 1);
0116 if (ret)
0117 goto err_put_device;
0118
0119 ret = platform_device_add_data(pd, mode, sizeof(*mode));
0120 if (ret)
0121 goto err_put_device;
0122
0123 ret = platform_device_add(pd);
0124 if (ret)
0125 goto err_put_device;
0126
0127 return pd;
0128
0129 err_put_device:
0130 platform_device_put(pd);
0131
0132 return ERR_PTR(ret);
0133 }