]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/video/fbdev/jz4740_fb.c
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-jammy-kernel.git] / drivers / video / fbdev / jz4740_fb.c
CommitLineData
a912e80b 1// SPDX-License-Identifier: GPL-2.0-or-later
7a92d545
LPC
2/*
3 * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
4 * JZ4740 SoC LCD framebuffer driver
7a92d545
LPC
5 */
6
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <linux/mutex.h>
10#include <linux/platform_device.h>
695ff985 11#include <linux/pinctrl/consumer.h>
7a92d545
LPC
12
13#include <linux/clk.h>
14#include <linux/delay.h>
15
16#include <linux/console.h>
17#include <linux/fb.h>
18
19#include <linux/dma-mapping.h>
20
21#include <asm/mach-jz4740/jz4740_fb.h>
7a92d545
LPC
22
23#define JZ_REG_LCD_CFG 0x00
24#define JZ_REG_LCD_VSYNC 0x04
25#define JZ_REG_LCD_HSYNC 0x08
26#define JZ_REG_LCD_VAT 0x0C
27#define JZ_REG_LCD_DAH 0x10
28#define JZ_REG_LCD_DAV 0x14
29#define JZ_REG_LCD_PS 0x18
30#define JZ_REG_LCD_CLS 0x1C
31#define JZ_REG_LCD_SPL 0x20
32#define JZ_REG_LCD_REV 0x24
33#define JZ_REG_LCD_CTRL 0x30
34#define JZ_REG_LCD_STATE 0x34
35#define JZ_REG_LCD_IID 0x38
36#define JZ_REG_LCD_DA0 0x40
37#define JZ_REG_LCD_SA0 0x44
38#define JZ_REG_LCD_FID0 0x48
39#define JZ_REG_LCD_CMD0 0x4C
40#define JZ_REG_LCD_DA1 0x50
41#define JZ_REG_LCD_SA1 0x54
42#define JZ_REG_LCD_FID1 0x58
43#define JZ_REG_LCD_CMD1 0x5C
44
45#define JZ_LCD_CFG_SLCD BIT(31)
46#define JZ_LCD_CFG_PS_DISABLE BIT(23)
47#define JZ_LCD_CFG_CLS_DISABLE BIT(22)
48#define JZ_LCD_CFG_SPL_DISABLE BIT(21)
49#define JZ_LCD_CFG_REV_DISABLE BIT(20)
50#define JZ_LCD_CFG_HSYNCM BIT(19)
51#define JZ_LCD_CFG_PCLKM BIT(18)
52#define JZ_LCD_CFG_INV BIT(17)
53#define JZ_LCD_CFG_SYNC_DIR BIT(16)
54#define JZ_LCD_CFG_PS_POLARITY BIT(15)
55#define JZ_LCD_CFG_CLS_POLARITY BIT(14)
56#define JZ_LCD_CFG_SPL_POLARITY BIT(13)
57#define JZ_LCD_CFG_REV_POLARITY BIT(12)
58#define JZ_LCD_CFG_HSYNC_ACTIVE_LOW BIT(11)
59#define JZ_LCD_CFG_PCLK_FALLING_EDGE BIT(10)
60#define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9)
61#define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8)
62#define JZ_LCD_CFG_18_BIT BIT(7)
63#define JZ_LCD_CFG_PDW (BIT(5) | BIT(4))
64#define JZ_LCD_CFG_MODE_MASK 0xf
65
66#define JZ_LCD_CTRL_BURST_4 (0x0 << 28)
67#define JZ_LCD_CTRL_BURST_8 (0x1 << 28)
68#define JZ_LCD_CTRL_BURST_16 (0x2 << 28)
69#define JZ_LCD_CTRL_RGB555 BIT(27)
70#define JZ_LCD_CTRL_OFUP BIT(26)
71#define JZ_LCD_CTRL_FRC_GRAYSCALE_16 (0x0 << 24)
72#define JZ_LCD_CTRL_FRC_GRAYSCALE_4 (0x1 << 24)
73#define JZ_LCD_CTRL_FRC_GRAYSCALE_2 (0x2 << 24)
74#define JZ_LCD_CTRL_PDD_MASK (0xff << 16)
75#define JZ_LCD_CTRL_EOF_IRQ BIT(13)
76#define JZ_LCD_CTRL_SOF_IRQ BIT(12)
77#define JZ_LCD_CTRL_OFU_IRQ BIT(11)
78#define JZ_LCD_CTRL_IFU0_IRQ BIT(10)
79#define JZ_LCD_CTRL_IFU1_IRQ BIT(9)
80#define JZ_LCD_CTRL_DD_IRQ BIT(8)
81#define JZ_LCD_CTRL_QDD_IRQ BIT(7)
82#define JZ_LCD_CTRL_REVERSE_ENDIAN BIT(6)
83#define JZ_LCD_CTRL_LSB_FISRT BIT(5)
84#define JZ_LCD_CTRL_DISABLE BIT(4)
85#define JZ_LCD_CTRL_ENABLE BIT(3)
86#define JZ_LCD_CTRL_BPP_1 0x0
87#define JZ_LCD_CTRL_BPP_2 0x1
88#define JZ_LCD_CTRL_BPP_4 0x2
89#define JZ_LCD_CTRL_BPP_8 0x3
90#define JZ_LCD_CTRL_BPP_15_16 0x4
91#define JZ_LCD_CTRL_BPP_18_24 0x5
92
8a519c43
LPC
93#define JZ_LCD_CMD_SOF_IRQ BIT(31)
94#define JZ_LCD_CMD_EOF_IRQ BIT(30)
95#define JZ_LCD_CMD_ENABLE_PAL BIT(28)
7a92d545
LPC
96
97#define JZ_LCD_SYNC_MASK 0x3ff
98
99#define JZ_LCD_STATE_DISABLED BIT(0)
100
101struct jzfb_framedesc {
102 uint32_t next;
103 uint32_t addr;
104 uint32_t id;
105 uint32_t cmd;
106} __packed;
107
108struct jzfb {
109 struct fb_info *fb;
110 struct platform_device *pdev;
111 void __iomem *base;
112 struct resource *mem;
113 struct jz4740_fb_platform_data *pdata;
114
115 size_t vidmem_size;
116 void *vidmem;
117 dma_addr_t vidmem_phys;
118 struct jzfb_framedesc *framedesc;
119 dma_addr_t framedesc_phys;
120
121 struct clk *ldclk;
122 struct clk *lpclk;
123
124 unsigned is_enabled:1;
125 struct mutex lock;
126
127 uint32_t pseudo_palette[16];
128};
129
48c68c4f 130static const struct fb_fix_screeninfo jzfb_fix = {
7a92d545
LPC
131 .id = "JZ4740 FB",
132 .type = FB_TYPE_PACKED_PIXELS,
133 .visual = FB_VISUAL_TRUECOLOR,
134 .xpanstep = 0,
135 .ypanstep = 0,
136 .ywrapstep = 0,
137 .accel = FB_ACCEL_NONE,
138};
139
7a92d545
LPC
140/* Based on CNVT_TOHW macro from skeletonfb.c */
141static inline uint32_t jzfb_convert_color_to_hw(unsigned val,
142 struct fb_bitfield *bf)
143{
144 return (((val << bf->length) + 0x7FFF - val) >> 16) << bf->offset;
145}
146
147static int jzfb_setcolreg(unsigned regno, unsigned red, unsigned green,
148 unsigned blue, unsigned transp, struct fb_info *fb)
149{
150 uint32_t color;
151
152 if (regno >= 16)
153 return -EINVAL;
154
155 color = jzfb_convert_color_to_hw(red, &fb->var.red);
156 color |= jzfb_convert_color_to_hw(green, &fb->var.green);
157 color |= jzfb_convert_color_to_hw(blue, &fb->var.blue);
158 color |= jzfb_convert_color_to_hw(transp, &fb->var.transp);
159
160 ((uint32_t *)(fb->pseudo_palette))[regno] = color;
161
162 return 0;
163}
164
165static int jzfb_get_controller_bpp(struct jzfb *jzfb)
166{
167 switch (jzfb->pdata->bpp) {
168 case 18:
169 case 24:
170 return 32;
171 case 15:
172 return 16;
173 default:
174 return jzfb->pdata->bpp;
175 }
176}
177
178static struct fb_videomode *jzfb_get_mode(struct jzfb *jzfb,
179 struct fb_var_screeninfo *var)
180{
181 size_t i;
182 struct fb_videomode *mode = jzfb->pdata->modes;
183
184 for (i = 0; i < jzfb->pdata->num_modes; ++i, ++mode) {
185 if (mode->xres == var->xres && mode->yres == var->yres)
186 return mode;
187 }
188
189 return NULL;
190}
191
192static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb)
193{
194 struct jzfb *jzfb = fb->par;
195 struct fb_videomode *mode;
196
197 if (var->bits_per_pixel != jzfb_get_controller_bpp(jzfb) &&
198 var->bits_per_pixel != jzfb->pdata->bpp)
199 return -EINVAL;
200
201 mode = jzfb_get_mode(jzfb, var);
202 if (mode == NULL)
203 return -EINVAL;
204
205 fb_videomode_to_var(var, mode);
206
207 switch (jzfb->pdata->bpp) {
208 case 8:
209 break;
210 case 15:
211 var->red.offset = 10;
212 var->red.length = 5;
213 var->green.offset = 6;
214 var->green.length = 5;
215 var->blue.offset = 0;
216 var->blue.length = 5;
217 break;
218 case 16:
219 var->red.offset = 11;
220 var->red.length = 5;
221 var->green.offset = 5;
222 var->green.length = 6;
223 var->blue.offset = 0;
224 var->blue.length = 5;
225 break;
226 case 18:
227 var->red.offset = 16;
228 var->red.length = 6;
229 var->green.offset = 8;
230 var->green.length = 6;
231 var->blue.offset = 0;
232 var->blue.length = 6;
233 var->bits_per_pixel = 32;
234 break;
235 case 32:
236 case 24:
237 var->transp.offset = 24;
238 var->transp.length = 8;
239 var->red.offset = 16;
240 var->red.length = 8;
241 var->green.offset = 8;
242 var->green.length = 8;
243 var->blue.offset = 0;
244 var->blue.length = 8;
245 var->bits_per_pixel = 32;
246 break;
247 default:
248 break;
249 }
250
251 return 0;
252}
253
254static int jzfb_set_par(struct fb_info *info)
255{
256 struct jzfb *jzfb = info->par;
257 struct jz4740_fb_platform_data *pdata = jzfb->pdata;
258 struct fb_var_screeninfo *var = &info->var;
259 struct fb_videomode *mode;
260 uint16_t hds, vds;
261 uint16_t hde, vde;
262 uint16_t ht, vt;
263 uint32_t ctrl;
264 uint32_t cfg;
265 unsigned long rate;
266
267 mode = jzfb_get_mode(jzfb, var);
268 if (mode == NULL)
269 return -EINVAL;
270
271 if (mode == info->mode)
272 return 0;
273
274 info->mode = mode;
275
276 hds = mode->hsync_len + mode->left_margin;
277 hde = hds + mode->xres;
278 ht = hde + mode->right_margin;
279
280 vds = mode->vsync_len + mode->upper_margin;
281 vde = vds + mode->yres;
282 vt = vde + mode->lower_margin;
283
284 ctrl = JZ_LCD_CTRL_OFUP | JZ_LCD_CTRL_BURST_16;
285
286 switch (pdata->bpp) {
287 case 1:
288 ctrl |= JZ_LCD_CTRL_BPP_1;
289 break;
290 case 2:
291 ctrl |= JZ_LCD_CTRL_BPP_2;
292 break;
293 case 4:
294 ctrl |= JZ_LCD_CTRL_BPP_4;
295 break;
296 case 8:
297 ctrl |= JZ_LCD_CTRL_BPP_8;
298 break;
299 case 15:
300 ctrl |= JZ_LCD_CTRL_RGB555; /* Falltrough */
301 case 16:
302 ctrl |= JZ_LCD_CTRL_BPP_15_16;
303 break;
304 case 18:
305 case 24:
306 case 32:
307 ctrl |= JZ_LCD_CTRL_BPP_18_24;
308 break;
309 default:
310 break;
311 }
312
313 cfg = pdata->lcd_type & 0xf;
314
315 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
316 cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW;
317
318 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
319 cfg |= JZ_LCD_CFG_VSYNC_ACTIVE_LOW;
320
321 if (pdata->pixclk_falling_edge)
322 cfg |= JZ_LCD_CFG_PCLK_FALLING_EDGE;
323
324 if (pdata->date_enable_active_low)
325 cfg |= JZ_LCD_CFG_DE_ACTIVE_LOW;
326
327 if (pdata->lcd_type == JZ_LCD_TYPE_GENERIC_18_BIT)
328 cfg |= JZ_LCD_CFG_18_BIT;
329
330 if (mode->pixclock) {
331 rate = PICOS2KHZ(mode->pixclock) * 1000;
332 mode->refresh = rate / vt / ht;
333 } else {
334 if (pdata->lcd_type == JZ_LCD_TYPE_8BIT_SERIAL)
335 rate = mode->refresh * (vt + 2 * mode->xres) * ht;
336 else
337 rate = mode->refresh * vt * ht;
338
339 mode->pixclock = KHZ2PICOS(rate / 1000);
340 }
341
342 mutex_lock(&jzfb->lock);
343 if (!jzfb->is_enabled)
344 clk_enable(jzfb->ldclk);
345 else
346 ctrl |= JZ_LCD_CTRL_ENABLE;
347
348 switch (pdata->lcd_type) {
349 case JZ_LCD_TYPE_SPECIAL_TFT_1:
350 case JZ_LCD_TYPE_SPECIAL_TFT_2:
351 case JZ_LCD_TYPE_SPECIAL_TFT_3:
352 writel(pdata->special_tft_config.spl, jzfb->base + JZ_REG_LCD_SPL);
353 writel(pdata->special_tft_config.cls, jzfb->base + JZ_REG_LCD_CLS);
354 writel(pdata->special_tft_config.ps, jzfb->base + JZ_REG_LCD_PS);
355 writel(pdata->special_tft_config.ps, jzfb->base + JZ_REG_LCD_REV);
356 break;
357 default:
358 cfg |= JZ_LCD_CFG_PS_DISABLE;
359 cfg |= JZ_LCD_CFG_CLS_DISABLE;
360 cfg |= JZ_LCD_CFG_SPL_DISABLE;
361 cfg |= JZ_LCD_CFG_REV_DISABLE;
362 break;
363 }
364
365 writel(mode->hsync_len, jzfb->base + JZ_REG_LCD_HSYNC);
366 writel(mode->vsync_len, jzfb->base + JZ_REG_LCD_VSYNC);
367
368 writel((ht << 16) | vt, jzfb->base + JZ_REG_LCD_VAT);
369
370 writel((hds << 16) | hde, jzfb->base + JZ_REG_LCD_DAH);
371 writel((vds << 16) | vde, jzfb->base + JZ_REG_LCD_DAV);
372
373 writel(cfg, jzfb->base + JZ_REG_LCD_CFG);
374
375 writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL);
376
377 if (!jzfb->is_enabled)
aeac9e3f 378 clk_disable_unprepare(jzfb->ldclk);
7a92d545
LPC
379
380 mutex_unlock(&jzfb->lock);
381
382 clk_set_rate(jzfb->lpclk, rate);
383 clk_set_rate(jzfb->ldclk, rate * 3);
384
385 return 0;
386}
387
388static void jzfb_enable(struct jzfb *jzfb)
389{
390 uint32_t ctrl;
391
aeac9e3f 392 clk_prepare_enable(jzfb->ldclk);
7a92d545 393
695ff985 394 pinctrl_pm_select_default_state(&jzfb->pdev->dev);
7a92d545
LPC
395
396 writel(0, jzfb->base + JZ_REG_LCD_STATE);
397
398 writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0);
399
400 ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL);
401 ctrl |= JZ_LCD_CTRL_ENABLE;
402 ctrl &= ~JZ_LCD_CTRL_DISABLE;
403 writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL);
404}
405
406static void jzfb_disable(struct jzfb *jzfb)
407{
408 uint32_t ctrl;
409
410 ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL);
411 ctrl |= JZ_LCD_CTRL_DISABLE;
412 writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL);
413 do {
414 ctrl = readl(jzfb->base + JZ_REG_LCD_STATE);
415 } while (!(ctrl & JZ_LCD_STATE_DISABLED));
416
695ff985 417 pinctrl_pm_select_sleep_state(&jzfb->pdev->dev);
7a92d545 418
aeac9e3f 419 clk_disable_unprepare(jzfb->ldclk);
7a92d545
LPC
420}
421
422static int jzfb_blank(int blank_mode, struct fb_info *info)
423{
424 struct jzfb *jzfb = info->par;
425
426 switch (blank_mode) {
427 case FB_BLANK_UNBLANK:
428 mutex_lock(&jzfb->lock);
429 if (jzfb->is_enabled) {
430 mutex_unlock(&jzfb->lock);
431 return 0;
432 }
433
434 jzfb_enable(jzfb);
435 jzfb->is_enabled = 1;
436
437 mutex_unlock(&jzfb->lock);
438 break;
439 default:
440 mutex_lock(&jzfb->lock);
441 if (!jzfb->is_enabled) {
442 mutex_unlock(&jzfb->lock);
443 return 0;
444 }
445
446 jzfb_disable(jzfb);
447 jzfb->is_enabled = 0;
448
449 mutex_unlock(&jzfb->lock);
450 break;
451 }
452
453 return 0;
454}
455
456static int jzfb_alloc_devmem(struct jzfb *jzfb)
457{
458 int max_videosize = 0;
459 struct fb_videomode *mode = jzfb->pdata->modes;
460 void *page;
461 int i;
462
463 for (i = 0; i < jzfb->pdata->num_modes; ++mode, ++i) {
464 if (max_videosize < mode->xres * mode->yres)
465 max_videosize = mode->xres * mode->yres;
466 }
467
468 max_videosize *= jzfb_get_controller_bpp(jzfb) >> 3;
469
470 jzfb->framedesc = dma_alloc_coherent(&jzfb->pdev->dev,
471 sizeof(*jzfb->framedesc),
472 &jzfb->framedesc_phys, GFP_KERNEL);
473
474 if (!jzfb->framedesc)
475 return -ENOMEM;
476
477 jzfb->vidmem_size = PAGE_ALIGN(max_videosize);
478 jzfb->vidmem = dma_alloc_coherent(&jzfb->pdev->dev,
479 jzfb->vidmem_size,
480 &jzfb->vidmem_phys, GFP_KERNEL);
481
482 if (!jzfb->vidmem)
483 goto err_free_framedesc;
484
485 for (page = jzfb->vidmem;
486 page < jzfb->vidmem + PAGE_ALIGN(jzfb->vidmem_size);
487 page += PAGE_SIZE) {
488 SetPageReserved(virt_to_page(page));
489 }
490
491 jzfb->framedesc->next = jzfb->framedesc_phys;
492 jzfb->framedesc->addr = jzfb->vidmem_phys;
493 jzfb->framedesc->id = 0xdeafbead;
494 jzfb->framedesc->cmd = 0;
495 jzfb->framedesc->cmd |= max_videosize / 4;
496
497 return 0;
498
499err_free_framedesc:
500 dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc),
501 jzfb->framedesc, jzfb->framedesc_phys);
502 return -ENOMEM;
503}
504
505static void jzfb_free_devmem(struct jzfb *jzfb)
506{
507 dma_free_coherent(&jzfb->pdev->dev, jzfb->vidmem_size,
508 jzfb->vidmem, jzfb->vidmem_phys);
509 dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc),
510 jzfb->framedesc, jzfb->framedesc_phys);
511}
512
513static struct fb_ops jzfb_ops = {
514 .owner = THIS_MODULE,
515 .fb_check_var = jzfb_check_var,
516 .fb_set_par = jzfb_set_par,
517 .fb_blank = jzfb_blank,
518 .fb_fillrect = sys_fillrect,
519 .fb_copyarea = sys_copyarea,
520 .fb_imageblit = sys_imageblit,
521 .fb_setcolreg = jzfb_setcolreg,
522};
523
48c68c4f 524static int jzfb_probe(struct platform_device *pdev)
7a92d545
LPC
525{
526 int ret;
527 struct jzfb *jzfb;
528 struct fb_info *fb;
529 struct jz4740_fb_platform_data *pdata = pdev->dev.platform_data;
530 struct resource *mem;
531
532 if (!pdata) {
533 dev_err(&pdev->dev, "Missing platform data\n");
534 return -ENXIO;
535 }
536
7a92d545
LPC
537 fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev);
538 if (!fb) {
539 dev_err(&pdev->dev, "Failed to allocate framebuffer device\n");
b5d4190f 540 return -ENOMEM;
7a92d545
LPC
541 }
542
543 fb->fbops = &jzfb_ops;
544 fb->flags = FBINFO_DEFAULT;
545
546 jzfb = fb->par;
547 jzfb->pdev = pdev;
548 jzfb->pdata = pdata;
7a92d545 549
b2ca7f4d 550 jzfb->ldclk = devm_clk_get(&pdev->dev, "lcd");
7a92d545
LPC
551 if (IS_ERR(jzfb->ldclk)) {
552 ret = PTR_ERR(jzfb->ldclk);
553 dev_err(&pdev->dev, "Failed to get lcd clock: %d\n", ret);
554 goto err_framebuffer_release;
555 }
556
b2ca7f4d 557 jzfb->lpclk = devm_clk_get(&pdev->dev, "lcd_pclk");
7a92d545
LPC
558 if (IS_ERR(jzfb->lpclk)) {
559 ret = PTR_ERR(jzfb->lpclk);
560 dev_err(&pdev->dev, "Failed to get lcd pixel clock: %d\n", ret);
b2ca7f4d 561 goto err_framebuffer_release;
7a92d545
LPC
562 }
563
b5d4190f 564 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
bc3bad16
TR
565 jzfb->base = devm_ioremap_resource(&pdev->dev, mem);
566 if (IS_ERR(jzfb->base)) {
567 ret = PTR_ERR(jzfb->base);
b2ca7f4d 568 goto err_framebuffer_release;
7a92d545
LPC
569 }
570
571 platform_set_drvdata(pdev, jzfb);
572
573 mutex_init(&jzfb->lock);
574
575 fb_videomode_to_modelist(pdata->modes, pdata->num_modes,
576 &fb->modelist);
577 fb_videomode_to_var(&fb->var, pdata->modes);
578 fb->var.bits_per_pixel = pdata->bpp;
579 jzfb_check_var(&fb->var, fb);
580
581 ret = jzfb_alloc_devmem(jzfb);
582 if (ret) {
583 dev_err(&pdev->dev, "Failed to allocate video memory\n");
b2ca7f4d 584 goto err_framebuffer_release;
7a92d545
LPC
585 }
586
587 fb->fix = jzfb_fix;
588 fb->fix.line_length = fb->var.bits_per_pixel * fb->var.xres / 8;
589 fb->fix.mmio_start = mem->start;
590 fb->fix.mmio_len = resource_size(mem);
591 fb->fix.smem_start = jzfb->vidmem_phys;
592 fb->fix.smem_len = fb->fix.line_length * fb->var.yres;
593 fb->screen_base = jzfb->vidmem;
594 fb->pseudo_palette = jzfb->pseudo_palette;
595
596 fb_alloc_cmap(&fb->cmap, 256, 0);
597
aeac9e3f 598 clk_prepare_enable(jzfb->ldclk);
7a92d545
LPC
599 jzfb->is_enabled = 1;
600
601 writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0);
602
603 fb->mode = NULL;
604 jzfb_set_par(fb);
605
7a92d545
LPC
606 ret = register_framebuffer(fb);
607 if (ret) {
608 dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret);
609 goto err_free_devmem;
610 }
611
612 jzfb->fb = fb;
613
614 return 0;
615
616err_free_devmem:
7a92d545
LPC
617 fb_dealloc_cmap(&fb->cmap);
618 jzfb_free_devmem(jzfb);
7a92d545
LPC
619err_framebuffer_release:
620 framebuffer_release(fb);
7a92d545
LPC
621 return ret;
622}
623
48c68c4f 624static int jzfb_remove(struct platform_device *pdev)
7a92d545
LPC
625{
626 struct jzfb *jzfb = platform_get_drvdata(pdev);
627
628 jzfb_blank(FB_BLANK_POWERDOWN, jzfb->fb);
629
7a92d545
LPC
630 fb_dealloc_cmap(&jzfb->fb->cmap);
631 jzfb_free_devmem(jzfb);
632
7a92d545
LPC
633 framebuffer_release(jzfb->fb);
634
635 return 0;
636}
637
638#ifdef CONFIG_PM
639
640static int jzfb_suspend(struct device *dev)
641{
642 struct jzfb *jzfb = dev_get_drvdata(dev);
643
ac751efa 644 console_lock();
7a92d545 645 fb_set_suspend(jzfb->fb, 1);
ac751efa 646 console_unlock();
7a92d545
LPC
647
648 mutex_lock(&jzfb->lock);
649 if (jzfb->is_enabled)
650 jzfb_disable(jzfb);
651 mutex_unlock(&jzfb->lock);
652
653 return 0;
654}
655
656static int jzfb_resume(struct device *dev)
657{
658 struct jzfb *jzfb = dev_get_drvdata(dev);
aeac9e3f 659 clk_prepare_enable(jzfb->ldclk);
7a92d545
LPC
660
661 mutex_lock(&jzfb->lock);
662 if (jzfb->is_enabled)
663 jzfb_enable(jzfb);
664 mutex_unlock(&jzfb->lock);
665
ac751efa 666 console_lock();
7a92d545 667 fb_set_suspend(jzfb->fb, 0);
ac751efa 668 console_unlock();
7a92d545
LPC
669
670 return 0;
671}
672
673static const struct dev_pm_ops jzfb_pm_ops = {
674 .suspend = jzfb_suspend,
675 .resume = jzfb_resume,
676 .poweroff = jzfb_suspend,
677 .restore = jzfb_resume,
678};
679
680#define JZFB_PM_OPS (&jzfb_pm_ops)
681
682#else
683#define JZFB_PM_OPS NULL
684#endif
685
686static struct platform_driver jzfb_driver = {
687 .probe = jzfb_probe,
48c68c4f 688 .remove = jzfb_remove,
7a92d545
LPC
689 .driver = {
690 .name = "jz4740-fb",
691 .pm = JZFB_PM_OPS,
692 },
693};
5fc89379 694module_platform_driver(jzfb_driver);
7a92d545
LPC
695
696MODULE_LICENSE("GPL");
697MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
698MODULE_DESCRIPTION("JZ4740 SoC LCD framebuffer driver");
699MODULE_ALIAS("platform:jz4740-fb");