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",

Reply via email to