diff options
author | Arthur Heymans <arthur@aheymans.xyz> | 2019-11-19 15:42:02 +0100 |
---|---|---|
committer | Kyösti Mälkki <kyosti.malkki@gmail.com> | 2019-11-20 18:32:42 +0000 |
commit | 0fd398a5a151fec4b3e5f257322b21a84ca48e87 (patch) | |
tree | 55253ac38064705b8e9509eb06938ac7249e814e /src/northbridge | |
parent | 4c38ed3c38ac5ef0136bf5d5c893d8b71d82b531 (diff) | |
download | coreboot-0fd398a5a151fec4b3e5f257322b21a84ca48e87.tar.xz |
nb/via/vx900: Drop support
Relocatable ramstage, postcar stage and C_ENVIRONMENT_BOOTBLOCK are
now mandatory features, which this platform lacks.
Change-Id: Ie971893da06fd3b1ac41dda398b1caeec3ee32db
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/36951
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: HAOUAS Elyes <ehaouas@noos.fr>
Reviewed-by: Nico Huber <nico.h@gmx.de>
Diffstat (limited to 'src/northbridge')
21 files changed, 0 insertions, 4155 deletions
diff --git a/src/northbridge/via/vx900/Kconfig b/src/northbridge/via/vx900/Kconfig deleted file mode 100644 index 8d95942866..0000000000 --- a/src/northbridge/via/vx900/Kconfig +++ /dev/null @@ -1,48 +0,0 @@ -## -## This file is part of the coreboot project. -## -## Copyright (C) 2011 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. -## - -config NORTHBRIDGE_VIA_VX900 - bool - select IOAPIC - select DRIVERS_GENERIC_IOAPIC - select HAVE_DEBUG_RAM_SETUP - select HAVE_DEBUG_SMBUS - select HAVE_CF9_RESET - select NO_RELOCATABLE_RAMSTAGE - -if NORTHBRIDGE_VIA_VX900 - -config MAX_PIRQ_LINKS - int - default 8 - -config MMCONF_BASE_ADDRESS - hex - default 0xe0000000 - -config MMCONF_BUS_NUMBER - int - default 256 - -config VGA_BIOS_ID - string - default "1106,7122" - -config BOOTBLOCK_NORTHBRIDGE_INIT - string - default "northbridge/via/vx900/bootblock.c" - -endif diff --git a/src/northbridge/via/vx900/Makefile.inc b/src/northbridge/via/vx900/Makefile.inc deleted file mode 100644 index 247cc249bf..0000000000 --- a/src/northbridge/via/vx900/Makefile.inc +++ /dev/null @@ -1,50 +0,0 @@ -## -## This file is part of the coreboot project. -## -## Copyright (C) 2011-2013 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. -## - -ifeq ($(CONFIG_NORTHBRIDGE_VIA_VX900),y) - -romstage-y += pci_util.c -romstage-y += early_smbus.c -romstage-y += early_vx900.c -romstage-y += early_host_bus_ctl.c -romstage-y += raminit_ddr3.c -romstage-y += memmap.c -romstage-y += ./../../../device/dram/ddr3.c -romstage-y += ./../../../southbridge/via/common/early_smbus_delay.c -romstage-y += ./../../../southbridge/via/common/early_smbus_is_busy.c -romstage-y += ./../../../southbridge/via/common/early_smbus_print_error.c -romstage-y += ./../../../southbridge/via/common/early_smbus_reset.c -romstage-y += ./../../../southbridge/via/common/early_smbus_wait_until_ready.c - -ramstage-y += pci_util.c -ramstage-y += pcie.c -ramstage-y += northbridge.c -ramstage-y += chrome9hd.c -ramstage-y += traf_ctrl.c -ramstage-y += sata.c -ramstage-y += lpc.c -ramstage-y += memmap.c - -# The buildsystem only includes this file if CONFIG_VGA is selected. -# We need to do some VGA I/O before the VGA can be initialized. We can make good -# use of some of the functions there, so include them unconditionally -ramstage-y += ./../../../drivers/pc80/vga/vga_io.c - - -bootblock-y += romstrap.ld -bootblock-y += romstrap.S - -endif diff --git a/src/northbridge/via/vx900/bootblock.c b/src/northbridge/via/vx900/bootblock.c deleted file mode 100644 index 6679cdb31b..0000000000 --- a/src/northbridge/via/vx900/bootblock.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2017 Lubomir Rintel <lkundrak@v3.sk> - * - * 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. - */ - -#include <device/pci_ops.h> - -#if CONFIG_ROM_SIZE == 0x80000 -# define ROM_DECODE_MAP 0x00 -#elif CONFIG_ROM_SIZE == 0x100000 -# define ROM_DECODE_MAP 0x40 -#elif CONFIG_ROM_SIZE == 0x180000 -# define ROM_DECODE_MAP 0x60 -#elif CONFIG_ROM_SIZE == 0x200000 -# define ROM_DECODE_MAP 0x70 -#elif CONFIG_ROM_SIZE == 0x280000 -# define ROM_DECODE_MAP 0x78 -#elif CONFIG_ROM_SIZE == 0x300000 -# define ROM_DECODE_MAP 0x7c -#elif CONFIG_ROM_SIZE == 0x380000 -# define ROM_DECODE_MAP 0x7e -#elif CONFIG_ROM_SIZE == 0x400000 -# define ROM_DECODE_MAP 0x7f -#else -# error "Bad CONFIG_ROM_SIZE" -#endif - -static void bootblock_northbridge_init(void) -{ - u8 reg; - - pci_io_read_config8(PCI_DEV(0, 0x11, 0), 0x41); - reg |= ROM_DECODE_MAP; - pci_io_write_config8(PCI_DEV(0, 0x11, 0), 0x41, reg); -} diff --git a/src/northbridge/via/vx900/chip.h b/src/northbridge/via/vx900/chip.h deleted file mode 100644 index 91a7a3d119..0000000000 --- a/src/northbridge/via/vx900/chip.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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. - */ - -#ifndef __VIA_VX900_CHIP_H__ -#define __VIA_VX900_CHIP_H__ - -struct northbridge_via_vx900_config { - /** - * \brief PCIe Lane[3:0] Function Select - * - * PCIe Lane3~Lane0 (PEXTX[3:0]P/VCC) can be used by the integrated - * graphic controller to output its display data. The PCIe lanes will - * be used to output DisplayPort data. - */ - u8 assign_pex_to_dp; - - /** - * \brief Lane Width for Root Port 1 - * - * Two PCIe lanes are used for Root port 1. Root port 2 is disabled. - */ - u8 pcie_port1_2_lane_wide; - - /** - * \brief PIRQ line to which to route the external interrupt - * - * The VX900 features an external interrupt which can be routed to any - * of the PIRQA->PIRQH lines. Usually, on-board devices are connected - * to the external interrupt. In some vendor BIOS's pirq table, this - * appears as link 9. - * - * Setting this line only affects the behavior of the integrated PIC. It - * has no effect on the IOAPIC. - * - * The value of this register must be a literal upper-case character - * from 'A' to 'H'. - */ - char ext_int_route_to_pirq; -}; - -#endif diff --git a/src/northbridge/via/vx900/chrome9hd.c b/src/northbridge/via/vx900/chrome9hd.c deleted file mode 100644 index fef53502f8..0000000000 --- a/src/northbridge/via/vx900/chrome9hd.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * 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. - */ - -#include <device/pci_ops.h> -#include <console/console.h> -#include <device/pci.h> -#include <device/pci_ids.h> -#include <pc80/vga_io.h> -#include <stdlib.h> - -#include "vx900.h" - -/** - * @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. - */ - -/** - * 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; - struct device *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 = pcidev_on_root(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(struct device *dev) -{ - u8 fb_pow = vx900_get_chrome9hd_fb_pow(); - - if (fb_pow == 0) - return; - - /* 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_or_config8(dev, 0xb0, 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(struct device *dev) -{ - struct device *mcu = dev_find_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_VX900_MEMCTRL, 0); - struct device *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_or_config8(mcu, 0xa4, (1 << 7)); /* VGA memory hole */ - - /* Step 2 - Forward MDA cycles to GFX */ - pci_or_config8(host, 0x4e, (1 << 1)); - - /* Step 3 - Enable GFX I/O space */ - pci_or_config8(dev, PCI_COMMAND, 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); - - uint64_t gfx_base = get_uma_memory_base(); - if (gfx_base == 0) - die("uma_memory_base not set. Abandon ship!\n"); - - /* Step 8 - Enable memory base register on the GFX */ - vga_sr_write(0x6d, (gfx_base >> 21) & 0xff); /* base 28:21 */ - vga_sr_write(0x6e, (gfx_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(struct device *dev) -{ - printk(BIOS_DEBUG, "======================================================\n"); - printk(BIOS_DEBUG, "== Chrome9 HD INIT\n"); - printk(BIOS_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 */ - - 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(PCI_BDF(dev)); -} - -static void chrome9hd_enable(struct device *dev) -{ - struct device *mcu = dev_find_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_VX900_MEMCTRL, 0); - /* FIXME: here? -=- ACLK 250MHz */ - pci_or_config8(mcu, 0xbb, 0x01); -} - -static void chrome9hd_disable(struct device *dev) -{ - struct device *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_update_config8(mcu, 0xa1, (u8)~(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, -}; diff --git a/src/northbridge/via/vx900/early_host_bus_ctl.c b/src/northbridge/via/vx900/early_host_bus_ctl.c deleted file mode 100644 index 1ef29449fd..0000000000 --- a/src/northbridge/via/vx900/early_host_bus_ctl.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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. - */ - -#include <device/pci_ops.h> - -#include "early_vx900.h" - -static void vx900_cpu_bus_preram_setup(void) -{ - /* Faster CPU to DRAM Cycle */ - pci_update_config8(HOST_BUS, 0x50, ~0x0f, 0x08); - /* CPU Interface Control - Basic Options */ - pci_or_config8(HOST_BUS, 0x51, 0x6c); - /*CPU Interface Control - Advanced Options */ - pci_write_config8(HOST_BUS, 0x52, 0xc7); - /* Enable 8QW burst and 4QW request merging [4] and [2] - * and special mode for read cycles bit[3] */ - pci_or_config8(HOST_BUS, 0x54, (1 << 4) | (1 << 2) | (1 << 3)); - /* High priority upstream requests on V4 bus */ - pci_write_config8(HOST_BUS, 0x56, 0x03); - /* CPU to DRAM extra 1T access control */ - pci_or_config8(HOST_BUS, 0x59, (1 << 2)); - /* Queue reordering */ - pci_or_config8(HOST_BUS, 0x5f, (1 << 6)); - /* Only Write cycle of CPU->GFXCTL will flush the CPU->Memory FIFO */ - pci_or_config8(HOST_BUS, 0x98, 0x60); - /* 1T delay for data on CPU bus */ - pci_write_config8(HOST_BUS, 0x9e, 0x0e); - /* Arbitrate ownership of DRAM controller a few cycles earlier */ - pci_or_config8(HOST_BUS, 0x9f, (1 << 7)); - /* Write retire policy */ - pci_write_config8(HOST_BUS, 0x5d, 0xa2); - /* Occupancy timer */ - pci_write_config8(HOST_BUS, 0x53, 0x44); - /* Medium Threshold for Write Retire Policy - 6 requests */ - pci_or_config8(HOST_BUS, 0x56, 0x60); - /* Bandwidth timer */ - pci_write_config8(HOST_BUS, 0x5e, 0x44); -} - -/** - * \brief Configure the CPU to northbridge bus (formerly, FSB) - * - * Configure the CPU <-> host interface. This interface is complex and needs to - * be set up to operate properly. Configured parameters include bandwidth - * arbitration. This function does not, however, change the physical interface - * parameters, such as drive strength and signal timing. Instead, it assumes - * that those parameters were already configured correctly from the ROMSTRAP. - */ -void vx900_cpu_bus_interface_setup(void) -{ - vx900_cpu_bus_preram_setup(); - - dump_pci_device(HOST_BUS); -} diff --git a/src/northbridge/via/vx900/early_smbus.c b/src/northbridge/via/vx900/early_smbus.c deleted file mode 100644 index 5816926f59..0000000000 --- a/src/northbridge/via/vx900/early_smbus.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2011 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. - */ - -#include <device/pci_ids.h> -#include "early_vx900.h" -#include <device/early_smbus.h> - -#include <arch/io.h> -#include <device/pci_ops.h> -#include <console/console.h> - -/** - * \brief SMBUS IO ports in relation to the base IO port - */ -#define SMBHSTSTAT(base) (u16)(u32)base + 0x0 -#define SMBSLVSTAT(base) (u16)(u32)base + 0x1 -#define SMBHSTCTL(base) (u16)(u32)base + 0x2 -#define SMBHSTCMD(base) (u16)(u32)base + 0x3 -#define SMBXMITADD(base) (u16)(u32)base + 0x4 -#define SMBHSTDAT0(base) (u16)(u32)base + 0x5 -#define SMBHSTDAT1(base) (u16)(u32)base + 0x6 -#define SMBBLKDAT(base) (u16)(u32)base + 0x7 -#define SMBSLVCTL(base) (u16)(u32)base + 0x8 -#define SMBTRNSADD(base) (u16)(u32)base + 0x9 -#define SMBSLVDATA (base) (u16)(u32)base + 0xa - -static void smbus_delays(int delays) -{ - while (delays--) - smbus_delay(); -} - -/** - * Read a byte from the SMBus. - * - * @param smbus_dev The PCI address of the SMBus device . - * @param addr The address location of the DIMM on the SMBus. - * @param offset The offset the data is located at. - */ -u8 smbus_read_byte(u32 smbus_dev, u8 addr, u8 offset) -{ - u8 val; - - /* Initialize SMBUS sequence */ - smbus_reset(smbus_dev); - /* Clear host data port. */ - outb(0x00, SMBHSTDAT0(smbus_dev)); - - smbus_wait_until_ready(smbus_dev); - smbus_delays(50); - - /* Actual addr to reg format. */ - addr = (addr << 1); - addr |= 1; /* read command */ - outb(addr, SMBXMITADD(smbus_dev)); - outb(offset, SMBHSTCMD(smbus_dev)); - /* Start transaction, byte data read. */ - outb(0x48, SMBHSTCTL(smbus_dev)); - smbus_wait_until_ready(smbus_dev); - - val = inb(SMBHSTDAT0(smbus_dev)); - return val; -} - -void enable_smbus(void) -{ - pci_devfn_t dev; - u8 reg8; - u32 smbus_dev = (u32) SMBUS_IO_BASE; - - /* Locate the Power Management control */ - dev = pci_locate_device(PCI_ID(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_VX900_LPC), 0); - - if (dev == PCI_DEV_INVALID) { - die("Power Management Controller not found\n"); - } - - /* - * To use SMBus to manage devices on the system board, it is a must to - * enable SMBus function by setting - * PMU_RXD2[0] (SMBus Controller Enable) to 1. - * And set PMU_RXD0 and PMU_RXD1 (SMBus I/O Base) to an appropriate - * I/O port address, so that all registers in SMBus I/O port can be - * accessed. - */ - - reg8 = pci_read_config8(dev, 0xd2); - /* Enable SMBus controller */ - reg8 |= 1; - /* Set SMBUS clock from 128k source */ - reg8 |= 1 << 2; - pci_write_config8(dev, 0xd2, reg8); - - reg8 = pci_read_config8(dev, 0x94); - /* SMBUS clock from divider of 14.318 MHz */ - reg8 &= ~(1 << 7); - pci_write_config8(dev, 0x94, reg8); - - /* Set SMBus IO base */ - pci_write_config16(dev, 0xd0, SMBUS_IO_BASE); - - /* - * Initialize the SMBus sequence: - */ - /* Clear SMBus host status register */ - smbus_reset(smbus_dev); - /* Clear SMBus host data 0 register */ - outb(0x00, SMBHSTDAT0(smbus_dev)); - - /* Wait for SMBUS */ - smbus_wait_until_ready(smbus_dev); - -} - -static int spd_get_length(u8 spd_byte0) -{ - spd_byte0 &= 0xf; - - switch (spd_byte0) { - case 0x3: - return 256; - case 0x2: - return 176; - case 0x1: - return 128; - default: - break; - } - return 0; -} - -void spd_read(u8 addr, spd_raw_data spd) -{ - u8 reg; - int i, regs; - u32 smbus_dev = SMBUS_IO_BASE; - - reg = smbus_read_byte(smbus_dev, addr, 2); - if (reg != 0x0b) { - printk(BIOS_DEBUG, "SMBUS device %x not a DDR3 module\n", addr); - spd[2] = 0; - return; - } - - reg = smbus_read_byte(smbus_dev, addr, 0); - if ((regs = spd_get_length(reg)) == 0) { - printk(BIOS_INFO, "No DIMM present at %x\n", addr); - spd[2] = 0; - return; - } - - for (i = 0; i < regs; i++) - spd[i] = smbus_read_byte(smbus_dev, addr, i); -} - -void dump_spd_data(spd_raw_data spd) -{ - int len, i; - u8 reg; - - if ((len = spd_get_length(spd[0])) == 0) { - printk(BIOS_DEBUG, "Invalid SPD\n"); - return; - } - - /* - * I originally saw this way to present SPD data in code from VIA. I - * really liked the idea, so here it goes. - */ - printk(BIOS_DEBUG, " 00 01 02 03 04 05 06 07 07 09 0A 0B 0C 0D 0E 0F\n"); - printk(BIOS_DEBUG, "---+------------------------------------------------"); - for (i = 0; i < len; i++) { - reg = spd[i]; - if ((i & 0x0f) == 0) - printk(BIOS_DEBUG, "\n%.2x |", i); - printk(BIOS_DEBUG, " %.2x", reg); - } - printk(BIOS_DEBUG, "\n"); -} diff --git a/src/northbridge/via/vx900/early_vx900.c b/src/northbridge/via/vx900/early_vx900.c deleted file mode 100644 index e50b96812d..0000000000 --- a/src/northbridge/via/vx900/early_vx900.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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. - */ - -#include "early_vx900.h" -#include <device/pci_ops.h> -#include <console/console.h> - -/** - * \brief Enable accessing of PCI configuration space for all devices. - * - * Enable accessing of D0F1 through D0F7, which would otherwise not be - * accessible. If MMCONF is enabled, configure it here. This is the first - * function that should be called in romstage. - */ -void vx900_enable_pci_config_space(void) -{ - /* MMCONF is not yet enabled, so we'll need to specify we want to do - * pci_io. We don't want to do pci_mmio until we enable it */ - /* Enable multifunction bit for northbridge. - * This enables the PCI configuration spaces of D0F1 to D0F7 to be - * accessed */ - pci_io_write_config8(HOST_CTR, 0x4f, 0x01); - - /* COOL, now enable MMCONF */ - u8 reg8 = pci_io_read_config8(TRAF_CTR, 0x60); - reg8 |= 3; - pci_io_write_config8(TRAF_CTR, 0x60, reg8); - - reg8 = CONFIG_MMCONF_BASE_ADDRESS >> 28; - pci_io_write_config8(TRAF_CTR, 0x61, reg8); -} - -/** - *\brief Prints information regarding the hardware strapping on VX900 - * - * Certain features on the VX900 are controlled by strapping pins which are - * hardwired on the mainboard. These values determine whether the ROM is on the - * SPI or LPC bus, or whether auto-reset is enabled. - * \n - * Having a feel for these values is important when trying to fix obscure - * problems found when porting a mainboard based on the VX900. - * \n - * These values are decoded and printed to the terminal. - */ -void vx900_print_strapping_info(void) -{ - u8 strap = pci_read_config8(SNMIC, 0x56); - - printk(BIOS_DEBUG, "VX900 strapping pins indicate that:\n"); - printk(BIOS_DEBUG, " ROM is on %s bus\n", - (strap & (1 << 0)) ? "SPI" : "LPC"); - printk(BIOS_DEBUG, " Auto reset is %s\n", - (strap & (1 << 1)) ? "disabled" : "enabled"); - printk(BIOS_DEBUG, " LPC FWH command is %s\n", - (strap & (1 << 2)) ? "enabled" : "disabled"); - printk(BIOS_DEBUG, " Debug link is is %s\n", - (strap & (1 << 4)) ? "enabled" : "disabled"); - printk(BIOS_DEBUG, " PCI master mode is %s\n", - (strap & (1 << 5)) ? "enabled" : "disabled"); -} - -/** - *\brief Disables the auto-reboot mechanism on VX900 - * - * The VX900 has an auto-reboot mechanism that can be enabled by a hardware - * strap. This mechanism can make development annoying, since we don't know if - * the reset was caused by a bug in coreboot, or by this mechanism. - */ -void vx900_disable_auto_reboot(void) -{ - if (pci_read_config8(SNMIC, 0x56) & (1 << 1)) { - printk(BIOS_DEBUG, "Auto-reboot is disabled in hardware\n"); - return; - } - /* Disable the GP3 timer, which is the root of all evil */ - pci_write_config8(LPC, 0x98, 0); - /* Yep, that's all it takes */ - printk(BIOS_DEBUG, "GP3 timer disabled." - " Auto-reboot should not give you any more trouble.\n"); -} - -/** - * \brief Disables 'shadowing' of system ROM - * - * Disable unnecessary shadowing of the ROM in the first 1MB of address space. - * coreboot runs in 32-bit mode from the start. Shadowing only gets in the way. - * This function frees the entire 640k-1M range for DRAM. VGA may still use - * the 640k-768k range, if enabled later. - */ -void vx900_disable_legacy_rom_shadow(void) -{ - pci_write_config8(MCU, 0x80, 0xff); /* LPC ROM 768k - 832k */ - pci_write_config8(MCU, 0x81, 0xff); /* LPC ROM 832k - 896k */ - pci_write_config8(MCU, 0x82, 0xff); /* LPC ROM 896k - 960k */ - /* LPC ROM 960k - 1M * SMRAM: 640k - 768k */ - pci_write_config8(MCU, 0x83, 0x31); - - /* Bits 6:0 are the ROM shadow on top of 4G, so leave those untouched */ - pci_update_config8(LPC, 0x41, (u8)~(1 << 7), 0); /* LPC ROM 896k - 960k */ - - pci_write_config8(SNMIC, 0x61, 0); /* 768k - 832k */ - pci_write_config8(SNMIC, 0x62, 0); /* 832k - 896k */ - pci_write_config8(SNMIC, 0x63, 0); /* 896k - 1M */ - pci_write_config8(SNMIC, 0x64, 0); /* 896k - 960k */ -} - -/** - * \brief Disables the VX900 integrated graphics controller - * - * Disable the graphics controller entirely. It will no longer be visible as a - * PCI device. - */ -void vx900_disable_gfx(void) -{ - /* Disable GFX */ - pci_update_config8(MCU, 0xa1, (u8)~(1 << 7), 0); -} diff --git a/src/northbridge/via/vx900/early_vx900.h b/src/northbridge/via/vx900/early_vx900.h deleted file mode 100644 index c1a823beaa..0000000000 --- a/src/northbridge/via/vx900/early_vx900.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2011-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. - */ - -#ifndef EARLY_VX900_H -#define EARLY_VX900_H - -#include "raminit.h" -#include "vx900.h" - -#include <stdint.h> - -/* North Module devices */ -#define HOST_CTR PCI_DEV(0, 0, 0) -#define ERR_REP PCI_DEV(0, 0, 1) -#define HOST_BUS PCI_DEV(0, 0, 2) -#define MCU PCI_DEV(0, 0, 3) -#define POWERMAN PCI_DEV(0, 0, 4) -#define TRAF_CTR PCI_DEV(0, 0, 5) -#define NSBIC PCI_DEV(0, 0, 7) - -#define GFX PCI_DEV(0, 1, 0) -#define HDMI PCI_DEV(0, 1, 0) - -#define PEXx PCI_DEV(0, 3, x) -#define PEX_CTR PCI_DEV(0, 3, 4) - -/* South Module devices */ -#define UARTx PCI_DEV(0, 0x0a, x) -#define USB_MASS PCI_DEV(0, 0x0b, 0) -#define SDIO PCI_DEV(0, 0x0c, 0) -#define CARD_RD PCI_DEV(0, 0x0d, 0) -#define SATA PCI_DEV(0, 0x0d, 0) -#define USBx PCI_DEV(0, 0x10, x) -#define USB_EHCI PCI_DEV(0, 0x10, 4) -#define LPC PCI_DEV(0, 0x11, 0) -#define PMU LPC -#define SNMIC PCI_DEV(0, 0x11, 7) -#define P2P PCI_DEV(0, 0x13, 0) -#define HDAC PCI_DEV(0, 0x14, 0) - -/* These control the behavior of raminit */ -#define RAMINIT_USE_HW_RXCR_CALIB 0 -#define RAMINIT_USE_HW_MRS_SEQ 0 - - -void enable_smbus(void); -void dump_spd_data(spd_raw_data spd); -void spd_read(u8 addr, spd_raw_data spd); - -void vx900_enable_pci_config_space(void); -void vx900_disable_legacy_rom_shadow(void); - -void vx900_print_strapping_info(void); -void vx900_disable_auto_reboot(void); - -void vx900_cpu_bus_interface_setup(void); - -void vx900_dram_set_gfx_resources(void); -void vx900_disable_gfx(void); - -#endif /* EARLY_VX900_H */ diff --git a/src/northbridge/via/vx900/lpc.c b/src/northbridge/via/vx900/lpc.c deleted file mode 100644 index fd4d5ad2a2..0000000000 --- a/src/northbridge/via/vx900/lpc.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2012-2013 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. - */ - -#include <device/pci_ops.h> -#include <arch/pirq_routing.h> -#include <console/console.h> -#include <device/pci.h> -#include <device/pci_ids.h> -#include <pc80/i8259.h> -#include <drivers/generic/ioapic/chip.h> - -#include "vx900.h" -#include "chip.h" - -/** - * @file vx900/lpc.c - * - * STATUS: - * We do a fair bit of setup, and most of it seems to work fairly well. There - * are still a few FIXME items here and there, but overall, this code hasn't - * been touched much from its initial 2012 version to 2013, when it was revived. - * - * We do the IOAPIC setup with the assumption that it is declared in the - * mainboard's devicetree.cb. We cannot use the IOAPIC however. The interrupts - * do not make it to the CPU. This issue is still under investigation. - * - * We also route PIRQs with CONFIG_PIRQ_ROUTE. This is currently the only way to - * get interrupts working. - * - * On the VX900, the keyboard can be connected directly to the chipset - * (referenced as "internal keyboard" in the documents). As long as that is the - * case (not connected to the superIO), and we disable the superIO keyboard LDN, - * it will work, but perhaps this should be more configurable. - */ - -static void vx900_lpc_misc_stuff(struct device *dev) -{ - char extint; - u8 val; - struct northbridge_via_vx900_config *nb = (void *)dev->chip_info; - - /* GPIO 11,10 to SATALED [1,0] */ - pci_or_config8(dev, 0xe4, 1 << 0); - - /* Route the external interrupt line */ - extint = nb->ext_int_route_to_pirq; - if (extint < 'A' || extint > 'H') { - printk(BIOS_WARNING, "Invalid PIRQ%c for external interrupt\n", - extint); - } else { - printk(BIOS_INFO, "Routing external interrupt to PIRQ%c\n", - extint); - val = extint - 'A'; - val |= (1 << 3); /* bit3 enables the external int */ - pci_update_config8(dev, 0x55, ~0xf, val); - - } -} - -static void vx900_lpc_dma_setup(struct device *dev) -{ - /* These are the steps recommended by VIA in order to get DMA running */ - - /* Enable Positive South Module PCI Cycle Decoding */ - /* FIXME: Setting this seems to hang our system */ - - /* Positive decoding for ROM + APIC + On-board IO ports */ - pci_or_config8(dev, 0x6c, (1 << 2) | (1 << 3) | (1 << 7)); - /* Enable DMA channels. BIOS guide recommends DMA channel 2 off */ - pci_write_config8(dev, 0x53, 0xfb); - /* Disable PCI/DMA Memory Cycles Output to PCI Bus */ - pci_update_config8(dev, 0x5b, ~(1 << 5), 0); - /* DMA bandwidth control - Improved bandwidth */ - pci_write_config8(dev, 0x53, 0xff); - /* ISA Positive Decoding control */ - pci_write_config8(dev, 0x6d, 0xdf); - pci_write_config8(dev, 0x6e, 0x98); - pci_write_config8(dev, 0x6f, 0x30); -} - -/** - *\brief VX900: Set up the south module IOAPIC (for the ISA/LPC bus) - * - * Enable the IOAPIC in the south module, and properly set it up. - * \n - * This is the hardware specific initialization for the IOAPIC, and complements - * the setup done by the generic IOAPIC driver. In order for the IOAPIC to work - * properly, it _must_ be declared in devicetree.cb . - * \n - * We are assuming this is called before the drivers/generic/ioapic code, - * which should be the case if devicetree.cb is set up properly. - */ -static void vx900_lpc_ioapic_setup(struct device *dev) -{ - /* Find the IOAPIC, and make sure it's set up correctly in devicetree.cb - * If it's not, then the generic ioapic driver will not set it up - * correctly, and the MP table will not be correctly generated */ - struct device *ioapic; - for (ioapic = dev->next; ioapic; ioapic = ioapic->next) { - if (ioapic->path.type == DEVICE_PATH_IOAPIC) - break; - } - - /* You did put an IOAPIC in devicetree.cb, didn't you? */ - if (ioapic == 0) { - /* We don't have enough info to set up the IOAPIC */ - printk(BIOS_ERR, "ERROR: South module IOAPIC not found. " - "Check your devicetree.cb\n"); - return; - } - - /* Found an IOAPIC, now we need to make sure it's the right one */ - ioapic_config_t *config = (ioapic_config_t *) ioapic->chip_info; - if (!config->have_isa_interrupts) { - /* Umh, is this the right IOAPIC ? */ - printk(BIOS_ERR, "ERROR: South module IOAPIC not carrying ISA " - "interrupts. Check your devicetree.cb\n"); - printk(BIOS_ERR, "Will not initialize this IOAPIC.\n"); - return; - } - - /* The base address of this IOAPIC _must_ be at 0xfec00000. - * Don't move this value to a #define, as people might think it's - * configurable. It is not. */ - const void *base = config->base; - if (base != (void *)0xfec00000) { - printk(BIOS_ERR, "ERROR: South module IOAPIC base should be at " - "0xfec00000\n but we found it at %p\n", base); - return; - } - - printk(BIOS_DEBUG, "VX900 LPC: Setting up the south module IOAPIC.\n"); - /* Enable IOAPIC - * So much work for one line of code. Talk about bloat :) - * The 8259 PIC should still work even if the IOAPIC is enabled, so - * there's no crime in enabling the IOAPIC here. */ - pci_or_config8(dev, 0x58, 1 << 6); -} - -static void vx900_lpc_interrupt_stuff(struct device *dev) -{ - /* Enable setting trigger mode through 0x4d0, and 0x4d1 ports - * And enable I/O recovery time */ - pci_or_config8(dev, 0x40, (1 << 2) | (1 << 6)); - /* Set serial IRQ frame width to 6 PCI cycles (recommended by VIA) - * And enable serial IRQ */ - pci_update_config8(dev, 0x52, ~(3 << 0), (1 << 3) | (1 << 0)); - - /* Disable IRQ12 storm FIXME: bad comment */ - pci_update_config8(dev, 0x51, ~(1 << 2), 0); - - pci_write_config8(dev, 0x4c, (1 << 6)); - - /* FIXME: Do we really need this? SeaBIOS/linux runs fine without it. - * Is this something the payload/OS should do, or is it safe for us to - * do it? */ - /* Get the IRQs up and running */ - setup_i8259(); - - vx900_lpc_dma_setup(dev); - - /* The IOAPIC is special, and we treat it separately */ - vx900_lpc_ioapic_setup(dev); -} - -static void vx900_lpc_init(struct device *dev) -{ - vx900_lpc_interrupt_stuff(dev); - vx900_lpc_misc_stuff(dev); - dump_pci_device(PCI_BDF(dev)); -} - -static void vx900_lpc_read_resources(struct device *dev) -{ - struct resource *res; - pci_dev_read_resources(dev); - - /* MMIO space */ - res = new_resource(dev, VX900_MMCONFIG_MBAR); - res->size = 0x1000; - res->align = 12; - res->gran = 12; - res->limit = 0xffffffff; - res->flags = IORESOURCE_MEM | IORESOURCE_RESERVE; - - /* SPI controller */ - res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0)); - res->size = 0x8; - res->align = 12; - res->gran = 12; - res->limit = 0xffffffff; - res->flags = IORESOURCE_MEM | IORESOURCE_RESERVE; -} - -static void vx900_lpc_set_resources(struct device *dev) -{ - struct resource *mmio, *spi; - u32 reg; - - mmio = find_resource(dev, VX900_MMCONFIG_MBAR); - if (mmio) { - report_resource_stored(dev, mmio, "<mmconfig>"); - mmio->flags |= IORESOURCE_STORED; - reg = pci_read_config32(dev, VX900_MMCONFIG_MBAR); - reg &= 0xff000000; - reg |= mmio->base >> 8; - pci_write_config32(dev, VX900_MMCONFIG_MBAR, reg); - - spi = find_resource(dev, IOINDEX_SUBTRACTIVE(0, 0)); - if (spi) { - report_resource_stored(dev, spi, "<spi>"); - spi->flags |= IORESOURCE_STORED; - /* Set base and the enable bit. */ - ((u32*)(uintptr_t)mmio->base)[0] = (spi->base | 0x01); - } - } - pci_dev_set_resources(dev); -} - -static struct device_operations vx900_lpc_ops = { - .read_resources = vx900_lpc_read_resources, - .set_resources = vx900_lpc_set_resources, - .enable_resources = pci_dev_enable_resources, - .init = vx900_lpc_init, - .scan_bus = scan_static_bus, -}; - -static const struct pci_driver lpc_driver __pci_driver = { - .ops = &vx900_lpc_ops, - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_VX900_LPC, -}; - -#if CONFIG(PIRQ_ROUTE) -void pirq_assign_irqs(const u8 *pirq) -{ - struct device *lpc; - - lpc = dev_find_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_VX900_LPC, 0); - - /* Take care of INTA -> INTD */ - pci_update_config8(lpc, 0x55, (u8)~(0xf << 4), pirq[0] << 4); - pci_write_config8(lpc, 0x56, pirq[1] | (pirq[2] << 4)); - pci_write_config8(lpc, 0x57, pirq[3] << 4); - - /* Enable INTE -> INTH to be on separate IRQs */ - pci_or_config8(lpc, 0x46, 1 << 4); - /* Now do INTE -> INTH */ - pci_write_config8(lpc, 0x44, pirq[4] | (pirq[5] << 4)); - pci_write_config8(lpc, 0x45, pirq[6] | (pirq[7] << 4)); -} -#endif diff --git a/src/northbridge/via/vx900/memmap.c b/src/northbridge/via/vx900/memmap.c deleted file mode 100644 index 3121d7406e..0000000000 --- a/src/northbridge/via/vx900/memmap.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com> - * Copyright (C) 2018 Lubomir Rintel <lkundrak@v3.sk> - * - * 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. - */ - -#define __SIMPLE_DEVICE__ - -#include <device/pci.h> -#include <device/pci_ops.h> -#include <cbmem.h> -#include <console/console.h> -#include <lib.h> - -#include "vx900.h" - -#define MCU PCI_DEV(0, 0, 3) - -#define CHROME_9_HD_MIN_FB_SIZE 8 -#define CHROME_9_HD_MAX_FB_SIZE 512 - -/* Helper to determine the framebuffer size */ -void vx900_set_chrome9hd_fb_size(u32 size_mb) -{ - u8 reg8, ranksize; - u32 tom_mb, max_size_mb; - int i; - - /* The minimum framebuffer size is 8MB. */ - size_mb = MAX(size_mb, CHROME_9_HD_MIN_FB_SIZE); - - /* - * 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 %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 down the framebuffer size to the closest power of 2 */ - if (size_mb == 0) - die("Framebuffer size is 0\n"); - - int fb_pow = log2(size_mb); - - size_mb = 1U << fb_pow; - - if (size_mb < CHROME_9_HD_MIN_FB_SIZE || size_mb > CHROME_9_HD_MAX_FB_SIZE) - die("Framebuffer size %u is out of range\n", size_mb); - - pci_update_config8(MCU, 0xa1, ~(7 << 4), (fb_pow - 2) << 4); -} - -/* Gets the configured framebuffer size as a power of 2 */ -u8 vx900_get_chrome9hd_fb_pow(void) -{ - u8 fb_pow = (pci_read_config8(MCU, 0xa1) >> 4) & 7; - - if (fb_pow > 0) - fb_pow += 2; - - return fb_pow; -} - -/* Gets the configured framebuffer size in MB */ -u32 vx900_get_chrome9hd_fb_size(void) -{ - u8 size = vx900_get_chrome9hd_fb_pow(); - - if (size == 0) - return 0; - - return 1 << size; -} - -u32 vx900_get_tolm(void) -{ - return (pci_read_config16(MCU, 0x84) & 0xfff0) >> 4; -} - -void *cbmem_top_chipset(void) -{ - uintptr_t tolm; - uintptr_t fb_size; - - tolm = vx900_get_tolm (); - fb_size = vx900_get_chrome9hd_fb_size (); - - if (tolm > 0xfc0 || tolm <= 0x3ff || fb_size == 0x0) - return NULL; - - return (void *)((tolm - fb_size) << 20); -} diff --git a/src/northbridge/via/vx900/northbridge.c b/src/northbridge/via/vx900/northbridge.c deleted file mode 100644 index 260bd3de05..0000000000 --- a/src/northbridge/via/vx900/northbridge.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * 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. - */ - -#include "vx900.h" -#include "chip.h" - -#include <console/console.h> -#include <device/device.h> -#include <device/pci.h> -#include <device/pci_ops.h> -#include <device/pci_ids.h> -#include <cpu/cpu.h> -#include <cf9_reset.h> -#include <reset.h> - -#define RAM_4GB (((u64)1) << 32) - -static uint64_t uma_memory_base = 0; -static uint64_t uma_memory_size = 0; - -/** - * @file vx900/northbridge.c - * - * STATUS: Pretty good - * One thing that needs to be thoroughly tested is the remap above 4G logic. - * Unfortunately, while we cannot initialize odd ranks, our testing - * possibilities are somewhat limited. A point of failure that is not covered is - * when the amount of RAM and PCI config space added up exceeds 8GB. The - * remapping mechanism will overflow, the effects of which are unknown. - */ - -void do_board_reset(void) -{ - system_reset(); -} - -uint64_t get_uma_memory_base(void) -{ - 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); - return uma_memory_base; -} - -static u64 vx900_get_top_of_ram(struct device *mcu) -{ - u16 reg16; - /* The last valid DRAM address is computed by the MCU - * One issue might be if we have a hole in the rank mappings, so that - * virtual ranks are not mapped successively in the linear address space - * (Ex: rank 0 mapped 0-1G, rank 1 mapped 2G-3G) - * We don't do this awkward mapping in RAM init, so we don't worry about - * it here, but it is something to keep in mind if having RAM issues */ - reg16 = pci_read_config16(mcu, 0x88) & 0x07ff; - return (u64) reg16 << 24; -} - -/* - * This guy is meant to go away, but for now, leave it in so that we can see - * if the logic to remap RAM above 4G has errors. - */ -static void killme_debug_4g_remap_reg(u32 reg32) -{ - if (reg32 & (1 << 0)) - printk(BIOS_DEBUG, "Mem remapping enabled\n"); - u64 remapstart = (reg32 >> 2) & 0x3ff; - u64 remapend = (reg32 >> 14) & 0x3ff; - remapstart <<= 26; - remapend <<= 26; - printk(BIOS_DEBUG, "Remapstart %lld(MB)\n", remapstart >> 20); - printk(BIOS_DEBUG, "Remapend %lld(MB)\n", remapend >> 20); -} - -/** - * \brief Remap low memory colliding with PCI MMIO space, above 4G - * - * @param mcu The memory controller - * @param tolm Top of low memory. - * - * @return The new top of memory. - */ -static u64 vx900_remap_above_4g(struct device *mcu, u32 tolm) -{ - size_t i; - u8 reg8, start8, end8, start, end; - u16 reg16; - u32 reg32; - u64 tor, newtor, chunk; - - /* - * The remapping mechanism works like this: - * - * - Choose the top of low memory. - * This becomes the "remap from" - * - Choose a chunk above 4G where to remap. - * This becomes "remap to" - * - Choose a chunk above 4G where to end the remapping. - * This becomes "remap until" - * - * This remaps a "chunk" of memory where we want to. - * sizeof(chunk) = until - to; - * - * Therefore the memory region from "from" to " from + sizeof(chunk)" - * becomes accessible at "to" to "until" - */ - if (tolm >= vx900_get_top_of_ram(mcu)) { - printk(BIOS_DEBUG, "Nothing to remap\n"); - return 0; - } - - /* This is how the Vendor BIOS. Keep it for comparison for now */ - killme_debug_4g_remap_reg(0x00180141); - /* We can remap with a granularity of 64MB, so align tolm */ - tolm &= ~((64 * MiB) - 1); - - /* The "start remapping from where ?" register */ - reg16 = ((tolm >> 20) & 0xfff) << 4; - pci_update_config16(mcu, 0x84, (u16)~0xfff0, reg16); - - /* Find the chunk size */ - tor = vx900_get_top_of_ram(mcu); - printk(BIOS_DEBUG, "Top of RAM %lldMB\n", tor >> 20); - - if (tor < RAM_4GB) { - chunk = tor - tolm; - newtor = RAM_4GB + chunk; - } else { - chunk = (RAM_4GB - tolm); - newtor = tor + chunk; - } - printk(BIOS_DEBUG, "New top of RAM %lldMB\n", newtor >> 20); - - reg8 = tolm >> 26; - /* Which rank does the PCI TOLM fall on? */ - for (i = 0; i < VX900_MAX_MEM_RANKS; i++) { - end8 = pci_read_config8(mcu, 0x40 + i); - if (reg8 > end8) - continue; - start8 = pci_read_config8(mcu, 0x48 + i); - if (reg8 <= start8) - continue; - printk(BIOS_DEBUG, "Address %x falls on rank %zu\n", tolm, i); - break; - } - - for (; i < VX900_MAX_MEM_RANKS; i++) { - start = pci_read_config8(mcu, 0x48 + i); - end = pci_read_config8(mcu, 0x40 + i); - - if (end == 0) { - printk(BIOS_DEBUG, "Huh? rank %zu empty?\n", i); - continue; - } - - if (end < (tolm >> 26)) { - printk(BIOS_DEBUG, "Huh? rank %zu don't need remap?\n", - i); - continue; - } - - printk(BIOS_DEBUG, "Physical rank %u is mapped to\n" - " Start address: 0x%.10llx (%dMB)\n" - " End address: 0x%.10llx (%dMB)\n", - (int)i, - ((u64) start << 26), (start << (26 - 20)), - ((u64) end << 26), (end << (26 - 20))); - - if (end < (RAM_4GB >> 26)) - end = (RAM_4GB >> 26); - - if (end >= (tolm >> 26)) - end += chunk >> 26; - - if (start > (tolm >> 26)) - start += chunk >> 26; - - pci_write_config8(mcu, 0x48 + i, start); - pci_write_config8(mcu, 0x40 + i, end); - - printk(BIOS_DEBUG, "ReMapped Physical rank %u, to\n" - " Start address: 0x%.10llx (%dMB)\n" - " End address: 0x%.10llx (%dMB)\n", - (int)i, - ((u64) start << 26), (start << (26 - 20)), - ((u64) end << 26), (end << (26 - 20))); - } - - /* The "remap to where?" register */ - reg32 = ((MAX(tor, RAM_4GB) >> 26) & 0x3ff) << 2; - /* The "remap until where?" register */ - reg32 |= ((newtor >> 26) & 0x3ff) << 14; - /* Now enable the goodies */ - reg32 |= (1 << 0); - pci_write_config32(mcu, 0xf8, reg32); - printk(BIOS_DEBUG, "Wrote remap map %x\n", reg32); - killme_debug_4g_remap_reg(reg32); - - printk(BIOS_DEBUG, "New top of memory is at %lldMB\n", newtor >> 20); - return newtor; -} - -static void vx900_set_resources(struct device *dev) -{ - u32 pci_tolm, tomk, vx900_tolm, full_tolmk, fbufk, tolmk; - - printk(BIOS_DEBUG, "========================================" - "========================================\n"); - printk(BIOS_DEBUG, "============= VX900 memory sizing & Co. " - "========================================\n"); - printk(BIOS_DEBUG, "========================================" - "========================================\n"); - - int idx = 10; - struct device *const mcu = dev_find_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_VX900_MEMCTRL, - 0); - if (!mcu) { - die("Something is terribly wrong.\n" - " We tried locating the MCU on the PCI bus, " - "but couldn't find it. Halting.\n"); - } - - /* How much low adrress space do we have? */ - pci_tolm = find_pci_tolm(dev->link_list); - printk(BIOS_SPEW, "Found PCI tolm at %.8x\n", pci_tolm); - printk(BIOS_SPEW, "Found PCI tolm at %dMB\n", pci_tolm >> 20); - - /* Figure out the total amount of RAM */ - tomk = vx900_get_top_of_ram(mcu) >> 10; - printk(BIOS_SPEW, "Found top of memory at %dMB\n", tomk >> 10); - - /* Do the same for top of low RAM */ - vx900_tolm = vx900_get_tolm(); - full_tolmk = vx900_tolm << (20 - 10); - /* Remap above 4G if needed */ - full_tolmk = MIN(full_tolmk, pci_tolm >> 10); - printk(BIOS_SPEW, "Found top of low memory at %dMB\n", - full_tolmk >> 10); - - /* What about the framebuffer for the integrated GPU? */ - fbufk = vx900_get_chrome9hd_fb_size() << (20 - 10); - printk(BIOS_SPEW, "Integrated graphics buffer: %dMB\n", fbufk >> 10); - - /* Can't use the framebuffer as system RAM, sorry */ - tolmk = MIN(full_tolmk, tomk); - tolmk -= fbufk; - ram_resource(dev, idx++, 0, 640); - printk(BIOS_SPEW, "System RAM left: %dMB\n", tolmk >> 10); - /* FIXME: how can we avoid leaving this hole? - * Leave a hole for VGA, 0xa0000 - 0xc0000 ?? */ - /* TODO: VGA Memory hole can be disabled in SNMIC. Upper 64k of ROM seem - * to be always mapped to the top of 1M, but this can be overcome with - * some smart positive/subtractive resource decoding */ - ram_resource(dev, idx++, 768, (tolmk - 768)); - - uma_memory_size = (uint64_t)fbufk << 10; - uma_memory_base = (uint64_t)tolmk << 10; - - if (uma_memory_size > UINT32_MAX) - die("uma_memory_size %llu exceeds 32-bit address range\n", uma_memory_size); - - if (uma_memory_base > UINT32_MAX) - die("uma_memory_base %llu exceeds 32-bit address range\n", uma_memory_base); - - //uma_resource(dev, idx++, uma_memory_base>>10, uma_memory_size>>10); - - printk(BIOS_DEBUG, "UMA @ %lldMB + %lldMB\n", uma_memory_base >> 20, - uma_memory_size >> 20); - /* FIXME: How do we handle remapping above 4G? */ - u64 tor = vx900_remap_above_4g(mcu, pci_tolm); - if (tor) - ram_resource(dev, idx++, RAM_4GB >> 10, (tor - RAM_4GB) >> 10); - - printk(BIOS_DEBUG, "======================================================\n"); - assign_resources(dev->link_list); -} - -static void vx900_read_resources(struct device *dev) -{ - /* Our fixed resources start at 0 */ - int idx = 0; - /* Reserve our ROM mapped space */ - struct resource *res; - res = new_resource(dev, idx++); - res->size = CONFIG_ROM_SIZE; - res->base = 0xffffffff - (res->size - 1); - res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; - - /* Now do the same for our MMCONF - * We always run with MMCONF enabled. We need to access the extended - * config space when configuring PCI-Express links */ - mmconf_resource(dev, idx++); - - pci_domain_read_resources(dev); -} - -static struct device_operations pci_domain_ops = { - .read_resources = vx900_read_resources, - .set_resources = vx900_set_resources, - .enable_resources = NULL, - .init = NULL, - .scan_bus = pci_domain_scan_bus, -}; - -static void cpu_bus_init(struct device *dev) -{ - initialize_cpus(dev->link_list); -} - -static struct device_operations cpu_bus_ops = { - .read_resources = DEVICE_NOOP, - .set_resources = DEVICE_NOOP, - .enable_resources = DEVICE_NOOP, - .init = cpu_bus_init, - .scan_bus = 0, -}; - -static void enable_dev(struct device *dev) -{ - /* Set the operations if it is a special bus type */ - if (dev->path.type == DEVICE_PATH_DOMAIN) { - dev->ops = &pci_domain_ops; - } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) { - dev->ops = &cpu_bus_ops; - } -} - -struct chip_operations northbridge_via_vx900_ops = { - CHIP_NAME("VIA VX900 Chipset") - .enable_dev = enable_dev, -}; diff --git a/src/northbridge/via/vx900/pci_util.c b/src/northbridge/via/vx900/pci_util.c deleted file mode 100644 index 57b08e7586..0000000000 --- a/src/northbridge/via/vx900/pci_util.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2013 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. - */ - -#include <console/console.h> -#include <device/pci_ops.h> - -#include "vx900.h" - -void dump_pci_device(pci_devfn_t dev) -{ - int i; - for (i = 0; i <= 0xff; i++) { - unsigned char val; - if ((i & 0x0f) == 0) - printk(BIOS_DEBUG, "%.2x:", i); - - if ((i & 0x0f) == 0x08) - printk(BIOS_DEBUG, " |"); - - val = pci_s_read_config8(dev, i); - printk(BIOS_DEBUG, " %.2x", val); - - if ((i & 0x0f) == 0x0f) - printk(BIOS_DEBUG, "\n"); - } -} diff --git a/src/northbridge/via/vx900/pcie.c b/src/northbridge/via/vx900/pcie.c deleted file mode 100644 index ef157d8a02..0000000000 --- a/src/northbridge/via/vx900/pcie.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2013 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. - */ - -#include <device/pci_ops.h> -#include <console/console.h> -#include <device/pci.h> -#include <device/pciexp.h> -#include <device/pci_ids.h> - -#include "vx900.h" - -/** - * @file vx900/pcie.c - * - * STATUS: - * We do part of the sequence to initialize the PCIE link. The problem is that - * the reset signal for each slot is connected to a GPO pin, but We don't know - * which GPO pin. We need to figure out which GPIO pin is hooked to which slot, - * and have a mechanism to specify this per-mainboard (devicetree.cb). - * - * There is currently no timeout detection mechanism for when a link comes up. - * If the link never comes up, we hang. - */ - -static void vx900_pcie_link_init(struct device *dev) -{ - u8 reg8; - u32 reg32; - - u8 fn = dev->path.pci.devfn & 0x07; - - /* Step 1 : Check for presence of PCIE device */ - reg8 = pci_read_config8(dev, 0x5a); - - if (reg8 & (1 << 6)) - printk(BIOS_DEBUG, "Card detected in PEX%i\n", fn); - else - return; - - /* Step 2: Wait for device to enter L0 state */ - /* FIXME: implement timeout detection */ - while (0x8a != pci_read_config8(dev, 0x1c3)); - - /* Step 3: Clear PCIe error status, then check for failures */ - pci_write_config32(dev, 0x104, 0xffffffff); - reg32 = pci_read_config32(dev, 0x104); - if (0 != reg32) { - printk(BIOS_DEBUG, "PEX init error. flags 0x%.8x\n", reg32); - return; - } - - pci_write_config32(dev, 0x110, 0xffffffff); - reg32 = pci_read_config32(dev, 0x110); - if (0 != reg32) - printk(BIOS_DEBUG, "PEX errors. flags 0x%.8x\n", reg32); - - pci_write_config8(dev, 0xa4, 0xff); - if (pci_read_config8(dev, 0x4a) & (1 << 3)) - printk(BIOS_DEBUG, "Unsupported request detected.\n"); - - pci_write_config8(dev, 0x15a, 0xff); - if (pci_read_config8(dev, 0x15a) & (1 << 1)) - printk(BIOS_DEBUG, "Negotiation pending.\n"); - - /* Step 4: Read vendor ID */ - /* FIXME: Do we want to run through the whole sequence and delay boot - * by several seconds if the device does not respond properly the first - * time? */ -} - -static void vx900_pex_dev_set_resources(struct device *dev) -{ - assign_resources(dev->link_list); -} - -static void vx900_pex_init(struct device *dev) -{ - /* FIXME: For some reason, PEX0 hangs on init. Find issue, fix it. */ - if ((dev->path.pci.devfn & 0x7) == 0) - return; - - vx900_pcie_link_init(dev); -} - -static struct device_operations vx900_pex_ops = { - .read_resources = pci_bus_read_resources, - .set_resources = vx900_pex_dev_set_resources, - .enable_resources = pci_bus_enable_resources, - .init = vx900_pex_init, - .scan_bus = pciexp_scan_bridge, - .reset_bus = pci_bus_reset, -}; - -static const unsigned short pci_device_ids[] = { - PCI_DEVICE_ID_VIA_VX900_PEX1, - PCI_DEVICE_ID_VIA_VX900_PEX2, - PCI_DEVICE_ID_VIA_VX900_PEX3, - PCI_DEVICE_ID_VIA_VX900_PEX4, - 0, -}; - -static const struct pci_driver pex_driver __pci_driver = { - .ops = &vx900_pex_ops, - .vendor = PCI_VENDOR_ID_VIA, - .devices = pci_device_ids, - -}; diff --git a/src/northbridge/via/vx900/raminit.h b/src/northbridge/via/vx900/raminit.h deleted file mode 100644 index 4c53d52d8c..0000000000 --- a/src/northbridge/via/vx900/raminit.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2011 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. - */ - -#ifndef RAMINIT_VX900_H -#define RAMINIT_VX900_H - -#include <device/dram/ddr3.h> -#include "vx900.h" - -#define SPD_END_LIST 0xff - -typedef struct dimm_layout_st -{ - /* The address of the DIMM on the SMBUS * - * 0xFF to terminate the array*/ - u8 spd_addr[VX900_MAX_DIMM_SLOTS + 1]; -} dimm_layout; - -typedef struct dimm_info_st -{ - dimm_attr dimm[VX900_MAX_DIMM_SLOTS]; -} dimm_info; - -typedef struct mem_rank_st { - u16 start_addr; - u16 end_addr; -} mem_rank; - -typedef struct rank_layout_st { - u32 phys_rank_size_mb[VX900_MAX_MEM_RANKS]; - mem_rank virt[VX900_MAX_MEM_RANKS]; - dimm_flags_t flags[VX900_MAX_MEM_RANKS]; -} rank_layout; - -typedef struct pci_reg8_st { - u8 addr; - u8 val; -} pci_reg8; - -typedef u8 timing_dly[8]; - -typedef struct delay_range_st { - timing_dly low; - timing_dly avg; - timing_dly high; -} delay_range; - -typedef struct vx900_delay_calib_st { - delay_range rx_dq_cr; - delay_range rx_dqs; - /* Transmit delays are calibrated for each dimm */ - delay_range tx_dq[VX900_MAX_DIMM_SLOTS]; - delay_range tx_dqs[VX900_MAX_DIMM_SLOTS]; -} vx900_delay_calib; - -typedef struct ramctr_timing_st { - enum spd_memory_type dram_type; - enum spd_dimm_type dimm_type; - u16 cas_supported; - /* tLatencies are in units of ns, scaled by x256 */ - u32 tCK; - u32 tAA; - u32 tWR; - u32 tRCD; - u32 tRRD; - u32 tRP; - u32 tRAS; - u32 tRC; - u32 tRFC; - u32 tWTR; - u32 tRTP; - u32 tFAW; - /* Latencies in terms of clock cycles - * They are saved separately as they are needed for DRAM MRS commands*/ - u8 CAS; /* CAS read latency */ - u8 CWL; /* CAS write latency */ - u8 WR; /* write recovery time */ - /* Number of dimms currently connected */ - u8 n_dimms; - -} ramctr_timing; - -void vx900_init_dram_ddr3(const dimm_layout *dimms); - -#endif /* RAMINIT_VX900_H */ diff --git a/src/northbridge/via/vx900/raminit_ddr3.c b/src/northbridge/via/vx900/raminit_ddr3.c deleted file mode 100644 index 4f79ed35b0..0000000000 --- a/src/northbridge/via/vx900/raminit_ddr3.c +++ /dev/null @@ -1,1671 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2011-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. - */ - -#include "early_vx900.h" -#include "raminit.h" -#include <arch/io.h> -#include <device/pci_ops.h> -#include <console/console.h> -#include <device/pci_ids.h> -#include <delay.h> -#include <lib.h> -#include <string.h> - -/** - * @file raminit_ddr3.c - * - * \brief DDR3 initialization for VIA VX900 chipset - * - * Rather than explain the DDR3 init algorithm, it is better to focus on what - * works and what doesn't. Familiarity with the DDR3 spec does not hurt. - * - * 1 DIMMs and 2 DIMMs with one rank each works. - * 1 rank DIMM with 2 rank DIMM works, but the odd ranks are disabled. - * (2) 2-rank DIMMs will not work. - * - * It is not yet clear if odd ranks do not work because of faulty timing - * calibration, or a misconfiguration of the MCU. I have seen this with DIMMS - * which mirror pins on the odd rank. That could also be the issue. - * - * The capture window is not calibrated, but preset. Whether that preset is - * universal or frequency dependent, and whether it is board-specific or not is - * not yet clear. @see vx900_dram_calibrate_receive_delays(). - * - * 4GBit and 8GBit modules may not work. This is untested. Modules with 11 - * column address bits are not tested. @see vx900_dram_map_row_col_bank() - * - * Everything else should be in a more or less usable state. FIXME s are placed - * all over as a reminder that either something really needs fixing, or as a - * reminder to double-check. - */ - -/* Map BA0 <-> A17, BA1 <-> A18 */ -/* Map BA2 <-> A19, RA0/RA1 must not overlap BA[0:2] */ -#define VX900_MRS_MA_MAP 0x4b33 /* MA Pin Mapping for MRS commands */ -#define VX900_CALIB_MA_MAP 0x5911 /* MA Pin mapping for calibrations */ - -/* - * Registers 0x78 -> 0x7f contain the calibration settings for DRAM IO timing - * The dataset in these registers is selected from 0x70. - * Once the correct dataset is selected the delays can be altered. - * delay_type refers to TxDQS, TxDQ, RxDQS, or RxCR - * bound refers to either manual, average, upper bound, or lower bound - */ -#define CALIB_TxDQS 0 -#define CALIB_TxDQ 1 -#define CALIB_RxDQS 2 -#define CALIB_RxDQ_CR 3 - -#define CALIB_AVERAGE 0 -#define CALIB_LOWER 1 -#define CALIB_UPPER 2 -#define CALIB_MANUAL 4 /* We want this & 3 to overflow to 0 */ - -static void vx900_delay_calib_mode_select(u8 delay_type, u8 bound) -{ - /* Which calibration setting */ - u8 reg8 = (delay_type & 0x03) << 2; - /* Upper, lower, average, or manual setting */ - reg8 |= (bound & 0x03); - pci_write_config8(MCU, 0x70, reg8); -} - -/* - * The vendor BIOS does something similar to vx900_delay_calib_mode_select(), - * then reads or write a byte, and repeats the process for all 8 bytes. This is - * annoyingly inefficient, and we can achieve the same result in a much more - * elegant manner. - */ -static void vx900_read_0x78_0x7f(timing_dly dly) -{ - *((u32 *) (&(dly[0]))) = pci_read_config32(MCU, 0x78); - *((u32 *) (&(dly[4]))) = pci_read_config32(MCU, 0x7c); -} - -static void vx900_write_0x78_0x7f(const timing_dly dly) -{ - pci_write_config32(MCU, 0x78, *((u32 *) (&(dly[0])))); - pci_write_config32(MCU, 0x7c, *((u32 *) (&(dly[4])))); -} - -static void vx900_read_delay_range(delay_range * d_range, u8 mode) -{ - vx900_delay_calib_mode_select(mode, CALIB_LOWER); - vx900_read_0x78_0x7f(d_range->low); - vx900_delay_calib_mode_select(mode, CALIB_AVERAGE); - vx900_read_0x78_0x7f(d_range->avg); - vx900_delay_calib_mode_select(mode, CALIB_UPPER); - vx900_read_0x78_0x7f(d_range->high); -} - -static void dump_delay(const timing_dly dly) -{ - u8 i; - for (i = 0; i < 8; i++) { - printram(" %.2x", dly[i]); - } - printram("\n"); -} - -static void dump_delay_range(const delay_range d_range) -{ - printram("Lower limit: "); - dump_delay(d_range.low); - printram("Average: "); - dump_delay(d_range.avg); - printram("Upper limit: "); - dump_delay(d_range.high); -} - -/* - * These are some "safe" values that can be used for memory initialization. - * Some will stay untouched, and others will be overwritten later on - */ -static pci_reg8 mcu_init_config[] = { - {0x40, 0x01}, /* Virtual rank 0 ending address = 64M - 1 */ - {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00}, /* Virtual Ranks ending */ - {0x48, 0x00}, /* Virtual rank 0 starting address = 0 */ - {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00}, /* Virtual Ranks beginning */ - {0x50, 0xd8}, /* Set ranks 0-3 to 11 col bits, 16 row bits */ - /* Disable all virtual ranks */ - {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00}, - /* Disable rank interleaving in ranks 0-3 */ - {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00}, - {0x6c, 0xA0}, /* Memory type: DDR3, VDIMM: 1.5V, 64-bit DRAM */ - {0xc4, 0x80}, /* Enable 8 memory banks */ - {0xc6, 0x80}, /* Minimum latency from self-refresh. Bit [7] must be 1 */ - /* FIXME: do it here or in Final config? */ - {0xc8, 0x80}, /* Enable automatic triggering of short ZQ calibration */ - {0x99, 0xf0}, /* Power Management and Bypass Reorder Queue */ - /* Enable differential DQS; MODT assertion values suggested in DS */ - {0x9e, 0xa1}, {0x9f, 0x51}, - /* DQ/DQM Duty Control - Do not put any extra delays */ - {0xe9, 0x00}, {0xea, 0x00}, {0xeb, 0x00}, {0xec, 0x00}, - {0xed, 0x00}, {0xee, 0x00}, {0xef, 0x00}, - {0xfc, 0x00}, {0xfd, 0x00}, {0xfe, 0x00}, {0xff, 0x00}, - /* The following parameters we may or may not change */ - {0x61, 0x2e}, /* DRAMC Pipeline Control */ - {0x77, 0x10}, /* MDQS Output Control */ - - /* The following are parameters we'll most likely never change again */ - {0x60, 0xf4}, /* DRAM Pipeline Turn-Around Setting */ - {0x65, 0x49}, /* DRAM Arbitration Bandwidth Timer - I */ - {0x66, 0x80}, /* DRAM Queue / Arbitration */ - {0x69, 0xc6}, /* Bank Control: 8 banks, high priority refresh */ - {0x6a, 0xfc}, /* DRAMC Request Reorder Control */ - {0x6e, 0x38}, /* Burst length: 8, burst-chop: enable */ - {0x73, 0x04}, /* Close All Pages Threshold */ - - /* The following need to be dynamically asserted */ - /* See: check_special_registers.c */ - {0x74, 0xa0}, /* Yes, same 0x74; add one more T */ - {0x76, 0x60}, /* Write Data Phase Control */ - -}; - -/* - * This table keeps the driving strength control setting that we can safely use - * during initialization. This settings come in part from SerialICE, and in part - * from code provided by VIA. - */ -static pci_reg8 mcu_drv_ctrl_config[] = { - {0xd3, 0x03}, /* Enable auto-compensation circuit for ODT strength */ - {0xd4, 0x80}, /* Set internal ODT to dynamically turn on or off */ - {0xd6, 0x20}, /* Enable strong driving for MA and DRAM commands */ - {0xd0, 0x88}, /* (ODT) Strength ?has effect? */ - {0xe0, 0x88}, /* DRAM Driving - Group DQS (MDQS) */ - {0xe1, 0x00}, /* Disable offset mode for driving strength control */ - {0xe2, 0x88}, /* DRAM Driving - Group DQ (MD, MDQM) */ - {0xe4, 0xcc}, /* DRAM Driving - Group CSA (MCS, MCKE, MODT) */ - {0xe8, 0x88}, /* DRAM Driving - Group MA (MA, MBA, MSRAS, MSCAS, MSWE) */ - {0xe6, 0xff}, /* DRAM Driving - Group DCLK0 (DCLK[2:0] for DIMM0) */ - {0xe7, 0xff}, /* DRAM Driving - Group DCLK1 (DCLK[5:3] for DIMM1) */ - {0xe4, 0xcc}, /* DRAM Driving - Group CSA (MCS, MCKE, MODT) */ - {0x91, 0x08}, /* MCLKO Output Phase Delay - I */ - {0x92, 0x08}, /* MCLKO Output Phase Delay - II */ - {0x93, 0x16}, /* CS/CKE Output Phase Delay */ - {0x95, 0x16}, /* SCMD/MA Output Phase Delay */ - {0x9b, 0x3f}, /* Memory Clock Output Enable */ -}; - -static void vx900_dram_set_ma_pin_map(u16 map) -{ - pci_write_config16(MCU, 0x52, map); -} - -/* - * FIXME: This function is a complete waste of space. All we really need is a - * MA MAP table based on either row address bits or column address bits. - * The problem is, I do not know if this mapping is applied during the column - * access or during the row access. At least the religiously verbose output - * makes pretty console output. - */ -static void vx900_dram_map_pins(u8 ba0, u8 ba1, u8 ba2, u8 ra0, u8 ra1) -{ - u16 map = 0; - - printram("Mapping address pins to DRAM pins:\n"); - printram(" BA0 -> A%u\n", ba0); - printram(" BA1 -> A%u\n", ba1); - printram(" BA2 -> A%u\n", ba2); - printram(" RA0 -> A%u\n", ra0); - printram(" RA1 -> A%u\n", ra1); - /* Make sure BA2 is enabled */ - map |= (1 << 11); - - /* - * Find RA1 (15:14) - * 00: A14 - * 01: A16 - * 10: A18 - * 11: A20 - */ - if ((ra1 & 0x01) || (ra1 < 14) || (ra1 > 20)) { - printram("Illegal mapping RA1 -> A%u\n", ra1); - return; - } - map |= (((ra1 - 14) >> 1) & 0x03) << 14; - - /* - * Find RA0 (13:12) - * 00: A15 - * 01: A17 - * 10: A19 - * 11: A21 - */ - if ((!(ra0 & 0x01)) || (ra0 < 15) || (ra0 > 21)) { - printram("Illegal mapping RA0 -> A%u\n", ra0); - return; - } - map |= (((ra0 - 15) >> 1) & 0x03) << 12; - - /* - * Find BA2 (10:8) - * x00: A14 - * x01: A15 - * x10: A18 - * x11: A19 - */ - switch (ba2) { - case 14: - map |= (0 << 8); - break; - case 15: - map |= (1 << 8); - break; - case 18: - map |= (2 << 8); - break; - case 19: - map |= (3 << 8); - break; - default: - printram("Illegal mapping BA2 -> A%u\n", ba2); - break; - } - - /* - * Find BA1 (6:4) - * 000: A12 - * 001: A14 - * 010: A16 - * 011: A18 - * 1xx: A20 - */ - if (((ba1 & 0x01)) || (ba1 < 12) || (ba1 > 20)) { - printram("Illegal mapping BA1 -> A%u\n", ba1); - return; - } - map |= (((ba1 - 12) >> 1) & 0x07) << 4; - - /* - * Find BA0 (2:0) - * 000: A11 - * 001: A13 - * 010: A15 - * 011: A17 - * 1xx: A19 - */ - if ((!(ba0 & 0x01)) || (ba0 < 11) || (ba0 > 19)) { - printram("Illegal mapping BA0 -> A%u\n", ba0); - return; - } - map |= (((ba0 - 11) >> 1) & 0x07) << 0; - - printram("Setting map mask (rx52) to %.4x\n", map); - vx900_dram_set_ma_pin_map(map); -} - -static void vx900_dram_write_init_config(void) -{ - /* Keep our RAM space free of legacy stuff */ - vx900_disable_legacy_rom_shadow(); - - /* Now worry about the real RAM init */ - size_t i; - for (i = 0; i < (sizeof(mcu_init_config) / sizeof(pci_reg8)); i++) { - pci_write_config8(MCU, mcu_init_config[i].addr, - mcu_init_config[i].val); - } - vx900_dram_set_ma_pin_map(VX900_CALIB_MA_MAP); - - /* FIXME: Slowing stuff down. Does this really help? */ - - /* Fast cycle control for CPU-to-DRAM Read Cycle 0:Disabled. - * This CPU bus controller will wait for all data */ - - /* Memory to CPU bus Controller Conversion Mode 1: Synchronous mode */ -} - -static void dram_find_spds_ddr3(const dimm_layout * addr, dimm_info * dimm) -{ - size_t i = 0; - int dimms = 0; - do { - spd_raw_data spd; - spd_read(addr->spd_addr[i], spd); - spd_decode_ddr3(&dimm->dimm[i], spd); - if (dimm->dimm[i].dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3) - continue; - dimms++; - dram_print_spd_ddr3(&dimm->dimm[i]); - } while (addr->spd_addr[++i] != SPD_END_LIST - && i < VX900_MAX_DIMM_SLOTS); - - if (!dimms) - die("No DIMMs were found"); -} - -static void dram_find_common_params(const dimm_info * dimms, - ramctr_timing * ctrl) -{ - size_t i, valid_dimms; - memset(ctrl, 0, sizeof(ramctr_timing)); - ctrl->cas_supported = 0xff; - valid_dimms = 0; - for (i = 0; i < VX900_MAX_DIMM_SLOTS; i++) { - const dimm_attr *dimm = &dimms->dimm[i]; - if (dimm->dram_type == SPD_MEMORY_TYPE_UNDEFINED) - continue; - valid_dimms++; - - if (valid_dimms == 1) { - /* First DIMM defines the type of DIMM */ - ctrl->dram_type = dimm->dram_type; - ctrl->dimm_type = dimm->dimm_type; - } else { - /* Check if we have mismatched DIMMs */ - if (ctrl->dram_type != dimm->dram_type - || ctrl->dimm_type != dimm->dimm_type) - die("Mismatched DIMM Types"); - } - /* Find all possible CAS combinations */ - ctrl->cas_supported &= dimm->cas_supported; - - /* Find the smallest common latencies supported by all DIMMs */ - ctrl->tCK = MAX(ctrl->tCK, dimm->tCK); - ctrl->tAA = MAX(ctrl->tAA, dimm->tAA); - ctrl->tWR = MAX(ctrl->tWR, dimm->tWR); - ctrl->tRCD = MAX(ctrl->tRCD, dimm->tRCD); - ctrl->tRRD = MAX(ctrl->tRRD, dimm->tRRD); - ctrl->tRP = MAX(ctrl->tRP, dimm->tRP); - ctrl->tRAS = MAX(ctrl->tRAS, dimm->tRAS); - ctrl->tRC = MAX(ctrl->tRC, dimm->tRC); - ctrl->tRFC = MAX(ctrl->tRFC, dimm->tRFC); - ctrl->tWTR = MAX(ctrl->tWTR, dimm->tWTR); - ctrl->tRTP = MAX(ctrl->tRTP, dimm->tRTP); - ctrl->tFAW = MAX(ctrl->tFAW, dimm->tFAW); - - } - - ctrl->n_dimms = valid_dimms; - if (!ctrl->cas_supported) - die("Unsupported DIMM combination. " - "DIMMS do not support common CAS latency"); - if (!valid_dimms) - die("No valid DIMMs found"); -} - -static void vx900_dram_phys_bank_range(const dimm_info * dimms, - rank_layout * ranks) -{ - size_t i; - for (i = 0; i < VX900_MAX_DIMM_SLOTS; i++) { - if (dimms->dimm[i].dram_type == SPD_MEMORY_TYPE_UNDEFINED) - continue; - u8 nranks = dimms->dimm[i].ranks; - /* Make sure we save the flags */ - ranks->flags[i * 2 + 1] = ranks->flags[i * 2] = - dimms->dimm[i].flags; - /* Only Rank1 has a mirrored pin mapping */ - ranks->flags[i * 2].pins_mirrored = 0; - if (nranks > 2) - die("Found DIMM with more than two ranks, which is not " - "supported by this chipset"); - u32 size = dimms->dimm[i].size_mb; - if (nranks == 2) { - /* Each rank holds half the capacity of the DIMM */ - size >>= 1; - ranks->phys_rank_size_mb[i << 1] = size; - ranks->phys_rank_size_mb[(i << 1) | 1] = size; - } else { - /* Otherwise, everything is held in the first bank */ - ranks->phys_rank_size_mb[i << 1] = size; - ranks->phys_rank_size_mb[(i << 1) | 1] = 0; - } - } -} - -#define ODT_R0 0 -#define ODT_R1 1 -#define ODT_R2 2 -#define ODT_R3 3 -/* - * This is the table that tells us which MODT pin to map to which rank. - * - * This table is taken from code provided by VIA, but no explanation was - * provided as to why it is done this way. It may be possible that this table is - * not suitable for the way we map ranks later on. - */ -static const u8 odt_lookup_table[][2] = { - /* RankMAP Rank 3 Rank 2 Rank 1 Rank 0 */ - {0x01, (ODT_R3 << 6) | (ODT_R2 << 4) | (ODT_R1 << 2) | (ODT_R0 << 0)}, - {0x03, (ODT_R3 << 6) | (ODT_R2 << 4) | (ODT_R0 << 2) | (ODT_R1 << 0)}, - {0x04, (ODT_R3 << 6) | (ODT_R2 << 4) | (ODT_R1 << 2) | (ODT_R0 << 0)}, - {0x05, (ODT_R3 << 6) | (ODT_R0 << 4) | (ODT_R1 << 2) | (ODT_R2 << 0)}, - {0x07, (ODT_R3 << 6) | (ODT_R0 << 4) | (ODT_R2 << 2) | (ODT_R2 << 0)}, - {0x0c, (ODT_R2 << 6) | (ODT_R3 << 4) | (ODT_R1 << 2) | (ODT_R0 << 0)}, - {0x0d, (ODT_R0 << 6) | (ODT_R0 << 4) | (ODT_R1 << 2) | (ODT_R2 << 0)}, - {0x0f, (ODT_R0 << 6) | (ODT_R0 << 4) | (ODT_R2 << 2) | (ODT_R2 << 0)}, - {0, 0}, -}; - -static void vx900_dram_driving_ctrl(const dimm_info * dimm) -{ - size_t i, ndimms; - u8 reg8, regxd5, rank_mask; - - rank_mask = 0; - /* For ODT range selection, datasheet recommends - * when 1 DIMM present: 60 Ohm - * when 2 DIMMs present: 120 Ohm */ - ndimms = 0; - for (i = 0; i < VX900_MAX_DIMM_SLOTS; i++) { - if (dimm->dimm[i].dram_type != SPD_MEMORY_TYPE_SDRAM_DDR3) - continue; - ndimms++; - rank_mask |= (1 << (i * 2)); - if (dimm->dimm[i].ranks > 1) - rank_mask |= (2 << (i * 2)); - } - /* ODT strength and MD/MDQM/MDQS driving strength */ - if (ndimms > 1) { - /* Enable 1 ODT block (120 Ohm ODT) */ - regxd5 = 0 << 2; - /* Enable strong driving for MD/MDQM/MDQS */ - regxd5 |= (1 << 7); - } else { - /* Enable 2 ODT blocks (60 Ohm ODT) */ - regxd5 = 1 << 2; - /* Leave MD/MDQM/MDQS driving weak */ - } - pci_write_config8(MCU, 0xd5, regxd5); - - /* Enable strong CLK driving for DIMMs with more than one rank */ - if (dimm->dimm[0].ranks > 1) - pci_or_config8(MCU, 0xd6, (1 << 7)); - if (dimm->dimm[1].ranks > 1) - pci_or_config8(MCU, 0xd6, (1 << 6)); - - /* DRAM ODT Lookup Table */ - for (i = 0;; i++) { - if (odt_lookup_table[i][0] == 0) { - printram("No ODT entry for rank mask %x\n", rank_mask); - die("Aborting"); - } - if (odt_lookup_table[i][0] != rank_mask) - continue; - - reg8 = odt_lookup_table[i][1]; - break; - } - - printram("Mapping rank mask %x to ODT entry %.2x\n", rank_mask, reg8); - pci_write_config8(MCU, 0x9c, reg8); - - for (i = 0; i < (sizeof(mcu_drv_ctrl_config) / sizeof(pci_reg8)); i++) { - pci_write_config8(MCU, mcu_drv_ctrl_config[i].addr, - mcu_drv_ctrl_config[i].val); - } -} - -static void vx900_pr_map_all_vr3(void) -{ - /* Enable all ranks and set them to VR3 */ - pci_write_config16(MCU, 0x54, 0xbbbb); -} - -/* Map physical rank pr to virtual rank vr */ -static void vx900_map_pr_vr(u8 pr, u8 vr) -{ - u16 val; - - pr &= 0x3; - vr &= 0x3; - /* Enable rank (bit [3], and set the VR number bits [1:0] */ - val = 0x8 | vr; - /* Now move the value to the appropriate PR */ - val <<= (pr * 4); - pci_update_config16(MCU, 0x54, ~(0xf << (pr * 4)), val); - printram("Mapping PR %u to VR %u\n", pr, vr); -} - -static u8 vx900_get_CWL(u8 CAS) -{ - /* Get CWL based on CAS using the following rule: - * _________________________________________ - * CAS: | 4T | 5T | 6T | 7T | 8T | 9T | 10T | 11T | - * CWL: | 5T | 5T | 5T | 6T | 6T | 7T | 7T | 8T | - */ - static const u8 cas_cwl_map[] = { 5, 5, 5, 6, 6, 7, 7, 8 }; - if (CAS > 11) - return 8; - return cas_cwl_map[CAS - 4]; -} - -/* - * Here we are calculating latencies, and writing them to the appropriate - * registers. Note that some registers do not take latencies from 0 = 0T, - * 1 = 1T, so each register gets its own math formula. - */ -static void vx900_dram_timing(ramctr_timing * ctrl) -{ - u8 reg8, val, tFAW, tRRD; - - /* Maximum supported DDR3 frequency is 533MHz (DDR3 1066) so make sure - * we cap it if we have faster DIMMs. - * Then, align it to the closest JEDEC standard frequency */ - if (ctrl->tCK <= TCK_533MHZ) { - ctrl->tCK = TCK_533MHZ; - } else if (ctrl->tCK <= TCK_400MHZ) { - ctrl->tCK = TCK_400MHZ; - } else if (ctrl->tCK <= TCK_333MHZ) { - ctrl->tCK = TCK_333MHZ; - } else { - ctrl->tCK = TCK_266MHZ; - } - - printram("Selected DRAM frequency: %u MHz\n", (1000 << 8) / ctrl->tCK); - - /* Find CAS and CWL latencies */ - val = DIV_ROUND_UP(ctrl->tAA, ctrl->tCK); - printram("Minimum CAS latency : %uT\n", val); - /* Find lowest supported CAS latency that satisfies the minimum value */ - while (!((ctrl->cas_supported >> (val - 4)) & 1) - && (ctrl->cas_supported >> (val - 4))) { - val++; - } - /* Is CAS supported */ - if (!(ctrl->cas_supported & (1 << (val - 4)))) - printram("CAS not supported\n"); - printram("Selected CAS latency : %uT\n", val); - ctrl->CAS = val; - ctrl->CWL = vx900_get_CWL(ctrl->CAS); - printram("Selected CWL latency : %uT\n", ctrl->CWL); - /* Write CAS and CWL */ - reg8 = (((ctrl->CWL - 4) & 0x07) << 4) | ((ctrl->CAS - 4) & 0x07); - pci_write_config8(MCU, 0xc0, reg8); - - /* Find tRCD */ - val = DIV_ROUND_UP(ctrl->tRCD, ctrl->tCK); - printram("Selected tRCD : %uT\n", val); - reg8 = ((val - 4) & 0x7) << 4; - /* Find tRP */ - val = DIV_ROUND_UP(ctrl->tRP, ctrl->tCK); - printram("Selected tRP : %uT\n", val); - reg8 |= ((val - 4) & 0x7); - pci_write_config8(MCU, 0xc1, reg8); - - /* Find tRAS */ - val = DIV_ROUND_UP(ctrl->tRAS, ctrl->tCK); - printram("Selected tRAS : %uT\n", val); - reg8 = ((val - 15) & 0x7) << 4; - /* Find tWR */ - ctrl->WR = DIV_ROUND_UP(ctrl->tWR, ctrl->tCK); - printram("Selected tWR : %uT\n", ctrl->WR); - reg8 |= ((ctrl->WR - 4) & 0x7); - pci_write_config8(MCU, 0xc2, reg8); - - /* Find tFAW */ - tFAW = DIV_ROUND_UP(ctrl->tFAW, ctrl->tCK); - printram("Selected tFAW : %uT\n", tFAW); - /* Find tRRD */ - tRRD = DIV_ROUND_UP(ctrl->tRRD, ctrl->tCK); - printram("Selected tRRD : %uT\n", tRRD); - val = tFAW - 4 * tRRD; /* number of cycles above 4*tRRD */ - reg8 = ((val - 0) & 0x7) << 4; - reg8 |= ((tRRD - 2) & 0x7); - pci_write_config8(MCU, 0xc3, reg8); - - /* Find tRTP */ - val = DIV_ROUND_UP(ctrl->tRTP, ctrl->tCK); - printram("Selected tRTP : %uT\n", val); - reg8 = ((val & 0x3) << 4); - /* Find tWTR */ - val = DIV_ROUND_UP(ctrl->tWTR, ctrl->tCK); - printram("Selected tWTR : %uT\n", val); - reg8 |= ((val - 2) & 0x7); - pci_update_config8(MCU, 0xc4, ~0x3f, reg8); - - /* DRAM Timing for All Ranks - VI - * [7:6] CKE Assertion Minimum Pulse Width - * We probably don't want to mess with this just yet. - * [5:0] Refresh-to-Active or Refresh-to-Refresh (tRFC) - * tRFC = (30 + 2 * [5:0])T - * Since we previously set RxC4[7] - */ - reg8 = pci_read_config8(MCU, 0xc5); - val = DIV_ROUND_UP(ctrl->tRFC, ctrl->tCK); - printram("Minimum tRFC : %uT\n", val); - if (val < 30) { - val = 0; - } else { - val = (val - 30 + 1) / 2; - } - ; - printram("Selected tRFC : %uT\n", 30 + 2 * val); - reg8 |= (val & 0x3f); - pci_write_config8(MCU, 0xc5, reg8); - - /* Where does this go??? */ - val = DIV_ROUND_UP(ctrl->tRC, ctrl->tCK); - printram("Required tRC : %uT\n", val); -} - -/* Program the DRAM frequency */ -static void vx900_dram_freq(ramctr_timing * ctrl) -{ - u8 val; - - /* Step 1 - Reset the PLL */ - pci_or_config8(MCU, 0x90, 0x0f); - /* Wait at least 10 ns; VIA code delays by 640us */ - udelay(640); - - /* Step 2 - Set target frequency */ - if (ctrl->tCK <= TCK_533MHZ) { - val = 0x07; - ctrl->tCK = TCK_533MHZ; - } else if (ctrl->tCK <= TCK_400MHZ) { - val = 0x06; - ctrl->tCK = TCK_400MHZ; - } else if (ctrl->tCK <= TCK_333MHZ) { - val = 0x05; - ctrl->tCK = TCK_333MHZ; - } else { /*ctrl->tCK <= TCK_266MHZ */ - val = 0x04; - ctrl->tCK = TCK_266MHZ; - } - /* Restart the PLL with the desired frequency */ - pci_update_config8(MCU, 0x90, ~0x0f, val); - - /* Step 3 - Wait for PLL to stabilize */ - udelay(2000); - - /* Step 4 - Reset the DLL - Clear [7,4] */ - pci_update_config8(MCU, 0x6b, (u8)~0x90, 0x00); - udelay(2000); - - /* Step 5 - Enable the DLL - Set bits [7,4] to 01b */ - pci_or_config8(MCU, 0x6b, 0x10); - udelay(2000); - - /* Step 6 - Start DLL Calibration - Set bit [7] */ - pci_or_config8(MCU, 0x6b, 0x80); - udelay(5); - - /* Step 7 - Finish DLL Calibration - Clear bit [7] */ - pci_update_config8(MCU, 0x6b, (u8)~0x80, 0x00); - - /* Step 8 - If we have registered DIMMs, we need to set bit[0] */ - if (spd_dimm_is_registered_ddr3(ctrl->dimm_type)) { - printram("Enabling RDIMM support in memory controller\n"); - pci_or_config8(MCU, 0x6c, 0x01); - } -} - -/* - * The VX900 can send the MRS commands directly through hardware - * It does the MR2->MR3->MR1->MR0->LongZQ JEDEC dance - * The parameters that we don't worry about are extracted from the timing - * registers we have programmed earlier. - */ -static void vx900_dram_ddr3_do_hw_mrs(u8 ma_swap, u8 rtt_nom, - u8 ods, u8 rtt_wr, u8 srt, u8 asr) -{ - u16 reg16 = 0; - - printram("Using Hardware method for DRAM MRS commands.\n"); - - reg16 |= ((rtt_wr & 0x03) << 12); - if (srt) - reg16 |= (1 << 9); - if (asr) - reg16 |= (1 << 8); - reg16 |= ((rtt_nom & 0x7) << 4); - reg16 |= ((ods & 0x03) << 2); - if (ma_swap) - reg16 |= (1 << 1); - reg16 |= (1 << 14); - reg16 |= (1 << 0); /* This is the trigger bit */ - printram("Hw MRS set is 0x%4x\n", reg16); - pci_write_config16(MCU, 0xcc, reg16); - /* Wait for MRS commands to be sent */ - while (pci_read_config8(MCU, 0xcc) & 1); -} - -/* - * Translate the MRS command into an address on the CPU bus - * - * Take an MRS command (mrs_cmd_t) and translate it to a read address on the CPU - * bus. Thus, reading from the returned address, will issue the correct MRS - * command, assuming we are in MRS mode, of course. - * - * A read from the returned address will produce the correct MRS command - * provided the following conditions are met: - * - The MA pin mapping is set to VX900_MRS_MA_MAP - * - The memory controller's Fun3_RX6B[2:0] is set to 011b (MSR Enable) - */ -static u32 vx900_get_mrs_addr(mrs_cmd_t cmd) -{ - u32 addr = 0; - u8 mrs_type = (cmd >> 16) & 0x07; - /* MA[9:0] <-> A[12:3] */ - addr |= ((cmd & 0x3ff) << 3); - /* MA10 <-> A20 */ - addr |= (((cmd >> 10) & 0x1) << 20); - /* MA[12:11] <-> A[14:13] */ - addr |= (((cmd >> 11) & 0x3) << 13); - /* BA[2:0] <-> A[19:17] */ - addr |= mrs_type << 17; - return addr; -} - -/* - * Here, we do the MR2->MR3->MR1->MR0->LongZQ JEDEC dance manually - * - * Why would we do this in software, when the VX900 can do it in hardware? The - * problem is the hardware sequence seems to be buggy on ranks with mirrored - * pins. Is this a hardware bug or a misconfigured MCU? No idea. - * - * To maintain API compatibility with the function that implements the hardware - * sequence, we don't ask for all parameters. To keep an overall cleaner code - * structure, we don't try to pass down all that information. Instead, we - * extract the extra parameters from the timing registers we have programmed - * earlier. - */ -static void vx900_dram_ddr3_do_sw_mrs(u8 ma_swap, enum ddr3_mr1_rtt_nom rtt_nom, - enum ddr3_mr1_ods ods, - enum ddr3_mr2_rttwr rtt_wr, - enum ddr3_mr2_srt_range srt, - enum ddr3_mr2_asr asr) -{ - mrs_cmd_t mrs; - u8 reg8, cas, cwl, twr; - - printram("Using Software method for DRAM MRS commands.\n"); - - /* Get CAS, CWL, and tWR that we programmed earlier */ - reg8 = pci_read_config8(MCU, 0xc0); - cas = (reg8 & 0x07) + 4; - cwl = ((reg8 >> 4) & 0x07) + 4; - reg8 = pci_read_config8(MCU, 0xc2); - twr = (reg8 & 0x07) + 4; - - /* Step 06 - Set Fun3_RX6B[2:0] to 001b (NOP Command Enable). */ - /* Was already done for us before calling us */ - - /* Step 07 - Read a double word from any address of the DIMM. */ - /* Was already done for us before calling us */ - - /* Step 08 - Set Fun3_RX6B[2:0] to 011b (MSR Enable). */ - pci_update_config8(MCU, 0x6b, ~0x07, 0x03); /* MSR Enable */ - - /* Step 09 - Issue MR2 cycle. Read a double word from the address - * depended on DRAM's Rtt_WR and CWL settings. */ - mrs = ddr3_get_mr2(rtt_wr, srt, asr, cwl); - if (ma_swap) - mrs = ddr3_mrs_mirror_pins(mrs); - volatile_read(vx900_get_mrs_addr(mrs)); - printram("MR2: %.5x\n", mrs); - udelay(1000); - - /* Step 10 - Issue MR3 cycle. Read a double word from the address 60000h - * to set DRAM to normal operation mode. */ - mrs = ddr3_get_mr3(0); - if (ma_swap) - mrs = ddr3_mrs_mirror_pins(mrs); - volatile_read(vx900_get_mrs_addr(mrs)); - printram("MR3: %.5x\n", mrs); - udelay(1000); - - /* Step 11 -Issue MR1 cycle. Read a double word from the address - * depended on DRAM's output driver impedance and Rtt_Nom settings. - * The DLL enable field, TDQS field, write leveling enable field, - * additive latency field and Qoff field should be set to 0. */ - mrs = ddr3_get_mr1(DDR3_MR1_QOFF_ENABLE, DDR3_MR1_TQDS_DISABLE, rtt_nom, - DDR3_MR1_WRLVL_DISABLE, ods, DDR3_MR1_AL_DISABLE, - DDR3_MR1_DLL_ENABLE); - if (ma_swap) - mrs = ddr3_mrs_mirror_pins(mrs); - volatile_read(vx900_get_mrs_addr(mrs)); - printram("MR1: %.5x\n", mrs); - udelay(1000); - - /* Step 12 - Issue MR0 cycle. Read a double word from the address - * depended on DRAM's burst length, CAS latency and write recovery time - * settings. - * The read burst type field should be set to interleave. - * The mode field should be set to normal mode. - * The DLL reset field should be set to No. - * The DLL control for precharge PD field should be set to Fast exit. - */ - mrs = ddr3_get_mr0(DDR3_MR0_PRECHARGE_FAST, twr, - DDR3_MR0_DLL_RESET_NO, DDR3_MR0_MODE_NORMAL, cas, - DDR3_MR0_BURST_TYPE_INTERLEAVED, - DDR3_MR0_BURST_LENGTH_CHOP); - volatile_read(vx900_get_mrs_addr(mrs)); - printram("MR0: %.5x\n", mrs); - udelay(1000); - - /* Step 13 - Set Fun3_RX6B[2:0] to 110b (Long ZQ calibration cmd) */ - pci_update_config8(MCU, 0x6b, ~0x07, 0x06); /* Long ZQ */ - /* Step 14 - Read a double word from any address of the DIMM. */ - volatile_read(0); - udelay(1000); -} - -/* - * This is where we take the DIMMs out of reset and do the JEDEC dance for each - * individual physical rank. - */ -static void vx900_dram_ddr3_dimm_init(const ramctr_timing * ctrl, - const rank_layout * ranks) -{ - size_t i; - u8 rtt_nom, rtt_wr, ods, pinswap; - - /* Set BA[0/1/2] to [A17/18/19] */ - vx900_dram_set_ma_pin_map(VX900_MRS_MA_MAP); - - /* Step 01 - Set Fun3_Rx6E[5] to 1b to support burst length. */ - pci_or_config8(MCU, 0x6e, 1 << 5); - /* Step 02 - Set Fun3_RX69[0] to 0b (Disable Multiple Page Mode). */ - pci_update_config8(MCU, 0x69, ~(1 << 0), 0x00); - /* And set [7:6] to 10b ? */ - pci_write_config8(MCU, 0x69, 0x87); - - /* Step 03 - Set the target physical rank to virtual rank0 and other - * ranks to virtual rank3. */ - vx900_pr_map_all_vr3(); - - /* Step 04 - Set Fun3_Rx50 to D8h. */ - pci_write_config8(MCU, 0x50, 0xd8); - /* Step 05 - Set Fun3_RX6B[5] to 1b to de-assert RESET# and wait for at - * least 500 us. */ - pci_or_config8(MCU, 0x6b, (1 << 5)); - udelay(500); - - /* Step 6 -> 15 - Set the target physical rank to virtual rank 0 and - * other ranks to virtual rank 3. - * Repeat Step 6 to 14 for every rank present, then jump to Step 16. */ - for (i = 0; i < VX900_MAX_MEM_RANKS; i++) { - if (ranks->phys_rank_size_mb[i] == 0) - continue; - printram("Initializing rank %zu\n", i); - - /* Set target physical rank to virtual rank 0 - * other ranks to virtual rank 3*/ - vx900_map_pr_vr(i, 0); - - /* FIXME: Is this needed on HW init? */ - pci_update_config8(MCU, 0x6b, ~0x07, 0x01); /* Enable NOP */ - volatile_read(0x0); /* Do NOP */ - pci_update_config8(MCU, 0x6b, ~0x07, 0x03); /* MSR Enable */ - - /* See init_dram_by_rank.c and get_basic_information.c - * in the VIA provided code */ - if (ctrl->n_dimms == 1) { - rtt_nom = DDR3_MR1_RTT_NOM_RZQ2; - rtt_wr = DDR3_MR2_RTTWR_OFF; - } else { - rtt_nom = DDR3_MR1_RTT_NOM_RZQ8; - rtt_wr = DDR3_MR2_RTTWR_RZQ2; - } - ods = ranks->flags[i].rzq7_supported ? - DDR3_MR1_ODS_RZQ7 : DDR3_MR1_ODS_RZQ6; - - pinswap = (ranks->flags[i].pins_mirrored); - if (pinswap) - printram("Pins mirrored\n"); - printram(" Swap : %x\n", pinswap); - printram(" rtt_nom : %x\n", rtt_nom); - printram(" ods : %x\n", ods); - printram(" rtt_wr : %x\n", rtt_wr); - if (RAMINIT_USE_HW_MRS_SEQ) - vx900_dram_ddr3_do_hw_mrs(pinswap, rtt_nom, ods, rtt_wr, - 0, 0); - else - vx900_dram_ddr3_do_sw_mrs(pinswap, rtt_nom, ods, rtt_wr, - 0, 0); - - /* Normal SDRAM Mode */ - pci_update_config8(MCU, 0x6b, ~0x07, 0x00); - - /* Step 15, set the rank to virtual rank 3 */ - vx900_map_pr_vr(i, 3); - } - - /* Step 16 - Set Fun3_Rx6B[2:0] to 000b (Normal SDRAM Mode). */ - pci_update_config8(MCU, 0x6b, ~0x07, 0x00); - - /* Set BA[0/1/2] to [A13/14/15] */ - vx900_dram_set_ma_pin_map(VX900_CALIB_MA_MAP); - - /* Step 17 - Set Fun3_Rx69[0] to 1b (Enable Multiple Page Mode). */ - pci_or_config8(MCU, 0x69, (1 << 0)); - - printram("DIMM initialization sequence complete\n"); -} - -/* - * This a small utility to send a single MRS command, but where we don't want to - * have to worry about changing the MCU mode. It gives the MCU back to us in - * normal operating mode. - */ -static void vx900_dram_send_soft_mrs(mrs_cmd_t cmd, u8 pin_swap) -{ - u32 addr; - /* Set Fun3_RX6B[2:0] to 011b (MSR Enable). */ - pci_update_config8(MCU, 0x6b, ~0x07, (3 << 0)); - /* Is this a funky rank with Address pins swapped? */ - if (pin_swap) - cmd = ddr3_mrs_mirror_pins(cmd); - /* Find the address corresponding to the MRS */ - addr = vx900_get_mrs_addr(cmd); - /* Execute the MRS */ - volatile_read(addr); - /* Set Fun3_Rx6B[2:0] to 000b (Normal SDRAM Mode). */ - pci_update_config8(MCU, 0x6b, ~0x07, 0x00); -} - -static void vx900_dram_enter_read_leveling(u8 pinswap) -{ - /* Precharge all before issuing read leveling MRS to DRAM */ - pci_update_config8(MCU, 0x06b, ~0x07, 0x02); - volatile_read(0x0); - udelay(1000); - - /* Enable read leveling: Set D0F3Rx71[7]=1 */ - pci_or_config8(MCU, 0x71, (1 << 7)); - - /* Put DRAM in read leveling mode */ - mrs_cmd_t cmd = ddr3_get_mr3(1); - vx900_dram_send_soft_mrs(cmd, pinswap); -} - -static void vx900_dram_exit_read_leveling(u8 pinswap) -{ - /* Disable read leveling, and put dram in normal operation mode */ - mrs_cmd_t cmd = ddr3_get_mr3(0); - vx900_dram_send_soft_mrs(cmd, pinswap); - - /* Disable read leveling: Set D0F3Rx71[7]=0 */ - pci_update_config8(MCU, 0x71, (u8)~(1 << 7), 0); -} - -/* - * We need to see if the delay window (difference between minimum and maximum) - * is large enough so that we actually have a valid window. The signal should be - * valid for at least 1/2T in general. If the window is significantly smaller, - * then chances are our window does not latch at the correct time, and the - * calibration will not work. - */ -#define DQSI_THRESHOLD 0x10 -#define DQO_THRESHOLD 0x09 -#define DQSO_THRESHOLD 0x12 -#define DELAY_RANGE_GOOD 0 -#define DELAY_RANGE_BAD -1 -static u8 vx900_dram_check_calib_range(const delay_range * dly, u8 window) -{ - size_t i; - for (i = 0; i < 8; i++) { - if (dly->high[i] - dly->low[i] < window) - return DELAY_RANGE_BAD; - /* When our maximum value is lower than our min, both values - * have overshot, and the window is definitely invalid */ - if (dly->high[i] < dly->low[i]) - return DELAY_RANGE_BAD; - } - return DELAY_RANGE_GOOD; -} - -static void vx900_dram_find_avg_delays(vx900_delay_calib * delays) -{ - size_t i; - u16 dq_low, dq_high, dqs_low, dqs_high, dq_final, dqs_final; - /* - * At this point, we have transmit delays for both DIMMA and DIMMB, each - * with a slightly different window We want to find the intersection of - * those windows, so that we have a constrained window which both - * DIMMA and DIMMB can use. The center of our constrained window will - * also be the safest setting for the transmit delays - * - * DIMMA window t:|xxxxxxxxxxxxxx---------------xxxxxxxxxxxxxxxxxxxxxxx| - * DIMMB window t:|xxxxxxxxxxxxxxxxxxx---------------xxxxxxxxxxxxxxxxxx| - * Safe window t:|xxxxxxxxxxxxxxxxxxx----------xxxxxxxxxxxxxxxxxxxxxxx| - */ - delay_range *tx_dq_a = &(delays->tx_dq[0]); - delay_range *tx_dq_b = &(delays->tx_dq[1]); - delay_range *tx_dqs_a = &(delays->tx_dqs[0]); - delay_range *tx_dqs_b = &(delays->tx_dqs[1]); - - for (i = 0; i < 8; i++) { - dq_low = MAX(tx_dq_a->low[i], tx_dq_b->low[i]); - dq_high = MIN(tx_dq_a->high[i], tx_dq_b->high[i]); - dqs_low = MAX(tx_dqs_a->low[i], tx_dqs_b->low[i]); - dqs_high = MIN(tx_dqs_a->high[i], tx_dqs_b->high[i]); - - /* Find the average */ - dq_final = ((dq_low + dq_high) / 2); - dqs_final = ((dqs_low + dqs_high) / 2); - - /* - * These adjustments are done in code provided by VIA. - * There is no explanation as to why this is done. - * - * We can get away without doing the DQS adjustment, but doing - * it, brings the values closer to what the vendor BIOS - * calibrates to. - */ - if ((dqs_final & 0x1f) >= 0x1c) - dqs_final -= 0x1c; - else - dqs_final += 0x04; - /* - * The DQ adjustment is more critical. If we don't do this - * adjustment our MCU won't be configured properly, and - * ram_check() will fail. - */ - if ((dq_final & 0x1f) >= 0x14) - dq_final -= 0x14; - else - dq_final += 0x0c; - - /* Store our values in the first delay */ - delays->tx_dq[0].avg[i] = dq_final; - delays->tx_dqs[0].avg[i] = dqs_final; - - } -} - -/* - * First calibration: When to receive data from the DRAM - * (MD and MDQS input delay) - * - * This calibration unfortunately does not seem to work. Whether this is due to - * a misconfigured MCU or hardware bug is unknown. - */ -static void vx900_rx_capture_range_calib(u8 pinswap) -{ - u8 reg8; - const u32 cal_addr = 0x20; - - /* Set IO calibration address */ - pci_update_config16(MCU, 0x8c, (u16)~0xfff0, cal_addr & (0xfff0)); - /* Data pattern must be 0x00 for this calibration - * See paragraph describing Rx8e */ - pci_write_config8(MCU, 0x8e, 0x00); - - /* Need to put DRAM and MCU in read leveling */ - vx900_dram_enter_read_leveling(pinswap); - - /* Data pattern must be 0x00 for this calibration - * See paragraph describing Rx8e */ - pci_write_config8(MCU, 0x8e, 0x00); - /* Trigger calibration */ - reg8 = 0xa0; - pci_write_config8(MCU, 0x71, reg8); - - /* Wait for it */ - while (pci_read_config8(MCU, 0x71) & 0x10); - vx900_dram_exit_read_leveling(pinswap); -} - -/* - * Second calibration: How much to delay DQS signal by - * (MDQS input delay) - */ -static void vx900_rx_dqs_delay_calib(u8 pinswap) -{ - const u32 cal_addr = 0x30; - - /* We need to disable refresh commands so that they don't interfere */ - const u8 ref_cnt = pci_read_config8(MCU, 0xc7); - pci_write_config8(MCU, 0xc7, 0); - /* Set IO calibration address */ - pci_update_config16(MCU, 0x8c, (u16)~0xfff0, cal_addr & (0xfff0)); - /* Data pattern must be 0x00 for this calibration - * See paragraph describing Rx8e */ - pci_write_config8(MCU, 0x8e, 0x00); - - /* Need to put DRAM and MCU in read leveling */ - vx900_dram_enter_read_leveling(pinswap); - - /* From VIA code; Undocumented - * In theory this enables MODT[3:0] to be asserted */ - pci_or_config8(MCU, 0x9e, 0x80); - - /* Trigger calibration: Set D0F3Rx71[1:0]=10b */ - pci_update_config8(MCU, 0x71, ~0x03, 0x02); - - /* Wait for calibration to complete */ - while (pci_read_config8(MCU, 0x71) & 0x02); - vx900_dram_exit_read_leveling(pinswap); - - /* Restore the refresh counter */ - pci_write_config8(MCU, 0xc7, ref_cnt); - - /* FIXME: should we save it before, or should we just set it as is */ - vx900_dram_set_ma_pin_map(VX900_CALIB_MA_MAP); -} - -static void vx900_tx_dqs_trigger_calib(u8 pattern) -{ - /* Data pattern for calibration */ - pci_write_config8(MCU, 0x8e, pattern); - /* Trigger calibration */ - pci_or_config8(MCU, 0x75, 0x20); - /* Wait for calibration */ - while (pci_read_config8(MCU, 0x75) & 0x20); -} - -/* - * Third calibration: How much to wait before asserting DQS - */ -static void vx900_tx_dqs_delay_calib(void) -{ - const u32 cal_addr = 0x00; - /* Set IO calibration address */ - pci_update_config16(MCU, 0x8c, (u16)~0xfff0, cal_addr & (0xfff0)); - /* Set circuit to use calibration results - Clear Rx75[0] */ - pci_update_config8(MCU, 0x75, ~0x01, 0); - /* Run calibration with first data pattern */ - vx900_tx_dqs_trigger_calib(0x5a); - /* Run again with different pattern */ - vx900_tx_dqs_trigger_calib(0xa5); -} - -/* - * Fourt calibration: How much to wait before putting data on DQ lines - */ -static void vx900_tx_dq_delay_calib(void) -{ - /* Data pattern for calibration */ - pci_write_config8(MCU, 0x8e, 0x5a); - /* Trigger calibration */ - pci_or_config8(MCU, 0x75, 0x02); - /* Wait for calibration */ - while (pci_read_config8(MCU, 0x75) & 0x02); -} - -static void vx900_rxdqs_adjust(delay_range * dly) -{ - /* Adjust Rx DQS delay after calibration has been run. This is - * recommended by VIA, but no explanation was provided as to why */ - size_t i; - for (i = 0; i < 8; i++) { - if (dly->low[i] < 3) { - if (i == 2 || i == 4) - dly->avg[i] += 4; - else - dly->avg[i] += 3; - - } - - if (dly->high[i] > 0x38) - dly->avg[i] -= 6; - else if (dly->high[i] > 0x30) - dly->avg[i] -= 4; - - if (dly->avg[i] > 0x20) - dly->avg[i] = 0x20; - } - - /* Put Rx DQS delay into manual mode (Set Rx[2,0] to 01) */ - pci_update_config8(MCU, 0x71, ~0x05, 0x01); - /* Now write the new settings */ - vx900_delay_calib_mode_select(CALIB_RxDQS, CALIB_MANUAL); - vx900_write_0x78_0x7f(dly->avg); -} - -static void vx900_dram_calibrate_receive_delays(vx900_delay_calib * delays, - u8 pinswap) -{ - size_t n_tries = 0; - delay_range *rx_dq_cr = &(delays->rx_dq_cr); - delay_range *rx_dqs = &(delays->rx_dqs); - /* We really should be able to finish this in a single pass, but it may - * in very rare circumstances not work the first time. We define a limit - * on the number of tries so that we have a way of warning the user */ - const size_t max_tries = 100; - for (;;) { - if (n_tries++ >= max_tries) { - die("Could not calibrate receive delays. Giving up"); - } - u8 result; - /* Run calibrations */ - if (RAMINIT_USE_HW_RXCR_CALIB) { - vx900_rx_capture_range_calib(pinswap); - vx900_read_delay_range(rx_dq_cr, CALIB_RxDQ_CR); - dump_delay_range(*rx_dq_cr); - - } else { - /*FIXME: Cheating with Rx CR setting\ - * We need to either use Rx CR calibration - * or set up a table for the calibration */ - u8 *override = &(rx_dq_cr->avg[0]); - override[0] = 0x28; - override[1] = 0x1c; - override[2] = 0x28; - override[3] = 0x28; - override[4] = 0x2c; - override[5] = 0x30; - override[6] = 0x30; - override[7] = 0x34; - printram("Bypassing RxCR 78-7f calibration with:\n"); - dump_delay(rx_dq_cr->avg); - } - /* We need to put the setting on manual mode */ - pci_or_config8(MCU, 0x71, 1 << 4); - vx900_delay_calib_mode_select(CALIB_RxDQ_CR, CALIB_MANUAL); - vx900_write_0x78_0x7f(rx_dq_cr->avg); - - /************* RxDQS *************/ - vx900_rx_dqs_delay_calib(pinswap); - vx900_read_delay_range(rx_dqs, CALIB_RxDQS); - vx900_rxdqs_adjust(rx_dqs); - - result = vx900_dram_check_calib_range(rx_dqs, DQSI_THRESHOLD); - if (result != DELAY_RANGE_GOOD) - continue; - - /* We're good to go. Switch to manual and write the manual - * setting */ - pci_or_config8(MCU, 0x71, 1 << 0); - vx900_delay_calib_mode_select(CALIB_RxDQS, CALIB_MANUAL); - vx900_write_0x78_0x7f(rx_dqs->avg); - break; - } - if (n_tries > 1) - printram("Hmm, we had to try %zu times before our calibration " - "was good.\n", n_tries); -} - -static void vx900_dram_calibrate_transmit_delays(delay_range * tx_dq, - delay_range * tx_dqs) -{ - /* Same timeout reasoning as in receive delays */ - size_t n_tries = 0; - int dq_tries = 0, dqs_tries = 0; - const size_t max_tries = 100; - for (;;) { - if (n_tries++ >= max_tries) { - printram("Tried DQS %i times and DQ %i times\n", - dqs_tries, dq_tries); - printram("Tx DQS calibration results\n"); - dump_delay_range(*tx_dqs); - printram("TX DQ delay calibration results:\n"); - dump_delay_range(*tx_dq); - die("Could not calibrate transmit delays. Giving up"); - } - u8 result; - /************* TxDQS *************/ - dqs_tries++; - vx900_tx_dqs_delay_calib(); - vx900_read_delay_range(tx_dqs, CALIB_TxDQS); - - result = vx900_dram_check_calib_range(tx_dqs, DQSO_THRESHOLD); - if (result != DELAY_RANGE_GOOD) - continue; - - /************* TxDQ *************/ - /* FIXME: not sure if multiple page mode should be enabled here - * Vendor BIOS does it */ - pci_or_config8(MCU, 0x69, 0x01); - - dq_tries++; - vx900_tx_dq_delay_calib(); - vx900_read_delay_range(tx_dq, CALIB_TxDQ); - - result = vx900_dram_check_calib_range(tx_dq, DQO_THRESHOLD); - if (result != DELAY_RANGE_GOOD) - continue; - - /* At this point, our RAM should give correct read-backs for - * addresses under 64 MB. If it doesn't, it won't work */ - if (ram_check_noprint_nodie(1 << 20, 1 << 20)) { - /* No, our RAM is not working, try again */ - /* FIXME: Except that we have not yet told the MCU what - * the geometry of the DIMM is, hence we don't trust - * this test for now */ - } - /* Good. We should be able to use this DIMM */ - /* That's it. We're done */ - break; - } - if (n_tries > 1) - printram("Hmm, we had to try %zu times before our calibration " - "was good.\n", n_tries); -} - -/* - * The meat and potatoes of getting our MCU to operate the DIMMs properly. - * - * Thank you JEDEC for making us need configurable delays for each set of MD - * signals. - */ -static void vx900_dram_calibrate_delays(const ramctr_timing * ctrl, - const rank_layout * ranks) -{ - size_t i; - u8 val; - u8 dimm; - vx900_delay_calib delay_cal; - memset(&delay_cal, 0, sizeof(delay_cal)); - printram("Starting delay calibration\n"); - - /**** Read delay control ****/ - /* MD Input Data Push Timing Control; - * use values recommended in datasheet - * Setting this too low causes the Rx window to move below the range we - * need it so we can capture it with Rx_78_7f - * This causes Rx calibrations to be too close to 0, and Tx - * calibrations will fail. - * Setting this too high causes the window to move above the range. - */ - if (ctrl->tCK <= TCK_533MHZ) - val = 2; - else if (ctrl->tCK <= TCK_333MHZ) - val = 1; - else - val = 0; - val++; /* FIXME: vendor BIOS sets this to 3 */ - pci_update_config8(MCU, 0x74, ~(0x03 << 1), ((val & 0x03) << 1)); - - /* FIXME: The vendor BIOS increases the MD input delay - WHY ? */ - pci_update_config8(MCU, 0xef, ~(3 << 4), 3 << 4); - - /**** Write delay control ****/ - /* FIXME: The vendor BIOS does this, but WHY? - * See check_special_registers in VIA provided code. This value seems - * to depend on the DRAM frequency. - */ - /* Early DQ/DQS for write cycles */ - pci_update_config8(MCU, 0x76, ~(3 << 2), 2 << 2); - /* FIXME: The vendor BIOS does this - Output preamble ? */ - pci_write_config8(MCU, 0x77, 0x10); - - /* Set BA[0/1/2] to [A17/18/19] */ - vx900_dram_set_ma_pin_map(VX900_MRS_MA_MAP); - /* Disable Multiple Page Mode - Set Rx69[0] to 0 */ - pci_update_config8(MCU, 0x69, ~(1 << 0), 0x00); - - /* It's very important that we keep all ranks which are not calibrated - * mapped to VR3. Even if we disable them, if they are mapped to VR0 - * (the rank we use for calibrations), the calibrations may fail in - * unexpected ways. */ - vx900_pr_map_all_vr3(); - - /* We only really need to run the receive calibrations once. They are - * meant to account for signal travel differences in the internal paths - * of the MCU, so it doesn't really matter which rank we use for this. - * Differences between ranks will be accounted for in the transmit - * calibration. */ - for (i = 0; i < VX900_MAX_DIMM_SLOTS; i += 2) { - /* Do we have a valid DIMM? */ - if (ranks->phys_rank_size_mb[i] + - ranks->phys_rank_size_mb[i + 1] == 0) - continue; - /* Map the first rank of the DIMM to VR0 */ - vx900_map_pr_vr(2 * i, 0); - /* Only run on first rank, remember? */ - break; - } - vx900_dram_calibrate_receive_delays(&delay_cal, - ranks->flags[i].pins_mirrored); - printram("RX DQS calibration results\n"); - dump_delay_range(delay_cal.rx_dqs); - - /* Enable multiple page mode for when calibrating transmit delays */ - pci_or_config8(MCU, 0x69, 1 << 1); - - /* - * Unlike the receive delays, we need to run the transmit calibration - * for each DIMM (not rank). We run the calibration on the even rank. - * The odd rank may have memory pins swapped, and this, it seems, - * confuses the calibration circuit. - */ - dimm = 0; - for (i = 0; i < VX900_MAX_DIMM_SLOTS; i++) { - /* Do we have a valid DIMM? */ - u32 dimm_size_mb = ranks->phys_rank_size_mb[2 * i] - + ranks->phys_rank_size_mb[2 * i + 1]; - if (dimm_size_mb == 0) - continue; - /* Map the first rank of the DIMM to VR0 */ - vx900_map_pr_vr(2 * i, 0); - vx900_dram_calibrate_transmit_delays(&(delay_cal.tx_dq[dimm]), - &(delay_cal.tx_dqs[dimm])); - /* We run this more than once, so dump delays for each DIMM */ - printram("Tx DQS calibration results\n"); - dump_delay_range(delay_cal.tx_dqs[dimm]); - printram("TX DQ delay calibration results:\n"); - dump_delay_range(delay_cal.tx_dq[dimm]); - /* Now move the DIMM back to VR3 */ - vx900_map_pr_vr(2 * i, 3); - /* We use dimm as a counter so that we fill tx_dq[] and tx_dqs[] - * results in order from 0, and do not leave any gaps */ - dimm++; - } - - /* When we have more dimms, we need to find a tx window with which all - * dimms can safely work */ - if (dimm > 1) { - vx900_dram_find_avg_delays(&delay_cal); - printram("Final delay values\n"); - printram("Tx DQS: "); - dump_delay(delay_cal.tx_dqs[0].avg); - printram("Tx DQ: "); - dump_delay(delay_cal.tx_dq[0].avg); - } - /* Write manual settings */ - pci_or_config8(MCU, 0x75, 0x01); - vx900_delay_calib_mode_select(CALIB_TxDQS, CALIB_MANUAL); - vx900_write_0x78_0x7f(delay_cal.tx_dqs[0].avg); - vx900_delay_calib_mode_select(CALIB_TxDQ, CALIB_MANUAL); - vx900_write_0x78_0x7f(delay_cal.tx_dq[0].avg); -} - -static void vx900_dram_set_refresh_counter(ramctr_timing * ctrl) -{ - u8 reg8; - /* Set DRAM refresh counter - * Based on a refresh counter of 0x61 at 400MHz */ - reg8 = (TCK_400MHZ * 0x61) / ctrl->tCK; - pci_write_config8(MCU, 0xc7, reg8); -} - -/* - * Here, we map each rank somewhere in our address space. We don't really care - * at this point if this will overlap the PCI config space. If needed, remapping - * is done in ramstage, where we actually know how much PCI space we actually - * need. - */ -static void vx900_dram_range(ramctr_timing * ctrl, rank_layout * ranks) -{ - size_t i, vrank = 0; - u8 reg8; - u32 ramsize_mb = 0, tolm_mb; - const u32 TOLM_3_5G = (7 << 29); - /* All unused physical ranks go to VR3. Otherwise, the MCU might be - * trying to read or write from unused ranks, or even worse, write some - * bits to the rank we want, and some to the unused ranks, even though - * they are disabled. Since VR3 is the last virtual rank to be used, we - * eliminate any ambiguities that the MCU may face. */ - vx900_pr_map_all_vr3(); - for (i = 0; i < VX900_MAX_MEM_RANKS; i++) { - u32 rank_size_mb = ranks->phys_rank_size_mb[i]; - if (!rank_size_mb) - continue; - - /* vvvvvvvvvv FIXME: Fix odd rank init vvvvvvvvvv */ - if ((i & 1)) { - printk(BIOS_EMERG, "I cannot initialize rank %zu\n", i); - printk(BIOS_EMERG, "I have to disable it\n"); - continue; - } - /* ^^^^^^^^^^ FIXME: Fix odd rank init ^^^^^^^^^^ */ - - ranks->virt[vrank].start_addr = ramsize_mb; - ramsize_mb += rank_size_mb; - ranks->virt[vrank].end_addr = ramsize_mb; - - /* Rank memory range */ - reg8 = (ranks->virt[vrank].start_addr >> 6); - pci_write_config8(MCU, 0x48 + vrank, reg8); - reg8 = (ranks->virt[vrank].end_addr >> 6); - pci_write_config8(MCU, 0x40 + vrank, reg8); - - vx900_map_pr_vr(i, vrank); - - printram("Mapped Physical rank %u, to virtual rank %u\n" - " Start address: 0x%.10llx\n" - " End address: 0x%.10llx\n", - (int)i, (int)vrank, - (u64) ranks->virt[vrank].start_addr << 20, - (u64) ranks->virt[vrank].end_addr << 20); - /* Move on to next virtual rank */ - vrank++; - } - - /* Limit the Top of Low memory at 3.5G - * Not to worry, we'll set tolm in ramstage, once we have initialized - * all devices and know pci_tolm. */ - tolm_mb = MIN(ramsize_mb, TOLM_3_5G >> 20); - u16 reg_tolm = (tolm_mb << 4) & 0xfff0; - pci_update_config16(MCU, 0x84, (u16)~0xfff0, reg_tolm); - - printram("Initialized %u virtual ranks, with a total size of %u MB\n", - (int)vrank, ramsize_mb); -} - -/* - * Here, we tell the memory controller how to treat a DIMM. This is an extremely - * important step. It tells the MCU how many address bits we have in each DIMM, - * and how to use them. This information is essential for the controller to - * understand the DIMM addressing, and write and read data in the correct place. - */ -static void vx900_dram_map_row_col_bank(dimm_info * dimms) -{ - u8 reg8, rcb_val, col_bits, max_row_bits; - size_t i; - /* Do we have 4Gbit chips? */ - /* FIXME: Implement this */ - - /* Do we have 8Gbit chips? */ - /* FIXME: Implement this */ - - max_row_bits = rcb_val = reg8 = 0; - for (i = 0; i < VX900_MAX_DIMM_SLOTS; i++) { - if (dimms->dimm[i].dram_type == SPD_MEMORY_TYPE_UNDEFINED) - continue; - - col_bits = dimms->dimm[i].col_bits; - - /* - * DDR3 always uses 3 bank address bits, and MA type 111b cannot - * be used due to chipset limitation. We are left with only two - * options, which we can choose based solely on the number of - * column address bits. - */ - if ((col_bits < 10) || (col_bits > 11)) { - printram("DIMM %zd has %d column address bits.\n", - i, col_bits); - die("Unsupported DIMM. Try booting without this DIMM"); - } - - rcb_val = col_bits - 5; - reg8 |= (rcb_val << ((i * 3) + 2)); - - /* */ - max_row_bits = MAX(max_row_bits, dimms->dimm[i].row_bits); - } - - printram("RCBA map (rx50) <- %.2x\n", reg8); - pci_write_config8(MCU, 0x50, reg8); - - printram("Houston, we have %d row address bits\n", max_row_bits); - /* FIXME: Do this properly */ - vx900_dram_map_pins(13, 14, 15, 17, 16); - -} - -/* - * Here, we set some final configuration bits, which should improve the - * performance of the memory slightly (arbitration, expiration counters, etc.) - * - * FIXME: We don't really do much else than the minimum to get the MCU properly - * configured. We don't yet do set the "performance-enhancing" bits referenced - * in the comment above. - */ -static void vx900_dram_write_final_config(ramctr_timing * ctrl) -{ - /* FIXME: These are quick cheats */ - - /* FIXME: Why are we doing this? */ - /* Tri-state MCSi# when rank is in self-refresh */ - pci_or_config8(MCU, 0x99, 0x0f); - - /* Enable paging mode and 8 page registers */ - pci_or_config8(MCU, 0x69, 0xe5); - - /* Enable automatic triggering of short ZQ calibration */ - pci_write_config8(MCU, 0xc8, 0x80); - - /* And last but not least, Enable A20 line */ - outb(inb(0x92) | (1 << 1), 0x92); -} - -void vx900_init_dram_ddr3(const dimm_layout * dimm_addr) -{ - dimm_info dimm_prop; - ramctr_timing ctrl_prop; - rank_layout ranks; - pci_devfn_t mcu; - - if (!ram_check_noprint_nodie(1 << 20, 1 << 20)) { - printram("RAM is already initialized. Skipping init\n"); - return; - } - /* Locate the Memory controller */ - mcu = pci_locate_device(PCI_ID(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_VX900_MEMCTRL), 0); - - if (mcu == PCI_DEV_INVALID) { - die("Memory Controller not found\n"); - } - memset(&dimm_prop, 0, sizeof(dimm_prop)); - memset(&ctrl_prop, 0, sizeof(ctrl_prop)); - memset(&ranks, 0, sizeof(ranks)); - /* 1) Write some initial "safe" parameters */ - vx900_dram_write_init_config(); - /* 2) Get timing information from SPDs */ - dram_find_spds_ddr3(dimm_addr, &dimm_prop); - /* 3) Find lowest common denominator for all modules */ - dram_find_common_params(&dimm_prop, &ctrl_prop); - /* 4) Find the size of each memory rank */ - vx900_dram_phys_bank_range(&dimm_prop, &ranks); - /* 5) Set DRAM driving strength */ - vx900_dram_driving_ctrl(&dimm_prop); - /* 6) Set DRAM frequency and latencies */ - vx900_dram_timing(&ctrl_prop); - vx900_dram_freq(&ctrl_prop); - /* 7) Initialize the modules themselves */ - vx900_dram_ddr3_dimm_init(&ctrl_prop, &ranks); - /* 8) Set refresh counter based on DRAM frequency */ - vx900_dram_set_refresh_counter(&ctrl_prop); - /* 9) Calibrate receive and transmit delays */ - vx900_dram_calibrate_delays(&ctrl_prop, &ranks); - /* 10) Enable Physical to Virtual Rank mapping */ - vx900_dram_range(&ctrl_prop, &ranks); - /* 11) Map address bits to DRAM pins */ - vx900_dram_map_row_col_bank(&dimm_prop); - /* 99) Some final adjustments */ - vx900_dram_write_final_config(&ctrl_prop); - /* Take a dump */ - dump_pci_device(mcu); -} diff --git a/src/northbridge/via/vx900/romstrap.S b/src/northbridge/via/vx900/romstrap.S deleted file mode 100644 index 26c1ee694a..0000000000 --- a/src/northbridge/via/vx900/romstrap.S +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2004 Tyan Computer - * (Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer) - * Copyright (C) 2007 Rudolf Marek <r.marek@assembler.cz> - * Copyright (C) 2009 One Laptop per Child, Association, Inc. - * Copyright (C) 2011-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; 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. - */ - -/* As extracted from the manufacturer's ROM, the romstrap table looks like: - * .long 0x77886047 .long 0x00777777 - * .long 0x00000000 .long 0x00000000 - * .long 0x00888888 .long 0x00AA1111 - * .long 0x00000000 .long 0x00000000 - * - * The vendor BIOS then adjusts some of these settings very early on. Instead of - * adjusting those settings in code, we work them in the romstrap table. - * - */ -/* This file constructs the ROM strap table for VX900 */ - - .section ".romstrap", "a", @progbits - - .globl __romstrap_start -__romstrap_start: -tblpointer: - .long 0x77886047 - .long 0x00777777 - .long 0x00000000 - .long 0x00000000 - .long 0x00888888 - .long 0x00AA1111 - .long 0x00000000 - .long 0x00000000 - -/* - * The pointer to above table should be at 0xffffffd0, - * the table itself MUST be aligned to 128B it seems! - */ -rspointers: - .long tblpointer // It will be 0xffffffd0 - - .globl __romstrap_end - -__romstrap_end: -.previous diff --git a/src/northbridge/via/vx900/romstrap.ld b/src/northbridge/via/vx900/romstrap.ld deleted file mode 100644 index 0217f41b87..0000000000 --- a/src/northbridge/via/vx900/romstrap.ld +++ /dev/null @@ -1,24 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2007 AMD - * (Written by Yinghai Lu <yinghai.lu@amd.com> for AMD) - * Copyright (C) 2011 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. - */ - -SECTIONS { - . = (0x100000000 - 0x2c) - (__romstrap_end - __romstrap_start); - .romstrap (.): { - KEEP(*(.romstrap)) - } -} diff --git a/src/northbridge/via/vx900/sata.c b/src/northbridge/via/vx900/sata.c deleted file mode 100644 index 791133142f..0000000000 --- a/src/northbridge/via/vx900/sata.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * 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. - */ - -#include <console/console.h> -#include <device/pci.h> -#include <device/pci_ops.h> -#include <device/pci_ids.h> - -#include "vx900.h" - -/** - * @file vx900/sata.c - * - * STATUS: Pretty good - * The only issue is the SATA EPHY configuration. We do not know if it is board - * specific or not. Otherwise, the SATA controller works without issues. - */ - -static void vx900_print_sata_errors(u32 flags) -{ - /* Status flags */ - printk(BIOS_DEBUG, "\tPhyRdy %s\n", - (flags & (1 << 16)) ? "changed" : "not changed"); - printk(BIOS_DEBUG, "\tCOMWAKE %s\n", - (flags & (1 << 16)) ? "detected" : "not detected"); - printk(BIOS_DEBUG, "\tExchange as determined by COMINIT %s\n", - (flags & (1 << 26)) ? "occurred" : "not occurred"); - printk(BIOS_DEBUG, "\tPort selector presence %s\n", - (flags & (1 << 27)) ? "detected" : "not detected"); - /* Errors */ - if (flags & (1 << 0)) - printk(BIOS_DEBUG, "\tRecovered data integrity ERROR\n"); - if (flags & (1 << 1)) - printk(BIOS_DEBUG, "\tRecovered data communication ERROR\n"); - if (flags & (1 << 8)) - printk(BIOS_DEBUG, "\tNon-recovered Transient Data Integrity ERROR\n"); - if (flags & (1 << 9)) - printk(BIOS_DEBUG, "\tNon-recovered Persistent Communication or" - "\tData Integrity ERROR\n"); - if (flags & (1 << 10)) - printk(BIOS_DEBUG, "\tProtocol ERROR\n"); - if (flags & (1 << 11)) - printk(BIOS_DEBUG, "\tInternal ERROR\n"); - if (flags & (1 << 17)) - printk(BIOS_DEBUG, "\tPHY Internal ERROR\n"); - if (flags & (1 << 19)) - printk(BIOS_DEBUG, "\t10B to 8B Decode ERROR\n"); - if (flags & (1 << 20)) - printk(BIOS_DEBUG, "\tDisparity ERROR\n"); - if (flags & (1 << 21)) - printk(BIOS_DEBUG, "\tCRC ERROR\n"); - if (flags & (1 << 22)) - printk(BIOS_DEBUG, "\tHandshake ERROR\n"); - if (flags & (1 << 23)) - printk(BIOS_DEBUG, "\tLink Sequence ERROR\n"); - if (flags & (1 << 24)) - printk(BIOS_DEBUG, "\tTransport State Transition ERROR\n"); - if (flags & (1 << 25)) - printk(BIOS_DEBUG, "\tUNRECOGNIZED FIS type\n"); -} - -static void vx900_dbg_sata_errors(struct device *dev) -{ - /* Port 0 */ - if (pci_read_config8(dev, 0xa0) & (1 << 0)) { - printk(BIOS_DEBUG, "Device detected in SATA port 0.\n"); - u32 flags = pci_read_config32(dev, 0xa8); - vx900_print_sata_errors(flags); - }; - /* Port 1 */ - if (pci_read_config8(dev, 0xa1) & (1 << 0)) { - printk(BIOS_DEBUG, "Device detected in SATA port 1.\n"); - u32 flags = pci_read_config32(dev, 0xac); - vx900_print_sata_errors(flags); - }; -} - -typedef u8 sata_phy_config[64]; - -static sata_phy_config reference_ephy = { - 0x80, 0xb8, 0xf0, 0xfe, 0x40, 0x7e, 0xf6, 0xdd, - 0x1a, 0x22, 0xa0, 0x10, 0x02, 0xa9, 0x7c, 0x7e, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x30, 0x84, 0x8c, - 0x75, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x40, 0xd0, 0x41, 0x40, 0x00, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x40, 0x50, 0x41, 0x40, 0x00, 0x00, 0x00, - 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -static u32 sata_phy_read32(struct device *dev, u8 index) -{ - /* The SATA PHY control registers are accessed by a funny index/value - * scheme. Each byte (0,1,2,3) has its own 4-bit index */ - index = (index >> 2) & 0xf; - u16 i16 = index | (index << 4) | (index << 8) | (index << 12); - /* The index */ - pci_write_config16(dev, 0x68, i16); - /* The value */ - return pci_read_config32(dev, 0x64); -} - -static void sata_phy_write32(struct device *dev, u8 index, u32 val) -{ - /* The SATA PHY control registers are accessed by a funny index/value - * scheme. Each byte (0,1,2,3) has its own 4-bit index */ - index = (index >> 2) & 0xf; - u16 i16 = index | (index << 4) | (index << 8) | (index << 12); - /* The index */ - pci_write_config16(dev, 0x68, i16); - /* The value */ - pci_write_config32(dev, 0x64, val); -} - -static void vx900_sata_read_phy_config(struct device *dev, sata_phy_config cfg) -{ - size_t i; - u32 *data = (u32 *) cfg; - for (i = 0; i < (sizeof(sata_phy_config)) >> 2; i++) { - data[i] = sata_phy_read32(dev, i << 2); - } -} - -static void vx900_sata_write_phy_config(struct device *dev, sata_phy_config cfg) -{ - size_t i; - u32 *data = (u32 *) cfg; - for (i = 0; i < (sizeof(sata_phy_config)) >> 2; i++) { - sata_phy_write32(dev, i << 2, data[i]); - } -} - -static void vx900_sata_dump_phy_config(sata_phy_config cfg) -{ - printk(BIOS_DEBUG, "SATA PHY config:\n"); - int i; - for (i = 0; i < sizeof(sata_phy_config); i++) { - unsigned char val; - if ((i & 0x0f) == 0) - printk(BIOS_DEBUG, "%02x:", i); - val = cfg[i]; - if ((i & 7) == 0) - printk(BIOS_DEBUG, " |"); - printk(BIOS_DEBUG, " %02x", val); - if ((i & 0x0f) == 0x0f) { - printk(BIOS_DEBUG, "\n"); - } - } -} - -/** - * \brief VX900: Place the onboard SATA controller in Native IDE mode - * - * AHCI mode requires a sub-class of 0x06, and Interface of 0x0 - * SATA mode requires a sub-class of 0x06, and Interface of 0x00 - * Unfortunately, setting the class to SATA, will prevent us from modyfing the - * interface register to an AHCI/SATA compliant value. Thus, payloads or OS may - * not properly identify this as a SATA controller. - * We could set the class code to 0x04, which would cause the interface register - * to become 0x00, which represents a RAID controller. Unfortunately, when we do - * this, SeaBIOS will skip this as a storage device, and we will not be able to - * boot. - * Our only option is to operate in IDE mode. We choose native IDE so that we - * can freely assign an IRQ, and are not forced to use IRQ14 - */ -static void vx900_native_ide_mode(struct device *dev) -{ - /* Disable subclass write protect */ - pci_update_config8(dev, 0x45, (u8)~(1 << 7), 0); - /* Change the device class to IDE */ - pci_write_config16(dev, PCI_CLASS_DEVICE, PCI_CLASS_STORAGE_IDE); - /* Re-enable subclass write protect */ - pci_or_config8(dev, 0x45, 1 << 7); - /* Put it in native IDE mode */ - pci_write_config8(dev, PCI_CLASS_PROG, 0x8f); -} - -static void vx900_sata_init(struct device *dev) -{ - /* Enable SATA primary channel IO access */ - pci_or_config8(dev, 0x40, 1 << 1); - /* Just SATA, so it makes sense to be in native SATA mode */ - vx900_native_ide_mode(dev); - - /* TP Layer Idle at least 20us before the Following Command */ - pci_or_config8(dev, 0x53, 1 << 7); - /* Resend COMRESET When Recovering SATA Gen2 Device Error */ - pci_update_config8(dev, 0x62, ~(1 << 1), 1 << 7); - - /* Fix "PMP Device Can't Detect HDD Normally" (VIA Porting Guide) - * SATA device detection will not work unless we clear these bits. - * Without doing this, SeaBIOS (and potentially other payloads) will - * timeout when detecting SATA devices */ - pci_update_config8(dev, 0x89, ~(1 << 3) | (1 << 6), 0); - - /* 12.7 Two Software Resets May Affect the System - * When the software does the second reset before the first reset - * finishes, it may cause the system hang. It would do one software - * reset and check the BSY bit of one port only, and the BSY bit of - * other port would be 1, then it does another software reset - * immediately and causes the system hang. - * This is because the first software reset doesn't finish, and the - * state machine of the host controller conflicts, it can't finish the - * second one anymore. The BSY bit of slave port would be always 1 after - * the second software reset issues. BIOS should set the following - * bit to avoid this issue. */ - pci_or_config8(dev, 0x80, 1 << 6); - - /* We need to set the EPHY values before doing anything with the link */ - sata_phy_config ephy; - vx900_sata_read_phy_config(dev, ephy); - if (1) { - vx900_sata_dump_phy_config(ephy); - vx900_sata_write_phy_config(dev, reference_ephy); - } else { - /* Enable TX and RX driving resistance */ - /* TX - 50 Ohm */ - ephy[1] &= ~(0x1f << 3); - ephy[1] |= (1 << 7) | (8 << 3); - /* RX - 50 Ohm */ - ephy[2] &= ~(0x1f << 3); - ephy[2] |= (1 << 7) | (8 << 3); - vx900_sata_write_phy_config(dev, ephy); - } - - vx900_sata_read_phy_config(dev, ephy); - vx900_sata_dump_phy_config(ephy); - - /* Clear error flags */ - pci_write_config32(dev, 0xa8, 0xffffffff); - pci_write_config32(dev, 0xac, 0xffffffff); - - /* Start OOB link negotiation sequence */ - pci_or_config8(dev, 0xb9, 3 << 4); - - /* FIXME: From now on, we are just doing DEBUG stuff - * Wait until PHY communication is enabled */ - u32 wloops = 0; - while (!(pci_read_config8(dev, 0xa0) & (1 << 1))) - wloops++; - printk(BIOS_SPEW, "SATA wait loops: %u\n", wloops); - - vx900_dbg_sata_errors(dev); -} - -static void vx900_sata_read_resources(struct device *dev) -{ - pci_dev_read_resources(dev); -} - -static struct device_operations vga_operations = { - .read_resources = vx900_sata_read_resources, - .set_resources = pci_dev_set_resources, - .enable_resources = pci_dev_enable_resources, - .init = vx900_sata_init, -}; - -static const struct pci_driver chrome9hd_driver __pci_driver = { - .ops = &vga_operations, - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_VX900_SATA, -}; diff --git a/src/northbridge/via/vx900/traf_ctrl.c b/src/northbridge/via/vx900/traf_ctrl.c deleted file mode 100644 index 2ef542afb8..0000000000 --- a/src/northbridge/via/vx900/traf_ctrl.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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. - */ - -#include <device/pci.h> -#include <device/pci_ops.h> -#include <device/pci_ids.h> -#include <console/console.h> -#include <drivers/generic/ioapic/chip.h> - -#include "vx900.h" -#include "chip.h" - -/** - * @file vx900/traf_ctrl.c - * - * STATUS: - * The same issues with the IOAPIC pointe in lpc.c also apply here. - * - * We need to check if the current PCIE lane configuration mechanism is sane. - */ - -/** - * \brief VX900: Set up the north module IOAPIC (for PCIE and VGA) - * - * Enable the IOAPIC in the south module, and properly set it up. - * \n - * This is the hardware specific initialization for the IOAPIC, and complements - * the setup done by the generic IOAPIC driver. In order for the IOAPIC to work - * properly, it _must_ be declared in devicetree.cb . - * \n - * We are assuming this is called before the drivers/generic/ioapic code, - * which should be the case if devicetree.cb is set up properly. - */ -static void vx900_north_ioapic_setup(struct device *dev) -{ - u8 base_val; - struct device *ioapic; - ioapic_config_t *config; - /* Find the IOAPIC, and make sure it's set up correctly in devicetree.cb - * If it's not, then the generic ioapic driver will not set it up - * correctly, and the MP table will not be correctly generated */ - for (ioapic = dev->next; ioapic; ioapic = ioapic->next) { - if (ioapic->path.type == DEVICE_PATH_IOAPIC) - break; - } - /* You did put an IOAPIC in devicetree.cb, didn't you? */ - if (ioapic == 0) { - /* We don't have enough info to set up the IOAPIC */ - printk(BIOS_ERR, "ERROR: North module IOAPIC not found. " - "Check your devicetree.cb\n"); - return; - } - /* Found our IOAPIC, and it should not carry ISA interrupts */ - config = (ioapic_config_t *) ioapic->chip_info; - if (config->have_isa_interrupts) { - /* Umh, is this the right IOAPIC ? */ - printk(BIOS_ERR, "ERROR: North module IOAPIC should not carry " - "ISA interrupts.\n" "Check your devicetree.cb\n"); - printk(BIOS_ERR, "Will not initialize this IOAPIC.\n"); - return; - } - /* The base address of this IOAPIC _must_ - * be between 0xfec00000 and 0xfecfff00 - * be 256-byte aligned - */ - if ((config->base < (void *)0xfec0000 || config->base > (void *)0xfecfff00) - || (((uintptr_t)config->base & 0xff) != 0)) { - printk(BIOS_ERR, "ERROR: North module IOAPIC base should be " - "between 0xfec00000 and 0xfecfff00\n" - "and must be aligned to a 256-byte boundary, " - "but we found it at 0x%p\n", config->base); - return; - } - - printk(BIOS_DEBUG, "VX900 TRAF_CTR: Setting up the north module IOAPIC " - "at %p\n", config->base); - - /* First register of the IOAPIC base */ - base_val = (((uintptr_t)config->base) >> 8) & 0xff; - pci_write_config8(dev, 0x41, base_val); - /* Second register of the base. - * Bit[7] also enables the IOAPIC and bit[5] enables MSI cycles */ - base_val = (((uintptr_t)config->base) >> 16) & 0xf; - pci_or_config8(dev, 0x40, base_val | (1 << 7) | (1 << 5)); -} - -/* - * Configures the PCI-express ports - * - * FIXME: triple-quadruple-check this - */ -static void vx900_pex_link_setup(struct device *dev) -{ - u8 reg8; - struct northbridge_via_vx900_config *nb = (void *)dev->chip_info; - - reg8 = pci_read_config8(dev, 0xb0); - reg8 &= ~((1 << 7) | (1 << 3)); - - if (nb->assign_pex_to_dp) - reg8 |= (1 << 7); - - if (!nb->pcie_port1_2_lane_wide) - reg8 |= (1 << 3); - - pci_write_config8(dev, 0xb0, reg8); -} - -static void vx900_traf_ctr_init(struct device *dev) -{ - vx900_north_ioapic_setup(dev); - vx900_pex_link_setup(dev); -} - -static struct device_operations traf_ctrl_ops = { - .read_resources = pci_dev_read_resources, - .set_resources = pci_dev_set_resources, - .enable_resources = pci_dev_enable_resources, - .init = vx900_traf_ctr_init, - /* Need this here, or the IOAPIC driver won't be called. - * FIXME: Technically not a LPC bus. */ - .scan_bus = scan_static_bus, -}; - -static const struct pci_driver traf_ctrl_driver __pci_driver = { - .ops = &traf_ctrl_ops, - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_VX900_TRAF, -}; diff --git a/src/northbridge/via/vx900/vx900.h b/src/northbridge/via/vx900/vx900.h deleted file mode 100644 index 1f611535aa..0000000000 --- a/src/northbridge/via/vx900/vx900.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2011 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. - */ -#ifndef __VX900_H -#define __VX900_H - -#define VX900_ACPI_IO_BASE 0x0400 - -#define SMBUS_IO_BASE 0x500 - -#define VX900_MMCONFIG_MBAR 0xbc - -/* The maximum number of DIMM slots that the VX900 supports */ -#define VX900_MAX_DIMM_SLOTS 2 -#define VX900_MAX_MEM_RANKS 4 - -#include <device/pci_ops.h> -#include <device/pci.h> - -u32 vx900_get_tolm(void); -void vx900_set_chrome9hd_fb_size(u32 size_mb); -u8 vx900_get_chrome9hd_fb_pow(void); -u32 vx900_get_chrome9hd_fb_size(void); -u8 vx900_int15_get_5f18_bl(void); -uint64_t get_uma_memory_base(void); - -/* We use these throughout the code. They really belong in a generic part of - * coreboot, but until bureaucracy gets them there, we still need them */ - -void dump_pci_device(pci_devfn_t dev); - -#endif /* __VX900_H */ |