From 21ef6a109c599adbf1f26804b9ba979c17ead0bc Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Tue, 31 May 2011 10:30:37 +0000 Subject: mmc: Tegra2: SD/MMC driver for Seaboard - eMMC on SDMMC4, SDIO on SDMMC3 Signed-off-by: Tom Warren Acked-by: Andy Fleming --- board/nvidia/common/board.c | 147 ++++++++++++++++++++++++++++++++++++++++++++ board/nvidia/common/board.h | 1 + 2 files changed, 148 insertions(+) (limited to 'board/nvidia') diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index 3d6c248..627e061 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -32,6 +32,10 @@ #include #include "board.h" +#ifdef CONFIG_TEGRA2_MMC +#include +#endif + DECLARE_GLOBAL_DATA_PTR; const struct tegra2_sysinfo sysinfo = { @@ -171,6 +175,116 @@ static void pin_mux_uart(void) } /* + * Routine: clock_init_mmc + * Description: init the PLL and clocks for the SDMMC controllers + */ +static void clock_init_mmc(void) +{ + struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + u32 reg; + + /* Do the SDMMC resets/clock enables */ + + /* Assert Reset to SDMMC4 */ + reg = readl(&clkrst->crc_rst_dev_l); + reg |= SWR_SDMMC4_RST; /* SWR_SDMMC4_RST = 1 */ + writel(reg, &clkrst->crc_rst_dev_l); + + /* Enable clk to SDMMC4 */ + reg = readl(&clkrst->crc_clk_out_enb_l); + reg |= CLK_ENB_SDMMC4; /* CLK_ENB_SDMMC4 = 1 */ + writel(reg, &clkrst->crc_clk_out_enb_l); + + /* Enable pllp_out0 to SDMMC4 */ + reg = readl(&clkrst->crc_clk_src_sdmmc4); + reg &= 0x3FFFFF00; /* SDMMC4_CLK_SRC = 00, PLLP_OUT0 */ + reg |= (10 << 1); /* n-1, 11-1 shl 1 */ + writel(reg, &clkrst->crc_clk_src_sdmmc4); + + /* + * As per the Tegra2 TRM, section 5.3.4: + * 'Wait 2 us for the clock to flush through the pipe/logic' + */ + udelay(2); + + /* De-assert reset to SDMMC4 */ + reg = readl(&clkrst->crc_rst_dev_l); + reg &= ~SWR_SDMMC4_RST; /* SWR_SDMMC4_RST = 0 */ + writel(reg, &clkrst->crc_rst_dev_l); + + /* Assert Reset to SDMMC3 */ + reg = readl(&clkrst->crc_rst_dev_u); + reg |= SWR_SDMMC3_RST; /* SWR_SDMMC3_RST = 1 */ + writel(reg, &clkrst->crc_rst_dev_u); + + /* Enable clk to SDMMC3 */ + reg = readl(&clkrst->crc_clk_out_enb_u); + reg |= CLK_ENB_SDMMC3; /* CLK_ENB_SDMMC3 = 1 */ + writel(reg, &clkrst->crc_clk_out_enb_u); + + /* Enable pllp_out0 to SDMMC4, set divisor to 11 for 20MHz */ + reg = readl(&clkrst->crc_clk_src_sdmmc3); + reg &= 0x3FFFFF00; /* SDMMC3_CLK_SRC = 00, PLLP_OUT0 */ + reg |= (10 << 1); /* n-1, 11-1 shl 1 */ + writel(reg, &clkrst->crc_clk_src_sdmmc3); + + /* wait for 2us */ + udelay(2); + + /* De-assert reset to SDMMC3 */ + reg = readl(&clkrst->crc_rst_dev_u); + reg &= ~SWR_SDMMC3_RST; /* SWR_SDMMC3_RST = 0 */ + writel(reg, &clkrst->crc_rst_dev_u); +} + +/* + * Routine: pin_mux_mmc + * Description: setup the pin muxes/tristate values for the SDMMC(s) + */ +static void pin_mux_mmc(void) +{ + struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 reg; + + /* SDMMC4 */ + /* config 2, x8 on 2nd set of pins */ + reg = readl(&pmt->pmt_ctl_a); + reg |= (3 << 16); /* ATB_SEL [17:16] = 11 SDIO4 */ + writel(reg, &pmt->pmt_ctl_a); + reg = readl(&pmt->pmt_ctl_b); + reg |= (3 << 0); /* GMA_SEL [1:0] = 11 SDIO4 */ + writel(reg, &pmt->pmt_ctl_b); + reg = readl(&pmt->pmt_ctl_d); + reg |= (3 << 0); /* GME_SEL [1:0] = 11 SDIO4 */ + writel(reg, &pmt->pmt_ctl_d); + + reg = readl(&pmt->pmt_tri_a); + reg &= ~Z_ATB; /* Z_ATB = normal (0) */ + reg &= ~Z_GMA; /* Z_GMA = normal (0) */ + writel(reg, &pmt->pmt_tri_a); + reg = readl(&pmt->pmt_tri_b); + reg &= ~Z_GME; /* Z_GME = normal (0) */ + writel(reg, &pmt->pmt_tri_b); + + /* SDMMC3 */ + /* SDIO3_CLK, SDIO3_CMD, SDIO3_DAT[3:0] */ + reg = readl(&pmt->pmt_ctl_d); + reg &= 0xFFFF03FF; + reg |= (2 << 10); /* SDB_SEL [11:10] = 01 SDIO3 */ + reg |= (2 << 12); /* SDC_SEL [13:12] = 01 SDIO3 */ + reg |= (2 << 14); /* SDD_SEL [15:14] = 01 SDIO3 */ + writel(reg, &pmt->pmt_ctl_d); + + reg = readl(&pmt->pmt_tri_b); + reg &= ~Z_SDC; /* Z_SDC = normal (0) */ + reg &= ~Z_SDD; /* Z_SDD = normal (0) */ + writel(reg, &pmt->pmt_tri_b); + reg = readl(&pmt->pmt_tri_d); + reg &= ~Z_SDB; /* Z_SDB = normal (0) */ + writel(reg, &pmt->pmt_tri_d); +} + +/* * Routine: clock_init * Description: Do individual peripheral clock reset/enables */ @@ -210,3 +324,36 @@ int board_init(void) return 0; } + +#ifdef CONFIG_TEGRA2_MMC +/* this is a weak define that we are overriding */ +int board_mmc_init(bd_t *bd) +{ + debug("board_mmc_init called\n"); + /* Enable clocks, muxes, etc. for SDMMC controllers */ + clock_init_mmc(); + pin_mux_mmc(); + + debug("board_mmc_init: init eMMC\n"); + /* init dev 0, eMMC chip, with 4-bit bus */ + tegra2_mmc_init(0, 4); + + debug("board_mmc_init: init SD slot\n"); + /* init dev 1, SD slot, with 4-bit bus */ + tegra2_mmc_init(1, 4); + + return 0; +} + +/* this is a weak define that we are overriding */ +int board_mmc_getcd(u8 *cd, struct mmc *mmc) +{ + debug("board_mmc_getcd called\n"); + /* + * Hard-code CD presence for now. Need to add GPIO inputs + * for Seaboard & Harmony (& Kaen/Aebl/Wario?) + */ + *cd = 1; + return 0; +} +#endif diff --git a/board/nvidia/common/board.h b/board/nvidia/common/board.h index 350bc57..4334c02 100644 --- a/board/nvidia/common/board.h +++ b/board/nvidia/common/board.h @@ -29,5 +29,6 @@ void clock_init(void); void pinmux_init(void); void gpio_init(void); void gpio_config_uart(void); +int tegra2_mmc_init(int dev_index, int bus_width); #endif /* BOARD_H */ -- cgit v1.1