PageRenderTime 53ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/staging/sm750fb/sm750_hw.c

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