1 /* $OpenBSD: bcm2835_bsc.c,v 1.1 2020/04/25 22:28:12 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2020 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/intr.h> 23 #include <machine/bus.h> 24 #include <machine/fdt.h> 25 26 #define _I2C_PRIVATE 27 #include <dev/i2c/i2cvar.h> 28 29 #include <dev/ofw/openfirm.h> 30 #include <dev/ofw/ofw_clock.h> 31 #include <dev/ofw/ofw_pinctrl.h> 32 #include <dev/ofw/fdt.h> 33 34 /* Registers. */ 35 #define BSC_C 0x00 36 #define BSC_C_I2CEN (1 << 15) 37 #define BSC_C_INTR (1 << 10) 38 #define BSC_C_INTT (1 << 9) 39 #define BSC_C_INTD (1 << 8) 40 #define BSC_C_ST (1 << 7) 41 #define BSC_C_CLEAR (0x3 << 4) 42 #define BSC_C_READ (1 << 0) 43 #define BSC_S 0x04 44 #define BSC_S_CLKT (1 << 9) 45 #define BSC_S_ERR (1 << 8) 46 #define BSC_S_RXF (1 << 7) 47 #define BSC_S_TXE (1 << 6) 48 #define BSC_S_RXD (1 << 5) 49 #define BSC_S_TXD (1 << 4) 50 #define BSC_S_RXR (1 << 3) 51 #define BSC_S_TXW (1 << 2) 52 #define BSC_S_DONE (1 << 1) 53 #define BSC_S_TA (1 << 0) 54 #define BSC_DLEN 0x08 55 #define BSC_A 0x0c 56 #define BSC_FIFO 0x10 57 #define BSC_DIV 0x14 58 #define BSC_DEL 0x18 59 #define BSC_DEL_FEDL_SHIFT 16 60 #define BSC_DEL_REDL_SHIFT 0 61 #define BSC_CLKT 0x1c 62 63 #define HREAD4(sc, reg) \ 64 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 65 #define HWRITE4(sc, reg, val) \ 66 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 67 68 struct bcmbsc_softc { 69 struct device sc_dev; 70 bus_space_tag_t sc_iot; 71 bus_space_handle_t sc_ioh; 72 73 int sc_node; 74 struct i2c_controller sc_ic; 75 }; 76 77 int bcmbsc_match(struct device *, void *, void *); 78 void bcmbsc_attach(struct device *, struct device *, void *); 79 80 struct cfattach bcmbsc_ca = { 81 sizeof (struct bcmbsc_softc), bcmbsc_match, bcmbsc_attach 82 }; 83 84 struct cfdriver bcmbsc_cd = { 85 NULL, "bcmbsc", DV_DULL 86 }; 87 88 int bcmbsc_acquire_bus(void *, int); 89 void bcmbsc_release_bus(void *, int); 90 int bcmbsc_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t, 91 void *, size_t, int); 92 93 void bcmbsc_bus_scan(struct device *, struct i2cbus_attach_args *, void *); 94 95 int 96 bcmbsc_match(struct device *parent, void *match, void *aux) 97 { 98 struct fdt_attach_args *faa = aux; 99 100 return OF_is_compatible(faa->fa_node, "brcm,bcm2835-i2c"); 101 } 102 103 void 104 bcmbsc_attach(struct device *parent, struct device *self, void *aux) 105 { 106 struct bcmbsc_softc *sc = (struct bcmbsc_softc *)self; 107 struct fdt_attach_args *faa = aux; 108 struct i2cbus_attach_args iba; 109 uint32_t clock_speed, bus_speed; 110 uint32_t div, fedl, redl; 111 112 if (faa->fa_nreg < 1) { 113 printf(": no registers\n"); 114 return; 115 } 116 117 sc->sc_iot = faa->fa_iot; 118 sc->sc_node = faa->fa_node; 119 120 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 121 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 122 printf(": can't map registers\n"); 123 return; 124 } 125 126 printf("\n"); 127 128 pinctrl_byname(sc->sc_node, "default"); 129 130 clock_enable_all(sc->sc_node); 131 132 clock_speed = clock_get_frequency(sc->sc_node, NULL); 133 bus_speed = OF_getpropint(sc->sc_node, "clock-frequency", 100000); 134 135 div = clock_speed / bus_speed; 136 if (div & 1) 137 div++; 138 fedl = MAX(div / 16, 1); 139 redl = MAX(div / 4, 1); 140 HWRITE4(sc, BSC_DIV, div); 141 HWRITE4(sc, BSC_DEL, (fedl << BSC_DEL_FEDL_SHIFT) | 142 (redl << BSC_DEL_REDL_SHIFT)); 143 144 sc->sc_ic.ic_cookie = sc; 145 sc->sc_ic.ic_acquire_bus = bcmbsc_acquire_bus; 146 sc->sc_ic.ic_release_bus = bcmbsc_release_bus; 147 sc->sc_ic.ic_exec = bcmbsc_exec; 148 149 /* Configure its children */ 150 memset(&iba, 0, sizeof(iba)); 151 iba.iba_name = "iic"; 152 iba.iba_tag = &sc->sc_ic; 153 iba.iba_bus_scan = bcmbsc_bus_scan; 154 iba.iba_bus_scan_arg = &sc->sc_node; 155 156 config_found(&sc->sc_dev, &iba, iicbus_print); 157 } 158 159 int 160 bcmbsc_acquire_bus(void *cookie, int flags) 161 { 162 struct bcmbsc_softc *sc = cookie; 163 164 HWRITE4(sc, BSC_S, HREAD4(sc, BSC_S)); 165 HWRITE4(sc, BSC_C, BSC_C_I2CEN | BSC_C_CLEAR); 166 return 0; 167 } 168 169 void 170 bcmbsc_release_bus(void *cookie, int flags) 171 { 172 struct bcmbsc_softc *sc = cookie; 173 174 HWRITE4(sc, BSC_C, BSC_C_CLEAR); 175 } 176 177 int 178 bcmbsc_wait(struct bcmbsc_softc *sc, uint32_t mask, uint32_t value) 179 { 180 uint32_t stat; 181 int timo; 182 183 for (timo = 10000; timo > 0; timo--) { 184 stat = HREAD4(sc, BSC_S); 185 if ((stat & mask) == value) 186 return 0; 187 if (stat & BSC_S_CLKT) 188 return ETIMEDOUT; 189 if (stat & BSC_S_ERR) 190 return EIO; 191 delay(1); 192 } 193 194 return ETIMEDOUT; 195 } 196 197 int 198 bcmbsc_read(struct bcmbsc_softc *sc, uint8_t *buf, size_t buflen) 199 { 200 int i, error; 201 202 for (i = 0; i < buflen; i++) { 203 error = bcmbsc_wait(sc, BSC_S_RXD, BSC_S_RXD); 204 if (error) 205 return error; 206 buf[i] = HREAD4(sc, BSC_FIFO); 207 } 208 209 return 0; 210 } 211 212 int 213 bcmbsc_write(struct bcmbsc_softc *sc, const uint8_t *buf, size_t buflen) 214 { 215 int i, error; 216 217 for (i = 0; i < buflen; i++) { 218 error = bcmbsc_wait(sc, BSC_S_TXD, BSC_S_TXD); 219 if (error) 220 return error; 221 HWRITE4(sc, BSC_FIFO, buf[i]); 222 } 223 224 return 0; 225 } 226 227 int 228 bcmbsc_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd, 229 size_t cmdlen, void *buf, size_t buflen, int flags) 230 { 231 struct bcmbsc_softc *sc = cookie; 232 uint32_t ctrl = BSC_C_I2CEN | BSC_C_ST; 233 int error; 234 235 if (cmdlen + buflen > 65535) 236 return EINVAL; 237 238 HWRITE4(sc, BSC_A, addr); 239 240 if (I2C_OP_READ_P(op)) 241 HWRITE4(sc, BSC_DLEN, cmdlen); 242 else 243 HWRITE4(sc, BSC_DLEN, cmdlen + buflen); 244 245 if (cmdlen > 0) { 246 HWRITE4(sc, BSC_C, ctrl); 247 error = bcmbsc_write(sc, cmd, cmdlen); 248 if (error) 249 return error; 250 if (I2C_OP_READ_P(op)) 251 bcmbsc_wait(sc, BSC_S_DONE, BSC_S_DONE); 252 } 253 254 if (I2C_OP_READ_P(op)) { 255 HWRITE4(sc, BSC_DLEN, buflen); 256 HWRITE4(sc, BSC_C, ctrl | BSC_C_READ); 257 error = bcmbsc_read(sc, buf, buflen); 258 if (error) 259 return error; 260 } else { 261 if (cmdlen == 0) 262 HWRITE4(sc, BSC_C, ctrl); 263 error = bcmbsc_write(sc, buf, buflen); 264 if (error) 265 return error; 266 } 267 268 return bcmbsc_wait(sc, BSC_S_DONE | BSC_S_TA, BSC_S_DONE); 269 } 270 271 void 272 bcmbsc_bus_scan(struct device *self, struct i2cbus_attach_args *iba, void *arg) 273 { 274 int iba_node = *(int *)arg; 275 struct i2c_attach_args ia; 276 char name[32]; 277 uint32_t reg[1]; 278 int node; 279 280 for (node = OF_child(iba_node); node; node = OF_peer(node)) { 281 memset(name, 0, sizeof(name)); 282 memset(reg, 0, sizeof(reg)); 283 284 if (OF_getprop(node, "compatible", name, sizeof(name)) == -1) 285 continue; 286 if (name[0] == '\0') 287 continue; 288 289 if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) 290 continue; 291 292 memset(&ia, 0, sizeof(ia)); 293 ia.ia_tag = iba->iba_tag; 294 ia.ia_addr = bemtoh32(®[0]); 295 ia.ia_name = name; 296 ia.ia_cookie = &node; 297 config_found(self, &ia, iic_print); 298 } 299 } 300