summaryrefslogtreecommitdiffstats
path: root/sys/powerpc/powermac/smu.c
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2010-03-23 03:14:44 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2010-03-23 03:14:44 +0000
commitbbf5ab2a3952a5c4354849865f12845751a696fd (patch)
treeed01872a037bb02b93fe09e25506a6a9bb3aa2e3 /sys/powerpc/powermac/smu.c
parenta4998a854d601c5a59c9f51479188de6d29c8919 (diff)
downloadFreeBSD-src-bbf5ab2a3952a5c4354849865f12845751a696fd.zip
FreeBSD-src-bbf5ab2a3952a5c4354849865f12845751a696fd.tar.gz
Get nexus(4) out of the RTC business. The interface used by nexus(4)
in Open Firmware was Apple-specific, and we have complete coverage of Apple system controllers, so move RTC responsibilities into the system controller drivers. This avoids interesting problems from manipulating these devices through Open Firmware behind the backs of their drivers. Obtained from: NetBSD MFC after: 2 weeks
Diffstat (limited to 'sys/powerpc/powermac/smu.c')
-rw-r--r--sys/powerpc/powermac/smu.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/sys/powerpc/powermac/smu.c b/sys/powerpc/powermac/smu.c
index 6754b3b..1001876 100644
--- a/sys/powerpc/powermac/smu.c
+++ b/sys/powerpc/powermac/smu.c
@@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/conf.h>
#include <sys/cpu.h>
+#include <sys/clock.h>
#include <sys/ctype.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
@@ -51,6 +52,8 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus.h>
#include <powerpc/powermac/macgpiovar.h>
+#include "clock_if.h"
+
struct smu_cmd {
volatile uint8_t cmd;
uint8_t len;
@@ -140,6 +143,10 @@ static int smu_attach(device_t);
static void smu_cpufreq_pre_change(device_t, const struct cf_level *level);
static void smu_cpufreq_post_change(device_t, const struct cf_level *level);
+/* clock interface */
+static int smu_gettime(device_t dev, struct timespec *ts);
+static int smu_settime(device_t dev, struct timespec *ts);
+
/* utility functions */
static int smu_run_cmd(device_t dev, struct smu_cmd *cmd, int wait);
static int smu_get_datablock(device_t dev, int8_t id, uint8_t *buf,
@@ -160,6 +167,10 @@ static device_method_t smu_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, smu_probe),
DEVMETHOD(device_attach, smu_attach),
+
+ /* Clock interface */
+ DEVMETHOD(clock_gettime, smu_gettime),
+ DEVMETHOD(clock_settime, smu_settime),
{ 0, 0 },
};
@@ -192,6 +203,9 @@ MALLOC_DEFINE(M_SMU, "smu", "SMU Sensor Information");
#define SMU_PWR_GET_POWERUP 0x00
#define SMU_PWR_SET_POWERUP 0x01
#define SMU_PWR_CLR_POWERUP 0x02
+#define SMU_RTC 0x8e
+#define SMU_RTC_GET 0x81
+#define SMU_RTC_SET 0x80
/* Power event types */
#define SMU_WAKEUP_KEYPRESS 0x01
@@ -349,6 +363,11 @@ smu_attach(device_t dev)
powerpc_config_intr(rman_get_start(sc->sc_doorbellirq),
INTR_TRIGGER_EDGE, INTR_POLARITY_LOW);
+ /*
+ * Connect RTC interface.
+ */
+ clock_register(dev, 1000);
+
return (0);
}
@@ -1043,3 +1062,51 @@ smu_server_mode(SYSCTL_HANDLER_ARGS)
return (smu_run_cmd(smu, &cmd, 1));
}
+static int
+smu_gettime(device_t dev, struct timespec *ts)
+{
+ struct smu_cmd cmd;
+ struct clocktime ct;
+
+ cmd.cmd = SMU_RTC;
+ cmd.len = 1;
+ cmd.data[0] = SMU_RTC_GET;
+
+ if (smu_run_cmd(dev, &cmd, 1) != 0)
+ return (ENXIO);
+
+ ct.nsec = 0;
+ ct.sec = bcd2bin(cmd.data[0]);
+ ct.min = bcd2bin(cmd.data[1]);
+ ct.hour = bcd2bin(cmd.data[2]);
+ ct.dow = bcd2bin(cmd.data[3]);
+ ct.day = bcd2bin(cmd.data[4]);
+ ct.mon = bcd2bin(cmd.data[5]);
+ ct.year = bcd2bin(cmd.data[6]) + 2000;
+
+ return (clock_ct_to_ts(&ct, ts));
+}
+
+static int
+smu_settime(device_t dev, struct timespec *ts)
+{
+ struct smu_cmd cmd;
+ struct clocktime ct;
+
+ cmd.cmd = SMU_RTC;
+ cmd.len = 8;
+ cmd.data[0] = SMU_RTC_SET;
+
+ clock_ts_to_ct(ts, &ct);
+
+ cmd.data[1] = bin2bcd(ct.sec);
+ cmd.data[2] = bin2bcd(ct.min);
+ cmd.data[3] = bin2bcd(ct.hour);
+ cmd.data[4] = bin2bcd(ct.dow);
+ cmd.data[5] = bin2bcd(ct.day);
+ cmd.data[6] = bin2bcd(ct.mon);
+ cmd.data[7] = bin2bcd(ct.year - 2000);
+
+ return (smu_run_cmd(dev, &cmd, 1));
+}
+
OpenPOWER on IntegriCloud