# 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} $@
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}
#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"
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);
}
/* configure i2c pinmux */
omap3_padconf_init();
+
+ /* map memory for rtc */
+ omap3_rtc_init();
}
/*===========================================================================*
--- /dev/null
+/*
+ * 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 */
+}
--- /dev/null
+#ifndef __OMAP_RTC_H
+#define __OMAP_RTC_H
+
+void omap3_rtc_init(void);
+void omap3_rtc_run(void);
+
+#endif /* __OMAP_RTC_H */