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