1 /*
2  * (C) Copyright 2001-2004
3  * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
4  *
5  * (C) Copyright 2005
6  * Stefan Roese, DENX Software Engineering, sr@denx.de.
7  *
8  * (C) Copyright 2006-2007
9  * Matthias Fuchs, esd GmbH, matthias.fuchs@esd-electronics.com
10  *
11  * (C) Copyright 2009-2010
12  * Max Tretene, ACube Systems Srl. mtretene@acube-systems.com.
13  *
14  * See file CREDITS for list of people who contributed to this
15  * project.
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License as
19  * published by the Free Software Foundation; either version 2 of
20  * the License, or (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30  * MA 02111-1307 USA
31  */
32 
33 #include <common.h>
34 #include <asm/processor.h>
35 #include <command.h>
36 #include <malloc.h>
37 #include <pci.h>
38 #include <video_fb.h>
39 #include <sm501.h>
40 
41 #ifdef CONFIG_VIDEO_SM502
42 
43 DECLARE_GLOBAL_DATA_PTR;
44 
45 #define SWAP32(x)	 ((((x) & 0x000000ff) << 24) | (((x) & 0x0000ff00) << 8)|\
46 			  (((x) & 0x00ff0000) >>  8) | (((x) & 0xff000000) >> 24) )
47 
48 #ifdef CONFIG_VIDEO_SM501_8BPP
49 #define BPP	8
50 #endif
51 
52 #define read8(ptrReg)                \
53     *(volatile unsigned char *)(sm501.isaBase + ptrReg)
54 
55 #define write8(ptrReg,value) \
56     *(volatile unsigned char *)(sm501.isaBase + ptrReg) = value
57 
58 #define read16(ptrReg) \
59     (*(volatile unsigned short *)(sm501.isaBase + ptrReg))
60 
61 #define write16(ptrReg,value) \
62     (*(volatile unsigned short *)(sm501.isaBase + ptrReg) = value)
63 
64 #define read32(ptrReg) \
65     (*(volatile unsigned int *)(sm501.isaBase + ptrReg))
66 
67 #define write32(ptrReg, value) \
68     (*(volatile unsigned int *)(sm501.isaBase + ptrReg) = value)
69 
70 GraphicDevice sm501;
71 
72 #define DISPLAY_WIDTH   640
73 #define DISPLAY_HEIGHT  480
74 
75 static const SMI_REGS init_regs_640x480[] = {
76     {0x00004, SWAP32(0x00000000)},
77     /* clocks for pm0... */
78     {0x00040, SWAP32(0x0002184f)},
79     {0x00044, SWAP32(0x091a0a01)}, /* 24 MHz pixclk */
80     {0x00054, SWAP32(0x00000000)},
81     /* clocks for pm1... */
82     {0x00048, SWAP32(0x0002184f)},
83     {0x0004C, SWAP32(0x091a0a01)},
84     {0x00054, SWAP32(0x00000001)},
85     /* panel control regs... */
86     {0x80004, SWAP32(0xc428bb17)},
87     {0x8000C, SWAP32(0x00000000)},
88     {0x80010, SWAP32(0x02800280)},
89     {0x80014, SWAP32(0x02800000)},
90     {0x80018, SWAP32(0x01e00000)},
91     {0x8001C, SWAP32(0x00000000)},
92     {0x80020, SWAP32(0x01e00280)},
93     {0x80024, SWAP32(0x02fa027f)},
94     {0x80028, SWAP32(0x004a0280)},
95     {0x8002C, SWAP32(0x020c01df)},
96     {0x80030, SWAP32(0x000201e7)},
97     {0x80200, SWAP32(0x00010000)},
98     {0x00008, SWAP32(0x20000000)}, /* gpio29 is pwm0, LED_PWM */
99     {0x0000C, SWAP32(0x3f000000)}, /* gpio56 - gpio61 as flat panel data pins */
100     {0x10020, SWAP32(0x25725728)}, /* 20 kHz pwm0, 50 % duty cycle, disabled */
101     {0x80000, SWAP32(0x0f013104)}, /* panel display control: 8 bit indexed mode */
102     {0x800F0, SWAP32(0x00000000)}, /* hardware sprite off */
103     {0x80040, SWAP32(0x00000000)}, /* video layer off */
104     /* Drawing Engine...                                                    */
105     /* Contrary to what said in the datasheet the Drawing Engine registers  */
106     /* are NOT initialized to ZERO at power-up, this lead to strange visual */
107     /* bugs under Linux and AmigaOS4.1 for example                          */
108     {0x100000, 0},
109     {0x100004, 0},
110     {0x100008, 0},
111     {0x10000c, 0},
112     {0x100010, 0},
113     {0x100014, 0},
114     {0x100018, 0},
115     {0x10001c, 0},
116     {0x100020, 0},
117     {0x100024, 0},
118     {0x100028, 0},
119     {0x10002c, 0},
120     {0x100030, 0},
121     {0x100034, 0},
122     {0x100038, 0},
123     {0x10003c, 0},
124     {0x100040, 0},
125     {0x100044, 0},
126     {0x100048, 0},
127     {0x10004c, 0},
128     {0x100050, 0},
129     {0, 0}
130 };
131 
132 /*
133  * Returns SM501 register base address. First thing called in the driver.
134  */
board_video_init(void)135 unsigned int board_video_init (void)
136 {
137 	pci_dev_t devbusfn;
138 	u32 addr;
139 
140 	/*
141 	 * Is SM501 connected (ppc221/ppc231)?
142 	 */
143 	devbusfn = pci_find_device(PCI_VENDOR_SM, PCI_DEVICE_SM501, 0);
144 	if (devbusfn != -1) {
145 		pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_1, (u32 *)&addr);
146 		return (addr & 0xfffffffe);
147 	}
148 
149 	return 0;
150 }
151 
152 /*
153  * Returns SM501 framebuffer address
154  */
board_video_get_fb(void)155 unsigned int board_video_get_fb (void)
156 {
157 	pci_dev_t devbusfn;
158 	u32 addr;
159 
160 	/*
161 	 * Is SM501 connected (ppc221/ppc231)?
162 	 */
163 	devbusfn = pci_find_device(PCI_VENDOR_SM, PCI_DEVICE_SM501, 0);
164 	if (devbusfn != -1) {
165 		pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, (u32 *)&addr);
166 		addr &= 0xfffffffe;
167 #ifdef CONFIG_VIDEO_SM501_FBMEM_OFFSET
168 		addr += CONFIG_VIDEO_SM501_FBMEM_OFFSET;
169 #endif
170 		return addr;
171 	}
172 
173 	return 0;
174 }
175 
176 /*
177  * Called after initializing the SM501 and before clearing the screen.
178  */
board_validate_screen(unsigned int base)179 void board_validate_screen (unsigned int base)
180 {
181 }
182 
183 /*
184  * Return a pointer to the initialization sequence.
185  */
board_get_regs(void)186 const SMI_REGS *board_get_regs (void)
187 {
188 	return init_regs_640x480;
189 }
190 
board_get_width(void)191 int board_get_width (void)
192 {
193 	return 640;
194 }
195 
board_get_height(void)196 int board_get_height (void)
197 {
198 	return 480;
199 }
200 
201 /*-----------------------------------------------------------------------------
202  * SmiSetRegs --
203  *-----------------------------------------------------------------------------
204  */
SmiSetRegs(void)205 static void SmiSetRegs (void)
206 {
207 	/*
208 	 * The content of the chipset register depends on the board (clocks,
209 	 * ...)
210 	 */
211 	const SMI_REGS *preg = board_get_regs ();
212 	while (preg->Index) {
213 		write32 (preg->Index, preg->Value);
214 		/*
215 		 * Insert a delay between
216 		 */
217 		udelay (1000);
218 		preg ++;
219 	}
220 }
221 
222 /*-----------------------------------------------------------------------------
223  * video_hw_init --
224  *-----------------------------------------------------------------------------
225  */
video_hw_init(void)226 void *video_hw_init (void)
227 {
228 	unsigned int *vm, i;
229 
230 	memset (&sm501, 0, sizeof (GraphicDevice));
231 
232 	/*
233 	 * Initialization of the access to the graphic chipset Retreive base
234 	 * address of the chipset (see board/RPXClassic/eccx.c)
235 	 */
236 	if ((sm501.isaBase = board_video_init ()) == 0) {
237 		return (NULL);
238 	}
239 
240 	if ((sm501.frameAdrs = board_video_get_fb ()) == 0) {
241 		return (NULL);
242 	}
243 
244 	sm501.winSizeX = board_get_width ();
245 	sm501.winSizeY = board_get_height ();
246 
247 #if defined(CONFIG_VIDEO_SM501_8BPP)
248 	sm501.gdfIndex = GDF__8BIT_INDEX;
249 	sm501.gdfBytesPP = 1;
250 
251 #elif defined(CONFIG_VIDEO_SM501_16BPP)
252 	sm501.gdfIndex = GDF_16BIT_565RGB;
253 	sm501.gdfBytesPP = 2;
254 
255 #elif defined(CONFIG_VIDEO_SM501_32BPP)
256 	sm501.gdfIndex = GDF_32BIT_X888RGB;
257 	sm501.gdfBytesPP = 4;
258 #else
259 #error Unsupported SM501 BPP
260 #endif
261 
262 	sm501.memSize = sm501.winSizeX * sm501.winSizeY * sm501.gdfBytesPP;
263 
264 	/* Load Smi registers */
265 	SmiSetRegs ();
266 
267 	/* (see board/RPXClassic/RPXClassic.c) */
268 	board_validate_screen (sm501.isaBase);
269 
270 	/* Clear video memory */
271 	i = sm501.memSize/4;
272 	vm = (unsigned int *)sm501.frameAdrs;
273 	while(i--)
274 		*vm++ = 0;
275 
276 	return (&sm501);
277 }
278 
279 /*-----------------------------------------------------------------------------
280  * video_set_lut --
281  *-----------------------------------------------------------------------------
282  */
video_set_lut(unsigned int index,unsigned char r,unsigned char g,unsigned char b)283 void video_set_lut (
284 	unsigned int index,           /* color number */
285 	unsigned char r,              /* red */
286 	unsigned char g,              /* green */
287 	unsigned char b               /* blue */
288 	)
289 {
290 	unsigned long value = 0;
291 	//unsigned char tt = index;
292 
293 	value = (r << 16) | (g << 8) | b;
294 
295 	// using a gray palette
296 	//value = (tt << 16) | (tt << 8) | tt;
297 
298 	write32 ((index*4) + 0x80400, SWAP32(value));
299 }
300 
301 #endif /* CONFIG_VIDEO_SM502 */
302