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

source code of linux/drivers/staging/sm750fb/sm750_hw.c