1 /* $OpenBSD: imxspi.c,v 1.3 2021/10/31 15:12:00 kettenis 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 size_t 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 int imxspi_intr(void *); 110 111 void imxspi_config(void *, struct spi_config *); 112 uint32_t imxspi_clkdiv(struct imxspi_softc *, uint32_t); 113 int imxspi_transfer(void *, char *, char *, int, int); 114 int imxspi_acquire_bus(void *, int); 115 void imxspi_release_bus(void *, int); 116 117 void *imxspi_find_cs_gpio(struct imxspi_softc *, int); 118 int imxspi_wait_state(struct imxspi_softc *, uint32_t, uint32_t); 119 120 void imxspi_scan(struct imxspi_softc *); 121 122 #define HREAD4(sc, reg) \ 123 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 124 #define HWRITE4(sc, reg, val) \ 125 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 126 #define HSET4(sc, reg, bits) \ 127 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 128 #define HCLR4(sc, reg, bits) \ 129 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 130 131 const struct cfattach imxspi_ca = { 132 sizeof(struct imxspi_softc), imxspi_match, imxspi_attach, 133 imxspi_detach 134 }; 135 136 struct cfdriver imxspi_cd = { 137 NULL, "imxspi", DV_DULL 138 }; 139 140 int 141 imxspi_match(struct device *parent, void *match, void *aux) 142 { 143 struct fdt_attach_args *faa = aux; 144 145 return OF_is_compatible(faa->fa_node, "fsl,imx51-ecspi"); 146 } 147 148 void 149 imxspi_attach(struct device *parent, struct device *self, void *aux) 150 { 151 struct imxspi_softc *sc = (struct imxspi_softc *)self; 152 struct fdt_attach_args *faa = aux; 153 154 if (faa->fa_nreg < 1) 155 return; 156 157 sc->sc_iot = faa->fa_iot; 158 sc->sc_ios = faa->fa_reg[0].size; 159 sc->sc_node = faa->fa_node; 160 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 161 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 162 printf(": can't map registers\n"); 163 return; 164 } 165 166 printf("\n"); 167 168 config_mountroot(self, imxspi_attachhook); 169 } 170 171 void 172 imxspi_attachhook(struct device *self) 173 { 174 struct imxspi_softc *sc = (struct imxspi_softc *)self; 175 uint32_t *gpio; 176 int i; 177 178 pinctrl_byname(sc->sc_node, "default"); 179 clock_enable(sc->sc_node, NULL); 180 181 sc->sc_gpiolen = OF_getproplen(sc->sc_node, "cs-gpios"); 182 if (sc->sc_gpiolen) { 183 sc->sc_gpio = malloc(sc->sc_gpiolen, M_DEVBUF, M_WAITOK); 184 OF_getpropintarray(sc->sc_node, "cs-gpios", 185 sc->sc_gpio, sc->sc_gpiolen); 186 for (i = 0; i < 4; i++) { 187 gpio = imxspi_find_cs_gpio(sc, i); 188 if (gpio == NULL) 189 break; 190 gpio_controller_config_pin(gpio, 191 GPIO_CONFIG_OUTPUT); 192 gpio_controller_set_pin(gpio, 1); 193 } 194 } 195 196 /* disable interrupts */ 197 HWRITE4(sc, SPI_INTREG, 0); 198 HWRITE4(sc, SPI_STATREG, SPI_STATREG_TC); 199 200 /* drain input buffer */ 201 while (HREAD4(sc, SPI_STATREG) & SPI_STATREG_RR) 202 HREAD4(sc, SPI_RXDATA); 203 204 rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname); 205 206 sc->sc_tag.sc_cookie = sc; 207 sc->sc_tag.sc_config = imxspi_config; 208 sc->sc_tag.sc_transfer = imxspi_transfer; 209 sc->sc_tag.sc_acquire_bus = imxspi_acquire_bus; 210 sc->sc_tag.sc_release_bus = imxspi_release_bus; 211 212 imxspi_scan(sc); 213 } 214 215 int 216 imxspi_detach(struct device *self, int flags) 217 { 218 struct imxspi_softc *sc = (struct imxspi_softc *)self; 219 220 HWRITE4(sc, SPI_CONREG, 0); 221 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); 222 free(sc->sc_gpio, M_DEVBUF, sc->sc_gpiolen); 223 return 0; 224 } 225 226 void 227 imxspi_config(void *cookie, struct spi_config *conf) 228 { 229 struct imxspi_softc *sc = cookie; 230 uint32_t conreg, configreg; 231 int cs; 232 233 cs = conf->sc_cs; 234 if (cs > 4) { 235 printf("%s: invalid chip-select (%d)\n", DEVNAME(sc), cs); 236 return; 237 } 238 sc->sc_cs = cs; 239 sc->sc_cs_delay = conf->sc_cs_delay; 240 241 conreg = SPI_CONREG_EN; 242 conreg |= SPI_CONREG_CHANNEL_MASTER; 243 conreg |= imxspi_clkdiv(sc, conf->sc_freq); 244 conreg |= SPI_CONREG_CHANNEL_SELECT(cs); 245 conreg |= SPI_CONREG_BURST_LENGTH(conf->sc_bpw - 1); 246 247 configreg = HREAD4(sc, SPI_CONFIGREG); 248 configreg &= ~SPI_CONFIGREG_SCLK_PHA(cs); 249 if (conf->sc_flags & SPI_CONFIG_CPHA) 250 configreg |= SPI_CONFIGREG_SCLK_PHA(cs); 251 configreg &= ~SPI_CONFIGREG_SCLK_POL(cs); 252 configreg &= ~SPI_CONFIGREG_SCLK_CTL(cs); 253 if (conf->sc_flags & SPI_CONFIG_CPOL) { 254 configreg |= SPI_CONFIGREG_SCLK_POL(cs); 255 configreg |= SPI_CONFIGREG_SCLK_CTL(cs); 256 } 257 configreg |= SPI_CONFIGREG_SS_CTL(cs); 258 configreg &= ~SPI_CONFIGREG_SS_POL(cs); 259 if (conf->sc_flags & SPI_CONFIG_CS_HIGH) 260 configreg |= SPI_CONFIGREG_SS_POL(cs); 261 262 HWRITE4(sc, SPI_CONREG, conreg); 263 HWRITE4(sc, SPI_TESTREG, HREAD4(sc, SPI_TESTREG) & 264 ~SPI_TESTREG_LBC); 265 HWRITE4(sc, SPI_CONFIGREG, configreg); 266 delay(1000); 267 } 268 269 uint32_t 270 imxspi_clkdiv(struct imxspi_softc *sc, uint32_t freq) 271 { 272 uint32_t pre, post; 273 uint32_t pfreq; 274 275 pfreq = clock_get_frequency(sc->sc_node, "per"); 276 277 pre = 0, post = 0; 278 while ((freq * (1 << post) * 16) < pfreq) 279 post++; 280 while ((freq * (1 << post) * (pre + 1)) < pfreq) 281 pre++; 282 if (post >= 16 || pre >= 16) { 283 printf("%s: clock frequency too high\n", 284 DEVNAME(sc)); 285 return 0; 286 } 287 288 return (pre << SPI_CONREG_PRE_DIVIDER_SHIFT | 289 post << SPI_CONREG_POST_DIVIDER_SHIFT); 290 } 291 292 int 293 imxspi_wait_state(struct imxspi_softc *sc, uint32_t mask, uint32_t value) 294 { 295 uint32_t state; 296 int timeout; 297 state = HREAD4(sc, SPI_STATREG); 298 for (timeout = 1000; timeout > 0; timeout--) { 299 if (((state = HREAD4(sc, SPI_STATREG)) & mask) == value) 300 return 0; 301 delay(10); 302 } 303 printf("%s: timeout mask %x value %x\n", __func__, mask, value); 304 return ETIMEDOUT; 305 } 306 307 void * 308 imxspi_find_cs_gpio(struct imxspi_softc *sc, int cs) 309 { 310 uint32_t *gpio; 311 312 if (sc->sc_gpio == NULL) 313 return NULL; 314 315 gpio = sc->sc_gpio; 316 while (gpio < sc->sc_gpio + (sc->sc_gpiolen / 4)) { 317 if (cs == 0) 318 return gpio; 319 gpio = gpio_controller_next_pin(gpio); 320 cs--; 321 } 322 323 return NULL; 324 } 325 326 int 327 imxspi_transfer(void *cookie, char *out, char *in, int len, int flags) 328 { 329 struct imxspi_softc *sc = cookie; 330 uint32_t *gpio; 331 int i; 332 333 sc->sc_ridx = sc->sc_widx = 0; 334 335 gpio = imxspi_find_cs_gpio(sc, sc->sc_cs); 336 if (gpio) { 337 gpio_controller_set_pin(gpio, 0); 338 delay(1); 339 } 340 delay(sc->sc_cs_delay); 341 342 /* drain input buffer */ 343 while (HREAD4(sc, SPI_STATREG) & SPI_STATREG_RR) 344 HREAD4(sc, SPI_RXDATA); 345 346 while (sc->sc_ridx < len || sc->sc_widx < len) { 347 for (i = sc->sc_widx; i < len; i++) { 348 if (imxspi_wait_state(sc, SPI_STATREG_TF, 0)) 349 goto err; 350 if (out) 351 HWRITE4(sc, SPI_TXDATA, out[i]); 352 else 353 HWRITE4(sc, SPI_TXDATA, 0xff); 354 sc->sc_widx++; 355 if (HREAD4(sc, SPI_STATREG) & SPI_STATREG_TF) 356 break; 357 } 358 359 HSET4(sc, SPI_CONREG, SPI_CONREG_XCH); 360 if (imxspi_wait_state(sc, SPI_STATREG_TC, SPI_STATREG_TC)) 361 goto err; 362 363 for (i = sc->sc_ridx; i < sc->sc_widx; i++) { 364 if (imxspi_wait_state(sc, SPI_STATREG_RR, SPI_STATREG_RR)) 365 goto err; 366 if (in) 367 in[i] = HREAD4(sc, SPI_RXDATA); 368 else 369 HREAD4(sc, SPI_RXDATA); 370 sc->sc_ridx++; 371 } 372 373 HWRITE4(sc, SPI_STATREG, SPI_STATREG_TC); 374 } 375 376 if (!ISSET(flags, SPI_KEEP_CS)) { 377 gpio = imxspi_find_cs_gpio(sc, sc->sc_cs); 378 if (gpio) { 379 gpio_controller_set_pin(gpio, 1); 380 delay(1); 381 } 382 } 383 384 return 0; 385 err: 386 HWRITE4(sc, SPI_CONREG, 0); 387 HWRITE4(sc, SPI_STATREG, SPI_STATREG_TC); 388 return ETIMEDOUT; 389 } 390 391 int 392 imxspi_acquire_bus(void *cookie, int flags) 393 { 394 struct imxspi_softc *sc = cookie; 395 396 rw_enter(&sc->sc_buslock, RW_WRITE); 397 return 0; 398 } 399 400 void 401 imxspi_release_bus(void *cookie, int flags) 402 { 403 struct imxspi_softc *sc = cookie; 404 405 rw_exit(&sc->sc_buslock); 406 } 407 408 void 409 imxspi_scan(struct imxspi_softc *sc) 410 { 411 struct spi_attach_args sa; 412 uint32_t reg[1]; 413 char name[32]; 414 int node; 415 416 for (node = OF_child(sc->sc_node); node; node = OF_peer(node)) { 417 memset(name, 0, sizeof(name)); 418 memset(reg, 0, sizeof(reg)); 419 420 if (OF_getprop(node, "compatible", name, sizeof(name)) == -1) 421 continue; 422 if (name[0] == '\0') 423 continue; 424 425 if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) 426 continue; 427 428 memset(&sa, 0, sizeof(sa)); 429 sa.sa_tag = &sc->sc_tag; 430 sa.sa_name = name; 431 sa.sa_cookie = &node; 432 433 config_found(&sc->sc_dev, &sa, NULL); 434 } 435 } 436