1/* 2 * Simple routines for Celleb/Beat 3 * 4 * (C) Copyright 2006-2007 TOSHIBA CORPORATION 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21#include <linux/module.h> 22#include <linux/init.h> 23#include <linux/err.h> 24#include <linux/rtc.h> 25#include <linux/interrupt.h> 26#include <linux/irqreturn.h> 27#include <linux/reboot.h> 28 29#include <asm/hvconsole.h> 30#include <asm/time.h> 31#include <asm/machdep.h> 32#include <asm/firmware.h> 33 34#include "beat_wrapper.h" 35#include "beat.h" 36#include "beat_interrupt.h" 37 38static int beat_pm_poweroff_flag; 39 40void beat_restart(char *cmd) 41{ 42 beat_shutdown_logical_partition(!beat_pm_poweroff_flag); 43} 44 45void beat_power_off(void) 46{ 47 beat_shutdown_logical_partition(0); 48} 49 50u64 beat_halt_code = 0x1000000000000000UL; 51EXPORT_SYMBOL(beat_halt_code); 52 53void beat_halt(void) 54{ 55 beat_shutdown_logical_partition(beat_halt_code); 56} 57 58int beat_set_rtc_time(struct rtc_time *rtc_time) 59{ 60 u64 tim; 61 tim = mktime(rtc_time->tm_year+1900, 62 rtc_time->tm_mon+1, rtc_time->tm_mday, 63 rtc_time->tm_hour, rtc_time->tm_min, rtc_time->tm_sec); 64 if (beat_rtc_write(tim)) 65 return -1; 66 return 0; 67} 68 69void beat_get_rtc_time(struct rtc_time *rtc_time) 70{ 71 u64 tim; 72 73 if (beat_rtc_read(&tim)) 74 tim = 0; 75 to_tm(tim, rtc_time); 76 rtc_time->tm_year -= 1900; 77 rtc_time->tm_mon -= 1; 78} 79 80#define BEAT_NVRAM_SIZE 4096 81 82ssize_t beat_nvram_read(char *buf, size_t count, loff_t *index) 83{ 84 unsigned int i; 85 unsigned long len; 86 char *p = buf; 87 88 if (*index >= BEAT_NVRAM_SIZE) 89 return -ENODEV; 90 i = *index; 91 if (i + count > BEAT_NVRAM_SIZE) 92 count = BEAT_NVRAM_SIZE - i; 93 94 for (; count != 0; count -= len) { 95 len = count; 96 if (len > BEAT_NVRW_CNT) 97 len = BEAT_NVRW_CNT; 98 if (beat_eeprom_read(i, len, p)) 99 return -EIO; 100 101 p += len; 102 i += len; 103 } 104 *index = i; 105 return p - buf; 106} 107 108ssize_t beat_nvram_write(char *buf, size_t count, loff_t *index) 109{ 110 unsigned int i; 111 unsigned long len; 112 char *p = buf; 113 114 if (*index >= BEAT_NVRAM_SIZE) 115 return -ENODEV; 116 i = *index; 117 if (i + count > BEAT_NVRAM_SIZE) 118 count = BEAT_NVRAM_SIZE - i; 119 120 for (; count != 0; count -= len) { 121 len = count; 122 if (len > BEAT_NVRW_CNT) 123 len = BEAT_NVRW_CNT; 124 if (beat_eeprom_write(i, len, p)) 125 return -EIO; 126 127 p += len; 128 i += len; 129 } 130 *index = i; 131 return p - buf; 132} 133 134ssize_t beat_nvram_get_size(void) 135{ 136 return BEAT_NVRAM_SIZE; 137} 138 139int beat_set_xdabr(unsigned long dabr) 140{ 141 if (beat_set_dabr(dabr, DABRX_KERNEL | DABRX_USER)) 142 return -1; 143 return 0; 144} 145 146int64_t beat_get_term_char(u64 vterm, u64 *len, u64 *t1, u64 *t2) 147{ 148 u64 db[2]; 149 s64 ret; 150 151 ret = beat_get_characters_from_console(vterm, len, (u8 *)db); 152 if (ret == 0) { 153 *t1 = db[0]; 154 *t2 = db[1]; 155 } 156 return ret; 157} 158EXPORT_SYMBOL(beat_get_term_char); 159 160int64_t beat_put_term_char(u64 vterm, u64 len, u64 t1, u64 t2) 161{ 162 u64 db[2]; 163 164 db[0] = t1; 165 db[1] = t2; 166 return beat_put_characters_to_console(vterm, len, (u8 *)db); 167} 168EXPORT_SYMBOL(beat_put_term_char); 169 170void beat_power_save(void) 171{ 172 beat_pause(0); 173} 174 175#ifdef CONFIG_KEXEC 176void beat_kexec_cpu_down(int crash, int secondary) 177{ 178 beatic_deinit_IRQ(); 179} 180#endif 181 182static irqreturn_t beat_power_event(int virq, void *arg) 183{ 184 printk(KERN_DEBUG "Beat: power button pressed\n"); 185 beat_pm_poweroff_flag = 1; 186 ctrl_alt_del(); 187 return IRQ_HANDLED; 188} 189 190static irqreturn_t beat_reset_event(int virq, void *arg) 191{ 192 printk(KERN_DEBUG "Beat: reset button pressed\n"); 193 beat_pm_poweroff_flag = 0; 194 ctrl_alt_del(); 195 return IRQ_HANDLED; 196} 197 198static struct beat_event_list { 199 const char *typecode; 200 irq_handler_t handler; 201 unsigned int virq; 202} beat_event_list[] = { 203 { "power", beat_power_event, 0 }, 204 { "reset", beat_reset_event, 0 }, 205}; 206 207static int __init beat_register_event(void) 208{ 209 u64 path[4], data[2]; 210 int rc, i; 211 unsigned int virq; 212 213 for (i = 0; i < ARRAY_SIZE(beat_event_list); i++) { 214 struct beat_event_list *ev = &beat_event_list[i]; 215 216 if (beat_construct_event_receive_port(data) != 0) { 217 printk(KERN_ERR "Beat: " 218 "cannot construct event receive port for %s\n", 219 ev->typecode); 220 return -EINVAL; 221 } 222 223 virq = irq_create_mapping(NULL, data[0]); 224 if (virq == NO_IRQ) { 225 printk(KERN_ERR "Beat: failed to get virtual IRQ" 226 " for event receive port for %s\n", 227 ev->typecode); 228 beat_destruct_event_receive_port(data[0]); 229 return -EIO; 230 } 231 ev->virq = virq; 232 233 rc = request_irq(virq, ev->handler, IRQF_DISABLED, 234 ev->typecode, NULL); 235 if (rc != 0) { 236 printk(KERN_ERR "Beat: failed to request virtual IRQ" 237 " for event receive port for %s\n", 238 ev->typecode); 239 beat_destruct_event_receive_port(data[0]); 240 return rc; 241 } 242 243 path[0] = 0x1000000065780000ul; /* 1,ex */ 244 path[1] = 0x627574746f6e0000ul; /* button */ 245 path[2] = 0; 246 strncpy((char *)&path[2], ev->typecode, 8); 247 path[3] = 0; 248 data[1] = 0; 249 250 beat_create_repository_node(path, data); 251 } 252 return 0; 253} 254 255static int __init beat_event_init(void) 256{ 257 if (!firmware_has_feature(FW_FEATURE_BEAT)) 258 return -EINVAL; 259 260 beat_pm_poweroff_flag = 0; 261 return beat_register_event(); 262} 263 264device_initcall(beat_event_init); 265