1 /* 2 * drivers/char/watchdog/booke_wdt.c 3 * 4 * Watchdog timer for PowerPC Book-E systems 5 * 6 * Author: Matthew McClintock 7 * Maintainer: Kumar Gala <galak@kernel.crashing.org> 8 * 9 * Copyright 2005 Freescale Semiconductor Inc. 10 * 11 * This program is free software; you can redistribute it and/or modify it 12 * under the terms of the GNU General Public License as published by the 13 * Free Software Foundation; either version 2 of the License, or (at your 14 * option) any later version. 15 */ 16 17 #include <linux/module.h> 18 #include <linux/fs.h> 19 #include <linux/miscdevice.h> 20 #include <linux/notifier.h> 21 #include <linux/watchdog.h> 22 23 #include <asm/reg_booke.h> 24 #include <asm/uaccess.h> 25 #include <asm/system.h> 26 27 /* If the kernel parameter wdt=1, the watchdog will be enabled at boot. 28 * Also, the wdt_period sets the watchdog timer period timeout. 29 * For E500 cpus the wdt_period sets which bit changing from 0->1 will 30 * trigger a watchog timeout. This watchdog timeout will occur 3 times, the 31 * first time nothing will happen, the second time a watchdog exception will 32 * occur, and the final time the board will reset. 33 */ 34 35 #ifdef CONFIG_FSL_BOOKE 36 #define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */ 37 #else 38 #define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */ 39 #endif /* for timing information */ 40 41 u32 booke_wdt_enabled = 0; 42 u32 booke_wdt_period = WDT_PERIOD_DEFAULT; 43 44 #ifdef CONFIG_FSL_BOOKE 45 #define WDTP(x) ((((63-x)&0x3)<<30)|(((63-x)&0x3c)<<15)) 46 #else 47 #define WDTP(x) (TCR_WP(x)) 48 #endif 49 50 /* 51 * booke_wdt_ping: 52 */ 53 static __inline__ void booke_wdt_ping(void) 54 { 55 mtspr(SPRN_TSR, TSR_ENW|TSR_WIS); 56 } 57 58 /* 59 * booke_wdt_enable: 60 */ 61 static __inline__ void booke_wdt_enable(void) 62 { 63 u32 val; 64 65 /* clear status before enabling watchdog */ 66 booke_wdt_ping(); 67 val = mfspr(SPRN_TCR); 68 val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period)); 69 70 mtspr(SPRN_TCR, val); 71 } 72 73 /* 74 * booke_wdt_write: 75 */ 76 static ssize_t booke_wdt_write (struct file *file, const char __user *buf, 77 size_t count, loff_t *ppos) 78 { 79 booke_wdt_ping(); 80 return count; 81 } 82 83 static struct watchdog_info ident = { 84 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, 85 .firmware_version = 0, 86 .identity = "PowerPC Book-E Watchdog", 87 }; 88 89 /* 90 * booke_wdt_ioctl: 91 */ 92 static int booke_wdt_ioctl (struct inode *inode, struct file *file, 93 unsigned int cmd, unsigned long arg) 94 { 95 u32 tmp = 0; 96 u32 __user *p = (u32 __user *)arg; 97 98 switch (cmd) { 99 case WDIOC_GETSUPPORT: 100 if (copy_to_user ((struct watchdog_info __user *) arg, &ident, 101 sizeof(struct watchdog_info))) 102 return -EFAULT; 103 case WDIOC_GETSTATUS: 104 return put_user(ident.options, p); 105 case WDIOC_GETBOOTSTATUS: 106 /* XXX: something is clearing TSR */ 107 tmp = mfspr(SPRN_TSR) & TSR_WRS(3); 108 /* returns 1 if last reset was caused by the WDT */ 109 return (tmp ? 1 : 0); 110 case WDIOC_KEEPALIVE: 111 booke_wdt_ping(); 112 return 0; 113 case WDIOC_SETTIMEOUT: 114 if (get_user(booke_wdt_period, p)) 115 return -EFAULT; 116 mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(booke_wdt_period)); 117 return 0; 118 case WDIOC_GETTIMEOUT: 119 return put_user(booke_wdt_period, p); 120 case WDIOC_SETOPTIONS: 121 if (get_user(tmp, p)) 122 return -EINVAL; 123 if (tmp == WDIOS_ENABLECARD) { 124 booke_wdt_ping(); 125 break; 126 } else 127 return -EINVAL; 128 return 0; 129 default: 130 return -ENOTTY; 131 } 132 133 return 0; 134 } 135 /* 136 * booke_wdt_open: 137 */ 138 static int booke_wdt_open (struct inode *inode, struct file *file) 139 { 140 if (booke_wdt_enabled == 0) { 141 booke_wdt_enabled = 1; 142 booke_wdt_enable(); 143 printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", 144 booke_wdt_period); 145 } 146 147 return nonseekable_open(inode, file); 148 } 149 150 static const struct file_operations booke_wdt_fops = { 151 .owner = THIS_MODULE, 152 .llseek = no_llseek, 153 .write = booke_wdt_write, 154 .ioctl = booke_wdt_ioctl, 155 .open = booke_wdt_open, 156 }; 157 158 static struct miscdevice booke_wdt_miscdev = { 159 .minor = WATCHDOG_MINOR, 160 .name = "watchdog", 161 .fops = &booke_wdt_fops, 162 }; 163 164 static void __exit booke_wdt_exit(void) 165 { 166 misc_deregister(&booke_wdt_miscdev); 167 } 168 169 /* 170 * booke_wdt_init: 171 */ 172 static int __init booke_wdt_init(void) 173 { 174 int ret = 0; 175 176 printk (KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n"); 177 ident.firmware_version = cur_cpu_spec->pvr_value; 178 179 ret = misc_register(&booke_wdt_miscdev); 180 if (ret) { 181 printk (KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n", 182 WATCHDOG_MINOR, ret); 183 return ret; 184 } 185 186 if (booke_wdt_enabled == 1) { 187 printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", 188 booke_wdt_period); 189 booke_wdt_enable(); 190 } 191 192 return ret; 193 } 194 device_initcall(booke_wdt_init); 195