diff options
Diffstat (limited to 'target/linux/sunxi/patches-3.13/118-clk-sunxi-add-pll5-pll6.patch')
-rw-r--r-- | target/linux/sunxi/patches-3.13/118-clk-sunxi-add-pll5-pll6.patch | 303 |
1 files changed, 0 insertions, 303 deletions
diff --git a/target/linux/sunxi/patches-3.13/118-clk-sunxi-add-pll5-pll6.patch b/target/linux/sunxi/patches-3.13/118-clk-sunxi-add-pll5-pll6.patch deleted file mode 100644 index 6cff37f..0000000 --- a/target/linux/sunxi/patches-3.13/118-clk-sunxi-add-pll5-pll6.patch +++ /dev/null @@ -1,303 +0,0 @@ -From 655893a197a5134a371a5c6b579f1bbce03ab413 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> -Date: Mon, 23 Dec 2013 00:32:37 -0300 -Subject: [PATCH] clk: sunxi: add PLL5 and PLL6 support -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This commit implements PLL5 and PLL6 support on the sunxi clock driver. -These PLLs use a similar factor clock, but differ on their outputs. - -Signed-off-by: Emilio López <emilio@elopez.com.ar> -Acked-by: Mike Turquette <mturquette@linaro.org> ---- - Documentation/devicetree/bindings/clock/sunxi.txt | 2 + - drivers/clk/sunxi/clk-sunxi.c | 230 ++++++++++++++++++++++ - 2 files changed, 232 insertions(+) - ---- a/Documentation/devicetree/bindings/clock/sunxi.txt -+++ b/Documentation/devicetree/bindings/clock/sunxi.txt -@@ -9,6 +9,8 @@ Required properties: - "allwinner,sun4i-osc-clk" - for a gatable oscillator - "allwinner,sun4i-pll1-clk" - for the main PLL clock and PLL4 - "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31 -+ "allwinner,sun4i-pll5-clk" - for the PLL5 clock -+ "allwinner,sun4i-pll6-clk" - for the PLL6 clock - "allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock - "allwinner,sun4i-axi-clk" - for the AXI clock - "allwinner,sun4i-axi-gates-clk" - for the AXI gates ---- a/drivers/clk/sunxi/clk-sunxi.c -+++ b/drivers/clk/sunxi/clk-sunxi.c -@@ -218,6 +218,40 @@ static void sun6i_a31_get_pll1_factors(u - } - - /** -+ * sun4i_get_pll5_factors() - calculates n, k factors for PLL5 -+ * PLL5 rate is calculated as follows -+ * rate = parent_rate * n * (k + 1) -+ * parent_rate is always 24Mhz -+ */ -+ -+static void sun4i_get_pll5_factors(u32 *freq, u32 parent_rate, -+ u8 *n, u8 *k, u8 *m, u8 *p) -+{ -+ u8 div; -+ -+ /* Normalize value to a parent_rate multiple (24M) */ -+ div = *freq / parent_rate; -+ *freq = parent_rate * div; -+ -+ /* we were called to round the frequency, we can now return */ -+ if (n == NULL) -+ return; -+ -+ if (div < 31) -+ *k = 0; -+ else if (div / 2 < 31) -+ *k = 1; -+ else if (div / 3 < 31) -+ *k = 2; -+ else -+ *k = 3; -+ -+ *n = DIV_ROUND_UP(div, (*k+1)); -+} -+ -+ -+ -+/** - * sun4i_get_apb1_factors() - calculates m, p factors for APB1 - * APB1 rate is calculated as follows - * rate = (parent_rate >> p) / (m + 1); -@@ -293,6 +327,13 @@ static struct clk_factors_config sun6i_a - .mwidth = 2, - }; - -+static struct clk_factors_config sun4i_pll5_config = { -+ .nshift = 8, -+ .nwidth = 5, -+ .kshift = 4, -+ .kwidth = 2, -+}; -+ - static struct clk_factors_config sun4i_apb1_config = { - .mshift = 0, - .mwidth = 5, -@@ -312,6 +353,12 @@ static const struct factors_data sun6i_a - .getter = sun6i_a31_get_pll1_factors, - }; - -+static const struct factors_data sun4i_pll5_data __initconst = { -+ .enable = 31, -+ .table = &sun4i_pll5_config, -+ .getter = sun4i_get_pll5_factors, -+}; -+ - static const struct factors_data sun4i_apb1_data __initconst = { - .table = &sun4i_apb1_config, - .getter = sun4i_get_apb1_factors, -@@ -627,6 +674,179 @@ static void __init sunxi_gates_clk_setup - of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); - } - -+ -+ -+/** -+ * sunxi_divs_clk_setup() helper data -+ */ -+ -+#define SUNXI_DIVS_MAX_QTY 2 -+#define SUNXI_DIVISOR_WIDTH 2 -+ -+struct divs_data { -+ const struct factors_data *factors; /* data for the factor clock */ -+ struct { -+ u8 fixed; /* is it a fixed divisor? if not... */ -+ struct clk_div_table *table; /* is it a table based divisor? */ -+ u8 shift; /* otherwise it's a normal divisor with this shift */ -+ u8 pow; /* is it power-of-two based? */ -+ u8 gate; /* is it independently gateable? */ -+ } div[SUNXI_DIVS_MAX_QTY]; -+}; -+ -+static struct clk_div_table pll6_sata_tbl[] = { -+ { .val = 0, .div = 6, }, -+ { .val = 1, .div = 12, }, -+ { .val = 2, .div = 18, }, -+ { .val = 3, .div = 24, }, -+ { } /* sentinel */ -+}; -+ -+static const struct divs_data pll5_divs_data __initconst = { -+ .factors = &sun4i_pll5_data, -+ .div = { -+ { .shift = 0, .pow = 0, }, /* M, DDR */ -+ { .shift = 16, .pow = 1, }, /* P, other */ -+ } -+}; -+ -+static const struct divs_data pll6_divs_data __initconst = { -+ .factors = &sun4i_pll5_data, -+ .div = { -+ { .shift = 0, .table = pll6_sata_tbl, .gate = 14 }, /* M, SATA */ -+ { .fixed = 2 }, /* P, other */ -+ } -+}; -+ -+/** -+ * sunxi_divs_clk_setup() - Setup function for leaf divisors on clocks -+ * -+ * These clocks look something like this -+ * ________________________ -+ * | ___divisor 1---|----> to consumer -+ * parent >--| pll___/___divisor 2---|----> to consumer -+ * | \_______________|____> to consumer -+ * |________________________| -+ */ -+ -+static void __init sunxi_divs_clk_setup(struct device_node *node, -+ struct divs_data *data) -+{ -+ struct clk_onecell_data *clk_data; -+ const char *parent = node->name; -+ const char *clk_name; -+ struct clk **clks, *pclk; -+ struct clk_hw *gate_hw, *rate_hw; -+ const struct clk_ops *rate_ops; -+ struct clk_gate *gate = NULL; -+ struct clk_fixed_factor *fix_factor; -+ struct clk_divider *divider; -+ void *reg; -+ int i = 0; -+ int flags, clkflags; -+ -+ /* Set up factor clock that we will be dividing */ -+ pclk = sunxi_factors_clk_setup(node, data->factors); -+ -+ reg = of_iomap(node, 0); -+ -+ clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); -+ if (!clk_data) -+ return; -+ -+ clks = kzalloc(SUNXI_DIVS_MAX_QTY * sizeof(struct clk *), GFP_KERNEL); -+ if (!clks) -+ goto free_clkdata; -+ -+ clk_data->clks = clks; -+ -+ /* It's not a good idea to have automatic reparenting changing -+ * our RAM clock! */ -+ clkflags = !strcmp("pll5", parent) ? 0 : CLK_SET_RATE_PARENT; -+ -+ for (i = 0; i < SUNXI_DIVS_MAX_QTY; i++) { -+ if (of_property_read_string_index(node, "clock-output-names", -+ i, &clk_name) != 0) -+ break; -+ -+ gate_hw = NULL; -+ rate_hw = NULL; -+ rate_ops = NULL; -+ -+ /* If this leaf clock can be gated, create a gate */ -+ if (data->div[i].gate) { -+ gate = kzalloc(sizeof(*gate), GFP_KERNEL); -+ if (!gate) -+ goto free_clks; -+ -+ gate->reg = reg; -+ gate->bit_idx = data->div[i].gate; -+ gate->lock = &clk_lock; -+ -+ gate_hw = &gate->hw; -+ } -+ -+ /* Leaves can be fixed or configurable divisors */ -+ if (data->div[i].fixed) { -+ fix_factor = kzalloc(sizeof(*fix_factor), GFP_KERNEL); -+ if (!fix_factor) -+ goto free_gate; -+ -+ fix_factor->mult = 1; -+ fix_factor->div = data->div[i].fixed; -+ -+ rate_hw = &fix_factor->hw; -+ rate_ops = &clk_fixed_factor_ops; -+ } else { -+ divider = kzalloc(sizeof(*divider), GFP_KERNEL); -+ if (!divider) -+ goto free_gate; -+ -+ flags = data->div[i].pow ? CLK_DIVIDER_POWER_OF_TWO : 0; -+ -+ divider->reg = reg; -+ divider->shift = data->div[i].shift; -+ divider->width = SUNXI_DIVISOR_WIDTH; -+ divider->flags = flags; -+ divider->lock = &clk_lock; -+ divider->table = data->div[i].table; -+ -+ rate_hw = ÷r->hw; -+ rate_ops = &clk_divider_ops; -+ } -+ -+ /* Wrap the (potential) gate and the divisor on a composite -+ * clock to unify them */ -+ clks[i] = clk_register_composite(NULL, clk_name, &parent, 1, -+ NULL, NULL, -+ rate_hw, rate_ops, -+ gate_hw, &clk_gate_ops, -+ clkflags); -+ -+ WARN_ON(IS_ERR(clk_data->clks[i])); -+ clk_register_clkdev(clks[i], clk_name, NULL); -+ } -+ -+ /* The last clock available on the getter is the parent */ -+ clks[i++] = pclk; -+ -+ /* Adjust to the real max */ -+ clk_data->clk_num = i; -+ -+ of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); -+ -+ return; -+ -+free_gate: -+ kfree(gate); -+free_clks: -+ kfree(clks); -+free_clkdata: -+ kfree(clk_data); -+} -+ -+ -+ - /* Matches for factors clocks */ - static const struct of_device_id clk_factors_match[] __initconst = { - {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,}, -@@ -644,6 +864,13 @@ static const struct of_device_id clk_div - {} - }; - -+/* Matches for divided outputs */ -+static const struct of_device_id clk_divs_match[] __initconst = { -+ {.compatible = "allwinner,sun4i-pll5-clk", .data = &pll5_divs_data,}, -+ {.compatible = "allwinner,sun4i-pll6-clk", .data = &pll6_divs_data,}, -+ {} -+}; -+ - /* Matches for mux clocks */ - static const struct of_device_id clk_mux_match[] __initconst = { - {.compatible = "allwinner,sun4i-cpu-clk", .data = &sun4i_cpu_mux_data,}, -@@ -721,6 +948,9 @@ static void __init sunxi_init_clocks(str - /* Register divider clocks */ - of_sunxi_table_clock_setup(clk_div_match, sunxi_divider_clk_setup); - -+ /* Register divided output clocks */ -+ of_sunxi_table_clock_setup(clk_divs_match, sunxi_divs_clk_setup); -+ - /* Register mux clocks */ - of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup); - |