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