Module Name: src Committed By: jmcneill Date: Sat May 2 14:10:03 UTC 2015
Modified Files: src/sys/arch/arm/nvidia: tegra_car.c tegra_carreg.h tegra_sdhc.c Log Message: 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. To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/nvidia/tegra_car.c \ src/sys/arch/arm/nvidia/tegra_carreg.h \ src/sys/arch/arm/nvidia/tegra_sdhc.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/nvidia/tegra_car.c diff -u src/sys/arch/arm/nvidia/tegra_car.c:1.1 src/sys/arch/arm/nvidia/tegra_car.c:1.2 --- src/sys/arch/arm/nvidia/tegra_car.c:1.1 Tue Apr 28 11:15:55 2015 +++ src/sys/arch/arm/nvidia/tegra_car.c Sat May 2 14:10:03 2015 @@ -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 <jmcne...@invisible.ca> @@ -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 @@ tegra_car_attach(device_t parent, device 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 @@ tegra_car_osc_rate(void) 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_pllx_rate(void) 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; +} Index: src/sys/arch/arm/nvidia/tegra_carreg.h diff -u src/sys/arch/arm/nvidia/tegra_carreg.h:1.1 src/sys/arch/arm/nvidia/tegra_carreg.h:1.2 --- src/sys/arch/arm/nvidia/tegra_carreg.h:1.1 Tue Apr 28 11:15:55 2015 +++ src/sys/arch/arm/nvidia/tegra_carreg.h Sat May 2 14:10:03 2015 @@ -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 <jmcne...@invisible.ca> @@ -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 */ Index: src/sys/arch/arm/nvidia/tegra_sdhc.c diff -u src/sys/arch/arm/nvidia/tegra_sdhc.c:1.1 src/sys/arch/arm/nvidia/tegra_sdhc.c:1.2 --- src/sys/arch/arm/nvidia/tegra_sdhc.c:1.1 Sun Mar 29 10:41:59 2015 +++ src/sys/arch/arm/nvidia/tegra_sdhc.c Sat May 2 14:10:03 2015 @@ -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 <jmcne...@invisible.ca> @@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: tegra_sdhc.c 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 @@ tegra_sdhc_attach(device_t parent, devic 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 @@ tegra_sdhc_attach(device_t parent, devic 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 @@ tegra_sdhc_attach(device_t parent, devic } 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",