300 lines
9.3 KiB
C
300 lines
9.3 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright 2015-2016 Freescale Semiconductor, Inc.
|
|
* Copyright 2017-2018 NXP
|
|
*/
|
|
|
|
#include <linux/of_address.h>
|
|
#include <linux/clk.h>
|
|
#include <dt-bindings/clock/s32v234-clock.h>
|
|
|
|
#include "clk.h"
|
|
|
|
static void __iomem *mc_cgm0_base;
|
|
static void __iomem *mc_cgm1_base;
|
|
static void __iomem *mc_cgm2_base;
|
|
static void __iomem *mc_cgm3_base;
|
|
static void __iomem *mc_me_base;
|
|
static void __iomem *src_base;
|
|
|
|
DEFINE_SPINLOCK(s32v234_lock);
|
|
|
|
/* sources for multiplexer clocks, this is used multiple times */
|
|
PNAME(osc_sels) = {"firc", "fxosc", };
|
|
|
|
PNAME(sys_sels) = {"firc", "fxosc", "armpll_dfs0", };
|
|
|
|
PNAME(can_sels) = {"firc", "fxosc", "dummy",
|
|
"periphpll_phi0_div5", };
|
|
|
|
PNAME(lin_sels) = {"firc", "fxosc", "dummy",
|
|
"periphpll_phi0_div3", "dummy", "dummy",
|
|
"dummy", "dummy", "sys6",};
|
|
|
|
PNAME(sdhc_sels) = {"firc", "fxosc", "dummy",
|
|
"enetpll_dfs3",};
|
|
|
|
PNAME(enet_sels) = {"firc", "fxosc", "dummy",
|
|
"dummy", "enetpll_phi0",};
|
|
|
|
PNAME(enet_time_sels) = {"firc", "fxosc", "dummy",
|
|
"dummy", "enetpll_phi0",};
|
|
|
|
static struct clk *clk[S32V234_CLK_END];
|
|
static struct clk_onecell_data clk_data;
|
|
|
|
static void __init s32v234_clocks_init(struct device_node *mc_cgm0_node)
|
|
{
|
|
struct device_node *np;
|
|
|
|
clk[S32V234_CLK_DUMMY] = s32_clk_fixed("dummy", 0);
|
|
clk[S32V234_CLK_FXOSC] = s32_obtain_fixed_clock("fxosc", 0);
|
|
clk[S32V234_CLK_FIRC] = s32_obtain_fixed_clock("firc", 0);
|
|
|
|
np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_me");
|
|
mc_me_base = of_iomap(np, 0);
|
|
if (WARN_ON(!mc_me_base))
|
|
return;
|
|
|
|
np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-src");
|
|
src_base = of_iomap(np, 0);
|
|
if (WARN_ON(!src_base))
|
|
return;
|
|
|
|
np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_cgm1");
|
|
mc_cgm1_base = of_iomap(np, 0);
|
|
if (WARN_ON(!mc_cgm1_base))
|
|
return;
|
|
|
|
np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_cgm2");
|
|
mc_cgm2_base = of_iomap(np, 0);
|
|
if (WARN_ON(!mc_cgm2_base))
|
|
return;
|
|
|
|
np = of_find_compatible_node(NULL, NULL, "fsl,s32v234-mc_cgm3");
|
|
mc_cgm3_base = of_iomap(np, 0);
|
|
if (WARN_ON(!mc_cgm3_base))
|
|
return;
|
|
|
|
np = mc_cgm0_node;
|
|
mc_cgm0_base = of_iomap(np, 0);
|
|
if (WARN_ON(!mc_cgm0_base))
|
|
return;
|
|
|
|
enable_cpumodes_onperipheralconfig(mc_me_base, MC_ME_RUN_PCn_DRUN |
|
|
MC_ME_RUN_PCn_RUN0 |
|
|
MC_ME_RUN_PCn_RUN1 |
|
|
MC_ME_RUN_PCn_RUN2 |
|
|
MC_ME_RUN_PCn_RUN3,
|
|
0);
|
|
|
|
/* turn on XOSC and FIRC */
|
|
enable_clocks_sources(MC_ME_MODE_MC_MVRON, MC_ME_MODE_MC_XOSCON |
|
|
MC_ME_MODE_MC_FIRCON,
|
|
MC_ME_RUNn_MC(mc_me_base, 0));
|
|
|
|
/* transition the core to RUN0 mode */
|
|
entry_to_target_mode(mc_me_base, MC_ME_MCTL_RUN0);
|
|
|
|
clk[S32V234_CLK_ARMPLL_SRC_SEL] = s32_clk_mux("armpll_sel",
|
|
SRC_GPR1, SRC_GPR1_ARMPLL_SRC_SEL_OFFSET,
|
|
SRC_GPR1_XPLL_SRC_SEL_SIZE,
|
|
osc_sels, ARRAY_SIZE(osc_sels), &s32v234_lock);
|
|
|
|
clk[S32V234_CLK_PERIPHPLL_SRC_SEL] = s32_clk_mux("periphpll_sel",
|
|
SRC_GPR1, SRC_GPR1_PERIPHPLL_SRC_SEL_OFFSET,
|
|
SRC_GPR1_XPLL_SRC_SEL_SIZE,
|
|
osc_sels, ARRAY_SIZE(osc_sels), &s32v234_lock);
|
|
|
|
clk[S32V234_CLK_ENETPLL_SRC_SEL] = s32_clk_mux("enetpll_sel",
|
|
SRC_GPR1, SRC_GPR1_ENETPLL_SRC_SEL_OFFSET,
|
|
SRC_GPR1_XPLL_SRC_SEL_SIZE,
|
|
osc_sels, ARRAY_SIZE(osc_sels), &s32v234_lock);
|
|
|
|
/* ARM_PLL */
|
|
clk[S32V234_CLK_ARMPLL_VCO] = s32v234_clk_plldig(S32_PLLDIG_ARM,
|
|
"armpll_vco", "armpll_sel", ARMPLL_PLLDIG(mc_cgm0_base),
|
|
ARMPLL_PLLDIG_PLLDV_MFD, ARMPLL_PLLDIG_PLLDV_MFN,
|
|
ARMPLL_PLLDIG_PLLDV_RFDPHI0, ARMPLL_PLLDIG_PLLDV_RFDPHI1);
|
|
|
|
clk[S32V234_CLK_ARMPLL_PHI0] = s32v234_clk_plldig_phi(S32_PLLDIG_ARM,
|
|
"armpll_phi0", "armpll_vco",
|
|
ARMPLL_PLLDIG(mc_cgm0_base), 0);
|
|
|
|
clk[S32V234_CLK_ARMPLL_PHI1] = s32v234_clk_plldig_phi(S32_PLLDIG_ARM,
|
|
"armpll_phi1", "armpll_vco",
|
|
ARMPLL_PLLDIG(mc_cgm0_base), 1);
|
|
|
|
clk[S32V234_CLK_ARMPLL_DFS0] = s32v234_clk_dfs(S32_PLLDIG_ARM,
|
|
"armpll_dfs0", "armpll_phi1",
|
|
ARMPLL_PLLDIG_DFS(mc_cgm0_base), 0,
|
|
ARMPLL_PLLDIG_DFS0_MFN);
|
|
|
|
clk[S32V234_CLK_ARMPLL_DFS1] = s32v234_clk_dfs(S32_PLLDIG_ARM,
|
|
"armpll_dfs1", "armpll_phi1",
|
|
ARMPLL_PLLDIG_DFS(mc_cgm0_base), 1,
|
|
ARMPLL_PLLDIG_DFS1_MFN);
|
|
|
|
clk[S32V234_CLK_ARMPLL_DFS2] = s32v234_clk_dfs(S32_PLLDIG_ARM,
|
|
"armpll_dfs2", "armpll_phi1",
|
|
ARMPLL_PLLDIG_DFS(mc_cgm0_base), 2,
|
|
ARMPLL_PLLDIG_DFS2_MFN);
|
|
|
|
clk[S32V234_CLK_SYS_SEL] = s32_clk_mux("sys_sel",
|
|
MC_ME_RUNn_MC(mc_me_base, 0),
|
|
MC_ME_MODE_MC_SYSCLK_OFFSET,
|
|
MC_ME_MODE_MC_SYSCLK_SIZE,
|
|
sys_sels, ARRAY_SIZE(sys_sels), &s32v234_lock);
|
|
|
|
clk[S32V234_CLK_SYS3] = s32_clk_divider("sys3", "sys_sel",
|
|
CGM_SC_DCn(mc_cgm0_base, 0), MC_CGM_SC_DCn_PREDIV_OFFSET,
|
|
MC_CGM_SC_DCn_PREDIV_SIZE, &s32v234_lock);
|
|
|
|
clk[S32V234_CLK_SYS6] = s32_clk_divider("sys6", "sys_sel",
|
|
CGM_SC_DCn(mc_cgm0_base, 1), MC_CGM_SC_DCn_PREDIV_OFFSET,
|
|
MC_CGM_SC_DCn_PREDIV_SIZE, &s32v234_lock);
|
|
|
|
clk[S32V234_CLK_SYS6_DIV2] = s32_clk_divider("sys6_div2", "sys_sel",
|
|
CGM_SC_DCn(mc_cgm0_base, 2), MC_CGM_SC_DCn_PREDIV_OFFSET,
|
|
MC_CGM_SC_DCn_PREDIV_SIZE, &s32v234_lock);
|
|
|
|
/* PERIPH_PLL */
|
|
clk[S32V234_CLK_PERIPHPLL_VCO] = s32v234_clk_plldig(S32_PLLDIG_PERIPH,
|
|
"periphpll_vco", "periphpll_sel",
|
|
PERIPHPLL_PLLDIG(mc_cgm0_base),
|
|
PERIPHPLL_PLLDIG_PLLDV_MFD, PERIPHPLL_PLLDIG_PLLDV_MFN,
|
|
PERIPHPLL_PLLDIG_PLLDV_RFDPHI0,
|
|
PERIPHPLL_PLLDIG_PLLDV_RFDPHI1);
|
|
|
|
clk[S32V234_CLK_PERIPHPLL_PHI0] =
|
|
s32v234_clk_plldig_phi(S32_PLLDIG_PERIPH,
|
|
"periphpll_phi0", "periphpll_vco",
|
|
PERIPHPLL_PLLDIG(mc_cgm0_base), 0);
|
|
|
|
clk[S32V234_CLK_PERIPHPLL_PHI1] =
|
|
s32v234_clk_plldig_phi(S32_PLLDIG_PERIPH,
|
|
"periphpll_phi1", "periphpll_vco",
|
|
PERIPHPLL_PLLDIG(mc_cgm0_base), 1);
|
|
|
|
clk[S32V234_CLK_PERIPHPLL_PHI0_DIV3] = s32_clk_fixed_factor(
|
|
"periphpll_phi0_div3", "periphpll_phi0", 1, 3);
|
|
|
|
clk[S32V234_CLK_PERIPHPLL_PHI0_DIV5] = s32_clk_fixed_factor(
|
|
"periphpll_phi0_div5", "periphpll_phi0", 1, 5);
|
|
|
|
clk[S32V234_CLK_CAN_SEL] = s32_clk_mux("can_sel",
|
|
CGM_ACn_SC(mc_cgm0_base, 6),
|
|
MC_CGM_ACn_SEL_OFFSET,
|
|
MC_CGM_ACn_SEL_SIZE,
|
|
can_sels, ARRAY_SIZE(can_sels), &s32v234_lock);
|
|
|
|
/* CAN Clock */
|
|
clk[S32V234_CLK_CAN] = s32_clk_divider("can", "can_sel",
|
|
CGM_ACn_DCm(mc_cgm0_base, 6, 0),
|
|
MC_CGM_ACn_DCm_PREDIV_OFFSET,
|
|
MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock);
|
|
|
|
/* Lin Clock */
|
|
clk[S32V234_CLK_LIN_SEL] = s32_clk_mux("lin_sel",
|
|
CGM_ACn_SC(mc_cgm0_base, 3),
|
|
MC_CGM_ACn_SEL_OFFSET,
|
|
MC_CGM_ACn_SEL_SIZE,
|
|
lin_sels, ARRAY_SIZE(lin_sels), &s32v234_lock);
|
|
|
|
clk[S32V234_CLK_LIN] = s32_clk_divider("lin", "lin_sel",
|
|
CGM_ACn_DCm(mc_cgm0_base, 3, 0),
|
|
MC_CGM_ACn_DCm_PREDIV_OFFSET,
|
|
MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock);
|
|
|
|
clk[S32V234_CLK_LIN_IPG] = s32_clk_fixed_factor("lin_ipg",
|
|
"lin", 1, 2);
|
|
|
|
/* enable PERIPHPLL */
|
|
enable_clocks_sources(0, MC_ME_MODE_MC_PERIPHPLL,
|
|
MC_ME_RUNn_MC(mc_me_base, 0));
|
|
|
|
/* ENET_PLL */
|
|
clk[S32V234_CLK_ENETPLL_VCO] = s32v234_clk_plldig(S32_PLLDIG_ENET,
|
|
"enetpll_vco", "enetpll_sel", ENETPLL_PLLDIG(mc_cgm0_base),
|
|
ENETPLL_PLLDIG_PLLDV_MFD, ENETPLL_PLLDIG_PLLDV_MFN,
|
|
ENETPLL_PLLDIG_PLLDV_RFDPHI0, ENETPLL_PLLDIG_PLLDV_RFDPHI1);
|
|
|
|
clk[S32V234_CLK_ENETPLL_PHI0] = s32v234_clk_plldig_phi(S32_PLLDIG_ENET,
|
|
"enetpll_phi0", "enetpll_vco",
|
|
ENETPLL_PLLDIG(mc_cgm0_base), 0);
|
|
|
|
clk[S32V234_CLK_ENETPLL_PHI1] = s32v234_clk_plldig_phi(S32_PLLDIG_ENET,
|
|
"enetpll_phi1", "enetpll_vco",
|
|
ENETPLL_PLLDIG(mc_cgm0_base), 1);
|
|
|
|
clk[S32V234_CLK_ENETPLL_DFS0] = s32v234_clk_dfs(S32_PLLDIG_ENET,
|
|
"enetpll_dfs0", "enetpll_phi1",
|
|
ENETPLL_PLLDIG_DFS(mc_cgm0_base), 0,
|
|
ENETPLL_PLLDIG_DFS0_MFN);
|
|
|
|
clk[S32V234_CLK_ENETPLL_DFS1] = s32v234_clk_dfs(S32_PLLDIG_ENET,
|
|
"enetpll_dfs1", "enetpll_phi1",
|
|
ENETPLL_PLLDIG_DFS(mc_cgm0_base), 1,
|
|
ENETPLL_PLLDIG_DFS1_MFN);
|
|
|
|
clk[S32V234_CLK_ENETPLL_DFS2] = s32v234_clk_dfs(S32_PLLDIG_ENET,
|
|
"enetpll_dfs2", "enetpll_phi1",
|
|
ENETPLL_PLLDIG_DFS(mc_cgm0_base), 2,
|
|
ENETPLL_PLLDIG_DFS2_MFN);
|
|
|
|
clk[S32V234_CLK_ENETPLL_DFS3] = s32v234_clk_dfs(S32_PLLDIG_ENET,
|
|
"enetpll_dfs3", "enetpll_phi1",
|
|
ENETPLL_PLLDIG_DFS(mc_cgm0_base), 3,
|
|
ENETPLL_PLLDIG_DFS3_MFN);
|
|
|
|
/* ENET Clock */
|
|
clk[S32V234_CLK_ENET_SEL] = s32_clk_mux("enet_sel",
|
|
CGM_ACn_SC(mc_cgm2_base, 2),
|
|
MC_CGM_ACn_SEL_OFFSET,
|
|
MC_CGM_ACn_SEL_SIZE,
|
|
enet_sels, ARRAY_SIZE(enet_sels), &s32v234_lock);
|
|
|
|
clk[S32V234_CLK_ENET_TIME_SEL] = s32_clk_mux("enet_time_sel",
|
|
CGM_ACn_SC(mc_cgm0_base, 7),
|
|
MC_CGM_ACn_SEL_OFFSET,
|
|
MC_CGM_ACn_SEL_SIZE,
|
|
enet_time_sels, ARRAY_SIZE(enet_time_sels), &s32v234_lock);
|
|
|
|
clk[S32V234_CLK_ENET] = s32_clk_divider("enet", "enet_sel",
|
|
CGM_ACn_DCm(mc_cgm2_base, 2, 0),
|
|
MC_CGM_ACn_DCm_PREDIV_OFFSET,
|
|
MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock);
|
|
|
|
clk[S32V234_CLK_ENET_TIME] = s32_clk_divider("enet_time",
|
|
"enet_time_sel",
|
|
CGM_ACn_DCm(mc_cgm0_base, 7, 1),
|
|
MC_CGM_ACn_DCm_PREDIV_OFFSET,
|
|
MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock);
|
|
|
|
/* SDHC Clock */
|
|
clk[S32V234_CLK_SDHC_SEL] = s32_clk_mux("sdhc_sel",
|
|
CGM_ACn_SC(mc_cgm0_base, 15),
|
|
MC_CGM_ACn_SEL_OFFSET,
|
|
MC_CGM_ACn_SEL_SIZE,
|
|
sdhc_sels, ARRAY_SIZE(sdhc_sels), &s32v234_lock);
|
|
|
|
clk[S32V234_CLK_SDHC] = s32_clk_divider("sdhc", "sdhc_sel",
|
|
CGM_ACn_DCm(mc_cgm0_base, 15, 0),
|
|
MC_CGM_ACn_DCm_PREDIV_OFFSET,
|
|
MC_CGM_ACn_DCm_PREDIV_SIZE, &s32v234_lock);
|
|
|
|
/* set the system clock */
|
|
enable_sysclock(MC_ME_MODE_MC_SYSCLK(0x2),
|
|
MC_ME_RUNn_MC(mc_me_base, 0));
|
|
|
|
/* transition the core to RUN0 mode */
|
|
entry_to_target_mode(mc_me_base, MC_ME_MCTL_RUN0);
|
|
|
|
/* Add the clocks to provider list */
|
|
clk_data.clks = clk;
|
|
clk_data.clk_num = ARRAY_SIZE(clk);
|
|
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
|
}
|
|
|
|
CLK_OF_DECLARE(S32V234, "fsl,s32v234-mc_cgm0", s32v234_clocks_init);
|