summaryrefslogtreecommitdiff
path: root/src/southbridge/amd/cs5530/vga.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/southbridge/amd/cs5530/vga.c')
-rw-r--r--src/southbridge/amd/cs5530/vga.c495
1 files changed, 495 insertions, 0 deletions
diff --git a/src/southbridge/amd/cs5530/vga.c b/src/southbridge/amd/cs5530/vga.c
new file mode 100644
index 0000000000..4a26251084
--- /dev/null
+++ b/src/southbridge/amd/cs5530/vga.c
@@ -0,0 +1,495 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2007 Juergen Beisert <juergen@kreuzholzen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+/**
+ * @brief Activate the VGA feature in a Geode GX1 based system with one
+ * of five possible VESA modes: VGA, SVGA, XGA, 4:3 SXGA and 5:4 SXGA.
+ * Also it is prepared to display a splash screen.
+ *
+ * In a Geode GX1 environment the companion CS5530 is the VGA
+ * interface only. It contains a PLL for pixel clock generation,
+ * DACs to generate the analogue RGB signals, drivers for HSYNC
+ * and VSYNC and drivers for a digital flatpanel.
+ * The graphic feature itself (framebuffer, acceleration unit)
+ * is not part of this device. It is part of the CPU device.
+ * But both depend on each other, we cannot divide them into
+ * different drivers. So this driver is not only a CS5530 driver,
+ * it is also a Geode GX1 chipset graphic driver.
+ */
+#include <arch/io.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ops.h>
+#include <device/pci_ids.h>
+#include <console/console.h>
+#include <cpu/amd/gx1def.h>
+#include <delay.h>
+
+#if CONFIG_GX1_VIDEO == 1
+/*
+ * Some register descriptions that are no listed in cpu/amd/gx1def.h
+ */
+#define CS5530_DOT_CLK_CONFIG 0x0024
+#define CS5530_DISPLAY_CONFIG 0x0004
+
+#define DC_FB_ST_OFFSET 0x8310 /* framebuffer start offset */
+#define DC_CB_ST_OFFSET 0x8314 /* compression start offset */
+#define DC_CURS_ST_OFFSET 0x8318 /* cursor start offset */
+#define DC_VID_ST_OFFSET 0x8320 /* video start offset */
+#define DC_LINE_DELTA 0x8324 /* fb and cb skip counts */
+#define DC_BUF_SIZE 0x8328 /* fb and cb line size */
+#define DC_H_TIMING_1 0x8330 /* horizontal timing... */
+#define DC_H_TIMING_2 0x8334
+#define DC_H_TIMING_3 0x8338
+#define DC_FP_H_TIMING 0x833C
+#define DC_V_TIMING_1 0x8340 /* vertical timing... */
+#define DC_V_TIMING_2 0x8344
+#define DC_V_TIMING_3 0x8348
+#define DC_FP_V_TIMING 0x834C
+#define DC_TIMING_CFG 0x8308
+#define DC_OUTPUT_CFG 0x830C
+
+/**
+ * what colour depth should be used as default (in bpp)
+ * Note: Currently no other value than 16 is supported
+ */
+#define COLOUR_DEPTH 16
+
+/**
+ * Support for a few basic video modes
+ * Note: all modes only for CRT. The flatpanel feature is
+ * not supported here (due to the lack of hardware to test)
+ */
+struct video_mode {
+ int pixel_clock; /*<< pixel clock in Hz */
+ unsigned long pll_value; /*<< pll register value for this clock */
+
+ int visible_pixel; /*<< visible pixels in one line */
+ int hsync_start; /*<< start of hsync behind visible pixels */
+ int hsync_end; /*<< end of hsync behind its start */
+ int line_length; /*<< whole line length */
+
+ int visible_lines; /*<< visible lines on screen */
+ int vsync_start; /*<< vsync start behind last visible line */
+ int vsync_end; /*<< end of vsync behind its start */
+ int picture_length; /*<< whole screen length */
+
+ int sync_pol; /*<< 0: low, 1: high, bit 0 hsync, bit 1 vsync */
+};
+
+/*
+ * values for .sync_pol in struct video_mode
+ */
+#define HSYNC_HIGH_POL 0
+#define HSYNC_LOW_POL 1
+#define VSYNC_HIGH_POL 0
+#define VSYNC_LOW_POL 2
+
+/**
+ * 640x480 @ 72Hz hsync: 37.9kHz
+ * VESA standard mode for classic 4:3 monitors
+ * Copied from X11:
+ * ModeLine "640x480" 31.5 640 664 704 832 480 489 491 520 -hsync -vsync
+ */
+static const struct video_mode mode_640x480 = {
+ .pixel_clock = 31500000,
+ .pll_value = 0x33915801,
+
+ .visible_pixel = 640,
+ .hsync_start = 664,
+ .hsync_end = 704, /* 1.27 us sync length */
+ .line_length = 832, /* 26.39us */
+
+ .visible_lines = 480,
+ .vsync_start = 489,
+ .vsync_end = 491,
+ .picture_length = 520, /* 13.89ms */
+
+ .sync_pol = HSYNC_LOW_POL | VSYNC_LOW_POL,
+};
+
+/**
+ * 800x600 @ 72Hz hsync: 48.1kHz
+ * VESA standard mode for classic 4:3 monitors
+ * Copied from X11:
+ * ModeLine "800x600" 50.0 800 856 976 1040 600 637 643 666 +hsync +vsync
+ */
+static const struct video_mode mode_800x600 = {
+ .pixel_clock = 50000000,
+ .pll_value = 0x23088801,
+
+ .visible_pixel = 800,
+ .hsync_start = 856,
+ .hsync_end = 976,
+ .line_length = 1040, /* 20.8us */
+
+ .visible_lines = 600,
+ .vsync_start = 637,
+ .vsync_end = 643,
+ .picture_length = 666, /* 13.89ms */
+
+ .sync_pol = HSYNC_HIGH_POL | VSYNC_HIGH_POL,
+};
+
+/**
+ * 1024x768 @ 70Hz (VESA) hsync: 56.5kHz
+ * Standard mode for classic 4:3 monitors
+ * Copied from X11:
+ * ModeLine "1024x768" 75.0 1024 1048 1184 1328 768 771 777 806 -hsync -vsync
+ */
+static const struct video_mode mode_1024x768 = {
+ .pixel_clock = 75000000,
+ .pll_value = 0x37E22801,
+
+ .visible_pixel = 1024,
+ .hsync_start = 1048,
+ .hsync_end = 1184,
+ .line_length = 1328, /* 17.7us */
+
+ .visible_lines = 768,
+ .vsync_start = 771,
+ .vsync_end = 777,
+ .picture_length = 806, /* 14.3us */
+
+ .sync_pol = HSYNC_LOW_POL | VSYNC_LOW_POL,
+};
+
+/**
+ * 1280x960 @ 60Hz (VESA) hsync: 60.0kHz
+ * Mode for classic 4:3 monitors
+ * Copied from X11:
+ * ModeLine "1280x960" 108.0 1280 1376 1488 1800 960 961 964 1000 +hsync +vsync
+ */
+static const struct video_mode mode_1280x960 = {
+ .pixel_clock = 108000000,
+ .pll_value = 0x2710C805,
+
+ .visible_pixel = 1280,
+ .hsync_start = 1376,
+ .hsync_end = 1488,
+ .line_length = 1800, /* 16.67us */
+
+ .visible_lines = 960,
+ .vsync_start = 961,
+ .vsync_end = 964,
+ .picture_length = 1000, /* 16.67ms */
+
+ .sync_pol = HSYNC_HIGH_POL | VSYNC_HIGH_POL,
+};
+
+/**
+ * 1280x1024 @ 60Hz (VESA) hsync: 64.0kHz
+ * Mode for modern 5:4 flat screens
+ * Copied from X11:
+ * ModeLine "1280x1024" 108.0 1280 1328 1440 1688 1024 1025 1028 1066 +hsync +vsync
+ */
+static const struct video_mode mode_1280x1024 = {
+ .pixel_clock = 108000000,
+ .pll_value = 0x2710C805,
+
+ .visible_pixel = 1280,
+ .hsync_start = 1328,
+ .hsync_end = 1440,
+ .line_length = 1688, /* 15.6us */
+
+ .visible_lines = 1024,
+ .vsync_start = 1025,
+ .vsync_end = 1028,
+ .picture_length = 1066,
+
+ .sync_pol = HSYNC_HIGH_POL | VSYNC_HIGH_POL,
+};
+
+/**
+ * List of supported common modes
+ */
+static const struct video_mode *modes[] = {
+ &mode_640x480, /* CONFIG_GX1_VIDEOMODE = 0 */
+ &mode_800x600, /* CONFIG_GX1_VIDEOMODE = 1 */
+ &mode_1024x768, /* CONFIG_GX1_VIDEOMODE = 2 */
+ &mode_1280x960, /* CONFIG_GX1_VIDEOMODE = 3 */
+ &mode_1280x1024 /* CONFIG_GX1_VIDEOMODE = 4 */
+};
+
+/* make a sanity check at buildtime */
+#if CONFIG_GX1_VIDEOMODE > 4
+# error Requested video mode is unknown!
+#endif
+
+/**
+ * Setup the pixel PLL in the companion chip
+ * @param[in] base register's base address
+ * @param[in] pll_val pll register value to be set
+ *
+ * The PLL to program here is located in the CS5530
+ */
+static void cs5530_set_clock_frequency(u32 io_base, unsigned long pll_val)
+{
+ unsigned long reg;
+
+ /* disable the PLL first, reset and power it down */
+ reg = read32(io_base+CS5530_DOT_CLK_CONFIG) & ~0x20;
+ reg |= 0x80000100;
+ write32(io_base+CS5530_DOT_CLK_CONFIG, reg);
+
+ /* write the new PLL setting */
+ reg |= (pll_val & ~0x80000920);
+ write32(io_base+CS5530_DOT_CLK_CONFIG, reg);
+
+ mdelay(1); /* wait for control voltage to be 0V */
+
+ /* enable the PLL */
+ reg |= 0x00000800;
+ write32(io_base+CS5530_DOT_CLK_CONFIG, reg);
+
+ /* clear reset */
+ reg &= ~0x80000000;
+ write32(io_base+CS5530_DOT_CLK_CONFIG, reg);
+
+ /* clear bypass */
+ reg &= ~0x00000100;
+ write32(io_base+CS5530_DOT_CLK_CONFIG, reg);
+}
+
+/**
+ * Setup memory layout
+ * @param[in] gx_base GX register area
+ * @param[in] mode Data about the video mode to setup
+ *
+ * Memory layout must be setup in Geode GX1's chipset.
+ * Note: This routine assumes unlocked DC registers.
+ * Note: Using compressed buffer is not supported yet!
+ * (makes more sense later, but not while booting)
+ *
+ * At this point a check is missed if the requested video
+ * mode is possible with the provided video memory.
+ * Check if symbol CONFIG_VIDEO_MB is at least:
+ * - 1 (=1MiB) for VGA and SVGA
+ * - 2 (=2MiB) for XGA
+ * - 4 (=4MiB) for SXGA
+ */
+static void dc_setup_layout(u32 gx_base, const struct video_mode *mode)
+{
+ u32 base = 0x00000000;
+
+ write32(gx_base + DC_FB_ST_OFFSET, base);
+
+ base += (COLOUR_DEPTH>>3) * mode->visible_pixel * mode->visible_lines;
+
+ write32(gx_base + DC_CB_ST_OFFSET, base);
+ write32(gx_base + DC_CURS_ST_OFFSET, base);
+ write32(gx_base + DC_VID_ST_OFFSET, base);
+ write32(gx_base + DC_LINE_DELTA, ((COLOUR_DEPTH>>3) * mode->visible_pixel) >> 2);
+ write32(gx_base + DC_BUF_SIZE, ((COLOUR_DEPTH>>3) * mode->visible_pixel) >> 3);
+}
+
+/**
+ * Setup the HSYNC/VSYNC, active video timing
+ * @param[in] gx_base GX register area
+ * @param[in] mode Data about the video mode to setup
+ *
+ * Sync signal generation is done in Geode GX1's chipset.
+ * Note: This routine assumes unlocked DC registers
+ *
+ * |<------------------------- htotal ----------------------------->|
+ * |<------------ hactive -------------->| |
+ * | hblankstart-->| |
+ * | hblankend-->|
+ * | hsyncstart-->| |
+ * | hsyncend-->| |
+ * |#####################################___________________________| RGB data
+ * |______________________________________________---------_________| HSYNC
+ *
+ * |<------------------------- vtotal ----------------------------->|
+ * |<------------ vactive -------------->| |
+ * | vblankstart-->| |
+ * | vblankend-->|
+ * | vsyncstart-->| |
+ * | vsyncend-->| |
+ * |#####################################___________________________| line data
+ * |______________________________________________---------_________| YSYNC
+ */
+static void dc_setup_timing(u32 gx_base, const struct video_mode *mode)
+{
+ u32 hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal;
+ u32 vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
+
+ hactive = mode->visible_pixel & 0x7FF;
+ hblankstart = hactive;
+ hsyncstart = mode->hsync_start & 0x7FF;
+ hsyncend = mode->hsync_end & 0x7FF;
+ hblankend = mode->line_length & 0x7FF;
+ htotal = hblankend;
+
+ vactive = mode->visible_lines & 0x7FF;
+ vblankstart = vactive;
+ vsyncstart = mode->vsync_start & 0x7FF;
+ vsyncend = mode->vsync_end & 0x7FF;
+ vblankend = mode->picture_length & 0x7FF;
+ vtotal = vblankend;
+
+ /* row description */
+ write32(gx_base + DC_H_TIMING_1, (hactive - 1) | ((htotal - 1) << 16));
+ /* horizontal blank description */
+ write32(gx_base + DC_H_TIMING_2, (hblankstart - 1) | ((hblankend - 1) << 16));
+ /* horizontal sync description */
+ write32(gx_base + DC_H_TIMING_3, (hsyncstart - 1) | ((hsyncend - 1) << 16));
+ write32(gx_base + DC_FP_H_TIMING, (hsyncstart - 1) | ((hsyncend - 1) << 16));
+
+ /* line description */
+ write32(gx_base + DC_V_TIMING_1, (vactive - 1) | ((vtotal - 1) << 16));
+ /* vertical blank description */
+ write32(gx_base + DC_V_TIMING_2, (vblankstart - 1) | ((vblankend - 1) << 16));
+ /* vertical sync description */
+ write32(gx_base + DC_V_TIMING_3, (vsyncstart - 1) | ((vsyncend - 1) << 16));
+ write32(gx_base + DC_FP_V_TIMING, (vsyncstart - 2) | ((vsyncend - 2) << 16));
+}
+
+/**
+ * Setup required internals to bring the mode up and running
+ * @param[in] gx_base GX register area
+ * @param[in] mode Data about the video mode to setup
+ *
+ * Must be setup in Geode GX1's chipset.
+ * Note: This routine assumes unlocked DC registers.
+ */
+static void cs5530_activate_mode(u32 gx_base, const struct video_mode *mode)
+{
+ write32(gx_base + DC_GENERAL_CFG, 0x00000080);
+ mdelay(1);
+ dc_setup_layout(gx_base,mode);
+ dc_setup_timing(gx_base,mode);
+
+ write32(gx_base + DC_GENERAL_CFG, 0x2000C581);
+ write32(gx_base + DC_TIMING_CFG, 0x0000002F);
+ write32(gx_base + DC_OUTPUT_CFG, 0x00003004);
+}
+
+/**
+ * Activate the current mode to be "visible" outside
+ * @param[in] gx_base GX register area
+ * @param[in] mode Data about the video mode to setup
+ *
+ * As we now activate the interface this must be done
+ * in the CS5530
+ */
+static void cs5530_activate_video(u32 io_base, const struct video_mode *mode)
+{
+ u32 val;
+
+ val = (u32)mode->sync_pol << 8;
+ write32(io_base + CS5530_DISPLAY_CONFIG, val | 0x0020002F);
+}
+
+#if CONFIG_SPLASH_GRAPHIC == 1
+
+/*
+ * This bitmap file must provide:
+ * int width: pixel count in one line
+ * int height: line count
+ * int colours: ount of used colour
+ * unsigned long colour_map[]: RGB 565 colours to be used
+ * unsigned char bitmap[]: index per pixel into colour_map[], width*height pixels
+ */
+#include "bitmap.c"
+
+/*
+ * show a boot splash screen in the right lower corner of the screen
+ * swidth: screen width in pixel
+ * sheight: screen height in lines
+ * pitch: line pitch in bytes
+ * base: screen base address
+ *
+ * This routine assumes we are using a 16 bit colour depth!
+ */
+static void show_boot_splash_16(u32 swidth, u32 sheight, u32 pitch,void *base)
+{
+ int word_count,i;
+ unsigned short *adr;
+ u32 xstart,ystart,x,y;
+ /*
+ * fill the screen with the colour of the
+ * left top pixel in the graphic
+ */
+ word_count = pitch * sheight;
+ adr = (unsigned short*)base;
+ for (i = 0; i < word_count; i++, adr++)
+ *adr = colour_map[bitmap[0]];
+
+ /*
+ * paint the splash
+ */
+ xstart = swidth-width;
+ ystart = sheight-height;
+ for (y = 0; y < height; y++) {
+ adr=(unsigned short*)(base + pitch*(y+ystart) + 2 * xstart);
+ for (x = 0; x < width; x++) {
+ *adr=(unsigned short)colour_map[(int)bitmap[x + y * width]];
+ adr++;
+ }
+ }
+}
+#else
+# define show_boot_splash_16(w, x, y , z)
+#endif
+
+/**
+ * coreboot management part
+ * @param[in] dev Info about the PCI device to initialise
+ */
+static void cs5530_vga_init(device_t dev)
+{
+ const struct video_mode *mode;
+ u32 io_base, gx_base;
+
+ io_base = pci_read_config32(dev, 0x10);
+ gx_base = GX_BASE;
+ mode = modes[CONFIG_GX1_VIDEOMODE];
+
+ printk(BIOS_DEBUG, "Setting up video mode %dx%d with %d Hz clock\n",
+ mode->visible_pixel, mode->visible_lines, mode->pixel_clock);
+
+ cs5530_set_clock_frequency(io_base, mode->pll_value);
+
+ write32(gx_base + DC_UNLOCK, DC_UNLOCK_MAGIC);
+
+ show_boot_splash_16(mode->visible_pixel, mode->visible_lines,
+ mode->visible_pixel * (COLOUR_DEPTH>>3), (void*)(GX_BASE + 0x800000));
+
+ cs5530_activate_mode(gx_base, mode);
+
+ cs5530_activate_video(io_base, mode);
+ write32(gx_base + DC_UNLOCK, 0x00000000);
+}
+
+static struct device_operations vga_ops = {
+ .read_resources = pci_dev_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = cs5530_vga_init,
+ .enable = NULL, /* not required */
+};
+
+static const struct pci_driver vga_pci_driver __pci_driver = {
+ .ops = &vga_ops,
+ .vendor = PCI_VENDOR_ID_CYRIX,
+ .device = PCI_DEVICE_ID_CYRIX_5530_VIDEO,
+};
+
+#endif /* #if CONFIG_GX1_VIDEO == 1 */