summaryrefslogtreecommitdiff
path: root/src/soc/dmp
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/dmp')
-rw-r--r--src/soc/dmp/vortex86ex/Kconfig20
-rw-r--r--src/soc/dmp/vortex86ex/Makefile.inc26
-rw-r--r--src/soc/dmp/vortex86ex/audio.c25
-rw-r--r--src/soc/dmp/vortex86ex/chip.h34
-rw-r--r--src/soc/dmp/vortex86ex/hard_reset.c21
-rw-r--r--src/soc/dmp/vortex86ex/ide_sd_sata.c167
-rw-r--r--src/soc/dmp/vortex86ex/northbridge.c133
-rw-r--r--src/soc/dmp/vortex86ex/northbridge.h65
-rw-r--r--src/soc/dmp/vortex86ex/raminit.c321
-rw-r--r--src/soc/dmp/vortex86ex/southbridge.c632
-rw-r--r--src/soc/dmp/vortex86ex/southbridge.h42
-rw-r--r--src/soc/dmp/vortex86ex/xgi_oprom.c31
12 files changed, 1517 insertions, 0 deletions
diff --git a/src/soc/dmp/vortex86ex/Kconfig b/src/soc/dmp/vortex86ex/Kconfig
new file mode 100644
index 0000000000..7c616d6f29
--- /dev/null
+++ b/src/soc/dmp/vortex86ex/Kconfig
@@ -0,0 +1,20 @@
+##
+## 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.
+##
+
+config SOC_DMP_VORTEX86EX
+ bool
+ select LATE_CBMEM_INIT
+ select AZALIA_PLUGIN_SUPPORT
+ select HAVE_HARD_RESET
diff --git a/src/soc/dmp/vortex86ex/Makefile.inc b/src/soc/dmp/vortex86ex/Makefile.inc
new file mode 100644
index 0000000000..a896fcd6fc
--- /dev/null
+++ b/src/soc/dmp/vortex86ex/Makefile.inc
@@ -0,0 +1,26 @@
+##
+## 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.
+##
+
+ifeq ($(CONFIG_SOC_DMP_VORTEX86EX),y)
+
+ramstage-y += northbridge.c
+ramstage-y += xgi_oprom.c
+
+ramstage-y += southbridge.c
+ramstage-y += hard_reset.c
+ramstage-y += ide_sd_sata.c
+ramstage-y += audio.c
+
+endif
diff --git a/src/soc/dmp/vortex86ex/audio.c b/src/soc/dmp/vortex86ex/audio.c
new file mode 100644
index 0000000000..05a0d8c7d2
--- /dev/null
+++ b/src/soc/dmp/vortex86ex/audio.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.
+ */
+
+#include <device/azalia_device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+
+/* RDC HD audio controller */
+static const struct pci_driver rdc_audio __pci_driver = {
+ .ops = &default_azalia_audio_ops,
+ .vendor = PCI_VENDOR_ID_RDC,
+ .device = 0x3010,
+};
diff --git a/src/soc/dmp/vortex86ex/chip.h b/src/soc/dmp/vortex86ex/chip.h
new file mode 100644
index 0000000000..d67b8014c1
--- /dev/null
+++ b/src/soc/dmp/vortex86ex/chip.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef _SOC_DMP_VORTEX86EX
+#define _SOC_DMP_VORTEX86EX
+
+struct soc_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 /* _SOC_DMP_VORTEX86EX */
diff --git a/src/soc/dmp/vortex86ex/hard_reset.c b/src/soc/dmp/vortex86ex/hard_reset.c
new file mode 100644
index 0000000000..9b9c426733
--- /dev/null
+++ b/src/soc/dmp/vortex86ex/hard_reset.c
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+#include <arch/io.h>
+#include <reset.h>
+
+void hard_reset(void)
+{
+}
diff --git a/src/soc/dmp/vortex86ex/ide_sd_sata.c b/src/soc/dmp/vortex86ex/ide_sd_sata.c
new file mode 100644
index 0000000000..936505e436
--- /dev/null
+++ b/src/soc/dmp/vortex86ex/ide_sd_sata.c
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+#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/soc/dmp/vortex86ex/northbridge.c b/src/soc/dmp/vortex86ex/northbridge.c
new file mode 100644
index 0000000000..62c68e062e
--- /dev/null
+++ b/src/soc/dmp/vortex86ex/northbridge.c
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <cbmem.h>
+#include <pc80/mc146818rtc.h>
+#include "chip.h"
+#include "northbridge.h"
+
+#define SPI_BASE 0xfc00
+
+static void northbridge_init(device_t dev)
+{
+ printk(BIOS_DEBUG, "Vortex86EX northbridge early init ...\n");
+ // enable F0A/ECA/E8A/E4A/E0A/C4A/C0A shadow read/writable.
+ pci_write_config32(dev, NB_REG_MAR, 0x3ff000f0);
+ // enable C0000h - C3FFFh/C4000h - C7FFF can be in L1 cache selection.
+ pci_write_config32(dev, NB_REG_HOST_CTL, (1 << 18) | (1 << 19));
+ // Set SPI register base.
+ pci_write_config16(dev, NB_REG_SPI_BASE, SPI_BASE | 1);
+}
+
+static struct device_operations northbridge_operations = {
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = northbridge_init
+};
+
+static const struct pci_driver northbridge_driver_6025 __pci_driver = {
+ .ops = &northbridge_operations,
+ .vendor = PCI_VENDOR_ID_RDC,
+ .device = 0x6025, /* EX CPU N/B ID */
+};
+
+/* Set CMOS register 15h/16h/17h/18h for base/extended
+ * memory size. */
+static void set_cmos_memory_size(unsigned long sizek)
+{
+ unsigned long ext_mem_size;
+ u8 ext_mem_size_hb, ext_mem_size_lb;
+ /* calculate memory size between 1M - 65M. */
+ ext_mem_size = sizek - 1024;
+ if (ext_mem_size > 65535)
+ ext_mem_size = 65535;
+ ext_mem_size_hb = (u8) (ext_mem_size >> 8);
+ ext_mem_size_lb = (u8) (ext_mem_size & 0xff);
+ /* Base memory is always 640K. */
+ cmos_write(0x80, 0x15);
+ cmos_write(0x02, 0x16);
+ /* Write extended memory size. */
+ cmos_write(ext_mem_size_lb, 0x17);
+ cmos_write(ext_mem_size_hb, 0x18);
+ /* register 0x30(48) is RTC_BOOT_BYTE for coreboot,
+ * don't touch it. */
+}
+
+static void pci_domain_set_resources(device_t dev)
+{
+ device_t mc_dev;
+ uint32_t pci_tolm;
+
+ printk(BIOS_SPEW, "Entering vortex86ex pci_domain_set_resources.\n");
+
+ pci_tolm = find_pci_tolm(dev->link_list);
+ mc_dev = dev->link_list->children;
+ if (mc_dev) {
+ unsigned long tomk, tolmk;
+ int idx;
+ int ss;
+ /* Get DDRII size setting from northbridge register. */
+ /* SS = 0 for 2MB, 1 for 4MB, 2 for 8MB, 3 for 16MB ... */
+ ss = pci_read_config16(mc_dev, 0x6c);
+ ss = ((ss >> 8) & 0xf);
+ tomk = (2 * 1024) << ss;
+ printk(BIOS_DEBUG, "I would set ram size to %ld Mbytes\n", (tomk >> 10));
+ /* Compute the top of Low memory */
+ tolmk = pci_tolm >> 10;
+ if (tolmk >= tomk)
+ /* The PCI hole does does not overlap the memory.
+ */
+ tolmk = tomk;
+
+ set_top_of_ram(tolmk * 1024);
+
+ /* Report the memory regions */
+ idx = 10;
+ ram_resource(dev, idx++, 0, 640); /* first 640k */
+ ram_resource(dev, idx++, 768, tolmk - 768); /* leave a hole for vga */
+ set_cmos_memory_size(tolmk);
+ }
+ assign_resources(dev->link_list);
+}
+
+static struct device_operations pci_domain_ops = {
+ .read_resources = pci_domain_read_resources,
+ .set_resources = pci_domain_set_resources,
+ .enable_resources = NULL,
+ .init = NULL,
+ .scan_bus = pci_domain_scan_bus,
+ .ops_pci_bus = pci_bus_default_ops,
+};
+
+static void enable_dev(struct device *dev)
+{
+ printk(BIOS_SPEW, "In vortex86ex enable_dev for device %s.\n", dev_path(dev));
+
+ /* Set the operations if it is a special bus type */
+ if (dev->path.type == DEVICE_PATH_DOMAIN) {
+ dev->ops = &pci_domain_ops;
+ }
+}
+
+struct chip_operations northbridge_dmp_vortex86ex_ops = {
+ CHIP_NAME("DMP Vortex86EX Northbridge")
+ .enable_dev = enable_dev,
+};
diff --git a/src/soc/dmp/vortex86ex/northbridge.h b/src/soc/dmp/vortex86ex/northbridge.h
new file mode 100644
index 0000000000..d5bb6f1c3a
--- /dev/null
+++ b/src/soc/dmp/vortex86ex/northbridge.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#ifndef NORTHBRIDGE_H
+#define NORTHBRIDGE_H
+
+#define NB PCI_DEV(0, 0, 0)
+#define NB_REG_SPI_BASE 0x40
+#define NB_REG_CLK_OUT_CTL 0x48
+#define NB_REG_PCI_CLK_CTL 0x4b
+#define NB_REG_STRAP 0x60
+#define NB_REG_STRAP2 0x64
+#define NB_REG_MBR 0x6c
+#define NB_REG_DDR3_CFG 0x74
+#define NB_REG_DDR3_MTR1 0x78
+#define NB_REG_DDR3_MTR2 0x7c
+#define NB_REG_SMM 0x83
+#define NB_REG_MAR 0x84
+#define NB_REG_CID 0x90
+#define NB_REG_S1R 0x94
+#define NB_REG_S2R 0x98
+#define NB_REG_S3R 0x9c
+#define NB_REG_HOST_CTL 0xa0
+#define NB_REG_CPU_MBCR 0xc4
+#define NB_REG_CDR 0xd0
+#define NB_REG_PACR 0xf0
+#define NB_REG_PMCR 0xf4
+#define NB_REG_PCI_TARGET 0xf8
+#define NB_REG_PCSCR 0xfc
+
+/* Additional "virtual" device, just extension of NB */
+#define NB1 PCI_DEV(0, 0, 1)
+#define NB1_REG_FJZ_PHY_CTL1 0x80
+#define NB1_REG_FJZ_PHY_CTL2 0x84
+#define NB1_REG_FJZ_PHY_CTL3 0x88
+#define NB1_REG_FJZ_DRAM_CTL1 0x90
+#define NB1_REG_FJZ_DRAM_CTL2 0x94
+#define NB1_REG_FJZ_DRAM_CTL3 0x98
+#define NB1_REG_FJZ_DRAM_CTL4 0x9c
+#define NB1_REG_PLL_TEST_CTL 0xa8
+#define NB1_REG_DDR3_PWR_SAV 0xbc
+#define NB1_REG_DDR3_CTL_OPT1 0xc0
+#define NB1_REG_DDR3_CTL_OPT3 0xc8
+#define NB1_REG_DDR3_CTL_OPT4 0xcc
+#define NB1_REG_DDR3_CTL_OPT5 0xce
+#define NB1_REG_PLL_TEST_MODE 0xd0
+#define NB1_REG_L2_CACHE_CTL 0xe8
+#define NB1_REG_SSCR 0xec
+#define NB1_REG_NB_CTL_OPT1 0xf4
+#define NB1_REG_UPDATE_PHY_IO 0xf8
+#define NB1_REG_RESET_DRAMC_PHY 0xfa
+
+#endif /* NORTHBRIDGE_H */
diff --git a/src/soc/dmp/vortex86ex/raminit.c b/src/soc/dmp/vortex86ex/raminit.c
new file mode 100644
index 0000000000..1ccdb27e7e
--- /dev/null
+++ b/src/soc/dmp/vortex86ex/raminit.c
@@ -0,0 +1,321 @@
+/*
+ * 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.
+ */
+
+static u16 get_mask(u16 bit_width, u16 bit_offset)
+{
+ u16 mask = (((1 << bit_width) - 1) << bit_offset);
+ return mask;
+}
+
+static u16 set_bitfield(u16 val, u16 bits, u16 bit_width, u16 bit_offset)
+{
+ u16 mask = get_mask(bit_width, bit_offset);
+ val = (val & ~mask) | (bits << bit_offset);
+ return val;
+}
+
+static u16 get_bitfield(u16 val, u16 bit_width, u16 bit_offset)
+{
+ u16 mask = get_mask(bit_width, bit_offset);
+ return (val & mask) >> bit_offset;
+}
+
+static u8 check_address_bit(int addr_bit)
+{
+ u16 dummy;
+ *(volatile u16 *)(0) = 0;
+ dummy = *(volatile u16 *)(0); // read push write
+ *(volatile u16 *)(1 << addr_bit) = 0x5a5a;
+ dummy = *(volatile u16 *)(1 << addr_bit); // read push write
+ if ((*(volatile u16 *)(0)) != 0)
+ return 0; // address bit wrapped.
+ return 1; // address bit not wrapped.
+}
+
+static u8 check_dram_side(int addr_bit)
+{
+ *(volatile u16 *)(1 << addr_bit) = 0x5a5a;
+ *(volatile u16 *)(0) = 0;
+ if ((*(volatile u16 *)(1 << addr_bit)) != 0x5a5a)
+ return 0; // DRAM only one side.
+ return 1; // two sides.
+}
+
+// DDRIII memory bank register control:
+// bit :
+// 2 - 0 : DRAMC_COLSIZE : DDRIII Column Address Type : 0 0 0 = 10bit
+// : 0 0 1 = 11bit
+// 7 - 5 : DRAMC_ROWSIZE : DDRIII Row Address Type : 0 0 0 = 13bit
+// : 0 0 1 = 14bit
+// : 0 1 0 = 15bit
+// : 0 1 1 = 16bit
+// 11 - 8 : DRAM_SIZE : DDRIII Size : 0 1 0 1 = 64M
+// : 0 1 1 0 = 128M
+// : 0 1 1 1 = 256M
+// : 1 0 0 0 = 512M
+// : 1 0 0 1 = 1GB
+// : 1 0 1 0 = 2GB
+// 13 : DRAMC_CSMASK : DDRIII CS#[1] Mask : 1 = Mask CS1 enable
+
+#define DDR3_COL_10BIT 0
+#define DDR3_COL_11BIT 1
+#define DDR3_ROW_13BIT 0
+#define DDR3_ROW_14BIT 1
+#define DDR3_ROW_15BIT 2
+#define DDR3_ROW_16BIT 3
+#define DDR3_SIZE_64M 5
+#define DDR3_SIZE_128M 6
+#define DDR3_SIZE_256M 7
+#define DDR3_SIZE_512M 8
+#define DDR3_SIZE_1GB 9
+#define DDR3_SIZE_2GB 10
+#define DDR3_C1M_ACTIVE 0
+#define DDR3_C1M_MASK 1
+
+static u16 set_ddr3_mem_reg_col(u16 reg, u16 col)
+{
+ return set_bitfield(reg, col, 3, 0);
+}
+
+static u16 get_ddr3_mem_reg_col(u16 reg)
+{
+ return get_bitfield(reg, 3, 0);
+}
+
+static u16 set_ddr3_mem_reg_row(u16 reg, u16 row)
+{
+ return set_bitfield(reg, row, 3, 5);
+}
+
+static u16 get_ddr3_mem_reg_row(u16 reg)
+{
+ return get_bitfield(reg, 3, 5);
+}
+
+static u16 set_ddr3_mem_reg_size(u16 reg, u16 size)
+{
+ return set_bitfield(reg, size, 4, 8);
+}
+
+static u16 get_ddr3_mem_reg_size(u16 reg)
+{
+ return get_bitfield(reg, 4, 8);
+}
+
+static u16 set_ddr3_mem_reg_c1m(u16 reg, u16 c1m)
+{
+ return set_bitfield(reg, c1m, 1, 13);
+}
+
+static u16 get_ddr3_mem_reg_c1m(u16 reg)
+{
+ return get_bitfield(reg, 1, 13);
+}
+
+static u16 auto_set_ddr3_mem_reg_size(u16 reg)
+{
+ u8 ss = 0;
+ // If reg is the minimum DRAM size,
+ // SS is also the minimum size 128M.
+ // If size in reg is bigger, SS is also bigger.
+ ss += get_ddr3_mem_reg_col(reg);
+ ss += get_ddr3_mem_reg_row(reg);
+ ss += (1 - get_ddr3_mem_reg_c1m(reg));
+ ss += DDR3_SIZE_128M;
+ return set_ddr3_mem_reg_size(reg, ss);
+}
+
+static u16 get_ddr3_mem_reg(u16 col, u16 row, u16 c1m)
+{
+ u16 reg;
+ reg = 0;
+ reg = set_ddr3_mem_reg_col(reg, col);
+ reg = set_ddr3_mem_reg_row(reg, row);
+ reg = set_ddr3_mem_reg_c1m(reg, c1m);
+ reg = auto_set_ddr3_mem_reg_size(reg);
+ return reg;
+}
+
+static void ddr3_phy_reset(void)
+{
+ // PCI N/B reg FAh bit 6 = RST_DRAM_PHY.
+ pci_write_config8(NB1, NB1_REG_RESET_DRAMC_PHY, 0x40);
+ while ((pci_read_config8(NB1, NB1_REG_RESET_DRAMC_PHY) & 0x40) == 0x40) {
+ }
+ // reload mode.
+ u32 ddr3_cfg = pci_read_config32(NB, NB_REG_DDR3_CFG);
+ pci_write_config32(NB, NB_REG_DDR3_CFG, ddr3_cfg);
+}
+
+static u8 detect_ddr3_dram_cs(u16 reg, u8 base_addr_bit)
+{
+ reg = set_ddr3_mem_reg_c1m(reg, DDR3_C1M_ACTIVE);
+ reg = auto_set_ddr3_mem_reg_size(reg);
+ pci_write_config16(NB, NB_REG_MBR, reg);
+ if (check_dram_side(base_addr_bit + 1)) {
+ base_addr_bit += 1;
+ return 0;
+ }
+
+ reg = set_ddr3_mem_reg_c1m(reg, DDR3_C1M_MASK);
+ reg = auto_set_ddr3_mem_reg_size(reg);
+ pci_write_config16(NB, NB_REG_MBR, reg);
+ // no need to check CS = 0.
+ // Need to reset DDR3 PHY.
+ ddr3_phy_reset();
+ return 0;
+}
+
+static u8 detect_ddr3_dram_row(u16 reg, u8 base_addr_bit)
+{
+ reg = set_ddr3_mem_reg_row(reg, DDR3_ROW_16BIT);
+ reg = auto_set_ddr3_mem_reg_size(reg);
+ pci_write_config16(NB, NB_REG_MBR, reg);
+ if (check_address_bit(base_addr_bit + 16)) {
+ base_addr_bit += 16;
+ return detect_ddr3_dram_cs(reg, base_addr_bit);
+ }
+
+ reg = set_ddr3_mem_reg_row(reg, DDR3_ROW_15BIT);
+ reg = auto_set_ddr3_mem_reg_size(reg);
+ pci_write_config16(NB, NB_REG_MBR, reg);
+ if (check_address_bit(base_addr_bit + 15)) {
+ base_addr_bit += 15;
+ return detect_ddr3_dram_cs(reg, base_addr_bit);
+ }
+
+ reg = set_ddr3_mem_reg_row(reg, DDR3_ROW_14BIT);
+ reg = auto_set_ddr3_mem_reg_size(reg);
+ pci_write_config16(NB, NB_REG_MBR, reg);
+ if (check_address_bit(base_addr_bit + 14)) {
+ base_addr_bit += 14;
+ return detect_ddr3_dram_cs(reg, base_addr_bit);
+ }
+
+ reg = set_ddr3_mem_reg_row(reg, DDR3_ROW_13BIT);
+ reg = auto_set_ddr3_mem_reg_size(reg);
+ pci_write_config16(NB, NB_REG_MBR, reg);
+ if (check_address_bit(base_addr_bit + 13)) {
+ base_addr_bit += 13;
+ return detect_ddr3_dram_cs(reg, base_addr_bit);
+ }
+ // row test error.
+ return 1;
+}
+
+static u8 detect_ddr3_dram_bank(u16 reg, u8 base_addr_bit)
+{
+ /* DDR3 is always 3 bank bits */
+ base_addr_bit += 3;
+ return detect_ddr3_dram_row(reg, base_addr_bit);
+}
+
+static u8 detect_ddr3_dram_col(u16 reg, u8 base_addr_bit)
+{
+ reg = set_ddr3_mem_reg_col(reg, DDR3_COL_11BIT);
+ reg = auto_set_ddr3_mem_reg_size(reg);
+ pci_write_config16(NB, NB_REG_MBR, reg);
+ if (check_address_bit(base_addr_bit + 11)) {
+ base_addr_bit += 11;
+ return detect_ddr3_dram_bank(reg, base_addr_bit);
+ }
+
+ reg = set_ddr3_mem_reg_col(reg, DDR3_COL_10BIT);
+ reg = auto_set_ddr3_mem_reg_size(reg);
+ pci_write_config16(NB, NB_REG_MBR, reg);
+ if (check_address_bit(base_addr_bit + 10)) {
+ base_addr_bit += 10;
+ return detect_ddr3_dram_bank(reg, base_addr_bit);
+ }
+ // col test error.
+ return 1;
+}
+
+static u8 detect_ddr3_dram_size(void)
+{
+ u16 reg;
+ u8 base_addr_bit = 0;
+ reg = get_ddr3_mem_reg(DDR3_COL_10BIT, DDR3_ROW_13BIT, DDR3_C1M_MASK);
+ return detect_ddr3_dram_col(reg, base_addr_bit);
+}
+
+static void print_ddr3_memory_setup(void)
+{
+#if CONFIG_DEBUG_RAM_SETUP
+ printk(BIOS_DEBUG, "DDR3 Timing Reg 0-3:\n");
+ printk(BIOS_DEBUG, "NB 6e : ");
+ print_debug_hex16(pci_read_config16(NB, 0x6e));
+ printk(BIOS_DEBUG, "\nNB 74 : ");
+ print_debug_hex32(pci_read_config32(NB, 0x74));
+ printk(BIOS_DEBUG, "\nNB 78 : ");
+ print_debug_hex32(pci_read_config32(NB, 0x78));
+ printk(BIOS_DEBUG, "\nNB 7c : ");
+ print_debug_hex32(pci_read_config32(NB, 0x7c));
+ u16 mbr = pci_read_config16(NB, 0x6c);
+ printk(BIOS_DEBUG, "\nNB 6c(MBR) : ");
+ print_debug_hex16(mbr);
+ const char *s;
+ u8 col = get_ddr3_mem_reg_col(mbr);
+ if (col == DDR3_COL_10BIT)
+ s = " (COL=10";
+ else
+ s = " (COL=11";
+ print_debug(s);
+ u8 row = get_ddr3_mem_reg_row(mbr);
+ switch (row) {
+ case DDR3_ROW_13BIT:
+ s = ", ROW = 13";
+ break;
+ case DDR3_ROW_14BIT:
+ s = ", ROW = 14";
+ break;
+ case DDR3_ROW_15BIT:
+ s = ", ROW = 15";
+ break;
+ default:
+ s = ", ROW = 16";
+ break;
+ }
+ print_debug(s);
+ u8 size = get_ddr3_mem_reg_size(mbr);
+ switch (size) {
+ case DDR3_SIZE_64M:
+ s = ", 64M";
+ break;
+ case DDR3_SIZE_128M:
+ s = ", 128M";
+ break;
+ case DDR3_SIZE_256M:
+ s = ", 256M";
+ break;
+ case DDR3_SIZE_512M:
+ s = ", 512M";
+ break;
+ case DDR3_SIZE_1GB:
+ s = ", 1GB";
+ break;
+ case DDR3_SIZE_2GB:
+ s = ", 2GB";
+ break;
+ }
+ print_debug(s);
+ u8 mask = get_ddr3_mem_reg_c1m(mbr);
+ if (mask == DDR3_C1M_ACTIVE)
+ s = ", CS MASK Enable)\n";
+ else
+ s = ", CS Mask Disable)\n";
+ print_debug(s);
+#endif
+}
diff --git a/src/soc/dmp/vortex86ex/southbridge.c b/src/soc/dmp/vortex86ex/southbridge.c
new file mode 100644
index 0000000000..05702d1eb6
--- /dev/null
+++ b/src/soc/dmp/vortex86ex/southbridge.c
@@ -0,0 +1,632 @@
+/*
+ * 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.
+ */
+
+#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 <pc80/keyboard.h>
+#include <string.h>
+#include <delay.h>
+#include "arch/io.h"
+#include "chip.h"
+#include "southbridge.h"
+#include "cpu/dmp/dmp_post_code.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 CAN_IRQ_SHIFT 28
+#define HDA_IRQ_SHIFT 20
+#define USBD_IRQ_SHIFT 16
+#define SIDE_IRQ_SHIFT 12
+#define PIDE_IRQ_SHIFT 8
+
+/* S/B function 1 Extend PCI Interrupt routing table reg 2(0xb4)
+ * field bit shift.
+ */
+#define SPI1_IRQ_SHIFT 8
+#define MOTOR_IRQ_SHIFT 0
+
+/* in-chip PCI device IRQs(0 for disabled). */
+#define EHCII_IRQ 5
+#define OHCII_IRQ 5
+#define MAC_IRQ 6
+
+#define CAN_IRQ 10
+#define HDA_IRQ 7
+#define USBD_IRQ 6
+#define PIDE_IRQ 5
+
+#define SPI1_IRQ 10
+#define I2C0_IRQ 10
+#define MOTOR_IRQ 11
+
+/* 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
+
+/* keyboard controller system flag timeout : 400 ms */
+#define KBC_TIMEOUT_SYS_FLAG 400
+
+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_DMP_KBD_FW_VERIFY_ERR);
+ 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_DMP_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);
+}
+
+static int kbc_wait_system_flag(void)
+{
+ /* wait keyboard controller ready by checking system flag
+ * (status port bit 2).
+ */
+ post_code(POST_DMP_KBD_CHK_READY);
+ u32 timeout;
+ for (timeout = KBC_TIMEOUT_SYS_FLAG;
+ timeout && ((inb(0x64) & 0x4) == 0); timeout--)
+ mdelay(1);
+
+ if (!timeout) {
+ printk(BIOS_WARNING, "Keyboard controller system flag timeout\n");
+ }
+ return !!timeout;
+}
+
+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_ROUTE, int_routing);
+
+ /* Setup S/B PCI Extend Interrupt routing table reg(0xb4). */
+ ext_int_routing |= irq_to_int_routing[CAN_IRQ] << CAN_IRQ_SHIFT;
+ ext_int_routing |= irq_to_int_routing[HDA_IRQ] << HDA_IRQ_SHIFT;
+ 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_EXT_PIRQ_ROUTE, 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 != 0) && (EHCII_IRQ != 0)) {
+ unsigned char irqs[4] = { OHCII_IRQ, EHCII_IRQ, 0, 0 };
+ pci_assign_irqs(0, 0xa, irqs);
+ }
+ if ((CONFIG_IDE_NATIVE_MODE != 0) && (PIDE_IRQ != 0)) {
+ /* IDE in native mode, setup PCI IRQ. */
+ unsigned char irqs[4] = { PIDE_IRQ, 0, 0, 0 };
+ pci_assign_irqs(0, 0xc, irqs);
+ }
+ if (CAN_IRQ) {
+ unsigned char irqs[4] = { CAN_IRQ, 0, 0, 0 };
+ pci_assign_irqs(0, 0x11, irqs);
+ }
+ if (HDA_IRQ) {
+ unsigned char irqs[4] = { HDA_IRQ, 0, 0, 0 };
+ pci_assign_irqs(0, 0xe, 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);
+
+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 void i2c_init(struct device *dev)
+{
+ u8 mapped_irq = irq_to_int_routing[I2C0_IRQ];
+ u32 cfg = 0;
+ cfg |= 1 << 31; // UE = enabled.
+ cfg |= (mapped_irq << 16); // IIRT0.
+ cfg |= CONFIG_I2C_BASE; // UIOA.
+ pci_write_config32(dev, SB_REG_II2CCR, cfg);
+}
+
+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 < 7; 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, unsigned index, u32 base, u32 size)
+{
+ struct resource *res;
+ res = new_resource(dev, index);
+ res->base = base;
+ res->size = size;
+ res->limit = 0xffffUL;
+ res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+}
+
+static void vortex86_sb_set_spi_flash_size(device_t dev, unsigned index, u32 flash_size)
+{
+ /* SPI flash is in topmost of 4G memory space */
+ struct resource *res;
+ res = new_resource(dev, index);
+ 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 legacy I/O */
+ vortex86_sb_set_io_resv(dev, 1, 0, 0x1000UL);
+
+ /* Reserve space for flash */
+ vortex86_sb_set_spi_flash_size(dev, 2, flash_size);
+
+ /* Reserve space for I2C */
+ vortex86_sb_set_io_resv(dev, 3, CONFIG_I2C_BASE, 8);
+}
+
+static void southbridge_init_func1(struct device *dev)
+{
+ /* Handle S/B function 1 PCI IRQ routing. (SPI1/MOTOR) */
+ u32 ext_int_routing2 = 0;
+ /* Setup S/B function 1 PCI Extend Interrupt routing table reg 2(0xb4). */
+ ext_int_routing2 |= irq_to_int_routing[SPI1_IRQ] << SPI1_IRQ_SHIFT;
+ ext_int_routing2 |= irq_to_int_routing[MOTOR_IRQ] << MOTOR_IRQ_SHIFT;
+ pci_write_config32(dev, SB1_REG_EXT_PIRQ_ROUTE2, ext_int_routing2);
+
+ /* Assign in-chip PCI device IRQs. */
+ if ((SPI1_IRQ != 0) || (MOTOR_IRQ != 0)) {
+ unsigned char irqs[4] = { MOTOR_IRQ, SPI1_IRQ, 0, 0 };
+ pci_assign_irqs(0, 0x10, irqs);
+ }
+}
+
+static void southbridge_init(struct device *dev)
+{
+ /* Check it is function 0 or 1. (Same Vendor/Device ID) */
+ if (get_pci_dev_func(dev) != 0) {
+ southbridge_init_func1(dev);
+ return;
+ }
+ upload_dmp_keyboard_firmware(dev);
+ vortex_sb_init(dev);
+ if (dev->device == 0x6011) {
+ ex_sb_gpio_init(dev);
+ ex_sb_uart_init(dev);
+ i2c_init(dev);
+ }
+ pci_routing_fixup(dev);
+
+ fix_cmos_rtc_time();
+ cmos_init(0);
+ /* Check keyboard controller ready. If timeout, reload firmware code
+ * and try again.
+ */
+ u32 retries = 10;
+ while (!kbc_wait_system_flag()) {
+ if (!retries) {
+ post_code(POST_DMP_KBD_IS_BAD);
+ die("The keyboard timeout occurred too often. "
+ "Your CPU is probably defect. "
+ "Contact your dealer to replace it\n");
+ }
+ upload_dmp_keyboard_firmware(dev);
+ retries--;
+ }
+ post_code(POST_DMP_KBD_IS_READY);
+ pc_keyboard_init(NO_AUX_DEVICE);
+}
+
+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_lpc_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/soc/dmp/vortex86ex/southbridge.h b/src/soc/dmp/vortex86ex/southbridge.h
new file mode 100644
index 0000000000..c2b91027ae
--- /dev/null
+++ b/src/soc/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.
+ */
+
+#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_ROUTE 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_EXT_PIRQ_ROUTE 0xb4
+#define SB_REG_OCDCR 0xbc
+#define SB_REG_IPFCR 0xc0
+#define SB_REG_FRWPR 0xc4
+#define SB_REG_STRAP 0xce
+#define SB_REG_II2CCR 0xd4
+
+#define SB1 PCI_DEV(0, 7, 1)
+#define SB1_REG_EXT_PIRQ_ROUTE2 0xb4
+
+#define SYSTEM_CTL_PORT 0x92
+
+#endif /* SOUTHBRIDGE_H */
diff --git a/src/soc/dmp/vortex86ex/xgi_oprom.c b/src/soc/dmp/vortex86ex/xgi_oprom.c
new file mode 100644
index 0000000000..b72157d37f
--- /dev/null
+++ b/src/soc/dmp/vortex86ex/xgi_oprom.c
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+/********************************************************************
+ * Change the vendor / device IDs to match the XGI Z9S VBIOS header.
+ ********************************************************************/
+#include <device/pci.h>
+u32 map_oprom_vendev(u32 vendev)
+{
+ u32 new_vendev = vendev;
+
+ switch (vendev) {
+ case 0x18ca0020:
+ new_vendev = 0x18ca0021;
+ break;
+ }
+
+ return new_vendev;
+}