soc: Introduce drivers/soc place-holder for SOC specific drivers
[deliverable/linux.git] / drivers / video / simplefb.c
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_data/simplefb.h>
28 #include <linux/platform_device.h>
29
30 static struct fb_fix_screeninfo simplefb_fix = {
31 .id = "simple",
32 .type = FB_TYPE_PACKED_PIXELS,
33 .visual = FB_VISUAL_TRUECOLOR,
34 .accel = FB_ACCEL_NONE,
35 };
36
37 static struct fb_var_screeninfo simplefb_var = {
38 .height = -1,
39 .width = -1,
40 .activate = FB_ACTIVATE_NOW,
41 .vmode = FB_VMODE_NONINTERLACED,
42 };
43
44 static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
45 u_int transp, struct fb_info *info)
46 {
47 u32 *pal = info->pseudo_palette;
48 u32 cr = red >> (16 - info->var.red.length);
49 u32 cg = green >> (16 - info->var.green.length);
50 u32 cb = blue >> (16 - info->var.blue.length);
51 u32 value;
52
53 if (regno >= 16)
54 return -EINVAL;
55
56 value = (cr << info->var.red.offset) |
57 (cg << info->var.green.offset) |
58 (cb << info->var.blue.offset);
59 if (info->var.transp.length > 0) {
60 u32 mask = (1 << info->var.transp.length) - 1;
61 mask <<= info->var.transp.offset;
62 value |= mask;
63 }
64 pal[regno] = value;
65
66 return 0;
67 }
68
69 static void simplefb_destroy(struct fb_info *info)
70 {
71 if (info->screen_base)
72 iounmap(info->screen_base);
73 }
74
75 static struct fb_ops simplefb_ops = {
76 .owner = THIS_MODULE,
77 .fb_destroy = simplefb_destroy,
78 .fb_setcolreg = simplefb_setcolreg,
79 .fb_fillrect = cfb_fillrect,
80 .fb_copyarea = cfb_copyarea,
81 .fb_imageblit = cfb_imageblit,
82 };
83
84 static struct simplefb_format simplefb_formats[] = SIMPLEFB_FORMATS;
85
86 struct simplefb_params {
87 u32 width;
88 u32 height;
89 u32 stride;
90 struct simplefb_format *format;
91 };
92
93 static int simplefb_parse_dt(struct platform_device *pdev,
94 struct simplefb_params *params)
95 {
96 struct device_node *np = pdev->dev.of_node;
97 int ret;
98 const char *format;
99 int i;
100
101 ret = of_property_read_u32(np, "width", &params->width);
102 if (ret) {
103 dev_err(&pdev->dev, "Can't parse width property\n");
104 return ret;
105 }
106
107 ret = of_property_read_u32(np, "height", &params->height);
108 if (ret) {
109 dev_err(&pdev->dev, "Can't parse height property\n");
110 return ret;
111 }
112
113 ret = of_property_read_u32(np, "stride", &params->stride);
114 if (ret) {
115 dev_err(&pdev->dev, "Can't parse stride property\n");
116 return ret;
117 }
118
119 ret = of_property_read_string(np, "format", &format);
120 if (ret) {
121 dev_err(&pdev->dev, "Can't parse format property\n");
122 return ret;
123 }
124 params->format = NULL;
125 for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) {
126 if (strcmp(format, simplefb_formats[i].name))
127 continue;
128 params->format = &simplefb_formats[i];
129 break;
130 }
131 if (!params->format) {
132 dev_err(&pdev->dev, "Invalid format value\n");
133 return -EINVAL;
134 }
135
136 return 0;
137 }
138
139 static int simplefb_parse_pd(struct platform_device *pdev,
140 struct simplefb_params *params)
141 {
142 struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev);
143 int i;
144
145 params->width = pd->width;
146 params->height = pd->height;
147 params->stride = pd->stride;
148
149 params->format = NULL;
150 for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) {
151 if (strcmp(pd->format, simplefb_formats[i].name))
152 continue;
153
154 params->format = &simplefb_formats[i];
155 break;
156 }
157
158 if (!params->format) {
159 dev_err(&pdev->dev, "Invalid format value\n");
160 return -EINVAL;
161 }
162
163 return 0;
164 }
165
166 static int simplefb_probe(struct platform_device *pdev)
167 {
168 int ret;
169 struct simplefb_params params;
170 struct fb_info *info;
171 struct resource *mem;
172
173 if (fb_get_options("simplefb", NULL))
174 return -ENODEV;
175
176 ret = -ENODEV;
177 if (dev_get_platdata(&pdev->dev))
178 ret = simplefb_parse_pd(pdev, &params);
179 else if (pdev->dev.of_node)
180 ret = simplefb_parse_dt(pdev, &params);
181
182 if (ret)
183 return ret;
184
185 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
186 if (!mem) {
187 dev_err(&pdev->dev, "No memory resource\n");
188 return -EINVAL;
189 }
190
191 info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev);
192 if (!info)
193 return -ENOMEM;
194 platform_set_drvdata(pdev, info);
195
196 info->fix = simplefb_fix;
197 info->fix.smem_start = mem->start;
198 info->fix.smem_len = resource_size(mem);
199 info->fix.line_length = params.stride;
200
201 info->var = simplefb_var;
202 info->var.xres = params.width;
203 info->var.yres = params.height;
204 info->var.xres_virtual = params.width;
205 info->var.yres_virtual = params.height;
206 info->var.bits_per_pixel = params.format->bits_per_pixel;
207 info->var.red = params.format->red;
208 info->var.green = params.format->green;
209 info->var.blue = params.format->blue;
210 info->var.transp = params.format->transp;
211
212 info->apertures = alloc_apertures(1);
213 if (!info->apertures) {
214 framebuffer_release(info);
215 return -ENOMEM;
216 }
217 info->apertures->ranges[0].base = info->fix.smem_start;
218 info->apertures->ranges[0].size = info->fix.smem_len;
219
220 info->fbops = &simplefb_ops;
221 info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE;
222 info->screen_base = ioremap_wc(info->fix.smem_start,
223 info->fix.smem_len);
224 if (!info->screen_base) {
225 framebuffer_release(info);
226 return -ENODEV;
227 }
228 info->pseudo_palette = (void *)(info + 1);
229
230 dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n",
231 info->fix.smem_start, info->fix.smem_len,
232 info->screen_base);
233 dev_info(&pdev->dev, "format=%s, mode=%dx%dx%d, linelength=%d\n",
234 params.format->name,
235 info->var.xres, info->var.yres,
236 info->var.bits_per_pixel, info->fix.line_length);
237
238 ret = register_framebuffer(info);
239 if (ret < 0) {
240 dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);
241 iounmap(info->screen_base);
242 framebuffer_release(info);
243 return ret;
244 }
245
246 dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node);
247
248 return 0;
249 }
250
251 static int simplefb_remove(struct platform_device *pdev)
252 {
253 struct fb_info *info = platform_get_drvdata(pdev);
254
255 unregister_framebuffer(info);
256 framebuffer_release(info);
257
258 return 0;
259 }
260
261 static const struct of_device_id simplefb_of_match[] = {
262 { .compatible = "simple-framebuffer", },
263 { },
264 };
265 MODULE_DEVICE_TABLE(of, simplefb_of_match);
266
267 static struct platform_driver simplefb_driver = {
268 .driver = {
269 .name = "simple-framebuffer",
270 .owner = THIS_MODULE,
271 .of_match_table = simplefb_of_match,
272 },
273 .probe = simplefb_probe,
274 .remove = simplefb_remove,
275 };
276 module_platform_driver(simplefb_driver);
277
278 MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>");
279 MODULE_DESCRIPTION("Simple framebuffer driver");
280 MODULE_LICENSE("GPL v2");
This page took 0.043879 seconds and 5 git commands to generate.