Path: blob/master/arch/powerpc/platforms/cell/beat.c
10818 views
/*1* Simple routines for Celleb/Beat2*3* (C) Copyright 2006-2007 TOSHIBA CORPORATION4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License along16* with this program; if not, write to the Free Software Foundation, Inc.,17* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.18*/1920#include <linux/module.h>21#include <linux/init.h>22#include <linux/err.h>23#include <linux/rtc.h>24#include <linux/interrupt.h>25#include <linux/irqreturn.h>26#include <linux/reboot.h>2728#include <asm/hvconsole.h>29#include <asm/time.h>30#include <asm/machdep.h>31#include <asm/firmware.h>3233#include "beat_wrapper.h"34#include "beat.h"35#include "beat_interrupt.h"3637static int beat_pm_poweroff_flag;3839void beat_restart(char *cmd)40{41beat_shutdown_logical_partition(!beat_pm_poweroff_flag);42}4344void beat_power_off(void)45{46beat_shutdown_logical_partition(0);47}4849u64 beat_halt_code = 0x1000000000000000UL;50EXPORT_SYMBOL(beat_halt_code);5152void beat_halt(void)53{54beat_shutdown_logical_partition(beat_halt_code);55}5657int beat_set_rtc_time(struct rtc_time *rtc_time)58{59u64 tim;60tim = mktime(rtc_time->tm_year+1900,61rtc_time->tm_mon+1, rtc_time->tm_mday,62rtc_time->tm_hour, rtc_time->tm_min, rtc_time->tm_sec);63if (beat_rtc_write(tim))64return -1;65return 0;66}6768void beat_get_rtc_time(struct rtc_time *rtc_time)69{70u64 tim;7172if (beat_rtc_read(&tim))73tim = 0;74to_tm(tim, rtc_time);75rtc_time->tm_year -= 1900;76rtc_time->tm_mon -= 1;77}7879#define BEAT_NVRAM_SIZE 40968081ssize_t beat_nvram_read(char *buf, size_t count, loff_t *index)82{83unsigned int i;84unsigned long len;85char *p = buf;8687if (*index >= BEAT_NVRAM_SIZE)88return -ENODEV;89i = *index;90if (i + count > BEAT_NVRAM_SIZE)91count = BEAT_NVRAM_SIZE - i;9293for (; count != 0; count -= len) {94len = count;95if (len > BEAT_NVRW_CNT)96len = BEAT_NVRW_CNT;97if (beat_eeprom_read(i, len, p))98return -EIO;99100p += len;101i += len;102}103*index = i;104return p - buf;105}106107ssize_t beat_nvram_write(char *buf, size_t count, loff_t *index)108{109unsigned int i;110unsigned long len;111char *p = buf;112113if (*index >= BEAT_NVRAM_SIZE)114return -ENODEV;115i = *index;116if (i + count > BEAT_NVRAM_SIZE)117count = BEAT_NVRAM_SIZE - i;118119for (; count != 0; count -= len) {120len = count;121if (len > BEAT_NVRW_CNT)122len = BEAT_NVRW_CNT;123if (beat_eeprom_write(i, len, p))124return -EIO;125126p += len;127i += len;128}129*index = i;130return p - buf;131}132133ssize_t beat_nvram_get_size(void)134{135return BEAT_NVRAM_SIZE;136}137138int beat_set_xdabr(unsigned long dabr)139{140if (beat_set_dabr(dabr, DABRX_KERNEL | DABRX_USER))141return -1;142return 0;143}144145int64_t beat_get_term_char(u64 vterm, u64 *len, u64 *t1, u64 *t2)146{147u64 db[2];148s64 ret;149150ret = beat_get_characters_from_console(vterm, len, (u8 *)db);151if (ret == 0) {152*t1 = db[0];153*t2 = db[1];154}155return ret;156}157EXPORT_SYMBOL(beat_get_term_char);158159int64_t beat_put_term_char(u64 vterm, u64 len, u64 t1, u64 t2)160{161u64 db[2];162163db[0] = t1;164db[1] = t2;165return beat_put_characters_to_console(vterm, len, (u8 *)db);166}167EXPORT_SYMBOL(beat_put_term_char);168169void beat_power_save(void)170{171beat_pause(0);172}173174#ifdef CONFIG_KEXEC175void beat_kexec_cpu_down(int crash, int secondary)176{177beatic_deinit_IRQ();178}179#endif180181static irqreturn_t beat_power_event(int virq, void *arg)182{183printk(KERN_DEBUG "Beat: power button pressed\n");184beat_pm_poweroff_flag = 1;185ctrl_alt_del();186return IRQ_HANDLED;187}188189static irqreturn_t beat_reset_event(int virq, void *arg)190{191printk(KERN_DEBUG "Beat: reset button pressed\n");192beat_pm_poweroff_flag = 0;193ctrl_alt_del();194return IRQ_HANDLED;195}196197static struct beat_event_list {198const char *typecode;199irq_handler_t handler;200unsigned int virq;201} beat_event_list[] = {202{ "power", beat_power_event, 0 },203{ "reset", beat_reset_event, 0 },204};205206static int __init beat_register_event(void)207{208u64 path[4], data[2];209int rc, i;210unsigned int virq;211212for (i = 0; i < ARRAY_SIZE(beat_event_list); i++) {213struct beat_event_list *ev = &beat_event_list[i];214215if (beat_construct_event_receive_port(data) != 0) {216printk(KERN_ERR "Beat: "217"cannot construct event receive port for %s\n",218ev->typecode);219return -EINVAL;220}221222virq = irq_create_mapping(NULL, data[0]);223if (virq == NO_IRQ) {224printk(KERN_ERR "Beat: failed to get virtual IRQ"225" for event receive port for %s\n",226ev->typecode);227beat_destruct_event_receive_port(data[0]);228return -EIO;229}230ev->virq = virq;231232rc = request_irq(virq, ev->handler, IRQF_DISABLED,233ev->typecode, NULL);234if (rc != 0) {235printk(KERN_ERR "Beat: failed to request virtual IRQ"236" for event receive port for %s\n",237ev->typecode);238beat_destruct_event_receive_port(data[0]);239return rc;240}241242path[0] = 0x1000000065780000ul; /* 1,ex */243path[1] = 0x627574746f6e0000ul; /* button */244path[2] = 0;245strncpy((char *)&path[2], ev->typecode, 8);246path[3] = 0;247data[1] = 0;248249beat_create_repository_node(path, data);250}251return 0;252}253254static int __init beat_event_init(void)255{256if (!firmware_has_feature(FW_FEATURE_BEAT))257return -EINVAL;258259beat_pm_poweroff_flag = 0;260return beat_register_event();261}262263device_initcall(beat_event_init);264265266