From 3eb635f1ca2d25bd11a697f5bdb52ac3d08c240e Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Thu, 3 Jul 2014 01:56:45 +0200 Subject: clk: composite: support determine_rate using rate_ops->round_rate + mux_ops->set_parent In case the rate_hw does not implement determine_rate, but only round_rate we fallback to best_parent selection if mux_hw is present and support reparenting. This also fixes a rate calculation problem when using the standard div and mux ops, as in this case currently only the mux->determine_rate is used in the composite rate calculation. So when for example the composite clock has two parents at 600 and 800MHz, the requested rate is 75MHz, which the divider could provide, without this change the rate would be set 600MHz ignoring the divider completely. This may be way out of spec for the component. Signed-off-by: Boris BREZILLON Signed-off-by: Heiko Stuebner [heiko@sntech.de: fixed output return a rate instead of the diff] Acked-By: Max Schwarz Tested-By: Max Schwarz Tested-by: Gabriel Fernandez Signed-off-by: Mike Turquette diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 57a078e..9548bfc 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -64,11 +64,56 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, const struct clk_ops *mux_ops = composite->mux_ops; struct clk_hw *rate_hw = composite->rate_hw; struct clk_hw *mux_hw = composite->mux_hw; + struct clk *parent; + unsigned long parent_rate; + long tmp_rate, best_rate = 0; + unsigned long rate_diff; + unsigned long best_rate_diff = ULONG_MAX; + int i; if (rate_hw && rate_ops && rate_ops->determine_rate) { rate_hw->clk = hw->clk; return rate_ops->determine_rate(rate_hw, rate, best_parent_rate, best_parent_p); + } else if (rate_hw && rate_ops && rate_ops->round_rate && + mux_hw && mux_ops && mux_ops->set_parent) { + *best_parent_p = NULL; + + if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) { + *best_parent_p = clk_get_parent(mux_hw->clk); + *best_parent_rate = __clk_get_rate(*best_parent_p); + + return rate_ops->round_rate(rate_hw, rate, + best_parent_rate); + } + + for (i = 0; i < __clk_get_num_parents(mux_hw->clk); i++) { + parent = clk_get_parent_by_index(mux_hw->clk, i); + if (!parent) + continue; + + parent_rate = __clk_get_rate(parent); + + tmp_rate = rate_ops->round_rate(rate_hw, rate, + &parent_rate); + if (tmp_rate < 0) + continue; + + rate_diff = abs(rate - tmp_rate); + + if (!rate_diff || !*best_parent_p + || best_rate_diff > rate_diff) { + *best_parent_p = parent; + *best_parent_rate = parent_rate; + best_rate_diff = rate_diff; + best_rate = tmp_rate; + } + + if (!rate_diff) + return rate; + } + + return best_rate; } else if (mux_hw && mux_ops && mux_ops->determine_rate) { mux_hw->clk = hw->clk; return mux_ops->determine_rate(mux_hw, rate, best_parent_rate, @@ -196,7 +241,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name, composite->rate_hw = rate_hw; composite->rate_ops = rate_ops; clk_composite_ops->recalc_rate = clk_composite_recalc_rate; - if (rate_ops->determine_rate) + if (rate_ops->determine_rate || + (rate_ops->round_rate && clk_composite_ops->set_parent)) clk_composite_ops->determine_rate = clk_composite_determine_rate; } -- cgit v0.10.2 From 0c02cf2f1c2ffd75221b43bacb4f02a0e52e014b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Thu, 3 Jul 2014 01:57:30 +0200 Subject: clk: composite: allow read-only clocks This allows readl-only composite clocks by making mux_ops->set_parent and divider_ops->round_rate/set_rate optional. Signed-off-by: Heiko Stuebner Acked-By: Max Schwarz Tested-By: Max Schwarz Signed-off-by: Mike Turquette diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 9548bfc..faf7c32 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -207,7 +207,7 @@ struct clk *clk_register_composite(struct device *dev, const char *name, clk_composite_ops = &composite->ops; if (mux_hw && mux_ops) { - if (!mux_ops->get_parent || !mux_ops->set_parent) { + if (!mux_ops->get_parent) { clk = ERR_PTR(-EINVAL); goto err; } @@ -215,7 +215,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name, composite->mux_hw = mux_hw; composite->mux_ops = mux_ops; clk_composite_ops->get_parent = clk_composite_get_parent; - clk_composite_ops->set_parent = clk_composite_set_parent; + if (mux_ops->set_parent) + clk_composite_ops->set_parent = clk_composite_set_parent; if (mux_ops->determine_rate) clk_composite_ops->determine_rate = clk_composite_determine_rate; } @@ -232,10 +233,6 @@ struct clk *clk_register_composite(struct device *dev, const char *name, if (rate_ops->set_rate) { clk_composite_ops->set_rate = clk_composite_set_rate; } - } else { - WARN(rate_ops->set_rate, - "%s: missing round_rate op is required\n", - __func__); } composite->rate_hw = rate_hw; -- cgit v0.10.2 From 5a994e151f7c54a5fdeb07fe2fed4ed64b9321b8 Mon Sep 17 00:00:00 2001 From: Mike Turquette Date: Thu, 3 Jul 2014 01:58:14 +0200 Subject: clk: composite: improve rate_hw sanity check logic The function pointer population and sanity checking logic got a bit ugly with the advent of the .determine_rate callback. Clean it up. Signed-off-by: Mike Turquette diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index faf7c32..b9355da 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -226,21 +226,27 @@ struct clk *clk_register_composite(struct device *dev, const char *name, clk = ERR_PTR(-EINVAL); goto err; } + clk_composite_ops->recalc_rate = clk_composite_recalc_rate; - /* .round_rate is a prerequisite for .set_rate */ - if (rate_ops->round_rate) { - clk_composite_ops->round_rate = clk_composite_round_rate; - if (rate_ops->set_rate) { - clk_composite_ops->set_rate = clk_composite_set_rate; - } + if (rate_ops->determine_rate) + clk_composite_ops->determine_rate = + clk_composite_determine_rate; + else if (rate_ops->round_rate) + clk_composite_ops->round_rate = + clk_composite_round_rate; + + /* .set_rate requires either .round_rate or .determine_rate */ + if (rate_ops->set_rate) { + if (rate_ops->determine_rate || rate_ops->round_rate) + clk_composite_ops->set_rate = + clk_composite_set_rate; + else + WARN(1, "%s: missing round_rate op is required\n", + __func__); } composite->rate_hw = rate_hw; composite->rate_ops = rate_ops; - clk_composite_ops->recalc_rate = clk_composite_recalc_rate; - if (rate_ops->determine_rate || - (rate_ops->round_rate && clk_composite_ops->set_parent)) - clk_composite_ops->determine_rate = clk_composite_determine_rate; } if (gate_hw && gate_ops) { -- cgit v0.10.2 From a245fecbb8064641d9cc317b347b5bdb2b7a4bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Thu, 3 Jul 2014 01:58:39 +0200 Subject: clk: rockchip: add basic infrastructure for clock branches This adds infrastructure for registering clock branches. On Rockchip SoCs most clock branches are a combination of mux,divider and gate components, thus a composite clock is used when appropriate. Clock branches are supposed to be declared in an array using the COMPOSITE* or MUX, etc makros defined in the header and then registered using rockchip_clk_register_branches. Signed-off-by: Heiko Stuebner Acked-By: Max Schwarz Tested-By: Max Schwarz Signed-off-by: Mike Turquette diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 8d3aefa..0068a8b 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -3,3 +3,4 @@ # obj-y += clk-rockchip.o +obj-y += clk.o diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c new file mode 100644 index 0000000..aa15d5a --- /dev/null +++ b/drivers/clk/rockchip/clk.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2014 MundoReader S.L. + * Author: Heiko Stuebner + * + * based on + * + * samsung/clk.c + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * Copyright (c) 2013 Linaro Ltd. + * Author: Thomas Abraham + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include "clk.h" + +/** + * Register a clock branch. + * Most clock branches have a form like + * + * src1 --|--\ + * |M |--[GATE]-[DIV]- + * src2 --|--/ + * + * sometimes without one of those components. + */ +struct clk *rockchip_clk_register_branch(const char *name, + const char **parent_names, u8 num_parents, void __iomem *base, + int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags, + u8 div_shift, u8 div_width, u8 div_flags, + struct clk_div_table *div_table, int gate_offset, + u8 gate_shift, u8 gate_flags, unsigned long flags, + spinlock_t *lock) +{ + struct clk *clk; + struct clk_mux *mux = NULL; + struct clk_gate *gate = NULL; + struct clk_divider *div = NULL; + const struct clk_ops *mux_ops = NULL, *div_ops = NULL, + *gate_ops = NULL; + + if (num_parents > 1) { + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + + mux->reg = base + muxdiv_offset; + mux->shift = mux_shift; + mux->mask = BIT(mux_width) - 1; + mux->flags = mux_flags; + mux->lock = lock; + mux_ops = (mux_flags & CLK_MUX_READ_ONLY) ? &clk_mux_ro_ops + : &clk_mux_ops; + } + + if (gate_offset >= 0) { + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + gate->flags = gate_flags; + gate->reg = base + gate_offset; + gate->bit_idx = gate_shift; + gate->lock = lock; + gate_ops = &clk_gate_ops; + } + + if (div_width > 0) { + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) + return ERR_PTR(-ENOMEM); + + div->flags = div_flags; + div->reg = base + muxdiv_offset; + div->shift = div_shift; + div->width = div_width; + div->lock = lock; + div->table = div_table; + div_ops = (div_flags & CLK_DIVIDER_READ_ONLY) + ? &clk_divider_ro_ops + : &clk_divider_ops; + } + + clk = clk_register_composite(NULL, name, parent_names, num_parents, + mux ? &mux->hw : NULL, mux_ops, + div ? &div->hw : NULL, div_ops, + gate ? &gate->hw : NULL, gate_ops, + flags); + + return clk; +} + +static DEFINE_SPINLOCK(clk_lock); +static struct clk **clk_table; +static void __iomem *reg_base; +static struct clk_onecell_data clk_data; + +void __init rockchip_clk_init(struct device_node *np, void __iomem *base, + unsigned long nr_clks) +{ + reg_base = base; + + clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL); + if (!clk_table) + pr_err("%s: could not allocate clock lookup table\n", __func__); + + clk_data.clks = clk_table; + clk_data.clk_num = nr_clks; + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); +} + +void rockchip_clk_add_lookup(struct clk *clk, unsigned int id) +{ + if (clk_table && id) + clk_table[id] = clk; +} + +void __init rockchip_clk_register_branches( + struct rockchip_clk_branch *list, + unsigned int nr_clk) +{ + struct clk *clk = NULL; + unsigned int idx; + unsigned long flags; + + for (idx = 0; idx < nr_clk; idx++, list++) { + flags = list->flags; + + /* catch simple muxes */ + switch (list->branch_type) { + case branch_mux: + clk = clk_register_mux(NULL, list->name, + list->parent_names, list->num_parents, + flags, reg_base + list->muxdiv_offset, + list->mux_shift, list->mux_width, + list->mux_flags, &clk_lock); + break; + case branch_divider: + if (list->div_table) + clk = clk_register_divider_table(NULL, + list->name, list->parent_names[0], + flags, reg_base + list->muxdiv_offset, + list->div_shift, list->div_width, + list->div_flags, list->div_table, + &clk_lock); + else + clk = clk_register_divider(NULL, list->name, + list->parent_names[0], flags, + reg_base + list->muxdiv_offset, + list->div_shift, list->div_width, + list->div_flags, &clk_lock); + break; + case branch_fraction_divider: + /* unimplemented */ + continue; + break; + case branch_gate: + flags |= CLK_SET_RATE_PARENT; + + /* keep all gates untouched for now */ + flags |= CLK_IGNORE_UNUSED; + + clk = clk_register_gate(NULL, list->name, + list->parent_names[0], flags, + reg_base + list->gate_offset, + list->gate_shift, list->gate_flags, &clk_lock); + break; + case branch_composite: + /* keep all gates untouched for now */ + flags |= CLK_IGNORE_UNUSED; + + clk = rockchip_clk_register_branch(list->name, + list->parent_names, list->num_parents, + reg_base, list->muxdiv_offset, list->mux_shift, + list->mux_width, list->mux_flags, + list->div_shift, list->div_width, + list->div_flags, list->div_table, + list->gate_offset, list->gate_shift, + list->gate_flags, flags, &clk_lock); + break; + } + + /* none of the cases above matched */ + if (!clk) { + pr_err("%s: unknown clock type %d\n", + __func__, list->branch_type); + continue; + } + + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s: %ld\n", + __func__, list->name, PTR_ERR(clk)); + continue; + } + + rockchip_clk_add_lookup(clk, list->id); + } +} diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h new file mode 100644 index 0000000..5b051b0 --- /dev/null +++ b/drivers/clk/rockchip/clk.h @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2014 MundoReader S.L. + * Author: Heiko Stuebner + * + * based on + * + * samsung/clk.h + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * Copyright (c) 2013 Linaro Ltd. + * Author: Thomas Abraham + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef CLK_ROCKCHIP_CLK_H +#define CLK_ROCKCHIP_CLK_H + +#include +#include +#include + +#define HIWORD_UPDATE(val, mask, shift) \ + ((val) << (shift) | (mask) << ((shift) + 16)) + +/* register positions shared by RK2928, RK3066 and RK3188 */ +#define RK2928_PLL_CON(x) (x * 0x4) +#define RK2928_MODE_CON 0x40 +#define RK2928_CLKSEL_CON(x) (x * 0x4 + 0x44) +#define RK2928_CLKGATE_CON(x) (x * 0x4 + 0xd0) +#define RK2928_GLB_SRST_FST 0x100 +#define RK2928_GLB_SRST_SND 0x104 +#define RK2928_SOFTRST_CON(x) (x * 0x4 + 0x110) +#define RK2928_MISC_CON 0x134 + +#define PNAME(x) static const char *x[] __initconst + +enum rockchip_clk_branch_type { + branch_composite, + branch_mux, + branch_divider, + branch_fraction_divider, + branch_gate, +}; + +struct rockchip_clk_branch { + unsigned int id; + enum rockchip_clk_branch_type branch_type; + const char *name; + const char **parent_names; + u8 num_parents; + unsigned long flags; + int muxdiv_offset; + u8 mux_shift; + u8 mux_width; + u8 mux_flags; + u8 div_shift; + u8 div_width; + u8 div_flags; + struct clk_div_table *div_table; + int gate_offset; + u8 gate_shift; + u8 gate_flags; +}; + +#define COMPOSITE(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw,\ + df, go, gs, gf) \ + { \ + .id = _id, \ + .branch_type = branch_composite, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .flags = f, \ + .muxdiv_offset = mo, \ + .mux_shift = ms, \ + .mux_width = mw, \ + .mux_flags = mf, \ + .div_shift = ds, \ + .div_width = dw, \ + .div_flags = df, \ + .gate_offset = go, \ + .gate_shift = gs, \ + .gate_flags = gf, \ + } + +#define COMPOSITE_NOMUX(_id, cname, pname, f, mo, ds, dw, df, \ + go, gs, gf) \ + { \ + .id = _id, \ + .branch_type = branch_composite, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .flags = f, \ + .muxdiv_offset = mo, \ + .div_shift = ds, \ + .div_width = dw, \ + .div_flags = df, \ + .gate_offset = go, \ + .gate_shift = gs, \ + .gate_flags = gf, \ + } + +#define COMPOSITE_NOMUX_DIVTBL(_id, cname, pname, f, mo, ds, dw,\ + df, dt, go, gs, gf) \ + { \ + .id = _id, \ + .branch_type = branch_composite, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .flags = f, \ + .muxdiv_offset = mo, \ + .div_shift = ds, \ + .div_width = dw, \ + .div_flags = df, \ + .div_table = dt, \ + .gate_offset = go, \ + .gate_shift = gs, \ + .gate_flags = gf, \ + } + +#define COMPOSITE_NODIV(_id, cname, pnames, f, mo, ms, mw, mf, \ + go, gs, gf) \ + { \ + .id = _id, \ + .branch_type = branch_composite, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .flags = f, \ + .muxdiv_offset = mo, \ + .mux_shift = ms, \ + .mux_width = mw, \ + .mux_flags = mf, \ + .gate_offset = go, \ + .gate_shift = gs, \ + .gate_flags = gf, \ + } + +#define COMPOSITE_NOGATE(_id, cname, pnames, f, mo, ms, mw, mf, \ + ds, dw, df) \ + { \ + .id = _id, \ + .branch_type = branch_composite, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .flags = f, \ + .muxdiv_offset = mo, \ + .mux_shift = ms, \ + .mux_width = mw, \ + .mux_flags = mf, \ + .div_shift = ds, \ + .div_width = dw, \ + .div_flags = df, \ + .gate_offset = -1, \ + } + +#define COMPOSITE_FRAC(_id, cname, pname, f, mo, df, go, gs, gf)\ + { \ + .id = _id, \ + .branch_type = branch_fraction_divider, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .flags = f, \ + .muxdiv_offset = mo, \ + .div_shift = 16, \ + .div_width = 16, \ + .div_flags = df, \ + .gate_offset = go, \ + .gate_shift = gs, \ + .gate_flags = gf, \ + } + +#define MUX(_id, cname, pnames, f, o, s, w, mf) \ + { \ + .id = _id, \ + .branch_type = branch_mux, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .flags = f, \ + .muxdiv_offset = o, \ + .mux_shift = s, \ + .mux_width = w, \ + .mux_flags = mf, \ + .gate_offset = -1, \ + } + +#define DIV(_id, cname, pname, f, o, s, w, df) \ + { \ + .id = _id, \ + .branch_type = branch_divider, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .flags = f, \ + .muxdiv_offset = o, \ + .div_shift = s, \ + .div_width = w, \ + .div_flags = df, \ + .gate_offset = -1, \ + } + +#define DIVTBL(_id, cname, pname, f, o, s, w, df, dt) \ + { \ + .id = _id, \ + .branch_type = branch_divider, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .flags = f, \ + .muxdiv_offset = o, \ + .div_shift = s, \ + .div_width = w, \ + .div_flags = df, \ + .div_table = dt, \ + } + +#define GATE(_id, cname, pname, f, o, b, gf) \ + { \ + .id = _id, \ + .branch_type = branch_gate, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .flags = f, \ + .gate_offset = o, \ + .gate_shift = b, \ + .gate_flags = gf, \ + } + + +void rockchip_clk_init(struct device_node *np, void __iomem *base, + unsigned long nr_clks); +void rockchip_clk_add_lookup(struct clk *clk, unsigned int id); +void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list, + unsigned int nr_clk); + +#endif -- cgit v0.10.2 From 90c590254051f511299538c158e12fdad41ce163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Thu, 3 Jul 2014 01:59:10 +0200 Subject: clk: rockchip: add clock type for pll clocks and pll used on rk3066 All known Rockchip SoCs down to the RK28xx (ARM9) use a similar pattern to handle their plls: |--\ xin32k ----------------|mux\ xin24m -----| pll |----|pll|--- pll output \---------------|src/ |--/ The pll output is sourced from 1 of 3 sources, the actual pll being one of them. To change the pll frequency it is imperative to remux it to another source beforehand. This is done by adding a clock-listener to the pll that handles the remuxing before and after the rate change. The output mux is implemented as a separate clock to make use of already existing common-clock features for disabling the pll if one of the other two sources is used. Signed-off-by: Heiko Stuebner Acked-By: Max Schwarz Tested-By: Max Schwarz Signed-off-by: Mike Turquette diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 0068a8b..2cb9164 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -4,3 +4,4 @@ obj-y += clk-rockchip.o obj-y += clk.o +obj-y += clk-pll.o diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c new file mode 100644 index 0000000..f2a1c7a --- /dev/null +++ b/drivers/clk/rockchip/clk-pll.c @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2014 MundoReader S.L. + * Author: Heiko Stuebner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "clk.h" + +#define PLL_MODE_MASK 0x3 +#define PLL_MODE_SLOW 0x0 +#define PLL_MODE_NORM 0x1 +#define PLL_MODE_DEEP 0x2 + +struct rockchip_clk_pll { + struct clk_hw hw; + + struct clk_mux pll_mux; + const struct clk_ops *pll_mux_ops; + + struct notifier_block clk_nb; + bool rate_change_remuxed; + + void __iomem *reg_base; + int lock_offset; + unsigned int lock_shift; + enum rockchip_pll_type type; + const struct rockchip_pll_rate_table *rate_table; + unsigned int rate_count; + spinlock_t *lock; +}; + +#define to_rockchip_clk_pll(_hw) container_of(_hw, struct rockchip_clk_pll, hw) +#define to_rockchip_clk_pll_nb(nb) \ + container_of(nb, struct rockchip_clk_pll, clk_nb) + +static const struct rockchip_pll_rate_table *rockchip_get_pll_settings( + struct rockchip_clk_pll *pll, unsigned long rate) +{ + const struct rockchip_pll_rate_table *rate_table = pll->rate_table; + int i; + + for (i = 0; i < pll->rate_count; i++) { + if (rate == rate_table[i].rate) + return &rate_table[i]; + } + + return NULL; +} + +static long rockchip_pll_round_rate(struct clk_hw *hw, + unsigned long drate, unsigned long *prate) +{ + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); + const struct rockchip_pll_rate_table *rate_table = pll->rate_table; + int i; + + /* Assumming rate_table is in descending order */ + for (i = 0; i < pll->rate_count; i++) { + if (drate >= rate_table[i].rate) + return rate_table[i].rate; + } + + /* return minimum supported value */ + return rate_table[i - 1].rate; +} + +/* + * Wait for the pll to reach the locked state. + * The calling set_rate function is responsible for making sure the + * grf regmap is available. + */ +static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll) +{ + struct regmap *grf = rockchip_clk_get_grf(); + unsigned int val; + int delay = 24000000, ret; + + while (delay > 0) { + ret = regmap_read(grf, pll->lock_offset, &val); + if (ret) { + pr_err("%s: failed to read pll lock status: %d\n", + __func__, ret); + return ret; + } + + if (val & BIT(pll->lock_shift)) + return 0; + delay--; + } + + pr_err("%s: timeout waiting for pll to lock\n", __func__); + return -ETIMEDOUT; +} + +/** + * Set pll mux when changing the pll rate. + * This makes sure to move the pll mux away from the actual pll before + * changing its rate and back to the original parent after the change. + */ +static int rockchip_pll_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct rockchip_clk_pll *pll = to_rockchip_clk_pll_nb(nb); + struct clk_mux *pll_mux = &pll->pll_mux; + const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; + int cur_parent; + + switch (event) { + case PRE_RATE_CHANGE: + cur_parent = pll_mux_ops->get_parent(&pll_mux->hw); + if (cur_parent == PLL_MODE_NORM) { + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW); + pll->rate_change_remuxed = 1; + } + break; + case POST_RATE_CHANGE: + if (pll->rate_change_remuxed) { + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM); + pll->rate_change_remuxed = 0; + } + break; + } + + return NOTIFY_OK; +} + +/** + * PLL used in RK3066, RK3188 and RK3288 + */ + +#define RK3066_PLL_RESET_DELAY(nr) ((nr * 500) / 24 + 1) + +#define RK3066_PLLCON(i) (i * 0x4) +#define RK3066_PLLCON0_OD_MASK 0xf +#define RK3066_PLLCON0_OD_SHIFT 0 +#define RK3066_PLLCON0_NR_MASK 0x3f +#define RK3066_PLLCON0_NR_SHIFT 8 +#define RK3066_PLLCON1_NF_MASK 0x1fff +#define RK3066_PLLCON1_NF_SHIFT 0 +#define RK3066_PLLCON2_BWADJ_MASK 0xfff +#define RK3066_PLLCON2_BWADJ_SHIFT 0 +#define RK3066_PLLCON3_RESET (1 << 5) +#define RK3066_PLLCON3_PWRDOWN (1 << 1) +#define RK3066_PLLCON3_BYPASS (1 << 0) + +static unsigned long rockchip_rk3066_pll_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); + u64 nf, nr, no, rate64 = prate; + u32 pllcon; + + pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(3)); + if (pllcon & RK3066_PLLCON3_BYPASS) { + pr_debug("%s: pll %s is bypassed\n", __func__, + __clk_get_name(hw->clk)); + return prate; + } + + pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(1)); + nf = (pllcon >> RK3066_PLLCON1_NF_SHIFT) & RK3066_PLLCON1_NF_MASK; + + pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(0)); + nr = (pllcon >> RK3066_PLLCON0_NR_SHIFT) & RK3066_PLLCON0_NR_MASK; + no = (pllcon >> RK3066_PLLCON0_OD_SHIFT) & RK3066_PLLCON0_OD_MASK; + + rate64 *= (nf + 1); + do_div(rate64, nr + 1); + do_div(rate64, no + 1); + + return (unsigned long)rate64; +} + +static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); + const struct rockchip_pll_rate_table *rate; + unsigned long old_rate = rockchip_rk3066_pll_recalc_rate(hw, prate); + struct regmap *grf = rockchip_clk_get_grf(); + int ret; + + if (IS_ERR(grf)) { + pr_debug("%s: grf regmap not available, aborting rate change\n", + __func__); + return PTR_ERR(grf); + } + + pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n", + __func__, __clk_get_name(hw->clk), old_rate, drate, prate); + + /* Get required rate settings from table */ + rate = rockchip_get_pll_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, __clk_get_name(hw->clk)); + return -EINVAL; + } + + pr_debug("%s: rate settings for %lu (nr, no, nf): (%d, %d, %d)\n", + __func__, rate->rate, rate->nr, rate->no, rate->nf); + + /* enter reset mode */ + writel(HIWORD_UPDATE(RK3066_PLLCON3_RESET, RK3066_PLLCON3_RESET, 0), + pll->reg_base + RK3066_PLLCON(3)); + + /* update pll values */ + writel(HIWORD_UPDATE(rate->nr - 1, RK3066_PLLCON0_NR_MASK, + RK3066_PLLCON0_NR_SHIFT) | + HIWORD_UPDATE(rate->no - 1, RK3066_PLLCON0_OD_MASK, + RK3066_PLLCON0_OD_SHIFT), + pll->reg_base + RK3066_PLLCON(0)); + + writel_relaxed(HIWORD_UPDATE(rate->nf - 1, RK3066_PLLCON1_NF_MASK, + RK3066_PLLCON1_NF_SHIFT), + pll->reg_base + RK3066_PLLCON(1)); + writel_relaxed(HIWORD_UPDATE(rate->bwadj, RK3066_PLLCON2_BWADJ_MASK, + RK3066_PLLCON2_BWADJ_SHIFT), + pll->reg_base + RK3066_PLLCON(2)); + + /* leave reset and wait the reset_delay */ + writel(HIWORD_UPDATE(0, RK3066_PLLCON3_RESET, 0), + pll->reg_base + RK3066_PLLCON(3)); + udelay(RK3066_PLL_RESET_DELAY(rate->nr)); + + /* wait for the pll to lock */ + ret = rockchip_pll_wait_lock(pll); + if (ret) { + pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", + __func__, old_rate); + rockchip_rk3066_pll_set_rate(hw, old_rate, prate); + } + + return ret; +} + +static int rockchip_rk3066_pll_enable(struct clk_hw *hw) +{ + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); + + writel(HIWORD_UPDATE(0, RK3066_PLLCON3_PWRDOWN, 0), + pll->reg_base + RK3066_PLLCON(3)); + + return 0; +} + +static void rockchip_rk3066_pll_disable(struct clk_hw *hw) +{ + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); + + writel(HIWORD_UPDATE(RK3066_PLLCON3_PWRDOWN, + RK3066_PLLCON3_PWRDOWN, 0), + pll->reg_base + RK3066_PLLCON(3)); +} + +static int rockchip_rk3066_pll_is_enabled(struct clk_hw *hw) +{ + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); + u32 pllcon = readl(pll->reg_base + RK3066_PLLCON(3)); + + return !(pllcon & RK3066_PLLCON3_PWRDOWN); +} + +static const struct clk_ops rockchip_rk3066_pll_clk_norate_ops = { + .recalc_rate = rockchip_rk3066_pll_recalc_rate, + .enable = rockchip_rk3066_pll_enable, + .disable = rockchip_rk3066_pll_disable, + .is_enabled = rockchip_rk3066_pll_is_enabled, +}; + +static const struct clk_ops rockchip_rk3066_pll_clk_ops = { + .recalc_rate = rockchip_rk3066_pll_recalc_rate, + .round_rate = rockchip_pll_round_rate, + .set_rate = rockchip_rk3066_pll_set_rate, + .enable = rockchip_rk3066_pll_enable, + .disable = rockchip_rk3066_pll_disable, + .is_enabled = rockchip_rk3066_pll_is_enabled, +}; + +/* + * Common registering of pll clocks + */ + +struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, + const char *name, const char **parent_names, u8 num_parents, + void __iomem *base, int con_offset, int grf_lock_offset, + int lock_shift, int mode_offset, int mode_shift, + struct rockchip_pll_rate_table *rate_table, + spinlock_t *lock) +{ + const char *pll_parents[3]; + struct clk_init_data init; + struct rockchip_clk_pll *pll; + struct clk_mux *pll_mux; + struct clk *pll_clk, *mux_clk; + char pll_name[20]; + int ret; + + if (num_parents != 2) { + pr_err("%s: needs two parent clocks\n", __func__); + return ERR_PTR(-EINVAL); + } + + /* name the actual pll */ + snprintf(pll_name, sizeof(pll_name), "pll_%s", name); + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = pll_name; + + /* keep all plls untouched for now */ + init.flags = CLK_IGNORE_UNUSED; + + init.parent_names = &parent_names[0]; + init.num_parents = 1; + + if (rate_table) { + int len; + + /* find count of rates in rate_table */ + for (len = 0; rate_table[len].rate != 0; ) + len++; + + pll->rate_count = len; + pll->rate_table = kmemdup(rate_table, + pll->rate_count * + sizeof(struct rockchip_pll_rate_table), + GFP_KERNEL); + WARN(!pll->rate_table, + "%s: could not allocate rate table for %s\n", + __func__, name); + } + + switch (pll_type) { + case pll_rk3066: + if (!pll->rate_table) + init.ops = &rockchip_rk3066_pll_clk_norate_ops; + else + init.ops = &rockchip_rk3066_pll_clk_ops; + break; + default: + pr_warn("%s: Unknown pll type for pll clk %s\n", + __func__, name); + } + + pll->hw.init = &init; + pll->type = pll_type; + pll->reg_base = base + con_offset; + pll->lock_offset = grf_lock_offset; + pll->lock_shift = lock_shift; + pll->lock = lock; + pll->clk_nb.notifier_call = rockchip_pll_notifier_cb; + + pll_clk = clk_register(NULL, &pll->hw); + if (IS_ERR(pll_clk)) { + pr_err("%s: failed to register pll clock %s : %ld\n", + __func__, name, PTR_ERR(pll_clk)); + mux_clk = pll_clk; + goto err_pll; + } + + ret = clk_notifier_register(pll_clk, &pll->clk_nb); + if (ret) { + pr_err("%s: failed to register clock notifier for %s : %d\n", + __func__, name, ret); + mux_clk = ERR_PTR(ret); + goto err_pll_notifier; + } + + /* create the mux on top of the real pll */ + pll->pll_mux_ops = &clk_mux_ops; + pll_mux = &pll->pll_mux; + + /* the actual muxing is xin24m, pll-output, xin32k */ + pll_parents[0] = parent_names[0]; + pll_parents[1] = pll_name; + pll_parents[2] = parent_names[1]; + + init.name = name; + init.flags = CLK_SET_RATE_PARENT; + init.ops = pll->pll_mux_ops; + init.parent_names = pll_parents; + init.num_parents = ARRAY_SIZE(pll_parents); + + pll_mux->reg = base + mode_offset; + pll_mux->shift = mode_shift; + pll_mux->mask = PLL_MODE_MASK; + pll_mux->flags = 0; + pll_mux->lock = lock; + pll_mux->hw.init = &init; + + if (pll_type == pll_rk3066) + pll_mux->flags |= CLK_MUX_HIWORD_MASK; + + mux_clk = clk_register(NULL, &pll_mux->hw); + if (IS_ERR(mux_clk)) + goto err_mux; + + return mux_clk; + +err_mux: + ret = clk_notifier_unregister(pll_clk, &pll->clk_nb); + if (ret) { + pr_err("%s: could not unregister clock notifier in error path : %d\n", + __func__, ret); + return mux_clk; + } +err_pll_notifier: + clk_unregister(pll_clk); +err_pll: + kfree(pll); + return mux_clk; +} diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index aa15d5a..278cf9d 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "clk.h" /** @@ -105,11 +107,15 @@ static DEFINE_SPINLOCK(clk_lock); static struct clk **clk_table; static void __iomem *reg_base; static struct clk_onecell_data clk_data; +static struct device_node *cru_node; +static struct regmap *grf; void __init rockchip_clk_init(struct device_node *np, void __iomem *base, unsigned long nr_clks) { reg_base = base; + cru_node = np; + grf = ERR_PTR(-EPROBE_DEFER); clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL); if (!clk_table) @@ -120,12 +126,41 @@ void __init rockchip_clk_init(struct device_node *np, void __iomem *base, of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); } +struct regmap *rockchip_clk_get_grf(void) +{ + if (IS_ERR(grf)) + grf = syscon_regmap_lookup_by_phandle(cru_node, "rockchip,grf"); + return grf; +} + void rockchip_clk_add_lookup(struct clk *clk, unsigned int id) { if (clk_table && id) clk_table[id] = clk; } +void __init rockchip_clk_register_plls(struct rockchip_pll_clock *list, + unsigned int nr_pll, int grf_lock_offset) +{ + struct clk *clk; + int idx; + + for (idx = 0; idx < nr_pll; idx++, list++) { + clk = rockchip_clk_register_pll(list->type, list->name, + list->parent_names, list->num_parents, + reg_base, list->con_offset, grf_lock_offset, + list->lock_shift, list->mode_offset, + list->mode_shift, list->rate_table, &clk_lock); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + list->name); + continue; + } + + rockchip_clk_add_lookup(clk, list->id); + } +} + void __init rockchip_clk_register_branches( struct rockchip_clk_branch *list, unsigned int nr_clk) diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 5b051b0..fb7ce85 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -40,6 +40,77 @@ #define RK2928_SOFTRST_CON(x) (x * 0x4 + 0x110) #define RK2928_MISC_CON 0x134 +enum rockchip_pll_type { + pll_rk3066, +}; + +#define RK3066_PLL_RATE(_rate, _nr, _nf, _no) \ +{ \ + .rate = _rate##U, \ + .nr = _nr, \ + .nf = _nf, \ + .no = _no, \ + .bwadj = (_nf >> 1), \ +} + +struct rockchip_pll_rate_table { + unsigned long rate; + unsigned int nr; + unsigned int nf; + unsigned int no; + unsigned int bwadj; +}; + +/** + * struct rockchip_pll_clock: information about pll clock + * @id: platform specific id of the clock. + * @name: name of this pll clock. + * @parent_name: name of the parent clock. + * @flags: optional flags for basic clock. + * @con_offset: offset of the register for configuring the PLL. + * @mode_offset: offset of the register for configuring the PLL-mode. + * @mode_shift: offset inside the mode-register for the mode of this pll. + * @lock_shift: offset inside the lock register for the lock status. + * @type: Type of PLL to be registered. + * @rate_table: Table of usable pll rates + */ +struct rockchip_pll_clock { + unsigned int id; + const char *name; + const char **parent_names; + u8 num_parents; + unsigned long flags; + int con_offset; + int mode_offset; + int mode_shift; + int lock_shift; + enum rockchip_pll_type type; + struct rockchip_pll_rate_table *rate_table; +}; + +#define PLL(_type, _id, _name, _pnames, _flags, _con, _mode, _mshift, \ + _lshift, _rtable) \ + { \ + .id = _id, \ + .type = _type, \ + .name = _name, \ + .parent_names = _pnames, \ + .num_parents = ARRAY_SIZE(_pnames), \ + .flags = CLK_GET_RATE_NOCACHE | _flags, \ + .con_offset = _con, \ + .mode_offset = _mode, \ + .mode_shift = _mshift, \ + .lock_shift = _lshift, \ + .rate_table = _rtable, \ + } + +struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, + const char *name, const char **parent_names, u8 num_parents, + void __iomem *base, int con_offset, int grf_lock_offset, + int lock_shift, int reg_mode, int mode_shift, + struct rockchip_pll_rate_table *rate_table, + spinlock_t *lock); + #define PNAME(x) static const char *x[] __initconst enum rockchip_clk_branch_type { @@ -243,8 +314,11 @@ struct rockchip_clk_branch { void rockchip_clk_init(struct device_node *np, void __iomem *base, unsigned long nr_clks); +struct regmap *rockchip_clk_get_grf(void); void rockchip_clk_add_lookup(struct clk *clk, unsigned int id); void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list, unsigned int nr_clk); +void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list, + unsigned int nr_pll, int grf_lock_offset); #endif -- cgit v0.10.2 From 85fa0c7f8d05eb6baf2c122e85d45d928df0992b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Thu, 3 Jul 2014 01:59:39 +0200 Subject: clk: rockchip: add reset controller All Rockchip SoCs at least down to the ARM9-based RK28xx include the reset- controller for SoC peripherals in their clock controller. While the older SoCs (ARM9 and Cortex-A8) use a regular scheme to change register values, the Cortex-A9 SoCs use a hiword-mask making locking unecessary. To be compatible with both schemes the reset controller takes a flag to decide which scheme to use, similar to the other HIWORD_MASK flags used in the clock framework. Signed-off-by: Heiko Stuebner Acked-By: Max Schwarz Tested-By: Max Schwarz Signed-off-by: Mike Turquette diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 2cb9164..85f8a55 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -5,3 +5,4 @@ obj-y += clk-rockchip.o obj-y += clk.o obj-y += clk-pll.o +obj-$(CONFIG_RESET_CONTROLLER) += softrst.o diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index fb7ce85..32c334d 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -321,4 +321,18 @@ void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list, void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list, unsigned int nr_pll, int grf_lock_offset); +#define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0) + +#ifdef CONFIG_RESET_CONTROLLER +void rockchip_register_softrst(struct device_node *np, + unsigned int num_regs, + void __iomem *base, u8 flags); +#else +static inline void rockchip_register_softrst(struct device_node *np, + unsigned int num_regs, + void __iomem *base, u8 flags) +{ +} +#endif + #endif diff --git a/drivers/clk/rockchip/softrst.c b/drivers/clk/rockchip/softrst.c new file mode 100644 index 0000000..552f7bb --- /dev/null +++ b/drivers/clk/rockchip/softrst.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2014 MundoReader S.L. + * Author: Heiko Stuebner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include "clk.h" + +struct rockchip_softrst { + struct reset_controller_dev rcdev; + void __iomem *reg_base; + int num_regs; + int num_per_reg; + u8 flags; + spinlock_t lock; +}; + +static int rockchip_softrst_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct rockchip_softrst *softrst = container_of(rcdev, + struct rockchip_softrst, + rcdev); + int bank = id / softrst->num_per_reg; + int offset = id % softrst->num_per_reg; + + if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) { + writel(BIT(offset) | (BIT(offset) << 16), + softrst->reg_base + (bank * 4)); + } else { + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&softrst->lock, flags); + + reg = readl(softrst->reg_base + (bank * 4)); + writel(reg | BIT(offset), softrst->reg_base + (bank * 4)); + + spin_unlock_irqrestore(&softrst->lock, flags); + } + + return 0; +} + +static int rockchip_softrst_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct rockchip_softrst *softrst = container_of(rcdev, + struct rockchip_softrst, + rcdev); + int bank = id / softrst->num_per_reg; + int offset = id % softrst->num_per_reg; + + if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) { + writel((BIT(offset) << 16), softrst->reg_base + (bank * 4)); + } else { + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&softrst->lock, flags); + + reg = readl(softrst->reg_base + (bank * 4)); + writel(reg & ~BIT(offset), softrst->reg_base + (bank * 4)); + + spin_unlock_irqrestore(&softrst->lock, flags); + } + + return 0; +} + +static struct reset_control_ops rockchip_softrst_ops = { + .assert = rockchip_softrst_assert, + .deassert = rockchip_softrst_deassert, +}; + +void __init rockchip_register_softrst(struct device_node *np, + unsigned int num_regs, + void __iomem *base, u8 flags) +{ + struct rockchip_softrst *softrst; + int ret; + + softrst = kzalloc(sizeof(*softrst), GFP_KERNEL); + if (!softrst) + return; + + spin_lock_init(&softrst->lock); + + softrst->reg_base = base; + softrst->flags = flags; + softrst->num_regs = num_regs; + softrst->num_per_reg = (flags & ROCKCHIP_SOFTRST_HIWORD_MASK) ? 16 + : 32; + + softrst->rcdev.owner = THIS_MODULE; + softrst->rcdev.nr_resets = num_regs * softrst->num_per_reg; + softrst->rcdev.ops = &rockchip_softrst_ops; + softrst->rcdev.of_node = np; + ret = reset_controller_register(&softrst->rcdev); + if (ret) { + pr_err("%s: could not register reset controller, %d\n", + __func__, ret); + kfree(softrst); + } +}; -- cgit v0.10.2 From 43aea81778e280a4e1d7ef144b3511bbc4aace11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Thu, 3 Jul 2014 02:00:44 +0200 Subject: dt-bindings: add documentation for rk3188 clock and reset unit This add bindings documentation for the clock and reset unit found on rk3188 and rk3066 SoCs from Rockchip. Also deprecate the old gate clock binding, as these shouldn't be used in the future. Signed-off-by: Heiko Stuebner Acked-By: Max Schwarz Tested-By: Max Schwarz Signed-off-by: Mike Turquette diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt new file mode 100644 index 0000000..0c2bf5e --- /dev/null +++ b/Documentation/devicetree/bindings/clock/rockchip,rk3188-cru.txt @@ -0,0 +1,61 @@ +* Rockchip RK3188/RK3066 Clock and Reset Unit + +The RK3188/RK3066 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: should be "rockchip,rk3188-cru", "rockchip,rk3188a-cru" or + "rockchip,rk3066a-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files" + If missing pll rates are not changable, due to the missing pll lock status. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/rk3188-cru.h and +dt-bindings/clock/rk3066-cru.h headers and can be used in device tree sources. +Similar macros exist for the reset sources in these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "xin32k" - rtc clock - optional, + - "xin27m" - 27mhz crystal input on rk3066 - optional, + - "ext_hsadc" - external HSADC clock - optional, + - "ext_cif0" - external camera clock - optional, + - "ext_rmii" - external RMII clock - optional, + - "ext_jtag" - externalJTAG clock - optional + +Example: Clock controller node: + + cru: cru@20000000 { + compatible = "rockchip,rk3188-cru"; + reg = <0x20000000 0x1000>; + rockchip,grf = <&grf>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@10124000 { + compatible = "snps,dw-apb-uart"; + reg = <0x10124000 0x400>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <1>; + clocks = <&cru SCLK_UART0>; + }; diff --git a/Documentation/devicetree/bindings/clock/rockchip.txt b/Documentation/devicetree/bindings/clock/rockchip.txt index a891c82..22f6769 100644 --- a/Documentation/devicetree/bindings/clock/rockchip.txt +++ b/Documentation/devicetree/bindings/clock/rockchip.txt @@ -6,6 +6,9 @@ This binding uses the common clock binding[1]. == Gate clocks == +These bindings are deprecated! +Please use the soc specific CRU bindings instead. + The gate registers form a continuos block which makes the dt node structure a matter of taste, as either all gates can be put into one gate clock spanning all registers or they can be divided into -- cgit v0.10.2 From 2c14736c75dba10d9da4c8337e1baee11577691c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Thu, 3 Jul 2014 02:01:14 +0200 Subject: clk: rockchip: add clock driver for rk3188 and rk3066 clocks This adds a clock driver that handles the specific muxes, dividers and gates of rk3188 and rk3066 SoCs. The structure of the clock list resembles the arrangement of their counterparts in the clock architecture diagrams found in the SoC documentation. Clocks exported to the clock provider are currently limited to well known or measured ones. So additional clock exports may be necessary in the future. Signed-off-by: Heiko Stuebner Acked-By: Max Schwarz Tested-By: Max Schwarz Signed-off-by: Mike Turquette diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 85f8a55..3eebf72 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -6,3 +6,5 @@ obj-y += clk-rockchip.o obj-y += clk.o obj-y += clk-pll.o obj-$(CONFIG_RESET_CONTROLLER) += softrst.o + +obj-y += clk-rk3188.o diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c new file mode 100644 index 0000000..a83a6d8 --- /dev/null +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -0,0 +1,672 @@ +/* + * Copyright (c) 2014 MundoReader S.L. + * Author: Heiko Stuebner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include "clk.h" + +#define RK3188_GRF_SOC_STATUS 0xac + +enum rk3188_plls { + apll, cpll, dpll, gpll, +}; + +struct rockchip_pll_rate_table rk3188_pll_rates[] = { + RK3066_PLL_RATE(2208000000, 1, 92, 1), + RK3066_PLL_RATE(2184000000, 1, 91, 1), + RK3066_PLL_RATE(2160000000, 1, 90, 1), + RK3066_PLL_RATE(2136000000, 1, 89, 1), + RK3066_PLL_RATE(2112000000, 1, 88, 1), + RK3066_PLL_RATE(2088000000, 1, 87, 1), + RK3066_PLL_RATE(2064000000, 1, 86, 1), + RK3066_PLL_RATE(2040000000, 1, 85, 1), + RK3066_PLL_RATE(2016000000, 1, 84, 1), + RK3066_PLL_RATE(1992000000, 1, 83, 1), + RK3066_PLL_RATE(1968000000, 1, 82, 1), + RK3066_PLL_RATE(1944000000, 1, 81, 1), + RK3066_PLL_RATE(1920000000, 1, 80, 1), + RK3066_PLL_RATE(1896000000, 1, 79, 1), + RK3066_PLL_RATE(1872000000, 1, 78, 1), + RK3066_PLL_RATE(1848000000, 1, 77, 1), + RK3066_PLL_RATE(1824000000, 1, 76, 1), + RK3066_PLL_RATE(1800000000, 1, 75, 1), + RK3066_PLL_RATE(1776000000, 1, 74, 1), + RK3066_PLL_RATE(1752000000, 1, 73, 1), + RK3066_PLL_RATE(1728000000, 1, 72, 1), + RK3066_PLL_RATE(1704000000, 1, 71, 1), + RK3066_PLL_RATE(1680000000, 1, 70, 1), + RK3066_PLL_RATE(1656000000, 1, 69, 1), + RK3066_PLL_RATE(1632000000, 1, 68, 1), + RK3066_PLL_RATE(1608000000, 1, 67, 1), + RK3066_PLL_RATE(1560000000, 1, 65, 1), + RK3066_PLL_RATE(1512000000, 1, 63, 1), + RK3066_PLL_RATE(1488000000, 1, 62, 1), + RK3066_PLL_RATE(1464000000, 1, 61, 1), + RK3066_PLL_RATE(1440000000, 1, 60, 1), + RK3066_PLL_RATE(1416000000, 1, 59, 1), + RK3066_PLL_RATE(1392000000, 1, 58, 1), + RK3066_PLL_RATE(1368000000, 1, 57, 1), + RK3066_PLL_RATE(1344000000, 1, 56, 1), + RK3066_PLL_RATE(1320000000, 1, 55, 1), + RK3066_PLL_RATE(1296000000, 1, 54, 1), + RK3066_PLL_RATE(1272000000, 1, 53, 1), + RK3066_PLL_RATE(1248000000, 1, 52, 1), + RK3066_PLL_RATE(1224000000, 1, 51, 1), + RK3066_PLL_RATE(1200000000, 1, 50, 1), + RK3066_PLL_RATE(1188000000, 2, 99, 1), + RK3066_PLL_RATE(1176000000, 1, 49, 1), + RK3066_PLL_RATE(1128000000, 1, 47, 1), + RK3066_PLL_RATE(1104000000, 1, 46, 1), + RK3066_PLL_RATE(1008000000, 1, 84, 2), + RK3066_PLL_RATE( 912000000, 1, 76, 2), + RK3066_PLL_RATE( 891000000, 8, 594, 2), + RK3066_PLL_RATE( 888000000, 1, 74, 2), + RK3066_PLL_RATE( 816000000, 1, 68, 2), + RK3066_PLL_RATE( 798000000, 2, 133, 2), + RK3066_PLL_RATE( 792000000, 1, 66, 2), + RK3066_PLL_RATE( 768000000, 1, 64, 2), + RK3066_PLL_RATE( 742500000, 8, 495, 2), + RK3066_PLL_RATE( 696000000, 1, 58, 2), + RK3066_PLL_RATE( 600000000, 1, 50, 2), + RK3066_PLL_RATE( 594000000, 2, 198, 4), + RK3066_PLL_RATE( 552000000, 1, 46, 2), + RK3066_PLL_RATE( 504000000, 1, 84, 4), + RK3066_PLL_RATE( 456000000, 1, 76, 4), + RK3066_PLL_RATE( 408000000, 1, 68, 4), + RK3066_PLL_RATE( 384000000, 2, 128, 4), + RK3066_PLL_RATE( 360000000, 1, 60, 4), + RK3066_PLL_RATE( 312000000, 1, 52, 4), + RK3066_PLL_RATE( 300000000, 1, 50, 4), + RK3066_PLL_RATE( 297000000, 2, 198, 8), + RK3066_PLL_RATE( 252000000, 1, 84, 8), + RK3066_PLL_RATE( 216000000, 1, 72, 8), + RK3066_PLL_RATE( 148500000, 2, 99, 8), + RK3066_PLL_RATE( 126000000, 1, 84, 16), + RK3066_PLL_RATE( 48000000, 1, 64, 32), + { /* sentinel */ }, +}; + +PNAME(mux_pll_p) = { "xin24m", "xin32k" }; +PNAME(mux_armclk_p) = { "apll", "gpll_armclk" }; +PNAME(mux_ddrphy_p) = { "dpll", "gpll_ddr" }; +PNAME(mux_pll_src_gpll_cpll_p) = { "gpll", "cpll" }; +PNAME(mux_pll_src_cpll_gpll_p) = { "cpll", "gpll" }; +PNAME(mux_aclk_cpu_p) = { "apll", "gpll" }; +PNAME(mux_sclk_cif0_p) = { "cif0_pre", "xin24m" }; +PNAME(mux_sclk_i2s0_p) = { "i2s0_pre", "i2s0_frac", "xin12m" }; +PNAME(mux_sclk_spdif_p) = { "spdif_src", "spdif_frac", "xin12m" }; +PNAME(mux_sclk_uart0_p) = { "uart0_pre", "uart0_frac", "xin24m" }; +PNAME(mux_sclk_uart1_p) = { "uart1_pre", "uart1_frac", "xin24m" }; +PNAME(mux_sclk_uart2_p) = { "uart2_pre", "uart2_frac", "xin24m" }; +PNAME(mux_sclk_uart3_p) = { "uart3_pre", "uart3_frac", "xin24m" }; +PNAME(mux_sclk_hsadc_p) = { "hsadc_src", "hsadc_frac", "ext_hsadc" }; +PNAME(mux_mac_p) = { "gpll", "dpll" }; +PNAME(mux_sclk_macref_p) = { "mac_src", "ext_rmii" }; + +static struct rockchip_pll_clock rk3188_pll_clks[] __initdata = { + [apll] = PLL(pll_rk3066, PLL_APLL, "apll", mux_pll_p, 0, RK2928_PLL_CON(0), + RK2928_MODE_CON, 0, 6, rk3188_pll_rates), + [dpll] = PLL(pll_rk3066, PLL_DPLL, "dpll", mux_pll_p, 0, RK2928_PLL_CON(4), + RK2928_MODE_CON, 4, 5, NULL), + [cpll] = PLL(pll_rk3066, PLL_CPLL, "cpll", mux_pll_p, 0, RK2928_PLL_CON(8), + RK2928_MODE_CON, 8, 7, rk3188_pll_rates), + [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(12), + RK2928_MODE_CON, 12, 8, rk3188_pll_rates), +}; + +#define MFLAGS CLK_MUX_HIWORD_MASK +#define DFLAGS CLK_DIVIDER_HIWORD_MASK +#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE) + +/* 2 ^ (val + 1) */ +static struct clk_div_table div_core_peri_t[] = { + { .val = 0, .div = 2 }, + { .val = 1, .div = 4 }, + { .val = 2, .div = 8 }, + { .val = 3, .div = 16 }, + { /* sentinel */ }, +}; + +static struct rockchip_clk_branch common_clk_branches[] __initdata = { + /* + * Clock-Architecture Diagram 2 + */ + + GATE(0, "gpll_armclk", "gpll", 0, RK2928_CLKGATE_CON(0), 1, GFLAGS), + + /* these two are set by the cpuclk and should not be changed */ + COMPOSITE_NOMUX_DIVTBL(CORE_PERI, "core_peri", "armclk", 0, + RK2928_CLKSEL_CON(0), 6, 2, DFLAGS | CLK_DIVIDER_READ_ONLY, + div_core_peri_t, RK2928_CLKGATE_CON(0), 0, GFLAGS), + + COMPOSITE(0, "aclk_vepu", mux_pll_src_cpll_gpll_p, 0, + RK2928_CLKSEL_CON(32), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK2928_CLKGATE_CON(3), 9, GFLAGS), + GATE(0, "hclk_vepu", "aclk_vepu", 0, + RK2928_CLKGATE_CON(3), 10, GFLAGS), + COMPOSITE(0, "aclk_vdpu", mux_pll_src_cpll_gpll_p, 0, + RK2928_CLKSEL_CON(32), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK2928_CLKGATE_CON(3), 11, GFLAGS), + GATE(0, "hclk_vdpu", "aclk_vdpu", 0, + RK2928_CLKGATE_CON(3), 12, GFLAGS), + + GATE(0, "gpll_ddr", "gpll", 0, + RK2928_CLKGATE_CON(1), 7, GFLAGS), + COMPOSITE(0, "ddrphy", mux_ddrphy_p, 0, + RK2928_CLKSEL_CON(26), 8, 1, MFLAGS, 0, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK2928_CLKGATE_CON(0), 2, GFLAGS), + + GATE(0, "aclk_cpu", "aclk_cpu_pre", 0, + RK2928_CLKGATE_CON(0), 3, GFLAGS), + + DIV(0, "pclk_cpu_pre", "aclk_cpu_pre", 0, + RK2928_CLKSEL_CON(1), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), + GATE(0, "atclk_cpu", "pclk_cpu_pre", 0, + RK2928_CLKGATE_CON(0), 6, GFLAGS), + GATE(0, "pclk_cpu", "pclk_cpu_pre", 0, + RK2928_CLKGATE_CON(0), 5, GFLAGS), + DIV(0, "hclk_cpu_pre", "aclk_cpu_pre", 0, + RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), + COMPOSITE_NOMUX(0, "hclk_ahb2apb", "hclk_cpu_pre", 0, + RK2928_CLKSEL_CON(1), 14, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK2928_CLKGATE_CON(4), 9, GFLAGS), + GATE(0, "hclk_cpu", "hclk_cpu_pre", 0, + RK2928_CLKGATE_CON(0), 4, GFLAGS), + + COMPOSITE(0, "aclk_lcdc0_pre", mux_pll_src_cpll_gpll_p, 0, + RK2928_CLKSEL_CON(31), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK2928_CLKGATE_CON(3), 0, GFLAGS), + COMPOSITE(0, "aclk_lcdc1_pre", mux_pll_src_cpll_gpll_p, 0, + RK2928_CLKSEL_CON(31), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK2928_CLKGATE_CON(1), 4, GFLAGS), + + GATE(0, "aclk_peri", "aclk_peri_pre", 0, + RK2928_CLKGATE_CON(2), 1, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_peri", "aclk_peri_pre", 0, + RK2928_CLKSEL_CON(10), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK2928_CLKGATE_CON(2), 2, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_peri", "aclk_peri_pre", 0, + RK2928_CLKSEL_CON(10), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK2928_CLKGATE_CON(2), 3, GFLAGS), + + MUX(0, "cif_src", mux_pll_src_cpll_gpll_p, 0, + RK2928_CLKSEL_CON(29), 0, 1, MFLAGS), + COMPOSITE_NOMUX(0, "cif0_pre", "cif_src", 0, + RK2928_CLKSEL_CON(29), 1, 5, DFLAGS, + RK2928_CLKGATE_CON(3), 7, GFLAGS), + MUX(SCLK_CIF0, "sclk_cif0", mux_sclk_cif0_p, 0, + RK2928_CLKSEL_CON(29), 7, 1, MFLAGS), + + GATE(0, "pclkin_cif0", "ext_cif0", 0, + RK2928_CLKGATE_CON(3), 3, GFLAGS), + + /* + * the 480m are generated inside the usb block from these clocks, + * but they are also a source for the hsicphy clock. + */ + GATE(SCLK_OTGPHY0, "sclk_otgphy0", "usb480m", 0, + RK2928_CLKGATE_CON(1), 5, GFLAGS), + GATE(SCLK_OTGPHY1, "sclk_otgphy1", "usb480m", 0, + RK2928_CLKGATE_CON(1), 6, GFLAGS), + + COMPOSITE(0, "mac_src", mux_mac_p, 0, + RK2928_CLKSEL_CON(21), 0, 1, MFLAGS, 8, 5, DFLAGS, + RK2928_CLKGATE_CON(2), 5, GFLAGS), + MUX(SCLK_MAC, "sclk_macref", mux_sclk_macref_p, CLK_SET_RATE_PARENT, + RK2928_CLKSEL_CON(21), 4, 1, MFLAGS), + GATE(0, "sclk_mac_lbtest", "sclk_macref", + RK2928_CLKGATE_CON(2), 12, 0, GFLAGS), + + COMPOSITE(0, "hsadc_src", mux_pll_src_gpll_cpll_p, 0, + RK2928_CLKSEL_CON(22), 0, 1, MFLAGS, 8, 8, DFLAGS, + RK2928_CLKGATE_CON(2), 6, GFLAGS), + COMPOSITE_FRAC(0, "hsadc_frac", "hsadc_src", + RK2928_CLKSEL_CON(23), 0, + RK2928_CLKGATE_CON(2), 7, 0, GFLAGS), + MUX(SCLK_HSADC, "sclk_hsadc", mux_sclk_hsadc_p, 0, + RK2928_CLKSEL_CON(22), 4, 2, MFLAGS), + + COMPOSITE_NOMUX(SCLK_SARADC, "sclk_saradc", "xin24m", 0, + RK2928_CLKSEL_CON(24), 8, 8, DFLAGS, + RK2928_CLKGATE_CON(2), 8, GFLAGS), + + /* + * Clock-Architecture Diagram 4 + */ + + GATE(SCLK_SMC, "sclk_smc", "hclk_peri", + RK2928_CLKGATE_CON(2), 4, 0, GFLAGS), + + COMPOSITE_NOMUX(SCLK_SPI0, "sclk_spi0", "pclk_peri", 0, + RK2928_CLKSEL_CON(25), 0, 7, DFLAGS, + RK2928_CLKGATE_CON(2), 9, GFLAGS), + COMPOSITE_NOMUX(SCLK_SPI1, "sclk_spi1", "pclk_peri", 0, + RK2928_CLKSEL_CON(25), 8, 7, DFLAGS, + RK2928_CLKGATE_CON(2), 10, GFLAGS), + + COMPOSITE_NOMUX(SCLK_SDMMC, "sclk_sdmmc", "hclk_peri", 0, + RK2928_CLKSEL_CON(11), 0, 6, DFLAGS, + RK2928_CLKGATE_CON(2), 11, GFLAGS), + COMPOSITE_NOMUX(SCLK_SDIO, "sclk_sdio", "hclk_peri", 0, + RK2928_CLKSEL_CON(12), 0, 6, DFLAGS, + RK2928_CLKGATE_CON(2), 13, GFLAGS), + COMPOSITE_NOMUX(SCLK_EMMC, "sclk_emmc", "hclk_peri", 0, + RK2928_CLKSEL_CON(12), 8, 6, DFLAGS, + RK2928_CLKGATE_CON(2), 14, GFLAGS), + + MUX(0, "uart_src", mux_pll_src_gpll_cpll_p, 0, + RK2928_CLKSEL_CON(12), 15, 1, MFLAGS), + COMPOSITE_NOMUX(0, "uart0_pre", "uart_src", 0, + RK2928_CLKSEL_CON(13), 0, 7, DFLAGS, + RK2928_CLKGATE_CON(1), 8, GFLAGS), + COMPOSITE_FRAC(0, "uart0_frac", "uart0_pre", 0, + RK2928_CLKSEL_CON(17), 0, + RK2928_CLKGATE_CON(1), 9, GFLAGS), + MUX(SCLK_UART0, "sclk_uart0", mux_sclk_uart0_p, 0, + RK2928_CLKSEL_CON(13), 8, 2, MFLAGS), + COMPOSITE_NOMUX(0, "uart1_pre", "uart_src", 0, + RK2928_CLKSEL_CON(14), 0, 7, DFLAGS, + RK2928_CLKGATE_CON(1), 10, GFLAGS), + COMPOSITE_FRAC(0, "uart1_frac", "uart1_pre", 0, + RK2928_CLKSEL_CON(18), 0, + RK2928_CLKGATE_CON(1), 11, GFLAGS), + MUX(SCLK_UART1, "sclk_uart1", mux_sclk_uart1_p, 0, + RK2928_CLKSEL_CON(14), 8, 2, MFLAGS), + COMPOSITE_NOMUX(0, "uart2_pre", "uart_src", 0, + RK2928_CLKSEL_CON(15), 0, 7, DFLAGS, + RK2928_CLKGATE_CON(1), 12, GFLAGS), + COMPOSITE_FRAC(0, "uart2_frac", "uart2_pre", 0, + RK2928_CLKSEL_CON(19), 0, + RK2928_CLKGATE_CON(1), 13, GFLAGS), + MUX(SCLK_UART2, "sclk_uart2", mux_sclk_uart2_p, 0, + RK2928_CLKSEL_CON(15), 8, 2, MFLAGS), + COMPOSITE_NOMUX(0, "uart3_pre", "uart_src", 0, + RK2928_CLKSEL_CON(16), 0, 7, DFLAGS, + RK2928_CLKGATE_CON(1), 14, GFLAGS), + COMPOSITE_FRAC(0, "uart3_frac", "uart3_pre", 0, + RK2928_CLKSEL_CON(20), 0, + RK2928_CLKGATE_CON(1), 15, GFLAGS), + MUX(SCLK_UART3, "sclk_uart3", mux_sclk_uart3_p, 0, + RK2928_CLKSEL_CON(16), 8, 2, MFLAGS), + + GATE(SCLK_JTAG, "jtag", "ext_jtag", 0, RK2928_CLKGATE_CON(1), 3, GFLAGS), + + GATE(SCLK_TIMER0, "timer0", "xin24m", 0, RK2928_CLKGATE_CON(1), 0, GFLAGS), + GATE(SCLK_TIMER1, "timer1", "xin24m", 0, RK2928_CLKGATE_CON(1), 1, GFLAGS), + + /* clk_core_pre gates */ + GATE(0, "core_dbg", "armclk", 0, RK2928_CLKGATE_CON(9), 0, GFLAGS), + + /* aclk_cpu gates */ + GATE(ACLK_DMA1, "aclk_dma1", "aclk_cpu", 0, RK2928_CLKGATE_CON(5), 0, GFLAGS), + GATE(0, "aclk_intmem", "aclk_cpu", 0, RK2928_CLKGATE_CON(4), 12, GFLAGS), + GATE(0, "aclk_strc_sys", "aclk_cpu", 0, RK2928_CLKGATE_CON(4), 10, GFLAGS), + + /* hclk_cpu gates */ + GATE(HCLK_ROM, "hclk_rom", "hclk_cpu", 0, RK2928_CLKGATE_CON(5), 6, GFLAGS), + GATE(HCLK_I2S0, "hclk_i2s0", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS), + GATE(HCLK_SPDIF, "hclk_spdif", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 1, GFLAGS), + GATE(0, "hclk_cpubus", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 8, GFLAGS), + /* hclk_ahb2apb is part of a clk branch */ + GATE(0, "hclk_vio_bus", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 12, GFLAGS), + GATE(HCLK_LCDC0, "hclk_lcdc0", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 1, GFLAGS), + GATE(HCLK_LCDC1, "hclk_lcdc1", "aclk_cpu", 0, RK2928_CLKGATE_CON(6), 2, GFLAGS), + GATE(HCLK_CIF0, "hclk_cif0", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 4, GFLAGS), + GATE(HCLK_IPP, "hclk_ipp", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 9, GFLAGS), + GATE(HCLK_RGA, "hclk_rga", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 10, GFLAGS), + + /* hclk_peri gates */ + GATE(0, "hclk_peri_axi_matrix", "hclk_peri", 0, RK2928_CLKGATE_CON(4), 0, GFLAGS), + GATE(0, "hclk_peri_ahb_arbi", "hclk_peri", 0, RK2928_CLKGATE_CON(4), 6, GFLAGS), + GATE(0, "hclk_emem_peri", "hclk_peri", 0, RK2928_CLKGATE_CON(4), 7, GFLAGS), + GATE(HCLK_EMAC, "hclk_emac", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 0, GFLAGS), + GATE(HCLK_NANDC0, "hclk_nandc0", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 9, GFLAGS), + GATE(0, "hclk_usb_peri", "hclk_peri", 0, RK2928_CLKGATE_CON(4), 5, GFLAGS), + GATE(HCLK_OTG0, "hclk_usbotg0", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 13, GFLAGS), + GATE(HCLK_HSADC, "hclk_hsadc", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 5, GFLAGS), + GATE(HCLK_PIDF, "hclk_pidfilter", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 6, GFLAGS), + GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 10, GFLAGS), + GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 11, GFLAGS), + GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 12, GFLAGS), + + /* aclk_lcdc0_pre gates */ + GATE(0, "aclk_vio0", "aclk_lcdc0_pre", 0, RK2928_CLKGATE_CON(6), 13, GFLAGS), + GATE(ACLK_LCDC0, "aclk_lcdc0", "aclk_vio0", 0, RK2928_CLKGATE_CON(6), 0, GFLAGS), + GATE(ACLK_CIF0, "aclk_cif0", "aclk_vio0", 0, RK2928_CLKGATE_CON(6), 5, GFLAGS), + GATE(ACLK_IPP, "aclk_ipp", "aclk_vio0", 0, RK2928_CLKGATE_CON(6), 8, GFLAGS), + + /* aclk_lcdc1_pre gates */ + GATE(0, "aclk_vio1", "aclk_lcdc1_pre", 0, RK2928_CLKGATE_CON(9), 5, GFLAGS), + GATE(ACLK_LCDC1, "aclk_lcdc1", "aclk_vio1", 0, RK2928_CLKGATE_CON(6), 3, GFLAGS), + GATE(ACLK_RGA, "aclk_rga", "aclk_vio1", 0, RK2928_CLKGATE_CON(6), 11, GFLAGS), + + /* atclk_cpu gates */ + GATE(0, "atclk", "atclk_cpu", 0, RK2928_CLKGATE_CON(9), 3, GFLAGS), + GATE(0, "trace", "atclk_cpu", 0, RK2928_CLKGATE_CON(9), 2, GFLAGS), + + /* pclk_cpu gates */ + GATE(PCLK_PWM01, "pclk_pwm01", "pclk_cpu", 0, RK2928_CLKGATE_CON(7), 10, GFLAGS), + GATE(PCLK_TIMER0, "pclk_timer0", "pclk_cpu", 0, RK2928_CLKGATE_CON(7), 7, GFLAGS), + GATE(PCLK_I2C0, "pclk_i2c0", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 4, GFLAGS), + GATE(PCLK_I2C1, "pclk_i2c1", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 5, GFLAGS), + GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 9, GFLAGS), + GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 10, GFLAGS), + GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 11, GFLAGS), + GATE(PCLK_EFUSE, "pclk_efuse", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 2, GFLAGS), + GATE(PCLK_TZPC, "pclk_tzpc", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 3, GFLAGS), + GATE(0, "pclk_ddrupctl", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 7, GFLAGS), + GATE(0, "pclk_ddrpubl", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS), + GATE(0, "pclk_dbg", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 1, GFLAGS), + GATE(PCLK_GRF, "pclk_grf", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 4, GFLAGS), + GATE(PCLK_PMU, "pclk_pmu", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 5, GFLAGS), + + /* aclk_peri */ + GATE(ACLK_DMA2, "aclk_dma2", "aclk_peri", 0, RK2928_CLKGATE_CON(5), 1, GFLAGS), + GATE(ACLK_SMC, "aclk_smc", "aclk_peri", 0, RK2928_CLKGATE_CON(5), 8, GFLAGS), + GATE(0, "aclk_peri_niu", "aclk_peri", 0, RK2928_CLKGATE_CON(4), 4, GFLAGS), + GATE(0, "aclk_cpu_peri", "aclk_peri", 0, RK2928_CLKGATE_CON(4), 2, GFLAGS), + GATE(0, "aclk_peri_axi_matrix", "aclk_peri", 0, RK2928_CLKGATE_CON(4), 3, GFLAGS), + + /* pclk_peri gates */ + GATE(0, "pclk_peri_axi_matrix", "pclk_peri", 0, RK2928_CLKGATE_CON(4), 1, GFLAGS), + GATE(PCLK_PWM23, "pclk_pwm23", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 11, GFLAGS), + GATE(PCLK_WDT, "pclk_wdt", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 15, GFLAGS), + GATE(PCLK_SPI0, "pclk_spi0", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 12, GFLAGS), + GATE(PCLK_SPI1, "pclk_spi1", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 13, GFLAGS), + GATE(PCLK_UART2, "pclk_uart2", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 2, GFLAGS), + GATE(PCLK_UART3, "pclk_uart3", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 3, GFLAGS), + GATE(PCLK_I2C2, "pclk_i2c2", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 6, GFLAGS), + GATE(PCLK_I2C3, "pclk_i2c3", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 7, GFLAGS), + GATE(PCLK_I2C4, "pclk_i2c4", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 8, GFLAGS), + GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 12, GFLAGS), + GATE(PCLK_SARADC, "pclk_saradc", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 14, GFLAGS), +}; + +PNAME(mux_rk3066_lcdc0_p) = { "dclk_lcdc0_src", "xin27m" }; +PNAME(mux_rk3066_lcdc1_p) = { "dclk_lcdc1_src", "xin27m" }; +PNAME(mux_sclk_cif1_p) = { "cif1_pre", "xin24m" }; +PNAME(mux_sclk_i2s1_p) = { "i2s1_pre", "i2s1_frac", "xin12m" }; +PNAME(mux_sclk_i2s2_p) = { "i2s2_pre", "i2s2_frac", "xin12m" }; + +static struct clk_div_table div_aclk_cpu_t[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 3 }, + { .val = 3, .div = 4 }, + { .val = 4, .div = 8 }, + { /* sentinel */ }, +}; + +static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { + COMPOSITE_NOGATE(0, "armclk", mux_armclk_p, 0, + RK2928_CLKSEL_CON(0), 8, 1, MFLAGS, 0, 5, DFLAGS), + DIVTBL(0, "aclk_cpu_pre", "armclk", 0, + RK2928_CLKSEL_CON(1), 0, 3, DFLAGS, div_aclk_cpu_t), + + GATE(CORE_L2C, "core_l2c", "aclk_cpu", 0, + RK2928_CLKGATE_CON(9), 4, GFLAGS), + + COMPOSITE(0, "aclk_peri_pre", mux_pll_src_gpll_cpll_p, 0, + RK2928_CLKSEL_CON(10), 15, 1, MFLAGS, 0, 5, DFLAGS, + RK2928_CLKGATE_CON(2), 0, GFLAGS), + + COMPOSITE(0, "dclk_lcdc0_src", mux_pll_src_cpll_gpll_p, 0, + RK2928_CLKSEL_CON(27), 0, 1, MFLAGS, 8, 8, DFLAGS, + RK2928_CLKGATE_CON(3), 1, GFLAGS), + MUX(DCLK_LCDC0, "dclk_lcdc0", mux_rk3066_lcdc0_p, 0, + RK2928_CLKSEL_CON(27), 4, 1, MFLAGS), + COMPOSITE(0, "dclk_lcdc1_src", mux_pll_src_cpll_gpll_p, 0, + RK2928_CLKSEL_CON(28), 0, 1, MFLAGS, 8, 8, DFLAGS, + RK2928_CLKGATE_CON(3), 2, GFLAGS), + MUX(DCLK_LCDC1, "dclk_lcdc1", mux_rk3066_lcdc1_p, 0, + RK2928_CLKSEL_CON(28), 4, 1, MFLAGS), + + COMPOSITE_NOMUX(0, "cif1_pre", "cif_src", 0, + RK2928_CLKSEL_CON(29), 8, 5, DFLAGS, + RK2928_CLKGATE_CON(3), 8, GFLAGS), + MUX(SCLK_CIF1, "sclk_cif1", mux_sclk_cif1_p, 0, + RK2928_CLKSEL_CON(29), 15, 1, MFLAGS), + + GATE(0, "pclkin_cif1", "ext_cif1", 0, + RK2928_CLKGATE_CON(3), 4, GFLAGS), + + COMPOSITE(0, "aclk_gpu_src", mux_pll_src_cpll_gpll_p, 0, + RK2928_CLKSEL_CON(33), 8, 1, MFLAGS, 0, 5, DFLAGS, + RK2928_CLKGATE_CON(3), 13, GFLAGS), + GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_src", 0, + RK2928_CLKGATE_CON(5), 15, GFLAGS), + + GATE(SCLK_TIMER2, "timer2", "xin24m", 0, + RK2928_CLKGATE_CON(3), 2, GFLAGS), + + COMPOSITE_NOMUX(0, "sclk_tsadc", "xin24m", 0, + RK2928_CLKSEL_CON(34), 0, 16, DFLAGS, + RK2928_CLKGATE_CON(2), 15, GFLAGS), + + MUX(0, "i2s_src", mux_pll_src_gpll_cpll_p, 0, + RK2928_CLKSEL_CON(2), 15, 1, MFLAGS), + COMPOSITE_NOMUX(0, "i2s0_pre", "i2s_src", 0, + RK2928_CLKSEL_CON(2), 0, 7, DFLAGS, + RK2928_CLKGATE_CON(0), 7, GFLAGS), + COMPOSITE_FRAC(0, "i2s0_frac", "i2s0_pre", 0, + RK2928_CLKSEL_CON(6), 0, + RK2928_CLKGATE_CON(0), 8, GFLAGS), + MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0, + RK2928_CLKSEL_CON(2), 8, 2, MFLAGS), + COMPOSITE_NOMUX(0, "i2s1_pre", "i2s_src", 0, + RK2928_CLKSEL_CON(3), 0, 7, DFLAGS, + RK2928_CLKGATE_CON(0), 9, GFLAGS), + COMPOSITE_FRAC(0, "i2s1_frac", "i2s1_pre", 0, + RK2928_CLKSEL_CON(7), 0, + RK2928_CLKGATE_CON(0), 10, GFLAGS), + MUX(SCLK_I2S1, "sclk_i2s1", mux_sclk_i2s1_p, 0, + RK2928_CLKSEL_CON(3), 8, 2, MFLAGS), + COMPOSITE_NOMUX(0, "i2s2_pre", "i2s_src", 0, + RK2928_CLKSEL_CON(4), 0, 7, DFLAGS, + RK2928_CLKGATE_CON(0), 11, GFLAGS), + COMPOSITE_FRAC(0, "i2s2_frac", "i2s2_pre", 0, + RK2928_CLKSEL_CON(8), 0, + RK2928_CLKGATE_CON(0), 12, GFLAGS), + MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, 0, + RK2928_CLKSEL_CON(4), 8, 2, MFLAGS), + COMPOSITE_NOMUX(0, "spdif_pre", "i2s_src", 0, + RK2928_CLKSEL_CON(5), 0, 7, DFLAGS, + RK2928_CLKGATE_CON(0), 13, GFLAGS), + COMPOSITE_FRAC(0, "spdif_frac", "spdif_pll", 0, + RK2928_CLKSEL_CON(9), 0, + RK2928_CLKGATE_CON(0), 14, GFLAGS), + MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, 0, + RK2928_CLKSEL_CON(5), 8, 2, MFLAGS), + + GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS), + GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS), + GATE(0, "hclk_cif1", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 6, GFLAGS), + GATE(0, "hclk_hdmi", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS), + + GATE(HCLK_OTG1, "hclk_usbotg1", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 14, GFLAGS), + + GATE(0, "aclk_cif1", "aclk_vio1", 0, RK2928_CLKGATE_CON(6), 7, GFLAGS), + + GATE(PCLK_TIMER1, "pclk_timer1", "pclk_cpu", 0, RK2928_CLKGATE_CON(7), 8, GFLAGS), + GATE(PCLK_TIMER2, "pclk_timer2", "pclk_cpu", 0, RK2928_CLKGATE_CON(7), 9, GFLAGS), + GATE(PCLK_GPIO6, "pclk_gpio6", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 15, GFLAGS), + GATE(PCLK_UART0, "pclk_uart0", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 0, GFLAGS), + GATE(PCLK_UART1, "pclk_uart1", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 1, GFLAGS), + + GATE(PCLK_GPIO4, "pclk_gpio4", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS), + GATE(PCLK_TSADC, "pclk_tsadc", "pclk_peri", 0, RK2928_CLKGATE_CON(4), 13, GFLAGS), +}; + +static struct clk_div_table div_rk3188_aclk_core_t[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 3 }, + { .val = 3, .div = 4 }, + { .val = 4, .div = 8 }, + { /* sentinel */ }, +}; + +PNAME(mux_hsicphy_p) = { "sclk_otgphy0", "sclk_otgphy1", + "gpll", "cpll" }; + +static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { + COMPOSITE_NOGATE(0, "armclk", mux_armclk_p, 0, + RK2928_CLKSEL_CON(0), 8, 1, MFLAGS, 9, 5, DFLAGS), + COMPOSITE_NOMUX_DIVTBL(0, "aclk_core", "armclk", 0, + RK2928_CLKSEL_CON(1), 3, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, + div_rk3188_aclk_core_t, RK2928_CLKGATE_CON(0), 7, GFLAGS), + + /* do not source aclk_cpu_pre from the apll, to keep complexity down */ + COMPOSITE_NOGATE(0, "aclk_cpu_pre", mux_aclk_cpu_p, CLK_SET_RATE_NO_REPARENT, + RK2928_CLKSEL_CON(0), 5, 1, MFLAGS, 0, 5, DFLAGS), + + GATE(CORE_L2C, "core_l2c", "armclk", 0, + RK2928_CLKGATE_CON(9), 4, GFLAGS), + + COMPOSITE(0, "aclk_peri_pre", mux_pll_src_cpll_gpll_p, 0, + RK2928_CLKSEL_CON(10), 15, 1, MFLAGS, 0, 5, DFLAGS, + RK2928_CLKGATE_CON(2), 0, GFLAGS), + + COMPOSITE(DCLK_LCDC0, "dclk_lcdc0", mux_pll_src_cpll_gpll_p, 0, + RK2928_CLKSEL_CON(27), 0, 1, MFLAGS, 8, 8, DFLAGS, + RK2928_CLKGATE_CON(3), 1, GFLAGS), + COMPOSITE(DCLK_LCDC1, "dclk_lcdc1", mux_pll_src_cpll_gpll_p, 0, + RK2928_CLKSEL_CON(28), 0, 1, MFLAGS, 8, 8, DFLAGS, + RK2928_CLKGATE_CON(3), 2, GFLAGS), + + COMPOSITE(0, "aclk_gpu_src", mux_pll_src_cpll_gpll_p, 0, + RK2928_CLKSEL_CON(34), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK2928_CLKGATE_CON(3), 15, GFLAGS), + GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_src", 0, + RK2928_CLKGATE_CON(9), 7, GFLAGS), + + GATE(SCLK_TIMER2, "timer2", "xin24m", 0, RK2928_CLKGATE_CON(3), 4, GFLAGS), + GATE(SCLK_TIMER3, "timer3", "xin24m", 0, RK2928_CLKGATE_CON(1), 2, GFLAGS), + GATE(SCLK_TIMER4, "timer4", "xin24m", 0, RK2928_CLKGATE_CON(3), 5, GFLAGS), + GATE(SCLK_TIMER5, "timer5", "xin24m", 0, RK2928_CLKGATE_CON(3), 8, GFLAGS), + GATE(SCLK_TIMER6, "timer6", "xin24m", 0, RK2928_CLKGATE_CON(3), 14, GFLAGS), + + COMPOSITE_NODIV(0, "sclk_hsicphy_480m", mux_hsicphy_p, 0, + RK2928_CLKSEL_CON(30), 0, 2, DFLAGS, + RK2928_CLKGATE_CON(3), 6, GFLAGS), + DIV(0, "sclk_hsicphy_12m", "sclk_hsicphy_480m", 0, + RK2928_CLKGATE_CON(11), 8, 6, DFLAGS), + + MUX(0, "i2s_src", mux_pll_src_gpll_cpll_p, 0, + RK2928_CLKSEL_CON(2), 15, 1, MFLAGS), + COMPOSITE_NOMUX(0, "i2s0_pre", "i2s_src", 0, + RK2928_CLKSEL_CON(3), 0, 7, DFLAGS, + RK2928_CLKGATE_CON(0), 9, GFLAGS), + COMPOSITE_FRAC(0, "i2s0_frac", "i2s0_pre", 0, + RK2928_CLKSEL_CON(7), 0, + RK2928_CLKGATE_CON(0), 10, GFLAGS), + MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0, + RK2928_CLKSEL_CON(3), 8, 2, MFLAGS), + COMPOSITE_NOMUX(0, "spdif_pre", "i2s_src", 0, + RK2928_CLKSEL_CON(5), 0, 7, DFLAGS, + RK2928_CLKGATE_CON(13), 13, GFLAGS), + COMPOSITE_FRAC(0, "spdif_frac", "spdif_pll", 0, + RK2928_CLKSEL_CON(9), 0, + RK2928_CLKGATE_CON(0), 14, GFLAGS), + MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, 0, + RK2928_CLKSEL_CON(5), 8, 2, MFLAGS), + + GATE(0, "hclk_imem0", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS), + GATE(0, "hclk_imem1", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 15, GFLAGS), + + GATE(HCLK_OTG1, "hclk_usbotg1", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS), + GATE(HCLK_HSIC, "hclk_hsic", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS), + + GATE(PCLK_TIMER3, "pclk_timer3", "pclk_cpu", 0, RK2928_CLKGATE_CON(7), 9, GFLAGS), + + GATE(PCLK_UART0, "pclk_uart0", "hclk_ahb2apb", 0, RK2928_CLKGATE_CON(8), 0, GFLAGS), + GATE(PCLK_UART1, "pclk_uart1", "hclk_ahb2apb", 0, RK2928_CLKGATE_CON(8), 1, GFLAGS), + + GATE(ACLK_GPS, "aclk_gps", "aclk_peri", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS), +}; + +static void __init rk3188_common_clk_init(struct device_node *np) +{ + void __iomem *reg_base; + struct clk *clk; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: could not map cru region\n", __func__); + return; + } + + rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + + /* xin12m is created by an cru-internal divider */ + clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2); + if (IS_ERR(clk)) + pr_warn("%s: could not register clock xin12m: %ld\n", + __func__, PTR_ERR(clk)); + + clk = clk_register_fixed_factor(NULL, "usb480m", "xin24m", 0, 20, 1); + if (IS_ERR(clk)) + pr_warn("%s: could not register clock usb480m: %ld\n", + __func__, PTR_ERR(clk)); + + rockchip_clk_register_plls(rk3188_pll_clks, + ARRAY_SIZE(rk3188_pll_clks), + RK3188_GRF_SOC_STATUS); + rockchip_clk_register_branches(common_clk_branches, + ARRAY_SIZE(common_clk_branches)); + + rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0), + ROCKCHIP_SOFTRST_HIWORD_MASK); +} + +static void __init rk3066a_clk_init(struct device_node *np) +{ + rk3188_common_clk_init(np); + rockchip_clk_register_branches(rk3066a_clk_branches, + ARRAY_SIZE(rk3066a_clk_branches)); +} +CLK_OF_DECLARE(rk3066a_cru, "rockchip,rk3066a-cru", rk3066a_clk_init); + +static void __init rk3188a_clk_init(struct device_node *np) +{ + rk3188_common_clk_init(np); + rockchip_clk_register_branches(rk3188_clk_branches, + ARRAY_SIZE(rk3188_clk_branches)); +} +CLK_OF_DECLARE(rk3188a_cru, "rockchip,rk3188a-cru", rk3188a_clk_init); + +static void __init rk3188_clk_init(struct device_node *np) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rk3188_pll_clks); i++) { + struct rockchip_pll_clock *pll = &rk3188_pll_clks[i]; + struct rockchip_pll_rate_table *rate; + + if (!pll->rate_table) + continue; + + rate = pll->rate_table; + while (rate->rate > 0) { + rate->bwadj = 0; + rate++; + } + } + + rk3188a_clk_init(np); +} +CLK_OF_DECLARE(rk3188_cru, "rockchip,rk3188-cru", rk3188_clk_init); diff --git a/include/dt-bindings/clock/rk3066a-cru.h b/include/dt-bindings/clock/rk3066a-cru.h new file mode 100644 index 0000000..bc1ed1d --- /dev/null +++ b/include/dt-bindings/clock/rk3066a-cru.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014 MundoReader S.L. + * Author: Heiko Stuebner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +/* soft-reset indices */ +#define SRST_SRST1 0 +#define SRST_SRST2 1 + +#define SRST_L2MEM 18 +#define SRST_I2S0 23 +#define SRST_I2S1 24 +#define SRST_I2S2 25 +#define SRST_TIMER2 29 + +#define SRST_GPIO4 36 +#define SRST_GPIO6 38 + +#define SRST_TSADC 92 + +#define SRST_HDMI 96 +#define SRST_HDMI_APB 97 +#define SRST_CIF1 111 diff --git a/include/dt-bindings/clock/rk3188-cru-common.h b/include/dt-bindings/clock/rk3188-cru-common.h new file mode 100644 index 0000000..750ee60 --- /dev/null +++ b/include/dt-bindings/clock/rk3188-cru-common.h @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2014 MundoReader S.L. + * Author: Heiko Stuebner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* core clocks from */ +#define PLL_APLL 1 +#define PLL_DPLL 2 +#define PLL_CPLL 3 +#define PLL_GPLL 4 +#define CORE_PERI 5 +#define CORE_L2C 6 + +/* sclk gates (special clocks) */ +#define SCLK_UART0 64 +#define SCLK_UART1 65 +#define SCLK_UART2 66 +#define SCLK_UART3 67 +#define SCLK_MAC 68 +#define SCLK_SPI0 69 +#define SCLK_SPI1 70 +#define SCLK_SARADC 71 +#define SCLK_SDMMC 72 +#define SCLK_SDIO 73 +#define SCLK_EMMC 74 +#define SCLK_I2S0 75 +#define SCLK_I2S1 76 +#define SCLK_I2S2 77 +#define SCLK_SPDIF 78 +#define SCLK_CIF0 79 +#define SCLK_CIF1 80 +#define SCLK_OTGPHY0 81 +#define SCLK_OTGPHY1 82 +#define SCLK_HSADC 83 +#define SCLK_TIMER0 84 +#define SCLK_TIMER1 85 +#define SCLK_TIMER2 86 +#define SCLK_TIMER3 87 +#define SCLK_TIMER4 88 +#define SCLK_TIMER5 89 +#define SCLK_TIMER6 90 +#define SCLK_JTAG 91 +#define SCLK_SMC 92 + +#define DCLK_LCDC0 190 +#define DCLK_LCDC1 191 + +/* aclk gates */ +#define ACLK_DMA1 192 +#define ACLK_DMA2 193 +#define ACLK_GPS 194 +#define ACLK_LCDC0 195 +#define ACLK_LCDC1 196 +#define ACLK_GPU 197 +#define ACLK_SMC 198 +#define ACLK_CIF 199 +#define ACLK_IPP 200 +#define ACLK_RGA 201 +#define ACLK_CIF0 202 + +/* pclk gates */ +#define PCLK_GRF 320 +#define PCLK_PMU 321 +#define PCLK_TIMER0 322 +#define PCLK_TIMER1 323 +#define PCLK_TIMER2 324 +#define PCLK_TIMER3 325 +#define PCLK_PWM01 326 +#define PCLK_PWM23 327 +#define PCLK_SPI0 328 +#define PCLK_SPI1 329 +#define PCLK_SARADC 330 +#define PCLK_WDT 331 +#define PCLK_UART0 332 +#define PCLK_UART1 333 +#define PCLK_UART2 334 +#define PCLK_UART3 335 +#define PCLK_I2C0 336 +#define PCLK_I2C1 337 +#define PCLK_I2C2 338 +#define PCLK_I2C3 339 +#define PCLK_I2C4 340 +#define PCLK_GPIO0 341 +#define PCLK_GPIO1 342 +#define PCLK_GPIO2 343 +#define PCLK_GPIO3 344 +#define PCLK_GPIO4 345 +#define PCLK_GPIO6 346 +#define PCLK_EFUSE 347 +#define PCLK_TZPC 348 +#define PCLK_TSADC 349 + +/* hclk gates */ +#define HCLK_SDMMC 448 +#define HCLK_SDIO 449 +#define HCLK_EMMC 450 +#define HCLK_OTG0 451 +#define HCLK_EMAC 452 +#define HCLK_SPDIF 453 +#define HCLK_I2S0 454 +#define HCLK_I2S1 455 +#define HCLK_I2S2 456 +#define HCLK_OTG1 457 +#define HCLK_HSIC 458 +#define HCLK_HSADC 459 +#define HCLK_PIDF 460 +#define HCLK_LCDC0 461 +#define HCLK_LCDC1 462 +#define HCLK_ROM 463 +#define HCLK_CIF0 464 +#define HCLK_IPP 465 +#define HCLK_RGA 466 +#define HCLK_NANDC0 467 + +#define CLK_NR_CLKS (HCLK_NANDC0 + 1) + +/* soft-reset indices */ +#define SRST_MCORE 2 +#define SRST_CORE0 3 +#define SRST_CORE1 4 +#define SRST_MCORE_DBG 7 +#define SRST_CORE0_DBG 8 +#define SRST_CORE1_DBG 9 +#define SRST_CORE0_WDT 12 +#define SRST_CORE1_WDT 13 +#define SRST_STRC_SYS 14 +#define SRST_L2C 15 + +#define SRST_CPU_AHB 17 +#define SRST_AHB2APB 19 +#define SRST_DMA1 20 +#define SRST_INTMEM 21 +#define SRST_ROM 22 +#define SRST_SPDIF 26 +#define SRST_TIMER0 27 +#define SRST_TIMER1 28 +#define SRST_EFUSE 30 + +#define SRST_GPIO0 32 +#define SRST_GPIO1 33 +#define SRST_GPIO2 34 +#define SRST_GPIO3 35 + +#define SRST_UART0 39 +#define SRST_UART1 40 +#define SRST_UART2 41 +#define SRST_UART3 42 +#define SRST_I2C0 43 +#define SRST_I2C1 44 +#define SRST_I2C2 45 +#define SRST_I2C3 46 +#define SRST_I2C4 47 + +#define SRST_PWM0 48 +#define SRST_PWM1 49 +#define SRST_DAP_PO 50 +#define SRST_DAP 51 +#define SRST_DAP_SYS 52 +#define SRST_TPIU_ATB 53 +#define SRST_PMU_APB 54 +#define SRST_GRF 55 +#define SRST_PMU 56 +#define SRST_PERI_AXI 57 +#define SRST_PERI_AHB 58 +#define SRST_PERI_APB 59 +#define SRST_PERI_NIU 60 +#define SRST_CPU_PERI 61 +#define SRST_EMEM_PERI 62 +#define SRST_USB_PERI 63 + +#define SRST_DMA2 64 +#define SRST_SMC 65 +#define SRST_MAC 66 +#define SRST_NANC0 68 +#define SRST_USBOTG0 69 +#define SRST_USBPHY0 70 +#define SRST_OTGC0 71 +#define SRST_USBOTG1 72 +#define SRST_USBPHY1 73 +#define SRST_OTGC1 74 +#define SRST_HSADC 76 +#define SRST_PIDFILTER 77 +#define SRST_DDR_MSCH 79 + +#define SRST_TZPC 80 +#define SRST_SDMMC 81 +#define SRST_SDIO 82 +#define SRST_EMMC 83 +#define SRST_SPI0 84 +#define SRST_SPI1 85 +#define SRST_WDT 86 +#define SRST_SARADC 87 +#define SRST_DDRPHY 88 +#define SRST_DDRPHY_APB 89 +#define SRST_DDRCTL 90 +#define SRST_DDRCTL_APB 91 +#define SRST_DDRPUB 93 + +#define SRST_VIO0_AXI 98 +#define SRST_VIO0_AHB 99 +#define SRST_LCDC0_AXI 100 +#define SRST_LCDC0_AHB 101 +#define SRST_LCDC0_DCLK 102 +#define SRST_LCDC1_AXI 103 +#define SRST_LCDC1_AHB 104 +#define SRST_LCDC1_DCLK 105 +#define SRST_IPP_AXI 106 +#define SRST_IPP_AHB 107 +#define SRST_RGA_AXI 108 +#define SRST_RGA_AHB 109 +#define SRST_CIF0 110 + +#define SRST_VCODEC_AXI 112 +#define SRST_VCODEC_AHB 113 +#define SRST_VIO1_AXI 114 +#define SRST_VCODEC_CPU 115 +#define SRST_VCODEC_NIU 116 +#define SRST_GPU 120 +#define SRST_GPU_NIU 122 +#define SRST_TFUN_ATB 125 +#define SRST_TFUN_APB 126 +#define SRST_CTI4_APB 127 + +#define SRST_TPIU_APB 128 +#define SRST_TRACE 129 +#define SRST_CORE_DBG 130 +#define SRST_DBG_APB 131 +#define SRST_CTI0 132 +#define SRST_CTI0_APB 133 +#define SRST_CTI1 134 +#define SRST_CTI1_APB 135 +#define SRST_PTM_CORE0 136 +#define SRST_PTM_CORE1 137 +#define SRST_PTM0 138 +#define SRST_PTM0_ATB 139 +#define SRST_PTM1 140 +#define SRST_PTM1_ATB 141 +#define SRST_CTM 142 +#define SRST_TS 143 diff --git a/include/dt-bindings/clock/rk3188-cru.h b/include/dt-bindings/clock/rk3188-cru.h new file mode 100644 index 0000000..9fac8ed --- /dev/null +++ b/include/dt-bindings/clock/rk3188-cru.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014 MundoReader S.L. + * Author: Heiko Stuebner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +/* soft-reset indices */ +#define SRST_PTM_CORE2 0 +#define SRST_PTM_CORE3 1 +#define SRST_CORE2 5 +#define SRST_CORE3 6 +#define SRST_CORE2_DBG 10 +#define SRST_CORE3_DBG 11 + +#define SRST_TIMER2 16 +#define SRST_TIMER4 23 +#define SRST_I2S0 24 +#define SRST_TIMER5 25 +#define SRST_TIMER3 29 +#define SRST_TIMER6 31 + +#define SRST_PTM3 36 +#define SRST_PTM3_ATB 37 + +#define SRST_GPS 67 +#define SRST_HSICPHY 75 +#define SRST_TIMER 78 + +#define SRST_PTM2 92 +#define SRST_CORE2_WDT 94 +#define SRST_CORE3_WDT 95 + +#define SRST_PTM2_ATB 111 + +#define SRST_HSIC 117 +#define SRST_CTI2 118 +#define SRST_CTI2_APB 119 +#define SRST_GPU_BRIDGE 121 +#define SRST_CTI3 123 +#define SRST_CTI3_APB 124 -- cgit v0.10.2 From 5775b82e74d1b307b7dab670993b6b838c92f786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Thu, 3 Jul 2014 02:02:12 +0200 Subject: dt-bindings: add documentation for rk3288 cru This adds the dt-binding documentation for the clock and reset unit found on Rockchip rk3288 SoCs. Signed-off-by: Heiko Stuebner Acked-By: Max Schwarz Tested-By: Max Schwarz Signed-off-by: Mike Turquette diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3288-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3288-cru.txt new file mode 100644 index 0000000..c9fbb76 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/rockchip,rk3288-cru.txt @@ -0,0 +1,61 @@ +* Rockchip RK3288 Clock and Reset Unit + +The RK3288 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: should be "rockchip,rk3288-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files" + If missing pll rates are not changable, due to the missing pll lock status. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/rk3288-cru.h headers and can be +used in device tree sources. Similar macros exist for the reset sources in +these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "xin32k" - rtc clock - optional, + - "ext_i2s" - external I2S clock - optional, + - "ext_hsadc" - external HSADC clock - optional, + - "ext_edp_24m" - external display port clock - optional, + - "ext_vip" - external VIP clock - optional, + - "ext_isp" - external ISP clock - optional, + - "ext_jtag" - external JTAG clock - optional + +Example: Clock controller node: + + cru: cru@20000000 { + compatible = "rockchip,rk3188-cru"; + reg = <0x20000000 0x1000>; + rockchip,grf = <&grf>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@10124000 { + compatible = "snps,dw-apb-uart"; + reg = <0x10124000 0x400>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <1>; + clocks = <&cru SCLK_UART0>; + }; -- cgit v0.10.2 From b9e4ba541607e6ee9c6c8493f51198fe3af03aec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Thu, 3 Jul 2014 02:02:37 +0200 Subject: clk: rockchip: add clock controller for rk3288 Add the clock tree definition for the new rk3288 SoC. Signed-off-by: Heiko Stuebner Acked-By: Max Schwarz Tested-By: Max Schwarz Signed-off-by: Mike Turquette diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 3eebf72..ee6b077 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -8,3 +8,4 @@ obj-y += clk-pll.o obj-$(CONFIG_RESET_CONTROLLER) += softrst.o obj-y += clk-rk3188.o +obj-y += clk-rk3288.o diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c new file mode 100644 index 0000000..0d8c6c5 --- /dev/null +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -0,0 +1,717 @@ +/* + * Copyright (c) 2014 MundoReader S.L. + * Author: Heiko Stuebner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include "clk.h" + +#define RK3288_GRF_SOC_CON(x) (0x244 + x * 4) +#define RK3288_GRF_SOC_STATUS 0x280 + +enum rk3288_plls { + apll, dpll, cpll, gpll, npll, +}; + +struct rockchip_pll_rate_table rk3288_pll_rates[] = { + RK3066_PLL_RATE(2208000000, 1, 92, 1), + RK3066_PLL_RATE(2184000000, 1, 91, 1), + RK3066_PLL_RATE(2160000000, 1, 90, 1), + RK3066_PLL_RATE(2136000000, 1, 89, 1), + RK3066_PLL_RATE(2112000000, 1, 88, 1), + RK3066_PLL_RATE(2088000000, 1, 87, 1), + RK3066_PLL_RATE(2064000000, 1, 86, 1), + RK3066_PLL_RATE(2040000000, 1, 85, 1), + RK3066_PLL_RATE(2016000000, 1, 84, 1), + RK3066_PLL_RATE(1992000000, 1, 83, 1), + RK3066_PLL_RATE(1968000000, 1, 82, 1), + RK3066_PLL_RATE(1944000000, 1, 81, 1), + RK3066_PLL_RATE(1920000000, 1, 80, 1), + RK3066_PLL_RATE(1896000000, 1, 79, 1), + RK3066_PLL_RATE(1872000000, 1, 78, 1), + RK3066_PLL_RATE(1848000000, 1, 77, 1), + RK3066_PLL_RATE(1824000000, 1, 76, 1), + RK3066_PLL_RATE(1800000000, 1, 75, 1), + RK3066_PLL_RATE(1776000000, 1, 74, 1), + RK3066_PLL_RATE(1752000000, 1, 73, 1), + RK3066_PLL_RATE(1728000000, 1, 72, 1), + RK3066_PLL_RATE(1704000000, 1, 71, 1), + RK3066_PLL_RATE(1680000000, 1, 70, 1), + RK3066_PLL_RATE(1656000000, 1, 69, 1), + RK3066_PLL_RATE(1632000000, 1, 68, 1), + RK3066_PLL_RATE(1608000000, 1, 67, 1), + RK3066_PLL_RATE(1560000000, 1, 65, 1), + RK3066_PLL_RATE(1512000000, 1, 63, 1), + RK3066_PLL_RATE(1488000000, 1, 62, 1), + RK3066_PLL_RATE(1464000000, 1, 61, 1), + RK3066_PLL_RATE(1440000000, 1, 60, 1), + RK3066_PLL_RATE(1416000000, 1, 59, 1), + RK3066_PLL_RATE(1392000000, 1, 58, 1), + RK3066_PLL_RATE(1368000000, 1, 57, 1), + RK3066_PLL_RATE(1344000000, 1, 56, 1), + RK3066_PLL_RATE(1320000000, 1, 55, 1), + RK3066_PLL_RATE(1296000000, 1, 54, 1), + RK3066_PLL_RATE(1272000000, 1, 53, 1), + RK3066_PLL_RATE(1248000000, 1, 52, 1), + RK3066_PLL_RATE(1224000000, 1, 51, 1), + RK3066_PLL_RATE(1200000000, 1, 50, 1), + RK3066_PLL_RATE(1188000000, 2, 99, 1), + RK3066_PLL_RATE(1176000000, 1, 49, 1), + RK3066_PLL_RATE(1128000000, 1, 47, 1), + RK3066_PLL_RATE(1104000000, 1, 46, 1), + RK3066_PLL_RATE(1008000000, 1, 84, 2), + RK3066_PLL_RATE( 912000000, 1, 76, 2), + RK3066_PLL_RATE( 891000000, 8, 594, 2), + RK3066_PLL_RATE( 888000000, 1, 74, 2), + RK3066_PLL_RATE( 816000000, 1, 68, 2), + RK3066_PLL_RATE( 798000000, 2, 133, 2), + RK3066_PLL_RATE( 792000000, 1, 66, 2), + RK3066_PLL_RATE( 768000000, 1, 64, 2), + RK3066_PLL_RATE( 742500000, 8, 495, 2), + RK3066_PLL_RATE( 696000000, 1, 58, 2), + RK3066_PLL_RATE( 600000000, 1, 50, 2), + RK3066_PLL_RATE( 594000000, 2, 198, 4), + RK3066_PLL_RATE( 552000000, 1, 46, 2), + RK3066_PLL_RATE( 504000000, 1, 84, 4), + RK3066_PLL_RATE( 456000000, 1, 76, 4), + RK3066_PLL_RATE( 408000000, 1, 68, 4), + RK3066_PLL_RATE( 384000000, 2, 128, 4), + RK3066_PLL_RATE( 360000000, 1, 60, 4), + RK3066_PLL_RATE( 312000000, 1, 52, 4), + RK3066_PLL_RATE( 300000000, 1, 50, 4), + RK3066_PLL_RATE( 297000000, 2, 198, 8), + RK3066_PLL_RATE( 252000000, 1, 84, 8), + RK3066_PLL_RATE( 216000000, 1, 72, 8), + RK3066_PLL_RATE( 148500000, 2, 99, 8), + RK3066_PLL_RATE( 126000000, 1, 84, 16), + RK3066_PLL_RATE( 48000000, 1, 64, 32), + { /* sentinel */ }, +}; + +PNAME(mux_pll_p) = { "xin24m", "xin32k" }; +PNAME(mux_armclk_p) = { "apll_core", "gpll_core" }; +PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" }; +PNAME(mux_aclk_cpu_src_p) = { "cpll_aclk_cpu", "gpll_aclk_cpu" }; + +PNAME(mux_pll_src_cpll_gpll_p) = { "cpll", "gpll" }; +PNAME(mux_pll_src_npll_cpll_gpll_p) = { "npll", "cpll", "gpll" }; +PNAME(mux_pll_src_cpll_gpll_npll_p) = { "cpll", "gpll", "npll" }; +PNAME(mux_pll_src_cpll_gpll_usb480m_p) = { "cpll", "gpll", "usb480m" }; + +PNAME(mux_mmc_src_p) = { "cpll", "gpll", "xin24m", "xin24m" }; +PNAME(mux_i2s_pre_p) = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" }; +PNAME(mux_i2s_clkout_p) = { "i2s_pre", "xin12m" }; +PNAME(mux_spdif_p) = { "spdif_pre", "spdif_frac", "xin12m" }; +PNAME(mux_spdif_8ch_p) = { "spdif_8ch_pre", "spdif_8ch_frac", "xin12m" }; +PNAME(mux_uart0_pll_p) = { "cpll", "gpll", "usbphy_480m_src", "npll" }; +PNAME(mux_uart0_p) = { "uart0_src", "uart0_frac", "xin24m" }; +PNAME(mux_uart1_p) = { "uart1_src", "uart1_frac", "xin24m" }; +PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" }; +PNAME(mux_uart3_p) = { "uart3_src", "uart3_frac", "xin24m" }; +PNAME(mux_uart4_p) = { "uart4_src", "uart4_frac", "xin24m" }; +PNAME(mux_cif_out_p) = { "cif_src", "xin24m" }; +PNAME(mux_macref_p) = { "mac_src", "ext_gmac" }; +PNAME(mux_hsadcout_p) = { "hsadc_src", "ext_hsadc" }; +PNAME(mux_edp_24m_p) = { "ext_edp_24m", "xin24m" }; +PNAME(mux_tspout_p) = { "cpll", "gpll", "npll", "xin27m" }; + +PNAME(mux_usbphy480m_p) = { "sclk_otgphy0", "sclk_otgphy1", + "sclk_otgphy2" }; +PNAME(mux_hsicphy480m_p) = { "cpll", "gpll", "usbphy480m_src" }; +PNAME(mux_hsicphy12m_p) = { "hsicphy12m_xin12m", "hsicphy12m_usbphy" }; + +static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = { + [apll] = PLL(pll_rk3066, PLL_APLL, "apll", mux_pll_p, 0, RK3288_PLL_CON(0), + RK3288_MODE_CON, 0, 6, rk3288_pll_rates), + [dpll] = PLL(pll_rk3066, PLL_DPLL, "dpll", mux_pll_p, 0, RK3288_PLL_CON(4), + RK3288_MODE_CON, 4, 5, NULL), + [cpll] = PLL(pll_rk3066, PLL_CPLL, "cpll", mux_pll_p, 0, RK3288_PLL_CON(8), + RK3288_MODE_CON, 8, 7, rk3288_pll_rates), + [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12), + RK3288_MODE_CON, 12, 8, rk3288_pll_rates), + [npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3288_PLL_CON(16), + RK3288_MODE_CON, 14, 9, NULL), +}; + +static struct clk_div_table div_hclk_cpu_t[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 3, .div = 4 }, + { /* sentinel */}, +}; + +#define MFLAGS CLK_MUX_HIWORD_MASK +#define DFLAGS CLK_DIVIDER_HIWORD_MASK +#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE) + +static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { + /* + * Clock-Architecture Diagram 1 + */ + + GATE(0, "apll_core", "apll", 0, + RK3288_CLKGATE_CON(0), 1, GFLAGS), + GATE(0, "gpll_core", "gpll", 0, + RK3288_CLKGATE_CON(0), 2, GFLAGS), + COMPOSITE_NOGATE(0, "armclk", mux_armclk_p, 0, + RK3288_CLKSEL_CON(0), 15, 1, MFLAGS, 8, 5, DFLAGS), + + COMPOSITE_NOMUX(0, "armcore0", "armclk", 0, + RK3288_CLKSEL_CON(36), 0, 3, DFLAGS, + RK3288_CLKGATE_CON(12), 0, GFLAGS), + COMPOSITE_NOMUX(0, "armcore1", "armclk", 0, + RK3288_CLKSEL_CON(36), 4, 3, DFLAGS, + RK3288_CLKGATE_CON(12), 1, GFLAGS), + COMPOSITE_NOMUX(0, "armcore2", "armclk", 0, + RK3288_CLKSEL_CON(36), 8, 3, DFLAGS, + RK3288_CLKGATE_CON(12), 2, GFLAGS), + COMPOSITE_NOMUX(0, "armcore3", "armclk", 0, + RK3288_CLKSEL_CON(36), 12, 3, DFLAGS, + RK3288_CLKGATE_CON(12), 3, GFLAGS), + COMPOSITE_NOMUX(0, "l2ram", "armclk", 0, + RK3288_CLKSEL_CON(37), 0, 3, DFLAGS, + RK3288_CLKGATE_CON(12), 4, GFLAGS), + COMPOSITE_NOMUX(0, "aclk_core_m0", "armclk", 0, + RK3288_CLKSEL_CON(0), 0, 4, DFLAGS, + RK3288_CLKGATE_CON(12), 5, GFLAGS), + COMPOSITE_NOMUX(0, "aclk_core_mp", "armclk", 0, + RK3288_CLKSEL_CON(0), 4, 4, DFLAGS, + RK3288_CLKGATE_CON(12), 6, GFLAGS), + COMPOSITE_NOMUX(0, "atclk", "armclk", 0, + RK3288_CLKSEL_CON(37), 4, 5, DFLAGS, + RK3288_CLKGATE_CON(12), 7, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_dbg_pre", "armclk", 0, + RK3288_CLKSEL_CON(37), 9, 5, DFLAGS, + RK3288_CLKGATE_CON(12), 8, GFLAGS), + GATE(0, "pclk_dbg", "pclk_dbg_pre", 0, + RK3288_CLKGATE_CON(12), 9, GFLAGS), + GATE(0, "cs_dbg", "pclk_dbg_pre", 0, + RK3288_CLKGATE_CON(12), 10, GFLAGS), + GATE(0, "pclk_core_niu", "pclk_dbg_pre", 0, + RK3288_CLKGATE_CON(12), 11, GFLAGS), + + GATE(0, "dpll_ddr", "dpll", 0, + RK3288_CLKGATE_CON(0), 8, GFLAGS), + GATE(0, "gpll_ddr", "gpll", 0, + RK3288_CLKGATE_CON(0), 9, GFLAGS), + COMPOSITE_NOGATE(0, "ddrphy", mux_ddrphy_p, 0, + RK3288_CLKSEL_CON(26), 2, 1, MFLAGS, 0, 2, + DFLAGS | CLK_DIVIDER_POWER_OF_TWO), + + GATE(0, "gpll_aclk_cpu", "gpll", 0, + RK3288_CLKGATE_CON(0), 10, GFLAGS), + GATE(0, "cpll_aclk_cpu", "cpll", 0, + RK3288_CLKGATE_CON(0), 11, GFLAGS), + COMPOSITE_NOGATE(0, "aclk_cpu_src", mux_aclk_cpu_src_p, 0, + RK3288_CLKSEL_CON(1), 15, 1, MFLAGS, 3, 5, DFLAGS), + DIV(0, "aclk_cpu_pre", "aclk_cpu_src", 0, + RK3288_CLKSEL_CON(1), 0, 3, DFLAGS), + GATE(0, "aclk_cpu", "aclk_cpu_pre", 0, + RK3288_CLKGATE_CON(0), 3, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_cpu", "aclk_cpu_pre", 0, + RK3288_CLKSEL_CON(1), 12, 3, DFLAGS, + RK3288_CLKGATE_CON(0), 5, GFLAGS), + COMPOSITE_NOMUX_DIVTBL(0, "hclk_cpu", "aclk_cpu_pre", 0, + RK3288_CLKSEL_CON(1), 8, 2, DFLAGS, div_hclk_cpu_t, + RK3288_CLKGATE_CON(0), 4, GFLAGS), + GATE(0, "c2c_host", "aclk_cpu_src", 0, + RK3288_CLKGATE_CON(13), 8, GFLAGS), + COMPOSITE_NOMUX(0, "crypto", "aclk_cpu_pre", 0, + RK3288_CLKSEL_CON(26), 6, 2, DFLAGS, + RK3288_CLKGATE_CON(5), 4, GFLAGS), + GATE(0, "aclk_bus_2pmu", "aclk_cpu_pre", 0, + RK3288_CLKGATE_CON(0), 7, GFLAGS), + + COMPOSITE(0, "i2s_src", mux_pll_src_cpll_gpll_p, 0, + RK3288_CLKSEL_CON(4), 15, 1, MFLAGS, 0, 7, DFLAGS, + RK3288_CLKGATE_CON(4), 1, GFLAGS), + COMPOSITE_FRAC(0, "i2s_frac", "i2s_src", 0, + RK3288_CLKSEL_CON(8), 0, + RK3288_CLKGATE_CON(4), 2, GFLAGS), + MUX(0, "i2s_pre", mux_i2s_pre_p, 0, + RK3288_CLKSEL_CON(4), 8, 2, MFLAGS), + COMPOSITE_NODIV(0, "i2s0_clkout", mux_i2s_clkout_p, 0, + RK3288_CLKSEL_CON(4), 12, 1, MFLAGS, + RK3288_CLKGATE_CON(4), 0, GFLAGS), + GATE(SCLK_I2S0, "sclk_i2s0", "i2s_pre", 0, + RK3288_CLKGATE_CON(4), 3, GFLAGS), + + MUX(0, "spdif_src", mux_pll_src_cpll_gpll_p, 0, + RK3288_CLKSEL_CON(5), 15, 1, MFLAGS), + COMPOSITE_NOMUX(0, "spdif_pre", "spdif_src", 0, + RK3288_CLKSEL_CON(5), 0, 7, DFLAGS, + RK3288_CLKGATE_CON(4), 4, GFLAGS), + COMPOSITE_FRAC(0, "spdif_frac", "spdif_src", 0, + RK3288_CLKSEL_CON(9), 0, + RK3288_CLKGATE_CON(4), 5, GFLAGS), + COMPOSITE_NODIV(SCLK_SPDIF, "sclk_spdif", mux_spdif_p, 0, + RK3288_CLKSEL_CON(5), 8, 2, MFLAGS, + RK3288_CLKGATE_CON(4), 6, GFLAGS), + COMPOSITE_NOMUX(0, "spdif_8ch_pre", "spdif_src", 0, + RK3288_CLKSEL_CON(40), 0, 7, DFLAGS, + RK3288_CLKGATE_CON(4), 7, GFLAGS), + COMPOSITE_FRAC(0, "spdif_8ch_frac", "spdif_8ch_src", 0, + RK3288_CLKSEL_CON(41), 0, + RK3288_CLKGATE_CON(4), 8, GFLAGS), + COMPOSITE_NODIV(SCLK_SPDIF8CH, "sclk_spdif_8ch", mux_spdif_8ch_p, 0, + RK3288_CLKSEL_CON(40), 8, 2, MFLAGS, + RK3288_CLKGATE_CON(4), 9, GFLAGS), + + GATE(0, "sclk_acc_efuse", "xin24m", 0, + RK3288_CLKGATE_CON(0), 12, GFLAGS), + + GATE(SCLK_TIMER0, "sclk_timer0", "xin24m", 0, + RK3288_CLKGATE_CON(1), 0, GFLAGS), + GATE(SCLK_TIMER1, "sclk_timer1", "xin24m", 0, + RK3288_CLKGATE_CON(1), 1, GFLAGS), + GATE(SCLK_TIMER2, "sclk_timer2", "xin24m", 0, + RK3288_CLKGATE_CON(1), 2, GFLAGS), + GATE(SCLK_TIMER3, "sclk_timer3", "xin24m", 0, + RK3288_CLKGATE_CON(1), 3, GFLAGS), + GATE(SCLK_TIMER4, "sclk_timer4", "xin24m", 0, + RK3288_CLKGATE_CON(1), 4, GFLAGS), + GATE(SCLK_TIMER5, "sclk_timer5", "xin24m", 0, + RK3288_CLKGATE_CON(1), 5, GFLAGS), + + /* + * Clock-Architecture Diagram 2 + */ + + COMPOSITE(0, "aclk_vepu", mux_pll_src_cpll_gpll_usb480m_p, 0, + RK3288_CLKSEL_CON(32), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3288_CLKGATE_CON(3), 9, GFLAGS), + COMPOSITE(0, "aclk_vdpu", mux_pll_src_cpll_gpll_usb480m_p, 0, + RK3288_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3288_CLKGATE_CON(3), 11, GFLAGS), + + COMPOSITE(0, "aclk_vio0", mux_pll_src_cpll_gpll_usb480m_p, 0, + RK3288_CLKSEL_CON(31), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3288_CLKGATE_CON(3), 0, GFLAGS), + DIV(0, "hclk_vio", "aclk_vio0", 0, + RK3288_CLKSEL_CON(28), 8, 5, DFLAGS), + COMPOSITE(0, "aclk_vio1", mux_pll_src_cpll_gpll_usb480m_p, 0, + RK3288_CLKSEL_CON(31), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3288_CLKGATE_CON(3), 2, GFLAGS), + + COMPOSITE(0, "aclk_rga_pre", mux_pll_src_cpll_gpll_usb480m_p, 0, + RK3288_CLKSEL_CON(30), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3288_CLKGATE_CON(3), 5, GFLAGS), + COMPOSITE(0, "sclk_rga", mux_pll_src_cpll_gpll_usb480m_p, 0, + RK3288_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3288_CLKGATE_CON(3), 4, GFLAGS), + + COMPOSITE(DCLK_VOP0, "dclk_vop0", mux_pll_src_cpll_gpll_npll_p, 0, + RK3288_CLKSEL_CON(27), 0, 2, MFLAGS, 8, 8, DFLAGS, + RK3288_CLKGATE_CON(3), 1, GFLAGS), + COMPOSITE(DCLK_VOP1, "dclk_vop1", mux_pll_src_cpll_gpll_npll_p, 0, + RK3288_CLKSEL_CON(29), 6, 2, MFLAGS, 8, 8, DFLAGS, + RK3288_CLKGATE_CON(3), 3, GFLAGS), + + COMPOSITE_NODIV(0, "sclk_edp_24m", mux_edp_24m_p, 0, + RK3288_CLKSEL_CON(28), 15, 1, MFLAGS, + RK3288_CLKGATE_CON(3), 12, GFLAGS), + COMPOSITE(0, "sclk_edp", mux_pll_src_cpll_gpll_npll_p, 0, + RK3288_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 6, DFLAGS, + RK3288_CLKGATE_CON(3), 13, GFLAGS), + + COMPOSITE(0, "sclk_isp", mux_pll_src_cpll_gpll_npll_p, 0, + RK3288_CLKSEL_CON(6), 6, 2, MFLAGS, 0, 6, DFLAGS, + RK3288_CLKGATE_CON(3), 14, GFLAGS), + COMPOSITE(0, "sclk_isp_jpe", mux_pll_src_cpll_gpll_npll_p, 0, + RK3288_CLKSEL_CON(6), 14, 2, MFLAGS, 8, 6, DFLAGS, + RK3288_CLKGATE_CON(3), 15, GFLAGS), + + GATE(0, "sclk_hdmi_hdcp", "xin24m", 0, + RK3288_CLKGATE_CON(5), 12, GFLAGS), + GATE(0, "sclk_hdmi_cec", "xin32k", 0, + RK3288_CLKGATE_CON(5), 11, GFLAGS), + + COMPOSITE(0, "aclk_hevc", mux_pll_src_cpll_gpll_npll_p, 0, + RK3288_CLKSEL_CON(39), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3288_CLKGATE_CON(13), 13, GFLAGS), + DIV(0, "hclk_hevc", "aclk_hevc", 0, + RK3288_CLKSEL_CON(40), 12, 2, DFLAGS), + + COMPOSITE(0, "sclk_hevc_cabac", mux_pll_src_cpll_gpll_npll_p, 0, + RK3288_CLKSEL_CON(42), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3288_CLKGATE_CON(13), 14, GFLAGS), + COMPOSITE(0, "sclk_hevc_core", mux_pll_src_cpll_gpll_npll_p, 0, + RK3288_CLKSEL_CON(42), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3288_CLKGATE_CON(13), 15, GFLAGS), + + COMPOSITE_NODIV(0, "vip_src", mux_pll_src_cpll_gpll_p, 0, + RK3288_CLKSEL_CON(26), 8, 1, MFLAGS, + RK3288_CLKGATE_CON(3), 7, GFLAGS), + COMPOSITE_NOGATE(0, "sclk_vip_out", mux_cif_out_p, 0, + RK3288_CLKSEL_CON(26), 15, 1, MFLAGS, 9, 5, DFLAGS), + + DIV(0, "pclk_pd_alive", "gpll", 0, + RK3288_CLKSEL_CON(33), 8, 5, DFLAGS), + COMPOSITE_NOMUX(0, "pclk_pd_pmu", "gpll", 0, + RK3288_CLKSEL_CON(33), 0, 5, DFLAGS, + RK3288_CLKGATE_CON(5), 8, GFLAGS), + + COMPOSITE(SCLK_GPU, "sclk_gpu", mux_pll_src_cpll_gpll_usb480m_p, 0, + RK3288_CLKSEL_CON(34), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3288_CLKGATE_CON(5), 7, GFLAGS), + + COMPOSITE(0, "aclk_peri_src", mux_pll_src_cpll_gpll_p, 0, + RK3288_CLKSEL_CON(10), 15, 1, MFLAGS, 0, 5, DFLAGS, + RK3288_CLKGATE_CON(2), 0, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_peri", "aclk_peri_src", 0, + RK3288_CLKSEL_CON(10), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK3288_CLKGATE_CON(2), 3, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_peri", "aclk_peri_src", 0, + RK3288_CLKSEL_CON(10), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK3288_CLKGATE_CON(2), 2, GFLAGS), + GATE(0, "aclk_peri", "aclk_peri_src", 0, + RK3288_CLKGATE_CON(2), 1, GFLAGS), + + /* + * Clock-Architecture Diagram 3 + */ + + COMPOSITE(SCLK_SPI0, "sclk_spi0", mux_pll_src_cpll_gpll_p, 0, + RK3288_CLKSEL_CON(25), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3288_CLKGATE_CON(2), 9, GFLAGS), + COMPOSITE(SCLK_SPI1, "sclk_spi1", mux_pll_src_cpll_gpll_p, 0, + RK3288_CLKSEL_CON(25), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3288_CLKGATE_CON(2), 10, GFLAGS), + COMPOSITE(SCLK_SPI2, "sclk_spi2", mux_pll_src_cpll_gpll_p, 0, + RK3288_CLKSEL_CON(39), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3288_CLKGATE_CON(2), 11, GFLAGS), + + COMPOSITE(SCLK_SDMMC, "sclk_sdmmc", mux_mmc_src_p, 0, + RK3288_CLKSEL_CON(11), 6, 2, MFLAGS, 0, 6, DFLAGS, + RK3288_CLKGATE_CON(13), 0, GFLAGS), + COMPOSITE(SCLK_SDIO0, "sclk_sdio0", mux_mmc_src_p, 0, + RK3288_CLKSEL_CON(12), 6, 2, MFLAGS, 0, 6, DFLAGS, + RK3288_CLKGATE_CON(13), 1, GFLAGS), + COMPOSITE(SCLK_SDIO1, "sclk_sdio1", mux_mmc_src_p, 0, + RK3288_CLKSEL_CON(34), 14, 2, MFLAGS, 8, 6, DFLAGS, + RK3288_CLKGATE_CON(13), 2, GFLAGS), + COMPOSITE(SCLK_EMMC, "sclk_emmc", mux_mmc_src_p, 0, + RK3288_CLKSEL_CON(12), 14, 2, MFLAGS, 8, 6, DFLAGS, + RK3288_CLKGATE_CON(13), 3, GFLAGS), + + COMPOSITE(0, "sclk_tspout", mux_tspout_p, 0, + RK3288_CLKSEL_CON(35), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3288_CLKGATE_CON(4), 11, GFLAGS), + COMPOSITE(0, "sclk_tsp", mux_pll_src_cpll_gpll_npll_p, 0, + RK3288_CLKSEL_CON(35), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3288_CLKGATE_CON(4), 10, GFLAGS), + + GATE(SCLK_OTGPHY0, "sclk_otgphy0", "usb480m", 0, + RK3288_CLKGATE_CON(13), 4, GFLAGS), + GATE(SCLK_OTGPHY1, "sclk_otgphy1", "usb480m", 0, + RK3288_CLKGATE_CON(13), 5, GFLAGS), + GATE(SCLK_OTGPHY2, "sclk_otgphy2", "usb480m", 0, + RK3288_CLKGATE_CON(13), 6, GFLAGS), + GATE(SCLK_OTG_ADP, "sclk_otg_adp", "xin32k", 0, + RK3288_CLKGATE_CON(13), 7, GFLAGS), + + COMPOSITE_NOMUX(SCLK_TSADC, "sclk_tsadc", "xin32k", 0, + RK3288_CLKSEL_CON(2), 0, 6, DFLAGS, + RK3288_CLKGATE_CON(2), 7, GFLAGS), + + COMPOSITE_NOMUX(SCLK_SARADC, "sclk_saradc", "xin24m", 0, + RK3288_CLKSEL_CON(24), 8, 8, DFLAGS, + RK3288_CLKGATE_CON(2), 8, GFLAGS), + + GATE(SCLK_PS2C, "sclk_ps2c", "xin24m", 0, + RK3288_CLKGATE_CON(5), 13, GFLAGS), + + COMPOSITE(SCLK_NANDC0, "sclk_nandc0", mux_pll_src_cpll_gpll_p, 0, + RK3288_CLKSEL_CON(38), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3288_CLKGATE_CON(5), 5, GFLAGS), + COMPOSITE(SCLK_NANDC1, "sclk_nandc1", mux_pll_src_cpll_gpll_p, 0, + RK3288_CLKSEL_CON(38), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3288_CLKGATE_CON(5), 6, GFLAGS), + + COMPOSITE(0, "uart0_src", mux_uart0_pll_p, 0, + RK3288_CLKSEL_CON(13), 13, 2, MFLAGS, 0, 7, DFLAGS, + RK3288_CLKGATE_CON(1), 8, GFLAGS), + COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", 0, + RK3288_CLKSEL_CON(17), 0, + RK3288_CLKGATE_CON(1), 9, GFLAGS), + MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, 0, + RK3288_CLKSEL_CON(13), 8, 2, MFLAGS), + MUX(0, "uart_src", mux_pll_src_cpll_gpll_p, 0, + RK3288_CLKSEL_CON(13), 15, 1, MFLAGS), + COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0, + RK3288_CLKSEL_CON(14), 0, 7, DFLAGS, + RK3288_CLKGATE_CON(1), 10, GFLAGS), + COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", 0, + RK3288_CLKSEL_CON(18), 0, + RK3288_CLKGATE_CON(1), 11, GFLAGS), + MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, 0, + RK3288_CLKSEL_CON(14), 8, 2, MFLAGS), + COMPOSITE_NOMUX(0, "uart2_src", "uart_src", 0, + RK3288_CLKSEL_CON(15), 0, 7, DFLAGS, + RK3288_CLKGATE_CON(1), 12, GFLAGS), + COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", 0, + RK3288_CLKSEL_CON(19), 0, + RK3288_CLKGATE_CON(1), 13, GFLAGS), + MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, 0, + RK3288_CLKSEL_CON(15), 8, 2, MFLAGS), + COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0, + RK3288_CLKSEL_CON(16), 0, 7, DFLAGS, + RK3288_CLKGATE_CON(1), 14, GFLAGS), + COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", 0, + RK3288_CLKSEL_CON(20), 0, + RK3288_CLKGATE_CON(1), 15, GFLAGS), + MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, 0, + RK3288_CLKSEL_CON(16), 8, 2, MFLAGS), + COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0, + RK3288_CLKSEL_CON(3), 0, 7, DFLAGS, + RK3288_CLKGATE_CON(2), 12, GFLAGS), + COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", 0, + RK3288_CLKSEL_CON(7), 0, + RK3288_CLKGATE_CON(2), 13, GFLAGS), + MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, 0, + RK3288_CLKSEL_CON(3), 8, 2, MFLAGS), + + COMPOSITE(0, "mac_src", mux_pll_src_npll_cpll_gpll_p, 0, + RK3288_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS, + RK3288_CLKGATE_CON(2), 5, GFLAGS), + MUX(0, "macref", mux_macref_p, 0, + RK3288_CLKSEL_CON(21), 4, 1, MFLAGS), + GATE(0, "sclk_macref_out", "macref", 0, + RK3288_CLKGATE_CON(5), 3, GFLAGS), + GATE(SCLK_MACREF, "sclk_macref", "macref", 0, + RK3288_CLKGATE_CON(5), 2, GFLAGS), + GATE(SCLK_MAC_RX, "sclk_mac_rx", "macref", 0, + RK3288_CLKGATE_CON(5), 0, GFLAGS), + GATE(SCLK_MAC_TX, "sclk_mac_tx", "macref", 0, + RK3288_CLKGATE_CON(5), 1, GFLAGS), + + COMPOSITE(0, "hsadc_src", mux_pll_src_cpll_gpll_p, 0, + RK3288_CLKSEL_CON(22), 0, 1, MFLAGS, 8, 8, DFLAGS, + RK3288_CLKGATE_CON(2), 6, GFLAGS), + MUX(SCLK_HSADC, "sclk_hsadc_out", mux_hsadcout_p, 0, + RK3288_CLKSEL_CON(22), 4, 1, MFLAGS), + + GATE(0, "jtag", "ext_jtag", 0, + RK3288_CLKGATE_CON(4), 14, GFLAGS), + + COMPOSITE_NODIV(0, "usbphy480m_src", mux_usbphy480m_p, 0, + RK3288_CLKSEL_CON(13), 11, 2, MFLAGS, + RK3288_CLKGATE_CON(5), 15, GFLAGS), + COMPOSITE_NODIV(SCLK_HSICPHY480M, "sclk_hsicphy480m", mux_hsicphy480m_p, 0, + RK3288_CLKSEL_CON(29), 0, 2, MFLAGS, + RK3288_CLKGATE_CON(3), 6, GFLAGS), + GATE(0, "hsicphy12m_xin12m", "xin12m", 0, + RK3288_CLKGATE_CON(13), 9, GFLAGS), + DIV(0, "hsicphy12m_usbphy", "sclk_hsicphy480m", 0, + RK3288_CLKSEL_CON(11), 8, 6, DFLAGS), + MUX(SCLK_HSICPHY12M, "sclk_hsicphy12m", mux_hsicphy12m_p, 0, + RK3288_CLKSEL_CON(22), 4, 1, MFLAGS), + + /* + * Clock-Architecture Diagram 4 + */ + + /* aclk_cpu gates */ + GATE(0, "sclk_intmem0", "aclk_cpu", 0, RK3288_CLKGATE_CON(10), 5, GFLAGS), + GATE(0, "sclk_intmem1", "aclk_cpu", 0, RK3288_CLKGATE_CON(10), 6, GFLAGS), + GATE(0, "sclk_intmem2", "aclk_cpu", 0, RK3288_CLKGATE_CON(10), 7, GFLAGS), + GATE(ACLK_DMAC1, "aclk_dmac1", "aclk_cpu", 0, RK3288_CLKGATE_CON(10), 12, GFLAGS), + GATE(0, "aclk_strc_sys", "aclk_cpu", 0, RK3288_CLKGATE_CON(10), 13, GFLAGS), + GATE(0, "aclk_intmem", "aclk_cpu", 0, RK3288_CLKGATE_CON(10), 4, GFLAGS), + GATE(ACLK_CRYPTO, "aclk_crypto", "aclk_cpu", 0, RK3288_CLKGATE_CON(11), 6, GFLAGS), + GATE(0, "aclk_ccp", "aclk_cpu", 0, RK3288_CLKGATE_CON(11), 8, GFLAGS), + + /* hclk_cpu gates */ + GATE(HCLK_CRYPTO, "hclk_crypto", "hclk_cpu", 0, RK3288_CLKGATE_CON(11), 7, GFLAGS), + GATE(HCLK_I2S0, "hclk_i2s0", "hclk_cpu", 0, RK3288_CLKGATE_CON(10), 8, GFLAGS), + GATE(HCLK_ROM, "hclk_rom", "hclk_cpu", 0, RK3288_CLKGATE_CON(10), 9, GFLAGS), + GATE(HCLK_SPDIF, "hclk_spdif", "hclk_cpu", 0, RK3288_CLKGATE_CON(10), 10, GFLAGS), + GATE(HCLK_SPDIF8CH, "hclk_spdif_8ch", "hclk_cpu", 0, RK3288_CLKGATE_CON(10), 11, GFLAGS), + + /* pclk_cpu gates */ + GATE(PCLK_PWM, "pclk_pwm", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 0, GFLAGS), + GATE(PCLK_TIMER, "pclk_timer", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 1, GFLAGS), + GATE(PCLK_I2C0, "pclk_i2c0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 2, GFLAGS), + GATE(PCLK_I2C1, "pclk_i2c1", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 3, GFLAGS), + GATE(0, "pclk_ddrupctl0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 14, GFLAGS), + GATE(0, "pclk_publ0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 15, GFLAGS), + GATE(0, "pclk_ddrupctl1", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 0, GFLAGS), + GATE(0, "pclk_publ1", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 1, GFLAGS), + GATE(0, "pclk_efuse_1024", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 2, GFLAGS), + GATE(PCLK_TZPC, "pclk_tzpc", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 3, GFLAGS), + GATE(PCLK_UART2, "pclk_uart2", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 9, GFLAGS), + GATE(0, "pclk_efuse_256", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 10, GFLAGS), + GATE(PCLK_RKPWM, "pclk_rkpwm", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 11, GFLAGS), + + /* ddrctrl [DDR Controller PHY clock] gates */ + GATE(0, "nclk_ddrupctl0", "ddrphy", 0, RK3288_CLKGATE_CON(11), 4, GFLAGS), + GATE(0, "nclk_ddrupctl1", "ddrphy", 0, RK3288_CLKGATE_CON(11), 5, GFLAGS), + + /* ddrphy gates */ + GATE(0, "sclk_ddrphy0", "ddrphy", 0, RK3288_CLKGATE_CON(4), 12, GFLAGS), + GATE(0, "sclk_ddrphy1", "ddrphy", 0, RK3288_CLKGATE_CON(4), 13, GFLAGS), + + /* aclk_peri gates */ + GATE(0, "aclk_peri_axi_matrix", "aclk_peri", 0, RK3288_CLKGATE_CON(6), 2, GFLAGS), + GATE(ACLK_DMAC2, "aclk_dmac2", "aclk_peri", 0, RK3288_CLKGATE_CON(6), 3, GFLAGS), + GATE(0, "aclk_peri_niu", "aclk_peri", 0, RK3288_CLKGATE_CON(7), 11, GFLAGS), + GATE(ACLK_MMU, "aclk_mmu", "aclk_peri", 0, RK3288_CLKGATE_CON(8), 12, GFLAGS), + GATE(ACLK_GMAC, "aclk_gmac", "aclk_peri", 0, RK3288_CLKGATE_CON(8), 0, GFLAGS), + GATE(HCLK_GPS, "hclk_gps", "aclk_peri", 0, RK3288_CLKGATE_CON(8), 2, GFLAGS), + + /* hclk_peri gates */ + GATE(0, "hclk_peri_matrix", "hclk_peri", 0, RK3288_CLKGATE_CON(6), 0, GFLAGS), + GATE(HCLK_OTG0, "hclk_otg0", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 4, GFLAGS), + GATE(HCLK_USBHOST0, "hclk_host0", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 6, GFLAGS), + GATE(HCLK_USBHOST1, "hclk_host1", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 7, GFLAGS), + GATE(HCLK_HSIC, "hclk_hsic", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 8, GFLAGS), + GATE(0, "hclk_usb_peri", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 9, GFLAGS), + GATE(0, "hclk_peri_ahb_arbi", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 10, GFLAGS), + GATE(0, "hclk_emem", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 12, GFLAGS), + GATE(0, "hclk_mem", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 13, GFLAGS), + GATE(HCLK_NANDC0, "hclk_nandc0", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 14, GFLAGS), + GATE(HCLK_NANDC1, "hclk_nandc1", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 15, GFLAGS), + GATE(HCLK_TSP, "hclk_tsp", "hclk_peri", 0, RK3288_CLKGATE_CON(8), 8, GFLAGS), + GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0, RK3288_CLKGATE_CON(8), 3, GFLAGS), + GATE(HCLK_SDIO0, "hclk_sdio0", "hclk_peri", 0, RK3288_CLKGATE_CON(8), 4, GFLAGS), + GATE(HCLK_SDIO1, "hclk_sdio1", "hclk_peri", 0, RK3288_CLKGATE_CON(8), 5, GFLAGS), + GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK3288_CLKGATE_CON(8), 6, GFLAGS), + GATE(HCLK_HSADC, "hclk_hsadc", "hclk_peri", 0, RK3288_CLKGATE_CON(8), 7, GFLAGS), + GATE(0, "pmu_hclk_otg0", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 5, GFLAGS), + + /* pclk_peri gates */ + GATE(0, "pclk_peri_matrix", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 1, GFLAGS), + GATE(PCLK_SPI0, "pclk_spi0", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 4, GFLAGS), + GATE(PCLK_SPI1, "pclk_spi1", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 5, GFLAGS), + GATE(PCLK_SPI2, "pclk_spi2", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 6, GFLAGS), + GATE(PCLK_PS2C, "pclk_ps2c", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 7, GFLAGS), + GATE(PCLK_UART0, "pclk_uart0", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 8, GFLAGS), + GATE(PCLK_UART1, "pclk_uart1", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 9, GFLAGS), + GATE(PCLK_I2C4, "pclk_i2c4", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 15, GFLAGS), + GATE(PCLK_UART3, "pclk_uart3", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 11, GFLAGS), + GATE(PCLK_UART4, "pclk_uart4", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 12, GFLAGS), + GATE(PCLK_I2C2, "pclk_i2c2", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 13, GFLAGS), + GATE(PCLK_I2C3, "pclk_i2c3", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 14, GFLAGS), + GATE(PCLK_SARADC, "pclk_saradc", "pclk_peri", 0, RK3288_CLKGATE_CON(7), 1, GFLAGS), + GATE(PCLK_TSADC, "pclk_tsadc", "pclk_peri", 0, RK3288_CLKGATE_CON(7), 2, GFLAGS), + GATE(PCLK_SIM, "pclk_sim", "pclk_peri", 0, RK3288_CLKGATE_CON(7), 3, GFLAGS), + GATE(PCLK_I2C5, "pclk_i2c5", "pclk_peri", 0, RK3288_CLKGATE_CON(7), 0, GFLAGS), + GATE(PCLK_GMAC, "pclk_gmac", "pclk_peri", 0, RK3288_CLKGATE_CON(8), 1, GFLAGS), + + GATE(SCLK_LCDC_PWM0, "sclk_lcdc_pwm0", "xin24m", 0, RK3288_CLKGATE_CON(13), 10, GFLAGS), + GATE(SCLK_LCDC_PWM1, "sclk_lcdc_pwm1", "xin24m", 0, RK3288_CLKGATE_CON(13), 11, GFLAGS), + GATE(0, "sclk_pvtm_core", "xin24m", 0, RK3288_CLKGATE_CON(5), 9, GFLAGS), + GATE(0, "sclk_pvtm_gpu", "xin24m", 0, RK3288_CLKGATE_CON(5), 10, GFLAGS), + GATE(0, "sclk_mipidsi_24m", "xin24m", 0, RK3288_CLKGATE_CON(5), 15, GFLAGS), + + /* sclk_gpu gates */ + GATE(ACLK_GPU, "aclk_gpu", "sclk_gpu", 0, RK3288_CLKGATE_CON(18), 0, GFLAGS), + + /* pclk_pd_alive gates */ + GATE(PCLK_GPIO8, "pclk_gpio8", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 8, GFLAGS), + GATE(PCLK_GPIO7, "pclk_gpio7", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 7, GFLAGS), + GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 1, GFLAGS), + GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 2, GFLAGS), + GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 3, GFLAGS), + GATE(PCLK_GPIO4, "pclk_gpio4", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 4, GFLAGS), + GATE(PCLK_GPIO5, "pclk_gpio5", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 5, GFLAGS), + GATE(PCLK_GPIO6, "pclk_gpio6", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 6, GFLAGS), + GATE(PCLK_GRF, "pclk_grf", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 11, GFLAGS), + GATE(0, "pclk_alive_niu", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 12, GFLAGS), + + /* pclk_pd_pmu gates */ + GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", 0, RK3288_CLKGATE_CON(17), 0, GFLAGS), + GATE(0, "pclk_intmem1", "pclk_pd_pmu", 0, RK3288_CLKGATE_CON(17), 1, GFLAGS), + GATE(0, "pclk_pmu_niu", "pclk_pd_pmu", 0, RK3288_CLKGATE_CON(17), 2, GFLAGS), + GATE(PCLK_SGRF, "pclk_sgrf", "pclk_pd_pmu", 0, RK3288_CLKGATE_CON(17), 3, GFLAGS), + GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_pd_pmu", 0, RK3288_CLKGATE_CON(17), 4, GFLAGS), + + /* hclk_vio gates */ + GATE(HCLK_RGA, "hclk_rga", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 1, GFLAGS), + GATE(HCLK_VOP0, "hclk_vop0", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 6, GFLAGS), + GATE(HCLK_VOP1, "hclk_vop1", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 8, GFLAGS), + GATE(0, "hclk_vio_ahb_arbi", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 9, GFLAGS), + GATE(0, "hclk_vio_niu", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 10, GFLAGS), + GATE(0, "hclk_vip", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 15, GFLAGS), + GATE(HCLK_IEP, "hclk_iep", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 3, GFLAGS), + GATE(HCLK_ISP, "hclk_isp", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 1, GFLAGS), + GATE(0, "hclk_vio2_h2p", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 10, GFLAGS), + GATE(0, "pclk_mipi_dsi0", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 4, GFLAGS), + GATE(0, "pclk_mipi_dsi1", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 5, GFLAGS), + GATE(0, "pclk_mipi_csi", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 6, GFLAGS), + GATE(0, "pclk_lvds_phy", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 7, GFLAGS), + GATE(0, "pclk_edp_ctrl", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 8, GFLAGS), + GATE(0, "pclk_hdmi_ctrl", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 9, GFLAGS), + GATE(0, "pclk_vio2_h2p", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 11, GFLAGS), + + /* aclk_vio0 gates */ + GATE(ACLK_VOP0, "aclk_vop0", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 5, GFLAGS), + GATE(0, "aclk_iep", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 2, GFLAGS), + GATE(0, "aclk_vio0_niu", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 11, GFLAGS), + GATE(0, "aclk_vip", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 14, GFLAGS), + + /* aclk_vio1 gates */ + GATE(ACLK_VOP1, "aclk_vop1", "aclk_vio1", 0, RK3288_CLKGATE_CON(15), 7, GFLAGS), + GATE(0, "aclk_isp", "aclk_vio1", 0, RK3288_CLKGATE_CON(16), 2, GFLAGS), + GATE(0, "aclk_vio1_niu", "aclk_vio1", 0, RK3288_CLKGATE_CON(15), 12, GFLAGS), + + /* aclk_rga_pre gates */ + GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK3288_CLKGATE_CON(15), 0, GFLAGS), + GATE(0, "aclk_rga_niu", "aclk_rga_pre", 0, RK3288_CLKGATE_CON(15), 13, GFLAGS), + + /* + * Other ungrouped clocks. + */ + + GATE(0, "pclk_vip_in", "ext_vip", 0, RK3288_CLKGATE_CON(16), 0, GFLAGS), + GATE(0, "pclk_isp_in", "ext_isp", 0, RK3288_CLKGATE_CON(16), 3, GFLAGS), +}; + +static void __init rk3288_clk_init(struct device_node *np) +{ + void __iomem *reg_base; + struct clk *clk; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: could not map cru region\n", __func__); + return; + } + + rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + + /* xin12m is created by an cru-internal divider */ + clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2); + if (IS_ERR(clk)) + pr_warn("%s: could not register clock xin12m: %ld\n", + __func__, PTR_ERR(clk)); + + + clk = clk_register_fixed_factor(NULL, "usb480m", "xin24m", 0, 20, 1); + if (IS_ERR(clk)) + pr_warn("%s: could not register clock usb480m: %ld\n", + __func__, PTR_ERR(clk)); + + rockchip_clk_register_plls(rk3288_pll_clks, + ARRAY_SIZE(rk3288_pll_clks), + RK3288_GRF_SOC_STATUS); + rockchip_clk_register_branches(rk3288_clk_branches, + ARRAY_SIZE(rk3288_clk_branches)); + + rockchip_register_softrst(np, 9, reg_base + RK3288_SOFTRST_CON(0), + ROCKCHIP_SOFTRST_HIWORD_MASK); +} +CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init); diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 32c334d..887cbde 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -40,6 +40,15 @@ #define RK2928_SOFTRST_CON(x) (x * 0x4 + 0x110) #define RK2928_MISC_CON 0x134 +#define RK3288_PLL_CON(x) RK2928_PLL_CON(x) +#define RK3288_MODE_CON 0x50 +#define RK3288_CLKSEL_CON(x) (x * 0x4 + 0x60) +#define RK3288_CLKGATE_CON(x) (x * 0x4 + 0x160) +#define RK3288_GLB_SRST_FST 0x1b0 +#define RK3288_GLB_SRST_SND 0x1b4 +#define RK3288_SOFTRST_CON(x) (x * 0x4 + 0x1b8) +#define RK3288_MISC_CON 0x1e8 + enum rockchip_pll_type { pll_rk3066, }; diff --git a/include/dt-bindings/clock/rk3288-cru.h b/include/dt-bindings/clock/rk3288-cru.h new file mode 100644 index 0000000..ebcb460 --- /dev/null +++ b/include/dt-bindings/clock/rk3288-cru.h @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2014 MundoReader S.L. + * Author: Heiko Stuebner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* core clocks */ +#define PLL_APLL 1 +#define PLL_DPLL 2 +#define PLL_CPLL 3 +#define PLL_GPLL 4 +#define PLL_NPLL 5 + +/* sclk gates (special clocks) */ +#define SCLK_GPU 64 +#define SCLK_SPI0 65 +#define SCLK_SPI1 66 +#define SCLK_SPI2 67 +#define SCLK_SDMMC 68 +#define SCLK_SDIO0 69 +#define SCLK_SDIO1 70 +#define SCLK_EMMC 71 +#define SCLK_TSADC 72 +#define SCLK_SARADC 73 +#define SCLK_PS2C 74 +#define SCLK_NANDC0 75 +#define SCLK_NANDC1 76 +#define SCLK_UART0 77 +#define SCLK_UART1 78 +#define SCLK_UART2 79 +#define SCLK_UART3 80 +#define SCLK_UART4 81 +#define SCLK_I2S0 82 +#define SCLK_SPDIF 83 +#define SCLK_SPDIF8CH 84 +#define SCLK_TIMER0 85 +#define SCLK_TIMER1 86 +#define SCLK_TIMER2 87 +#define SCLK_TIMER3 88 +#define SCLK_TIMER4 89 +#define SCLK_TIMER5 90 +#define SCLK_TIMER6 91 +#define SCLK_HSADC 92 +#define SCLK_OTGPHY0 93 +#define SCLK_OTGPHY1 94 +#define SCLK_OTGPHY2 95 +#define SCLK_OTG_ADP 96 +#define SCLK_HSICPHY480M 97 +#define SCLK_HSICPHY12M 98 +#define SCLK_MACREF 99 +#define SCLK_LCDC_PWM0 100 +#define SCLK_LCDC_PWM1 101 +#define SCLK_MAC_RX 102 +#define SCLK_MAC_TX 103 + +#define DCLK_VOP0 190 +#define DCLK_VOP1 191 + +/* aclk gates */ +#define ACLK_GPU 192 +#define ACLK_DMAC1 193 +#define ACLK_DMAC2 194 +#define ACLK_MMU 195 +#define ACLK_GMAC 196 +#define ACLK_VOP0 197 +#define ACLK_VOP1 198 +#define ACLK_CRYPTO 199 +#define ACLK_RGA 200 + +/* pclk gates */ +#define PCLK_GPIO0 320 +#define PCLK_GPIO1 321 +#define PCLK_GPIO2 322 +#define PCLK_GPIO3 323 +#define PCLK_GPIO4 324 +#define PCLK_GPIO5 325 +#define PCLK_GPIO6 326 +#define PCLK_GPIO7 327 +#define PCLK_GPIO8 328 +#define PCLK_GRF 329 +#define PCLK_SGRF 330 +#define PCLK_PMU 331 +#define PCLK_I2C0 332 +#define PCLK_I2C1 333 +#define PCLK_I2C2 334 +#define PCLK_I2C3 335 +#define PCLK_I2C4 336 +#define PCLK_I2C5 337 +#define PCLK_SPI0 338 +#define PCLK_SPI1 339 +#define PCLK_SPI2 340 +#define PCLK_UART0 341 +#define PCLK_UART1 342 +#define PCLK_UART2 343 +#define PCLK_UART3 344 +#define PCLK_UART4 345 +#define PCLK_TSADC 346 +#define PCLK_SARADC 347 +#define PCLK_SIM 348 +#define PCLK_GMAC 349 +#define PCLK_PWM 350 +#define PCLK_RKPWM 351 +#define PCLK_PS2C 352 +#define PCLK_TIMER 353 +#define PCLK_TZPC 354 + +/* hclk gates */ +#define HCLK_GPS 448 +#define HCLK_OTG0 449 +#define HCLK_USBHOST0 450 +#define HCLK_USBHOST1 451 +#define HCLK_HSIC 452 +#define HCLK_NANDC0 453 +#define HCLK_NANDC1 454 +#define HCLK_TSP 455 +#define HCLK_SDMMC 456 +#define HCLK_SDIO0 457 +#define HCLK_SDIO1 458 +#define HCLK_EMMC 459 +#define HCLK_HSADC 460 +#define HCLK_CRYPTO 461 +#define HCLK_I2S0 462 +#define HCLK_SPDIF 463 +#define HCLK_SPDIF8CH 464 +#define HCLK_VOP0 465 +#define HCLK_VOP1 466 +#define HCLK_ROM 467 +#define HCLK_IEP 468 +#define HCLK_ISP 469 +#define HCLK_RGA 470 + +#define CLK_NR_CLKS (HCLK_RGA + 1) + +/* soft-reset indices */ +#define SRST_CORE0 0 +#define SRST_CORE1 1 +#define SRST_CORE2 2 +#define SRST_CORE3 3 +#define SRST_CORE0_PO 4 +#define SRST_CORE1_PO 5 +#define SRST_CORE2_PO 6 +#define SRST_CORE3_PO 7 +#define SRST_PDCORE_STRSYS 8 +#define SRST_PDBUS_STRSYS 9 +#define SRST_L2C 10 +#define SRST_TOPDBG 11 +#define SRST_CORE0_DBG 12 +#define SRST_CORE1_DBG 13 +#define SRST_CORE2_DBG 14 +#define SRST_CORE3_DBG 15 + +#define SRST_PDBUG_AHB_ARBITOR 16 +#define SRST_EFUSE256 17 +#define SRST_DMAC1 18 +#define SRST_INTMEM 19 +#define SRST_ROM 20 +#define SRST_SPDIF8CH 21 +#define SRST_TIMER 22 +#define SRST_I2S0 23 +#define SRST_SPDIF 24 +#define SRST_TIMER0 25 +#define SRST_TIMER1 26 +#define SRST_TIMER2 27 +#define SRST_TIMER3 28 +#define SRST_TIMER4 29 +#define SRST_TIMER5 30 +#define SRST_EFUSE 31 + +#define SRST_GPIO0 32 +#define SRST_GPIO1 33 +#define SRST_GPIO2 34 +#define SRST_GPIO3 35 +#define SRST_GPIO4 36 +#define SRST_GPIO5 37 +#define SRST_GPIO6 38 +#define SRST_GPIO7 39 +#define SRST_GPIO8 40 +#define SRST_I2C0 42 +#define SRST_I2C1 43 +#define SRST_I2C2 44 +#define SRST_I2C3 45 +#define SRST_I2C4 46 +#define SRST_I2C5 47 + +#define SRST_DWPWM 48 +#define SRST_MMC_PERI 49 +#define SRST_PERIPH_MMU 50 +#define SRST_DAP 51 +#define SRST_DAP_SYS 52 +#define SRST_TPIU 53 +#define SRST_PMU_APB 54 +#define SRST_GRF 55 +#define SRST_PMU 56 +#define SRST_PERIPH_AXI 57 +#define SRST_PERIPH_AHB 58 +#define SRST_PERIPH_APB 59 +#define SRST_PERIPH_NIU 60 +#define SRST_PDPERI_AHB_ARBI 61 +#define SRST_EMEM 62 +#define SRST_USB_PERI 63 + +#define SRST_DMAC2 64 +#define SRST_MAC 66 +#define SRST_GPS 67 +#define SRST_RKPWM 69 +#define SRST_CCP 71 +#define SRST_USBHOST0 72 +#define SRST_HSIC 73 +#define SRST_HSIC_AUX 74 +#define SRST_HSIC_PHY 75 +#define SRST_HSADC 76 +#define SRST_NANDC0 77 +#define SRST_NANDC1 78 + +#define SRST_TZPC 80 +#define SRST_SPI0 83 +#define SRST_SPI1 84 +#define SRST_SPI2 85 +#define SRST_SARADC 87 +#define SRST_PDALIVE_NIU 88 +#define SRST_PDPMU_INTMEM 89 +#define SRST_PDPMU_NIU 90 +#define SRST_SGRF 91 + +#define SRST_VIO_ARBI 96 +#define SRST_RGA_NIU 97 +#define SRST_VIO0_NIU_AXI 98 +#define SRST_VIO_NIU_AHB 99 +#define SRST_LCDC0_AXI 100 +#define SRST_LCDC0_AHB 101 +#define SRST_LCDC0_DCLK 102 +#define SRST_VIO1_NIU_AXI 103 +#define SRST_VIP 104 +#define SRST_RGA_CORE 105 +#define SRST_IEP_AXI 106 +#define SRST_IEP_AHB 107 +#define SRST_RGA_AXI 108 +#define SRST_RGA_AHB 109 +#define SRST_ISP 110 +#define SRST_EDP 111 + +#define SRST_VCODEC_AXI 112 +#define SRST_VCODEC_AHB 113 +#define SRST_VIO_H2P 114 +#define SRST_MIPIDSI0 115 +#define SRST_MIPIDSI1 116 +#define SRST_MIPICSI 117 +#define SRST_LVDS_PHY 118 +#define SRST_LVDS_CON 119 +#define SRST_GPU 120 +#define SRST_HDMI 121 +#define SRST_CORE_PVTM 124 +#define SRST_GPU_PVTM 125 + +#define SRST_MMC0 128 +#define SRST_SDIO0 129 +#define SRST_SDIO1 130 +#define SRST_EMMC 131 +#define SRST_USBOTG_AHB 132 +#define SRST_USBOTG_PHY 133 +#define SRST_USBOTG_CON 134 +#define SRST_USBHOST0_AHB 135 +#define SRST_USBHOST0_PHY 136 +#define SRST_USBHOST0_CON 137 +#define SRST_USBHOST1_AHB 138 +#define SRST_USBHOST1_PHY 139 +#define SRST_USBHOST1_CON 140 +#define SRST_USB_ADP 141 +#define SRST_ACC_EFUSE 142 -- cgit v0.10.2 From 1fe69496cf463b654d2d6e1a9a10fb8d99f10831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Thu, 3 Jul 2014 02:02:58 +0200 Subject: ARM: rockchip: Select ARCH_HAS_RESET_CONTROLLER All known Rockchip SoCs have a reset controller in their CRUs, so it's helpful to have the reset controller framework selected by default, only be deselected by the user in special cases. Signed-off-by: Heiko Stuebner Acked-By: Max Schwarz Tested-By: Max Schwarz Signed-off-by: Mike Turquette diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig index 1caee6d..e4564c2 100644 --- a/arch/arm/mach-rockchip/Kconfig +++ b/arch/arm/mach-rockchip/Kconfig @@ -2,6 +2,7 @@ config ARCH_ROCKCHIP bool "Rockchip RK2928 and RK3xxx SOCs" if ARCH_MULTI_V7 select PINCTRL select PINCTRL_ROCKCHIP + select ARCH_HAS_RESET_CONTROLLER select ARCH_REQUIRE_GPIOLIB select ARM_GIC select CACHE_L2X0 -- cgit v0.10.2