summaryrefslogtreecommitdiff
path: root/drivers/clk/mediatek
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/mediatek')
-rw-r--r--drivers/clk/mediatek/clk-mt8173.c50
-rw-r--r--drivers/clk/mediatek/clk-mtk.h6
-rw-r--r--drivers/clk/mediatek/clk-pll.c39
3 files changed, 75 insertions, 20 deletions
diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c
index 2e0f17be9ea0..90eff85f4285 100644
--- a/drivers/clk/mediatek/clk-mt8173.c
+++ b/drivers/clk/mediatek/clk-mt8173.c
@@ -701,6 +701,22 @@ static const struct mtk_composite peri_clks[] __initconst = {
MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, 0x40c, 3, 1),
};
+static struct clk_onecell_data *mt8173_top_clk_data __initdata;
+static struct clk_onecell_data *mt8173_pll_clk_data __initdata;
+
+static void __init mtk_clk_enable_critical(void)
+{
+ if (!mt8173_top_clk_data || !mt8173_pll_clk_data)
+ return;
+
+ clk_prepare_enable(mt8173_pll_clk_data->clks[CLK_APMIXED_ARMCA15PLL]);
+ clk_prepare_enable(mt8173_pll_clk_data->clks[CLK_APMIXED_ARMCA7PLL]);
+ clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_MEM_SEL]);
+ clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_DDRPHYCFG_SEL]);
+ clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_CCI400_SEL]);
+ clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_RTC_SEL]);
+}
+
static void __init mtk_topckgen_init(struct device_node *node)
{
struct clk_onecell_data *clk_data;
@@ -713,19 +729,19 @@ static void __init mtk_topckgen_init(struct device_node *node)
return;
}
- clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
+ mt8173_top_clk_data = clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
mtk_clk_register_factors(root_clk_alias, ARRAY_SIZE(root_clk_alias), clk_data);
mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
&mt8173_clk_lock, clk_data);
- clk_prepare_enable(clk_data->clks[CLK_TOP_CCI400_SEL]);
-
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
pr_err("%s(): could not register clock provider: %d\n",
__func__, r);
+
+ mtk_clk_enable_critical();
}
CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt8173-topckgen", mtk_topckgen_init);
@@ -780,8 +796,9 @@ CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8173-pericfg", mtk_pericfg_init);
#define CON0_MT8173_RST_BAR BIT(24)
-#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, _pd_shift, \
- _tuner_reg, _pcw_reg, _pcw_shift) { \
+#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
+ _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \
+ _pcw_shift, _div_table) { \
.id = _id, \
.name = _name, \
.reg = _reg, \
@@ -796,14 +813,31 @@ CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8173-pericfg", mtk_pericfg_init);
.tuner_reg = _tuner_reg, \
.pcw_reg = _pcw_reg, \
.pcw_shift = _pcw_shift, \
+ .div_table = _div_table, \
}
+#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
+ _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \
+ _pcw_shift) \
+ PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
+ _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \
+ NULL)
+
+static const struct mtk_pll_div_table mmpll_div_table[] = {
+ { .div = 0, .freq = MT8173_PLL_FMAX },
+ { .div = 1, .freq = 1000000000 },
+ { .div = 2, .freq = 702000000 },
+ { .div = 3, .freq = 253500000 },
+ { .div = 4, .freq = 126750000 },
+ { } /* sentinel */
+};
+
static const struct mtk_pll_data plls[] = {
PLL(CLK_APMIXED_ARMCA15PLL, "armca15pll", 0x200, 0x20c, 0x00000001, 0, 21, 0x204, 24, 0x0, 0x204, 0),
PLL(CLK_APMIXED_ARMCA7PLL, "armca7pll", 0x210, 0x21c, 0x00000001, 0, 21, 0x214, 24, 0x0, 0x214, 0),
PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x220, 0x22c, 0xf0000101, HAVE_RST_BAR, 21, 0x220, 4, 0x0, 0x224, 0),
PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x230, 0x23c, 0xfe000001, HAVE_RST_BAR, 7, 0x230, 4, 0x0, 0x234, 14),
- PLL(CLK_APMIXED_MMPLL, "mmpll", 0x240, 0x24c, 0x00000001, 0, 21, 0x244, 24, 0x0, 0x244, 0),
+ PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x240, 0x24c, 0x00000001, 0, 21, 0x244, 24, 0x0, 0x244, 0, mmpll_div_table),
PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x250, 0x25c, 0x00000001, 0, 21, 0x250, 4, 0x0, 0x254, 0),
PLL(CLK_APMIXED_VENCPLL, "vencpll", 0x260, 0x26c, 0x00000001, 0, 21, 0x260, 4, 0x0, 0x264, 0),
PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x270, 0x27c, 0x00000001, 0, 21, 0x270, 4, 0x0, 0x274, 0),
@@ -819,13 +853,13 @@ static void __init mtk_apmixedsys_init(struct device_node *node)
{
struct clk_onecell_data *clk_data;
- clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
+ mt8173_pll_clk_data = clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
if (!clk_data)
return;
mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
- clk_prepare_enable(clk_data->clks[CLK_APMIXED_ARMCA15PLL]);
+ mtk_clk_enable_critical();
}
CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8173-apmixedsys",
mtk_apmixedsys_init);
diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
index 624716c4776b..c5cbecb3d218 100644
--- a/drivers/clk/mediatek/clk-mtk.h
+++ b/drivers/clk/mediatek/clk-mtk.h
@@ -135,6 +135,11 @@ struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
#define HAVE_RST_BAR BIT(0)
+struct mtk_pll_div_table {
+ u32 div;
+ unsigned long freq;
+};
+
struct mtk_pll_data {
int id;
const char *name;
@@ -151,6 +156,7 @@ struct mtk_pll_data {
int pcwbits;
uint32_t pcw_reg;
int pcw_shift;
+ const struct mtk_pll_div_table *div_table;
};
void __init mtk_clk_register_plls(struct device_node *node,
diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c
index 44409e98c52f..622e7b6c62b4 100644
--- a/drivers/clk/mediatek/clk-pll.c
+++ b/drivers/clk/mediatek/clk-pll.c
@@ -90,20 +90,23 @@ static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin,
static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw,
int postdiv)
{
- u32 con1, pd, val;
+ u32 con1, val;
int pll_en;
- /* set postdiv */
- pd = readl(pll->pd_addr);
- pd &= ~(POSTDIV_MASK << pll->data->pd_shift);
- pd |= (ffs(postdiv) - 1) << pll->data->pd_shift;
- writel(pd, pll->pd_addr);
-
pll_en = readl(pll->base_addr + REG_CON0) & CON0_BASE_EN;
- /* set pcw */
- val = readl(pll->pcw_addr);
+ /* set postdiv */
+ val = readl(pll->pd_addr);
+ val &= ~(POSTDIV_MASK << pll->data->pd_shift);
+ val |= (ffs(postdiv) - 1) << pll->data->pd_shift;
+
+ /* postdiv and pcw need to set at the same time if on same register */
+ if (pll->pd_addr != pll->pcw_addr) {
+ writel(val, pll->pd_addr);
+ val = readl(pll->pcw_addr);
+ }
+ /* set pcw */
val &= ~GENMASK(pll->data->pcw_shift + pll->data->pcwbits - 1,
pll->data->pcw_shift);
val |= pcw << pll->data->pcw_shift;
@@ -135,16 +138,28 @@ static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv,
u32 freq, u32 fin)
{
unsigned long fmin = 1000 * MHZ;
+ const struct mtk_pll_div_table *div_table = pll->data->div_table;
u64 _pcw;
u32 val;
if (freq > pll->data->fmax)
freq = pll->data->fmax;
- for (val = 0; val < 4; val++) {
+ if (div_table) {
+ if (freq > div_table[0].freq)
+ freq = div_table[0].freq;
+
+ for (val = 0; div_table[val + 1].freq != 0; val++) {
+ if (freq > div_table[val + 1].freq)
+ break;
+ }
*postdiv = 1 << val;
- if (freq * *postdiv >= fmin)
- break;
+ } else {
+ for (val = 0; val < 5; val++) {
+ *postdiv = 1 << val;
+ if ((u64)freq * *postdiv >= fmin)
+ break;
+ }
}
/* _pcw = freq * postdiv / fin * 2^pcwfbits */