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