1 // SPDX-License-Identifier: GPL-2.0-only 2 /* leo.c: LEO frame buffer driver 3 * 4 * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) 5 * Copyright (C) 1996-1999 Jakub Jelinek (jj@ultra.linux.cz) 6 * Copyright (C) 1997 Michal Rehacek (Michal.Rehacek@st.mff.cuni.cz) 7 * 8 * Driver layout based loosely on tgafb.c, see that file for credits. 9 */ 10 11 #include <linux/module.h> 12 #include <linux/kernel.h> 13 #include <linux/errno.h> 14 #include <linux/string.h> 15 #include <linux/delay.h> 16 #include <linux/init.h> 17 #include <linux/fb.h> 18 #include <linux/mm.h> 19 #include <linux/io.h> 20 #include <linux/of.h> 21 #include <linux/platform_device.h> 22 23 #include <asm/fbio.h> 24 25 #include "sbuslib.h" 26 27 /* 28 * Local functions. 29 */ 30 31 static int leo_setcolreg(unsigned, unsigned, unsigned, unsigned, 32 unsigned, struct fb_info *); 33 static int leo_blank(int, struct fb_info *); 34 static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *); 35 36 static int leo_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma); 37 static int leo_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); 38 39 /* 40 * Frame buffer operations 41 */ 42 43 static const struct fb_ops leo_ops = { 44 .owner = THIS_MODULE, 45 FB_DEFAULT_SBUS_OPS(leo), 46 .fb_setcolreg = leo_setcolreg, 47 .fb_blank = leo_blank, 48 .fb_pan_display = leo_pan_display, 49 }; 50 51 #define LEO_OFF_LC_SS0_KRN 0x00200000UL 52 #define LEO_OFF_LC_SS0_USR 0x00201000UL 53 #define LEO_OFF_LC_SS1_KRN 0x01200000UL 54 #define LEO_OFF_LC_SS1_USR 0x01201000UL 55 #define LEO_OFF_LD_SS0 0x00400000UL 56 #define LEO_OFF_LD_SS1 0x01400000UL 57 #define LEO_OFF_LD_GBL 0x00401000UL 58 #define LEO_OFF_LX_KRN 0x00600000UL 59 #define LEO_OFF_LX_CURSOR 0x00601000UL 60 #define LEO_OFF_SS0 0x00800000UL 61 #define LEO_OFF_SS1 0x01800000UL 62 #define LEO_OFF_UNK 0x00602000UL 63 #define LEO_OFF_UNK2 0x00000000UL 64 65 #define LEO_CUR_ENABLE 0x00000080 66 #define LEO_CUR_UPDATE 0x00000030 67 #define LEO_CUR_PROGRESS 0x00000006 68 #define LEO_CUR_UPDATECMAP 0x00000003 69 70 #define LEO_CUR_TYPE_MASK 0x00000000 71 #define LEO_CUR_TYPE_IMAGE 0x00000020 72 #define LEO_CUR_TYPE_CMAP 0x00000050 73 74 struct leo_cursor { 75 u8 xxx0[16]; 76 u32 cur_type; 77 u32 cur_misc; 78 u32 cur_cursxy; 79 u32 cur_data; 80 }; 81 82 #define LEO_KRN_TYPE_CLUT0 0x00001000 83 #define LEO_KRN_TYPE_CLUT1 0x00001001 84 #define LEO_KRN_TYPE_CLUT2 0x00001002 85 #define LEO_KRN_TYPE_WID 0x00001003 86 #define LEO_KRN_TYPE_UNK 0x00001006 87 #define LEO_KRN_TYPE_VIDEO 0x00002003 88 #define LEO_KRN_TYPE_CLUTDATA 0x00004000 89 #define LEO_KRN_CSR_ENABLE 0x00000008 90 #define LEO_KRN_CSR_PROGRESS 0x00000004 91 #define LEO_KRN_CSR_UNK 0x00000002 92 #define LEO_KRN_CSR_UNK2 0x00000001 93 94 struct leo_lx_krn { 95 u32 krn_type; 96 u32 krn_csr; 97 u32 krn_value; 98 }; 99 100 struct leo_lc_ss0_krn { 101 u32 misc; 102 u8 xxx0[0x800-4]; 103 u32 rev; 104 }; 105 106 struct leo_lc_ss0_usr { 107 u32 csr; 108 u32 addrspace; 109 u32 fontmsk; 110 u32 fontt; 111 u32 extent; 112 u32 src; 113 u32 dst; 114 u32 copy; 115 u32 fill; 116 }; 117 118 struct leo_lc_ss1_krn { 119 u8 unknown; 120 }; 121 122 struct leo_lc_ss1_usr { 123 u8 unknown; 124 }; 125 126 struct leo_ld_ss0 { 127 u8 xxx0[0xe00]; 128 u32 csr; 129 u32 wid; 130 u32 wmask; 131 u32 widclip; 132 u32 vclipmin; 133 u32 vclipmax; 134 u32 pickmin; /* SS1 only */ 135 u32 pickmax; /* SS1 only */ 136 u32 fg; 137 u32 bg; 138 u32 src; /* Copy/Scroll (SS0 only) */ 139 u32 dst; /* Copy/Scroll/Fill (SS0 only) */ 140 u32 extent; /* Copy/Scroll/Fill size (SS0 only) */ 141 u32 xxx1[3]; 142 u32 setsem; /* SS1 only */ 143 u32 clrsem; /* SS1 only */ 144 u32 clrpick; /* SS1 only */ 145 u32 clrdat; /* SS1 only */ 146 u32 alpha; /* SS1 only */ 147 u8 xxx2[0x2c]; 148 u32 winbg; 149 u32 planemask; 150 u32 rop; 151 u32 z; 152 u32 dczf; /* SS1 only */ 153 u32 dczb; /* SS1 only */ 154 u32 dcs; /* SS1 only */ 155 u32 dczs; /* SS1 only */ 156 u32 pickfb; /* SS1 only */ 157 u32 pickbb; /* SS1 only */ 158 u32 dcfc; /* SS1 only */ 159 u32 forcecol; /* SS1 only */ 160 u32 door[8]; /* SS1 only */ 161 u32 pick[5]; /* SS1 only */ 162 }; 163 164 #define LEO_SS1_MISC_ENABLE 0x00000001 165 #define LEO_SS1_MISC_STEREO 0x00000002 166 struct leo_ld_ss1 { 167 u8 xxx0[0xef4]; 168 u32 ss1_misc; 169 }; 170 171 struct leo_ld_gbl { 172 u8 unknown; 173 }; 174 175 struct leo_par { 176 spinlock_t lock; 177 struct leo_lx_krn __iomem *lx_krn; 178 struct leo_lc_ss0_usr __iomem *lc_ss0_usr; 179 struct leo_ld_ss0 __iomem *ld_ss0; 180 struct leo_ld_ss1 __iomem *ld_ss1; 181 struct leo_cursor __iomem *cursor; 182 u32 extent; 183 u32 clut_data[256]; 184 185 u32 flags; 186 #define LEO_FLAG_BLANKED 0x00000001 187 188 unsigned long which_io; 189 }; 190 191 static void leo_wait(struct leo_lx_krn __iomem *lx_krn) 192 { 193 int i; 194 195 for (i = 0; 196 (sbus_readl(&lx_krn->krn_csr) & LEO_KRN_CSR_PROGRESS) && 197 i < 300000; 198 i++) 199 udelay(1); /* Busy wait at most 0.3 sec */ 200 return; 201 } 202 203 static void leo_switch_from_graph(struct fb_info *info) 204 { 205 struct leo_par *par = (struct leo_par *) info->par; 206 struct leo_ld_ss0 __iomem *ss = par->ld_ss0; 207 struct leo_cursor __iomem *cursor = par->cursor; 208 unsigned long flags; 209 u32 val; 210 211 spin_lock_irqsave(&par->lock, flags); 212 213 par->extent = ((info->var.xres - 1) | 214 ((info->var.yres - 1) << 16)); 215 216 sbus_writel(0xffffffff, &ss->wid); 217 sbus_writel(0xffff, &ss->wmask); 218 sbus_writel(0, &ss->vclipmin); 219 sbus_writel(par->extent, &ss->vclipmax); 220 sbus_writel(0, &ss->fg); 221 sbus_writel(0xff000000, &ss->planemask); 222 sbus_writel(0x310850, &ss->rop); 223 sbus_writel(0, &ss->widclip); 224 sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11), 225 &par->lc_ss0_usr->extent); 226 sbus_writel(4, &par->lc_ss0_usr->addrspace); 227 sbus_writel(0x80000000, &par->lc_ss0_usr->fill); 228 sbus_writel(0, &par->lc_ss0_usr->fontt); 229 do { 230 val = sbus_readl(&par->lc_ss0_usr->csr); 231 } while (val & 0x20000000); 232 233 /* setup screen buffer for cfb_* functions */ 234 sbus_writel(1, &ss->wid); 235 sbus_writel(0x00ffffff, &ss->planemask); 236 sbus_writel(0x310b90, &ss->rop); 237 sbus_writel(0, &par->lc_ss0_usr->addrspace); 238 239 /* hide cursor */ 240 sbus_writel(sbus_readl(&cursor->cur_misc) & ~LEO_CUR_ENABLE, &cursor->cur_misc); 241 242 spin_unlock_irqrestore(&par->lock, flags); 243 } 244 245 static int leo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) 246 { 247 /* We just use this to catch switches out of 248 * graphics mode. 249 */ 250 leo_switch_from_graph(info); 251 252 if (var->xoffset || var->yoffset || var->vmode) 253 return -EINVAL; 254 return 0; 255 } 256 257 /** 258 * leo_setcolreg - Optional function. Sets a color register. 259 * @regno: boolean, 0 copy local, 1 get_user() function 260 * @red: frame buffer colormap structure 261 * @green: The green value which can be up to 16 bits wide 262 * @blue: The blue value which can be up to 16 bits wide. 263 * @transp: If supported the alpha value which can be up to 16 bits wide. 264 * @info: frame buffer info structure 265 */ 266 static int leo_setcolreg(unsigned regno, 267 unsigned red, unsigned green, unsigned blue, 268 unsigned transp, struct fb_info *info) 269 { 270 struct leo_par *par = (struct leo_par *) info->par; 271 struct leo_lx_krn __iomem *lx_krn = par->lx_krn; 272 unsigned long flags; 273 u32 val; 274 int i; 275 276 if (regno >= 256) 277 return 1; 278 279 red >>= 8; 280 green >>= 8; 281 blue >>= 8; 282 283 par->clut_data[regno] = red | (green << 8) | (blue << 16); 284 285 spin_lock_irqsave(&par->lock, flags); 286 287 leo_wait(lx_krn); 288 289 sbus_writel(LEO_KRN_TYPE_CLUTDATA, &lx_krn->krn_type); 290 for (i = 0; i < 256; i++) 291 sbus_writel(par->clut_data[i], &lx_krn->krn_value); 292 sbus_writel(LEO_KRN_TYPE_CLUT0, &lx_krn->krn_type); 293 294 val = sbus_readl(&lx_krn->krn_csr); 295 val |= (LEO_KRN_CSR_UNK | LEO_KRN_CSR_UNK2); 296 sbus_writel(val, &lx_krn->krn_csr); 297 298 spin_unlock_irqrestore(&par->lock, flags); 299 300 return 0; 301 } 302 303 /** 304 * leo_blank - Optional function. Blanks the display. 305 * @blank: the blank mode we want. 306 * @info: frame buffer structure that represents a single frame buffer 307 */ 308 static int leo_blank(int blank, struct fb_info *info) 309 { 310 struct leo_par *par = (struct leo_par *) info->par; 311 struct leo_lx_krn __iomem *lx_krn = par->lx_krn; 312 unsigned long flags; 313 u32 val; 314 315 spin_lock_irqsave(&par->lock, flags); 316 317 switch (blank) { 318 case FB_BLANK_UNBLANK: /* Unblanking */ 319 val = sbus_readl(&lx_krn->krn_csr); 320 val |= LEO_KRN_CSR_ENABLE; 321 sbus_writel(val, &lx_krn->krn_csr); 322 par->flags &= ~LEO_FLAG_BLANKED; 323 break; 324 325 case FB_BLANK_NORMAL: /* Normal blanking */ 326 case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ 327 case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ 328 case FB_BLANK_POWERDOWN: /* Poweroff */ 329 val = sbus_readl(&lx_krn->krn_csr); 330 val &= ~LEO_KRN_CSR_ENABLE; 331 sbus_writel(val, &lx_krn->krn_csr); 332 par->flags |= LEO_FLAG_BLANKED; 333 break; 334 } 335 336 spin_unlock_irqrestore(&par->lock, flags); 337 338 return 0; 339 } 340 341 static const struct sbus_mmap_map leo_mmap_map[] = { 342 { 343 .voff = LEO_SS0_MAP, 344 .poff = LEO_OFF_SS0, 345 .size = 0x800000 346 }, 347 { 348 .voff = LEO_LC_SS0_USR_MAP, 349 .poff = LEO_OFF_LC_SS0_USR, 350 .size = 0x1000 351 }, 352 { 353 .voff = LEO_LD_SS0_MAP, 354 .poff = LEO_OFF_LD_SS0, 355 .size = 0x1000 356 }, 357 { 358 .voff = LEO_LX_CURSOR_MAP, 359 .poff = LEO_OFF_LX_CURSOR, 360 .size = 0x1000 361 }, 362 { 363 .voff = LEO_SS1_MAP, 364 .poff = LEO_OFF_SS1, 365 .size = 0x800000 366 }, 367 { 368 .voff = LEO_LC_SS1_USR_MAP, 369 .poff = LEO_OFF_LC_SS1_USR, 370 .size = 0x1000 371 }, 372 { 373 .voff = LEO_LD_SS1_MAP, 374 .poff = LEO_OFF_LD_SS1, 375 .size = 0x1000 376 }, 377 { 378 .voff = LEO_UNK_MAP, 379 .poff = LEO_OFF_UNK, 380 .size = 0x1000 381 }, 382 { 383 .voff = LEO_LX_KRN_MAP, 384 .poff = LEO_OFF_LX_KRN, 385 .size = 0x1000 386 }, 387 { 388 .voff = LEO_LC_SS0_KRN_MAP, 389 .poff = LEO_OFF_LC_SS0_KRN, 390 .size = 0x1000 391 }, 392 { 393 .voff = LEO_LC_SS1_KRN_MAP, 394 .poff = LEO_OFF_LC_SS1_KRN, 395 .size = 0x1000 396 }, 397 { 398 .voff = LEO_LD_GBL_MAP, 399 .poff = LEO_OFF_LD_GBL, 400 .size = 0x1000 401 }, 402 { 403 .voff = LEO_UNK2_MAP, 404 .poff = LEO_OFF_UNK2, 405 .size = 0x100000 406 }, 407 { .size = 0 } 408 }; 409 410 static int leo_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma) 411 { 412 struct leo_par *par = (struct leo_par *)info->par; 413 414 return sbusfb_mmap_helper(leo_mmap_map, 415 info->fix.smem_start, info->fix.smem_len, 416 par->which_io, vma); 417 } 418 419 static int leo_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) 420 { 421 return sbusfb_ioctl_helper(cmd, arg, info, 422 FBTYPE_SUNLEO, 32, info->fix.smem_len); 423 } 424 425 /* 426 * Initialisation 427 */ 428 429 static void 430 leo_init_fix(struct fb_info *info, struct device_node *dp) 431 { 432 snprintf(info->fix.id, sizeof(info->fix.id), "%pOFn", dp); 433 434 info->fix.type = FB_TYPE_PACKED_PIXELS; 435 info->fix.visual = FB_VISUAL_TRUECOLOR; 436 437 info->fix.line_length = 8192; 438 439 info->fix.accel = FB_ACCEL_SUN_LEO; 440 } 441 442 static void leo_wid_put(struct fb_info *info, struct fb_wid_list *wl) 443 { 444 struct leo_par *par = (struct leo_par *) info->par; 445 struct leo_lx_krn __iomem *lx_krn = par->lx_krn; 446 struct fb_wid_item *wi; 447 unsigned long flags; 448 u32 val; 449 int i, j; 450 451 spin_lock_irqsave(&par->lock, flags); 452 453 leo_wait(lx_krn); 454 455 for (i = 0, wi = wl->wl_list; i < wl->wl_count; i++, wi++) { 456 switch (wi->wi_type) { 457 case FB_WID_DBL_8: 458 j = (wi->wi_index & 0xf) + 0x40; 459 break; 460 461 case FB_WID_DBL_24: 462 j = wi->wi_index & 0x3f; 463 break; 464 465 default: 466 continue; 467 } 468 sbus_writel(0x5800 + j, &lx_krn->krn_type); 469 sbus_writel(wi->wi_values[0], &lx_krn->krn_value); 470 } 471 sbus_writel(LEO_KRN_TYPE_WID, &lx_krn->krn_type); 472 473 val = sbus_readl(&lx_krn->krn_csr); 474 val |= (LEO_KRN_CSR_UNK | LEO_KRN_CSR_UNK2); 475 sbus_writel(val, &lx_krn->krn_csr); 476 477 spin_unlock_irqrestore(&par->lock, flags); 478 } 479 480 static void leo_init_wids(struct fb_info *info) 481 { 482 struct fb_wid_item wi; 483 struct fb_wid_list wl; 484 485 wl.wl_count = 1; 486 wl.wl_list = &wi; 487 wi.wi_type = FB_WID_DBL_8; 488 wi.wi_index = 0; 489 wi.wi_values [0] = 0x2c0; 490 leo_wid_put(info, &wl); 491 wi.wi_index = 1; 492 wi.wi_values [0] = 0x30; 493 leo_wid_put(info, &wl); 494 wi.wi_index = 2; 495 wi.wi_values [0] = 0x20; 496 leo_wid_put(info, &wl); 497 wi.wi_type = FB_WID_DBL_24; 498 wi.wi_index = 1; 499 wi.wi_values [0] = 0x30; 500 leo_wid_put(info, &wl); 501 } 502 503 static void leo_init_hw(struct fb_info *info) 504 { 505 struct leo_par *par = (struct leo_par *) info->par; 506 u32 val; 507 508 val = sbus_readl(&par->ld_ss1->ss1_misc); 509 val |= LEO_SS1_MISC_ENABLE; 510 sbus_writel(val, &par->ld_ss1->ss1_misc); 511 512 leo_switch_from_graph(info); 513 } 514 515 static void leo_fixup_var_rgb(struct fb_var_screeninfo *var) 516 { 517 var->red.offset = 0; 518 var->red.length = 8; 519 var->green.offset = 8; 520 var->green.length = 8; 521 var->blue.offset = 16; 522 var->blue.length = 8; 523 var->transp.offset = 0; 524 var->transp.length = 0; 525 } 526 527 static void leo_unmap_regs(struct platform_device *op, struct fb_info *info, 528 struct leo_par *par) 529 { 530 if (par->lc_ss0_usr) 531 of_iounmap(&op->resource[0], par->lc_ss0_usr, 0x1000); 532 if (par->ld_ss0) 533 of_iounmap(&op->resource[0], par->ld_ss0, 0x1000); 534 if (par->ld_ss1) 535 of_iounmap(&op->resource[0], par->ld_ss1, 0x1000); 536 if (par->lx_krn) 537 of_iounmap(&op->resource[0], par->lx_krn, 0x1000); 538 if (par->cursor) 539 of_iounmap(&op->resource[0], 540 par->cursor, sizeof(struct leo_cursor)); 541 if (info->screen_base) 542 of_iounmap(&op->resource[0], info->screen_base, 0x800000); 543 } 544 545 static int leo_probe(struct platform_device *op) 546 { 547 struct device_node *dp = op->dev.of_node; 548 struct fb_info *info; 549 struct leo_par *par; 550 int linebytes, err; 551 552 info = framebuffer_alloc(sizeof(struct leo_par), &op->dev); 553 554 err = -ENOMEM; 555 if (!info) 556 goto out_err; 557 par = info->par; 558 559 spin_lock_init(&par->lock); 560 561 info->fix.smem_start = op->resource[0].start; 562 par->which_io = op->resource[0].flags & IORESOURCE_BITS; 563 564 sbusfb_fill_var(&info->var, dp, 32); 565 leo_fixup_var_rgb(&info->var); 566 567 linebytes = of_getintprop_default(dp, "linebytes", 568 info->var.xres); 569 info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); 570 571 par->lc_ss0_usr = 572 of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR, 573 0x1000, "leolc ss0usr"); 574 par->ld_ss0 = 575 of_ioremap(&op->resource[0], LEO_OFF_LD_SS0, 576 0x1000, "leold ss0"); 577 par->ld_ss1 = 578 of_ioremap(&op->resource[0], LEO_OFF_LD_SS1, 579 0x1000, "leold ss1"); 580 par->lx_krn = 581 of_ioremap(&op->resource[0], LEO_OFF_LX_KRN, 582 0x1000, "leolx krn"); 583 par->cursor = 584 of_ioremap(&op->resource[0], LEO_OFF_LX_CURSOR, 585 sizeof(struct leo_cursor), "leolx cursor"); 586 info->screen_base = 587 of_ioremap(&op->resource[0], LEO_OFF_SS0, 588 0x800000, "leo ram"); 589 if (!par->lc_ss0_usr || 590 !par->ld_ss0 || 591 !par->ld_ss1 || 592 !par->lx_krn || 593 !par->cursor || 594 !info->screen_base) 595 goto out_unmap_regs; 596 597 info->fbops = &leo_ops; 598 info->pseudo_palette = par->clut_data; 599 600 leo_init_wids(info); 601 leo_init_hw(info); 602 603 leo_blank(FB_BLANK_UNBLANK, info); 604 605 if (fb_alloc_cmap(&info->cmap, 256, 0)) 606 goto out_unmap_regs; 607 608 leo_init_fix(info, dp); 609 610 err = register_framebuffer(info); 611 if (err < 0) 612 goto out_dealloc_cmap; 613 614 dev_set_drvdata(&op->dev, info); 615 616 printk(KERN_INFO "%pOF: leo at %lx:%lx\n", 617 dp, 618 par->which_io, info->fix.smem_start); 619 620 return 0; 621 622 out_dealloc_cmap: 623 fb_dealloc_cmap(&info->cmap); 624 625 out_unmap_regs: 626 leo_unmap_regs(op, info, par); 627 framebuffer_release(info); 628 629 out_err: 630 return err; 631 } 632 633 static void leo_remove(struct platform_device *op) 634 { 635 struct fb_info *info = dev_get_drvdata(&op->dev); 636 struct leo_par *par = info->par; 637 638 unregister_framebuffer(info); 639 fb_dealloc_cmap(&info->cmap); 640 641 leo_unmap_regs(op, info, par); 642 643 framebuffer_release(info); 644 } 645 646 static const struct of_device_id leo_match[] = { 647 { 648 .name = "SUNW,leo", 649 }, 650 {}, 651 }; 652 MODULE_DEVICE_TABLE(of, leo_match); 653 654 static struct platform_driver leo_driver = { 655 .driver = { 656 .name = "leo", 657 .of_match_table = leo_match, 658 }, 659 .probe = leo_probe, 660 .remove = leo_remove, 661 }; 662 663 static int __init leo_init(void) 664 { 665 if (fb_get_options("leofb", NULL)) 666 return -ENODEV; 667 668 return platform_driver_register(&leo_driver); 669 } 670 671 static void __exit leo_exit(void) 672 { 673 platform_driver_unregister(&leo_driver); 674 } 675 676 module_init(leo_init); 677 module_exit(leo_exit); 678 679 MODULE_DESCRIPTION("framebuffer driver for LEO chipsets"); 680 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); 681 MODULE_VERSION("2.0"); 682 MODULE_LICENSE("GPL"); 683