aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/simplefb.c
diff options
context:
space:
mode:
authorStephen Warren <swarren@wwwdotorg.org>2013-05-24 18:55:13 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-24 19:22:51 -0400
commit26549c8d36a64d9130e4c0f32412be7ba6180923 (patch)
treea2b08793316a95ded04ea90fd6aabaa2d5dc9236 /drivers/video/simplefb.c
parentafe1bb73f8ed588ab6268c27c5a447fe0484e48f (diff)
drivers/video: implement a simple framebuffer driver
A simple frame-buffer describes a raw memory region that may be rendered to, with the assumption that the display hardware has already been set up to scan out from that buffer. This is useful in cases where a bootloader exists and has set up the display hardware, but a Linux driver doesn't yet exist for the display hardware. Examples use-cases include: * The built-in LCD panels on the Samsung ARM chromebook, and Tegra devices, and likely many other ARM or embedded systems. These cannot yet be supported using a full graphics driver, since the panel control should be provided by the CDF (Common Display Framework), which has been stuck in design/review for quite some time. One could support these panels using custom SoC-specific code, but there is a desire to use common infra-structure rather than having each SoC vendor invent their own code, hence the desire to wait for CDF. * Hardware for which a full graphics driver is not yet available, and the path to obtain one upstream isn't yet clear. For example, the Raspberry Pi. * Any hardware in early stages of upstreaming, before a full graphics driver has been tackled. This driver can provide a graphical boot console (even full X support) much earlier in the upstreaming process, thus making new SoC or board support more generally useful earlier. [akpm@linux-foundation.org: make simplefb_formats[] static] Signed-off-by: Stephen Warren <swarren@wwwdotorg.org> Cc: Arnd Bergmann <arnd@arndb.de> Acked-by: Olof Johansson <olof@lixom.net> Cc: Rob Clark <robclark@gmail.com> Cc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de> Cc: Tomasz Figa <tomasz.figa@gmail.com> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/simplefb.c')
-rw-r--r--drivers/video/simplefb.c234
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
29static 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
36static struct fb_var_screeninfo simplefb_var = {
37 .height = -1,
38 .width = -1,
39 .activate = FB_ACTIVATE_NOW,
40 .vmode = FB_VMODE_NONINTERLACED,
41};
42
43static 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
68static 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
76struct 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
85static struct simplefb_format simplefb_formats[] = {
86 { "r5g6b5", 16, {11, 5}, {5, 6}, {0, 5}, {0, 0} },
87};
88
89struct simplefb_params {
90 u32 width;
91 u32 height;
92 u32 stride;
93 struct simplefb_format *format;
94};
95
96static 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", &params->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", &params->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", &params->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
142static 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, &params);
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
205static 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
215static const struct of_device_id simplefb_of_match[] = {
216 { .compatible = "simple-framebuffer", },
217 { },
218};
219MODULE_DEVICE_TABLE(of, simplefb_of_match);
220
221static 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};
230module_platform_driver(simplefb_driver);
231
232MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>");
233MODULE_DESCRIPTION("Simple framebuffer driver");
234MODULE_LICENSE("GPL v2");