| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: mesongx_mmc.c,v 1.13 2021/01/27 03:10:18 thorpej Exp $ */ | | 1 | /* $NetBSD: mesongx_mmc.c,v 1.14 2021/01/28 11:45:31 jmcneill Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2019 Jared McNeill <jmcneill@invisible.ca> | | 4 | * Copyright (c) 2019 Jared McNeill <jmcneill@invisible.ca> |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -17,27 +17,27 @@ | | | @@ -17,27 +17,27 @@ |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | | 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | | 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | | 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. | | 26 | * SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | #include <sys/cdefs.h> | | 29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: mesongx_mmc.c,v 1.13 2021/01/27 03:10:18 thorpej Exp $"); | | 30 | __KERNEL_RCSID(0, "$NetBSD: mesongx_mmc.c,v 1.14 2021/01/28 11:45:31 jmcneill Exp $"); |
31 | | | 31 | |
32 | #include <sys/param.h> | | 32 | #include <sys/param.h> |
33 | #include <sys/bus.h> | | 33 | #include <sys/bus.h> |
34 | #include <sys/device.h> | | 34 | #include <sys/device.h> |
35 | #include <sys/intr.h> | | 35 | #include <sys/intr.h> |
36 | #include <sys/systm.h> | | 36 | #include <sys/systm.h> |
37 | #include <sys/kernel.h> | | 37 | #include <sys/kernel.h> |
38 | #include <sys/bitops.h> | | 38 | #include <sys/bitops.h> |
39 | #include <sys/gpio.h> | | 39 | #include <sys/gpio.h> |
40 | | | 40 | |
41 | #include <dev/sdmmc/sdmmcvar.h> | | 41 | #include <dev/sdmmc/sdmmcvar.h> |
42 | #include <dev/sdmmc/sdmmcchip.h> | | 42 | #include <dev/sdmmc/sdmmcchip.h> |
43 | #include <dev/sdmmc/sdmmc_ioreg.h> | | 43 | #include <dev/sdmmc/sdmmc_ioreg.h> |
| @@ -486,43 +486,58 @@ mesongx_mmc_set_clock(struct mesongx_mmc | | | @@ -486,43 +486,58 @@ mesongx_mmc_set_clock(struct mesongx_mmc |
486 | continue; | | 486 | continue; |
487 | const int diff = target_rate - rate; | | 487 | const int diff = target_rate - rate; |
488 | if (diff < best_diff) { | | 488 | if (diff < best_diff) { |
489 | best_diff = diff; | | 489 | best_diff = diff; |
490 | best_sel = sel; | | 490 | best_sel = sel; |
491 | best_div = div; | | 491 | best_div = div; |
492 | } | | 492 | } |
493 | } | | 493 | } |
494 | } | | 494 | } |
495 | | | 495 | |
496 | if (best_diff == INT_MAX) | | 496 | if (best_diff == INT_MAX) |
497 | return ERANGE; | | 497 | return ERANGE; |
498 | | | 498 | |
| | | 499 | val = MMC_READ(sc, SD_EMMC_CFG); |
| | | 500 | val |= CFG_STOP_CLK; |
| | | 501 | MMC_WRITE(sc, SD_EMMC_CFG, val); |
| | | 502 | |
| | | 503 | val = MMC_READ(sc, SD_EMMC_CFG); |
| | | 504 | if (ddr) |
| | | 505 | val |= CFG_DDR; |
| | | 506 | else |
| | | 507 | val &= ~CFG_DDR; |
| | | 508 | MMC_WRITE(sc, SD_EMMC_CFG, val); |
| | | 509 | |
499 | val = MMC_READ(sc, SD_EMMC_CLOCK); | | 510 | val = MMC_READ(sc, SD_EMMC_CLOCK); |
500 | if (sc->sc_hwtype == MESONGX_MMC_V3) | | 511 | if (sc->sc_hwtype == MESONGX_MMC_V3) |
501 | val |= CLOCK_CFG_V3_ALWAYS_ON; | | 512 | val |= CLOCK_CFG_V3_ALWAYS_ON; |
502 | else | | 513 | else |
503 | val |= CLOCK_CFG_V2_ALWAYS_ON; | | 514 | val |= CLOCK_CFG_V2_ALWAYS_ON; |
504 | val &= ~CLOCK_CFG_RX_PHASE; | | 515 | val &= ~CLOCK_CFG_RX_PHASE; |
505 | val |= __SHIFTIN(0, CLOCK_CFG_RX_PHASE); | | 516 | val |= __SHIFTIN(0, CLOCK_CFG_RX_PHASE); |
506 | val &= ~CLOCK_CFG_TX_PHASE; | | 517 | val &= ~CLOCK_CFG_TX_PHASE; |
507 | val |= __SHIFTIN(2, CLOCK_CFG_TX_PHASE); | | 518 | val |= __SHIFTIN(0, CLOCK_CFG_TX_PHASE); |
508 | val &= ~CLOCK_CFG_CO_PHASE; | | 519 | val &= ~CLOCK_CFG_CO_PHASE; |
509 | val |= __SHIFTIN(3, CLOCK_CFG_CO_PHASE); | | 520 | val |= __SHIFTIN(2, CLOCK_CFG_CO_PHASE); |
510 | val &= ~CLOCK_CFG_SRC; | | 521 | val &= ~CLOCK_CFG_SRC; |
511 | val |= __SHIFTIN(best_sel, CLOCK_CFG_SRC); | | 522 | val |= __SHIFTIN(best_sel, CLOCK_CFG_SRC); |
512 | val &= ~CLOCK_CFG_DIV; | | 523 | val &= ~CLOCK_CFG_DIV; |
513 | val |= __SHIFTIN(best_div, CLOCK_CFG_DIV); | | 524 | val |= __SHIFTIN(best_div, CLOCK_CFG_DIV); |
514 | MMC_WRITE(sc, SD_EMMC_CLOCK, val); | | 525 | MMC_WRITE(sc, SD_EMMC_CLOCK, val); |
515 | | | 526 | |
| | | 527 | val = MMC_READ(sc, SD_EMMC_CFG); |
| | | 528 | val &= ~CFG_STOP_CLK; |
| | | 529 | MMC_WRITE(sc, SD_EMMC_CFG, val); |
| | | 530 | |
516 | return 0; | | 531 | return 0; |
517 | } | | 532 | } |
518 | | | 533 | |
519 | static void | | 534 | static void |
520 | mesongx_mmc_attach_i(device_t self) | | 535 | mesongx_mmc_attach_i(device_t self) |
521 | { | | 536 | { |
522 | struct mesongx_mmc_softc * const sc = device_private(self); | | 537 | struct mesongx_mmc_softc * const sc = device_private(self); |
523 | struct sdmmcbus_attach_args saa; | | 538 | struct sdmmcbus_attach_args saa; |
524 | uint32_t width; | | 539 | uint32_t width; |
525 | | | 540 | |
526 | if (sc->sc_pwrseq) | | 541 | if (sc->sc_pwrseq) |
527 | fdtbus_mmc_pwrseq_pre_power_on(sc->sc_pwrseq); | | 542 | fdtbus_mmc_pwrseq_pre_power_on(sc->sc_pwrseq); |
528 | | | 543 | |
| @@ -723,41 +738,28 @@ mesongx_mmc_write_protect(sdmmc_chipset_ | | | @@ -723,41 +738,28 @@ mesongx_mmc_write_protect(sdmmc_chipset_ |
723 | return 0; | | 738 | return 0; |
724 | } | | 739 | } |
725 | | | 740 | |
726 | static int | | 741 | static int |
727 | mesongx_mmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) | | 742 | mesongx_mmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) |
728 | { | | 743 | { |
729 | return 0; | | 744 | return 0; |
730 | } | | 745 | } |
731 | | | 746 | |
732 | static int | | 747 | static int |
733 | mesongx_mmc_bus_clock(sdmmc_chipset_handle_t sch, int freq, bool ddr) | | 748 | mesongx_mmc_bus_clock(sdmmc_chipset_handle_t sch, int freq, bool ddr) |
734 | { | | 749 | { |
735 | struct mesongx_mmc_softc * const sc = sch; | | 750 | struct mesongx_mmc_softc * const sc = sch; |
736 | uint32_t val; | | | |
737 | int error; | | | |
738 | | | | |
739 | error = mesongx_mmc_set_clock(sc, freq, ddr); | | | |
740 | if (error != 0) | | | |
741 | return error; | | | |
742 | | | | |
743 | val = MMC_READ(sc, SD_EMMC_CFG); | | | |
744 | if (ddr) | | | |
745 | val |= CFG_DDR; | | | |
746 | else | | | |
747 | val &= ~CFG_DDR; | | | |
748 | MMC_WRITE(sc, SD_EMMC_CFG, val); | | | |
749 | | | 751 | |
750 | return 0; | | 752 | return mesongx_mmc_set_clock(sc, freq, ddr); |
751 | } | | 753 | } |
752 | | | 754 | |
753 | static int | | 755 | static int |
754 | mesongx_mmc_bus_width(sdmmc_chipset_handle_t sch, int width) | | 756 | mesongx_mmc_bus_width(sdmmc_chipset_handle_t sch, int width) |
755 | { | | 757 | { |
756 | struct mesongx_mmc_softc *sc = sch; | | 758 | struct mesongx_mmc_softc *sc = sch; |
757 | uint32_t val; | | 759 | uint32_t val; |
758 | | | 760 | |
759 | val = MMC_READ(sc, SD_EMMC_CFG); | | 761 | val = MMC_READ(sc, SD_EMMC_CFG); |
760 | val &= ~CFG_BUS_WIDTH; | | 762 | val &= ~CFG_BUS_WIDTH; |
761 | | | 763 | |
762 | switch (width) { | | 764 | switch (width) { |
763 | case 1: | | 765 | case 1: |