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/consumer.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 const 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 (fbi->shannon_lcden)
803 gpiod_set_value(fbi->shannon_lcden, 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 (fbi->shannon_lcden)
821 gpiod_set_value(fbi->shannon_lcden, 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 fallthrough;
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 int
976sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,
977 void *data)
978{
979 struct sa1100fb_info *fbi = TO_INF(nb, freq_transition);
980 u_int pcd;
981
982 switch (val) {
983 case CPUFREQ_PRECHANGE:
984 set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
985 break;
986
987 case CPUFREQ_POSTCHANGE:
988 pcd = get_pcd(fbi, fbi->fb.var.pixclock);
989 fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
990 set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
991 break;
992 }
993 return 0;
994}
995#endif
996
997#ifdef CONFIG_PM
998
999
1000
1001
1002static int sa1100fb_suspend(struct platform_device *dev, pm_message_t state)
1003{
1004 struct sa1100fb_info *fbi = platform_get_drvdata(dev);
1005
1006 set_ctrlr_state(fbi, C_DISABLE_PM);
1007 return 0;
1008}
1009
1010static int sa1100fb_resume(struct platform_device *dev)
1011{
1012 struct sa1100fb_info *fbi = platform_get_drvdata(dev);
1013
1014 set_ctrlr_state(fbi, C_ENABLE_PM);
1015 return 0;
1016}
1017#else
1018#define sa1100fb_suspend NULL
1019#define sa1100fb_resume NULL
1020#endif
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030static int sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
1031{
1032
1033
1034
1035
1036 fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
1037 fbi->map_cpu = dma_alloc_wc(fbi->dev, fbi->map_size, &fbi->map_dma,
1038 GFP_KERNEL);
1039
1040 if (fbi->map_cpu) {
1041 fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
1042 fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
1043
1044
1045
1046
1047
1048
1049 fbi->fb.fix.smem_start = fbi->screen_dma;
1050 }
1051
1052 return fbi->map_cpu ? 0 : -ENOMEM;
1053}
1054
1055
1056static const struct fb_monspecs monspecs = {
1057 .hfmin = 30000,
1058 .hfmax = 70000,
1059 .vfmin = 50,
1060 .vfmax = 65,
1061};
1062
1063
1064static struct sa1100fb_info *sa1100fb_init_fbinfo(struct device *dev)
1065{
1066 struct sa1100fb_mach_info *inf = dev_get_platdata(dev);
1067 struct sa1100fb_info *fbi;
1068 unsigned i;
1069
1070 fbi = devm_kzalloc(dev, sizeof(struct sa1100fb_info), GFP_KERNEL);
1071 if (!fbi)
1072 return NULL;
1073
1074 fbi->dev = dev;
1075
1076 strcpy(fbi->fb.fix.id, SA1100_NAME);
1077
1078 fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
1079 fbi->fb.fix.type_aux = 0;
1080 fbi->fb.fix.xpanstep = 0;
1081 fbi->fb.fix.ypanstep = 0;
1082 fbi->fb.fix.ywrapstep = 0;
1083 fbi->fb.fix.accel = FB_ACCEL_NONE;
1084
1085 fbi->fb.var.nonstd = 0;
1086 fbi->fb.var.activate = FB_ACTIVATE_NOW;
1087 fbi->fb.var.height = -1;
1088 fbi->fb.var.width = -1;
1089 fbi->fb.var.accel_flags = 0;
1090 fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
1091
1092 fbi->fb.fbops = &sa1100fb_ops;
1093 fbi->fb.flags = FBINFO_DEFAULT;
1094 fbi->fb.monspecs = monspecs;
1095 fbi->fb.pseudo_palette = fbi->pseudo_palette;
1096
1097 fbi->rgb[RGB_4] = &rgb_4;
1098 fbi->rgb[RGB_8] = &rgb_8;
1099 fbi->rgb[RGB_16] = &def_rgb_16;
1100
1101
1102
1103
1104
1105
1106 if (inf->lccr3 & (LCCR3_VrtSnchL|LCCR3_HorSnchL|0xff) ||
1107 inf->pixclock == 0)
1108 panic("sa1100fb error: invalid LCCR3 fields set or zero "
1109 "pixclock.");
1110
1111 fbi->fb.var.xres = inf->xres;
1112 fbi->fb.var.xres_virtual = inf->xres;
1113 fbi->fb.var.yres = inf->yres;
1114 fbi->fb.var.yres_virtual = inf->yres;
1115 fbi->fb.var.bits_per_pixel = inf->bpp;
1116 fbi->fb.var.pixclock = inf->pixclock;
1117 fbi->fb.var.hsync_len = inf->hsync_len;
1118 fbi->fb.var.left_margin = inf->left_margin;
1119 fbi->fb.var.right_margin = inf->right_margin;
1120 fbi->fb.var.vsync_len = inf->vsync_len;
1121 fbi->fb.var.upper_margin = inf->upper_margin;
1122 fbi->fb.var.lower_margin = inf->lower_margin;
1123 fbi->fb.var.sync = inf->sync;
1124 fbi->fb.var.grayscale = inf->cmap_greyscale;
1125 fbi->state = C_STARTUP;
1126 fbi->task_state = (u_char)-1;
1127 fbi->fb.fix.smem_len = inf->xres * inf->yres *
1128 inf->bpp / 8;
1129 fbi->inf = inf;
1130
1131
1132 for (i = 0; i < NR_RGB; i++)
1133 if (inf->rgb[i])
1134 fbi->rgb[i] = inf->rgb[i];
1135
1136 init_waitqueue_head(&fbi->ctrlr_wait);
1137 INIT_WORK(&fbi->task, sa1100fb_task);
1138 mutex_init(&fbi->ctrlr_lock);
1139
1140 return fbi;
1141}
1142
1143static int sa1100fb_probe(struct platform_device *pdev)
1144{
1145 struct sa1100fb_info *fbi;
1146 int ret, irq;
1147
1148 if (!dev_get_platdata(&pdev->dev)) {
1149 dev_err(&pdev->dev, "no platform LCD data\n");
1150 return -EINVAL;
1151 }
1152
1153 irq = platform_get_irq(pdev, 0);
1154 if (irq < 0)
1155 return -EINVAL;
1156
1157 fbi = sa1100fb_init_fbinfo(&pdev->dev);
1158 if (!fbi)
1159 return -ENOMEM;
1160
1161 fbi->base = devm_platform_ioremap_resource(pdev, 0);
1162 if (IS_ERR(fbi->base))
1163 return PTR_ERR(fbi->base);
1164
1165 fbi->clk = devm_clk_get(&pdev->dev, NULL);
1166 if (IS_ERR(fbi->clk))
1167 return PTR_ERR(fbi->clk);
1168
1169 ret = devm_request_irq(&pdev->dev, irq, sa1100fb_handle_irq, 0,
1170 "LCD", fbi);
1171 if (ret) {
1172 dev_err(&pdev->dev, "request_irq failed: %d\n", ret);
1173 return ret;
1174 }
1175
1176 fbi->shannon_lcden = gpiod_get_optional(&pdev->dev, "shannon-lcden",
1177 GPIOD_OUT_LOW);
1178 if (IS_ERR(fbi->shannon_lcden))
1179 return PTR_ERR(fbi->shannon_lcden);
1180
1181
1182 ret = sa1100fb_map_video_memory(fbi);
1183 if (ret)
1184 return ret;
1185
1186
1187
1188
1189
1190 sa1100fb_check_var(&fbi->fb.var, &fbi->fb);
1191
1192 platform_set_drvdata(pdev, fbi);
1193
1194 ret = register_framebuffer(&fbi->fb);
1195 if (ret < 0) {
1196 dma_free_wc(fbi->dev, fbi->map_size, fbi->map_cpu,
1197 fbi->map_dma);
1198 return ret;
1199 }
1200
1201#ifdef CONFIG_CPU_FREQ
1202 fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
1203 cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
1204#endif
1205
1206
1207 return 0;
1208}
1209
1210static struct platform_driver sa1100fb_driver = {
1211 .probe = sa1100fb_probe,
1212 .suspend = sa1100fb_suspend,
1213 .resume = sa1100fb_resume,
1214 .driver = {
1215 .name = "sa11x0-fb",
1216 },
1217};
1218
1219int __init sa1100fb_init(void)
1220{
1221 if (fb_get_options("sa1100fb", NULL))
1222 return -ENODEV;
1223
1224 return platform_driver_register(&sa1100fb_driver);
1225}
1226
1227int __init sa1100fb_setup(char *options)
1228{
1229#if 0
1230 char *this_opt;
1231
1232 if (!options || !*options)
1233 return 0;
1234
1235 while ((this_opt = strsep(&options, ",")) != NULL) {
1236
1237 if (!strncmp(this_opt, "bpp:", 4))
1238 current_par.max_bpp =
1239 simple_strtoul(this_opt + 4, NULL, 0);
1240
1241 if (!strncmp(this_opt, "lccr0:", 6))
1242 lcd_shadow.lccr0 =
1243 simple_strtoul(this_opt + 6, NULL, 0);
1244 if (!strncmp(this_opt, "lccr1:", 6)) {
1245 lcd_shadow.lccr1 =
1246 simple_strtoul(this_opt + 6, NULL, 0);
1247 current_par.max_xres =
1248 (lcd_shadow.lccr1 & 0x3ff) + 16;
1249 }
1250 if (!strncmp(this_opt, "lccr2:", 6)) {
1251 lcd_shadow.lccr2 =
1252 simple_strtoul(this_opt + 6, NULL, 0);
1253 current_par.max_yres =
1254 (lcd_shadow.
1255 lccr0 & LCCR0_SDS) ? ((lcd_shadow.
1256 lccr2 & 0x3ff) +
1257 1) *
1258 2 : ((lcd_shadow.lccr2 & 0x3ff) + 1);
1259 }
1260 if (!strncmp(this_opt, "lccr3:", 6))
1261 lcd_shadow.lccr3 =
1262 simple_strtoul(this_opt + 6, NULL, 0);
1263 }
1264#endif
1265 return 0;
1266}
1267
1268module_init(sa1100fb_init);
1269MODULE_DESCRIPTION("StrongARM-1100/1110 framebuffer driver");
1270MODULE_LICENSE("GPL");
1271