Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/32075
Change subject: nb/intel/sandybridge: Introduce soc/iomap.h ......................................................................
nb/intel/sandybridge: Introduce soc/iomap.h
Defines the memory ranges used by the northbridge in a separate header. Include the new header and rename the defines to match the one found in soc/intel/common.
Change-Id: I93aa0e78ff52e46256debd26601600a96404509f Signed-off-by: Patrick Rudolph patrick.rudolph@9elements.com --- M src/northbridge/intel/sandybridge/Makefile.inc M src/northbridge/intel/sandybridge/acpi.c M src/northbridge/intel/sandybridge/early_init.c A src/northbridge/intel/sandybridge/include/soc/iomap.h M src/northbridge/intel/sandybridge/northbridge.c M src/northbridge/intel/sandybridge/raminit_common.c M src/northbridge/intel/sandybridge/raminit_mrc.c M src/northbridge/intel/sandybridge/sandybridge.h 8 files changed, 92 insertions(+), 54 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/75/32075/1
diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index 54a4057..c3d9079 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -15,6 +15,8 @@
ifeq ($(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE)$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE),y)
+CFLAGS_common += -Isrc/northbridge/intel/sandybridge/include + ramstage-y += ram_calc.c ramstage-y += northbridge.c ramstage-y += pcie.c diff --git a/src/northbridge/intel/sandybridge/acpi.c b/src/northbridge/intel/sandybridge/acpi.c index 4afb546..af2f37b 100644 --- a/src/northbridge/intel/sandybridge/acpi.c +++ b/src/northbridge/intel/sandybridge/acpi.c @@ -92,7 +92,8 @@ unsigned long tmp;
tmp = current; - current += acpi_create_dmar_drhd(current, 0, 0, IOMMU_BASE1); + current += acpi_create_dmar_drhd(current, 0, 0, + GFXVT_BASE_ADDRESS); current += acpi_create_dmar_ds_pci(current, 0, 2, 0); current += acpi_create_dmar_ds_pci(current, 0, 2, 1); acpi_dmar_drhd_fixup(tmp, current); @@ -107,8 +108,8 @@ }
const unsigned long tmp = current; - current += acpi_create_dmar_drhd(current, - DRHD_INCLUDE_PCI_ALL, 0, IOMMU_BASE2); + current += acpi_create_dmar_drhd(current, DRHD_INCLUDE_PCI_ALL, 0, + VTVC0_BASE_ADDRESS); current += acpi_create_dmar_ds_ioapic(current, 2, PCH_IOAPIC_PCI_BUS, PCH_IOAPIC_PCI_SLOT, 0); size_t i; diff --git a/src/northbridge/intel/sandybridge/early_init.c b/src/northbridge/intel/sandybridge/early_init.c index 5307a2c..2e0f087 100644 --- a/src/northbridge/intel/sandybridge/early_init.c +++ b/src/northbridge/intel/sandybridge/early_init.c @@ -35,20 +35,20 @@ return;
/* setup BARs */ - MCHBAR32(0x5404) = IOMMU_BASE1 >> 32; - MCHBAR32(0x5400) = IOMMU_BASE1 | 1; - MCHBAR32(0x5414) = IOMMU_BASE2 >> 32; - MCHBAR32(0x5410) = IOMMU_BASE2 | 1; + MCHBAR32(0x5404) = GFXVT_BASE_ADDRESS >> 32; + MCHBAR32(0x5400) = GFXVT_BASE_ADDRESS | 1; + MCHBAR32(0x5414) = VTVC0_BASE_ADDRESS >> 32; + MCHBAR32(0x5410) = VTVC0_BASE_ADDRESS | 1;
/* lock policies */ - write32((void *)(IOMMU_BASE1 + 0xff0), 0x80000000); + write32((void *)(GFXVT_BASE_ADDRESS + 0xff0), 0x80000000);
const struct device *const azalia = pcidev_on_root(0x1b, 0); if (azalia && azalia->enabled) { - write32((void *)(IOMMU_BASE2 + 0xff0), 0x20000000); - write32((void *)(IOMMU_BASE2 + 0xff0), 0xa0000000); + write32((void *)(VTVC0_BASE_ADDRESS + 0xff0), 0x20000000); + write32((void *)(VTVC0_BASE_ADDRESS + 0xff0), 0xa0000000); } else { - write32((void *)(IOMMU_BASE2 + 0xff0), 0x80000000); + write32((void *)(VTVC0_BASE_ADDRESS + 0xff0), 0x80000000); } }
@@ -67,12 +67,12 @@ { printk(BIOS_DEBUG, "Setting up static northbridge registers..."); /* Set up all hardcoded northbridge BARs */ - pci_write_config32(PCI_DEV(0, 0x00, 0), EPBAR, DEFAULT_EPBAR | 1); - pci_write_config32(PCI_DEV(0, 0x00, 0), EPBAR + 4, (0LL+DEFAULT_EPBAR) >> 32); - pci_write_config32(PCI_DEV(0, 0x00, 0), MCHBAR, (uintptr_t)DEFAULT_MCHBAR | 1); - pci_write_config32(PCI_DEV(0, 0x00, 0), MCHBAR + 4, (0LL+(uintptr_t)DEFAULT_MCHBAR) >> 32); - pci_write_config32(PCI_DEV(0, 0x00, 0), DMIBAR, (uintptr_t)DEFAULT_DMIBAR | 1); - pci_write_config32(PCI_DEV(0, 0x00, 0), DMIBAR + 4, (0LL+(uintptr_t)DEFAULT_DMIBAR) >> 32); + pci_write_config32(PCI_DEV(0, 0x00, 0), EPBAR, EP_BASE_ADDRESS | 1); + pci_write_config32(PCI_DEV(0, 0x00, 0), EPBAR + 4, EP_BASE_ADDRESS >> 32); + pci_write_config32(PCI_DEV(0, 0x00, 0), MCHBAR, MCH_BASE_ADDRESS | 1); + pci_write_config32(PCI_DEV(0, 0x00, 0), MCHBAR + 4, MCH_BASE_ADDRESS >> 32); + pci_write_config32(PCI_DEV(0, 0x00, 0), DMIBAR, DMI_BASE_ADDRESS | 1); + pci_write_config32(PCI_DEV(0, 0x00, 0), DMIBAR + 4, DMI_BASE_ADDRESS >> 32);
printk(BIOS_DEBUG, " done\n"); } diff --git a/src/northbridge/intel/sandybridge/include/soc/iomap.h b/src/northbridge/intel/sandybridge/include/soc/iomap.h new file mode 100644 index 0000000..75fd9d9 --- /dev/null +++ b/src/northbridge/intel/sandybridge/include/soc/iomap.h @@ -0,0 +1,51 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2018 Intel Corporation. + * + * 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_SANDYBRIDGE_IOMAP_H_ +#define _SOC_SANDYBRIDGE_IOMAP_H_ + +/* + * Memory-mapped I/O registers. + */ +#define MCFG_BASE_ADDRESS CONFIG_MMCONF_BASE_ADDRESS +#define MCFG_BASE_SIZE 0x4000000 + +/* Intel Enhanced Debug region must be 4MB */ + +#define IED_SIZE CONFIG_IED_REGION_SIZE + +#define ILB_BASE_ADDRESS 0xfed08000ULL +#define ILB_BASE_SIZE 0x400 + +#define DMI_BASE_ADDRESS 0xfed18000ULL +#define DMI_BASE_SIZE 0x1000 + +#define MCH_BASE_ADDRESS 0xfed10000ULL +#define MCH_BASE_SIZE 0x4000 + +#define EP_BASE_ADDRESS 0xfed19000ULL +#define EP_BASE_SIZE 0x1000 + +#define GFXVT_BASE_ADDRESS 0xfed90000ULL +#define GFXVT_BASE_SIZE 0x1000 + +#define VTVC0_BASE_ADDRESS 0xfed91000ULL +#define VTVC0_BASE_SIZE 0x1000 + +#define TPM_BASE_ADDRESS 0xfed40000ULL +#define TPM_BASE_SIZE 0x5000 + + +#endif diff --git a/src/northbridge/intel/sandybridge/northbridge.c b/src/northbridge/intel/sandybridge/northbridge.c index 5aa06c8..71dea62 100644 --- a/src/northbridge/intel/sandybridge/northbridge.c +++ b/src/northbridge/intel/sandybridge/northbridge.c @@ -112,8 +112,8 @@ /* Reserve IOMMU BARs */ const u32 capid0_a = pci_read_config32(dev, 0xe4); if (!(capid0_a & (1 << 23))) { - mmio_resource(dev, index++, IOMMU_BASE1 >> 10, 4); - mmio_resource(dev, index++, IOMMU_BASE2 >> 10, 4); + mmio_resource(dev, index++, GFXVT_BASE_ADDRESS / KiB, 4); + mmio_resource(dev, index++, VTVC0_BASE_ADDRESS / KiB, 4); } }
diff --git a/src/northbridge/intel/sandybridge/raminit_common.c b/src/northbridge/intel/sandybridge/raminit_common.c index 55df03b..72ae5b0 100644 --- a/src/northbridge/intel/sandybridge/raminit_common.c +++ b/src/northbridge/intel/sandybridge/raminit_common.c @@ -41,23 +41,23 @@ * Channel X = [0, 1] * Command queue index Y = [0, 1, 2, 3] * - * DEFAULT_MCHBAR + 0x4220 + 0x400 * X + 4 * Y: command io register + * MCH_BASE_ADDRESS + 0x4220 + 0x400 * X + 4 * Y: command io register * Controls the DRAM command signals * Bit 0: !RAS * Bit 1: !CAS * Bit 2: !WE * - * DEFAULT_MCHBAR + 0x4200 + 0x400 * X + 4 * Y: addr bankslot io register + * MCH_BASE_ADDRESS + 0x4200 + 0x400 * X + 4 * Y: addr bankslot io register * Controls the address, bank address and slotrank signals * Bit 0-15 : Address * Bit 20-22: Bank Address * Bit 24-25: slotrank * - * DEFAULT_MCHBAR + 0x4230 + 0x400 * X + 4 * Y: idle register + * MCH_BASE_ADDRESS + 0x4230 + 0x400 * X + 4 * Y: idle register * Controls the idle time after issuing this DRAM command * Bit 16-32: number of clock-cylces to idle * - * DEFAULT_MCHBAR + 0x4284 + 0x400 * channel: execute command queue + * MCH_BASE_ADDRESS + 0x4284 + 0x400 * channel: execute command queue * Starts to execute all queued commands * Bit 0 : start DRAM command execution * Bit 18-19 : number of queued commands - 1 diff --git a/src/northbridge/intel/sandybridge/raminit_mrc.c b/src/northbridge/intel/sandybridge/raminit_mrc.c index c544a74..2382084 100644 --- a/src/northbridge/intel/sandybridge/raminit_mrc.c +++ b/src/northbridge/intel/sandybridge/raminit_mrc.c @@ -277,10 +277,10 @@
static void northbridge_fill_pei_data(struct pei_data *pei_data) { - pei_data->mchbar = (uintptr_t)DEFAULT_MCHBAR; - pei_data->dmibar = (uintptr_t)DEFAULT_DMIBAR; - pei_data->epbar = DEFAULT_EPBAR; - pei_data->pciexbar = CONFIG_MMCONF_BASE_ADDRESS; + pei_data->mchbar = MCH_BASE_ADDRESS; + pei_data->dmibar = DMI_BASE_ADDRESS; + pei_data->epbar = EP_BASE_ADDRESS; + pei_data->pciexbar = MCFG_BASE_ADDRESS; pei_data->smbusbar = SMBUS_IO_BASE; pei_data->wdbbar = 0x4000000; pei_data->wdbsize = 0x1000; diff --git a/src/northbridge/intel/sandybridge/sandybridge.h b/src/northbridge/intel/sandybridge/sandybridge.h index d7de843..dc9f889 100644 --- a/src/northbridge/intel/sandybridge/sandybridge.h +++ b/src/northbridge/intel/sandybridge/sandybridge.h @@ -17,6 +17,8 @@ #ifndef __NORTHBRIDGE_INTEL_SANDYBRIDGE_SANDYBRIDGE_H__ #define __NORTHBRIDGE_INTEL_SANDYBRIDGE_SANDYBRIDGE_H__
+#include <northbridge/intel/sandybridge/include/soc/iomap.h> + /* Device ID for SandyBridge and IvyBridge */ #define BASE_REV_SNB 0x00 #define BASE_REV_IVB 0x50 @@ -34,24 +36,6 @@ #define IVB_STEP_K0 (BASE_REV_IVB + 5) #define IVB_STEP_D0 (BASE_REV_IVB + 6)
-/* Intel Enhanced Debug region must be 4MB */ - -#define IED_SIZE CONFIG_IED_REGION_SIZE - -/* Northbridge BARs */ -#ifndef __ACPI__ -#define DEFAULT_MCHBAR ((u8 *)0xfed10000) /* 16 KB */ -#define DEFAULT_DMIBAR ((u8 *)0xfed18000) /* 4 KB */ -#else -#define DEFAULT_MCHBAR 0xfed10000 /* 16 KB */ -#define DEFAULT_DMIBAR 0xfed18000 /* 4 KB */ -#endif -#define DEFAULT_EPBAR 0xfed19000 /* 4 KB */ -#define DEFAULT_RCBABASE ((u8 *)0xfed1c000) - -#define IOMMU_BASE1 0xfed90000ULL -#define IOMMU_BASE2 0xfed91000ULL - /* Everything below this line is ignored in the DSDT */ #ifndef __ACPI__ #include <cpu/intel/model_206ax/model_206ax.h> @@ -118,9 +102,9 @@ * MCHBAR */
-#define MCHBAR8(x) (*((volatile u8 *)(DEFAULT_MCHBAR + (x)))) -#define MCHBAR16(x) (*((volatile u16 *)(DEFAULT_MCHBAR + (x)))) -#define MCHBAR32(x) (*((volatile u32 *)(DEFAULT_MCHBAR + (x)))) +#define MCHBAR8(x) (*((volatile u8 *)((uintptr_t)MCH_BASE_ADDRESS + (x)))) +#define MCHBAR16(x) (*((volatile u16 *)((uintptr_t)MCH_BASE_ADDRESS + (x)))) +#define MCHBAR32(x) (*((volatile u32 *)((uintptr_t)MCH_BASE_ADDRESS + (x)))) #define MCHBAR32_OR(x, or) (MCHBAR32(x) = (MCHBAR32(x) | (or))) #define MCHBAR32_AND(x, and) (MCHBAR32(x) = (MCHBAR32(x) & (and))) #define MCHBAR32_AND_OR(x, and, or) \ @@ -133,9 +117,9 @@ * EPBAR - Egress Port Root Complex Register Block */
-#define EPBAR8(x) (*((volatile u8 *)(DEFAULT_EPBAR + (x)))) -#define EPBAR16(x) (*((volatile u16 *)(DEFAULT_EPBAR + (x)))) -#define EPBAR32(x) (*((volatile u32 *)(DEFAULT_EPBAR + (x)))) +#define EPBAR8(x) (*((volatile u8 *)((uintptr_t)EP_BASE_ADDRESS + (x)))) +#define EPBAR16(x) (*((volatile u16 *)((uintptr_t)EP_BASE_ADDRESS + (x)))) +#define EPBAR32(x) (*((volatile u32 *)((uintptr_t)EP_BASE_ADDRESS + (x))))
#define EPPVCCAP1 0x004 /* 32bit */ #define EPPVCCAP2 0x008 /* 32bit */ @@ -164,9 +148,9 @@ * DMIBAR */
-#define DMIBAR8(x) (*((volatile u8 *)(DEFAULT_DMIBAR + (x)))) -#define DMIBAR16(x) (*((volatile u16 *)(DEFAULT_DMIBAR + (x)))) -#define DMIBAR32(x) (*((volatile u32 *)(DEFAULT_DMIBAR + (x)))) +#define DMIBAR8(x) (*((volatile u8 *)((uintptr_t)DMI_BASE_ADDRESS + (x)))) +#define DMIBAR16(x) (*((volatile u16 *)((uintptr_t)DMI_BASE_ADDRESS + (x)))) +#define DMIBAR32(x) (*((volatile u32 *)((uintptr_t)DMI_BASE_ADDRESS + (x))))
#define DMIVCECH 0x000 /* 32bit */ #define DMIPVCCAP1 0x004 /* 32bit */
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32075 )
Change subject: nb/intel/sandybridge: Introduce soc/iomap.h ......................................................................
Patch Set 1:
(3 comments)
https://review.coreboot.org/#/c/32075/1/src/northbridge/intel/sandybridge/ea... File src/northbridge/intel/sandybridge/early_init.c:
https://review.coreboot.org/#/c/32075/1/src/northbridge/intel/sandybridge/ea... PS1, Line 71: pci_write_config32(PCI_DEV(0, 0x00, 0), EPBAR + 4, EP_BASE_ADDRESS >> 32); line over 80 characters
https://review.coreboot.org/#/c/32075/1/src/northbridge/intel/sandybridge/ea... PS1, Line 73: pci_write_config32(PCI_DEV(0, 0x00, 0), MCHBAR + 4, MCH_BASE_ADDRESS >> 32); line over 80 characters
https://review.coreboot.org/#/c/32075/1/src/northbridge/intel/sandybridge/ea... PS1, Line 75: pci_write_config32(PCI_DEV(0, 0x00, 0), DMIBAR + 4, DMI_BASE_ADDRESS >> 32); line over 80 characters
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32075 )
Change subject: nb/intel/sandybridge: Introduce soc/iomap.h ......................................................................
Patch Set 2:
(3 comments)
https://review.coreboot.org/#/c/32075/2/src/northbridge/intel/sandybridge/ea... File src/northbridge/intel/sandybridge/early_init.c:
https://review.coreboot.org/#/c/32075/2/src/northbridge/intel/sandybridge/ea... PS2, Line 71: pci_write_config32(PCI_DEV(0, 0x00, 0), EPBAR + 4, EP_BASE_ADDRESS >> 32); line over 80 characters
https://review.coreboot.org/#/c/32075/2/src/northbridge/intel/sandybridge/ea... PS2, Line 73: pci_write_config32(PCI_DEV(0, 0x00, 0), MCHBAR + 4, MCH_BASE_ADDRESS >> 32); line over 80 characters
https://review.coreboot.org/#/c/32075/2/src/northbridge/intel/sandybridge/ea... PS2, Line 75: pci_write_config32(PCI_DEV(0, 0x00, 0), DMIBAR + 4, DMI_BASE_ADDRESS >> 32); line over 80 characters
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32075 )
Change subject: nb/intel/sandybridge: Introduce soc/iomap.h ......................................................................
Patch Set 3:
(3 comments)
https://review.coreboot.org/#/c/32075/3/src/northbridge/intel/sandybridge/ea... File src/northbridge/intel/sandybridge/early_init.c:
https://review.coreboot.org/#/c/32075/3/src/northbridge/intel/sandybridge/ea... PS3, Line 71: pci_write_config32(PCI_DEV(0, 0x00, 0), EPBAR + 4, EP_BASE_ADDRESS >> 32); line over 80 characters
https://review.coreboot.org/#/c/32075/3/src/northbridge/intel/sandybridge/ea... PS3, Line 73: pci_write_config32(PCI_DEV(0, 0x00, 0), MCHBAR + 4, MCH_BASE_ADDRESS >> 32); line over 80 characters
https://review.coreboot.org/#/c/32075/3/src/northbridge/intel/sandybridge/ea... PS3, Line 75: pci_write_config32(PCI_DEV(0, 0x00, 0), DMIBAR + 4, DMI_BASE_ADDRESS >> 32); line over 80 characters
Hello Patrick Rudolph, build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/32075
to look at the new patch set (#4).
Change subject: nb/intel/sandybridge: Introduce soc/iomap.h ......................................................................
nb/intel/sandybridge: Introduce soc/iomap.h
Defines the memory ranges used by the northbridge in a separate header. Include the new header and rename the defines to match the one found in soc/intel/common.
Change-Id: I93aa0e78ff52e46256debd26601600a96404509f Signed-off-by: Patrick Rudolph patrick.rudolph@9elements.com --- M src/northbridge/intel/sandybridge/Makefile.inc M src/northbridge/intel/sandybridge/acpi.c M src/northbridge/intel/sandybridge/early_init.c A src/northbridge/intel/sandybridge/include/soc/iomap.h M src/northbridge/intel/sandybridge/northbridge.c M src/northbridge/intel/sandybridge/raminit_common.c M src/northbridge/intel/sandybridge/raminit_mrc.c M src/northbridge/intel/sandybridge/sandybridge.h 8 files changed, 95 insertions(+), 54 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/75/32075/4
Hello Patrick Rudolph, build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/32075
to look at the new patch set (#5).
Change subject: nb/intel/sandybridge: Introduce soc/iomap.h ......................................................................
nb/intel/sandybridge: Introduce soc/iomap.h
Defines the memory ranges used by the northbridge in a separate header. Include the new header and rename the defines to match the one found in soc/intel/common.
Tested on Lenovo T520 (Intel Sandy Bridge). Still boots to OS, no errors visible in dmesg.
Change-Id: I93aa0e78ff52e46256debd26601600a96404509f Signed-off-by: Patrick Rudolph patrick.rudolph@9elements.com --- M src/northbridge/intel/sandybridge/Makefile.inc M src/northbridge/intel/sandybridge/acpi.c M src/northbridge/intel/sandybridge/early_init.c A src/northbridge/intel/sandybridge/include/soc/iomap.h M src/northbridge/intel/sandybridge/northbridge.c M src/northbridge/intel/sandybridge/raminit_common.c M src/northbridge/intel/sandybridge/raminit_mrc.c M src/northbridge/intel/sandybridge/sandybridge.h 8 files changed, 95 insertions(+), 54 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/75/32075/5
Felix Held has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32075 )
Change subject: nb/intel/sandybridge: Introduce soc/iomap.h ......................................................................
Patch Set 5: Code-Review+1
Patrick Georgi has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32075 )
Change subject: nb/intel/sandybridge: Introduce soc/iomap.h ......................................................................
Patch Set 5: Code-Review+2
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32075 )
Change subject: nb/intel/sandybridge: Introduce soc/iomap.h ......................................................................
Patch Set 5:
(2 comments)
https://review.coreboot.org/c/coreboot/+/32075/5/src/northbridge/intel/sandy... File src/northbridge/intel/sandybridge/include/soc/iomap.h:
PS5: Please use SPDX.
Also, could we replace "soc" with "platform" please? This is not a SoC at all...
https://review.coreboot.org/c/coreboot/+/32075/5/src/northbridge/intel/sandy... PS5, Line 27: Missing a tab?
Martin L Roth has abandoned this change. ( https://review.coreboot.org/c/coreboot/+/32075?usp=email )
Change subject: nb/intel/sandybridge: Introduce soc/iomap.h ......................................................................
Abandoned
This patch has not been touched in over 12 months. Anyone who wants to take over work on this patch, please feel free to restore it and do any work needed to get it merged. If you create a new patch based on this work, please credit the original author.