diff options
Diffstat (limited to 'target/linux/sunxi/patches-3.13')
91 files changed, 8503 insertions, 0 deletions
diff --git a/target/linux/sunxi/patches-3.13/100-clk-composite-determine-rate.patch b/target/linux/sunxi/patches-3.13/100-clk-composite-determine-rate.patch new file mode 100644 index 0000000000..6abbcbe5ff --- /dev/null +++ b/target/linux/sunxi/patches-3.13/100-clk-composite-determine-rate.patch @@ -0,0 +1,75 @@ +From a968e9dc5983d258a4aa7e496d58c92e9e4cf670 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +Date: Sat, 14 Sep 2013 21:37:59 -0300 +Subject: [PATCH] clk: composite: .determine_rate support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit adds .determine_rate support to the composite clock. It will +use the .determine_rate callback from the rate component if available, +and fall back on the mux component otherwise. This allows composite +clocks to enjoy the benefits of automatic clock reparenting. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + drivers/clk/clk-composite.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c +index a33f46f..753d0b7 100644 +--- a/drivers/clk/clk-composite.c ++++ b/drivers/clk/clk-composite.c +@@ -55,6 +55,30 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, + return rate_ops->recalc_rate(rate_hw, parent_rate); + } + ++static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *best_parent_rate, ++ struct clk **best_parent_p) ++{ ++ struct clk_composite *composite = to_clk_composite(hw); ++ const struct clk_ops *rate_ops = composite->rate_ops; ++ 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; ++ ++ 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 (mux_hw && mux_ops && mux_ops->determine_rate) { ++ mux_hw->clk = hw->clk; ++ return mux_ops->determine_rate(rate_hw, rate, best_parent_rate, ++ best_parent_p); ++ } else { ++ pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n"); ++ return 0; ++ } ++} ++ + static long clk_composite_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) + { +@@ -147,6 +171,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name, + 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->determine_rate) ++ clk_composite_ops->determine_rate = clk_composite_determine_rate; + } + + if (rate_hw && rate_ops) { +@@ -170,6 +196,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) ++ clk_composite_ops->determine_rate = clk_composite_determine_rate; + } + + if (gate_hw && gate_ops) { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/101-fix-off-by-one-masks.patch b/target/linux/sunxi/patches-3.13/101-fix-off-by-one-masks.patch new file mode 100644 index 0000000000..4f04d54151 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/101-fix-off-by-one-masks.patch @@ -0,0 +1,34 @@ +From b3cb099f8b0cbe56fcfbb4fb9c7cce48afff41f0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +Date: Fri, 20 Sep 2013 22:03:10 -0300 +Subject: [PATCH] clk: sunxi: factors: fix off-by-one masks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The previous code would generate one bit too long masks, and was +needlessly complicated. This patch replaces it by simpler code that can +generate the masks correctly. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + drivers/clk/sunxi/clk-factors.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c +index 88523f9..5687ac9 100644 +--- a/drivers/clk/sunxi/clk-factors.c ++++ b/drivers/clk/sunxi/clk-factors.c +@@ -40,7 +40,7 @@ struct clk_factors { + + #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) + +-#define SETMASK(len, pos) (((-1U) >> (31-len)) << (pos)) ++#define SETMASK(len, pos) (((1U << (len)) - 1) << (pos)) + #define CLRMASK(len, pos) (~(SETMASK(len, pos))) + #define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit)) + +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/102-clk-factors-clear-vars.patch b/target/linux/sunxi/patches-3.13/102-clk-factors-clear-vars.patch new file mode 100644 index 0000000000..6254e1be56 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/102-clk-factors-clear-vars.patch @@ -0,0 +1,32 @@ +From 789bea92aba0256a7f5309992327df8729333750 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +Date: Fri, 20 Sep 2013 22:03:11 -0300 +Subject: [PATCH] clk: sunxi: factors: clear variables before using them +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Random bits may get into our factors if we don't clear n, k, m and p. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + drivers/clk/sunxi/clk-factors.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c +index 5687ac9..f05207a 100644 +--- a/drivers/clk/sunxi/clk-factors.c ++++ b/drivers/clk/sunxi/clk-factors.c +@@ -88,7 +88,7 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, + static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) + { +- u8 n, k, m, p; ++ u8 n = 0, k = 0, m = 0, p = 0; + u32 reg; + struct clk_factors *factors = to_clk_factors(hw); + struct clk_factors_config *config = factors->config; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/103-sunxi-clk-core-clock-protect.patch b/target/linux/sunxi/patches-3.13/103-sunxi-clk-core-clock-protect.patch new file mode 100644 index 0000000000..a2a430d9c1 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/103-sunxi-clk-core-clock-protect.patch @@ -0,0 +1,71 @@ +From 7df19a0adca7806e081479eecb07365652c26ef5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +Date: Fri, 20 Sep 2013 22:03:12 -0300 +Subject: [PATCH] clk: sunxi: protect core clocks from accidental shutdown +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some important clocks may get disabled as a side effect of another clock +being disabled, because they have no consumers. This patch implements a +mechanism so those clocks can be claimed by the driver and therefore +remain enabled at all times. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> + +Conflicts: + drivers/clk/sunxi/clk-sunxi.c +--- + drivers/clk/sunxi/clk-sunxi.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 9bbd035..8fc1375 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -616,6 +616,31 @@ static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_mat + } + } + ++/** ++ * System clock protection ++ * ++ * By enabling these critical clocks, we prevent their accidental gating ++ * by the framework ++ */ ++static void __init sunxi_clock_protect(void) ++{ ++ struct clk *clk; ++ ++ /* memory bus clock - sun5i+ */ ++ clk = clk_get(NULL, "mbus"); ++ if (!IS_ERR(clk)) { ++ clk_prepare_enable(clk); ++ clk_put(clk); ++ } ++ ++ /* DDR clock - sun4i+ */ ++ clk = clk_get(NULL, "pll5_ddr"); ++ if (!IS_ERR(clk)) { ++ clk_prepare_enable(clk); ++ clk_put(clk); ++ } ++} ++ + static void __init sunxi_init_clocks(struct device_node *np) + { + /* Register factor clocks */ +@@ -629,6 +654,9 @@ static void __init sunxi_init_clocks(struct device_node *np) + + /* Register gate clocks */ + of_sunxi_table_clock_setup(clk_gates_match, sunxi_gates_clk_setup); ++ ++ /* Enable core system clocks */ ++ sunxi_clock_protect(); + } + CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sunxi_init_clocks); + CLK_OF_DECLARE(sun5i_a10s_clk_init, "allwinner,sun5i-a10s", sunxi_init_clocks); +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/104-clk-sunxi-fix-memory-leak.patch b/target/linux/sunxi/patches-3.13/104-clk-sunxi-fix-memory-leak.patch new file mode 100644 index 0000000000..99b0db892d --- /dev/null +++ b/target/linux/sunxi/patches-3.13/104-clk-sunxi-fix-memory-leak.patch @@ -0,0 +1,68 @@ +From 9dc8189536f4c59bb7ad8c736021cefc1488bf74 Mon Sep 17 00:00:00 2001 +From: "Victor N. Ramos Mello" <victornrm@gmail.com> +Date: Fri, 18 Oct 2013 20:27:51 -0300 +Subject: [PATCH] drivers: clk: sunxi: Fix memory leakage in clk-sunxi.c + +Fix a possible memory leak in sun4i_osc_clk_setup(). +Moved clock-frequency check to save superfluous allocation. + +Signed-off-by: Victor N. Ramos Mello <victornrm@gmail.com> +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + drivers/clk/sunxi/clk-sunxi.c | 28 +++++++++++++++++----------- + 1 file changed, 17 insertions(+), 11 deletions(-) + +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 8fc1375..492ef0e 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -37,18 +37,16 @@ static void __init sun4i_osc_clk_setup(struct device_node *node) + const char *clk_name = node->name; + u32 rate; + ++ if (of_property_read_u32(node, "clock-frequency", &rate)) ++ return; ++ + /* allocate fixed-rate and gate clock structs */ + fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL); + if (!fixed) + return; + gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); +- if (!gate) { +- kfree(fixed); +- return; +- } +- +- if (of_property_read_u32(node, "clock-frequency", &rate)) +- return; ++ if (!gate) ++ goto err_free_fixed; + + /* set up gate and fixed rate properties */ + gate->reg = of_iomap(node, 0); +@@ -63,10 +61,18 @@ static void __init sun4i_osc_clk_setup(struct device_node *node) + &gate->hw, &clk_gate_ops, + CLK_IS_ROOT); + +- if (!IS_ERR(clk)) { +- of_clk_add_provider(node, of_clk_src_simple_get, clk); +- clk_register_clkdev(clk, clk_name, NULL); +- } ++ if (IS_ERR(clk)) ++ goto err_free_gate; ++ ++ of_clk_add_provider(node, of_clk_src_simple_get, clk); ++ clk_register_clkdev(clk, clk_name, NULL); ++ ++ return; ++ ++err_free_gate: ++ kfree(gate); ++err_free_fixed: ++ kfree(fixed); + } + CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-osc-clk", sun4i_osc_clk_setup); + +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/105-reset-add-reset-ctrler.patch b/target/linux/sunxi/patches-3.13/105-reset-add-reset-ctrler.patch new file mode 100644 index 0000000000..38c8f75878 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/105-reset-add-reset-ctrler.patch @@ -0,0 +1,214 @@ +From 8015cea648c452bbfe0fc820dcb1185beaeb8736 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Tue, 24 Sep 2013 11:07:43 +0300 +Subject: [PATCH] reset: Add Allwinner SoCs Reset Controller Driver + +The Allwinner A31 and most of the other Allwinner SoCs have an IP +maintaining a few other IPs in the SoC in reset by default. Among these +IPs are the A31's High Speed Timers, hence why we can't use the regular +driver construct in every cases, and need to call the registering +function directly during machine initialisation. + +Apart from this, the implementation is fairly straightforward, and could +easily be moved to a generic MMIO-based reset controller driver if the +need ever arise. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +Acked-by: Philipp Zabel <p.zabel@pengutronix.de> +--- + drivers/reset/Makefile | 1 + + drivers/reset/reset-sunxi.c | 175 ++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 176 insertions(+) + create mode 100644 drivers/reset/reset-sunxi.c + +diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile +index 1e2d83f..cc29832 100644 +--- a/drivers/reset/Makefile ++++ b/drivers/reset/Makefile +@@ -1 +1,2 @@ + obj-$(CONFIG_RESET_CONTROLLER) += core.o ++obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o +diff --git a/drivers/reset/reset-sunxi.c b/drivers/reset/reset-sunxi.c +new file mode 100644 +index 0000000..695bd34 +--- /dev/null ++++ b/drivers/reset/reset-sunxi.c +@@ -0,0 +1,175 @@ ++/* ++ * Allwinner SoCs Reset Controller driver ++ * ++ * Copyright 2013 Maxime Ripard ++ * ++ * Maxime Ripard <maxime.ripard@free-electrons.com> ++ * ++ * 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. ++ */ ++ ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/reset-controller.h> ++#include <linux/slab.h> ++#include <linux/spinlock.h> ++#include <linux/types.h> ++ ++struct sunxi_reset_data { ++ spinlock_t lock; ++ void __iomem *membase; ++ struct reset_controller_dev rcdev; ++}; ++ ++static int sunxi_reset_assert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ struct sunxi_reset_data *data = container_of(rcdev, ++ struct sunxi_reset_data, ++ rcdev); ++ int bank = id / BITS_PER_LONG; ++ int offset = id % BITS_PER_LONG; ++ unsigned long flags; ++ u32 reg; ++ ++ spin_lock_irqsave(&data->lock, flags); ++ ++ reg = readl(data->membase + (bank * 4)); ++ writel(reg & ~BIT(offset), data->membase + (bank * 4)); ++ ++ spin_unlock_irqrestore(&data->lock, flags); ++ ++ return 0; ++} ++ ++static int sunxi_reset_deassert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ struct sunxi_reset_data *data = container_of(rcdev, ++ struct sunxi_reset_data, ++ rcdev); ++ int bank = id / BITS_PER_LONG; ++ int offset = id % BITS_PER_LONG; ++ unsigned long flags; ++ u32 reg; ++ ++ spin_lock_irqsave(&data->lock, flags); ++ ++ reg = readl(data->membase + (bank * 4)); ++ writel(reg | BIT(offset), data->membase + (bank * 4)); ++ ++ spin_unlock_irqrestore(&data->lock, flags); ++ ++ return 0; ++} ++ ++static struct reset_control_ops sunxi_reset_ops = { ++ .assert = sunxi_reset_assert, ++ .deassert = sunxi_reset_deassert, ++}; ++ ++static int sunxi_reset_init(struct device_node *np) ++{ ++ struct sunxi_reset_data *data; ++ struct resource res; ++ resource_size_t size; ++ int ret; ++ ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ ret = of_address_to_resource(np, 0, &res); ++ if (ret) ++ goto err_alloc; ++ ++ size = resource_size(&res); ++ if (!request_mem_region(res.start, size, np->name)) { ++ ret = -EBUSY; ++ goto err_alloc; ++ } ++ ++ data->membase = ioremap(res.start, size); ++ if (!data->membase) { ++ ret = -ENOMEM; ++ goto err_alloc; ++ } ++ ++ data->rcdev.owner = THIS_MODULE; ++ data->rcdev.nr_resets = size * 32; ++ data->rcdev.ops = &sunxi_reset_ops; ++ data->rcdev.of_node = np; ++ reset_controller_register(&data->rcdev); ++ ++ return 0; ++ ++err_alloc: ++ kfree(data); ++ return ret; ++}; ++ ++/* ++ * These are the reset controller we need to initialize early on in ++ * our system, before we can even think of using a regular device ++ * driver for it. ++ */ ++static const struct of_device_id sunxi_early_reset_dt_ids[] __initdata = { ++ { .compatible = "allwinner,sun6i-a31-ahb1-reset", }, ++ { /* sentinel */ }, ++}; ++ ++void __init sun6i_reset_init(void) ++{ ++ struct device_node *np; ++ ++ for_each_matching_node(np, sunxi_early_reset_dt_ids) ++ sunxi_reset_init(np); ++} ++ ++/* ++ * And these are the controllers we can register through the regular ++ * device model. ++ */ ++static const struct of_device_id sunxi_reset_dt_ids[] = { ++ { .compatible = "allwinner,sun6i-a31-clock-reset", }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, sunxi_reset_dt_ids); ++ ++static int sunxi_reset_probe(struct platform_device *pdev) ++{ ++ return sunxi_reset_init(pdev->dev.of_node); ++} ++ ++static int sunxi_reset_remove(struct platform_device *pdev) ++{ ++ struct sunxi_reset_data *data = platform_get_drvdata(pdev); ++ ++ reset_controller_unregister(&data->rcdev); ++ iounmap(data->membase); ++ kfree(data); ++ ++ return 0; ++} ++ ++static struct platform_driver sunxi_reset_driver = { ++ .probe = sunxi_reset_probe, ++ .remove = sunxi_reset_remove, ++ .driver = { ++ .name = "sunxi-reset", ++ .owner = THIS_MODULE, ++ .of_match_table = sunxi_reset_dt_ids, ++ }, ++}; ++module_platform_driver(sunxi_reset_driver); ++ ++MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); ++MODULE_DESCRIPTION("Allwinner SoCs Reset Controller Driver"); ++MODULE_LICENSE("GPL"); +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/106-add-Kconfig-for-reset.patch b/target/linux/sunxi/patches-3.13/106-add-Kconfig-for-reset.patch new file mode 100644 index 0000000000..ae2a50499a --- /dev/null +++ b/target/linux/sunxi/patches-3.13/106-add-Kconfig-for-reset.patch @@ -0,0 +1,28 @@ +From 73f948fb57f489ed8252fa8480575c91f027200d Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Tue, 24 Sep 2013 11:09:55 +0300 +Subject: [PATCH] ARM: sunxi: Select ARCH_HAS_RESET_CONTROLLER + +The A31 has a reset controller, and we have to select this option to +have access to the reset controller framework. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +Acked-by: Philipp Zabel <p.zabel@pengutronix.de> +--- + arch/arm/mach-sunxi/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig +index c9e72c8..e3457b9 100644 +--- a/arch/arm/mach-sunxi/Kconfig ++++ b/arch/arm/mach-sunxi/Kconfig +@@ -1,5 +1,6 @@ + config ARCH_SUNXI + bool "Allwinner A1X SOCs" if ARCH_MULTI_V7 ++ select ARCH_HAS_RESET_CONTROLLER + select ARCH_REQUIRE_GPIOLIB + select ARM_GIC + select CLKSRC_MMIO +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/107-sunxi-register-a31-reset.patch b/target/linux/sunxi/patches-3.13/107-sunxi-register-a31-reset.patch new file mode 100644 index 0000000000..b0e98d7fbb --- /dev/null +++ b/target/linux/sunxi/patches-3.13/107-sunxi-register-a31-reset.patch @@ -0,0 +1,50 @@ +From dae0e37c2df466f5eb6459d05f392e86b4236666 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Sat, 5 Oct 2013 14:53:48 +0200 +Subject: [PATCH] ARM: sunxi: Register the A31 reset IP in init_time + +The A31 has a reset IP that maintains a few other IPs in reset by +default. Among these IPs are the UARTs, and most notably the timers. We +thus need to register the reset driver before initializing the timers so +that the reset timer can use the reset framework. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +Acked-by: Philipp Zabel <p.zabel@pengutronix.de> +--- + arch/arm/mach-sunxi/sunxi.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c +index 61d3a38..594ac48 100644 +--- a/arch/arm/mach-sunxi/sunxi.c ++++ b/arch/arm/mach-sunxi/sunxi.c +@@ -10,6 +10,8 @@ + * warranty of any kind, whether express or implied. + */ + ++#include <linux/clk-provider.h> ++#include <linux/clocksource.h> + #include <linux/delay.h> + #include <linux/kernel.h> + #include <linux/init.h> +@@ -132,8 +134,17 @@ static void __init sunxi_dt_init(void) + NULL, + }; + ++extern void __init sun6i_reset_init(void); ++static void __init sun6i_timer_init(void) ++{ ++ of_clk_init(NULL); ++ sun6i_reset_init(); ++ clocksource_of_init(); ++} ++ + DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family") + .init_machine = sunxi_dt_init, ++ .init_time = sun6i_timer_init, + .dt_compat = sun6i_board_dt_compat, + .restart = sun6i_restart, + MACHINE_END +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/108-sun6i-add-smp-support.patch b/target/linux/sunxi/patches-3.13/108-sun6i-add-smp-support.patch new file mode 100644 index 0000000000..e591404b95 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/108-sun6i-add-smp-support.patch @@ -0,0 +1,222 @@ +From 6f5002c91f35f6b171bc608b87b3f2b55451f32b Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Sun, 3 Nov 2013 10:30:13 +0100 +Subject: [PATCH] ARM: sun6i: Add SMP support for the Allwinner A31 + +The A31 is a quad Cortex-A7. Add the logic to use the IPs used to +control the CPU configuration and the CPU power so that we can bring up +secondary CPUs at boot. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + arch/arm/mach-sunxi/Makefile | 1 + + arch/arm/mach-sunxi/common.h | 19 +++++++ + arch/arm/mach-sunxi/headsmp.S | 9 +++ + arch/arm/mach-sunxi/platsmp.c | 124 ++++++++++++++++++++++++++++++++++++++++++ + arch/arm/mach-sunxi/sunxi.c | 3 + + 5 files changed, 156 insertions(+) + create mode 100644 arch/arm/mach-sunxi/common.h + create mode 100644 arch/arm/mach-sunxi/headsmp.S + create mode 100644 arch/arm/mach-sunxi/platsmp.c + +diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile +index 93bebfc..d939720 100644 +--- a/arch/arm/mach-sunxi/Makefile ++++ b/arch/arm/mach-sunxi/Makefile +@@ -1 +1,2 @@ + obj-$(CONFIG_ARCH_SUNXI) += sunxi.o ++obj-$(CONFIG_SMP) += platsmp.o headsmp.o +diff --git a/arch/arm/mach-sunxi/common.h b/arch/arm/mach-sunxi/common.h +new file mode 100644 +index 0000000..9e5ac47 +--- /dev/null ++++ b/arch/arm/mach-sunxi/common.h +@@ -0,0 +1,19 @@ ++/* ++ * Core functions for Allwinner SoCs ++ * ++ * Copyright (C) 2013 Maxime Ripard ++ * ++ * Maxime Ripard <maxime.ripard@free-electrons.com> ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#ifndef __ARCH_SUNXI_COMMON_H_ ++#define __ARCH_SUNXI_COMMON_H_ ++ ++void sun6i_secondary_startup(void); ++extern struct smp_operations sun6i_smp_ops; ++ ++#endif /* __ARCH_SUNXI_COMMON_H_ */ +diff --git a/arch/arm/mach-sunxi/headsmp.S b/arch/arm/mach-sunxi/headsmp.S +new file mode 100644 +index 0000000..a10d494 +--- /dev/null ++++ b/arch/arm/mach-sunxi/headsmp.S +@@ -0,0 +1,9 @@ ++#include <linux/linkage.h> ++#include <linux/init.h> ++ ++ .section ".text.head", "ax" ++ ++ENTRY(sun6i_secondary_startup) ++ msr cpsr_fsxc, #0xd3 ++ b secondary_startup ++ENDPROC(sun6i_secondary_startup) +diff --git a/arch/arm/mach-sunxi/platsmp.c b/arch/arm/mach-sunxi/platsmp.c +new file mode 100644 +index 0000000..7b141d8 +--- /dev/null ++++ b/arch/arm/mach-sunxi/platsmp.c +@@ -0,0 +1,124 @@ ++/* ++ * SMP support for Allwinner SoCs ++ * ++ * Copyright (C) 2013 Maxime Ripard ++ * ++ * Maxime Ripard <maxime.ripard@free-electrons.com> ++ * ++ * Based on code ++ * Copyright (C) 2012-2013 Allwinner Ltd. ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/memory.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/smp.h> ++ ++#include "common.h" ++ ++#define CPUCFG_CPU_PWR_CLAMP_STATUS_REG(cpu) ((cpu) * 0x40 + 0x64) ++#define CPUCFG_CPU_RST_CTRL_REG(cpu) (((cpu) + 1) * 0x40) ++#define CPUCFG_CPU_CTRL_REG(cpu) (((cpu) + 1) * 0x40 + 0x04) ++#define CPUCFG_CPU_STATUS_REG(cpu) (((cpu) + 1) * 0x40 + 0x08) ++#define CPUCFG_GEN_CTRL_REG 0x184 ++#define CPUCFG_PRIVATE0_REG 0x1a4 ++#define CPUCFG_PRIVATE1_REG 0x1a8 ++#define CPUCFG_DBG_CTL0_REG 0x1e0 ++#define CPUCFG_DBG_CTL1_REG 0x1e4 ++ ++#define PRCM_CPU_PWROFF_REG 0x100 ++#define PRCM_CPU_PWR_CLAMP_REG(cpu) (((cpu) * 4) + 0x140) ++ ++static void __iomem *cpucfg_membase; ++static void __iomem *prcm_membase; ++ ++static DEFINE_SPINLOCK(cpu_lock); ++ ++static void __init sun6i_smp_prepare_cpus(unsigned int max_cpus) ++{ ++ struct device_node *node; ++ ++ node = of_find_compatible_node(NULL, NULL, "allwinner,sun6i-a31-prcm"); ++ if (!node) { ++ pr_err("Missing A31 PRCM node in the device tree\n"); ++ return; ++ } ++ ++ prcm_membase = of_iomap(node, 0); ++ if (!prcm_membase) { ++ pr_err("Couldn't map A31 PRCM registers\n"); ++ return; ++ } ++ ++ node = of_find_compatible_node(NULL, NULL, ++ "allwinner,sun6i-a31-cpuconfig"); ++ if (!node) { ++ pr_err("Missing A31 CPU config node in the device tree\n"); ++ return; ++ } ++ ++ cpucfg_membase = of_iomap(node, 0); ++ if (!cpucfg_membase) ++ pr_err("Couldn't map A31 CPU config registers\n"); ++ ++} ++ ++static int sun6i_smp_boot_secondary(unsigned int cpu, ++ struct task_struct *idle) ++{ ++ u32 reg; ++ int i; ++ ++ if (!(prcm_membase && cpucfg_membase)) ++ return -EFAULT; ++ ++ spin_lock(&cpu_lock); ++ ++ /* Set CPU boot address */ ++ writel(virt_to_phys(sun6i_secondary_startup), ++ cpucfg_membase + CPUCFG_PRIVATE0_REG); ++ ++ /* Assert the CPU core in reset */ ++ writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu)); ++ ++ /* Assert the L1 cache in reset */ ++ reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG); ++ writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG); ++ ++ /* Disable external debug access */ ++ reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG); ++ writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG); ++ ++ /* Power up the CPU */ ++ for (i = 0; i <= 8; i++) ++ writel(0xff >> i, prcm_membase + PRCM_CPU_PWR_CLAMP_REG(cpu)); ++ mdelay(10); ++ ++ /* Clear CPU power-off gating */ ++ reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG); ++ writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG); ++ mdelay(1); ++ ++ /* Deassert the CPU core reset */ ++ writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu)); ++ ++ /* Enable back the external debug accesses */ ++ reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG); ++ writel(reg | BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG); ++ ++ spin_unlock(&cpu_lock); ++ ++ return 0; ++} ++ ++struct smp_operations sun6i_smp_ops __initdata = { ++ .smp_prepare_cpus = sun6i_smp_prepare_cpus, ++ .smp_boot_secondary = sun6i_smp_boot_secondary, ++}; +diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c +index 594ac48..aeea6ce 100644 +--- a/arch/arm/mach-sunxi/sunxi.c ++++ b/arch/arm/mach-sunxi/sunxi.c +@@ -25,6 +25,8 @@ + #include <asm/mach/map.h> + #include <asm/system_misc.h> + ++#include "common.h" ++ + #define SUN4I_WATCHDOG_CTRL_REG 0x00 + #define SUN4I_WATCHDOG_CTRL_RESTART BIT(0) + #define SUN4I_WATCHDOG_MODE_REG 0x04 +@@ -147,6 +149,7 @@ static void __init sun6i_timer_init(void) + .init_time = sun6i_timer_init, + .dt_compat = sun6i_board_dt_compat, + .restart = sun6i_restart, ++ .smp = smp_ops(sun6i_smp_ops), + MACHINE_END + + static const char * const sun7i_board_dt_compat[] = { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/109-dt-sun6i-add-reset-ctrler.patch b/target/linux/sunxi/patches-3.13/109-dt-sun6i-add-reset-ctrler.patch new file mode 100644 index 0000000000..92f2efafb4 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/109-dt-sun6i-add-reset-ctrler.patch @@ -0,0 +1,95 @@ +From f88dc0623908b574d9dcdae8815ccd0829fc6828 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Tue, 24 Sep 2013 11:10:41 +0300 +Subject: [PATCH] ARM: sun6i: Add the reset controller to the DTSI + +The A31 has a reset controller IP that maintains a few other IPs in +reset, among which we can find the UARTs, high speed timers or the I2C. +Now that we have support for them, add the reset controllers to the DTSI. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +Acked-by: Philipp Zabel <p.zabel@pengutronix.de> +--- + arch/arm/boot/dts/sun6i-a31.dtsi | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi +index 7f5878c..97966b0 100644 +--- a/arch/arm/boot/dts/sun6i-a31.dtsi ++++ b/arch/arm/boot/dts/sun6i-a31.dtsi +@@ -212,6 +212,24 @@ + }; + }; + ++ ahb1_rst: reset@01c202c0 { ++ #reset-cells = <1>; ++ compatible = "allwinner,sun6i-a31-ahb1-reset"; ++ reg = <0x01c202c0 0xc>; ++ }; ++ ++ apb1_rst: reset@01c202d0 { ++ #reset-cells = <1>; ++ compatible = "allwinner,sun6i-a31-clock-reset"; ++ reg = <0x01c202d0 0x4>; ++ }; ++ ++ apb2_rst: reset@01c202d8 { ++ #reset-cells = <1>; ++ compatible = "allwinner,sun6i-a31-clock-reset"; ++ reg = <0x01c202d8 0x4>; ++ }; ++ + timer@01c20c00 { + compatible = "allwinner,sun4i-timer"; + reg = <0x01c20c00 0xa0>; +@@ -235,6 +253,7 @@ + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&apb2_gates 16>; ++ resets = <&apb2_rst 16>; + status = "disabled"; + }; + +@@ -245,6 +264,7 @@ + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&apb2_gates 17>; ++ resets = <&apb2_rst 17>; + status = "disabled"; + }; + +@@ -255,6 +275,7 @@ + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&apb2_gates 18>; ++ resets = <&apb2_rst 18>; + status = "disabled"; + }; + +@@ -265,6 +286,7 @@ + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&apb2_gates 19>; ++ resets = <&apb2_rst 19>; + status = "disabled"; + }; + +@@ -275,6 +297,7 @@ + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&apb2_gates 20>; ++ resets = <&apb2_rst 20>; + status = "disabled"; + }; + +@@ -285,6 +308,7 @@ + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&apb2_gates 21>; ++ resets = <&apb2_rst 21>; + status = "disabled"; + }; + +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/110-sun4i-clkevent-fill-irqfield.patch b/target/linux/sunxi/patches-3.13/110-sun4i-clkevent-fill-irqfield.patch new file mode 100644 index 0000000000..12bd64a391 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/110-sun4i-clkevent-fill-irqfield.patch @@ -0,0 +1,33 @@ +From abc12cd5c39556824cc9022db6eddc64e8e8dbe9 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Wed, 23 Oct 2013 17:54:39 +0100 +Subject: [PATCH] clockevent: sun4i: Fill the irq field in the clockevent + structure + +The clock event structure irq field was not filled previously to the +interrupt we're using. + +This was resulting in the timer not being used at all when using a +configuration with SMP enabled on a system with several CPUs, and with +the cpumask set to the cpu_possible_mask. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + drivers/clocksource/sun4i_timer.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c +index a4f6119..db937e9 100644 +--- a/drivers/clocksource/sun4i_timer.c ++++ b/drivers/clocksource/sun4i_timer.c +@@ -191,6 +191,7 @@ static void __init sun4i_timer_init(struct device_node *node) + writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG); + + sun4i_clockevent.cpumask = cpumask_of(0); ++ sun4i_clockevent.irq = irq; + + clockevents_config_and_register(&sun4i_clockevent, rate, + TIMER_SYNC_TICKS, 0xffffffff); +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/111-sun4i-clksrc-change-cpu-mask.patch b/target/linux/sunxi/patches-3.13/111-sun4i-clksrc-change-cpu-mask.patch new file mode 100644 index 0000000000..8f32c7ee7e --- /dev/null +++ b/target/linux/sunxi/patches-3.13/111-sun4i-clksrc-change-cpu-mask.patch @@ -0,0 +1,30 @@ +From 64a9fa131380f9cef9328d0cf9f2d49a538e6dd2 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Wed, 9 Oct 2013 22:44:56 +0200 +Subject: [PATCH] clocksource: sun4i: change CPU mask to cpu_possible_mask + +The interrupt for the timer is a shared processor interrupt, so any CPU +found in the system can handle it. Switch to our cpumask to +cpu_possible_mask instead of cpumask_of(0). + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + drivers/clocksource/sun4i_timer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c +index db937e9..e1878eb 100644 +--- a/drivers/clocksource/sun4i_timer.c ++++ b/drivers/clocksource/sun4i_timer.c +@@ -190,7 +190,7 @@ static void __init sun4i_timer_init(struct device_node *node) + val = readl(timer_base + TIMER_IRQ_EN_REG); + writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG); + +- sun4i_clockevent.cpumask = cpumask_of(0); ++ sun4i_clockevent.cpumask = cpu_possible_mask; + sun4i_clockevent.irq = irq; + + clockevents_config_and_register(&sun4i_clockevent, rate, +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/112-sun4i-clksrc-increase-a-bit-in-clockevent.patch b/target/linux/sunxi/patches-3.13/112-sun4i-clksrc-increase-a-bit-in-clockevent.patch new file mode 100644 index 0000000000..4067e274d7 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/112-sun4i-clksrc-increase-a-bit-in-clockevent.patch @@ -0,0 +1,46 @@ +From a4eb936767bd6a63d54734b9ce48932609ce58eb Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Thu, 7 Nov 2013 12:01:48 +0100 +Subject: [PATCH] clocksource: sun4i: Increase a bit the clock event and + sources rating +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We want to keep this driver as the default provider of the clock events +and source, yet some other driver might fit in the "desired" category of +ratings. Hence, we need to increase a bit the rating so that we can have +more flexibility in the ratings we choose. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +Tested-by: Emilio López <emilio@elopez.com.ar> +Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org> +--- + drivers/clocksource/sun4i_timer.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c +index e1878eb..a9b0b5b 100644 +--- a/drivers/clocksource/sun4i_timer.c ++++ b/drivers/clocksource/sun4i_timer.c +@@ -114,7 +114,7 @@ static int sun4i_clkevt_next_event(unsigned long evt, + + static struct clock_event_device sun4i_clockevent = { + .name = "sun4i_tick", +- .rating = 300, ++ .rating = 350, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = sun4i_clkevt_mode, + .set_next_event = sun4i_clkevt_next_event, +@@ -172,7 +172,7 @@ static void __init sun4i_timer_init(struct device_node *node) + + setup_sched_clock(sun4i_timer_sched_read, 32, rate); + clocksource_mmio_init(timer_base + TIMER_CNTVAL_REG(1), node->name, +- rate, 300, 32, clocksource_mmio_readl_down); ++ rate, 350, 32, clocksource_mmio_readl_down); + + ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); + +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/113-clk-sunxi-register-factors-clocks.patch b/target/linux/sunxi/patches-3.13/113-clk-sunxi-register-factors-clocks.patch new file mode 100644 index 0000000000..6a6974e637 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/113-clk-sunxi-register-factors-clocks.patch @@ -0,0 +1,232 @@ +From 9212bc4a3752e9a4db2f73afd99278eb28e5dcff 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:32 -0300 +Subject: [PATCH] clk: sunxi: register factors clocks behind composite +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit reworks factors clock registration to be done behind a +composite clock. This allows us to additionally add a gate, mux or +divisors, as it will be needed by some future PLLs. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + drivers/clk/sunxi/clk-factors.c | 63 +------------------------------------ + drivers/clk/sunxi/clk-factors.h | 16 +++++----- + drivers/clk/sunxi/clk-sunxi.c | 70 ++++++++++++++++++++++++++++++++++++++--- + 3 files changed, 76 insertions(+), 73 deletions(-) + +diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c +index f05207a..9e23264 100644 +--- a/drivers/clk/sunxi/clk-factors.c ++++ b/drivers/clk/sunxi/clk-factors.c +@@ -30,14 +30,6 @@ + * parent - fixed parent. No clk_set_parent support + */ + +-struct clk_factors { +- struct clk_hw hw; +- void __iomem *reg; +- struct clk_factors_config *config; +- void (*get_factors) (u32 *rate, u32 parent, u8 *n, u8 *k, u8 *m, u8 *p); +- spinlock_t *lock; +-}; +- + #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) + + #define SETMASK(len, pos) (((1U << (len)) - 1) << (pos)) +@@ -120,61 +112,8 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, + return 0; + } + +-static const struct clk_ops clk_factors_ops = { ++const struct clk_ops clk_factors_ops = { + .recalc_rate = clk_factors_recalc_rate, + .round_rate = clk_factors_round_rate, + .set_rate = clk_factors_set_rate, + }; +- +-/** +- * clk_register_factors - register a factors clock with +- * the clock framework +- * @dev: device registering this clock +- * @name: name of this clock +- * @parent_name: name of clock's parent +- * @flags: framework-specific flags +- * @reg: register address to adjust factors +- * @config: shift and width of factors n, k, m and p +- * @get_factors: function to calculate the factors for a given frequency +- * @lock: shared register lock for this clock +- */ +-struct clk *clk_register_factors(struct device *dev, const char *name, +- const char *parent_name, +- unsigned long flags, void __iomem *reg, +- struct clk_factors_config *config, +- void (*get_factors)(u32 *rate, u32 parent, +- u8 *n, u8 *k, u8 *m, u8 *p), +- spinlock_t *lock) +-{ +- struct clk_factors *factors; +- struct clk *clk; +- struct clk_init_data init; +- +- /* allocate the factors */ +- factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); +- if (!factors) { +- pr_err("%s: could not allocate factors clk\n", __func__); +- return ERR_PTR(-ENOMEM); +- } +- +- init.name = name; +- init.ops = &clk_factors_ops; +- init.flags = flags; +- init.parent_names = (parent_name ? &parent_name : NULL); +- init.num_parents = (parent_name ? 1 : 0); +- +- /* struct clk_factors assignments */ +- factors->reg = reg; +- factors->config = config; +- factors->lock = lock; +- factors->hw.init = &init; +- factors->get_factors = get_factors; +- +- /* register the clock */ +- clk = clk_register(dev, &factors->hw); +- +- if (IS_ERR(clk)) +- kfree(factors); +- +- return clk; +-} +diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h +index f49851c..02e1a43 100644 +--- a/drivers/clk/sunxi/clk-factors.h ++++ b/drivers/clk/sunxi/clk-factors.h +@@ -17,11 +17,13 @@ struct clk_factors_config { + u8 pwidth; + }; + +-struct clk *clk_register_factors(struct device *dev, const char *name, +- const char *parent_name, +- unsigned long flags, void __iomem *reg, +- struct clk_factors_config *config, +- void (*get_factors) (u32 *rate, u32 parent_rate, +- u8 *n, u8 *k, u8 *m, u8 *p), +- spinlock_t *lock); ++struct clk_factors { ++ struct clk_hw hw; ++ void __iomem *reg; ++ struct clk_factors_config *config; ++ void (*get_factors) (u32 *rate, u32 parent, u8 *n, u8 *k, u8 *m, u8 *p); ++ spinlock_t *lock; ++}; ++ ++extern const struct clk_ops clk_factors_ops; + #endif +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 492ef0e..7dc39a6 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -23,6 +23,9 @@ + + static DEFINE_SPINLOCK(clk_lock); + ++/* Maximum number of parents our clocks have */ ++#define SUNXI_MAX_PARENTS 5 ++ + /** + * sun4i_osc_clk_setup() - Setup function for gatable oscillator + */ +@@ -261,7 +264,11 @@ static void sun4i_get_apb1_factors(u32 *freq, u32 parent_rate, + * sunxi_factors_clk_setup() - Setup function for factor clocks + */ + ++#define SUNXI_FACTORS_MUX_MASK 0x3 ++ + struct factors_data { ++ int enable; ++ int mux; + struct clk_factors_config *table; + void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p); + }; +@@ -312,16 +319,71 @@ static void __init sunxi_factors_clk_setup(struct device_node *node, + struct factors_data *data) + { + struct clk *clk; ++ struct clk_factors *factors; ++ struct clk_gate *gate = NULL; ++ struct clk_mux *mux = NULL; ++ struct clk_hw *gate_hw = NULL; ++ struct clk_hw *mux_hw = NULL; + const char *clk_name = node->name; +- const char *parent; ++ const char *parents[SUNXI_MAX_PARENTS]; + void *reg; ++ int i = 0; + + reg = of_iomap(node, 0); + +- parent = of_clk_get_parent_name(node, 0); ++ /* if we have a mux, we will have >1 parents */ ++ while (i < SUNXI_MAX_PARENTS && ++ (parents[i] = of_clk_get_parent_name(node, i)) != NULL) ++ i++; ++ ++ factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); ++ if (!factors) ++ return; ++ ++ /* Add a gate if this factor clock can be gated */ ++ if (data->enable) { ++ gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); ++ if (!gate) { ++ kfree(factors); ++ return; ++ } ++ ++ /* set up gate properties */ ++ gate->reg = reg; ++ gate->bit_idx = data->enable; ++ gate->lock = &clk_lock; ++ gate_hw = &gate->hw; ++ } ++ ++ /* Add a mux if this factor clock can be muxed */ ++ if (data->mux) { ++ mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); ++ if (!mux) { ++ kfree(factors); ++ kfree(gate); ++ return; ++ } ++ ++ /* set up gate properties */ ++ mux->reg = reg; ++ mux->shift = data->mux; ++ mux->mask = SUNXI_FACTORS_MUX_MASK; ++ mux->lock = &clk_lock; ++ mux_hw = &mux->hw; ++ } ++ ++ /* set up factors properties */ ++ factors->reg = reg; ++ factors->config = data->table; ++ factors->get_factors = data->getter; ++ factors->lock = &clk_lock; + +- clk = clk_register_factors(NULL, clk_name, parent, 0, reg, +- data->table, data->getter, &clk_lock); ++ clk = clk_register_composite(NULL, clk_name, ++ parents, i, ++ mux_hw, &clk_mux_ops, ++ &factors->hw, &clk_factors_ops, ++ gate_hw, &clk_gate_ops, ++ i ? 0 : CLK_IS_ROOT); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/114-clk-sunxi-clean-magic-number.patch b/target/linux/sunxi/patches-3.13/114-clk-sunxi-clean-magic-number.patch new file mode 100644 index 0000000000..be77e30909 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/114-clk-sunxi-clean-magic-number.patch @@ -0,0 +1,40 @@ +From 33574f94b0d4d8bc8af732fbcb4f911c3dd8c96b 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:33 -0300 +Subject: [PATCH] clk: sunxi: clean the magic number of mux parents +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This was pointed out during the review of the factor patches. Let's +indicate what does that magic 5 mean. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +--- + drivers/clk/sunxi/clk-sunxi.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 7dc39a6..25ebba8 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -420,13 +420,14 @@ static void __init sunxi_mux_clk_setup(struct device_node *node, + { + struct clk *clk; + const char *clk_name = node->name; +- const char *parents[5]; ++ const char *parents[SUNXI_MAX_PARENTS]; + void *reg; + int i = 0; + + reg = of_iomap(node, 0); + +- while (i < 5 && (parents[i] = of_clk_get_parent_name(node, i)) != NULL) ++ while (i < SUNXI_MAX_PARENTS && ++ (parents[i] = of_clk_get_parent_name(node, i)) != NULL) + i++; + + clk = clk_register_mux(NULL, clk_name, parents, i, +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/115-clk-sunxi_add-gating-pll1.patch b/target/linux/sunxi/patches-3.13/115-clk-sunxi_add-gating-pll1.patch new file mode 100644 index 0000000000..a982d4cd18 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/115-clk-sunxi_add-gating-pll1.patch @@ -0,0 +1,53 @@ +From 3d56b9643ff9fff3c7ceb095e03f4ab7e149b9ce 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:34 -0300 +Subject: [PATCH] clk: sunxi: add gating support to PLL1 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit adds gating support to PLL1 on the clock driver. This makes +the PLL1 implementation fully compatible with PLL4 as well. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> +Acked-by: Mike Turquette <mturquette@linaro.org> +--- + Documentation/devicetree/bindings/clock/sunxi.txt | 2 +- + drivers/clk/sunxi/clk-sunxi.c | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt +index 91a748f..b8c6cc4 100644 +--- a/Documentation/devicetree/bindings/clock/sunxi.txt ++++ b/Documentation/devicetree/bindings/clock/sunxi.txt +@@ -7,7 +7,7 @@ This binding uses the common clock binding[1]. + Required properties: + - compatible : shall be one of the following: + "allwinner,sun4i-osc-clk" - for a gatable oscillator +- "allwinner,sun4i-pll1-clk" - for the main PLL clock ++ "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-cpu-clk" - for the CPU multiplexer clock + "allwinner,sun4i-axi-clk" - for the AXI clock +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 25ebba8..52f34ec 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -301,11 +301,13 @@ struct factors_data { + }; + + static const struct factors_data sun4i_pll1_data __initconst = { ++ .enable = 31, + .table = &sun4i_pll1_config, + .getter = sun4i_get_pll1_factors, + }; + + static const struct factors_data sun6i_a31_pll1_data __initconst = { ++ .enable = 31, + .table = &sun6i_a31_pll1_config, + .getter = sun6i_a31_get_pll1_factors, + }; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/116-clk-sunxi-add-pll4.patch b/target/linux/sunxi/patches-3.13/116-clk-sunxi-add-pll4.patch new file mode 100644 index 0000000000..84541de349 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/116-clk-sunxi-add-pll4.patch @@ -0,0 +1,95 @@ +From ff0b5fdb65bc7f10af7e83bb0919cb6bec2dc624 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:35 -0300 +Subject: [PATCH] ARM: sunxi: add PLL4 support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit adds the PLL4 definition to the sun4i, sun5i and sun7i +device trees. PLL4 is compatible with PLL1. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + arch/arm/boot/dts/sun4i-a10.dtsi | 7 +++++++ + arch/arm/boot/dts/sun5i-a10s.dtsi | 7 +++++++ + arch/arm/boot/dts/sun5i-a13.dtsi | 7 +++++++ + arch/arm/boot/dts/sun7i-a20.dtsi | 7 +++++++ + 4 files changed, 28 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi +index 0bf70ee..1d6346c 100644 +--- a/arch/arm/boot/dts/sun4i-a10.dtsi ++++ b/arch/arm/boot/dts/sun4i-a10.dtsi +@@ -70,6 +70,13 @@ + clocks = <&osc24M>; + }; + ++ pll4: pll4@01c20018 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-pll1-clk"; ++ reg = <0x01c20018 0x4>; ++ clocks = <&osc24M>; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi +index 924a2c1..64d6d75 100644 +--- a/arch/arm/boot/dts/sun5i-a10s.dtsi ++++ b/arch/arm/boot/dts/sun5i-a10s.dtsi +@@ -67,6 +67,13 @@ + clocks = <&osc24M>; + }; + ++ pll4: pll4@01c20018 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-pll1-clk"; ++ reg = <0x01c20018 0x4>; ++ clocks = <&osc24M>; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi +index 1ccd75d..2c355c8 100644 +--- a/arch/arm/boot/dts/sun5i-a13.dtsi ++++ b/arch/arm/boot/dts/sun5i-a13.dtsi +@@ -67,6 +67,13 @@ + clocks = <&osc24M>; + }; + ++ pll4: pll4@01c20018 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-pll1-clk"; ++ reg = <0x01c20018 0x4>; ++ clocks = <&osc24M>; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index c74147a..18144f0 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -66,6 +66,13 @@ + clocks = <&osc24M>; + }; + ++ pll4: pll4@01c20018 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-pll1-clk"; ++ reg = <0x01c20018 0x4>; ++ clocks = <&osc24M>; ++ }; ++ + /* + * This is a dummy clock, to be used as placeholder on + * other mux clocks when a specific parent clock is not +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/117-clk-sunxi-factors_clk_setup_update.patch b/target/linux/sunxi/patches-3.13/117-clk-sunxi-factors_clk_setup_update.patch new file mode 100644 index 0000000000..be38689ca5 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/117-clk-sunxi-factors_clk_setup_update.patch @@ -0,0 +1,79 @@ +From 8a3282a0a185108e37e7a48437b58d956ff56f4a 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:36 -0300 +Subject: [PATCH] clk: sunxi: make factors_clk_setup return the clock it + registers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We will be needing this to register a factor clock as parent with leaf +divisors on a single call. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +Acked-by: Mike Turquette <mturquette@linaro.org> +--- + drivers/clk/sunxi/clk-sunxi.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 52f34ec..96ccb3c 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -317,8 +317,8 @@ struct factors_data { + .getter = sun4i_get_apb1_factors, + }; + +-static void __init sunxi_factors_clk_setup(struct device_node *node, +- struct factors_data *data) ++static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, ++ const struct factors_data *data) + { + struct clk *clk; + struct clk_factors *factors; +@@ -340,14 +340,14 @@ static void __init sunxi_factors_clk_setup(struct device_node *node, + + factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); + if (!factors) +- return; ++ return NULL; + + /* Add a gate if this factor clock can be gated */ + if (data->enable) { + gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); + if (!gate) { + kfree(factors); +- return; ++ return NULL; + } + + /* set up gate properties */ +@@ -363,7 +363,7 @@ static void __init sunxi_factors_clk_setup(struct device_node *node, + if (!mux) { + kfree(factors); + kfree(gate); +- return; ++ return NULL; + } + + /* set up gate properties */ +@@ -384,13 +384,14 @@ static void __init sunxi_factors_clk_setup(struct device_node *node, + parents, i, + mux_hw, &clk_mux_ops, + &factors->hw, &clk_factors_ops, +- gate_hw, &clk_gate_ops, +- i ? 0 : CLK_IS_ROOT); ++ gate_hw, &clk_gate_ops, 0); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + } ++ ++ return clk; + } + + +-- +1.8.5.1 + 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 new file mode 100644 index 0000000000..425c92955e --- /dev/null +++ b/target/linux/sunxi/patches-3.13/118-clk-sunxi-add-pll5-pll6.patch @@ -0,0 +1,310 @@ +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(+) + +diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt +index b8c6cc4..80b2a39 100644 +--- 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 +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 96ccb3c..649d7c3 100644 +--- 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(u32 *freq, u32 parent_rate, + } + + /** ++ * 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 @@ struct factors_data { + .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 @@ struct factors_data { + .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(struct device_node *node, + 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 void __init sunxi_gates_clk_setup(struct device_node *node, + {} + }; + ++/* 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(struct device_node *np) + /* 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); + +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/119-dt-sunxi-add-pll5-pll6.patch b/target/linux/sunxi/patches-3.13/119-dt-sunxi-add-pll5-pll6.patch new file mode 100644 index 0000000000..bfc278c9a4 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/119-dt-sunxi-add-pll5-pll6.patch @@ -0,0 +1,198 @@ +From 6d3ca59232090bff1b5e1abfd3417a3859e47425 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:38 -0300 +Subject: [PATCH] ARM: sunxi: add PLL5 and PLL6 support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit adds PLL5 and PLL6 nodes to the sun4i, sun5i and sun7i +device trees. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + arch/arm/boot/dts/sun4i-a10.dtsi | 19 +++++++++++++++++-- + arch/arm/boot/dts/sun5i-a10s.dtsi | 19 +++++++++++++++++-- + arch/arm/boot/dts/sun5i-a13.dtsi | 19 +++++++++++++++++-- + arch/arm/boot/dts/sun7i-a20.dtsi | 28 ++++++++++++++++------------ + 4 files changed, 67 insertions(+), 18 deletions(-) + +diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi +index 1d6346c..07564e9e 100644 +--- a/arch/arm/boot/dts/sun4i-a10.dtsi ++++ b/arch/arm/boot/dts/sun4i-a10.dtsi +@@ -77,6 +77,22 @@ + clocks = <&osc24M>; + }; + ++ pll5: pll5@01c20020 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll5-clk"; ++ reg = <0x01c20020 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll5_ddr", "pll5_other"; ++ }; ++ ++ pll6: pll6@01c20028 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll6-clk"; ++ reg = <0x01c20028 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll6_sata", "pll6_other", "pll6"; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +@@ -142,12 +158,11 @@ + "apb0_ir1", "apb0_keypad"; + }; + +- /* dummy is pll62 */ + apb1_mux: apb1_mux@01c20058 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-apb1-mux-clk"; + reg = <0x01c20058 0x4>; +- clocks = <&osc24M>, <&dummy>, <&osc32k>; ++ clocks = <&osc24M>, <&pll6 1>, <&osc32k>; + }; + + apb1: apb1@01c20058 { +diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi +index 64d6d75..ca19362 100644 +--- a/arch/arm/boot/dts/sun5i-a10s.dtsi ++++ b/arch/arm/boot/dts/sun5i-a10s.dtsi +@@ -74,6 +74,22 @@ + clocks = <&osc24M>; + }; + ++ pll5: pll5@01c20020 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll5-clk"; ++ reg = <0x01c20020 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll5_ddr", "pll5_other"; ++ }; ++ ++ pll6: pll6@01c20028 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll6-clk"; ++ reg = <0x01c20028 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll6_sata", "pll6_other", "pll6"; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +@@ -134,12 +150,11 @@ + "apb0_ir", "apb0_keypad"; + }; + +- /* dummy is pll62 */ + apb1_mux: apb1_mux@01c20058 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-apb1-mux-clk"; + reg = <0x01c20058 0x4>; +- clocks = <&osc24M>, <&dummy>, <&osc32k>; ++ clocks = <&osc24M>, <&pll6 1>, <&osc32k>; + }; + + apb1: apb1@01c20058 { +diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi +index 2c355c8..9ac706a 100644 +--- a/arch/arm/boot/dts/sun5i-a13.dtsi ++++ b/arch/arm/boot/dts/sun5i-a13.dtsi +@@ -74,6 +74,22 @@ + clocks = <&osc24M>; + }; + ++ pll5: pll5@01c20020 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll5-clk"; ++ reg = <0x01c20020 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll5_ddr", "pll5_other"; ++ }; ++ ++ pll6: pll6@01c20028 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll6-clk"; ++ reg = <0x01c20028 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll6_sata", "pll6_other", "pll6"; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +@@ -132,12 +148,11 @@ + clock-output-names = "apb0_codec", "apb0_pio", "apb0_ir"; + }; + +- /* dummy is pll6 */ + apb1_mux: apb1_mux@01c20058 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-apb1-mux-clk"; + reg = <0x01c20058 0x4>; +- clocks = <&osc24M>, <&dummy>, <&osc32k>; ++ clocks = <&osc24M>, <&pll6 1>, <&osc32k>; + }; + + apb1: apb1@01c20058 { +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 18144f0..9176ed0 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -73,23 +73,27 @@ + clocks = <&osc24M>; + }; + +- /* +- * This is a dummy clock, to be used as placeholder on +- * other mux clocks when a specific parent clock is not +- * yet implemented. It should be dropped when the driver +- * is complete. +- */ +- pll6: pll6 { +- #clock-cells = <0>; +- compatible = "fixed-clock"; +- clock-frequency = <0>; ++ pll5: pll5@01c20020 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll5-clk"; ++ reg = <0x01c20020 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll5_ddr", "pll5_other"; ++ }; ++ ++ pll6: pll6@01c20028 { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun4i-pll6-clk"; ++ reg = <0x01c20028 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "pll6_sata", "pll6_other", "pll6"; + }; + + cpu: cpu@01c20054 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-cpu-clk"; + reg = <0x01c20054 0x4>; +- clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll6>; ++ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll6 1>; + }; + + axi: axi@01c20054 { +@@ -148,7 +152,7 @@ + #clock-cells = <0>; + compatible = "allwinner,sun4i-apb1-mux-clk"; + reg = <0x01c20058 0x4>; +- clocks = <&osc24M>, <&pll6>, <&osc32k>; ++ clocks = <&osc24M>, <&pll6 1>, <&osc32k>; + }; + + apb1: apb1@01c20058 { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/120-clk-sunxi-mod0.patch b/target/linux/sunxi/patches-3.13/120-clk-sunxi-mod0.patch new file mode 100644 index 0000000000..34a2a2ac2b --- /dev/null +++ b/target/linux/sunxi/patches-3.13/120-clk-sunxi-mod0.patch @@ -0,0 +1,129 @@ +From bdc913d1ef5143a8728ae414fcb90f9ed87a58da 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:39 -0300 +Subject: [PATCH] clk: sunxi: mod0 support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit implements support for the "module 0" type of clocks, as +used by MMC, IR, NAND, SATA and other components. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +Acked-by: Mike Turquette <mturquette@linaro.org> +--- + Documentation/devicetree/bindings/clock/sunxi.txt | 5 +- + drivers/clk/sunxi/clk-sunxi.c | 57 +++++++++++++++++++++++ + 2 files changed, 61 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt +index 80b2a39..46d8433 100644 +--- a/Documentation/devicetree/bindings/clock/sunxi.txt ++++ b/Documentation/devicetree/bindings/clock/sunxi.txt +@@ -35,10 +35,13 @@ Required properties: + "allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20 + "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31 + "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 ++ "allwinner,sun4i-mod0-clk" - for the module 0 family of clocks + + Required properties for all clocks: + - reg : shall be the control register address for the clock. +-- clocks : shall be the input parent clock(s) phandle for the clock ++- clocks : shall be the input parent clock(s) phandle for the clock. For ++ multiplexed clocks, the list order must match the hardware ++ programming order. + - #clock-cells : from common clock binding; shall be set to 0 except for + "allwinner,*-gates-clk" where it shall be set to 1 + +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 649d7c3..af99b57 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -295,6 +295,47 @@ static void sun4i_get_apb1_factors(u32 *freq, u32 parent_rate, + + + /** ++ * sun4i_get_mod0_factors() - calculates m, n factors for MOD0-style clocks ++ * MMC rate is calculated as follows ++ * rate = (parent_rate >> p) / (m + 1); ++ */ ++ ++static void sun4i_get_mod0_factors(u32 *freq, u32 parent_rate, ++ u8 *n, u8 *k, u8 *m, u8 *p) ++{ ++ u8 div, calcm, calcp; ++ ++ /* These clocks can only divide, so we will never be able to achieve ++ * frequencies higher than the parent frequency */ ++ if (*freq > parent_rate) ++ *freq = parent_rate; ++ ++ div = parent_rate / *freq; ++ ++ if (div < 16) ++ calcp = 0; ++ else if (div / 2 < 16) ++ calcp = 1; ++ else if (div / 4 < 16) ++ calcp = 2; ++ else ++ calcp = 3; ++ ++ calcm = DIV_ROUND_UP(div, 1 << calcp); ++ ++ *freq = (parent_rate >> calcp) / calcm; ++ ++ /* we were called to round the frequency, we can now return */ ++ if (n == NULL) ++ return; ++ ++ *m = calcm - 1; ++ *p = calcp; ++} ++ ++ ++ ++/** + * sunxi_factors_clk_setup() - Setup function for factor clocks + */ + +@@ -341,6 +382,14 @@ struct factors_data { + .pwidth = 2, + }; + ++/* user manual says "n" but it's really "p" */ ++static struct clk_factors_config sun4i_mod0_config = { ++ .mshift = 0, ++ .mwidth = 4, ++ .pshift = 16, ++ .pwidth = 2, ++}; ++ + static const struct factors_data sun4i_pll1_data __initconst = { + .enable = 31, + .table = &sun4i_pll1_config, +@@ -364,6 +413,13 @@ struct factors_data { + .getter = sun4i_get_apb1_factors, + }; + ++static const struct factors_data sun4i_mod0_data __initconst = { ++ .enable = 31, ++ .mux = 24, ++ .table = &sun4i_mod0_config, ++ .getter = sun4i_get_mod0_factors, ++}; ++ + static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, + const struct factors_data *data) + { +@@ -852,6 +908,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, + {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,}, + {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,}, + {.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,}, ++ {.compatible = "allwinner,sun4i-mod0-clk", .data = &sun4i_mod0_data,}, + {} + }; + +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/121-clk-sunxi-better-factor-dt-nodes.patch b/target/linux/sunxi/patches-3.13/121-clk-sunxi-better-factor-dt-nodes.patch new file mode 100644 index 0000000000..175f115cea --- /dev/null +++ b/target/linux/sunxi/patches-3.13/121-clk-sunxi-better-factor-dt-nodes.patch @@ -0,0 +1,52 @@ +From 7d47b009bf287bf5e0817f47c40e32b7ec0e8151 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:40 -0300 +Subject: [PATCH] clk: sunxi: support better factor DT nodes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The DT nodes should look like + + abc_clk: clk@deadbeef { + ... + clock-output-names = "abc"; + } + +But our old DT nodes look like + + abc: abc@deadbeef { + ... + } + +So, let's support both formats, until we can transition everything +to the new, correct one. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +--- + drivers/clk/sunxi/clk-sunxi.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index af99b57..81d4c72 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -441,6 +441,15 @@ static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, + (parents[i] = of_clk_get_parent_name(node, i)) != NULL) + i++; + ++ /* Nodes should be providing the name via clock-output-names ++ * but originally our dts didn't, and so we used node->name. ++ * The new, better nodes look like clk@deadbeef, so we pull the ++ * name just in this case */ ++ if (!strcmp("clk", clk_name)) { ++ of_property_read_string_index(node, "clock-output-names", ++ 0, &clk_name); ++ } ++ + factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); + if (!factors) + return NULL; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/122-1-dt-sun4i-add-mod0.patch b/target/linux/sunxi/patches-3.13/122-1-dt-sun4i-add-mod0.patch new file mode 100644 index 0000000000..e635f2eabd --- /dev/null +++ b/target/linux/sunxi/patches-3.13/122-1-dt-sun4i-add-mod0.patch @@ -0,0 +1,150 @@ +From dda274b6f95902b619af1fb14f26e231bb420371 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:41 -0300 +Subject: [PATCH] ARM: sun4i: dt: mod0 clocks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit adds all the mod0 clocks present on sun4i to its device tree + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + arch/arm/boot/dts/sun4i-a10.dtsi | 120 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 120 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi +index 07564e9e..3ba2b46 100644 +--- a/arch/arm/boot/dts/sun4i-a10.dtsi ++++ b/arch/arm/boot/dts/sun4i-a10.dtsi +@@ -184,6 +184,126 @@ + "apb1_uart4", "apb1_uart5", "apb1_uart6", + "apb1_uart7"; + }; ++ ++ nand_clk: clk@01c20080 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20080 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "nand"; ++ }; ++ ++ ms_clk: clk@01c20084 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20084 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ms"; ++ }; ++ ++ mmc0_clk: clk@01c20088 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20088 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mmc0"; ++ }; ++ ++ mmc1_clk: clk@01c2008c { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c2008c 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mmc1"; ++ }; ++ ++ mmc2_clk: clk@01c20090 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20090 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mmc2"; ++ }; ++ ++ mmc3_clk: clk@01c20094 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20094 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mmc3"; ++ }; ++ ++ ts_clk: clk@01c20098 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20098 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ts"; ++ }; ++ ++ ss_clk: clk@01c2009c { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c2009c 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ss"; ++ }; ++ ++ spi0_clk: clk@01c200a0 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200a0 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "spi0"; ++ }; ++ ++ spi1_clk: clk@01c200a4 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200a4 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "spi1"; ++ }; ++ ++ spi2_clk: clk@01c200a8 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200a8 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "spi2"; ++ }; ++ ++ pata_clk: clk@01c200ac { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200ac 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "pata"; ++ }; ++ ++ ir0_clk: clk@01c200b0 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200b0 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ir0"; ++ }; ++ ++ ir1_clk: clk@01c200b4 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200b4 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ir1"; ++ }; ++ ++ spi3_clk: clk@01c200d4 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200d4 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "spi3"; ++ }; + }; + + soc@01c00000 { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/122-2-dt-sun5i-add-mod0.patch b/target/linux/sunxi/patches-3.13/122-2-dt-sun5i-add-mod0.patch new file mode 100644 index 0000000000..bea53fe456 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/122-2-dt-sun5i-add-mod0.patch @@ -0,0 +1,220 @@ +From 9a8d3f21c94099a2bcd79ac1684cc8020fd98df2 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:42 -0300 +Subject: [PATCH] ARM: sun5i: dt: mod0 clocks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit adds all the mod0 clocks available on A10 and A13. The list +has been constructed by looking at the Allwinner code release for A10S +and A13. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + arch/arm/boot/dts/sun5i-a10s.dtsi | 88 +++++++++++++++++++++++++++++++++++++++ + arch/arm/boot/dts/sun5i-a13.dtsi | 88 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 176 insertions(+) + +diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi +index ca19362..96c7185 100644 +--- a/arch/arm/boot/dts/sun5i-a10s.dtsi ++++ b/arch/arm/boot/dts/sun5i-a10s.dtsi +@@ -173,6 +173,94 @@ + "apb1_i2c2", "apb1_uart0", "apb1_uart1", + "apb1_uart2", "apb1_uart3"; + }; ++ ++ nand_clk: clk@01c20080 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20080 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "nand"; ++ }; ++ ++ ms_clk: clk@01c20084 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20084 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ms"; ++ }; ++ ++ mmc0_clk: clk@01c20088 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20088 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mmc0"; ++ }; ++ ++ mmc1_clk: clk@01c2008c { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c2008c 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mmc1"; ++ }; ++ ++ mmc2_clk: clk@01c20090 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20090 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mmc2"; ++ }; ++ ++ ts_clk: clk@01c20098 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20098 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ts"; ++ }; ++ ++ ss_clk: clk@01c2009c { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c2009c 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ss"; ++ }; ++ ++ spi0_clk: clk@01c200a0 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200a0 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "spi0"; ++ }; ++ ++ spi1_clk: clk@01c200a4 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200a4 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "spi1"; ++ }; ++ ++ spi2_clk: clk@01c200a8 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200a8 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "spi2"; ++ }; ++ ++ ir0_clk: clk@01c200b0 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200b0 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ir0"; ++ }; + }; + + soc@01c00000 { +diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi +index 9ac706a..e2505d6 100644 +--- a/arch/arm/boot/dts/sun5i-a13.dtsi ++++ b/arch/arm/boot/dts/sun5i-a13.dtsi +@@ -170,6 +170,94 @@ + clock-output-names = "apb1_i2c0", "apb1_i2c1", + "apb1_i2c2", "apb1_uart1", "apb1_uart3"; + }; ++ ++ nand_clk: clk@01c20080 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20080 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "nand"; ++ }; ++ ++ ms_clk: clk@01c20084 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20084 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ms"; ++ }; ++ ++ mmc0_clk: clk@01c20088 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20088 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mmc0"; ++ }; ++ ++ mmc1_clk: clk@01c2008c { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c2008c 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mmc1"; ++ }; ++ ++ mmc2_clk: clk@01c20090 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20090 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mmc2"; ++ }; ++ ++ ts_clk: clk@01c20098 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20098 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ts"; ++ }; ++ ++ ss_clk: clk@01c2009c { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c2009c 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ss"; ++ }; ++ ++ spi0_clk: clk@01c200a0 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200a0 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "spi0"; ++ }; ++ ++ spi1_clk: clk@01c200a4 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200a4 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "spi1"; ++ }; ++ ++ spi2_clk: clk@01c200a8 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200a8 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "spi2"; ++ }; ++ ++ ir0_clk: clk@01c200b0 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200b0 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ir0"; ++ }; + }; + + soc@01c00000 { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/122-3-dt-sun7i-add-mod0.patch b/target/linux/sunxi/patches-3.13/122-3-dt-sun7i-add-mod0.patch new file mode 100644 index 0000000000..bf61059016 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/122-3-dt-sun7i-add-mod0.patch @@ -0,0 +1,151 @@ +From d7904e075e3378bec09333b6a3247b3146b3dd91 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:43 -0300 +Subject: [PATCH] ARM: sun7i: dt: mod0 clocks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit adds all the mod0 clocks available on A20 to its device +tree. This list was created by looking at AW's code release. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + arch/arm/boot/dts/sun7i-a20.dtsi | 120 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 120 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 9176ed0..f6ee631 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -174,6 +174,126 @@ + "apb1_uart2", "apb1_uart3", "apb1_uart4", + "apb1_uart5", "apb1_uart6", "apb1_uart7"; + }; ++ ++ nand_clk: clk@01c20080 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20080 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "nand"; ++ }; ++ ++ ms_clk: clk@01c20084 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20084 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ms"; ++ }; ++ ++ mmc0_clk: clk@01c20088 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20088 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mmc0"; ++ }; ++ ++ mmc1_clk: clk@01c2008c { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c2008c 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mmc1"; ++ }; ++ ++ mmc2_clk: clk@01c20090 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20090 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mmc2"; ++ }; ++ ++ mmc3_clk: clk@01c20094 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20094 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mmc3"; ++ }; ++ ++ ts_clk: clk@01c20098 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c20098 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ts"; ++ }; ++ ++ ss_clk: clk@01c2009c { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c2009c 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ss"; ++ }; ++ ++ spi0_clk: clk@01c200a0 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200a0 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "spi0"; ++ }; ++ ++ spi1_clk: clk@01c200a4 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200a4 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "spi1"; ++ }; ++ ++ spi2_clk: clk@01c200a8 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200a8 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "spi2"; ++ }; ++ ++ pata_clk: clk@01c200ac { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200ac 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "pata"; ++ }; ++ ++ ir0_clk: clk@01c200b0 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200b0 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ir0"; ++ }; ++ ++ ir1_clk: clk@01c200b4 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200b4 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "ir1"; ++ }; ++ ++ spi3_clk: clk@01c200d4 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c200d4 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "spi3"; ++ }; + }; + + soc@01c00000 { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/123-clk-sunxi-automatic-reparenting.patch b/target/linux/sunxi/patches-3.13/123-clk-sunxi-automatic-reparenting.patch new file mode 100644 index 0000000000..c772b9fe6f --- /dev/null +++ b/target/linux/sunxi/patches-3.13/123-clk-sunxi-automatic-reparenting.patch @@ -0,0 +1,73 @@ +From 04b5b3f9c83c0c0b472c4704d83ec7f56a485a21 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +Date: Thu, 5 Sep 2013 19:52:41 -0300 +Subject: [PATCH] clk: sunxi: factors: automatic reparenting support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit implements .determine_rate, so that our factor clocks can be +reparented when needed. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +--- + drivers/clk/sunxi/clk-factors.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c +index 9e23264..3806d97 100644 +--- a/drivers/clk/sunxi/clk-factors.c ++++ b/drivers/clk/sunxi/clk-factors.c +@@ -77,6 +77,41 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, + return rate; + } + ++static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *best_parent_rate, ++ struct clk **best_parent_p) ++{ ++ struct clk *clk = hw->clk, *parent, *best_parent = NULL; ++ int i, num_parents; ++ unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0; ++ ++ /* find the parent that can help provide the fastest rate <= rate */ ++ num_parents = __clk_get_num_parents(clk); ++ for (i = 0; i < num_parents; i++) { ++ parent = clk_get_parent_by_index(clk, i); ++ if (!parent) ++ continue; ++ if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT) ++ parent_rate = __clk_round_rate(parent, rate); ++ else ++ parent_rate = __clk_get_rate(parent); ++ ++ child_rate = clk_factors_round_rate(hw, rate, &parent_rate); ++ ++ if (child_rate <= rate && child_rate > best_child_rate) { ++ best_parent = parent; ++ best = parent_rate; ++ best_child_rate = child_rate; ++ } ++ } ++ ++ if (best_parent) ++ *best_parent_p = best_parent; ++ *best_parent_rate = best; ++ ++ return best_child_rate; ++} ++ + static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) + { +@@ -113,6 +148,7 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, + } + + const struct clk_ops clk_factors_ops = { ++ .determine_rate = clk_factors_determine_rate, + .recalc_rate = clk_factors_recalc_rate, + .round_rate = clk_factors_round_rate, + .set_rate = clk_factors_set_rate, +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/124-clk-sunxi-muxable-ahb-clock.patch b/target/linux/sunxi/patches-3.13/124-clk-sunxi-muxable-ahb-clock.patch new file mode 100644 index 0000000000..83b69b5b9a --- /dev/null +++ b/target/linux/sunxi/patches-3.13/124-clk-sunxi-muxable-ahb-clock.patch @@ -0,0 +1,102 @@ +From 9490107c16c8eaa35b07794e19d5d2eddea8e44b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +Date: Sat, 14 Sep 2013 20:48:40 -0300 +Subject: [PATCH] clk: sunxi: Implement muxable AHB clock +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +sun5i and sun7i have a mux to change the AHB clock parent, this commit +adds support for it on the driver. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +--- + Documentation/devicetree/bindings/clock/sunxi.txt | 1 + + drivers/clk/sunxi/clk-sunxi.c | 37 +++++++++++++++++++++++ + 2 files changed, 38 insertions(+) + +diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt +index e840cb2..941bd93 100644 +--- a/Documentation/devicetree/bindings/clock/sunxi.txt ++++ b/Documentation/devicetree/bindings/clock/sunxi.txt +@@ -15,6 +15,7 @@ Required properties: + "allwinner,sun4i-axi-clk" - for the AXI clock + "allwinner,sun4i-axi-gates-clk" - for the AXI gates + "allwinner,sun4i-ahb-clk" - for the AHB clock ++ "allwinner,sun5i-a13-ahb-clk" - for the AHB clock on A13 + "allwinner,sun4i-ahb-gates-clk" - for the AHB gates on A10 + "allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13 + "allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index ea3edeb..625089b 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -249,7 +249,32 @@ static void sun4i_get_pll5_factors(u32 *freq, u32 parent_rate, + *n = DIV_ROUND_UP(div, (*k+1)); + } + ++/** ++ * sun5i_get_ahb_factors() - calculates p factor for AHB ++ * AHB rate is calculated as follows ++ * rate = parent_rate >> p ++ */ + ++static void sun5i_a13_get_ahb_factors(u32 *freq, u32 parent_rate, ++ u8 *n, u8 *k, u8 *m, u8 *p) ++{ ++ u8 div; ++ ++ /* This clock can only divide, so we will never achieve a higher ++ * rate than the parent's */ ++ if (*freq > parent_rate) ++ *freq = parent_rate; ++ ++ /* Normalize value to a parent multiple */ ++ div = *freq / parent_rate; ++ *freq = parent_rate * div; ++ ++ /* we were called to round the frequency, we can now return */ ++ if (n == NULL) ++ return; ++ ++ *p = div; ++} + + /** + * sun4i_get_apb1_factors() - calculates m, p factors for APB1 +@@ -375,6 +400,11 @@ struct factors_data { + .kwidth = 2, + }; + ++static struct clk_factors_config sun5i_a13_ahb_config = { ++ .pshift = 4, ++ .pwidth = 2, ++}; ++ + static struct clk_factors_config sun4i_apb1_config = { + .mshift = 0, + .mwidth = 5, +@@ -408,6 +438,12 @@ struct factors_data { + .getter = sun4i_get_pll5_factors, + }; + ++static const struct factors_data sun5i_a13_ahb_data __initconst = { ++ .mux = 6, ++ .table = &sun5i_a13_ahb_config, ++ .getter = sun5i_a13_get_ahb_factors, ++}; ++ + static const struct factors_data sun4i_apb1_data __initconst = { + .mux = 24, + .table = &sun4i_apb1_config, +@@ -913,6 +949,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, + static const struct of_device_id clk_factors_match[] __initconst = { + {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,}, + {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,}, ++ {.compatible = "allwinner,sun5i-a13-ahb-clk", .data = &sun5i_a13_ahb_data,}, + {.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,}, + {.compatible = "allwinner,sun4i-mod0-clk", .data = &sun4i_mod0_data,}, + {} +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/125-dt-sunxi-update-ahb-clock-sun57i.patch b/target/linux/sunxi/patches-3.13/125-dt-sunxi-update-ahb-clock-sun57i.patch new file mode 100644 index 0000000000..6e1dc68ee8 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/125-dt-sunxi-update-ahb-clock-sun57i.patch @@ -0,0 +1,69 @@ +From c8fe5648aff581545ce5744f73ee1312080b8ef4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +Date: Sat, 14 Sep 2013 20:44:03 -0300 +Subject: [PATCH] ARM: sunxi: dt: Update AHB clock to be muxable on sun[57]i +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +sun5i and sun7i have a mux to select the parent clock for AHB. This +commit implements the required changes on the device trees. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +--- + arch/arm/boot/dts/sun5i-a10s.dtsi | 4 ++-- + arch/arm/boot/dts/sun5i-a13.dtsi | 4 ++-- + arch/arm/boot/dts/sun7i-a20.dtsi | 4 ++-- + 3 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi +index fd3acbd..c42ed2a 100644 +--- a/arch/arm/boot/dts/sun5i-a10s.dtsi ++++ b/arch/arm/boot/dts/sun5i-a10s.dtsi +@@ -115,9 +115,9 @@ + + ahb: ahb@01c20054 { + #clock-cells = <0>; +- compatible = "allwinner,sun4i-ahb-clk"; ++ compatible = "allwinner,sun5i-a13-ahb-clk"; + reg = <0x01c20054 0x4>; +- clocks = <&axi>; ++ clocks = <&axi>, <&cpu>, <&pll6 1>; + }; + + ahb_gates: ahb_gates@01c20060 { +diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi +index 9d40bb4..8274a41 100644 +--- a/arch/arm/boot/dts/sun5i-a13.dtsi ++++ b/arch/arm/boot/dts/sun5i-a13.dtsi +@@ -115,9 +115,9 @@ + + ahb: ahb@01c20054 { + #clock-cells = <0>; +- compatible = "allwinner,sun4i-ahb-clk"; ++ compatible = "allwinner,sun5i-a13-ahb-clk"; + reg = <0x01c20054 0x4>; +- clocks = <&axi>; ++ clocks = <&axi>, <&cpu>, <&pll6 1>; + }; + + ahb_gates: ahb_gates@01c20060 { +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index ec13310..8819c68 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -105,9 +105,9 @@ + + ahb: ahb@01c20054 { + #clock-cells = <0>; +- compatible = "allwinner,sun4i-ahb-clk"; ++ compatible = "allwinner,sun5i-a13-ahb-clk"; + reg = <0x01c20054 0x4>; +- clocks = <&axi>; ++ clocks = <&axi>, <&pll6 1>, <&pll6 2>; + }; + + ahb_gates: ahb_gates@01c20060 { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/126-regulator-dont-print-error-when-no-regulator-found.patch b/target/linux/sunxi/patches-3.13/126-regulator-dont-print-error-when-no-regulator-found.patch new file mode 100644 index 0000000000..b7952b8484 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/126-regulator-dont-print-error-when-no-regulator-found.patch @@ -0,0 +1,34 @@ +From 820a121fdef79cc1293e6fee2fbe8156d9e8a75a Mon Sep 17 00:00:00 2001 +From: Hans de Goede <hdegoede@redhat.com> +Date: Wed, 11 Dec 2013 15:07:52 +0100 +Subject: [PATCH] regulator_get_optional: don't print an error when no + regulator is found + +Only print an error when _regulator_get() is expected to return a valid +regulator, that is when _regulator_get() is called from regulator_get() and +we're not using the dummy because we don't have full-constraints, or when +_regulator_get() is called from regulator_get_exclusive() in which case +returning a dummy is not allowed. + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + drivers/regulator/core.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index d85f313..9888f26 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1351,7 +1351,8 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, + + rdev = dummy_regulator_rdev; + goto found; +- } else { ++ /* Don't log an error when called from regulator_get_optional() */ ++ } else if (!have_full_constraints() || exclusive) { + dev_err(dev, "dummy supplies not allowed\n"); + } + +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/130-dt-sunxi-add-mbusclk.patch b/target/linux/sunxi/patches-3.13/130-dt-sunxi-add-mbusclk.patch new file mode 100644 index 0000000000..a76a97ea08 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/130-dt-sunxi-add-mbusclk.patch @@ -0,0 +1,79 @@ +From 538d4a6ca5f41039d906f28be82e0f4d26ec8ac9 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:44 -0300 +Subject: [PATCH] ARM: sunxi: dt: add nodes for the mbus clock +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +mbus is the memory bus clock, and it is present on both sun5i and sun7i +machines. Its register layout is compatible with the mod0 one. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + arch/arm/boot/dts/sun5i-a10s.dtsi | 8 ++++++++ + arch/arm/boot/dts/sun5i-a13.dtsi | 8 ++++++++ + arch/arm/boot/dts/sun7i-a20.dtsi | 8 ++++++++ + 3 files changed, 24 insertions(+) + +diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi +index 96c7185..78360b3 100644 +--- a/arch/arm/boot/dts/sun5i-a10s.dtsi ++++ b/arch/arm/boot/dts/sun5i-a10s.dtsi +@@ -261,6 +261,14 @@ + clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; + clock-output-names = "ir0"; + }; ++ ++ mbus_clk: clk@01c2015c { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c2015c 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mbus"; ++ }; + }; + + soc@01c00000 { +diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi +index e2505d6..2f37ca5 100644 +--- a/arch/arm/boot/dts/sun5i-a13.dtsi ++++ b/arch/arm/boot/dts/sun5i-a13.dtsi +@@ -258,6 +258,14 @@ + clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; + clock-output-names = "ir0"; + }; ++ ++ mbus_clk: clk@01c2015c { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c2015c 0x4>; ++ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; ++ clock-output-names = "mbus"; ++ }; + }; + + soc@01c00000 { +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index f6ee631..4c25f81 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -294,6 +294,14 @@ + clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; + clock-output-names = "spi3"; + }; ++ ++ mbus_clk: clk@01c2015c { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun4i-mod0-clk"; ++ reg = <0x01c2015c 0x4>; ++ clocks = <&osc24M>, <&pll6 2>, <&pll5 1>; ++ clock-output-names = "mbus"; ++ }; + }; + + soc@01c00000 { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/131-dt-sunxi-add-emac-aliases.patch b/target/linux/sunxi/patches-3.13/131-dt-sunxi-add-emac-aliases.patch new file mode 100644 index 0000000000..e9e929e16d --- /dev/null +++ b/target/linux/sunxi/patches-3.13/131-dt-sunxi-add-emac-aliases.patch @@ -0,0 +1,69 @@ +From 2af807481169af627dc63f98b773c33d85020658 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +Date: Fri, 15 Nov 2013 15:26:44 -0300 +Subject: [PATCH] ARM: sunxi: dt: add EMAC aliases +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +U-Boot uses the ethernet0 alias to locate the right node to fill in +the MAC address of the first ethernet interface. This patch adds the +alias on all the sunxi SoCs with EMAC. In this way, people using +ethernet in U-Boot (eg, for tftp) can keep a consistent address on both +U-Boot and Linux with no additional effort. + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +--- + arch/arm/boot/dts/sun4i-a10.dtsi | 4 ++++ + arch/arm/boot/dts/sun5i-a10s.dtsi | 4 ++++ + arch/arm/boot/dts/sun7i-a20.dtsi | 4 ++++ + 3 files changed, 12 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi +index f11f292..0bf70ee 100644 +--- a/arch/arm/boot/dts/sun4i-a10.dtsi ++++ b/arch/arm/boot/dts/sun4i-a10.dtsi +@@ -15,6 +15,10 @@ + / { + interrupt-parent = <&intc>; + ++ aliases { ++ ethernet0 = &emac; ++ }; ++ + cpus { + #address-cells = <1>; + #size-cells = <0>; +diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi +index 5247674..b4764be 100644 +--- a/arch/arm/boot/dts/sun5i-a10s.dtsi ++++ b/arch/arm/boot/dts/sun5i-a10s.dtsi +@@ -16,6 +16,10 @@ + / { + interrupt-parent = <&intc>; + ++ aliases { ++ ethernet0 = &emac; ++ }; ++ + cpus { + cpu@0 { + compatible = "arm,cortex-a8"; +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index cc3683c..93f7f96 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -16,6 +16,10 @@ + / { + interrupt-parent = <&gic>; + ++ aliases { ++ ethernet0 = &emac; ++ }; ++ + cpus { + #address-cells = <1>; + #size-cells = <0>; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/132-dt-sun7i-update-eth-aliases.patch b/target/linux/sunxi/patches-3.13/132-dt-sun7i-update-eth-aliases.patch new file mode 100644 index 0000000000..b4f5009c2f --- /dev/null +++ b/target/linux/sunxi/patches-3.13/132-dt-sun7i-update-eth-aliases.patch @@ -0,0 +1,30 @@ +From dfd4430579f5e53324c00e9e21fb0929bb46542c Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai <wens@csie.org> +Date: Sat, 7 Dec 2013 01:29:43 +0800 +Subject: [PATCH] ARM: dts: sun7i: Add ethernet alias for GMAC + +U-Boot will insert MAC address into the device tree image. +It looks up ethernet[0-5] aliases to find the ethernet nodes. +Alias GMAC as ethernet0, as it is the only ethernet controller used. + +Signed-off-by: Chen-Yu Tsai <wens@csie.org> +--- + arch/arm/boot/dts/sun7i-a20.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index a0d6ef7..d718f65 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -17,7 +17,7 @@ + interrupt-parent = <&gic>; + + aliases { +- ethernet0 = &emac; ++ ethernet0 = &gmac; + }; + + cpus { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/133-dt-sun7i-add-arch-timers.patch b/target/linux/sunxi/patches-3.13/133-dt-sun7i-add-arch-timers.patch new file mode 100644 index 0000000000..c3b51e7780 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/133-dt-sun7i-add-arch-timers.patch @@ -0,0 +1,38 @@ +From 26523a27f47828e50212201ba25862fe1e2b845c Mon Sep 17 00:00:00 2001 +From: Hans de Goede <hdegoede@redhat.com> +Date: Sun, 1 Dec 2013 22:40:34 +0100 +Subject: [PATCH] ARM: dts: sun7i: Add arch timers + +Note this requires a new enough uboot, otherwise things won't work, ie: + +https://github.com/jwrdegoede/u-boot-sunxi/commits/sunxi-next +or: +http://xenbits.xen.org/gitweb/?p=people/ianc/u-boot.git;a=shortlog;h=refs/heads/devel/sunxi-psci + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun7i-a20.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index d718f65..c9c123a 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -297,6 +297,14 @@ + }; + }; + ++ timer { ++ compatible = "arm,armv7-timer"; ++ interrupts = <1 13 0xf08>, ++ <1 14 0xf08>, ++ <1 11 0xf08>, ++ <1 10 0xf08>; ++ }; ++ + soc@01c00000 { + compatible = "simple-bus"; + #address-cells = <1>; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/135-dt-sun5i-a13-add-olinuxino-micro.patch b/target/linux/sunxi/patches-3.13/135-dt-sun5i-a13-add-olinuxino-micro.patch new file mode 100644 index 0000000000..5872d8448a --- /dev/null +++ b/target/linux/sunxi/patches-3.13/135-dt-sun5i-a13-add-olinuxino-micro.patch @@ -0,0 +1,116 @@ +From aad62992a2921436ec7c054f8b80bc916b8cc9d7 Mon Sep 17 00:00:00 2001 +From: Hans de Goede <hdegoede@redhat.com> +Date: Sat, 14 Dec 2013 16:26:17 +0100 +Subject: [PATCH] ARM: dts: sun5i: Add new sun5i-a13-olinuxino-micro board + +The A13-OLinuXino-MICRO is a small dev-board with the Allwinner A13 SoC: +https://www.olimex.com/Products/OLinuXino/A13/A13-OLinuXino-MICRO/ + +Features: +A13 Cortex A8 processor at 1GHz, 3D Mali400 GPU +256 MB RAM (128Mbit x 16) +5VDC input power supply with own ICs, noise immune design +1 USB host +1 USB OTG which can power the board +SD-card connector for booting the Linux image +VGA video output +LCD signals available on connector so you still can use LCD if you disable VGA/HDMI +Audio output +Microphone input pads (no connector) + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts | 68 +++++++++++++++++++++++++ + 2 files changed, 69 insertions(+) + create mode 100644 arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index d57c1a6..b663ed7 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -255,6 +255,7 @@ dtb-$(CONFIG_ARCH_SUNXI) += \ + sun4i-a10-hackberry.dtb \ + sun5i-a10s-olinuxino-micro.dtb \ + sun5i-a13-olinuxino.dtb \ ++ sun5i-a13-olinuxino-micro.dtb \ + sun6i-a31-colombus.dtb \ + sun7i-a20-cubieboard2.dtb \ + sun7i-a20-cubietruck.dtb \ +diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts +new file mode 100644 +index 0000000..fe2ce0a +--- /dev/null ++++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts +@@ -0,0 +1,68 @@ ++/* ++ * Copyright 2012 Maxime Ripard ++ * Copyright 2013 Hans de Goede <hdegoede@redhat.com> ++ * ++ * Maxime Ripard <maxime.ripard@free-electrons.com> ++ * ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/dts-v1/; ++/include/ "sun5i-a13.dtsi" ++ ++/ { ++ model = "Olimex A13-Olinuxino Micro"; ++ compatible = "olimex,a13-olinuxino-micro", "allwinner,sun5i-a13"; ++ ++ soc@01c00000 { ++ pinctrl@01c20800 { ++ led_pins_olinuxinom: led_pins@0 { ++ allwinner,pins = "PG9"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <1>; ++ allwinner,pull = <0>; ++ }; ++ }; ++ ++ uart1: serial@01c28400 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart1_pins_b>; ++ status = "okay"; ++ }; ++ ++ i2c0: i2c@01c2ac00 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c0_pins_a>; ++ status = "okay"; ++ }; ++ ++ i2c1: i2c@01c2b000 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c1_pins_a>; ++ status = "okay"; ++ }; ++ ++ i2c2: i2c@01c2b400 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_pins_a>; ++ status = "okay"; ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&led_pins_olinuxinom>; ++ ++ power { ++ label = "a13-olinuxino-micro:green:power"; ++ gpios = <&pio 6 9 0>; ++ default-state = "on"; ++ }; ++ }; ++}; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/140-sun47i-rtc-driver.patch b/target/linux/sunxi/patches-3.13/140-sun47i-rtc-driver.patch new file mode 100644 index 0000000000..7945522512 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/140-sun47i-rtc-driver.patch @@ -0,0 +1,580 @@ +From c6890cadc2129a07d69f3dcbfca66522c27b8069 Mon Sep 17 00:00:00 2001 +From: Carlo Caione <carlo.caione@gmail.com> +Date: Sat, 16 Nov 2013 18:33:54 +0100 +Subject: [PATCH] ARM: sun4i/sun7i: RTC driver + +This patch introduces the driver for the RTC in the Allwinner A10 and +A20 SoCs. + +Signed-off-by: Carlo Caione <carlo.caione@gmail.com> +Acked-by: Alessandro Zummo <a.zummo@towertech.it> +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + drivers/rtc/Kconfig | 7 + + drivers/rtc/Makefile | 1 + + drivers/rtc/rtc-sunxi.c | 523 ++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 531 insertions(+) + create mode 100644 drivers/rtc/rtc-sunxi.c + +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 0077302..c2fa86c 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1104,6 +1104,13 @@ config RTC_DRV_SUN4V + If you say Y here you will get support for the Hypervisor + based RTC on SUN4V systems. + ++config RTC_DRV_SUNXI ++ tristate "Allwinner sun4i/sun7i RTC" ++ depends on ARCH_SUNXI ++ help ++ If you say Y here you will get support for the RTC found on ++ Allwinner A10/A20. ++ + config RTC_DRV_STARFIRE + bool "Starfire RTC" + depends on SPARC64 +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 27b4bd8..63f3e99 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -117,6 +117,7 @@ obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o + obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o + obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o + obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o ++obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o + obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o + obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o + obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o +diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c +new file mode 100644 +index 0000000..68a3528 +--- /dev/null ++++ b/drivers/rtc/rtc-sunxi.c +@@ -0,0 +1,523 @@ ++/* ++ * An RTC driver for Allwinner A10/A20 ++ * ++ * Copyright (c) 2013, Carlo Caione <carlo.caione@gmail.com> ++ * ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/err.h> ++#include <linux/fs.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include <linux/rtc.h> ++#include <linux/types.h> ++ ++#define SUNXI_LOSC_CTRL 0x0000 ++#define SUNXI_LOSC_CTRL_RTC_HMS_ACC BIT(8) ++#define SUNXI_LOSC_CTRL_RTC_YMD_ACC BIT(7) ++ ++#define SUNXI_RTC_YMD 0x0004 ++ ++#define SUNXI_RTC_HMS 0x0008 ++ ++#define SUNXI_ALRM_DHMS 0x000c ++ ++#define SUNXI_ALRM_EN 0x0014 ++#define SUNXI_ALRM_EN_CNT_EN BIT(8) ++ ++#define SUNXI_ALRM_IRQ_EN 0x0018 ++#define SUNXI_ALRM_IRQ_EN_CNT_IRQ_EN BIT(0) ++ ++#define SUNXI_ALRM_IRQ_STA 0x001c ++#define SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND BIT(0) ++ ++#define SUNXI_MASK_DH 0x0000001f ++#define SUNXI_MASK_SM 0x0000003f ++#define SUNXI_MASK_M 0x0000000f ++#define SUNXI_MASK_LY 0x00000001 ++#define SUNXI_MASK_D 0x00000ffe ++#define SUNXI_MASK_M 0x0000000f ++ ++#define SUNXI_GET(x, mask, shift) (((x) & ((mask) << (shift))) \ ++ >> (shift)) ++ ++#define SUNXI_SET(x, mask, shift) (((x) & (mask)) << (shift)) ++ ++/* ++ * Get date values ++ */ ++#define SUNXI_DATE_GET_DAY_VALUE(x) SUNXI_GET(x, SUNXI_MASK_DH, 0) ++#define SUNXI_DATE_GET_MON_VALUE(x) SUNXI_GET(x, SUNXI_MASK_M, 8) ++#define SUNXI_DATE_GET_YEAR_VALUE(x, mask) SUNXI_GET(x, mask, 16) ++ ++/* ++ * Get time values ++ */ ++#define SUNXI_TIME_GET_SEC_VALUE(x) SUNXI_GET(x, SUNXI_MASK_SM, 0) ++#define SUNXI_TIME_GET_MIN_VALUE(x) SUNXI_GET(x, SUNXI_MASK_SM, 8) ++#define SUNXI_TIME_GET_HOUR_VALUE(x) SUNXI_GET(x, SUNXI_MASK_DH, 16) ++ ++/* ++ * Get alarm values ++ */ ++#define SUNXI_ALRM_GET_SEC_VALUE(x) SUNXI_GET(x, SUNXI_MASK_SM, 0) ++#define SUNXI_ALRM_GET_MIN_VALUE(x) SUNXI_GET(x, SUNXI_MASK_SM, 8) ++#define SUNXI_ALRM_GET_HOUR_VALUE(x) SUNXI_GET(x, SUNXI_MASK_DH, 16) ++ ++/* ++ * Set date values ++ */ ++#define SUNXI_DATE_SET_DAY_VALUE(x) SUNXI_DATE_GET_DAY_VALUE(x) ++#define SUNXI_DATE_SET_MON_VALUE(x) SUNXI_SET(x, SUNXI_MASK_M, 8) ++#define SUNXI_DATE_SET_YEAR_VALUE(x, mask) SUNXI_SET(x, mask, 16) ++#define SUNXI_LEAP_SET_VALUE(x, shift) SUNXI_SET(x, SUNXI_MASK_LY, shift) ++ ++/* ++ * Set time values ++ */ ++#define SUNXI_TIME_SET_SEC_VALUE(x) SUNXI_TIME_GET_SEC_VALUE(x) ++#define SUNXI_TIME_SET_MIN_VALUE(x) SUNXI_SET(x, SUNXI_MASK_SM, 8) ++#define SUNXI_TIME_SET_HOUR_VALUE(x) SUNXI_SET(x, SUNXI_MASK_DH, 16) ++ ++/* ++ * Set alarm values ++ */ ++#define SUNXI_ALRM_SET_SEC_VALUE(x) SUNXI_ALRM_GET_SEC_VALUE(x) ++#define SUNXI_ALRM_SET_MIN_VALUE(x) SUNXI_SET(x, SUNXI_MASK_SM, 8) ++#define SUNXI_ALRM_SET_HOUR_VALUE(x) SUNXI_SET(x, SUNXI_MASK_DH, 16) ++#define SUNXI_ALRM_SET_DAY_VALUE(x) SUNXI_SET(x, SUNXI_MASK_D, 21) ++ ++/* ++ * Time unit conversions ++ */ ++#define SEC_IN_MIN 60 ++#define SEC_IN_HOUR (60 * SEC_IN_MIN) ++#define SEC_IN_DAY (24 * SEC_IN_HOUR) ++ ++/* ++ * The year parameter passed to the driver is usually an offset relative to ++ * the year 1900. This macro is used to convert this offset to another one ++ * relative to the minimum year allowed by the hardware. ++ */ ++#define SUNXI_YEAR_OFF(x) ((x)->min - 1900) ++ ++/* ++ * min and max year are arbitrary set considering the limited range of the ++ * hardware register field ++ */ ++struct sunxi_rtc_data_year { ++ unsigned int min; /* min year allowed */ ++ unsigned int max; /* max year allowed */ ++ unsigned int mask; /* mask for the year field */ ++ unsigned char leap_shift; /* bit shift to get the leap year */ ++}; ++ ++static struct sunxi_rtc_data_year data_year_param[] = { ++ [0] = { ++ .min = 2010, ++ .max = 2073, ++ .mask = 0x3f, ++ .leap_shift = 22, ++ }, ++ [1] = { ++ .min = 1970, ++ .max = 2225, ++ .mask = 0xff, ++ .leap_shift = 24, ++ }, ++}; ++ ++struct sunxi_rtc_dev { ++ struct rtc_device *rtc; ++ struct device *dev; ++ struct sunxi_rtc_data_year *data_year; ++ void __iomem *base; ++ int irq; ++}; ++ ++static irqreturn_t sunxi_rtc_alarmirq(int irq, void *id) ++{ ++ struct sunxi_rtc_dev *chip = (struct sunxi_rtc_dev *) id; ++ u32 val; ++ ++ val = readl(chip->base + SUNXI_ALRM_IRQ_STA); ++ ++ if (val & SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND) { ++ val |= SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND; ++ writel(val, chip->base + SUNXI_ALRM_IRQ_STA); ++ ++ rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF); ++ ++ return IRQ_HANDLED; ++ } ++ ++ return IRQ_NONE; ++} ++ ++static void sunxi_rtc_setaie(int to, struct sunxi_rtc_dev *chip) ++{ ++ u32 alrm_val = 0; ++ u32 alrm_irq_val = 0; ++ ++ if (to) { ++ alrm_val = readl(chip->base + SUNXI_ALRM_EN); ++ alrm_val |= SUNXI_ALRM_EN_CNT_EN; ++ ++ alrm_irq_val = readl(chip->base + SUNXI_ALRM_IRQ_EN); ++ alrm_irq_val |= SUNXI_ALRM_IRQ_EN_CNT_IRQ_EN; ++ } else { ++ writel(SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND, ++ chip->base + SUNXI_ALRM_IRQ_STA); ++ } ++ ++ writel(alrm_val, chip->base + SUNXI_ALRM_EN); ++ writel(alrm_irq_val, chip->base + SUNXI_ALRM_IRQ_EN); ++} ++ ++static int sunxi_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm) ++{ ++ struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); ++ struct rtc_time *alrm_tm = &wkalrm->time; ++ u32 alrm; ++ u32 alrm_en; ++ u32 date; ++ ++ alrm = readl(chip->base + SUNXI_ALRM_DHMS); ++ date = readl(chip->base + SUNXI_RTC_YMD); ++ ++ alrm_tm->tm_sec = SUNXI_ALRM_GET_SEC_VALUE(alrm); ++ alrm_tm->tm_min = SUNXI_ALRM_GET_MIN_VALUE(alrm); ++ alrm_tm->tm_hour = SUNXI_ALRM_GET_HOUR_VALUE(alrm); ++ ++ alrm_tm->tm_mday = SUNXI_DATE_GET_DAY_VALUE(date); ++ alrm_tm->tm_mon = SUNXI_DATE_GET_MON_VALUE(date); ++ alrm_tm->tm_year = SUNXI_DATE_GET_YEAR_VALUE(date, ++ chip->data_year->mask); ++ ++ alrm_tm->tm_mon -= 1; ++ ++ /* ++ * switch from (data_year->min)-relative offset to ++ * a (1900)-relative one ++ */ ++ alrm_tm->tm_year += SUNXI_YEAR_OFF(chip->data_year); ++ ++ alrm_en = readl(chip->base + SUNXI_ALRM_IRQ_EN); ++ if (alrm_en & SUNXI_ALRM_EN_CNT_EN) ++ wkalrm->enabled = 1; ++ ++ return 0; ++} ++ ++static int sunxi_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) ++{ ++ struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); ++ u32 date, time; ++ ++ /* ++ * read again in case it changes ++ */ ++ do { ++ date = readl(chip->base + SUNXI_RTC_YMD); ++ time = readl(chip->base + SUNXI_RTC_HMS); ++ } while ((date != readl(chip->base + SUNXI_RTC_YMD)) || ++ (time != readl(chip->base + SUNXI_RTC_HMS))); ++ ++ rtc_tm->tm_sec = SUNXI_TIME_GET_SEC_VALUE(time); ++ rtc_tm->tm_min = SUNXI_TIME_GET_MIN_VALUE(time); ++ rtc_tm->tm_hour = SUNXI_TIME_GET_HOUR_VALUE(time); ++ ++ rtc_tm->tm_mday = SUNXI_DATE_GET_DAY_VALUE(date); ++ rtc_tm->tm_mon = SUNXI_DATE_GET_MON_VALUE(date); ++ rtc_tm->tm_year = SUNXI_DATE_GET_YEAR_VALUE(date, ++ chip->data_year->mask); ++ ++ rtc_tm->tm_mon -= 1; ++ ++ /* ++ * switch from (data_year->min)-relative offset to ++ * a (1900)-relative one ++ */ ++ rtc_tm->tm_year += SUNXI_YEAR_OFF(chip->data_year); ++ ++ return rtc_valid_tm(rtc_tm); ++} ++ ++static int sunxi_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm) ++{ ++ struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); ++ struct rtc_time *alrm_tm = &wkalrm->time; ++ struct rtc_time tm_now; ++ u32 alrm = 0; ++ unsigned long time_now = 0; ++ unsigned long time_set = 0; ++ unsigned long time_gap = 0; ++ unsigned long time_gap_day = 0; ++ unsigned long time_gap_hour = 0; ++ unsigned long time_gap_min = 0; ++ int ret = 0; ++ ++ ret = sunxi_rtc_gettime(dev, &tm_now); ++ if (ret < 0) { ++ dev_err(dev, "Error in getting time\n"); ++ return -EINVAL; ++ } ++ ++ rtc_tm_to_time(alrm_tm, &time_set); ++ rtc_tm_to_time(&tm_now, &time_now); ++ if (time_set <= time_now) { ++ dev_err(dev, "Date to set in the past\n"); ++ return -EINVAL; ++ } ++ ++ time_gap = time_set - time_now; ++ time_gap_day = time_gap / SEC_IN_DAY; ++ time_gap -= time_gap_day * SEC_IN_DAY; ++ time_gap_hour = time_gap / SEC_IN_HOUR; ++ time_gap -= time_gap_hour * SEC_IN_HOUR; ++ time_gap_min = time_gap / SEC_IN_MIN; ++ time_gap -= time_gap_min * SEC_IN_MIN; ++ ++ if (time_gap_day > 255) { ++ dev_err(dev, "Day must be in the range 0 - 255\n"); ++ return -EINVAL; ++ } ++ ++ sunxi_rtc_setaie(0, chip); ++ writel(0, chip->base + SUNXI_ALRM_DHMS); ++ usleep_range(100, 300); ++ ++ alrm = SUNXI_ALRM_SET_SEC_VALUE(time_gap) | ++ SUNXI_ALRM_SET_MIN_VALUE(time_gap_min) | ++ SUNXI_ALRM_SET_HOUR_VALUE(time_gap_hour) | ++ SUNXI_ALRM_SET_DAY_VALUE(time_gap_day); ++ writel(alrm, chip->base + SUNXI_ALRM_DHMS); ++ ++ writel(0, chip->base + SUNXI_ALRM_IRQ_EN); ++ writel(SUNXI_ALRM_IRQ_EN_CNT_IRQ_EN, chip->base + SUNXI_ALRM_IRQ_EN); ++ ++ sunxi_rtc_setaie(wkalrm->enabled, chip); ++ ++ return 0; ++} ++ ++static int sunxi_rtc_wait(struct sunxi_rtc_dev *chip, int offset, ++ unsigned int mask, unsigned int ms_timeout) ++{ ++ const unsigned long timeout = jiffies + msecs_to_jiffies(ms_timeout); ++ u32 reg; ++ ++ do { ++ reg = readl(chip->base + offset); ++ reg &= mask; ++ ++ if (reg == mask) ++ return 0; ++ ++ } while (time_before(jiffies, timeout)); ++ ++ return -ETIMEDOUT; ++} ++ ++static int sunxi_rtc_settime(struct device *dev, struct rtc_time *rtc_tm) ++{ ++ struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); ++ u32 date = 0; ++ u32 time = 0; ++ int year; ++ ++ /* ++ * the input rtc_tm->tm_year is the offset relative to 1900. We use ++ * the SUNXI_YEAR_OFF macro to rebase it with respect to the min year ++ * allowed by the hardware ++ */ ++ ++ year = rtc_tm->tm_year + 1900; ++ if (year < chip->data_year->min || year > chip->data_year->max) { ++ dev_err(dev, "rtc only supports year in range %d - %d\n", ++ chip->data_year->min, chip->data_year->max); ++ return -EINVAL; ++ } ++ ++ rtc_tm->tm_year -= SUNXI_YEAR_OFF(chip->data_year); ++ rtc_tm->tm_mon += 1; ++ ++ date = SUNXI_DATE_SET_DAY_VALUE(rtc_tm->tm_mday) | ++ SUNXI_DATE_SET_MON_VALUE(rtc_tm->tm_mon) | ++ SUNXI_DATE_SET_YEAR_VALUE(rtc_tm->tm_year, ++ chip->data_year->mask); ++ ++ if (is_leap_year(year)) ++ date |= SUNXI_LEAP_SET_VALUE(1, chip->data_year->leap_shift); ++ ++ time = SUNXI_TIME_SET_SEC_VALUE(rtc_tm->tm_sec) | ++ SUNXI_TIME_SET_MIN_VALUE(rtc_tm->tm_min) | ++ SUNXI_TIME_SET_HOUR_VALUE(rtc_tm->tm_hour); ++ ++ writel(0, chip->base + SUNXI_RTC_HMS); ++ writel(0, chip->base + SUNXI_RTC_YMD); ++ ++ writel(time, chip->base + SUNXI_RTC_HMS); ++ ++ /* ++ * After writing the RTC HH-MM-SS register, the ++ * SUNXI_LOSC_CTRL_RTC_HMS_ACC bit is set and it will not ++ * be cleared until the real writing operation is finished ++ */ ++ ++ if (sunxi_rtc_wait(chip, SUNXI_LOSC_CTRL, ++ SUNXI_LOSC_CTRL_RTC_HMS_ACC, 50)) { ++ dev_err(dev, "Failed to set rtc time.\n"); ++ return -1; ++ } ++ ++ writel(date, chip->base + SUNXI_RTC_YMD); ++ ++ /* ++ * After writing the RTC YY-MM-DD register, the ++ * SUNXI_LOSC_CTRL_RTC_YMD_ACC bit is set and it will not ++ * be cleared until the real writing operation is finished ++ */ ++ ++ if (sunxi_rtc_wait(chip, SUNXI_LOSC_CTRL, ++ SUNXI_LOSC_CTRL_RTC_YMD_ACC, 50)) { ++ dev_err(dev, "Failed to set rtc time.\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int sunxi_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) ++{ ++ struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); ++ ++ if (!enabled) ++ sunxi_rtc_setaie(enabled, chip); ++ ++ return 0; ++} ++ ++static const struct rtc_class_ops sunxi_rtc_ops = { ++ .read_time = sunxi_rtc_gettime, ++ .set_time = sunxi_rtc_settime, ++ .read_alarm = sunxi_rtc_getalarm, ++ .set_alarm = sunxi_rtc_setalarm, ++ .alarm_irq_enable = sunxi_rtc_alarm_irq_enable ++}; ++ ++static const struct of_device_id sunxi_rtc_dt_ids[] = { ++ { .compatible = "allwinner,sun4i-rtc", .data = &data_year_param[0] }, ++ { .compatible = "allwinner,sun7i-a20-rtc", .data = &data_year_param[1] }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, sunxi_rtc_dt_ids); ++ ++static int sunxi_rtc_probe(struct platform_device *pdev) ++{ ++ struct sunxi_rtc_dev *chip; ++ struct resource *res; ++ const struct of_device_id *of_id; ++ int ret; ++ ++ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); ++ if (!chip) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, chip); ++ chip->dev = &pdev->dev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ chip->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(chip->base)) ++ return PTR_ERR(chip->base); ++ ++ chip->irq = platform_get_irq(pdev, 0); ++ if (chip->irq < 0) { ++ dev_err(&pdev->dev, "No IRQ resource\n"); ++ return chip->irq; ++ } ++ ret = devm_request_irq(&pdev->dev, chip->irq, sunxi_rtc_alarmirq, ++ 0, dev_name(&pdev->dev), chip); ++ if (ret) { ++ dev_err(&pdev->dev, "Could not request IRQ\n"); ++ return ret; ++ } ++ ++ of_id = of_match_device(sunxi_rtc_dt_ids, &pdev->dev); ++ if (!of_id) { ++ dev_err(&pdev->dev, "Unable to setup RTC data\n"); ++ return -ENODEV; ++ } ++ chip->data_year = (struct sunxi_rtc_data_year *) of_id->data; ++ ++ /* clear the alarm count value */ ++ writel(0, chip->base + SUNXI_ALRM_DHMS); ++ ++ /* disable alarm, not generate irq pending */ ++ writel(0, chip->base + SUNXI_ALRM_EN); ++ ++ /* disable alarm week/cnt irq, unset to cpu */ ++ writel(0, chip->base + SUNXI_ALRM_IRQ_EN); ++ ++ /* clear alarm week/cnt irq pending */ ++ writel(SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND, chip->base + ++ SUNXI_ALRM_IRQ_STA); ++ ++ chip->rtc = rtc_device_register("rtc-sunxi", &pdev->dev, ++ &sunxi_rtc_ops, THIS_MODULE); ++ if (IS_ERR(chip->rtc)) { ++ dev_err(&pdev->dev, "unable to register device\n"); ++ return PTR_ERR(chip->rtc); ++ } ++ ++ dev_info(&pdev->dev, "RTC enabled\n"); ++ ++ return 0; ++} ++ ++static int sunxi_rtc_remove(struct platform_device *pdev) ++{ ++ struct sunxi_rtc_dev *chip = platform_get_drvdata(pdev); ++ ++ rtc_device_unregister(chip->rtc); ++ ++ return 0; ++} ++ ++static struct platform_driver sunxi_rtc_driver = { ++ .probe = sunxi_rtc_probe, ++ .remove = sunxi_rtc_remove, ++ .driver = { ++ .name = "sunxi-rtc", ++ .owner = THIS_MODULE, ++ .of_match_table = sunxi_rtc_dt_ids, ++ }, ++}; ++ ++module_platform_driver(sunxi_rtc_driver); ++ ++MODULE_DESCRIPTION("sunxi RTC driver"); ++MODULE_AUTHOR("Carlo Caione <carlo.caione@gmail.com>"); ++MODULE_LICENSE("GPL"); +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/141-dt-sun47i-add-rtc.patch b/target/linux/sunxi/patches-3.13/141-dt-sun47i-add-rtc.patch new file mode 100644 index 0000000000..63de19bff1 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/141-dt-sun47i-add-rtc.patch @@ -0,0 +1,51 @@ +From b15b9f68606134222f7aff5120c8ef70ffab92b8 Mon Sep 17 00:00:00 2001 +From: Carlo Caione <carlo.caione@gmail.com> +Date: Wed, 16 Oct 2013 20:30:26 +0200 +Subject: [PATCH] ARM: dts: sun4i/sun7i: add RTC node + +Add the RTC node to DTS for Allwinner A10 and Allwinner A20. + +Signed-off-by: Carlo Caione <carlo.caione@gmail.com> +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + arch/arm/boot/dts/sun4i-a10.dtsi | 6 ++++++ + arch/arm/boot/dts/sun7i-a20.dtsi | 6 ++++++ + 2 files changed, 12 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi +index 319cc6b..f11f292 100644 +--- a/arch/arm/boot/dts/sun4i-a10.dtsi ++++ b/arch/arm/boot/dts/sun4i-a10.dtsi +@@ -266,6 +266,12 @@ + reg = <0x01c20c90 0x10>; + }; + ++ rtc: rtc@01c20d00 { ++ compatible = "allwinner,sun4i-rtc"; ++ reg = <0x01c20d00 0x20>; ++ interrupts = <24>; ++ }; ++ + sid: eeprom@01c23800 { + compatible = "allwinner,sun4i-sid"; + reg = <0x01c23800 0x10>; +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 367611a..cc3683c 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -265,6 +265,12 @@ + reg = <0x01c20c90 0x10>; + }; + ++ rtc: rtc@01c20d00 { ++ compatible = "allwinner,sun7i-a20-rtc"; ++ reg = <0x01c20d00 0x20>; ++ interrupts = <0 24 1>; ++ }; ++ + sid: eeprom@01c23800 { + compatible = "allwinner,sun7i-a20-sid"; + reg = <0x01c23800 0x200>; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/145-clksrc-add-hstimer.patch b/target/linux/sunxi/patches-3.13/145-clksrc-add-hstimer.patch new file mode 100644 index 0000000000..db54eb8f8b --- /dev/null +++ b/target/linux/sunxi/patches-3.13/145-clksrc-add-hstimer.patch @@ -0,0 +1,297 @@ +From 3bf30f6381f9287eb99ce096bf2fa327a69c8a71 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Thu, 7 Nov 2013 12:01:48 +0100 +Subject: [PATCH] clocksource: Add Allwinner SoCs HS timers driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Most of the Allwinner SoCs (at this time, all but the A10) also have a +High Speed timers that are not using the 24MHz oscillator as a source +but rather the AHB clock running much faster. + +The IP is slightly different between the A10s/A13 and the one used in +the A20/A31, since the latter have 4 timers available, while the former +have only 2 of them. + +[dlezcano] : Fixed conflict with b788beda "Order Kconfig options + alphabetically" + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +Tested-by: Emilio López <emilio@elopez.com.ar> +Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org> +--- + .../bindings/timer/allwinner,sun5i-a13-hstimer.txt | 22 +++ + arch/arm/mach-sunxi/Kconfig | 1 + + drivers/clocksource/Kconfig | 4 + + drivers/clocksource/Makefile | 1 + + drivers/clocksource/timer-sun5i.c | 192 +++++++++++++++++++++ + 5 files changed, 220 insertions(+) + create mode 100644 Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt + create mode 100644 drivers/clocksource/timer-sun5i.c + +diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt +new file mode 100644 +index 0000000..7c26154 +--- /dev/null ++++ b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt +@@ -0,0 +1,22 @@ ++Allwinner SoCs High Speed Timer Controller ++ ++Required properties: ++ ++- compatible : should be "allwinner,sun5i-a13-hstimer" or ++ "allwinner,sun7i-a20-hstimer" ++- reg : Specifies base physical address and size of the registers. ++- interrupts : The interrupts of these timers (2 for the sun5i IP, 4 for the sun7i ++ one) ++- clocks: phandle to the source clock (usually the AHB clock) ++ ++Example: ++ ++timer@01c60000 { ++ compatible = "allwinner,sun7i-a20-hstimer"; ++ reg = <0x01c60000 0x1000>; ++ interrupts = <0 51 1>, ++ <0 52 1>, ++ <0 53 1>, ++ <0 54 1>; ++ clocks = <&ahb1_gates 19>; ++}; +diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig +index e3457b9..547004c 100644 +--- a/arch/arm/mach-sunxi/Kconfig ++++ b/arch/arm/mach-sunxi/Kconfig +@@ -13,3 +13,4 @@ config ARCH_SUNXI + select PINCTRL_SUNXI + select SPARSE_IRQ + select SUN4I_TIMER ++ select SUN5I_HSTIMER +diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig +index 634c4d6..cd6950f 100644 +--- a/drivers/clocksource/Kconfig ++++ b/drivers/clocksource/Kconfig +@@ -37,6 +37,10 @@ config SUN4I_TIMER + select CLKSRC_MMIO + bool + ++config SUN5I_HSTIMER ++ select CLKSRC_MMIO ++ bool ++ + config VT8500_TIMER + bool + +diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile +index 33621ef..358358d 100644 +--- a/drivers/clocksource/Makefile ++++ b/drivers/clocksource/Makefile +@@ -22,6 +22,7 @@ obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o + obj-$(CONFIG_ARCH_MXS) += mxs_timer.o + obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o + obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o ++obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o + obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o + obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o + obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o +diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c +new file mode 100644 +index 0000000..bddc522 +--- /dev/null ++++ b/drivers/clocksource/timer-sun5i.c +@@ -0,0 +1,192 @@ ++/* ++ * Allwinner SoCs hstimer driver. ++ * ++ * Copyright (C) 2013 Maxime Ripard ++ * ++ * Maxime Ripard <maxime.ripard@free-electrons.com> ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include <linux/clk.h> ++#include <linux/clockchips.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/irq.h> ++#include <linux/irqreturn.h> ++#include <linux/sched_clock.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/of_irq.h> ++ ++#define TIMER_IRQ_EN_REG 0x00 ++#define TIMER_IRQ_EN(val) BIT(val) ++#define TIMER_IRQ_ST_REG 0x04 ++#define TIMER_CTL_REG(val) (0x20 * (val) + 0x10) ++#define TIMER_CTL_ENABLE BIT(0) ++#define TIMER_CTL_RELOAD BIT(1) ++#define TIMER_CTL_CLK_PRES(val) (((val) & 0x7) << 4) ++#define TIMER_CTL_ONESHOT BIT(7) ++#define TIMER_INTVAL_LO_REG(val) (0x20 * (val) + 0x14) ++#define TIMER_INTVAL_HI_REG(val) (0x20 * (val) + 0x18) ++#define TIMER_CNTVAL_LO_REG(val) (0x20 * (val) + 0x1c) ++#define TIMER_CNTVAL_HI_REG(val) (0x20 * (val) + 0x20) ++ ++#define TIMER_SYNC_TICKS 3 ++ ++static void __iomem *timer_base; ++static u32 ticks_per_jiffy; ++ ++/* ++ * When we disable a timer, we need to wait at least for 2 cycles of ++ * the timer source clock. We will use for that the clocksource timer ++ * that is already setup and runs at the same frequency than the other ++ * timers, and we never will be disabled. ++ */ ++static void sun5i_clkevt_sync(void) ++{ ++ u32 old = readl(timer_base + TIMER_CNTVAL_LO_REG(1)); ++ ++ while ((old - readl(timer_base + TIMER_CNTVAL_LO_REG(1))) < TIMER_SYNC_TICKS) ++ cpu_relax(); ++} ++ ++static void sun5i_clkevt_time_stop(u8 timer) ++{ ++ u32 val = readl(timer_base + TIMER_CTL_REG(timer)); ++ writel(val & ~TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(timer)); ++ ++ sun5i_clkevt_sync(); ++} ++ ++static void sun5i_clkevt_time_setup(u8 timer, u32 delay) ++{ ++ writel(delay, timer_base + TIMER_INTVAL_LO_REG(timer)); ++} ++ ++static void sun5i_clkevt_time_start(u8 timer, bool periodic) ++{ ++ u32 val = readl(timer_base + TIMER_CTL_REG(timer)); ++ ++ if (periodic) ++ val &= ~TIMER_CTL_ONESHOT; ++ else ++ val |= TIMER_CTL_ONESHOT; ++ ++ writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, ++ timer_base + TIMER_CTL_REG(timer)); ++} ++ ++static void sun5i_clkevt_mode(enum clock_event_mode mode, ++ struct clock_event_device *clk) ++{ ++ switch (mode) { ++ case CLOCK_EVT_MODE_PERIODIC: ++ sun5i_clkevt_time_stop(0); ++ sun5i_clkevt_time_setup(0, ticks_per_jiffy); ++ sun5i_clkevt_time_start(0, true); ++ break; ++ case CLOCK_EVT_MODE_ONESHOT: ++ sun5i_clkevt_time_stop(0); ++ sun5i_clkevt_time_start(0, false); ++ break; ++ case CLOCK_EVT_MODE_UNUSED: ++ case CLOCK_EVT_MODE_SHUTDOWN: ++ default: ++ sun5i_clkevt_time_stop(0); ++ break; ++ } ++} ++ ++static int sun5i_clkevt_next_event(unsigned long evt, ++ struct clock_event_device *unused) ++{ ++ sun5i_clkevt_time_stop(0); ++ sun5i_clkevt_time_setup(0, evt - TIMER_SYNC_TICKS); ++ sun5i_clkevt_time_start(0, false); ++ ++ return 0; ++} ++ ++static struct clock_event_device sun5i_clockevent = { ++ .name = "sun5i_tick", ++ .rating = 340, ++ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, ++ .set_mode = sun5i_clkevt_mode, ++ .set_next_event = sun5i_clkevt_next_event, ++}; ++ ++ ++static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id) ++{ ++ struct clock_event_device *evt = (struct clock_event_device *)dev_id; ++ ++ writel(0x1, timer_base + TIMER_IRQ_ST_REG); ++ evt->event_handler(evt); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction sun5i_timer_irq = { ++ .name = "sun5i_timer0", ++ .flags = IRQF_TIMER | IRQF_IRQPOLL, ++ .handler = sun5i_timer_interrupt, ++ .dev_id = &sun5i_clockevent, ++}; ++ ++static u32 sun5i_timer_sched_read(void) ++{ ++ return ~readl(timer_base + TIMER_CNTVAL_LO_REG(1)); ++} ++ ++static void __init sun5i_timer_init(struct device_node *node) ++{ ++ unsigned long rate; ++ struct clk *clk; ++ int ret, irq; ++ u32 val; ++ ++ timer_base = of_iomap(node, 0); ++ if (!timer_base) ++ panic("Can't map registers"); ++ ++ irq = irq_of_parse_and_map(node, 0); ++ if (irq <= 0) ++ panic("Can't parse IRQ"); ++ ++ clk = of_clk_get(node, 0); ++ if (IS_ERR(clk)) ++ panic("Can't get timer clock"); ++ clk_prepare_enable(clk); ++ rate = clk_get_rate(clk); ++ ++ writel(~0, timer_base + TIMER_INTVAL_LO_REG(1)); ++ writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, ++ timer_base + TIMER_CTL_REG(1)); ++ ++ setup_sched_clock(sun5i_timer_sched_read, 32, rate); ++ clocksource_mmio_init(timer_base + TIMER_CNTVAL_LO_REG(1), node->name, ++ rate, 340, 32, clocksource_mmio_readl_down); ++ ++ ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); ++ ++ ret = setup_irq(irq, &sun5i_timer_irq); ++ if (ret) ++ pr_warn("failed to setup irq %d\n", irq); ++ ++ /* Enable timer0 interrupt */ ++ val = readl(timer_base + TIMER_IRQ_EN_REG); ++ writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG); ++ ++ sun5i_clockevent.cpumask = cpu_possible_mask; ++ sun5i_clockevent.irq = irq; ++ ++ clockevents_config_and_register(&sun5i_clockevent, rate, ++ TIMER_SYNC_TICKS, 0xffffffff); ++} ++CLOCKSOURCE_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer", ++ sun5i_timer_init); ++CLOCKSOURCE_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer", ++ sun5i_timer_init); +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/146-1-dt-sun5i-a10s-add-hstimer.patch b/target/linux/sunxi/patches-3.13/146-1-dt-sun5i-a10s-add-hstimer.patch new file mode 100644 index 0000000000..afdaa5a248 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/146-1-dt-sun5i-a10s-add-hstimer.patch @@ -0,0 +1,38 @@ +From 5ace5467690055b1772dcac69dd1377735b8a34b Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Thu, 7 Nov 2013 12:01:48 +0100 +Subject: [PATCH] ARM: sun5i: a10s: Add support for the High Speed Timers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The Allwinner A10s has support for two high speed timers. Now that we +have a driver to support it, we can enable them in the device tree. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +Tested-by: Emilio López <emilio@elopez.com.ar> +Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org> +--- + arch/arm/boot/dts/sun5i-a10s.dtsi | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi +index b4764be..924a2c1 100644 +--- a/arch/arm/boot/dts/sun5i-a10s.dtsi ++++ b/arch/arm/boot/dts/sun5i-a10s.dtsi +@@ -336,5 +336,12 @@ + clock-frequency = <100000>; + status = "disabled"; + }; ++ ++ timer@01c60000 { ++ compatible = "allwinner,sun5i-a13-hstimer"; ++ reg = <0x01c60000 0x1000>; ++ interrupts = <82>, <83>; ++ clocks = <&ahb_gates 28>; ++ }; + }; + }; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/146-2-dt-sun5i-a13-add-hstimer.patch b/target/linux/sunxi/patches-3.13/146-2-dt-sun5i-a13-add-hstimer.patch new file mode 100644 index 0000000000..b209b125fe --- /dev/null +++ b/target/linux/sunxi/patches-3.13/146-2-dt-sun5i-a13-add-hstimer.patch @@ -0,0 +1,38 @@ +From 22a3eff19679e0e592e061201690670a2f5fdba7 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Thu, 7 Nov 2013 12:01:48 +0100 +Subject: [PATCH] ARM: sun5i: a13: Add support for the High Speed Timers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The Allwinner A13 has support for two high speed timers. Now that we +have a driver to support it, we can enable them in the device tree. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +Tested-by: Emilio López <emilio@elopez.com.ar> +Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org> +--- + arch/arm/boot/dts/sun5i-a13.dtsi | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi +index ce8ef2a..1ccd75d 100644 +--- a/arch/arm/boot/dts/sun5i-a13.dtsi ++++ b/arch/arm/boot/dts/sun5i-a13.dtsi +@@ -273,5 +273,12 @@ + clock-frequency = <100000>; + status = "disabled"; + }; ++ ++ timer@01c60000 { ++ compatible = "allwinner,sun5i-a13-hstimer"; ++ reg = <0x01c60000 0x1000>; ++ interrupts = <82>, <83>; ++ clocks = <&ahb_gates 28>; ++ }; + }; + }; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/146-3-dt-sun7i-a20-add-hstimer.patch b/target/linux/sunxi/patches-3.13/146-3-dt-sun7i-a20-add-hstimer.patch new file mode 100644 index 0000000000..7112ff0bce --- /dev/null +++ b/target/linux/sunxi/patches-3.13/146-3-dt-sun7i-a20-add-hstimer.patch @@ -0,0 +1,48 @@ +From 6c23e1fa6bd220b8f5665c150c83d4c016d95482 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Thu, 7 Nov 2013 12:01:48 +0100 +Subject: [PATCH] ARM: sun7i: a20: Add support for the High Speed Timers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The Allwinner A20 has support for four high speed timers. Apart for the +number of timers (4 vs 2), it's basically the same logic than the high +speed timers found in the sun5i chips. + +Now that we have a driver to support it, we can enable them in the +device tree. + +[dlezcano] : Fixed conflict with 428abbb8 "Enable the I2C controllers" + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +Tested-by: Emilio López <emilio@elopez.com.ar> +Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org> +--- + arch/arm/boot/dts/sun7i-a20.dtsi | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 93f7f96..c74147a 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -405,6 +405,16 @@ + status = "disabled"; + }; + ++ hstimer@01c60000 { ++ compatible = "allwinner,sun7i-a20-hstimer"; ++ reg = <0x01c60000 0x1000>; ++ interrupts = <0 81 1>, ++ <0 82 1>, ++ <0 83 1>, ++ <0 84 1>; ++ clocks = <&ahb_gates 28>; ++ }; ++ + gic: interrupt-controller@01c81000 { + compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x01c81000 0x1000>, +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/150-1-clk-sunxi-implement-mmc-phasectrl.patch b/target/linux/sunxi/patches-3.13/150-1-clk-sunxi-implement-mmc-phasectrl.patch new file mode 100644 index 0000000000..69586c4388 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/150-1-clk-sunxi-implement-mmc-phasectrl.patch @@ -0,0 +1,62 @@ +From 4f43ab43125a12dbc23e352ac0eb4fd80a876fb5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar> +Date: Fri, 20 Sep 2013 20:29:17 -0300 +Subject: [PATCH] clk: sunxi: Implement MMC phase control +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Emilio López <emilio@elopez.com.ar> +--- + drivers/clk/sunxi/clk-sunxi.c | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 625089b..6d3286a 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -361,6 +361,41 @@ static void sun4i_get_mod0_factors(u32 *freq, u32 parent_rate, + + + /** ++ * clk_sunxi_mmc_phase_control() - configures MMC clock phase control ++ */ ++ ++void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output) ++{ ++ #define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw) ++ #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) ++ ++ struct clk_composite *composite = to_clk_composite(hw); ++ struct clk_hw *rate_hw = composite->rate_hw; ++ struct clk_factors *factors = to_clk_factors(rate_hw); ++ unsigned long flags = 0; ++ u32 reg; ++ ++ if (factors->lock) ++ spin_lock_irqsave(factors->lock, flags); ++ ++ reg = readl(factors->reg); ++ ++ /* set sample clock phase control */ ++ reg &= ~(0x7 << 20); ++ reg |= ((sample & 0x7) << 20); ++ ++ /* set output clock phase control */ ++ reg &= ~(0x7 << 8); ++ reg |= ((output & 0x7) << 8); ++ ++ writel(reg, factors->reg); ++ ++ if (factors->lock) ++ spin_unlock_irqrestore(factors->lock, flags); ++} ++ ++ ++/** + * sunxi_factors_clk_setup() - Setup function for factor clocks + */ + +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/150-2-clk-sunxi-export-func.patch b/target/linux/sunxi/patches-3.13/150-2-clk-sunxi-export-func.patch new file mode 100644 index 0000000000..59c884954c --- /dev/null +++ b/target/linux/sunxi/patches-3.13/150-2-clk-sunxi-export-func.patch @@ -0,0 +1,42 @@ +From a8cfe8ebdb18e6724b6520e08602b8e72e762ab9 Mon Sep 17 00:00:00 2001 +From: Hans de Goede <hdegoede@redhat.com> +Date: Sun, 15 Dec 2013 19:44:01 +0100 +Subject: [PATCH] ARM: sunxi: clk: export clk_sunxi_mmc_phase_control + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + include/linux/clk/sunxi.h | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + create mode 100644 include/linux/clk/sunxi.h + +diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h +new file mode 100644 +index 0000000..1ef5c89 +--- /dev/null ++++ b/include/linux/clk/sunxi.h +@@ -0,0 +1,22 @@ ++/* ++ * Copyright 2013 - Hans de Goede <hdegoede@redhat.com> ++ * ++ * 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 __LINUX_CLK_SUNXI_H_ ++#define __LINUX_CLK_SUNXI_H_ ++ ++#include <linux/clk.h> ++ ++void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output); ++ ++#endif +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/151-pinctrl-sun5i-a13-port-F.patch b/target/linux/sunxi/patches-3.13/151-pinctrl-sun5i-a13-port-F.patch new file mode 100644 index 0000000000..cbd3194751 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/151-pinctrl-sun5i-a13-port-F.patch @@ -0,0 +1,56 @@ +From 33b0123664b627005728cfe7b1967b790392ceec Mon Sep 17 00:00:00 2001 +From: Hans de Goede <hdegoede@redhat.com> +Date: Sat, 14 Dec 2013 17:20:13 +0100 +Subject: [PATCH] ARM: sunxi: fix sun5i-a13 port F multiplexing + +The correct value for selecting the mmc0 function on port F pins is 2 not 4, +as per the data-sheet: +http://dl.linux-sunxi.org/A13/A13%20Datasheet%20-%20v1.12%20%282012-03-29%29.pdf + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + drivers/pinctrl/pinctrl-sunxi-pins.h | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-sunxi-pins.h b/drivers/pinctrl/pinctrl-sunxi-pins.h +index 2c7446a..7c1b05e 100644 +--- a/drivers/pinctrl/pinctrl-sunxi-pins.h ++++ b/drivers/pinctrl/pinctrl-sunxi-pins.h +@@ -1932,27 +1932,27 @@ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), +- SUNXI_FUNCTION(0x4, "mmc0")), /* D1 */ ++ SUNXI_FUNCTION(0x2, "mmc0")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), +- SUNXI_FUNCTION(0x4, "mmc0")), /* D0 */ ++ SUNXI_FUNCTION(0x2, "mmc0")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), +- SUNXI_FUNCTION(0x4, "mmc0")), /* CLK */ ++ SUNXI_FUNCTION(0x2, "mmc0")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), +- SUNXI_FUNCTION(0x4, "mmc0")), /* CMD */ ++ SUNXI_FUNCTION(0x2, "mmc0")), /* CMD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), +- SUNXI_FUNCTION(0x4, "mmc0")), /* D3 */ ++ SUNXI_FUNCTION(0x2, "mmc0")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), +- SUNXI_FUNCTION(0x4, "mmc0")), /* D2 */ ++ SUNXI_FUNCTION(0x2, "mmc0")), /* D2 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0, + SUNXI_FUNCTION(0x0, "gpio_in"), +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/152-sunxi-mmc-add-Kconfig.patch b/target/linux/sunxi/patches-3.13/152-sunxi-mmc-add-Kconfig.patch new file mode 100644 index 0000000000..c3cb13d43d --- /dev/null +++ b/target/linux/sunxi/patches-3.13/152-sunxi-mmc-add-Kconfig.patch @@ -0,0 +1,55 @@ +From 447675f817b95881e9922f002de3fc7f6d6e9207 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?David=20Lanzend=C3=B6rfer?= <david.lanzendoerfer@o2s.ch> +Date: Fri, 6 Sep 2013 22:34:33 +0200 +Subject: [PATCH] ARM: sunxi-mci: Add driver for SD/MMC hosts found within + Allwinner A1X SoCs + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + drivers/mmc/host/Kconfig | 8 + + drivers/mmc/host/Makefile | 2 + + drivers/mmc/host/sunxi-mci.c | 1056 ++++++++++++++++++++++++++++++++++++++++++ + drivers/mmc/host/sunxi-mci.h | 334 +++++++++++++ + 4 files changed, 1400 insertions(+) + create mode 100644 drivers/mmc/host/sunxi-mci.c + create mode 100644 drivers/mmc/host/sunxi-mci.h + +diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig +index 7fc5099..0df0322 100644 +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -665,3 +665,11 @@ config MMC_REALTEK_PCI + help + Say Y here to include driver code to support SD/MMC card interface + of Realtek PCI-E card reader ++ ++config MMC_SUNXI ++ tristate "Allwinner A1X SD/MMC Host Controller support" ++ depends on ARCH_SUNXI ++ default y ++ help ++ This selects support for the SD/MMC Host Controller on ++ Allwinner A1X based SoCs. +diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile +index c41d0c3..f76f783 100644 +--- a/drivers/mmc/host/Makefile ++++ b/drivers/mmc/host/Makefile +@@ -52,6 +52,8 @@ obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o + + obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o + ++obj-$(CONFIG_MMC_SUNXI) += sunxi-mci.o ++ + obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o + obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o + obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o +diff --git a/drivers/mmc/host/sunxi-mci.c b/drivers/mmc/host/sunxi-mci.c +new file mode 100644 +index 0000000..cbde1d3 +diff --git a/drivers/mmc/host/sunxi-mci.h b/drivers/mmc/host/sunxi-mci.h +new file mode 100644 +index 0000000..0f5f95c +\ No newline at end of file +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/153-1-dt-sun4i-add-mmc.patch b/target/linux/sunxi/patches-3.13/153-1-dt-sun4i-add-mmc.patch new file mode 100644 index 0000000000..bcc323fada --- /dev/null +++ b/target/linux/sunxi/patches-3.13/153-1-dt-sun4i-add-mmc.patch @@ -0,0 +1,106 @@ +From 677631fa522e4ac24f636535e3abb5cd1a5ef40e Mon Sep 17 00:00:00 2001 +From: Hans de Goede <hdegoede@redhat.com> +Date: Sat, 14 Dec 2013 22:58:12 +0100 +Subject: [PATCH] ARM: dts: sun4i: Add support for mmc + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun4i-a10-a1000.dts | 16 ++++++++++++++++ + arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 16 ++++++++++++++++ + arch/arm/boot/dts/sun4i-a10.dtsi | 17 +++++++++++++++++ + 3 files changed, 49 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts +index eb4d73b..aef8207 100644 +--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts ++++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts +@@ -39,7 +39,23 @@ + }; + }; + ++ mmc0: mmc@01c0f000 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc0_pins_a>; ++ pinctrl-1 = <&mmc0_cd_pin_a1000>; ++ cd-gpios = <&pio 7 1 0>; /* PH1 */ ++ cd-mode = <1>; ++ status = "okay"; ++ }; ++ + pinctrl@01c20800 { ++ mmc0_cd_pin_a1000: mmc0_cd_pin@0 { ++ allwinner,pins = "PH1"; ++ allwinner,function = "gpio_in"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ + emac_power_pin_a1000: emac_power_pin@0 { + allwinner,pins = "PH15"; + allwinner,function = "gpio_out"; +diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts +index 425a7db..f50fb2b 100644 +--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts ++++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts +@@ -42,7 +42,23 @@ + }; + }; + ++ mmc0: mmc@01c0f000 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc0_pins_a>; ++ pinctrl-1 = <&mmc0_cd_pin_cubieboard>; ++ cd-gpios = <&pio 7 1 0>; /* PH1 */ ++ cd-mode = <1>; ++ status = "okay"; ++ }; ++ + pinctrl@01c20800 { ++ mmc0_cd_pin_cubieboard: mmc0_cd_pin@0 { ++ allwinner,pins = "PH1"; ++ allwinner,function = "gpio_in"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ + led_pins_cubieboard: led_pins@0 { + allwinner,pins = "PH20", "PH21"; + allwinner,function = "gpio_out"; +diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi +index 9779c6b..4736dd2 100644 +--- a/arch/arm/boot/dts/sun4i-a10.dtsi ++++ b/arch/arm/boot/dts/sun4i-a10.dtsi +@@ -321,6 +321,16 @@ + #size-cells = <0>; + }; + ++ mmc0: mmc@01c0f000 { ++ compatible = "allwinner,sun4i-a10-mmc"; ++ reg = <0x01c0f000 0x1000>; ++ clocks = <&ahb_gates 8>, <&mmc0_clk>; ++ clock-names = "ahb", "mod"; ++ interrupts = <32>; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ + intc: interrupt-controller@01c20400 { + compatible = "allwinner,sun4i-ic"; + reg = <0x01c20400 0x400>; +@@ -391,6 +401,13 @@ + allwinner,drive = <0>; + allwinner,pull = <0>; + }; ++ ++ mmc0_pins_a: mmc0@0 { ++ allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5"; ++ allwinner,function = "mmc0"; ++ allwinner,drive = <3>; ++ allwinner,pull = <0>; ++ }; + }; + + timer@01c20c00 { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/153-2-dt-sun5i-add-mmc.patch b/target/linux/sunxi/patches-3.13/153-2-dt-sun5i-add-mmc.patch new file mode 100644 index 0000000000..48d8f850a7 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/153-2-dt-sun5i-add-mmc.patch @@ -0,0 +1,204 @@ +From 48332fd7217cf5b06b438503513e54e6138e0637 Mon Sep 17 00:00:00 2001 +From: Hans de Goede <hdegoede@redhat.com> +Date: Sat, 14 Dec 2013 22:58:14 +0100 +Subject: [PATCH] ARM: dts: sun5i: Add support for mmc + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts | 32 ++++++++++++++++++++++ + arch/arm/boot/dts/sun5i-a10s.dtsi | 34 ++++++++++++++++++++++++ + arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts | 16 +++++++++++ + arch/arm/boot/dts/sun5i-a13-olinuxino.dts | 16 +++++++++++ + arch/arm/boot/dts/sun5i-a13.dtsi | 17 ++++++++++++ + 5 files changed, 115 insertions(+) + +diff --git a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts +index 3c9f8b3..e47a731 100644 +--- a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts ++++ b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts +@@ -34,7 +34,39 @@ + }; + }; + ++ mmc0: mmc@01c0f000 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc0_pins_a>; ++ pinctrl-1 = <&mmc0_cd_pin_olinuxino_micro>; ++ cd-gpios = <&pio 6 1 0>; /* PG1 */ ++ cd-mode = <1>; ++ status = "okay"; ++ }; ++ ++ mmc1: mmc@01c10000 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc1_pins_a>; ++ pinctrl-1 = <&mmc1_cd_pin_olinuxino_micro>; ++ cd-gpios = <&pio 6 13 0>; /* PG13 */ ++ cd-mode = <1>; ++ status = "okay"; ++ }; ++ + pinctrl@01c20800 { ++ mmc0_cd_pin_olinuxino_micro: mmc0_cd_pin@0 { ++ allwinner,pins = "PG1"; ++ allwinner,function = "gpio_in"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ ++ mmc1_cd_pin_olinuxino_micro: mmc1_cd_pin@0 { ++ allwinner,pins = "PG13"; ++ allwinner,function = "gpio_in"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ + led_pins_olinuxino: led_pins@0 { + allwinner,pins = "PE3"; + allwinner,function = "gpio_out"; +diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi +index c42ed2a..c3bb9bd 100644 +--- a/arch/arm/boot/dts/sun5i-a10s.dtsi ++++ b/arch/arm/boot/dts/sun5i-a10s.dtsi +@@ -286,6 +286,26 @@ + #size-cells = <0>; + }; + ++ mmc0: mmc@01c0f000 { ++ compatible = "allwinner,sun5i-a13-mmc"; ++ reg = <0x01c0f000 0x1000>; ++ clocks = <&ahb_gates 8>, <&mmc0_clk>; ++ clock-names = "ahb", "mod"; ++ interrupts = <32>; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ ++ mmc1: mmc@01c10000 { ++ compatible = "allwinner,sun5i-a13-mmc"; ++ reg = <0x01c10000 0x1000>; ++ clocks = <&ahb_gates 9>, <&mmc1_clk>; ++ clock-names = "ahb", "mod"; ++ interrupts = <33>; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ + intc: interrupt-controller@01c20400 { + compatible = "allwinner,sun4i-ic"; + reg = <0x01c20400 0x400>; +@@ -356,6 +376,20 @@ + allwinner,drive = <0>; + allwinner,pull = <0>; + }; ++ ++ mmc0_pins_a: mmc0@0 { ++ allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5"; ++ allwinner,function = "mmc0"; ++ allwinner,drive = <3>; ++ allwinner,pull = <0>; ++ }; ++ ++ mmc1_pins_a: mmc1@0 { ++ allwinner,pins = "PG3","PG4","PG5","PG6","PG7","PG8"; ++ allwinner,function = "mmc1"; ++ allwinner,drive = <3>; ++ allwinner,pull = <0>; ++ }; + }; + + timer@01c20c00 { +diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts +index fe2ce0a..37ec3d9 100644 +--- a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts ++++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts +@@ -20,7 +20,23 @@ + compatible = "olimex,a13-olinuxino-micro", "allwinner,sun5i-a13"; + + soc@01c00000 { ++ mmc0: mmc@01c0f000 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc0_pins_a>; ++ pinctrl-1 = <&mmc0_cd_pin_olinuxinom>; ++ cd-gpios = <&pio 6 0 0>; /* PG0 */ ++ cd-mode = <1>; ++ status = "okay"; ++ }; ++ + pinctrl@01c20800 { ++ mmc0_cd_pin_olinuxinom: mmc0_cd_pin@0 { ++ allwinner,pins = "PG0"; ++ allwinner,function = "gpio_in"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ + led_pins_olinuxinom: led_pins@0 { + allwinner,pins = "PG9"; + allwinner,function = "gpio_out"; +diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts +index 9e508dc..cf77d9a 100644 +--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts ++++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts +@@ -23,7 +23,23 @@ + }; + + soc@01c00000 { ++ mmc0: mmc@01c0f000 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc0_pins_a>; ++ pinctrl-1 = <&mmc0_cd_pin_olinuxino>; ++ cd-gpios = <&pio 6 0 0>; /* PG0 */ ++ cd-mode = <1>; ++ status = "okay"; ++ }; ++ + pinctrl@01c20800 { ++ mmc0_cd_pin_olinuxino: mmc0_cd_pin@0 { ++ allwinner,pins = "PG0"; ++ allwinner,function = "gpio_in"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ + led_pins_olinuxino: led_pins@0 { + allwinner,pins = "PG9"; + allwinner,function = "gpio_out"; +diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi +index 8274a41..2dde48a 100644 +--- a/arch/arm/boot/dts/sun5i-a13.dtsi ++++ b/arch/arm/boot/dts/sun5i-a13.dtsi +@@ -267,6 +267,16 @@ + #size-cells = <1>; + ranges; + ++ mmc0: mmc@01c0f000 { ++ compatible = "allwinner,sun5i-a13-mmc"; ++ reg = <0x01c0f000 0x1000>; ++ clocks = <&ahb_gates 8>, <&mmc0_clk>; ++ clock-names = "ahb", "mod"; ++ interrupts = <32>; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ + intc: interrupt-controller@01c20400 { + compatible = "allwinner,sun4i-ic"; + reg = <0x01c20400 0x400>; +@@ -319,6 +329,13 @@ + allwinner,drive = <0>; + allwinner,pull = <0>; + }; ++ ++ mmc0_pins_a: mmc0@0 { ++ allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5"; ++ allwinner,function = "mmc0"; ++ allwinner,drive = <3>; ++ allwinner,pull = <0>; ++ }; + }; + + timer@01c20c00 { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/153-3-dt-sun7i-add-mmc.patch b/target/linux/sunxi/patches-3.13/153-3-dt-sun7i-add-mmc.patch new file mode 100644 index 0000000000..79286b250f --- /dev/null +++ b/target/linux/sunxi/patches-3.13/153-3-dt-sun7i-add-mmc.patch @@ -0,0 +1,142 @@ +From 3cce544eb5964c14653dddde731cac4cbff97d90 Mon Sep 17 00:00:00 2001 +From: Hans de Goede <hdegoede@redhat.com> +Date: Sat, 14 Dec 2013 22:58:15 +0100 +Subject: [PATCH] ARM: dts: sun7i: Add support for mmc + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 16 ++++++++++++ + arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 16 ++++++++++++ + arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 32 +++++++++++++++++++++++ + arch/arm/boot/dts/sun7i-a20.dtsi | 34 +++++++++++++++++++++++++ + 4 files changed, 98 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +index 5c51cb8..d28e600 100644 +--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts ++++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +@@ -34,7 +34,23 @@ + }; + }; + ++ mmc0: mmc@01c0f000 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc0_pins_a>; ++ pinctrl-1 = <&mmc0_cd_pin_cubieboard2>; ++ cd-gpios = <&pio 7 1 0>; /* PH1 */ ++ cd-mode = <1>; ++ status = "okay"; ++ }; ++ + pinctrl@01c20800 { ++ mmc0_cd_pin_cubieboard2: mmc0_cd_pin@0 { ++ allwinner,pins = "PH1"; ++ allwinner,function = "gpio_in"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ + led_pins_cubieboard2: led_pins@0 { + allwinner,pins = "PH20", "PH21"; + allwinner,function = "gpio_out"; +diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts +index 8a1009d..7ee628a 100644 +diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +index ead3013..d377696 100644 +--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts ++++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +@@ -34,7 +34,39 @@ + }; + }; + ++ mmc0: mmc@01c0f000 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc0_pins_a>; ++ pinctrl-1 = <&mmc0_cd_pin_olinuxinom>; ++ cd-gpios = <&pio 7 1 0>; /* PH1 */ ++ cd-mode = <1>; ++ status = "okay"; ++ }; ++ ++ mmc3: mmc@01c12000 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc3_pins_a>; ++ pinctrl-1 = <&mmc3_cd_pin_olinuxinom>; ++ cd-gpios = <&pio 7 11 0>; /* PH11 */ ++ cd-mode = <1>; ++ status = "okay"; ++ }; ++ + pinctrl@01c20800 { ++ mmc0_cd_pin_olinuxinom: mmc0_cd_pin@0 { ++ allwinner,pins = "PH1"; ++ allwinner,function = "gpio_in"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ ++ mmc3_cd_pin_olinuxinom: mmc3_cd_pin@0 { ++ allwinner,pins = "PH11"; ++ allwinner,function = "gpio_in"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ + led_pins_olinuxino: led_pins@0 { + allwinner,pins = "PH2"; + allwinner,function = "gpio_out"; +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 8819c68..0c1d363 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -319,6 +319,26 @@ + #size-cells = <0>; + }; + ++ mmc0: mmc@01c0f000 { ++ compatible = "allwinner,sun5i-a13-mmc"; ++ reg = <0x01c0f000 0x1000>; ++ clocks = <&ahb_gates 8>, <&mmc0_clk>; ++ clock-names = "ahb", "mod"; ++ interrupts = <0 32 4>; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ ++ mmc3: mmc@01c12000 { ++ compatible = "allwinner,sun5i-a13-mmc"; ++ reg = <0x01c12000 0x1000>; ++ clocks = <&ahb_gates 11>, <&mmc3_clk>; ++ clock-names = "ahb", "mod"; ++ interrupts = <0 35 4>; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ + pio: pinctrl@01c20800 { + compatible = "allwinner,sun7i-a20-pinctrl"; + reg = <0x01c20800 0x400>; +@@ -382,6 +402,20 @@ + allwinner,drive = <0>; + allwinner,pull = <0>; + }; ++ ++ mmc0_pins_a: mmc0@0 { ++ allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5"; ++ allwinner,function = "mmc0"; ++ allwinner,drive = <3>; ++ allwinner,pull = <0>; ++ }; ++ ++ mmc3_pins_a: mmc3@0 { ++ allwinner,pins = "PI4","PI5","PI6","PI7","PI8","PI9"; ++ allwinner,function = "mmc3"; ++ allwinner,drive = <3>; ++ allwinner,pull = <0>; ++ }; + }; + + timer@01c20c00 { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/154-mmc-update-compat-nodes.patch b/target/linux/sunxi/patches-3.13/154-mmc-update-compat-nodes.patch new file mode 100644 index 0000000000..5de609374b --- /dev/null +++ b/target/linux/sunxi/patches-3.13/154-mmc-update-compat-nodes.patch @@ -0,0 +1,23 @@ +diff -ruN old/drivers/mmc/host/sunxi-mci.c new/drivers/mmc/host/sunxi-mci.c +--- old/drivers/mmc/host/sunxi-mci.c 2014-01-22 23:41:25.000000000 +0100 ++++ new/drivers/mmc/host/sunxi-mci.c 2014-01-28 16:55:24.000000000 +0100 +@@ -715,8 +715,8 @@ + } + + static const struct of_device_id sunxi_mmc_of_match[] = { +- { .compatible = "allwinner,sun4i-mmc", }, +- { .compatible = "allwinner,sun5i-mmc", }, ++ { .compatible = "allwinner,sun4i-a10-mmc", }, ++ { .compatible = "allwinner,sun5i-a13-mmc", }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match); +@@ -736,7 +736,7 @@ + struct device_node *np = pdev->dev.of_node; + int ret; + +- if (of_device_is_compatible(np, "allwinner,sun4i-mmc")) ++ if (of_device_is_compatible(np, "allwinner,sun4i-a10-mmc")) + host->idma_des_size_bits = 13; + else + host->idma_des_size_bits = 16; diff --git a/target/linux/sunxi/patches-3.13/160-ahci-add-pre-start-hook.patch b/target/linux/sunxi/patches-3.13/160-ahci-add-pre-start-hook.patch new file mode 100644 index 0000000000..342c11436d --- /dev/null +++ b/target/linux/sunxi/patches-3.13/160-ahci-add-pre-start-hook.patch @@ -0,0 +1,53 @@ +From 3eec76bc21d78e56ac8404b59f29dd9dbbd1528a Mon Sep 17 00:00:00 2001 +From: Oliver Schinagl <oliver@schinagl.nl> +Date: Mon, 2 Dec 2013 16:13:32 +0100 +Subject: [PATCH] libahci: Add a pre ahci_start_engine hook + +Allwinner A10 and A20 ARM SoCs have an AHCI sata controller which need a +special register to be poked before starting the DMA engine. + +This register gets reset on an ahci_stop_engine call, so there is no other +place then ahci_start_engine where this poking can be done. + +This commit adds a pre ahci_start_engine hook for use by the Allwinner AHCI +driver (and potentially other drivers in the future). + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + drivers/ata/ahci.h | 2 ++ + drivers/ata/libahci.c | 4 ++++ + 2 files changed, 6 insertions(+) + +diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h +index 2289efd..1bba479 100644 +--- a/drivers/ata/ahci.h ++++ b/drivers/ata/ahci.h +@@ -323,6 +323,8 @@ struct ahci_host_priv { + u32 em_msg_type; /* EM message type */ + struct clk *clk; /* Only for platforms supporting clk */ + void *plat_data; /* Other platform data */ ++ /* Optional pre ahci_start_engine hook */ ++ void (*pre_start_engine)(struct ata_port *ap); + }; + + extern int ahci_ignore_sss; +diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c +index c482f8c..780e9df 100644 +--- a/drivers/ata/libahci.c ++++ b/drivers/ata/libahci.c +@@ -568,8 +568,12 @@ static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) + void ahci_start_engine(struct ata_port *ap) + { + void __iomem *port_mmio = ahci_port_base(ap); ++ struct ahci_host_priv *hpriv = ap->host->private_data; + u32 tmp; + ++ if (hpriv->pre_start_engine) ++ hpriv->pre_start_engine(ap); ++ + /* start DMA */ + tmp = readl(port_mmio + PORT_CMD); + tmp |= PORT_CMD_START; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/161-sunxi-ahci-add-driver.patch b/target/linux/sunxi/patches-3.13/161-sunxi-ahci-add-driver.patch new file mode 100644 index 0000000000..c4b8d38ad7 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/161-sunxi-ahci-add-driver.patch @@ -0,0 +1,449 @@ +From 22345cc059de4a6ea1dc7657dd6ad86ca16a8814 Mon Sep 17 00:00:00 2001 +From: Oliver Schinagl <oliver@schinagl.nl> +Date: Tue, 3 Dec 2013 12:07:01 +0100 +Subject: [PATCH] ARM: sunxi: Add ahci-sunxi driver for the Allwinner SUNXi + SoCs sata + +This patch adds support for the ahci sata controler found on Allwinner A10 +and A20 SoCs. + +Orignally written by Olliver Schinagl using the approach of having a platform +device which probe method creates a new child platform device which gets +driven by ahci_platform.c, as done by ahci_imx.c . + +Given that almost all functionality already is shared through libahci / +ata-core, and that ahci_platform.c cannot cleanly handle somewhat more complex +platform specific ahci cases, such as the sunxi case, it was refactored into +a stand-alone platform driver by Hans de Goede. + +Signed-off-by: Olliver Schinagl <oliver@schinagl.nl> +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + .../devicetree/bindings/ata/ahci-sunxi.txt | 24 ++ + drivers/ata/Kconfig | 9 + + drivers/ata/Makefile | 1 + + drivers/ata/ahci_sunxi.c | 349 +++++++++++++++++++++ + 4 files changed, 383 insertions(+) + create mode 100644 Documentation/devicetree/bindings/ata/ahci-sunxi.txt + create mode 100644 drivers/ata/ahci_sunxi.c + +diff --git a/Documentation/devicetree/bindings/ata/ahci-sunxi.txt b/Documentation/devicetree/bindings/ata/ahci-sunxi.txt +new file mode 100644 +index 0000000..0792fa5 +--- /dev/null ++++ b/Documentation/devicetree/bindings/ata/ahci-sunxi.txt +@@ -0,0 +1,24 @@ ++Allwinner SUNXI AHCI SATA Controller ++ ++SATA nodes are defined to describe on-chip Serial ATA controllers. ++Each SATA controller should have its own node. ++ ++Required properties: ++- compatible : compatible list, contains "allwinner,sun4i-a10-ahci" ++- reg : <registers mapping> ++- interrupts : <interrupt mapping for AHCI IRQ> ++- clocks : clocks for ACHI ++- clock-names : clock names for AHCI ++ ++Optional properties: ++- pwr-supply : regulator to control the power supply GPIO ++ ++Example: ++ ahci@01c18000 { ++ compatible = "allwinner,sun4i-a10-ahci"; ++ reg = <0x01c18000 0x1000>; ++ interrupts = <0 56 1>; ++ clocks = <&ahb_gates 25>, <&pll6 0>; ++ clock-names = "ahb_sata", "pll6_sata"; ++ pwr-supply = <®_ahci_5v>; ++ }; +diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig +index 4e73772..3c80bbe 100644 +--- a/drivers/ata/Kconfig ++++ b/drivers/ata/Kconfig +@@ -106,6 +106,15 @@ config AHCI_IMX + + If unsure, say N. + ++config AHCI_SUNXI ++ tristate "Allwinner sunxi AHCI SATA support" ++ depends on ARCH_SUNXI ++ help ++ This option enables support for the Allwinner sunxi SoC's ++ onboard AHCI SATA. ++ ++ If unsure, say N. ++ + config SATA_FSL + tristate "Freescale 3.0Gbps SATA support" + depends on FSL_SOC +diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile +index 46518c6..956abc3 100644 +--- a/drivers/ata/Makefile ++++ b/drivers/ata/Makefile +@@ -11,6 +11,7 @@ obj-$(CONFIG_SATA_SIL24) += sata_sil24.o + obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o + obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o + obj-$(CONFIG_AHCI_IMX) += ahci_imx.o ++obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o libahci.o + + # SFF w/ custom DMA + obj-$(CONFIG_PDC_ADMA) += pdc_adma.o +diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c +new file mode 100644 +index 0000000..22d3972 +--- /dev/null ++++ b/drivers/ata/ahci_sunxi.c +@@ -0,0 +1,349 @@ ++/* ++ * Allwinner sunxi AHCI SATA platform driver ++ * Copyright 2013 Olliver Schinagl <oliver@schinagl.nl> ++ * Copyright 2014 Hans de Goede <hdegoede@redhat.com> ++ * ++ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov ++ * Based on code from Allwinner Technology Co., Ltd. <www.allwinnertech.com>, ++ * Daniel Wang <danielwang@allwinnertech.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 <linux/clk.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include <linux/regulator/consumer.h> ++#include "ahci.h" ++ ++#define AHCI_BISTAFR 0x00a0 ++#define AHCI_BISTCR 0x00a4 ++#define AHCI_BISTFCTR 0x00a8 ++#define AHCI_BISTSR 0x00ac ++#define AHCI_BISTDECR 0x00b0 ++#define AHCI_DIAGNR0 0x00b4 ++#define AHCI_DIAGNR1 0x00b8 ++#define AHCI_OOBR 0x00bc ++#define AHCI_PHYCS0R 0x00c0 ++#define AHCI_PHYCS1R 0x00c4 ++#define AHCI_PHYCS2R 0x00c8 ++#define AHCI_TIMER1MS 0x00e0 ++#define AHCI_GPARAM1R 0x00e8 ++#define AHCI_GPARAM2R 0x00ec ++#define AHCI_PPARAMR 0x00f0 ++#define AHCI_TESTR 0x00f4 ++#define AHCI_VERSIONR 0x00f8 ++#define AHCI_IDR 0x00fc ++#define AHCI_RWCR 0x00fc ++#define AHCI_P0DMACR 0x0170 ++#define AHCI_P0PHYCR 0x0178 ++#define AHCI_P0PHYSR 0x017c ++ ++struct sunxi_ahci { ++ struct ahci_host_priv hpriv; ++ struct regulator *pwr; ++ struct clk *sata_clk; ++ struct clk *ahb_clk; ++}; ++ ++static void sunxi_clrbits(void __iomem *reg, u32 clr_val) ++{ ++ u32 reg_val; ++ ++ reg_val = readl(reg); ++ reg_val &= ~(clr_val); ++ writel(reg_val, reg); ++} ++ ++static void sunxi_setbits(void __iomem *reg, u32 set_val) ++{ ++ u32 reg_val; ++ ++ reg_val = readl(reg); ++ reg_val |= set_val; ++ writel(reg_val, reg); ++} ++ ++static void sunxi_clrsetbits(void __iomem *reg, u32 clr_val, u32 set_val) ++{ ++ u32 reg_val; ++ ++ reg_val = readl(reg); ++ reg_val &= ~(clr_val); ++ reg_val |= set_val; ++ writel(reg_val, reg); ++} ++ ++static u32 sunxi_getbits(void __iomem *reg, u8 mask, u8 shift) ++{ ++ return (readl(reg) >> shift) & mask; ++} ++ ++static int sunxi_ahci_phy_init(struct device *dev, void __iomem *reg_base) ++{ ++ u32 reg_val; ++ int timeout; ++ ++ /* This magic is from the original code */ ++ writel(0, reg_base + AHCI_RWCR); ++ mdelay(5); ++ ++ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(19)); ++ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R, ++ (0x7 << 24), ++ (0x5 << 24) | BIT(23) | BIT(18)); ++ sunxi_clrsetbits(reg_base + AHCI_PHYCS1R, ++ (0x3 << 16) | (0x1f << 8) | (0x3 << 6), ++ (0x2 << 16) | (0x6 << 8) | (0x2 << 6)); ++ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(28) | BIT(15)); ++ sunxi_clrbits(reg_base + AHCI_PHYCS1R, BIT(19)); ++ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R, ++ (0x7 << 20), (0x3 << 20)); ++ sunxi_clrsetbits(reg_base + AHCI_PHYCS2R, ++ (0x1f << 5), (0x19 << 5)); ++ mdelay(5); ++ ++ sunxi_setbits(reg_base + AHCI_PHYCS0R, (0x1 << 19)); ++ ++ timeout = 0x100000; ++ do { ++ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS0R, 0x7, 28); ++ } while (--timeout && (reg_val != 0x2)); ++ if (!timeout) { ++ dev_err(dev, "PHY power up failed.\n"); ++ return -EIO; ++ } ++ ++ sunxi_setbits(reg_base + AHCI_PHYCS2R, (0x1 << 24)); ++ ++ timeout = 0x100000; ++ do { ++ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS2R, 0x1, 24); ++ } while (--timeout && reg_val); ++ if (!timeout) { ++ dev_err(dev, "PHY calibration failed.\n"); ++ return -EIO; ++ } ++ mdelay(15); ++ ++ writel(0x7, reg_base + AHCI_RWCR); ++ ++ return 0; ++} ++ ++void sunxi_ahci_pre_start_engine(struct ata_port *ap) ++{ ++ struct ahci_host_priv *hpriv = ap->host->private_data; ++ ++ /* Setup DMA before DMA start */ ++ sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ff00, 0x00004400); ++} ++ ++static int sunxi_ahci_enable_clks(struct sunxi_ahci *ahci) ++{ ++ int ret; ++ ++ ret = clk_prepare_enable(ahci->sata_clk); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(ahci->ahb_clk); ++ if (ret) ++ clk_disable_unprepare(ahci->sata_clk); ++ ++ return ret; ++} ++ ++static void sunxi_ahci_disable_clks(struct sunxi_ahci *ahci) ++{ ++ clk_disable_unprepare(ahci->ahb_clk); ++ clk_disable_unprepare(ahci->sata_clk); ++} ++ ++static void sunxi_ahci_host_stop(struct ata_host *host) ++{ ++ struct ahci_host_priv *hpriv = host->private_data; ++ struct sunxi_ahci *ahci = hpriv->plat_data; ++ ++ if (!IS_ERR(ahci->pwr)) ++ regulator_disable(ahci->pwr); ++ ++ sunxi_ahci_disable_clks(ahci); ++} ++ ++static struct ata_port_operations sunxi_ahci_platform_ops = { ++ .inherits = &ahci_ops, ++ .host_stop = sunxi_ahci_host_stop, ++}; ++ ++static const struct ata_port_info sunxiahci_port_info = { ++ AHCI_HFLAGS(AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | ++ AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ), ++ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ, ++ .pio_mask = ATA_PIO4, ++ .udma_mask = ATA_UDMA6, ++ .port_ops = &sunxi_ahci_platform_ops, ++}; ++ ++static struct scsi_host_template sunxi_ahci_platform_sht = { ++ AHCI_SHT("sunxi_ahci"), ++}; ++ ++static int sunxi_ahci_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ const struct ata_port_info *ppi[] = { &sunxiahci_port_info, NULL }; ++ struct sunxi_ahci *ahci; ++ struct ata_host *host; ++ int ret; ++ ++ ahci = devm_kzalloc(&pdev->dev, sizeof(*ahci), GFP_KERNEL); ++ if (!ahci) ++ return -ENOMEM; ++ ++ ahci->pwr = devm_regulator_get_optional(dev, "pwr"); ++ if (IS_ERR(ahci->pwr) && PTR_ERR(ahci->pwr) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ ++ host = ata_host_alloc_pinfo(dev, ppi, 1); ++ if (!host) ++ return -ENOMEM; ++ ++ host->private_data = &ahci->hpriv; ++ host->flags |= ATA_HOST_PARALLEL_SCAN; ++ ++ ahci->hpriv.flags = (unsigned long)ppi[0]->private_data; ++ ahci->hpriv.plat_data = ahci; ++ ahci->hpriv.pre_start_engine = sunxi_ahci_pre_start_engine; ++ ahci->hpriv.mmio = devm_ioremap_resource(dev, ++ platform_get_resource(pdev, IORESOURCE_MEM, 0)); ++ if (IS_ERR(ahci->hpriv.mmio)) ++ return PTR_ERR(ahci->hpriv.mmio); ++ ++ ahci->ahb_clk = devm_clk_get(&pdev->dev, "ahb_sata"); ++ if (IS_ERR(ahci->ahb_clk)) ++ return PTR_ERR(ahci->ahb_clk); ++ ++ ahci->sata_clk = devm_clk_get(&pdev->dev, "pll6_sata"); ++ if (IS_ERR(ahci->sata_clk)) ++ return PTR_ERR(ahci->sata_clk); ++ ++ ret = sunxi_ahci_enable_clks(ahci); ++ if (ret) ++ return ret; ++ ++ if (!IS_ERR(ahci->pwr)) { ++ ret = regulator_enable(ahci->pwr); ++ if (ret) { ++ sunxi_ahci_disable_clks(ahci); ++ return ret; ++ } ++ } ++ ++ ret = sunxi_ahci_phy_init(dev, ahci->hpriv.mmio); ++ if (ret) { ++ sunxi_ahci_host_stop(host); ++ return ret; ++ } ++ ++ ahci_save_initial_config(dev, &ahci->hpriv, 0, 0); ++ ++ ret = ahci_reset_controller(host); ++ if (ret) { ++ sunxi_ahci_host_stop(host); ++ return ret; ++ } ++ ++ ahci_init_controller(host); ++ ahci_print_info(host, "sunxi"); ++ ++ ret = ata_host_activate(host, platform_get_irq(pdev, 0), ++ ahci_interrupt, 0, &sunxi_ahci_platform_sht); ++ if (ret) ++ sunxi_ahci_host_stop(host); ++ ++ return ret; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int sunxi_ahci_susp(struct device *dev) ++{ ++ struct ata_host *host = dev_get_drvdata(dev); ++ struct ahci_host_priv *hpriv = host->private_data; ++ struct sunxi_ahci *ahci = hpriv->plat_data; ++ int ret; ++ ++ /* ++ * AHCI spec rev1.1 section 8.3.3: ++ * Software must disable interrupts prior to requesting a ++ * transition of the HBA to D3 state. ++ */ ++ sunxi_clrbits(hpriv->mmio + HOST_CTL, HOST_IRQ_EN); ++ ++ ret = ata_host_suspend(host, PMSG_SUSPEND); ++ if (ret) ++ return ret; ++ ++ sunxi_ahci_disable_clks(ahci); ++ ++ return 0; ++} ++ ++static int sunxi_ahci_resume(struct device *dev) ++{ ++ struct ata_host *host = dev_get_drvdata(dev); ++ struct ahci_host_priv *hpriv = host->private_data; ++ struct sunxi_ahci *ahci = hpriv->plat_data; ++ int ret; ++ ++ ret = sunxi_ahci_enable_clks(ahci); ++ if (ret) ++ return ret; ++ ++ if (dev->power.power_state.event == PM_EVENT_SUSPEND) { ++ ret = ahci_reset_controller(host); ++ if (ret) ++ return ret; ++ ++ ahci_init_controller(host); ++ } ++ ++ ata_host_resume(host); ++ ++ return 0; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(sunxi_ahci_pmo, sunxi_ahci_susp, sunxi_ahci_resume); ++ ++static const struct of_device_id sunxi_ahci_of_match[] = { ++ { .compatible = "allwinner,sun4i-a10-ahci" }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, sunxi_ahci_of_match); ++ ++static struct platform_driver sunxi_ahci_driver = { ++ .probe = sunxi_ahci_probe, ++ .remove = ata_platform_remove_one, ++ .driver = { ++ .name = "sunxi-ahci", ++ .owner = THIS_MODULE, ++ .of_match_table = sunxi_ahci_of_match, ++ .pm = &sunxi_ahci_pmo, ++ }, ++}; ++module_platform_driver(sunxi_ahci_driver); ++ ++MODULE_DESCRIPTION("Allwinner sunxi AHCI SATA platform driver"); ++MODULE_AUTHOR("Olliver Schinagl <oliver@schinagl.nl>"); ++MODULE_LICENSE("GPL"); +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/162-1-dt-sun4i-add-ahci-nodes.patch b/target/linux/sunxi/patches-3.13/162-1-dt-sun4i-add-ahci-nodes.patch new file mode 100644 index 0000000000..b69c4807cd --- /dev/null +++ b/target/linux/sunxi/patches-3.13/162-1-dt-sun4i-add-ahci-nodes.patch @@ -0,0 +1,99 @@ +From 23af610e09f78822ade4067a400ff9ceb5b020ea Mon Sep 17 00:00:00 2001 +From: Oliver Schinagl <oliver@schinagl.nl> +Date: Tue, 3 Dec 2013 12:10:11 +0100 +Subject: [PATCH] ARM: sun4i: dts: Add ahci / sata support + +This patch adds sunxi sata support to A10 boards that have such a connector. +Some boards also feature a regulator via a GPIO and support for this is also +added. + +Signed-off-by: Olliver Schinagl <oliver@schinagl.nl> +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun4i-a10-a1000.dts | 4 ++++ + arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 27 +++++++++++++++++++++++++++ + arch/arm/boot/dts/sun4i-a10.dtsi | 9 +++++++++ + 3 files changed, 40 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts +index aef8207..fd6d512 100644 +--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts ++++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts +@@ -48,6 +48,10 @@ + status = "okay"; + }; + ++ sata: ahci@01c18000 { ++ status = "okay"; ++ }; ++ + pinctrl@01c20800 { + mmc0_cd_pin_a1000: mmc0_cd_pin@0 { + allwinner,pins = "PH1"; +diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts +index f50fb2b..53ac453 100644 +--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts ++++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts +@@ -51,7 +51,19 @@ + status = "okay"; + }; + ++ sata: ahci@01c18000 { ++ pwr-supply = <®_ahci_5v>; ++ status = "okay"; ++ }; ++ + pinctrl@01c20800 { ++ ahci_pwr_pin_cubieboard: ahci_pwr_pin@0 { ++ allwinner,pins = "PB8"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ + mmc0_cd_pin_cubieboard: mmc0_cd_pin@0 { + allwinner,pins = "PH1"; + allwinner,function = "gpio_in"; +@@ -102,4 +114,19 @@ + linux,default-trigger = "heartbeat"; + }; + }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ pinctrl-names = "default"; ++ ++ reg_ahci_5v: ahci-5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "ahci-5v"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ pinctrl-0 = <&ahci_pwr_pin_cubieboard>; ++ gpio = <&pio 1 8 0>; ++ enable-active-high; ++ }; ++ }; + }; +diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi +index 4736dd2..731b491 100644 +--- a/arch/arm/boot/dts/sun4i-a10.dtsi ++++ b/arch/arm/boot/dts/sun4i-a10.dtsi +@@ -331,6 +331,15 @@ + status = "disabled"; + }; + ++ sata: ahci@01c18000 { ++ compatible = "allwinner,sun4i-a10-ahci"; ++ reg = <0x01c18000 0x1000>; ++ interrupts = <56>; ++ clocks = <&ahb_gates 25>, <&pll6 0>; ++ clock-names = "ahb_sata", "pll6_sata"; ++ status = "disabled"; ++ }; ++ + intc: interrupt-controller@01c20400 { + compatible = "allwinner,sun4i-ic"; + reg = <0x01c20400 0x400>; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/162-2-dt-sun7i-add-ahci-nodes.patch b/target/linux/sunxi/patches-3.13/162-2-dt-sun7i-add-ahci-nodes.patch new file mode 100644 index 0000000000..5801f66e55 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/162-2-dt-sun7i-add-ahci-nodes.patch @@ -0,0 +1,178 @@ +From 4ce1f4c3ab04a697e9861b77582077b905b3f8a0 Mon Sep 17 00:00:00 2001 +From: Hans de Goede <hdegoede@redhat.com> +Date: Fri, 3 Jan 2014 10:27:51 +0100 +Subject: [PATCH] ARM: sun7i: dts: Add ahci / sata support + +This patch adds sunxi sata support to A20 boards that have such a connector. +Some boards also feature a regulator via a GPIO and support for this is also +added. + +Signed-off-by: Olliver Schinagl <oliver@schinagl.nl> +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 27 +++++++++++++++++++++++++ + arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 27 +++++++++++++++++++++++++ + arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 26 ++++++++++++++++++++++++ + arch/arm/boot/dts/sun7i-a20.dtsi | 9 +++++++++ + 4 files changed, 89 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +index 48777cd..a26711c 100644 +--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts ++++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +@@ -28,7 +28,19 @@ + status = "okay"; + }; + ++ sata: ahci@01c18000 { ++ pwr-supply = <®_ahci_5v>; ++ status = "okay"; ++ }; ++ + pinctrl@01c20800 { ++ ahci_pwr_pin_cubieboard2: ahci_pwr_pin@0 { ++ allwinner,pins = "PB8"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ + mmc0_cd_pin_cubieboard2: mmc0_cd_pin@0 { + allwinner,pins = "PH1"; + allwinner,function = "gpio_in"; +@@ -86,4 +98,19 @@ + gpios = <&pio 7 20 0>; + }; + }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ pinctrl-names = "default"; ++ ++ reg_ahci_5v: ahci-5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "ahci-5v"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ pinctrl-0 = <&ahci_pwr_pin_cubieboard2>; ++ gpio = <&pio 1 8 0>; ++ enable-active-high; ++ }; ++ }; + }; +diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts +index 2684f27..a5f3418 100644 +--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts ++++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts +@@ -28,6 +28,11 @@ + status = "okay"; + }; + ++ sata: ahci@01c18000 { ++ pwr-supply = <®_ahci_5v>; ++ status = "okay"; ++ }; ++ + pinctrl@01c20800 { + mmc0_cd_pin_cubietruck: mmc0_cd_pin@0 { + allwinner,pins = "PH1"; +@@ -36,6 +41,13 @@ + allwinner,pull = <0>; + }; + ++ ahci_pwr_pin_cubietruck: ahci_pwr_pin@0 { ++ allwinner,pins = "PH12"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ + led_pins_cubietruck: led_pins@0 { + allwinner,pins = "PH7", "PH11", "PH20", "PH21"; + allwinner,function = "gpio_out"; +@@ -84,4 +96,19 @@ + gpios = <&pio 7 7 0>; + }; + }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ pinctrl-names = "default"; ++ ++ reg_ahci_5v: ahci-5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "ahci-5v"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ pinctrl-0 = <&ahci_pwr_pin_cubietruck>; ++ gpio = <&pio 7 12 0>; ++ enable-active-high; ++ }; ++ }; + }; +diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +index bf6f6c8..20b1000 100644 +--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts ++++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +@@ -37,7 +37,19 @@ + status = "okay"; + }; + ++ sata: ahci@01c18000 { ++ pwr-supply = <®_ahci_5v>; ++ status = "okay"; ++ }; ++ + pinctrl@01c20800 { ++ ahci_pwr_pin_olinuxinom: ahci_pwr_pin@0 { ++ allwinner,pins = "PB8"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ + mmc0_cd_pin_olinuxinom: mmc0_cd_pin@0 { + allwinner,pins = "PH1"; + allwinner,function = "gpio_in"; +@@ -116,4 +128,18 @@ + default-state = "on"; + }; + }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ ++ reg_ahci_5v: ahci-5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "ahci-5v"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ pinctrl-0 = <&ahci_pwr_pin_olinuxinom>; ++ gpio = <&pio 1 8 0>; ++ enable-active-high; ++ }; ++ }; + }; +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index c9c123a..3242a29 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -448,6 +448,15 @@ + }; + }; + ++ sata: ahci@01c18000 { ++ compatible = "allwinner,sun4i-a10-ahci"; ++ reg = <0x01c18000 0x1000>; ++ interrupts = <0 56 1>; ++ clocks = <&ahb_gates 25>, <&pll6 0>; ++ clock-names = "ahb_sata", "pll6_sata"; ++ status = "disabled"; ++ }; ++ + timer@01c20c00 { + compatible = "allwinner,sun4i-timer"; + reg = <0x01c20c00 0x90>; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/170-clk-sunxi-add-support-for-usbclocks.patch b/target/linux/sunxi/patches-3.13/170-clk-sunxi-add-support-for-usbclocks.patch new file mode 100644 index 0000000000..54aa9f20d9 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/170-clk-sunxi-add-support-for-usbclocks.patch @@ -0,0 +1,36 @@ +From 109e7dc17a77f84d56e76dea873363a8262bc806 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Thu, 19 Sep 2013 21:59:32 +0200 +Subject: [PATCH] clk: sunxi: Add support for USB clocks + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + drivers/clk/sunxi/clk-sunxi.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 6d3286a..573ef28 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -702,6 +702,10 @@ struct gates_data { + .mask = {0x7F77FFF, 0x14FB3F}, + }; + ++static const struct gates_data sun47i_usb_gates_data __initconst = { ++ .mask = {0x1C0}, ++}; ++ + static const struct gates_data sun5i_a10s_ahb_gates_data __initconst = { + .mask = {0x147667e7, 0x185915}, + }; +@@ -1017,6 +1021,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, + static const struct of_device_id clk_gates_match[] __initconst = { + {.compatible = "allwinner,sun4i-axi-gates-clk", .data = &sun4i_axi_gates_data,}, + {.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &sun4i_ahb_gates_data,}, ++ {.compatible = "allwinner,sun47i-usb-gates-clk", .data = &sun47i_usb_gates_data,}, + {.compatible = "allwinner,sun5i-a10s-ahb-gates-clk", .data = &sun5i_a10s_ahb_gates_data,}, + {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,}, + {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,}, +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/171-clk-sunxi-add-support-for-sun5i-usbclocks.patch b/target/linux/sunxi/patches-3.13/171-clk-sunxi-add-support-for-sun5i-usbclocks.patch new file mode 100644 index 0000000000..d8456e483e --- /dev/null +++ b/target/linux/sunxi/patches-3.13/171-clk-sunxi-add-support-for-sun5i-usbclocks.patch @@ -0,0 +1,36 @@ +From 6b5cb5cada555c90562aed82e8891439a35009ab Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Sun, 6 Oct 2013 14:04:50 +0200 +Subject: [PATCH] clk: sun5i: Add support for USB clocks + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + drivers/clk/sunxi/clk-sunxi.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 573ef28..8a07a68 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -706,6 +706,10 @@ struct gates_data { + .mask = {0x1C0}, + }; + ++static const struct gates_data sun5i_usb_gates_data __initconst = { ++ .mask = {0x140}, ++}; ++ + static const struct gates_data sun5i_a10s_ahb_gates_data __initconst = { + .mask = {0x147667e7, 0x185915}, + }; +@@ -1024,6 +1028,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, + {.compatible = "allwinner,sun47i-usb-gates-clk", .data = &sun47i_usb_gates_data,}, + {.compatible = "allwinner,sun5i-a10s-ahb-gates-clk", .data = &sun5i_a10s_ahb_gates_data,}, + {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,}, ++ {.compatible = "allwinner,sun5i-usb-gates-clk", .data = &sun5i_usb_gates_data,}, + {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,}, + {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,}, + {.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &sun4i_apb0_gates_data,}, +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/172-usb-add-ehci-driver.patch b/target/linux/sunxi/patches-3.13/172-usb-add-ehci-driver.patch new file mode 100644 index 0000000000..724c73a3d9 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/172-usb-add-ehci-driver.patch @@ -0,0 +1,503 @@ +From 825ce97e1faa39bfd30c3dca95fba5eb021cb534 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Wed, 18 Sep 2013 21:45:03 +0200 +Subject: [PATCH] ARM: sunxi: usb: Add Allwinner sunXi EHCI driver + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> + +Conflicts: + drivers/usb/host/Makefile +--- + drivers/usb/host/Kconfig | 9 + + drivers/usb/host/Makefile | 1 + + drivers/usb/host/ehci-sunxi.c | 446 ++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 456 insertions(+) + create mode 100644 drivers/usb/host/ehci-sunxi.c + +diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig +index a9707da..db94dba 100644 +--- a/drivers/usb/host/Kconfig ++++ b/drivers/usb/host/Kconfig +@@ -273,6 +273,15 @@ config USB_OCTEON_EHCI + USB 2.0 device support. All CN6XXX based chips with USB are + supported. + ++config USB_SUNXI_EHCI ++ tristate "Allwinner sunXi EHCI support" ++ depends on ARCH_SUNXI ++ default n ++ help ++ Enable support for the Allwinner sunXi on-chip EHCI ++ controller. It is needed for high-speed (480Mbit/sec) ++ USB 2.0 device support. ++ + endif # USB_EHCI_HCD + + config USB_OXU210HP_HCD +diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile +index 01e879e..d96053d 100644 +--- a/drivers/usb/host/Makefile ++++ b/drivers/usb/host/Makefile +@@ -39,6 +39,7 @@ obj-$(CONFIG_USB_EHCI_HCD_AT91) += ehci-atmel.o + obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o + obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o + obj-$(CONFIG_USB_W90X900_EHCI) += ehci-w90x900.o ++obj-$(CONFIG_USB_SUNXI_EHCI) += ehci-sunxi.o + + obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o + obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o +diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c +new file mode 100644 +index 0000000..e7e15cc +--- /dev/null ++++ b/drivers/usb/host/ehci-sunxi.c +@@ -0,0 +1,446 @@ ++/* ++ * Copyright (C) 2013 Roman Byshko ++ * ++ * Roman Byshko <rbyshko@gmail.com> ++ * ++ * Based on code from ++ * Allwinner Technology Co., Ltd. <www.allwinnertech.com> ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include <linux/bitops.h> ++#include <linux/clk.h> ++#include <linux/dma-mapping.h> ++#include <linux/io.h> ++#include <linux/irq.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/platform_device.h> ++#include <linux/regulator/consumer.h> ++#include <linux/reset.h> ++#include <linux/usb.h> ++#include <linux/usb/hcd.h> ++ ++#include "ehci.h" ++ ++#define DRV_DESC "Allwinner sunXi EHCI driver" ++#define DRV_NAME "sunxi-ehci" ++ ++#define SUNXI_USB_PASSBY_EN 1 ++ ++#define SUNXI_EHCI_AHB_ICHR8_EN BIT(10) ++#define SUNXI_EHCI_AHB_INCR4_BURST_EN BIT(9) ++#define SUNXI_EHCI_AHB_INCRX_ALIGN_EN BIT(8) ++#define SUNXI_EHCI_ULPI_BYPASS_EN BIT(0) ++ ++struct sunxi_ehci_hcd { ++ struct clk *phy_clk; ++ struct clk *ahb_ehci_clk; ++ struct reset_control *reset; ++ struct regulator *vbus_reg; ++ void __iomem *csr; ++ void __iomem *pmuirq; ++ int irq; ++ int id; ++}; ++ ++ ++static void usb_phy_write(struct sunxi_ehci_hcd *sunxi_ehci,u32 addr, u32 data, u32 len) ++{ ++ u32 j = 0; ++ u32 temp = 0; ++ u32 usbc_bit = 0; ++ void __iomem *dest = sunxi_ehci->csr; ++ ++ usbc_bit = BIT(sunxi_ehci->id << 1); ++ ++ for (j = 0; j < len; j++) { ++ temp = readl(dest); ++ ++ /* clear the address portion */ ++ temp &= ~(0xff << 8); ++ ++ /* set the address */ ++ temp |= ((addr + j) << 8); ++ writel(temp, dest); ++ ++ /* set the data bit and clear usbc bit*/ ++ temp = readb(dest); ++ if (data & 0x1) ++ temp |= BIT(7); ++ else ++ temp &= ~BIT(7); ++ temp &= ~usbc_bit; ++ writeb(temp, dest); ++ ++ /* flip usbc_bit */ ++ __set_bit(usbc_bit, dest); ++ __clear_bit(usbc_bit, dest); ++ ++ data >>= 1; ++ } ++} ++ ++/* FIXME: should this function be protected by a lock? ++ * ehci1 and ehci0 could call it concurrently with same csr. ++ */ ++static void sunxi_usb_phy_init(struct sunxi_ehci_hcd *sunxi_ehci) ++{ ++ /* The following comments are machine ++ * translated from Chinese, you have been warned! ++ */ ++ ++ /* adjust PHY's magnitude and rate */ ++ usb_phy_write(sunxi_ehci, 0x20, 0x14, 5); ++ ++ /* threshold adjustment disconnect */ ++ usb_phy_write(sunxi_ehci, 0x2a, 3, 2); ++ ++ return; ++} ++ ++static void sunxi_usb_passby(struct sunxi_ehci_hcd *sunxi_ehci, int enable) ++{ ++ unsigned long reg_value = 0; ++ unsigned long bits = 0; ++ static DEFINE_SPINLOCK(lock); ++ unsigned long flags = 0; ++ void __iomem *addr = sunxi_ehci->pmuirq; ++ ++ bits = SUNXI_EHCI_AHB_ICHR8_EN | ++ SUNXI_EHCI_AHB_INCR4_BURST_EN | ++ SUNXI_EHCI_AHB_INCRX_ALIGN_EN | ++ SUNXI_EHCI_ULPI_BYPASS_EN; ++ ++ spin_lock_irqsave(&lock, flags); ++ ++ reg_value = readl(addr); ++ ++ if (enable) ++ reg_value |= bits; ++ else ++ reg_value &= ~bits; ++ ++ writel(reg_value, addr); ++ ++ spin_unlock_irqrestore(&lock, flags); ++ ++ return; ++} ++ ++static void sunxi_ehci_disable(struct sunxi_ehci_hcd *sunxi_ehci) ++{ ++ regulator_disable(sunxi_ehci->vbus_reg); ++ ++ sunxi_usb_passby(sunxi_ehci, !SUNXI_USB_PASSBY_EN); ++ ++ clk_disable_unprepare(sunxi_ehci->ahb_ehci_clk); ++ clk_disable_unprepare(sunxi_ehci->phy_clk); ++ ++ reset_control_assert(sunxi_ehci->reset); ++} ++ ++static int sunxi_ehci_enable(struct sunxi_ehci_hcd *sunxi_ehci) ++{ ++ int ret; ++ ++ ret = clk_prepare_enable(sunxi_ehci->phy_clk); ++ if (ret) ++ return ret; ++ ++ ret = reset_control_deassert(sunxi_ehci->reset); ++ if (ret) ++ goto fail1; ++ ++ ret = clk_prepare_enable(sunxi_ehci->ahb_ehci_clk); ++ if (ret) ++ goto fail2; ++ ++ sunxi_usb_phy_init(sunxi_ehci); ++ ++ sunxi_usb_passby(sunxi_ehci, SUNXI_USB_PASSBY_EN); ++ ++ ret = regulator_enable(sunxi_ehci->vbus_reg); ++ if (ret) ++ goto fail3; ++ ++ return 0; ++ ++fail3: ++ clk_disable_unprepare(sunxi_ehci->ahb_ehci_clk); ++fail2: ++ reset_control_assert(sunxi_ehci->reset); ++fail1: ++ clk_disable_unprepare(sunxi_ehci->phy_clk); ++ ++ return ret; ++} ++ ++#ifdef CONFIG_PM ++static int sunxi_ehci_suspend(struct device *dev) ++{ ++ struct sunxi_ehci_hcd *sunxi_ehci = NULL; ++ struct usb_hcd *hcd = dev_get_drvdata(dev); ++ int ret; ++ ++ bool do_wakeup = device_may_wakeup(dev); ++ ++ ret = ehci_suspend(hcd, do_wakeup); ++ ++ sunxi_ehci = (struct sunxi_ehci_hcd *)hcd_to_ehci(hcd)->priv; ++ ++ sunxi_ehci_disable(sunxi_ehci); ++ ++ return ret; ++} ++ ++static int sunxi_ehci_resume(struct device *dev) ++{ ++ struct sunxi_ehci_hcd *sunxi_ehci = NULL; ++ struct usb_hcd *hcd = dev_get_drvdata(dev); ++ int ret; ++ ++ sunxi_ehci = (struct sunxi_ehci_hcd *)hcd_to_ehci(hcd)->priv; ++ ++ ret = sunxi_ehci_enable(sunxi_ehci); ++ if (ret) ++ return ret; ++ ++ return ehci_resume(hcd, false); ++} ++ ++ ++static const struct dev_pm_ops sunxi_ehci_pmops = { ++ .suspend = sunxi_ehci_suspend, ++ .resume = sunxi_ehci_resume, ++}; ++ ++#define SUNXI_EHCI_PMOPS (&sunxi_ehci_pmops) ++#else /* !CONFIG_PM */ ++#define SUNXI_EHCI_PMOPS NULL ++#endif /* CONFIG_PM */ ++ ++static const struct ehci_driver_overrides sunxi_overrides __initconst = { ++ .reset = NULL, ++ .extra_priv_size = sizeof(struct sunxi_ehci_hcd), ++}; ++ ++/* FIXME: Should there be two instances of hc_driver, ++ * or one is enough to handle two EHCI controllers? */ ++static struct hc_driver __read_mostly sunxi_ehci_hc_driver; ++ ++static int sunxi_ehci_init(struct platform_device *pdev, struct usb_hcd *hcd, ++ struct sunxi_ehci_hcd *sunxi_ehci) ++{ ++ void __iomem *ehci_regs = NULL; ++ struct resource *res = NULL; ++ ++ sunxi_ehci->vbus_reg = devm_regulator_get(&pdev->dev, "vbus"); ++ if (IS_ERR(sunxi_ehci->vbus_reg)) { ++ if (PTR_ERR(sunxi_ehci->vbus_reg) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ ++ dev_info(&pdev->dev, "no USB VBUS power supply found\n"); ++ } ++ ++ sunxi_ehci->id = of_alias_get_id(pdev->dev.of_node, "ehci"); ++ if (sunxi_ehci->id < 0) ++ return sunxi_ehci->id; ++ ++ /* FIXME: should res be freed on some failure? */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to get I/O memory\n"); ++ return -ENXIO; ++ } ++ ehci_regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(ehci_regs)) ++ return PTR_ERR(ehci_regs); ++ ++ hcd->rsrc_start = res->start; ++ hcd->rsrc_len = resource_size(res); ++ hcd->regs = ehci_regs; ++ hcd_to_ehci(hcd)->caps = ehci_regs; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to get I/O memory\n"); ++ return -ENXIO; ++ } ++ sunxi_ehci->pmuirq = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(sunxi_ehci->pmuirq)) ++ return PTR_ERR(sunxi_ehci->pmuirq); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 2); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to get I/O memory\n"); ++ return -ENXIO; ++ } ++ ++ /* FIXME: this one byte needs to be shared between both EHCIs, ++ * that is why ioremap instead of devm_ioremap_resource, ++ * memory is not unmaped back for now. ++ */ ++ sunxi_ehci->csr = ioremap(res->start, resource_size(res)); ++ if (IS_ERR(sunxi_ehci->csr)) { ++ dev_err(&pdev->dev, "failed to remap memory\n"); ++ return PTR_ERR(sunxi_ehci->csr); ++ } ++ ++ sunxi_ehci->irq = platform_get_irq(pdev, 0); ++ if (!sunxi_ehci->irq) { ++ dev_err(&pdev->dev, "failed to get IRQ\n"); ++ return -ENODEV; ++ } ++ ++ sunxi_ehci->phy_clk = devm_clk_get(&pdev->dev, "usb_phy"); ++ if (IS_ERR(sunxi_ehci->phy_clk)) { ++ dev_err(&pdev->dev, "failed to get usb_phy clock\n"); ++ return PTR_ERR(sunxi_ehci->phy_clk); ++ } ++ sunxi_ehci->ahb_ehci_clk = devm_clk_get(&pdev->dev, "ahb_ehci"); ++ if (IS_ERR(sunxi_ehci->ahb_ehci_clk)) { ++ dev_err(&pdev->dev, "failed to get ahb_ehci clock\n"); ++ return PTR_ERR(sunxi_ehci->ahb_ehci_clk); ++ } ++ ++ sunxi_ehci->reset = reset_control_get(&pdev->dev, "ehci_reset"); ++ if (IS_ERR(sunxi_ehci->reset)) ++ { ++ dev_err(&pdev->dev, "failed to get ehci_reset reset line\n"); ++ return PTR_ERR(sunxi_ehci->reset); ++ } ++ ++ return 0; ++} ++ ++static int sunxi_ehci_probe(struct platform_device *pdev) ++{ ++ struct sunxi_ehci_hcd *sunxi_ehci = NULL; ++ struct usb_hcd *hcd = NULL; ++ int ret; ++ ++ if (pdev->num_resources != 4) { ++ dev_err(&pdev->dev, "invalid number of resources: %i\n", ++ pdev->num_resources); ++ return -ENODEV; ++ } ++ ++ if (pdev->resource[0].flags != IORESOURCE_MEM ++ || pdev->resource[1].flags != IORESOURCE_MEM ++ || pdev->resource[2].flags != IORESOURCE_MEM ++ || pdev->resource[3].flags != IORESOURCE_IRQ) { ++ dev_err(&pdev->dev, "invalid resource type\n"); ++ return -ENODEV; ++ } ++ ++ if (!pdev->dev.dma_mask) ++ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; ++ if (!pdev->dev.coherent_dma_mask) ++ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); ++ ++ hcd = usb_create_hcd(&sunxi_ehci_hc_driver, &pdev->dev, ++ dev_name(&pdev->dev)); ++ if (!hcd) { ++ dev_err(&pdev->dev, "unable to create HCD\n"); ++ return -ENOMEM; ++ } ++ ++ platform_set_drvdata(pdev, hcd); ++ ++ sunxi_ehci = (struct sunxi_ehci_hcd *)hcd_to_ehci(hcd)->priv; ++ ret = sunxi_ehci_init(pdev, hcd, sunxi_ehci); ++ if (ret) ++ goto fail1; ++ ++ ret = sunxi_ehci_enable(sunxi_ehci); ++ if (ret) ++ goto fail1; ++ ++ ret = usb_add_hcd(hcd, sunxi_ehci->irq, IRQF_SHARED | IRQF_DISABLED); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to add USB HCD\n"); ++ goto fail2; ++ } ++ ++ return 0; ++ ++fail2: ++ sunxi_ehci_disable(sunxi_ehci); ++ ++fail1: ++ usb_put_hcd(hcd); ++ return ret; ++} ++ ++static int sunxi_ehci_remove(struct platform_device *pdev) ++{ ++ struct usb_hcd *hcd = platform_get_drvdata(pdev); ++ struct sunxi_ehci_hcd *sunxi_ehci = NULL; ++ ++ sunxi_ehci = (struct sunxi_ehci_hcd *)hcd_to_ehci(hcd)->priv; ++ ++ usb_remove_hcd(hcd); ++ ++ sunxi_ehci_disable(sunxi_ehci); ++ ++ usb_put_hcd(hcd); ++ ++ return 0; ++} ++ ++static void sunxi_ehci_shutdown(struct platform_device *pdev) ++{ ++ struct usb_hcd *hcd = platform_get_drvdata(pdev); ++ struct sunxi_ehci_hcd *sunxi_ehci = NULL; ++ ++ sunxi_ehci = (struct sunxi_ehci_hcd *)hcd_to_ehci(hcd)->priv; ++ ++ usb_hcd_platform_shutdown(pdev); ++ ++ sunxi_ehci_disable(sunxi_ehci); ++} ++ ++static const struct of_device_id ehci_of_match[] = { ++ {.compatible = "allwinner,sunxi-ehci"}, ++ {}, ++}; ++ ++static struct platform_driver ehci_sunxi_driver = { ++ .driver = { ++ .of_match_table = ehci_of_match, ++ .name = DRV_NAME, ++ .pm = SUNXI_EHCI_PMOPS, ++ }, ++ .probe = sunxi_ehci_probe, ++ .remove = sunxi_ehci_remove, ++ .shutdown = sunxi_ehci_shutdown, ++}; ++ ++static int __init sunxi_ehci_init_module(void) ++{ ++ if (usb_disabled()) ++ return -ENODEV; ++ ++ pr_info(DRV_NAME ": " DRV_DESC "\n"); ++ ++ ehci_init_driver(&sunxi_ehci_hc_driver, &sunxi_overrides); ++ ++ return platform_driver_register(&ehci_sunxi_driver); ++} ++module_init(sunxi_ehci_init_module); ++ ++static void __exit sunxi_ehci_exit_module(void) ++{ ++ platform_driver_unregister(&ehci_sunxi_driver); ++} ++module_exit(sunxi_ehci_exit_module); ++ ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:" DRV_NAME); ++MODULE_DEVICE_TABLE(of, ehci_of_match); ++MODULE_AUTHOR("Roman Byshko <rbyshko@gmail.com>"); +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/173-1-dt-sun4i-add-usbclock-nodes.patch b/target/linux/sunxi/patches-3.13/173-1-dt-sun4i-add-usbclock-nodes.patch new file mode 100644 index 0000000000..1d702d81dc --- /dev/null +++ b/target/linux/sunxi/patches-3.13/173-1-dt-sun4i-add-usbclock-nodes.patch @@ -0,0 +1,32 @@ +From 04f41bafdff26bd895f2a1f894fd427779d7ed51 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Thu, 19 Sep 2013 21:58:47 +0200 +Subject: [PATCH] ARM: sun4i: dt: Add bindings for USB clocks + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun4i-a10.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi +index 731b491..c9913c0 100644 +--- a/arch/arm/boot/dts/sun4i-a10.dtsi ++++ b/arch/arm/boot/dts/sun4i-a10.dtsi +@@ -93,6 +93,14 @@ + clock-output-names = "pll6_sata", "pll6_other", "pll6"; + }; + ++ usb:usb@0x01c200cc { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun47i-usb-gates-clk"; ++ reg = <0x01c200cc 0x4>; ++ clocks = <&pll6 1>; ++ clock-output-names = "usb_ohci0", "usb_ohci1", "usb_phy"; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/173-2-dt-sun4i-add-ehci-bindings.patch b/target/linux/sunxi/patches-3.13/173-2-dt-sun4i-add-ehci-bindings.patch new file mode 100644 index 0000000000..b00e6d9b0f --- /dev/null +++ b/target/linux/sunxi/patches-3.13/173-2-dt-sun4i-add-ehci-bindings.patch @@ -0,0 +1,63 @@ +From ec53e86224acaa3891148fa298bb1504f3579d6b Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Wed, 18 Sep 2013 00:30:04 +0200 +Subject: [PATCH] ARM: sun4i: dt: Add USB EHCI bindings + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> + +Conflicts: + arch/arm/boot/dts/sun4i-a10.dtsi +--- + arch/arm/boot/dts/sun4i-a10.dtsi | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi +index c9913c0..64eda82 100644 +--- a/arch/arm/boot/dts/sun4i-a10.dtsi ++++ b/arch/arm/boot/dts/sun4i-a10.dtsi +@@ -17,6 +17,8 @@ + + aliases { + ethernet0 = &emac; ++ ehci1 = &ehci0; ++ ehci2 = &ehci1; + }; + + cpus { +@@ -556,5 +558,33 @@ + clock-frequency = <100000>; + status = "disabled"; + }; ++ ++ usb_rst: reset@0x01c200cc { ++ #reset-cells = <1>; ++ compatible = "allwinner,sun4i-clock-reset"; ++ reg = <0x01c200cc 0x4>; ++ }; ++ ++ ehci0: ehci0@0x01c14000 { ++ compatible = "allwinner,sunxi-ehci"; ++ reg = <0x01c14000 0x400 0x01c14800 0x4 0x01c13404 0x4>; ++ interrupts = <39>; ++ resets = <&usb_rst 1>; ++ reset-names = "ehci_reset"; ++ clocks = <&usb 8>, <&ahb_gates 1>; ++ clock-names = "usb_phy", "ahb_ehci"; ++ status = "disabled"; ++ }; ++ ++ ehci1: ehci1@0x01c1c000 { ++ compatible = "allwinner,sunxi-ehci"; ++ reg = <0x01c1c000 0x400 0x01c1c800 0x4 0x01c13404 0x4>; ++ interrupts = <40>; ++ resets = <&usb_rst 2>; ++ reset-names = "ehci_reset"; ++ clocks = <&usb 8>, <&ahb_gates 3>; ++ clock-names = "usb_phy", "ahb_ehci"; ++ status = "disabled"; ++ }; + }; + }; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/173-3-dt-sun4i-add-ehci-cubieboard.patch b/target/linux/sunxi/patches-3.13/173-3-dt-sun4i-add-ehci-cubieboard.patch new file mode 100644 index 0000000000..a71e6b4d43 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/173-3-dt-sun4i-add-ehci-cubieboard.patch @@ -0,0 +1,86 @@ +From 875bbd46c296e4b9ed130848bc64be5cf39669c8 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Wed, 18 Sep 2013 22:45:06 +0200 +Subject: [PATCH] ARM: sun4i: dt: Add EHCI bindings to Cubieboard-A10 + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> + +Conflicts: + arch/arm/boot/dts/sun4i-a10-cubieboard.dts +--- + arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 46 ++++++++++++++++++++++++++++++ + 1 file changed, 46 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts +index 53ac453..48864a4 100644 +--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts ++++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts +@@ -77,6 +77,20 @@ + allwinner,drive = <1>; + allwinner,pull = <0>; + }; ++ ++ usb1_vbus_pin: usb1_vbus_pin@0 { ++ allwinner,pins = "PH6"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; ++ ++ usb2_vbus_pin: usb2_vbus_pin@0 { ++ allwinner,pins = "PH3"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; + }; + + uart0: serial@01c28000 { +@@ -96,6 +110,16 @@ + pinctrl-0 = <&i2c1_pins_a>; + status = "okay"; + }; ++ ++ ehci0: ehci0@0x01c14000 { ++ vbus-supply = <®_usb1_vbus>; ++ status = "okay"; ++ }; ++ ++ ehci1: ehci1@0x01c1c000 { ++ vbus-supply = <®_usb2_vbus>; ++ status = "okay"; ++ }; + }; + + leds { +@@ -128,5 +152,27 @@ + gpio = <&pio 1 8 0>; + enable-active-high; + }; ++ ++ reg_usb1_vbus: usb1-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb1_vbus_pin>; ++ regulator-name = "usb1-vbus"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ enable-active-high; ++ gpio = <&pio 7 6 0>; ++ }; ++ ++ reg_usb2_vbus: usb2-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb2_vbus_pin>; ++ regulator-name = "usb2-vbus"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ enable-active-high; ++ gpio = <&pio 7 3 0>; ++ }; + }; + }; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/173-4-dt-sun4i-add-ehci-a1000.patch b/target/linux/sunxi/patches-3.13/173-4-dt-sun4i-add-ehci-a1000.patch new file mode 100644 index 0000000000..f9a7125d2d --- /dev/null +++ b/target/linux/sunxi/patches-3.13/173-4-dt-sun4i-add-ehci-a1000.patch @@ -0,0 +1,83 @@ +From 9a86b6c16abc11b1090fbf4e102b4eed1d474d96 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Wed, 18 Sep 2013 00:30:40 +0200 +Subject: [PATCH] ARM: sun4i: dt: Add EHCI bindings to the Mele A1000 + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun4i-a10-a1000.dts | 46 +++++++++++++++++++++++++++++++++++ + 1 file changed, 46 insertions(+) + +diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts +index fd6d512..e3bfc59 100644 +--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts ++++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts +@@ -73,6 +73,20 @@ + allwinner,drive = <0>; + allwinner,pull = <0>; + }; ++ ++ usb1_vbus_pin: usb1_vbus_pin@0 { ++ allwinner,pins = "PH6"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; ++ ++ usb2_vbus_pin: usb2_vbus_pin@0 { ++ allwinner,pins = "PH3"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; + }; + + uart0: serial@01c28000 { +@@ -86,6 +100,16 @@ + pinctrl-0 = <&i2c0_pins_a>; + status = "okay"; + }; ++ ++ ehci0: ehci0@0x01c14000 { ++ vbus-supply = <®_usb1_vbus>; ++ status = "okay"; ++ }; ++ ++ ehci1: ehci1@0x01c1c000 { ++ vbus-supply = <®_usb2_vbus>; ++ status = "okay"; ++ }; + }; + + leds { +@@ -117,5 +141,27 @@ + enable-active-high; + gpio = <&pio 7 15 0>; + }; ++ ++ reg_usb1_vbus: usb1-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb1_vbus_pin>; ++ regulator-name = "usb1-vbus"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ enable-active-high; ++ gpio = <&pio 7 6 0>; ++ }; ++ ++ reg_usb2_vbus: usb2-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb2_vbus_pin>; ++ regulator-name = "usb2-vbus"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ enable-active-high; ++ gpio = <&pio 7 3 0>; ++ }; + }; + }; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/174-1-dt-sun7i-add-usbclock-nodes.patch b/target/linux/sunxi/patches-3.13/174-1-dt-sun7i-add-usbclock-nodes.patch new file mode 100644 index 0000000000..7f2f080db3 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/174-1-dt-sun7i-add-usbclock-nodes.patch @@ -0,0 +1,32 @@ +From b7739d837e1176b2206ee541075c9eba0a263695 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Thu, 19 Sep 2013 21:24:20 +0200 +Subject: [PATCH] ARM: sun7i: dt: Add bindings for USB clocks + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun7i-a20.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 3242a29..4eddc79 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -89,6 +89,14 @@ + clock-output-names = "pll6_sata", "pll6_other", "pll6"; + }; + ++ usb:usb@0x01c200cc { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun47i-usb-gates-clk"; ++ reg = <0x01c200cc 0x4>; ++ clocks = <&pll6 1>; ++ clock-output-names = "usb_ohci0", "usb_ohci1", "usb_phy"; ++ }; ++ + cpu: cpu@01c20054 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-cpu-clk"; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/174-2-dt-sun7i-add-ehci-bindings.patch b/target/linux/sunxi/patches-3.13/174-2-dt-sun7i-add-ehci-bindings.patch new file mode 100644 index 0000000000..779ad3cdec --- /dev/null +++ b/target/linux/sunxi/patches-3.13/174-2-dt-sun7i-add-ehci-bindings.patch @@ -0,0 +1,63 @@ +From a82eb088ea3fa4c25b256400690a30f4b0392e91 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Thu, 19 Sep 2013 21:36:10 +0200 +Subject: [PATCH] ARM: sun7i: dt: Add USB EHCI bindings + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> + +Conflicts: + arch/arm/boot/dts/sun7i-a20.dtsi +--- + arch/arm/boot/dts/sun7i-a20.dtsi | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 4eddc79..956b5cd 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -18,6 +18,8 @@ + + aliases { + ethernet0 = &gmac; ++ ehci1 = &ehci0; ++ ehci2 = &ehci1; + }; + + cpus { +@@ -652,5 +654,33 @@ + #interrupt-cells = <3>; + interrupts = <1 9 0xf04>; + }; ++ ++ usb_rst: reset@0x01c200cc { ++ #reset-cells = <1>; ++ compatible = "allwinner,sun4i-clock-reset"; ++ reg = <0x01c200cc 0x4>; ++ }; ++ ++ ehci0: ehci0@0x01c14000 { ++ compatible = "allwinner,sunxi-ehci"; ++ reg = <0x01c14000 0x400 0x01c14800 0x4 0x01c13404 0x4>; ++ interrupts = <0 39 1>; ++ resets = <&usb_rst 1>; ++ reset-names = "ehci_reset"; ++ clocks = <&usb 8>, <&ahb_gates 1>; ++ clock-names = "usb_phy", "ahb_ehci"; ++ status = "disabled"; ++ }; ++ ++ ehci1: ehci1@0x01c1c000 { ++ compatible = "allwinner,sunxi-ehci"; ++ reg = <0x01c1c000 0x400 0x01c1c800 0x4 0x01c13404 0x4>; ++ interrupts = <0 40 1>; ++ resets = <&usb_rst 2>; ++ reset-names = "ehci_reset"; ++ clocks = <&usb 8>, <&ahb_gates 3>; ++ clock-names = "usb_phy", "ahb_ehci"; ++ status = "disabled"; ++ }; + }; + }; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/174-3-dt-sun7i-add-ehci-cubieboard2.patch b/target/linux/sunxi/patches-3.13/174-3-dt-sun7i-add-ehci-cubieboard2.patch new file mode 100644 index 0000000000..0f00c2564e --- /dev/null +++ b/target/linux/sunxi/patches-3.13/174-3-dt-sun7i-add-ehci-cubieboard2.patch @@ -0,0 +1,85 @@ +From 8ba068f40cce9612d2ac0879b6978274ab497d31 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Thu, 19 Sep 2013 21:29:45 +0200 +Subject: [PATCH] ARM: sun7i: dt: Add USB EHCI bindings for Cubieboard2 + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> + +Conflicts: + arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +--- + arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 45 +++++++++++++++++++++++++++++ + 1 file changed, 45 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +index a26711c..10ea99d 100644 +--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts ++++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +@@ -54,6 +54,20 @@ + allwinner,drive = <0>; + allwinner,pull = <0>; + }; ++ ++ usb1_vbus_pin: usb1_vbus_pin@0 { ++ allwinner,pins = "PH6"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; ++ ++ usb2_vbus_pin: usb2_vbus_pin@0 { ++ allwinner,pins = "PH3"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; + }; + + uart0: serial@01c28000 { +@@ -71,6 +85,15 @@ + i2c1: i2c@01c2b000 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins_a>; ++ }; ++ ++ ehci0: ehci0@0x01c14000 { ++ vbus-supply = <®_usb1_vbus>; ++ status = "okay"; ++ }; ++ ++ ehci1: ehci1@0x01c1c000 { ++ vbus-supply = <®_usb2_vbus>; + status = "okay"; + }; + +@@ -112,5 +135,27 @@ + gpio = <&pio 1 8 0>; + enable-active-high; + }; ++ ++ reg_usb1_vbus: usb1-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb1_vbus_pin>; ++ regulator-name = "usb1-vbus"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ enable-active-high; ++ gpio = <&pio 7 6 0>; ++ }; ++ ++ reg_usb2_vbus: usb2-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb2_vbus_pin>; ++ regulator-name = "usb2-vbus"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ enable-active-high; ++ gpio = <&pio 7 3 0>; ++ }; + }; + }; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/174-4-dt-sun7i-add-ehci-olinuxino-a20-micro.patch b/target/linux/sunxi/patches-3.13/174-4-dt-sun7i-add-ehci-olinuxino-a20-micro.patch new file mode 100644 index 0000000000..41f55da03f --- /dev/null +++ b/target/linux/sunxi/patches-3.13/174-4-dt-sun7i-add-ehci-olinuxino-a20-micro.patch @@ -0,0 +1,91 @@ +From 5031cb9d88fe9ea4a37fe342ec5f8e2f0f930e00 Mon Sep 17 00:00:00 2001 +From: Zalan Blenessy <zalan.blenessy@gmail.com> +Date: Sun, 22 Dec 2013 17:08:10 +0100 +Subject: [PATCH] ARM: dts: sun7i: Add ehci nodes to Olinuxino A20 Micro dts + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 47 +++++++++++++++++++++++++ + 1 file changed, 47 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +index 20b1000..5f13ed64 100644 +--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts ++++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +@@ -70,6 +70,20 @@ + allwinner,drive = <1>; + allwinner,pull = <0>; + }; ++ ++ usb1_vbus_pin: usb1_vbus_pin@0 { ++ allwinner,pins = "PH6"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; ++ ++ usb2_vbus_pin: usb2_vbus_pin@0 { ++ allwinner,pins = "PH3"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; + }; + + uart0: serial@01c28000 { +@@ -115,6 +129,16 @@ + phy-mode = "mii"; + status = "okay"; + }; ++ ++ ehci0: ehci0@0x01c14000 { ++ vbus-supply = <®_usb1_vbus>; ++ status = "okay"; ++ }; ++ ++ ehci1: ehci1@0x01c1c000 { ++ vbus-supply = <®_usb2_vbus>; ++ status = "okay"; ++ }; + }; + + leds { +@@ -131,6 +155,7 @@ + + regulators { + compatible = "simple-bus"; ++ pinctrl-names = "default"; + + reg_ahci_5v: ahci-5v { + compatible = "regulator-fixed"; +@@ -141,5 +166,27 @@ + gpio = <&pio 1 8 0>; + enable-active-high; + }; ++ ++ reg_usb1_vbus: usb1-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb1_vbus_pin>; ++ regulator-name = "usb1-vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ enable-active-high; ++ gpio = <&pio 7 6 0>; ++ }; ++ ++ reg_usb2_vbus: usb2-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb2_vbus_pin>; ++ regulator-name = "usb2-vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ enable-active-high; ++ gpio = <&pio 7 3 0>; ++ }; + }; + }; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/174-5-dt-sun7i-add-ehci-cubietruck.patch b/target/linux/sunxi/patches-3.13/174-5-dt-sun7i-add-ehci-cubietruck.patch new file mode 100644 index 0000000000..0f77758d2a --- /dev/null +++ b/target/linux/sunxi/patches-3.13/174-5-dt-sun7i-add-ehci-cubietruck.patch @@ -0,0 +1,88 @@ +From 90cab9a5e7c43bfbda25dd114a838f4e4b50b6ff Mon Sep 17 00:00:00 2001 +From: Hans de Goede <hdegoede@redhat.com> +Date: Tue, 17 Dec 2013 23:04:57 +0100 +Subject: [PATCH] ARM: dts: sun7i: Add ehci nodes to cubietruck dts + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 46 ++++++++++++++++++++++++++++++ + 1 file changed, 46 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts +index a5f3418..c8b3ea9 100644 +--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts ++++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts +@@ -28,11 +28,21 @@ + status = "okay"; + }; + ++ ehci0: ehci0@0x01c14000 { ++ vbus-supply = <®_usb1_vbus>; ++ status = "okay"; ++ }; ++ + sata: ahci@01c18000 { + pwr-supply = <®_ahci_5v>; + status = "okay"; + }; + ++ ehci1: ehci1@0x01c1c000 { ++ vbus-supply = <®_usb2_vbus>; ++ status = "okay"; ++ }; ++ + pinctrl@01c20800 { + mmc0_cd_pin_cubietruck: mmc0_cd_pin@0 { + allwinner,pins = "PH1"; +@@ -54,6 +64,20 @@ + allwinner,drive = <0>; + allwinner,pull = <0>; + }; ++ ++ usb1_vbus_pin: usb1_vbus_pin@0 { ++ allwinner,pins = "PH6"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; ++ ++ usb2_vbus_pin: usb2_vbus_pin@0 { ++ allwinner,pins = "PH3"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; + }; + + uart0: serial@01c28000 { +@@ -110,5 +134,27 @@ + gpio = <&pio 7 12 0>; + enable-active-high; + }; ++ ++ reg_usb1_vbus: usb1-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb1_vbus_pin>; ++ regulator-name = "usb1-vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ enable-active-high; ++ gpio = <&pio 7 6 0>; ++ }; ++ ++ reg_usb2_vbus: usb2-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb2_vbus_pin>; ++ regulator-name = "usb2-vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ enable-active-high; ++ gpio = <&pio 7 3 0>; ++ }; + }; + }; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/175-1-dt-sun5i-add-usbclock-nodes.patch b/target/linux/sunxi/patches-3.13/175-1-dt-sun5i-add-usbclock-nodes.patch new file mode 100644 index 0000000000..8adcde5694 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/175-1-dt-sun5i-add-usbclock-nodes.patch @@ -0,0 +1,32 @@ +From f017ea35bd87e7935fbf5a03bc016d8b1efa03c0 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Tue, 24 Sep 2013 20:02:39 +0200 +Subject: [PATCH] ARM: sun5i: dt: Add bindings for USB Host clocks + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun5i-a13.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi +index 2dde48a..1a416d0 100644 +--- a/arch/arm/boot/dts/sun5i-a13.dtsi ++++ b/arch/arm/boot/dts/sun5i-a13.dtsi +@@ -90,6 +90,14 @@ + clock-output-names = "pll6_sata", "pll6_other", "pll6"; + }; + ++ usb:usb@0x01c200cc { ++ #clock-cells = <1>; ++ compatible = "allwinner,sun5i-usb-gates-clk"; ++ reg = <0x01c200cc 0x4>; ++ clocks = <&pll6 1>; ++ clock-output-names = "usb_ohci0", "usb_phy"; ++ }; ++ + /* dummy is 200M */ + cpu: cpu@01c20054 { + #clock-cells = <0>; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/175-2-dt-sun5i-add-ehci-bindings.patch b/target/linux/sunxi/patches-3.13/175-2-dt-sun5i-add-ehci-bindings.patch new file mode 100644 index 0000000000..1434cfe1a6 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/175-2-dt-sun5i-add-ehci-bindings.patch @@ -0,0 +1,51 @@ +From 3d3aa5f5c67d3f860b68def6a0ffce5e7175f85e Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Tue, 24 Sep 2013 20:03:40 +0200 +Subject: [PATCH] ARM: sun5i: dt: Add USB EHCI bindings + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun5i-a13.dtsi | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi +index 1a416d0..5bf7e9a 100644 +--- a/arch/arm/boot/dts/sun5i-a13.dtsi ++++ b/arch/arm/boot/dts/sun5i-a13.dtsi +@@ -16,6 +16,10 @@ + / { + interrupt-parent = <&intc>; + ++ aliases { ++ ehci1 = &ehci0; ++ }; ++ + cpus { + #address-cells = <1>; + #size-cells = <0>; +@@ -416,5 +420,22 @@ + interrupts = <82>, <83>; + clocks = <&ahb_gates 28>; + }; ++ ++ usb_rst: reset@0x01c200cc { ++ #reset-cells = <1>; ++ compatible = "allwinner,sun4i-clock-reset"; ++ reg = <0x01c200cc 0x4>; ++ }; ++ ++ ehci0: ehci0@0x01c14000 { ++ compatible = "allwinner,sunxi-ehci"; ++ reg = <0x01c14000 0x400 0x01c14800 0x4 0x01c13404 0x4>; ++ interrupts = <39>; ++ resets = <&usb_rst 1>; ++ reset-names = "ehci_reset"; ++ clocks = <&usb 8>, <&ahb_gates 1>; ++ clock-names = "usb_phy", "ahb_ehci"; ++ status = "disabled"; ++ }; + }; + }; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/175-3-dt-sun5i-add-ehci-a13.patch b/target/linux/sunxi/patches-3.13/175-3-dt-sun5i-add-ehci-a13.patch new file mode 100644 index 0000000000..8dbc37c09e --- /dev/null +++ b/target/linux/sunxi/patches-3.13/175-3-dt-sun5i-add-ehci-a13.patch @@ -0,0 +1,63 @@ +From 586c4aa0aeb07dacccb25a419a7b6625521ddea8 Mon Sep 17 00:00:00 2001 +From: arokux <arokux@gmail.com> +Date: Tue, 24 Sep 2013 20:07:53 +0200 +Subject: [PATCH] ARM: sun5i: dt: Add EHCI bindings to A13-Olinuxino + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun5i-a13-olinuxino.dts | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts +index cf77d9a..4b73e3e 100644 +--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts ++++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts +@@ -46,6 +46,13 @@ + allwinner,drive = <1>; + allwinner,pull = <0>; + }; ++ ++ usb1_vbus_pin: usb1_vbus_pin@0 { ++ allwinner,pins = "PG11"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = <0>; ++ allwinner,pull = <2>; ++ }; + }; + + uart1: serial@01c28400 { +@@ -71,6 +78,11 @@ + pinctrl-0 = <&i2c2_pins_a>; + status = "okay"; + }; ++ ++ ehci0: ehci0@0x01c14000 { ++ vbus-supply = <®_usb1_vbus>; ++ status = "okay"; ++ }; + }; + + leds { +@@ -83,4 +95,19 @@ + default-state = "on"; + }; + }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ ++ reg_usb1_vbus: usb1-vbus { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb1_vbus_pin>; ++ regulator-name = "usb1-vbus"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ enable-active-high; ++ gpio = <&pio 6 11 0>; ++ }; ++ }; + }; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/176-dt-sunxi-update-usb-regulator.patch b/target/linux/sunxi/patches-3.13/176-dt-sunxi-update-usb-regulator.patch new file mode 100644 index 0000000000..0db0f2b8f6 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/176-dt-sunxi-update-usb-regulator.patch @@ -0,0 +1,109 @@ +From b0a614458fb67fdb53e1b5518dabb85d688b196e Mon Sep 17 00:00:00 2001 +From: Hans de Goede <hdegoede@redhat.com> +Date: Tue, 17 Dec 2013 22:59:17 +0100 +Subject: [PATCH] ARM: dts: sunxi: usb Vbus is 5v not 3.3v + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun4i-a10-a1000.dts | 8 ++++---- + arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 8 ++++---- + arch/arm/boot/dts/sun5i-a13-olinuxino.dts | 4 ++-- + arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 8 ++++---- + 4 files changed, 14 insertions(+), 14 deletions(-) + +diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts +index e3bfc59..315e607 100644 +--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts ++++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts +@@ -147,8 +147,8 @@ + pinctrl-names = "default"; + pinctrl-0 = <&usb1_vbus_pin>; + regulator-name = "usb1-vbus"; +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; + enable-active-high; + gpio = <&pio 7 6 0>; + }; +@@ -158,8 +158,8 @@ + pinctrl-names = "default"; + pinctrl-0 = <&usb2_vbus_pin>; + regulator-name = "usb2-vbus"; +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; + enable-active-high; + gpio = <&pio 7 3 0>; + }; +diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts +index 48864a4..0bd2aae 100644 +--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts ++++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts +@@ -158,8 +158,8 @@ + pinctrl-names = "default"; + pinctrl-0 = <&usb1_vbus_pin>; + regulator-name = "usb1-vbus"; +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; + enable-active-high; + gpio = <&pio 7 6 0>; + }; +@@ -169,8 +169,8 @@ + pinctrl-names = "default"; + pinctrl-0 = <&usb2_vbus_pin>; + regulator-name = "usb2-vbus"; +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; + enable-active-high; + gpio = <&pio 7 3 0>; + }; +diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts +index 4b73e3e..b255d1b 100644 +--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts ++++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts +@@ -104,8 +104,8 @@ + pinctrl-names = "default"; + pinctrl-0 = <&usb1_vbus_pin>; + regulator-name = "usb1-vbus"; +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; + enable-active-high; + gpio = <&pio 6 11 0>; + }; +diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +index 10ea99d..144b11a 100644 +--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts ++++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +@@ -141,8 +141,8 @@ + pinctrl-names = "default"; + pinctrl-0 = <&usb1_vbus_pin>; + regulator-name = "usb1-vbus"; +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; + enable-active-high; + gpio = <&pio 7 6 0>; + }; +@@ -152,8 +152,8 @@ + pinctrl-names = "default"; + pinctrl-0 = <&usb2_vbus_pin>; + regulator-name = "usb2-vbus"; +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; + enable-active-high; + gpio = <&pio 7 3 0>; + }; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/177-dt-sun7i-fix-ehci-irqtypes.patch b/target/linux/sunxi/patches-3.13/177-dt-sun7i-fix-ehci-irqtypes.patch new file mode 100644 index 0000000000..9b4575e800 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/177-dt-sun7i-fix-ehci-irqtypes.patch @@ -0,0 +1,35 @@ +From 06285d1c64552291f136eb197b6f05bc9d9c1d0e Mon Sep 17 00:00:00 2001 +From: Hans de Goede <hdegoede@redhat.com> +Date: Tue, 17 Dec 2013 23:26:45 +0100 +Subject: [PATCH] ARM: dts: sun7i: Fix ehci interrupt types + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/boot/dts/sun7i-a20.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 956b5cd..2e19c47 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -664,7 +664,7 @@ + ehci0: ehci0@0x01c14000 { + compatible = "allwinner,sunxi-ehci"; + reg = <0x01c14000 0x400 0x01c14800 0x4 0x01c13404 0x4>; +- interrupts = <0 39 1>; ++ interrupts = <0 39 4>; + resets = <&usb_rst 1>; + reset-names = "ehci_reset"; + clocks = <&usb 8>, <&ahb_gates 1>; +@@ -675,7 +675,7 @@ + ehci1: ehci1@0x01c1c000 { + compatible = "allwinner,sunxi-ehci"; + reg = <0x01c1c000 0x400 0x01c1c800 0x4 0x01c13404 0x4>; +- interrupts = <0 40 1>; ++ interrupts = <0 40 4>; + resets = <&usb_rst 2>; + reset-names = "ehci_reset"; + clocks = <&usb 8>, <&ahb_gates 3>; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/178-sunxi-ehci-fix-resource-check.patch b/target/linux/sunxi/patches-3.13/178-sunxi-ehci-fix-resource-check.patch new file mode 100644 index 0000000000..0f472b3582 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/178-sunxi-ehci-fix-resource-check.patch @@ -0,0 +1,27 @@ +From e772c9c2f552740ae735328cbd06b1d7f8e9d885 Mon Sep 17 00:00:00 2001 +From: Hans de Goede <hdegoede@redhat.com> +Date: Tue, 17 Dec 2013 23:27:03 +0100 +Subject: [PATCH] ARM: sunxi-ehci: Fix resource check + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + drivers/usb/host/ehci-sunxi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c +index e7e15cc..e050d78 100644 +--- a/drivers/usb/host/ehci-sunxi.c ++++ b/drivers/usb/host/ehci-sunxi.c +@@ -332,7 +332,8 @@ static int sunxi_ehci_probe(struct platform_device *pdev) + if (pdev->resource[0].flags != IORESOURCE_MEM + || pdev->resource[1].flags != IORESOURCE_MEM + || pdev->resource[2].flags != IORESOURCE_MEM +- || pdev->resource[3].flags != IORESOURCE_IRQ) { ++ || (pdev->resource[3].flags & IORESOURCE_TYPE_BITS) ++ != IORESOURCE_IRQ) { + dev_err(&pdev->dev, "invalid resource type\n"); + return -ENODEV; + } +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/180-sunxi-select-PSCI.patch b/target/linux/sunxi/patches-3.13/180-sunxi-select-PSCI.patch new file mode 100644 index 0000000000..3c7f178579 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/180-sunxi-select-PSCI.patch @@ -0,0 +1,27 @@ +From d46cebc1431948638fe4e6cfd27fb9da48e6c593 Mon Sep 17 00:00:00 2001 +From: Zalan Blenessy <zalan.blenessy@gmail.com> +Date: Sun, 22 Dec 2013 17:10:06 +0100 +Subject: [PATCH] ARM: sunxi: select ARM_PSCI + +This is necessary for SMP on sun7i. + +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +--- + arch/arm/mach-sunxi/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig +index 547004c..09df4b81 100644 +--- a/arch/arm/mach-sunxi/Kconfig ++++ b/arch/arm/mach-sunxi/Kconfig +@@ -3,6 +3,7 @@ config ARCH_SUNXI + select ARCH_HAS_RESET_CONTROLLER + select ARCH_REQUIRE_GPIOLIB + select ARM_GIC ++ select ARM_PSCI + select CLKSRC_MMIO + select CLKSRC_OF + select COMMON_CLK +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/190-stmmac-enable-main-clock-when-probing.patch b/target/linux/sunxi/patches-3.13/190-stmmac-enable-main-clock-when-probing.patch new file mode 100644 index 0000000000..f7085843d3 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/190-stmmac-enable-main-clock-when-probing.patch @@ -0,0 +1,71 @@ +From 133a9b75e2b0c48cd1d8f93b0ee61089821c32d9 Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai <wens@csie.org> +Date: Sat, 7 Dec 2013 01:29:34 +0800 +Subject: [PATCH] net: stmmac: Enable stmmac main clock when probing hardware + +Signed-off-by: Chen-Yu Tsai <wens@csie.org> +--- + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 24 +++++++++++++---------- + 1 file changed, 14 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +index 8a7a23a..4d75cba 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -2682,10 +2682,17 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, + if ((phyaddr >= 0) && (phyaddr <= 31)) + priv->plat->phy_addr = phyaddr; + ++ priv->stmmac_clk = clk_get(priv->device, STMMAC_RESOURCE_NAME); ++ if (IS_ERR(priv->stmmac_clk)) { ++ pr_warn("%s: warning: cannot get CSR clock\n", __func__); ++ goto error_clk_get; ++ } ++ clk_prepare_enable(priv->stmmac_clk); ++ + /* Init MAC and get the capabilities */ + ret = stmmac_hw_init(priv); + if (ret) +- goto error_free_netdev; ++ goto error_hw_init; + + ndev->netdev_ops = &stmmac_netdev_ops; + +@@ -2723,12 +2730,6 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, + goto error_netdev_register; + } + +- priv->stmmac_clk = clk_get(priv->device, STMMAC_RESOURCE_NAME); +- if (IS_ERR(priv->stmmac_clk)) { +- pr_warn("%s: warning: cannot get CSR clock\n", __func__); +- goto error_clk_get; +- } +- + /* If a specific clk_csr value is passed from the platform + * this means that the CSR Clock Range selection cannot be + * changed at run-time and it is fixed. Viceversa the driver'll try to +@@ -2753,15 +2754,18 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, + } + } + ++ clk_disable_unprepare(priv->stmmac_clk); ++ + return priv; + + error_mdio_register: +- clk_put(priv->stmmac_clk); +-error_clk_get: + unregister_netdev(ndev); + error_netdev_register: + netif_napi_del(&priv->napi); +-error_free_netdev: ++error_hw_init: ++ clk_disable_unprepare(priv->stmmac_clk); ++ clk_put(priv->stmmac_clk); ++error_clk_get: + free_netdev(ndev); + + return NULL; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/191-stmmac-honor-DT-params.patch b/target/linux/sunxi/patches-3.13/191-stmmac-honor-DT-params.patch new file mode 100644 index 0000000000..6f0b02e02a --- /dev/null +++ b/target/linux/sunxi/patches-3.13/191-stmmac-honor-DT-params.patch @@ -0,0 +1,29 @@ +From a2acf761e37031737300c47284181a21b6bc0cc2 Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai <wens@csie.org> +Date: Sat, 7 Dec 2013 01:29:35 +0800 +Subject: [PATCH] net: stmmac: Honor DT parameter to force DMA store and + forward mode + +"snps,force_sf_dma_mode" is documented in stmmac device tree bindings, +but is never handled by the driver. + +Signed-off-by: Chen-Yu Tsai <wens@csie.org> +--- + drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +index 51c9069..74c7aef 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +@@ -47,6 +47,7 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, + plat->bus_id = 0; + + of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr); ++ plat->force_sf_dma_mode = of_property_read_bool(np, "snps,force_sf_dma_mode"); + + plat->mdio_bus_data = devm_kzalloc(&pdev->dev, + sizeof(struct stmmac_mdio_bus_data), +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/192-stmmac-use-platform-data-with-compat.patch b/target/linux/sunxi/patches-3.13/192-stmmac-use-platform-data-with-compat.patch new file mode 100644 index 0000000000..70b50750a0 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/192-stmmac-use-platform-data-with-compat.patch @@ -0,0 +1,73 @@ +From 34722924d416c3521de2bc8d10dfcd07a55135ea Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai <wens@csie.org> +Date: Sat, 7 Dec 2013 01:29:36 +0800 +Subject: [PATCH] net: stmmac: Use platform data tied with compatible strings + +Signed-off-by: Chen-Yu Tsai <wens@csie.org> +--- + .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 29 ++++++++++++++-------- + 1 file changed, 19 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +index 74c7aef..df3fd1c 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +@@ -26,8 +26,19 @@ + #include <linux/io.h> + #include <linux/of.h> + #include <linux/of_net.h> ++#include <linux/of_device.h> + #include "stmmac.h" + ++static const struct of_device_id stmmac_dt_ids[] = { ++ { .compatible = "st,spear600-gmac"}, ++ { .compatible = "snps,dwmac-3.610"}, ++ { .compatible = "snps,dwmac-3.70a"}, ++ { .compatible = "snps,dwmac-3.710"}, ++ { .compatible = "snps,dwmac"}, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, stmmac_dt_ids); ++ + #ifdef CONFIG_OF + static int stmmac_probe_config_dt(struct platform_device *pdev, + struct plat_stmmacenet_data *plat, +@@ -35,10 +46,18 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, + { + struct device_node *np = pdev->dev.of_node; + struct stmmac_dma_cfg *dma_cfg; ++ const struct of_device_id *device; + + if (!np) + return -ENODEV; + ++ device = of_match_device(stmmac_dt_ids, &pdev->dev); ++ if (!device) ++ return -ENODEV; ++ ++ if (device->data) ++ memcpy(plat, device->data, sizeof(*plat)); ++ + *mac = of_get_mac_address(np); + plat->interface = of_get_phy_mode(np); + +@@ -257,16 +276,6 @@ int stmmac_pltfr_restore(struct device *dev) + static const struct dev_pm_ops stmmac_pltfr_pm_ops; + #endif /* CONFIG_PM */ + +-static const struct of_device_id stmmac_dt_ids[] = { +- { .compatible = "st,spear600-gmac"}, +- { .compatible = "snps,dwmac-3.610"}, +- { .compatible = "snps,dwmac-3.70a"}, +- { .compatible = "snps,dwmac-3.710"}, +- { .compatible = "snps,dwmac"}, +- { /* sentinel */ } +-}; +-MODULE_DEVICE_TABLE(of, stmmac_dt_ids); +- + struct platform_driver stmmac_pltfr_driver = { + .probe = stmmac_pltfr_probe, + .remove = stmmac_pltfr_remove, +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/193-stmmac-platform-ext-for-a20.patch b/target/linux/sunxi/patches-3.13/193-stmmac-platform-ext-for-a20.patch new file mode 100644 index 0000000000..9bc1bcbbf0 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/193-stmmac-platform-ext-for-a20.patch @@ -0,0 +1,204 @@ +From 3c6560eccfeee3a93d57c3b2206abfbe06459015 Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai <wens@csie.org> +Date: Sat, 7 Dec 2013 01:29:37 +0800 +Subject: [PATCH] net: stmmac: sunxi platfrom extensions for GMAC in Allwinner + A20 SoC's + +The Allwinner A20 has an ethernet controller that seems to be +an early version of Synopsys DesignWare MAC 10/100/1000 Universal, +which is supported by the stmmac driver. + +Allwinner's GMAC requires setting additional registers in the SoC's +clock control unit. + +The exact version of the DWMAC IP that Allwinner uses is unknown, +thus the exact feature set is unknown. + +Signed-off-by: Chen-Yu Tsai <wens@csie.org> +--- + .../bindings/net/allwinner,sun7i-gmac.txt | 22 +++++++ + drivers/net/ethernet/stmicro/stmmac/Kconfig | 12 ++++ + drivers/net/ethernet/stmicro/stmmac/Makefile | 1 + + drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c | 76 ++++++++++++++++++++++ + drivers/net/ethernet/stmicro/stmmac/stmmac.h | 3 + + .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 3 + + 6 files changed, 117 insertions(+) + create mode 100644 Documentation/devicetree/bindings/net/allwinner,sun7i-gmac.txt + create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c + +diff --git a/Documentation/devicetree/bindings/net/allwinner,sun7i-gmac.txt b/Documentation/devicetree/bindings/net/allwinner,sun7i-gmac.txt +new file mode 100644 +index 0000000..271554a +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/allwinner,sun7i-gmac.txt +@@ -0,0 +1,22 @@ ++* Allwinner GMAC ethernet controller ++ ++This device is a platform glue layer for stmmac. ++Please see stmmac.txt for the other unchanged properties. ++ ++Required properties: ++ - compatible: Should be "allwinner,sun7i-gmac" ++ - reg: Address and length of register set for the device and corresponding ++ clock control ++ ++Examples: ++ ++ gmac: ethernet@01c50000 { ++ compatible = "allwinner,sun7i-gmac"; ++ reg = <0x01c50000 0x10000>, ++ <0x01c20164 0x4>; ++ interrupts = <0 85 1>; ++ interrupt-names = "macirq"; ++ clocks = <&ahb_gates 49>; ++ clock-names = "stmmaceth"; ++ phy-mode = "mii"; ++ }; +diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig +index 6e52c0f..6d71210 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig ++++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig +@@ -25,6 +25,18 @@ config STMMAC_PLATFORM + + If unsure, say N. + ++config DWMAC_SUNXI ++ bool "Allwinner GMAC support" ++ depends on STMMAC_PLATFORM ++ depends on ARCH_SUNXI ++ default y ++ ---help--- ++ Support for Allwinner A20 GMAC ethernet driver. ++ ++ This selects Allwinner SoC glue layer support for the ++ stmmac device driver. This driver is used for A20 GMAC ++ ethernet controller. ++ + config STMMAC_PCI + bool "STMMAC PCI bus support" + depends on STMMAC_ETH && PCI +diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile +index 356a9dd..ecadece 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/Makefile ++++ b/drivers/net/ethernet/stmicro/stmmac/Makefile +@@ -1,6 +1,7 @@ + obj-$(CONFIG_STMMAC_ETH) += stmmac.o + stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o + stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o ++stmmac-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o + stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ + chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \ + dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \ +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c +new file mode 100644 +index 0000000..6c9fdb0 +--- /dev/null ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c +@@ -0,0 +1,76 @@ ++/** ++ * dwmac-sunxi.c - Allwinner sunxi DWMAC specific glue layer ++ * ++ * Copyright (C) 2013 Chen-Yu Tsai ++ * ++ * Chen-Yu Tsai <wens@csie.org> ++ * ++ * 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 <linux/clk.h> ++#include <linux/phy.h> ++#include <linux/stmmac.h> ++ ++#define GMAC_IF_TYPE_RGMII 0x4 ++ ++#define GMAC_TX_CLK_MASK 0x3 ++#define GMAC_TX_CLK_MII 0x0 ++#define GMAC_TX_CLK_RGMII_INT 0x2 ++ ++static int sun7i_gmac_init(struct platform_device *pdev) ++{ ++ struct resource *res; ++ struct device *dev = &pdev->dev; ++ void __iomem *addr = NULL; ++ struct plat_stmmacenet_data *plat_dat = NULL; ++ u32 priv_clk_reg; ++ ++ plat_dat = dev_get_platdata(&pdev->dev); ++ if (!plat_dat) ++ return -EINVAL; ++ ++ /* Get GMAC clock register in CCU */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ addr = devm_ioremap_resource(dev, res); ++ if (IS_ERR(addr)) ++ return PTR_ERR(addr); ++ ++ priv_clk_reg = readl(addr); ++ ++ /* Set GMAC interface port mode */ ++ if (plat_dat->interface == PHY_INTERFACE_MODE_RGMII) ++ priv_clk_reg |= GMAC_IF_TYPE_RGMII; ++ else ++ priv_clk_reg &= ~GMAC_IF_TYPE_RGMII; ++ ++ /* Set GMAC transmit clock source. */ ++ priv_clk_reg &= ~GMAC_TX_CLK_MASK; ++ if (plat_dat->interface == PHY_INTERFACE_MODE_RGMII ++ || plat_dat->interface == PHY_INTERFACE_MODE_GMII) ++ priv_clk_reg |= GMAC_TX_CLK_RGMII_INT; ++ else ++ priv_clk_reg |= GMAC_TX_CLK_MII; ++ ++ writel(priv_clk_reg, addr); ++ ++ /* mask out phy addr 0x0 */ ++ plat_dat->mdio_bus_data->phy_mask = 0x1; ++ ++ return 0; ++} ++ ++const struct plat_stmmacenet_data sun7i_gmac_data = { ++ .has_gmac = 1, ++ .tx_coe = 1, ++ .init = sun7i_gmac_init, ++}; ++ +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h +index 22f89ff..c8f659a 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h +@@ -130,6 +130,9 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, + bool stmmac_eee_init(struct stmmac_priv *priv); + + #ifdef CONFIG_STMMAC_PLATFORM ++#ifdef CONFIG_DWMAC_SUNXI ++extern const struct plat_stmmacenet_data sun7i_gmac_data; ++#endif + extern struct platform_driver stmmac_pltfr_driver; + static inline int stmmac_register_platform(void) + { +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +index df3fd1c..6cf8292 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +@@ -35,6 +35,9 @@ + { .compatible = "snps,dwmac-3.70a"}, + { .compatible = "snps,dwmac-3.710"}, + { .compatible = "snps,dwmac"}, ++#ifdef CONFIG_DWMAC_SUNXI ++ { .compatible = "allwinner,sun7i-gmac", .data = &sun7i_gmac_data}, ++#endif + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(of, stmmac_dt_ids); +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/194-dt-sun7i-add-gmac-ctrler.patch b/target/linux/sunxi/patches-3.13/194-dt-sun7i-add-gmac-ctrler.patch new file mode 100644 index 0000000000..894378b815 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/194-dt-sun7i-add-gmac-ctrler.patch @@ -0,0 +1,38 @@ +From a07eeb627d300da0dee8cb39b59173332be8e4bb Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai <wens@csie.org> +Date: Sat, 7 Dec 2013 01:29:38 +0800 +Subject: [PATCH] ARM: dts: sun7i: Add GMAC controller node to sun7i DTSI + +Signed-off-by: Chen-Yu Tsai <wens@csie.org> +--- + arch/arm/boot/dts/sun7i-a20.dtsi | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 0c1d363..82be552 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -571,6 +571,20 @@ + status = "disabled"; + }; + ++ gmac: ethernet@01c50000 { ++ compatible = "allwinner,sun7i-gmac", "snps,dwmac"; ++ reg = <0x01c50000 0x10000>, ++ <0x01c20164 0x4>; ++ interrupts = <0 85 1>; ++ interrupt-names = "macirq"; ++ clocks = <&ahb_gates 49>; ++ clock-names = "stmmaceth"; ++ snps,pbl = <2>; ++ snps,fixed-burst; ++ snps,force_sf_dma_mode; ++ status = "disabled"; ++ }; ++ + hstimer@01c60000 { + compatible = "allwinner,sun7i-a20-hstimer"; + reg = <0x01c60000 0x1000>; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/195-dt-sun7i-add-gmac-pinmuxing.patch b/target/linux/sunxi/patches-3.13/195-dt-sun7i-add-gmac-pinmuxing.patch new file mode 100644 index 0000000000..5d66055836 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/195-dt-sun7i-add-gmac-pinmuxing.patch @@ -0,0 +1,49 @@ +From 777ba9f88e1a566a6ed26fe1e8dfff4b8c1448fc Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai <wens@csie.org> +Date: Sat, 7 Dec 2013 01:29:39 +0800 +Subject: [PATCH] ARM: dts: sun7i: Add pin muxing options for the GMAC + +The A20 has EMAC and GMAC muxed on the same pins. +Add pin sets with gmac function for MII and RGMII mode to the DTSI. + +Signed-off-by: Chen-Yu Tsai <wens@csie.org> +--- + arch/arm/boot/dts/sun7i-a20.dtsi | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 82be552..a0d6ef7 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -403,6 +403,28 @@ + allwinner,pull = <0>; + }; + ++ gmac_pins_mii: gmac_mii { ++ allwinner,pins = "PA0", "PA1", "PA2", ++ "PA3", "PA4", "PA5", "PA6", ++ "PA7", "PA8", "PA9", "PA10", ++ "PA11", "PA12", "PA13", "PA14", ++ "PA15", "PA16"; ++ allwinner,function = "gmac"; ++ allwinner,drive = <3>; ++ allwinner,pull = <0>; ++ }; ++ ++ gmac_pins_rgmii: gmac_rgmii { ++ allwinner,pins = "PA0", "PA1", "PA2", ++ "PA3", "PA4", "PA5", "PA6", ++ "PA7", "PA8", "PA10", ++ "PA11", "PA12", "PA13", ++ "PA15", "PA16"; ++ allwinner,function = "gmac"; ++ allwinner,drive = <3>; ++ allwinner,pull = <0>; ++ }; ++ + mmc0_pins_a: mmc0@0 { + allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5"; + allwinner,function = "mmc0"; +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/196-1-dt-sun7i-enable-gmac-cubietruck.patch b/target/linux/sunxi/patches-3.13/196-1-dt-sun7i-enable-gmac-cubietruck.patch new file mode 100644 index 0000000000..f547e666a0 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/196-1-dt-sun7i-enable-gmac-cubietruck.patch @@ -0,0 +1,34 @@ +From a94741174cdc6bd29c56c5aa1a225ac6e7f4ebde Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai <wens@csie.org> +Date: Sat, 7 Dec 2013 01:29:40 +0800 +Subject: [PATCH] ARM: dts: sun7i: cubietruck: Enable the GMAC + +The CubieTruck uses the GMAC with an RGMII phy. + +Signed-off-by: Chen-Yu Tsai <wens@csie.org> +--- + arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts +index 7ee628a..2684f27 100644 +--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts ++++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts +@@ -49,6 +49,14 @@ + pinctrl-0 = <&uart0_pins_a>; + status = "okay"; + }; ++ ++ gmac: ethernet@01c50000 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&gmac_pins_rgmii>; ++ snps,phy-addr = <1>; ++ phy-mode = "rgmii"; ++ status = "okay"; ++ }; + }; + + leds { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/196-2-dt-sun7i-enable-gmac-cubieboard2.patch b/target/linux/sunxi/patches-3.13/196-2-dt-sun7i-enable-gmac-cubieboard2.patch new file mode 100644 index 0000000000..c4256a4b10 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/196-2-dt-sun7i-enable-gmac-cubieboard2.patch @@ -0,0 +1,57 @@ +From e28b63650ff934751b9fe56415dc2491a6c6b704 Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai <wens@csie.org> +Date: Sat, 7 Dec 2013 01:29:41 +0800 +Subject: [PATCH] ARM: dts: sun7i: cubieboard2: Enable GMAC instead of EMAC + +GMAC has better performance and fewer hardware issues. +Use the GMAC in MII mode for ethernet instead of the EMAC. + +Signed-off-by: Chen-Yu Tsai <wens@csie.org> +--- + arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 23 ++++++++--------------- + 1 file changed, 8 insertions(+), 15 deletions(-) + +diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +index d28e600..48777cd 100644 +--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts ++++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts +@@ -19,21 +19,6 @@ + compatible = "cubietech,cubieboard2", "allwinner,sun7i-a20"; + + soc@01c00000 { +- emac: ethernet@01c0b000 { +- pinctrl-names = "default"; +- pinctrl-0 = <&emac_pins_a>; +- phy = <&phy1>; +- status = "okay"; +- }; +- +- mdio@01c0b080 { +- status = "okay"; +- +- phy1: ethernet-phy@1 { +- reg = <1>; +- }; +- }; +- + mmc0: mmc@01c0f000 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_pins_a>; +@@ -76,6 +61,14 @@ + pinctrl-0 = <&i2c1_pins_a>; + status = "okay"; + }; ++ ++ gmac: ethernet@01c50000 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&gmac_pins_mii>; ++ snps,phy-addr = <1>; ++ phy-mode = "mii"; ++ status = "okay"; ++ }; + }; + + leds { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/196-3-dt-sun7i-enable-gmac-a20-micro.patch b/target/linux/sunxi/patches-3.13/196-3-dt-sun7i-enable-gmac-a20-micro.patch new file mode 100644 index 0000000000..b2aa3268ff --- /dev/null +++ b/target/linux/sunxi/patches-3.13/196-3-dt-sun7i-enable-gmac-a20-micro.patch @@ -0,0 +1,57 @@ +From e39d51b2236ab17628fe5d110296cd33a9c4427e Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai <wens@csie.org> +Date: Sat, 7 Dec 2013 01:29:42 +0800 +Subject: [PATCH] ARM: dts: sun7i: olinuxino-micro: Enable GMAC instead of EMAC + +GMAC has better performance and fewer hardware issues. +Use the GMAC in MII mode for ethernet instead of the EMAC. + +Signed-off-by: Chen-Yu Tsai <wens@csie.org> +--- + arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 23 ++++++++--------------- + 1 file changed, 8 insertions(+), 15 deletions(-) + +diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +index d377696..bf6f6c8 100644 +--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts ++++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +@@ -19,21 +19,6 @@ + compatible = "olimex,a20-olinuxino-micro", "allwinner,sun7i-a20"; + + soc@01c00000 { +- emac: ethernet@01c0b000 { +- pinctrl-names = "default"; +- pinctrl-0 = <&emac_pins_a>; +- phy = <&phy1>; +- status = "okay"; +- }; +- +- mdio@01c0b080 { +- status = "okay"; +- +- phy1: ethernet-phy@1 { +- reg = <1>; +- }; +- }; +- + mmc0: mmc@01c0f000 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_pins_a>; +@@ -110,6 +95,14 @@ + pinctrl-0 = <&i2c2_pins_a>; + status = "okay"; + }; ++ ++ gmac: ethernet@01c50000 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&gmac_pins_mii>; ++ snps,phy-addr = <1>; ++ phy-mode = "mii"; ++ status = "okay"; ++ }; + }; + + leds { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/200-sun5i-timer-add-support-for-reset-ctrler.patch b/target/linux/sunxi/patches-3.13/200-sun5i-timer-add-support-for-reset-ctrler.patch new file mode 100644 index 0000000000..c13d9911c0 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/200-sun5i-timer-add-support-for-reset-ctrler.patch @@ -0,0 +1,69 @@ +From 99489f45debd07f6e1cfa36f5c9890409714518d Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Fri, 20 Dec 2013 22:41:08 +0100 +Subject: [PATCH] clocksource: sun5i: Add support for reset controller + +The Allwinner A31 that uses this timer has the timer IP asserted in reset. +Add an optional reset property to the DT, and deassert the timer from reset if +it's there. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + .../devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt | 4 ++++ + drivers/clocksource/timer-sun5i.c | 6 ++++++ + 2 files changed, 10 insertions(+) + +diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt +index 7c26154..27cfc7d 100644 +--- a/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt ++++ b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt +@@ -9,6 +9,9 @@ Required properties: + one) + - clocks: phandle to the source clock (usually the AHB clock) + ++Optionnal properties: ++- resets: phandle to a reset controller asserting the timer ++ + Example: + + timer@01c60000 { +@@ -19,4 +22,5 @@ timer@01c60000 { + <0 53 1>, + <0 54 1>; + clocks = <&ahb1_gates 19>; ++ resets = <&ahb1rst 19>; + }; +diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c +index bddc522..f74d75e 100644 +--- a/drivers/clocksource/timer-sun5i.c ++++ b/drivers/clocksource/timer-sun5i.c +@@ -16,6 +16,7 @@ + #include <linux/interrupt.h> + #include <linux/irq.h> + #include <linux/irqreturn.h> ++#include <linux/reset.h> + #include <linux/sched_clock.h> + #include <linux/of.h> + #include <linux/of_address.h> +@@ -143,6 +144,7 @@ static u32 sun5i_timer_sched_read(void) + + static void __init sun5i_timer_init(struct device_node *node) + { ++ struct reset_control *rstc; + unsigned long rate; + struct clk *clk; + int ret, irq; +@@ -162,6 +164,10 @@ static void __init sun5i_timer_init(struct device_node *node) + clk_prepare_enable(clk); + rate = clk_get_rate(clk); + ++ rstc = of_reset_control_get(node, NULL); ++ if (!IS_ERR(rstc)) ++ reset_control_deassert(rstc); ++ + writel(~0, timer_base + TIMER_INTVAL_LO_REG(1)); + writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, + timer_base + TIMER_CTL_REG(1)); +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/201-reset-add-of_reset_control_get.patch b/target/linux/sunxi/patches-3.13/201-reset-add-of_reset_control_get.patch new file mode 100644 index 0000000000..73ecca10f7 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/201-reset-add-of_reset_control_get.patch @@ -0,0 +1,119 @@ +From 0325b48d6149e131c90ed6ec77458f4d2df73898 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime.ripard@free-electrons.com> +Date: Fri, 20 Dec 2013 22:41:07 +0100 +Subject: [PATCH] reset: Add of_reset_control_get + +In some cases, you might need to deassert from reset an hardware block that +doesn't associated to a struct device (CPUs, timers, etc.). + +Add a small helper to retrieve the reset controller from the device tree +without the need to pass a struct device. + +Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> +--- + drivers/reset/core.c | 39 ++++++++++++++++++++++++++++++--------- + include/linux/reset.h | 4 ++++ + 2 files changed, 34 insertions(+), 9 deletions(-) + +diff --git a/drivers/reset/core.c b/drivers/reset/core.c +index d1b6089..4f3dda7 100644 +--- a/drivers/reset/core.c ++++ b/drivers/reset/core.c +@@ -127,15 +127,16 @@ int reset_control_deassert(struct reset_control *rstc) + EXPORT_SYMBOL_GPL(reset_control_deassert); + + /** +- * reset_control_get - Lookup and obtain a reference to a reset controller. +- * @dev: device to be reset by the controller ++ * of_reset_control_get - Lookup and obtain a reference to a reset controller. ++ * @node: device to be reset by the controller + * @id: reset line name + * + * Returns a struct reset_control or IS_ERR() condition containing errno. + * + * Use of id names is optional. + */ +-struct reset_control *reset_control_get(struct device *dev, const char *id) ++struct reset_control *of_reset_control_get(struct device_node *node, ++ const char *id) + { + struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER); + struct reset_controller_dev *r, *rcdev; +@@ -144,13 +145,10 @@ struct reset_control *reset_control_get(struct device *dev, const char *id) + int rstc_id; + int ret; + +- if (!dev) +- return ERR_PTR(-EINVAL); +- + if (id) +- index = of_property_match_string(dev->of_node, ++ index = of_property_match_string(node, + "reset-names", id); +- ret = of_parse_phandle_with_args(dev->of_node, "resets", "#reset-cells", ++ ret = of_parse_phandle_with_args(node, "resets", "#reset-cells", + index, &args); + if (ret) + return ERR_PTR(ret); +@@ -185,12 +183,35 @@ struct reset_control *reset_control_get(struct device *dev, const char *id) + return ERR_PTR(-ENOMEM); + } + +- rstc->dev = dev; + rstc->rcdev = rcdev; + rstc->id = rstc_id; + + return rstc; + } ++EXPORT_SYMBOL_GPL(of_reset_control_get); ++ ++/** ++ * reset_control_get - Lookup and obtain a reference to a reset controller. ++ * @dev: device to be reset by the controller ++ * @id: reset line name ++ * ++ * Returns a struct reset_control or IS_ERR() condition containing errno. ++ * ++ * Use of id names is optional. ++ */ ++struct reset_control *reset_control_get(struct device *dev, const char *id) ++{ ++ struct reset_control *rstc; ++ ++ if (!dev) ++ return ERR_PTR(-EINVAL); ++ ++ rstc = of_reset_control_get(dev->of_node, id); ++ if (!IS_ERR(rstc)) ++ rstc->dev = dev; ++ ++ return rstc; ++} + EXPORT_SYMBOL_GPL(reset_control_get); + + /** +diff --git a/include/linux/reset.h b/include/linux/reset.h +index 6082247..a398025 100644 +--- a/include/linux/reset.h ++++ b/include/linux/reset.h +@@ -1,6 +1,8 @@ + #ifndef _LINUX_RESET_H_ + #define _LINUX_RESET_H_ + ++#include <linux/of.h> ++ + struct device; + struct reset_control; + +@@ -8,6 +10,8 @@ + int reset_control_assert(struct reset_control *rstc); + int reset_control_deassert(struct reset_control *rstc); + ++struct reset_control *of_reset_control_get(struct device_node *node, ++ const char *id); + struct reset_control *reset_control_get(struct device *dev, const char *id); + void reset_control_put(struct reset_control *rstc); + struct reset_control *devm_reset_control_get(struct device *dev, const char *id); +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/210-clk-sunxi-add-a20-output-clk.patch b/target/linux/sunxi/patches-3.13/210-clk-sunxi-add-a20-output-clk.patch new file mode 100644 index 0000000000..5b46d8b127 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/210-clk-sunxi-add-a20-output-clk.patch @@ -0,0 +1,119 @@ +From 5ca9eadcb5f5cd9af6f1650029ad64052a1a0b10 Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai <wens@csie.org> +Date: Tue, 24 Dec 2013 21:26:17 +0800 +Subject: [PATCH] clk: sunxi: Allwinner A20 output clock support + +This patch adds support for the external clock outputs on the +Allwinner A20 SoC. The clock outputs are similar to "module 0" +type clocks, with different offsets and widths for clock factors. + +Signed-off-by: Chen-Yu Tsai <wens@csie.org> +--- + Documentation/devicetree/bindings/clock/sunxi.txt | 1 + + drivers/clk/sunxi/clk-sunxi.c | 57 +++++++++++++++++++++++ + 2 files changed, 58 insertions(+) + +diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt +index 941bd93..79c7197 100644 +--- a/Documentation/devicetree/bindings/clock/sunxi.txt ++++ b/Documentation/devicetree/bindings/clock/sunxi.txt +@@ -36,6 +36,7 @@ Required properties: + "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31 + "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 + "allwinner,sun4i-mod0-clk" - for the module 0 family of clocks ++ "allwinner,sun7i-a20-out-clk" - for the external output clocks + + Required properties for all clocks: + - reg : shall be the control register address for the clock. +diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c +index 8a07a68..df1f385 100644 +--- a/drivers/clk/sunxi/clk-sunxi.c ++++ b/drivers/clk/sunxi/clk-sunxi.c +@@ -396,6 +396,47 @@ void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output) + + + /** ++ * sun7i_a20_get_out_factors() - calculates m, p factors for CLK_OUT_A/B ++ * CLK_OUT rate is calculated as follows ++ * rate = (parent_rate >> p) / (m + 1); ++ */ ++ ++static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate, ++ u8 *n, u8 *k, u8 *m, u8 *p) ++{ ++ u8 div, calcm, calcp; ++ ++ /* These clocks can only divide, so we will never be able to achieve ++ * frequencies higher than the parent frequency */ ++ if (*freq > parent_rate) ++ *freq = parent_rate; ++ ++ div = parent_rate / *freq; ++ ++ if (div < 32) ++ calcp = 0; ++ else if (div / 2 < 32) ++ calcp = 1; ++ else if (div / 4 < 32) ++ calcp = 2; ++ else ++ calcp = 3; ++ ++ calcm = DIV_ROUND_UP(div, 1 << calcp); ++ ++ *freq = (parent_rate >> calcp) / calcm; ++ ++ /* we were called to round the frequency, we can now return */ ++ if (n == NULL) ++ return; ++ ++ *m = calcm - 1; ++ *p = calcp; ++} ++ ++ ++ ++/** + * sunxi_factors_clk_setup() - Setup function for factor clocks + */ + +@@ -455,6 +496,14 @@ struct factors_data { + .pwidth = 2, + }; + ++/* user manual says "n" but it's really "p" */ ++static struct clk_factors_config sun7i_a20_out_config = { ++ .mshift = 8, ++ .mwidth = 5, ++ .pshift = 20, ++ .pwidth = 2, ++}; ++ + static const struct factors_data sun4i_pll1_data __initconst = { + .enable = 31, + .table = &sun4i_pll1_config, +@@ -492,6 +541,13 @@ struct factors_data { + .getter = sun4i_get_mod0_factors, + }; + ++static const struct factors_data sun7i_a20_out_data __initconst = { ++ .enable = 31, ++ .mux = 24, ++ .table = &sun7i_a20_out_config, ++ .getter = sun7i_a20_get_out_factors, ++}; ++ + static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, + const struct factors_data *data) + { +@@ -995,6 +1051,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, + {.compatible = "allwinner,sun5i-a13-ahb-clk", .data = &sun5i_a13_ahb_data,}, + {.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,}, + {.compatible = "allwinner,sun4i-mod0-clk", .data = &sun4i_mod0_data,}, ++ {.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,}, + {} + }; + +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/211-dt-sun7i-add-external-clk-output.patch b/target/linux/sunxi/patches-3.13/211-dt-sun7i-add-external-clk-output.patch new file mode 100644 index 0000000000..ac7cd6ac08 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/211-dt-sun7i-add-external-clk-output.patch @@ -0,0 +1,56 @@ +From 6dd612e3d7e0c76f863efaddae4738fadc461f72 Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai <wens@csie.org> +Date: Tue, 24 Dec 2013 21:26:18 +0800 +Subject: [PATCH] ARM: dts: sun7i: external clock outputs + +This commit adds the two external clock outputs available on A20 to +its device tree. A dummy fixed factor clock is also added to serve as +the first input of the clock outputs, which according to AW's A20 user +manual, is the 24MHz oscillator divided by 750. + +Signed-off-by: Chen-Yu Tsai <wens@csie.org> +--- + arch/arm/boot/dts/sun7i-a20.dtsi | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 2e19c47..858e0710 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -305,6 +305,33 @@ + clocks = <&osc24M>, <&pll6 2>, <&pll5 1>; + clock-output-names = "mbus"; + }; ++ ++ /* ++ * Dummy clock used by output clocks ++ */ ++ osc24M_32k: osc24M_32k { ++ #clock-cells = <0>; ++ compatible = "fixed-factor-clock"; ++ clock-div = <750>; ++ clock-mult = <1>; ++ clocks = <&osc24M>; ++ }; ++ ++ clk_out_a: clk@01c201f0 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun7i-a20-out-clk"; ++ reg = <0x01c201f0 0x4>; ++ clocks = <&osc24M_32k>, <&osc32k>, <&osc24M>; ++ clock-output-names = "clk_out_a"; ++ }; ++ ++ clk_out_b: clk@01c201f4 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun7i-a20-out-clk"; ++ reg = <0x01c201f4 0x4>; ++ clocks = <&osc24M_32k>, <&osc32k>, <&osc24M>; ++ clock-output-names = "clk_out_b"; ++ }; + }; + + timer { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/212-pinctrl-sunxi-add-a20-output-clkpin-funcs.patch b/target/linux/sunxi/patches-3.13/212-pinctrl-sunxi-add-a20-output-clkpin-funcs.patch new file mode 100644 index 0000000000..299d89f0bc --- /dev/null +++ b/target/linux/sunxi/patches-3.13/212-pinctrl-sunxi-add-a20-output-clkpin-funcs.patch @@ -0,0 +1,37 @@ +From 271a35ef6237c3b775aad357969dc75ae5b56988 Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai <wens@csie.org> +Date: Tue, 24 Dec 2013 21:26:19 +0800 +Subject: [PATCH] pinctrl: sunxi: Add Allwinner A20 clock output pin functions + +This patch adds the clock output pin functions on the A20. +The 2 pins can output a configurable clock to be used by +external modules. This is used on the CubieTruck, to supply +a 32768 Hz low power clock to the onboard Wifi+BT module. + +Signed-off-by: Chen-Yu Tsai <wens@csie.org> +--- + drivers/pinctrl/pinctrl-sunxi-pins.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pinctrl/pinctrl-sunxi-pins.h b/drivers/pinctrl/pinctrl-sunxi-pins.h +index 7c1b05e..3d60669 100644 +--- a/drivers/pinctrl/pinctrl-sunxi-pins.h ++++ b/drivers/pinctrl/pinctrl-sunxi-pins.h +@@ -3774,12 +3774,14 @@ + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi0"), /* MOSI */ + SUNXI_FUNCTION(0x3, "uart6"), /* TX */ ++ SUNXI_FUNCTION(0x4, "clk_out_a"), /* CLK_OUT_A */ + SUNXI_FUNCTION_IRQ(0x5, 24)), /* EINT24 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI13, + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi0"), /* MISO */ + SUNXI_FUNCTION(0x3, "uart6"), /* RX */ ++ SUNXI_FUNCTION(0x4, "clk_out_b"), /* CLK_OUT_B */ + SUNXI_FUNCTION_IRQ(0x5, 25)), /* EINT25 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN_PI14, + SUNXI_FUNCTION(0x0, "gpio_in"), +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/213-dt-sun7i-add-external-clk-outputs.patch b/target/linux/sunxi/patches-3.13/213-dt-sun7i-add-external-clk-outputs.patch new file mode 100644 index 0000000000..bc9694bbd8 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/213-dt-sun7i-add-external-clk-outputs.patch @@ -0,0 +1,43 @@ +From f3a50c26f33a4627e5d3e35f80db3f22a5375237 Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai <wens@csie.org> +Date: Tue, 24 Dec 2013 21:26:20 +0800 +Subject: [PATCH] ARM: dts: sun7i: Add pin muxing options for clock outputs + +This patch adds the clock output pin options on the A20. +The 2 pins can output a configurable clock to be used by +external modules. This is used on the CubieTruck, to supply +a 32768 Hz low power clock to the onboard Wifi+BT module. + +Signed-off-by: Chen-Yu Tsai <wens@csie.org> +--- + arch/arm/boot/dts/sun7i-a20.dtsi | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 858e0710..bd52041 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -483,6 +483,20 @@ + allwinner,drive = <3>; + allwinner,pull = <0>; + }; ++ ++ clk_out_a_pins: clk_out_a@0 { ++ allwinner,pins = "PI12"; ++ allwinner,function = "clk_out_a"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; ++ ++ clk_out_b_pins: clk_out_b@0 { ++ allwinner,pins = "PI13"; ++ allwinner,function = "clk_out_b"; ++ allwinner,drive = <0>; ++ allwinner,pull = <0>; ++ }; + }; + + sata: ahci@01c18000 { +-- +1.8.5.1 + diff --git a/target/linux/sunxi/patches-3.13/230-dt-add-pcduino.patch b/target/linux/sunxi/patches-3.13/230-dt-add-pcduino.patch new file mode 100644 index 0000000000..91c633cf17 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/230-dt-add-pcduino.patch @@ -0,0 +1,11 @@ +diff -ruN old/arch/arm/boot/dts/Makefile new/arch/arm/boot/dts/Makefile +--- old/arch/arm/boot/dts/Makefile 2014-01-02 22:08:07.288255421 +0100 ++++ new/arch/arm/boot/dts/Makefile 2014-01-02 21:25:02.000000000 +0100 +@@ -231,6 +231,7 @@ + sun4i-a10-cubieboard.dtb \ + sun4i-a10-mini-xplus.dtb \ + sun4i-a10-hackberry.dtb \ ++ sun4i-a10-pcduino.dtb \ + sun5i-a10s-olinuxino-micro.dtb \ + sun5i-a13-olinuxino.dtb \ + sun6i-a31-colombus.dtb \ diff --git a/target/linux/sunxi/patches-3.13/231-dt-add-a10-olinuxino-lime.patch b/target/linux/sunxi/patches-3.13/231-dt-add-a10-olinuxino-lime.patch new file mode 100644 index 0000000000..1c7a15c7aa --- /dev/null +++ b/target/linux/sunxi/patches-3.13/231-dt-add-a10-olinuxino-lime.patch @@ -0,0 +1,12 @@ +Index: linux-3.12.5/arch/arm/boot/dts/Makefile +=================================================================== +--- linux-3.12.5.orig/arch/arm/boot/dts/Makefile 2014-01-07 20:20:35.112013217 +0100 ++++ linux-3.12.5/arch/arm/boot/dts/Makefile 2014-01-07 20:20:35.124013454 +0100 +@@ -232,6 +232,7 @@ + sun4i-a10-mini-xplus.dtb \ + sun4i-a10-hackberry.dtb \ + sun4i-a10-pcduino.dtb \ ++ sun4i-a10-olinuxino-lime.dtb \ + sun5i-a10s-olinuxino-micro.dtb \ + sun5i-a13-olinuxino.dtb \ + sun5i-a13-olinuxino-micro.dtb \ diff --git a/target/linux/sunxi/patches-3.13/232-dt-pcduino-update-mmc-entry.patch b/target/linux/sunxi/patches-3.13/232-dt-pcduino-update-mmc-entry.patch new file mode 100644 index 0000000000..53c3ebd5f4 --- /dev/null +++ b/target/linux/sunxi/patches-3.13/232-dt-pcduino-update-mmc-entry.patch @@ -0,0 +1,15 @@ +diff -ruN old/arch/arm/boot/dts/sun4i-a10-pcduino.dts new/arch/arm/boot/dts/sun4i-a10-pcduino.dts +--- old/arch/arm/boot/dts/sun4i-a10-pcduino.dts 2014-01-22 23:41:25.000000000 +0100 ++++ new/arch/arm/boot/dts/sun4i-a10-pcduino.dts 2014-01-28 01:08:52.787630026 +0100 +@@ -42,9 +42,9 @@ + }; + }; + +- sdc0: sdc@01c0f000 { ++ mmc0: mmc@01c0f000 { + pinctrl-names = "default"; +- pinctrl-0 = <&sdc0_pins_a>; ++ pinctrl-0 = <&mmc0_pins_a>; + pinctrl-1 = <&mmc0_cd_pin_pcduino>; + cd-gpios = <&pio 7 1 0>; /* PH1 */ + cd-mode = <1>; diff --git a/target/linux/sunxi/patches-3.13/233-dt-lime-update-mmc-entry.patch b/target/linux/sunxi/patches-3.13/233-dt-lime-update-mmc-entry.patch new file mode 100644 index 0000000000..d6c2d4089c --- /dev/null +++ b/target/linux/sunxi/patches-3.13/233-dt-lime-update-mmc-entry.patch @@ -0,0 +1,15 @@ +diff -ruN old/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts new/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts +--- old/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts 2014-01-22 23:41:25.000000000 +0100 ++++ new/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts 2014-01-28 01:23:50.083617987 +0100 +@@ -33,9 +33,9 @@ + }; + }; + +- sdc0: sdc@01c0f000 { ++ mmc0: mmc@01c0f000 { + pinctrl-names = "default"; +- pinctrl-0 = <&sdc0_pins_a>; ++ pinctrl-0 = <&mmc0_pins_a>; + pinctrl-1 = <&mmc0_cd_pin_olinuxino>; + cd-gpios = <&pio 7 1 0>; /* PH1 */ + cd-mode = <1>; diff --git a/target/linux/sunxi/patches-3.13/234-dt-cubietruck-update-mmc-entry.patch b/target/linux/sunxi/patches-3.13/234-dt-cubietruck-update-mmc-entry.patch new file mode 100644 index 0000000000..1fe1a5a2bf --- /dev/null +++ b/target/linux/sunxi/patches-3.13/234-dt-cubietruck-update-mmc-entry.patch @@ -0,0 +1,15 @@ +diff -ruN old/arch/arm/boot/dts/sun7i-a20-cubietruck.dts new/arch/arm/boot/dts/sun7i-a20-cubietruck.dts +--- old/arch/arm/boot/dts/sun7i-a20-cubietruck.dts 2014-01-31 18:02:42.000000000 +0100 ++++ new/arch/arm/boot/dts/sun7i-a20-cubietruck.dts 2014-01-31 18:07:13.719332547 +0100 +@@ -19,9 +19,9 @@ + compatible = "cubietech,cubietruck", "allwinner,sun7i-a20"; + + soc@01c00000 { +- sdc0: sdc@01c0f000 { ++ mmc0: mmc@01c0f000 { + pinctrl-names = "default"; +- pinctrl-0 = <&sdc0_pins_a>; ++ pinctrl-0 = <&mmc0_pins_a>; + pinctrl-1 = <&mmc0_cd_pin_cubietruck>; + cd-gpios = <&pio 7 1 0>; /* PH1 */ + cd-mode = <1>; |