1
2
3
4
5
6
7
8
9
10
11#include <linux/atomic.h>
12#include <linux/backlight.h>
13#include <linux/clk.h>
14#include <linux/console.h>
15#include <linux/ctype.h>
16#include <linux/dma-mapping.h>
17#include <linux/delay.h>
18#include <linux/gpio.h>
19#include <linux/init.h>
20#include <linux/interrupt.h>
21#include <linux/ioctl.h>
22#include <linux/kernel.h>
23#include <linux/mm.h>
24#include <linux/module.h>
25#include <linux/platform_device.h>
26#include <linux/pm_runtime.h>
27#include <linux/slab.h>
28#include <linux/videodev2.h>
29#include <linux/vmalloc.h>
30
31#include <video/sh_mobile_lcdc.h>
32#include <video/sh_mobile_meram.h>
33
34#include "sh_mobile_lcdcfb.h"
35
36
37
38
39
40#define LDBCR 0xb00
41#define LDBCR_UPC(n) (1 << ((n) + 16))
42#define LDBCR_UPF(n) (1 << ((n) + 8))
43#define LDBCR_UPD(n) (1 << ((n) + 0))
44#define LDBnBSIFR(n) (0xb20 + (n) * 0x20 + 0x00)
45#define LDBBSIFR_EN (1 << 31)
46#define LDBBSIFR_VS (1 << 29)
47#define LDBBSIFR_BRSEL (1 << 28)
48#define LDBBSIFR_MX (1 << 27)
49#define LDBBSIFR_MY (1 << 26)
50#define LDBBSIFR_CV3 (3 << 24)
51#define LDBBSIFR_CV2 (2 << 24)
52#define LDBBSIFR_CV1 (1 << 24)
53#define LDBBSIFR_CV0 (0 << 24)
54#define LDBBSIFR_CV_MASK (3 << 24)
55#define LDBBSIFR_LAY_MASK (0xff << 16)
56#define LDBBSIFR_LAY_SHIFT 16
57#define LDBBSIFR_ROP3_MASK (0xff << 16)
58#define LDBBSIFR_ROP3_SHIFT 16
59#define LDBBSIFR_AL_PL8 (3 << 14)
60#define LDBBSIFR_AL_PL1 (2 << 14)
61#define LDBBSIFR_AL_PK (1 << 14)
62#define LDBBSIFR_AL_1 (0 << 14)
63#define LDBBSIFR_AL_MASK (3 << 14)
64#define LDBBSIFR_SWPL (1 << 10)
65#define LDBBSIFR_SWPW (1 << 9)
66#define LDBBSIFR_SWPB (1 << 8)
67#define LDBBSIFR_RY (1 << 7)
68#define LDBBSIFR_CHRR_420 (2 << 0)
69#define LDBBSIFR_CHRR_422 (1 << 0)
70#define LDBBSIFR_CHRR_444 (0 << 0)
71#define LDBBSIFR_RPKF_ARGB32 (0x00 << 0)
72#define LDBBSIFR_RPKF_RGB16 (0x03 << 0)
73#define LDBBSIFR_RPKF_RGB24 (0x0b << 0)
74#define LDBBSIFR_RPKF_MASK (0x1f << 0)
75#define LDBnBSSZR(n) (0xb20 + (n) * 0x20 + 0x04)
76#define LDBBSSZR_BVSS_MASK (0xfff << 16)
77#define LDBBSSZR_BVSS_SHIFT 16
78#define LDBBSSZR_BHSS_MASK (0xfff << 0)
79#define LDBBSSZR_BHSS_SHIFT 0
80#define LDBnBLOCR(n) (0xb20 + (n) * 0x20 + 0x08)
81#define LDBBLOCR_CVLC_MASK (0xfff << 16)
82#define LDBBLOCR_CVLC_SHIFT 16
83#define LDBBLOCR_CHLC_MASK (0xfff << 0)
84#define LDBBLOCR_CHLC_SHIFT 0
85#define LDBnBSMWR(n) (0xb20 + (n) * 0x20 + 0x0c)
86#define LDBBSMWR_BSMWA_MASK (0xffff << 16)
87#define LDBBSMWR_BSMWA_SHIFT 16
88#define LDBBSMWR_BSMW_MASK (0xffff << 0)
89#define LDBBSMWR_BSMW_SHIFT 0
90#define LDBnBSAYR(n) (0xb20 + (n) * 0x20 + 0x10)
91#define LDBBSAYR_FG1A_MASK (0xff << 24)
92#define LDBBSAYR_FG1A_SHIFT 24
93#define LDBBSAYR_FG1R_MASK (0xff << 16)
94#define LDBBSAYR_FG1R_SHIFT 16
95#define LDBBSAYR_FG1G_MASK (0xff << 8)
96#define LDBBSAYR_FG1G_SHIFT 8
97#define LDBBSAYR_FG1B_MASK (0xff << 0)
98#define LDBBSAYR_FG1B_SHIFT 0
99#define LDBnBSACR(n) (0xb20 + (n) * 0x20 + 0x14)
100#define LDBBSACR_FG2A_MASK (0xff << 24)
101#define LDBBSACR_FG2A_SHIFT 24
102#define LDBBSACR_FG2R_MASK (0xff << 16)
103#define LDBBSACR_FG2R_SHIFT 16
104#define LDBBSACR_FG2G_MASK (0xff << 8)
105#define LDBBSACR_FG2G_SHIFT 8
106#define LDBBSACR_FG2B_MASK (0xff << 0)
107#define LDBBSACR_FG2B_SHIFT 0
108#define LDBnBSAAR(n) (0xb20 + (n) * 0x20 + 0x18)
109#define LDBBSAAR_AP_MASK (0xff << 24)
110#define LDBBSAAR_AP_SHIFT 24
111#define LDBBSAAR_R_MASK (0xff << 16)
112#define LDBBSAAR_R_SHIFT 16
113#define LDBBSAAR_GY_MASK (0xff << 8)
114#define LDBBSAAR_GY_SHIFT 8
115#define LDBBSAAR_B_MASK (0xff << 0)
116#define LDBBSAAR_B_SHIFT 0
117#define LDBnBPPCR(n) (0xb20 + (n) * 0x20 + 0x1c)
118#define LDBBPPCR_AP_MASK (0xff << 24)
119#define LDBBPPCR_AP_SHIFT 24
120#define LDBBPPCR_R_MASK (0xff << 16)
121#define LDBBPPCR_R_SHIFT 16
122#define LDBBPPCR_GY_MASK (0xff << 8)
123#define LDBBPPCR_GY_SHIFT 8
124#define LDBBPPCR_B_MASK (0xff << 0)
125#define LDBBPPCR_B_SHIFT 0
126#define LDBnBBGCL(n) (0xb10 + (n) * 0x04)
127#define LDBBBGCL_BGA_MASK (0xff << 24)
128#define LDBBBGCL_BGA_SHIFT 24
129#define LDBBBGCL_BGR_MASK (0xff << 16)
130#define LDBBBGCL_BGR_SHIFT 16
131#define LDBBBGCL_BGG_MASK (0xff << 8)
132#define LDBBBGCL_BGG_SHIFT 8
133#define LDBBBGCL_BGB_MASK (0xff << 0)
134#define LDBBBGCL_BGB_SHIFT 0
135
136#define SIDE_B_OFFSET 0x1000
137#define MIRROR_OFFSET 0x2000
138
139#define MAX_XRES 1920
140#define MAX_YRES 1080
141
142enum sh_mobile_lcdc_overlay_mode {
143 LCDC_OVERLAY_BLEND,
144 LCDC_OVERLAY_ROP3,
145};
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174struct sh_mobile_lcdc_overlay {
175 struct sh_mobile_lcdc_chan *channel;
176
177 const struct sh_mobile_lcdc_overlay_cfg *cfg;
178 struct fb_info *info;
179
180 unsigned int index;
181 unsigned long base;
182
183 bool enabled;
184 enum sh_mobile_lcdc_overlay_mode mode;
185 unsigned int alpha;
186 unsigned int rop3;
187
188 void *fb_mem;
189 unsigned long fb_size;
190
191 dma_addr_t dma_handle;
192 unsigned long base_addr_y;
193 unsigned long base_addr_c;
194 unsigned long pan_y_offset;
195
196 const struct sh_mobile_lcdc_format_info *format;
197 unsigned int xres;
198 unsigned int xres_virtual;
199 unsigned int yres;
200 unsigned int yres_virtual;
201 unsigned int pitch;
202 int pos_x;
203 int pos_y;
204};
205
206struct sh_mobile_lcdc_priv {
207 void __iomem *base;
208 int irq;
209 atomic_t hw_usecnt;
210 struct device *dev;
211 struct clk *dot_clk;
212 unsigned long lddckr;
213
214 struct sh_mobile_lcdc_chan ch[2];
215 struct sh_mobile_lcdc_overlay overlays[4];
216
217 struct notifier_block notifier;
218 int started;
219 int forced_fourcc;
220 struct sh_mobile_meram_info *meram_dev;
221};
222
223
224
225
226
227static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = {
228 [LDDCKPAT1R] = 0x400,
229 [LDDCKPAT2R] = 0x404,
230 [LDMT1R] = 0x418,
231 [LDMT2R] = 0x41c,
232 [LDMT3R] = 0x420,
233 [LDDFR] = 0x424,
234 [LDSM1R] = 0x428,
235 [LDSM2R] = 0x42c,
236 [LDSA1R] = 0x430,
237 [LDSA2R] = 0x434,
238 [LDMLSR] = 0x438,
239 [LDHCNR] = 0x448,
240 [LDHSYNR] = 0x44c,
241 [LDVLNR] = 0x450,
242 [LDVSYNR] = 0x454,
243 [LDPMR] = 0x460,
244 [LDHAJR] = 0x4a0,
245};
246
247static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {
248 [LDDCKPAT1R] = 0x408,
249 [LDDCKPAT2R] = 0x40c,
250 [LDMT1R] = 0x600,
251 [LDMT2R] = 0x604,
252 [LDMT3R] = 0x608,
253 [LDDFR] = 0x60c,
254 [LDSM1R] = 0x610,
255 [LDSM2R] = 0x614,
256 [LDSA1R] = 0x618,
257 [LDMLSR] = 0x620,
258 [LDHCNR] = 0x624,
259 [LDHSYNR] = 0x628,
260 [LDVLNR] = 0x62c,
261 [LDVSYNR] = 0x630,
262 [LDPMR] = 0x63c,
263};
264
265static bool banked(int reg_nr)
266{
267 switch (reg_nr) {
268 case LDMT1R:
269 case LDMT2R:
270 case LDMT3R:
271 case LDDFR:
272 case LDSM1R:
273 case LDSA1R:
274 case LDSA2R:
275 case LDMLSR:
276 case LDHCNR:
277 case LDHSYNR:
278 case LDVLNR:
279 case LDVSYNR:
280 return true;
281 }
282 return false;
283}
284
285static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan)
286{
287 return chan->cfg->chan == LCDC_CHAN_SUBLCD;
288}
289
290static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan,
291 int reg_nr, unsigned long data)
292{
293 iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr]);
294 if (banked(reg_nr))
295 iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] +
296 SIDE_B_OFFSET);
297}
298
299static void lcdc_write_chan_mirror(struct sh_mobile_lcdc_chan *chan,
300 int reg_nr, unsigned long data)
301{
302 iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] +
303 MIRROR_OFFSET);
304}
305
306static unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan,
307 int reg_nr)
308{
309 return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]);
310}
311
312static void lcdc_write_overlay(struct sh_mobile_lcdc_overlay *ovl,
313 int reg, unsigned long data)
314{
315 iowrite32(data, ovl->channel->lcdc->base + reg);
316 iowrite32(data, ovl->channel->lcdc->base + reg + SIDE_B_OFFSET);
317}
318
319static void lcdc_write(struct sh_mobile_lcdc_priv *priv,
320 unsigned long reg_offs, unsigned long data)
321{
322 iowrite32(data, priv->base + reg_offs);
323}
324
325static unsigned long lcdc_read(struct sh_mobile_lcdc_priv *priv,
326 unsigned long reg_offs)
327{
328 return ioread32(priv->base + reg_offs);
329}
330
331static void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv,
332 unsigned long reg_offs,
333 unsigned long mask, unsigned long until)
334{
335 while ((lcdc_read(priv, reg_offs) & mask) != until)
336 cpu_relax();
337}
338
339
340
341
342
343static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
344{
345 if (atomic_inc_and_test(&priv->hw_usecnt)) {
346 if (priv->dot_clk)
347 clk_prepare_enable(priv->dot_clk);
348 pm_runtime_get_sync(priv->dev);
349 if (priv->meram_dev && priv->meram_dev->pdev)
350 pm_runtime_get_sync(&priv->meram_dev->pdev->dev);
351 }
352}
353
354static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
355{
356 if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {
357 if (priv->meram_dev && priv->meram_dev->pdev)
358 pm_runtime_put_sync(&priv->meram_dev->pdev->dev);
359 pm_runtime_put(priv->dev);
360 if (priv->dot_clk)
361 clk_disable_unprepare(priv->dot_clk);
362 }
363}
364
365static int sh_mobile_lcdc_setup_clocks(struct sh_mobile_lcdc_priv *priv,
366 int clock_source)
367{
368 struct clk *clk;
369 char *str;
370
371 switch (clock_source) {
372 case LCDC_CLK_BUS:
373 str = "bus_clk";
374 priv->lddckr = LDDCKR_ICKSEL_BUS;
375 break;
376 case LCDC_CLK_PERIPHERAL:
377 str = "peripheral_clk";
378 priv->lddckr = LDDCKR_ICKSEL_MIPI;
379 break;
380 case LCDC_CLK_EXTERNAL:
381 str = NULL;
382 priv->lddckr = LDDCKR_ICKSEL_HDMI;
383 break;
384 default:
385 return -EINVAL;
386 }
387
388 if (str == NULL)
389 return 0;
390
391 clk = clk_get(priv->dev, str);
392 if (IS_ERR(clk)) {
393 dev_err(priv->dev, "cannot get dot clock %s\n", str);
394 return PTR_ERR(clk);
395 }
396
397 priv->dot_clk = clk;
398 return 0;
399}
400
401
402
403
404
405static void lcdc_sys_write_index(void *handle, unsigned long data)
406{
407 struct sh_mobile_lcdc_chan *ch = handle;
408
409 lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT);
410 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
411 lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
412 (lcdc_chan_is_sublcd(ch) ? 2 : 0));
413 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
414}
415
416static void lcdc_sys_write_data(void *handle, unsigned long data)
417{
418 struct sh_mobile_lcdc_chan *ch = handle;
419
420 lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT | LDDWDxR_RSW);
421 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
422 lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
423 (lcdc_chan_is_sublcd(ch) ? 2 : 0));
424 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
425}
426
427static unsigned long lcdc_sys_read_data(void *handle)
428{
429 struct sh_mobile_lcdc_chan *ch = handle;
430
431 lcdc_write(ch->lcdc, _LDDRDR, LDDRDR_RSR);
432 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
433 lcdc_write(ch->lcdc, _LDDRAR, LDDRAR_RA |
434 (lcdc_chan_is_sublcd(ch) ? 2 : 0));
435 udelay(1);
436 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
437
438 return lcdc_read(ch->lcdc, _LDDRDR) & LDDRDR_DRD_MASK;
439}
440
441static struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
442 lcdc_sys_write_index,
443 lcdc_sys_write_data,
444 lcdc_sys_read_data,
445};
446
447static int sh_mobile_lcdc_sginit(struct fb_info *info,
448 struct list_head *pagelist)
449{
450 struct sh_mobile_lcdc_chan *ch = info->par;
451 unsigned int nr_pages_max = ch->fb_size >> PAGE_SHIFT;
452 struct page *page;
453 int nr_pages = 0;
454
455 sg_init_table(ch->sglist, nr_pages_max);
456
457 list_for_each_entry(page, pagelist, lru)
458 sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0);
459
460 return nr_pages;
461}
462
463static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
464 struct list_head *pagelist)
465{
466 struct sh_mobile_lcdc_chan *ch = info->par;
467 const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
468
469
470 sh_mobile_lcdc_clk_on(ch->lcdc);
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487 if (!list_empty(pagelist)) {
488 unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagelist);
489
490
491 dma_map_sg(ch->lcdc->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
492 if (panel->start_transfer)
493 panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
494 lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
495 dma_unmap_sg(ch->lcdc->dev, ch->sglist, nr_pages,
496 DMA_TO_DEVICE);
497 } else {
498 if (panel->start_transfer)
499 panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
500 lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
501 }
502}
503
504static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
505{
506 struct fb_deferred_io *fbdefio = info->fbdefio;
507
508 if (fbdefio)
509 schedule_delayed_work(&info->deferred_work, fbdefio->delay);
510}
511
512static void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)
513{
514 const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
515
516 if (ch->tx_dev) {
517 int ret;
518
519 ret = ch->tx_dev->ops->display_on(ch->tx_dev);
520 if (ret < 0)
521 return;
522
523 if (ret == SH_MOBILE_LCDC_DISPLAY_DISCONNECTED)
524 ch->info->state = FBINFO_STATE_SUSPENDED;
525 }
526
527
528 if (panel->display_on)
529 panel->display_on();
530}
531
532static void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch)
533{
534 const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
535
536 if (panel->display_off)
537 panel->display_off();
538
539 if (ch->tx_dev)
540 ch->tx_dev->ops->display_off(ch->tx_dev);
541}
542
543static bool
544sh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch,
545 const struct fb_videomode *new_mode)
546{
547 dev_dbg(ch->info->dev, "Old %ux%u, new %ux%u\n",
548 ch->display.mode.xres, ch->display.mode.yres,
549 new_mode->xres, new_mode->yres);
550
551
552 if (fb_mode_is_equal(&ch->display.mode, new_mode))
553 return false;
554
555 dev_dbg(ch->info->dev, "Switching %u -> %u lines\n",
556 ch->display.mode.yres, new_mode->yres);
557 ch->display.mode = *new_mode;
558
559 return true;
560}
561
562static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
563 struct fb_info *info);
564
565static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
566 enum sh_mobile_lcdc_entity_event event,
567 const struct fb_videomode *mode,
568 const struct fb_monspecs *monspec)
569{
570 struct fb_info *info = ch->info;
571 struct fb_var_screeninfo var;
572 int ret = 0;
573
574 switch (event) {
575 case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT:
576
577 console_lock();
578 if (lock_fb_info(info)) {
579
580
581 ch->display.width = monspec->max_x * 10;
582 ch->display.height = monspec->max_y * 10;
583
584 if (!sh_mobile_lcdc_must_reconfigure(ch, mode) &&
585 info->state == FBINFO_STATE_RUNNING) {
586
587
588
589
590 info->var.width = ch->display.width;
591 info->var.height = ch->display.height;
592 sh_mobile_lcdc_display_on(ch);
593 } else {
594
595 fb_set_suspend(info, 0);
596 }
597
598
599 unlock_fb_info(info);
600 }
601 console_unlock();
602 break;
603
604 case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT:
605
606 console_lock();
607 if (lock_fb_info(info)) {
608 fb_set_suspend(info, 1);
609 unlock_fb_info(info);
610 }
611 console_unlock();
612 break;
613
614 case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE:
615
616 fb_videomode_to_var(&var, mode);
617 var.bits_per_pixel = info->var.bits_per_pixel;
618 var.grayscale = info->var.grayscale;
619 ret = sh_mobile_lcdc_check_var(&var, info);
620 break;
621 }
622
623 return ret;
624}
625
626
627
628
629
630struct sh_mobile_lcdc_format_info {
631 u32 fourcc;
632 unsigned int bpp;
633 bool yuv;
634 u32 lddfr;
635};
636
637static const struct sh_mobile_lcdc_format_info sh_mobile_format_infos[] = {
638 {
639 .fourcc = V4L2_PIX_FMT_RGB565,
640 .bpp = 16,
641 .yuv = false,
642 .lddfr = LDDFR_PKF_RGB16,
643 }, {
644 .fourcc = V4L2_PIX_FMT_BGR24,
645 .bpp = 24,
646 .yuv = false,
647 .lddfr = LDDFR_PKF_RGB24,
648 }, {
649 .fourcc = V4L2_PIX_FMT_BGR32,
650 .bpp = 32,
651 .yuv = false,
652 .lddfr = LDDFR_PKF_ARGB32,
653 }, {
654 .fourcc = V4L2_PIX_FMT_NV12,
655 .bpp = 12,
656 .yuv = true,
657 .lddfr = LDDFR_CC | LDDFR_YF_420,
658 }, {
659 .fourcc = V4L2_PIX_FMT_NV21,
660 .bpp = 12,
661 .yuv = true,
662 .lddfr = LDDFR_CC | LDDFR_YF_420,
663 }, {
664 .fourcc = V4L2_PIX_FMT_NV16,
665 .bpp = 16,
666 .yuv = true,
667 .lddfr = LDDFR_CC | LDDFR_YF_422,
668 }, {
669 .fourcc = V4L2_PIX_FMT_NV61,
670 .bpp = 16,
671 .yuv = true,
672 .lddfr = LDDFR_CC | LDDFR_YF_422,
673 }, {
674 .fourcc = V4L2_PIX_FMT_NV24,
675 .bpp = 24,
676 .yuv = true,
677 .lddfr = LDDFR_CC | LDDFR_YF_444,
678 }, {
679 .fourcc = V4L2_PIX_FMT_NV42,
680 .bpp = 24,
681 .yuv = true,
682 .lddfr = LDDFR_CC | LDDFR_YF_444,
683 },
684};
685
686static const struct sh_mobile_lcdc_format_info *
687sh_mobile_format_info(u32 fourcc)
688{
689 unsigned int i;
690
691 for (i = 0; i < ARRAY_SIZE(sh_mobile_format_infos); ++i) {
692 if (sh_mobile_format_infos[i].fourcc == fourcc)
693 return &sh_mobile_format_infos[i];
694 }
695
696 return NULL;
697}
698
699static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
700{
701 if (var->grayscale > 1)
702 return var->grayscale;
703
704 switch (var->bits_per_pixel) {
705 case 16:
706 return V4L2_PIX_FMT_RGB565;
707 case 24:
708 return V4L2_PIX_FMT_BGR24;
709 case 32:
710 return V4L2_PIX_FMT_BGR32;
711 default:
712 return 0;
713 }
714}
715
716static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
717{
718 return var->grayscale > 1;
719}
720
721
722
723
724
725static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
726{
727 struct sh_mobile_lcdc_priv *priv = data;
728 struct sh_mobile_lcdc_chan *ch;
729 unsigned long ldintr;
730 int is_sub;
731 int k;
732
733
734 ldintr = lcdc_read(priv, _LDINTR);
735 lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE);
736
737
738 is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0;
739
740
741 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
742 ch = &priv->ch[k];
743
744 if (!ch->enabled)
745 continue;
746
747
748 if (ldintr & LDINTR_FS) {
749 if (is_sub == lcdc_chan_is_sublcd(ch)) {
750 ch->frame_end = 1;
751 wake_up(&ch->frame_end_wait);
752
753 sh_mobile_lcdc_clk_off(priv);
754 }
755 }
756
757
758 if (ldintr & LDINTR_VES)
759 complete(&ch->vsync_completion);
760 }
761
762 return IRQ_HANDLED;
763}
764
765static int sh_mobile_lcdc_wait_for_vsync(struct sh_mobile_lcdc_chan *ch)
766{
767 unsigned long ldintr;
768 int ret;
769
770
771
772
773 ldintr = lcdc_read(ch->lcdc, _LDINTR);
774 ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
775 lcdc_write(ch->lcdc, _LDINTR, ldintr);
776
777 ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
778 msecs_to_jiffies(100));
779 if (!ret)
780 return -ETIMEDOUT;
781
782 return 0;
783}
784
785static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
786 int start)
787{
788 unsigned long tmp = lcdc_read(priv, _LDCNT2R);
789 int k;
790
791
792 if (start)
793 lcdc_write(priv, _LDCNT2R, tmp | LDCNT2R_DO);
794 else
795 lcdc_write(priv, _LDCNT2R, tmp & ~LDCNT2R_DO);
796
797
798 for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
799 if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled)
800 while (1) {
801 tmp = lcdc_read_chan(&priv->ch[k], LDPMR)
802 & LDPMR_LPS;
803 if (start && tmp == LDPMR_LPS)
804 break;
805 if (!start && tmp == 0)
806 break;
807 cpu_relax();
808 }
809
810 if (!start)
811 lcdc_write(priv, _LDDCKSTPR, 1);
812}
813
814static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
815{
816 const struct fb_var_screeninfo *var = &ch->info->var;
817 const struct fb_videomode *mode = &ch->display.mode;
818 unsigned long h_total, hsync_pos, display_h_total;
819 u32 tmp;
820
821 tmp = ch->ldmt1r_value;
822 tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL;
823 tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL;
824 tmp |= (ch->cfg->flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;
825 tmp |= (ch->cfg->flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;
826 tmp |= (ch->cfg->flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;
827 tmp |= (ch->cfg->flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;
828 tmp |= (ch->cfg->flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;
829 lcdc_write_chan(ch, LDMT1R, tmp);
830
831
832 lcdc_write_chan(ch, LDMT2R, ch->cfg->sys_bus_cfg.ldmt2r);
833 lcdc_write_chan(ch, LDMT3R, ch->cfg->sys_bus_cfg.ldmt3r);
834
835
836 h_total = mode->xres + mode->hsync_len + mode->left_margin
837 + mode->right_margin;
838 tmp = h_total / 8;
839 tmp |= (min(mode->xres, ch->xres) / 8) << 16;
840 lcdc_write_chan(ch, LDHCNR, tmp);
841
842 hsync_pos = mode->xres + mode->right_margin;
843 tmp = hsync_pos / 8;
844 tmp |= (mode->hsync_len / 8) << 16;
845 lcdc_write_chan(ch, LDHSYNR, tmp);
846
847
848 tmp = mode->yres + mode->vsync_len + mode->upper_margin
849 + mode->lower_margin;
850 tmp |= min(mode->yres, ch->yres) << 16;
851 lcdc_write_chan(ch, LDVLNR, tmp);
852
853 tmp = mode->yres + mode->lower_margin;
854 tmp |= mode->vsync_len << 16;
855 lcdc_write_chan(ch, LDVSYNR, tmp);
856
857
858 display_h_total = mode->xres + mode->hsync_len + mode->left_margin
859 + mode->right_margin;
860 tmp = ((mode->xres & 7) << 24) | ((display_h_total & 7) << 16)
861 | ((mode->hsync_len & 7) << 8) | (hsync_pos & 7);
862 lcdc_write_chan(ch, LDHAJR, tmp);
863 lcdc_write_chan_mirror(ch, LDHAJR, tmp);
864}
865
866static void sh_mobile_lcdc_overlay_setup(struct sh_mobile_lcdc_overlay *ovl)
867{
868 u32 format = 0;
869
870 if (!ovl->enabled) {
871 lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
872 lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), 0);
873 lcdc_write(ovl->channel->lcdc, LDBCR,
874 LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
875 return;
876 }
877
878 ovl->base_addr_y = ovl->dma_handle;
879 ovl->base_addr_c = ovl->dma_handle
880 + ovl->xres_virtual * ovl->yres_virtual;
881
882 switch (ovl->mode) {
883 case LCDC_OVERLAY_BLEND:
884 format = LDBBSIFR_EN | (ovl->alpha << LDBBSIFR_LAY_SHIFT);
885 break;
886
887 case LCDC_OVERLAY_ROP3:
888 format = LDBBSIFR_EN | LDBBSIFR_BRSEL
889 | (ovl->rop3 << LDBBSIFR_ROP3_SHIFT);
890 break;
891 }
892
893 switch (ovl->format->fourcc) {
894 case V4L2_PIX_FMT_RGB565:
895 case V4L2_PIX_FMT_NV21:
896 case V4L2_PIX_FMT_NV61:
897 case V4L2_PIX_FMT_NV42:
898 format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW;
899 break;
900 case V4L2_PIX_FMT_BGR24:
901 case V4L2_PIX_FMT_NV12:
902 case V4L2_PIX_FMT_NV16:
903 case V4L2_PIX_FMT_NV24:
904 format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB;
905 break;
906 case V4L2_PIX_FMT_BGR32:
907 default:
908 format |= LDBBSIFR_SWPL;
909 break;
910 }
911
912 switch (ovl->format->fourcc) {
913 case V4L2_PIX_FMT_RGB565:
914 format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16;
915 break;
916 case V4L2_PIX_FMT_BGR24:
917 format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24;
918 break;
919 case V4L2_PIX_FMT_BGR32:
920 format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32;
921 break;
922 case V4L2_PIX_FMT_NV12:
923 case V4L2_PIX_FMT_NV21:
924 format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420;
925 break;
926 case V4L2_PIX_FMT_NV16:
927 case V4L2_PIX_FMT_NV61:
928 format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422;
929 break;
930 case V4L2_PIX_FMT_NV24:
931 case V4L2_PIX_FMT_NV42:
932 format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444;
933 break;
934 }
935
936 lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
937
938 lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), format);
939
940 lcdc_write_overlay(ovl, LDBnBSSZR(ovl->index),
941 (ovl->yres << LDBBSSZR_BVSS_SHIFT) |
942 (ovl->xres << LDBBSSZR_BHSS_SHIFT));
943 lcdc_write_overlay(ovl, LDBnBLOCR(ovl->index),
944 (ovl->pos_y << LDBBLOCR_CVLC_SHIFT) |
945 (ovl->pos_x << LDBBLOCR_CHLC_SHIFT));
946 lcdc_write_overlay(ovl, LDBnBSMWR(ovl->index),
947 ovl->pitch << LDBBSMWR_BSMW_SHIFT);
948
949 lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);
950 lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);
951
952 lcdc_write(ovl->channel->lcdc, LDBCR,
953 LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
954}
955
956
957
958
959
960
961
962
963static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
964{
965 struct sh_mobile_lcdc_chan *ch;
966 unsigned long tmp;
967 int k, m;
968
969
970
971
972 lcdc_write(priv, _LDCNT2R, priv->ch[0].enabled | priv->ch[1].enabled);
973
974
975 sh_mobile_lcdc_start_stop(priv, 0);
976 lcdc_write(priv, _LDINTR, 0);
977
978
979 tmp = priv->lddckr;
980 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
981 ch = &priv->ch[k];
982 if (!ch->enabled)
983 continue;
984
985
986 lcdc_write_chan(ch, LDPMR, 0);
987
988 m = ch->cfg->clock_divider;
989 if (!m)
990 continue;
991
992
993
994
995 lcdc_write_chan(ch, LDDCKPAT1R, 0);
996 lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1);
997
998 if (m == 1)
999 m = LDDCKR_MOSEL;
1000 tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
1001 }
1002
1003 lcdc_write(priv, _LDDCKR, tmp);
1004 lcdc_write(priv, _LDDCKSTPR, 0);
1005 lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0);
1006
1007
1008 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1009 ch = &priv->ch[k];
1010 if (!ch->enabled)
1011 continue;
1012
1013 sh_mobile_lcdc_geometry(ch);
1014
1015 tmp = ch->format->lddfr;
1016
1017 if (ch->format->yuv) {
1018 switch (ch->colorspace) {
1019 case V4L2_COLORSPACE_REC709:
1020 tmp |= LDDFR_CF1;
1021 break;
1022 case V4L2_COLORSPACE_JPEG:
1023 tmp |= LDDFR_CF0;
1024 break;
1025 }
1026 }
1027
1028 lcdc_write_chan(ch, LDDFR, tmp);
1029 lcdc_write_chan(ch, LDMLSR, ch->line_size);
1030 lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
1031 if (ch->format->yuv)
1032 lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
1033
1034
1035
1036
1037
1038 if (ch->ldmt1r_value & LDMT1R_IFM &&
1039 ch->cfg->sys_bus_cfg.deferred_io_msec) {
1040 lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);
1041 lcdc_write(priv, _LDINTR, LDINTR_FE);
1042 } else {
1043 lcdc_write_chan(ch, LDSM1R, 0);
1044 }
1045 }
1046
1047
1048 switch (priv->ch[0].format->fourcc) {
1049 case V4L2_PIX_FMT_RGB565:
1050 case V4L2_PIX_FMT_NV21:
1051 case V4L2_PIX_FMT_NV61:
1052 case V4L2_PIX_FMT_NV42:
1053 tmp = LDDDSR_LS | LDDDSR_WS;
1054 break;
1055 case V4L2_PIX_FMT_BGR24:
1056 case V4L2_PIX_FMT_NV12:
1057 case V4L2_PIX_FMT_NV16:
1058 case V4L2_PIX_FMT_NV24:
1059 tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
1060 break;
1061 case V4L2_PIX_FMT_BGR32:
1062 default:
1063 tmp = LDDDSR_LS;
1064 break;
1065 }
1066 lcdc_write(priv, _LDDDSR, tmp);
1067
1068
1069 lcdc_write(priv, _LDCNT1R, LDCNT1R_DE);
1070 sh_mobile_lcdc_start_stop(priv, 1);
1071 priv->started = 1;
1072}
1073
1074static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
1075{
1076 struct sh_mobile_meram_info *mdev = priv->meram_dev;
1077 struct sh_mobile_lcdc_chan *ch;
1078 unsigned long tmp;
1079 int ret;
1080 int k;
1081
1082
1083 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1084 if (priv->ch[k].enabled)
1085 sh_mobile_lcdc_clk_on(priv);
1086 }
1087
1088
1089 lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LDCNT2R_BR);
1090 lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);
1091
1092 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1093 const struct sh_mobile_lcdc_panel_cfg *panel;
1094
1095 ch = &priv->ch[k];
1096 if (!ch->enabled)
1097 continue;
1098
1099 panel = &ch->cfg->panel_cfg;
1100 if (panel->setup_sys) {
1101 ret = panel->setup_sys(ch, &sh_mobile_lcdc_sys_bus_ops);
1102 if (ret)
1103 return ret;
1104 }
1105 }
1106
1107
1108 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1109 int pixelformat;
1110 void *cache;
1111
1112 ch = &priv->ch[k];
1113 if (!ch->enabled)
1114 continue;
1115
1116 ch->base_addr_y = ch->dma_handle;
1117 ch->base_addr_c = ch->dma_handle
1118 + ch->xres_virtual * ch->yres_virtual;
1119 ch->line_size = ch->pitch;
1120
1121
1122 if (mdev == NULL || ch->cfg->meram_cfg == NULL)
1123 continue;
1124
1125
1126 if (ch->cache) {
1127 sh_mobile_meram_cache_free(mdev, ch->cache);
1128 ch->cache = NULL;
1129 }
1130
1131 switch (ch->format->fourcc) {
1132 case V4L2_PIX_FMT_NV12:
1133 case V4L2_PIX_FMT_NV21:
1134 case V4L2_PIX_FMT_NV16:
1135 case V4L2_PIX_FMT_NV61:
1136 pixelformat = SH_MOBILE_MERAM_PF_NV;
1137 break;
1138 case V4L2_PIX_FMT_NV24:
1139 case V4L2_PIX_FMT_NV42:
1140 pixelformat = SH_MOBILE_MERAM_PF_NV24;
1141 break;
1142 case V4L2_PIX_FMT_RGB565:
1143 case V4L2_PIX_FMT_BGR24:
1144 case V4L2_PIX_FMT_BGR32:
1145 default:
1146 pixelformat = SH_MOBILE_MERAM_PF_RGB;
1147 break;
1148 }
1149
1150 cache = sh_mobile_meram_cache_alloc(mdev, ch->cfg->meram_cfg,
1151 ch->pitch, ch->yres, pixelformat,
1152 &ch->line_size);
1153 if (!IS_ERR(cache)) {
1154 sh_mobile_meram_cache_update(mdev, cache,
1155 ch->base_addr_y, ch->base_addr_c,
1156 &ch->base_addr_y, &ch->base_addr_c);
1157 ch->cache = cache;
1158 }
1159 }
1160
1161 for (k = 0; k < ARRAY_SIZE(priv->overlays); ++k) {
1162 struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[k];
1163 sh_mobile_lcdc_overlay_setup(ovl);
1164 }
1165
1166
1167 __sh_mobile_lcdc_start(priv);
1168
1169
1170
1171
1172 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1173 ch = &priv->ch[k];
1174 if (!ch->enabled)
1175 continue;
1176
1177 tmp = ch->cfg->sys_bus_cfg.deferred_io_msec;
1178 if (ch->ldmt1r_value & LDMT1R_IFM && tmp) {
1179 ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
1180 ch->defio.delay = msecs_to_jiffies(tmp);
1181 ch->info->fbdefio = &ch->defio;
1182 fb_deferred_io_init(ch->info);
1183 }
1184
1185 sh_mobile_lcdc_display_on(ch);
1186
1187 if (ch->bl) {
1188 ch->bl->props.power = FB_BLANK_UNBLANK;
1189 backlight_update_status(ch->bl);
1190 }
1191 }
1192
1193 return 0;
1194}
1195
1196static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
1197{
1198 struct sh_mobile_lcdc_chan *ch;
1199 int k;
1200
1201
1202 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1203 ch = &priv->ch[k];
1204 if (!ch->enabled)
1205 continue;
1206
1207
1208
1209
1210
1211 if (ch->info && ch->info->fbdefio) {
1212 ch->frame_end = 0;
1213 schedule_delayed_work(&ch->info->deferred_work, 0);
1214 wait_event(ch->frame_end_wait, ch->frame_end);
1215 fb_deferred_io_cleanup(ch->info);
1216 ch->info->fbdefio = NULL;
1217 sh_mobile_lcdc_clk_on(priv);
1218 }
1219
1220 if (ch->bl) {
1221 ch->bl->props.power = FB_BLANK_POWERDOWN;
1222 backlight_update_status(ch->bl);
1223 }
1224
1225 sh_mobile_lcdc_display_off(ch);
1226
1227
1228 if (ch->cache) {
1229 sh_mobile_meram_cache_free(priv->meram_dev, ch->cache);
1230 ch->cache = NULL;
1231 }
1232
1233 }
1234
1235
1236 if (priv->started) {
1237 sh_mobile_lcdc_start_stop(priv, 0);
1238 priv->started = 0;
1239 }
1240
1241
1242 for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
1243 if (priv->ch[k].enabled)
1244 sh_mobile_lcdc_clk_off(priv);
1245}
1246
1247static int __sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
1248 struct fb_info *info)
1249{
1250 if (var->xres > MAX_XRES || var->yres > MAX_YRES)
1251 return -EINVAL;
1252
1253
1254
1255
1256 if (var->xres_virtual < var->xres)
1257 var->xres_virtual = var->xres;
1258 if (var->yres_virtual < var->yres)
1259 var->yres_virtual = var->yres;
1260
1261 if (sh_mobile_format_is_fourcc(var)) {
1262 const struct sh_mobile_lcdc_format_info *format;
1263
1264 format = sh_mobile_format_info(var->grayscale);
1265 if (format == NULL)
1266 return -EINVAL;
1267 var->bits_per_pixel = format->bpp;
1268
1269
1270
1271
1272 if (!format->yuv)
1273 var->colorspace = V4L2_COLORSPACE_SRGB;
1274 else if (var->colorspace != V4L2_COLORSPACE_REC709)
1275 var->colorspace = V4L2_COLORSPACE_JPEG;
1276 } else {
1277 if (var->bits_per_pixel <= 16) {
1278 var->bits_per_pixel = 16;
1279 var->red.offset = 11;
1280 var->red.length = 5;
1281 var->green.offset = 5;
1282 var->green.length = 6;
1283 var->blue.offset = 0;
1284 var->blue.length = 5;
1285 var->transp.offset = 0;
1286 var->transp.length = 0;
1287 } else if (var->bits_per_pixel <= 24) {
1288 var->bits_per_pixel = 24;
1289 var->red.offset = 16;
1290 var->red.length = 8;
1291 var->green.offset = 8;
1292 var->green.length = 8;
1293 var->blue.offset = 0;
1294 var->blue.length = 8;
1295 var->transp.offset = 0;
1296 var->transp.length = 0;
1297 } else if (var->bits_per_pixel <= 32) {
1298 var->bits_per_pixel = 32;
1299 var->red.offset = 16;
1300 var->red.length = 8;
1301 var->green.offset = 8;
1302 var->green.length = 8;
1303 var->blue.offset = 0;
1304 var->blue.length = 8;
1305 var->transp.offset = 24;
1306 var->transp.length = 8;
1307 } else
1308 return -EINVAL;
1309
1310 var->red.msb_right = 0;
1311 var->green.msb_right = 0;
1312 var->blue.msb_right = 0;
1313 var->transp.msb_right = 0;
1314 }
1315
1316
1317 if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
1318 info->fix.smem_len)
1319 return -EINVAL;
1320
1321 return 0;
1322}
1323
1324
1325
1326
1327
1328static ssize_t
1329overlay_alpha_show(struct device *dev, struct device_attribute *attr, char *buf)
1330{
1331 struct fb_info *info = dev_get_drvdata(dev);
1332 struct sh_mobile_lcdc_overlay *ovl = info->par;
1333
1334 return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->alpha);
1335}
1336
1337static ssize_t
1338overlay_alpha_store(struct device *dev, struct device_attribute *attr,
1339 const char *buf, size_t count)
1340{
1341 struct fb_info *info = dev_get_drvdata(dev);
1342 struct sh_mobile_lcdc_overlay *ovl = info->par;
1343 unsigned int alpha;
1344 char *endp;
1345
1346 alpha = simple_strtoul(buf, &endp, 10);
1347 if (isspace(*endp))
1348 endp++;
1349
1350 if (endp - buf != count)
1351 return -EINVAL;
1352
1353 if (alpha > 255)
1354 return -EINVAL;
1355
1356 if (ovl->alpha != alpha) {
1357 ovl->alpha = alpha;
1358
1359 if (ovl->mode == LCDC_OVERLAY_BLEND && ovl->enabled)
1360 sh_mobile_lcdc_overlay_setup(ovl);
1361 }
1362
1363 return count;
1364}
1365
1366static ssize_t
1367overlay_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
1368{
1369 struct fb_info *info = dev_get_drvdata(dev);
1370 struct sh_mobile_lcdc_overlay *ovl = info->par;
1371
1372 return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->mode);
1373}
1374
1375static ssize_t
1376overlay_mode_store(struct device *dev, struct device_attribute *attr,
1377 const char *buf, size_t count)
1378{
1379 struct fb_info *info = dev_get_drvdata(dev);
1380 struct sh_mobile_lcdc_overlay *ovl = info->par;
1381 unsigned int mode;
1382 char *endp;
1383
1384 mode = simple_strtoul(buf, &endp, 10);
1385 if (isspace(*endp))
1386 endp++;
1387
1388 if (endp - buf != count)
1389 return -EINVAL;
1390
1391 if (mode != LCDC_OVERLAY_BLEND && mode != LCDC_OVERLAY_ROP3)
1392 return -EINVAL;
1393
1394 if (ovl->mode != mode) {
1395 ovl->mode = mode;
1396
1397 if (ovl->enabled)
1398 sh_mobile_lcdc_overlay_setup(ovl);
1399 }
1400
1401 return count;
1402}
1403
1404static ssize_t
1405overlay_position_show(struct device *dev, struct device_attribute *attr,
1406 char *buf)
1407{
1408 struct fb_info *info = dev_get_drvdata(dev);
1409 struct sh_mobile_lcdc_overlay *ovl = info->par;
1410
1411 return scnprintf(buf, PAGE_SIZE, "%d,%d\n", ovl->pos_x, ovl->pos_y);
1412}
1413
1414static ssize_t
1415overlay_position_store(struct device *dev, struct device_attribute *attr,
1416 const char *buf, size_t count)
1417{
1418 struct fb_info *info = dev_get_drvdata(dev);
1419 struct sh_mobile_lcdc_overlay *ovl = info->par;
1420 char *endp;
1421 int pos_x;
1422 int pos_y;
1423
1424 pos_x = simple_strtol(buf, &endp, 10);
1425 if (*endp != ',')
1426 return -EINVAL;
1427
1428 pos_y = simple_strtol(endp + 1, &endp, 10);
1429 if (isspace(*endp))
1430 endp++;
1431
1432 if (endp - buf != count)
1433 return -EINVAL;
1434
1435 if (ovl->pos_x != pos_x || ovl->pos_y != pos_y) {
1436 ovl->pos_x = pos_x;
1437 ovl->pos_y = pos_y;
1438
1439 if (ovl->enabled)
1440 sh_mobile_lcdc_overlay_setup(ovl);
1441 }
1442
1443 return count;
1444}
1445
1446static ssize_t
1447overlay_rop3_show(struct device *dev, struct device_attribute *attr, char *buf)
1448{
1449 struct fb_info *info = dev_get_drvdata(dev);
1450 struct sh_mobile_lcdc_overlay *ovl = info->par;
1451
1452 return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->rop3);
1453}
1454
1455static ssize_t
1456overlay_rop3_store(struct device *dev, struct device_attribute *attr,
1457 const char *buf, size_t count)
1458{
1459 struct fb_info *info = dev_get_drvdata(dev);
1460 struct sh_mobile_lcdc_overlay *ovl = info->par;
1461 unsigned int rop3;
1462 char *endp;
1463
1464 rop3 = simple_strtoul(buf, &endp, 10);
1465 if (isspace(*endp))
1466 endp++;
1467
1468 if (endp - buf != count)
1469 return -EINVAL;
1470
1471 if (rop3 > 255)
1472 return -EINVAL;
1473
1474 if (ovl->rop3 != rop3) {
1475 ovl->rop3 = rop3;
1476
1477 if (ovl->mode == LCDC_OVERLAY_ROP3 && ovl->enabled)
1478 sh_mobile_lcdc_overlay_setup(ovl);
1479 }
1480
1481 return count;
1482}
1483
1484static const struct device_attribute overlay_sysfs_attrs[] = {
1485 __ATTR(ovl_alpha, S_IRUGO|S_IWUSR,
1486 overlay_alpha_show, overlay_alpha_store),
1487 __ATTR(ovl_mode, S_IRUGO|S_IWUSR,
1488 overlay_mode_show, overlay_mode_store),
1489 __ATTR(ovl_position, S_IRUGO|S_IWUSR,
1490 overlay_position_show, overlay_position_store),
1491 __ATTR(ovl_rop3, S_IRUGO|S_IWUSR,
1492 overlay_rop3_show, overlay_rop3_store),
1493};
1494
1495static const struct fb_fix_screeninfo sh_mobile_lcdc_overlay_fix = {
1496 .id = "SH Mobile LCDC",
1497 .type = FB_TYPE_PACKED_PIXELS,
1498 .visual = FB_VISUAL_TRUECOLOR,
1499 .accel = FB_ACCEL_NONE,
1500 .xpanstep = 1,
1501 .ypanstep = 1,
1502 .ywrapstep = 0,
1503 .capabilities = FB_CAP_FOURCC,
1504};
1505
1506static int sh_mobile_lcdc_overlay_pan(struct fb_var_screeninfo *var,
1507 struct fb_info *info)
1508{
1509 struct sh_mobile_lcdc_overlay *ovl = info->par;
1510 unsigned long base_addr_y;
1511 unsigned long base_addr_c;
1512 unsigned long y_offset;
1513 unsigned long c_offset;
1514
1515 if (!ovl->format->yuv) {
1516 y_offset = (var->yoffset * ovl->xres_virtual + var->xoffset)
1517 * ovl->format->bpp / 8;
1518 c_offset = 0;
1519 } else {
1520 unsigned int xsub = ovl->format->bpp < 24 ? 2 : 1;
1521 unsigned int ysub = ovl->format->bpp < 16 ? 2 : 1;
1522
1523 y_offset = var->yoffset * ovl->xres_virtual + var->xoffset;
1524 c_offset = var->yoffset / ysub * ovl->xres_virtual * 2 / xsub
1525 + var->xoffset * 2 / xsub;
1526 }
1527
1528
1529
1530
1531 if (y_offset == ovl->pan_y_offset)
1532 return 0;
1533
1534
1535 base_addr_y = ovl->dma_handle + y_offset;
1536 base_addr_c = ovl->dma_handle + ovl->xres_virtual * ovl->yres_virtual
1537 + c_offset;
1538
1539 ovl->base_addr_y = base_addr_y;
1540 ovl->base_addr_c = base_addr_c;
1541 ovl->pan_y_offset = y_offset;
1542
1543 lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
1544
1545 lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);
1546 lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);
1547
1548 lcdc_write(ovl->channel->lcdc, LDBCR,
1549 LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
1550
1551 return 0;
1552}
1553
1554static int sh_mobile_lcdc_overlay_ioctl(struct fb_info *info, unsigned int cmd,
1555 unsigned long arg)
1556{
1557 struct sh_mobile_lcdc_overlay *ovl = info->par;
1558
1559 switch (cmd) {
1560 case FBIO_WAITFORVSYNC:
1561 return sh_mobile_lcdc_wait_for_vsync(ovl->channel);
1562
1563 default:
1564 return -ENOIOCTLCMD;
1565 }
1566}
1567
1568static int sh_mobile_lcdc_overlay_check_var(struct fb_var_screeninfo *var,
1569 struct fb_info *info)
1570{
1571 return __sh_mobile_lcdc_check_var(var, info);
1572}
1573
1574static int sh_mobile_lcdc_overlay_set_par(struct fb_info *info)
1575{
1576 struct sh_mobile_lcdc_overlay *ovl = info->par;
1577
1578 ovl->format =
1579 sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
1580
1581 ovl->xres = info->var.xres;
1582 ovl->xres_virtual = info->var.xres_virtual;
1583 ovl->yres = info->var.yres;
1584 ovl->yres_virtual = info->var.yres_virtual;
1585
1586 if (ovl->format->yuv)
1587 ovl->pitch = info->var.xres_virtual;
1588 else
1589 ovl->pitch = info->var.xres_virtual * ovl->format->bpp / 8;
1590
1591 sh_mobile_lcdc_overlay_setup(ovl);
1592
1593 info->fix.line_length = ovl->pitch;
1594
1595 if (sh_mobile_format_is_fourcc(&info->var)) {
1596 info->fix.type = FB_TYPE_FOURCC;
1597 info->fix.visual = FB_VISUAL_FOURCC;
1598 } else {
1599 info->fix.type = FB_TYPE_PACKED_PIXELS;
1600 info->fix.visual = FB_VISUAL_TRUECOLOR;
1601 }
1602
1603 return 0;
1604}
1605
1606
1607static int sh_mobile_lcdc_overlay_blank(int blank, struct fb_info *info)
1608{
1609 struct sh_mobile_lcdc_overlay *ovl = info->par;
1610
1611 ovl->enabled = !blank;
1612 sh_mobile_lcdc_overlay_setup(ovl);
1613
1614
1615
1616
1617 return 1;
1618}
1619
1620static int
1621sh_mobile_lcdc_overlay_mmap(struct fb_info *info, struct vm_area_struct *vma)
1622{
1623 struct sh_mobile_lcdc_overlay *ovl = info->par;
1624
1625 return dma_mmap_coherent(ovl->channel->lcdc->dev, vma, ovl->fb_mem,
1626 ovl->dma_handle, ovl->fb_size);
1627}
1628
1629static struct fb_ops sh_mobile_lcdc_overlay_ops = {
1630 .owner = THIS_MODULE,
1631 .fb_read = fb_sys_read,
1632 .fb_write = fb_sys_write,
1633 .fb_fillrect = sys_fillrect,
1634 .fb_copyarea = sys_copyarea,
1635 .fb_imageblit = sys_imageblit,
1636 .fb_blank = sh_mobile_lcdc_overlay_blank,
1637 .fb_pan_display = sh_mobile_lcdc_overlay_pan,
1638 .fb_ioctl = sh_mobile_lcdc_overlay_ioctl,
1639 .fb_check_var = sh_mobile_lcdc_overlay_check_var,
1640 .fb_set_par = sh_mobile_lcdc_overlay_set_par,
1641 .fb_mmap = sh_mobile_lcdc_overlay_mmap,
1642};
1643
1644static void
1645sh_mobile_lcdc_overlay_fb_unregister(struct sh_mobile_lcdc_overlay *ovl)
1646{
1647 struct fb_info *info = ovl->info;
1648
1649 if (info == NULL || info->dev == NULL)
1650 return;
1651
1652 unregister_framebuffer(ovl->info);
1653}
1654
1655static int
1656sh_mobile_lcdc_overlay_fb_register(struct sh_mobile_lcdc_overlay *ovl)
1657{
1658 struct sh_mobile_lcdc_priv *lcdc = ovl->channel->lcdc;
1659 struct fb_info *info = ovl->info;
1660 unsigned int i;
1661 int ret;
1662
1663 if (info == NULL)
1664 return 0;
1665
1666 ret = register_framebuffer(info);
1667 if (ret < 0)
1668 return ret;
1669
1670 dev_info(lcdc->dev, "registered %s/overlay %u as %dx%d %dbpp.\n",
1671 dev_name(lcdc->dev), ovl->index, info->var.xres,
1672 info->var.yres, info->var.bits_per_pixel);
1673
1674 for (i = 0; i < ARRAY_SIZE(overlay_sysfs_attrs); ++i) {
1675 ret = device_create_file(info->dev, &overlay_sysfs_attrs[i]);
1676 if (ret < 0)
1677 return ret;
1678 }
1679
1680 return 0;
1681}
1682
1683static void
1684sh_mobile_lcdc_overlay_fb_cleanup(struct sh_mobile_lcdc_overlay *ovl)
1685{
1686 struct fb_info *info = ovl->info;
1687
1688 if (info == NULL || info->device == NULL)
1689 return;
1690
1691 framebuffer_release(info);
1692}
1693
1694static int
1695sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl)
1696{
1697 struct sh_mobile_lcdc_priv *priv = ovl->channel->lcdc;
1698 struct fb_var_screeninfo *var;
1699 struct fb_info *info;
1700
1701
1702 info = framebuffer_alloc(0, priv->dev);
1703 if (info == NULL) {
1704 dev_err(priv->dev, "unable to allocate fb_info\n");
1705 return -ENOMEM;
1706 }
1707
1708 ovl->info = info;
1709
1710 info->flags = FBINFO_FLAG_DEFAULT;
1711 info->fbops = &sh_mobile_lcdc_overlay_ops;
1712 info->device = priv->dev;
1713 info->screen_base = ovl->fb_mem;
1714 info->par = ovl;
1715
1716
1717
1718
1719 info->fix = sh_mobile_lcdc_overlay_fix;
1720 snprintf(info->fix.id, sizeof(info->fix.id),
1721 "SH Mobile LCDC Overlay %u", ovl->index);
1722 info->fix.smem_start = ovl->dma_handle;
1723 info->fix.smem_len = ovl->fb_size;
1724 info->fix.line_length = ovl->pitch;
1725
1726 if (ovl->format->yuv)
1727 info->fix.visual = FB_VISUAL_FOURCC;
1728 else
1729 info->fix.visual = FB_VISUAL_TRUECOLOR;
1730
1731 switch (ovl->format->fourcc) {
1732 case V4L2_PIX_FMT_NV12:
1733 case V4L2_PIX_FMT_NV21:
1734 info->fix.ypanstep = 2;
1735 case V4L2_PIX_FMT_NV16:
1736 case V4L2_PIX_FMT_NV61:
1737 info->fix.xpanstep = 2;
1738 }
1739
1740
1741 var = &info->var;
1742 memset(var, 0, sizeof(*var));
1743 var->xres = ovl->xres;
1744 var->yres = ovl->yres;
1745 var->xres_virtual = ovl->xres_virtual;
1746 var->yres_virtual = ovl->yres_virtual;
1747 var->activate = FB_ACTIVATE_NOW;
1748
1749
1750
1751
1752 if (!ovl->format->yuv)
1753 var->bits_per_pixel = ovl->format->bpp;
1754 else
1755 var->grayscale = ovl->format->fourcc;
1756
1757 return sh_mobile_lcdc_overlay_check_var(var, info);
1758}
1759
1760
1761
1762
1763
1764static int sh_mobile_lcdc_setcolreg(u_int regno,
1765 u_int red, u_int green, u_int blue,
1766 u_int transp, struct fb_info *info)
1767{
1768 u32 *palette = info->pseudo_palette;
1769
1770 if (regno >= PALETTE_NR)
1771 return -EINVAL;
1772
1773
1774
1775 red >>= 16 - info->var.red.length;
1776 green >>= 16 - info->var.green.length;
1777 blue >>= 16 - info->var.blue.length;
1778 transp >>= 16 - info->var.transp.length;
1779
1780 palette[regno] = (red << info->var.red.offset) |
1781 (green << info->var.green.offset) |
1782 (blue << info->var.blue.offset) |
1783 (transp << info->var.transp.offset);
1784
1785 return 0;
1786}
1787
1788static const struct fb_fix_screeninfo sh_mobile_lcdc_fix = {
1789 .id = "SH Mobile LCDC",
1790 .type = FB_TYPE_PACKED_PIXELS,
1791 .visual = FB_VISUAL_TRUECOLOR,
1792 .accel = FB_ACCEL_NONE,
1793 .xpanstep = 1,
1794 .ypanstep = 1,
1795 .ywrapstep = 0,
1796 .capabilities = FB_CAP_FOURCC,
1797};
1798
1799static void sh_mobile_lcdc_fillrect(struct fb_info *info,
1800 const struct fb_fillrect *rect)
1801{
1802 sys_fillrect(info, rect);
1803 sh_mobile_lcdc_deferred_io_touch(info);
1804}
1805
1806static void sh_mobile_lcdc_copyarea(struct fb_info *info,
1807 const struct fb_copyarea *area)
1808{
1809 sys_copyarea(info, area);
1810 sh_mobile_lcdc_deferred_io_touch(info);
1811}
1812
1813static void sh_mobile_lcdc_imageblit(struct fb_info *info,
1814 const struct fb_image *image)
1815{
1816 sys_imageblit(info, image);
1817 sh_mobile_lcdc_deferred_io_touch(info);
1818}
1819
1820static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var,
1821 struct fb_info *info)
1822{
1823 struct sh_mobile_lcdc_chan *ch = info->par;
1824 struct sh_mobile_lcdc_priv *priv = ch->lcdc;
1825 unsigned long ldrcntr;
1826 unsigned long base_addr_y, base_addr_c;
1827 unsigned long y_offset;
1828 unsigned long c_offset;
1829
1830 if (!ch->format->yuv) {
1831 y_offset = (var->yoffset * ch->xres_virtual + var->xoffset)
1832 * ch->format->bpp / 8;
1833 c_offset = 0;
1834 } else {
1835 unsigned int xsub = ch->format->bpp < 24 ? 2 : 1;
1836 unsigned int ysub = ch->format->bpp < 16 ? 2 : 1;
1837
1838 y_offset = var->yoffset * ch->xres_virtual + var->xoffset;
1839 c_offset = var->yoffset / ysub * ch->xres_virtual * 2 / xsub
1840 + var->xoffset * 2 / xsub;
1841 }
1842
1843
1844
1845
1846 if (y_offset == ch->pan_y_offset)
1847 return 0;
1848
1849
1850 base_addr_y = ch->dma_handle + y_offset;
1851 base_addr_c = ch->dma_handle + ch->xres_virtual * ch->yres_virtual
1852 + c_offset;
1853
1854 if (ch->cache)
1855 sh_mobile_meram_cache_update(priv->meram_dev, ch->cache,
1856 base_addr_y, base_addr_c,
1857 &base_addr_y, &base_addr_c);
1858
1859 ch->base_addr_y = base_addr_y;
1860 ch->base_addr_c = base_addr_c;
1861 ch->pan_y_offset = y_offset;
1862
1863 lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
1864 if (ch->format->yuv)
1865 lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
1866
1867 ldrcntr = lcdc_read(priv, _LDRCNTR);
1868 if (lcdc_chan_is_sublcd(ch))
1869 lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
1870 else
1871 lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS);
1872
1873
1874 sh_mobile_lcdc_deferred_io_touch(info);
1875
1876 return 0;
1877}
1878
1879static int sh_mobile_lcdc_ioctl(struct fb_info *info, unsigned int cmd,
1880 unsigned long arg)
1881{
1882 struct sh_mobile_lcdc_chan *ch = info->par;
1883 int retval;
1884
1885 switch (cmd) {
1886 case FBIO_WAITFORVSYNC:
1887 retval = sh_mobile_lcdc_wait_for_vsync(ch);
1888 break;
1889
1890 default:
1891 retval = -ENOIOCTLCMD;
1892 break;
1893 }
1894 return retval;
1895}
1896
1897static void sh_mobile_fb_reconfig(struct fb_info *info)
1898{
1899 struct sh_mobile_lcdc_chan *ch = info->par;
1900 struct fb_var_screeninfo var;
1901 struct fb_videomode mode;
1902 struct fb_event event;
1903 int evnt = FB_EVENT_MODE_CHANGE_ALL;
1904
1905 if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par))
1906
1907 return;
1908
1909 fb_var_to_videomode(&mode, &info->var);
1910
1911 if (fb_mode_is_equal(&ch->display.mode, &mode))
1912 return;
1913
1914
1915 var = info->var;
1916 fb_videomode_to_var(&var, &ch->display.mode);
1917 var.width = ch->display.width;
1918 var.height = ch->display.height;
1919 var.activate = FB_ACTIVATE_NOW;
1920
1921 if (fb_set_var(info, &var) < 0)
1922
1923 return;
1924
1925
1926
1927
1928
1929
1930 event.info = info;
1931 event.data = &ch->display.mode;
1932 fb_notifier_call_chain(evnt, &event);
1933}
1934
1935
1936
1937
1938
1939static int sh_mobile_lcdc_release(struct fb_info *info, int user)
1940{
1941 struct sh_mobile_lcdc_chan *ch = info->par;
1942
1943 mutex_lock(&ch->open_lock);
1944 dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);
1945
1946 ch->use_count--;
1947
1948
1949 if (user) {
1950 console_lock();
1951 sh_mobile_fb_reconfig(info);
1952 console_unlock();
1953 }
1954
1955 mutex_unlock(&ch->open_lock);
1956
1957 return 0;
1958}
1959
1960static int sh_mobile_lcdc_open(struct fb_info *info, int user)
1961{
1962 struct sh_mobile_lcdc_chan *ch = info->par;
1963
1964 mutex_lock(&ch->open_lock);
1965 ch->use_count++;
1966
1967 dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);
1968 mutex_unlock(&ch->open_lock);
1969
1970 return 0;
1971}
1972
1973static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
1974 struct fb_info *info)
1975{
1976 struct sh_mobile_lcdc_chan *ch = info->par;
1977 struct sh_mobile_lcdc_priv *p = ch->lcdc;
1978 unsigned int best_dist = (unsigned int)-1;
1979 unsigned int best_xres = 0;
1980 unsigned int best_yres = 0;
1981 unsigned int i;
1982 int ret;
1983
1984
1985
1986
1987
1988
1989 for (i = 0; i < ch->cfg->num_modes; ++i) {
1990 const struct fb_videomode *mode = &ch->cfg->lcd_modes[i];
1991 unsigned int dist;
1992
1993
1994 if (var->xres > mode->xres || var->yres > mode->yres)
1995 continue;
1996
1997 dist = var->xres * var->yres + mode->xres * mode->yres
1998 - 2 * min(var->xres, mode->xres)
1999 * min(var->yres, mode->yres);
2000
2001 if (dist < best_dist) {
2002 best_xres = mode->xres;
2003 best_yres = mode->yres;
2004 best_dist = dist;
2005 }
2006 }
2007
2008
2009 if (ch->cfg->num_modes != 0) {
2010 if (best_dist == (unsigned int)-1)
2011 return -EINVAL;
2012
2013 var->xres = best_xres;
2014 var->yres = best_yres;
2015 }
2016
2017 ret = __sh_mobile_lcdc_check_var(var, info);
2018 if (ret < 0)
2019 return ret;
2020
2021
2022 if (p->forced_fourcc &&
2023 p->forced_fourcc != sh_mobile_format_fourcc(var))
2024 return -EINVAL;
2025
2026 return 0;
2027}
2028
2029static int sh_mobile_lcdc_set_par(struct fb_info *info)
2030{
2031 struct sh_mobile_lcdc_chan *ch = info->par;
2032 int ret;
2033
2034 sh_mobile_lcdc_stop(ch->lcdc);
2035
2036 ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
2037 ch->colorspace = info->var.colorspace;
2038
2039 ch->xres = info->var.xres;
2040 ch->xres_virtual = info->var.xres_virtual;
2041 ch->yres = info->var.yres;
2042 ch->yres_virtual = info->var.yres_virtual;
2043
2044 if (ch->format->yuv)
2045 ch->pitch = info->var.xres_virtual;
2046 else
2047 ch->pitch = info->var.xres_virtual * ch->format->bpp / 8;
2048
2049 ret = sh_mobile_lcdc_start(ch->lcdc);
2050 if (ret < 0)
2051 dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);
2052
2053 info->fix.line_length = ch->pitch;
2054
2055 if (sh_mobile_format_is_fourcc(&info->var)) {
2056 info->fix.type = FB_TYPE_FOURCC;
2057 info->fix.visual = FB_VISUAL_FOURCC;
2058 } else {
2059 info->fix.type = FB_TYPE_PACKED_PIXELS;
2060 info->fix.visual = FB_VISUAL_TRUECOLOR;
2061 }
2062
2063 return ret;
2064}
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074static int sh_mobile_lcdc_blank(int blank, struct fb_info *info)
2075{
2076 struct sh_mobile_lcdc_chan *ch = info->par;
2077 struct sh_mobile_lcdc_priv *p = ch->lcdc;
2078
2079
2080 if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) {
2081 struct fb_fillrect rect = {
2082 .width = ch->xres,
2083 .height = ch->yres,
2084 };
2085 sh_mobile_lcdc_fillrect(info, &rect);
2086 }
2087
2088 if (blank <= FB_BLANK_NORMAL && ch->blank_status > FB_BLANK_NORMAL) {
2089 sh_mobile_lcdc_clk_on(p);
2090 }
2091
2092 if (blank > FB_BLANK_NORMAL && ch->blank_status <= FB_BLANK_NORMAL) {
2093
2094
2095
2096
2097
2098 if (!info->fbdefio) {
2099 sh_mobile_lcdc_wait_for_vsync(ch);
2100 sh_mobile_lcdc_wait_for_vsync(ch);
2101 }
2102 sh_mobile_lcdc_clk_off(p);
2103 }
2104
2105 ch->blank_status = blank;
2106 return 0;
2107}
2108
2109static int
2110sh_mobile_lcdc_mmap(struct fb_info *info, struct vm_area_struct *vma)
2111{
2112 struct sh_mobile_lcdc_chan *ch = info->par;
2113
2114 return dma_mmap_coherent(ch->lcdc->dev, vma, ch->fb_mem,
2115 ch->dma_handle, ch->fb_size);
2116}
2117
2118static struct fb_ops sh_mobile_lcdc_ops = {
2119 .owner = THIS_MODULE,
2120 .fb_setcolreg = sh_mobile_lcdc_setcolreg,
2121 .fb_read = fb_sys_read,
2122 .fb_write = fb_sys_write,
2123 .fb_fillrect = sh_mobile_lcdc_fillrect,
2124 .fb_copyarea = sh_mobile_lcdc_copyarea,
2125 .fb_imageblit = sh_mobile_lcdc_imageblit,
2126 .fb_blank = sh_mobile_lcdc_blank,
2127 .fb_pan_display = sh_mobile_lcdc_pan,
2128 .fb_ioctl = sh_mobile_lcdc_ioctl,
2129 .fb_open = sh_mobile_lcdc_open,
2130 .fb_release = sh_mobile_lcdc_release,
2131 .fb_check_var = sh_mobile_lcdc_check_var,
2132 .fb_set_par = sh_mobile_lcdc_set_par,
2133 .fb_mmap = sh_mobile_lcdc_mmap,
2134};
2135
2136static void
2137sh_mobile_lcdc_channel_fb_unregister(struct sh_mobile_lcdc_chan *ch)
2138{
2139 if (ch->info && ch->info->dev)
2140 unregister_framebuffer(ch->info);
2141}
2142
2143static int
2144sh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch)
2145{
2146 struct fb_info *info = ch->info;
2147 int ret;
2148
2149 if (info->fbdefio) {
2150 ch->sglist = vmalloc(sizeof(struct scatterlist) *
2151 ch->fb_size >> PAGE_SHIFT);
2152 if (!ch->sglist) {
2153 dev_err(ch->lcdc->dev, "cannot allocate sglist\n");
2154 return -ENOMEM;
2155 }
2156 }
2157
2158 info->bl_dev = ch->bl;
2159
2160 ret = register_framebuffer(info);
2161 if (ret < 0)
2162 return ret;
2163
2164 dev_info(ch->lcdc->dev, "registered %s/%s as %dx%d %dbpp.\n",
2165 dev_name(ch->lcdc->dev), (ch->cfg->chan == LCDC_CHAN_MAINLCD) ?
2166 "mainlcd" : "sublcd", info->var.xres, info->var.yres,
2167 info->var.bits_per_pixel);
2168
2169
2170 if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)
2171 sh_mobile_lcdc_clk_off(ch->lcdc);
2172
2173 return ret;
2174}
2175
2176static void
2177sh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch)
2178{
2179 struct fb_info *info = ch->info;
2180
2181 if (!info || !info->device)
2182 return;
2183
2184 vfree(ch->sglist);
2185
2186 fb_dealloc_cmap(&info->cmap);
2187 framebuffer_release(info);
2188}
2189
2190static int
2191sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
2192 const struct fb_videomode *modes,
2193 unsigned int num_modes)
2194{
2195 struct sh_mobile_lcdc_priv *priv = ch->lcdc;
2196 struct fb_var_screeninfo *var;
2197 struct fb_info *info;
2198 int ret;
2199
2200
2201
2202
2203 info = framebuffer_alloc(0, priv->dev);
2204 if (info == NULL) {
2205 dev_err(priv->dev, "unable to allocate fb_info\n");
2206 return -ENOMEM;
2207 }
2208
2209 ch->info = info;
2210
2211 info->flags = FBINFO_FLAG_DEFAULT;
2212 info->fbops = &sh_mobile_lcdc_ops;
2213 info->device = priv->dev;
2214 info->screen_base = ch->fb_mem;
2215 info->pseudo_palette = &ch->pseudo_palette;
2216 info->par = ch;
2217
2218 fb_videomode_to_modelist(modes, num_modes, &info->modelist);
2219
2220 ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
2221 if (ret < 0) {
2222 dev_err(priv->dev, "unable to allocate cmap\n");
2223 return ret;
2224 }
2225
2226
2227
2228
2229 info->fix = sh_mobile_lcdc_fix;
2230 info->fix.smem_start = ch->dma_handle;
2231 info->fix.smem_len = ch->fb_size;
2232 info->fix.line_length = ch->pitch;
2233
2234 if (ch->format->yuv)
2235 info->fix.visual = FB_VISUAL_FOURCC;
2236 else
2237 info->fix.visual = FB_VISUAL_TRUECOLOR;
2238
2239 switch (ch->format->fourcc) {
2240 case V4L2_PIX_FMT_NV12:
2241 case V4L2_PIX_FMT_NV21:
2242 info->fix.ypanstep = 2;
2243 case V4L2_PIX_FMT_NV16:
2244 case V4L2_PIX_FMT_NV61:
2245 info->fix.xpanstep = 2;
2246 }
2247
2248
2249
2250
2251 var = &info->var;
2252 fb_videomode_to_var(var, modes);
2253 var->width = ch->display.width;
2254 var->height = ch->display.height;
2255 var->xres_virtual = ch->xres_virtual;
2256 var->yres_virtual = ch->yres_virtual;
2257 var->activate = FB_ACTIVATE_NOW;
2258
2259
2260
2261
2262 if (!ch->format->yuv)
2263 var->bits_per_pixel = ch->format->bpp;
2264 else
2265 var->grayscale = ch->format->fourcc;
2266
2267 ret = sh_mobile_lcdc_check_var(var, info);
2268 if (ret)
2269 return ret;
2270
2271 return 0;
2272}
2273
2274
2275
2276
2277
2278static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev)
2279{
2280 struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
2281 int brightness = bdev->props.brightness;
2282
2283 if (bdev->props.power != FB_BLANK_UNBLANK ||
2284 bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
2285 brightness = 0;
2286
2287 ch->bl_brightness = brightness;
2288 return ch->cfg->bl_info.set_brightness(brightness);
2289}
2290
2291static int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev)
2292{
2293 struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
2294
2295 return ch->bl_brightness;
2296}
2297
2298static int sh_mobile_lcdc_check_fb(struct backlight_device *bdev,
2299 struct fb_info *info)
2300{
2301 return (info->bl_dev == bdev);
2302}
2303
2304static struct backlight_ops sh_mobile_lcdc_bl_ops = {
2305 .options = BL_CORE_SUSPENDRESUME,
2306 .update_status = sh_mobile_lcdc_update_bl,
2307 .get_brightness = sh_mobile_lcdc_get_brightness,
2308 .check_fb = sh_mobile_lcdc_check_fb,
2309};
2310
2311static struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent,
2312 struct sh_mobile_lcdc_chan *ch)
2313{
2314 struct backlight_device *bl;
2315
2316 bl = backlight_device_register(ch->cfg->bl_info.name, parent, ch,
2317 &sh_mobile_lcdc_bl_ops, NULL);
2318 if (IS_ERR(bl)) {
2319 dev_err(parent, "unable to register backlight device: %ld\n",
2320 PTR_ERR(bl));
2321 return NULL;
2322 }
2323
2324 bl->props.max_brightness = ch->cfg->bl_info.max_brightness;
2325 bl->props.brightness = bl->props.max_brightness;
2326 backlight_update_status(bl);
2327
2328 return bl;
2329}
2330
2331static void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev)
2332{
2333 backlight_device_unregister(bdev);
2334}
2335
2336
2337
2338
2339
2340static int sh_mobile_lcdc_suspend(struct device *dev)
2341{
2342 struct platform_device *pdev = to_platform_device(dev);
2343
2344 sh_mobile_lcdc_stop(platform_get_drvdata(pdev));
2345 return 0;
2346}
2347
2348static int sh_mobile_lcdc_resume(struct device *dev)
2349{
2350 struct platform_device *pdev = to_platform_device(dev);
2351
2352 return sh_mobile_lcdc_start(platform_get_drvdata(pdev));
2353}
2354
2355static int sh_mobile_lcdc_runtime_suspend(struct device *dev)
2356{
2357 struct platform_device *pdev = to_platform_device(dev);
2358 struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
2359
2360
2361 lcdc_write(priv, _LDCNT1R, 0);
2362
2363 return 0;
2364}
2365
2366static int sh_mobile_lcdc_runtime_resume(struct device *dev)
2367{
2368 struct platform_device *pdev = to_platform_device(dev);
2369 struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
2370
2371 __sh_mobile_lcdc_start(priv);
2372
2373 return 0;
2374}
2375
2376static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
2377 .suspend = sh_mobile_lcdc_suspend,
2378 .resume = sh_mobile_lcdc_resume,
2379 .runtime_suspend = sh_mobile_lcdc_runtime_suspend,
2380 .runtime_resume = sh_mobile_lcdc_runtime_resume,
2381};
2382
2383
2384
2385
2386
2387
2388static int sh_mobile_lcdc_notify(struct notifier_block *nb,
2389 unsigned long action, void *data)
2390{
2391 struct fb_event *event = data;
2392 struct fb_info *info = event->info;
2393 struct sh_mobile_lcdc_chan *ch = info->par;
2394
2395 if (&ch->lcdc->notifier != nb)
2396 return NOTIFY_DONE;
2397
2398 dev_dbg(info->dev, "%s(): action = %lu, data = %p\n",
2399 __func__, action, event->data);
2400
2401 switch(action) {
2402 case FB_EVENT_SUSPEND:
2403 sh_mobile_lcdc_display_off(ch);
2404 sh_mobile_lcdc_stop(ch->lcdc);
2405 break;
2406 case FB_EVENT_RESUME:
2407 mutex_lock(&ch->open_lock);
2408 sh_mobile_fb_reconfig(info);
2409 mutex_unlock(&ch->open_lock);
2410
2411 sh_mobile_lcdc_display_on(ch);
2412 sh_mobile_lcdc_start(ch->lcdc);
2413 }
2414
2415 return NOTIFY_OK;
2416}
2417
2418
2419
2420
2421
2422static const struct fb_videomode default_720p = {
2423 .name = "HDMI 720p",
2424 .xres = 1280,
2425 .yres = 720,
2426
2427 .left_margin = 220,
2428 .right_margin = 110,
2429 .hsync_len = 40,
2430
2431 .upper_margin = 20,
2432 .lower_margin = 5,
2433 .vsync_len = 5,
2434
2435 .pixclock = 13468,
2436 .refresh = 60,
2437 .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
2438};
2439
2440static int sh_mobile_lcdc_remove(struct platform_device *pdev)
2441{
2442 struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
2443 unsigned int i;
2444
2445 fb_unregister_client(&priv->notifier);
2446
2447 for (i = 0; i < ARRAY_SIZE(priv->overlays); i++)
2448 sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]);
2449 for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
2450 sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]);
2451
2452 sh_mobile_lcdc_stop(priv);
2453
2454 for (i = 0; i < ARRAY_SIZE(priv->overlays); i++) {
2455 struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
2456
2457 sh_mobile_lcdc_overlay_fb_cleanup(ovl);
2458
2459 if (ovl->fb_mem)
2460 dma_free_coherent(&pdev->dev, ovl->fb_size,
2461 ovl->fb_mem, ovl->dma_handle);
2462 }
2463
2464 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
2465 struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
2466
2467 if (ch->tx_dev) {
2468 ch->tx_dev->lcdc = NULL;
2469 module_put(ch->cfg->tx_dev->dev.driver->owner);
2470 }
2471
2472 sh_mobile_lcdc_channel_fb_cleanup(ch);
2473
2474 if (ch->fb_mem)
2475 dma_free_coherent(&pdev->dev, ch->fb_size,
2476 ch->fb_mem, ch->dma_handle);
2477 }
2478
2479 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
2480 struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
2481
2482 if (ch->bl)
2483 sh_mobile_lcdc_bl_remove(ch->bl);
2484 mutex_destroy(&ch->open_lock);
2485 }
2486
2487 if (priv->dot_clk) {
2488 pm_runtime_disable(&pdev->dev);
2489 clk_put(priv->dot_clk);
2490 }
2491
2492 if (priv->base)
2493 iounmap(priv->base);
2494
2495 if (priv->irq)
2496 free_irq(priv->irq, priv);
2497 kfree(priv);
2498 return 0;
2499}
2500
2501static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
2502{
2503 int interface_type = ch->cfg->interface_type;
2504
2505 switch (interface_type) {
2506 case RGB8:
2507 case RGB9:
2508 case RGB12A:
2509 case RGB12B:
2510 case RGB16:
2511 case RGB18:
2512 case RGB24:
2513 case SYS8A:
2514 case SYS8B:
2515 case SYS8C:
2516 case SYS8D:
2517 case SYS9:
2518 case SYS12:
2519 case SYS16A:
2520 case SYS16B:
2521 case SYS16C:
2522 case SYS18:
2523 case SYS24:
2524 break;
2525 default:
2526 return -EINVAL;
2527 }
2528
2529
2530 if (lcdc_chan_is_sublcd(ch)) {
2531 if (!(interface_type & LDMT1R_IFM))
2532 return -EINVAL;
2533
2534 interface_type &= ~LDMT1R_IFM;
2535 }
2536
2537 ch->ldmt1r_value = interface_type;
2538 return 0;
2539}
2540
2541static int
2542sh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_overlay *ovl)
2543{
2544 const struct sh_mobile_lcdc_format_info *format;
2545 struct device *dev = ovl->channel->lcdc->dev;
2546 int ret;
2547
2548 if (ovl->cfg->fourcc == 0)
2549 return 0;
2550
2551
2552 format = sh_mobile_format_info(ovl->cfg->fourcc);
2553 if (format == NULL) {
2554 dev_err(dev, "Invalid FOURCC %08x\n", ovl->cfg->fourcc);
2555 return -EINVAL;
2556 }
2557
2558 ovl->enabled = false;
2559 ovl->mode = LCDC_OVERLAY_BLEND;
2560 ovl->alpha = 255;
2561 ovl->rop3 = 0;
2562 ovl->pos_x = 0;
2563 ovl->pos_y = 0;
2564
2565
2566
2567
2568 ovl->format = format;
2569 ovl->xres = ovl->cfg->max_xres;
2570 ovl->xres_virtual = ovl->xres;
2571 ovl->yres = ovl->cfg->max_yres;
2572 ovl->yres_virtual = ovl->yres * 2;
2573
2574 if (!format->yuv)
2575 ovl->pitch = ovl->xres_virtual * format->bpp / 8;
2576 else
2577 ovl->pitch = ovl->xres_virtual;
2578
2579
2580 ovl->fb_size = ovl->cfg->max_xres * ovl->cfg->max_yres
2581 * format->bpp / 8 * 2;
2582 ovl->fb_mem = dma_alloc_coherent(dev, ovl->fb_size, &ovl->dma_handle,
2583 GFP_KERNEL);
2584 if (!ovl->fb_mem) {
2585 dev_err(dev, "unable to allocate buffer\n");
2586 return -ENOMEM;
2587 }
2588
2589 ret = sh_mobile_lcdc_overlay_fb_init(ovl);
2590 if (ret < 0)
2591 return ret;
2592
2593 return 0;
2594}
2595
2596static int
2597sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch)
2598{
2599 const struct sh_mobile_lcdc_format_info *format;
2600 const struct sh_mobile_lcdc_chan_cfg *cfg = ch->cfg;
2601 struct device *dev = ch->lcdc->dev;
2602 const struct fb_videomode *max_mode;
2603 const struct fb_videomode *mode;
2604 unsigned int num_modes;
2605 unsigned int max_size;
2606 unsigned int i;
2607
2608 ch->notify = sh_mobile_lcdc_display_notify;
2609
2610
2611 format = sh_mobile_format_info(cfg->fourcc);
2612 if (format == NULL) {
2613 dev_err(dev, "Invalid FOURCC %08x.\n", cfg->fourcc);
2614 return -EINVAL;
2615 }
2616
2617
2618
2619
2620 max_mode = NULL;
2621 max_size = 0;
2622
2623 for (i = 0, mode = cfg->lcd_modes; i < cfg->num_modes; i++, mode++) {
2624 unsigned int size = mode->yres * mode->xres;
2625
2626
2627 if ((cfg->fourcc == V4L2_PIX_FMT_NV12 ||
2628 cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) {
2629 dev_err(dev, "yres must be multiple of 2 for "
2630 "YCbCr420 mode.\n");
2631 return -EINVAL;
2632 }
2633
2634 if (size > max_size) {
2635 max_mode = mode;
2636 max_size = size;
2637 }
2638 }
2639
2640 if (!max_size)
2641 max_size = MAX_XRES * MAX_YRES;
2642 else
2643 dev_dbg(dev, "Found largest videomode %ux%u\n",
2644 max_mode->xres, max_mode->yres);
2645
2646 if (cfg->lcd_modes == NULL) {
2647 mode = &default_720p;
2648 num_modes = 1;
2649 } else {
2650 mode = cfg->lcd_modes;
2651 num_modes = cfg->num_modes;
2652 }
2653
2654
2655
2656
2657 ch->format = format;
2658 ch->xres = mode->xres;
2659 ch->xres_virtual = mode->xres;
2660 ch->yres = mode->yres;
2661 ch->yres_virtual = mode->yres * 2;
2662
2663 if (!format->yuv) {
2664 ch->colorspace = V4L2_COLORSPACE_SRGB;
2665 ch->pitch = ch->xres_virtual * format->bpp / 8;
2666 } else {
2667 ch->colorspace = V4L2_COLORSPACE_REC709;
2668 ch->pitch = ch->xres_virtual;
2669 }
2670
2671 ch->display.width = cfg->panel_cfg.width;
2672 ch->display.height = cfg->panel_cfg.height;
2673 ch->display.mode = *mode;
2674
2675
2676 ch->fb_size = max_size * format->bpp / 8 * 2;
2677 ch->fb_mem = dma_alloc_coherent(dev, ch->fb_size, &ch->dma_handle,
2678 GFP_KERNEL);
2679 if (ch->fb_mem == NULL) {
2680 dev_err(dev, "unable to allocate buffer\n");
2681 return -ENOMEM;
2682 }
2683
2684
2685 if (cfg->tx_dev) {
2686 if (!cfg->tx_dev->dev.driver ||
2687 !try_module_get(cfg->tx_dev->dev.driver->owner)) {
2688 dev_warn(dev, "unable to get transmitter device\n");
2689 return -EINVAL;
2690 }
2691 ch->tx_dev = platform_get_drvdata(cfg->tx_dev);
2692 ch->tx_dev->lcdc = ch;
2693 ch->tx_dev->def_mode = *mode;
2694 }
2695
2696 return sh_mobile_lcdc_channel_fb_init(ch, mode, num_modes);
2697}
2698
2699static int sh_mobile_lcdc_probe(struct platform_device *pdev)
2700{
2701 struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data;
2702 struct sh_mobile_lcdc_priv *priv;
2703 struct resource *res;
2704 int num_channels;
2705 int error;
2706 int irq, i;
2707
2708 if (!pdata) {
2709 dev_err(&pdev->dev, "no platform data defined\n");
2710 return -EINVAL;
2711 }
2712
2713 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2714 irq = platform_get_irq(pdev, 0);
2715 if (!res || irq < 0) {
2716 dev_err(&pdev->dev, "cannot get platform resources\n");
2717 return -ENOENT;
2718 }
2719
2720 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
2721 if (!priv) {
2722 dev_err(&pdev->dev, "cannot allocate device data\n");
2723 return -ENOMEM;
2724 }
2725
2726 priv->dev = &pdev->dev;
2727 priv->meram_dev = pdata->meram_dev;
2728 for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
2729 mutex_init(&priv->ch[i].open_lock);
2730 platform_set_drvdata(pdev, priv);
2731
2732 error = request_irq(irq, sh_mobile_lcdc_irq, 0,
2733 dev_name(&pdev->dev), priv);
2734 if (error) {
2735 dev_err(&pdev->dev, "unable to request irq\n");
2736 goto err1;
2737 }
2738
2739 priv->irq = irq;
2740 atomic_set(&priv->hw_usecnt, -1);
2741
2742 for (i = 0, num_channels = 0; i < ARRAY_SIZE(pdata->ch); i++) {
2743 struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels;
2744
2745 ch->lcdc = priv;
2746 ch->cfg = &pdata->ch[i];
2747
2748 error = sh_mobile_lcdc_check_interface(ch);
2749 if (error) {
2750 dev_err(&pdev->dev, "unsupported interface type\n");
2751 goto err1;
2752 }
2753 init_waitqueue_head(&ch->frame_end_wait);
2754 init_completion(&ch->vsync_completion);
2755
2756
2757 if (ch->cfg->bl_info.max_brightness)
2758 ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch);
2759
2760 switch (pdata->ch[i].chan) {
2761 case LCDC_CHAN_MAINLCD:
2762 ch->enabled = LDCNT2R_ME;
2763 ch->reg_offs = lcdc_offs_mainlcd;
2764 num_channels++;
2765 break;
2766 case LCDC_CHAN_SUBLCD:
2767 ch->enabled = LDCNT2R_SE;
2768 ch->reg_offs = lcdc_offs_sublcd;
2769 num_channels++;
2770 break;
2771 }
2772 }
2773
2774 if (!num_channels) {
2775 dev_err(&pdev->dev, "no channels defined\n");
2776 error = -EINVAL;
2777 goto err1;
2778 }
2779
2780
2781 if (num_channels == 2)
2782 priv->forced_fourcc = pdata->ch[0].fourcc;
2783
2784 priv->base = ioremap_nocache(res->start, resource_size(res));
2785 if (!priv->base)
2786 goto err1;
2787
2788 error = sh_mobile_lcdc_setup_clocks(priv, pdata->clock_source);
2789 if (error) {
2790 dev_err(&pdev->dev, "unable to setup clocks\n");
2791 goto err1;
2792 }
2793
2794
2795 pm_runtime_enable(&pdev->dev);
2796
2797 for (i = 0; i < num_channels; i++) {
2798 struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
2799
2800 error = sh_mobile_lcdc_channel_init(ch);
2801 if (error)
2802 goto err1;
2803 }
2804
2805 for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {
2806 struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
2807
2808 ovl->cfg = &pdata->overlays[i];
2809 ovl->channel = &priv->ch[0];
2810
2811 error = sh_mobile_lcdc_overlay_init(ovl);
2812 if (error)
2813 goto err1;
2814 }
2815
2816 error = sh_mobile_lcdc_start(priv);
2817 if (error) {
2818 dev_err(&pdev->dev, "unable to start hardware\n");
2819 goto err1;
2820 }
2821
2822 for (i = 0; i < num_channels; i++) {
2823 struct sh_mobile_lcdc_chan *ch = priv->ch + i;
2824
2825 error = sh_mobile_lcdc_channel_fb_register(ch);
2826 if (error)
2827 goto err1;
2828 }
2829
2830 for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {
2831 struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
2832
2833 error = sh_mobile_lcdc_overlay_fb_register(ovl);
2834 if (error)
2835 goto err1;
2836 }
2837
2838
2839 priv->notifier.notifier_call = sh_mobile_lcdc_notify;
2840 fb_register_client(&priv->notifier);
2841
2842 return 0;
2843err1:
2844 sh_mobile_lcdc_remove(pdev);
2845
2846 return error;
2847}
2848
2849static struct platform_driver sh_mobile_lcdc_driver = {
2850 .driver = {
2851 .name = "sh_mobile_lcdc_fb",
2852 .pm = &sh_mobile_lcdc_dev_pm_ops,
2853 },
2854 .probe = sh_mobile_lcdc_probe,
2855 .remove = sh_mobile_lcdc_remove,
2856};
2857
2858module_platform_driver(sh_mobile_lcdc_driver);
2859
2860MODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver");
2861MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
2862MODULE_LICENSE("GPL v2");
2863