1 /* $OpenBSD: aplefuse.c,v 1.2 2024/05/13 01:15:50 jsg Exp $ */
2 /*
3 * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21
22 #include <machine/bus.h>
23 #include <machine/fdt.h>
24
25 #include <dev/ofw/openfirm.h>
26 #include <dev/ofw/ofw_misc.h>
27 #include <dev/ofw/fdt.h>
28
29 struct aplefuse_softc {
30 struct device sc_dev;
31 bus_space_tag_t sc_iot;
32 bus_space_handle_t sc_ioh;
33 bus_size_t sc_ios;
34
35 struct nvmem_device sc_nd;
36 };
37
38 int aplefuse_match(struct device *, void *, void *);
39 void aplefuse_attach(struct device *, struct device *, void *);
40
41 const struct cfattach aplefuse_ca = {
42 sizeof (struct aplefuse_softc), aplefuse_match, aplefuse_attach
43 };
44
45 struct cfdriver aplefuse_cd = {
46 NULL, "aplefuse", DV_DULL
47 };
48
49 int aplefuse_nvmem_read(void *, bus_addr_t, void *, bus_size_t);
50
51 int
aplefuse_match(struct device * parent,void * match,void * aux)52 aplefuse_match(struct device *parent, void *match, void *aux)
53 {
54 struct fdt_attach_args *faa = aux;
55
56 return OF_is_compatible(faa->fa_node, "apple,efuses");
57 }
58
59 void
aplefuse_attach(struct device * parent,struct device * self,void * aux)60 aplefuse_attach(struct device *parent, struct device *self, void *aux)
61 {
62 struct aplefuse_softc *sc = (struct aplefuse_softc *)self;
63 struct fdt_attach_args *faa = aux;
64
65 if (faa->fa_nreg < 1) {
66 printf(": no registers\n");
67 return;
68 }
69
70 sc->sc_iot = faa->fa_iot;
71 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
72 faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
73 printf(": can't map registers\n");
74 return;
75 }
76 sc->sc_ios = faa->fa_reg[0].size;
77
78 printf("\n");
79
80 sc->sc_nd.nd_node = faa->fa_node;
81 sc->sc_nd.nd_cookie = sc;
82 sc->sc_nd.nd_read = aplefuse_nvmem_read;
83 nvmem_register(&sc->sc_nd);
84 }
85
86 int
aplefuse_nvmem_read(void * cookie,bus_addr_t addr,void * data,bus_size_t size)87 aplefuse_nvmem_read(void *cookie, bus_addr_t addr, void *data, bus_size_t size)
88 {
89 struct aplefuse_softc *sc = cookie;
90 uint8_t *p = data;
91 uint32_t value;
92 uint8_t buf[4];
93 int offset;
94
95 if (addr > sc->sc_ios || size > sc->sc_ios - addr)
96 return EINVAL;
97
98 offset = addr & 0x3;
99 addr &= ~0x3;
100 while (size > 0) {
101 value = bus_space_read_4(sc->sc_iot, sc->sc_ioh, addr);
102 htolem32(buf, value);
103 memcpy(p, &buf[offset], MIN(size, 4 - offset));
104 size -= MIN(size, 4 - offset);
105 p += MIN(size, 4 - offset);
106 addr += 4;
107 offset = 0;
108 }
109
110 return 0;
111 }
112