Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/arm/ti Add TI OMAP watchdog timer driver.
details: https://anonhg.NetBSD.org/src/rev/34ea9ba59623
branches: trunk
changeset: 465603:34ea9ba59623
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Fri Nov 29 20:54:00 2019 +0000
description:
Add TI OMAP watchdog timer driver.
diffstat:
sys/arch/arm/ti/am3_prcm.c | 6 +-
sys/arch/arm/ti/files.ti | 7 +-
sys/arch/arm/ti/ti_wdt.c | 259 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 269 insertions(+), 3 deletions(-)
diffs (truncated from 311 to 300 lines):
diff -r aaee1a5a56a6 -r 34ea9ba59623 sys/arch/arm/ti/am3_prcm.c
--- a/sys/arch/arm/ti/am3_prcm.c Fri Nov 29 20:50:54 2019 +0000
+++ b/sys/arch/arm/ti/am3_prcm.c Fri Nov 29 20:54:00 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: am3_prcm.c,v 1.11 2019/11/27 23:02:54 jmcneill Exp $ */
+/* $NetBSD: am3_prcm.c,v 1.12 2019/11/29 20:54:00 jmcneill Exp $ */
/*-
* Copyright (c) 2017 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -28,7 +28,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: am3_prcm.c,v 1.11 2019/11/27 23:02:54 jmcneill Exp $");
+__KERNEL_RCSID(1, "$NetBSD: am3_prcm.c,v 1.12 2019/11/29 20:54:00 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -169,6 +169,8 @@
AM3_PRCM_HWMOD_PER("timer6", 0xf0, "FIXED_24MHZ"),
AM3_PRCM_HWMOD_PER("timer7", 0x7c, "FIXED_24MHZ"),
+ AM3_PRCM_HWMOD_WKUP("wd_timer2", 0xd4, "FIXED_32K"),
+
AM3_PRCM_HWMOD_PER("mmc1", 0x3c, "MMC_CLK"),
AM3_PRCM_HWMOD_PER("mmc2", 0xf4, "MMC_CLK"),
AM3_PRCM_HWMOD_PER("mmc3", 0xf8, "MMC_CLK"),
diff -r aaee1a5a56a6 -r 34ea9ba59623 sys/arch/arm/ti/files.ti
--- a/sys/arch/arm/ti/files.ti Fri Nov 29 20:50:54 2019 +0000
+++ b/sys/arch/arm/ti/files.ti Fri Nov 29 20:54:00 2019 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: files.ti,v 1.20 2019/11/03 22:59:06 jmcneill Exp $
+# $NetBSD: files.ti,v 1.21 2019/11/29 20:54:00 jmcneill Exp $
#
file arch/arm/ti/ti_cpufreq.c soc_ti
@@ -131,6 +131,11 @@
attach omapnand at fdt
file arch/arm/ti/omap2_nand.c omapnand
+# Watchdog timer
+device tiwdt: sysmon_wdog
+attach tiwdt at fdt with ti_wdt
+file arch/arm/ti/ti_wdt.c ti_wdt
+
# SOC parameters
defflag opt_soc.h SOC_TI
defflag opt_soc.h SOC_AM33XX: SOC_TI
diff -r aaee1a5a56a6 -r 34ea9ba59623 sys/arch/arm/ti/ti_wdt.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/ti/ti_wdt.c Fri Nov 29 20:54:00 2019 +0000
@@ -0,0 +1,259 @@
+/* $NetBSD: ti_wdt.c,v 1.1 2019/11/29 20:54:00 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2019 Jared McNeill <jmcneill%invisible.ca@localhost>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: ti_wdt.c,v 1.1 2019/11/29 20:54:00 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/device.h>
+#include <sys/wdog.h>
+
+#include <dev/sysmon/sysmonvar.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#include <arm/ti/ti_prcm.h>
+
+#define WDT_WDSC 0x10
+#define WDSC_SOFTRESET __BIT(1)
+#define WDT_WDST 0x14
+#define WDT_WISR 0x18
+#define WDT_WIER 0x1c
+#define WDT_WCLR 0x24
+#define WCLR_PRE __BIT(5)
+#define WCLR_PTV __BITS(4,2)
+#define WDT_WCRR 0x28
+#define WDT_WLDR 0x2c
+#define WDT_WTGR 0x30
+#define WDT_WWPS 0x34
+#define WWPS_W_PEND_WDLY __BIT(5)
+#define WWPS_W_PEND_WSPR __BIT(4)
+#define WWPS_W_PEND_WTGR __BIT(3)
+#define WWPS_W_PEND_WLDR __BIT(2)
+#define WWPS_W_PEND_WCRR __BIT(1)
+#define WWPS_W_PEND_WCLR __BIT(0)
+#define WWPS_W_PEND_MASK __BITS(5,0)
+#define WDT_WDLY 0x44
+#define WDT_WSPR 0x48
+#define WDT_WIRQSTATRAW 0x54
+#define WDT_WIRQSTAT 0x58
+#define WDT_WIRQENSET 0x5c
+#define WDT_WIRQENCLR 0x60
+#define WIRQ_EVENT_DLY __BIT(1)
+#define WIRQ_EVENT_OVF __BIT(0)
+
+#define WATCHDOG_PERIOD_DEFAULT 10
+
+static const char * compatible[] = {
+ "ti,omap3-wdt",
+ NULL
+};
+
+struct ti_wdt_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
+
+ struct sysmon_wdog sc_wdog;
+ u_int sc_rate;
+};
+
+#define RD4(sc, reg) \
+ bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define WR4(sc, reg, val) \
+ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+static void
+ti_wdt_sync(struct ti_wdt_softc *sc, uint32_t mask)
+{
+ uint32_t val;
+ int retry;
+
+ for (retry = 10000; retry > 0; retry--) {
+ val = RD4(sc, WDT_WWPS);
+ if ((val & mask) == 0)
+ return;
+ }
+
+ aprint_error_dev(sc->sc_dev,
+ "reg sync timeout, mask=%#x, wwps=%#x\n", mask, val);
+}
+
+static void
+ti_wdt_sync_all(struct ti_wdt_softc *sc)
+{
+ ti_wdt_sync(sc, WWPS_W_PEND_MASK);
+}
+
+static int
+ti_wdt_reset(struct ti_wdt_softc *sc)
+{
+ uint32_t val;
+ int retry;
+
+ val = RD4(sc, WDT_WDSC);
+ val |= WDSC_SOFTRESET;
+ WR4(sc, WDT_WDSC, val);
+ for (retry = 10000; retry > 0; retry--) {
+ val = RD4(sc, WDT_WDSC);
+ if ((val & WDSC_SOFTRESET) == 0)
+ return 0;
+ delay(10);
+ }
+
+ return EIO;
+}
+
+static void
+ti_wdt_stop(struct ti_wdt_softc *sc)
+{
+ WR4(sc, WDT_WSPR, 0xaaaa);
+ ti_wdt_sync(sc, WWPS_W_PEND_WSPR);
+ WR4(sc, WDT_WSPR, 0x5555);
+ ti_wdt_sync(sc, WWPS_W_PEND_WSPR);
+}
+
+static void
+ti_wdt_start(struct ti_wdt_softc *sc)
+{
+ WR4(sc, WDT_WSPR, 0xbbbb);
+ ti_wdt_sync(sc, WWPS_W_PEND_WSPR);
+ WR4(sc, WDT_WSPR, 0x4444);
+ ti_wdt_sync(sc, WWPS_W_PEND_WSPR);
+}
+
+static int
+ti_wdt_setmode(struct sysmon_wdog *smw)
+{
+ struct ti_wdt_softc * const sc = smw->smw_cookie;
+ uint32_t counter_val;
+
+ if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
+ ti_wdt_stop(sc);
+ return 0;
+ }
+
+ if (smw->smw_period == WDOG_PERIOD_DEFAULT)
+ sc->sc_wdog.smw_period = WATCHDOG_PERIOD_DEFAULT;
+ else
+ sc->sc_wdog.smw_period = smw->smw_period;
+
+ if (sc->sc_wdog.smw_period == 0)
+ counter_val = ~0u;
+ else
+ counter_val = ~(sc->sc_wdog.smw_period * sc->sc_rate / 2);
+
+ ti_wdt_stop(sc);
+ ti_wdt_sync_all(sc);
+
+ WR4(sc, WDT_WCLR, WCLR_PRE | __SHIFTIN(1, WCLR_PTV));
+ WR4(sc, WDT_WLDR, counter_val);
+ WR4(sc, WDT_WCRR, counter_val);
+
+ ti_wdt_sync_all(sc);
+
+ ti_wdt_start(sc);
+
+ return 0;
+}
+
+static int
+ti_wdt_tickle(struct sysmon_wdog *smw)
+{
+ struct ti_wdt_softc * const sc = smw->smw_cookie;
+ uint32_t val;
+
+ ti_wdt_sync_all(sc);
+ val = RD4(sc, WDT_WTGR);
+ WR4(sc, WDT_WTGR, ~val);
+
+ return 0;
+}
+
+static int
+ti_wdt_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct fdt_attach_args * const faa = aux;
+
+ return of_match_compatible(faa->faa_phandle, compatible);
+}
+
+static void
+ti_wdt_attach(device_t parent, device_t self, void *aux)
+{
+ struct ti_wdt_softc * const sc = device_private(self);
+ struct fdt_attach_args * const faa = aux;
+ const int phandle = faa->faa_phandle;
+ struct clk *clk;
+ bus_addr_t addr;
+ bus_size_t size;
+
+ if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
+ aprint_error(": couldn't get registers\n");
+ return;
+ }
+
+ clk = ti_prcm_get_hwmod(phandle, 0);
+ if (clk == NULL || clk_enable(clk) != 0) {
+ aprint_error(": couldn't enable hwmod\n");
+ return;
+ }
+
+ sc->sc_dev = self;
+ sc->sc_bst = faa->faa_bst;
+ if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
+ aprint_error(": couldn't map registers\n");
+ return;
+ }
+ sc->sc_rate = clk_get_rate(clk);
+
+ aprint_naive("\n");
+ aprint_normal(": WATCHDOG\n");
+
+ /* Software reset */
+ if (ti_wdt_reset(sc) != 0) {
+ aprint_error_dev(self, "software reset timeout\n");
+ return;
+ }
+
+ /* Stop the watchdog */
+ ti_wdt_stop(sc);
+
Home |
Main Index |
Thread Index |
Old Index