2015-05-12 17:26:08

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 00/21] Tegra210 Clock Support

This patch series updates the tegra common clock driver and adds
support for the Tegra210 clocks. The clocks in Tegra210 changed
significantly in some ways from earlier generations, so to support
them, we need to extend our base framework a bit and add some new
features.

Some patches here also address issues found while adding features
and other cleanup type work.

Note this series does depend on
"clk: tegra: Fix comments for structure definitions" which has been
reviewed already.

v5:
- Reorderd some patches
- Added Thierry's kerneldoc update patch as dependency

v4:
- Fixed minor checkpatch errors and other typos
- Rebased ontop of linux-next 20150504

v3:
- Added a fix from Andrew Bresticker that was found while testing
this code.

Andrew Bresticker (1):
clk: tegra: pll: Fix issues with rates for VCO PLLs

Bill Huang (7):
clk: tegra: pll-params: change misc_reg count from 3 -> 6
clk: tegra: pll: Add code to handle if resets are supported by PLL
clk: tegra: pll: Adjust vco_min if SDM present
clk: tegra: pll: Add dyn_ramp callback
clk: tegra: pll: Add Set_default logic
clk: tegra: pll: Add logic for SS
clk: tegra: Add Super Gen5 Logic

Rhyland Klein (12):
clk: tegra: Modify tegra_audio_clk_init to accept more plls
clk: tegra: periph: add new periph clks and muxes for Tegra210
clk: tegra: pll: add tegra_pll_wait_for_lock to clk header
clk: tegra: pll: simplify clk_enable_path
clk: tegra: pll: update warning msg
clk: tegra: pll: Don't unconditionally set LOCK flags
clk: tegra: pll: Add logic for handling SDM data
clk: tegra: pll: Add logic for out-of-table rates for T210
clk: tegra: pll: Add specialized logic for T210
clk: tegra: pll: Add support for PLLMB for T210
clk: tegra: pll: Fix _pll_ramp_calc_pll logic and
_calc_dynamic_ramp_rate
clk: tegra210: add support for Tegra210 clocks

Thierry Reding (1):
clk: tegra: Update struct tegra_clk_pll_params kerneldoc

.../bindings/clock/nvidia,tegra210-car.txt | 56 +
drivers/clk/tegra/Makefile | 2 +
drivers/clk/tegra/clk-id.h | 67 +-
drivers/clk/tegra/clk-pll.c | 709 ++++-
drivers/clk/tegra/clk-tegra-audio.c | 25 +-
drivers/clk/tegra/clk-tegra-periph.c | 304 ++-
drivers/clk/tegra/clk-tegra-super-gen5.c | 150 ++
drivers/clk/tegra/clk-tegra114.c | 31 +-
drivers/clk/tegra/clk-tegra124.c | 32 +-
drivers/clk/tegra/clk-tegra20.c | 18 +-
drivers/clk/tegra/clk-tegra210.c | 2792 ++++++++++++++++++++
drivers/clk/tegra/clk-tegra30.c | 32 +-
drivers/clk/tegra/clk.h | 123 +-
include/dt-bindings/clock/tegra210-car.h | 401 +++
14 files changed, 4595 insertions(+), 147 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/nvidia,tegra210-car.txt
create mode 100644 drivers/clk/tegra/clk-tegra-super-gen5.c
create mode 100644 drivers/clk/tegra/clk-tegra210.c
create mode 100644 include/dt-bindings/clock/tegra210-car.h

--
1.7.9.5


2015-05-12 17:33:17

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 01/21] clk: tegra: Update struct tegra_clk_pll_params kerneldoc

From: Thierry Reding <[email protected]>

Benson Leung pointed out that the kerneldoc for this structure has
become stale. Update the field descriptions to match the structure
content.

Reported-by: Benson Leung <[email protected]>
Acked-by: Rhyland Klein <[email protected]>
Signed-off-by: Thierry Reding <[email protected]>
Reviewed-by: Benson Leung <[email protected]>
Signed-off-by: Rhyland Klein <[email protected]>
---
drivers/clk/tegra/clk.h | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 9da799849e04..a4e6c8180968 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -157,7 +157,7 @@ struct div_nmp {
};

/**
- * struct clk_pll_params - PLL parameters
+ * struct tegra_clk_pll_params - PLL parameters
*
* @input_min: Minimum input frequency
* @input_max: Maximum input frequency
@@ -168,12 +168,24 @@ struct div_nmp {
* @base_reg: PLL base reg offset
* @misc_reg: PLL misc reg offset
* @lock_reg: PLL lock reg offset
- * @lock_bit_idx: Bit index for PLL lock status
+ * @lock_mask: Bitmask for PLL lock status
* @lock_enable_bit_idx: Bit index to enable PLL lock
+ * @iddq_reg: PLL IDDQ register offset
+ * @iddq_bit_idx: Bit index to enable PLL IDDQ
+ * @aux_reg: AUX register offset
+ * @dyn_ramp_reg: Dynamic ramp control register offset
+ * @ext_misc_reg: Miscellaneous control register offsets
+ * @pmc_divnm_reg: n, m divider PMC override register offset (PLLM)
+ * @pmc_divp_reg: p divider PMC override register offset (PLLM)
+ * @flags: PLL flags
+ * @stepa_shift: Dynamic ramp step A field shift
+ * @stepb_shift: Dynamic ramp step B field shift
* @lock_delay: Delay in us if PLL lock is not used
+ * @max_p: maximum value for the p divider
+ * @pdiv_tohw: mapping of p divider to register values
+ * @div_nmp: offsets and widths on n, m and p fields
* @freq_table: array of frequencies supported by PLL
* @fixed_rate: PLL rate if it is fixed
- * @flags: PLL flags
*
* Flags:
* TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for
--
1.7.9.5

2015-05-12 17:26:15

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 01/21] FROMLIST: clk: tegra: Update struct tegra_clk_pll_params kerneldoc

From: Thierry Reding <[email protected]>

Benson Leung pointed out that the kerneldoc for this structure has
become stale. Update the field descriptions to match the structure
content.

Reported-by: Benson Leung <[email protected]>
Acked-by: Rhyland Klein <[email protected]>
Signed-off-by: Thierry Reding <[email protected]>
Reviewed-by: Benson Leung <[email protected]>
---
drivers/clk/tegra/clk.h | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 9da799849e04..a4e6c8180968 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -157,7 +157,7 @@ struct div_nmp {
};

/**
- * struct clk_pll_params - PLL parameters
+ * struct tegra_clk_pll_params - PLL parameters
*
* @input_min: Minimum input frequency
* @input_max: Maximum input frequency
@@ -168,12 +168,24 @@ struct div_nmp {
* @base_reg: PLL base reg offset
* @misc_reg: PLL misc reg offset
* @lock_reg: PLL lock reg offset
- * @lock_bit_idx: Bit index for PLL lock status
+ * @lock_mask: Bitmask for PLL lock status
* @lock_enable_bit_idx: Bit index to enable PLL lock
+ * @iddq_reg: PLL IDDQ register offset
+ * @iddq_bit_idx: Bit index to enable PLL IDDQ
+ * @aux_reg: AUX register offset
+ * @dyn_ramp_reg: Dynamic ramp control register offset
+ * @ext_misc_reg: Miscellaneous control register offsets
+ * @pmc_divnm_reg: n, m divider PMC override register offset (PLLM)
+ * @pmc_divp_reg: p divider PMC override register offset (PLLM)
+ * @flags: PLL flags
+ * @stepa_shift: Dynamic ramp step A field shift
+ * @stepb_shift: Dynamic ramp step B field shift
* @lock_delay: Delay in us if PLL lock is not used
+ * @max_p: maximum value for the p divider
+ * @pdiv_tohw: mapping of p divider to register values
+ * @div_nmp: offsets and widths on n, m and p fields
* @freq_table: array of frequencies supported by PLL
* @fixed_rate: PLL rate if it is fixed
- * @flags: PLL flags
*
* Flags:
* TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for
--
1.7.9.5

2015-05-12 17:26:22

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 02/21] clk: tegra: Modify tegra_audio_clk_init to accept more plls

tegra_audio_clk_init was written expecting a single PLL to be
passed in directly. Change this to accept an array which will
allow for supporting multiple plls and specifying specific data
about them, like their parent, which may change over time.

Reviewed-by: Benson Leung <[email protected]>
Signed-off-by: Rhyland Klein <[email protected]>
---
v5:
- changed num_plls to unsigned int from int
- Changed calls to tegra_audio_clk_init to using ARRAY_SIZE
- Fixed incorrect type passed for T114 and T30

drivers/clk/tegra/clk-tegra-audio.c | 25 ++++++++++++++++++-------
drivers/clk/tegra/clk-tegra114.c | 8 +++++++-
drivers/clk/tegra/clk-tegra124.c | 8 +++++++-
drivers/clk/tegra/clk-tegra30.c | 8 +++++++-
drivers/clk/tegra/clk.h | 18 +++++++++++++++++-
5 files changed, 56 insertions(+), 11 deletions(-)

diff --git a/drivers/clk/tegra/clk-tegra-audio.c b/drivers/clk/tegra/clk-tegra-audio.c
index 5c38aab2c5b8..b39874e89502 100644
--- a/drivers/clk/tegra/clk-tegra-audio.c
+++ b/drivers/clk/tegra/clk-tegra-audio.c
@@ -126,18 +126,29 @@ static struct tegra_audio2x_clk_initdata audio2x_clks[] = {

void __init tegra_audio_clk_init(void __iomem *clk_base,
void __iomem *pmc_base, struct tegra_clk *tegra_clks,
- struct tegra_clk_pll_params *pll_a_params)
+ struct tegra_audio_clk_info *audio_info,
+ unsigned int num_plls)
{
struct clk *clk;
struct clk **dt_clk;
int i;

- /* PLLA */
- dt_clk = tegra_lookup_dt_id(tegra_clk_pll_a, tegra_clks);
- if (dt_clk) {
- clk = tegra_clk_register_pll("pll_a", "pll_p_out1", clk_base,
- pmc_base, 0, pll_a_params, NULL);
- *dt_clk = clk;
+ if (!audio_info || num_plls < 1) {
+ pr_err("No audio data passed to tegra_audio_clk_init\n");
+ WARN_ON(1);
+ return;
+ }
+
+ for (i = 0; i < num_plls; i++) {
+ struct tegra_audio_clk_info *info = &audio_info[i];
+
+ dt_clk = tegra_lookup_dt_id(info->clk_id, tegra_clks);
+ if (dt_clk) {
+ clk = tegra_clk_register_pll(info->name, info->parent,
+ clk_base, pmc_base, 0, info->pll_params,
+ NULL);
+ *dt_clk = clk;
+ }
}

/* PLLA_OUT0 */
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 8237d16b4075..d8586bd6afce 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -935,6 +935,10 @@ static u32 mux_pllm_pllc2_c_c3_pllp_plla_idx[] = {
[0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6,
};

+static struct tegra_audio_clk_info tegra114_audio_plls[] = {
+ { "pll_a", &pll_a_params, tegra_clk_pll_a, "pll_p_out1" },
+};
+
static struct clk **clks;

static unsigned long osc_freq;
@@ -1483,7 +1487,9 @@ static void __init tegra114_clock_init(struct device_node *np)
tegra114_fixed_clk_init(clk_base);
tegra114_pll_init(clk_base, pmc_base);
tegra114_periph_clk_init(clk_base, pmc_base);
- tegra_audio_clk_init(clk_base, pmc_base, tegra114_clks, &pll_a_params);
+ tegra_audio_clk_init(clk_base, pmc_base, tegra114_clks,
+ tegra114_audio_plls,
+ ARRAY_SIZE(tegra114_audio_plls));
tegra_pmc_clk_init(pmc_base, tegra114_clks);
tegra_super_clk_gen4_init(clk_base, pmc_base, tegra114_clks,
&pll_x_params);
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index 11f857cd5f6a..5010e43d7785 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -1413,6 +1413,10 @@ static struct tegra_clk_init_table tegra132_init_table[] __initdata = {
{TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
};

+static struct tegra_audio_clk_info tegra124_audio_plls[] = {
+ { "pll_a", &pll_a_params, tegra_clk_pll_a, "pll_p_out1" },
+};
+
/**
* tegra124_clock_apply_init_table - initialize clocks on Tegra124 SoCs
*
@@ -1489,7 +1493,9 @@ static void __init tegra124_132_clock_init_pre(struct device_node *np)
tegra_fixed_clk_init(tegra124_clks);
tegra124_pll_init(clk_base, pmc_base);
tegra124_periph_clk_init(clk_base, pmc_base);
- tegra_audio_clk_init(clk_base, pmc_base, tegra124_clks, &pll_a_params);
+ tegra_audio_clk_init(clk_base, pmc_base, tegra124_clks,
+ tegra124_audio_plls,
+ ARRAY_SIZE(tegra124_audio_plls));
tegra_pmc_clk_init(pmc_base, tegra124_clks);

/* For Tegra124 & Tegra132, PLLD is the only source for DSIA & DSIB */
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 4b26509fc218..105514989f9c 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -1406,6 +1406,10 @@ static const struct of_device_id pmc_match[] __initconst = {
{},
};

+static struct tegra_audio_clk_info tegra30_audio_plls[] = {
+ { "pll_a", &pll_a_params, tegra_clk_pll_a, "pll_p_out1" },
+};
+
static void __init tegra30_clock_init(struct device_node *np)
{
struct device_node *node;
@@ -1443,7 +1447,9 @@ static void __init tegra30_clock_init(struct device_node *np)
tegra30_pll_init();
tegra30_super_clk_init();
tegra30_periph_clk_init();
- tegra_audio_clk_init(clk_base, pmc_base, tegra30_clks, &pll_a_params);
+ tegra_audio_clk_init(clk_base, pmc_base, tegra30_clks,
+ tegra30_audio_plls,
+ ARRAY_SIZE(tegra30_audio_plls));
tegra_pmc_clk_init(pmc_base, tegra30_clks);

tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA30_CLK_CLK_MAX);
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index a4e6c8180968..4a37a0d38624 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -270,6 +270,21 @@ struct tegra_clk_pll {

#define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw)

+/**
+ * struct tegra_audio_clk_info - Tegra Audio Clk Information
+ *
+ * @name: name for the audio pll
+ * @pll_params: pll_params for audio pll
+ * @clk_id: clk_ids for the audio pll
+ * @parent: name of the parent of the audio pll
+ */
+struct tegra_audio_clk_info {
+ char *name;
+ struct tegra_clk_pll_params *pll_params;
+ int clk_id;
+ char *parent;
+};
+
extern const struct clk_ops tegra_clk_pll_ops;
extern const struct clk_ops tegra_clk_plle_ops;
struct clk *tegra_clk_register_pll(const char *name, const char *parent_name,
@@ -619,7 +634,8 @@ void tegra_register_devclks(struct tegra_devclk *dev_clks, int num);

void tegra_audio_clk_init(void __iomem *clk_base,
void __iomem *pmc_base, struct tegra_clk *tegra_clks,
- struct tegra_clk_pll_params *pll_params);
+ struct tegra_audio_clk_info *audio_info,
+ unsigned int num_plls);

void tegra_periph_clk_init(void __iomem *clk_base, void __iomem *pmc_base,
struct tegra_clk *tegra_clks,
--
1.7.9.5

2015-05-12 17:26:26

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 03/21] clk: tegra: periph: add new periph clks and muxes for Tegra210

Tegra210 has significant differences in muxes for peripheral clocks.
One of the most important changes is that pll_m isn't to be used
as a source for peripherals. Therefore, we need to define the new
muxes and new clocks to use those muxes for Tegra210 support.

Including work by Andrew Bresticker <[email protected]>.

Signed-off-by: Rhyland Klein <[email protected]>
---
v5:
- Added usb2_hsic_trk, hsic_trk, and usb2_trk clks
- fixed sor1 mux to use pll_d2_out0
- Added div clk support

drivers/clk/tegra/clk-id.h | 60 ++++++-
drivers/clk/tegra/clk-tegra-periph.c | 304 +++++++++++++++++++++++++++++++++-
2 files changed, 362 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h
index 60738cc954cb..768c913e5bdc 100644
--- a/drivers/clk/tegra/clk-id.h
+++ b/drivers/clk/tegra/clk-id.h
@@ -13,6 +13,7 @@ enum clk_id {
tegra_clk_amx1,
tegra_clk_apbdma,
tegra_clk_apbif,
+ tegra_clk_ape,
tegra_clk_audio0,
tegra_clk_audio0_2x,
tegra_clk_audio0_mux,
@@ -38,6 +39,7 @@ enum clk_id {
tegra_clk_cile,
tegra_clk_clk_32k,
tegra_clk_clk72Mhz,
+ tegra_clk_clk72Mhz_8,
tegra_clk_clk_m,
tegra_clk_clk_m_div2,
tegra_clk_clk_m_div4,
@@ -51,17 +53,21 @@ enum clk_id {
tegra_clk_cml1,
tegra_clk_csi,
tegra_clk_csite,
+ tegra_clk_csite_8,
tegra_clk_csus,
tegra_clk_cve,
tegra_clk_dam0,
tegra_clk_dam1,
tegra_clk_dam2,
tegra_clk_d_audio,
+ tegra_clk_dbgapb,
tegra_clk_dds,
tegra_clk_dfll_ref,
tegra_clk_dfll_soc,
tegra_clk_disp1,
+ tegra_clk_disp1_8,
tegra_clk_disp2,
+ tegra_clk_disp2_8,
tegra_clk_dp2,
tegra_clk_dpaux,
tegra_clk_dsialp,
@@ -71,6 +77,7 @@ enum clk_id {
tegra_clk_dtv,
tegra_clk_emc,
tegra_clk_entropy,
+ tegra_clk_entropy_8,
tegra_clk_epp,
tegra_clk_epp_8,
tegra_clk_extern1,
@@ -85,12 +92,16 @@ enum clk_id {
tegra_clk_gr3d_8,
tegra_clk_hclk,
tegra_clk_hda,
+ tegra_clk_hda_8,
tegra_clk_hda2codec_2x,
+ tegra_clk_hda2codec_2x_8,
tegra_clk_hda2hdmi,
tegra_clk_hdmi,
tegra_clk_hdmi_audio,
tegra_clk_host1x,
tegra_clk_host1x_8,
+ tegra_clk_host1x_9,
+ tegra_clk_hsic_trk,
tegra_clk_i2c1,
tegra_clk_i2c2,
tegra_clk_i2c3,
@@ -110,11 +121,14 @@ enum clk_id {
tegra_clk_i2s4_sync,
tegra_clk_isp,
tegra_clk_isp_8,
+ tegra_clk_isp_9,
tegra_clk_ispb,
tegra_clk_kbc,
tegra_clk_kfuse,
tegra_clk_la,
+ tegra_clk_maud,
tegra_clk_mipi,
+ tegra_clk_mipibif,
tegra_clk_mipi_cal,
tegra_clk_mpe,
tegra_clk_mselect,
@@ -124,11 +138,16 @@ enum clk_id {
tegra_clk_ndspeed,
tegra_clk_ndspeed_8,
tegra_clk_nor,
+ tegra_clk_nvdec,
+ tegra_clk_nvenc,
+ tegra_clk_nvjpg,
tegra_clk_owr,
+ tegra_clk_owr_8,
tegra_clk_pcie,
tegra_clk_pclk,
tegra_clk_pll_a,
tegra_clk_pll_a_out0,
+ tegra_clk_pll_a1,
tegra_clk_pll_c,
tegra_clk_pll_c2,
tegra_clk_pll_c3,
@@ -140,8 +159,10 @@ enum clk_id {
tegra_clk_pll_d_out0,
tegra_clk_pll_dp,
tegra_clk_pll_e_out0,
+ tegra_clk_pll_g_ref,
tegra_clk_pll_m,
tegra_clk_pll_m_out1,
+ tegra_clk_pll_mb,
tegra_clk_pll_p,
tegra_clk_pll_p_out1,
tegra_clk_pll_p_out2,
@@ -160,53 +181,80 @@ enum clk_id {
tegra_clk_pll_x,
tegra_clk_pll_x_out0,
tegra_clk_pwm,
+ tegra_clk_qspi,
tegra_clk_rtc,
tegra_clk_sata,
+ tegra_clk_sata_8,
tegra_clk_sata_cold,
tegra_clk_sata_oob,
+ tegra_clk_sata_oob_8,
tegra_clk_sbc1,
tegra_clk_sbc1_8,
+ tegra_clk_sbc1_9,
tegra_clk_sbc2,
tegra_clk_sbc2_8,
+ tegra_clk_sbc2_9,
tegra_clk_sbc3,
tegra_clk_sbc3_8,
+ tegra_clk_sbc3_9,
tegra_clk_sbc4,
tegra_clk_sbc4_8,
+ tegra_clk_sbc4_9,
tegra_clk_sbc5,
tegra_clk_sbc5_8,
tegra_clk_sbc6,
tegra_clk_sbc6_8,
tegra_clk_sclk,
+ tegra_clk_sdmmc_legacy,
tegra_clk_sdmmc1,
tegra_clk_sdmmc1_8,
+ tegra_clk_sdmmc1_9,
tegra_clk_sdmmc2,
tegra_clk_sdmmc2_8,
+ tegra_clk_sdmmc2_9,
tegra_clk_sdmmc3,
tegra_clk_sdmmc3_8,
+ tegra_clk_sdmmc3_9,
tegra_clk_sdmmc4,
tegra_clk_sdmmc4_8,
+ tegra_clk_sdmmc4_9,
tegra_clk_se,
tegra_clk_soc_therm,
+ tegra_clk_soc_therm_8,
tegra_clk_sor0,
tegra_clk_sor0_lvds,
+ tegra_clk_sor1,
+ tegra_clk_sor1_brick,
+ tegra_clk_sor1_src,
tegra_clk_spdif,
tegra_clk_spdif_2x,
tegra_clk_spdif_in,
+ tegra_clk_spdif_in_8,
tegra_clk_spdif_in_sync,
tegra_clk_spdif_mux,
tegra_clk_spdif_out,
tegra_clk_timer,
tegra_clk_trace,
tegra_clk_tsec,
+ tegra_clk_tsec_8,
+ tegra_clk_tsecb,
tegra_clk_tsensor,
tegra_clk_tvdac,
tegra_clk_tvo,
tegra_clk_uarta,
+ tegra_clk_uarta_8,
tegra_clk_uartb,
+ tegra_clk_uartb_8,
tegra_clk_uartc,
+ tegra_clk_uartc_8,
tegra_clk_uartd,
+ tegra_clk_uartd_8,
tegra_clk_uarte,
+ tegra_clk_uarte_8,
+ tegra_clk_uartape,
tegra_clk_usb2,
+ tegra_clk_usb2_hsic_trk,
+ tegra_clk_usb2_trk,
tegra_clk_usb3,
tegra_clk_usbd,
tegra_clk_vcp,
@@ -216,22 +264,32 @@ enum clk_id {
tegra_clk_vi,
tegra_clk_vi_8,
tegra_clk_vi_9,
+ tegra_clk_vi_10,
+ tegra_clk_vi_i2c,
tegra_clk_vic03,
+ tegra_clk_vic03_8,
tegra_clk_vim2_clk,
tegra_clk_vimclk_sync,
tegra_clk_vi_sensor,
- tegra_clk_vi_sensor2,
tegra_clk_vi_sensor_8,
+ tegra_clk_vi_sensor_9,
+ tegra_clk_vi_sensor2,
+ tegra_clk_vi_sensor2_8,
tegra_clk_xusb_dev,
tegra_clk_xusb_dev_src,
+ tegra_clk_xusb_dev_src_8,
tegra_clk_xusb_falcon_src,
+ tegra_clk_xusb_falcon_src_8,
tegra_clk_xusb_fs_src,
tegra_clk_xusb_host,
tegra_clk_xusb_host_src,
+ tegra_clk_xusb_host_src_8,
tegra_clk_xusb_hs_src,
tegra_clk_xusb_ss,
tegra_clk_xusb_ss_src,
+ tegra_clk_xusb_ss_src_8,
tegra_clk_xusb_ss_div2,
+ tegra_clk_sclk_mux,
tegra_clk_max,
};

diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c
index 46af9244ba74..7dddefeaf1c7 100644
--- a/drivers/clk/tegra/clk-tegra-periph.c
+++ b/drivers/clk/tegra/clk-tegra-periph.c
@@ -125,6 +125,20 @@
#define CLK_SOURCE_HDMI_AUDIO 0x668
#define CLK_SOURCE_VIC03 0x678
#define CLK_SOURCE_CLK72MHZ 0x66c
+#define CLK_SOURCE_DBGAPB 0x718
+#define CLK_SOURCE_NVENC 0x6a0
+#define CLK_SOURCE_NVDEC 0x698
+#define CLK_SOURCE_NVJPG 0x69c
+#define CLK_SOURCE_APE 0x6c0
+#define CLK_SOURCE_SOR1 0x410
+#define CLK_SOURCE_SDMMC_LEGACY 0x694
+#define CLK_SOURCE_QSPI 0x6c4
+#define CLK_SOURCE_VI_I2C 0x6c8
+#define CLK_SOURCE_MIPIBIF 0x660
+#define CLK_SOURCE_UARTAPE 0x710
+#define CLK_SOURCE_TSECB 0x6d8
+#define CLK_SOURCE_MAUD 0x6d4
+#define CLK_SOURCE_USB2_HSIC_TRK 0x6cc

#define MASK(x) (BIT(x) - 1)

@@ -183,6 +197,13 @@
TEGRA_DIVIDER_ROUND_UP, _clk_num, 0, _clk_id,\
_parents##_idx, 0, NULL)

+#define UART8(_name, _parents, _offset,\
+ _clk_num, _clk_id) \
+ TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\
+ 29, MASK(3), 0, 0, 16, 1, TEGRA_DIVIDER_UART| \
+ TEGRA_DIVIDER_ROUND_UP, _clk_num, 0, _clk_id,\
+ _parents##_idx, 0, NULL)
+
#define I2C(_name, _parents, _offset,\
_clk_num, _clk_id) \
TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\
@@ -222,6 +243,18 @@
.flags = _flags \
}

+#define DIV8(_name, _parent_name, _offset, _clk_id, _flags) \
+ { \
+ .name = _name, \
+ .clk_id = _clk_id, \
+ .p.parent_name = _parent_name, \
+ .periph = TEGRA_CLK_PERIPH(0, 0, 0, 0, 8, 1, \
+ TEGRA_DIVIDER_ROUND_UP, 0, 0, \
+ NULL, NULL), \
+ .offset = _offset, \
+ .flags = _flags, \
+ }
+
#define PLLP_BASE 0xa0
#define PLLP_MISC 0xac
#define PLLP_OUTA 0xa4
@@ -235,6 +268,7 @@ static DEFINE_SPINLOCK(PLLP_OUTA_lock);
static DEFINE_SPINLOCK(PLLP_OUTB_lock);
static DEFINE_SPINLOCK(PLLP_OUTC_lock);
static DEFINE_SPINLOCK(sor0_lock);
+static DEFINE_SPINLOCK(sor1_lock);

#define MUX_I2S_SPDIF(_id) \
static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = { "pll_a_out0", \
@@ -286,6 +320,68 @@ static u32 mux_pllp_clkm_idx[] = {
[0] = 0, [1] = 3,
};

+static const char *mux_pllp_clkm_2[] = {
+ "pll_p", "clk_m"
+};
+static u32 mux_pllp_clkm_2_idx[] = {
+ [0] = 2, [1] = 6,
+};
+
+static const char *mux_pllc2_c_c3_pllp_plla1_clkm[] = {
+ "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a1", "clk_m"
+};
+static u32 mux_pllc2_c_c3_pllp_plla1_clkm_idx[] = {
+ [0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 6, [5] = 7,
+};
+
+static const char *
+mux_pllc4_out1_pllc_pllc4_out2_pllp_clkm_plla_pllc4_out0[] = {
+ "pll_c4_out1", "pll_c", "pll_c4_out2", "pll_p", "clk_m",
+ "pll_a_out0", "pll_c4_out0"
+};
+static u32 mux_pllc4_out1_pllc_pllc4_out2_pllp_clkm_plla_pllc4_out0_idx[] = {
+ [0] = 0, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6, [6] = 7,
+};
+
+static const char *mux_pllc_pllp_plla[] = {
+ "pll_c", "pll_p", "pll_a_out0"
+};
+static u32 mux_pllc_pllp_plla_idx[] = {
+ [0] = 1, [1] = 2, [2] = 3,
+};
+
+static const char *mux_clkm_pllc_pllp_plla[] = {
+ "clk_m", "pll_c", "pll_p", "pll_a_out0"
+};
+#define mux_clkm_pllc_pllp_plla_idx NULL
+
+static const char *mux_pllc_pllp_plla1_pllc2_c3_clkm[] = {
+ "pll_c", "pll_p", "pll_a1", "pll_c2", "pll_c3", "clk_m"
+};
+static u32 mux_pllc_pllp_plla1_pllc2_c3_clkm_idx[] = {
+ [0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6,
+};
+
+static const char *mux_pllc2_c_c3_pllp_clkm_plla1_pllc4[] = {
+ "pll_c2", "pll_c", "pll_c3", "pll_p", "clk_m", "pll_a1", "pll_c4_out0",
+};
+static u32 mux_pllc2_c_c3_pllp_clkm_plla1_pllc4_idx[] = {
+ [0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6, [6] = 7,
+};
+
+static const char *mux_pllc_pllp_plla1_pllc2_c3_clkm_pllc4[] = {
+ "pll_c", "pll_p", "pll_a1", "pll_c2", "pll_c3", "clk_m", "pll_c4_out0",
+};
+#define mux_pllc_pllp_plla1_pllc2_c3_clkm_pllc4_idx \
+ mux_pllc2_c_c3_pllp_clkm_plla1_pllc4_idx
+
+static const char *
+mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm[] = {
+ "pll_a_out0", "pll_c4_out0", "pll_c", "pll_c4_out1", "pll_p",
+ "pll_c4_out2", "clk_m"
+};
+#define mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm_idx NULL
+
static const char *mux_pllm_pllc2_c_c3_pllp_plla[] = {
"pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0"
};
@@ -303,12 +399,93 @@ static const char *mux_pllm_pllc_pllp_plla[] = {
#define mux_pllm_pllc_pllp_plla_idx mux_pllp_pllc_pllm_clkm_idx

static const char *mux_pllp_pllc_clkm[] = {
- "pll_p", "pll_c", "pll_m"
+ "pll_p", "pll_c", "clk_m"
};
static u32 mux_pllp_pllc_clkm_idx[] = {
[0] = 0, [1] = 1, [2] = 3,
};

+static const char *mux_pllp_pllc_clkm_1[] = {
+ "pll_p", "pll_c", "clk_m"
+};
+static u32 mux_pllp_pllc_clkm_1_idx[] = {
+ [0] = 0, [1] = 2, [2] = 5,
+};
+
+static const char *mux_pllp_pllc_plla_clkm[] = {
+ "pll_p", "pll_c", "pll_a_out0", "clk_m"
+};
+static u32 mux_pllp_pllc_plla_clkm_idx[] = {
+ [0] = 0, [1] = 2, [2] = 4, [3] = 6,
+};
+
+static const char *mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2[] = {
+ "pll_p", "pll_c", "pll_c4_out0", "pll_c4_out1", "clk_m", "pll_c4_out2"
+};
+static u32 mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2_idx[] = {
+ [0] = 0, [1] = 2, [2] = 3, [3] = 5, [4] = 6, [5] = 7,
+};
+
+static const char *
+mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0[] = {
+ "pll_p", "pll_c_out1", "pll_c", "pll_c4_out2", "pll_c4_out1",
+ "clk_m", "pll_c4_out0"
+};
+static u32
+mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0_idx[] = {
+ [0] = 0, [1] = 1, [2] = 2, [3] = 4, [4] = 5, [5] = 6, [6] = 7,
+};
+
+static const char *mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0[] = {
+ "pll_p", "pll_c4_out2", "pll_c4_out1", "clk_m", "pll_c4_out0"
+};
+static u32 mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0_idx[] = {
+ [0] = 0, [1] = 3, [2] = 4, [3] = 6, [4] = 7,
+};
+
+static const char *mux_pllp_clkm_pllc4_out2_out1_out0_lj[] = {
+ "pll_p",
+ "pll_c4_out2", "pll_c4_out0", /* LJ input */
+ "pll_c4_out2", "pll_c4_out1",
+ "pll_c4_out1", /* LJ input */
+ "clk_m", "pll_c4_out0"
+};
+#define mux_pllp_clkm_pllc4_out2_out1_out0_lj_idx NULL
+
+static const char *mux_pllp_pllc2_c_c3_clkm[] = {
+ "pll_p", "pll_c2", "pll_c", "pll_c3", "clk_m"
+};
+static u32 mux_pllp_pllc2_c_c3_clkm_idx[] = {
+ [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 6,
+};
+
+static const char *mux_pllp_clkm_clk32_plle[] = {
+ "pll_p", "clk_m", "clk_32k", "pll_e"
+};
+static u32 mux_pllp_clkm_clk32_plle_idx[] = {
+ [0] = 0, [1] = 2, [2] = 4, [3] = 6,
+};
+
+static const char *mux_pllp_pllp_out3_clkm_clk32k_plla[] = {
+ "pll_p", "pll_p_out3", "clk_m", "clk_32k", "pll_a_out0"
+};
+#define mux_pllp_pllp_out3_clkm_clk32k_plla_idx NULL
+
+static const char *mux_pllp_out3_clkm_pllp_pllc4[] = {
+ "pll_p_out3", "clk_m", "pll_p", "pll_c4_out0", "pll_c4_out1",
+ "pll_c4_out2"
+};
+static u32 mux_pllp_out3_clkm_pllp_pllc4_idx[] = {
+ [0] = 0, [1] = 3, [2] = 4, [3] = 5, [4] = 6, [5] = 7,
+};
+
+static const char *mux_clkm_pllp_pllre[] = {
+ "clk_m", "pll_p_out_xusb", "pll_re_out"
+};
+static u32 mux_clkm_pllp_pllre_idx[] = {
+ [0] = 0, [1] = 1, [2] = 5,
+};
+
static const char *mux_pllp_pllc_clkm_clk32[] = {
"pll_p", "pll_c", "clk_m", "clk_32k"
};
@@ -333,6 +510,11 @@ static u32 mux_clkm_48M_pllp_480M_idx[] = {
[0] = 0, [1] = 2, [2] = 4, [3] = 6,
};

+static const char *mux_clkm_pllre_clk32_480M[] = {
+ "clk_m", "pll_re_out", "clk_32k", "pll_u_480M"
+};
+#define mux_clkm_pllre_clk32_480M_idx NULL
+
static const char *mux_clkm_pllre_clk32_480M_pllc_ref[] = {
"clk_m", "pll_re_out", "clk_32k", "pll_u_480M", "pll_c", "pll_ref"
};
@@ -340,6 +522,13 @@ static u32 mux_clkm_pllre_clk32_480M_pllc_ref_idx[] = {
[0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 4, [5] = 7,
};

+static const char *mux_pllp_out3_pllp_pllc_clkm[] = {
+ "pll_p_out3", "pll_p", "pll_c", "clk_m"
+};
+static u32 mux_pllp_out3_pllp_pllc_clkm_idx[] = {
+ [0] = 0, [1] = 1, [2] = 2, [3] = 6,
+};
+
static const char *mux_ss_60M[] = {
"xusb_ss_div2", "pll_u_60M"
};
@@ -387,6 +576,32 @@ static u32 mux_pllm_pllc2_c_c3_pllp_plla_pllc4_idx[] = {
[0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6, [6] = 7,
};

+/* SOR1 mux'es */
+static const char *mux_pllp_plld_plld2_clkm[] = {
+ "pll_p", "pll_d_out0", "pll_d2_out0", "clk_m"
+};
+static u32 mux_pllp_plld_plld2_clkm_idx[] = {
+ [0] = 0, [1] = 2, [2] = 5, [3] = 6
+};
+
+static const char *mux_plldp_sor1_src[] = {
+ "pll_dp", "clk_sor1_src"
+};
+#define mux_plldp_sor1_src_idx NULL
+
+static const char *mux_clkm_sor1_brick_sor1_src[] = {
+ "clk_m", "sor1_brick", "sor1_src", "sor1_brick"
+};
+#define mux_clkm_sor1_brick_sor1_src_idx NULL
+
+static const char *mux_pllp_pllre_clkm[] = {
+ "pll_p", "pll_re_out1", "clk_m"
+};
+
+static u32 mux_pllp_pllre_clkm_idx[] = {
+ [0] = 0, [1] = 2, [2] = 3,
+};
+
static const char *mux_clkm_plldp_sor0lvds[] = {
"clk_m", "pll_dp", "sor0_lvds",
};
@@ -402,6 +617,7 @@ static struct tegra_periph_init_data periph_clks[] = {
I2C("i2c3", mux_pllp_clkm, CLK_SOURCE_I2C3, 67, tegra_clk_i2c3),
I2C("i2c4", mux_pllp_clkm, CLK_SOURCE_I2C4, 103, tegra_clk_i2c4),
I2C("i2c5", mux_pllp_clkm, CLK_SOURCE_I2C5, 47, tegra_clk_i2c5),
+ I2C("i2c6", mux_pllp_clkm, CLK_SOURCE_I2C6, 166, tegra_clk_i2c6),
INT("vde", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VDE, 61, 0, tegra_clk_vde),
INT("vi", mux_pllm_pllc_pllp_plla, CLK_SOURCE_VI, 20, 0, tegra_clk_vi),
INT("epp", mux_pllm_pllc_pllp_plla, CLK_SOURCE_EPP, 19, 0, tegra_clk_epp),
@@ -412,14 +628,19 @@ static struct tegra_periph_init_data periph_clks[] = {
INT8("vde", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_VDE, 61, 0, tegra_clk_vde_8),
INT8("vi", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI, 20, 0, tegra_clk_vi_8),
INT8("vi", mux_pllm_pllc2_c_c3_pllp_plla_pllc4, CLK_SOURCE_VI, 20, 0, tegra_clk_vi_9),
+ INT8("vi", mux_pllc2_c_c3_pllp_clkm_plla1_pllc4, CLK_SOURCE_VI, 20, 0, tegra_clk_vi_10),
INT8("epp", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_EPP, 19, 0, tegra_clk_epp_8),
INT8("msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, TEGRA_PERIPH_WAR_1005168, tegra_clk_msenc),
INT8("tsec", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_TSEC, 83, 0, tegra_clk_tsec),
+ INT("tsec", mux_pllp_pllc_clkm, CLK_SOURCE_TSEC, 83, 0, tegra_clk_tsec_8),
INT8("host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x_8),
+ INT8("host1x", mux_pllc4_out1_pllc_pllc4_out2_pllp_clkm_plla_pllc4_out0, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x_9),
INT8("se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se),
+ INT8("se", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se),
INT8("2d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_2D, 21, 0, tegra_clk_gr2d_8),
INT8("3d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_3D, 24, 0, tegra_clk_gr3d_8),
INT8("vic03", mux_pllm_pllc_pllp_plla_pllc2_c3_clkm, CLK_SOURCE_VIC03, 178, 0, tegra_clk_vic03),
+ INT8("vic03", mux_pllc_pllp_plla1_pllc2_c3_clkm, CLK_SOURCE_VIC03, 178, 0, tegra_clk_vic03_8),
INT_FLAGS("mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, 0, tegra_clk_mselect, CLK_IGNORE_UNUSED),
MUX("i2s0", mux_pllaout0_audio0_2x_pllp_clkm, CLK_SOURCE_I2S0, 30, TEGRA_PERIPH_ON_APB, tegra_clk_i2s0),
MUX("i2s1", mux_pllaout0_audio1_2x_pllp_clkm, CLK_SOURCE_I2S1, 11, TEGRA_PERIPH_ON_APB, tegra_clk_i2s1),
@@ -428,22 +649,31 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX("i2s4", mux_pllaout0_audio4_2x_pllp_clkm, CLK_SOURCE_I2S4, 102, TEGRA_PERIPH_ON_APB, tegra_clk_i2s4),
MUX("spdif_out", mux_pllaout0_audio_2x_pllp_clkm, CLK_SOURCE_SPDIF_OUT, 10, TEGRA_PERIPH_ON_APB, tegra_clk_spdif_out),
MUX("spdif_in", mux_pllp_pllc_pllm, CLK_SOURCE_SPDIF_IN, 10, TEGRA_PERIPH_ON_APB, tegra_clk_spdif_in),
+ MUX8("spdif_in", mux_pllp_pllc_clkm_1, CLK_SOURCE_SPDIF_IN, 10, TEGRA_PERIPH_ON_APB, tegra_clk_spdif_in_8),
MUX("pwm", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_PWM, 17, TEGRA_PERIPH_ON_APB, tegra_clk_pwm),
MUX("adx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX, 154, TEGRA_PERIPH_ON_APB, tegra_clk_adx),
MUX("amx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX, 153, TEGRA_PERIPH_ON_APB, tegra_clk_amx),
MUX("hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA, 125, TEGRA_PERIPH_ON_APB, tegra_clk_hda),
+ MUX("hda", mux_pllp_pllc_clkm, CLK_SOURCE_HDA, 125, TEGRA_PERIPH_ON_APB, tegra_clk_hda_8),
MUX("hda2codec_2x", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, TEGRA_PERIPH_ON_APB, tegra_clk_hda2codec_2x),
+ MUX8("hda2codec_2x", mux_pllp_pllc_plla_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, TEGRA_PERIPH_ON_APB, tegra_clk_hda2codec_2x_8),
MUX("vfir", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VFIR, 7, TEGRA_PERIPH_ON_APB, tegra_clk_vfir),
MUX("sdmmc1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1),
MUX("sdmmc2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2),
MUX("sdmmc3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3),
MUX("sdmmc4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4),
+ MUX8("sdmmc1", mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1_9),
+ MUX8("sdmmc2", mux_pllp_clkm_pllc4_out2_out1_out0_lj, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2_9),
+ MUX8("sdmmc3", mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3_9),
+ MUX8("sdmmc4", mux_pllp_clkm_pllc4_out2_out1_out0_lj, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4_9),
MUX("la", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_LA, 76, TEGRA_PERIPH_ON_APB, tegra_clk_la),
MUX("trace", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_TRACE, 77, TEGRA_PERIPH_ON_APB, tegra_clk_trace),
MUX("owr", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_OWR, 71, TEGRA_PERIPH_ON_APB, tegra_clk_owr),
+ MUX("owr", mux_pllp_pllc_clkm, CLK_SOURCE_OWR, 71, TEGRA_PERIPH_ON_APB, tegra_clk_owr_8),
MUX("nor", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NOR, 42, 0, tegra_clk_nor),
MUX("mipi", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_MIPI, 50, TEGRA_PERIPH_ON_APB, tegra_clk_mipi),
MUX("vi_sensor", mux_pllm_pllc_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor),
+ MUX("vi_sensor", mux_pllc_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor_9),
MUX("cilab", mux_pllp_pllc_clkm, CLK_SOURCE_CILAB, 144, 0, tegra_clk_cilab),
MUX("cilcd", mux_pllp_pllc_clkm, CLK_SOURCE_CILCD, 145, 0, tegra_clk_cilcd),
MUX("cile", mux_pllp_pllc_clkm, CLK_SOURCE_CILE, 146, 0, tegra_clk_cile),
@@ -466,10 +696,13 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX("ndflash", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NDFLASH, 13, TEGRA_PERIPH_ON_APB, tegra_clk_ndflash),
MUX("ndspeed", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NDSPEED, 80, TEGRA_PERIPH_ON_APB, tegra_clk_ndspeed),
MUX("sata_oob", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SATA_OOB, 123, TEGRA_PERIPH_ON_APB, tegra_clk_sata_oob),
+ MUX("sata_oob", mux_pllp_pllc_clkm, CLK_SOURCE_SATA_OOB, 123, TEGRA_PERIPH_ON_APB, tegra_clk_sata_oob_8),
MUX("sata", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SATA, 124, TEGRA_PERIPH_ON_APB, tegra_clk_sata),
+ MUX("sata", mux_pllp_pllc_clkm, CLK_SOURCE_SATA, 124, TEGRA_PERIPH_ON_APB, tegra_clk_sata_8),
MUX("adx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX1, 180, TEGRA_PERIPH_ON_APB, tegra_clk_adx1),
MUX("amx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX1, 185, TEGRA_PERIPH_ON_APB, tegra_clk_amx1),
MUX("vi_sensor2", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR2, 165, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2),
+ MUX("vi_sensor2", mux_pllc_pllp_plla, CLK_SOURCE_VI_SENSOR2, 165, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2_8),
MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1_8),
MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2_8),
MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3_8),
@@ -480,6 +713,10 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX8("sbc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC4, 68, TEGRA_PERIPH_ON_APB, tegra_clk_sbc4_8),
MUX8("sbc5", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC5, 104, TEGRA_PERIPH_ON_APB, tegra_clk_sbc5_8),
MUX8("sbc6", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC6, 105, TEGRA_PERIPH_ON_APB, tegra_clk_sbc6_8),
+ MUX("sbc1", mux_pllp_pllc_clkm, CLK_SOURCE_SBC1, 41, TEGRA_PERIPH_ON_APB, tegra_clk_sbc1_9),
+ MUX("sbc2", mux_pllp_pllc_clkm, CLK_SOURCE_SBC2, 44, TEGRA_PERIPH_ON_APB, tegra_clk_sbc2_9),
+ MUX("sbc3", mux_pllp_pllc_clkm, CLK_SOURCE_SBC3, 46, TEGRA_PERIPH_ON_APB, tegra_clk_sbc3_9),
+ MUX("sbc4", mux_pllp_pllc_clkm, CLK_SOURCE_SBC4, 68, TEGRA_PERIPH_ON_APB, tegra_clk_sbc4_9),
MUX8("ndflash", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDFLASH, 13, TEGRA_PERIPH_ON_APB, tegra_clk_ndflash_8),
MUX8("ndspeed", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDSPEED, 80, TEGRA_PERIPH_ON_APB, tegra_clk_ndspeed_8),
MUX8("hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, 0, tegra_clk_hdmi),
@@ -487,27 +724,57 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX8("extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, 0, tegra_clk_extern2),
MUX8("extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, 0, tegra_clk_extern3),
MUX8("soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm),
+ MUX8("soc_therm", mux_clkm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm_8),
MUX8("vi_sensor", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 164, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor_8),
MUX8("isp", mux_pllm_pllc_pllp_plla_clkm_pllc4, CLK_SOURCE_ISP, 23, TEGRA_PERIPH_ON_APB, tegra_clk_isp_8),
+ MUX8("isp", mux_pllc_pllp_plla1_pllc2_c3_clkm_pllc4, CLK_SOURCE_ISP, 23, TEGRA_PERIPH_ON_APB, tegra_clk_isp_9),
MUX8("entropy", mux_pllp_clkm1, CLK_SOURCE_ENTROPY, 149, 0, tegra_clk_entropy),
+ MUX8("entropy", mux_pllp_clkm_clk32_plle, CLK_SOURCE_ENTROPY, 149, 0, tegra_clk_entropy_8),
MUX8("hdmi_audio", mux_pllp3_pllc_clkm, CLK_SOURCE_HDMI_AUDIO, 176, TEGRA_PERIPH_NO_RESET, tegra_clk_hdmi_audio),
MUX8("clk72mhz", mux_pllp3_pllc_clkm, CLK_SOURCE_CLK72MHZ, 177, TEGRA_PERIPH_NO_RESET, tegra_clk_clk72Mhz),
+ MUX8("clk72mhz", mux_pllp_out3_pllp_pllc_clkm, CLK_SOURCE_CLK72MHZ, 177, TEGRA_PERIPH_NO_RESET, tegra_clk_clk72Mhz_8),
MUX8_NOGATE_LOCK("sor0_lvds", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_SOR0, tegra_clk_sor0_lvds, &sor0_lock),
MUX_FLAGS("csite", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_CSITE, 73, TEGRA_PERIPH_ON_APB, tegra_clk_csite, CLK_IGNORE_UNUSED),
+ MUX_FLAGS("csite", mux_pllp_pllre_clkm, CLK_SOURCE_CSITE, 73, TEGRA_PERIPH_ON_APB, tegra_clk_csite_8, CLK_IGNORE_UNUSED),
NODIV("disp1", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP1, 29, 7, 27, 0, tegra_clk_disp1, NULL),
+ NODIV("disp1", mux_pllp_plld_plld2_clkm, CLK_SOURCE_DISP1, 29, 7, 27, 0, tegra_clk_disp1_8, NULL),
NODIV("disp2", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP2, 29, 7, 26, 0, tegra_clk_disp2, NULL),
+ NODIV("disp2", mux_pllp_plld_plld2_clkm, CLK_SOURCE_DISP2, 29, 7, 26, 0, tegra_clk_disp2_8, NULL),
NODIV("sor0", mux_clkm_plldp_sor0lvds, CLK_SOURCE_SOR0, 14, 3, 182, 0, tegra_clk_sor0, &sor0_lock),
UART("uarta", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTA, 6, tegra_clk_uarta),
UART("uartb", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTB, 7, tegra_clk_uartb),
UART("uartc", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTC, 55, tegra_clk_uartc),
UART("uartd", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTD, 65, tegra_clk_uartd),
UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 66, tegra_clk_uarte),
+ UART8("uarta", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTA, 6, tegra_clk_uarta_8),
+ UART8("uartb", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTB, 7, tegra_clk_uartb_8),
+ UART8("uartc", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTC, 55, tegra_clk_uartc_8),
+ UART8("uartd", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTD, 65, tegra_clk_uartd_8),
XUSB("xusb_host_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_host_src),
+ XUSB("xusb_host_src", mux_clkm_pllp_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_host_src_8),
XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src),
+ XUSB("xusb_falcon_src", mux_clkm_pllp_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src_8),
XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src),
XUSB("xusb_ss_src", mux_clkm_pllre_clk32_480M_pllc_ref, CLK_SOURCE_XUSB_SS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ss_src),
+ XUSB("xusb_ss_src", mux_clkm_pllre_clk32_480M, CLK_SOURCE_XUSB_SS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ss_src_8),
NODIV("xusb_hs_src", mux_ss_60M, CLK_SOURCE_XUSB_SS_SRC, 25, MASK(1), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_hs_src, NULL),
XUSB("xusb_dev_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src),
+ XUSB("xusb_dev_src", mux_clkm_pllp_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src_8),
+ MUX8("dbgapb", mux_pllp_clkm_2, CLK_SOURCE_DBGAPB, 185, TEGRA_PERIPH_NO_RESET, tegra_clk_dbgapb),
+ MUX8("msenc", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVENC, 219, 0, tegra_clk_nvenc),
+ MUX8("nvdec", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVDEC, 194, 0, tegra_clk_nvdec),
+ MUX8("nvjpg", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVJPG, 195, 0, tegra_clk_nvjpg),
+ MUX8("ape", mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm, CLK_SOURCE_APE, 198, TEGRA_PERIPH_ON_APB, tegra_clk_ape),
+ MUX8_NOGATE_LOCK("sor1_src", mux_pllp_plld_plld2_clkm, CLK_SOURCE_SOR1, tegra_clk_sor1_src, &sor1_lock),
+ NODIV("sor1_brick", mux_plldp_sor1_src, CLK_SOURCE_SOR1, 14, MASK(1), 183, 0, tegra_clk_sor1_brick, &sor1_lock),
+ NODIV("sor1", mux_clkm_sor1_brick_sor1_src, CLK_SOURCE_SOR1, 15, MASK(1), 183, 0, tegra_clk_sor1, &sor1_lock),
+ MUX8("sdmmc_legacy", mux_pllp_out3_clkm_pllp_pllc4, CLK_SOURCE_SDMMC_LEGACY, 193, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_sdmmc_legacy),
+ MUX8("qspi", mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_QSPI, 211, TEGRA_PERIPH_ON_APB, tegra_clk_qspi),
+ MUX("vii2c", mux_pllp_pllc_clkm, CLK_SOURCE_VI_I2C, 208, TEGRA_PERIPH_ON_APB, tegra_clk_vi_i2c),
+ MUX("mipibif", mux_pllp_clkm, CLK_SOURCE_MIPIBIF, 173, TEGRA_PERIPH_ON_APB, tegra_clk_mipibif),
+ MUX("uartape", mux_pllp_pllc_clkm, CLK_SOURCE_UARTAPE, 212, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_uartape),
+ MUX8("tsecb", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_TSECB, 206, 0, tegra_clk_tsecb),
+ MUX8("maud", mux_pllp_pllp_out3_clkm_clk32k_plla, CLK_SOURCE_MAUD, 202, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_maud),
};

static struct tegra_periph_init_data gate_clks[] = {
@@ -544,6 +811,13 @@ static struct tegra_periph_init_data gate_clks[] = {
GATE("pcie", "clk_m", 70, 0, tegra_clk_pcie, 0),
GATE("dpaux", "clk_m", 181, 0, tegra_clk_dpaux, 0),
GATE("gpu", "pll_ref", 184, 0, tegra_clk_gpu, 0),
+ GATE("pllg_ref", "pll_ref", 189, 0, tegra_clk_pll_g_ref, 0),
+ GATE("hsic_trk", "usb2_hsic_trk", 209, TEGRA_PERIPH_NO_RESET, tegra_clk_hsic_trk, 0),
+ GATE("usb2_trk", "usb2_hsic_trk", 210, TEGRA_PERIPH_NO_RESET, tegra_clk_usb2_trk, 0),
+};
+
+static struct tegra_periph_init_data div_clks[] = {
+ DIV8("usb2_hsic_trk", "clk_m", CLK_SOURCE_USB2_HSIC_TRK, tegra_clk_usb2_hsic_trk, 0),
};

struct pll_out_data {
@@ -634,6 +908,33 @@ static void __init gate_clk_init(void __iomem *clk_base,
}
}

+static void __init div_clk_init(void __iomem *clk_base,
+ struct tegra_clk *tegra_clks)
+{
+ int i;
+ struct clk *clk;
+ struct clk **dt_clk;
+
+ for (i = 0; i < ARRAY_SIZE(div_clks); i++) {
+ struct tegra_periph_init_data *data;
+
+ data = div_clks + i;
+
+ dt_clk = tegra_lookup_dt_id(data->clk_id, tegra_clks);
+ if (!dt_clk)
+ continue;
+
+ clk = tegra_clk_register_divider(data->name,
+ data->p.parent_name, clk_base + data->offset,
+ data->flags, data->periph.divider.flags,
+ data->periph.divider.shift,
+ data->periph.divider.width,
+ data->periph.divider.frac_width,
+ data->periph.divider.lock);
+ *dt_clk = clk;
+ }
+}
+
static void __init init_pllp(void __iomem *clk_base, void __iomem *pmc_base,
struct tegra_clk *tegra_clks,
struct tegra_clk_pll_params *pll_params)
@@ -679,4 +980,5 @@ void __init tegra_periph_clk_init(void __iomem *clk_base,
init_pllp(clk_base, pmc_base, tegra_clks, pll_params);
periph_clk_init(clk_base, tegra_clks);
gate_clk_init(clk_base, tegra_clks);
+ div_clk_init(clk_base, tegra_clks);
}
--
1.7.9.5

2015-05-12 17:32:48

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 04/21] clk: tegra: pll: add tegra_pll_wait_for_lock to clk header

Create a wrapper interface to make use of the existing
clk_pll_wait_for_lock. This will be useful for implementations
of callbacks in Tegra SoC specific clock drivers.

Signed-off-by: Rhyland Klein <[email protected]>
---
drivers/clk/tegra/clk-pll.c | 5 +++++
drivers/clk/tegra/clk.h | 1 +
2 files changed, 6 insertions(+)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 05c6d08a6695..b9a739ce4b98 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -269,6 +269,11 @@ static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll)
return -1;
}

+int tegra_pll_wait_for_lock(struct tegra_clk_pll *pll)
+{
+ return clk_pll_wait_for_lock(pll);
+}
+
static int clk_pll_is_enabled(struct clk_hw *hw)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 4a37a0d38624..2c60319a886f 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -659,5 +659,6 @@ void tegra114_clock_deassert_dfll_dvco_reset(void);

typedef void (*tegra_clk_apply_init_table_func)(void);
extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
+int tegra_pll_wait_for_lock(struct tegra_clk_pll *pll);

#endif /* TEGRA_CLK_H */
--
1.7.9.5

2015-05-12 17:26:30

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 05/21] clk: tegra: pll: simplify clk_enable_path

Instead of having multiple similar wrapper functions for
_clk_pll_[enable|disable], we can simplify it to single
wrappers and use checks to avoid the logic we don't want to use.

Reviewed-by: Benson Leung <[email protected]>
Signed-off-by: Rhyland Klein <[email protected]>
---
v2:
- Moved the iddq settings into _clk_pll_enable/disable. This is because
some places in this file call directly into these internal functions,
but still need the iddq/reset logic to happen.

drivers/clk/tegra/clk-pll.c | 76 +++++++++++++------------------------------
1 file changed, 22 insertions(+), 54 deletions(-)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index b9a739ce4b98..1e1018dd466f 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -295,6 +295,13 @@ static void _clk_pll_enable(struct clk_hw *hw)
struct tegra_clk_pll *pll = to_clk_pll(hw);
u32 val;

+ if (pll->params->iddq_reg) {
+ val = pll_readl(pll->params->iddq_reg, pll);
+ val &= ~BIT(pll->params->iddq_bit_idx);
+ pll_writel(val, pll->params->iddq_reg, pll);
+ udelay(2);
+ }
+
clk_pll_enable_lock(pll);

val = pll_readl_base(pll);
@@ -326,6 +333,13 @@ static void _clk_pll_disable(struct clk_hw *hw)
val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE);
}
+
+ if (pll->params->iddq_reg) {
+ val = pll_readl(pll->params->iddq_reg, pll);
+ val |= BIT(pll->params->iddq_bit_idx);
+ pll_writel(val, pll->params->iddq_reg, pll);
+ udelay(2);
+ }
}

static int clk_pll_enable(struct clk_hw *hw)
@@ -876,52 +890,6 @@ static int _setup_dynamic_ramp(struct tegra_clk_pll_params *pll_params,
return 0;
}

-static int clk_pll_iddq_enable(struct clk_hw *hw)
-{
- struct tegra_clk_pll *pll = to_clk_pll(hw);
- unsigned long flags = 0;
-
- u32 val;
- int ret;
-
- if (pll->lock)
- spin_lock_irqsave(pll->lock, flags);
-
- val = pll_readl(pll->params->iddq_reg, pll);
- val &= ~BIT(pll->params->iddq_bit_idx);
- pll_writel(val, pll->params->iddq_reg, pll);
- udelay(2);
-
- _clk_pll_enable(hw);
-
- ret = clk_pll_wait_for_lock(pll);
-
- if (pll->lock)
- spin_unlock_irqrestore(pll->lock, flags);
-
- return 0;
-}
-
-static void clk_pll_iddq_disable(struct clk_hw *hw)
-{
- struct tegra_clk_pll *pll = to_clk_pll(hw);
- unsigned long flags = 0;
- u32 val;
-
- if (pll->lock)
- spin_lock_irqsave(pll->lock, flags);
-
- _clk_pll_disable(hw);
-
- val = pll_readl(pll->params->iddq_reg, pll);
- val |= BIT(pll->params->iddq_bit_idx);
- pll_writel(val, pll->params->iddq_reg, pll);
- udelay(2);
-
- if (pll->lock)
- spin_unlock_irqrestore(pll->lock, flags);
-}
-
static int _calc_dynamic_ramp_rate(struct clk_hw *hw,
struct tegra_clk_pll_freq_table *cfg,
unsigned long rate, unsigned long parent_rate)
@@ -1518,8 +1486,8 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
defined(CONFIG_ARCH_TEGRA_132_SOC)
static const struct clk_ops tegra_clk_pllxc_ops = {
.is_enabled = clk_pll_is_enabled,
- .enable = clk_pll_iddq_enable,
- .disable = clk_pll_iddq_disable,
+ .enable = clk_pll_enable,
+ .disable = clk_pll_disable,
.recalc_rate = clk_pll_recalc_rate,
.round_rate = clk_pll_ramp_round_rate,
.set_rate = clk_pllxc_set_rate,
@@ -1527,8 +1495,8 @@ static const struct clk_ops tegra_clk_pllxc_ops = {

static const struct clk_ops tegra_clk_pllm_ops = {
.is_enabled = clk_pll_is_enabled,
- .enable = clk_pll_iddq_enable,
- .disable = clk_pll_iddq_disable,
+ .enable = clk_pll_enable,
+ .disable = clk_pll_disable,
.recalc_rate = clk_pll_recalc_rate,
.round_rate = clk_pll_ramp_round_rate,
.set_rate = clk_pllm_set_rate,
@@ -1545,8 +1513,8 @@ static const struct clk_ops tegra_clk_pllc_ops = {

static const struct clk_ops tegra_clk_pllre_ops = {
.is_enabled = clk_pll_is_enabled,
- .enable = clk_pll_iddq_enable,
- .disable = clk_pll_iddq_disable,
+ .enable = clk_pll_enable,
+ .disable = clk_pll_disable,
.recalc_rate = clk_pllre_recalc_rate,
.round_rate = clk_pllre_round_rate,
.set_rate = clk_pllre_set_rate,
@@ -1815,8 +1783,8 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name,
#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
static const struct clk_ops tegra_clk_pllss_ops = {
.is_enabled = clk_pll_is_enabled,
- .enable = clk_pll_iddq_enable,
- .disable = clk_pll_iddq_disable,
+ .enable = clk_pll_enable,
+ .disable = clk_pll_disable,
.recalc_rate = clk_pll_recalc_rate,
.round_rate = clk_pll_ramp_round_rate,
.set_rate = clk_pllxc_set_rate,
--
1.7.9.5

2015-05-12 17:32:28

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 06/21] clk: tegra: pll: update warning msg

Swap out the generic WARN_ON with a WARN which gives more
information about what is happening.

Reviewed-by: Benson Leung <[email protected]>
Signed-off-by: Rhyland Klein <[email protected]>
---
drivers/clk/tegra/clk-pll.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 1e1018dd466f..0282d9f4f2d7 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -692,7 +692,8 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,

pdiv = _hw_to_p_div(hw, cfg.p);
if (pdiv < 0) {
- WARN_ON(1);
+ WARN(1, "Clock %s has invalid pdiv value : 0x%x\n",
+ __clk_get_name(hw->clk), cfg.p);
pdiv = 1;
}

--
1.7.9.5

2015-05-12 17:32:08

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 07/21] clk: tegra: pll-params: change misc_reg count from 3 -> 6

From: Bill Huang <[email protected]>

New SoC's may have more then 3 MISC registers, so bump up the
array size and use a #define to be more informative about the value.

Reviewed-by: Benson Leung <[email protected]>
Signed-off-by: Bill Huang <[email protected]>
Signed-off-by: Rhyland Klein <[email protected]>
---
drivers/clk/tegra/clk.h | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 2c60319a886f..afcdd8575355 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -156,6 +156,8 @@ struct div_nmp {
u8 override_divp_shift;
};

+#define MAX_PLL_MISC_REG_COUNT 6
+
/**
* struct tegra_clk_pll_params - PLL parameters
*
@@ -225,7 +227,7 @@ struct tegra_clk_pll_params {
u32 iddq_bit_idx;
u32 aux_reg;
u32 dyn_ramp_reg;
- u32 ext_misc_reg[3];
+ u32 ext_misc_reg[MAX_PLL_MISC_REG_COUNT];
u32 pmc_divnm_reg;
u32 pmc_divp_reg;
u32 flags;
--
1.7.9.5

2015-05-12 17:31:27

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 08/21] clk: tegra: pll: Don't unconditionally set LOCK flags

SoC specific drivers should define the appropriate flags for each
PLL rather than relying on the registration functions to automatically
set flags on their behalf. This will properly allow for changes between
SoC generations where flags might be different and allow sharing the
same logic functions.

Reviewed-by: Benson Leung <[email protected]>
Signed-off-by: Rhyland Klein <[email protected]>
---
drivers/clk/tegra/clk-pll.c | 11 ++---------
drivers/clk/tegra/clk-tegra114.c | 23 +++++++++++++----------
drivers/clk/tegra/clk-tegra124.c | 24 +++++++++++++++---------
drivers/clk/tegra/clk-tegra20.c | 18 ++++++++++--------
drivers/clk/tegra/clk-tegra30.c | 24 +++++++++++++++---------
5 files changed, 55 insertions(+), 45 deletions(-)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 0282d9f4f2d7..13d86c5b234d 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -1434,7 +1434,7 @@ struct clk *tegra_clk_register_pll(const char *name, const char *parent_name,
struct clk *clk;

pll_params->flags |= TEGRA_PLL_BYPASS;
- pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+
pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
if (IS_ERR(pll))
return ERR_CAST(pll);
@@ -1464,8 +1464,7 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
struct tegra_clk_pll *pll;
struct clk *clk;

- pll_params->flags |= TEGRA_PLL_LOCK_MISC | TEGRA_PLL_BYPASS;
- pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+ pll_params->flags |= TEGRA_PLL_BYPASS;

if (!pll_params->div_nmp)
pll_params->div_nmp = &pll_e_nmp;
@@ -1569,7 +1568,6 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
writel_relaxed(val_iddq, clk_base + pll_params->iddq_reg);
}

- pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
if (IS_ERR(pll))
return ERR_CAST(pll);
@@ -1592,8 +1590,6 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,
struct tegra_clk_pll *pll;
struct clk *clk;

- pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_LOCK_MISC;
-
pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);

pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
@@ -1653,7 +1649,6 @@ struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);

pll_params->flags |= TEGRA_PLL_BYPASS;
- pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
pll_params->flags |= TEGRA_PLLM;
pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
if (IS_ERR(pll))
@@ -1751,7 +1746,6 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name,
struct clk *clk;
u32 val, val_aux;

- pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
if (IS_ERR(pll))
return ERR_CAST(pll);
@@ -1813,7 +1807,6 @@ struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
return ERR_PTR(-EINVAL);
}

- pll_params->flags = TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_USE_LOCK;
pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
if (IS_ERR(pll))
return ERR_CAST(pll);
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index d8586bd6afce..2e8ed12a6889 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -234,7 +234,7 @@ static struct tegra_clk_pll_params pll_c_params = {
.pdiv_tohw = pllxc_p,
.div_nmp = &pllxc_nmp,
.freq_table = pll_c_freq_table,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct div_nmp pllcx_nmp = {
@@ -353,7 +353,7 @@ static struct tegra_clk_pll_params pll_m_params = {
.pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
.freq_table = pll_m_freq_table,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct div_nmp pllp_nmp = {
@@ -388,7 +388,8 @@ static struct tegra_clk_pll_params pll_p_params = {
.lock_delay = 300,
.div_nmp = &pllp_nmp,
.freq_table = pll_p_freq_table,
- .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 408000000,
};

@@ -418,7 +419,8 @@ static struct tegra_clk_pll_params pll_a_params = {
.lock_delay = 300,
.div_nmp = &pllp_nmp,
.freq_table = pll_a_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
@@ -457,7 +459,7 @@ static struct tegra_clk_pll_params pll_d_params = {
.div_nmp = &pllp_nmp,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
- TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_params pll_d2_params = {
@@ -475,7 +477,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
.div_nmp = &pllp_nmp,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
- TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct pdiv_map pllu_p[] = {
@@ -518,7 +520,7 @@ static struct tegra_clk_pll_params pll_u_params = {
.div_nmp = &pllu_nmp,
.freq_table = pll_u_freq_table,
.flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
- TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
@@ -553,7 +555,7 @@ static struct tegra_clk_pll_params pll_x_params = {
.pdiv_tohw = pllxc_p,
.div_nmp = &pllxc_nmp,
.freq_table = pll_x_freq_table,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
@@ -588,7 +590,7 @@ static struct tegra_clk_pll_params pll_e_params = {
.lock_delay = 300,
.div_nmp = &plle_nmp,
.freq_table = pll_e_freq_table,
- .flags = TEGRA_PLL_FIXED,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 100000000,
};

@@ -616,7 +618,8 @@ static struct tegra_clk_pll_params pll_re_vco_params = {
.iddq_reg = PLLRE_MISC,
.iddq_bit_idx = PLLRE_IDDQ_BIT,
.div_nmp = &pllre_nmp,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
+ TEGRA_PLL_LOCK_MISC,
};

/* possible OSC frequencies in Hz */
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index 5010e43d7785..6c182ec152e1 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -216,7 +216,7 @@ static struct tegra_clk_pll_params pll_x_params = {
.pdiv_tohw = pllxc_p,
.div_nmp = &pllxc_nmp,
.freq_table = pll_x_freq_table,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
@@ -250,7 +250,7 @@ static struct tegra_clk_pll_params pll_c_params = {
.pdiv_tohw = pllxc_p,
.div_nmp = &pllxc_nmp,
.freq_table = pll_c_freq_table,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct div_nmp pllcx_nmp = {
@@ -384,6 +384,7 @@ static struct tegra_clk_pll_params pll_c4_params = {
.ext_misc_reg[1] = 0x5b0,
.ext_misc_reg[2] = 0x5b4,
.freq_table = pll_c4_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct pdiv_map pllm_p[] = {
@@ -431,7 +432,7 @@ static struct tegra_clk_pll_params pll_m_params = {
.pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
.freq_table = pll_m_freq_table,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
@@ -467,7 +468,7 @@ static struct tegra_clk_pll_params pll_e_params = {
.lock_delay = 300,
.div_nmp = &plle_nmp,
.freq_table = pll_e_freq_table,
- .flags = TEGRA_PLL_FIXED,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 100000000,
};

@@ -505,7 +506,8 @@ static struct tegra_clk_pll_params pll_re_vco_params = {
.iddq_reg = PLLRE_MISC,
.iddq_bit_idx = PLLRE_IDDQ_BIT,
.div_nmp = &pllre_nmp,
- .flags = TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
+ TEGRA_PLL_LOCK_MISC,
};

static struct div_nmp pllp_nmp = {
@@ -541,7 +543,8 @@ static struct tegra_clk_pll_params pll_p_params = {
.div_nmp = &pllp_nmp,
.freq_table = pll_p_freq_table,
.fixed_rate = 408000000,
- .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
@@ -569,7 +572,8 @@ static struct tegra_clk_pll_params pll_a_params = {
.lock_delay = 300,
.div_nmp = &pllp_nmp,
.freq_table = pll_a_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct div_nmp plld_nmp = {
@@ -617,7 +621,7 @@ static struct tegra_clk_pll_params pll_d_params = {
.div_nmp = &plld_nmp,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
- TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_freq_table tegra124_pll_d2_freq_table[] = {
@@ -650,6 +654,7 @@ static struct tegra_clk_pll_params tegra124_pll_d2_params = {
.ext_misc_reg[2] = 0x578,
.max_p = 15,
.freq_table = tegra124_pll_d2_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_freq_table pll_dp_freq_table[] = {
@@ -682,6 +687,7 @@ static struct tegra_clk_pll_params pll_dp_params = {
.ext_misc_reg[2] = 0x5a0,
.max_p = 5,
.freq_table = pll_dp_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct pdiv_map pllu_p[] = {
@@ -724,7 +730,7 @@ static struct tegra_clk_pll_params pll_u_params = {
.div_nmp = &pllu_nmp,
.freq_table = pll_u_freq_table,
.flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
- TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

struct utmi_clk_param {
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index 41272dcc9e22..98ed1a9b8f65 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -303,7 +303,7 @@ static struct tegra_clk_pll_params pll_c_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_c_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_params pll_m_params = {
@@ -319,7 +319,7 @@ static struct tegra_clk_pll_params pll_m_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_m_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_params pll_p_params = {
@@ -335,7 +335,8 @@ static struct tegra_clk_pll_params pll_p_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_p_freq_table,
- .flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 216000000,
};

@@ -352,7 +353,7 @@ static struct tegra_clk_pll_params pll_a_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_a_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_params pll_d_params = {
@@ -368,7 +369,7 @@ static struct tegra_clk_pll_params pll_d_params = {
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
.freq_table = pll_d_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct pdiv_map pllu_p[] = {
@@ -391,7 +392,7 @@ static struct tegra_clk_pll_params pll_u_params = {
.lock_delay = 1000,
.pdiv_tohw = pllu_p,
.freq_table = pll_u_freq_table,
- .flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON,
+ .flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_params pll_x_params = {
@@ -407,7 +408,7 @@ static struct tegra_clk_pll_params pll_x_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_x_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_params pll_e_params = {
@@ -423,7 +424,8 @@ static struct tegra_clk_pll_params pll_e_params = {
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
.lock_delay = 0,
.freq_table = pll_e_freq_table,
- .flags = TEGRA_PLL_FIXED,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_LOCK_MISC |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 100000000,
};

diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 105514989f9c..ccc0c476c577 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -423,7 +423,8 @@ static struct tegra_clk_pll_params pll_c_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_c_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct div_nmp pllm_nmp = {
@@ -455,7 +456,8 @@ static struct tegra_clk_pll_params pll_m_params = {
.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE,
.freq_table = pll_m_freq_table,
.flags = TEGRA_PLLM | TEGRA_PLL_HAS_CPCON |
- TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_params pll_p_params = {
@@ -471,7 +473,8 @@ static struct tegra_clk_pll_params pll_p_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_p_freq_table,
- .flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 408000000,
};

@@ -488,7 +491,8 @@ static struct tegra_clk_pll_params pll_a_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_a_freq_table,
- .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+ .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_params pll_d_params = {
@@ -505,7 +509,7 @@ static struct tegra_clk_pll_params pll_d_params = {
.lock_delay = 1000,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
- TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,

};

@@ -523,7 +527,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
.lock_delay = 1000,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
- TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_params pll_u_params = {
@@ -540,7 +544,8 @@ static struct tegra_clk_pll_params pll_u_params = {
.lock_delay = 1000,
.pdiv_tohw = pllu_p,
.freq_table = pll_u_freq_table,
- .flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
+ .flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_params pll_x_params = {
@@ -557,7 +562,7 @@ static struct tegra_clk_pll_params pll_x_params = {
.lock_delay = 300,
.freq_table = pll_x_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_DCCON |
- TEGRA_PLL_USE_LOCK,
+ TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};

static struct tegra_clk_pll_params pll_e_params = {
@@ -573,7 +578,8 @@ static struct tegra_clk_pll_params pll_e_params = {
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_e_freq_table,
- .flags = TEGRA_PLLE_CONFIGURE | TEGRA_PLL_FIXED,
+ .flags = TEGRA_PLLE_CONFIGURE | TEGRA_PLL_FIXED |
+ TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_LOCK_MISC,
.fixed_rate = 100000000,
};

--
1.7.9.5

2015-05-12 17:26:34

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 09/21] clk: tegra: pll: Add logic for handling SDM data

This adds logic for taking SDM_DIN (Sigma Delta Modulator) setting into
the equation to calculate the effective N value for PLL which supports
fractional divider.

The effective N = NDIV + 1/2 + SDM_DIN/2^13, where NDIV is the integer
feedback divider.

Signed-off-by: Rhyland Klein <[email protected]>
---
v5:
- made use of sdm_en_mask when possible to clean up logic
- added kerneldoc info for new struct params
- Added info about SDM near sdm_set_data
- rewrote check in sdm_set_data to make it clearer

drivers/clk/tegra/clk-pll.c | 66 ++++++++++++++++++++++++++++++++++++++++++-
drivers/clk/tegra/clk.h | 15 +++++++++-
2 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 13d86c5b234d..8b27cb6fe992 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -187,17 +187,23 @@
#define pll_readl_base(p) pll_readl(p->params->base_reg, p)
#define pll_readl_misc(p) pll_readl(p->params->misc_reg, p)
#define pll_override_readl(offset, p) readl_relaxed(p->pmc + offset)
+#define pll_readl_sdm_din(p) pll_readl(p->params->sdm_din_reg, p)
+#define pll_readl_sdm_ctrl(p) pll_readl(p->params->sdm_ctrl_reg, p)

#define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset)
#define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p)
#define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p)
#define pll_override_writel(val, offset, p) writel(val, p->pmc + offset)
+#define pll_writel_sdm_din(val, p) pll_writel(val, p->params->sdm_din_reg, p)
+#define pll_writel_sdm_ctrl(val, p) pll_writel(val, p->params->sdm_ctrl_reg, p)

#define mask(w) ((1 << (w)) - 1)
#define divm_mask(p) mask(p->params->div_nmp->divm_width)
#define divn_mask(p) mask(p->params->div_nmp->divn_width)
#define divp_mask(p) (p->params->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK :\
mask(p->params->div_nmp->divp_width))
+#define sdm_din_mask(p) p->params->sdm_din_mask
+#define sdm_en_mask(p) p->params->sdm_ctrl_en_mask

#define divm_shift(p) (p)->params->div_nmp->divm_shift
#define divn_shift(p) (p)->params->div_nmp->divn_shift
@@ -211,6 +217,9 @@
#define divn_max(p) (divn_mask(p))
#define divp_max(p) (1 << (divp_mask(p)))

+#define sdin_din_to_data(din) ((u16)((din) ? : 0xFFFFU))
+#define sdin_data_to_din(dat) (((dat) == 0xFFFFU) ? 0 : (s16)dat)
+
static struct div_nmp default_nmp = {
.divn_shift = PLL_BASE_DIVN_SHIFT,
.divn_width = PLL_BASE_DIVN_WIDTH,
@@ -429,6 +438,7 @@ static int _get_table_rate(struct clk_hw *hw,
cfg->n = sel->n;
cfg->p = sel->p;
cfg->cpcon = sel->cpcon;
+ cfg->sdm_data = sel->sdm_data;

return 0;
}
@@ -495,6 +505,42 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
return 0;
}

+/*
+ * SDM (Sigma Delta Modulator) divisor is 16-bit 2's complement signed number
+ * within (-2^12 ... 2^12-1) range. Represented in PLL data structure as
+ * unsigned 16-bit value, with "0" divisor mapped to 0xFFFF. Data "0" is used
+ * to indicate that SDM is disabled.
+ *
+ * Effective ndiv value when SDM is enabled: ndiv + 1/2 + sdm_din/2^13
+ */
+static void clk_pll_set_sdm_data(struct clk_hw *hw,
+ struct tegra_clk_pll_freq_table *cfg)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ u32 val;
+ bool enabled;
+
+ if (!pll->params->sdm_din_reg)
+ return;
+
+ if (cfg->sdm_data) {
+ val = pll_readl_sdm_din(pll) & (~sdm_din_mask(pll));
+ val |= sdin_data_to_din(cfg->sdm_data) & sdm_din_mask(pll);
+ pll_writel_sdm_din(val, pll);
+ }
+
+ val = pll_readl_sdm_ctrl(pll);
+ enabled = (val & sdm_en_mask(pll));
+
+ if (cfg->sdm_data == 0 && enabled)
+ val &= ~pll->params->sdm_ctrl_en_mask;
+
+ if (cfg->sdm_data != 0 && !enabled)
+ val |= pll->params->sdm_ctrl_en_mask;
+
+ pll_writel_sdm_ctrl(val, pll);
+}
+
static void _update_pll_mnp(struct tegra_clk_pll *pll,
struct tegra_clk_pll_freq_table *cfg)
{
@@ -527,6 +573,8 @@ static void _update_pll_mnp(struct tegra_clk_pll *pll,
(cfg->p << divp_shift(pll));

pll_writel_base(val, pll);
+
+ clk_pll_set_sdm_data(&pll->hw, cfg);
}
}

@@ -552,6 +600,14 @@ static void _get_pll_mnp(struct tegra_clk_pll *pll,
cfg->m = (val >> div_nmp->divm_shift) & divm_mask(pll);
cfg->n = (val >> div_nmp->divn_shift) & divn_mask(pll);
cfg->p = (val >> div_nmp->divp_shift) & divp_mask(pll);
+
+ if (pll->params->sdm_din_reg) {
+ if (sdm_en_mask(pll) & pll_readl_sdm_ctrl(pll)) {
+ val = pll_readl_sdm_din(pll);
+ val &= sdm_din_mask(pll);
+ cfg->sdm_data = sdin_din_to_data(val);
+ }
+ }
}
}

@@ -633,7 +689,8 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,

_get_pll_mnp(pll, &old_cfg);

- if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p)
+ if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p ||
+ old_cfg.sdm_data != cfg.sdm_data)
ret = _program_pll(hw, &cfg, rate);

if (pll->lock)
@@ -697,6 +754,9 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
pdiv = 1;
}

+ if (pll->params->set_gain)
+ pll->params->set_gain(&cfg);
+
cfg.m *= pdiv;

rate *= cfg.n;
@@ -978,6 +1038,7 @@ static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate,
static long clk_pll_ramp_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
struct tegra_clk_pll_freq_table cfg;
int ret, p_div;
u64 output_rate = *prate;
@@ -990,6 +1051,9 @@ static long clk_pll_ramp_round_rate(struct clk_hw *hw, unsigned long rate,
if (p_div < 0)
return p_div;

+ if (pll->params->set_gain)
+ pll->params->set_gain(&cfg);
+
output_rate *= cfg.n;
do_div(output_rate, cfg.m * p_div);

diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index afcdd8575355..e78133822233 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -110,14 +110,16 @@ struct clk *tegra_clk_register_mc(const char *name, const char *parent_name,
* @m: input divider
* @p: post divider
* @cpcon: charge pump current
+ * @sdm_data: fraction divider setting (0 = disabled)
*/
struct tegra_clk_pll_freq_table {
unsigned long input_rate;
unsigned long output_rate;
- u16 n;
+ u32 n;
u16 m;
u8 p;
u8 cpcon;
+ u16 sdm_data;
};

/**
@@ -174,6 +176,10 @@ struct div_nmp {
* @lock_enable_bit_idx: Bit index to enable PLL lock
* @iddq_reg: PLL IDDQ register offset
* @iddq_bit_idx: Bit index to enable PLL IDDQ
+ * @sdm_din_reg: Register offset where SDM settings are
+ * @sdm_din_mask: Mask of SDM divider bits
+ * @sdm_ctrl_reg: Register offset where SDM enable is
+ * @sdm_ctrl_en_mask: Mask of SDM enable bit
* @aux_reg: AUX register offset
* @dyn_ramp_reg: Dynamic ramp control register offset
* @ext_misc_reg: Miscellaneous control register offsets
@@ -188,6 +194,8 @@ struct div_nmp {
* @div_nmp: offsets and widths on n, m and p fields
* @freq_table: array of frequencies supported by PLL
* @fixed_rate: PLL rate if it is fixed
+ * @set_gain: Callback to adjust N div for SDM enabled
+ * PLL's based on fractional divider value.
*
* Flags:
* TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for
@@ -225,6 +233,10 @@ struct tegra_clk_pll_params {
u32 lock_enable_bit_idx;
u32 iddq_reg;
u32 iddq_bit_idx;
+ u32 sdm_din_reg;
+ u32 sdm_din_mask;
+ u32 sdm_ctrl_reg;
+ u32 sdm_ctrl_en_mask;
u32 aux_reg;
u32 dyn_ramp_reg;
u32 ext_misc_reg[MAX_PLL_MISC_REG_COUNT];
@@ -239,6 +251,7 @@ struct tegra_clk_pll_params {
struct div_nmp *div_nmp;
struct tegra_clk_pll_freq_table *freq_table;
unsigned long fixed_rate;
+ void (*set_gain)(struct tegra_clk_pll_freq_table *cfg);
};

#define TEGRA_PLL_USE_LOCK BIT(0)
--
1.7.9.5

2015-05-12 17:26:38

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 10/21] clk: tegra: pll: Add logic for out-of-table rates for T210

For Tegra210, the logic to calculate out-of-table rates is different
from previous generations. Add callbacks that can be overridden to
allow for different ways of calculating rates. Default to
_cal_rate when not specified.

This patch also includes a new flag which is used to set which method
of fixed_mdiv calculation is used. The new method for calculating the
fixed divider value for M can be more accurate especially when
fractional dividers are in play. This allows for older chipsets to use
the existing logic and new generations to use a newer version which
may work better for them.

Based on original work by Aleksandr Frid <[email protected]>

Signed-off-by: Rhyland Klein <[email protected]>
---
v5:
- Updated description to include mentioning the NEW_MDIV flag
- Added kerneldoc info for new members

drivers/clk/tegra/clk-pll.c | 24 ++++++++++++++++++++++--
drivers/clk/tegra/clk.h | 13 +++++++++++++
2 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 8b27cb6fe992..95ad0669291f 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -678,7 +678,7 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
}

if (_get_table_rate(hw, &cfg, rate, parent_rate) &&
- _calc_rate(hw, &cfg, rate, parent_rate)) {
+ pll->params->calc_rate(hw, &cfg, rate, parent_rate)) {
pr_err("%s: Failed to set %s rate %lu\n", __func__,
__clk_get_name(hw->clk), rate);
WARN_ON(1);
@@ -713,7 +713,7 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
return __clk_get_rate(hw->clk);

if (_get_table_rate(hw, &cfg, rate, *prate) &&
- _calc_rate(hw, &cfg, rate, *prate))
+ pll->params->calc_rate(hw, &cfg, rate, *prate))
return -EINVAL;

return cfg.output_rate;
@@ -903,12 +903,28 @@ const struct clk_ops tegra_clk_plle_ops = {
static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params,
unsigned long parent_rate)
{
+ u16 mdiv = parent_rate / pll_params->cf_min;
+
+ if (pll_params->flags & TEGRA_MDIV_NEW)
+ return (!pll_params->mdiv_default ? mdiv :
+ min(mdiv, pll_params->mdiv_default));
+
+ if (pll_params->mdiv_default)
+ return pll_params->mdiv_default;
+
if (parent_rate > pll_params->cf_max)
return 2;
else
return 1;
}

+u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+
+ return (u16)_pll_fixed_mdiv(pll->params, input_rate);
+}
+
static unsigned long _clip_vco_min(unsigned long vco_min,
unsigned long parent_rate)
{
@@ -1483,6 +1499,10 @@ static struct clk *_tegra_clk_register_pll(struct tegra_clk_pll *pll,
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);

+ /* Default to _calc_rate if unspecified */
+ if (!pll->params->calc_rate)
+ pll->params->calc_rate = _calc_rate;
+
/* Data in .init is copied by clk_register(), so stack variable OK */
pll->hw.init = &init;

diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index e78133822233..35ce2a382792 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -194,8 +194,12 @@ struct div_nmp {
* @div_nmp: offsets and widths on n, m and p fields
* @freq_table: array of frequencies supported by PLL
* @fixed_rate: PLL rate if it is fixed
+ * @mdiv_default: Default value for fixed mdiv for this PLL
+ * @round_p_to_pdiv: Callback used to round p to the closed pdiv
* @set_gain: Callback to adjust N div for SDM enabled
* PLL's based on fractional divider value.
+ * @calc_rate: Callback used to change how out of table
+ * rates (dividers and multipler) are calculated.
*
* Flags:
* TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for
@@ -217,6 +221,8 @@ struct div_nmp {
* base register.
* TEGRA_PLL_BYPASS - PLL has bypass bit
* TEGRA_PLL_HAS_LOCK_ENABLE - PLL has bit to enable lock monitoring
+ * TEGRA_MDIV_NEW - Switch to new method for calculating fixed mdiv
+ * it may be more accurate (especially if SDM present)
*/
struct tegra_clk_pll_params {
unsigned long input_min;
@@ -251,7 +257,12 @@ struct tegra_clk_pll_params {
struct div_nmp *div_nmp;
struct tegra_clk_pll_freq_table *freq_table;
unsigned long fixed_rate;
+ u16 mdiv_default;
+ u32 (*round_p_to_pdiv)(u32 p, u32 *pdiv);
void (*set_gain)(struct tegra_clk_pll_freq_table *cfg);
+ int (*calc_rate)(struct clk_hw *hw,
+ struct tegra_clk_pll_freq_table *cfg,
+ unsigned long rate, unsigned long parent_rate);
};

#define TEGRA_PLL_USE_LOCK BIT(0)
@@ -265,6 +276,7 @@ struct tegra_clk_pll_params {
#define TEGRA_PLL_LOCK_MISC BIT(8)
#define TEGRA_PLL_BYPASS BIT(9)
#define TEGRA_PLL_HAS_LOCK_ENABLE BIT(10)
+#define TEGRA_MDIV_NEW BIT(11)

/**
* struct tegra_clk_pll - Tegra PLL clock
@@ -675,5 +687,6 @@ void tegra114_clock_deassert_dfll_dvco_reset(void);
typedef void (*tegra_clk_apply_init_table_func)(void);
extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
int tegra_pll_wait_for_lock(struct tegra_clk_pll *pll);
+u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate);

#endif /* TEGRA_CLK_H */
--
1.7.9.5

2015-05-12 17:26:42

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 11/21] clk: tegra: pll: Add code to handle if resets are supported by PLL

From: Bill Huang <[email protected]>

If a PLL has a reset_reg specified, properly handle that in the
enable/disable logic paths.

Reviewed-by: Benson Leung <[email protected]>
Signed-off-by: Bill Huang <[email protected]>
Signed-off-by: Rhyland Klein <[email protected]>
---
v5:
- Added kerneldoc for new members

v2:
- Moved reset logic to _clk_pll_enable/disable as well

drivers/clk/tegra/clk-pll.c | 12 ++++++++++++
drivers/clk/tegra/clk.h | 4 ++++
2 files changed, 16 insertions(+)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 95ad0669291f..54ebab2b85e5 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -311,6 +311,12 @@ static void _clk_pll_enable(struct clk_hw *hw)
udelay(2);
}

+ if (pll->params->reset_reg) {
+ val = pll_readl(pll->params->reset_reg, pll);
+ val &= ~BIT(pll->params->reset_bit_idx);
+ pll_writel(val, pll->params->reset_reg, pll);
+ }
+
clk_pll_enable_lock(pll);

val = pll_readl_base(pll);
@@ -343,6 +349,12 @@ static void _clk_pll_disable(struct clk_hw *hw)
writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE);
}

+ if (pll->params->reset_reg) {
+ val = pll_readl(pll->params->reset_reg, pll);
+ val |= BIT(pll->params->reset_bit_idx);
+ pll_writel(val, pll->params->reset_reg, pll);
+ }
+
if (pll->params->iddq_reg) {
val = pll_readl(pll->params->iddq_reg, pll);
val |= BIT(pll->params->iddq_bit_idx);
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 35ce2a382792..12c3e7edba4c 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -176,6 +176,8 @@ struct div_nmp {
* @lock_enable_bit_idx: Bit index to enable PLL lock
* @iddq_reg: PLL IDDQ register offset
* @iddq_bit_idx: Bit index to enable PLL IDDQ
+ * @reset_reg: Register offset of where RESET bit is
+ * @reset_bit_idx: Shift of reset bit in reset_reg
* @sdm_din_reg: Register offset where SDM settings are
* @sdm_din_mask: Mask of SDM divider bits
* @sdm_ctrl_reg: Register offset where SDM enable is
@@ -239,6 +241,8 @@ struct tegra_clk_pll_params {
u32 lock_enable_bit_idx;
u32 iddq_reg;
u32 iddq_bit_idx;
+ u32 reset_reg;
+ u32 reset_bit_idx;
u32 sdm_din_reg;
u32 sdm_din_mask;
u32 sdm_ctrl_reg;
--
1.7.9.5

2015-05-12 17:30:57

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 12/21] clk: tegra: pll: Add specialized logic for T210

On Tegra210 SoC's, the logic to enable several of the plls is different
from previous generations. Therefore, add registeration functions specific
to Tegra210 which will handle them appropriately.

Signed-off-by: Rhyland Klein <[email protected]>
---
v5:
- Removed unused variables.

v4:
- Fixed plle_tegra210_is_enabled callback typos

v2:
- Fixed plle logic. PLLE on Tegra210 has had its enable bit moved, so
we can't use the default _clk_pll_enable/disable routines. Instead,
manually set/clear the correct bit for PLLE within its functions.

drivers/clk/tegra/clk-pll.c | 347 ++++++++++++++++++++++++++++++++++++++++++-
drivers/clk/tegra/clk.h | 24 +++
2 files changed, 369 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 54ebab2b85e5..2b1f672e3bdb 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -65,6 +65,7 @@
#define PLLE_BASE_DIVN_WIDTH 8
#define PLLE_BASE_DIVM_SHIFT 0
#define PLLE_BASE_DIVM_WIDTH 8
+#define PLLE_BASE_ENABLE BIT(31)

#define PLLE_MISC_SETUP_BASE_SHIFT 16
#define PLLE_MISC_SETUP_BASE_MASK (0xffff << PLLE_MISC_SETUP_BASE_SHIFT)
@@ -910,7 +911,8 @@ const struct clk_ops tegra_clk_plle_ops = {

#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
defined(CONFIG_ARCH_TEGRA_124_SOC) || \
- defined(CONFIG_ARCH_TEGRA_132_SOC)
+ defined(CONFIG_ARCH_TEGRA_132_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_210_SOC)

static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params,
unsigned long parent_rate)
@@ -1579,7 +1581,8 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,

#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
defined(CONFIG_ARCH_TEGRA_124_SOC) || \
- defined(CONFIG_ARCH_TEGRA_132_SOC)
+ defined(CONFIG_ARCH_TEGRA_132_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_210_SOC)
static const struct clk_ops tegra_clk_pllxc_ops = {
.is_enabled = clk_pll_is_enabled,
.enable = clk_pll_enable,
@@ -1958,3 +1961,343 @@ struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
return clk;
}
#endif
+
+#if defined(CONFIG_ARCH_TEGRA_210_SOC)
+static int clk_plle_tegra210_enable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ struct tegra_clk_pll_freq_table sel;
+ u32 val;
+ int ret;
+ unsigned long flags = 0;
+ unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk));
+
+ if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate))
+ return -EINVAL;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ val = pll_readl_base(pll);
+ val &= ~BIT(29); /* Disable lock override */
+ pll_writel_base(val, pll);
+
+ val = pll_readl(pll->params->aux_reg, pll);
+ val |= PLLE_AUX_ENABLE_SWCTL;
+ val &= ~PLLE_AUX_SEQ_ENABLE;
+ pll_writel(val, pll->params->aux_reg, pll);
+ udelay(1);
+
+ val = pll_readl_misc(pll);
+ val |= PLLE_MISC_LOCK_ENABLE;
+ val |= PLLE_MISC_IDDQ_SW_CTRL;
+ val &= ~PLLE_MISC_IDDQ_SW_VALUE;
+ val |= PLLE_MISC_PLLE_PTS;
+ val |= PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK;
+ pll_writel_misc(val, pll);
+ udelay(5);
+
+ val = pll_readl(PLLE_SS_CTRL, pll);
+ val |= PLLE_SS_DISABLE;
+ pll_writel(val, PLLE_SS_CTRL, pll);
+
+ val = pll_readl_base(pll);
+ val &= ~(divp_mask_shifted(pll) | divn_mask_shifted(pll) |
+ divm_mask_shifted(pll));
+ val &= ~(PLLE_BASE_DIVCML_MASK << PLLE_BASE_DIVCML_SHIFT);
+ val |= sel.m << divm_shift(pll);
+ val |= sel.n << divn_shift(pll);
+ val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;
+ pll_writel_base(val, pll);
+ udelay(1);
+
+ val = pll_readl_base(pll);
+ val |= PLLE_BASE_ENABLE;
+ pll_writel_base(val, pll);
+
+ ret = clk_pll_wait_for_lock(pll);
+
+ if (ret < 0)
+ goto out;
+
+ val = pll_readl(PLLE_SS_CTRL, pll);
+ val &= ~(PLLE_SS_CNTL_CENTER | PLLE_SS_CNTL_INVERT);
+ val &= ~PLLE_SS_COEFFICIENTS_MASK;
+ val |= PLLE_SS_COEFFICIENTS_VAL;
+ pll_writel(val, PLLE_SS_CTRL, pll);
+ val &= ~(PLLE_SS_CNTL_SSC_BYP | PLLE_SS_CNTL_BYPASS_SS);
+ pll_writel(val, PLLE_SS_CTRL, pll);
+ udelay(1);
+ val &= ~PLLE_SS_CNTL_INTERP_RESET;
+ pll_writel(val, PLLE_SS_CTRL, pll);
+ udelay(1);
+
+ /* Enable hw control of xusb brick pll */
+ val = pll_readl_misc(pll);
+ val &= ~PLLE_MISC_IDDQ_SW_CTRL;
+ pll_writel_misc(val, pll);
+
+ val = pll_readl(pll->params->aux_reg, pll);
+ val |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SEQ_START_STATE);
+ val &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL);
+ pll_writel(val, pll->params->aux_reg, pll);
+ udelay(1);
+ val |= PLLE_AUX_SEQ_ENABLE;
+ pll_writel(val, pll->params->aux_reg, pll);
+
+ val = pll_readl(XUSBIO_PLL_CFG0, pll);
+ val |= (XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET |
+ XUSBIO_PLL_CFG0_SEQ_START_STATE);
+ val &= ~(XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL |
+ XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL);
+ pll_writel(val, XUSBIO_PLL_CFG0, pll);
+ udelay(1);
+ val |= XUSBIO_PLL_CFG0_SEQ_ENABLE;
+ pll_writel(val, XUSBIO_PLL_CFG0, pll);
+
+ /* Enable hw control of SATA pll */
+ val = pll_readl(SATA_PLL_CFG0, pll);
+ val &= ~SATA_PLL_CFG0_PADPLL_RESET_SWCTL;
+ val |= SATA_PLL_CFG0_PADPLL_USE_LOCKDET;
+ val |= SATA_PLL_CFG0_SEQ_START_STATE;
+ pll_writel(val, SATA_PLL_CFG0, pll);
+
+ udelay(1);
+
+ val = pll_readl(SATA_PLL_CFG0, pll);
+ val |= SATA_PLL_CFG0_SEQ_ENABLE;
+ pll_writel(val, SATA_PLL_CFG0, pll);
+
+out:
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+
+ return ret;
+}
+
+static void clk_plle_tegra210_disable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ val = pll_readl_base(pll);
+ val &= ~PLLE_BASE_ENABLE;
+ pll_writel_base(val, pll);
+
+ val = pll_readl_misc(pll);
+ val |= PLLE_MISC_IDDQ_SW_CTRL | PLLE_MISC_IDDQ_SW_VALUE;
+ pll_writel_misc(val, pll);
+ udelay(1);
+
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static int clk_plle_tegra210_is_enabled(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ u32 val;
+
+ val = pll_readl_base(pll);
+
+ return val & PLLE_BASE_ENABLE ? 1 : 0;
+}
+
+static const struct clk_ops tegra_clk_plle_tegra210_ops = {
+ .is_enabled = clk_plle_tegra210_is_enabled,
+ .enable = clk_plle_tegra210_enable,
+ .disable = clk_plle_tegra210_disable,
+ .recalc_rate = clk_pll_recalc_rate,
+};
+
+struct clk *tegra_clk_register_plle_tegra210(const char *name,
+ const char *parent_name,
+ void __iomem *clk_base, unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock)
+{
+ struct tegra_clk_pll *pll;
+ struct clk *clk;
+ u32 val, val_aux;
+
+ pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ /* ensure parent is set to pll_re_vco */
+
+ val = pll_readl_base(pll);
+ val_aux = pll_readl(pll_params->aux_reg, pll);
+
+ if (val & PLLE_BASE_ENABLE) {
+ if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
+ (val_aux & PLLE_AUX_PLLP_SEL))
+ WARN(1, "pll_e enabled with unsupported parent %s\n",
+ (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
+ "pll_re_vco");
+ } else {
+ val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
+ pll_writel(val_aux, pll_params->aux_reg, pll);
+ }
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_plle_tegra210_ops);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+
+struct clk *tegra_clk_register_pllc_tegra210(const char *name,
+ const char *parent_name, void __iomem *clk_base,
+ void __iomem *pmc, unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock)
+{
+ struct clk *parent, *clk;
+ struct pdiv_map *p_tohw = pll_params->pdiv_tohw;
+ struct tegra_clk_pll *pll;
+ unsigned long parent_rate;
+
+ if (!p_tohw)
+ return ERR_PTR(-EINVAL);
+
+ parent = __clk_lookup(parent_name);
+ if (!parent) {
+ WARN(1, "parent clk %s of %s must be registered first\n",
+ name, parent_name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ parent_rate = __clk_get_rate(parent);
+
+ pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
+
+ pll_params->flags |= TEGRA_PLL_BYPASS;
+ pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_pll_ops);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+
+struct clk *tegra_clk_register_pllxc_tegra210(const char *name,
+ const char *parent_name, void __iomem *clk_base,
+ void __iomem *pmc, unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock)
+{
+ struct tegra_clk_pll *pll;
+ struct clk *clk, *parent;
+ unsigned long parent_rate;
+
+ parent = __clk_lookup(parent_name);
+ if (!parent) {
+ WARN(1, "parent clk %s of %s must be registered first\n",
+ name, parent_name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!pll_params->pdiv_tohw)
+ return ERR_PTR(-EINVAL);
+
+ parent_rate = __clk_get_rate(parent);
+
+ pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
+
+ pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_pll_ops);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+
+struct clk *tegra_clk_register_pllss_tegra210(const char *name,
+ const char *parent_name, void __iomem *clk_base,
+ unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock)
+{
+ struct tegra_clk_pll *pll;
+ struct clk *clk, *parent;
+ struct tegra_clk_pll_freq_table cfg;
+ unsigned long parent_rate;
+ u32 val;
+ int i;
+
+ if (!pll_params->div_nmp)
+ return ERR_PTR(-EINVAL);
+
+ parent = __clk_lookup(parent_name);
+ if (!parent) {
+ WARN(1, "parent clk %s of %s must be registered first\n",
+ name, parent_name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ val = pll_readl_base(pll);
+ val &= ~PLLSS_REF_SRC_SEL_MASK;
+ pll_writel_base(val, pll);
+
+ parent_rate = __clk_get_rate(parent);
+
+ pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
+
+ /* initialize PLL to minimum rate */
+
+ cfg.m = _pll_fixed_mdiv(pll_params, parent_rate);
+ cfg.n = cfg.m * pll_params->vco_min / parent_rate;
+
+ for (i = 0; pll_params->pdiv_tohw[i].pdiv; i++)
+ ;
+ if (!i) {
+ kfree(pll);
+ return ERR_PTR(-EINVAL);
+ }
+
+ cfg.p = pll_params->pdiv_tohw[i-1].hw_val;
+
+ _update_pll_mnp(pll, &cfg);
+
+ pll_writel_misc(PLLSS_MISC_DEFAULT, pll);
+
+ val = pll_readl_base(pll);
+ if (val & PLL_BASE_ENABLE) {
+ if (val & BIT(pll_params->iddq_bit_idx)) {
+ WARN(1, "%s is on but IDDQ set\n", name);
+ kfree(pll);
+ return ERR_PTR(-EINVAL);
+ }
+ } else
+ val |= BIT(pll_params->iddq_bit_idx);
+
+ val &= ~PLLSS_LOCK_OVERRIDE;
+ pll_writel_base(val, pll);
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_pll_ops);
+
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+#endif
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 12c3e7edba4c..74190ab4f579 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -334,6 +334,12 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
struct tegra_clk_pll_params *pll_params,
spinlock_t *lock);

+struct clk *tegra_clk_register_pllxc_tegra210(const char *name,
+ const char *parent_name, void __iomem *clk_base,
+ void __iomem *pmc, unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock);
+
struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
void __iomem *clk_base, void __iomem *pmc,
unsigned long flags,
@@ -358,6 +364,24 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name,
struct tegra_clk_pll_params *pll_params,
spinlock_t *lock);

+struct clk *tegra_clk_register_plle_tegra210(const char *name,
+ const char *parent_name,
+ void __iomem *clk_base, unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock);
+
+struct clk *tegra_clk_register_pllc_tegra210(const char *name,
+ const char *parent_name, void __iomem *clk_base,
+ void __iomem *pmc, unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock);
+
+struct clk *tegra_clk_register_pllss_tegra210(const char *name,
+ const char *parent_name, void __iomem *clk_base,
+ unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock);
+
struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
void __iomem *clk_base, unsigned long flags,
struct tegra_clk_pll_params *pll_params,
--
1.7.9.5

2015-05-12 17:26:46

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 13/21] clk: tegra: pll: Add support for PLLMB for T210

Tegra210 SoC's have 2 PLLS for memory usage. Add plumbing to register
and handle PLLMB.

PLLMB is used to allow switching between 2 PLLM's without having to use
and intermediate backup PLL, as we need to lock the PLL before we can
switch to it.

Signed-off-by: Rhyland Klein <[email protected]>
---
v3:
- Flushed out comment more.

v2:
- Fixed commit description as suggested.

drivers/clk/tegra/clk-pll.c | 46 +++++++++++++++++++++++++++++++++++++++----
drivers/clk/tegra/clk.h | 9 +++++++++
2 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 2b1f672e3bdb..1dfa1433375d 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -561,7 +561,7 @@ static void _update_pll_mnp(struct tegra_clk_pll *pll,
struct tegra_clk_pll_params *params = pll->params;
struct div_nmp *div_nmp = params->div_nmp;

- if ((params->flags & TEGRA_PLLM) &&
+ if ((params->flags & (TEGRA_PLLM | TEGRA_PLLMB)) &&
(pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) &
PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) {
val = pll_override_readl(params->pmc_divp_reg, pll);
@@ -598,7 +598,7 @@ static void _get_pll_mnp(struct tegra_clk_pll *pll,
struct tegra_clk_pll_params *params = pll->params;
struct div_nmp *div_nmp = params->div_nmp;

- if ((params->flags & TEGRA_PLLM) &&
+ if ((params->flags & (TEGRA_PLLM | TEGRA_PLLMB)) &&
(pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) &
PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) {
val = pll_override_readl(params->pmc_divp_reg, pll);
@@ -721,8 +721,8 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
if (pll->params->flags & TEGRA_PLL_FIXED)
return pll->params->fixed_rate;

- /* PLLM is used for memory; we do not change rate */
- if (pll->params->flags & TEGRA_PLLM)
+ /* PLLM/MB are used for memory; we do not change rate */
+ if (pll->params->flags & (TEGRA_PLLM | TEGRA_PLLMB))
return __clk_get_rate(hw->clk);

if (_get_table_rate(hw, &cfg, rate, *prate) &&
@@ -2300,4 +2300,42 @@ struct clk *tegra_clk_register_pllss_tegra210(const char *name,

return clk;
}
+
+struct clk *tegra_clk_register_pllmb(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock)
+{
+ struct tegra_clk_pll *pll;
+ struct clk *clk, *parent;
+ unsigned long parent_rate;
+
+ if (!pll_params->pdiv_tohw)
+ return ERR_PTR(-EINVAL);
+
+ parent = __clk_lookup(parent_name);
+ if (!parent) {
+ WARN(1, "parent clk %s of %s must be registered first\n",
+ name, parent_name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ parent_rate = __clk_get_rate(parent);
+
+ pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
+
+ pll_params->flags |= TEGRA_PLL_BYPASS;
+ pll_params->flags |= TEGRA_PLLMB;
+ pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_pllm_ops);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
#endif
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 74190ab4f579..7ee764e583f9 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -225,6 +225,8 @@ struct div_nmp {
* TEGRA_PLL_HAS_LOCK_ENABLE - PLL has bit to enable lock monitoring
* TEGRA_MDIV_NEW - Switch to new method for calculating fixed mdiv
* it may be more accurate (especially if SDM present)
+ * TEGRA_PLLMB - PLLMB has should be treated similar to PLLM. This
+ * flag indicated that it is PLLMB.
*/
struct tegra_clk_pll_params {
unsigned long input_min;
@@ -281,6 +283,7 @@ struct tegra_clk_pll_params {
#define TEGRA_PLL_BYPASS BIT(9)
#define TEGRA_PLL_HAS_LOCK_ENABLE BIT(10)
#define TEGRA_MDIV_NEW BIT(11)
+#define TEGRA_PLLMB BIT(12)

/**
* struct tegra_clk_pll - Tegra PLL clock
@@ -387,6 +390,12 @@ struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
struct tegra_clk_pll_params *pll_params,
spinlock_t *lock);

+struct clk *tegra_clk_register_pllmb(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags,
+ struct tegra_clk_pll_params *pll_params,
+ spinlock_t *lock);
+
/**
* struct tegra_clk_pll_out - PLL divider down clock
*
--
1.7.9.5

2015-05-12 17:30:19

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 14/21] clk: tegra: pll: Adjust vco_min if SDM present

From: Bill Huang <[email protected]>

This code makes use of the SDM fractional divider if present to
contrain the allowable programming range of the PLL divider register
bitfields to take advantage of higher frequency granularity that can
be induced by the SDM divider.

Based on original work by Aleksandr Frid <[email protected]>

Signed-off-by: Bill Huang <[email protected]>
---
v5:
- Removed whitespace change

drivers/clk/tegra/clk-pll.c | 28 ++++++++++++++++++++++++++++
drivers/clk/tegra/clk.h | 2 ++
2 files changed, 30 insertions(+)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 1dfa1433375d..626466665dde 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -1653,6 +1653,10 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,

pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);

+ if (pll_params->adjust_vco)
+ pll_params->vco_min = pll_params->adjust_vco(pll_params,
+ parent_rate);
+
err = _setup_dynamic_ramp(pll_params, clk_base, parent_rate);
if (err)
return ERR_PTR(err);
@@ -1691,6 +1695,10 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,

pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);

+ if (pll_params->adjust_vco)
+ pll_params->vco_min = pll_params->adjust_vco(pll_params,
+ parent_rate);
+
pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
if (IS_ERR(pll))
return ERR_CAST(pll);
@@ -1747,6 +1755,10 @@ struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,

pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);

+ if (pll_params->adjust_vco)
+ pll_params->vco_min = pll_params->adjust_vco(pll_params,
+ parent_rate);
+
pll_params->flags |= TEGRA_PLL_BYPASS;
pll_params->flags |= TEGRA_PLLM;
pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
@@ -2177,6 +2189,10 @@ struct clk *tegra_clk_register_pllc_tegra210(const char *name,

pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);

+ if (pll_params->adjust_vco)
+ pll_params->vco_min = pll_params->adjust_vco(pll_params,
+ parent_rate);
+
pll_params->flags |= TEGRA_PLL_BYPASS;
pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
if (IS_ERR(pll))
@@ -2214,6 +2230,10 @@ struct clk *tegra_clk_register_pllxc_tegra210(const char *name,

pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);

+ if (pll_params->adjust_vco)
+ pll_params->vco_min = pll_params->adjust_vco(pll_params,
+ parent_rate);
+
pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
if (IS_ERR(pll))
return ERR_CAST(pll);
@@ -2261,6 +2281,10 @@ struct clk *tegra_clk_register_pllss_tegra210(const char *name,

pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);

+ if (pll_params->adjust_vco)
+ pll_params->vco_min = pll_params->adjust_vco(pll_params,
+ parent_rate);
+
/* initialize PLL to minimum rate */

cfg.m = _pll_fixed_mdiv(pll_params, parent_rate);
@@ -2325,6 +2349,10 @@ struct clk *tegra_clk_register_pllmb(const char *name, const char *parent_name,

pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);

+ if (pll_params->adjust_vco)
+ pll_params->vco_min = pll_params->adjust_vco(pll_params,
+ parent_rate);
+
pll_params->flags |= TEGRA_PLL_BYPASS;
pll_params->flags |= TEGRA_PLLMB;
pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 7ee764e583f9..330729a822cf 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -269,6 +269,8 @@ struct tegra_clk_pll_params {
int (*calc_rate)(struct clk_hw *hw,
struct tegra_clk_pll_freq_table *cfg,
unsigned long rate, unsigned long parent_rate);
+ unsigned long (*adjust_vco)(struct tegra_clk_pll_params *pll_params,
+ unsigned long parent_rate);
};

#define TEGRA_PLL_USE_LOCK BIT(0)
--
1.7.9.5

2015-05-12 17:29:41

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 15/21] clk: tegra: pll: Add dyn_ramp callback

From: Bill Huang <[email protected]>

Add a callback to the pll_params for custom dynamic ramping
functions which can be specified per PLL.

Signed-off-by: Bill Huang <[email protected]>
---
drivers/clk/tegra/clk.h | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 330729a822cf..a61d388364b3 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -160,6 +160,8 @@ struct div_nmp {

#define MAX_PLL_MISC_REG_COUNT 6

+struct tegra_clk_pll;
+
/**
* struct tegra_clk_pll_params - PLL parameters
*
@@ -271,6 +273,8 @@ struct tegra_clk_pll_params {
unsigned long rate, unsigned long parent_rate);
unsigned long (*adjust_vco)(struct tegra_clk_pll_params *pll_params,
unsigned long parent_rate);
+ int (*dyn_ramp)(struct tegra_clk_pll *pll,
+ struct tegra_clk_pll_freq_table *cfg);
};

#define TEGRA_PLL_USE_LOCK BIT(0)
--
1.7.9.5

2015-05-12 17:29:39

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 16/21] clk: tegra: pll: Add Set_default logic

From: Bill Huang <[email protected]>

Add logic which (if specified for a pll) can verify that a PLL is set
to the proper default value and if not can set it. This can be
specified per PLL as each will have different default values.

Based on original work by Aleksandr Frid <[email protected]>

Signed-off-by: Bill Huang <[email protected]>
---
v2:
- Remove MACRO for PLL_MISC_CHECK_DEFAULT as suggested, and instead
the tegra210 driver will include an inline version of this function.

drivers/clk/tegra/clk-pll.c | 46 ++++++++++++++++++++++++++++++++-----------
drivers/clk/tegra/clk.h | 2 ++
2 files changed, 37 insertions(+), 11 deletions(-)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 626466665dde..36aa2a95fac0 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -652,13 +652,26 @@ static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
unsigned long rate)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
+ struct tegra_clk_pll_freq_table old_cfg;
int state, ret = 0;

state = clk_pll_is_enabled(hw);

+ _get_pll_mnp(pll, &old_cfg);
+
+ if (state && pll->params->defaults_set && pll->params->dyn_ramp &&
+ (cfg->m == old_cfg.m) && (cfg->p == old_cfg.p)) {
+ ret = pll->params->dyn_ramp(pll, cfg);
+ if (!ret)
+ return 0;
+ }
+
if (state)
_clk_pll_disable(hw);

+ if (!pll->params->defaults_set && pll->params->set_defaults)
+ pll->params->set_defaults(pll);
+
_update_pll_mnp(pll, cfg);

if (pll->params->flags & TEGRA_PLL_HAS_CPCON)
@@ -1517,6 +1530,9 @@ static struct clk *_tegra_clk_register_pll(struct tegra_clk_pll *pll,
if (!pll->params->calc_rate)
pll->params->calc_rate = _calc_rate;

+ if (pll->params->set_defaults)
+ pll->params->set_defaults(pll);
+
/* Data in .init is copied by clk_register(), so stack variable OK */
pll->hw.init = &init;

@@ -1636,7 +1652,6 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
struct tegra_clk_pll *pll;
struct clk *clk, *parent;
unsigned long parent_rate;
- int err;
u32 val, val_iddq;

parent = __clk_lookup(parent_name);
@@ -1657,18 +1672,27 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
pll_params->vco_min = pll_params->adjust_vco(pll_params,
parent_rate);

- err = _setup_dynamic_ramp(pll_params, clk_base, parent_rate);
- if (err)
- return ERR_PTR(err);
+ /*
+ * If the pll has a set_defaults callback, it will take care of
+ * configuring dynamic ramping and setting IDDQ in that path.
+ */
+ if (!pll_params->set_defaults) {
+ int err;

- val = readl_relaxed(clk_base + pll_params->base_reg);
- val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg);
+ err = _setup_dynamic_ramp(pll_params, clk_base, parent_rate);
+ if (err)
+ return ERR_PTR(err);

- if (val & PLL_BASE_ENABLE)
- WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx));
- else {
- val_iddq |= BIT(pll_params->iddq_bit_idx);
- writel_relaxed(val_iddq, clk_base + pll_params->iddq_reg);
+ val = readl_relaxed(clk_base + pll_params->base_reg);
+ val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg);
+
+ if (val & PLL_BASE_ENABLE)
+ WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx));
+ else {
+ val_iddq |= BIT(pll_params->iddq_bit_idx);
+ writel_relaxed(val_iddq,
+ clk_base + pll_params->iddq_reg);
+ }
}

pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index a61d388364b3..38b4c95cfb2f 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -261,6 +261,7 @@ struct tegra_clk_pll_params {
int stepb_shift;
int lock_delay;
int max_p;
+ bool defaults_set;
struct pdiv_map *pdiv_tohw;
struct div_nmp *div_nmp;
struct tegra_clk_pll_freq_table *freq_table;
@@ -275,6 +276,7 @@ struct tegra_clk_pll_params {
unsigned long parent_rate);
int (*dyn_ramp)(struct tegra_clk_pll *pll,
struct tegra_clk_pll_freq_table *cfg);
+ void (*set_defaults)(struct tegra_clk_pll *pll);
};

#define TEGRA_PLL_USE_LOCK BIT(0)
--
1.7.9.5

2015-05-12 17:28:28

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 17/21] clk: tegra: pll: Add logic for SS

From: Bill Huang <[email protected]>

Add some logic for Spread Spectrum control. It is used in conjuncture
with SDM fractional dividers. SSC has to be disabled when we configure
the divider settings.

Signed-off-by: Bill Huang <[email protected]>
---
v5:
- Reorderd Patch so set_defaults logic is present already

drivers/clk/tegra/clk-pll.c | 25 ++++++++++++++++++++++++-
drivers/clk/tegra/clk.h | 4 ++++
2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 36aa2a95fac0..727fedff824d 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -648,6 +648,26 @@ static void _update_pll_cpcon(struct tegra_clk_pll *pll,
pll_writel_misc(val, pll);
}

+static void pll_clk_start_ss(struct tegra_clk_pll *pll)
+{
+ if (pll->params->defaults_set && pll->params->ssc_ctrl_en_mask) {
+ u32 val = pll_readl(pll->params->ssc_ctrl_reg, pll);
+
+ val |= pll->params->ssc_ctrl_en_mask;
+ pll_writel(val, pll->params->ssc_ctrl_reg, pll);
+ }
+}
+
+static void pll_clk_stop_ss(struct tegra_clk_pll *pll)
+{
+ if (pll->params->defaults_set && pll->params->ssc_ctrl_en_mask) {
+ u32 val = pll_readl(pll->params->ssc_ctrl_reg, pll);
+
+ val &= ~pll->params->ssc_ctrl_en_mask;
+ pll_writel(val, pll->params->ssc_ctrl_reg, pll);
+ }
+}
+
static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
unsigned long rate)
{
@@ -666,8 +686,10 @@ static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
return 0;
}

- if (state)
+ if (state) {
+ pll_clk_stop_ss(pll);
_clk_pll_disable(hw);
+ }

if (!pll->params->defaults_set && pll->params->set_defaults)
pll->params->set_defaults(pll);
@@ -680,6 +702,7 @@ static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
if (state) {
_clk_pll_enable(hw);
ret = clk_pll_wait_for_lock(pll);
+ pll_clk_start_ss(pll);
}

return ret;
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 38b4c95cfb2f..32ce32a056ca 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -184,6 +184,8 @@ struct tegra_clk_pll;
* @sdm_din_mask: Mask of SDM divider bits
* @sdm_ctrl_reg: Register offset where SDM enable is
* @sdm_ctrl_en_mask: Mask of SDM enable bit
+ * @ssc_ctrl_reg: Register offset where SSC settings are
+ * @ssc_ctrl_en_mask: Mask of SSC enable bit
* @aux_reg: AUX register offset
* @dyn_ramp_reg: Dynamic ramp control register offset
* @ext_misc_reg: Miscellaneous control register offsets
@@ -251,6 +253,8 @@ struct tegra_clk_pll_params {
u32 sdm_din_mask;
u32 sdm_ctrl_reg;
u32 sdm_ctrl_en_mask;
+ u32 ssc_ctrl_reg;
+ u32 ssc_ctrl_en_mask;
u32 aux_reg;
u32 dyn_ramp_reg;
u32 ext_misc_reg[MAX_PLL_MISC_REG_COUNT];
--
1.7.9.5

2015-05-12 17:28:04

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 18/21] clk: tegra: pll: Fix _pll_ramp_calc_pll logic and _calc_dynamic_ramp_rate

This removes the conversion from pdiv to hw, which is already taken
care of by _get_table_rate before this code is run. This avoids
incorrectly converting pdiv to hw twice and getting the wrong hw value.

Also set the input_rate in the freq cfg in _calc_dynamic_ramp_rate while
setting all the other fields.

Signed-off-by: Rhyland Klein <[email protected]>
---
v2:
- Added fix for _calc_dynamic_ramp_rate where input_rate wasn't ever
populated in the cfg, which could cause problems later if/when
accessed.

drivers/clk/tegra/clk-pll.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 727fedff824d..43d7ee4fb603 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -1032,6 +1032,7 @@ static int _calc_dynamic_ramp_rate(struct clk_hw *hw,
cfg->m = _pll_fixed_mdiv(pll->params, parent_rate);
cfg->output_rate = rate * p;
cfg->n = cfg->output_rate * cfg->m / parent_rate;
+ cfg->input_rate = parent_rate;

p_div = _p_div_to_hw(hw, p);
if (p_div < 0)
@@ -1050,7 +1051,7 @@ static int _pll_ramp_calc_pll(struct clk_hw *hw,
unsigned long rate, unsigned long parent_rate)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
- int err = 0, p_div;
+ int err = 0;

err = _get_table_rate(hw, cfg, rate, parent_rate);
if (err < 0)
@@ -1061,11 +1062,6 @@ static int _pll_ramp_calc_pll(struct clk_hw *hw,
err = -EINVAL;
goto out;
}
- p_div = _p_div_to_hw(hw, cfg->p);
- if (p_div < 0)
- return p_div;
- else
- cfg->p = p_div;
}

if (cfg->p > pll->params->max_p)
--
1.7.9.5

2015-05-12 17:27:44

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 19/21] clk: tegra: Add Super Gen5 Logic

From: Bill Huang <[email protected]>

Super clock divider control and clock source mux of Tegra210 has changed
a little against prior SoCs, this patch adds Gen5 logic to address those
differences.

Signed-off-by: Bill Huang <[email protected]>
---
v2:
- Fixed sclk divider address (0x370 -> 0x2c)

drivers/clk/tegra/Makefile | 1 +
drivers/clk/tegra/clk-tegra-super-gen5.c | 150 ++++++++++++++++++++++++++++++
drivers/clk/tegra/clk.h | 3 +
3 files changed, 154 insertions(+)
create mode 100644 drivers/clk/tegra/clk-tegra-super-gen5.c

diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
index edb8358fa6ce..ff0c3e205db6 100644
--- a/drivers/clk/tegra/Makefile
+++ b/drivers/clk/tegra/Makefile
@@ -11,6 +11,7 @@ obj-y += clk-tegra-periph.o
obj-y += clk-tegra-pmc.o
obj-y += clk-tegra-fixed.o
obj-y += clk-tegra-super-gen4.o
+obj-y += clk-tegra-super-gen5.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o
diff --git a/drivers/clk/tegra/clk-tegra-super-gen5.c b/drivers/clk/tegra/clk-tegra-super-gen5.c
new file mode 100644
index 000000000000..14c3c3ad2079
--- /dev/null
+++ b/drivers/clk/tegra/clk-tegra-super-gen5.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/clk/tegra.h>
+
+#include "clk.h"
+#include "clk-id.h"
+
+#define PLLX_BASE 0xe0
+#define PLLX_MISC 0xe4
+#define PLLX_MISC2 0x514
+#define PLLX_MISC3 0x518
+
+#define CCLKG_BURST_POLICY 0x368
+#define CCLKLP_BURST_POLICY 0x370
+#define SCLK_DIVIDER 0x2c
+#define SCLK_BURST_POLICY 0x028
+#define SYSTEM_CLK_RATE 0x030
+
+static DEFINE_SPINLOCK(sysrate_lock);
+
+static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_c4_out3",
+ "pll_p", "pll_p_out2", "pll_c4_out1",
+ "clk_32k", "pll_c4_out2" };
+
+static const char *cclk_g_parents[] = { "clk_m", "unused", "clk_32k", "unused",
+ "pll_p", "pll_p_out4", "unused",
+ "unused", "pll_x", "unused", "unused",
+ "unused", "unused", "unused", "unused",
+ "dfllCPU_out" };
+
+static const char *cclk_lp_parents[] = { "clk_m", "unused", "clk_32k", "unused",
+ "pll_p", "pll_p_out4", "unused",
+ "unused", "pll_x", "unused", "unused",
+ "unused", "unused", "unused", "unused",
+ "dfllCPU_out" };
+
+static void __init tegra_sclk_init(void __iomem *clk_base,
+ struct tegra_clk *tegra_clks)
+{
+ struct clk *clk;
+ struct clk **dt_clk;
+
+ /* SCLK_MUX */
+ dt_clk = tegra_lookup_dt_id(tegra_clk_sclk_mux, tegra_clks);
+ if (dt_clk) {
+ clk = tegra_clk_register_super_mux("sclk_mux", sclk_parents,
+ ARRAY_SIZE(sclk_parents),
+ CLK_SET_RATE_PARENT,
+ clk_base + SCLK_BURST_POLICY,
+ 0, 4, 0, 0, NULL);
+ *dt_clk = clk;
+ }
+ /* SCLK */
+ dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks);
+ if (dt_clk) {
+ clk = clk_register_divider(NULL, "sclk", "sclk_mux", 0,
+ clk_base + SCLK_DIVIDER, 0, 8,
+ 0, &sysrate_lock);
+ *dt_clk = clk;
+ }
+
+ /* HCLK */
+ dt_clk = tegra_lookup_dt_id(tegra_clk_hclk, tegra_clks);
+ if (dt_clk) {
+ clk = clk_register_divider(NULL, "hclk_div", "sclk", 0,
+ clk_base + SYSTEM_CLK_RATE, 4, 2, 0,
+ &sysrate_lock);
+ clk = clk_register_gate(NULL, "hclk", "hclk_div",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ clk_base + SYSTEM_CLK_RATE,
+ 7, CLK_GATE_SET_TO_DISABLE, &sysrate_lock);
+ *dt_clk = clk;
+ }
+
+ /* PCLK */
+ dt_clk = tegra_lookup_dt_id(tegra_clk_pclk, tegra_clks);
+ if (!dt_clk)
+ return;
+
+ clk = clk_register_divider(NULL, "pclk_div", "hclk", 0,
+ clk_base + SYSTEM_CLK_RATE, 0, 2, 0,
+ &sysrate_lock);
+ clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT |
+ CLK_IGNORE_UNUSED, clk_base + SYSTEM_CLK_RATE,
+ 3, CLK_GATE_SET_TO_DISABLE, &sysrate_lock);
+ *dt_clk = clk;
+}
+
+void __init tegra_super_clk_gen5_init(void __iomem *clk_base,
+ void __iomem *pmc_base,
+ struct tegra_clk *tegra_clks,
+ struct tegra_clk_pll_params *params)
+{
+ struct clk *clk;
+ struct clk **dt_clk;
+
+ /* CCLKG */
+ dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_g, tegra_clks);
+ if (dt_clk) {
+ clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents,
+ ARRAY_SIZE(cclk_g_parents),
+ CLK_SET_RATE_PARENT,
+ clk_base + CCLKG_BURST_POLICY,
+ 0, 4, 8, 0, NULL);
+ *dt_clk = clk;
+ }
+
+ /* CCLKLP */
+ dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_lp, tegra_clks);
+ if (dt_clk) {
+ clk = tegra_clk_register_super_mux("cclk_lp", cclk_lp_parents,
+ ARRAY_SIZE(cclk_lp_parents),
+ CLK_SET_RATE_PARENT,
+ clk_base + CCLKLP_BURST_POLICY,
+ 0, 4, 8, 0, NULL);
+ *dt_clk = clk;
+ }
+
+ tegra_sclk_init(clk_base, tegra_clks);
+
+ /* PLLX */
+ dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x, tegra_clks);
+ if (!dt_clk)
+ return;
+
+ clk = tegra_clk_register_pllxc("pll_x", "pll_ref", clk_base,
+ pmc_base, CLK_IGNORE_UNUSED, params, NULL);
+ *dt_clk = clk;
+}
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 32ce32a056ca..ec5939c03e2c 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -726,6 +726,9 @@ int tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks,
void tegra_super_clk_gen4_init(void __iomem *clk_base,
void __iomem *pmc_base, struct tegra_clk *tegra_clks,
struct tegra_clk_pll_params *pll_params);
+void tegra_super_clk_gen5_init(void __iomem *clk_base,
+ void __iomem *pmc_base, struct tegra_clk *tegra_clks,
+ struct tegra_clk_pll_params *pll_params);

void tegra114_clock_tune_cpu_trimmers_high(void);
void tegra114_clock_tune_cpu_trimmers_low(void);
--
1.7.9.5

2015-05-12 17:27:20

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 20/21] clk: tegra210: add support for Tegra210 clocks

Implement clock support for Tegra210.

Signed-off-by: Rhyland Klein <[email protected]>
---
v5:
- Fixed UTMIP_PLL_CFG1/2 MACROS
- Added pr_warns for set_defaults when PLL is already enabled
- Changed vco_out member to flag instead (as it was simple boolean anyway)
- Switch to using clk72Mhz_8 for new mux
- Added usb2_hsic_trk, hsic_trk, and usb2_trk clks
- renamed pll_d_dsi -> pll_d_dsi_out
- Used ARRAY_SIZE for tegra_audio_clk_init
- Initialzed pll_dp to allow set_defaults to run properly

v4:
- Fixed checkpatch errors
- Fixed pllx_dyn_ramp error (missing ->params)

v3:
- Fixed pll_u hierarchy. PLL_U has a vco output now, and out1 and out2
clocks which are used to generate 60M and 48M clocks. VCO is used for
480M clock and the pll_u_out clock generates the 240M clock.
- Renamed pll_u -> pll_u_vco
- Removed 12M clock which doesn't exist anymore
- Renamed pll_re_c4_div_table -> pll_vco_post_div_table
- Set initial rates for pll_u_out1/2 for 48M/60M respectively.

v2:
- Fixed pll_a sdm_din_reg address (MISC0 -> MISC1)
- Fixed plld_set_defaults to not override DSI_CLKENABLE
- Fixed error in pll_e_freq table where cml divider was set into wrong field
- Removed freq comments based on previous review comments
- Removed freq for FPGA as suggested
- Added _pll_misc_chk_default inline function
- Fixed error in pllx dynamic ramp logic

.../bindings/clock/nvidia,tegra210-car.txt | 56 +
drivers/clk/tegra/Makefile | 1 +
drivers/clk/tegra/clk-id.h | 7 +
drivers/clk/tegra/clk-tegra210.c | 2792 ++++++++++++++++++++
drivers/clk/tegra/clk.h | 2 +
include/dt-bindings/clock/tegra210-car.h | 401 +++
6 files changed, 3259 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/nvidia,tegra210-car.txt
create mode 100644 drivers/clk/tegra/clk-tegra210.c
create mode 100644 include/dt-bindings/clock/tegra210-car.h

diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra210-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra210-car.txt
new file mode 100644
index 000000000000..26f237f641b7
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/nvidia,tegra210-car.txt
@@ -0,0 +1,56 @@
+NVIDIA Tegra210 Clock And Reset Controller
+
+This binding uses the common clock binding:
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The CAR (Clock And Reset) Controller on Tegra is the HW module responsible
+for muxing and gating Tegra's clocks, and setting their rates.
+
+Required properties :
+- compatible : Should be "nvidia,tegra210-car"
+- reg : Should contain CAR registers location and length
+- clocks : Should contain phandle and clock specifiers for two clocks:
+ the 32 KHz "32k_in".
+- #clock-cells : Should be 1.
+ In clock consumers, this cell represents the clock ID exposed by the
+ CAR. The assignments may be found in header file
+ <dt-bindings/clock/tegra210-car.h>.
+- #reset-cells : Should be 1.
+ In clock consumers, this cell represents the bit number in the CAR's
+ array of CLK_RST_CONTROLLER_RST_DEVICES_* registers.
+
+Example SoC include file:
+
+/ {
+ tegra_car: clock {
+ compatible = "nvidia,tegra210-car";
+ reg = <0x60006000 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ usb@c5004000 {
+ clocks = <&tegra_car TEGRA210_CLK_USB2>;
+ };
+};
+
+Example board file:
+
+/ {
+ clocks {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ clk_32k: clock@1 {
+ compatible = "fixed-clock";
+ reg = <1>;
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+ };
+
+ &tegra_car {
+ clocks = <&clk_32k>;
+ };
+};
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
index ff0c3e205db6..3b868f41926a 100644
--- a/drivers/clk/tegra/Makefile
+++ b/drivers/clk/tegra/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o
obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124.o
obj-$(CONFIG_ARCH_TEGRA_132_SOC) += clk-tegra124.o
+obj-$(CONFIG_ARCH_TEGRA_210_SOC) += clk-tegra210.o
diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h
index 768c913e5bdc..4488c75f5d93 100644
--- a/drivers/clk/tegra/clk-id.h
+++ b/drivers/clk/tegra/clk-id.h
@@ -152,6 +152,10 @@ enum clk_id {
tegra_clk_pll_c2,
tegra_clk_pll_c3,
tegra_clk_pll_c4,
+ tegra_clk_pll_c4_out0,
+ tegra_clk_pll_c4_out1,
+ tegra_clk_pll_c4_out2,
+ tegra_clk_pll_c4_out3,
tegra_clk_pll_c_out1,
tegra_clk_pll_d,
tegra_clk_pll_d2,
@@ -174,6 +178,9 @@ enum clk_id {
tegra_clk_pll_re_out,
tegra_clk_pll_re_vco,
tegra_clk_pll_u,
+ tegra_clk_pll_u_out,
+ tegra_clk_pll_u_out1,
+ tegra_clk_pll_u_out2,
tegra_clk_pll_u_12m,
tegra_clk_pll_u_480m,
tegra_clk_pll_u_48m,
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
new file mode 100644
index 000000000000..7f25e60e4d48
--- /dev/null
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -0,0 +1,2792 @@
+/*
+ * Copyright (c) 2012-2014 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/clk/tegra.h>
+#include <dt-bindings/clock/tegra210-car.h>
+
+#include "clk.h"
+#include "clk-id.h"
+
+/*
+ * TEGRA210_CAR_BANK_COUNT: the number of peripheral clock register
+ * banks present in the Tegra210 CAR IP block. The banks are
+ * identified by single letters, e.g.: L, H, U, V, W, X, Y. See
+ * periph_regs[] in drivers/clk/tegra/clk.c
+ */
+#define TEGRA210_CAR_BANK_COUNT 7
+
+#define CLK_SOURCE_CSITE 0x1d4
+#define CLK_SOURCE_EMC 0x19c
+
+#define PLLC_BASE 0x80
+#define PLLC_OUT 0x84
+#define PLLC_MISC0 0x88
+#define PLLC_MISC1 0x8c
+#define PLLC_MISC2 0x5d0
+#define PLLC_MISC3 0x5d4
+
+#define PLLC2_BASE 0x4e8
+#define PLLC2_MISC0 0x4ec
+#define PLLC2_MISC1 0x4f0
+#define PLLC2_MISC2 0x4f4
+#define PLLC2_MISC3 0x4f8
+
+#define PLLC3_BASE 0x4fc
+#define PLLC3_MISC0 0x500
+#define PLLC3_MISC1 0x504
+#define PLLC3_MISC2 0x508
+#define PLLC3_MISC3 0x50c
+
+#define PLLM_BASE 0x90
+#define PLLM_MISC0 0x9c
+#define PLLM_MISC1 0x98
+#define PLLP_BASE 0xa0
+#define PLLP_MISC0 0xac
+#define PLLP_MISC1 0x680
+#define PLLA_BASE 0xb0
+#define PLLA_MISC0 0xbc
+#define PLLA_MISC1 0xb8
+#define PLLA_MISC2 0x5d8
+#define PLLD_BASE 0xd0
+#define PLLD_MISC0 0xdc
+#define PLLD_MISC1 0xd8
+#define PLLU_BASE 0xc0
+#define PLLU_OUTA 0xc4
+#define PLLU_MISC0 0xcc
+#define PLLU_MISC1 0xc8
+#define PLLX_BASE 0xe0
+#define PLLX_MISC0 0xe4
+#define PLLX_MISC1 0x510
+#define PLLX_MISC2 0x514
+#define PLLX_MISC3 0x518
+#define PLLX_MISC4 0x5f0
+#define PLLX_MISC5 0x5f4
+#define PLLE_BASE 0xe8
+#define PLLE_MISC0 0xec
+#define PLLD2_BASE 0x4b8
+#define PLLD2_MISC0 0x4bc
+#define PLLD2_MISC1 0x570
+#define PLLD2_MISC2 0x574
+#define PLLD2_MISC3 0x578
+#define PLLE_AUX 0x48c
+#define PLLRE_BASE 0x4c4
+#define PLLRE_MISC0 0x4c8
+#define PLLDP_BASE 0x590
+#define PLLDP_MISC 0x594
+
+#define PLLC4_BASE 0x5a4
+#define PLLC4_MISC0 0x5a8
+#define PLLC4_OUT 0x5e4
+#define PLLMB_BASE 0x5e8
+#define PLLMB_MISC0 0x5ec
+#define PLLA1_BASE 0x6a4
+#define PLLA1_MISC0 0x6a8
+#define PLLA1_MISC1 0x6ac
+#define PLLA1_MISC2 0x6b0
+#define PLLA1_MISC3 0x6b4
+
+#define PLLU_IDDQ_BIT 31
+#define PLLCX_IDDQ_BIT 27
+#define PLLRE_IDDQ_BIT 24
+#define PLLA_IDDQ_BIT 25
+#define PLLD_IDDQ_BIT 20
+#define PLLSS_IDDQ_BIT 18
+#define PLLM_IDDQ_BIT 5
+#define PLLMB_IDDQ_BIT 17
+#define PLLXP_IDDQ_BIT 3
+
+#define PLLCX_RESET_BIT 30
+
+#define PLL_BASE_LOCK BIT(27)
+#define PLLCX_BASE_LOCK BIT(26)
+#define PLLE_MISC_LOCK BIT(11)
+#define PLLRE_MISC_LOCK BIT(27)
+
+#define PLL_MISC_LOCK_ENABLE 18
+#define PLLC_MISC_LOCK_ENABLE 24
+#define PLLDU_MISC_LOCK_ENABLE 22
+#define PLLU_MISC_LOCK_ENABLE 29
+#define PLLE_MISC_LOCK_ENABLE 9
+#define PLLRE_MISC_LOCK_ENABLE 30
+#define PLLSS_MISC_LOCK_ENABLE 30
+#define PLLP_MISC_LOCK_ENABLE 18
+#define PLLM_MISC_LOCK_ENABLE 4
+#define PLLMB_MISC_LOCK_ENABLE 16
+#define PLLA_MISC_LOCK_ENABLE 28
+#define PLLU_MISC_LOCK_ENABLE 29
+#define PLLD_MISC_LOCK_ENABLE 18
+
+#define PLLA_SDM_DIN_MASK 0xffff
+#define PLLA_SDM_EN_MASK BIT(26)
+
+#define PLLD_SDM_EN_MASK BIT(16)
+
+#define PLLD2_SDM_EN_MASK BIT(31)
+#define PLLD2_SSC_EN_MASK BIT(30)
+
+#define PLLDP_SS_CFG 0x598
+#define PLLDP_SDM_EN_MASK BIT(31)
+#define PLLDP_SSC_EN_MASK BIT(30)
+#define PLLDP_SS_CTRL1 0x59c
+#define PLLDP_SS_CTRL2 0x5a0
+
+#define PMC_PLLM_WB0_OVERRIDE 0x1dc
+#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0
+
+#define UTMIP_PLL_CFG2 0x488
+#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xfff) << 6)
+#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4)
+
+#define UTMIP_PLL_CFG1 0x484
+#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
+#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP BIT(17)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP BIT(15)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12)
+
+#define UTMIPLL_HW_PWRDN_CFG0 0x52c
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE BIT(25)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE BIT(24)
+#define UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET BIT(6)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_RESET_INPUT_VALUE BIT(5)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_IN_SWCTL BIT(4)
+#define UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL BIT(2)
+#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE BIT(1)
+#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL BIT(0)
+
+#define SPARE_REG0 0x55c
+#define CLK_M_DIVISOR_SHIFT 2
+#define CLK_M_DIVISOR_MASK 0x3
+
+/*
+ * SDM fractional divisor is 16-bit 2's complement signed number within
+ * (-2^12 ... 2^12-1) range. Represented in PLL data structure as unsigned
+ * 16-bit value, with "0" divisor mapped to 0xFFFF. Data "0" is used to
+ * indicate that SDM is disabled.
+ *
+ * Effective ndiv value when SDM is enabled: ndiv + 1/2 + sdm_din/2^13
+ */
+#define PLL_SDM_COEFF BIT(13)
+#define sdin_din_to_data(din) ((u16)((din) ? : 0xFFFFU))
+#define sdin_data_to_din(dat) (((dat) == 0xFFFFU) ? 0 : (s16)dat)
+
+/* Tegra CPU clock and reset control regs */
+#define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470
+
+#ifdef CONFIG_PM_SLEEP
+static struct cpu_clk_suspend_context {
+ u32 clk_csite_src;
+} tegra210_cpu_clk_sctx;
+#endif
+
+static void __iomem *clk_base;
+static void __iomem *pmc_base;
+
+static unsigned long osc_freq;
+static unsigned long pll_ref_freq;
+
+static DEFINE_SPINLOCK(pll_d_lock);
+static DEFINE_SPINLOCK(pll_e_lock);
+static DEFINE_SPINLOCK(pll_re_lock);
+static DEFINE_SPINLOCK(pll_u_lock);
+static DEFINE_SPINLOCK(emc_lock);
+
+/* possible OSC frequencies in Hz */
+static unsigned long tegra210_input_freq[] = {
+ [5] = 38400000,
+ [8] = 12000000,
+};
+
+static const char *mux_pllmcp_clkm[] = {
+ "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_c2", "pll_c3",
+};
+#define mux_pllmcp_clkm_idx NULL
+
+#define PLL_ENABLE (1 << 30)
+
+#define PLLCX_MISC1_IDDQ (1 << 27)
+#define PLLCX_MISC0_RESET (1 << 30)
+
+#define PLLCX_MISC0_DEFAULT_VALUE 0x40080000
+#define PLLCX_MISC0_WRITE_MASK 0x400ffffb
+#define PLLCX_MISC1_DEFAULT_VALUE 0x08000000
+#define PLLCX_MISC1_WRITE_MASK 0x08003cff
+#define PLLCX_MISC2_DEFAULT_VALUE 0x1f720f05
+#define PLLCX_MISC2_WRITE_MASK 0xffffff17
+#define PLLCX_MISC3_DEFAULT_VALUE 0x000000c4
+#define PLLCX_MISC3_WRITE_MASK 0x00ffffff
+
+/* PLLA */
+#define PLLA_BASE_IDDQ (1 << 25)
+#define PLLA_BASE_LOCK (1 << 27)
+
+#define PLLA_MISC0_LOCK_ENABLE (1 << 28)
+#define PLLA_MISC0_LOCK_OVERRIDE (1 << 27)
+
+#define PLLA_MISC2_EN_SDM (1 << 26)
+#define PLLA_MISC2_EN_DYNRAMP (1 << 25)
+
+#define PLLA_MISC0_DEFAULT_VALUE 0x12000020
+#define PLLA_MISC0_WRITE_MASK 0x7fffffff
+#define PLLA_MISC2_DEFAULT_VALUE 0x0
+#define PLLA_MISC2_WRITE_MASK 0x06ffffff
+
+/* PLLD */
+#define PLLD_MISC0_EN_SDM (1 << 16)
+#define PLLD_MISC0_LOCK_OVERRIDE (1 << 17)
+#define PLLD_MISC0_LOCK_ENABLE (1 << 18)
+#define PLLD_MISC0_IDDQ (1 << 20)
+#define PLLD_MISC0_DSI_CLKENABLE (1 << 21)
+
+#define PLLD_MISC0_DEFAULT_VALUE 0x00140000
+#define PLLD_MISC0_WRITE_MASK 0x3ff7ffff
+#define PLLD_MISC1_DEFAULT_VALUE 0x20
+#define PLLD_MISC1_WRITE_MASK 0x00ffffff
+
+/* PLLD2 and PLLDP and PLLC4 */
+#define PLLDSS_BASE_LOCK (1 << 27)
+#define PLLDSS_BASE_LOCK_OVERRIDE (1 << 24)
+#define PLLDSS_BASE_IDDQ (1 << 18)
+#define PLLDSS_BASE_REF_SEL_SHIFT 25
+#define PLLDSS_BASE_REF_SEL_MASK (0x3 << PLLDSS_BASE_REF_SEL_SHIFT)
+
+#define PLLDSS_MISC0_LOCK_ENABLE (1 << 30)
+
+#define PLLDSS_MISC1_CFG_EN_SDM (1 << 31)
+#define PLLDSS_MISC1_CFG_EN_SSC (1 << 30)
+
+#define PLLD2_MISC0_DEFAULT_VALUE 0x40000020
+#define PLLD2_MISC1_CFG_DEFAULT_VALUE 0x10000000
+#define PLLD2_MISC2_CTRL1_DEFAULT_VALUE 0x0
+#define PLLD2_MISC3_CTRL2_DEFAULT_VALUE 0x0
+
+#define PLLDP_MISC0_DEFAULT_VALUE 0x40000020
+#define PLLDP_MISC1_CFG_DEFAULT_VALUE 0xc0000000
+#define PLLDP_MISC2_CTRL1_DEFAULT_VALUE 0xf400f0da
+#define PLLDP_MISC3_CTRL2_DEFAULT_VALUE 0x2004f400
+
+#define PLLDSS_MISC0_WRITE_MASK 0x47ffffff
+#define PLLDSS_MISC1_CFG_WRITE_MASK 0xf8000000
+#define PLLDSS_MISC2_CTRL1_WRITE_MASK 0xffffffff
+#define PLLDSS_MISC3_CTRL2_WRITE_MASK 0xffffffff
+
+#define PLLC4_MISC0_DEFAULT_VALUE 0x40000000
+
+/* PLLRE */
+#define PLLRE_MISC0_LOCK_ENABLE (1 << 30)
+#define PLLRE_MISC0_LOCK_OVERRIDE (1 << 29)
+#define PLLRE_MISC0_LOCK (1 << 27)
+#define PLLRE_MISC0_IDDQ (1 << 24)
+
+#define PLLRE_BASE_DEFAULT_VALUE 0x0
+#define PLLRE_MISC0_DEFAULT_VALUE 0x41000000
+
+#define PLLRE_BASE_DEFAULT_MASK 0x1c000000
+#define PLLRE_MISC0_WRITE_MASK 0x67ffffff
+
+/* PLLX */
+#define PLLX_USE_DYN_RAMP 1
+#define PLLX_BASE_LOCK (1 << 27)
+
+#define PLLX_MISC0_FO_G_DISABLE (0x1 << 28)
+#define PLLX_MISC0_LOCK_ENABLE (0x1 << 18)
+
+#define PLLX_MISC2_DYNRAMP_STEPB_SHIFT 24
+#define PLLX_MISC2_DYNRAMP_STEPB_MASK (0xFF << PLLX_MISC2_DYNRAMP_STEPB_SHIFT)
+#define PLLX_MISC2_DYNRAMP_STEPA_SHIFT 16
+#define PLLX_MISC2_DYNRAMP_STEPA_MASK (0xFF << PLLX_MISC2_DYNRAMP_STEPA_SHIFT)
+#define PLLX_MISC2_NDIV_NEW_SHIFT 8
+#define PLLX_MISC2_NDIV_NEW_MASK (0xFF << PLLX_MISC2_NDIV_NEW_SHIFT)
+#define PLLX_MISC2_LOCK_OVERRIDE (0x1 << 4)
+#define PLLX_MISC2_DYNRAMP_DONE (0x1 << 2)
+#define PLLX_MISC2_EN_DYNRAMP (0x1 << 0)
+
+#define PLLX_MISC3_IDDQ (0x1 << 3)
+
+#define PLLX_MISC0_DEFAULT_VALUE PLLX_MISC0_LOCK_ENABLE
+#define PLLX_MISC0_WRITE_MASK 0x10c40000
+#define PLLX_MISC1_DEFAULT_VALUE 0x20
+#define PLLX_MISC1_WRITE_MASK 0x00ffffff
+#define PLLX_MISC2_DEFAULT_VALUE 0x0
+#define PLLX_MISC2_WRITE_MASK 0xffffff11
+#define PLLX_MISC3_DEFAULT_VALUE PLLX_MISC3_IDDQ
+#define PLLX_MISC3_WRITE_MASK 0x01ff0f0f
+#define PLLX_MISC4_DEFAULT_VALUE 0x0
+#define PLLX_MISC4_WRITE_MASK 0x8000ffff
+#define PLLX_MISC5_DEFAULT_VALUE 0x0
+#define PLLX_MISC5_WRITE_MASK 0x0000ffff
+
+#define PLLX_HW_CTRL_CFG 0x548
+#define PLLX_HW_CTRL_CFG_SWCTRL (0x1 << 0)
+
+/* PLLMB */
+#define PLLMB_BASE_LOCK (1 << 27)
+
+#define PLLMB_MISC0_LOCK_OVERRIDE (1 << 18)
+#define PLLMB_MISC0_IDDQ (1 << 17)
+#define PLLMB_MISC0_LOCK_ENABLE (1 << 16)
+
+#define PLLMB_MISC0_DEFAULT_VALUE 0x00030000
+#define PLLMB_MISC0_WRITE_MASK 0x0007ffff
+
+/* PLLP */
+#define PLLP_BASE_OVERRIDE (1 << 28)
+#define PLLP_BASE_LOCK (1 << 27)
+
+#define PLLP_MISC0_LOCK_ENABLE (1 << 18)
+#define PLLP_MISC0_LOCK_OVERRIDE (1 << 17)
+#define PLLP_MISC0_IDDQ (1 << 3)
+
+#define PLLP_MISC1_HSIO_EN_SHIFT 29
+#define PLLP_MISC1_HSIO_EN (1 << PLLP_MISC1_HSIO_EN_SHIFT)
+#define PLLP_MISC1_XUSB_EN_SHIFT 28
+#define PLLP_MISC1_XUSB_EN (1 << PLLP_MISC1_XUSB_EN_SHIFT)
+
+#define PLLP_MISC0_DEFAULT_VALUE 0x00040008
+#define PLLP_MISC1_DEFAULT_VALUE 0x0
+
+#define PLLP_MISC0_WRITE_MASK 0xdc6000f
+#define PLLP_MISC1_WRITE_MASK 0x70ffffff
+
+/* PLLU */
+#define PLLU_BASE_LOCK (1 << 27)
+#define PLLU_BASE_OVERRIDE (1 << 24)
+#define PLLU_BASE_CLKENABLE_USB (1 << 21)
+
+#define PLLU_MISC0_IDDQ (1 << 31)
+#define PLLU_MISC0_LOCK_ENABLE (1 << 29)
+#define PLLU_MISC1_LOCK_OVERRIDE (1 << 0)
+
+#define PLLU_MISC0_DEFAULT_VALUE 0xa0000000
+#define PLLU_MISC1_DEFAULT_VALUE 0x0
+
+#define PLLU_MISC0_WRITE_MASK 0xbfffffff
+#define PLLU_MISC1_WRITE_MASK 0x00000007
+
+static inline void _pll_misc_chk_default(void __iomem *base,
+ struct tegra_clk_pll_params *params,
+ u8 misc_num, u32 default_val, u32 mask)
+{
+ u32 boot_val = readl_relaxed(base + params->ext_misc_reg[misc_num]);
+
+ boot_val &= mask;
+ default_val &= mask;
+ if (boot_val != default_val) {
+ pr_warn("boot misc%d 0x%x: expected 0x%x\n",
+ misc_num, boot_val, default_val);
+ pr_warn(" (comparison mask = 0x%x)\n", mask);
+ params->defaults_set = false;
+ }
+}
+
+/*
+ * PLLCX: PLLC, PLLC2, PLLC3, PLLA1
+ * Hybrid PLLs with dynamic ramp. Dynamic ramp is allowed for any transition
+ * that changes NDIV only, while PLL is already locked.
+ */
+static void pllcx_check_defaults(struct tegra_clk_pll_params *params)
+{
+ u32 default_val;
+
+ default_val = PLLCX_MISC0_DEFAULT_VALUE & (~PLLCX_MISC0_RESET);
+ _pll_misc_chk_default(clk_base, params, 0, default_val,
+ PLLCX_MISC0_WRITE_MASK);
+
+ default_val = PLLCX_MISC1_DEFAULT_VALUE & (~PLLCX_MISC1_IDDQ);
+ _pll_misc_chk_default(clk_base, params, 1, default_val,
+ PLLCX_MISC1_WRITE_MASK);
+
+ default_val = PLLCX_MISC2_DEFAULT_VALUE;
+ _pll_misc_chk_default(clk_base, params, 2, default_val,
+ PLLCX_MISC2_WRITE_MASK);
+
+ default_val = PLLCX_MISC3_DEFAULT_VALUE;
+ _pll_misc_chk_default(clk_base, params, 3, default_val,
+ PLLCX_MISC3_WRITE_MASK);
+}
+
+void tegra210_pllcx_set_defaults(struct tegra_clk_pll *pllcx)
+{
+ pllcx->params->defaults_set = true;
+
+ if (readl_relaxed(clk_base + pllcx->params->base_reg) &
+ PLL_ENABLE) {
+ /* PLL is ON: only check if defaults already set */
+ pllcx_check_defaults(pllcx->params);
+ pr_warn("%s already enabled. Postponing set full defaults\n",
+ __clk_get_name(pllcx->hw.clk));
+ return;
+ }
+
+ /* Defaults assert PLL reset, and set IDDQ */
+ writel_relaxed(PLLCX_MISC0_DEFAULT_VALUE,
+ clk_base + pllcx->params->ext_misc_reg[0]);
+ writel_relaxed(PLLCX_MISC1_DEFAULT_VALUE,
+ clk_base + pllcx->params->ext_misc_reg[1]);
+ writel_relaxed(PLLCX_MISC2_DEFAULT_VALUE,
+ clk_base + pllcx->params->ext_misc_reg[2]);
+ writel_relaxed(PLLCX_MISC3_DEFAULT_VALUE,
+ clk_base + pllcx->params->ext_misc_reg[3]);
+ udelay(1);
+}
+
+/*
+ * PLLA
+ * PLL with dynamic ramp and fractional SDM. Dynamic ramp is not used.
+ * Fractional SDM is allowed to provide exact audio rates.
+ */
+void tegra210_plla_set_defaults(struct tegra_clk_pll *plla)
+{
+ u32 mask;
+ u32 val = readl_relaxed(clk_base + plla->params->base_reg);
+
+ plla->params->defaults_set = true;
+
+ if (val & PLL_ENABLE) {
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ if (val & PLLA_BASE_IDDQ) {
+ pr_warn("PLL_A boot enabled with IDDQ set\n");
+ plla->params->defaults_set = false;
+ }
+
+ pr_warn("%s already enabled. Postponing set full defaults\n",
+ __clk_get_name(plla->hw.clk));
+
+ val = PLLA_MISC0_DEFAULT_VALUE; /* ignore lock enable */
+ mask = PLLA_MISC0_LOCK_ENABLE | PLLA_MISC0_LOCK_OVERRIDE;
+ _pll_misc_chk_default(clk_base, plla->params, 0, val,
+ ~mask & PLLA_MISC0_WRITE_MASK);
+
+ val = PLLA_MISC2_DEFAULT_VALUE; /* ignore all but control bit */
+ _pll_misc_chk_default(clk_base, plla->params, 2, val,
+ PLLA_MISC2_EN_DYNRAMP);
+
+ /* Enable lock detect */
+ val = readl_relaxed(clk_base + plla->params->ext_misc_reg[0]);
+ val &= ~mask;
+ val |= PLLA_MISC0_DEFAULT_VALUE & mask;
+ writel_relaxed(val, clk_base + plla->params->ext_misc_reg[0]);
+ udelay(1);
+
+ return;
+ }
+
+ /* set IDDQ, enable lock detect, disable dynamic ramp and SDM */
+ val |= PLLA_BASE_IDDQ;
+ writel_relaxed(val, clk_base + plla->params->base_reg);
+ writel_relaxed(PLLA_MISC0_DEFAULT_VALUE,
+ clk_base + plla->params->ext_misc_reg[0]);
+ writel_relaxed(PLLA_MISC2_DEFAULT_VALUE,
+ clk_base + plla->params->ext_misc_reg[2]);
+ udelay(1);
+}
+
+/*
+ * PLLD
+ * PLL with fractional SDM.
+ */
+void tegra210_plld_set_defaults(struct tegra_clk_pll *plld)
+{
+ u32 val;
+ u32 mask = 0xffff;
+
+ plld->params->defaults_set = true;
+
+ if (readl_relaxed(clk_base + plld->params->base_reg) &
+ PLL_ENABLE) {
+ pr_warn("%s already enabled. Postponing set full defaults\n",
+ __clk_get_name(plld->hw.clk));
+
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ val = PLLD_MISC1_DEFAULT_VALUE;
+ _pll_misc_chk_default(clk_base, plld->params, 1,
+ val, PLLD_MISC1_WRITE_MASK);
+
+ /* ignore lock, DSI and SDM controls, make sure IDDQ not set */
+ val = PLLD_MISC0_DEFAULT_VALUE & (~PLLD_MISC0_IDDQ);
+ mask |= PLLD_MISC0_DSI_CLKENABLE | PLLD_MISC0_LOCK_ENABLE |
+ PLLD_MISC0_LOCK_OVERRIDE | PLLD_MISC0_EN_SDM;
+ _pll_misc_chk_default(clk_base, plld->params, 0, val,
+ ~mask & PLLD_MISC0_WRITE_MASK);
+
+ /* Enable lock detect */
+ mask = PLLD_MISC0_LOCK_ENABLE | PLLD_MISC0_LOCK_OVERRIDE;
+ val = readl_relaxed(clk_base + plld->params->ext_misc_reg[0]);
+ val &= ~mask;
+ val |= PLLD_MISC0_DEFAULT_VALUE & mask;
+ writel_relaxed(val, clk_base + plld->params->ext_misc_reg[0]);
+ udelay(1);
+
+ return;
+ }
+
+ val = readl_relaxed(clk_base + plld->params->ext_misc_reg[0]);
+ val &= PLLD_MISC0_DSI_CLKENABLE;
+ val |= PLLD_MISC0_DEFAULT_VALUE;
+ /* set IDDQ, enable lock detect, disable SDM */
+ writel_relaxed(val, clk_base + plld->params->ext_misc_reg[0]);
+ writel_relaxed(PLLD_MISC1_DEFAULT_VALUE, clk_base +
+ plld->params->ext_misc_reg[1]);
+ udelay(1);
+}
+
+/*
+ * PLLD2, PLLDP
+ * PLL with fractional SDM and Spread Spectrum (SDM is a must if SSC is used).
+ */
+static void plldss_defaults(struct tegra_clk_pll *plldss,
+ u32 misc0_val, u32 misc1_val, u32 misc2_val, u32 misc3_val)
+{
+ u32 default_val;
+ u32 val = readl_relaxed(clk_base + plldss->params->base_reg);
+
+ plldss->params->defaults_set = true;
+
+ if (val & PLL_ENABLE) {
+ pr_warn("%s already enabled. Postponing set full defaults\n",
+ __clk_get_name(plldss->hw.clk));
+
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ if (val & PLLDSS_BASE_IDDQ) {
+ pr_warn("plldss boot enabled with IDDQ set\n");
+ plldss->params->defaults_set = false;
+ }
+
+ /* ignore lock enable */
+ default_val = misc0_val;
+ _pll_misc_chk_default(clk_base, plldss->params, 0, default_val,
+ PLLDSS_MISC0_WRITE_MASK &
+ (~PLLDSS_MISC0_LOCK_ENABLE));
+
+ /*
+ * If SSC is used, check all settings, otherwise just confirm
+ * that SSC is not used on boot as well. Do nothing when using
+ * this function for PLLC4 that has only MISC0.
+ */
+ if (plldss->params->ssc_ctrl_en_mask) {
+ default_val = misc1_val;
+ _pll_misc_chk_default(clk_base, plldss->params, 1,
+ default_val, PLLDSS_MISC1_CFG_WRITE_MASK);
+ default_val = misc2_val;
+ _pll_misc_chk_default(clk_base, plldss->params, 2,
+ default_val, PLLDSS_MISC2_CTRL1_WRITE_MASK);
+ default_val = misc3_val;
+ _pll_misc_chk_default(clk_base, plldss->params, 3,
+ default_val, PLLDSS_MISC3_CTRL2_WRITE_MASK);
+ } else if (plldss->params->ext_misc_reg[1]) {
+ default_val = misc1_val;
+ _pll_misc_chk_default(clk_base, plldss->params, 1,
+ default_val, PLLDSS_MISC1_CFG_WRITE_MASK &
+ (~PLLDSS_MISC1_CFG_EN_SDM));
+ }
+
+ /* Enable lock detect */
+ if (val & PLLDSS_BASE_LOCK_OVERRIDE) {
+ val &= ~PLLDSS_BASE_LOCK_OVERRIDE;
+ writel_relaxed(val, clk_base +
+ plldss->params->base_reg);
+ }
+
+ val = readl_relaxed(clk_base + plldss->params->ext_misc_reg[0]);
+ val &= ~PLLDSS_MISC0_LOCK_ENABLE;
+ val |= misc0_val & PLLDSS_MISC0_LOCK_ENABLE;
+ writel_relaxed(val, clk_base + plldss->params->ext_misc_reg[0]);
+ udelay(1);
+
+ return;
+ }
+
+ /* set IDDQ, enable lock detect, configure SDM/SSC */
+ val |= PLLDSS_BASE_IDDQ;
+ val &= ~PLLDSS_BASE_LOCK_OVERRIDE;
+ writel_relaxed(val, clk_base + plldss->params->base_reg);
+
+ /* When using this function for PLLC4 exit here */
+ if (!plldss->params->ext_misc_reg[1]) {
+ writel_relaxed(misc0_val, clk_base +
+ plldss->params->ext_misc_reg[0]);
+ udelay(1);
+ return;
+ }
+
+ writel_relaxed(misc0_val, clk_base +
+ plldss->params->ext_misc_reg[0]);
+ /* if SSC used set by 1st enable */
+ writel_relaxed(misc1_val & (~PLLDSS_MISC1_CFG_EN_SSC),
+ clk_base + plldss->params->ext_misc_reg[1]);
+ writel_relaxed(misc2_val, clk_base + plldss->params->ext_misc_reg[2]);
+ writel_relaxed(misc3_val, clk_base + plldss->params->ext_misc_reg[3]);
+ udelay(1);
+}
+
+void tegra210_plld2_set_defaults(struct tegra_clk_pll *plld2)
+{
+ plldss_defaults(plld2, PLLD2_MISC0_DEFAULT_VALUE,
+ PLLD2_MISC1_CFG_DEFAULT_VALUE,
+ PLLD2_MISC2_CTRL1_DEFAULT_VALUE,
+ PLLD2_MISC3_CTRL2_DEFAULT_VALUE);
+}
+
+void tegra210_plldp_set_defaults(struct tegra_clk_pll *plldp)
+{
+ plldss_defaults(plldp, PLLDP_MISC0_DEFAULT_VALUE,
+ PLLDP_MISC1_CFG_DEFAULT_VALUE,
+ PLLDP_MISC2_CTRL1_DEFAULT_VALUE,
+ PLLDP_MISC3_CTRL2_DEFAULT_VALUE);
+}
+
+/*
+ * PLLC4
+ * Base and misc0 layout is the same as PLLD2/PLLDP, but no SDM/SSC support.
+ * VCO is exposed to the clock tree via fixed 1/3 and 1/5 dividers.
+ */
+void tegra210_pllc4_set_defaults(struct tegra_clk_pll *pllc4)
+{
+ plldss_defaults(pllc4, PLLC4_MISC0_DEFAULT_VALUE, 0, 0, 0);
+}
+
+/*
+ * PLLRE
+ * VCO is exposed to the clock tree directly along with post-divider output
+ */
+void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre)
+{
+ u32 mask;
+ u32 val = readl_relaxed(clk_base + pllre->params->base_reg);
+
+ pllre->params->defaults_set = true;
+
+ if (val & PLL_ENABLE) {
+ pr_warn("%s already enabled. Postponing set full defaults\n",
+ __clk_get_name(pllre->hw.clk));
+
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ val &= PLLRE_BASE_DEFAULT_MASK;
+ if (val != PLLRE_BASE_DEFAULT_VALUE) {
+ pr_warn("pllre boot base 0x%x : expected 0x%x\n",
+ val, PLLRE_BASE_DEFAULT_VALUE);
+ pr_warn("(comparison mask = 0x%x)\n",
+ PLLRE_BASE_DEFAULT_MASK);
+ pllre->params->defaults_set = false;
+ }
+
+ /* Ignore lock enable */
+ val = PLLRE_MISC0_DEFAULT_VALUE & (~PLLRE_MISC0_IDDQ);
+ mask = PLLRE_MISC0_LOCK_ENABLE | PLLRE_MISC0_LOCK_OVERRIDE;
+ _pll_misc_chk_default(clk_base, pllre->params, 0, val,
+ ~mask & PLLRE_MISC0_WRITE_MASK);
+
+ /* Enable lock detect */
+ val = readl_relaxed(clk_base + pllre->params->ext_misc_reg[0]);
+ val &= ~mask;
+ val |= PLLRE_MISC0_DEFAULT_VALUE & mask;
+ writel_relaxed(val, clk_base + pllre->params->ext_misc_reg[0]);
+ udelay(1);
+
+ return;
+ }
+
+ /* set IDDQ, enable lock detect */
+ val &= ~PLLRE_BASE_DEFAULT_MASK;
+ val |= PLLRE_BASE_DEFAULT_VALUE & PLLRE_BASE_DEFAULT_MASK;
+ writel_relaxed(val, clk_base + pllre->params->base_reg);
+ writel_relaxed(PLLRE_MISC0_DEFAULT_VALUE,
+ clk_base + pllre->params->ext_misc_reg[0]);
+ udelay(1);
+}
+
+static void pllx_get_dyn_steps(struct clk_hw *hw, u32 *step_a, u32 *step_b)
+{
+ unsigned long input_rate;
+
+ if (!IS_ERR_OR_NULL(hw->clk)) {
+ input_rate = __clk_get_rate(__clk_get_parent(hw->clk));
+ /* cf rate */
+ input_rate /= tegra_pll_get_fixed_mdiv(hw, input_rate);
+ } else {
+ input_rate = 38400000;
+ }
+
+ switch (input_rate) {
+ case 12000000:
+ case 12800000:
+ case 13000000:
+ *step_a = 0x2B;
+ *step_b = 0x0B;
+ return;
+ case 19200000:
+ *step_a = 0x12;
+ *step_b = 0x08;
+ return;
+ case 38400000:
+ *step_a = 0x04;
+ *step_b = 0x05;
+ return;
+ default:
+ pr_err("%s: Unexpected reference rate %lu\n",
+ __func__, input_rate);
+ BUG();
+ }
+}
+
+static void pllx_check_defaults(struct tegra_clk_pll *pll)
+{
+ u32 default_val;
+
+ default_val = PLLX_MISC0_DEFAULT_VALUE;
+ /* ignore lock enable */
+ _pll_misc_chk_default(clk_base, pll->params, 0, default_val,
+ PLLX_MISC0_WRITE_MASK & (~PLLX_MISC0_LOCK_ENABLE));
+
+ default_val = PLLX_MISC1_DEFAULT_VALUE;
+ _pll_misc_chk_default(clk_base, pll->params, 1, default_val,
+ PLLX_MISC1_WRITE_MASK);
+
+ /* ignore all but control bit */
+ default_val = PLLX_MISC2_DEFAULT_VALUE;
+ _pll_misc_chk_default(clk_base, pll->params, 2,
+ default_val, PLLX_MISC2_EN_DYNRAMP);
+
+ default_val = PLLX_MISC3_DEFAULT_VALUE & (~PLLX_MISC3_IDDQ);
+ _pll_misc_chk_default(clk_base, pll->params, 3, default_val,
+ PLLX_MISC3_WRITE_MASK);
+
+ default_val = PLLX_MISC4_DEFAULT_VALUE;
+ _pll_misc_chk_default(clk_base, pll->params, 4, default_val,
+ PLLX_MISC4_WRITE_MASK);
+
+ default_val = PLLX_MISC5_DEFAULT_VALUE;
+ _pll_misc_chk_default(clk_base, pll->params, 5, default_val,
+ PLLX_MISC5_WRITE_MASK);
+}
+
+void tegra210_pllx_set_defaults(struct tegra_clk_pll *pllx)
+{
+ u32 val;
+ u32 step_a, step_b;
+
+ pllx->params->defaults_set = true;
+
+ /* Get ready dyn ramp state machine settings */
+ pllx_get_dyn_steps(&pllx->hw, &step_a, &step_b);
+ val = PLLX_MISC2_DEFAULT_VALUE & (~PLLX_MISC2_DYNRAMP_STEPA_MASK) &
+ (~PLLX_MISC2_DYNRAMP_STEPB_MASK);
+ val |= step_a << PLLX_MISC2_DYNRAMP_STEPA_SHIFT;
+ val |= step_b << PLLX_MISC2_DYNRAMP_STEPB_SHIFT;
+
+ if (readl_relaxed(clk_base + pllx->params->base_reg) & PLL_ENABLE) {
+ pr_warn("%s already enabled. Postponing set full defaults\n",
+ __clk_get_name(pllx->hw.clk));
+
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ pllx_check_defaults(pllx);
+
+ /* Configure dyn ramp, disable lock override */
+ writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
+
+ /* Enable lock detect */
+ val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[0]);
+ val &= ~PLLX_MISC0_LOCK_ENABLE;
+ val |= PLLX_MISC0_DEFAULT_VALUE & PLLX_MISC0_LOCK_ENABLE;
+ writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[0]);
+ udelay(1);
+
+ return;
+ }
+
+ /* Enable lock detect and CPU output */
+ writel_relaxed(PLLX_MISC0_DEFAULT_VALUE, clk_base +
+ pllx->params->ext_misc_reg[0]);
+
+ /* Setup */
+ writel_relaxed(PLLX_MISC1_DEFAULT_VALUE, clk_base +
+ pllx->params->ext_misc_reg[1]);
+
+ /* Configure dyn ramp state machine, disable lock override */
+ writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
+
+ /* Set IDDQ */
+ writel_relaxed(PLLX_MISC3_DEFAULT_VALUE, clk_base +
+ pllx->params->ext_misc_reg[3]);
+
+ /* Disable SDM */
+ writel_relaxed(PLLX_MISC4_DEFAULT_VALUE, clk_base +
+ pllx->params->ext_misc_reg[4]);
+ writel_relaxed(PLLX_MISC5_DEFAULT_VALUE, clk_base +
+ pllx->params->ext_misc_reg[5]);
+ udelay(1);
+}
+
+/* PLLMB */
+void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb)
+{
+ u32 mask, val = readl_relaxed(clk_base + pllmb->params->base_reg);
+
+ pllmb->params->defaults_set = true;
+
+ if (val & PLL_ENABLE) {
+ pr_warn("%s already enabled. Postponing set full defaults\n",
+ __clk_get_name(pllmb->hw.clk));
+
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ val = PLLMB_MISC0_DEFAULT_VALUE & (~PLLMB_MISC0_IDDQ);
+ mask = PLLMB_MISC0_LOCK_ENABLE | PLLMB_MISC0_LOCK_OVERRIDE;
+ _pll_misc_chk_default(clk_base, pllmb->params, 0, val,
+ ~mask & PLLMB_MISC0_WRITE_MASK);
+
+ /* Enable lock detect */
+ val = readl_relaxed(clk_base + pllmb->params->ext_misc_reg[0]);
+ val &= ~mask;
+ val |= PLLMB_MISC0_DEFAULT_VALUE & mask;
+ writel_relaxed(val, clk_base + pllmb->params->ext_misc_reg[0]);
+ udelay(1);
+
+ return;
+ }
+
+ /* set IDDQ, enable lock detect */
+ writel_relaxed(PLLMB_MISC0_DEFAULT_VALUE,
+ clk_base + pllmb->params->ext_misc_reg[0]);
+ udelay(1);
+}
+
+/*
+ * PLLP
+ * VCO is exposed to the clock tree directly along with post-divider output.
+ * Both VCO and post-divider output rates are fixed at 408MHz and 204MHz,
+ * respectively.
+ */
+static void pllp_check_defaults(struct tegra_clk_pll *pll, bool enabled)
+{
+ u32 val, mask;
+
+ /* Ignore lock enable (will be set), make sure not in IDDQ if enabled */
+ val = PLLP_MISC0_DEFAULT_VALUE & (~PLLP_MISC0_IDDQ);
+ mask = PLLP_MISC0_LOCK_ENABLE | PLLP_MISC0_LOCK_OVERRIDE;
+ if (!enabled)
+ mask |= PLLP_MISC0_IDDQ;
+ _pll_misc_chk_default(clk_base, pll->params, 0, val,
+ ~mask & PLLP_MISC0_WRITE_MASK);
+
+ /* Ignore branch controls */
+ val = PLLP_MISC1_DEFAULT_VALUE;
+ mask = PLLP_MISC1_HSIO_EN | PLLP_MISC1_XUSB_EN;
+ _pll_misc_chk_default(clk_base, pll->params, 1, val,
+ ~mask & PLLP_MISC1_WRITE_MASK);
+}
+
+void tegra210_pllp_set_defaults(struct tegra_clk_pll *pllp)
+{
+ u32 mask;
+ u32 val = readl_relaxed(clk_base + pllp->params->base_reg);
+
+ pllp->params->defaults_set = true;
+
+ if (val & PLL_ENABLE) {
+ pr_warn("%s already enabled. Postponing set full defaults\n",
+ __clk_get_name(pllp->hw.clk));
+
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ pllp_check_defaults(pllp, true);
+
+ /* Enable lock detect */
+ val = readl_relaxed(clk_base + pllp->params->ext_misc_reg[0]);
+ mask = PLLP_MISC0_LOCK_ENABLE | PLLP_MISC0_LOCK_OVERRIDE;
+ val &= ~mask;
+ val |= PLLP_MISC0_DEFAULT_VALUE & mask;
+ writel_relaxed(val, clk_base + pllp->params->ext_misc_reg[0]);
+ udelay(1);
+
+ return;
+ }
+
+ /* set IDDQ, enable lock detect */
+ writel_relaxed(PLLP_MISC0_DEFAULT_VALUE,
+ clk_base + pllp->params->ext_misc_reg[0]);
+
+ /* Preserve branch control */
+ val = readl_relaxed(clk_base + pllp->params->ext_misc_reg[1]);
+ mask = PLLP_MISC1_HSIO_EN | PLLP_MISC1_XUSB_EN;
+ val &= mask;
+ val |= ~mask & PLLP_MISC1_DEFAULT_VALUE;
+ writel_relaxed(val, clk_base + pllp->params->ext_misc_reg[1]);
+ udelay(1);
+}
+
+/*
+ * PLLU
+ * VCO is exposed to the clock tree directly along with post-divider output.
+ * Both VCO and post-divider output rates are fixed at 480MHz and 240MHz,
+ * respectively.
+ */
+static void pllu_check_defaults(struct tegra_clk_pll *pll, bool hw_control)
+{
+ u32 val, mask;
+
+ /* Ignore lock enable (will be set) and IDDQ if under h/w control */
+ val = PLLU_MISC0_DEFAULT_VALUE & (~PLLU_MISC0_IDDQ);
+ mask = PLLU_MISC0_LOCK_ENABLE | (hw_control ? PLLU_MISC0_IDDQ : 0);
+ _pll_misc_chk_default(clk_base, pll->params, 0, val,
+ ~mask & PLLU_MISC0_WRITE_MASK);
+
+ val = PLLU_MISC1_DEFAULT_VALUE;
+ mask = PLLU_MISC1_LOCK_OVERRIDE;
+ _pll_misc_chk_default(clk_base, pll->params, 1, val,
+ ~mask & PLLU_MISC1_WRITE_MASK);
+}
+
+void tegra210_pllu_set_defaults(struct tegra_clk_pll *pllu)
+{
+ u32 val = readl_relaxed(clk_base + pllu->params->base_reg);
+
+ pllu->params->defaults_set = true;
+
+ if (val & PLL_ENABLE) {
+ pr_warn("%s already enabled. Postponing set full defaults\n",
+ __clk_get_name(pllu->hw.clk));
+
+ /*
+ * PLL is ON: check if defaults already set, then set those
+ * that can be updated in flight.
+ */
+ pllu_check_defaults(pllu, false);
+
+ /* Enable lock detect */
+ val = readl_relaxed(clk_base + pllu->params->ext_misc_reg[0]);
+ val &= ~PLLU_MISC0_LOCK_ENABLE;
+ val |= PLLU_MISC0_DEFAULT_VALUE & PLLU_MISC0_LOCK_ENABLE;
+ writel_relaxed(val, clk_base + pllu->params->ext_misc_reg[0]);
+
+ val = readl_relaxed(clk_base + pllu->params->ext_misc_reg[1]);
+ val &= ~PLLU_MISC1_LOCK_OVERRIDE;
+ val |= PLLU_MISC1_DEFAULT_VALUE & PLLU_MISC1_LOCK_OVERRIDE;
+ writel_relaxed(val, clk_base + pllu->params->ext_misc_reg[1]);
+ udelay(1);
+
+ return;
+ }
+
+ /* set IDDQ, enable lock detect */
+ writel_relaxed(PLLU_MISC0_DEFAULT_VALUE,
+ clk_base + pllu->params->ext_misc_reg[0]);
+ writel_relaxed(PLLU_MISC1_DEFAULT_VALUE,
+ clk_base + pllu->params->ext_misc_reg[1]);
+ udelay(1);
+}
+
+#define mask(w) ((1 << (w)) - 1)
+#define divm_mask(p) mask(p->params->div_nmp->divm_width)
+#define divn_mask(p) mask(p->params->div_nmp->divn_width)
+#define divp_mask(p) (p->params->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK :\
+ mask(p->params->div_nmp->divp_width))
+
+#define divm_shift(p) ((p)->params->div_nmp->divm_shift)
+#define divn_shift(p) ((p)->params->div_nmp->divn_shift)
+#define divp_shift(p) ((p)->params->div_nmp->divp_shift)
+
+#define divm_mask_shifted(p) (divm_mask(p) << divm_shift(p))
+#define divn_mask_shifted(p) (divn_mask(p) << divn_shift(p))
+#define divp_mask_shifted(p) (divp_mask(p) << divp_shift(p))
+
+#define PLL_LOCKDET_DELAY 2 /* Lock detection safety delays */
+static int tegra210_wait_for_mask(struct tegra_clk_pll *pll,
+ u32 reg, u32 mask)
+{
+ int i;
+ u32 val = 0;
+
+ for (i = 0; i < pll->params->lock_delay / PLL_LOCKDET_DELAY + 1; i++) {
+ udelay(PLL_LOCKDET_DELAY);
+ val = readl_relaxed(clk_base + reg);
+ if ((val & mask) == mask) {
+ udelay(PLL_LOCKDET_DELAY);
+ return 0;
+ }
+ }
+ return -ETIMEDOUT;
+}
+
+static int tegra210_pllx_dyn_ramp(struct tegra_clk_pll *pllx,
+ struct tegra_clk_pll_freq_table *cfg)
+{
+ u32 val, base, ndiv_new_mask;
+
+ ndiv_new_mask = (divn_mask(pllx) >> pllx->params->div_nmp->divn_shift)
+ << PLLX_MISC2_NDIV_NEW_SHIFT;
+
+ val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[2]);
+ val &= (~ndiv_new_mask);
+ val |= cfg->n << PLLX_MISC2_NDIV_NEW_SHIFT;
+ writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
+ udelay(1);
+
+ val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[2]);
+ val |= PLLX_MISC2_EN_DYNRAMP;
+ writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
+ udelay(1);
+
+ tegra210_wait_for_mask(pllx, pllx->params->ext_misc_reg[2],
+ PLLX_MISC2_DYNRAMP_DONE);
+
+ base = readl_relaxed(clk_base + pllx->params->base_reg) &
+ (~divn_mask_shifted(pllx));
+ base |= cfg->n << pllx->params->div_nmp->divn_shift;
+ writel_relaxed(base, clk_base + pllx->params->base_reg);
+ udelay(1);
+
+ val &= ~PLLX_MISC2_EN_DYNRAMP;
+ writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
+ udelay(1);
+
+ pr_debug("%s: dynamic ramp to m = %u n = %u p = %u, Fout = %lu kHz\n",
+ __clk_get_name(pllx->hw.clk), cfg->m, cfg->n, cfg->p,
+ cfg->input_rate / cfg->m * cfg->n /
+ pllx->params->pdiv_tohw[cfg->p].pdiv / 1000);
+
+ return 0;
+}
+
+static int _p_div_to_hw(struct clk_hw *hw, u8 p_div)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
+
+ if (p_tohw) {
+ while (p_tohw->pdiv) {
+ if (p_div <= p_tohw->pdiv)
+ return p_tohw->hw_val;
+ p_tohw++;
+ }
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+/*
+ * Common configuration for PLLs with fixed input divider policy:
+ * - always set fixed M-value based on the reference rate
+ * - always set P-value value 1:1 for output rates above VCO minimum, and
+ * choose minimum necessary P-value for output rates below VCO maximum
+ * - calculate N-value based on selected M and P
+ * - calculate SDM_DIN fractional part
+ */
+static int tegra210_pll_fixed_mdiv_cfg(struct clk_hw *hw,
+ struct tegra_clk_pll_freq_table *cfg,
+ unsigned long rate, unsigned long input_rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ struct tegra_clk_pll_params *params = pll->params;
+ int p;
+ unsigned long cf, p_rate;
+ u32 pdiv;
+
+ if (!rate)
+ return -EINVAL;
+
+ if (!(params->flags & TEGRA_PLL_VCO_OUT)) {
+ p = DIV_ROUND_UP(params->vco_min, rate);
+ p = params->round_p_to_pdiv(p, &pdiv);
+ } else {
+ p = rate >= params->vco_min ? 1 : -EINVAL;
+ }
+
+ if (IS_ERR_VALUE(p))
+ return -EINVAL;
+
+ cfg->m = tegra_pll_get_fixed_mdiv(hw, input_rate);
+ cfg->p = p;
+
+ /* Store P as HW value, as that is what is expected */
+ cfg->p = _p_div_to_hw(hw, cfg->p);
+
+ p_rate = rate * p;
+ if (p_rate > params->vco_max)
+ p_rate = params->vco_max;
+ cf = input_rate / cfg->m;
+ cfg->n = p_rate / cf;
+
+ cfg->sdm_data = 0;
+ if (params->sdm_ctrl_reg) {
+ unsigned long rem = p_rate - cf * cfg->n;
+ /* If ssc is enabled SDM enabled as well, even for integer n */
+ if (rem || params->ssc_ctrl_reg) {
+ u64 s = rem * PLL_SDM_COEFF;
+
+ do_div(s, cf);
+ s -= PLL_SDM_COEFF / 2;
+ cfg->sdm_data = sdin_din_to_data(s);
+ }
+ }
+
+ cfg->input_rate = input_rate;
+ cfg->output_rate = rate;
+
+ return 0;
+}
+
+/*
+ * clk_pll_set_gain - set gain to m, n to calculate correct VCO rate
+ *
+ * @cfg: struct tegra_clk_pll_freq_table * cfg
+ *
+ * For Normal mode:
+ * Fvco = Fref * NDIV / MDIV
+ *
+ * For fractional mode:
+ * Fvco = Fref * (NDIV + 0.5 + SDM_DIN / PLL_SDM_COEFF) / MDIV
+ */
+static void tegra210_clk_pll_set_gain(struct tegra_clk_pll_freq_table *cfg)
+{
+ cfg->n = cfg->n * PLL_SDM_COEFF + PLL_SDM_COEFF/2 +
+ sdin_data_to_din(cfg->sdm_data);
+ cfg->m *= PLL_SDM_COEFF;
+}
+
+unsigned long tegra210_clk_adjust_vco_min(struct tegra_clk_pll_params *params,
+ unsigned long parent_rate)
+{
+ unsigned long vco_min = params->vco_min;
+
+ params->vco_min += DIV_ROUND_UP(parent_rate, PLL_SDM_COEFF);
+ vco_min = min(vco_min, params->vco_min);
+
+ return vco_min;
+}
+
+static struct div_nmp pllx_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 5,
+};
+/*
+ * PLL post divider maps - two types: quasi-linear and exponential
+ * post divider.
+ */
+#define PLL_QLIN_PDIV_MAX 16
+static struct pdiv_map pll_qlin_pdiv_to_hw[] = {
+ { .pdiv = 1, .hw_val = 0 },
+ { .pdiv = 2, .hw_val = 1 },
+ { .pdiv = 3, .hw_val = 2 },
+ { .pdiv = 4, .hw_val = 3 },
+ { .pdiv = 5, .hw_val = 4 },
+ { .pdiv = 6, .hw_val = 5 },
+ { .pdiv = 8, .hw_val = 6 },
+ { .pdiv = 9, .hw_val = 7 },
+ { .pdiv = 10, .hw_val = 8 },
+ { .pdiv = 12, .hw_val = 9 },
+ { .pdiv = 15, .hw_val = 10 },
+ { .pdiv = 16, .hw_val = 11 },
+ { .pdiv = 18, .hw_val = 12 },
+ { .pdiv = 20, .hw_val = 13 },
+ { .pdiv = 24, .hw_val = 14 },
+ { .pdiv = 30, .hw_val = 15 },
+ { .pdiv = 32, .hw_val = 16, },
+};
+
+static u32 pll_qlin_p_to_pdiv(u32 p, u32 *pdiv)
+{
+ int i;
+
+ if (p) {
+ for (i = 0; i <= PLL_QLIN_PDIV_MAX; i++) {
+ if (p <= pll_qlin_pdiv_to_hw[i].pdiv) {
+ if (pdiv)
+ *pdiv = i;
+ return pll_qlin_pdiv_to_hw[i].pdiv;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+#define PLL_EXPO_PDIV_MAX 7
+static struct pdiv_map pll_expo_pdiv_to_hw[] = {
+ { .pdiv = 1, .hw_val = 0, },
+ { .pdiv = 2, .hw_val = 1, },
+ { .pdiv = 4, .hw_val = 2, },
+ { .pdiv = 8, .hw_val = 3, },
+ { .pdiv = 16, .hw_val = 4, },
+ { .pdiv = 32, .hw_val = 5, },
+ { .pdiv = 64, .hw_val = 6, },
+ { .pdiv = 128, .hw_val = 7, },
+};
+
+static u32 pll_expo_p_to_pdiv(u32 p, u32 *pdiv)
+{
+ if (p) {
+ u32 i = fls(p);
+
+ if (i == ffs(p))
+ i--;
+
+ if (i <= PLL_EXPO_PDIV_MAX) {
+ if (pdiv)
+ *pdiv = i;
+ return 1 << i;
+ }
+ }
+ return -EINVAL;
+}
+
+static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
+ /* 1 GHz */
+ { 12000000, 1000000000, 166, 1, 1}, /* actual: 996.0 MHz */
+ { 13000000, 1000000000, 153, 1, 1}, /* actual: 994.0 MHz */
+ { 38400000, 1000000000, 156, 3, 1}, /* actual: 998.4 MHz */
+ {0, 0, 0, 0, 0, 0},
+};
+
+static struct tegra_clk_pll_params pll_x_params = {
+ .input_min = 12000000,
+ .input_max = 800000000,
+ .cf_min = 12000000,
+ .cf_max = 38400000,
+ .vco_min = 1350000000,
+ .vco_max = 3000000000UL,
+ .base_reg = PLLX_BASE,
+ .misc_reg = PLLX_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .ext_misc_reg[0] = PLLX_MISC0,
+ .ext_misc_reg[1] = PLLX_MISC1,
+ .ext_misc_reg[2] = PLLX_MISC2,
+ .ext_misc_reg[3] = PLLX_MISC3,
+ .ext_misc_reg[4] = PLLX_MISC4,
+ .ext_misc_reg[5] = PLLX_MISC5,
+ .iddq_reg = PLLX_MISC3,
+ .iddq_bit_idx = PLLXP_IDDQ_BIT,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .mdiv_default = 2,
+ .dyn_ramp_reg = PLLX_MISC2,
+ .stepa_shift = 16,
+ .stepb_shift = 24,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllx_nmp,
+ .freq_table = pll_x_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .dyn_ramp = tegra210_pllx_dyn_ramp,
+ .set_defaults = tegra210_pllx_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct div_nmp pllc_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 10,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_freq_table pll_cx_freq_table[] = {
+ { 12000000, 510000000, 85, 1, 1},
+ { 13000000, 510000000, 78, 1, 1}, /* actual: 507.0 MHz */
+ { 38400000, 510000000, 79, 3, 1}, /* actual: 505.6 MHz */
+ {0, 0, 0, 0, 0, 0},
+};
+
+static struct tegra_clk_pll_params pll_c_params = {
+ .input_min = 12000000,
+ .input_max = 700000000,
+ .cf_min = 12000000,
+ .cf_max = 50000000,
+ .vco_min = 600000000,
+ .vco_max = 1200000000,
+ .base_reg = PLLC_BASE,
+ .misc_reg = PLLC_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_delay = 300,
+ .iddq_reg = PLLC_MISC1,
+ .iddq_bit_idx = PLLCX_IDDQ_BIT,
+ .reset_reg = PLLC_MISC0,
+ .reset_bit_idx = PLLCX_RESET_BIT,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .ext_misc_reg[0] = PLLC_MISC0,
+ .ext_misc_reg[1] = PLLC_MISC1,
+ .ext_misc_reg[2] = PLLC_MISC2,
+ .ext_misc_reg[3] = PLLC_MISC3,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .mdiv_default = 3,
+ .div_nmp = &pllc_nmp,
+ .freq_table = pll_cx_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .set_defaults = tegra210_pllcx_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct div_nmp pllcx_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 10,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_params pll_c2_params = {
+ .input_min = 12000000,
+ .input_max = 700000000,
+ .cf_min = 12000000,
+ .cf_max = 50000000,
+ .vco_min = 600000000,
+ .vco_max = 1200000000,
+ .base_reg = PLLC2_BASE,
+ .misc_reg = PLLC2_MISC0,
+ .iddq_reg = PLLC2_MISC1,
+ .iddq_bit_idx = PLLCX_IDDQ_BIT,
+ .reset_reg = PLLC2_MISC0,
+ .reset_bit_idx = PLLCX_RESET_BIT,
+ .lock_mask = PLLCX_BASE_LOCK,
+ .lock_delay = 300,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .mdiv_default = 3,
+ .div_nmp = &pllcx_nmp,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .ext_misc_reg[0] = PLLC2_MISC0,
+ .ext_misc_reg[1] = PLLC2_MISC1,
+ .ext_misc_reg[2] = PLLC2_MISC2,
+ .ext_misc_reg[3] = PLLC2_MISC3,
+ .freq_table = pll_cx_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .set_defaults = tegra210_pllcx_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct tegra_clk_pll_params pll_c3_params = {
+ .input_min = 12000000,
+ .input_max = 700000000,
+ .cf_min = 12000000,
+ .cf_max = 50000000,
+ .vco_min = 600000000,
+ .vco_max = 1200000000,
+ .base_reg = PLLC3_BASE,
+ .misc_reg = PLLC3_MISC0,
+ .lock_mask = PLLCX_BASE_LOCK,
+ .lock_delay = 300,
+ .iddq_reg = PLLC3_MISC1,
+ .iddq_bit_idx = PLLCX_IDDQ_BIT,
+ .reset_reg = PLLC3_MISC0,
+ .reset_bit_idx = PLLCX_RESET_BIT,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .mdiv_default = 3,
+ .div_nmp = &pllcx_nmp,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .ext_misc_reg[0] = PLLC3_MISC0,
+ .ext_misc_reg[1] = PLLC3_MISC1,
+ .ext_misc_reg[2] = PLLC3_MISC2,
+ .ext_misc_reg[3] = PLLC3_MISC3,
+ .freq_table = pll_cx_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .set_defaults = tegra210_pllcx_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct div_nmp pllss_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 19,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_freq_table pll_c4_vco_freq_table[] = {
+ { 12000000, 600000000, 50, 1, 0},
+ { 13000000, 600000000, 46, 1, 0}, /* actual: 598.0 MHz */
+ { 38400000, 600000000, 62, 4, 0}, /* actual: 595.2 MHz */
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static const struct clk_div_table pll_vco_post_div_table[] = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 2 },
+ { .val = 2, .div = 3 },
+ { .val = 3, .div = 4 },
+ { .val = 4, .div = 5 },
+ { .val = 5, .div = 6 },
+ { .val = 6, .div = 8 },
+ { .val = 7, .div = 10 },
+ { .val = 8, .div = 12 },
+ { .val = 9, .div = 16 },
+ { .val = 10, .div = 12 },
+ { .val = 11, .div = 16 },
+ { .val = 12, .div = 20 },
+ { .val = 13, .div = 24 },
+ { .val = 14, .div = 32 },
+ { .val = 0, .div = 0 },
+};
+
+static struct tegra_clk_pll_params pll_c4_vco_params = {
+ .input_min = 9600000,
+ .input_max = 800000000,
+ .cf_min = 9600000,
+ .cf_max = 19200000,
+ .vco_min = 500000000,
+ .vco_max = 1080000000,
+ .base_reg = PLLC4_BASE,
+ .misc_reg = PLLC4_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .ext_misc_reg[0] = PLLC4_MISC0,
+ .iddq_reg = PLLC4_BASE,
+ .iddq_bit_idx = PLLSS_IDDQ_BIT,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .mdiv_default = 3,
+ .div_nmp = &pllss_nmp,
+ .freq_table = pll_c4_vco_freq_table,
+ .set_defaults = tegra210_pllc4_set_defaults,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
+ TEGRA_PLL_VCO_OUT,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
+ { 12000000, 800000000, 66, 1, 0}, /* actual: 792.0 MHz */
+ { 13000000, 800000000, 61, 1, 0}, /* actual: 793.0 MHz */
+ { 38400000, 297600000, 93, 4, 2},
+ { 38400000, 400000000, 125, 4, 2},
+ { 38400000, 532800000, 111, 4, 1},
+ { 38400000, 665600000, 104, 3, 1},
+ { 38400000, 800000000, 125, 3, 1},
+ { 38400000, 931200000, 97, 4, 0},
+ { 38400000, 1065600000, 111, 4, 0},
+ { 38400000, 1200000000, 125, 4, 0},
+ { 38400000, 1331200000, 104, 3, 0},
+ { 38400000, 1459200000, 76, 2, 0},
+ { 38400000, 1600000000, 125, 3, 0},
+ {0, 0, 0, 0, 0, 0},
+};
+
+static struct div_nmp pllm_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .override_divm_shift = 0,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .override_divn_shift = 8,
+ .divp_shift = 20,
+ .divp_width = 5,
+ .override_divp_shift = 27,
+};
+
+static struct tegra_clk_pll_params pll_m_params = {
+ .input_min = 9600000,
+ .input_max = 500000000,
+ .cf_min = 9600000,
+ .cf_max = 19200000,
+ .vco_min = 800000000,
+ .vco_max = 1866000000,
+ .base_reg = PLLM_BASE,
+ .misc_reg = PLLM_MISC1,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLM_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .iddq_reg = PLLM_MISC0,
+ .iddq_bit_idx = PLLM_IDDQ_BIT,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .ext_misc_reg[0] = PLLM_MISC0,
+ .ext_misc_reg[0] = PLLM_MISC1,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllm_nmp,
+ .pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
+ .pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
+ .freq_table = pll_m_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct tegra_clk_pll_params pll_mb_params = {
+ .input_min = 9600000,
+ .input_max = 500000000,
+ .cf_min = 9600000,
+ .cf_max = 19200000,
+ .vco_min = 800000000,
+ .vco_max = 1866000000,
+ .base_reg = PLLMB_BASE,
+ .misc_reg = PLLMB_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLMB_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .iddq_reg = PLLMB_MISC0,
+ .iddq_bit_idx = PLLMB_IDDQ_BIT,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .ext_misc_reg[0] = PLLMB_MISC0,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllm_nmp,
+ .freq_table = pll_m_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .set_defaults = tegra210_pllmb_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+
+static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
+ /* PLLE special case: use cpcon field to store cml divider value */
+ { 672000000, 100000000, 125, 42, 0, 13,},
+ { 624000000, 100000000, 125, 39, 0, 13,},
+ { 336000000, 100000000, 125, 21, 0, 13,},
+ { 312000000, 100000000, 200, 26, 0, 14,},
+ { 38400000, 100000000, 125, 2, 0, 14,},
+ { 12000000, 100000000, 200, 1, 0, 14,},
+ {0, 0, 0, 0, 0, 0},
+};
+
+static struct div_nmp plle_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 24,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_params pll_e_params = {
+ .input_min = 12000000,
+ .input_max = 800000000,
+ .cf_min = 12000000,
+ .cf_max = 38400000,
+ .vco_min = 1600000000,
+ .vco_max = 2500000000U,
+ .base_reg = PLLE_BASE,
+ .misc_reg = PLLE_MISC0,
+ .aux_reg = PLLE_AUX,
+ .lock_mask = PLLE_MISC_LOCK,
+ .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .div_nmp = &plle_nmp,
+ .freq_table = pll_e_freq_table,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_LOCK_MISC | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
+ .fixed_rate = 100000000,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct tegra_clk_pll_freq_table pll_re_vco_freq_table[] = {
+ { 12000000, 672000000, 56, 1, 0},
+ { 13000000, 672000000, 51, 1, 0}, /* actual: 663.0 MHz */
+ { 38400000, 672000000, 70, 4, 0},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct div_nmp pllre_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 16,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_params pll_re_vco_params = {
+ .input_min = 9600000,
+ .input_max = 800000000,
+ .cf_min = 9600000,
+ .cf_max = 19200000,
+ .vco_min = 350000000,
+ .vco_max = 700000000,
+ .base_reg = PLLRE_BASE,
+ .misc_reg = PLLRE_MISC0,
+ .lock_mask = PLLRE_MISC_LOCK,
+ .lock_enable_bit_idx = PLLRE_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .ext_misc_reg[0] = PLLRE_MISC0,
+ .iddq_reg = PLLRE_MISC0,
+ .iddq_bit_idx = PLLRE_IDDQ_BIT,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllre_nmp,
+ .freq_table = pll_re_vco_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_LOCK_MISC |
+ TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_VCO_OUT,
+ .set_defaults = tegra210_pllre_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct div_nmp pllp_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 10,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
+ { 12000000, 408000000, 34, 1, 0},
+ { 38400000, 408000000, 85, 8, 0}, /* cf = 4.8MHz, allowed exception */
+ {0, 0, 0, 0, 0, 0},
+};
+
+static struct tegra_clk_pll_params pll_p_params = {
+ .input_min = 9600000,
+ .input_max = 800000000,
+ .cf_min = 9600000,
+ .cf_max = 19200000,
+ .vco_min = 350000000,
+ .vco_max = 700000000,
+ .base_reg = PLLP_BASE,
+ .misc_reg = PLLP_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLP_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .iddq_reg = PLLP_MISC0,
+ .iddq_bit_idx = PLLXP_IDDQ_BIT,
+ .ext_misc_reg[0] = PLLP_MISC0,
+ .ext_misc_reg[1] = PLLP_MISC1,
+ .div_nmp = &pllp_nmp,
+ .freq_table = pll_p_freq_table,
+ .fixed_rate = 408000000,
+ .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK |
+ TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_VCO_OUT,
+ .set_defaults = tegra210_pllp_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct tegra_clk_pll_params pll_a1_params = {
+ .input_min = 12000000,
+ .input_max = 700000000,
+ .cf_min = 12000000,
+ .cf_max = 50000000,
+ .vco_min = 600000000,
+ .vco_max = 1200000000,
+ .base_reg = PLLA1_BASE,
+ .misc_reg = PLLA1_MISC0,
+ .lock_mask = PLLCX_BASE_LOCK,
+ .lock_delay = 300,
+ .iddq_reg = PLLA1_MISC0,
+ .iddq_bit_idx = PLLCX_IDDQ_BIT,
+ .reset_reg = PLLA1_MISC0,
+ .reset_bit_idx = PLLCX_RESET_BIT,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllc_nmp,
+ .ext_misc_reg[0] = PLLA1_MISC0,
+ .ext_misc_reg[1] = PLLA1_MISC1,
+ .ext_misc_reg[2] = PLLA1_MISC2,
+ .ext_misc_reg[3] = PLLA1_MISC3,
+ .freq_table = pll_cx_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .set_defaults = tegra210_pllcx_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct div_nmp plla_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
+ { 12000000, 282240000, 47, 1, 1, 1, 0xf148}, /* actual: 282240234 */
+ { 12000000, 368640000, 61, 1, 1, 1, 0xfe15}, /* actual: 368640381 */
+ { 12000000, 240000000, 60, 1, 2, 1, },
+
+ { 13000000, 282240000, 43, 1, 1, 1, 0xfd7d}, /* actual: 282239807 */
+ { 13000000, 368640000, 56, 1, 1, 1, 0x06d8}, /* actual: 368640137 */
+ { 13000000, 240000000, 55, 1, 2, 1, }, /* actual: 238.3 MHz */
+
+ { 38400000, 282240000, 44, 3, 1, 1, 0xf333}, /* actual: 282239844 */
+ { 38400000, 368640000, 57, 3, 1, 1, 0x0333}, /* actual: 368639844 */
+ { 38400000, 240000000, 75, 3, 3, 1,},
+ {0, 0, 0, 0, 0, 0, 0},
+};
+
+static struct tegra_clk_pll_params pll_a_params = {
+ .input_min = 12000000,
+ .input_max = 800000000,
+ .cf_min = 12000000,
+ .cf_max = 19200000,
+ .vco_min = 500000000,
+ .vco_max = 1000000000,
+ .base_reg = PLLA_BASE,
+ .misc_reg = PLLA_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLA_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .iddq_reg = PLLA_BASE,
+ .iddq_bit_idx = PLLA_IDDQ_BIT,
+ .div_nmp = &plla_nmp,
+ .sdm_din_reg = PLLA_MISC1,
+ .sdm_din_mask = PLLA_SDM_DIN_MASK,
+ .sdm_ctrl_reg = PLLA_MISC2,
+ .sdm_ctrl_en_mask = PLLA_SDM_EN_MASK,
+ .ext_misc_reg[0] = PLLA_MISC0,
+ .ext_misc_reg[1] = PLLA_MISC1,
+ .ext_misc_reg[2] = PLLA_MISC2,
+ .freq_table = pll_a_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_MDIV_NEW |
+ TEGRA_PLL_HAS_LOCK_ENABLE,
+ .set_defaults = tegra210_plla_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+ .set_gain = tegra210_clk_pll_set_gain,
+ .adjust_vco = tegra210_clk_adjust_vco_min,
+};
+
+static struct div_nmp plld_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 11,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 3,
+};
+
+static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
+ { 12000000, 594000000, 99, 1, 1},
+ { 13000000, 594000000, 91, 1, 1, 0, 0xfc4f}, /* actual: 594000183 */
+ { 38400000, 594000000, 30, 1, 1, 0, 0x0e00},
+ {0, 0, 0, 0, 0, 0},
+};
+
+static struct tegra_clk_pll_params pll_d_params = {
+ .input_min = 12000000,
+ .input_max = 800000000,
+ .cf_min = 12000000,
+ .cf_max = 38400000,
+ .vco_min = 750000000,
+ .vco_max = 1500000000,
+ .base_reg = PLLD_BASE,
+ .misc_reg = PLLD_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLD_MISC_LOCK_ENABLE,
+ .lock_delay = 1000,
+ .iddq_reg = PLLD_MISC0,
+ .iddq_bit_idx = PLLD_IDDQ_BIT,
+ .round_p_to_pdiv = pll_expo_p_to_pdiv,
+ .pdiv_tohw = pll_expo_pdiv_to_hw,
+ .div_nmp = &plld_nmp,
+ .sdm_din_reg = PLLD_MISC0,
+ .sdm_din_mask = PLLA_SDM_DIN_MASK,
+ .sdm_ctrl_reg = PLLD_MISC0,
+ .sdm_ctrl_en_mask = PLLD_SDM_EN_MASK,
+ .ext_misc_reg[0] = PLLD_MISC0,
+ .ext_misc_reg[1] = PLLD_MISC1,
+ .freq_table = pll_d_freq_table,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .mdiv_default = 1,
+ .set_defaults = tegra210_plld_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+ .set_gain = tegra210_clk_pll_set_gain,
+ .adjust_vco = tegra210_clk_adjust_vco_min,
+};
+
+static struct tegra_clk_pll_freq_table tegra210_pll_d2_freq_table[] = {
+ { 12000000, 594000000, 99, 1, 1, 0, 0xf000},
+ { 13000000, 594000000, 91, 1, 1, 0, 0xfc4f}, /* actual: 594000183 */
+ { 38400000, 594000000, 30, 1, 1, 0, 0x0e00},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+/* s/w policy, always tegra_pll_ref */
+static struct tegra_clk_pll_params pll_d2_params = {
+ .input_min = 12000000,
+ .input_max = 800000000,
+ .cf_min = 12000000,
+ .cf_max = 38400000,
+ .vco_min = 750000000,
+ .vco_max = 1500000000,
+ .base_reg = PLLD2_BASE,
+ .misc_reg = PLLD2_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .iddq_reg = PLLD2_BASE,
+ .iddq_bit_idx = PLLSS_IDDQ_BIT,
+ .sdm_din_reg = PLLD2_MISC3,
+ .sdm_din_mask = PLLA_SDM_DIN_MASK,
+ .sdm_ctrl_reg = PLLD2_MISC1,
+ .sdm_ctrl_en_mask = PLLD2_SDM_EN_MASK,
+ .ssc_ctrl_reg = PLLD2_MISC1,
+ .ssc_ctrl_en_mask = PLLD2_SSC_EN_MASK,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllss_nmp,
+ .ext_misc_reg[0] = PLLD2_MISC0,
+ .ext_misc_reg[1] = PLLD2_MISC1,
+ .ext_misc_reg[2] = PLLD2_MISC2,
+ .ext_misc_reg[3] = PLLD2_MISC3,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .mdiv_default = 1,
+ .freq_table = tegra210_pll_d2_freq_table,
+ .set_defaults = tegra210_plld2_set_defaults,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+ .set_gain = tegra210_clk_pll_set_gain,
+ .adjust_vco = tegra210_clk_adjust_vco_min,
+};
+
+static struct tegra_clk_pll_freq_table pll_dp_freq_table[] = {
+ { 12000000, 270000000, 90, 1, 3, 0, 0xf000},
+ { 13000000, 270000000, 83, 1, 3, 0, 0xf000}, /* actual: 269.8 MHz */
+ { 38400000, 270000000, 28, 1, 3, 0, 0xf400},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_params pll_dp_params = {
+ .input_min = 12000000,
+ .input_max = 800000000,
+ .cf_min = 12000000,
+ .cf_max = 38400000,
+ .vco_min = 750000000,
+ .vco_max = 1500000000,
+ .base_reg = PLLDP_BASE,
+ .misc_reg = PLLDP_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .iddq_reg = PLLDP_BASE,
+ .iddq_bit_idx = PLLSS_IDDQ_BIT,
+ .sdm_din_reg = PLLDP_SS_CTRL2,
+ .sdm_din_mask = PLLA_SDM_DIN_MASK,
+ .sdm_ctrl_reg = PLLDP_SS_CFG,
+ .sdm_ctrl_en_mask = PLLDP_SDM_EN_MASK,
+ .ssc_ctrl_reg = PLLDP_SS_CFG,
+ .ssc_ctrl_en_mask = PLLDP_SSC_EN_MASK,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllss_nmp,
+ .ext_misc_reg[0] = PLLDP_MISC,
+ .ext_misc_reg[1] = PLLDP_SS_CFG,
+ .ext_misc_reg[2] = PLLDP_SS_CTRL1,
+ .ext_misc_reg[3] = PLLDP_SS_CTRL2,
+ .max_p = PLL_QLIN_PDIV_MAX,
+ .mdiv_default = 1,
+ .freq_table = pll_dp_freq_table,
+ .set_defaults = tegra210_plldp_set_defaults,
+ .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+ .set_gain = tegra210_clk_pll_set_gain,
+ .adjust_vco = tegra210_clk_adjust_vco_min,
+};
+
+static struct div_nmp pllu_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 16,
+ .divp_width = 5,
+};
+
+static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
+ { 12000000, 480000000, 40, 1, 0},
+ { 13000000, 480000000, 36, 1, 0}, /* actual: 468.0 MHz */
+ { 38400000, 480000000, 25, 2, 0},
+ {0, 0, 0, 0, 0, 0},
+};
+
+static struct tegra_clk_pll_params pll_u_vco_params = {
+ .input_min = 9600000,
+ .input_max = 800000000,
+ .cf_min = 9600000,
+ .cf_max = 19200000,
+ .vco_min = 350000000,
+ .vco_max = 700000000,
+ .base_reg = PLLU_BASE,
+ .misc_reg = PLLU_MISC0,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLU_MISC_LOCK_ENABLE,
+ .lock_delay = 1000,
+ .iddq_reg = PLLU_MISC0,
+ .iddq_bit_idx = PLLU_IDDQ_BIT,
+ .ext_misc_reg[0] = PLLU_MISC0,
+ .ext_misc_reg[1] = PLLU_MISC1,
+ .round_p_to_pdiv = pll_qlin_p_to_pdiv,
+ .pdiv_tohw = pll_qlin_pdiv_to_hw,
+ .div_nmp = &pllu_nmp,
+ .freq_table = pll_u_freq_table,
+ .flags = TEGRA_PLLU | TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
+ TEGRA_PLL_VCO_OUT,
+ .set_defaults = tegra210_pllu_set_defaults,
+ .calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+struct utmi_clk_param {
+ /* Oscillator Frequency in KHz */
+ u32 osc_frequency;
+ /* UTMIP PLL Enable Delay Count */
+ u8 enable_delay_count;
+ /* UTMIP PLL Stable count */
+ u16 stable_count;
+ /* UTMIP PLL Active delay count */
+ u8 active_delay_count;
+ /* UTMIP PLL Xtal frequency count */
+ u16 xtal_freq_count;
+};
+
+static const struct utmi_clk_param utmi_parameters[] = {
+ {.osc_frequency = 38400000, .enable_delay_count = 0x05,
+ .stable_count = 0x96, .active_delay_count = 0x18,
+ .xtal_freq_count = 0x177},
+ {.osc_frequency = 13000000, .enable_delay_count = 0x02,
+ .stable_count = 0x33, .active_delay_count = 0x05,
+ .xtal_freq_count = 0x7F},
+ {.osc_frequency = 19200000, .enable_delay_count = 0x03,
+ .stable_count = 0x4B, .active_delay_count = 0x06,
+ .xtal_freq_count = 0xBB},
+ {.osc_frequency = 12000000, .enable_delay_count = 0x02,
+ .stable_count = 0x2F, .active_delay_count = 0x08,
+ .xtal_freq_count = 0x76},
+ {.osc_frequency = 26000000, .enable_delay_count = 0x04,
+ .stable_count = 0x66, .active_delay_count = 0x09,
+ .xtal_freq_count = 0xFE},
+ {.osc_frequency = 16800000, .enable_delay_count = 0x03,
+ .stable_count = 0x41, .active_delay_count = 0x0A,
+ .xtal_freq_count = 0xA4},
+};
+
+static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
+ [tegra_clk_ispb] = { .dt_id = TEGRA210_CLK_ISPB, .present = true },
+ [tegra_clk_rtc] = { .dt_id = TEGRA210_CLK_RTC, .present = true },
+ [tegra_clk_timer] = { .dt_id = TEGRA210_CLK_TIMER, .present = true },
+ [tegra_clk_uarta_8] = { .dt_id = TEGRA210_CLK_UARTA, .present = true },
+ [tegra_clk_sdmmc2_9] = { .dt_id = TEGRA210_CLK_SDMMC2, .present = true },
+ [tegra_clk_i2s1] = { .dt_id = TEGRA210_CLK_I2S1, .present = true },
+ [tegra_clk_i2c1] = { .dt_id = TEGRA210_CLK_I2C1, .present = true },
+ [tegra_clk_sdmmc1_9] = { .dt_id = TEGRA210_CLK_SDMMC1, .present = true },
+ [tegra_clk_sdmmc4_9] = { .dt_id = TEGRA210_CLK_SDMMC4, .present = true },
+ [tegra_clk_pwm] = { .dt_id = TEGRA210_CLK_PWM, .present = true },
+ [tegra_clk_i2s2] = { .dt_id = TEGRA210_CLK_I2S2, .present = true },
+ [tegra_clk_usbd] = { .dt_id = TEGRA210_CLK_USBD, .present = true },
+ [tegra_clk_isp_9] = { .dt_id = TEGRA210_CLK_ISP, .present = true },
+ [tegra_clk_disp2_8] = { .dt_id = TEGRA210_CLK_DISP2, .present = true },
+ [tegra_clk_disp1_8] = { .dt_id = TEGRA210_CLK_DISP1, .present = true },
+ [tegra_clk_host1x_9] = { .dt_id = TEGRA210_CLK_HOST1X, .present = true },
+ [tegra_clk_i2s0] = { .dt_id = TEGRA210_CLK_I2S0, .present = true },
+ [tegra_clk_apbdma] = { .dt_id = TEGRA210_CLK_APBDMA, .present = true },
+ [tegra_clk_kfuse] = { .dt_id = TEGRA210_CLK_KFUSE, .present = true },
+ [tegra_clk_sbc1_9] = { .dt_id = TEGRA210_CLK_SBC1, .present = true },
+ [tegra_clk_sbc2_9] = { .dt_id = TEGRA210_CLK_SBC2, .present = true },
+ [tegra_clk_sbc3_9] = { .dt_id = TEGRA210_CLK_SBC3, .present = true },
+ [tegra_clk_i2c5] = { .dt_id = TEGRA210_CLK_I2C5, .present = true },
+ [tegra_clk_csi] = { .dt_id = TEGRA210_CLK_CSI, .present = true },
+ [tegra_clk_i2c2] = { .dt_id = TEGRA210_CLK_I2C2, .present = true },
+ [tegra_clk_uartc_8] = { .dt_id = TEGRA210_CLK_UARTC, .present = true },
+ [tegra_clk_mipi_cal] = { .dt_id = TEGRA210_CLK_MIPI_CAL, .present = true },
+ [tegra_clk_emc] = { .dt_id = TEGRA210_CLK_EMC, .present = true },
+ [tegra_clk_usb2] = { .dt_id = TEGRA210_CLK_USB2, .present = true },
+ [tegra_clk_bsev] = { .dt_id = TEGRA210_CLK_BSEV, .present = true },
+ [tegra_clk_uartd_8] = { .dt_id = TEGRA210_CLK_UARTD, .present = true },
+ [tegra_clk_i2c3] = { .dt_id = TEGRA210_CLK_I2C3, .present = true },
+ [tegra_clk_sbc4_9] = { .dt_id = TEGRA210_CLK_SBC4, .present = true },
+ [tegra_clk_sdmmc3_9] = { .dt_id = TEGRA210_CLK_SDMMC3, .present = true },
+ [tegra_clk_pcie] = { .dt_id = TEGRA210_CLK_PCIE, .present = true },
+ [tegra_clk_owr_8] = { .dt_id = TEGRA210_CLK_OWR, .present = true },
+ [tegra_clk_afi] = { .dt_id = TEGRA210_CLK_AFI, .present = true },
+ [tegra_clk_csite_8] = { .dt_id = TEGRA210_CLK_CSITE, .present = true },
+ [tegra_clk_soc_therm_8] = { .dt_id = TEGRA210_CLK_SOC_THERM, .present = true },
+ [tegra_clk_dtv] = { .dt_id = TEGRA210_CLK_DTV, .present = true },
+ [tegra_clk_i2cslow] = { .dt_id = TEGRA210_CLK_I2CSLOW, .present = true },
+ [tegra_clk_tsec_8] = { .dt_id = TEGRA210_CLK_TSEC, .present = true },
+ [tegra_clk_xusb_host] = { .dt_id = TEGRA210_CLK_XUSB_HOST, .present = true },
+ [tegra_clk_csus] = { .dt_id = TEGRA210_CLK_CSUS, .present = true },
+ [tegra_clk_mselect] = { .dt_id = TEGRA210_CLK_MSELECT, .present = true },
+ [tegra_clk_tsensor] = { .dt_id = TEGRA210_CLK_TSENSOR, .present = true },
+ [tegra_clk_i2s3] = { .dt_id = TEGRA210_CLK_I2S3, .present = true },
+ [tegra_clk_i2s4] = { .dt_id = TEGRA210_CLK_I2S4, .present = true },
+ [tegra_clk_i2c4] = { .dt_id = TEGRA210_CLK_I2C4, .present = true },
+ [tegra_clk_d_audio] = { .dt_id = TEGRA210_CLK_D_AUDIO, .present = true },
+ [tegra_clk_hda2codec_2x_8] = { .dt_id = TEGRA210_CLK_HDA2CODEC_2X, .present = true },
+ [tegra_clk_spdif_2x] = { .dt_id = TEGRA210_CLK_SPDIF_2X, .present = true },
+ [tegra_clk_actmon] = { .dt_id = TEGRA210_CLK_ACTMON, .present = true },
+ [tegra_clk_extern1] = { .dt_id = TEGRA210_CLK_EXTERN1, .present = true },
+ [tegra_clk_extern2] = { .dt_id = TEGRA210_CLK_EXTERN2, .present = true },
+ [tegra_clk_extern3] = { .dt_id = TEGRA210_CLK_EXTERN3, .present = true },
+ [tegra_clk_sata_oob_8] = { .dt_id = TEGRA210_CLK_SATA_OOB, .present = true },
+ [tegra_clk_sata_8] = { .dt_id = TEGRA210_CLK_SATA, .present = true },
+ [tegra_clk_hda_8] = { .dt_id = TEGRA210_CLK_HDA, .present = true },
+ [tegra_clk_hda2hdmi] = { .dt_id = TEGRA210_CLK_HDA2HDMI, .present = true },
+ [tegra_clk_cilab] = { .dt_id = TEGRA210_CLK_CILAB, .present = true },
+ [tegra_clk_cilcd] = { .dt_id = TEGRA210_CLK_CILCD, .present = true },
+ [tegra_clk_cile] = { .dt_id = TEGRA210_CLK_CILE, .present = true },
+ [tegra_clk_dsialp] = { .dt_id = TEGRA210_CLK_DSIALP, .present = true },
+ [tegra_clk_dsiblp] = { .dt_id = TEGRA210_CLK_DSIBLP, .present = true },
+ [tegra_clk_entropy_8] = { .dt_id = TEGRA210_CLK_ENTROPY, .present = true },
+ [tegra_clk_xusb_ss] = { .dt_id = TEGRA210_CLK_XUSB_SS, .present = true },
+ [tegra_clk_i2c6] = { .dt_id = TEGRA210_CLK_I2C6, .present = true },
+ [tegra_clk_vim2_clk] = { .dt_id = TEGRA210_CLK_VIM2_CLK, .present = true },
+ [tegra_clk_clk72Mhz_8] = { .dt_id = TEGRA210_CLK_CLK72MHZ, .present = true },
+ [tegra_clk_vic03_8] = { .dt_id = TEGRA210_CLK_VIC03, .present = true },
+ [tegra_clk_dpaux] = { .dt_id = TEGRA210_CLK_DPAUX, .present = true },
+ [tegra_clk_sor0] = { .dt_id = TEGRA210_CLK_SOR0, .present = true },
+ [tegra_clk_sor0_lvds] = { .dt_id = TEGRA210_CLK_SOR0_LVDS, .present = true },
+ [tegra_clk_gpu] = { .dt_id = TEGRA210_CLK_GPU, .present = true },
+ [tegra_clk_pll_g_ref] = { .dt_id = TEGRA210_CLK_PLL_G_REF, .present = true, },
+ [tegra_clk_uartb_8] = { .dt_id = TEGRA210_CLK_UARTB, .present = true },
+ [tegra_clk_vfir] = { .dt_id = TEGRA210_CLK_VFIR, .present = true },
+ [tegra_clk_spdif_in_8] = { .dt_id = TEGRA210_CLK_SPDIF_IN, .present = true },
+ [tegra_clk_spdif_out] = { .dt_id = TEGRA210_CLK_SPDIF_OUT, .present = true },
+ [tegra_clk_vi_10] = { .dt_id = TEGRA210_CLK_VI, .present = true },
+ [tegra_clk_vi_sensor_8] = { .dt_id = TEGRA210_CLK_VI_SENSOR, .present = true },
+ [tegra_clk_fuse] = { .dt_id = TEGRA210_CLK_FUSE, .present = true },
+ [tegra_clk_fuse_burn] = { .dt_id = TEGRA210_CLK_FUSE_BURN, .present = true },
+ [tegra_clk_clk_32k] = { .dt_id = TEGRA210_CLK_CLK_32K, .present = true },
+ [tegra_clk_clk_m] = { .dt_id = TEGRA210_CLK_CLK_M, .present = true },
+ [tegra_clk_clk_m_div2] = { .dt_id = TEGRA210_CLK_CLK_M_DIV2, .present = true },
+ [tegra_clk_clk_m_div4] = { .dt_id = TEGRA210_CLK_CLK_M_DIV4, .present = true },
+ [tegra_clk_pll_ref] = { .dt_id = TEGRA210_CLK_PLL_REF, .present = true },
+ [tegra_clk_pll_c] = { .dt_id = TEGRA210_CLK_PLL_C, .present = true },
+ [tegra_clk_pll_c_out1] = { .dt_id = TEGRA210_CLK_PLL_C_OUT1, .present = true },
+ [tegra_clk_pll_c2] = { .dt_id = TEGRA210_CLK_PLL_C2, .present = true },
+ [tegra_clk_pll_c3] = { .dt_id = TEGRA210_CLK_PLL_C3, .present = true },
+ [tegra_clk_pll_m] = { .dt_id = TEGRA210_CLK_PLL_M, .present = true },
+ [tegra_clk_pll_m_out1] = { .dt_id = TEGRA210_CLK_PLL_M_OUT1, .present = true },
+ [tegra_clk_pll_p] = { .dt_id = TEGRA210_CLK_PLL_P, .present = true },
+ [tegra_clk_pll_p_out1] = { .dt_id = TEGRA210_CLK_PLL_P_OUT1, .present = true },
+ [tegra_clk_pll_p_out2] = { .dt_id = TEGRA210_CLK_PLL_P_OUT2, .present = true },
+ [tegra_clk_pll_p_out3] = { .dt_id = TEGRA210_CLK_PLL_P_OUT3, .present = true },
+ [tegra_clk_pll_p_out4] = { .dt_id = TEGRA210_CLK_PLL_P_OUT4, .present = true },
+ [tegra_clk_pll_a] = { .dt_id = TEGRA210_CLK_PLL_A, .present = true },
+ [tegra_clk_pll_a_out0] = { .dt_id = TEGRA210_CLK_PLL_A_OUT0, .present = true },
+ [tegra_clk_pll_d] = { .dt_id = TEGRA210_CLK_PLL_D, .present = true },
+ [tegra_clk_pll_d_out0] = { .dt_id = TEGRA210_CLK_PLL_D_OUT0, .present = true },
+ [tegra_clk_pll_d2] = { .dt_id = TEGRA210_CLK_PLL_D2, .present = true },
+ [tegra_clk_pll_d2_out0] = { .dt_id = TEGRA210_CLK_PLL_D2_OUT0, .present = true },
+ [tegra_clk_pll_u] = { .dt_id = TEGRA210_CLK_PLL_U, .present = true },
+ [tegra_clk_pll_u_out] = { .dt_id = TEGRA210_CLK_PLL_U_OUT, .present = true },
+ [tegra_clk_pll_u_out1] = { .dt_id = TEGRA210_CLK_PLL_U_OUT1, .present = true },
+ [tegra_clk_pll_u_out2] = { .dt_id = TEGRA210_CLK_PLL_U_OUT2, .present = true },
+ [tegra_clk_pll_u_480m] = { .dt_id = TEGRA210_CLK_PLL_U_480M, .present = true },
+ [tegra_clk_pll_u_60m] = { .dt_id = TEGRA210_CLK_PLL_U_60M, .present = true },
+ [tegra_clk_pll_u_48m] = { .dt_id = TEGRA210_CLK_PLL_U_48M, .present = true },
+ [tegra_clk_pll_x] = { .dt_id = TEGRA210_CLK_PLL_X, .present = true },
+ [tegra_clk_pll_x_out0] = { .dt_id = TEGRA210_CLK_PLL_X_OUT0, .present = true },
+ [tegra_clk_pll_re_vco] = { .dt_id = TEGRA210_CLK_PLL_RE_VCO, .present = true },
+ [tegra_clk_pll_re_out] = { .dt_id = TEGRA210_CLK_PLL_RE_OUT, .present = true },
+ [tegra_clk_spdif_in_sync] = { .dt_id = TEGRA210_CLK_SPDIF_IN_SYNC, .present = true },
+ [tegra_clk_i2s0_sync] = { .dt_id = TEGRA210_CLK_I2S0_SYNC, .present = true },
+ [tegra_clk_i2s1_sync] = { .dt_id = TEGRA210_CLK_I2S1_SYNC, .present = true },
+ [tegra_clk_i2s2_sync] = { .dt_id = TEGRA210_CLK_I2S2_SYNC, .present = true },
+ [tegra_clk_i2s3_sync] = { .dt_id = TEGRA210_CLK_I2S3_SYNC, .present = true },
+ [tegra_clk_i2s4_sync] = { .dt_id = TEGRA210_CLK_I2S4_SYNC, .present = true },
+ [tegra_clk_vimclk_sync] = { .dt_id = TEGRA210_CLK_VIMCLK_SYNC, .present = true },
+ [tegra_clk_audio0] = { .dt_id = TEGRA210_CLK_AUDIO0, .present = true },
+ [tegra_clk_audio1] = { .dt_id = TEGRA210_CLK_AUDIO1, .present = true },
+ [tegra_clk_audio2] = { .dt_id = TEGRA210_CLK_AUDIO2, .present = true },
+ [tegra_clk_audio3] = { .dt_id = TEGRA210_CLK_AUDIO3, .present = true },
+ [tegra_clk_audio4] = { .dt_id = TEGRA210_CLK_AUDIO4, .present = true },
+ [tegra_clk_spdif] = { .dt_id = TEGRA210_CLK_SPDIF, .present = true },
+ [tegra_clk_clk_out_1] = { .dt_id = TEGRA210_CLK_CLK_OUT_1, .present = true },
+ [tegra_clk_clk_out_2] = { .dt_id = TEGRA210_CLK_CLK_OUT_2, .present = true },
+ [tegra_clk_clk_out_3] = { .dt_id = TEGRA210_CLK_CLK_OUT_3, .present = true },
+ [tegra_clk_blink] = { .dt_id = TEGRA210_CLK_BLINK, .present = true },
+ [tegra_clk_xusb_host_src_8] = { .dt_id = TEGRA210_CLK_XUSB_HOST_SRC, .present = true },
+ [tegra_clk_xusb_falcon_src_8] = { .dt_id = TEGRA210_CLK_XUSB_FALCON_SRC, .present = true },
+ [tegra_clk_xusb_fs_src] = { .dt_id = TEGRA210_CLK_XUSB_FS_SRC, .present = true },
+ [tegra_clk_xusb_ss_src_8] = { .dt_id = TEGRA210_CLK_XUSB_SS_SRC, .present = true },
+ [tegra_clk_xusb_ss_div2] = { .dt_id = TEGRA210_CLK_XUSB_SS_DIV2, .present = true },
+ [tegra_clk_xusb_dev_src_8] = { .dt_id = TEGRA210_CLK_XUSB_DEV_SRC, .present = true },
+ [tegra_clk_xusb_dev] = { .dt_id = TEGRA210_CLK_XUSB_DEV, .present = true },
+ [tegra_clk_xusb_hs_src] = { .dt_id = TEGRA210_CLK_XUSB_HS_SRC, .present = true },
+ [tegra_clk_usb2_hsic_trk] = { .dt_id = TEGRA210_CLK_USB2_HSIC_TRK, .present = true },
+ [tegra_clk_hsic_trk] = { .dt_id = TEGRA210_CLK_HSIC_TRK, .present = true },
+ [tegra_clk_usb2_trk] = { .dt_id = TEGRA210_CLK_USB2_TRK, .present = true },
+ [tegra_clk_sclk] = { .dt_id = TEGRA210_CLK_SCLK, .present = true },
+ [tegra_clk_sclk_mux] = { .dt_id = TEGRA210_CLK_SCLK_MUX, .present = true },
+ [tegra_clk_hclk] = { .dt_id = TEGRA210_CLK_HCLK, .present = true },
+ [tegra_clk_pclk] = { .dt_id = TEGRA210_CLK_PCLK, .present = true },
+ [tegra_clk_cclk_g] = { .dt_id = TEGRA210_CLK_CCLK_G, .present = true },
+ [tegra_clk_cclk_lp] = { .dt_id = TEGRA210_CLK_CCLK_LP, .present = true },
+ [tegra_clk_dfll_ref] = { .dt_id = TEGRA210_CLK_DFLL_REF, .present = true },
+ [tegra_clk_dfll_soc] = { .dt_id = TEGRA210_CLK_DFLL_SOC, .present = true },
+ [tegra_clk_vi_sensor2_8] = { .dt_id = TEGRA210_CLK_VI_SENSOR2, .present = true },
+ [tegra_clk_pll_p_out5] = { .dt_id = TEGRA210_CLK_PLL_P_OUT5, .present = true },
+ [tegra_clk_pll_c4] = { .dt_id = TEGRA210_CLK_PLL_C4, .present = true },
+ [tegra_clk_pll_dp] = { .dt_id = TEGRA210_CLK_PLL_DP, .present = true },
+ [tegra_clk_audio0_mux] = { .dt_id = TEGRA210_CLK_AUDIO0_MUX, .present = true },
+ [tegra_clk_audio1_mux] = { .dt_id = TEGRA210_CLK_AUDIO1_MUX, .present = true },
+ [tegra_clk_audio2_mux] = { .dt_id = TEGRA210_CLK_AUDIO2_MUX, .present = true },
+ [tegra_clk_audio3_mux] = { .dt_id = TEGRA210_CLK_AUDIO3_MUX, .present = true },
+ [tegra_clk_audio4_mux] = { .dt_id = TEGRA210_CLK_AUDIO4_MUX, .present = true },
+ [tegra_clk_spdif_mux] = { .dt_id = TEGRA210_CLK_SPDIF_MUX, .present = true },
+ [tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_1_MUX, .present = true },
+ [tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_2_MUX, .present = true },
+ [tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_3_MUX, .present = true },
+ [tegra_clk_maud] = { .dt_id = TEGRA210_CLK_MAUD, .present = true },
+ [tegra_clk_mipibif] = { .dt_id = TEGRA210_CLK_MIPIBIF, .present = true },
+ [tegra_clk_qspi] = { .dt_id = TEGRA210_CLK_QSPI, .present = true },
+ [tegra_clk_sdmmc_legacy] = { .dt_id = TEGRA210_CLK_SDMMC_LEGACY, .present = true },
+ [tegra_clk_tsecb] = { .dt_id = TEGRA210_CLK_TSECB, .present = true },
+ [tegra_clk_uartape] = { .dt_id = TEGRA210_CLK_UARTAPE, .present = true },
+ [tegra_clk_vi_i2c] = { .dt_id = TEGRA210_CLK_VI_I2C, .present = true },
+ [tegra_clk_ape] = { .dt_id = TEGRA210_CLK_APE, .present = true },
+ [tegra_clk_dbgapb] = { .dt_id = TEGRA210_CLK_DBGAPB, .present = true },
+ [tegra_clk_nvdec] = { .dt_id = TEGRA210_CLK_NVDEC, .present = true },
+ [tegra_clk_nvenc] = { .dt_id = TEGRA210_CLK_NVENC, .present = true },
+ [tegra_clk_nvjpg] = { .dt_id = TEGRA210_CLK_NVJPG, .present = true },
+ [tegra_clk_pll_c4_out0] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT0, .present = true },
+ [tegra_clk_pll_c4_out1] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT1, .present = true },
+ [tegra_clk_pll_c4_out2] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT2, .present = true },
+ [tegra_clk_pll_c4_out3] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT3, .present = true },
+};
+
+static struct tegra_devclk devclks[] __initdata = {
+ { .con_id = "clk_m", .dt_id = TEGRA210_CLK_CLK_M },
+ { .con_id = "pll_ref", .dt_id = TEGRA210_CLK_PLL_REF },
+ { .con_id = "clk_32k", .dt_id = TEGRA210_CLK_CLK_32K },
+ { .con_id = "clk_m_div2", .dt_id = TEGRA210_CLK_CLK_M_DIV2 },
+ { .con_id = "clk_m_div4", .dt_id = TEGRA210_CLK_CLK_M_DIV4 },
+ { .con_id = "pll_c", .dt_id = TEGRA210_CLK_PLL_C },
+ { .con_id = "pll_c_out1", .dt_id = TEGRA210_CLK_PLL_C_OUT1 },
+ { .con_id = "pll_c2", .dt_id = TEGRA210_CLK_PLL_C2 },
+ { .con_id = "pll_c3", .dt_id = TEGRA210_CLK_PLL_C3 },
+ { .con_id = "pll_p", .dt_id = TEGRA210_CLK_PLL_P },
+ { .con_id = "pll_p_out1", .dt_id = TEGRA210_CLK_PLL_P_OUT1 },
+ { .con_id = "pll_p_out2", .dt_id = TEGRA210_CLK_PLL_P_OUT2 },
+ { .con_id = "pll_p_out3", .dt_id = TEGRA210_CLK_PLL_P_OUT3 },
+ { .con_id = "pll_p_out4", .dt_id = TEGRA210_CLK_PLL_P_OUT4 },
+ { .con_id = "pll_m", .dt_id = TEGRA210_CLK_PLL_M },
+ { .con_id = "pll_m_out1", .dt_id = TEGRA210_CLK_PLL_M_OUT1 },
+ { .con_id = "pll_x", .dt_id = TEGRA210_CLK_PLL_X },
+ { .con_id = "pll_x_out0", .dt_id = TEGRA210_CLK_PLL_X_OUT0 },
+ { .con_id = "pll_u", .dt_id = TEGRA210_CLK_PLL_U },
+ { .con_id = "pll_u_out", .dt_id = TEGRA210_CLK_PLL_U_OUT },
+ { .con_id = "pll_u_out1", .dt_id = TEGRA210_CLK_PLL_U_OUT1 },
+ { .con_id = "pll_u_out2", .dt_id = TEGRA210_CLK_PLL_U_OUT2 },
+ { .con_id = "pll_u_480M", .dt_id = TEGRA210_CLK_PLL_U_480M },
+ { .con_id = "pll_u_60M", .dt_id = TEGRA210_CLK_PLL_U_60M },
+ { .con_id = "pll_u_48M", .dt_id = TEGRA210_CLK_PLL_U_48M },
+ { .con_id = "pll_d", .dt_id = TEGRA210_CLK_PLL_D },
+ { .con_id = "pll_d_out0", .dt_id = TEGRA210_CLK_PLL_D_OUT0 },
+ { .con_id = "pll_d2", .dt_id = TEGRA210_CLK_PLL_D2 },
+ { .con_id = "pll_d2_out0", .dt_id = TEGRA210_CLK_PLL_D2_OUT0 },
+ { .con_id = "pll_a", .dt_id = TEGRA210_CLK_PLL_A },
+ { .con_id = "pll_a_out0", .dt_id = TEGRA210_CLK_PLL_A_OUT0 },
+ { .con_id = "pll_re_vco", .dt_id = TEGRA210_CLK_PLL_RE_VCO },
+ { .con_id = "pll_re_out", .dt_id = TEGRA210_CLK_PLL_RE_OUT },
+ { .con_id = "spdif_in_sync", .dt_id = TEGRA210_CLK_SPDIF_IN_SYNC },
+ { .con_id = "i2s0_sync", .dt_id = TEGRA210_CLK_I2S0_SYNC },
+ { .con_id = "i2s1_sync", .dt_id = TEGRA210_CLK_I2S1_SYNC },
+ { .con_id = "i2s2_sync", .dt_id = TEGRA210_CLK_I2S2_SYNC },
+ { .con_id = "i2s3_sync", .dt_id = TEGRA210_CLK_I2S3_SYNC },
+ { .con_id = "i2s4_sync", .dt_id = TEGRA210_CLK_I2S4_SYNC },
+ { .con_id = "vimclk_sync", .dt_id = TEGRA210_CLK_VIMCLK_SYNC },
+ { .con_id = "audio0", .dt_id = TEGRA210_CLK_AUDIO0 },
+ { .con_id = "audio1", .dt_id = TEGRA210_CLK_AUDIO1 },
+ { .con_id = "audio2", .dt_id = TEGRA210_CLK_AUDIO2 },
+ { .con_id = "audio3", .dt_id = TEGRA210_CLK_AUDIO3 },
+ { .con_id = "audio4", .dt_id = TEGRA210_CLK_AUDIO4 },
+ { .con_id = "spdif", .dt_id = TEGRA210_CLK_SPDIF },
+ { .con_id = "spdif_2x", .dt_id = TEGRA210_CLK_SPDIF_2X },
+ { .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA210_CLK_EXTERN1 },
+ { .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA210_CLK_EXTERN2 },
+ { .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA210_CLK_EXTERN3 },
+ { .con_id = "blink", .dt_id = TEGRA210_CLK_BLINK },
+ { .con_id = "cclk_g", .dt_id = TEGRA210_CLK_CCLK_G },
+ { .con_id = "cclk_lp", .dt_id = TEGRA210_CLK_CCLK_LP },
+ { .con_id = "sclk", .dt_id = TEGRA210_CLK_SCLK },
+ { .con_id = "hclk", .dt_id = TEGRA210_CLK_HCLK },
+ { .con_id = "pclk", .dt_id = TEGRA210_CLK_PCLK },
+ { .con_id = "fuse", .dt_id = TEGRA210_CLK_FUSE },
+ { .dev_id = "rtc-tegra", .dt_id = TEGRA210_CLK_RTC },
+ { .dev_id = "timer", .dt_id = TEGRA210_CLK_TIMER },
+ { .con_id = "pll_c4_out0", .dt_id = TEGRA210_CLK_PLL_C4_OUT0 },
+ { .con_id = "pll_c4_out1", .dt_id = TEGRA210_CLK_PLL_C4_OUT1 },
+ { .con_id = "pll_c4_out2", .dt_id = TEGRA210_CLK_PLL_C4_OUT2 },
+ { .con_id = "pll_c4_out3", .dt_id = TEGRA210_CLK_PLL_C4_OUT3 },
+ { .con_id = "dpaux", .dt_id = TEGRA210_CLK_DPAUX },
+ { .con_id = "sor0", .dt_id = TEGRA210_CLK_SOR0 },
+};
+
+static struct tegra_audio_clk_info tegra210_audio_plls[] = {
+ { "pll_a", &pll_a_params, tegra_clk_pll_a, "pll_ref" },
+ { "pll_a1", &pll_a1_params, tegra_clk_pll_a1, "pll_ref" },
+};
+
+static struct clk **clks;
+
+static void tegra210_utmi_param_configure(void __iomem *clk_base)
+{
+ u32 reg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
+ if (osc_freq == utmi_parameters[i].osc_frequency)
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(utmi_parameters)) {
+ pr_err("%s: Unexpected oscillator freq %lu\n", __func__,
+ osc_freq);
+ return;
+ }
+
+ reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2);
+
+ /* Program UTMIP PLL stable and active counts */
+ /* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */
+ reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+ reg |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
+
+ reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+
+ reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(utmi_parameters[i].
+ active_delay_count);
+
+ /* Remove power downs from UTMIP PLL control bits */
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
+
+ writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2);
+
+ /* Program UTMIP PLL delay and oscillator frequency counts */
+ reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
+ reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+
+ reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(utmi_parameters[i].
+ enable_delay_count);
+
+ reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+ reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(utmi_parameters[i].
+ xtal_freq_count);
+
+ /* Remove power downs from UTMIP PLL control bits */
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
+ writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
+
+ /* Setup HW control of UTMIPLL */
+ reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ reg |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET;
+ reg &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL;
+ reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE;
+ writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+ reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
+
+ udelay(1);
+
+ /* Setup SW override of UTMIPLL assuming USB2.0
+ ports are assigned to USB2 */
+ reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ reg |= UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL;
+ reg &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
+ writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+ udelay(1);
+
+ /* Enable HW control UTMIPLL */
+ reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE;
+ writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
+}
+
+static __init void tegra210_periph_clk_init(void __iomem *clk_base,
+ void __iomem *pmc_base)
+{
+ struct clk *clk;
+
+ /* xusb_ss_div2 */
+ clk = clk_register_fixed_factor(NULL, "xusb_ss_div2", "xusb_ss_src", 0,
+ 1, 2);
+ clks[TEGRA210_CLK_XUSB_SS_DIV2] = clk;
+
+ /* pll_d_dsi_out */
+ clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0,
+ clk_base + PLLD_MISC0, 21, 0, &pll_d_lock);
+ clks[TEGRA210_CLK_PLL_D_DSI_OUT] = clk;
+
+ /* dsia */
+ clk = tegra_clk_register_periph_gate("dsia", "pll_d_dsi_out", 0,
+ clk_base, 0, 48,
+ periph_clk_enb_refcnt);
+ clks[TEGRA210_CLK_DSIA] = clk;
+
+ /* dsib */
+ clk = tegra_clk_register_periph_gate("dsib", "pll_d_dsi_out", 0,
+ clk_base, 0, 82,
+ periph_clk_enb_refcnt);
+ clks[TEGRA210_CLK_DSIB] = clk;
+
+ /* emc mux */
+ clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
+ ARRAY_SIZE(mux_pllmcp_clkm), 0,
+ clk_base + CLK_SOURCE_EMC,
+ 29, 3, 0, &emc_lock);
+
+ clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
+ &emc_lock);
+ clks[TEGRA210_CLK_MC] = clk;
+
+ /* cml0 */
+ clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX,
+ 0, 0, &pll_e_lock);
+ clk_register_clkdev(clk, "cml0", NULL);
+ clks[TEGRA210_CLK_CML0] = clk;
+
+ /* cml1 */
+ clk = clk_register_gate(NULL, "cml1", "pll_e", 0, clk_base + PLLE_AUX,
+ 1, 0, &pll_e_lock);
+ clk_register_clkdev(clk, "cml1", NULL);
+ clks[TEGRA210_CLK_CML1] = clk;
+
+ tegra_periph_clk_init(clk_base, pmc_base, tegra210_clks, &pll_p_params);
+}
+
+static void __init tegra210_pll_init(void __iomem *clk_base,
+ void __iomem *pmc)
+{
+ u32 val;
+ struct clk *clk;
+
+ /* PLLC */
+ clk = tegra_clk_register_pllxc_tegra210("pll_c", "pll_ref", clk_base,
+ pmc, 0, &pll_c_params, NULL);
+ if (!WARN_ON(IS_ERR(clk)))
+ clk_register_clkdev(clk, "pll_c", NULL);
+ clks[TEGRA210_CLK_PLL_C] = clk;
+
+ /* PLLC_OUT1 */
+ clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c",
+ clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, NULL);
+ clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div",
+ clk_base + PLLC_OUT, 1, 0,
+ CLK_SET_RATE_PARENT, 0, NULL);
+ clk_register_clkdev(clk, "pll_c_out1", NULL);
+ clks[TEGRA210_CLK_PLL_C_OUT1] = clk;
+
+ /* PLLC_UD */
+ clk = clk_register_fixed_factor(NULL, "pll_c_ud", "pll_c",
+ CLK_SET_RATE_PARENT, 1, 1);
+ clk_register_clkdev(clk, "pll_c_ud", NULL);
+ clks[TEGRA210_CLK_PLL_C_UD] = clk;
+
+ /* PLLC2 */
+ clk = tegra_clk_register_pllc_tegra210("pll_c2", "pll_ref", clk_base,
+ pmc, 0, &pll_c2_params, NULL);
+ clk_register_clkdev(clk, "pll_c2", NULL);
+ clks[TEGRA210_CLK_PLL_C2] = clk;
+
+ /* PLLC3 */
+ clk = tegra_clk_register_pllc_tegra210("pll_c3", "pll_ref", clk_base,
+ pmc, 0, &pll_c3_params, NULL);
+ clk_register_clkdev(clk, "pll_c3", NULL);
+ clks[TEGRA210_CLK_PLL_C3] = clk;
+
+ /* PLLM */
+ clk = tegra_clk_register_pllm("pll_m", "osc", clk_base, pmc,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE,
+ &pll_m_params, NULL);
+ clk_register_clkdev(clk, "pll_m", NULL);
+ clks[TEGRA210_CLK_PLL_M] = clk;
+
+ /* PLLMB */
+ clk = tegra_clk_register_pllmb("pll_mb", "osc", clk_base, pmc,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE,
+ &pll_mb_params, NULL);
+ clk_register_clkdev(clk, "pll_mb", NULL);
+ clks[TEGRA210_CLK_PLL_MB] = clk;
+
+ clk_register_clkdev(clk, "pll_m_out1", NULL);
+ clks[TEGRA210_CLK_PLL_M_OUT1] = clk;
+
+ /* PLLM_UD */
+ clk = clk_register_fixed_factor(NULL, "pll_m_ud", "pll_m",
+ CLK_SET_RATE_PARENT, 1, 1);
+ clk_register_clkdev(clk, "pll_m_ud", NULL);
+ clks[TEGRA210_CLK_PLL_M_UD] = clk;
+
+ /* PLLU_VCO */
+ val = readl(clk_base + pll_u_vco_params.base_reg);
+ val &= ~BIT(24); /* disable PLLU_OVERRIDE */
+ writel(val, clk_base + pll_u_vco_params.base_reg);
+
+ clk = tegra_clk_register_pllre("pll_u_vco", "pll_ref", clk_base, pmc,
+ 0, &pll_u_vco_params, &pll_u_lock, pll_ref_freq);
+ clk_register_clkdev(clk, "pll_u_vco", NULL);
+ clks[TEGRA210_CLK_PLL_U] = clk;
+
+ /* PLLU_OUT */
+ clk = clk_register_divider_table(NULL, "pll_u_out", "pll_u_vco", 0,
+ clk_base + PLLU_BASE, 16, 4, 0,
+ pll_vco_post_div_table, NULL);
+ clk_register_clkdev(clk, "pll_u_out", NULL);
+ clks[TEGRA210_CLK_PLL_U_OUT] = clk;
+
+ /* PLLU_OUT1 */
+ clk = tegra_clk_register_divider("pll_u_out1_div", "pll_u_out",
+ clk_base + PLLU_OUTA, 0,
+ TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, &pll_u_lock);
+ clk = tegra_clk_register_pll_out("pll_u_out1", "pll_u_out1_div",
+ clk_base + PLLU_OUTA, 1, 0,
+ CLK_SET_RATE_PARENT, 0, &pll_u_lock);
+ clk_register_clkdev(clk, "pll_u_out1", NULL);
+ clks[TEGRA210_CLK_PLL_U_OUT1] = clk;
+
+ /* PLLU_OUT2 */
+ clk = tegra_clk_register_divider("pll_u_out2_div", "pll_u_out",
+ clk_base + PLLU_OUTA, 0,
+ TEGRA_DIVIDER_ROUND_UP,
+ 24, 8, 1, &pll_u_lock);
+ clk = tegra_clk_register_pll_out("pll_u_out2", "pll_u_out2_div",
+ clk_base + PLLU_OUTA, 17, 16,
+ CLK_SET_RATE_PARENT, 0, &pll_u_lock);
+ clk_register_clkdev(clk, "pll_u_out2", NULL);
+ clks[TEGRA210_CLK_PLL_U_OUT2] = clk;
+
+ tegra210_utmi_param_configure(clk_base);
+
+ /* PLLU_480M */
+ clk = clk_register_gate(NULL, "pll_u_480M", "pll_u_vco",
+ CLK_SET_RATE_PARENT, clk_base + PLLU_BASE,
+ 22, 0, &pll_u_lock);
+ clk_register_clkdev(clk, "pll_u_480M", NULL);
+ clks[TEGRA210_CLK_PLL_U_480M] = clk;
+
+ /* PLLU_60M */
+ clk = clk_register_gate(NULL, "pll_u_60M", "pll_u_out2",
+ CLK_SET_RATE_PARENT, clk_base + PLLU_BASE,
+ 23, 0, NULL);
+ clk_register_clkdev(clk, "pll_u_60M", NULL);
+ clks[TEGRA210_CLK_PLL_U_60M] = clk;
+
+ /* PLLU_48M */
+ clk = clk_register_gate(NULL, "pll_u_48M", "pll_u_out1",
+ CLK_SET_RATE_PARENT, clk_base + PLLU_BASE,
+ 25, 0, NULL);
+ clk_register_clkdev(clk, "pll_u_48M", NULL);
+ clks[TEGRA210_CLK_PLL_U_48M] = clk;
+
+ /* PLLD */
+ clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc, 0,
+ &pll_d_params, &pll_d_lock);
+ clk_register_clkdev(clk, "pll_d", NULL);
+ clks[TEGRA210_CLK_PLL_D] = clk;
+
+ /* PLLD_OUT0 */
+ clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll_d_out0", NULL);
+ clks[TEGRA210_CLK_PLL_D_OUT0] = clk;
+
+ /* PLLRE */
+ clk = tegra_clk_register_pllre("pll_re_vco", "pll_ref", clk_base, pmc,
+ 0, &pll_re_vco_params, &pll_re_lock, pll_ref_freq);
+ clk_register_clkdev(clk, "pll_re_vco", NULL);
+ clks[TEGRA210_CLK_PLL_RE_VCO] = clk;
+
+ clk = clk_register_divider_table(NULL, "pll_re_out", "pll_re_vco", 0,
+ clk_base + PLLRE_BASE, 16, 5, 0,
+ pll_vco_post_div_table, &pll_re_lock);
+ clk_register_clkdev(clk, "pll_re_out", NULL);
+ clks[TEGRA210_CLK_PLL_RE_OUT] = clk;
+
+ /* PLLE */
+ clk = tegra_clk_register_plle_tegra210("pll_e", "pll_ref",
+ clk_base, 0, &pll_e_params, NULL);
+ clk_register_clkdev(clk, "pll_e", NULL);
+ clks[TEGRA210_CLK_PLL_E] = clk;
+
+ /* PLLC4 */
+ clk = tegra_clk_register_pllre("pll_c4_vco", "pll_ref", clk_base, pmc,
+ 0, &pll_c4_vco_params, NULL, pll_ref_freq);
+ clk_register_clkdev(clk, "pll_c4_vco", NULL);
+ clks[TEGRA210_CLK_PLL_C4] = clk;
+
+ /* PLLC4_OUT0 */
+ clk = clk_register_divider_table(NULL, "pll_c4_out0", "pll_c4_vco", 0,
+ clk_base + PLLC4_BASE, 19, 4, 0,
+ pll_vco_post_div_table, NULL);
+ clk_register_clkdev(clk, "pll_c4_out0", NULL);
+ clks[TEGRA210_CLK_PLL_C4_OUT0] = clk;
+
+ /* PLLC4_OUT1 */
+ clk = clk_register_fixed_factor(NULL, "pll_c4_out1", "pll_c4_vco",
+ CLK_SET_RATE_PARENT, 1, 3);
+ clk_register_clkdev(clk, "pll_c4_out1", NULL);
+ clks[TEGRA210_CLK_PLL_C4_OUT1] = clk;
+
+ /* PLLC4_OUT2 */
+ clk = clk_register_fixed_factor(NULL, "pll_c4_out2", "pll_c4_vco",
+ CLK_SET_RATE_PARENT, 1, 5);
+ clk_register_clkdev(clk, "pll_c4_out2", NULL);
+ clks[TEGRA210_CLK_PLL_C4_OUT2] = clk;
+
+ /* PLLC4_OUT3 */
+ clk = tegra_clk_register_divider("pll_c4_out3_div", "pll_c4_out0",
+ clk_base + PLLC4_OUT, 0, TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, NULL);
+ clk = tegra_clk_register_pll_out("pll_c4_out3", "pll_c4_out3_div",
+ clk_base + PLLC4_OUT, 1, 0,
+ CLK_SET_RATE_PARENT, 0, NULL);
+ clk_register_clkdev(clk, "pll_c4_out3", NULL);
+ clks[TEGRA210_CLK_PLL_C4_OUT3] = clk;
+
+ /* PLLDP */
+ clk = tegra_clk_register_pllss_tegra210("pll_dp", "pll_ref", clk_base,
+ 0, &pll_dp_params, NULL);
+ clk_register_clkdev(clk, "pll_dp", NULL);
+ clks[TEGRA210_CLK_PLL_DP] = clk;
+
+ /* PLLD2 */
+ clk = tegra_clk_register_pllss_tegra210("pll_d2", "pll_ref", clk_base,
+ 0, &pll_d2_params, NULL);
+ clk_register_clkdev(clk, "pll_d2", NULL);
+ clks[TEGRA210_CLK_PLL_D2] = clk;
+
+ /* PLLD2_OUT0 */
+ clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2",
+ CLK_SET_RATE_PARENT, 1, 1);
+ clk_register_clkdev(clk, "pll_d2_out0", NULL);
+ clks[TEGRA210_CLK_PLL_D2_OUT0] = clk;
+
+}
+
+/* Tegra210 CPU clock and reset control functions */
+static void tegra210_wait_cpu_in_reset(u32 cpu)
+{
+ unsigned int reg;
+
+ do {
+ reg = readl(clk_base + CLK_RST_CONTROLLER_CPU_CMPLX_STATUS);
+ cpu_relax();
+ } while (!(reg & (1 << cpu))); /* check CPU been reset or not */
+}
+
+static void tegra210_disable_cpu_clock(u32 cpu)
+{
+ /* flow controller would take care in the power sequence. */
+}
+
+#ifdef CONFIG_PM_SLEEP
+static void tegra210_cpu_clock_suspend(void)
+{
+ /* switch coresite to clk_m, save off original source */
+ tegra210_cpu_clk_sctx.clk_csite_src =
+ readl(clk_base + CLK_SOURCE_CSITE);
+ writel(3 << 30, clk_base + CLK_SOURCE_CSITE);
+}
+
+static void tegra210_cpu_clock_resume(void)
+{
+ writel(tegra210_cpu_clk_sctx.clk_csite_src,
+ clk_base + CLK_SOURCE_CSITE);
+}
+#endif
+
+static struct tegra_cpu_car_ops tegra210_cpu_car_ops = {
+ .wait_for_reset = tegra210_wait_cpu_in_reset,
+ .disable_clock = tegra210_disable_cpu_clock,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = tegra210_cpu_clock_suspend,
+ .resume = tegra210_cpu_clock_resume,
+#endif
+};
+
+static const struct of_device_id pmc_match[] __initconst = {
+ { .compatible = "nvidia,tegra210-pmc" },
+ {},
+};
+
+static struct tegra_clk_init_table common_init_table[] __initdata = {
+ {TEGRA210_CLK_UARTA, TEGRA210_CLK_PLL_P, 408000000, 0},
+ {TEGRA210_CLK_UARTB, TEGRA210_CLK_PLL_P, 408000000, 0},
+ {TEGRA210_CLK_UARTC, TEGRA210_CLK_PLL_P, 408000000, 0},
+ {TEGRA210_CLK_UARTD, TEGRA210_CLK_PLL_P, 408000000, 0},
+ {TEGRA210_CLK_PLL_A, TEGRA210_CLK_CLK_MAX, 564480000, 1},
+ {TEGRA210_CLK_PLL_A_OUT0, TEGRA210_CLK_CLK_MAX, 11289600, 1},
+ {TEGRA210_CLK_EXTERN1, TEGRA210_CLK_PLL_A_OUT0, 0, 1},
+ {TEGRA210_CLK_CLK_OUT_1_MUX, TEGRA210_CLK_EXTERN1, 0, 1},
+ {TEGRA210_CLK_CLK_OUT_1, TEGRA210_CLK_CLK_MAX, 0, 1},
+ {TEGRA210_CLK_I2S0, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0},
+ {TEGRA210_CLK_I2S1, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0},
+ {TEGRA210_CLK_I2S2, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0},
+ {TEGRA210_CLK_I2S3, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0},
+ {TEGRA210_CLK_I2S4, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0},
+ {TEGRA210_CLK_HOST1X, TEGRA210_CLK_PLL_P, 136000000, 1},
+ {TEGRA210_CLK_SCLK_MUX, TEGRA210_CLK_PLL_P, 0, 1},
+ {TEGRA210_CLK_SCLK, TEGRA210_CLK_CLK_MAX, 102000000, 1},
+ {TEGRA210_CLK_DFLL_SOC, TEGRA210_CLK_PLL_P, 51000000, 1},
+ {TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1},
+ {TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1},
+ {TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 624000000, 0},
+ {TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 0},
+ {TEGRA210_CLK_PLL_U_OUT2, TEGRA210_CLK_CLK_MAX, 60000000, 0},
+ {TEGRA210_CLK_XUSB_SS_SRC, TEGRA210_CLK_PLL_U_480M, 120000000, 0},
+ {TEGRA210_CLK_XUSB_FS_SRC, TEGRA210_CLK_PLL_U_48M, 48000000, 0},
+ {TEGRA210_CLK_XUSB_HS_SRC, TEGRA210_CLK_PLL_U_60M, 60000000, 0},
+ {TEGRA210_CLK_XUSB_FALCON_SRC, TEGRA210_CLK_PLL_RE_OUT, 224000000, 0},
+ {TEGRA210_CLK_XUSB_HOST_SRC, TEGRA210_CLK_PLL_RE_OUT, 112000000, 0},
+ {TEGRA210_CLK_SATA, TEGRA210_CLK_PLL_P, 104000000, 0},
+ {TEGRA210_CLK_SATA_OOB, TEGRA210_CLK_PLL_P, 204000000, 0},
+ {TEGRA210_CLK_EMC, TEGRA210_CLK_CLK_MAX, 0, 1},
+ {TEGRA210_CLK_MSELECT, TEGRA210_CLK_CLK_MAX, 0, 1},
+ {TEGRA210_CLK_CSITE, TEGRA210_CLK_CLK_MAX, 0, 1},
+ {TEGRA210_CLK_TSENSOR, TEGRA210_CLK_CLK_M, 400000, 0},
+ {TEGRA210_CLK_I2C1, TEGRA210_CLK_PLL_P, 0, 0},
+ {TEGRA210_CLK_I2C2, TEGRA210_CLK_PLL_P, 0, 0},
+ {TEGRA210_CLK_I2C3, TEGRA210_CLK_PLL_P, 0, 0},
+ {TEGRA210_CLK_I2C4, TEGRA210_CLK_PLL_P, 0, 0},
+ {TEGRA210_CLK_I2C5, TEGRA210_CLK_PLL_P, 0, 0},
+ {TEGRA210_CLK_I2C6, TEGRA210_CLK_PLL_P, 0, 0},
+ {TEGRA210_CLK_PLL_DP, TEGRA210_CLK_CLK_MAX, 270000000, 0},
+ /* This MUST be the last entry. */
+ {TEGRA210_CLK_CLK_MAX, TEGRA210_CLK_CLK_MAX, 0, 0},
+};
+
+static struct tegra_clk_init_table tegra210_init_table[] __initdata = {
+ {TEGRA210_CLK_SOC_THERM, TEGRA210_CLK_PLL_P, 51000000, 0},
+ {TEGRA210_CLK_CCLK_G, TEGRA210_CLK_CLK_MAX, 0, 1},
+ /* This MUST be the last entry. */
+ {TEGRA210_CLK_CLK_MAX, TEGRA210_CLK_CLK_MAX, 0, 0},
+};
+
+/**
+ * tegra210_clock_apply_init_table - initialize clocks on Tegra210 SoCs
+ *
+ * Program an initial clock rate and enable or disable clocks needed
+ * by the rest of the kernel, for Tegra210 SoCs. It is intended to be
+ * called by assigning a pointer to it to tegra_clk_apply_init_table -
+ * this will be called as an arch_initcall. No return value.
+ */
+static void __init tegra210_clock_apply_init_table(void)
+{
+ tegra_init_from_table(common_init_table, clks, TEGRA210_CLK_CLK_MAX);
+ tegra_init_from_table(tegra210_init_table, clks, TEGRA210_CLK_CLK_MAX);
+}
+
+/**
+ * tegra210_clock_init - Tegra210-specific clock initialization
+ * @np: struct device_node * of the DT node for the SoC CAR IP block
+ *
+ * Register most SoC clocks for the Tegra210 system-on-chip. Intended
+ * to be called by the OF init code when a DT node with the
+ * "nvidia,tegra210-car" string is encountered, and declared with
+ * CLK_OF_DECLARE. No return value.
+ */
+static void __init tegra210_clock_init(struct device_node *np)
+{
+ struct device_node *node;
+ u32 value, clk_m_div;
+
+ clk_base = of_iomap(np, 0);
+ if (!clk_base) {
+ pr_err("ioremap tegra210 CAR failed\n");
+ return;
+ }
+
+ node = of_find_matching_node(NULL, pmc_match);
+ if (!node) {
+ pr_err("Failed to find pmc node\n");
+ WARN_ON(1);
+ return;
+ }
+
+ pmc_base = of_iomap(node, 0);
+ if (!pmc_base) {
+ pr_err("Can't map pmc registers\n");
+ WARN_ON(1);
+ return;
+ }
+
+ clks = tegra_clk_init(clk_base, TEGRA210_CLK_CLK_MAX,
+ TEGRA210_CAR_BANK_COUNT);
+ if (!clks)
+ return;
+
+ value = clk_readl(clk_base + SPARE_REG0) >> CLK_M_DIVISOR_SHIFT;
+ clk_m_div = (value & CLK_M_DIVISOR_MASK) + 1;
+
+ if (tegra_osc_clk_init(clk_base, tegra210_clks, tegra210_input_freq,
+ ARRAY_SIZE(tegra210_input_freq), clk_m_div,
+ &osc_freq, &pll_ref_freq) < 0)
+ return;
+
+ tegra_fixed_clk_init(tegra210_clks);
+ tegra210_pll_init(clk_base, pmc_base);
+ tegra210_periph_clk_init(clk_base, pmc_base);
+ tegra_audio_clk_init(clk_base, pmc_base, tegra210_clks,
+ tegra210_audio_plls,
+ ARRAY_SIZE(tegra210_audio_plls));
+ tegra_pmc_clk_init(pmc_base, tegra210_clks);
+
+ /* For Tegra210, PLLD is the only source for DSIA & DSIB */
+ value = clk_readl(clk_base + PLLD_BASE);
+ value &= ~BIT(25);
+ clk_writel(value, clk_base + PLLD_BASE);
+
+ tegra_clk_apply_init_table = tegra210_clock_apply_init_table;
+
+ tegra_super_clk_gen5_init(clk_base, pmc_base, tegra210_clks,
+ &pll_x_params);
+ tegra_add_of_provider(np);
+ tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
+
+ tegra_cpu_car_ops = &tegra210_cpu_car_ops;
+}
+CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index ec5939c03e2c..475156d8fc1b 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -231,6 +231,7 @@ struct tegra_clk_pll;
* it may be more accurate (especially if SDM present)
* TEGRA_PLLMB - PLLMB has should be treated similar to PLLM. This
* flag indicated that it is PLLMB.
+ * TEGRA_PLL_VCO_OUT - Used to indicate that the PLL has a VCO output
*/
struct tegra_clk_pll_params {
unsigned long input_min;
@@ -296,6 +297,7 @@ struct tegra_clk_pll_params {
#define TEGRA_PLL_HAS_LOCK_ENABLE BIT(10)
#define TEGRA_MDIV_NEW BIT(11)
#define TEGRA_PLLMB BIT(12)
+#define TEGRA_PLL_VCO_OUT BIT(13)

/**
* struct tegra_clk_pll - Tegra PLL clock
diff --git a/include/dt-bindings/clock/tegra210-car.h b/include/dt-bindings/clock/tegra210-car.h
new file mode 100644
index 000000000000..db4f86f4fbca
--- /dev/null
+++ b/include/dt-bindings/clock/tegra210-car.h
@@ -0,0 +1,401 @@
+/*
+ * This header provides constants for binding nvidia,tegra210-car.
+ *
+ * The first 224 clocks are numbered to match the bits in the CAR's CLK_OUT_ENB
+ * registers. These IDs often match those in the CAR's RST_DEVICES registers,
+ * but not in all cases. Some bits in CLK_OUT_ENB affect multiple clocks. In
+ * this case, those clocks are assigned IDs above 224 in order to highlight
+ * this issue. Implementations that interpret these clock IDs as bit values
+ * within the CLK_OUT_ENB or RST_DEVICES registers should be careful to
+ * explicitly handle these special cases.
+ *
+ * The balance of the clocks controlled by the CAR are assigned IDs of 224 and
+ * above.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_TEGRA210_CAR_H
+#define _DT_BINDINGS_CLOCK_TEGRA210_CAR_H
+
+/* 0 */
+/* 1 */
+/* 2 */
+#define TEGRA210_CLK_ISPB 3
+#define TEGRA210_CLK_RTC 4
+#define TEGRA210_CLK_TIMER 5
+#define TEGRA210_CLK_UARTA 6
+/* 7 (register bit affects uartb and vfir) */
+#define TEGRA210_CLK_GPIO 8
+#define TEGRA210_CLK_SDMMC2 9
+/* 10 (register bit affects spdif_in and spdif_out) */
+#define TEGRA210_CLK_I2S1 11
+#define TEGRA210_CLK_I2C1 12
+/* 13 */
+#define TEGRA210_CLK_SDMMC1 14
+#define TEGRA210_CLK_SDMMC4 15
+/* 16 */
+#define TEGRA210_CLK_PWM 17
+#define TEGRA210_CLK_I2S2 18
+/* 19 */
+/* 20 (register bit affects vi and vi_sensor) */
+/* 21 */
+#define TEGRA210_CLK_USBD 22
+#define TEGRA210_CLK_ISP 23
+/* 24 */
+/* 25 */
+#define TEGRA210_CLK_DISP2 26
+#define TEGRA210_CLK_DISP1 27
+#define TEGRA210_CLK_HOST1X 28
+/* 29 */
+#define TEGRA210_CLK_I2S0 30
+/* 31 */
+
+#define TEGRA210_CLK_MC 32
+#define TEGRA210_CLK_AHBDMA 33
+#define TEGRA210_CLK_APBDMA 34
+/* 35 */
+/* 36 */
+/* 37 */
+#define TEGRA210_CLK_PMC 38
+/* 39 (register bit affects fuse and fuse_burn) */
+#define TEGRA210_CLK_KFUSE 40
+#define TEGRA210_CLK_SBC1 41
+/* 42 */
+/* 43 */
+#define TEGRA210_CLK_SBC2 44
+/* 45 */
+#define TEGRA210_CLK_SBC3 46
+#define TEGRA210_CLK_I2C5 47
+#define TEGRA210_CLK_DSIA 48
+/* 49 */
+/* 50 */
+/* 51 */
+#define TEGRA210_CLK_CSI 52
+/* 53 */
+#define TEGRA210_CLK_I2C2 54
+#define TEGRA210_CLK_UARTC 55
+#define TEGRA210_CLK_MIPI_CAL 56
+#define TEGRA210_CLK_EMC 57
+#define TEGRA210_CLK_USB2 58
+/* 59 */
+/* 60 */
+/* 61 */
+/* 62 */
+#define TEGRA210_CLK_BSEV 63
+
+/* 64 */
+#define TEGRA210_CLK_UARTD 65
+/* 66 */
+#define TEGRA210_CLK_I2C3 67
+#define TEGRA210_CLK_SBC4 68
+#define TEGRA210_CLK_SDMMC3 69
+#define TEGRA210_CLK_PCIE 70
+#define TEGRA210_CLK_OWR 71
+#define TEGRA210_CLK_AFI 72
+#define TEGRA210_CLK_CSITE 73
+/* 74 */
+/* 75 */
+/* 76 */
+/* 77 */
+#define TEGRA210_CLK_SOC_THERM 78
+#define TEGRA210_CLK_DTV 79
+/* 80 */
+#define TEGRA210_CLK_I2CSLOW 81
+#define TEGRA210_CLK_DSIB 82
+#define TEGRA210_CLK_TSEC 83
+/* 84 */
+/* 85 */
+/* 86 */
+/* 87 */
+/* 88 */
+#define TEGRA210_CLK_XUSB_HOST 89
+/* 90 */
+/* 91 */
+#define TEGRA210_CLK_CSUS 92
+/* 93 */
+/* 94 */
+/* 95 (bit affects xusb_dev and xusb_dev_src) */
+
+/* 96 */
+/* 97 */
+/* 98 */
+#define TEGRA210_CLK_MSELECT 99
+#define TEGRA210_CLK_TSENSOR 100
+#define TEGRA210_CLK_I2S3 101
+#define TEGRA210_CLK_I2S4 102
+#define TEGRA210_CLK_I2C4 103
+/* 104 */
+/* 105 */
+#define TEGRA210_CLK_D_AUDIO 106
+/* 107 ( affects abp -> ape) */
+/* 108 */
+/* 109 */
+/* 110 */
+#define TEGRA210_CLK_HDA2CODEC_2X 111
+/* 112 */
+/* 113 */
+/* 114 */
+/* 115 */
+/* 116 */
+/* 117 */
+#define TEGRA210_CLK_SPDIF_2X 118
+#define TEGRA210_CLK_ACTMON 119
+#define TEGRA210_CLK_EXTERN1 120
+#define TEGRA210_CLK_EXTERN2 121
+#define TEGRA210_CLK_EXTERN3 122
+#define TEGRA210_CLK_SATA_OOB 123
+#define TEGRA210_CLK_SATA 124
+#define TEGRA210_CLK_HDA 125
+/* 126 */
+/* 127 */
+
+#define TEGRA210_CLK_HDA2HDMI 128
+/* 129 */
+/* 130 */
+/* 131 */
+/* 132 */
+/* 133 */
+/* 134 */
+/* 135 */
+/* 136 */
+/* 137 */
+/* 138 */
+/* 139 */
+/* 140 */
+/* 141 */
+/* 142 */
+/* 143 (bit affects xusb_falcon_src, xusb_fs_src, */
+/* xusb_host_src and xusb_ss_src) */
+#define TEGRA210_CLK_CILAB 144
+#define TEGRA210_CLK_CILCD 145
+#define TEGRA210_CLK_CILE 146
+#define TEGRA210_CLK_DSIALP 147
+#define TEGRA210_CLK_DSIBLP 148
+#define TEGRA210_CLK_ENTROPY 149
+/* 150 */
+/* 151 */
+/* 152 */
+/* 153 */
+/* 154 */
+/* 155 (bit affects dfll_ref and dfll_soc) */
+#define TEGRA210_CLK_XUSB_SS 156
+/* 157 */
+/* 158 */
+/* 159 */
+
+/* 160 */
+#define TEGRA210_CLK_DMIC1 161
+#define TEGRA210_CLK_DMIC2 162
+/* 163 */
+/* 164 */
+/* 165 */
+#define TEGRA210_CLK_I2C6 166
+/* 167 */
+/* 168 */
+/* 169 */
+/* 170 */
+#define TEGRA210_CLK_VIM2_CLK 171
+/* 172 */
+#define TEGRA210_CLK_MIPIBIF 173
+/* 174 */
+/* 175 */
+/* 176 */
+#define TEGRA210_CLK_CLK72MHZ 177
+#define TEGRA210_CLK_VIC03 178
+/* 179 */
+/* 180 */
+#define TEGRA210_CLK_DPAUX 181
+#define TEGRA210_CLK_SOR0 182
+#define TEGRA210_CLK_SOR1 183
+#define TEGRA210_CLK_GPU 184
+#define TEGRA210_CLK_DBGAPB 185
+/* 186 */
+/* 187 */
+/* 188 */
+#define TEGRA210_CLK_PLL_G_REF 189
+/* 190 */
+/* 191 */
+
+/* 192 */
+#define TEGRA210_CLK_SDMMC_LEGACY 193
+#define TEGRA210_CLK_NVDEC 194
+#define TEGRA210_CLK_NVJPG 195
+/* 196 */
+#define TEGRA210_CLK_DMIC3 197
+#define TEGRA210_CLK_APE 198
+/* 199 */
+/* 200 */
+/* 201 */
+#define TEGRA210_CLK_MAUD 202
+/* 203 */
+/* 204 */
+/* 205 */
+#define TEGRA210_CLK_TSECB 206
+#define TEGRA210_CLK_DPAUX1 207
+#define TEGRA210_CLK_VI_I2C 208
+#define TEGRA210_CLK_HSIC_TRK 209
+#define TEGRA210_CLK_USB2_TRK 210
+#define TEGRA210_CLK_QSPI 211
+#define TEGRA210_CLK_UARTAPE 212
+/* 213 */
+/* 214 */
+/* 215 */
+/* 216 */
+/* 217 */
+/* 218 */
+#define TEGRA210_CLK_NVENC 219
+/* 220 */
+/* 221 */
+#define TEGRA210_CLK_SOR_SAFE 222
+/* 223 */
+
+
+#define TEGRA210_CLK_UARTB 224
+#define TEGRA210_CLK_VFIR 225
+#define TEGRA210_CLK_SPDIF_IN 226
+#define TEGRA210_CLK_SPDIF_OUT 227
+#define TEGRA210_CLK_VI 228
+#define TEGRA210_CLK_VI_SENSOR 229
+#define TEGRA210_CLK_FUSE 230
+#define TEGRA210_CLK_FUSE_BURN 231
+#define TEGRA210_CLK_CLK_32K 232
+#define TEGRA210_CLK_CLK_M 233
+#define TEGRA210_CLK_CLK_M_DIV2 234
+#define TEGRA210_CLK_CLK_M_DIV4 235
+#define TEGRA210_CLK_PLL_REF 236
+#define TEGRA210_CLK_PLL_C 237
+#define TEGRA210_CLK_PLL_C_OUT1 238
+#define TEGRA210_CLK_PLL_C2 239
+#define TEGRA210_CLK_PLL_C3 240
+#define TEGRA210_CLK_PLL_M 241
+#define TEGRA210_CLK_PLL_M_OUT1 242
+#define TEGRA210_CLK_PLL_P 243
+#define TEGRA210_CLK_PLL_P_OUT1 244
+#define TEGRA210_CLK_PLL_P_OUT2 245
+#define TEGRA210_CLK_PLL_P_OUT3 246
+#define TEGRA210_CLK_PLL_P_OUT4 247
+#define TEGRA210_CLK_PLL_A 248
+#define TEGRA210_CLK_PLL_A_OUT0 249
+#define TEGRA210_CLK_PLL_D 250
+#define TEGRA210_CLK_PLL_D_OUT0 251
+#define TEGRA210_CLK_PLL_D2 252
+#define TEGRA210_CLK_PLL_D2_OUT0 253
+#define TEGRA210_CLK_PLL_U 254
+#define TEGRA210_CLK_PLL_U_480M 255
+
+#define TEGRA210_CLK_PLL_U_60M 256
+#define TEGRA210_CLK_PLL_U_48M 257
+/* 258 */
+#define TEGRA210_CLK_PLL_X 259
+#define TEGRA210_CLK_PLL_X_OUT0 260
+#define TEGRA210_CLK_PLL_RE_VCO 261
+#define TEGRA210_CLK_PLL_RE_OUT 262
+#define TEGRA210_CLK_PLL_E 263
+#define TEGRA210_CLK_SPDIF_IN_SYNC 264
+#define TEGRA210_CLK_I2S0_SYNC 265
+#define TEGRA210_CLK_I2S1_SYNC 266
+#define TEGRA210_CLK_I2S2_SYNC 267
+#define TEGRA210_CLK_I2S3_SYNC 268
+#define TEGRA210_CLK_I2S4_SYNC 269
+#define TEGRA210_CLK_VIMCLK_SYNC 270
+#define TEGRA210_CLK_AUDIO0 271
+#define TEGRA210_CLK_AUDIO1 272
+#define TEGRA210_CLK_AUDIO2 273
+#define TEGRA210_CLK_AUDIO3 274
+#define TEGRA210_CLK_AUDIO4 275
+#define TEGRA210_CLK_SPDIF 276
+#define TEGRA210_CLK_CLK_OUT_1 277
+#define TEGRA210_CLK_CLK_OUT_2 278
+#define TEGRA210_CLK_CLK_OUT_3 279
+#define TEGRA210_CLK_BLINK 280
+/* 281 */
+/* 282 */
+/* 283 */
+#define TEGRA210_CLK_XUSB_HOST_SRC 284
+#define TEGRA210_CLK_XUSB_FALCON_SRC 285
+#define TEGRA210_CLK_XUSB_FS_SRC 286
+#define TEGRA210_CLK_XUSB_SS_SRC 287
+
+#define TEGRA210_CLK_XUSB_DEV_SRC 288
+#define TEGRA210_CLK_XUSB_DEV 289
+#define TEGRA210_CLK_XUSB_HS_SRC 290
+#define TEGRA210_CLK_SCLK 291
+#define TEGRA210_CLK_HCLK 292
+#define TEGRA210_CLK_PCLK 293
+#define TEGRA210_CLK_CCLK_G 294
+#define TEGRA210_CLK_CCLK_LP 295
+#define TEGRA210_CLK_DFLL_REF 296
+#define TEGRA210_CLK_DFLL_SOC 297
+#define TEGRA210_CLK_VI_SENSOR2 298
+#define TEGRA210_CLK_PLL_P_OUT5 299
+#define TEGRA210_CLK_CML0 300
+#define TEGRA210_CLK_CML1 301
+#define TEGRA210_CLK_PLL_C4 302
+#define TEGRA210_CLK_PLL_DP 303
+#define TEGRA210_CLK_PLL_E_MUX 304
+#define TEGRA210_CLK_PLL_MB 305
+#define TEGRA210_CLK_PLL_A1 306
+#define TEGRA210_CLK_PLL_D_DSI_OUT 307
+#define TEGRA210_CLK_PLL_C4_OUT0 308
+#define TEGRA210_CLK_PLL_C4_OUT1 309
+#define TEGRA210_CLK_PLL_C4_OUT2 310
+#define TEGRA210_CLK_PLL_C4_OUT3 311
+#define TEGRA210_CLK_PLL_U_OUT 312
+#define TEGRA210_CLK_PLL_U_OUT1 313
+#define TEGRA210_CLK_PLL_U_OUT2 314
+#define TEGRA210_CLK_USB2_HSIC_TRK 315
+/* 316 */
+/* 317 */
+/* 318 */
+/* 319 */
+/* 320 */
+/* 321 */
+/* 322 */
+/* 323 */
+/* 324 */
+/* 325 */
+/* 326 */
+/* 327 */
+/* 328 */
+/* 329 */
+/* 330 */
+/* 331 */
+/* 332 */
+/* 333 */
+/* 334 */
+/* 335 */
+/* 336 */
+/* 337 */
+/* 338 */
+/* 339 */
+/* 340 */
+/* 341 */
+/* 342 */
+/* 343 */
+/* 344 */
+/* 345 */
+/* 346 */
+/* 347 */
+/* 348 */
+/* 349 */
+
+#define TEGRA210_CLK_AUDIO0_MUX 350
+#define TEGRA210_CLK_AUDIO1_MUX 351
+#define TEGRA210_CLK_AUDIO2_MUX 352
+#define TEGRA210_CLK_AUDIO3_MUX 353
+#define TEGRA210_CLK_AUDIO4_MUX 354
+#define TEGRA210_CLK_SPDIF_MUX 355
+#define TEGRA210_CLK_CLK_OUT_1_MUX 356
+#define TEGRA210_CLK_CLK_OUT_2_MUX 357
+#define TEGRA210_CLK_CLK_OUT_3_MUX 358
+#define TEGRA210_CLK_DSIA_MUX 359
+#define TEGRA210_CLK_DSIB_MUX 360
+#define TEGRA210_CLK_SOR0_LVDS 361
+#define TEGRA210_CLK_XUSB_SS_DIV2 362
+
+#define TEGRA210_CLK_PLL_M_UD 363
+#define TEGRA210_CLK_PLL_C_UD 364
+#define TEGRA210_CLK_SCLK_MUX 365
+
+#define TEGRA210_CLK_CLK_MAX 366
+
+#endif /* _DT_BINDINGS_CLOCK_TEGRA210_CAR_H */
--
1.7.9.5

2015-05-12 17:26:53

by Rhyland Klein

[permalink] [raw]
Subject: [PATCH v5 21/21] clk: tegra: pll: Fix issues with rates for VCO PLLs

From: Andrew Bresticker <[email protected]>

Without this change clk_get_rate would return the final output
rather than the VCO output as it would factor in the pdiv when
it shouldn't. This will cause problems for all dividers in the
subtree of the VCO PLL.

Signed-off-by: Andrew Bresticker <[email protected]>
Signed-off-by: Rhyland Klein <[email protected]>
---
v5:
- Switched to using flag for VCO_OUT

v3:
- Added fix for this bug which was found during testing

drivers/clk/tegra/clk-pll.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 43d7ee4fb603..11d97fd559d6 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -737,6 +737,8 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
spin_lock_irqsave(pll->lock, flags);

_get_pll_mnp(pll, &old_cfg);
+ if (pll->params->flags & TEGRA_PLL_VCO_OUT)
+ cfg.p = old_cfg.p;

if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p ||
old_cfg.sdm_data != cfg.sdm_data)
@@ -796,11 +798,15 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,

_get_pll_mnp(pll, &cfg);

- pdiv = _hw_to_p_div(hw, cfg.p);
- if (pdiv < 0) {
- WARN(1, "Clock %s has invalid pdiv value : 0x%x\n",
- __clk_get_name(hw->clk), cfg.p);
+ if (pll->params->flags & TEGRA_PLL_VCO_OUT) {
pdiv = 1;
+ } else {
+ pdiv = _hw_to_p_div(hw, cfg.p);
+ if (pdiv < 0) {
+ WARN(1, "Clock %s has invalid pdiv value : 0x%x\n",
+ __clk_get_name(hw->clk), cfg.p);
+ pdiv = 1;
+ }
}

if (pll->params->set_gain)
@@ -1087,6 +1093,8 @@ static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate,
spin_lock_irqsave(pll->lock, flags);

_get_pll_mnp(pll, &old_cfg);
+ if (pll->params->flags & TEGRA_PLL_VCO_OUT)
+ cfg.p = old_cfg.p;

if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p)
ret = _program_pll(hw, &cfg, rate);
--
1.7.9.5

2015-05-12 21:52:15

by Benson Leung

[permalink] [raw]
Subject: Re: [PATCH v5 04/21] clk: tegra: pll: add tegra_pll_wait_for_lock to clk header

On Tue, May 12, 2015 at 10:23 AM, Rhyland Klein <[email protected]> wrote:
> Create a wrapper interface to make use of the existing
> clk_pll_wait_for_lock. This will be useful for implementations
> of callbacks in Tegra SoC specific clock drivers.
>
> Signed-off-by: Rhyland Klein <[email protected]>

Reviewed-by: Benson Leung <[email protected]>


--
Benson Leung
Software Engineer, Chrom* OS
[email protected]

2015-05-13 00:01:42

by Benson Leung

[permalink] [raw]
Subject: Re: [PATCH v5 10/21] clk: tegra: pll: Add logic for out-of-table rates for T210

On Tue, May 12, 2015 at 10:23 AM, Rhyland Klein <[email protected]> wrote:
> For Tegra210, the logic to calculate out-of-table rates is different
> from previous generations. Add callbacks that can be overridden to
> allow for different ways of calculating rates. Default to
> _cal_rate when not specified.
>
> This patch also includes a new flag which is used to set which method
> of fixed_mdiv calculation is used. The new method for calculating the
> fixed divider value for M can be more accurate especially when
> fractional dividers are in play. This allows for older chipsets to use
> the existing logic and new generations to use a newer version which
> may work better for them.
>
> Based on original work by Aleksandr Frid <[email protected]>
>
> Signed-off-by: Rhyland Klein <[email protected]>

Reviewed-by: Benson Leung <[email protected]>

> ---
> v5:
> - Updated description to include mentioning the NEW_MDIV flag
> - Added kerneldoc info for new members




--
Benson Leung
Software Engineer, Chrom* OS
[email protected]

2015-05-13 20:36:16

by Benson Leung

[permalink] [raw]
Subject: Re: [PATCH v5 19/21] clk: tegra: Add Super Gen5 Logic

On Tue, May 12, 2015 at 10:24 AM, Rhyland Klein <[email protected]> wrote:
> From: Bill Huang <[email protected]>
>
> Super clock divider control and clock source mux of Tegra210 has changed
> a little against prior SoCs, this patch adds Gen5 logic to address those
> differences.
>
> Signed-off-by: Bill Huang <[email protected]>

It looks like Mikko's and Thierry's EMC changes landed since you rebased :

0c1135f clk: tegra: EMC clock driver depends on EMC driver
dc9fdb6 clk: tegra: Add EMC clock driver

So v5 doesn't apply cleanly anymore. Could you rebase?

> ---
> v2:
> - Fixed sclk divider address (0x370 -> 0x2c)


--
Benson Leung
Software Engineer, Chrom* OS
[email protected]

2015-05-13 20:59:44

by Benson Leung

[permalink] [raw]
Subject: Re: [PATCH v5 12/21] clk: tegra: pll: Add specialized logic for T210

On Tue, May 12, 2015 at 10:23 AM, Rhyland Klein <[email protected]> wrote:
> On Tegra210 SoC's, the logic to enable several of the plls is different
> from previous generations. Therefore, add registeration functions specific

s/registeration/registration

> to Tegra210 which will handle them appropriately.
>
> Signed-off-by: Rhyland Klein <[email protected]>
> ---
> v5:
> - Removed unused variables.
>
> v4:
> - Fixed plle_tegra210_is_enabled callback typos
>
> v2:
> - Fixed plle logic. PLLE on Tegra210 has had its enable bit moved, so
> we can't use the default _clk_pll_enable/disable routines. Instead,
> manually set/clear the correct bit for PLLE within its functions.
>
> drivers/clk/tegra/clk-pll.c | 347 ++++++++++++++++++++++++++++++++++++++++++-
> drivers/clk/tegra/clk.h | 24 +++
> 2 files changed, 369 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
> index 54ebab2b85e5..2b1f672e3bdb 100644
> --- a/drivers/clk/tegra/clk-pll.c
> +++ b/drivers/clk/tegra/clk-pll.c
> @@ -65,6 +65,7 @@
> #define PLLE_BASE_DIVN_WIDTH 8
> #define PLLE_BASE_DIVM_SHIFT 0
> #define PLLE_BASE_DIVM_WIDTH 8
> +#define PLLE_BASE_ENABLE BIT(31)
>
> #define PLLE_MISC_SETUP_BASE_SHIFT 16
> #define PLLE_MISC_SETUP_BASE_MASK (0xffff << PLLE_MISC_SETUP_BASE_SHIFT)
> @@ -910,7 +911,8 @@ const struct clk_ops tegra_clk_plle_ops = {
>
> #if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
> defined(CONFIG_ARCH_TEGRA_124_SOC) || \
> - defined(CONFIG_ARCH_TEGRA_132_SOC)
> + defined(CONFIG_ARCH_TEGRA_132_SOC) || \
> + defined(CONFIG_ARCH_TEGRA_210_SOC)
>
> static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params,
> unsigned long parent_rate)
> @@ -1579,7 +1581,8 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
>
> #if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
> defined(CONFIG_ARCH_TEGRA_124_SOC) || \
> - defined(CONFIG_ARCH_TEGRA_132_SOC)
> + defined(CONFIG_ARCH_TEGRA_132_SOC) || \
> + defined(CONFIG_ARCH_TEGRA_210_SOC)
> static const struct clk_ops tegra_clk_pllxc_ops = {
> .is_enabled = clk_pll_is_enabled,
> .enable = clk_pll_enable,


It looks like you might have missed changing one set of #if defined
further down below to include CONFIG_ARCH_TEGRA_210_SOC :

#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
static const struct clk_ops tegra_clk_pllss_ops = {
.is_enabled = clk_pll_is_enabled,
.enable = clk_pll_enable,
.disable = clk_pll_disable,
.recalc_rate = clk_pll_recalc_rate,
.round_rate = clk_pll_ramp_round_rate,
.set_rate = clk_pllxc_set_rate,
};

struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
void __iomem *clk_base, unsigned long flags,
struct tegra_clk_pll_params *pll_params,
spinlock_t *lock)

...

#endif

--
Benson Leung
Software Engineer, Chrom* OS
[email protected]

2015-05-13 22:04:19

by Benson Leung

[permalink] [raw]
Subject: Re: [PATCH v5 13/21] clk: tegra: pll: Add support for PLLMB for T210

On Tue, May 12, 2015 at 10:23 AM, Rhyland Klein <[email protected]> wrote:
> Tegra210 SoC's have 2 PLLS for memory usage. Add plumbing to register
> and handle PLLMB.
>
> PLLMB is used to allow switching between 2 PLLM's without having to use
> and intermediate backup PLL, as we need to lock the PLL before we can
> switch to it.
>
> Signed-off-by: Rhyland Klein <[email protected]>

Reviewed-by: Benson Leung <[email protected]>


--
Benson Leung
Software Engineer, Chrom* OS
[email protected]

2015-05-13 22:12:05

by Benson Leung

[permalink] [raw]
Subject: Re: [PATCH v5 14/21] clk: tegra: pll: Adjust vco_min if SDM present

On Tue, May 12, 2015 at 10:23 AM, Rhyland Klein <[email protected]> wrote:
> From: Bill Huang <[email protected]>
>
> This code makes use of the SDM fractional divider if present to
> contrain the allowable programming range of the PLL divider register

s/contrain/constrain

> bitfields to take advantage of higher frequency granularity that can
> be induced by the SDM divider.
>
> Based on original work by Aleksandr Frid <[email protected]>
>
> Signed-off-by: Bill Huang <[email protected]>
> ---
> v5:
> - Removed whitespace change
>
> drivers/clk/tegra/clk-pll.c | 28 ++++++++++++++++++++++++++++
> drivers/clk/tegra/clk.h | 2 ++
> 2 files changed, 30 insertions(+)
>
> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
> index 1dfa1433375d..626466665dde 100644
> --- a/drivers/clk/tegra/clk-pll.c
> +++ b/drivers/clk/tegra/clk-pll.c
> @@ -1653,6 +1653,10 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
>
> pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
>
> + if (pll_params->adjust_vco)
> + pll_params->vco_min = pll_params->adjust_vco(pll_params,
> + parent_rate);
> +
> err = _setup_dynamic_ramp(pll_params, clk_base, parent_rate);
> if (err)
> return ERR_PTR(err);
> @@ -1691,6 +1695,10 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,
>
> pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
>
> + if (pll_params->adjust_vco)
> + pll_params->vco_min = pll_params->adjust_vco(pll_params,
> + parent_rate);
> +
> pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
> if (IS_ERR(pll))
> return ERR_CAST(pll);
> @@ -1747,6 +1755,10 @@ struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
>
> pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
>
> + if (pll_params->adjust_vco)
> + pll_params->vco_min = pll_params->adjust_vco(pll_params,
> + parent_rate);
> +
> pll_params->flags |= TEGRA_PLL_BYPASS;
> pll_params->flags |= TEGRA_PLLM;
> pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
> @@ -2177,6 +2189,10 @@ struct clk *tegra_clk_register_pllc_tegra210(const char *name,
>
> pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
>
> + if (pll_params->adjust_vco)
> + pll_params->vco_min = pll_params->adjust_vco(pll_params,
> + parent_rate);
> +
> pll_params->flags |= TEGRA_PLL_BYPASS;
> pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
> if (IS_ERR(pll))
> @@ -2214,6 +2230,10 @@ struct clk *tegra_clk_register_pllxc_tegra210(const char *name,
>
> pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
>
> + if (pll_params->adjust_vco)
> + pll_params->vco_min = pll_params->adjust_vco(pll_params,
> + parent_rate);
> +
> pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
> if (IS_ERR(pll))
> return ERR_CAST(pll);
> @@ -2261,6 +2281,10 @@ struct clk *tegra_clk_register_pllss_tegra210(const char *name,
>
> pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
>
> + if (pll_params->adjust_vco)
> + pll_params->vco_min = pll_params->adjust_vco(pll_params,
> + parent_rate);
> +
> /* initialize PLL to minimum rate */
>
> cfg.m = _pll_fixed_mdiv(pll_params, parent_rate);
> @@ -2325,6 +2349,10 @@ struct clk *tegra_clk_register_pllmb(const char *name, const char *parent_name,
>
> pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
>
> + if (pll_params->adjust_vco)
> + pll_params->vco_min = pll_params->adjust_vco(pll_params,
> + parent_rate);
> +
> pll_params->flags |= TEGRA_PLL_BYPASS;
> pll_params->flags |= TEGRA_PLLMB;
> pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
> index 7ee764e583f9..330729a822cf 100644
> --- a/drivers/clk/tegra/clk.h
> +++ b/drivers/clk/tegra/clk.h
> @@ -269,6 +269,8 @@ struct tegra_clk_pll_params {
> int (*calc_rate)(struct clk_hw *hw,
> struct tegra_clk_pll_freq_table *cfg,
> unsigned long rate, unsigned long parent_rate);
> + unsigned long (*adjust_vco)(struct tegra_clk_pll_params *pll_params,
> + unsigned long parent_rate);

Please add kerneldoc for this new member above.



--
Benson Leung
Software Engineer, Chrom* OS
[email protected]

2015-05-13 22:20:36

by Benson Leung

[permalink] [raw]
Subject: Re: [PATCH v5 15/21] clk: tegra: pll: Add dyn_ramp callback

On Tue, May 12, 2015 at 10:23 AM, Rhyland Klein <[email protected]> wrote:
> From: Bill Huang <[email protected]>
>
> Add a callback to the pll_params for custom dynamic ramping
> functions which can be specified per PLL.
>
> Signed-off-by: Bill Huang <[email protected]>

Modulo kerneldoc addition,
Reviewed-by: Benson Leung <[email protected]>

> ---
> drivers/clk/tegra/clk.h | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
> index 330729a822cf..a61d388364b3 100644
> --- a/drivers/clk/tegra/clk.h
> +++ b/drivers/clk/tegra/clk.h
> @@ -160,6 +160,8 @@ struct div_nmp {
>
> #define MAX_PLL_MISC_REG_COUNT 6
>
> +struct tegra_clk_pll;
> +
> /**
> * struct tegra_clk_pll_params - PLL parameters
> *
> @@ -271,6 +273,8 @@ struct tegra_clk_pll_params {
> unsigned long rate, unsigned long parent_rate);
> unsigned long (*adjust_vco)(struct tegra_clk_pll_params *pll_params,
> unsigned long parent_rate);
> + int (*dyn_ramp)(struct tegra_clk_pll *pll,
> + struct tegra_clk_pll_freq_table *cfg);

Please add kerneldoc for dyn_ramp member above.

> };
>
> #define TEGRA_PLL_USE_LOCK BIT(0)
> --
> 1.7.9.5
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html



--
Benson Leung
Software Engineer, Chrom* OS
[email protected]

2015-05-14 00:04:28

by Benson Leung

[permalink] [raw]
Subject: Re: [PATCH v5 16/21] clk: tegra: pll: Add Set_default logic

On Tue, May 12, 2015 at 10:23 AM, Rhyland Klein <[email protected]> wrote:
> From: Bill Huang <[email protected]>
>
> Add logic which (if specified for a pll) can verify that a PLL is set
> to the proper default value and if not can set it. This can be
> specified per PLL as each will have different default values.
>
> Based on original work by Aleksandr Frid <[email protected]>
>
> Signed-off-by: Bill Huang <[email protected]>
> ---
> v2:
> - Remove MACRO for PLL_MISC_CHECK_DEFAULT as suggested, and instead
> the tegra210 driver will include an inline version of this function.
>
> drivers/clk/tegra/clk-pll.c | 46 ++++++++++++++++++++++++++++++++-----------
> drivers/clk/tegra/clk.h | 2 ++
> 2 files changed, 37 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
> index 626466665dde..36aa2a95fac0 100644
> --- a/drivers/clk/tegra/clk-pll.c
> +++ b/drivers/clk/tegra/clk-pll.c
> @@ -652,13 +652,26 @@ static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
> unsigned long rate)
> {
> struct tegra_clk_pll *pll = to_clk_pll(hw);
> + struct tegra_clk_pll_freq_table old_cfg;
> int state, ret = 0;
>
> state = clk_pll_is_enabled(hw);
>
> + _get_pll_mnp(pll, &old_cfg);
> +
> + if (state && pll->params->defaults_set && pll->params->dyn_ramp &&
> + (cfg->m == old_cfg.m) && (cfg->p == old_cfg.p)) {
> + ret = pll->params->dyn_ramp(pll, cfg);
> + if (!ret)
> + return 0;
> + }
> +

This block above depends on defaults_set, but seems to be some
additional dyn_ramp logic that is different from what the commit
message describes of this patch, namely, setting defaults if
defaults_set is not true.

Could you perhaps reverse the order of this patch [16/21] and the
preceding one [15/21] clk: tegra: pll: Add dyn_ramp callback, and move
this chunk of code into the dyn_ramp patch?

> if (state)
> _clk_pll_disable(hw);
>
> + if (!pll->params->defaults_set && pll->params->set_defaults)
> + pll->params->set_defaults(pll);
> +
> _update_pll_mnp(pll, cfg);
>
> if (pll->params->flags & TEGRA_PLL_HAS_CPCON)
> @@ -1517,6 +1530,9 @@ static struct clk *_tegra_clk_register_pll(struct tegra_clk_pll *pll,
> if (!pll->params->calc_rate)
> pll->params->calc_rate = _calc_rate;
>
> + if (pll->params->set_defaults)
> + pll->params->set_defaults(pll);
> +
> /* Data in .init is copied by clk_register(), so stack variable OK */
> pll->hw.init = &init;
>
> @@ -1636,7 +1652,6 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
> struct tegra_clk_pll *pll;
> struct clk *clk, *parent;
> unsigned long parent_rate;
> - int err;
> u32 val, val_iddq;
>
> parent = __clk_lookup(parent_name);
> @@ -1657,18 +1672,27 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
> pll_params->vco_min = pll_params->adjust_vco(pll_params,
> parent_rate);
>
> - err = _setup_dynamic_ramp(pll_params, clk_base, parent_rate);
> - if (err)
> - return ERR_PTR(err);
> + /*
> + * If the pll has a set_defaults callback, it will take care of
> + * configuring dynamic ramping and setting IDDQ in that path.
> + */
> + if (!pll_params->set_defaults) {
> + int err;
>
> - val = readl_relaxed(clk_base + pll_params->base_reg);
> - val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg);
> + err = _setup_dynamic_ramp(pll_params, clk_base, parent_rate);
> + if (err)
> + return ERR_PTR(err);
>
> - if (val & PLL_BASE_ENABLE)
> - WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx));
> - else {
> - val_iddq |= BIT(pll_params->iddq_bit_idx);
> - writel_relaxed(val_iddq, clk_base + pll_params->iddq_reg);
> + val = readl_relaxed(clk_base + pll_params->base_reg);
> + val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg);
> +
> + if (val & PLL_BASE_ENABLE)
> + WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx));
> + else {
> + val_iddq |= BIT(pll_params->iddq_bit_idx);
> + writel_relaxed(val_iddq,
> + clk_base + pll_params->iddq_reg);
> + }
> }
>
> pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
> index a61d388364b3..38b4c95cfb2f 100644
> --- a/drivers/clk/tegra/clk.h
> +++ b/drivers/clk/tegra/clk.h
> @@ -261,6 +261,7 @@ struct tegra_clk_pll_params {
> int stepb_shift;
> int lock_delay;
> int max_p;
> + bool defaults_set;
> struct pdiv_map *pdiv_tohw;
> struct div_nmp *div_nmp;
> struct tegra_clk_pll_freq_table *freq_table;
> @@ -275,6 +276,7 @@ struct tegra_clk_pll_params {
> unsigned long parent_rate);
> int (*dyn_ramp)(struct tegra_clk_pll *pll,
> struct tegra_clk_pll_freq_table *cfg);
> + void (*set_defaults)(struct tegra_clk_pll *pll);

Kerneldoc for the two members, please. This is especially useful since
the two members have such similar names, but they mean different
things.



--
Benson Leung
Software Engineer, Chrom* OS
[email protected]

2015-05-14 00:25:21

by Benson Leung

[permalink] [raw]
Subject: Re: [PATCH v5 17/21] clk: tegra: pll: Add logic for SS

On Tue, May 12, 2015 at 10:24 AM, Rhyland Klein <[email protected]> wrote:
> +static void pll_clk_start_ss(struct tegra_clk_pll *pll)
> +{
> + if (pll->params->defaults_set && pll->params->ssc_ctrl_en_mask) {

Is there any reason you're checking for the existence of
ssc_ctrl_en_mask rather than ssc_ctrl_reg?

> + u32 val = pll_readl(pll->params->ssc_ctrl_reg, pll);
> +
> + val |= pll->params->ssc_ctrl_en_mask;
> + pll_writel(val, pll->params->ssc_ctrl_reg, pll);
> + }
> +}
> +
> +static void pll_clk_stop_ss(struct tegra_clk_pll *pll)
> +{
> + if (pll->params->defaults_set && pll->params->ssc_ctrl_en_mask) {
> + u32 val = pll_readl(pll->params->ssc_ctrl_reg, pll);
> +
> + val &= ~pll->params->ssc_ctrl_en_mask;
> + pll_writel(val, pll->params->ssc_ctrl_reg, pll);
> + }
> +}
> +




--
Benson Leung
Software Engineer, Chrom* OS
[email protected]

2015-05-14 00:29:53

by Benson Leung

[permalink] [raw]
Subject: Re: [PATCH v5 18/21] clk: tegra: pll: Fix _pll_ramp_calc_pll logic and _calc_dynamic_ramp_rate

On Tue, May 12, 2015 at 10:24 AM, Rhyland Klein <[email protected]> wrote:
> This removes the conversion from pdiv to hw, which is already taken
> care of by _get_table_rate before this code is run. This avoids
> incorrectly converting pdiv to hw twice and getting the wrong hw value.
>
> Also set the input_rate in the freq cfg in _calc_dynamic_ramp_rate while
> setting all the other fields.
>
> Signed-off-by: Rhyland Klein <[email protected]>


Reviewed-by: Benson Leung <[email protected]>

--
Benson Leung
Software Engineer, Chrom* OS
[email protected]

2015-05-14 19:37:27

by Benson Leung

[permalink] [raw]
Subject: Re: [PATCH v5 19/21] clk: tegra: Add Super Gen5 Logic

On Tue, May 12, 2015 at 10:24 AM, Rhyland Klein <[email protected]> wrote:
> From: Bill Huang <[email protected]>
>
> Super clock divider control and clock source mux of Tegra210 has changed
> a little against prior SoCs, this patch adds Gen5 logic to address those
> differences.
>
> Signed-off-by: Bill Huang <[email protected]>
> ---
> v2:
> - Fixed sclk divider address (0x370 -> 0x2c)
>
> drivers/clk/tegra/Makefile | 1 +
> drivers/clk/tegra/clk-tegra-super-gen5.c | 150 ++++++++++++++++++++++++++++++
> drivers/clk/tegra/clk.h | 3 +
> 3 files changed, 154 insertions(+)
> create mode 100644 drivers/clk/tegra/clk-tegra-super-gen5.c

I've diffed clk-tegra-super-gen5.c and the existing
clk-tegra-super-gen4.c, and there's a lot of code duplication here.
They're the same pair of functions, with several small changes. Since
the idea behind pulling out the super clock initialization into a
common file was to reuse the same init, could we extend the super-gen4
file (rename if you have to) to support both gens instead?

--
Benson Leung
Software Engineer, Chrom* OS
[email protected]

2015-05-14 20:03:00

by Benson Leung

[permalink] [raw]
Subject: Re: [PATCH v5 21/21] clk: tegra: pll: Fix issues with rates for VCO PLLs

On Tue, May 12, 2015 at 10:24 AM, Rhyland Klein <[email protected]> wrote:
> From: Andrew Bresticker <[email protected]>
>
> Without this change clk_get_rate would return the final output
> rather than the VCO output as it would factor in the pdiv when
> it shouldn't. This will cause problems for all dividers in the
> subtree of the VCO PLL.
>
> Signed-off-by: Andrew Bresticker <[email protected]>
> Signed-off-by: Rhyland Klein <[email protected]>

Reviewed-by: Benson Leung <[email protected]>

--
Benson Leung
Software Engineer, Chrom* OS
[email protected]

2015-05-14 20:23:19

by Benson Leung

[permalink] [raw]
Subject: Re: [PATCH v5 20/21] clk: tegra210: add support for Tegra210 clocks

On Tue, May 12, 2015 at 10:24 AM, Rhyland Klein <[email protected]> wrote:
> +static int _p_div_to_hw(struct clk_hw *hw, u8 p_div)
> +{
> + struct tegra_clk_pll *pll = to_clk_pll(hw);
> + struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
> +
> + if (p_tohw) {
> + while (p_tohw->pdiv) {
> + if (p_div <= p_tohw->pdiv)
> + return p_tohw->hw_val;
> + p_tohw++;
> + }
> + return -EINVAL;
> + }
> + return -EINVAL;
> +}

This is the same function as the one that lives in clk-pll.c. Can you
make these common?

--
Benson Leung
Software Engineer, Chrom* OS
[email protected]

2015-05-18 22:35:18

by Benson Leung

[permalink] [raw]
Subject: Re: [PATCH v5 09/21] clk: tegra: pll: Add logic for handling SDM data

On Tue, May 12, 2015 at 10:23 AM, Rhyland Klein <[email protected]> wrote:
> This adds logic for taking SDM_DIN (Sigma Delta Modulator) setting into
> the equation to calculate the effective N value for PLL which supports
> fractional divider.
>
> The effective N = NDIV + 1/2 + SDM_DIN/2^13, where NDIV is the integer
> feedback divider.
>
> Signed-off-by: Rhyland Klein <[email protected]>

Reviewed-by: Benson Leung <[email protected]>

Thanks for making the suggested changes.
> ---
> v5:
> - made use of sdm_en_mask when possible to clean up logic
> - added kerneldoc info for new struct params
> - Added info about SDM near sdm_set_data
> - rewrote check in sdm_set_data to make it clearer




--
Benson Leung
Software Engineer, Chrom* OS
[email protected]

2015-05-20 09:47:30

by Jim Lin

[permalink] [raw]
Subject: Re: [PATCH v5 20/21] clk: tegra210: add support for Tegra210 clocks

On 05/13/2015 01:24 AM, Rhyland Klein wrote:
> diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
> new file mode 100644
> index 000000000000..7f25e60e4d48
> --- /dev/null
> +++ b/drivers/clk/tegra/clk-tegra210.c
>
> +
> +static struct tegra_clk_init_table common_init_table[] __initdata = {
> + {TEGRA210_CLK_UARTA, TEGRA210_CLK_PLL_P, 408000000, 0},
> + {TEGRA210_CLK_UARTB, TEGRA210_CLK_PLL_P, 408000000, 0},
> + {TEGRA210_CLK_UARTC, TEGRA210_CLK_PLL_P, 408000000, 0},
> + {TEGRA210_CLK_UARTD, TEGRA210_CLK_PLL_P, 408000000, 0},
> + {TEGRA210_CLK_PLL_A, TEGRA210_CLK_CLK_MAX, 564480000, 1},
> + {TEGRA210_CLK_PLL_A_OUT0, TEGRA210_CLK_CLK_MAX, 11289600, 1},
> + {TEGRA210_CLK_EXTERN1, TEGRA210_CLK_PLL_A_OUT0, 0, 1},
> + {TEGRA210_CLK_CLK_OUT_1_MUX, TEGRA210_CLK_EXTERN1, 0, 1},
> + {TEGRA210_CLK_CLK_OUT_1, TEGRA210_CLK_CLK_MAX, 0, 1},
> + {TEGRA210_CLK_I2S0, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0},
> + {TEGRA210_CLK_I2S1, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0},
> + {TEGRA210_CLK_I2S2, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0},
> + {TEGRA210_CLK_I2S3, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0},
> + {TEGRA210_CLK_I2S4, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0},
> + {TEGRA210_CLK_HOST1X, TEGRA210_CLK_PLL_P, 136000000, 1},
> + {TEGRA210_CLK_SCLK_MUX, TEGRA210_CLK_PLL_P, 0, 1},
> + {TEGRA210_CLK_SCLK, TEGRA210_CLK_CLK_MAX, 102000000, 1},
> + {TEGRA210_CLK_DFLL_SOC, TEGRA210_CLK_PLL_P, 51000000, 1},
> + {TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1},
> + {TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1},
> + {TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 624000000, 0},
> + {TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 0},
> + {TEGRA210_CLK_PLL_U_OUT2, TEGRA210_CLK_CLK_MAX, 60000000, 0},
Could you help to modify this as the following?
Clocks have to be enabled only once.

+ {TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 624000000, 1},
+ {TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1},
+ {TEGRA210_CLK_PLL_U_OUT2, TEGRA210_CLK_CLK_MAX, 60000000, 1},


> + {TEGRA210_CLK_XUSB_SS_SRC, TEGRA210_CLK_PLL_U_480M, 120000000, 0},
> + {TEGRA210_CLK_XUSB_FS_SRC, TEGRA210_CLK_PLL_U_48M, 48000000, 0},
> + {TEGRA210_CLK_XUSB_HS_SRC, TEGRA210_CLK_PLL_U_60M, 60000000, 0},
> + {TEGRA210_CLK_XUSB_FALCON_SRC, TEGRA210_CLK_PLL_RE_OUT, 224000000, 0},
> + {TEGRA210_CLK_XUSB_HOST_SRC, TEGRA210_CLK_PLL_RE_OUT, 112000000, 0},
> + {TEGRA210_CLK_SATA, TEGRA210_CLK_PLL_P, 104000000, 0},
> + {TEGRA210_CLK_SATA_OOB, TEGRA210_CLK_PLL_P, 204000000, 0},
> + {TEGRA210_CLK_EMC, TEGRA210_CLK_CLK_MAX, 0, 1},
> + {TEGRA210_CLK_MSELECT, TEGRA210_CLK_CLK_MAX, 0, 1},
> + {TEGRA210_CLK_CSITE, TEGRA210_CLK_CLK_MAX, 0, 1},
> + {TEGRA210_CLK_TSENSOR, TEGRA210_CLK_CLK_M, 400000, 0},
> + {TEGRA210_CLK_I2C1, TEGRA210_CLK_PLL_P, 0, 0},
> + {TEGRA210_CLK_I2C2, TEGRA210_CLK_PLL_P, 0, 0},
> + {TEGRA210_CLK_I2C3, TEGRA210_CLK_PLL_P, 0, 0},
> + {TEGRA210_CLK_I2C4, TEGRA210_CLK_PLL_P, 0, 0},
> + {TEGRA210_CLK_I2C5, TEGRA210_CLK_PLL_P, 0, 0},
> + {TEGRA210_CLK_I2C6, TEGRA210_CLK_PLL_P, 0, 0},
> + {TEGRA210_CLK_PLL_DP, TEGRA210_CLK_CLK_MAX, 270000000, 0},
> + /* This MUST be the last entry. */
> + {TEGRA210_CLK_CLK_MAX, TEGRA210_CLK_CLK_MAX, 0, 0},
> +};
> +
--nvpublic

2015-05-20 17:16:59

by Rhyland Klein

[permalink] [raw]
Subject: Re: [PATCH v5 20/21] clk: tegra210: add support for Tegra210 clocks

On 5/20/2015 5:47 AM, Jim Lin wrote:
> On 05/13/2015 01:24 AM, Rhyland Klein wrote:
>> diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
>> new file mode 100644
>> index 000000000000..7f25e60e4d48
>> --- /dev/null
>> +++ b/drivers/clk/tegra/clk-tegra210.c
>>
>> +
>> +static struct tegra_clk_init_table common_init_table[] __initdata = {
>> + {TEGRA210_CLK_UARTA, TEGRA210_CLK_PLL_P, 408000000, 0},
>> + {TEGRA210_CLK_UARTB, TEGRA210_CLK_PLL_P, 408000000, 0},
>> + {TEGRA210_CLK_UARTC, TEGRA210_CLK_PLL_P, 408000000, 0},
>> + {TEGRA210_CLK_UARTD, TEGRA210_CLK_PLL_P, 408000000, 0},
>> + {TEGRA210_CLK_PLL_A, TEGRA210_CLK_CLK_MAX, 564480000, 1},
>> + {TEGRA210_CLK_PLL_A_OUT0, TEGRA210_CLK_CLK_MAX, 11289600, 1},
>> + {TEGRA210_CLK_EXTERN1, TEGRA210_CLK_PLL_A_OUT0, 0, 1},
>> + {TEGRA210_CLK_CLK_OUT_1_MUX, TEGRA210_CLK_EXTERN1, 0, 1},
>> + {TEGRA210_CLK_CLK_OUT_1, TEGRA210_CLK_CLK_MAX, 0, 1},
>> + {TEGRA210_CLK_I2S0, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0},
>> + {TEGRA210_CLK_I2S1, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0},
>> + {TEGRA210_CLK_I2S2, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0},
>> + {TEGRA210_CLK_I2S3, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0},
>> + {TEGRA210_CLK_I2S4, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0},
>> + {TEGRA210_CLK_HOST1X, TEGRA210_CLK_PLL_P, 136000000, 1},
>> + {TEGRA210_CLK_SCLK_MUX, TEGRA210_CLK_PLL_P, 0, 1},
>> + {TEGRA210_CLK_SCLK, TEGRA210_CLK_CLK_MAX, 102000000, 1},
>> + {TEGRA210_CLK_DFLL_SOC, TEGRA210_CLK_PLL_P, 51000000, 1},
>> + {TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1},
>> + {TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1},
>> + {TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 624000000, 0},
>> + {TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 0},
>> + {TEGRA210_CLK_PLL_U_OUT2, TEGRA210_CLK_CLK_MAX, 60000000, 0},
> Could you help to modify this as the following?
> Clocks have to be enabled only once.
>
> + {TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 624000000, 1},
> + {TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1},
> + {TEGRA210_CLK_PLL_U_OUT2, TEGRA210_CLK_CLK_MAX, 60000000, 1},
>
Yes I can merge this into v6.

-rhyland

--
nvpublic

2015-05-20 17:17:28

by Rhyland Klein

[permalink] [raw]
Subject: Re: [PATCH v5 20/21] clk: tegra210: add support for Tegra210 clocks

On 5/14/2015 4:23 PM, Benson Leung wrote:
> On Tue, May 12, 2015 at 10:24 AM, Rhyland Klein <[email protected]> wrote:
>> +static int _p_div_to_hw(struct clk_hw *hw, u8 p_div)
>> +{
>> + struct tegra_clk_pll *pll = to_clk_pll(hw);
>> + struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
>> +
>> + if (p_tohw) {
>> + while (p_tohw->pdiv) {
>> + if (p_div <= p_tohw->pdiv)
>> + return p_tohw->hw_val;
>> + p_tohw++;
>> + }
>> + return -EINVAL;
>> + }
>> + return -EINVAL;
>> +}
>
> This is the same function as the one that lives in clk-pll.c. Can you
> make these common?
>
Sure, I'll add that for v6.

-rhyland


--
nvpublic

2015-05-20 17:19:16

by Rhyland Klein

[permalink] [raw]
Subject: Re: [PATCH v5 17/21] clk: tegra: pll: Add logic for SS

On 5/13/2015 8:25 PM, Benson Leung wrote:
> On Tue, May 12, 2015 at 10:24 AM, Rhyland Klein <[email protected]> wrote:
>> +static void pll_clk_start_ss(struct tegra_clk_pll *pll)
>> +{
>> + if (pll->params->defaults_set && pll->params->ssc_ctrl_en_mask) {
>
> Is there any reason you're checking for the existence of
> ssc_ctrl_en_mask rather than ssc_ctrl_reg?

Not particularly, just a way of seeing if ssc is supported by this pll,
I will change it to check the register to be more consistent with other
checks in the code.

-rhyland

--
nvpublic

2015-05-20 17:21:09

by Rhyland Klein

[permalink] [raw]
Subject: Re: [PATCH v5 16/21] clk: tegra: pll: Add Set_default logic

On 5/13/2015 8:04 PM, Benson Leung wrote:
> On Tue, May 12, 2015 at 10:23 AM, Rhyland Klein <[email protected]> wrote:
>> From: Bill Huang <[email protected]>
>>
>> Add logic which (if specified for a pll) can verify that a PLL is set
>> to the proper default value and if not can set it. This can be
>> specified per PLL as each will have different default values.
>>
>> Based on original work by Aleksandr Frid <[email protected]>
>>
>> Signed-off-by: Bill Huang <[email protected]>
>> ---
>> v2:
>> - Remove MACRO for PLL_MISC_CHECK_DEFAULT as suggested, and instead
>> the tegra210 driver will include an inline version of this function.
>>
>> drivers/clk/tegra/clk-pll.c | 46 ++++++++++++++++++++++++++++++++-----------
>> drivers/clk/tegra/clk.h | 2 ++
>> 2 files changed, 37 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
>> index 626466665dde..36aa2a95fac0 100644
>> --- a/drivers/clk/tegra/clk-pll.c
>> +++ b/drivers/clk/tegra/clk-pll.c
>> @@ -652,13 +652,26 @@ static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
>> unsigned long rate)
>> {
>> struct tegra_clk_pll *pll = to_clk_pll(hw);
>> + struct tegra_clk_pll_freq_table old_cfg;
>> int state, ret = 0;
>>
>> state = clk_pll_is_enabled(hw);
>>
>> + _get_pll_mnp(pll, &old_cfg);
>> +
>> + if (state && pll->params->defaults_set && pll->params->dyn_ramp &&
>> + (cfg->m == old_cfg.m) && (cfg->p == old_cfg.p)) {
>> + ret = pll->params->dyn_ramp(pll, cfg);
>> + if (!ret)
>> + return 0;
>> + }
>> +
>
> This block above depends on defaults_set, but seems to be some
> additional dyn_ramp logic that is different from what the commit
> message describes of this patch, namely, setting defaults if
> defaults_set is not true.
>
> Could you perhaps reverse the order of this patch [16/21] and the
> preceding one [15/21] clk: tegra: pll: Add dyn_ramp callback, and move
> this chunk of code into the dyn_ramp patch?

Will do.

>
>> if (state)
>> _clk_pll_disable(hw);
>>
>> + if (!pll->params->defaults_set && pll->params->set_defaults)
>> + pll->params->set_defaults(pll);
>> +
>> _update_pll_mnp(pll, cfg);
>>
>> if (pll->params->flags & TEGRA_PLL_HAS_CPCON)
>> @@ -1517,6 +1530,9 @@ static struct clk *_tegra_clk_register_pll(struct tegra_clk_pll *pll,
>> if (!pll->params->calc_rate)
>> pll->params->calc_rate = _calc_rate;
>>
>> + if (pll->params->set_defaults)
>> + pll->params->set_defaults(pll);
>> +
>> /* Data in .init is copied by clk_register(), so stack variable OK */
>> pll->hw.init = &init;
>>
>> @@ -1636,7 +1652,6 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
>> struct tegra_clk_pll *pll;
>> struct clk *clk, *parent;
>> unsigned long parent_rate;
>> - int err;
>> u32 val, val_iddq;
>>
>> parent = __clk_lookup(parent_name);
>> @@ -1657,18 +1672,27 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
>> pll_params->vco_min = pll_params->adjust_vco(pll_params,
>> parent_rate);
>>
>> - err = _setup_dynamic_ramp(pll_params, clk_base, parent_rate);
>> - if (err)
>> - return ERR_PTR(err);
>> + /*
>> + * If the pll has a set_defaults callback, it will take care of
>> + * configuring dynamic ramping and setting IDDQ in that path.
>> + */
>> + if (!pll_params->set_defaults) {
>> + int err;
>>
>> - val = readl_relaxed(clk_base + pll_params->base_reg);
>> - val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg);
>> + err = _setup_dynamic_ramp(pll_params, clk_base, parent_rate);
>> + if (err)
>> + return ERR_PTR(err);
>>
>> - if (val & PLL_BASE_ENABLE)
>> - WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx));
>> - else {
>> - val_iddq |= BIT(pll_params->iddq_bit_idx);
>> - writel_relaxed(val_iddq, clk_base + pll_params->iddq_reg);
>> + val = readl_relaxed(clk_base + pll_params->base_reg);
>> + val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg);
>> +
>> + if (val & PLL_BASE_ENABLE)
>> + WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx));
>> + else {
>> + val_iddq |= BIT(pll_params->iddq_bit_idx);
>> + writel_relaxed(val_iddq,
>> + clk_base + pll_params->iddq_reg);
>> + }
>> }
>>
>> pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
>> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
>> index a61d388364b3..38b4c95cfb2f 100644
>> --- a/drivers/clk/tegra/clk.h
>> +++ b/drivers/clk/tegra/clk.h
>> @@ -261,6 +261,7 @@ struct tegra_clk_pll_params {
>> int stepb_shift;
>> int lock_delay;
>> int max_p;
>> + bool defaults_set;
>> struct pdiv_map *pdiv_tohw;
>> struct div_nmp *div_nmp;
>> struct tegra_clk_pll_freq_table *freq_table;
>> @@ -275,6 +276,7 @@ struct tegra_clk_pll_params {
>> unsigned long parent_rate);
>> int (*dyn_ramp)(struct tegra_clk_pll *pll,
>> struct tegra_clk_pll_freq_table *cfg);
>> + void (*set_defaults)(struct tegra_clk_pll *pll);
>
> Kerneldoc for the two members, please. This is especially useful since
> the two members have such similar names, but they mean different
> things.
>

Yah I thought I got all the new members, but apparently I got distracted
part way through the series and missed some. I'll double check for v6
that ALL members are kerneldoc'd.

-rhyland

--
nvpublic

2015-05-20 17:24:47

by Rhyland Klein

[permalink] [raw]
Subject: Re: [PATCH v5 12/21] clk: tegra: pll: Add specialized logic for T210

On 5/13/2015 4:59 PM, Benson Leung wrote:
> On Tue, May 12, 2015 at 10:23 AM, Rhyland Klein <[email protected]> wrote:
>> On Tegra210 SoC's, the logic to enable several of the plls is different
>> from previous generations. Therefore, add registeration functions specific
>
> s/registeration/registration
>
>> to Tegra210 which will handle them appropriately.
>>
>> Signed-off-by: Rhyland Klein <[email protected]>
>> ---
>> v5:
>> - Removed unused variables.
>>
>> v4:
>> - Fixed plle_tegra210_is_enabled callback typos
>>
>> v2:
>> - Fixed plle logic. PLLE on Tegra210 has had its enable bit moved, so
>> we can't use the default _clk_pll_enable/disable routines. Instead,
>> manually set/clear the correct bit for PLLE within its functions.
>>
>> drivers/clk/tegra/clk-pll.c | 347 ++++++++++++++++++++++++++++++++++++++++++-
>> drivers/clk/tegra/clk.h | 24 +++
>> 2 files changed, 369 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
>> index 54ebab2b85e5..2b1f672e3bdb 100644
>> --- a/drivers/clk/tegra/clk-pll.c
>> +++ b/drivers/clk/tegra/clk-pll.c
>> @@ -65,6 +65,7 @@
>> #define PLLE_BASE_DIVN_WIDTH 8
>> #define PLLE_BASE_DIVM_SHIFT 0
>> #define PLLE_BASE_DIVM_WIDTH 8
>> +#define PLLE_BASE_ENABLE BIT(31)
>>
>> #define PLLE_MISC_SETUP_BASE_SHIFT 16
>> #define PLLE_MISC_SETUP_BASE_MASK (0xffff << PLLE_MISC_SETUP_BASE_SHIFT)
>> @@ -910,7 +911,8 @@ const struct clk_ops tegra_clk_plle_ops = {
>>
>> #if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
>> defined(CONFIG_ARCH_TEGRA_124_SOC) || \
>> - defined(CONFIG_ARCH_TEGRA_132_SOC)
>> + defined(CONFIG_ARCH_TEGRA_132_SOC) || \
>> + defined(CONFIG_ARCH_TEGRA_210_SOC)
>>
>> static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params,
>> unsigned long parent_rate)
>> @@ -1579,7 +1581,8 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
>>
>> #if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
>> defined(CONFIG_ARCH_TEGRA_124_SOC) || \
>> - defined(CONFIG_ARCH_TEGRA_132_SOC)
>> + defined(CONFIG_ARCH_TEGRA_132_SOC) || \
>> + defined(CONFIG_ARCH_TEGRA_210_SOC)
>> static const struct clk_ops tegra_clk_pllxc_ops = {
>> .is_enabled = clk_pll_is_enabled,
>> .enable = clk_pll_enable,
>
>
> It looks like you might have missed changing one set of #if defined
> further down below to include CONFIG_ARCH_TEGRA_210_SOC :
>
> #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
...
> struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
...
> #endif
>

No, this was intentional. tegra_clk_register_pllss isn't used on
Tegra210, it adds its own version "register_clk_register_pllss_tegra210"
which it uses and it doesn't need the tegra_clk_pllss_ops either. So it
should be fine without this.

-rhyland

--
nvpublic

2015-05-20 17:26:21

by Benson Leung

[permalink] [raw]
Subject: Re: [PATCH v5 12/21] clk: tegra: pll: Add specialized logic for T210

On Wed, May 20, 2015 at 10:24 AM, Rhyland Klein <[email protected]> wrote:
> No, this was intentional. tegra_clk_register_pllss isn't used on
> Tegra210, it adds its own version "register_clk_register_pllss_tegra210"
> which it uses and it doesn't need the tegra_clk_pllss_ops either. So it
> should be fine without this.


Sounds good.

Reviewed-by: Benson Leung <[email protected]>

--
Benson Leung
Software Engineer, Chrom* OS
[email protected]

2015-05-25 08:20:01

by Bill Huang

[permalink] [raw]
Subject: RE: [PATCH v5 19/21] clk: tegra: Add Super Gen5 Logic


> -----Original Message-----
> From: [email protected] [mailto:[email protected]] On Behalf Of Benson
> Leung
> Sent: Friday, May 15, 2015 3:37 AM
> To: Rhyland Klein
> Cc: Peter De Schrijver; Mike Turquette; Stephen Warren; Stephen Boyd; Thierry
> Reding; Alexandre Courbot; Bill Huang; Paul Walmsley; Jim Lin; linux-
> [email protected]; [email protected]; [email protected]
> Subject: Re: [PATCH v5 19/21] clk: tegra: Add Super Gen5 Logic
>
> On Tue, May 12, 2015 at 10:24 AM, Rhyland Klein <[email protected]> wrote:
> > From: Bill Huang <[email protected]>
> >
> > Super clock divider control and clock source mux of Tegra210 has
> > changed a little against prior SoCs, this patch adds Gen5 logic to
> > address those differences.
> >
> > Signed-off-by: Bill Huang <[email protected]>
> > ---
> > v2:
> > - Fixed sclk divider address (0x370 -> 0x2c)
> >
> > drivers/clk/tegra/Makefile | 1 +
> > drivers/clk/tegra/clk-tegra-super-gen5.c | 150
> ++++++++++++++++++++++++++++++
> > drivers/clk/tegra/clk.h | 3 +
> > 3 files changed, 154 insertions(+)
> > create mode 100644 drivers/clk/tegra/clk-tegra-super-gen5.c
>
> I've diffed clk-tegra-super-gen5.c and the existing clk-tegra-super-gen4.c, and
> there's a lot of code duplication here.
> They're the same pair of functions, with several small changes. Since the idea
> behind pulling out the super clock initialization into a common file was to reuse
> the same init, could we extend the super-gen4 file (rename if you have to) to
> support both gens instead?
>
Thanks, we'll integrate gen5 into gen4 file in v6.
> --
> Benson Leung
> Software Engineer, Chrom* OS
> [email protected]
????{.n?+???????+%?????ݶ??w??{.n?+????{??G?????{ay?ʇڙ?,j??f???h?????????z_??(?階?ݢj"???m??????G????????????&???~???iO???z??v?^?m???? ????????I?

2015-06-04 18:53:06

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v5 14/21] clk: tegra: pll: Adjust vco_min if SDM present

On 05/12, Rhyland Klein wrote:
> From: Bill Huang <[email protected]>
>
> This code makes use of the SDM fractional divider if present to
> contrain the allowable programming range of the PLL divider register

s/contrain/constrain/

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project