southbridge/amd/sr5650: Add IOMMU support
Change-Id: I2083d0c5653515c27d4626c62a6499b850f7547b Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com> Reviewed-on: http://review.coreboot.org/12044 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth <martinroth@google.com>
This commit is contained in:
parent
ff8ccf05b0
commit
44e4a4e4db
|
@ -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
|
||||
|
|
|
@ -69,3 +69,40 @@ unsigned long acpi_fill_madt(unsigned long current)
|
|||
|
||||
return current;
|
||||
}
|
||||
|
||||
unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t* ivrs, unsigned long current)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
uint32_t apicid_sp5100;
|
||||
uint32_t apicid_sr5650;
|
||||
|
||||
apicid_sp5100 = 0x20;
|
||||
apicid_sr5650 = apicid_sp5100 + 1;
|
||||
|
||||
/* Describe NB IOAPIC */
|
||||
p = (uint8_t *)current;
|
||||
p[0] = 0x48; /* Entry type */
|
||||
p[1] = 0; /* Device */
|
||||
p[2] = 0; /* Bus */
|
||||
p[3] = 0x0; /* Data */
|
||||
p[4] = apicid_sr5650; /* IOAPIC ID */
|
||||
p[5] = 0x1; /* Device 0 Function 1 */
|
||||
p[6] = 0x0; /* Northbridge bus */
|
||||
p[7] = 0x1; /* Variety */
|
||||
current += 8;
|
||||
|
||||
/* Describe SB IOAPIC */
|
||||
p = (uint8_t *)current;
|
||||
p[0] = 0x48; /* Entry type */
|
||||
p[1] = 0; /* Device */
|
||||
p[2] = 0; /* Bus */
|
||||
p[3] = 0xd7; /* Data */
|
||||
p[4] = apicid_sp5100; /* IOAPIC ID */
|
||||
p[5] = 0x14 << 3; /* Device 0x14 Function 0 */
|
||||
p[6] = 0x0; /* Southbridge bus */
|
||||
p[7] = 0x1; /* Variety */
|
||||
current += 8;
|
||||
|
||||
return current;
|
||||
}
|
|
@ -62,3 +62,40 @@ unsigned long acpi_fill_madt(unsigned long current)
|
|||
|
||||
return current;
|
||||
}
|
||||
|
||||
unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t* ivrs, unsigned long current)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
uint32_t apicid_sp5100;
|
||||
uint32_t apicid_sr5650;
|
||||
|
||||
apicid_sp5100 = 0x20;
|
||||
apicid_sr5650 = apicid_sp5100 + 1;
|
||||
|
||||
/* Describe NB IOAPIC */
|
||||
p = (uint8_t *)current;
|
||||
p[0] = 0x48; /* Entry type */
|
||||
p[1] = 0; /* Device */
|
||||
p[2] = 0; /* Bus */
|
||||
p[3] = 0x0; /* Data */
|
||||
p[4] = apicid_sr5650; /* IOAPIC ID */
|
||||
p[5] = 0x1; /* Device 0 Function 1 */
|
||||
p[6] = 0x0; /* Northbridge bus */
|
||||
p[7] = 0x1; /* Variety */
|
||||
current += 8;
|
||||
|
||||
/* Describe SB IOAPIC */
|
||||
p = (uint8_t *)current;
|
||||
p[0] = 0x48; /* Entry type */
|
||||
p[1] = 0; /* Device */
|
||||
p[2] = 0; /* Bus */
|
||||
p[3] = 0xd7; /* Data */
|
||||
p[4] = apicid_sp5100; /* IOAPIC ID */
|
||||
p[5] = 0x14 << 3; /* Device 0x14 Function 0 */
|
||||
p[6] = 0x0; /* Southbridge bus */
|
||||
p[7] = 0x1; /* Variety */
|
||||
current += 8;
|
||||
|
||||
return current;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -22,6 +23,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
|
||||
|
||||
|
|
|
@ -20,6 +20,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"
|
||||
|
||||
|
@ -267,6 +269,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 */
|
||||
|
@ -331,8 +361,21 @@ static void sr5650_por_pcicfg_init(device_t nb_dev)
|
|||
*****************************************/
|
||||
static void sr5650_por_misc_index_init(device_t nb_dev)
|
||||
{
|
||||
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 */
|
||||
|
@ -370,10 +413,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);
|
||||
|
|
|
@ -22,7 +22,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"
|
||||
|
||||
|
@ -83,6 +85,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:
|
||||
|
@ -282,6 +304,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;
|
||||
|
@ -361,6 +617,8 @@ void sr5650_enable(device_t dev)
|
|||
dev_ind = dev->path.pci.devfn >> 3;
|
||||
switch (dev_ind) {
|
||||
case 0: /* bus0, dev0, fun0; */
|
||||
switch (dev->path.pci.devfn & 0x7) {
|
||||
case 0:
|
||||
printk(BIOS_INFO, "Bus-0, Dev-0, Fun-0.\n");
|
||||
enable_pcie_bar3(nb_dev); /* PCIEMiscInit */
|
||||
|
||||
|
@ -369,6 +627,14 @@ void sr5650_enable(device_t dev)
|
|||
|
||||
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 */
|
||||
case 3:
|
||||
|
@ -434,6 +700,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,
|
||||
|
|
|
@ -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
|
||||
|
@ -17,6 +18,7 @@
|
|||
#define __SR5650_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <arch/acpi.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include "chip.h"
|
||||
#include "rev.h"
|
||||
|
@ -91,16 +93,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);
|
||||
|
@ -114,6 +124,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);
|
||||
|
|
Loading…
Reference in New Issue