0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163 #include <linux/module.h>
0164 #include <linux/kernel.h>
0165 #include <linux/sched.h>
0166 #include <linux/errno.h>
0167 #include <linux/string.h>
0168 #include <linux/interrupt.h>
0169 #include <linux/slab.h>
0170 #include <linux/mm.h>
0171 #include <linux/fb.h>
0172 #include <linux/delay.h>
0173 #include <linux/init.h>
0174 #include <linux/ioport.h>
0175 #include <linux/cpufreq.h>
0176 #include <linux/gpio/consumer.h>
0177 #include <linux/platform_device.h>
0178 #include <linux/dma-mapping.h>
0179 #include <linux/mutex.h>
0180 #include <linux/io.h>
0181 #include <linux/clk.h>
0182
0183 #include <video/sa1100fb.h>
0184
0185 #include <mach/hardware.h>
0186 #include <asm/mach-types.h>
0187 #include <mach/shannon.h>
0188
0189
0190
0191
0192 #define DEBUG_VAR 1
0193
0194 #include "sa1100fb.h"
0195
0196 static const struct sa1100fb_rgb rgb_4 = {
0197 .red = { .offset = 0, .length = 4, },
0198 .green = { .offset = 0, .length = 4, },
0199 .blue = { .offset = 0, .length = 4, },
0200 .transp = { .offset = 0, .length = 0, },
0201 };
0202
0203 static const struct sa1100fb_rgb rgb_8 = {
0204 .red = { .offset = 0, .length = 8, },
0205 .green = { .offset = 0, .length = 8, },
0206 .blue = { .offset = 0, .length = 8, },
0207 .transp = { .offset = 0, .length = 0, },
0208 };
0209
0210 static const struct sa1100fb_rgb def_rgb_16 = {
0211 .red = { .offset = 11, .length = 5, },
0212 .green = { .offset = 5, .length = 6, },
0213 .blue = { .offset = 0, .length = 5, },
0214 .transp = { .offset = 0, .length = 0, },
0215 };
0216
0217
0218
0219 static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);
0220 static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);
0221
0222 static inline void sa1100fb_schedule_work(struct sa1100fb_info *fbi, u_int state)
0223 {
0224 unsigned long flags;
0225
0226 local_irq_save(flags);
0227
0228
0229
0230
0231
0232
0233
0234
0235 if (fbi->task_state == C_ENABLE && state == C_REENABLE)
0236 state = (u_int) -1;
0237 if (fbi->task_state == C_DISABLE && state == C_ENABLE)
0238 state = C_REENABLE;
0239
0240 if (state != (u_int)-1) {
0241 fbi->task_state = state;
0242 schedule_work(&fbi->task);
0243 }
0244 local_irq_restore(flags);
0245 }
0246
0247 static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
0248 {
0249 chan &= 0xffff;
0250 chan >>= 16 - bf->length;
0251 return chan << bf->offset;
0252 }
0253
0254
0255
0256
0257 static inline u_int palette_pbs(struct fb_var_screeninfo *var)
0258 {
0259 int ret = 0;
0260 switch (var->bits_per_pixel) {
0261 case 4: ret = 0 << 12; break;
0262 case 8: ret = 1 << 12; break;
0263 case 16: ret = 2 << 12; break;
0264 }
0265 return ret;
0266 }
0267
0268 static int
0269 sa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
0270 u_int trans, struct fb_info *info)
0271 {
0272 struct sa1100fb_info *fbi =
0273 container_of(info, struct sa1100fb_info, fb);
0274 u_int val, ret = 1;
0275
0276 if (regno < fbi->palette_size) {
0277 val = ((red >> 4) & 0xf00);
0278 val |= ((green >> 8) & 0x0f0);
0279 val |= ((blue >> 12) & 0x00f);
0280
0281 if (regno == 0)
0282 val |= palette_pbs(&fbi->fb.var);
0283
0284 fbi->palette_cpu[regno] = val;
0285 ret = 0;
0286 }
0287 return ret;
0288 }
0289
0290 static int
0291 sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
0292 u_int trans, struct fb_info *info)
0293 {
0294 struct sa1100fb_info *fbi =
0295 container_of(info, struct sa1100fb_info, fb);
0296 unsigned int val;
0297 int ret = 1;
0298
0299
0300
0301
0302
0303
0304
0305 if (fbi->inf->cmap_inverse) {
0306 red = 0xffff - red;
0307 green = 0xffff - green;
0308 blue = 0xffff - blue;
0309 }
0310
0311
0312
0313
0314
0315 if (fbi->fb.var.grayscale)
0316 red = green = blue = (19595 * red + 38470 * green +
0317 7471 * blue) >> 16;
0318
0319 switch (fbi->fb.fix.visual) {
0320 case FB_VISUAL_TRUECOLOR:
0321
0322
0323
0324
0325 if (regno < 16) {
0326 val = chan_to_field(red, &fbi->fb.var.red);
0327 val |= chan_to_field(green, &fbi->fb.var.green);
0328 val |= chan_to_field(blue, &fbi->fb.var.blue);
0329
0330 fbi->pseudo_palette[regno] = val;
0331 ret = 0;
0332 }
0333 break;
0334
0335 case FB_VISUAL_STATIC_PSEUDOCOLOR:
0336 case FB_VISUAL_PSEUDOCOLOR:
0337 ret = sa1100fb_setpalettereg(regno, red, green, blue, trans, info);
0338 break;
0339 }
0340
0341 return ret;
0342 }
0343
0344 #ifdef CONFIG_CPU_FREQ
0345
0346
0347
0348
0349
0350
0351 static inline unsigned int sa1100fb_display_dma_period(struct fb_var_screeninfo *var)
0352 {
0353
0354
0355
0356
0357 return var->pixclock * 8 * 16 / var->bits_per_pixel;
0358 }
0359 #endif
0360
0361
0362
0363
0364
0365
0366
0367 static int
0368 sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
0369 {
0370 struct sa1100fb_info *fbi =
0371 container_of(info, struct sa1100fb_info, fb);
0372 int rgbidx;
0373
0374 if (var->xres < MIN_XRES)
0375 var->xres = MIN_XRES;
0376 if (var->yres < MIN_YRES)
0377 var->yres = MIN_YRES;
0378 if (var->xres > fbi->inf->xres)
0379 var->xres = fbi->inf->xres;
0380 if (var->yres > fbi->inf->yres)
0381 var->yres = fbi->inf->yres;
0382 var->xres_virtual = max(var->xres_virtual, var->xres);
0383 var->yres_virtual = max(var->yres_virtual, var->yres);
0384
0385 dev_dbg(fbi->dev, "var->bits_per_pixel=%d\n", var->bits_per_pixel);
0386 switch (var->bits_per_pixel) {
0387 case 4:
0388 rgbidx = RGB_4;
0389 break;
0390 case 8:
0391 rgbidx = RGB_8;
0392 break;
0393 case 16:
0394 rgbidx = RGB_16;
0395 break;
0396 default:
0397 return -EINVAL;
0398 }
0399
0400
0401
0402
0403
0404 var->red = fbi->rgb[rgbidx]->red;
0405 var->green = fbi->rgb[rgbidx]->green;
0406 var->blue = fbi->rgb[rgbidx]->blue;
0407 var->transp = fbi->rgb[rgbidx]->transp;
0408
0409 dev_dbg(fbi->dev, "RGBT length = %d:%d:%d:%d\n",
0410 var->red.length, var->green.length, var->blue.length,
0411 var->transp.length);
0412
0413 dev_dbg(fbi->dev, "RGBT offset = %d:%d:%d:%d\n",
0414 var->red.offset, var->green.offset, var->blue.offset,
0415 var->transp.offset);
0416
0417 #ifdef CONFIG_CPU_FREQ
0418 dev_dbg(fbi->dev, "dma period = %d ps, clock = %ld kHz\n",
0419 sa1100fb_display_dma_period(var),
0420 clk_get_rate(fbi->clk) / 1000);
0421 #endif
0422
0423 return 0;
0424 }
0425
0426 static void sa1100fb_set_visual(struct sa1100fb_info *fbi, u32 visual)
0427 {
0428 if (fbi->inf->set_visual)
0429 fbi->inf->set_visual(visual);
0430 }
0431
0432
0433
0434
0435
0436 static int sa1100fb_set_par(struct fb_info *info)
0437 {
0438 struct sa1100fb_info *fbi =
0439 container_of(info, struct sa1100fb_info, fb);
0440 struct fb_var_screeninfo *var = &info->var;
0441 unsigned long palette_mem_size;
0442
0443 dev_dbg(fbi->dev, "set_par\n");
0444
0445 if (var->bits_per_pixel == 16)
0446 fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
0447 else if (!fbi->inf->cmap_static)
0448 fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
0449 else {
0450
0451
0452
0453
0454
0455 fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
0456 }
0457
0458 fbi->fb.fix.line_length = var->xres_virtual *
0459 var->bits_per_pixel / 8;
0460 fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
0461
0462 palette_mem_size = fbi->palette_size * sizeof(u16);
0463
0464 dev_dbg(fbi->dev, "palette_mem_size = 0x%08lx\n", palette_mem_size);
0465
0466 fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
0467 fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
0468
0469
0470
0471
0472 sa1100fb_set_visual(fbi, fbi->fb.fix.visual);
0473 sa1100fb_activate_var(var, fbi);
0474
0475 return 0;
0476 }
0477
0478 #if 0
0479 static int
0480 sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
0481 struct fb_info *info)
0482 {
0483 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
0484
0485
0486
0487
0488 if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->inf->cmap_static))
0489 return -EINVAL;
0490
0491 return gen_set_cmap(cmap, kspc, con, info);
0492 }
0493 #endif
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530 static int sa1100fb_blank(int blank, struct fb_info *info)
0531 {
0532 struct sa1100fb_info *fbi =
0533 container_of(info, struct sa1100fb_info, fb);
0534 int i;
0535
0536 dev_dbg(fbi->dev, "sa1100fb_blank: blank=%d\n", blank);
0537
0538 switch (blank) {
0539 case FB_BLANK_POWERDOWN:
0540 case FB_BLANK_VSYNC_SUSPEND:
0541 case FB_BLANK_HSYNC_SUSPEND:
0542 case FB_BLANK_NORMAL:
0543 if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
0544 fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
0545 for (i = 0; i < fbi->palette_size; i++)
0546 sa1100fb_setpalettereg(i, 0, 0, 0, 0, info);
0547 sa1100fb_schedule_work(fbi, C_DISABLE);
0548 break;
0549
0550 case FB_BLANK_UNBLANK:
0551 if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
0552 fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
0553 fb_set_cmap(&fbi->fb.cmap, info);
0554 sa1100fb_schedule_work(fbi, C_ENABLE);
0555 }
0556 return 0;
0557 }
0558
0559 static int sa1100fb_mmap(struct fb_info *info,
0560 struct vm_area_struct *vma)
0561 {
0562 struct sa1100fb_info *fbi =
0563 container_of(info, struct sa1100fb_info, fb);
0564 unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
0565
0566 if (off < info->fix.smem_len) {
0567 vma->vm_pgoff += 1;
0568 return dma_mmap_wc(fbi->dev, vma, fbi->map_cpu, fbi->map_dma,
0569 fbi->map_size);
0570 }
0571
0572 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
0573
0574 return vm_iomap_memory(vma, info->fix.mmio_start, info->fix.mmio_len);
0575 }
0576
0577 static const struct fb_ops sa1100fb_ops = {
0578 .owner = THIS_MODULE,
0579 .fb_check_var = sa1100fb_check_var,
0580 .fb_set_par = sa1100fb_set_par,
0581
0582 .fb_setcolreg = sa1100fb_setcolreg,
0583 .fb_fillrect = cfb_fillrect,
0584 .fb_copyarea = cfb_copyarea,
0585 .fb_imageblit = cfb_imageblit,
0586 .fb_blank = sa1100fb_blank,
0587 .fb_mmap = sa1100fb_mmap,
0588 };
0589
0590
0591
0592
0593
0594 static inline unsigned int get_pcd(struct sa1100fb_info *fbi,
0595 unsigned int pixclock)
0596 {
0597 unsigned int pcd = clk_get_rate(fbi->clk) / 100 / 1000;
0598
0599 pcd *= pixclock;
0600 pcd /= 10000000;
0601
0602 return pcd + 1;
0603 }
0604
0605
0606
0607
0608
0609
0610 static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
0611 {
0612 struct sa1100fb_lcd_reg new_regs;
0613 u_int half_screen_size, yres, pcd;
0614 u_long flags;
0615
0616 dev_dbg(fbi->dev, "Configuring SA1100 LCD\n");
0617
0618 dev_dbg(fbi->dev, "var: xres=%d hslen=%d lm=%d rm=%d\n",
0619 var->xres, var->hsync_len,
0620 var->left_margin, var->right_margin);
0621 dev_dbg(fbi->dev, "var: yres=%d vslen=%d um=%d bm=%d\n",
0622 var->yres, var->vsync_len,
0623 var->upper_margin, var->lower_margin);
0624
0625 #if DEBUG_VAR
0626 if (var->xres < 16 || var->xres > 1024)
0627 dev_err(fbi->dev, "%s: invalid xres %d\n",
0628 fbi->fb.fix.id, var->xres);
0629 if (var->hsync_len < 1 || var->hsync_len > 64)
0630 dev_err(fbi->dev, "%s: invalid hsync_len %d\n",
0631 fbi->fb.fix.id, var->hsync_len);
0632 if (var->left_margin < 1 || var->left_margin > 255)
0633 dev_err(fbi->dev, "%s: invalid left_margin %d\n",
0634 fbi->fb.fix.id, var->left_margin);
0635 if (var->right_margin < 1 || var->right_margin > 255)
0636 dev_err(fbi->dev, "%s: invalid right_margin %d\n",
0637 fbi->fb.fix.id, var->right_margin);
0638 if (var->yres < 1 || var->yres > 1024)
0639 dev_err(fbi->dev, "%s: invalid yres %d\n",
0640 fbi->fb.fix.id, var->yres);
0641 if (var->vsync_len < 1 || var->vsync_len > 64)
0642 dev_err(fbi->dev, "%s: invalid vsync_len %d\n",
0643 fbi->fb.fix.id, var->vsync_len);
0644 if (var->upper_margin < 0 || var->upper_margin > 255)
0645 dev_err(fbi->dev, "%s: invalid upper_margin %d\n",
0646 fbi->fb.fix.id, var->upper_margin);
0647 if (var->lower_margin < 0 || var->lower_margin > 255)
0648 dev_err(fbi->dev, "%s: invalid lower_margin %d\n",
0649 fbi->fb.fix.id, var->lower_margin);
0650 #endif
0651
0652 new_regs.lccr0 = fbi->inf->lccr0 |
0653 LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
0654 LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
0655
0656 new_regs.lccr1 =
0657 LCCR1_DisWdth(var->xres) +
0658 LCCR1_HorSnchWdth(var->hsync_len) +
0659 LCCR1_BegLnDel(var->left_margin) +
0660 LCCR1_EndLnDel(var->right_margin);
0661
0662
0663
0664
0665
0666 yres = var->yres;
0667 if (fbi->inf->lccr0 & LCCR0_Dual)
0668 yres /= 2;
0669
0670 new_regs.lccr2 =
0671 LCCR2_DisHght(yres) +
0672 LCCR2_VrtSnchWdth(var->vsync_len) +
0673 LCCR2_BegFrmDel(var->upper_margin) +
0674 LCCR2_EndFrmDel(var->lower_margin);
0675
0676 pcd = get_pcd(fbi, var->pixclock);
0677 new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->inf->lccr3 |
0678 (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
0679 (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
0680
0681 dev_dbg(fbi->dev, "nlccr0 = 0x%08lx\n", new_regs.lccr0);
0682 dev_dbg(fbi->dev, "nlccr1 = 0x%08lx\n", new_regs.lccr1);
0683 dev_dbg(fbi->dev, "nlccr2 = 0x%08lx\n", new_regs.lccr2);
0684 dev_dbg(fbi->dev, "nlccr3 = 0x%08lx\n", new_regs.lccr3);
0685
0686 half_screen_size = var->bits_per_pixel;
0687 half_screen_size = half_screen_size * var->xres * var->yres / 16;
0688
0689
0690 local_irq_save(flags);
0691 fbi->dbar1 = fbi->palette_dma;
0692 fbi->dbar2 = fbi->screen_dma + half_screen_size;
0693
0694 fbi->reg_lccr0 = new_regs.lccr0;
0695 fbi->reg_lccr1 = new_regs.lccr1;
0696 fbi->reg_lccr2 = new_regs.lccr2;
0697 fbi->reg_lccr3 = new_regs.lccr3;
0698 local_irq_restore(flags);
0699
0700
0701
0702
0703
0704 if (readl_relaxed(fbi->base + LCCR0) != fbi->reg_lccr0 ||
0705 readl_relaxed(fbi->base + LCCR1) != fbi->reg_lccr1 ||
0706 readl_relaxed(fbi->base + LCCR2) != fbi->reg_lccr2 ||
0707 readl_relaxed(fbi->base + LCCR3) != fbi->reg_lccr3 ||
0708 readl_relaxed(fbi->base + DBAR1) != fbi->dbar1 ||
0709 readl_relaxed(fbi->base + DBAR2) != fbi->dbar2)
0710 sa1100fb_schedule_work(fbi, C_REENABLE);
0711
0712 return 0;
0713 }
0714
0715
0716
0717
0718
0719
0720
0721 static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on)
0722 {
0723 dev_dbg(fbi->dev, "backlight o%s\n", on ? "n" : "ff");
0724
0725 if (fbi->inf->backlight_power)
0726 fbi->inf->backlight_power(on);
0727 }
0728
0729 static inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on)
0730 {
0731 dev_dbg(fbi->dev, "LCD power o%s\n", on ? "n" : "ff");
0732
0733 if (fbi->inf->lcd_power)
0734 fbi->inf->lcd_power(on);
0735 }
0736
0737 static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
0738 {
0739 u_int mask = 0;
0740
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753 if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color &&
0754 (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) {
0755 mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
0756
0757 if (fbi->fb.var.bits_per_pixel > 8 ||
0758 (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual)
0759 mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12;
0760
0761 }
0762
0763 if (mask) {
0764 unsigned long flags;
0765
0766
0767
0768
0769
0770
0771
0772
0773 local_irq_save(flags);
0774 GPDR |= mask;
0775 GAFR |= mask;
0776 local_irq_restore(flags);
0777 }
0778 }
0779
0780 static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
0781 {
0782 dev_dbg(fbi->dev, "Enabling LCD controller\n");
0783
0784
0785
0786
0787 fbi->palette_cpu[0] &= 0xcfff;
0788 fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
0789
0790
0791 clk_prepare_enable(fbi->clk);
0792
0793
0794 writel_relaxed(fbi->reg_lccr3, fbi->base + LCCR3);
0795 writel_relaxed(fbi->reg_lccr2, fbi->base + LCCR2);
0796 writel_relaxed(fbi->reg_lccr1, fbi->base + LCCR1);
0797 writel_relaxed(fbi->reg_lccr0 & ~LCCR0_LEN, fbi->base + LCCR0);
0798 writel_relaxed(fbi->dbar1, fbi->base + DBAR1);
0799 writel_relaxed(fbi->dbar2, fbi->base + DBAR2);
0800 writel_relaxed(fbi->reg_lccr0 | LCCR0_LEN, fbi->base + LCCR0);
0801
0802 if (fbi->shannon_lcden)
0803 gpiod_set_value(fbi->shannon_lcden, 1);
0804
0805 dev_dbg(fbi->dev, "DBAR1: 0x%08x\n", readl_relaxed(fbi->base + DBAR1));
0806 dev_dbg(fbi->dev, "DBAR2: 0x%08x\n", readl_relaxed(fbi->base + DBAR2));
0807 dev_dbg(fbi->dev, "LCCR0: 0x%08x\n", readl_relaxed(fbi->base + LCCR0));
0808 dev_dbg(fbi->dev, "LCCR1: 0x%08x\n", readl_relaxed(fbi->base + LCCR1));
0809 dev_dbg(fbi->dev, "LCCR2: 0x%08x\n", readl_relaxed(fbi->base + LCCR2));
0810 dev_dbg(fbi->dev, "LCCR3: 0x%08x\n", readl_relaxed(fbi->base + LCCR3));
0811 }
0812
0813 static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
0814 {
0815 DECLARE_WAITQUEUE(wait, current);
0816 u32 lccr0;
0817
0818 dev_dbg(fbi->dev, "Disabling LCD controller\n");
0819
0820 if (fbi->shannon_lcden)
0821 gpiod_set_value(fbi->shannon_lcden, 0);
0822
0823 set_current_state(TASK_UNINTERRUPTIBLE);
0824 add_wait_queue(&fbi->ctrlr_wait, &wait);
0825
0826
0827 writel_relaxed(~0, fbi->base + LCSR);
0828
0829 lccr0 = readl_relaxed(fbi->base + LCCR0);
0830 lccr0 &= ~LCCR0_LDM;
0831 writel_relaxed(lccr0, fbi->base + LCCR0);
0832 lccr0 &= ~LCCR0_LEN;
0833 writel_relaxed(lccr0, fbi->base + LCCR0);
0834
0835 schedule_timeout(20 * HZ / 1000);
0836 remove_wait_queue(&fbi->ctrlr_wait, &wait);
0837
0838
0839 clk_disable_unprepare(fbi->clk);
0840 }
0841
0842
0843
0844
0845 static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id)
0846 {
0847 struct sa1100fb_info *fbi = dev_id;
0848 unsigned int lcsr = readl_relaxed(fbi->base + LCSR);
0849
0850 if (lcsr & LCSR_LDD) {
0851 u32 lccr0 = readl_relaxed(fbi->base + LCCR0) | LCCR0_LDM;
0852 writel_relaxed(lccr0, fbi->base + LCCR0);
0853 wake_up(&fbi->ctrlr_wait);
0854 }
0855
0856 writel_relaxed(lcsr, fbi->base + LCSR);
0857 return IRQ_HANDLED;
0858 }
0859
0860
0861
0862
0863
0864
0865 static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
0866 {
0867 u_int old_state;
0868
0869 mutex_lock(&fbi->ctrlr_lock);
0870
0871 old_state = fbi->state;
0872
0873
0874
0875
0876 if (old_state == C_STARTUP && state == C_REENABLE)
0877 state = C_ENABLE;
0878
0879 switch (state) {
0880 case C_DISABLE_CLKCHANGE:
0881
0882
0883
0884
0885 if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
0886 fbi->state = state;
0887 sa1100fb_disable_controller(fbi);
0888 }
0889 break;
0890
0891 case C_DISABLE_PM:
0892 case C_DISABLE:
0893
0894
0895
0896 if (old_state != C_DISABLE) {
0897 fbi->state = state;
0898
0899 __sa1100fb_backlight_power(fbi, 0);
0900 if (old_state != C_DISABLE_CLKCHANGE)
0901 sa1100fb_disable_controller(fbi);
0902 __sa1100fb_lcd_power(fbi, 0);
0903 }
0904 break;
0905
0906 case C_ENABLE_CLKCHANGE:
0907
0908
0909
0910
0911 if (old_state == C_DISABLE_CLKCHANGE) {
0912 fbi->state = C_ENABLE;
0913 sa1100fb_enable_controller(fbi);
0914 }
0915 break;
0916
0917 case C_REENABLE:
0918
0919
0920
0921
0922
0923 if (old_state == C_ENABLE) {
0924 sa1100fb_disable_controller(fbi);
0925 sa1100fb_setup_gpio(fbi);
0926 sa1100fb_enable_controller(fbi);
0927 }
0928 break;
0929
0930 case C_ENABLE_PM:
0931
0932
0933
0934
0935
0936 if (old_state != C_DISABLE_PM)
0937 break;
0938 fallthrough;
0939
0940 case C_ENABLE:
0941
0942
0943
0944
0945 if (old_state != C_ENABLE) {
0946 fbi->state = C_ENABLE;
0947 sa1100fb_setup_gpio(fbi);
0948 __sa1100fb_lcd_power(fbi, 1);
0949 sa1100fb_enable_controller(fbi);
0950 __sa1100fb_backlight_power(fbi, 1);
0951 }
0952 break;
0953 }
0954 mutex_unlock(&fbi->ctrlr_lock);
0955 }
0956
0957
0958
0959
0960
0961 static void sa1100fb_task(struct work_struct *w)
0962 {
0963 struct sa1100fb_info *fbi = container_of(w, struct sa1100fb_info, task);
0964 u_int state = xchg(&fbi->task_state, -1);
0965
0966 set_ctrlr_state(fbi, state);
0967 }
0968
0969 #ifdef CONFIG_CPU_FREQ
0970
0971
0972
0973
0974
0975 static int
0976 sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,
0977 void *data)
0978 {
0979 struct sa1100fb_info *fbi = TO_INF(nb, freq_transition);
0980 u_int pcd;
0981
0982 switch (val) {
0983 case CPUFREQ_PRECHANGE:
0984 set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
0985 break;
0986
0987 case CPUFREQ_POSTCHANGE:
0988 pcd = get_pcd(fbi, fbi->fb.var.pixclock);
0989 fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
0990 set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
0991 break;
0992 }
0993 return 0;
0994 }
0995 #endif
0996
0997 #ifdef CONFIG_PM
0998
0999
1000
1001
1002 static 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
1010 static 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
1030 static 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
1056 static const struct fb_monspecs monspecs = {
1057 .hfmin = 30000,
1058 .hfmax = 70000,
1059 .vfmin = 50,
1060 .vfmax = 65,
1061 };
1062
1063
1064 static 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
1143 static 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
1210 static 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
1219 int __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
1227 module_init(sa1100fb_init);
1228 MODULE_DESCRIPTION("StrongARM-1100/1110 framebuffer driver");
1229 MODULE_LICENSE("GPL");