Date:2010-04-24 12:13:58 (12 years 5 months ago)
Author:Lars C.
Commit:0254927d6bcc67123d10ce9cabc907780dc7dec6
Message:Add jz4740 framebuffer driver

Files: drivers/video/Kconfig (1 diff)
drivers/video/Makefile (1 diff)
drivers/video/jz4740_fb.c (1 diff)
include/linux/jz4740_fb.h (1 diff)

Change Details

drivers/video/Kconfig
22142214      and could also have been called by other names when coupled with
22152215      a bridge adapter.
22162216
2217config FB_JZ4740
2218    tristate "JZ47420/JZ4740 LCD framebuffer support"
2219    depends on FB
2220    select FB_SYS_FILLRECT
2221    select FB_SYS_COPYAREA
2222    select FB_SYS_IMAGEBLIT
2223    help
2224      Framebuffer support for the JZ4720 and JZ4740 SoC.
2225
22172226source "drivers/video/omap/Kconfig"
22182227source "drivers/video/omap2/Kconfig"
22192228
drivers/video/Makefile
131131obj-$(CONFIG_FB_MB862XX) += mb862xx/
132132obj-$(CONFIG_FB_MSM) += msm/
133133obj-$(CONFIG_FB_NUC900) += nuc900fb.o
134obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o
134135
135136# Platform or fallback drivers go here
136137obj-$(CONFIG_FB_UVESA) += uvesafb.o
drivers/video/jz4740_fb.c
1/*
2 * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4720/JZ4740 SoC LCD framebuffer driver
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/mutex.h>
19#include <linux/platform_device.h>
20
21#include <linux/clk.h>
22#include <linux/delay.h>
23
24#include <linux/console.h>
25#include <linux/fb.h>
26
27#include <linux/dma-mapping.h>
28
29#include <linux/jz4740_fb.h>
30#include <asm/mach-jz4740/gpio.h>
31
32#define JZ_REG_LCD_CFG 0x00
33#define JZ_REG_LCD_VSYNC 0x04
34#define JZ_REG_LCD_HSYNC 0x08
35#define JZ_REG_LCD_VAT 0x0C
36#define JZ_REG_LCD_DAH 0x10
37#define JZ_REG_LCD_DAV 0x14
38#define JZ_REG_LCD_PS 0x18
39#define JZ_REG_LCD_CLS 0x1C
40#define JZ_REG_LCD_SPL 0x20
41#define JZ_REG_LCD_REV 0x24
42#define JZ_REG_LCD_CTRL 0x30
43#define JZ_REG_LCD_STATE 0x34
44#define JZ_REG_LCD_IID 0x38
45#define JZ_REG_LCD_DA0 0x40
46#define JZ_REG_LCD_SA0 0x44
47#define JZ_REG_LCD_FID0 0x48
48#define JZ_REG_LCD_CMD0 0x4C
49#define JZ_REG_LCD_DA1 0x50
50#define JZ_REG_LCD_SA1 0x54
51#define JZ_REG_LCD_FID1 0x58
52#define JZ_REG_LCD_CMD1 0x5C
53
54#define JZ_LCD_CFG_SLCD BIT(31)
55#define JZ_LCD_CFG_PS_DISABLE BIT(23)
56#define JZ_LCD_CFG_CLS_DISABLE BIT(22)
57#define JZ_LCD_CFG_SPL_DISABLE BIT(21)
58#define JZ_LCD_CFG_REV_DISABLE BIT(20)
59#define JZ_LCD_CFG_HSYNCM BIT(19)
60#define JZ_LCD_CFG_PCLKM BIT(18)
61#define JZ_LCD_CFG_INV BIT(17)
62#define JZ_LCD_CFG_SYNC_DIR BIT(16)
63#define JZ_LCD_CFG_PS_POLARITY BIT(15)
64#define JZ_LCD_CFG_CLS_POLARITY BIT(14)
65#define JZ_LCD_CFG_SPL_POLARITY BIT(13)
66#define JZ_LCD_CFG_REV_POLARITY BIT(12)
67#define JZ_LCD_CFG_HSYNC_ACTIVE_LOW BIT(11)
68#define JZ_LCD_CFG_PCLK_FALLING_EDGE BIT(10)
69#define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9)
70#define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8)
71#define JZ_LCD_CFG_18_BIT BIT(7)
72#define JZ_LCD_CFG_PDW (BIT(5) | BIT(4))
73#define JZ_LCD_CFG_MODE_MASK 0xf
74
75#define JZ_LCD_CTRL_BURST_4 (0x0 << 28)
76#define JZ_LCD_CTRL_BURST_8 (0x1 << 28)
77#define JZ_LCD_CTRL_BURST_16 (0x2 << 28)
78#define JZ_LCD_CTRL_RGB555 BIT(27)
79#define JZ_LCD_CTRL_OFUP BIT(26)
80#define JZ_LCD_CTRL_FRC_GRAYSCALE_16 (0x0 << 24)
81#define JZ_LCD_CTRL_FRC_GRAYSCALE_4 (0x1 << 24)
82#define JZ_LCD_CTRL_FRC_GRAYSCALE_2 (0x2 << 24)
83#define JZ_LCD_CTRL_PDD_MASK (0xff << 16)
84#define JZ_LCD_CTRL_EOF_IRQ BIT(13)
85#define JZ_LCD_CTRL_SOF_IRQ BIT(12)
86#define JZ_LCD_CTRL_OFU_IRQ BIT(11)
87#define JZ_LCD_CTRL_IFU0_IRQ BIT(10)
88#define JZ_LCD_CTRL_IFU1_IRQ BIT(9)
89#define JZ_LCD_CTRL_DD_IRQ BIT(8)
90#define JZ_LCD_CTRL_QDD_IRQ BIT(7)
91#define JZ_LCD_CTRL_REVERSE_ENDIAN BIT(6)
92#define JZ_LCD_CTRL_LSB_FISRT BIT(5)
93#define JZ_LCD_CTRL_DISABLE BIT(4)
94#define JZ_LCD_CTRL_ENABLE BIT(3)
95#define JZ_LCD_CTRL_BPP_1 0x0
96#define JZ_LCD_CTRL_BPP_2 0x1
97#define JZ_LCD_CTRL_BPP_4 0x2
98#define JZ_LCD_CTRL_BPP_8 0x3
99#define JZ_LCD_CTRL_BPP_15_16 0x4
100#define JZ_LCD_CTRL_BPP_18_24 0x5
101
102#define JZ_LCD_CMD_SOF_IRQ BIT(15)
103#define JZ_LCD_CMD_EOF_IRQ BIT(16)
104#define JZ_LCD_CMD_ENABLE_PAL BIT(12)
105
106#define JZ_LCD_SYNC_MASK 0x3ff
107
108#define JZ_LCD_STATE_DISABLED BIT(0)
109
110struct jzfb_framedesc {
111    uint32_t next;
112    uint32_t addr;
113    uint32_t id;
114    uint32_t cmd;
115} __attribute__((packed));
116
117struct jzfb {
118    struct fb_info *fb;
119    struct platform_device *pdev;
120    void __iomem *base;
121    struct resource *mem;
122    struct jz4740_fb_platform_data *pdata;
123
124    size_t vidmem_size;
125    void *vidmem;
126    dma_addr_t vidmem_phys;
127    struct jzfb_framedesc *framedesc;
128    dma_addr_t framedesc_phys;
129
130    struct clk *ldclk;
131    struct clk *lpclk;
132
133    unsigned is_enabled:1;
134    struct mutex lock;
135
136    uint32_t pseudo_palette[256];
137};
138
139static struct fb_fix_screeninfo jzfb_fix __devinitdata = {
140    .id = "JZ4740 FB",
141    .type = FB_TYPE_PACKED_PIXELS,
142    .visual = FB_VISUAL_TRUECOLOR,
143    .xpanstep = 0,
144    .ypanstep = 0,
145    .ywrapstep = 0,
146    .accel = FB_ACCEL_NONE,
147};
148
149const static struct jz_gpio_bulk_request jz_lcd_ctrl_pins[] = {
150    JZ_GPIO_BULK_PIN(LCD_PCLK),
151    JZ_GPIO_BULK_PIN(LCD_HSYNC),
152    JZ_GPIO_BULK_PIN(LCD_VSYNC),
153    JZ_GPIO_BULK_PIN(LCD_DE),
154    JZ_GPIO_BULK_PIN(LCD_PS),
155    JZ_GPIO_BULK_PIN(LCD_REV),
156};
157
158const static struct jz_gpio_bulk_request jz_lcd_data_pins[] = {
159    JZ_GPIO_BULK_PIN(LCD_DATA0),
160    JZ_GPIO_BULK_PIN(LCD_DATA1),
161    JZ_GPIO_BULK_PIN(LCD_DATA2),
162    JZ_GPIO_BULK_PIN(LCD_DATA3),
163    JZ_GPIO_BULK_PIN(LCD_DATA4),
164    JZ_GPIO_BULK_PIN(LCD_DATA5),
165    JZ_GPIO_BULK_PIN(LCD_DATA6),
166    JZ_GPIO_BULK_PIN(LCD_DATA7),
167    JZ_GPIO_BULK_PIN(LCD_DATA8),
168    JZ_GPIO_BULK_PIN(LCD_DATA9),
169    JZ_GPIO_BULK_PIN(LCD_DATA10),
170    JZ_GPIO_BULK_PIN(LCD_DATA11),
171    JZ_GPIO_BULK_PIN(LCD_DATA12),
172    JZ_GPIO_BULK_PIN(LCD_DATA13),
173    JZ_GPIO_BULK_PIN(LCD_DATA14),
174    JZ_GPIO_BULK_PIN(LCD_DATA15),
175    JZ_GPIO_BULK_PIN(LCD_DATA16),
176    JZ_GPIO_BULK_PIN(LCD_DATA17),
177};
178
179static unsigned int jzfb_num_ctrl_pins(struct jzfb *jzfb)
180{
181    unsigned int num;
182
183    switch (jzfb->pdata->lcd_type) {
184    case JZ_LCD_TYPE_GENERIC_16_BIT:
185        num = 4;
186        break;
187    case JZ_LCD_TYPE_GENERIC_18_BIT:
188        num = 4;
189        break;
190    case JZ_LCD_TYPE_8BIT_SERIAL:
191        num = 3;
192        break;
193    default:
194        num = 0;
195        break;
196    }
197    return num;
198}
199
200static unsigned int jzfb_num_data_pins(struct jzfb *jzfb)
201{
202    unsigned int num;
203
204    switch (jzfb->pdata->lcd_type) {
205    case JZ_LCD_TYPE_GENERIC_16_BIT:
206        num = 16;
207        break;
208    case JZ_LCD_TYPE_GENERIC_18_BIT:
209        num = 19;
210        break;
211    case JZ_LCD_TYPE_8BIT_SERIAL:
212        num = 8;
213        break;
214    default:
215        num = 0;
216        break;
217    }
218    return num;
219}
220
221static int jzfb_setcolreg(unsigned regno, unsigned red, unsigned green,
222            unsigned blue, unsigned transp, struct fb_info *fb)
223{
224    if (regno >= fb->cmap.len)
225        return -EINVAL;
226
227    ((uint32_t *)fb->pseudo_palette)[regno] = red << 16 | green << 8 | blue;
228
229    return 0;
230}
231
232static int jzfb_get_controller_bpp(struct jzfb *jzfb)
233{
234    switch (jzfb->pdata->bpp) {
235    case 18:
236    case 24:
237        return 32;
238    case 15:
239        return 16;
240    default:
241        return jzfb->pdata->bpp;
242    }
243}
244
245static struct fb_videomode *jzfb_get_mode(struct jzfb *jzfb, struct fb_var_screeninfo *var)
246{
247    size_t i;
248    struct fb_videomode *mode = jzfb->pdata->modes;
249
250    for (i = 0; i < jzfb->pdata->num_modes; ++i, ++mode) {
251        if (mode->xres == var->xres && mode->yres == var->yres)
252            return mode;
253    }
254
255    return NULL;
256}
257
258static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb)
259{
260    struct jzfb *jzfb = fb->par;
261    struct fb_videomode *mode;
262
263    if (var->bits_per_pixel != jzfb_get_controller_bpp(jzfb) &&
264        var->bits_per_pixel != jzfb->pdata->bpp)
265        return -EINVAL;
266
267    mode = jzfb_get_mode(jzfb, var);
268    if (mode == NULL)
269        return -EINVAL;
270
271    fb_videomode_to_var(var, mode);
272
273    switch (jzfb->pdata->bpp) {
274    case 8:
275        break;
276    case 15:
277        var->red.offset = 10;
278        var->red.length = 5;
279        var->green.offset = 6;
280        var->green.length = 5;
281        var->blue.offset = 0;
282        var->blue.length = 5;
283        break;
284    case 16:
285        var->red.offset = 11;
286        var->red.length = 5;
287        var->green.offset = 6;
288        var->green.length = 6;
289        var->blue.offset = 0;
290        var->blue.length = 5;
291        break;
292    case 18:
293        var->red.offset = 16;
294        var->red.length = 6;
295        var->green.offset = 8;
296        var->green.length = 6;
297        var->blue.offset = 0;
298        var->blue.length = 6;
299        var->bits_per_pixel = 32;
300        break;
301    case 32:
302    case 24:
303        var->transp.offset = 24;
304        var->transp.length = 8;
305        var->red.offset = 16;
306        var->red.length = 8;
307        var->green.offset = 8;
308        var->green.length = 8;
309        var->blue.offset = 0;
310        var->blue.length = 8;
311        var->bits_per_pixel = 32;
312        break;
313    default:
314        break;
315    }
316
317    return 0;
318}
319
320static int jzfb_set_par(struct fb_info *info)
321{
322    struct jzfb *jzfb = info->par;
323    struct fb_var_screeninfo *var = &info->var;
324    struct fb_videomode *mode;
325    uint16_t hds, vds;
326    uint16_t hde, vde;
327    uint16_t ht, vt;
328    uint32_t ctrl;
329    uint32_t cfg;
330    unsigned long rate;
331
332    mode = jzfb_get_mode(jzfb, var);
333    if (mode == NULL)
334        return -EINVAL;
335
336    info->mode = mode;
337
338    hds = mode->hsync_len + mode->left_margin;
339    hde = hds + mode->xres;
340    ht = hde + mode->right_margin;
341
342    vds = mode->vsync_len + mode->upper_margin;
343    vde = vds + mode->yres;
344    vt = vde + mode->lower_margin;
345
346    ctrl = JZ_LCD_CTRL_OFUP | JZ_LCD_CTRL_BURST_16;
347
348    switch (jzfb->pdata->bpp) {
349    case 1:
350        ctrl |= JZ_LCD_CTRL_BPP_1;
351        break;
352    case 2:
353        ctrl |= JZ_LCD_CTRL_BPP_2;
354        break;
355    case 4:
356        ctrl |= JZ_LCD_CTRL_BPP_4;
357        break;
358    case 8:
359        ctrl |= JZ_LCD_CTRL_BPP_8;
360    break;
361    case 15:
362        ctrl |= JZ_LCD_CTRL_RGB555; /* Falltrough */
363    case 16:
364        ctrl |= JZ_LCD_CTRL_BPP_15_16;
365        break;
366    case 18:
367    case 24:
368    case 32:
369        ctrl |= JZ_LCD_CTRL_BPP_18_24;
370        break;
371    default:
372        break;
373    }
374
375    cfg = 0;
376    cfg |= JZ_LCD_CFG_PS_DISABLE;
377    cfg |= JZ_LCD_CFG_CLS_DISABLE;
378    cfg |= JZ_LCD_CFG_SPL_DISABLE;
379    cfg |= JZ_LCD_CFG_REV_DISABLE;
380
381    if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
382        cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW;
383
384    if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
385        cfg |= JZ_LCD_CFG_VSYNC_ACTIVE_LOW;
386
387    if (jzfb->pdata->pixclk_falling_edge)
388        cfg |= JZ_LCD_CFG_PCLK_FALLING_EDGE;
389
390    if (jzfb->pdata->date_enable_active_low)
391        cfg |= JZ_LCD_CFG_DE_ACTIVE_LOW;
392
393    if (jzfb->pdata->lcd_type == JZ_LCD_TYPE_GENERIC_18_BIT)
394        cfg |= JZ_LCD_CFG_18_BIT;
395
396    cfg |= jzfb->pdata->lcd_type & 0xf;
397
398    if (mode->pixclock) {
399        rate = PICOS2KHZ(mode->pixclock) * 1000;
400        mode->refresh = rate / vt / ht;
401    } else {
402        if (jzfb->pdata->lcd_type == JZ_LCD_TYPE_8BIT_SERIAL)
403            rate = mode->refresh * (vt + 2 * mode->xres) * ht;
404        else
405            rate = mode->refresh * vt * ht;
406
407        mode->pixclock = KHZ2PICOS(rate / 1000);
408    }
409
410    mutex_lock(&jzfb->lock);
411    if (!jzfb->is_enabled)
412        clk_enable(jzfb->ldclk);
413    else
414        ctrl |= JZ_LCD_CTRL_ENABLE;
415
416    writel(mode->hsync_len, jzfb->base + JZ_REG_LCD_HSYNC);
417    writel(mode->vsync_len, jzfb->base + JZ_REG_LCD_VSYNC);
418
419    writel((ht << 16) | vt, jzfb->base + JZ_REG_LCD_VAT);
420
421    writel((hds << 16) | hde, jzfb->base + JZ_REG_LCD_DAH);
422    writel((vds << 16) | vde, jzfb->base + JZ_REG_LCD_DAV);
423
424    writel(cfg, jzfb->base + JZ_REG_LCD_CFG);
425
426    writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL);
427
428    if (!jzfb->is_enabled)
429        clk_disable(jzfb->ldclk);
430    mutex_unlock(&jzfb->lock);
431
432    clk_set_rate(jzfb->lpclk, rate);
433    clk_set_rate(jzfb->ldclk, rate * 3);
434
435    return 0;
436}
437
438static void jzfb_enable(struct jzfb *jzfb)
439{
440    uint32_t ctrl;
441
442    clk_enable(jzfb->ldclk);
443
444    jz_gpio_bulk_resume(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
445    jz_gpio_bulk_resume(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
446
447    writel(0, jzfb->base + JZ_REG_LCD_STATE);
448
449    writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0);
450
451    ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL);
452    ctrl |= JZ_LCD_CTRL_ENABLE;
453    ctrl &= ~JZ_LCD_CTRL_DISABLE;
454    writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL);
455}
456
457static void jzfb_disable(struct jzfb *jzfb)
458{
459    uint32_t ctrl;
460
461    ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL);
462    ctrl |= JZ_LCD_CTRL_DISABLE;
463    writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL);
464    do {
465        ctrl = readl(jzfb->base + JZ_REG_LCD_STATE);
466    } while (!(ctrl & JZ_LCD_STATE_DISABLED));
467
468    jz_gpio_bulk_suspend(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
469    jz_gpio_bulk_suspend(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
470
471    clk_disable(jzfb->ldclk);
472}
473
474static int jzfb_blank(int blank_mode, struct fb_info *info)
475{
476    struct jzfb *jzfb = info->par;
477
478    switch (blank_mode) {
479    case FB_BLANK_UNBLANK:
480        mutex_lock(&jzfb->lock);
481        if (jzfb->is_enabled) {
482            mutex_unlock(&jzfb->lock);
483            return 0;
484        }
485
486        jzfb_enable(jzfb);
487        jzfb->is_enabled = 1;
488
489        mutex_unlock(&jzfb->lock);
490
491        break;
492    default:
493        mutex_lock(&jzfb->lock);
494        if (!jzfb->is_enabled) {
495            mutex_unlock(&jzfb->lock);
496            return 0;
497        }
498
499        jzfb_disable(jzfb);
500
501        jzfb->is_enabled = 0;
502        mutex_unlock(&jzfb->lock);
503        break;
504    }
505
506    return 0;
507}
508
509static int jzfb_alloc_devmem(struct jzfb *jzfb)
510{
511    int max_videosize = 0;
512    struct fb_videomode *mode = jzfb->pdata->modes;
513    void *page;
514    int i;
515
516    for (i = 0; i < jzfb->pdata->num_modes; ++mode, ++i) {
517        if (max_videosize < mode->xres * mode->yres)
518            max_videosize = mode->xres * mode->yres;
519    }
520
521    max_videosize *= jzfb_get_controller_bpp(jzfb) >> 3;
522
523    jzfb->framedesc = dma_alloc_coherent(&jzfb->pdev->dev,
524                    sizeof(*jzfb->framedesc),
525                    &jzfb->framedesc_phys, GFP_KERNEL);
526
527    if (!jzfb->framedesc)
528        return -ENOMEM;
529
530    jzfb->vidmem_size = PAGE_ALIGN(max_videosize);
531    jzfb->vidmem = dma_alloc_coherent(&jzfb->pdev->dev,
532                        jzfb->vidmem_size,
533                        &jzfb->vidmem_phys, GFP_KERNEL);
534
535    if (!jzfb->vidmem)
536        goto err_free_framedesc;
537
538    for (page = jzfb->vidmem;
539         page < jzfb->vidmem + PAGE_ALIGN(jzfb->vidmem_size);
540         page += PAGE_SIZE) {
541        SetPageReserved(virt_to_page(page));
542    }
543
544
545    jzfb->framedesc->next = jzfb->framedesc_phys;
546    jzfb->framedesc->addr = jzfb->vidmem_phys;
547    jzfb->framedesc->id = 0xdeafbead;
548    jzfb->framedesc->cmd = 0;
549    jzfb->framedesc->cmd |= max_videosize / 4;
550
551    return 0;
552
553err_free_framedesc:
554    dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc),
555                jzfb->framedesc, jzfb->framedesc_phys);
556    return -ENOMEM;
557}
558
559static void jzfb_free_devmem(struct jzfb *jzfb)
560{
561    dma_free_coherent(&jzfb->pdev->dev, jzfb->vidmem_size,
562                jzfb->vidmem, jzfb->vidmem_phys);
563    dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc),
564                jzfb->framedesc, jzfb->framedesc_phys);
565}
566
567static struct fb_ops jzfb_ops = {
568    .owner = THIS_MODULE,
569    .fb_check_var = jzfb_check_var,
570    .fb_set_par = jzfb_set_par,
571    .fb_blank = jzfb_blank,
572    .fb_fillrect = sys_fillrect,
573    .fb_copyarea = sys_copyarea,
574    .fb_imageblit = sys_imageblit,
575    .fb_setcolreg = jzfb_setcolreg,
576};
577
578static int __devinit jzfb_probe(struct platform_device *pdev)
579{
580    int ret;
581    struct jzfb *jzfb;
582    struct fb_info *fb;
583    struct jz4740_fb_platform_data *pdata = pdev->dev.platform_data;
584    struct resource *mem;
585
586    if (!pdata) {
587        dev_err(&pdev->dev, "Missing platform data\n");
588        return -ENOENT;
589    }
590
591    mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
592
593    if (!mem) {
594        dev_err(&pdev->dev, "Failed to get register memory resource\n");
595        return -ENOENT;
596    }
597
598    mem = request_mem_region(mem->start, resource_size(mem), pdev->name);
599
600    if (!mem) {
601        dev_err(&pdev->dev, "Failed to request register memory region\n");
602        return -EBUSY;
603    }
604
605
606    fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev);
607
608    if (!fb) {
609        dev_err(&pdev->dev, "Failed to allocate framebuffer device\n");
610        ret = -ENOMEM;
611        goto err_release_mem_region;
612    }
613
614    fb->fbops = &jzfb_ops;
615    fb->flags = FBINFO_DEFAULT;
616
617    jzfb = fb->par;
618    jzfb->pdev = pdev;
619    jzfb->pdata = pdata;
620    jzfb->mem = mem;
621
622    jzfb->ldclk = clk_get(&pdev->dev, "lcd");
623    jzfb->lpclk = clk_get(&pdev->dev, "lcd_pclk");
624
625    if (IS_ERR(jzfb->ldclk)) {
626        ret = PTR_ERR(jzfb->ldclk);
627        dev_err(&pdev->dev, "Faild to get device clock: %d\n", ret);
628        goto err_framebuffer_release;
629    }
630
631    if (IS_ERR(jzfb->lpclk)) {
632        ret = PTR_ERR(jzfb->ldclk);
633        dev_err(&pdev->dev, "Faild to get pixel clock: %d\n", ret);
634        goto err_framebuffer_release;
635    }
636
637
638    jzfb->base = ioremap(mem->start, resource_size(mem));
639
640    if (!jzfb->base) {
641        dev_err(&pdev->dev, "Failed to ioremap register memory region\n");
642        ret = -EBUSY;
643        goto err_framebuffer_release;
644    }
645
646    platform_set_drvdata(pdev, jzfb);
647
648    fb_videomode_to_modelist(pdata->modes, pdata->num_modes,
649                 &fb->modelist);
650    fb->mode = pdata->modes;
651
652    fb_videomode_to_var(&fb->var, fb->mode);
653    fb->var.bits_per_pixel = pdata->bpp;
654    jzfb_check_var(&fb->var, fb);
655
656    ret = jzfb_alloc_devmem(jzfb);
657    if (ret) {
658        dev_err(&pdev->dev, "Failed to allocate video memory\n");
659        goto err_iounmap;
660    }
661
662    fb->fix = jzfb_fix;
663    fb->fix.line_length = fb->var.bits_per_pixel * fb->var.xres / 8;
664    fb->fix.mmio_start = mem->start;
665    fb->fix.mmio_len = resource_size(mem);
666    fb->fix.smem_start = jzfb->vidmem_phys;
667    fb->fix.smem_len = fb->fix.line_length * fb->var.yres;
668    fb->screen_base = jzfb->vidmem;
669    fb->pseudo_palette = jzfb->pseudo_palette;
670
671    fb_alloc_cmap(&fb->cmap, 256, 0);
672
673    mutex_init(&jzfb->lock);
674
675    clk_enable(jzfb->ldclk);
676    jzfb->is_enabled = 1;
677
678    writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0);
679    jzfb_set_par(fb);
680
681    jz_gpio_bulk_request(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
682    jz_gpio_bulk_request(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
683
684    ret = register_framebuffer(fb);
685    if (ret) {
686        dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret);
687        goto err_free_devmem;
688    }
689
690    jzfb->fb = fb;
691
692    return 0;
693err_free_devmem:
694    jzfb_free_devmem(jzfb);
695err_iounmap:
696    iounmap(jzfb->base);
697err_framebuffer_release:
698    framebuffer_release(fb);
699err_release_mem_region:
700    release_mem_region(mem->start, resource_size(mem));
701    return ret;
702}
703
704static int __devexit jzfb_remove(struct platform_device *pdev)
705{
706    struct jzfb *jzfb = platform_get_drvdata(pdev);
707
708    jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
709    jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
710    iounmap(jzfb->base);
711    release_mem_region(jzfb->mem->start, resource_size(jzfb->mem));
712    jzfb_free_devmem(jzfb);
713    platform_set_drvdata(pdev, NULL);
714    framebuffer_release(jzfb->fb);
715    return 0;
716}
717
718#ifdef CONFIG_PM
719
720static int jzfb_suspend(struct device *dev)
721{
722    struct jzfb *jzfb = dev_get_drvdata(dev);
723
724    acquire_console_sem();
725    fb_set_suspend(jzfb->fb, 1);
726    release_console_sem();
727
728    mutex_lock(&jzfb->lock);
729    if (jzfb->is_enabled)
730        jzfb_disable(jzfb);
731    mutex_unlock(&jzfb->lock);
732
733    return 0;
734}
735
736static int jzfb_resume(struct device *dev)
737{
738    struct jzfb *jzfb = dev_get_drvdata(dev);
739    clk_enable(jzfb->ldclk);
740
741    mutex_lock(&jzfb->lock);
742    if (jzfb->is_enabled)
743        jzfb_enable(jzfb);
744    mutex_unlock(&jzfb->lock);
745
746    acquire_console_sem();
747    fb_set_suspend(jzfb->fb, 0);
748    release_console_sem();
749
750    return 0;
751}
752
753static const struct dev_pm_ops jzfb_pm_ops = {
754    .suspend = jzfb_suspend,
755    .resume = jzfb_resume,
756    .poweroff = jzfb_suspend,
757    .restore = jzfb_resume,
758};
759
760#define JZFB_PM_OPS (&jzfb_pm_ops)
761
762#else
763#define JZFB_PM_OPS NULL
764#endif
765
766static struct platform_driver jzfb_driver = {
767    .probe = jzfb_probe,
768    .remove = __devexit_p(jzfb_remove),
769
770    .driver = {
771        .name = "jz4740-fb",
772        .pm = JZFB_PM_OPS,
773    },
774};
775
776int __init jzfb_init(void)
777{
778    return platform_driver_register(&jzfb_driver);
779}
780module_init(jzfb_init);
781
782void __exit jzfb_exit(void)
783{
784    platform_driver_unregister(&jzfb_driver);
785}
786module_exit(jzfb_exit);
787
788MODULE_LICENSE("GPL");
789MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
790MODULE_DESCRIPTION("JZ4720/JZ4740 SoC LCD framebuffer driver");
791MODULE_ALIAS("platform:jz4740-fb");
792MODULE_ALIAS("platform:jz4720-fb");
include/linux/jz4740_fb.h
1/*
2 * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * You should have received a copy of the GNU General Public License along
10 * with this program; if not, write to the Free Software Foundation, Inc.,
11 * 675 Mass Ave, Cambridge, MA 02139, USA.
12 *
13 */
14
15#ifndef __LINUX_JZ4740_FB_H
16#define __LINUX_JZ4740_FB_H
17
18#include <linux/fb.h>
19
20enum jz4740_fb_lcd_type {
21    JZ_LCD_TYPE_GENERIC_16_BIT = 0,
22    JZ_LCD_TYPE_GENERIC_18_BIT = 0 | (1 << 4),
23    JZ_LCD_TYPE_SPECIAL_TFT_1 = 1,
24    JZ_LCD_TYPE_SPECIAL_TFT_2 = 2,
25    JZ_LCD_TYPE_SPECIAL_TFT_3 = 3,
26    JZ_LCD_TYPE_NON_INTERLACED_CCIR656 = 5,
27    JZ_LCD_TYPE_INTERLACED_CCIR656 = 7,
28    JZ_LCD_TYPE_SINGLE_COLOR_STN = 8,
29    JZ_LCD_TYPE_SINGLE_MONOCHROME_STN = 9,
30    JZ_LCD_TYPE_DUAL_COLOR_STN = 10,
31    JZ_LCD_TYPE_DUAL_MONOCHROME_STN = 11,
32    JZ_LCD_TYPE_8BIT_SERIAL = 12,
33};
34
35/*
36* width: width of the lcd display in mm
37* height: height of the lcd display in mm
38* num_modes: size of modes
39* modes: list of valid video modes
40* bpp: bits per pixel for the lcd
41* lcd_type: lcd type
42*/
43
44struct jz4740_fb_platform_data {
45    unsigned int width;
46    unsigned int height;
47
48    size_t num_modes;
49    struct fb_videomode *modes;
50
51    unsigned int bpp;
52    enum jz4740_fb_lcd_type lcd_type;
53
54    unsigned pixclk_falling_edge:1;
55    unsigned date_enable_active_low:1;
56};
57
58#endif

Archive Download the corresponding diff file



interactive