sm750_hw.c (14303B)
1// SPDX-License-Identifier: GPL-2.0 2#include <linux/module.h> 3#include <linux/kernel.h> 4#include <linux/errno.h> 5#include <linux/string.h> 6#include <linux/mm.h> 7#include <linux/slab.h> 8#include <linux/delay.h> 9#include <linux/fb.h> 10#include <linux/ioport.h> 11#include <linux/init.h> 12#include <linux/pci.h> 13#include <linux/vmalloc.h> 14#include <linux/pagemap.h> 15#include <linux/console.h> 16#ifdef CONFIG_MTRR 17#include <asm/mtrr.h> 18#endif 19#include <linux/platform_device.h> 20#include <linux/screen_info.h> 21#include <linux/sizes.h> 22 23#include "sm750.h" 24#include "ddk750.h" 25#include "sm750_accel.h" 26 27void __iomem *mmio750; 28 29int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev) 30{ 31 int ret; 32 33 ret = 0; 34 35 sm750_dev->vidreg_start = pci_resource_start(pdev, 1); 36 sm750_dev->vidreg_size = SZ_2M; 37 38 pr_info("mmio phyAddr = %lx\n", sm750_dev->vidreg_start); 39 40 /* 41 * reserve the vidreg space of smi adaptor 42 * if you do this, you need to add release region code 43 * in lynxfb_remove, or memory will not be mapped again 44 * successfully 45 */ 46 ret = pci_request_region(pdev, 1, "sm750fb"); 47 if (ret) { 48 pr_err("Can not request PCI regions.\n"); 49 goto exit; 50 } 51 52 /* now map mmio and vidmem */ 53 sm750_dev->pvReg = 54 ioremap(sm750_dev->vidreg_start, sm750_dev->vidreg_size); 55 if (!sm750_dev->pvReg) { 56 pr_err("mmio failed\n"); 57 ret = -EFAULT; 58 goto exit; 59 } else { 60 pr_info("mmio virtual addr = %p\n", sm750_dev->pvReg); 61 } 62 63 sm750_dev->accel.dprBase = sm750_dev->pvReg + DE_BASE_ADDR_TYPE1; 64 sm750_dev->accel.dpPortBase = sm750_dev->pvReg + DE_PORT_ADDR_TYPE1; 65 66 mmio750 = sm750_dev->pvReg; 67 sm750_set_chip_type(sm750_dev->devid, sm750_dev->revid); 68 69 sm750_dev->vidmem_start = pci_resource_start(pdev, 0); 70 /* 71 * don't use pdev_resource[x].end - resource[x].start to 72 * calculate the resource size, it's only the maximum available 73 * size but not the actual size, using 74 * @ddk750_get_vm_size function can be safe. 75 */ 76 sm750_dev->vidmem_size = ddk750_get_vm_size(); 77 pr_info("video memory phyAddr = %lx, size = %u bytes\n", 78 sm750_dev->vidmem_start, sm750_dev->vidmem_size); 79 80 /* reserve the vidmem space of smi adaptor */ 81 sm750_dev->pvMem = 82 ioremap_wc(sm750_dev->vidmem_start, sm750_dev->vidmem_size); 83 if (!sm750_dev->pvMem) { 84 iounmap(sm750_dev->pvReg); 85 pr_err("Map video memory failed\n"); 86 ret = -EFAULT; 87 goto exit; 88 } else { 89 pr_info("video memory vaddr = %p\n", sm750_dev->pvMem); 90 } 91exit: 92 return ret; 93} 94 95int hw_sm750_inithw(struct sm750_dev *sm750_dev, struct pci_dev *pdev) 96{ 97 struct init_status *parm; 98 99 parm = &sm750_dev->initParm; 100 if (parm->chip_clk == 0) 101 parm->chip_clk = (sm750_get_chip_type() == SM750LE) ? 102 DEFAULT_SM750LE_CHIP_CLOCK : 103 DEFAULT_SM750_CHIP_CLOCK; 104 105 if (parm->mem_clk == 0) 106 parm->mem_clk = parm->chip_clk; 107 if (parm->master_clk == 0) 108 parm->master_clk = parm->chip_clk / 3; 109 110 ddk750_init_hw((struct initchip_param *)&sm750_dev->initParm); 111 /* for sm718, open pci burst */ 112 if (sm750_dev->devid == 0x718) { 113 poke32(SYSTEM_CTRL, 114 peek32(SYSTEM_CTRL) | SYSTEM_CTRL_PCI_BURST); 115 } 116 117 if (sm750_get_chip_type() != SM750LE) { 118 unsigned int val; 119 /* does user need CRT? */ 120 if (sm750_dev->nocrt) { 121 poke32(MISC_CTRL, 122 peek32(MISC_CTRL) | MISC_CTRL_DAC_POWER_OFF); 123 /* shut off dpms */ 124 val = peek32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK; 125 val |= SYSTEM_CTRL_DPMS_VPHN; 126 poke32(SYSTEM_CTRL, val); 127 } else { 128 poke32(MISC_CTRL, 129 peek32(MISC_CTRL) & ~MISC_CTRL_DAC_POWER_OFF); 130 /* turn on dpms */ 131 val = peek32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK; 132 val |= SYSTEM_CTRL_DPMS_VPHP; 133 poke32(SYSTEM_CTRL, val); 134 } 135 136 val = peek32(PANEL_DISPLAY_CTRL) & 137 ~(PANEL_DISPLAY_CTRL_DUAL_DISPLAY | 138 PANEL_DISPLAY_CTRL_DOUBLE_PIXEL); 139 switch (sm750_dev->pnltype) { 140 case sm750_24TFT: 141 break; 142 case sm750_doubleTFT: 143 val |= PANEL_DISPLAY_CTRL_DOUBLE_PIXEL; 144 break; 145 case sm750_dualTFT: 146 val |= PANEL_DISPLAY_CTRL_DUAL_DISPLAY; 147 break; 148 } 149 poke32(PANEL_DISPLAY_CTRL, val); 150 } else { 151 /* 152 * for 750LE, no DVI chip initialization 153 * makes Monitor no signal 154 * 155 * Set up GPIO for software I2C to program DVI chip in the 156 * Xilinx SP605 board, in order to have video signal. 157 */ 158 sm750_sw_i2c_init(0, 1); 159 160 /* 161 * Customer may NOT use CH7301 DVI chip, which has to be 162 * initialized differently. 163 */ 164 if (sm750_sw_i2c_read_reg(0xec, 0x4a) == 0x95) { 165 /* 166 * The following register values for CH7301 are from 167 * Chrontel app note and our experiment. 168 */ 169 pr_info("yes,CH7301 DVI chip found\n"); 170 sm750_sw_i2c_write_reg(0xec, 0x1d, 0x16); 171 sm750_sw_i2c_write_reg(0xec, 0x21, 0x9); 172 sm750_sw_i2c_write_reg(0xec, 0x49, 0xC0); 173 pr_info("okay,CH7301 DVI chip setup done\n"); 174 } 175 } 176 177 /* init 2d engine */ 178 if (!sm750_dev->accel_off) 179 hw_sm750_initAccel(sm750_dev); 180 181 return 0; 182} 183 184int hw_sm750_output_setMode(struct lynxfb_output *output, 185 struct fb_var_screeninfo *var, 186 struct fb_fix_screeninfo *fix) 187{ 188 int ret; 189 enum disp_output disp_set; 190 int channel; 191 192 ret = 0; 193 disp_set = 0; 194 channel = *output->channel; 195 196 if (sm750_get_chip_type() != SM750LE) { 197 if (channel == sm750_primary) { 198 pr_info("primary channel\n"); 199 if (output->paths & sm750_panel) 200 disp_set |= do_LCD1_PRI; 201 if (output->paths & sm750_crt) 202 disp_set |= do_CRT_PRI; 203 204 } else { 205 pr_info("secondary channel\n"); 206 if (output->paths & sm750_panel) 207 disp_set |= do_LCD1_SEC; 208 if (output->paths & sm750_crt) 209 disp_set |= do_CRT_SEC; 210 } 211 ddk750_set_logical_disp_out(disp_set); 212 } else { 213 /* just open DISPLAY_CONTROL_750LE register bit 3:0 */ 214 u32 reg; 215 216 reg = peek32(DISPLAY_CONTROL_750LE); 217 reg |= 0xf; 218 poke32(DISPLAY_CONTROL_750LE, reg); 219 } 220 221 pr_info("ddk setlogicdispout done\n"); 222 return ret; 223} 224 225int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc, 226 struct fb_var_screeninfo *var) 227{ 228 struct sm750_dev *sm750_dev; 229 struct lynxfb_par *par = container_of(crtc, struct lynxfb_par, crtc); 230 231 sm750_dev = par->dev; 232 233 switch (var->bits_per_pixel) { 234 case 8: 235 case 16: 236 break; 237 case 32: 238 if (sm750_dev->revid == SM750LE_REVISION_ID) { 239 pr_debug("750le do not support 32bpp\n"); 240 return -EINVAL; 241 } 242 break; 243 default: 244 return -EINVAL; 245 } 246 247 return 0; 248} 249 250/* set the controller's mode for @crtc charged with @var and @fix parameters */ 251int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc, 252 struct fb_var_screeninfo *var, 253 struct fb_fix_screeninfo *fix) 254{ 255 int ret, fmt; 256 u32 reg; 257 struct mode_parameter modparm; 258 enum clock_type clock; 259 struct sm750_dev *sm750_dev; 260 struct lynxfb_par *par; 261 262 ret = 0; 263 par = container_of(crtc, struct lynxfb_par, crtc); 264 sm750_dev = par->dev; 265 266 if (!sm750_dev->accel_off) { 267 /* set 2d engine pixel format according to mode bpp */ 268 switch (var->bits_per_pixel) { 269 case 8: 270 fmt = 0; 271 break; 272 case 16: 273 fmt = 1; 274 break; 275 case 32: 276 default: 277 fmt = 2; 278 break; 279 } 280 sm750_hw_set2dformat(&sm750_dev->accel, fmt); 281 } 282 283 /* set timing */ 284 modparm.pixel_clock = ps_to_hz(var->pixclock); 285 modparm.vertical_sync_polarity = 286 (var->sync & FB_SYNC_HOR_HIGH_ACT) ? POS : NEG; 287 modparm.horizontal_sync_polarity = 288 (var->sync & FB_SYNC_VERT_HIGH_ACT) ? POS : NEG; 289 modparm.clock_phase_polarity = 290 (var->sync & FB_SYNC_COMP_HIGH_ACT) ? POS : NEG; 291 modparm.horizontal_display_end = var->xres; 292 modparm.horizontal_sync_width = var->hsync_len; 293 modparm.horizontal_sync_start = var->xres + var->right_margin; 294 modparm.horizontal_total = var->xres + var->left_margin + 295 var->right_margin + var->hsync_len; 296 modparm.vertical_display_end = var->yres; 297 modparm.vertical_sync_height = var->vsync_len; 298 modparm.vertical_sync_start = var->yres + var->lower_margin; 299 modparm.vertical_total = var->yres + var->upper_margin + 300 var->lower_margin + var->vsync_len; 301 302 /* choose pll */ 303 if (crtc->channel != sm750_secondary) 304 clock = PRIMARY_PLL; 305 else 306 clock = SECONDARY_PLL; 307 308 pr_debug("Request pixel clock = %lu\n", modparm.pixel_clock); 309 ret = ddk750_setModeTiming(&modparm, clock); 310 if (ret) { 311 pr_err("Set mode timing failed\n"); 312 goto exit; 313 } 314 315 if (crtc->channel != sm750_secondary) { 316 /* set pitch, offset, width, start address, etc... */ 317 poke32(PANEL_FB_ADDRESS, 318 crtc->o_screen & PANEL_FB_ADDRESS_ADDRESS_MASK); 319 320 reg = var->xres * (var->bits_per_pixel >> 3); 321 /* 322 * crtc->channel is not equal to par->index on numeric, 323 * be aware of that 324 */ 325 reg = ALIGN(reg, crtc->line_pad); 326 reg = (reg << PANEL_FB_WIDTH_WIDTH_SHIFT) & 327 PANEL_FB_WIDTH_WIDTH_MASK; 328 reg |= (fix->line_length & PANEL_FB_WIDTH_OFFSET_MASK); 329 poke32(PANEL_FB_WIDTH, reg); 330 331 reg = ((var->xres - 1) << PANEL_WINDOW_WIDTH_WIDTH_SHIFT) & 332 PANEL_WINDOW_WIDTH_WIDTH_MASK; 333 reg |= (var->xoffset & PANEL_WINDOW_WIDTH_X_MASK); 334 poke32(PANEL_WINDOW_WIDTH, reg); 335 336 reg = (var->yres_virtual - 1) 337 << PANEL_WINDOW_HEIGHT_HEIGHT_SHIFT; 338 reg &= PANEL_WINDOW_HEIGHT_HEIGHT_MASK; 339 reg |= (var->yoffset & PANEL_WINDOW_HEIGHT_Y_MASK); 340 poke32(PANEL_WINDOW_HEIGHT, reg); 341 342 poke32(PANEL_PLANE_TL, 0); 343 344 reg = ((var->yres - 1) << PANEL_PLANE_BR_BOTTOM_SHIFT) & 345 PANEL_PLANE_BR_BOTTOM_MASK; 346 reg |= ((var->xres - 1) & PANEL_PLANE_BR_RIGHT_MASK); 347 poke32(PANEL_PLANE_BR, reg); 348 349 /* set pixel format */ 350 reg = peek32(PANEL_DISPLAY_CTRL); 351 poke32(PANEL_DISPLAY_CTRL, reg | (var->bits_per_pixel >> 4)); 352 } else { 353 /* not implemented now */ 354 poke32(CRT_FB_ADDRESS, crtc->o_screen); 355 reg = var->xres * (var->bits_per_pixel >> 3); 356 /* 357 * crtc->channel is not equal to par->index on numeric, 358 * be aware of that 359 */ 360 reg = ALIGN(reg, crtc->line_pad) << CRT_FB_WIDTH_WIDTH_SHIFT; 361 reg &= CRT_FB_WIDTH_WIDTH_MASK; 362 reg |= (fix->line_length & CRT_FB_WIDTH_OFFSET_MASK); 363 poke32(CRT_FB_WIDTH, reg); 364 365 /* SET PIXEL FORMAT */ 366 reg = peek32(CRT_DISPLAY_CTRL); 367 reg |= ((var->bits_per_pixel >> 4) & 368 CRT_DISPLAY_CTRL_FORMAT_MASK); 369 poke32(CRT_DISPLAY_CTRL, reg); 370 } 371 372exit: 373 return ret; 374} 375 376int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index, ushort red, 377 ushort green, ushort blue) 378{ 379 static unsigned int add[] = { PANEL_PALETTE_RAM, CRT_PALETTE_RAM }; 380 381 poke32(add[crtc->channel] + index * 4, 382 (red << 16) | (green << 8) | blue); 383 return 0; 384} 385 386int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank) 387{ 388 int dpms, crtdb; 389 390 switch (blank) { 391 case FB_BLANK_UNBLANK: 392 dpms = CRT_DISPLAY_CTRL_DPMS_0; 393 crtdb = 0; 394 break; 395 case FB_BLANK_NORMAL: 396 dpms = CRT_DISPLAY_CTRL_DPMS_0; 397 crtdb = CRT_DISPLAY_CTRL_BLANK; 398 break; 399 case FB_BLANK_VSYNC_SUSPEND: 400 dpms = CRT_DISPLAY_CTRL_DPMS_2; 401 crtdb = CRT_DISPLAY_CTRL_BLANK; 402 break; 403 case FB_BLANK_HSYNC_SUSPEND: 404 dpms = CRT_DISPLAY_CTRL_DPMS_1; 405 crtdb = CRT_DISPLAY_CTRL_BLANK; 406 break; 407 case FB_BLANK_POWERDOWN: 408 dpms = CRT_DISPLAY_CTRL_DPMS_3; 409 crtdb = CRT_DISPLAY_CTRL_BLANK; 410 break; 411 default: 412 return -EINVAL; 413 } 414 415 if (output->paths & sm750_crt) { 416 unsigned int val; 417 418 val = peek32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_DPMS_MASK; 419 poke32(CRT_DISPLAY_CTRL, val | dpms); 420 421 val = peek32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK; 422 poke32(CRT_DISPLAY_CTRL, val | crtdb); 423 } 424 return 0; 425} 426 427int hw_sm750_setBLANK(struct lynxfb_output *output, int blank) 428{ 429 unsigned int dpms, pps, crtdb; 430 431 dpms = 0; 432 pps = 0; 433 crtdb = 0; 434 435 switch (blank) { 436 case FB_BLANK_UNBLANK: 437 pr_debug("flag = FB_BLANK_UNBLANK\n"); 438 dpms = SYSTEM_CTRL_DPMS_VPHP; 439 pps = PANEL_DISPLAY_CTRL_DATA; 440 break; 441 case FB_BLANK_NORMAL: 442 pr_debug("flag = FB_BLANK_NORMAL\n"); 443 dpms = SYSTEM_CTRL_DPMS_VPHP; 444 crtdb = CRT_DISPLAY_CTRL_BLANK; 445 break; 446 case FB_BLANK_VSYNC_SUSPEND: 447 dpms = SYSTEM_CTRL_DPMS_VNHP; 448 crtdb = CRT_DISPLAY_CTRL_BLANK; 449 break; 450 case FB_BLANK_HSYNC_SUSPEND: 451 dpms = SYSTEM_CTRL_DPMS_VPHN; 452 crtdb = CRT_DISPLAY_CTRL_BLANK; 453 break; 454 case FB_BLANK_POWERDOWN: 455 dpms = SYSTEM_CTRL_DPMS_VNHN; 456 crtdb = CRT_DISPLAY_CTRL_BLANK; 457 break; 458 } 459 460 if (output->paths & sm750_crt) { 461 unsigned int val = peek32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK; 462 463 poke32(SYSTEM_CTRL, val | dpms); 464 465 val = peek32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK; 466 poke32(CRT_DISPLAY_CTRL, val | crtdb); 467 } 468 469 if (output->paths & sm750_panel) { 470 unsigned int val = peek32(PANEL_DISPLAY_CTRL); 471 472 val &= ~PANEL_DISPLAY_CTRL_DATA; 473 val |= pps; 474 poke32(PANEL_DISPLAY_CTRL, val); 475 } 476 477 return 0; 478} 479 480void hw_sm750_initAccel(struct sm750_dev *sm750_dev) 481{ 482 u32 reg; 483 484 sm750_enable_2d_engine(1); 485 486 if (sm750_get_chip_type() == SM750LE) { 487 reg = peek32(DE_STATE1); 488 reg |= DE_STATE1_DE_ABORT; 489 poke32(DE_STATE1, reg); 490 491 reg = peek32(DE_STATE1); 492 reg &= ~DE_STATE1_DE_ABORT; 493 poke32(DE_STATE1, reg); 494 495 } else { 496 /* engine reset */ 497 reg = peek32(SYSTEM_CTRL); 498 reg |= SYSTEM_CTRL_DE_ABORT; 499 poke32(SYSTEM_CTRL, reg); 500 501 reg = peek32(SYSTEM_CTRL); 502 reg &= ~SYSTEM_CTRL_DE_ABORT; 503 poke32(SYSTEM_CTRL, reg); 504 } 505 506 /* call 2d init */ 507 sm750_dev->accel.de_init(&sm750_dev->accel); 508} 509 510int hw_sm750le_deWait(void) 511{ 512 int i = 0x10000000; 513 unsigned int mask = DE_STATE2_DE_STATUS_BUSY | DE_STATE2_DE_FIFO_EMPTY | 514 DE_STATE2_DE_MEM_FIFO_EMPTY; 515 516 while (i--) { 517 unsigned int val = peek32(DE_STATE2); 518 519 if ((val & mask) == 520 (DE_STATE2_DE_FIFO_EMPTY | DE_STATE2_DE_MEM_FIFO_EMPTY)) 521 return 0; 522 } 523 /* timeout error */ 524 return -1; 525} 526 527int hw_sm750_deWait(void) 528{ 529 int i = 0x10000000; 530 unsigned int mask = SYSTEM_CTRL_DE_STATUS_BUSY | 531 SYSTEM_CTRL_DE_FIFO_EMPTY | 532 SYSTEM_CTRL_DE_MEM_FIFO_EMPTY; 533 534 while (i--) { 535 unsigned int val = peek32(SYSTEM_CTRL); 536 537 if ((val & mask) == 538 (SYSTEM_CTRL_DE_FIFO_EMPTY | SYSTEM_CTRL_DE_MEM_FIFO_EMPTY)) 539 return 0; 540 } 541 /* timeout error */ 542 return -1; 543} 544 545int hw_sm750_pan_display(struct lynxfb_crtc *crtc, 546 const struct fb_var_screeninfo *var, 547 const struct fb_info *info) 548{ 549 u32 total; 550 /* check params */ 551 if ((var->xoffset + var->xres > var->xres_virtual) || 552 (var->yoffset + var->yres > var->yres_virtual)) { 553 return -EINVAL; 554 } 555 556 total = var->yoffset * info->fix.line_length + 557 ((var->xoffset * var->bits_per_pixel) >> 3); 558 total += crtc->o_screen; 559 if (crtc->channel == sm750_primary) { 560 poke32(PANEL_FB_ADDRESS, 561 peek32(PANEL_FB_ADDRESS) | 562 (total & PANEL_FB_ADDRESS_ADDRESS_MASK)); 563 } else { 564 poke32(CRT_FB_ADDRESS, 565 peek32(CRT_FB_ADDRESS) | 566 (total & CRT_FB_ADDRESS_ADDRESS_MASK)); 567 } 568 return 0; 569}