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