2 * Copyright (C) 2007 Google, Inc.
3 * Copyright (C) 2012 Intel, Inc.
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/dma-mapping.h>
19 #include <linux/errno.h>
20 #include <linux/string.h>
21 #include <linux/slab.h>
22 #include <linux/delay.h>
25 #include <linux/init.h>
26 #include <linux/interrupt.h>
27 #include <linux/ioport.h>
28 #include <linux/platform_device.h>
36 FB_SET_ROTATION
= 0x14,
38 FB_GET_PHYS_WIDTH
= 0x1c,
39 FB_GET_PHYS_HEIGHT
= 0x20,
41 FB_INT_VSYNC
= 1U << 0,
42 FB_INT_BASE_UPDATE_DONE
= 1U << 1
46 void __iomem
*reg_base
;
49 wait_queue_head_t wait
;
50 int base_update_count
;
56 static irqreturn_t
goldfish_fb_interrupt(int irq
, void *dev_id
)
58 unsigned long irq_flags
;
59 struct goldfish_fb
*fb
= dev_id
;
62 spin_lock_irqsave(&fb
->lock
, irq_flags
);
63 status
= readl(fb
->reg_base
+ FB_INT_STATUS
);
64 if (status
& FB_INT_BASE_UPDATE_DONE
) {
65 fb
->base_update_count
++;
68 spin_unlock_irqrestore(&fb
->lock
, irq_flags
);
69 return status
? IRQ_HANDLED
: IRQ_NONE
;
72 static inline u32
convert_bitfield(int val
, struct fb_bitfield
*bf
)
74 unsigned int mask
= (1 << bf
->length
) - 1;
76 return (val
>> (16 - bf
->length
) & mask
) << bf
->offset
;
80 goldfish_fb_setcolreg(unsigned int regno
, unsigned int red
, unsigned int green
,
81 unsigned int blue
, unsigned int transp
, struct fb_info
*info
)
83 struct goldfish_fb
*fb
= container_of(info
, struct goldfish_fb
, fb
);
86 fb
->cmap
[regno
] = convert_bitfield(transp
, &fb
->fb
.var
.transp
) |
87 convert_bitfield(blue
, &fb
->fb
.var
.blue
) |
88 convert_bitfield(green
, &fb
->fb
.var
.green
) |
89 convert_bitfield(red
, &fb
->fb
.var
.red
);
96 static int goldfish_fb_check_var(struct fb_var_screeninfo
*var
,
99 if ((var
->rotate
& 1) != (info
->var
.rotate
& 1)) {
100 if ((var
->xres
!= info
->var
.yres
) ||
101 (var
->yres
!= info
->var
.xres
) ||
102 (var
->xres_virtual
!= info
->var
.yres
) ||
103 (var
->yres_virtual
> info
->var
.xres
* 2) ||
104 (var
->yres_virtual
< info
->var
.xres
)) {
108 if ((var
->xres
!= info
->var
.xres
) ||
109 (var
->yres
!= info
->var
.yres
) ||
110 (var
->xres_virtual
!= info
->var
.xres
) ||
111 (var
->yres_virtual
> info
->var
.yres
* 2) ||
112 (var
->yres_virtual
< info
->var
.yres
)) {
116 if ((var
->xoffset
!= info
->var
.xoffset
) ||
117 (var
->bits_per_pixel
!= info
->var
.bits_per_pixel
) ||
118 (var
->grayscale
!= info
->var
.grayscale
)) {
124 static int goldfish_fb_set_par(struct fb_info
*info
)
126 struct goldfish_fb
*fb
= container_of(info
, struct goldfish_fb
, fb
);
127 if (fb
->rotation
!= fb
->fb
.var
.rotate
) {
128 info
->fix
.line_length
= info
->var
.xres
* 2;
129 fb
->rotation
= fb
->fb
.var
.rotate
;
130 writel(fb
->rotation
, fb
->reg_base
+ FB_SET_ROTATION
);
136 static int goldfish_fb_pan_display(struct fb_var_screeninfo
*var
,
137 struct fb_info
*info
)
139 unsigned long irq_flags
;
140 int base_update_count
;
141 struct goldfish_fb
*fb
= container_of(info
, struct goldfish_fb
, fb
);
143 spin_lock_irqsave(&fb
->lock
, irq_flags
);
144 base_update_count
= fb
->base_update_count
;
145 writel(fb
->fb
.fix
.smem_start
+ fb
->fb
.var
.xres
* 2 * var
->yoffset
,
146 fb
->reg_base
+ FB_SET_BASE
);
147 spin_unlock_irqrestore(&fb
->lock
, irq_flags
);
148 wait_event_timeout(fb
->wait
,
149 fb
->base_update_count
!= base_update_count
, HZ
/ 15);
150 if (fb
->base_update_count
== base_update_count
)
151 pr_err("goldfish_fb_pan_display: timeout waiting for base update\n");
155 static int goldfish_fb_blank(int blank
, struct fb_info
*info
)
157 struct goldfish_fb
*fb
= container_of(info
, struct goldfish_fb
, fb
);
159 case FB_BLANK_NORMAL
:
160 writel(1, fb
->reg_base
+ FB_SET_BLANK
);
162 case FB_BLANK_UNBLANK
:
163 writel(0, fb
->reg_base
+ FB_SET_BLANK
);
169 static struct fb_ops goldfish_fb_ops
= {
170 .owner
= THIS_MODULE
,
171 .fb_check_var
= goldfish_fb_check_var
,
172 .fb_set_par
= goldfish_fb_set_par
,
173 .fb_setcolreg
= goldfish_fb_setcolreg
,
174 .fb_pan_display
= goldfish_fb_pan_display
,
175 .fb_blank
= goldfish_fb_blank
,
176 .fb_fillrect
= cfb_fillrect
,
177 .fb_copyarea
= cfb_copyarea
,
178 .fb_imageblit
= cfb_imageblit
,
182 static int goldfish_fb_probe(struct platform_device
*pdev
)
186 struct goldfish_fb
*fb
;
191 fb
= kzalloc(sizeof(*fb
), GFP_KERNEL
);
194 goto err_fb_alloc_failed
;
196 spin_lock_init(&fb
->lock
);
197 init_waitqueue_head(&fb
->wait
);
198 platform_set_drvdata(pdev
, fb
);
200 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
205 fb
->reg_base
= ioremap(r
->start
, PAGE_SIZE
);
206 if (fb
->reg_base
== NULL
) {
211 fb
->irq
= platform_get_irq(pdev
, 0);
217 width
= readl(fb
->reg_base
+ FB_GET_WIDTH
);
218 height
= readl(fb
->reg_base
+ FB_GET_HEIGHT
);
220 fb
->fb
.fbops
= &goldfish_fb_ops
;
221 fb
->fb
.flags
= FBINFO_FLAG_DEFAULT
;
222 fb
->fb
.pseudo_palette
= fb
->cmap
;
223 fb
->fb
.fix
.type
= FB_TYPE_PACKED_PIXELS
;
224 fb
->fb
.fix
.visual
= FB_VISUAL_TRUECOLOR
;
225 fb
->fb
.fix
.line_length
= width
* 2;
226 fb
->fb
.fix
.accel
= FB_ACCEL_NONE
;
227 fb
->fb
.fix
.ypanstep
= 1;
229 fb
->fb
.var
.xres
= width
;
230 fb
->fb
.var
.yres
= height
;
231 fb
->fb
.var
.xres_virtual
= width
;
232 fb
->fb
.var
.yres_virtual
= height
* 2;
233 fb
->fb
.var
.bits_per_pixel
= 16;
234 fb
->fb
.var
.activate
= FB_ACTIVATE_NOW
;
235 fb
->fb
.var
.height
= readl(fb
->reg_base
+ FB_GET_PHYS_HEIGHT
);
236 fb
->fb
.var
.width
= readl(fb
->reg_base
+ FB_GET_PHYS_WIDTH
);
237 fb
->fb
.var
.pixclock
= 10000;
239 fb
->fb
.var
.red
.offset
= 11;
240 fb
->fb
.var
.red
.length
= 5;
241 fb
->fb
.var
.green
.offset
= 5;
242 fb
->fb
.var
.green
.length
= 6;
243 fb
->fb
.var
.blue
.offset
= 0;
244 fb
->fb
.var
.blue
.length
= 5;
246 framesize
= width
* height
* 2 * 2;
247 fb
->fb
.screen_base
= (char __force __iomem
*)dma_alloc_coherent(
248 &pdev
->dev
, framesize
,
249 &fbpaddr
, GFP_KERNEL
);
250 pr_debug("allocating frame buffer %d * %d, got %p\n",
251 width
, height
, fb
->fb
.screen_base
);
252 if (fb
->fb
.screen_base
== NULL
) {
254 goto err_alloc_screen_base_failed
;
256 fb
->fb
.fix
.smem_start
= fbpaddr
;
257 fb
->fb
.fix
.smem_len
= framesize
;
259 ret
= fb_set_var(&fb
->fb
, &fb
->fb
.var
);
261 goto err_fb_set_var_failed
;
263 ret
= request_irq(fb
->irq
, goldfish_fb_interrupt
, IRQF_SHARED
,
266 goto err_request_irq_failed
;
268 writel(FB_INT_BASE_UPDATE_DONE
, fb
->reg_base
+ FB_INT_ENABLE
);
269 goldfish_fb_pan_display(&fb
->fb
.var
, &fb
->fb
); /* updates base */
271 ret
= register_framebuffer(&fb
->fb
);
273 goto err_register_framebuffer_failed
;
276 err_register_framebuffer_failed
:
277 free_irq(fb
->irq
, fb
);
278 err_request_irq_failed
:
279 err_fb_set_var_failed
:
280 dma_free_coherent(&pdev
->dev
, framesize
,
281 (void *)fb
->fb
.screen_base
,
282 fb
->fb
.fix
.smem_start
);
283 err_alloc_screen_base_failed
:
285 iounmap(fb
->reg_base
);
292 static int goldfish_fb_remove(struct platform_device
*pdev
)
295 struct goldfish_fb
*fb
= platform_get_drvdata(pdev
);
297 framesize
= fb
->fb
.var
.xres_virtual
* fb
->fb
.var
.yres_virtual
* 2;
298 unregister_framebuffer(&fb
->fb
);
299 free_irq(fb
->irq
, fb
);
301 dma_free_coherent(&pdev
->dev
, framesize
, (void *)fb
->fb
.screen_base
,
302 fb
->fb
.fix
.smem_start
);
303 iounmap(fb
->reg_base
);
308 static const struct of_device_id goldfish_fb_of_match
[] = {
309 { .compatible
= "google,goldfish-fb", },
312 MODULE_DEVICE_TABLE(of
, goldfish_fb_of_match
);
314 static struct platform_driver goldfish_fb_driver
= {
315 .probe
= goldfish_fb_probe
,
316 .remove
= goldfish_fb_remove
,
318 .name
= "goldfish_fb",
319 .of_match_table
= goldfish_fb_of_match
,
323 module_platform_driver(goldfish_fb_driver
);
325 MODULE_LICENSE("GPL v2");