From: Ron Manosuthi Subject: Initial Raspberry Pi CPU frequency driver (apm -A) To: "tech@openbsd.org" Date: Thu, 08 Jan 2026 19:48:24 +0000 Hi tech@, I've implemented Arm core reclocking on Raspberry Pis with a new driver rpicpu(4). The driver's still quite basic and just obeys whatever level cpu_setperf feeds it. Tested and only enabled on Pi 4B and 400 for now. Remember to unset force_turbo. Expect to see something like this in dmesg: rpicpu0 at simplebus0: 600-1800 MHz There are 5 patches: 1. bcmclock: refactors, add bcmclock_set_frequency 2. bcmmbox: guard bcmmbox_post with a rwlock 3. vcprop: model definition updates 4. rpicpu: basic driver 5. rpicpu: enable in GENERIC, manpage Please let me know of any possible improvements. - Ron ---- 1. bcmclock: refactors, add bcmclock_set_frequency Change bcmclock_get_frequency to not deal with BCMCLOCK_CLOCK_*. Instead, a wrapper bcmclock_cd_get_frequency, which does that, is attached to cd_get_frequency. diff --git sys/dev/fdt/bcm2835_clock.c sys/dev/fdt/bcm2835_clock.c index 8927f8968af..b611bdbe67d 100644 --- sys/dev/fdt/bcm2835_clock.c +++ sys/dev/fdt/bcm2835_clock.c @@ -53,6 +53,7 @@ #include #include +#include #include #include @@ -84,14 +85,14 @@ struct bcmclock_softc { int bcmclock_match(struct device *, void *, void *); void bcmclock_attach(struct device *, struct device *, void *); +uint32_t bcmclock_cd_get_frequency(void *, uint32_t *); + const struct cfattach bcmclock_ca = { sizeof(struct bcmclock_softc), bcmclock_match, bcmclock_attach, }; -uint32_t bcmclock_get_frequency(void *, uint32_t *); - struct cfdriver bcmclock_cd = { NULL, "bcmclock", DV_DULL }; int @@ -113,13 +114,64 @@ bcmclock_attach(struct device *parent, struct device *self, void *aux) sc->sc_cd.cd_node = faa->fa_node; sc->sc_cd.cd_cookie = sc; - sc->sc_cd.cd_get_frequency = bcmclock_get_frequency; + sc->sc_cd.cd_get_frequency = bcmclock_cd_get_frequency; clock_register(&sc->sc_cd); } -uint32_t -bcmclock_get_frequency(void *cookie, uint32_t *cells) +int +bcmclock_get_frequency(uint32_t *res, uint32_t clk_vc_id, uint32_t clk_vc_type) +{ + struct request { + struct vcprop_buffer_hdr vb_hdr; + struct vcprop_tag_clockrate vbt_clkrate; + struct vcprop_tag end; + } __packed; + + int error; + uint32_t result; + struct request req = { + .vb_hdr = { + .vpb_len = sizeof(req), + .vpb_rcode = VCPROP_PROCESS_REQUEST, + }, + .vbt_clkrate = { + .tag = { + .vpt_tag = clk_vc_type, + .vpt_len = VCPROPTAG_LEN(req.vbt_clkrate), + .vpt_rcode = VCPROPTAG_REQUEST + }, + .id = clk_vc_id, + }, + .end = { + .vpt_tag = VCPROPTAG_NULL + } + }; + + + if (req.vbt_clkrate.id == 0) { + printf("%s: request to unknown clock id %d\n", __func__, clk_vc_id); + return (ENOENT); + } + + error = bcmmbox_post(BCMMBOX_CHANARM2VC, &req, sizeof(req), &result); + if (error) { + printf("%s: post failed, error %d\n", __func__, error); + return error; + } + + if (vcprop_tag_success_p(&req.vbt_clkrate.tag)) { + *res = req.vbt_clkrate.rate; + return 0; + } else { + printf("%s: vcprop result %x:%x\n", __func__, req.vb_hdr.vpb_rcode, + req.vbt_clkrate.tag.vpt_rcode); + return (EINVAL); + } +} + +int +bcmclock_set_frequency(uint32_t clk_vc_id, uint32_t clk_hz) { struct request { struct vcprop_buffer_hdr vb_hdr; @@ -127,6 +179,7 @@ bcmclock_get_frequency(void *cookie, uint32_t *cells) struct vcprop_tag end; } __packed; + int error; uint32_t result; struct request req = { .vb_hdr = { @@ -135,68 +188,93 @@ bcmclock_get_frequency(void *cookie, uint32_t *cells) }, .vbt_clkrate = { .tag = { - .vpt_tag = VCPROPTAG_GET_CLOCKRATE, + .vpt_tag = VCPROPTAG_SET_CLOCKRATE, .vpt_len = VCPROPTAG_LEN(req.vbt_clkrate), .vpt_rcode = VCPROPTAG_REQUEST }, + .id = clk_vc_id, + .rate = clk_hz, }, .end = { .vpt_tag = VCPROPTAG_NULL } }; + + if (req.vbt_clkrate.id == 0) { + printf("%s: request to unknown clock id %d\n", __func__, clk_vc_id); + return (ENOENT); + } + + error = bcmmbox_post(BCMMBOX_CHANARM2VC, &req, sizeof(req), &result); + if (error) { + printf("%s: post failed, error %d\n", __func__, error); + return error; + } + + if (vcprop_tag_success_p(&req.vbt_clkrate.tag)) { + return 0; + } else { + printf("%s: vcprop result %x:%x\n", __func__, req.vb_hdr.vpb_rcode, + req.vbt_clkrate.tag.vpt_rcode); + return (EINVAL); + } +} + +uint32_t +bcmclock_cd_get_frequency(void *cookie, uint32_t *cells) +{ + int error; + uint32_t clk_id = 0, res = 0; + switch (cells[0]) { case BCMCLOCK_CLOCK_TIMER: break; case BCMCLOCK_CLOCK_UART: - req.vbt_clkrate.id = VCPROP_CLK_UART; + clk_id = VCPROP_CLK_UART; break; case BCMCLOCK_CLOCK_VPU: - req.vbt_clkrate.id = VCPROP_CLK_CORE; + clk_id = VCPROP_CLK_CORE; break; case BCMCLOCK_CLOCK_V3D: - req.vbt_clkrate.id = VCPROP_CLK_V3D; + clk_id = VCPROP_CLK_V3D; break; case BCMCLOCK_CLOCK_ISP: - req.vbt_clkrate.id = VCPROP_CLK_ISP; + clk_id = VCPROP_CLK_ISP; break; case BCMCLOCK_CLOCK_H264: - req.vbt_clkrate.id = VCPROP_CLK_H264; + clk_id = VCPROP_CLK_H264; break; case BCMCLOCK_CLOCK_VEC: break; case BCMCLOCK_CLOCK_HSM: break; case BCMCLOCK_CLOCK_SDRAM: - req.vbt_clkrate.id = VCPROP_CLK_SDRAM; + clk_id = VCPROP_CLK_SDRAM; break; case BCMCLOCK_CLOCK_TSENS: break; case BCMCLOCK_CLOCK_EMMC: - req.vbt_clkrate.id = VCPROP_CLK_EMMC; + clk_id = VCPROP_CLK_EMMC; break; case BCMCLOCK_CLOCK_PERIIMAGE: break; case BCMCLOCK_CLOCK_PWM: - req.vbt_clkrate.id = VCPROP_CLK_PWM; + clk_id = VCPROP_CLK_PWM; break; case BCMCLOCK_CLOCK_PCM: break; } - - if (req.vbt_clkrate.id == 0) { - printf("bcmclock[unknown]: request to unknown clock type %d\n", - cells[0]); + if (clk_id == 0) { + printf("%s: unknown clock device %d\n", __func__, cells[0]); return 0; } - bcmmbox_post(BCMMBOX_CHANARM2VC, &req, sizeof(req), &result); - - if (vcprop_tag_success_p(&req.vbt_clkrate.tag)) - return req.vbt_clkrate.rate; - - printf("%s: vcprop result %x:%x\n", __func__, req.vb_hdr.vpb_rcode, - req.vbt_clkrate.tag.vpt_rcode); + error = bcmclock_get_frequency(&res, clk_id, VCPROPTAG_GET_CLOCKRATE); + if (error) { + printf("%s: failed to get frequency for clock device %d: error code %d\n", __func__, cells[0], error); + return 0; + } - return 0; + return res; } diff --git sys/dev/ic/bcm2835_clock.h sys/dev/ic/bcm2835_clock.h new file mode 100644 index 00000000000..f9d6d9e7ac9 --- /dev/null +++ sys/dev/ic/bcm2835_clock.h @@ -0,0 +1,7 @@ +#ifndef BCM2835_CLOCK_H +#define BCM2835_CLOCK_H + +int bcmclock_get_frequency(uint32_t *, uint32_t, uint32_t); +int bcmclock_set_frequency(uint32_t, uint32_t); + +#endif 2. bcmmbox: guard bcmmbox_post with a rwlock The better solution would probably be to create a per-bcmmbox_post dma bounce and a wake queue. I have an ancient cursed branch that does that but wanted to get something simpler working first after the remake. (Also said version used a TAILQ but maybe mbuf would be better?) diff --git sys/dev/fdt/bcm2835_mbox.c sys/dev/fdt/bcm2835_mbox.c index 6987529f916..e8877a0e226 100644 --- sys/dev/fdt/bcm2835_mbox.c +++ sys/dev/fdt/bcm2835_mbox.c @@ -76,7 +76,12 @@ struct bcmmbox_softc { void *sc_ih; - struct mutex sc_intr_lock; + /* We only have one dma bounce. + * Serialize post to avoid overwriting it. */ + struct rwlock sc_post_lock; + + struct mutex sc_intr_lock; + int sc_chan[BCMMBOX_NUM_CHANNELS]; uint32_t sc_mbox[BCMMBOX_NUM_CHANNELS]; }; @@ -122,6 +127,7 @@ bcmmbox_attach(struct device *parent, struct device *self, void *aux) bcmmbox_sc = sc; mtx_init(&sc->sc_intr_lock, IPL_VM); + rw_init(&sc->sc_post_lock, "bcmmbox_post"); if (faa->fa_nreg < 1) { printf(": no registers\n"); @@ -318,6 +324,7 @@ bcmmbox_post(uint8_t chan, void *buf, size_t len, uint32_t *res) if (sc == NULL) return ENXIO; + rw_enter_write(&sc->sc_post_lock); memcpy(sc->sc_dmabuf, buf, len); bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0, len, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); @@ -328,6 +335,7 @@ bcmmbox_post(uint8_t chan, void *buf, size_t len, uint32_t *res) bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0, len, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); memcpy(buf, sc->sc_dmabuf, len); + rw_exit_write(&sc->sc_post_lock); return 0; } 3. vcprop: model definition updates Old definition was outdated and contained some errors. We weren't using them before, but rpicpu will. Additionally, rename the models to follow source material's format. diff --git sys/dev/ic/bcm2835_vcprop.h sys/dev/ic/bcm2835_vcprop.h index 09350fc94c5..6f854707ad0 100644 --- sys/dev/ic/bcm2835_vcprop.h +++ sys/dev/ic/bcm2835_vcprop.h @@ -152,27 +152,45 @@ struct vcprop_tag_boardmodel { uint32_t model; }; +/* Source: https://github.com/raspberrypi/documentation/blob/master/documentation/asciidoc/computers/raspberry-pi/revision-codes.adoc */ struct vcprop_tag_boardrev { struct vcprop_tag tag; uint32_t rev; }; #define VCPROP_REV_PCBREV 15 #define VCPROP_REV_MODEL (255 << 4) -#define RPI_MODEL_A 0 -#define RPI_MODEL_B 1 -#define RPI_MODEL_A_PLUS 2 -#define RPI_MODEL_B_PLUS 3 -#define RPI_MODEL_B_PI2 4 -#define RPI_MODEL_ALPHA 5 -#define RPI_MODEL_COMPUTE 6 -#define RPI_MODEL_ZERO 7 -#define RPI_MODEL_B_PI3 8 -#define RPI_MODEL_COMPUTE_PI3 9 -#define RPI_MODEL_ZERO_W 10 +#define RPI_MODEL_A 0x00 +#define RPI_MODEL_B 0x01 +#define RPI_MODEL_A_PLUS 0x02 +#define RPI_MODEL_B_PLUS 0x03 +#define RPI_MODEL_2B 0x04 +#define RPI_MODEL_ALPHA 0x05 +#define RPI_MODEL_CM1 0x06 +#define RPI_MODEL_3B 0x08 +#define RPI_MODEL_ZERO 0x09 +#define RPI_MODEL_CM3 0x0a +#define RPI_MODEL_ZERO_W 0x0c +#define RPI_MODEL_3B_PLUS 0x0d +#define RPI_MODEL_3A_PLUS 0x0e +/* #define RPI_MODEL_INTERNAL 0x0f */ +#define RPI_MODEL_CM3_PLUS 0x10 +#define RPI_MODEL_4B 0x11 +#define RPI_MODEL_ZERO_2W 0x12 +#define RPI_MODEL_400 0x13 +#define RPI_MODEL_CM4 0x14 +#define RPI_MODEL_CM4S 0x15 +/* #define RPI_MODEL_INTERNAL 0x16 */ +#define RPI_MODEL_5 0x17 +#define RPI_MODEL_CM5 0x18 +#define RPI_MODEL_500 0x19 +#define RPI_MODEL_CM5_LITE 0x1a + #define VCPROP_REV_PROCESSOR (15 << 12) #define RPI_PROCESSOR_BCM2835 0 #define RPI_PROCESSOR_BCM2836 1 #define RPI_PROCESSOR_BCM2837 2 +#define RPI_PROCESSOR_BCM2711 3 +#define RPI_PROCESSOR_BCM2712 4 #define VCPROP_REV_MANUF (15 << 16) #define VCPROP_REV_MEMSIZE (7 << 20) #define VCPROP_REV_ENCFLAG (1 << 23) 4. rpicpu: basic driver Basic driver that hooks to cpu_cpuspeed and cpu_setperf. sensordev isn't implemented yet. diff --git sys/arch/arm64/conf/files.arm64 sys/arch/arm64/conf/files.arm64 index 34d9f5d35f5..6635665cb94 100644 --- sys/arch/arm64/conf/files.arm64 +++ sys/arch/arm64/conf/files.arm64 @@ -272,6 +272,10 @@ device rpiclock attach rpiclock at fdt file arch/arm64/dev/rpiclock.c rpiclock +device rpicpu +attach rpicpu at fdt +file arch/arm64/dev/rpicpu.c rpicpu + device rpigpio attach rpigpio at fdt file arch/arm64/dev/rpigpio.c rpigpio diff --git sys/arch/arm64/dev/rpicpu.c sys/arch/arm64/dev/rpicpu.c new file mode 100644 index 00000000000..79a33c3d9b2 --- /dev/null +++ sys/arch/arm64/dev/rpicpu.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2026 Ron Manosuthi + * + * Permission to use, copy, modify, and 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#define DEVNAME(sc) ((sc)->sc_dev.dv_xname) +#define HZ_TO_MHZ(hz) ((hz) / 1000000) + +struct rpicpu_softc { + struct device sc_dev; + + uint32_t sc_min_clk_hz; + uint32_t sc_max_clk_hz; + uint32_t sc_target_clk_hz; + + struct task sc_task_reclk; +}; + +static struct rpicpu_softc *rpicpu_sc; + +int rpicpu_match(struct device *, void *, void *); +void rpicpu_attach(struct device *, struct device *, void *); +int rpicpu_get_board_rev(uint32_t *); +int rpicpu_clockspeed(int *); +void rpicpu_setperf(int); +void rpicpu_reclock(void *); + +const struct cfattach rpicpu_ca = { + sizeof (struct rpicpu_softc), rpicpu_match, rpicpu_attach +}; + +struct cfdriver rpicpu_cd = { + NULL, "rpicpu", DV_DULL +}; + +int +rpicpu_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + /* XXX find a better node */ + return OF_is_compatible(faa->fa_node, "raspberrypi,bcm2835-firmware"); +} + +void +rpicpu_attach(struct device *parent, struct device *self, void *aux) +{ + struct rpicpu_softc *sc = (struct rpicpu_softc *)self; + int error; + uint32_t board_rev; + + error = rpicpu_get_board_rev(&board_rev); + if (error) { + printf(": failed to get board revision: %d\n", error); + return; + } + board_rev &= VCPROP_REV_MODEL; + board_rev >>= 4; + if (board_rev != RPI_MODEL_4B && + board_rev != RPI_MODEL_400) { + printf(": unsupported board revision %#x\n", board_rev); + return; + } + + error = bcmclock_get_frequency(&sc->sc_min_clk_hz, VCPROP_CLK_ARM, VCPROPTAG_GET_MIN_CLOCKRATE); + if (error) { + printf(": failed to get min clock frequency: %d\n", error); + return; + } + + error = bcmclock_get_frequency(&sc->sc_max_clk_hz, VCPROP_CLK_ARM, VCPROPTAG_GET_MAX_CLOCKRATE); + if (error) { + printf(": failed to get max clock frequency: %d\n", error); + return; + } + + cpu_cpuspeed = rpicpu_clockspeed; + cpu_setperf = rpicpu_setperf; + + task_set(&sc->sc_task_reclk, rpicpu_reclock, sc); + rpicpu_sc = sc; + + printf(": %d-%d MHz\n", HZ_TO_MHZ(sc->sc_min_clk_hz), HZ_TO_MHZ(sc->sc_max_clk_hz)); + + /* XXX sensordev */ +} + +int +rpicpu_get_board_rev(uint32_t *board_rev) +{ + struct request { + struct vcprop_buffer_hdr vb_hdr; + struct vcprop_tag_boardrev vbt_br; + struct vcprop_tag end; + } __packed; + + int error; + uint32_t result; + struct request req = { + .vb_hdr = { + .vpb_len = sizeof(req), + .vpb_rcode = VCPROP_PROCESS_REQUEST, + }, + .vbt_br = { + .tag = { + .vpt_tag = VCPROPTAG_GET_BOARDREVISION, + .vpt_len = VCPROPTAG_LEN(req.vbt_br), + .vpt_rcode = VCPROPTAG_REQUEST + }, + .rev = 0, + }, + .end = { + .vpt_tag = VCPROPTAG_NULL + } + }; + + error = bcmmbox_post(BCMMBOX_CHANARM2VC, &req, sizeof(req), &result); + if (error) { + printf("%s: post failed, error %d\n", __func__, error); + return error; + } + + if (vcprop_tag_success_p(&req.vbt_br.tag)) { + *board_rev = req.vbt_br.rev; + return 0; + } else { + return (EINVAL); + } +} + +int +rpicpu_clockspeed(int *freq) +{ + struct rpicpu_softc *sc = rpicpu_sc; + uint32_t clk_hz; + + if (sc == NULL) + return (ENXIO); + + clk_hz = atomic_load_int(&sc->sc_target_clk_hz); + *freq = HZ_TO_MHZ(clk_hz); + return 0; +} + +void +rpicpu_setperf(int level) +{ + struct rpicpu_softc *sc = rpicpu_sc; + uint64_t target_clk_hz, min_hz, max_hz; + + if (sc == NULL) + return; + + min_hz = sc->sc_min_clk_hz; + max_hz = sc->sc_max_clk_hz; + target_clk_hz = min_hz + (((max_hz - min_hz) * level) / 100); + atomic_store_int(&sc->sc_target_clk_hz, (uint32_t)target_clk_hz); + + /* defer work to task queue so + * post can sleep */ + task_add(systqmp, &sc->sc_task_reclk); +} + +void +rpicpu_reclock(void *cookie) +{ + struct rpicpu_softc *sc = (struct rpicpu_softc *)cookie; + uint32_t target_clk_hz; + + target_clk_hz = atomic_load_int(&sc->sc_target_clk_hz); + KASSERT(target_clk_hz >= sc->sc_min_clk_hz && + target_clk_hz <= sc->sc_max_clk_hz); + + bcmclock_set_frequency(VCPROP_CLK_ARM, target_clk_hz); +} 5. rpicpu: enable in GENERIC, manpage You should see something like this in dmesg: rpicpu0 at simplebus0: 600-1800 MHz diff --git share/man/man4/man4.arm64/Makefile share/man/man4/man4.arm64/Makefile index f85efe499e0..8de25a14a1c 100644 --- share/man/man4/man4.arm64/Makefile +++ share/man/man4/man4.arm64/Makefile @@ -6,7 +6,7 @@ MAN= agintc.4 agtimer.4 ampchwm.4 ampintc.4 \ aplhidev.4 apliic.4 aplintc.4 aplmbox.4 aplmca.4 aplnco.4 aplns.4 \ aplpcie.4 aplpinctrl.4 aplpmgr.4 aplpmu.4 aplpwm.4 \ aplsart.4 aplsmc.4 aplspi.4 aplspmi.4 apm.4 \ - intro.4 rpiclock.4 rpipwm.4 rpirtc.4 rpone.4 smbios.4 + intro.4 rpiclock.4 rpicpu.4 rpipwm.4 rpirtc.4 rpone.4 smbios.4 MANSUBDIR=arm64 diff --git share/man/man4/man4.arm64/rpicpu.4 share/man/man4/man4.arm64/rpicpu.4 new file mode 100644 index 00000000000..9ccfe012ea8 --- /dev/null +++ share/man/man4/man4.arm64/rpicpu.4 @@ -0,0 +1,59 @@ +.\" Copyright (c) 2026 Ron Manosuthi +.\" +.\" Permission to use, copy, modify, and 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. +.\" +.Dd $Mdocdate: January 7 2026 $ +.Dt RPICPU 4 arm64 +.Os +.Sh NAME +.Nm rpicpu +.Nd Raspberry Pi CPU frequency driver +.Sh SYNOPSIS +.Cd "rpicpu* at fdt?" +.Sh DESCRIPTION +The +.Nm +driver enables support for CPU frequency reclocking on Raspberry Pi devices. +It should theoretically work on all devices which can be reclocked using +.Xr bcmclock_set_frequency 9 . +.Pp +Currently, the driver is only enabled for the following tested devices: +.Pp +.Bl -bullet -offset indent -compact +.It +Raspberry Pi 4B +.It +Raspberry Pi 400 +.El +.Sh CAVEATS +The +.Nm +driver does not handle voltage adjustments or thermal throttling. +.Pp +Sensor reporting has not been implemented. +.Sh SEE ALSO +.Xr apm 8 , +.Xr apmd 8 , +.Xr bcmclock 4 , +.Xr intro 4 +.Sh HISTORY +The +.Nm +driver first appeared in +.Ox 7.8 . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Ron Manosuthi Aq Mt rman401@proton.me . diff --git sys/arch/arm64/conf/GENERIC sys/arch/arm64/conf/GENERIC index bc1aebe0610..100f7687744 100644 --- sys/arch/arm64/conf/GENERIC +++ sys/arch/arm64/conf/GENERIC @@ -255,6 +255,7 @@ dwctwo* at fdt? usb* at dwctwo? rpone* at pci? rpiclock* at fdt? early 1 +rpicpu* at fdt? rpigpio* at fdt? early 1 rpipwm* at fdt? rpirtc* at fdt?