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