ARM: SoC driver updates for v4.9
Driver updates for ARM SoCs, including a couple of newly added drivers: - The Qualcomm external bus interface 2 (EBI2), used in some of their mobile phone chips for connecting flash memory, LCD displays or other peripherals - Secure monitor firmware for Amlogic SoCs, and an NVMEM driver for the EFUSE based on that firmware interface. - Perf support for the AppliedMicro X-Gene performance monitor unit - Reset driver for STMicroelectronics STM32 - Reset driver for SocioNext UniPhier SoCs Aside from these, there are minor updates to SoC-specific bus, clocksource, firmware, pinctrl, reset, rtc and pmic drivers. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIVAwUAV/gaimCrR//JCVInAQJaOQ/6A++YfLVmdF4wxgcu/0ti28lA7SkQIGJV UAsfCmqMEutbeDvnloVGmTV2K2NS7mzxdxsJGbVB7Oe/zdOFN+T9sf9hAlId01QA oVkoagpofoxlyKoKJ/l+heuEEZMa0Ekk3XXRTGv/Ovymo7252o4tEdGu9c+gyaMJ KqgixcrQRzxuWDgPpHUPUez2vY1iRMvvdcb0EmfiHcIgPOEJc6MIxulsqEIrkoMz WYeGFIeqRJxnrur3QD8WnD+aZD6bV01wkFTkWXGWg4H87QfEESgVBu5A7TL+5sL8 1SlX/b7S5/ZJbrOiOS2IUyvbK7NiA/Q+NunHW2rMVnUWuEvJ9HAQB1kVSQH5LIYO 6OBokjcijm6m/j6O6fdDfvNd6PLsIEUqfWVws7O+uofMMqKPxqak4VBTRdFM+aeF ZtK7mEbzteCX0bnC+XblZrseAlkIehYnP80CLDbtDTerTWP4gsjxGVt3U6MO0NzB K0ACWZOclzrcFscNKrmP6uPCpfZriiPV/XMCEHcylA/X2iYsVmpqKzdLuNs5aeUr uPzQbNWu9ygg/bDRXMYY2E3Kzjsc0eIOKEOPyhLaZdSo4e1FQxud6L2V2Vj0RLB/ iMA7/CyQZqn6Yzgs0VMZm/bnh+hIdHioGFl5K5j6Fcw9VZRkNmnEQJzX4VU5efGO g1+5av0vFXg= =GvTq -----END PGP SIGNATURE----- Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc Pull ARM SoC driver updates from Arnd Bergmann: "Driver updates for ARM SoCs, including a couple of newly added drivers: - The Qualcomm external bus interface 2 (EBI2), used in some of their mobile phone chips for connecting flash memory, LCD displays or other peripherals - Secure monitor firmware for Amlogic SoCs, and an NVMEM driver for the EFUSE based on that firmware interface. - Perf support for the AppliedMicro X-Gene performance monitor unit - Reset driver for STMicroelectronics STM32 - Reset driver for SocioNext UniPhier SoCs Aside from these, there are minor updates to SoC-specific bus, clocksource, firmware, pinctrl, reset, rtc and pmic drivers" * tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (50 commits) bus: qcom-ebi2: depend on HAS_IOMEM pinctrl: mvebu: orion5x: Generalise mv88f5181l support for 88f5181 clk: mvebu: Add clk support for the orion5x SoC mv88f5181 dt-bindings: EXYNOS: Add Exynos5433 PMU compatible clocksource: exynos_mct: Add the support for ARM64 perf: xgene: Add APM X-Gene SoC Performance Monitoring Unit driver Documentation: Add documentation for APM X-Gene SoC PMU DTS binding MAINTAINERS: Add entry for APM X-Gene SoC PMU driver bus: qcom: add EBI2 driver bus: qcom: add EBI2 device tree bindings rtc: rtc-pm8xxx: Add support for pm8018 rtc nvmem: amlogic: Add Amlogic Meson EFUSE driver firmware: Amlogic: Add secure monitor driver soc: qcom: smd: Reset rx tail rather than tx memory: atmel-sdramc: fix a possible NULL dereference reset: hi6220: allow to compile test driver on other architectures reset: zynq: add driver Kconfig option reset: sunxi: add driver Kconfig option reset: stm32: add driver Kconfig option reset: socfpga: add driver Kconfig option ...
This commit is contained in:
commit
6afd563d4b
|
@ -10,6 +10,7 @@ Properties:
|
|||
- "samsung,exynos5260-pmu" - for Exynos5260 SoC.
|
||||
- "samsung,exynos5410-pmu" - for Exynos5410 SoC,
|
||||
- "samsung,exynos5420-pmu" - for Exynos5420 SoC.
|
||||
- "samsung,exynos5433-pmu" - for Exynos5433 SoC.
|
||||
- "samsung,exynos7-pmu" - for Exynos7 SoC.
|
||||
second value must be always "syscon".
|
||||
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
Qualcomm External Bus Interface 2 (EBI2)
|
||||
|
||||
The EBI2 contains two peripheral blocks: XMEM and LCDC. The XMEM handles any
|
||||
external memory (such as NAND or other memory-mapped peripherals) whereas
|
||||
LCDC handles LCD displays.
|
||||
|
||||
As it says it connects devices to an external bus interface, meaning address
|
||||
lines (up to 9 address lines so can only address 1KiB external memory space),
|
||||
data lines (16 bits), OE (output enable), ADV (address valid, used on some
|
||||
NOR flash memories), WE (write enable). This on top of 6 different chip selects
|
||||
(CS0 thru CS5) so that in theory 6 different devices can be connected.
|
||||
|
||||
Apparently this bus is clocked at 64MHz. It has dedicated pins on the package
|
||||
and the bus can only come out on these pins, however if some of the pins are
|
||||
unused they can be left unconnected or remuxed to be used as GPIO or in some
|
||||
cases other orthogonal functions as well.
|
||||
|
||||
Also CS1 and CS2 has -A and -B signals. Why they have that is unclear to me.
|
||||
|
||||
The chip selects have the following memory range assignments. This region of
|
||||
memory is referred to as "Chip Peripheral SS FPB0" and is 168MB big.
|
||||
|
||||
Chip Select Physical address base
|
||||
CS0 GPIO134 0x1a800000-0x1b000000 (8MB)
|
||||
CS1 GPIO39 (A) / GPIO123 (B) 0x1b000000-0x1b800000 (8MB)
|
||||
CS2 GPIO40 (A) / GPIO124 (B) 0x1b800000-0x1c000000 (8MB)
|
||||
CS3 GPIO133 0x1d000000-0x25000000 (128 MB)
|
||||
CS4 GPIO132 0x1c800000-0x1d000000 (8MB)
|
||||
CS5 GPIO131 0x1c000000-0x1c800000 (8MB)
|
||||
|
||||
The APQ8060 Qualcomm Application Processor User Guide, 80-N7150-14 Rev. A,
|
||||
August 6, 2012 contains some incomplete documentation of the EBI2.
|
||||
|
||||
FIXME: the manual mentions "write precharge cycles" and "precharge cycles".
|
||||
We have not been able to figure out which bit fields these correspond to
|
||||
in the hardware, or what valid values exist. The current hypothesis is that
|
||||
this is something just used on the FAST chip selects and that the SLOW
|
||||
chip selects are understood fully. There is also a "byte device enable"
|
||||
flag somewhere for 8bit memories.
|
||||
|
||||
FIXME: The chipselects have SLOW and FAST configuration registers. It's a bit
|
||||
unclear what this means, if they are mutually exclusive or can be used
|
||||
together, or if some chip selects are hardwired to be FAST and others are SLOW
|
||||
by design.
|
||||
|
||||
The XMEM registers are totally undocumented but could be partially decoded
|
||||
because the Cypress AN49576 Antioch Westbridge apparently has suspiciously
|
||||
similar register layout, see: http://www.cypress.com/file/105771/download
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one of:
|
||||
"qcom,msm8660-ebi2"
|
||||
"qcom,apq8060-ebi2"
|
||||
- #address-cells: shoule be <2>: the first cell is the chipselect,
|
||||
the second cell is the offset inside the memory range
|
||||
- #size-cells: should be <1>
|
||||
- ranges: should be set to:
|
||||
ranges = <0 0x0 0x1a800000 0x00800000>,
|
||||
<1 0x0 0x1b000000 0x00800000>,
|
||||
<2 0x0 0x1b800000 0x00800000>,
|
||||
<3 0x0 0x1d000000 0x08000000>,
|
||||
<4 0x0 0x1c800000 0x00800000>,
|
||||
<5 0x0 0x1c000000 0x00800000>;
|
||||
- reg: two ranges of registers: EBI2 config and XMEM config areas
|
||||
- reg-names: should be "ebi2", "xmem"
|
||||
- clocks: two clocks, EBI_2X and EBI
|
||||
- clock-names: shoule be "ebi2x", "ebi2"
|
||||
|
||||
Optional subnodes:
|
||||
- Nodes inside the EBI2 will be considered device nodes.
|
||||
|
||||
The following optional properties are properties that can be tagged onto
|
||||
any device subnode. We are assuming that there can be only ONE device per
|
||||
chipselect subnode, else the properties will become ambigous.
|
||||
|
||||
Optional properties arrays for SLOW chip selects:
|
||||
- qcom,xmem-recovery-cycles: recovery cycles is the time the memory continues to
|
||||
drive the data bus after OE is de-asserted, in order to avoid contention on
|
||||
the data bus. They are inserted when reading one CS and switching to another
|
||||
CS or read followed by write on the same CS. Valid values 0 thru 15. Minimum
|
||||
value is actually 1, so a value of 0 will still yield 1 recovery cycle.
|
||||
- qcom,xmem-write-hold-cycles: write hold cycles, these are extra cycles
|
||||
inserted after every write minimum 1. The data out is driven from the time
|
||||
WE is asserted until CS is asserted. With a hold of 1 (value = 0), the CS
|
||||
stays active for 1 extra cycle etc. Valid values 0 thru 15.
|
||||
- qcom,xmem-write-delta-cycles: initial latency for write cycles inserted for
|
||||
the first write to a page or burst memory. Valid values 0 thru 255.
|
||||
- qcom,xmem-read-delta-cycles: initial latency for read cycles inserted for the
|
||||
first read to a page or burst memory. Valid values 0 thru 255.
|
||||
- qcom,xmem-write-wait-cycles: number of wait cycles for every write access, 0=1
|
||||
cycle. Valid values 0 thru 15.
|
||||
- qcom,xmem-read-wait-cycles: number of wait cycles for every read access, 0=1
|
||||
cycle. Valid values 0 thru 15.
|
||||
|
||||
Optional properties arrays for FAST chip selects:
|
||||
- qcom,xmem-address-hold-enable: this is a boolean property stating that we
|
||||
shall hold the address for an extra cycle to meet hold time requirements
|
||||
with ADV assertion.
|
||||
- qcom,xmem-adv-to-oe-recovery-cycles: the number of cycles elapsed before an OE
|
||||
assertion, with respect to the cycle where ADV (address valid) is asserted.
|
||||
2 means 2 cycles between ADV and OE. Valid values 0, 1, 2 or 3.
|
||||
- qcom,xmem-read-hold-cycles: the length in cycles of the first segment of a
|
||||
read transfer. For a single read trandfer this will be the time from CS
|
||||
assertion to OE assertion. Valid values 0 thru 15.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
ebi2@1a100000 {
|
||||
compatible = "qcom,apq8060-ebi2";
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0 0x0 0x1a800000 0x00800000>,
|
||||
<1 0x0 0x1b000000 0x00800000>,
|
||||
<2 0x0 0x1b800000 0x00800000>,
|
||||
<3 0x0 0x1d000000 0x08000000>,
|
||||
<4 0x0 0x1c800000 0x00800000>,
|
||||
<5 0x0 0x1c000000 0x00800000>;
|
||||
reg = <0x1a100000 0x1000>, <0x1a110000 0x1000>;
|
||||
reg-names = "ebi2", "xmem";
|
||||
clocks = <&gcc EBI2_2X_CLK>, <&gcc EBI2_CLK>;
|
||||
clock-names = "ebi2x", "ebi2";
|
||||
/* Make sure to set up the pin control for the EBI2 */
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&foo_ebi2_pins>;
|
||||
|
||||
foo-ebi2@2,0 {
|
||||
compatible = "foo";
|
||||
reg = <2 0x0 0x100>;
|
||||
(...)
|
||||
qcom,xmem-recovery-cycles = <0>;
|
||||
qcom,xmem-write-hold-cycles = <3>;
|
||||
qcom,xmem-write-delta-cycles = <31>;
|
||||
qcom,xmem-read-delta-cycles = <28>;
|
||||
qcom,xmem-write-wait-cycles = <9>;
|
||||
qcom,xmem-read-wait-cycles = <9>;
|
||||
};
|
||||
};
|
|
@ -52,6 +52,7 @@ Required properties:
|
|||
"marvell,dove-core-clock" - for Dove SoC core clocks
|
||||
"marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180)
|
||||
"marvell,mv88f6180-core-clock" - for Kirkwood MV88f6180 SoC
|
||||
"marvell,mv88f5181-core-clock" - for Orion MV88F5181 SoC
|
||||
"marvell,mv88f5182-core-clock" - for Orion MV88F5182 SoC
|
||||
"marvell,mv88f5281-core-clock" - for Orion MV88F5281 SoC
|
||||
"marvell,mv88f6183-core-clock" - for Orion MV88F6183 SoC
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
STMicroelectronics STM32 Reset and Clock Controller
|
||||
===================================================
|
||||
|
||||
The RCC IP is both a reset and a clock controller. This documentation only
|
||||
describes the clock part.
|
||||
The RCC IP is both a reset and a clock controller.
|
||||
|
||||
Please also refer to clock-bindings.txt in this directory for common clock
|
||||
controller binding usage.
|
||||
Please refer to clock-bindings.txt for common clock controller binding usage.
|
||||
Please also refer to reset.txt for common reset controller binding usage.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "st,stm32f42xx-rcc"
|
||||
- reg: should be register base and length as documented in the
|
||||
datasheet
|
||||
- #reset-cells: 1, see below
|
||||
- #clock-cells: 2, device nodes should specify the clock in their "clocks"
|
||||
property, containing a phandle to the clock device node, an index selecting
|
||||
between gated clocks and other clocks and an index specifying the clock to
|
||||
|
@ -19,6 +19,7 @@ Required properties:
|
|||
Example:
|
||||
|
||||
rcc: rcc@40023800 {
|
||||
#reset-cells = <1>;
|
||||
#clock-cells = <2>
|
||||
compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
|
||||
reg = <0x40023800 0x400>;
|
||||
|
@ -35,16 +36,23 @@ from the first RCC clock enable register (RCC_AHB1ENR, address offset 0x30).
|
|||
It is calculated as: index = register_offset / 4 * 32 + bit_offset.
|
||||
Where bit_offset is the bit offset within the register (LSB is 0, MSB is 31).
|
||||
|
||||
To simplify the usage and to share bit definition with the reset and clock
|
||||
drivers of the RCC IP, macros are available to generate the index in
|
||||
human-readble format.
|
||||
|
||||
For STM32F4 series, the macro are available here:
|
||||
- include/dt-bindings/mfd/stm32f4-rcc.h
|
||||
|
||||
Example:
|
||||
|
||||
/* Gated clock, AHB1 bit 0 (GPIOA) */
|
||||
... {
|
||||
clocks = <&rcc 0 0>
|
||||
clocks = <&rcc 0 STM32F4_AHB1_CLOCK(GPIOA)>
|
||||
};
|
||||
|
||||
/* Gated clock, AHB2 bit 4 (CRYP) */
|
||||
... {
|
||||
clocks = <&rcc 0 36>
|
||||
clocks = <&rcc 0 STM32F4_AHB2_CLOCK(CRYP)>
|
||||
};
|
||||
|
||||
Specifying other clocks
|
||||
|
@ -61,5 +69,25 @@ Example:
|
|||
|
||||
/* Misc clock, FCLK */
|
||||
... {
|
||||
clocks = <&rcc 1 1>
|
||||
clocks = <&rcc 1 STM32F4_APB1_CLOCK(TIM2)>
|
||||
};
|
||||
|
||||
|
||||
Specifying softreset control of devices
|
||||
=======================================
|
||||
|
||||
Device nodes should specify the reset channel required in their "resets"
|
||||
property, containing a phandle to the reset device node and an index specifying
|
||||
which channel to use.
|
||||
The index is the bit number within the RCC registers bank, starting from RCC
|
||||
base address.
|
||||
It is calculated as: index = register_offset / 4 * 32 + bit_offset.
|
||||
Where bit_offset is the bit offset within the register.
|
||||
For example, for CRC reset:
|
||||
crc = AHB1RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x10 / 4 * 32 + 12 = 140
|
||||
|
||||
example:
|
||||
|
||||
timer2 {
|
||||
resets = <&rcc STM32F4_APB1_RESET(TIM2)>;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
* APM X-Gene SoC PMU bindings
|
||||
|
||||
This is APM X-Gene SoC PMU (Performance Monitoring Unit) module.
|
||||
The following PMU devices are supported:
|
||||
|
||||
L3C - L3 cache controller
|
||||
IOB - IO bridge
|
||||
MCB - Memory controller bridge
|
||||
MC - Memory controller
|
||||
|
||||
The following section describes the SoC PMU DT node binding.
|
||||
|
||||
Required properties:
|
||||
- compatible : Shall be "apm,xgene-pmu" for revision 1 or
|
||||
"apm,xgene-pmu-v2" for revision 2.
|
||||
- regmap-csw : Regmap of the CPU switch fabric (CSW) resource.
|
||||
- regmap-mcba : Regmap of the MCB-A (memory bridge) resource.
|
||||
- regmap-mcbb : Regmap of the MCB-B (memory bridge) resource.
|
||||
- reg : First resource shall be the CPU bus PMU resource.
|
||||
- interrupts : Interrupt-specifier for PMU IRQ.
|
||||
|
||||
Required properties for L3C subnode:
|
||||
- compatible : Shall be "apm,xgene-pmu-l3c".
|
||||
- reg : First resource shall be the L3C PMU resource.
|
||||
|
||||
Required properties for IOB subnode:
|
||||
- compatible : Shall be "apm,xgene-pmu-iob".
|
||||
- reg : First resource shall be the IOB PMU resource.
|
||||
|
||||
Required properties for MCB subnode:
|
||||
- compatible : Shall be "apm,xgene-pmu-mcb".
|
||||
- reg : First resource shall be the MCB PMU resource.
|
||||
- enable-bit-index : The bit indicates if the according MCB is enabled.
|
||||
|
||||
Required properties for MC subnode:
|
||||
- compatible : Shall be "apm,xgene-pmu-mc".
|
||||
- reg : First resource shall be the MC PMU resource.
|
||||
- enable-bit-index : The bit indicates if the according MC is enabled.
|
||||
|
||||
Example:
|
||||
csw: csw@7e200000 {
|
||||
compatible = "apm,xgene-csw", "syscon";
|
||||
reg = <0x0 0x7e200000 0x0 0x1000>;
|
||||
};
|
||||
|
||||
mcba: mcba@7e700000 {
|
||||
compatible = "apm,xgene-mcb", "syscon";
|
||||
reg = <0x0 0x7e700000 0x0 0x1000>;
|
||||
};
|
||||
|
||||
mcbb: mcbb@7e720000 {
|
||||
compatible = "apm,xgene-mcb", "syscon";
|
||||
reg = <0x0 0x7e720000 0x0 0x1000>;
|
||||
};
|
||||
|
||||
pmu: pmu@78810000 {
|
||||
compatible = "apm,xgene-pmu-v2";
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
regmap-csw = <&csw>;
|
||||
regmap-mcba = <&mcba>;
|
||||
regmap-mcbb = <&mcbb>;
|
||||
reg = <0x0 0x78810000 0x0 0x1000>;
|
||||
interrupts = <0x0 0x22 0x4>;
|
||||
|
||||
pmul3c@7e610000 {
|
||||
compatible = "apm,xgene-pmu-l3c";
|
||||
reg = <0x0 0x7e610000 0x0 0x1000>;
|
||||
};
|
||||
|
||||
pmuiob@7e940000 {
|
||||
compatible = "apm,xgene-pmu-iob";
|
||||
reg = <0x0 0x7e940000 0x0 0x1000>;
|
||||
};
|
||||
|
||||
pmucmcb@7e710000 {
|
||||
compatible = "apm,xgene-pmu-mcb";
|
||||
reg = <0x0 0x7e710000 0x0 0x1000>;
|
||||
enable-bit-index = <0>;
|
||||
};
|
||||
|
||||
pmucmcb@7e730000 {
|
||||
compatible = "apm,xgene-pmu-mcb";
|
||||
reg = <0x0 0x7e730000 0x0 0x1000>;
|
||||
enable-bit-index = <1>;
|
||||
};
|
||||
|
||||
pmucmc@7e810000 {
|
||||
compatible = "apm,xgene-pmu-mc";
|
||||
reg = <0x0 0x7e810000 0x0 0x1000>;
|
||||
enable-bit-index = <0>;
|
||||
};
|
||||
|
||||
pmucmc@7e850000 {
|
||||
compatible = "apm,xgene-pmu-mc";
|
||||
reg = <0x0 0x7e850000 0x0 0x1000>;
|
||||
enable-bit-index = <1>;
|
||||
};
|
||||
|
||||
pmucmc@7e890000 {
|
||||
compatible = "apm,xgene-pmu-mc";
|
||||
reg = <0x0 0x7e890000 0x0 0x1000>;
|
||||
enable-bit-index = <2>;
|
||||
};
|
||||
|
||||
pmucmc@7e8d0000 {
|
||||
compatible = "apm,xgene-pmu-mc";
|
||||
reg = <0x0 0x7e8d0000 0x0 0x1000>;
|
||||
enable-bit-index = <3>;
|
||||
};
|
||||
};
|
|
@ -4,7 +4,9 @@ Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding
|
|||
part and usage.
|
||||
|
||||
Required properties:
|
||||
- compatible: "marvell,88f5181l-pinctrl", "marvell,88f5182-pinctrl",
|
||||
- compatible: "marvell,88f5181-pinctrl",
|
||||
"marvell,88f5181l-pinctrl",
|
||||
"marvell,88f5182-pinctrl",
|
||||
"marvell,88f5281-pinctrl"
|
||||
|
||||
- reg: two register areas, the first one describing the first two
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
STMicroelectronics STM32 Peripheral Reset Controller
|
||||
====================================================
|
||||
|
||||
The RCC IP is both a reset and a clock controller.
|
||||
|
||||
Please see Documentation/devicetree/bindings/clock/st,stm32-rcc.txt
|
|
@ -0,0 +1,93 @@
|
|||
UniPhier reset controller
|
||||
|
||||
|
||||
System reset
|
||||
------------
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one of the following:
|
||||
"socionext,uniphier-sld3-reset" - for PH1-sLD3 SoC.
|
||||
"socionext,uniphier-ld4-reset" - for PH1-LD4 SoC.
|
||||
"socionext,uniphier-pro4-reset" - for PH1-Pro4 SoC.
|
||||
"socionext,uniphier-sld8-reset" - for PH1-sLD8 SoC.
|
||||
"socionext,uniphier-pro5-reset" - for PH1-Pro5 SoC.
|
||||
"socionext,uniphier-pxs2-reset" - for ProXstream2/PH1-LD6b SoC.
|
||||
"socionext,uniphier-ld11-reset" - for PH1-LD11 SoC.
|
||||
"socionext,uniphier-ld20-reset" - for PH1-LD20 SoC.
|
||||
- #reset-cells: should be 1.
|
||||
|
||||
Example:
|
||||
|
||||
sysctrl@61840000 {
|
||||
compatible = "socionext,uniphier-ld20-sysctrl",
|
||||
"simple-mfd", "syscon";
|
||||
reg = <0x61840000 0x4000>;
|
||||
|
||||
reset {
|
||||
compatible = "socionext,uniphier-ld20-reset";
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
other nodes ...
|
||||
};
|
||||
|
||||
|
||||
Media I/O (MIO) reset
|
||||
---------------------
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one of the following:
|
||||
"socionext,uniphier-sld3-mio-reset" - for PH1-sLD3 SoC.
|
||||
"socionext,uniphier-ld4-mio-reset" - for PH1-LD4 SoC.
|
||||
"socionext,uniphier-pro4-mio-reset" - for PH1-Pro4 SoC.
|
||||
"socionext,uniphier-sld8-mio-reset" - for PH1-sLD8 SoC.
|
||||
"socionext,uniphier-pro5-mio-reset" - for PH1-Pro5 SoC.
|
||||
"socionext,uniphier-pxs2-mio-reset" - for ProXstream2/PH1-LD6b SoC.
|
||||
"socionext,uniphier-ld11-mio-reset" - for PH1-LD11 SoC.
|
||||
"socionext,uniphier-ld20-mio-reset" - for PH1-LD20 SoC.
|
||||
- #reset-cells: should be 1.
|
||||
|
||||
Example:
|
||||
|
||||
mioctrl@59810000 {
|
||||
compatible = "socionext,uniphier-ld20-mioctrl",
|
||||
"simple-mfd", "syscon";
|
||||
reg = <0x59810000 0x800>;
|
||||
|
||||
reset {
|
||||
compatible = "socionext,uniphier-ld20-mio-reset";
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
other nodes ...
|
||||
};
|
||||
|
||||
|
||||
Peripheral reset
|
||||
----------------
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one of the following:
|
||||
"socionext,uniphier-ld4-peri-reset" - for PH1-LD4 SoC.
|
||||
"socionext,uniphier-pro4-peri-reset" - for PH1-Pro4 SoC.
|
||||
"socionext,uniphier-sld8-peri-reset" - for PH1-sLD8 SoC.
|
||||
"socionext,uniphier-pro5-peri-reset" - for PH1-Pro5 SoC.
|
||||
"socionext,uniphier-pxs2-peri-reset" - for ProXstream2/PH1-LD6b SoC.
|
||||
"socionext,uniphier-ld11-peri-reset" - for PH1-LD11 SoC.
|
||||
"socionext,uniphier-ld20-peri-reset" - for PH1-LD20 SoC.
|
||||
- #reset-cells: should be 1.
|
||||
|
||||
Example:
|
||||
|
||||
perictrl@59820000 {
|
||||
compatible = "socionext,uniphier-ld20-perictrl",
|
||||
"simple-mfd", "syscon";
|
||||
reg = <0x59820000 0x200>;
|
||||
|
||||
reset {
|
||||
compatible = "socionext,uniphier-ld20-peri-reset";
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
other nodes ...
|
||||
};
|
|
@ -0,0 +1,48 @@
|
|||
APM X-Gene SoC Performance Monitoring Unit (PMU)
|
||||
================================================
|
||||
|
||||
X-Gene SoC PMU consists of various independent system device PMUs such as
|
||||
L3 cache(s), I/O bridge(s), memory controller bridge(s) and memory
|
||||
controller(s). These PMU devices are loosely architected to follow the
|
||||
same model as the PMU for ARM cores. The PMUs share the same top level
|
||||
interrupt and status CSR region.
|
||||
|
||||
PMU (perf) driver
|
||||
-----------------
|
||||
|
||||
The xgene-pmu driver registers several perf PMU drivers. Each of the perf
|
||||
driver provides description of its available events and configuration options
|
||||
in sysfs, see /sys/devices/<l3cX/iobX/mcbX/mcX>/.
|
||||
|
||||
The "format" directory describes format of the config (event ID),
|
||||
config1 (agent ID) fields of the perf_event_attr structure. The "events"
|
||||
directory provides configuration templates for all supported event types that
|
||||
can be used with perf tool. For example, "l3c0/bank-fifo-full/" is an
|
||||
equivalent of "l3c0/config=0x0b/".
|
||||
|
||||
Most of the SoC PMU has a specific list of agent ID used for monitoring
|
||||
performance of a specific datapath. For example, agents of a L3 cache can be
|
||||
a specific CPU or an I/O bridge. Each PMU has a set of 2 registers capable of
|
||||
masking the agents from which the request come from. If the bit with
|
||||
the bit number corresponding to the agent is set, the event is counted only if
|
||||
it is caused by a request from that agent. Each agent ID bit is inversely mapped
|
||||
to a corresponding bit in "config1" field. By default, the event will be
|
||||
counted for all agent requests (config1 = 0x0). For all the supported agents of
|
||||
each PMU, please refer to APM X-Gene User Manual.
|
||||
|
||||
Each perf driver also provides a "cpumask" sysfs attribute, which contains a
|
||||
single CPU ID of the processor which will be used to handle all the PMU events.
|
||||
|
||||
Example for perf tool use:
|
||||
|
||||
/ # perf list | grep -e l3c -e iob -e mcb -e mc
|
||||
l3c0/ackq-full/ [Kernel PMU event]
|
||||
<...>
|
||||
mcb1/mcb-csw-stall/ [Kernel PMU event]
|
||||
|
||||
/ # perf stat -a -e l3c0/read-miss/,mcb1/csw-write-request/ sleep 1
|
||||
|
||||
/ # perf stat -a -e l3c0/read-miss,config1=0xfffffffffffffffe/ sleep 1
|
||||
|
||||
The driver does not support sampling, therefore "perf record" will
|
||||
not work. Per-task (without "-a") perf sessions are not supported.
|
|
@ -866,6 +866,13 @@ F: drivers/net/phy/mdio-xgene.c
|
|||
F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt
|
||||
F: Documentation/devicetree/bindings/net/apm-xgene-mdio.txt
|
||||
|
||||
APPLIED MICRO (APM) X-GENE SOC PMU
|
||||
M: Tai Nguyen <ttnguyen@apm.com>
|
||||
S: Supported
|
||||
F: drivers/perf/xgene_pmu.c
|
||||
F: Documentation/perf/xgene-pmu.txt
|
||||
F: Documentation/devicetree/bindings/perf/apm-xgene-pmu.txt
|
||||
|
||||
APTINA CAMERA SENSOR PLL
|
||||
M: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
@ -1861,6 +1868,7 @@ F: drivers/bus/uniphier-system-bus.c
|
|||
F: drivers/clk/uniphier/
|
||||
F: drivers/i2c/busses/i2c-uniphier*
|
||||
F: drivers/pinctrl/uniphier/
|
||||
F: drivers/reset/reset-uniphier.c
|
||||
F: drivers/tty/serial/8250/8250_uniphier.c
|
||||
N: uniphier
|
||||
|
||||
|
|
|
@ -334,6 +334,7 @@
|
|||
};
|
||||
|
||||
rcc: rcc@40023810 {
|
||||
#reset-cells = <1>;
|
||||
#clock-cells = <2>;
|
||||
compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
|
||||
reg = <0x40023800 0x400>;
|
||||
|
|
|
@ -108,6 +108,14 @@ config OMAP_OCP2SCP
|
|||
OCP2SCP and in OMAP5, both USB PHY and SATA PHY is connected via
|
||||
OCP2SCP.
|
||||
|
||||
config QCOM_EBI2
|
||||
bool "Qualcomm External Bus Interface 2 (EBI2)"
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
Say y here to enable support for the Qualcomm External Bus
|
||||
Interface 2, which can be used to connect things like NAND Flash,
|
||||
SRAM, ethernet adapters, FPGAs and LCD displays.
|
||||
|
||||
config SIMPLE_PM_BUS
|
||||
bool "Simple Power-Managed Bus Driver"
|
||||
depends on OF && PM
|
||||
|
@ -132,12 +140,8 @@ config SUNXI_RSB
|
|||
with various RSB based devices, such as AXP223, AXP8XX PMICs,
|
||||
and AC100/AC200 ICs.
|
||||
|
||||
# TODO: This uses pm_clk_*() symbols that aren't exported in v4.7 and hence
|
||||
# the driver will fail to build as a module. However there are patches to
|
||||
# address that queued for v4.8, so this can be turned into a tristate symbol
|
||||
# after v4.8-rc1.
|
||||
config TEGRA_ACONNECT
|
||||
bool "Tegra ACONNECT Bus Driver"
|
||||
tristate "Tegra ACONNECT Bus Driver"
|
||||
depends on ARCH_TEGRA_210_SOC
|
||||
depends on OF && PM
|
||||
select PM_CLK
|
||||
|
|
|
@ -15,6 +15,7 @@ obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o
|
|||
obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o
|
||||
|
||||
obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
|
||||
obj-$(CONFIG_QCOM_EBI2) += qcom-ebi2.o
|
||||
obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
|
||||
obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
|
||||
obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o
|
||||
|
|
|
@ -0,0 +1,408 @@
|
|||
/*
|
||||
* Qualcomm External Bus Interface 2 (EBI2) driver
|
||||
* an older version of the Qualcomm Parallel Interface Controller (QPIC)
|
||||
*
|
||||
* Copyright (C) 2016 Linaro Ltd.
|
||||
*
|
||||
* Author: Linus Walleij <linus.walleij@linaro.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* See the device tree bindings for this block for more details on the
|
||||
* hardware.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/*
|
||||
* CS0, CS1, CS4 and CS5 are two bits wide, CS2 and CS3 are one bit.
|
||||
*/
|
||||
#define EBI2_CS0_ENABLE_MASK BIT(0)|BIT(1)
|
||||
#define EBI2_CS1_ENABLE_MASK BIT(2)|BIT(3)
|
||||
#define EBI2_CS2_ENABLE_MASK BIT(4)
|
||||
#define EBI2_CS3_ENABLE_MASK BIT(5)
|
||||
#define EBI2_CS4_ENABLE_MASK BIT(6)|BIT(7)
|
||||
#define EBI2_CS5_ENABLE_MASK BIT(8)|BIT(9)
|
||||
#define EBI2_CSN_MASK GENMASK(9, 0)
|
||||
|
||||
#define EBI2_XMEM_CFG 0x0000 /* Power management etc */
|
||||
|
||||
/*
|
||||
* SLOW CSn CFG
|
||||
*
|
||||
* Bits 31-28: RECOVERY recovery cycles (0 = 1, 1 = 2 etc) this is the time the
|
||||
* memory continues to drive the data bus after OE is de-asserted.
|
||||
* Inserted when reading one CS and switching to another CS or read
|
||||
* followed by write on the same CS. Valid values 0 thru 15.
|
||||
* Bits 27-24: WR_HOLD write hold cycles, these are extra cycles inserted after
|
||||
* every write minimum 1. The data out is driven from the time WE is
|
||||
* asserted until CS is asserted. With a hold of 1, the CS stays
|
||||
* active for 1 extra cycle etc. Valid values 0 thru 15.
|
||||
* Bits 23-16: WR_DELTA initial latency for write cycles inserted for the first
|
||||
* write to a page or burst memory
|
||||
* Bits 15-8: RD_DELTA initial latency for read cycles inserted for the first
|
||||
* read to a page or burst memory
|
||||
* Bits 7-4: WR_WAIT number of wait cycles for every write access, 0=1 cycle
|
||||
* so 1 thru 16 cycles.
|
||||
* Bits 3-0: RD_WAIT number of wait cycles for every read access, 0=1 cycle
|
||||
* so 1 thru 16 cycles.
|
||||
*/
|
||||
#define EBI2_XMEM_CS0_SLOW_CFG 0x0008
|
||||
#define EBI2_XMEM_CS1_SLOW_CFG 0x000C
|
||||
#define EBI2_XMEM_CS2_SLOW_CFG 0x0010
|
||||
#define EBI2_XMEM_CS3_SLOW_CFG 0x0014
|
||||
#define EBI2_XMEM_CS4_SLOW_CFG 0x0018
|
||||
#define EBI2_XMEM_CS5_SLOW_CFG 0x001C
|
||||
|
||||
#define EBI2_XMEM_RECOVERY_SHIFT 28
|
||||
#define EBI2_XMEM_WR_HOLD_SHIFT 24
|
||||
#define EBI2_XMEM_WR_DELTA_SHIFT 16
|
||||
#define EBI2_XMEM_RD_DELTA_SHIFT 8
|
||||
#define EBI2_XMEM_WR_WAIT_SHIFT 4
|
||||
#define EBI2_XMEM_RD_WAIT_SHIFT 0
|
||||
|
||||
/*
|
||||
* FAST CSn CFG
|
||||
* Bits 31-28: ?
|
||||
* Bits 27-24: RD_HOLD: the length in cycles of the first segment of a read
|
||||
* transfer. For a single read trandfer this will be the time
|
||||
* from CS assertion to OE assertion.
|
||||
* Bits 18-24: ?
|
||||
* Bits 17-16: ADV_OE_RECOVERY, the number of cycles elapsed before an OE
|
||||
* assertion, with respect to the cycle where ADV is asserted.
|
||||
* 2 means 2 cycles between ADV and OE. Values 0, 1, 2 or 3.
|
||||
* Bits 5: ADDR_HOLD_ENA, The address is held for an extra cycle to meet
|
||||
* hold time requirements with ADV assertion.
|
||||
*
|
||||
* The manual mentions "write precharge cycles" and "precharge cycles".
|
||||
* We have not been able to figure out which bit fields these correspond to
|
||||
* in the hardware, or what valid values exist. The current hypothesis is that
|
||||
* this is something just used on the FAST chip selects. There is also a "byte
|
||||
* device enable" flag somewhere for 8bit memories.
|
||||
*/
|
||||
#define EBI2_XMEM_CS0_FAST_CFG 0x0028
|
||||
#define EBI2_XMEM_CS1_FAST_CFG 0x002C
|
||||
#define EBI2_XMEM_CS2_FAST_CFG 0x0030
|
||||
#define EBI2_XMEM_CS3_FAST_CFG 0x0034
|
||||
#define EBI2_XMEM_CS4_FAST_CFG 0x0038
|
||||
#define EBI2_XMEM_CS5_FAST_CFG 0x003C
|
||||
|
||||
#define EBI2_XMEM_RD_HOLD_SHIFT 24
|
||||
#define EBI2_XMEM_ADV_OE_RECOVERY_SHIFT 16
|
||||
#define EBI2_XMEM_ADDR_HOLD_ENA_SHIFT 5
|
||||
|
||||
/**
|
||||
* struct cs_data - struct with info on a chipselect setting
|
||||
* @enable_mask: mask to enable the chipselect in the EBI2 config
|
||||
* @slow_cfg0: offset to XMEMC slow CS config
|
||||
* @fast_cfg1: offset to XMEMC fast CS config
|
||||
*/
|
||||
struct cs_data {
|
||||
u32 enable_mask;
|
||||
u16 slow_cfg;
|
||||
u16 fast_cfg;
|
||||
};
|
||||
|
||||
static const struct cs_data cs_info[] = {
|
||||
{
|
||||
/* CS0 */
|
||||
.enable_mask = EBI2_CS0_ENABLE_MASK,
|
||||
.slow_cfg = EBI2_XMEM_CS0_SLOW_CFG,
|
||||
.fast_cfg = EBI2_XMEM_CS0_FAST_CFG,
|
||||
},
|
||||
{
|
||||
/* CS1 */
|
||||
.enable_mask = EBI2_CS1_ENABLE_MASK,
|
||||
.slow_cfg = EBI2_XMEM_CS1_SLOW_CFG,
|
||||
.fast_cfg = EBI2_XMEM_CS1_FAST_CFG,
|
||||
},
|
||||
{
|
||||
/* CS2 */
|
||||
.enable_mask = EBI2_CS2_ENABLE_MASK,
|
||||
.slow_cfg = EBI2_XMEM_CS2_SLOW_CFG,
|
||||
.fast_cfg = EBI2_XMEM_CS2_FAST_CFG,
|
||||
},
|
||||
{
|
||||
/* CS3 */
|
||||
.enable_mask = EBI2_CS3_ENABLE_MASK,
|
||||
.slow_cfg = EBI2_XMEM_CS3_SLOW_CFG,
|
||||
.fast_cfg = EBI2_XMEM_CS3_FAST_CFG,
|
||||
},
|
||||
{
|
||||
/* CS4 */
|
||||
.enable_mask = EBI2_CS4_ENABLE_MASK,
|
||||
.slow_cfg = EBI2_XMEM_CS4_SLOW_CFG,
|
||||
.fast_cfg = EBI2_XMEM_CS4_FAST_CFG,
|
||||
},
|
||||
{
|
||||
/* CS5 */
|
||||
.enable_mask = EBI2_CS5_ENABLE_MASK,
|
||||
.slow_cfg = EBI2_XMEM_CS5_SLOW_CFG,
|
||||
.fast_cfg = EBI2_XMEM_CS5_FAST_CFG,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ebi2_xmem_prop - describes an XMEM config property
|
||||
* @prop: the device tree binding name
|
||||
* @max: maximum value for the property
|
||||
* @slowreg: true if this property is in the SLOW CS config register
|
||||
* else it is assumed to be in the FAST config register
|
||||
* @shift: the bit field start in the SLOW or FAST register for this
|
||||
* property
|
||||
*/
|
||||
struct ebi2_xmem_prop {
|
||||
const char *prop;
|
||||
u32 max;
|
||||
bool slowreg;
|
||||
u16 shift;
|
||||
};
|
||||
|
||||
static const struct ebi2_xmem_prop xmem_props[] = {
|
||||
{
|
||||
.prop = "qcom,xmem-recovery-cycles",
|
||||
.max = 15,
|
||||
.slowreg = true,
|
||||
.shift = EBI2_XMEM_RECOVERY_SHIFT,
|
||||
},
|
||||
{
|
||||
.prop = "qcom,xmem-write-hold-cycles",
|
||||
.max = 15,
|
||||
.slowreg = true,
|
||||
.shift = EBI2_XMEM_WR_HOLD_SHIFT,
|
||||
},
|
||||
{
|
||||
.prop = "qcom,xmem-write-delta-cycles",
|
||||
.max = 255,
|
||||
.slowreg = true,
|
||||
.shift = EBI2_XMEM_WR_DELTA_SHIFT,
|
||||
},
|
||||
{
|
||||
.prop = "qcom,xmem-read-delta-cycles",
|
||||
.max = 255,
|
||||
.slowreg = true,
|
||||
.shift = EBI2_XMEM_RD_DELTA_SHIFT,
|
||||
},
|
||||
{
|
||||
.prop = "qcom,xmem-write-wait-cycles",
|
||||
.max = 15,
|
||||
.slowreg = true,
|
||||
.shift = EBI2_XMEM_WR_WAIT_SHIFT,
|
||||
},
|
||||
{
|
||||
.prop = "qcom,xmem-read-wait-cycles",
|
||||
.max = 15,
|
||||
.slowreg = true,
|
||||
.shift = EBI2_XMEM_RD_WAIT_SHIFT,
|
||||
},
|
||||
{
|
||||
.prop = "qcom,xmem-address-hold-enable",
|
||||
.max = 1, /* boolean prop */
|
||||
.slowreg = false,
|
||||
.shift = EBI2_XMEM_ADDR_HOLD_ENA_SHIFT,
|
||||
},
|
||||
{
|
||||
.prop = "qcom,xmem-adv-to-oe-recovery-cycles",
|
||||
.max = 3,
|
||||
.slowreg = false,
|
||||
.shift = EBI2_XMEM_ADV_OE_RECOVERY_SHIFT,
|
||||
},
|
||||
{
|
||||
.prop = "qcom,xmem-read-hold-cycles",
|
||||
.max = 15,
|
||||
.slowreg = false,
|
||||
.shift = EBI2_XMEM_RD_HOLD_SHIFT,
|
||||
},
|
||||
};
|
||||
|
||||
static void qcom_ebi2_setup_chipselect(struct device_node *np,
|
||||
struct device *dev,
|
||||
void __iomem *ebi2_base,
|
||||
void __iomem *ebi2_xmem,
|
||||
u32 csindex)
|
||||
{
|
||||
const struct cs_data *csd;
|
||||
u32 slowcfg, fastcfg;
|
||||
u32 val;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
csd = &cs_info[csindex];
|
||||
val = readl(ebi2_base);
|
||||
val |= csd->enable_mask;
|
||||
writel(val, ebi2_base);
|
||||
dev_dbg(dev, "enabled CS%u\n", csindex);
|
||||
|
||||
/* Next set up the XMEMC */
|
||||
slowcfg = 0;
|
||||
fastcfg = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(xmem_props); i++) {
|
||||
const struct ebi2_xmem_prop *xp = &xmem_props[i];
|
||||
|
||||
/* All are regular u32 values */
|
||||
ret = of_property_read_u32(np, xp->prop, &val);
|
||||
if (ret) {
|
||||
dev_dbg(dev, "could not read %s for CS%d\n",
|
||||
xp->prop, csindex);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* First check boolean props */
|
||||
if (xp->max == 1 && val) {
|
||||
if (xp->slowreg)
|
||||
slowcfg |= BIT(xp->shift);
|
||||
else
|
||||
fastcfg |= BIT(xp->shift);
|
||||
dev_dbg(dev, "set %s flag\n", xp->prop);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We're dealing with an u32 */
|
||||
if (val > xp->max) {
|
||||
dev_err(dev,
|
||||
"too high value for %s: %u, capped at %u\n",
|
||||
xp->prop, val, xp->max);
|
||||
val = xp->max;
|
||||
}
|
||||
if (xp->slowreg)
|
||||
slowcfg |= (val << xp->shift);
|
||||
else
|
||||
fastcfg |= (val << xp->shift);
|
||||
dev_dbg(dev, "set %s to %u\n", xp->prop, val);
|
||||
}
|
||||
|
||||
dev_info(dev, "CS%u: SLOW CFG 0x%08x, FAST CFG 0x%08x\n",
|
||||
csindex, slowcfg, fastcfg);
|
||||
|
||||
if (slowcfg)
|
||||
writel(slowcfg, ebi2_xmem + csd->slow_cfg);
|
||||
if (fastcfg)
|
||||
writel(fastcfg, ebi2_xmem + csd->fast_cfg);
|
||||
}
|
||||
|
||||
static int qcom_ebi2_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *child;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
void __iomem *ebi2_base;
|
||||
void __iomem *ebi2_xmem;
|
||||
struct clk *ebi2xclk;
|
||||
struct clk *ebi2clk;
|
||||
bool have_children = false;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ebi2xclk = devm_clk_get(dev, "ebi2x");
|
||||
if (IS_ERR(ebi2xclk))
|
||||
return PTR_ERR(ebi2xclk);
|
||||
|
||||
ret = clk_prepare_enable(ebi2xclk);
|
||||
if (ret) {
|
||||
dev_err(dev, "could not enable EBI2X clk (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ebi2clk = devm_clk_get(dev, "ebi2");
|
||||
if (IS_ERR(ebi2clk)) {
|
||||
ret = PTR_ERR(ebi2clk);
|
||||
goto err_disable_2x_clk;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(ebi2clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "could not enable EBI2 clk\n");
|
||||
goto err_disable_2x_clk;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
ebi2_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(ebi2_base)) {
|
||||
ret = PTR_ERR(ebi2_base);
|
||||
goto err_disable_clk;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
ebi2_xmem = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(ebi2_xmem)) {
|
||||
ret = PTR_ERR(ebi2_xmem);
|
||||
goto err_disable_clk;
|
||||
}
|
||||
|
||||
/* Allegedly this turns the power save mode off */
|
||||
writel(0UL, ebi2_xmem + EBI2_XMEM_CFG);
|
||||
|
||||
/* Disable all chipselects */
|
||||
val = readl(ebi2_base);
|
||||
val &= ~EBI2_CSN_MASK;
|
||||
writel(val, ebi2_base);
|
||||
|
||||
/* Walk over the child nodes and see what chipselects we use */
|
||||
for_each_available_child_of_node(np, child) {
|
||||
u32 csindex;
|
||||
|
||||
/* Figure out the chipselect */
|
||||
ret = of_property_read_u32(child, "reg", &csindex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (csindex > 5) {
|
||||
dev_err(dev,
|
||||
"invalid chipselect %u, we only support 0-5\n",
|
||||
csindex);
|
||||
continue;
|
||||
}
|
||||
|
||||
qcom_ebi2_setup_chipselect(child,
|
||||
dev,
|
||||
ebi2_base,
|
||||
ebi2_xmem,
|
||||
csindex);
|
||||
|
||||
/* We have at least one child */
|
||||
have_children = true;
|
||||
}
|
||||
|
||||
if (have_children)
|
||||
return of_platform_default_populate(np, NULL, dev);
|
||||
return 0;
|
||||
|
||||
err_disable_clk:
|
||||
clk_disable_unprepare(ebi2clk);
|
||||
err_disable_2x_clk:
|
||||
clk_disable_unprepare(ebi2xclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id qcom_ebi2_of_match[] = {
|
||||
{ .compatible = "qcom,msm8660-ebi2", },
|
||||
{ .compatible = "qcom,apq8060-ebi2", },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver qcom_ebi2_driver = {
|
||||
.probe = qcom_ebi2_probe,
|
||||
.driver = {
|
||||
.name = "qcom-ebi2",
|
||||
.of_match_table = qcom_ebi2_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(qcom_ebi2_driver);
|
||||
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
|
||||
MODULE_DESCRIPTION("Qualcomm EBI2 driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -15,24 +15,6 @@
|
|||
#include <linux/pm_clock.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
static int tegra_aconnect_add_clock(struct device *dev, char *name)
|
||||
{
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
clk = clk_get(dev, name);
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "%s clock not found\n", name);
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
ret = pm_clk_add_clk(dev, clk);
|
||||
if (ret)
|
||||
clk_put(clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_aconnect_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
|
@ -44,11 +26,11 @@ static int tegra_aconnect_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tegra_aconnect_add_clock(&pdev->dev, "ape");
|
||||
ret = of_pm_clk_add_clk(&pdev->dev, "ape");
|
||||
if (ret)
|
||||
goto clk_destroy;
|
||||
|
||||
ret = tegra_aconnect_add_clock(&pdev->dev, "apb2ape");
|
||||
ret = of_pm_clk_add_clk(&pdev->dev, "apb2ape");
|
||||
if (ret)
|
||||
goto clk_destroy;
|
||||
|
||||
|
|
|
@ -20,6 +20,76 @@ static const struct coreclk_ratio orion_coreclk_ratios[] __initconst = {
|
|||
{ .id = 0, .name = "ddrclk", }
|
||||
};
|
||||
|
||||
/*
|
||||
* Orion 5181
|
||||
*/
|
||||
|
||||
#define SAR_MV88F5181_TCLK_FREQ 8
|
||||
#define SAR_MV88F5181_TCLK_FREQ_MASK 0x3
|
||||
|
||||
static u32 __init mv88f5181_get_tclk_freq(void __iomem *sar)
|
||||
{
|
||||
u32 opt = (readl(sar) >> SAR_MV88F5181_TCLK_FREQ) &
|
||||
SAR_MV88F5181_TCLK_FREQ_MASK;
|
||||
if (opt == 0)
|
||||
return 133333333;
|
||||
else if (opt == 1)
|
||||
return 150000000;
|
||||
else if (opt == 2)
|
||||
return 166666667;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SAR_MV88F5181_CPU_FREQ 4
|
||||
#define SAR_MV88F5181_CPU_FREQ_MASK 0xf
|
||||
|
||||
static u32 __init mv88f5181_get_cpu_freq(void __iomem *sar)
|
||||
{
|
||||
u32 opt = (readl(sar) >> SAR_MV88F5181_CPU_FREQ) &
|
||||
SAR_MV88F5181_CPU_FREQ_MASK;
|
||||
if (opt == 0)
|
||||
return 333333333;
|
||||
else if (opt == 1 || opt == 2)
|
||||
return 400000000;
|
||||
else if (opt == 3)
|
||||
return 500000000;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init mv88f5181_get_clk_ratio(void __iomem *sar, int id,
|
||||
int *mult, int *div)
|
||||
{
|
||||
u32 opt = (readl(sar) >> SAR_MV88F5181_CPU_FREQ) &
|
||||
SAR_MV88F5181_CPU_FREQ_MASK;
|
||||
if (opt == 0 || opt == 1) {
|
||||
*mult = 1;
|
||||
*div = 2;
|
||||
} else if (opt == 2 || opt == 3) {
|
||||
*mult = 1;
|
||||
*div = 3;
|
||||
} else {
|
||||
*mult = 0;
|
||||
*div = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct coreclk_soc_desc mv88f5181_coreclks = {
|
||||
.get_tclk_freq = mv88f5181_get_tclk_freq,
|
||||
.get_cpu_freq = mv88f5181_get_cpu_freq,
|
||||
.get_clk_ratio = mv88f5181_get_clk_ratio,
|
||||
.ratios = orion_coreclk_ratios,
|
||||
.num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
|
||||
};
|
||||
|
||||
static void __init mv88f5181_clk_init(struct device_node *np)
|
||||
{
|
||||
return mvebu_coreclk_setup(np, &mv88f5181_coreclks);
|
||||
}
|
||||
|
||||
CLK_OF_DECLARE(mv88f5181_clk, "marvell,mv88f5181-core-clock", mv88f5181_clk_init);
|
||||
|
||||
/*
|
||||
* Orion 5182
|
||||
*/
|
||||
|
|
|
@ -361,7 +361,7 @@ config CLKSRC_METAG_GENERIC
|
|||
|
||||
config CLKSRC_EXYNOS_MCT
|
||||
bool "Exynos multi core timer driver" if COMPILE_TEST
|
||||
depends on ARM
|
||||
depends on ARM || ARM64
|
||||
help
|
||||
Support for Multi Core Timer controller on Exynos SoCs.
|
||||
|
||||
|
|
|
@ -223,6 +223,7 @@ static u64 notrace exynos4_read_sched_clock(void)
|
|||
return exynos4_read_count_32();
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ARM)
|
||||
static struct delay_timer exynos4_delay_timer;
|
||||
|
||||
static cycles_t exynos4_read_current_timer(void)
|
||||
|
@ -231,14 +232,17 @@ static cycles_t exynos4_read_current_timer(void)
|
|||
"cycles_t needs to move to 32-bit for ARM64 usage");
|
||||
return exynos4_read_count_32();
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init exynos4_clocksource_init(void)
|
||||
{
|
||||
exynos4_mct_frc_start();
|
||||
|
||||
#if defined(CONFIG_ARM)
|
||||
exynos4_delay_timer.read_current_timer = &exynos4_read_current_timer;
|
||||
exynos4_delay_timer.freq = clk_rate;
|
||||
register_current_timer_delay(&exynos4_delay_timer);
|
||||
#endif
|
||||
|
||||
if (clocksource_register_hz(&mct_frc, clk_rate))
|
||||
panic("%s: can't register clocksource\n", mct_frc.name);
|
||||
|
|
|
@ -209,5 +209,6 @@ config HAVE_ARM_SMCCC
|
|||
source "drivers/firmware/broadcom/Kconfig"
|
||||
source "drivers/firmware/google/Kconfig"
|
||||
source "drivers/firmware/efi/Kconfig"
|
||||
source "drivers/firmware/meson/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -22,6 +22,7 @@ obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o
|
|||
CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a
|
||||
|
||||
obj-y += broadcom/
|
||||
obj-y += meson/
|
||||
obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
|
||||
obj-$(CONFIG_EFI) += efi/
|
||||
obj-$(CONFIG_UEFI_CPER) += efi/
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# Amlogic Secure Monitor driver
|
||||
#
|
||||
config MESON_SM
|
||||
bool
|
||||
default ARCH_MESON
|
||||
depends on ARM64_4K_PAGES
|
||||
help
|
||||
Say y here to enable the Amlogic secure monitor driver
|
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_MESON_SM) += meson_sm.o
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* Amlogic Secure Monitor driver
|
||||
*
|
||||
* Copyright (C) 2016 Endless Mobile, Inc.
|
||||
* Author: Carlo Caione <carlo@endlessm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "meson-sm: " fmt
|
||||
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#include <linux/firmware/meson/meson_sm.h>
|
||||
|
||||
struct meson_sm_cmd {
|
||||
unsigned int index;
|
||||
u32 smc_id;
|
||||
};
|
||||
#define CMD(d, s) { .index = (d), .smc_id = (s), }
|
||||
|
||||
struct meson_sm_chip {
|
||||
unsigned int shmem_size;
|
||||
u32 cmd_shmem_in_base;
|
||||
u32 cmd_shmem_out_base;
|
||||
struct meson_sm_cmd cmd[];
|
||||
};
|
||||
|
||||
struct meson_sm_chip gxbb_chip = {
|
||||
.shmem_size = SZ_4K,
|
||||
.cmd_shmem_in_base = 0x82000020,
|
||||
.cmd_shmem_out_base = 0x82000021,
|
||||
.cmd = {
|
||||
CMD(SM_EFUSE_READ, 0x82000030),
|
||||
CMD(SM_EFUSE_WRITE, 0x82000031),
|
||||
CMD(SM_EFUSE_USER_MAX, 0x82000033),
|
||||
{ /* sentinel */ },
|
||||
},
|
||||
};
|
||||
|
||||
struct meson_sm_firmware {
|
||||
const struct meson_sm_chip *chip;
|
||||
void __iomem *sm_shmem_in_base;
|
||||
void __iomem *sm_shmem_out_base;
|
||||
};
|
||||
|
||||
static struct meson_sm_firmware fw;
|
||||
|
||||
static u32 meson_sm_get_cmd(const struct meson_sm_chip *chip,
|
||||
unsigned int cmd_index)
|
||||
{
|
||||
const struct meson_sm_cmd *cmd = chip->cmd;
|
||||
|
||||
while (cmd->smc_id && cmd->index != cmd_index)
|
||||
cmd++;
|
||||
|
||||
return cmd->smc_id;
|
||||
}
|
||||
|
||||
static u32 __meson_sm_call(u32 cmd, u32 arg0, u32 arg1, u32 arg2,
|
||||
u32 arg3, u32 arg4)
|
||||
{
|
||||
struct arm_smccc_res res;
|
||||
|
||||
arm_smccc_smc(cmd, arg0, arg1, arg2, arg3, arg4, 0, 0, &res);
|
||||
return res.a0;
|
||||
}
|
||||
|
||||
static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size)
|
||||
{
|
||||
u32 sm_phy_base;
|
||||
|
||||
sm_phy_base = __meson_sm_call(cmd_shmem, 0, 0, 0, 0, 0);
|
||||
if (!sm_phy_base)
|
||||
return 0;
|
||||
|
||||
return ioremap_cache(sm_phy_base, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* meson_sm_call - generic SMC32 call to the secure-monitor
|
||||
*
|
||||
* @cmd_index: Index of the SMC32 function ID
|
||||
* @ret: Returned value
|
||||
* @arg0: SMC32 Argument 0
|
||||
* @arg1: SMC32 Argument 1
|
||||
* @arg2: SMC32 Argument 2
|
||||
* @arg3: SMC32 Argument 3
|
||||
* @arg4: SMC32 Argument 4
|
||||
*
|
||||
* Return: 0 on success, a negative value on error
|
||||
*/
|
||||
int meson_sm_call(unsigned int cmd_index, u32 *ret, u32 arg0,
|
||||
u32 arg1, u32 arg2, u32 arg3, u32 arg4)
|
||||
{
|
||||
u32 cmd, lret;
|
||||
|
||||
if (!fw.chip)
|
||||
return -ENOENT;
|
||||
|
||||
cmd = meson_sm_get_cmd(fw.chip, cmd_index);
|
||||
if (!cmd)
|
||||
return -EINVAL;
|
||||
|
||||
lret = __meson_sm_call(cmd, arg0, arg1, arg2, arg3, arg4);
|
||||
|
||||
if (ret)
|
||||
*ret = lret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(meson_sm_call);
|
||||
|
||||
/**
|
||||
* meson_sm_call_read - retrieve data from secure-monitor
|
||||
*
|
||||
* @buffer: Buffer to store the retrieved data
|
||||
* @cmd_index: Index of the SMC32 function ID
|
||||
* @arg0: SMC32 Argument 0
|
||||
* @arg1: SMC32 Argument 1
|
||||
* @arg2: SMC32 Argument 2
|
||||
* @arg3: SMC32 Argument 3
|
||||
* @arg4: SMC32 Argument 4
|
||||
*
|
||||
* Return: size of read data on success, a negative value on error
|
||||
*/
|
||||
int meson_sm_call_read(void *buffer, unsigned int cmd_index, u32 arg0,
|
||||
u32 arg1, u32 arg2, u32 arg3, u32 arg4)
|
||||
{
|
||||
u32 size;
|
||||
|
||||
if (!fw.chip)
|
||||
return -ENOENT;
|
||||
|
||||
if (!fw.chip->cmd_shmem_out_base)
|
||||
return -EINVAL;
|
||||
|
||||
if (meson_sm_call(cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!size || size > fw.chip->shmem_size)
|
||||
return -EINVAL;
|
||||
|
||||
if (buffer)
|
||||
memcpy(buffer, fw.sm_shmem_out_base, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
EXPORT_SYMBOL(meson_sm_call_read);
|
||||
|
||||
/**
|
||||
* meson_sm_call_write - send data to secure-monitor
|
||||
*
|
||||
* @buffer: Buffer containing data to send
|
||||
* @size: Size of the data to send
|
||||
* @cmd_index: Index of the SMC32 function ID
|
||||
* @arg0: SMC32 Argument 0
|
||||
* @arg1: SMC32 Argument 1
|
||||
* @arg2: SMC32 Argument 2
|
||||
* @arg3: SMC32 Argument 3
|
||||
* @arg4: SMC32 Argument 4
|
||||
*
|
||||
* Return: size of sent data on success, a negative value on error
|
||||
*/
|
||||
int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index,
|
||||
u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
|
||||
{
|
||||
u32 written;
|
||||
|
||||
if (!fw.chip)
|
||||
return -ENOENT;
|
||||
|
||||
if (size > fw.chip->shmem_size)
|
||||
return -EINVAL;
|
||||
|
||||
if (!fw.chip->cmd_shmem_in_base)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(fw.sm_shmem_in_base, buffer, size);
|
||||
|
||||
if (meson_sm_call(cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!written)
|
||||
return -EINVAL;
|
||||
|
||||
return written;
|
||||
}
|
||||
EXPORT_SYMBOL(meson_sm_call_write);
|
||||
|
||||
static const struct of_device_id meson_sm_ids[] = {
|
||||
{ .compatible = "amlogic,meson-gxbb-sm", .data = &gxbb_chip },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
int __init meson_sm_init(void)
|
||||
{
|
||||
const struct meson_sm_chip *chip;
|
||||
const struct of_device_id *matched_np;
|
||||
struct device_node *np;
|
||||
|
||||
np = of_find_matching_node_and_match(NULL, meson_sm_ids, &matched_np);
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
chip = matched_np->data;
|
||||
if (!chip) {
|
||||
pr_err("unable to setup secure-monitor data\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (chip->cmd_shmem_in_base) {
|
||||
fw.sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base,
|
||||
chip->shmem_size);
|
||||
if (WARN_ON(!fw.sm_shmem_in_base))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (chip->cmd_shmem_out_base) {
|
||||
fw.sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base,
|
||||
chip->shmem_size);
|
||||
if (WARN_ON(!fw.sm_shmem_out_base))
|
||||
goto out_in_base;
|
||||
}
|
||||
|
||||
fw.chip = chip;
|
||||
pr_info("secure-monitor enabled\n");
|
||||
|
||||
return 0;
|
||||
|
||||
out_in_base:
|
||||
iounmap(fw.sm_shmem_in_base);
|
||||
out:
|
||||
return -EINVAL;
|
||||
}
|
||||
device_initcall(meson_sm_init);
|
|
@ -1,4 +1,7 @@
|
|||
/* Copyright (c) 2010,2015, The Linux Foundation. All rights reserved.
|
||||
/*
|
||||
* Qualcomm SCM driver
|
||||
*
|
||||
* Copyright (c) 2010,2015, The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2015 Linaro Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -12,7 +15,7 @@
|
|||
*
|
||||
*/
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
@ -376,8 +379,6 @@ static const struct of_device_id qcom_scm_dt_match[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, qcom_scm_dt_match);
|
||||
|
||||
static struct platform_driver qcom_scm_driver = {
|
||||
.driver = {
|
||||
.name = "qcom_scm",
|
||||
|
@ -414,14 +415,4 @@ static int __init qcom_scm_init(void)
|
|||
|
||||
return platform_driver_register(&qcom_scm_driver);
|
||||
}
|
||||
|
||||
subsys_initcall(qcom_scm_init);
|
||||
|
||||
static void __exit qcom_scm_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&qcom_scm_driver);
|
||||
}
|
||||
module_exit(qcom_scm_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm SCM driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#define DRIVER_NAME "meson-ir"
|
||||
|
||||
/* valid on all Meson platforms */
|
||||
#define IR_DEC_LDR_ACTIVE 0x00
|
||||
#define IR_DEC_LDR_IDLE 0x04
|
||||
#define IR_DEC_LDR_REPEAT 0x08
|
||||
|
@ -32,12 +33,21 @@
|
|||
#define IR_DEC_FRAME 0x14
|
||||
#define IR_DEC_STATUS 0x18
|
||||
#define IR_DEC_REG1 0x1c
|
||||
/* only available on Meson 8b and newer */
|
||||
#define IR_DEC_REG2 0x20
|
||||
|
||||
#define REG0_RATE_MASK (BIT(11) - 1)
|
||||
|
||||
#define REG1_MODE_MASK (BIT(7) | BIT(8))
|
||||
#define REG1_MODE_NEC (0 << 7)
|
||||
#define REG1_MODE_GENERAL (2 << 7)
|
||||
#define DECODE_MODE_NEC 0x0
|
||||
#define DECODE_MODE_RAW 0x2
|
||||
|
||||
/* Meson 6b uses REG1 to configure the mode */
|
||||
#define REG1_MODE_MASK GENMASK(8, 7)
|
||||
#define REG1_MODE_SHIFT 7
|
||||
|
||||
/* Meson 8b / GXBB use REG2 to configure the mode */
|
||||
#define REG2_MODE_MASK GENMASK(3, 0)
|
||||
#define REG2_MODE_SHIFT 0
|
||||
|
||||
#define REG1_TIME_IV_SHIFT 16
|
||||
#define REG1_TIME_IV_MASK ((BIT(13) - 1) << REG1_TIME_IV_SHIFT)
|
||||
|
@ -158,8 +168,15 @@ static int meson_ir_probe(struct platform_device *pdev)
|
|||
/* Reset the decoder */
|
||||
meson_ir_set_mask(ir, IR_DEC_REG1, REG1_RESET, REG1_RESET);
|
||||
meson_ir_set_mask(ir, IR_DEC_REG1, REG1_RESET, 0);
|
||||
/* Set general operation mode */
|
||||
meson_ir_set_mask(ir, IR_DEC_REG1, REG1_MODE_MASK, REG1_MODE_GENERAL);
|
||||
|
||||
/* Set general operation mode (= raw/software decoding) */
|
||||
if (of_device_is_compatible(node, "amlogic,meson6-ir"))
|
||||
meson_ir_set_mask(ir, IR_DEC_REG1, REG1_MODE_MASK,
|
||||
DECODE_MODE_RAW << REG1_MODE_SHIFT);
|
||||
else
|
||||
meson_ir_set_mask(ir, IR_DEC_REG2, REG2_MODE_MASK,
|
||||
DECODE_MODE_RAW << REG2_MODE_SHIFT);
|
||||
|
||||
/* Set rate */
|
||||
meson_ir_set_mask(ir, IR_DEC_REG0, REG0_RATE_MASK, MESON_TRATE - 1);
|
||||
/* IRQ on rising and falling edges */
|
||||
|
@ -197,6 +214,8 @@ static int meson_ir_remove(struct platform_device *pdev)
|
|||
|
||||
static const struct of_device_id meson_ir_match[] = {
|
||||
{ .compatible = "amlogic,meson6-ir" },
|
||||
{ .compatible = "amlogic,meson8b-ir" },
|
||||
{ .compatible = "amlogic,meson-gxbb-ir" },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
|
|
@ -410,10 +410,7 @@ static int at91sam9_ebi_init(struct at91_ebi *ebi)
|
|||
|
||||
field.reg = AT91SAM9_SMC_MODE(AT91SAM9_SMC_GENERIC);
|
||||
fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
|
||||
if (IS_ERR(fields->mode))
|
||||
return PTR_ERR(fields->mode);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(fields->mode);
|
||||
}
|
||||
|
||||
static int sama5d3_ebi_init(struct at91_ebi *ebi)
|
||||
|
@ -441,10 +438,7 @@ static int sama5d3_ebi_init(struct at91_ebi *ebi)
|
|||
|
||||
field.reg = SAMA5_SMC_MODE(SAMA5_SMC_GENERIC);
|
||||
fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
|
||||
if (IS_ERR(fields->mode))
|
||||
return PTR_ERR(fields->mode);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(fields->mode);
|
||||
}
|
||||
|
||||
static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np,
|
||||
|
|
|
@ -53,12 +53,10 @@ static const struct of_device_id atmel_ramc_of_match[] = {
|
|||
|
||||
static int atmel_ramc_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
const struct at91_ramc_caps *caps;
|
||||
struct clk *clk;
|
||||
|
||||
match = of_match_device(atmel_ramc_of_match, &pdev->dev);
|
||||
caps = match->data;
|
||||
caps = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
if (caps->has_ddrck) {
|
||||
clk = devm_clk_get(&pdev->dev, "ddrck");
|
||||
|
|
|
@ -350,8 +350,8 @@ static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
|
|||
return (time_ps + tick_ps - 1) / tick_ps;
|
||||
}
|
||||
|
||||
unsigned int gpmc_clk_ticks_to_ns(unsigned ticks, int cs,
|
||||
enum gpmc_clk_domain cd)
|
||||
static unsigned int gpmc_clk_ticks_to_ns(unsigned int ticks, int cs,
|
||||
enum gpmc_clk_domain cd)
|
||||
{
|
||||
return ticks * gpmc_get_clk_period(cs, cd) / 1000;
|
||||
}
|
||||
|
@ -2143,9 +2143,7 @@ err_child_fail:
|
|||
ret = -ENODEV;
|
||||
|
||||
err_cs:
|
||||
if (waitpin_desc)
|
||||
gpiochip_free_own_desc(waitpin_desc);
|
||||
|
||||
gpiochip_free_own_desc(waitpin_desc);
|
||||
err:
|
||||
gpmc_cs_free(cs);
|
||||
|
||||
|
@ -2265,7 +2263,7 @@ static int gpmc_gpio_init(struct gpmc_device *gpmc)
|
|||
gpmc->gpio_chip.get = gpmc_gpio_get;
|
||||
gpmc->gpio_chip.base = -1;
|
||||
|
||||
ret = gpiochip_add(&gpmc->gpio_chip);
|
||||
ret = devm_gpiochip_add_data(gpmc->dev, &gpmc->gpio_chip, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(gpmc->dev, "could not register gpio chip: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -2274,11 +2272,6 @@ static int gpmc_gpio_init(struct gpmc_device *gpmc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void gpmc_gpio_exit(struct gpmc_device *gpmc)
|
||||
{
|
||||
gpiochip_remove(&gpmc->gpio_chip);
|
||||
}
|
||||
|
||||
static int gpmc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int rc;
|
||||
|
@ -2365,15 +2358,13 @@ static int gpmc_probe(struct platform_device *pdev)
|
|||
rc = gpmc_setup_irq(gpmc);
|
||||
if (rc) {
|
||||
dev_err(gpmc->dev, "gpmc_setup_irq failed\n");
|
||||
goto setup_irq_failed;
|
||||
goto gpio_init_failed;
|
||||
}
|
||||
|
||||
gpmc_probe_dt_children(pdev);
|
||||
|
||||
return 0;
|
||||
|
||||
setup_irq_failed:
|
||||
gpmc_gpio_exit(gpmc);
|
||||
gpio_init_failed:
|
||||
gpmc_mem_exit();
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
|
@ -2387,7 +2378,6 @@ static int gpmc_remove(struct platform_device *pdev)
|
|||
struct gpmc_device *gpmc = platform_get_drvdata(pdev);
|
||||
|
||||
gpmc_free_irq(gpmc);
|
||||
gpmc_gpio_exit(gpmc);
|
||||
gpmc_mem_exit();
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
|
|
@ -101,4 +101,14 @@ config NVMEM_VF610_OCOTP
|
|||
This driver can also be build as a module. If so, the module will
|
||||
be called nvmem-vf610-ocotp.
|
||||
|
||||
config MESON_EFUSE
|
||||
tristate "Amlogic eFuse Support"
|
||||
depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM
|
||||
help
|
||||
This is a driver to retrieve specific values from the eFuse found on
|
||||
the Amlogic Meson SoCs.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called nvmem_meson_efuse.
|
||||
|
||||
endif
|
||||
|
|
|
@ -22,3 +22,5 @@ obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o
|
|||
nvmem_sunxi_sid-y := sunxi_sid.o
|
||||
obj-$(CONFIG_NVMEM_VF610_OCOTP) += nvmem-vf610-ocotp.o
|
||||
nvmem-vf610-ocotp-y := vf610-ocotp.o
|
||||
obj-$(CONFIG_MESON_EFUSE) += nvmem_meson_efuse.o
|
||||
nvmem_meson_efuse-y := meson-efuse.o
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Amlogic eFuse Driver
|
||||
*
|
||||
* Copyright (c) 2016 Endless Computers, Inc.
|
||||
* Author: Carlo Caione <carlo@endlessm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/nvmem-provider.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/firmware/meson/meson_sm.h>
|
||||
|
||||
static int meson_efuse_read(void *context, unsigned int offset,
|
||||
void *val, size_t bytes)
|
||||
{
|
||||
u8 *buf = val;
|
||||
int ret;
|
||||
|
||||
ret = meson_sm_call_read(buf, SM_EFUSE_READ, offset,
|
||||
bytes, 0, 0, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nvmem_config econfig = {
|
||||
.name = "meson-efuse",
|
||||
.owner = THIS_MODULE,
|
||||
.stride = 1,
|
||||
.word_size = 1,
|
||||
.read_only = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id meson_efuse_match[] = {
|
||||
{ .compatible = "amlogic,meson-gxbb-efuse", },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_efuse_match);
|
||||
|
||||
static int meson_efuse_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct nvmem_device *nvmem;
|
||||
unsigned int size;
|
||||
|
||||
if (meson_sm_call(SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
econfig.dev = &pdev->dev;
|
||||
econfig.reg_read = meson_efuse_read;
|
||||
econfig.size = size;
|
||||
|
||||
nvmem = nvmem_register(&econfig);
|
||||
if (IS_ERR(nvmem))
|
||||
return PTR_ERR(nvmem);
|
||||
|
||||
platform_set_drvdata(pdev, nvmem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_efuse_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct nvmem_device *nvmem = platform_get_drvdata(pdev);
|
||||
|
||||
return nvmem_unregister(nvmem);
|
||||
}
|
||||
|
||||
static struct platform_driver meson_efuse_driver = {
|
||||
.probe = meson_efuse_probe,
|
||||
.remove = meson_efuse_remove,
|
||||
.driver = {
|
||||
.name = "meson-efuse",
|
||||
.of_match_table = meson_efuse_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(meson_efuse_driver);
|
||||
|
||||
MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>");
|
||||
MODULE_DESCRIPTION("Amlogic Meson NVMEM driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -12,4 +12,11 @@ config ARM_PMU
|
|||
Say y if you want to use CPU performance monitors on ARM-based
|
||||
systems.
|
||||
|
||||
config XGENE_PMU
|
||||
depends on PERF_EVENTS && ARCH_XGENE
|
||||
bool "APM X-Gene SoC PMU"
|
||||
default n
|
||||
help
|
||||
Say y if you want to use APM X-Gene SoC performance monitors.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
obj-$(CONFIG_ARM_PMU) += arm_pmu.o
|
||||
obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -64,11 +64,11 @@ static int orion_mpp_ctrl_set(unsigned pid, unsigned long config)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define V(f5181l, f5182, f5281) \
|
||||
((f5181l << 0) | (f5182 << 1) | (f5281 << 2))
|
||||
#define V(f5181, f5182, f5281) \
|
||||
((f5181 << 0) | (f5182 << 1) | (f5281 << 2))
|
||||
|
||||
enum orion_variant {
|
||||
V_5181L = V(1, 0, 0),
|
||||
V_5181 = V(1, 0, 0),
|
||||
V_5182 = V(0, 1, 0),
|
||||
V_5281 = V(0, 0, 1),
|
||||
V_ALL = V(1, 1, 1),
|
||||
|
@ -103,13 +103,13 @@ static struct mvebu_mpp_mode orion_mpp_modes[] = {
|
|||
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL),
|
||||
MPP_VAR_FUNCTION(0x2, "pci", "req5", V_ALL),
|
||||
MPP_VAR_FUNCTION(0x4, "nand", "re0", V_5182 | V_5281),
|
||||
MPP_VAR_FUNCTION(0x5, "pci-1", "clk", V_5181L),
|
||||
MPP_VAR_FUNCTION(0x5, "pci-1", "clk", V_5181),
|
||||
MPP_VAR_FUNCTION(0x5, "sata0", "act", V_5182)),
|
||||
MPP_MODE(7,
|
||||
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL),
|
||||
MPP_VAR_FUNCTION(0x2, "pci", "gnt5", V_ALL),
|
||||
MPP_VAR_FUNCTION(0x4, "nand", "we0", V_5182 | V_5281),
|
||||
MPP_VAR_FUNCTION(0x5, "pci-1", "clk", V_5181L),
|
||||
MPP_VAR_FUNCTION(0x5, "pci-1", "clk", V_5181),
|
||||
MPP_VAR_FUNCTION(0x5, "sata1", "act", V_5182)),
|
||||
MPP_MODE(8,
|
||||
MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL),
|
||||
|
@ -165,7 +165,7 @@ static struct mvebu_mpp_ctrl orion_mpp_controls[] = {
|
|||
MPP_FUNC_CTRL(0, 19, NULL, orion_mpp_ctrl),
|
||||
};
|
||||
|
||||
static struct pinctrl_gpio_range mv88f5181l_gpio_ranges[] = {
|
||||
static struct pinctrl_gpio_range mv88f5181_gpio_ranges[] = {
|
||||
MPP_GPIO_RANGE(0, 0, 0, 16),
|
||||
};
|
||||
|
||||
|
@ -177,14 +177,14 @@ static struct pinctrl_gpio_range mv88f5281_gpio_ranges[] = {
|
|||
MPP_GPIO_RANGE(0, 0, 0, 16),
|
||||
};
|
||||
|
||||
static struct mvebu_pinctrl_soc_info mv88f5181l_info = {
|
||||
.variant = V_5181L,
|
||||
static struct mvebu_pinctrl_soc_info mv88f5181_info = {
|
||||
.variant = V_5181,
|
||||
.controls = orion_mpp_controls,
|
||||
.ncontrols = ARRAY_SIZE(orion_mpp_controls),
|
||||
.modes = orion_mpp_modes,
|
||||
.nmodes = ARRAY_SIZE(orion_mpp_modes),
|
||||
.gpioranges = mv88f5181l_gpio_ranges,
|
||||
.ngpioranges = ARRAY_SIZE(mv88f5181l_gpio_ranges),
|
||||
.gpioranges = mv88f5181_gpio_ranges,
|
||||
.ngpioranges = ARRAY_SIZE(mv88f5181_gpio_ranges),
|
||||
};
|
||||
|
||||
static struct mvebu_pinctrl_soc_info mv88f5182_info = {
|
||||
|
@ -212,7 +212,8 @@ static struct mvebu_pinctrl_soc_info mv88f5281_info = {
|
|||
* muxing, they are identical.
|
||||
*/
|
||||
static const struct of_device_id orion_pinctrl_of_match[] = {
|
||||
{ .compatible = "marvell,88f5181l-pinctrl", .data = &mv88f5181l_info },
|
||||
{ .compatible = "marvell,88f5181-pinctrl", .data = &mv88f5181_info },
|
||||
{ .compatible = "marvell,88f5181l-pinctrl", .data = &mv88f5181_info },
|
||||
{ .compatible = "marvell,88f5182-pinctrl", .data = &mv88f5182_info },
|
||||
{ .compatible = "marvell,88f5281-pinctrl", .data = &mv88f5281_info },
|
||||
{ }
|
||||
|
|
|
@ -14,9 +14,58 @@ menuconfig RESET_CONTROLLER
|
|||
|
||||
if RESET_CONTROLLER
|
||||
|
||||
config RESET_ATH79
|
||||
bool "AR71xx Reset Driver" if COMPILE_TEST
|
||||
default ATH79
|
||||
help
|
||||
This enables the ATH79 reset controller driver that supports the
|
||||
AR71xx SoC reset controller.
|
||||
|
||||
config RESET_BERLIN
|
||||
bool "Berlin Reset Driver" if COMPILE_TEST
|
||||
default ARCH_BERLIN
|
||||
help
|
||||
This enables the reset controller driver for Marvell Berlin SoCs.
|
||||
|
||||
config RESET_LPC18XX
|
||||
bool "LPC18xx/43xx Reset Driver" if COMPILE_TEST
|
||||
default ARCH_LPC18XX
|
||||
help
|
||||
This enables the reset controller driver for NXP LPC18xx/43xx SoCs.
|
||||
|
||||
config RESET_MESON
|
||||
bool "Meson Reset Driver" if COMPILE_TEST
|
||||
default ARCH_MESON
|
||||
help
|
||||
This enables the reset driver for Amlogic Meson SoCs.
|
||||
|
||||
config RESET_OXNAS
|
||||
bool
|
||||
|
||||
config RESET_PISTACHIO
|
||||
bool "Pistachio Reset Driver" if COMPILE_TEST
|
||||
default MACH_PISTACHIO
|
||||
help
|
||||
This enables the reset driver for ImgTec Pistachio SoCs.
|
||||
|
||||
config RESET_SOCFPGA
|
||||
bool "SoCFPGA Reset Driver" if COMPILE_TEST
|
||||
default ARCH_SOCFPGA
|
||||
help
|
||||
This enables the reset controller driver for Altera SoCFPGAs.
|
||||
|
||||
config RESET_STM32
|
||||
bool "STM32 Reset Driver" if COMPILE_TEST
|
||||
default ARCH_STM32
|
||||
help
|
||||
This enables the RCC reset controller driver for STM32 MCUs.
|
||||
|
||||
config RESET_SUNXI
|
||||
bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI
|
||||
default ARCH_SUNXI
|
||||
help
|
||||
This enables the reset driver for Allwinner SoCs.
|
||||
|
||||
config TI_SYSCON_RESET
|
||||
tristate "TI SYSCON Reset Driver"
|
||||
depends on HAS_IOMEM
|
||||
|
@ -27,6 +76,22 @@ config TI_SYSCON_RESET
|
|||
you wish to use the reset framework for such memory-mapped devices,
|
||||
say Y here. Otherwise, say N.
|
||||
|
||||
config RESET_UNIPHIER
|
||||
tristate "Reset controller driver for UniPhier SoCs"
|
||||
depends on ARCH_UNIPHIER || COMPILE_TEST
|
||||
depends on OF && MFD_SYSCON
|
||||
default ARCH_UNIPHIER
|
||||
help
|
||||
Support for reset controllers on UniPhier SoCs.
|
||||
Say Y if you want to control reset signals provided by System Control
|
||||
block, Media I/O block, Peripheral Block.
|
||||
|
||||
config RESET_ZYNQ
|
||||
bool "ZYNQ Reset Driver" if COMPILE_TEST
|
||||
default ARCH_ZYNQ
|
||||
help
|
||||
This enables the reset controller driver for Xilinx Zynq SoCs.
|
||||
|
||||
source "drivers/reset/sti/Kconfig"
|
||||
source "drivers/reset/hisilicon/Kconfig"
|
||||
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
obj-y += core.o
|
||||
obj-$(CONFIG_ARCH_LPC18XX) += reset-lpc18xx.o
|
||||
obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
|
||||
obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
|
||||
obj-$(CONFIG_MACH_PISTACHIO) += reset-pistachio.o
|
||||
obj-$(CONFIG_ARCH_MESON) += reset-meson.o
|
||||
obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
|
||||
obj-y += hisilicon/
|
||||
obj-$(CONFIG_ARCH_STI) += sti/
|
||||
obj-$(CONFIG_ARCH_HISI) += hisilicon/
|
||||
obj-$(CONFIG_ARCH_ZYNQ) += reset-zynq.o
|
||||
obj-$(CONFIG_ATH79) += reset-ath79.o
|
||||
obj-$(CONFIG_RESET_ATH79) += reset-ath79.o
|
||||
obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o
|
||||
obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
|
||||
obj-$(CONFIG_RESET_MESON) += reset-meson.o
|
||||
obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
|
||||
obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
|
||||
obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
|
||||
obj-$(CONFIG_RESET_STM32) += reset-stm32.o
|
||||
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
|
||||
obj-$(CONFIG_TI_SYSCON_RESET) += reset-ti-syscon.o
|
||||
obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
|
||||
obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
|
||||
|
|
|
@ -138,7 +138,8 @@ EXPORT_SYMBOL_GPL(devm_reset_controller_register);
|
|||
*/
|
||||
int reset_control_reset(struct reset_control *rstc)
|
||||
{
|
||||
if (WARN_ON(rstc->shared))
|
||||
if (WARN_ON(IS_ERR_OR_NULL(rstc)) ||
|
||||
WARN_ON(rstc->shared))
|
||||
return -EINVAL;
|
||||
|
||||
if (rstc->rcdev->ops->reset)
|
||||
|
@ -161,6 +162,9 @@ EXPORT_SYMBOL_GPL(reset_control_reset);
|
|||
*/
|
||||
int reset_control_assert(struct reset_control *rstc)
|
||||
{
|
||||
if (WARN_ON(IS_ERR_OR_NULL(rstc)))
|
||||
return -EINVAL;
|
||||
|
||||
if (!rstc->rcdev->ops->assert)
|
||||
return -ENOTSUPP;
|
||||
|
||||
|
@ -184,6 +188,9 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
|
|||
*/
|
||||
int reset_control_deassert(struct reset_control *rstc)
|
||||
{
|
||||
if (WARN_ON(IS_ERR_OR_NULL(rstc)))
|
||||
return -EINVAL;
|
||||
|
||||
if (!rstc->rcdev->ops->deassert)
|
||||
return -ENOTSUPP;
|
||||
|
||||
|
@ -204,6 +211,9 @@ EXPORT_SYMBOL_GPL(reset_control_deassert);
|
|||
*/
|
||||
int reset_control_status(struct reset_control *rstc)
|
||||
{
|
||||
if (WARN_ON(IS_ERR_OR_NULL(rstc)))
|
||||
return -EINVAL;
|
||||
|
||||
if (rstc->rcdev->ops->status)
|
||||
return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
config COMMON_RESET_HI6220
|
||||
tristate "Hi6220 Reset Driver"
|
||||
depends on (ARCH_HISI && RESET_CONTROLLER)
|
||||
depends on ARCH_HISI || COMPILE_TEST
|
||||
default ARCH_HISI
|
||||
help
|
||||
Build the Hisilicon Hi6220 reset driver.
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
struct socfpga_reset_data {
|
||||
spinlock_t lock;
|
||||
void __iomem *membase;
|
||||
u32 modrst_offset;
|
||||
struct reset_controller_dev rcdev;
|
||||
};
|
||||
|
||||
|
@ -45,9 +44,8 @@ static int socfpga_reset_assert(struct reset_controller_dev *rcdev,
|
|||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
|
||||
reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS));
|
||||
writel(reg | BIT(offset), data->membase + data->modrst_offset +
|
||||
(bank * NR_BANKS));
|
||||
reg = readl(data->membase + (bank * NR_BANKS));
|
||||
writel(reg | BIT(offset), data->membase + (bank * NR_BANKS));
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
|
||||
return 0;
|
||||
|
@ -67,9 +65,8 @@ static int socfpga_reset_deassert(struct reset_controller_dev *rcdev,
|
|||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
|
||||
reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS));
|
||||
writel(reg & ~BIT(offset), data->membase + data->modrst_offset +
|
||||
(bank * NR_BANKS));
|
||||
reg = readl(data->membase + (bank * NR_BANKS));
|
||||
writel(reg & ~BIT(offset), data->membase + (bank * NR_BANKS));
|
||||
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
|
||||
|
@ -85,7 +82,7 @@ static int socfpga_reset_status(struct reset_controller_dev *rcdev,
|
|||
int offset = id % BITS_PER_LONG;
|
||||
u32 reg;
|
||||
|
||||
reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS));
|
||||
reg = readl(data->membase + (bank * NR_BANKS));
|
||||
|
||||
return !(reg & BIT(offset));
|
||||
}
|
||||
|
@ -102,6 +99,7 @@ static int socfpga_reset_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
u32 modrst_offset;
|
||||
|
||||
/*
|
||||
* The binding was mainlined without the required property.
|
||||
|
@ -122,10 +120,11 @@ static int socfpga_reset_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(data->membase))
|
||||
return PTR_ERR(data->membase);
|
||||
|
||||
if (of_property_read_u32(np, "altr,modrst-offset", &data->modrst_offset)) {
|
||||
if (of_property_read_u32(np, "altr,modrst-offset", &modrst_offset)) {
|
||||
dev_warn(dev, "missing altr,modrst-offset property, assuming 0x10!\n");
|
||||
data->modrst_offset = 0x10;
|
||||
modrst_offset = 0x10;
|
||||
}
|
||||
data->membase += modrst_offset;
|
||||
|
||||
spin_lock_init(&data->lock);
|
||||
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (C) Maxime Coquelin 2015
|
||||
* Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
|
||||
* License terms: GNU General Public License (GPL), version 2
|
||||
*
|
||||
* Heavily based on sunxi driver from Maxime Ripard.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct stm32_reset_data {
|
||||
spinlock_t lock;
|
||||
void __iomem *membase;
|
||||
struct reset_controller_dev rcdev;
|
||||
};
|
||||
|
||||
static int stm32_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct stm32_reset_data *data = container_of(rcdev,
|
||||
struct stm32_reset_data,
|
||||
rcdev);
|
||||
int bank = id / BITS_PER_LONG;
|
||||
int offset = id % BITS_PER_LONG;
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
|
||||
reg = readl(data->membase + (bank * 4));
|
||||
writel(reg | BIT(offset), data->membase + (bank * 4));
|
||||
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct stm32_reset_data *data = container_of(rcdev,
|
||||
struct stm32_reset_data,
|
||||
rcdev);
|
||||
int bank = id / BITS_PER_LONG;
|
||||
int offset = id % BITS_PER_LONG;
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
|
||||
reg = readl(data->membase + (bank * 4));
|
||||
writel(reg & ~BIT(offset), data->membase + (bank * 4));
|
||||
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct reset_control_ops stm32_reset_ops = {
|
||||
.assert = stm32_reset_assert,
|
||||
.deassert = stm32_reset_deassert,
|
||||
};
|
||||
|
||||
static const struct of_device_id stm32_reset_dt_ids[] = {
|
||||
{ .compatible = "st,stm32-rcc", },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static int stm32_reset_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct stm32_reset_data *data;
|
||||
struct resource *res;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
data->membase = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(data->membase))
|
||||
return PTR_ERR(data->membase);
|
||||
|
||||
spin_lock_init(&data->lock);
|
||||
|
||||
data->rcdev.owner = THIS_MODULE;
|
||||
data->rcdev.nr_resets = resource_size(res) * 8;
|
||||
data->rcdev.ops = &stm32_reset_ops;
|
||||
data->rcdev.of_node = pdev->dev.of_node;
|
||||
|
||||
return devm_reset_controller_register(&pdev->dev, &data->rcdev);
|
||||
}
|
||||
|
||||
static struct platform_driver stm32_reset_driver = {
|
||||
.probe = stm32_reset_probe,
|
||||
.driver = {
|
||||
.name = "stm32-rcc-reset",
|
||||
.of_match_table = stm32_reset_dt_ids,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(stm32_reset_driver);
|
|
@ -0,0 +1,440 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Socionext Inc.
|
||||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset-controller.h>
|
||||
|
||||
struct uniphier_reset_data {
|
||||
unsigned int id;
|
||||
unsigned int reg;
|
||||
unsigned int bit;
|
||||
unsigned int flags;
|
||||
#define UNIPHIER_RESET_ACTIVE_LOW BIT(0)
|
||||
};
|
||||
|
||||
#define UNIPHIER_RESET_ID_END (unsigned int)(-1)
|
||||
|
||||
#define UNIPHIER_RESET_END \
|
||||
{ .id = UNIPHIER_RESET_ID_END }
|
||||
|
||||
#define UNIPHIER_RESET(_id, _reg, _bit) \
|
||||
{ \
|
||||
.id = (_id), \
|
||||
.reg = (_reg), \
|
||||
.bit = (_bit), \
|
||||
}
|
||||
|
||||
#define UNIPHIER_RESETX(_id, _reg, _bit) \
|
||||
{ \
|
||||
.id = (_id), \
|
||||
.reg = (_reg), \
|
||||
.bit = (_bit), \
|
||||
.flags = UNIPHIER_RESET_ACTIVE_LOW, \
|
||||
}
|
||||
|
||||
/* System reset data */
|
||||
#define UNIPHIER_SLD3_SYS_RESET_STDMAC(id) \
|
||||
UNIPHIER_RESETX((id), 0x2000, 10)
|
||||
|
||||
#define UNIPHIER_LD11_SYS_RESET_STDMAC(id) \
|
||||
UNIPHIER_RESETX((id), 0x200c, 8)
|
||||
|
||||
#define UNIPHIER_PRO4_SYS_RESET_GIO(id) \
|
||||
UNIPHIER_RESETX((id), 0x2000, 6)
|
||||
|
||||
#define UNIPHIER_LD20_SYS_RESET_GIO(id) \
|
||||
UNIPHIER_RESETX((id), 0x200c, 5)
|
||||
|
||||
#define UNIPHIER_PRO4_SYS_RESET_USB3(id, ch) \
|
||||
UNIPHIER_RESETX((id), 0x2000 + 0x4 * (ch), 17)
|
||||
|
||||
const struct uniphier_reset_data uniphier_sld3_sys_reset_data[] = {
|
||||
UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* Ether, HSC, MIO */
|
||||
UNIPHIER_RESET_END,
|
||||
};
|
||||
|
||||
const struct uniphier_reset_data uniphier_pro4_sys_reset_data[] = {
|
||||
UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* HSC, MIO, RLE */
|
||||
UNIPHIER_PRO4_SYS_RESET_GIO(12), /* Ether, SATA, USB3 */
|
||||
UNIPHIER_PRO4_SYS_RESET_USB3(14, 0),
|
||||
UNIPHIER_PRO4_SYS_RESET_USB3(15, 1),
|
||||
UNIPHIER_RESET_END,
|
||||
};
|
||||
|
||||
const struct uniphier_reset_data uniphier_pro5_sys_reset_data[] = {
|
||||
UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* HSC */
|
||||
UNIPHIER_PRO4_SYS_RESET_GIO(12), /* PCIe, USB3 */
|
||||
UNIPHIER_PRO4_SYS_RESET_USB3(14, 0),
|
||||
UNIPHIER_PRO4_SYS_RESET_USB3(15, 1),
|
||||
UNIPHIER_RESET_END,
|
||||
};
|
||||
|
||||
const struct uniphier_reset_data uniphier_pxs2_sys_reset_data[] = {
|
||||
UNIPHIER_SLD3_SYS_RESET_STDMAC(8), /* HSC, RLE */
|
||||
UNIPHIER_PRO4_SYS_RESET_USB3(14, 0),
|
||||
UNIPHIER_PRO4_SYS_RESET_USB3(15, 1),
|
||||
UNIPHIER_RESETX(16, 0x2014, 4), /* USB30-PHY0 */
|
||||
UNIPHIER_RESETX(17, 0x2014, 0), /* USB30-PHY1 */
|
||||
UNIPHIER_RESETX(18, 0x2014, 2), /* USB30-PHY2 */
|
||||
UNIPHIER_RESETX(20, 0x2014, 5), /* USB31-PHY0 */
|
||||
UNIPHIER_RESETX(21, 0x2014, 1), /* USB31-PHY1 */
|
||||
UNIPHIER_RESETX(28, 0x2014, 12), /* SATA */
|
||||
UNIPHIER_RESET(29, 0x2014, 8), /* SATA-PHY (active high) */
|
||||
UNIPHIER_RESET_END,
|
||||
};
|
||||
|
||||
const struct uniphier_reset_data uniphier_ld11_sys_reset_data[] = {
|
||||
UNIPHIER_LD11_SYS_RESET_STDMAC(8), /* HSC, MIO */
|
||||
UNIPHIER_RESET_END,
|
||||
};
|
||||
|
||||
const struct uniphier_reset_data uniphier_ld20_sys_reset_data[] = {
|
||||
UNIPHIER_LD11_SYS_RESET_STDMAC(8), /* HSC */
|
||||
UNIPHIER_LD20_SYS_RESET_GIO(12), /* PCIe, USB3 */
|
||||
UNIPHIER_RESETX(16, 0x200c, 12), /* USB30-PHY0 */
|
||||
UNIPHIER_RESETX(17, 0x200c, 13), /* USB30-PHY1 */
|
||||
UNIPHIER_RESETX(18, 0x200c, 14), /* USB30-PHY2 */
|
||||
UNIPHIER_RESETX(19, 0x200c, 15), /* USB30-PHY3 */
|
||||
UNIPHIER_RESET_END,
|
||||
};
|
||||
|
||||
/* Media I/O reset data */
|
||||
#define UNIPHIER_MIO_RESET_SD(id, ch) \
|
||||
UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 0)
|
||||
|
||||
#define UNIPHIER_MIO_RESET_SD_BRIDGE(id, ch) \
|
||||
UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 26)
|
||||
|
||||
#define UNIPHIER_MIO_RESET_EMMC_HW_RESET(id, ch) \
|
||||
UNIPHIER_RESETX((id), 0x80 + 0x200 * (ch), 0)
|
||||
|
||||
#define UNIPHIER_MIO_RESET_USB2(id, ch) \
|
||||
UNIPHIER_RESETX((id), 0x114 + 0x200 * (ch), 0)
|
||||
|
||||
#define UNIPHIER_MIO_RESET_USB2_BRIDGE(id, ch) \
|
||||
UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 24)
|
||||
|
||||
#define UNIPHIER_MIO_RESET_DMAC(id) \
|
||||
UNIPHIER_RESETX((id), 0x110, 17)
|
||||
|
||||
const struct uniphier_reset_data uniphier_sld3_mio_reset_data[] = {
|
||||
UNIPHIER_MIO_RESET_SD(0, 0),
|
||||
UNIPHIER_MIO_RESET_SD(1, 1),
|
||||
UNIPHIER_MIO_RESET_SD(2, 2),
|
||||
UNIPHIER_MIO_RESET_SD_BRIDGE(3, 0),
|
||||
UNIPHIER_MIO_RESET_SD_BRIDGE(4, 1),
|
||||
UNIPHIER_MIO_RESET_SD_BRIDGE(5, 2),
|
||||
UNIPHIER_MIO_RESET_EMMC_HW_RESET(6, 1),
|
||||
UNIPHIER_MIO_RESET_DMAC(7),
|
||||
UNIPHIER_MIO_RESET_USB2(8, 0),
|
||||
UNIPHIER_MIO_RESET_USB2(9, 1),
|
||||
UNIPHIER_MIO_RESET_USB2(10, 2),
|
||||
UNIPHIER_MIO_RESET_USB2(11, 3),
|
||||
UNIPHIER_MIO_RESET_USB2_BRIDGE(12, 0),
|
||||
UNIPHIER_MIO_RESET_USB2_BRIDGE(13, 1),
|
||||
UNIPHIER_MIO_RESET_USB2_BRIDGE(14, 2),
|
||||
UNIPHIER_MIO_RESET_USB2_BRIDGE(15, 3),
|
||||
UNIPHIER_RESET_END,
|
||||
};
|
||||
|
||||
const struct uniphier_reset_data uniphier_pro5_mio_reset_data[] = {
|
||||
UNIPHIER_MIO_RESET_SD(0, 0),
|
||||
UNIPHIER_MIO_RESET_SD(1, 1),
|
||||
UNIPHIER_MIO_RESET_EMMC_HW_RESET(6, 1),
|
||||
UNIPHIER_RESET_END,
|
||||
};
|
||||
|
||||
/* Peripheral reset data */
|
||||
#define UNIPHIER_PERI_RESET_UART(id, ch) \
|
||||
UNIPHIER_RESETX((id), 0x114, 19 + (ch))
|
||||
|
||||
#define UNIPHIER_PERI_RESET_I2C(id, ch) \
|
||||
UNIPHIER_RESETX((id), 0x114, 5 + (ch))
|
||||
|
||||
#define UNIPHIER_PERI_RESET_FI2C(id, ch) \
|
||||
UNIPHIER_RESETX((id), 0x114, 24 + (ch))
|
||||
|
||||
const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = {
|
||||
UNIPHIER_PERI_RESET_UART(0, 0),
|
||||
UNIPHIER_PERI_RESET_UART(1, 1),
|
||||
UNIPHIER_PERI_RESET_UART(2, 2),
|
||||
UNIPHIER_PERI_RESET_UART(3, 3),
|
||||
UNIPHIER_PERI_RESET_I2C(4, 0),
|
||||
UNIPHIER_PERI_RESET_I2C(5, 1),
|
||||
UNIPHIER_PERI_RESET_I2C(6, 2),
|
||||
UNIPHIER_PERI_RESET_I2C(7, 3),
|
||||
UNIPHIER_PERI_RESET_I2C(8, 4),
|
||||
UNIPHIER_RESET_END,
|
||||
};
|
||||
|
||||
const struct uniphier_reset_data uniphier_pro4_peri_reset_data[] = {
|
||||
UNIPHIER_PERI_RESET_UART(0, 0),
|
||||
UNIPHIER_PERI_RESET_UART(1, 1),
|
||||
UNIPHIER_PERI_RESET_UART(2, 2),
|
||||
UNIPHIER_PERI_RESET_UART(3, 3),
|
||||
UNIPHIER_PERI_RESET_FI2C(4, 0),
|
||||
UNIPHIER_PERI_RESET_FI2C(5, 1),
|
||||
UNIPHIER_PERI_RESET_FI2C(6, 2),
|
||||
UNIPHIER_PERI_RESET_FI2C(7, 3),
|
||||
UNIPHIER_PERI_RESET_FI2C(8, 4),
|
||||
UNIPHIER_PERI_RESET_FI2C(9, 5),
|
||||
UNIPHIER_PERI_RESET_FI2C(10, 6),
|
||||
UNIPHIER_RESET_END,
|
||||
};
|
||||
|
||||
/* core implementaton */
|
||||
struct uniphier_reset_priv {
|
||||
struct reset_controller_dev rcdev;
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
const struct uniphier_reset_data *data;
|
||||
};
|
||||
|
||||
#define to_uniphier_reset_priv(_rcdev) \
|
||||
container_of(_rcdev, struct uniphier_reset_priv, rcdev)
|
||||
|
||||
static int uniphier_reset_update(struct reset_controller_dev *rcdev,
|
||||
unsigned long id, int assert)
|
||||
{
|
||||
struct uniphier_reset_priv *priv = to_uniphier_reset_priv(rcdev);
|
||||
const struct uniphier_reset_data *p;
|
||||
|
||||
for (p = priv->data; p->id != UNIPHIER_RESET_ID_END; p++) {
|
||||
unsigned int mask, val;
|
||||
|
||||
if (p->id != id)
|
||||
continue;
|
||||
|
||||
mask = BIT(p->bit);
|
||||
|
||||
if (assert)
|
||||
val = mask;
|
||||
else
|
||||
val = ~mask;
|
||||
|
||||
if (p->flags & UNIPHIER_RESET_ACTIVE_LOW)
|
||||
val = ~val;
|
||||
|
||||
return regmap_write_bits(priv->regmap, p->reg, mask, val);
|
||||
}
|
||||
|
||||
dev_err(priv->dev, "reset_id=%lu was not handled\n", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int uniphier_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return uniphier_reset_update(rcdev, id, 1);
|
||||
}
|
||||
|
||||
static int uniphier_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return uniphier_reset_update(rcdev, id, 0);
|
||||
}
|
||||
|
||||
static int uniphier_reset_status(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct uniphier_reset_priv *priv = to_uniphier_reset_priv(rcdev);
|
||||
const struct uniphier_reset_data *p;
|
||||
|
||||
for (p = priv->data; p->id != UNIPHIER_RESET_ID_END; p++) {
|
||||
unsigned int val;
|
||||
int ret, asserted;
|
||||
|
||||
if (p->id != id)
|
||||
continue;
|
||||
|
||||
ret = regmap_read(priv->regmap, p->reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
asserted = !!(val & BIT(p->bit));
|
||||
|
||||
if (p->flags & UNIPHIER_RESET_ACTIVE_LOW)
|
||||
asserted = !asserted;
|
||||
|
||||
return asserted;
|
||||
}
|
||||
|
||||
dev_err(priv->dev, "reset_id=%lu was not found\n", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct reset_control_ops uniphier_reset_ops = {
|
||||
.assert = uniphier_reset_assert,
|
||||
.deassert = uniphier_reset_deassert,
|
||||
.status = uniphier_reset_status,
|
||||
};
|
||||
|
||||
static int uniphier_reset_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct uniphier_reset_priv *priv;
|
||||
const struct uniphier_reset_data *p, *data;
|
||||
struct regmap *regmap;
|
||||
struct device_node *parent;
|
||||
unsigned int nr_resets = 0;
|
||||
|
||||
data = of_device_get_match_data(dev);
|
||||
if (WARN_ON(!data))
|
||||
return -EINVAL;
|
||||
|
||||
parent = of_get_parent(dev->of_node); /* parent should be syscon node */
|
||||
regmap = syscon_node_to_regmap(parent);
|
||||
of_node_put(parent);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(dev, "failed to get regmap (error %ld)\n",
|
||||
PTR_ERR(regmap));
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
for (p = data; p->id != UNIPHIER_RESET_ID_END; p++)
|
||||
nr_resets = max(nr_resets, p->id + 1);
|
||||
|
||||
priv->rcdev.ops = &uniphier_reset_ops;
|
||||
priv->rcdev.owner = dev->driver->owner;
|
||||
priv->rcdev.of_node = dev->of_node;
|
||||
priv->rcdev.nr_resets = nr_resets;
|
||||
priv->dev = dev;
|
||||
priv->regmap = regmap;
|
||||
priv->data = data;
|
||||
|
||||
return devm_reset_controller_register(&pdev->dev, &priv->rcdev);
|
||||
}
|
||||
|
||||
static const struct of_device_id uniphier_reset_match[] = {
|
||||
/* System reset */
|
||||
{
|
||||
.compatible = "socionext,uniphier-sld3-reset",
|
||||
.data = uniphier_sld3_sys_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld4-reset",
|
||||
.data = uniphier_sld3_sys_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-pro4-reset",
|
||||
.data = uniphier_pro4_sys_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-sld8-reset",
|
||||
.data = uniphier_sld3_sys_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-pro5-reset",
|
||||
.data = uniphier_pro5_sys_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-pxs2-reset",
|
||||
.data = uniphier_pxs2_sys_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld11-reset",
|
||||
.data = uniphier_ld11_sys_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld20-reset",
|
||||
.data = uniphier_ld20_sys_reset_data,
|
||||
},
|
||||
/* Media I/O reset */
|
||||
{
|
||||
.compatible = "socionext,uniphier-sld3-mio-reset",
|
||||
.data = uniphier_sld3_mio_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld4-mio-reset",
|
||||
.data = uniphier_sld3_mio_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-pro4-mio-reset",
|
||||
.data = uniphier_sld3_mio_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-sld8-mio-reset",
|
||||
.data = uniphier_sld3_mio_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-pro5-mio-reset",
|
||||
.data = uniphier_pro5_mio_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-pxs2-mio-reset",
|
||||
.data = uniphier_pro5_mio_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld11-mio-reset",
|
||||
.data = uniphier_sld3_mio_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld20-mio-reset",
|
||||
.data = uniphier_pro5_mio_reset_data,
|
||||
},
|
||||
/* Peripheral reset */
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld4-peri-reset",
|
||||
.data = uniphier_ld4_peri_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-pro4-peri-reset",
|
||||
.data = uniphier_pro4_peri_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-sld8-peri-reset",
|
||||
.data = uniphier_ld4_peri_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-pro5-peri-reset",
|
||||
.data = uniphier_pro4_peri_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-pxs2-peri-reset",
|
||||
.data = uniphier_pro4_peri_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld11-peri-reset",
|
||||
.data = uniphier_pro4_peri_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld20-peri-reset",
|
||||
.data = uniphier_pro4_peri_reset_data,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, uniphier_reset_match);
|
||||
|
||||
static struct platform_driver uniphier_reset_driver = {
|
||||
.probe = uniphier_reset_probe,
|
||||
.driver = {
|
||||
.name = "uniphier-reset",
|
||||
.of_match_table = uniphier_reset_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(uniphier_reset_driver);
|
||||
|
||||
MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
|
||||
MODULE_DESCRIPTION("UniPhier Reset Controller Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -583,7 +583,7 @@ static int pwrap_wait_for_state(struct pmic_wrapper *wrp,
|
|||
{
|
||||
unsigned long timeout;
|
||||
|
||||
timeout = jiffies + usecs_to_jiffies(255);
|
||||
timeout = jiffies + usecs_to_jiffies(10000);
|
||||
|
||||
do {
|
||||
if (time_after(jiffies, timeout))
|
||||
|
|
|
@ -95,7 +95,7 @@ static const struct {
|
|||
|
||||
/**
|
||||
* struct qcom_smd_edge - representing a remote processor
|
||||
* @smd: handle to qcom_smd
|
||||
* @dev: device for this edge
|
||||
* @of_node: of_node handle for information related to this edge
|
||||
* @edge_id: identifier of this edge
|
||||
* @remote_pid: identifier of remote processor
|
||||
|
@ -111,7 +111,8 @@ static const struct {
|
|||
* @state_work: work item for edge state changes
|
||||
*/
|
||||
struct qcom_smd_edge {
|
||||
struct qcom_smd *smd;
|
||||
struct device dev;
|
||||
|
||||
struct device_node *of_node;
|
||||
unsigned edge_id;
|
||||
unsigned remote_pid;
|
||||
|
@ -135,6 +136,8 @@ struct qcom_smd_edge {
|
|||
struct work_struct state_work;
|
||||
};
|
||||
|
||||
#define to_smd_edge(d) container_of(d, struct qcom_smd_edge, dev)
|
||||
|
||||
/*
|
||||
* SMD channel states.
|
||||
*/
|
||||
|
@ -197,20 +200,6 @@ struct qcom_smd_channel {
|
|||
void *drvdata;
|
||||
|
||||
struct list_head list;
|
||||
struct list_head dev_list;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qcom_smd - smd struct
|
||||
* @dev: device struct
|
||||
* @num_edges: number of entries in @edges
|
||||
* @edges: array of edges to be handled
|
||||
*/
|
||||
struct qcom_smd {
|
||||
struct device *dev;
|
||||
|
||||
unsigned num_edges;
|
||||
struct qcom_smd_edge edges[0];
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -374,7 +363,7 @@ static void qcom_smd_channel_reset(struct qcom_smd_channel *channel)
|
|||
SET_TX_CHANNEL_FLAG(channel, fSTATE, 1);
|
||||
SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1);
|
||||
SET_TX_CHANNEL_INFO(channel, head, 0);
|
||||
SET_TX_CHANNEL_INFO(channel, tail, 0);
|
||||
SET_RX_CHANNEL_INFO(channel, tail, 0);
|
||||
|
||||
qcom_smd_signal_channel(channel);
|
||||
|
||||
|
@ -421,7 +410,7 @@ static void qcom_smd_channel_set_state(struct qcom_smd_channel *channel,
|
|||
if (channel->state == state)
|
||||
return;
|
||||
|
||||
dev_dbg(edge->smd->dev, "set_state(%s, %d)\n", channel->name, state);
|
||||
dev_dbg(&edge->dev, "set_state(%s, %d)\n", channel->name, state);
|
||||
|
||||
SET_TX_CHANNEL_FLAG(channel, fDSR, is_open);
|
||||
SET_TX_CHANNEL_FLAG(channel, fCTS, is_open);
|
||||
|
@ -891,8 +880,6 @@ static int qcom_smd_dev_remove(struct device *dev)
|
|||
struct qcom_smd_device *qsdev = to_smd_device(dev);
|
||||
struct qcom_smd_driver *qsdrv = to_smd_driver(dev);
|
||||
struct qcom_smd_channel *channel = qsdev->channel;
|
||||
struct qcom_smd_channel *tmp;
|
||||
struct qcom_smd_channel *ch;
|
||||
|
||||
qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSING);
|
||||
|
||||
|
@ -911,15 +898,9 @@ static int qcom_smd_dev_remove(struct device *dev)
|
|||
if (qsdrv->remove)
|
||||
qsdrv->remove(qsdev);
|
||||
|
||||
/*
|
||||
* The client is now gone, close and release all channels associated
|
||||
* with this sdev
|
||||
*/
|
||||
list_for_each_entry_safe(ch, tmp, &channel->dev_list, dev_list) {
|
||||
qcom_smd_channel_close(ch);
|
||||
list_del(&ch->dev_list);
|
||||
ch->qsdev = NULL;
|
||||
}
|
||||
/* The client is now gone, close the primary channel */
|
||||
qcom_smd_channel_close(channel);
|
||||
channel->qsdev = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -973,13 +954,12 @@ static int qcom_smd_create_device(struct qcom_smd_channel *channel)
|
|||
struct qcom_smd_device *qsdev;
|
||||
struct qcom_smd_edge *edge = channel->edge;
|
||||
struct device_node *node;
|
||||
struct qcom_smd *smd = edge->smd;
|
||||
int ret;
|
||||
|
||||
if (channel->qsdev)
|
||||
return -EEXIST;
|
||||
|
||||
dev_dbg(smd->dev, "registering '%s'\n", channel->name);
|
||||
dev_dbg(&edge->dev, "registering '%s'\n", channel->name);
|
||||
|
||||
qsdev = kzalloc(sizeof(*qsdev), GFP_KERNEL);
|
||||
if (!qsdev)
|
||||
|
@ -990,7 +970,7 @@ static int qcom_smd_create_device(struct qcom_smd_channel *channel)
|
|||
edge->of_node->name,
|
||||
node ? node->name : channel->name);
|
||||
|
||||
qsdev->dev.parent = smd->dev;
|
||||
qsdev->dev.parent = &edge->dev;
|
||||
qsdev->dev.bus = &qcom_smd_bus;
|
||||
qsdev->dev.release = qcom_smd_release_device;
|
||||
qsdev->dev.of_node = node;
|
||||
|
@ -1001,7 +981,7 @@ static int qcom_smd_create_device(struct qcom_smd_channel *channel)
|
|||
|
||||
ret = device_register(&qsdev->dev);
|
||||
if (ret) {
|
||||
dev_err(smd->dev, "device_register failed: %d\n", ret);
|
||||
dev_err(&edge->dev, "device_register failed: %d\n", ret);
|
||||
put_device(&qsdev->dev);
|
||||
}
|
||||
|
||||
|
@ -1091,6 +1071,8 @@ qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name)
|
|||
*
|
||||
* Returns a channel handle on success, or -EPROBE_DEFER if the channel isn't
|
||||
* ready.
|
||||
*
|
||||
* Any channels returned must be closed with a call to qcom_smd_close_channel()
|
||||
*/
|
||||
struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *parent,
|
||||
const char *name,
|
||||
|
@ -1120,15 +1102,21 @@ struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *parent,
|
|||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append the list of channel to the channels associated with the sdev
|
||||
*/
|
||||
list_add_tail(&channel->dev_list, &sdev->channel->dev_list);
|
||||
|
||||
return channel;
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_smd_open_channel);
|
||||
|
||||
/**
|
||||
* qcom_smd_close_channel() - close an additionally opened channel
|
||||
* @channel: channel handle, returned by qcom_smd_open_channel()
|
||||
*/
|
||||
void qcom_smd_close_channel(struct qcom_smd_channel *channel)
|
||||
{
|
||||
qcom_smd_channel_close(channel);
|
||||
channel->qsdev = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_smd_close_channel);
|
||||
|
||||
/*
|
||||
* Allocate the qcom_smd_channel object for a newly found smd channel,
|
||||
* retrieving and validating the smem items involved.
|
||||
|
@ -1139,20 +1127,18 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
|
|||
char *name)
|
||||
{
|
||||
struct qcom_smd_channel *channel;
|
||||
struct qcom_smd *smd = edge->smd;
|
||||
size_t fifo_size;
|
||||
size_t info_size;
|
||||
void *fifo_base;
|
||||
void *info;
|
||||
int ret;
|
||||
|
||||
channel = devm_kzalloc(smd->dev, sizeof(*channel), GFP_KERNEL);
|
||||
channel = devm_kzalloc(&edge->dev, sizeof(*channel), GFP_KERNEL);
|
||||
if (!channel)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
INIT_LIST_HEAD(&channel->dev_list);
|
||||
channel->edge = edge;
|
||||
channel->name = devm_kstrdup(smd->dev, name, GFP_KERNEL);
|
||||
channel->name = devm_kstrdup(&edge->dev, name, GFP_KERNEL);
|
||||
if (!channel->name)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
@ -1175,7 +1161,7 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
|
|||
} else if (info_size == 2 * sizeof(struct smd_channel_info)) {
|
||||
channel->info = info;
|
||||
} else {
|
||||
dev_err(smd->dev,
|
||||
dev_err(&edge->dev,
|
||||
"channel info of size %zu not supported\n", info_size);
|
||||
ret = -EINVAL;
|
||||
goto free_name_and_channel;
|
||||
|
@ -1190,7 +1176,7 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
|
|||
/* The channel consist of a rx and tx fifo of equal size */
|
||||
fifo_size /= 2;
|
||||
|
||||
dev_dbg(smd->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n",
|
||||
dev_dbg(&edge->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n",
|
||||
name, info_size, fifo_size);
|
||||
|
||||
channel->tx_fifo = fifo_base;
|
||||
|
@ -1202,8 +1188,8 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
|
|||
return channel;
|
||||
|
||||
free_name_and_channel:
|
||||
devm_kfree(smd->dev, channel->name);
|
||||
devm_kfree(smd->dev, channel);
|
||||
devm_kfree(&edge->dev, channel->name);
|
||||
devm_kfree(&edge->dev, channel);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
@ -1219,7 +1205,6 @@ static void qcom_channel_scan_worker(struct work_struct *work)
|
|||
struct qcom_smd_alloc_entry *alloc_tbl;
|
||||
struct qcom_smd_alloc_entry *entry;
|
||||
struct qcom_smd_channel *channel;
|
||||
struct qcom_smd *smd = edge->smd;
|
||||
unsigned long flags;
|
||||
unsigned fifo_id;
|
||||
unsigned info_id;
|
||||
|
@ -1263,7 +1248,7 @@ static void qcom_channel_scan_worker(struct work_struct *work)
|
|||
list_add(&channel->list, &edge->channels);
|
||||
spin_unlock_irqrestore(&edge->channels_lock, flags);
|
||||
|
||||
dev_dbg(smd->dev, "new channel found: '%s'\n", channel->name);
|
||||
dev_dbg(&edge->dev, "new channel found: '%s'\n", channel->name);
|
||||
set_bit(i, edge->allocated[tbl]);
|
||||
|
||||
wake_up_interruptible(&edge->new_channel_event);
|
||||
|
@ -1350,22 +1335,6 @@ static int qcom_smd_parse_edge(struct device *dev,
|
|||
|
||||
edge->of_node = of_node_get(node);
|
||||
|
||||
irq = irq_of_parse_and_map(node, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "required smd interrupt missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, irq,
|
||||
qcom_smd_edge_intr, IRQF_TRIGGER_RISING,
|
||||
node->name, edge);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to request smd irq\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
edge->irq = irq;
|
||||
|
||||
key = "qcom,smd-edge";
|
||||
ret = of_property_read_u32(node, key, &edge->edge_id);
|
||||
if (ret) {
|
||||
|
@ -1400,18 +1369,121 @@ static int qcom_smd_parse_edge(struct device *dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
irq = irq_of_parse_and_map(node, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "required smd interrupt missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, irq,
|
||||
qcom_smd_edge_intr, IRQF_TRIGGER_RISING,
|
||||
node->name, edge);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to request smd irq\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
edge->irq = irq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_smd_probe(struct platform_device *pdev)
|
||||
/*
|
||||
* Release function for an edge.
|
||||
* Reset the state of each associated channel and free the edge context.
|
||||
*/
|
||||
static void qcom_smd_edge_release(struct device *dev)
|
||||
{
|
||||
struct qcom_smd_channel *channel;
|
||||
struct qcom_smd_edge *edge = to_smd_edge(dev);
|
||||
|
||||
list_for_each_entry(channel, &edge->channels, list) {
|
||||
SET_RX_CHANNEL_INFO(channel, state, SMD_CHANNEL_CLOSED);
|
||||
SET_RX_CHANNEL_INFO(channel, head, 0);
|
||||
SET_RX_CHANNEL_INFO(channel, tail, 0);
|
||||
}
|
||||
|
||||
kfree(edge);
|
||||
}
|
||||
|
||||
/**
|
||||
* qcom_smd_register_edge() - register an edge based on an device_node
|
||||
* @parent: parent device for the edge
|
||||
* @node: device_node describing the edge
|
||||
*
|
||||
* Returns an edge reference, or negative ERR_PTR() on failure.
|
||||
*/
|
||||
struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent,
|
||||
struct device_node *node)
|
||||
{
|
||||
struct qcom_smd_edge *edge;
|
||||
struct device_node *node;
|
||||
struct qcom_smd *smd;
|
||||
size_t array_size;
|
||||
int num_edges;
|
||||
int ret;
|
||||
int i = 0;
|
||||
|
||||
edge = kzalloc(sizeof(*edge), GFP_KERNEL);
|
||||
if (!edge)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init_waitqueue_head(&edge->new_channel_event);
|
||||
|
||||
edge->dev.parent = parent;
|
||||
edge->dev.release = qcom_smd_edge_release;
|
||||
dev_set_name(&edge->dev, "%s:%s", dev_name(parent), node->name);
|
||||
ret = device_register(&edge->dev);
|
||||
if (ret) {
|
||||
pr_err("failed to register smd edge\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
ret = qcom_smd_parse_edge(&edge->dev, node, edge);
|
||||
if (ret) {
|
||||
dev_err(&edge->dev, "failed to parse smd edge\n");
|
||||
goto unregister_dev;
|
||||
}
|
||||
|
||||
schedule_work(&edge->scan_work);
|
||||
|
||||
return edge;
|
||||
|
||||
unregister_dev:
|
||||
put_device(&edge->dev);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_smd_register_edge);
|
||||
|
||||
static int qcom_smd_remove_device(struct device *dev, void *data)
|
||||
{
|
||||
device_unregister(dev);
|
||||
of_node_put(dev->of_node);
|
||||
put_device(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* qcom_smd_unregister_edge() - release an edge and its children
|
||||
* @edge: edge reference acquired from qcom_smd_register_edge
|
||||
*/
|
||||
int qcom_smd_unregister_edge(struct qcom_smd_edge *edge)
|
||||
{
|
||||
int ret;
|
||||
|
||||
disable_irq(edge->irq);
|
||||
cancel_work_sync(&edge->scan_work);
|
||||
cancel_work_sync(&edge->state_work);
|
||||
|
||||
ret = device_for_each_child(&edge->dev, NULL, qcom_smd_remove_device);
|
||||
if (ret)
|
||||
dev_warn(&edge->dev, "can't remove smd device: %d\n", ret);
|
||||
|
||||
device_unregister(&edge->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_smd_unregister_edge);
|
||||
|
||||
static int qcom_smd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node;
|
||||
void *p;
|
||||
|
||||
/* Wait for smem */
|
||||
|
@ -1419,59 +1491,32 @@ static int qcom_smd_probe(struct platform_device *pdev)
|
|||
if (PTR_ERR(p) == -EPROBE_DEFER)
|
||||
return PTR_ERR(p);
|
||||
|
||||
num_edges = of_get_available_child_count(pdev->dev.of_node);
|
||||
array_size = sizeof(*smd) + num_edges * sizeof(struct qcom_smd_edge);
|
||||
smd = devm_kzalloc(&pdev->dev, array_size, GFP_KERNEL);
|
||||
if (!smd)
|
||||
return -ENOMEM;
|
||||
smd->dev = &pdev->dev;
|
||||
|
||||
smd->num_edges = num_edges;
|
||||
for_each_available_child_of_node(pdev->dev.of_node, node) {
|
||||
edge = &smd->edges[i++];
|
||||
edge->smd = smd;
|
||||
init_waitqueue_head(&edge->new_channel_event);
|
||||
|
||||
ret = qcom_smd_parse_edge(&pdev->dev, node, edge);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
schedule_work(&edge->scan_work);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, smd);
|
||||
for_each_available_child_of_node(pdev->dev.of_node, node)
|
||||
qcom_smd_register_edge(&pdev->dev, node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_smd_remove_edge(struct device *dev, void *data)
|
||||
{
|
||||
struct qcom_smd_edge *edge = to_smd_edge(dev);
|
||||
|
||||
return qcom_smd_unregister_edge(edge);
|
||||
}
|
||||
|
||||
/*
|
||||
* Shut down all smd clients by making sure that each edge stops processing
|
||||
* events and scanning for new channels, then call destroy on the devices.
|
||||
*/
|
||||
static int qcom_smd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct qcom_smd_channel *channel;
|
||||
struct qcom_smd_edge *edge;
|
||||
struct qcom_smd *smd = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < smd->num_edges; i++) {
|
||||
edge = &smd->edges[i];
|
||||
ret = device_for_each_child(&pdev->dev, NULL, qcom_smd_remove_edge);
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "can't remove smd device: %d\n", ret);
|
||||
|
||||
disable_irq(edge->irq);
|
||||
cancel_work_sync(&edge->scan_work);
|
||||
cancel_work_sync(&edge->state_work);
|
||||
|
||||
/* No need to lock here, because the writer is gone */
|
||||
list_for_each_entry(channel, &edge->channels, list) {
|
||||
if (!channel->qsdev)
|
||||
continue;
|
||||
|
||||
qcom_smd_destroy_device(channel);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id qcom_smd_of_match[] = {
|
||||
|
|
|
@ -740,7 +740,8 @@ static int qcom_smem_probe(struct platform_device *pdev)
|
|||
|
||||
hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
|
||||
if (hwlock_id < 0) {
|
||||
dev_err(&pdev->dev, "failed to retrieve hwlock\n");
|
||||
if (hwlock_id != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "failed to retrieve hwlock\n");
|
||||
return hwlock_id;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ struct rockchip_domain_info {
|
|||
int req_mask;
|
||||
int idle_mask;
|
||||
int ack_mask;
|
||||
bool active_wakeup;
|
||||
};
|
||||
|
||||
struct rockchip_pmu_info {
|
||||
|
@ -75,23 +76,24 @@ struct rockchip_pmu {
|
|||
|
||||
#define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd)
|
||||
|
||||
#define DOMAIN(pwr, status, req, idle, ack) \
|
||||
#define DOMAIN(pwr, status, req, idle, ack, wakeup) \
|
||||
{ \
|
||||
.pwr_mask = (pwr >= 0) ? BIT(pwr) : 0, \
|
||||
.status_mask = (status >= 0) ? BIT(status) : 0, \
|
||||
.req_mask = (req >= 0) ? BIT(req) : 0, \
|
||||
.idle_mask = (idle >= 0) ? BIT(idle) : 0, \
|
||||
.ack_mask = (ack >= 0) ? BIT(ack) : 0, \
|
||||
.active_wakeup = wakeup, \
|
||||
}
|
||||
|
||||
#define DOMAIN_RK3288(pwr, status, req) \
|
||||
DOMAIN(pwr, status, req, req, (req) + 16)
|
||||
#define DOMAIN_RK3288(pwr, status, req, wakeup) \
|
||||
DOMAIN(pwr, status, req, req, (req) + 16, wakeup)
|
||||
|
||||
#define DOMAIN_RK3368(pwr, status, req) \
|
||||
DOMAIN(pwr, status, req, (req) + 16, req)
|
||||
#define DOMAIN_RK3368(pwr, status, req, wakeup) \
|
||||
DOMAIN(pwr, status, req, (req) + 16, req, wakeup)
|
||||
|
||||
#define DOMAIN_RK3399(pwr, status, req) \
|
||||
DOMAIN(pwr, status, req, req, req)
|
||||
#define DOMAIN_RK3399(pwr, status, req, wakeup) \
|
||||
DOMAIN(pwr, status, req, req, req, wakeup)
|
||||
|
||||
static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
|
||||
{
|
||||
|
@ -295,6 +297,17 @@ static void rockchip_pd_detach_dev(struct generic_pm_domain *genpd,
|
|||
pm_clk_destroy(dev);
|
||||
}
|
||||
|
||||
static bool rockchip_active_wakeup(struct device *dev)
|
||||
{
|
||||
struct generic_pm_domain *genpd;
|
||||
struct rockchip_pm_domain *pd;
|
||||
|
||||
genpd = pd_to_genpd(dev->pm_domain);
|
||||
pd = container_of(genpd, struct rockchip_pm_domain, genpd);
|
||||
|
||||
return pd->info->active_wakeup;
|
||||
}
|
||||
|
||||
static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
|
||||
struct device_node *node)
|
||||
{
|
||||
|
@ -415,6 +428,7 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
|
|||
pd->genpd.power_on = rockchip_pd_power_on;
|
||||
pd->genpd.attach_dev = rockchip_pd_attach_dev;
|
||||
pd->genpd.detach_dev = rockchip_pd_detach_dev;
|
||||
pd->genpd.dev_ops.active_wakeup = rockchip_active_wakeup;
|
||||
pd->genpd.flags = GENPD_FLAG_PM_CLK;
|
||||
pm_genpd_init(&pd->genpd, NULL, false);
|
||||
|
||||
|
@ -623,48 +637,48 @@ err_out:
|
|||
}
|
||||
|
||||
static const struct rockchip_domain_info rk3288_pm_domains[] = {
|
||||
[RK3288_PD_VIO] = DOMAIN_RK3288(7, 7, 4),
|
||||
[RK3288_PD_HEVC] = DOMAIN_RK3288(14, 10, 9),
|
||||
[RK3288_PD_VIDEO] = DOMAIN_RK3288(8, 8, 3),
|
||||
[RK3288_PD_GPU] = DOMAIN_RK3288(9, 9, 2),
|
||||
[RK3288_PD_VIO] = DOMAIN_RK3288(7, 7, 4, false),
|
||||
[RK3288_PD_HEVC] = DOMAIN_RK3288(14, 10, 9, false),
|
||||
[RK3288_PD_VIDEO] = DOMAIN_RK3288(8, 8, 3, false),
|
||||
[RK3288_PD_GPU] = DOMAIN_RK3288(9, 9, 2, false),
|
||||
};
|
||||
|
||||
static const struct rockchip_domain_info rk3368_pm_domains[] = {
|
||||
[RK3368_PD_PERI] = DOMAIN_RK3368(13, 12, 6),
|
||||
[RK3368_PD_VIO] = DOMAIN_RK3368(15, 14, 8),
|
||||
[RK3368_PD_VIDEO] = DOMAIN_RK3368(14, 13, 7),
|
||||
[RK3368_PD_GPU_0] = DOMAIN_RK3368(16, 15, 2),
|
||||
[RK3368_PD_GPU_1] = DOMAIN_RK3368(17, 16, 2),
|
||||
[RK3368_PD_PERI] = DOMAIN_RK3368(13, 12, 6, true),
|
||||
[RK3368_PD_VIO] = DOMAIN_RK3368(15, 14, 8, false),
|
||||
[RK3368_PD_VIDEO] = DOMAIN_RK3368(14, 13, 7, false),
|
||||
[RK3368_PD_GPU_0] = DOMAIN_RK3368(16, 15, 2, false),
|
||||
[RK3368_PD_GPU_1] = DOMAIN_RK3368(17, 16, 2, false),
|
||||
};
|
||||
|
||||
static const struct rockchip_domain_info rk3399_pm_domains[] = {
|
||||
[RK3399_PD_TCPD0] = DOMAIN_RK3399(8, 8, -1),
|
||||
[RK3399_PD_TCPD1] = DOMAIN_RK3399(9, 9, -1),
|
||||
[RK3399_PD_CCI] = DOMAIN_RK3399(10, 10, -1),
|
||||
[RK3399_PD_CCI0] = DOMAIN_RK3399(-1, -1, 15),
|
||||
[RK3399_PD_CCI1] = DOMAIN_RK3399(-1, -1, 16),
|
||||
[RK3399_PD_PERILP] = DOMAIN_RK3399(11, 11, 1),
|
||||
[RK3399_PD_PERIHP] = DOMAIN_RK3399(12, 12, 2),
|
||||
[RK3399_PD_CENTER] = DOMAIN_RK3399(13, 13, 14),
|
||||
[RK3399_PD_VIO] = DOMAIN_RK3399(14, 14, 17),
|
||||
[RK3399_PD_GPU] = DOMAIN_RK3399(15, 15, 0),
|
||||
[RK3399_PD_VCODEC] = DOMAIN_RK3399(16, 16, 3),
|
||||
[RK3399_PD_VDU] = DOMAIN_RK3399(17, 17, 4),
|
||||
[RK3399_PD_RGA] = DOMAIN_RK3399(18, 18, 5),
|
||||
[RK3399_PD_IEP] = DOMAIN_RK3399(19, 19, 6),
|
||||
[RK3399_PD_VO] = DOMAIN_RK3399(20, 20, -1),
|
||||
[RK3399_PD_VOPB] = DOMAIN_RK3399(-1, -1, 7),
|
||||
[RK3399_PD_VOPL] = DOMAIN_RK3399(-1, -1, 8),
|
||||
[RK3399_PD_ISP0] = DOMAIN_RK3399(22, 22, 9),
|
||||
[RK3399_PD_ISP1] = DOMAIN_RK3399(23, 23, 10),
|
||||
[RK3399_PD_HDCP] = DOMAIN_RK3399(24, 24, 11),
|
||||
[RK3399_PD_GMAC] = DOMAIN_RK3399(25, 25, 23),
|
||||
[RK3399_PD_EMMC] = DOMAIN_RK3399(26, 26, 24),
|
||||
[RK3399_PD_USB3] = DOMAIN_RK3399(27, 27, 12),
|
||||
[RK3399_PD_EDP] = DOMAIN_RK3399(28, 28, 22),
|
||||
[RK3399_PD_GIC] = DOMAIN_RK3399(29, 29, 27),
|
||||
[RK3399_PD_SD] = DOMAIN_RK3399(30, 30, 28),
|
||||
[RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399(31, 31, 29),
|
||||
[RK3399_PD_TCPD0] = DOMAIN_RK3399(8, 8, -1, false),
|
||||
[RK3399_PD_TCPD1] = DOMAIN_RK3399(9, 9, -1, false),
|
||||
[RK3399_PD_CCI] = DOMAIN_RK3399(10, 10, -1, true),
|
||||
[RK3399_PD_CCI0] = DOMAIN_RK3399(-1, -1, 15, true),
|
||||
[RK3399_PD_CCI1] = DOMAIN_RK3399(-1, -1, 16, true),
|
||||
[RK3399_PD_PERILP] = DOMAIN_RK3399(11, 11, 1, true),
|
||||
[RK3399_PD_PERIHP] = DOMAIN_RK3399(12, 12, 2, true),
|
||||
[RK3399_PD_CENTER] = DOMAIN_RK3399(13, 13, 14, true),
|
||||
[RK3399_PD_VIO] = DOMAIN_RK3399(14, 14, 17, false),
|
||||
[RK3399_PD_GPU] = DOMAIN_RK3399(15, 15, 0, false),
|
||||
[RK3399_PD_VCODEC] = DOMAIN_RK3399(16, 16, 3, false),
|
||||
[RK3399_PD_VDU] = DOMAIN_RK3399(17, 17, 4, false),
|
||||
[RK3399_PD_RGA] = DOMAIN_RK3399(18, 18, 5, false),
|
||||
[RK3399_PD_IEP] = DOMAIN_RK3399(19, 19, 6, false),
|
||||
[RK3399_PD_VO] = DOMAIN_RK3399(20, 20, -1, false),
|
||||
[RK3399_PD_VOPB] = DOMAIN_RK3399(-1, -1, 7, false),
|
||||
[RK3399_PD_VOPL] = DOMAIN_RK3399(-1, -1, 8, false),
|
||||
[RK3399_PD_ISP0] = DOMAIN_RK3399(22, 22, 9, false),
|
||||
[RK3399_PD_ISP1] = DOMAIN_RK3399(23, 23, 10, false),
|
||||
[RK3399_PD_HDCP] = DOMAIN_RK3399(24, 24, 11, false),
|
||||
[RK3399_PD_GMAC] = DOMAIN_RK3399(25, 25, 23, true),
|
||||
[RK3399_PD_EMMC] = DOMAIN_RK3399(26, 26, 24, true),
|
||||
[RK3399_PD_USB3] = DOMAIN_RK3399(27, 27, 12, true),
|
||||
[RK3399_PD_EDP] = DOMAIN_RK3399(28, 28, 22, false),
|
||||
[RK3399_PD_GIC] = DOMAIN_RK3399(29, 29, 27, true),
|
||||
[RK3399_PD_SD] = DOMAIN_RK3399(30, 30, 28, true),
|
||||
[RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399(31, 31, 29, true),
|
||||
};
|
||||
|
||||
static const struct rockchip_pmu_info rk3288_pmu = {
|
||||
|
|
|
@ -967,8 +967,8 @@ static void tegra_io_rail_unprepare(void)
|
|||
|
||||
int tegra_io_rail_power_on(unsigned int id)
|
||||
{
|
||||
unsigned long request, status, value;
|
||||
unsigned int bit, mask;
|
||||
unsigned long request, status;
|
||||
unsigned int bit;
|
||||
int err;
|
||||
|
||||
mutex_lock(&pmc->powergates_lock);
|
||||
|
@ -977,15 +977,9 @@ int tegra_io_rail_power_on(unsigned int id)
|
|||
if (err)
|
||||
goto error;
|
||||
|
||||
mask = 1 << bit;
|
||||
tegra_pmc_writel(IO_DPD_REQ_CODE_OFF | BIT(bit), request);
|
||||
|
||||
value = tegra_pmc_readl(request);
|
||||
value |= mask;
|
||||
value &= ~IO_DPD_REQ_CODE_MASK;
|
||||
value |= IO_DPD_REQ_CODE_OFF;
|
||||
tegra_pmc_writel(value, request);
|
||||
|
||||
err = tegra_io_rail_poll(status, mask, 0, 250);
|
||||
err = tegra_io_rail_poll(status, BIT(bit), 0, 250);
|
||||
if (err) {
|
||||
pr_info("tegra_io_rail_poll() failed: %d\n", err);
|
||||
goto error;
|
||||
|
@ -1002,8 +996,8 @@ EXPORT_SYMBOL(tegra_io_rail_power_on);
|
|||
|
||||
int tegra_io_rail_power_off(unsigned int id)
|
||||
{
|
||||
unsigned long request, status, value;
|
||||
unsigned int bit, mask;
|
||||
unsigned long request, status;
|
||||
unsigned int bit;
|
||||
int err;
|
||||
|
||||
mutex_lock(&pmc->powergates_lock);
|
||||
|
@ -1014,15 +1008,9 @@ int tegra_io_rail_power_off(unsigned int id)
|
|||
goto error;
|
||||
}
|
||||
|
||||
mask = 1 << bit;
|
||||
tegra_pmc_writel(IO_DPD_REQ_CODE_ON | BIT(bit), request);
|
||||
|
||||
value = tegra_pmc_readl(request);
|
||||
value |= mask;
|
||||
value &= ~IO_DPD_REQ_CODE_MASK;
|
||||
value |= IO_DPD_REQ_CODE_ON;
|
||||
tegra_pmc_writel(value, request);
|
||||
|
||||
err = tegra_io_rail_poll(status, mask, mask, 250);
|
||||
err = tegra_io_rail_poll(status, BIT(bit), BIT(bit), 250);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* This header provides constants for the STM32F4 RCC IP
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_MFD_STM32F4_RCC_H
|
||||
#define _DT_BINDINGS_MFD_STM32F4_RCC_H
|
||||
|
||||
/* AHB1 */
|
||||
#define STM32F4_RCC_AHB1_GPIOA 0
|
||||
#define STM32F4_RCC_AHB1_GPIOB 1
|
||||
#define STM32F4_RCC_AHB1_GPIOC 2
|
||||
#define STM32F4_RCC_AHB1_GPIOD 3
|
||||
#define STM32F4_RCC_AHB1_GPIOE 4
|
||||
#define STM32F4_RCC_AHB1_GPIOF 5
|
||||
#define STM32F4_RCC_AHB1_GPIOG 6
|
||||
#define STM32F4_RCC_AHB1_GPIOH 7
|
||||
#define STM32F4_RCC_AHB1_GPIOI 8
|
||||
#define STM32F4_RCC_AHB1_GPIOJ 9
|
||||
#define STM32F4_RCC_AHB1_GPIOK 10
|
||||
#define STM32F4_RCC_AHB1_CRC 12
|
||||
#define STM32F4_RCC_AHB1_DMA1 21
|
||||
#define STM32F4_RCC_AHB1_DMA2 22
|
||||
#define STM32F4_RCC_AHB1_DMA2D 23
|
||||
#define STM32F4_RCC_AHB1_ETHMAC 25
|
||||
#define STM32F4_RCC_AHB1_OTGHS 29
|
||||
|
||||
#define STM32F4_AHB1_RESET(bit) (STM32F4_RCC_AHB1_##bit + (0x10 * 8))
|
||||
#define STM32F4_AHB1_CLOCK(bit) (STM32F4_RCC_AHB1_##bit + (0x30 * 8))
|
||||
|
||||
|
||||
/* AHB2 */
|
||||
#define STM32F4_RCC_AHB2_DCMI 0
|
||||
#define STM32F4_RCC_AHB2_CRYP 4
|
||||
#define STM32F4_RCC_AHB2_HASH 5
|
||||
#define STM32F4_RCC_AHB2_RNG 6
|
||||
#define STM32F4_RCC_AHB2_OTGFS 7
|
||||
|
||||
#define STM32F4_AHB2_RESET(bit) (STM32F4_RCC_AHB2_##bit + (0x14 * 8))
|
||||
#define STM32F4_AHB2_CLOCK(bit) (STM32F4_RCC_AHB2_##bit + (0x34 * 8))
|
||||
|
||||
/* AHB3 */
|
||||
#define STM32F4_RCC_AHB3_FMC 0
|
||||
|
||||
#define STM32F4_AHB3_RESET(bit) (STM32F4_RCC_AHB3_##bit + (0x18 * 8))
|
||||
#define STM32F4_AHB3_CLOCK(bit) (STM32F4_RCC_AHB3_##bit + (0x38 * 8))
|
||||
|
||||
/* APB1 */
|
||||
#define STM32F4_RCC_APB1_TIM2 0
|
||||
#define STM32F4_RCC_APB1_TIM3 1
|
||||
#define STM32F4_RCC_APB1_TIM4 2
|
||||
#define STM32F4_RCC_APB1_TIM5 3
|
||||
#define STM32F4_RCC_APB1_TIM6 4
|
||||
#define STM32F4_RCC_APB1_TIM7 5
|
||||
#define STM32F4_RCC_APB1_TIM12 6
|
||||
#define STM32F4_RCC_APB1_TIM13 7
|
||||
#define STM32F4_RCC_APB1_TIM14 8
|
||||
#define STM32F4_RCC_APB1_WWDG 11
|
||||
#define STM32F4_RCC_APB1_SPI2 14
|
||||
#define STM32F4_RCC_APB1_SPI3 15
|
||||
#define STM32F4_RCC_APB1_UART2 17
|
||||
#define STM32F4_RCC_APB1_UART3 18
|
||||
#define STM32F4_RCC_APB1_UART4 19
|
||||
#define STM32F4_RCC_APB1_UART5 20
|
||||
#define STM32F4_RCC_APB1_I2C1 21
|
||||
#define STM32F4_RCC_APB1_I2C2 22
|
||||
#define STM32F4_RCC_APB1_I2C3 23
|
||||
#define STM32F4_RCC_APB1_CAN1 25
|
||||
#define STM32F4_RCC_APB1_CAN2 26
|
||||
#define STM32F4_RCC_APB1_PWR 28
|
||||
#define STM32F4_RCC_APB1_DAC 29
|
||||
#define STM32F4_RCC_APB1_UART7 30
|
||||
#define STM32F4_RCC_APB1_UART8 31
|
||||
|
||||
#define STM32F4_APB1_RESET(bit) (STM32F4_RCC_APB1_##bit + (0x20 * 8))
|
||||
#define STM32F4_APB1_CLOCK(bit) (STM32F4_RCC_APB1_##bit + (0x40 * 8))
|
||||
|
||||
/* APB2 */
|
||||
#define STM32F4_RCC_APB2_TIM1 0
|
||||
#define STM32F4_RCC_APB2_TIM8 1
|
||||
#define STM32F4_RCC_APB2_USART1 4
|
||||
#define STM32F4_RCC_APB2_USART6 5
|
||||
#define STM32F4_RCC_APB2_ADC 8
|
||||
#define STM32F4_RCC_APB2_SDIO 11
|
||||
#define STM32F4_RCC_APB2_SPI1 12
|
||||
#define STM32F4_RCC_APB2_SPI4 13
|
||||
#define STM32F4_RCC_APB2_SYSCFG 14
|
||||
#define STM32F4_RCC_APB2_TIM9 16
|
||||
#define STM32F4_RCC_APB2_TIM10 17
|
||||
#define STM32F4_RCC_APB2_TIM11 18
|
||||
#define STM32F4_RCC_APB2_SPI5 20
|
||||
#define STM32F4_RCC_APB2_SPI6 21
|
||||
#define STM32F4_RCC_APB2_SAI1 22
|
||||
#define STM32F4_RCC_APB2_LTDC 26
|
||||
|
||||
#define STM32F4_APB2_RESET(bit) (STM32F4_RCC_APB2_##bit + (0x24 * 8))
|
||||
#define STM32F4_APB2_CLOCK(bit) (STM32F4_RCC_APB2_##bit + (0x44 * 8))
|
||||
|
||||
#endif /* _DT_BINDINGS_MFD_STM32F4_RCC_H */
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Endless Mobile, Inc.
|
||||
* Author: Carlo Caione <carlo@endlessm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MESON_SM_FW_H_
|
||||
#define _MESON_SM_FW_H_
|
||||
|
||||
enum {
|
||||
SM_EFUSE_READ,
|
||||
SM_EFUSE_WRITE,
|
||||
SM_EFUSE_USER_MAX,
|
||||
};
|
||||
|
||||
struct meson_sm_firmware;
|
||||
|
||||
int meson_sm_call(unsigned int cmd_index, u32 *ret, u32 arg0, u32 arg1,
|
||||
u32 arg2, u32 arg3, u32 arg4);
|
||||
int meson_sm_call_write(void *buffer, unsigned int b_size, unsigned int cmd_index,
|
||||
u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4);
|
||||
int meson_sm_call_read(void *buffer, unsigned int cmd_index, u32 arg0, u32 arg1,
|
||||
u32 arg2, u32 arg3, u32 arg4);
|
||||
|
||||
#endif /* _MESON_SM_FW_H_ */
|
|
@ -29,8 +29,8 @@ struct gpmc_nand_regs;
|
|||
struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *regs,
|
||||
int cs);
|
||||
#else
|
||||
static inline gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *regs,
|
||||
int cs)
|
||||
static inline struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *regs,
|
||||
int cs)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -55,11 +55,16 @@ void qcom_smd_driver_unregister(struct qcom_smd_driver *drv);
|
|||
struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *channel,
|
||||
const char *name,
|
||||
qcom_smd_cb_t cb);
|
||||
void qcom_smd_close_channel(struct qcom_smd_channel *channel);
|
||||
void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel);
|
||||
void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data);
|
||||
int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len);
|
||||
|
||||
|
||||
struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent,
|
||||
struct device_node *node);
|
||||
int qcom_smd_unregister_edge(struct qcom_smd_edge *edge);
|
||||
|
||||
#else
|
||||
|
||||
static inline int qcom_smd_driver_register(struct qcom_smd_driver *drv)
|
||||
|
@ -83,14 +88,20 @@ qcom_smd_open_channel(struct qcom_smd_channel *channel,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel)
|
||||
static inline void qcom_smd_close_channel(struct qcom_smd_channel *channel)
|
||||
{
|
||||
/* This shouldn't be possible */
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static inline void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel)
|
||||
{
|
||||
/* This shouldn't be possible */
|
||||
WARN_ON(1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data)
|
||||
static inline void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data)
|
||||
{
|
||||
/* This shouldn't be possible */
|
||||
WARN_ON(1);
|
||||
|
@ -104,6 +115,20 @@ static inline int qcom_smd_send(struct qcom_smd_channel *channel,
|
|||
return -ENXIO;
|
||||
}
|
||||
|
||||
static inline struct qcom_smd_edge *
|
||||
qcom_smd_register_edge(struct device *parent,
|
||||
struct device_node *node)
|
||||
{
|
||||
return ERR_PTR(-ENXIO);
|
||||
}
|
||||
|
||||
static inline int qcom_smd_unregister_edge(struct qcom_smd_edge *edge)
|
||||
{
|
||||
/* This shouldn't be possible */
|
||||
WARN_ON(1);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define module_qcom_smd_driver(__smd_driver) \
|
||||
|
|
Loading…
Reference in New Issue