diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-05-26 21:40:19 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-05-26 21:40:19 -0400 |
commit | f35c69b736e4f910d7447346980145212c283570 (patch) | |
tree | 824b90cd870e6de07bbba19d761c1c74cf1fb4a7 /drivers/video/simplefb.c | |
parent | cd4373984a5903276f52777a6003425e023eaa7e (diff) | |
parent | e4aa937ec75df0eea0bee03bffa3303ad36c986b (diff) |
Merge 3.10-rc3 into char-misc-next
We want the changes in here.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/video/simplefb.c')
-rw-r--r-- | drivers/video/simplefb.c | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c new file mode 100644 index 000000000000..e2e9e3e61b72 --- /dev/null +++ b/drivers/video/simplefb.c | |||
@@ -0,0 +1,234 @@ | |||
1 | /* | ||
2 | * Simplest possible simple frame-buffer driver, as a platform device | ||
3 | * | ||
4 | * Copyright (c) 2013, Stephen Warren | ||
5 | * | ||
6 | * Based on q40fb.c, which was: | ||
7 | * Copyright (C) 2001 Richard Zidlicky <rz@linux-m68k.org> | ||
8 | * | ||
9 | * Also based on offb.c, which was: | ||
10 | * Copyright (C) 1997 Geert Uytterhoeven | ||
11 | * Copyright (C) 1996 Paul Mackerras | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms and conditions of the GNU General Public License, | ||
15 | * version 2, as published by the Free Software Foundation. | ||
16 | * | ||
17 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
20 | * more details. | ||
21 | */ | ||
22 | |||
23 | #include <linux/errno.h> | ||
24 | #include <linux/fb.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | |||
29 | static struct fb_fix_screeninfo simplefb_fix = { | ||
30 | .id = "simple", | ||
31 | .type = FB_TYPE_PACKED_PIXELS, | ||
32 | .visual = FB_VISUAL_TRUECOLOR, | ||
33 | .accel = FB_ACCEL_NONE, | ||
34 | }; | ||
35 | |||
36 | static struct fb_var_screeninfo simplefb_var = { | ||
37 | .height = -1, | ||
38 | .width = -1, | ||
39 | .activate = FB_ACTIVATE_NOW, | ||
40 | .vmode = FB_VMODE_NONINTERLACED, | ||
41 | }; | ||
42 | |||
43 | static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | ||
44 | u_int transp, struct fb_info *info) | ||
45 | { | ||
46 | u32 *pal = info->pseudo_palette; | ||
47 | u32 cr = red >> (16 - info->var.red.length); | ||
48 | u32 cg = green >> (16 - info->var.green.length); | ||
49 | u32 cb = blue >> (16 - info->var.blue.length); | ||
50 | u32 value; | ||
51 | |||
52 | if (regno >= 16) | ||
53 | return -EINVAL; | ||
54 | |||
55 | value = (cr << info->var.red.offset) | | ||
56 | (cg << info->var.green.offset) | | ||
57 | (cb << info->var.blue.offset); | ||
58 | if (info->var.transp.length > 0) { | ||
59 | u32 mask = (1 << info->var.transp.length) - 1; | ||
60 | mask <<= info->var.transp.offset; | ||
61 | value |= mask; | ||
62 | } | ||
63 | pal[regno] = value; | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static struct fb_ops simplefb_ops = { | ||
69 | .owner = THIS_MODULE, | ||
70 | .fb_setcolreg = simplefb_setcolreg, | ||
71 | .fb_fillrect = cfb_fillrect, | ||
72 | .fb_copyarea = cfb_copyarea, | ||
73 | .fb_imageblit = cfb_imageblit, | ||
74 | }; | ||
75 | |||
76 | struct simplefb_format { | ||
77 | const char *name; | ||
78 | u32 bits_per_pixel; | ||
79 | struct fb_bitfield red; | ||
80 | struct fb_bitfield green; | ||
81 | struct fb_bitfield blue; | ||
82 | struct fb_bitfield transp; | ||
83 | }; | ||
84 | |||
85 | static struct simplefb_format simplefb_formats[] = { | ||
86 | { "r5g6b5", 16, {11, 5}, {5, 6}, {0, 5}, {0, 0} }, | ||
87 | }; | ||
88 | |||
89 | struct simplefb_params { | ||
90 | u32 width; | ||
91 | u32 height; | ||
92 | u32 stride; | ||
93 | struct simplefb_format *format; | ||
94 | }; | ||
95 | |||
96 | static int simplefb_parse_dt(struct platform_device *pdev, | ||
97 | struct simplefb_params *params) | ||
98 | { | ||
99 | struct device_node *np = pdev->dev.of_node; | ||
100 | int ret; | ||
101 | const char *format; | ||
102 | int i; | ||
103 | |||
104 | ret = of_property_read_u32(np, "width", ¶ms->width); | ||
105 | if (ret) { | ||
106 | dev_err(&pdev->dev, "Can't parse width property\n"); | ||
107 | return ret; | ||
108 | } | ||
109 | |||
110 | ret = of_property_read_u32(np, "height", ¶ms->height); | ||
111 | if (ret) { | ||
112 | dev_err(&pdev->dev, "Can't parse height property\n"); | ||
113 | return ret; | ||
114 | } | ||
115 | |||
116 | ret = of_property_read_u32(np, "stride", ¶ms->stride); | ||
117 | if (ret) { | ||
118 | dev_err(&pdev->dev, "Can't parse stride property\n"); | ||
119 | return ret; | ||
120 | } | ||
121 | |||
122 | ret = of_property_read_string(np, "format", &format); | ||
123 | if (ret) { | ||
124 | dev_err(&pdev->dev, "Can't parse format property\n"); | ||
125 | return ret; | ||
126 | } | ||
127 | params->format = NULL; | ||
128 | for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) { | ||
129 | if (strcmp(format, simplefb_formats[i].name)) | ||
130 | continue; | ||
131 | params->format = &simplefb_formats[i]; | ||
132 | break; | ||
133 | } | ||
134 | if (!params->format) { | ||
135 | dev_err(&pdev->dev, "Invalid format value\n"); | ||
136 | return -EINVAL; | ||
137 | } | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int simplefb_probe(struct platform_device *pdev) | ||
143 | { | ||
144 | int ret; | ||
145 | struct simplefb_params params; | ||
146 | struct fb_info *info; | ||
147 | struct resource *mem; | ||
148 | |||
149 | if (fb_get_options("simplefb", NULL)) | ||
150 | return -ENODEV; | ||
151 | |||
152 | ret = simplefb_parse_dt(pdev, ¶ms); | ||
153 | if (ret) | ||
154 | return ret; | ||
155 | |||
156 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
157 | if (!mem) { | ||
158 | dev_err(&pdev->dev, "No memory resource\n"); | ||
159 | return -EINVAL; | ||
160 | } | ||
161 | |||
162 | info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev); | ||
163 | if (!info) | ||
164 | return -ENOMEM; | ||
165 | platform_set_drvdata(pdev, info); | ||
166 | |||
167 | info->fix = simplefb_fix; | ||
168 | info->fix.smem_start = mem->start; | ||
169 | info->fix.smem_len = resource_size(mem); | ||
170 | info->fix.line_length = params.stride; | ||
171 | |||
172 | info->var = simplefb_var; | ||
173 | info->var.xres = params.width; | ||
174 | info->var.yres = params.height; | ||
175 | info->var.xres_virtual = params.width; | ||
176 | info->var.yres_virtual = params.height; | ||
177 | info->var.bits_per_pixel = params.format->bits_per_pixel; | ||
178 | info->var.red = params.format->red; | ||
179 | info->var.green = params.format->green; | ||
180 | info->var.blue = params.format->blue; | ||
181 | info->var.transp = params.format->transp; | ||
182 | |||
183 | info->fbops = &simplefb_ops; | ||
184 | info->flags = FBINFO_DEFAULT; | ||
185 | info->screen_base = devm_ioremap(&pdev->dev, info->fix.smem_start, | ||
186 | info->fix.smem_len); | ||
187 | if (!info->screen_base) { | ||
188 | framebuffer_release(info); | ||
189 | return -ENODEV; | ||
190 | } | ||
191 | info->pseudo_palette = (void *)(info + 1); | ||
192 | |||
193 | ret = register_framebuffer(info); | ||
194 | if (ret < 0) { | ||
195 | dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret); | ||
196 | framebuffer_release(info); | ||
197 | return ret; | ||
198 | } | ||
199 | |||
200 | dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int simplefb_remove(struct platform_device *pdev) | ||
206 | { | ||
207 | struct fb_info *info = platform_get_drvdata(pdev); | ||
208 | |||
209 | unregister_framebuffer(info); | ||
210 | framebuffer_release(info); | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static const struct of_device_id simplefb_of_match[] = { | ||
216 | { .compatible = "simple-framebuffer", }, | ||
217 | { }, | ||
218 | }; | ||
219 | MODULE_DEVICE_TABLE(of, simplefb_of_match); | ||
220 | |||
221 | static struct platform_driver simplefb_driver = { | ||
222 | .driver = { | ||
223 | .name = "simple-framebuffer", | ||
224 | .owner = THIS_MODULE, | ||
225 | .of_match_table = simplefb_of_match, | ||
226 | }, | ||
227 | .probe = simplefb_probe, | ||
228 | .remove = simplefb_remove, | ||
229 | }; | ||
230 | module_platform_driver(simplefb_driver); | ||
231 | |||
232 | MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>"); | ||
233 | MODULE_DESCRIPTION("Simple framebuffer driver"); | ||
234 | MODULE_LICENSE("GPL v2"); | ||