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 <sjg@chromium.org>
Tested-by: Tom Warren <twarren@nvidia.com>
diff --git a/drivers/mmc/tegra2_mmc.c b/drivers/mmc/tegra2_mmc.c
index 8b6f829..a71785c 100644
--- a/drivers/mmc/tegra2_mmc.c
+++ b/drivers/mmc/tegra2_mmc.c
@@ -23,36 +23,46 @@
#include <mmc.h>
#include <asm/io.h>
#include <asm/arch/clk_rst.h>
+#include <asm/arch/clock.h>
#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 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 @@
* 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 @@
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 @@
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 @@
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;