0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/module.h>
0012 #include <linux/kernel.h>
0013 #include <linux/errno.h>
0014 #include <linux/string.h>
0015 #include <linux/delay.h>
0016 #include <linux/init.h>
0017 #include <linux/fb.h>
0018 #include <linux/mm.h>
0019 #include <linux/of_device.h>
0020 #include <linux/io.h>
0021
0022 #include <asm/fbio.h>
0023
0024 #include "sbuslib.h"
0025
0026
0027
0028
0029
0030 static int leo_setcolreg(unsigned, unsigned, unsigned, unsigned,
0031 unsigned, struct fb_info *);
0032 static int leo_blank(int, struct fb_info *);
0033
0034 static int leo_mmap(struct fb_info *, struct vm_area_struct *);
0035 static int leo_ioctl(struct fb_info *, unsigned int, unsigned long);
0036 static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *);
0037
0038
0039
0040
0041
0042 static const struct fb_ops leo_ops = {
0043 .owner = THIS_MODULE,
0044 .fb_setcolreg = leo_setcolreg,
0045 .fb_blank = leo_blank,
0046 .fb_pan_display = leo_pan_display,
0047 .fb_fillrect = cfb_fillrect,
0048 .fb_copyarea = cfb_copyarea,
0049 .fb_imageblit = cfb_imageblit,
0050 .fb_mmap = leo_mmap,
0051 .fb_ioctl = leo_ioctl,
0052 #ifdef CONFIG_COMPAT
0053 .fb_compat_ioctl = sbusfb_compat_ioctl,
0054 #endif
0055 };
0056
0057 #define LEO_OFF_LC_SS0_KRN 0x00200000UL
0058 #define LEO_OFF_LC_SS0_USR 0x00201000UL
0059 #define LEO_OFF_LC_SS1_KRN 0x01200000UL
0060 #define LEO_OFF_LC_SS1_USR 0x01201000UL
0061 #define LEO_OFF_LD_SS0 0x00400000UL
0062 #define LEO_OFF_LD_SS1 0x01400000UL
0063 #define LEO_OFF_LD_GBL 0x00401000UL
0064 #define LEO_OFF_LX_KRN 0x00600000UL
0065 #define LEO_OFF_LX_CURSOR 0x00601000UL
0066 #define LEO_OFF_SS0 0x00800000UL
0067 #define LEO_OFF_SS1 0x01800000UL
0068 #define LEO_OFF_UNK 0x00602000UL
0069 #define LEO_OFF_UNK2 0x00000000UL
0070
0071 #define LEO_CUR_ENABLE 0x00000080
0072 #define LEO_CUR_UPDATE 0x00000030
0073 #define LEO_CUR_PROGRESS 0x00000006
0074 #define LEO_CUR_UPDATECMAP 0x00000003
0075
0076 #define LEO_CUR_TYPE_MASK 0x00000000
0077 #define LEO_CUR_TYPE_IMAGE 0x00000020
0078 #define LEO_CUR_TYPE_CMAP 0x00000050
0079
0080 struct leo_cursor {
0081 u8 xxx0[16];
0082 u32 cur_type;
0083 u32 cur_misc;
0084 u32 cur_cursxy;
0085 u32 cur_data;
0086 };
0087
0088 #define LEO_KRN_TYPE_CLUT0 0x00001000
0089 #define LEO_KRN_TYPE_CLUT1 0x00001001
0090 #define LEO_KRN_TYPE_CLUT2 0x00001002
0091 #define LEO_KRN_TYPE_WID 0x00001003
0092 #define LEO_KRN_TYPE_UNK 0x00001006
0093 #define LEO_KRN_TYPE_VIDEO 0x00002003
0094 #define LEO_KRN_TYPE_CLUTDATA 0x00004000
0095 #define LEO_KRN_CSR_ENABLE 0x00000008
0096 #define LEO_KRN_CSR_PROGRESS 0x00000004
0097 #define LEO_KRN_CSR_UNK 0x00000002
0098 #define LEO_KRN_CSR_UNK2 0x00000001
0099
0100 struct leo_lx_krn {
0101 u32 krn_type;
0102 u32 krn_csr;
0103 u32 krn_value;
0104 };
0105
0106 struct leo_lc_ss0_krn {
0107 u32 misc;
0108 u8 xxx0[0x800-4];
0109 u32 rev;
0110 };
0111
0112 struct leo_lc_ss0_usr {
0113 u32 csr;
0114 u32 addrspace;
0115 u32 fontmsk;
0116 u32 fontt;
0117 u32 extent;
0118 u32 src;
0119 u32 dst;
0120 u32 copy;
0121 u32 fill;
0122 };
0123
0124 struct leo_lc_ss1_krn {
0125 u8 unknown;
0126 };
0127
0128 struct leo_lc_ss1_usr {
0129 u8 unknown;
0130 };
0131
0132 struct leo_ld_ss0 {
0133 u8 xxx0[0xe00];
0134 u32 csr;
0135 u32 wid;
0136 u32 wmask;
0137 u32 widclip;
0138 u32 vclipmin;
0139 u32 vclipmax;
0140 u32 pickmin;
0141 u32 pickmax;
0142 u32 fg;
0143 u32 bg;
0144 u32 src;
0145 u32 dst;
0146 u32 extent;
0147 u32 xxx1[3];
0148 u32 setsem;
0149 u32 clrsem;
0150 u32 clrpick;
0151 u32 clrdat;
0152 u32 alpha;
0153 u8 xxx2[0x2c];
0154 u32 winbg;
0155 u32 planemask;
0156 u32 rop;
0157 u32 z;
0158 u32 dczf;
0159 u32 dczb;
0160 u32 dcs;
0161 u32 dczs;
0162 u32 pickfb;
0163 u32 pickbb;
0164 u32 dcfc;
0165 u32 forcecol;
0166 u32 door[8];
0167 u32 pick[5];
0168 };
0169
0170 #define LEO_SS1_MISC_ENABLE 0x00000001
0171 #define LEO_SS1_MISC_STEREO 0x00000002
0172 struct leo_ld_ss1 {
0173 u8 xxx0[0xef4];
0174 u32 ss1_misc;
0175 };
0176
0177 struct leo_ld_gbl {
0178 u8 unknown;
0179 };
0180
0181 struct leo_par {
0182 spinlock_t lock;
0183 struct leo_lx_krn __iomem *lx_krn;
0184 struct leo_lc_ss0_usr __iomem *lc_ss0_usr;
0185 struct leo_ld_ss0 __iomem *ld_ss0;
0186 struct leo_ld_ss1 __iomem *ld_ss1;
0187 struct leo_cursor __iomem *cursor;
0188 u32 extent;
0189 u32 clut_data[256];
0190
0191 u32 flags;
0192 #define LEO_FLAG_BLANKED 0x00000001
0193
0194 unsigned long which_io;
0195 };
0196
0197 static void leo_wait(struct leo_lx_krn __iomem *lx_krn)
0198 {
0199 int i;
0200
0201 for (i = 0;
0202 (sbus_readl(&lx_krn->krn_csr) & LEO_KRN_CSR_PROGRESS) &&
0203 i < 300000;
0204 i++)
0205 udelay(1);
0206 return;
0207 }
0208
0209 static void leo_switch_from_graph(struct fb_info *info)
0210 {
0211 struct leo_par *par = (struct leo_par *) info->par;
0212 struct leo_ld_ss0 __iomem *ss = par->ld_ss0;
0213 struct leo_cursor __iomem *cursor = par->cursor;
0214 unsigned long flags;
0215 u32 val;
0216
0217 spin_lock_irqsave(&par->lock, flags);
0218
0219 par->extent = ((info->var.xres - 1) |
0220 ((info->var.yres - 1) << 16));
0221
0222 sbus_writel(0xffffffff, &ss->wid);
0223 sbus_writel(0xffff, &ss->wmask);
0224 sbus_writel(0, &ss->vclipmin);
0225 sbus_writel(par->extent, &ss->vclipmax);
0226 sbus_writel(0, &ss->fg);
0227 sbus_writel(0xff000000, &ss->planemask);
0228 sbus_writel(0x310850, &ss->rop);
0229 sbus_writel(0, &ss->widclip);
0230 sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11),
0231 &par->lc_ss0_usr->extent);
0232 sbus_writel(4, &par->lc_ss0_usr->addrspace);
0233 sbus_writel(0x80000000, &par->lc_ss0_usr->fill);
0234 sbus_writel(0, &par->lc_ss0_usr->fontt);
0235 do {
0236 val = sbus_readl(&par->lc_ss0_usr->csr);
0237 } while (val & 0x20000000);
0238
0239
0240 sbus_writel(1, &ss->wid);
0241 sbus_writel(0x00ffffff, &ss->planemask);
0242 sbus_writel(0x310b90, &ss->rop);
0243 sbus_writel(0, &par->lc_ss0_usr->addrspace);
0244
0245
0246 sbus_writel(sbus_readl(&cursor->cur_misc) & ~LEO_CUR_ENABLE, &cursor->cur_misc);
0247
0248 spin_unlock_irqrestore(&par->lock, flags);
0249 }
0250
0251 static int leo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
0252 {
0253
0254
0255
0256 leo_switch_from_graph(info);
0257
0258 if (var->xoffset || var->yoffset || var->vmode)
0259 return -EINVAL;
0260 return 0;
0261 }
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272 static int leo_setcolreg(unsigned regno,
0273 unsigned red, unsigned green, unsigned blue,
0274 unsigned transp, struct fb_info *info)
0275 {
0276 struct leo_par *par = (struct leo_par *) info->par;
0277 struct leo_lx_krn __iomem *lx_krn = par->lx_krn;
0278 unsigned long flags;
0279 u32 val;
0280 int i;
0281
0282 if (regno >= 256)
0283 return 1;
0284
0285 red >>= 8;
0286 green >>= 8;
0287 blue >>= 8;
0288
0289 par->clut_data[regno] = red | (green << 8) | (blue << 16);
0290
0291 spin_lock_irqsave(&par->lock, flags);
0292
0293 leo_wait(lx_krn);
0294
0295 sbus_writel(LEO_KRN_TYPE_CLUTDATA, &lx_krn->krn_type);
0296 for (i = 0; i < 256; i++)
0297 sbus_writel(par->clut_data[i], &lx_krn->krn_value);
0298 sbus_writel(LEO_KRN_TYPE_CLUT0, &lx_krn->krn_type);
0299
0300 val = sbus_readl(&lx_krn->krn_csr);
0301 val |= (LEO_KRN_CSR_UNK | LEO_KRN_CSR_UNK2);
0302 sbus_writel(val, &lx_krn->krn_csr);
0303
0304 spin_unlock_irqrestore(&par->lock, flags);
0305
0306 return 0;
0307 }
0308
0309
0310
0311
0312
0313
0314 static int leo_blank(int blank, struct fb_info *info)
0315 {
0316 struct leo_par *par = (struct leo_par *) info->par;
0317 struct leo_lx_krn __iomem *lx_krn = par->lx_krn;
0318 unsigned long flags;
0319 u32 val;
0320
0321 spin_lock_irqsave(&par->lock, flags);
0322
0323 switch (blank) {
0324 case FB_BLANK_UNBLANK:
0325 val = sbus_readl(&lx_krn->krn_csr);
0326 val |= LEO_KRN_CSR_ENABLE;
0327 sbus_writel(val, &lx_krn->krn_csr);
0328 par->flags &= ~LEO_FLAG_BLANKED;
0329 break;
0330
0331 case FB_BLANK_NORMAL:
0332 case FB_BLANK_VSYNC_SUSPEND:
0333 case FB_BLANK_HSYNC_SUSPEND:
0334 case FB_BLANK_POWERDOWN:
0335 val = sbus_readl(&lx_krn->krn_csr);
0336 val &= ~LEO_KRN_CSR_ENABLE;
0337 sbus_writel(val, &lx_krn->krn_csr);
0338 par->flags |= LEO_FLAG_BLANKED;
0339 break;
0340 }
0341
0342 spin_unlock_irqrestore(&par->lock, flags);
0343
0344 return 0;
0345 }
0346
0347 static struct sbus_mmap_map leo_mmap_map[] = {
0348 {
0349 .voff = LEO_SS0_MAP,
0350 .poff = LEO_OFF_SS0,
0351 .size = 0x800000
0352 },
0353 {
0354 .voff = LEO_LC_SS0_USR_MAP,
0355 .poff = LEO_OFF_LC_SS0_USR,
0356 .size = 0x1000
0357 },
0358 {
0359 .voff = LEO_LD_SS0_MAP,
0360 .poff = LEO_OFF_LD_SS0,
0361 .size = 0x1000
0362 },
0363 {
0364 .voff = LEO_LX_CURSOR_MAP,
0365 .poff = LEO_OFF_LX_CURSOR,
0366 .size = 0x1000
0367 },
0368 {
0369 .voff = LEO_SS1_MAP,
0370 .poff = LEO_OFF_SS1,
0371 .size = 0x800000
0372 },
0373 {
0374 .voff = LEO_LC_SS1_USR_MAP,
0375 .poff = LEO_OFF_LC_SS1_USR,
0376 .size = 0x1000
0377 },
0378 {
0379 .voff = LEO_LD_SS1_MAP,
0380 .poff = LEO_OFF_LD_SS1,
0381 .size = 0x1000
0382 },
0383 {
0384 .voff = LEO_UNK_MAP,
0385 .poff = LEO_OFF_UNK,
0386 .size = 0x1000
0387 },
0388 {
0389 .voff = LEO_LX_KRN_MAP,
0390 .poff = LEO_OFF_LX_KRN,
0391 .size = 0x1000
0392 },
0393 {
0394 .voff = LEO_LC_SS0_KRN_MAP,
0395 .poff = LEO_OFF_LC_SS0_KRN,
0396 .size = 0x1000
0397 },
0398 {
0399 .voff = LEO_LC_SS1_KRN_MAP,
0400 .poff = LEO_OFF_LC_SS1_KRN,
0401 .size = 0x1000
0402 },
0403 {
0404 .voff = LEO_LD_GBL_MAP,
0405 .poff = LEO_OFF_LD_GBL,
0406 .size = 0x1000
0407 },
0408 {
0409 .voff = LEO_UNK2_MAP,
0410 .poff = LEO_OFF_UNK2,
0411 .size = 0x100000
0412 },
0413 { .size = 0 }
0414 };
0415
0416 static int leo_mmap(struct fb_info *info, struct vm_area_struct *vma)
0417 {
0418 struct leo_par *par = (struct leo_par *)info->par;
0419
0420 return sbusfb_mmap_helper(leo_mmap_map,
0421 info->fix.smem_start, info->fix.smem_len,
0422 par->which_io, vma);
0423 }
0424
0425 static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
0426 {
0427 return sbusfb_ioctl_helper(cmd, arg, info,
0428 FBTYPE_SUNLEO, 32, info->fix.smem_len);
0429 }
0430
0431
0432
0433
0434
0435 static void
0436 leo_init_fix(struct fb_info *info, struct device_node *dp)
0437 {
0438 snprintf(info->fix.id, sizeof(info->fix.id), "%pOFn", dp);
0439
0440 info->fix.type = FB_TYPE_PACKED_PIXELS;
0441 info->fix.visual = FB_VISUAL_TRUECOLOR;
0442
0443 info->fix.line_length = 8192;
0444
0445 info->fix.accel = FB_ACCEL_SUN_LEO;
0446 }
0447
0448 static void leo_wid_put(struct fb_info *info, struct fb_wid_list *wl)
0449 {
0450 struct leo_par *par = (struct leo_par *) info->par;
0451 struct leo_lx_krn __iomem *lx_krn = par->lx_krn;
0452 struct fb_wid_item *wi;
0453 unsigned long flags;
0454 u32 val;
0455 int i, j;
0456
0457 spin_lock_irqsave(&par->lock, flags);
0458
0459 leo_wait(lx_krn);
0460
0461 for (i = 0, wi = wl->wl_list; i < wl->wl_count; i++, wi++) {
0462 switch (wi->wi_type) {
0463 case FB_WID_DBL_8:
0464 j = (wi->wi_index & 0xf) + 0x40;
0465 break;
0466
0467 case FB_WID_DBL_24:
0468 j = wi->wi_index & 0x3f;
0469 break;
0470
0471 default:
0472 continue;
0473 }
0474 sbus_writel(0x5800 + j, &lx_krn->krn_type);
0475 sbus_writel(wi->wi_values[0], &lx_krn->krn_value);
0476 }
0477 sbus_writel(LEO_KRN_TYPE_WID, &lx_krn->krn_type);
0478
0479 val = sbus_readl(&lx_krn->krn_csr);
0480 val |= (LEO_KRN_CSR_UNK | LEO_KRN_CSR_UNK2);
0481 sbus_writel(val, &lx_krn->krn_csr);
0482
0483 spin_unlock_irqrestore(&par->lock, flags);
0484 }
0485
0486 static void leo_init_wids(struct fb_info *info)
0487 {
0488 struct fb_wid_item wi;
0489 struct fb_wid_list wl;
0490
0491 wl.wl_count = 1;
0492 wl.wl_list = &wi;
0493 wi.wi_type = FB_WID_DBL_8;
0494 wi.wi_index = 0;
0495 wi.wi_values [0] = 0x2c0;
0496 leo_wid_put(info, &wl);
0497 wi.wi_index = 1;
0498 wi.wi_values [0] = 0x30;
0499 leo_wid_put(info, &wl);
0500 wi.wi_index = 2;
0501 wi.wi_values [0] = 0x20;
0502 leo_wid_put(info, &wl);
0503 wi.wi_type = FB_WID_DBL_24;
0504 wi.wi_index = 1;
0505 wi.wi_values [0] = 0x30;
0506 leo_wid_put(info, &wl);
0507 }
0508
0509 static void leo_init_hw(struct fb_info *info)
0510 {
0511 struct leo_par *par = (struct leo_par *) info->par;
0512 u32 val;
0513
0514 val = sbus_readl(&par->ld_ss1->ss1_misc);
0515 val |= LEO_SS1_MISC_ENABLE;
0516 sbus_writel(val, &par->ld_ss1->ss1_misc);
0517
0518 leo_switch_from_graph(info);
0519 }
0520
0521 static void leo_fixup_var_rgb(struct fb_var_screeninfo *var)
0522 {
0523 var->red.offset = 0;
0524 var->red.length = 8;
0525 var->green.offset = 8;
0526 var->green.length = 8;
0527 var->blue.offset = 16;
0528 var->blue.length = 8;
0529 var->transp.offset = 0;
0530 var->transp.length = 0;
0531 }
0532
0533 static void leo_unmap_regs(struct platform_device *op, struct fb_info *info,
0534 struct leo_par *par)
0535 {
0536 if (par->lc_ss0_usr)
0537 of_iounmap(&op->resource[0], par->lc_ss0_usr, 0x1000);
0538 if (par->ld_ss0)
0539 of_iounmap(&op->resource[0], par->ld_ss0, 0x1000);
0540 if (par->ld_ss1)
0541 of_iounmap(&op->resource[0], par->ld_ss1, 0x1000);
0542 if (par->lx_krn)
0543 of_iounmap(&op->resource[0], par->lx_krn, 0x1000);
0544 if (par->cursor)
0545 of_iounmap(&op->resource[0],
0546 par->cursor, sizeof(struct leo_cursor));
0547 if (info->screen_base)
0548 of_iounmap(&op->resource[0], info->screen_base, 0x800000);
0549 }
0550
0551 static int leo_probe(struct platform_device *op)
0552 {
0553 struct device_node *dp = op->dev.of_node;
0554 struct fb_info *info;
0555 struct leo_par *par;
0556 int linebytes, err;
0557
0558 info = framebuffer_alloc(sizeof(struct leo_par), &op->dev);
0559
0560 err = -ENOMEM;
0561 if (!info)
0562 goto out_err;
0563 par = info->par;
0564
0565 spin_lock_init(&par->lock);
0566
0567 info->fix.smem_start = op->resource[0].start;
0568 par->which_io = op->resource[0].flags & IORESOURCE_BITS;
0569
0570 sbusfb_fill_var(&info->var, dp, 32);
0571 leo_fixup_var_rgb(&info->var);
0572
0573 linebytes = of_getintprop_default(dp, "linebytes",
0574 info->var.xres);
0575 info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
0576
0577 par->lc_ss0_usr =
0578 of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR,
0579 0x1000, "leolc ss0usr");
0580 par->ld_ss0 =
0581 of_ioremap(&op->resource[0], LEO_OFF_LD_SS0,
0582 0x1000, "leold ss0");
0583 par->ld_ss1 =
0584 of_ioremap(&op->resource[0], LEO_OFF_LD_SS1,
0585 0x1000, "leold ss1");
0586 par->lx_krn =
0587 of_ioremap(&op->resource[0], LEO_OFF_LX_KRN,
0588 0x1000, "leolx krn");
0589 par->cursor =
0590 of_ioremap(&op->resource[0], LEO_OFF_LX_CURSOR,
0591 sizeof(struct leo_cursor), "leolx cursor");
0592 info->screen_base =
0593 of_ioremap(&op->resource[0], LEO_OFF_SS0,
0594 0x800000, "leo ram");
0595 if (!par->lc_ss0_usr ||
0596 !par->ld_ss0 ||
0597 !par->ld_ss1 ||
0598 !par->lx_krn ||
0599 !par->cursor ||
0600 !info->screen_base)
0601 goto out_unmap_regs;
0602
0603 info->flags = FBINFO_DEFAULT;
0604 info->fbops = &leo_ops;
0605 info->pseudo_palette = par->clut_data;
0606
0607 leo_init_wids(info);
0608 leo_init_hw(info);
0609
0610 leo_blank(FB_BLANK_UNBLANK, info);
0611
0612 if (fb_alloc_cmap(&info->cmap, 256, 0))
0613 goto out_unmap_regs;
0614
0615 leo_init_fix(info, dp);
0616
0617 err = register_framebuffer(info);
0618 if (err < 0)
0619 goto out_dealloc_cmap;
0620
0621 dev_set_drvdata(&op->dev, info);
0622
0623 printk(KERN_INFO "%pOF: leo at %lx:%lx\n",
0624 dp,
0625 par->which_io, info->fix.smem_start);
0626
0627 return 0;
0628
0629 out_dealloc_cmap:
0630 fb_dealloc_cmap(&info->cmap);
0631
0632 out_unmap_regs:
0633 leo_unmap_regs(op, info, par);
0634 framebuffer_release(info);
0635
0636 out_err:
0637 return err;
0638 }
0639
0640 static int leo_remove(struct platform_device *op)
0641 {
0642 struct fb_info *info = dev_get_drvdata(&op->dev);
0643 struct leo_par *par = info->par;
0644
0645 unregister_framebuffer(info);
0646 fb_dealloc_cmap(&info->cmap);
0647
0648 leo_unmap_regs(op, info, par);
0649
0650 framebuffer_release(info);
0651
0652 return 0;
0653 }
0654
0655 static const struct of_device_id leo_match[] = {
0656 {
0657 .name = "SUNW,leo",
0658 },
0659 {},
0660 };
0661 MODULE_DEVICE_TABLE(of, leo_match);
0662
0663 static struct platform_driver leo_driver = {
0664 .driver = {
0665 .name = "leo",
0666 .of_match_table = leo_match,
0667 },
0668 .probe = leo_probe,
0669 .remove = leo_remove,
0670 };
0671
0672 static int __init leo_init(void)
0673 {
0674 if (fb_get_options("leofb", NULL))
0675 return -ENODEV;
0676
0677 return platform_driver_register(&leo_driver);
0678 }
0679
0680 static void __exit leo_exit(void)
0681 {
0682 platform_driver_unregister(&leo_driver);
0683 }
0684
0685 module_init(leo_init);
0686 module_exit(leo_exit);
0687
0688 MODULE_DESCRIPTION("framebuffer driver for LEO chipsets");
0689 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
0690 MODULE_VERSION("2.0");
0691 MODULE_LICENSE("GPL");