arspi.c revision 1.10
1/* $NetBSD: arspi.c,v 1.10 2012/10/27 17:18:02 chs Exp $ */ 2 3/*- 4 * Copyright (c) 2006 Urbana-Champaign Independent Media Center. 5 * Copyright (c) 2006 Garrett D'Amore. 6 * All rights reserved. 7 * 8 * Portions of this code were written by Garrett D'Amore for the 9 * Champaign-Urbana Community Wireless Network Project. 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer in the documentation and/or other materials provided 19 * with the distribution. 20 * 3. All advertising materials mentioning features or use of this 21 * software must display the following acknowledgements: 22 * This product includes software developed by the Urbana-Champaign 23 * Independent Media Center. 24 * This product includes software developed by Garrett D'Amore. 25 * 4. Urbana-Champaign Independent Media Center's name and Garrett 26 * D'Amore's name may not be used to endorse or promote products 27 * derived from this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT 30 * MEDIA CENTER AND GARRETT D'AMORE ``AS IS'' AND ANY EXPRESS OR 31 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT 34 * MEDIA CENTER OR GARRETT D'AMORE BE LIABLE FOR ANY DIRECT, INDIRECT, 35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 */ 43 44#include <sys/cdefs.h> 45__KERNEL_RCSID(0, "$NetBSD: arspi.c,v 1.10 2012/10/27 17:18:02 chs Exp $"); 46 47#include "locators.h" 48 49#include <sys/param.h> 50#include <sys/bus.h> 51#include <sys/cpu.h> 52#include <sys/device.h> 53#include <sys/errno.h> 54#include <sys/kernel.h> 55#include <sys/malloc.h> 56#include <sys/proc.h> 57#include <sys/systm.h> 58 59#include <mips/atheros/include/ar5315reg.h> 60#include <mips/atheros/include/arbusvar.h> 61 62#include <mips/atheros/dev/arspireg.h> 63 64#include <dev/spi/spiflash.h> 65#include <dev/spi/spivar.h> 66 67/* 68 * This device is intended only to operate with specific SPI flash 69 * parts, and is not a general purpose SPI host. (Or at least if it 70 * is, the Linux and eCos sources do not show how to use it as such.) 71 * And lack of documentation on the Atheros SoCs is less than helpful. 72 * 73 * So for now we just "emulate" enough of the host bus framework to 74 * make the SPI flash drivers happy. 75 */ 76 77struct arspi_job { 78 uint8_t job_opcode; 79 struct spi_chunk *job_chunk; 80 uint32_t job_flags; 81 uint32_t job_addr; 82 uint32_t job_data; 83 int job_rxcnt; 84 int job_txcnt; 85 int job_addrcnt; 86 int job_rresid; 87 int job_wresid; 88}; 89 90#define JOB_READ 0x1 91#define JOB_WRITE 0x2 92#define JOB_LAST 0x4 93#define JOB_WAIT 0x8 /* job must wait for WIP bits */ 94#define JOB_WREN 0x10 /* WREN needed */ 95 96struct arspi_softc { 97 struct spi_controller sc_spi; 98 void *sc_ih; 99 bool sc_interrupts; 100 101 struct spi_transfer *sc_transfer; 102 struct spi_chunk *sc_wchunk; /* for partial writes */ 103 struct spi_transq sc_transq; 104 bus_space_tag_t sc_st; 105 bus_space_handle_t sc_sh; 106 bus_size_t sc_size; 107}; 108 109#define STATIC 110 111STATIC int arspi_match(device_t, cfdata_t, void *); 112STATIC void arspi_attach(device_t, device_t, void *); 113STATIC void arspi_interrupts(device_t); 114STATIC int arspi_intr(void *); 115/* SPI service routines */ 116STATIC int arspi_configure(void *, int, int, int); 117STATIC int arspi_transfer(void *, struct spi_transfer *); 118/* internal support */ 119STATIC void arspi_poll(struct arspi_softc *); 120STATIC void arspi_done(struct arspi_softc *, int); 121STATIC void arspi_sched(struct arspi_softc *); 122STATIC int arspi_get_byte(struct spi_chunk **, uint8_t *); 123STATIC int arspi_put_byte(struct spi_chunk **, uint8_t); 124STATIC int arspi_make_job(struct spi_transfer *); 125STATIC void arspi_update_job(struct spi_transfer *); 126STATIC void arspi_finish_job(struct spi_transfer *); 127 128 129CFATTACH_DECL_NEW(arspi, sizeof(struct arspi_softc), 130 arspi_match, arspi_attach, NULL, NULL); 131 132#define GETREG(sc, o) bus_space_read_4(sc->sc_st, sc->sc_sh, o) 133#define PUTREG(sc, o, v) bus_space_write_4(sc->sc_st, sc->sc_sh, o, v) 134 135int 136arspi_match(device_t parent, cfdata_t cf, void *aux) 137{ 138 struct arbus_attach_args *aa = aux; 139 140 if (strcmp(aa->aa_name, cf->cf_name) != 0) 141 return 0; 142 return 1; 143} 144 145void 146arspi_attach(device_t parent, device_t self, void *aux) 147{ 148 struct arspi_softc *sc = device_private(self); 149 struct spibus_attach_args sba; 150 struct arbus_attach_args *aa = aux; 151 152 /* 153 * Map registers. 154 */ 155 sc->sc_st = aa->aa_bst; 156 sc->sc_size = aa->aa_size; 157 if (bus_space_map(sc->sc_st, aa->aa_addr, sc->sc_size, 0, 158 &sc->sc_sh) != 0) { 159 printf(": unable to map registers!\n"); 160 return; 161 } 162 163 aprint_normal(": Atheros SPI controller\n"); 164 165 /* 166 * Initialize SPI controller. 167 */ 168 sc->sc_spi.sct_cookie = sc; 169 sc->sc_spi.sct_configure = arspi_configure; 170 sc->sc_spi.sct_transfer = arspi_transfer; 171 sc->sc_spi.sct_nslaves = 1; 172 173 174 /* 175 * Initialize the queue. 176 */ 177 spi_transq_init(&sc->sc_transq); 178 179 /* 180 * Enable device interrupts. 181 */ 182 sc->sc_ih = arbus_intr_establish(aa->aa_cirq, aa->aa_mirq, 183 arspi_intr, sc); 184 if (sc->sc_ih == NULL) { 185 aprint_error("%s: couldn't establish interrupt\n", 186 device_xname(self)); 187 /* just leave it in polled mode */ 188 } else 189 config_interrupts(self, arspi_interrupts); 190 191 /* 192 * Initialize and attach bus attach. 193 */ 194 sba.sba_controller = &sc->sc_spi; 195 (void) config_found_ia(self, "spibus", &sba, spibus_print); 196} 197 198void 199arspi_interrupts(device_t self) 200{ 201 /* 202 * we never leave polling mode, because, apparently, we 203 * are missing some data about how to drive the SPI in interrupt 204 * mode. 205 */ 206#if 0 207 struct arspi_softc *sc = device_private(self); 208 int s; 209 210 s = splbio(); 211 sc->sc_interrupts = true; 212 splx(s); 213#endif 214} 215 216int 217arspi_intr(void *arg) 218{ 219 struct arspi_softc *sc = arg; 220 221 while (GETREG(sc, ARSPI_REG_CTL) & ARSPI_CTL_BUSY); 222 223 arspi_done(sc, 0); 224 225 return 1; 226} 227 228void 229arspi_poll(struct arspi_softc *sc) 230{ 231 232 while (sc->sc_transfer) { 233 arspi_intr(sc); 234 } 235} 236 237int 238arspi_configure(void *cookie, int slave, int mode, int speed) 239{ 240 241 /* 242 * We don't support the full SPI protocol, and hopefully the 243 * firmware has programmed a reasonable mode already. So 244 * just a couple of quick sanity checks, then bail. 245 */ 246 if ((mode != 0) || (slave != 0)) 247 return EINVAL; 248 249 return 0; 250} 251 252int 253arspi_transfer(void *cookie, struct spi_transfer *st) 254{ 255 struct arspi_softc *sc = cookie; 256 int rv; 257 int s; 258 259 st->st_busprivate = NULL; 260 if ((rv = arspi_make_job(st)) != 0) { 261 if (st->st_busprivate) { 262 free(st->st_busprivate, M_DEVBUF); 263 st->st_busprivate = NULL; 264 } 265 spi_done(st, rv); 266 return rv; 267 } 268 269 s = splbio(); 270 spi_transq_enqueue(&sc->sc_transq, st); 271 if (sc->sc_transfer == NULL) { 272 arspi_sched(sc); 273 if (!sc->sc_interrupts) 274 arspi_poll(sc); 275 } 276 splx(s); 277 return 0; 278} 279 280void 281arspi_sched(struct arspi_softc *sc) 282{ 283 struct spi_transfer *st; 284 struct arspi_job *job; 285 uint32_t ctl, cnt; 286 287 for (;;) { 288 if ((st = sc->sc_transfer) == NULL) { 289 if ((st = spi_transq_first(&sc->sc_transq)) == NULL) { 290 /* no work left to do */ 291 break; 292 } 293 spi_transq_dequeue(&sc->sc_transq); 294 sc->sc_transfer = st; 295 } 296 297 arspi_update_job(st); 298 job = st->st_busprivate; 299 300 /* there shouldn't be anything running, but ensure it */ 301 do { 302 ctl = GETREG(sc, ARSPI_REG_CTL); 303 } while (ctl & ARSPI_CTL_BUSY); 304 /* clear all of the tx and rx bits */ 305 ctl &= ~(ARSPI_CTL_TXCNT_MASK | ARSPI_CTL_RXCNT_MASK); 306 307 if (job->job_flags & JOB_WAIT) { 308 PUTREG(sc, ARSPI_REG_OPCODE, SPIFLASH_CMD_RDSR); 309 /* only the opcode for tx */ 310 ctl |= (1 << ARSPI_CTL_TXCNT_SHIFT); 311 /* and one rx byte */ 312 ctl |= (1 << ARSPI_CTL_RXCNT_SHIFT); 313 } else if (job->job_flags & JOB_WREN) { 314 PUTREG(sc, ARSPI_REG_OPCODE, SPIFLASH_CMD_WREN); 315 /* just the opcode */ 316 ctl |= (1 << ARSPI_CTL_TXCNT_SHIFT); 317 /* no rx bytes */ 318 } else { 319 /* set the data */ 320 PUTREG(sc, ARSPI_REG_DATA, job->job_data); 321 322 /* set the opcode and the address */ 323 PUTREG(sc, ARSPI_REG_OPCODE, job->job_opcode | 324 (job->job_addr << 8)); 325 326 /* now set txcnt */ 327 cnt = 1; /* opcode */ 328 cnt += job->job_addrcnt + job->job_txcnt; 329 ctl |= (cnt << ARSPI_CTL_TXCNT_SHIFT); 330 331 /* now set rxcnt */ 332 cnt = job->job_rxcnt; 333 ctl |= (cnt << ARSPI_CTL_RXCNT_SHIFT); 334 } 335 336 /* set the start bit */ 337 ctl |= ARSPI_CTL_START; 338 339 PUTREG(sc, ARSPI_REG_CTL, ctl); 340 break; 341 } 342} 343 344void 345arspi_done(struct arspi_softc *sc, int err) 346{ 347 struct spi_transfer *st; 348 struct arspi_job *job; 349 350 if ((st = sc->sc_transfer) != NULL) { 351 job = st->st_busprivate; 352 353 if (job->job_flags & JOB_WAIT) { 354 if (err == 0) { 355 if ((GETREG(sc, ARSPI_REG_DATA) & 356 SPIFLASH_SR_BUSY) == 0) { 357 /* intermediate wait done */ 358 job->job_flags &= ~JOB_WAIT; 359 goto done; 360 } 361 } 362 } else if (job->job_flags & JOB_WREN) { 363 if (err == 0) { 364 job->job_flags &= ~JOB_WREN; 365 goto done; 366 } 367 } else if (err == 0) { 368 /* 369 * When breaking up write jobs, we have to wait until 370 * the WIP bit is clear, and we have to separately 371 * send WREN for each chunk. These flags facilitate 372 * that. 373 */ 374 if (job->job_flags & JOB_WRITE) 375 job->job_flags |= (JOB_WAIT | JOB_WREN); 376 job->job_data = GETREG(sc, ARSPI_REG_DATA); 377 arspi_finish_job(st); 378 } 379 380 if (err || (job->job_flags & JOB_LAST)) { 381 sc->sc_transfer = NULL; 382 st->st_busprivate = NULL; 383 spi_done(st, err); 384 free(job, M_DEVBUF); 385 } 386 } 387done: 388 arspi_sched(sc); 389} 390 391int 392arspi_get_byte(struct spi_chunk **chunkp, uint8_t *bytep) 393{ 394 struct spi_chunk *chunk; 395 396 chunk = *chunkp; 397 398 /* skip leading empty (or already consumed) chunks */ 399 while (chunk && chunk->chunk_wresid == 0) 400 chunk = chunk->chunk_next; 401 402 if (chunk == NULL) { 403 return ENODATA; 404 } 405 406 /* 407 * chunk must be write only. SPI flash doesn't support 408 * any full duplex operations. 409 */ 410 if ((chunk->chunk_rptr) || !(chunk->chunk_wptr)) { 411 return EINVAL; 412 } 413 414 *bytep = *chunk->chunk_wptr; 415 chunk->chunk_wptr++; 416 chunk->chunk_wresid--; 417 chunk->chunk_rresid--; 418 /* clearing wptr and rptr makes sanity checks later easier */ 419 if (chunk->chunk_wresid == 0) 420 chunk->chunk_wptr = NULL; 421 if (chunk->chunk_rresid == 0) 422 chunk->chunk_rptr = NULL; 423 while (chunk && chunk->chunk_wresid == 0) 424 chunk = chunk->chunk_next; 425 426 *chunkp = chunk; 427 return 0; 428} 429 430int 431arspi_put_byte(struct spi_chunk **chunkp, uint8_t byte) 432{ 433 struct spi_chunk *chunk; 434 435 chunk = *chunkp; 436 437 /* skip leading empty (or already consumed) chunks */ 438 while (chunk && chunk->chunk_rresid == 0) 439 chunk = chunk->chunk_next; 440 441 if (chunk == NULL) { 442 return EOVERFLOW; 443 } 444 445 /* 446 * chunk must be read only. SPI flash doesn't support 447 * any full duplex operations. 448 */ 449 if ((chunk->chunk_wptr) || !(chunk->chunk_rptr)) { 450 return EINVAL; 451 } 452 453 *chunk->chunk_rptr = byte; 454 chunk->chunk_rptr++; 455 chunk->chunk_wresid--; /* technically this was done at send time */ 456 chunk->chunk_rresid--; 457 while (chunk && chunk->chunk_rresid == 0) 458 chunk = chunk->chunk_next; 459 460 *chunkp = chunk; 461 return 0; 462} 463 464int 465arspi_make_job(struct spi_transfer *st) 466{ 467 struct arspi_job *job; 468 struct spi_chunk *chunk; 469 uint8_t byte; 470 int i, rv; 471 472 job = malloc(sizeof (struct arspi_job), M_DEVBUF, M_ZERO); 473 if (job == NULL) { 474 return ENOMEM; 475 } 476 477 st->st_busprivate = job; 478 479 /* skip any leading empty chunks (should not be any!) */ 480 chunk = st->st_chunks; 481 482 /* get transfer opcode */ 483 if ((rv = arspi_get_byte(&chunk, &byte)) != 0) 484 return rv; 485 486 job->job_opcode = byte; 487 switch (job->job_opcode) { 488 case SPIFLASH_CMD_WREN: 489 case SPIFLASH_CMD_WRDI: 490 case SPIFLASH_CMD_CHIPERASE: 491 break; 492 case SPIFLASH_CMD_RDJI: 493 job->job_rxcnt = 3; 494 break; 495 case SPIFLASH_CMD_RDSR: 496 job->job_rxcnt = 1; 497 break; 498 case SPIFLASH_CMD_WRSR: 499 /* 500 * is this in data, or in address? stick it in data 501 * for now. 502 */ 503 job->job_txcnt = 1; 504 break; 505 case SPIFLASH_CMD_RDID: 506 job->job_addrcnt = 3; /* 3 dummy bytes */ 507 job->job_rxcnt = 1; 508 break; 509 case SPIFLASH_CMD_ERASE: 510 job->job_addrcnt = 3; 511 break; 512 case SPIFLASH_CMD_READ: 513 job->job_addrcnt = 3; 514 job->job_flags |= JOB_READ; 515 break; 516 case SPIFLASH_CMD_PROGRAM: 517 job->job_addrcnt = 3; 518 job->job_flags |= JOB_WRITE; 519 break; 520 case SPIFLASH_CMD_READFAST: 521 /* 522 * This is a pain in the arse to support, so we will 523 * rewrite as an ordinary read. But later, after we 524 * obtain the address. 525 */ 526 job->job_addrcnt = 3; /* 3 address */ 527 job->job_flags |= JOB_READ; 528 break; 529 default: 530 return EINVAL; 531 } 532 533 for (i = 0; i < job->job_addrcnt; i++) { 534 if ((rv = arspi_get_byte(&chunk, &byte)) != 0) 535 return rv; 536 job->job_addr <<= 8; 537 job->job_addr |= byte; 538 } 539 540 541 if (job->job_opcode == SPIFLASH_CMD_READFAST) { 542 /* eat the dummy timing byte */ 543 if ((rv = arspi_get_byte(&chunk, &byte)) != 0) 544 return rv; 545 /* rewrite this as a read */ 546 job->job_opcode = SPIFLASH_CMD_READ; 547 } 548 549 job->job_chunk = chunk; 550 551 /* 552 * Now quickly check a few other things. Namely, we are not 553 * allowed to have both READ and WRITE. 554 */ 555 for (chunk = job->job_chunk; chunk; chunk = chunk->chunk_next) { 556 if (chunk->chunk_wptr) { 557 job->job_wresid += chunk->chunk_wresid; 558 } 559 if (chunk->chunk_rptr) { 560 job->job_rresid += chunk->chunk_rresid; 561 } 562 } 563 564 if (job->job_rresid && job->job_wresid) { 565 return EINVAL; 566 } 567 568 return 0; 569} 570 571/* 572 * NB: The Atheros SPI controller runs in little endian mode. So all 573 * data accesses must be swapped appropriately. 574 * 575 * The controller auto-swaps read accesses done through the mapped memory 576 * region, but when using SPI directly, we have to do the right thing to 577 * swap to or from little endian. 578 */ 579 580void 581arspi_update_job(struct spi_transfer *st) 582{ 583 struct arspi_job *job = st->st_busprivate; 584 uint8_t byte; 585 int i; 586 587 if (job->job_flags & (JOB_WAIT|JOB_WREN)) 588 return; 589 590 job->job_rxcnt = 0; 591 job->job_txcnt = 0; 592 job->job_data = 0; 593 594 job->job_txcnt = min(job->job_wresid, 4); 595 job->job_rxcnt = min(job->job_rresid, 4); 596 597 job->job_wresid -= job->job_txcnt; 598 job->job_rresid -= job->job_rxcnt; 599 600 for (i = 0; i < job->job_txcnt; i++) { 601 arspi_get_byte(&job->job_chunk, &byte); 602 job->job_data |= (byte << (i * 8)); 603 } 604 605 if ((!job->job_wresid) && (!job->job_rresid)) { 606 job->job_flags |= JOB_LAST; 607 } 608} 609 610void 611arspi_finish_job(struct spi_transfer *st) 612{ 613 struct arspi_job *job = st->st_busprivate; 614 uint8_t byte; 615 int i; 616 617 job->job_addr += job->job_rxcnt; 618 job->job_addr += job->job_txcnt; 619 for (i = 0; i < job->job_rxcnt; i++) { 620 byte = job->job_data & 0xff; 621 job->job_data >>= 8; 622 arspi_put_byte(&job->job_chunk, byte); 623 } 624} 625 626