1 /* $OpenBSD: imxspi.c,v 1.1 2018/07/26 10:59:07 patrick 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 }; 103 104 int imxspi_match(struct device *, void *, void *); 105 void imxspi_attach(struct device *, struct device *, void *); 106 void imxspi_attachhook(struct device *); 107 int imxspi_detach(struct device *, int); 108 int imxspi_intr(void *); 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); 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 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) { 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 239 conreg = SPI_CONREG_EN; 240 conreg |= SPI_CONREG_CHANNEL_MASTER; 241 conreg |= imxspi_clkdiv(sc, conf->sc_freq); 242 conreg |= SPI_CONREG_CHANNEL_SELECT(cs); 243 conreg |= SPI_CONREG_BURST_LENGTH(conf->sc_bpw - 1); 244 245 configreg = HREAD4(sc, SPI_CONFIGREG); 246 configreg &= ~SPI_CONFIGREG_SCLK_PHA(cs); 247 if (conf->sc_flags & SPI_CONFIG_CPHA) 248 configreg |= SPI_CONFIGREG_SCLK_PHA(cs); 249 configreg &= ~SPI_CONFIGREG_SCLK_POL(cs); 250 configreg &= ~SPI_CONFIGREG_SCLK_CTL(cs); 251 if (conf->sc_flags & SPI_CONFIG_CPOL) { 252 configreg |= SPI_CONFIGREG_SCLK_POL(cs); 253 configreg |= SPI_CONFIGREG_SCLK_CTL(cs); 254 } 255 configreg |= SPI_CONFIGREG_SS_CTL(cs); 256 configreg &= ~SPI_CONFIGREG_SS_POL(cs); 257 if (conf->sc_flags & SPI_CONFIG_CS_HIGH) 258 configreg |= SPI_CONFIGREG_SS_POL(cs); 259 260 HWRITE4(sc, SPI_CONREG, conreg); 261 HWRITE4(sc, SPI_TESTREG, HREAD4(sc, SPI_TESTREG) & 262 ~SPI_TESTREG_LBC); 263 HWRITE4(sc, SPI_CONFIGREG, configreg); 264 delay(1000); 265 } 266 267 uint32_t 268 imxspi_clkdiv(struct imxspi_softc *sc, uint32_t freq) 269 { 270 uint32_t pre, post; 271 uint32_t pfreq; 272 273 pfreq = clock_get_frequency(sc->sc_node, "per"); 274 275 pre = 0, post = 0; 276 while ((freq * (1 << post) * 16) < pfreq) 277 post++; 278 while ((freq * (1 << post) * (pre + 1)) < pfreq) 279 pre++; 280 if (post >= 16 || pre >= 16) { 281 printf("%s: clock frequency too high\n", 282 DEVNAME(sc)); 283 return 0; 284 } 285 286 return (pre << SPI_CONREG_PRE_DIVIDER_SHIFT | 287 post << SPI_CONREG_POST_DIVIDER_SHIFT); 288 } 289 290 int 291 imxspi_wait_state(struct imxspi_softc *sc, uint32_t mask, uint32_t value) 292 { 293 uint32_t state; 294 int timeout; 295 state = HREAD4(sc, SPI_STATREG); 296 for (timeout = 1000; timeout > 0; timeout--) { 297 if (((state = HREAD4(sc, SPI_STATREG)) & mask) == value) 298 return 0; 299 delay(10); 300 } 301 printf("%s: timeout mask %x value %x\n", __func__, mask, value); 302 return ETIMEDOUT; 303 } 304 305 void * 306 imxspi_find_cs_gpio(struct imxspi_softc *sc, int cs) 307 { 308 uint32_t *gpio; 309 310 if (sc->sc_gpio == NULL) 311 return NULL; 312 313 gpio = sc->sc_gpio; 314 while (gpio < sc->sc_gpio + (sc->sc_gpiolen / 4)) { 315 if (cs == 0) 316 return gpio; 317 gpio = gpio_controller_next_pin(gpio); 318 cs--; 319 } 320 321 return NULL; 322 } 323 324 int 325 imxspi_transfer(void *cookie, char *out, char *in, int len) 326 { 327 struct imxspi_softc *sc = cookie; 328 uint32_t *gpio; 329 int i; 330 331 sc->sc_ridx = sc->sc_widx = 0; 332 333 gpio = imxspi_find_cs_gpio(sc, sc->sc_cs); 334 if (gpio) { 335 gpio_controller_set_pin(gpio, 0); 336 delay(1); 337 } 338 339 /* drain input buffer */ 340 while (HREAD4(sc, SPI_STATREG) & SPI_STATREG_RR) 341 HREAD4(sc, SPI_RXDATA); 342 343 while (sc->sc_ridx < len || sc->sc_widx < len) { 344 for (i = sc->sc_widx; i < len; i++) { 345 if (imxspi_wait_state(sc, SPI_STATREG_TF, 0)) 346 goto err; 347 if (out) 348 HWRITE4(sc, SPI_TXDATA, out[i]); 349 else 350 HWRITE4(sc, SPI_TXDATA, 0xff); 351 sc->sc_widx++; 352 if (HREAD4(sc, SPI_STATREG) & SPI_STATREG_TF) 353 break; 354 } 355 356 HSET4(sc, SPI_CONREG, SPI_CONREG_XCH); 357 if (imxspi_wait_state(sc, SPI_STATREG_TC, SPI_STATREG_TC)) 358 goto err; 359 360 for (i = sc->sc_ridx; i < sc->sc_widx; i++) { 361 if (imxspi_wait_state(sc, SPI_STATREG_RR, SPI_STATREG_RR)) 362 goto err; 363 if (in) 364 in[i] = HREAD4(sc, SPI_RXDATA); 365 else 366 HREAD4(sc, SPI_RXDATA); 367 sc->sc_ridx++; 368 } 369 370 HWRITE4(sc, SPI_STATREG, SPI_STATREG_TC); 371 } 372 373 gpio = imxspi_find_cs_gpio(sc, sc->sc_cs); 374 if (gpio) { 375 gpio_controller_set_pin(gpio, 1); 376 delay(1); 377 } 378 379 return 0; 380 err: 381 HWRITE4(sc, SPI_CONREG, 0); 382 HWRITE4(sc, SPI_STATREG, SPI_STATREG_TC); 383 return ETIMEDOUT; 384 } 385 386 int 387 imxspi_acquire_bus(void *cookie, int flags) 388 { 389 struct imxspi_softc *sc = cookie; 390 391 rw_enter(&sc->sc_buslock, RW_WRITE); 392 return 0; 393 } 394 395 void 396 imxspi_release_bus(void *cookie, int flags) 397 { 398 struct imxspi_softc *sc = cookie; 399 400 rw_exit(&sc->sc_buslock); 401 } 402 403 void 404 imxspi_scan(struct imxspi_softc *sc) 405 { 406 struct spi_attach_args sa; 407 uint32_t reg[1]; 408 char name[32]; 409 int node; 410 411 for (node = OF_child(sc->sc_node); node; node = OF_peer(node)) { 412 memset(name, 0, sizeof(name)); 413 memset(reg, 0, sizeof(reg)); 414 415 if (OF_getprop(node, "compatible", name, sizeof(name)) == -1) 416 continue; 417 if (name[0] == '\0') 418 continue; 419 420 if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) 421 continue; 422 423 memset(&sa, 0, sizeof(sa)); 424 sa.sa_tag = &sc->sc_tag; 425 sa.sa_name = name; 426 sa.sa_cookie = &node; 427 428 config_found(&sc->sc_dev, &sa, NULL); 429 } 430 } 431