diff options
Diffstat (limited to 'src/northbridge/via/vx900/chrome9hd.c')
-rw-r--r-- | src/northbridge/via/vx900/chrome9hd.c | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/src/northbridge/via/vx900/chrome9hd.c b/src/northbridge/via/vx900/chrome9hd.c new file mode 100644 index 0000000000..633328e164 --- /dev/null +++ b/src/northbridge/via/vx900/chrome9hd.c @@ -0,0 +1,368 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com> + * + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <arch/io.h> +#include <config.h> +#include <console/console.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <pc80/vga_io.h> + +#include "vx900.h" + +#define CHROME_9_HD_MIN_FB_SIZE 8 +#define CHROME_9_HD_MAX_FB_SIZE 512 + +/** + * @file chrome9hd.c + * + * \brief Initialization for Chrome9HD integrated graphics adapters + * + * This takes care of the initialization we need to do before calling the VGA + * BIOS. The device is not documented in the VX900 datasheet. + * + * The device is documented in: + * Open Graphics Programming Manual + * Chrome9GraphicsHD Processor + * VX900 Series System Processor + * Part I: Graphics Core / 2D + * + * This document was released by VIA to the Xorg project, and is available at: + * <http://www.x.org/docs/via/OGPM_Chrome9%20HD%20DX9%20_R100_PartI_Core_2D.pdf> + * + * STATUS: + * We do the minimal initialization described in VIA documents. Running the VGA + * option ROM does not get us a usable display. We configure the framebuffer and + * the IGP is able to use it. GRUB2 and linux are capable of getting a usable + * text console, which uses the monitor's native resolution (even 1920x1080). + * The graphical console (linux) does not work properly. + * @TODO + * 1. Figure out what sequence we need to do to get the VGA BIOS running + * properly. Use the code provided by VIA and compare their sequence to ours, + * fill in any missing steps, etc. + * 2. Make BAR2 and the framebuffer use the same memory space. This is a feature + * called "Direct framebuffer access" which allows us to save memory space by + * setting BAR2 of the VGA to the location in memory of the framebuffer. This + * reduces the amount of PCI MMIO space we need below 4G, and is especially + * useful considering we only have 8GB (33 bits) of memory-mapped space. + */ + +/* Helper to determine the framebuffer size */ +u32 chrome9hd_fb_size(void) +{ + static u32 fb_size = 0; + u8 reg8, ranksize; + u32 size_mb, tom_mb, max_size_mb; + int i; + /* We do some PCI and CMOS IO to find our value, so if we've already + * found it, save some time */ + if (fb_size != 0) + return fb_size; + /* FIXME: read fb_size from CMOS, but until that is implemented, start + * from 512MB */ + size_mb = 512; + + /* The minimum framebuffer size is 8MB. */ + size_mb = max(size_mb, CHROME_9_HD_MIN_FB_SIZE); + + const device_t mcu = dev_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_MEMCTRL, + 0); + /* + * We have two limitations on the maximum framebuffer size: + * 1) (Sanity) No more that 1/4 of system RAM + * 2) (Hardware limitation) No larger than DRAM in last rank + * Check both of these limitations and apply them to our framebuffer */ + tom_mb = (pci_read_config16(mcu, 0x88) & 0x07ff) << (24 - 20); + max_size_mb = tom_mb >> 2; + if (size_mb > max_size_mb) { + printk(BIOS_ALERT, "The framebuffer size of of %dMB is larger" + " than 1/4 of available memory.\n" + " Limiting framebuffer to %dMB\n", size_mb, max_size_mb); + size_mb = max_size_mb; + } + + /* Now handle limitation #2 + * Look at the ending address of the memory ranks, from last to first, + * until we find one that is not zero. That is our last rank, and its + * size is the limit of our framebuffer. */ + /* FIXME: This has a bug. If we remap memory above 4G, we consider the + * memory hole as part of our RAM. Thus if we install 3G, with a TOLM of + * 2.5G, our TOM will be at 5G and we'll assume we have 5G RAM instead + * of the actual 3.5G */ + for (i = VX900_MAX_MEM_RANKS - 1; i > -1; i--) { + reg8 = pci_read_config8(mcu, 0x40 + i); + if (reg8 == 0) + continue; + /* We've reached the last populated rank */ + ranksize = reg8 - pci_read_config8(mcu, 0x48 + i); + max_size_mb = ranksize << 6; + /* That's it. We got what we needed. */ + break; + }; + if (size_mb > max_size_mb) { + printk(BIOS_ALERT, "The framebuffer size of %dMB is larger" + " than size of the last DRAM rank.\n" + " Limiting framebuffer to %dMB\n", size_mb, max_size_mb); + size_mb = max_size_mb; + } + + /* Now round the framebuffer size to the closest power of 2 */ + u8 fb_pow = 0; + while (size_mb >> fb_pow) + fb_pow++; + fb_pow--; + size_mb = (1 << fb_pow); + /* We store the framebuffer size in bytes, for simplicity */ + fb_size = size_mb << 20; + return fb_size; +} + +/** + * @defgroup vx900_int15 + * + * \brief INT15 helpers for Chrome9HD IGP + * + * The following are helpers for INT15 handlers for the VGA BIOS. The full set + * of INT15 callbacks is described in + * + * VIA/S3Graphics + * Video BIOS External Interface Specification for Chrome9 Series IGP + * VX900 Series + * + * This document is only available under NDA, however, the callbacks are very + * similar to other VIA/Intel IGP callbacks. + * + * Callback 0x5f18 is the most important one. It informs the VGA BIOS of the + * RAM speed and framebuffer size. The other callbacks seem to be optional. + * @{ + */ + +/** + * \brief Get X86_BL value for VGA INT15 function 5f18 + * + * Int15 5f18 lets the VGA BIOS know the framebuffer size and the memory speed. + * This handler is very important. If it is not implemented, the VGA BIOS will + * not work correctly. + * + * To use, just call this from the 15f18 handler, and place the return value in + * X86_BL + * + * @code{.c} + * case 0x5f18: + * X86_BX = vx900_int15_get_5f18_bl(); + * res = 0; + * break; + * @endcode + * + */ +u8 vx900_int15_get_5f18_bl(void) +{ + u8 reg8, ret; + device_t dev; + /* + * BL Bit[7:4] + * Memory Data Rate (not to be confused with fCLK) + * 0000: 66MHz + * 0001: 100MHz + * 0010: 133MHz + * 0011: 200MHz ( DDR200 ) + * 0100: 266MHz ( DDR266 ) + * 0101: 333MHz ( DDR333 ) + * 0110: 400MHz ( DDR400 ) + * 0111: 533MHz ( DDR I/II 533) + * 1000: 667MHz ( DDR I/II 667) + * 1001: 800MHz ( DDR3 800) + * 1010: 1066MHz ( DDR3 1066) + * 1011: 1333MHz ( DDR3 1333) + * Bit[3:0] + * N: Frame Buffer Size 2^N MB + */ + dev = dev_find_slot(0, PCI_DEVFN(0, 3)); + reg8 = pci_read_config8(dev, 0xa1); + ret = (u32) ((reg8 & 0x70) >> 4) + 2; + reg8 = pci_read_config8(dev, 0x90); + reg8 = ((reg8 & 0x07) + 3) << 4; + ret |= (u32) reg8; + + return ret; +} +/** @} */ + +static void chrome9hd_set_sid_vid(u16 vendor, u16 device) +{ + vga_sr_write(0x36, vendor >> 8); /* SVID high byte */ + vga_sr_write(0x35, vendor & 0xff); /* SVID low byte */ + vga_sr_write(0x38, device >> 8); /* SID high byte */ + vga_sr_write(0x37, device & 0xff); /* SID low byte */ +} + +static void chrome9hd_handle_uma(device_t dev) +{ + /* Mirror mirror, shiny glass, tell me that is not my ass */ + u32 fb_size = chrome9hd_fb_size() >> 20; + + //uma_resource(dev, 0x18, uma_memory_base>>10, uma_memory_size>>10); + + printk(BIOS_DEBUG, "UMA base 0x%.8llx (%lluMB)\n", uma_memory_base, + uma_memory_base >> 20); + printk(BIOS_DEBUG, "UMA size 0x%.8llx (%lluMB)\n", uma_memory_size, + uma_memory_size >> 20); + u8 fb_pow = 0; + while (fb_size >> fb_pow) + fb_pow++; + fb_pow--; + + /* Step 6 - Let MCU know the framebuffer size */ + device_t mcu = dev_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_MEMCTRL, 0); + pci_mod_config8(mcu, 0xa1, 7 << 4, (fb_pow - 2) << 4); + + /* Step 7 - Let GFX know the framebuffer size (through PCI and IOCTL) + * The size we set here affects the behavior of BAR2, and the amount of + * MMIO space it requests. The default is 512MB, so if we don't set this + * before reading the resources, we could waste space below 4G */ + pci_write_config8(dev, 0xb2, ((0xff << (fb_pow - 2)) & ~(1 << 7))); + vga_sr_write(0x68, (0xff << (fb_pow - 1))); + /* And also that the framebuffer is in the system, RAM */ + pci_mod_config8(dev, 0xb0, 0, 1 << 0); +} + +/** + * \brief Initialization sequence before running the VGA BIOS + * + * This is the initialization sequence described in: + * + * BIOS Porting Guide + * VX900 Series + * All-in-One System Processor + * + * This document is only available under NDA. + */ +static void chrome9hd_biosguide_init_seq(device_t dev) +{ + device_t mcu = dev_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_MEMCTRL, 0); + device_t host = dev_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_HOST_BR, 0); + + /* Step 1 - Enable VGA controller */ + /* FIXME: This is the VGA hole @ 640k-768k, and the vga port io + * We need the port IO, but can we disable the memory hole? */ + pci_mod_config8(mcu, 0xa4, 0, (1 << 7)); /* VGA memory hole */ + + /* Step 2 - Forward MDA cycles to GFX */ + pci_mod_config8(host, 0x4e, 0, (1 << 1)); + + /* Step 3 - Enable GFX I/O space */ + pci_mod_config8(dev, PCI_COMMAND, 0, PCI_COMMAND_IO); + + /* Step 4 - Enable video subsystem */ + vga_enable_mask((1 << 0), (1 << 0)); + + /* FIXME: VGA IO Address Select. 3B5 or 3D5? */ + vga_misc_mask((1 << 0), (1 << 0)); + + /* Step 5 - Unlock accessing of IO space */ + vga_sr_write(0x10, 0x01); + + chrome9hd_handle_uma(dev); + + /* Step 8 - Enable memory base register on the GFX */ + if (uma_memory_base == 0) + die("uma_memory_base not set. Abandon ship!\n"); + printk(BIOS_DEBUG, "UMA base 0x%.10llx (%lluMB)\n", uma_memory_base, + uma_memory_base >> 20); + vga_sr_write(0x6d, (uma_memory_base >> 21) & 0xff); /* base 28:21 */ + vga_sr_write(0x6e, (uma_memory_base >> 29) & 0xff); /* base 36:29 */ + vga_sr_write(0x6f, 0x00); /* base 43:37 */ + + /* Step 9 - Set SID/VID */ + chrome9hd_set_sid_vid(0x1106, 0x7122); + +} + +static void chrome9hd_init(device_t dev) +{ + print_debug("======================================================\n"); + print_debug("== Chrome9 HD INIT\n"); + print_debug("======================================================\n"); + + chrome9hd_biosguide_init_seq(dev); + + /* Prime PLL FIXME: bad comment */ + vga_sr_mask(0x3c, 1 << 2, 1 << 2); + + /* FIXME: recheck; VGA IO Address Select. 3B5 or 3D5? */ + vga_misc_mask(1 << 0, 1 << 0); + + /* FIXME: recheck; Enable Base VGA 16 Bits Decode */ + ////pci_mod_config8(host, 0x4e, 0, 1<<4); + + u32 fb_address = pci_read_config32(dev, PCI_BASE_ADDRESS_2); + fb_address &= ~0x0F; + if (!fb_address) { + printk(BIOS_WARNING, "Chrome9HD: No FB BAR assigned!\n"); + return; + } + + printk(BIOS_INFO, "Chrome: Using %dMB Framebuffer at 0x%08X.\n", + 256, fb_address); + + printk(BIOS_DEBUG, "Initializing VGA...\n"); + + pci_dev_init(dev); + + printk(BIOS_DEBUG, "Enable VGA console\n"); + + dump_pci_device(dev); +} + +static void chrome9hd_enable(device_t dev) +{ + device_t mcu = dev_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_MEMCTRL, 0); + /* FIXME: here? -=- ACLK 250Mhz */ + pci_mod_config8(mcu, 0xbb, 0, 0x01); +} + +static void chrome9hd_disable(device_t dev) +{ + device_t mcu = dev_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_VX900_MEMCTRL, 0); + /* Disable GFX - This step effectively renders the GFX inert + * It won't even show up as a PCI device during enumeration */ + pci_mod_config8(mcu, 0xa1, 1 << 7, 0); +} + +static struct device_operations chrome9hd_operations = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = chrome9hd_init, + .disable = chrome9hd_disable, + .enable = chrome9hd_enable, + .ops_pci = 0, +}; + +static const struct pci_driver chrome9hd_driver __pci_driver = { + .ops = &chrome9hd_operations, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_VX900_VGA, +}; |