]> Zhao Yanbai Git Server - minix.git/commitdiff
kernel: add support for am335x PMIC-base power-off 98/698/2
authorThomas Cort <tcort@minix3.org>
Fri, 2 Aug 2013 14:10:55 +0000 (10:10 -0400)
committerThomas Cort <tcort@minix3.org>
Mon, 5 Aug 2013 14:22:59 +0000 (10:22 -0400)
AM335X SoCs support power-off via a power management
chip (PMIC). An alarm in the real time clock is used
to trigger the PMIC to cut the power.

To ensure the alarm goes off when the system is in
a safe state, the RTC is frozen when the alarm is
set. At the last moment, the kernel unfreezes the RTC
to let the alarm go off.

This patch adds a mini driver for unfreezing the RTC
as well as code to handle RBT_POWEROFF on Minix/arm.

Change-Id: I7d48e75791e3a81bdd2f7704997193a269409fe8

kernel/arch/earm/Makefile.inc
kernel/arch/earm/arch_reset.c
kernel/arch/earm/arch_system.c
kernel/arch/earm/omap_rtc.c [new file with mode: 0644]
kernel/arch/earm/omap_rtc.h [new file with mode: 0644]

index ca94480a876d47fcd81b38bae024725aa5e3b036..7d048fd85143579a327691e5d8096776d5514189 100644 (file)
@@ -52,7 +52,7 @@ CPPFLAGS.findfp.c+= -I ${NETBSDSRCDIR}/lib/libc/include
 # that must live in their own unique namespace.
 #
 .for unpaged_obj in head.o pre_init.o direct_tty_utils.o \
-       pg_utils.o klib.o omap_serial.o utility.o arch_reset.o \
+       pg_utils.o klib.o omap_serial.o omap_rtc.o utility.o arch_reset.o \
        ${MINLIB_OBJS_UNPAGED} ${MINC_OBJS_UNPAGED} ${SYS_OBJS_UNPAGED}
 unpaged_${unpaged_obj}: ${unpaged_obj}
        ${OBJCOPY} --prefix-symbols=__k_unpaged_ ${.OBJDIR}/${unpaged_obj} $@
@@ -63,8 +63,8 @@ ORIG_UNPAGED_OBJS += ${unpaged_obj}
 CLEANFILES+= ${ORIG_UNPAGED_OBJS}
 
 SRCS+= mpx.S arch_clock.c arch_do_vmctl.c arch_system.c \
-       omap_serial.c omap_timer.c omap_padconf.c omap_intr.c exception.c \
-       klib.S memory.c \
+       omap_serial.c omap_timer.c omap_padconf.c omap_intr.c omap_rtc.c \
+       exception.c klib.S memory.c \
        protect.c direct_tty_utils.c arch_reset.c \
        pg_utils.c phys_copy.S phys_memset.S exc.S
 OBJS.kernel+=  ${UNPAGED_OBJS}
index 2269711f6379068a9324544525b6d9c07dbbb8b3..fc0d3a623444d037dba6dec20607313a29ed0eaf 100644 (file)
@@ -8,12 +8,15 @@
 #include <assert.h>
 #include <signal.h>
 #include <machine/vm.h>
+#include <io.h>
 
+#include <minix/reboot.h>
 #include <minix/u64.h>
 
 #include "archconst.h"
 #include "arch_proto.h"
 #include "serial.h"
+#include "omap_rtc.h"
 #include "kernel/proc.h"
 #include "kernel/debug.h"
 #include "direct_utils.h"
@@ -34,9 +37,48 @@ reset(void)
     while (1);
 }
 
+void
+poweroff(void)
+{
+
+/*
+ * The am335x can signal an external power management chip to cut the power
+ * by toggling the PMIC_POWER_EN pin. It might fail if there isn't an
+ * external PMIC or if the PMIC hasn't been configured to respond to toggles.
+ * The only way to pull the pin low is via ALARM2 (see TRM 20.3.3.8).
+ * At this point PM should have already signaled readclock to set the alarm.
+ */
+#ifdef AM335X
+
+       /* Powers down the SoC within 3 seconds */
+       direct_print("PMIC Power-Off in 3 Seconds\n");
+
+       /* rtc was frozen to prevent premature power-off, unfreeze it now */
+       omap3_rtc_run();
+
+       /* wait for the alarm to go off and PMIC to disable power to SoC */
+       while (1);
+
+#endif /* AM335X */
+
+       /* fallback option: hang */
+       direct_print("Unable to power-off this device.");
+       while (1);
+}
+
 __dead void
 arch_shutdown(int how)
 {
+       switch (how) {
+
+       case RBT_POWEROFF:
+               /* Power off if possible, hang otherwise */
+               poweroff();
+               NOT_REACHABLE;
+
+       default:
+               break;
+       }
        while (1);
 }
 
index 03c0fa280852e751a34ec05e542c0fc23fcab346..0f0fc3a0bb8c1ba3a3ed67e2c168aa3319415d0b 100644 (file)
@@ -128,6 +128,9 @@ void arch_init(void)
 
        /* configure i2c pinmux */
        omap3_padconf_init();
+
+       /* map memory for rtc */
+       omap3_rtc_init();
 }
 
 /*===========================================================================*
diff --git a/kernel/arch/earm/omap_rtc.c b/kernel/arch/earm/omap_rtc.c
new file mode 100644 (file)
index 0000000..849d77f
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * This is a mini driver for the AM335X Real Time Clock. The majority of the
+ * work is done in user space in readclock, but for power-off the clock needs
+ * to be put into run mode at the last possible moment in arch_reset.c. This
+ * driver just implements mapping the memory and re-starting the clock.
+ */
+
+#include <assert.h>
+#include <sys/types.h>
+#include <machine/cpu.h>
+#include <minix/type.h>
+#include <io.h>
+
+#include "kernel/kernel.h"
+#include "kernel/proc.h"
+#include "kernel/vm.h"
+#include "kernel/proto.h"
+#include "arch_proto.h"
+#include "omap_rtc.h"
+
+#define RTC_SS_BASE 0x44e3e000
+#define RTC_SS_SIZE 0x1000
+#define RTC_CTRL_REG 0x40
+#define RTC_CTRL_RTC_STOP_BIT 0
+
+struct omap_rtc
+{
+       vir_bytes base;
+       vir_bytes size;
+};
+
+static struct omap_rtc omap_rtc = {
+       .base = RTC_SS_BASE,
+       .size = RTC_SS_SIZE
+};
+
+static kern_phys_map rtc_phys_map;
+
+void
+omap3_rtc_init(void)
+{
+#ifdef AM335X
+       kern_phys_map_ptr(omap_rtc.base, omap_rtc.size, &rtc_phys_map,
+           &omap_rtc.base);
+#endif /* AM335X */
+}
+
+void
+omap3_rtc_run(void)
+{
+#ifdef AM335X
+       /* Setting the stop bit starts the RTC running */
+       mmio_set((omap_rtc.base + RTC_CTRL_REG), (1 << RTC_CTRL_RTC_STOP_BIT));
+#endif /* AM335X */
+}
diff --git a/kernel/arch/earm/omap_rtc.h b/kernel/arch/earm/omap_rtc.h
new file mode 100644 (file)
index 0000000..cbed3a5
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __OMAP_RTC_H
+#define __OMAP_RTC_H
+
+void omap3_rtc_init(void);
+void omap3_rtc_run(void);
+
+#endif /* __OMAP_RTC_H */