]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/video/sh_mobile_lcdcfb.c
x86_64: fix incorrect comments
[mv-sheeva.git] / drivers / video / sh_mobile_lcdcfb.c
1 /*
2  * SuperH Mobile LCDC Framebuffer
3  *
4  * Copyright (c) 2008 Magnus Damm
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License.  See the file "COPYING" in the main directory of this archive
8  * for more details.
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/delay.h>
14 #include <linux/mm.h>
15 #include <linux/fb.h>
16 #include <linux/clk.h>
17 #include <linux/platform_device.h>
18 #include <linux/dma-mapping.h>
19 #include <linux/interrupt.h>
20 #include <video/sh_mobile_lcdc.h>
21 #include <asm/atomic.h>
22
23 #define PALETTE_NR 16
24
25 struct sh_mobile_lcdc_priv;
26 struct sh_mobile_lcdc_chan {
27         struct sh_mobile_lcdc_priv *lcdc;
28         unsigned long *reg_offs;
29         unsigned long ldmt1r_value;
30         unsigned long enabled; /* ME and SE in LDCNT2R */
31         struct sh_mobile_lcdc_chan_cfg cfg;
32         u32 pseudo_palette[PALETTE_NR];
33         struct fb_info info;
34         dma_addr_t dma_handle;
35         struct fb_deferred_io defio;
36         unsigned long frame_end;
37         wait_queue_head_t frame_end_wait;
38 };
39
40 struct sh_mobile_lcdc_priv {
41         void __iomem *base;
42         int irq;
43 #ifdef CONFIG_HAVE_CLK
44         atomic_t clk_usecnt;
45         struct clk *dot_clk;
46         struct clk *clk;
47 #endif
48         unsigned long lddckr;
49         struct sh_mobile_lcdc_chan ch[2];
50 };
51
52 /* shared registers */
53 #define _LDDCKR 0x410
54 #define _LDDCKSTPR 0x414
55 #define _LDINTR 0x468
56 #define _LDSR 0x46c
57 #define _LDCNT1R 0x470
58 #define _LDCNT2R 0x474
59 #define _LDDDSR 0x47c
60 #define _LDDWD0R 0x800
61 #define _LDDRDR 0x840
62 #define _LDDWAR 0x900
63 #define _LDDRAR 0x904
64
65 /* per-channel registers */
66 enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R,
67        LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR };
68
69 static unsigned long lcdc_offs_mainlcd[] = {
70         [LDDCKPAT1R] = 0x400,
71         [LDDCKPAT2R] = 0x404,
72         [LDMT1R] = 0x418,
73         [LDMT2R] = 0x41c,
74         [LDMT3R] = 0x420,
75         [LDDFR] = 0x424,
76         [LDSM1R] = 0x428,
77         [LDSM2R] = 0x42c,
78         [LDSA1R] = 0x430,
79         [LDMLSR] = 0x438,
80         [LDHCNR] = 0x448,
81         [LDHSYNR] = 0x44c,
82         [LDVLNR] = 0x450,
83         [LDVSYNR] = 0x454,
84         [LDPMR] = 0x460,
85 };
86
87 static unsigned long lcdc_offs_sublcd[] = {
88         [LDDCKPAT1R] = 0x408,
89         [LDDCKPAT2R] = 0x40c,
90         [LDMT1R] = 0x600,
91         [LDMT2R] = 0x604,
92         [LDMT3R] = 0x608,
93         [LDDFR] = 0x60c,
94         [LDSM1R] = 0x610,
95         [LDSM2R] = 0x614,
96         [LDSA1R] = 0x618,
97         [LDMLSR] = 0x620,
98         [LDHCNR] = 0x624,
99         [LDHSYNR] = 0x628,
100         [LDVLNR] = 0x62c,
101         [LDVSYNR] = 0x630,
102         [LDPMR] = 0x63c,
103 };
104
105 #define START_LCDC      0x00000001
106 #define LCDC_RESET      0x00000100
107 #define DISPLAY_BEU     0x00000008
108 #define LCDC_ENABLE     0x00000001
109 #define LDINTR_FE       0x00000400
110 #define LDINTR_FS       0x00000004
111
112 static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan,
113                             int reg_nr, unsigned long data)
114 {
115         iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr]);
116 }
117
118 static unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan,
119                                     int reg_nr)
120 {
121         return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]);
122 }
123
124 static void lcdc_write(struct sh_mobile_lcdc_priv *priv,
125                        unsigned long reg_offs, unsigned long data)
126 {
127         iowrite32(data, priv->base + reg_offs);
128 }
129
130 static unsigned long lcdc_read(struct sh_mobile_lcdc_priv *priv,
131                                unsigned long reg_offs)
132 {
133         return ioread32(priv->base + reg_offs);
134 }
135
136 static void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv,
137                           unsigned long reg_offs,
138                           unsigned long mask, unsigned long until)
139 {
140         while ((lcdc_read(priv, reg_offs) & mask) != until)
141                 cpu_relax();
142 }
143
144 static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan)
145 {
146         return chan->cfg.chan == LCDC_CHAN_SUBLCD;
147 }
148
149 static void lcdc_sys_write_index(void *handle, unsigned long data)
150 {
151         struct sh_mobile_lcdc_chan *ch = handle;
152
153         lcdc_write(ch->lcdc, _LDDWD0R, data | 0x10000000);
154         lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
155         lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0));
156 }
157
158 static void lcdc_sys_write_data(void *handle, unsigned long data)
159 {
160         struct sh_mobile_lcdc_chan *ch = handle;
161
162         lcdc_write(ch->lcdc, _LDDWD0R, data | 0x11000000);
163         lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
164         lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0));
165 }
166
167 static unsigned long lcdc_sys_read_data(void *handle)
168 {
169         struct sh_mobile_lcdc_chan *ch = handle;
170
171         lcdc_write(ch->lcdc, _LDDRDR, 0x01000000);
172         lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
173         lcdc_write(ch->lcdc, _LDDRAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0));
174         udelay(1);
175
176         return lcdc_read(ch->lcdc, _LDDRDR) & 0xffff;
177 }
178
179 struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
180         lcdc_sys_write_index,
181         lcdc_sys_write_data,
182         lcdc_sys_read_data,
183 };
184
185 #ifdef CONFIG_HAVE_CLK
186 static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
187 {
188         if (atomic_inc_and_test(&priv->clk_usecnt)) {
189                 clk_enable(priv->clk);
190                 if (priv->dot_clk)
191                         clk_enable(priv->dot_clk);
192         }
193 }
194
195 static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
196 {
197         if (atomic_sub_return(1, &priv->clk_usecnt) == -1) {
198                 if (priv->dot_clk)
199                         clk_disable(priv->dot_clk);
200                 clk_disable(priv->clk);
201         }
202 }
203 #else
204 static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) {}
205 static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) {}
206 #endif
207
208 static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
209                                        struct list_head *pagelist)
210 {
211         struct sh_mobile_lcdc_chan *ch = info->par;
212
213         /* enable clocks before accessing hardware */
214         sh_mobile_lcdc_clk_on(ch->lcdc);
215
216         /* trigger panel update */
217         lcdc_write_chan(ch, LDSM2R, 1);
218 }
219
220 static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
221 {
222         struct fb_deferred_io *fbdefio = info->fbdefio;
223
224         if (fbdefio)
225                 schedule_delayed_work(&info->deferred_work, fbdefio->delay);
226 }
227
228 static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
229 {
230         struct sh_mobile_lcdc_priv *priv = data;
231         struct sh_mobile_lcdc_chan *ch;
232         unsigned long tmp;
233         int is_sub;
234         int k;
235
236         /* acknowledge interrupt */
237         tmp = lcdc_read(priv, _LDINTR);
238         tmp &= 0xffffff00; /* mask in high 24 bits */
239         tmp |= 0x000000ff ^ LDINTR_FS; /* status in low 8 */
240         lcdc_write(priv, _LDINTR, tmp);
241
242         /* figure out if this interrupt is for main or sub lcd */
243         is_sub = (lcdc_read(priv, _LDSR) & (1 << 10)) ? 1 : 0;
244
245         /* wake up channel and disable clocks*/
246         for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
247                 ch = &priv->ch[k];
248
249                 if (!ch->enabled)
250                         continue;
251
252                 if (is_sub == lcdc_chan_is_sublcd(ch)) {
253                         ch->frame_end = 1;
254                         wake_up(&ch->frame_end_wait);
255
256                         sh_mobile_lcdc_clk_off(priv);
257                 }
258         }
259
260         return IRQ_HANDLED;
261 }
262
263 static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
264                                       int start)
265 {
266         unsigned long tmp = lcdc_read(priv, _LDCNT2R);
267         int k;
268
269         /* start or stop the lcdc */
270         if (start)
271                 lcdc_write(priv, _LDCNT2R, tmp | START_LCDC);
272         else
273                 lcdc_write(priv, _LDCNT2R, tmp & ~START_LCDC);
274
275         /* wait until power is applied/stopped on all channels */
276         for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
277                 if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled)
278                         while (1) {
279                                 tmp = lcdc_read_chan(&priv->ch[k], LDPMR) & 3;
280                                 if (start && tmp == 3)
281                                         break;
282                                 if (!start && tmp == 0)
283                                         break;
284                                 cpu_relax();
285                         }
286
287         if (!start)
288                 lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */
289 }
290
291 static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
292 {
293         struct sh_mobile_lcdc_chan *ch;
294         struct fb_videomode *lcd_cfg;
295         struct sh_mobile_lcdc_board_cfg *board_cfg;
296         unsigned long tmp;
297         int k, m;
298         int ret = 0;
299
300         /* enable clocks before accessing the hardware */
301         for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
302                 if (priv->ch[k].enabled)
303                         sh_mobile_lcdc_clk_on(priv);
304
305         /* reset */
306         lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET);
307         lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0);
308
309         /* enable LCDC channels */
310         tmp = lcdc_read(priv, _LDCNT2R);
311         tmp |= priv->ch[0].enabled;
312         tmp |= priv->ch[1].enabled;
313         lcdc_write(priv, _LDCNT2R, tmp);
314
315         /* read data from external memory, avoid using the BEU for now */
316         lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU);
317
318         /* stop the lcdc first */
319         sh_mobile_lcdc_start_stop(priv, 0);
320
321         /* configure clocks */
322         tmp = priv->lddckr;
323         for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
324                 ch = &priv->ch[k];
325
326                 if (!priv->ch[k].enabled)
327                         continue;
328
329                 m = ch->cfg.clock_divider;
330                 if (!m)
331                         continue;
332
333                 if (m == 1)
334                         m = 1 << 6;
335                 tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
336
337                 lcdc_write_chan(ch, LDDCKPAT1R, 0x00000000);
338                 lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1);
339         }
340
341         lcdc_write(priv, _LDDCKR, tmp);
342
343         /* start dotclock again */
344         lcdc_write(priv, _LDDCKSTPR, 0);
345         lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0);
346
347         /* interrupts are disabled to begin with */
348         lcdc_write(priv, _LDINTR, 0);
349
350         for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
351                 ch = &priv->ch[k];
352                 lcd_cfg = &ch->cfg.lcd_cfg;
353
354                 if (!ch->enabled)
355                         continue;
356
357                 tmp = ch->ldmt1r_value;
358                 tmp |= (lcd_cfg->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28;
359                 tmp |= (lcd_cfg->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27;
360                 tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0;
361                 tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0;
362                 tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0;
363                 tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0;
364                 tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0;
365                 lcdc_write_chan(ch, LDMT1R, tmp);
366
367                 /* setup SYS bus */
368                 lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r);
369                 lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r);
370
371                 /* horizontal configuration */
372                 tmp = lcd_cfg->xres + lcd_cfg->hsync_len;
373                 tmp += lcd_cfg->left_margin;
374                 tmp += lcd_cfg->right_margin;
375                 tmp /= 8; /* HTCN */
376                 tmp |= (lcd_cfg->xres / 8) << 16; /* HDCN */
377                 lcdc_write_chan(ch, LDHCNR, tmp);
378
379                 tmp = lcd_cfg->xres;
380                 tmp += lcd_cfg->right_margin;
381                 tmp /= 8; /* HSYNP */
382                 tmp |= (lcd_cfg->hsync_len / 8) << 16; /* HSYNW */
383                 lcdc_write_chan(ch, LDHSYNR, tmp);
384
385                 /* power supply */
386                 lcdc_write_chan(ch, LDPMR, 0);
387
388                 /* vertical configuration */
389                 tmp = lcd_cfg->yres + lcd_cfg->vsync_len;
390                 tmp += lcd_cfg->upper_margin;
391                 tmp += lcd_cfg->lower_margin; /* VTLN */
392                 tmp |= lcd_cfg->yres << 16; /* VDLN */
393                 lcdc_write_chan(ch, LDVLNR, tmp);
394
395                 tmp = lcd_cfg->yres;
396                 tmp += lcd_cfg->lower_margin; /* VSYNP */
397                 tmp |= lcd_cfg->vsync_len << 16; /* VSYNW */
398                 lcdc_write_chan(ch, LDVSYNR, tmp);
399
400                 board_cfg = &ch->cfg.board_cfg;
401                 if (board_cfg->setup_sys)
402                         ret = board_cfg->setup_sys(board_cfg->board_data, ch,
403                                                    &sh_mobile_lcdc_sys_bus_ops);
404                 if (ret)
405                         return ret;
406         }
407
408         /* word and long word swap */
409         lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6);
410
411         for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
412                 ch = &priv->ch[k];
413
414                 if (!priv->ch[k].enabled)
415                         continue;
416
417                 /* set bpp format in PKF[4:0] */
418                 tmp = lcdc_read_chan(ch, LDDFR);
419                 tmp &= ~(0x0001001f);
420                 tmp |= (priv->ch[k].info.var.bits_per_pixel == 16) ? 3 : 0;
421                 lcdc_write_chan(ch, LDDFR, tmp);
422
423                 /* point out our frame buffer */
424                 lcdc_write_chan(ch, LDSA1R, ch->info.fix.smem_start);
425
426                 /* set line size */
427                 lcdc_write_chan(ch, LDMLSR, ch->info.fix.line_length);
428
429                 /* setup deferred io if SYS bus */
430                 tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
431                 if (ch->ldmt1r_value & (1 << 12) && tmp) {
432                         ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
433                         ch->defio.delay = msecs_to_jiffies(tmp);
434                         ch->info.fbdefio = &ch->defio;
435                         fb_deferred_io_init(&ch->info);
436
437                         /* one-shot mode */
438                         lcdc_write_chan(ch, LDSM1R, 1);
439
440                         /* enable "Frame End Interrupt Enable" bit */
441                         lcdc_write(priv, _LDINTR, LDINTR_FE);
442
443                 } else {
444                         /* continuous read mode */
445                         lcdc_write_chan(ch, LDSM1R, 0);
446                 }
447         }
448
449         /* display output */
450         lcdc_write(priv, _LDCNT1R, LCDC_ENABLE);
451
452         /* start the lcdc */
453         sh_mobile_lcdc_start_stop(priv, 1);
454
455         /* tell the board code to enable the panel */
456         for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
457                 ch = &priv->ch[k];
458                 board_cfg = &ch->cfg.board_cfg;
459                 if (board_cfg->display_on)
460                         board_cfg->display_on(board_cfg->board_data);
461         }
462
463         return 0;
464 }
465
466 static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
467 {
468         struct sh_mobile_lcdc_chan *ch;
469         struct sh_mobile_lcdc_board_cfg *board_cfg;
470         int k;
471
472         /* clean up deferred io and ask board code to disable panel */
473         for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
474                 ch = &priv->ch[k];
475
476                 /* deferred io mode:
477                  * flush frame, and wait for frame end interrupt
478                  * clean up deferred io and enable clock
479                  */
480                 if (ch->info.fbdefio) {
481                         ch->frame_end = 0;
482                         schedule_delayed_work(&ch->info.deferred_work, 0);
483                         wait_event(ch->frame_end_wait, ch->frame_end);
484                         fb_deferred_io_cleanup(&ch->info);
485                         ch->info.fbdefio = NULL;
486                         sh_mobile_lcdc_clk_on(priv);
487                 }
488
489                 board_cfg = &ch->cfg.board_cfg;
490                 if (board_cfg->display_off)
491                         board_cfg->display_off(board_cfg->board_data);
492
493         }
494
495         /* stop the lcdc */
496         sh_mobile_lcdc_start_stop(priv, 0);
497
498         /* stop clocks */
499         for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
500                 if (priv->ch[k].enabled)
501                         sh_mobile_lcdc_clk_off(priv);
502 }
503
504 static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
505 {
506         int ifm, miftyp;
507
508         switch (ch->cfg.interface_type) {
509         case RGB8: ifm = 0; miftyp = 0; break;
510         case RGB9: ifm = 0; miftyp = 4; break;
511         case RGB12A: ifm = 0; miftyp = 5; break;
512         case RGB12B: ifm = 0; miftyp = 6; break;
513         case RGB16: ifm = 0; miftyp = 7; break;
514         case RGB18: ifm = 0; miftyp = 10; break;
515         case RGB24: ifm = 0; miftyp = 11; break;
516         case SYS8A: ifm = 1; miftyp = 0; break;
517         case SYS8B: ifm = 1; miftyp = 1; break;
518         case SYS8C: ifm = 1; miftyp = 2; break;
519         case SYS8D: ifm = 1; miftyp = 3; break;
520         case SYS9: ifm = 1; miftyp = 4; break;
521         case SYS12: ifm = 1; miftyp = 5; break;
522         case SYS16A: ifm = 1; miftyp = 7; break;
523         case SYS16B: ifm = 1; miftyp = 8; break;
524         case SYS16C: ifm = 1; miftyp = 9; break;
525         case SYS18: ifm = 1; miftyp = 10; break;
526         case SYS24: ifm = 1; miftyp = 11; break;
527         default: goto bad;
528         }
529
530         /* SUBLCD only supports SYS interface */
531         if (lcdc_chan_is_sublcd(ch)) {
532                 if (ifm == 0)
533                         goto bad;
534                 else
535                         ifm = 0;
536         }
537
538         ch->ldmt1r_value = (ifm << 12) | miftyp;
539         return 0;
540  bad:
541         return -EINVAL;
542 }
543
544 static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
545                                        int clock_source,
546                                        struct sh_mobile_lcdc_priv *priv)
547 {
548 #ifdef CONFIG_HAVE_CLK
549         char clk_name[8];
550 #endif
551         char *str;
552         int icksel;
553
554         switch (clock_source) {
555         case LCDC_CLK_BUS: str = "bus_clk"; icksel = 0; break;
556         case LCDC_CLK_PERIPHERAL: str = "peripheral_clk"; icksel = 1; break;
557         case LCDC_CLK_EXTERNAL: str = NULL; icksel = 2; break;
558         default:
559                 return -EINVAL;
560         }
561
562         priv->lddckr = icksel << 16;
563
564 #ifdef CONFIG_HAVE_CLK
565         atomic_set(&priv->clk_usecnt, -1);
566         snprintf(clk_name, sizeof(clk_name), "lcdc%d", pdev->id);
567         priv->clk = clk_get(&pdev->dev, clk_name);
568         if (IS_ERR(priv->clk)) {
569                 dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
570                 return PTR_ERR(priv->clk);
571         }
572         
573         if (str) {
574                 priv->dot_clk = clk_get(&pdev->dev, str);
575                 if (IS_ERR(priv->dot_clk)) {
576                         dev_err(&pdev->dev, "cannot get dot clock %s\n", str);
577                         clk_put(priv->clk);
578                         return PTR_ERR(priv->dot_clk);
579                 }
580         }
581 #endif
582
583         return 0;
584 }
585
586 static int sh_mobile_lcdc_setcolreg(u_int regno,
587                                     u_int red, u_int green, u_int blue,
588                                     u_int transp, struct fb_info *info)
589 {
590         u32 *palette = info->pseudo_palette;
591
592         if (regno >= PALETTE_NR)
593                 return -EINVAL;
594
595         /* only FB_VISUAL_TRUECOLOR supported */
596
597         red >>= 16 - info->var.red.length;
598         green >>= 16 - info->var.green.length;
599         blue >>= 16 - info->var.blue.length;
600         transp >>= 16 - info->var.transp.length;
601
602         palette[regno] = (red << info->var.red.offset) |
603           (green << info->var.green.offset) |
604           (blue << info->var.blue.offset) |
605           (transp << info->var.transp.offset);
606
607         return 0;
608 }
609
610 static struct fb_fix_screeninfo sh_mobile_lcdc_fix  = {
611         .id =           "SH Mobile LCDC",
612         .type =         FB_TYPE_PACKED_PIXELS,
613         .visual =       FB_VISUAL_TRUECOLOR,
614         .accel =        FB_ACCEL_NONE,
615 };
616
617 static void sh_mobile_lcdc_fillrect(struct fb_info *info,
618                                     const struct fb_fillrect *rect)
619 {
620         sys_fillrect(info, rect);
621         sh_mobile_lcdc_deferred_io_touch(info);
622 }
623
624 static void sh_mobile_lcdc_copyarea(struct fb_info *info,
625                                     const struct fb_copyarea *area)
626 {
627         sys_copyarea(info, area);
628         sh_mobile_lcdc_deferred_io_touch(info);
629 }
630
631 static void sh_mobile_lcdc_imageblit(struct fb_info *info,
632                                      const struct fb_image *image)
633 {
634         sys_imageblit(info, image);
635         sh_mobile_lcdc_deferred_io_touch(info);
636 }
637
638 static struct fb_ops sh_mobile_lcdc_ops = {
639         .fb_setcolreg   = sh_mobile_lcdc_setcolreg,
640         .fb_read        = fb_sys_read,
641         .fb_write       = fb_sys_write,
642         .fb_fillrect    = sh_mobile_lcdc_fillrect,
643         .fb_copyarea    = sh_mobile_lcdc_copyarea,
644         .fb_imageblit   = sh_mobile_lcdc_imageblit,
645 };
646
647 static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp)
648 {
649         switch (bpp) {
650         case 16: /* PKF[4:0] = 00011 - RGB 565 */
651                 var->red.offset = 11;
652                 var->red.length = 5;
653                 var->green.offset = 5;
654                 var->green.length = 6;
655                 var->blue.offset = 0;
656                 var->blue.length = 5;
657                 var->transp.offset = 0;
658                 var->transp.length = 0;
659                 break;
660
661         case 32: /* PKF[4:0] = 00000 - RGB 888
662                   * sh7722 pdf says 00RRGGBB but reality is GGBB00RR
663                   * this may be because LDDDSR has word swap enabled..
664                   */
665                 var->red.offset = 0;
666                 var->red.length = 8;
667                 var->green.offset = 24;
668                 var->green.length = 8;
669                 var->blue.offset = 16;
670                 var->blue.length = 8;
671                 var->transp.offset = 0;
672                 var->transp.length = 0;
673                 break;
674         default:
675                 return -EINVAL;
676         }
677         var->bits_per_pixel = bpp;
678         var->red.msb_right = 0;
679         var->green.msb_right = 0;
680         var->blue.msb_right = 0;
681         var->transp.msb_right = 0;
682         return 0;
683 }
684
685 static int sh_mobile_lcdc_suspend(struct device *dev)
686 {
687         struct platform_device *pdev = to_platform_device(dev);
688
689         sh_mobile_lcdc_stop(platform_get_drvdata(pdev));
690         return 0;
691 }
692
693 static int sh_mobile_lcdc_resume(struct device *dev)
694 {
695         struct platform_device *pdev = to_platform_device(dev);
696
697         return sh_mobile_lcdc_start(platform_get_drvdata(pdev));
698 }
699
700 static struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
701         .suspend = sh_mobile_lcdc_suspend,
702         .resume = sh_mobile_lcdc_resume,
703 };
704
705 static int sh_mobile_lcdc_remove(struct platform_device *pdev);
706
707 static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
708 {
709         struct fb_info *info;
710         struct sh_mobile_lcdc_priv *priv;
711         struct sh_mobile_lcdc_info *pdata;
712         struct sh_mobile_lcdc_chan_cfg *cfg;
713         struct resource *res;
714         int error;
715         void *buf;
716         int i, j;
717
718         if (!pdev->dev.platform_data) {
719                 dev_err(&pdev->dev, "no platform data defined\n");
720                 error = -EINVAL;
721                 goto err0;
722         }
723
724         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
725         i = platform_get_irq(pdev, 0);
726         if (!res || i < 0) {
727                 dev_err(&pdev->dev, "cannot get platform resources\n");
728                 error = -ENOENT;
729                 goto err0;
730         }
731
732         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
733         if (!priv) {
734                 dev_err(&pdev->dev, "cannot allocate device data\n");
735                 error = -ENOMEM;
736                 goto err0;
737         }
738
739         error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED,
740                             dev_name(&pdev->dev), priv);
741         if (error) {
742                 dev_err(&pdev->dev, "unable to request irq\n");
743                 goto err1;
744         }
745
746         priv->irq = i;
747         platform_set_drvdata(pdev, priv);
748         pdata = pdev->dev.platform_data;
749
750         j = 0;
751         for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) {
752                 priv->ch[j].lcdc = priv;
753                 memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i]));
754
755                 error = sh_mobile_lcdc_check_interface(&priv->ch[i]);
756                 if (error) {
757                         dev_err(&pdev->dev, "unsupported interface type\n");
758                         goto err1;
759                 }
760                 init_waitqueue_head(&priv->ch[i].frame_end_wait);
761
762                 switch (pdata->ch[i].chan) {
763                 case LCDC_CHAN_MAINLCD:
764                         priv->ch[j].enabled = 1 << 1;
765                         priv->ch[j].reg_offs = lcdc_offs_mainlcd;
766                         j++;
767                         break;
768                 case LCDC_CHAN_SUBLCD:
769                         priv->ch[j].enabled = 1 << 2;
770                         priv->ch[j].reg_offs = lcdc_offs_sublcd;
771                         j++;
772                         break;
773                 }
774         }
775
776         if (!j) {
777                 dev_err(&pdev->dev, "no channels defined\n");
778                 error = -EINVAL;
779                 goto err1;
780         }
781
782         error = sh_mobile_lcdc_setup_clocks(pdev, pdata->clock_source, priv);
783         if (error) {
784                 dev_err(&pdev->dev, "unable to setup clocks\n");
785                 goto err1;
786         }
787
788         priv->base = ioremap_nocache(res->start, (res->end - res->start) + 1);
789
790         for (i = 0; i < j; i++) {
791                 info = &priv->ch[i].info;
792                 cfg = &priv->ch[i].cfg;
793
794                 info->fbops = &sh_mobile_lcdc_ops;
795                 info->var.xres = info->var.xres_virtual = cfg->lcd_cfg.xres;
796                 info->var.yres = info->var.yres_virtual = cfg->lcd_cfg.yres;
797                 info->var.width = cfg->lcd_size_cfg.width;
798                 info->var.height = cfg->lcd_size_cfg.height;
799                 info->var.activate = FB_ACTIVATE_NOW;
800                 error = sh_mobile_lcdc_set_bpp(&info->var, cfg->bpp);
801                 if (error)
802                         break;
803
804                 info->fix = sh_mobile_lcdc_fix;
805                 info->fix.line_length = cfg->lcd_cfg.xres * (cfg->bpp / 8);
806                 info->fix.smem_len = info->fix.line_length * cfg->lcd_cfg.yres;
807
808                 buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len,
809                                          &priv->ch[i].dma_handle, GFP_KERNEL);
810                 if (!buf) {
811                         dev_err(&pdev->dev, "unable to allocate buffer\n");
812                         error = -ENOMEM;
813                         break;
814                 }
815
816                 info->pseudo_palette = &priv->ch[i].pseudo_palette;
817                 info->flags = FBINFO_FLAG_DEFAULT;
818
819                 error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
820                 if (error < 0) {
821                         dev_err(&pdev->dev, "unable to allocate cmap\n");
822                         dma_free_coherent(&pdev->dev, info->fix.smem_len,
823                                           buf, priv->ch[i].dma_handle);
824                         break;
825                 }
826
827                 memset(buf, 0, info->fix.smem_len);
828                 info->fix.smem_start = priv->ch[i].dma_handle;
829                 info->screen_base = buf;
830                 info->device = &pdev->dev;
831                 info->par = &priv->ch[i];
832         }
833
834         if (error)
835                 goto err1;
836
837         error = sh_mobile_lcdc_start(priv);
838         if (error) {
839                 dev_err(&pdev->dev, "unable to start hardware\n");
840                 goto err1;
841         }
842
843         for (i = 0; i < j; i++) {
844                 error = register_framebuffer(&priv->ch[i].info);
845                 if (error < 0)
846                         goto err1;
847         }
848
849         for (i = 0; i < j; i++) {
850                 info = &priv->ch[i].info;
851                 dev_info(info->dev,
852                          "registered %s/%s as %dx%d %dbpp.\n",
853                          pdev->name,
854                          (priv->ch[i].cfg.chan == LCDC_CHAN_MAINLCD) ?
855                          "mainlcd" : "sublcd",
856                          (int) priv->ch[i].cfg.lcd_cfg.xres,
857                          (int) priv->ch[i].cfg.lcd_cfg.yres,
858                          priv->ch[i].cfg.bpp);
859
860                 /* deferred io mode: disable clock to save power */
861                 if (info->fbdefio)
862                         sh_mobile_lcdc_clk_off(priv);
863         }
864
865         return 0;
866  err1:
867         sh_mobile_lcdc_remove(pdev);
868  err0:
869         return error;
870 }
871
872 static int sh_mobile_lcdc_remove(struct platform_device *pdev)
873 {
874         struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
875         struct fb_info *info;
876         int i;
877
878         for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
879                 if (priv->ch[i].info.dev)
880                         unregister_framebuffer(&priv->ch[i].info);
881
882         sh_mobile_lcdc_stop(priv);
883
884         for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
885                 info = &priv->ch[i].info;
886
887                 if (!info->device)
888                         continue;
889
890                 dma_free_coherent(&pdev->dev, info->fix.smem_len,
891                                   info->screen_base, priv->ch[i].dma_handle);
892                 fb_dealloc_cmap(&info->cmap);
893         }
894
895 #ifdef CONFIG_HAVE_CLK
896         if (priv->dot_clk)
897                 clk_put(priv->dot_clk);
898         clk_put(priv->clk);
899 #endif
900
901         if (priv->base)
902                 iounmap(priv->base);
903
904         if (priv->irq)
905                 free_irq(priv->irq, priv);
906         kfree(priv);
907         return 0;
908 }
909
910 static struct platform_driver sh_mobile_lcdc_driver = {
911         .driver         = {
912                 .name           = "sh_mobile_lcdc_fb",
913                 .owner          = THIS_MODULE,
914                 .pm             = &sh_mobile_lcdc_dev_pm_ops,
915         },
916         .probe          = sh_mobile_lcdc_probe,
917         .remove         = sh_mobile_lcdc_remove,
918 };
919
920 static int __init sh_mobile_lcdc_init(void)
921 {
922         return platform_driver_register(&sh_mobile_lcdc_driver);
923 }
924
925 static void __exit sh_mobile_lcdc_exit(void)
926 {
927         platform_driver_unregister(&sh_mobile_lcdc_driver);
928 }
929
930 module_init(sh_mobile_lcdc_init);
931 module_exit(sh_mobile_lcdc_exit);
932
933 MODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver");
934 MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
935 MODULE_LICENSE("GPL v2");