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 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 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
568
569 return vm_iomap_memory(vma, info->fix.mmio_start, info->fix.mmio_len);
570}
571
572static struct fb_ops sa1100fb_ops = {
573 .owner = THIS_MODULE,
574 .fb_check_var = sa1100fb_check_var,
575 .fb_set_par = sa1100fb_set_par,
576
577 .fb_setcolreg = sa1100fb_setcolreg,
578 .fb_fillrect = cfb_fillrect,
579 .fb_copyarea = cfb_copyarea,
580 .fb_imageblit = cfb_imageblit,
581 .fb_blank = sa1100fb_blank,
582 .fb_mmap = sa1100fb_mmap,
583};
584
585
586
587
588
589static inline unsigned int get_pcd(unsigned int pixclock, unsigned int cpuclock)
590{
591 unsigned int pcd = cpuclock / 100;
592
593 pcd *= pixclock;
594 pcd /= 10000000;
595
596 return pcd + 1;
597}
598
599
600
601
602
603
604static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
605{
606 struct sa1100fb_lcd_reg new_regs;
607 u_int half_screen_size, yres, pcd;
608 u_long flags;
609
610 dev_dbg(fbi->dev, "Configuring SA1100 LCD\n");
611
612 dev_dbg(fbi->dev, "var: xres=%d hslen=%d lm=%d rm=%d\n",
613 var->xres, var->hsync_len,
614 var->left_margin, var->right_margin);
615 dev_dbg(fbi->dev, "var: yres=%d vslen=%d um=%d bm=%d\n",
616 var->yres, var->vsync_len,
617 var->upper_margin, var->lower_margin);
618
619#if DEBUG_VAR
620 if (var->xres < 16 || var->xres > 1024)
621 dev_err(fbi->dev, "%s: invalid xres %d\n",
622 fbi->fb.fix.id, var->xres);
623 if (var->hsync_len < 1 || var->hsync_len > 64)
624 dev_err(fbi->dev, "%s: invalid hsync_len %d\n",
625 fbi->fb.fix.id, var->hsync_len);
626 if (var->left_margin < 1 || var->left_margin > 255)
627 dev_err(fbi->dev, "%s: invalid left_margin %d\n",
628 fbi->fb.fix.id, var->left_margin);
629 if (var->right_margin < 1 || var->right_margin > 255)
630 dev_err(fbi->dev, "%s: invalid right_margin %d\n",
631 fbi->fb.fix.id, var->right_margin);
632 if (var->yres < 1 || var->yres > 1024)
633 dev_err(fbi->dev, "%s: invalid yres %d\n",
634 fbi->fb.fix.id, var->yres);
635 if (var->vsync_len < 1 || var->vsync_len > 64)
636 dev_err(fbi->dev, "%s: invalid vsync_len %d\n",
637 fbi->fb.fix.id, var->vsync_len);
638 if (var->upper_margin < 0 || var->upper_margin > 255)
639 dev_err(fbi->dev, "%s: invalid upper_margin %d\n",
640 fbi->fb.fix.id, var->upper_margin);
641 if (var->lower_margin < 0 || var->lower_margin > 255)
642 dev_err(fbi->dev, "%s: invalid lower_margin %d\n",
643 fbi->fb.fix.id, var->lower_margin);
644#endif
645
646 new_regs.lccr0 = fbi->inf->lccr0 |
647 LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
648 LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
649
650 new_regs.lccr1 =
651 LCCR1_DisWdth(var->xres) +
652 LCCR1_HorSnchWdth(var->hsync_len) +
653 LCCR1_BegLnDel(var->left_margin) +
654 LCCR1_EndLnDel(var->right_margin);
655
656
657
658
659
660 yres = var->yres;
661 if (fbi->inf->lccr0 & LCCR0_Dual)
662 yres /= 2;
663
664 new_regs.lccr2 =
665 LCCR2_DisHght(yres) +
666 LCCR2_VrtSnchWdth(var->vsync_len) +
667 LCCR2_BegFrmDel(var->upper_margin) +
668 LCCR2_EndFrmDel(var->lower_margin);
669
670 pcd = get_pcd(var->pixclock, cpufreq_get(0));
671 new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->inf->lccr3 |
672 (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
673 (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
674
675 dev_dbg(fbi->dev, "nlccr0 = 0x%08lx\n", new_regs.lccr0);
676 dev_dbg(fbi->dev, "nlccr1 = 0x%08lx\n", new_regs.lccr1);
677 dev_dbg(fbi->dev, "nlccr2 = 0x%08lx\n", new_regs.lccr2);
678 dev_dbg(fbi->dev, "nlccr3 = 0x%08lx\n", new_regs.lccr3);
679
680 half_screen_size = var->bits_per_pixel;
681 half_screen_size = half_screen_size * var->xres * var->yres / 16;
682
683
684 local_irq_save(flags);
685 fbi->dbar1 = fbi->palette_dma;
686 fbi->dbar2 = fbi->screen_dma + half_screen_size;
687
688 fbi->reg_lccr0 = new_regs.lccr0;
689 fbi->reg_lccr1 = new_regs.lccr1;
690 fbi->reg_lccr2 = new_regs.lccr2;
691 fbi->reg_lccr3 = new_regs.lccr3;
692 local_irq_restore(flags);
693
694
695
696
697
698 if (readl_relaxed(fbi->base + LCCR0) != fbi->reg_lccr0 ||
699 readl_relaxed(fbi->base + LCCR1) != fbi->reg_lccr1 ||
700 readl_relaxed(fbi->base + LCCR2) != fbi->reg_lccr2 ||
701 readl_relaxed(fbi->base + LCCR3) != fbi->reg_lccr3 ||
702 readl_relaxed(fbi->base + DBAR1) != fbi->dbar1 ||
703 readl_relaxed(fbi->base + DBAR2) != fbi->dbar2)
704 sa1100fb_schedule_work(fbi, C_REENABLE);
705
706 return 0;
707}
708
709
710
711
712
713
714
715static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on)
716{
717 dev_dbg(fbi->dev, "backlight o%s\n", on ? "n" : "ff");
718
719 if (fbi->inf->backlight_power)
720 fbi->inf->backlight_power(on);
721}
722
723static inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on)
724{
725 dev_dbg(fbi->dev, "LCD power o%s\n", on ? "n" : "ff");
726
727 if (fbi->inf->lcd_power)
728 fbi->inf->lcd_power(on);
729}
730
731static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
732{
733 u_int mask = 0;
734
735
736
737
738
739
740
741
742
743
744
745
746
747 if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color &&
748 (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) {
749 mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
750
751 if (fbi->fb.var.bits_per_pixel > 8 ||
752 (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual)
753 mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12;
754
755 }
756
757 if (mask) {
758 unsigned long flags;
759
760
761
762
763
764
765
766
767 local_irq_save(flags);
768 GPDR |= mask;
769 GAFR |= mask;
770 local_irq_restore(flags);
771 }
772}
773
774static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
775{
776 dev_dbg(fbi->dev, "Enabling LCD controller\n");
777
778
779
780
781 fbi->palette_cpu[0] &= 0xcfff;
782 fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
783
784
785 writel_relaxed(fbi->reg_lccr3, fbi->base + LCCR3);
786 writel_relaxed(fbi->reg_lccr2, fbi->base + LCCR2);
787 writel_relaxed(fbi->reg_lccr1, fbi->base + LCCR1);
788 writel_relaxed(fbi->reg_lccr0 & ~LCCR0_LEN, fbi->base + LCCR0);
789 writel_relaxed(fbi->dbar1, fbi->base + DBAR1);
790 writel_relaxed(fbi->dbar2, fbi->base + DBAR2);
791 writel_relaxed(fbi->reg_lccr0 | LCCR0_LEN, fbi->base + LCCR0);
792
793 if (machine_is_shannon())
794 gpio_set_value(SHANNON_GPIO_DISP_EN, 1);
795
796 dev_dbg(fbi->dev, "DBAR1: 0x%08x\n", readl_relaxed(fbi->base + DBAR1));
797 dev_dbg(fbi->dev, "DBAR2: 0x%08x\n", readl_relaxed(fbi->base + DBAR2));
798 dev_dbg(fbi->dev, "LCCR0: 0x%08x\n", readl_relaxed(fbi->base + LCCR0));
799 dev_dbg(fbi->dev, "LCCR1: 0x%08x\n", readl_relaxed(fbi->base + LCCR1));
800 dev_dbg(fbi->dev, "LCCR2: 0x%08x\n", readl_relaxed(fbi->base + LCCR2));
801 dev_dbg(fbi->dev, "LCCR3: 0x%08x\n", readl_relaxed(fbi->base + LCCR3));
802}
803
804static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
805{
806 DECLARE_WAITQUEUE(wait, current);
807 u32 lccr0;
808
809 dev_dbg(fbi->dev, "Disabling LCD controller\n");
810
811 if (machine_is_shannon())
812 gpio_set_value(SHANNON_GPIO_DISP_EN, 0);
813
814 set_current_state(TASK_UNINTERRUPTIBLE);
815 add_wait_queue(&fbi->ctrlr_wait, &wait);
816
817
818 writel_relaxed(~0, fbi->base + LCSR);
819
820 lccr0 = readl_relaxed(fbi->base + LCCR0);
821 lccr0 &= ~LCCR0_LDM;
822 writel_relaxed(lccr0, fbi->base + LCCR0);
823 lccr0 &= ~LCCR0_LEN;
824 writel_relaxed(lccr0, fbi->base + LCCR0);
825
826 schedule_timeout(20 * HZ / 1000);
827 remove_wait_queue(&fbi->ctrlr_wait, &wait);
828}
829
830
831
832
833static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id)
834{
835 struct sa1100fb_info *fbi = dev_id;
836 unsigned int lcsr = readl_relaxed(fbi->base + LCSR);
837
838 if (lcsr & LCSR_LDD) {
839 u32 lccr0 = readl_relaxed(fbi->base + LCCR0) | LCCR0_LDM;
840 writel_relaxed(lccr0, fbi->base + LCCR0);
841 wake_up(&fbi->ctrlr_wait);
842 }
843
844 writel_relaxed(lcsr, fbi->base + LCSR);
845 return IRQ_HANDLED;
846}
847
848
849
850
851
852
853static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
854{
855 u_int old_state;
856
857 mutex_lock(&fbi->ctrlr_lock);
858
859 old_state = fbi->state;
860
861
862
863
864 if (old_state == C_STARTUP && state == C_REENABLE)
865 state = C_ENABLE;
866
867 switch (state) {
868 case C_DISABLE_CLKCHANGE:
869
870
871
872
873 if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
874 fbi->state = state;
875 sa1100fb_disable_controller(fbi);
876 }
877 break;
878
879 case C_DISABLE_PM:
880 case C_DISABLE:
881
882
883
884 if (old_state != C_DISABLE) {
885 fbi->state = state;
886
887 __sa1100fb_backlight_power(fbi, 0);
888 if (old_state != C_DISABLE_CLKCHANGE)
889 sa1100fb_disable_controller(fbi);
890 __sa1100fb_lcd_power(fbi, 0);
891 }
892 break;
893
894 case C_ENABLE_CLKCHANGE:
895
896
897
898
899 if (old_state == C_DISABLE_CLKCHANGE) {
900 fbi->state = C_ENABLE;
901 sa1100fb_enable_controller(fbi);
902 }
903 break;
904
905 case C_REENABLE:
906
907
908
909
910
911 if (old_state == C_ENABLE) {
912 sa1100fb_disable_controller(fbi);
913 sa1100fb_setup_gpio(fbi);
914 sa1100fb_enable_controller(fbi);
915 }
916 break;
917
918 case C_ENABLE_PM:
919
920
921
922
923
924 if (old_state != C_DISABLE_PM)
925 break;
926
927
928 case C_ENABLE:
929
930
931
932
933 if (old_state != C_ENABLE) {
934 fbi->state = C_ENABLE;
935 sa1100fb_setup_gpio(fbi);
936 __sa1100fb_lcd_power(fbi, 1);
937 sa1100fb_enable_controller(fbi);
938 __sa1100fb_backlight_power(fbi, 1);
939 }
940 break;
941 }
942 mutex_unlock(&fbi->ctrlr_lock);
943}
944
945
946
947
948
949static void sa1100fb_task(struct work_struct *w)
950{
951 struct sa1100fb_info *fbi = container_of(w, struct sa1100fb_info, task);
952 u_int state = xchg(&fbi->task_state, -1);
953
954 set_ctrlr_state(fbi, state);
955}
956
957#ifdef CONFIG_CPU_FREQ
958
959
960
961
962
963static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
964{
965#if 0
966 unsigned int min_period = (unsigned int)-1;
967 int i;
968
969 for (i = 0; i < MAX_NR_CONSOLES; i++) {
970 struct display *disp = &fb_display[i];
971 unsigned int period;
972
973
974
975
976 if (disp->fb_info != &fbi->fb)
977 continue;
978
979
980
981
982 period = sa1100fb_display_dma_period(&disp->var);
983 if (period < min_period)
984 min_period = period;
985 }
986
987 return min_period;
988#else
989
990
991
992 return sa1100fb_display_dma_period(&fbi->fb.var);
993#endif
994}
995
996
997
998
999
1000
1001static int
1002sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,
1003 void *data)
1004{
1005 struct sa1100fb_info *fbi = TO_INF(nb, freq_transition);
1006 struct cpufreq_freqs *f = data;
1007 u_int pcd;
1008
1009 switch (val) {
1010 case CPUFREQ_PRECHANGE:
1011 set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
1012 break;
1013
1014 case CPUFREQ_POSTCHANGE:
1015 pcd = get_pcd(fbi->fb.var.pixclock, f->new);
1016 fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
1017 set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
1018 break;
1019 }
1020 return 0;
1021}
1022
1023static int
1024sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val,
1025 void *data)
1026{
1027 struct sa1100fb_info *fbi = TO_INF(nb, freq_policy);
1028 struct cpufreq_policy *policy = data;
1029
1030 switch (val) {
1031 case CPUFREQ_ADJUST:
1032 case CPUFREQ_INCOMPATIBLE:
1033 dev_dbg(fbi->dev, "min dma period: %d ps, "
1034 "new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
1035 policy->max);
1036
1037 break;
1038 case CPUFREQ_NOTIFY:
1039 do {} while(0);
1040
1041
1042
1043
1044 break;
1045 }
1046 return 0;
1047}
1048#endif
1049
1050#ifdef CONFIG_PM
1051
1052
1053
1054
1055static int sa1100fb_suspend(struct platform_device *dev, pm_message_t state)
1056{
1057 struct sa1100fb_info *fbi = platform_get_drvdata(dev);
1058
1059 set_ctrlr_state(fbi, C_DISABLE_PM);
1060 return 0;
1061}
1062
1063static int sa1100fb_resume(struct platform_device *dev)
1064{
1065 struct sa1100fb_info *fbi = platform_get_drvdata(dev);
1066
1067 set_ctrlr_state(fbi, C_ENABLE_PM);
1068 return 0;
1069}
1070#else
1071#define sa1100fb_suspend NULL
1072#define sa1100fb_resume NULL
1073#endif
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083static int sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
1084{
1085
1086
1087
1088
1089 fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
1090 fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
1091 &fbi->map_dma, GFP_KERNEL);
1092
1093 if (fbi->map_cpu) {
1094 fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
1095 fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
1096
1097
1098
1099
1100
1101
1102 fbi->fb.fix.smem_start = fbi->screen_dma;
1103 }
1104
1105 return fbi->map_cpu ? 0 : -ENOMEM;
1106}
1107
1108
1109static struct fb_monspecs monspecs = {
1110 .hfmin = 30000,
1111 .hfmax = 70000,
1112 .vfmin = 50,
1113 .vfmax = 65,
1114};
1115
1116
1117static struct sa1100fb_info *sa1100fb_init_fbinfo(struct device *dev)
1118{
1119 struct sa1100fb_mach_info *inf = dev_get_platdata(dev);
1120 struct sa1100fb_info *fbi;
1121 unsigned i;
1122
1123 fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(u32) * 16,
1124 GFP_KERNEL);
1125 if (!fbi)
1126 return NULL;
1127
1128 memset(fbi, 0, sizeof(struct sa1100fb_info));
1129 fbi->dev = dev;
1130
1131 strcpy(fbi->fb.fix.id, SA1100_NAME);
1132
1133 fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
1134 fbi->fb.fix.type_aux = 0;
1135 fbi->fb.fix.xpanstep = 0;
1136 fbi->fb.fix.ypanstep = 0;
1137 fbi->fb.fix.ywrapstep = 0;
1138 fbi->fb.fix.accel = FB_ACCEL_NONE;
1139
1140 fbi->fb.var.nonstd = 0;
1141 fbi->fb.var.activate = FB_ACTIVATE_NOW;
1142 fbi->fb.var.height = -1;
1143 fbi->fb.var.width = -1;
1144 fbi->fb.var.accel_flags = 0;
1145 fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
1146
1147 fbi->fb.fbops = &sa1100fb_ops;
1148 fbi->fb.flags = FBINFO_DEFAULT;
1149 fbi->fb.monspecs = monspecs;
1150 fbi->fb.pseudo_palette = (fbi + 1);
1151
1152 fbi->rgb[RGB_4] = &rgb_4;
1153 fbi->rgb[RGB_8] = &rgb_8;
1154 fbi->rgb[RGB_16] = &def_rgb_16;
1155
1156
1157
1158
1159
1160
1161 if (inf->lccr3 & (LCCR3_VrtSnchL|LCCR3_HorSnchL|0xff) ||
1162 inf->pixclock == 0)
1163 panic("sa1100fb error: invalid LCCR3 fields set or zero "
1164 "pixclock.");
1165
1166 fbi->fb.var.xres = inf->xres;
1167 fbi->fb.var.xres_virtual = inf->xres;
1168 fbi->fb.var.yres = inf->yres;
1169 fbi->fb.var.yres_virtual = inf->yres;
1170 fbi->fb.var.bits_per_pixel = inf->bpp;
1171 fbi->fb.var.pixclock = inf->pixclock;
1172 fbi->fb.var.hsync_len = inf->hsync_len;
1173 fbi->fb.var.left_margin = inf->left_margin;
1174 fbi->fb.var.right_margin = inf->right_margin;
1175 fbi->fb.var.vsync_len = inf->vsync_len;
1176 fbi->fb.var.upper_margin = inf->upper_margin;
1177 fbi->fb.var.lower_margin = inf->lower_margin;
1178 fbi->fb.var.sync = inf->sync;
1179 fbi->fb.var.grayscale = inf->cmap_greyscale;
1180 fbi->state = C_STARTUP;
1181 fbi->task_state = (u_char)-1;
1182 fbi->fb.fix.smem_len = inf->xres * inf->yres *
1183 inf->bpp / 8;
1184 fbi->inf = inf;
1185
1186
1187 for (i = 0; i < NR_RGB; i++)
1188 if (inf->rgb[i])
1189 fbi->rgb[i] = inf->rgb[i];
1190
1191 init_waitqueue_head(&fbi->ctrlr_wait);
1192 INIT_WORK(&fbi->task, sa1100fb_task);
1193 mutex_init(&fbi->ctrlr_lock);
1194
1195 return fbi;
1196}
1197
1198static int sa1100fb_probe(struct platform_device *pdev)
1199{
1200 struct sa1100fb_info *fbi;
1201 struct resource *res;
1202 int ret, irq;
1203
1204 if (!dev_get_platdata(&pdev->dev)) {
1205 dev_err(&pdev->dev, "no platform LCD data\n");
1206 return -EINVAL;
1207 }
1208
1209 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1210 irq = platform_get_irq(pdev, 0);
1211 if (irq < 0 || !res)
1212 return -EINVAL;
1213
1214 if (!request_mem_region(res->start, resource_size(res), "LCD"))
1215 return -EBUSY;
1216
1217 fbi = sa1100fb_init_fbinfo(&pdev->dev);
1218 ret = -ENOMEM;
1219 if (!fbi)
1220 goto failed;
1221
1222 fbi->base = ioremap(res->start, resource_size(res));
1223 if (!fbi->base)
1224 goto failed;
1225
1226
1227 ret = sa1100fb_map_video_memory(fbi);
1228 if (ret)
1229 goto failed;
1230
1231 ret = request_irq(irq, sa1100fb_handle_irq, 0, "LCD", fbi);
1232 if (ret) {
1233 dev_err(&pdev->dev, "request_irq failed: %d\n", ret);
1234 goto failed;
1235 }
1236
1237 if (machine_is_shannon()) {
1238 ret = gpio_request_one(SHANNON_GPIO_DISP_EN,
1239 GPIOF_OUT_INIT_LOW, "display enable");
1240 if (ret)
1241 goto err_free_irq;
1242 }
1243
1244
1245
1246
1247
1248 sa1100fb_check_var(&fbi->fb.var, &fbi->fb);
1249
1250 platform_set_drvdata(pdev, fbi);
1251
1252 ret = register_framebuffer(&fbi->fb);
1253 if (ret < 0)
1254 goto err_reg_fb;
1255
1256#ifdef CONFIG_CPU_FREQ
1257 fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
1258 fbi->freq_policy.notifier_call = sa1100fb_freq_policy;
1259 cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
1260 cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
1261#endif
1262
1263
1264 return 0;
1265
1266 err_reg_fb:
1267 if (machine_is_shannon())
1268 gpio_free(SHANNON_GPIO_DISP_EN);
1269 err_free_irq:
1270 free_irq(irq, fbi);
1271 failed:
1272 if (fbi)
1273 iounmap(fbi->base);
1274 kfree(fbi);
1275 release_mem_region(res->start, resource_size(res));
1276 return ret;
1277}
1278
1279static struct platform_driver sa1100fb_driver = {
1280 .probe = sa1100fb_probe,
1281 .suspend = sa1100fb_suspend,
1282 .resume = sa1100fb_resume,
1283 .driver = {
1284 .name = "sa11x0-fb",
1285 .owner = THIS_MODULE,
1286 },
1287};
1288
1289int __init sa1100fb_init(void)
1290{
1291 if (fb_get_options("sa1100fb", NULL))
1292 return -ENODEV;
1293
1294 return platform_driver_register(&sa1100fb_driver);
1295}
1296
1297int __init sa1100fb_setup(char *options)
1298{
1299#if 0
1300 char *this_opt;
1301
1302 if (!options || !*options)
1303 return 0;
1304
1305 while ((this_opt = strsep(&options, ",")) != NULL) {
1306
1307 if (!strncmp(this_opt, "bpp:", 4))
1308 current_par.max_bpp =
1309 simple_strtoul(this_opt + 4, NULL, 0);
1310
1311 if (!strncmp(this_opt, "lccr0:", 6))
1312 lcd_shadow.lccr0 =
1313 simple_strtoul(this_opt + 6, NULL, 0);
1314 if (!strncmp(this_opt, "lccr1:", 6)) {
1315 lcd_shadow.lccr1 =
1316 simple_strtoul(this_opt + 6, NULL, 0);
1317 current_par.max_xres =
1318 (lcd_shadow.lccr1 & 0x3ff) + 16;
1319 }
1320 if (!strncmp(this_opt, "lccr2:", 6)) {
1321 lcd_shadow.lccr2 =
1322 simple_strtoul(this_opt + 6, NULL, 0);
1323 current_par.max_yres =
1324 (lcd_shadow.
1325 lccr0 & LCCR0_SDS) ? ((lcd_shadow.
1326 lccr2 & 0x3ff) +
1327 1) *
1328 2 : ((lcd_shadow.lccr2 & 0x3ff) + 1);
1329 }
1330 if (!strncmp(this_opt, "lccr3:", 6))
1331 lcd_shadow.lccr3 =
1332 simple_strtoul(this_opt + 6, NULL, 0);
1333 }
1334#endif
1335 return 0;
1336}
1337
1338module_init(sa1100fb_init);
1339MODULE_DESCRIPTION("StrongARM-1100/1110 framebuffer driver");
1340MODULE_LICENSE("GPL");
1341