From nobody Wed Apr 10 15:19:29 2024 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4VF61s2SlTz5HHYh; Wed, 10 Apr 2024 15:19:29 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4VF61s1rJLz4nXc; Wed, 10 Apr 2024 15:19:29 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1712762369; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=WbEeHEiqk77c99InBVPNmPX46Vyl+0JcrsJedsgmOBI=; b=A5iWCGO2/9FgU4M7TXf76JNZqnmSN2GDfwvKS71iz51pXboCa3Iqp+n1Yl95Hl86NZTIuO lF8Yc+3g1zx5AGrCQC8L12sIgVrGs7j42XJK2MLzLkSExn5z8KGwnrWxYDqwZ+wn8oPHmP rPRIxJI7aP1bcfh/ZYvIUQVhBItsKtLCzR2lDLgcuW3DMXqBmRSdDVvxF5ZXrOfaDpyg8G O1liQiZCJ7lNyApCW5FwL2nnv8W8riSyaUVvIl5IiHt9QdisuHle2DqMQ2xslWI6jcRky5 8j+bg0ZBPYiOKkiL/v1i0amAre0ylPbu+WcWTf2VcYLc1lDYmZreiR36kMgr3Q== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1712762369; a=rsa-sha256; cv=none; b=IIAdE44bw7xVUnIMKQHLmihbSpWQBDo5ZipCzibL4EPa+WuBNDvqNdUsajJeLcwUXavSSI SPfgcRHPM/gH/v/PHhrcyaCyef2yg4JNbPD6cnVnCTQ9XcWXdpfanXCGb8NtwLpeffL2Gi NcPniy/InpQHclqLmw0pIJunZhXjS55MUaxJODDdG90qqErY56f6mwjQx2ffosgooUIkaA ON5Q2626PCWyaRb/XLm6nJCYkOcboJa+f8Di+YMu3ffIVKmfqN1jFCI1i/nlnLZxZE+DLk XdHqEQD1A8RnqwZtbh7xX2JYRfvW8lm8Bsc5r/am5EZzFABPlwHKjqNhis9Iaw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1712762369; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=WbEeHEiqk77c99InBVPNmPX46Vyl+0JcrsJedsgmOBI=; b=dVvLIAiLosWfuv5YDaEvj/VFtGA5FgHFqFP401YUzCf3ZKlFT8VyY9QaV9xL+KIi+za6d6 tZ+ZUPVQPzGhAGnpN+1puOkJ0YSfX4u+UioG7hqoUba5tnQaGN691IaUVeTYpdH8jdj6xx YTL0sGQixsPwj8hfurQI4NtVQjw/xl60Uu/Ee1OymiA3wI+HziywPgAYwXEO+5cUvkT7MR kHtoRRGTdRwIEja6f6t7oSJSB1fJXcfiPqXu3vsrTY9Yx8ldOev1MUhD/SrZ+KkcuaJ3JZ yIfJmTpJFntE4MGcplLNSdD+Y/MH6YXzWGikvQBvZNLO+tbgmNzXYJmuZpjk/w== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4VF61s1SgmzjXl; Wed, 10 Apr 2024 15:19:29 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 43AFJTel093882; Wed, 10 Apr 2024 15:19:29 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 43AFJT2U093879; Wed, 10 Apr 2024 15:19:29 GMT (envelope-from git) Date: Wed, 10 Apr 2024 15:19:29 GMT Message-Id: <202404101519.43AFJT2U093879@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Mark Johnston Subject: git: 014d7082a239 - main - bhyve: Implement a PL031 RTC on arm64 List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: dev-commits-src-main+owner@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 014d7082a2398ec39e76b5f7b1f842fc9be6c51e Auto-Submitted: auto-generated The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=014d7082a2398ec39e76b5f7b1f842fc9be6c51e commit 014d7082a2398ec39e76b5f7b1f842fc9be6c51e Author: Jessica Clarke AuthorDate: 2024-02-21 22:57:04 +0000 Commit: Mark Johnston CommitDate: 2024-04-10 15:17:56 +0000 bhyve: Implement a PL031 RTC on arm64 Unlike amd64's, this RTC is implemented entirely in userspace. This is the same RTC as is provided by QEMU's virt machine. Reviewed by: jhb MFC after: 2 weeks Obtained from: CheriBSD --- usr.sbin/bhyve/aarch64/Makefile.inc | 1 + usr.sbin/bhyve/aarch64/bhyverun_machdep.c | 60 +++++++ usr.sbin/bhyve/aarch64/fdt.c | 31 ++++ usr.sbin/bhyve/aarch64/fdt.h | 1 + usr.sbin/bhyve/rtc_pl031.c | 279 ++++++++++++++++++++++++++++++ usr.sbin/bhyve/rtc_pl031.h | 40 +++++ 6 files changed, 412 insertions(+) diff --git a/usr.sbin/bhyve/aarch64/Makefile.inc b/usr.sbin/bhyve/aarch64/Makefile.inc index 2c7a3cac105e..e2ea4414ca19 100644 --- a/usr.sbin/bhyve/aarch64/Makefile.inc +++ b/usr.sbin/bhyve/aarch64/Makefile.inc @@ -1,5 +1,6 @@ SRCS+= \ fdt.c \ + rtc_pl031.c \ uart_pl011.c .PATH: ${BHYVE_SYSDIR}/sys/arm64/vmm diff --git a/usr.sbin/bhyve/aarch64/bhyverun_machdep.c b/usr.sbin/bhyve/aarch64/bhyverun_machdep.c index 2aa7d2d9b4fd..a5fd3f054706 100644 --- a/usr.sbin/bhyve/aarch64/bhyverun_machdep.c +++ b/usr.sbin/bhyve/aarch64/bhyverun_machdep.c @@ -48,6 +48,7 @@ #include "mem.h" #include "pci_emul.h" #include "pci_irq.h" +#include "rtc_pl031.h" #include "uart_emul.h" /* Start of mem + 1M */ @@ -58,6 +59,9 @@ #define UART_MMIO_BASE 0x10000 #define UART_MMIO_SIZE 0x1000 #define UART_INTR 32 +#define RTC_MMIO_BASE 0x11000 +#define RTC_MMIO_SIZE 0x1000 +#define RTC_INTR 33 #define GIC_DIST_BASE 0x2f000000 #define GIC_DIST_SIZE 0x10000 @@ -287,6 +291,60 @@ init_mmio_uart(struct vmctx *ctx) return (true); } +static void +mmio_rtc_intr_assert(void *arg) +{ + struct vmctx *ctx = arg; + + vm_assert_irq(ctx, RTC_INTR); +} + +static void +mmio_rtc_intr_deassert(void *arg) +{ + struct vmctx *ctx = arg; + + vm_deassert_irq(ctx, RTC_INTR); +} + +static int +mmio_rtc_mem_handler(struct vcpu *vcpu __unused, int dir, + uint64_t addr, int size __unused, uint64_t *val, void *arg1, long arg2) +{ + struct rtc_pl031_softc *sc = arg1; + long reg; + + reg = addr - arg2; + if (dir == MEM_F_WRITE) + rtc_pl031_write(sc, reg, *val); + else + *val = rtc_pl031_read(sc, reg); + + return (0); +} + +static void +init_mmio_rtc(struct vmctx *ctx) +{ + struct rtc_pl031_softc *sc; + struct mem_range mr; + int error; + + sc = rtc_pl031_init(mmio_rtc_intr_assert, mmio_rtc_intr_deassert, + ctx); + + bzero(&mr, sizeof(struct mem_range)); + mr.name = "rtc"; + mr.base = RTC_MMIO_BASE; + mr.size = RTC_MMIO_SIZE; + mr.flags = MEM_F_RW; + mr.handler = mmio_rtc_mem_handler; + mr.arg1 = sc; + mr.arg2 = mr.base; + error = register_mem(&mr); + assert(error == 0); +} + static vm_paddr_t fdt_gpa(struct vmctx *ctx) { @@ -328,6 +386,8 @@ bhyve_init_platform(struct vmctx *ctx, struct vcpu *bsp) if (init_mmio_uart(ctx)) fdt_add_uart(UART_MMIO_BASE, UART_MMIO_SIZE, UART_INTR); + init_mmio_rtc(ctx); + fdt_add_rtc(RTC_MMIO_BASE, RTC_MMIO_SIZE, RTC_INTR); fdt_add_timer(); pci_irq_init(pcie_intrs); fdt_add_pcie(pcie_intrs); diff --git a/usr.sbin/bhyve/aarch64/fdt.c b/usr.sbin/bhyve/aarch64/fdt.c index e8c959a65f3b..3fb97a40c241 100644 --- a/usr.sbin/bhyve/aarch64/fdt.c +++ b/usr.sbin/bhyve/aarch64/fdt.c @@ -248,6 +248,37 @@ fdt_add_uart(uint64_t uart_base, uint64_t uart_size, int intr) fdt_end_node(fdt); } +void +fdt_add_rtc(uint64_t rtc_base, uint64_t rtc_size, int intr) +{ + void *fdt, *interrupts, *prop; + char node_name[32]; + + assert(gic_phandle != 0); + assert(apb_pclk_phandle != 0); + assert(intr >= GIC_FIRST_SPI); + + fdt = fdtroot; + + snprintf(node_name, sizeof(node_name), "rtc@%lx", rtc_base); + fdt_begin_node(fdt, node_name); +#define RTC_COMPAT "arm,pl031\0arm,primecell" + fdt_property(fdt, "compatible", RTC_COMPAT, sizeof(RTC_COMPAT)); +#undef RTC_COMPAT + set_single_reg(fdt, rtc_base, rtc_size); + fdt_property_u32(fdt, "interrupt-parent", gic_phandle); + fdt_property_placeholder(fdt, "interrupts", 3 * sizeof(uint32_t), + &interrupts); + SET_PROP_U32(interrupts, 0, GIC_SPI); + SET_PROP_U32(interrupts, 1, intr - GIC_FIRST_SPI); + SET_PROP_U32(interrupts, 2, IRQ_TYPE_LEVEL_HIGH); + fdt_property_placeholder(fdt, "clocks", sizeof(uint32_t), &prop); + SET_PROP_U32(prop, 0, apb_pclk_phandle); + fdt_property_string(fdt, "clock-names", "apb_pclk"); + + fdt_end_node(fdt); +} + void fdt_add_timer(void) { diff --git a/usr.sbin/bhyve/aarch64/fdt.h b/usr.sbin/bhyve/aarch64/fdt.h index 6534266173d0..c19d19d34a46 100644 --- a/usr.sbin/bhyve/aarch64/fdt.h +++ b/usr.sbin/bhyve/aarch64/fdt.h @@ -42,6 +42,7 @@ void fdt_add_gic(uint64_t dist_base, uint64_t dist_size, void fdt_add_timer(void); void fdt_add_pcie(int intrs[static 4]); void fdt_add_uart(uint64_t uart_base, uint64_t uart_size, int intr); +void fdt_add_rtc(uint64_t rtc_base, uint64_t rtc_size, int intr); void fdt_finalize(void); #endif /* _FDT_H_ */ diff --git a/usr.sbin/bhyve/rtc_pl031.c b/usr.sbin/bhyve/rtc_pl031.c new file mode 100644 index 000000000000..e334de6f92bb --- /dev/null +++ b/usr.sbin/bhyve/rtc_pl031.c @@ -0,0 +1,279 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 Jessica Clarke + * + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 + +#include +#include +#include +#include +#include + +#include "config.h" +#include "mevent.h" +#include "rtc_pl031.h" + +#define RTCDR 0x000 +#define RTCMR 0x004 +#define RTCLR 0x008 +#define RTCCR 0x00C +#define RTCIMSC 0x010 +#define RTCRIS 0x014 +#define RTCMIS 0x018 +#define RTCICR 0x01C + +#define RTCPeriphID0 0xFE0 +#define RTCPeriphID1 0xFE4 +#define RTCPeriphID2 0xFE8 +#define RTCPeriphID3 0xFEC +#define _RTCPeriphID_VAL 0x00141031 +#define RTCPeriphID_VAL(_n) ((_RTCPeriphID_VAL >> (8 * (_n))) & 0xff) + +#define RTCCellID0 0xFF0 +#define RTCCellID1 0xFF4 +#define RTCCellID2 0xFF8 +#define RTCCellID3 0xFFC +#define _RTCCellID_VAL 0xb105f00d +#define RTCCellID_VAL(_n) ((_RTCCellID_VAL >> (8 * (_n))) & 0xff) + +struct rtc_pl031_softc { + pthread_mutex_t mtx; + + time_t last_tick; + uint32_t dr; + uint32_t mr; + uint32_t lr; + uint8_t imsc; + uint8_t ris; + uint8_t prev_mis; + + struct mevent *mevp; + + void *arg; + rtc_pl031_intr_func_t intr_assert; + rtc_pl031_intr_func_t intr_deassert; +}; + +static void rtc_pl031_callback(int fd, enum ev_type type, void *param); + +/* + * Returns the current RTC time as number of seconds since 00:00:00 Jan 1, 1970 + */ +static time_t +rtc_pl031_time(void) +{ + struct tm tm; + time_t t; + + time(&t); + if (get_config_bool_default("rtc.use_localtime", false)) { + localtime_r(&t, &tm); + t = timegm(&tm); + } + return (t); +} + +static void +rtc_pl031_update_mis(struct rtc_pl031_softc *sc) +{ + uint8_t mis; + + mis = sc->ris & sc->imsc; + if (mis == sc->prev_mis) + return; + + sc->prev_mis = mis; + if (mis) + (*sc->intr_assert)(sc->arg); + else + (*sc->intr_deassert)(sc->arg); +} + +static uint64_t +rtc_pl031_next_match_ticks(struct rtc_pl031_softc *sc) +{ + uint32_t ticks; + + ticks = sc->mr - sc->dr; + if (ticks == 0) + return ((uint64_t)1 << 32); + + return (ticks); +} + +static int +rtc_pl031_next_timer_msecs(struct rtc_pl031_softc *sc) +{ + uint64_t ticks; + + ticks = rtc_pl031_next_match_ticks(sc); + return (MIN(ticks * 1000, INT_MAX)); +} + +static void +rtc_pl031_update_timer(struct rtc_pl031_softc *sc) +{ + mevent_timer_update(sc->mevp, rtc_pl031_next_timer_msecs(sc)); +} + +static void +rtc_pl031_tick(struct rtc_pl031_softc *sc, bool from_timer) +{ + bool match; + time_t now, ticks; + + now = rtc_pl031_time(); + ticks = now - sc->last_tick; + match = ticks >= 0 && + (uint64_t)ticks >= rtc_pl031_next_match_ticks(sc); + sc->dr += ticks; + sc->last_tick = now; + + if (match) { + sc->ris = 1; + rtc_pl031_update_mis(sc); + } + + if (match || from_timer || ticks < 0) + rtc_pl031_update_timer(sc); +} + +static void +rtc_pl031_callback(int fd __unused, enum ev_type type __unused, void *param) +{ + struct rtc_pl031_softc *sc = param; + + pthread_mutex_lock(&sc->mtx); + rtc_pl031_tick(sc, true); + pthread_mutex_unlock(&sc->mtx); +} + +void +rtc_pl031_write(struct rtc_pl031_softc *sc, int offset, uint32_t value) +{ + pthread_mutex_lock(&sc->mtx); + rtc_pl031_tick(sc, false); + switch (offset) { + case RTCMR: + sc->mr = value; + rtc_pl031_update_timer(sc); + break; + case RTCLR: + sc->lr = value; + sc->dr = sc->lr; + rtc_pl031_update_timer(sc); + break; + case RTCIMSC: + sc->imsc = value & 1; + rtc_pl031_update_mis(sc); + break; + case RTCICR: + sc->ris &= ~value; + rtc_pl031_update_mis(sc); + break; + default: + /* Ignore writes to read-only/unassigned/ID registers */ + break; + } + pthread_mutex_unlock(&sc->mtx); +} + +uint32_t +rtc_pl031_read(struct rtc_pl031_softc *sc, int offset) +{ + uint32_t reg; + + pthread_mutex_lock(&sc->mtx); + rtc_pl031_tick(sc, false); + switch (offset) { + case RTCDR: + reg = sc->dr; + break; + case RTCMR: + reg = sc->mr; + break; + case RTCLR: + reg = sc->lr; + break; + case RTCCR: + /* RTC enabled from reset */ + reg = 1; + break; + case RTCIMSC: + reg = sc->imsc; + break; + case RTCRIS: + reg = sc->ris; + break; + case RTCMIS: + reg = sc->ris & sc->imsc; + break; + case RTCPeriphID0: + case RTCPeriphID1: + case RTCPeriphID2: + case RTCPeriphID3: + reg = RTCPeriphID_VAL(offset - RTCPeriphID0); + break; + case RTCCellID0: + case RTCCellID1: + case RTCCellID2: + case RTCCellID3: + reg = RTCCellID_VAL(offset - RTCCellID0); + break; + default: + /* Return 0 in reads from unasigned registers */ + reg = 0; + break; + } + pthread_mutex_unlock(&sc->mtx); + + return (reg); +} + +struct rtc_pl031_softc * +rtc_pl031_init(rtc_pl031_intr_func_t intr_assert, + rtc_pl031_intr_func_t intr_deassert, void *arg) +{ + struct rtc_pl031_softc *sc; + time_t now; + + sc = calloc(1, sizeof(struct rtc_pl031_softc)); + + pthread_mutex_init(&sc->mtx, NULL); + + now = rtc_pl031_time(); + sc->dr = now; + sc->last_tick = now; + sc->arg = arg; + sc->intr_assert = intr_assert; + sc->intr_deassert = intr_deassert; + + sc->mevp = mevent_add(rtc_pl031_next_timer_msecs(sc), EVF_TIMER, + rtc_pl031_callback, sc); + + return (sc); +} diff --git a/usr.sbin/bhyve/rtc_pl031.h b/usr.sbin/bhyve/rtc_pl031.h new file mode 100644 index 000000000000..8e4ef685908a --- /dev/null +++ b/usr.sbin/bhyve/rtc_pl031.h @@ -0,0 +1,40 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 Jessica Clarke + * + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +#ifndef _RTC_PL031_H_ +#define _RTC_PL031_H_ + +struct rtc_pl031_softc; +typedef void (*rtc_pl031_intr_func_t)(void *arg); + +struct rtc_pl031_softc *rtc_pl031_init(rtc_pl031_intr_func_t intr_assert, + rtc_pl031_intr_func_t intr_deassert, void *arg); +void rtc_pl031_write(struct rtc_pl031_softc *sc, int offset, + uint32_t value); +uint32_t rtc_pl031_read(struct rtc_pl031_softc *sc, int offset); + +#endif /* _RTC_PL031_H_ */