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