ARM: tegra: clocks: Add emc scaling

Change-Id: Ica5ee704dd35b5fbf02d8c030a8578d5e8694839
Signed-off-by: Colin Cross <ccross@android.com>
This commit is contained in:
Colin Cross
2010-11-22 18:37:54 -08:00
parent 931788acdb
commit 7312d0e19c

View File

@@ -32,6 +32,7 @@
#include "clock.h"
#include "fuse.h"
#include "tegra2_emc.h"
#define RST_DEVICES 0x004
#define RST_DEVICES_SET 0x300
@@ -1021,6 +1022,53 @@ static struct clk_ops tegra_periph_clk_ops = {
.reset = &tegra2_periph_clk_reset,
};
/* External memory controller clock ops */
static void tegra2_emc_clk_init(struct clk *c)
{
tegra2_periph_clk_init(c);
c->max_rate = clk_get_rate_locked(c);
}
static long tegra2_emc_clk_round_rate(struct clk *c, unsigned long rate)
{
long new_rate = rate;
new_rate = tegra_emc_round_rate(new_rate);
if (new_rate < 0)
return c->max_rate;
BUG_ON(new_rate != tegra2_periph_clk_round_rate(c, new_rate));
return new_rate;
}
static int tegra2_emc_clk_set_rate(struct clk *c, unsigned long rate)
{
int ret;
/* The Tegra2 memory controller has an interlock with the clock
* block that allows memory shadowed registers to be updated,
* and then transfer them to the main registers at the same
* time as the clock update without glitches. */
ret = tegra_emc_set_rate(rate);
if (ret < 0)
return ret;
ret = tegra2_periph_clk_set_rate(c, rate);
udelay(1);
return ret;
}
static struct clk_ops tegra_emc_clk_ops = {
.init = &tegra2_emc_clk_init,
.enable = &tegra2_periph_clk_enable,
.disable = &tegra2_periph_clk_disable,
.set_parent = &tegra2_periph_clk_set_parent,
.set_rate = &tegra2_emc_clk_set_rate,
.round_rate = &tegra2_emc_clk_round_rate,
.reset = &tegra2_periph_clk_reset,
};
/* Clock doubler ops */
static void tegra2_clk_double_init(struct clk *c)
{
@@ -1157,7 +1205,8 @@ static void tegra_clk_shared_bus_update(struct clk *bus)
rate = max(c->u.shared_bus_user.rate, rate);
}
clk_set_rate(bus, rate);
if (rate != clk_get_rate(bus))
clk_set_rate(bus, rate);
};
static void tegra_clk_shared_bus_init(struct clk *c)
@@ -1839,6 +1888,18 @@ static struct clk_mux_sel mux_clk_32k[] = {
{ 0, 0},
};
static struct clk tegra_clk_emc = {
.name = "emc",
.ops = &tegra_emc_clk_ops,
.reg = 0x19c,
.max_rate = 800000000,
.inputs = mux_pllm_pllc_pllp_clkm,
.flags = MUX | DIV_U71 | PERIPH_EMC_ENB,
.u.periph = {
.clk_num = 57,
},
};
#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
{ \
.name = _name, \
@@ -1927,13 +1988,17 @@ struct clk tegra_list_clks[] = {
PERIPH_CLK("usbd", "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb2", "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb3", "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("emc", "emc", NULL, 57, 0x19c, 800000000, mux_pllm_pllc_pllp_clkm, MUX | DIV_U71 | PERIPH_EMC_ENB),
PERIPH_CLK("dsi", "dsi", NULL, 48, 0, 500000000, mux_plld, 0), /* scales with voltage */
PERIPH_CLK("csi", "tegra_camera", "csi", 52, 0, 72000000, mux_pllp_out3, 0),
PERIPH_CLK("isp", "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0), /* same frequency as VI */
PERIPH_CLK("csus", "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET),
SHARED_CLK("avp.sclk", "tegra-avp", "sclk", &tegra_clk_sclk),
SHARED_CLK("avp.emc", "tegra-avp", "emc", &tegra_clk_emc),
SHARED_CLK("cpu.emc", "cpu", "emc", &tegra_clk_emc),
SHARED_CLK("disp1.emc", "tegradc.0", "emc", &tegra_clk_emc),
SHARED_CLK("disp2.emc", "tegradc.1", "emc", &tegra_clk_emc),
SHARED_CLK("hdmi.emc", "hdmi", "emc", &tegra_clk_emc),
};
#define CLK_DUPLICATE(_name, _dev, _con) \
@@ -2008,6 +2073,7 @@ struct clk *tegra_ptr_clks[] = {
&tegra_clk_virtual_cpu,
&tegra_clk_blink,
&tegra_clk_cop,
&tegra_clk_emc,
};
static void tegra2_init_one_clock(struct clk *c)