| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: hdaudio.c,v 1.4.10.2 2017/11/24 08:35:34 martin Exp $ */ | | 1 | /* $NetBSD: hdaudio.c,v 1.4.10.3 2017/11/27 10:21:26 martin Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2009 Precedence Technologies Ltd <support@precedence.co.uk> | | 4 | * Copyright (c) 2009 Precedence Technologies Ltd <support@precedence.co.uk> |
5 | * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca> | | 5 | * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca> |
6 | * All rights reserved. | | 6 | * All rights reserved. |
7 | * | | 7 | * |
8 | * This code is derived from software contributed to The NetBSD Foundation | | 8 | * This code is derived from software contributed to The NetBSD Foundation |
9 | * by Precedence Technologies Ltd | | 9 | * by Precedence Technologies Ltd |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
| @@ -20,27 +20,27 @@ | | | @@ -20,27 +20,27 @@ |
20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | | 23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
24 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | | 24 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | | 25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
26 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | | 26 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
27 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 27 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. | | 29 | * SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: hdaudio.c,v 1.4.10.2 2017/11/24 08:35:34 martin Exp $"); | | 33 | __KERNEL_RCSID(0, "$NetBSD: hdaudio.c,v 1.4.10.3 2017/11/27 10:21:26 martin Exp $"); |
34 | | | 34 | |
35 | #include <sys/types.h> | | 35 | #include <sys/types.h> |
36 | #include <sys/param.h> | | 36 | #include <sys/param.h> |
37 | #include <sys/systm.h> | | 37 | #include <sys/systm.h> |
38 | #include <sys/device.h> | | 38 | #include <sys/device.h> |
39 | #include <sys/conf.h> | | 39 | #include <sys/conf.h> |
40 | #include <sys/bus.h> | | 40 | #include <sys/bus.h> |
41 | #include <sys/kmem.h> | | 41 | #include <sys/kmem.h> |
42 | #include <sys/module.h> | | 42 | #include <sys/module.h> |
43 | | | 43 | |
44 | #include "hdaudiovar.h" | | 44 | #include "hdaudiovar.h" |
45 | #include "hdaudioreg.h" | | 45 | #include "hdaudioreg.h" |
46 | #include "hdaudioio.h" | | 46 | #include "hdaudioio.h" |
| @@ -337,26 +337,29 @@ hdaudio_command(struct hdaudio_codec *co | | | @@ -337,26 +337,29 @@ hdaudio_command(struct hdaudio_codec *co |
337 | | | 337 | |
338 | uint32_t | | 338 | uint32_t |
339 | hdaudio_command_unlocked(struct hdaudio_codec *co, int nid, uint32_t control, | | 339 | hdaudio_command_unlocked(struct hdaudio_codec *co, int nid, uint32_t control, |
340 | uint32_t param) | | 340 | uint32_t param) |
341 | { | | 341 | { |
342 | struct hdaudio_softc *sc = co->co_host; | | 342 | struct hdaudio_softc *sc = co->co_host; |
343 | uint32_t result; | | 343 | uint32_t result; |
344 | | | 344 | |
345 | hda_trace(sc, "cmd : request %08X %08X (%02X)\n", | | 345 | hda_trace(sc, "cmd : request %08X %08X (%02X)\n", |
346 | control, param, nid); | | 346 | control, param, nid); |
347 | hdaudio_corb_enqueue(sc, co->co_addr, nid, control, param); | | 347 | hdaudio_corb_enqueue(sc, co->co_addr, nid, control, param); |
348 | result = hdaudio_rirb_dequeue(sc, false); | | 348 | result = hdaudio_rirb_dequeue(sc, false); |
349 | | | 349 | |
| | | 350 | /* Clear response interrupt status */ |
| | | 351 | hda_write1(sc, HDAUDIO_MMIO_RIRBSTS, hda_read1(sc, HDAUDIO_MMIO_RIRBSTS)); |
| | | 352 | |
350 | return result; | | 353 | return result; |
351 | } | | 354 | } |
352 | | | 355 | |
353 | static int | | 356 | static int |
354 | hdaudio_corb_setsize(struct hdaudio_softc *sc) | | 357 | hdaudio_corb_setsize(struct hdaudio_softc *sc) |
355 | { | | 358 | { |
356 | uint8_t corbsize; | | 359 | uint8_t corbsize; |
357 | bus_size_t bufsize = 0; | | 360 | bus_size_t bufsize = 0; |
358 | | | 361 | |
359 | /* | | 362 | /* |
360 | * The size of the CORB is programmable to 2, 16, or 256 entries | | 363 | * The size of the CORB is programmable to 2, 16, or 256 entries |
361 | * by using the CORBSIZE register. Choose a size based on the | | 364 | * by using the CORBSIZE register. Choose a size based on the |
362 | * controller capabilities, preferring a larger size when possible. | | 365 | * controller capabilities, preferring a larger size when possible. |
| @@ -418,54 +421,54 @@ hdaudio_corb_config(struct hdaudio_softc | | | @@ -418,54 +421,54 @@ hdaudio_corb_config(struct hdaudio_softc |
418 | return 0; | | 421 | return 0; |
419 | } | | 422 | } |
420 | | | 423 | |
421 | static int | | 424 | static int |
422 | hdaudio_corb_stop(struct hdaudio_softc *sc) | | 425 | hdaudio_corb_stop(struct hdaudio_softc *sc) |
423 | { | | 426 | { |
424 | uint8_t corbctl; | | 427 | uint8_t corbctl; |
425 | int retry = HDAUDIO_CORB_TIMEOUT; | | 428 | int retry = HDAUDIO_CORB_TIMEOUT; |
426 | | | 429 | |
427 | /* Stop the CORB if necessary */ | | 430 | /* Stop the CORB if necessary */ |
428 | corbctl = hda_read1(sc, HDAUDIO_MMIO_CORBCTL); | | 431 | corbctl = hda_read1(sc, HDAUDIO_MMIO_CORBCTL); |
429 | if (corbctl & HDAUDIO_CORBCTL_RUN) { | | 432 | if (corbctl & HDAUDIO_CORBCTL_RUN) { |
430 | corbctl &= ~HDAUDIO_CORBCTL_RUN; | | 433 | corbctl &= ~HDAUDIO_CORBCTL_RUN; |
431 | hda_write4(sc, HDAUDIO_MMIO_CORBCTL, corbctl); | | 434 | hda_write1(sc, HDAUDIO_MMIO_CORBCTL, corbctl); |
432 | do { | | 435 | do { |
433 | hda_delay(10); | | 436 | hda_delay(10); |
434 | corbctl = hda_read4(sc, HDAUDIO_MMIO_CORBCTL); | | 437 | corbctl = hda_read1(sc, HDAUDIO_MMIO_CORBCTL); |
435 | } while (--retry > 0 && (corbctl & HDAUDIO_CORBCTL_RUN) != 0); | | 438 | } while (--retry > 0 && (corbctl & HDAUDIO_CORBCTL_RUN) != 0); |
436 | if (retry == 0) { | | 439 | if (retry == 0) { |
437 | hda_error(sc, "timeout stopping CORB\n"); | | 440 | hda_error(sc, "timeout stopping CORB\n"); |
438 | return ETIME; | | 441 | return ETIME; |
439 | } | | 442 | } |
440 | } | | 443 | } |
441 | | | 444 | |
442 | return 0; | | 445 | return 0; |
443 | } | | 446 | } |
444 | | | 447 | |
445 | static int | | 448 | static int |
446 | hdaudio_corb_start(struct hdaudio_softc *sc) | | 449 | hdaudio_corb_start(struct hdaudio_softc *sc) |
447 | { | | 450 | { |
448 | uint8_t corbctl; | | 451 | uint8_t corbctl; |
449 | int retry = HDAUDIO_CORB_TIMEOUT; | | 452 | int retry = HDAUDIO_CORB_TIMEOUT; |
450 | | | 453 | |
451 | /* Start the CORB if necessary */ | | 454 | /* Start the CORB if necessary */ |
452 | corbctl = hda_read1(sc, HDAUDIO_MMIO_CORBCTL); | | 455 | corbctl = hda_read1(sc, HDAUDIO_MMIO_CORBCTL); |
453 | if ((corbctl & HDAUDIO_CORBCTL_RUN) == 0) { | | 456 | if ((corbctl & HDAUDIO_CORBCTL_RUN) == 0) { |
454 | corbctl |= HDAUDIO_CORBCTL_RUN; | | 457 | corbctl |= HDAUDIO_CORBCTL_RUN; |
455 | hda_write4(sc, HDAUDIO_MMIO_CORBCTL, corbctl); | | 458 | hda_write1(sc, HDAUDIO_MMIO_CORBCTL, corbctl); |
456 | do { | | 459 | do { |
457 | hda_delay(10); | | 460 | hda_delay(10); |
458 | corbctl = hda_read4(sc, HDAUDIO_MMIO_CORBCTL); | | 461 | corbctl = hda_read1(sc, HDAUDIO_MMIO_CORBCTL); |
459 | } while (--retry > 0 && (corbctl & HDAUDIO_CORBCTL_RUN) == 0); | | 462 | } while (--retry > 0 && (corbctl & HDAUDIO_CORBCTL_RUN) == 0); |
460 | if (retry == 0) { | | 463 | if (retry == 0) { |
461 | hda_error(sc, "timeout starting CORB\n"); | | 464 | hda_error(sc, "timeout starting CORB\n"); |
462 | return ETIME; | | 465 | return ETIME; |
463 | } | | 466 | } |
464 | } | | 467 | } |
465 | | | 468 | |
466 | return 0; | | 469 | return 0; |
467 | } | | 470 | } |
468 | | | 471 | |
469 | static int | | 472 | static int |
470 | hdaudio_rirb_stop(struct hdaudio_softc *sc) | | 473 | hdaudio_rirb_stop(struct hdaudio_softc *sc) |
471 | { | | 474 | { |
| @@ -487,40 +490,41 @@ hdaudio_rirb_stop(struct hdaudio_softc * | | | @@ -487,40 +490,41 @@ hdaudio_rirb_stop(struct hdaudio_softc * |
487 | return ETIME; | | 490 | return ETIME; |
488 | } | | 491 | } |
489 | } | | 492 | } |
490 | | | 493 | |
491 | return 0; | | 494 | return 0; |
492 | } | | 495 | } |
493 | | | 496 | |
494 | static int | | 497 | static int |
495 | hdaudio_rirb_start(struct hdaudio_softc *sc) | | 498 | hdaudio_rirb_start(struct hdaudio_softc *sc) |
496 | { | | 499 | { |
497 | uint8_t rirbctl; | | 500 | uint8_t rirbctl; |
498 | int retry = HDAUDIO_RIRB_TIMEOUT; | | 501 | int retry = HDAUDIO_RIRB_TIMEOUT; |
499 | | | 502 | |
500 | /* Start the RIRB if necessary */ | | 503 | /* Set the RIRB interrupt count */ |
| | | 504 | hda_write2(sc, HDAUDIO_MMIO_RINTCNT, 1); |
| | | 505 | |
| | | 506 | /* Start the RIRB */ |
501 | rirbctl = hda_read1(sc, HDAUDIO_MMIO_RIRBCTL); | | 507 | rirbctl = hda_read1(sc, HDAUDIO_MMIO_RIRBCTL); |
502 | if ((rirbctl & (HDAUDIO_RIRBCTL_RUN|HDAUDIO_RIRBCTL_INT_EN)) == 0) { | | 508 | rirbctl |= HDAUDIO_RIRBCTL_RUN; |
503 | rirbctl |= HDAUDIO_RIRBCTL_RUN; | | 509 | rirbctl |= HDAUDIO_RIRBCTL_INT_EN; |
504 | rirbctl |= HDAUDIO_RIRBCTL_INT_EN; | | 510 | hda_write1(sc, HDAUDIO_MMIO_RIRBCTL, rirbctl); |
505 | hda_write1(sc, HDAUDIO_MMIO_RIRBCTL, rirbctl); | | 511 | do { |
506 | do { | | 512 | hda_delay(10); |
507 | hda_delay(10); | | 513 | rirbctl = hda_read1(sc, HDAUDIO_MMIO_RIRBCTL); |
508 | rirbctl = hda_read1(sc, HDAUDIO_MMIO_RIRBCTL); | | 514 | } while (--retry > 0 && (rirbctl & HDAUDIO_RIRBCTL_RUN) == 0); |
509 | } while (--retry > 0 && (rirbctl & HDAUDIO_RIRBCTL_RUN) == 0); | | 515 | if (retry == 0) { |
510 | if (retry == 0) { | | 516 | hda_error(sc, "timeout starting RIRB\n"); |
511 | hda_error(sc, "timeout starting RIRB\n"); | | 517 | return ETIME; |
512 | return ETIME; | | | |
513 | } | | | |
514 | } | | 518 | } |
515 | | | 519 | |
516 | return 0; | | 520 | return 0; |
517 | } | | 521 | } |
518 | | | 522 | |
519 | static int | | 523 | static int |
520 | hdaudio_rirb_setsize(struct hdaudio_softc *sc) | | 524 | hdaudio_rirb_setsize(struct hdaudio_softc *sc) |
521 | { | | 525 | { |
522 | uint8_t rirbsize; | | 526 | uint8_t rirbsize; |
523 | bus_size_t bufsize = 0; | | 527 | bus_size_t bufsize = 0; |
524 | | | 528 | |
525 | /* | | 529 | /* |
526 | * The size of the RIRB is programmable to 2, 16, or 256 entries | | 530 | * The size of the RIRB is programmable to 2, 16, or 256 entries |
| @@ -548,47 +552,36 @@ hdaudio_rirb_setsize(struct hdaudio_soft | | | @@ -548,47 +552,36 @@ hdaudio_rirb_setsize(struct hdaudio_soft |
548 | (int)bufsize, rirbsize >> 4); | | 552 | (int)bufsize, rirbsize >> 4); |
549 | #endif | | 553 | #endif |
550 | | | 554 | |
551 | sc->sc_rirb.dma_size = bufsize; | | 555 | sc->sc_rirb.dma_size = bufsize; |
552 | sc->sc_rirb.dma_sizereg = rirbsize; | | 556 | sc->sc_rirb.dma_sizereg = rirbsize; |
553 | | | 557 | |
554 | return 0; | | 558 | return 0; |
555 | } | | 559 | } |
556 | | | 560 | |
557 | static int | | 561 | static int |
558 | hdaudio_rirb_config(struct hdaudio_softc *sc) | | 562 | hdaudio_rirb_config(struct hdaudio_softc *sc) |
559 | { | | 563 | { |
560 | uint32_t rirbubase, rirblbase; | | 564 | uint32_t rirbubase, rirblbase; |
561 | uint32_t rirbwp; | | | |
562 | int retry = HDAUDIO_RIRB_TIMEOUT; | | | |
563 | | | 565 | |
564 | /* Program command buffer base address and size */ | | 566 | /* Program command buffer base address and size */ |
565 | rirblbase = (uint32_t)DMA_DMAADDR(&sc->sc_rirb); | | 567 | rirblbase = (uint32_t)DMA_DMAADDR(&sc->sc_rirb); |
566 | rirbubase = (uint32_t)(((uint64_t)DMA_DMAADDR(&sc->sc_rirb)) >> 32); | | 568 | rirbubase = (uint32_t)(((uint64_t)DMA_DMAADDR(&sc->sc_rirb)) >> 32); |
567 | hda_write4(sc, HDAUDIO_MMIO_RIRBLBASE, rirblbase); | | 569 | hda_write4(sc, HDAUDIO_MMIO_RIRBLBASE, rirblbase); |
568 | hda_write4(sc, HDAUDIO_MMIO_RIRBUBASE, rirbubase); | | 570 | hda_write4(sc, HDAUDIO_MMIO_RIRBUBASE, rirbubase); |
569 | hda_write1(sc, HDAUDIO_MMIO_RIRBSIZE, sc->sc_rirb.dma_sizereg); | | 571 | hda_write1(sc, HDAUDIO_MMIO_RIRBSIZE, sc->sc_rirb.dma_sizereg); |
570 | | | 572 | |
571 | /* Clear the write pointer */ | | 573 | /* Clear the write pointer */ |
572 | hda_write2(sc, HDAUDIO_MMIO_RIRBWP, HDAUDIO_RIRBWP_WP_RESET); | | 574 | hda_write2(sc, HDAUDIO_MMIO_RIRBWP, HDAUDIO_RIRBWP_WP_RESET); |
573 | hda_write2(sc, HDAUDIO_MMIO_RIRBWP, 0); | | | |
574 | do { | | | |
575 | hda_delay(10); | | | |
576 | rirbwp = hda_read2(sc, HDAUDIO_MMIO_RIRBWP); | | | |
577 | } while (--retry > 0 && (rirbwp & HDAUDIO_RIRBWP_WP_RESET) != 0); | | | |
578 | if (retry == 0) { | | | |
579 | hda_error(sc, "timeout resetting RIRB\n"); | | | |
580 | return ETIME; | | | |
581 | } | | | |
582 | sc->sc_rirbrp = 0; | | 575 | sc->sc_rirbrp = 0; |
583 | | | 576 | |
584 | return 0; | | 577 | return 0; |
585 | } | | 578 | } |
586 | | | 579 | |
587 | static int | | 580 | static int |
588 | hdaudio_reset(struct hdaudio_softc *sc) | | 581 | hdaudio_reset(struct hdaudio_softc *sc) |
589 | { | | 582 | { |
590 | int retry = HDAUDIO_RESET_TIMEOUT; | | 583 | int retry = HDAUDIO_RESET_TIMEOUT; |
591 | uint32_t gctl; | | 584 | uint32_t gctl; |
592 | int err; | | 585 | int err; |
593 | | | 586 | |
594 | if ((err = hdaudio_rirb_stop(sc)) != 0) { | | 587 | if ((err = hdaudio_rirb_stop(sc)) != 0) { |