diff options
Diffstat (limited to 'resources/libreboot/patch/kgpe-d16/0111-southbridge-amd-sr5650-Add-IOMMU-support.patch')
-rw-r--r-- | resources/libreboot/patch/kgpe-d16/0111-southbridge-amd-sr5650-Add-IOMMU-support.patch | 711 |
1 files changed, 711 insertions, 0 deletions
diff --git a/resources/libreboot/patch/kgpe-d16/0111-southbridge-amd-sr5650-Add-IOMMU-support.patch b/resources/libreboot/patch/kgpe-d16/0111-southbridge-amd-sr5650-Add-IOMMU-support.patch new file mode 100644 index 00000000..54f04d08 --- /dev/null +++ b/resources/libreboot/patch/kgpe-d16/0111-southbridge-amd-sr5650-Add-IOMMU-support.patch @@ -0,0 +1,711 @@ +From 274c926921dc0f24e15e09beed752f4927220fc6 Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <tpearson@raptorengineeringinc.com> +Date: Tue, 11 Aug 2015 17:49:06 -0500 +Subject: [PATCH 111/139] southbridge/amd/sr5650: Add IOMMU support + +Change-Id: I2083d0c5653515c27d4626c62a6499b850f7547b +Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com> +--- + src/include/device/pci_ids.h | 1 + + src/southbridge/amd/sr5650/cmn.h | 3 + + src/southbridge/amd/sr5650/early_setup.c | 50 +++- + src/southbridge/amd/sr5650/sr5650.c | 479 ++++++++++++++++++++++++++++++- + src/southbridge/amd/sr5650/sr5650.h | 14 + + 5 files changed, 537 insertions(+), 10 deletions(-) + +diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h +index 664ac49..72f1ece 100644 +--- a/src/include/device/pci_ids.h ++++ b/src/include/device/pci_ids.h +@@ -429,6 +429,7 @@ + #define PCI_DEVICE_ID_AMD_SR5650_PCIE_DEV12 0x5A20 + #define PCI_DEVICE_ID_AMD_SR5650_PCIE_DEV13 0x5A1E + #define PCI_DEVICE_ID_AMD_SR5650_PCIE_DEV8 0x5A21 ++#define PCI_DEVICE_ID_AMD_SR5650_IOMMU 0x5A23 + + #define PCI_DEVICE_ID_AMD_CZ_HDA 0x157A + #define PCI_DEVICE_ID_AMD_CZ_LPC 0x790E +diff --git a/src/southbridge/amd/sr5650/cmn.h b/src/southbridge/amd/sr5650/cmn.h +index 23d25d5..a54bdc5 100644 +--- a/src/southbridge/amd/sr5650/cmn.h ++++ b/src/southbridge/amd/sr5650/cmn.h +@@ -2,6 +2,7 @@ + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Advanced Micro Devices, Inc. ++ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering + * + * 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 +@@ -26,6 +27,8 @@ + #define NBHTIU_INDEX 0x94 /* Note: It is different with RS690, whose HTIU index is 0xA8 */ + #define NBMC_INDEX 0xE8 + #define NBPCIE_INDEX 0xE0 ++#define L2CFG_INDEX 0xF0 ++#define L1CFG_INDEX 0xF8 + #define EXT_CONF_BASE_ADDRESS CONFIG_MMCONF_BASE_ADDRESS + #define TEMP_MMIO_BASE_ADDRESS 0xC0000000 + +diff --git a/src/southbridge/amd/sr5650/early_setup.c b/src/southbridge/amd/sr5650/early_setup.c +index 62b0dab..e7cca06 100644 +--- a/src/southbridge/amd/sr5650/early_setup.c ++++ b/src/southbridge/amd/sr5650/early_setup.c +@@ -24,6 +24,8 @@ + #include <arch/io.h> + #include <console/console.h> + #include <cpu/x86/msr.h> ++#include <option.h> ++#include <reset.h> + #include "sr5650.h" + #include "cmn.h" + +@@ -271,6 +273,34 @@ void sr5650_htinit(void) + /* HT Buffer Allocation for Ganged Links!!! */ + #endif /* CONFIG_NORTHBRIDGE_AMD_AMDFAM10 || CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY10 */ + } ++ ++} ++ ++/* Must be run immediately after HT setup is complete and first warm reset has occurred (if applicable) ++ * Attempting to switch the NB into isochronous mode before the CPUs have engaged isochronous mode ++ * will cause a system hard lockup... ++ */ ++void sr5650_htinit_dect_and_enable_isochronous_link(void) ++{ ++ device_t sr5650_f0; ++ unsigned char iommu; ++ ++ sr5650_f0 = PCI_DEV(0, 0, 0); ++ ++ iommu = 1; ++ get_option(&iommu, "iommu"); ++ ++ if (iommu) { ++ /* Enable isochronous mode */ ++ set_nbcfg_enable_bits(sr5650_f0, 0xc8, 1 << 12, 1 << 12); ++ ++ /* Apply pending changes */ ++ if (!((pci_read_config32(sr5650_f0, 0xc8) >> 12) & 0x1)) { ++ printk(BIOS_INFO, "...WARM RESET...\n\n\n"); ++ soft_reset(); ++ die("After soft_reset_x - shouldn't see this message!!!\n"); ++ } ++ } + } + + #if CONFIG_NORTHBRIDGE_AMD_AMDFAM10 || CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY10 /* save some spaces */ +@@ -335,8 +365,21 @@ static void sr5650_por_pcicfg_init(device_t nb_dev) + *****************************************/ + static void sr5650_por_misc_index_init(device_t nb_dev) + { +- /* disable IOMMU */ +- set_nbmisc_enable_bits(nb_dev, 0x75, 0x1, 0x0); ++ unsigned char iommu; ++ ++ iommu = 1; ++ get_option(&iommu, "iommu"); ++ ++ if (iommu) { ++ /* enable IOMMU */ ++ printk(BIOS_DEBUG, "Enabling IOMMU\n"); ++ set_nbmisc_enable_bits(nb_dev, 0x75, 0x1, 0x1); ++ } else { ++ /* disable IOMMU */ ++ printk(BIOS_DEBUG, "Disabling IOMMU\n"); ++ set_nbmisc_enable_bits(nb_dev, 0x75, 0x1, 0x0); ++ } ++ + /* NBMISCIND:0x75[29]= 1 Device ID for hotplug and PME message */ + set_nbmisc_enable_bits(nb_dev, 0x75, 1 << 29, 1 << 29); + set_nbmisc_enable_bits(nb_dev, 0x75, 1 << 9, 1 << 9); /* no doc reference, comply with BTS */ +@@ -374,10 +417,11 @@ static void sr5650_por_misc_index_init(device_t nb_dev) + * HIDE_NB_AGP_CAP ([0], default=1)HIDE + * HIDE_P2P_AGP_CAP ([1], default=1)HIDE + * HIDE_NB_GART_BAR ([2], default=1)HIDE ++ * HIDE_MMCFG_BAR ([3], default=1)SHOW + * AGPMODE30 ([4], default=0)DISABLE + * AGP30ENCHANCED ([5], default=0)DISABLE + * HIDE_AGP_CAP ([8], default=1)ENABLE */ +- set_nbmisc_enable_bits(nb_dev, 0x00, 0x0000FFFF, 0 << 0 | 1 << 1 | 1 << 2 | 0 << 6); ++ set_nbmisc_enable_bits(nb_dev, 0x00, 0x0000FFFF, 0 << 0 | 1 << 1 | 1 << 2 | 0 << 3 | 0 << 6); + + /* IOC_LAT_PERF_CNTR_CNTL */ + set_nbmisc_enable_bits(nb_dev, 0x30, 0xFF, 0x00); +diff --git a/src/southbridge/amd/sr5650/sr5650.c b/src/southbridge/amd/sr5650/sr5650.c +index 6db1eb1..b296c47 100644 +--- a/src/southbridge/amd/sr5650/sr5650.c ++++ b/src/southbridge/amd/sr5650/sr5650.c +@@ -26,7 +26,9 @@ + #include <device/pci_ops.h> + #include <cpu/x86/msr.h> + #include <cpu/amd/mtrr.h> ++#include <stdlib.h> + #include <delay.h> ++#include <option.h> + #include "sr5650.h" + #include "cmn.h" + +@@ -87,6 +89,26 @@ void nbpcie_ind_write_index(device_t nb_dev, u32 index, u32 data) + nb_write_index((nb_dev), NBPCIE_INDEX, (index), (data)); + } + ++uint32_t l2cfg_ind_read_index(device_t nb_dev, uint32_t index) ++{ ++ return nb_read_index((nb_dev), L2CFG_INDEX, (index)); ++} ++ ++void l2cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data) ++{ ++ nb_write_index((nb_dev), L2CFG_INDEX | (0x1 << 8), (index), (data)); ++} ++ ++uint32_t l1cfg_ind_read_index(device_t nb_dev, uint32_t index) ++{ ++ return nb_read_index((nb_dev), L1CFG_INDEX, (index)); ++} ++ ++void l1cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data) ++{ ++ nb_write_index((nb_dev), L1CFG_INDEX | (0x1 << 31), (index), (data)); ++} ++ + /*********************************************************** + * To access bar3 we need to program PCI MMIO 7 in K8. + * in_out: +@@ -286,6 +308,240 @@ u32 get_vid_did(device_t dev) + return pci_read_config32(dev, 0); + } + ++void detect_and_enable_iommu(device_t iommu_dev) { ++ uint32_t dword; ++ uint8_t l1_target; ++ unsigned char iommu; ++ void * mmio_base; ++ ++ iommu = 1; ++ get_option(&iommu, "iommu"); ++ ++ if (iommu) { ++ printk(BIOS_DEBUG, "Initializing IOMMU\n"); ++ ++ device_t nb_dev = dev_find_slot(0, PCI_DEVFN(0, 0)); ++ ++ if (!nb_dev) { ++ printk(BIOS_WARNING, "Unable to find SR5690 device! IOMMU NOT initialized\n"); ++ return; ++ } ++ ++ mmio_base = (void*)(pci_read_config32(iommu_dev, 0x44) & 0xffffc000); ++ ++ // if (get_nb_rev(nb_dev) == REV_SR5650_A11) { ++ // dword = pci_read_config32(iommu_dev, 0x6c); ++ // dword &= ~(0x1 << 8); ++ // pci_write_config32(iommu_dev, 0x6c, dword); ++ // } ++ ++ dword = pci_read_config32(iommu_dev, 0x50); ++ dword &= ~(0x1 << 22); ++ pci_write_config32(iommu_dev, 0x50, dword); ++ ++ dword = pci_read_config32(iommu_dev, 0x44); ++ dword |= 0x1; ++ pci_write_config32(iommu_dev, 0x44, dword); ++ ++ write32((void*)(mmio_base + 0x8), 0x0); ++ write32((void*)(mmio_base + 0xc), 0x08000000); ++ write32((void*)(mmio_base + 0x10), 0x0); ++ write32((void*)(mmio_base + 0x2008), 0x0); ++ write32((void*)(mmio_base + 0x2010), 0x0); ++ ++ /* IOMMU L1 initialization */ ++ for (l1_target = 0; l1_target < 6; l1_target++) { ++ dword = l1cfg_ind_read_index(nb_dev, (l1_target << 16) + 0xc); ++ dword |= (0x7 << 28); ++ l1cfg_ind_write_index(nb_dev, (l1_target << 16) + 0xc, dword); ++ ++ dword = l1cfg_ind_read_index(nb_dev, (l1_target << 16) + 0x7); ++ dword |= (0x1 << 5); ++ l1cfg_ind_write_index(nb_dev, (l1_target << 16) + 0x7, dword); ++ } ++ ++ /* IOMMU L2 initialization */ ++ dword = l2cfg_ind_read_index(nb_dev, 0xc); ++ dword |= (0x7 << 29); ++ l2cfg_ind_write_index(nb_dev, 0xc, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x10); ++ dword &= ~(0x3 << 8); ++ dword |= (0x2 << 8); ++ l2cfg_ind_write_index(nb_dev, 0x10, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x14); ++ dword &= ~(0x3 << 8); ++ dword |= (0x2 << 8); ++ l2cfg_ind_write_index(nb_dev, 0x14, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x18); ++ dword &= ~(0x3 << 8); ++ dword |= (0x2 << 8); ++ l2cfg_ind_write_index(nb_dev, 0x18, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x1c); ++ dword &= ~(0x3 << 8); ++ dword |= (0x2 << 8); ++ l2cfg_ind_write_index(nb_dev, 0x1c, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x50); ++ dword &= ~(0x3 << 8); ++ dword |= (0x2 << 8); ++ l2cfg_ind_write_index(nb_dev, 0x50, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x10); ++ dword |= (0x1 << 4); ++ l2cfg_ind_write_index(nb_dev, 0x10, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x14); ++ dword |= (0x1 << 4); ++ l2cfg_ind_write_index(nb_dev, 0x14, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x18); ++ dword |= (0x1 << 4); ++ l2cfg_ind_write_index(nb_dev, 0x18, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x1c); ++ dword |= (0x1 << 4); ++ l2cfg_ind_write_index(nb_dev, 0x1c, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x50); ++ dword |= (0x1 << 4); ++ l2cfg_ind_write_index(nb_dev, 0x50, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x6); ++ dword |= (0x1 << 7); ++ l2cfg_ind_write_index(nb_dev, 0x6, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x44); ++ dword |= (0x1 << 0); ++ l2cfg_ind_write_index(nb_dev, 0x44, dword); ++ ++// if (get_nb_rev(nb_dev) == REV_SR5650_A21) { ++ dword = l2cfg_ind_read_index(nb_dev, 0x7); ++ dword |= (0x1 << 1); ++ l2cfg_ind_write_index(nb_dev, 0x7, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x44); ++ dword |= (0x1 << 1); ++ l2cfg_ind_write_index(nb_dev, 0x44, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x7); ++ dword |= (0x1 << 2); ++ l2cfg_ind_write_index(nb_dev, 0x7, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x7); ++ dword |= (0x1 << 3); ++ l2cfg_ind_write_index(nb_dev, 0x7, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x44); ++ dword |= (0x1 << 3); ++ l2cfg_ind_write_index(nb_dev, 0x44, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x7); ++ dword |= (0x1 << 4); ++ l2cfg_ind_write_index(nb_dev, 0x7, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x6); ++ dword |= (0x1 << 5); ++ l2cfg_ind_write_index(nb_dev, 0x6, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x6); ++ dword |= (0x1 << 6); ++ l2cfg_ind_write_index(nb_dev, 0x6, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x7); ++ dword |= (0x1 << 5); ++ l2cfg_ind_write_index(nb_dev, 0x7, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x44); ++ dword |= (0x1 << 4); ++ l2cfg_ind_write_index(nb_dev, 0x44, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x7); ++ dword |= (0x1 << 6); ++ l2cfg_ind_write_index(nb_dev, 0x7, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x7); ++ dword |= (0x1 << 7); ++ l2cfg_ind_write_index(nb_dev, 0x7, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x6); ++ dword |= (0x1 << 8); ++ l2cfg_ind_write_index(nb_dev, 0x6, dword); ++// } ++ ++ l2cfg_ind_write_index(nb_dev, 0x52, 0xf0000002); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x80); ++ dword |= (0x1 << 0); ++ l2cfg_ind_write_index(nb_dev, 0x80, dword); ++ ++ dword = l2cfg_ind_read_index(nb_dev, 0x30); ++ dword |= (0x1 << 0); ++ l2cfg_ind_write_index(nb_dev, 0x30, dword); ++ } ++} ++ ++void sr5650_iommu_read_resources(device_t dev) ++{ ++ unsigned char iommu; ++ struct resource *res; ++ ++ iommu = 1; ++ get_option(&iommu, "iommu"); ++ ++ /* Get the normal pci resources of this device */ ++ pci_dev_read_resources(dev); ++ ++ if (iommu) { ++ /* Request MMIO range allocation */ ++ res = new_resource(dev, 0x44); /* IOMMU */ ++ res->base = 0x0; ++ res->size = 0x4000; ++ res->limit = 0xFFFFFFFFUL; /* res->base + res->size -1; */ ++ res->align = 14; /* 16k alignment */ ++ res->gran = 14; ++ res->flags = IORESOURCE_MEM | IORESOURCE_RESERVE; ++ } ++ ++ compact_resources(dev); ++} ++ ++void sr5650_iommu_set_resources(device_t dev) ++{ ++ unsigned char iommu; ++ struct resource *res; ++ ++ iommu = 1; ++ get_option(&iommu, "iommu"); ++ ++ /* Get the normal pci resources of this device */ ++ pci_dev_read_resources(dev); ++ ++ if (iommu) { ++ /* Get the allocated range */ ++ res = find_resource(dev, 0x44); ++ ++ if (res->base == 0) { ++ printk(BIOS_WARNING, "Unable to allocate MMIO range to IOMMU\n"); ++ } ++ ++ /* Assign the range to hardware */ ++ pci_write_config32(dev, 0x44, res->base & 0xffffc000); ++ pci_write_config32(dev, 0x48, 0x0); ++ } ++ ++ /* Run standard resource set routine */ ++ pci_dev_set_resources(dev); ++} ++ ++void sr5650_iommu_enable_resources(device_t dev) ++{ ++ detect_and_enable_iommu(dev); ++} ++ + void sr5650_nb_pci_table(device_t nb_dev) + { /* NBPOR_InitPOR function. */ + u8 temp8; +@@ -365,13 +621,23 @@ void sr5650_enable(device_t dev) + dev_ind = dev->path.pci.devfn >> 3; + switch (dev_ind) { + case 0: /* bus0, dev0, fun0; */ +- printk(BIOS_INFO, "Bus-0, Dev-0, Fun-0.\n"); +- enable_pcie_bar3(nb_dev); /* PCIEMiscInit */ +- +- config_gpp_core(nb_dev, sb_dev); +- sr5650_gpp_sb_init(nb_dev, sb_dev, 8); +- +- sr5650_nb_pci_table(nb_dev); ++ switch (dev->path.pci.devfn & 0x7) { ++ case 0: ++ printk(BIOS_INFO, "Bus-0, Dev-0, Fun-0.\n"); ++ enable_pcie_bar3(nb_dev); /* PCIEMiscInit */ ++ ++ config_gpp_core(nb_dev, sb_dev); ++ sr5650_gpp_sb_init(nb_dev, sb_dev, 8); ++ ++ sr5650_nb_pci_table(nb_dev); ++ break; ++ case 1: ++ printk(BIOS_INFO, "Bus-0, Dev-0, Fun-1.\n"); ++ break; ++ case 2: ++ printk(BIOS_INFO, "Bus-0, Dev-0, Fun-2.\n"); ++ break; ++ } + break; + + case 2: /* bus0, dev2,3 GPP1 */ +@@ -438,6 +704,205 @@ void sr5650_enable(device_t dev) + } + } + ++static void add_ivrs_device_entries(struct device *parent, struct device *dev, int depth, int linknum, int8_t *root_level, unsigned long *current, uint16_t *length) ++{ ++ uint8_t *p; ++ struct device *sibling; ++ struct bus *link; ++ ++ if (!root_level) { ++ root_level = malloc(sizeof(int8_t)); ++ *root_level = -1; ++ } ++ ++ if (dev->path.type == DEVICE_PATH_PCI) { ++ if ((dev->bus->secondary == 0x0) && (dev->path.pci.devfn == 0x0)) ++ *root_level = depth; ++ ++ if (*root_level != -1) { ++ if (depth >= *root_level) { ++ if (dev->enabled) { ++ if (depth == *root_level) { ++ if (dev->path.pci.devfn < (0x1 << 3)) { ++ /* SR5690 control device */ ++ } else if ((dev->path.pci.devfn >= (0x1 << 3)) && (dev->path.pci.devfn < (0xe << 3))) { ++ /* SR5690 PCIe bridge device */ ++ } else { ++ if (dev->path.pci.devfn == (0x14 << 3)) { ++ /* SMBUS controller */ ++ p = (uint8_t *) *current; ++ p[0] = 0x2; /* Entry type */ ++ p[1] = dev->path.pci.devfn; /* Device */ ++ p[2] = dev->bus->secondary; /* Bus */ ++ p[3] = 0x97; /* Data */ ++ p[4] = 0x0; /* Padding */ ++ p[5] = 0x0; /* Padding */ ++ p[6] = 0x0; /* Padding */ ++ p[7] = 0x0; /* Padding */ ++ *length += 8; ++ *current += 8; ++ } else { ++ /* Other southbridge device */ ++ p = (uint8_t *) *current; ++ p[0] = 0x2; /* Entry type */ ++ p[1] = dev->path.pci.devfn; /* Device */ ++ p[2] = dev->bus->secondary; /* Bus */ ++ p[3] = 0x0; /* Data */ ++ p[4] = 0x0; /* Padding */ ++ p[5] = 0x0; /* Padding */ ++ p[6] = 0x0; /* Padding */ ++ p[7] = 0x0; /* Padding */ ++ *length += 8; ++ *current += 8; ++ } ++ } ++ } else { ++ if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) { ++ /* Device behind bridge */ ++ if (pci_find_capability(dev, PCI_CAP_ID_PCIE)) { ++ /* Device is PCIe */ ++ p = (uint8_t *) *current; ++ p[0] = 0x2; /* Entry type */ ++ p[1] = dev->path.pci.devfn; /* Device */ ++ p[2] = dev->bus->secondary; /* Bus */ ++ p[3] = 0x0; /* Data */ ++ p[4] = 0x0; /* Padding */ ++ p[5] = 0x0; /* Padding */ ++ p[6] = 0x0; /* Padding */ ++ p[7] = 0x0; /* Padding */ ++ *length += 8; ++ *current += 8; ++ } else { ++ /* Device is legacy PCI or PCI-X */ ++ p = (uint8_t *) *current; ++ p[0] = 0x42; /* Entry type */ ++ p[1] = dev->path.pci.devfn; /* Device */ ++ p[2] = dev->bus->secondary; /* Bus */ ++ p[3] = 0x0; /* Data */ ++ p[4] = 0x0; /* Reserved */ ++ p[5] = parent->path.pci.devfn; /* Device */ ++ p[6] = parent->bus->secondary; /* Bus */ ++ p[7] = 0x0; /* Reserved */ ++ *length += 8; ++ *current += 8; ++ } ++ } ++ } ++ } ++ } ++ } ++ } ++ ++ for (link = dev->link_list; link; link = link->next) ++ for (sibling = link->children; sibling; sibling = sibling->sibling) ++ add_ivrs_device_entries(dev, sibling, depth + 1, depth, root_level, current, length); ++ ++ free(root_level); ++} ++ ++static unsigned long acpi_fill_ivrs(acpi_ivrs_t* ivrs, unsigned long current) ++{ ++ uint8_t *p; ++ ++ device_t nb_dev = dev_find_slot(0, PCI_DEVFN(0, 0)); ++ if (!nb_dev) { ++ printk(BIOS_WARNING, "acpi_fill_ivrs: Unable to locate SR5650 device! IVRS table not generated...\n"); ++ return (unsigned long)ivrs; ++ } ++ ++ device_t iommu_dev = dev_find_slot(0, PCI_DEVFN(0, 2)); ++ if (!iommu_dev) { ++ printk(BIOS_WARNING, "acpi_fill_ivrs: Unable to locate SR5650 IOMMU device! IVRS table not generated...\n"); ++ return (unsigned long)ivrs; ++ } ++ ++ ivrs->iv_info = 0x0; ++ ivrs->iv_info |= (0x40 << 15); /* Maximum supported virtual address size */ ++ ivrs->iv_info |= (0x34 << 8); /* Maximum supported physical address size */ ++ ++ ivrs->ivhd.type = 0x10; ++ ivrs->ivhd.flags = 0x0e; ++ // if (get_nb_rev(nb_dev) != REV_SR5650_A11) { ++ ivrs->ivhd.flags |= 0x10; /* Enable ATS support on all revisions except A11 */ ++ // } ++ ivrs->ivhd.length = sizeof(struct acpi_ivrs_ivhd); ++ ivrs->ivhd.device_id = 0x2 | (nb_dev->bus->secondary << 8); /* BDF <bus>:00.2 */ ++ ivrs->ivhd.capability_offset = 0x40; /* Capability block 0x40 (type 0xf, "Secure device") */ ++ ivrs->ivhd.iommu_base_low = pci_read_config32(iommu_dev, 0x44) & 0xffffc000; ++ ivrs->ivhd.iommu_base_high = pci_read_config32(iommu_dev, 0x48); ++ ivrs->ivhd.pci_segment_group = 0x0; ++ ivrs->ivhd.iommu_info = 0x0; ++ ivrs->ivhd.iommu_info |= (0x14 << 8); ++ ivrs->ivhd.efr = 0x0; ++ ++ /* Describe HPET */ ++ p = (uint8_t *)current; ++ p[0] = 0x48; /* Entry type */ ++ p[1] = 0; /* Device */ ++ p[2] = 0; /* Bus */ ++ p[3] = 0xd7; /* Data */ ++ p[4] = 0x0; /* HPET number */ ++ p[5] = 0x14 << 3; /* HPET device */ ++ p[6] = nb_dev->bus->secondary; /* HPET bus */ ++ p[7] = 0x2; /* Variety */ ++ ivrs->ivhd.length += 8; ++ current += 8; ++ ++ /* Describe PCI devices */ ++ add_ivrs_device_entries(NULL, all_devices, 0, -1, NULL, ¤t, &ivrs->ivhd.length); ++ ++ /* Describe IOAPICs */ ++ unsigned long prev_current = current; ++ current = acpi_fill_ivrs_ioapic(ivrs, current); ++ ivrs->ivhd.length += (current - prev_current); ++ ++ return current; ++} ++ ++unsigned long southbridge_write_acpi_tables(device_t device, ++ unsigned long current, ++ struct acpi_rsdp *rsdp) ++{ ++ unsigned char iommu; ++ ++ iommu = 1; ++ get_option(&iommu, "iommu"); ++ ++ if (iommu) { ++ acpi_ivrs_t *ivrs; ++ ++ /* IVRS */ ++ current = ALIGN(current, 8); ++ printk(BIOS_DEBUG, "ACPI: * IVRS at %lx\n", current); ++ ivrs = (acpi_ivrs_t *) current; ++ acpi_create_ivrs(ivrs, acpi_fill_ivrs); ++ current += ivrs->header.length; ++ acpi_add_table(rsdp, ivrs); ++ } ++ ++ return current; ++} ++ ++static struct pci_operations iommu_ops_pci = { ++ .set_subsystem = pci_dev_set_subsystem, ++}; ++ ++static struct device_operations iommu_ops = { ++ .read_resources = sr5650_iommu_read_resources, ++ .set_resources = sr5650_iommu_set_resources, ++ .enable_resources = sr5650_iommu_enable_resources, ++ .write_acpi_tables = southbridge_write_acpi_tables, ++ .init = 0, ++ .scan_bus = 0, ++ .ops_pci = &iommu_ops_pci, ++}; ++ ++static const struct pci_driver ht_driver_sr5690 __pci_driver = { ++ .ops = &iommu_ops, ++ .vendor = PCI_VENDOR_ID_ATI, ++ .device = PCI_DEVICE_ID_AMD_SR5650_IOMMU, ++}; ++ + struct chip_operations southbridge_amd_sr5650_ops = { + CHIP_NAME("ATI SR5650") + .enable_dev = sr5650_enable, +diff --git a/src/southbridge/amd/sr5650/sr5650.h b/src/southbridge/amd/sr5650/sr5650.h +index ebbde41..a3518fb 100644 +--- a/src/southbridge/amd/sr5650/sr5650.h ++++ b/src/southbridge/amd/sr5650/sr5650.h +@@ -2,6 +2,7 @@ + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Advanced Micro Devices, Inc. ++ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering + * + * 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 +@@ -21,6 +22,7 @@ + #define __SR5650_H__ + + #include <stdint.h> ++#include <arch/acpi.h> + #include <device/pci_ids.h> + #include "chip.h" + #include "rev.h" +@@ -95,16 +97,24 @@ u32 nbpcie_p_read_index(device_t dev, u32 index); + void nbpcie_p_write_index(device_t dev, u32 index, u32 data); + u32 nbpcie_ind_read_index(device_t nb_dev, u32 index); + void nbpcie_ind_write_index(device_t nb_dev, u32 index, u32 data); ++uint32_t l2cfg_ind_read_index(device_t nb_dev, uint32_t index); ++void l2cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data); ++uint32_t l1cfg_ind_read_index(device_t nb_dev, uint32_t index); ++void l1cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data); + u32 pci_ext_read_config32(device_t nb_dev, device_t dev, u32 reg); + void pci_ext_write_config32(device_t nb_dev, device_t dev, u32 reg, u32 mask, u32 val); + void sr5650_set_tom(device_t nb_dev); + ++unsigned long southbridge_write_acpi_tables(device_t device, unsigned long current, ++ struct acpi_rsdp *rsdp); ++ + void ProgK8TempMmioBase(u8 in_out, u32 pcie_base_add, u32 mmio_base_add); + void enable_pcie_bar3(device_t nb_dev); + void disable_pcie_bar3(device_t nb_dev); + + void enable_sr5650_dev8(void); + void sr5650_htinit(void); ++void sr5650_htinit_dect_and_enable_isochronous_link(void); + void sr5650_early_setup(void); + void sr5650_before_pci_init(void); + void sr5650_enable(device_t dev); +@@ -118,6 +128,10 @@ void pcie_config_misc_clk(device_t nb_dev); + void fam10_optimization(void); + void sr5650_disable_pcie_bridge(void); + u32 get_vid_did(device_t dev); ++void detect_and_enable_iommu(device_t iommu_dev); ++void sr5650_iommu_read_resources(device_t dev); ++void sr5650_iommu_set_resources(device_t dev); ++void sr5650_iommu_enable_resources(device_t dev); + void sr5650_nb_pci_table(device_t nb_dev); + void init_gen2(device_t nb_dev, device_t dev, u8 port); + void sr56x0_lock_hwinitreg(void); +-- +1.9.1 + |