1 /* $OpenBSD: imxspi.c,v 1.5 2024/05/13 01:15:50 jsg Exp $ */ 2 /* 3 * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se> 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/kernel.h> 21 #include <sys/device.h> 22 #include <sys/malloc.h> 23 #include <sys/stdint.h> 24 25 #include <machine/bus.h> 26 #include <machine/fdt.h> 27 28 #include <dev/spi/spivar.h> 29 #include <dev/ofw/openfirm.h> 30 #include <dev/ofw/ofw_clock.h> 31 #include <dev/ofw/ofw_gpio.h> 32 #include <dev/ofw/ofw_pinctrl.h> 33 #include <dev/ofw/fdt.h> 34 35 /* registers */ 36 #define SPI_RXDATA 0x00 37 #define SPI_TXDATA 0x04 38 #define SPI_CONREG 0x08 39 #define SPI_CONREG_EN (1 << 0) 40 #define SPI_CONREG_HT (1 << 1) 41 #define SPI_CONREG_XCH (1 << 2) 42 #define SPI_CONREG_SMC (1 << 3) 43 #define SPI_CONREG_CHANNEL_MASTER (0xf << 4) 44 #define SPI_CONREG_POST_DIVIDER_SHIFT 8 45 #define SPI_CONREG_POST_DIVIDER_MASK 0xf 46 #define SPI_CONREG_PRE_DIVIDER_SHIFT 12 47 #define SPI_CONREG_PRE_DIVIDER_MASK 0xf 48 #define SPI_CONREG_DRCTL_SHIFT 16 49 #define SPI_CONREG_DRCTL_MASK 0x3 50 #define SPI_CONREG_CHANNEL_SELECT(x) ((x) << 18) 51 #define SPI_CONREG_BURST_LENGTH(x) ((x) << 20) 52 #define SPI_CONFIGREG 0x0c 53 #define SPI_CONFIGREG_SCLK_PHA(x) (1 << (0 + (x))) 54 #define SPI_CONFIGREG_SCLK_POL(x) (1 << (4 + (x))) 55 #define SPI_CONFIGREG_SS_CTL(x) (1 << (8 + (x))) 56 #define SPI_CONFIGREG_SS_POL(x) (1 << (12 + (x))) 57 #define SPI_CONFIGREG_DATA_CTL(x) (1 << (16 + (x))) 58 #define SPI_CONFIGREG_SCLK_CTL(x) (1 << (20 + (x))) 59 #define SPI_CONFIGREG_HT_LENGTH(x) (((x) & 0x1f) << 24) 60 #define SPI_INTREG 0x10 61 #define SPI_INTREG_TEEN (1 << 0) 62 #define SPI_INTREG_TDREN (1 << 1) 63 #define SPI_INTREG_TFEN (1 << 2) 64 #define SPI_INTREG_RREN (1 << 3) 65 #define SPI_INTREG_RDREN (1 << 4) 66 #define SPI_INTREG_RFEN (1 << 5) 67 #define SPI_INTREG_ROEN (1 << 6) 68 #define SPI_INTREG_TCEN (1 << 7) 69 #define SPI_DMAREG 0x14 70 #define SPI_STATREG 0x18 71 #define SPI_STATREG_TE (1 << 0) 72 #define SPI_STATREG_TDR (1 << 1) 73 #define SPI_STATREG_TF (1 << 2) 74 #define SPI_STATREG_RR (1 << 3) 75 #define SPI_STATREG_RDR (1 << 4) 76 #define SPI_STATREG_RF (1 << 5) 77 #define SPI_STATREG_RO (1 << 6) 78 #define SPI_STATREG_TC (1 << 7) 79 #define SPI_PERIODREG 0x1c 80 #define SPI_TESTREG 0x20 81 #define SPI_TESTREG_LBC (1U << 31) 82 #define SPI_MSGDATA 0x40 83 84 #define DEVNAME(sc) ((sc)->sc_dev.dv_xname) 85 86 struct imxspi_softc { 87 struct device sc_dev; 88 bus_space_tag_t sc_iot; 89 bus_space_handle_t sc_ioh; 90 bus_size_t sc_ios; 91 int sc_node; 92 93 uint32_t *sc_gpio; 94 int sc_gpiolen; 95 96 struct rwlock sc_buslock; 97 struct spi_controller sc_tag; 98 99 int sc_ridx; 100 int sc_widx; 101 int sc_cs; 102 u_int sc_cs_delay; 103 }; 104 105 int imxspi_match(struct device *, void *, void *); 106 void imxspi_attach(struct device *, struct device *, void *); 107 void imxspi_attachhook(struct device *); 108 int imxspi_detach(struct device *, int); 109 110 void imxspi_config(void *, struct spi_config *); 111 uint32_t imxspi_clkdiv(struct imxspi_softc *, uint32_t); 112 int imxspi_transfer(void *, char *, char *, int, int); 113 int imxspi_acquire_bus(void *, int); 114 void imxspi_release_bus(void *, int); 115 116 void *imxspi_find_cs_gpio(struct imxspi_softc *, int); 117 int imxspi_wait_state(struct imxspi_softc *, uint32_t, uint32_t); 118 119 void imxspi_scan(struct imxspi_softc *); 120 121 #define HREAD4(sc, reg) \ 122 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 123 #define HWRITE4(sc, reg, val) \ 124 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 125 #define HSET4(sc, reg, bits) \ 126 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 127 #define HCLR4(sc, reg, bits) \ 128 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 129 130 const struct cfattach imxspi_ca = { 131 sizeof(struct imxspi_softc), imxspi_match, imxspi_attach, 132 imxspi_detach 133 }; 134 135 struct cfdriver imxspi_cd = { 136 NULL, "imxspi", DV_DULL 137 }; 138 139 int 140 imxspi_match(struct device *parent, void *match, void *aux) 141 { 142 struct fdt_attach_args *faa = aux; 143 144 return OF_is_compatible(faa->fa_node, "fsl,imx51-ecspi"); 145 } 146 147 void 148 imxspi_attach(struct device *parent, struct device *self, void *aux) 149 { 150 struct imxspi_softc *sc = (struct imxspi_softc *)self; 151 struct fdt_attach_args *faa = aux; 152 153 if (faa->fa_nreg < 1) 154 return; 155 156 sc->sc_iot = faa->fa_iot; 157 sc->sc_ios = faa->fa_reg[0].size; 158 sc->sc_node = faa->fa_node; 159 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 160 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 161 printf(": can't map registers\n"); 162 return; 163 } 164 165 printf("\n"); 166 167 config_mountroot(self, imxspi_attachhook); 168 } 169 170 void 171 imxspi_attachhook(struct device *self) 172 { 173 struct imxspi_softc *sc = (struct imxspi_softc *)self; 174 uint32_t *gpio; 175 int i; 176 177 pinctrl_byname(sc->sc_node, "default"); 178 clock_enable(sc->sc_node, NULL); 179 180 sc->sc_gpiolen = OF_getproplen(sc->sc_node, "cs-gpios"); 181 if (sc->sc_gpiolen > 0) { 182 sc->sc_gpio = malloc(sc->sc_gpiolen, M_DEVBUF, M_WAITOK); 183 OF_getpropintarray(sc->sc_node, "cs-gpios", 184 sc->sc_gpio, sc->sc_gpiolen); 185 for (i = 0; i < 4; i++) { 186 gpio = imxspi_find_cs_gpio(sc, i); 187 if (gpio == NULL) 188 break; 189 gpio_controller_config_pin(gpio, 190 GPIO_CONFIG_OUTPUT); 191 gpio_controller_set_pin(gpio, 1); 192 } 193 } 194 195 /* disable interrupts */ 196 HWRITE4(sc, SPI_INTREG, 0); 197 HWRITE4(sc, SPI_STATREG, SPI_STATREG_TC); 198 199 /* drain input buffer */ 200 while (HREAD4(sc, SPI_STATREG) & SPI_STATREG_RR) 201 HREAD4(sc, SPI_RXDATA); 202 203 rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname); 204 205 sc->sc_tag.sc_cookie = sc; 206 sc->sc_tag.sc_config = imxspi_config; 207 sc->sc_tag.sc_transfer = imxspi_transfer; 208 sc->sc_tag.sc_acquire_bus = imxspi_acquire_bus; 209 sc->sc_tag.sc_release_bus = imxspi_release_bus; 210 211 imxspi_scan(sc); 212 } 213 214 int 215 imxspi_detach(struct device *self, int flags) 216 { 217 struct imxspi_softc *sc = (struct imxspi_softc *)self; 218 219 HWRITE4(sc, SPI_CONREG, 0); 220 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); 221 free(sc->sc_gpio, M_DEVBUF, sc->sc_gpiolen); 222 return 0; 223 } 224 225 void 226 imxspi_config(void *cookie, struct spi_config *conf) 227 { 228 struct imxspi_softc *sc = cookie; 229 uint32_t conreg, configreg; 230 int cs; 231 232 cs = conf->sc_cs; 233 if (cs > 4) { 234 printf("%s: invalid chip-select (%d)\n", DEVNAME(sc), cs); 235 return; 236 } 237 sc->sc_cs = cs; 238 sc->sc_cs_delay = conf->sc_cs_delay; 239 240 conreg = SPI_CONREG_EN; 241 conreg |= SPI_CONREG_CHANNEL_MASTER; 242 conreg |= imxspi_clkdiv(sc, conf->sc_freq); 243 conreg |= SPI_CONREG_CHANNEL_SELECT(cs); 244 conreg |= SPI_CONREG_BURST_LENGTH(conf->sc_bpw - 1); 245 246 configreg = HREAD4(sc, SPI_CONFIGREG); 247 configreg &= ~SPI_CONFIGREG_SCLK_PHA(cs); 248 if (conf->sc_flags & SPI_CONFIG_CPHA) 249 configreg |= SPI_CONFIGREG_SCLK_PHA(cs); 250 configreg &= ~SPI_CONFIGREG_SCLK_POL(cs); 251 configreg &= ~SPI_CONFIGREG_SCLK_CTL(cs); 252 if (conf->sc_flags & SPI_CONFIG_CPOL) { 253 configreg |= SPI_CONFIGREG_SCLK_POL(cs); 254 configreg |= SPI_CONFIGREG_SCLK_CTL(cs); 255 } 256 configreg |= SPI_CONFIGREG_SS_CTL(cs); 257 configreg &= ~SPI_CONFIGREG_SS_POL(cs); 258 if (conf->sc_flags & SPI_CONFIG_CS_HIGH) 259 configreg |= SPI_CONFIGREG_SS_POL(cs); 260 261 HWRITE4(sc, SPI_CONREG, conreg); 262 HWRITE4(sc, SPI_TESTREG, HREAD4(sc, SPI_TESTREG) & 263 ~SPI_TESTREG_LBC); 264 HWRITE4(sc, SPI_CONFIGREG, configreg); 265 delay(1000); 266 } 267 268 uint32_t 269 imxspi_clkdiv(struct imxspi_softc *sc, uint32_t freq) 270 { 271 uint32_t pre, post; 272 uint32_t pfreq; 273 274 pfreq = clock_get_frequency(sc->sc_node, "per"); 275 276 pre = 0, post = 0; 277 while ((freq * (1 << post) * 16) < pfreq) 278 post++; 279 while ((freq * (1 << post) * (pre + 1)) < pfreq) 280 pre++; 281 if (post >= 16 || pre >= 16) { 282 printf("%s: clock frequency too high\n", 283 DEVNAME(sc)); 284 return 0; 285 } 286 287 return (pre << SPI_CONREG_PRE_DIVIDER_SHIFT | 288 post << SPI_CONREG_POST_DIVIDER_SHIFT); 289 } 290 291 int 292 imxspi_wait_state(struct imxspi_softc *sc, uint32_t mask, uint32_t value) 293 { 294 uint32_t state; 295 int timeout; 296 state = HREAD4(sc, SPI_STATREG); 297 for (timeout = 1000; timeout > 0; timeout--) { 298 if (((state = HREAD4(sc, SPI_STATREG)) & mask) == value) 299 return 0; 300 delay(10); 301 } 302 printf("%s: timeout mask %x value %x\n", __func__, mask, value); 303 return ETIMEDOUT; 304 } 305 306 void * 307 imxspi_find_cs_gpio(struct imxspi_softc *sc, int cs) 308 { 309 uint32_t *gpio; 310 311 if (sc->sc_gpio == NULL) 312 return NULL; 313 314 gpio = sc->sc_gpio; 315 while (gpio < sc->sc_gpio + (sc->sc_gpiolen / 4)) { 316 if (cs == 0) 317 return gpio; 318 gpio = gpio_controller_next_pin(gpio); 319 cs--; 320 } 321 322 return NULL; 323 } 324 325 int 326 imxspi_transfer(void *cookie, char *out, char *in, int len, int flags) 327 { 328 struct imxspi_softc *sc = cookie; 329 uint32_t *gpio; 330 int i; 331 332 sc->sc_ridx = sc->sc_widx = 0; 333 334 gpio = imxspi_find_cs_gpio(sc, sc->sc_cs); 335 if (gpio) { 336 gpio_controller_set_pin(gpio, 0); 337 delay(1); 338 } 339 delay(sc->sc_cs_delay); 340 341 /* drain input buffer */ 342 while (HREAD4(sc, SPI_STATREG) & SPI_STATREG_RR) 343 HREAD4(sc, SPI_RXDATA); 344 345 while (sc->sc_ridx < len || sc->sc_widx < len) { 346 for (i = sc->sc_widx; i < len; i++) { 347 if (imxspi_wait_state(sc, SPI_STATREG_TF, 0)) 348 goto err; 349 if (out) 350 HWRITE4(sc, SPI_TXDATA, out[i]); 351 else 352 HWRITE4(sc, SPI_TXDATA, 0xff); 353 sc->sc_widx++; 354 if (HREAD4(sc, SPI_STATREG) & SPI_STATREG_TF) 355 break; 356 } 357 358 HSET4(sc, SPI_CONREG, SPI_CONREG_XCH); 359 if (imxspi_wait_state(sc, SPI_STATREG_TC, SPI_STATREG_TC)) 360 goto err; 361 362 for (i = sc->sc_ridx; i < sc->sc_widx; i++) { 363 if (imxspi_wait_state(sc, SPI_STATREG_RR, SPI_STATREG_RR)) 364 goto err; 365 if (in) 366 in[i] = HREAD4(sc, SPI_RXDATA); 367 else 368 HREAD4(sc, SPI_RXDATA); 369 sc->sc_ridx++; 370 } 371 372 HWRITE4(sc, SPI_STATREG, SPI_STATREG_TC); 373 } 374 375 if (!ISSET(flags, SPI_KEEP_CS)) { 376 gpio = imxspi_find_cs_gpio(sc, sc->sc_cs); 377 if (gpio) { 378 gpio_controller_set_pin(gpio, 1); 379 delay(1); 380 } 381 } 382 383 return 0; 384 err: 385 HWRITE4(sc, SPI_CONREG, 0); 386 HWRITE4(sc, SPI_STATREG, SPI_STATREG_TC); 387 return ETIMEDOUT; 388 } 389 390 int 391 imxspi_acquire_bus(void *cookie, int flags) 392 { 393 struct imxspi_softc *sc = cookie; 394 395 rw_enter(&sc->sc_buslock, RW_WRITE); 396 return 0; 397 } 398 399 void 400 imxspi_release_bus(void *cookie, int flags) 401 { 402 struct imxspi_softc *sc = cookie; 403 404 rw_exit(&sc->sc_buslock); 405 } 406 407 void 408 imxspi_scan(struct imxspi_softc *sc) 409 { 410 struct spi_attach_args sa; 411 uint32_t reg[1]; 412 char name[32]; 413 int node; 414 415 for (node = OF_child(sc->sc_node); node; node = OF_peer(node)) { 416 memset(name, 0, sizeof(name)); 417 memset(reg, 0, sizeof(reg)); 418 419 if (OF_getprop(node, "compatible", name, sizeof(name)) == -1) 420 continue; 421 if (name[0] == '\0') 422 continue; 423 424 if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) 425 continue; 426 427 memset(&sa, 0, sizeof(sa)); 428 sa.sa_tag = &sc->sc_tag; 429 sa.sa_name = name; 430 sa.sa_cookie = &node; 431 432 config_found(&sc->sc_dev, &sa, NULL); 433 } 434 } 435