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