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