summaryrefslogtreecommitdiff
path: root/src/mainboard/island/aruma/mainboard.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mainboard/island/aruma/mainboard.c')
-rw-r--r--src/mainboard/island/aruma/mainboard.c339
1 files changed, 339 insertions, 0 deletions
diff --git a/src/mainboard/island/aruma/mainboard.c b/src/mainboard/island/aruma/mainboard.c
new file mode 100644
index 0000000000..6de2b302b9
--- /dev/null
+++ b/src/mainboard/island/aruma/mainboard.c
@@ -0,0 +1,339 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <cpu/x86/msr.h>
+#include <part/hard_reset.h>
+#include <device/smbus.h>
+#include <delay.h>
+
+#include <arch/io.h>
+#include "../../../northbridge/amd/amdk8/northbridge.h"
+#include "../../../northbridge/amd/amdk8/cpu_rev.c"
+#include "chip.h"
+
+#include "pc80/mc146818rtc.h"
+
+
+#undef DEBUG
+#define DEBUG 0
+#if DEBUG
+static void debug_init(device_t dev)
+{
+ 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
+}
+
+static void debug_noop(device_t dummy)
+{
+}
+
+static struct device_operations debug_operations = {
+ .read_resources = debug_noop,
+ .set_resources = debug_noop,
+ .enable_resources = debug_noop,
+ .init = debug_init,
+};
+
+static unsigned int scan_root_bus(device_t root, unsigned int max)
+{
+ 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
+
+#if 0
+static void handle_smbus_error(int value, const char *msg)
+{
+ 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;
+ }
+}
+
+#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 nvolts_lo, nvolts_hi;
+ unsigned cpuvolts_hi, cpuvolts_lo;
+ int value;
+ int loops;
+
+ loops = 1000;
+ do {
+ 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);
+
+}
+
+static void adm1026_enable_monitoring(device_t dev)
+{
+ 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");
+ }
+}
+
+
+static unsigned k8_cpu_volts(void)
+{
+ unsigned volts = ~0;
+ if (is_cpu_c0()) {
+ volts = 1500000000;
+ }
+ if (is_cpu_b3()) {
+ volts = 1550000000;
+ }
+ return volts;
+}
+
+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;
+ }
+ /* 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);
+}
+
+#define SMBUS_MUX 0x70
+
+static void do_verify_cpu_voltages(void)
+{
+ device_t smbus_dev;
+ device_t mux, sensor;
+ struct device_path mux_path, sensor_path;
+ int result;
+ int mux_setting;
+
+ /* Find the smbus controller */
+ smbus_dev = dev_find_device(0x1022, 0x746b, 0);
+ if (!smbus_dev) {
+ die("SMBUS controller not found\n");
+ }
+
+ /* 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");
+ }
+
+ /* Find the adm1026 sensor */
+ sensor_path.type = DEVICE_PATH_I2C;
+ sensor_path.u.i2c.device = ADM1026_DEVICE;
+ sensor = find_dev_path(mux, &sensor_path);
+ if (!sensor) {
+ die("ADM1026 not found\n");
+ }
+
+ /* 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("");
+ }
+
+ adm1026_enable_monitoring(sensor);
+
+ /* It takes 11.38ms to read a new voltage sensor value */
+ mdelay(12);
+
+ /* Read the cpu voltages and make certain everything looks sane */
+ verify_cpu_voltages(sensor);
+}
+#else
+#define do_verify_cpu_voltages() do {} while(0)
+#endif
+
+
+static void fixup_aruma(void)
+{
+ msr_t msr;
+
+ /* bit 6 (0x40) in MSR 0xC0010015
+ * disables the TLB cache flush filter
+ */
+ msr=rdmsr(0xC0010015);
+ msr.lo |= 0x40;
+ wrmsr(0xC0010015, msr);
+}
+
+
+static void mainboard_init(device_t dev)
+{
+ root_dev_init(dev);
+
+ do_verify_cpu_voltages();
+
+ printk_info("Initializing mainboard specific functions... ");
+ fixup_aruma();
+ printk_info("ok\n");
+}
+
+static struct device_operations mainboard_operations = {
+ .read_resources = root_dev_read_resources,
+ .set_resources = root_dev_set_resources,
+ .enable_resources = root_dev_enable_resources,
+ .init = mainboard_init,
+#if !DEBUG
+ .scan_bus = root_dev_scan_bus,
+#else
+ .scan_bus = scan_root_bus,
+#endif
+ .enable = 0,
+};
+
+static void enable_dev(struct device *dev)
+{
+ dev->ops = &mainboard_operations;
+}
+struct chip_operations mainboard_island_aruma_ops = {
+ .enable_dev = enable_dev,
+};
+