-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
powerpc/powernv: Add RTC and NVRAM support plus RTAS fallbacks
Implements OPAL RTC and NVRAM support and wire all that up to the powernv platform. We use RTAS for RTC as a fallback if available. Using RTAS for nvram is not supported yet, pending some rework/cleanup and generalization of the pSeries & CHRP code. We also use RTAS fallbacks for power off and reboot Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
- Loading branch information
Benjamin Herrenschmidt
committed
Sep 20, 2011
1 parent
ec27329
commit 628daa8
Showing
5 changed files
with
229 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
obj-y += setup.o opal-takeover.o opal-wrappers.o opal.o | ||
obj-y += opal-rtc.o opal-nvram.o | ||
|
||
obj-$(CONFIG_SMP) += smp.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
* PowerNV nvram code. | ||
* | ||
* Copyright 2011 IBM Corp. | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation; either version | ||
* 2 of the License, or (at your option) any later version. | ||
*/ | ||
|
||
#define DEBUG | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/init.h> | ||
#include <linux/of.h> | ||
|
||
#include <asm/opal.h> | ||
#include <asm/machdep.h> | ||
|
||
static unsigned int nvram_size; | ||
|
||
static ssize_t opal_nvram_size(void) | ||
{ | ||
return nvram_size; | ||
} | ||
|
||
static ssize_t opal_nvram_read(char *buf, size_t count, loff_t *index) | ||
{ | ||
s64 rc; | ||
int off; | ||
|
||
if (*index >= nvram_size) | ||
return 0; | ||
off = *index; | ||
if ((off + count) > nvram_size) | ||
count = nvram_size - off; | ||
rc = opal_read_nvram(__pa(buf), count, off); | ||
if (rc != OPAL_SUCCESS) | ||
return -EIO; | ||
*index += count; | ||
return count; | ||
} | ||
|
||
static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index) | ||
{ | ||
s64 rc = OPAL_BUSY; | ||
int off; | ||
|
||
if (*index >= nvram_size) | ||
return 0; | ||
off = *index; | ||
if ((off + count) > nvram_size) | ||
count = nvram_size - off; | ||
|
||
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { | ||
rc = opal_write_nvram(__pa(buf), count, off); | ||
if (rc == OPAL_BUSY_EVENT) | ||
opal_poll_events(NULL); | ||
} | ||
*index += count; | ||
return count; | ||
} | ||
|
||
void __init opal_nvram_init(void) | ||
{ | ||
struct device_node *np; | ||
const u32 *nbytes_p; | ||
|
||
np = of_find_compatible_node(NULL, NULL, "ibm,opal-nvram"); | ||
if (np == NULL) | ||
return; | ||
|
||
nbytes_p = of_get_property(np, "#bytes", NULL); | ||
if (!nbytes_p) { | ||
of_node_put(np); | ||
return; | ||
} | ||
nvram_size = *nbytes_p; | ||
|
||
printk(KERN_INFO "OPAL nvram setup, %u bytes\n", nvram_size); | ||
of_node_put(np); | ||
|
||
ppc_md.nvram_read = opal_nvram_read; | ||
ppc_md.nvram_write = opal_nvram_write; | ||
ppc_md.nvram_size = opal_nvram_size; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/* | ||
* PowerNV Real Time Clock. | ||
* | ||
* Copyright 2011 IBM Corp. | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation; either version | ||
* 2 of the License, or (at your option) any later version. | ||
*/ | ||
|
||
|
||
#include <linux/kernel.h> | ||
#include <linux/time.h> | ||
#include <linux/bcd.h> | ||
#include <linux/rtc.h> | ||
#include <linux/delay.h> | ||
|
||
#include <asm/opal.h> | ||
#include <asm/firmware.h> | ||
|
||
static void opal_to_tm(u32 y_m_d, u64 h_m_s_ms, struct rtc_time *tm) | ||
{ | ||
tm->tm_year = ((bcd2bin(y_m_d >> 24) * 100) + | ||
bcd2bin((y_m_d >> 16) & 0xff)) - 1900; | ||
tm->tm_mon = bcd2bin((y_m_d >> 8) & 0xff) - 1; | ||
tm->tm_mday = bcd2bin(y_m_d & 0xff); | ||
tm->tm_hour = bcd2bin((h_m_s_ms >> 56) & 0xff); | ||
tm->tm_min = bcd2bin((h_m_s_ms >> 48) & 0xff); | ||
tm->tm_sec = bcd2bin((h_m_s_ms >> 40) & 0xff); | ||
|
||
GregorianDay(tm); | ||
} | ||
|
||
unsigned long __init opal_get_boot_time(void) | ||
{ | ||
struct rtc_time tm; | ||
u32 y_m_d; | ||
u64 h_m_s_ms; | ||
long rc = OPAL_BUSY; | ||
|
||
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { | ||
rc = opal_rtc_read(&y_m_d, &h_m_s_ms); | ||
if (rc == OPAL_BUSY_EVENT) | ||
opal_poll_events(NULL); | ||
else | ||
mdelay(10); | ||
} | ||
if (rc != OPAL_SUCCESS) | ||
return 0; | ||
opal_to_tm(y_m_d, h_m_s_ms, &tm); | ||
return mktime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, | ||
tm.tm_hour, tm.tm_min, tm.tm_sec); | ||
} | ||
|
||
void opal_get_rtc_time(struct rtc_time *tm) | ||
{ | ||
long rc = OPAL_BUSY; | ||
u32 y_m_d; | ||
u64 h_m_s_ms; | ||
|
||
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { | ||
rc = opal_rtc_read(&y_m_d, &h_m_s_ms); | ||
if (rc == OPAL_BUSY_EVENT) | ||
opal_poll_events(NULL); | ||
else | ||
mdelay(10); | ||
} | ||
if (rc != OPAL_SUCCESS) | ||
return; | ||
opal_to_tm(y_m_d, h_m_s_ms, tm); | ||
} | ||
|
||
int opal_set_rtc_time(struct rtc_time *tm) | ||
{ | ||
long rc = OPAL_BUSY; | ||
u32 y_m_d = 0; | ||
u64 h_m_s_ms = 0; | ||
|
||
y_m_d |= ((u32)bin2bcd((tm->tm_year + 1900) / 100)) << 24; | ||
y_m_d |= ((u32)bin2bcd((tm->tm_year + 1900) % 100)) << 16; | ||
y_m_d |= ((u32)bin2bcd((tm->tm_mon + 1))) << 8; | ||
y_m_d |= ((u32)bin2bcd(tm->tm_mday)); | ||
|
||
h_m_s_ms |= ((u64)bin2bcd(tm->tm_hour)) << 56; | ||
h_m_s_ms |= ((u64)bin2bcd(tm->tm_min)) << 48; | ||
h_m_s_ms |= ((u64)bin2bcd(tm->tm_sec)) << 40; | ||
|
||
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { | ||
rc = opal_rtc_write(y_m_d, h_m_s_ms); | ||
if (rc == OPAL_BUSY_EVENT) | ||
opal_poll_events(NULL); | ||
else | ||
mdelay(10); | ||
} | ||
return rc == OPAL_SUCCESS ? 0 : -EIO; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters