xref: /openbsd-src/sys/arch/arm64/dev/aplefuse.c (revision 0f9e9ec23bb2b65cc62a3d17df12827a45dae80c)
1*0f9e9ec2Sjsg /*	$OpenBSD: aplefuse.c,v 1.2 2024/05/13 01:15:50 jsg Exp $	*/
234ba59a1Skettenis /*
334ba59a1Skettenis  * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
434ba59a1Skettenis  *
534ba59a1Skettenis  * Permission to use, copy, modify, and distribute this software for any
634ba59a1Skettenis  * purpose with or without fee is hereby granted, provided that the above
734ba59a1Skettenis  * copyright notice and this permission notice appear in all copies.
834ba59a1Skettenis  *
934ba59a1Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1034ba59a1Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1134ba59a1Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1234ba59a1Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1334ba59a1Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1434ba59a1Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1534ba59a1Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1634ba59a1Skettenis  */
1734ba59a1Skettenis 
1834ba59a1Skettenis #include <sys/param.h>
1934ba59a1Skettenis #include <sys/systm.h>
2034ba59a1Skettenis #include <sys/device.h>
2134ba59a1Skettenis 
2234ba59a1Skettenis #include <machine/bus.h>
2334ba59a1Skettenis #include <machine/fdt.h>
2434ba59a1Skettenis 
2534ba59a1Skettenis #include <dev/ofw/openfirm.h>
2634ba59a1Skettenis #include <dev/ofw/ofw_misc.h>
2734ba59a1Skettenis #include <dev/ofw/fdt.h>
2834ba59a1Skettenis 
2934ba59a1Skettenis struct aplefuse_softc {
3034ba59a1Skettenis 	struct device		sc_dev;
3134ba59a1Skettenis 	bus_space_tag_t		sc_iot;
3234ba59a1Skettenis 	bus_space_handle_t	sc_ioh;
3334ba59a1Skettenis 	bus_size_t		sc_ios;
3434ba59a1Skettenis 
3534ba59a1Skettenis 	struct nvmem_device	sc_nd;
3634ba59a1Skettenis };
3734ba59a1Skettenis 
3834ba59a1Skettenis int	aplefuse_match(struct device *, void *, void *);
3934ba59a1Skettenis void	aplefuse_attach(struct device *, struct device *, void *);
4034ba59a1Skettenis 
4134ba59a1Skettenis const struct cfattach aplefuse_ca = {
4234ba59a1Skettenis 	sizeof (struct aplefuse_softc), aplefuse_match, aplefuse_attach
4334ba59a1Skettenis };
4434ba59a1Skettenis 
4534ba59a1Skettenis struct cfdriver aplefuse_cd = {
4634ba59a1Skettenis 	NULL, "aplefuse", DV_DULL
4734ba59a1Skettenis };
4834ba59a1Skettenis 
4934ba59a1Skettenis int	aplefuse_nvmem_read(void *, bus_addr_t, void *, bus_size_t);
5034ba59a1Skettenis 
5134ba59a1Skettenis int
aplefuse_match(struct device * parent,void * match,void * aux)5234ba59a1Skettenis aplefuse_match(struct device *parent, void *match, void *aux)
5334ba59a1Skettenis {
5434ba59a1Skettenis 	struct fdt_attach_args *faa = aux;
5534ba59a1Skettenis 
5634ba59a1Skettenis 	return OF_is_compatible(faa->fa_node, "apple,efuses");
5734ba59a1Skettenis }
5834ba59a1Skettenis 
5934ba59a1Skettenis void
aplefuse_attach(struct device * parent,struct device * self,void * aux)6034ba59a1Skettenis aplefuse_attach(struct device *parent, struct device *self, void *aux)
6134ba59a1Skettenis {
6234ba59a1Skettenis 	struct aplefuse_softc *sc = (struct aplefuse_softc *)self;
6334ba59a1Skettenis 	struct fdt_attach_args *faa = aux;
6434ba59a1Skettenis 
6534ba59a1Skettenis 	if (faa->fa_nreg < 1) {
6634ba59a1Skettenis 		printf(": no registers\n");
6734ba59a1Skettenis 		return;
6834ba59a1Skettenis 	}
6934ba59a1Skettenis 
7034ba59a1Skettenis 	sc->sc_iot = faa->fa_iot;
7134ba59a1Skettenis 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
7234ba59a1Skettenis 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
7334ba59a1Skettenis 		printf(": can't map registers\n");
7434ba59a1Skettenis 		return;
7534ba59a1Skettenis 	}
7634ba59a1Skettenis 	sc->sc_ios = faa->fa_reg[0].size;
7734ba59a1Skettenis 
7834ba59a1Skettenis 	printf("\n");
7934ba59a1Skettenis 
8034ba59a1Skettenis 	sc->sc_nd.nd_node = faa->fa_node;
8134ba59a1Skettenis 	sc->sc_nd.nd_cookie = sc;
8234ba59a1Skettenis 	sc->sc_nd.nd_read = aplefuse_nvmem_read;
8334ba59a1Skettenis 	nvmem_register(&sc->sc_nd);
8434ba59a1Skettenis }
8534ba59a1Skettenis 
8634ba59a1Skettenis int
aplefuse_nvmem_read(void * cookie,bus_addr_t addr,void * data,bus_size_t size)8734ba59a1Skettenis aplefuse_nvmem_read(void *cookie, bus_addr_t addr, void *data, bus_size_t size)
8834ba59a1Skettenis {
8934ba59a1Skettenis 	struct aplefuse_softc *sc = cookie;
9034ba59a1Skettenis 	uint8_t *p = data;
9134ba59a1Skettenis 	uint32_t value;
9234ba59a1Skettenis 	uint8_t buf[4];
9334ba59a1Skettenis 	int offset;
9434ba59a1Skettenis 
9534ba59a1Skettenis 	if (addr > sc->sc_ios || size > sc->sc_ios - addr)
9634ba59a1Skettenis 		return EINVAL;
9734ba59a1Skettenis 
9834ba59a1Skettenis 	offset = addr & 0x3;
9934ba59a1Skettenis 	addr &= ~0x3;
10034ba59a1Skettenis 	while (size > 0) {
10134ba59a1Skettenis 		value = bus_space_read_4(sc->sc_iot, sc->sc_ioh, addr);
10234ba59a1Skettenis 		htolem32(buf, value);
10334ba59a1Skettenis 		memcpy(p, &buf[offset], MIN(size, 4 - offset));
10434ba59a1Skettenis 		size -= MIN(size, 4 - offset);
10534ba59a1Skettenis 		p += MIN(size, 4 - offset);
10634ba59a1Skettenis 		addr += 4;
10734ba59a1Skettenis 		offset = 0;
10834ba59a1Skettenis 	}
10934ba59a1Skettenis 
11034ba59a1Skettenis 	return 0;
11134ba59a1Skettenis }
112