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

Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc

Pull ARM SoC driver updates from Olof Johansson:
"Driver updates for ARM SoCs. Some for SoC-family code under
drivers/soc, but also some other driver updates that don't belong
anywhere else. We also bring in the drivers/reset code through
arm-soc.

Some of the larger updates:

- Qualcomm support for SMEM, SMSM, SMP2P. All used to communicate
with other parts of the chip/board on these platforms, all
proprietary protocols that don't fit into other subsystems and live
in drivers/soc for now.

- System bus driver for UniPhier

- Driver for the TI Wakeup M3 IPC device

- Power management for Raspberry PI

+ Again a bunch of other smaller updates and patches"

* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (38 commits)
bus: uniphier: allow only built-in driver
ARM: bcm2835: clarify RASPBERRYPI_FIRMWARE dependency
MAINTAINERS: Drop Kumar Gala from QCOM
bus: uniphier-system-bus: add UniPhier System Bus driver
ARM: bcm2835: add rpi power domain driver
dt-bindings: add rpi power domain driver bindings
ARM: bcm2835: Define two new packets from the latest firmware.
drivers/soc: make mediatek/mtk-scpsys.c explicitly non-modular
soc: mediatek: SCPSYS: Add regulator support
MAINTAINERS: Change QCOM entries
soc: qcom: smd-rpm: Add existing platform support
memory/tegra: Add number of TLB lines for Tegra124
reset: hi6220: fix modular build
soc: qcom: Introduce WCNSS_CTRL SMD client
ARM: qcom: select ARM_CPU_SUSPEND for power management
MAINTAINERS: Add rules for Qualcomm dts files
soc: qcom: enable smsm/smp2p modular build
serial: msm_serial: Make config tristate
soc: qcom: smp2p: Qualcomm Shared Memory Point to Point
soc: qcom: smsm: Add driver for Qualcomm SMSM
...

+3439 -48
+66
Documentation/devicetree/bindings/bus/uniphier-system-bus.txt
··· 1 + UniPhier System Bus 2 + 3 + The UniPhier System Bus is an external bus that connects on-board devices to 4 + the UniPhier SoC. It is a simple (semi-)parallel bus with address, data, and 5 + some control signals. It supports up to 8 banks (chip selects). 6 + 7 + Before any access to the bus, the bus controller must be configured; the bus 8 + controller registers provide the control for the translation from the offset 9 + within each bank to the CPU-viewed address. The needed setup includes the base 10 + address, the size of each bank. Optionally, some timing parameters can be 11 + optimized for faster bus access. 12 + 13 + Required properties: 14 + - compatible: should be "socionext,uniphier-system-bus". 15 + - reg: offset and length of the register set for the bus controller device. 16 + - #address-cells: should be 2. The first cell is the bank number (chip select). 17 + The second cell is the address offset within the bank. 18 + - #size-cells: should be 1. 19 + - ranges: should provide a proper address translation from the System Bus to 20 + the parent bus. 21 + 22 + Note: 23 + The address region(s) that can be assigned for the System Bus is implementation 24 + defined. Some SoCs can use 0x00000000-0x0fffffff and 0x40000000-0x4fffffff, 25 + while other SoCs can only use 0x40000000-0x4fffffff. There might be additional 26 + limitations depending on SoCs and the boot mode. The address translation is 27 + arbitrary as long as the banks are assigned in the supported address space with 28 + the required alignment and they do not overlap one another. 29 + For example, it is possible to map: 30 + bank 0 to 0x42000000-0x43ffffff, bank 5 to 0x46000000-0x46ffffff 31 + It is also possible to map: 32 + bank 0 to 0x48000000-0x49ffffff, bank 5 to 0x44000000-0x44ffffff 33 + There is no reason to stick to a particular translation mapping, but the 34 + "ranges" property should provide a "reasonable" default that is known to work. 35 + The software should initialize the bus controller according to it. 36 + 37 + Example: 38 + 39 + system-bus { 40 + compatible = "socionext,uniphier-system-bus"; 41 + reg = <0x58c00000 0x400>; 42 + #address-cells = <2>; 43 + #size-cells = <1>; 44 + ranges = <1 0x00000000 0x42000000 0x02000000 45 + 5 0x00000000 0x46000000 0x01000000>; 46 + 47 + ethernet@1,01f00000 { 48 + compatible = "smsc,lan9115"; 49 + reg = <1 0x01f00000 0x1000>; 50 + interrupts = <0 48 4> 51 + phy-mode = "mii"; 52 + }; 53 + 54 + uart@5,00200000 { 55 + compatible = "ns16550a"; 56 + reg = <5 0x00200000 0x20>; 57 + interrupts = <0 49 4> 58 + clock-frequency = <12288000>; 59 + }; 60 + }; 61 + 62 + In this example, 63 + - the Ethernet device is connected at the offset 0x01f00000 of CS1 and 64 + mapped to 0x43f00000 of the parent bus. 65 + - the UART device is connected at the offset 0x00200000 of CS5 and 66 + mapped to 0x46200000 of the parent bus.
+34
Documentation/devicetree/bindings/reset/hisilicon,hi6220-reset.txt
··· 1 + Hisilicon System Reset Controller 2 + ====================================== 3 + 4 + Please also refer to reset.txt in this directory for common reset 5 + controller binding usage. 6 + 7 + The reset controller registers are part of the system-ctl block on 8 + hi6220 SoC. 9 + 10 + Required properties: 11 + - compatible: may be "hisilicon,hi6220-sysctrl" 12 + - reg: should be register base and length as documented in the 13 + datasheet 14 + - #reset-cells: 1, see below 15 + 16 + Example: 17 + sys_ctrl: sys_ctrl@f7030000 { 18 + compatible = "hisilicon,hi6220-sysctrl", "syscon"; 19 + reg = <0x0 0xf7030000 0x0 0x2000>; 20 + #clock-cells = <1>; 21 + #reset-cells = <1>; 22 + }; 23 + 24 + Specifying reset lines connected to IP modules 25 + ============================================== 26 + example: 27 + 28 + uart1: serial@..... { 29 + ... 30 + resets = <&sys_ctrl PERIPH_RSTEN3_UART1>; 31 + ... 32 + }; 33 + 34 + The index could be found in <dt-bindings/reset/hisi,hi6220-resets.h>.
+47
Documentation/devicetree/bindings/soc/bcm/raspberrypi,bcm2835-power.txt
··· 1 + Raspberry Pi power domain driver 2 + 3 + Required properties: 4 + 5 + - compatible: Should be "raspberrypi,bcm2835-power". 6 + - firmware: Reference to the RPi firmware device node. 7 + - #power-domain-cells: Should be <1>, we providing multiple power domains. 8 + 9 + The valid defines for power domain are: 10 + 11 + RPI_POWER_DOMAIN_I2C0 12 + RPI_POWER_DOMAIN_I2C1 13 + RPI_POWER_DOMAIN_I2C2 14 + RPI_POWER_DOMAIN_VIDEO_SCALER 15 + RPI_POWER_DOMAIN_VPU1 16 + RPI_POWER_DOMAIN_HDMI 17 + RPI_POWER_DOMAIN_USB 18 + RPI_POWER_DOMAIN_VEC 19 + RPI_POWER_DOMAIN_JPEG 20 + RPI_POWER_DOMAIN_H264 21 + RPI_POWER_DOMAIN_V3D 22 + RPI_POWER_DOMAIN_ISP 23 + RPI_POWER_DOMAIN_UNICAM0 24 + RPI_POWER_DOMAIN_UNICAM1 25 + RPI_POWER_DOMAIN_CCP2RX 26 + RPI_POWER_DOMAIN_CSI2 27 + RPI_POWER_DOMAIN_CPI 28 + RPI_POWER_DOMAIN_DSI0 29 + RPI_POWER_DOMAIN_DSI1 30 + RPI_POWER_DOMAIN_TRANSPOSER 31 + RPI_POWER_DOMAIN_CCP2TX 32 + RPI_POWER_DOMAIN_CDP 33 + RPI_POWER_DOMAIN_ARM 34 + 35 + Example: 36 + 37 + power: power { 38 + compatible = "raspberrypi,bcm2835-power"; 39 + firmware = <&firmware>; 40 + #power-domain-cells = <1>; 41 + }; 42 + 43 + Example for using power domain: 44 + 45 + &usb { 46 + power-domains = <&power RPI_POWER_DOMAIN_USB>; 47 + };
+57
Documentation/devicetree/bindings/soc/ti/wkup_m3_ipc.txt
··· 1 + Wakeup M3 IPC Driver 2 + ===================== 3 + 4 + The TI AM33xx and AM43xx family of devices use a small Cortex M3 co-processor 5 + (commonly referred to as Wakeup M3 or CM3) to help with various low power tasks 6 + that cannot be controlled from the MPU, like suspend/resume and certain deep 7 + C-states for CPU Idle. Once the wkup_m3_ipc driver uses the wkup_m3_rproc driver 8 + to boot the wkup_m3, it handles communication with the CM3 using IPC registers 9 + present in the SoC's control module and a mailbox. The wkup_m3_ipc exposes an 10 + API to allow the SoC PM code to execute specific PM tasks. 11 + 12 + Wkup M3 Device Node: 13 + ==================== 14 + A wkup_m3_ipc device node is used to represent the IPC registers within an 15 + SoC. 16 + 17 + Required properties: 18 + -------------------- 19 + - compatible: Should be, 20 + "ti,am3352-wkup-m3-ipc" for AM33xx SoCs 21 + "ti,am4372-wkup-m3-ipc" for AM43xx SoCs 22 + - reg: Contains the IPC register address space to communicate 23 + with the Wakeup M3 processor 24 + - interrupts: Contains the interrupt information for the wkup_m3 25 + interrupt that signals the MPU. 26 + - ti,rproc: phandle to the wkup_m3 rproc node so the IPC driver 27 + can boot it. 28 + - mboxes: phandles used by IPC framework to get correct mbox 29 + channel for communication. Must point to appropriate 30 + mbox_wkupm3 child node. 31 + 32 + Example: 33 + -------- 34 + /* AM33xx */ 35 + l4_wkup: l4_wkup@44c00000 { 36 + ... 37 + 38 + scm: scm@210000 { 39 + compatible = "ti,am3-scm", "simple-bus"; 40 + reg = <0x210000 0x2000>; 41 + #address-cells = <1>; 42 + #size-cells = <1>; 43 + ranges = <0 0x210000 0x2000>; 44 + 45 + ... 46 + 47 + wkup_m3_ipc: wkup_m3_ipc@1324 { 48 + compatible = "ti,am3352-wkup-m3-ipc"; 49 + reg = <0x1324 0x24>; 50 + interrupts = <78>; 51 + ti,rproc = <&wkup_m3>; 52 + mboxes = <&mailbox &mbox_wkupm3>; 53 + }; 54 + 55 + ... 56 + }; 57 + };
+6 -4
MAINTAINERS
··· 1415 1415 S: Maintained 1416 1416 1417 1417 ARM/QUALCOMM SUPPORT 1418 - M: Kumar Gala <galak@codeaurora.org> 1419 - M: Andy Gross <agross@codeaurora.org> 1420 - M: David Brown <davidb@codeaurora.org> 1418 + M: Andy Gross <andy.gross@linaro.org> 1419 + M: David Brown <david.brown@linaro.org> 1421 1420 L: linux-arm-msm@vger.kernel.org 1422 1421 L: linux-soc@vger.kernel.org 1423 1422 S: Maintained 1423 + F: arch/arm/boot/dts/qcom-*.dts 1424 + F: arch/arm/boot/dts/qcom-*.dtsi 1424 1425 F: arch/arm/mach-qcom/ 1425 1426 F: drivers/soc/qcom/ 1426 1427 F: drivers/tty/serial/msm_serial.h ··· 1429 1428 F: drivers/*/pm8???-* 1430 1429 F: drivers/mfd/ssbi.c 1431 1430 F: drivers/firmware/qcom_scm.c 1432 - T: git git://git.kernel.org/pub/scm/linux/kernel/git/galak/linux-qcom.git 1431 + T: git git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux.git 1433 1432 1434 1433 ARM/RADISYS ENP2611 MACHINE SUPPORT 1435 1434 M: Lennert Buytenhek <kernel@wantstofly.org> ··· 1674 1673 F: arch/arm/mach-uniphier/ 1675 1674 F: arch/arm/mm/cache-uniphier.c 1676 1675 F: arch/arm64/boot/dts/socionext/ 1676 + F: drivers/bus/uniphier-system-bus.c 1677 1677 F: drivers/i2c/busses/i2c-uniphier* 1678 1678 F: drivers/pinctrl/uniphier/ 1679 1679 F: drivers/tty/serial/8250/8250_uniphier.c
+1
arch/arm64/boot/dts/hisilicon/hi6220.dtsi
··· 147 147 compatible = "hisilicon,hi6220-sysctrl", "syscon"; 148 148 reg = <0x0 0xf7030000 0x0 0x2000>; 149 149 #clock-cells = <1>; 150 + #reset-cells = <1>; 150 151 }; 151 152 152 153 media_ctrl: media_ctrl@f4410000 {
+8
drivers/bus/Kconfig
··· 131 131 with various RSB based devices, such as AXP223, AXP8XX PMICs, 132 132 and AC100/AC200 ICs. 133 133 134 + config UNIPHIER_SYSTEM_BUS 135 + bool "UniPhier System Bus driver" 136 + depends on ARCH_UNIPHIER && OF 137 + default y 138 + help 139 + Support for UniPhier System Bus, a simple external bus. This is 140 + needed to use on-board devices connected to UniPhier SoCs. 141 + 134 142 config VEXPRESS_CONFIG 135 143 bool "Versatile Express configuration bus" 136 144 default y if ARCH_VEXPRESS
+1
drivers/bus/Makefile
··· 17 17 obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o 18 18 obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o 19 19 obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o 20 + obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o 20 21 obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o
+281
drivers/bus/uniphier-system-bus.c
··· 1 + /* 2 + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License as published by 6 + * the Free Software Foundation; either version 2 of the License, or 7 + * (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + 15 + #include <linux/io.h> 16 + #include <linux/log2.h> 17 + #include <linux/module.h> 18 + #include <linux/of.h> 19 + #include <linux/of_address.h> 20 + #include <linux/of_platform.h> 21 + #include <linux/platform_device.h> 22 + 23 + /* System Bus Controller registers */ 24 + #define UNIPHIER_SBC_BASE 0x100 /* base address of bank0 space */ 25 + #define UNIPHIER_SBC_BASE_BE BIT(0) /* bank_enable */ 26 + #define UNIPHIER_SBC_CTRL0 0x200 /* timing parameter 0 of bank0 */ 27 + #define UNIPHIER_SBC_CTRL1 0x204 /* timing parameter 1 of bank0 */ 28 + #define UNIPHIER_SBC_CTRL2 0x208 /* timing parameter 2 of bank0 */ 29 + #define UNIPHIER_SBC_CTRL3 0x20c /* timing parameter 3 of bank0 */ 30 + #define UNIPHIER_SBC_CTRL4 0x300 /* timing parameter 4 of bank0 */ 31 + 32 + #define UNIPHIER_SBC_STRIDE 0x10 /* register stride to next bank */ 33 + #define UNIPHIER_SBC_NR_BANKS 8 /* number of banks (chip select) */ 34 + #define UNIPHIER_SBC_BASE_DUMMY 0xffffffff /* data to squash bank 0, 1 */ 35 + 36 + struct uniphier_system_bus_bank { 37 + u32 base; 38 + u32 end; 39 + }; 40 + 41 + struct uniphier_system_bus_priv { 42 + struct device *dev; 43 + void __iomem *membase; 44 + struct uniphier_system_bus_bank bank[UNIPHIER_SBC_NR_BANKS]; 45 + }; 46 + 47 + static int uniphier_system_bus_add_bank(struct uniphier_system_bus_priv *priv, 48 + int bank, u32 addr, u64 paddr, u32 size) 49 + { 50 + u64 end, mask; 51 + 52 + dev_dbg(priv->dev, 53 + "range found: bank = %d, addr = %08x, paddr = %08llx, size = %08x\n", 54 + bank, addr, paddr, size); 55 + 56 + if (bank >= ARRAY_SIZE(priv->bank)) { 57 + dev_err(priv->dev, "unsupported bank number %d\n", bank); 58 + return -EINVAL; 59 + } 60 + 61 + if (priv->bank[bank].base || priv->bank[bank].end) { 62 + dev_err(priv->dev, 63 + "range for bank %d has already been specified\n", bank); 64 + return -EINVAL; 65 + } 66 + 67 + if (paddr > U32_MAX) { 68 + dev_err(priv->dev, "base address %llx is too high\n", paddr); 69 + return -EINVAL; 70 + } 71 + 72 + end = paddr + size; 73 + 74 + if (addr > paddr) { 75 + dev_err(priv->dev, 76 + "base %08x cannot be mapped to %08llx of parent\n", 77 + addr, paddr); 78 + return -EINVAL; 79 + } 80 + paddr -= addr; 81 + 82 + paddr = round_down(paddr, 0x00020000); 83 + end = round_up(end, 0x00020000); 84 + 85 + if (end > U32_MAX) { 86 + dev_err(priv->dev, "end address %08llx is too high\n", end); 87 + return -EINVAL; 88 + } 89 + mask = paddr ^ (end - 1); 90 + mask = roundup_pow_of_two(mask); 91 + 92 + paddr = round_down(paddr, mask); 93 + end = round_up(end, mask); 94 + 95 + priv->bank[bank].base = paddr; 96 + priv->bank[bank].end = end; 97 + 98 + dev_dbg(priv->dev, "range added: bank = %d, addr = %08x, end = %08x\n", 99 + bank, priv->bank[bank].base, priv->bank[bank].end); 100 + 101 + return 0; 102 + } 103 + 104 + static int uniphier_system_bus_check_overlap( 105 + const struct uniphier_system_bus_priv *priv) 106 + { 107 + int i, j; 108 + 109 + for (i = 0; i < ARRAY_SIZE(priv->bank); i++) { 110 + for (j = i + 1; j < ARRAY_SIZE(priv->bank); j++) { 111 + if (priv->bank[i].end > priv->bank[j].base || 112 + priv->bank[i].base < priv->bank[j].end) { 113 + dev_err(priv->dev, 114 + "region overlap between bank%d and bank%d\n", 115 + i, j); 116 + return -EINVAL; 117 + } 118 + } 119 + } 120 + 121 + return 0; 122 + } 123 + 124 + static void uniphier_system_bus_check_boot_swap( 125 + struct uniphier_system_bus_priv *priv) 126 + { 127 + void __iomem *base_reg = priv->membase + UNIPHIER_SBC_BASE; 128 + int is_swapped; 129 + 130 + is_swapped = !(readl(base_reg) & UNIPHIER_SBC_BASE_BE); 131 + 132 + dev_dbg(priv->dev, "Boot Swap: %s\n", is_swapped ? "on" : "off"); 133 + 134 + /* 135 + * If BOOT_SWAP was asserted on power-on-reset, the CS0 and CS1 are 136 + * swapped. In this case, bank0 and bank1 should be swapped as well. 137 + */ 138 + if (is_swapped) 139 + swap(priv->bank[0], priv->bank[1]); 140 + } 141 + 142 + static void uniphier_system_bus_set_reg( 143 + const struct uniphier_system_bus_priv *priv) 144 + { 145 + void __iomem *base_reg = priv->membase + UNIPHIER_SBC_BASE; 146 + u32 base, end, mask, val; 147 + int i; 148 + 149 + for (i = 0; i < ARRAY_SIZE(priv->bank); i++) { 150 + base = priv->bank[i].base; 151 + end = priv->bank[i].end; 152 + 153 + if (base == end) { 154 + /* 155 + * If SBC_BASE0 or SBC_BASE1 is set to zero, the access 156 + * to anywhere in the system bus space is routed to 157 + * bank 0 (if boot swap if off) or bank 1 (if boot swap 158 + * if on). It means that CPUs cannot get access to 159 + * bank 2 or later. In other words, bank 0/1 cannot 160 + * be disabled even if its bank_enable bits is cleared. 161 + * This seems odd, but it is how this hardware goes. 162 + * As a workaround, dummy data (0xffffffff) should be 163 + * set when the bank 0/1 is unused. As for bank 2 and 164 + * later, they can be simply disable by clearing the 165 + * bank_enable bit. 166 + */ 167 + if (i < 2) 168 + val = UNIPHIER_SBC_BASE_DUMMY; 169 + else 170 + val = 0; 171 + } else { 172 + mask = base ^ (end - 1); 173 + 174 + val = base & 0xfffe0000; 175 + val |= (~mask >> 16) & 0xfffe; 176 + val |= UNIPHIER_SBC_BASE_BE; 177 + } 178 + dev_dbg(priv->dev, "SBC_BASE[%d] = 0x%08x\n", i, val); 179 + 180 + writel(val, base_reg + UNIPHIER_SBC_STRIDE * i); 181 + } 182 + } 183 + 184 + static int uniphier_system_bus_probe(struct platform_device *pdev) 185 + { 186 + struct device *dev = &pdev->dev; 187 + struct uniphier_system_bus_priv *priv; 188 + struct resource *regs; 189 + const __be32 *ranges; 190 + u32 cells, addr, size; 191 + u64 paddr; 192 + int pna, bank, rlen, rone, ret; 193 + 194 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 195 + if (!priv) 196 + return -ENOMEM; 197 + 198 + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 199 + priv->membase = devm_ioremap_resource(dev, regs); 200 + if (IS_ERR(priv->membase)) 201 + return PTR_ERR(priv->membase); 202 + 203 + priv->dev = dev; 204 + 205 + pna = of_n_addr_cells(dev->of_node); 206 + 207 + ret = of_property_read_u32(dev->of_node, "#address-cells", &cells); 208 + if (ret) { 209 + dev_err(dev, "failed to get #address-cells\n"); 210 + return ret; 211 + } 212 + if (cells != 2) { 213 + dev_err(dev, "#address-cells must be 2\n"); 214 + return -EINVAL; 215 + } 216 + 217 + ret = of_property_read_u32(dev->of_node, "#size-cells", &cells); 218 + if (ret) { 219 + dev_err(dev, "failed to get #size-cells\n"); 220 + return ret; 221 + } 222 + if (cells != 1) { 223 + dev_err(dev, "#size-cells must be 1\n"); 224 + return -EINVAL; 225 + } 226 + 227 + ranges = of_get_property(dev->of_node, "ranges", &rlen); 228 + if (!ranges) { 229 + dev_err(dev, "failed to get ranges property\n"); 230 + return -ENOENT; 231 + } 232 + 233 + rlen /= sizeof(*ranges); 234 + rone = pna + 2; 235 + 236 + for (; rlen >= rone; rlen -= rone) { 237 + bank = be32_to_cpup(ranges++); 238 + addr = be32_to_cpup(ranges++); 239 + paddr = of_translate_address(dev->of_node, ranges); 240 + if (paddr == OF_BAD_ADDR) 241 + return -EINVAL; 242 + ranges += pna; 243 + size = be32_to_cpup(ranges++); 244 + 245 + ret = uniphier_system_bus_add_bank(priv, bank, addr, 246 + paddr, size); 247 + if (ret) 248 + return ret; 249 + } 250 + 251 + ret = uniphier_system_bus_check_overlap(priv); 252 + if (ret) 253 + return ret; 254 + 255 + uniphier_system_bus_check_boot_swap(priv); 256 + 257 + uniphier_system_bus_set_reg(priv); 258 + 259 + /* Now, the bus is configured. Populate platform_devices below it */ 260 + return of_platform_populate(dev->of_node, of_default_bus_match_table, 261 + NULL, dev); 262 + } 263 + 264 + static const struct of_device_id uniphier_system_bus_match[] = { 265 + { .compatible = "socionext,uniphier-system-bus" }, 266 + { /* sentinel */ } 267 + }; 268 + MODULE_DEVICE_TABLE(of, uniphier_system_bus_match); 269 + 270 + static struct platform_driver uniphier_system_bus_driver = { 271 + .probe = uniphier_system_bus_probe, 272 + .driver = { 273 + .name = "uniphier-system-bus", 274 + .of_match_table = uniphier_system_bus_match, 275 + }, 276 + }; 277 + module_platform_driver(uniphier_system_bus_driver); 278 + 279 + MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>"); 280 + MODULE_DESCRIPTION("UniPhier System Bus driver"); 281 + MODULE_LICENSE("GPL");
+1
drivers/memory/tegra/tegra124.c
··· 1007 1007 .num_swgroups = ARRAY_SIZE(tegra124_swgroups), 1008 1008 .supports_round_robin_arbitration = true, 1009 1009 .supports_request_limit = true, 1010 + .num_tlb_lines = 32, 1010 1011 .num_asids = 128, 1011 1012 }; 1012 1013
+1
drivers/reset/Kconfig
··· 13 13 If unsure, say no. 14 14 15 15 source "drivers/reset/sti/Kconfig" 16 + source "drivers/reset/hisilicon/Kconfig"
+2 -1
drivers/reset/Makefile
··· 1 - obj-$(CONFIG_RESET_CONTROLLER) += core.o 1 + obj-y += core.o 2 2 obj-$(CONFIG_ARCH_LPC18XX) += reset-lpc18xx.o 3 3 obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o 4 4 obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o 5 5 obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o 6 6 obj-$(CONFIG_ARCH_STI) += sti/ 7 + obj-$(CONFIG_ARCH_HISI) += hisilicon/ 7 8 obj-$(CONFIG_ARCH_ZYNQ) += reset-zynq.o 8 9 obj-$(CONFIG_ATH79) += reset-ath79.o
+37 -23
drivers/reset/core.c
··· 30 30 */ 31 31 struct reset_control { 32 32 struct reset_controller_dev *rcdev; 33 - struct device *dev; 34 33 unsigned int id; 35 34 }; 36 35 ··· 94 95 if (rstc->rcdev->ops->reset) 95 96 return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id); 96 97 97 - return -ENOSYS; 98 + return -ENOTSUPP; 98 99 } 99 100 EXPORT_SYMBOL_GPL(reset_control_reset); 100 101 ··· 107 108 if (rstc->rcdev->ops->assert) 108 109 return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id); 109 110 110 - return -ENOSYS; 111 + return -ENOTSUPP; 111 112 } 112 113 EXPORT_SYMBOL_GPL(reset_control_assert); 113 114 ··· 120 121 if (rstc->rcdev->ops->deassert) 121 122 return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id); 122 123 123 - return -ENOSYS; 124 + return -ENOTSUPP; 124 125 } 125 126 EXPORT_SYMBOL_GPL(reset_control_deassert); 126 127 ··· 135 136 if (rstc->rcdev->ops->status) 136 137 return rstc->rcdev->ops->status(rstc->rcdev, rstc->id); 137 138 138 - return -ENOSYS; 139 + return -ENOTSUPP; 139 140 } 140 141 EXPORT_SYMBOL_GPL(reset_control_status); 141 142 142 143 /** 143 - * of_reset_control_get - Lookup and obtain a reference to a reset controller. 144 + * of_reset_control_get_by_index - Lookup and obtain a reference to a reset 145 + * controller by index. 144 146 * @node: device to be reset by the controller 145 - * @id: reset line name 147 + * @index: index of the reset controller 146 148 * 147 - * Returns a struct reset_control or IS_ERR() condition containing errno. 148 - * 149 - * Use of id names is optional. 149 + * This is to be used to perform a list of resets for a device or power domain 150 + * in whatever order. Returns a struct reset_control or IS_ERR() condition 151 + * containing errno. 150 152 */ 151 - struct reset_control *of_reset_control_get(struct device_node *node, 152 - const char *id) 153 + struct reset_control *of_reset_control_get_by_index(struct device_node *node, 154 + int index) 153 155 { 154 156 struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER); 155 157 struct reset_controller_dev *r, *rcdev; 156 158 struct of_phandle_args args; 157 - int index = 0; 158 159 int rstc_id; 159 160 int ret; 160 161 161 - if (id) 162 - index = of_property_match_string(node, 163 - "reset-names", id); 164 162 ret = of_parse_phandle_with_args(node, "resets", "#reset-cells", 165 163 index, &args); 166 164 if (ret) ··· 198 202 199 203 return rstc; 200 204 } 205 + EXPORT_SYMBOL_GPL(of_reset_control_get_by_index); 206 + 207 + /** 208 + * of_reset_control_get - Lookup and obtain a reference to a reset controller. 209 + * @node: device to be reset by the controller 210 + * @id: reset line name 211 + * 212 + * Returns a struct reset_control or IS_ERR() condition containing errno. 213 + * 214 + * Use of id names is optional. 215 + */ 216 + struct reset_control *of_reset_control_get(struct device_node *node, 217 + const char *id) 218 + { 219 + int index = 0; 220 + 221 + if (id) { 222 + index = of_property_match_string(node, 223 + "reset-names", id); 224 + if (index < 0) 225 + return ERR_PTR(-ENOENT); 226 + } 227 + return of_reset_control_get_by_index(node, index); 228 + } 201 229 EXPORT_SYMBOL_GPL(of_reset_control_get); 202 230 203 231 /** ··· 235 215 */ 236 216 struct reset_control *reset_control_get(struct device *dev, const char *id) 237 217 { 238 - struct reset_control *rstc; 239 - 240 218 if (!dev) 241 219 return ERR_PTR(-EINVAL); 242 220 243 - rstc = of_reset_control_get(dev->of_node, id); 244 - if (!IS_ERR(rstc)) 245 - rstc->dev = dev; 246 - 247 - return rstc; 221 + return of_reset_control_get(dev->of_node, id); 248 222 } 249 223 EXPORT_SYMBOL_GPL(reset_control_get); 250 224
+5
drivers/reset/hisilicon/Kconfig
··· 1 + config COMMON_RESET_HI6220 2 + tristate "Hi6220 Reset Driver" 3 + depends on (ARCH_HISI && RESET_CONTROLLER) 4 + help 5 + Build the Hisilicon Hi6220 reset driver.
+1
drivers/reset/hisilicon/Makefile
··· 1 + obj-$(CONFIG_COMMON_RESET_HI6220) += hi6220_reset.o
+109
drivers/reset/hisilicon/hi6220_reset.c
··· 1 + /* 2 + * Hisilicon Hi6220 reset controller driver 3 + * 4 + * Copyright (c) 2015 Hisilicon Limited. 5 + * 6 + * Author: Feng Chen <puck.chen@hisilicon.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 version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + 13 + #include <linux/io.h> 14 + #include <linux/init.h> 15 + #include <linux/module.h> 16 + #include <linux/bitops.h> 17 + #include <linux/of.h> 18 + #include <linux/reset-controller.h> 19 + #include <linux/reset.h> 20 + #include <linux/platform_device.h> 21 + 22 + #define ASSERT_OFFSET 0x300 23 + #define DEASSERT_OFFSET 0x304 24 + #define MAX_INDEX 0x509 25 + 26 + #define to_reset_data(x) container_of(x, struct hi6220_reset_data, rc_dev) 27 + 28 + struct hi6220_reset_data { 29 + void __iomem *assert_base; 30 + void __iomem *deassert_base; 31 + struct reset_controller_dev rc_dev; 32 + }; 33 + 34 + static int hi6220_reset_assert(struct reset_controller_dev *rc_dev, 35 + unsigned long idx) 36 + { 37 + struct hi6220_reset_data *data = to_reset_data(rc_dev); 38 + 39 + int bank = idx >> 8; 40 + int offset = idx & 0xff; 41 + 42 + writel(BIT(offset), data->assert_base + (bank * 0x10)); 43 + 44 + return 0; 45 + } 46 + 47 + static int hi6220_reset_deassert(struct reset_controller_dev *rc_dev, 48 + unsigned long idx) 49 + { 50 + struct hi6220_reset_data *data = to_reset_data(rc_dev); 51 + 52 + int bank = idx >> 8; 53 + int offset = idx & 0xff; 54 + 55 + writel(BIT(offset), data->deassert_base + (bank * 0x10)); 56 + 57 + return 0; 58 + } 59 + 60 + static struct reset_control_ops hi6220_reset_ops = { 61 + .assert = hi6220_reset_assert, 62 + .deassert = hi6220_reset_deassert, 63 + }; 64 + 65 + static int hi6220_reset_probe(struct platform_device *pdev) 66 + { 67 + struct hi6220_reset_data *data; 68 + struct resource *res; 69 + void __iomem *src_base; 70 + 71 + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 72 + if (!data) 73 + return -ENOMEM; 74 + 75 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 76 + src_base = devm_ioremap_resource(&pdev->dev, res); 77 + if (IS_ERR(src_base)) 78 + return PTR_ERR(src_base); 79 + 80 + data->assert_base = src_base + ASSERT_OFFSET; 81 + data->deassert_base = src_base + DEASSERT_OFFSET; 82 + data->rc_dev.nr_resets = MAX_INDEX; 83 + data->rc_dev.ops = &hi6220_reset_ops; 84 + data->rc_dev.of_node = pdev->dev.of_node; 85 + 86 + reset_controller_register(&data->rc_dev); 87 + 88 + return 0; 89 + } 90 + 91 + static const struct of_device_id hi6220_reset_match[] = { 92 + { .compatible = "hisilicon,hi6220-sysctrl" }, 93 + { }, 94 + }; 95 + 96 + static struct platform_driver hi6220_reset_driver = { 97 + .probe = hi6220_reset_probe, 98 + .driver = { 99 + .name = "reset-hi6220", 100 + .of_match_table = hi6220_reset_match, 101 + }, 102 + }; 103 + 104 + static int __init hi6220_reset_init(void) 105 + { 106 + return platform_driver_register(&hi6220_reset_driver); 107 + } 108 + 109 + postcore_initcall(hi6220_reset_init);
+29 -1
drivers/reset/reset-ath79.c
··· 15 15 #include <linux/module.h> 16 16 #include <linux/platform_device.h> 17 17 #include <linux/reset-controller.h> 18 + #include <linux/reboot.h> 18 19 19 20 struct ath79_reset { 20 21 struct reset_controller_dev rcdev; 22 + struct notifier_block restart_nb; 21 23 void __iomem *base; 22 24 spinlock_t lock; 23 25 }; 26 + 27 + #define FULL_CHIP_RESET 24 24 28 25 29 static int ath79_reset_update(struct reset_controller_dev *rcdev, 26 30 unsigned long id, bool assert) ··· 76 72 .status = ath79_reset_status, 77 73 }; 78 74 75 + static int ath79_reset_restart_handler(struct notifier_block *nb, 76 + unsigned long action, void *data) 77 + { 78 + struct ath79_reset *ath79_reset = 79 + container_of(nb, struct ath79_reset, restart_nb); 80 + 81 + ath79_reset_assert(&ath79_reset->rcdev, FULL_CHIP_RESET); 82 + 83 + return NOTIFY_DONE; 84 + } 85 + 79 86 static int ath79_reset_probe(struct platform_device *pdev) 80 87 { 81 88 struct ath79_reset *ath79_reset; 82 89 struct resource *res; 90 + int err; 83 91 84 92 ath79_reset = devm_kzalloc(&pdev->dev, 85 93 sizeof(*ath79_reset), GFP_KERNEL); ··· 112 96 ath79_reset->rcdev.of_reset_n_cells = 1; 113 97 ath79_reset->rcdev.nr_resets = 32; 114 98 115 - return reset_controller_register(&ath79_reset->rcdev); 99 + err = reset_controller_register(&ath79_reset->rcdev); 100 + if (err) 101 + return err; 102 + 103 + ath79_reset->restart_nb.notifier_call = ath79_reset_restart_handler; 104 + ath79_reset->restart_nb.priority = 128; 105 + 106 + err = register_restart_handler(&ath79_reset->restart_nb); 107 + if (err) 108 + dev_warn(&pdev->dev, "Failed to register restart handler\n"); 109 + 110 + return 0; 116 111 } 117 112 118 113 static int ath79_reset_remove(struct platform_device *pdev) 119 114 { 120 115 struct ath79_reset *ath79_reset = platform_get_drvdata(pdev); 121 116 117 + unregister_restart_handler(&ath79_reset->restart_nb); 122 118 reset_controller_unregister(&ath79_reset->rcdev); 123 119 124 120 return 0;
+1 -3
drivers/reset/reset-berlin.c
··· 87 87 priv->rcdev.of_reset_n_cells = 2; 88 88 priv->rcdev.of_xlate = berlin_reset_xlate; 89 89 90 - reset_controller_register(&priv->rcdev); 91 - 92 - return 0; 90 + return reset_controller_register(&priv->rcdev); 93 91 } 94 92 95 93 static const struct of_device_id berlin_reset_dt_match[] = {
+1 -2
drivers/reset/reset-socfpga.c
··· 133 133 data->rcdev.nr_resets = NR_BANKS * BITS_PER_LONG; 134 134 data->rcdev.ops = &socfpga_reset_ops; 135 135 data->rcdev.of_node = pdev->dev.of_node; 136 - reset_controller_register(&data->rcdev); 137 136 138 - return 0; 137 + return reset_controller_register(&data->rcdev); 139 138 } 140 139 141 140 static int socfpga_reset_remove(struct platform_device *pdev)
+2 -3
drivers/reset/reset-sunxi.c
··· 108 108 data->rcdev.nr_resets = size * 32; 109 109 data->rcdev.ops = &sunxi_reset_ops; 110 110 data->rcdev.of_node = np; 111 - reset_controller_register(&data->rcdev); 112 111 113 - return 0; 112 + return reset_controller_register(&data->rcdev); 114 113 115 114 err_alloc: 116 115 kfree(data); ··· 121 122 * our system, before we can even think of using a regular device 122 123 * driver for it. 123 124 */ 124 - static const struct of_device_id sunxi_early_reset_dt_ids[] __initdata = { 125 + static const struct of_device_id sunxi_early_reset_dt_ids[] __initconst = { 125 126 { .compatible = "allwinner,sun6i-a31-ahb1-reset", }, 126 127 { /* sentinel */ }, 127 128 };
+1 -2
drivers/reset/reset-zynq.c
··· 121 121 priv->rcdev.nr_resets = resource_size(res) / 4 * BITS_PER_LONG; 122 122 priv->rcdev.ops = &zynq_reset_ops; 123 123 priv->rcdev.of_node = pdev->dev.of_node; 124 - reset_controller_register(&priv->rcdev); 125 124 126 - return 0; 125 + return reset_controller_register(&priv->rcdev); 127 126 } 128 127 129 128 static int zynq_reset_remove(struct platform_device *pdev)
+5
drivers/reset/sti/reset-stih407.c
··· 52 52 }; 53 53 54 54 /* Reset Generator control 0/1 */ 55 + #define SYSCFG_5128 0x200 55 56 #define SYSCFG_5131 0x20c 56 57 #define SYSCFG_5132 0x210 57 58 ··· 97 96 [STIH407_ERAM_HVA_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 1), 98 97 [STIH407_LPM_SOFTRESET] = STIH407_SRST_SBC(SYSCFG_4002, 2), 99 98 [STIH407_KEYSCAN_SOFTRESET] = STIH407_SRST_LPM(LPM_SYSCFG_1, 8), 99 + [STIH407_ST231_AUD_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 26), 100 + [STIH407_ST231_DMU_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 27), 101 + [STIH407_ST231_GP0_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 28), 102 + [STIH407_ST231_GP1_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5128, 2), 100 103 }; 101 104 102 105 /* PicoPHY reset/control */
+26 -1
drivers/reset/sti/reset-syscfg.c
··· 103 103 static int syscfg_reset_dev(struct reset_controller_dev *rcdev, 104 104 unsigned long idx) 105 105 { 106 - int err = syscfg_reset_assert(rcdev, idx); 106 + int err; 107 + 108 + err = syscfg_reset_assert(rcdev, idx); 107 109 if (err) 108 110 return err; 109 111 110 112 return syscfg_reset_deassert(rcdev, idx); 111 113 } 112 114 115 + static int syscfg_reset_status(struct reset_controller_dev *rcdev, 116 + unsigned long idx) 117 + { 118 + struct syscfg_reset_controller *rst = to_syscfg_reset_controller(rcdev); 119 + const struct syscfg_reset_channel *ch; 120 + u32 ret_val = 0; 121 + int err; 122 + 123 + if (idx >= rcdev->nr_resets) 124 + return -EINVAL; 125 + 126 + ch = &rst->channels[idx]; 127 + if (ch->ack) 128 + err = regmap_field_read(ch->ack, &ret_val); 129 + else 130 + err = regmap_field_read(ch->reset, &ret_val); 131 + if (err) 132 + return err; 133 + 134 + return rst->active_low ? !ret_val : !!ret_val; 135 + } 136 + 113 137 static struct reset_control_ops syscfg_reset_ops = { 114 138 .reset = syscfg_reset_dev, 115 139 .assert = syscfg_reset_assert, 116 140 .deassert = syscfg_reset_deassert, 141 + .status = syscfg_reset_status, 117 142 }; 118 143 119 144 static int syscfg_reset_controller_register(struct device *dev,
+1
drivers/soc/Kconfig
··· 1 1 menu "SOC (System On Chip) specific Drivers" 2 2 3 + source "drivers/soc/bcm/Kconfig" 3 4 source "drivers/soc/brcmstb/Kconfig" 4 5 source "drivers/soc/fsl/qe/Kconfig" 5 6 source "drivers/soc/mediatek/Kconfig"
+1
drivers/soc/Makefile
··· 2 2 # Makefile for the Linux Kernel SOC specific device drivers. 3 3 # 4 4 5 + obj-y += bcm/ 5 6 obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/ 6 7 obj-$(CONFIG_ARCH_DOVE) += dove/ 7 8 obj-$(CONFIG_MACH_DOVE) += dove/
+9
drivers/soc/bcm/Kconfig
··· 1 + config RASPBERRYPI_POWER 2 + bool "Raspberry Pi power domain driver" 3 + depends on ARCH_BCM2835 || COMPILE_TEST 4 + depends on RASPBERRYPI_FIRMWARE=y 5 + select PM_GENERIC_DOMAINS if PM 6 + select PM_GENERIC_DOMAINS_OF if PM 7 + help 8 + This enables support for the RPi power domains which can be enabled 9 + or disabled via the RPi firmware.
+1
drivers/soc/bcm/Makefile
··· 1 + obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o
+247
drivers/soc/bcm/raspberrypi-power.c
··· 1 + /* (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de> 2 + * 3 + * This program is free software; you can redistribute it and/or modify 4 + * it under the terms of the GNU General Public License version 2 as 5 + * published by the Free Software Foundation. 6 + * 7 + * Authors: 8 + * Alexander Aring <aar@pengutronix.de> 9 + * Eric Anholt <eric@anholt.net> 10 + */ 11 + 12 + #include <linux/module.h> 13 + #include <linux/of_platform.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/pm_domain.h> 16 + #include <dt-bindings/power/raspberrypi-power.h> 17 + #include <soc/bcm2835/raspberrypi-firmware.h> 18 + 19 + /* 20 + * Firmware indices for the old power domains interface. Only a few 21 + * of them were actually implemented. 22 + */ 23 + #define RPI_OLD_POWER_DOMAIN_USB 3 24 + #define RPI_OLD_POWER_DOMAIN_V3D 10 25 + 26 + struct rpi_power_domain { 27 + u32 domain; 28 + bool enabled; 29 + bool old_interface; 30 + struct generic_pm_domain base; 31 + struct rpi_firmware *fw; 32 + }; 33 + 34 + struct rpi_power_domains { 35 + bool has_new_interface; 36 + struct genpd_onecell_data xlate; 37 + struct rpi_firmware *fw; 38 + struct rpi_power_domain domains[RPI_POWER_DOMAIN_COUNT]; 39 + }; 40 + 41 + /* 42 + * Packet definition used by RPI_FIRMWARE_SET_POWER_STATE and 43 + * RPI_FIRMWARE_SET_DOMAIN_STATE 44 + */ 45 + struct rpi_power_domain_packet { 46 + u32 domain; 47 + u32 on; 48 + } __packet; 49 + 50 + /* 51 + * Asks the firmware to enable or disable power on a specific power 52 + * domain. 53 + */ 54 + static int rpi_firmware_set_power(struct rpi_power_domain *rpi_domain, bool on) 55 + { 56 + struct rpi_power_domain_packet packet; 57 + 58 + packet.domain = rpi_domain->domain; 59 + packet.on = on; 60 + return rpi_firmware_property(rpi_domain->fw, 61 + rpi_domain->old_interface ? 62 + RPI_FIRMWARE_SET_POWER_STATE : 63 + RPI_FIRMWARE_SET_DOMAIN_STATE, 64 + &packet, sizeof(packet)); 65 + } 66 + 67 + static int rpi_domain_off(struct generic_pm_domain *domain) 68 + { 69 + struct rpi_power_domain *rpi_domain = 70 + container_of(domain, struct rpi_power_domain, base); 71 + 72 + return rpi_firmware_set_power(rpi_domain, false); 73 + } 74 + 75 + static int rpi_domain_on(struct generic_pm_domain *domain) 76 + { 77 + struct rpi_power_domain *rpi_domain = 78 + container_of(domain, struct rpi_power_domain, base); 79 + 80 + return rpi_firmware_set_power(rpi_domain, true); 81 + } 82 + 83 + static void rpi_common_init_power_domain(struct rpi_power_domains *rpi_domains, 84 + int xlate_index, const char *name) 85 + { 86 + struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index]; 87 + 88 + dom->fw = rpi_domains->fw; 89 + 90 + dom->base.name = name; 91 + dom->base.power_on = rpi_domain_on; 92 + dom->base.power_off = rpi_domain_off; 93 + 94 + /* 95 + * Treat all power domains as off at boot. 96 + * 97 + * The firmware itself may be keeping some domains on, but 98 + * from Linux's perspective all we control is the refcounts 99 + * that we give to the firmware, and we can't ask the firmware 100 + * to turn off something that we haven't ourselves turned on. 101 + */ 102 + pm_genpd_init(&dom->base, NULL, true); 103 + 104 + rpi_domains->xlate.domains[xlate_index] = &dom->base; 105 + } 106 + 107 + static void rpi_init_power_domain(struct rpi_power_domains *rpi_domains, 108 + int xlate_index, const char *name) 109 + { 110 + struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index]; 111 + 112 + if (!rpi_domains->has_new_interface) 113 + return; 114 + 115 + /* The DT binding index is the firmware's domain index minus one. */ 116 + dom->domain = xlate_index + 1; 117 + 118 + rpi_common_init_power_domain(rpi_domains, xlate_index, name); 119 + } 120 + 121 + static void rpi_init_old_power_domain(struct rpi_power_domains *rpi_domains, 122 + int xlate_index, int domain, 123 + const char *name) 124 + { 125 + struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index]; 126 + 127 + dom->old_interface = true; 128 + dom->domain = domain; 129 + 130 + rpi_common_init_power_domain(rpi_domains, xlate_index, name); 131 + } 132 + 133 + /* 134 + * Detects whether the firmware supports the new power domains interface. 135 + * 136 + * The firmware doesn't actually return an error on an unknown tag, 137 + * and just skips over it, so we do the detection by putting an 138 + * unexpected value in the return field and checking if it was 139 + * unchanged. 140 + */ 141 + static bool 142 + rpi_has_new_domain_support(struct rpi_power_domains *rpi_domains) 143 + { 144 + struct rpi_power_domain_packet packet; 145 + int ret; 146 + 147 + packet.domain = RPI_POWER_DOMAIN_ARM; 148 + packet.on = ~0; 149 + 150 + ret = rpi_firmware_property(rpi_domains->fw, 151 + RPI_FIRMWARE_GET_DOMAIN_STATE, 152 + &packet, sizeof(packet)); 153 + 154 + return ret == 0 && packet.on != ~0; 155 + } 156 + 157 + static int rpi_power_probe(struct platform_device *pdev) 158 + { 159 + struct device_node *fw_np; 160 + struct device *dev = &pdev->dev; 161 + struct rpi_power_domains *rpi_domains; 162 + 163 + rpi_domains = devm_kzalloc(dev, sizeof(*rpi_domains), GFP_KERNEL); 164 + if (!rpi_domains) 165 + return -ENOMEM; 166 + 167 + rpi_domains->xlate.domains = 168 + devm_kzalloc(dev, sizeof(*rpi_domains->xlate.domains) * 169 + RPI_POWER_DOMAIN_COUNT, GFP_KERNEL); 170 + if (!rpi_domains->xlate.domains) 171 + return -ENOMEM; 172 + 173 + rpi_domains->xlate.num_domains = RPI_POWER_DOMAIN_COUNT; 174 + 175 + fw_np = of_parse_phandle(pdev->dev.of_node, "firmware", 0); 176 + if (!fw_np) { 177 + dev_err(&pdev->dev, "no firmware node\n"); 178 + return -ENODEV; 179 + } 180 + 181 + rpi_domains->fw = rpi_firmware_get(fw_np); 182 + of_node_put(fw_np); 183 + if (!rpi_domains->fw) 184 + return -EPROBE_DEFER; 185 + 186 + rpi_domains->has_new_interface = 187 + rpi_has_new_domain_support(rpi_domains); 188 + 189 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C0, "I2C0"); 190 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C1, "I2C1"); 191 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C2, "I2C2"); 192 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VIDEO_SCALER, 193 + "VIDEO_SCALER"); 194 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VPU1, "VPU1"); 195 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_HDMI, "HDMI"); 196 + 197 + /* 198 + * Use the old firmware interface for USB power, so that we 199 + * can turn it on even if the firmware hasn't been updated. 200 + */ 201 + rpi_init_old_power_domain(rpi_domains, RPI_POWER_DOMAIN_USB, 202 + RPI_OLD_POWER_DOMAIN_USB, "USB"); 203 + 204 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VEC, "VEC"); 205 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_JPEG, "JPEG"); 206 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_H264, "H264"); 207 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_V3D, "V3D"); 208 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_ISP, "ISP"); 209 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_UNICAM0, "UNICAM0"); 210 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_UNICAM1, "UNICAM1"); 211 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CCP2RX, "CCP2RX"); 212 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CSI2, "CSI2"); 213 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CPI, "CPI"); 214 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_DSI0, "DSI0"); 215 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_DSI1, "DSI1"); 216 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_TRANSPOSER, 217 + "TRANSPOSER"); 218 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CCP2TX, "CCP2TX"); 219 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CDP, "CDP"); 220 + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_ARM, "ARM"); 221 + 222 + of_genpd_add_provider_onecell(dev->of_node, &rpi_domains->xlate); 223 + 224 + platform_set_drvdata(pdev, rpi_domains); 225 + 226 + return 0; 227 + } 228 + 229 + static const struct of_device_id rpi_power_of_match[] = { 230 + { .compatible = "raspberrypi,bcm2835-power", }, 231 + {}, 232 + }; 233 + MODULE_DEVICE_TABLE(of, rpi_power_of_match); 234 + 235 + static struct platform_driver rpi_power_driver = { 236 + .driver = { 237 + .name = "raspberrypi-power", 238 + .of_match_table = rpi_power_of_match, 239 + }, 240 + .probe = rpi_power_probe, 241 + }; 242 + builtin_platform_driver(rpi_power_driver); 243 + 244 + MODULE_AUTHOR("Alexander Aring <aar@pengutronix.de>"); 245 + MODULE_AUTHOR("Eric Anholt <eric@anholt.net>"); 246 + MODULE_DESCRIPTION("Raspberry Pi power domain driver"); 247 + MODULE_LICENSE("GPL v2");
+29 -3
drivers/soc/mediatek/mtk-scpsys.c
··· 15 15 #include <linux/io.h> 16 16 #include <linux/kernel.h> 17 17 #include <linux/mfd/syscon.h> 18 - #include <linux/module.h> 18 + #include <linux/init.h> 19 19 #include <linux/of_device.h> 20 20 #include <linux/platform_device.h> 21 21 #include <linux/pm_domain.h> 22 22 #include <linux/regmap.h> 23 23 #include <linux/soc/mediatek/infracfg.h> 24 + #include <linux/regulator/consumer.h> 24 25 #include <dt-bindings/power/mt8173-power.h> 25 26 26 27 #define SPM_VDE_PWR_CON 0x0210 ··· 180 179 u32 sram_pdn_ack_bits; 181 180 u32 bus_prot_mask; 182 181 bool active_wakeup; 182 + struct regulator *supply; 183 183 }; 184 184 185 185 struct scp { ··· 222 220 u32 val; 223 221 int ret; 224 222 int i; 223 + 224 + if (scpd->supply) { 225 + ret = regulator_enable(scpd->supply); 226 + if (ret) 227 + return ret; 228 + } 225 229 226 230 for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) { 227 231 ret = clk_prepare_enable(scpd->clk[i]); ··· 307 299 clk_disable_unprepare(scpd->clk[i]); 308 300 } 309 301 err_clk: 302 + if (scpd->supply) 303 + regulator_disable(scpd->supply); 304 + 310 305 dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name); 311 306 312 307 return ret; ··· 390 379 for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) 391 380 clk_disable_unprepare(scpd->clk[i]); 392 381 382 + if (scpd->supply) 383 + regulator_disable(scpd->supply); 384 + 393 385 return 0; 394 386 395 387 out: ··· 460 446 dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n", 461 447 PTR_ERR(scp->infracfg)); 462 448 return PTR_ERR(scp->infracfg); 449 + } 450 + 451 + for (i = 0; i < NUM_DOMAINS; i++) { 452 + struct scp_domain *scpd = &scp->domains[i]; 453 + const struct scp_domain_data *data = &scp_domain_data[i]; 454 + 455 + scpd->supply = devm_regulator_get_optional(&pdev->dev, data->name); 456 + if (IS_ERR(scpd->supply)) { 457 + if (PTR_ERR(scpd->supply) == -ENODEV) 458 + scpd->supply = NULL; 459 + else 460 + return PTR_ERR(scpd->supply); 461 + } 463 462 } 464 463 465 464 pd_data->num_domains = NUM_DOMAINS; ··· 548 521 .of_match_table = of_match_ptr(of_scpsys_match_tbl), 549 522 }, 550 523 }; 551 - 552 - module_platform_driver_probe(scpsys_drv, scpsys_probe); 524 + builtin_platform_driver_probe(scpsys_drv, scpsys_probe);
+27
drivers/soc/qcom/Kconfig
··· 13 13 config QCOM_PM 14 14 bool "Qualcomm Power Management" 15 15 depends on ARCH_QCOM && !ARM64 16 + select ARM_CPU_SUSPEND 16 17 select QCOM_SCM 17 18 help 18 19 QCOM Platform specific power driver to manage cores and L2 low power ··· 50 49 51 50 Say M here if you want to include support for the Qualcomm RPM as a 52 51 module. This will build a module called "qcom-smd-rpm". 52 + 53 + config QCOM_SMEM_STATE 54 + bool 55 + 56 + config QCOM_SMP2P 57 + tristate "Qualcomm Shared Memory Point to Point support" 58 + depends on QCOM_SMEM 59 + select QCOM_SMEM_STATE 60 + help 61 + Say yes here to support the Qualcomm Shared Memory Point to Point 62 + protocol. 63 + 64 + config QCOM_SMSM 65 + tristate "Qualcomm Shared Memory State Machine" 66 + depends on QCOM_SMEM 67 + select QCOM_SMEM_STATE 68 + help 69 + Say yes here to support the Qualcomm Shared Memory State Machine. 70 + The state machine is represented by bits in shared memory. 71 + 72 + config QCOM_WCNSS_CTRL 73 + tristate "Qualcomm WCNSS control driver" 74 + depends on QCOM_SMD 75 + help 76 + Client driver for the WCNSS_CTRL SMD channel, used to download nv 77 + firmware to a newly booted WCNSS chip.
+4
drivers/soc/qcom/Makefile
··· 3 3 obj-$(CONFIG_QCOM_SMD) += smd.o 4 4 obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o 5 5 obj-$(CONFIG_QCOM_SMEM) += smem.o 6 + obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o 7 + obj-$(CONFIG_QCOM_SMP2P) += smp2p.o 8 + obj-$(CONFIG_QCOM_SMSM) += smsm.o 9 + obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
+2
drivers/soc/qcom/smd-rpm.c
··· 219 219 } 220 220 221 221 static const struct of_device_id qcom_smd_rpm_of_match[] = { 222 + { .compatible = "qcom,rpm-apq8084" }, 223 + { .compatible = "qcom,rpm-msm8916" }, 222 224 { .compatible = "qcom,rpm-msm8974" }, 223 225 {} 224 226 };
+201
drivers/soc/qcom/smem_state.c
··· 1 + /* 2 + * Copyright (c) 2015, Sony Mobile Communications Inc. 3 + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 and 7 + * only version 2 as published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + #include <linux/device.h> 15 + #include <linux/list.h> 16 + #include <linux/module.h> 17 + #include <linux/of.h> 18 + #include <linux/slab.h> 19 + #include <linux/soc/qcom/smem_state.h> 20 + 21 + static LIST_HEAD(smem_states); 22 + static DEFINE_MUTEX(list_lock); 23 + 24 + /** 25 + * struct qcom_smem_state - state context 26 + * @refcount: refcount for the state 27 + * @orphan: boolean indicator that this state has been unregistered 28 + * @list: entry in smem_states list 29 + * @of_node: of_node to use for matching the state in DT 30 + * @priv: implementation private data 31 + * @ops: ops for the state 32 + */ 33 + struct qcom_smem_state { 34 + struct kref refcount; 35 + bool orphan; 36 + 37 + struct list_head list; 38 + struct device_node *of_node; 39 + 40 + void *priv; 41 + 42 + struct qcom_smem_state_ops ops; 43 + }; 44 + 45 + /** 46 + * qcom_smem_state_update_bits() - update the masked bits in state with value 47 + * @state: state handle acquired by calling qcom_smem_state_get() 48 + * @mask: bit mask for the change 49 + * @value: new value for the masked bits 50 + * 51 + * Returns 0 on success, otherwise negative errno. 52 + */ 53 + int qcom_smem_state_update_bits(struct qcom_smem_state *state, 54 + u32 mask, 55 + u32 value) 56 + { 57 + if (state->orphan) 58 + return -ENXIO; 59 + 60 + if (!state->ops.update_bits) 61 + return -ENOTSUPP; 62 + 63 + return state->ops.update_bits(state->priv, mask, value); 64 + } 65 + EXPORT_SYMBOL_GPL(qcom_smem_state_update_bits); 66 + 67 + static struct qcom_smem_state *of_node_to_state(struct device_node *np) 68 + { 69 + struct qcom_smem_state *state; 70 + 71 + mutex_lock(&list_lock); 72 + 73 + list_for_each_entry(state, &smem_states, list) { 74 + if (state->of_node == np) { 75 + kref_get(&state->refcount); 76 + goto unlock; 77 + } 78 + } 79 + state = ERR_PTR(-EPROBE_DEFER); 80 + 81 + unlock: 82 + mutex_unlock(&list_lock); 83 + 84 + return state; 85 + } 86 + 87 + /** 88 + * qcom_smem_state_get() - acquire handle to a state 89 + * @dev: client device pointer 90 + * @con_id: name of the state to lookup 91 + * @bit: flags from the state reference, indicating which bit's affected 92 + * 93 + * Returns handle to the state, or ERR_PTR(). qcom_smem_state_put() must be 94 + * called to release the returned state handle. 95 + */ 96 + struct qcom_smem_state *qcom_smem_state_get(struct device *dev, 97 + const char *con_id, 98 + unsigned *bit) 99 + { 100 + struct qcom_smem_state *state; 101 + struct of_phandle_args args; 102 + int index = 0; 103 + int ret; 104 + 105 + if (con_id) { 106 + index = of_property_match_string(dev->of_node, 107 + "qcom,state-names", 108 + con_id); 109 + if (index < 0) { 110 + dev_err(dev, "missing qcom,state-names\n"); 111 + return ERR_PTR(index); 112 + } 113 + } 114 + 115 + ret = of_parse_phandle_with_args(dev->of_node, 116 + "qcom,state", 117 + "#qcom,state-cells", 118 + index, 119 + &args); 120 + if (ret) { 121 + dev_err(dev, "failed to parse qcom,state property\n"); 122 + return ERR_PTR(ret); 123 + } 124 + 125 + if (args.args_count != 1) { 126 + dev_err(dev, "invalid #qcom,state-cells\n"); 127 + return ERR_PTR(-EINVAL); 128 + } 129 + 130 + state = of_node_to_state(args.np); 131 + if (IS_ERR(state)) 132 + goto put; 133 + 134 + *bit = args.args[0]; 135 + 136 + put: 137 + of_node_put(args.np); 138 + return state; 139 + } 140 + EXPORT_SYMBOL_GPL(qcom_smem_state_get); 141 + 142 + static void qcom_smem_state_release(struct kref *ref) 143 + { 144 + struct qcom_smem_state *state = container_of(ref, struct qcom_smem_state, refcount); 145 + 146 + list_del(&state->list); 147 + kfree(state); 148 + } 149 + 150 + /** 151 + * qcom_smem_state_put() - release state handle 152 + * @state: state handle to be released 153 + */ 154 + void qcom_smem_state_put(struct qcom_smem_state *state) 155 + { 156 + mutex_lock(&list_lock); 157 + kref_put(&state->refcount, qcom_smem_state_release); 158 + mutex_unlock(&list_lock); 159 + } 160 + EXPORT_SYMBOL_GPL(qcom_smem_state_put); 161 + 162 + /** 163 + * qcom_smem_state_register() - register a new state 164 + * @of_node: of_node used for matching client lookups 165 + * @ops: implementation ops 166 + * @priv: implementation specific private data 167 + */ 168 + struct qcom_smem_state *qcom_smem_state_register(struct device_node *of_node, 169 + const struct qcom_smem_state_ops *ops, 170 + void *priv) 171 + { 172 + struct qcom_smem_state *state; 173 + 174 + state = kzalloc(sizeof(*state), GFP_KERNEL); 175 + if (!state) 176 + return ERR_PTR(-ENOMEM); 177 + 178 + kref_init(&state->refcount); 179 + 180 + state->of_node = of_node; 181 + state->ops = *ops; 182 + state->priv = priv; 183 + 184 + mutex_lock(&list_lock); 185 + list_add(&state->list, &smem_states); 186 + mutex_unlock(&list_lock); 187 + 188 + return state; 189 + } 190 + EXPORT_SYMBOL_GPL(qcom_smem_state_register); 191 + 192 + /** 193 + * qcom_smem_state_unregister() - unregister a registered state 194 + * @state: state handle to be unregistered 195 + */ 196 + void qcom_smem_state_unregister(struct qcom_smem_state *state) 197 + { 198 + state->orphan = true; 199 + qcom_smem_state_put(state); 200 + } 201 + EXPORT_SYMBOL_GPL(qcom_smem_state_unregister);
+578
drivers/soc/qcom/smp2p.c
··· 1 + /* 2 + * Copyright (c) 2015, Sony Mobile Communications AB. 3 + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 and 7 + * only version 2 as published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + 15 + #include <linux/interrupt.h> 16 + #include <linux/list.h> 17 + #include <linux/io.h> 18 + #include <linux/of.h> 19 + #include <linux/irq.h> 20 + #include <linux/irqdomain.h> 21 + #include <linux/mfd/syscon.h> 22 + #include <linux/module.h> 23 + #include <linux/platform_device.h> 24 + #include <linux/regmap.h> 25 + #include <linux/soc/qcom/smem.h> 26 + #include <linux/soc/qcom/smem_state.h> 27 + #include <linux/spinlock.h> 28 + 29 + /* 30 + * The Shared Memory Point to Point (SMP2P) protocol facilitates communication 31 + * of a single 32-bit value between two processors. Each value has a single 32 + * writer (the local side) and a single reader (the remote side). Values are 33 + * uniquely identified in the system by the directed edge (local processor ID 34 + * to remote processor ID) and a string identifier. 35 + * 36 + * Each processor is responsible for creating the outgoing SMEM items and each 37 + * item is writable by the local processor and readable by the remote 38 + * processor. By using two separate SMEM items that are single-reader and 39 + * single-writer, SMP2P does not require any remote locking mechanisms. 40 + * 41 + * The driver uses the Linux GPIO and interrupt framework to expose a virtual 42 + * GPIO for each outbound entry and a virtual interrupt controller for each 43 + * inbound entry. 44 + */ 45 + 46 + #define SMP2P_MAX_ENTRY 16 47 + #define SMP2P_MAX_ENTRY_NAME 16 48 + 49 + #define SMP2P_FEATURE_SSR_ACK 0x1 50 + 51 + #define SMP2P_MAGIC 0x504d5324 52 + 53 + /** 54 + * struct smp2p_smem_item - in memory communication structure 55 + * @magic: magic number 56 + * @version: version - must be 1 57 + * @features: features flag - currently unused 58 + * @local_pid: processor id of sending end 59 + * @remote_pid: processor id of receiving end 60 + * @total_entries: number of entries - always SMP2P_MAX_ENTRY 61 + * @valid_entries: number of allocated entries 62 + * @flags: 63 + * @entries: individual communication entries 64 + * @name: name of the entry 65 + * @value: content of the entry 66 + */ 67 + struct smp2p_smem_item { 68 + u32 magic; 69 + u8 version; 70 + unsigned features:24; 71 + u16 local_pid; 72 + u16 remote_pid; 73 + u16 total_entries; 74 + u16 valid_entries; 75 + u32 flags; 76 + 77 + struct { 78 + u8 name[SMP2P_MAX_ENTRY_NAME]; 79 + u32 value; 80 + } entries[SMP2P_MAX_ENTRY]; 81 + } __packed; 82 + 83 + /** 84 + * struct smp2p_entry - driver context matching one entry 85 + * @node: list entry to keep track of allocated entries 86 + * @smp2p: reference to the device driver context 87 + * @name: name of the entry, to match against smp2p_smem_item 88 + * @value: pointer to smp2p_smem_item entry value 89 + * @last_value: last handled value 90 + * @domain: irq_domain for inbound entries 91 + * @irq_enabled:bitmap to track enabled irq bits 92 + * @irq_rising: bitmap to mark irq bits for rising detection 93 + * @irq_falling:bitmap to mark irq bits for falling detection 94 + * @state: smem state handle 95 + * @lock: spinlock to protect read-modify-write of the value 96 + */ 97 + struct smp2p_entry { 98 + struct list_head node; 99 + struct qcom_smp2p *smp2p; 100 + 101 + const char *name; 102 + u32 *value; 103 + u32 last_value; 104 + 105 + struct irq_domain *domain; 106 + DECLARE_BITMAP(irq_enabled, 32); 107 + DECLARE_BITMAP(irq_rising, 32); 108 + DECLARE_BITMAP(irq_falling, 32); 109 + 110 + struct qcom_smem_state *state; 111 + 112 + spinlock_t lock; 113 + }; 114 + 115 + #define SMP2P_INBOUND 0 116 + #define SMP2P_OUTBOUND 1 117 + 118 + /** 119 + * struct qcom_smp2p - device driver context 120 + * @dev: device driver handle 121 + * @in: pointer to the inbound smem item 122 + * @smem_items: ids of the two smem items 123 + * @valid_entries: already scanned inbound entries 124 + * @local_pid: processor id of the inbound edge 125 + * @remote_pid: processor id of the outbound edge 126 + * @ipc_regmap: regmap for the outbound ipc 127 + * @ipc_offset: offset within the regmap 128 + * @ipc_bit: bit in regmap@offset to kick to signal remote processor 129 + * @inbound: list of inbound entries 130 + * @outbound: list of outbound entries 131 + */ 132 + struct qcom_smp2p { 133 + struct device *dev; 134 + 135 + struct smp2p_smem_item *in; 136 + struct smp2p_smem_item *out; 137 + 138 + unsigned smem_items[SMP2P_OUTBOUND + 1]; 139 + 140 + unsigned valid_entries; 141 + 142 + unsigned local_pid; 143 + unsigned remote_pid; 144 + 145 + struct regmap *ipc_regmap; 146 + int ipc_offset; 147 + int ipc_bit; 148 + 149 + struct list_head inbound; 150 + struct list_head outbound; 151 + }; 152 + 153 + static void qcom_smp2p_kick(struct qcom_smp2p *smp2p) 154 + { 155 + /* Make sure any updated data is written before the kick */ 156 + wmb(); 157 + regmap_write(smp2p->ipc_regmap, smp2p->ipc_offset, BIT(smp2p->ipc_bit)); 158 + } 159 + 160 + /** 161 + * qcom_smp2p_intr() - interrupt handler for incoming notifications 162 + * @irq: unused 163 + * @data: smp2p driver context 164 + * 165 + * Handle notifications from the remote side to handle newly allocated entries 166 + * or any changes to the state bits of existing entries. 167 + */ 168 + static irqreturn_t qcom_smp2p_intr(int irq, void *data) 169 + { 170 + struct smp2p_smem_item *in; 171 + struct smp2p_entry *entry; 172 + struct qcom_smp2p *smp2p = data; 173 + unsigned smem_id = smp2p->smem_items[SMP2P_INBOUND]; 174 + unsigned pid = smp2p->remote_pid; 175 + size_t size; 176 + int irq_pin; 177 + u32 status; 178 + char buf[SMP2P_MAX_ENTRY_NAME]; 179 + u32 val; 180 + int i; 181 + 182 + in = smp2p->in; 183 + 184 + /* Acquire smem item, if not already found */ 185 + if (!in) { 186 + in = qcom_smem_get(pid, smem_id, &size); 187 + if (IS_ERR(in)) { 188 + dev_err(smp2p->dev, 189 + "Unable to acquire remote smp2p item\n"); 190 + return IRQ_HANDLED; 191 + } 192 + 193 + smp2p->in = in; 194 + } 195 + 196 + /* Match newly created entries */ 197 + for (i = smp2p->valid_entries; i < in->valid_entries; i++) { 198 + list_for_each_entry(entry, &smp2p->inbound, node) { 199 + memcpy_fromio(buf, in->entries[i].name, sizeof(buf)); 200 + if (!strcmp(buf, entry->name)) { 201 + entry->value = &in->entries[i].value; 202 + break; 203 + } 204 + } 205 + } 206 + smp2p->valid_entries = i; 207 + 208 + /* Fire interrupts based on any value changes */ 209 + list_for_each_entry(entry, &smp2p->inbound, node) { 210 + /* Ignore entries not yet allocated by the remote side */ 211 + if (!entry->value) 212 + continue; 213 + 214 + val = readl(entry->value); 215 + 216 + status = val ^ entry->last_value; 217 + entry->last_value = val; 218 + 219 + /* No changes of this entry? */ 220 + if (!status) 221 + continue; 222 + 223 + for_each_set_bit(i, entry->irq_enabled, 32) { 224 + if (!(status & BIT(i))) 225 + continue; 226 + 227 + if ((val & BIT(i) && test_bit(i, entry->irq_rising)) || 228 + (!(val & BIT(i)) && test_bit(i, entry->irq_falling))) { 229 + irq_pin = irq_find_mapping(entry->domain, i); 230 + handle_nested_irq(irq_pin); 231 + } 232 + } 233 + } 234 + 235 + return IRQ_HANDLED; 236 + } 237 + 238 + static void smp2p_mask_irq(struct irq_data *irqd) 239 + { 240 + struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd); 241 + irq_hw_number_t irq = irqd_to_hwirq(irqd); 242 + 243 + clear_bit(irq, entry->irq_enabled); 244 + } 245 + 246 + static void smp2p_unmask_irq(struct irq_data *irqd) 247 + { 248 + struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd); 249 + irq_hw_number_t irq = irqd_to_hwirq(irqd); 250 + 251 + set_bit(irq, entry->irq_enabled); 252 + } 253 + 254 + static int smp2p_set_irq_type(struct irq_data *irqd, unsigned int type) 255 + { 256 + struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd); 257 + irq_hw_number_t irq = irqd_to_hwirq(irqd); 258 + 259 + if (!(type & IRQ_TYPE_EDGE_BOTH)) 260 + return -EINVAL; 261 + 262 + if (type & IRQ_TYPE_EDGE_RISING) 263 + set_bit(irq, entry->irq_rising); 264 + else 265 + clear_bit(irq, entry->irq_rising); 266 + 267 + if (type & IRQ_TYPE_EDGE_FALLING) 268 + set_bit(irq, entry->irq_falling); 269 + else 270 + clear_bit(irq, entry->irq_falling); 271 + 272 + return 0; 273 + } 274 + 275 + static struct irq_chip smp2p_irq_chip = { 276 + .name = "smp2p", 277 + .irq_mask = smp2p_mask_irq, 278 + .irq_unmask = smp2p_unmask_irq, 279 + .irq_set_type = smp2p_set_irq_type, 280 + }; 281 + 282 + static int smp2p_irq_map(struct irq_domain *d, 283 + unsigned int irq, 284 + irq_hw_number_t hw) 285 + { 286 + struct smp2p_entry *entry = d->host_data; 287 + 288 + irq_set_chip_and_handler(irq, &smp2p_irq_chip, handle_level_irq); 289 + irq_set_chip_data(irq, entry); 290 + irq_set_nested_thread(irq, 1); 291 + irq_set_noprobe(irq); 292 + 293 + return 0; 294 + } 295 + 296 + static const struct irq_domain_ops smp2p_irq_ops = { 297 + .map = smp2p_irq_map, 298 + .xlate = irq_domain_xlate_twocell, 299 + }; 300 + 301 + static int qcom_smp2p_inbound_entry(struct qcom_smp2p *smp2p, 302 + struct smp2p_entry *entry, 303 + struct device_node *node) 304 + { 305 + entry->domain = irq_domain_add_linear(node, 32, &smp2p_irq_ops, entry); 306 + if (!entry->domain) { 307 + dev_err(smp2p->dev, "failed to add irq_domain\n"); 308 + return -ENOMEM; 309 + } 310 + 311 + return 0; 312 + } 313 + 314 + static int smp2p_update_bits(void *data, u32 mask, u32 value) 315 + { 316 + struct smp2p_entry *entry = data; 317 + u32 orig; 318 + u32 val; 319 + 320 + spin_lock(&entry->lock); 321 + val = orig = readl(entry->value); 322 + val &= ~mask; 323 + val |= value; 324 + writel(val, entry->value); 325 + spin_unlock(&entry->lock); 326 + 327 + if (val != orig) 328 + qcom_smp2p_kick(entry->smp2p); 329 + 330 + return 0; 331 + } 332 + 333 + static const struct qcom_smem_state_ops smp2p_state_ops = { 334 + .update_bits = smp2p_update_bits, 335 + }; 336 + 337 + static int qcom_smp2p_outbound_entry(struct qcom_smp2p *smp2p, 338 + struct smp2p_entry *entry, 339 + struct device_node *node) 340 + { 341 + struct smp2p_smem_item *out = smp2p->out; 342 + char buf[SMP2P_MAX_ENTRY_NAME] = {}; 343 + 344 + /* Allocate an entry from the smem item */ 345 + strlcpy(buf, entry->name, SMP2P_MAX_ENTRY_NAME); 346 + memcpy_toio(out->entries[out->valid_entries].name, buf, SMP2P_MAX_ENTRY_NAME); 347 + out->valid_entries++; 348 + 349 + /* Make the logical entry reference the physical value */ 350 + entry->value = &out->entries[out->valid_entries].value; 351 + 352 + entry->state = qcom_smem_state_register(node, &smp2p_state_ops, entry); 353 + if (IS_ERR(entry->state)) { 354 + dev_err(smp2p->dev, "failed to register qcom_smem_state\n"); 355 + return PTR_ERR(entry->state); 356 + } 357 + 358 + return 0; 359 + } 360 + 361 + static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p) 362 + { 363 + struct smp2p_smem_item *out; 364 + unsigned smem_id = smp2p->smem_items[SMP2P_OUTBOUND]; 365 + unsigned pid = smp2p->remote_pid; 366 + int ret; 367 + 368 + ret = qcom_smem_alloc(pid, smem_id, sizeof(*out)); 369 + if (ret < 0 && ret != -EEXIST) { 370 + if (ret != -EPROBE_DEFER) 371 + dev_err(smp2p->dev, 372 + "unable to allocate local smp2p item\n"); 373 + return ret; 374 + } 375 + 376 + out = qcom_smem_get(pid, smem_id, NULL); 377 + if (IS_ERR(out)) { 378 + dev_err(smp2p->dev, "Unable to acquire local smp2p item\n"); 379 + return PTR_ERR(out); 380 + } 381 + 382 + memset(out, 0, sizeof(*out)); 383 + out->magic = SMP2P_MAGIC; 384 + out->local_pid = smp2p->local_pid; 385 + out->remote_pid = smp2p->remote_pid; 386 + out->total_entries = SMP2P_MAX_ENTRY; 387 + out->valid_entries = 0; 388 + 389 + /* 390 + * Make sure the rest of the header is written before we validate the 391 + * item by writing a valid version number. 392 + */ 393 + wmb(); 394 + out->version = 1; 395 + 396 + qcom_smp2p_kick(smp2p); 397 + 398 + smp2p->out = out; 399 + 400 + return 0; 401 + } 402 + 403 + static int smp2p_parse_ipc(struct qcom_smp2p *smp2p) 404 + { 405 + struct device_node *syscon; 406 + struct device *dev = smp2p->dev; 407 + const char *key; 408 + int ret; 409 + 410 + syscon = of_parse_phandle(dev->of_node, "qcom,ipc", 0); 411 + if (!syscon) { 412 + dev_err(dev, "no qcom,ipc node\n"); 413 + return -ENODEV; 414 + } 415 + 416 + smp2p->ipc_regmap = syscon_node_to_regmap(syscon); 417 + if (IS_ERR(smp2p->ipc_regmap)) 418 + return PTR_ERR(smp2p->ipc_regmap); 419 + 420 + key = "qcom,ipc"; 421 + ret = of_property_read_u32_index(dev->of_node, key, 1, &smp2p->ipc_offset); 422 + if (ret < 0) { 423 + dev_err(dev, "no offset in %s\n", key); 424 + return -EINVAL; 425 + } 426 + 427 + ret = of_property_read_u32_index(dev->of_node, key, 2, &smp2p->ipc_bit); 428 + if (ret < 0) { 429 + dev_err(dev, "no bit in %s\n", key); 430 + return -EINVAL; 431 + } 432 + 433 + return 0; 434 + } 435 + 436 + static int qcom_smp2p_probe(struct platform_device *pdev) 437 + { 438 + struct smp2p_entry *entry; 439 + struct device_node *node; 440 + struct qcom_smp2p *smp2p; 441 + const char *key; 442 + int irq; 443 + int ret; 444 + 445 + smp2p = devm_kzalloc(&pdev->dev, sizeof(*smp2p), GFP_KERNEL); 446 + if (!smp2p) 447 + return -ENOMEM; 448 + 449 + smp2p->dev = &pdev->dev; 450 + INIT_LIST_HEAD(&smp2p->inbound); 451 + INIT_LIST_HEAD(&smp2p->outbound); 452 + 453 + platform_set_drvdata(pdev, smp2p); 454 + 455 + ret = smp2p_parse_ipc(smp2p); 456 + if (ret) 457 + return ret; 458 + 459 + key = "qcom,smem"; 460 + ret = of_property_read_u32_array(pdev->dev.of_node, key, 461 + smp2p->smem_items, 2); 462 + if (ret) 463 + return ret; 464 + 465 + key = "qcom,local-pid"; 466 + ret = of_property_read_u32(pdev->dev.of_node, key, &smp2p->local_pid); 467 + if (ret < 0) { 468 + dev_err(&pdev->dev, "failed to read %s\n", key); 469 + return -EINVAL; 470 + } 471 + 472 + key = "qcom,remote-pid"; 473 + ret = of_property_read_u32(pdev->dev.of_node, key, &smp2p->remote_pid); 474 + if (ret < 0) { 475 + dev_err(&pdev->dev, "failed to read %s\n", key); 476 + return -EINVAL; 477 + } 478 + 479 + irq = platform_get_irq(pdev, 0); 480 + if (irq < 0) { 481 + dev_err(&pdev->dev, "unable to acquire smp2p interrupt\n"); 482 + return irq; 483 + } 484 + 485 + ret = qcom_smp2p_alloc_outbound_item(smp2p); 486 + if (ret < 0) 487 + return ret; 488 + 489 + for_each_available_child_of_node(pdev->dev.of_node, node) { 490 + entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL); 491 + if (!entry) { 492 + ret = -ENOMEM; 493 + goto unwind_interfaces; 494 + } 495 + 496 + entry->smp2p = smp2p; 497 + spin_lock_init(&entry->lock); 498 + 499 + ret = of_property_read_string(node, "qcom,entry-name", &entry->name); 500 + if (ret < 0) 501 + goto unwind_interfaces; 502 + 503 + if (of_property_read_bool(node, "interrupt-controller")) { 504 + ret = qcom_smp2p_inbound_entry(smp2p, entry, node); 505 + if (ret < 0) 506 + goto unwind_interfaces; 507 + 508 + list_add(&entry->node, &smp2p->inbound); 509 + } else { 510 + ret = qcom_smp2p_outbound_entry(smp2p, entry, node); 511 + if (ret < 0) 512 + goto unwind_interfaces; 513 + 514 + list_add(&entry->node, &smp2p->outbound); 515 + } 516 + } 517 + 518 + /* Kick the outgoing edge after allocating entries */ 519 + qcom_smp2p_kick(smp2p); 520 + 521 + ret = devm_request_threaded_irq(&pdev->dev, irq, 522 + NULL, qcom_smp2p_intr, 523 + IRQF_ONESHOT, 524 + "smp2p", (void *)smp2p); 525 + if (ret) { 526 + dev_err(&pdev->dev, "failed to request interrupt\n"); 527 + goto unwind_interfaces; 528 + } 529 + 530 + 531 + return 0; 532 + 533 + unwind_interfaces: 534 + list_for_each_entry(entry, &smp2p->inbound, node) 535 + irq_domain_remove(entry->domain); 536 + 537 + list_for_each_entry(entry, &smp2p->outbound, node) 538 + qcom_smem_state_unregister(entry->state); 539 + 540 + smp2p->out->valid_entries = 0; 541 + 542 + return ret; 543 + } 544 + 545 + static int qcom_smp2p_remove(struct platform_device *pdev) 546 + { 547 + struct qcom_smp2p *smp2p = platform_get_drvdata(pdev); 548 + struct smp2p_entry *entry; 549 + 550 + list_for_each_entry(entry, &smp2p->inbound, node) 551 + irq_domain_remove(entry->domain); 552 + 553 + list_for_each_entry(entry, &smp2p->outbound, node) 554 + qcom_smem_state_unregister(entry->state); 555 + 556 + smp2p->out->valid_entries = 0; 557 + 558 + return 0; 559 + } 560 + 561 + static const struct of_device_id qcom_smp2p_of_match[] = { 562 + { .compatible = "qcom,smp2p" }, 563 + {} 564 + }; 565 + MODULE_DEVICE_TABLE(of, qcom_smp2p_of_match); 566 + 567 + static struct platform_driver qcom_smp2p_driver = { 568 + .probe = qcom_smp2p_probe, 569 + .remove = qcom_smp2p_remove, 570 + .driver = { 571 + .name = "qcom_smp2p", 572 + .of_match_table = qcom_smp2p_of_match, 573 + }, 574 + }; 575 + module_platform_driver(qcom_smp2p_driver); 576 + 577 + MODULE_DESCRIPTION("Qualcomm Shared Memory Point to Point driver"); 578 + MODULE_LICENSE("GPL v2");
+625
drivers/soc/qcom/smsm.c
··· 1 + /* 2 + * Copyright (c) 2015, Sony Mobile Communications Inc. 3 + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 and 7 + * only version 2 as published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + 15 + #include <linux/interrupt.h> 16 + #include <linux/mfd/syscon.h> 17 + #include <linux/module.h> 18 + #include <linux/of_irq.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/spinlock.h> 21 + #include <linux/regmap.h> 22 + #include <linux/soc/qcom/smem.h> 23 + #include <linux/soc/qcom/smem_state.h> 24 + 25 + /* 26 + * This driver implements the Qualcomm Shared Memory State Machine, a mechanism 27 + * for communicating single bit state information to remote processors. 28 + * 29 + * The implementation is based on two sections of shared memory; the first 30 + * holding the state bits and the second holding a matrix of subscription bits. 31 + * 32 + * The state bits are structured in entries of 32 bits, each belonging to one 33 + * system in the SoC. The entry belonging to the local system is considered 34 + * read-write, while the rest should be considered read-only. 35 + * 36 + * The subscription matrix consists of N bitmaps per entry, denoting interest 37 + * in updates of the entry for each of the N hosts. Upon updating a state bit 38 + * each host's subscription bitmap should be queried and the remote system 39 + * should be interrupted if they request so. 40 + * 41 + * The subscription matrix is laid out in entry-major order: 42 + * entry0: [host0 ... hostN] 43 + * . 44 + * . 45 + * entryM: [host0 ... hostN] 46 + * 47 + * A third, optional, shared memory region might contain information regarding 48 + * the number of entries in the state bitmap as well as number of columns in 49 + * the subscription matrix. 50 + */ 51 + 52 + /* 53 + * Shared memory identifiers, used to acquire handles to respective memory 54 + * region. 55 + */ 56 + #define SMEM_SMSM_SHARED_STATE 85 57 + #define SMEM_SMSM_CPU_INTR_MASK 333 58 + #define SMEM_SMSM_SIZE_INFO 419 59 + 60 + /* 61 + * Default sizes, in case SMEM_SMSM_SIZE_INFO is not found. 62 + */ 63 + #define SMSM_DEFAULT_NUM_ENTRIES 8 64 + #define SMSM_DEFAULT_NUM_HOSTS 3 65 + 66 + struct smsm_entry; 67 + struct smsm_host; 68 + 69 + /** 70 + * struct qcom_smsm - smsm driver context 71 + * @dev: smsm device pointer 72 + * @local_host: column in the subscription matrix representing this system 73 + * @num_hosts: number of columns in the subscription matrix 74 + * @num_entries: number of entries in the state map and rows in the subscription 75 + * matrix 76 + * @local_state: pointer to the local processor's state bits 77 + * @subscription: pointer to local processor's row in subscription matrix 78 + * @state: smem state handle 79 + * @lock: spinlock for read-modify-write of the outgoing state 80 + * @entries: context for each of the entries 81 + * @hosts: context for each of the hosts 82 + */ 83 + struct qcom_smsm { 84 + struct device *dev; 85 + 86 + u32 local_host; 87 + 88 + u32 num_hosts; 89 + u32 num_entries; 90 + 91 + u32 *local_state; 92 + u32 *subscription; 93 + struct qcom_smem_state *state; 94 + 95 + spinlock_t lock; 96 + 97 + struct smsm_entry *entries; 98 + struct smsm_host *hosts; 99 + }; 100 + 101 + /** 102 + * struct smsm_entry - per remote processor entry context 103 + * @smsm: back-reference to driver context 104 + * @domain: IRQ domain for this entry, if representing a remote system 105 + * @irq_enabled: bitmap of which state bits IRQs are enabled 106 + * @irq_rising: bitmap tracking if rising bits should be propagated 107 + * @irq_falling: bitmap tracking if falling bits should be propagated 108 + * @last_value: snapshot of state bits last time the interrupts where propagated 109 + * @remote_state: pointer to this entry's state bits 110 + * @subscription: pointer to a row in the subscription matrix representing this 111 + * entry 112 + */ 113 + struct smsm_entry { 114 + struct qcom_smsm *smsm; 115 + 116 + struct irq_domain *domain; 117 + DECLARE_BITMAP(irq_enabled, 32); 118 + DECLARE_BITMAP(irq_rising, 32); 119 + DECLARE_BITMAP(irq_falling, 32); 120 + u32 last_value; 121 + 122 + u32 *remote_state; 123 + u32 *subscription; 124 + }; 125 + 126 + /** 127 + * struct smsm_host - representation of a remote host 128 + * @ipc_regmap: regmap for outgoing interrupt 129 + * @ipc_offset: offset in @ipc_regmap for outgoing interrupt 130 + * @ipc_bit: bit in @ipc_regmap + @ipc_offset for outgoing interrupt 131 + */ 132 + struct smsm_host { 133 + struct regmap *ipc_regmap; 134 + int ipc_offset; 135 + int ipc_bit; 136 + }; 137 + 138 + /** 139 + * smsm_update_bits() - change bit in outgoing entry and inform subscribers 140 + * @data: smsm context pointer 141 + * @offset: bit in the entry 142 + * @value: new value 143 + * 144 + * Used to set and clear the bits in the outgoing/local entry and inform 145 + * subscribers about the change. 146 + */ 147 + static int smsm_update_bits(void *data, u32 mask, u32 value) 148 + { 149 + struct qcom_smsm *smsm = data; 150 + struct smsm_host *hostp; 151 + unsigned long flags; 152 + u32 changes; 153 + u32 host; 154 + u32 orig; 155 + u32 val; 156 + 157 + spin_lock_irqsave(&smsm->lock, flags); 158 + 159 + /* Update the entry */ 160 + val = orig = readl(smsm->local_state); 161 + val &= ~mask; 162 + val |= value; 163 + 164 + /* Don't signal if we didn't change the value */ 165 + changes = val ^ orig; 166 + if (!changes) { 167 + spin_unlock_irqrestore(&smsm->lock, flags); 168 + goto done; 169 + } 170 + 171 + /* Write out the new value */ 172 + writel(val, smsm->local_state); 173 + spin_unlock_irqrestore(&smsm->lock, flags); 174 + 175 + /* Make sure the value update is ordered before any kicks */ 176 + wmb(); 177 + 178 + /* Iterate over all hosts to check whom wants a kick */ 179 + for (host = 0; host < smsm->num_hosts; host++) { 180 + hostp = &smsm->hosts[host]; 181 + 182 + val = readl(smsm->subscription + host); 183 + if (val & changes && hostp->ipc_regmap) { 184 + regmap_write(hostp->ipc_regmap, 185 + hostp->ipc_offset, 186 + BIT(hostp->ipc_bit)); 187 + } 188 + } 189 + 190 + done: 191 + return 0; 192 + } 193 + 194 + static const struct qcom_smem_state_ops smsm_state_ops = { 195 + .update_bits = smsm_update_bits, 196 + }; 197 + 198 + /** 199 + * smsm_intr() - cascading IRQ handler for SMSM 200 + * @irq: unused 201 + * @data: entry related to this IRQ 202 + * 203 + * This function cascades an incoming interrupt from a remote system, based on 204 + * the state bits and configuration. 205 + */ 206 + static irqreturn_t smsm_intr(int irq, void *data) 207 + { 208 + struct smsm_entry *entry = data; 209 + unsigned i; 210 + int irq_pin; 211 + u32 changed; 212 + u32 val; 213 + 214 + val = readl(entry->remote_state); 215 + changed = val ^ entry->last_value; 216 + entry->last_value = val; 217 + 218 + for_each_set_bit(i, entry->irq_enabled, 32) { 219 + if (!(changed & BIT(i))) 220 + continue; 221 + 222 + if (val & BIT(i)) { 223 + if (test_bit(i, entry->irq_rising)) { 224 + irq_pin = irq_find_mapping(entry->domain, i); 225 + handle_nested_irq(irq_pin); 226 + } 227 + } else { 228 + if (test_bit(i, entry->irq_falling)) { 229 + irq_pin = irq_find_mapping(entry->domain, i); 230 + handle_nested_irq(irq_pin); 231 + } 232 + } 233 + } 234 + 235 + return IRQ_HANDLED; 236 + } 237 + 238 + /** 239 + * smsm_mask_irq() - un-subscribe from cascades of IRQs of a certain staus bit 240 + * @irqd: IRQ handle to be masked 241 + * 242 + * This un-subscribes the local CPU from interrupts upon changes to the defines 243 + * status bit. The bit is also cleared from cascading. 244 + */ 245 + static void smsm_mask_irq(struct irq_data *irqd) 246 + { 247 + struct smsm_entry *entry = irq_data_get_irq_chip_data(irqd); 248 + irq_hw_number_t irq = irqd_to_hwirq(irqd); 249 + struct qcom_smsm *smsm = entry->smsm; 250 + u32 val; 251 + 252 + if (entry->subscription) { 253 + val = readl(entry->subscription + smsm->local_host); 254 + val &= ~BIT(irq); 255 + writel(val, entry->subscription + smsm->local_host); 256 + } 257 + 258 + clear_bit(irq, entry->irq_enabled); 259 + } 260 + 261 + /** 262 + * smsm_unmask_irq() - subscribe to cascades of IRQs of a certain status bit 263 + * @irqd: IRQ handle to be unmasked 264 + * 265 + 266 + * This subscribes the local CPU to interrupts upon changes to the defined 267 + * status bit. The bit is also marked for cascading. 268 + 269 + */ 270 + static void smsm_unmask_irq(struct irq_data *irqd) 271 + { 272 + struct smsm_entry *entry = irq_data_get_irq_chip_data(irqd); 273 + irq_hw_number_t irq = irqd_to_hwirq(irqd); 274 + struct qcom_smsm *smsm = entry->smsm; 275 + u32 val; 276 + 277 + set_bit(irq, entry->irq_enabled); 278 + 279 + if (entry->subscription) { 280 + val = readl(entry->subscription + smsm->local_host); 281 + val |= BIT(irq); 282 + writel(val, entry->subscription + smsm->local_host); 283 + } 284 + } 285 + 286 + /** 287 + * smsm_set_irq_type() - updates the requested IRQ type for the cascading 288 + * @irqd: consumer interrupt handle 289 + * @type: requested flags 290 + */ 291 + static int smsm_set_irq_type(struct irq_data *irqd, unsigned int type) 292 + { 293 + struct smsm_entry *entry = irq_data_get_irq_chip_data(irqd); 294 + irq_hw_number_t irq = irqd_to_hwirq(irqd); 295 + 296 + if (!(type & IRQ_TYPE_EDGE_BOTH)) 297 + return -EINVAL; 298 + 299 + if (type & IRQ_TYPE_EDGE_RISING) 300 + set_bit(irq, entry->irq_rising); 301 + else 302 + clear_bit(irq, entry->irq_rising); 303 + 304 + if (type & IRQ_TYPE_EDGE_FALLING) 305 + set_bit(irq, entry->irq_falling); 306 + else 307 + clear_bit(irq, entry->irq_falling); 308 + 309 + return 0; 310 + } 311 + 312 + static struct irq_chip smsm_irq_chip = { 313 + .name = "smsm", 314 + .irq_mask = smsm_mask_irq, 315 + .irq_unmask = smsm_unmask_irq, 316 + .irq_set_type = smsm_set_irq_type, 317 + }; 318 + 319 + /** 320 + * smsm_irq_map() - sets up a mapping for a cascaded IRQ 321 + * @d: IRQ domain representing an entry 322 + * @irq: IRQ to set up 323 + * @hw: unused 324 + */ 325 + static int smsm_irq_map(struct irq_domain *d, 326 + unsigned int irq, 327 + irq_hw_number_t hw) 328 + { 329 + struct smsm_entry *entry = d->host_data; 330 + 331 + irq_set_chip_and_handler(irq, &smsm_irq_chip, handle_level_irq); 332 + irq_set_chip_data(irq, entry); 333 + irq_set_nested_thread(irq, 1); 334 + 335 + return 0; 336 + } 337 + 338 + static const struct irq_domain_ops smsm_irq_ops = { 339 + .map = smsm_irq_map, 340 + .xlate = irq_domain_xlate_twocell, 341 + }; 342 + 343 + /** 344 + * smsm_parse_ipc() - parses a qcom,ipc-%d device tree property 345 + * @smsm: smsm driver context 346 + * @host_id: index of the remote host to be resolved 347 + * 348 + * Parses device tree to acquire the information needed for sending the 349 + * outgoing interrupts to a remote host - identified by @host_id. 350 + */ 351 + static int smsm_parse_ipc(struct qcom_smsm *smsm, unsigned host_id) 352 + { 353 + struct device_node *syscon; 354 + struct device_node *node = smsm->dev->of_node; 355 + struct smsm_host *host = &smsm->hosts[host_id]; 356 + char key[16]; 357 + int ret; 358 + 359 + snprintf(key, sizeof(key), "qcom,ipc-%d", host_id); 360 + syscon = of_parse_phandle(node, key, 0); 361 + if (!syscon) 362 + return 0; 363 + 364 + host->ipc_regmap = syscon_node_to_regmap(syscon); 365 + if (IS_ERR(host->ipc_regmap)) 366 + return PTR_ERR(host->ipc_regmap); 367 + 368 + ret = of_property_read_u32_index(node, key, 1, &host->ipc_offset); 369 + if (ret < 0) { 370 + dev_err(smsm->dev, "no offset in %s\n", key); 371 + return -EINVAL; 372 + } 373 + 374 + ret = of_property_read_u32_index(node, key, 2, &host->ipc_bit); 375 + if (ret < 0) { 376 + dev_err(smsm->dev, "no bit in %s\n", key); 377 + return -EINVAL; 378 + } 379 + 380 + return 0; 381 + } 382 + 383 + /** 384 + * smsm_inbound_entry() - parse DT and set up an entry representing a remote system 385 + * @smsm: smsm driver context 386 + * @entry: entry context to be set up 387 + * @node: dt node containing the entry's properties 388 + */ 389 + static int smsm_inbound_entry(struct qcom_smsm *smsm, 390 + struct smsm_entry *entry, 391 + struct device_node *node) 392 + { 393 + int ret; 394 + int irq; 395 + 396 + irq = irq_of_parse_and_map(node, 0); 397 + if (!irq) { 398 + dev_err(smsm->dev, "failed to parse smsm interrupt\n"); 399 + return -EINVAL; 400 + } 401 + 402 + ret = devm_request_threaded_irq(smsm->dev, irq, 403 + NULL, smsm_intr, 404 + IRQF_ONESHOT, 405 + "smsm", (void *)entry); 406 + if (ret) { 407 + dev_err(smsm->dev, "failed to request interrupt\n"); 408 + return ret; 409 + } 410 + 411 + entry->domain = irq_domain_add_linear(node, 32, &smsm_irq_ops, entry); 412 + if (!entry->domain) { 413 + dev_err(smsm->dev, "failed to add irq_domain\n"); 414 + return -ENOMEM; 415 + } 416 + 417 + return 0; 418 + } 419 + 420 + /** 421 + * smsm_get_size_info() - parse the optional memory segment for sizes 422 + * @smsm: smsm driver context 423 + * 424 + * Attempt to acquire the number of hosts and entries from the optional shared 425 + * memory location. Not being able to find this segment should indicate that 426 + * we're on a older system where these values was hard coded to 427 + * SMSM_DEFAULT_NUM_ENTRIES and SMSM_DEFAULT_NUM_HOSTS. 428 + * 429 + * Returns 0 on success, negative errno on failure. 430 + */ 431 + static int smsm_get_size_info(struct qcom_smsm *smsm) 432 + { 433 + size_t size; 434 + struct { 435 + u32 num_hosts; 436 + u32 num_entries; 437 + u32 reserved0; 438 + u32 reserved1; 439 + } *info; 440 + 441 + info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_SMSM_SIZE_INFO, &size); 442 + if (PTR_ERR(info) == -ENOENT || size != sizeof(*info)) { 443 + dev_warn(smsm->dev, "no smsm size info, using defaults\n"); 444 + smsm->num_entries = SMSM_DEFAULT_NUM_ENTRIES; 445 + smsm->num_hosts = SMSM_DEFAULT_NUM_HOSTS; 446 + return 0; 447 + } else if (IS_ERR(info)) { 448 + dev_err(smsm->dev, "unable to retrieve smsm size info\n"); 449 + return PTR_ERR(info); 450 + } 451 + 452 + smsm->num_entries = info->num_entries; 453 + smsm->num_hosts = info->num_hosts; 454 + 455 + dev_dbg(smsm->dev, 456 + "found custom size of smsm: %d entries %d hosts\n", 457 + smsm->num_entries, smsm->num_hosts); 458 + 459 + return 0; 460 + } 461 + 462 + static int qcom_smsm_probe(struct platform_device *pdev) 463 + { 464 + struct device_node *local_node; 465 + struct device_node *node; 466 + struct smsm_entry *entry; 467 + struct qcom_smsm *smsm; 468 + u32 *intr_mask; 469 + size_t size; 470 + u32 *states; 471 + u32 id; 472 + int ret; 473 + 474 + smsm = devm_kzalloc(&pdev->dev, sizeof(*smsm), GFP_KERNEL); 475 + if (!smsm) 476 + return -ENOMEM; 477 + smsm->dev = &pdev->dev; 478 + spin_lock_init(&smsm->lock); 479 + 480 + ret = smsm_get_size_info(smsm); 481 + if (ret) 482 + return ret; 483 + 484 + smsm->entries = devm_kcalloc(&pdev->dev, 485 + smsm->num_entries, 486 + sizeof(struct smsm_entry), 487 + GFP_KERNEL); 488 + if (!smsm->entries) 489 + return -ENOMEM; 490 + 491 + smsm->hosts = devm_kcalloc(&pdev->dev, 492 + smsm->num_hosts, 493 + sizeof(struct smsm_host), 494 + GFP_KERNEL); 495 + if (!smsm->hosts) 496 + return -ENOMEM; 497 + 498 + local_node = of_find_node_with_property(pdev->dev.of_node, "#qcom,state-cells"); 499 + if (!local_node) { 500 + dev_err(&pdev->dev, "no state entry\n"); 501 + return -EINVAL; 502 + } 503 + 504 + of_property_read_u32(pdev->dev.of_node, 505 + "qcom,local-host", 506 + &smsm->local_host); 507 + 508 + /* Parse the host properties */ 509 + for (id = 0; id < smsm->num_hosts; id++) { 510 + ret = smsm_parse_ipc(smsm, id); 511 + if (ret < 0) 512 + return ret; 513 + } 514 + 515 + /* Acquire the main SMSM state vector */ 516 + ret = qcom_smem_alloc(QCOM_SMEM_HOST_ANY, SMEM_SMSM_SHARED_STATE, 517 + smsm->num_entries * sizeof(u32)); 518 + if (ret < 0 && ret != -EEXIST) { 519 + dev_err(&pdev->dev, "unable to allocate shared state entry\n"); 520 + return ret; 521 + } 522 + 523 + states = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_SMSM_SHARED_STATE, NULL); 524 + if (IS_ERR(states)) { 525 + dev_err(&pdev->dev, "Unable to acquire shared state entry\n"); 526 + return PTR_ERR(states); 527 + } 528 + 529 + /* Acquire the list of interrupt mask vectors */ 530 + size = smsm->num_entries * smsm->num_hosts * sizeof(u32); 531 + ret = qcom_smem_alloc(QCOM_SMEM_HOST_ANY, SMEM_SMSM_CPU_INTR_MASK, size); 532 + if (ret < 0 && ret != -EEXIST) { 533 + dev_err(&pdev->dev, "unable to allocate smsm interrupt mask\n"); 534 + return ret; 535 + } 536 + 537 + intr_mask = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_SMSM_CPU_INTR_MASK, NULL); 538 + if (IS_ERR(intr_mask)) { 539 + dev_err(&pdev->dev, "unable to acquire shared memory interrupt mask\n"); 540 + return PTR_ERR(intr_mask); 541 + } 542 + 543 + /* Setup the reference to the local state bits */ 544 + smsm->local_state = states + smsm->local_host; 545 + smsm->subscription = intr_mask + smsm->local_host * smsm->num_hosts; 546 + 547 + /* Register the outgoing state */ 548 + smsm->state = qcom_smem_state_register(local_node, &smsm_state_ops, smsm); 549 + if (IS_ERR(smsm->state)) { 550 + dev_err(smsm->dev, "failed to register qcom_smem_state\n"); 551 + return PTR_ERR(smsm->state); 552 + } 553 + 554 + /* Register handlers for remote processor entries of interest. */ 555 + for_each_available_child_of_node(pdev->dev.of_node, node) { 556 + if (!of_property_read_bool(node, "interrupt-controller")) 557 + continue; 558 + 559 + ret = of_property_read_u32(node, "reg", &id); 560 + if (ret || id >= smsm->num_entries) { 561 + dev_err(&pdev->dev, "invalid reg of entry\n"); 562 + if (!ret) 563 + ret = -EINVAL; 564 + goto unwind_interfaces; 565 + } 566 + entry = &smsm->entries[id]; 567 + 568 + entry->smsm = smsm; 569 + entry->remote_state = states + id; 570 + 571 + /* Setup subscription pointers and unsubscribe to any kicks */ 572 + entry->subscription = intr_mask + id * smsm->num_hosts; 573 + writel(0, entry->subscription + smsm->local_host); 574 + 575 + ret = smsm_inbound_entry(smsm, entry, node); 576 + if (ret < 0) 577 + goto unwind_interfaces; 578 + } 579 + 580 + platform_set_drvdata(pdev, smsm); 581 + 582 + return 0; 583 + 584 + unwind_interfaces: 585 + for (id = 0; id < smsm->num_entries; id++) 586 + if (smsm->entries[id].domain) 587 + irq_domain_remove(smsm->entries[id].domain); 588 + 589 + qcom_smem_state_unregister(smsm->state); 590 + 591 + return ret; 592 + } 593 + 594 + static int qcom_smsm_remove(struct platform_device *pdev) 595 + { 596 + struct qcom_smsm *smsm = platform_get_drvdata(pdev); 597 + unsigned id; 598 + 599 + for (id = 0; id < smsm->num_entries; id++) 600 + if (smsm->entries[id].domain) 601 + irq_domain_remove(smsm->entries[id].domain); 602 + 603 + qcom_smem_state_unregister(smsm->state); 604 + 605 + return 0; 606 + } 607 + 608 + static const struct of_device_id qcom_smsm_of_match[] = { 609 + { .compatible = "qcom,smsm" }, 610 + {} 611 + }; 612 + MODULE_DEVICE_TABLE(of, qcom_smsm_of_match); 613 + 614 + static struct platform_driver qcom_smsm_driver = { 615 + .probe = qcom_smsm_probe, 616 + .remove = qcom_smsm_remove, 617 + .driver = { 618 + .name = "qcom-smsm", 619 + .of_match_table = qcom_smsm_of_match, 620 + }, 621 + }; 622 + module_platform_driver(qcom_smsm_driver); 623 + 624 + MODULE_DESCRIPTION("Qualcomm Shared Memory State Machine driver"); 625 + MODULE_LICENSE("GPL v2");
+272
drivers/soc/qcom/wcnss_ctrl.c
··· 1 + /* 2 + * Copyright (c) 2015, Sony Mobile Communications Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 and 6 + * only version 2 as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + #include <linux/firmware.h> 14 + #include <linux/module.h> 15 + #include <linux/slab.h> 16 + #include <linux/soc/qcom/smd.h> 17 + 18 + #define WCNSS_REQUEST_TIMEOUT (5 * HZ) 19 + 20 + #define NV_FRAGMENT_SIZE 3072 21 + #define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin" 22 + 23 + /** 24 + * struct wcnss_ctrl - driver context 25 + * @dev: device handle 26 + * @channel: SMD channel handle 27 + * @ack: completion for outstanding requests 28 + * @ack_status: status of the outstanding request 29 + * @download_nv_work: worker for uploading nv binary 30 + */ 31 + struct wcnss_ctrl { 32 + struct device *dev; 33 + struct qcom_smd_channel *channel; 34 + 35 + struct completion ack; 36 + int ack_status; 37 + 38 + struct work_struct download_nv_work; 39 + }; 40 + 41 + /* message types */ 42 + enum { 43 + WCNSS_VERSION_REQ = 0x01000000, 44 + WCNSS_VERSION_RESP, 45 + WCNSS_DOWNLOAD_NV_REQ, 46 + WCNSS_DOWNLOAD_NV_RESP, 47 + WCNSS_UPLOAD_CAL_REQ, 48 + WCNSS_UPLOAD_CAL_RESP, 49 + WCNSS_DOWNLOAD_CAL_REQ, 50 + WCNSS_DOWNLOAD_CAL_RESP, 51 + }; 52 + 53 + /** 54 + * struct wcnss_msg_hdr - common packet header for requests and responses 55 + * @type: packet message type 56 + * @len: total length of the packet, including this header 57 + */ 58 + struct wcnss_msg_hdr { 59 + u32 type; 60 + u32 len; 61 + } __packed; 62 + 63 + /** 64 + * struct wcnss_version_resp - version request response 65 + * @hdr: common packet wcnss_msg_hdr header 66 + */ 67 + struct wcnss_version_resp { 68 + struct wcnss_msg_hdr hdr; 69 + u8 major; 70 + u8 minor; 71 + u8 version; 72 + u8 revision; 73 + } __packed; 74 + 75 + /** 76 + * struct wcnss_download_nv_req - firmware fragment request 77 + * @hdr: common packet wcnss_msg_hdr header 78 + * @seq: sequence number of this fragment 79 + * @last: boolean indicator of this being the last fragment of the binary 80 + * @frag_size: length of this fragment 81 + * @fragment: fragment data 82 + */ 83 + struct wcnss_download_nv_req { 84 + struct wcnss_msg_hdr hdr; 85 + u16 seq; 86 + u16 last; 87 + u32 frag_size; 88 + u8 fragment[]; 89 + } __packed; 90 + 91 + /** 92 + * struct wcnss_download_nv_resp - firmware download response 93 + * @hdr: common packet wcnss_msg_hdr header 94 + * @status: boolean to indicate success of the download 95 + */ 96 + struct wcnss_download_nv_resp { 97 + struct wcnss_msg_hdr hdr; 98 + u8 status; 99 + } __packed; 100 + 101 + /** 102 + * wcnss_ctrl_smd_callback() - handler from SMD responses 103 + * @qsdev: smd device handle 104 + * @data: pointer to the incoming data packet 105 + * @count: size of the incoming data packet 106 + * 107 + * Handles any incoming packets from the remote WCNSS_CTRL service. 108 + */ 109 + static int wcnss_ctrl_smd_callback(struct qcom_smd_device *qsdev, 110 + const void *data, 111 + size_t count) 112 + { 113 + struct wcnss_ctrl *wcnss = dev_get_drvdata(&qsdev->dev); 114 + const struct wcnss_download_nv_resp *nvresp; 115 + const struct wcnss_version_resp *version; 116 + const struct wcnss_msg_hdr *hdr = data; 117 + 118 + switch (hdr->type) { 119 + case WCNSS_VERSION_RESP: 120 + if (count != sizeof(*version)) { 121 + dev_err(wcnss->dev, 122 + "invalid size of version response\n"); 123 + break; 124 + } 125 + 126 + version = data; 127 + dev_info(wcnss->dev, "WCNSS Version %d.%d %d.%d\n", 128 + version->major, version->minor, 129 + version->version, version->revision); 130 + 131 + schedule_work(&wcnss->download_nv_work); 132 + break; 133 + case WCNSS_DOWNLOAD_NV_RESP: 134 + if (count != sizeof(*nvresp)) { 135 + dev_err(wcnss->dev, 136 + "invalid size of download response\n"); 137 + break; 138 + } 139 + 140 + nvresp = data; 141 + wcnss->ack_status = nvresp->status; 142 + complete(&wcnss->ack); 143 + break; 144 + default: 145 + dev_info(wcnss->dev, "unknown message type %d\n", hdr->type); 146 + break; 147 + } 148 + 149 + return 0; 150 + } 151 + 152 + /** 153 + * wcnss_request_version() - send a version request to WCNSS 154 + * @wcnss: wcnss ctrl driver context 155 + */ 156 + static int wcnss_request_version(struct wcnss_ctrl *wcnss) 157 + { 158 + struct wcnss_msg_hdr msg; 159 + 160 + msg.type = WCNSS_VERSION_REQ; 161 + msg.len = sizeof(msg); 162 + 163 + return qcom_smd_send(wcnss->channel, &msg, sizeof(msg)); 164 + } 165 + 166 + /** 167 + * wcnss_download_nv() - send nv binary to WCNSS 168 + * @work: work struct to acquire wcnss context 169 + */ 170 + static void wcnss_download_nv(struct work_struct *work) 171 + { 172 + struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, download_nv_work); 173 + struct wcnss_download_nv_req *req; 174 + const struct firmware *fw; 175 + const void *data; 176 + ssize_t left; 177 + int ret; 178 + 179 + req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL); 180 + if (!req) 181 + return; 182 + 183 + ret = request_firmware(&fw, NVBIN_FILE, wcnss->dev); 184 + if (ret) { 185 + dev_err(wcnss->dev, "Failed to load nv file %s: %d\n", 186 + NVBIN_FILE, ret); 187 + goto free_req; 188 + } 189 + 190 + data = fw->data; 191 + left = fw->size; 192 + 193 + req->hdr.type = WCNSS_DOWNLOAD_NV_REQ; 194 + req->hdr.len = sizeof(*req) + NV_FRAGMENT_SIZE; 195 + 196 + req->last = 0; 197 + req->frag_size = NV_FRAGMENT_SIZE; 198 + 199 + req->seq = 0; 200 + do { 201 + if (left <= NV_FRAGMENT_SIZE) { 202 + req->last = 1; 203 + req->frag_size = left; 204 + req->hdr.len = sizeof(*req) + left; 205 + } 206 + 207 + memcpy(req->fragment, data, req->frag_size); 208 + 209 + ret = qcom_smd_send(wcnss->channel, req, req->hdr.len); 210 + if (ret) { 211 + dev_err(wcnss->dev, "failed to send smd packet\n"); 212 + goto release_fw; 213 + } 214 + 215 + /* Increment for next fragment */ 216 + req->seq++; 217 + 218 + data += req->hdr.len; 219 + left -= NV_FRAGMENT_SIZE; 220 + } while (left > 0); 221 + 222 + ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_REQUEST_TIMEOUT); 223 + if (!ret) 224 + dev_err(wcnss->dev, "timeout waiting for nv upload ack\n"); 225 + else if (wcnss->ack_status != 1) 226 + dev_err(wcnss->dev, "nv upload response failed err: %d\n", 227 + wcnss->ack_status); 228 + 229 + release_fw: 230 + release_firmware(fw); 231 + free_req: 232 + kfree(req); 233 + } 234 + 235 + static int wcnss_ctrl_probe(struct qcom_smd_device *sdev) 236 + { 237 + struct wcnss_ctrl *wcnss; 238 + 239 + wcnss = devm_kzalloc(&sdev->dev, sizeof(*wcnss), GFP_KERNEL); 240 + if (!wcnss) 241 + return -ENOMEM; 242 + 243 + wcnss->dev = &sdev->dev; 244 + wcnss->channel = sdev->channel; 245 + 246 + init_completion(&wcnss->ack); 247 + INIT_WORK(&wcnss->download_nv_work, wcnss_download_nv); 248 + 249 + dev_set_drvdata(&sdev->dev, wcnss); 250 + 251 + return wcnss_request_version(wcnss); 252 + } 253 + 254 + static const struct qcom_smd_id wcnss_ctrl_smd_match[] = { 255 + { .name = "WCNSS_CTRL" }, 256 + {} 257 + }; 258 + 259 + static struct qcom_smd_driver wcnss_ctrl_driver = { 260 + .probe = wcnss_ctrl_probe, 261 + .callback = wcnss_ctrl_smd_callback, 262 + .smd_match_table = wcnss_ctrl_smd_match, 263 + .driver = { 264 + .name = "qcom_wcnss_ctrl", 265 + .owner = THIS_MODULE, 266 + }, 267 + }; 268 + 269 + module_qcom_smd_driver(wcnss_ctrl_driver); 270 + 271 + MODULE_DESCRIPTION("Qualcomm WCNSS control driver"); 272 + MODULE_LICENSE("GPL v2");
+10
drivers/soc/ti/Kconfig
··· 28 28 29 29 If unsure, say N. 30 30 31 + config WKUP_M3_IPC 32 + tristate "TI AMx3 Wkup-M3 IPC Driver" 33 + depends on WKUP_M3_RPROC 34 + depends on OMAP2PLUS_MBOX 35 + help 36 + TI AM33XX and AM43XX have a Cortex M3, the Wakeup M3, to handle 37 + low power transitions. This IPC driver provides the necessary API 38 + to communicate and use the Wakeup M3 for PM features like suspend 39 + resume and boots it using wkup_m3_rproc driver. 40 + 31 41 endif # SOC_TI
+1
drivers/soc/ti/Makefile
··· 4 4 obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS) += knav_qmss.o 5 5 knav_qmss-y := knav_qmss_queue.o knav_qmss_acc.o 6 6 obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA) += knav_dma.o 7 + obj-$(CONFIG_WKUP_M3_IPC) += wkup_m3_ipc.o
+508
drivers/soc/ti/wkup_m3_ipc.c
··· 1 + /* 2 + * AMx3 Wkup M3 IPC driver 3 + * 4 + * Copyright (C) 2015 Texas Instruments, Inc. 5 + * 6 + * Dave Gerlach <d-gerlach@ti.com> 7 + * 8 + * This program is free software; you can redistribute it and/or 9 + * modify it under the terms of the GNU General Public License 10 + * version 2 as published by the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #include <linux/err.h> 19 + #include <linux/kernel.h> 20 + #include <linux/kthread.h> 21 + #include <linux/interrupt.h> 22 + #include <linux/irq.h> 23 + #include <linux/module.h> 24 + #include <linux/of.h> 25 + #include <linux/omap-mailbox.h> 26 + #include <linux/platform_device.h> 27 + #include <linux/remoteproc.h> 28 + #include <linux/suspend.h> 29 + #include <linux/wkup_m3_ipc.h> 30 + 31 + #define AM33XX_CTRL_IPC_REG_COUNT 0x8 32 + #define AM33XX_CTRL_IPC_REG_OFFSET(m) (0x4 + 4 * (m)) 33 + 34 + /* AM33XX M3_TXEV_EOI register */ 35 + #define AM33XX_CONTROL_M3_TXEV_EOI 0x00 36 + 37 + #define AM33XX_M3_TXEV_ACK (0x1 << 0) 38 + #define AM33XX_M3_TXEV_ENABLE (0x0 << 0) 39 + 40 + #define IPC_CMD_DS0 0x4 41 + #define IPC_CMD_STANDBY 0xc 42 + #define IPC_CMD_IDLE 0x10 43 + #define IPC_CMD_RESET 0xe 44 + #define DS_IPC_DEFAULT 0xffffffff 45 + #define M3_VERSION_UNKNOWN 0x0000ffff 46 + #define M3_BASELINE_VERSION 0x191 47 + #define M3_STATUS_RESP_MASK (0xffff << 16) 48 + #define M3_FW_VERSION_MASK 0xffff 49 + 50 + #define M3_STATE_UNKNOWN 0 51 + #define M3_STATE_RESET 1 52 + #define M3_STATE_INITED 2 53 + #define M3_STATE_MSG_FOR_LP 3 54 + #define M3_STATE_MSG_FOR_RESET 4 55 + 56 + static struct wkup_m3_ipc *m3_ipc_state; 57 + 58 + static void am33xx_txev_eoi(struct wkup_m3_ipc *m3_ipc) 59 + { 60 + writel(AM33XX_M3_TXEV_ACK, 61 + m3_ipc->ipc_mem_base + AM33XX_CONTROL_M3_TXEV_EOI); 62 + } 63 + 64 + static void am33xx_txev_enable(struct wkup_m3_ipc *m3_ipc) 65 + { 66 + writel(AM33XX_M3_TXEV_ENABLE, 67 + m3_ipc->ipc_mem_base + AM33XX_CONTROL_M3_TXEV_EOI); 68 + } 69 + 70 + static void wkup_m3_ctrl_ipc_write(struct wkup_m3_ipc *m3_ipc, 71 + u32 val, int ipc_reg_num) 72 + { 73 + if (WARN(ipc_reg_num < 0 || ipc_reg_num > AM33XX_CTRL_IPC_REG_COUNT, 74 + "ipc register operation out of range")) 75 + return; 76 + 77 + writel(val, m3_ipc->ipc_mem_base + 78 + AM33XX_CTRL_IPC_REG_OFFSET(ipc_reg_num)); 79 + } 80 + 81 + static unsigned int wkup_m3_ctrl_ipc_read(struct wkup_m3_ipc *m3_ipc, 82 + int ipc_reg_num) 83 + { 84 + if (WARN(ipc_reg_num < 0 || ipc_reg_num > AM33XX_CTRL_IPC_REG_COUNT, 85 + "ipc register operation out of range")) 86 + return 0; 87 + 88 + return readl(m3_ipc->ipc_mem_base + 89 + AM33XX_CTRL_IPC_REG_OFFSET(ipc_reg_num)); 90 + } 91 + 92 + static int wkup_m3_fw_version_read(struct wkup_m3_ipc *m3_ipc) 93 + { 94 + int val; 95 + 96 + val = wkup_m3_ctrl_ipc_read(m3_ipc, 2); 97 + 98 + return val & M3_FW_VERSION_MASK; 99 + } 100 + 101 + static irqreturn_t wkup_m3_txev_handler(int irq, void *ipc_data) 102 + { 103 + struct wkup_m3_ipc *m3_ipc = ipc_data; 104 + struct device *dev = m3_ipc->dev; 105 + int ver = 0; 106 + 107 + am33xx_txev_eoi(m3_ipc); 108 + 109 + switch (m3_ipc->state) { 110 + case M3_STATE_RESET: 111 + ver = wkup_m3_fw_version_read(m3_ipc); 112 + 113 + if (ver == M3_VERSION_UNKNOWN || 114 + ver < M3_BASELINE_VERSION) { 115 + dev_warn(dev, "CM3 Firmware Version %x not supported\n", 116 + ver); 117 + } else { 118 + dev_info(dev, "CM3 Firmware Version = 0x%x\n", ver); 119 + } 120 + 121 + m3_ipc->state = M3_STATE_INITED; 122 + complete(&m3_ipc->sync_complete); 123 + break; 124 + case M3_STATE_MSG_FOR_RESET: 125 + m3_ipc->state = M3_STATE_INITED; 126 + complete(&m3_ipc->sync_complete); 127 + break; 128 + case M3_STATE_MSG_FOR_LP: 129 + complete(&m3_ipc->sync_complete); 130 + break; 131 + case M3_STATE_UNKNOWN: 132 + dev_warn(dev, "Unknown CM3 State\n"); 133 + } 134 + 135 + am33xx_txev_enable(m3_ipc); 136 + 137 + return IRQ_HANDLED; 138 + } 139 + 140 + static int wkup_m3_ping(struct wkup_m3_ipc *m3_ipc) 141 + { 142 + struct device *dev = m3_ipc->dev; 143 + mbox_msg_t dummy_msg = 0; 144 + int ret; 145 + 146 + if (!m3_ipc->mbox) { 147 + dev_err(dev, 148 + "No IPC channel to communicate with wkup_m3!\n"); 149 + return -EIO; 150 + } 151 + 152 + /* 153 + * Write a dummy message to the mailbox in order to trigger the RX 154 + * interrupt to alert the M3 that data is available in the IPC 155 + * registers. We must enable the IRQ here and disable it after in 156 + * the RX callback to avoid multiple interrupts being received 157 + * by the CM3. 158 + */ 159 + ret = mbox_send_message(m3_ipc->mbox, &dummy_msg); 160 + if (ret < 0) { 161 + dev_err(dev, "%s: mbox_send_message() failed: %d\n", 162 + __func__, ret); 163 + return ret; 164 + } 165 + 166 + ret = wait_for_completion_timeout(&m3_ipc->sync_complete, 167 + msecs_to_jiffies(500)); 168 + if (!ret) { 169 + dev_err(dev, "MPU<->CM3 sync failure\n"); 170 + m3_ipc->state = M3_STATE_UNKNOWN; 171 + return -EIO; 172 + } 173 + 174 + mbox_client_txdone(m3_ipc->mbox, 0); 175 + return 0; 176 + } 177 + 178 + static int wkup_m3_ping_noirq(struct wkup_m3_ipc *m3_ipc) 179 + { 180 + struct device *dev = m3_ipc->dev; 181 + mbox_msg_t dummy_msg = 0; 182 + int ret; 183 + 184 + if (!m3_ipc->mbox) { 185 + dev_err(dev, 186 + "No IPC channel to communicate with wkup_m3!\n"); 187 + return -EIO; 188 + } 189 + 190 + ret = mbox_send_message(m3_ipc->mbox, &dummy_msg); 191 + if (ret < 0) { 192 + dev_err(dev, "%s: mbox_send_message() failed: %d\n", 193 + __func__, ret); 194 + return ret; 195 + } 196 + 197 + mbox_client_txdone(m3_ipc->mbox, 0); 198 + return 0; 199 + } 200 + 201 + static int wkup_m3_is_available(struct wkup_m3_ipc *m3_ipc) 202 + { 203 + return ((m3_ipc->state != M3_STATE_RESET) && 204 + (m3_ipc->state != M3_STATE_UNKNOWN)); 205 + } 206 + 207 + /* Public functions */ 208 + /** 209 + * wkup_m3_set_mem_type - Pass wkup_m3 which type of memory is in use 210 + * @mem_type: memory type value read directly from emif 211 + * 212 + * wkup_m3 must know what memory type is in use to properly suspend 213 + * and resume. 214 + */ 215 + static void wkup_m3_set_mem_type(struct wkup_m3_ipc *m3_ipc, int mem_type) 216 + { 217 + m3_ipc->mem_type = mem_type; 218 + } 219 + 220 + /** 221 + * wkup_m3_set_resume_address - Pass wkup_m3 resume address 222 + * @addr: Physical address from which resume code should execute 223 + */ 224 + static void wkup_m3_set_resume_address(struct wkup_m3_ipc *m3_ipc, void *addr) 225 + { 226 + m3_ipc->resume_addr = (unsigned long)addr; 227 + } 228 + 229 + /** 230 + * wkup_m3_request_pm_status - Retrieve wkup_m3 status code after suspend 231 + * 232 + * Returns code representing the status of a low power mode transition. 233 + * 0 - Successful transition 234 + * 1 - Failure to transition to low power state 235 + */ 236 + static int wkup_m3_request_pm_status(struct wkup_m3_ipc *m3_ipc) 237 + { 238 + unsigned int i; 239 + int val; 240 + 241 + val = wkup_m3_ctrl_ipc_read(m3_ipc, 1); 242 + 243 + i = M3_STATUS_RESP_MASK & val; 244 + i >>= __ffs(M3_STATUS_RESP_MASK); 245 + 246 + return i; 247 + } 248 + 249 + /** 250 + * wkup_m3_prepare_low_power - Request preparation for transition to 251 + * low power state 252 + * @state: A kernel suspend state to enter, either MEM or STANDBY 253 + * 254 + * Returns 0 if preparation was successful, otherwise returns error code 255 + */ 256 + static int wkup_m3_prepare_low_power(struct wkup_m3_ipc *m3_ipc, int state) 257 + { 258 + struct device *dev = m3_ipc->dev; 259 + int m3_power_state; 260 + int ret = 0; 261 + 262 + if (!wkup_m3_is_available(m3_ipc)) 263 + return -ENODEV; 264 + 265 + switch (state) { 266 + case WKUP_M3_DEEPSLEEP: 267 + m3_power_state = IPC_CMD_DS0; 268 + break; 269 + case WKUP_M3_STANDBY: 270 + m3_power_state = IPC_CMD_STANDBY; 271 + break; 272 + case WKUP_M3_IDLE: 273 + m3_power_state = IPC_CMD_IDLE; 274 + break; 275 + default: 276 + return 1; 277 + } 278 + 279 + /* Program each required IPC register then write defaults to others */ 280 + wkup_m3_ctrl_ipc_write(m3_ipc, m3_ipc->resume_addr, 0); 281 + wkup_m3_ctrl_ipc_write(m3_ipc, m3_power_state, 1); 282 + wkup_m3_ctrl_ipc_write(m3_ipc, m3_ipc->mem_type, 4); 283 + 284 + wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 2); 285 + wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 3); 286 + wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 5); 287 + wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 6); 288 + wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 7); 289 + 290 + m3_ipc->state = M3_STATE_MSG_FOR_LP; 291 + 292 + if (state == WKUP_M3_IDLE) 293 + ret = wkup_m3_ping_noirq(m3_ipc); 294 + else 295 + ret = wkup_m3_ping(m3_ipc); 296 + 297 + if (ret) { 298 + dev_err(dev, "Unable to ping CM3\n"); 299 + return ret; 300 + } 301 + 302 + return 0; 303 + } 304 + 305 + /** 306 + * wkup_m3_finish_low_power - Return m3 to reset state 307 + * 308 + * Returns 0 if reset was successful, otherwise returns error code 309 + */ 310 + static int wkup_m3_finish_low_power(struct wkup_m3_ipc *m3_ipc) 311 + { 312 + struct device *dev = m3_ipc->dev; 313 + int ret = 0; 314 + 315 + if (!wkup_m3_is_available(m3_ipc)) 316 + return -ENODEV; 317 + 318 + wkup_m3_ctrl_ipc_write(m3_ipc, IPC_CMD_RESET, 1); 319 + wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 2); 320 + 321 + m3_ipc->state = M3_STATE_MSG_FOR_RESET; 322 + 323 + ret = wkup_m3_ping(m3_ipc); 324 + if (ret) { 325 + dev_err(dev, "Unable to ping CM3\n"); 326 + return ret; 327 + } 328 + 329 + return 0; 330 + } 331 + 332 + static struct wkup_m3_ipc_ops ipc_ops = { 333 + .set_mem_type = wkup_m3_set_mem_type, 334 + .set_resume_address = wkup_m3_set_resume_address, 335 + .prepare_low_power = wkup_m3_prepare_low_power, 336 + .finish_low_power = wkup_m3_finish_low_power, 337 + .request_pm_status = wkup_m3_request_pm_status, 338 + }; 339 + 340 + /** 341 + * wkup_m3_ipc_get - Return handle to wkup_m3_ipc 342 + * 343 + * Returns NULL if the wkup_m3 is not yet available, otherwise returns 344 + * pointer to wkup_m3_ipc struct. 345 + */ 346 + struct wkup_m3_ipc *wkup_m3_ipc_get(void) 347 + { 348 + if (m3_ipc_state) 349 + get_device(m3_ipc_state->dev); 350 + else 351 + return NULL; 352 + 353 + return m3_ipc_state; 354 + } 355 + EXPORT_SYMBOL_GPL(wkup_m3_ipc_get); 356 + 357 + /** 358 + * wkup_m3_ipc_put - Free handle to wkup_m3_ipc returned from wkup_m3_ipc_get 359 + * @m3_ipc: A pointer to wkup_m3_ipc struct returned by wkup_m3_ipc_get 360 + */ 361 + void wkup_m3_ipc_put(struct wkup_m3_ipc *m3_ipc) 362 + { 363 + if (m3_ipc_state) 364 + put_device(m3_ipc_state->dev); 365 + } 366 + EXPORT_SYMBOL_GPL(wkup_m3_ipc_put); 367 + 368 + static void wkup_m3_rproc_boot_thread(struct wkup_m3_ipc *m3_ipc) 369 + { 370 + struct device *dev = m3_ipc->dev; 371 + int ret; 372 + 373 + wait_for_completion(&m3_ipc->rproc->firmware_loading_complete); 374 + 375 + init_completion(&m3_ipc->sync_complete); 376 + 377 + ret = rproc_boot(m3_ipc->rproc); 378 + if (ret) 379 + dev_err(dev, "rproc_boot failed\n"); 380 + 381 + do_exit(0); 382 + } 383 + 384 + static int wkup_m3_ipc_probe(struct platform_device *pdev) 385 + { 386 + struct device *dev = &pdev->dev; 387 + int irq, ret; 388 + phandle rproc_phandle; 389 + struct rproc *m3_rproc; 390 + struct resource *res; 391 + struct task_struct *task; 392 + struct wkup_m3_ipc *m3_ipc; 393 + 394 + m3_ipc = devm_kzalloc(dev, sizeof(*m3_ipc), GFP_KERNEL); 395 + if (!m3_ipc) 396 + return -ENOMEM; 397 + 398 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 399 + m3_ipc->ipc_mem_base = devm_ioremap_resource(dev, res); 400 + if (IS_ERR(m3_ipc->ipc_mem_base)) { 401 + dev_err(dev, "could not ioremap ipc_mem\n"); 402 + return PTR_ERR(m3_ipc->ipc_mem_base); 403 + } 404 + 405 + irq = platform_get_irq(pdev, 0); 406 + if (!irq) { 407 + dev_err(&pdev->dev, "no irq resource\n"); 408 + return -ENXIO; 409 + } 410 + 411 + ret = devm_request_irq(dev, irq, wkup_m3_txev_handler, 412 + 0, "wkup_m3_txev", m3_ipc); 413 + if (ret) { 414 + dev_err(dev, "request_irq failed\n"); 415 + return ret; 416 + } 417 + 418 + m3_ipc->mbox_client.dev = dev; 419 + m3_ipc->mbox_client.tx_done = NULL; 420 + m3_ipc->mbox_client.tx_prepare = NULL; 421 + m3_ipc->mbox_client.rx_callback = NULL; 422 + m3_ipc->mbox_client.tx_block = false; 423 + m3_ipc->mbox_client.knows_txdone = false; 424 + 425 + m3_ipc->mbox = mbox_request_channel(&m3_ipc->mbox_client, 0); 426 + 427 + if (IS_ERR(m3_ipc->mbox)) { 428 + dev_err(dev, "IPC Request for A8->M3 Channel failed! %ld\n", 429 + PTR_ERR(m3_ipc->mbox)); 430 + return PTR_ERR(m3_ipc->mbox); 431 + } 432 + 433 + if (of_property_read_u32(dev->of_node, "ti,rproc", &rproc_phandle)) { 434 + dev_err(&pdev->dev, "could not get rproc phandle\n"); 435 + ret = -ENODEV; 436 + goto err_free_mbox; 437 + } 438 + 439 + m3_rproc = rproc_get_by_phandle(rproc_phandle); 440 + if (!m3_rproc) { 441 + dev_err(&pdev->dev, "could not get rproc handle\n"); 442 + ret = -EPROBE_DEFER; 443 + goto err_free_mbox; 444 + } 445 + 446 + m3_ipc->rproc = m3_rproc; 447 + m3_ipc->dev = dev; 448 + m3_ipc->state = M3_STATE_RESET; 449 + 450 + m3_ipc->ops = &ipc_ops; 451 + 452 + /* 453 + * Wait for firmware loading completion in a thread so we 454 + * can boot the wkup_m3 as soon as it's ready without holding 455 + * up kernel boot 456 + */ 457 + task = kthread_run((void *)wkup_m3_rproc_boot_thread, m3_ipc, 458 + "wkup_m3_rproc_loader"); 459 + 460 + if (IS_ERR(task)) { 461 + dev_err(dev, "can't create rproc_boot thread\n"); 462 + goto err_put_rproc; 463 + } 464 + 465 + m3_ipc_state = m3_ipc; 466 + 467 + return 0; 468 + 469 + err_put_rproc: 470 + rproc_put(m3_rproc); 471 + err_free_mbox: 472 + mbox_free_channel(m3_ipc->mbox); 473 + return ret; 474 + } 475 + 476 + static int wkup_m3_ipc_remove(struct platform_device *pdev) 477 + { 478 + mbox_free_channel(m3_ipc_state->mbox); 479 + 480 + rproc_shutdown(m3_ipc_state->rproc); 481 + rproc_put(m3_ipc_state->rproc); 482 + 483 + m3_ipc_state = NULL; 484 + 485 + return 0; 486 + } 487 + 488 + static const struct of_device_id wkup_m3_ipc_of_match[] = { 489 + { .compatible = "ti,am3352-wkup-m3-ipc", }, 490 + { .compatible = "ti,am4372-wkup-m3-ipc", }, 491 + {}, 492 + }; 493 + MODULE_DEVICE_TABLE(of, wkup_m3_ipc_of_match); 494 + 495 + static struct platform_driver wkup_m3_ipc_driver = { 496 + .probe = wkup_m3_ipc_probe, 497 + .remove = wkup_m3_ipc_remove, 498 + .driver = { 499 + .name = "wkup_m3_ipc", 500 + .of_match_table = wkup_m3_ipc_of_match, 501 + }, 502 + }; 503 + 504 + module_platform_driver(wkup_m3_ipc_driver); 505 + 506 + MODULE_LICENSE("GPL v2"); 507 + MODULE_DESCRIPTION("wkup m3 remote processor ipc driver"); 508 + MODULE_AUTHOR("Dave Gerlach <d-gerlach@ti.com>");
+1 -1
drivers/tty/serial/Kconfig
··· 1047 1047 say Y or M. Otherwise, say N. 1048 1048 1049 1049 config SERIAL_MSM 1050 - bool "MSM on-chip serial port support" 1050 + tristate "MSM on-chip serial port support" 1051 1051 depends on ARCH_QCOM 1052 1052 select SERIAL_CORE 1053 1053
+41
include/dt-bindings/power/raspberrypi-power.h
··· 1 + /* 2 + * Copyright © 2015 Broadcom 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #ifndef _DT_BINDINGS_ARM_BCM2835_RPI_POWER_H 10 + #define _DT_BINDINGS_ARM_BCM2835_RPI_POWER_H 11 + 12 + /* These power domain indices are the firmware interface's indices 13 + * minus one. 14 + */ 15 + #define RPI_POWER_DOMAIN_I2C0 0 16 + #define RPI_POWER_DOMAIN_I2C1 1 17 + #define RPI_POWER_DOMAIN_I2C2 2 18 + #define RPI_POWER_DOMAIN_VIDEO_SCALER 3 19 + #define RPI_POWER_DOMAIN_VPU1 4 20 + #define RPI_POWER_DOMAIN_HDMI 5 21 + #define RPI_POWER_DOMAIN_USB 6 22 + #define RPI_POWER_DOMAIN_VEC 7 23 + #define RPI_POWER_DOMAIN_JPEG 8 24 + #define RPI_POWER_DOMAIN_H264 9 25 + #define RPI_POWER_DOMAIN_V3D 10 26 + #define RPI_POWER_DOMAIN_ISP 11 27 + #define RPI_POWER_DOMAIN_UNICAM0 12 28 + #define RPI_POWER_DOMAIN_UNICAM1 13 29 + #define RPI_POWER_DOMAIN_CCP2RX 14 30 + #define RPI_POWER_DOMAIN_CSI2 15 31 + #define RPI_POWER_DOMAIN_CPI 16 32 + #define RPI_POWER_DOMAIN_DSI0 17 33 + #define RPI_POWER_DOMAIN_DSI1 18 34 + #define RPI_POWER_DOMAIN_TRANSPOSER 19 35 + #define RPI_POWER_DOMAIN_CCP2TX 20 36 + #define RPI_POWER_DOMAIN_CDP 21 37 + #define RPI_POWER_DOMAIN_ARM 22 38 + 39 + #define RPI_POWER_DOMAIN_COUNT 23 40 + 41 + #endif /* _DT_BINDINGS_ARM_BCM2835_RPI_POWER_H */
+67
include/dt-bindings/reset/hisi,hi6220-resets.h
··· 1 + /** 2 + * This header provides index for the reset controller 3 + * based on hi6220 SoC. 4 + */ 5 + #ifndef _DT_BINDINGS_RESET_CONTROLLER_HI6220 6 + #define _DT_BINDINGS_RESET_CONTROLLER_HI6220 7 + 8 + #define PERIPH_RSTDIS0_MMC0 0x000 9 + #define PERIPH_RSTDIS0_MMC1 0x001 10 + #define PERIPH_RSTDIS0_MMC2 0x002 11 + #define PERIPH_RSTDIS0_NANDC 0x003 12 + #define PERIPH_RSTDIS0_USBOTG_BUS 0x004 13 + #define PERIPH_RSTDIS0_POR_PICOPHY 0x005 14 + #define PERIPH_RSTDIS0_USBOTG 0x006 15 + #define PERIPH_RSTDIS0_USBOTG_32K 0x007 16 + #define PERIPH_RSTDIS1_HIFI 0x100 17 + #define PERIPH_RSTDIS1_DIGACODEC 0x105 18 + #define PERIPH_RSTEN2_IPF 0x200 19 + #define PERIPH_RSTEN2_SOCP 0x201 20 + #define PERIPH_RSTEN2_DMAC 0x202 21 + #define PERIPH_RSTEN2_SECENG 0x203 22 + #define PERIPH_RSTEN2_ABB 0x204 23 + #define PERIPH_RSTEN2_HPM0 0x205 24 + #define PERIPH_RSTEN2_HPM1 0x206 25 + #define PERIPH_RSTEN2_HPM2 0x207 26 + #define PERIPH_RSTEN2_HPM3 0x208 27 + #define PERIPH_RSTEN3_CSSYS 0x300 28 + #define PERIPH_RSTEN3_I2C0 0x301 29 + #define PERIPH_RSTEN3_I2C1 0x302 30 + #define PERIPH_RSTEN3_I2C2 0x303 31 + #define PERIPH_RSTEN3_I2C3 0x304 32 + #define PERIPH_RSTEN3_UART1 0x305 33 + #define PERIPH_RSTEN3_UART2 0x306 34 + #define PERIPH_RSTEN3_UART3 0x307 35 + #define PERIPH_RSTEN3_UART4 0x308 36 + #define PERIPH_RSTEN3_SSP 0x309 37 + #define PERIPH_RSTEN3_PWM 0x30a 38 + #define PERIPH_RSTEN3_BLPWM 0x30b 39 + #define PERIPH_RSTEN3_TSENSOR 0x30c 40 + #define PERIPH_RSTEN3_DAPB 0x312 41 + #define PERIPH_RSTEN3_HKADC 0x313 42 + #define PERIPH_RSTEN3_CODEC_SSI 0x314 43 + #define PERIPH_RSTEN3_PMUSSI1 0x316 44 + #define PERIPH_RSTEN8_RS0 0x400 45 + #define PERIPH_RSTEN8_RS2 0x401 46 + #define PERIPH_RSTEN8_RS3 0x402 47 + #define PERIPH_RSTEN8_MS0 0x403 48 + #define PERIPH_RSTEN8_MS2 0x405 49 + #define PERIPH_RSTEN8_XG2RAM0 0x406 50 + #define PERIPH_RSTEN8_X2SRAM_TZMA 0x407 51 + #define PERIPH_RSTEN8_SRAM 0x408 52 + #define PERIPH_RSTEN8_HARQ 0x40a 53 + #define PERIPH_RSTEN8_DDRC 0x40c 54 + #define PERIPH_RSTEN8_DDRC_APB 0x40d 55 + #define PERIPH_RSTEN8_DDRPACK_APB 0x40e 56 + #define PERIPH_RSTEN8_DDRT 0x411 57 + #define PERIPH_RSDIST9_CARM_DAP 0x500 58 + #define PERIPH_RSDIST9_CARM_ATB 0x501 59 + #define PERIPH_RSDIST9_CARM_LBUS 0x502 60 + #define PERIPH_RSDIST9_CARM_POR 0x503 61 + #define PERIPH_RSDIST9_CARM_CORE 0x504 62 + #define PERIPH_RSDIST9_CARM_DBG 0x505 63 + #define PERIPH_RSDIST9_CARM_L2 0x506 64 + #define PERIPH_RSDIST9_CARM_SOCDBG 0x507 65 + #define PERIPH_RSDIST9_CARM_ETM 0x508 66 + 67 + #endif /*_DT_BINDINGS_RESET_CONTROLLER_HI6220*/
+4
include/dt-bindings/reset/stih407-resets.h
··· 52 52 #define STIH407_KEYSCAN_SOFTRESET 26 53 53 #define STIH407_USB2_PORT0_SOFTRESET 27 54 54 #define STIH407_USB2_PORT1_SOFTRESET 28 55 + #define STIH407_ST231_AUD_SOFTRESET 29 56 + #define STIH407_ST231_DMU_SOFTRESET 30 57 + #define STIH407_ST231_GP0_SOFTRESET 31 58 + #define STIH407_ST231_GP1_SOFTRESET 32 55 59 56 60 /* Picophy reset defines */ 57 61 #define STIH407_PICOPHY0_RESET 0
+13 -4
include/linux/reset.h
··· 38 38 struct reset_control *of_reset_control_get(struct device_node *node, 39 39 const char *id); 40 40 41 + struct reset_control *of_reset_control_get_by_index( 42 + struct device_node *node, int index); 43 + 41 44 #else 42 45 43 46 static inline int reset_control_reset(struct reset_control *rstc) ··· 74 71 75 72 static inline int device_reset_optional(struct device *dev) 76 73 { 77 - return -ENOSYS; 74 + return -ENOTSUPP; 78 75 } 79 76 80 77 static inline struct reset_control *__must_check reset_control_get( ··· 94 91 static inline struct reset_control *reset_control_get_optional( 95 92 struct device *dev, const char *id) 96 93 { 97 - return ERR_PTR(-ENOSYS); 94 + return ERR_PTR(-ENOTSUPP); 98 95 } 99 96 100 97 static inline struct reset_control *devm_reset_control_get_optional( 101 98 struct device *dev, const char *id) 102 99 { 103 - return ERR_PTR(-ENOSYS); 100 + return ERR_PTR(-ENOTSUPP); 104 101 } 105 102 106 103 static inline struct reset_control *of_reset_control_get( 107 104 struct device_node *node, const char *id) 108 105 { 109 - return ERR_PTR(-ENOSYS); 106 + return ERR_PTR(-ENOTSUPP); 107 + } 108 + 109 + static inline struct reset_control *of_reset_control_get_by_index( 110 + struct device_node *node, int index) 111 + { 112 + return ERR_PTR(-ENOTSUPP); 110 113 } 111 114 112 115 #endif /* CONFIG_RESET_CONTROLLER */
+18
include/linux/soc/qcom/smem_state.h
··· 1 + #ifndef __QCOM_SMEM_STATE__ 2 + #define __QCOM_SMEM_STATE__ 3 + 4 + struct qcom_smem_state; 5 + 6 + struct qcom_smem_state_ops { 7 + int (*update_bits)(void *, u32, u32); 8 + }; 9 + 10 + struct qcom_smem_state *qcom_smem_state_get(struct device *dev, const char *con_id, unsigned *bit); 11 + void qcom_smem_state_put(struct qcom_smem_state *); 12 + 13 + int qcom_smem_state_update_bits(struct qcom_smem_state *state, u32 mask, u32 value); 14 + 15 + struct qcom_smem_state *qcom_smem_state_register(struct device_node *of_node, const struct qcom_smem_state_ops *ops, void *data); 16 + void qcom_smem_state_unregister(struct qcom_smem_state *state); 17 + 18 + #endif
+55
include/linux/wkup_m3_ipc.h
··· 1 + /* 2 + * TI Wakeup M3 for AMx3 SoCs Power Management Routines 3 + * 4 + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ 5 + * Dave Gerlach <d-gerlach@ti.com> 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify it under the terms of the GNU General Public License as 9 + * published by the Free Software Foundation version 2. 10 + * 11 + * This program is distributed "as is" WITHOUT ANY WARRANTY of any 12 + * kind, whether express or implied; without even the implied warranty 13 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + */ 16 + 17 + #ifndef _LINUX_WKUP_M3_IPC_H 18 + #define _LINUX_WKUP_M3_IPC_H 19 + 20 + #define WKUP_M3_DEEPSLEEP 1 21 + #define WKUP_M3_STANDBY 2 22 + #define WKUP_M3_IDLE 3 23 + 24 + #include <linux/mailbox_client.h> 25 + 26 + struct wkup_m3_ipc_ops; 27 + 28 + struct wkup_m3_ipc { 29 + struct rproc *rproc; 30 + 31 + void __iomem *ipc_mem_base; 32 + struct device *dev; 33 + 34 + int mem_type; 35 + unsigned long resume_addr; 36 + int state; 37 + 38 + struct completion sync_complete; 39 + struct mbox_client mbox_client; 40 + struct mbox_chan *mbox; 41 + 42 + struct wkup_m3_ipc_ops *ops; 43 + }; 44 + 45 + struct wkup_m3_ipc_ops { 46 + void (*set_mem_type)(struct wkup_m3_ipc *m3_ipc, int mem_type); 47 + void (*set_resume_address)(struct wkup_m3_ipc *m3_ipc, void *addr); 48 + int (*prepare_low_power)(struct wkup_m3_ipc *m3_ipc, int state); 49 + int (*finish_low_power)(struct wkup_m3_ipc *m3_ipc); 50 + int (*request_pm_status)(struct wkup_m3_ipc *m3_ipc); 51 + }; 52 + 53 + struct wkup_m3_ipc *wkup_m3_ipc_get(void); 54 + void wkup_m3_ipc_put(struct wkup_m3_ipc *m3_ipc); 55 + #endif /* _LINUX_WKUP_M3_IPC_H */
+2
include/soc/bcm2835/raspberrypi-firmware.h
··· 72 72 RPI_FIRMWARE_SET_ENABLE_QPU = 0x00030012, 73 73 RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014, 74 74 RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020, 75 + RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030, 75 76 RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001, 76 77 RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002, 77 78 RPI_FIRMWARE_SET_VOLTAGE = 0x00038003, 78 79 RPI_FIRMWARE_SET_TURBO = 0x00038009, 80 + RPI_FIRMWARE_SET_DOMAIN_STATE = 0x00038030, 79 81 80 82 /* Dispmanx TAGS */ 81 83 RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,