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