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#if 0
978 unsigned int min_period = (unsigned int)-1;
979 int i;
980
981 for (i = 0; i < MAX_NR_CONSOLES; i++) {
982 struct display *disp = &fb_display[i];
983 unsigned int period;
984
985
986
987
988 if (disp->fb_info != &fbi->fb)
989 continue;
990
991
992
993
994 period = sa1100fb_display_dma_period(&disp->var);
995 if (period < min_period)
996 min_period = period;
997 }
998
999 return min_period;
1000#else
1001
1002
1003
1004 return sa1100fb_display_dma_period(&fbi->fb.var);
1005#endif
1006}
1007
1008
1009
1010
1011
1012
1013static int
1014sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,
1015 void *data)
1016{
1017 struct sa1100fb_info *fbi = TO_INF(nb, freq_transition);
1018 u_int pcd;
1019
1020 switch (val) {
1021 case CPUFREQ_PRECHANGE:
1022 set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
1023 break;
1024
1025 case CPUFREQ_POSTCHANGE:
1026 pcd = get_pcd(fbi, fbi->fb.var.pixclock);
1027 fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
1028 set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
1029 break;
1030 }
1031 return 0;
1032}
1033
1034static int
1035sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val,
1036 void *data)
1037{
1038 struct sa1100fb_info *fbi = TO_INF(nb, freq_policy);
1039 struct cpufreq_policy *policy = data;
1040
1041 switch (val) {
1042 case CPUFREQ_ADJUST:
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 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_wc(fbi->dev, fbi->map_size, &fbi->map_dma,
1101 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 = {
1120 .hfmin = 30000,
1121 .hfmax = 70000,
1122 .vfmin = 50,
1123 .vfmax = 65,
1124};
1125
1126
1127static struct sa1100fb_info *sa1100fb_init_fbinfo(struct device *dev)
1128{
1129 struct sa1100fb_mach_info *inf = dev_get_platdata(dev);
1130 struct sa1100fb_info *fbi;
1131 unsigned i;
1132
1133 fbi = devm_kzalloc(dev, sizeof(struct sa1100fb_info), GFP_KERNEL);
1134 if (!fbi)
1135 return NULL;
1136
1137 fbi->dev = dev;
1138
1139 strcpy(fbi->fb.fix.id, SA1100_NAME);
1140
1141 fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
1142 fbi->fb.fix.type_aux = 0;
1143 fbi->fb.fix.xpanstep = 0;
1144 fbi->fb.fix.ypanstep = 0;
1145 fbi->fb.fix.ywrapstep = 0;
1146 fbi->fb.fix.accel = FB_ACCEL_NONE;
1147
1148 fbi->fb.var.nonstd = 0;
1149 fbi->fb.var.activate = FB_ACTIVATE_NOW;
1150 fbi->fb.var.height = -1;
1151 fbi->fb.var.width = -1;
1152 fbi->fb.var.accel_flags = 0;
1153 fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
1154
1155 fbi->fb.fbops = &sa1100fb_ops;
1156 fbi->fb.flags = FBINFO_DEFAULT;
1157 fbi->fb.monspecs = monspecs;
1158 fbi->fb.pseudo_palette = fbi->pseudo_palette;
1159
1160 fbi->rgb[RGB_4] = &rgb_4;
1161 fbi->rgb[RGB_8] = &rgb_8;
1162 fbi->rgb[RGB_16] = &def_rgb_16;
1163
1164
1165
1166
1167
1168
1169 if (inf->lccr3 & (LCCR3_VrtSnchL|LCCR3_HorSnchL|0xff) ||
1170 inf->pixclock == 0)
1171 panic("sa1100fb error: invalid LCCR3 fields set or zero "
1172 "pixclock.");
1173
1174 fbi->fb.var.xres = inf->xres;
1175 fbi->fb.var.xres_virtual = inf->xres;
1176 fbi->fb.var.yres = inf->yres;
1177 fbi->fb.var.yres_virtual = inf->yres;
1178 fbi->fb.var.bits_per_pixel = inf->bpp;
1179 fbi->fb.var.pixclock = inf->pixclock;
1180 fbi->fb.var.hsync_len = inf->hsync_len;
1181 fbi->fb.var.left_margin = inf->left_margin;
1182 fbi->fb.var.right_margin = inf->right_margin;
1183 fbi->fb.var.vsync_len = inf->vsync_len;
1184 fbi->fb.var.upper_margin = inf->upper_margin;
1185 fbi->fb.var.lower_margin = inf->lower_margin;
1186 fbi->fb.var.sync = inf->sync;
1187 fbi->fb.var.grayscale = inf->cmap_greyscale;
1188 fbi->state = C_STARTUP;
1189 fbi->task_state = (u_char)-1;
1190 fbi->fb.fix.smem_len = inf->xres * inf->yres *
1191 inf->bpp / 8;
1192 fbi->inf = inf;
1193
1194
1195 for (i = 0; i < NR_RGB; i++)
1196 if (inf->rgb[i])
1197 fbi->rgb[i] = inf->rgb[i];
1198
1199 init_waitqueue_head(&fbi->ctrlr_wait);
1200 INIT_WORK(&fbi->task, sa1100fb_task);
1201 mutex_init(&fbi->ctrlr_lock);
1202
1203 return fbi;
1204}
1205
1206static int sa1100fb_probe(struct platform_device *pdev)
1207{
1208 struct sa1100fb_info *fbi;
1209 struct resource *res;
1210 int ret, irq;
1211
1212 if (!dev_get_platdata(&pdev->dev)) {
1213 dev_err(&pdev->dev, "no platform LCD data\n");
1214 return -EINVAL;
1215 }
1216
1217 irq = platform_get_irq(pdev, 0);
1218 if (irq < 0)
1219 return -EINVAL;
1220
1221 fbi = sa1100fb_init_fbinfo(&pdev->dev);
1222 if (!fbi)
1223 return -ENOMEM;
1224
1225 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1226 fbi->base = devm_ioremap_resource(&pdev->dev, res);
1227 if (IS_ERR(fbi->base))
1228 return PTR_ERR(fbi->base);
1229
1230 fbi->clk = devm_clk_get(&pdev->dev, NULL);
1231 if (IS_ERR(fbi->clk))
1232 return PTR_ERR(fbi->clk);
1233
1234 ret = devm_request_irq(&pdev->dev, irq, sa1100fb_handle_irq, 0,
1235 "LCD", fbi);
1236 if (ret) {
1237 dev_err(&pdev->dev, "request_irq failed: %d\n", ret);
1238 return ret;
1239 }
1240
1241 if (machine_is_shannon()) {
1242 ret = devm_gpio_request_one(&pdev->dev, SHANNON_GPIO_DISP_EN,
1243 GPIOF_OUT_INIT_LOW, "display enable");
1244 if (ret)
1245 return ret;
1246 }
1247
1248
1249 ret = sa1100fb_map_video_memory(fbi);
1250 if (ret)
1251 return ret;
1252
1253
1254
1255
1256
1257 sa1100fb_check_var(&fbi->fb.var, &fbi->fb);
1258
1259 platform_set_drvdata(pdev, fbi);
1260
1261 ret = register_framebuffer(&fbi->fb);
1262 if (ret < 0) {
1263 dma_free_wc(fbi->dev, fbi->map_size, fbi->map_cpu,
1264 fbi->map_dma);
1265 return ret;
1266 }
1267
1268#ifdef CONFIG_CPU_FREQ
1269 fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
1270 fbi->freq_policy.notifier_call = sa1100fb_freq_policy;
1271 cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
1272 cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
1273#endif
1274
1275
1276 return 0;
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 },
1286};
1287
1288int __init sa1100fb_init(void)
1289{
1290 if (fb_get_options("sa1100fb", NULL))
1291 return -ENODEV;
1292
1293 return platform_driver_register(&sa1100fb_driver);
1294}
1295
1296int __init sa1100fb_setup(char *options)
1297{
1298#if 0
1299 char *this_opt;
1300
1301 if (!options || !*options)
1302 return 0;
1303
1304 while ((this_opt = strsep(&options, ",")) != NULL) {
1305
1306 if (!strncmp(this_opt, "bpp:", 4))
1307 current_par.max_bpp =
1308 simple_strtoul(this_opt + 4, NULL, 0);
1309
1310 if (!strncmp(this_opt, "lccr0:", 6))
1311 lcd_shadow.lccr0 =
1312 simple_strtoul(this_opt + 6, NULL, 0);
1313 if (!strncmp(this_opt, "lccr1:", 6)) {
1314 lcd_shadow.lccr1 =
1315 simple_strtoul(this_opt + 6, NULL, 0);
1316 current_par.max_xres =
1317 (lcd_shadow.lccr1 & 0x3ff) + 16;
1318 }
1319 if (!strncmp(this_opt, "lccr2:", 6)) {
1320 lcd_shadow.lccr2 =
1321 simple_strtoul(this_opt + 6, NULL, 0);
1322 current_par.max_yres =
1323 (lcd_shadow.
1324 lccr0 & LCCR0_SDS) ? ((lcd_shadow.
1325 lccr2 & 0x3ff) +
1326 1) *
1327 2 : ((lcd_shadow.lccr2 & 0x3ff) + 1);
1328 }
1329 if (!strncmp(this_opt, "lccr3:", 6))
1330 lcd_shadow.lccr3 =
1331 simple_strtoul(this_opt + 6, NULL, 0);
1332 }
1333#endif
1334 return 0;
1335}
1336
1337module_init(sa1100fb_init);
1338MODULE_DESCRIPTION("StrongARM-1100/1110 framebuffer driver");
1339MODULE_LICENSE("GPL");
1340