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