diff options
author | Andrew Wu <arw@dmp.com.tw> | 2013-06-26 21:24:59 +0800 |
---|---|---|
committer | Ronald G. Minnich <rminnich@gmail.com> | 2013-07-03 18:31:22 +0200 |
commit | 00bf647bf6a980e8b9c3d8d91d79859c9b3de0a1 (patch) | |
tree | 65109dd32c0d3d8dd0e8e7734cbdea7e93d12118 /src/southbridge/dmp/vortex86ex | |
parent | dd94fa93b403a73cc7d7b282eb6cefeb27512d13 (diff) | |
download | coreboot-00bf647bf6a980e8b9c3d8d91d79859c9b3de0a1.tar.xz |
Add support for DMP Vortex86EX PCI southbridge.
Change-Id: Iad11cb1b22e9d1e2953b12221541b1478cad9665
Signed-off-by: Andrew Wu <arw@dmp.com.tw>
Reviewed-on: http://review.coreboot.org/3547
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Diffstat (limited to 'src/southbridge/dmp/vortex86ex')
-rw-r--r-- | src/southbridge/dmp/vortex86ex/Kconfig | 22 | ||||
-rw-r--r-- | src/southbridge/dmp/vortex86ex/Makefile.inc | 22 | ||||
-rw-r--r-- | src/southbridge/dmp/vortex86ex/chip.h | 38 | ||||
-rw-r--r-- | src/southbridge/dmp/vortex86ex/hard_reset.c | 25 | ||||
-rw-r--r-- | src/southbridge/dmp/vortex86ex/ide_sd_sata.c | 171 | ||||
-rw-r--r-- | src/southbridge/dmp/vortex86ex/southbridge.c | 557 | ||||
-rw-r--r-- | src/southbridge/dmp/vortex86ex/southbridge.h | 42 |
7 files changed, 877 insertions, 0 deletions
diff --git a/src/southbridge/dmp/vortex86ex/Kconfig b/src/southbridge/dmp/vortex86ex/Kconfig new file mode 100644 index 0000000000..e12477cbe8 --- /dev/null +++ b/src/southbridge/dmp/vortex86ex/Kconfig @@ -0,0 +1,22 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2013 DMP Electronics Inc. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; version 2 of the License. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +config SOUTHBRIDGE_DMP_VORTEX86EX + bool + select HAVE_HARD_RESET diff --git a/src/southbridge/dmp/vortex86ex/Makefile.inc b/src/southbridge/dmp/vortex86ex/Makefile.inc new file mode 100644 index 0000000000..6d2a921e93 --- /dev/null +++ b/src/southbridge/dmp/vortex86ex/Makefile.inc @@ -0,0 +1,22 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2013 DMP Electronics Inc. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; version 2 of the License. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +ramstage-y += southbridge.c +ramstage-y += hard_reset.c +ramstage-y += ide_sd_sata.c diff --git a/src/southbridge/dmp/vortex86ex/chip.h b/src/southbridge/dmp/vortex86ex/chip.h new file mode 100644 index 0000000000..09312f92c8 --- /dev/null +++ b/src/southbridge/dmp/vortex86ex/chip.h @@ -0,0 +1,38 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 DMP Electronics Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SOUTHBRIDGE_DMP_VORTEX86EX +#define _SOUTHBRIDGE_DMP_VORTEX86EX + +struct southbridge_dmp_vortex86ex_config { + /* PCI function enables */ + /* i.e. so that pci scan bus will find them. */ + /* I am putting in IDE as an example but obviously this needs + * to be more complete! + */ + int enable_ide; + /* enables of functions of devices */ + int enable_usb; + int enable_native_ide; + int enable_com_ports; + int enable_keyboard; + int enable_nvram; +}; + +#endif /* _SOUTHBRIDGE_DMP_VORTEX86EX */ diff --git a/src/southbridge/dmp/vortex86ex/hard_reset.c b/src/southbridge/dmp/vortex86ex/hard_reset.c new file mode 100644 index 0000000000..5d216ab141 --- /dev/null +++ b/src/southbridge/dmp/vortex86ex/hard_reset.c @@ -0,0 +1,25 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 DMP Electronics Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <arch/io.h> +#include <reset.h> + +void hard_reset(void) +{ +} diff --git a/src/southbridge/dmp/vortex86ex/ide_sd_sata.c b/src/southbridge/dmp/vortex86ex/ide_sd_sata.c new file mode 100644 index 0000000000..8214549bc5 --- /dev/null +++ b/src/southbridge/dmp/vortex86ex/ide_sd_sata.c @@ -0,0 +1,171 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 DMP Electronics Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <delay.h> +#include <stdlib.h> +#include <string.h> +#include <arch/io.h> + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> + +/* Vortex86EX IDE to SD/STAT controller need to enable ATA decoder and + * setup timing. */ + +/* + * Primary ATA Timing Register (PATR) - Offset 40-41h + * Secondary ATA Timing Register (PATR) - Offset 42-43h + * + * Bit R/W Default Description + * 15 R/W 0h ATA Decode Enable. Decode the I/O addressing ranges assigned to this controller. + * 1: Enabled. + * 0: Disabled. + * 14 R/W 0b Device 1 ATA Timing Register Enable + * 1: Enable the device 1 ATA timing. + * 0: Disable the device 1 ATA timing + * 13-12 R/W 0h IORDY Sample Mode. Sets the setup time before IORDY are sampled. + * 00: PIO-0 + * 10: PIO-2, SW-2 + * 10: PIO-3, PIO-4, MW-1, MW-2 + * 11: Reserved + * 11-10 RO 0h Reserved + * 9-8 R/W 0h Recovery Mode. Sets the hold time after IORDY are sampled. + * 00: PIO-0, PIO-2, SW-2 + * 10: PIO-3, MW-1 + * 10: Reserved + * 11: PIO-4, MW-2 + * 7 R/W 0b DMA Timing Enable Only Select 1 + * 1: Enable the device timings for DMA operation for device 1 + * 0: Disable the device timings for DMA operation for device 1 + * 6 R/W 0b ATA/ATAPI Device Indicator 1 + * 1: Indicate presence od an ATA device + * 0: Indicate presence od an ATAPI device + * 5 R/W 0b IORDY Sample Point Enabled Select 1 + * 1: Enable IORDY sample for PIO transfers for device 1 + * 0: Disable IORDY sample for PIO transfers for device 1 + * 4 R/W 0b Fast Drive Timing Select 1 + * 1: Enable faster than PIO-0 timing modes for device 1 + * 0: Disable faster than PIO-0 timing modes for device 1 + * 3 R/W 0b DMA Timing Enable Only Select 0 + * 1: Enable the device timings for DMA operation for device 0 + * 0: Disable the device timings for DMA operation for device 0 + * 2 R/W 0b ATA/ATAPI Device Indicator 0 + * 1: Indicate presence od an ATA device + * 0: Indicate presence od an ATAPI device + * 1 R/W 0b IORDY Sample Point Enabled Select 0 + * 1: Enable IORDY sample for PIO transfers for device 0 + * 0: Disable IORDY sample for PIO transfers for device 0 + * 0 R/W 0b Fast Drive Timing Select 0 + * 1: Enable faster than PIO-0 timing modes for device 0 + * 0: Disable faster than PIO-0 timing modes for device 0 + * */ + +static void init_ide_ata_timing(struct device *dev) +{ + u16 ata_timing_pri, ata_timing_sec; + u32 ata_timing_reg32; + /* Primary channel is SD. */ +#if CONFIG_IDE1_ENABLE + ata_timing_pri = 0x8000; +#else + ata_timing_pri = 0x0000; // Disable this channel. +#endif + /* Secondary channel is SATA. */ +#if CONFIG_IDE2_ENABLE + ata_timing_sec = 0xa30f; // This setting value works well. +#else + ata_timing_sec = 0x0000; // Disable this channel. +#endif + ata_timing_reg32 = (ata_timing_sec << 16) | ata_timing_pri; + pci_write_config32(dev, 0x40, ata_timing_reg32); +#if CONFIG_IDE_NATIVE_MODE + /* Set both IDE channels to native mode. */ + u8 prog_if; + prog_if = pci_read_config8(dev, 0x09); + prog_if |= 5; + pci_write_config8(dev, 0x09, prog_if); +#endif + /* MMC function enable. */ + u32 sd_ctrl_reg; + sd_ctrl_reg = pci_read_config32(dev, 0x94); + sd_ctrl_reg |= 0x0200; + pci_write_config32(dev, 0x94, sd_ctrl_reg); + printk(BIOS_INFO, "Vortex86EX IDE controller ATA TIMING reg = %08x\n", ata_timing_reg32); +} + +static void setup_std_ide_compatible(struct device *dev) +{ +#if CONFIG_IDE_STANDARD_COMPATIBLE + // Misc Control Register (MCR) Offset 90h + // bit 0 = Vendor ID Access, bit 1 = Device ID Access. + u8 mcr; + u16 vendor = (u16) (CONFIG_IDE_COMPATIBLE_SELECTION >> 16); + u16 device = (u16) (CONFIG_IDE_COMPATIBLE_SELECTION & 0xffff); + // unlock vendor/device ID access bits. + mcr = pci_read_config8(dev, 0x90); + pci_write_config8(dev, 0x90, mcr | 3); + pci_write_config16(dev, 0x00, vendor); + pci_write_config16(dev, 0x02, device); + // restore lock bits. + pci_write_config8(dev, 0x90, mcr); +#endif +} + +static void vortex_ide_init(struct device *dev) +{ + if (dev->device == 0x1010) { + // This is SX/old DX IDE controller. + // Set IOCFG bit 15/13 : IDE Decoder Enable for Primary/Secondary channel. + u16 iocfg = 0xa000; + pci_write_config16(dev, 0x40, iocfg); + } else if (dev->device == 0x1011 || dev->device == 0x1012) { + // This is new DX/MX/MX+/DX2 IDE controller. + init_ide_ata_timing(dev); + setup_std_ide_compatible(dev); + } +} + +static struct device_operations vortex_ide_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = vortex_ide_init, + .scan_bus = 0, +}; + +static const struct pci_driver vortex_ide_driver_1010 __pci_driver = { + .ops = &vortex_ide_ops, + .vendor = PCI_VENDOR_ID_RDC, + .device = 0x1010, +}; + +static const struct pci_driver vortex_ide_driver_1011 __pci_driver = { + .ops = &vortex_ide_ops, + .vendor = PCI_VENDOR_ID_RDC, + .device = 0x1011, +}; + +static const struct pci_driver vortex_ide_driver_1012 __pci_driver = { + .ops = &vortex_ide_ops, + .vendor = PCI_VENDOR_ID_RDC, + .device = 0x1012, +}; diff --git a/src/southbridge/dmp/vortex86ex/southbridge.c b/src/southbridge/dmp/vortex86ex/southbridge.c new file mode 100644 index 0000000000..28fe3c933e --- /dev/null +++ b/src/southbridge/dmp/vortex86ex/southbridge.c @@ -0,0 +1,557 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 DMP Electronics Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ops.h> +#include <device/pci_ids.h> +#include <pc80/mc146818rtc.h> +#include <string.h> +#include "arch/io.h" +#include "chip.h" +#include "southbridge.h" + +/* IRQ number to S/B PCI Interrupt routing table reg(0x58/0xb4) mapping table. */ +static const unsigned char irq_to_int_routing[16] = { + 0x0, 0x0, 0x0, 0x2, // IRQ0-2 is unmappable, IRQ3 = 2. + 0x4, 0x5, 0x7, 0x6, // IRQ4-7 = 4, 5, 7, 6. + 0x0, 0x1, 0x3, 0x9, // IRQ8 is unmappable, IRQ9-11 = 1, 3, 9. + 0xb, 0x0, 0xd, 0xf // IRQ12 = b, IRQ13 is unmappable, IRQ14-15 = d, f. +}; + +/* S/B PCI Interrupt routing table reg(0x58) field bit shift. */ +#define EHCIH_IRQ_SHIFT 28 +#define OHCII_IRQ_SHIFT 24 +#define MAC_IRQ_SHIFT 16 +#define RT3_IRQ_SHIFT 12 +#define RT2_IRQ_SHIFT 8 +#define RT1_IRQ_SHIFT 4 +#define RT0_IRQ_SHIFT 0 + +/* S/B Extend PCI Interrupt routing table reg(0xb4) field bit shift. */ +#define USBD_IRQ_SHIFT 16 +#define SIDE_IRQ_SHIFT 12 +#define PIDE_IRQ_SHIFT 8 + +/* in-chip PCI device IRQs(0 for disabled). */ +#define EHCII_IRQ 5 +#define OHCII_IRQ 5 +#define MAC_IRQ 6 + +#define USBD_IRQ 0 +#define PIDE_IRQ 5 + +/* RT0-3 IRQs. */ +#define RT3_IRQ 3 +#define RT2_IRQ 4 +#define RT1_IRQ 5 +#define RT0_IRQ 6 + +/* IDE legacy mode IRQs. */ +#define IDE1_LEGACY_IRQ 14 +#define IDE2_LEGACY_IRQ 15 + +/* Internal parallel port */ +#define LPT_INT_C 0 +#define LPT_INT_ACK_SET 0 +#define LPT_UE 1 +#define LPT_PDMAS 0 +#define LPT_DREQS 0 + +/* Post codes */ +#define POST_KBD_FW_UPLOAD 0x06 +#define POST_KBD_CHK_READY 0x07 +#define POST_KBD_IS_READY 0x08 +#define POST_KBD_FW_VERIFY_FAILURE 0x82 + +static u8 get_pci_dev_func(device_t dev) +{ + return PCI_FUNC(dev->path.pci.devfn); +} + +static void verify_dmp_keyboard_error(void) +{ + post_code(POST_KBD_FW_VERIFY_FAILURE); + die("Internal keyboard firmware verify error!\n"); +} + +static void upload_dmp_keyboard_firmware(struct device *dev) +{ + u32 reg_sb_c0; + u32 fwptr; + + // enable firmware uploading function by set bit 10. + post_code(POST_KBD_FW_UPLOAD); + reg_sb_c0 = pci_read_config32(dev, SB_REG_IPFCR); + pci_write_config32(dev, SB_REG_IPFCR, reg_sb_c0 | 0x400); + + outw(0, 0x62); // reset upload address to 0. + // upload 4096 bytes from 0xFFFFE000. + outsb(0x66, (u8 *) 0xffffe000, 4096); + // upload 4096 bytes from 0xFFFFC000. + outsb(0x66, (u8 *) 0xffffc000, 4096); + + outw(0, 0x62); // reset upload address to 0. + // verify 4096 bytes from 0xFFFFE000. + for (fwptr = 0xffffe000; fwptr < 0xfffff000; fwptr++) { + if (inb(0x66) != *(u8 *) fwptr) { + verify_dmp_keyboard_error(); + } + } + // verify 4096 bytes from 0xFFFFC000. + for (fwptr = 0xffffc000; fwptr < 0xffffd000; fwptr++) { + if (inb(0x66) != *(u8 *) fwptr) { + verify_dmp_keyboard_error(); + } + } + + // disable firmware uploading. + pci_write_config32(dev, SB_REG_IPFCR, reg_sb_c0 & ~0x400L); + // wait keyboard controller ready by checking status port bit 2. + post_code(POST_KBD_CHK_READY); + while ((inb(0x64) & 0x4) == 0) { + } + post_code(POST_KBD_IS_READY); +} + +static void pci_routing_fixup(struct device *dev) +{ + const unsigned slot[3] = { 0 }; + const unsigned char slot_irqs[1][4] = { + {RT0_IRQ, RT1_IRQ, RT2_IRQ, RT3_IRQ}, + }; + const int slot_num = 1; + int i; + u32 int_routing = 0; + u32 ext_int_routing = 0; + + /* assign PCI-e bridge (bus#0, dev#1, fn#0) IRQ to RT0. */ + pci_assign_irqs(0, 1, slot_irqs[0]); + + /* RT0 is enabled. */ + int_routing |= irq_to_int_routing[RT0_IRQ] << RT0_IRQ_SHIFT; + + /* assign PCI slot IRQs. */ + for (i = 0; i < slot_num; i++) { + pci_assign_irqs(1, slot[i], slot_irqs[i]); + } + + /* Read PCI slot IRQs to see if RT1-3 is used, and enables it */ + for (i = 0; i < slot_num; i++) { + unsigned int funct; + device_t pdev; + u8 irq; + + /* Each slot may contain up to eight functions. */ + for (funct = 0; funct < 8; funct++) { + pdev = dev_find_slot(1, (slot[i] << 3) + funct); + if (!pdev) + continue; + irq = pci_read_config8(pdev, PCI_INTERRUPT_LINE); + if (irq == RT1_IRQ) { + int_routing |= irq_to_int_routing[RT1_IRQ] << RT1_IRQ_SHIFT; + } else if (irq == RT2_IRQ) { + int_routing |= irq_to_int_routing[RT2_IRQ] << RT2_IRQ_SHIFT; + } else if (irq == RT3_IRQ) { + int_routing |= irq_to_int_routing[RT3_IRQ] << RT3_IRQ_SHIFT; + } + } + } + + /* Setup S/B PCI Interrupt routing table reg(0x58). */ + int_routing |= irq_to_int_routing[EHCII_IRQ] << EHCIH_IRQ_SHIFT; + int_routing |= irq_to_int_routing[OHCII_IRQ] << OHCII_IRQ_SHIFT; + int_routing |= irq_to_int_routing[MAC_IRQ] << MAC_IRQ_SHIFT; + pci_write_config32(dev, SB_REG_PIRQ_X_ROUT, int_routing); + + /* Setup S/B PCI Extend Interrupt routing table reg(0xb4). */ + ext_int_routing |= irq_to_int_routing[USBD_IRQ] << USBD_IRQ_SHIFT; +#if CONFIG_IDE_NATIVE_MODE + /* IDE in native mode, only uses one IRQ. */ + ext_int_routing |= irq_to_int_routing[0] << SIDE_IRQ_SHIFT; + ext_int_routing |= irq_to_int_routing[PIDE_IRQ] << PIDE_IRQ_SHIFT; +#else + /* IDE in legacy mode, use IRQ 14, 15. */ + ext_int_routing |= irq_to_int_routing[IDE2_LEGACY_IRQ] << SIDE_IRQ_SHIFT; + ext_int_routing |= irq_to_int_routing[IDE1_LEGACY_IRQ] << PIDE_IRQ_SHIFT; +#endif + pci_write_config32(dev, SB_REG_PIRQ_X_ROUT2, ext_int_routing); + + /* Assign in-chip PCI device IRQs. */ + if (MAC_IRQ) { + unsigned char irqs[4] = { MAC_IRQ, 0, 0, 0 }; + pci_assign_irqs(0, 0x8, irqs); + } + if (OHCII_IRQ && EHCII_IRQ) { + unsigned char irqs[4] = { OHCII_IRQ, EHCII_IRQ, 0, 0 }; + pci_assign_irqs(0, 0xa, irqs); + } + if (CONFIG_IDE_NATIVE_MODE && PIDE_IRQ) { + /* IDE in native mode, setup PCI IRQ. */ + unsigned char irqs[4] = { PIDE_IRQ, 0, 0, 0 }; + pci_assign_irqs(0, 0xc, irqs); + } + if (USBD_IRQ) { + unsigned char irqs[4] = { USBD_IRQ, 0, 0, 0 }; + pci_assign_irqs(0, 0xf, irqs); + } +} + +static void vortex_sb_init(struct device *dev) +{ + u32 lpt_reg = 0; + +#if CONFIG_LPT_ENABLE + int ppmod = 0; +#if CONFIG_LPT_MODE_BPP + ppmod = 0; +#elif CONFIG_LPT_MODE_EPP_19_AND_SPP + ppmod = 1; +#elif CONFIG_LPT_MODE_ECP + ppmod = 2; +#elif CONFIG_LPT_MODE_ECP_AND_EPP_19 + ppmod = 3; +#elif CONFIG_LPT_MODE_SPP + ppmod = 4; +#elif CONFIG_LPT_MODE_EPP_17_AND_SPP + ppmod = 5; +#elif CONFIG_LPT_MODE_ECP_AND_EPP_17 + ppmod = 7; +#else +#error CONFIG_LPT_MODE error. +#endif + + /* Setup internal parallel port */ + lpt_reg |= (LPT_INT_C << 28); + lpt_reg |= (LPT_INT_ACK_SET << 27); + lpt_reg |= (ppmod << 24); + lpt_reg |= (LPT_UE << 23); + lpt_reg |= (LPT_PDMAS << 22); + lpt_reg |= (LPT_DREQS << 20); + lpt_reg |= (irq_to_int_routing[CONFIG_LPT_IRQ] << 16); + lpt_reg |= (CONFIG_LPT_IO << 0); +#endif // CONFIG_LPT_ENABLE + pci_write_config32(dev, SB_REG_IPPCR, lpt_reg); +} + +#define SETUP_GPIO_ADDR(n) \ + u32 cfg##n = (CONFIG_GPIO_P##n##_DIR_ADDR << 16) | (CONFIG_GPIO_P##n##_DATA_ADDR);\ + outl(cfg##n, base + 4 + (n * 4));\ + gpio_enable_mask |= (1 << n); + +#define INIT_GPIO(n) \ + outb(CONFIG_GPIO_P##n##_INIT_DIR, CONFIG_GPIO_P##n##_DIR_ADDR);\ + outb(CONFIG_GPIO_P##n##_INIT_DATA, CONFIG_GPIO_P##n##_DATA_ADDR); + +static void ex_sb_gpio_init(struct device *dev) +{ + const int base = 0xb00; + u32 gpio_enable_mask = 0; + /* S/B register 63h - 62h : GPIO Port Config IO Base Address */ + pci_write_config16(dev, SB_REG_GPIO_CFG_IO_BASE, base | 1); + /* Set GPIO port 0~9 base address. + * Config Base + 04h, 08h, 0ch... : GPIO port 0~9 data/dir decode addr. + * Bit 31-16 : DBA, GPIO direction base address. + * Bit 15-0 : DPBA, GPIO data port base address. + * */ +#if CONFIG_GPIO_P0_ENABLE + SETUP_GPIO_ADDR(0) +#endif +#if CONFIG_GPIO_P1_ENABLE + SETUP_GPIO_ADDR(1) +#endif +#if CONFIG_GPIO_P2_ENABLE + SETUP_GPIO_ADDR(2) +#endif +#if CONFIG_GPIO_P3_ENABLE + SETUP_GPIO_ADDR(3) +#endif +#if CONFIG_GPIO_P4_ENABLE + SETUP_GPIO_ADDR(4) +#endif +#if CONFIG_GPIO_P5_ENABLE + SETUP_GPIO_ADDR(5) +#endif +#if CONFIG_GPIO_P6_ENABLE + SETUP_GPIO_ADDR(6) +#endif +#if CONFIG_GPIO_P7_ENABLE + SETUP_GPIO_ADDR(7) +#endif +#if CONFIG_GPIO_P8_ENABLE + SETUP_GPIO_ADDR(8) +#endif +#if CONFIG_GPIO_P9_ENABLE + SETUP_GPIO_ADDR(9) +#endif + /* Enable GPIO port 0~9. */ + outl(gpio_enable_mask, base); + /* Set GPIO port 0-9 initial dir and data. */ +#if CONFIG_GPIO_P0_ENABLE + INIT_GPIO(0) +#endif +#if CONFIG_GPIO_P1_ENABLE + INIT_GPIO(1) +#endif +#if CONFIG_GPIO_P2_ENABLE + INIT_GPIO(2) +#endif +#if CONFIG_GPIO_P3_ENABLE + INIT_GPIO(3) +#endif +#if CONFIG_GPIO_P4_ENABLE + INIT_GPIO(4) +#endif +#if CONFIG_GPIO_P5_ENABLE + INIT_GPIO(5) +#endif +#if CONFIG_GPIO_P6_ENABLE + INIT_GPIO(6) +#endif +#if CONFIG_GPIO_P7_ENABLE + INIT_GPIO(7) +#endif +#if CONFIG_GPIO_P8_ENABLE + INIT_GPIO(8) +#endif +#if CONFIG_GPIO_P9_ENABLE + INIT_GPIO(9) +#endif + /* Disable GPIO Port Config IO Base Address. */ + pci_write_config16(dev, SB_REG_GPIO_CFG_IO_BASE, 0x0); +} + +static u32 make_uart_config(u16 base, u8 irq) +{ + u8 mapped_irq = irq_to_int_routing[irq]; + u32 cfg = 0; + cfg |= 1 << 23; // UE = enabled. + cfg |= (mapped_irq << 16); // UIRT. + cfg |= base; // UIOA. + return cfg; +} + +#define SETUP_UART(n) \ + uart_cfg = make_uart_config(CONFIG_UART##n##_IO, CONFIG_UART##n##_IRQ);\ + outl(uart_cfg, base + (n - 1) * 4);\ + uart8250_init(CONFIG_UART##n##_IO, 115200 / CONFIG_UART##n##_BAUD); + +static void ex_sb_uart_init(struct device *dev) +{ + const int base = 0xc00; + u32 uart_cfg = 0; + /* S/B register 61h - 60h : UART Config IO Base Address */ + pci_write_config16(dev, SB_REG_UART_CFG_IO_BASE, base | 1); + /* setup UART */ +#if CONFIG_UART1_ENABLE + SETUP_UART(1) +#endif +#if CONFIG_UART2_ENABLE + SETUP_UART(2) +#endif +#if CONFIG_UART3_ENABLE + SETUP_UART(3) +#endif +#if CONFIG_UART4_ENABLE + SETUP_UART(4) +#endif +#if CONFIG_UART5_ENABLE + SETUP_UART(5) +#endif +#if CONFIG_UART6_ENABLE + SETUP_UART(6) +#endif +#if CONFIG_UART7_ENABLE + SETUP_UART(7) +#endif +#if CONFIG_UART8_ENABLE + SETUP_UART(8) +#endif +#if CONFIG_UART9_ENABLE + SETUP_UART(9) +#endif +#if CONFIG_UART10_ENABLE + SETUP_UART(10) +#endif + /* Keep UART Config I/O base address */ + //pci_write_config16(SB, SB_REG_UART_CFG_IO_BASE, 0x0); +} + +static int get_rtc_update_in_progress(void) +{ + if (cmos_read(RTC_REG_A) & RTC_UIP) + return 1; + return 0; +} + +static void unsafe_read_cmos_rtc(u8 rtc[7]) +{ + rtc[0] = cmos_read(RTC_CLK_ALTCENTURY); + rtc[1] = cmos_read(RTC_CLK_YEAR); + rtc[2] = cmos_read(RTC_CLK_MONTH); + rtc[3] = cmos_read(RTC_CLK_DAYOFMONTH); + rtc[4] = cmos_read(RTC_CLK_HOUR); + rtc[5] = cmos_read(RTC_CLK_MINUTE); + rtc[6] = cmos_read(RTC_CLK_SECOND); +} + +static void read_cmos_rtc(u8 rtc[7]) +{ + /* Read RTC twice and check update-in-progress flag, to make + * sure RTC is correct */ + u8 rtc_old[7], rtc_new[7]; + while (get_rtc_update_in_progress()) ; + unsafe_read_cmos_rtc(rtc_new); + do { + memcpy(rtc_old, rtc_new, 7); + while (get_rtc_update_in_progress()) ; + unsafe_read_cmos_rtc(rtc_new); + } while (memcmp(rtc_new, rtc_old, 7) != 0); +} + +/* + * Convert a number in decimal format into the BCD format. + * Return 255 if not a valid BCD value. + */ +static u8 bcd2dec(u8 bcd) +{ + u8 h, l; + h = bcd >> 4; + l = bcd & 0xf; + if (h > 9 || l > 9) + return 255; + return h * 10 + l; +} + +static void fix_cmos_rtc_time(void) +{ + /* Read RTC data. */ + u8 rtc[7]; + read_cmos_rtc(rtc); + + /* Convert RTC from BCD format to binary. */ + u8 bin_rtc[7]; + int i; + for (i = 0; i < 8; i++) { + bin_rtc[i] = bcd2dec(rtc[i]); + } + + /* If RTC date is invalid, fix it. */ + if (bin_rtc[0] > 99 || bin_rtc[1] > 99 || bin_rtc[2] > 12 || bin_rtc[3] > 31) { + /* Set PC compatible timing mode. */ + cmos_write(0x26, RTC_REG_A); + cmos_write(0x02, RTC_REG_B); + /* Now setup a default date 2008/08/08 08:08:08. */ + cmos_write(0x8, RTC_CLK_SECOND); + cmos_write(0x8, RTC_CLK_MINUTE); + cmos_write(0x8, RTC_CLK_HOUR); + cmos_write(0x6, RTC_CLK_DAYOFWEEK); /* Friday */ + cmos_write(0x8, RTC_CLK_DAYOFMONTH); + cmos_write(0x8, RTC_CLK_MONTH); + cmos_write(0x8, RTC_CLK_YEAR); + cmos_write(0x20, RTC_CLK_ALTCENTURY); + } +} + +static void vortex86_sb_set_io_resv(device_t dev, u32 io_resv_size) +{ + struct resource *res; + res = new_resource(dev, 1); + res->base = 0x0UL; + res->size = io_resv_size; + res->limit = 0xffffUL; + res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; +} + +static void vortex86_sb_set_spi_flash_size(device_t dev, u32 flash_size) +{ + /* SPI flash is in topmost of 4G memory space */ + struct resource *res; + res = new_resource(dev, 2); + res->base = 0x100000000LL - flash_size; + res->size = flash_size; + res->limit = 0xffffffffUL; + res->flags = IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; +} + +static void vortex86_sb_read_resources(device_t dev) +{ + u32 flash_size = 8 * 1024 * 1024; + + pci_dev_read_resources(dev); + + if (dev->device == 0x6011) { + /* It is EX CPU southbridge */ + if (get_pci_dev_func(dev) != 0) { + /* only for function 0, skip function 1 */ + return; + } + /* default SPI flash ROM is 64MB */ + flash_size = 64 * 1024 * 1024; + } + + /* Reserve space for I/O */ + vortex86_sb_set_io_resv(dev, 0x1000UL); + + /* Reserve space for flash */ + vortex86_sb_set_spi_flash_size(dev, flash_size); +} + +static void southbridge_init(struct device *dev) +{ + if (dev->device == 0x6011) { + /* It is EX CPU southbridge */ + if (get_pci_dev_func(dev) != 0) { + /* only for function 0, skip function 1 */ + return; + } + } + upload_dmp_keyboard_firmware(dev); + vortex_sb_init(dev); + if (dev->device == 0x6011) { + ex_sb_gpio_init(dev); + ex_sb_uart_init(dev); + } + pci_routing_fixup(dev); + + fix_cmos_rtc_time(); + rtc_init(0); +} + +static struct device_operations vortex_sb_ops = { + .read_resources = vortex86_sb_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = &southbridge_init, + .scan_bus = scan_static_bus, + .enable = 0, + .ops_pci = 0, +}; + +static const struct pci_driver pci_driver_6011 __pci_driver = { + .ops = &vortex_sb_ops, + .vendor = PCI_VENDOR_ID_RDC, + .device = 0x6011, /* EX CPU S/B ID */ +}; + +struct chip_operations southbridge_dmp_vortex86ex_ops = { + CHIP_NAME("DMP Vortex86EX Southbridge") + .enable_dev = 0 +}; diff --git a/src/southbridge/dmp/vortex86ex/southbridge.h b/src/southbridge/dmp/vortex86ex/southbridge.h new file mode 100644 index 0000000000..60e6dbcaac --- /dev/null +++ b/src/southbridge/dmp/vortex86ex/southbridge.h @@ -0,0 +1,42 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 DMP Electronics Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SOUTHBRIDGE_H +#define SOUTHBRIDGE_H + +#define SB PCI_DEV(0, 7, 0) +#define SB_REG_LPCCR 0x41 +#define SB_REG_FRCSCR 0x42 +#define SB_REG_PIRQ_X_ROUT 0x58 +#define SB_REG_UART_CFG_IO_BASE 0x60 +#define SB_REG_GPIO_CFG_IO_BASE 0x62 +#define SB_REG_CS_BASE0 0x90 +#define SB_REG_CS_BASE_MASK0 0x94 +#define SB_REG_CS_BASE1 0x98 +#define SB_REG_CS_BASE_MASK1 0x9c +#define SB_REG_IPPCR 0xb0 +#define SB_REG_PIRQ_X_ROUT2 0xb4 +#define SB_REG_OCDCR 0xbc +#define SB_REG_IPFCR 0xc0 +#define SB_REG_FRWPR 0xc4 +#define SB_REG_STRAP 0xce + +#define SYSTEM_CTL_PORT 0x92 + +#endif /* SOUTHBRIDGE_H */ |