Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'sunxi-core-for-3.14-2' of https://github.com/mripard/linux into next/soc

From Maxime Ripard:
Second round of core additions for the Allwinner SoCs

Fixes to select missing configuration options, and update of the maintainer
file.

* tag 'sunxi-core-for-3.14-2' of https://github.com/mripard/linux:
ARM: sunxi: select ARM_PSCI
MAINTAINERS: Update Allwinner sunXi maintainer files
ARM: sunxi: Select RESET_CONTROLLER
ARM: sun6i: Add SMP support for the Allwinner A31
dt-bindings: fix example of allwinner interrupt controller
ARM: sunxi: Register the A31 reset IP in init_time
ARM: sunxi: Select ARCH_HAS_RESET_CONTROLLER
reset: Add Allwinner SoCs Reset Controller Driver

Signed-off-by: Kevin Hilman <khilman@linaro.org>

+353 -2
+1 -1
Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt
··· 14 14 compatible = "allwinner,sun4i-ic"; 15 15 reg = <0x01c20400 0x400>; 16 16 interrupt-controller; 17 - #interrupt-cells = <2>; 17 + #interrupt-cells = <1>; 18 18 };
+6 -1
MAINTAINERS
··· 766 766 M: Maxime Ripard <maxime.ripard@free-electrons.com> 767 767 L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) 768 768 S: Maintained 769 - F: arch/arm/mach-sunxi/ 769 + N: sun[x4567]i 770 + 771 + ARM/Allwinner SoC Clock Support 772 + M: Emilio López <emilio@elopez.com.ar> 773 + S: Maintained 774 + F: drivers/clk/sunxi/ 770 775 771 776 ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES 772 777 M: Andrew Victor <linux@maxim.org.za>
+3
arch/arm/mach-sunxi/Kconfig
··· 1 1 config ARCH_SUNXI 2 2 bool "Allwinner A1X SOCs" if ARCH_MULTI_V7 3 + select ARCH_HAS_RESET_CONTROLLER 3 4 select ARCH_REQUIRE_GPIOLIB 4 5 select ARM_GIC 6 + select ARM_PSCI 5 7 select CLKSRC_MMIO 6 8 select CLKSRC_OF 7 9 select COMMON_CLK ··· 12 10 select HAVE_SMP 13 11 select PINCTRL 14 12 select PINCTRL_SUNXI 13 + select RESET_CONTROLLER 15 14 select SPARSE_IRQ 16 15 select SUN4I_TIMER
+1
arch/arm/mach-sunxi/Makefile
··· 1 1 obj-$(CONFIG_ARCH_SUNXI) += sunxi.o 2 + obj-$(CONFIG_SMP) += platsmp.o headsmp.o
+19
arch/arm/mach-sunxi/common.h
··· 1 + /* 2 + * Core functions for Allwinner SoCs 3 + * 4 + * Copyright (C) 2013 Maxime Ripard 5 + * 6 + * Maxime Ripard <maxime.ripard@free-electrons.com> 7 + * 8 + * This file is licensed under the terms of the GNU General Public 9 + * License version 2. This program is licensed "as is" without any 10 + * warranty of any kind, whether express or implied. 11 + */ 12 + 13 + #ifndef __ARCH_SUNXI_COMMON_H_ 14 + #define __ARCH_SUNXI_COMMON_H_ 15 + 16 + void sun6i_secondary_startup(void); 17 + extern struct smp_operations sun6i_smp_ops; 18 + 19 + #endif /* __ARCH_SUNXI_COMMON_H_ */
+9
arch/arm/mach-sunxi/headsmp.S
··· 1 + #include <linux/linkage.h> 2 + #include <linux/init.h> 3 + 4 + .section ".text.head", "ax" 5 + 6 + ENTRY(sun6i_secondary_startup) 7 + msr cpsr_fsxc, #0xd3 8 + b secondary_startup 9 + ENDPROC(sun6i_secondary_startup)
+124
arch/arm/mach-sunxi/platsmp.c
··· 1 + /* 2 + * SMP support for Allwinner SoCs 3 + * 4 + * Copyright (C) 2013 Maxime Ripard 5 + * 6 + * Maxime Ripard <maxime.ripard@free-electrons.com> 7 + * 8 + * Based on code 9 + * Copyright (C) 2012-2013 Allwinner Ltd. 10 + * 11 + * This file is licensed under the terms of the GNU General Public 12 + * License version 2. This program is licensed "as is" without any 13 + * warranty of any kind, whether express or implied. 14 + */ 15 + 16 + #include <linux/delay.h> 17 + #include <linux/init.h> 18 + #include <linux/io.h> 19 + #include <linux/memory.h> 20 + #include <linux/of.h> 21 + #include <linux/of_address.h> 22 + #include <linux/smp.h> 23 + 24 + #include "common.h" 25 + 26 + #define CPUCFG_CPU_PWR_CLAMP_STATUS_REG(cpu) ((cpu) * 0x40 + 0x64) 27 + #define CPUCFG_CPU_RST_CTRL_REG(cpu) (((cpu) + 1) * 0x40) 28 + #define CPUCFG_CPU_CTRL_REG(cpu) (((cpu) + 1) * 0x40 + 0x04) 29 + #define CPUCFG_CPU_STATUS_REG(cpu) (((cpu) + 1) * 0x40 + 0x08) 30 + #define CPUCFG_GEN_CTRL_REG 0x184 31 + #define CPUCFG_PRIVATE0_REG 0x1a4 32 + #define CPUCFG_PRIVATE1_REG 0x1a8 33 + #define CPUCFG_DBG_CTL0_REG 0x1e0 34 + #define CPUCFG_DBG_CTL1_REG 0x1e4 35 + 36 + #define PRCM_CPU_PWROFF_REG 0x100 37 + #define PRCM_CPU_PWR_CLAMP_REG(cpu) (((cpu) * 4) + 0x140) 38 + 39 + static void __iomem *cpucfg_membase; 40 + static void __iomem *prcm_membase; 41 + 42 + static DEFINE_SPINLOCK(cpu_lock); 43 + 44 + static void __init sun6i_smp_prepare_cpus(unsigned int max_cpus) 45 + { 46 + struct device_node *node; 47 + 48 + node = of_find_compatible_node(NULL, NULL, "allwinner,sun6i-a31-prcm"); 49 + if (!node) { 50 + pr_err("Missing A31 PRCM node in the device tree\n"); 51 + return; 52 + } 53 + 54 + prcm_membase = of_iomap(node, 0); 55 + if (!prcm_membase) { 56 + pr_err("Couldn't map A31 PRCM registers\n"); 57 + return; 58 + } 59 + 60 + node = of_find_compatible_node(NULL, NULL, 61 + "allwinner,sun6i-a31-cpuconfig"); 62 + if (!node) { 63 + pr_err("Missing A31 CPU config node in the device tree\n"); 64 + return; 65 + } 66 + 67 + cpucfg_membase = of_iomap(node, 0); 68 + if (!cpucfg_membase) 69 + pr_err("Couldn't map A31 CPU config registers\n"); 70 + 71 + } 72 + 73 + static int sun6i_smp_boot_secondary(unsigned int cpu, 74 + struct task_struct *idle) 75 + { 76 + u32 reg; 77 + int i; 78 + 79 + if (!(prcm_membase && cpucfg_membase)) 80 + return -EFAULT; 81 + 82 + spin_lock(&cpu_lock); 83 + 84 + /* Set CPU boot address */ 85 + writel(virt_to_phys(sun6i_secondary_startup), 86 + cpucfg_membase + CPUCFG_PRIVATE0_REG); 87 + 88 + /* Assert the CPU core in reset */ 89 + writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu)); 90 + 91 + /* Assert the L1 cache in reset */ 92 + reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG); 93 + writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG); 94 + 95 + /* Disable external debug access */ 96 + reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG); 97 + writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG); 98 + 99 + /* Power up the CPU */ 100 + for (i = 0; i <= 8; i++) 101 + writel(0xff >> i, prcm_membase + PRCM_CPU_PWR_CLAMP_REG(cpu)); 102 + mdelay(10); 103 + 104 + /* Clear CPU power-off gating */ 105 + reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG); 106 + writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG); 107 + mdelay(1); 108 + 109 + /* Deassert the CPU core reset */ 110 + writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu)); 111 + 112 + /* Enable back the external debug accesses */ 113 + reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG); 114 + writel(reg | BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG); 115 + 116 + spin_unlock(&cpu_lock); 117 + 118 + return 0; 119 + } 120 + 121 + struct smp_operations sun6i_smp_ops __initdata = { 122 + .smp_prepare_cpus = sun6i_smp_prepare_cpus, 123 + .smp_boot_secondary = sun6i_smp_boot_secondary, 124 + };
+14
arch/arm/mach-sunxi/sunxi.c
··· 10 10 * warranty of any kind, whether express or implied. 11 11 */ 12 12 13 + #include <linux/clk-provider.h> 14 + #include <linux/clocksource.h> 13 15 #include <linux/delay.h> 14 16 #include <linux/kernel.h> 15 17 #include <linux/init.h> ··· 24 22 #include <asm/mach/arch.h> 25 23 #include <asm/mach/map.h> 26 24 #include <asm/system_misc.h> 25 + 26 + #include "common.h" 27 27 28 28 #define SUN4I_WATCHDOG_CTRL_REG 0x00 29 29 #define SUN4I_WATCHDOG_CTRL_RESTART BIT(0) ··· 136 132 NULL, 137 133 }; 138 134 135 + extern void __init sun6i_reset_init(void); 136 + static void __init sun6i_timer_init(void) 137 + { 138 + of_clk_init(NULL); 139 + sun6i_reset_init(); 140 + clocksource_of_init(); 141 + } 142 + 139 143 DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family") 140 144 .init_machine = sunxi_dt_init, 145 + .init_time = sun6i_timer_init, 141 146 .dt_compat = sun6i_board_dt_compat, 142 147 .restart = sun6i_restart, 148 + .smp = smp_ops(sun6i_smp_ops), 143 149 MACHINE_END 144 150 145 151 static const char * const sun7i_board_dt_compat[] = {
+1
drivers/reset/Makefile
··· 1 1 obj-$(CONFIG_RESET_CONTROLLER) += core.o 2 + obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
+175
drivers/reset/reset-sunxi.c
··· 1 + /* 2 + * Allwinner SoCs Reset Controller driver 3 + * 4 + * Copyright 2013 Maxime Ripard 5 + * 6 + * Maxime Ripard <maxime.ripard@free-electrons.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License as published by 10 + * the Free Software Foundation; either version 2 of the License, or 11 + * (at your option) any later version. 12 + */ 13 + 14 + #include <linux/err.h> 15 + #include <linux/io.h> 16 + #include <linux/module.h> 17 + #include <linux/of.h> 18 + #include <linux/of_address.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/reset-controller.h> 21 + #include <linux/slab.h> 22 + #include <linux/spinlock.h> 23 + #include <linux/types.h> 24 + 25 + struct sunxi_reset_data { 26 + spinlock_t lock; 27 + void __iomem *membase; 28 + struct reset_controller_dev rcdev; 29 + }; 30 + 31 + static int sunxi_reset_assert(struct reset_controller_dev *rcdev, 32 + unsigned long id) 33 + { 34 + struct sunxi_reset_data *data = container_of(rcdev, 35 + struct sunxi_reset_data, 36 + rcdev); 37 + int bank = id / BITS_PER_LONG; 38 + int offset = id % BITS_PER_LONG; 39 + unsigned long flags; 40 + u32 reg; 41 + 42 + spin_lock_irqsave(&data->lock, flags); 43 + 44 + reg = readl(data->membase + (bank * 4)); 45 + writel(reg & ~BIT(offset), data->membase + (bank * 4)); 46 + 47 + spin_unlock_irqrestore(&data->lock, flags); 48 + 49 + return 0; 50 + } 51 + 52 + static int sunxi_reset_deassert(struct reset_controller_dev *rcdev, 53 + unsigned long id) 54 + { 55 + struct sunxi_reset_data *data = container_of(rcdev, 56 + struct sunxi_reset_data, 57 + rcdev); 58 + int bank = id / BITS_PER_LONG; 59 + int offset = id % BITS_PER_LONG; 60 + unsigned long flags; 61 + u32 reg; 62 + 63 + spin_lock_irqsave(&data->lock, flags); 64 + 65 + reg = readl(data->membase + (bank * 4)); 66 + writel(reg | BIT(offset), data->membase + (bank * 4)); 67 + 68 + spin_unlock_irqrestore(&data->lock, flags); 69 + 70 + return 0; 71 + } 72 + 73 + static struct reset_control_ops sunxi_reset_ops = { 74 + .assert = sunxi_reset_assert, 75 + .deassert = sunxi_reset_deassert, 76 + }; 77 + 78 + static int sunxi_reset_init(struct device_node *np) 79 + { 80 + struct sunxi_reset_data *data; 81 + struct resource res; 82 + resource_size_t size; 83 + int ret; 84 + 85 + data = kzalloc(sizeof(*data), GFP_KERNEL); 86 + if (!data) 87 + return -ENOMEM; 88 + 89 + ret = of_address_to_resource(np, 0, &res); 90 + if (ret) 91 + goto err_alloc; 92 + 93 + size = resource_size(&res); 94 + if (!request_mem_region(res.start, size, np->name)) { 95 + ret = -EBUSY; 96 + goto err_alloc; 97 + } 98 + 99 + data->membase = ioremap(res.start, size); 100 + if (!data->membase) { 101 + ret = -ENOMEM; 102 + goto err_alloc; 103 + } 104 + 105 + data->rcdev.owner = THIS_MODULE; 106 + data->rcdev.nr_resets = size * 32; 107 + data->rcdev.ops = &sunxi_reset_ops; 108 + data->rcdev.of_node = np; 109 + reset_controller_register(&data->rcdev); 110 + 111 + return 0; 112 + 113 + err_alloc: 114 + kfree(data); 115 + return ret; 116 + }; 117 + 118 + /* 119 + * These are the reset controller we need to initialize early on in 120 + * our system, before we can even think of using a regular device 121 + * driver for it. 122 + */ 123 + static const struct of_device_id sunxi_early_reset_dt_ids[] __initdata = { 124 + { .compatible = "allwinner,sun6i-a31-ahb1-reset", }, 125 + { /* sentinel */ }, 126 + }; 127 + 128 + void __init sun6i_reset_init(void) 129 + { 130 + struct device_node *np; 131 + 132 + for_each_matching_node(np, sunxi_early_reset_dt_ids) 133 + sunxi_reset_init(np); 134 + } 135 + 136 + /* 137 + * And these are the controllers we can register through the regular 138 + * device model. 139 + */ 140 + static const struct of_device_id sunxi_reset_dt_ids[] = { 141 + { .compatible = "allwinner,sun6i-a31-clock-reset", }, 142 + { /* sentinel */ }, 143 + }; 144 + MODULE_DEVICE_TABLE(of, sunxi_reset_dt_ids); 145 + 146 + static int sunxi_reset_probe(struct platform_device *pdev) 147 + { 148 + return sunxi_reset_init(pdev->dev.of_node); 149 + } 150 + 151 + static int sunxi_reset_remove(struct platform_device *pdev) 152 + { 153 + struct sunxi_reset_data *data = platform_get_drvdata(pdev); 154 + 155 + reset_controller_unregister(&data->rcdev); 156 + iounmap(data->membase); 157 + kfree(data); 158 + 159 + return 0; 160 + } 161 + 162 + static struct platform_driver sunxi_reset_driver = { 163 + .probe = sunxi_reset_probe, 164 + .remove = sunxi_reset_remove, 165 + .driver = { 166 + .name = "sunxi-reset", 167 + .owner = THIS_MODULE, 168 + .of_match_table = sunxi_reset_dt_ids, 169 + }, 170 + }; 171 + module_platform_driver(sunxi_reset_driver); 172 + 173 + MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); 174 + MODULE_DESCRIPTION("Allwinner SoCs Reset Controller Driver"); 175 + MODULE_LICENSE("GPL");