diff options
author | Visa Hankala <visa@cvs.openbsd.org> | 2022-01-05 03:32:45 +0000 |
---|---|---|
committer | Visa Hankala <visa@cvs.openbsd.org> | 2022-01-05 03:32:45 +0000 |
commit | 6c57c9d4fae13e95608bd65cd23d5f76680dfd18 (patch) | |
tree | 46b74cd35346bc86672592802902df3f973d0132 /sys/arch | |
parent | 551e71f752c770d58fb16102ccba0fd6960a46a4 (diff) |
Add mpfclock(4), a driver for the PolarFire SoC MSS clock controller.
OK kettenis@
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/riscv64/conf/GENERIC | 5 | ||||
-rw-r--r-- | sys/arch/riscv64/conf/RAMDISK | 5 | ||||
-rw-r--r-- | sys/arch/riscv64/conf/files.riscv64 | 7 | ||||
-rw-r--r-- | sys/arch/riscv64/dev/mpfclock.c | 235 |
4 files changed, 249 insertions, 3 deletions
diff --git a/sys/arch/riscv64/conf/GENERIC b/sys/arch/riscv64/conf/GENERIC index 4c7e21926e7..3024748578e 100644 --- a/sys/arch/riscv64/conf/GENERIC +++ b/sys/arch/riscv64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.31 2022/01/03 15:50:16 visa Exp $ +# $OpenBSD: GENERIC,v 1.32 2022/01/05 03:32:44 visa Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -44,6 +44,9 @@ intc0 at cpu0 # NS16550 compatible serial ports com* at fdt? +# PolarFire SoCs +mpfclock* at fdt? early 1 + # SiFive SoCs sfclock* at fdt? early 1 # PRCI sfcc* at fdt? early 1 # L2 Cache Controller diff --git a/sys/arch/riscv64/conf/RAMDISK b/sys/arch/riscv64/conf/RAMDISK index 3c85f6f4a97..74993f13161 100644 --- a/sys/arch/riscv64/conf/RAMDISK +++ b/sys/arch/riscv64/conf/RAMDISK @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK,v 1.27 2022/01/03 15:50:16 visa Exp $ +# $OpenBSD: RAMDISK,v 1.28 2022/01/05 03:32:44 visa Exp $ machine riscv64 maxusers 4 @@ -35,6 +35,9 @@ intc0 at cpu0 # NS16550 compatible serial ports com* at fdt? +# PolarFire SoCs +mpfclock* at fdt? early 1 + # SiFive SoCs sfclock* at fdt? early 1 # PRCI sfcc* at fdt? early 1 # L2 Cache Controller diff --git a/sys/arch/riscv64/conf/files.riscv64 b/sys/arch/riscv64/conf/files.riscv64 index 998c313677a..819892c7100 100644 --- a/sys/arch/riscv64/conf/files.riscv64 +++ b/sys/arch/riscv64/conf/files.riscv64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.riscv64,v 1.17 2021/10/05 18:32:27 deraadt Exp $ +# $OpenBSD: files.riscv64,v 1.18 2022/01/05 03:32:44 visa Exp $ # Standard stanzas config(8) can't run without maxpartitions 16 @@ -84,6 +84,11 @@ device plic attach plic at fdt file arch/riscv64/dev/plic.c plic +# PolarFire SoC MSS clock controller +device mpfclock +attach mpfclock at fdt +file arch/riscv64/dev/mpfclock.c mpfclock + # L2 cache controller device sfcc attach sfcc at fdt diff --git a/sys/arch/riscv64/dev/mpfclock.c b/sys/arch/riscv64/dev/mpfclock.c new file mode 100644 index 00000000000..7b39405941b --- /dev/null +++ b/sys/arch/riscv64/dev/mpfclock.c @@ -0,0 +1,235 @@ +/* $OpenBSD: mpfclock.c,v 1.1 2022/01/05 03:32:44 visa Exp $ */ + +/* + * Copyright (c) 2022 Visa Hankala + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Driver for PolarFire SoC MSS clock controller. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/mutex.h> + +#include <machine/bus.h> +#include <machine/fdt.h> + +#include <dev/ofw/fdt.h> +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_clock.h> + +extern void (*cpuresetfn)(void); + +#define CLOCK_CONFIG_CR 0x0008 +#define CLOCK_CONFIG_CR_AHB_DIV_SHIFT 4 +#define CLOCK_CONFIG_CR_AXI_DIV_SHIFT 2 +#define CLOCK_CONFIG_CR_CPU_DIV_SHIFT 0 +#define CLOCK_CONFIG_CR_DIV_MASK 0x3 +#define MSS_RESET_CR 0x0018 +#define SUBBLK_CLOCK_CR 0x0084 +#define SUBBLK_RESET_CR 0x0088 + +#define CLK_CPU 0 +#define CLK_AXI 1 +#define CLK_AHB 2 +#define CLK_ENVM 3 +#define CLK_MAC0 4 +#define CLK_MAC1 5 +#define CLK_MMC 6 +#define CLK_TIMER 7 +#define CLK_MMUART0 8 +#define CLK_MMUART1 9 +#define CLK_MMUART2 10 +#define CLK_MMUART3 11 +#define CLK_MMUART4 12 +#define CLK_SPI0 13 +#define CLK_SPI1 14 +#define CLK_I2C0 15 +#define CLK_I2C1 16 +#define CLK_CAN0 17 +#define CLK_CAN1 18 +#define CLK_USB 19 +#define CLK_RESERVED 20 /* FPGA in SUBBLK_RESET_CR */ +#define CLK_RTC 21 +#define CLK_QSPI 22 +#define CLK_GPIO0 23 +#define CLK_GPIO1 24 +#define CLK_GPIO2 25 +#define CLK_DDRC 26 +#define CLK_FIC0 27 +#define CLK_FIC1 28 +#define CLK_FIC2 29 +#define CLK_FIC3 30 +#define CLK_ATHENA 31 +#define CLK_CFM 32 + +struct mpfclock_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + uint32_t sc_clkcfg; + uint32_t sc_refclk; + + struct clock_device sc_cd; +}; + +#define HREAD4(sc, reg) \ + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) + +int mpfclock_match(struct device *, void *, void *); +void mpfclock_attach(struct device *, struct device *, void *); + +void mpfclock_enable(void *, uint32_t *, int); +uint32_t mpfclock_get_frequency(void *, uint32_t *); +int mpfclock_set_frequency(void *, uint32_t *, uint32_t); + +void mpfclock_cpureset(void); + +const struct cfattach mpfclock_ca = { + sizeof(struct mpfclock_softc), mpfclock_match, mpfclock_attach +}; + +struct cfdriver mpfclock_cd = { + NULL, "mpfclock", DV_DULL +}; + +struct mutex mpfclock_mtx = MUTEX_INITIALIZER(IPL_HIGH); +struct mpfclock_softc *mpfclock_sc; + +int +mpfclock_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + if (faa->fa_nreg < 1) + return 0; + return OF_is_compatible(faa->fa_node, "microchip,mpfs-clkcfg"); +} + +void +mpfclock_attach(struct device *parent, struct device *self, void *aux) +{ + struct fdt_attach_args *faa = aux; + struct mpfclock_softc *sc = (struct mpfclock_softc *)self; + + sc->sc_refclk = clock_get_frequency_idx(faa->fa_node, 0); + if (sc->sc_refclk == 0) { + printf(": can't get refclk frequency\n"); + return; + } + + sc->sc_iot = faa->fa_iot; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &sc->sc_ioh) != 0) { + printf(": can't map registers\n"); + return; + } + + sc->sc_clkcfg = HREAD4(sc, CLOCK_CONFIG_CR); + + printf(": %u MHz ref clock\n", (sc->sc_refclk + 500000) / 1000000); + + sc->sc_cd.cd_node = faa->fa_node; + sc->sc_cd.cd_cookie = sc; + sc->sc_cd.cd_enable = mpfclock_enable; + sc->sc_cd.cd_get_frequency = mpfclock_get_frequency; + sc->sc_cd.cd_set_frequency = mpfclock_set_frequency; + clock_register(&sc->sc_cd); + + mpfclock_sc = sc; + cpuresetfn = mpfclock_cpureset; +} + +uint32_t +mpfclock_get_frequency(void *cookie, uint32_t *cells) +{ + struct mpfclock_softc *sc = cookie; + uint32_t div, shift; + uint32_t idx = cells[0]; + + if (idx == CLK_MMC) + return 200000000; + + if (idx > CLK_AHB) + idx = CLK_AHB; + + switch (idx) { + case CLK_CPU: + shift = CLOCK_CONFIG_CR_CPU_DIV_SHIFT; + break; + case CLK_AXI: + shift = CLOCK_CONFIG_CR_AXI_DIV_SHIFT; + break; + case CLK_AHB: + shift = CLOCK_CONFIG_CR_AHB_DIV_SHIFT; + break; + default: + panic("%s: invalid idx %u\n", __func__, idx); + } + + div = 1U << ((sc->sc_clkcfg >> shift) & CLOCK_CONFIG_CR_DIV_MASK); + + return sc->sc_refclk / div; +} + +int +mpfclock_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) +{ + return -1; +} + +void +mpfclock_enable(void *cookie, uint32_t *cells, int on) +{ + struct mpfclock_softc *sc = cookie; + uint32_t idx = cells[0]; + uint32_t bit, val; + + if (idx < CLK_ENVM || idx - CLK_ENVM > 31) + return; + bit = 1U << (idx - CLK_ENVM); + + mtx_enter(&mpfclock_mtx); + if (on) { + val = HREAD4(sc, SUBBLK_CLOCK_CR); + val |= bit; + HWRITE4(sc, SUBBLK_CLOCK_CR, val); + + val = HREAD4(sc, SUBBLK_RESET_CR); + val &= ~bit; + HWRITE4(sc, SUBBLK_RESET_CR, val); + } else { + val = HREAD4(sc, SUBBLK_RESET_CR); + val |= bit; + HWRITE4(sc, SUBBLK_RESET_CR, val); + + val = HREAD4(sc, SUBBLK_CLOCK_CR); + val &= ~bit; + HWRITE4(sc, SUBBLK_CLOCK_CR, val); + } + mtx_leave(&mpfclock_mtx); +} + +void +mpfclock_cpureset(void) +{ + struct mpfclock_softc *sc = mpfclock_sc; + + HWRITE4(sc, MSS_RESET_CR, 0xdead); +} |