From 88e790a445b35cf137a62e590ced5315defad060 Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Mon, 6 Aug 2012 11:57:39 +0530 Subject: ARM: tegra30: Separate out clk ops and clk data Move clock initialization data to separate file. This is required for migrating to generic clock framework if static initialization is used. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/tegra30_clocks.c | 1155 +--------------------------------- 1 file changed, 22 insertions(+), 1133 deletions(-) (limited to 'arch/arm/mach-tegra/tegra30_clocks.c') diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c index 6674f100e16f..645ef6900a0e 100644 --- a/arch/arm/mach-tegra/tegra30_clocks.c +++ b/arch/arm/mach-tegra/tegra30_clocks.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/tegra30_clocks.c * - * Copyright (c) 2010-2011 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -533,13 +533,13 @@ static void tegra30_clk_m_disable(struct clk *c) WARN(1, "Attempting to disable main SoC clock\n"); } -static struct clk_ops tegra_clk_m_ops = { +struct clk_ops tegra30_clk_m_ops = { .init = tegra30_clk_m_init, .enable = tegra30_clk_m_enable, .disable = tegra30_clk_m_disable, }; -static struct clk_ops tegra_clk_m_div_ops = { +struct clk_ops tegra_clk_m_div_ops = { .enable = tegra30_clk_m_enable, }; @@ -567,7 +567,7 @@ static void tegra30_pll_ref_init(struct clk *c) c->state = ON; } -static struct clk_ops tegra_pll_ref_ops = { +struct clk_ops tegra_pll_ref_ops = { .init = tegra30_pll_ref_init, .enable = tegra30_clk_m_enable, .disable = tegra30_clk_m_disable, @@ -707,7 +707,7 @@ static int tegra30_super_clk_set_rate(struct clk *c, unsigned long rate) return clk_set_rate(c->parent, rate); } -static struct clk_ops tegra_super_ops = { +struct clk_ops tegra30_super_ops = { .init = tegra30_super_clk_init, .enable = tegra30_super_clk_enable, .disable = tegra30_super_clk_disable, @@ -722,7 +722,7 @@ static int tegra30_twd_clk_set_rate(struct clk *c, unsigned long rate) return 0; } -static struct clk_ops tegra30_twd_ops = { +struct clk_ops tegra30_twd_ops = { .set_rate = tegra30_twd_clk_set_rate, }; @@ -801,7 +801,7 @@ static int tegra30_blink_clk_set_rate(struct clk *c, unsigned long rate) return 0; } -static struct clk_ops tegra_blink_clk_ops = { +struct clk_ops tegra30_blink_clk_ops = { .init = &tegra30_blink_clk_init, .enable = &tegra30_blink_clk_enable, .disable = &tegra30_blink_clk_disable, @@ -829,7 +829,6 @@ static int tegra30_pll_clk_wait_for_lock(struct clk *c, u32 lock_reg, return 0; } - static void tegra30_utmi_param_configure(struct clk *c) { u32 reg; @@ -1100,7 +1099,7 @@ static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate) return 0; } -static struct clk_ops tegra_pll_ops = { +struct clk_ops tegra30_pll_ops = { .init = tegra30_pll_clk_init, .enable = tegra30_pll_clk_enable, .disable = tegra30_pll_clk_disable, @@ -1141,7 +1140,7 @@ tegra30_plld_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) return 0; } -static struct clk_ops tegra_plld_ops = { +struct clk_ops tegra_plld_ops = { .init = tegra30_pll_clk_init, .enable = tegra30_pll_clk_enable, .disable = tegra30_pll_clk_disable, @@ -1258,7 +1257,7 @@ static int tegra30_plle_clk_enable(struct clk *c) return tegra30_plle_configure(c, !c->set); } -static struct clk_ops tegra_plle_ops = { +struct clk_ops tegra30_plle_ops = { .init = tegra30_plle_clk_init, .enable = tegra30_plle_clk_enable, .disable = tegra30_plle_clk_disable, @@ -1386,7 +1385,7 @@ static long tegra30_pll_div_clk_round_rate(struct clk *c, unsigned long rate) return -EINVAL; } -static struct clk_ops tegra_pll_div_ops = { +struct clk_ops tegra30_pll_div_ops = { .init = tegra30_pll_div_clk_init, .enable = tegra30_pll_div_clk_enable, .disable = tegra30_pll_div_clk_disable, @@ -1634,7 +1633,7 @@ static long tegra30_periph_clk_round_rate(struct clk *c, return -EINVAL; } -static struct clk_ops tegra_periph_clk_ops = { +struct clk_ops tegra30_periph_clk_ops = { .init = &tegra30_periph_clk_init, .enable = &tegra30_periph_clk_enable, .disable = &tegra30_periph_clk_disable, @@ -1644,7 +1643,6 @@ static struct clk_ops tegra_periph_clk_ops = { .reset = &tegra30_periph_clk_reset, }; - /* Periph extended clock configuration ops */ static int tegra30_vi_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) @@ -1660,7 +1658,7 @@ tegra30_vi_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) return -EINVAL; } -static struct clk_ops tegra_vi_clk_ops = { +struct clk_ops tegra_vi_clk_ops = { .init = &tegra30_periph_clk_init, .enable = &tegra30_periph_clk_enable, .disable = &tegra30_periph_clk_disable, @@ -1686,7 +1684,7 @@ tegra30_nand_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) return -EINVAL; } -static struct clk_ops tegra_nand_clk_ops = { +struct clk_ops tegra_nand_clk_ops = { .init = &tegra30_periph_clk_init, .enable = &tegra30_periph_clk_enable, .disable = &tegra30_periph_clk_disable, @@ -1697,7 +1695,6 @@ static struct clk_ops tegra_nand_clk_ops = { .reset = &tegra30_periph_clk_reset, }; - static int tegra30_dtv_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) { @@ -1713,7 +1710,7 @@ tegra30_dtv_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) return -EINVAL; } -static struct clk_ops tegra_dtv_clk_ops = { +struct clk_ops tegra_dtv_clk_ops = { .init = &tegra30_periph_clk_init, .enable = &tegra30_periph_clk_enable, .disable = &tegra30_periph_clk_disable, @@ -1753,7 +1750,7 @@ static int tegra30_dsib_clk_set_parent(struct clk *c, struct clk *p) return -EINVAL; } -static struct clk_ops tegra_dsib_clk_ops = { +struct clk_ops tegra_dsib_clk_ops = { .init = &tegra30_periph_clk_init, .enable = &tegra30_periph_clk_enable, .disable = &tegra30_periph_clk_disable, @@ -1764,7 +1761,7 @@ static struct clk_ops tegra_dsib_clk_ops = { }; /* pciex clock support only reset function */ -static struct clk_ops tegra_pciex_clk_ops = { +struct clk_ops tegra_pciex_clk_ops = { .reset = tegra30_periph_clk_reset, }; @@ -1851,14 +1848,13 @@ static int tegra30_clk_out_set_parent(struct clk *c, struct clk *p) return -EINVAL; } -static struct clk_ops tegra_clk_out_ops = { +struct clk_ops tegra_clk_out_ops = { .init = &tegra30_clk_out_init, .enable = &tegra30_clk_out_enable, .disable = &tegra30_clk_out_disable, .set_parent = &tegra30_clk_out_set_parent, }; - /* Clock doubler ops */ static void tegra30_clk_double_init(struct clk *c) { @@ -1890,7 +1886,7 @@ static int tegra30_clk_double_set_rate(struct clk *c, unsigned long rate) return -EINVAL; } -static struct clk_ops tegra_clk_double_ops = { +struct clk_ops tegra30_clk_double_ops = { .init = &tegra30_clk_double_init, .enable = &tegra30_periph_clk_enable, .disable = &tegra30_periph_clk_disable, @@ -1904,7 +1900,7 @@ static int tegra30_sync_source_set_rate(struct clk *c, unsigned long rate) return 0; } -static struct clk_ops tegra_sync_source_ops = { +struct clk_ops tegra_sync_source_ops = { .set_rate = &tegra30_sync_source_set_rate, }; @@ -1961,7 +1957,7 @@ static int tegra30_audio_sync_clk_set_parent(struct clk *c, struct clk *p) return -EINVAL; } -static struct clk_ops tegra_audio_sync_clk_ops = { +struct clk_ops tegra30_audio_sync_clk_ops = { .init = tegra30_audio_sync_clk_init, .enable = tegra30_audio_sync_clk_enable, .disable = tegra30_audio_sync_clk_disable, @@ -1990,1115 +1986,8 @@ static void tegra30_cml_clk_disable(struct clk *c) clk_writel(val, c->reg); } -static struct clk_ops tegra_cml_clk_ops = { +struct clk_ops tegra_cml_clk_ops = { .init = &tegra30_cml_clk_init, .enable = &tegra30_cml_clk_enable, .disable = &tegra30_cml_clk_disable, }; - -/* Clock definitions */ -static struct clk tegra_clk_32k = { - .name = "clk_32k", - .rate = 32768, - .ops = NULL, - .max_rate = 32768, -}; - -static struct clk tegra_clk_m = { - .name = "clk_m", - .flags = ENABLE_ON_INIT, - .ops = &tegra_clk_m_ops, - .reg = 0x1fc, - .reg_shift = 28, - .max_rate = 48000000, -}; - -static struct clk tegra_clk_m_div2 = { - .name = "clk_m_div2", - .ops = &tegra_clk_m_div_ops, - .parent = &tegra_clk_m, - .mul = 1, - .div = 2, - .state = ON, - .max_rate = 24000000, -}; - -static struct clk tegra_clk_m_div4 = { - .name = "clk_m_div4", - .ops = &tegra_clk_m_div_ops, - .parent = &tegra_clk_m, - .mul = 1, - .div = 4, - .state = ON, - .max_rate = 12000000, -}; - -static struct clk tegra_pll_ref = { - .name = "pll_ref", - .flags = ENABLE_ON_INIT, - .ops = &tegra_pll_ref_ops, - .parent = &tegra_clk_m, - .max_rate = 26000000, -}; - -static struct clk_pll_freq_table tegra_pll_c_freq_table[] = { - { 12000000, 1040000000, 520, 6, 1, 8}, - { 13000000, 1040000000, 480, 6, 1, 8}, - { 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */ - { 19200000, 1040000000, 325, 6, 1, 6}, - { 26000000, 1040000000, 520, 13, 1, 8}, - - { 12000000, 832000000, 416, 6, 1, 8}, - { 13000000, 832000000, 832, 13, 1, 8}, - { 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */ - { 19200000, 832000000, 260, 6, 1, 8}, - { 26000000, 832000000, 416, 13, 1, 8}, - - { 12000000, 624000000, 624, 12, 1, 8}, - { 13000000, 624000000, 624, 13, 1, 8}, - { 16800000, 600000000, 520, 14, 1, 8}, - { 19200000, 624000000, 520, 16, 1, 8}, - { 26000000, 624000000, 624, 26, 1, 8}, - - { 12000000, 600000000, 600, 12, 1, 8}, - { 13000000, 600000000, 600, 13, 1, 8}, - { 16800000, 600000000, 500, 14, 1, 8}, - { 19200000, 600000000, 375, 12, 1, 6}, - { 26000000, 600000000, 600, 26, 1, 8}, - - { 12000000, 520000000, 520, 12, 1, 8}, - { 13000000, 520000000, 520, 13, 1, 8}, - { 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */ - { 19200000, 520000000, 325, 12, 1, 6}, - { 26000000, 520000000, 520, 26, 1, 8}, - - { 12000000, 416000000, 416, 12, 1, 8}, - { 13000000, 416000000, 416, 13, 1, 8}, - { 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */ - { 19200000, 416000000, 260, 12, 1, 6}, - { 26000000, 416000000, 416, 26, 1, 8}, - { 0, 0, 0, 0, 0, 0 }, -}; - -static struct clk tegra_pll_c = { - .name = "pll_c", - .flags = PLL_HAS_CPCON, - .ops = &tegra_pll_ops, - .reg = 0x80, - .parent = &tegra_pll_ref, - .max_rate = 1400000000, - .u.pll = { - .input_min = 2000000, - .input_max = 31000000, - .cf_min = 1000000, - .cf_max = 6000000, - .vco_min = 20000000, - .vco_max = 1400000000, - .freq_table = tegra_pll_c_freq_table, - .lock_delay = 300, - }, -}; - -static struct clk tegra_pll_c_out1 = { - .name = "pll_c_out1", - .ops = &tegra_pll_div_ops, - .flags = DIV_U71, - .parent = &tegra_pll_c, - .reg = 0x84, - .reg_shift = 0, - .max_rate = 700000000, -}; - -static struct clk_pll_freq_table tegra_pll_m_freq_table[] = { - { 12000000, 666000000, 666, 12, 1, 8}, - { 13000000, 666000000, 666, 13, 1, 8}, - { 16800000, 666000000, 555, 14, 1, 8}, - { 19200000, 666000000, 555, 16, 1, 8}, - { 26000000, 666000000, 666, 26, 1, 8}, - { 12000000, 600000000, 600, 12, 1, 8}, - { 13000000, 600000000, 600, 13, 1, 8}, - { 16800000, 600000000, 500, 14, 1, 8}, - { 19200000, 600000000, 375, 12, 1, 6}, - { 26000000, 600000000, 600, 26, 1, 8}, - { 0, 0, 0, 0, 0, 0 }, -}; - -static struct clk tegra_pll_m = { - .name = "pll_m", - .flags = PLL_HAS_CPCON | PLLM, - .ops = &tegra_pll_ops, - .reg = 0x90, - .parent = &tegra_pll_ref, - .max_rate = 800000000, - .u.pll = { - .input_min = 2000000, - .input_max = 31000000, - .cf_min = 1000000, - .cf_max = 6000000, - .vco_min = 20000000, - .vco_max = 1200000000, - .freq_table = tegra_pll_m_freq_table, - .lock_delay = 300, - }, -}; - -static struct clk tegra_pll_m_out1 = { - .name = "pll_m_out1", - .ops = &tegra_pll_div_ops, - .flags = DIV_U71, - .parent = &tegra_pll_m, - .reg = 0x94, - .reg_shift = 0, - .max_rate = 600000000, -}; - -static struct clk_pll_freq_table tegra_pll_p_freq_table[] = { - { 12000000, 216000000, 432, 12, 2, 8}, - { 13000000, 216000000, 432, 13, 2, 8}, - { 16800000, 216000000, 360, 14, 2, 8}, - { 19200000, 216000000, 360, 16, 2, 8}, - { 26000000, 216000000, 432, 26, 2, 8}, - { 0, 0, 0, 0, 0, 0 }, -}; - -static struct clk tegra_pll_p = { - .name = "pll_p", - .flags = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON, - .ops = &tegra_pll_ops, - .reg = 0xa0, - .parent = &tegra_pll_ref, - .max_rate = 432000000, - .u.pll = { - .input_min = 2000000, - .input_max = 31000000, - .cf_min = 1000000, - .cf_max = 6000000, - .vco_min = 20000000, - .vco_max = 1400000000, - .freq_table = tegra_pll_p_freq_table, - .lock_delay = 300, - .fixed_rate = 408000000, - }, -}; - -static struct clk tegra_pll_p_out1 = { - .name = "pll_p_out1", - .ops = &tegra_pll_div_ops, - .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, - .parent = &tegra_pll_p, - .reg = 0xa4, - .reg_shift = 0, - .max_rate = 432000000, -}; - -static struct clk tegra_pll_p_out2 = { - .name = "pll_p_out2", - .ops = &tegra_pll_div_ops, - .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, - .parent = &tegra_pll_p, - .reg = 0xa4, - .reg_shift = 16, - .max_rate = 432000000, -}; - -static struct clk tegra_pll_p_out3 = { - .name = "pll_p_out3", - .ops = &tegra_pll_div_ops, - .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, - .parent = &tegra_pll_p, - .reg = 0xa8, - .reg_shift = 0, - .max_rate = 432000000, -}; - -static struct clk tegra_pll_p_out4 = { - .name = "pll_p_out4", - .ops = &tegra_pll_div_ops, - .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, - .parent = &tegra_pll_p, - .reg = 0xa8, - .reg_shift = 16, - .max_rate = 432000000, -}; - -static struct clk_pll_freq_table tegra_pll_a_freq_table[] = { - { 9600000, 564480000, 294, 5, 1, 4}, - { 9600000, 552960000, 288, 5, 1, 4}, - { 9600000, 24000000, 5, 2, 1, 1}, - - { 28800000, 56448000, 49, 25, 1, 1}, - { 28800000, 73728000, 64, 25, 1, 1}, - { 28800000, 24000000, 5, 6, 1, 1}, - { 0, 0, 0, 0, 0, 0 }, -}; - -static struct clk tegra_pll_a = { - .name = "pll_a", - .flags = PLL_HAS_CPCON, - .ops = &tegra_pll_ops, - .reg = 0xb0, - .parent = &tegra_pll_p_out1, - .max_rate = 700000000, - .u.pll = { - .input_min = 2000000, - .input_max = 31000000, - .cf_min = 1000000, - .cf_max = 6000000, - .vco_min = 20000000, - .vco_max = 1400000000, - .freq_table = tegra_pll_a_freq_table, - .lock_delay = 300, - }, -}; - -static struct clk tegra_pll_a_out0 = { - .name = "pll_a_out0", - .ops = &tegra_pll_div_ops, - .flags = DIV_U71, - .parent = &tegra_pll_a, - .reg = 0xb4, - .reg_shift = 0, - .max_rate = 100000000, -}; - -static struct clk_pll_freq_table tegra_pll_d_freq_table[] = { - { 12000000, 216000000, 216, 12, 1, 4}, - { 13000000, 216000000, 216, 13, 1, 4}, - { 16800000, 216000000, 180, 14, 1, 4}, - { 19200000, 216000000, 180, 16, 1, 4}, - { 26000000, 216000000, 216, 26, 1, 4}, - - { 12000000, 594000000, 594, 12, 1, 8}, - { 13000000, 594000000, 594, 13, 1, 8}, - { 16800000, 594000000, 495, 14, 1, 8}, - { 19200000, 594000000, 495, 16, 1, 8}, - { 26000000, 594000000, 594, 26, 1, 8}, - - { 12000000, 1000000000, 1000, 12, 1, 12}, - { 13000000, 1000000000, 1000, 13, 1, 12}, - { 19200000, 1000000000, 625, 12, 1, 8}, - { 26000000, 1000000000, 1000, 26, 1, 12}, - - { 0, 0, 0, 0, 0, 0 }, -}; - -static struct clk tegra_pll_d = { - .name = "pll_d", - .flags = PLL_HAS_CPCON | PLLD, - .ops = &tegra_plld_ops, - .reg = 0xd0, - .parent = &tegra_pll_ref, - .max_rate = 1000000000, - .u.pll = { - .input_min = 2000000, - .input_max = 40000000, - .cf_min = 1000000, - .cf_max = 6000000, - .vco_min = 40000000, - .vco_max = 1000000000, - .freq_table = tegra_pll_d_freq_table, - .lock_delay = 1000, - }, -}; - -static struct clk tegra_pll_d_out0 = { - .name = "pll_d_out0", - .ops = &tegra_pll_div_ops, - .flags = DIV_2 | PLLD, - .parent = &tegra_pll_d, - .max_rate = 500000000, -}; - -static struct clk tegra_pll_d2 = { - .name = "pll_d2", - .flags = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLD, - .ops = &tegra_plld_ops, - .reg = 0x4b8, - .parent = &tegra_pll_ref, - .max_rate = 1000000000, - .u.pll = { - .input_min = 2000000, - .input_max = 40000000, - .cf_min = 1000000, - .cf_max = 6000000, - .vco_min = 40000000, - .vco_max = 1000000000, - .freq_table = tegra_pll_d_freq_table, - .lock_delay = 1000, - }, -}; - -static struct clk tegra_pll_d2_out0 = { - .name = "pll_d2_out0", - .ops = &tegra_pll_div_ops, - .flags = DIV_2 | PLLD, - .parent = &tegra_pll_d2, - .max_rate = 500000000, -}; - -static struct clk_pll_freq_table tegra_pll_u_freq_table[] = { - { 12000000, 480000000, 960, 12, 2, 12}, - { 13000000, 480000000, 960, 13, 2, 12}, - { 16800000, 480000000, 400, 7, 2, 5}, - { 19200000, 480000000, 200, 4, 2, 3}, - { 26000000, 480000000, 960, 26, 2, 12}, - { 0, 0, 0, 0, 0, 0 }, -}; - -static struct clk tegra_pll_u = { - .name = "pll_u", - .flags = PLL_HAS_CPCON | PLLU, - .ops = &tegra_pll_ops, - .reg = 0xc0, - .parent = &tegra_pll_ref, - .max_rate = 480000000, - .u.pll = { - .input_min = 2000000, - .input_max = 40000000, - .cf_min = 1000000, - .cf_max = 6000000, - .vco_min = 480000000, - .vco_max = 960000000, - .freq_table = tegra_pll_u_freq_table, - .lock_delay = 1000, - }, -}; - -static struct clk_pll_freq_table tegra_pll_x_freq_table[] = { - /* 1.7 GHz */ - { 12000000, 1700000000, 850, 6, 1, 8}, - { 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */ - { 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */ - { 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */ - { 26000000, 1700000000, 850, 13, 1, 8}, - - /* 1.6 GHz */ - { 12000000, 1600000000, 800, 6, 1, 8}, - { 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */ - { 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */ - { 19200000, 1600000000, 500, 6, 1, 8}, - { 26000000, 1600000000, 800, 13, 1, 8}, - - /* 1.5 GHz */ - { 12000000, 1500000000, 750, 6, 1, 8}, - { 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */ - { 16800000, 1500000000, 625, 7, 1, 8}, - { 19200000, 1500000000, 625, 8, 1, 8}, - { 26000000, 1500000000, 750, 13, 1, 8}, - - /* 1.4 GHz */ - { 12000000, 1400000000, 700, 6, 1, 8}, - { 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */ - { 16800000, 1400000000, 1000, 12, 1, 8}, - { 19200000, 1400000000, 875, 12, 1, 8}, - { 26000000, 1400000000, 700, 13, 1, 8}, - - /* 1.3 GHz */ - { 12000000, 1300000000, 975, 9, 1, 8}, - { 13000000, 1300000000, 1000, 10, 1, 8}, - { 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */ - { 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */ - { 26000000, 1300000000, 650, 13, 1, 8}, - - /* 1.2 GHz */ - { 12000000, 1200000000, 1000, 10, 1, 8}, - { 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */ - { 16800000, 1200000000, 1000, 14, 1, 8}, - { 19200000, 1200000000, 1000, 16, 1, 8}, - { 26000000, 1200000000, 600, 13, 1, 8}, - - /* 1.1 GHz */ - { 12000000, 1100000000, 825, 9, 1, 8}, - { 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */ - { 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */ - { 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */ - { 26000000, 1100000000, 550, 13, 1, 8}, - - /* 1 GHz */ - { 12000000, 1000000000, 1000, 12, 1, 8}, - { 13000000, 1000000000, 1000, 13, 1, 8}, - { 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */ - { 19200000, 1000000000, 625, 12, 1, 8}, - { 26000000, 1000000000, 1000, 26, 1, 8}, - - { 0, 0, 0, 0, 0, 0 }, -}; - -static struct clk tegra_pll_x = { - .name = "pll_x", - .flags = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLX, - .ops = &tegra_pll_ops, - .reg = 0xe0, - .parent = &tegra_pll_ref, - .max_rate = 1700000000, - .u.pll = { - .input_min = 2000000, - .input_max = 31000000, - .cf_min = 1000000, - .cf_max = 6000000, - .vco_min = 20000000, - .vco_max = 1700000000, - .freq_table = tegra_pll_x_freq_table, - .lock_delay = 300, - }, -}; - -static struct clk tegra_pll_x_out0 = { - .name = "pll_x_out0", - .ops = &tegra_pll_div_ops, - .flags = DIV_2 | PLLX, - .parent = &tegra_pll_x, - .max_rate = 850000000, -}; - - -static struct clk_pll_freq_table tegra_pll_e_freq_table[] = { - /* PLLE special case: use cpcon field to store cml divider value */ - { 12000000, 100000000, 150, 1, 18, 11}, - { 216000000, 100000000, 200, 18, 24, 13}, - { 0, 0, 0, 0, 0, 0 }, -}; - -static struct clk tegra_pll_e = { - .name = "pll_e", - .flags = PLL_ALT_MISC_REG, - .ops = &tegra_plle_ops, - .reg = 0xe8, - .max_rate = 100000000, - .u.pll = { - .input_min = 12000000, - .input_max = 216000000, - .cf_min = 12000000, - .cf_max = 12000000, - .vco_min = 1200000000, - .vco_max = 2400000000U, - .freq_table = tegra_pll_e_freq_table, - .lock_delay = 300, - .fixed_rate = 100000000, - }, -}; - -static struct clk tegra_cml0_clk = { - .name = "cml0", - .parent = &tegra_pll_e, - .ops = &tegra_cml_clk_ops, - .reg = PLLE_AUX, - .max_rate = 100000000, - .u.periph = { - .clk_num = 0, - }, -}; - -static struct clk tegra_cml1_clk = { - .name = "cml1", - .parent = &tegra_pll_e, - .ops = &tegra_cml_clk_ops, - .reg = PLLE_AUX, - .max_rate = 100000000, - .u.periph = { - .clk_num = 1, - }, -}; - -static struct clk tegra_pciex_clk = { - .name = "pciex", - .parent = &tegra_pll_e, - .ops = &tegra_pciex_clk_ops, - .max_rate = 100000000, - .u.periph = { - .clk_num = 74, - }, -}; - -/* Audio sync clocks */ -#define SYNC_SOURCE(_id) \ - { \ - .name = #_id "_sync", \ - .rate = 24000000, \ - .max_rate = 24000000, \ - .ops = &tegra_sync_source_ops \ - } -static struct clk tegra_sync_source_list[] = { - SYNC_SOURCE(spdif_in), - SYNC_SOURCE(i2s0), - SYNC_SOURCE(i2s1), - SYNC_SOURCE(i2s2), - SYNC_SOURCE(i2s3), - SYNC_SOURCE(i2s4), - SYNC_SOURCE(vimclk), -}; - -static struct clk_mux_sel mux_audio_sync_clk[] = { - { .input = &tegra_sync_source_list[0], .value = 0}, - { .input = &tegra_sync_source_list[1], .value = 1}, - { .input = &tegra_sync_source_list[2], .value = 2}, - { .input = &tegra_sync_source_list[3], .value = 3}, - { .input = &tegra_sync_source_list[4], .value = 4}, - { .input = &tegra_sync_source_list[5], .value = 5}, - { .input = &tegra_pll_a_out0, .value = 6}, - { .input = &tegra_sync_source_list[6], .value = 7}, - { 0, 0 } -}; - -#define AUDIO_SYNC_CLK(_id, _index) \ - { \ - .name = #_id, \ - .inputs = mux_audio_sync_clk, \ - .reg = 0x4A0 + (_index) * 4, \ - .max_rate = 24000000, \ - .ops = &tegra_audio_sync_clk_ops \ - } -static struct clk tegra_clk_audio_list[] = { - AUDIO_SYNC_CLK(audio0, 0), - AUDIO_SYNC_CLK(audio1, 1), - AUDIO_SYNC_CLK(audio2, 2), - AUDIO_SYNC_CLK(audio3, 3), - AUDIO_SYNC_CLK(audio4, 4), - AUDIO_SYNC_CLK(audio, 5), /* SPDIF */ -}; - -#define AUDIO_SYNC_2X_CLK(_id, _index) \ - { \ - .name = #_id "_2x", \ - .flags = PERIPH_NO_RESET, \ - .max_rate = 48000000, \ - .ops = &tegra_clk_double_ops, \ - .reg = 0x49C, \ - .reg_shift = 24 + (_index), \ - .parent = &tegra_clk_audio_list[(_index)], \ - .u.periph = { \ - .clk_num = 113 + (_index), \ - }, \ - } -static struct clk tegra_clk_audio_2x_list[] = { - AUDIO_SYNC_2X_CLK(audio0, 0), - AUDIO_SYNC_2X_CLK(audio1, 1), - AUDIO_SYNC_2X_CLK(audio2, 2), - AUDIO_SYNC_2X_CLK(audio3, 3), - AUDIO_SYNC_2X_CLK(audio4, 4), - AUDIO_SYNC_2X_CLK(audio, 5), /* SPDIF */ -}; - -#define MUX_I2S_SPDIF(_id, _index) \ -static struct clk_mux_sel mux_pllaout0_##_id##_2x_pllp_clkm[] = { \ - {.input = &tegra_pll_a_out0, .value = 0}, \ - {.input = &tegra_clk_audio_2x_list[(_index)], .value = 1}, \ - {.input = &tegra_pll_p, .value = 2}, \ - {.input = &tegra_clk_m, .value = 3}, \ - { 0, 0}, \ -} -MUX_I2S_SPDIF(audio0, 0); -MUX_I2S_SPDIF(audio1, 1); -MUX_I2S_SPDIF(audio2, 2); -MUX_I2S_SPDIF(audio3, 3); -MUX_I2S_SPDIF(audio4, 4); -MUX_I2S_SPDIF(audio, 5); /* SPDIF */ - -/* External clock outputs (through PMC) */ -#define MUX_EXTERN_OUT(_id) \ -static struct clk_mux_sel mux_clkm_clkm2_clkm4_extern##_id[] = { \ - {.input = &tegra_clk_m, .value = 0}, \ - {.input = &tegra_clk_m_div2, .value = 1}, \ - {.input = &tegra_clk_m_div4, .value = 2}, \ - {.input = NULL, .value = 3}, /* placeholder */ \ - { 0, 0}, \ -} -MUX_EXTERN_OUT(1); -MUX_EXTERN_OUT(2); -MUX_EXTERN_OUT(3); - -static struct clk_mux_sel *mux_extern_out_list[] = { - mux_clkm_clkm2_clkm4_extern1, - mux_clkm_clkm2_clkm4_extern2, - mux_clkm_clkm2_clkm4_extern3, -}; - -#define CLK_OUT_CLK(_id) \ - { \ - .name = "clk_out_" #_id, \ - .lookup = { \ - .dev_id = "clk_out_" #_id, \ - .con_id = "extern" #_id, \ - }, \ - .ops = &tegra_clk_out_ops, \ - .reg = 0x1a8, \ - .inputs = mux_clkm_clkm2_clkm4_extern##_id, \ - .flags = MUX_CLK_OUT, \ - .max_rate = 216000000, \ - .u.periph = { \ - .clk_num = (_id - 1) * 8 + 2, \ - }, \ - } -static struct clk tegra_clk_out_list[] = { - CLK_OUT_CLK(1), - CLK_OUT_CLK(2), - CLK_OUT_CLK(3), -}; - -/* called after peripheral external clocks are initialized */ -static void init_clk_out_mux(void) -{ - int i; - struct clk *c; - - /* output clock con_id is the name of peripheral - external clock connected to input 3 of the output mux */ - for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++) { - c = tegra_get_clock_by_name( - tegra_clk_out_list[i].lookup.con_id); - if (!c) - pr_err("%s: could not find clk %s\n", __func__, - tegra_clk_out_list[i].lookup.con_id); - mux_extern_out_list[i][3].input = c; - } -} - -/* Peripheral muxes */ -static struct clk_mux_sel mux_sclk[] = { - { .input = &tegra_clk_m, .value = 0}, - { .input = &tegra_pll_c_out1, .value = 1}, - { .input = &tegra_pll_p_out4, .value = 2}, - { .input = &tegra_pll_p_out3, .value = 3}, - { .input = &tegra_pll_p_out2, .value = 4}, - /* { .input = &tegra_clk_d, .value = 5}, - no use on tegra30 */ - { .input = &tegra_clk_32k, .value = 6}, - { .input = &tegra_pll_m_out1, .value = 7}, - { 0, 0}, -}; - -static struct clk tegra_clk_sclk = { - .name = "sclk", - .inputs = mux_sclk, - .reg = 0x28, - .ops = &tegra_super_ops, - .max_rate = 334000000, - .min_rate = 40000000, -}; - -static struct clk tegra_clk_blink = { - .name = "blink", - .parent = &tegra_clk_32k, - .reg = 0x40, - .ops = &tegra_blink_clk_ops, - .max_rate = 32768, -}; - -static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = { - { .input = &tegra_pll_m, .value = 0}, - { .input = &tegra_pll_c, .value = 1}, - { .input = &tegra_pll_p, .value = 2}, - { .input = &tegra_pll_a_out0, .value = 3}, - { 0, 0}, -}; - -static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = { - { .input = &tegra_pll_p, .value = 0}, - { .input = &tegra_pll_c, .value = 1}, - { .input = &tegra_pll_m, .value = 2}, - { .input = &tegra_clk_m, .value = 3}, - { 0, 0}, -}; - -static struct clk_mux_sel mux_pllp_clkm[] = { - { .input = &tegra_pll_p, .value = 0}, - { .input = &tegra_clk_m, .value = 3}, - { 0, 0}, -}; - -static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = { - {.input = &tegra_pll_p, .value = 0}, - {.input = &tegra_pll_d_out0, .value = 1}, - {.input = &tegra_pll_c, .value = 2}, - {.input = &tegra_clk_m, .value = 3}, - { 0, 0}, -}; - -static struct clk_mux_sel mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = { - {.input = &tegra_pll_p, .value = 0}, - {.input = &tegra_pll_m, .value = 1}, - {.input = &tegra_pll_d_out0, .value = 2}, - {.input = &tegra_pll_a_out0, .value = 3}, - {.input = &tegra_pll_c, .value = 4}, - {.input = &tegra_pll_d2_out0, .value = 5}, - {.input = &tegra_clk_m, .value = 6}, - { 0, 0}, -}; - -static struct clk_mux_sel mux_plla_pllc_pllp_clkm[] = { - { .input = &tegra_pll_a_out0, .value = 0}, - /* { .input = &tegra_pll_c, .value = 1}, no use on tegra30 */ - { .input = &tegra_pll_p, .value = 2}, - { .input = &tegra_clk_m, .value = 3}, - { 0, 0}, -}; - -static struct clk_mux_sel mux_pllp_pllc_clk32_clkm[] = { - {.input = &tegra_pll_p, .value = 0}, - {.input = &tegra_pll_c, .value = 1}, - {.input = &tegra_clk_32k, .value = 2}, - {.input = &tegra_clk_m, .value = 3}, - { 0, 0}, -}; - -static struct clk_mux_sel mux_pllp_pllc_clkm_clk32[] = { - {.input = &tegra_pll_p, .value = 0}, - {.input = &tegra_pll_c, .value = 1}, - {.input = &tegra_clk_m, .value = 2}, - {.input = &tegra_clk_32k, .value = 3}, - { 0, 0}, -}; - -static struct clk_mux_sel mux_pllp_pllc_pllm[] = { - {.input = &tegra_pll_p, .value = 0}, - {.input = &tegra_pll_c, .value = 1}, - {.input = &tegra_pll_m, .value = 2}, - { 0, 0}, -}; - -static struct clk_mux_sel mux_clk_m[] = { - { .input = &tegra_clk_m, .value = 0}, - { 0, 0}, -}; - -static struct clk_mux_sel mux_pllp_out3[] = { - { .input = &tegra_pll_p_out3, .value = 0}, - { 0, 0}, -}; - -static struct clk_mux_sel mux_plld_out0[] = { - { .input = &tegra_pll_d_out0, .value = 0}, - { 0, 0}, -}; - -static struct clk_mux_sel mux_plld_out0_plld2_out0[] = { - { .input = &tegra_pll_d_out0, .value = 0}, - { .input = &tegra_pll_d2_out0, .value = 1}, - { 0, 0}, -}; - -static struct clk_mux_sel mux_clk_32k[] = { - { .input = &tegra_clk_32k, .value = 0}, - { 0, 0}, -}; - -static struct clk_mux_sel mux_plla_clk32_pllp_clkm_plle[] = { - { .input = &tegra_pll_a_out0, .value = 0}, - { .input = &tegra_clk_32k, .value = 1}, - { .input = &tegra_pll_p, .value = 2}, - { .input = &tegra_clk_m, .value = 3}, - { .input = &tegra_pll_e, .value = 4}, - { 0, 0}, -}; - -static struct clk_mux_sel mux_cclk_g[] = { - { .input = &tegra_clk_m, .value = 0}, - { .input = &tegra_pll_c, .value = 1}, - { .input = &tegra_clk_32k, .value = 2}, - { .input = &tegra_pll_m, .value = 3}, - { .input = &tegra_pll_p, .value = 4}, - { .input = &tegra_pll_p_out4, .value = 5}, - { .input = &tegra_pll_p_out3, .value = 6}, - { .input = &tegra_pll_x, .value = 8}, - { 0, 0}, -}; - -static struct clk tegra_clk_cclk_g = { - .name = "cclk_g", - .flags = DIV_U71 | DIV_U71_INT, - .inputs = mux_cclk_g, - .reg = 0x368, - .ops = &tegra_super_ops, - .max_rate = 1700000000, -}; - -static struct clk tegra30_clk_twd = { - .parent = &tegra_clk_cclk_g, - .name = "twd", - .ops = &tegra30_twd_ops, - .max_rate = 1400000000, /* Same as tegra_clk_cpu_cmplx.max_rate */ - .mul = 1, - .div = 2, -}; - -#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \ - { \ - .name = _name, \ - .lookup = { \ - .dev_id = _dev, \ - .con_id = _con, \ - }, \ - .ops = &tegra_periph_clk_ops, \ - .reg = _reg, \ - .inputs = _inputs, \ - .flags = _flags, \ - .max_rate = _max, \ - .u.periph = { \ - .clk_num = _clk_num, \ - }, \ - } - -#define PERIPH_CLK_EX(_name, _dev, _con, _clk_num, _reg, _max, _inputs, \ - _flags, _ops) \ - { \ - .name = _name, \ - .lookup = { \ - .dev_id = _dev, \ - .con_id = _con, \ - }, \ - .ops = _ops, \ - .reg = _reg, \ - .inputs = _inputs, \ - .flags = _flags, \ - .max_rate = _max, \ - .u.periph = { \ - .clk_num = _clk_num, \ - }, \ - } - -#define SHARED_CLK(_name, _dev, _con, _parent, _id, _div, _mode)\ - { \ - .name = _name, \ - .lookup = { \ - .dev_id = _dev, \ - .con_id = _con, \ - }, \ - .ops = &tegra_clk_shared_bus_ops, \ - .parent = _parent, \ - .u.shared_bus_user = { \ - .client_id = _id, \ - .client_div = _div, \ - .mode = _mode, \ - }, \ - } -struct clk tegra_list_clks[] = { - PERIPH_CLK("apbdma", "tegra-apbdma", NULL, 34, 0, 26000000, mux_clk_m, 0), - PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB), - PERIPH_CLK("kbc", "tegra-kbc", NULL, 36, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB), - PERIPH_CLK("timer", "timer", NULL, 5, 0, 26000000, mux_clk_m, 0), - PERIPH_CLK("kfuse", "kfuse-tegra", NULL, 40, 0, 26000000, mux_clk_m, 0), - PERIPH_CLK("fuse", "fuse-tegra", "fuse", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB), - PERIPH_CLK("fuse_burn", "fuse-tegra", "fuse_burn", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB), - PERIPH_CLK("apbif", "tegra30-ahub", "apbif", 107, 0, 26000000, mux_clk_m, 0), - PERIPH_CLK("i2s0", "tegra30-i2s.0", NULL, 30, 0x1d8, 26000000, mux_pllaout0_audio0_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("i2s1", "tegra30-i2s.1", NULL, 11, 0x100, 26000000, mux_pllaout0_audio1_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("i2s2", "tegra30-i2s.2", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("i2s3", "tegra30-i2s.3", NULL, 101, 0x3bc, 26000000, mux_pllaout0_audio3_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("i2s4", "tegra30-i2s.4", NULL, 102, 0x3c0, 26000000, mux_pllaout0_audio4_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("spdif_out", "tegra30-spdif", "spdif_out", 10, 0x108, 100000000, mux_pllaout0_audio_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("spdif_in", "tegra30-spdif", "spdif_in", 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("pwm", "tegra-pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_clk32_clkm, MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("d_audio", "tegra30-ahub", "d_audio", 106, 0x3d0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71), - PERIPH_CLK("dam0", "tegra30-dam.0", NULL, 108, 0x3d8, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71), - PERIPH_CLK("dam1", "tegra30-dam.1", NULL, 109, 0x3dc, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71), - PERIPH_CLK("dam2", "tegra30-dam.2", NULL, 110, 0x3e0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71), - PERIPH_CLK("hda", "tegra30-hda", "hda", 125, 0x428, 108000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("hda2codec_2x", "tegra30-hda", "hda2codec", 111, 0x3e4, 48000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("hda2hdmi", "tegra30-hda", "hda2hdmi", 128, 0, 48000000, mux_clk_m, 0), - PERIPH_CLK("sbc1", "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("sbc2", "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("sbc3", "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("sbc4", "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("sbc5", "spi_tegra.4", NULL, 104, 0x3c8, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("sbc6", "spi_tegra.5", NULL, 105, 0x3cc, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("sata_oob", "tegra_sata_oob", NULL, 123, 0x420, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("sata", "tegra_sata", NULL, 124, 0x424, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("sata_cold", "tegra_sata_cold", NULL, 129, 0, 48000000, mux_clk_m, 0), - PERIPH_CLK_EX("ndflash", "tegra_nand", NULL, 13, 0x160, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71, &tegra_nand_clk_ops), - PERIPH_CLK("ndspeed", "tegra_nand_speed", NULL, 80, 0x3f8, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("vfir", "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("sdmmc1", "sdhci-tegra.0", NULL, 14, 0x150, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */ - PERIPH_CLK("sdmmc2", "sdhci-tegra.1", NULL, 9, 0x154, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */ - PERIPH_CLK("sdmmc3", "sdhci-tegra.2", NULL, 69, 0x1bc, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */ - PERIPH_CLK("sdmmc4", "sdhci-tegra.3", NULL, 15, 0x164, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */ - PERIPH_CLK("vcp", "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0), - PERIPH_CLK("bsea", "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0), - PERIPH_CLK("bsev", "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0), - PERIPH_CLK("vde", "vde", NULL, 61, 0x1c8, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT), - PERIPH_CLK("csite", "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* max rate ??? */ - PERIPH_CLK("la", "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("owr", "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("nor", "nor", NULL, 42, 0x1d0, 127000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* requires min voltage */ - PERIPH_CLK("mipi", "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB), /* scales with voltage */ - PERIPH_CLK("i2c1", "tegra-i2c.0", NULL, 12, 0x124, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB), - PERIPH_CLK("i2c2", "tegra-i2c.1", NULL, 54, 0x198, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB), - PERIPH_CLK("i2c3", "tegra-i2c.2", NULL, 67, 0x1b8, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB), - PERIPH_CLK("i2c4", "tegra-i2c.3", NULL, 103, 0x3c4, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB), - PERIPH_CLK("i2c5", "tegra-i2c.4", NULL, 47, 0x128, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB), - PERIPH_CLK("uarta", "tegra-uart.0", NULL, 6, 0x178, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uartb", "tegra-uart.1", NULL, 7, 0x17c, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uartc", "tegra-uart.2", NULL, 55, 0x1a0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uartd", "tegra-uart.3", NULL, 65, 0x1c0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uarte", "tegra-uart.4", NULL, 66, 0x1c4, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK_EX("vi", "tegra_camera", "vi", 20, 0x148, 425000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT, &tegra_vi_clk_ops), - PERIPH_CLK("3d", "3d", NULL, 24, 0x158, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET), - PERIPH_CLK("3d2", "3d2", NULL, 98, 0x3b0, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET), - PERIPH_CLK("2d", "2d", NULL, 21, 0x15c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE), - PERIPH_CLK("vi_sensor", "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET), - PERIPH_CLK("epp", "epp", NULL, 19, 0x16c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT), - PERIPH_CLK("mpe", "mpe", NULL, 60, 0x170, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT), - PERIPH_CLK("host1x", "host1x", NULL, 28, 0x180, 260000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT), - PERIPH_CLK("cve", "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */ - PERIPH_CLK("tvo", "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */ - PERIPH_CLK_EX("dtv", "dtv", NULL, 79, 0x1dc, 250000000, mux_clk_m, 0, &tegra_dtv_clk_ops), - PERIPH_CLK("hdmi", "hdmi", NULL, 51, 0x18c, 148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8 | DIV_U71), - PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, 220000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */ - PERIPH_CLK("disp1", "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8), - PERIPH_CLK("disp2", "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8), - 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("dsia", "tegradc.0", "dsia", 48, 0, 500000000, mux_plld_out0, 0), - PERIPH_CLK_EX("dsib", "tegradc.1", "dsib", 82, 0xd0, 500000000, mux_plld_out0_plld2_out0, MUX | PLLD, &tegra_dsib_clk_ops), - PERIPH_CLK("csi", "tegra_camera", "csi", 52, 0, 102000000, 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), - - PERIPH_CLK("tsensor", "tegra-tsensor", NULL, 100, 0x3b8, 216000000, mux_pllp_pllc_clkm_clk32, MUX | DIV_U71), - PERIPH_CLK("actmon", "actmon", NULL, 119, 0x3e8, 216000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71), - PERIPH_CLK("extern1", "extern1", NULL, 120, 0x3ec, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71), - PERIPH_CLK("extern2", "extern2", NULL, 121, 0x3f0, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71), - PERIPH_CLK("extern3", "extern3", NULL, 122, 0x3f4, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71), - PERIPH_CLK("i2cslow", "i2cslow", NULL, 81, 0x3fc, 26000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71 | PERIPH_ON_APB), - PERIPH_CLK("pcie", "tegra-pcie", "pcie", 70, 0, 250000000, mux_clk_m, 0), - PERIPH_CLK("afi", "tegra-pcie", "afi", 72, 0, 250000000, mux_clk_m, 0), - PERIPH_CLK("se", "se", NULL, 127, 0x42c, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT), -}; - -#define CLK_DUPLICATE(_name, _dev, _con) \ - { \ - .name = _name, \ - .lookup = { \ - .dev_id = _dev, \ - .con_id = _con, \ - }, \ - } - -/* Some clocks may be used by different drivers depending on the board - * configuration. List those here to register them twice in the clock lookup - * table under two names. - */ -struct clk_duplicate tegra_clk_duplicates[] = { - CLK_DUPLICATE("uarta", "serial8250.0", NULL), - CLK_DUPLICATE("uartb", "serial8250.1", NULL), - CLK_DUPLICATE("uartc", "serial8250.2", NULL), - CLK_DUPLICATE("uartd", "serial8250.3", NULL), - CLK_DUPLICATE("uarte", "serial8250.4", NULL), - CLK_DUPLICATE("usbd", "utmip-pad", NULL), - CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL), - CLK_DUPLICATE("usbd", "tegra-otg", NULL), - CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"), - CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"), - CLK_DUPLICATE("dsib", "tegradc.0", "dsib"), - CLK_DUPLICATE("dsia", "tegradc.1", "dsia"), - CLK_DUPLICATE("bsev", "tegra-avp", "bsev"), - CLK_DUPLICATE("bsev", "nvavp", "bsev"), - CLK_DUPLICATE("vde", "tegra-aes", "vde"), - CLK_DUPLICATE("bsea", "tegra-aes", "bsea"), - CLK_DUPLICATE("bsea", "nvavp", "bsea"), - CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL), - CLK_DUPLICATE("cml0", "tegra_pcie", "cml"), - CLK_DUPLICATE("pciex", "tegra_pcie", "pciex"), - CLK_DUPLICATE("i2c1", "tegra-i2c-slave.0", NULL), - CLK_DUPLICATE("i2c2", "tegra-i2c-slave.1", NULL), - CLK_DUPLICATE("i2c3", "tegra-i2c-slave.2", NULL), - CLK_DUPLICATE("i2c4", "tegra-i2c-slave.3", NULL), - CLK_DUPLICATE("i2c5", "tegra-i2c-slave.4", NULL), - CLK_DUPLICATE("sbc1", "spi_slave_tegra.0", NULL), - CLK_DUPLICATE("sbc2", "spi_slave_tegra.1", NULL), - CLK_DUPLICATE("sbc3", "spi_slave_tegra.2", NULL), - CLK_DUPLICATE("sbc4", "spi_slave_tegra.3", NULL), - CLK_DUPLICATE("sbc5", "spi_slave_tegra.4", NULL), - CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL), - CLK_DUPLICATE("twd", "smp_twd", NULL), - CLK_DUPLICATE("vcp", "nvavp", "vcp"), - CLK_DUPLICATE("i2s0", NULL, "i2s0"), - CLK_DUPLICATE("i2s1", NULL, "i2s1"), - CLK_DUPLICATE("i2s2", NULL, "i2s2"), - CLK_DUPLICATE("i2s3", NULL, "i2s3"), - CLK_DUPLICATE("i2s4", NULL, "i2s4"), - CLK_DUPLICATE("dam0", NULL, "dam0"), - CLK_DUPLICATE("dam1", NULL, "dam1"), - CLK_DUPLICATE("dam2", NULL, "dam2"), - CLK_DUPLICATE("spdif_in", NULL, "spdif_in"), -}; - -struct clk *tegra_ptr_clks[] = { - &tegra_clk_32k, - &tegra_clk_m, - &tegra_clk_m_div2, - &tegra_clk_m_div4, - &tegra_pll_ref, - &tegra_pll_m, - &tegra_pll_m_out1, - &tegra_pll_c, - &tegra_pll_c_out1, - &tegra_pll_p, - &tegra_pll_p_out1, - &tegra_pll_p_out2, - &tegra_pll_p_out3, - &tegra_pll_p_out4, - &tegra_pll_a, - &tegra_pll_a_out0, - &tegra_pll_d, - &tegra_pll_d_out0, - &tegra_pll_d2, - &tegra_pll_d2_out0, - &tegra_pll_u, - &tegra_pll_x, - &tegra_pll_x_out0, - &tegra_pll_e, - &tegra_clk_cclk_g, - &tegra_cml0_clk, - &tegra_cml1_clk, - &tegra_pciex_clk, - &tegra_clk_sclk, - &tegra_clk_blink, - &tegra30_clk_twd, -}; - - -static void tegra30_init_one_clock(struct clk *c) -{ - clk_init(c); - INIT_LIST_HEAD(&c->shared_bus_list); - if (!c->lookup.dev_id && !c->lookup.con_id) - c->lookup.con_id = c->name; - c->lookup.clk = c; - clkdev_add(&c->lookup); -} - -void __init tegra30_init_clocks(void) -{ - int i; - struct clk *c; - - for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++) - tegra30_init_one_clock(tegra_ptr_clks[i]); - - for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++) - tegra30_init_one_clock(&tegra_list_clks[i]); - - for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) { - c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name); - if (!c) { - pr_err("%s: Unknown duplicate clock %s\n", __func__, - tegra_clk_duplicates[i].name); - continue; - } - - tegra_clk_duplicates[i].lookup.clk = c; - clkdev_add(&tegra_clk_duplicates[i].lookup); - } - - for (i = 0; i < ARRAY_SIZE(tegra_sync_source_list); i++) - tegra30_init_one_clock(&tegra_sync_source_list[i]); - for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_list); i++) - tegra30_init_one_clock(&tegra_clk_audio_list[i]); - for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_2x_list); i++) - tegra30_init_one_clock(&tegra_clk_audio_2x_list[i]); - - init_clk_out_mux(); - for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++) - tegra30_init_one_clock(&tegra_clk_out_list[i]); - -} -- cgit v1.2.1 From 92fe58f07f6e51185497785aed632d0e676afe6e Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Mon, 6 Aug 2012 11:57:43 +0530 Subject: ARM: tegra: Port tegra to generic clock framework This patch converts tegra clock code to generic clock framework in following way: - Implement clk_ops as required by generic clk framework. (tegraXX_clocks.c) - Use platform specific struct clk_tegra in clk_ops implementation instead of struct clk. - Initialize all clock data statically. (tegraXX_clocks_data.c) Legacy framework did not have recalc_rate and is_enabled functions. Implemented these functions. Removed init function. It's functionality is splitted into recalc_rate and is_enabled. Static initialization is used since slab is not up in .init_early and clock is needed to be initialized before clockevent/clocksource initialization. Macros redefined for clk_tegra. Also, single struct clk_tegra is used for all type of clocks (PLL, peripheral etc.). This is to move quickly to generic common clock framework so that other dependent features will not be blocked (such as DT binding). Enabling COMMON_CLOCK config moved to ARCH_TEGRA since it is enabled for both Tegra20 and Tegra30. Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/tegra30_clocks.c | 1416 ++++++++++++++++++++-------------- 1 file changed, 823 insertions(+), 593 deletions(-) (limited to 'arch/arm/mach-tegra/tegra30_clocks.c') diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c index 645ef6900a0e..a9fa8ea0b6e0 100644 --- a/arch/arm/mach-tegra/tegra30_clocks.c +++ b/arch/arm/mach-tegra/tegra30_clocks.c @@ -381,14 +381,16 @@ static int tegra_periph_clk_enable_refcount[CLK_OUT_ENB_NUM * 32]; udelay(2); \ } while (0) - -static inline int clk_set_div(struct clk *c, u32 n) +static inline int clk_set_div(struct clk_tegra *c, u32 n) { - return clk_set_rate(c, (clk_get_rate(c->parent) + n-1) / n); + struct clk *clk = c->hw.clk; + + return clk_set_rate(clk, + (__clk_get_rate(__clk_get_parent(clk)) + n - 1) / n); } static inline u32 periph_clk_to_reg( - struct clk *c, u32 reg_L, u32 reg_V, int offs) + struct clk_tegra *c, u32 reg_L, u32 reg_V, int offs) { u32 reg = c->u.periph.clk_num / 32; BUG_ON(reg >= RST_DEVICES_NUM); @@ -470,15 +472,32 @@ static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate) return divider_u16 - 1; } +static unsigned long tegra30_clk_fixed_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return to_clk_tegra(hw)->fixed_rate; +} + +struct clk_ops tegra_clk_32k_ops = { + .recalc_rate = tegra30_clk_fixed_recalc_rate, +}; + /* clk_m functions */ -static unsigned long tegra30_clk_m_autodetect_rate(struct clk *c) +static unsigned long tegra30_clk_m_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + if (!to_clk_tegra(hw)->fixed_rate) + to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq(); + return to_clk_tegra(hw)->fixed_rate; +} + +static void tegra30_clk_m_init(struct clk_hw *hw) { u32 osc_ctrl = clk_readl(OSC_CTRL); u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK; u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK; - c->rate = clk_measure_input_freq(); - switch (c->rate) { + switch (to_clk_tegra(hw)->fixed_rate) { case 12000000: auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ; BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); @@ -508,46 +527,44 @@ static unsigned long tegra30_clk_m_autodetect_rate(struct clk *c) BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4); break; default: - pr_err("%s: Unexpected clock rate %ld", __func__, c->rate); + pr_err("%s: Unexpected clock rate %ld", __func__, + to_clk_tegra(hw)->fixed_rate); BUG(); } clk_writel(auto_clock_control, OSC_CTRL); - return c->rate; } -static void tegra30_clk_m_init(struct clk *c) -{ - pr_debug("%s on clock %s\n", __func__, c->name); - tegra30_clk_m_autodetect_rate(c); -} +struct clk_ops tegra30_clk_m_ops = { + .init = tegra30_clk_m_init, + .recalc_rate = tegra30_clk_m_recalc_rate, +}; -static int tegra30_clk_m_enable(struct clk *c) +static unsigned long tegra30_clk_m_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) { - pr_debug("%s on clock %s\n", __func__, c->name); - return 0; -} + struct clk_tegra *c = to_clk_tegra(hw); + u64 rate = parent_rate; -static void tegra30_clk_m_disable(struct clk *c) -{ - pr_debug("%s on clock %s\n", __func__, c->name); - WARN(1, "Attempting to disable main SoC clock\n"); -} + if (c->mul != 0 && c->div != 0) { + rate *= c->mul; + rate += c->div - 1; /* round up */ + do_div(rate, c->div); + } -struct clk_ops tegra30_clk_m_ops = { - .init = tegra30_clk_m_init, - .enable = tegra30_clk_m_enable, - .disable = tegra30_clk_m_disable, -}; + return rate; +} struct clk_ops tegra_clk_m_div_ops = { - .enable = tegra30_clk_m_enable, + .recalc_rate = tegra30_clk_m_div_recalc_rate, }; /* PLL reference divider functions */ -static void tegra30_pll_ref_init(struct clk *c) +static unsigned long tegra30_pll_ref_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) { + struct clk_tegra *c = to_clk_tegra(hw); + unsigned long rate = parent_rate; u32 pll_ref_div = clk_readl(OSC_CTRL) & OSC_CTRL_PLL_REF_DIV_MASK; - pr_debug("%s on clock %s\n", __func__, c->name); switch (pll_ref_div) { case OSC_CTRL_PLL_REF_DIV_1: @@ -564,13 +581,18 @@ static void tegra30_pll_ref_init(struct clk *c) BUG(); } c->mul = 1; - c->state = ON; + + if (c->mul != 0 && c->div != 0) { + rate *= c->mul; + rate += c->div - 1; /* round up */ + do_div(rate, c->div); + } + + return rate; } struct clk_ops tegra_pll_ref_ops = { - .init = tegra30_pll_ref_init, - .enable = tegra30_clk_m_enable, - .disable = tegra30_clk_m_disable, + .recalc_rate = tegra30_pll_ref_recalc_rate, }; /* super clock functions */ @@ -581,56 +603,50 @@ struct clk_ops tegra_pll_ref_ops = { * only when its parent is a fixed rate PLL, since we can't change PLL rate * in this case. */ -static void tegra30_super_clk_init(struct clk *c) +static void tegra30_super_clk_init(struct clk_hw *hw) { - u32 val; - int source; - int shift; - const struct clk_mux_sel *sel; - val = clk_readl(c->reg + SUPER_CLK_MUX); - c->state = ON; - BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) && - ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE)); - shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ? - SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT; - source = (val >> shift) & SUPER_SOURCE_MASK; - if (c->flags & DIV_2) - source |= val & SUPER_LP_DIV2_BYPASS; - for (sel = c->inputs; sel->input != NULL; sel++) { - if (sel->value == source) - break; - } - BUG_ON(sel->input == NULL); - c->parent = sel->input; + struct clk_tegra *c = to_clk_tegra(hw); + struct clk_tegra *p = + to_clk_tegra(__clk_get_hw(__clk_get_parent(hw->clk))); + c->state = ON; if (c->flags & DIV_U71) { /* Init safe 7.1 divider value (does not affect PLLX path) */ clk_writel(SUPER_CLOCK_DIV_U71_MIN << SUPER_CLOCK_DIV_U71_SHIFT, c->reg + SUPER_CLK_DIVIDER); c->mul = 2; c->div = 2; - if (!(c->parent->flags & PLLX)) + if (!(p->flags & PLLX)) c->div += SUPER_CLOCK_DIV_U71_MIN; } else clk_writel(0, c->reg + SUPER_CLK_DIVIDER); } -static int tegra30_super_clk_enable(struct clk *c) +static u8 tegra30_super_clk_get_parent(struct clk_hw *hw) { - return 0; -} + struct clk_tegra *c = to_clk_tegra(hw); + u32 val; + int source; + int shift; -static void tegra30_super_clk_disable(struct clk *c) -{ - /* since tegra 3 has 2 CPU super clocks - low power lp-mode clock and - geared up g-mode super clock - mode switch may request to disable - either of them; accept request with no affect on h/w */ + val = clk_readl(c->reg + SUPER_CLK_MUX); + BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) && + ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE)); + shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ? + SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT; + source = (val >> shift) & SUPER_SOURCE_MASK; + if (c->flags & DIV_2) + source |= val & SUPER_LP_DIV2_BYPASS; + + return source; } -static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p) +static int tegra30_super_clk_set_parent(struct clk_hw *hw, u8 index) { + struct clk_tegra *c = to_clk_tegra(hw); + struct clk_tegra *p = + to_clk_tegra(__clk_get_hw(clk_get_parent(hw->clk))); u32 val; - const struct clk_mux_sel *sel; int shift; val = clk_readl(c->reg + SUPER_CLK_MUX); @@ -638,48 +654,36 @@ static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p) ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE)); shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ? SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT; - for (sel = c->inputs; sel->input != NULL; sel++) { - if (sel->input == p) { - /* For LP mode super-clock switch between PLLX direct - and divided-by-2 outputs is allowed only when other - than PLLX clock source is current parent */ - if ((c->flags & DIV_2) && (p->flags & PLLX) && - ((sel->value ^ val) & SUPER_LP_DIV2_BYPASS)) { - if (c->parent->flags & PLLX) - return -EINVAL; - val ^= SUPER_LP_DIV2_BYPASS; - clk_writel_delay(val, c->reg); - } - val &= ~(SUPER_SOURCE_MASK << shift); - val |= (sel->value & SUPER_SOURCE_MASK) << shift; - - /* 7.1 divider for CPU super-clock does not affect - PLLX path */ - if (c->flags & DIV_U71) { - u32 div = 0; - if (!(p->flags & PLLX)) { - div = clk_readl(c->reg + - SUPER_CLK_DIVIDER); - div &= SUPER_CLOCK_DIV_U71_MASK; - div >>= SUPER_CLOCK_DIV_U71_SHIFT; - } - c->div = div + 2; - c->mul = 2; - } - - if (c->refcnt) - clk_enable(p); - - clk_writel_delay(val, c->reg); - if (c->refcnt && c->parent) - clk_disable(c->parent); + /* For LP mode super-clock switch between PLLX direct + and divided-by-2 outputs is allowed only when other + than PLLX clock source is current parent */ + if ((c->flags & DIV_2) && (p->flags & PLLX) && + ((index ^ val) & SUPER_LP_DIV2_BYPASS)) { + if (p->flags & PLLX) + return -EINVAL; + val ^= SUPER_LP_DIV2_BYPASS; + clk_writel_delay(val, c->reg); + } + val &= ~(SUPER_SOURCE_MASK << shift); + val |= (index & SUPER_SOURCE_MASK) << shift; - clk_reparent(c, p); - return 0; + /* 7.1 divider for CPU super-clock does not affect + PLLX path */ + if (c->flags & DIV_U71) { + u32 div = 0; + if (!(p->flags & PLLX)) { + div = clk_readl(c->reg + + SUPER_CLK_DIVIDER); + div &= SUPER_CLOCK_DIV_U71_MASK; + div >>= SUPER_CLOCK_DIV_U71_SHIFT; } + c->div = div + 2; + c->mul = 2; } - return -EINVAL; + clk_writel_delay(val, c->reg); + + return 0; } /* @@ -691,10 +695,15 @@ static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p) * rate of this PLL can't be changed, and it has many other children. In * this case use 7.1 fractional divider to adjust the super clock rate. */ -static int tegra30_super_clk_set_rate(struct clk *c, unsigned long rate) +static int tegra30_super_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { - if ((c->flags & DIV_U71) && (c->parent->flags & PLL_FIXED)) { - int div = clk_div71_get_divider(c->parent->u.pll.fixed_rate, + struct clk_tegra *c = to_clk_tegra(hw); + struct clk *parent = __clk_get_parent(hw->clk); + struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent)); + + if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) { + int div = clk_div71_get_divider(parent_rate, rate, c->flags, ROUND_DIVIDER_DOWN); div = max(div, SUPER_CLOCK_DIV_U71_MIN); @@ -704,55 +713,86 @@ static int tegra30_super_clk_set_rate(struct clk *c, unsigned long rate) c->mul = 2; return 0; } - return clk_set_rate(c->parent, rate); + return 0; +} + +static unsigned long tegra30_super_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_tegra *c = to_clk_tegra(hw); + u64 rate = parent_rate; + + if (c->mul != 0 && c->div != 0) { + rate *= c->mul; + rate += c->div - 1; /* round up */ + do_div(rate, c->div); + } + + return rate; +} + +static long tegra30_super_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_tegra *c = to_clk_tegra(hw); + struct clk *parent = __clk_get_parent(hw->clk); + struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent)); + int mul = 2; + int div; + + if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) { + div = clk_div71_get_divider(*prate, + rate, c->flags, ROUND_DIVIDER_DOWN); + div = max(div, SUPER_CLOCK_DIV_U71_MIN) + 2; + rate = *prate * mul; + rate += div - 1; /* round up */ + do_div(rate, c->div); + + return rate; + } + return *prate; } struct clk_ops tegra30_super_ops = { - .init = tegra30_super_clk_init, - .enable = tegra30_super_clk_enable, - .disable = tegra30_super_clk_disable, - .set_parent = tegra30_super_clk_set_parent, - .set_rate = tegra30_super_clk_set_rate, + .init = tegra30_super_clk_init, + .set_parent = tegra30_super_clk_set_parent, + .get_parent = tegra30_super_clk_get_parent, + .recalc_rate = tegra30_super_clk_recalc_rate, + .round_rate = tegra30_super_clk_round_rate, + .set_rate = tegra30_super_clk_set_rate, }; -static int tegra30_twd_clk_set_rate(struct clk *c, unsigned long rate) +static unsigned long tegra30_twd_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) { - /* The input value 'rate' is the clock rate of the CPU complex. */ - c->rate = (rate * c->mul) / c->div; - return 0; + struct clk_tegra *c = to_clk_tegra(hw); + u64 rate = parent_rate; + + if (c->mul != 0 && c->div != 0) { + rate *= c->mul; + rate += c->div - 1; /* round up */ + do_div(rate, c->div); + } + + return rate; } struct clk_ops tegra30_twd_ops = { - .set_rate = tegra30_twd_clk_set_rate, + .recalc_rate = tegra30_twd_clk_recalc_rate, }; /* Blink output functions */ - -static void tegra30_blink_clk_init(struct clk *c) +static int tegra30_blink_clk_is_enabled(struct clk_hw *hw) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val; val = pmc_readl(PMC_CTRL); c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF; - c->mul = 1; - val = pmc_readl(c->reg); - - if (val & PMC_BLINK_TIMER_ENB) { - unsigned int on_off; - - on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) & - PMC_BLINK_TIMER_DATA_ON_MASK; - val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT; - val &= PMC_BLINK_TIMER_DATA_OFF_MASK; - on_off += val; - /* each tick in the blink timer is 4 32KHz clocks */ - c->div = on_off * 4; - } else { - c->div = 1; - } + return c->state; } -static int tegra30_blink_clk_enable(struct clk *c) +static int tegra30_blink_clk_enable(struct clk_hw *hw) { u32 val; @@ -765,7 +805,7 @@ static int tegra30_blink_clk_enable(struct clk *c) return 0; } -static void tegra30_blink_clk_disable(struct clk *c) +static void tegra30_blink_clk_disable(struct clk_hw *hw) { u32 val; @@ -776,9 +816,11 @@ static void tegra30_blink_clk_disable(struct clk *c) pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE); } -static int tegra30_blink_clk_set_rate(struct clk *c, unsigned long rate) +static int tegra30_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { - unsigned long parent_rate = clk_get_rate(c->parent); + struct clk_tegra *c = to_clk_tegra(hw); + if (rate >= parent_rate) { c->div = 1; pmc_writel(0, c->reg); @@ -801,40 +843,77 @@ static int tegra30_blink_clk_set_rate(struct clk *c, unsigned long rate) return 0; } -struct clk_ops tegra30_blink_clk_ops = { - .init = &tegra30_blink_clk_init, - .enable = &tegra30_blink_clk_enable, - .disable = &tegra30_blink_clk_disable, - .set_rate = &tegra30_blink_clk_set_rate, -}; +static unsigned long tegra30_blink_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_tegra *c = to_clk_tegra(hw); + u64 rate = parent_rate; + u32 val; + u32 mul; + u32 div; + u32 on_off; -/* PLL Functions */ -static int tegra30_pll_clk_wait_for_lock(struct clk *c, u32 lock_reg, - u32 lock_bit) + mul = 1; + val = pmc_readl(c->reg); + + if (val & PMC_BLINK_TIMER_ENB) { + on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) & + PMC_BLINK_TIMER_DATA_ON_MASK; + val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT; + val &= PMC_BLINK_TIMER_DATA_OFF_MASK; + on_off += val; + /* each tick in the blink timer is 4 32KHz clocks */ + div = on_off * 4; + } else { + div = 1; + } + + if (mul != 0 && div != 0) { + rate *= mul; + rate += div - 1; /* round up */ + do_div(rate, div); + } + return rate; +} + +static long tegra30_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) { -#if USE_PLL_LOCK_BITS - int i; - for (i = 0; i < c->u.pll.lock_delay; i++) { - if (clk_readl(lock_reg) & lock_bit) { - udelay(PLL_POST_LOCK_DELAY); - return 0; - } - udelay(2); /* timeout = 2 * lock time */ + int div; + int mul; + long round_rate = *prate; + + mul = 1; + + if (rate >= *prate) { + div = 1; + } else { + div = DIV_ROUND_UP(*prate / 8, rate); + div *= 8; } - pr_err("Timed out waiting for lock bit on pll %s", c->name); - return -1; -#endif - udelay(c->u.pll.lock_delay); - return 0; + round_rate *= mul; + round_rate += div - 1; + do_div(round_rate, div); + + return round_rate; } -static void tegra30_utmi_param_configure(struct clk *c) +struct clk_ops tegra30_blink_clk_ops = { + .is_enabled = tegra30_blink_clk_is_enabled, + .enable = tegra30_blink_clk_enable, + .disable = tegra30_blink_clk_disable, + .recalc_rate = tegra30_blink_clk_recalc_rate, + .round_rate = tegra30_blink_clk_round_rate, + .set_rate = tegra30_blink_clk_set_rate, +}; + +static void tegra30_utmi_param_configure(struct clk_hw *hw) { + unsigned long main_rate = + __clk_get_rate(__clk_get_parent(__clk_get_parent(hw->clk))); u32 reg; int i; - unsigned long main_rate = - clk_get_rate(c->parent->parent); for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) { if (main_rate == utmi_parameters[i].osc_frequency) @@ -885,50 +964,52 @@ static void tegra30_utmi_param_configure(struct clk *c) clk_writel(reg, UTMIP_PLL_CFG1); } -static void tegra30_pll_clk_init(struct clk *c) +/* PLL Functions */ +static int tegra30_pll_clk_wait_for_lock(struct clk_tegra *c, u32 lock_reg, + u32 lock_bit) +{ + int ret = 0; + +#if USE_PLL_LOCK_BITS + int i; + for (i = 0; i < c->u.pll.lock_delay; i++) { + if (clk_readl(lock_reg) & lock_bit) { + udelay(PLL_POST_LOCK_DELAY); + return 0; + } + udelay(2); /* timeout = 2 * lock time */ + } + pr_err("Timed out waiting for lock bit on pll %s", + __clk_get_name(hw->clk)); + ret = -1; +#else + udelay(c->u.pll.lock_delay); +#endif + return ret; +} + +static int tegra30_pll_clk_is_enabled(struct clk_hw *hw) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val = clk_readl(c->reg + PLL_BASE); c->state = (val & PLL_BASE_ENABLE) ? ON : OFF; + return c->state; +} - if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) { - const struct clk_pll_freq_table *sel; - unsigned long input_rate = clk_get_rate(c->parent); - for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { - if (sel->input_rate == input_rate && - sel->output_rate == c->u.pll.fixed_rate) { - c->mul = sel->n; - c->div = sel->m * sel->p; - return; - } - } - pr_err("Clock %s has unknown fixed frequency\n", c->name); - BUG(); - } else if (val & PLL_BASE_BYPASS) { - c->mul = 1; - c->div = 1; - } else { - c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT; - c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT; - if (c->flags & PLLU) - c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2; - else - c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >> - PLL_BASE_DIVP_SHIFT)); - if (c->flags & PLL_FIXED) { - unsigned long rate = clk_get_rate_locked(c); - BUG_ON(rate != c->u.pll.fixed_rate); - } - } +static void tegra30_pll_clk_init(struct clk_hw *hw) +{ + struct clk_tegra *c = to_clk_tegra(hw); if (c->flags & PLLU) - tegra30_utmi_param_configure(c); + tegra30_utmi_param_configure(hw); } -static int tegra30_pll_clk_enable(struct clk *c) +static int tegra30_pll_clk_enable(struct clk_hw *hw) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val; - pr_debug("%s on clock %s\n", __func__, c->name); + pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); #if USE_PLL_LOCK_BITS val = clk_readl(c->reg + PLL_MISC(c)); @@ -951,10 +1032,11 @@ static int tegra30_pll_clk_enable(struct clk *c) return 0; } -static void tegra30_pll_clk_disable(struct clk *c) +static void tegra30_pll_clk_disable(struct clk_hw *hw) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val; - pr_debug("%s on clock %s\n", __func__, c->name); + pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk)); val = clk_readl(c->reg); val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); @@ -967,36 +1049,36 @@ static void tegra30_pll_clk_disable(struct clk *c) } } -static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate) +static int tegra30_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val, p_div, old_base; unsigned long input_rate; const struct clk_pll_freq_table *sel; struct clk_pll_freq_table cfg; - pr_debug("%s: %s %lu\n", __func__, c->name, rate); - if (c->flags & PLL_FIXED) { int ret = 0; if (rate != c->u.pll.fixed_rate) { pr_err("%s: Can not change %s fixed rate %lu to %lu\n", - __func__, c->name, c->u.pll.fixed_rate, rate); + __func__, __clk_get_name(hw->clk), + c->u.pll.fixed_rate, rate); ret = -EINVAL; } return ret; } if (c->flags & PLLM) { - if (rate != clk_get_rate_locked(c)) { + if (rate != __clk_get_rate(hw->clk)) { pr_err("%s: Can not change memory %s rate in flight\n", - __func__, c->name); + __func__, __clk_get_name(hw->clk)); return -EINVAL; } - return 0; } p_div = 0; - input_rate = clk_get_rate(c->parent); + input_rate = parent_rate; /* Check if the target rate is tabulated */ for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { @@ -1054,7 +1136,7 @@ static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate) (p_div > (PLL_BASE_DIVP_MASK >> PLL_BASE_DIVP_SHIFT)) || (cfg.output_rate > c->u.pll.vco_max)) { pr_err("%s: Failed to set %s out-of-table rate %lu\n", - __func__, c->name, rate); + __func__, __clk_get_name(hw->clk), rate); return -EINVAL; } p_div <<= PLL_BASE_DIVP_SHIFT; @@ -1072,7 +1154,7 @@ static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate) return 0; if (c->state == ON) { - tegra30_pll_clk_disable(c); + tegra30_pll_clk_disable(hw); val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); } clk_writel(val, c->reg + PLL_BASE); @@ -1094,87 +1176,201 @@ static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate) } if (c->state == ON) - tegra30_pll_clk_enable(c); - - return 0; -} + tegra30_pll_clk_enable(hw); -struct clk_ops tegra30_pll_ops = { - .init = tegra30_pll_clk_init, - .enable = tegra30_pll_clk_enable, - .disable = tegra30_pll_clk_disable, - .set_rate = tegra30_pll_clk_set_rate, -}; - -static int -tegra30_plld_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) -{ - u32 val, mask, reg; - - switch (p) { - case TEGRA_CLK_PLLD_CSI_OUT_ENB: - mask = PLLD_BASE_CSI_CLKENABLE; - reg = c->reg + PLL_BASE; - break; - case TEGRA_CLK_PLLD_DSI_OUT_ENB: - mask = PLLD_MISC_DSI_CLKENABLE; - reg = c->reg + PLL_MISC(c); - break; - case TEGRA_CLK_PLLD_MIPI_MUX_SEL: - if (!(c->flags & PLL_ALT_MISC_REG)) { - mask = PLLD_BASE_DSIB_MUX_MASK; - reg = c->reg + PLL_BASE; - break; - } - /* fall through - error since PLLD2 does not have MUX_SEL control */ - default: - return -EINVAL; - } + c->u.pll.fixed_rate = rate; - val = clk_readl(reg); - if (setting) - val |= mask; - else - val &= ~mask; - clk_writel(val, reg); return 0; } -struct clk_ops tegra_plld_ops = { - .init = tegra30_pll_clk_init, - .enable = tegra30_pll_clk_enable, - .disable = tegra30_pll_clk_disable, - .set_rate = tegra30_pll_clk_set_rate, - .clk_cfg_ex = tegra30_plld_clk_cfg_ex, -}; - -static void tegra30_plle_clk_init(struct clk *c) +static long tegra30_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) { + struct clk_tegra *c = to_clk_tegra(hw); + unsigned long input_rate = *prate; + unsigned long output_rate = *prate; + const struct clk_pll_freq_table *sel; + struct clk_pll_freq_table cfg; + int mul; + int div; + u32 p_div; u32 val; - val = clk_readl(PLLE_AUX); - c->parent = (val & PLLE_AUX_PLLP_SEL) ? - tegra_get_clock_by_name("pll_p") : - tegra_get_clock_by_name("pll_ref"); + if (c->flags & PLL_FIXED) + return c->u.pll.fixed_rate; - val = clk_readl(c->reg + PLL_BASE); - c->state = (val & PLLE_BASE_ENABLE) ? ON : OFF; - c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT; - c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT; - c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT; -} + if (c->flags & PLLM) + return __clk_get_rate(hw->clk); -static void tegra30_plle_clk_disable(struct clk *c) -{ - u32 val; - pr_debug("%s on clock %s\n", __func__, c->name); + p_div = 0; + /* Check if the target rate is tabulated */ + for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { + if (sel->input_rate == input_rate && sel->output_rate == rate) { + if (c->flags & PLLU) { + BUG_ON(sel->p < 1 || sel->p > 2); + if (sel->p == 1) + p_div = PLLU_BASE_POST_DIV; + } else { + BUG_ON(sel->p < 1); + for (val = sel->p; val > 1; val >>= 1) + p_div++; + p_div <<= PLL_BASE_DIVP_SHIFT; + } + break; + } + } - val = clk_readl(c->reg + PLL_BASE); - val &= ~(PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE); - clk_writel(val, c->reg + PLL_BASE); -} + if (sel->input_rate == 0) { + unsigned long cfreq; + BUG_ON(c->flags & PLLU); + sel = &cfg; + + switch (input_rate) { + case 12000000: + case 26000000: + cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000; + break; + case 13000000: + cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000; + break; + case 16800000: + case 19200000: + cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000; + break; + default: + pr_err("%s: Unexpected reference rate %lu\n", + __func__, input_rate); + BUG(); + } + + /* Raise VCO to guarantee 0.5% accuracy */ + for (cfg.output_rate = rate; cfg.output_rate < 200 * cfreq; + cfg.output_rate <<= 1) + p_div++; + + cfg.p = 0x1 << p_div; + cfg.m = input_rate / cfreq; + cfg.n = cfg.output_rate / cfreq; + } + + mul = sel->n; + div = sel->m * sel->p; + + output_rate *= mul; + output_rate += div - 1; /* round up */ + do_div(output_rate, div); + + return output_rate; +} + +static unsigned long tegra30_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_tegra *c = to_clk_tegra(hw); + u64 rate = parent_rate; + u32 val = clk_readl(c->reg + PLL_BASE); + + if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) { + const struct clk_pll_freq_table *sel; + for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { + if (sel->input_rate == parent_rate && + sel->output_rate == c->u.pll.fixed_rate) { + c->mul = sel->n; + c->div = sel->m * sel->p; + break; + } + } + pr_err("Clock %s has unknown fixed frequency\n", + __clk_get_name(hw->clk)); + BUG(); + } else if (val & PLL_BASE_BYPASS) { + c->mul = 1; + c->div = 1; + } else { + c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT; + c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT; + if (c->flags & PLLU) + c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2; + else + c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >> + PLL_BASE_DIVP_SHIFT)); + } + + if (c->mul != 0 && c->div != 0) { + rate *= c->mul; + rate += c->div - 1; /* round up */ + do_div(rate, c->div); + } + + return rate; +} + +struct clk_ops tegra30_pll_ops = { + .is_enabled = tegra30_pll_clk_is_enabled, + .init = tegra30_pll_clk_init, + .enable = tegra30_pll_clk_enable, + .disable = tegra30_pll_clk_disable, + .recalc_rate = tegra30_pll_recalc_rate, + .round_rate = tegra30_pll_round_rate, + .set_rate = tegra30_pll_clk_set_rate, +}; + +int tegra30_plld_clk_cfg_ex(struct clk_hw *hw, + enum tegra_clk_ex_param p, u32 setting) +{ + struct clk_tegra *c = to_clk_tegra(hw); + u32 val, mask, reg; + + switch (p) { + case TEGRA_CLK_PLLD_CSI_OUT_ENB: + mask = PLLD_BASE_CSI_CLKENABLE; + reg = c->reg + PLL_BASE; + break; + case TEGRA_CLK_PLLD_DSI_OUT_ENB: + mask = PLLD_MISC_DSI_CLKENABLE; + reg = c->reg + PLL_MISC(c); + break; + case TEGRA_CLK_PLLD_MIPI_MUX_SEL: + if (!(c->flags & PLL_ALT_MISC_REG)) { + mask = PLLD_BASE_DSIB_MUX_MASK; + reg = c->reg + PLL_BASE; + break; + } + /* fall through - error since PLLD2 does not have MUX_SEL control */ + default: + return -EINVAL; + } + + val = clk_readl(reg); + if (setting) + val |= mask; + else + val &= ~mask; + clk_writel(val, reg); + return 0; +} + +static int tegra30_plle_clk_is_enabled(struct clk_hw *hw) +{ + struct clk_tegra *c = to_clk_tegra(hw); + u32 val; + + val = clk_readl(c->reg + PLL_BASE); + c->state = (val & PLLE_BASE_ENABLE) ? ON : OFF; + return c->state; +} + +static void tegra30_plle_clk_disable(struct clk_hw *hw) +{ + struct clk_tegra *c = to_clk_tegra(hw); + u32 val; + + val = clk_readl(c->reg + PLL_BASE); + val &= ~(PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE); + clk_writel(val, c->reg + PLL_BASE); +} -static void tegra30_plle_training(struct clk *c) +static void tegra30_plle_training(struct clk_tegra *c) { u32 val; @@ -1197,12 +1393,15 @@ static void tegra30_plle_training(struct clk *c) } while (!(val & PLLE_MISC_READY)); } -static int tegra30_plle_configure(struct clk *c, bool force_training) +static int tegra30_plle_configure(struct clk_hw *hw, bool force_training) { - u32 val; + struct clk_tegra *c = to_clk_tegra(hw); + struct clk *parent = __clk_get_parent(hw->clk); const struct clk_pll_freq_table *sel; + u32 val; + unsigned long rate = c->u.pll.fixed_rate; - unsigned long input_rate = clk_get_rate(c->parent); + unsigned long input_rate = __clk_get_rate(parent); for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { if (sel->input_rate == input_rate && sel->output_rate == rate) @@ -1213,7 +1412,7 @@ static int tegra30_plle_configure(struct clk *c, bool force_training) return -ENOSYS; /* disable PLLE, clear setup fiels */ - tegra30_plle_clk_disable(c); + tegra30_plle_clk_disable(hw); val = clk_readl(c->reg + PLL_MISC(c)); val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK); @@ -1251,52 +1450,64 @@ static int tegra30_plle_configure(struct clk *c, bool force_training) return 0; } -static int tegra30_plle_clk_enable(struct clk *c) +static int tegra30_plle_clk_enable(struct clk_hw *hw) { - pr_debug("%s on clock %s\n", __func__, c->name); - return tegra30_plle_configure(c, !c->set); + struct clk_tegra *c = to_clk_tegra(hw); + + return tegra30_plle_configure(hw, !c->set); +} + +static unsigned long tegra30_plle_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_tegra *c = to_clk_tegra(hw); + unsigned long rate = parent_rate; + u32 val; + + val = clk_readl(c->reg + PLL_BASE); + c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT; + c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT; + c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT; + + if (c->mul != 0 && c->div != 0) { + rate *= c->mul; + rate += c->div - 1; /* round up */ + do_div(rate, c->div); + } + return rate; } struct clk_ops tegra30_plle_ops = { - .init = tegra30_plle_clk_init, - .enable = tegra30_plle_clk_enable, - .disable = tegra30_plle_clk_disable, + .is_enabled = tegra30_plle_clk_is_enabled, + .enable = tegra30_plle_clk_enable, + .disable = tegra30_plle_clk_disable, + .recalc_rate = tegra30_plle_clk_recalc_rate, }; /* Clock divider ops */ -static void tegra30_pll_div_clk_init(struct clk *c) +static int tegra30_pll_div_clk_is_enabled(struct clk_hw *hw) { + struct clk_tegra *c = to_clk_tegra(hw); + if (c->flags & DIV_U71) { - u32 divu71; u32 val = clk_readl(c->reg); val >>= c->reg_shift; c->state = (val & PLL_OUT_CLKEN) ? ON : OFF; if (!(val & PLL_OUT_RESET_DISABLE)) c->state = OFF; - - divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT; - c->div = (divu71 + 2); - c->mul = 2; - } else if (c->flags & DIV_2) { - c->state = ON; - if (c->flags & (PLLD | PLLX)) { - c->div = 2; - c->mul = 1; - } else - BUG(); } else { c->state = ON; - c->div = 1; - c->mul = 1; } + return c->state; } -static int tegra30_pll_div_clk_enable(struct clk *c) +static int tegra30_pll_div_clk_enable(struct clk_hw *hw) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val; u32 new_val; - pr_debug("%s: %s\n", __func__, c->name); + pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk)); if (c->flags & DIV_U71) { val = clk_readl(c->reg); new_val = val >> c->reg_shift; @@ -1314,12 +1525,13 @@ static int tegra30_pll_div_clk_enable(struct clk *c) return -EINVAL; } -static void tegra30_pll_div_clk_disable(struct clk *c) +static void tegra30_pll_div_clk_disable(struct clk_hw *hw) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val; u32 new_val; - pr_debug("%s: %s\n", __func__, c->name); + pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk)); if (c->flags & DIV_U71) { val = clk_readl(c->reg); new_val = val >> c->reg_shift; @@ -1333,14 +1545,14 @@ static void tegra30_pll_div_clk_disable(struct clk *c) } } -static int tegra30_pll_div_clk_set_rate(struct clk *c, unsigned long rate) +static int tegra30_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val; u32 new_val; int divider_u71; - unsigned long parent_rate = clk_get_rate(c->parent); - pr_debug("%s: %s %lu\n", __func__, c->name, rate); if (c->flags & DIV_U71) { divider_u71 = clk_div71_get_divider( parent_rate, rate, c->flags, ROUND_DIVIDER_UP); @@ -1358,19 +1570,59 @@ static int tegra30_pll_div_clk_set_rate(struct clk *c, unsigned long rate) clk_writel_delay(val, c->reg); c->div = divider_u71 + 2; c->mul = 2; + c->fixed_rate = rate; return 0; } - } else if (c->flags & DIV_2) - return clk_set_rate(c->parent, rate * 2); + } else if (c->flags & DIV_2) { + c->fixed_rate = rate; + return 0; + } return -EINVAL; } -static long tegra30_pll_div_clk_round_rate(struct clk *c, unsigned long rate) +static unsigned long tegra30_pll_div_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_tegra *c = to_clk_tegra(hw); + u64 rate = parent_rate; + + if (c->flags & DIV_U71) { + u32 divu71; + u32 val = clk_readl(c->reg); + val >>= c->reg_shift; + + divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT; + c->div = (divu71 + 2); + c->mul = 2; + } else if (c->flags & DIV_2) { + if (c->flags & (PLLD | PLLX)) { + c->div = 2; + c->mul = 1; + } else + BUG(); + } else { + c->div = 1; + c->mul = 1; + } + if (c->mul != 0 && c->div != 0) { + rate *= c->mul; + rate += c->div - 1; /* round up */ + do_div(rate, c->div); + } + + return rate; +} + +static long tegra30_pll_div_clk_round_rate(struct clk_hw *hw, + unsigned long rate, unsigned long *prate) { + struct clk_tegra *c = to_clk_tegra(hw); + unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); int divider; - unsigned long parent_rate = clk_get_rate(c->parent); - pr_debug("%s: %s %lu\n", __func__, c->name, rate); + + if (prate) + parent_rate = *prate; if (c->flags & DIV_U71) { divider = clk_div71_get_divider( @@ -1378,23 +1630,25 @@ static long tegra30_pll_div_clk_round_rate(struct clk *c, unsigned long rate) if (divider < 0) return divider; return DIV_ROUND_UP(parent_rate * 2, divider + 2); - } else if (c->flags & DIV_2) - /* no rounding - fixed DIV_2 dividers pass rate to parent PLL */ + } else if (c->flags & DIV_2) { + *prate = rate * 2; return rate; + } return -EINVAL; } struct clk_ops tegra30_pll_div_ops = { - .init = tegra30_pll_div_clk_init, - .enable = tegra30_pll_div_clk_enable, - .disable = tegra30_pll_div_clk_disable, - .set_rate = tegra30_pll_div_clk_set_rate, - .round_rate = tegra30_pll_div_clk_round_rate, + .is_enabled = tegra30_pll_div_clk_is_enabled, + .enable = tegra30_pll_div_clk_enable, + .disable = tegra30_pll_div_clk_disable, + .set_rate = tegra30_pll_div_clk_set_rate, + .recalc_rate = tegra30_pll_div_clk_recalc_rate, + .round_rate = tegra30_pll_div_clk_round_rate, }; /* Periph clk ops */ -static inline u32 periph_clk_source_mask(struct clk *c) +static inline u32 periph_clk_source_mask(struct clk_tegra *c) { if (c->flags & MUX8) return 7 << 29; @@ -1408,7 +1662,7 @@ static inline u32 periph_clk_source_mask(struct clk *c) return 3 << 30; } -static inline u32 periph_clk_source_shift(struct clk *c) +static inline u32 periph_clk_source_shift(struct clk_tegra *c) { if (c->flags & MUX8) return 29; @@ -1422,47 +1676,9 @@ static inline u32 periph_clk_source_shift(struct clk *c) return 30; } -static void tegra30_periph_clk_init(struct clk *c) +static int tegra30_periph_clk_is_enabled(struct clk_hw *hw) { - u32 val = clk_readl(c->reg); - const struct clk_mux_sel *mux = 0; - const struct clk_mux_sel *sel; - if (c->flags & MUX) { - for (sel = c->inputs; sel->input != NULL; sel++) { - if (((val & periph_clk_source_mask(c)) >> - periph_clk_source_shift(c)) == sel->value) - mux = sel; - } - BUG_ON(!mux); - - c->parent = mux->input; - } else { - c->parent = c->inputs[0].input; - } - - if (c->flags & DIV_U71) { - u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK; - if ((c->flags & DIV_U71_UART) && - (!(val & PERIPH_CLK_UART_DIV_ENB))) { - divu71 = 0; - } - if (c->flags & DIV_U71_IDLE) { - val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK << - PERIPH_CLK_SOURCE_DIVIDLE_SHIFT); - val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL << - PERIPH_CLK_SOURCE_DIVIDLE_SHIFT); - clk_writel(val, c->reg); - } - c->div = divu71 + 2; - c->mul = 2; - } else if (c->flags & DIV_U16) { - u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK; - c->div = divu16 + 1; - c->mul = 1; - } else { - c->div = 1; - c->mul = 1; - } + struct clk_tegra *c = to_clk_tegra(hw); c->state = ON; if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c))) @@ -1470,11 +1686,12 @@ static void tegra30_periph_clk_init(struct clk *c) if (!(c->flags & PERIPH_NO_RESET)) if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & PERIPH_CLK_TO_BIT(c)) c->state = OFF; + return c->state; } -static int tegra30_periph_clk_enable(struct clk *c) +static int tegra30_periph_clk_enable(struct clk_hw *hw) { - pr_debug("%s on clock %s\n", __func__, c->name); + struct clk_tegra *c = to_clk_tegra(hw); tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++; if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1) @@ -1493,31 +1710,29 @@ static int tegra30_periph_clk_enable(struct clk *c) return 0; } -static void tegra30_periph_clk_disable(struct clk *c) +static void tegra30_periph_clk_disable(struct clk_hw *hw) { + struct clk_tegra *c = to_clk_tegra(hw); unsigned long val; - pr_debug("%s on clock %s\n", __func__, c->name); - if (c->refcnt) - tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--; + tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--; - if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] == 0) { - /* If peripheral is in the APB bus then read the APB bus to - * flush the write operation in apb bus. This will avoid the - * peripheral access after disabling clock*/ - if (c->flags & PERIPH_ON_APB) - val = chipid_readl(); + if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0) + return; - clk_writel_delay( - PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c)); - } + /* If peripheral is in the APB bus then read the APB bus to + * flush the write operation in apb bus. This will avoid the + * peripheral access after disabling clock*/ + if (c->flags & PERIPH_ON_APB) + val = chipid_readl(); + + clk_writel_delay(PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c)); } -static void tegra30_periph_clk_reset(struct clk *c, bool assert) +void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert) { + struct clk_tegra *c = to_clk_tegra(hw); unsigned long val; - pr_debug("%s %s on clock %s\n", __func__, - assert ? "assert" : "deassert", c->name); if (!(c->flags & PERIPH_NO_RESET)) { if (assert) { @@ -1536,42 +1751,40 @@ static void tegra30_periph_clk_reset(struct clk *c, bool assert) } } -static int tegra30_periph_clk_set_parent(struct clk *c, struct clk *p) +static int tegra30_periph_clk_set_parent(struct clk_hw *hw, u8 index) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val; - const struct clk_mux_sel *sel; - pr_debug("%s: %s %s\n", __func__, c->name, p->name); if (!(c->flags & MUX)) - return (p == c->parent) ? 0 : (-EINVAL); - - for (sel = c->inputs; sel->input != NULL; sel++) { - if (sel->input == p) { - val = clk_readl(c->reg); - val &= ~periph_clk_source_mask(c); - val |= (sel->value << periph_clk_source_shift(c)); - - if (c->refcnt) - clk_enable(p); + return (index == 0) ? 0 : (-EINVAL); - clk_writel_delay(val, c->reg); + val = clk_readl(c->reg); + val &= ~periph_clk_source_mask(c); + val |= (index << periph_clk_source_shift(c)); + clk_writel_delay(val, c->reg); + return 0; +} - if (c->refcnt && c->parent) - clk_disable(c->parent); +static u8 tegra30_periph_clk_get_parent(struct clk_hw *hw) +{ + struct clk_tegra *c = to_clk_tegra(hw); + u32 val = clk_readl(c->reg); + int source = (val & periph_clk_source_mask(c)) >> + periph_clk_source_shift(c); - clk_reparent(c, p); - return 0; - } - } + if (!(c->flags & MUX)) + return 0; - return -EINVAL; + return source; } -static int tegra30_periph_clk_set_rate(struct clk *c, unsigned long rate) +static int tegra30_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val; int divider; - unsigned long parent_rate = clk_get_rate(c->parent); if (c->flags & DIV_U71) { divider = clk_div71_get_divider( @@ -1610,12 +1823,15 @@ static int tegra30_periph_clk_set_rate(struct clk *c, unsigned long rate) return -EINVAL; } -static long tegra30_periph_clk_round_rate(struct clk *c, - unsigned long rate) +static long tegra30_periph_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) { + struct clk_tegra *c = to_clk_tegra(hw); + unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); int divider; - unsigned long parent_rate = clk_get_rate(c->parent); - pr_debug("%s: %s %lu\n", __func__, c->name, rate); + + if (prate) + parent_rate = *prate; if (c->flags & DIV_U71) { divider = clk_div71_get_divider( @@ -1633,20 +1849,85 @@ static long tegra30_periph_clk_round_rate(struct clk *c, return -EINVAL; } +static unsigned long tegra30_periph_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_tegra *c = to_clk_tegra(hw); + u64 rate = parent_rate; + u32 val = clk_readl(c->reg); + + if (c->flags & DIV_U71) { + u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK; + if ((c->flags & DIV_U71_UART) && + (!(val & PERIPH_CLK_UART_DIV_ENB))) { + divu71 = 0; + } + if (c->flags & DIV_U71_IDLE) { + val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK << + PERIPH_CLK_SOURCE_DIVIDLE_SHIFT); + val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL << + PERIPH_CLK_SOURCE_DIVIDLE_SHIFT); + clk_writel(val, c->reg); + } + c->div = divu71 + 2; + c->mul = 2; + } else if (c->flags & DIV_U16) { + u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK; + c->div = divu16 + 1; + c->mul = 1; + } else { + c->div = 1; + c->mul = 1; + } + + if (c->mul != 0 && c->div != 0) { + rate *= c->mul; + rate += c->div - 1; /* round up */ + do_div(rate, c->div); + } + return rate; +} + struct clk_ops tegra30_periph_clk_ops = { - .init = &tegra30_periph_clk_init, + .is_enabled = tegra30_periph_clk_is_enabled, + .enable = tegra30_periph_clk_enable, + .disable = tegra30_periph_clk_disable, + .set_parent = tegra30_periph_clk_set_parent, + .get_parent = tegra30_periph_clk_get_parent, + .set_rate = tegra30_periph_clk_set_rate, + .round_rate = tegra30_periph_clk_round_rate, + .recalc_rate = tegra30_periph_clk_recalc_rate, +}; + +static int tegra30_dsib_clk_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk *d = clk_get_sys(NULL, "pll_d"); + /* The DSIB parent selection bit is in PLLD base + register - can not do direct r-m-w, must be + protected by PLLD lock */ + tegra_clk_cfg_ex( + d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, index); + + return 0; +} + +struct clk_ops tegra30_dsib_clk_ops = { + .is_enabled = tegra30_periph_clk_is_enabled, .enable = &tegra30_periph_clk_enable, .disable = &tegra30_periph_clk_disable, - .set_parent = &tegra30_periph_clk_set_parent, + .set_parent = &tegra30_dsib_clk_set_parent, + .get_parent = &tegra30_periph_clk_get_parent, .set_rate = &tegra30_periph_clk_set_rate, .round_rate = &tegra30_periph_clk_round_rate, - .reset = &tegra30_periph_clk_reset, + .recalc_rate = &tegra30_periph_clk_recalc_rate, }; /* Periph extended clock configuration ops */ -static int -tegra30_vi_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) +int tegra30_vi_clk_cfg_ex(struct clk_hw *hw, + enum tegra_clk_ex_param p, u32 setting) { + struct clk_tegra *c = to_clk_tegra(hw); + if (p == TEGRA_CLK_VI_INP_SEL) { u32 val = clk_readl(c->reg); val &= ~PERIPH_CLK_VI_SEL_EX_MASK; @@ -1658,20 +1939,11 @@ tegra30_vi_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) return -EINVAL; } -struct clk_ops tegra_vi_clk_ops = { - .init = &tegra30_periph_clk_init, - .enable = &tegra30_periph_clk_enable, - .disable = &tegra30_periph_clk_disable, - .set_parent = &tegra30_periph_clk_set_parent, - .set_rate = &tegra30_periph_clk_set_rate, - .round_rate = &tegra30_periph_clk_round_rate, - .clk_cfg_ex = &tegra30_vi_clk_cfg_ex, - .reset = &tegra30_periph_clk_reset, -}; - -static int -tegra30_nand_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) +int tegra30_nand_clk_cfg_ex(struct clk_hw *hw, + enum tegra_clk_ex_param p, u32 setting) { + struct clk_tegra *c = to_clk_tegra(hw); + if (p == TEGRA_CLK_NAND_PAD_DIV2_ENB) { u32 val = clk_readl(c->reg); if (setting) @@ -1684,20 +1956,11 @@ tegra30_nand_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) return -EINVAL; } -struct clk_ops tegra_nand_clk_ops = { - .init = &tegra30_periph_clk_init, - .enable = &tegra30_periph_clk_enable, - .disable = &tegra30_periph_clk_disable, - .set_parent = &tegra30_periph_clk_set_parent, - .set_rate = &tegra30_periph_clk_set_rate, - .round_rate = &tegra30_periph_clk_round_rate, - .clk_cfg_ex = &tegra30_nand_clk_cfg_ex, - .reset = &tegra30_periph_clk_reset, -}; - -static int -tegra30_dtv_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) +int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw, + enum tegra_clk_ex_param p, u32 setting) { + struct clk_tegra *c = to_clk_tegra(hw); + if (p == TEGRA_CLK_DTV_INVERT) { u32 val = clk_readl(c->reg); if (setting) @@ -1710,91 +1973,27 @@ tegra30_dtv_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) return -EINVAL; } -struct clk_ops tegra_dtv_clk_ops = { - .init = &tegra30_periph_clk_init, - .enable = &tegra30_periph_clk_enable, - .disable = &tegra30_periph_clk_disable, - .set_parent = &tegra30_periph_clk_set_parent, - .set_rate = &tegra30_periph_clk_set_rate, - .round_rate = &tegra30_periph_clk_round_rate, - .clk_cfg_ex = &tegra30_dtv_clk_cfg_ex, - .reset = &tegra30_periph_clk_reset, -}; - -static int tegra30_dsib_clk_set_parent(struct clk *c, struct clk *p) -{ - const struct clk_mux_sel *sel; - struct clk *d = tegra_get_clock_by_name("pll_d"); - - pr_debug("%s: %s %s\n", __func__, c->name, p->name); - - for (sel = c->inputs; sel->input != NULL; sel++) { - if (sel->input == p) { - if (c->refcnt) - clk_enable(p); - - /* The DSIB parent selection bit is in PLLD base - register - can not do direct r-m-w, must be - protected by PLLD lock */ - tegra_clk_cfg_ex( - d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, sel->value); - - if (c->refcnt && c->parent) - clk_disable(c->parent); - - clk_reparent(c, p); - return 0; - } - } - - return -EINVAL; -} - -struct clk_ops tegra_dsib_clk_ops = { - .init = &tegra30_periph_clk_init, - .enable = &tegra30_periph_clk_enable, - .disable = &tegra30_periph_clk_disable, - .set_parent = &tegra30_dsib_clk_set_parent, - .set_rate = &tegra30_periph_clk_set_rate, - .round_rate = &tegra30_periph_clk_round_rate, - .reset = &tegra30_periph_clk_reset, -}; - -/* pciex clock support only reset function */ -struct clk_ops tegra_pciex_clk_ops = { - .reset = tegra30_periph_clk_reset, -}; - /* Output clock ops */ static DEFINE_SPINLOCK(clk_out_lock); -static void tegra30_clk_out_init(struct clk *c) +static int tegra30_clk_out_is_enabled(struct clk_hw *hw) { - const struct clk_mux_sel *mux = 0; - const struct clk_mux_sel *sel; + struct clk_tegra *c = to_clk_tegra(hw); u32 val = pmc_readl(c->reg); c->state = (val & (0x1 << c->u.periph.clk_num)) ? ON : OFF; c->mul = 1; c->div = 1; - - for (sel = c->inputs; sel->input != NULL; sel++) { - if (((val & periph_clk_source_mask(c)) >> - periph_clk_source_shift(c)) == sel->value) - mux = sel; - } - BUG_ON(!mux); - c->parent = mux->input; + return c->state; } -static int tegra30_clk_out_enable(struct clk *c) +static int tegra30_clk_out_enable(struct clk_hw *hw) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val; unsigned long flags; - pr_debug("%s on clock %s\n", __func__, c->name); - spin_lock_irqsave(&clk_out_lock, flags); val = pmc_readl(c->reg); val |= (0x1 << c->u.periph.clk_num); @@ -1804,13 +2003,12 @@ static int tegra30_clk_out_enable(struct clk *c) return 0; } -static void tegra30_clk_out_disable(struct clk *c) +static void tegra30_clk_out_disable(struct clk_hw *hw) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val; unsigned long flags; - pr_debug("%s on clock %s\n", __func__, c->name); - spin_lock_irqsave(&clk_out_lock, flags); val = pmc_readl(c->reg); val &= ~(0x1 << c->u.periph.clk_num); @@ -1818,58 +2016,59 @@ static void tegra30_clk_out_disable(struct clk *c) spin_unlock_irqrestore(&clk_out_lock, flags); } -static int tegra30_clk_out_set_parent(struct clk *c, struct clk *p) +static int tegra30_clk_out_set_parent(struct clk_hw *hw, u8 index) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val; unsigned long flags; - const struct clk_mux_sel *sel; - pr_debug("%s: %s %s\n", __func__, c->name, p->name); - - for (sel = c->inputs; sel->input != NULL; sel++) { - if (sel->input == p) { - if (c->refcnt) - clk_enable(p); + spin_lock_irqsave(&clk_out_lock, flags); + val = pmc_readl(c->reg); + val &= ~periph_clk_source_mask(c); + val |= (index << periph_clk_source_shift(c)); + pmc_writel(val, c->reg); + spin_unlock_irqrestore(&clk_out_lock, flags); - spin_lock_irqsave(&clk_out_lock, flags); - val = pmc_readl(c->reg); - val &= ~periph_clk_source_mask(c); - val |= (sel->value << periph_clk_source_shift(c)); - pmc_writel(val, c->reg); - spin_unlock_irqrestore(&clk_out_lock, flags); + return 0; +} - if (c->refcnt && c->parent) - clk_disable(c->parent); +static u8 tegra30_clk_out_get_parent(struct clk_hw *hw) +{ + struct clk_tegra *c = to_clk_tegra(hw); + u32 val = pmc_readl(c->reg); + int source; - clk_reparent(c, p); - return 0; - } - } - return -EINVAL; + source = (val & periph_clk_source_mask(c)) >> + periph_clk_source_shift(c); + return source; } struct clk_ops tegra_clk_out_ops = { - .init = &tegra30_clk_out_init, - .enable = &tegra30_clk_out_enable, - .disable = &tegra30_clk_out_disable, - .set_parent = &tegra30_clk_out_set_parent, + .is_enabled = tegra30_clk_out_is_enabled, + .enable = tegra30_clk_out_enable, + .disable = tegra30_clk_out_disable, + .set_parent = tegra30_clk_out_set_parent, + .get_parent = tegra30_clk_out_get_parent, + .recalc_rate = tegra30_clk_fixed_recalc_rate, }; /* Clock doubler ops */ -static void tegra30_clk_double_init(struct clk *c) +static int tegra30_clk_double_is_enabled(struct clk_hw *hw) { - u32 val = clk_readl(c->reg); - c->mul = val & (0x1 << c->reg_shift) ? 1 : 2; - c->div = 1; + struct clk_tegra *c = to_clk_tegra(hw); + c->state = ON; if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c))) c->state = OFF; + return c->state; }; -static int tegra30_clk_double_set_rate(struct clk *c, unsigned long rate) +static int tegra30_clk_double_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val; - unsigned long parent_rate = clk_get_rate(c->parent); + if (rate == parent_rate) { val = clk_readl(c->reg) | (0x1 << c->reg_shift); clk_writel(val, c->reg); @@ -1886,108 +2085,139 @@ static int tegra30_clk_double_set_rate(struct clk *c, unsigned long rate) return -EINVAL; } -struct clk_ops tegra30_clk_double_ops = { - .init = &tegra30_clk_double_init, - .enable = &tegra30_periph_clk_enable, - .disable = &tegra30_periph_clk_disable, - .set_rate = &tegra30_clk_double_set_rate, -}; +static unsigned long tegra30_clk_double_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_tegra *c = to_clk_tegra(hw); + u64 rate = parent_rate; -/* Audio sync clock ops */ -static int tegra30_sync_source_set_rate(struct clk *c, unsigned long rate) + u32 val = clk_readl(c->reg); + c->mul = val & (0x1 << c->reg_shift) ? 1 : 2; + c->div = 1; + + if (c->mul != 0 && c->div != 0) { + rate *= c->mul; + rate += c->div - 1; /* round up */ + do_div(rate, c->div); + } + + return rate; +} + +static long tegra30_clk_double_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) { - c->rate = rate; - return 0; + unsigned long output_rate = *prate; + + do_div(output_rate, 2); + return output_rate; } +struct clk_ops tegra30_clk_double_ops = { + .is_enabled = tegra30_clk_double_is_enabled, + .enable = tegra30_periph_clk_enable, + .disable = tegra30_periph_clk_disable, + .recalc_rate = tegra30_clk_double_recalc_rate, + .round_rate = tegra30_clk_double_round_rate, + .set_rate = tegra30_clk_double_set_rate, +}; + +/* Audio sync clock ops */ struct clk_ops tegra_sync_source_ops = { - .set_rate = &tegra30_sync_source_set_rate, + .recalc_rate = tegra30_clk_fixed_recalc_rate, }; -static void tegra30_audio_sync_clk_init(struct clk *c) +static int tegra30_audio_sync_clk_is_enabled(struct clk_hw *hw) { - int source; - const struct clk_mux_sel *sel; + struct clk_tegra *c = to_clk_tegra(hw); u32 val = clk_readl(c->reg); c->state = (val & AUDIO_SYNC_DISABLE_BIT) ? OFF : ON; - source = val & AUDIO_SYNC_SOURCE_MASK; - for (sel = c->inputs; sel->input != NULL; sel++) - if (sel->value == source) - break; - BUG_ON(sel->input == NULL); - c->parent = sel->input; + return c->state; } -static int tegra30_audio_sync_clk_enable(struct clk *c) +static int tegra30_audio_sync_clk_enable(struct clk_hw *hw) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val = clk_readl(c->reg); clk_writel((val & (~AUDIO_SYNC_DISABLE_BIT)), c->reg); return 0; } -static void tegra30_audio_sync_clk_disable(struct clk *c) +static void tegra30_audio_sync_clk_disable(struct clk_hw *hw) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val = clk_readl(c->reg); clk_writel((val | AUDIO_SYNC_DISABLE_BIT), c->reg); } -static int tegra30_audio_sync_clk_set_parent(struct clk *c, struct clk *p) +static int tegra30_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val; - const struct clk_mux_sel *sel; - for (sel = c->inputs; sel->input != NULL; sel++) { - if (sel->input == p) { - val = clk_readl(c->reg); - val &= ~AUDIO_SYNC_SOURCE_MASK; - val |= sel->value; - if (c->refcnt) - clk_enable(p); - - clk_writel(val, c->reg); + val = clk_readl(c->reg); + val &= ~AUDIO_SYNC_SOURCE_MASK; + val |= index; - if (c->refcnt && c->parent) - clk_disable(c->parent); + clk_writel(val, c->reg); + return 0; +} - clk_reparent(c, p); - return 0; - } - } +static u8 tegra30_audio_sync_clk_get_parent(struct clk_hw *hw) +{ + struct clk_tegra *c = to_clk_tegra(hw); + u32 val = clk_readl(c->reg); + int source; - return -EINVAL; + source = val & AUDIO_SYNC_SOURCE_MASK; + return source; } struct clk_ops tegra30_audio_sync_clk_ops = { - .init = tegra30_audio_sync_clk_init, - .enable = tegra30_audio_sync_clk_enable, - .disable = tegra30_audio_sync_clk_disable, + .is_enabled = tegra30_audio_sync_clk_is_enabled, + .enable = tegra30_audio_sync_clk_enable, + .disable = tegra30_audio_sync_clk_disable, .set_parent = tegra30_audio_sync_clk_set_parent, + .get_parent = tegra30_audio_sync_clk_get_parent, + .recalc_rate = tegra30_clk_fixed_recalc_rate, }; /* cml0 (pcie), and cml1 (sata) clock ops */ -static void tegra30_cml_clk_init(struct clk *c) +static int tegra30_cml_clk_is_enabled(struct clk_hw *hw) { + struct clk_tegra *c = to_clk_tegra(hw); u32 val = clk_readl(c->reg); c->state = val & (0x1 << c->u.periph.clk_num) ? ON : OFF; + return c->state; } -static int tegra30_cml_clk_enable(struct clk *c) +static int tegra30_cml_clk_enable(struct clk_hw *hw) { + struct clk_tegra *c = to_clk_tegra(hw); + u32 val = clk_readl(c->reg); val |= (0x1 << c->u.periph.clk_num); clk_writel(val, c->reg); + return 0; } -static void tegra30_cml_clk_disable(struct clk *c) +static void tegra30_cml_clk_disable(struct clk_hw *hw) { + struct clk_tegra *c = to_clk_tegra(hw); + u32 val = clk_readl(c->reg); val &= ~(0x1 << c->u.periph.clk_num); clk_writel(val, c->reg); } struct clk_ops tegra_cml_clk_ops = { - .init = &tegra30_cml_clk_init, - .enable = &tegra30_cml_clk_enable, - .disable = &tegra30_cml_clk_disable, + .is_enabled = tegra30_cml_clk_is_enabled, + .enable = tegra30_cml_clk_enable, + .disable = tegra30_cml_clk_disable, + .recalc_rate = tegra30_clk_fixed_recalc_rate, +}; + +struct clk_ops tegra_pciex_clk_ops = { + .recalc_rate = tegra30_clk_fixed_recalc_rate, }; -- cgit v1.2.1 From b78c030cebdaf8da14b44a4454146a7919e763a8 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Fri, 17 Aug 2012 14:51:21 +0800 Subject: ARM: tegra: clocks: separate tegra_clk_32k_ops from Tegra20 and Tegra30 Currently the tegra20 and tegra30 share the same symbol for tegra_clk_32k_ops. This will cause a compile error when building a tegra20-only kernel image. Add tegra_clk_32k_ops for tegra20 and modify tegra30_clk_32k_ops for tegra30. Signed-off-by: Joseph Lo Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/tegra30_clocks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/mach-tegra/tegra30_clocks.c') diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c index a9fa8ea0b6e0..3129c2f21d81 100644 --- a/arch/arm/mach-tegra/tegra30_clocks.c +++ b/arch/arm/mach-tegra/tegra30_clocks.c @@ -478,7 +478,7 @@ static unsigned long tegra30_clk_fixed_recalc_rate(struct clk_hw *hw, return to_clk_tegra(hw)->fixed_rate; } -struct clk_ops tegra_clk_32k_ops = { +struct clk_ops tegra30_clk_32k_ops = { .recalc_rate = tegra30_clk_fixed_recalc_rate, }; -- cgit v1.2.1 From fa67ccb61d10fbd55d1c3b5b6b537e4d74da1e4b Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 7 Sep 2012 11:10:55 +0530 Subject: ARM: tegra: Fix data type for io address Warnings were generated because following commit changed data type for address pointer 195bbca ARM: 7500/1: io: avoid writeback addressing modes for __raw_ accessors arch/arm/mach-tegra/tegra30_clocks.c: In function 'clk_measure_input_freq': arch/arm/mach-tegra/tegra30_clocks.c:418:2: warning: passing argument 2 of '__raw_writel' makes pointer from integer without a cast .../arch/arm/include/asm/io.h:88:20: note: expected 'volatile void *' but argument is of type 'unsigned int Signed-off-by: Prashant Gaikwad Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/tegra30_clocks.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'arch/arm/mach-tegra/tegra30_clocks.c') diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c index 3129c2f21d81..63615dadfbb2 100644 --- a/arch/arm/mach-tegra/tegra30_clocks.c +++ b/arch/arm/mach-tegra/tegra30_clocks.c @@ -365,19 +365,19 @@ static void __iomem *misc_gp_hidrev_base = IO_ADDRESS(TEGRA_APB_MISC_BASE); static int tegra_periph_clk_enable_refcount[CLK_OUT_ENB_NUM * 32]; #define clk_writel(value, reg) \ - __raw_writel(value, (u32)reg_clk_base + (reg)) + __raw_writel(value, reg_clk_base + (reg)) #define clk_readl(reg) \ - __raw_readl((u32)reg_clk_base + (reg)) + __raw_readl(reg_clk_base + (reg)) #define pmc_writel(value, reg) \ - __raw_writel(value, (u32)reg_pmc_base + (reg)) + __raw_writel(value, reg_pmc_base + (reg)) #define pmc_readl(reg) \ - __raw_readl((u32)reg_pmc_base + (reg)) + __raw_readl(reg_pmc_base + (reg)) #define chipid_readl() \ - __raw_readl((u32)misc_gp_hidrev_base + MISC_GP_HIDREV) + __raw_readl(misc_gp_hidrev_base + MISC_GP_HIDREV) #define clk_writel_delay(value, reg) \ do { \ - __raw_writel((value), (u32)reg_clk_base + (reg)); \ + __raw_writel((value), reg_clk_base + (reg)); \ udelay(2); \ } while (0) -- cgit v1.2.1 From dab403ef23f7561f7d77e0dc72dfd1be0fa333c1 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Thu, 16 Aug 2012 17:31:48 +0800 Subject: ARM: tegra: introduce tegra_cpu_car_ops structures The tegra_cpu_car_ops provide the interface for CPU to control it's clock gating and reset status. The other drivers should use this for CPU control. And should not directly access CAR registers to control CPU. Signed-off-by: Joseph Lo Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/tegra30_clocks.c | 72 ++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'arch/arm/mach-tegra/tegra30_clocks.c') diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c index 63615dadfbb2..5cd502c27163 100644 --- a/arch/arm/mach-tegra/tegra30_clocks.c +++ b/arch/arm/mach-tegra/tegra30_clocks.c @@ -35,6 +35,7 @@ #include "clock.h" #include "fuse.h" +#include "tegra_cpu_car.h" #define USE_PLL_LOCK_BITS 0 @@ -299,6 +300,16 @@ /* FIXME: recommended safety delay after lock is detected */ #define PLL_POST_LOCK_DELAY 100 +/* Tegra CPU clock and reset control regs */ +#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c +#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340 +#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344 +#define TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR 0x34c +#define TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470 + +#define CPU_CLOCK(cpu) (0x1 << (8 + cpu)) +#define CPU_RESET(cpu) (0x1111ul << (cpu)) + /** * Structure defining the fields for USB UTMI clocks Parameters. */ @@ -2221,3 +2232,64 @@ struct clk_ops tegra_cml_clk_ops = { struct clk_ops tegra_pciex_clk_ops = { .recalc_rate = tegra30_clk_fixed_recalc_rate, }; + +/* Tegra30 CPU clock and reset control functions */ +static void tegra30_wait_cpu_in_reset(u32 cpu) +{ + unsigned int reg; + + do { + reg = readl(reg_clk_base + + TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); + cpu_relax(); + } while (!(reg & (1 << cpu))); /* check CPU been reset or not */ + + return; +} + +static void tegra30_put_cpu_in_reset(u32 cpu) +{ + writel(CPU_RESET(cpu), + reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); + dmb(); +} + +static void tegra30_cpu_out_of_reset(u32 cpu) +{ + writel(CPU_RESET(cpu), + reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); + wmb(); +} + +static void tegra30_enable_cpu_clock(u32 cpu) +{ + unsigned int reg; + + writel(CPU_CLOCK(cpu), + reg_clk_base + TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); + reg = readl(reg_clk_base + + TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); +} + +static void tegra30_disable_cpu_clock(u32 cpu) +{ + + unsigned int reg; + + reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); + writel(reg | CPU_CLOCK(cpu), + reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); +} + +static struct tegra_cpu_car_ops tegra30_cpu_car_ops = { + .wait_for_reset = tegra30_wait_cpu_in_reset, + .put_in_reset = tegra30_put_cpu_in_reset, + .out_of_reset = tegra30_cpu_out_of_reset, + .enable_clock = tegra30_enable_cpu_clock, + .disable_clock = tegra30_disable_cpu_clock, +}; + +void __init tegra30_cpu_car_ops_init(void) +{ + tegra_cpu_car_ops = &tegra30_cpu_car_ops; +} -- cgit v1.2.1