Skip to content

Commit

Permalink
Merge tag 'memory-controller-drv-tegra-5.14-2' of https://git.kernel.…
Browse files Browse the repository at this point in the history
…org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl into arm/drivers

Memory controller drivers for v5.14 - Tegra SoC, part two

Second set of changes for Tegra SoC memory controller drivers,
containing patchset from Thierry Reding:

"The goal here is to avoid early identity mappings altogether and instead
postpone the need for the identity mappings to when devices are attached
to the SMMU. This works by making the SMMU driver coordinate with the
memory controller driver on when to start enforcing SMMU translations.
This makes Tegra behave in a more standard way and pushes the code to
deal with the Tegra-specific programming into the NVIDIA SMMU
implementation."

This pulls a dependency from Will Deacon (ARM SMMU driver) and contains
further ARM SMMU driver patches to resolve complex dependencies between
different patchsets.  The pull from Will contains only one patch
("Implement ->probe_finalize()").  Further work in Will's tree might
depend on this patch, therefore patch was applied there.

On the other hand, this ("Implement ->probe_finalize()") patch is also a
dependency for ARM SMMU driver changes for Tegra.  These changes,
bringing seamless transition from the firmware framebuffer to the OS
framebuffer, depend on earlier Tegra memory controller driver patches.

* tag 'memory-controller-drv-tegra-5.14-2' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl: (37 commits)
  iommu/arm-smmu: Use Tegra implementation on Tegra186
  iommu/arm-smmu: tegra: Implement SID override programming
  iommu/arm-smmu: tegra: Detect number of instances at runtime
  dt-bindings: arm-smmu: Add Tegra186 compatible string
  memory: tegra: Delete dead debugfs checking code
  iommu/arm-smmu: Implement ->probe_finalize()
  memory: tegra: Implement SID override programming
  memory: tegra: Split Tegra194 data into separate file
  memory: tegra: Add memory client IDs to tables
  memory: tegra: Unify drivers
  memory: tegra: Only initialize reset controller if available
  memory: tegra: Make IRQ support opitonal
  memory: tegra: Parameterize interrupt handler
  memory: tegra: Extract setup code into callback
  memory: tegra: Make per-SoC setup more generic
  memory: tegra: Push suspend/resume into SoC drivers
  memory: tegra: Introduce struct tegra_mc_ops
  memory: tegra: Unify struct tegra_mc across SoC generations
  memory: tegra: Consolidate register fields
  memory: tegra30-emc: Use devm_tegra_core_dev_init_opp_table()
  ...

Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Olof Johansson <[email protected]>
  • Loading branch information
olofj committed Jun 17, 2021
2 parents e73153b + 2c1bc37 commit 1eb5f83
Show file tree
Hide file tree
Showing 39 changed files with 5,662 additions and 4,011 deletions.
11 changes: 9 additions & 2 deletions Documentation/devicetree/bindings/iommu/arm,smmu.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,14 @@ properties:
- const: arm,mmu-500
- description: NVIDIA SoCs that program two ARM MMU-500s identically
items:
- description: NVIDIA SoCs that require memory controller interaction
and may program multiple ARM MMU-500s identically with the memory
controller interleaving translations between multiple instances
for improved performance.
items:
- enum:
- nvidia,tegra194-smmu
- const: nvidia,tegra194-smmu
- const: nvidia,tegra186-smmu
- const: nvidia,smmu-500
- items:
- const: arm,mmu-500
Expand Down Expand Up @@ -165,10 +171,11 @@ allOf:
contains:
enum:
- nvidia,tegra194-smmu
- nvidia,tegra186-smmu
then:
properties:
reg:
minItems: 2
minItems: 1
maxItems: 2
else:
properties:
Expand Down
80 changes: 47 additions & 33 deletions drivers/clk/tegra/clk-periph-gate.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,36 +48,45 @@ static int clk_periph_is_enabled(struct clk_hw *hw)
return state;
}

static int clk_periph_enable(struct clk_hw *hw)
static void clk_periph_enable_locked(struct clk_hw *hw)
{
struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
unsigned long flags = 0;

spin_lock_irqsave(&periph_ref_lock, flags);

gate->enable_refcnt[gate->clk_num]++;
if (gate->enable_refcnt[gate->clk_num] > 1) {
spin_unlock_irqrestore(&periph_ref_lock, flags);
return 0;
}

write_enb_set(periph_clk_to_bit(gate), gate);
udelay(2);

if (!(gate->flags & TEGRA_PERIPH_NO_RESET) &&
!(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) {
if (read_rst(gate) & periph_clk_to_bit(gate)) {
udelay(5); /* reset propogation delay */
write_rst_clr(periph_clk_to_bit(gate), gate);
}
}

if (gate->flags & TEGRA_PERIPH_WAR_1005168) {
writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE);
writel_relaxed(BIT(22), gate->clk_base + LVL2_CLK_GATE_OVRE);
udelay(1);
writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE);
}
}

static void clk_periph_disable_locked(struct clk_hw *hw)
{
struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);

/*
* If peripheral is in the APB bus then read the APB bus to
* flush the write operation in apb bus. This will avoid the
* peripheral access after disabling clock
*/
if (gate->flags & TEGRA_PERIPH_ON_APB)
tegra_read_chipid();

write_enb_clr(periph_clk_to_bit(gate), gate);
}

static int clk_periph_enable(struct clk_hw *hw)
{
struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
unsigned long flags = 0;

spin_lock_irqsave(&periph_ref_lock, flags);

if (!gate->enable_refcnt[gate->clk_num]++)
clk_periph_enable_locked(hw);

spin_unlock_irqrestore(&periph_ref_lock, flags);

Expand All @@ -91,21 +100,28 @@ static void clk_periph_disable(struct clk_hw *hw)

spin_lock_irqsave(&periph_ref_lock, flags);

gate->enable_refcnt[gate->clk_num]--;
if (gate->enable_refcnt[gate->clk_num] > 0) {
spin_unlock_irqrestore(&periph_ref_lock, flags);
return;
}
WARN_ON(!gate->enable_refcnt[gate->clk_num]);

if (--gate->enable_refcnt[gate->clk_num] == 0)
clk_periph_disable_locked(hw);

spin_unlock_irqrestore(&periph_ref_lock, flags);
}

static void clk_periph_disable_unused(struct clk_hw *hw)
{
struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
unsigned long flags = 0;

spin_lock_irqsave(&periph_ref_lock, flags);

/*
* If peripheral is in the APB bus then read the APB bus to
* flush the write operation in apb bus. This will avoid the
* peripheral access after disabling clock
* Some clocks are duplicated and some of them are marked as critical,
* like fuse and fuse_burn for example, thus the enable_refcnt will
* be non-zero here if the "unused" duplicate is disabled by CCF.
*/
if (gate->flags & TEGRA_PERIPH_ON_APB)
tegra_read_chipid();

write_enb_clr(periph_clk_to_bit(gate), gate);
if (!gate->enable_refcnt[gate->clk_num])
clk_periph_disable_locked(hw);

spin_unlock_irqrestore(&periph_ref_lock, flags);
}
Expand All @@ -114,6 +130,7 @@ const struct clk_ops tegra_clk_periph_gate_ops = {
.is_enabled = clk_periph_is_enabled,
.enable = clk_periph_enable,
.disable = clk_periph_disable,
.disable_unused = clk_periph_disable_unused,
};

struct clk *tegra_clk_register_periph_gate(const char *name,
Expand Down Expand Up @@ -148,9 +165,6 @@ struct clk *tegra_clk_register_periph_gate(const char *name,
gate->enable_refcnt = enable_refcnt;
gate->regs = pregs;

if (read_enb(gate) & periph_clk_to_bit(gate))
enable_refcnt[clk_num]++;

/* Data in .init is copied by clk_register(), so stack variable OK */
gate->hw.init = &init;

Expand Down
11 changes: 11 additions & 0 deletions drivers/clk/tegra/clk-periph.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,15 @@ static void clk_periph_disable(struct clk_hw *hw)
gate_ops->disable(gate_hw);
}

static void clk_periph_disable_unused(struct clk_hw *hw)
{
struct tegra_clk_periph *periph = to_clk_periph(hw);
const struct clk_ops *gate_ops = periph->gate_ops;
struct clk_hw *gate_hw = &periph->gate.hw;

gate_ops->disable_unused(gate_hw);
}

static void clk_periph_restore_context(struct clk_hw *hw)
{
struct tegra_clk_periph *periph = to_clk_periph(hw);
Expand All @@ -126,6 +135,7 @@ const struct clk_ops tegra_clk_periph_ops = {
.is_enabled = clk_periph_is_enabled,
.enable = clk_periph_enable,
.disable = clk_periph_disable,
.disable_unused = clk_periph_disable_unused,
.restore_context = clk_periph_restore_context,
};

Expand All @@ -135,6 +145,7 @@ static const struct clk_ops tegra_clk_periph_nodiv_ops = {
.is_enabled = clk_periph_is_enabled,
.enable = clk_periph_enable,
.disable = clk_periph_disable,
.disable_unused = clk_periph_disable_unused,
.restore_context = clk_periph_restore_context,
};

Expand Down
12 changes: 7 additions & 5 deletions drivers/clk/tegra/clk-pll.c
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,9 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
u32 p_div = 0;
int ret;

if (!rate)
return -EINVAL;

switch (parent_rate) {
case 12000000:
case 26000000:
Expand Down Expand Up @@ -1131,7 +1134,8 @@ static int clk_pllu_enable(struct clk_hw *hw)
if (pll->lock)
spin_lock_irqsave(pll->lock, flags);

_clk_pll_enable(hw);
if (!clk_pll_is_enabled(hw))
_clk_pll_enable(hw);

ret = clk_pll_wait_for_lock(pll);
if (ret < 0)
Expand Down Expand Up @@ -1748,15 +1752,13 @@ static int clk_pllu_tegra114_enable(struct clk_hw *hw)
return -EINVAL;
}

if (clk_pll_is_enabled(hw))
return 0;

input_rate = clk_hw_get_rate(__clk_get_hw(osc));

if (pll->lock)
spin_lock_irqsave(pll->lock, flags);

_clk_pll_enable(hw);
if (!clk_pll_is_enabled(hw))
_clk_pll_enable(hw);

ret = clk_pll_wait_for_lock(pll);
if (ret < 0)
Expand Down
6 changes: 3 additions & 3 deletions drivers/clk/tegra/clk-tegra-periph.c
Original file line number Diff line number Diff line change
Expand Up @@ -712,9 +712,9 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX8("ndflash", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDFLASH, 13, TEGRA_PERIPH_ON_APB, tegra_clk_ndflash_8),
MUX8("ndspeed", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDSPEED, 80, TEGRA_PERIPH_ON_APB, tegra_clk_ndspeed_8),
MUX8("hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, 0, tegra_clk_hdmi),
MUX8("extern1", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, 0, tegra_clk_extern1),
MUX8("extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, 0, tegra_clk_extern2),
MUX8("extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, 0, tegra_clk_extern3),
MUX8("extern1", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, TEGRA_PERIPH_NO_RESET, tegra_clk_extern1),
MUX8("extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, TEGRA_PERIPH_NO_RESET, tegra_clk_extern2),
MUX8("extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, TEGRA_PERIPH_NO_RESET, tegra_clk_extern3),
MUX8("soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm),
MUX8("soc_therm", mux_clkm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm_8),
MUX8("vi_sensor", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 164, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor_8),
Expand Down
16 changes: 14 additions & 2 deletions drivers/clk/tegra/clk-tegra-super-cclk.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

#define SUPER_CDIV_ENB BIT(31)

#define TSENSOR_SLOWDOWN BIT(23)

static struct tegra_clk_super_mux *cclk_super;
static bool cclk_on_pllx;

Expand All @@ -47,10 +49,20 @@ static int cclk_super_set_rate(struct clk_hw *hw, unsigned long rate,
static unsigned long cclk_super_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
u32 val = readl_relaxed(super->reg);
unsigned int div2;

/* check whether thermal throttling is active */
if (val & TSENSOR_SLOWDOWN)
div2 = 1;
else
div2 = 0;

if (cclk_super_get_parent(hw) == PLLX_INDEX)
return parent_rate;
return parent_rate >> div2;

return tegra_clk_super_ops.recalc_rate(hw, parent_rate);
return tegra_clk_super_ops.recalc_rate(hw, parent_rate) >> div2;
}

static int cclk_super_determine_rate(struct clk_hw *hw,
Expand Down
6 changes: 3 additions & 3 deletions drivers/clk/tegra/clk-tegra20.c
Original file line number Diff line number Diff line change
Expand Up @@ -1021,9 +1021,9 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{ TEGRA20_CLK_PLL_P_OUT3, TEGRA20_CLK_CLK_MAX, 72000000, 1 },
{ TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1 },
{ TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 0 },
{ TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 240000000, 0 },
{ TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 240000000, 0 },
{ TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 240000000, 0 },
{ TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 120000000, 0 },
{ TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 120000000, 0 },
{ TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 120000000, 0 },
{ TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 0 },
{ TEGRA20_CLK_CSITE, TEGRA20_CLK_CLK_MAX, 0, 1 },
{ TEGRA20_CLK_CCLK, TEGRA20_CLK_CLK_MAX, 0, 1 },
Expand Down
6 changes: 3 additions & 3 deletions drivers/clk/tegra/clk-tegra30.c
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,7 @@ static void __init tegra30_super_clk_init(void)
/* CCLKG */
clk = tegra_clk_register_super_cclk("cclk_g", cclk_g_parents,
ARRAY_SIZE(cclk_g_parents),
CLK_SET_RATE_PARENT,
CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
clk_base + CCLKG_BURST_POLICY,
0, NULL);
clks[TEGRA30_CLK_CCLK_G] = clk;
Expand Down Expand Up @@ -1006,7 +1006,7 @@ static struct tegra_periph_init_data tegra_periph_clk_list[] = {
TEGRA_INIT_DATA_MUX("dam0", mux_pllacp_clkm, CLK_SOURCE_DAM0, 108, 0, TEGRA30_CLK_DAM0),
TEGRA_INIT_DATA_MUX("dam1", mux_pllacp_clkm, CLK_SOURCE_DAM1, 109, 0, TEGRA30_CLK_DAM1),
TEGRA_INIT_DATA_MUX("dam2", mux_pllacp_clkm, CLK_SOURCE_DAM2, 110, 0, TEGRA30_CLK_DAM2),
TEGRA_INIT_DATA_INT("3d2", mux_pllmcpa, CLK_SOURCE_3D2, 98, TEGRA_PERIPH_MANUAL_RESET, TEGRA30_CLK_GR3D2),
TEGRA_INIT_DATA_INT("3d2", mux_pllmcpa, CLK_SOURCE_3D2, 98, 0, TEGRA30_CLK_GR3D2),
TEGRA_INIT_DATA_INT("se", mux_pllpcm_clkm, CLK_SOURCE_SE, 127, 0, TEGRA30_CLK_SE),
TEGRA_INIT_DATA_MUX8("hdmi", mux_pllpmdacd2_clkm, CLK_SOURCE_HDMI, 51, 0, TEGRA30_CLK_HDMI),
TEGRA_INIT_DATA("pwm", NULL, NULL, pwm_parents, CLK_SOURCE_PWM, 28, 2, 0, 0, 8, 1, 0, 17, TEGRA_PERIPH_ON_APB, TEGRA30_CLK_PWM),
Expand Down Expand Up @@ -1245,7 +1245,7 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{ TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0 },
{ TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0 },
{ TEGRA30_CLK_PLL_U, TEGRA30_CLK_CLK_MAX, 480000000, 0 },
{ TEGRA30_CLK_VDE, TEGRA30_CLK_PLL_C, 600000000, 0 },
{ TEGRA30_CLK_VDE, TEGRA30_CLK_PLL_C, 300000000, 0 },
{ TEGRA30_CLK_SPDIF_IN_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
{ TEGRA30_CLK_I2S0_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
{ TEGRA30_CLK_I2S1_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
Expand Down
4 changes: 0 additions & 4 deletions drivers/clk/tegra/clk.h
Original file line number Diff line number Diff line change
Expand Up @@ -553,9 +553,6 @@ struct tegra_clk_periph_regs {
* Flags:
* TEGRA_PERIPH_NO_RESET - This flag indicates that reset is not allowed
* for this module.
* TEGRA_PERIPH_MANUAL_RESET - This flag indicates not to reset module
* after clock enable and driver for the module is responsible for
* doing reset.
* TEGRA_PERIPH_ON_APB - If peripheral is in the APB bus then read the
* bus to flush the write operation in apb bus. This flag indicates
* that this peripheral is in apb bus.
Expand All @@ -577,7 +574,6 @@ struct tegra_clk_periph_gate {
#define TEGRA_CLK_PERIPH_GATE_MAGIC 0x17760309

#define TEGRA_PERIPH_NO_RESET BIT(0)
#define TEGRA_PERIPH_MANUAL_RESET BIT(1)
#define TEGRA_PERIPH_ON_APB BIT(2)
#define TEGRA_PERIPH_WAR_1005168 BIT(3)
#define TEGRA_PERIPH_NO_DIV BIT(4)
Expand Down
3 changes: 2 additions & 1 deletion drivers/iommu/arm/arm-smmu/arm-smmu-impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu)
if (of_property_read_bool(np, "calxeda,smmu-secure-config-access"))
smmu->impl = &calxeda_impl;

if (of_device_is_compatible(np, "nvidia,tegra194-smmu"))
if (of_device_is_compatible(np, "nvidia,tegra194-smmu") ||
of_device_is_compatible(np, "nvidia,tegra186-smmu"))
return nvidia_smmu_impl_init(smmu);

smmu = qcom_smmu_impl_init(smmu);
Expand Down
Loading

0 comments on commit 1eb5f83

Please sign in to comment.