diff options
Diffstat (limited to 'arch/powerpc/platforms/44x/warp.c')
| -rw-r--r-- | arch/powerpc/platforms/44x/warp.c | 276 |
1 files changed, 221 insertions, 55 deletions
diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c index da5b7b7599d..534574a97ec 100644 --- a/arch/powerpc/platforms/44x/warp.c +++ b/arch/powerpc/platforms/44x/warp.c @@ -1,7 +1,7 @@ /* * PIKA Warp(tm) board specific routines * - * Copyright (c) 2008 PIKA Technologies + * Copyright (c) 2008-2009 PIKA Technologies * Sean MacLennan <smaclennan@pikatech.com> * * This program is free software; you can redistribute it and/or modify it @@ -12,14 +12,19 @@ #include <linux/init.h> #include <linux/of_platform.h> #include <linux/kthread.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/of_gpio.h> +#include <linux/slab.h> +#include <linux/export.h> #include <asm/machdep.h> #include <asm/prom.h> #include <asm/udbg.h> #include <asm/time.h> #include <asm/uic.h> - -#include "44x.h" +#include <asm/ppc4xx.h> static __initdata struct of_device_id warp_of_bus[] = { @@ -40,7 +45,13 @@ static int __init warp_probe(void) { unsigned long root = of_get_flat_dt_root(); - return of_flat_dt_is_compatible(root, "pika,warp"); + if (!of_flat_dt_is_compatible(root, "pika,warp")) + return 0; + + /* For __dma_alloc_coherent */ + ISA_DMA_THRESHOLD = ~0L; + + return 1; } define_machine(warp) { @@ -49,66 +60,210 @@ define_machine(warp) { .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, - .restart = ppc44x_reset_system, + .restart = ppc4xx_reset_system, .calibrate_decr = generic_calibrate_decr, }; -#define LED_GREEN (0x80000000 >> 0) -#define LED_RED (0x80000000 >> 1) +static int __init warp_post_info(void) +{ + struct device_node *np; + void __iomem *fpga; + u32 post1, post2; + + /* Sighhhh... POST information is in the sd area. */ + np = of_find_compatible_node(NULL, NULL, "pika,fpga-sd"); + if (np == NULL) + return -ENOENT; + + fpga = of_iomap(np, 0); + of_node_put(np); + if (fpga == NULL) + return -ENOENT; + + post1 = in_be32(fpga + 0x40); + post2 = in_be32(fpga + 0x44); + + iounmap(fpga); + + if (post1 || post2) + printk(KERN_INFO "Warp POST %08x %08x\n", post1, post2); + else + printk(KERN_INFO "Warp POST OK\n"); + + return 0; +} + + +#ifdef CONFIG_SENSORS_AD7414 + +static LIST_HEAD(dtm_shutdown_list); +static void __iomem *dtm_fpga; +static unsigned green_led, red_led; + + +struct dtm_shutdown { + struct list_head list; + void (*func)(void *arg); + void *arg; +}; -/* This is for the power LEDs 1 = on, 0 = off, -1 = leave alone */ -void warp_set_power_leds(int green, int red) +int pika_dtm_register_shutdown(void (*func)(void *arg), void *arg) { - static void __iomem *gpio_base = NULL; - unsigned leds; - - if (gpio_base == NULL) { - struct device_node *np; - - /* Power LEDS are on the second GPIO controller */ - np = of_find_compatible_node(NULL, NULL, "ibm,gpio-440EP"); - if (np) - np = of_find_compatible_node(np, NULL, "ibm,gpio-440EP"); - if (np == NULL) { - printk(KERN_ERR __FILE__ ": Unable to find gpio\n"); - return; + struct dtm_shutdown *shutdown; + + shutdown = kmalloc(sizeof(struct dtm_shutdown), GFP_KERNEL); + if (shutdown == NULL) + return -ENOMEM; + + shutdown->func = func; + shutdown->arg = arg; + + list_add(&shutdown->list, &dtm_shutdown_list); + + return 0; +} + +int pika_dtm_unregister_shutdown(void (*func)(void *arg), void *arg) +{ + struct dtm_shutdown *shutdown; + + list_for_each_entry(shutdown, &dtm_shutdown_list, list) + if (shutdown->func == func && shutdown->arg == arg) { + list_del(&shutdown->list); + kfree(shutdown); + return 0; } - gpio_base = of_iomap(np, 0); - of_node_put(np); - if (gpio_base == NULL) { - printk(KERN_ERR __FILE__ ": Unable to map gpio"); - return; + return -EINVAL; +} + +static irqreturn_t temp_isr(int irq, void *context) +{ + struct dtm_shutdown *shutdown; + int value = 1; + + local_irq_disable(); + + gpio_set_value(green_led, 0); + + /* Run through the shutdown list. */ + list_for_each_entry(shutdown, &dtm_shutdown_list, list) + shutdown->func(shutdown->arg); + + printk(KERN_EMERG "\n\nCritical Temperature Shutdown\n\n"); + + while (1) { + if (dtm_fpga) { + unsigned reset = in_be32(dtm_fpga + 0x14); + out_be32(dtm_fpga + 0x14, reset); } + + gpio_set_value(red_led, value); + value ^= 1; + mdelay(500); } - leds = in_be32(gpio_base); + /* Not reached */ + return IRQ_HANDLED; +} + +static int pika_setup_leds(void) +{ + struct device_node *np, *child; - switch (green) { - case 0: leds &= ~LED_GREEN; break; - case 1: leds |= LED_GREEN; break; + np = of_find_compatible_node(NULL, NULL, "gpio-leds"); + if (!np) { + printk(KERN_ERR __FILE__ ": Unable to find leds\n"); + return -ENOENT; } - switch (red) { - case 0: leds &= ~LED_RED; break; - case 1: leds |= LED_RED; break; + + for_each_child_of_node(np, child) + if (strcmp(child->name, "green") == 0) + green_led = of_get_gpio(child, 0); + else if (strcmp(child->name, "red") == 0) + red_led = of_get_gpio(child, 0); + + of_node_put(np); + + return 0; +} + +static void pika_setup_critical_temp(struct device_node *np, + struct i2c_client *client) +{ + int irq, rc; + + /* Do this before enabling critical temp interrupt since we + * may immediately interrupt. + */ + pika_setup_leds(); + + /* These registers are in 1 degree increments. */ + i2c_smbus_write_byte_data(client, 2, 65); /* Thigh */ + i2c_smbus_write_byte_data(client, 3, 0); /* Tlow */ + + irq = irq_of_parse_and_map(np, 0); + if (irq == NO_IRQ) { + printk(KERN_ERR __FILE__ ": Unable to get ad7414 irq\n"); + return; } - out_be32(gpio_base, leds); + rc = request_irq(irq, temp_isr, 0, "ad7414", NULL); + if (rc) { + printk(KERN_ERR __FILE__ + ": Unable to request ad7414 irq %d = %d\n", irq, rc); + return; + } } -EXPORT_SYMBOL(warp_set_power_leds); +static inline void pika_dtm_check_fan(void __iomem *fpga) +{ + static int fan_state; + u32 fan = in_be32(fpga + 0x34) & (1 << 14); + + if (fan_state != fan) { + fan_state = fan; + if (fan) + printk(KERN_WARNING "Fan rotation error detected." + " Please check hardware.\n"); + } +} -#ifdef CONFIG_SENSORS_AD7414 static int pika_dtm_thread(void __iomem *fpga) { - extern int ad7414_get_temp(int index); + struct device_node *np; + struct i2c_client *client; + + np = of_find_compatible_node(NULL, NULL, "adi,ad7414"); + if (np == NULL) + return -ENOENT; + + client = of_find_i2c_device_by_node(np); + if (client == NULL) { + of_node_put(np); + return -ENOENT; + } + + pika_setup_critical_temp(np, client); + + of_node_put(np); + + printk(KERN_INFO "Warp DTM thread running.\n"); while (!kthread_should_stop()) { - int temp = ad7414_get_temp(0); + int val; - out_be32(fpga, temp); + val = i2c_smbus_read_word_data(client, 0); + if (val < 0) + dev_dbg(&client->dev, "DTM read temp failed.\n"); + else { + s16 temp = swab16(val); + out_be32(fpga + 0x20, temp); + } + + pika_dtm_check_fan(fpga); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); @@ -121,33 +276,44 @@ static int __init pika_dtm_start(void) { struct task_struct *dtm_thread; struct device_node *np; - struct resource res; - void __iomem *fpga; np = of_find_compatible_node(NULL, NULL, "pika,fpga"); if (np == NULL) return -ENOENT; - /* We do not call of_iomap here since it would map in the entire - * fpga space, which is over 8k. - */ - if (of_address_to_resource(np, 0, &res)) { - of_node_put(np); - return -ENOENT; - } + dtm_fpga = of_iomap(np, 0); of_node_put(np); - - fpga = ioremap(res.start, 0x24); - if (fpga == NULL) + if (dtm_fpga == NULL) return -ENOENT; - dtm_thread = kthread_run(pika_dtm_thread, fpga + 0x20, "pika-dtm"); + /* Must get post info before thread starts. */ + warp_post_info(); + + dtm_thread = kthread_run(pika_dtm_thread, dtm_fpga, "pika-dtm"); if (IS_ERR(dtm_thread)) { - iounmap(fpga); + iounmap(dtm_fpga); return PTR_ERR(dtm_thread); } return 0; } -device_initcall(pika_dtm_start); +machine_late_initcall(warp, pika_dtm_start); + +#else /* !CONFIG_SENSORS_AD7414 */ + +int pika_dtm_register_shutdown(void (*func)(void *arg), void *arg) +{ + return 0; +} + +int pika_dtm_unregister_shutdown(void (*func)(void *arg), void *arg) +{ + return 0; +} + +machine_late_initcall(warp, warp_post_info); + #endif + +EXPORT_SYMBOL(pika_dtm_register_shutdown); +EXPORT_SYMBOL(pika_dtm_unregister_shutdown); |
