blob: 221004379c754b4b370bda1099177b64a1adc76c [file] [log] [blame]
Liviu Dudaucaf003f2012-01-18 16:52:04 +00001/*
2 * drivers/video/arm-hdlcd.c
3 *
4 * Copyright (C) 2011 ARM Limited
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 *
10 * ARM HDLCD Controller
11 */
12
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/errno.h>
16#include <linux/string.h>
17#include <linux/ctype.h>
18#include <linux/mm.h>
19#include <linux/delay.h>
20#include <linux/of.h>
21#include <linux/fb.h>
22#include <linux/clk.h>
23#include <linux/init.h>
24#include <linux/ioport.h>
25#include <linux/dma-mapping.h>
26#include <linux/platform_device.h>
27#include <linux/memblock.h>
28#include <linux/arm-hdlcd.h>
29
30#include "edid.h"
31
32#ifdef CONFIG_SERIAL_AMBA_PCU_UART
33/* set the DVI output mode using the firmware */
34int set_dvi_mode(u8 *msgbuf);
35int get_edid(u8 *msgbuf);
36#endif
37
38#define to_hdlcd_device(info) container_of(info, struct hdlcd_device, fb)
39
40static struct of_device_id hdlcd_of_matches[] = {
41 { .compatible = "arm,hdlcd" },
42 {},
43};
44
45/* Framebuffer size. */
46static unsigned long framebuffer_size;
47
48static char *fb_mode = "1680x1050-32@60\0\0\0\0\0";
49
50static struct fb_var_screeninfo cached_var_screeninfo;
51
52static struct fb_videomode hdlcd_default_mode = {
53 .refresh = 60,
54 .xres = 1680,
55 .yres = 1050,
56 .pixclock = 8403,
57 .left_margin = 80,
58 .right_margin = 48,
59 .upper_margin = 21,
60 .lower_margin = 3,
61 .hsync_len = 32,
62 .vsync_len = 6,
63 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
64 .vmode = FB_VMODE_NONINTERLACED
65};
66
67
68static inline void hdlcd_enable(struct hdlcd_device *hdlcd)
69{
70 dev_dbg(hdlcd->dev, "HDLCD: output enabled\n");
71 writel(1, hdlcd->base + HDLCD_REG_COMMAND);
72}
73
74static inline void hdlcd_disable(struct hdlcd_device *hdlcd)
75{
76 dev_dbg(hdlcd->dev, "HDLCD: output disabled\n");
77 writel(0, hdlcd->base + HDLCD_REG_COMMAND);
78}
79
80static int hdlcd_set_bitfields(struct hdlcd_device *hdlcd,
81 struct fb_var_screeninfo *var)
82{
83 int ret = 0;
84
85 memset(&var->transp, 0, sizeof(var->transp));
86 var->red.msb_right = 0;
87 var->green.msb_right = 0;
88 var->blue.msb_right = 0;
89 var->blue.offset = 0;
90
91 switch (var->bits_per_pixel) {
92 case 8:
93 /* pseudocolor */
94 var->red.length = 8;
95 var->green.length = 8;
96 var->blue.length = 8;
97 break;
98 case 16:
99 /* 565 format */
100 var->red.length = 5;
101 var->green.length = 6;
102 var->blue.length = 5;
103 break;
104 case 32:
105 var->transp.length = 8;
106 case 24:
107 var->red.length = 8;
108 var->green.length = 8;
109 var->blue.length = 8;
110 break;
111 default:
112 ret = -EINVAL;
113 break;
114 }
115
116 if (!ret) {
117 var->green.offset = var->blue.length;
118 var->red.offset = var->green.offset + var->green.length;
119 if (var->bits_per_pixel == 32)
120 var->transp.offset = var->red.offset + var->red.length;
121 }
122
123 return ret;
124}
125
126static int hdlcd_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
127{
128 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
129 int bytes_per_pixel = var->bits_per_pixel / 8;
130
131 var->yres_virtual = 2 * var->yres;
132
133 if ((var->xres_virtual * bytes_per_pixel * var->yres_virtual) > hdlcd->fb.fix.smem_len)
134 return -ENOMEM;
135
136 if (var->xres > HDLCD_MAX_XRES || var->yres > HDLCD_MAX_YRES)
137 return -EINVAL;
138
139 /* make sure the bitfields are set appropriately */
140 return hdlcd_set_bitfields(hdlcd, var);
141}
142
143#ifdef CONFIG_SERIAL_AMBA_PCU_UART
144static int hdlcd_set_output_mode(int xres, int yres)
145{
146 /* firmware uses some stupid protocol: 5 bytes (only byte 1 used)
147 to send 3 bits of information (value between 0 - 5) */
148 u8 msgbuffer[5];
149
150 memset(msgbuffer, 0, sizeof(msgbuffer));
151 /* default resolution: 640 x 480 */
152 if (xres == 800 && yres <= 600)
153 msgbuffer[0] = 1; /* SVGA: 800 * 600 */
154 else if (xres == 1024 && yres <= 768)
155 msgbuffer[0] = 2; /* XGA: 1024 * 768 */
156 else if (xres == 1280 && yres <= 1024)
157 msgbuffer[0] = 3; /* SXGA: 1280 * 1024 */
158 else if (xres == 1600 && yres <= 1200)
159 msgbuffer[0] = 4; /* UXGA: 1600 * 1200 */
160 else if (xres == 1920 && yres <= 1200)
161 msgbuffer[0] = 5; /* WUXGA: 1920 * 1200 */
162
163 return set_dvi_mode(msgbuffer);
164}
165#else
166inline int hdlcd_set_output_mode(int xres, int yres)
167{
168 return 0;
169}
170#endif
171
172#define WRITE_HDLCD_REG(reg, value) writel((value), hdlcd->base + (reg))
173#define READ_HDLCD_REG(reg) readl(hdlcd->base + (reg))
174
175static int hdlcd_set_par(struct fb_info *info)
176{
177 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
178 int bytes_per_pixel = hdlcd->fb.var.bits_per_pixel / 8;
179 int polarities;
180
181 if (!memcmp(&info->var, &cached_var_screeninfo, sizeof(struct fb_var_screeninfo)))
182 return 0;
183
184 hdlcd->fb.fix.line_length = hdlcd->fb.var.xres * bytes_per_pixel;
185
186 if (hdlcd->fb.var.bits_per_pixel >= 16)
187 hdlcd->fb.fix.visual = FB_VISUAL_TRUECOLOR;
188 else
189 hdlcd->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
190
191 memcpy(&cached_var_screeninfo, &info->var, sizeof(struct fb_var_screeninfo));
192
193 polarities = HDLCD_POLARITY_DATAEN |
194#ifndef CONFIG_ARCH_TUSCAN
195 HDLCD_POLARITY_PIXELCLK |
196#endif
197 HDLCD_POLARITY_DATA;
198 polarities |= (hdlcd->fb.var.sync & FB_SYNC_HOR_HIGH_ACT) ? HDLCD_POLARITY_HSYNC : 0;
199 polarities |= (hdlcd->fb.var.sync & FB_SYNC_VERT_HIGH_ACT) ? HDLCD_POLARITY_VSYNC : 0;
200
201 hdlcd_disable(hdlcd);
202
203 WRITE_HDLCD_REG(HDLCD_REG_FB_LINE_LENGTH, hdlcd->fb.var.xres * bytes_per_pixel);
204 WRITE_HDLCD_REG(HDLCD_REG_FB_LINE_PITCH, hdlcd->fb.var.xres * bytes_per_pixel);
205 WRITE_HDLCD_REG(HDLCD_REG_FB_LINE_COUNT, hdlcd->fb.var.yres - 1);
206 WRITE_HDLCD_REG(HDLCD_REG_V_SYNC, hdlcd->fb.var.vsync_len - 1);
207 WRITE_HDLCD_REG(HDLCD_REG_V_BACK_PORCH, hdlcd->fb.var.upper_margin - 1);
208 WRITE_HDLCD_REG(HDLCD_REG_V_DATA, hdlcd->fb.var.yres - 1);
209 WRITE_HDLCD_REG(HDLCD_REG_V_FRONT_PORCH, hdlcd->fb.var.lower_margin - 1);
210 WRITE_HDLCD_REG(HDLCD_REG_H_SYNC, hdlcd->fb.var.hsync_len - 1);
211 WRITE_HDLCD_REG(HDLCD_REG_H_BACK_PORCH, hdlcd->fb.var.left_margin - 1);
212 WRITE_HDLCD_REG(HDLCD_REG_H_DATA, hdlcd->fb.var.xres - 1);
213 WRITE_HDLCD_REG(HDLCD_REG_H_FRONT_PORCH, hdlcd->fb.var.right_margin - 1);
214 WRITE_HDLCD_REG(HDLCD_REG_POLARITIES, polarities);
215 WRITE_HDLCD_REG(HDLCD_REG_PIXEL_FORMAT, (bytes_per_pixel - 1) << 3);
216 WRITE_HDLCD_REG(HDLCD_REG_RED_SELECT, ((hdlcd->fb.var.red.length & 0xf) << 8) | hdlcd->fb.var.red.offset);
217 WRITE_HDLCD_REG(HDLCD_REG_GREEN_SELECT, ((hdlcd->fb.var.green.length & 0xf) << 8) | hdlcd->fb.var.green.offset);
218 WRITE_HDLCD_REG(HDLCD_REG_BLUE_SELECT, ((hdlcd->fb.var.blue.length & 0xf) << 8) | hdlcd->fb.var.blue.offset);
219
220 hdlcd_set_output_mode(hdlcd->fb.var.xres, hdlcd->fb.var.yres);
221
Jon Medhurst7c7d3b32012-06-13 09:45:43 +0100222 clk_prepare(hdlcd->clk);
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000223 clk_set_rate(hdlcd->clk, (1000000000 / hdlcd->fb.var.pixclock) * 1000);
224 clk_enable(hdlcd->clk);
225
226 hdlcd_enable(hdlcd);
227
228 return 0;
229}
230
231static int hdlcd_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
232 unsigned int blue, unsigned int transp, struct fb_info *info)
233{
234 if (regno < 16) {
235 u32 *pal = info->pseudo_palette;
236
237 pal[regno] = ((red >> 8) << info->var.red.offset) |
238 ((green >> 8) << info->var.green.offset) |
239 ((blue >> 8) << info->var.blue.offset);
240 }
241
242 return 0;
243}
244
245static irqreturn_t hdlcd_irq(int irq, void *data)
246{
247 struct hdlcd_device *hdlcd = data;
248 unsigned long irq_mask, irq_status;
249
250 irq_mask = READ_HDLCD_REG(HDLCD_REG_INT_MASK);
251 irq_status = READ_HDLCD_REG(HDLCD_REG_INT_STATUS);
252
253 /* acknowledge interrupt(s) */
254 WRITE_HDLCD_REG(HDLCD_REG_INT_CLEAR, irq_status);
255
256 if (irq_status & HDLCD_INTERRUPT_VSYNC) {
257 /* disable future VSYNC interrupts */
258 WRITE_HDLCD_REG(HDLCD_REG_INT_MASK, irq_mask & ~HDLCD_INTERRUPT_VSYNC);
259
260 complete(&hdlcd->vsync_completion);
261 }
262
263 return IRQ_HANDLED;
264}
265
266static int hdlcd_wait_for_vsync(struct fb_info *info)
267{
268 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
269 unsigned long irq_mask;
270 int err;
271
272 /* enable VSYNC interrupt */
273 irq_mask = READ_HDLCD_REG(HDLCD_REG_INT_MASK);
274 WRITE_HDLCD_REG(HDLCD_REG_INT_MASK, irq_mask | HDLCD_INTERRUPT_VSYNC);
275
276 err = wait_for_completion_interruptible_timeout(&hdlcd->vsync_completion,
277 msecs_to_jiffies(100));
278
279 if (!err)
280 return -ETIMEDOUT;
281
282 return 0;
283}
284
285static int hdlcd_blank(int blank_mode, struct fb_info *info)
286{
287 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
288
289 switch (blank_mode) {
290 case FB_BLANK_POWERDOWN:
291 clk_disable(hdlcd->clk);
292 case FB_BLANK_NORMAL:
293 hdlcd_disable(hdlcd);
294 break;
295 case FB_BLANK_UNBLANK:
296 clk_enable(hdlcd->clk);
297 hdlcd_enable(hdlcd);
298 break;
299 case FB_BLANK_VSYNC_SUSPEND:
300 case FB_BLANK_HSYNC_SUSPEND:
301 default:
302 return 1;
303 }
304
305 return 0;
306}
307
308static void hdlcd_mmap_open(struct vm_area_struct *vma)
309{
310}
311
312static void hdlcd_mmap_close(struct vm_area_struct *vma)
313{
314}
315
316static struct vm_operations_struct hdlcd_mmap_ops = {
317 .open = hdlcd_mmap_open,
318 .close = hdlcd_mmap_close,
319};
320
321static int hdlcd_mmap(struct fb_info *info, struct vm_area_struct *vma)
322{
323 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
324 unsigned long off;
325 unsigned long start;
326 unsigned long len = hdlcd->fb.fix.smem_len;
327
328 if (vma->vm_end - vma->vm_start == 0)
329 return 0;
330 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
331 return -EINVAL;
332
333 off = vma->vm_pgoff << PAGE_SHIFT;
334 if ((off >= len) || (vma->vm_end - vma->vm_start + off) > len)
335 return -EINVAL;
336
337 start = hdlcd->fb.fix.smem_start;
338 off += start;
339
340 vma->vm_pgoff = off >> PAGE_SHIFT;
341 vma->vm_flags |= VM_IO;
342 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
343 vma->vm_ops = &hdlcd_mmap_ops;
344 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
345 vma->vm_end - vma->vm_start,
346 vma->vm_page_prot))
347 return -EAGAIN;
348
349 return 0;
350}
351
352static int hdlcd_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
353{
354 struct hdlcd_device *hdlcd = to_hdlcd_device(info);
355
356 hdlcd->fb.var.yoffset = var->yoffset;
357 WRITE_HDLCD_REG(HDLCD_REG_FB_BASE, hdlcd->fb.fix.smem_start +
358 (var->yoffset * hdlcd->fb.fix.line_length));
359
360 hdlcd_wait_for_vsync(info);
361
362 return 0;
363}
364
365static int hdlcd_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
366{
367 int err;
368
369 switch (cmd) {
370 case FBIO_WAITFORVSYNC:
371 err = hdlcd_wait_for_vsync(info);
372 break;
373 default:
374 err = -ENOIOCTLCMD;
375 break;
376 }
377
378 return err;
379}
380
381static struct fb_ops hdlcd_ops = {
382 .owner = THIS_MODULE,
383 .fb_check_var = hdlcd_check_var,
384 .fb_set_par = hdlcd_set_par,
385 .fb_setcolreg = hdlcd_setcolreg,
386 .fb_blank = hdlcd_blank,
387 .fb_fillrect = cfb_fillrect,
388 .fb_copyarea = cfb_copyarea,
389 .fb_imageblit = cfb_imageblit,
390 .fb_mmap = hdlcd_mmap,
391 .fb_pan_display = hdlcd_pan_display,
392 .fb_ioctl = hdlcd_ioctl,
393 .fb_compat_ioctl = hdlcd_ioctl
394};
395
396static int hdlcd_setup(struct hdlcd_device *hdlcd)
397{
398 u32 version;
399 int err = -EFAULT;
400
401 hdlcd->clk = clk_get(hdlcd->dev, NULL);
402 if (IS_ERR(hdlcd->clk)) {
403 dev_err(hdlcd->dev, "HDLCD: unable to find clock data\n");
404 return PTR_ERR(hdlcd->clk);
405 }
406
407 hdlcd->base = ioremap_nocache(hdlcd->fb.fix.mmio_start, hdlcd->fb.fix.mmio_len);
408 if (!hdlcd->base) {
409 dev_err(hdlcd->dev, "HDLCD: unable to map registers\n");
410 goto remap_err;
411 }
412
413 hdlcd->fb.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
414 if (!hdlcd->fb.pseudo_palette) {
415 dev_err(hdlcd->dev, "HDLCD: unable to allocate pseudo_palette memory\n");
416 err = -ENOMEM;
417 goto kmalloc_err;
418 }
419
420 version = readl(hdlcd->base + HDLCD_REG_VERSION);
421 if ((version & HDLCD_PRODUCT_MASK) != HDLCD_PRODUCT_ID) {
422 dev_err(hdlcd->dev, "HDLCD: unknown product id: 0x%x\n", version);
423 err = -EINVAL;
424 goto kmalloc_err;
425 }
426 dev_info(hdlcd->dev, "HDLCD: found ARM HDLCD version r%dp%d\n",
427 (version & HDLCD_VERSION_MAJOR_MASK) >> 8,
428 version & HDLCD_VERSION_MINOR_MASK);
429
430 strcpy(hdlcd->fb.fix.id, "hdlcd");
431 hdlcd->fb.fbops = &hdlcd_ops;
432 hdlcd->fb.flags = FBINFO_FLAG_DEFAULT/* | FBINFO_VIRTFB*/;
433
434 hdlcd->fb.fix.type = FB_TYPE_PACKED_PIXELS;
435 hdlcd->fb.fix.type_aux = 0;
436 hdlcd->fb.fix.xpanstep = 0;
437 hdlcd->fb.fix.ypanstep = 1;
438 hdlcd->fb.fix.ywrapstep = 0;
439 hdlcd->fb.fix.accel = FB_ACCEL_NONE;
440
441 hdlcd->fb.var.nonstd = 0;
442 hdlcd->fb.var.activate = FB_ACTIVATE_NOW;
443 hdlcd->fb.var.height = -1;
444 hdlcd->fb.var.width = -1;
445 hdlcd->fb.var.accel_flags = 0;
446
447 init_completion(&hdlcd->vsync_completion);
448
449 if (hdlcd->edid) {
450 /* build modedb from EDID */
451 fb_edid_to_monspecs(hdlcd->edid, &hdlcd->fb.monspecs);
452 fb_videomode_to_modelist(hdlcd->fb.monspecs.modedb,
453 hdlcd->fb.monspecs.modedb_len,
454 &hdlcd->fb.modelist);
455 fb_find_mode(&hdlcd->fb.var, &hdlcd->fb, fb_mode,
456 hdlcd->fb.monspecs.modedb,
457 hdlcd->fb.monspecs.modedb_len,
458 &hdlcd_default_mode, 32);
459 } else {
460 hdlcd->fb.monspecs.hfmin = 0;
461 hdlcd->fb.monspecs.hfmax = 100000;
462 hdlcd->fb.monspecs.vfmin = 0;
463 hdlcd->fb.monspecs.vfmax = 400;
464 hdlcd->fb.monspecs.dclkmin = 1000000;
465 hdlcd->fb.monspecs.dclkmax = 100000000;
466 fb_find_mode(&hdlcd->fb.var, &hdlcd->fb, fb_mode, NULL, 0, &hdlcd_default_mode, 32);
467 }
468
469 dev_info(hdlcd->dev, "using %dx%d-%d@%d mode\n", hdlcd->fb.var.xres,
470 hdlcd->fb.var.yres, hdlcd->fb.var.bits_per_pixel,
471 hdlcd->fb.mode ? hdlcd->fb.mode->refresh : 60);
472 hdlcd->fb.var.xres_virtual = hdlcd->fb.var.xres;
473 hdlcd->fb.var.yres_virtual = hdlcd->fb.var.yres * 2;
474
475 /* initialise and set the palette */
476 if (fb_alloc_cmap(&hdlcd->fb.cmap, NR_PALETTE, 0)) {
477 dev_err(hdlcd->dev, "failed to allocate cmap memory\n");
478 err = -ENOMEM;
479 goto setup_err;
480 }
481 fb_set_cmap(&hdlcd->fb.cmap, &hdlcd->fb);
482
483 /* Allow max number of outstanding requests with the largest beat burst */
484 WRITE_HDLCD_REG(HDLCD_REG_BUS_OPTIONS, HDLCD_BUS_MAX_OUTSTAND | HDLCD_BUS_BURST_16);
485 /* Set the framebuffer base to start of allocated memory */
486 WRITE_HDLCD_REG(HDLCD_REG_FB_BASE, hdlcd->fb.fix.smem_start);
487 /* Ensure interrupts are disabled */
488 WRITE_HDLCD_REG(HDLCD_REG_INT_MASK, 0);
489
490 if (!register_framebuffer(&hdlcd->fb)) {
491 fb_set_var(&hdlcd->fb, &hdlcd->fb.var);
492 clk_enable(hdlcd->clk);
493 return 0;
494 }
495
496 dev_err(hdlcd->dev, "HDLCD: cannot register framebuffer\n");
497
498 fb_dealloc_cmap(&hdlcd->fb.cmap);
499setup_err:
500 iounmap(hdlcd->base);
501kmalloc_err:
502 kfree(hdlcd->fb.pseudo_palette);
503remap_err:
504 clk_put(hdlcd->clk);
505 return err;
506}
507
508static inline unsigned char atohex(u8 data)
509{
510 if (!isxdigit(data))
511 return 0;
512 /* truncate the upper nibble and add 9 to non-digit values */
513 return (data > 0x39) ? ((data & 0xf) + 9) : (data & 0xf);
514}
515
516/* EDID data is passed from devicetree in a literal string that can contain spaces and
517 the hexadecimal dump of the data */
518static int parse_edid_data(struct hdlcd_device *hdlcd, const u8 *edid_data, int data_len)
519{
520 int i, j;
521
522 if (!edid_data)
523 return -EINVAL;
524
525 hdlcd->edid = kzalloc(EDID_LENGTH, GFP_KERNEL);
526 if (!hdlcd->edid)
527 return -ENOMEM;
528
529 for (i = 0, j = 0; i < data_len; i++) {
530 if (isspace(edid_data[i]))
531 continue;
532 hdlcd->edid[j++] = atohex(edid_data[i]);
533 if (j >= EDID_LENGTH)
534 break;
535 }
536
537 if (j < EDID_LENGTH) {
538 kfree(hdlcd->edid);
539 hdlcd->edid = NULL;
540 return -EINVAL;
541 }
542
543 return 0;
544}
545
546static int hdlcd_probe(struct platform_device *pdev)
547{
548 int err = 0, i;
549 struct hdlcd_device *hdlcd;
550 struct resource *mem;
551#ifdef CONFIG_OF
552 struct device_node *of_node;
553#endif
554
555 memset(&cached_var_screeninfo, 0, sizeof(struct fb_var_screeninfo));
556
557 dev_dbg(&pdev->dev, "HDLCD: probing\n");
558
559 hdlcd = kzalloc(sizeof(*hdlcd), GFP_KERNEL);
560 if (!hdlcd)
561 return -ENOMEM;
562
563#ifdef CONFIG_OF
564 of_node = pdev->dev.of_node;
565 if (of_node) {
566 int len;
567 const u8 *edid;
568 const void *prop = of_get_property(of_node, "mode", &len);
569 if (prop)
570 strncpy(fb_mode, prop, len);
571 prop = of_get_property(of_node, "framebuffer", &len);
572 if (prop) {
573 hdlcd->fb.fix.smem_start = of_read_ulong((const __be32 *) prop, 1);
574 framebuffer_size = of_read_ulong((const __be32 *)prop, 1);
575 if (framebuffer_size > HDLCD_MAX_FRAMEBUFFER_SIZE)
576 framebuffer_size = HDLCD_MAX_FRAMEBUFFER_SIZE;
577 dev_dbg(&pdev->dev, "HDLCD: phys_addr = 0x%lx, size = 0x%lx\n",
578 hdlcd->fb.fix.smem_start, framebuffer_size);
579 }
580 edid = of_get_property(of_node, "edid", &len);
581 if (edid) {
582 err = parse_edid_data(hdlcd, edid, len);
583#ifdef CONFIG_SERIAL_AMBA_PCU_UART
584 } else {
585 /* ask the firmware to fetch the EDID */
586 dev_dbg(&pdev->dev, "HDLCD: Requesting EDID data\n");
587 hdlcd->edid = kzalloc(EDID_LENGTH, GFP_KERNEL);
588 if (!hdlcd->edid)
589 return -ENOMEM;
590 err = get_edid(hdlcd->edid);
591#endif /* CONFIG_SERIAL_AMBA_PCU_UART */
592 }
593 if (err)
594 dev_info(&pdev->dev, "HDLCD: Failed to parse EDID data\n");
595 }
596#endif /* CONFIG_OF */
597
598 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
599 if (!mem) {
600 dev_err(&pdev->dev, "HDLCD: cannot get platform resources\n");
601 err = -EINVAL;
602 goto resource_err;
603 }
604
605 i = platform_get_irq(pdev, 0);
606 if (i < 0) {
607 dev_err(&pdev->dev, "HDLCD: no irq defined for vsync\n");
608 err = -ENOENT;
609 goto resource_err;
610 } else {
611 err = request_irq(i, hdlcd_irq, 0, dev_name(&pdev->dev), hdlcd);
612 if (err) {
613 dev_err(&pdev->dev, "HDLCD: unable to request irq\n");
614 goto resource_err;
615 }
616 hdlcd->irq = i;
617 }
618
619 if (!request_mem_region(mem->start, resource_size(mem), dev_name(&pdev->dev))) {
620 err = -ENXIO;
621 goto request_err;
622 }
623
624 if (!hdlcd->fb.fix.smem_start) {
625 dev_err(&pdev->dev, "platform did not allocate frame buffer memory\n");
626 err = -ENOMEM;
627 goto memalloc_err;
628 }
629 hdlcd->fb.screen_base = ioremap_wc(hdlcd->fb.fix.smem_start, framebuffer_size);
630 if (!hdlcd->fb.screen_base) {
631 dev_err(&pdev->dev, "unable to ioremap framebuffer\n");
632 err = -ENOMEM;
633 goto probe_err;
634 }
635
636 hdlcd->fb.screen_size = framebuffer_size;
637 hdlcd->fb.fix.smem_len = framebuffer_size;
638 hdlcd->fb.fix.mmio_start = mem->start;
639 hdlcd->fb.fix.mmio_len = resource_size(mem);
640
641 /* Clear the framebuffer */
642 memset(hdlcd->fb.screen_base, 0, framebuffer_size);
643
644 hdlcd->dev = &pdev->dev;
645
646 dev_dbg(&pdev->dev, "HDLCD: framebuffer virt base %p, phys base 0x%lX\n",
647 hdlcd->fb.screen_base, (unsigned long)hdlcd->fb.fix.smem_start);
648
649 err = hdlcd_setup(hdlcd);
650
651 if (err)
652 goto probe_err;
653
654 platform_set_drvdata(pdev, hdlcd);
655 return 0;
656
657probe_err:
658 iounmap(hdlcd->fb.screen_base);
659 memblock_free(hdlcd->fb.fix.smem_start, hdlcd->fb.fix.smem_start);
660
661memalloc_err:
662 release_mem_region(mem->start, resource_size(mem));
663
664request_err:
665 free_irq(hdlcd->irq, hdlcd);
666
667resource_err:
668 kfree(hdlcd);
669
670 return err;
671}
672
673static int hdlcd_remove(struct platform_device *pdev)
674{
675 struct hdlcd_device *hdlcd = platform_get_drvdata(pdev);
676
677 clk_disable(hdlcd->clk);
Jon Medhurst7c7d3b32012-06-13 09:45:43 +0100678 clk_unprepare(hdlcd->clk);
Liviu Dudaucaf003f2012-01-18 16:52:04 +0000679 clk_put(hdlcd->clk);
680
681 /* unmap memory */
682 iounmap(hdlcd->fb.screen_base);
683 iounmap(hdlcd->base);
684
685 /* deallocate fb memory */
686 fb_dealloc_cmap(&hdlcd->fb.cmap);
687 kfree(hdlcd->fb.pseudo_palette);
688 memblock_free(hdlcd->fb.fix.smem_start, hdlcd->fb.fix.smem_start);
689 release_mem_region(hdlcd->fb.fix.mmio_start, hdlcd->fb.fix.mmio_len);
690
691 free_irq(hdlcd->irq, NULL);
692 kfree(hdlcd);
693
694 return 0;
695}
696
697#ifdef CONFIG_PM
698static int hdlcd_suspend(struct platform_device *pdev, pm_message_t state)
699{
700 /* not implemented yet */
701 return 0;
702}
703
704static int hdlcd_resume(struct platform_device *pdev)
705{
706 /* not implemented yet */
707 return 0;
708}
709#else
710#define hdlcd_suspend NULL
711#define hdlcd_resume NULL
712#endif
713
714static struct platform_driver hdlcd_driver = {
715 .probe = hdlcd_probe,
716 .remove = hdlcd_remove,
717 .suspend = hdlcd_suspend,
718 .resume = hdlcd_resume,
719 .driver = {
720 .name = "hdlcd",
721 .owner = THIS_MODULE,
722 .of_match_table = hdlcd_of_matches,
723 },
724};
725
726static int __init hdlcd_init(void)
727{
728 return platform_driver_register(&hdlcd_driver);
729}
730
731void __exit hdlcd_exit(void)
732{
733 platform_driver_unregister(&hdlcd_driver);
734}
735
736module_init(hdlcd_init);
737module_exit(hdlcd_exit);
738
739MODULE_AUTHOR("Liviu Dudau");
740MODULE_DESCRIPTION("ARM HDLCD core driver");
741MODULE_LICENSE("GPL v2");