From 4ed59e70e4e0309794d532120d8c357b308b0e23 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 21 Sep 2011 12:40:04 +0000 Subject: tegra2: Add more clock functions This adds most of the clock functions required by board and driver code: -query and adjust peripheral clocks -query and adjust PLLs -reset and enable control These functions are plumbed in as required. Signed-off-by: Simon Glass Tested-by: Tom Warren --- drivers/mmc/tegra2_mmc.c | 92 ++++++++++++++++-------------------------------- drivers/mmc/tegra2_mmc.h | 1 + 2 files changed, 32 insertions(+), 61 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/tegra2_mmc.c b/drivers/mmc/tegra2_mmc.c index 8b6f829e73..a71785cd7c 100644 --- a/drivers/mmc/tegra2_mmc.c +++ b/drivers/mmc/tegra2_mmc.c @@ -23,36 +23,46 @@ #include #include #include +#include #include "tegra2_mmc.h" /* support 4 mmc hosts */ struct mmc mmc_dev[4]; struct mmc_host mmc_host[4]; -static inline struct tegra2_mmc *tegra2_get_base_mmc(int dev_index) + +/** + * Get the host address and peripheral ID for a device. Devices are numbered + * from 0 to 3. + * + * @param host Structure to fill in (base, reg, mmc_id) + * @param dev_index Device index (0-3) + */ +static void tegra2_get_setup(struct mmc_host *host, int dev_index) { - unsigned long offset; debug("tegra2_get_base_mmc: dev_index = %d\n", dev_index); switch (dev_index) { - case 0: - offset = TEGRA2_SDMMC4_BASE; - break; case 1: - offset = TEGRA2_SDMMC3_BASE; + host->base = TEGRA2_SDMMC3_BASE; + host->mmc_id = PERIPH_ID_SDMMC3; break; case 2: - offset = TEGRA2_SDMMC2_BASE; + host->base = TEGRA2_SDMMC2_BASE; + host->mmc_id = PERIPH_ID_SDMMC2; break; case 3: - offset = TEGRA2_SDMMC1_BASE; + host->base = TEGRA2_SDMMC1_BASE; + host->mmc_id = PERIPH_ID_SDMMC1; break; + case 0: default: - offset = TEGRA2_SDMMC4_BASE; + host->base = TEGRA2_SDMMC4_BASE; + host->mmc_id = PERIPH_ID_SDMMC4; break; } - return (struct tegra2_mmc *)(offset); + host->reg = (struct tegra2_mmc *)host->base; } static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data) @@ -274,62 +284,24 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, static void mmc_change_clock(struct mmc_host *host, uint clock) { - int div, hw_div; + int div; unsigned short clk; unsigned long timeout; - unsigned int reg, hostbase; - struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + debug(" mmc_change_clock called\n"); - /* Change Tegra2 SDMMCx clock divisor here */ - /* Source is 216MHz, PLLP_OUT0 */ + /* + * Change Tegra2 SDMMCx clock divisor here. Source is 216MHz, + * PLLP_OUT0 + */ if (clock == 0) goto out; - - div = 1; - if (clock <= 400000) { - hw_div = ((9-1)<<1); /* Best match is 375KHz */ - div = 64; - } else if (clock <= 20000000) - hw_div = ((11-1)<<1); /* Best match is 19.6MHz */ - else if (clock <= 26000000) - hw_div = ((9-1)<<1); /* Use 24MHz */ - else - hw_div = ((4-1)<<1) + 1; /* 4.5 divisor for 48MHz */ - - debug("mmc_change_clock: hw_div = %d, card clock div = %d\n", - hw_div, div); - - /* Change SDMMCx divisor */ - - hostbase = readl(&host->base); - debug("mmc_change_clock: hostbase = %08X\n", hostbase); - - if (hostbase == TEGRA2_SDMMC1_BASE) { - reg = readl(&clkrst->crc_clk_src_sdmmc1); - reg &= 0xFFFFFF00; /* divisor (7.1) = 00 */ - reg |= hw_div; /* n-1 */ - writel(reg, &clkrst->crc_clk_src_sdmmc1); - } else if (hostbase == TEGRA2_SDMMC2_BASE) { - reg = readl(&clkrst->crc_clk_src_sdmmc2); - reg &= 0xFFFFFF00; /* divisor (7.1) = 00 */ - reg |= hw_div; /* n-1 */ - writel(reg, &clkrst->crc_clk_src_sdmmc2); - } else if (hostbase == TEGRA2_SDMMC3_BASE) { - reg = readl(&clkrst->crc_clk_src_sdmmc3); - reg &= 0xFFFFFF00; /* divisor (7.1) = 00 */ - reg |= hw_div; /* n-1 */ - writel(reg, &clkrst->crc_clk_src_sdmmc3); - } else { - reg = readl(&clkrst->crc_clk_src_sdmmc4); - reg &= 0xFFFFFF00; /* divisor (7.1) = 00 */ - reg |= hw_div; /* n-1 */ - writel(reg, &clkrst->crc_clk_src_sdmmc4); - } + clock_adjust_periph_pll_div(host->mmc_id, CLOCK_ID_PERIPH, clock, + &div); + debug("div = %d\n", div); writew(0, &host->reg->clkcon); - div >>= 1; /* * CLKCON * SELFREQ[15:8] : base clock divided by value @@ -337,6 +309,7 @@ static void mmc_change_clock(struct mmc_host *host, uint clock) * STBLINTCLK[1] : Internal Clock Stable * ENINTCLK[0] : Internal Clock Enable */ + div >>= 1; clk = (div << 8) | (1 << 0); writew(clk, &host->reg->clkcon); @@ -355,7 +328,6 @@ static void mmc_change_clock(struct mmc_host *host, uint clock) writew(clk, &host->reg->clkcon); debug("mmc_change_clock: clkcon = %08X\n", clk); - debug("mmc_change_clock: CLK_SOURCE_SDMMCx = %08X\n", reg); out: host->clock = clock; @@ -370,7 +342,6 @@ static void mmc_set_ios(struct mmc *mmc) debug("bus_width: %x, clock: %d\n", mmc->bus_width, mmc->clock); /* Change clock first */ - mmc_change_clock(host, mmc->clock); ctrl = readb(&host->reg->hostctl); @@ -495,8 +466,7 @@ static int tegra2_mmc_initialize(int dev_index, int bus_width) mmc->f_max = 48000000; mmc_host[dev_index].clock = 0; - mmc_host[dev_index].reg = tegra2_get_base_mmc(dev_index); - mmc_host[dev_index].base = (unsigned int)mmc_host[dev_index].reg; + tegra2_get_setup(&mmc_host[dev_index], dev_index); mmc_register(mmc); return 0; diff --git a/drivers/mmc/tegra2_mmc.h b/drivers/mmc/tegra2_mmc.h index 4b80f9f3b3..28698e0fc0 100644 --- a/drivers/mmc/tegra2_mmc.h +++ b/drivers/mmc/tegra2_mmc.h @@ -73,6 +73,7 @@ struct mmc_host { unsigned int version; /* SDHCI spec. version */ unsigned int clock; /* Current clock (MHz) */ unsigned int base; /* Base address, SDMMC1/2/3/4 */ + enum periph_id mmc_id; /* Peripheral ID: PERIPH_ID_... */ }; int tegra2_mmc_init(int dev_index, int bus_width); -- cgit