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/platform_device.h>
177#include <linux/dma-mapping.h>
178#include <linux/mutex.h>
179#include <linux/io.h>
180
181#include <mach/hardware.h>
182#include <asm/mach-types.h>
183#include <mach/assabet.h>
184#include <mach/shannon.h>
185
186
187
188
189#define DEBUG 0
190
191
192
193#define DEBUG_VAR 1
194
195#undef ASSABET_PAL_VIDEO
196
197#include "sa1100fb.h"
198
199extern void (*sa1100fb_backlight_power)(int on);
200extern void (*sa1100fb_lcd_power)(int on);
201
202static struct sa1100fb_rgb rgb_4 = {
203 .red = { .offset = 0, .length = 4, },
204 .green = { .offset = 0, .length = 4, },
205 .blue = { .offset = 0, .length = 4, },
206 .transp = { .offset = 0, .length = 0, },
207};
208
209static struct sa1100fb_rgb rgb_8 = {
210 .red = { .offset = 0, .length = 8, },
211 .green = { .offset = 0, .length = 8, },
212 .blue = { .offset = 0, .length = 8, },
213 .transp = { .offset = 0, .length = 0, },
214};
215
216static struct sa1100fb_rgb def_rgb_16 = {
217 .red = { .offset = 11, .length = 5, },
218 .green = { .offset = 5, .length = 6, },
219 .blue = { .offset = 0, .length = 5, },
220 .transp = { .offset = 0, .length = 0, },
221};
222
223#ifdef CONFIG_SA1100_ASSABET
224#ifndef ASSABET_PAL_VIDEO
225
226
227
228
229
230static struct sa1100fb_mach_info lq039q2ds54_info __initdata = {
231 .pixclock = 171521, .bpp = 16,
232 .xres = 320, .yres = 240,
233
234 .hsync_len = 5, .vsync_len = 1,
235 .left_margin = 61, .upper_margin = 3,
236 .right_margin = 9, .lower_margin = 0,
237
238 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
239
240 .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
241 .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
242};
243#else
244static struct sa1100fb_mach_info pal_info __initdata = {
245 .pixclock = 67797, .bpp = 16,
246 .xres = 640, .yres = 512,
247
248 .hsync_len = 64, .vsync_len = 6,
249 .left_margin = 125, .upper_margin = 70,
250 .right_margin = 115, .lower_margin = 36,
251
252 .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
253 .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
254};
255#endif
256#endif
257
258#ifdef CONFIG_SA1100_H3600
259static struct sa1100fb_mach_info h3600_info __initdata = {
260 .pixclock = 174757, .bpp = 16,
261 .xres = 320, .yres = 240,
262
263 .hsync_len = 3, .vsync_len = 3,
264 .left_margin = 12, .upper_margin = 10,
265 .right_margin = 17, .lower_margin = 1,
266
267 .cmap_static = 1,
268
269 .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
270 .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
271};
272
273static struct sa1100fb_rgb h3600_rgb_16 = {
274 .red = { .offset = 12, .length = 4, },
275 .green = { .offset = 7, .length = 4, },
276 .blue = { .offset = 1, .length = 4, },
277 .transp = { .offset = 0, .length = 0, },
278};
279#endif
280
281#ifdef CONFIG_SA1100_H3100
282static struct sa1100fb_mach_info h3100_info __initdata = {
283 .pixclock = 406977, .bpp = 4,
284 .xres = 320, .yres = 240,
285
286 .hsync_len = 26, .vsync_len = 41,
287 .left_margin = 4, .upper_margin = 0,
288 .right_margin = 4, .lower_margin = 0,
289
290 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
291 .cmap_greyscale = 1,
292 .cmap_inverse = 1,
293
294 .lccr0 = LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
295 .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
296};
297#endif
298
299#ifdef CONFIG_SA1100_COLLIE
300static struct sa1100fb_mach_info collie_info __initdata = {
301 .pixclock = 171521, .bpp = 16,
302 .xres = 320, .yres = 240,
303
304 .hsync_len = 5, .vsync_len = 1,
305 .left_margin = 11, .upper_margin = 2,
306 .right_margin = 30, .lower_margin = 0,
307
308 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
309
310 .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
311 .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
312};
313#endif
314
315#ifdef LART_GREY_LCD
316static struct sa1100fb_mach_info lart_grey_info __initdata = {
317 .pixclock = 150000, .bpp = 4,
318 .xres = 320, .yres = 240,
319
320 .hsync_len = 1, .vsync_len = 1,
321 .left_margin = 4, .upper_margin = 0,
322 .right_margin = 2, .lower_margin = 0,
323
324 .cmap_greyscale = 1,
325 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
326
327 .lccr0 = LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
328 .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
329};
330#endif
331#ifdef LART_COLOR_LCD
332static struct sa1100fb_mach_info lart_color_info __initdata = {
333 .pixclock = 150000, .bpp = 16,
334 .xres = 320, .yres = 240,
335
336 .hsync_len = 2, .vsync_len = 3,
337 .left_margin = 69, .upper_margin = 14,
338 .right_margin = 8, .lower_margin = 4,
339
340 .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
341 .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
342};
343#endif
344#ifdef LART_VIDEO_OUT
345static struct sa1100fb_mach_info lart_video_info __initdata = {
346 .pixclock = 39721, .bpp = 16,
347 .xres = 640, .yres = 480,
348
349 .hsync_len = 95, .vsync_len = 2,
350 .left_margin = 40, .upper_margin = 32,
351 .right_margin = 24, .lower_margin = 11,
352
353 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
354
355 .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
356 .lccr3 = LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
357};
358#endif
359
360#ifdef LART_KIT01_LCD
361static struct sa1100fb_mach_info lart_kit01_info __initdata = {
362 .pixclock = 63291, .bpp = 16,
363 .xres = 640, .yres = 480,
364
365 .hsync_len = 64, .vsync_len = 3,
366 .left_margin = 122, .upper_margin = 45,
367 .right_margin = 10, .lower_margin = 10,
368
369 .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
370 .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg
371};
372#endif
373
374#ifdef CONFIG_SA1100_SHANNON
375static struct sa1100fb_mach_info shannon_info __initdata = {
376 .pixclock = 152500, .bpp = 8,
377 .xres = 640, .yres = 480,
378
379 .hsync_len = 4, .vsync_len = 3,
380 .left_margin = 2, .upper_margin = 0,
381 .right_margin = 1, .lower_margin = 0,
382
383 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
384
385 .lccr0 = LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
386 .lccr3 = LCCR3_ACBsDiv(512),
387};
388#endif
389
390
391
392static struct sa1100fb_mach_info * __init
393sa1100fb_get_machine_info(struct sa1100fb_info *fbi)
394{
395 struct sa1100fb_mach_info *inf = NULL;
396
397
398
399
400
401
402
403#ifdef CONFIG_SA1100_ASSABET
404 if (machine_is_assabet()) {
405#ifndef ASSABET_PAL_VIDEO
406 inf = &lq039q2ds54_info;
407#else
408 inf = &pal_info;
409#endif
410 }
411#endif
412#ifdef CONFIG_SA1100_H3100
413 if (machine_is_h3100()) {
414 inf = &h3100_info;
415 }
416#endif
417#ifdef CONFIG_SA1100_H3600
418 if (machine_is_h3600()) {
419 inf = &h3600_info;
420 fbi->rgb[RGB_16] = &h3600_rgb_16;
421 }
422#endif
423#ifdef CONFIG_SA1100_COLLIE
424 if (machine_is_collie()) {
425 inf = &collie_info;
426 }
427#endif
428#ifdef CONFIG_SA1100_LART
429 if (machine_is_lart()) {
430#ifdef LART_GREY_LCD
431 inf = &lart_grey_info;
432#endif
433#ifdef LART_COLOR_LCD
434 inf = &lart_color_info;
435#endif
436#ifdef LART_VIDEO_OUT
437 inf = &lart_video_info;
438#endif
439#ifdef LART_KIT01_LCD
440 inf = &lart_kit01_info;
441#endif
442 }
443#endif
444#ifdef CONFIG_SA1100_SHANNON
445 if (machine_is_shannon()) {
446 inf = &shannon_info;
447 }
448#endif
449 return inf;
450}
451
452static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);
453static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);
454
455static inline void sa1100fb_schedule_work(struct sa1100fb_info *fbi, u_int state)
456{
457 unsigned long flags;
458
459 local_irq_save(flags);
460
461
462
463
464
465
466
467
468 if (fbi->task_state == C_ENABLE && state == C_REENABLE)
469 state = (u_int) -1;
470 if (fbi->task_state == C_DISABLE && state == C_ENABLE)
471 state = C_REENABLE;
472
473 if (state != (u_int)-1) {
474 fbi->task_state = state;
475 schedule_work(&fbi->task);
476 }
477 local_irq_restore(flags);
478}
479
480static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
481{
482 chan &= 0xffff;
483 chan >>= 16 - bf->length;
484 return chan << bf->offset;
485}
486
487
488
489
490static inline u_int palette_pbs(struct fb_var_screeninfo *var)
491{
492 int ret = 0;
493 switch (var->bits_per_pixel) {
494 case 4: ret = 0 << 12; break;
495 case 8: ret = 1 << 12; break;
496 case 16: ret = 2 << 12; break;
497 }
498 return ret;
499}
500
501static int
502sa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
503 u_int trans, struct fb_info *info)
504{
505 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
506 u_int val, ret = 1;
507
508 if (regno < fbi->palette_size) {
509 val = ((red >> 4) & 0xf00);
510 val |= ((green >> 8) & 0x0f0);
511 val |= ((blue >> 12) & 0x00f);
512
513 if (regno == 0)
514 val |= palette_pbs(&fbi->fb.var);
515
516 fbi->palette_cpu[regno] = val;
517 ret = 0;
518 }
519 return ret;
520}
521
522static int
523sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
524 u_int trans, struct fb_info *info)
525{
526 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
527 unsigned int val;
528 int ret = 1;
529
530
531
532
533
534
535
536 if (fbi->cmap_inverse) {
537 red = 0xffff - red;
538 green = 0xffff - green;
539 blue = 0xffff - blue;
540 }
541
542
543
544
545
546 if (fbi->fb.var.grayscale)
547 red = green = blue = (19595 * red + 38470 * green +
548 7471 * blue) >> 16;
549
550 switch (fbi->fb.fix.visual) {
551 case FB_VISUAL_TRUECOLOR:
552
553
554
555
556 if (regno < 16) {
557 u32 *pal = fbi->fb.pseudo_palette;
558
559 val = chan_to_field(red, &fbi->fb.var.red);
560 val |= chan_to_field(green, &fbi->fb.var.green);
561 val |= chan_to_field(blue, &fbi->fb.var.blue);
562
563 pal[regno] = val;
564 ret = 0;
565 }
566 break;
567
568 case FB_VISUAL_STATIC_PSEUDOCOLOR:
569 case FB_VISUAL_PSEUDOCOLOR:
570 ret = sa1100fb_setpalettereg(regno, red, green, blue, trans, info);
571 break;
572 }
573
574 return ret;
575}
576
577#ifdef CONFIG_CPU_FREQ
578
579
580
581
582
583
584static inline unsigned int sa1100fb_display_dma_period(struct fb_var_screeninfo *var)
585{
586
587
588
589
590 return var->pixclock * 8 * 16 / var->bits_per_pixel;
591}
592#endif
593
594
595
596
597
598
599
600static int
601sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
602{
603 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
604 int rgbidx;
605
606 if (var->xres < MIN_XRES)
607 var->xres = MIN_XRES;
608 if (var->yres < MIN_YRES)
609 var->yres = MIN_YRES;
610 if (var->xres > fbi->max_xres)
611 var->xres = fbi->max_xres;
612 if (var->yres > fbi->max_yres)
613 var->yres = fbi->max_yres;
614 var->xres_virtual = max(var->xres_virtual, var->xres);
615 var->yres_virtual = max(var->yres_virtual, var->yres);
616
617 DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
618 switch (var->bits_per_pixel) {
619 case 4:
620 rgbidx = RGB_4;
621 break;
622 case 8:
623 rgbidx = RGB_8;
624 break;
625 case 16:
626 rgbidx = RGB_16;
627 break;
628 default:
629 return -EINVAL;
630 }
631
632
633
634
635
636 var->red = fbi->rgb[rgbidx]->red;
637 var->green = fbi->rgb[rgbidx]->green;
638 var->blue = fbi->rgb[rgbidx]->blue;
639 var->transp = fbi->rgb[rgbidx]->transp;
640
641 DPRINTK("RGBT length = %d:%d:%d:%d\n",
642 var->red.length, var->green.length, var->blue.length,
643 var->transp.length);
644
645 DPRINTK("RGBT offset = %d:%d:%d:%d\n",
646 var->red.offset, var->green.offset, var->blue.offset,
647 var->transp.offset);
648
649#ifdef CONFIG_CPU_FREQ
650 printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n",
651 sa1100fb_display_dma_period(var),
652 cpufreq_get(smp_processor_id()));
653#endif
654
655 return 0;
656}
657
658static inline void sa1100fb_set_truecolor(u_int is_true_color)
659{
660 if (machine_is_assabet()) {
661#if 1
662 if (is_true_color)
663 ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
664 else
665 ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
666#else
667
668 if (is_true_color)
669 ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
670 else
671 ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
672#endif
673 }
674}
675
676
677
678
679
680static int sa1100fb_set_par(struct fb_info *info)
681{
682 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
683 struct fb_var_screeninfo *var = &info->var;
684 unsigned long palette_mem_size;
685
686 DPRINTK("set_par\n");
687
688 if (var->bits_per_pixel == 16)
689 fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
690 else if (!fbi->cmap_static)
691 fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
692 else {
693
694
695
696
697
698 fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
699 }
700
701 fbi->fb.fix.line_length = var->xres_virtual *
702 var->bits_per_pixel / 8;
703 fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
704
705 palette_mem_size = fbi->palette_size * sizeof(u16);
706
707 DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
708
709 fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
710 fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
711
712
713
714
715 sa1100fb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
716 sa1100fb_activate_var(var, fbi);
717
718 return 0;
719}
720
721#if 0
722static int
723sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
724 struct fb_info *info)
725{
726 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
727
728
729
730
731 if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->cmap_static))
732 return -EINVAL;
733
734 return gen_set_cmap(cmap, kspc, con, info);
735}
736#endif
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773static int sa1100fb_blank(int blank, struct fb_info *info)
774{
775 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
776 int i;
777
778 DPRINTK("sa1100fb_blank: blank=%d\n", blank);
779
780 switch (blank) {
781 case FB_BLANK_POWERDOWN:
782 case FB_BLANK_VSYNC_SUSPEND:
783 case FB_BLANK_HSYNC_SUSPEND:
784 case FB_BLANK_NORMAL:
785 if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
786 fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
787 for (i = 0; i < fbi->palette_size; i++)
788 sa1100fb_setpalettereg(i, 0, 0, 0, 0, info);
789 sa1100fb_schedule_work(fbi, C_DISABLE);
790 break;
791
792 case FB_BLANK_UNBLANK:
793 if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
794 fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
795 fb_set_cmap(&fbi->fb.cmap, info);
796 sa1100fb_schedule_work(fbi, C_ENABLE);
797 }
798 return 0;
799}
800
801static int sa1100fb_mmap(struct fb_info *info,
802 struct vm_area_struct *vma)
803{
804 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
805 unsigned long start, len, off = vma->vm_pgoff << PAGE_SHIFT;
806
807 if (off < info->fix.smem_len) {
808 vma->vm_pgoff += 1;
809 return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu,
810 fbi->map_dma, fbi->map_size);
811 }
812
813 start = info->fix.mmio_start;
814 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
815
816 if ((vma->vm_end - vma->vm_start + off) > len)
817 return -EINVAL;
818
819 off += start & PAGE_MASK;
820 vma->vm_pgoff = off >> PAGE_SHIFT;
821 vma->vm_flags |= VM_IO;
822 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
823 return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
824 vma->vm_end - vma->vm_start,
825 vma->vm_page_prot);
826}
827
828static struct fb_ops sa1100fb_ops = {
829 .owner = THIS_MODULE,
830 .fb_check_var = sa1100fb_check_var,
831 .fb_set_par = sa1100fb_set_par,
832
833 .fb_setcolreg = sa1100fb_setcolreg,
834 .fb_fillrect = cfb_fillrect,
835 .fb_copyarea = cfb_copyarea,
836 .fb_imageblit = cfb_imageblit,
837 .fb_blank = sa1100fb_blank,
838 .fb_mmap = sa1100fb_mmap,
839};
840
841
842
843
844
845static inline unsigned int get_pcd(unsigned int pixclock, unsigned int cpuclock)
846{
847 unsigned int pcd = cpuclock / 100;
848
849 pcd *= pixclock;
850 pcd /= 10000000;
851
852 return pcd + 1;
853}
854
855
856
857
858
859
860static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
861{
862 struct sa1100fb_lcd_reg new_regs;
863 u_int half_screen_size, yres, pcd;
864 u_long flags;
865
866 DPRINTK("Configuring SA1100 LCD\n");
867
868 DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n",
869 var->xres, var->hsync_len,
870 var->left_margin, var->right_margin);
871 DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n",
872 var->yres, var->vsync_len,
873 var->upper_margin, var->lower_margin);
874
875#if DEBUG_VAR
876 if (var->xres < 16 || var->xres > 1024)
877 printk(KERN_ERR "%s: invalid xres %d\n",
878 fbi->fb.fix.id, var->xres);
879 if (var->hsync_len < 1 || var->hsync_len > 64)
880 printk(KERN_ERR "%s: invalid hsync_len %d\n",
881 fbi->fb.fix.id, var->hsync_len);
882 if (var->left_margin < 1 || var->left_margin > 255)
883 printk(KERN_ERR "%s: invalid left_margin %d\n",
884 fbi->fb.fix.id, var->left_margin);
885 if (var->right_margin < 1 || var->right_margin > 255)
886 printk(KERN_ERR "%s: invalid right_margin %d\n",
887 fbi->fb.fix.id, var->right_margin);
888 if (var->yres < 1 || var->yres > 1024)
889 printk(KERN_ERR "%s: invalid yres %d\n",
890 fbi->fb.fix.id, var->yres);
891 if (var->vsync_len < 1 || var->vsync_len > 64)
892 printk(KERN_ERR "%s: invalid vsync_len %d\n",
893 fbi->fb.fix.id, var->vsync_len);
894 if (var->upper_margin < 0 || var->upper_margin > 255)
895 printk(KERN_ERR "%s: invalid upper_margin %d\n",
896 fbi->fb.fix.id, var->upper_margin);
897 if (var->lower_margin < 0 || var->lower_margin > 255)
898 printk(KERN_ERR "%s: invalid lower_margin %d\n",
899 fbi->fb.fix.id, var->lower_margin);
900#endif
901
902 new_regs.lccr0 = fbi->lccr0 |
903 LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
904 LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
905
906 new_regs.lccr1 =
907 LCCR1_DisWdth(var->xres) +
908 LCCR1_HorSnchWdth(var->hsync_len) +
909 LCCR1_BegLnDel(var->left_margin) +
910 LCCR1_EndLnDel(var->right_margin);
911
912
913
914
915
916 yres = var->yres;
917 if (fbi->lccr0 & LCCR0_Dual)
918 yres /= 2;
919
920 new_regs.lccr2 =
921 LCCR2_DisHght(yres) +
922 LCCR2_VrtSnchWdth(var->vsync_len) +
923 LCCR2_BegFrmDel(var->upper_margin) +
924 LCCR2_EndFrmDel(var->lower_margin);
925
926 pcd = get_pcd(var->pixclock, cpufreq_get(0));
927 new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->lccr3 |
928 (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
929 (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
930
931 DPRINTK("nlccr0 = 0x%08lx\n", new_regs.lccr0);
932 DPRINTK("nlccr1 = 0x%08lx\n", new_regs.lccr1);
933 DPRINTK("nlccr2 = 0x%08lx\n", new_regs.lccr2);
934 DPRINTK("nlccr3 = 0x%08lx\n", new_regs.lccr3);
935
936 half_screen_size = var->bits_per_pixel;
937 half_screen_size = half_screen_size * var->xres * var->yres / 16;
938
939
940 local_irq_save(flags);
941 fbi->dbar1 = fbi->palette_dma;
942 fbi->dbar2 = fbi->screen_dma + half_screen_size;
943
944 fbi->reg_lccr0 = new_regs.lccr0;
945 fbi->reg_lccr1 = new_regs.lccr1;
946 fbi->reg_lccr2 = new_regs.lccr2;
947 fbi->reg_lccr3 = new_regs.lccr3;
948 local_irq_restore(flags);
949
950
951
952
953
954 if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) ||
955 (LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) ||
956 (DBAR1 != fbi->dbar1) || (DBAR2 != fbi->dbar2))
957 sa1100fb_schedule_work(fbi, C_REENABLE);
958
959 return 0;
960}
961
962
963
964
965
966
967
968static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on)
969{
970 DPRINTK("backlight o%s\n", on ? "n" : "ff");
971
972 if (sa1100fb_backlight_power)
973 sa1100fb_backlight_power(on);
974}
975
976static inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on)
977{
978 DPRINTK("LCD power o%s\n", on ? "n" : "ff");
979
980 if (sa1100fb_lcd_power)
981 sa1100fb_lcd_power(on);
982}
983
984static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
985{
986 u_int mask = 0;
987
988
989
990
991
992
993
994
995
996
997
998
999
1000 if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color &&
1001 (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) {
1002 mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
1003
1004 if (fbi->fb.var.bits_per_pixel > 8 ||
1005 (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual)
1006 mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12;
1007
1008 }
1009
1010 if (mask) {
1011 GPDR |= mask;
1012 GAFR |= mask;
1013 }
1014}
1015
1016static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
1017{
1018 DPRINTK("Enabling LCD controller\n");
1019
1020
1021
1022
1023 fbi->palette_cpu[0] &= 0xcfff;
1024 fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
1025
1026
1027 LCCR3 = fbi->reg_lccr3;
1028 LCCR2 = fbi->reg_lccr2;
1029 LCCR1 = fbi->reg_lccr1;
1030 LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN;
1031 DBAR1 = fbi->dbar1;
1032 DBAR2 = fbi->dbar2;
1033 LCCR0 |= LCCR0_LEN;
1034
1035 if (machine_is_shannon()) {
1036 GPDR |= SHANNON_GPIO_DISP_EN;
1037 GPSR |= SHANNON_GPIO_DISP_EN;
1038 }
1039
1040 DPRINTK("DBAR1 = 0x%08x\n", DBAR1);
1041 DPRINTK("DBAR2 = 0x%08x\n", DBAR2);
1042 DPRINTK("LCCR0 = 0x%08x\n", LCCR0);
1043 DPRINTK("LCCR1 = 0x%08x\n", LCCR1);
1044 DPRINTK("LCCR2 = 0x%08x\n", LCCR2);
1045 DPRINTK("LCCR3 = 0x%08x\n", LCCR3);
1046}
1047
1048static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
1049{
1050 DECLARE_WAITQUEUE(wait, current);
1051
1052 DPRINTK("Disabling LCD controller\n");
1053
1054 if (machine_is_shannon()) {
1055 GPCR |= SHANNON_GPIO_DISP_EN;
1056 }
1057
1058 set_current_state(TASK_UNINTERRUPTIBLE);
1059 add_wait_queue(&fbi->ctrlr_wait, &wait);
1060
1061 LCSR = 0xffffffff;
1062 LCCR0 &= ~LCCR0_LDM;
1063 LCCR0 &= ~LCCR0_LEN;
1064
1065 schedule_timeout(20 * HZ / 1000);
1066 remove_wait_queue(&fbi->ctrlr_wait, &wait);
1067}
1068
1069
1070
1071
1072static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id)
1073{
1074 struct sa1100fb_info *fbi = dev_id;
1075 unsigned int lcsr = LCSR;
1076
1077 if (lcsr & LCSR_LDD) {
1078 LCCR0 |= LCCR0_LDM;
1079 wake_up(&fbi->ctrlr_wait);
1080 }
1081
1082 LCSR = lcsr;
1083 return IRQ_HANDLED;
1084}
1085
1086
1087
1088
1089
1090
1091static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
1092{
1093 u_int old_state;
1094
1095 mutex_lock(&fbi->ctrlr_lock);
1096
1097 old_state = fbi->state;
1098
1099
1100
1101
1102 if (old_state == C_STARTUP && state == C_REENABLE)
1103 state = C_ENABLE;
1104
1105 switch (state) {
1106 case C_DISABLE_CLKCHANGE:
1107
1108
1109
1110
1111 if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
1112 fbi->state = state;
1113 sa1100fb_disable_controller(fbi);
1114 }
1115 break;
1116
1117 case C_DISABLE_PM:
1118 case C_DISABLE:
1119
1120
1121
1122 if (old_state != C_DISABLE) {
1123 fbi->state = state;
1124
1125 __sa1100fb_backlight_power(fbi, 0);
1126 if (old_state != C_DISABLE_CLKCHANGE)
1127 sa1100fb_disable_controller(fbi);
1128 __sa1100fb_lcd_power(fbi, 0);
1129 }
1130 break;
1131
1132 case C_ENABLE_CLKCHANGE:
1133
1134
1135
1136
1137 if (old_state == C_DISABLE_CLKCHANGE) {
1138 fbi->state = C_ENABLE;
1139 sa1100fb_enable_controller(fbi);
1140 }
1141 break;
1142
1143 case C_REENABLE:
1144
1145
1146
1147
1148
1149 if (old_state == C_ENABLE) {
1150 sa1100fb_disable_controller(fbi);
1151 sa1100fb_setup_gpio(fbi);
1152 sa1100fb_enable_controller(fbi);
1153 }
1154 break;
1155
1156 case C_ENABLE_PM:
1157
1158
1159
1160
1161
1162 if (old_state != C_DISABLE_PM)
1163 break;
1164
1165
1166 case C_ENABLE:
1167
1168
1169
1170
1171 if (old_state != C_ENABLE) {
1172 fbi->state = C_ENABLE;
1173 sa1100fb_setup_gpio(fbi);
1174 __sa1100fb_lcd_power(fbi, 1);
1175 sa1100fb_enable_controller(fbi);
1176 __sa1100fb_backlight_power(fbi, 1);
1177 }
1178 break;
1179 }
1180 mutex_unlock(&fbi->ctrlr_lock);
1181}
1182
1183
1184
1185
1186
1187static void sa1100fb_task(struct work_struct *w)
1188{
1189 struct sa1100fb_info *fbi = container_of(w, struct sa1100fb_info, task);
1190 u_int state = xchg(&fbi->task_state, -1);
1191
1192 set_ctrlr_state(fbi, state);
1193}
1194
1195#ifdef CONFIG_CPU_FREQ
1196
1197
1198
1199
1200
1201static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
1202{
1203#if 0
1204 unsigned int min_period = (unsigned int)-1;
1205 int i;
1206
1207 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1208 struct display *disp = &fb_display[i];
1209 unsigned int period;
1210
1211
1212
1213
1214 if (disp->fb_info != &fbi->fb)
1215 continue;
1216
1217
1218
1219
1220 period = sa1100fb_display_dma_period(&disp->var);
1221 if (period < min_period)
1222 min_period = period;
1223 }
1224
1225 return min_period;
1226#else
1227
1228
1229
1230 return sa1100fb_display_dma_period(&fbi->fb.var);
1231#endif
1232}
1233
1234
1235
1236
1237
1238
1239static int
1240sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,
1241 void *data)
1242{
1243 struct sa1100fb_info *fbi = TO_INF(nb, freq_transition);
1244 struct cpufreq_freqs *f = data;
1245 u_int pcd;
1246
1247 switch (val) {
1248 case CPUFREQ_PRECHANGE:
1249 set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
1250 break;
1251
1252 case CPUFREQ_POSTCHANGE:
1253 pcd = get_pcd(fbi->fb.var.pixclock, f->new);
1254 fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
1255 set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
1256 break;
1257 }
1258 return 0;
1259}
1260
1261static int
1262sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val,
1263 void *data)
1264{
1265 struct sa1100fb_info *fbi = TO_INF(nb, freq_policy);
1266 struct cpufreq_policy *policy = data;
1267
1268 switch (val) {
1269 case CPUFREQ_ADJUST:
1270 case CPUFREQ_INCOMPATIBLE:
1271 printk(KERN_DEBUG "min dma period: %d ps, "
1272 "new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
1273 policy->max);
1274
1275 break;
1276 case CPUFREQ_NOTIFY:
1277 do {} while(0);
1278
1279
1280
1281
1282 break;
1283 }
1284 return 0;
1285}
1286#endif
1287
1288#ifdef CONFIG_PM
1289
1290
1291
1292
1293static int sa1100fb_suspend(struct platform_device *dev, pm_message_t state)
1294{
1295 struct sa1100fb_info *fbi = platform_get_drvdata(dev);
1296
1297 set_ctrlr_state(fbi, C_DISABLE_PM);
1298 return 0;
1299}
1300
1301static int sa1100fb_resume(struct platform_device *dev)
1302{
1303 struct sa1100fb_info *fbi = platform_get_drvdata(dev);
1304
1305 set_ctrlr_state(fbi, C_ENABLE_PM);
1306 return 0;
1307}
1308#else
1309#define sa1100fb_suspend NULL
1310#define sa1100fb_resume NULL
1311#endif
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
1322{
1323
1324
1325
1326
1327 fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
1328 fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
1329 &fbi->map_dma, GFP_KERNEL);
1330
1331 if (fbi->map_cpu) {
1332 fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
1333 fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
1334
1335
1336
1337
1338
1339
1340 fbi->fb.fix.smem_start = fbi->screen_dma;
1341 }
1342
1343 return fbi->map_cpu ? 0 : -ENOMEM;
1344}
1345
1346
1347static struct fb_monspecs monspecs __initdata = {
1348 .hfmin = 30000,
1349 .hfmax = 70000,
1350 .vfmin = 50,
1351 .vfmax = 65,
1352};
1353
1354
1355static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
1356{
1357 struct sa1100fb_mach_info *inf;
1358 struct sa1100fb_info *fbi;
1359
1360 fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(u32) * 16,
1361 GFP_KERNEL);
1362 if (!fbi)
1363 return NULL;
1364
1365 memset(fbi, 0, sizeof(struct sa1100fb_info));
1366 fbi->dev = dev;
1367
1368 strcpy(fbi->fb.fix.id, SA1100_NAME);
1369
1370 fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
1371 fbi->fb.fix.type_aux = 0;
1372 fbi->fb.fix.xpanstep = 0;
1373 fbi->fb.fix.ypanstep = 0;
1374 fbi->fb.fix.ywrapstep = 0;
1375 fbi->fb.fix.accel = FB_ACCEL_NONE;
1376
1377 fbi->fb.var.nonstd = 0;
1378 fbi->fb.var.activate = FB_ACTIVATE_NOW;
1379 fbi->fb.var.height = -1;
1380 fbi->fb.var.width = -1;
1381 fbi->fb.var.accel_flags = 0;
1382 fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
1383
1384 fbi->fb.fbops = &sa1100fb_ops;
1385 fbi->fb.flags = FBINFO_DEFAULT;
1386 fbi->fb.monspecs = monspecs;
1387 fbi->fb.pseudo_palette = (fbi + 1);
1388
1389 fbi->rgb[RGB_4] = &rgb_4;
1390 fbi->rgb[RGB_8] = &rgb_8;
1391 fbi->rgb[RGB_16] = &def_rgb_16;
1392
1393 inf = sa1100fb_get_machine_info(fbi);
1394
1395
1396
1397
1398
1399
1400 if (inf->lccr3 & (LCCR3_VrtSnchL|LCCR3_HorSnchL|0xff) ||
1401 inf->pixclock == 0)
1402 panic("sa1100fb error: invalid LCCR3 fields set or zero "
1403 "pixclock.");
1404
1405 fbi->max_xres = inf->xres;
1406 fbi->fb.var.xres = inf->xres;
1407 fbi->fb.var.xres_virtual = inf->xres;
1408 fbi->max_yres = inf->yres;
1409 fbi->fb.var.yres = inf->yres;
1410 fbi->fb.var.yres_virtual = inf->yres;
1411 fbi->max_bpp = inf->bpp;
1412 fbi->fb.var.bits_per_pixel = inf->bpp;
1413 fbi->fb.var.pixclock = inf->pixclock;
1414 fbi->fb.var.hsync_len = inf->hsync_len;
1415 fbi->fb.var.left_margin = inf->left_margin;
1416 fbi->fb.var.right_margin = inf->right_margin;
1417 fbi->fb.var.vsync_len = inf->vsync_len;
1418 fbi->fb.var.upper_margin = inf->upper_margin;
1419 fbi->fb.var.lower_margin = inf->lower_margin;
1420 fbi->fb.var.sync = inf->sync;
1421 fbi->fb.var.grayscale = inf->cmap_greyscale;
1422 fbi->cmap_inverse = inf->cmap_inverse;
1423 fbi->cmap_static = inf->cmap_static;
1424 fbi->lccr0 = inf->lccr0;
1425 fbi->lccr3 = inf->lccr3;
1426 fbi->state = C_STARTUP;
1427 fbi->task_state = (u_char)-1;
1428 fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres *
1429 fbi->max_bpp / 8;
1430
1431 init_waitqueue_head(&fbi->ctrlr_wait);
1432 INIT_WORK(&fbi->task, sa1100fb_task);
1433 mutex_init(&fbi->ctrlr_lock);
1434
1435 return fbi;
1436}
1437
1438static int __init sa1100fb_probe(struct platform_device *pdev)
1439{
1440 struct sa1100fb_info *fbi;
1441 int ret, irq;
1442
1443 irq = platform_get_irq(pdev, 0);
1444 if (irq < 0)
1445 return -EINVAL;
1446
1447 if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
1448 return -EBUSY;
1449
1450 fbi = sa1100fb_init_fbinfo(&pdev->dev);
1451 ret = -ENOMEM;
1452 if (!fbi)
1453 goto failed;
1454
1455
1456 ret = sa1100fb_map_video_memory(fbi);
1457 if (ret)
1458 goto failed;
1459
1460 ret = request_irq(irq, sa1100fb_handle_irq, IRQF_DISABLED,
1461 "LCD", fbi);
1462 if (ret) {
1463 printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret);
1464 goto failed;
1465 }
1466
1467#ifdef ASSABET_PAL_VIDEO
1468 if (machine_is_assabet())
1469 ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
1470#endif
1471
1472
1473
1474
1475
1476 sa1100fb_check_var(&fbi->fb.var, &fbi->fb);
1477
1478 platform_set_drvdata(pdev, fbi);
1479
1480 ret = register_framebuffer(&fbi->fb);
1481 if (ret < 0)
1482 goto err_free_irq;
1483
1484#ifdef CONFIG_CPU_FREQ
1485 fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
1486 fbi->freq_policy.notifier_call = sa1100fb_freq_policy;
1487 cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
1488 cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
1489#endif
1490
1491
1492 return 0;
1493
1494 err_free_irq:
1495 free_irq(irq, fbi);
1496 failed:
1497 platform_set_drvdata(pdev, NULL);
1498 kfree(fbi);
1499 release_mem_region(0xb0100000, 0x10000);
1500 return ret;
1501}
1502
1503static struct platform_driver sa1100fb_driver = {
1504 .probe = sa1100fb_probe,
1505 .suspend = sa1100fb_suspend,
1506 .resume = sa1100fb_resume,
1507 .driver = {
1508 .name = "sa11x0-fb",
1509 },
1510};
1511
1512int __init sa1100fb_init(void)
1513{
1514 if (fb_get_options("sa1100fb", NULL))
1515 return -ENODEV;
1516
1517 return platform_driver_register(&sa1100fb_driver);
1518}
1519
1520int __init sa1100fb_setup(char *options)
1521{
1522#if 0
1523 char *this_opt;
1524
1525 if (!options || !*options)
1526 return 0;
1527
1528 while ((this_opt = strsep(&options, ",")) != NULL) {
1529
1530 if (!strncmp(this_opt, "bpp:", 4))
1531 current_par.max_bpp =
1532 simple_strtoul(this_opt + 4, NULL, 0);
1533
1534 if (!strncmp(this_opt, "lccr0:", 6))
1535 lcd_shadow.lccr0 =
1536 simple_strtoul(this_opt + 6, NULL, 0);
1537 if (!strncmp(this_opt, "lccr1:", 6)) {
1538 lcd_shadow.lccr1 =
1539 simple_strtoul(this_opt + 6, NULL, 0);
1540 current_par.max_xres =
1541 (lcd_shadow.lccr1 & 0x3ff) + 16;
1542 }
1543 if (!strncmp(this_opt, "lccr2:", 6)) {
1544 lcd_shadow.lccr2 =
1545 simple_strtoul(this_opt + 6, NULL, 0);
1546 current_par.max_yres =
1547 (lcd_shadow.
1548 lccr0 & LCCR0_SDS) ? ((lcd_shadow.
1549 lccr2 & 0x3ff) +
1550 1) *
1551 2 : ((lcd_shadow.lccr2 & 0x3ff) + 1);
1552 }
1553 if (!strncmp(this_opt, "lccr3:", 6))
1554 lcd_shadow.lccr3 =
1555 simple_strtoul(this_opt + 6, NULL, 0);
1556 }
1557#endif
1558 return 0;
1559}
1560
1561module_init(sa1100fb_init);
1562MODULE_DESCRIPTION("StrongARM-1100/1110 framebuffer driver");
1563MODULE_LICENSE("GPL");
1564