This patch will add support for the Geode GX1/CS5530 VGA feature. It's able
[coreboot.git] / src / southbridge / amd / cs5530 / cs5530_vga.c
1 /*
2  * Copyright (C) 2007 Juergen Beisert <juergen@kreuzholzen.de>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
16  *
17  * Purpose:
18  * Activate the VGA feature in a Geode GX1 based system with one of five
19  * possible VESA modes: VGA, SVGA, XGA, 4:3 SXGA and 5:4 SXGA. Also it is
20  * prepared to display a splash screen.
21  */
22 #include <arch/io.h>
23 #include <device/device.h>
24 #include <device/pci.h>
25 #include <device/pci_ops.h>
26 #include <device/pci_ids.h>
27 #include <console/console.h>
28 #include <cpu/amd/gx1def.h>
29 #include <delay.h>
30
31 #if CONFIG_GX1_VIDEO == 1
32 /*
33  * Some register descriptions that are no listed in cpu/amd/gx1def.h
34  */
35 #define CS5530_DOT_CLK_CONFIG   0x0024
36 #define CS5530_DISPLAY_CONFIG   0x0004
37
38 #define DC_FB_ST_OFFSET         0x8310  /* framebuffer start offset */
39 #define DC_CB_ST_OFFSET         0x8314  /* compression start offset */
40 #define DC_CURS_ST_OFFSET       0x8318  /* cursor start offset */
41 #define DC_VID_ST_OFFSET        0x8320  /* video start offset */
42 #define DC_LINE_DELTA           0x8324  /* fb and cb skip counts */
43 #define DC_BUF_SIZE             0x8328  /* fb and cb line size */
44 #define DC_H_TIMING_1           0x8330  /* horizontal timing... */
45 #define DC_H_TIMING_2           0x8334
46 #define DC_H_TIMING_3           0x8338
47 #define DC_FP_H_TIMING          0x833C
48 #define DC_V_TIMING_1           0x8340  /* vertical timing... */
49 #define DC_V_TIMING_2           0x8344
50 #define DC_V_TIMING_3           0x8348
51 #define DC_FP_V_TIMING          0x834C
52 #define DC_TIMING_CFG           0x8308
53 #define DC_OUTPUT_CFG           0x830C
54
55 /*
56  * what colour depth should be used as default (in bpp)
57  * Note: Currently no other value than 16 is supported
58  */
59 #define COLOUR_DEPTH 16
60
61 /*
62  * Support for a few basic video modes
63  * Note: all modes only for CRT. The flatpanel feature is
64  * not supported here (due to the lack of hardware to test)
65  */
66 struct video_mode {
67         int pixel_clock;                /*<< pixel clock in Hz */
68         unsigned long pll_value;        /*<< pll register value for this clock */
69
70         int visible_pixel;
71         int hsync_start;
72         int hsync_end;
73         int line_length;
74
75         int visible_lines;
76         int vsync_start;
77         int vsync_end;
78         int picture_length;
79
80         int sync_pol;           /*<< 0: low, 1: high, bit 0 hsync, bit 1 vsync */
81 };
82
83 /*
84  * values for .sync_pol
85  */
86 #define HSYNC_HIGH_POL 0
87 #define HSYNC_LOW_POL 1
88 #define VSYNC_HIGH_POL 0
89 #define VSYNC_LOW_POL 2
90
91 /* ModeLine "640x480" 31.5 640 664 704 832 480 489 491 520 -hsync -vsync */
92 static const struct video_mode mode_640x480 = {
93         /*
94          * 640x480 @ 72Hz hsync: 37.9kHz
95          * VESA standard mode for classic 4:3 monitors
96          */
97         .pixel_clock = 31500000,
98         .pll_value = 0x33915801,
99
100         .visible_pixel = 640,
101         .hsync_start = 664,
102         .hsync_end = 704,       /* 1.27 us sync length */
103         .line_length = 832,     /* 26.39us */
104
105         .visible_lines = 480,
106         .vsync_start = 489,
107         .vsync_end = 491,
108         .picture_length = 520, /* 13.89ms */
109
110         .sync_pol = HSYNC_LOW_POL | VSYNC_LOW_POL
111 };
112
113 /* ModeLine "800x600" 50.0 800 856 976 1040 600 637 643 666 +hsync +vsync */
114 static const struct video_mode mode_800x600 = {
115         /*
116          * 800x600 @ 72Hz hsync: 48.1kHz
117          * VESA standard mode for classic 4:3 monitors
118          */
119         .pixel_clock = 50000000,
120         .pll_value = 0x23088801,
121
122         .visible_pixel = 800,
123         .hsync_start = 856,
124         .hsync_end = 976,
125         .line_length = 1040, /* 20.8us */
126
127         .visible_lines = 600,
128         .vsync_start = 637,
129         .vsync_end = 643,
130         .picture_length = 666, /* 13.89ms */
131
132         .sync_pol = HSYNC_HIGH_POL | VSYNC_HIGH_POL
133 };
134
135 /* ModeLine "1024x768" 75.0 1024 1048 1184 1328 768 771 777 806 -hsync -vsync */
136 static const struct video_mode mode_1024x768 = {
137         /*
138          * 1024x768 @ 70Hz (VESA) hsync: 56.5kHz
139          * Standard mode for classic 4:3 monitors
140          */
141         .pixel_clock = 75000000,
142         .pll_value = 0x37E22801,
143
144         .visible_pixel = 1024,
145         .hsync_start = 1048,
146         .hsync_end = 1184,
147         .line_length = 1328,    /* 17.7us */
148
149         .visible_lines = 768,
150         .vsync_start = 771,
151         .vsync_end = 777,
152         .picture_length = 806,  /* 14.3us */
153
154         .sync_pol = HSYNC_LOW_POL | VSYNC_LOW_POL
155 };
156
157 /* ModeLine "1280x960" 108.0 1280 1376 1488 1800 960 961 964 1000 +hsync +vsync */
158 static const struct video_mode mode_1280x960 = {
159         /*
160          * 1280x960 @ 60Hz (VESA) hsync: 60.0kHz
161          * Mode for classic 4:3 monitors
162          */
163         .pixel_clock = 108000000,
164         .pll_value = 0x2710C805,
165
166         .visible_pixel = 1280,
167         .hsync_start = 1376,
168         .hsync_end = 1488,
169         .line_length = 1800,    /* 16.67us */
170
171         .visible_lines = 960,
172         .vsync_start = 961,
173         .vsync_end = 964,
174         .picture_length = 1000, /* 16.67ms */
175
176         .sync_pol = HSYNC_HIGH_POL | VSYNC_HIGH_POL
177 };
178
179 /* ModeLine "1280x1024" 108.0 1280 1328 1440 1688 1024 1025 1028 1066 +hsync +vsync */
180 static const struct video_mode mode_1280x1024 = {
181         /*
182          * 1280x1024 @ 60Hz (VESA) hsync: 64.0kHz
183          * Mode for modern 5:4 flat screens
184          */
185         .pixel_clock = 108000000,
186         .pll_value = 0x2710C805,
187
188         .visible_pixel = 1280,
189         .hsync_start = 1328,
190         .hsync_end = 1440,
191         .line_length = 1688,    /* 15.6us */
192
193         .visible_lines = 1024,
194         .vsync_start = 1025,
195         .vsync_end = 1028,
196         .picture_length = 1066,
197
198         .sync_pol = HSYNC_HIGH_POL | VSYNC_HIGH_POL
199 };
200
201 /*
202  * a few supported common modes
203  */
204 static const struct video_mode *modes[] = {
205         &mode_640x480,  /* CONFIG_GX1_VIDEOMODE = 0 */
206         &mode_800x600,  /* CONFIG_GX1_VIDEOMODE = 1 */
207         &mode_1024x768, /* CONFIG_GX1_VIDEOMODE = 2 */
208         &mode_1280x960, /* CONFIG_GX1_VIDEOMODE = 3 */
209         &mode_1280x1024 /* CONFIG_GX1_VIDEOMODE = 4 */
210 };
211
212 /* make a sanity check at buildtime */
213 #if CONFIG_GX1_VIDEOMODE > 4
214 # error Requested video mode is unknown!
215 #endif
216
217 /*
218  * Setup the pixel PLL in the companion chip
219  * base: register's base address
220  * pll_val: pll register value to be set
221  */
222 static void cs5530_set_clock_frequency(void *io_base,unsigned long pll_val)
223 {
224         unsigned long reg;
225
226         /* disable the PLL first, reset and power it down */
227         reg = readl(io_base+CS5530_DOT_CLK_CONFIG) & ~0x20;
228         reg |= 0x80000100;
229         writel(reg, io_base+CS5530_DOT_CLK_CONFIG);
230
231         /* write the new PLL setting */
232         reg |= (pll_val & ~0x80000920);
233         writel(reg, io_base+CS5530_DOT_CLK_CONFIG);
234
235         mdelay(1);      /* wait for control voltage to be 0V */
236
237         /* enable the PLL */
238         reg |= 0x00000800;
239         writel(reg, io_base+CS5530_DOT_CLK_CONFIG);
240
241         /* clear reset */
242         reg &= ~0x80000000;
243         writel(reg, io_base+CS5530_DOT_CLK_CONFIG);
244
245         /* clear bypass */
246         reg &= ~0x00000100;
247         writel(reg, io_base+CS5530_DOT_CLK_CONFIG);
248 }
249
250 /*
251  * Setup memory layout
252  * gx_base: GX register area
253  * mode: Data about the video mode to setup
254  *
255  * This routine assumes unlocked DC registers. Using compressed buffer
256  * is not supported! (makes more sense later, but not while booting)
257  */
258 static void dc_setup_layout(void *gx_base,const struct video_mode *mode)
259 {
260         unsigned long base = 0x00000000;
261
262         writel(base, gx_base + DC_FB_ST_OFFSET);
263
264         base += (COLOUR_DEPTH>>3) * mode->visible_pixel * mode->visible_lines;
265
266         writel(base, gx_base + DC_CB_ST_OFFSET);
267         writel(base, gx_base + DC_CURS_ST_OFFSET);
268         writel(base, gx_base + DC_VID_ST_OFFSET);
269         writel(((COLOUR_DEPTH>>3) * mode->visible_pixel) >> 2, gx_base + DC_LINE_DELTA);
270         writel(((COLOUR_DEPTH>>3) * mode->visible_pixel) >> 3, gx_base + DC_BUF_SIZE);
271 }
272
273 /*
274  * Setup the HSYNC/VSYNC, active video timing
275  * gx_base: GX register area
276  * mode: Data about the video mode to setup
277  *
278  * This routine assumes unlocked DC registers
279  *
280  * |<------------------------- htotal ----------------------------->|
281  * |<------------ hactive -------------->|                          |
282  * |                       hblankstart-->|                          |
283  * |                                                    hblankend-->|
284  * |                                hsyncstart-->|                  |
285  * |                                           hsyncend-->|         |
286  * |#####################################___________________________| RGB data
287  * |______________________________________________---------_________| HSYNC
288  *
289  * |<------------------------- vtotal ----------------------------->|
290  * |<------------ vactive -------------->|                          |
291  * |                       vblankstart-->|                          |
292  * |                                                    vblankend-->|
293  * |                                vsyncstart-->|                  |
294  * |                                           vsyncend-->|         |
295  * |#####################################___________________________| line data
296  * |______________________________________________---------_________| YSYNC
297  */
298 static void dc_setup_timing(void *gx_base,const struct video_mode *mode)
299 {
300         unsigned long hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal;
301         unsigned long vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
302
303         hactive = mode->visible_pixel & 0x7FF;
304         hblankstart = hactive;
305         hsyncstart = mode->hsync_start & 0x7FF;
306         hsyncend =  mode->hsync_end & 0x7FF;
307         hblankend = mode->line_length & 0x7FF;
308         htotal = hblankend;
309
310         vactive = mode->visible_lines & 0x7FF;
311         vblankstart = vactive;
312         vsyncstart = mode->vsync_start & 0x7FF;
313         vsyncend =  mode->vsync_end & 0x7FF;
314         vblankend = mode->picture_length & 0x7FF;
315         vtotal = vblankend;
316
317         /* row description */
318         writel((hactive - 1) | ((htotal - 1) << 16), gx_base + DC_H_TIMING_1);
319         /* horizontal blank description */
320         writel((hblankstart - 1) | ((hblankend - 1) << 16), gx_base + DC_H_TIMING_2);
321         /* horizontal sync description */
322         writel((hsyncstart - 1) | ((hsyncend - 1) << 16), gx_base + DC_H_TIMING_3);
323         writel((hsyncstart - 1) | ((hsyncend - 1) << 16), gx_base + DC_FP_H_TIMING);
324
325         /* line description */
326         writel((vactive - 1) | ((vtotal - 1) << 16), gx_base + DC_V_TIMING_1);
327         /* vertical blank description */
328         writel((vblankstart - 1) | ((vblankend - 1) << 16), gx_base + DC_V_TIMING_2);
329         /* vertical sync description */
330         writel((vsyncstart - 1) | ((vsyncend - 1) << 16), gx_base + DC_V_TIMING_3);
331         writel((vsyncstart - 2) | ((vsyncend - 2) << 16), gx_base + DC_FP_V_TIMING);
332 }
333
334 /*
335  * Setup required internals to bring the mode up and running
336  * gx_base: GX register area
337  * mode: Data about the video mode to setup
338  */
339 static void cs5530_activate_mode(void *gx_base, const struct video_mode *mode)
340 {
341         writel(0x00000080, gx_base + DC_GENERAL_CFG);
342         mdelay(1);
343         dc_setup_layout(gx_base,mode);
344         dc_setup_timing(gx_base,mode);
345
346         writel(0x2000C581, gx_base + DC_GENERAL_CFG);
347         writel(0x0000002F, gx_base + DC_TIMING_CFG);
348         writel(0x00003004, gx_base + DC_OUTPUT_CFG);
349 }
350
351 /*
352  * Activate the current mode to be "visible" outside
353  * gx_base: GX register area
354  * mode: Data about the video mode to setup
355  */
356 static void cs5530_activate_video(void *io_base, const struct video_mode *mode)
357 {
358         u32 val;
359
360         val = mode->sync_pol;
361         val <<= 8;
362
363         writel(val | 0x0020002F, io_base + CS5530_DISPLAY_CONFIG);
364 }
365
366 /*
367  * This bitmap file must provide:
368  * int width: pixel count in one line
369  * int height: line count
370  * int colours: ount of used colour
371  * unsigned long colour_map[]: RGB 565 colours to be used
372  * unsigned char bitmap[]: index per pixel into colour_map[], width*height pixels
373  */
374 #include "bitmap.c"
375
376 /*
377  * show a boot splash screen in the right lower corner of the screen
378  * swidth: screen width in pixel
379  * sheight: screen height in lines
380  * pitch: line pitch in bytes
381  * base: screen base address
382  *
383  * This routine assumes we are using a 16 bit colour depth!
384  */
385 static void show_boot_splash_16(u32 swidth,u32 sheight,u32 pitch,void *base)
386 {
387         int word_count,i;
388         unsigned short *adr;
389         u32 xstart,ystart,x,y;
390         /*
391          * fill the screen with the colour of the
392          * left top pixel in the graphic
393          */
394         word_count = pitch*sheight;
395         printk_debug("Clear Screen at %p, %d words\n",base,word_count);
396         adr = (unsigned short *) base;
397         for (i=0; i < word_count; i++, adr++)
398                 *adr = colour_map[bitmap[0]];
399         printk_debug("Ready\n");
400
401         /*
402          * paint the splash
403          */
404         xstart=swidth-width;
405         ystart=sheight-height;
406         printk_debug("Start at %u,%u\n",xstart,ystart);
407         for (y=0;y<height;y++) {
408                 adr=(unsigned short*)(base + pitch*(y+ystart)+2*xstart);
409                 for (x=0;x<width;x++) {
410                         *adr=(unsigned short)colour_map[(int)bitmap[x+y*width]];
411                         adr++;
412                 }
413         }
414 }
415
416 /*
417  * management part
418  */
419 static void cs5530_vga_init(device_t dev)
420 {
421         const struct video_mode *mode;
422         void *io_base, *gx_base;
423
424         io_base = (void*)pci_read_config32(dev,0x10);
425         gx_base = (void*)GX_BASE;
426         mode = modes[CONFIG_GX1_VIDEOMODE];
427
428         printk_debug("Setting up video mode %dx%d with %d Hz clock\n",
429                 mode->visible_pixel, mode->visible_lines, mode->pixel_clock);
430
431         cs5530_set_clock_frequency(io_base,mode->pll_value);
432
433         writel(DC_UNLOCK_MAGIC, gx_base + DC_UNLOCK);
434
435         show_boot_splash_16(mode->visible_pixel, mode->visible_lines,
436                 mode->visible_pixel*(COLOUR_DEPTH>>3),(void*)(GX_BASE+0x800000));
437
438         cs5530_activate_mode(gx_base,mode);
439
440         cs5530_activate_video(io_base, mode);
441         writel(0x00000000, gx_base + DC_UNLOCK);
442 }
443
444 static struct device_operations vga_ops = {
445         .read_resources   = pci_dev_read_resources,
446         .set_resources    = pci_dev_set_resources,
447         .enable_resources = pci_dev_enable_resources,
448         .init             = cs5530_vga_init,
449         .enable           = NULL /* not required */
450 };
451
452 static struct pci_driver vga_pci_driver __pci_driver = {
453         .ops    = &vga_ops,
454         .vendor = PCI_VENDOR_ID_CYRIX,
455         .device = PCI_DEVICE_ID_CYRIX_5530_VIDEO
456 };
457
458 #endif /* #if CONFIG_GX1_VIDEO == 1 */