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