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