Commit 8c88e568 authored by Stephen Boyd's avatar Stephen Boyd

Merge branches 'clk-tegra', 'clk-imx', 'clk-zynq', 'clk-socfpga', 'clk-at91'...

Merge branches 'clk-tegra', 'clk-imx', 'clk-zynq', 'clk-socfpga', 'clk-at91' and 'clk-ti' into clk-next

 - Support custom flags in Xilinx zynq firmware
 - Various small fixes to the Xilinx clk driver
 - Support for Intel Agilex clks

* clk-tegra:
  clk: tegra: Add Tegra210 CSI TPG clock gate
  clk: tegra30: Use custom CCLK implementation
  clk: tegra20: Use custom CCLK implementation
  clk: tegra: cclk: Add helpers for handling PLLX rate changes
  clk: tegra: pll: Add pre/post rate-change hooks
  clk: tegra: Add custom CCLK implementation
  clk: tegra: Remove the old emc_mux clock for Tegra210
  clk: tegra: Implement Tegra210 EMC clock
  clk: tegra: Export functions for EMC clock scaling
  clk: tegra: Add PLLP_UD and PLLMB_UD for Tegra210
  clk: tegra: Rename Tegra124 EMC clock source file
  dt-bindings: clock: tegra: Add clock ID for CSI TPG clock

* clk-imx:
  clk: imx: use imx8m_clk_hw_composite_bus for i.MX8M bus clk slice
  clk: imx: add imx8m_clk_hw_composite_bus
  clk: imx: add mux ops for i.MX8M composite clk
  clk: imx8m: migrate A53 clk root to use composite core
  clk: imx8mp: use imx8m_clk_hw_composite_core to simplify code
  clk: imx8mp: Define gates for pll1/2 fixed dividers
  clk: imx: imx8mp: fix pll mux bit
  clk: imx8m: drop clk_hw_set_parent for A53
  dt-bindings: clocks: imx8mp: Add ids for audiomix clocks
  clk: imx: Add helpers for passing the device as argument
  clk: imx: pll14xx: Add the device as argument when registering
  clk: imx: gate2: Allow single bit gating clock
  clk: imx: clk-pllv3: Use readl_relaxed_poll_timeout() for PLL lock wait
  clk: imx: clk-sscg-pll: Remove unnecessary blank lines
  clk: imx: drop the dependency on ARM64 for i.MX8M
  clk: imx7ulp: make it easy to change ARM core clk
  clk: imx: imx6ul: change flexcan clock to support CiA bitrates

* clk-zynq:
  clk: zynqmp: Make zynqmp_clk_get_max_divisor static
  clk: zynqmp: Update fraction clock check from custom type flags
  clk: zynqmp: Add support for custom type flags
  clk: zynqmp: fix memory leak in zynqmp_register_clocks
  clk: zynqmp: Fix invalid clock name queries
  clk: zynqmp: Fix divider2 calculation
  clk: zynqmp: Limit bestdiv with maxdiv

* clk-socfpga:
  clk: socfpga: agilex: add clock driver for the Agilex platform
  dt-bindings: documentation: add clock bindings information for Agilex
  clk: socfpga: add const to _ops data structures
  clk: socfpga: remove clk_ops enable/disable methods
  clk: socfpga: stratix10: use new parent data scheme

* clk-at91:
  clk: at91: allow setting all PMC clock parents via DT
  clk: at91: allow setting PCKx parent via DT
  clk: at91: optimize pmc data allocation
  clk: at91: pmc: decrement node's refcount
  clk: at91: pmc: do not continue if compatible not located
  clk: at91: Add peripheral clock for PTC

* clk-ti:
  clk: ti: dra7: remove two unused symbols
  clk: ti: dra7xx: fix RNG clock parent
  clk: ti: dra7xx: mark MCAN clock as DRA76x only
  clk: ti: dra7xx: fix gpu clkctrl parent
  clk: ti: omap5: Add proper parent clocks for l4-secure clocks
  clk: ti: omap4: Add proper parent clocks for l4-secure clocks
  clk: ti: composite: fix memory leak
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/intel,agilex.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Intel SoCFPGA Agilex platform clock controller binding
maintainers:
- Dinh Nguyen <dinguyen@kernel.org>
description:
The Intel Agilex Clock controller is an integrated clock controller, which
generates and supplies to all modules.
properties:
compatible:
const: intel,agilex-clkmgr
'#clock-cells':
const: 1
reg:
maxItems: 1
clocks:
maxItems: 1
required:
- compatible
- reg
- clocks
- '#clock-cells'
additionalProperties: false
examples:
# Clock controller node:
- |
clkmgr: clock-controller@ffd10000 {
compatible = "intel,agilex-clkmgr";
reg = <0xffd10000 0x1000>;
clocks = <&osc1>;
#clock-cells = <1>;
};
...
......@@ -104,10 +104,11 @@ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
obj-$(CONFIG_CLK_SIFIVE) += sifive/
obj-$(CONFIG_ARCH_SIRF) += sirf/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_ARCH_AGILEX) += socfpga/
obj-$(CONFIG_ARCH_STRATIX10) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/
obj-$(CONFIG_ARCH_SPRD) += sprd/
obj-$(CONFIG_ARCH_STI) += st/
obj-$(CONFIG_ARCH_STRATIX10) += socfpga/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_SUNXI_CCU) += sunxi-ng/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
......
......@@ -98,9 +98,9 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
at91rm9200_pmc = pmc_data_allocate(PMC_MAIN + 1,
at91rm9200_pmc = pmc_data_allocate(PMC_PLLBCK + 1,
nck(at91rm9200_systemck),
nck(at91rm9200_periphck), 0);
nck(at91rm9200_periphck), 0, 4);
if (!at91rm9200_pmc)
return;
......@@ -123,12 +123,16 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
at91rm9200_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_pll(regmap, "pllbck", "mainck", 1,
&at91rm9200_pll_layout,
&rm9200_pll_characteristics);
if (IS_ERR(hw))
goto err_free;
at91rm9200_pmc->chws[PMC_PLLBCK] = hw;
parent_names[0] = slowxtal_name;
parent_names[1] = "mainck";
parent_names[2] = "pllack";
......@@ -159,6 +163,8 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
&at91rm9200_programmable_layout);
if (IS_ERR(hw))
goto err_free;
at91rm9200_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(at91rm9200_systemck); i++) {
......@@ -187,7 +193,7 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(at91rm9200_pmc);
kfree(at91rm9200_pmc);
}
/*
* While the TCB can be used as the clocksource, the system timer is most likely
......
......@@ -352,9 +352,10 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
if (IS_ERR(regmap))
return;
at91sam9260_pmc = pmc_data_allocate(PMC_MAIN + 1,
at91sam9260_pmc = pmc_data_allocate(PMC_PLLBCK + 1,
ndck(data->sck, data->num_sck),
ndck(data->pck, data->num_pck), 0);
ndck(data->pck, data->num_pck),
0, data->num_progck);
if (!at91sam9260_pmc)
return;
......@@ -398,12 +399,16 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
if (IS_ERR(hw))
goto err_free;
at91sam9260_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_pll(regmap, "pllbck", "mainck", 1,
data->pllb_layout,
data->pllb_characteristics);
if (IS_ERR(hw))
goto err_free;
at91sam9260_pmc->chws[PMC_PLLBCK] = hw;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "pllack";
......@@ -434,6 +439,8 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
&at91rm9200_programmable_layout);
if (IS_ERR(hw))
goto err_free;
at91sam9260_pmc->pchws[i] = hw;
}
for (i = 0; i < data->num_sck; i++) {
......@@ -462,7 +469,7 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
return;
err_free:
pmc_data_free(at91sam9260_pmc);
kfree(at91sam9260_pmc);
}
static void __init at91sam9260_pmc_setup(struct device_node *np)
......
......@@ -115,9 +115,9 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
at91sam9g45_pmc = pmc_data_allocate(PMC_MAIN + 1,
at91sam9g45_pmc = pmc_data_allocate(PMC_PLLACK + 1,
nck(at91sam9g45_systemck),
nck(at91sam9g45_periphck), 0);
nck(at91sam9g45_periphck), 0, 2);
if (!at91sam9g45_pmc)
return;
......@@ -143,6 +143,8 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
at91sam9g45_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
......@@ -182,6 +184,8 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
&at91sam9g45_programmable_layout);
if (IS_ERR(hw))
goto err_free;
at91sam9g45_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(at91sam9g45_systemck); i++) {
......@@ -210,7 +214,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(at91sam9g45_pmc);
kfree(at91sam9g45_pmc);
}
/*
* The TCB is used as the clocksource so its clock is needed early. This means
......
......@@ -128,8 +128,8 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
at91sam9n12_pmc = pmc_data_allocate(PMC_MAIN + 1,
nck(at91sam9n12_systemck), 31, 0);
at91sam9n12_pmc = pmc_data_allocate(PMC_PLLBCK + 1,
nck(at91sam9n12_systemck), 31, 0, 2);
if (!at91sam9n12_pmc)
return;
......@@ -162,11 +162,15 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
at91sam9n12_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_pll(regmap, "pllbck", "mainck", 1,
&at91rm9200_pll_layout, &pllb_characteristics);
if (IS_ERR(hw))
goto err_free;
at91sam9n12_pmc->chws[PMC_PLLBCK] = hw;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plladivck";
......@@ -198,6 +202,8 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
&at91sam9x5_programmable_layout);
if (IS_ERR(hw))
goto err_free;
at91sam9n12_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(at91sam9n12_systemck); i++) {
......@@ -228,7 +234,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(at91sam9n12_pmc);
kfree(at91sam9n12_pmc);
}
/*
* The TCB is used as the clocksource so its clock is needed early. This means
......
......@@ -87,9 +87,9 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
at91sam9rl_pmc = pmc_data_allocate(PMC_MAIN + 1,
at91sam9rl_pmc = pmc_data_allocate(PMC_PLLACK + 1,
nck(at91sam9rl_systemck),
nck(at91sam9rl_periphck), 0);
nck(at91sam9rl_periphck), 0, 2);
if (!at91sam9rl_pmc)
return;
......@@ -105,6 +105,8 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
at91sam9rl_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
......@@ -138,6 +140,8 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
&at91rm9200_programmable_layout);
if (IS_ERR(hw))
goto err_free;
at91sam9rl_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(at91sam9rl_systemck); i++) {
......@@ -166,6 +170,6 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(at91sam9rl_pmc);
kfree(at91sam9rl_pmc);
}
CLK_OF_DECLARE_DRIVER(at91sam9rl_pmc, "atmel,at91sam9rl-pmc", at91sam9rl_pmc_setup);
......@@ -150,8 +150,8 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
if (IS_ERR(regmap))
return;
at91sam9x5_pmc = pmc_data_allocate(PMC_MAIN + 1,
nck(at91sam9x5_systemck), 31, 0);
at91sam9x5_pmc = pmc_data_allocate(PMC_PLLACK + 1,
nck(at91sam9x5_systemck), 31, 0, 2);
if (!at91sam9x5_pmc)
return;
......@@ -184,6 +184,8 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
if (IS_ERR(hw))
goto err_free;
at91sam9x5_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
......@@ -227,6 +229,8 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
&at91sam9x5_programmable_layout);
if (IS_ERR(hw))
goto err_free;
at91sam9x5_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(at91sam9x5_systemck); i++) {
......@@ -278,7 +282,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
return;
err_free:
pmc_data_free(at91sam9x5_pmc);
kfree(at91sam9x5_pmc);
}
static void __init at91sam9g15_pmc_setup(struct device_node *np)
......
......@@ -67,6 +67,10 @@ struct clk_hw *of_clk_hw_pmc_get(struct of_phandle_args *clkspec, void *data)
if (idx < pmc_data->ngck)
return pmc_data->ghws[idx];
break;
case PMC_TYPE_PROGRAMMABLE:
if (idx < pmc_data->npck)
return pmc_data->pchws[idx];
break;
default:
break;
}
......@@ -76,48 +80,34 @@ struct clk_hw *of_clk_hw_pmc_get(struct of_phandle_args *clkspec, void *data)
return ERR_PTR(-EINVAL);
}
void pmc_data_free(struct pmc_data *pmc_data)
{
kfree(pmc_data->chws);
kfree(pmc_data->shws);
kfree(pmc_data->phws);
kfree(pmc_data->ghws);
}
struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
unsigned int nperiph, unsigned int ngck)
unsigned int nperiph, unsigned int ngck,
unsigned int npck)
{
struct pmc_data *pmc_data = kzalloc(sizeof(*pmc_data), GFP_KERNEL);
unsigned int num_clks = ncore + nsystem + nperiph + ngck + npck;
struct pmc_data *pmc_data;
pmc_data = kzalloc(struct_size(pmc_data, hwtable, num_clks),
GFP_KERNEL);
if (!pmc_data)
return NULL;
pmc_data->ncore = ncore;
pmc_data->chws = kcalloc(ncore, sizeof(struct clk_hw *), GFP_KERNEL);
if (!pmc_data->chws)
goto err;
pmc_data->chws = pmc_data->hwtable;
pmc_data->nsystem = nsystem;
pmc_data->shws = kcalloc(nsystem, sizeof(struct clk_hw *), GFP_KERNEL);
if (!pmc_data->shws)
goto err;
pmc_data->shws = pmc_data->chws + ncore;
pmc_data->nperiph = nperiph;
pmc_data->phws = kcalloc(nperiph, sizeof(struct clk_hw *), GFP_KERNEL);
if (!pmc_data->phws)
goto err;
pmc_data->phws = pmc_data->shws + nsystem;
pmc_data->ngck = ngck;
pmc_data->ghws = kcalloc(ngck, sizeof(struct clk_hw *), GFP_KERNEL);
if (!pmc_data->ghws)
goto err;
pmc_data->ghws = pmc_data->phws + nperiph;
return pmc_data;
err:
pmc_data_free(pmc_data);
pmc_data->npck = npck;
pmc_data->pchws = pmc_data->ghws + ngck;
return NULL;
return pmc_data;
}
#ifdef CONFIG_PM
......@@ -274,8 +264,11 @@ static int __init pmc_register_ops(void)
struct device_node *np;
np = of_find_matching_node(NULL, sama5d2_pmc_dt_ids);
if (!np)
return -ENODEV;
pmcreg = device_node_to_regmap(np);
of_node_put(np);
if (IS_ERR(pmcreg))
return PTR_ERR(pmcreg);
......
......@@ -24,6 +24,10 @@ struct pmc_data {
struct clk_hw **phws;
unsigned int ngck;
struct clk_hw **ghws;
unsigned int npck;
struct clk_hw **pchws;
struct clk_hw *hwtable[];
};
struct clk_range {
......@@ -94,8 +98,8 @@ struct clk_pcr_layout {
#define ndck(a, s) (a[s - 1].id + 1)
#define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1)
struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
unsigned int nperiph, unsigned int ngck);
void pmc_data_free(struct pmc_data *pmc_data);
unsigned int nperiph, unsigned int ngck,
unsigned int npck);
int of_at91_get_clk_range(struct device_node *np, const char *propname,
struct clk_range *range);
......
......@@ -182,10 +182,10 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
sam9x60_pmc = pmc_data_allocate(PMC_MAIN + 1,
sam9x60_pmc = pmc_data_allocate(PMC_PLLACK + 1,
nck(sam9x60_systemck),
nck(sam9x60_periphck),
nck(sam9x60_gck));
nck(sam9x60_gck), 8);
if (!sam9x60_pmc)
return;
......@@ -214,6 +214,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
sam9x60_pmc->chws[PMC_PLLACK] = hw;
hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "upllck",
"main_osc", 1, &upll_characteristics);
if (IS_ERR(hw))
......@@ -255,6 +257,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
&sam9x60_programmable_layout);
if (IS_ERR(hw))
goto err_free;
sam9x60_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(sam9x60_systemck); i++) {
......@@ -299,7 +303,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(sam9x60_pmc);
kfree(sam9x60_pmc);
}
/* Some clks are used for a clocksource */
CLK_OF_DECLARE(sam9x60_pmc, "microchip,sam9x60-pmc", sam9x60_pmc_setup);
......@@ -89,6 +89,7 @@ static const struct {
{ .n = "i2s1_clk", .id = 55, .r = { .min = 0, .max = 83000000 }, },
{ .n = "can0_clk", .id = 56, .r = { .min = 0, .max = 83000000 }, },
{ .n = "can1_clk", .id = 57, .r = { .min = 0, .max = 83000000 }, },
{ .n = "ptc_clk", .id = 58, .r = { .min = 0, .max = 83000000 }, },
{ .n = "classd_clk", .id = 59, .r = { .min = 0, .max = 83000000 }, },
};
......@@ -166,10 +167,10 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
sama5d2_pmc = pmc_data_allocate(PMC_I2S1_MUX + 1,
sama5d2_pmc = pmc_data_allocate(PMC_AUDIOPLLCK + 1,
nck(sama5d2_systemck),
nck(sama5d2_periph32ck),
nck(sama5d2_gck));
nck(sama5d2_gck), 3);
if (!sama5d2_pmc)
return;
......@@ -202,6 +203,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_audio_pll_frac(regmap, "audiopll_fracck",
"mainck");
if (IS_ERR(hw))
......@@ -217,6 +220,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->chws[PMC_AUDIOPLLCK] = hw;
regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
if (IS_ERR(regmap_sfr))
regmap_sfr = NULL;
......@@ -267,6 +272,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
&sama5d2_programmable_layout);
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(sama5d2_systemck); i++) {
......@@ -350,6 +357,6 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(sama5d2_pmc);
kfree(sama5d2_pmc);
}
CLK_OF_DECLARE_DRIVER(sama5d2_pmc, "atmel,sama5d2-pmc", sama5d2_pmc_setup);
......@@ -125,9 +125,9 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
sama5d3_pmc = pmc_data_allocate(PMC_MAIN + 1,
sama5d3_pmc = pmc_data_allocate(PMC_PLLACK + 1,
nck(sama5d3_systemck),
nck(sama5d3_periphck), 0);
nck(sama5d3_periphck), 0, 3);
if (!sama5d3_pmc)
return;
......@@ -158,6 +158,8 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
sama5d3_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
......@@ -201,6 +203,8 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
&at91sam9x5_programmable_layout);
if (IS_ERR(hw))
goto err_free;
sama5d3_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(sama5d3_systemck); i++) {
......@@ -231,7 +235,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(sama5d3_pmc);
kfree(sama5d3_pmc);
}
/*
* The TCB is used as the clocksource so its clock is needed early. This means
......
......@@ -140,9 +140,9 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
sama5d4_pmc = pmc_data_allocate(PMC_MCK2 + 1,
sama5d4_pmc = pmc_data_allocate(PMC_PLLACK + 1,
nck(sama5d4_systemck),
nck(sama5d4_periph32ck), 0);
nck(sama5d4_periph32ck), 0, 3);
if (!sama5d4_pmc)
return;
......@@ -173,6 +173,8 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
sama5d4_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
......@@ -224,6 +226,8 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
&at91sam9x5_programmable_layout);
if (IS_ERR(hw))
goto err_free;
sama5d4_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(sama5d4_systemck); i++) {
......@@ -267,6 +271,6 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(sama5d4_pmc);
kfree(sama5d4_pmc);
}
CLK_OF_DECLARE_DRIVER(sama5d4_pmc, "atmel,sama5d4-pmc", sama5d4_pmc_setup);
......@@ -10,25 +10,25 @@ config MXC_CLK_SCU
config CLK_IMX8MM
bool "IMX8MM CCM Clock Driver"
depends on ARCH_MXC && ARM64
depends on ARCH_MXC
help
Build the driver for i.MX8MM CCM Clock Driver
config CLK_IMX8MN
bool "IMX8MN CCM Clock Driver"
depends on ARCH_MXC && ARM64
depends on ARCH_MXC
help
Build the driver for i.MX8MN CCM Clock Driver
config CLK_IMX8MP
bool "IMX8MP CCM Clock Driver"
depends on ARCH_MXC && ARM64
depends on ARCH_MXC
help
Build the driver for i.MX8MP CCM Clock Driver
config CLK_IMX8MQ
bool "IMX8MQ CCM Clock Driver"
depends on ARCH_MXC && ARM64
depends on ARCH_MXC
help
Build the driver for i.MX8MQ CCM Clock Driver
......
......@@ -124,6 +124,52 @@ static const struct clk_ops imx8m_clk_composite_divider_ops = {
.set_rate = imx8m_clk_composite_divider_set_rate,
};
static u8 imx8m_clk_composite_mux_get_parent(struct clk_hw *hw)
{
return clk_mux_ops.get_parent(hw);
}
static int imx8m_clk_composite_mux_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_mux *mux = to_clk_mux(hw);
u32 val = clk_mux_index_to_val(mux->table, mux->flags, index);
unsigned long flags = 0;
u32 reg;
if (mux->lock)
spin_lock_irqsave(mux->lock, flags);
reg = readl(mux->reg);
reg &= ~(mux->mask << mux->shift);
val = val << mux->shift;
reg |= val;
/*
* write twice to make sure non-target interface
* SEL_A/B point the same clk input.
*/
writel(reg, mux->reg);
writel(reg, mux->reg);
if (mux->lock)
spin_unlock_irqrestore(mux->lock, flags);
return 0;
}
static int
imx8m_clk_composite_mux_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
return clk_mux_ops.determine_rate(hw, req);
}
static const struct clk_ops imx8m_clk_composite_mux_ops = {
.get_parent = imx8m_clk_composite_mux_get_parent,
.set_parent = imx8m_clk_composite_mux_set_parent,
.determine_rate = imx8m_clk_composite_mux_determine_rate,
};
struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
const char * const *parent_names,
int num_parents, void __iomem *reg,
......@@ -136,6 +182,7 @@ struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
struct clk_gate *gate = NULL;
struct clk_mux *mux = NULL;
const struct clk_ops *divider_ops;
const struct clk_ops *mux_ops;
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux)
......@@ -157,10 +204,17 @@ struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
div->shift = PCG_DIV_SHIFT;
div->width = PCG_CORE_DIV_WIDTH;
divider_ops = &clk_divider_ops;
mux_ops = &imx8m_clk_composite_mux_ops;
} else if (composite_flags & IMX_COMPOSITE_BUS) {
div->shift = PCG_PREDIV_SHIFT;
div->width = PCG_PREDIV_WIDTH;
divider_ops = &imx8m_clk_composite_divider_ops;
mux_ops = &imx8m_clk_composite_mux_ops;
} else {
div->shift = PCG_PREDIV_SHIFT;
div->width = PCG_PREDIV_WIDTH;
divider_ops = &imx8m_clk_composite_divider_ops;
mux_ops = &clk_mux_ops;
}
div->lock = &imx_ccm_lock;
......@@ -176,7 +230,7 @@ struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
gate->lock = &imx_ccm_lock;
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
mux_hw, &clk_mux_ops, div_hw,
mux_hw, mux_ops, div_hw,
divider_ops, gate_hw, &clk_gate_ops, flags);
if (IS_ERR(hw))
goto fail;
......
......@@ -41,21 +41,26 @@ static int clk_gate2_enable(struct clk_hw *hw)
struct clk_gate2 *gate = to_clk_gate2(hw);
u32 reg;
unsigned long flags;
int ret = 0;
spin_lock_irqsave(gate->lock, flags);
if (gate->share_count && (*gate->share_count)++ > 0)
goto out;
reg = readl(gate->reg);
reg &= ~(3 << gate->bit_idx);
reg |= gate->cgr_val << gate->bit_idx;
writel(reg, gate->reg);
if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT) {
ret = clk_gate_ops.enable(hw);
} else {
reg = readl(gate->reg);
reg &= ~(3 << gate->bit_idx);
reg |= gate->cgr_val << gate->bit_idx;
writel(reg, gate->reg);
}
out:
spin_unlock_irqrestore(gate->lock, flags);
return 0;
return ret;
}
static void clk_gate2_disable(struct clk_hw *hw)
......@@ -73,9 +78,13 @@ static void clk_gate2_disable(struct clk_hw *hw)
goto out;
}
reg = readl(gate->reg);
reg &= ~(3 << gate->bit_idx);
writel(reg, gate->reg);
if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT) {
clk_gate_ops.disable(hw);
} else {
reg = readl(gate->reg);
reg &= ~(3 << gate->bit_idx);
writel(reg, gate->reg);
}
out:
spin_unlock_irqrestore(gate->lock, flags);
......@@ -95,6 +104,9 @@ static int clk_gate2_is_enabled(struct clk_hw *hw)
{
struct clk_gate2 *gate = to_clk_gate2(hw);
if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT)
return clk_gate_ops.is_enabled(hw);
return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx);
}
......@@ -104,6 +116,9 @@ static void clk_gate2_disable_unused(struct clk_hw *hw)
unsigned long flags;
u32 reg;
if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT)
return;
spin_lock_irqsave(gate->lock, flags);
if (!gate->share_count || *gate->share_count == 0) {
......
......@@ -503,7 +503,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clk_prepare_enable(hws[IMX6UL_CLK_USBPHY2_GATE]->clk);
}
clk_set_parent(hws[IMX6UL_CLK_CAN_SEL]->clk, hws[IMX6UL_CLK_PLL3_60M]->clk);
clk_set_parent(hws[IMX6UL_CLK_CAN_SEL]->clk, hws[IMX6UL_CLK_PLL3_80M]->clk);
if (clk_on_imx6ul())
clk_set_parent(hws[IMX6UL_CLK_SIM_PRE_SEL]->clk, hws[IMX6UL_CLK_PLL3_USB_OTG]->clk);
else if (clk_on_imx6ull())
......
......@@ -29,7 +29,7 @@ static const char * const ddr_sels[] = { "apll_pfd_sel", "dummy", "dummy", "dum
static const char * const nic_sels[] = { "firc", "ddr_clk", };
static const char * const periph_plat_sels[] = { "dummy", "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", "apll_pfd1", "apll_pfd0", "upll", };
static const char * const periph_bus_sels[] = { "dummy", "sosc_bus_clk", "dummy", "firc_bus_clk", "rosc", "nic1_bus_clk", "nic1_clk", "spll_bus_clk", };
static const char * const arm_sels[] = { "divcore", "dummy", "dummy", "hsrun_divcore", };
static const char * const arm_sels[] = { "core", "dummy", "dummy", "hsrun_core", };
/* used by sosc/sirc/firc/ddr/spll/apll dividers */
static const struct clk_div_table ulp_div_table[] = {
......@@ -121,7 +121,9 @@ static void __init imx7ulp_clk_scg1_init(struct device_node *np)
hws[IMX7ULP_CLK_DDR_SEL] = imx_clk_hw_mux_flags("ddr_sel", base + 0x30, 24, 2, ddr_sels, ARRAY_SIZE(ddr_sels), CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
hws[IMX7ULP_CLK_CORE_DIV] = imx_clk_hw_divider_flags("divcore", "scs_sel", base + 0x14, 16, 4, CLK_SET_RATE_PARENT);
hws[IMX7ULP_CLK_CORE] = imx_clk_hw_cpu("core", "divcore", hws[IMX7ULP_CLK_CORE_DIV]->clk, hws[IMX7ULP_CLK_SYS_SEL]->clk, hws[IMX7ULP_CLK_SPLL_SEL]->clk, hws[IMX7ULP_CLK_FIRC]->clk);
hws[IMX7ULP_CLK_HSRUN_CORE_DIV] = imx_clk_hw_divider_flags("hsrun_divcore", "hsrun_scs_sel", base + 0x1c, 16, 4, CLK_SET_RATE_PARENT);
hws[IMX7ULP_CLK_HSRUN_CORE] = imx_clk_hw_cpu("hsrun_core", "hsrun_divcore", hws[IMX7ULP_CLK_HSRUN_CORE_DIV]->clk, hws[IMX7ULP_CLK_HSRUN_SYS_SEL]->clk, hws[IMX7ULP_CLK_SPLL_SEL]->clk, hws[IMX7ULP_CLK_FIRC]->clk);
hws[IMX7ULP_CLK_DDR_DIV] = imx_clk_hw_divider_gate("ddr_clk", "ddr_sel", CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, base + 0x30, 0, 3,
0, ulp_div_table, &imx_ccm_lock);
......@@ -270,7 +272,7 @@ static void __init imx7ulp_clk_smc1_init(struct device_node *np)
base = of_iomap(np, 0);
WARN_ON(!base);
hws[IMX7ULP_CLK_ARM] = imx_clk_hw_mux_flags("arm", base + 0x10, 8, 2, arm_sels, ARRAY_SIZE(arm_sels), CLK_IS_CRITICAL);
hws[IMX7ULP_CLK_ARM] = imx_clk_hw_mux_flags("arm", base + 0x10, 8, 2, arm_sels, ARRAY_SIZE(arm_sels), CLK_SET_RATE_PARENT);
imx_check_clk_hws(hws, clk_data->num);
......
......@@ -416,9 +416,9 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
return PTR_ERR(base);
/* Core Slice */
hws[IMX8MM_CLK_A53_SRC] = imx_clk_hw_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mm_a53_sels, ARRAY_SIZE(imx8mm_a53_sels));
hws[IMX8MM_CLK_A53_CG] = imx_clk_hw_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28);
hws[IMX8MM_CLK_A53_DIV] = imx_clk_hw_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3);
hws[IMX8MM_CLK_A53_DIV] = imx8m_clk_hw_composite_core("arm_a53_div", imx8mm_a53_sels, base + 0x8000);
hws[IMX8MM_CLK_A53_CG] = hws[IMX8MM_CLK_A53_DIV];
hws[IMX8MM_CLK_A53_SRC] = hws[IMX8MM_CLK_A53_DIV];
hws[IMX8MM_CLK_M4_CORE] = imx8m_clk_hw_composite_core("arm_m4_core", imx8mm_m4_sels, base + 0x8080);
hws[IMX8MM_CLK_VPU_CORE] = imx8m_clk_hw_composite_core("vpu_core", imx8mm_vpu_sels, base + 0x8100);
......@@ -444,21 +444,21 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
/* BUS */
hws[IMX8MM_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mm_main_axi_sels, base + 0x8800);
hws[IMX8MM_CLK_ENET_AXI] = imx8m_clk_hw_composite("enet_axi", imx8mm_enet_axi_sels, base + 0x8880);
hws[IMX8MM_CLK_ENET_AXI] = imx8m_clk_hw_composite_bus("enet_axi", imx8mm_enet_axi_sels, base + 0x8880);
hws[IMX8MM_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite_critical("nand_usdhc_bus", imx8mm_nand_usdhc_sels, base + 0x8900);
hws[IMX8MM_CLK_VPU_BUS] = imx8m_clk_hw_composite("vpu_bus", imx8mm_vpu_bus_sels, base + 0x8980);
hws[IMX8MM_CLK_DISP_AXI] = imx8m_clk_hw_composite("disp_axi", imx8mm_disp_axi_sels, base + 0x8a00);
hws[IMX8MM_CLK_DISP_APB] = imx8m_clk_hw_composite("disp_apb", imx8mm_disp_apb_sels, base + 0x8a80);
hws[IMX8MM_CLK_DISP_RTRM] = imx8m_clk_hw_composite("disp_rtrm", imx8mm_disp_rtrm_sels, base + 0x8b00);
hws[IMX8MM_CLK_USB_BUS] = imx8m_clk_hw_composite("usb_bus", imx8mm_usb_bus_sels, base + 0x8b80);
hws[IMX8MM_CLK_GPU_AXI] = imx8m_clk_hw_composite("gpu_axi", imx8mm_gpu_axi_sels, base + 0x8c00);
hws[IMX8MM_CLK_GPU_AHB] = imx8m_clk_hw_composite("gpu_ahb", imx8mm_gpu_ahb_sels, base + 0x8c80);
hws[IMX8MM_CLK_VPU_BUS] = imx8m_clk_hw_composite_bus("vpu_bus", imx8mm_vpu_bus_sels, base + 0x8980);
hws[IMX8MM_CLK_DISP_AXI] = imx8m_clk_hw_composite_bus("disp_axi", imx8mm_disp_axi_sels, base + 0x8a00);
hws[IMX8MM_CLK_DISP_APB] = imx8m_clk_hw_composite_bus("disp_apb", imx8mm_disp_apb_sels, base + 0x8a80);
hws[IMX8MM_CLK_DISP_RTRM] = imx8m_clk_hw_composite_bus("disp_rtrm", imx8mm_disp_rtrm_sels, base + 0x8b00);
hws[IMX8MM_CLK_USB_BUS] = imx8m_clk_hw_composite_bus("usb_bus", imx8mm_usb_bus_sels, base + 0x8b80);
hws[IMX8MM_CLK_GPU_AXI] = imx8m_clk_hw_composite_bus("gpu_axi", imx8mm_gpu_axi_sels, base + 0x8c00);
hws[IMX8MM_CLK_GPU_AHB] = imx8m_clk_hw_composite_bus("gpu_ahb", imx8mm_gpu_ahb_sels, base + 0x8c80);
hws[IMX8MM_CLK_NOC] = imx8m_clk_hw_composite_critical("noc", imx8mm_noc_sels, base + 0x8d00);
hws[IMX8MM_CLK_NOC_APB] = imx8m_clk_hw_composite_critical("noc_apb", imx8mm_noc_apb_sels, base + 0x8d80);
/* AHB */
hws[IMX8MM_CLK_AHB] = imx8m_clk_hw_composite_critical("ahb", imx8mm_ahb_sels, base + 0x9000);
hws[IMX8MM_CLK_AUDIO_AHB] = imx8m_clk_hw_composite("audio_ahb", imx8mm_audio_ahb_sels, base + 0x9100);
hws[IMX8MM_CLK_AUDIO_AHB] = imx8m_clk_hw_composite_bus("audio_ahb", imx8mm_audio_ahb_sels, base + 0x9100);
/* IPG */
hws[IMX8MM_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb", base + 0x9080, 0, 1);
......@@ -614,9 +614,6 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
hws[IMX8MM_ARM_PLL_OUT]->clk,
hws[IMX8MM_CLK_A53_DIV]->clk);
clk_hw_set_parent(hws[IMX8MM_CLK_A53_SRC], hws[IMX8MM_SYS_PLL1_800M]);
clk_hw_set_parent(hws[IMX8MM_CLK_A53_CORE], hws[IMX8MM_ARM_PLL_OUT]);
imx_check_clk_hws(hws, IMX8MM_CLK_END);
ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
......
......@@ -413,9 +413,9 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
}
/* CORE */
hws[IMX8MN_CLK_A53_SRC] = imx_clk_hw_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mn_a53_sels, ARRAY_SIZE(imx8mn_a53_sels));
hws[IMX8MN_CLK_A53_CG] = imx_clk_hw_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28);
hws[IMX8MN_CLK_A53_DIV] = imx_clk_hw_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3);
hws[IMX8MN_CLK_A53_DIV] = imx8m_clk_hw_composite_core("arm_a53_div", imx8mn_a53_sels, base + 0x8000);
hws[IMX8MN_CLK_A53_SRC] = hws[IMX8MN_CLK_A53_DIV];
hws[IMX8MN_CLK_A53_CG] = hws[IMX8MN_CLK_A53_DIV];
hws[IMX8MN_CLK_GPU_CORE] = imx8m_clk_hw_composite_core("gpu_core", imx8mn_gpu_core_sels, base + 0x8180);
hws[IMX8MN_CLK_GPU_SHADER] = imx8m_clk_hw_composite_core("gpu_shader", imx8mn_gpu_shader_sels, base + 0x8200);
......@@ -432,17 +432,17 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
/* BUS */
hws[IMX8MN_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mn_main_axi_sels, base + 0x8800);
hws[IMX8MN_CLK_ENET_AXI] = imx8m_clk_hw_composite("enet_axi", imx8mn_enet_axi_sels, base + 0x8880);
hws[IMX8MN_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite("nand_usdhc_bus", imx8mn_nand_usdhc_sels, base + 0x8900);
hws[IMX8MN_CLK_DISP_AXI] = imx8m_clk_hw_composite("disp_axi", imx8mn_disp_axi_sels, base + 0x8a00);
hws[IMX8MN_CLK_DISP_APB] = imx8m_clk_hw_composite("disp_apb", imx8mn_disp_apb_sels, base + 0x8a80);
hws[IMX8MN_CLK_USB_BUS] = imx8m_clk_hw_composite("usb_bus", imx8mn_usb_bus_sels, base + 0x8b80);
hws[IMX8MN_CLK_GPU_AXI] = imx8m_clk_hw_composite("gpu_axi", imx8mn_gpu_axi_sels, base + 0x8c00);
hws[IMX8MN_CLK_GPU_AHB] = imx8m_clk_hw_composite("gpu_ahb", imx8mn_gpu_ahb_sels, base + 0x8c80);
hws[IMX8MN_CLK_ENET_AXI] = imx8m_clk_hw_composite_bus("enet_axi", imx8mn_enet_axi_sels, base + 0x8880);
hws[IMX8MN_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite_bus("nand_usdhc_bus", imx8mn_nand_usdhc_sels, base + 0x8900);
hws[IMX8MN_CLK_DISP_AXI] = imx8m_clk_hw_composite_bus("disp_axi", imx8mn_disp_axi_sels, base + 0x8a00);
hws[IMX8MN_CLK_DISP_APB] = imx8m_clk_hw_composite_bus("disp_apb", imx8mn_disp_apb_sels, base + 0x8a80);
hws[IMX8MN_CLK_USB_BUS] = imx8m_clk_hw_composite_bus("usb_bus", imx8mn_usb_bus_sels, base + 0x8b80);
hws[IMX8MN_CLK_GPU_AXI] = imx8m_clk_hw_composite_bus("gpu_axi", imx8mn_gpu_axi_sels, base + 0x8c00);
hws[IMX8MN_CLK_GPU_AHB] = imx8m_clk_hw_composite_bus("gpu_ahb", imx8mn_gpu_ahb_sels, base + 0x8c80);
hws[IMX8MN_CLK_NOC] = imx8m_clk_hw_composite_critical("noc", imx8mn_noc_sels, base + 0x8d00);
hws[IMX8MN_CLK_AHB] = imx8m_clk_hw_composite_critical("ahb", imx8mn_ahb_sels, base + 0x9000);
hws[IMX8MN_CLK_AUDIO_AHB] = imx8m_clk_hw_composite("audio_ahb", imx8mn_audio_ahb_sels, base + 0x9100);
hws[IMX8MN_CLK_AUDIO_AHB] = imx8m_clk_hw_composite_bus("audio_ahb", imx8mn_audio_ahb_sels, base + 0x9100);
hws[IMX8MN_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb", base + 0x9080, 0, 1);
hws[IMX8MN_CLK_IPG_AUDIO_ROOT] = imx_clk_hw_divider2("ipg_audio_root", "audio_ahb", base + 0x9180, 0, 1);
hws[IMX8MN_CLK_DRAM_CORE] = imx_clk_hw_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mn_dram_core_sels, ARRAY_SIZE(imx8mn_dram_core_sels), CLK_IS_CRITICAL);
......@@ -565,9 +565,6 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
hws[IMX8MN_ARM_PLL_OUT]->clk,
hws[IMX8MN_CLK_A53_DIV]->clk);
clk_hw_set_parent(hws[IMX8MN_CLK_A53_SRC], hws[IMX8MN_SYS_PLL1_800M]);
clk_hw_set_parent(hws[IMX8MN_CLK_A53_CORE], hws[IMX8MN_ARM_PLL_OUT]);
imx_check_clk_hws(hws, IMX8MN_CLK_END);
ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
......
This diff is collapsed.
......@@ -405,9 +405,9 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
return PTR_ERR(base);
/* CORE */
hws[IMX8MQ_CLK_A53_SRC] = imx_clk_hw_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mq_a53_sels, ARRAY_SIZE(imx8mq_a53_sels));
hws[IMX8MQ_CLK_A53_CG] = imx_clk_hw_gate3_flags("arm_a53_cg", "arm_a53_src", base + 0x8000, 28, CLK_IS_CRITICAL);
hws[IMX8MQ_CLK_A53_DIV] = imx_clk_hw_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3);
hws[IMX8MQ_CLK_A53_DIV] = imx8m_clk_hw_composite_core("arm_a53_div", imx8mq_a53_sels, base + 0x8000);
hws[IMX8MQ_CLK_A53_CG] = hws[IMX8MQ_CLK_A53_DIV];
hws[IMX8MQ_CLK_A53_SRC] = hws[IMX8MQ_CLK_A53_DIV];
hws[IMX8MQ_CLK_M4_CORE] = imx8m_clk_hw_composite_core("arm_m4_core", imx8mq_arm_m4_sels, base + 0x8080);
hws[IMX8MQ_CLK_VPU_CORE] = imx8m_clk_hw_composite_core("vpu_core", imx8mq_vpu_sels, base + 0x8100);
......@@ -432,22 +432,22 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
/* BUS */
hws[IMX8MQ_CLK_MAIN_AXI] = imx8m_clk_hw_composite_critical("main_axi", imx8mq_main_axi_sels, base + 0x8800);
hws[IMX8MQ_CLK_ENET_AXI] = imx8m_clk_hw_composite("enet_axi", imx8mq_enet_axi_sels, base + 0x8880);
hws[IMX8MQ_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite("nand_usdhc_bus", imx8mq_nand_usdhc_sels, base + 0x8900);
hws[IMX8MQ_CLK_VPU_BUS] = imx8m_clk_hw_composite("vpu_bus", imx8mq_vpu_bus_sels, base + 0x8980);
hws[IMX8MQ_CLK_DISP_AXI] = imx8m_clk_hw_composite("disp_axi", imx8mq_disp_axi_sels, base + 0x8a00);
hws[IMX8MQ_CLK_DISP_APB] = imx8m_clk_hw_composite("disp_apb", imx8mq_disp_apb_sels, base + 0x8a80);
hws[IMX8MQ_CLK_DISP_RTRM] = imx8m_clk_hw_composite("disp_rtrm", imx8mq_disp_rtrm_sels, base + 0x8b00);
hws[IMX8MQ_CLK_USB_BUS] = imx8m_clk_hw_composite("usb_bus", imx8mq_usb_bus_sels, base + 0x8b80);
hws[IMX8MQ_CLK_GPU_AXI] = imx8m_clk_hw_composite("gpu_axi", imx8mq_gpu_axi_sels, base + 0x8c00);
hws[IMX8MQ_CLK_GPU_AHB] = imx8m_clk_hw_composite("gpu_ahb", imx8mq_gpu_ahb_sels, base + 0x8c80);
hws[IMX8MQ_CLK_ENET_AXI] = imx8m_clk_hw_composite_bus("enet_axi", imx8mq_enet_axi_sels, base + 0x8880);
hws[IMX8MQ_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite_bus("nand_usdhc_bus", imx8mq_nand_usdhc_sels, base + 0x8900);
hws[IMX8MQ_CLK_VPU_BUS] = imx8m_clk_hw_composite_bus("vpu_bus", imx8mq_vpu_bus_sels, base + 0x8980);
hws[IMX8MQ_CLK_DISP_AXI] = imx8m_clk_hw_composite_bus("disp_axi", imx8mq_disp_axi_sels, base + 0x8a00);
hws[IMX8MQ_CLK_DISP_APB] = imx8m_clk_hw_composite_bus("disp_apb", imx8mq_disp_apb_sels, base + 0x8a80);
hws[IMX8MQ_CLK_DISP_RTRM] = imx8m_clk_hw_composite_bus("disp_rtrm", imx8mq_disp_rtrm_sels, base + 0x8b00);
hws[IMX8MQ_CLK_USB_BUS] = imx8m_clk_hw_composite_bus("usb_bus", imx8mq_usb_bus_sels, base + 0x8b80);
hws[IMX8MQ_CLK_GPU_AXI] = imx8m_clk_hw_composite_bus("gpu_axi", imx8mq_gpu_axi_sels, base + 0x8c00);
hws[IMX8MQ_CLK_GPU_AHB] = imx8m_clk_hw_composite_bus("gpu_ahb", imx8mq_gpu_ahb_sels, base + 0x8c80);
hws[IMX8MQ_CLK_NOC] = imx8m_clk_hw_composite_critical("noc", imx8mq_noc_sels, base + 0x8d00);
hws[IMX8MQ_CLK_NOC_APB] = imx8m_clk_hw_composite_critical("noc_apb", imx8mq_noc_apb_sels, base + 0x8d80);
/* AHB */
/* AHB clock is used by the AHB bus therefore marked as critical */
hws[IMX8MQ_CLK_AHB] = imx8m_clk_hw_composite_critical("ahb", imx8mq_ahb_sels, base + 0x9000);
hws[IMX8MQ_CLK_AUDIO_AHB] = imx8m_clk_hw_composite("audio_ahb", imx8mq_audio_ahb_sels, base + 0x9100);
hws[IMX8MQ_CLK_AUDIO_AHB] = imx8m_clk_hw_composite_bus("audio_ahb", imx8mq_audio_ahb_sels, base + 0x9100);
/* IPG */
hws[IMX8MQ_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb", base + 0x9080, 0, 1);
......@@ -599,9 +599,6 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
hws[IMX8MQ_ARM_PLL_OUT]->clk,
hws[IMX8MQ_CLK_A53_DIV]->clk);
clk_hw_set_parent(hws[IMX8MQ_CLK_A53_SRC], hws[IMX8MQ_SYS1_PLL_800M]);
clk_hw_set_parent(hws[IMX8MQ_CLK_A53_CORE], hws[IMX8MQ_ARM_PLL_OUT]);
imx_check_clk_hws(hws, IMX8MQ_CLK_END);
err = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
......
......@@ -378,9 +378,9 @@ static const struct clk_ops clk_pll1443x_ops = {
.set_rate = clk_pll1443x_set_rate,
};
struct clk_hw *imx_clk_hw_pll14xx(const char *name, const char *parent_name,
void __iomem *base,
const struct imx_pll14xx_clk *pll_clk)
struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
const char *parent_name, void __iomem *base,
const struct imx_pll14xx_clk *pll_clk)
{
struct clk_pll14xx *pll;
struct clk_hw *hw;
......@@ -426,7 +426,7 @@ struct clk_hw *imx_clk_hw_pll14xx(const char *name, const char *parent_name,
hw = &pll->hw;
ret = clk_hw_register(NULL, hw);
ret = clk_hw_register(dev, hw);
if (ret) {
pr_err("%s: failed to register pll %s %d\n",
__func__, name, ret);
......
......@@ -7,6 +7,7 @@
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/err.h>
......@@ -25,6 +26,8 @@
#define IMX7_ENET_PLL_POWER (0x1 << 5)
#define IMX7_DDR_PLL_POWER (0x1 << 20)
#define PLL_LOCK_TIMEOUT 10000
/**
* struct clk_pllv3 - IMX PLL clock version 3
* @clk_hw: clock source
......@@ -53,23 +56,14 @@ struct clk_pllv3 {
static int clk_pllv3_wait_lock(struct clk_pllv3 *pll)
{
unsigned long timeout = jiffies + msecs_to_jiffies(10);
u32 val = readl_relaxed(pll->base) & pll->power_bit;
/* No need to wait for lock when pll is not powered up */
if ((pll->powerup_set && !val) || (!pll->powerup_set && val))
return 0;
/* Wait for PLL to lock */
do {
if (readl_relaxed(pll->base) & BM_PLL_LOCK)
break;
if (time_after(jiffies, timeout))
break;
usleep_range(50, 500);
} while (1);
return readl_relaxed(pll->base) & BM_PLL_LOCK ? 0 : -ETIMEDOUT;
return readl_relaxed_poll_timeout(pll->base, val, val & BM_PLL_LOCK,
500, PLL_LOCK_TIMEOUT);
}
static int clk_pllv3_prepare(struct clk_hw *hw)
......
......@@ -72,7 +72,6 @@ struct clk_sscg_pll_setup {
int divr2, divf2;
int divq;
int bypass;
uint64_t vco1;
uint64_t vco2;
uint64_t fout;
......@@ -86,11 +85,8 @@ struct clk_sscg_pll_setup {
struct clk_sscg_pll {
struct clk_hw hw;
const struct clk_ops ops;
void __iomem *base;
struct clk_sscg_pll_setup setup;
u8 parent;
u8 bypass1;
u8 bypass2;
......@@ -194,7 +190,6 @@ static int clk_sscg_pll2_find_setup(struct clk_sscg_pll_setup *setup,
struct clk_sscg_pll_setup *temp_setup,
uint64_t ref)
{
int ret;
if (ref < PLL_STAGE1_MIN_FREQ || ref > PLL_STAGE1_MAX_FREQ)
......@@ -253,7 +248,6 @@ static int clk_sscg_pll1_find_setup(struct clk_sscg_pll_setup *setup,
struct clk_sscg_pll_setup *temp_setup,
uint64_t ref)
{
int ret;
if (ref < PLL_REF_MIN_FREQ || ref > PLL_REF_MAX_FREQ)
......@@ -280,7 +274,6 @@ static int clk_sscg_pll_find_setup(struct clk_sscg_pll_setup *setup,
temp_setup.fout_request = rate;
switch (try_bypass) {
case PLL_BYPASS2:
if (prate == rate) {
setup->bypass = PLL_BYPASS2;
......@@ -288,11 +281,9 @@ static int clk_sscg_pll_find_setup(struct clk_sscg_pll_setup *setup,
ret = 0;
}
break;
case PLL_BYPASS1:
ret = clk_sscg_pll2_find_setup(setup, &temp_setup, prate);
break;
case PLL_BYPASS_NONE:
ret = clk_sscg_pll1_find_setup(setup, &temp_setup, prate);
break;
......@@ -301,7 +292,6 @@ static int clk_sscg_pll_find_setup(struct clk_sscg_pll_setup *setup,
return ret;
}
static int clk_sscg_pll_is_prepared(struct clk_hw *hw)
{
struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
......
......@@ -5,6 +5,8 @@
#include <linux/spinlock.h>
#include <linux/clk-provider.h>
#define IMX_CLK_GATE2_SINGLE_BIT 1
extern spinlock_t imx_ccm_lock;
void imx_check_clocks(struct clk *clks[], unsigned int count);
......@@ -131,9 +133,9 @@ struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
#define imx_clk_pll14xx(name, parent_name, base, pll_clk) \
to_clk(imx_clk_hw_pll14xx(name, parent_name, base, pll_clk))
struct clk_hw *imx_clk_hw_pll14xx(const char *name, const char *parent_name,
void __iomem *base,
const struct imx_pll14xx_clk *pll_clk);
struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
const char *parent_name, void __iomem *base,
const struct imx_pll14xx_clk *pll_clk);
struct clk_hw *imx_clk_hw_pllv1(enum imx_pllv1_type type, const char *name,
const char *parent, void __iomem *base);
......@@ -240,6 +242,13 @@ static inline struct clk *to_clk(struct clk_hw *hw)
return hw->clk;
}
static inline struct clk_hw *imx_clk_hw_pll14xx(const char *name, const char *parent_name,
void __iomem *base,
const struct imx_pll14xx_clk *pll_clk)
{
return imx_dev_clk_hw_pll14xx(NULL, name, parent_name, base, pll_clk);
}
static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate)
{
return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate);
......@@ -310,6 +319,13 @@ static inline struct clk_hw *imx_clk_hw_gate(const char *name, const char *paren
shift, 0, &imx_ccm_lock);
}
static inline struct clk_hw *imx_dev_clk_hw_gate(struct device *dev, const char *name,
const char *parent, void __iomem *reg, u8 shift)
{
return clk_hw_register_gate(dev, name, parent, CLK_SET_RATE_PARENT, reg,
shift, 0, &imx_ccm_lock);
}
static inline struct clk_hw *imx_clk_hw_gate_dis(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
......@@ -355,6 +371,17 @@ static inline struct clk_hw *imx_clk_hw_gate2_shared2(const char *name,
&imx_ccm_lock, share_count);
}
static inline struct clk_hw *imx_dev_clk_hw_gate_shared(struct device *dev,
const char *name, const char *parent,
void __iomem *reg, u8 shift,
unsigned int *share_count)
{
return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
CLK_OPS_PARENT_ENABLE, reg, shift, 0x3,
IMX_CLK_GATE2_SINGLE_BIT,
&imx_ccm_lock, share_count);
}
static inline struct clk *imx_clk_gate2_cgr(const char *name,
const char *parent, void __iomem *reg, u8 shift, u8 cgr_val)
{
......@@ -411,6 +438,15 @@ static inline struct clk_hw *imx_clk_hw_mux(const char *name, void __iomem *reg,
width, 0, &imx_ccm_lock);
}
static inline struct clk_hw *imx_dev_clk_hw_mux(struct device *dev,
const char *name, void __iomem *reg, u8 shift,
u8 width, const char * const *parents, int num_parents)
{
return clk_hw_register_mux(dev, name, parents, num_parents,
CLK_SET_RATE_NO_REPARENT | CLK_SET_PARENT_GATE,
reg, shift, width, 0, &imx_ccm_lock);
}
static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg,
u8 shift, u8 width, const char * const *parents,
int num_parents)
......@@ -473,11 +509,25 @@ static inline struct clk_hw *imx_clk_hw_mux_flags(const char *name,
reg, shift, width, 0, &imx_ccm_lock);
}
static inline struct clk_hw *imx_dev_clk_hw_mux_flags(struct device *dev,
const char *name,
void __iomem *reg, u8 shift,
u8 width,
const char * const *parents,
int num_parents,
unsigned long flags)
{
return clk_hw_register_mux(dev, name, parents, num_parents,
flags | CLK_SET_RATE_NO_REPARENT,
reg, shift, width, 0, &imx_ccm_lock);
}
struct clk_hw *imx_clk_hw_cpu(const char *name, const char *parent_name,
struct clk *div, struct clk *mux, struct clk *pll,
struct clk *step);
#define IMX_COMPOSITE_CORE BIT(0)
#define IMX_COMPOSITE_BUS BIT(1)
struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
const char * const *parent_names,
......@@ -486,6 +536,12 @@ struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
u32 composite_flags,
unsigned long flags);
#define imx8m_clk_hw_composite_bus(name, parent_names, reg) \
imx8m_clk_hw_composite_flags(name, parent_names, \
ARRAY_SIZE(parent_names), reg, \
IMX_COMPOSITE_BUS, \
CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE)
#define imx8m_clk_hw_composite_core(name, parent_names, reg) \
imx8m_clk_hw_composite_flags(name, parent_names, \
ARRAY_SIZE(parent_names), reg, \
......
......@@ -3,3 +3,5 @@ obj-$(CONFIG_ARCH_SOCFPGA) += clk.o clk-gate.o clk-pll.o clk-periph.o
obj-$(CONFIG_ARCH_SOCFPGA) += clk-pll-a10.o clk-periph-a10.o clk-gate-a10.o
obj-$(CONFIG_ARCH_STRATIX10) += clk-s10.o
obj-$(CONFIG_ARCH_STRATIX10) += clk-pll-s10.o clk-periph-s10.o clk-gate-s10.o
obj-$(CONFIG_ARCH_AGILEX) += clk-agilex.o
obj-$(CONFIG_ARCH_AGILEX) += clk-pll-s10.o clk-periph-s10.o clk-gate-s10.o
This diff is collapsed.
......@@ -70,7 +70,6 @@ struct clk *s10_register_gate(const struct stratix10_gate_clock *clks, void __io
struct clk *clk;
struct socfpga_gate_clk *socfpga_clk;
struct clk_init_data init;
const char * const *parent_names = clks->parent_names;
const char *parent_name = clks->parent_name;
socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
......@@ -108,7 +107,9 @@ struct clk *s10_register_gate(const struct stratix10_gate_clock *clks, void __io
init.flags = clks->flags;
init.num_parents = clks->num_parents;
init.parent_names = parent_names ? parent_names : &parent_name;
init.parent_names = parent_name ? &parent_name : NULL;
if (init.parent_names == NULL)
init.parent_data = clks->parent_data;
socfpga_clk->hw.hw.init = &init;
clk = clk_register(NULL, &socfpga_clk->hw.hw);
......
......@@ -81,7 +81,6 @@ struct clk *s10_register_periph(const struct stratix10_perip_c_clock *clks,
struct clk_init_data init;
const char *name = clks->name;
const char *parent_name = clks->parent_name;
const char * const *parent_names = clks->parent_names;
periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
if (WARN_ON(!periph_clk))
......@@ -94,7 +93,9 @@ struct clk *s10_register_periph(const struct stratix10_perip_c_clock *clks,
init.flags = clks->flags;
init.num_parents = clks->num_parents;
init.parent_names = parent_names ? parent_names : &parent_name;
init.parent_names = parent_name ? &parent_name : NULL;
if (init.parent_names == NULL)
init.parent_data = clks->parent_data;
periph_clk->hw.hw.init = &init;
......@@ -114,7 +115,6 @@ struct clk *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *clks
struct clk_init_data init;
const char *name = clks->name;
const char *parent_name = clks->parent_name;
const char * const *parent_names = clks->parent_names;
periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
if (WARN_ON(!periph_clk))
......@@ -137,7 +137,9 @@ struct clk *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *clks
init.flags = clks->flags;
init.num_parents = clks->num_parents;
init.parent_names = parent_names ? parent_names : &parent_name;
init.parent_names = parent_name ? &parent_name : NULL;
if (init.parent_names == NULL)
init.parent_data = clks->parent_data;
periph_clk->hw.hw.init = &init;
......
......@@ -58,7 +58,7 @@ static u8 clk_pll_get_parent(struct clk_hw *hwclk)
CLK_MGR_PLL_CLK_SRC_MASK;
}
static struct clk_ops clk_pll_ops = {
static const struct clk_ops clk_pll_ops = {
.recalc_rate = clk_pll_recalc_rate,
.get_parent = clk_pll_get_parent,
};
......@@ -102,8 +102,6 @@ static struct clk * __init __socfpga_pll_init(struct device_node *node,
pll_clk->hw.hw.init = &init;
pll_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA;
clk_pll_ops.enable = clk_gate_ops.enable;
clk_pll_ops.disable = clk_gate_ops.disable;
clk = clk_register(NULL, &pll_clk->hw.hw);
if (WARN_ON(IS_ERR(clk))) {
......
......@@ -18,8 +18,12 @@
#define SOCFPGA_PLL_RESET_MASK 0x2
#define SOCFPGA_PLL_REFDIV_MASK 0x00003F00
#define SOCFPGA_PLL_REFDIV_SHIFT 8
#define SOCFPGA_PLL_AREFDIV_MASK 0x00000F00
#define SOCFPGA_PLL_DREFDIV_MASK 0x00003000
#define SOCFPGA_PLL_DREFDIV_SHIFT 12
#define SOCFPGA_PLL_MDIV_MASK 0xFF000000
#define SOCFPGA_PLL_MDIV_SHIFT 24
#define SOCFPGA_AGILEX_PLL_MDIV_MASK 0x000003FF
#define SWCTRLBTCLKSEL_MASK 0x200
#define SWCTRLBTCLKSEL_SHIFT 9
......@@ -27,6 +31,27 @@
#define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)
static unsigned long agilex_clk_pll_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate)
{
struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
unsigned long arefdiv, reg, mdiv;
unsigned long long vco_freq;
/* read VCO1 reg for numerator and denominator */
reg = readl(socfpgaclk->hw.reg);
arefdiv = (reg & SOCFPGA_PLL_AREFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT;
vco_freq = (unsigned long long)parent_rate / arefdiv;
/* Read mdiv and fdiv from the fdbck register */
reg = readl(socfpgaclk->hw.reg + 0x24);
mdiv = reg & SOCFPGA_AGILEX_PLL_MDIV_MASK;
vco_freq = (unsigned long long)vco_freq * mdiv;
return (unsigned long)vco_freq;
}
static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate)
{
......@@ -98,13 +123,19 @@ static int clk_pll_prepare(struct clk_hw *hwclk)
return 0;
}
static struct clk_ops clk_pll_ops = {
static const struct clk_ops agilex_clk_pll_ops = {
.recalc_rate = agilex_clk_pll_recalc_rate,
.get_parent = clk_pll_get_parent,
.prepare = clk_pll_prepare,
};
static const struct clk_ops clk_pll_ops = {
.recalc_rate = clk_pll_recalc_rate,
.get_parent = clk_pll_get_parent,
.prepare = clk_pll_prepare,
};
static struct clk_ops clk_boot_ops = {
static const struct clk_ops clk_boot_ops = {
.recalc_rate = clk_boot_clk_recalc_rate,
.get_parent = clk_boot_get_parent,
.prepare = clk_pll_prepare,
......@@ -117,7 +148,6 @@ struct clk *s10_register_pll(const struct stratix10_pll_clock *clks,
struct socfpga_pll *pll_clk;
struct clk_init_data init;
const char *name = clks->name;
const char * const *parent_names = clks->parent_names;
pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
if (WARN_ON(!pll_clk))
......@@ -134,12 +164,48 @@ struct clk *s10_register_pll(const struct stratix10_pll_clock *clks,
init.flags = clks->flags;
init.num_parents = clks->num_parents;
init.parent_names = parent_names;
init.parent_names = NULL;
init.parent_data = clks->parent_data;
pll_clk->hw.hw.init = &init;
pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;
clk = clk_register(NULL, &pll_clk->hw.hw);
if (WARN_ON(IS_ERR(clk))) {
kfree(pll_clk);
return NULL;
}
return clk;
}
struct clk *agilex_register_pll(const struct stratix10_pll_clock *clks,
void __iomem *reg)
{
struct clk *clk;
struct socfpga_pll *pll_clk;
struct clk_init_data init;
const char *name = clks->name;
pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
if (WARN_ON(!pll_clk))
return NULL;
pll_clk->hw.reg = reg + clks->offset;
if (streq(name, SOCFPGA_BOOT_CLK))
init.ops = &clk_boot_ops;
else
init.ops = &agilex_clk_pll_ops;
init.name = name;
init.flags = clks->flags;
init.num_parents = clks->num_parents;
init.parent_names = NULL;
init.parent_data = clks->parent_data;
pll_clk->hw.hw.init = &init;
pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;
clk_pll_ops.enable = clk_gate_ops.enable;
clk_pll_ops.disable = clk_gate_ops.disable;
clk = clk_register(NULL, &pll_clk->hw.hw);
if (WARN_ON(IS_ERR(clk))) {
......
......@@ -65,7 +65,7 @@ static u8 clk_pll_get_parent(struct clk_hw *hwclk)
CLK_MGR_PLL_CLK_SRC_MASK;
}
static struct clk_ops clk_pll_ops = {
static const struct clk_ops clk_pll_ops = {
.recalc_rate = clk_pll_recalc_rate,
.get_parent = clk_pll_get_parent,
};
......@@ -105,8 +105,6 @@ static __init struct clk *__socfpga_pll_init(struct device_node *node,
pll_clk->hw.hw.init = &init;
pll_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA;
clk_pll_ops.enable = clk_gate_ops.enable;
clk_pll_ops.disable = clk_gate_ops.disable;
clk = clk_register(NULL, &pll_clk->hw.hw);
if (WARN_ON(IS_ERR(clk))) {
......
......@@ -12,35 +12,137 @@
#include "stratix10-clk.h"
static const char * const pll_mux[] = { "osc1", "cb-intosc-hs-div2-clk",
"f2s-free-clk",};
static const char * const cntr_mux[] = { "main_pll", "periph_pll",
"osc1", "cb-intosc-hs-div2-clk",
"f2s-free-clk"};
static const char * const boot_mux[] = { "osc1", "cb-intosc-hs-div2-clk",};
static const char * const noc_free_mux[] = {"main_noc_base_clk",
"peri_noc_base_clk",
"osc1", "cb-intosc-hs-div2-clk",
"f2s-free-clk"};
static const char * const emaca_free_mux[] = {"peri_emaca_clk", "boot_clk"};
static const char * const emacb_free_mux[] = {"peri_emacb_clk", "boot_clk"};
static const char * const emac_ptp_free_mux[] = {"peri_emac_ptp_clk", "boot_clk"};
static const char * const gpio_db_free_mux[] = {"peri_gpio_db_clk", "boot_clk"};
static const char * const sdmmc_free_mux[] = {"main_sdmmc_clk", "boot_clk"};
static const char * const s2f_usr1_free_mux[] = {"peri_s2f_usr1_clk", "boot_clk"};
static const char * const psi_ref_free_mux[] = {"peri_psi_ref_clk", "boot_clk"};
static const char * const mpu_mux[] = { "mpu_free_clk", "boot_clk",};
static const char * const s2f_usr0_mux[] = {"f2s-free-clk", "boot_clk"};
static const char * const emac_mux[] = {"emaca_free_clk", "emacb_free_clk"};
static const char * const noc_mux[] = {"noc_free_clk", "boot_clk"};
static const char * const mpu_free_mux[] = {"main_mpu_base_clk",
"peri_mpu_base_clk",
"osc1", "cb-intosc-hs-div2-clk",
"f2s-free-clk"};
static const struct clk_parent_data pll_mux[] = {
{ .fw_name = "osc1",
.name = "osc1" },
{ .fw_name = "cb-intosc-hs-div2-clk",
.name = "cb-intosc-hs-div2-clk" },
{ .fw_name = "f2s-free-clk",
.name = "f2s-free-clk" },
};
static const struct clk_parent_data cntr_mux[] = {
{ .fw_name = "main_pll",
.name = "main_pll", },
{ .fw_name = "periph_pll",
.name = "periph_pll", },
{ .fw_name = "osc1",
.name = "osc1", },
{ .fw_name = "cb-intosc-hs-div2-clk",
.name = "cb-intosc-hs-div2-clk", },
{ .fw_name = "f2s-free-clk",
.name = "f2s-free-clk", },
};
static const struct clk_parent_data boot_mux[] = {
{ .fw_name = "osc1",
.name = "osc1" },
{ .fw_name = "cb-intosc-hs-div2-clk",
.name = "cb-intosc-hs-div2-clk" },
};
static const struct clk_parent_data noc_free_mux[] = {
{ .fw_name = "main_noc_base_clk",
.name = "main_noc_base_clk", },
{ .fw_name = "peri_noc_base_clk",
.name = "peri_noc_base_clk", },
{ .fw_name = "osc1",
.name = "osc1", },
{ .fw_name = "cb-intosc-hs-div2-clk",
.name = "cb-intosc-hs-div2-clk", },
{ .fw_name = "f2s-free-clk",
.name = "f2s-free-clk", },
};
static const struct clk_parent_data emaca_free_mux[] = {
{ .fw_name = "peri_emaca_clk",
.name = "peri_emaca_clk", },
{ .fw_name = "boot_clk",
.name = "boot_clk", },
};
static const struct clk_parent_data emacb_free_mux[] = {
{ .fw_name = "peri_emacb_clk",
.name = "peri_emacb_clk", },
{ .fw_name = "boot_clk",
.name = "boot_clk", },
};
static const struct clk_parent_data emac_ptp_free_mux[] = {
{ .fw_name = "peri_emac_ptp_clk",
.name = "peri_emac_ptp_clk", },
{ .fw_name = "boot_clk",
.name = "boot_clk", },
};
static const struct clk_parent_data gpio_db_free_mux[] = {
{ .fw_name = "peri_gpio_db_clk",
.name = "peri_gpio_db_clk", },
{ .fw_name = "boot_clk",
.name = "boot_clk", },
};
static const struct clk_parent_data sdmmc_free_mux[] = {
{ .fw_name = "main_sdmmc_clk",
.name = "main_sdmmc_clk", },
{ .fw_name = "boot_clk",
.name = "boot_clk", },
};
static const struct clk_parent_data s2f_usr1_free_mux[] = {
{ .fw_name = "peri_s2f_usr1_clk",
.name = "peri_s2f_usr1_clk", },
{ .fw_name = "boot_clk",
.name = "boot_clk", },
};
static const struct clk_parent_data psi_ref_free_mux[] = {
{ .fw_name = "peri_psi_ref_clk",
.name = "peri_psi_ref_clk", },
{ .fw_name = "boot_clk",
.name = "boot_clk", },
};
static const struct clk_parent_data mpu_mux[] = {
{ .fw_name = "mpu_free_clk",
.name = "mpu_free_clk", },
{ .fw_name = "boot_clk",
.name = "boot_clk", },
};
static const struct clk_parent_data s2f_usr0_mux[] = {
{ .fw_name = "f2s-free-clk",
.name = "f2s-free-clk", },
{ .fw_name = "boot_clk",
.name = "boot_clk", },
};
static const struct clk_parent_data emac_mux[] = {
{ .fw_name = "emaca_free_clk",
.name = "emaca_free_clk", },
{ .fw_name = "emacb_free_clk",
.name = "emacb_free_clk", },
};
static const struct clk_parent_data noc_mux[] = {
{ .fw_name = "noc_free_clk",
.name = "noc_free_clk", },
{ .fw_name = "boot_clk",
.name = "boot_clk", },
};
static const struct clk_parent_data mpu_free_mux[] = {
{ .fw_name = "main_mpu_base_clk",
.name = "main_mpu_base_clk", },
{ .fw_name = "peri_mpu_base_clk",
.name = "peri_mpu_base_clk", },
{ .fw_name = "osc1",
.name = "osc1", },
{ .fw_name = "cb-intosc-hs-div2-clk",
.name = "cb-intosc-hs-div2-clk", },
{ .fw_name = "f2s-free-clk",
.name = "f2s-free-clk", },
};
/* clocks in AO (always on) controller */
static const struct stratix10_pll_clock s10_pll_clks[] = {
......
......@@ -14,7 +14,7 @@ struct stratix10_clock_data {
struct stratix10_pll_clock {
unsigned int id;
const char *name;
const char *const *parent_names;
const struct clk_parent_data *parent_data;
u8 num_parents;
unsigned long flags;
unsigned long offset;
......@@ -24,7 +24,7 @@ struct stratix10_perip_c_clock {
unsigned int id;
const char *name;
const char *parent_name;
const char *const *parent_names;
const struct clk_parent_data *parent_data;
u8 num_parents;
unsigned long flags;
unsigned long offset;
......@@ -34,7 +34,7 @@ struct stratix10_perip_cnt_clock {
unsigned int id;
const char *name;
const char *parent_name;
const char *const *parent_names;
const struct clk_parent_data *parent_data;
u8 num_parents;
unsigned long flags;
unsigned long offset;
......@@ -47,7 +47,7 @@ struct stratix10_gate_clock {
unsigned int id;
const char *name;
const char *parent_name;
const char *const *parent_names;
const struct clk_parent_data *parent_data;
u8 num_parents;
unsigned long flags;
unsigned long gate_reg;
......@@ -62,6 +62,8 @@ struct stratix10_gate_clock {
struct clk *s10_register_pll(const struct stratix10_pll_clock *,
void __iomem *);
struct clk *agilex_register_pll(const struct stratix10_pll_clock *,
void __iomem *);
struct clk *s10_register_periph(const struct stratix10_perip_c_clock *,
void __iomem *);
struct clk *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *,
......
# SPDX-License-Identifier: GPL-2.0-only
config TEGRA_CLK_EMC
def_bool y
depends on TEGRA124_EMC
config CLK_TEGRA_BPMP
def_bool y
depends on TEGRA_BPMP
......
......@@ -13,8 +13,8 @@ obj-y += clk-super.o
obj-y += clk-tegra-audio.o
obj-y += clk-tegra-periph.o
obj-y += clk-tegra-fixed.o
obj-y += clk-tegra-super-cclk.o
obj-y += clk-tegra-super-gen4.o
obj-$(CONFIG_TEGRA_CLK_EMC) += clk-emc.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20-emc.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o
......@@ -22,8 +22,10 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra20-emc.o
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o
obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124.o
obj-$(CONFIG_TEGRA_CLK_DFLL) += clk-tegra124-dfll-fcpu.o
obj-$(CONFIG_TEGRA124_EMC) += clk-tegra124-emc.o
obj-$(CONFIG_ARCH_TEGRA_132_SOC) += clk-tegra124.o
obj-y += cvb.o
obj-$(CONFIG_ARCH_TEGRA_210_SOC) += clk-tegra210.o
obj-$(CONFIG_ARCH_TEGRA_210_SOC) += clk-tegra210-emc.o
obj-$(CONFIG_CLK_TEGRA_BPMP) += clk-bpmp.o
obj-y += clk-utils.o
......@@ -744,13 +744,19 @@ static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
state = clk_pll_is_enabled(hw);
if (state && pll->params->pre_rate_change) {
ret = pll->params->pre_rate_change();
if (WARN_ON(ret))
return ret;
}
_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;
goto done;
}
if (state) {
......@@ -772,6 +778,10 @@ static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
pll_clk_start_ss(pll);
}
done:
if (state && pll->params->post_rate_change)
pll->params->post_rate_change();
return ret;
}
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Based on clk-super.c
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* Based on older tegra20-cpufreq driver by Colin Cross <ccross@google.com>
* Copyright (C) 2010 Google, Inc.
*
* Author: Dmitry Osipenko <digetx@gmail.com>
* Copyright (C) 2019 GRATE-DRIVER project
*/
#include <linux/bits.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/types.h>
#include "clk.h"
#define PLLP_INDEX 4
#define PLLX_INDEX 8
#define SUPER_CDIV_ENB BIT(31)
static struct tegra_clk_super_mux *cclk_super;
static bool cclk_on_pllx;
static u8 cclk_super_get_parent(struct clk_hw *hw)
{
return tegra_clk_super_ops.get_parent(hw);
}
static int cclk_super_set_parent(struct clk_hw *hw, u8 index)
{
return tegra_clk_super_ops.set_parent(hw, index);
}
static int cclk_super_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
return tegra_clk_super_ops.set_rate(hw, rate, parent_rate);
}
static unsigned long cclk_super_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
if (cclk_super_get_parent(hw) == PLLX_INDEX)
return parent_rate;
return tegra_clk_super_ops.recalc_rate(hw, parent_rate);
}
static int cclk_super_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct clk_hw *pllp_hw = clk_hw_get_parent_by_index(hw, PLLP_INDEX);
struct clk_hw *pllx_hw = clk_hw_get_parent_by_index(hw, PLLX_INDEX);
struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
unsigned long pllp_rate;
long rate = req->rate;
if (WARN_ON_ONCE(!pllp_hw || !pllx_hw))
return -EINVAL;
/*
* Switch parent to PLLP for all CCLK rates that are suitable for PLLP.
* PLLX will be disabled in this case, saving some power.
*/
pllp_rate = clk_hw_get_rate(pllp_hw);
if (rate <= pllp_rate) {
if (super->flags & TEGRA20_SUPER_CLK)
rate = pllp_rate;
else
rate = tegra_clk_super_ops.round_rate(hw, rate,
&pllp_rate);
req->best_parent_rate = pllp_rate;
req->best_parent_hw = pllp_hw;
req->rate = rate;
} else {
rate = clk_hw_round_rate(pllx_hw, rate);
req->best_parent_rate = rate;
req->best_parent_hw = pllx_hw;
req->rate = rate;
}
if (WARN_ON_ONCE(rate <= 0))
return -EINVAL;
return 0;
}
static const struct clk_ops tegra_cclk_super_ops = {
.get_parent = cclk_super_get_parent,
.set_parent = cclk_super_set_parent,
.set_rate = cclk_super_set_rate,
.recalc_rate = cclk_super_recalc_rate,
.determine_rate = cclk_super_determine_rate,
};
static const struct clk_ops tegra_cclk_super_mux_ops = {
.get_parent = cclk_super_get_parent,
.set_parent = cclk_super_set_parent,
.determine_rate = cclk_super_determine_rate,
};
struct clk *tegra_clk_register_super_cclk(const char *name,
const char * const *parent_names, u8 num_parents,
unsigned long flags, void __iomem *reg, u8 clk_super_flags,
spinlock_t *lock)
{
struct tegra_clk_super_mux *super;
struct clk *clk;
struct clk_init_data init;
u32 val;
if (WARN_ON(cclk_super))
return ERR_PTR(-EBUSY);
super = kzalloc(sizeof(*super), GFP_KERNEL);
if (!super)
return ERR_PTR(-ENOMEM);
init.name = name;
init.flags = flags;
init.parent_names = parent_names;
init.num_parents = num_parents;
super->reg = reg;
super->lock = lock;
super->width = 4;
super->flags = clk_super_flags;
super->hw.init = &init;
if (super->flags & TEGRA20_SUPER_CLK) {
init.ops = &tegra_cclk_super_mux_ops;
} else {
init.ops = &tegra_cclk_super_ops;
super->frac_div.reg = reg + 4;
super->frac_div.shift = 16;
super->frac_div.width = 8;
super->frac_div.frac_width = 1;
super->frac_div.lock = lock;
super->div_ops = &tegra_clk_frac_div_ops;
}
/*
* Tegra30+ has the following CPUG clock topology:
*
* +---+ +-------+ +-+ +-+ +-+
* PLLP+->+ +->+DIVIDER+->+0| +-------->+0| ------------->+0|
* | | +-------+ | | | +---+ | | | | |
* PLLC+->+MUX| | +->+ | S | | +->+ | +->+CPU
* ... | | | | | | K | | | | +-------+ | |
* PLLX+->+-->+------------>+1| +->+ I +->+1| +->+ DIV2 +->+1|
* +---+ +++ | P | +++ |SKIPPER| +++
* ^ | P | ^ +-------+ ^
* | | E | | |
* PLLX_SEL+--+ | R | | OVERHEAT+--+
* +---+ |
* |
* SUPER_CDIV_ENB+--+
*
* Tegra20 is similar, but simpler. It doesn't have the divider and
* thermal DIV2 skipper.
*
* At least for now we're not going to use clock-skipper, hence let's
* ensure that it is disabled.
*/
val = readl_relaxed(reg + 4);
val &= ~SUPER_CDIV_ENB;
writel_relaxed(val, reg + 4);
clk = clk_register(NULL, &super->hw);
if (IS_ERR(clk))
kfree(super);
else
cclk_super = super;
return clk;
}
int tegra_cclk_pre_pllx_rate_change(void)
{
if (IS_ERR_OR_NULL(cclk_super))
return -EINVAL;
if (cclk_super_get_parent(&cclk_super->hw) == PLLX_INDEX)
cclk_on_pllx = true;
else
cclk_on_pllx = false;
/*
* CPU needs to be temporarily re-parented away from PLLX if PLLX
* changes its rate. PLLP is a safe parent for CPU on all Tegra SoCs.
*/
if (cclk_on_pllx)
cclk_super_set_parent(&cclk_super->hw, PLLP_INDEX);
return 0;
}
void tegra_cclk_post_pllx_rate_change(void)
{
if (cclk_on_pllx)
cclk_super_set_parent(&cclk_super->hw, PLLX_INDEX);
}
......@@ -391,6 +391,8 @@ 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_HAS_LOCK_ENABLE,
.pre_rate_change = tegra_cclk_pre_pllx_rate_change,
.post_rate_change = tegra_cclk_post_pllx_rate_change,
};
static struct tegra_clk_pll_params pll_e_params = {
......@@ -702,9 +704,10 @@ static void tegra20_super_clk_init(void)
struct clk *clk;
/* CCLK */
clk = tegra_clk_register_super_mux("cclk", cclk_parents,
clk = tegra_clk_register_super_cclk("cclk", cclk_parents,
ARRAY_SIZE(cclk_parents), CLK_SET_RATE_PARENT,
clk_base + CCLK_BURST_POLICY, 0, 4, 0, 0, NULL);
clk_base + CCLK_BURST_POLICY, TEGRA20_SUPER_CLK,
NULL);
clks[TEGRA20_CLK_CCLK] = clk;
/* SCLK */
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2015-2020, NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clk/tegra.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/slab.h>
#define CLK_SOURCE_EMC 0x19c
#define CLK_SOURCE_EMC_2X_CLK_SRC GENMASK(31, 29)
#define CLK_SOURCE_EMC_MC_EMC_SAME_FREQ BIT(16)
#define CLK_SOURCE_EMC_2X_CLK_DIVISOR GENMASK(7, 0)
#define CLK_SRC_PLLM 0
#define CLK_SRC_PLLC 1
#define CLK_SRC_PLLP 2
#define CLK_SRC_CLK_M 3
#define CLK_SRC_PLLM_UD 4
#define CLK_SRC_PLLMB_UD 5
#define CLK_SRC_PLLMB 6
#define CLK_SRC_PLLP_UD 7
struct tegra210_clk_emc {
struct clk_hw hw;
void __iomem *regs;
struct tegra210_clk_emc_provider *provider;
struct clk *parents[8];
};
static inline struct tegra210_clk_emc *
to_tegra210_clk_emc(struct clk_hw *hw)
{
return container_of(hw, struct tegra210_clk_emc, hw);
}
static const char *tegra210_clk_emc_parents[] = {
"pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_mb_ud",
"pll_mb", "pll_p_ud",
};
static u8 tegra210_clk_emc_get_parent(struct clk_hw *hw)
{
struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw);
u32 value;
u8 src;
value = readl_relaxed(emc->regs + CLK_SOURCE_EMC);
src = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_SRC, value);
return src;
}
static unsigned long tegra210_clk_emc_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw);
u32 value, div;
/*
* CCF assumes that neither the parent nor its rate will change during
* ->set_rate(), so the parent rate passed in here was cached from the
* parent before the ->set_rate() call.
*
* This can lead to wrong results being reported for the EMC clock if
* the parent and/or parent rate have changed as part of the EMC rate
* change sequence. Fix this by overriding the parent clock with what
* we know to be the correct value after the rate change.
*/
parent_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
value = readl_relaxed(emc->regs + CLK_SOURCE_EMC);
div = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_DIVISOR, value);
div += 2;
return DIV_ROUND_UP(parent_rate * 2, div);
}
static long tegra210_clk_emc_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw);
struct tegra210_clk_emc_provider *provider = emc->provider;
unsigned int i;
if (!provider || !provider->configs || provider->num_configs == 0)
return clk_hw_get_rate(hw);
for (i = 0; i < provider->num_configs; i++) {
if (provider->configs[i].rate >= rate)
return provider->configs[i].rate;
}
return provider->configs[i - 1].rate;
}
static struct clk *tegra210_clk_emc_find_parent(struct tegra210_clk_emc *emc,
u8 index)
{
struct clk_hw *parent = clk_hw_get_parent_by_index(&emc->hw, index);
const char *name = clk_hw_get_name(parent);
/* XXX implement cache? */
return __clk_lookup(name);
}
static int tegra210_clk_emc_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw);
struct tegra210_clk_emc_provider *provider = emc->provider;
struct tegra210_clk_emc_config *config;
struct device *dev = provider->dev;
struct clk_hw *old, *new, *parent;
u8 old_idx, new_idx, index;
struct clk *clk;
unsigned int i;
int err;
if (!provider || !provider->configs || provider->num_configs == 0)
return -EINVAL;
for (i = 0; i < provider->num_configs; i++) {
if (provider->configs[i].rate >= rate) {
config = &provider->configs[i];
break;
}
}
if (i == provider->num_configs)
config = &provider->configs[i - 1];
old_idx = tegra210_clk_emc_get_parent(hw);
new_idx = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_SRC, config->value);
old = clk_hw_get_parent_by_index(hw, old_idx);
new = clk_hw_get_parent_by_index(hw, new_idx);
/* if the rate has changed... */
if (config->parent_rate != clk_hw_get_rate(old)) {
/* ... but the clock source remains the same ... */
if (new_idx == old_idx) {
/* ... switch to the alternative clock source. */
switch (new_idx) {
case CLK_SRC_PLLM:
new_idx = CLK_SRC_PLLMB;
break;
case CLK_SRC_PLLM_UD:
new_idx = CLK_SRC_PLLMB_UD;
break;
case CLK_SRC_PLLMB_UD:
new_idx = CLK_SRC_PLLM_UD;
break;
case CLK_SRC_PLLMB:
new_idx = CLK_SRC_PLLM;
break;
}
/*
* This should never happen because we can't deal with
* it.
*/
if (WARN_ON(new_idx == old_idx))
return -EINVAL;
new = clk_hw_get_parent_by_index(hw, new_idx);
}
index = new_idx;
parent = new;
} else {
index = old_idx;
parent = old;
}
clk = tegra210_clk_emc_find_parent(emc, index);
if (IS_ERR(clk)) {
err = PTR_ERR(clk);
dev_err(dev, "failed to get parent clock for index %u: %d\n",
index, err);
return err;
}
/* set the new parent clock to the required rate */
if (clk_get_rate(clk) != config->parent_rate) {
err = clk_set_rate(clk, config->parent_rate);
if (err < 0) {
dev_err(dev, "failed to set rate %lu Hz for %pC: %d\n",
config->parent_rate, clk, err);
return err;
}
}
/* enable the new parent clock */
if (parent != old) {
err = clk_prepare_enable(clk);
if (err < 0) {
dev_err(dev, "failed to enable parent clock %pC: %d\n",
clk, err);
return err;
}
}
/* update the EMC source configuration to reflect the new parent */
config->value &= ~CLK_SOURCE_EMC_2X_CLK_SRC;
config->value |= FIELD_PREP(CLK_SOURCE_EMC_2X_CLK_SRC, index);
/*
* Finally, switch the EMC programming with both old and new parent
* clocks enabled.
*/
err = provider->set_rate(dev, config);
if (err < 0) {
dev_err(dev, "failed to set EMC rate to %lu Hz: %d\n", rate,
err);
/*
* If we're unable to switch to the new EMC frequency, we no
* longer need the new parent to be enabled.
*/
if (parent != old)
clk_disable_unprepare(clk);
return err;
}
/* reparent to new parent clock and disable the old parent clock */
if (parent != old) {
clk = tegra210_clk_emc_find_parent(emc, old_idx);
if (IS_ERR(clk)) {
err = PTR_ERR(clk);
dev_err(dev,
"failed to get parent clock for index %u: %d\n",
old_idx, err);
return err;
}
clk_hw_reparent(hw, parent);
clk_disable_unprepare(clk);
}
return err;
}
static const struct clk_ops tegra210_clk_emc_ops = {
.get_parent = tegra210_clk_emc_get_parent,
.recalc_rate = tegra210_clk_emc_recalc_rate,
.round_rate = tegra210_clk_emc_round_rate,
.set_rate = tegra210_clk_emc_set_rate,
};
struct clk *tegra210_clk_register_emc(struct device_node *np,
void __iomem *regs)
{
struct tegra210_clk_emc *emc;
struct clk_init_data init;
struct clk *clk;
emc = kzalloc(sizeof(*emc), GFP_KERNEL);
if (!emc)
return ERR_PTR(-ENOMEM);
emc->regs = regs;
init.name = "emc";
init.ops = &tegra210_clk_emc_ops;
init.flags = CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE;
init.parent_names = tegra210_clk_emc_parents;
init.num_parents = ARRAY_SIZE(tegra210_clk_emc_parents);
emc->hw.init = &init;
clk = clk_register(NULL, &emc->hw);
if (IS_ERR(clk)) {
kfree(emc);
return clk;
}
return clk;
}
int tegra210_clk_emc_attach(struct clk *clk,
struct tegra210_clk_emc_provider *provider)
{
struct clk_hw *hw = __clk_get_hw(clk);
struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw);
struct device *dev = provider->dev;
unsigned int i;
int err;
if (!try_module_get(provider->owner))
return -ENODEV;
for (i = 0; i < provider->num_configs; i++) {
struct tegra210_clk_emc_config *config = &provider->configs[i];
struct clk_hw *parent;
bool same_freq;
u8 div, src;
div = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_DIVISOR, config->value);
src = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_SRC, config->value);
/* do basic sanity checking on the EMC timings */
if (div & 0x1) {
dev_err(dev, "invalid odd divider %u for rate %lu Hz\n",
div, config->rate);
err = -EINVAL;
goto put;
}
same_freq = config->value & CLK_SOURCE_EMC_MC_EMC_SAME_FREQ;
if (same_freq != config->same_freq) {
dev_err(dev,
"ambiguous EMC to MC ratio for rate %lu Hz\n",
config->rate);
err = -EINVAL;
goto put;
}
parent = clk_hw_get_parent_by_index(hw, src);
config->parent = src;
if (src == CLK_SRC_PLLM || src == CLK_SRC_PLLM_UD) {
config->parent_rate = config->rate * (1 + div / 2);
} else {
unsigned long rate = config->rate * (1 + div / 2);
config->parent_rate = clk_hw_get_rate(parent);
if (config->parent_rate != rate) {
dev_err(dev,
"rate %lu Hz does not match input\n",
config->rate);
err = -EINVAL;
goto put;
}
}
}
emc->provider = provider;
return 0;
put:
module_put(provider->owner);
return err;
}
EXPORT_SYMBOL_GPL(tegra210_clk_emc_attach);
void tegra210_clk_emc_detach(struct clk *clk)
{
struct tegra210_clk_emc *emc = to_tegra210_clk_emc(__clk_get_hw(clk));
module_put(emc->provider->owner);
emc->provider = NULL;
}
EXPORT_SYMBOL_GPL(tegra210_clk_emc_detach);
......@@ -37,6 +37,7 @@
#define CLK_SOURCE_LA 0x1f8
#define CLK_SOURCE_SDMMC2 0x154
#define CLK_SOURCE_SDMMC4 0x164
#define CLK_SOURCE_EMC_DLL 0x664
#define PLLC_BASE 0x80
#define PLLC_OUT 0x84
......@@ -227,6 +228,10 @@
#define RST_DFLL_DVCO 0x2f4
#define DVFS_DFLL_RESET_SHIFT 0
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X_SET 0x284
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X_CLR 0x288
#define CLK_OUT_ENB_X_CLK_ENB_EMC_DLL BIT(14)
#define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2a8
#define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2ac
#define CPU_SOFTRST_CTRL 0x380
......@@ -314,12 +319,6 @@ static unsigned long tegra210_input_freq[] = {
[8] = 12000000,
};
static const char *mux_pllmcp_clkm[] = {
"pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_mb", "pll_mb",
"pll_p",
};
#define mux_pllmcp_clkm_idx NULL
#define PLL_ENABLE (1 << 30)
#define PLLCX_MISC1_IDDQ (1 << 27)
......@@ -555,6 +554,27 @@ void tegra210_set_sata_pll_seq_sw(bool state)
}
EXPORT_SYMBOL_GPL(tegra210_set_sata_pll_seq_sw);
void tegra210_clk_emc_dll_enable(bool flag)
{
u32 offset = flag ? CLK_RST_CONTROLLER_CLK_OUT_ENB_X_SET :
CLK_RST_CONTROLLER_CLK_OUT_ENB_X_CLR;
writel_relaxed(CLK_OUT_ENB_X_CLK_ENB_EMC_DLL, clk_base + offset);
}
EXPORT_SYMBOL_GPL(tegra210_clk_emc_dll_enable);
void tegra210_clk_emc_dll_update_setting(u32 emc_dll_src_value)
{
writel_relaxed(emc_dll_src_value, clk_base + CLK_SOURCE_EMC_DLL);
}
EXPORT_SYMBOL_GPL(tegra210_clk_emc_dll_update_setting);
void tegra210_clk_emc_update_setting(u32 emc_src_value)
{
writel_relaxed(emc_src_value, clk_base + CLK_SOURCE_EMC);
}
EXPORT_SYMBOL_GPL(tegra210_clk_emc_update_setting);
static void tegra210_generic_mbist_war(struct tegra210_domain_mbist_war *mbist)
{
u32 val;
......@@ -2310,7 +2330,6 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
[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 },
......@@ -2953,6 +2972,27 @@ static const char * const sor1_parents[] = {
static u32 sor1_parents_idx[] = { 0, 2, 5, 6 };
static const struct clk_div_table mc_div_table_tegra210[] = {
{ .val = 0, .div = 2 },
{ .val = 1, .div = 4 },
{ .val = 2, .div = 1 },
{ .val = 3, .div = 2 },
{ .val = 0, .div = 0 },
};
static void tegra210_clk_register_mc(const char *name,
const char *parent_name)
{
struct clk *clk;
clk = clk_register_divider_table(NULL, name, parent_name,
CLK_IS_CRITICAL,
clk_base + CLK_SOURCE_EMC,
15, 2, CLK_DIVIDER_READ_ONLY,
mc_div_table_tegra210, &emc_lock);
clks[TEGRA210_CLK_MC] = clk;
}
static const char * const sor1_out_parents[] = {
/*
* Bit 0 of the mux selects sor1_pad_clkout, irrespective of bit 1, so
......@@ -2995,7 +3035,8 @@ static const char * const la_parents[] = {
static struct tegra_clk_periph tegra210_la =
TEGRA_CLK_PERIPH(29, 7, 9, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, 76, 0, NULL, NULL);
static __init void tegra210_periph_clk_init(void __iomem *clk_base,
static __init void tegra210_periph_clk_init(struct device_node *np,
void __iomem *clk_base,
void __iomem *pmc_base)
{
struct clk *clk;
......@@ -3035,22 +3076,19 @@ static __init void tegra210_periph_clk_init(void __iomem *clk_base,
periph_clk_enb_refcnt);
clks[TEGRA210_CLK_DSIB] = clk;
/* csi_tpg */
clk = clk_register_gate(NULL, "csi_tpg", "pll_d",
CLK_SET_RATE_PARENT, clk_base + PLLD_BASE,
23, 0, &pll_d_lock);
clk_register_clkdev(clk, "csi_tpg", NULL);
clks[TEGRA210_CLK_CSI_TPG] = clk;
/* la */
clk = tegra_clk_register_periph("la", la_parents,
ARRAY_SIZE(la_parents), &tegra210_la, clk_base,
CLK_SOURCE_LA, 0);
clks[TEGRA210_CLK_LA] = 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);
......@@ -3093,6 +3131,13 @@ static __init void tegra210_periph_clk_init(void __iomem *clk_base,
}
tegra_periph_clk_init(clk_base, pmc_base, tegra210_clks, &pll_p_params);
/* emc */
clk = tegra210_clk_register_emc(np, clk_base);
clks[TEGRA210_CLK_EMC] = clk;
/* mc */
tegra210_clk_register_mc("mc", "emc");
}
static void __init tegra210_pll_init(void __iomem *clk_base,
......@@ -3153,6 +3198,17 @@ static void __init tegra210_pll_init(void __iomem *clk_base,
clk_register_clkdev(clk, "pll_m_ud", NULL);
clks[TEGRA210_CLK_PLL_M_UD] = clk;
/* PLLMB_UD */
clk = clk_register_fixed_factor(NULL, "pll_mb_ud", "pll_mb",
CLK_SET_RATE_PARENT, 1, 1);
clk_register_clkdev(clk, "pll_mb_ud", NULL);
clks[TEGRA210_CLK_PLL_MB_UD] = clk;
/* PLLP_UD */
clk = clk_register_fixed_factor(NULL, "pll_p_ud", "pll_p",
0, 1, 1);
clks[TEGRA210_CLK_PLL_P_UD] = clk;
/* PLLU_VCO */
if (!tegra210_init_pllu()) {
clk = clk_register_fixed_rate(NULL, "pll_u_vco", "pll_ref", 0,
......@@ -3680,7 +3736,7 @@ static void __init tegra210_clock_init(struct device_node *np)
tegra_fixed_clk_init(tegra210_clks);
tegra210_pll_init(clk_base, pmc_base);
tegra210_periph_clk_init(clk_base, pmc_base);
tegra210_periph_clk_init(np, clk_base, pmc_base);
tegra_audio_clk_init(clk_base, pmc_base, tegra210_clks,
tegra210_audio_plls,
ARRAY_SIZE(tegra210_audio_plls), 24576000);
......
......@@ -499,6 +499,8 @@ static struct tegra_clk_pll_params pll_x_params __ro_after_init = {
.freq_table = pll_x_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_DCCON |
TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
.pre_rate_change = tegra_cclk_pre_pllx_rate_change,
.post_rate_change = tegra_cclk_post_pllx_rate_change,
};
static struct tegra_clk_pll_params pll_e_params __ro_after_init = {
......@@ -926,11 +928,11 @@ static void __init tegra30_super_clk_init(void)
clk_register_clkdev(clk, "pll_p_out4_cclkg", NULL);
/* CCLKG */
clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents,
clk = tegra_clk_register_super_cclk("cclk_g", cclk_g_parents,
ARRAY_SIZE(cclk_g_parents),
CLK_SET_RATE_PARENT,
clk_base + CCLKG_BURST_POLICY,
0, 4, 0, 0, NULL);
0, NULL);
clks[TEGRA30_CLK_CCLK_G] = clk;
/*
......
......@@ -266,6 +266,10 @@ struct tegra_clk_pll;
* disabled.
* @dyn_ramp: Callback which can be used to define a custom
* dynamic ramp function for a given PLL.
* @pre_rate_change: Callback which is invoked just before changing
* PLL's rate.
* @post_rate_change: Callback which is invoked right after changing
* PLL's rate.
*
* Flags:
* TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for
......@@ -342,6 +346,8 @@ struct tegra_clk_pll_params {
void (*set_defaults)(struct tegra_clk_pll *pll);
int (*dyn_ramp)(struct tegra_clk_pll *pll,
struct tegra_clk_pll_freq_table *cfg);
int (*pre_rate_change)(void);
void (*post_rate_change)(void);
};
#define TEGRA_PLL_USE_LOCK BIT(0)
......@@ -729,8 +735,10 @@ struct clk *tegra_clk_register_periph_data(void __iomem *clk_base,
* TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag indicates
* that this is LP cluster clock.
* TEGRA210_CPU_CLK - This flag is used to identify CPU cluster for gen5
* super mux parent using PLLP branches. To use PLLP branches to CPU, need
* to configure additional bit PLLP_OUT_CPU in the clock registers.
* super mux parent using PLLP branches. To use PLLP branches to CPU, need
* to configure additional bit PLLP_OUT_CPU in the clock registers.
* TEGRA20_SUPER_CLK - Tegra20 doesn't have a dedicated divider for Super
* clocks, it only has a clock-skipper.
*/
struct tegra_clk_super_mux {
struct clk_hw hw;
......@@ -748,6 +756,7 @@ struct tegra_clk_super_mux {
#define TEGRA_DIVIDER_2 BIT(0)
#define TEGRA210_CPU_CLK BIT(1)
#define TEGRA20_SUPER_CLK BIT(2)
extern const struct clk_ops tegra_clk_super_ops;
struct clk *tegra_clk_register_super_mux(const char *name,
......@@ -758,6 +767,12 @@ struct clk *tegra_clk_register_super_clk(const char *name,
const char * const *parent_names, u8 num_parents,
unsigned long flags, void __iomem *reg, u8 clk_super_flags,
spinlock_t *lock);
struct clk *tegra_clk_register_super_cclk(const char *name,
const char * const *parent_names, u8 num_parents,
unsigned long flags, void __iomem *reg, u8 clk_super_flags,
spinlock_t *lock);
int tegra_cclk_pre_pllx_rate_change(void);
void tegra_cclk_post_pllx_rate_change(void);
/**
* struct tegra_sdmmc_mux - switch divider with Low Jitter inputs for SDMMC
......@@ -866,7 +881,7 @@ 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);
#ifdef CONFIG_TEGRA_CLK_EMC
#ifdef CONFIG_TEGRA124_EMC
struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np,
spinlock_t *lock);
#else
......@@ -907,4 +922,7 @@ void tegra_clk_periph_resume(void);
bool tegra20_clk_emc_driver_available(struct clk_hw *emc_hw);
struct clk *tegra20_clk_register_emc(void __iomem *ioaddr, bool low_jitter);
struct clk *tegra210_clk_register_emc(struct device_node *np,
void __iomem *regs);
#endif /* TEGRA_CLK_H */
......@@ -606,13 +606,13 @@ static const struct omap_clkctrl_reg_data omap4_l4_per_clkctrl_regs[] __initcons
static const struct
omap_clkctrl_reg_data omap4_l4_secure_clkctrl_regs[] __initconst = {
{ OMAP4_AES1_CLKCTRL, NULL, CLKF_SW_SUP, "" },
{ OMAP4_AES2_CLKCTRL, NULL, CLKF_SW_SUP, "" },
{ OMAP4_DES3DES_CLKCTRL, NULL, CLKF_SW_SUP, "" },
{ OMAP4_PKA_CLKCTRL, NULL, CLKF_SW_SUP, "" },
{ OMAP4_RNG_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_SOC_NONSEC, "" },
{ OMAP4_SHA2MD5_CLKCTRL, NULL, CLKF_SW_SUP, "" },
{ OMAP4_CRYPTODMA_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_SOC_NONSEC, "" },
{ OMAP4_AES1_CLKCTRL, NULL, CLKF_SW_SUP, "l3_div_ck" },
{ OMAP4_AES2_CLKCTRL, NULL, CLKF_SW_SUP, "l3_div_ck" },
{ OMAP4_DES3DES_CLKCTRL, NULL, CLKF_SW_SUP, "l4_div_ck" },
{ OMAP4_PKA_CLKCTRL, NULL, CLKF_SW_SUP, "l4_div_ck" },
{ OMAP4_RNG_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_SOC_NONSEC, "l4_div_ck" },
{ OMAP4_SHA2MD5_CLKCTRL, NULL, CLKF_SW_SUP, "l3_div_ck" },
{ OMAP4_CRYPTODMA_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_SOC_NONSEC, "l3_div_ck" },
{ 0 },
};
......
......@@ -303,13 +303,13 @@ static const struct omap_clkctrl_reg_data omap5_l4per_clkctrl_regs[] __initconst
static const struct
omap_clkctrl_reg_data omap5_l4_secure_clkctrl_regs[] __initconst = {
{ OMAP5_AES1_CLKCTRL, NULL, CLKF_HW_SUP, "" },
{ OMAP5_AES2_CLKCTRL, NULL, CLKF_HW_SUP, "" },
{ OMAP5_DES3DES_CLKCTRL, NULL, CLKF_HW_SUP, "" },
{ OMAP5_FPKA_CLKCTRL, NULL, CLKF_SW_SUP, "" },
{ OMAP5_RNG_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_SOC_NONSEC, "" },
{ OMAP5_SHA2MD5_CLKCTRL, NULL, CLKF_HW_SUP, "" },
{ OMAP5_DMA_CRYPTO_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_SOC_NONSEC, "" },
{ OMAP5_AES1_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
{ OMAP5_AES2_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
{ OMAP5_DES3DES_CLKCTRL, NULL, CLKF_HW_SUP, "l4_root_clk_div" },
{ OMAP5_FPKA_CLKCTRL, NULL, CLKF_SW_SUP, "l4_root_clk_div" },
{ OMAP5_RNG_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_SOC_NONSEC, "l4_root_clk_div" },
{ OMAP5_SHA2MD5_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
{ OMAP5_DMA_CRYPTO_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_SOC_NONSEC, "l3_iclk_div" },
{ 0 },
};
......
......@@ -312,15 +312,6 @@ static const char * const dra7_gpu_hyd_mux_parents[] __initconst = {
NULL,
};
static const char * const dra7_gpu_sys_clk_parents[] __initconst = {
"sys_clkin",
NULL,
};
static const struct omap_clkctrl_div_data dra7_gpu_sys_clk_data __initconst = {
.max_div = 2,
};
static const struct omap_clkctrl_bit_data dra7_gpu_core_bit_data[] __initconst = {
{ 24, TI_CLK_MUX, dra7_gpu_core_mux_parents, NULL, },
{ 26, TI_CLK_MUX, dra7_gpu_hyd_mux_parents, NULL, },
......@@ -328,7 +319,7 @@ static const struct omap_clkctrl_bit_data dra7_gpu_core_bit_data[] __initconst =
};
static const struct omap_clkctrl_reg_data dra7_gpu_clkctrl_regs[] __initconst = {
{ DRA7_GPU_CLKCTRL, dra7_gpu_core_bit_data, CLKF_SW_SUP, "gpu_cm:clk:0000:24", },
{ DRA7_GPU_CLKCTRL, dra7_gpu_core_bit_data, CLKF_SW_SUP, "gpu-clkctrl:0000:24", },
{ 0 },
};
......@@ -644,7 +635,7 @@ static const struct omap_clkctrl_reg_data dra7_l4sec_clkctrl_regs[] __initconst
{ DRA7_L4SEC_AES1_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
{ DRA7_L4SEC_AES2_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
{ DRA7_L4SEC_DES_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
{ DRA7_L4SEC_RNG_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_SOC_NONSEC, "" },
{ DRA7_L4SEC_RNG_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_SOC_NONSEC, "l4_root_clk_div" },
{ DRA7_L4SEC_SHAM_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
{ 0 },
};
......@@ -815,7 +806,7 @@ static const struct omap_clkctrl_reg_data dra7_wkupaon_clkctrl_regs[] __initcons
{ DRA7_WKUPAON_COUNTER_32K_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" },
{ DRA7_WKUPAON_UART10_CLKCTRL, dra7_uart10_bit_data, CLKF_SW_SUP, "wkupaon-clkctrl:0060:24" },
{ DRA7_WKUPAON_DCAN1_CLKCTRL, dra7_dcan1_bit_data, CLKF_SW_SUP, "wkupaon-clkctrl:0068:24" },
{ DRA7_WKUPAON_ADC_CLKCTRL, NULL, CLKF_SW_SUP, "mcan_clk" },
{ DRA7_WKUPAON_ADC_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_SOC_DRA76, "mcan_clk" },
{ 0 },
};
......
......@@ -196,6 +196,7 @@ static void __init _register_composite(void *user,
if (!cclk->comp_clks[i])
continue;
list_del(&cclk->comp_clks[i]->link);
kfree(cclk->comp_clks[i]->parent_names);
kfree(cclk->comp_clks[i]);
}
......
......@@ -30,6 +30,7 @@ struct clock_topology {
u32 type;
u32 flag;
u32 type_flag;
u8 custom_type_flag;
};
struct clk_hw *zynqmp_clk_register_pll(const char *name, u32 clk_id,
......
......@@ -84,6 +84,7 @@ struct name_resp {
struct topology_resp {
#define CLK_TOPOLOGY_TYPE GENMASK(3, 0)
#define CLK_TOPOLOGY_CUSTOM_TYPE_FLAGS GENMASK(7, 4)
#define CLK_TOPOLOGY_FLAGS GENMASK(23, 8)
#define CLK_TOPOLOGY_TYPE_FLAGS GENMASK(31, 24)
u32 topology[CLK_GET_TOPOLOGY_RESP_WORDS];
......@@ -396,6 +397,9 @@ static int __zynqmp_clock_get_topology(struct clock_topology *topology,
topology[*nnodes].type_flag =
FIELD_GET(CLK_TOPOLOGY_TYPE_FLAGS,
response->topology[i]);
topology[*nnodes].custom_type_flag =
FIELD_GET(CLK_TOPOLOGY_CUSTOM_TYPE_FLAGS,
response->topology[i]);
(*nnodes)++;
}
......@@ -558,7 +562,7 @@ static struct clk_hw *zynqmp_register_clk_topology(int clk_id, char *clk_name,
{
int j;
u32 num_nodes, clk_dev_id;
char *clk_out = NULL;
char *clk_out[MAX_NODES];
struct clock_topology *nodes;
struct clk_hw *hw = NULL;
......@@ -572,16 +576,16 @@ static struct clk_hw *zynqmp_register_clk_topology(int clk_id, char *clk_name,
* Intermediate clock names are postfixed with type of clock.
*/
if (j != (num_nodes - 1)) {
clk_out = kasprintf(GFP_KERNEL, "%s%s", clk_name,
clk_out[j] = kasprintf(GFP_KERNEL, "%s%s", clk_name,
clk_type_postfix[nodes[j].type]);
} else {
clk_out = kasprintf(GFP_KERNEL, "%s", clk_name);
clk_out[j] = kasprintf(GFP_KERNEL, "%s", clk_name);
}
if (!clk_topology[nodes[j].type])
continue;
hw = (*clk_topology[nodes[j].type])(clk_out, clk_dev_id,
hw = (*clk_topology[nodes[j].type])(clk_out[j], clk_dev_id,
parent_names,
num_parents,
&nodes[j]);
......@@ -590,9 +594,12 @@ static struct clk_hw *zynqmp_register_clk_topology(int clk_id, char *clk_name,
__func__, clk_dev_id, clk_name,
PTR_ERR(hw));
parent_names[0] = clk_out;
parent_names[0] = clk_out[j];
}
kfree(clk_out);
for (j = 0; j < num_nodes; j++)
kfree(clk_out[j]);
return hw;
}
......@@ -663,6 +670,11 @@ static void zynqmp_get_clock_info(void)
continue;
clock[i].valid = FIELD_GET(CLK_ATTR_VALID, attr.attr[0]);
/* skip query for Invalid clock */
ret = zynqmp_is_valid_clock(i);
if (ret != CLK_ATTR_VALID)
continue;
clock[i].type = FIELD_GET(CLK_ATTR_TYPE, attr.attr[0]) ?
CLK_TYPE_EXTERNAL : CLK_TYPE_OUTPUT;
......
......@@ -25,7 +25,8 @@
#define to_zynqmp_clk_divider(_hw) \
container_of(_hw, struct zynqmp_clk_divider, hw)
#define CLK_FRAC BIT(13) /* has a fractional parent */
#define CLK_FRAC BIT(13) /* has a fractional parent */
#define CUSTOM_FLAG_CLK_FRAC BIT(0) /* has a fractional parent in custom type flag */
/**
* struct zynqmp_clk_divider - adjustable divider clock
......@@ -111,23 +112,30 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw,
static void zynqmp_get_divider2_val(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate,
struct zynqmp_clk_divider *divider,
int *bestdiv)
{
int div1;
int div2;
long error = LONG_MAX;
struct clk_hw *parent_hw = clk_hw_get_parent(hw);
struct zynqmp_clk_divider *pdivider = to_zynqmp_clk_divider(parent_hw);
unsigned long div1_prate;
struct clk_hw *div1_parent_hw;
struct clk_hw *div2_parent_hw = clk_hw_get_parent(hw);
struct zynqmp_clk_divider *pdivider =
to_zynqmp_clk_divider(div2_parent_hw);
if (!pdivider)
return;
div1_parent_hw = clk_hw_get_parent(div2_parent_hw);
if (!div1_parent_hw)
return;
div1_prate = clk_hw_get_rate(div1_parent_hw);
*bestdiv = 1;
for (div1 = 1; div1 <= pdivider->max_div;) {
for (div2 = 1; div2 <= divider->max_div;) {
long new_error = ((parent_rate / div1) / div2) - rate;
long new_error = ((div1_prate / div1) / div2) - rate;
if (abs(new_error) < abs(error)) {
*bestdiv = div2;
......@@ -192,11 +200,13 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw,
*/
if (div_type == TYPE_DIV2 &&
(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
zynqmp_get_divider2_val(hw, rate, *prate, divider, &bestdiv);
zynqmp_get_divider2_val(hw, rate, divider, &bestdiv);
}
if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && divider->is_frac)
bestdiv = rate % *prate ? 1 : bestdiv;
bestdiv = min_t(u32, bestdiv, divider->max_div);
*prate = rate * bestdiv;
return rate;
......@@ -256,7 +266,7 @@ static const struct clk_ops zynqmp_clk_divider_ops = {
* Return: Maximum divisor of a clock if query data is successful
* U16_MAX in case of query data is not success
*/
u32 zynqmp_clk_get_max_divisor(u32 clk_id, u32 type)
static u32 zynqmp_clk_get_max_divisor(u32 clk_id, u32 type)
{
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
struct zynqmp_pm_query_data qdata = {0};
......@@ -311,7 +321,8 @@ struct clk_hw *zynqmp_clk_register_divider(const char *name,
init.num_parents = 1;
/* struct clk_divider assignments */
div->is_frac = !!(nodes->flag & CLK_FRAC);
div->is_frac = !!((nodes->flag & CLK_FRAC) |
(nodes->custom_type_flag & CUSTOM_FLAG_CLK_FRAC));
div->flags = nodes->type_flag;
div->hw.init = &init;
div->clk_id = clk_id;
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2019, Intel Corporation
*/
#ifndef __AGILEX_CLOCK_H
#define __AGILEX_CLOCK_H
/* fixed rate clocks */
#define AGILEX_OSC1 0
#define AGILEX_CB_INTOSC_HS_DIV2_CLK 1
#define AGILEX_CB_INTOSC_LS_CLK 2
#define AGILEX_L4_SYS_FREE_CLK 3
#define AGILEX_F2S_FREE_CLK 4
/* PLL clocks */
#define AGILEX_MAIN_PLL_CLK 5
#define AGILEX_MAIN_PLL_C0_CLK 6
#define AGILEX_MAIN_PLL_C1_CLK 7
#define AGILEX_MAIN_PLL_C2_CLK 8
#define AGILEX_MAIN_PLL_C3_CLK 9
#define AGILEX_PERIPH_PLL_CLK 10
#define AGILEX_PERIPH_PLL_C0_CLK 11
#define AGILEX_PERIPH_PLL_C1_CLK 12
#define AGILEX_PERIPH_PLL_C2_CLK 13
#define AGILEX_PERIPH_PLL_C3_CLK 14
#define AGILEX_MPU_FREE_CLK 15
#define AGILEX_MPU_CCU_CLK 16
#define AGILEX_BOOT_CLK 17
/* fixed factor clocks */
#define AGILEX_L3_MAIN_FREE_CLK 18
#define AGILEX_NOC_FREE_CLK 19
#define AGILEX_S2F_USR0_CLK 20
#define AGILEX_NOC_CLK 21
#define AGILEX_EMAC_A_FREE_CLK 22
#define AGILEX_EMAC_B_FREE_CLK 23
#define AGILEX_EMAC_PTP_FREE_CLK 24
#define AGILEX_GPIO_DB_FREE_CLK 25
#define AGILEX_SDMMC_FREE_CLK 26
#define AGILEX_S2F_USER0_FREE_CLK 27
#define AGILEX_S2F_USER1_FREE_CLK 28
#define AGILEX_PSI_REF_FREE_CLK 29
/* Gate clocks */
#define AGILEX_MPU_CLK 30
#define AGILEX_MPU_L2RAM_CLK 31
#define AGILEX_MPU_PERIPH_CLK 32
#define AGILEX_L4_MAIN_CLK 33
#define AGILEX_L4_MP_CLK 34
#define AGILEX_L4_SP_CLK 35
#define AGILEX_CS_AT_CLK 36
#define AGILEX_CS_TRACE_CLK 37
#define AGILEX_CS_PDBG_CLK 38
#define AGILEX_CS_TIMER_CLK 39
#define AGILEX_S2F_USER0_CLK 40
#define AGILEX_EMAC0_CLK 41
#define AGILEX_EMAC1_CLK 43
#define AGILEX_EMAC2_CLK 44
#define AGILEX_EMAC_PTP_CLK 45
#define AGILEX_GPIO_DB_CLK 46
#define AGILEX_NAND_CLK 47
#define AGILEX_PSI_REF_CLK 48
#define AGILEX_S2F_USER1_CLK 49
#define AGILEX_SDMMC_CLK 50
#define AGILEX_SPI_M_CLK 51
#define AGILEX_USB_CLK 52
#define AGILEX_NUM_CLKS 53
#endif /* __AGILEX_CLOCK_H */
......@@ -12,6 +12,7 @@
#define PMC_TYPE_SYSTEM 1
#define PMC_TYPE_PERIPHERAL 2
#define PMC_TYPE_GCK 3
#define PMC_TYPE_PROGRAMMABLE 4
#define PMC_SLOW 0
#define PMC_MCK 1
......@@ -20,6 +21,9 @@
#define PMC_MCK2 4
#define PMC_I2S0_MUX 5
#define PMC_I2S1_MUX 6
#define PMC_PLLACK 7
#define PMC_PLLBCK 8
#define PMC_AUDIOPLLCK 9
#ifndef AT91_PMC_MOSCS
#define AT91_PMC_MOSCS 0 /* MOSCS Flag */
......
......@@ -58,7 +58,10 @@
#define IMX7ULP_CLK_HSRUN_SYS_SEL 44
#define IMX7ULP_CLK_HSRUN_CORE_DIV 45
#define IMX7ULP_CLK_SCG1_END 46
#define IMX7ULP_CLK_CORE 46
#define IMX7ULP_CLK_HSRUN_CORE 47
#define IMX7ULP_CLK_SCG1_END 48
/* PCC2 */
#define IMX7ULP_CLK_DMA1 0
......
......@@ -296,6 +296,94 @@
#define IMX8MP_CLK_ARM 287
#define IMX8MP_CLK_A53_CORE 288
#define IMX8MP_CLK_END 289
#define IMX8MP_SYS_PLL1_40M_CG 289
#define IMX8MP_SYS_PLL1_80M_CG 290
#define IMX8MP_SYS_PLL1_100M_CG 291
#define IMX8MP_SYS_PLL1_133M_CG 292
#define IMX8MP_SYS_PLL1_160M_CG 293
#define IMX8MP_SYS_PLL1_200M_CG 294
#define IMX8MP_SYS_PLL1_266M_CG 295
#define IMX8MP_SYS_PLL1_400M_CG 296
#define IMX8MP_SYS_PLL2_50M_CG 297
#define IMX8MP_SYS_PLL2_100M_CG 298
#define IMX8MP_SYS_PLL2_125M_CG 299
#define IMX8MP_SYS_PLL2_166M_CG 300
#define IMX8MP_SYS_PLL2_200M_CG 301
#define IMX8MP_SYS_PLL2_250M_CG 302
#define IMX8MP_SYS_PLL2_333M_CG 303
#define IMX8MP_SYS_PLL2_500M_CG 304
#define IMX8MP_CLK_M7_CORE 305
#define IMX8MP_CLK_ML_CORE 306
#define IMX8MP_CLK_GPU3D_CORE 307
#define IMX8MP_CLK_GPU3D_SHADER_CORE 308
#define IMX8MP_CLK_GPU2D_CORE 309
#define IMX8MP_CLK_AUDIO_AXI 310
#define IMX8MP_CLK_HSIO_AXI 311
#define IMX8MP_CLK_MEDIA_ISP 312
#define IMX8MP_CLK_END 313
#define IMX8MP_CLK_AUDIOMIX_SAI1_IPG 0
#define IMX8MP_CLK_AUDIOMIX_SAI1_MCLK1 1
#define IMX8MP_CLK_AUDIOMIX_SAI1_MCLK2 2
#define IMX8MP_CLK_AUDIOMIX_SAI1_MCLK3 3
#define IMX8MP_CLK_AUDIOMIX_SAI2_IPG 4
#define IMX8MP_CLK_AUDIOMIX_SAI2_MCLK1 5
#define IMX8MP_CLK_AUDIOMIX_SAI2_MCLK2 6
#define IMX8MP_CLK_AUDIOMIX_SAI2_MCLK3 7
#define IMX8MP_CLK_AUDIOMIX_SAI3_IPG 8
#define IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1 9
#define IMX8MP_CLK_AUDIOMIX_SAI3_MCLK2 10
#define IMX8MP_CLK_AUDIOMIX_SAI3_MCLK3 11
#define IMX8MP_CLK_AUDIOMIX_SAI5_IPG 12
#define IMX8MP_CLK_AUDIOMIX_SAI5_MCLK1 13
#define IMX8MP_CLK_AUDIOMIX_SAI5_MCLK2 14
#define IMX8MP_CLK_AUDIOMIX_SAI5_MCLK3 15
#define IMX8MP_CLK_AUDIOMIX_SAI6_IPG 16
#define IMX8MP_CLK_AUDIOMIX_SAI6_MCLK1 17
#define IMX8MP_CLK_AUDIOMIX_SAI6_MCLK2 18
#define IMX8MP_CLK_AUDIOMIX_SAI6_MCLK3 19
#define IMX8MP_CLK_AUDIOMIX_SAI7_IPG 20
#define IMX8MP_CLK_AUDIOMIX_SAI7_MCLK1 21
#define IMX8MP_CLK_AUDIOMIX_SAI7_MCLK2 22
#define IMX8MP_CLK_AUDIOMIX_SAI7_MCLK3 23
#define IMX8MP_CLK_AUDIOMIX_ASRC_IPG 24
#define IMX8MP_CLK_AUDIOMIX_PDM_IPG 25
#define IMX8MP_CLK_AUDIOMIX_SDMA2_ROOT 26
#define IMX8MP_CLK_AUDIOMIX_SDMA3_ROOT 27
#define IMX8MP_CLK_AUDIOMIX_SPBA2_ROOT 28
#define IMX8MP_CLK_AUDIOMIX_DSP_ROOT 29
#define IMX8MP_CLK_AUDIOMIX_DSPDBG_ROOT 30
#define IMX8MP_CLK_AUDIOMIX_EARC_IPG 31
#define IMX8MP_CLK_AUDIOMIX_OCRAMA_IPG 32
#define IMX8MP_CLK_AUDIOMIX_AUD2HTX_IPG 33
#define IMX8MP_CLK_AUDIOMIX_EDMA_ROOT 34
#define IMX8MP_CLK_AUDIOMIX_AUDPLL_ROOT 35
#define IMX8MP_CLK_AUDIOMIX_MU2_ROOT 36
#define IMX8MP_CLK_AUDIOMIX_MU3_ROOT 37
#define IMX8MP_CLK_AUDIOMIX_EARC_PHY 38
#define IMX8MP_CLK_AUDIOMIX_PDM_ROOT 39
#define IMX8MP_CLK_AUDIOMIX_SAI1_MCLK1_SEL 40
#define IMX8MP_CLK_AUDIOMIX_SAI1_MCLK2_SEL 41
#define IMX8MP_CLK_AUDIOMIX_SAI2_MCLK1_SEL 42
#define IMX8MP_CLK_AUDIOMIX_SAI2_MCLK2_SEL 43
#define IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1_SEL 44
#define IMX8MP_CLK_AUDIOMIX_SAI3_MCLK2_SEL 45
#define IMX8MP_CLK_AUDIOMIX_SAI4_MCLK1_SEL 46
#define IMX8MP_CLK_AUDIOMIX_SAI4_MCLK2_SEL 47
#define IMX8MP_CLK_AUDIOMIX_SAI5_MCLK1_SEL 48
#define IMX8MP_CLK_AUDIOMIX_SAI5_MCLK2_SEL 49
#define IMX8MP_CLK_AUDIOMIX_SAI6_MCLK1_SEL 50
#define IMX8MP_CLK_AUDIOMIX_SAI6_MCLK2_SEL 51
#define IMX8MP_CLK_AUDIOMIX_SAI7_MCLK1_SEL 52
#define IMX8MP_CLK_AUDIOMIX_SAI7_MCLK2_SEL 53
#define IMX8MP_CLK_AUDIOMIX_PDM_SEL 54
#define IMX8MP_CLK_AUDIOMIX_SAI_PLL_REF_SEL 55
#define IMX8MP_CLK_AUDIOMIX_SAI_PLL 56
#define IMX8MP_CLK_AUDIOMIX_SAI_PLL_BYPASS 57
#define IMX8MP_CLK_AUDIOMIX_SAI_PLL_OUT 58
#define IMX8MP_CLK_AUDIOMIX_END 59
#endif
......@@ -351,14 +351,14 @@
#define TEGRA210_CLK_PLL_P_OUT_XUSB 317
#define TEGRA210_CLK_XUSB_SSP_SRC 318
#define TEGRA210_CLK_PLL_RE_OUT1 319
/* 320 */
/* 321 */
#define TEGRA210_CLK_PLL_MB_UD 320
#define TEGRA210_CLK_PLL_P_UD 321
#define TEGRA210_CLK_ISP 322
#define TEGRA210_CLK_PLL_A_OUT_ADSP 323
#define TEGRA210_CLK_PLL_A_OUT0_OUT_ADSP 324
/* 325 */
#define TEGRA210_CLK_OSC 326
/* 327 */
#define TEGRA210_CLK_CSI_TPG 327
/* 328 */
/* 329 */
/* 330 */
......
......@@ -131,6 +131,9 @@ extern void tegra210_set_sata_pll_seq_sw(bool state);
extern void tegra210_put_utmipll_in_iddq(void);
extern void tegra210_put_utmipll_out_iddq(void);
extern int tegra210_clk_handle_mbist_war(unsigned int id);
extern void tegra210_clk_emc_dll_enable(bool flag);
extern void tegra210_clk_emc_dll_update_setting(u32 emc_dll_src_value);
extern void tegra210_clk_emc_update_setting(u32 emc_src_value);
struct clk;
......@@ -143,4 +146,28 @@ void tegra20_clk_set_emc_round_callback(tegra20_clk_emc_round_cb *round_cb,
void *cb_arg);
int tegra20_clk_prepare_emc_mc_same_freq(struct clk *emc_clk, bool same);
struct tegra210_clk_emc_config {
unsigned long rate;
bool same_freq;
u32 value;
unsigned long parent_rate;
u8 parent;
};
struct tegra210_clk_emc_provider {
struct module *owner;
struct device *dev;
struct tegra210_clk_emc_config *configs;
unsigned int num_configs;
int (*set_rate)(struct device *dev,
const struct tegra210_clk_emc_config *config);
};
int tegra210_clk_emc_attach(struct clk *clk,
struct tegra210_clk_emc_provider *provider);
void tegra210_clk_emc_detach(struct clk *clk);
#endif /* __LINUX_CLK_TEGRA_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment