From d1ca9d207acc1056bd460f7cba2f50af87004f58 Mon Sep 17 00:00:00 2001 From: Zoltan HERPAI Date: Wed, 5 Feb 2014 08:42:28 +0000 Subject: sunxi: initial 3.13 support Signed-off-by: Zoltan HERPAI git-svn-id: svn://svn.openwrt.org/openwrt/trunk@39471 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- .../patches-3.13/105-reset-add-reset-ctrler.patch | 214 +++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 target/linux/sunxi/patches-3.13/105-reset-add-reset-ctrler.patch (limited to 'target/linux/sunxi/patches-3.13/105-reset-add-reset-ctrler.patch') 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 +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 +Acked-by: Philipp Zabel +--- + 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 ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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