diff options
author | Eric Biederman <ebiederm@xmission.com> | 2004-10-14 20:54:17 +0000 |
---|---|---|
committer | Eric Biederman <ebiederm@xmission.com> | 2004-10-14 20:54:17 +0000 |
commit | b78c1972feed4c57eebba8f94de86a91e32c3fa7 (patch) | |
tree | 2ba60cfe9866f4d1e2de1d9727d0e548139afb35 /src/mainboard/arima/hdama/mainboard.c | |
parent | cadfd4c462673bcb44cdb1f193e52c95a888762a (diff) |
- First pass through with with device tree enhancement merge. Most of the mechanisms should
be in place but don't expect anything to quite work yet.
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1662 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/mainboard/arima/hdama/mainboard.c')
-rw-r--r-- | src/mainboard/arima/hdama/mainboard.c | 429 |
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, |