aboutsummaryrefslogtreecommitdiff
path: root/src/mainboard/arima/hdama/mainboard.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mainboard/arima/hdama/mainboard.c')
-rw-r--r--src/mainboard/arima/hdama/mainboard.c429
1 files changed, 235 insertions, 194 deletions
diff --git a/src/mainboard/arima/hdama/mainboard.c b/src/mainboard/arima/hdama/mainboard.c
index bbc6f53716..52a32b0adf 100644
--- a/src/mainboard/arima/hdama/mainboard.c
+++ b/src/mainboard/arima/hdama/mainboard.c
@@ -3,145 +3,251 @@
#include <device/pci.h>
#include <device/pci_ids.h>
#include <device/pci_ops.h>
-#include <cpu/p6/msr.h>
+#include <cpu/x86/msr.h>
+#include <part/hard_reset.h>
+#include <device/smbus.h>
+#include <delay.h>
#include <arch/io.h>
#include <device/chip.h>
#include "../../../northbridge/amd/amdk8/northbridge.h"
+#include "../../../northbridge/amd/amdk8/cpu_rev.c"
#include "chip.h"
#include "pc80/mc146818rtc.h"
-
-unsigned long initial_apicid[CONFIG_MAX_CPUS] =
+#undef DEBUG
+#define DEBUG 0
+#if DEBUG
+static void debug_init(device_t dev)
{
- 0, 1,
-};
+ unsigned bus;
+ unsigned devfn;
+#if 0
+ for(bus = 0; bus < 256; bus++) {
+ for(devfn = 0; devfn < 256; devfn++) {
+ int i;
+ dev = dev_find_slot(bus, devfn);
+ if (!dev) {
+ continue;
+ }
+ if (!dev->enabled) {
+ continue;
+ }
+ printk_info("%02x:%02x.%0x aka %s\n",
+ bus, devfn >> 3, devfn & 7, dev_path(dev));
+ for(i = 0; i < 256; i++) {
+ if ((i & 0x0f) == 0) {
+ printk_info("%02x:", i);
+ }
+ printk_info(" %02x", pci_read_config8(dev, i));
+ if ((i & 0x0f) == 0xf) {
+ printk_info("\n");
+ }
+ }
+ printk_info("\n");
+ }
+ }
+#endif
+#if 0
+ msr_t msr;
+ unsigned index;
+ unsigned eax, ebx, ecx, edx;
+ index = 0x80000007;
+ printk_debug("calling cpuid 0x%08x\n", index);
+ asm volatile(
+ "cpuid"
+ : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+ : "a" (index)
+ );
+ printk_debug("cpuid[%08x]: %08x %08x %08x %08x\n",
+ index, eax, ebx, ecx, edx);
+ if (edx & (3 << 1)) {
+ index = 0xC0010042;
+ printk_debug("Reading msr: 0x%08x\n", index);
+ msr = rdmsr(index);
+ printk_debug("msr[0x%08x]: 0x%08x%08x\n",
+ index, msr.hi, msr.hi);
+ }
+#endif
+}
-#define SMBGSTATUS 0xe0
-#define SMBGCTL 0xe2
-#define SMBHSTADDR 0xe4
-#define SMBHSTDAT 0xe6
-#define SMBHSTCMD 0xe8
-#define SMBHSTFIFO 0xe9
+static void debug_noop(device_t dummy)
+{
+}
-#define SMBUS_TIMEOUT (100*1000*10)
+static struct device_operations debug_operations = {
+ .read_resources = debug_noop,
+ .set_resources = debug_noop,
+ .enable_resources = debug_noop,
+ .init = debug_init,
+};
-static inline void smbus_delay(void)
+static unsigned int scan_root_bus(device_t root, unsigned int max)
{
- outb(0x80, 0x80);
+ struct device_path path;
+ device_t debug;
+ max = root_dev_scan_bus(root, max);
+ path.type = DEVICE_PATH_PNP;
+ path.u.pnp.port = 0;
+ path.u.pnp.device = 0;
+ debug = alloc_dev(&root->link[1], &path);
+ debug->ops = &debug_operations;
+ return max;
}
+#endif
-static int smbus_wait_until_ready(unsigned smbus_io_base)
+#if 0
+static void handle_smbus_error(int value, const char *msg)
{
- unsigned long loops;
- loops = SMBUS_TIMEOUT;
- do {
- unsigned short val;
- smbus_delay();
- val = inw(smbus_io_base + SMBGSTATUS);
- if ((val & 0x800) == 0) {
- break;
- }
- if(loops == (SMBUS_TIMEOUT / 2)) {
- outw(inw(smbus_io_base + SMBGSTATUS),
- smbus_io_base + SMBGSTATUS);
- }
- } while(--loops);
- return loops?0:-2;
+ if (value >= 0) {
+ return;
+ }
+ switch(value) {
+ case SMBUS_WAIT_UNTIL_READY_TIMEOUT:
+ printk_emerg("SMBUS wait until ready timed out - resetting...");
+ hard_reset();
+ break;
+ case SMBUS_WAIT_UNTIL_DONE_TIMEOUT:
+ printk_emerg("SMBUS wait until done timed out - resetting...");
+ hard_reset();
+ break;
+ default:
+ die(msg);
+ break;
+ }
}
-static int smbus_wait_until_done(unsigned smbus_io_base)
+#define ADM1026_DEVICE 0x2c /* 0x2e or 0x2d */
+#define ADM1026_REG_CONFIG1 0x00
+#define CFG1_MONITOR 0x01
+#define CFG1_INT_ENABLE 0x02
+#define CFG1_INT_CLEAR 0x04
+#define CFG1_AIN8_9 0x08
+#define CFG1_THERM_HOT 0x10
+#define CFT1_DAC_AFC 0x20
+#define CFG1_PWM_AFC 0x40
+#define CFG1_RESET 0x80
+#define ADM1026_REG_CONFIG2 0x01
+#define ADM1026_REG_CONFIG3 0x07
+
+
+
+#define BILLION 1000000000UL
+
+static void verify_cpu_voltage(const char *name,
+ device_t dev, unsigned int reg,
+ unsigned factor, unsigned cpu_volts, unsigned delta)
{
- unsigned long loops;
- loops = SMBUS_TIMEOUT;
+ unsigned nvolts_lo, nvolts_hi;
+ unsigned cpuvolts_hi, cpuvolts_lo;
+ int value;
+ int loops;
+
+ loops = 1000;
do {
- unsigned short val;
- smbus_delay();
+ value = smbus_read_byte(dev, reg);
+ handle_smbus_error(value, "SMBUS read byte failed");
+ } while ((--loops > 0) && value == 0);
+ /* Convert the byte value to nanoVolts.
+ * My accuracy is nowhere near that good but I don't
+ * have to round so the math is simple.
+ * I can only go up to about 4.2 Volts this way so my range is
+ * limited.
+ */
+ nvolts_lo = ((unsigned)value * factor);
+ nvolts_hi = nvolts_lo + factor - 1;
+ /* Get the range of acceptable cpu voltage values */
+ cpuvolts_lo = cpu_volts - delta;
+ cpuvolts_hi = cpu_volts + delta;
+ if ((nvolts_lo < cpuvolts_lo) || (nvolts_hi > cpuvolts_hi)) {
+ printk_emerg("%s at (%u.%09u-%u.%09u)Volts expected %u.%09u+/-%u.%09uVolts\n",
+ name,
+ nvolts_lo/BILLION, nvolts_lo%BILLION,
+ nvolts_hi/BILLION, nvolts_hi%BILLION,
+ cpu_volts/BILLION, cpu_volts%BILLION,
+ delta/BILLION, delta%BILLION);
+ die("");
+ }
+ printk_info("%s at (%u.%09u-%u.%09u)Volts\n",
+ name,
+ nvolts_lo/BILLION, nvolts_lo%BILLION,
+ nvolts_hi/BILLION, nvolts_hi%BILLION);
- val = inw(smbus_io_base + SMBGSTATUS);
- if (((val & 0x8) == 0) | ((val & 0x437) != 0)) {
- break;
- }
- } while(--loops);
- return loops?0:-3;
}
-static int smbus_send_byte(unsigned smbus_io_base, unsigned device, unsigned value)
+static void adm1026_enable_monitoring(device_t dev)
{
- unsigned char global_status_register;
+ int result;
+ result = smbus_read_byte(dev, ADM1026_REG_CONFIG1);
+ handle_smbus_error(result, "ADM1026: cannot read config1");
+
+ result = (result | CFG1_MONITOR) & ~(CFG1_INT_CLEAR | CFG1_RESET);
+ result = smbus_write_byte(dev, ADM1026_REG_CONFIG1, result);
+ handle_smbus_error(result, "ADM1026: cannot write to config1");
+
+ result = smbus_read_byte(dev, ADM1026_REG_CONFIG1);
+ handle_smbus_error(result, "ADM1026: cannot reread config1");
+ if (!(result & CFG1_MONITOR)) {
+ die("ADM1026: monitoring would not enable");
+ }
+}
- if (smbus_wait_until_ready(smbus_io_base) < 0) {
- return -2;
+
+static unsigned k8_cpu_volts(void)
+{
+ unsigned volts = ~0;
+ if (is_cpu_c0()) {
+ volts = 1500000000;
}
-
- /* setup transaction */
- /* disable interrupts */
- outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
- /* set the device I'm talking too */
- outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
- /* set the command/address... */
- outb(0, smbus_io_base + SMBHSTCMD);
- /* set up for a send byte */
- outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL);
-
- /* clear any lingering errors, so the transaction will run */
- /* Do I need to write the bits to a 1 to clear an error? */
- outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
-
- /* set the data word...*/
- outw(value, smbus_io_base + SMBHSTDAT);
-
- /* start the command */
- outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
-
-
- /* poll for transaction completion */
- if (smbus_wait_until_done(smbus_io_base) < 0) {
- return -3;
+ if (is_cpu_b3()) {
+ volts = 1550000000;
}
- global_status_register = inw(smbus_io_base + SMBGSTATUS);
+ return volts;
+}
- if (global_status_register != (1 << 4)) {
- return -1;
+static void verify_cpu_voltages(device_t dev)
+{
+ unsigned cpu_volts;
+ unsigned delta;
+#if 0
+ delta = 50000000;
+#else
+ delta = 75000000;
+#endif
+ cpu_volts = k8_cpu_volts();
+ if (cpu_volts == ~0) {
+ printk_info("Required cpu voltage unknwon not checking\n");
+ return;
}
- return 0;
+ /* I need to read registers 0x37 == Ain7CPU1 core 0x2d == VcppCPU0 core */
+ /* CPU1 core
+ * The sensor has a range of 0-2.5V and reports in
+ * 256 distinct steps.
+ */
+ verify_cpu_voltage("CPU1 Vcore", dev, 0x37, 9765625,
+ cpu_volts, delta);
+ /* CPU0 core
+ * The sensor has range of 0-3.0V and reports in
+ * 256 distinct steps.
+ */
+ verify_cpu_voltage("CPU0 Vcore", dev, 0x2d, 11718750,
+ cpu_volts, delta);
}
-static int smbus_recv_byte(unsigned smbus_io_base, unsigned device)
-{
- unsigned char global_status_register;
- unsigned char byte;
+#define SMBUS_MUX 0x70
if (smbus_wait_until_ready(smbus_io_base) < 0) {
return -2;
}
- /* setup transaction */
- /* disable interrupts */
- outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
- /* set the device I'm talking too */
- outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
- /* set the command/address... */
- outb(0, smbus_io_base + SMBHSTCMD);
- /* set up for a send byte */
- outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL);
-
- /* clear any lingering errors, so the transaction will run */
- /* Do I need to write the bits to a 1 to clear an error? */
- outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
-
- /* set the data word...*/
- outw(0, smbus_io_base + SMBHSTDAT);
-
- /* start the command */
- outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
-
-
- /* poll for transaction completion */
- if (smbus_wait_until_done(smbus_io_base) < 0) {
- return -3;
+ /* Find the smbus mux */
+ mux_path.type = DEVICE_PATH_I2C;
+ mux_path.u.i2c.device = SMBUS_MUX;
+ mux = find_dev_path(smbus_dev, &mux_path);
+ if (!mux) {
+ die("SMBUS mux not found\n");
}
global_status_register = inw(smbus_io_base + SMBGSTATUS);
@@ -165,119 +271,54 @@ static int smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned add
return -2;
}
- /* setup transaction */
- /* disable interrupts */
- outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
- /* set the device I'm talking too */
- outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
- /* set the command/address... */
- outb(address & 0xFF, smbus_io_base + SMBHSTCMD);
- /* set up for a byte data read */
- outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x2), smbus_io_base + SMBGCTL);
-
- /* clear any lingering errors, so the transaction will run */
- /* Do I need to write the bits to a 1 to clear an error? */
- outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
-
- /* clear the data word...*/
- outw(0, smbus_io_base + SMBHSTDAT);
-
- /* start the command */
- outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
-
-
- /* poll for transaction completion */
- if (smbus_wait_until_done(smbus_io_base) < 0) {
- return -3;
+ /* Set the mux to see the temperature sensors */
+ mux_setting = 1;
+ result = smbus_send_byte(mux, mux_setting);
+ handle_smbus_error(result, "SMBUS send byte failed\n");
+
+ result = smbus_recv_byte(mux);
+ handle_smbus_error(result, "SMBUS recv byte failed\n");
+ if (result != mux_setting) {
+ printk_emerg("SMBUS mux would not set to %d\n", mux_setting);
+ die("");
}
- global_status_register = inw(smbus_io_base + SMBGSTATUS);
+ adm1026_enable_monitoring(sensor);
- /* read results of transaction */
- byte = inw(smbus_io_base + SMBHSTDAT) & 0xff;
+ /* It takes 11.38ms to read a new voltage sensor value */
+ mdelay(12);
- if (global_status_register != (1 << 4)) {
- return -1;
- }
- return byte;
-}
-
-static int smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned address, unsigned char val)
-{
- if (smbus_wait_until_ready(smbus_io_base) < 0) {
- return -2;
- }
-
- /* setup transaction */
- /* disable interrupts */
- outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)),
- smbus_io_base + SMBGCTL);
- /* set the device I'm talking too */
- outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
- outb(address & 0xFF, smbus_io_base + SMBHSTCMD);
- /* set up for a byte data write */ /* FIXME */
- outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL);
- /* clear any lingering errors, so the transaction will run */
- /* Do I need to write the bits to a 1 to clear an error? */
- outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
-
- /* clear the data word...*/
- outw(val, smbus_io_base + SMBHSTDAT);
-
- /* start the command */
- outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
-
- /* poll for transaction completion */
- if (smbus_wait_until_done(smbus_io_base) < 0) {
- return -3;
- }
- return 0;
+ /* Read the cpu voltages and make certain everything looks sane */
+ verify_cpu_voltages(sensor);
}
+#else
+#define do_verify_cpu_voltages() do {} while(0)
#endif
-#define SMBUS_MUX 0x70
static void mainboard_init(device_t dev)
{
- /* Set the mux to see the temperature sensors */
- dev = dev_find_device(0x1022, 0x746b, 0);
- if (dev) {
- unsigned smbus_io_base;
- unsigned device;
- int result;
- int mux_setting;
- device = SMBUS_MUX;
- mux_setting = 1;
- smbus_io_base = pci_read_config32(dev, 0x58) & ~1;;
- result = smbus_send_byte(smbus_io_base, device, mux_setting);
- if ((result < 0) ||
- (smbus_recv_byte(smbus_io_base, device) != mux_setting)) {
- printk_err("SMBUS mux would not set to %d\n", mux_setting);
- }
-
- }
- else {
- printk_err("SMBUS_controller not found\n");
- }
+ root_dev_init(dev);
+
+ do_verify_cpu_voltages();
}
static struct device_operations mainboard_operations = {
.read_resources = root_dev_read_resources,
.set_resources = root_dev_set_resources,
- .enable_resources = enable_childrens_resources,
+ .enable_resources = root_dev_enable_resources,
.init = mainboard_init,
- .scan_bus = amdk8_scan_root_bus,
+#if !DEBUG
+ .scan_bus = root_dev_scan_bus,
+#else
+ .scan_bus = scan_root_bus,
+#endif
.enable = 0,
};
static void enumerate(struct chip *chip)
{
- struct chip *child;
dev_root.ops = &mainboard_operations;
- chip->dev = &dev_root;
- chip->bus = 0;
- for(child = chip->children; child; child = child->next) {
- child->bus = &dev_root.link[0];
- }
+ chip_enumerate(chip);
}
struct chip_control mainboard_arima_hdama_control = {
.enumerate = enumerate,