Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm/nvidia SDMMC clock input is PLLP (408 MHz). Set...



details:   https://anonhg.NetBSD.org/src/rev/4be26f7af4c5
branches:  trunk
changeset: 337875:4be26f7af4c5
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sat May 02 14:10:03 2015 +0000

description:
SDMMC clock input is PLLP (408 MHz). Set input divisor to 2 to get a
204 MHz input for the SDHC, which is just below the maximum supported
frequency for SDR104.

diffstat:

 sys/arch/arm/nvidia/tegra_car.c    |  87 ++++++++++++++++++++++++++++++++++---
 sys/arch/arm/nvidia/tegra_carreg.h |  47 ++++++++++++++++++-
 sys/arch/arm/nvidia/tegra_sdhc.c   |  34 ++++++-------
 3 files changed, 137 insertions(+), 31 deletions(-)

diffs (275 lines):

diff -r a11f29d79aa0 -r 4be26f7af4c5 sys/arch/arm/nvidia/tegra_car.c
--- a/sys/arch/arm/nvidia/tegra_car.c   Sat May 02 12:57:19 2015 +0000
+++ b/sys/arch/arm/nvidia/tegra_car.c   Sat May 02 14:10:03 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_car.c,v 1.1 2015/04/28 11:15:55 jmcneill Exp $ */
+/* $NetBSD: tegra_car.c,v 1.2 2015/05/02 14:10:03 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -29,7 +29,7 @@
 #include "locators.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tegra_car.c,v 1.1 2015/04/28 11:15:55 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tegra_car.c,v 1.2 2015/05/02 14:10:03 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -81,6 +81,7 @@
        aprint_normal(": CAR\n");
 
        aprint_verbose_dev(self, "PLLX = %u Hz\n", tegra_car_pllx_rate());
+       aprint_verbose_dev(self, "PLLP0 = %u Hz\n", tegra_car_pllp0_rate());
 }
 
 static void
@@ -102,8 +103,9 @@
        return TEGRA_REF_FREQ;
 }
 
-u_int
-tegra_car_pllx_rate(void)
+static u_int
+tegra_car_pll_rate(u_int base_reg, u_int divm_mask, u_int divn_mask,
+    u_int divp_mask)
 {
        bus_space_tag_t bst;
        bus_space_handle_t bsh;
@@ -112,12 +114,79 @@
        tegra_car_get_bs(&bst, &bsh);
 
        rate = tegra_car_osc_rate();    
-       const uint32_t base = bus_space_read_4(bst, bsh, CAR_PLLX_BASE_REG);
-       const u_int divm = __SHIFTOUT(base, CAR_PLLX_BASE_DIVM);
-       const u_int divn = __SHIFTOUT(base, CAR_PLLX_BASE_DIVN);
-       const u_int divp = __SHIFTOUT(base, CAR_PLLX_BASE_DIVP);
+       const uint32_t base = bus_space_read_4(bst, bsh, base_reg);
+       const u_int divm = __SHIFTOUT(base, divm_mask);
+       const u_int divn = __SHIFTOUT(base, divn_mask);
+       const u_int divp = __SHIFTOUT(base, divp_mask);
 
-       rate = tegra_car_osc_rate() * divn;
+       rate = (uint64_t)tegra_car_osc_rate() * divn;
 
        return rate / (divm << divp);
 }
+
+u_int
+tegra_car_pllx_rate(void)
+{
+       return tegra_car_pll_rate(CAR_PLLX_BASE_REG, CAR_PLLX_BASE_DIVM,
+           CAR_PLLX_BASE_DIVN, CAR_PLLX_BASE_DIVP);
+}
+
+u_int
+tegra_car_pllp0_rate(void)
+{
+       return tegra_car_pll_rate(CAR_PLLP_BASE_REG, CAR_PLLP_BASE_DIVM,
+           CAR_PLLP_BASE_DIVN, CAR_PLLP_BASE_DIVP);
+}
+
+u_int
+tegra_car_periph_sdmmc_rate(u_int port)
+{
+       bus_space_tag_t bst;
+       bus_space_handle_t bsh;
+       bus_size_t src_reg;
+
+       tegra_car_get_bs(&bst, &bsh);
+
+       switch (port) {
+       case 0: src_reg = CAR_CLKSRC_SDMMC1_REG; break;
+       case 1: src_reg = CAR_CLKSRC_SDMMC2_REG; break;
+       case 2: src_reg = CAR_CLKSRC_SDMMC3_REG; break;
+       case 3: src_reg = CAR_CLKSRC_SDMMC4_REG; break;
+       default: return 0;
+       }
+
+       const uint32_t src = bus_space_read_4(bst, bsh, src_reg);
+
+       const u_int div = __SHIFTOUT(src, CAR_CLKSRC_SDMMC_DIV) + 1;
+
+       return tegra_car_pllp0_rate() / div;
+}
+
+int
+tegra_car_periph_sdmmc_set_div(u_int port, u_int div)
+{
+       bus_space_tag_t bst;
+       bus_space_handle_t bsh;
+       bus_size_t src_reg;
+       uint32_t src;
+
+       KASSERT(div > 0);
+
+       tegra_car_get_bs(&bst, &bsh);
+
+       switch (port) {
+       case 0: src_reg = CAR_CLKSRC_SDMMC1_REG; break;
+       case 1: src_reg = CAR_CLKSRC_SDMMC2_REG; break;
+       case 2: src_reg = CAR_CLKSRC_SDMMC3_REG; break;
+       case 3: src_reg = CAR_CLKSRC_SDMMC4_REG; break;
+       default: return EINVAL;
+       }
+
+       src = __SHIFTIN(CAR_CLKSRC_SDMMC_SRC_PLLP_OUT0,
+                       CAR_CLKSRC_SDMMC_SRC);
+       src |= __SHIFTIN(div - 1, CAR_CLKSRC_SDMMC_DIV);
+
+       bus_space_write_4(bst, bsh, src_reg, src);
+
+       return 0;
+}
diff -r a11f29d79aa0 -r 4be26f7af4c5 sys/arch/arm/nvidia/tegra_carreg.h
--- a/sys/arch/arm/nvidia/tegra_carreg.h        Sat May 02 12:57:19 2015 +0000
+++ b/sys/arch/arm/nvidia/tegra_carreg.h        Sat May 02 14:10:03 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_carreg.h,v 1.1 2015/04/28 11:15:55 jmcneill Exp $ */
+/* $NetBSD: tegra_carreg.h,v 1.2 2015/05/02 14:10:03 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -29,10 +29,28 @@
 #ifndef _ARM_TEGRA_CARREG_H
 #define _ARM_TEGRA_CARREG_H
 
+#define CAR_CLK_OUT_ENB_L_REG  0x10
+#define CAR_CLK_OUT_ENB_H_REG  0x14
+#define CAR_CLK_OUT_ENB_U_REG  0x18
+
+#define CAR_PLLP_BASE_REG      0xa0
+#define CAR_PLLP_BASE_BYPASS           __BIT(31)
+#define CAR_PLLP_BASE_ENABLE           __BIT(30)
+#define CAR_PLLP_BASE_REF_DIS          __BIT(29)
+#define CAR_PLLP_BASE_OVERRIDE         __BIT(28)
+#define CAR_PLLP_BASE_LOCK             __BIT(27)
+#define CAR_PLLP_BASE_DIVP             __BITS(22,20)
+#define CAR_PLLP_BASE_DIVN             __BITS(17,8)
+#define CAR_PLLP_BASE_DIVM             __BITS(4,0)
+
+#define CAR_PLLP_OUTA_REG      0xa4
+#define CAR_PLLP_OUTB_REG      0xa8
+#define CAR_PLLP_MISC_REG      0xac
+
 #define CAR_PLLX_BASE_REG      0xe0
-#define CAR_PLLX_BASE_ENABLE           __BIT(31)
-#define CAR_PLLX_BASE_LOCK_OVERRIDE    __BIT(30)
-#define CAR_PLLX_BASE_REF              __BIT(29)
+#define CAR_PLLX_BASE_BYPASS           __BIT(31)
+#define CAR_PLLX_BASE_ENABLE           __BIT(30)
+#define CAR_PLLX_BASE_REF_DIS          __BIT(29)
 #define CAR_PLLX_BASE_LOCK             __BIT(27)
 #define CAR_PLLX_BASE_DIVP             __BITS(23,20)
 #define CAR_PLLX_BASE_DIVN             __BITS(15,8)
@@ -40,5 +58,26 @@
 
 #define CAR_PLLX_MISC_REG      0xe8
 
+#define CAR_CLKSRC_SDMMC1_REG          0x150
+#define CAR_CLKSRC_SDMMC2_REG          0x154
+#define CAR_CLKSRC_SDMMC4_REG          0x164
+#define CAR_CLKSRC_SDMMC3_REG          0x1bc
+
+#define CAR_CLKSRC_SDMMC_SRC           __BITS(31,29)
+#define CAR_CLKSRC_SDMMC_SRC_PLLP_OUT0 0
+#define CAR_CLKSRC_SDMMC_SRC_PLLC2_OUT0        1
+#define CAR_CLKSRC_SDMMC_SRC_PLLC_OUT0 2
+#define CAR_CLKSRC_SDMMC_SRC_PLLC3_OUT0        3
+#define CAR_CLKSRC_SDMMC_SRC_PLLM_OUT0 4
+#define CAR_CLKSRC_SDMMC_SRC_PLLE_OUT0 5
+#define CAR_CLKSRC_SDMMC_SRC_CLK_M     6
+#define CAR_CLKSRC_SDMMC_DIV           __BITS(7,0)
+
+#define CAR_RST_DEV_L_SET_REG          0x300
+#define CAR_RST_DEV_L_CLR_REG          0x304
+#define CAR_RST_DEV_H_SET_REG          0x308
+#define CAR_RST_DEV_H_CLR_REG          0x30c
+#define CAR_RST_DEV_U_SET_REG          0x310
+#define CAR_RST_DEV_U_CLR_REG          0x314
 
 #endif /* _ARM_TEGRA_CARREG_H */
diff -r a11f29d79aa0 -r 4be26f7af4c5 sys/arch/arm/nvidia/tegra_sdhc.c
--- a/sys/arch/arm/nvidia/tegra_sdhc.c  Sat May 02 12:57:19 2015 +0000
+++ b/sys/arch/arm/nvidia/tegra_sdhc.c  Sat May 02 14:10:03 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_sdhc.c,v 1.1 2015/03/29 10:41:59 jmcneill Exp $ */
+/* $NetBSD: tegra_sdhc.c,v 1.2 2015/05/02 14:10:03 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -29,7 +29,7 @@
 #include "locators.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tegra_sdhc.c,v 1.1 2015/03/29 10:41:59 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tegra_sdhc.c,v 1.2 2015/05/02 14:10:03 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -50,11 +50,11 @@
 static int     tegra_sdhc_match(device_t, cfdata_t, void *);
 static void    tegra_sdhc_attach(device_t, device_t, void *);
 
-static void    tegra_sdhc_attach_i(device_t);
-
 struct tegra_sdhc_softc {
        struct sdhc_softc       sc;
 
+       u_int                   sc_port;
+
        bus_space_tag_t         sc_bst;
        bus_space_handle_t      sc_bsh;
        bus_size_t              sc_bsz;
@@ -77,10 +77,14 @@
        struct tegra_sdhc_softc * const sc = device_private(self);
        struct tegraio_attach_args * const tio = aux;
        const struct tegra_locators * const loc = &tio->tio_loc;
+       int error;
 
        sc->sc.sc_dev = self;
        sc->sc.sc_dmat = tio->tio_dmat;
        sc->sc.sc_flags = SDHC_FLAG_32BIT_ACCESS |
+                         SDHC_FLAG_NO_PWR0 |
+                         SDHC_FLAG_NO_HS_BIT |
+                         SDHC_FLAG_NO_CLKBASE |
                          SDHC_FLAG_USE_DMA;
        if (SDMMC_8BIT_P(loc->loc_port)) {
                sc->sc.sc_flags |= SDHC_FLAG_8BIT_MODE;
@@ -91,12 +95,15 @@
        bus_space_subregion(tio->tio_bst, tio->tio_bsh,
            loc->loc_offset, loc->loc_size, &sc->sc_bsh);
        sc->sc_bsz = loc->loc_size;
+       sc->sc_port = loc->loc_port;
 
-#if notyet
-       sc->sc.sc_clkbase = tegra_sdhc_get_freq(loc->loc_port) / 1000;
-#else
-       sc->sc.sc_clkbase = 0;
-#endif
+       /*
+        * The controller supports SDR104 speeds (208 MHz). With PLLP (408 Mhz)
+        * as input and div=2 we can get a reasonable 204 MHz for the SDHC.
+        */
+       const u_int div = howmany(tegra_car_pllp0_rate() / 1000, 208000);
+       tegra_car_periph_sdmmc_set_div(sc->sc_port, div);
+       sc->sc.sc_clkbase = tegra_car_periph_sdmmc_rate(sc->sc_port) / 1000;
 
        aprint_naive("\n");
        aprint_normal(": SDMMC%d\n", loc->loc_port + 1);
@@ -115,15 +122,6 @@
        }
        aprint_normal_dev(self, "interrupting on irq %d\n", loc->loc_intr);
 
-       config_interrupts(self, tegra_sdhc_attach_i);
-}
-
-static void
-tegra_sdhc_attach_i(device_t self)
-{
-       struct tegra_sdhc_softc * const sc = device_private(self);
-       int error;
-
        error = sdhc_host_found(&sc->sc, sc->sc_bst, sc->sc_bsh, sc->sc_bsz);
        if (error) {
                aprint_error_dev(self, "couldn't initialize host, error = %d\n",



Home | Main Index | Thread Index | Old Index