2 * Copyright (C) 2007 Juergen Beisert <juergen@kreuzholzen.de>
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.
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.
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
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.
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.
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>
42 #if CONFIG_GX1_VIDEO == 1
44 * Some register descriptions that are no listed in cpu/amd/gx1def.h
46 #define CS5530_DOT_CLK_CONFIG 0x0024
47 #define CS5530_DISPLAY_CONFIG 0x0004
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
67 * what colour depth should be used as default (in bpp)
68 * Note: Currently no other value than 16 is supported
70 #define COLOUR_DEPTH 16
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)
78 int pixel_clock; /*<< pixel clock in Hz */
79 unsigned long pll_value; /*<< pll register value for this clock */
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 */
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 */
91 int sync_pol; /*<< 0: low, 1: high, bit 0 hsync, bit 1 vsync */
95 * values for .sync_pol in struct video_mode
97 #define HSYNC_HIGH_POL 0
98 #define HSYNC_LOW_POL 1
99 #define VSYNC_HIGH_POL 0
100 #define VSYNC_LOW_POL 2
103 * 640x480 @ 72Hz hsync: 37.9kHz
104 * VESA standard mode for classic 4:3 monitors
106 * ModeLine "640x480" 31.5 640 664 704 832 480 489 491 520 -hsync -vsync
108 static const struct video_mode mode_640x480 = {
109 .pixel_clock = 31500000,
110 .pll_value = 0x33915801,
112 .visible_pixel = 640,
114 .hsync_end = 704, /* 1.27 us sync length */
115 .line_length = 832, /* 26.39us */
117 .visible_lines = 480,
120 .picture_length = 520, /* 13.89ms */
122 .sync_pol = HSYNC_LOW_POL | VSYNC_LOW_POL,
126 * 800x600 @ 72Hz hsync: 48.1kHz
127 * VESA standard mode for classic 4:3 monitors
129 * ModeLine "800x600" 50.0 800 856 976 1040 600 637 643 666 +hsync +vsync
131 static const struct video_mode mode_800x600 = {
132 .pixel_clock = 50000000,
133 .pll_value = 0x23088801,
135 .visible_pixel = 800,
138 .line_length = 1040, /* 20.8us */
140 .visible_lines = 600,
143 .picture_length = 666, /* 13.89ms */
145 .sync_pol = HSYNC_HIGH_POL | VSYNC_HIGH_POL,
149 * 1024x768 @ 70Hz (VESA) hsync: 56.5kHz
150 * Standard mode for classic 4:3 monitors
152 * ModeLine "1024x768" 75.0 1024 1048 1184 1328 768 771 777 806 -hsync -vsync
154 static const struct video_mode mode_1024x768 = {
155 .pixel_clock = 75000000,
156 .pll_value = 0x37E22801,
158 .visible_pixel = 1024,
161 .line_length = 1328, /* 17.7us */
163 .visible_lines = 768,
166 .picture_length = 806, /* 14.3us */
168 .sync_pol = HSYNC_LOW_POL | VSYNC_LOW_POL,
172 * 1280x960 @ 60Hz (VESA) hsync: 60.0kHz
173 * Mode for classic 4:3 monitors
175 * ModeLine "1280x960" 108.0 1280 1376 1488 1800 960 961 964 1000 +hsync +vsync
177 static const struct video_mode mode_1280x960 = {
178 .pixel_clock = 108000000,
179 .pll_value = 0x2710C805,
181 .visible_pixel = 1280,
184 .line_length = 1800, /* 16.67us */
186 .visible_lines = 960,
189 .picture_length = 1000, /* 16.67ms */
191 .sync_pol = HSYNC_HIGH_POL | VSYNC_HIGH_POL,
195 * 1280x1024 @ 60Hz (VESA) hsync: 64.0kHz
196 * Mode for modern 5:4 flat screens
198 * ModeLine "1280x1024" 108.0 1280 1328 1440 1688 1024 1025 1028 1066 +hsync +vsync
200 static const struct video_mode mode_1280x1024 = {
201 .pixel_clock = 108000000,
202 .pll_value = 0x2710C805,
204 .visible_pixel = 1280,
207 .line_length = 1688, /* 15.6us */
209 .visible_lines = 1024,
212 .picture_length = 1066,
214 .sync_pol = HSYNC_HIGH_POL | VSYNC_HIGH_POL,
218 * List of supported common modes
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 */
228 /* make a sanity check at buildtime */
229 #if CONFIG_GX1_VIDEOMODE > 4
230 # error Requested video mode is unknown!
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
238 * The PLL to program here is located in the CS5530
240 static void cs5530_set_clock_frequency(u32 io_base, unsigned long pll_val)
244 /* disable the PLL first, reset and power it down */
245 reg = read32(io_base+CS5530_DOT_CLK_CONFIG) & ~0x20;
247 write32(io_base+CS5530_DOT_CLK_CONFIG, reg);
249 /* write the new PLL setting */
250 reg |= (pll_val & ~0x80000920);
251 write32(io_base+CS5530_DOT_CLK_CONFIG, reg);
253 mdelay(1); /* wait for control voltage to be 0V */
257 write32(io_base+CS5530_DOT_CLK_CONFIG, reg);
261 write32(io_base+CS5530_DOT_CLK_CONFIG, reg);
265 write32(io_base+CS5530_DOT_CLK_CONFIG, reg);
269 * Setup memory layout
270 * @param[in] gx_base GX register area
271 * @param[in] mode Data about the video mode to setup
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)
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
285 static void dc_setup_layout(u32 gx_base, const struct video_mode *mode)
287 u32 base = 0x00000000;
289 write32(gx_base + DC_FB_ST_OFFSET, base);
291 base += (COLOUR_DEPTH>>3) * mode->visible_pixel * mode->visible_lines;
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);
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
305 * Sync signal generation is done in Geode GX1's chipset.
306 * Note: This routine assumes unlocked DC registers
308 * |<------------------------- htotal ----------------------------->|
309 * |<------------ hactive -------------->| |
310 * | hblankstart-->| |
314 * |#####################################___________________________| RGB data
315 * |______________________________________________---------_________| HSYNC
317 * |<------------------------- vtotal ----------------------------->|
318 * |<------------ vactive -------------->| |
319 * | vblankstart-->| |
323 * |#####################################___________________________| line data
324 * |______________________________________________---------_________| YSYNC
326 static void dc_setup_timing(u32 gx_base, const struct video_mode *mode)
328 u32 hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal;
329 u32 vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
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;
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;
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));
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));
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
367 * Must be setup in Geode GX1's chipset.
368 * Note: This routine assumes unlocked DC registers.
370 static void cs5530_activate_mode(u32 gx_base, const struct video_mode *mode)
372 write32(gx_base + DC_GENERAL_CFG, 0x00000080);
374 dc_setup_layout(gx_base,mode);
375 dc_setup_timing(gx_base,mode);
377 write32(gx_base + DC_GENERAL_CFG, 0x2000C581);
378 write32(gx_base + DC_TIMING_CFG, 0x0000002F);
379 write32(gx_base + DC_OUTPUT_CFG, 0x00003004);
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
387 * As we now activate the interface this must be done
390 static void cs5530_activate_video(u32 io_base, const struct video_mode *mode)
394 val = (u32)mode->sync_pol << 8;
395 write32(io_base + CS5530_DISPLAY_CONFIG, val | 0x0020002F);
398 #if CONFIG_SPLASH_GRAPHIC == 1
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
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
417 * This routine assumes we are using a 16 bit colour depth!
419 static void show_boot_splash_16(u32 swidth, u32 sheight, u32 pitch,void *base)
423 u32 xstart,ystart,x,y;
425 * fill the screen with the colour of the
426 * left top pixel in the graphic
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]];
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]];
447 # define show_boot_splash_16(w, x, y , z)
451 * coreboot management part
452 * @param[in] dev Info about the PCI device to initialise
454 static void cs5530_vga_init(device_t dev)
456 const struct video_mode *mode;
457 u32 io_base, gx_base;
459 io_base = pci_read_config32(dev, 0x10);
461 mode = modes[CONFIG_GX1_VIDEOMODE];
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);
466 cs5530_set_clock_frequency(io_base, mode->pll_value);
468 write32(gx_base + DC_UNLOCK, DC_UNLOCK_MAGIC);
470 show_boot_splash_16(mode->visible_pixel, mode->visible_lines,
471 mode->visible_pixel * (COLOUR_DEPTH>>3), (void*)(GX_BASE + 0x800000));
473 cs5530_activate_mode(gx_base, mode);
475 cs5530_activate_video(io_base, mode);
476 write32(gx_base + DC_UNLOCK, 0x00000000);
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 */
487 static const struct pci_driver vga_pci_driver __pci_driver = {
489 .vendor = PCI_VENDOR_ID_CYRIX,
490 .device = PCI_DEVICE_ID_CYRIX_5530_VIDEO,
493 #endif /* #if CONFIG_GX1_VIDEO == 1 */