Index | Thread | Search

From:
Vitaliy Makkoveev <mvs@openbsd.org>
Subject:
Re: Initial Raspberry Pi CPU frequency driver (apm -A)
To:
Ron Manosuthi <rman401@proton.me>
Cc:
"tech@openbsd.org" <tech@openbsd.org>
Date:
Wed, 21 Jan 2026 11:34:58 +0000

Download raw body.

Thread
On Mon, Jan 19, 2026 at 01:47:37AM +0000, Ron Manosuthi wrote:
> Hi,
> 
> Here's a one-diff version with
> - style(9) fixes
> - better comments
> - earlier error handling in bcmclock(4) get/set freq
> - removed unused imports in rpicpu(4) (not used yet)
> 
> - Ron
> 

Please run 'mandoc -T lint' and fix  share/man/man4/man4.arm64/rpicpu.4
man page. 

> ----
> 
> 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 <rman401@proton.me>
> +.\"
> +.\" 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?
> 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..e426bdb1185
> --- /dev/null
> +++ sys/arch/arm64/dev/rpicpu.c
> @@ -0,0 +1,204 @@
> +/*
> + * Copyright (c) 2026 Ron Manosuthi <rman401@proton.me>
> + *
> + * 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 <sys/param.h>
> +#include <sys/systm.h>
> +#include <sys/sysctl.h>
> +#include <sys/task.h>
> +#include <sys/atomic.h>
> +
> +#include <machine/bus.h>
> +#include <machine/fdt.h>
> +
> +#include <dev/ic/bcm2835_clock.h>
> +#include <dev/ic/bcm2835_mbox.h>
> +#include <dev/ic/bcm2835_vcprop.h>
> +#include <dev/ofw/openfirm.h>
> +#include <dev/ofw/fdt.h>
> +
> +#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 bcmmbox_post(9) 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);
> +}
> diff --git sys/dev/fdt/bcm2835_clock.c sys/dev/fdt/bcm2835_clock.c
> index 8927f8968af..08493e30725 100644
> --- sys/dev/fdt/bcm2835_clock.c
> +++ sys/dev/fdt/bcm2835_clock.c
> @@ -53,6 +53,7 @@
>  #include <dev/ofw/ofw_clock.h>
>  #include <dev/ofw/openfirm.h>
>  
> +#include <dev/ic/bcm2835_clock.h>
>  #include <dev/ic/bcm2835_mbox.h>
>  #include <dev/ic/bcm2835_vcprop.h>
>  
> @@ -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,21 +114,80 @@ 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;
> +	uint32_t result;
> +	int error;
> +
> +	if (clk_vc_id == 0) {
> +		printf("%s: unknown clock id %d\n",
> +		    __func__, clk_vc_id);
> +		return (ENOENT);
> +	}
>  
> +	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
> +		}
> +	};
> +
> +	error = bcmmbox_post(BCMMBOX_CHANARM2VC, &req, sizeof(req), &result);
> +	if (error) {
> +		printf("%s: post 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 %d:%d\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;
> +		struct vcprop_tag_clockrate vbt_clkrate;
> +		struct vcprop_tag end;
> +	} __packed;
>  	uint32_t result;
> +	int error;
> +
> +	if (clk_vc_id == 0) {
> +		printf("%s: unknown clock id %d\n",
> +		    __func__, clk_vc_id);
> +		return (ENOENT);
> +	}
> +
>  	struct request req = {
>  		.vb_hdr = {
>  			.vpb_len = sizeof(req),
> @@ -135,68 +195,90 @@ 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
>  		}
>  	};
>  
> +	error = bcmmbox_post(BCMMBOX_CHANARM2VC, &req, sizeof(req), &result);
> +	if (error) {
> +		printf("%s: post error %d\n", __func__, error);
> +		return error;
> +	}
> +
> +	if (vcprop_tag_success_p(&req.vbt_clkrate.tag)) {
> +		return 0;
> +	} else {
> +		printf("%s: vcprop result %d:%d\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)
> +{
> +	uint32_t clk_id = 0;
> +	uint32_t res;
> +	int error;
> +
>  	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 %d\n", __func__, cells[0], error);
> +		return 0;
> +	}
>  
> -	return 0;
> +	return res;
>  }
> diff --git sys/dev/fdt/bcm2835_mbox.c sys/dev/fdt/bcm2835_mbox.c
> index 6987529f916..2835d90260a 100644
> --- sys/dev/fdt/bcm2835_mbox.c
> +++ sys/dev/fdt/bcm2835_mbox.c
> @@ -76,7 +76,14 @@ struct bcmmbox_softc {
>  
>  	void *sc_ih;
>  
> -	struct mutex sc_intr_lock;
> +	/*
> +	 * We only have one DMA buffer.
> +	 * Serialize bcmmbox_post(9) 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 +129,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");
> @@ -162,8 +170,8 @@ bcmmbox_attach(struct device *parent, struct device *self, void *aux)
>  		goto clean_dmamap_destroy;
>  	}
>  
> -	sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_VM, bcmmbox_intr, sc,
> -	    DEVNAME(sc));
> +	sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_VM,
> +	    bcmmbox_intr, sc, DEVNAME(sc));
>  	if (sc->sc_ih == NULL) {
>  		printf(": failed to establish interrupt\n");
>  		goto clean_dmamap;
> @@ -227,7 +235,9 @@ bcmmbox_intr_helper(struct bcmmbox_softc *sc, int broadcast)
>  
>  	bcmmbox_reg_flush(sc, BUS_SPACE_BARRIER_READ);
>  
> -	while (!ISSET(bcmmbox_reg_read(sc, BCMMBOX0_STATUS), BCMMBOX_STATUS_EMPTY)) {
> +	while (!ISSET(
> +	    bcmmbox_reg_read(sc, BCMMBOX0_STATUS),
> +	    BCMMBOX_STATUS_EMPTY)) {
>  		mbox = bcmmbox_reg_read(sc, BCMMBOX0_READ);
>  
>  		chan = mbox & BCMMBOX_CHANNEL_MASK;
> @@ -318,6 +328,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 +339,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;
>  }
> 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
> diff --git sys/dev/ic/bcm2835_vcprop.h sys/dev/ic/bcm2835_vcprop.h
> index 09350fc94c5..1488947ebba 100644
> --- sys/dev/ic/bcm2835_vcprop.h
> +++ sys/dev/ic/bcm2835_vcprop.h
> @@ -152,27 +152,48 @@ struct vcprop_tag_boardmodel {
>  	uint32_t model;
>  };
>  
> +/*
> + * Revision codes:
> + * <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)
>