2 * Simplest possible simple frame-buffer driver, as a platform device
4 * Copyright (c) 2013, Stephen Warren
6 * Based on q40fb.c, which was:
7 * Copyright (C) 2001 Richard Zidlicky <rz@linux-m68k.org>
9 * Also based on offb.c, which was:
10 * Copyright (C) 1997 Geert Uytterhoeven
11 * Copyright (C) 1996 Paul Mackerras
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.
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
23 #include <linux/errno.h>
26 #include <linux/module.h>
27 #include <linux/platform_data/simplefb.h>
28 #include <linux/platform_device.h>
30 static struct fb_fix_screeninfo simplefb_fix
= {
32 .type
= FB_TYPE_PACKED_PIXELS
,
33 .visual
= FB_VISUAL_TRUECOLOR
,
34 .accel
= FB_ACCEL_NONE
,
37 static struct fb_var_screeninfo simplefb_var
= {
40 .activate
= FB_ACTIVATE_NOW
,
41 .vmode
= FB_VMODE_NONINTERLACED
,
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
)
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
);
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
;
69 static void simplefb_destroy(struct fb_info
*info
)
71 if (info
->screen_base
)
72 iounmap(info
->screen_base
);
75 static struct fb_ops simplefb_ops
= {
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
,
84 static struct simplefb_format simplefb_formats
[] = SIMPLEFB_FORMATS
;
86 struct simplefb_params
{
90 struct simplefb_format
*format
;
93 static int simplefb_parse_dt(struct platform_device
*pdev
,
94 struct simplefb_params
*params
)
96 struct device_node
*np
= pdev
->dev
.of_node
;
101 ret
= of_property_read_u32(np
, "width", ¶ms
->width
);
103 dev_err(&pdev
->dev
, "Can't parse width property\n");
107 ret
= of_property_read_u32(np
, "height", ¶ms
->height
);
109 dev_err(&pdev
->dev
, "Can't parse height property\n");
113 ret
= of_property_read_u32(np
, "stride", ¶ms
->stride
);
115 dev_err(&pdev
->dev
, "Can't parse stride property\n");
119 ret
= of_property_read_string(np
, "format", &format
);
121 dev_err(&pdev
->dev
, "Can't parse format property\n");
124 params
->format
= NULL
;
125 for (i
= 0; i
< ARRAY_SIZE(simplefb_formats
); i
++) {
126 if (strcmp(format
, simplefb_formats
[i
].name
))
128 params
->format
= &simplefb_formats
[i
];
131 if (!params
->format
) {
132 dev_err(&pdev
->dev
, "Invalid format value\n");
139 static int simplefb_parse_pd(struct platform_device
*pdev
,
140 struct simplefb_params
*params
)
142 struct simplefb_platform_data
*pd
= dev_get_platdata(&pdev
->dev
);
145 params
->width
= pd
->width
;
146 params
->height
= pd
->height
;
147 params
->stride
= pd
->stride
;
149 params
->format
= NULL
;
150 for (i
= 0; i
< ARRAY_SIZE(simplefb_formats
); i
++) {
151 if (strcmp(pd
->format
, simplefb_formats
[i
].name
))
154 params
->format
= &simplefb_formats
[i
];
158 if (!params
->format
) {
159 dev_err(&pdev
->dev
, "Invalid format value\n");
166 static int simplefb_probe(struct platform_device
*pdev
)
169 struct simplefb_params params
;
170 struct fb_info
*info
;
171 struct resource
*mem
;
173 if (fb_get_options("simplefb", NULL
))
177 if (dev_get_platdata(&pdev
->dev
))
178 ret
= simplefb_parse_pd(pdev
, ¶ms
);
179 else if (pdev
->dev
.of_node
)
180 ret
= simplefb_parse_dt(pdev
, ¶ms
);
185 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
187 dev_err(&pdev
->dev
, "No memory resource\n");
191 info
= framebuffer_alloc(sizeof(u32
) * 16, &pdev
->dev
);
194 platform_set_drvdata(pdev
, info
);
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
;
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
;
212 info
->apertures
= alloc_apertures(1);
213 if (!info
->apertures
) {
214 framebuffer_release(info
);
217 info
->apertures
->ranges
[0].base
= info
->fix
.smem_start
;
218 info
->apertures
->ranges
[0].size
= info
->fix
.smem_len
;
220 info
->fbops
= &simplefb_ops
;
221 info
->flags
= FBINFO_DEFAULT
| FBINFO_MISC_FIRMWARE
;
222 info
->screen_base
= ioremap_wc(info
->fix
.smem_start
,
224 if (!info
->screen_base
) {
225 framebuffer_release(info
);
228 info
->pseudo_palette
= (void *)(info
+ 1);
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
,
233 dev_info(&pdev
->dev
, "format=%s, mode=%dx%dx%d, linelength=%d\n",
235 info
->var
.xres
, info
->var
.yres
,
236 info
->var
.bits_per_pixel
, info
->fix
.line_length
);
238 ret
= register_framebuffer(info
);
240 dev_err(&pdev
->dev
, "Unable to register simplefb: %d\n", ret
);
241 iounmap(info
->screen_base
);
242 framebuffer_release(info
);
246 dev_info(&pdev
->dev
, "fb%d: simplefb registered!\n", info
->node
);
251 static int simplefb_remove(struct platform_device
*pdev
)
253 struct fb_info
*info
= platform_get_drvdata(pdev
);
255 unregister_framebuffer(info
);
256 framebuffer_release(info
);
261 static const struct of_device_id simplefb_of_match
[] = {
262 { .compatible
= "simple-framebuffer", },
265 MODULE_DEVICE_TABLE(of
, simplefb_of_match
);
267 static struct platform_driver simplefb_driver
= {
269 .name
= "simple-framebuffer",
270 .owner
= THIS_MODULE
,
271 .of_match_table
= simplefb_of_match
,
273 .probe
= simplefb_probe
,
274 .remove
= simplefb_remove
,
276 module_platform_driver(simplefb_driver
);
278 MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>");
279 MODULE_DESCRIPTION("Simple framebuffer driver");
280 MODULE_LICENSE("GPL v2");