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