Commit 148edd50 authored by Stephen Boyd's avatar Stephen Boyd
Browse files

Merge tag 'meson-clk-4.20-1' of https://github.com/BayLibre/clk-meson into clk-meson

Pull meson clk driver updates from Jerome Brunet:

 - clk-pll driver improvements and updates
 - add axg audio controller system clocks
 - drop mpll3 from the possible pcie clock parent of the axg
 - register meson8b clock controller early

* tag 'meson-clk-4.20-1' of https://github.com/BayLibre/clk-meson:
  clk: meson: meson8b: use the regmap in the internal reset controller
  clk: meson: meson8b: register the clock controller early
  clk: meson-axg: pcie: drop the mpll3 clock parent
  clk: meson: axg: round audio system master clocks down
  clk: meson: clk-pll: drop hard-coded rates from pll tables
  clk: meson: clk-pll: remove od parameters
  clk: meson: clk-pll: drop CLK_GET_RATE_NOCACHE where unnecessary
  clk: meson: clk-pll: add enable bit
parents 5b394b2d 93c873d6
Loading
Loading
Loading
Loading
+23 −11
Original line number Diff line number Diff line
@@ -101,10 +101,16 @@ static const char * const mst_mux_parent_names[] = {
	"axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7",
};

#define AXG_MST_MCLK_MUX(_name, _reg)					\
	AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \
#define AXG_MST_MUX(_name, _reg, _flag)				\
	AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, _flag,		\
		    mst_mux_parent_names, CLK_SET_RATE_PARENT)

#define AXG_MST_MCLK_MUX(_name, _reg)				\
	AXG_MST_MUX(_name, _reg, CLK_MUX_ROUND_CLOSEST)

#define AXG_MST_SYS_MUX(_name, _reg)				\
	AXG_MST_MUX(_name, _reg, 0)

static AXG_MST_MCLK_MUX(mst_a_mclk,   AUDIO_MCLK_A_CTRL);
static AXG_MST_MCLK_MUX(mst_b_mclk,   AUDIO_MCLK_B_CTRL);
static AXG_MST_MCLK_MUX(mst_c_mclk,   AUDIO_MCLK_C_CTRL);
@@ -112,14 +118,20 @@ static AXG_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL);
static AXG_MST_MCLK_MUX(mst_e_mclk,   AUDIO_MCLK_E_CTRL);
static AXG_MST_MCLK_MUX(mst_f_mclk,   AUDIO_MCLK_F_CTRL);
static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
static AXG_MST_MCLK_MUX(spdifin_clk,  AUDIO_CLK_SPDIFIN_CTRL);
static AXG_MST_MCLK_MUX(pdm_dclk,     AUDIO_CLK_PDMIN_CTRL0);
static AXG_MST_MCLK_MUX(pdm_sysclk,   AUDIO_CLK_PDMIN_CTRL1);
static AXG_MST_SYS_MUX(spdifin_clk,   AUDIO_CLK_SPDIFIN_CTRL);
static AXG_MST_SYS_MUX(pdm_sysclk,    AUDIO_CLK_PDMIN_CTRL1);

#define AXG_MST_MCLK_DIV(_name, _reg)					\
	AXG_AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \
#define AXG_MST_DIV(_name, _reg, _flag)				\
	AXG_AUD_DIV(_name##_div, _reg, 0, 16, _flag,		\
		    "axg_"#_name"_sel", CLK_SET_RATE_PARENT)	\

#define AXG_MST_MCLK_DIV(_name, _reg)				\
	AXG_MST_DIV(_name, _reg, CLK_DIVIDER_ROUND_CLOSEST)

#define AXG_MST_SYS_DIV(_name, _reg)				\
	AXG_MST_DIV(_name, _reg, 0)

static AXG_MST_MCLK_DIV(mst_a_mclk,   AUDIO_MCLK_A_CTRL);
static AXG_MST_MCLK_DIV(mst_b_mclk,   AUDIO_MCLK_B_CTRL);
static AXG_MST_MCLK_DIV(mst_c_mclk,   AUDIO_MCLK_C_CTRL);
@@ -127,9 +139,9 @@ static AXG_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL);
static AXG_MST_MCLK_DIV(mst_e_mclk,   AUDIO_MCLK_E_CTRL);
static AXG_MST_MCLK_DIV(mst_f_mclk,   AUDIO_MCLK_F_CTRL);
static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
static AXG_MST_MCLK_DIV(spdifin_clk,  AUDIO_CLK_SPDIFIN_CTRL);
static AXG_MST_MCLK_DIV(pdm_dclk,     AUDIO_CLK_PDMIN_CTRL0);
static AXG_MST_MCLK_DIV(pdm_sysclk,   AUDIO_CLK_PDMIN_CTRL1);
static AXG_MST_SYS_DIV(spdifin_clk,   AUDIO_CLK_SPDIFIN_CTRL);
static AXG_MST_SYS_DIV(pdm_sysclk,    AUDIO_CLK_PDMIN_CTRL1);

#define AXG_MST_MCLK_GATE(_name, _reg)				\
	AXG_AUD_GATE(_name, _reg, 31,  "axg_"#_name"_div",	\
+189 −143
Original line number Diff line number Diff line
@@ -22,8 +22,13 @@

static DEFINE_SPINLOCK(meson_clk_lock);

static struct clk_regmap axg_fixed_pll = {
static struct clk_regmap axg_fixed_pll_dco = {
	.data = &(struct meson_clk_pll_data){
		.en = {
			.reg_off = HHI_MPLL_CNTL,
			.shift   = 30,
			.width   = 1,
		},
		.m = {
			.reg_off = HHI_MPLL_CNTL,
			.shift   = 0,
@@ -34,11 +39,6 @@ static struct clk_regmap axg_fixed_pll = {
			.shift   = 9,
			.width   = 5,
		},
		.od = {
			.reg_off = HHI_MPLL_CNTL,
			.shift   = 16,
			.width   = 2,
		},
		.frac = {
			.reg_off = HHI_MPLL_CNTL2,
			.shift   = 0,
@@ -56,15 +56,39 @@ static struct clk_regmap axg_fixed_pll = {
		},
	},
	.hw.init = &(struct clk_init_data){
		.name = "fixed_pll",
		.name = "fixed_pll_dco",
		.ops = &meson_clk_pll_ro_ops,
		.parent_names = (const char *[]){ "xtal" },
		.num_parents = 1,
	},
};

static struct clk_regmap axg_sys_pll = {
static struct clk_regmap axg_fixed_pll = {
	.data = &(struct clk_regmap_div_data){
		.offset = HHI_MPLL_CNTL,
		.shift = 16,
		.width = 2,
		.flags = CLK_DIVIDER_POWER_OF_TWO,
	},
	.hw.init = &(struct clk_init_data){
		.name = "fixed_pll",
		.ops = &clk_regmap_divider_ro_ops,
		.parent_names = (const char *[]){ "fixed_pll_dco" },
		.num_parents = 1,
		/*
		 * This clock won't ever change at runtime so
		 * CLK_SET_RATE_PARENT is not required
		 */
	},
};

static struct clk_regmap axg_sys_pll_dco = {
	.data = &(struct meson_clk_pll_data){
		.en = {
			.reg_off = HHI_SYS_PLL_CNTL,
			.shift   = 30,
			.width   = 1,
		},
		.m = {
			.reg_off = HHI_SYS_PLL_CNTL,
			.shift   = 0,
@@ -75,11 +99,6 @@ static struct clk_regmap axg_sys_pll = {
			.shift   = 9,
			.width   = 5,
		},
		.od = {
			.reg_off = HHI_SYS_PLL_CNTL,
			.shift   = 16,
			.width   = 2,
		},
		.l = {
			.reg_off = HHI_SYS_PLL_CNTL,
			.shift   = 31,
@@ -92,102 +111,59 @@ static struct clk_regmap axg_sys_pll = {
		},
	},
	.hw.init = &(struct clk_init_data){
		.name = "sys_pll",
		.name = "sys_pll_dco",
		.ops = &meson_clk_pll_ro_ops,
		.parent_names = (const char *[]){ "xtal" },
		.num_parents = 1,
		.flags = CLK_GET_RATE_NOCACHE,
	},
};

static const struct pll_rate_table axg_gp0_pll_rate_table[] = {
	PLL_RATE(240000000, 40, 1, 2),
	PLL_RATE(246000000, 41, 1, 2),
	PLL_RATE(252000000, 42, 1, 2),
	PLL_RATE(258000000, 43, 1, 2),
	PLL_RATE(264000000, 44, 1, 2),
	PLL_RATE(270000000, 45, 1, 2),
	PLL_RATE(276000000, 46, 1, 2),
	PLL_RATE(282000000, 47, 1, 2),
	PLL_RATE(288000000, 48, 1, 2),
	PLL_RATE(294000000, 49, 1, 2),
	PLL_RATE(300000000, 50, 1, 2),
	PLL_RATE(306000000, 51, 1, 2),
	PLL_RATE(312000000, 52, 1, 2),
	PLL_RATE(318000000, 53, 1, 2),
	PLL_RATE(324000000, 54, 1, 2),
	PLL_RATE(330000000, 55, 1, 2),
	PLL_RATE(336000000, 56, 1, 2),
	PLL_RATE(342000000, 57, 1, 2),
	PLL_RATE(348000000, 58, 1, 2),
	PLL_RATE(354000000, 59, 1, 2),
	PLL_RATE(360000000, 60, 1, 2),
	PLL_RATE(366000000, 61, 1, 2),
	PLL_RATE(372000000, 62, 1, 2),
	PLL_RATE(378000000, 63, 1, 2),
	PLL_RATE(384000000, 64, 1, 2),
	PLL_RATE(390000000, 65, 1, 3),
	PLL_RATE(396000000, 66, 1, 3),
	PLL_RATE(402000000, 67, 1, 3),
	PLL_RATE(408000000, 68, 1, 3),
	PLL_RATE(480000000, 40, 1, 1),
	PLL_RATE(492000000, 41, 1, 1),
	PLL_RATE(504000000, 42, 1, 1),
	PLL_RATE(516000000, 43, 1, 1),
	PLL_RATE(528000000, 44, 1, 1),
	PLL_RATE(540000000, 45, 1, 1),
	PLL_RATE(552000000, 46, 1, 1),
	PLL_RATE(564000000, 47, 1, 1),
	PLL_RATE(576000000, 48, 1, 1),
	PLL_RATE(588000000, 49, 1, 1),
	PLL_RATE(600000000, 50, 1, 1),
	PLL_RATE(612000000, 51, 1, 1),
	PLL_RATE(624000000, 52, 1, 1),
	PLL_RATE(636000000, 53, 1, 1),
	PLL_RATE(648000000, 54, 1, 1),
	PLL_RATE(660000000, 55, 1, 1),
	PLL_RATE(672000000, 56, 1, 1),
	PLL_RATE(684000000, 57, 1, 1),
	PLL_RATE(696000000, 58, 1, 1),
	PLL_RATE(708000000, 59, 1, 1),
	PLL_RATE(720000000, 60, 1, 1),
	PLL_RATE(732000000, 61, 1, 1),
	PLL_RATE(744000000, 62, 1, 1),
	PLL_RATE(756000000, 63, 1, 1),
	PLL_RATE(768000000, 64, 1, 1),
	PLL_RATE(780000000, 65, 1, 1),
	PLL_RATE(792000000, 66, 1, 1),
	PLL_RATE(804000000, 67, 1, 1),
	PLL_RATE(816000000, 68, 1, 1),
	PLL_RATE(960000000, 40, 1, 0),
	PLL_RATE(984000000, 41, 1, 0),
	PLL_RATE(1008000000, 42, 1, 0),
	PLL_RATE(1032000000, 43, 1, 0),
	PLL_RATE(1056000000, 44, 1, 0),
	PLL_RATE(1080000000, 45, 1, 0),
	PLL_RATE(1104000000, 46, 1, 0),
	PLL_RATE(1128000000, 47, 1, 0),
	PLL_RATE(1152000000, 48, 1, 0),
	PLL_RATE(1176000000, 49, 1, 0),
	PLL_RATE(1200000000, 50, 1, 0),
	PLL_RATE(1224000000, 51, 1, 0),
	PLL_RATE(1248000000, 52, 1, 0),
	PLL_RATE(1272000000, 53, 1, 0),
	PLL_RATE(1296000000, 54, 1, 0),
	PLL_RATE(1320000000, 55, 1, 0),
	PLL_RATE(1344000000, 56, 1, 0),
	PLL_RATE(1368000000, 57, 1, 0),
	PLL_RATE(1392000000, 58, 1, 0),
	PLL_RATE(1416000000, 59, 1, 0),
	PLL_RATE(1440000000, 60, 1, 0),
	PLL_RATE(1464000000, 61, 1, 0),
	PLL_RATE(1488000000, 62, 1, 0),
	PLL_RATE(1512000000, 63, 1, 0),
	PLL_RATE(1536000000, 64, 1, 0),
	PLL_RATE(1560000000, 65, 1, 0),
	PLL_RATE(1584000000, 66, 1, 0),
	PLL_RATE(1608000000, 67, 1, 0),
	PLL_RATE(1632000000, 68, 1, 0),
static struct clk_regmap axg_sys_pll = {
	.data = &(struct clk_regmap_div_data){
		.offset = HHI_SYS_PLL_CNTL,
		.shift = 16,
		.width = 2,
		.flags = CLK_DIVIDER_POWER_OF_TWO,
	},
	.hw.init = &(struct clk_init_data){
		.name = "sys_pll",
		.ops = &clk_regmap_divider_ro_ops,
		.parent_names = (const char *[]){ "sys_pll_dco" },
		.num_parents = 1,
		.flags = CLK_SET_RATE_PARENT,
	},
};

static const struct pll_params_table axg_gp0_pll_params_table[] = {
	PLL_PARAMS(40, 1),
	PLL_PARAMS(41, 1),
	PLL_PARAMS(42, 1),
	PLL_PARAMS(43, 1),
	PLL_PARAMS(44, 1),
	PLL_PARAMS(45, 1),
	PLL_PARAMS(46, 1),
	PLL_PARAMS(47, 1),
	PLL_PARAMS(48, 1),
	PLL_PARAMS(49, 1),
	PLL_PARAMS(50, 1),
	PLL_PARAMS(51, 1),
	PLL_PARAMS(52, 1),
	PLL_PARAMS(53, 1),
	PLL_PARAMS(54, 1),
	PLL_PARAMS(55, 1),
	PLL_PARAMS(56, 1),
	PLL_PARAMS(57, 1),
	PLL_PARAMS(58, 1),
	PLL_PARAMS(59, 1),
	PLL_PARAMS(60, 1),
	PLL_PARAMS(61, 1),
	PLL_PARAMS(62, 1),
	PLL_PARAMS(63, 1),
	PLL_PARAMS(64, 1),
	PLL_PARAMS(65, 1),
	PLL_PARAMS(66, 1),
	PLL_PARAMS(67, 1),
	PLL_PARAMS(68, 1),
	{ /* sentinel */ },
};

@@ -197,11 +173,15 @@ static const struct reg_sequence axg_gp0_init_regs[] = {
	{ .reg = HHI_GP0_PLL_CNTL3,	.def = 0x0a59a288 },
	{ .reg = HHI_GP0_PLL_CNTL4,	.def = 0xc000004d },
	{ .reg = HHI_GP0_PLL_CNTL5,	.def = 0x00078000 },
	{ .reg = HHI_GP0_PLL_CNTL,	.def = 0x40010250 },
};

static struct clk_regmap axg_gp0_pll = {
static struct clk_regmap axg_gp0_pll_dco = {
	.data = &(struct meson_clk_pll_data){
		.en = {
			.reg_off = HHI_GP0_PLL_CNTL,
			.shift   = 30,
			.width   = 1,
		},
		.m = {
			.reg_off = HHI_GP0_PLL_CNTL,
			.shift   = 0,
@@ -212,11 +192,6 @@ static struct clk_regmap axg_gp0_pll = {
			.shift   = 9,
			.width   = 5,
		},
		.od = {
			.reg_off = HHI_GP0_PLL_CNTL,
			.shift   = 16,
			.width   = 2,
		},
		.frac = {
			.reg_off = HHI_GP0_PLL_CNTL1,
			.shift   = 0,
@@ -232,29 +207,49 @@ static struct clk_regmap axg_gp0_pll = {
			.shift   = 29,
			.width   = 1,
		},
		.table = axg_gp0_pll_rate_table,
		.table = axg_gp0_pll_params_table,
		.init_regs = axg_gp0_init_regs,
		.init_count = ARRAY_SIZE(axg_gp0_init_regs),
	},
	.hw.init = &(struct clk_init_data){
		.name = "gp0_pll",
		.name = "gp0_pll_dco",
		.ops = &meson_clk_pll_ops,
		.parent_names = (const char *[]){ "xtal" },
		.num_parents = 1,
	},
};

static struct clk_regmap axg_gp0_pll = {
	.data = &(struct clk_regmap_div_data){
		.offset = HHI_GP0_PLL_CNTL,
		.shift = 16,
		.width = 2,
		.flags = CLK_DIVIDER_POWER_OF_TWO,
	},
	.hw.init = &(struct clk_init_data){
		.name = "gp0_pll",
		.ops = &clk_regmap_divider_ops,
		.parent_names = (const char *[]){ "gp0_pll_dco" },
		.num_parents = 1,
		.flags = CLK_SET_RATE_PARENT,
	},
};

static const struct reg_sequence axg_hifi_init_regs[] = {
	{ .reg = HHI_HIFI_PLL_CNTL1,	.def = 0xc084b000 },
	{ .reg = HHI_HIFI_PLL_CNTL2,	.def = 0xb75020be },
	{ .reg = HHI_HIFI_PLL_CNTL3,	.def = 0x0a6a3a88 },
	{ .reg = HHI_HIFI_PLL_CNTL4,	.def = 0xc000004d },
	{ .reg = HHI_HIFI_PLL_CNTL5,	.def = 0x00058000 },
	{ .reg = HHI_HIFI_PLL_CNTL,	.def = 0x40010250 },
};

static struct clk_regmap axg_hifi_pll = {
static struct clk_regmap axg_hifi_pll_dco = {
	.data = &(struct meson_clk_pll_data){
		.en = {
			.reg_off = HHI_HIFI_PLL_CNTL,
			.shift   = 30,
			.width   = 1,
		},
		.m = {
			.reg_off = HHI_HIFI_PLL_CNTL,
			.shift   = 0,
@@ -265,11 +260,6 @@ static struct clk_regmap axg_hifi_pll = {
			.shift   = 9,
			.width   = 5,
		},
		.od = {
			.reg_off = HHI_HIFI_PLL_CNTL,
			.shift   = 16,
			.width   = 2,
		},
		.frac = {
			.reg_off = HHI_HIFI_PLL_CNTL5,
			.shift   = 0,
@@ -285,19 +275,35 @@ static struct clk_regmap axg_hifi_pll = {
			.shift   = 29,
			.width   = 1,
		},
		.table = axg_gp0_pll_rate_table,
		.table = axg_gp0_pll_params_table,
		.init_regs = axg_hifi_init_regs,
		.init_count = ARRAY_SIZE(axg_hifi_init_regs),
		.flags = CLK_MESON_PLL_ROUND_CLOSEST,
	},
	.hw.init = &(struct clk_init_data){
		.name = "hifi_pll",
		.name = "hifi_pll_dco",
		.ops = &meson_clk_pll_ops,
		.parent_names = (const char *[]){ "xtal" },
		.num_parents = 1,
	},
};

static struct clk_regmap axg_hifi_pll = {
	.data = &(struct clk_regmap_div_data){
		.offset = HHI_HIFI_PLL_CNTL,
		.shift = 16,
		.width = 2,
		.flags = CLK_DIVIDER_POWER_OF_TWO,
	},
	.hw.init = &(struct clk_init_data){
		.name = "hifi_pll",
		.ops = &clk_regmap_divider_ops,
		.parent_names = (const char *[]){ "hifi_pll_dco" },
		.num_parents = 1,
		.flags = CLK_SET_RATE_PARENT,
	},
};

static struct clk_fixed_factor axg_fclk_div2_div = {
	.mult = 1,
	.div = 2,
@@ -625,29 +631,31 @@ static struct clk_regmap axg_mpll3 = {
	},
};

static const struct pll_rate_table axg_pcie_pll_rate_table[] = {
static const struct pll_params_table axg_pcie_pll_params_table[] = {
	{
		.rate	= 100000000,
		.m = 200,
		.n = 3,
		.od	= 1,
		.od2	= 3,
	},
	{ /* sentinel */ },
};

static const struct reg_sequence axg_pcie_init_regs[] = {
	{ .reg = HHI_PCIE_PLL_CNTL,	.def = 0x400106c8 },
	{ .reg = HHI_PCIE_PLL_CNTL1,	.def = 0x0084a2aa },
	{ .reg = HHI_PCIE_PLL_CNTL2,	.def = 0xb75020be },
	{ .reg = HHI_PCIE_PLL_CNTL3,	.def = 0x0a47488e },
	{ .reg = HHI_PCIE_PLL_CNTL4,	.def = 0xc000004d },
	{ .reg = HHI_PCIE_PLL_CNTL5,	.def = 0x00078000 },
	{ .reg = HHI_PCIE_PLL_CNTL6,	.def = 0x002323c6 },
	{ .reg = HHI_PCIE_PLL_CNTL,     .def = 0x400106c8 },
};

static struct clk_regmap axg_pcie_pll = {
static struct clk_regmap axg_pcie_pll_dco = {
	.data = &(struct meson_clk_pll_data){
		.en = {
			.reg_off = HHI_PCIE_PLL_CNTL,
			.shift   = 30,
			.width   = 1,
		},
		.m = {
			.reg_off = HHI_PCIE_PLL_CNTL,
			.shift   = 0,
@@ -658,16 +666,6 @@ static struct clk_regmap axg_pcie_pll = {
			.shift   = 9,
			.width   = 5,
		},
		.od = {
			.reg_off = HHI_PCIE_PLL_CNTL,
			.shift   = 16,
			.width   = 2,
		},
		.od2 = {
			.reg_off = HHI_PCIE_PLL_CNTL6,
			.shift   = 6,
			.width   = 2,
		},
		.frac = {
			.reg_off = HHI_PCIE_PLL_CNTL1,
			.shift   = 0,
@@ -683,29 +681,63 @@ static struct clk_regmap axg_pcie_pll = {
			.shift   = 29,
			.width   = 1,
		},
		.table = axg_pcie_pll_rate_table,
		.table = axg_pcie_pll_params_table,
		.init_regs = axg_pcie_init_regs,
		.init_count = ARRAY_SIZE(axg_pcie_init_regs),
	},
	.hw.init = &(struct clk_init_data){
		.name = "pcie_pll",
		.name = "pcie_pll_dco",
		.ops = &meson_clk_pll_ops,
		.parent_names = (const char *[]){ "xtal" },
		.num_parents = 1,
	},
};

static struct clk_regmap axg_pcie_pll_od = {
	.data = &(struct clk_regmap_div_data){
		.offset = HHI_PCIE_PLL_CNTL,
		.shift = 16,
		.width = 2,
		.flags = CLK_DIVIDER_POWER_OF_TWO,
	},
	.hw.init = &(struct clk_init_data){
		.name = "pcie_pll_od",
		.ops = &clk_regmap_divider_ops,
		.parent_names = (const char *[]){ "pcie_pll_dco" },
		.num_parents = 1,
		.flags = CLK_SET_RATE_PARENT,
	},
};

static struct clk_regmap axg_pcie_pll = {
	.data = &(struct clk_regmap_div_data){
		.offset = HHI_PCIE_PLL_CNTL6,
		.shift = 6,
		.width = 2,
		.flags = CLK_DIVIDER_POWER_OF_TWO,
	},
	.hw.init = &(struct clk_init_data){
		.name = "pcie_pll",
		.ops = &clk_regmap_divider_ops,
		.parent_names = (const char *[]){ "pcie_pll_od" },
		.num_parents = 1,
		.flags = CLK_SET_RATE_PARENT,
	},
};

static struct clk_regmap axg_pcie_mux = {
	.data = &(struct clk_regmap_mux_data){
		.offset = HHI_PCIE_PLL_CNTL6,
		.mask = 0x1,
		.shift = 2,
		/* skip the parent mpll3, reserved for debug */
		.table = (u32[]){ 1 },
	},
	.hw.init = &(struct clk_init_data){
		.name = "pcie_mux",
		.ops = &clk_regmap_mux_ops,
		.parent_names = (const char *[]){ "mpll3", "pcie_pll" },
		.num_parents = 2,
		.parent_names = (const char *[]){ "pcie_pll" },
		.num_parents = 1,
		.flags = CLK_SET_RATE_PARENT,
	},
};
@@ -1107,6 +1139,12 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = {
		[CLKID_GEN_CLK_SEL]		= &axg_gen_clk_sel.hw,
		[CLKID_GEN_CLK_DIV]		= &axg_gen_clk_div.hw,
		[CLKID_GEN_CLK]			= &axg_gen_clk.hw,
		[CLKID_SYS_PLL_DCO]		= &axg_sys_pll_dco.hw,
		[CLKID_FIXED_PLL_DCO]		= &axg_fixed_pll_dco.hw,
		[CLKID_GP0_PLL_DCO]		= &axg_gp0_pll_dco.hw,
		[CLKID_HIFI_PLL_DCO]		= &axg_hifi_pll_dco.hw,
		[CLKID_PCIE_PLL_DCO]		= &axg_pcie_pll_dco.hw,
		[CLKID_PCIE_PLL_OD]		= &axg_pcie_pll_od.hw,
		[NR_CLKS]			= NULL,
	},
	.num = NR_CLKS,
@@ -1185,6 +1223,8 @@ static struct clk_regmap *const axg_clk_regmaps[] = {
	&axg_fclk_div4,
	&axg_fclk_div5,
	&axg_fclk_div7,
	&axg_pcie_pll_dco,
	&axg_pcie_pll_od,
	&axg_pcie_pll,
	&axg_pcie_mux,
	&axg_pcie_ref,
@@ -1194,6 +1234,12 @@ static struct clk_regmap *const axg_clk_regmaps[] = {
	&axg_gen_clk_sel,
	&axg_gen_clk_div,
	&axg_gen_clk,
	&axg_fixed_pll_dco,
	&axg_sys_pll_dco,
	&axg_gp0_pll_dco,
	&axg_hifi_pll_dco,
	&axg_pcie_pll_dco,
	&axg_pcie_pll_od,
};

static const struct of_device_id clkc_match_table[] = {
+7 −1
Original line number Diff line number Diff line
@@ -133,8 +133,14 @@
#define CLKID_PCIE_REF				78
#define CLKID_GEN_CLK_SEL			82
#define CLKID_GEN_CLK_DIV			83
#define CLKID_SYS_PLL_DCO			85
#define CLKID_FIXED_PLL_DCO			86
#define CLKID_GP0_PLL_DCO			87
#define CLKID_HIFI_PLL_DCO			88
#define CLKID_PCIE_PLL_DCO			89
#define CLKID_PCIE_PLL_OD			90

#define NR_CLKS					85
#define NR_CLKS					91

/* include the CLKIDs that have been made part of the DT binding */
#include <dt-bindings/clock/axg-clkc.h>
+101 −55
Original line number Diff line number Diff line
@@ -11,15 +11,19 @@
 * In the most basic form, a Meson PLL is composed as follows:
 *
 *                     PLL
 *      +------------------------------+
 *        +--------------------------------+
 *        |                                |
 * in -----[ /N ]---[ *M ]---[ >>OD ]----->> out
 *      |         ^        ^           |
 *      +------------------------------+
 *        |             +--+               |
 *  in >>-----[ /N ]--->|  |      +-----+  |
 *        |             |  |------| DCO |---->> out
 *        |  +--------->|  |      +--v--+  |
 *        |  |          +--+         |     |
 *        |  |                       |     |
 *        |  +--[ *(M + (F/Fmax) ]<--+     |
 *        |                                |
 *               FREF     VCO
 *        +--------------------------------+
 *
 * out = in * (m + frac / frac_max) / (n << sum(ods))
 * out = in * (m + frac / frac_max) / n
 */

#include <linux/clk-provider.h>
@@ -41,12 +45,11 @@ meson_clk_pll_data(struct clk_regmap *clk)
}

static unsigned long __pll_params_to_rate(unsigned long parent_rate,
					  const struct pll_rate_table *pllt,
					  const struct pll_params_table *pllt,
					  u16 frac,
					  struct meson_clk_pll_data *pll)
{
	u64 rate = (u64)parent_rate * pllt->m;
	unsigned int od = pllt->od + pllt->od2 + pllt->od3;

	if (frac && MESON_PARM_APPLICABLE(&pll->frac)) {
		u64 frac_rate = (u64)parent_rate * frac;
@@ -55,7 +58,7 @@ static unsigned long __pll_params_to_rate(unsigned long parent_rate,
					 (1 << pll->frac.width));
	}

	return DIV_ROUND_UP_ULL(rate, pllt->n << od);
	return DIV_ROUND_UP_ULL(rate, pllt->n);
}

static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
@@ -63,20 +66,11 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
{
	struct clk_regmap *clk = to_clk_regmap(hw);
	struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
	struct pll_rate_table pllt;
	struct pll_params_table pllt;
	u16 frac;

	pllt.n = meson_parm_read(clk->map, &pll->n);
	pllt.m = meson_parm_read(clk->map, &pll->m);
	pllt.od = meson_parm_read(clk->map, &pll->od);

	pllt.od2 = MESON_PARM_APPLICABLE(&pll->od2) ?
		meson_parm_read(clk->map, &pll->od2) :
		0;

	pllt.od3 = MESON_PARM_APPLICABLE(&pll->od3) ?
		meson_parm_read(clk->map, &pll->od3) :
		0;

	frac = MESON_PARM_APPLICABLE(&pll->frac) ?
		meson_parm_read(clk->map, &pll->frac) :
@@ -87,14 +81,12 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,

static u16 __pll_params_with_frac(unsigned long rate,
				  unsigned long parent_rate,
				  const struct pll_rate_table *pllt,
				  const struct pll_params_table *pllt,
				  struct meson_clk_pll_data *pll)
{
	u16 frac_max = (1 << pll->frac.width);
	u64 val = (u64)rate * pllt->n;

	val <<= pllt->od + pllt->od2 + pllt->od3;

	if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST)
		val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate);
	else
@@ -105,29 +97,50 @@ static u16 __pll_params_with_frac(unsigned long rate,
	return min((u16)val, (u16)(frac_max - 1));
}

static const struct pll_rate_table *
static bool meson_clk_pll_is_better(unsigned long rate,
				    unsigned long best,
				    unsigned long now,
				    struct meson_clk_pll_data *pll)
{
	if (!(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) ||
	    MESON_PARM_APPLICABLE(&pll->frac)) {
		/* Round down */
		if (now < rate && best < now)
			return true;
	} else {
		/* Round Closest */
		if (abs(now - rate) < abs(best - rate))
			return true;
	}

	return false;
}

static const struct pll_params_table *
meson_clk_get_pll_settings(unsigned long rate,
			   unsigned long parent_rate,
			   struct meson_clk_pll_data *pll)
{
	const struct pll_rate_table *table = pll->table;
	unsigned int i = 0;
	const struct pll_params_table *table = pll->table;
	unsigned long best = 0, now = 0;
	unsigned int i, best_i = 0;

	if (!table)
		return NULL;

	/* Find the first table element exceeding rate */
	while (table[i].rate && table[i].rate <= rate)
		i++;
	for (i = 0; table[i].n; i++) {
		now = __pll_params_to_rate(parent_rate, &table[i], 0, pll);

	if (i != 0) {
		if (MESON_PARM_APPLICABLE(&pll->frac) ||
		    !(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) ||
		    (abs(rate - table[i - 1].rate) <
		     abs(rate - table[i].rate)))
			i--;
		/* If we get an exact match, don't bother any further */
		if (now == rate) {
			return &table[i];
		} else if (meson_clk_pll_is_better(rate, best, now, pll)) {
			best = now;
			best_i = i;
		}
	}

	return (struct pll_rate_table *)&table[i];
	return (struct pll_params_table *)&table[best_i];
}

static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -135,16 +148,18 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
{
	struct clk_regmap *clk = to_clk_regmap(hw);
	struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
	const struct pll_rate_table *pllt =
		meson_clk_get_pll_settings(rate, pll);
	const struct pll_params_table *pllt =
		meson_clk_get_pll_settings(rate, *parent_rate, pll);
	unsigned long round;
	u16 frac;

	if (!pllt)
		return meson_clk_pll_recalc_rate(hw, *parent_rate);

	if (!MESON_PARM_APPLICABLE(&pll->frac)
	    || rate == pllt->rate)
		return pllt->rate;
	round = __pll_params_to_rate(*parent_rate, pllt, 0, pll);

	if (!MESON_PARM_APPLICABLE(&pll->frac) || rate == round)
		return round;

	/*
	 * The rate provided by the setting is not an exact match, let's
@@ -185,12 +200,45 @@ static void meson_clk_pll_init(struct clk_hw *hw)
	}
}

static int meson_clk_pll_enable(struct clk_hw *hw)
{
	struct clk_regmap *clk = to_clk_regmap(hw);
	struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);

	/* Make sure the pll is in reset */
	meson_parm_write(clk->map, &pll->rst, 1);

	/* Enable the pll */
	meson_parm_write(clk->map, &pll->en, 1);

	/* Take the pll out reset */
	meson_parm_write(clk->map, &pll->rst, 0);

	if (meson_clk_pll_wait_lock(hw))
		return -EIO;

	return 0;
}

static void meson_clk_pll_disable(struct clk_hw *hw)
{
	struct clk_regmap *clk = to_clk_regmap(hw);
	struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);

	/* Put the pll is in reset */
	meson_parm_write(clk->map, &pll->rst, 1);

	/* Disable the pll */
	meson_parm_write(clk->map, &pll->en, 0);
}

static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
				  unsigned long parent_rate)
{
	struct clk_regmap *clk = to_clk_regmap(hw);
	struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
	const struct pll_rate_table *pllt;
	const struct pll_params_table *pllt;
	unsigned int enabled;
	unsigned long old_rate;
	u16 frac = 0;

@@ -199,32 +247,28 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,

	old_rate = rate;

	pllt = meson_clk_get_pll_settings(rate, pll);
	pllt = meson_clk_get_pll_settings(rate, parent_rate, pll);
	if (!pllt)
		return -EINVAL;

	/* Put the pll in reset to write the params */
	meson_parm_write(clk->map, &pll->rst, 1);
	enabled = meson_parm_read(clk->map, &pll->en);
	if (enabled)
		meson_clk_pll_disable(hw);

	meson_parm_write(clk->map, &pll->n, pllt->n);
	meson_parm_write(clk->map, &pll->m, pllt->m);
	meson_parm_write(clk->map, &pll->od, pllt->od);

	if (MESON_PARM_APPLICABLE(&pll->od2))
		meson_parm_write(clk->map, &pll->od2, pllt->od2);

	if (MESON_PARM_APPLICABLE(&pll->od3))
		meson_parm_write(clk->map, &pll->od3, pllt->od3);

	if (MESON_PARM_APPLICABLE(&pll->frac)) {
		frac = __pll_params_with_frac(rate, parent_rate, pllt, pll);
		meson_parm_write(clk->map, &pll->frac, frac);
	}

	/* make sure the reset is cleared at this point */
	meson_parm_write(clk->map, &pll->rst, 0);
	/* If the pll is stopped, bail out now */
	if (!enabled)
		return 0;

	if (meson_clk_pll_wait_lock(hw)) {
	if (meson_clk_pll_enable(hw)) {
		pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
			__func__, old_rate);
		/*
@@ -244,6 +288,8 @@ const struct clk_ops meson_clk_pll_ops = {
	.recalc_rate	= meson_clk_pll_recalc_rate,
	.round_rate	= meson_clk_pll_round_rate,
	.set_rate	= meson_clk_pll_set_rate,
	.enable		= meson_clk_pll_enable,
	.disable	= meson_clk_pll_disable
};

const struct clk_ops meson_clk_pll_ro_ops = {
+4 −12
Original line number Diff line number Diff line
@@ -43,37 +43,29 @@ static inline void meson_parm_write(struct regmap *map, struct parm *p,
}


struct pll_rate_table {
	unsigned long	rate;
struct pll_params_table {
	u16		m;
	u16		n;
	u16		od;
	u16		od2;
	u16		od3;
};

#define PLL_RATE(_r, _m, _n, _od)					\
#define PLL_PARAMS(_m, _n)						\
	{								\
		.rate		= (_r),					\
		.m		= (_m),					\
		.n		= (_n),					\
		.od		= (_od),				\
	}

#define CLK_MESON_PLL_ROUND_CLOSEST	BIT(0)

struct meson_clk_pll_data {
	struct parm en;
	struct parm m;
	struct parm n;
	struct parm frac;
	struct parm od;
	struct parm od2;
	struct parm od3;
	struct parm l;
	struct parm rst;
	const struct reg_sequence *init_regs;
	unsigned int init_count;
	const struct pll_rate_table *table;
	const struct pll_params_table *table;
	u8 flags;
};

Loading