#include "southbridge/amd/amd8111/amd8111_early_smbus.c"
#include "northbridge/amd/amdk8/raminit.h"
+
+static void print_debug_pci_dev(unsigned dev)
+{
+ print_debug("PCI: ");
+ print_debug_hex8((dev >> 16) & 0xff);
+ print_debug_char(':');
+ print_debug_hex8((dev >> 11) & 0x1f);
+ print_debug_char('.');
+ print_debug_hex8((dev >> 8) & 7);
+}
+
+static void print_pci_devices(void)
+{
+ device_t dev;
+ for(dev = PCI_DEV(0, 0, 0);
+ dev <= PCI_DEV(0, 0x1f, 0x7);
+ dev += PCI_DEV(0,0,1)) {
+ uint32_t id;
+ id = pci_read_config32(dev, PCI_VENDOR_ID);
+ if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0x0000)) {
+ continue;
+ }
+ print_debug_pci_dev(dev);
+ print_debug("\r\n");
+ }
+}
+
+static void dump_pci_device(unsigned dev)
+{
+ int i;
+ print_debug_pci_dev(dev);
+ print_debug("\r\n");
+
+ for(i = 0; i <= 255; i++) {
+ unsigned char val;
+ if ((i & 0x0f) == 0) {
+ print_debug_hex8(i);
+ print_debug_char(':');
+ }
+ val = pci_read_config8(dev, i);
+ print_debug_char(' ');
+ print_debug_hex8(val);
+ if ((i & 0x0f) == 0x0f) {
+ print_debug("\r\n");
+ }
+ }
+}
+
+static void dump_pci_devices(void)
+{
+ device_t dev;
+ for(dev = PCI_DEV(0, 0, 0);
+ dev <= PCI_DEV(0, 0x1f, 0x7);
+ dev += PCI_DEV(0,0,1)) {
+ uint32_t id;
+ id = pci_read_config32(dev, PCI_VENDOR_ID);
+ if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0x0000)) {
+ continue;
+ }
+ dump_pci_device(dev);
+ }
+}
+
+static void dump_spd_registers(const struct mem_controller *ctrl)
+{
+ int i;
+ print_debug("\r\n");
+ for(i = 0; i < 4; i++) {
+ unsigned device;
+ device = ctrl->channel0[i];
+ if (device) {
+ int j;
+ print_debug("dimm: ");
+ print_debug_hex8(i);
+ print_debug(".0: ");
+ print_debug_hex8(device);
+ for(j = 0; j < 256; j++) {
+ int status;
+ unsigned char byte;
+ if ((j & 0xf) == 0) {
+ print_debug("\r\n");
+ print_debug_hex8(j);
+ print_debug(": ");
+ }
+ status = smbus_read_byte(device, j);
+ if (status < 0) {
+ print_debug("bad device\r\n");
+ break;
+ }
+ byte = status & 0xff;
+ print_debug_hex8(byte);
+ print_debug_char(' ');
+ }
+ print_debug("\r\n");
+ }
+ device = ctrl->channel1[i];
+ if (device) {
+ int j;
+ print_debug("dimm: ");
+ print_debug_hex8(i);
+ print_debug(".1: ");
+ print_debug_hex8(device);
+ for(j = 0; j < 256; j++) {
+ int status;
+ unsigned char byte;
+ if ((j & 0xf) == 0) {
+ print_debug("\r\n");
+ print_debug_hex8(j);
+ print_debug(": ");
+ }
+ status = smbus_read_byte(device, j);
+ if (status < 0) {
+ print_debug("bad device\r\n");
+ break;
+ }
+ byte = status & 0xff;
+ print_debug_hex8(byte);
+ print_debug_char(' ');
+ }
+ print_debug("\r\n");
+ }
+ }
+}
+
#warning "FIXME move these delay functions somewhere more appropriate"
#warning "FIXME use the apic timer instead it needs no calibration on an Opteron it runs at 200Mhz"
static void print_clock_multiplier(void)
outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(0<<0), SMBUS_IO_BASE + 0xc0 + 28);
/* Ensure the BIOS has control of the memory lines */
outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(0<<0), SMBUS_IO_BASE + 0xc0 + 29);
- print_debug("memreset lo\r\n");
}
static void memreset(const struct mem_controller *ctrl)
udelay(800);
/* Set memreset_high */
outb((0<<7)|(0<<6)|(0<<5)|(0<<4)|(1<<2)|(1<<0), SMBUS_IO_BASE + 0xc0 + 28);
- print_debug("memreset hi\r\n");
udelay(50);
}
}
-static void print_debug_pci_dev(unsigned dev)
-{
- print_debug("PCI: ");
- print_debug_hex8((dev >> 16) & 0xff);
- print_debug_char(':');
- print_debug_hex8((dev >> 11) & 0x1f);
- print_debug_char('.');
- print_debug_hex8((dev >> 8) & 7);
-}
-
-static void print_pci_devices(void)
-{
- device_t dev;
- for(dev = PCI_DEV(0, 0, 0);
- dev <= PCI_DEV(0, 0x1f, 0x7);
- dev += PCI_DEV(0,0,1)) {
- uint32_t id;
- id = pci_read_config32(dev, PCI_VENDOR_ID);
- if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
- (((id >> 16) & 0xffff) == 0xffff) ||
- (((id >> 16) & 0xffff) == 0x0000)) {
- continue;
- }
- print_debug_pci_dev(dev);
- print_debug("\r\n");
- }
-}
-
-
-static void dump_pci_device(unsigned dev)
-{
- int i;
- print_debug_pci_dev(dev);
- print_debug("\r\n");
-
- for(i = 0; i <= 255; i++) {
- unsigned char val;
- if ((i & 0x0f) == 0) {
- print_debug_hex8(i);
- print_debug_char(':');
- }
- val = pci_read_config8(dev, i);
- print_debug_char(' ');
- print_debug_hex8(val);
- if ((i & 0x0f) == 0x0f) {
- print_debug("\r\n");
- }
- }
-}
-
-static void dump_pci_devices(void)
-{
- device_t dev;
- for(dev = PCI_DEV(0, 0, 0);
- dev <= PCI_DEV(0, 0x1f, 0x7);
- dev += PCI_DEV(0,0,1)) {
- uint32_t id;
- id = pci_read_config32(dev, PCI_VENDOR_ID);
- if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
- (((id >> 16) & 0xffff) == 0xffff) ||
- (((id >> 16) & 0xffff) == 0x0000)) {
- continue;
- }
- dump_pci_device(dev);
- }
-}
-
-static void dump_spd_registers(const struct mem_controller *ctrl)
-{
- int i;
- print_debug("\r\n");
- for(i = 0; i < 4; i++) {
- unsigned device;
- device = ctrl->channel0[i];
- if (device) {
- int j;
- print_debug("dimm: ");
- print_debug_hex8(i);
- print_debug(".0: ");
- print_debug_hex8(device);
- for(j = 0; j < 256; j++) {
- int status;
- unsigned char byte;
- if ((j & 0xf) == 0) {
- print_debug("\r\n");
- print_debug_hex8(j);
- print_debug(": ");
- }
- status = smbus_read_byte(device, j);
- if (status < 0) {
- print_debug("bad device\r\n");
- break;
- }
- byte = status & 0xff;
- print_debug_hex8(byte);
- print_debug_char(' ');
- }
- print_debug("\r\n");
- }
- device = ctrl->channel1[i];
- if (device) {
- int j;
- print_debug("dimm: ");
- print_debug_hex8(i);
- print_debug(".1: ");
- print_debug_hex8(device);
- for(j = 0; j < 256; j++) {
- int status;
- unsigned char byte;
- if ((j & 0xf) == 0) {
- print_debug("\r\n");
- print_debug_hex8(j);
- print_debug(": ");
- }
- status = smbus_read_byte(device, j);
- if (status < 0) {
- print_debug("bad device\r\n");
- break;
- }
- byte = status & 0xff;
- print_debug_hex8(byte);
- print_debug_char(' ');
- }
- print_debug("\r\n");
- }
- }
-}
static void pnp_write_config(unsigned char port, unsigned char value, unsigned char reg)
{
uart_init();
console_init();
if (boot_cpu() && !cpu_init_detected()) {
-#if 1
+#if 0
init_apic_timer();
#endif
+#if 1
setup_default_resource_map();
+#endif
+
+#if 0
+ dump_pci_device(PCI_DEV(0, 0x18, 0));
+#endif
+
setup_coherent_ht_domain();
+#if 1
+ disable_probes();
+#endif
enumerate_ht_chain();
print_pci_devices();
enable_smbus();
+#if 0
dump_spd_registers(&cpu0);
+#endif
sdram_initialize(&cpu0);
-#if 0
+#if 1
dump_pci_devices();
#endif
#if 0
#endif
/* Check all of memory */
+#if 0
msr_t msr;
msr = rdmsr(TOP_MEM);
print_debug("TOP_MEM: ");
print_debug_hex32(msr.hi);
print_debug_hex32(msr.lo);
print_debug("\r\n");
+#endif
#if 0
ram_check(0x00000000, msr.lo);
#else
+#if 1
/* Check 16MB of memory */
- ram_check(0x00000000, 0x1600000);
+ ram_check(0x00000000, 0x01000000);
#endif
-#if 0
- print_debug("sleeping 15s\r\n");
- delay(15);
- print_debug("sleeping 15s done\r\n");
#endif
}
}
+#if 0
static void setup_coherent_ht_domain(void)
{
static const unsigned int register_values[] = {
*/
PCI_ADDR(0, 0x18, 0, 0x68), 0x00800000, 0x0f00840f,
/* HT Initialization Control Register
- * F0:0x6C
+ * F0:0x6C ok...
* [ 0: 0] Routing Table Disable
* 0 = Packets are routed according to routing tables
* 1 = Packets are routed according to the default link field
}
print_debug("done.\r\n");
}
+#else
+/* coherent hypertransport initialization for AMD64
+ * written by Stefan Reinauer <stepan@openbios.info>
+ * (c) 2003 by SuSE Linux AG
+ *
+ * This code is licensed under GPL.
+ */
+
+/*
+ * This algorithm assumes a grid configuration as follows:
+ *
+ * nodes : 1 2 4 6 8
+ * org. : 1x1 2x1 2x2 2x3 2x4
+ *
+ */
+
+#if 0
+#include "compat.h"
+#endif
+
+#include <device/pci_def.h>
+#include "arch/romcc_io.h"
+
+
+/* when generating a temporary row configuration we
+ * don't want broadcast to be enabled for that node.
+ */
+
+#define generate_temp_row(x...) ((generate_row(x)&(~0x0f0000))|0x010000)
+#define clear_temp_row(x) fill_row(x,7,DEFAULT)
+#define enable_bsp_routing() enable_routing(0)
+
+#define NODE_HT(x) PCI_DEV(0,24+x,0)
+#define NODE_MP(x) PCI_DEV(0,24+x,1)
+#define NODE_MC(x) PCI_DEV(0,24+x,3)
+
+#define DEFAULT 0x00010101 /* default row entry */
+
+typedef uint8_t u8;
+typedef uint32_t u32;
+typedef int8_t bool;
+
+#define TRUE (-1)
+#define FALSE (0)
+
+static void disable_probes(void)
+{
+ /* disable read/write/fill probes for uniprocessor setup
+ * they don't make sense if only one cpu is available
+ */
+
+ /* Hypetransport Transaction Control Register
+ * F0:0x68
+ * [ 0: 0] Disable read byte probe
+ * 0 = Probes issues
+ * 1 = Probes not issued
+ * [ 1: 1] Disable Read Doubleword probe
+ * 0 = Probes issued
+ * 1 = Probes not issued
+ * [ 2: 2] Disable write byte probes
+ * 0 = Probes issued
+ * 1 = Probes not issued
+ * [ 3: 3] Disable Write Doubleword Probes
+ * 0 = Probes issued
+ * 1 = Probes not issued.
+ * [10:10] Disable Fill Probe
+ * 0 = Probes issued for cache fills
+ * 1 = Probes not issued for cache fills.
+ */
+
+ u32 val;
+
+ print_debug("Disabling read/write/fill probes for UP... ");
+
+ val=pci_read_config32(NODE_HT(0), 0x68);
+ val |= 0x0000040f;
+ pci_write_config32(NODE_HT(0), 0x68, val);
+
+ print_debug("done.\r\n");
+
+}
+
+static void enable_routing(u8 node)
+{
+ u32 val;
+
+ /* HT Initialization Control Register
+ * F0:0x6C
+ * [ 0: 0] Routing Table Disable
+ * 0 = Packets are routed according to routing tables
+ * 1 = Packets are routed according to the default link field
+ * [ 1: 1] Request Disable (BSP should clear this)
+ * 0 = Request packets may be generated
+ * 1 = Request packets may not be generated.
+ * [ 3: 2] Default Link (Read-only)
+ * 00 = LDT0
+ * 01 = LDT1
+ * 10 = LDT2
+ * 11 = CPU on same node
+ * [ 4: 4] Cold Reset
+ * - Scratch bit cleared by a cold reset
+ * [ 5: 5] BIOS Reset Detect
+ * - Scratch bit cleared by a cold reset
+ * [ 6: 6] INIT Detect
+ * - Scratch bit cleared by a warm or cold reset not by an INIT
+ *
+ */
+
+ /* Enable routing table for BSP */
+ print_debug("Enabling routing table for node ");
+ print_debug_hex32(node);
+
+ val=pci_read_config32(NODE_HT(node), 0x6c);
+ val |= (1 << 6) | (1 << 5) | (1 << 4);
+#if 0
+ val &= ~((1<<1)|(1<<0));
+#else
+ /* Don't enable requests here as the indicated processor starts booting */
+ val &= ~(1<<0);
+#endif
+ pci_write_config32(NODE_HT(node), 0x6c, val);
+
+ print_debug(" done.\r\n");
+}
+
+#if MAX_CPUS > 1
+
+static void rename_temp_node(u8 node)
+{
+ u32 val;
+
+ print_debug("Renaming current temp node to ");
+ print_debug_hex32(node);
+
+ val=pci_read_config32(NODE_HT(7), 0x60);
+ val &= (~7); /* clear low bits. */
+ val |= node; /* new node */
+ pci_write_config32(NODE_HT(7), 0x60, val);
+
+ print_debug(" done.\r\n");
+
+
+}
+
+static bool check_connection(u8 src, u8 dest, u8 link)
+{
+ /* this function does 2 things:
+ * 1) detect whether the coherent HT link is connected
+ * 2) verify that the coherent hypertransport link
+ * is established and actually working by reading the
+ * remote node's vendor/device id
+ */
+
+#define UP 0x00
+#define ACROSS 0x20
+#define DOWN 0x40
+
+ u32 val;
+
+ /* 1) */
+ val=pci_read_config32(NODE_HT(src), 0x98+link);
+ if ( (val&0x17) != 0x03)
+ return 0;
+
+ /* 2) */
+ val=pci_read_config32(NODE_HT(dest),0);
+ if(val != 0x11001022)
+ return 0;
+
+ return 1;
+}
+
+static unsigned int generate_row(u8 node, u8 row, u8 maxnodes)
+{
+ /* Routing Table Node i
+ *
+ * F0: 0x40, 0x44, 0x48, 0x4c, 0x50, 0x54, 0x58, 0x5c
+ * i: 0, 1, 2, 3, 4, 5, 6, 7
+ *
+ * [ 0: 3] Request Route
+ * [0] Route to this node
+ * [1] Route to Link 0
+ * [2] Route to Link 1
+ * [3] Route to Link 2
+ * [11: 8] Response Route
+ * [0] Route to this node
+ * [1] Route to Link 0
+ * [2] Route to Link 1
+ * [3] Route to Link 2
+ * [19:16] Broadcast route
+ * [0] Route to this node
+ * [1] Route to Link 0
+ * [2] Route to Link 1
+ * [3] Route to Link 2
+ */
+
+ u32 ret=DEFAULT;
+
+ static const unsigned int rows_2p[2][2] = {
+ { 0x00030101, 0x00010404 },
+ { 0x00010404, 0x00030101 }
+ };
+
+ static const unsigned int rows_4p[4][4] = {
+ { 0x00070101, 0x00010404, 0x00050202, 0x00010402 },
+ { 0x00010808, 0x000b0101, 0x00010802, 0x00090202 },
+ { 0x00090202, 0x00010802, 0x000b0101, 0x00010808 },
+ { 0x00010402, 0x00050202, 0x00010404, 0x00070101 }
+ };
+
+ if (!(node>=maxnodes || row>=maxnodes)) {
+ if (maxnodes==2)
+ ret=rows_2p[node][row];
+ if (maxnodes==4)
+ ret=rows_4p[node][row];
+ }
+
+#if 0
+ printk_spew("generating entry n=%d, r=%d, max=%d - row=%x\n",
+ node,row,maxnodes,ret);
+#endif
+
+ return ret;
+}
+
+static void fill_row(u8 node, u8 row, u32 value)
+{
+#if 0
+ print_debug("fill_row: pci_write_config32(");
+ print_debug_hex32(NODE_HT(node));
+ print_debug_char(',');
+ print_debug_hex32(0x40 + (row << 2));
+ print_debug_char(',');
+ print_debug_hex32(value);
+ print_debug(")\r\n");
+#endif
+ pci_write_config32(NODE_HT(node), 0x40+(row<<2), value);
+}
+
+static void setup_row(u8 source, u8 dest, u8 cpus)
+{
+#if 0
+ printk_spew("setting up link from node %d to %d (%d cpus)\r\n",
+ source, dest, cpus);
+#endif
+
+ fill_row(source,dest,generate_row(source,dest,cpus));
+}
+
+static void setup_temp_row(u8 source, u8 dest, u8 cpus)
+{
+#if 0
+ printk_spew("setting up temp. link from node %d to %d (%d cpus)\r\n",
+ source, dest, cpus);
+#endif
+
+ fill_row(source,7,generate_temp_row(source,dest,cpus));
+}
+
+static void setup_node(u8 node, u8 cpus)
+{
+ u8 row;
+ for(row=0; row<cpus; row++)
+ setup_row(node, row, cpus);
+}
+
+static void setup_remote_row(u8 source, u8 dest, u8 cpus)
+{
+ fill_row(7, dest, generate_row(source, dest, cpus));
+}
+
+static void setup_remote_node(u8 node, u8 cpus)
+{
+ static const uint8_t pci_reg[] = {
+ 0x44, 0x4c, 0x54, 0x5c, 0x64, 0x6c, 0x74, 0x7c,
+ 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78,
+ 0x84, 0x8c, 0x94, 0x9c, 0xa4, 0xac, 0xb4, 0xbc,
+ 0x80, 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8,
+ 0xc4, 0xcc, 0xd4, 0xdc,
+ 0xc0, 0xc8, 0xd0, 0xd8,
+ 0xe0, 0xe4, 0xe8, 0xec,
+ };
+ uint8_t row;
+ int i;
+#if 1
+ print_debug("setup_remote_node\r\n");
+#endif
+ for(row=0; row<cpus; row++)
+ setup_remote_row(node, row, cpus);
+
+ /* copy the default resource map from node 0 */
+ for(i = 0; i < sizeof(pci_reg)/sizeof(pci_reg[0]); i++) {
+ uint32_t value;
+ uint8_t reg;
+ reg = pci_reg[i];
+ print_debug("copying reg: ");
+ print_debug_hex8(reg);
+ print_debug("\r\n");
+ value = pci_read_config32(NODE_MP(0), reg);
+ pci_write_config32(NODE_MP(7), reg, value);
+
+ }
+#if 1
+ print_debug("setup_remote_done\r\n");
+#endif
+}
+
+#endif
+
+#if MAX_CPUS > 2
+static void setup_temp_node(u8 node, u8 cpus)
+{
+ u8 row;
+ for(row=0; row<cpus; row++)
+ fill_row(7,row,generate_row(node,row,cpus));
+}
+#endif
+
+static u8 setup_uniprocessor(void)
+{
+ print_debug("Enabling UP settings\r\n");
+ disable_probes();
+ return 1;
+}
+
+#if MAX_CPUS > 1
+static u8 setup_smp(void)
+{
+ u8 cpus=2;
+
+ print_debug("Enabling SMP settings\r\n");
+
+ setup_row(0,0,cpus);
+ /* Setup and check a temporary connection to node 1 */
+ setup_temp_row(0,1,cpus);
+
+ if (!check_connection(0, 7, ACROSS)) { // Link: ACROSS
+ print_debug("No connection to Node 1.\r\n");
+ clear_temp_row(0); /* delete temp connection */
+ setup_uniprocessor(); /* and get up working */
+ return 1;
+ }
+
+ /* We found 2 nodes so far */
+ setup_node(0, cpus); /* Node 1 is there. Setup Node 0 correctly */
+ setup_remote_node(1, cpus); /* Setup the routes on the remote node */
+ enable_routing(1); /* Enable routing on Node 1 */
+ rename_temp_node(1); /* Rename Node 7 to Node 1 */
+
+ clear_temp_row(0); /* delete temporary connection */
+
+#if MAX_CPUS > 2
+ cpus=4;
+
+ /* Setup and check temporary connection from Node 0 to Node 2 */
+ setup_temp_row(0,2,cpus);
+
+ if (!check_connection(0, 7, UP)) { // Link: UP
+ print_debug("No connection to Node 2.\r\n");
+ clear_temp_row(0); /* delete temp connection */
+ // detect_mp_capability(2); /* and get 2p working */
+ return 2;
+ }
+
+ /* We found 3 nodes so far. Now setup a temporary
+ * connection from node 0 to node 3 via node 1
+ */
+
+ setup_temp_row(0,1,cpus); /* temp. link between nodes 0 and 1 */
+ setup_temp_row(1,3,cpus); /* temp. link between nodes 1 and 3 */
+
+ if (!check_connection(0, 7, UP)) { // Link: UP
+ print_debug("No connection to Node 3.\r\n");
+ clear_temp_row(0); /* delete temp connection */
+ clear_temp_row(1); /* delete temp connection */
+ //detect_mp_capability(2); /* and get 2p working */
+ return 2;
+ }
+
+ /* We found 4 nodes so far. Now setup all nodes for 4p */
+
+ setup_node(0, cpus); /* The first 2 nodes are configured */
+ setup_node(1, cpus); /* already. Just configure them for 4p */
+
+ setup_temp_row(0,2,cpus);
+ setup_temp_node(2,cpus);
+ enable_routing(7);
+ rename_temp_node(2);
+
+ setup_temp_row(0,1,cpus);
+ setup_temp_row(1,3,cpus);
+ setup_temp_node(3,cpus);
+ enable_routing(3);
+ rename_temp_node(3);
+
+ clear_temp_row(0);
+ clear_temp_row(1);
+ clear_temp_row(2);
+ clear_temp_row(3);
+
+#endif
+ print_debug_hex32(cpus);
+ print_debug(" nodes initialized.\r\n");
+ return cpus;
+}
+#endif
+
+#if MAX_CPUS > 1
+static unsigned detect_mp_capabilities(unsigned cpus)
+{
+ unsigned node, row, mask;
+ bool mp_cap=TRUE;
+
+#if 1
+ print_debug("detect_mp_capabilities: ");
+ print_debug_hex32(cpus);
+ print_debug("\r\n");
+#endif
+ if (cpus>2)
+ mask=0x04; /* BigMPCap */
+ else
+ mask=0x02; /* MPCap */
+
+ for (node=0; node<cpus; node++) {
+ if (!(pci_read_config32(NODE_MC(node), 0xe8) & mask))
+ mp_cap=FALSE;
+ }
+
+ if (mp_cap)
+ return cpus;
+
+ /* one of our cpus is not mp capable */
+
+ print_debug("One of the CPUs is not MP capable. Going back to UP\r\n");
+
+ for (node=cpus; node>0; node--)
+ for (row=cpus; row>0; row--)
+ fill_row(NODE_HT(node-1), row-1, DEFAULT);
+
+ return setup_uniprocessor();
+}
+
+#endif
+
+/* this is a shrunken cpuid. */
+
+static unsigned int cpuid(unsigned int op)
+{
+ unsigned int ret;
+
+ asm volatile ( "cpuid" : "=a" (ret) : "a" (op));
+
+ return ret;
+}
+
+static void coherent_ht_finalize(unsigned cpus)
+{
+ int node;
+ bool rev_a0;
+
+ /* set up cpu count and node count and enable Limit
+ * Config Space Range for all available CPUs.
+ * Also clear non coherent hypertransport bus range
+ * registers on Hammer A0 revision.
+ */
+
+#if 1
+ print_debug("coherent_ht_finalize\r\n");
+#endif
+ rev_a0=((cpuid(1)&0xffff)==0x0f10);
+
+ for (node=0; node<cpus; node++) {
+ u32 val;
+ val=pci_read_config32(NODE_HT(node), 0x60);
+ val &= 0x000F0070;
+ val |= ((cpus-1)<<16)|((cpus-1)<<4);
+ pci_write_config32(NODE_HT(node),0x60,val);
+
+ val=pci_read_config32(NODE_HT(node), 0x68);
+ val |= 0x00008000;
+ pci_write_config32(NODE_HT(node),0x68,val);
+
+ if (rev_a0) {
+ pci_write_config32(NODE_HT(node),0x94,0);
+ pci_write_config32(NODE_HT(node),0xb4,0);
+ pci_write_config32(NODE_HT(node),0xd4,0);
+ }
+ }
+
+#if 1
+ print_debug("done\n");
+#endif
+}
+
+static void setup_coherent_ht_domain(void)
+{
+ unsigned cpus;
+
+ enable_bsp_routing();
+
+#if MAX_CPUS == 1
+ cpus=setup_uniprocessor();
+#else
+ cpus=setup_smp();
+ cpus=detect_mp_capabilities(cpus);
+#endif
+ coherent_ht_finalize(cpus);
+}
+
+#endif