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