1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163#include <linux/module.h>
164#include <linux/kernel.h>
165#include <linux/sched.h>
166#include <linux/errno.h>
167#include <linux/string.h>
168#include <linux/interrupt.h>
169#include <linux/slab.h>
170#include <linux/mm.h>
171#include <linux/fb.h>
172#include <linux/delay.h>
173#include <linux/init.h>
174#include <linux/ioport.h>
175#include <linux/cpufreq.h>
176#include <linux/gpio.h>
177#include <linux/platform_device.h>
178#include <linux/dma-mapping.h>
179#include <linux/mutex.h>
180#include <linux/io.h>
181#include <linux/clk.h>
182
183#include <video/sa1100fb.h>
184
185#include <mach/hardware.h>
186#include <asm/mach-types.h>
187#include <mach/shannon.h>
188
189
190
191
192#define DEBUG_VAR 1
193
194#include "sa1100fb.h"
195
196static const struct sa1100fb_rgb rgb_4 = {
197 .red = { .offset = 0, .length = 4, },
198 .green = { .offset = 0, .length = 4, },
199 .blue = { .offset = 0, .length = 4, },
200 .transp = { .offset = 0, .length = 0, },
201};
202
203static const struct sa1100fb_rgb rgb_8 = {
204 .red = { .offset = 0, .length = 8, },
205 .green = { .offset = 0, .length = 8, },
206 .blue = { .offset = 0, .length = 8, },
207 .transp = { .offset = 0, .length = 0, },
208};
209
210static const struct sa1100fb_rgb def_rgb_16 = {
211 .red = { .offset = 11, .length = 5, },
212 .green = { .offset = 5, .length = 6, },
213 .blue = { .offset = 0, .length = 5, },
214 .transp = { .offset = 0, .length = 0, },
215};
216
217
218
219static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);
220static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);
221
222static inline void sa1100fb_schedule_work(struct sa1100fb_info *fbi, u_int state)
223{
224 unsigned long flags;
225
226 local_irq_save(flags);
227
228
229
230
231
232
233
234
235 if (fbi->task_state == C_ENABLE && state == C_REENABLE)
236 state = (u_int) -1;
237 if (fbi->task_state == C_DISABLE && state == C_ENABLE)
238 state = C_REENABLE;
239
240 if (state != (u_int)-1) {
241 fbi->task_state = state;
242 schedule_work(&fbi->task);
243 }
244 local_irq_restore(flags);
245}
246
247static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
248{
249 chan &= 0xffff;
250 chan >>= 16 - bf->length;
251 return chan << bf->offset;
252}
253
254
255
256
257static inline u_int palette_pbs(struct fb_var_screeninfo *var)
258{
259 int ret = 0;
260 switch (var->bits_per_pixel) {
261 case 4: ret = 0 << 12; break;
262 case 8: ret = 1 << 12; break;
263 case 16: ret = 2 << 12; break;
264 }
265 return ret;
266}
267
268static int
269sa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
270 u_int trans, struct fb_info *info)
271{
272 struct sa1100fb_info *fbi =
273 container_of(info, struct sa1100fb_info, fb);
274 u_int val, ret = 1;
275
276 if (regno < fbi->palette_size) {
277 val = ((red >> 4) & 0xf00);
278 val |= ((green >> 8) & 0x0f0);
279 val |= ((blue >> 12) & 0x00f);
280
281 if (regno == 0)
282 val |= palette_pbs(&fbi->fb.var);
283
284 fbi->palette_cpu[regno] = val;
285 ret = 0;
286 }
287 return ret;
288}
289
290static int
291sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
292 u_int trans, struct fb_info *info)
293{
294 struct sa1100fb_info *fbi =
295 container_of(info, struct sa1100fb_info, fb);
296 unsigned int val;
297 int ret = 1;
298
299
300
301
302
303
304
305 if (fbi->inf->cmap_inverse) {
306 red = 0xffff - red;
307 green = 0xffff - green;
308 blue = 0xffff - blue;
309 }
310
311
312
313
314
315 if (fbi->fb.var.grayscale)
316 red = green = blue = (19595 * red + 38470 * green +
317 7471 * blue) >> 16;
318
319 switch (fbi->fb.fix.visual) {
320 case FB_VISUAL_TRUECOLOR:
321
322
323
324
325 if (regno < 16) {
326 val = chan_to_field(red, &fbi->fb.var.red);
327 val |= chan_to_field(green, &fbi->fb.var.green);
328 val |= chan_to_field(blue, &fbi->fb.var.blue);
329
330 fbi->pseudo_palette[regno] = val;
331 ret = 0;
332 }
333 break;
334
335 case FB_VISUAL_STATIC_PSEUDOCOLOR:
336 case FB_VISUAL_PSEUDOCOLOR:
337 ret = sa1100fb_setpalettereg(regno, red, green, blue, trans, info);
338 break;
339 }
340
341 return ret;
342}
343
344#ifdef CONFIG_CPU_FREQ
345
346
347
348
349
350
351static inline unsigned int sa1100fb_display_dma_period(struct fb_var_screeninfo *var)
352{
353
354
355
356
357 return var->pixclock * 8 * 16 / var->bits_per_pixel;
358}
359#endif
360
361
362
363
364
365
366
367static int
368sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
369{
370 struct sa1100fb_info *fbi =
371 container_of(info, struct sa1100fb_info, fb);
372 int rgbidx;
373
374 if (var->xres < MIN_XRES)
375 var->xres = MIN_XRES;
376 if (var->yres < MIN_YRES)
377 var->yres = MIN_YRES;
378 if (var->xres > fbi->inf->xres)
379 var->xres = fbi->inf->xres;
380 if (var->yres > fbi->inf->yres)
381 var->yres = fbi->inf->yres;
382 var->xres_virtual = max(var->xres_virtual, var->xres);
383 var->yres_virtual = max(var->yres_virtual, var->yres);
384
385 dev_dbg(fbi->dev, "var->bits_per_pixel=%d\n", var->bits_per_pixel);
386 switch (var->bits_per_pixel) {
387 case 4:
388 rgbidx = RGB_4;
389 break;
390 case 8:
391 rgbidx = RGB_8;
392 break;
393 case 16:
394 rgbidx = RGB_16;
395 break;
396 default:
397 return -EINVAL;
398 }
399
400
401
402
403
404 var->red = fbi->rgb[rgbidx]->red;
405 var->green = fbi->rgb[rgbidx]->green;
406 var->blue = fbi->rgb[rgbidx]->blue;
407 var->transp = fbi->rgb[rgbidx]->transp;
408
409 dev_dbg(fbi->dev, "RGBT length = %d:%d:%d:%d\n",
410 var->red.length, var->green.length, var->blue.length,
411 var->transp.length);
412
413 dev_dbg(fbi->dev, "RGBT offset = %d:%d:%d:%d\n",
414 var->red.offset, var->green.offset, var->blue.offset,
415 var->transp.offset);
416
417#ifdef CONFIG_CPU_FREQ
418 dev_dbg(fbi->dev, "dma period = %d ps, clock = %ld kHz\n",
419 sa1100fb_display_dma_period(var),
420 clk_get_rate(fbi->clk) / 1000);
421#endif
422
423 return 0;
424}
425
426static void sa1100fb_set_visual(struct sa1100fb_info *fbi, u32 visual)
427{
428 if (fbi->inf->set_visual)
429 fbi->inf->set_visual(visual);
430}
431
432
433
434
435
436static int sa1100fb_set_par(struct fb_info *info)
437{
438 struct sa1100fb_info *fbi =
439 container_of(info, struct sa1100fb_info, fb);
440 struct fb_var_screeninfo *var = &info->var;
441 unsigned long palette_mem_size;
442
443 dev_dbg(fbi->dev, "set_par\n");
444
445 if (var->bits_per_pixel == 16)
446 fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
447 else if (!fbi->inf->cmap_static)
448 fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
449 else {
450
451
452
453
454
455 fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
456 }
457
458 fbi->fb.fix.line_length = var->xres_virtual *
459 var->bits_per_pixel / 8;
460 fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
461
462 palette_mem_size = fbi->palette_size * sizeof(u16);
463
464 dev_dbg(fbi->dev, "palette_mem_size = 0x%08lx\n", palette_mem_size);
465
466 fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
467 fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
468
469
470
471
472 sa1100fb_set_visual(fbi, fbi->fb.fix.visual);
473 sa1100fb_activate_var(var, fbi);
474
475 return 0;
476}
477
478#if 0
479static int
480sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
481 struct fb_info *info)
482{
483 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
484
485
486
487
488 if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->inf->cmap_static))
489 return -EINVAL;
490
491 return gen_set_cmap(cmap, kspc, con, info);
492}
493#endif
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530static int sa1100fb_blank(int blank, struct fb_info *info)
531{
532 struct sa1100fb_info *fbi =
533 container_of(info, struct sa1100fb_info, fb);
534 int i;
535
536 dev_dbg(fbi->dev, "sa1100fb_blank: blank=%d\n", blank);
537
538 switch (blank) {
539 case FB_BLANK_POWERDOWN:
540 case FB_BLANK_VSYNC_SUSPEND:
541 case FB_BLANK_HSYNC_SUSPEND:
542 case FB_BLANK_NORMAL:
543 if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
544 fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
545 for (i = 0; i < fbi->palette_size; i++)
546 sa1100fb_setpalettereg(i, 0, 0, 0, 0, info);
547 sa1100fb_schedule_work(fbi, C_DISABLE);
548 break;
549
550 case FB_BLANK_UNBLANK:
551 if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
552 fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
553 fb_set_cmap(&fbi->fb.cmap, info);
554 sa1100fb_schedule_work(fbi, C_ENABLE);
555 }
556 return 0;
557}
558
559static int sa1100fb_mmap(struct fb_info *info,
560 struct vm_area_struct *vma)
561{
562 struct sa1100fb_info *fbi =
563 container_of(info, struct sa1100fb_info, fb);
564 unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
565
566 if (off < info->fix.smem_len) {
567 vma->vm_pgoff += 1;
568 return dma_mmap_wc(fbi->dev, vma, fbi->map_cpu, fbi->map_dma,
569 fbi->map_size);
570 }
571
572 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
573
574 return vm_iomap_memory(vma, info->fix.mmio_start, info->fix.mmio_len);
575}
576
577static struct fb_ops sa1100fb_ops = {
578 .owner = THIS_MODULE,
579 .fb_check_var = sa1100fb_check_var,
580 .fb_set_par = sa1100fb_set_par,
581
582 .fb_setcolreg = sa1100fb_setcolreg,
583 .fb_fillrect = cfb_fillrect,
584 .fb_copyarea = cfb_copyarea,
585 .fb_imageblit = cfb_imageblit,
586 .fb_blank = sa1100fb_blank,
587 .fb_mmap = sa1100fb_mmap,
588};
589
590
591
592
593
594static inline unsigned int get_pcd(struct sa1100fb_info *fbi,
595 unsigned int pixclock)
596{
597 unsigned int pcd = clk_get_rate(fbi->clk) / 100 / 1000;
598
599 pcd *= pixclock;
600 pcd /= 10000000;
601
602 return pcd + 1;
603}
604
605
606
607
608
609
610static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
611{
612 struct sa1100fb_lcd_reg new_regs;
613 u_int half_screen_size, yres, pcd;
614 u_long flags;
615
616 dev_dbg(fbi->dev, "Configuring SA1100 LCD\n");
617
618 dev_dbg(fbi->dev, "var: xres=%d hslen=%d lm=%d rm=%d\n",
619 var->xres, var->hsync_len,
620 var->left_margin, var->right_margin);
621 dev_dbg(fbi->dev, "var: yres=%d vslen=%d um=%d bm=%d\n",
622 var->yres, var->vsync_len,
623 var->upper_margin, var->lower_margin);
624
625#if DEBUG_VAR
626 if (var->xres < 16 || var->xres > 1024)
627 dev_err(fbi->dev, "%s: invalid xres %d\n",
628 fbi->fb.fix.id, var->xres);
629 if (var->hsync_len < 1 || var->hsync_len > 64)
630 dev_err(fbi->dev, "%s: invalid hsync_len %d\n",
631 fbi->fb.fix.id, var->hsync_len);
632 if (var->left_margin < 1 || var->left_margin > 255)
633 dev_err(fbi->dev, "%s: invalid left_margin %d\n",
634 fbi->fb.fix.id, var->left_margin);
635 if (var->right_margin < 1 || var->right_margin > 255)
636 dev_err(fbi->dev, "%s: invalid right_margin %d\n",
637 fbi->fb.fix.id, var->right_margin);
638 if (var->yres < 1 || var->yres > 1024)
639 dev_err(fbi->dev, "%s: invalid yres %d\n",
640 fbi->fb.fix.id, var->yres);
641 if (var->vsync_len < 1 || var->vsync_len > 64)
642 dev_err(fbi->dev, "%s: invalid vsync_len %d\n",
643 fbi->fb.fix.id, var->vsync_len);
644 if (var->upper_margin < 0 || var->upper_margin > 255)
645 dev_err(fbi->dev, "%s: invalid upper_margin %d\n",
646 fbi->fb.fix.id, var->upper_margin);
647 if (var->lower_margin < 0 || var->lower_margin > 255)
648 dev_err(fbi->dev, "%s: invalid lower_margin %d\n",
649 fbi->fb.fix.id, var->lower_margin);
650#endif
651
652 new_regs.lccr0 = fbi->inf->lccr0 |
653 LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
654 LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
655
656 new_regs.lccr1 =
657 LCCR1_DisWdth(var->xres) +
658 LCCR1_HorSnchWdth(var->hsync_len) +
659 LCCR1_BegLnDel(var->left_margin) +
660 LCCR1_EndLnDel(var->right_margin);
661
662
663
664
665
666 yres = var->yres;
667 if (fbi->inf->lccr0 & LCCR0_Dual)
668 yres /= 2;
669
670 new_regs.lccr2 =
671 LCCR2_DisHght(yres) +
672 LCCR2_VrtSnchWdth(var->vsync_len) +
673 LCCR2_BegFrmDel(var->upper_margin) +
674 LCCR2_EndFrmDel(var->lower_margin);
675
676 pcd = get_pcd(fbi, var->pixclock);
677 new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->inf->lccr3 |
678 (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
679 (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
680
681 dev_dbg(fbi->dev, "nlccr0 = 0x%08lx\n", new_regs.lccr0);
682 dev_dbg(fbi->dev, "nlccr1 = 0x%08lx\n", new_regs.lccr1);
683 dev_dbg(fbi->dev, "nlccr2 = 0x%08lx\n", new_regs.lccr2);
684 dev_dbg(fbi->dev, "nlccr3 = 0x%08lx\n", new_regs.lccr3);
685
686 half_screen_size = var->bits_per_pixel;
687 half_screen_size = half_screen_size * var->xres * var->yres / 16;
688
689
690 local_irq_save(flags);
691 fbi->dbar1 = fbi->palette_dma;
692 fbi->dbar2 = fbi->screen_dma + half_screen_size;
693
694 fbi->reg_lccr0 = new_regs.lccr0;
695 fbi->reg_lccr1 = new_regs.lccr1;
696 fbi->reg_lccr2 = new_regs.lccr2;
697 fbi->reg_lccr3 = new_regs.lccr3;
698 local_irq_restore(flags);
699
700
701
702
703
704 if (readl_relaxed(fbi->base + LCCR0) != fbi->reg_lccr0 ||
705 readl_relaxed(fbi->base + LCCR1) != fbi->reg_lccr1 ||
706 readl_relaxed(fbi->base + LCCR2) != fbi->reg_lccr2 ||
707 readl_relaxed(fbi->base + LCCR3) != fbi->reg_lccr3 ||
708 readl_relaxed(fbi->base + DBAR1) != fbi->dbar1 ||
709 readl_relaxed(fbi->base + DBAR2) != fbi->dbar2)
710 sa1100fb_schedule_work(fbi, C_REENABLE);
711
712 return 0;
713}
714
715
716
717
718
719
720
721static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on)
722{
723 dev_dbg(fbi->dev, "backlight o%s\n", on ? "n" : "ff");
724
725 if (fbi->inf->backlight_power)
726 fbi->inf->backlight_power(on);
727}
728
729static inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on)
730{
731 dev_dbg(fbi->dev, "LCD power o%s\n", on ? "n" : "ff");
732
733 if (fbi->inf->lcd_power)
734 fbi->inf->lcd_power(on);
735}
736
737static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
738{
739 u_int mask = 0;
740
741
742
743
744
745
746
747
748
749
750
751
752
753 if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color &&
754 (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) {
755 mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
756
757 if (fbi->fb.var.bits_per_pixel > 8 ||
758 (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual)
759 mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12;
760
761 }
762
763 if (mask) {
764 unsigned long flags;
765
766
767
768
769
770
771
772
773 local_irq_save(flags);
774 GPDR |= mask;
775 GAFR |= mask;
776 local_irq_restore(flags);
777 }
778}
779
780static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
781{
782 dev_dbg(fbi->dev, "Enabling LCD controller\n");
783
784
785
786
787 fbi->palette_cpu[0] &= 0xcfff;
788 fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
789
790
791 clk_prepare_enable(fbi->clk);
792
793
794 writel_relaxed(fbi->reg_lccr3, fbi->base + LCCR3);
795 writel_relaxed(fbi->reg_lccr2, fbi->base + LCCR2);
796 writel_relaxed(fbi->reg_lccr1, fbi->base + LCCR1);
797 writel_relaxed(fbi->reg_lccr0 & ~LCCR0_LEN, fbi->base + LCCR0);
798 writel_relaxed(fbi->dbar1, fbi->base + DBAR1);
799 writel_relaxed(fbi->dbar2, fbi->base + DBAR2);
800 writel_relaxed(fbi->reg_lccr0 | LCCR0_LEN, fbi->base + LCCR0);
801
802 if (machine_is_shannon())
803 gpio_set_value(SHANNON_GPIO_DISP_EN, 1);
804
805 dev_dbg(fbi->dev, "DBAR1: 0x%08x\n", readl_relaxed(fbi->base + DBAR1));
806 dev_dbg(fbi->dev, "DBAR2: 0x%08x\n", readl_relaxed(fbi->base + DBAR2));
807 dev_dbg(fbi->dev, "LCCR0: 0x%08x\n", readl_relaxed(fbi->base + LCCR0));
808 dev_dbg(fbi->dev, "LCCR1: 0x%08x\n", readl_relaxed(fbi->base + LCCR1));
809 dev_dbg(fbi->dev, "LCCR2: 0x%08x\n", readl_relaxed(fbi->base + LCCR2));
810 dev_dbg(fbi->dev, "LCCR3: 0x%08x\n", readl_relaxed(fbi->base + LCCR3));
811}
812
813static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
814{
815 DECLARE_WAITQUEUE(wait, current);
816 u32 lccr0;
817
818 dev_dbg(fbi->dev, "Disabling LCD controller\n");
819
820 if (machine_is_shannon())
821 gpio_set_value(SHANNON_GPIO_DISP_EN, 0);
822
823 set_current_state(TASK_UNINTERRUPTIBLE);
824 add_wait_queue(&fbi->ctrlr_wait, &wait);
825
826
827 writel_relaxed(~0, fbi->base + LCSR);
828
829 lccr0 = readl_relaxed(fbi->base + LCCR0);
830 lccr0 &= ~LCCR0_LDM;
831 writel_relaxed(lccr0, fbi->base + LCCR0);
832 lccr0 &= ~LCCR0_LEN;
833 writel_relaxed(lccr0, fbi->base + LCCR0);
834
835 schedule_timeout(20 * HZ / 1000);
836 remove_wait_queue(&fbi->ctrlr_wait, &wait);
837
838
839 clk_disable_unprepare(fbi->clk);
840}
841
842
843
844
845static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id)
846{
847 struct sa1100fb_info *fbi = dev_id;
848 unsigned int lcsr = readl_relaxed(fbi->base + LCSR);
849
850 if (lcsr & LCSR_LDD) {
851 u32 lccr0 = readl_relaxed(fbi->base + LCCR0) | LCCR0_LDM;
852 writel_relaxed(lccr0, fbi->base + LCCR0);
853 wake_up(&fbi->ctrlr_wait);
854 }
855
856 writel_relaxed(lcsr, fbi->base + LCSR);
857 return IRQ_HANDLED;
858}
859
860
861
862
863
864
865static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
866{
867 u_int old_state;
868
869 mutex_lock(&fbi->ctrlr_lock);
870
871 old_state = fbi->state;
872
873
874
875
876 if (old_state == C_STARTUP && state == C_REENABLE)
877 state = C_ENABLE;
878
879 switch (state) {
880 case C_DISABLE_CLKCHANGE:
881
882
883
884
885 if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
886 fbi->state = state;
887 sa1100fb_disable_controller(fbi);
888 }
889 break;
890
891 case C_DISABLE_PM:
892 case C_DISABLE:
893
894
895
896 if (old_state != C_DISABLE) {
897 fbi->state = state;
898
899 __sa1100fb_backlight_power(fbi, 0);
900 if (old_state != C_DISABLE_CLKCHANGE)
901 sa1100fb_disable_controller(fbi);
902 __sa1100fb_lcd_power(fbi, 0);
903 }
904 break;
905
906 case C_ENABLE_CLKCHANGE:
907
908
909
910
911 if (old_state == C_DISABLE_CLKCHANGE) {
912 fbi->state = C_ENABLE;
913 sa1100fb_enable_controller(fbi);
914 }
915 break;
916
917 case C_REENABLE:
918
919
920
921
922
923 if (old_state == C_ENABLE) {
924 sa1100fb_disable_controller(fbi);
925 sa1100fb_setup_gpio(fbi);
926 sa1100fb_enable_controller(fbi);
927 }
928 break;
929
930 case C_ENABLE_PM:
931
932
933
934
935
936 if (old_state != C_DISABLE_PM)
937 break;
938
939
940 case C_ENABLE:
941
942
943
944
945 if (old_state != C_ENABLE) {
946 fbi->state = C_ENABLE;
947 sa1100fb_setup_gpio(fbi);
948 __sa1100fb_lcd_power(fbi, 1);
949 sa1100fb_enable_controller(fbi);
950 __sa1100fb_backlight_power(fbi, 1);
951 }
952 break;
953 }
954 mutex_unlock(&fbi->ctrlr_lock);
955}
956
957
958
959
960
961static void sa1100fb_task(struct work_struct *w)
962{
963 struct sa1100fb_info *fbi = container_of(w, struct sa1100fb_info, task);
964 u_int state = xchg(&fbi->task_state, -1);
965
966 set_ctrlr_state(fbi, state);
967}
968
969#ifdef CONFIG_CPU_FREQ
970
971
972
973
974
975static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
976{
977
978
979
980 return sa1100fb_display_dma_period(&fbi->fb.var);
981}
982
983
984
985
986
987
988static int
989sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,
990 void *data)
991{
992 struct sa1100fb_info *fbi = TO_INF(nb, freq_transition);
993 u_int pcd;
994
995 switch (val) {
996 case CPUFREQ_PRECHANGE:
997 set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
998 break;
999
1000 case CPUFREQ_POSTCHANGE:
1001 pcd = get_pcd(fbi, fbi->fb.var.pixclock);
1002 fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
1003 set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
1004 break;
1005 }
1006 return 0;
1007}
1008#endif
1009
1010#ifdef CONFIG_PM
1011
1012
1013
1014
1015static int sa1100fb_suspend(struct platform_device *dev, pm_message_t state)
1016{
1017 struct sa1100fb_info *fbi = platform_get_drvdata(dev);
1018
1019 set_ctrlr_state(fbi, C_DISABLE_PM);
1020 return 0;
1021}
1022
1023static int sa1100fb_resume(struct platform_device *dev)
1024{
1025 struct sa1100fb_info *fbi = platform_get_drvdata(dev);
1026
1027 set_ctrlr_state(fbi, C_ENABLE_PM);
1028 return 0;
1029}
1030#else
1031#define sa1100fb_suspend NULL
1032#define sa1100fb_resume NULL
1033#endif
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043static int sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
1044{
1045
1046
1047
1048
1049 fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
1050 fbi->map_cpu = dma_alloc_wc(fbi->dev, fbi->map_size, &fbi->map_dma,
1051 GFP_KERNEL);
1052
1053 if (fbi->map_cpu) {
1054 fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
1055 fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
1056
1057
1058
1059
1060
1061
1062 fbi->fb.fix.smem_start = fbi->screen_dma;
1063 }
1064
1065 return fbi->map_cpu ? 0 : -ENOMEM;
1066}
1067
1068
1069static struct fb_monspecs monspecs = {
1070 .hfmin = 30000,
1071 .hfmax = 70000,
1072 .vfmin = 50,
1073 .vfmax = 65,
1074};
1075
1076
1077static struct sa1100fb_info *sa1100fb_init_fbinfo(struct device *dev)
1078{
1079 struct sa1100fb_mach_info *inf = dev_get_platdata(dev);
1080 struct sa1100fb_info *fbi;
1081 unsigned i;
1082
1083 fbi = devm_kzalloc(dev, sizeof(struct sa1100fb_info), GFP_KERNEL);
1084 if (!fbi)
1085 return NULL;
1086
1087 fbi->dev = dev;
1088
1089 strcpy(fbi->fb.fix.id, SA1100_NAME);
1090
1091 fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
1092 fbi->fb.fix.type_aux = 0;
1093 fbi->fb.fix.xpanstep = 0;
1094 fbi->fb.fix.ypanstep = 0;
1095 fbi->fb.fix.ywrapstep = 0;
1096 fbi->fb.fix.accel = FB_ACCEL_NONE;
1097
1098 fbi->fb.var.nonstd = 0;
1099 fbi->fb.var.activate = FB_ACTIVATE_NOW;
1100 fbi->fb.var.height = -1;
1101 fbi->fb.var.width = -1;
1102 fbi->fb.var.accel_flags = 0;
1103 fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
1104
1105 fbi->fb.fbops = &sa1100fb_ops;
1106 fbi->fb.flags = FBINFO_DEFAULT;
1107 fbi->fb.monspecs = monspecs;
1108 fbi->fb.pseudo_palette = fbi->pseudo_palette;
1109
1110 fbi->rgb[RGB_4] = &rgb_4;
1111 fbi->rgb[RGB_8] = &rgb_8;
1112 fbi->rgb[RGB_16] = &def_rgb_16;
1113
1114
1115
1116
1117
1118
1119 if (inf->lccr3 & (LCCR3_VrtSnchL|LCCR3_HorSnchL|0xff) ||
1120 inf->pixclock == 0)
1121 panic("sa1100fb error: invalid LCCR3 fields set or zero "
1122 "pixclock.");
1123
1124 fbi->fb.var.xres = inf->xres;
1125 fbi->fb.var.xres_virtual = inf->xres;
1126 fbi->fb.var.yres = inf->yres;
1127 fbi->fb.var.yres_virtual = inf->yres;
1128 fbi->fb.var.bits_per_pixel = inf->bpp;
1129 fbi->fb.var.pixclock = inf->pixclock;
1130 fbi->fb.var.hsync_len = inf->hsync_len;
1131 fbi->fb.var.left_margin = inf->left_margin;
1132 fbi->fb.var.right_margin = inf->right_margin;
1133 fbi->fb.var.vsync_len = inf->vsync_len;
1134 fbi->fb.var.upper_margin = inf->upper_margin;
1135 fbi->fb.var.lower_margin = inf->lower_margin;
1136 fbi->fb.var.sync = inf->sync;
1137 fbi->fb.var.grayscale = inf->cmap_greyscale;
1138 fbi->state = C_STARTUP;
1139 fbi->task_state = (u_char)-1;
1140 fbi->fb.fix.smem_len = inf->xres * inf->yres *
1141 inf->bpp / 8;
1142 fbi->inf = inf;
1143
1144
1145 for (i = 0; i < NR_RGB; i++)
1146 if (inf->rgb[i])
1147 fbi->rgb[i] = inf->rgb[i];
1148
1149 init_waitqueue_head(&fbi->ctrlr_wait);
1150 INIT_WORK(&fbi->task, sa1100fb_task);
1151 mutex_init(&fbi->ctrlr_lock);
1152
1153 return fbi;
1154}
1155
1156static int sa1100fb_probe(struct platform_device *pdev)
1157{
1158 struct sa1100fb_info *fbi;
1159 struct resource *res;
1160 int ret, irq;
1161
1162 if (!dev_get_platdata(&pdev->dev)) {
1163 dev_err(&pdev->dev, "no platform LCD data\n");
1164 return -EINVAL;
1165 }
1166
1167 irq = platform_get_irq(pdev, 0);
1168 if (irq < 0)
1169 return -EINVAL;
1170
1171 fbi = sa1100fb_init_fbinfo(&pdev->dev);
1172 if (!fbi)
1173 return -ENOMEM;
1174
1175 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1176 fbi->base = devm_ioremap_resource(&pdev->dev, res);
1177 if (IS_ERR(fbi->base))
1178 return PTR_ERR(fbi->base);
1179
1180 fbi->clk = devm_clk_get(&pdev->dev, NULL);
1181 if (IS_ERR(fbi->clk))
1182 return PTR_ERR(fbi->clk);
1183
1184 ret = devm_request_irq(&pdev->dev, irq, sa1100fb_handle_irq, 0,
1185 "LCD", fbi);
1186 if (ret) {
1187 dev_err(&pdev->dev, "request_irq failed: %d\n", ret);
1188 return ret;
1189 }
1190
1191 if (machine_is_shannon()) {
1192 ret = devm_gpio_request_one(&pdev->dev, SHANNON_GPIO_DISP_EN,
1193 GPIOF_OUT_INIT_LOW, "display enable");
1194 if (ret)
1195 return ret;
1196 }
1197
1198
1199 ret = sa1100fb_map_video_memory(fbi);
1200 if (ret)
1201 return ret;
1202
1203
1204
1205
1206
1207 sa1100fb_check_var(&fbi->fb.var, &fbi->fb);
1208
1209 platform_set_drvdata(pdev, fbi);
1210
1211 ret = register_framebuffer(&fbi->fb);
1212 if (ret < 0) {
1213 dma_free_wc(fbi->dev, fbi->map_size, fbi->map_cpu,
1214 fbi->map_dma);
1215 return ret;
1216 }
1217
1218#ifdef CONFIG_CPU_FREQ
1219 fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
1220 cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
1221#endif
1222
1223
1224 return 0;
1225}
1226
1227static struct platform_driver sa1100fb_driver = {
1228 .probe = sa1100fb_probe,
1229 .suspend = sa1100fb_suspend,
1230 .resume = sa1100fb_resume,
1231 .driver = {
1232 .name = "sa11x0-fb",
1233 },
1234};
1235
1236int __init sa1100fb_init(void)
1237{
1238 if (fb_get_options("sa1100fb", NULL))
1239 return -ENODEV;
1240
1241 return platform_driver_register(&sa1100fb_driver);
1242}
1243
1244int __init sa1100fb_setup(char *options)
1245{
1246#if 0
1247 char *this_opt;
1248
1249 if (!options || !*options)
1250 return 0;
1251
1252 while ((this_opt = strsep(&options, ",")) != NULL) {
1253
1254 if (!strncmp(this_opt, "bpp:", 4))
1255 current_par.max_bpp =
1256 simple_strtoul(this_opt + 4, NULL, 0);
1257
1258 if (!strncmp(this_opt, "lccr0:", 6))
1259 lcd_shadow.lccr0 =
1260 simple_strtoul(this_opt + 6, NULL, 0);
1261 if (!strncmp(this_opt, "lccr1:", 6)) {
1262 lcd_shadow.lccr1 =
1263 simple_strtoul(this_opt + 6, NULL, 0);
1264 current_par.max_xres =
1265 (lcd_shadow.lccr1 & 0x3ff) + 16;
1266 }
1267 if (!strncmp(this_opt, "lccr2:", 6)) {
1268 lcd_shadow.lccr2 =
1269 simple_strtoul(this_opt + 6, NULL, 0);
1270 current_par.max_yres =
1271 (lcd_shadow.
1272 lccr0 & LCCR0_SDS) ? ((lcd_shadow.
1273 lccr2 & 0x3ff) +
1274 1) *
1275 2 : ((lcd_shadow.lccr2 & 0x3ff) + 1);
1276 }
1277 if (!strncmp(this_opt, "lccr3:", 6))
1278 lcd_shadow.lccr3 =
1279 simple_strtoul(this_opt + 6, NULL, 0);
1280 }
1281#endif
1282 return 0;
1283}
1284
1285module_init(sa1100fb_init);
1286MODULE_DESCRIPTION("StrongARM-1100/1110 framebuffer driver");
1287MODULE_LICENSE("GPL");
1288