implementation for the IDs to use. For Juno
R0 and Juno R1 refer to [3].
+Power domain bindings for the power domains based on SCPI Message Protocol
+------------------------------------------------------------
+
+This binding uses the generic power domain binding[4].
+
+PM domain providers
+===================
+
+Required properties:
+ - #power-domain-cells : Should be 1. Contains the device or the power
+ domain ID value used by SCPI commands.
+ - num-domains: Total number of power domains provided by SCPI. This is
+ needed as the SCPI message protocol lacks a mechanism to
+ query this information at runtime.
+
+PM domain consumers
+===================
+
+Required properties:
+ - power-domains : A phandle and PM domain specifier as defined by bindings of
+ the power controller specified by phandle.
+
[0] http://infocenter.arm.com/help/topic/com.arm.doc.dui0922b/index.html
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/thermal/thermal.txt
[3] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0922b/apas03s22.html
+[4] Documentation/devicetree/bindings/power/power_domain.txt
Example:
compatible = "arm,scpi-sensors";
#thermal-sensor-cells = <1>;
};
+
+ scpi_devpd: scpi-power-domains {
+ compatible = "arm,scpi-power-domains";
+ num-domains = <2>;
+ #power-domain-cells = <1>;
+ };
};
cpu@0 {
...
reg = <0 0x7ff60000 0 0x1000>;
clocks = <&scpi_clk 4>;
+ power-domains = <&scpi_devpd 1>;
};
thermal-zones {
temperature sensor provided by SCP firmware to setup a thermal
zone. The ID "3" is the sensor identifier for the temperature sensor
as used by the firmware.
+
+The num-domains property in scpi-power-domains domain specifies that
+SCPI provides 2 power domains. The hdlcd node uses the power domain with
+domain ID 1.
--- /dev/null
+NVIDIA Tegra ACONNECT Bus
+
+The Tegra ACONNECT bus is an AXI switch which is used to connnect various
+components inside the Audio Processing Engine (APE). All CPU accesses to
+the APE subsystem go through the ACONNECT via an APB to AXI wrapper.
+
+Required properties:
+- compatible: Must be "nvidia,tegra210-aconnect".
+- clocks: Must contain the entries for the APE clock (TEGRA210_CLK_APE),
+ and APE interface clock (TEGRA210_CLK_APB2APE).
+- clock-names: Must contain the names "ape" and "apb2ape" for the corresponding
+ 'clocks' entries.
+- power-domains: Must contain a phandle that points to the audio powergate
+ (namely 'aud') for Tegra210.
+- #address-cells: The number of cells used to represent physical base addresses
+ in the aconnect address space. Should be 1.
+- #size-cells: The number of cells used to represent the size of an address
+ range in the aconnect address space. Should be 1.
+- ranges: Mapping of the aconnect address space to the CPU address space.
+
+All devices accessed via the ACONNNECT are described by child-nodes.
+
+Example:
+
+ aconnect@702c0000 {
+ compatible = "nvidia,tegra210-aconnect";
+ clocks = <&tegra_car TEGRA210_CLK_APE>,
+ <&tegra_car TEGRA210_CLK_APB2APE>;
+ clock-names = "ape", "apb2ape";
+ power-domains = <&pd_audio>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x702c0000 0x0 0x702c0000 0x00040000>;
+
+ status = "disabled";
+
+ child1 {
+ ...
+ };
+
+ child2 {
+ ...
+ };
+ };
* Clock bindings for the Cirrus Logic CLPS711X CPUs
Required properties:
-- compatible : Shall contain "cirrus,clps711x-clk".
+- compatible : Shall contain "cirrus,ep7209-clk".
- reg : Address of the internal register set.
- startup-frequency: Factory set CPU startup frequency in HZ.
- #clock-cells : Should be <1>.
Example:
clks: clks@80000000 {
#clock-cells = <1>;
- compatible = "cirrus,ep7312-clk", "cirrus,clps711x-clk";
+ compatible = "cirrus,ep7312-clk", "cirrus,ep7209-clk";
reg = <0x80000000 0xc000>;
startup-frequency = <73728000>;
};
* Currus Logic CLPS711X Framebuffer
Required properties:
-- compatible: Shall contain "cirrus,clps711x-fb".
+- compatible: Shall contain "cirrus,ep7209-fb".
- reg : Physical base address and length of the controller's registers +
location and size of the framebuffer memory.
- clocks : phandle + clock specifier pair of the FB reference clock.
Example:
fb: fb@800002c0 {
- compatible = "cirrus,ep7312-fb", "cirrus,clps711x-fb";
+ compatible = "cirrus,ep7312-fb", "cirrus,ep7209-fb";
reg = <0x800002c0 0xd44>, <0x60000000 0xc000>;
clocks = <&clks 2>;
lcd-supply = <®5v0>;
* Cirrus Logic CLPS711X matrix keypad device tree bindings
Required Properties:
-- compatible: Shall contain "cirrus,clps711x-keypad".
+- compatible: Shall contain "cirrus,ep7209-keypad".
- row-gpios: List of GPIOs used as row lines.
- poll-interval: Poll interval time in milliseconds.
- linux,keymap: The definition can be found at
Example:
keypad {
- compatible = "cirrus,ep7312-keypad", "cirrus,clps711x-keypad";
+ compatible = "cirrus,ep7312-keypad", "cirrus,ep7209-keypad";
autorepeat;
poll-interval = <120>;
row-gpios = <&porta 0 0>,
Required properties:
-- compatible: Should be "cirrus,clps711x-intc".
+- compatible: Should be "cirrus,ep7209-intc".
- reg: Specifies base physical address of the registers set.
- interrupt-controller: Identifies the node as an interrupt controller.
- #interrupt-cells: Specifies the number of cells needed to encode an
Example:
intc: interrupt-controller {
- compatible = "cirrus,clps711x-intc";
+ compatible = "cirrus,ep7312-intc", "cirrus,ep7209-intc";
reg = <0x80000000 0x4000>;
interrupt-controller;
#interrupt-cells = <1>;
--- /dev/null
+Device-Tree bindings for LIRC TX driver for Nokia N900(RX51)
+
+Required properties:
+ - compatible: should be "nokia,n900-ir".
+ - pwms: specifies PWM used for IR signal transmission.
+
+Example node:
+
+ pwm9: dmtimer-pwm@9 {
+ compatible = "ti,omap-dmtimer-pwm";
+ ti,timers = <&timer9>;
+ ti,clock-source = <0x00>; /* timer_sys_ck */
+ #pwm-cells = <3>;
+ };
+
+ ir: n900-ir {
+ compatible = "nokia,n900-ir";
+
+ pwms = <&pwm9 0 26316 0>; /* 38000 Hz */
+ };
- clock-names : from common clock binding: must contain "mfc",
corresponding to entry in the clocks property.
- - samsung,mfc-r : Base address of the first memory bank used by MFC
- for DMA contiguous memory allocation and its size.
-
- - samsung,mfc-l : Base address of the second memory bank used by MFC
- for DMA contiguous memory allocation and its size.
-
Optional properties:
- power-domains : power-domain property defined with a phandle
to respective power domain.
+ - memory-region : from reserved memory binding: phandles to two reserved
+ memory regions, first is for "left" mfc memory bus interfaces,
+ second if for the "right" mfc memory bus, used when no SYSMMU
+ support is available
+
+Obsolete properties:
+ - samsung,mfc-r, samsung,mfc-l : support removed, please use memory-region
+ property instead
+
Example:
SoC specific DT entry:
clock-names = "mfc";
};
+Reserved memory specific DT entry for given board (see reserved memory binding
+for more information):
+
+reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ mfc_left: region@51000000 {
+ compatible = "shared-dma-pool";
+ no-map;
+ reg = <0x51000000 0x800000>;
+ };
+
+ mfc_right: region@43000000 {
+ compatible = "shared-dma-pool";
+ no-map;
+ reg = <0x43000000 0x800000>;
+ };
+};
+
Board specific DT entry:
codec@13400000 {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
+ memory-region = <&mfc_left>, <&mfc_right>;
};
--- /dev/null
+* Device tree bindings for Atmel EBI
+
+The External Bus Interface (EBI) controller is a bus where you can connect
+asynchronous (NAND, NOR, SRAM, ....) and synchronous memories (SDR/DDR SDRAMs).
+The EBI provides a glue-less interface to asynchronous memories through the SMC
+(Static Memory Controller).
+
+Required properties:
+
+- compatible: "atmel,at91sam9260-ebi"
+ "atmel,at91sam9261-ebi"
+ "atmel,at91sam9263-ebi0"
+ "atmel,at91sam9263-ebi1"
+ "atmel,at91sam9rl-ebi"
+ "atmel,at91sam9g45-ebi"
+ "atmel,at91sam9x5-ebi"
+ "atmel,sama5d3-ebi"
+
+- reg: Contains offset/length value for EBI memory mapping.
+ This property might contain several entries if the EBI
+ memory range is not contiguous
+
+- #address-cells: Must be 2.
+ The first cell encodes the CS.
+ The second cell encode the offset into the CS memory
+ range.
+
+- #size-cells: Must be set to 1.
+
+- ranges: Encodes CS to memory region association.
+
+- clocks: Clock feeding the EBI controller.
+ See clock-bindings.txt
+
+Children device nodes are representing device connected to the EBI bus.
+
+Required device node properties:
+
+- reg: Contains the chip-select id, the offset and the length
+ of the memory region requested by the device.
+
+EBI bus configuration will be defined directly in the device subnode.
+
+Optional EBI/SMC properties:
+
+- atmel,smc-bus-width: width of the asynchronous device's data bus
+ 8, 16 or 32.
+ Default to 8 when undefined.
+
+- atmel,smc-byte-access-type "write" or "select" (see Atmel datasheet).
+ Default to "select" when undefined.
+
+- atmel,smc-read-mode "nrd" or "ncs".
+ Default to "ncs" when undefined.
+
+- atmel,smc-write-mode "nwe" or "ncs".
+ Default to "ncs" when undefined.
+
+- atmel,smc-exnw-mode "disabled", "frozen" or "ready".
+ Default to "disabled" when undefined.
+
+- atmel,smc-page-mode enable page mode if present. The provided value
+ defines the page size (supported values: 4, 8,
+ 16 and 32).
+
+- atmel,smc-tdf-mode: "normal" or "optimized". When set to
+ "optimized" the data float time is optimized
+ depending on the next device being accessed
+ (next device setup time is subtracted to the
+ current device data float time).
+ Default to "normal" when undefined.
+
+If at least one atmel,smc- property is defined the following SMC timing
+properties become mandatory. In the other hand, if none of the atmel,smc-
+properties are specified, we assume that the EBI bus configuration will be
+handled by the sub-device driver, and none of those properties should be
+defined.
+
+All the timings are expressed in nanoseconds (see Atmel datasheet for a full
+description).
+
+- atmel,smc-ncs-rd-setup-ns
+- atmel,smc-nrd-setup-ns
+- atmel,smc-ncs-wr-setup-ns
+- atmel,smc-nwe-setup-ns
+- atmel,smc-ncs-rd-pulse-ns
+- atmel,smc-nrd-pulse-ns
+- atmel,smc-ncs-wr-pulse-ns
+- atmel,smc-nwe-pulse-ns
+- atmel,smc-nwe-cycle-ns
+- atmel,smc-nrd-cycle-ns
+- atmel,smc-tdf-ns
+
+Example:
+
+ ebi: ebi@10000000 {
+ compatible = "atmel,sama5d3-ebi";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ atmel,smc = <&hsmc>;
+ atmel,matrix = <&matrix>;
+ reg = <0x10000000 0x10000000
+ 0x40000000 0x30000000>;
+ ranges = <0x0 0x0 0x10000000 0x10000000
+ 0x1 0x0 0x40000000 0x10000000
+ 0x2 0x0 0x50000000 0x10000000
+ 0x3 0x0 0x60000000 0x10000000>;
+ clocks = <&mck>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ebi_addr>;
+
+ nor: flash@0,0 {
+ compatible = "cfi-flash";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x0 0x0 0x1000000>;
+ bank-width = <2>;
+
+ atmel,smc-read-mode = "nrd";
+ atmel,smc-write-mode = "nwe";
+ atmel,smc-bus-width = <16>;
+ atmel,smc-ncs-rd-setup-ns = <0>;
+ atmel,smc-ncs-wr-setup-ns = <0>;
+ atmel,smc-nwe-setup-ns = <8>;
+ atmel,smc-nrd-setup-ns = <16>;
+ atmel,smc-ncs-rd-pulse-ns = <84>;
+ atmel,smc-ncs-wr-pulse-ns = <84>;
+ atmel,smc-nrd-pulse-ns = <76>;
+ atmel,smc-nwe-pulse-ns = <76>;
+ atmel,smc-nrd-cycle-ns = <107>;
+ atmel,smc-nwe-cycle-ns = <84>;
+ atmel,smc-tdf-ns = <16>;
+ };
+ };
+
- "renesas,r8a7793-sysc" (R-Car M2-N)
- "renesas,r8a7794-sysc" (R-Car E2)
- "renesas,r8a7795-sysc" (R-Car H3)
+ - "renesas,r8a7796-sysc" (R-Car M3-W)
- reg: Address start and address range for the device.
- #power-domain-cells: Must be 1.
* Cirris Logic CLPS711X PWM controller
Required properties:
-- compatible: Shall contain "cirrus,clps711x-pwm".
+- compatible: Shall contain "cirrus,ep7209-pwm".
- reg: Physical base address and length of the controller's registers.
- clocks: phandle + clock specifier pair of the PWM reference clock.
- #pwm-cells: Should be 1. The cell specifies the index of the channel.
Example:
pwm: pwm@80000400 {
- compatible = "cirrus,ep7312-pwm",
- "cirrus,clps711x-pwm";
+ compatible = "cirrus,ep7312-pwm", "cirrus,ep7209-pwm";
reg = <0x80000400 0x4>;
clocks = <&clks 8>;
#pwm-cells = <1>;
Optional properties:
- ti,prescaler: Should be a value between 0 and 7, see the timers datasheet
+- ti,clock-source: Set dmtimer parent clock, values between 0 and 2:
+ - 0x00 - high-frequency system clock (timer_sys_ck)
+ - 0x01 - 32-kHz always-on clock (timer_32k_ck)
+ - 0x02 - external clock (timer_ext_ck, OMAP2 only)
Example:
pwm9: dmtimer-pwm@9 {
--- /dev/null
+Amlogic Meson SoC Reset Controller
+=======================================
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Required properties:
+- compatible: Should be "amlogic,meson8b-reset" or "amlogic,meson-gxbb-reset"
+- reg: should contain the register address base
+- #reset-cells: 1, see below
+
+example:
+
+reset: reset-controller {
+ compatible = "amlogic,meson-gxbb-reset";
+ reg = <0x0 0x04404 0x0 0x20>;
+ #reset-cells = <1>;
+};
hi6220 SoC.
Required properties:
-- compatible: may be "hisilicon,hi6220-sysctrl"
+- compatible: should be one of the following:
+ - "hisilicon,hi6220-sysctrl", "syscon" : For peripheral reset controller.
+ - "hisilicon,hi6220-mediactrl", "syscon" : For media reset controller.
- reg: should be register base and length as documented in the
datasheet
- #reset-cells: 1, see below
--- /dev/null
+TI SysCon Reset Controller
+=======================
+
+Almost all SoCs have hardware modules that require reset control in addition
+to clock and power control for their functionality. The reset control is
+typically provided by means of memory-mapped I/O registers. These registers are
+sometimes a part of a larger register space region implementing various
+functionalities. This register range is best represented as a syscon node to
+allow multiple entities to access their relevant registers in the common
+register space.
+
+A SysCon Reset Controller node defines a device that uses a syscon node
+and provides reset management functionality for various hardware modules
+present on the SoC.
+
+SysCon Reset Controller Node
+============================
+Each of the reset provider/controller nodes should be a child of a syscon
+node and have the following properties.
+
+Required properties:
+--------------------
+ - compatible : Should be,
+ "ti,k2e-pscrst"
+ "ti,k2l-pscrst"
+ "ti,k2hk-pscrst"
+ "ti,syscon-reset"
+ - #reset-cells : Should be 1. Please see the reset consumer node below
+ for usage details
+ - ti,reset-bits : Contains the reset control register information
+ Should contain 7 cells for each reset exposed to
+ consumers, defined as:
+ Cell #1 : offset of the reset assert control
+ register from the syscon register base
+ Cell #2 : bit position of the reset in the reset
+ assert control register
+ Cell #3 : offset of the reset deassert control
+ register from the syscon register base
+ Cell #4 : bit position of the reset in the reset
+ deassert control register
+ Cell #5 : offset of the reset status register
+ from the syscon register base
+ Cell #6 : bit position of the reset in the
+ reset status register
+ Cell #7 : Flags used to control reset behavior,
+ availible flags defined in the DT include
+ file <dt-bindings/reset/ti-syscon.h>
+
+SysCon Reset Consumer Nodes
+===========================
+Each of the reset consumer nodes should have the following properties,
+in addition to their own properties.
+
+Required properties:
+--------------------
+ - resets : A phandle to the reset controller node and an index number
+ to a reset specifier as defined above.
+
+Please also refer to Documentation/devicetree/bindings/reset/reset.txt for
+common reset controller usage by consumers.
+
+Example:
+--------
+The following example demonstrates a syscon node, the reset controller node
+using the syscon node, and a consumer (a DSP device) on the TI Keystone 2
+Edison SoC.
+
+/ {
+ soc {
+ psc: power-sleep-controller@02350000 {
+ compatible = "syscon", "simple-mfd";
+ reg = <0x02350000 0x1000>;
+
+ pscrst: psc-reset {
+ compatible = "ti,k2e-pscrst", "ti,syscon-reset";
+ #reset-cells = <1>;
+
+ ti,reset-bits = <
+ 0xa3c 8 0xa3c 8 0x83c 8 (ASSERT_SET|DEASSERT_CLEAR|STATUS_SET) /* 0: pcrst-dsp0 */
+ 0xa40 5 0xa44 3 0 0 (ASSERT_SET|DEASSERT_CLEAR|STATUS_NONE) /* 1: pcrst-example */
+ >;
+ };
+ };
+
+ dsp0: dsp0 {
+ ...
+ resets = <&pscrst 0>;
+ ...
+ };
+ };
+};
* Cirrus Logic CLPS711X Universal Asynchronous Receiver/Transmitter (UART)
Required properties:
-- compatible: Should be "cirrus,clps711x-uart".
+- compatible: Should be "cirrus,ep7209-uart".
- reg: Address and length of the register set for the device.
- interrupts: Should contain UART TX and RX interrupt.
- clocks: Should contain UART core clock number.
};
uart1: uart@80000480 {
- compatible = "cirrus,clps711x-uart";
+ compatible = "cirrus,ep7312-uart","cirrus,ep7209-uart";
reg = <0x80000480 0x80>;
interrupts = <12 13>;
clocks = <&clks 11>;
Value type: <u32>
Definition: must be 2 - denoting the bit in the entry and IRQ flags
-- #qcom,state-cells:
+- #qcom,smem-state-cells:
Usage: required for outgoing entries
Value type: <u32>
Definition: must be 1 - denoting the bit in the entry
wcnss_smp2p_out: master-kernel {
qcom,entry-name = "master-kernel";
- #qcom,state-cells = <1>;
+ #qcom,smem-state-cells = <1>;
};
wcnss_smp2p_in: slave-kernel {
Definition: specifies the offset, in words, of the first bit for this
entry
-- #qcom,state-cells:
+- #qcom,smem-state-cells:
Usage: required for local entry
Value type: <u32>
Definition: must be 1 - denotes bit number
apps_smsm: apps@0 {
reg = <0>;
- #qcom,state-cells = <1>;
+ #qcom,smem-state-cells = <1>;
};
wcnss_smsm: wcnss@7 {
* Cirrus Logic CLPS711X Timer Counter
Required properties:
-- compatible: Shall contain "cirrus,clps711x-timer".
+- compatible: Shall contain "cirrus,ep7209-timer".
- reg : Address and length of the register set.
- interrupts: The interrupt number of the timer.
- clocks : phandle of timer reference clock.
};
timer1: timer@80000300 {
- compatible = "cirrus,ep7312-timer", "cirrus,clps711x-timer";
+ compatible = "cirrus,ep7312-timer", "cirrus,ep7209-timer";
reg = <0x80000300 0x4>;
interrupts = <8>;
clocks = <&clks 5>;
};
timer2: timer@80000340 {
- compatible = "cirrus,ep7312-timer", "cirrus,clps711x-timer";
+ compatible = "cirrus,ep7312-timer", "cirrus,ep7209-timer";
reg = <0x80000340 0x4>;
interrupts = <9>;
clocks = <&clks 6>;
devm_regulator_put()
devm_regulator_register()
+RESET
+ devm_reset_control_get()
+ devm_reset_controller_register()
+
SLAVE DMA ENGINE
devm_acpi_dma_controller_register()
L: linux-arm-msm@vger.kernel.org
L: linux-soc@vger.kernel.org
S: Maintained
+F: Documentation/devicetree/bindings/soc/qcom/
F: arch/arm/boot/dts/qcom-*.dts
F: arch/arm/boot/dts/qcom-*.dtsi
F: arch/arm/mach-qcom/
T: git git://git.linaro.org/people/ulfh/clk.git
S: Maintained
F: drivers/clk/ux500/
-F: include/linux/platform_data/clk-ux500.h
ARM/VERSATILE EXPRESS PLATFORM
M: Liviu Dudau <liviu.dudau@arm.com>
M: Florian Fainelli <f.fainelli@gmail.com>
M: Ray Jui <rjui@broadcom.com>
M: Scott Branden <sbranden@broadcom.com>
-L: bcm-kernel-feedback-list@broadcom.com
+M: bcm-kernel-feedback-list@broadcom.com
T: git git://github.com/broadcom/mach-bcm
S: Maintained
+N: bcm281*
+N: bcm113*
+N: bcm216*
+N: kona
F: arch/arm/mach-bcm/
-F: arch/arm/boot/dts/bcm113*
-F: arch/arm/boot/dts/bcm216*
-F: arch/arm/boot/dts/bcm281*
-F: arch/arm64/boot/dts/broadcom/
-F: arch/arm/configs/bcm_defconfig
-F: drivers/mmc/host/sdhci-bcm-kona.c
-F: drivers/clocksource/bcm_kona_timer.c
BROADCOM BCM2835 ARM ARCHITECTURE
M: Stephen Warren <swarren@wwwdotorg.org>
BROADCOM BCM5301X ARM ARCHITECTURE
M: Hauke Mehrtens <hauke@hauke-m.de>
+M: Rafał Miłecki <zajec5@gmail.com>
+M: bcm-kernel-feedback-list@broadcom.com
L: linux-arm-kernel@lists.infradead.org
S: Maintained
F: arch/arm/mach-bcm/bcm_5301x.c
-F: arch/arm/boot/dts/bcm5301x.dtsi
+F: arch/arm/boot/dts/bcm5301x*.dtsi
F: arch/arm/boot/dts/bcm470*
BROADCOM BCM63XX ARM ARCHITECTURE
M: Florian Fainelli <f.fainelli@gmail.com>
+M: bcm-kernel-feedback-list@broadcom.com
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-L: bcm-kernel-feedback-list@broadcom.com
T: git git://github.com/broadcom/stblinux.git
S: Maintained
-F: arch/arm/mach-bcm/bcm63xx.c
-F: arch/arm/include/debug/bcm63xx.S
+N: bcm63xx
BROADCOM BCM63XX/BCM33XX UDC DRIVER
M: Kevin Cernekee <cernekee@gmail.com>
M: Brian Norris <computersforpeace@gmail.com>
M: Gregory Fong <gregory.0xf0@gmail.com>
M: Florian Fainelli <f.fainelli@gmail.com>
+M: bcm-kernel-feedback-list@broadcom.com
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-L: bcm-kernel-feedback-list@broadcom.com
T: git git://github.com/broadcom/stblinux.git
S: Maintained
F: arch/arm/mach-bcm/*brcmstb*
M: Ray Jui <rjui@broadcom.com>
M: Scott Branden <sbranden@broadcom.com>
M: Jon Mason <jonmason@broadcom.com>
+M: bcm-kernel-feedback-list@broadcom.com
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-L: bcm-kernel-feedback-list@broadcom.com
T: git git://github.com/broadcom/cygnus-linux.git
S: Maintained
N: iproc
N: cygnus
-N: nsp
+N: bcm[-_]nsp
N: bcm9113*
N: bcm9583*
N: bcm9585*
N: bcm585*
N: bcm586*
N: bcm88312
+F: arch/arm64/boot/dts/broadcom/ns2*
+F: drivers/clk/bcm/clk-ns*
+F: drivers/pinctrl/bcm/pinctrl-ns*
BROADCOM BRCMSTB GPIO DRIVER
M: Gregory Fong <gregory.0xf0@gmail.com>
BROADCOM VULCAN ARM64 SOC
M: Jayachandran C. <jchandra@broadcom.com>
+M: bcm-kernel-feedback-list@broadcom.com
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-L: bcm-kernel-feedback-list@broadcom.com
S: Maintained
F: arch/arm64/boot/dts/broadcom/vulcan*
--- /dev/null
+/*
+ * Samsung's Exynos SoC MFC (Video Codec) reserved memory common definition.
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+/ {
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ mfc_left: region@51000000 {
+ compatible = "shared-dma-pool";
+ no-map;
+ reg = <0x51000000 0x800000>;
+ };
+
+ mfc_right: region@43000000 {
+ compatible = "shared-dma-pool";
+ no-map;
+ reg = <0x43000000 0x800000>;
+ };
+ };
+};
#include "exynos4210.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
+#include "exynos-mfc-reserved-memory.dtsi"
/ {
model = "Insignal Origen evaluation board based on Exynos4210";
};
&mfc {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
+ memory-region = <&mfc_left>, <&mfc_right>;
status = "okay";
};
/dts-v1/;
#include "exynos4210.dtsi"
#include <dt-bindings/gpio/gpio.h>
+#include "exynos-mfc-reserved-memory.dtsi"
/ {
model = "Samsung smdkv310 evaluation board based on Exynos4210";
};
&mfc {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
+ memory-region = <&mfc_left>, <&mfc_right>;
status = "okay";
};
#include "exynos4412.dtsi"
#include "exynos4412-ppmu-common.dtsi"
#include <dt-bindings/gpio/gpio.h>
+#include "exynos-mfc-reserved-memory.dtsi"
/ {
chosen {
clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
};
+&mfc {
+ memory-region = <&mfc_left>, <&mfc_right>;
+ status = "okay";
+};
+
&mixer {
status = "okay";
};
#include "exynos4412.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
+#include "exynos-mfc-reserved-memory.dtsi"
/ {
model = "Insignal Origen evaluation board based on Exynos4412";
};
&mfc {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
+ memory-region = <&mfc_left>, <&mfc_right>;
status = "okay";
};
/dts-v1/;
#include "exynos4412.dtsi"
+#include "exynos-mfc-reserved-memory.dtsi"
/ {
model = "Samsung SMDK evaluation board based on Exynos4412";
};
&mfc {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
+ memory-region = <&mfc_left>, <&mfc_right>;
status = "okay";
};
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/input/input.h>
#include "exynos5250.dtsi"
+#include "exynos-mfc-reserved-memory.dtsi"
/ {
model = "Insignal Arndale evaluation board based on EXYNOS5250";
};
&mfc {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
+ memory-region = <&mfc_left>, <&mfc_right>;
};
&mmc_0 {
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include "exynos5250.dtsi"
+#include "exynos-mfc-reserved-memory.dtsi"
/ {
model = "SAMSUNG SMDK5250 board based on EXYNOS5250";
};
&mfc {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
+ memory-region = <&mfc_left>, <&mfc_right>;
};
&mmc_0 {
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/input/input.h>
#include "exynos5250.dtsi"
+#include "exynos-mfc-reserved-memory.dtsi"
/ {
model = "Google Spring";
};
&mfc {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
+ memory-region = <&mfc_left>, <&mfc_right>;
};
&mmc_0 {
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/clock/samsung,s2mps11.h>
+#include "exynos-mfc-reserved-memory.dtsi"
/ {
model = "Insignal Arndale Octa evaluation board based on EXYNOS5420";
};
&mfc {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
+ memory-region = <&mfc_left>, <&mfc_right>;
};
&mmc_0 {
#include <dt-bindings/regulator/maxim,max77802.h>
#include "exynos5420.dtsi"
#include "exynos5420-cpus.dtsi"
+#include "exynos-mfc-reserved-memory.dtsi"
/ {
model = "Google Peach Pit Rev 6+";
};
&mfc {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
+ memory-region = <&mfc_left>, <&mfc_right>;
};
&mmc_0 {
#include "exynos5420.dtsi"
#include "exynos5420-cpus.dtsi"
#include <dt-bindings/gpio/gpio.h>
+#include "exynos-mfc-reserved-memory.dtsi"
/ {
model = "Samsung SMDK5420 board based on EXYNOS5420";
};
&mfc {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
+ memory-region = <&mfc_left>, <&mfc_right>;
};
&mmc_0 {
#include "exynos5800.dtsi"
#include "exynos5422-cpus.dtsi"
#include "exynos5422-cpu-thermal.dtsi"
+#include "exynos-mfc-reserved-memory.dtsi"
/ {
memory {
};
&mfc {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
+ memory-region = <&mfc_left>, <&mfc_right>;
};
&mmc_0 {
#include <dt-bindings/regulator/maxim,max77802.h>
#include "exynos5800.dtsi"
#include "exynos5420-cpus.dtsi"
+#include "exynos-mfc-reserved-memory.dtsi"
/ {
model = "Google Peach Pi Rev 10+";
};
&mfc {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
+ memory-region = <&mfc_left>, <&mfc_right>;
};
&mmc_0 {
obj-$(CONFIG_EXYNOS5420_MCPM) += mcpm-exynos.o
CFLAGS_mcpm-exynos.o += -march=armv7-a
-
-obj-$(CONFIG_S5P_DEV_MFC) += s5p-dev-mfc.o
#include <mach/map.h>
#include "common.h"
-#include "mfc.h"
static struct map_desc exynos4_iodesc[] __initdata = {
{
NULL
};
-static void __init exynos_reserve(void)
-{
-#ifdef CONFIG_S5P_DEV_MFC
- int i;
- char *mfc_mem[] = {
- "samsung,mfc-v5",
- "samsung,mfc-v6",
- "samsung,mfc-v7",
- "samsung,mfc-v8",
- };
-
- for (i = 0; i < ARRAY_SIZE(mfc_mem); i++)
- if (of_scan_flat_dt(s5p_fdt_alloc_mfc_mem, mfc_mem[i]))
- break;
-#endif
-}
-
static void __init exynos_dt_fixup(void)
{
/*
.init_machine = exynos_dt_machine_init,
.init_late = exynos_init_late,
.dt_compat = exynos_dt_compat,
- .reserve = exynos_reserve,
.dt_fixup = exynos_dt_fixup,
MACHINE_END
+++ /dev/null
-/*
- * Copyright (C) 2013 Samsung Electronics Co.Ltd
- *
- * 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.
- */
-
-#ifndef __MACH_EXYNOS_MFC_H
-#define __MACH_EXYNOS_MFC_H __FILE__
-
-int __init s5p_fdt_alloc_mfc_mem(unsigned long node, const char *uname,
- int depth, void *data);
-
-#endif /* __MACH_EXYNOS_MFC_H */
+++ /dev/null
-/*
- * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
- *
- * Base S5P MFC resource and device definitions
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/memblock.h>
-#include <linux/ioport.h>
-#include <linux/of_fdt.h>
-#include <linux/of.h>
-
-static struct platform_device s5p_device_mfc_l;
-static struct platform_device s5p_device_mfc_r;
-
-struct s5p_mfc_dt_meminfo {
- unsigned long loff;
- unsigned long lsize;
- unsigned long roff;
- unsigned long rsize;
- char *compatible;
-};
-
-struct s5p_mfc_reserved_mem {
- phys_addr_t base;
- unsigned long size;
- struct device *dev;
-};
-
-static struct s5p_mfc_reserved_mem s5p_mfc_mem[2] __initdata;
-
-
-static void __init s5p_mfc_reserve_mem(phys_addr_t rbase, unsigned int rsize,
- phys_addr_t lbase, unsigned int lsize)
-{
- int i;
-
- s5p_mfc_mem[0].dev = &s5p_device_mfc_r.dev;
- s5p_mfc_mem[0].base = rbase;
- s5p_mfc_mem[0].size = rsize;
-
- s5p_mfc_mem[1].dev = &s5p_device_mfc_l.dev;
- s5p_mfc_mem[1].base = lbase;
- s5p_mfc_mem[1].size = lsize;
-
- for (i = 0; i < ARRAY_SIZE(s5p_mfc_mem); i++) {
- struct s5p_mfc_reserved_mem *area = &s5p_mfc_mem[i];
- if (memblock_remove(area->base, area->size)) {
- printk(KERN_ERR "Failed to reserve memory for MFC device (%ld bytes at 0x%08lx)\n",
- area->size, (unsigned long) area->base);
- area->base = 0;
- }
- }
-}
-
-int __init s5p_fdt_alloc_mfc_mem(unsigned long node, const char *uname,
- int depth, void *data)
-{
- const __be32 *prop;
- int len;
- struct s5p_mfc_dt_meminfo mfc_mem;
-
- if (!data)
- return 0;
-
- if (!of_flat_dt_is_compatible(node, data))
- return 0;
-
- prop = of_get_flat_dt_prop(node, "samsung,mfc-l", &len);
- if (!prop || (len != 2 * sizeof(unsigned long)))
- return 0;
-
- mfc_mem.loff = be32_to_cpu(prop[0]);
- mfc_mem.lsize = be32_to_cpu(prop[1]);
-
- prop = of_get_flat_dt_prop(node, "samsung,mfc-r", &len);
- if (!prop || (len != 2 * sizeof(unsigned long)))
- return 0;
-
- mfc_mem.roff = be32_to_cpu(prop[0]);
- mfc_mem.rsize = be32_to_cpu(prop[1]);
-
- s5p_mfc_reserve_mem(mfc_mem.roff, mfc_mem.rsize,
- mfc_mem.loff, mfc_mem.lsize);
-
- return 1;
-}
#if defined(CONFIG_IR_RX51) || defined(CONFIG_IR_RX51_MODULE)
static struct lirc_rx51_platform_data rx51_lirc_data = {
.set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat,
- .pwm_timer = 9, /* Use GPT 9 for CIR */
-#if IS_ENABLED(CONFIG_OMAP_DM_TIMER)
- .dmtimer = &pwm_dmtimer_pdata,
-#endif
-
};
static struct platform_device rx51_lirc_device = {
},
};
-static struct platform_device rx51_lirc_device;
-
static void __init nokia_n900_legacy_init(void)
{
hsmmc2_internal_input_clk();
pr_info("RX-51: Registering OMAP3 HWRNG device\n");
platform_device_register(&omap3_rom_rng_device);
-
}
-
- platform_device_register(&rx51_lirc_device);
}
static void __init omap3_tao3530_legacy_init(void)
static struct lirc_rx51_platform_data __maybe_unused rx51_lirc_data = {
.set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat,
- .pwm_timer = 9, /* Use GPT 9 for CIR */
-#if IS_ENABLED(CONFIG_OMAP_DM_TIMER)
- .dmtimer = &pwm_dmtimer_pdata,
-#endif
};
static struct platform_device __maybe_unused rx51_lirc_device = {
&omap3_iommu_pdata),
OF_DEV_AUXDATA("ti,omap3-hsmmc", 0x4809c000, "4809c000.mmc", &mmc_pdata[0]),
OF_DEV_AUXDATA("ti,omap3-hsmmc", 0x480b4000, "480b4000.mmc", &mmc_pdata[1]),
+ OF_DEV_AUXDATA("nokia,n900-ir", 0, "n900-ir", &rx51_lirc_data),
/* Only on am3517 */
OF_DEV_AUXDATA("ti,davinci_mdio", 0x5c030000, "davinci_mdio.0", NULL),
OF_DEV_AUXDATA("ti,am3517-emac", 0x5c000000, "davinci_emac.0",
static void __init r8a7779_sysc_init(void)
{
- void __iomem *base = rcar_sysc_init(0xffd85000);
-
- /* enable all interrupt sources, but do not use interrupt handler */
- iowrite32(0x0131000e, base + SYSCIER);
- iowrite32(0, base + SYSCIMR);
+ rcar_sysc_init(0xffd85000, 0x0131000e);
}
#else /* CONFIG_PM || CONFIG_SMP */
static void __init rcar_gen2_sysc_init(u32 syscier)
{
- void __iomem *base = rcar_sysc_init(0xe6180000);
-
- /* enable all interrupt sources, but do not use interrupt handler */
- iowrite32(syscier, base + SYSCIER);
- iowrite32(0, base + SYSCIMR);
+ rcar_sysc_init(0xe6180000, syscier);
}
#else /* CONFIG_SMP */
# Makefile for the linux kernel, U8500 machine.
#
-obj-y := cpu.o id.o pm.o
-obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
+obj-y := pm.o
obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o
-obj-$(CONFIG_MACH_MOP500) += board-mop500-regulators.o \
- board-mop500-audio.o
+obj-$(CONFIG_MACH_MOP500) += board-mop500-audio.o
obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o
+++ /dev/null
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- *
- * Authors: Sundar Iyer <sundar.iyer@stericsson.com>
- * Bengt Jonsson <bengt.g.jonsson@stericsson.com>
- * Daniel Willerud <daniel.willerud@stericsson.com>
- *
- * MOP500 board specific initialization for regulators
- */
-#include <linux/kernel.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/ab8500.h>
-#include "board-mop500-regulators.h"
-#include "id.h"
-
-static struct regulator_consumer_supply gpio_en_3v3_consumers[] = {
- REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
-};
-
-struct regulator_init_data gpio_en_3v3_regulator = {
- .constraints = {
- .name = "EN-3V3",
- .min_uV = 3300000,
- .max_uV = 3300000,
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(gpio_en_3v3_consumers),
- .consumer_supplies = gpio_en_3v3_consumers,
-};
-
-/*
- * TPS61052 regulator
- */
-static struct regulator_consumer_supply tps61052_vaudio_consumers[] = {
- /*
- * Boost converter supply to raise voltage on audio speaker, this
- * is actually connected to three pins, VInVhfL (left amplifier)
- * VInVhfR (right amplifier) and VIntDClassInt - all three must
- * be connected to the same voltage.
- */
- REGULATOR_SUPPLY("vintdclassint", "ab8500-codec.0"),
-};
-
-struct regulator_init_data tps61052_regulator = {
- .constraints = {
- .name = "vaudio-hf",
- .min_uV = 4500000,
- .max_uV = 4500000,
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(tps61052_vaudio_consumers),
- .consumer_supplies = tps61052_vaudio_consumers,
-};
-
-static struct regulator_consumer_supply ab8500_vaux1_consumers[] = {
- /* Main display, u8500 R3 uib */
- REGULATOR_SUPPLY("vddi", "mcde_disp_sony_acx424akp.0"),
- /* Main display, u8500 uib and ST uib */
- REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.0"),
- /* Secondary display, ST uib */
- REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.1"),
- /* SFH7741 proximity sensor */
- REGULATOR_SUPPLY("vcc", "gpio-keys.0"),
- /* BH1780GLS ambient light sensor */
- REGULATOR_SUPPLY("vcc", "2-0029"),
- /* lsm303dlh accelerometer */
- REGULATOR_SUPPLY("vdd", "2-0018"),
- /* lsm303dlhc accelerometer */
- REGULATOR_SUPPLY("vdd", "2-0019"),
- /* lsm303dlh magnetometer */
- REGULATOR_SUPPLY("vdd", "2-001e"),
- /* Rohm BU21013 Touchscreen devices */
- REGULATOR_SUPPLY("avdd", "3-005c"),
- REGULATOR_SUPPLY("avdd", "3-005d"),
- /* Synaptics RMI4 Touchscreen device */
- REGULATOR_SUPPLY("vdd", "3-004b"),
- /* L3G4200D Gyroscope device */
- REGULATOR_SUPPLY("vdd", "2-0068"),
- /* Ambient light sensor device */
- REGULATOR_SUPPLY("vdd", "3-0029"),
- /* Pressure sensor device */
- REGULATOR_SUPPLY("vdd", "2-005c"),
- /* Cypress TrueTouch Touchscreen device */
- REGULATOR_SUPPLY("vcpin", "spi8.0"),
- /* Camera device */
- REGULATOR_SUPPLY("vaux12v5", "mmio_camera"),
-};
-
-static struct regulator_consumer_supply ab8500_vaux2_consumers[] = {
- /* On-board eMMC power */
- REGULATOR_SUPPLY("vmmc", "sdi4"),
- /* AB8500 audio codec */
- REGULATOR_SUPPLY("vcc-N2158", "ab8500-codec.0"),
- /* AB8500 accessory detect 1 */
- REGULATOR_SUPPLY("vcc-N2158", "ab8500-acc-det.0"),
- /* AB8500 Tv-out device */
- REGULATOR_SUPPLY("vcc-N2158", "mcde_tv_ab8500.4"),
- /* AV8100 HDMI device */
- REGULATOR_SUPPLY("vcc-N2158", "av8100_hdmi.3"),
-};
-
-static struct regulator_consumer_supply ab8500_vaux3_consumers[] = {
- REGULATOR_SUPPLY("v-SD-STM", "stm"),
- /* External MMC slot power */
- REGULATOR_SUPPLY("vmmc", "sdi0"),
-};
-
-static struct regulator_consumer_supply ab8505_vaux4_consumers[] = {
-};
-
-static struct regulator_consumer_supply ab8505_vaux5_consumers[] = {
-};
-
-static struct regulator_consumer_supply ab8505_vaux6_consumers[] = {
-};
-
-static struct regulator_consumer_supply ab8505_vaux8_consumers[] = {
- /* AB8500 audio codec device */
- REGULATOR_SUPPLY("v-aux8", NULL),
-};
-
-static struct regulator_consumer_supply ab8505_vadc_consumers[] = {
- /* Internal general-purpose ADC */
- REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"),
- /* ADC for charger */
- REGULATOR_SUPPLY("vddadc", "ab8500-charger.0"),
-};
-
-static struct regulator_consumer_supply ab8500_vtvout_consumers[] = {
- /* TV-out DENC supply */
- REGULATOR_SUPPLY("vtvout", "ab8500-denc.0"),
- /* Internal general-purpose ADC */
- REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"),
- /* ADC for charger */
- REGULATOR_SUPPLY("vddadc", "ab8500-charger.0"),
- /* AB8500 Tv-out device */
- REGULATOR_SUPPLY("vtvout", "mcde_tv_ab8500.4"),
-};
-
-static struct regulator_consumer_supply ab8500_vaud_consumers[] = {
- /* AB8500 audio-codec main supply */
- REGULATOR_SUPPLY("vaud", "ab8500-codec.0"),
-};
-
-static struct regulator_consumer_supply ab8500_vamic1_consumers[] = {
- /* AB8500 audio-codec Mic1 supply */
- REGULATOR_SUPPLY("vamic1", "ab8500-codec.0"),
-};
-
-static struct regulator_consumer_supply ab8500_vamic2_consumers[] = {
- /* AB8500 audio-codec Mic2 supply */
- REGULATOR_SUPPLY("vamic2", "ab8500-codec.0"),
-};
-
-static struct regulator_consumer_supply ab8500_vdmic_consumers[] = {
- /* AB8500 audio-codec DMic supply */
- REGULATOR_SUPPLY("vdmic", "ab8500-codec.0"),
-};
-
-static struct regulator_consumer_supply ab8500_vintcore_consumers[] = {
- /* SoC core supply, no device */
- REGULATOR_SUPPLY("v-intcore", NULL),
- /* USB Transceiver */
- REGULATOR_SUPPLY("vddulpivio18", "ab8500-usb.0"),
- /* Handled by abx500 clk driver */
- REGULATOR_SUPPLY("v-intcore", "abx500-clk.0"),
-};
-
-static struct regulator_consumer_supply ab8505_usb_consumers[] = {
- /* HS USB OTG physical interface */
- REGULATOR_SUPPLY("v-ape", NULL),
-};
-
-static struct regulator_consumer_supply ab8500_vana_consumers[] = {
- /* DB8500 DSI */
- REGULATOR_SUPPLY("vdddsi1v2", "mcde"),
- REGULATOR_SUPPLY("vdddsi1v2", "b2r2_core"),
- REGULATOR_SUPPLY("vdddsi1v2", "b2r2_1_core"),
- REGULATOR_SUPPLY("vdddsi1v2", "dsilink.0"),
- REGULATOR_SUPPLY("vdddsi1v2", "dsilink.1"),
- REGULATOR_SUPPLY("vdddsi1v2", "dsilink.2"),
- /* DB8500 CSI */
- REGULATOR_SUPPLY("vddcsi1v2", "mmio_camera"),
-};
-
-/* ab8500 regulator register initialization */
-static struct ab8500_regulator_reg_init ab8500_reg_init[] = {
- /*
- * VanaRequestCtrl = HP/LP depending on VxRequest
- * VextSupply1RequestCtrl = HP/LP depending on VxRequest
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2, 0xf0, 0x00),
- /*
- * VextSupply2RequestCtrl = HP/LP depending on VxRequest
- * VextSupply3RequestCtrl = HP/LP depending on VxRequest
- * Vaux1RequestCtrl = HP/LP depending on VxRequest
- * Vaux2RequestCtrl = HP/LP depending on VxRequest
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL3, 0xff, 0x00),
- /*
- * Vaux3RequestCtrl = HP/LP depending on VxRequest
- * SwHPReq = Control through SWValid disabled
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL4, 0x07, 0x00),
- /*
- * VanaSysClkReq1HPValid = disabled
- * Vaux1SysClkReq1HPValid = disabled
- * Vaux2SysClkReq1HPValid = disabled
- * Vaux3SysClkReq1HPValid = disabled
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0xe8, 0x00),
- /*
- * VextSupply1SysClkReq1HPValid = disabled
- * VextSupply2SysClkReq1HPValid = disabled
- * VextSupply3SysClkReq1HPValid = SysClkReq1 controlled
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID2, 0x70, 0x40),
- /*
- * VanaHwHPReq1Valid = disabled
- * Vaux1HwHPreq1Valid = disabled
- * Vaux2HwHPReq1Valid = disabled
- * Vaux3HwHPReqValid = disabled
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID1, 0xe8, 0x00),
- /*
- * VextSupply1HwHPReq1Valid = disabled
- * VextSupply2HwHPReq1Valid = disabled
- * VextSupply3HwHPReq1Valid = disabled
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID2, 0x07, 0x00),
- /*
- * VanaHwHPReq2Valid = disabled
- * Vaux1HwHPReq2Valid = disabled
- * Vaux2HwHPReq2Valid = disabled
- * Vaux3HwHPReq2Valid = disabled
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID1, 0xe8, 0x00),
- /*
- * VextSupply1HwHPReq2Valid = disabled
- * VextSupply2HwHPReq2Valid = disabled
- * VextSupply3HwHPReq2Valid = HWReq2 controlled
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID2, 0x07, 0x04),
- /*
- * VanaSwHPReqValid = disabled
- * Vaux1SwHPReqValid = disabled
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID1, 0xa0, 0x00),
- /*
- * Vaux2SwHPReqValid = disabled
- * Vaux3SwHPReqValid = disabled
- * VextSupply1SwHPReqValid = disabled
- * VextSupply2SwHPReqValid = disabled
- * VextSupply3SwHPReqValid = disabled
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID2, 0x1f, 0x00),
- /*
- * SysClkReq2Valid1 = SysClkReq2 controlled
- * SysClkReq3Valid1 = disabled
- * SysClkReq4Valid1 = SysClkReq4 controlled
- * SysClkReq5Valid1 = disabled
- * SysClkReq6Valid1 = SysClkReq6 controlled
- * SysClkReq7Valid1 = disabled
- * SysClkReq8Valid1 = disabled
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID1, 0xfe, 0x2a),
- /*
- * SysClkReq2Valid2 = disabled
- * SysClkReq3Valid2 = disabled
- * SysClkReq4Valid2 = disabled
- * SysClkReq5Valid2 = disabled
- * SysClkReq6Valid2 = SysClkReq6 controlled
- * SysClkReq7Valid2 = disabled
- * SysClkReq8Valid2 = disabled
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID2, 0xfe, 0x20),
- /*
- * VTVoutEna = disabled
- * Vintcore12Ena = disabled
- * Vintcore12Sel = 1.25 V
- * Vintcore12LP = inactive (HP)
- * VTVoutLP = inactive (HP)
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUMISC1, 0xfe, 0x10),
- /*
- * VaudioEna = disabled
- * VdmicEna = disabled
- * Vamic1Ena = disabled
- * Vamic2Ena = disabled
- */
- INIT_REGULATOR_REGISTER(AB8500_VAUDIOSUPPLY, 0x1e, 0x00),
- /*
- * Vamic1_dzout = high-Z when Vamic1 is disabled
- * Vamic2_dzout = high-Z when Vamic2 is disabled
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC, 0x03, 0x00),
- /*
- * VPll = Hw controlled (NOTE! PRCMU bits)
- * VanaRegu = force off
- */
- INIT_REGULATOR_REGISTER(AB8500_VPLLVANAREGU, 0x0f, 0x02),
- /*
- * VrefDDREna = disabled
- * VrefDDRSleepMode = inactive (no pulldown)
- */
- INIT_REGULATOR_REGISTER(AB8500_VREFDDR, 0x03, 0x00),
- /*
- * VextSupply1Regu = force LP
- * VextSupply2Regu = force OFF
- * VextSupply3Regu = force HP (-> STBB2=LP and TPS=LP)
- * ExtSupply2Bypass = ExtSupply12LPn ball is 0 when Ena is 0
- * ExtSupply3Bypass = ExtSupply3LPn ball is 0 when Ena is 0
- */
- INIT_REGULATOR_REGISTER(AB8500_EXTSUPPLYREGU, 0xff, 0x13),
- /*
- * Vaux1Regu = force HP
- * Vaux2Regu = force off
- */
- INIT_REGULATOR_REGISTER(AB8500_VAUX12REGU, 0x0f, 0x01),
- /*
- * Vaux3Regu = force off
- */
- INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x03, 0x00),
- /*
- * Vaux1Sel = 2.8 V
- */
- INIT_REGULATOR_REGISTER(AB8500_VAUX1SEL, 0x0f, 0x0C),
- /*
- * Vaux2Sel = 2.9 V
- */
- INIT_REGULATOR_REGISTER(AB8500_VAUX2SEL, 0x0f, 0x0d),
- /*
- * Vaux3Sel = 2.91 V
- */
- INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3SEL, 0x07, 0x07),
- /*
- * VextSupply12LP = disabled (no LP)
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUCTRL2SPARE, 0x01, 0x00),
- /*
- * Vaux1Disch = short discharge time
- * Vaux2Disch = short discharge time
- * Vaux3Disch = short discharge time
- * Vintcore12Disch = short discharge time
- * VTVoutDisch = short discharge time
- * VaudioDisch = short discharge time
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH, 0xfc, 0x00),
- /*
- * VanaDisch = short discharge time
- * VdmicPullDownEna = pulldown disabled when Vdmic is disabled
- * VdmicDisch = short discharge time
- */
- INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH2, 0x16, 0x00),
-};
-
-/* AB8500 regulators */
-static struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
- /* supplies to the display/camera */
- [AB8500_LDO_AUX1] = {
- .supply_regulator = "ab8500-ext-supply3",
- .constraints = {
- .name = "V-DISPLAY",
- .min_uV = 2800000,
- .max_uV = 3300000,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
- REGULATOR_CHANGE_STATUS,
- .boot_on = 1, /* display is on at boot */
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers),
- .consumer_supplies = ab8500_vaux1_consumers,
- },
- /* supplies to the on-board eMMC */
- [AB8500_LDO_AUX2] = {
- .supply_regulator = "ab8500-ext-supply3",
- .constraints = {
- .name = "V-eMMC1",
- .min_uV = 1100000,
- .max_uV = 3300000,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
- REGULATOR_CHANGE_STATUS |
- REGULATOR_CHANGE_MODE,
- .valid_modes_mask = REGULATOR_MODE_NORMAL |
- REGULATOR_MODE_IDLE,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers),
- .consumer_supplies = ab8500_vaux2_consumers,
- },
- /* supply for VAUX3, supplies to SDcard slots */
- [AB8500_LDO_AUX3] = {
- .supply_regulator = "ab8500-ext-supply3",
- .constraints = {
- .name = "V-MMC-SD",
- .min_uV = 1100000,
- .max_uV = 3300000,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
- REGULATOR_CHANGE_STATUS |
- REGULATOR_CHANGE_MODE,
- .valid_modes_mask = REGULATOR_MODE_NORMAL |
- REGULATOR_MODE_IDLE,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers),
- .consumer_supplies = ab8500_vaux3_consumers,
- },
- /* supply for tvout, gpadc, TVOUT LDO */
- [AB8500_LDO_TVOUT] = {
- .constraints = {
- .name = "V-TVOUT",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vtvout_consumers),
- .consumer_supplies = ab8500_vtvout_consumers,
- },
- /* supply for ab8500-vaudio, VAUDIO LDO */
- [AB8500_LDO_AUDIO] = {
- .constraints = {
- .name = "V-AUD",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vaud_consumers),
- .consumer_supplies = ab8500_vaud_consumers,
- },
- /* supply for v-anamic1 VAMic1-LDO */
- [AB8500_LDO_ANAMIC1] = {
- .constraints = {
- .name = "V-AMIC1",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers),
- .consumer_supplies = ab8500_vamic1_consumers,
- },
- /* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
- [AB8500_LDO_ANAMIC2] = {
- .constraints = {
- .name = "V-AMIC2",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers),
- .consumer_supplies = ab8500_vamic2_consumers,
- },
- /* supply for v-dmic, VDMIC LDO */
- [AB8500_LDO_DMIC] = {
- .constraints = {
- .name = "V-DMIC",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vdmic_consumers),
- .consumer_supplies = ab8500_vdmic_consumers,
- },
- /* supply for v-intcore12, VINTCORE12 LDO */
- [AB8500_LDO_INTCORE] = {
- .constraints = {
- .name = "V-INTCORE",
- .min_uV = 1250000,
- .max_uV = 1350000,
- .input_uV = 1800000,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
- REGULATOR_CHANGE_STATUS |
- REGULATOR_CHANGE_MODE |
- REGULATOR_CHANGE_DRMS,
- .valid_modes_mask = REGULATOR_MODE_NORMAL |
- REGULATOR_MODE_IDLE,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers),
- .consumer_supplies = ab8500_vintcore_consumers,
- },
- /* supply for U8500 CSI-DSI, VANA LDO */
- [AB8500_LDO_ANA] = {
- .constraints = {
- .name = "V-CSI-DSI",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers),
- .consumer_supplies = ab8500_vana_consumers,
- },
-};
-
-/* supply for VextSupply3 */
-static struct regulator_consumer_supply ab8500_ext_supply3_consumers[] = {
- /* SIM supply for 3 V SIM cards */
- REGULATOR_SUPPLY("vinvsim", "sim-detect.0"),
-};
-
-/* extended configuration for VextSupply2, only used for HREFP_V20 boards */
-static struct ab8500_ext_regulator_cfg ab8500_ext_supply2 = {
- .hwreq = true,
-};
-
-/*
- * AB8500 external regulators
- */
-static struct regulator_init_data ab8500_ext_regulators[] = {
- /* fixed Vbat supplies VSMPS1_EXT_1V8 */
- [AB8500_EXT_SUPPLY1] = {
- .constraints = {
- .name = "ab8500-ext-supply1",
- .min_uV = 1800000,
- .max_uV = 1800000,
- .initial_mode = REGULATOR_MODE_IDLE,
- .boot_on = 1,
- .always_on = 1,
- },
- },
- /* fixed Vbat supplies VSMPS2_EXT_1V36 and VSMPS5_EXT_1V15 */
- [AB8500_EXT_SUPPLY2] = {
- .constraints = {
- .name = "ab8500-ext-supply2",
- .min_uV = 1360000,
- .max_uV = 1360000,
- },
- },
- /* fixed Vbat supplies VSMPS3_EXT_3V4 and VSMPS4_EXT_3V4 */
- [AB8500_EXT_SUPPLY3] = {
- .constraints = {
- .name = "ab8500-ext-supply3",
- .min_uV = 3400000,
- .max_uV = 3400000,
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- .boot_on = 1,
- },
- .num_consumer_supplies =
- ARRAY_SIZE(ab8500_ext_supply3_consumers),
- .consumer_supplies = ab8500_ext_supply3_consumers,
- },
-};
-
-/* ab8505 regulator register initialization */
-static struct ab8500_regulator_reg_init ab8505_reg_init[] = {
- /*
- * VarmRequestCtrl
- * VsmpsCRequestCtrl
- * VsmpsARequestCtrl
- * VsmpsBRequestCtrl
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL1, 0x00, 0x00),
- /*
- * VsafeRequestCtrl
- * VpllRequestCtrl
- * VanaRequestCtrl = HP/LP depending on VxRequest
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL2, 0x30, 0x00),
- /*
- * Vaux1RequestCtrl = HP/LP depending on VxRequest
- * Vaux2RequestCtrl = HP/LP depending on VxRequest
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL3, 0xf0, 0x00),
- /*
- * Vaux3RequestCtrl = HP/LP depending on VxRequest
- * SwHPReq = Control through SWValid disabled
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL4, 0x07, 0x00),
- /*
- * VsmpsASysClkReq1HPValid
- * VsmpsBSysClkReq1HPValid
- * VsafeSysClkReq1HPValid
- * VanaSysClkReq1HPValid = disabled
- * VpllSysClkReq1HPValid
- * Vaux1SysClkReq1HPValid = disabled
- * Vaux2SysClkReq1HPValid = disabled
- * Vaux3SysClkReq1HPValid = disabled
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQ1HPVALID1, 0xe8, 0x00),
- /*
- * VsmpsCSysClkReq1HPValid
- * VarmSysClkReq1HPValid
- * VbbSysClkReq1HPValid
- * VsmpsMSysClkReq1HPValid
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQ1HPVALID2, 0x00, 0x00),
- /*
- * VsmpsAHwHPReq1Valid
- * VsmpsBHwHPReq1Valid
- * VsafeHwHPReq1Valid
- * VanaHwHPReq1Valid = disabled
- * VpllHwHPReq1Valid
- * Vaux1HwHPreq1Valid = disabled
- * Vaux2HwHPReq1Valid = disabled
- * Vaux3HwHPReqValid = disabled
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ1VALID1, 0xe8, 0x00),
- /*
- * VsmpsMHwHPReq1Valid
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ1VALID2, 0x00, 0x00),
- /*
- * VsmpsAHwHPReq2Valid
- * VsmpsBHwHPReq2Valid
- * VsafeHwHPReq2Valid
- * VanaHwHPReq2Valid = disabled
- * VpllHwHPReq2Valid
- * Vaux1HwHPReq2Valid = disabled
- * Vaux2HwHPReq2Valid = disabled
- * Vaux3HwHPReq2Valid = disabled
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ2VALID1, 0xe8, 0x00),
- /*
- * VsmpsMHwHPReq2Valid
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ2VALID2, 0x00, 0x00),
- /**
- * VsmpsCSwHPReqValid
- * VarmSwHPReqValid
- * VsmpsASwHPReqValid
- * VsmpsBSwHPReqValid
- * VsafeSwHPReqValid
- * VanaSwHPReqValid
- * VanaSwHPReqValid = disabled
- * VpllSwHPReqValid
- * Vaux1SwHPReqValid = disabled
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUSWHPREQVALID1, 0xa0, 0x00),
- /*
- * Vaux2SwHPReqValid = disabled
- * Vaux3SwHPReqValid = disabled
- * VsmpsMSwHPReqValid
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUSWHPREQVALID2, 0x03, 0x00),
- /*
- * SysClkReq2Valid1 = SysClkReq2 controlled
- * SysClkReq3Valid1 = disabled
- * SysClkReq4Valid1 = SysClkReq4 controlled
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQVALID1, 0x0e, 0x0a),
- /*
- * SysClkReq2Valid2 = disabled
- * SysClkReq3Valid2 = disabled
- * SysClkReq4Valid2 = disabled
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQVALID2, 0x0e, 0x00),
- /*
- * Vaux4SwHPReqValid
- * Vaux4HwHPReq2Valid
- * Vaux4HwHPReq1Valid
- * Vaux4SysClkReq1HPValid
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUVAUX4REQVALID, 0x00, 0x00),
- /*
- * VadcEna = disabled
- * VintCore12Ena = disabled
- * VintCore12Sel = 1.25 V
- * VintCore12LP = inactive (HP)
- * VadcLP = inactive (HP)
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUMISC1, 0xfe, 0x10),
- /*
- * VaudioEna = disabled
- * Vaux8Ena = disabled
- * Vamic1Ena = disabled
- * Vamic2Ena = disabled
- */
- INIT_REGULATOR_REGISTER(AB8505_VAUDIOSUPPLY, 0x1e, 0x00),
- /*
- * Vamic1_dzout = high-Z when Vamic1 is disabled
- * Vamic2_dzout = high-Z when Vamic2 is disabled
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUCTRL1VAMIC, 0x03, 0x00),
- /*
- * VsmpsARegu
- * VsmpsASelCtrl
- * VsmpsAAutoMode
- * VsmpsAPWMMode
- */
- INIT_REGULATOR_REGISTER(AB8505_VSMPSAREGU, 0x00, 0x00),
- /*
- * VsmpsBRegu
- * VsmpsBSelCtrl
- * VsmpsBAutoMode
- * VsmpsBPWMMode
- */
- INIT_REGULATOR_REGISTER(AB8505_VSMPSBREGU, 0x00, 0x00),
- /*
- * VsafeRegu
- * VsafeSelCtrl
- * VsafeAutoMode
- * VsafePWMMode
- */
- INIT_REGULATOR_REGISTER(AB8505_VSAFEREGU, 0x00, 0x00),
- /*
- * VPll = Hw controlled (NOTE! PRCMU bits)
- * VanaRegu = force off
- */
- INIT_REGULATOR_REGISTER(AB8505_VPLLVANAREGU, 0x0f, 0x02),
- /*
- * VextSupply1Regu = force OFF (OTP_ExtSupply12LPnPolarity 1)
- * VextSupply2Regu = force OFF (OTP_ExtSupply12LPnPolarity 1)
- * VextSupply3Regu = force OFF (OTP_ExtSupply3LPnPolarity 0)
- * ExtSupply2Bypass = ExtSupply12LPn ball is 0 when Ena is 0
- * ExtSupply3Bypass = ExtSupply3LPn ball is 0 when Ena is 0
- */
- INIT_REGULATOR_REGISTER(AB8505_EXTSUPPLYREGU, 0xff, 0x30),
- /*
- * Vaux1Regu = force HP
- * Vaux2Regu = force off
- */
- INIT_REGULATOR_REGISTER(AB8505_VAUX12REGU, 0x0f, 0x01),
- /*
- * Vaux3Regu = force off
- */
- INIT_REGULATOR_REGISTER(AB8505_VRF1VAUX3REGU, 0x03, 0x00),
- /*
- * VsmpsASel1
- */
- INIT_REGULATOR_REGISTER(AB8505_VSMPSASEL1, 0x00, 0x00),
- /*
- * VsmpsASel2
- */
- INIT_REGULATOR_REGISTER(AB8505_VSMPSASEL2, 0x00, 0x00),
- /*
- * VsmpsASel3
- */
- INIT_REGULATOR_REGISTER(AB8505_VSMPSASEL3, 0x00, 0x00),
- /*
- * VsmpsBSel1
- */
- INIT_REGULATOR_REGISTER(AB8505_VSMPSBSEL1, 0x00, 0x00),
- /*
- * VsmpsBSel2
- */
- INIT_REGULATOR_REGISTER(AB8505_VSMPSBSEL2, 0x00, 0x00),
- /*
- * VsmpsBSel3
- */
- INIT_REGULATOR_REGISTER(AB8505_VSMPSBSEL3, 0x00, 0x00),
- /*
- * VsafeSel1
- */
- INIT_REGULATOR_REGISTER(AB8505_VSAFESEL1, 0x00, 0x00),
- /*
- * VsafeSel2
- */
- INIT_REGULATOR_REGISTER(AB8505_VSAFESEL2, 0x00, 0x00),
- /*
- * VsafeSel3
- */
- INIT_REGULATOR_REGISTER(AB8505_VSAFESEL3, 0x00, 0x00),
- /*
- * Vaux1Sel = 2.8 V
- */
- INIT_REGULATOR_REGISTER(AB8505_VAUX1SEL, 0x0f, 0x0C),
- /*
- * Vaux2Sel = 2.9 V
- */
- INIT_REGULATOR_REGISTER(AB8505_VAUX2SEL, 0x0f, 0x0d),
- /*
- * Vaux3Sel = 2.91 V
- */
- INIT_REGULATOR_REGISTER(AB8505_VRF1VAUX3SEL, 0x07, 0x07),
- /*
- * Vaux4RequestCtrl
- */
- INIT_REGULATOR_REGISTER(AB8505_VAUX4REQCTRL, 0x00, 0x00),
- /*
- * Vaux4Regu
- */
- INIT_REGULATOR_REGISTER(AB8505_VAUX4REGU, 0x00, 0x00),
- /*
- * Vaux4Sel
- */
- INIT_REGULATOR_REGISTER(AB8505_VAUX4SEL, 0x00, 0x00),
- /*
- * Vaux1Disch = short discharge time
- * Vaux2Disch = short discharge time
- * Vaux3Disch = short discharge time
- * Vintcore12Disch = short discharge time
- * VTVoutDisch = short discharge time
- * VaudioDisch = short discharge time
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUCTRLDISCH, 0xfc, 0x00),
- /*
- * VanaDisch = short discharge time
- * Vaux8PullDownEna = pulldown disabled when Vaux8 is disabled
- * Vaux8Disch = short discharge time
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUCTRLDISCH2, 0x16, 0x00),
- /*
- * Vaux4Disch = short discharge time
- */
- INIT_REGULATOR_REGISTER(AB8505_REGUCTRLDISCH3, 0x01, 0x00),
- /*
- * Vaux5Sel
- * Vaux5LP
- * Vaux5Ena
- * Vaux5Disch
- * Vaux5DisSfst
- * Vaux5DisPulld
- */
- INIT_REGULATOR_REGISTER(AB8505_CTRLVAUX5, 0x00, 0x00),
- /*
- * Vaux6Sel
- * Vaux6LP
- * Vaux6Ena
- * Vaux6DisPulld
- */
- INIT_REGULATOR_REGISTER(AB8505_CTRLVAUX6, 0x00, 0x00),
-};
-
-static struct regulator_init_data ab8505_regulators[AB8505_NUM_REGULATORS] = {
- /* supplies to the display/camera */
- [AB8505_LDO_AUX1] = {
- .constraints = {
- .name = "V-DISPLAY",
- .min_uV = 2800000,
- .max_uV = 3300000,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
- REGULATOR_CHANGE_STATUS,
- .boot_on = 1, /* display is on at boot */
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers),
- .consumer_supplies = ab8500_vaux1_consumers,
- },
- /* supplies to the on-board eMMC */
- [AB8505_LDO_AUX2] = {
- .constraints = {
- .name = "V-eMMC1",
- .min_uV = 1100000,
- .max_uV = 3300000,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
- REGULATOR_CHANGE_STATUS |
- REGULATOR_CHANGE_MODE,
- .valid_modes_mask = REGULATOR_MODE_NORMAL |
- REGULATOR_MODE_IDLE,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers),
- .consumer_supplies = ab8500_vaux2_consumers,
- },
- /* supply for VAUX3, supplies to SDcard slots */
- [AB8505_LDO_AUX3] = {
- .constraints = {
- .name = "V-MMC-SD",
- .min_uV = 1100000,
- .max_uV = 3300000,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
- REGULATOR_CHANGE_STATUS |
- REGULATOR_CHANGE_MODE,
- .valid_modes_mask = REGULATOR_MODE_NORMAL |
- REGULATOR_MODE_IDLE,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers),
- .consumer_supplies = ab8500_vaux3_consumers,
- },
- /* supply for VAUX4, supplies to NFC and standalone secure element */
- [AB8505_LDO_AUX4] = {
- .constraints = {
- .name = "V-NFC-SE",
- .min_uV = 1100000,
- .max_uV = 3300000,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
- REGULATOR_CHANGE_STATUS |
- REGULATOR_CHANGE_MODE,
- .valid_modes_mask = REGULATOR_MODE_NORMAL |
- REGULATOR_MODE_IDLE,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8505_vaux4_consumers),
- .consumer_supplies = ab8505_vaux4_consumers,
- },
- /* supply for VAUX5, supplies to TBD */
- [AB8505_LDO_AUX5] = {
- .constraints = {
- .name = "V-AUX5",
- .min_uV = 1050000,
- .max_uV = 2790000,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
- REGULATOR_CHANGE_STATUS |
- REGULATOR_CHANGE_MODE,
- .valid_modes_mask = REGULATOR_MODE_NORMAL |
- REGULATOR_MODE_IDLE,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8505_vaux5_consumers),
- .consumer_supplies = ab8505_vaux5_consumers,
- },
- /* supply for VAUX6, supplies to TBD */
- [AB8505_LDO_AUX6] = {
- .constraints = {
- .name = "V-AUX6",
- .min_uV = 1050000,
- .max_uV = 2790000,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
- REGULATOR_CHANGE_STATUS |
- REGULATOR_CHANGE_MODE,
- .valid_modes_mask = REGULATOR_MODE_NORMAL |
- REGULATOR_MODE_IDLE,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8505_vaux6_consumers),
- .consumer_supplies = ab8505_vaux6_consumers,
- },
- /* supply for gpadc, ADC LDO */
- [AB8505_LDO_ADC] = {
- .constraints = {
- .name = "V-ADC",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8505_vadc_consumers),
- .consumer_supplies = ab8505_vadc_consumers,
- },
- /* supply for ab8500-vaudio, VAUDIO LDO */
- [AB8505_LDO_AUDIO] = {
- .constraints = {
- .name = "V-AUD",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vaud_consumers),
- .consumer_supplies = ab8500_vaud_consumers,
- },
- /* supply for v-anamic1 VAMic1-LDO */
- [AB8505_LDO_ANAMIC1] = {
- .constraints = {
- .name = "V-AMIC1",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS |
- REGULATOR_CHANGE_MODE,
- .valid_modes_mask = REGULATOR_MODE_NORMAL |
- REGULATOR_MODE_IDLE,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers),
- .consumer_supplies = ab8500_vamic1_consumers,
- },
- /* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
- [AB8505_LDO_ANAMIC2] = {
- .constraints = {
- .name = "V-AMIC2",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS |
- REGULATOR_CHANGE_MODE,
- .valid_modes_mask = REGULATOR_MODE_NORMAL |
- REGULATOR_MODE_IDLE,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers),
- .consumer_supplies = ab8500_vamic2_consumers,
- },
- /* supply for v-aux8, VAUX8 LDO */
- [AB8505_LDO_AUX8] = {
- .constraints = {
- .name = "V-AUX8",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8505_vaux8_consumers),
- .consumer_supplies = ab8505_vaux8_consumers,
- },
- /* supply for v-intcore12, VINTCORE12 LDO */
- [AB8505_LDO_INTCORE] = {
- .constraints = {
- .name = "V-INTCORE",
- .min_uV = 1250000,
- .max_uV = 1350000,
- .input_uV = 1800000,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
- REGULATOR_CHANGE_STATUS |
- REGULATOR_CHANGE_MODE |
- REGULATOR_CHANGE_DRMS,
- .valid_modes_mask = REGULATOR_MODE_NORMAL |
- REGULATOR_MODE_IDLE,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers),
- .consumer_supplies = ab8500_vintcore_consumers,
- },
- /* supply for LDO USB */
- [AB8505_LDO_USB] = {
- .constraints = {
- .name = "V-USB",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS |
- REGULATOR_CHANGE_MODE,
- .valid_modes_mask = REGULATOR_MODE_NORMAL |
- REGULATOR_MODE_IDLE,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8505_usb_consumers),
- .consumer_supplies = ab8505_usb_consumers,
- },
- /* supply for U8500 CSI-DSI, VANA LDO */
- [AB8505_LDO_ANA] = {
- .constraints = {
- .name = "V-CSI-DSI",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers),
- .consumer_supplies = ab8500_vana_consumers,
- },
-};
-
-struct ab8500_regulator_platform_data ab8500_regulator_plat_data = {
- .reg_init = ab8500_reg_init,
- .num_reg_init = ARRAY_SIZE(ab8500_reg_init),
- .regulator = ab8500_regulators,
- .num_regulator = ARRAY_SIZE(ab8500_regulators),
- .ext_regulator = ab8500_ext_regulators,
- .num_ext_regulator = ARRAY_SIZE(ab8500_ext_regulators),
-};
-
-struct ab8500_regulator_platform_data ab8505_regulator_plat_data = {
- .reg_init = ab8505_reg_init,
- .num_reg_init = ARRAY_SIZE(ab8505_reg_init),
- .regulator = ab8505_regulators,
- .num_regulator = ARRAY_SIZE(ab8505_regulators),
-};
-
-static void ab8500_modify_reg_init(int id, u8 mask, u8 value)
-{
- int i;
-
- if (cpu_is_u8520()) {
- for (i = ARRAY_SIZE(ab8505_reg_init) - 1; i >= 0; i--) {
- if (ab8505_reg_init[i].id == id) {
- u8 initval = ab8505_reg_init[i].value;
- initval = (initval & ~mask) | (value & mask);
- ab8505_reg_init[i].value = initval;
-
- BUG_ON(mask & ~ab8505_reg_init[i].mask);
- return;
- }
- }
- } else {
- for (i = ARRAY_SIZE(ab8500_reg_init) - 1; i >= 0; i--) {
- if (ab8500_reg_init[i].id == id) {
- u8 initval = ab8500_reg_init[i].value;
- initval = (initval & ~mask) | (value & mask);
- ab8500_reg_init[i].value = initval;
-
- BUG_ON(mask & ~ab8500_reg_init[i].mask);
- return;
- }
- }
- }
-
- BUG_ON(1);
-}
-
-void mop500_regulator_init(void)
-{
- struct regulator_init_data *regulator;
-
- /*
- * Temporarily turn on Vaux2 on 8520 machine
- */
- if (cpu_is_u8520()) {
- /* Vaux2 initialized to be on */
- ab8500_modify_reg_init(AB8505_VAUX12REGU, 0x0f, 0x05);
- }
-
- /*
- * Handle AB8500_EXT_SUPPLY2 on HREFP_V20_V50 boards (do it for
- * all HREFP_V20 boards)
- */
- if (cpu_is_u8500v20()) {
- /* VextSupply2RequestCtrl = HP/OFF depending on VxRequest */
- ab8500_modify_reg_init(AB8500_REGUREQUESTCTRL3, 0x01, 0x01);
-
- /* VextSupply2SysClkReq1HPValid = SysClkReq1 controlled */
- ab8500_modify_reg_init(AB8500_REGUSYSCLKREQ1HPVALID2,
- 0x20, 0x20);
-
- /* VextSupply2 = force HP at initialization */
- ab8500_modify_reg_init(AB8500_EXTSUPPLYREGU, 0x0c, 0x04);
-
- /* enable VextSupply2 during platform active */
- regulator = &ab8500_ext_regulators[AB8500_EXT_SUPPLY2];
- regulator->constraints.always_on = 1;
-
- /* disable VextSupply2 in suspend */
- regulator = &ab8500_ext_regulators[AB8500_EXT_SUPPLY2];
- regulator->constraints.state_mem.disabled = 1;
- regulator->constraints.state_standby.disabled = 1;
-
- /* enable VextSupply2 HW control (used in suspend) */
- regulator->driver_data = (void *)&ab8500_ext_supply2;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- *
- * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
- *
- * MOP500 board specific initialization for regulators
- */
-
-#ifndef __BOARD_MOP500_REGULATORS_H
-#define __BOARD_MOP500_REGULATORS_H
-
-#include <linux/regulator/machine.h>
-#include <linux/regulator/ab8500.h>
-
-extern struct ab8500_regulator_platform_data ab8500_regulator_plat_data;
-extern struct ab8500_regulator_platform_data ab8505_regulator_plat_data;
-extern struct regulator_init_data tps61052_regulator;
-extern struct regulator_init_data gpio_en_3v3_regulator;
-
-void mop500_regulator_init(void);
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) ST-Ericsson SA 2011
- *
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-
-#include <asm/outercache.h>
-#include <asm/hardware/cache-l2x0.h>
-
-#include "db8500-regs.h"
-#include "id.h"
-
-static int __init ux500_l2x0_unlock(void)
-{
- int i;
- struct device_node *np;
- void __iomem *l2x0_base;
-
- np = of_find_compatible_node(NULL, NULL, "arm,pl310-cache");
- l2x0_base = of_iomap(np, 0);
- of_node_put(np);
- if (!l2x0_base)
- return -ENODEV;
-
- /*
- * Unlock Data and Instruction Lock if locked. Ux500 U-Boot versions
- * apparently locks both caches before jumping to the kernel. The
- * l2x0 core will not touch the unlock registers if the l2x0 is
- * already enabled, so we do it right here instead. The PL310 has
- * 8 sets of registers, one per possible CPU.
- */
- for (i = 0; i < 8; i++) {
- writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE +
- i * L2X0_LOCKDOWN_STRIDE);
- writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE +
- i * L2X0_LOCKDOWN_STRIDE);
- }
- iounmap(l2x0_base);
- return 0;
-}
-
-static void ux500_l2c310_write_sec(unsigned long val, unsigned reg)
-{
- /*
- * We can't write to secure registers as we are in non-secure
- * mode, until we have some SMI service available.
- */
-}
-
-static int __init ux500_l2x0_init(void)
-{
- /* Multiplatform guard */
- if (!((cpu_is_u8500_family() || cpu_is_ux540_family())))
- return -ENODEV;
-
- /* Unlock before init */
- ux500_l2x0_unlock();
- outer_cache.write_sec = ux500_l2c310_write_sec;
- l2x0_of_init(0, ~0);
-
- return 0;
-}
-early_initcall(ux500_l2x0_init);
#include <linux/init.h>
#include <linux/device.h>
#include <linux/amba/bus.h>
+#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/platform_data/arm-ux500-pm.h>
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/dbx500-prcmu.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/perf/arm_pmu.h>
#include <linux/regulator/machine.h>
-#include <linux/random.h>
+#include <asm/outercache.h>
+#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
#include "setup.h"
-#include "board-mop500-regulators.h"
#include "board-mop500.h"
#include "db8500-regs.h"
-#include "id.h"
-static struct ab8500_platform_data ab8500_platdata = {
- .regulator = &ab8500_regulator_plat_data,
-};
+static int __init ux500_l2x0_unlock(void)
+{
+ int i;
+ struct device_node *np;
+ void __iomem *l2x0_base;
-static struct prcmu_pdata db8500_prcmu_pdata = {
- .ab_platdata = &ab8500_platdata,
- .version_offset = DB8500_PRCMU_FW_VERSION_OFFSET,
- .legacy_offset = DB8500_PRCMU_LEGACY_OFFSET,
-};
+ np = of_find_compatible_node(NULL, NULL, "arm,pl310-cache");
+ l2x0_base = of_iomap(np, 0);
+ of_node_put(np);
+ if (!l2x0_base)
+ return -ENODEV;
+
+ /*
+ * Unlock Data and Instruction Lock if locked. Ux500 U-Boot versions
+ * apparently locks both caches before jumping to the kernel. The
+ * l2x0 core will not touch the unlock registers if the l2x0 is
+ * already enabled, so we do it right here instead. The PL310 has
+ * 8 sets of registers, one per possible CPU.
+ */
+ for (i = 0; i < 8; i++) {
+ writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE +
+ i * L2X0_LOCKDOWN_STRIDE);
+ writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE +
+ i * L2X0_LOCKDOWN_STRIDE);
+ }
+ iounmap(l2x0_base);
+ return 0;
+}
+
+static void ux500_l2c310_write_sec(unsigned long val, unsigned reg)
+{
+ /*
+ * We can't write to secure registers as we are in non-secure
+ * mode, until we have some SMI service available.
+ */
+}
-static void __init u8500_map_io(void)
+/*
+ * FIXME: Should we set up the GPIO domain here?
+ *
+ * The problem is that we cannot put the interrupt resources into the platform
+ * device until the irqdomain has been added. Right now, we set the GIC interrupt
+ * domain from init_irq(), then load the gpio driver from
+ * core_initcall(nmk_gpio_init) and add the platform devices from
+ * arch_initcall(customize_machine).
+ *
+ * This feels fragile because it depends on the gpio device getting probed
+ * _before_ any device uses the gpio interrupts.
+*/
+static void __init ux500_init_irq(void)
+{
+ struct device_node *np;
+ struct resource r;
+
+ irqchip_init();
+ np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu");
+ of_address_to_resource(np, 0, &r);
+ of_node_put(np);
+ if (!r.start) {
+ pr_err("could not find PRCMU base resource\n");
+ return;
+ }
+ prcmu_early_init(r.start, r.end-r.start);
+ ux500_pm_init(r.start, r.end-r.start);
+
+ /* Unlock before init */
+ ux500_l2x0_unlock();
+ outer_cache.write_sec = ux500_l2c310_write_sec;
+}
+
+static void ux500_restart(enum reboot_mode mode, const char *cmd)
{
- debug_ll_io_init();
- ux500_setup_id();
+ local_irq_disable();
+ local_fiq_disable();
+
+ prcmu_system_reset(0);
}
/*
.handle_irq = db8500_pmu_handler,
};
-static const char *db8500_read_soc_id(void)
-{
- void __iomem *uid;
- const char *retstr;
-
- uid = ioremap(U8500_BB_UID_BASE, 0x20);
- if (!uid)
- return NULL;
- /* Throw these device-specific numbers into the entropy pool */
- add_device_randomness(uid, 0x14);
- retstr = kasprintf(GFP_KERNEL, "%08x%08x%08x%08x%08x",
- readl((u32 *)uid+0),
- readl((u32 *)uid+1), readl((u32 *)uid+2),
- readl((u32 *)uid+3), readl((u32 *)uid+4));
- iounmap(uid);
- return retstr;
-}
-
-static struct device * __init db8500_soc_device_init(void)
-{
- const char *soc_id = db8500_read_soc_id();
-
- return ux500_soc_device_init(soc_id);
-}
-
static struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
/* Requires call-back bindings. */
OF_DEV_AUXDATA("arm,cortex-a9-pmu", 0, "arm-pmu", &db8500_pmu_platdata),
OF_DEV_AUXDATA("stericsson,ux500-msp-i2s", 0x80125000,
"ux500-msp-i2s.3", &msp3_platform_data),
/* Requires non-DT:able platform data. */
- OF_DEV_AUXDATA("stericsson,db8500-prcmu", 0x80157000, "db8500-prcmu",
- &db8500_prcmu_pdata),
+ OF_DEV_AUXDATA("stericsson,db8500-prcmu", 0x80157000, "db8500-prcmu", NULL),
OF_DEV_AUXDATA("stericsson,ux500-cryp", 0xa03cb000, "cryp1", NULL),
OF_DEV_AUXDATA("stericsson,ux500-hash", 0xa03c2000, "hash1", NULL),
OF_DEV_AUXDATA("stericsson,snd-soc-mop500", 0, "snd-soc-mop500.0",
};
static struct of_dev_auxdata u8540_auxdata_lookup[] __initdata = {
- OF_DEV_AUXDATA("stericsson,db8500-prcmu", 0x80157000, "db8500-prcmu",
- &db8500_prcmu_pdata),
+ OF_DEV_AUXDATA("stericsson,db8500-prcmu", 0x80157000, "db8500-prcmu", NULL),
{},
};
static void __init u8500_init_machine(void)
{
- struct device *parent = db8500_soc_device_init();
-
/* automatically probe child nodes of dbx5x0 devices */
if (of_machine_is_compatible("st-ericsson,u8540"))
of_platform_populate(NULL, u8500_local_bus_nodes,
- u8540_auxdata_lookup, parent);
+ u8540_auxdata_lookup, NULL);
else
of_platform_populate(NULL, u8500_local_bus_nodes,
- u8500_auxdata_lookup, parent);
+ u8500_auxdata_lookup, NULL);
}
static const char * stericsson_dt_platform_compat[] = {
};
DT_MACHINE_START(U8500_DT, "ST-Ericsson Ux5x0 platform (Device Tree Support)")
- .map_io = u8500_map_io,
+ .l2c_aux_val = 0,
+ .l2c_aux_mask = ~0,
.init_irq = ux500_init_irq,
.init_machine = u8500_init_machine,
- .init_late = NULL,
.dt_compat = stericsson_dt_platform_compat,
.restart = ux500_restart,
MACHINE_END
+++ /dev/null
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
- * Author: Lee Jones <lee.jones@linaro.org> for ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/mfd/dbx500-prcmu.h>
-#include <linux/sys_soc.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/of_address.h>
-#include <linux/irq.h>
-#include <linux/irqchip.h>
-#include <linux/irqchip/arm-gic.h>
-#include <linux/platform_data/clk-ux500.h>
-#include <linux/platform_data/arm-ux500-pm.h>
-
-#include <asm/mach/map.h>
-
-#include "setup.h"
-
-#include "board-mop500.h"
-#include "db8500-regs.h"
-#include "id.h"
-
-void ux500_restart(enum reboot_mode mode, const char *cmd)
-{
- local_irq_disable();
- local_fiq_disable();
-
- prcmu_system_reset(0);
-}
-
-/*
- * FIXME: Should we set up the GPIO domain here?
- *
- * The problem is that we cannot put the interrupt resources into the platform
- * device until the irqdomain has been added. Right now, we set the GIC interrupt
- * domain from init_irq(), then load the gpio driver from
- * core_initcall(nmk_gpio_init) and add the platform devices from
- * arch_initcall(customize_machine).
- *
- * This feels fragile because it depends on the gpio device getting probed
- * _before_ any device uses the gpio interrupts.
-*/
-void __init ux500_init_irq(void)
-{
- struct device_node *np;
- struct resource r;
-
- irqchip_init();
- np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu");
- of_address_to_resource(np, 0, &r);
- of_node_put(np);
- if (!r.start) {
- pr_err("could not find PRCMU base resource\n");
- return;
- }
- prcmu_early_init(r.start, r.end-r.start);
- ux500_pm_init(r.start, r.end-r.start);
-
- /*
- * Init clocks here so that they are available for system timer
- * initialization.
- */
- if (cpu_is_u8500_family())
- u8500_clk_init();
- else if (cpu_is_u9540())
- u9540_clk_init();
- else if (cpu_is_u8540())
- u8540_clk_init();
-}
-
-static const char * __init ux500_get_machine(void)
-{
- return kasprintf(GFP_KERNEL, "DB%4x", dbx500_partnumber());
-}
-
-static const char * __init ux500_get_family(void)
-{
- return kasprintf(GFP_KERNEL, "ux500");
-}
-
-static const char * __init ux500_get_revision(void)
-{
- unsigned int rev = dbx500_revision();
-
- if (rev == 0x01)
- return kasprintf(GFP_KERNEL, "%s", "ED");
- else if (rev >= 0xA0)
- return kasprintf(GFP_KERNEL, "%d.%d",
- (rev >> 4) - 0xA + 1, rev & 0xf);
-
- return kasprintf(GFP_KERNEL, "%s", "Unknown");
-}
-
-static ssize_t ux500_get_process(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- if (dbx500_id.process == 0x00)
- return sprintf(buf, "Standard\n");
-
- return sprintf(buf, "%02xnm\n", dbx500_id.process);
-}
-
-static void __init soc_info_populate(struct soc_device_attribute *soc_dev_attr,
- const char *soc_id)
-{
- soc_dev_attr->soc_id = soc_id;
- soc_dev_attr->machine = ux500_get_machine();
- soc_dev_attr->family = ux500_get_family();
- soc_dev_attr->revision = ux500_get_revision();
-}
-
-static const struct device_attribute ux500_soc_attr =
- __ATTR(process, S_IRUGO, ux500_get_process, NULL);
-
-struct device * __init ux500_soc_device_init(const char *soc_id)
-{
- struct device *parent;
- struct soc_device *soc_dev;
- struct soc_device_attribute *soc_dev_attr;
-
- soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
- if (!soc_dev_attr)
- return ERR_PTR(-ENOMEM);
-
- soc_info_populate(soc_dev_attr, soc_id);
-
- soc_dev = soc_device_register(soc_dev_attr);
- if (IS_ERR(soc_dev)) {
- kfree(soc_dev_attr);
- return NULL;
- }
-
- parent = soc_device_to_device(soc_dev);
- device_create_file(parent, &ux500_soc_attr);
-
- return parent;
-}
+++ /dev/null
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-
-#include <asm/cputype.h>
-#include <asm/tlbflush.h>
-#include <asm/cacheflush.h>
-#include <asm/mach/map.h>
-
-#include "setup.h"
-
-#include "db8500-regs.h"
-#include "id.h"
-
-struct dbx500_asic_id dbx500_id;
-
-static unsigned int __init ux500_read_asicid(phys_addr_t addr)
-{
- phys_addr_t base = addr & ~0xfff;
- struct map_desc desc = {
- .virtual = (unsigned long)UX500_VIRT_ROM,
- .pfn = __phys_to_pfn(base),
- .length = SZ_16K,
- .type = MT_DEVICE,
- };
-
- iotable_init(&desc, 1);
-
- /* As in devicemaps_init() */
- local_flush_tlb_all();
- flush_cache_all();
-
- return readl(UX500_VIRT_ROM + (addr & 0xfff));
-}
-
-static void ux500_print_soc_info(unsigned int asicid)
-{
- unsigned int rev = dbx500_revision();
-
- pr_info("DB%4x ", dbx500_partnumber());
-
- if (rev == 0x01)
- pr_cont("Early Drop");
- else if (rev >= 0xA0)
- pr_cont("v%d.%d" , (rev >> 4) - 0xA + 1, rev & 0xf);
- else
- pr_cont("Unknown");
-
- pr_cont(" [%#010x]\n", asicid);
-}
-
-static unsigned int partnumber(unsigned int asicid)
-{
- return (asicid >> 8) & 0xffff;
-}
-
-/*
- * SOC MIDR ASICID ADDRESS ASICID VALUE
- * DB8500ed 0x410fc090 0x9001FFF4 0x00850001
- * DB8500v1 0x411fc091 0x9001FFF4 0x008500A0
- * DB8500v1.1 0x411fc091 0x9001FFF4 0x008500A1
- * DB8500v2 0x412fc091 0x9001DBF4 0x008500B0
- * DB8520v2.2 0x412fc091 0x9001DBF4 0x008500B2
- * DB5500v1 0x412fc091 0x9001FFF4 0x005500A0
- * DB9540 0x413fc090 0xFFFFDBF4 0x009540xx
- */
-
-void __init ux500_setup_id(void)
-{
- unsigned int cpuid = read_cpuid_id();
- unsigned int asicid = 0;
- phys_addr_t addr = 0;
-
- switch (cpuid) {
- case 0x410fc090: /* DB8500ed */
- case 0x411fc091: /* DB8500v1 */
- addr = 0x9001FFF4;
- break;
-
- case 0x412fc091: /* DB8520 / DB8500v2 / DB5500v1 */
- asicid = ux500_read_asicid(0x9001DBF4);
- if (partnumber(asicid) == 0x8500 ||
- partnumber(asicid) == 0x8520)
- /* DB8500v2 */
- break;
-
- /* DB5500v1 */
- addr = 0x9001FFF4;
- break;
-
- case 0x413fc090: /* DB9540 */
- addr = 0xFFFFDBF4;
- break;
- }
-
- if (addr)
- asicid = ux500_read_asicid(addr);
-
- if (!asicid) {
- pr_err("Unable to identify SoC\n");
- ux500_unknown_soc();
- }
-
- dbx500_id.process = asicid >> 24;
- dbx500_id.partnumber = partnumber(asicid);
- dbx500_id.revision = asicid & 0xff;
-
- ux500_print_soc_info(asicid);
-}
+++ /dev/null
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#ifndef __MACH_UX500_ID
-#define __MACH_UX500_ID
-
-/**
- * struct dbx500_asic_id - fields of the ASIC ID
- * @process: the manufacturing process, 0x40 is 40 nm 0x00 is "standard"
- * @partnumber: hithereto 0x8500 for DB8500
- * @revision: version code in the series
- */
-struct dbx500_asic_id {
- u16 partnumber;
- u8 revision;
- u8 process;
-};
-
-extern struct dbx500_asic_id dbx500_id;
-
-static inline unsigned int __attribute_const__ dbx500_partnumber(void)
-{
- return dbx500_id.partnumber;
-}
-
-static inline unsigned int __attribute_const__ dbx500_revision(void)
-{
- return dbx500_id.revision;
-}
-
-/*
- * SOCs
- */
-
-static inline bool __attribute_const__ cpu_is_u8500(void)
-{
- return dbx500_partnumber() == 0x8500;
-}
-
-static inline bool __attribute_const__ cpu_is_u8520(void)
-{
- return dbx500_partnumber() == 0x8520;
-}
-
-static inline bool cpu_is_u8500_family(void)
-{
- return cpu_is_u8500() || cpu_is_u8520();
-}
-
-static inline bool __attribute_const__ cpu_is_u9540(void)
-{
- return dbx500_partnumber() == 0x9540;
-}
-
-static inline bool __attribute_const__ cpu_is_u8540(void)
-{
- return dbx500_partnumber() == 0x8540;
-}
-
-static inline bool __attribute_const__ cpu_is_u8580(void)
-{
- return dbx500_partnumber() == 0x8580;
-}
-
-static inline bool cpu_is_ux540_family(void)
-{
- return cpu_is_u9540() || cpu_is_u8540() || cpu_is_u8580();
-}
-
-/*
- * 8500 revisions
- */
-
-static inline bool __attribute_const__ cpu_is_u8500ed(void)
-{
- return cpu_is_u8500() && dbx500_revision() == 0x00;
-}
-
-static inline bool __attribute_const__ cpu_is_u8500v1(void)
-{
- return cpu_is_u8500() && (dbx500_revision() & 0xf0) == 0xA0;
-}
-
-static inline bool __attribute_const__ cpu_is_u8500v10(void)
-{
- return cpu_is_u8500() && dbx500_revision() == 0xA0;
-}
-
-static inline bool __attribute_const__ cpu_is_u8500v11(void)
-{
- return cpu_is_u8500() && dbx500_revision() == 0xA1;
-}
-
-static inline bool __attribute_const__ cpu_is_u8500v2(void)
-{
- return cpu_is_u8500() && ((dbx500_revision() & 0xf0) == 0xB0);
-}
-
-static inline bool cpu_is_u8500v20(void)
-{
- return cpu_is_u8500() && (dbx500_revision() == 0xB0);
-}
-
-static inline bool cpu_is_u8500v21(void)
-{
- return cpu_is_u8500() && (dbx500_revision() == 0xB1);
-}
-
-static inline bool cpu_is_u8500v22(void)
-{
- return cpu_is_u8500() && (dbx500_revision() == 0xB2);
-}
-
-static inline bool cpu_is_u8500v20_or_later(void)
-{
- return (cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11());
-}
-
-/*
- * 8540 revisions
- */
-
-static inline bool __attribute_const__ cpu_is_u8540v10(void)
-{
- return cpu_is_u8540() && dbx500_revision() == 0xA0;
-}
-
-static inline bool __attribute_const__ cpu_is_u8580v10(void)
-{
- return cpu_is_u8580() && dbx500_revision() == 0xA0;
-}
-
-static inline bool ux500_is_svp(void)
-{
- return false;
-}
-
-#define ux500_unknown_soc() BUG()
-
-#endif
#include "setup.h"
#include "db8500-regs.h"
-#include "id.h"
/* Magic triggers in backup RAM */
#define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4
#ifndef __ASM_ARCH_SETUP_H
#define __ASM_ARCH_SETUP_H
-#include <asm/mach/arch.h>
-#include <linux/init.h>
-#include <linux/mfd/abx500/ab8500.h>
-
-void ux500_restart(enum reboot_mode mode, const char *cmd);
-
-void __init ux500_setup_id(void);
-
-extern void __init ux500_init_irq(void);
-
-extern struct device *ux500_soc_device_init(const char *soc_id);
-
extern void ux500_cpu_die(unsigned int cpu);
#endif /* __ASM_ARCH_SETUP_H */
*/
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/reset/hisi,hi6220-resets.h>
#include <dt-bindings/clock/hi6220-clock.h>
#include <dt-bindings/pinctrl/hisi.h>
#include <dt-bindings/thermal/thermal.h>
compatible = "hisilicon,hi6220-mediactrl", "syscon";
reg = <0x0 0xf4410000 0x0 0x1000>;
#clock-cells = <1>;
+ #reset-cells = <1>;
};
pm_ctrl: pm_ctrl@f7032000 {
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"
+ depends on ARCH_TEGRA_210_SOC
+ depends on OF && PM
+ select PM_CLK
+ help
+ Driver for the Tegra ACONNECT bus which is used to interface with
+ the devices inside the Audio Processing Engine (APE) for Tegra210.
+
config UNIPHIER_SYSTEM_BUS
tristate "UniPhier System Bus driver"
depends on ARCH_UNIPHIER && OF
obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
+obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o
obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o
obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o
--- /dev/null
+/*
+ * Tegra ACONNECT Bus Driver
+ *
+ * Copyright (C) 2016, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#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;
+
+ if (!pdev->dev.of_node)
+ return -EINVAL;
+
+ ret = pm_clk_create(&pdev->dev);
+ if (ret)
+ return ret;
+
+ ret = tegra_aconnect_add_clock(&pdev->dev, "ape");
+ if (ret)
+ goto clk_destroy;
+
+ ret = tegra_aconnect_add_clock(&pdev->dev, "apb2ape");
+ if (ret)
+ goto clk_destroy;
+
+ pm_runtime_enable(&pdev->dev);
+
+ of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
+ dev_info(&pdev->dev, "Tegra ACONNECT bus registered\n");
+
+ return 0;
+
+clk_destroy:
+ pm_clk_destroy(&pdev->dev);
+
+ return ret;
+}
+
+static int tegra_aconnect_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ pm_clk_destroy(&pdev->dev);
+
+ return 0;
+}
+
+static int tegra_aconnect_runtime_resume(struct device *dev)
+{
+ return pm_clk_resume(dev);
+}
+
+static int tegra_aconnect_runtime_suspend(struct device *dev)
+{
+ return pm_clk_suspend(dev);
+}
+
+static const struct dev_pm_ops tegra_aconnect_pm_ops = {
+ SET_RUNTIME_PM_OPS(tegra_aconnect_runtime_suspend,
+ tegra_aconnect_runtime_resume, NULL)
+};
+
+static const struct of_device_id tegra_aconnect_of_match[] = {
+ { .compatible = "nvidia,tegra210-aconnect", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tegra_aconnect_of_match);
+
+static struct platform_driver tegra_aconnect_driver = {
+ .probe = tegra_aconnect_probe,
+ .remove = tegra_aconnect_remove,
+ .driver = {
+ .name = "tegra-aconnect",
+ .of_match_table = tegra_aconnect_of_match,
+ .pm = &tegra_aconnect_pm_ops,
+ },
+};
+module_platform_driver(tegra_aconnect_driver);
+
+MODULE_DESCRIPTION("NVIDIA Tegra ACONNECT Bus Driver");
+MODULE_AUTHOR("Jon Hunter <jonathanh@nvidia.com>");
+MODULE_LICENSE("GPL v2");
of_clk_add_provider(np, of_clk_src_onecell_get,
&clps711x_clk->clk_data);
}
-CLK_OF_DECLARE(clps711x, "cirrus,clps711x-clk", clps711x_clk_init_dt);
+CLK_OF_DECLARE(clps711x, "cirrus,ep7209-clk", clps711x_clk_init_dt);
#endif
#include <linux/of_address.h>
#include <linux/clk-provider.h>
#include <linux/mfd/dbx500-prcmu.h>
-#include <linux/platform_data/clk-ux500.h>
#include "clk.h"
#define PRCC_NUM_PERIPH_CLUSTERS 6
return PRCC_SHOW(clk_data, base, bit);
}
-static const struct of_device_id u8500_clk_of_match[] = {
- { .compatible = "stericsson,u8500-clks", },
- { },
-};
-
/* CLKRST4 is missing making it hard to index things */
enum clkrst_index {
CLKRST1_INDEX = 0,
CLKRST_MAX,
};
-void u8500_clk_init(void)
+static void u8500_clk_init(struct device_node *np)
{
struct prcmu_fw_version *fw_version;
- struct device_node *np = NULL;
struct device_node *child = NULL;
const char *sgaclk_parent = NULL;
struct clk *clk, *rtc_clk, *twd_clk;
u32 bases[CLKRST_MAX];
int i;
- if (of_have_populated_dt())
- np = of_find_matching_node(NULL, u8500_clk_of_match);
- if (!np) {
- pr_err("Either DT or U8500 Clock node not found\n");
- return;
- }
for (i = 0; i < ARRAY_SIZE(bases); i++) {
struct resource r;
of_clk_add_provider(child, of_clk_src_simple_get, twd_clk);
}
}
+CLK_OF_DECLARE(u8500_clks, "stericsson,u8500-clks", u8500_clk_init);
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/mfd/dbx500-prcmu.h>
-#include <linux/platform_data/clk-ux500.h>
#include "clk.h"
-static const struct of_device_id u8540_clk_of_match[] = {
- { .compatible = "stericsson,u8540-clks", },
- { }
-};
-
/* CLKRST4 is missing making it hard to index things */
enum clkrst_index {
CLKRST1_INDEX = 0,
CLKRST_MAX,
};
-void u8540_clk_init(void)
+static void u8540_clk_init(struct device_node *np)
{
struct clk *clk;
- struct device_node *np = NULL;
u32 bases[CLKRST_MAX];
int i;
- if (of_have_populated_dt())
- np = of_find_matching_node(NULL, u8540_clk_of_match);
- if (!np) {
- pr_err("Either DT or U8540 Clock node not found\n");
- return;
- }
for (i = 0; i < ARRAY_SIZE(bases); i++) {
struct resource r;
bases[CLKRST6_INDEX], BIT(0), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "rng");
}
+CLK_OF_DECLARE(u8540_clks, "stericsson,u8540-clks", u8540_clk_init);
#include <linux/clk-provider.h>
#include <linux/mfd/dbx500-prcmu.h>
-#include <linux/platform_data/clk-ux500.h>
#include "clk.h"
-void u9540_clk_init(void)
+static void u9540_clk_init(struct device_node *np)
{
/* register clocks here */
}
+CLK_OF_DECLARE(u9540_clks, "stericsson,u9540-clks", u9540_clk_init);
break;
}
}
-CLOCKSOURCE_OF_DECLARE(clps711x, "cirrus,clps711x-timer", clps711x_timer_init);
+CLOCKSOURCE_OF_DECLARE(clps711x, "cirrus,ep7209-timer", clps711x_timer_init);
#endif
config ARM_SCPI_PROTOCOL
tristate "ARM System Control and Power Interface (SCPI) Message Protocol"
- depends on ARM_MHU
+ depends on MAILBOX
help
System Control and Power Interface (SCPI) Message Protocol is
defined for the purpose of communication between the Application
This protocol library provides interface for all the client drivers
making use of the features offered by the SCP.
+config ARM_SCPI_POWER_DOMAIN
+ tristate "SCPI power domain driver"
+ depends on ARM_SCPI_PROTOCOL || (COMPILE_TEST && OF)
+ default y
+ select PM_GENERIC_DOMAINS if PM
+ help
+ This enables support for the SCPI power domains which can be
+ enabled or disabled via the SCP firmware
+
config EDD
tristate "BIOS Enhanced Disk Drive calls determine boot disk"
depends on X86
config QCOM_SCM
bool
depends on ARM || ARM64
+ select RESET_CONTROLLER
config QCOM_SCM_32
def_bool y
#
obj-$(CONFIG_ARM_PSCI_FW) += psci.o
obj-$(CONFIG_ARM_SCPI_PROTOCOL) += arm_scpi.o
+obj-$(CONFIG_ARM_SCPI_POWER_DOMAIN) += scpi_pm_domain.o
obj-$(CONFIG_DMI) += dmi_scan.o
obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o
obj-$(CONFIG_EDD) += edd.o
} opps[MAX_DVFS_OPPS];
} __packed;
-struct dvfs_get {
- u8 index;
-} __packed;
-
struct dvfs_set {
u8 domain;
u8 index;
__le32 hi_val;
} __packed;
+struct dev_pstate_set {
+ u16 dev_id;
+ u8 pstate;
+} __packed;
+
static struct scpi_drvinfo *scpi_info;
static int scpi_linux_errmap[SCPI_ERR_MAX] = {
static int scpi_dvfs_get_idx(u8 domain)
{
int ret;
- struct dvfs_get dvfs;
+ u8 dvfs_idx;
ret = scpi_send_message(SCPI_CMD_GET_DVFS, &domain, sizeof(domain),
- &dvfs, sizeof(dvfs));
- return ret ? ret : dvfs.index;
+ &dvfs_idx, sizeof(dvfs_idx));
+ return ret ? ret : dvfs_idx;
}
static int scpi_dvfs_set_idx(u8 domain, u8 index)
return ret;
}
-int scpi_sensor_get_value(u16 sensor, u64 *val)
+static int scpi_sensor_get_value(u16 sensor, u64 *val)
{
__le16 id = cpu_to_le16(sensor);
struct sensor_value buf;
return ret;
}
+static int scpi_device_get_power_state(u16 dev_id)
+{
+ int ret;
+ u8 pstate;
+ __le16 id = cpu_to_le16(dev_id);
+
+ ret = scpi_send_message(SCPI_CMD_GET_DEVICE_PWR_STATE, &id,
+ sizeof(id), &pstate, sizeof(pstate));
+ return ret ? ret : pstate;
+}
+
+static int scpi_device_set_power_state(u16 dev_id, u8 pstate)
+{
+ int stat;
+ struct dev_pstate_set dev_set = {
+ .dev_id = cpu_to_le16(dev_id),
+ .pstate = pstate,
+ };
+
+ return scpi_send_message(SCPI_CMD_SET_DEVICE_PWR_STATE, &dev_set,
+ sizeof(dev_set), &stat, sizeof(stat));
+}
+
static struct scpi_ops scpi_ops = {
.get_version = scpi_get_version,
.clk_get_range = scpi_clk_get_range,
.sensor_get_capability = scpi_sensor_get_capability,
.sensor_get_info = scpi_sensor_get_info,
.sensor_get_value = scpi_sensor_get_value,
+ .device_get_power_state = scpi_device_get_power_state,
+ .device_set_power_state = scpi_device_set_power_state,
};
struct scpi_ops *get_scpi_ops(void)
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/qcom_scm.h>
-
-#include <asm/cacheflush.h>
+#include <linux/dma-mapping.h>
#include "qcom_scm.h"
__le32 is_complete;
};
-/**
- * alloc_qcom_scm_command() - Allocate an SCM command
- * @cmd_size: size of the command buffer
- * @resp_size: size of the response buffer
- *
- * Allocate an SCM command, including enough room for the command
- * and response headers as well as the command and response buffers.
- *
- * Returns a valid &qcom_scm_command on success or %NULL if the allocation fails.
- */
-static struct qcom_scm_command *alloc_qcom_scm_command(size_t cmd_size, size_t resp_size)
-{
- struct qcom_scm_command *cmd;
- size_t len = sizeof(*cmd) + sizeof(struct qcom_scm_response) + cmd_size +
- resp_size;
- u32 offset;
-
- cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL);
- if (cmd) {
- cmd->len = cpu_to_le32(len);
- offset = offsetof(struct qcom_scm_command, buf);
- cmd->buf_offset = cpu_to_le32(offset);
- cmd->resp_hdr_offset = cpu_to_le32(offset + cmd_size);
- }
- return cmd;
-}
-
-/**
- * free_qcom_scm_command() - Free an SCM command
- * @cmd: command to free
- *
- * Free an SCM command.
- */
-static inline void free_qcom_scm_command(struct qcom_scm_command *cmd)
-{
- kfree(cmd);
-}
-
/**
* qcom_scm_command_to_response() - Get a pointer to a qcom_scm_response
* @cmd: command
return (void *)rsp + le32_to_cpu(rsp->buf_offset);
}
-static int qcom_scm_remap_error(int err)
-{
- pr_err("qcom_scm_call failed with error code %d\n", err);
- switch (err) {
- case QCOM_SCM_ERROR:
- return -EIO;
- case QCOM_SCM_EINVAL_ADDR:
- case QCOM_SCM_EINVAL_ARG:
- return -EINVAL;
- case QCOM_SCM_EOPNOTSUPP:
- return -EOPNOTSUPP;
- case QCOM_SCM_ENOMEM:
- return -ENOMEM;
- }
- return -EINVAL;
-}
-
static u32 smc(u32 cmd_addr)
{
int context_id;
return r0;
}
-static int __qcom_scm_call(const struct qcom_scm_command *cmd)
-{
- int ret;
- u32 cmd_addr = virt_to_phys(cmd);
-
- /*
- * Flush the command buffer so that the secure world sees
- * the correct data.
- */
- secure_flush_area(cmd, cmd->len);
-
- ret = smc(cmd_addr);
- if (ret < 0)
- ret = qcom_scm_remap_error(ret);
-
- return ret;
-}
-
-static void qcom_scm_inv_range(unsigned long start, unsigned long end)
-{
- u32 cacheline_size, ctr;
-
- asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr));
- cacheline_size = 4 << ((ctr >> 16) & 0xf);
-
- start = round_down(start, cacheline_size);
- end = round_up(end, cacheline_size);
- outer_inv_range(start, end);
- while (start < end) {
- asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start)
- : "memory");
- start += cacheline_size;
- }
- dsb();
- isb();
-}
-
/**
* qcom_scm_call() - Send an SCM command
+ * @dev: struct device
* @svc_id: service identifier
* @cmd_id: command identifier
* @cmd_buf: command buffer
* and response buffers is taken care of by qcom_scm_call; however, callers are
* responsible for any other cached buffers passed over to the secure world.
*/
-static int qcom_scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf,
- size_t cmd_len, void *resp_buf, size_t resp_len)
+static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
+ const void *cmd_buf, size_t cmd_len, void *resp_buf,
+ size_t resp_len)
{
int ret;
struct qcom_scm_command *cmd;
struct qcom_scm_response *rsp;
- unsigned long start, end;
+ size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len;
+ dma_addr_t cmd_phys;
- cmd = alloc_qcom_scm_command(cmd_len, resp_len);
+ cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
+ cmd->len = cpu_to_le32(alloc_len);
+ cmd->buf_offset = cpu_to_le32(sizeof(*cmd));
+ cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len);
+
cmd->id = cpu_to_le32((svc_id << 10) | cmd_id);
if (cmd_buf)
memcpy(qcom_scm_get_command_buffer(cmd), cmd_buf, cmd_len);
+ rsp = qcom_scm_command_to_response(cmd);
+
+ cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, cmd_phys)) {
+ kfree(cmd);
+ return -ENOMEM;
+ }
+
mutex_lock(&qcom_scm_lock);
- ret = __qcom_scm_call(cmd);
+ ret = smc(cmd_phys);
+ if (ret < 0)
+ ret = qcom_scm_remap_error(ret);
mutex_unlock(&qcom_scm_lock);
if (ret)
goto out;
- rsp = qcom_scm_command_to_response(cmd);
- start = (unsigned long)rsp;
-
do {
- qcom_scm_inv_range(start, start + sizeof(*rsp));
+ dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len,
+ sizeof(*rsp), DMA_FROM_DEVICE);
} while (!rsp->is_complete);
- end = (unsigned long)qcom_scm_get_response_buffer(rsp) + resp_len;
- qcom_scm_inv_range(start, end);
-
- if (resp_buf)
- memcpy(resp_buf, qcom_scm_get_response_buffer(rsp), resp_len);
+ if (resp_buf) {
+ dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len +
+ le32_to_cpu(rsp->buf_offset),
+ resp_len, DMA_FROM_DEVICE);
+ memcpy(resp_buf, qcom_scm_get_response_buffer(rsp),
+ resp_len);
+ }
out:
- free_qcom_scm_command(cmd);
+ dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE);
+ kfree(cmd);
return ret;
}
return r0;
}
+/**
+ * qcom_scm_call_atomic2() - Send an atomic SCM command with two arguments
+ * @svc_id: service identifier
+ * @cmd_id: command identifier
+ * @arg1: first argument
+ * @arg2: second argument
+ *
+ * This shall only be used with commands that are guaranteed to be
+ * uninterruptable, atomic and SMP safe.
+ */
+static s32 qcom_scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2)
+{
+ int context_id;
+
+ register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 2);
+ register u32 r1 asm("r1") = (u32)&context_id;
+ register u32 r2 asm("r2") = arg1;
+ register u32 r3 asm("r3") = arg2;
+
+ asm volatile(
+ __asmeq("%0", "r0")
+ __asmeq("%1", "r0")
+ __asmeq("%2", "r1")
+ __asmeq("%3", "r2")
+ __asmeq("%4", "r3")
+#ifdef REQUIRES_SEC
+ ".arch_extension sec\n"
+#endif
+ "smc #0 @ switch to secure world\n"
+ : "=r" (r0)
+ : "r" (r0), "r" (r1), "r" (r2), "r" (r3)
+ );
+ return r0;
+}
+
u32 qcom_scm_get_version(void)
{
int context_id;
}
EXPORT_SYMBOL(qcom_scm_get_version);
-/*
- * Set the cold/warm boot address for one of the CPU cores.
- */
-static int qcom_scm_set_boot_addr(u32 addr, int flags)
-{
- struct {
- __le32 flags;
- __le32 addr;
- } cmd;
-
- cmd.addr = cpu_to_le32(addr);
- cmd.flags = cpu_to_le32(flags);
- return qcom_scm_call(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR,
- &cmd, sizeof(cmd), NULL, 0);
-}
-
/**
* qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
* @entry: Entry point function for the cpus
set_cpu_present(cpu, false);
}
- return qcom_scm_set_boot_addr(virt_to_phys(entry), flags);
+ return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR,
+ flags, virt_to_phys(entry));
}
/**
* Set the Linux entry point for the SCM to transfer control to when coming
* out of a power down. CPU power down may be executed on cpuidle or hotplug.
*/
-int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
+int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
+ const cpumask_t *cpus)
{
int ret;
int flags = 0;
int cpu;
+ struct {
+ __le32 flags;
+ __le32 addr;
+ } cmd;
/*
* Reassign only if we are switching from hotplug entry point
if (!flags)
return 0;
- ret = qcom_scm_set_boot_addr(virt_to_phys(entry), flags);
+ cmd.addr = cpu_to_le32(virt_to_phys(entry));
+ cmd.flags = cpu_to_le32(flags);
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR,
+ &cmd, sizeof(cmd), NULL, 0);
if (!ret) {
for_each_cpu(cpu, cpus)
qcom_scm_wb[cpu].entry = entry;
flags & QCOM_SCM_FLUSH_FLAG_MASK);
}
-int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id)
+int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
{
int ret;
__le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id);
__le32 ret_val = 0;
- ret = qcom_scm_call(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD, &svc_cmd,
- sizeof(svc_cmd), &ret_val, sizeof(ret_val));
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD,
+ &svc_cmd, sizeof(svc_cmd), &ret_val,
+ sizeof(ret_val));
if (ret)
return ret;
return le32_to_cpu(ret_val);
}
-int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
+int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
+ u32 req_cnt, u32 *resp)
{
if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
return -ERANGE;
- return qcom_scm_call(QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP,
+ return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP,
req, req_cnt * sizeof(*req), resp, sizeof(*resp));
}
+
+void __qcom_scm_init(void)
+{
+}
+
+bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
+{
+ __le32 out;
+ __le32 in;
+ int ret;
+
+ in = cpu_to_le32(peripheral);
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
+ QCOM_SCM_PAS_IS_SUPPORTED_CMD,
+ &in, sizeof(in),
+ &out, sizeof(out));
+
+ return ret ? false : !!out;
+}
+
+int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
+ dma_addr_t metadata_phys)
+{
+ __le32 scm_ret;
+ int ret;
+ struct {
+ __le32 proc;
+ __le32 image_addr;
+ } request;
+
+ request.proc = cpu_to_le32(peripheral);
+ request.image_addr = cpu_to_le32(metadata_phys);
+
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
+ QCOM_SCM_PAS_INIT_IMAGE_CMD,
+ &request, sizeof(request),
+ &scm_ret, sizeof(scm_ret));
+
+ return ret ? : le32_to_cpu(scm_ret);
+}
+
+int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
+ phys_addr_t addr, phys_addr_t size)
+{
+ __le32 scm_ret;
+ int ret;
+ struct {
+ __le32 proc;
+ __le32 addr;
+ __le32 len;
+ } request;
+
+ request.proc = cpu_to_le32(peripheral);
+ request.addr = cpu_to_le32(addr);
+ request.len = cpu_to_le32(size);
+
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
+ QCOM_SCM_PAS_MEM_SETUP_CMD,
+ &request, sizeof(request),
+ &scm_ret, sizeof(scm_ret));
+
+ return ret ? : le32_to_cpu(scm_ret);
+}
+
+int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
+{
+ __le32 out;
+ __le32 in;
+ int ret;
+
+ in = cpu_to_le32(peripheral);
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
+ QCOM_SCM_PAS_AUTH_AND_RESET_CMD,
+ &in, sizeof(in),
+ &out, sizeof(out));
+
+ return ret ? : le32_to_cpu(out);
+}
+
+int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
+{
+ __le32 out;
+ __le32 in;
+ int ret;
+
+ in = cpu_to_le32(peripheral);
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
+ QCOM_SCM_PAS_SHUTDOWN_CMD,
+ &in, sizeof(in),
+ &out, sizeof(out));
+
+ return ret ? : le32_to_cpu(out);
+}
+
+int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
+{
+ __le32 out;
+ __le32 in = cpu_to_le32(reset);
+ int ret;
+
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET,
+ &in, sizeof(in),
+ &out, sizeof(out));
+
+ return ret ? : le32_to_cpu(out);
+}
#include <linux/io.h>
#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/types.h>
#include <linux/qcom_scm.h>
+#include <linux/arm-smccc.h>
+#include <linux/dma-mapping.h>
+
+#include "qcom_scm.h"
+
+#define QCOM_SCM_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
+
+#define MAX_QCOM_SCM_ARGS 10
+#define MAX_QCOM_SCM_RETS 3
+
+enum qcom_scm_arg_types {
+ QCOM_SCM_VAL,
+ QCOM_SCM_RO,
+ QCOM_SCM_RW,
+ QCOM_SCM_BUFVAL,
+};
+
+#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\
+ (((a) & 0x3) << 4) | \
+ (((b) & 0x3) << 6) | \
+ (((c) & 0x3) << 8) | \
+ (((d) & 0x3) << 10) | \
+ (((e) & 0x3) << 12) | \
+ (((f) & 0x3) << 14) | \
+ (((g) & 0x3) << 16) | \
+ (((h) & 0x3) << 18) | \
+ (((i) & 0x3) << 20) | \
+ (((j) & 0x3) << 22) | \
+ ((num) & 0xf))
+
+#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+
+/**
+ * struct qcom_scm_desc
+ * @arginfo: Metadata describing the arguments in args[]
+ * @args: The array of arguments for the secure syscall
+ * @res: The values returned by the secure syscall
+ */
+struct qcom_scm_desc {
+ u32 arginfo;
+ u64 args[MAX_QCOM_SCM_ARGS];
+};
+
+static u64 qcom_smccc_convention = -1;
+static DEFINE_MUTEX(qcom_scm_lock);
+
+#define QCOM_SCM_EBUSY_WAIT_MS 30
+#define QCOM_SCM_EBUSY_MAX_RETRY 20
+
+#define N_EXT_QCOM_SCM_ARGS 7
+#define FIRST_EXT_ARG_IDX 3
+#define N_REGISTER_ARGS (MAX_QCOM_SCM_ARGS - N_EXT_QCOM_SCM_ARGS + 1)
+
+/**
+ * qcom_scm_call() - Invoke a syscall in the secure world
+ * @dev: device
+ * @svc_id: service identifier
+ * @cmd_id: command identifier
+ * @desc: Descriptor structure containing arguments and return values
+ *
+ * Sends a command to the SCM and waits for the command to finish processing.
+ * This should *only* be called in pre-emptible context.
+*/
+static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
+ const struct qcom_scm_desc *desc,
+ struct arm_smccc_res *res)
+{
+ int arglen = desc->arginfo & 0xf;
+ int retry_count = 0, i;
+ u32 fn_id = QCOM_SCM_FNID(svc_id, cmd_id);
+ u64 cmd, x5 = desc->args[FIRST_EXT_ARG_IDX];
+ dma_addr_t args_phys = 0;
+ void *args_virt = NULL;
+ size_t alloc_len;
+
+ if (unlikely(arglen > N_REGISTER_ARGS)) {
+ alloc_len = N_EXT_QCOM_SCM_ARGS * sizeof(u64);
+ args_virt = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
+
+ if (!args_virt)
+ return -ENOMEM;
+
+ if (qcom_smccc_convention == ARM_SMCCC_SMC_32) {
+ __le32 *args = args_virt;
+
+ for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++)
+ args[i] = cpu_to_le32(desc->args[i +
+ FIRST_EXT_ARG_IDX]);
+ } else {
+ __le64 *args = args_virt;
+
+ for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++)
+ args[i] = cpu_to_le64(desc->args[i +
+ FIRST_EXT_ARG_IDX]);
+ }
+
+ args_phys = dma_map_single(dev, args_virt, alloc_len,
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(dev, args_phys)) {
+ kfree(args_virt);
+ return -ENOMEM;
+ }
+
+ x5 = args_phys;
+ }
+
+ do {
+ mutex_lock(&qcom_scm_lock);
+
+ cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL,
+ qcom_smccc_convention,
+ ARM_SMCCC_OWNER_SIP, fn_id);
+
+ do {
+ arm_smccc_smc(cmd, desc->arginfo, desc->args[0],
+ desc->args[1], desc->args[2], x5, 0, 0,
+ res);
+ } while (res->a0 == QCOM_SCM_INTERRUPTED);
+
+ mutex_unlock(&qcom_scm_lock);
+
+ if (res->a0 == QCOM_SCM_V2_EBUSY) {
+ if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
+ break;
+ msleep(QCOM_SCM_EBUSY_WAIT_MS);
+ }
+ } while (res->a0 == QCOM_SCM_V2_EBUSY);
+
+ if (args_virt) {
+ dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
+ kfree(args_virt);
+ }
+
+ if (res->a0 < 0)
+ return qcom_scm_remap_error(res->a0);
+
+ return 0;
+}
/**
* qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
/**
* qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
+ * @dev: Device pointer
* @entry: Entry point function for the cpus
* @cpus: The cpumask of cpus that will use the entry point
*
* Set the Linux entry point for the SCM to transfer control to when coming
* out of a power down. CPU power down may be executed on cpuidle or hotplug.
*/
-int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
+int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
+ const cpumask_t *cpus)
{
return -ENOTSUPP;
}
{
}
-int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id)
+int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
{
- return -ENOTSUPP;
+ int ret;
+ struct qcom_scm_desc desc = {0};
+ struct arm_smccc_res res;
+
+ desc.arginfo = QCOM_SCM_ARGS(1);
+ desc.args[0] = QCOM_SCM_FNID(svc_id, cmd_id) |
+ (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
+
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD,
+ &desc, &res);
+
+ return ret ? : res.a1;
}
-int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
+int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
+ u32 req_cnt, u32 *resp)
{
- return -ENOTSUPP;
+ int ret;
+ struct qcom_scm_desc desc = {0};
+ struct arm_smccc_res res;
+
+ if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
+ return -ERANGE;
+
+ desc.args[0] = req[0].addr;
+ desc.args[1] = req[0].val;
+ desc.args[2] = req[1].addr;
+ desc.args[3] = req[1].val;
+ desc.args[4] = req[2].addr;
+ desc.args[5] = req[2].val;
+ desc.args[6] = req[3].addr;
+ desc.args[7] = req[3].val;
+ desc.args[8] = req[4].addr;
+ desc.args[9] = req[4].val;
+ desc.arginfo = QCOM_SCM_ARGS(10);
+
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP, &desc,
+ &res);
+ *resp = res.a1;
+
+ return ret;
+}
+
+void __qcom_scm_init(void)
+{
+ u64 cmd;
+ struct arm_smccc_res res;
+ u32 function = QCOM_SCM_FNID(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD);
+
+ /* First try a SMC64 call */
+ cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
+ ARM_SMCCC_OWNER_SIP, function);
+
+ arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd & (~BIT(ARM_SMCCC_TYPE_SHIFT)),
+ 0, 0, 0, 0, 0, &res);
+
+ if (!res.a0 && res.a1)
+ qcom_smccc_convention = ARM_SMCCC_SMC_64;
+ else
+ qcom_smccc_convention = ARM_SMCCC_SMC_32;
+}
+
+bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
+{
+ int ret;
+ struct qcom_scm_desc desc = {0};
+ struct arm_smccc_res res;
+
+ desc.args[0] = peripheral;
+ desc.arginfo = QCOM_SCM_ARGS(1);
+
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
+ QCOM_SCM_PAS_IS_SUPPORTED_CMD,
+ &desc, &res);
+
+ return ret ? false : !!res.a1;
+}
+
+int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
+ dma_addr_t metadata_phys)
+{
+ int ret;
+ struct qcom_scm_desc desc = {0};
+ struct arm_smccc_res res;
+
+ desc.args[0] = peripheral;
+ desc.args[1] = metadata_phys;
+ desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);
+
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_INIT_IMAGE_CMD,
+ &desc, &res);
+
+ return ret ? : res.a1;
+}
+
+int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
+ phys_addr_t addr, phys_addr_t size)
+{
+ int ret;
+ struct qcom_scm_desc desc = {0};
+ struct arm_smccc_res res;
+
+ desc.args[0] = peripheral;
+ desc.args[1] = addr;
+ desc.args[2] = size;
+ desc.arginfo = QCOM_SCM_ARGS(3);
+
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MEM_SETUP_CMD,
+ &desc, &res);
+
+ return ret ? : res.a1;
+}
+
+int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
+{
+ int ret;
+ struct qcom_scm_desc desc = {0};
+ struct arm_smccc_res res;
+
+ desc.args[0] = peripheral;
+ desc.arginfo = QCOM_SCM_ARGS(1);
+
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
+ QCOM_SCM_PAS_AUTH_AND_RESET_CMD,
+ &desc, &res);
+
+ return ret ? : res.a1;
+}
+
+int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
+{
+ int ret;
+ struct qcom_scm_desc desc = {0};
+ struct arm_smccc_res res;
+
+ desc.args[0] = peripheral;
+ desc.arginfo = QCOM_SCM_ARGS(1);
+
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_SHUTDOWN_CMD,
+ &desc, &res);
+
+ return ret ? : res.a1;
+}
+
+int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
+{
+ struct qcom_scm_desc desc = {0};
+ struct arm_smccc_res res;
+ int ret;
+
+ desc.args[0] = reset;
+ desc.args[1] = 0;
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET, &desc,
+ &res);
+
+ return ret ? : res.a1;
}
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
*/
-
+#include <linux/platform_device.h>
+#include <linux/module.h>
#include <linux/cpumask.h>
#include <linux/export.h>
+#include <linux/dma-mapping.h>
#include <linux/types.h>
#include <linux/qcom_scm.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <linux/reset-controller.h>
#include "qcom_scm.h"
+struct qcom_scm {
+ struct device *dev;
+ struct clk *core_clk;
+ struct clk *iface_clk;
+ struct clk *bus_clk;
+ struct reset_controller_dev reset;
+};
+
+static struct qcom_scm *__scm;
+
+static int qcom_scm_clk_enable(void)
+{
+ int ret;
+
+ ret = clk_prepare_enable(__scm->core_clk);
+ if (ret)
+ goto bail;
+
+ ret = clk_prepare_enable(__scm->iface_clk);
+ if (ret)
+ goto disable_core;
+
+ ret = clk_prepare_enable(__scm->bus_clk);
+ if (ret)
+ goto disable_iface;
+
+ return 0;
+
+disable_iface:
+ clk_disable_unprepare(__scm->iface_clk);
+disable_core:
+ clk_disable_unprepare(__scm->core_clk);
+bail:
+ return ret;
+}
+
+static void qcom_scm_clk_disable(void)
+{
+ clk_disable_unprepare(__scm->core_clk);
+ clk_disable_unprepare(__scm->iface_clk);
+ clk_disable_unprepare(__scm->bus_clk);
+}
+
/**
* qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
* @entry: Entry point function for the cpus
*/
int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
{
- return __qcom_scm_set_warm_boot_addr(entry, cpus);
+ return __qcom_scm_set_warm_boot_addr(__scm->dev, entry, cpus);
}
EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
*/
bool qcom_scm_hdcp_available(void)
{
- int ret;
+ int ret = qcom_scm_clk_enable();
- ret = __qcom_scm_is_call_available(QCOM_SCM_SVC_HDCP,
- QCOM_SCM_CMD_HDCP);
+ if (ret)
+ return ret;
- return (ret > 0) ? true : false;
+ ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP,
+ QCOM_SCM_CMD_HDCP);
+
+ qcom_scm_clk_disable();
+
+ return ret > 0 ? true : false;
}
EXPORT_SYMBOL(qcom_scm_hdcp_available);
*/
int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
{
- return __qcom_scm_hdcp_req(req, req_cnt, resp);
+ int ret = qcom_scm_clk_enable();
+
+ if (ret)
+ return ret;
+
+ ret = __qcom_scm_hdcp_req(__scm->dev, req, req_cnt, resp);
+ qcom_scm_clk_disable();
+ return ret;
}
EXPORT_SYMBOL(qcom_scm_hdcp_req);
+
+/**
+ * qcom_scm_pas_supported() - Check if the peripheral authentication service is
+ * available for the given peripherial
+ * @peripheral: peripheral id
+ *
+ * Returns true if PAS is supported for this peripheral, otherwise false.
+ */
+bool qcom_scm_pas_supported(u32 peripheral)
+{
+ int ret;
+
+ ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
+ QCOM_SCM_PAS_IS_SUPPORTED_CMD);
+ if (ret <= 0)
+ return false;
+
+ return __qcom_scm_pas_supported(__scm->dev, peripheral);
+}
+EXPORT_SYMBOL(qcom_scm_pas_supported);
+
+/**
+ * qcom_scm_pas_init_image() - Initialize peripheral authentication service
+ * state machine for a given peripheral, using the
+ * metadata
+ * @peripheral: peripheral id
+ * @metadata: pointer to memory containing ELF header, program header table
+ * and optional blob of data used for authenticating the metadata
+ * and the rest of the firmware
+ * @size: size of the metadata
+ *
+ * Returns 0 on success.
+ */
+int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size)
+{
+ dma_addr_t mdata_phys;
+ void *mdata_buf;
+ int ret;
+
+ /*
+ * During the scm call memory protection will be enabled for the meta
+ * data blob, so make sure it's physically contiguous, 4K aligned and
+ * non-cachable to avoid XPU violations.
+ */
+ mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys,
+ GFP_KERNEL);
+ if (!mdata_buf) {
+ dev_err(__scm->dev, "Allocation of metadata buffer failed.\n");
+ return -ENOMEM;
+ }
+ memcpy(mdata_buf, metadata, size);
+
+ ret = qcom_scm_clk_enable();
+ if (ret)
+ goto free_metadata;
+
+ ret = __qcom_scm_pas_init_image(__scm->dev, peripheral, mdata_phys);
+
+ qcom_scm_clk_disable();
+
+free_metadata:
+ dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
+
+ return ret;
+}
+EXPORT_SYMBOL(qcom_scm_pas_init_image);
+
+/**
+ * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral
+ * for firmware loading
+ * @peripheral: peripheral id
+ * @addr: start address of memory area to prepare
+ * @size: size of the memory area to prepare
+ *
+ * Returns 0 on success.
+ */
+int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size)
+{
+ int ret;
+
+ ret = qcom_scm_clk_enable();
+ if (ret)
+ return ret;
+
+ ret = __qcom_scm_pas_mem_setup(__scm->dev, peripheral, addr, size);
+ qcom_scm_clk_disable();
+
+ return ret;
+}
+EXPORT_SYMBOL(qcom_scm_pas_mem_setup);
+
+/**
+ * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
+ * and reset the remote processor
+ * @peripheral: peripheral id
+ *
+ * Return 0 on success.
+ */
+int qcom_scm_pas_auth_and_reset(u32 peripheral)
+{
+ int ret;
+
+ ret = qcom_scm_clk_enable();
+ if (ret)
+ return ret;
+
+ ret = __qcom_scm_pas_auth_and_reset(__scm->dev, peripheral);
+ qcom_scm_clk_disable();
+
+ return ret;
+}
+EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset);
+
+/**
+ * qcom_scm_pas_shutdown() - Shut down the remote processor
+ * @peripheral: peripheral id
+ *
+ * Returns 0 on success.
+ */
+int qcom_scm_pas_shutdown(u32 peripheral)
+{
+ int ret;
+
+ ret = qcom_scm_clk_enable();
+ if (ret)
+ return ret;
+
+ ret = __qcom_scm_pas_shutdown(__scm->dev, peripheral);
+ qcom_scm_clk_disable();
+
+ return ret;
+}
+EXPORT_SYMBOL(qcom_scm_pas_shutdown);
+
+static int qcom_scm_pas_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long idx)
+{
+ if (idx != 0)
+ return -EINVAL;
+
+ return __qcom_scm_pas_mss_reset(__scm->dev, 1);
+}
+
+static int qcom_scm_pas_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long idx)
+{
+ if (idx != 0)
+ return -EINVAL;
+
+ return __qcom_scm_pas_mss_reset(__scm->dev, 0);
+}
+
+static const struct reset_control_ops qcom_scm_pas_reset_ops = {
+ .assert = qcom_scm_pas_reset_assert,
+ .deassert = qcom_scm_pas_reset_deassert,
+};
+
+/**
+ * qcom_scm_is_available() - Checks if SCM is available
+ */
+bool qcom_scm_is_available(void)
+{
+ return !!__scm;
+}
+EXPORT_SYMBOL(qcom_scm_is_available);
+
+static int qcom_scm_probe(struct platform_device *pdev)
+{
+ struct qcom_scm *scm;
+ int ret;
+
+ scm = devm_kzalloc(&pdev->dev, sizeof(*scm), GFP_KERNEL);
+ if (!scm)
+ return -ENOMEM;
+
+ scm->core_clk = devm_clk_get(&pdev->dev, "core");
+ if (IS_ERR(scm->core_clk)) {
+ if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER)
+ return PTR_ERR(scm->core_clk);
+
+ scm->core_clk = NULL;
+ }
+
+ if (of_device_is_compatible(pdev->dev.of_node, "qcom,scm")) {
+ scm->iface_clk = devm_clk_get(&pdev->dev, "iface");
+ if (IS_ERR(scm->iface_clk)) {
+ if (PTR_ERR(scm->iface_clk) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "failed to acquire iface clk\n");
+ return PTR_ERR(scm->iface_clk);
+ }
+
+ scm->bus_clk = devm_clk_get(&pdev->dev, "bus");
+ if (IS_ERR(scm->bus_clk)) {
+ if (PTR_ERR(scm->bus_clk) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "failed to acquire bus clk\n");
+ return PTR_ERR(scm->bus_clk);
+ }
+ }
+
+ scm->reset.ops = &qcom_scm_pas_reset_ops;
+ scm->reset.nr_resets = 1;
+ scm->reset.of_node = pdev->dev.of_node;
+ reset_controller_register(&scm->reset);
+
+ /* vote for max clk rate for highest performance */
+ ret = clk_set_rate(scm->core_clk, INT_MAX);
+ if (ret)
+ return ret;
+
+ __scm = scm;
+ __scm->dev = &pdev->dev;
+
+ __qcom_scm_init();
+
+ return 0;
+}
+
+static const struct of_device_id qcom_scm_dt_match[] = {
+ { .compatible = "qcom,scm-apq8064",},
+ { .compatible = "qcom,scm-msm8660",},
+ { .compatible = "qcom,scm-msm8960",},
+ { .compatible = "qcom,scm",},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, qcom_scm_dt_match);
+
+static struct platform_driver qcom_scm_driver = {
+ .driver = {
+ .name = "qcom_scm",
+ .of_match_table = qcom_scm_dt_match,
+ },
+ .probe = qcom_scm_probe,
+};
+
+static int __init qcom_scm_init(void)
+{
+ struct device_node *np, *fw_np;
+ int ret;
+
+ fw_np = of_find_node_by_name(NULL, "firmware");
+
+ if (!fw_np)
+ return -ENODEV;
+
+ np = of_find_matching_node(fw_np, qcom_scm_dt_match);
+
+ if (!np) {
+ of_node_put(fw_np);
+ return -ENODEV;
+ }
+
+ of_node_put(np);
+
+ ret = of_platform_populate(fw_np, qcom_scm_dt_match, NULL, NULL);
+
+ of_node_put(fw_np);
+
+ if (ret)
+ return ret;
+
+ 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");
#define QCOM_SCM_FLAG_HLOS 0x01
#define QCOM_SCM_FLAG_COLDBOOT_MC 0x02
#define QCOM_SCM_FLAG_WARMBOOT_MC 0x04
-extern int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus);
+extern int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
+ const cpumask_t *cpus);
extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
#define QCOM_SCM_CMD_TERMINATE_PC 0x2
#define QCOM_SCM_SVC_INFO 0x6
#define QCOM_IS_CALL_AVAIL_CMD 0x1
-extern int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id);
+extern int __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
+ u32 cmd_id);
#define QCOM_SCM_SVC_HDCP 0x11
#define QCOM_SCM_CMD_HDCP 0x01
-extern int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
- u32 *resp);
+extern int __qcom_scm_hdcp_req(struct device *dev,
+ struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp);
+
+extern void __qcom_scm_init(void);
+
+#define QCOM_SCM_SVC_PIL 0x2
+#define QCOM_SCM_PAS_INIT_IMAGE_CMD 0x1
+#define QCOM_SCM_PAS_MEM_SETUP_CMD 0x2
+#define QCOM_SCM_PAS_AUTH_AND_RESET_CMD 0x5
+#define QCOM_SCM_PAS_SHUTDOWN_CMD 0x6
+#define QCOM_SCM_PAS_IS_SUPPORTED_CMD 0x7
+#define QCOM_SCM_PAS_MSS_RESET 0xa
+extern bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral);
+extern int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
+ dma_addr_t metadata_phys);
+extern int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
+ phys_addr_t addr, phys_addr_t size);
+extern int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral);
+extern int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral);
+extern int __qcom_scm_pas_mss_reset(struct device *dev, bool reset);
/* common error codes */
+#define QCOM_SCM_V2_EBUSY -12
#define QCOM_SCM_ENOMEM -5
#define QCOM_SCM_EOPNOTSUPP -4
#define QCOM_SCM_EINVAL_ADDR -3
#define QCOM_SCM_ERROR -1
#define QCOM_SCM_INTERRUPTED 1
+static inline int qcom_scm_remap_error(int err)
+{
+ switch (err) {
+ case QCOM_SCM_ERROR:
+ return -EIO;
+ case QCOM_SCM_EINVAL_ADDR:
+ case QCOM_SCM_EINVAL_ARG:
+ return -EINVAL;
+ case QCOM_SCM_EOPNOTSUPP:
+ return -EOPNOTSUPP;
+ case QCOM_SCM_ENOMEM:
+ return -ENOMEM;
+ case QCOM_SCM_V2_EBUSY:
+ return -EBUSY;
+ }
+ return -EINVAL;
+}
+
#endif
--- /dev/null
+/*
+ * SCPI Generic power domain support.
+ *
+ * Copyright (C) 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/pm_domain.h>
+#include <linux/scpi_protocol.h>
+
+struct scpi_pm_domain {
+ struct generic_pm_domain genpd;
+ struct scpi_ops *ops;
+ u32 domain;
+ char name[30];
+};
+
+/*
+ * These device power state values are not well-defined in the specification.
+ * In case, different implementations use different values, we can make these
+ * specific to compatibles rather than getting these values from device tree.
+ */
+enum scpi_power_domain_state {
+ SCPI_PD_STATE_ON = 0,
+ SCPI_PD_STATE_OFF = 3,
+};
+
+#define to_scpi_pd(gpd) container_of(gpd, struct scpi_pm_domain, genpd)
+
+static int scpi_pd_power(struct scpi_pm_domain *pd, bool power_on)
+{
+ int ret;
+ enum scpi_power_domain_state state;
+
+ if (power_on)
+ state = SCPI_PD_STATE_ON;
+ else
+ state = SCPI_PD_STATE_OFF;
+
+ ret = pd->ops->device_set_power_state(pd->domain, state);
+ if (ret)
+ return ret;
+
+ return !(state == pd->ops->device_get_power_state(pd->domain));
+}
+
+static int scpi_pd_power_on(struct generic_pm_domain *domain)
+{
+ struct scpi_pm_domain *pd = to_scpi_pd(domain);
+
+ return scpi_pd_power(pd, true);
+}
+
+static int scpi_pd_power_off(struct generic_pm_domain *domain)
+{
+ struct scpi_pm_domain *pd = to_scpi_pd(domain);
+
+ return scpi_pd_power(pd, false);
+}
+
+static int scpi_pm_domain_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct scpi_pm_domain *scpi_pd;
+ struct genpd_onecell_data *scpi_pd_data;
+ struct generic_pm_domain **domains;
+ struct scpi_ops *scpi_ops;
+ int ret, num_domains, i;
+
+ scpi_ops = get_scpi_ops();
+ if (!scpi_ops)
+ return -EPROBE_DEFER;
+
+ if (!np) {
+ dev_err(dev, "device tree node not found\n");
+ return -ENODEV;
+ }
+
+ if (!scpi_ops->device_set_power_state ||
+ !scpi_ops->device_get_power_state) {
+ dev_err(dev, "power domains not supported in the firmware\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_u32(np, "num-domains", &num_domains);
+ if (ret) {
+ dev_err(dev, "number of domains not found\n");
+ return -EINVAL;
+ }
+
+ scpi_pd = devm_kcalloc(dev, num_domains, sizeof(*scpi_pd), GFP_KERNEL);
+ if (!scpi_pd)
+ return -ENOMEM;
+
+ scpi_pd_data = devm_kzalloc(dev, sizeof(*scpi_pd_data), GFP_KERNEL);
+ if (!scpi_pd_data)
+ return -ENOMEM;
+
+ domains = devm_kcalloc(dev, num_domains, sizeof(*domains), GFP_KERNEL);
+ if (!domains)
+ return -ENOMEM;
+
+ for (i = 0; i < num_domains; i++, scpi_pd++) {
+ domains[i] = &scpi_pd->genpd;
+
+ scpi_pd->domain = i;
+ scpi_pd->ops = scpi_ops;
+ sprintf(scpi_pd->name, "%s.%d", np->name, i);
+ scpi_pd->genpd.name = scpi_pd->name;
+ scpi_pd->genpd.power_off = scpi_pd_power_off;
+ scpi_pd->genpd.power_on = scpi_pd_power_on;
+
+ /*
+ * Treat all power domains as off at boot.
+ *
+ * The SCP firmware itself may have switched on some domains,
+ * but for reference counting purpose, keep it this way.
+ */
+ pm_genpd_init(&scpi_pd->genpd, NULL, true);
+ }
+
+ scpi_pd_data->domains = domains;
+ scpi_pd_data->num_domains = num_domains;
+
+ of_genpd_add_provider_onecell(np, scpi_pd_data);
+
+ return 0;
+}
+
+static const struct of_device_id scpi_power_domain_ids[] = {
+ { .compatible = "arm,scpi-power-domains", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, scpi_power_domain_ids);
+
+static struct platform_driver scpi_power_domain_driver = {
+ .driver = {
+ .name = "scpi_power_domain",
+ .of_match_table = scpi_power_domain_ids,
+ },
+ .probe = scpi_pm_domain_probe,
+};
+module_platform_driver(scpi_power_domain_driver);
+
+MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
+MODULE_DESCRIPTION("ARM SCPI power domain driver");
+MODULE_LICENSE("GPL v2");
return -ENOMEM;
priv->syscon =
- syscon_regmap_lookup_by_compatible("cirrus,clps711x-syscon1");
+ syscon_regmap_lookup_by_compatible("cirrus,ep7209-syscon1");
if (IS_ERR(priv->syscon))
return PTR_ERR(priv->syscon);
}
static const struct of_device_id clps711x_keypad_of_match[] = {
- { .compatible = "cirrus,clps711x-keypad", },
+ { .compatible = "cirrus,ep7209-keypad", },
{ }
};
MODULE_DEVICE_TABLE(of, clps711x_keypad_of_match);
return _clps711x_intc_init(np, res.start, resource_size(&res));
}
-IRQCHIP_DECLARE(clps711x, "cirrus,clps711x-intc", clps711x_intc_init_dt);
+IRQCHIP_DECLARE(clps711x, "cirrus,ep7209-intc", clps711x_intc_init_dt);
#endif
goto err_m2m;
/* Initialize continious memory allocator */
+ vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
gsc->alloc_ctx = vb2_dma_contig_init_ctx(dev);
if (IS_ERR(gsc->alloc_ctx)) {
ret = PTR_ERR(gsc->alloc_ctx);
v4l2_device_unregister(&gsc->v4l2_dev);
vb2_dma_contig_cleanup_ctx(gsc->alloc_ctx);
+ vb2_dma_contig_clear_max_seg_size(&pdev->dev);
pm_runtime_disable(&pdev->dev);
gsc_clk_put(gsc);
}
/* Initialize contiguous memory allocator */
+ vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev);
if (IS_ERR(fimc->alloc_ctx)) {
ret = PTR_ERR(fimc->alloc_ctx);
fimc_unregister_capture_subdev(fimc);
vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);
+ vb2_dma_contig_clear_max_seg_size(&pdev->dev);
clk_disable(fimc->clock[CLK_BUS]);
fimc_clk_put(fimc);
if (ret < 0)
goto err_pm;
+ vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
is->alloc_ctx = vb2_dma_contig_init_ctx(dev);
if (IS_ERR(is->alloc_ctx)) {
ret = PTR_ERR(is->alloc_ctx);
free_irq(is->irq, is);
fimc_is_unregister_subdevs(is);
vb2_dma_contig_cleanup_ctx(is->alloc_ctx);
+ vb2_dma_contig_clear_max_seg_size(dev);
fimc_is_put_clocks(is);
fimc_is_debugfs_remove(is);
release_firmware(is->fw.f_w);
goto err_sd;
}
+ vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev);
if (IS_ERR(fimc->alloc_ctx)) {
ret = PTR_ERR(fimc->alloc_ctx);
pm_runtime_set_suspended(dev);
fimc_lite_unregister_capture_subdev(fimc);
vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);
+ vb2_dma_contig_clear_max_seg_size(dev);
fimc_lite_clk_put(fimc);
dev_info(dev, "Driver unloaded\n");
goto put_clk_gate;
}
+ vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
if (IS_ERR(dev->alloc_ctx)) {
ret = PTR_ERR(dev->alloc_ctx);
video_unregister_device(dev->vfd);
v4l2_device_unregister(&dev->v4l2_dev);
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+ vb2_dma_contig_clear_max_seg_size(&pdev->dev);
clk_unprepare(dev->gate);
clk_put(dev->gate);
clk_unprepare(dev->clk);
goto device_register_rollback;
}
+ vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
if (IS_ERR(jpeg->alloc_ctx)) {
v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
video_unregister_device(jpeg->vfd_decoder);
video_unregister_device(jpeg->vfd_encoder);
vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
+ vb2_dma_contig_clear_max_seg_size(&pdev->dev);
v4l2_m2m_release(jpeg->m2m_dev);
v4l2_device_unregister(&jpeg->v4l2_dev);
#include <media/v4l2-event.h>
#include <linux/workqueue.h>
#include <linux/of.h>
+#include <linux/of_reserved_mem.h>
#include <media/videobuf2-v4l2.h>
#include "s5p_mfc_common.h"
#include "s5p_mfc_ctrl.h"
#include "s5p_mfc_dec.h"
#include "s5p_mfc_enc.h"
#include "s5p_mfc_intr.h"
+#include "s5p_mfc_iommu.h"
#include "s5p_mfc_opr.h"
#include "s5p_mfc_cmd.h"
#include "s5p_mfc_pm.h"
.mmap = s5p_mfc_mmap,
};
-static int match_child(struct device *dev, void *data)
+/* DMA memory related helper functions */
+static void s5p_mfc_memdev_release(struct device *dev)
{
- if (!dev_name(dev))
- return 0;
- return !strcmp(dev_name(dev), (char *)data);
+ of_reserved_mem_device_release(dev);
}
-static void *mfc_get_drv_data(struct platform_device *pdev);
-
-static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev)
+static struct device *s5p_mfc_alloc_memdev(struct device *dev,
+ const char *name, unsigned int idx)
{
- unsigned int mem_info[2] = { };
+ struct device *child;
+ int ret;
- dev->mem_dev_l = devm_kzalloc(&dev->plat_dev->dev,
- sizeof(struct device), GFP_KERNEL);
- if (!dev->mem_dev_l) {
- mfc_err("Not enough memory\n");
- return -ENOMEM;
- }
- device_initialize(dev->mem_dev_l);
- of_property_read_u32_array(dev->plat_dev->dev.of_node,
- "samsung,mfc-l", mem_info, 2);
- if (dma_declare_coherent_memory(dev->mem_dev_l, mem_info[0],
- mem_info[0], mem_info[1],
- DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) {
- mfc_err("Failed to declare coherent memory for\n"
- "MFC device\n");
- return -ENOMEM;
+ child = devm_kzalloc(dev, sizeof(struct device), GFP_KERNEL);
+ if (!child)
+ return NULL;
+
+ device_initialize(child);
+ dev_set_name(child, "%s:%s", dev_name(dev), name);
+ child->parent = dev;
+ child->bus = dev->bus;
+ child->coherent_dma_mask = dev->coherent_dma_mask;
+ child->dma_mask = dev->dma_mask;
+ child->release = s5p_mfc_memdev_release;
+
+ if (device_add(child) == 0) {
+ ret = of_reserved_mem_device_init_by_idx(child, dev->of_node,
+ idx);
+ if (ret == 0)
+ return child;
}
- dev->mem_dev_r = devm_kzalloc(&dev->plat_dev->dev,
- sizeof(struct device), GFP_KERNEL);
- if (!dev->mem_dev_r) {
- mfc_err("Not enough memory\n");
- return -ENOMEM;
+ put_device(child);
+ return NULL;
+}
+
+static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev)
+{
+ struct device *dev = &mfc_dev->plat_dev->dev;
+
+ /*
+ * When IOMMU is available, we cannot use the default configuration,
+ * because of MFC firmware requirements: address space limited to
+ * 256M and non-zero default start address.
+ * This is still simplified, not optimal configuration, but for now
+ * IOMMU core doesn't allow to configure device's IOMMUs channel
+ * separately.
+ */
+ if (exynos_is_iommu_available(dev)) {
+ int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE,
+ S5P_MFC_IOMMU_DMA_SIZE);
+ if (ret == 0)
+ mfc_dev->mem_dev_l = mfc_dev->mem_dev_r = dev;
+ return ret;
}
- device_initialize(dev->mem_dev_r);
- of_property_read_u32_array(dev->plat_dev->dev.of_node,
- "samsung,mfc-r", mem_info, 2);
- if (dma_declare_coherent_memory(dev->mem_dev_r, mem_info[0],
- mem_info[0], mem_info[1],
- DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) {
- pr_err("Failed to declare coherent memory for\n"
- "MFC device\n");
- return -ENOMEM;
+
+ /*
+ * Create and initialize virtual devices for accessing
+ * reserved memory regions.
+ */
+ mfc_dev->mem_dev_l = s5p_mfc_alloc_memdev(dev, "left",
+ MFC_BANK1_ALLOC_CTX);
+ if (!mfc_dev->mem_dev_l)
+ return -ENODEV;
+ mfc_dev->mem_dev_r = s5p_mfc_alloc_memdev(dev, "right",
+ MFC_BANK2_ALLOC_CTX);
+ if (!mfc_dev->mem_dev_r) {
+ device_unregister(mfc_dev->mem_dev_l);
+ return -ENODEV;
}
+
return 0;
}
+static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev)
+{
+ struct device *dev = &mfc_dev->plat_dev->dev;
+
+ if (exynos_is_iommu_available(dev)) {
+ exynos_unconfigure_iommu(dev);
+ return;
+ }
+
+ device_unregister(mfc_dev->mem_dev_l);
+ device_unregister(mfc_dev->mem_dev_r);
+}
+
+static void *mfc_get_drv_data(struct platform_device *pdev);
+
/* MFC probe function */
static int s5p_mfc_probe(struct platform_device *pdev)
{
dev->variant = mfc_get_drv_data(pdev);
- ret = s5p_mfc_init_pm(dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to get mfc clock source\n");
- return ret;
- }
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
goto err_res;
}
- if (pdev->dev.of_node) {
- ret = s5p_mfc_alloc_memdevs(dev);
- if (ret < 0)
- goto err_res;
- } else {
- dev->mem_dev_l = device_find_child(&dev->plat_dev->dev,
- "s5p-mfc-l", match_child);
- if (!dev->mem_dev_l) {
- mfc_err("Mem child (L) device get failed\n");
- ret = -ENODEV;
- goto err_res;
- }
- dev->mem_dev_r = device_find_child(&dev->plat_dev->dev,
- "s5p-mfc-r", match_child);
- if (!dev->mem_dev_r) {
- mfc_err("Mem child (R) device get failed\n");
- ret = -ENODEV;
- goto err_res;
- }
+ ret = s5p_mfc_configure_dma_memory(dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to configure DMA memory\n");
+ return ret;
}
+ ret = s5p_mfc_init_pm(dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to get mfc clock source\n");
+ return ret;
+ }
+
+ vb2_dma_contig_set_max_seg_size(dev->mem_dev_l, DMA_BIT_MASK(32));
dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l);
if (IS_ERR(dev->alloc_ctx[0])) {
ret = PTR_ERR(dev->alloc_ctx[0]);
goto err_res;
}
+ vb2_dma_contig_set_max_seg_size(dev->mem_dev_r, DMA_BIT_MASK(32));
dev->alloc_ctx[1] = vb2_dma_contig_init_ctx(dev->mem_dev_r);
if (IS_ERR(dev->alloc_ctx[1])) {
ret = PTR_ERR(dev->alloc_ctx[1]);
vfd->vfl_dir = VFL_DIR_M2M;
snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME);
dev->vfd_dec = vfd;
- ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
- if (ret) {
- v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
- video_device_release(vfd);
- goto err_dec_reg;
- }
- v4l2_info(&dev->v4l2_dev,
- "decoder registered as /dev/video%d\n", vfd->num);
video_set_drvdata(vfd, dev);
/* encoder */
vfd->vfl_dir = VFL_DIR_M2M;
snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME);
dev->vfd_enc = vfd;
- ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
- if (ret) {
- v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
- video_device_release(vfd);
- goto err_enc_reg;
- }
- v4l2_info(&dev->v4l2_dev,
- "encoder registered as /dev/video%d\n", vfd->num);
video_set_drvdata(vfd, dev);
platform_set_drvdata(pdev, dev);
s5p_mfc_init_hw_cmds(dev);
s5p_mfc_init_regs(dev);
+ /* Register decoder and encoder */
+ ret = video_register_device(dev->vfd_dec, VFL_TYPE_GRABBER, 0);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+ video_device_release(dev->vfd_dec);
+ goto err_dec_reg;
+ }
+ v4l2_info(&dev->v4l2_dev,
+ "decoder registered as /dev/video%d\n", dev->vfd_dec->num);
+
+ ret = video_register_device(dev->vfd_enc, VFL_TYPE_GRABBER, 0);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+ video_device_release(dev->vfd_enc);
+ goto err_enc_reg;
+ }
+ v4l2_info(&dev->v4l2_dev,
+ "encoder registered as /dev/video%d\n", dev->vfd_enc->num);
+
pr_debug("%s--\n", __func__);
return 0;
/* Deinit MFC if probe had failed */
err_enc_reg:
- video_device_release(dev->vfd_enc);
-err_enc_alloc:
video_unregister_device(dev->vfd_dec);
err_dec_reg:
+ video_device_release(dev->vfd_enc);
+err_enc_alloc:
video_device_release(dev->vfd_dec);
err_dec_alloc:
v4l2_device_unregister(&dev->v4l2_dev);
s5p_mfc_release_firmware(dev);
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
- if (pdev->dev.of_node) {
- put_device(dev->mem_dev_l);
- put_device(dev->mem_dev_r);
- }
+ s5p_mfc_unconfigure_dma_memory(dev);
+ vb2_dma_contig_clear_max_seg_size(dev->mem_dev_l);
+ vb2_dma_contig_clear_max_seg_size(dev->mem_dev_r);
s5p_mfc_final_pm(dev);
return 0;
--- /dev/null
+/*
+ * Copyright (C) 2015 Samsung Electronics Co.Ltd
+ * Authors: Marek Szyprowski <m.szyprowski@samsung.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.
+ */
+
+#ifndef S5P_MFC_IOMMU_H_
+#define S5P_MFC_IOMMU_H_
+
+#define S5P_MFC_IOMMU_DMA_BASE 0x20000000lu
+#define S5P_MFC_IOMMU_DMA_SIZE SZ_256M
+
+#ifdef CONFIG_EXYNOS_IOMMU
+
+#include <asm/dma-iommu.h>
+
+static inline bool exynos_is_iommu_available(struct device *dev)
+{
+ return dev->archdata.iommu != NULL;
+}
+
+static inline void exynos_unconfigure_iommu(struct device *dev)
+{
+ struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
+
+ arm_iommu_detach_device(dev);
+ arm_iommu_release_mapping(mapping);
+}
+
+static inline int exynos_configure_iommu(struct device *dev,
+ unsigned int base, unsigned int size)
+{
+ struct dma_iommu_mapping *mapping = NULL;
+ int ret;
+
+ /* Disable the default mapping created by device core */
+ if (to_dma_iommu_mapping(dev))
+ exynos_unconfigure_iommu(dev);
+
+ mapping = arm_iommu_create_mapping(dev->bus, base, size);
+ if (IS_ERR(mapping)) {
+ pr_warn("Failed to create IOMMU mapping for device %s\n",
+ dev_name(dev));
+ return PTR_ERR(mapping);
+ }
+
+ ret = arm_iommu_attach_device(dev, mapping);
+ if (ret) {
+ pr_warn("Failed to attached device %s to IOMMU_mapping\n",
+ dev_name(dev));
+ arm_iommu_release_mapping(mapping);
+ return ret;
+ }
+
+ return 0;
+}
+
+#else
+
+static inline bool exynos_is_iommu_available(struct device *dev)
+{
+ return false;
+}
+
+static inline int exynos_configure_iommu(struct device *dev,
+ unsigned int base, unsigned int size)
+{
+ return -ENOSYS;
+}
+
+static inline void exynos_unconfigure_iommu(struct device *dev) { }
+
+#endif
+
+#endif /* S5P_MFC_IOMMU_H_ */
goto fail;
}
+ vb2_dma_contig_set_max_seg_size(mdev->dev, DMA_BIT_MASK(32));
mdev->alloc_ctx = vb2_dma_contig_init_ctx(mdev->dev);
if (IS_ERR(mdev->alloc_ctx)) {
mxr_err(mdev, "could not acquire vb2 allocator\n");
kfree(mdev->output[i]);
vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
+ vb2_dma_contig_clear_max_seg_size(mdev->dev);
v4l2_device_unregister(&mdev->v4l2_dev);
}
config IR_RX51
tristate "Nokia N900 IR transmitter diode"
- depends on OMAP_DM_TIMER && ARCH_OMAP2PLUS && LIRC && !ARCH_MULTIPLATFORM
+ depends on OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS && LIRC
---help---
Say Y or M here if you want to enable support for the IR
transmitter diode built in the Nokia N900 (RX51) device.
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
-
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/wait.h>
-
-#include <plat/dmtimer.h>
-#include <plat/clock.h>
+#include <linux/pwm.h>
+#include <linux/of.h>
+#include <linux/hrtimer.h>
#include <media/lirc.h>
#include <media/lirc_dev.h>
#define WBUF_LEN 256
-#define TIMER_MAX_VALUE 0xffffffff
-
struct lirc_rx51 {
- struct omap_dm_timer *pwm_timer;
- struct omap_dm_timer *pulse_timer;
+ struct pwm_device *pwm;
+ struct hrtimer timer;
struct device *dev;
struct lirc_rx51_platform_data *pdata;
wait_queue_head_t wqueue;
- unsigned long fclk_khz;
unsigned int freq; /* carrier frequency */
unsigned int duty_cycle; /* carrier duty cycle */
- unsigned int irq_num;
- unsigned int match;
int wbuf[WBUF_LEN];
int wbuf_index;
unsigned long device_is_open;
- int pwm_timer_num;
};
-static void lirc_rx51_on(struct lirc_rx51 *lirc_rx51)
+static inline void lirc_rx51_on(struct lirc_rx51 *lirc_rx51)
{
- omap_dm_timer_set_pwm(lirc_rx51->pwm_timer, 0, 1,
- OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+ pwm_enable(lirc_rx51->pwm);
}
-static void lirc_rx51_off(struct lirc_rx51 *lirc_rx51)
+static inline void lirc_rx51_off(struct lirc_rx51 *lirc_rx51)
{
- omap_dm_timer_set_pwm(lirc_rx51->pwm_timer, 0, 1,
- OMAP_TIMER_TRIGGER_NONE);
+ pwm_disable(lirc_rx51->pwm);
}
static int init_timing_params(struct lirc_rx51 *lirc_rx51)
{
- u32 load, match;
+ struct pwm_device *pwm = lirc_rx51->pwm;
+ int duty, period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, lirc_rx51->freq);
- load = -(lirc_rx51->fclk_khz * 1000 / lirc_rx51->freq);
- match = -(lirc_rx51->duty_cycle * -load / 100);
- omap_dm_timer_set_load(lirc_rx51->pwm_timer, 1, load);
- omap_dm_timer_set_match(lirc_rx51->pwm_timer, 1, match);
- omap_dm_timer_write_counter(lirc_rx51->pwm_timer, TIMER_MAX_VALUE - 2);
- omap_dm_timer_start(lirc_rx51->pwm_timer);
- omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer, 0);
- omap_dm_timer_start(lirc_rx51->pulse_timer);
+ duty = DIV_ROUND_CLOSEST(lirc_rx51->duty_cycle * period, 100);
- lirc_rx51->match = 0;
+ pwm_config(pwm, duty, period);
return 0;
}
-#define tics_after(a, b) ((long)(b) - (long)(a) < 0)
-
-static int pulse_timer_set_timeout(struct lirc_rx51 *lirc_rx51, int usec)
+static enum hrtimer_restart lirc_rx51_timer_cb(struct hrtimer *timer)
{
- int counter;
-
- BUG_ON(usec < 0);
-
- if (lirc_rx51->match == 0)
- counter = omap_dm_timer_read_counter(lirc_rx51->pulse_timer);
- else
- counter = lirc_rx51->match;
-
- counter += (u32)(lirc_rx51->fclk_khz * usec / (1000));
- omap_dm_timer_set_match(lirc_rx51->pulse_timer, 1, counter);
- omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer,
- OMAP_TIMER_INT_MATCH);
- if (tics_after(omap_dm_timer_read_counter(lirc_rx51->pulse_timer),
- counter)) {
- return 1;
- }
- return 0;
-}
-
-static irqreturn_t lirc_rx51_interrupt_handler(int irq, void *ptr)
-{
- unsigned int retval;
- struct lirc_rx51 *lirc_rx51 = ptr;
-
- retval = omap_dm_timer_read_status(lirc_rx51->pulse_timer);
- if (!retval)
- return IRQ_NONE;
+ struct lirc_rx51 *lirc_rx51 =
+ container_of(timer, struct lirc_rx51, timer);
+ ktime_t now;
- if (retval & ~OMAP_TIMER_INT_MATCH)
- dev_err_ratelimited(lirc_rx51->dev,
- ": Unexpected interrupt source: %x\n", retval);
-
- omap_dm_timer_write_status(lirc_rx51->pulse_timer,
- OMAP_TIMER_INT_MATCH |
- OMAP_TIMER_INT_OVERFLOW |
- OMAP_TIMER_INT_CAPTURE);
if (lirc_rx51->wbuf_index < 0) {
dev_err_ratelimited(lirc_rx51->dev,
- ": BUG wbuf_index has value of %i\n",
+ "BUG wbuf_index has value of %i\n",
lirc_rx51->wbuf_index);
goto end;
}
* pulses until we catch up.
*/
do {
+ u64 ns;
+
if (lirc_rx51->wbuf_index >= WBUF_LEN)
goto end;
if (lirc_rx51->wbuf[lirc_rx51->wbuf_index] == -1)
else
lirc_rx51_on(lirc_rx51);
- retval = pulse_timer_set_timeout(lirc_rx51,
- lirc_rx51->wbuf[lirc_rx51->wbuf_index]);
+ ns = 1000 * lirc_rx51->wbuf[lirc_rx51->wbuf_index];
+ hrtimer_add_expires_ns(timer, ns);
+
lirc_rx51->wbuf_index++;
- } while (retval);
+ now = timer->base->get_time();
+
+ } while (hrtimer_get_expires_tv64(timer) < now.tv64);
- return IRQ_HANDLED;
+ return HRTIMER_RESTART;
end:
/* Stop TX here */
lirc_rx51_off(lirc_rx51);
lirc_rx51->wbuf_index = -1;
- omap_dm_timer_stop(lirc_rx51->pwm_timer);
- omap_dm_timer_stop(lirc_rx51->pulse_timer);
- omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer, 0);
- wake_up_interruptible(&lirc_rx51->wqueue);
-
- return IRQ_HANDLED;
-}
-
-static int lirc_rx51_init_port(struct lirc_rx51 *lirc_rx51)
-{
- struct clk *clk_fclk;
- int retval, pwm_timer = lirc_rx51->pwm_timer_num;
-
- lirc_rx51->pwm_timer = omap_dm_timer_request_specific(pwm_timer);
- if (lirc_rx51->pwm_timer == NULL) {
- dev_err(lirc_rx51->dev, ": Error requesting GPT%d timer\n",
- pwm_timer);
- return -EBUSY;
- }
-
- lirc_rx51->pulse_timer = omap_dm_timer_request();
- if (lirc_rx51->pulse_timer == NULL) {
- dev_err(lirc_rx51->dev, ": Error requesting pulse timer\n");
- retval = -EBUSY;
- goto err1;
- }
-
- omap_dm_timer_set_source(lirc_rx51->pwm_timer, OMAP_TIMER_SRC_SYS_CLK);
- omap_dm_timer_set_source(lirc_rx51->pulse_timer,
- OMAP_TIMER_SRC_SYS_CLK);
-
- omap_dm_timer_enable(lirc_rx51->pwm_timer);
- omap_dm_timer_enable(lirc_rx51->pulse_timer);
-
- lirc_rx51->irq_num = omap_dm_timer_get_irq(lirc_rx51->pulse_timer);
- retval = request_irq(lirc_rx51->irq_num, lirc_rx51_interrupt_handler,
- IRQF_SHARED, "lirc_pulse_timer", lirc_rx51);
- if (retval) {
- dev_err(lirc_rx51->dev, ": Failed to request interrupt line\n");
- goto err2;
- }
-
- clk_fclk = omap_dm_timer_get_fclk(lirc_rx51->pwm_timer);
- lirc_rx51->fclk_khz = clk_fclk->rate / 1000;
-
- return 0;
-err2:
- omap_dm_timer_free(lirc_rx51->pulse_timer);
-err1:
- omap_dm_timer_free(lirc_rx51->pwm_timer);
-
- return retval;
-}
-
-static int lirc_rx51_free_port(struct lirc_rx51 *lirc_rx51)
-{
- omap_dm_timer_set_int_enable(lirc_rx51->pulse_timer, 0);
- free_irq(lirc_rx51->irq_num, lirc_rx51);
- lirc_rx51_off(lirc_rx51);
- omap_dm_timer_disable(lirc_rx51->pwm_timer);
- omap_dm_timer_disable(lirc_rx51->pulse_timer);
- omap_dm_timer_free(lirc_rx51->pwm_timer);
- omap_dm_timer_free(lirc_rx51->pulse_timer);
- lirc_rx51->wbuf_index = -1;
+ wake_up_interruptible(&lirc_rx51->wqueue);
- return 0;
+ return HRTIMER_NORESTART;
}
static ssize_t lirc_rx51_write(struct file *file, const char *buf,
lirc_rx51_on(lirc_rx51);
lirc_rx51->wbuf_index = 1;
- pulse_timer_set_timeout(lirc_rx51, lirc_rx51->wbuf[0]);
-
+ hrtimer_start(&lirc_rx51->timer,
+ ns_to_ktime(1000 * lirc_rx51->wbuf[0]),
+ HRTIMER_MODE_REL);
/*
* Don't return back to the userspace until the transfer has
* finished
if (test_and_set_bit(1, &lirc_rx51->device_is_open))
return -EBUSY;
- return lirc_rx51_init_port(lirc_rx51);
+ lirc_rx51->pwm = pwm_get(lirc_rx51->dev, NULL);
+ if (IS_ERR(lirc_rx51->pwm)) {
+ int res = PTR_ERR(lirc_rx51->pwm);
+
+ dev_err(lirc_rx51->dev, "pwm_get failed: %d\n", res);
+ return res;
+ }
+
+ return 0;
}
static int lirc_rx51_release(struct inode *inode, struct file *file)
{
struct lirc_rx51 *lirc_rx51 = file->private_data;
- lirc_rx51_free_port(lirc_rx51);
+ hrtimer_cancel(&lirc_rx51->timer);
+ lirc_rx51_off(lirc_rx51);
+ pwm_put(lirc_rx51->pwm);
clear_bit(1, &lirc_rx51->device_is_open);
}
static struct lirc_rx51 lirc_rx51 = {
- .freq = 38000,
.duty_cycle = 50,
.wbuf_index = -1,
};
static int lirc_rx51_probe(struct platform_device *dev)
{
+ struct pwm_device *pwm;
+
lirc_rx51_driver.features = LIRC_RX51_DRIVER_FEATURES;
lirc_rx51.pdata = dev->dev.platform_data;
- lirc_rx51.pwm_timer_num = lirc_rx51.pdata->pwm_timer;
+
+ if (!lirc_rx51.pdata) {
+ dev_err(&dev->dev, "Platform Data is missing\n");
+ return -ENXIO;
+ }
+
+ pwm = pwm_get(&dev->dev, NULL);
+ if (IS_ERR(pwm)) {
+ int err = PTR_ERR(pwm);
+
+ if (err != -EPROBE_DEFER)
+ dev_err(&dev->dev, "pwm_get failed: %d\n", err);
+ return err;
+ }
+
+ /* Use default, in case userspace does not set the carrier */
+ lirc_rx51.freq = DIV_ROUND_CLOSEST(pwm_get_period(pwm), NSEC_PER_SEC);
+ pwm_put(pwm);
+
+ hrtimer_init(&lirc_rx51.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ lirc_rx51.timer.function = lirc_rx51_timer_cb;
+
lirc_rx51.dev = &dev->dev;
lirc_rx51_driver.dev = &dev->dev;
lirc_rx51_driver.minor = lirc_register_driver(&lirc_rx51_driver);
lirc_rx51_driver.minor);
return lirc_rx51_driver.minor;
}
- dev_info(lirc_rx51.dev, "registration ok, minor: %d, pwm: %d\n",
- lirc_rx51_driver.minor, lirc_rx51.pwm_timer_num);
return 0;
}
return lirc_unregister_driver(lirc_rx51_driver.minor);
}
+static const struct of_device_id lirc_rx51_match[] = {
+ {
+ .compatible = "nokia,n900-ir",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, lirc_rx51_match);
+
struct platform_driver lirc_rx51_platform_driver = {
.probe = lirc_rx51_probe,
.remove = lirc_rx51_remove,
.resume = lirc_rx51_resume,
.driver = {
.name = DRIVER_NAME,
- .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lirc_rx51_match),
},
};
module_platform_driver(lirc_rx51_platform_driver);
}
EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx);
+/**
+ * vb2_dma_contig_set_max_seg_size() - configure DMA max segment size
+ * @dev: device for configuring DMA parameters
+ * @size: size of DMA max segment size to set
+ *
+ * To allow mapping the scatter-list into a single chunk in the DMA
+ * address space, the device is required to have the DMA max segment
+ * size parameter set to a value larger than the buffer size. Otherwise,
+ * the DMA-mapping subsystem will split the mapping into max segment
+ * size chunks. This function sets the DMA max segment size
+ * parameter to let DMA-mapping map a buffer as a single chunk in DMA
+ * address space.
+ * This code assumes that the DMA-mapping subsystem will merge all
+ * scatterlist segments if this is really possible (for example when
+ * an IOMMU is available and enabled).
+ * Ideally, this parameter should be set by the generic bus code, but it
+ * is left with the default 64KiB value due to historical litmiations in
+ * other subsystems (like limited USB host drivers) and there no good
+ * place to set it to the proper value.
+ * This function should be called from the drivers, which are known to
+ * operate on platforms with IOMMU and provide access to shared buffers
+ * (either USERPTR or DMABUF). This should be done before initializing
+ * videobuf2 queue.
+ */
+int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size)
+{
+ if (!dev->dma_parms) {
+ dev->dma_parms = kzalloc(sizeof(dev->dma_parms), GFP_KERNEL);
+ if (!dev->dma_parms)
+ return -ENOMEM;
+ }
+ if (dma_get_max_seg_size(dev) < size)
+ return dma_set_max_seg_size(dev, size);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_dma_contig_set_max_seg_size);
+
+/*
+ * vb2_dma_contig_clear_max_seg_size() - release resources for DMA parameters
+ * @dev: device for configuring DMA parameters
+ *
+ * This function releases resources allocated to configure DMA parameters
+ * (see vb2_dma_contig_set_max_seg_size() function). It should be called from
+ * device drivers on driver remove.
+ */
+void vb2_dma_contig_clear_max_seg_size(struct device *dev)
+{
+ kfree(dev->dma_parms);
+ dev->dma_parms = NULL;
+}
+EXPORT_SYMBOL_GPL(vb2_dma_contig_clear_max_seg_size);
+
MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2");
MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
MODULE_LICENSE("GPL");
Starting with the at91sam9g45, this controller supports SDR, DDR and
LP-DDR memories.
+config ATMEL_EBI
+ bool "Atmel EBI driver"
+ default y
+ depends on ARCH_AT91 && OF
+ select MFD_SYSCON
+ help
+ Driver for Atmel EBI controller.
+ Used to configure the EBI (external bus interface) when the device-
+ tree is used. This bus supports NANDs, external ethernet controller,
+ SRAMs, ATA devices, etc.
+
config TI_AEMIF
tristate "Texas Instruments AEMIF driver"
depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF
endif
obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o
obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o
+obj-$(CONFIG_ATMEL_EBI) += atmel-ebi.o
obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
obj-$(CONFIG_TI_EMIF) += emif.o
obj-$(CONFIG_OMAP_GPMC) += omap-gpmc.o
--- /dev/null
+/*
+ * EBI driver for Atmel chips
+ * inspired by the fsl weim bus driver
+ *
+ * Copyright (C) 2013 Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/atmel-matrix.h>
+#include <linux/mfd/syscon/atmel-smc.h>
+#include <linux/init.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+
+struct at91sam9_smc_timings {
+ u32 ncs_rd_setup_ns;
+ u32 nrd_setup_ns;
+ u32 ncs_wr_setup_ns;
+ u32 nwe_setup_ns;
+ u32 ncs_rd_pulse_ns;
+ u32 nrd_pulse_ns;
+ u32 ncs_wr_pulse_ns;
+ u32 nwe_pulse_ns;
+ u32 nrd_cycle_ns;
+ u32 nwe_cycle_ns;
+ u32 tdf_ns;
+};
+
+struct at91sam9_smc_generic_fields {
+ struct regmap_field *setup;
+ struct regmap_field *pulse;
+ struct regmap_field *cycle;
+ struct regmap_field *mode;
+};
+
+struct at91sam9_ebi_dev_config {
+ struct at91sam9_smc_timings timings;
+ u32 mode;
+};
+
+struct at91_ebi_dev_config {
+ int cs;
+ union {
+ struct at91sam9_ebi_dev_config sam9;
+ };
+};
+
+struct at91_ebi;
+
+struct at91_ebi_dev {
+ struct list_head node;
+ struct at91_ebi *ebi;
+ u32 mode;
+ int numcs;
+ struct at91_ebi_dev_config configs[];
+};
+
+struct at91_ebi_caps {
+ unsigned int available_cs;
+ const struct reg_field *ebi_csa;
+ void (*get_config)(struct at91_ebi_dev *ebid,
+ struct at91_ebi_dev_config *conf);
+ int (*xlate_config)(struct at91_ebi_dev *ebid,
+ struct device_node *configs_np,
+ struct at91_ebi_dev_config *conf);
+ int (*apply_config)(struct at91_ebi_dev *ebid,
+ struct at91_ebi_dev_config *conf);
+ int (*init)(struct at91_ebi *ebi);
+};
+
+struct at91_ebi {
+ struct clk *clk;
+ struct regmap *smc;
+ struct regmap *matrix;
+
+ struct regmap_field *ebi_csa;
+
+ struct device *dev;
+ const struct at91_ebi_caps *caps;
+ struct list_head devs;
+ union {
+ struct at91sam9_smc_generic_fields sam9;
+ };
+};
+
+static void at91sam9_ebi_get_config(struct at91_ebi_dev *ebid,
+ struct at91_ebi_dev_config *conf)
+{
+ struct at91sam9_smc_generic_fields *fields = &ebid->ebi->sam9;
+ unsigned int clk_rate = clk_get_rate(ebid->ebi->clk);
+ struct at91sam9_ebi_dev_config *config = &conf->sam9;
+ struct at91sam9_smc_timings *timings = &config->timings;
+ unsigned int val;
+
+ regmap_fields_read(fields->mode, conf->cs, &val);
+ config->mode = val & ~AT91_SMC_TDF;
+
+ val = (val & AT91_SMC_TDF) >> 16;
+ timings->tdf_ns = clk_rate * val;
+
+ regmap_fields_read(fields->setup, conf->cs, &val);
+ timings->ncs_rd_setup_ns = (val >> 24) & 0x1f;
+ timings->ncs_rd_setup_ns += ((val >> 29) & 0x1) * 128;
+ timings->ncs_rd_setup_ns *= clk_rate;
+ timings->nrd_setup_ns = (val >> 16) & 0x1f;
+ timings->nrd_setup_ns += ((val >> 21) & 0x1) * 128;
+ timings->nrd_setup_ns *= clk_rate;
+ timings->ncs_wr_setup_ns = (val >> 8) & 0x1f;
+ timings->ncs_wr_setup_ns += ((val >> 13) & 0x1) * 128;
+ timings->ncs_wr_setup_ns *= clk_rate;
+ timings->nwe_setup_ns = val & 0x1f;
+ timings->nwe_setup_ns += ((val >> 5) & 0x1) * 128;
+ timings->nwe_setup_ns *= clk_rate;
+
+ regmap_fields_read(fields->pulse, conf->cs, &val);
+ timings->ncs_rd_pulse_ns = (val >> 24) & 0x3f;
+ timings->ncs_rd_pulse_ns += ((val >> 30) & 0x1) * 256;
+ timings->ncs_rd_pulse_ns *= clk_rate;
+ timings->nrd_pulse_ns = (val >> 16) & 0x3f;
+ timings->nrd_pulse_ns += ((val >> 22) & 0x1) * 256;
+ timings->nrd_pulse_ns *= clk_rate;
+ timings->ncs_wr_pulse_ns = (val >> 8) & 0x3f;
+ timings->ncs_wr_pulse_ns += ((val >> 14) & 0x1) * 256;
+ timings->ncs_wr_pulse_ns *= clk_rate;
+ timings->nwe_pulse_ns = val & 0x3f;
+ timings->nwe_pulse_ns += ((val >> 6) & 0x1) * 256;
+ timings->nwe_pulse_ns *= clk_rate;
+
+ regmap_fields_read(fields->cycle, conf->cs, &val);
+ timings->nrd_cycle_ns = (val >> 16) & 0x7f;
+ timings->nrd_cycle_ns += ((val >> 23) & 0x3) * 256;
+ timings->nrd_cycle_ns *= clk_rate;
+ timings->nwe_cycle_ns = val & 0x7f;
+ timings->nwe_cycle_ns += ((val >> 7) & 0x3) * 256;
+ timings->nwe_cycle_ns *= clk_rate;
+}
+
+static int at91_xlate_timing(struct device_node *np, const char *prop,
+ u32 *val, bool *required)
+{
+ if (!of_property_read_u32(np, prop, val)) {
+ *required = true;
+ return 0;
+ }
+
+ if (*required)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int at91sam9_smc_xslate_timings(struct at91_ebi_dev *ebid,
+ struct device_node *np,
+ struct at91sam9_smc_timings *timings,
+ bool *required)
+{
+ int ret;
+
+ ret = at91_xlate_timing(np, "atmel,smc-ncs-rd-setup-ns",
+ &timings->ncs_rd_setup_ns, required);
+ if (ret)
+ goto out;
+
+ ret = at91_xlate_timing(np, "atmel,smc-nrd-setup-ns",
+ &timings->nrd_setup_ns, required);
+ if (ret)
+ goto out;
+
+ ret = at91_xlate_timing(np, "atmel,smc-ncs-wr-setup-ns",
+ &timings->ncs_wr_setup_ns, required);
+ if (ret)
+ goto out;
+
+ ret = at91_xlate_timing(np, "atmel,smc-nwe-setup-ns",
+ &timings->nwe_setup_ns, required);
+ if (ret)
+ goto out;
+
+ ret = at91_xlate_timing(np, "atmel,smc-ncs-rd-pulse-ns",
+ &timings->ncs_rd_pulse_ns, required);
+ if (ret)
+ goto out;
+
+ ret = at91_xlate_timing(np, "atmel,smc-nrd-pulse-ns",
+ &timings->nrd_pulse_ns, required);
+ if (ret)
+ goto out;
+
+ ret = at91_xlate_timing(np, "atmel,smc-ncs-wr-pulse-ns",
+ &timings->ncs_wr_pulse_ns, required);
+ if (ret)
+ goto out;
+
+ ret = at91_xlate_timing(np, "atmel,smc-nwe-pulse-ns",
+ &timings->nwe_pulse_ns, required);
+ if (ret)
+ goto out;
+
+ ret = at91_xlate_timing(np, "atmel,smc-nwe-cycle-ns",
+ &timings->nwe_cycle_ns, required);
+ if (ret)
+ goto out;
+
+ ret = at91_xlate_timing(np, "atmel,smc-nrd-cycle-ns",
+ &timings->nrd_cycle_ns, required);
+ if (ret)
+ goto out;
+
+ ret = at91_xlate_timing(np, "atmel,smc-tdf-ns",
+ &timings->tdf_ns, required);
+
+out:
+ if (ret)
+ dev_err(ebid->ebi->dev,
+ "missing or invalid timings definition in %s",
+ np->full_name);
+
+ return ret;
+}
+
+static int at91sam9_ebi_xslate_config(struct at91_ebi_dev *ebid,
+ struct device_node *np,
+ struct at91_ebi_dev_config *conf)
+{
+ struct at91sam9_ebi_dev_config *config = &conf->sam9;
+ bool required = false;
+ const char *tmp_str;
+ u32 tmp;
+ int ret;
+
+ ret = of_property_read_u32(np, "atmel,smc-bus-width", &tmp);
+ if (!ret) {
+ switch (tmp) {
+ case 8:
+ config->mode |= AT91_SMC_DBW_8;
+ break;
+
+ case 16:
+ config->mode |= AT91_SMC_DBW_16;
+ break;
+
+ case 32:
+ config->mode |= AT91_SMC_DBW_32;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ required = true;
+ }
+
+ if (of_property_read_bool(np, "atmel,smc-tdf-optimized")) {
+ config->mode |= AT91_SMC_TDFMODE_OPTIMIZED;
+ required = true;
+ }
+
+ tmp_str = NULL;
+ of_property_read_string(np, "atmel,smc-byte-access-type", &tmp_str);
+ if (tmp_str && !strcmp(tmp_str, "write")) {
+ config->mode |= AT91_SMC_BAT_WRITE;
+ required = true;
+ }
+
+ tmp_str = NULL;
+ of_property_read_string(np, "atmel,smc-read-mode", &tmp_str);
+ if (tmp_str && !strcmp(tmp_str, "nrd")) {
+ config->mode |= AT91_SMC_READMODE_NRD;
+ required = true;
+ }
+
+ tmp_str = NULL;
+ of_property_read_string(np, "atmel,smc-write-mode", &tmp_str);
+ if (tmp_str && !strcmp(tmp_str, "nwe")) {
+ config->mode |= AT91_SMC_WRITEMODE_NWE;
+ required = true;
+ }
+
+ tmp_str = NULL;
+ of_property_read_string(np, "atmel,smc-exnw-mode", &tmp_str);
+ if (tmp_str) {
+ if (!strcmp(tmp_str, "frozen"))
+ config->mode |= AT91_SMC_EXNWMODE_FROZEN;
+ else if (!strcmp(tmp_str, "ready"))
+ config->mode |= AT91_SMC_EXNWMODE_READY;
+ else if (strcmp(tmp_str, "disabled"))
+ return -EINVAL;
+
+ required = true;
+ }
+
+ ret = of_property_read_u32(np, "atmel,smc-page-mode", &tmp);
+ if (!ret) {
+ switch (tmp) {
+ case 4:
+ config->mode |= AT91_SMC_PS_4;
+ break;
+
+ case 8:
+ config->mode |= AT91_SMC_PS_8;
+ break;
+
+ case 16:
+ config->mode |= AT91_SMC_PS_16;
+ break;
+
+ case 32:
+ config->mode |= AT91_SMC_PS_32;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ config->mode |= AT91_SMC_PMEN;
+ required = true;
+ }
+
+ ret = at91sam9_smc_xslate_timings(ebid, np, &config->timings,
+ &required);
+ if (ret)
+ return ret;
+
+ return required;
+}
+
+static int at91sam9_ebi_apply_config(struct at91_ebi_dev *ebid,
+ struct at91_ebi_dev_config *conf)
+{
+ unsigned int clk_rate = clk_get_rate(ebid->ebi->clk);
+ struct at91sam9_ebi_dev_config *config = &conf->sam9;
+ struct at91sam9_smc_timings *timings = &config->timings;
+ struct at91sam9_smc_generic_fields *fields = &ebid->ebi->sam9;
+ u32 coded_val;
+ u32 val;
+
+ coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
+ timings->ncs_rd_setup_ns);
+ val = AT91SAM9_SMC_NCS_NRDSETUP(coded_val);
+ coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
+ timings->nrd_setup_ns);
+ val |= AT91SAM9_SMC_NRDSETUP(coded_val);
+ coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
+ timings->ncs_wr_setup_ns);
+ val |= AT91SAM9_SMC_NCS_WRSETUP(coded_val);
+ coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
+ timings->nwe_setup_ns);
+ val |= AT91SAM9_SMC_NWESETUP(coded_val);
+ regmap_fields_write(fields->setup, conf->cs, val);
+
+ coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
+ timings->ncs_rd_pulse_ns);
+ val = AT91SAM9_SMC_NCS_NRDPULSE(coded_val);
+ coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
+ timings->nrd_pulse_ns);
+ val |= AT91SAM9_SMC_NRDPULSE(coded_val);
+ coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
+ timings->ncs_wr_pulse_ns);
+ val |= AT91SAM9_SMC_NCS_WRPULSE(coded_val);
+ coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
+ timings->nwe_pulse_ns);
+ val |= AT91SAM9_SMC_NWEPULSE(coded_val);
+ regmap_fields_write(fields->pulse, conf->cs, val);
+
+ coded_val = at91sam9_smc_cycle_ns_to_cycles(clk_rate,
+ timings->nrd_cycle_ns);
+ val = AT91SAM9_SMC_NRDCYCLE(coded_val);
+ coded_val = at91sam9_smc_cycle_ns_to_cycles(clk_rate,
+ timings->nwe_cycle_ns);
+ val |= AT91SAM9_SMC_NWECYCLE(coded_val);
+ regmap_fields_write(fields->cycle, conf->cs, val);
+
+ val = DIV_ROUND_UP(timings->tdf_ns, clk_rate);
+ if (val > AT91_SMC_TDF_MAX)
+ val = AT91_SMC_TDF_MAX;
+ regmap_fields_write(fields->mode, conf->cs,
+ config->mode | AT91_SMC_TDF_(val));
+
+ return 0;
+}
+
+static int at91sam9_ebi_init(struct at91_ebi *ebi)
+{
+ struct at91sam9_smc_generic_fields *fields = &ebi->sam9;
+ struct reg_field field = REG_FIELD(0, 0, 31);
+
+ field.id_size = fls(ebi->caps->available_cs);
+ field.id_offset = AT91SAM9_SMC_GENERIC_BLK_SZ;
+
+ field.reg = AT91SAM9_SMC_SETUP(AT91SAM9_SMC_GENERIC);
+ fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
+ if (IS_ERR(fields->setup))
+ return PTR_ERR(fields->setup);
+
+ field.reg = AT91SAM9_SMC_PULSE(AT91SAM9_SMC_GENERIC);
+ fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
+ if (IS_ERR(fields->pulse))
+ return PTR_ERR(fields->pulse);
+
+ field.reg = AT91SAM9_SMC_CYCLE(AT91SAM9_SMC_GENERIC);
+ fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
+ if (IS_ERR(fields->cycle))
+ return PTR_ERR(fields->cycle);
+
+ 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;
+}
+
+static int sama5d3_ebi_init(struct at91_ebi *ebi)
+{
+ struct at91sam9_smc_generic_fields *fields = &ebi->sam9;
+ struct reg_field field = REG_FIELD(0, 0, 31);
+
+ field.id_size = fls(ebi->caps->available_cs);
+ field.id_offset = SAMA5_SMC_GENERIC_BLK_SZ;
+
+ field.reg = AT91SAM9_SMC_SETUP(SAMA5_SMC_GENERIC);
+ fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
+ if (IS_ERR(fields->setup))
+ return PTR_ERR(fields->setup);
+
+ field.reg = AT91SAM9_SMC_PULSE(SAMA5_SMC_GENERIC);
+ fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
+ if (IS_ERR(fields->pulse))
+ return PTR_ERR(fields->pulse);
+
+ field.reg = AT91SAM9_SMC_CYCLE(SAMA5_SMC_GENERIC);
+ fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
+ if (IS_ERR(fields->cycle))
+ return PTR_ERR(fields->cycle);
+
+ 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;
+}
+
+static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np,
+ int reg_cells)
+{
+ const struct at91_ebi_caps *caps = ebi->caps;
+ struct at91_ebi_dev_config conf = { };
+ struct device *dev = ebi->dev;
+ struct at91_ebi_dev *ebid;
+ int ret, numcs = 0, i;
+ bool apply = false;
+
+ numcs = of_property_count_elems_of_size(np, "reg",
+ reg_cells * sizeof(u32));
+ if (numcs <= 0) {
+ dev_err(dev, "invalid reg property in %s\n", np->full_name);
+ return -EINVAL;
+ }
+
+ ebid = devm_kzalloc(ebi->dev,
+ sizeof(*ebid) + (numcs * sizeof(*ebid->configs)),
+ GFP_KERNEL);
+ if (!ebid)
+ return -ENOMEM;
+
+ ebid->ebi = ebi;
+
+ ret = caps->xlate_config(ebid, np, &conf);
+ if (ret < 0)
+ return ret;
+ else if (ret)
+ apply = true;
+
+ for (i = 0; i < numcs; i++) {
+ u32 cs;
+
+ ret = of_property_read_u32_index(np, "reg", i * reg_cells,
+ &cs);
+ if (ret)
+ return ret;
+
+ if (cs > AT91_MATRIX_EBI_NUM_CS ||
+ !(ebi->caps->available_cs & BIT(cs))) {
+ dev_err(dev, "invalid reg property in %s\n",
+ np->full_name);
+ return -EINVAL;
+ }
+
+ ebid->configs[i].cs = cs;
+
+ if (apply) {
+ conf.cs = cs;
+ ret = caps->apply_config(ebid, &conf);
+ if (ret)
+ return ret;
+ }
+
+ caps->get_config(ebid, &ebid->configs[i]);
+
+ /*
+ * Attach the EBI device to the generic SMC logic if at least
+ * one "atmel,smc-" property is present.
+ */
+ if (ebi->ebi_csa && ret)
+ regmap_field_update_bits(ebi->ebi_csa,
+ BIT(cs), 0);
+ }
+
+ list_add_tail(&ebid->node, &ebi->devs);
+
+ return 0;
+}
+
+static const struct reg_field at91sam9260_ebi_csa =
+ REG_FIELD(AT91SAM9260_MATRIX_EBICSA, 0,
+ AT91_MATRIX_EBI_NUM_CS - 1);
+
+static const struct at91_ebi_caps at91sam9260_ebi_caps = {
+ .available_cs = 0xff,
+ .ebi_csa = &at91sam9260_ebi_csa,
+ .get_config = at91sam9_ebi_get_config,
+ .xlate_config = at91sam9_ebi_xslate_config,
+ .apply_config = at91sam9_ebi_apply_config,
+ .init = at91sam9_ebi_init,
+};
+
+static const struct reg_field at91sam9261_ebi_csa =
+ REG_FIELD(AT91SAM9261_MATRIX_EBICSA, 0,
+ AT91_MATRIX_EBI_NUM_CS - 1);
+
+static const struct at91_ebi_caps at91sam9261_ebi_caps = {
+ .available_cs = 0xff,
+ .ebi_csa = &at91sam9261_ebi_csa,
+ .get_config = at91sam9_ebi_get_config,
+ .xlate_config = at91sam9_ebi_xslate_config,
+ .apply_config = at91sam9_ebi_apply_config,
+ .init = at91sam9_ebi_init,
+};
+
+static const struct reg_field at91sam9263_ebi0_csa =
+ REG_FIELD(AT91SAM9263_MATRIX_EBI0CSA, 0,
+ AT91_MATRIX_EBI_NUM_CS - 1);
+
+static const struct at91_ebi_caps at91sam9263_ebi0_caps = {
+ .available_cs = 0x3f,
+ .ebi_csa = &at91sam9263_ebi0_csa,
+ .get_config = at91sam9_ebi_get_config,
+ .xlate_config = at91sam9_ebi_xslate_config,
+ .apply_config = at91sam9_ebi_apply_config,
+ .init = at91sam9_ebi_init,
+};
+
+static const struct reg_field at91sam9263_ebi1_csa =
+ REG_FIELD(AT91SAM9263_MATRIX_EBI1CSA, 0,
+ AT91_MATRIX_EBI_NUM_CS - 1);
+
+static const struct at91_ebi_caps at91sam9263_ebi1_caps = {
+ .available_cs = 0x7,
+ .ebi_csa = &at91sam9263_ebi1_csa,
+ .get_config = at91sam9_ebi_get_config,
+ .xlate_config = at91sam9_ebi_xslate_config,
+ .apply_config = at91sam9_ebi_apply_config,
+ .init = at91sam9_ebi_init,
+};
+
+static const struct reg_field at91sam9rl_ebi_csa =
+ REG_FIELD(AT91SAM9RL_MATRIX_EBICSA, 0,
+ AT91_MATRIX_EBI_NUM_CS - 1);
+
+static const struct at91_ebi_caps at91sam9rl_ebi_caps = {
+ .available_cs = 0x3f,
+ .ebi_csa = &at91sam9rl_ebi_csa,
+ .get_config = at91sam9_ebi_get_config,
+ .xlate_config = at91sam9_ebi_xslate_config,
+ .apply_config = at91sam9_ebi_apply_config,
+ .init = at91sam9_ebi_init,
+};
+
+static const struct reg_field at91sam9g45_ebi_csa =
+ REG_FIELD(AT91SAM9G45_MATRIX_EBICSA, 0,
+ AT91_MATRIX_EBI_NUM_CS - 1);
+
+static const struct at91_ebi_caps at91sam9g45_ebi_caps = {
+ .available_cs = 0x3f,
+ .ebi_csa = &at91sam9g45_ebi_csa,
+ .get_config = at91sam9_ebi_get_config,
+ .xlate_config = at91sam9_ebi_xslate_config,
+ .apply_config = at91sam9_ebi_apply_config,
+ .init = at91sam9_ebi_init,
+};
+
+static const struct at91_ebi_caps at91sam9x5_ebi_caps = {
+ .available_cs = 0x3f,
+ .ebi_csa = &at91sam9263_ebi0_csa,
+ .get_config = at91sam9_ebi_get_config,
+ .xlate_config = at91sam9_ebi_xslate_config,
+ .apply_config = at91sam9_ebi_apply_config,
+ .init = at91sam9_ebi_init,
+};
+
+static const struct at91_ebi_caps sama5d3_ebi_caps = {
+ .available_cs = 0xf,
+ .get_config = at91sam9_ebi_get_config,
+ .xlate_config = at91sam9_ebi_xslate_config,
+ .apply_config = at91sam9_ebi_apply_config,
+ .init = sama5d3_ebi_init,
+};
+
+static const struct of_device_id at91_ebi_id_table[] = {
+ {
+ .compatible = "atmel,at91sam9260-ebi",
+ .data = &at91sam9260_ebi_caps,
+ },
+ {
+ .compatible = "atmel,at91sam9261-ebi",
+ .data = &at91sam9261_ebi_caps,
+ },
+ {
+ .compatible = "atmel,at91sam9263-ebi0",
+ .data = &at91sam9263_ebi0_caps,
+ },
+ {
+ .compatible = "atmel,at91sam9263-ebi1",
+ .data = &at91sam9263_ebi1_caps,
+ },
+ {
+ .compatible = "atmel,at91sam9rl-ebi",
+ .data = &at91sam9rl_ebi_caps,
+ },
+ {
+ .compatible = "atmel,at91sam9g45-ebi",
+ .data = &at91sam9g45_ebi_caps,
+ },
+ {
+ .compatible = "atmel,at91sam9x5-ebi",
+ .data = &at91sam9x5_ebi_caps,
+ },
+ {
+ .compatible = "atmel,sama5d3-ebi",
+ .data = &sama5d3_ebi_caps,
+ },
+ { /* sentinel */ }
+};
+
+static int at91_ebi_dev_disable(struct at91_ebi *ebi, struct device_node *np)
+{
+ struct device *dev = ebi->dev;
+ struct property *newprop;
+
+ newprop = devm_kzalloc(dev, sizeof(*newprop), GFP_KERNEL);
+ if (!newprop)
+ return -ENOMEM;
+
+ newprop->name = devm_kstrdup(dev, "status", GFP_KERNEL);
+ if (!newprop->name)
+ return -ENOMEM;
+
+ newprop->value = devm_kstrdup(dev, "disabled", GFP_KERNEL);
+ if (!newprop->name)
+ return -ENOMEM;
+
+ newprop->length = sizeof("disabled");
+
+ return of_update_property(np, newprop);
+}
+
+static int at91_ebi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *child, *np = dev->of_node;
+ const struct of_device_id *match;
+ struct at91_ebi *ebi;
+ int ret, reg_cells;
+ struct clk *clk;
+ u32 val;
+
+ match = of_match_device(at91_ebi_id_table, dev);
+ if (!match || !match->data)
+ return -EINVAL;
+
+ ebi = devm_kzalloc(dev, sizeof(*ebi), GFP_KERNEL);
+ if (!ebi)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&ebi->devs);
+ ebi->caps = match->data;
+ ebi->dev = dev;
+
+ clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ ebi->clk = clk;
+
+ ebi->smc = syscon_regmap_lookup_by_phandle(np, "atmel,smc");
+ if (IS_ERR(ebi->smc))
+ return PTR_ERR(ebi->smc);
+
+ /*
+ * The sama5d3 does not provide an EBICSA register and thus does need
+ * to access the matrix registers.
+ */
+ if (ebi->caps->ebi_csa) {
+ ebi->matrix =
+ syscon_regmap_lookup_by_phandle(np, "atmel,matrix");
+ if (IS_ERR(ebi->matrix))
+ return PTR_ERR(ebi->matrix);
+
+ ebi->ebi_csa = regmap_field_alloc(ebi->matrix,
+ *ebi->caps->ebi_csa);
+ if (IS_ERR(ebi->ebi_csa))
+ return PTR_ERR(ebi->ebi_csa);
+ }
+
+ ret = ebi->caps->init(ebi);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(np, "#address-cells", &val);
+ if (ret) {
+ dev_err(dev, "missing #address-cells property\n");
+ return ret;
+ }
+
+ reg_cells = val;
+
+ ret = of_property_read_u32(np, "#size-cells", &val);
+ if (ret) {
+ dev_err(dev, "missing #address-cells property\n");
+ return ret;
+ }
+
+ reg_cells += val;
+
+ for_each_available_child_of_node(np, child) {
+ if (!of_find_property(child, "reg", NULL))
+ continue;
+
+ ret = at91_ebi_dev_setup(ebi, child, reg_cells);
+ if (ret) {
+ dev_err(dev, "failed to configure EBI bus for %s, disabling the device",
+ child->full_name);
+
+ ret = at91_ebi_dev_disable(ebi, child);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return of_platform_populate(np, NULL, NULL, dev);
+}
+
+static struct platform_driver at91_ebi_driver = {
+ .driver = {
+ .name = "atmel-ebi",
+ .of_match_table = at91_ebi_id_table,
+ },
+};
+builtin_platform_driver_probe(at91_ebi_driver, at91_ebi_probe);
/*
* Atmel (Multi-port DDR-)SDRAM Controller driver
*
+ * Author: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ *
* Copyright (C) 2014 Atmel
*
* This program is free software: you can redistribute it and/or modify
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
{ .compatible = "atmel,sama5d3-ddramc", .data = &sama5d3_caps, },
{},
};
-MODULE_DEVICE_TABLE(of, atmel_ramc_of_match);
static int atmel_ramc_probe(struct platform_device *pdev)
{
{
return platform_driver_register(&atmel_ramc_driver);
}
-module_init(atmel_ramc_init);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
-MODULE_DESCRIPTION("Atmel (Multi-port DDR-)SDRAM Controller");
+device_initcall(atmel_ramc_init);
#include <linux/ioport.h>
#include <linux/spinlock.h>
#include <linux/io.h>
-#include <linux/module.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
{ .compatible = "ti,am3352-gpmc" }, /* am335x devices */
{ }
};
-MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
/**
* gpmc_read_settings_dt - read gpmc settings from device-tree
return ret;
}
-static int gpmc_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
-{
- return 1; /* we're input only */
-}
-
-static int gpmc_gpio_direction_input(struct gpio_chip *chip,
- unsigned int offset)
-{
- return 0; /* we're input only */
-}
-
-static int gpmc_gpio_direction_output(struct gpio_chip *chip,
- unsigned int offset, int value)
-{
- return -EINVAL; /* we're input only */
-}
-
-static void gpmc_gpio_set(struct gpio_chip *chip, unsigned int offset,
- int value)
-{
-}
-
-static int gpmc_gpio_get(struct gpio_chip *chip, unsigned int offset)
-{
- u32 reg;
-
- offset += 8;
-
- reg = gpmc_read_reg(GPMC_STATUS) & BIT(offset);
-
- return !!reg;
-}
-
-static int gpmc_gpio_init(struct gpmc_device *gpmc)
-{
- int ret;
-
- gpmc->gpio_chip.parent = gpmc->dev;
- gpmc->gpio_chip.owner = THIS_MODULE;
- gpmc->gpio_chip.label = DEVICE_NAME;
- gpmc->gpio_chip.ngpio = gpmc_nr_waitpins;
- gpmc->gpio_chip.get_direction = gpmc_gpio_get_direction;
- gpmc->gpio_chip.direction_input = gpmc_gpio_direction_input;
- gpmc->gpio_chip.direction_output = gpmc_gpio_direction_output;
- gpmc->gpio_chip.set = gpmc_gpio_set;
- gpmc->gpio_chip.get = gpmc_gpio_get;
- gpmc->gpio_chip.base = -1;
-
- ret = gpiochip_add(&gpmc->gpio_chip);
- if (ret < 0) {
- dev_err(gpmc->dev, "could not register gpio chip: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-static void gpmc_gpio_exit(struct gpmc_device *gpmc)
-{
- gpiochip_remove(&gpmc->gpio_chip);
-}
-
static int gpmc_probe_dt(struct platform_device *pdev)
{
int ret;
{
return 0;
}
-#endif
+#endif /* CONFIG_OF */
+
+static int gpmc_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+ return 1; /* we're input only */
+}
+
+static int gpmc_gpio_direction_input(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ return 0; /* we're input only */
+}
+
+static int gpmc_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ return -EINVAL; /* we're input only */
+}
+
+static void gpmc_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+}
+
+static int gpmc_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ u32 reg;
+
+ offset += 8;
+
+ reg = gpmc_read_reg(GPMC_STATUS) & BIT(offset);
+
+ return !!reg;
+}
+
+static int gpmc_gpio_init(struct gpmc_device *gpmc)
+{
+ int ret;
+
+ gpmc->gpio_chip.parent = gpmc->dev;
+ gpmc->gpio_chip.owner = THIS_MODULE;
+ gpmc->gpio_chip.label = DEVICE_NAME;
+ gpmc->gpio_chip.ngpio = gpmc_nr_waitpins;
+ gpmc->gpio_chip.get_direction = gpmc_gpio_get_direction;
+ gpmc->gpio_chip.direction_input = gpmc_gpio_direction_input;
+ gpmc->gpio_chip.direction_output = gpmc_gpio_direction_output;
+ gpmc->gpio_chip.set = gpmc_gpio_set;
+ gpmc->gpio_chip.get = gpmc_gpio_get;
+ gpmc->gpio_chip.base = -1;
+
+ ret = gpiochip_add(&gpmc->gpio_chip);
+ if (ret < 0) {
+ dev_err(gpmc->dev, "could not register gpio chip: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void gpmc_gpio_exit(struct gpmc_device *gpmc)
+{
+ gpiochip_remove(&gpmc->gpio_chip);
+}
static int gpmc_probe(struct platform_device *pdev)
{
{
return platform_driver_register(&gpmc_driver);
}
-
-static __exit void gpmc_exit(void)
-{
- platform_driver_unregister(&gpmc_driver);
-
-}
-
postcore_initcall(gpmc_init);
-module_exit(gpmc_exit);
static struct omap3_gpmc_regs gpmc_context;
timing = &mc->timings[i++];
err = load_one_timing(mc, timing, child);
- if (err)
+ if (err) {
+ of_node_put(child);
return err;
+ }
}
return 0;
for_each_child_of_node(mc->dev->of_node, node) {
err = of_property_read_u32(node, "nvidia,ram-code",
&node_ram_code);
- if (err || (node_ram_code != ram_code)) {
- of_node_put(node);
+ if (err || (node_ram_code != ram_code))
continue;
- }
err = load_timings(mc, node);
+ of_node_put(node);
if (err)
return err;
- of_node_put(node);
break;
}
timing = &emc->timings[i++];
err = load_one_timing_from_dt(emc, timing, child);
- if (err)
+ if (err) {
+ of_node_put(child);
return err;
+ }
}
sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings,
u32 value;
err = of_property_read_u32(np, "nvidia,ram-code", &value);
- if (err || (value != ram_code)) {
- of_node_put(np);
+ if (err || (value != ram_code))
continue;
- }
return np;
}
"Vbus Detect (USB)",
"USB ID Detect",
"UART Factory Mode Detect"};
- struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev);
const struct platform_device_id *platid = platform_get_device_id(pdev);
enum ab8500_version version = AB8500_VERSION_UNDEFINED;
struct device_node *np = pdev->dev.of_node;
pr_cont("None\n");
}
- if (plat && plat->init)
- plat->init(ab8500);
-
if (is_ab9540(ab8500)) {
ret = get_register_interruptible(ab8500, AB8500_CHARGER,
AB8500_CH_USBCH_STAT1_REG, &value);
static int ab8500_sysctrl_probe(struct platform_device *pdev)
{
- struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
- struct ab8500_platform_data *plat;
- struct ab8500_sysctrl_platform_data *pdata;
-
- plat = dev_get_platdata(pdev->dev.parent);
-
- if (!plat)
- return -EINVAL;
-
sysctrl_dev = &pdev->dev;
if (!pm_power_off)
pm_power_off = ab8500_power_off;
- pdata = plat->sysctrl;
- if (pdata) {
- int last, ret, i, j;
-
- if (is_ab8505(ab8500))
- last = AB8500_SYSCLKREQ4RFCLKBUF;
- else
- last = AB8500_SYSCLKREQ8RFCLKBUF;
-
- for (i = AB8500_SYSCLKREQ1RFCLKBUF; i <= last; i++) {
- j = i - AB8500_SYSCLKREQ1RFCLKBUF;
- ret = ab8500_sysctrl_write(i, 0xff,
- pdata->initial_req_buf_config[j]);
- dev_dbg(&pdev->dev,
- "Setting SysClkReq%dRfClkBuf 0x%X\n",
- j + 1,
- pdata->initial_req_buf_config[j]);
- if (ret < 0) {
- dev_err(&pdev->dev,
- "Can't set sysClkReq%dRfClkBuf: %d\n",
- j + 1, ret);
- }
- }
- }
-
return 0;
}
}
}
-static int db8500_prcmu_register_ab8500(struct device *parent,
- struct ab8500_platform_data *pdata)
+static int db8500_prcmu_register_ab8500(struct device *parent)
{
struct device_node *np;
struct resource ab8500_resource;
.name = "ab8500-core",
.of_compatible = "stericsson,ab8500",
.id = AB8500_VERSION_AB8500,
- .platform_data = pdata,
- .pdata_size = sizeof(struct ab8500_platform_data),
.resources = &ab8500_resource,
.num_resources = 1,
};
static int db8500_prcmu_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- struct prcmu_pdata *pdata = dev_get_platdata(&pdev->dev);
int irq = 0, err = 0;
struct resource *res;
return -ENOMEM;
}
init_prcm_registers();
- dbx500_fw_version_init(pdev, pdata->version_offset);
+ dbx500_fw_version_init(pdev, DB8500_PRCMU_FW_VERSION_OFFSET);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcdm");
if (!res) {
dev_err(&pdev->dev, "no prcmu tcdm region provided\n");
}
}
- err = db8500_prcmu_register_ab8500(&pdev->dev, pdata->ab_platdata);
+ err = db8500_prcmu_register_ab8500(&pdev->dev);
if (err) {
mfd_remove_devices(&pdev->dev);
pr_err("prcmu: Failed to add ab8500 subdevice\n");
#include <linux/sizes.h>
#include <linux/of_reserved_mem.h>
#include <linux/sort.h>
+#include <linux/slab.h>
#define MAX_RESERVED_REGIONS 16
static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
return NULL;
}
+struct rmem_assigned_device {
+ struct device *dev;
+ struct reserved_mem *rmem;
+ struct list_head list;
+};
+
+static LIST_HEAD(of_rmem_assigned_device_list);
+static DEFINE_MUTEX(of_rmem_assigned_device_mutex);
+
/**
- * of_reserved_mem_device_init() - assign reserved memory region to given device
+ * of_reserved_mem_device_init_by_idx() - assign reserved memory region to
+ * given device
+ * @dev: Pointer to the device to configure
+ * @np: Pointer to the device_node with 'reserved-memory' property
+ * @idx: Index of selected region
*
- * This function assign memory region pointed by "memory-region" device tree
- * property to the given device.
+ * This function assigns respective DMA-mapping operations based on reserved
+ * memory region specified by 'memory-region' property in @np node to the @dev
+ * device. When driver needs to use more than one reserved memory region, it
+ * should allocate child devices and initialize regions by name for each of
+ * child device.
+ *
+ * Returns error code or zero on success.
*/
-int of_reserved_mem_device_init(struct device *dev)
+int of_reserved_mem_device_init_by_idx(struct device *dev,
+ struct device_node *np, int idx)
{
+ struct rmem_assigned_device *rd;
+ struct device_node *target;
struct reserved_mem *rmem;
- struct device_node *np;
int ret;
- np = of_parse_phandle(dev->of_node, "memory-region", 0);
- if (!np)
- return -ENODEV;
+ if (!np || !dev)
+ return -EINVAL;
+
+ target = of_parse_phandle(np, "memory-region", idx);
+ if (!target)
+ return -EINVAL;
- rmem = __find_rmem(np);
- of_node_put(np);
+ rmem = __find_rmem(target);
+ of_node_put(target);
if (!rmem || !rmem->ops || !rmem->ops->device_init)
return -EINVAL;
+ rd = kmalloc(sizeof(struct rmem_assigned_device), GFP_KERNEL);
+ if (!rd)
+ return -ENOMEM;
+
ret = rmem->ops->device_init(rmem, dev);
- if (ret == 0)
+ if (ret == 0) {
+ rd->dev = dev;
+ rd->rmem = rmem;
+
+ mutex_lock(&of_rmem_assigned_device_mutex);
+ list_add(&rd->list, &of_rmem_assigned_device_list);
+ mutex_unlock(&of_rmem_assigned_device_mutex);
+
dev_info(dev, "assigned reserved memory node %s\n", rmem->name);
+ } else {
+ kfree(rd);
+ }
return ret;
}
-EXPORT_SYMBOL_GPL(of_reserved_mem_device_init);
+EXPORT_SYMBOL_GPL(of_reserved_mem_device_init_by_idx);
/**
* of_reserved_mem_device_release() - release reserved memory device structures
+ * @dev: Pointer to the device to deconfigure
*
* This function releases structures allocated for memory region handling for
* the given device.
*/
void of_reserved_mem_device_release(struct device *dev)
{
- struct reserved_mem *rmem;
- struct device_node *np;
-
- np = of_parse_phandle(dev->of_node, "memory-region", 0);
- if (!np)
- return;
-
- rmem = __find_rmem(np);
- of_node_put(np);
+ struct rmem_assigned_device *rd;
+ struct reserved_mem *rmem = NULL;
+
+ mutex_lock(&of_rmem_assigned_device_mutex);
+ list_for_each_entry(rd, &of_rmem_assigned_device_list, list) {
+ if (rd->dev == dev) {
+ rmem = rd->rmem;
+ list_del(&rd->list);
+ kfree(rd);
+ break;
+ }
+ }
+ mutex_unlock(&of_rmem_assigned_device_mutex);
if (!rmem || !rmem->ops || !rmem->ops->device_release)
return;
Say Y if you have an Axxia family SoC.
+config POWER_RESET_BRCMKONA
+ bool "Broadcom Kona reset driver"
+ depends on ARM || COMPILE_TEST
+ default ARCH_BCM_MOBILE
+ help
+ This driver provides restart support for Broadcom Kona chips.
+
+ Say Y here if you have a Broadcom Kona-based board and you wish
+ to have restart support.
+
config POWER_RESET_BRCMSTB
bool "Broadcom STB reset driver"
depends on ARM || MIPS || COMPILE_TEST
obj-$(CONFIG_POWER_RESET_AT91_RESET) += at91-reset.o
obj-$(CONFIG_POWER_RESET_AT91_SAMA5D2_SHDWC) += at91-sama5d2_shdwc.o
obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o
+obj-$(CONFIG_POWER_RESET_BRCMKONA) += brcm-kona-reset.o
obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o
obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
--- /dev/null
+/*
+ * Copyright (C) 2016 Broadcom
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/reboot.h>
+
+#define RSTMGR_REG_WR_ACCESS_OFFSET 0
+#define RSTMGR_REG_CHIP_SOFT_RST_OFFSET 4
+
+#define RSTMGR_WR_PASSWORD 0xa5a5
+#define RSTMGR_WR_PASSWORD_SHIFT 8
+#define RSTMGR_WR_ACCESS_ENABLE 1
+
+static void __iomem *kona_reset_base;
+
+static int kona_reset_handler(struct notifier_block *this,
+ unsigned long mode, void *cmd)
+{
+ /*
+ * A soft reset is triggered by writing a 0 to bit 0 of the soft reset
+ * register. To write to that register we must first write the password
+ * and the enable bit in the write access enable register.
+ */
+ writel((RSTMGR_WR_PASSWORD << RSTMGR_WR_PASSWORD_SHIFT) |
+ RSTMGR_WR_ACCESS_ENABLE,
+ kona_reset_base + RSTMGR_REG_WR_ACCESS_OFFSET);
+ writel(0, kona_reset_base + RSTMGR_REG_CHIP_SOFT_RST_OFFSET);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block kona_reset_nb = {
+ .notifier_call = kona_reset_handler,
+ .priority = 128,
+};
+
+static int kona_reset_probe(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ kona_reset_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(kona_reset_base))
+ return PTR_ERR(kona_reset_base);
+
+ return register_restart_handler(&kona_reset_nb);
+}
+
+static const struct of_device_id of_match[] = {
+ { .compatible = "brcm,bcm21664-resetmgr" },
+ {},
+};
+
+static struct platform_driver bcm_kona_reset_driver = {
+ .probe = kona_reset_probe,
+ .driver = {
+ .name = "brcm-kona-reset",
+ .of_match_table = of_match,
+ },
+};
+
+builtin_platform_driver(bcm_kona_reset_driver);
}
static const struct of_device_id __maybe_unused clps711x_pwm_dt_ids[] = {
- { .compatible = "cirrus,clps711x-pwm", },
+ { .compatible = "cirrus,ep7209-pwm", },
{ }
};
MODULE_DEVICE_TABLE(of, clps711x_pwm_dt_ids);
struct pwm_omap_dmtimer_chip *omap;
struct pwm_omap_dmtimer_pdata *pdata;
pwm_omap_dmtimer *dm_timer;
- u32 prescaler;
+ u32 v;
int status;
pdata = dev_get_platdata(&pdev->dev);
if (pm_runtime_active(&omap->dm_timer_pdev->dev))
omap->pdata->stop(omap->dm_timer);
- /* setup dmtimer prescaler */
- if (!of_property_read_u32(pdev->dev.of_node, "ti,prescaler",
- &prescaler))
- omap->pdata->set_prescaler(omap->dm_timer, prescaler);
+ if (!of_property_read_u32(pdev->dev.of_node, "ti,prescaler", &v))
+ omap->pdata->set_prescaler(omap->dm_timer, v);
+
+ /* setup dmtimer clock source */
+ if (!of_property_read_u32(pdev->dev.of_node, "ti,clock-source", &v))
+ omap->pdata->set_source(omap->dm_timer, v);
omap->chip.dev = &pdev->dev;
omap->chip.ops = &pwm_omap_dmtimer_ops;
#include <linux/mfd/abx500/ab8500.h>
#include <linux/regulator/ab8500.h>
+static struct regulator_consumer_supply ab8500_vaux1_consumers[] = {
+ /* Main display, u8500 R3 uib */
+ REGULATOR_SUPPLY("vddi", "mcde_disp_sony_acx424akp.0"),
+ /* Main display, u8500 uib and ST uib */
+ REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.0"),
+ /* Secondary display, ST uib */
+ REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.1"),
+ /* SFH7741 proximity sensor */
+ REGULATOR_SUPPLY("vcc", "gpio-keys.0"),
+ /* BH1780GLS ambient light sensor */
+ REGULATOR_SUPPLY("vcc", "2-0029"),
+ /* lsm303dlh accelerometer */
+ REGULATOR_SUPPLY("vdd", "2-0018"),
+ /* lsm303dlhc accelerometer */
+ REGULATOR_SUPPLY("vdd", "2-0019"),
+ /* lsm303dlh magnetometer */
+ REGULATOR_SUPPLY("vdd", "2-001e"),
+ /* Rohm BU21013 Touchscreen devices */
+ REGULATOR_SUPPLY("avdd", "3-005c"),
+ REGULATOR_SUPPLY("avdd", "3-005d"),
+ /* Synaptics RMI4 Touchscreen device */
+ REGULATOR_SUPPLY("vdd", "3-004b"),
+ /* L3G4200D Gyroscope device */
+ REGULATOR_SUPPLY("vdd", "2-0068"),
+ /* Ambient light sensor device */
+ REGULATOR_SUPPLY("vdd", "3-0029"),
+ /* Pressure sensor device */
+ REGULATOR_SUPPLY("vdd", "2-005c"),
+ /* Cypress TrueTouch Touchscreen device */
+ REGULATOR_SUPPLY("vcpin", "spi8.0"),
+ /* Camera device */
+ REGULATOR_SUPPLY("vaux12v5", "mmio_camera"),
+};
+
+static struct regulator_consumer_supply ab8500_vaux2_consumers[] = {
+ /* On-board eMMC power */
+ REGULATOR_SUPPLY("vmmc", "sdi4"),
+ /* AB8500 audio codec */
+ REGULATOR_SUPPLY("vcc-N2158", "ab8500-codec.0"),
+ /* AB8500 accessory detect 1 */
+ REGULATOR_SUPPLY("vcc-N2158", "ab8500-acc-det.0"),
+ /* AB8500 Tv-out device */
+ REGULATOR_SUPPLY("vcc-N2158", "mcde_tv_ab8500.4"),
+ /* AV8100 HDMI device */
+ REGULATOR_SUPPLY("vcc-N2158", "av8100_hdmi.3"),
+};
+
+static struct regulator_consumer_supply ab8500_vaux3_consumers[] = {
+ REGULATOR_SUPPLY("v-SD-STM", "stm"),
+ /* External MMC slot power */
+ REGULATOR_SUPPLY("vmmc", "sdi0"),
+};
+
+static struct regulator_consumer_supply ab8500_vtvout_consumers[] = {
+ /* TV-out DENC supply */
+ REGULATOR_SUPPLY("vtvout", "ab8500-denc.0"),
+ /* Internal general-purpose ADC */
+ REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"),
+ /* ADC for charger */
+ REGULATOR_SUPPLY("vddadc", "ab8500-charger.0"),
+ /* AB8500 Tv-out device */
+ REGULATOR_SUPPLY("vtvout", "mcde_tv_ab8500.4"),
+};
+
+static struct regulator_consumer_supply ab8500_vaud_consumers[] = {
+ /* AB8500 audio-codec main supply */
+ REGULATOR_SUPPLY("vaud", "ab8500-codec.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vamic1_consumers[] = {
+ /* AB8500 audio-codec Mic1 supply */
+ REGULATOR_SUPPLY("vamic1", "ab8500-codec.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vamic2_consumers[] = {
+ /* AB8500 audio-codec Mic2 supply */
+ REGULATOR_SUPPLY("vamic2", "ab8500-codec.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vdmic_consumers[] = {
+ /* AB8500 audio-codec DMic supply */
+ REGULATOR_SUPPLY("vdmic", "ab8500-codec.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vintcore_consumers[] = {
+ /* SoC core supply, no device */
+ REGULATOR_SUPPLY("v-intcore", NULL),
+ /* USB Transceiver */
+ REGULATOR_SUPPLY("vddulpivio18", "ab8500-usb.0"),
+ /* Handled by abx500 clk driver */
+ REGULATOR_SUPPLY("v-intcore", "abx500-clk.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vana_consumers[] = {
+ /* DB8500 DSI */
+ REGULATOR_SUPPLY("vdddsi1v2", "mcde"),
+ REGULATOR_SUPPLY("vdddsi1v2", "b2r2_core"),
+ REGULATOR_SUPPLY("vdddsi1v2", "b2r2_1_core"),
+ REGULATOR_SUPPLY("vdddsi1v2", "dsilink.0"),
+ REGULATOR_SUPPLY("vdddsi1v2", "dsilink.1"),
+ REGULATOR_SUPPLY("vdddsi1v2", "dsilink.2"),
+ /* DB8500 CSI */
+ REGULATOR_SUPPLY("vddcsi1v2", "mmio_camera"),
+};
+
+/* ab8500 regulator register initialization */
+static struct ab8500_regulator_reg_init ab8500_reg_init[] = {
+ /*
+ * VanaRequestCtrl = HP/LP depending on VxRequest
+ * VextSupply1RequestCtrl = HP/LP depending on VxRequest
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2, 0xf0, 0x00),
+ /*
+ * VextSupply2RequestCtrl = HP/LP depending on VxRequest
+ * VextSupply3RequestCtrl = HP/LP depending on VxRequest
+ * Vaux1RequestCtrl = HP/LP depending on VxRequest
+ * Vaux2RequestCtrl = HP/LP depending on VxRequest
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL3, 0xff, 0x00),
+ /*
+ * Vaux3RequestCtrl = HP/LP depending on VxRequest
+ * SwHPReq = Control through SWValid disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL4, 0x07, 0x00),
+ /*
+ * VanaSysClkReq1HPValid = disabled
+ * Vaux1SysClkReq1HPValid = disabled
+ * Vaux2SysClkReq1HPValid = disabled
+ * Vaux3SysClkReq1HPValid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0xe8, 0x00),
+ /*
+ * VextSupply1SysClkReq1HPValid = disabled
+ * VextSupply2SysClkReq1HPValid = disabled
+ * VextSupply3SysClkReq1HPValid = SysClkReq1 controlled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID2, 0x70, 0x40),
+ /*
+ * VanaHwHPReq1Valid = disabled
+ * Vaux1HwHPreq1Valid = disabled
+ * Vaux2HwHPReq1Valid = disabled
+ * Vaux3HwHPReqValid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID1, 0xe8, 0x00),
+ /*
+ * VextSupply1HwHPReq1Valid = disabled
+ * VextSupply2HwHPReq1Valid = disabled
+ * VextSupply3HwHPReq1Valid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID2, 0x07, 0x00),
+ /*
+ * VanaHwHPReq2Valid = disabled
+ * Vaux1HwHPReq2Valid = disabled
+ * Vaux2HwHPReq2Valid = disabled
+ * Vaux3HwHPReq2Valid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID1, 0xe8, 0x00),
+ /*
+ * VextSupply1HwHPReq2Valid = disabled
+ * VextSupply2HwHPReq2Valid = disabled
+ * VextSupply3HwHPReq2Valid = HWReq2 controlled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID2, 0x07, 0x04),
+ /*
+ * VanaSwHPReqValid = disabled
+ * Vaux1SwHPReqValid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID1, 0xa0, 0x00),
+ /*
+ * Vaux2SwHPReqValid = disabled
+ * Vaux3SwHPReqValid = disabled
+ * VextSupply1SwHPReqValid = disabled
+ * VextSupply2SwHPReqValid = disabled
+ * VextSupply3SwHPReqValid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID2, 0x1f, 0x00),
+ /*
+ * SysClkReq2Valid1 = SysClkReq2 controlled
+ * SysClkReq3Valid1 = disabled
+ * SysClkReq4Valid1 = SysClkReq4 controlled
+ * SysClkReq5Valid1 = disabled
+ * SysClkReq6Valid1 = SysClkReq6 controlled
+ * SysClkReq7Valid1 = disabled
+ * SysClkReq8Valid1 = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID1, 0xfe, 0x2a),
+ /*
+ * SysClkReq2Valid2 = disabled
+ * SysClkReq3Valid2 = disabled
+ * SysClkReq4Valid2 = disabled
+ * SysClkReq5Valid2 = disabled
+ * SysClkReq6Valid2 = SysClkReq6 controlled
+ * SysClkReq7Valid2 = disabled
+ * SysClkReq8Valid2 = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID2, 0xfe, 0x20),
+ /*
+ * VTVoutEna = disabled
+ * Vintcore12Ena = disabled
+ * Vintcore12Sel = 1.25 V
+ * Vintcore12LP = inactive (HP)
+ * VTVoutLP = inactive (HP)
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUMISC1, 0xfe, 0x10),
+ /*
+ * VaudioEna = disabled
+ * VdmicEna = disabled
+ * Vamic1Ena = disabled
+ * Vamic2Ena = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VAUDIOSUPPLY, 0x1e, 0x00),
+ /*
+ * Vamic1_dzout = high-Z when Vamic1 is disabled
+ * Vamic2_dzout = high-Z when Vamic2 is disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC, 0x03, 0x00),
+ /*
+ * VPll = Hw controlled (NOTE! PRCMU bits)
+ * VanaRegu = force off
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VPLLVANAREGU, 0x0f, 0x02),
+ /*
+ * VrefDDREna = disabled
+ * VrefDDRSleepMode = inactive (no pulldown)
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VREFDDR, 0x03, 0x00),
+ /*
+ * VextSupply1Regu = force LP
+ * VextSupply2Regu = force OFF
+ * VextSupply3Regu = force HP (-> STBB2=LP and TPS=LP)
+ * ExtSupply2Bypass = ExtSupply12LPn ball is 0 when Ena is 0
+ * ExtSupply3Bypass = ExtSupply3LPn ball is 0 when Ena is 0
+ */
+ INIT_REGULATOR_REGISTER(AB8500_EXTSUPPLYREGU, 0xff, 0x13),
+ /*
+ * Vaux1Regu = force HP
+ * Vaux2Regu = force off
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VAUX12REGU, 0x0f, 0x01),
+ /*
+ * Vaux3Regu = force off
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x03, 0x00),
+ /*
+ * Vaux1Sel = 2.8 V
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VAUX1SEL, 0x0f, 0x0C),
+ /*
+ * Vaux2Sel = 2.9 V
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VAUX2SEL, 0x0f, 0x0d),
+ /*
+ * Vaux3Sel = 2.91 V
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3SEL, 0x07, 0x07),
+ /*
+ * VextSupply12LP = disabled (no LP)
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUCTRL2SPARE, 0x01, 0x00),
+ /*
+ * Vaux1Disch = short discharge time
+ * Vaux2Disch = short discharge time
+ * Vaux3Disch = short discharge time
+ * Vintcore12Disch = short discharge time
+ * VTVoutDisch = short discharge time
+ * VaudioDisch = short discharge time
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH, 0xfc, 0x00),
+ /*
+ * VanaDisch = short discharge time
+ * VdmicPullDownEna = pulldown disabled when Vdmic is disabled
+ * VdmicDisch = short discharge time
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH2, 0x16, 0x00),
+};
+
+/* AB8500 regulators */
+static struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
+ /* supplies to the display/camera */
+ [AB8500_LDO_AUX1] = {
+ .supply_regulator = "ab8500-ext-supply3",
+ .constraints = {
+ .name = "V-DISPLAY",
+ .min_uV = 2800000,
+ .max_uV = 3300000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ .boot_on = 1, /* display is on at boot */
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers),
+ .consumer_supplies = ab8500_vaux1_consumers,
+ },
+ /* supplies to the on-board eMMC */
+ [AB8500_LDO_AUX2] = {
+ .supply_regulator = "ab8500-ext-supply3",
+ .constraints = {
+ .name = "V-eMMC1",
+ .min_uV = 1100000,
+ .max_uV = 3300000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers),
+ .consumer_supplies = ab8500_vaux2_consumers,
+ },
+ /* supply for VAUX3, supplies to SDcard slots */
+ [AB8500_LDO_AUX3] = {
+ .supply_regulator = "ab8500-ext-supply3",
+ .constraints = {
+ .name = "V-MMC-SD",
+ .min_uV = 1100000,
+ .max_uV = 3300000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers),
+ .consumer_supplies = ab8500_vaux3_consumers,
+ },
+ /* supply for tvout, gpadc, TVOUT LDO */
+ [AB8500_LDO_TVOUT] = {
+ .constraints = {
+ .name = "V-TVOUT",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vtvout_consumers),
+ .consumer_supplies = ab8500_vtvout_consumers,
+ },
+ /* supply for ab8500-vaudio, VAUDIO LDO */
+ [AB8500_LDO_AUDIO] = {
+ .constraints = {
+ .name = "V-AUD",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaud_consumers),
+ .consumer_supplies = ab8500_vaud_consumers,
+ },
+ /* supply for v-anamic1 VAMic1-LDO */
+ [AB8500_LDO_ANAMIC1] = {
+ .constraints = {
+ .name = "V-AMIC1",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers),
+ .consumer_supplies = ab8500_vamic1_consumers,
+ },
+ /* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
+ [AB8500_LDO_ANAMIC2] = {
+ .constraints = {
+ .name = "V-AMIC2",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers),
+ .consumer_supplies = ab8500_vamic2_consumers,
+ },
+ /* supply for v-dmic, VDMIC LDO */
+ [AB8500_LDO_DMIC] = {
+ .constraints = {
+ .name = "V-DMIC",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vdmic_consumers),
+ .consumer_supplies = ab8500_vdmic_consumers,
+ },
+ /* supply for v-intcore12, VINTCORE12 LDO */
+ [AB8500_LDO_INTCORE] = {
+ .constraints = {
+ .name = "V-INTCORE",
+ .min_uV = 1250000,
+ .max_uV = 1350000,
+ .input_uV = 1800000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE |
+ REGULATOR_CHANGE_DRMS,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers),
+ .consumer_supplies = ab8500_vintcore_consumers,
+ },
+ /* supply for U8500 CSI-DSI, VANA LDO */
+ [AB8500_LDO_ANA] = {
+ .constraints = {
+ .name = "V-CSI-DSI",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers),
+ .consumer_supplies = ab8500_vana_consumers,
+ },
+};
+
+/* supply for VextSupply3 */
+static struct regulator_consumer_supply ab8500_ext_supply3_consumers[] = {
+ /* SIM supply for 3 V SIM cards */
+ REGULATOR_SUPPLY("vinvsim", "sim-detect.0"),
+};
+
+/*
+ * AB8500 external regulators
+ */
+static struct regulator_init_data ab8500_ext_regulators[] = {
+ /* fixed Vbat supplies VSMPS1_EXT_1V8 */
+ [AB8500_EXT_SUPPLY1] = {
+ .constraints = {
+ .name = "ab8500-ext-supply1",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .initial_mode = REGULATOR_MODE_IDLE,
+ .boot_on = 1,
+ .always_on = 1,
+ },
+ },
+ /* fixed Vbat supplies VSMPS2_EXT_1V36 and VSMPS5_EXT_1V15 */
+ [AB8500_EXT_SUPPLY2] = {
+ .constraints = {
+ .name = "ab8500-ext-supply2",
+ .min_uV = 1360000,
+ .max_uV = 1360000,
+ },
+ },
+ /* fixed Vbat supplies VSMPS3_EXT_3V4 and VSMPS4_EXT_3V4 */
+ [AB8500_EXT_SUPPLY3] = {
+ .constraints = {
+ .name = "ab8500-ext-supply3",
+ .min_uV = 3400000,
+ .max_uV = 3400000,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies =
+ ARRAY_SIZE(ab8500_ext_supply3_consumers),
+ .consumer_supplies = ab8500_ext_supply3_consumers,
+ },
+};
+
+static struct ab8500_regulator_platform_data ab8500_regulator_plat_data = {
+ .reg_init = ab8500_reg_init,
+ .num_reg_init = ARRAY_SIZE(ab8500_reg_init),
+ .regulator = ab8500_regulators,
+ .num_regulator = ARRAY_SIZE(ab8500_regulators),
+ .ext_regulator = ab8500_ext_regulators,
+ .num_ext_regulator = ARRAY_SIZE(ab8500_ext_regulators),
+};
+
/**
* struct ab8500_ext_regulator_info - ab8500 regulator information
* @dev: device pointer
static int ab8500_ext_regulator_probe(struct platform_device *pdev)
{
struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
- struct ab8500_platform_data *ppdata;
- struct ab8500_regulator_platform_data *pdata;
+ struct ab8500_regulator_platform_data *pdata = &ab8500_regulator_plat_data;
struct device_node *np = pdev->dev.of_node;
struct regulator_config config = { };
int i, err;
return -EINVAL;
}
- ppdata = dev_get_platdata(ab8500->dev);
- if (!ppdata) {
- dev_err(&pdev->dev, "null parent pdata\n");
- return -EINVAL;
- }
-
- pdata = ppdata->regulator;
- if (!pdata) {
- dev_err(&pdev->dev, "null pdata\n");
- return -EINVAL;
- }
-
/* make sure the platform data has the correct size */
if (pdata->num_ext_regulator != ARRAY_SIZE(ab8500_ext_regulator_info)) {
dev_err(&pdev->dev, "Configuration error: size mismatch.\n");
If unsure, say no.
+if RESET_CONTROLLER
+
config RESET_OXNAS
bool
+config TI_SYSCON_RESET
+ tristate "TI SYSCON Reset Driver"
+ depends on HAS_IOMEM
+ select MFD_SYSCON
+ help
+ This enables the reset driver support for TI devices with
+ memory-mapped reset registers as part of a syscon device node. If
+ you wish to use the reset framework for such memory-mapped devices,
+ say Y here. Otherwise, say N.
+
source "drivers/reset/sti/Kconfig"
source "drivers/reset/hisilicon/Kconfig"
+
+endif
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-$(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_OXNAS) += reset-oxnas.o
+obj-$(CONFIG_TI_SYSCON_RESET) += reset-ti-syscon.o
}
EXPORT_SYMBOL_GPL(reset_controller_unregister);
+static void devm_reset_controller_release(struct device *dev, void *res)
+{
+ reset_controller_unregister(*(struct reset_controller_dev **)res);
+}
+
+/**
+ * devm_reset_controller_register - resource managed reset_controller_register()
+ * @dev: device that is registering this reset controller
+ * @rcdev: a pointer to the initialized reset controller device
+ *
+ * Managed reset_controller_register(). For reset controllers registered by
+ * this function, reset_controller_unregister() is automatically called on
+ * driver detach. See reset_controller_register() for more information.
+ */
+int devm_reset_controller_register(struct device *dev,
+ struct reset_controller_dev *rcdev)
+{
+ struct reset_controller_dev **rcdevp;
+ int ret;
+
+ rcdevp = devres_alloc(devm_reset_controller_release, sizeof(*rcdevp),
+ GFP_KERNEL);
+ if (!rcdevp)
+ return -ENOMEM;
+
+ ret = reset_controller_register(rcdev);
+ if (!ret) {
+ *rcdevp = rcdev;
+ devres_add(dev, rcdevp);
+ } else {
+ devres_free(rcdevp);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devm_reset_controller_register);
+
/**
* reset_control_reset - reset the controlled device
* @rstc: reset controller
/*
* Hisilicon Hi6220 reset controller driver
*
- * Copyright (c) 2015 Hisilicon Limited.
+ * Copyright (c) 2016 Linaro Limited.
+ * Copyright (c) 2015-2016 Hisilicon Limited.
*
* Author: Feng Chen <puck.chen@hisilicon.com>
*
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
#include <linux/reset-controller.h>
#include <linux/reset.h>
#include <linux/platform_device.h>
-#define ASSERT_OFFSET 0x300
-#define DEASSERT_OFFSET 0x304
-#define MAX_INDEX 0x509
+#define PERIPH_ASSERT_OFFSET 0x300
+#define PERIPH_DEASSERT_OFFSET 0x304
+#define PERIPH_MAX_INDEX 0x509
+
+#define SC_MEDIA_RSTEN 0x052C
+#define SC_MEDIA_RSTDIS 0x0530
+#define MEDIA_MAX_INDEX 8
#define to_reset_data(x) container_of(x, struct hi6220_reset_data, rc_dev)
+enum hi6220_reset_ctrl_type {
+ PERIPHERAL,
+ MEDIA,
+};
+
struct hi6220_reset_data {
- void __iomem *assert_base;
- void __iomem *deassert_base;
- struct reset_controller_dev rc_dev;
+ struct reset_controller_dev rc_dev;
+ struct regmap *regmap;
};
-static int hi6220_reset_assert(struct reset_controller_dev *rc_dev,
- unsigned long idx)
+static int hi6220_peripheral_assert(struct reset_controller_dev *rc_dev,
+ unsigned long idx)
{
struct hi6220_reset_data *data = to_reset_data(rc_dev);
+ struct regmap *regmap = data->regmap;
+ u32 bank = idx >> 8;
+ u32 offset = idx & 0xff;
+ u32 reg = PERIPH_ASSERT_OFFSET + bank * 0x10;
- int bank = idx >> 8;
- int offset = idx & 0xff;
+ return regmap_write(regmap, reg, BIT(offset));
+}
- writel(BIT(offset), data->assert_base + (bank * 0x10));
+static int hi6220_peripheral_deassert(struct reset_controller_dev *rc_dev,
+ unsigned long idx)
+{
+ struct hi6220_reset_data *data = to_reset_data(rc_dev);
+ struct regmap *regmap = data->regmap;
+ u32 bank = idx >> 8;
+ u32 offset = idx & 0xff;
+ u32 reg = PERIPH_DEASSERT_OFFSET + bank * 0x10;
- return 0;
+ return regmap_write(regmap, reg, BIT(offset));
}
-static int hi6220_reset_deassert(struct reset_controller_dev *rc_dev,
- unsigned long idx)
+static const struct reset_control_ops hi6220_peripheral_reset_ops = {
+ .assert = hi6220_peripheral_assert,
+ .deassert = hi6220_peripheral_deassert,
+};
+
+static int hi6220_media_assert(struct reset_controller_dev *rc_dev,
+ unsigned long idx)
{
struct hi6220_reset_data *data = to_reset_data(rc_dev);
+ struct regmap *regmap = data->regmap;
- int bank = idx >> 8;
- int offset = idx & 0xff;
+ return regmap_write(regmap, SC_MEDIA_RSTEN, BIT(idx));
+}
- writel(BIT(offset), data->deassert_base + (bank * 0x10));
+static int hi6220_media_deassert(struct reset_controller_dev *rc_dev,
+ unsigned long idx)
+{
+ struct hi6220_reset_data *data = to_reset_data(rc_dev);
+ struct regmap *regmap = data->regmap;
- return 0;
+ return regmap_write(regmap, SC_MEDIA_RSTDIS, BIT(idx));
}
-static const struct reset_control_ops hi6220_reset_ops = {
- .assert = hi6220_reset_assert,
- .deassert = hi6220_reset_deassert,
+static const struct reset_control_ops hi6220_media_reset_ops = {
+ .assert = hi6220_media_assert,
+ .deassert = hi6220_media_deassert,
};
static int hi6220_reset_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ enum hi6220_reset_ctrl_type type;
struct hi6220_reset_data *data;
- struct resource *res;
- void __iomem *src_base;
+ struct regmap *regmap;
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- src_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(src_base))
- return PTR_ERR(src_base);
+ type = (enum hi6220_reset_ctrl_type)of_device_get_match_data(dev);
+
+ regmap = syscon_node_to_regmap(np);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "failed to get reset controller regmap\n");
+ return PTR_ERR(regmap);
+ }
- data->assert_base = src_base + ASSERT_OFFSET;
- data->deassert_base = src_base + DEASSERT_OFFSET;
- data->rc_dev.nr_resets = MAX_INDEX;
- data->rc_dev.ops = &hi6220_reset_ops;
- data->rc_dev.of_node = pdev->dev.of_node;
+ data->regmap = regmap;
+ data->rc_dev.of_node = np;
+ if (type == MEDIA) {
+ data->rc_dev.ops = &hi6220_media_reset_ops;
+ data->rc_dev.nr_resets = MEDIA_MAX_INDEX;
+ } else {
+ data->rc_dev.ops = &hi6220_peripheral_reset_ops;
+ data->rc_dev.nr_resets = PERIPH_MAX_INDEX;
+ }
return reset_controller_register(&data->rc_dev);
}
static const struct of_device_id hi6220_reset_match[] = {
- { .compatible = "hisilicon,hi6220-sysctrl" },
- { },
+ {
+ .compatible = "hisilicon,hi6220-sysctrl",
+ .data = (void *)PERIPHERAL,
+ },
+ {
+ .compatible = "hisilicon,hi6220-mediactrl",
+ .data = (void *)MEDIA,
+ },
+ { /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, hi6220_reset_match);
static struct platform_driver hi6220_reset_driver = {
.probe = hi6220_reset_probe,
ath79_reset->rcdev.of_reset_n_cells = 1;
ath79_reset->rcdev.nr_resets = 32;
- err = reset_controller_register(&ath79_reset->rcdev);
+ err = devm_reset_controller_register(&pdev->dev, &ath79_reset->rcdev);
if (err)
return err;
struct ath79_reset *ath79_reset = platform_get_drvdata(pdev);
unregister_restart_handler(&ath79_reset->restart_nb);
- reset_controller_unregister(&ath79_reset->rcdev);
return 0;
}
--- /dev/null
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright (c) 2016 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * BSD LICENSE
+ *
+ * Copyright (c) 2016 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define REG_COUNT 8
+#define BITS_PER_REG 32
+
+struct meson_reset {
+ void __iomem *reg_base;
+ struct reset_controller_dev rcdev;
+};
+
+static int meson_reset_reset(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct meson_reset *data =
+ container_of(rcdev, struct meson_reset, rcdev);
+ unsigned int bank = id / BITS_PER_REG;
+ unsigned int offset = id % BITS_PER_REG;
+ void __iomem *reg_addr = data->reg_base + (bank << 2);
+
+ if (bank >= REG_COUNT)
+ return -EINVAL;
+
+ writel(BIT(offset), reg_addr);
+
+ return 0;
+}
+
+static const struct reset_control_ops meson_reset_ops = {
+ .reset = meson_reset_reset,
+};
+
+static const struct of_device_id meson_reset_dt_ids[] = {
+ { .compatible = "amlogic,meson8b-reset", },
+ { .compatible = "amlogic,meson-gxbb-reset", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, meson_reset_dt_ids);
+
+static int meson_reset_probe(struct platform_device *pdev)
+{
+ struct meson_reset *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->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(data->reg_base))
+ return PTR_ERR(data->reg_base);
+
+ platform_set_drvdata(pdev, data);
+
+ data->rcdev.owner = THIS_MODULE;
+ data->rcdev.nr_resets = REG_COUNT * BITS_PER_REG;
+ data->rcdev.ops = &meson_reset_ops;
+ data->rcdev.of_node = pdev->dev.of_node;
+
+ return devm_reset_controller_register(&pdev->dev, &data->rcdev);
+}
+
+static struct platform_driver meson_reset_driver = {
+ .probe = meson_reset_probe,
+ .driver = {
+ .name = "meson_reset",
+ .of_match_table = meson_reset_dt_ids,
+ },
+};
+
+module_platform_driver(meson_reset_driver);
+
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_DESCRIPTION("Amlogic Meson Reset Controller driver");
+MODULE_LICENSE("Dual BSD/GPL");
data->rcdev.ops = &oxnas_reset_ops;
data->rcdev.of_node = pdev->dev.of_node;
- return reset_controller_register(&data->rcdev);
-}
-
-static int oxnas_reset_remove(struct platform_device *pdev)
-{
- struct oxnas_reset *data = platform_get_drvdata(pdev);
-
- reset_controller_unregister(&data->rcdev);
-
- return 0;
+ return devm_reset_controller_register(&pdev->dev, &data->rcdev);
}
static struct platform_driver oxnas_reset_driver = {
.probe = oxnas_reset_probe,
- .remove = oxnas_reset_remove,
.driver = {
.name = "oxnas-reset",
.of_match_table = oxnas_reset_dt_ids,
rd->rcdev.ops = &pistachio_reset_ops;
rd->rcdev.of_node = np;
- return reset_controller_register(&rd->rcdev);
-}
-
-static int pistachio_reset_remove(struct platform_device *pdev)
-{
- struct pistachio_reset_data *data = platform_get_drvdata(pdev);
-
- reset_controller_unregister(&data->rcdev);
-
- return 0;
+ return devm_reset_controller_register(dev, &rd->rcdev);
}
static const struct of_device_id pistachio_reset_dt_ids[] = {
static struct platform_driver pistachio_reset_driver = {
.probe = pistachio_reset_probe,
- .remove = pistachio_reset_remove,
.driver = {
.name = "pistachio-reset",
.of_match_table = pistachio_reset_dt_ids,
data->rcdev.ops = &socfpga_reset_ops;
data->rcdev.of_node = pdev->dev.of_node;
- return reset_controller_register(&data->rcdev);
-}
-
-static int socfpga_reset_remove(struct platform_device *pdev)
-{
- struct socfpga_reset_data *data = platform_get_drvdata(pdev);
-
- reset_controller_unregister(&data->rcdev);
-
- return 0;
+ return devm_reset_controller_register(dev, &data->rcdev);
}
static const struct of_device_id socfpga_reset_dt_ids[] = {
static struct platform_driver socfpga_reset_driver = {
.probe = socfpga_reset_probe,
- .remove = socfpga_reset_remove,
.driver = {
.name = "socfpga-reset",
.of_match_table = socfpga_reset_dt_ids,
data->rcdev.ops = &sunxi_reset_ops;
data->rcdev.of_node = pdev->dev.of_node;
- return reset_controller_register(&data->rcdev);
-}
-
-static int sunxi_reset_remove(struct platform_device *pdev)
-{
- struct sunxi_reset_data *data = platform_get_drvdata(pdev);
-
- reset_controller_unregister(&data->rcdev);
-
- return 0;
+ return devm_reset_controller_register(&pdev->dev, &data->rcdev);
}
static struct platform_driver sunxi_reset_driver = {
.probe = sunxi_reset_probe,
- .remove = sunxi_reset_remove,
.driver = {
.name = "sunxi-reset",
.of_match_table = sunxi_reset_dt_ids,
--- /dev/null
+/*
+ * TI SYSCON regmap reset driver
+ *
+ * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
+ * Andrew F. Davis <afd@ti.com>
+ * Suman Anna <afd@ti.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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; 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/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/reset/ti-syscon.h>
+
+/**
+ * struct ti_syscon_reset_control - reset control structure
+ * @assert_offset: reset assert control register offset from syscon base
+ * @assert_bit: reset assert bit in the reset assert control register
+ * @deassert_offset: reset deassert control register offset from syscon base
+ * @deassert_bit: reset deassert bit in the reset deassert control register
+ * @status_offset: reset status register offset from syscon base
+ * @status_bit: reset status bit in the reset status register
+ * @flags: reset flag indicating how the (de)assert and status are handled
+ */
+struct ti_syscon_reset_control {
+ unsigned int assert_offset;
+ unsigned int assert_bit;
+ unsigned int deassert_offset;
+ unsigned int deassert_bit;
+ unsigned int status_offset;
+ unsigned int status_bit;
+ u32 flags;
+};
+
+/**
+ * struct ti_syscon_reset_data - reset controller information structure
+ * @rcdev: reset controller entity
+ * @regmap: regmap handle containing the memory-mapped reset registers
+ * @controls: array of reset controls
+ * @nr_controls: number of controls in control array
+ */
+struct ti_syscon_reset_data {
+ struct reset_controller_dev rcdev;
+ struct regmap *regmap;
+ struct ti_syscon_reset_control *controls;
+ unsigned int nr_controls;
+};
+
+#define to_ti_syscon_reset_data(rcdev) \
+ container_of(rcdev, struct ti_syscon_reset_data, rcdev)
+
+/**
+ * ti_syscon_reset_assert() - assert device reset
+ * @rcdev: reset controller entity
+ * @id: ID of the reset to be asserted
+ *
+ * This function implements the reset driver op to assert a device's reset.
+ * This asserts the reset in a manner prescribed by the reset flags.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int ti_syscon_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct ti_syscon_reset_data *data = to_ti_syscon_reset_data(rcdev);
+ struct ti_syscon_reset_control *control;
+ unsigned int mask, value;
+
+ if (id >= data->nr_controls)
+ return -EINVAL;
+
+ control = &data->controls[id];
+
+ if (control->flags & ASSERT_NONE)
+ return -ENOTSUPP; /* assert not supported for this reset */
+
+ mask = BIT(control->assert_bit);
+ value = (control->flags & ASSERT_SET) ? mask : 0x0;
+
+ return regmap_update_bits(data->regmap, control->assert_offset, mask, value);
+}
+
+/**
+ * ti_syscon_reset_deassert() - deassert device reset
+ * @rcdev: reset controller entity
+ * @id: ID of reset to be deasserted
+ *
+ * This function implements the reset driver op to deassert a device's reset.
+ * This deasserts the reset in a manner prescribed by the reset flags.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int ti_syscon_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct ti_syscon_reset_data *data = to_ti_syscon_reset_data(rcdev);
+ struct ti_syscon_reset_control *control;
+ unsigned int mask, value;
+
+ if (id >= data->nr_controls)
+ return -EINVAL;
+
+ control = &data->controls[id];
+
+ if (control->flags & DEASSERT_NONE)
+ return -ENOTSUPP; /* deassert not supported for this reset */
+
+ mask = BIT(control->deassert_bit);
+ value = (control->flags & DEASSERT_SET) ? mask : 0x0;
+
+ return regmap_update_bits(data->regmap, control->deassert_offset, mask, value);
+}
+
+/**
+ * ti_syscon_reset_status() - check device reset status
+ * @rcdev: reset controller entity
+ * @id: ID of the reset for which the status is being requested
+ *
+ * This function implements the reset driver op to return the status of a
+ * device's reset.
+ *
+ * Return: 0 if reset is deasserted, true if reset is asserted, else a
+ * corresponding error value
+ */
+static int ti_syscon_reset_status(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct ti_syscon_reset_data *data = to_ti_syscon_reset_data(rcdev);
+ struct ti_syscon_reset_control *control;
+ unsigned int reset_state;
+ int ret;
+
+ if (id >= data->nr_controls)
+ return -EINVAL;
+
+ control = &data->controls[id];
+
+ if (control->flags & STATUS_NONE)
+ return -ENOTSUPP; /* status not supported for this reset */
+
+ ret = regmap_read(data->regmap, control->status_offset, &reset_state);
+ if (ret)
+ return ret;
+
+ return (reset_state & BIT(control->status_bit)) &&
+ (control->flags & STATUS_SET);
+}
+
+static struct reset_control_ops ti_syscon_reset_ops = {
+ .assert = ti_syscon_reset_assert,
+ .deassert = ti_syscon_reset_deassert,
+ .status = ti_syscon_reset_status,
+};
+
+static int ti_syscon_reset_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct ti_syscon_reset_data *data;
+ struct regmap *regmap;
+ const __be32 *list;
+ struct ti_syscon_reset_control *controls;
+ int size, nr_controls, i;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ regmap = syscon_node_to_regmap(np->parent);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ list = of_get_property(np, "ti,reset-bits", &size);
+ if (!list || (size / sizeof(*list)) % 7 != 0) {
+ dev_err(dev, "invalid DT reset description\n");
+ return -EINVAL;
+ }
+
+ nr_controls = (size / sizeof(*list)) / 7;
+ controls = devm_kzalloc(dev, nr_controls * sizeof(*controls), GFP_KERNEL);
+ if (!controls)
+ return -ENOMEM;
+
+ for (i = 0; i < nr_controls; i++) {
+ controls[i].assert_offset = be32_to_cpup(list++);
+ controls[i].assert_bit = be32_to_cpup(list++);
+ controls[i].deassert_offset = be32_to_cpup(list++);
+ controls[i].deassert_bit = be32_to_cpup(list++);
+ controls[i].status_offset = be32_to_cpup(list++);
+ controls[i].status_bit = be32_to_cpup(list++);
+ controls[i].flags = be32_to_cpup(list++);
+ }
+
+ data->rcdev.ops = &ti_syscon_reset_ops;
+ data->rcdev.owner = THIS_MODULE;
+ data->rcdev.of_node = np;
+ data->rcdev.nr_resets = nr_controls;
+ data->regmap = regmap;
+ data->controls = controls;
+ data->nr_controls = nr_controls;
+
+ platform_set_drvdata(pdev, data);
+
+ return devm_reset_controller_register(dev, &data->rcdev);
+}
+
+static const struct of_device_id ti_syscon_reset_of_match[] = {
+ { .compatible = "ti,syscon-reset", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ti_syscon_reset_of_match);
+
+static struct platform_driver ti_syscon_reset_driver = {
+ .probe = ti_syscon_reset_probe,
+ .driver = {
+ .name = "ti-syscon-reset",
+ .of_match_table = ti_syscon_reset_of_match,
+ },
+};
+module_platform_driver(ti_syscon_reset_driver);
+
+MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
+MODULE_DESCRIPTION("TI SYSCON Regmap Reset Driver");
+MODULE_LICENSE("GPL v2");
priv->rcdev.ops = &zynq_reset_ops;
priv->rcdev.of_node = pdev->dev.of_node;
- return reset_controller_register(&priv->rcdev);
-}
-
-static int zynq_reset_remove(struct platform_device *pdev)
-{
- struct zynq_reset_data *priv = platform_get_drvdata(pdev);
-
- reset_controller_unregister(&priv->rcdev);
-
- return 0;
+ return devm_reset_controller_register(&pdev->dev, &priv->rcdev);
}
static const struct of_device_id zynq_reset_dt_ids[] = {
static struct platform_driver zynq_reset_driver = {
.probe = zynq_reset_probe,
- .remove = zynq_reset_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = zynq_reset_dt_ids,
config STI_RESET_SYSCFG
bool
- select RESET_CONTROLLER
config STIH415_RESET
bool
menu "SOC (System On Chip) specific Drivers"
source "drivers/soc/bcm/Kconfig"
-source "drivers/soc/brcmstb/Kconfig"
source "drivers/soc/fsl/qe/Kconfig"
source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/qcom/Kconfig"
source "drivers/soc/sunxi/Kconfig"
source "drivers/soc/tegra/Kconfig"
source "drivers/soc/ti/Kconfig"
+source "drivers/soc/ux500/Kconfig"
source "drivers/soc/versatile/Kconfig"
endmenu
#
obj-y += bcm/
-obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
obj-$(CONFIG_ARCH_DOVE) += dove/
obj-$(CONFIG_MACH_DOVE) += dove/
obj-y += fsl/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_SOC_TI) += ti/
+obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_PLAT_VERSATILE) += versatile/
+menu "Broadcom SoC drivers"
+
config RASPBERRYPI_POWER
bool "Raspberry Pi power domain driver"
- depends on ARCH_BCM2835 || COMPILE_TEST
+ depends on ARCH_BCM2835 || (COMPILE_TEST && OF)
depends on RASPBERRYPI_FIRMWARE=y
select PM_GENERIC_DOMAINS if PM
- select PM_GENERIC_DOMAINS_OF if PM
help
This enables support for the RPi power domains which can be enabled
or disabled via the RPi firmware.
+
+config SOC_BRCMSTB
+ bool "Broadcom STB SoC drivers"
+ depends on ARM
+ select SOC_BUS
+ help
+ Enables drivers for the Broadcom Set-Top Box (STB) series of chips.
+ This option alone enables only some support code, while the drivers
+ can be enabled individually within this menu.
+
+ If unsure, say N.
+
+endmenu
obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o
+obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/syscore_ops.h>
+#include <linux/soc/brcmstb/brcmstb.h>
#define CPU_CREDIT_REG_OFFSET 0x184
#define CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK 0x70000000
+++ /dev/null
-menuconfig SOC_BRCMSTB
- bool "Broadcom STB SoC drivers"
- depends on ARM
- select SOC_BUS
- help
- Enables drivers for the Broadcom Set-Top Box (STB) series of chips.
- This option alone enables only some support code, while the drivers
- can be enabled individually within this menu.
-
- If unsure, say N.
if (con_id) {
index = of_property_match_string(dev->of_node,
- "qcom,state-names",
+ "qcom,smem-state-names",
con_id);
if (index < 0) {
- dev_err(dev, "missing qcom,state-names\n");
+ dev_err(dev, "missing qcom,smem-state-names\n");
return ERR_PTR(index);
}
}
ret = of_parse_phandle_with_args(dev->of_node,
- "qcom,state",
- "#qcom,state-cells",
+ "qcom,smem-states",
+ "#qcom,smem-state-cells",
index,
&args);
if (ret) {
- dev_err(dev, "failed to parse qcom,state property\n");
+ dev_err(dev, "failed to parse qcom,smem-states property\n");
return ERR_PTR(ret);
}
if (args.args_count != 1) {
- dev_err(dev, "invalid #qcom,state-cells\n");
+ dev_err(dev, "invalid #qcom,smem-state-cells\n");
return ERR_PTR(-EINVAL);
}
/* Match newly created entries */
for (i = smp2p->valid_entries; i < in->valid_entries; i++) {
list_for_each_entry(entry, &smp2p->inbound, node) {
- memcpy_fromio(buf, in->entries[i].name, sizeof(buf));
+ memcpy(buf, in->entries[i].name, sizeof(buf));
if (!strcmp(buf, entry->name)) {
entry->value = &in->entries[i].value;
break;
/* Allocate an entry from the smem item */
strlcpy(buf, entry->name, SMP2P_MAX_ENTRY_NAME);
- memcpy_toio(out->entries[out->valid_entries].name, buf, SMP2P_MAX_ENTRY_NAME);
- out->valid_entries++;
+ memcpy(out->entries[out->valid_entries].name, buf, SMP2P_MAX_ENTRY_NAME);
/* Make the logical entry reference the physical value */
entry->value = &out->entries[out->valid_entries].value;
+ out->valid_entries++;
+
entry->state = qcom_smem_state_register(node, &smp2p_state_ops, entry);
if (IS_ERR(entry->state)) {
dev_err(smp2p->dev, "failed to register qcom_smem_state\n");
if (!smsm->hosts)
return -ENOMEM;
- local_node = of_find_node_with_property(pdev->dev.of_node, "#qcom,state-cells");
+ local_node = of_find_node_with_property(pdev->dev.of_node, "#qcom,smem-state-cells");
if (!local_node) {
dev_err(&pdev->dev, "no state entry\n");
return -EINVAL;
/*
+ * Copyright (c) 2016, Linaro Ltd.
* Copyright (c) 2015, Sony Mobile Communications Inc.
*
* This program is free software; you can redistribute it and/or modify
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/soc/qcom/smd.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/soc/qcom/wcnss_ctrl.h>
#define WCNSS_REQUEST_TIMEOUT (5 * HZ)
+#define WCNSS_CBC_TIMEOUT (10 * HZ)
+
+#define WCNSS_ACK_DONE_BOOTING 1
+#define WCNSS_ACK_COLD_BOOTING 2
#define NV_FRAGMENT_SIZE 3072
#define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin"
* @dev: device handle
* @channel: SMD channel handle
* @ack: completion for outstanding requests
+ * @cbc: completion for cbc complete indication
* @ack_status: status of the outstanding request
- * @download_nv_work: worker for uploading nv binary
+ * @probe_work: worker for uploading nv binary
*/
struct wcnss_ctrl {
struct device *dev;
struct qcom_smd_channel *channel;
struct completion ack;
+ struct completion cbc;
int ack_status;
- struct work_struct download_nv_work;
+ struct work_struct probe_work;
};
/* message types */
WCNSS_UPLOAD_CAL_RESP,
WCNSS_DOWNLOAD_CAL_REQ,
WCNSS_DOWNLOAD_CAL_RESP,
+ WCNSS_VBAT_LEVEL_IND,
+ WCNSS_BUILD_VERSION_REQ,
+ WCNSS_BUILD_VERSION_RESP,
+ WCNSS_PM_CONFIG_REQ,
+ WCNSS_CBC_COMPLETE_IND,
};
/**
version->major, version->minor,
version->version, version->revision);
- schedule_work(&wcnss->download_nv_work);
+ complete(&wcnss->ack);
break;
case WCNSS_DOWNLOAD_NV_RESP:
if (count != sizeof(*nvresp)) {
wcnss->ack_status = nvresp->status;
complete(&wcnss->ack);
break;
+ case WCNSS_CBC_COMPLETE_IND:
+ dev_dbg(wcnss->dev, "cold boot complete\n");
+ complete(&wcnss->cbc);
+ break;
default:
dev_info(wcnss->dev, "unknown message type %d\n", hdr->type);
break;
static int wcnss_request_version(struct wcnss_ctrl *wcnss)
{
struct wcnss_msg_hdr msg;
+ int ret;
msg.type = WCNSS_VERSION_REQ;
msg.len = sizeof(msg);
+ ret = qcom_smd_send(wcnss->channel, &msg, sizeof(msg));
+ if (ret < 0)
+ return ret;
+
+ ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_CBC_TIMEOUT);
+ if (!ret) {
+ dev_err(wcnss->dev, "timeout waiting for version response\n");
+ return -ETIMEDOUT;
+ }
- return qcom_smd_send(wcnss->channel, &msg, sizeof(msg));
+ return 0;
}
/**
* wcnss_download_nv() - send nv binary to WCNSS
- * @work: work struct to acquire wcnss context
+ * @wcnss: wcnss_ctrl state handle
+ * @expect_cbc: indicator to caller that an cbc event is expected
+ *
+ * Returns 0 on success. Negative errno on failure.
*/
-static void wcnss_download_nv(struct work_struct *work)
+static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc)
{
- struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, download_nv_work);
struct wcnss_download_nv_req *req;
const struct firmware *fw;
const void *data;
req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL);
if (!req)
- return;
+ return -ENOMEM;
ret = request_firmware(&fw, NVBIN_FILE, wcnss->dev);
- if (ret) {
+ if (ret < 0) {
dev_err(wcnss->dev, "Failed to load nv file %s: %d\n",
NVBIN_FILE, ret);
goto free_req;
memcpy(req->fragment, data, req->frag_size);
ret = qcom_smd_send(wcnss->channel, req, req->hdr.len);
- if (ret) {
+ if (ret < 0) {
dev_err(wcnss->dev, "failed to send smd packet\n");
goto release_fw;
}
} while (left > 0);
ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_REQUEST_TIMEOUT);
- if (!ret)
+ if (!ret) {
dev_err(wcnss->dev, "timeout waiting for nv upload ack\n");
- else if (wcnss->ack_status != 1)
- dev_err(wcnss->dev, "nv upload response failed err: %d\n",
- wcnss->ack_status);
+ ret = -ETIMEDOUT;
+ } else {
+ *expect_cbc = wcnss->ack_status == WCNSS_ACK_COLD_BOOTING;
+ ret = 0;
+ }
release_fw:
release_firmware(fw);
free_req:
kfree(req);
+
+ return ret;
+}
+
+/**
+ * qcom_wcnss_open_channel() - open additional SMD channel to WCNSS
+ * @wcnss: wcnss handle, retrieved from drvdata
+ * @name: SMD channel name
+ * @cb: callback to handle incoming data on the channel
+ */
+struct qcom_smd_channel *qcom_wcnss_open_channel(void *wcnss, const char *name, qcom_smd_cb_t cb)
+{
+ struct wcnss_ctrl *_wcnss = wcnss;
+
+ return qcom_smd_open_channel(_wcnss->channel, name, cb);
+}
+EXPORT_SYMBOL(qcom_wcnss_open_channel);
+
+static void wcnss_async_probe(struct work_struct *work)
+{
+ struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, probe_work);
+ bool expect_cbc;
+ int ret;
+
+ ret = wcnss_request_version(wcnss);
+ if (ret < 0)
+ return;
+
+ ret = wcnss_download_nv(wcnss, &expect_cbc);
+ if (ret < 0)
+ return;
+
+ /* Wait for pending cold boot completion if indicated by the nv downloader */
+ if (expect_cbc) {
+ ret = wait_for_completion_timeout(&wcnss->cbc, WCNSS_REQUEST_TIMEOUT);
+ if (!ret)
+ dev_err(wcnss->dev, "expected cold boot completion\n");
+ }
+
+ of_platform_populate(wcnss->dev->of_node, NULL, NULL, wcnss->dev);
}
static int wcnss_ctrl_probe(struct qcom_smd_device *sdev)
wcnss->channel = sdev->channel;
init_completion(&wcnss->ack);
- INIT_WORK(&wcnss->download_nv_work, wcnss_download_nv);
+ init_completion(&wcnss->cbc);
+ INIT_WORK(&wcnss->probe_work, wcnss_async_probe);
qcom_smd_set_drvdata(sdev->channel, wcnss);
+ dev_set_drvdata(&sdev->dev, wcnss);
+
+ schedule_work(&wcnss->probe_work);
+
+ return 0;
+}
+
+static void wcnss_ctrl_remove(struct qcom_smd_device *sdev)
+{
+ struct wcnss_ctrl *wcnss = qcom_smd_get_drvdata(sdev->channel);
- return wcnss_request_version(wcnss);
+ cancel_work_sync(&wcnss->probe_work);
+ of_platform_depopulate(&sdev->dev);
}
-static const struct qcom_smd_id wcnss_ctrl_smd_match[] = {
- { .name = "WCNSS_CTRL" },
+static const struct of_device_id wcnss_ctrl_of_match[] = {
+ { .compatible = "qcom,wcnss", },
{}
};
static struct qcom_smd_driver wcnss_ctrl_driver = {
.probe = wcnss_ctrl_probe,
+ .remove = wcnss_ctrl_remove,
.callback = wcnss_ctrl_smd_callback,
- .smd_match_table = wcnss_ctrl_smd_match,
.driver = {
.name = "qcom_wcnss_ctrl",
.owner = THIS_MODULE,
+ .of_match_table = wcnss_ctrl_of_match,
},
};
obj-$(CONFIG_ARCH_R8A7779) += rcar-sysc.o r8a7779-sysc.o
obj-$(CONFIG_ARCH_R8A7790) += rcar-sysc.o r8a7790-sysc.o
obj-$(CONFIG_ARCH_R8A7791) += rcar-sysc.o r8a7791-sysc.o
+obj-$(CONFIG_ARCH_R8A7792) += rcar-sysc.o r8a7792-sysc.o
# R-Car M2-N is identical to R-Car M2-W w.r.t. power domains.
obj-$(CONFIG_ARCH_R8A7793) += rcar-sysc.o r8a7791-sysc.o
obj-$(CONFIG_ARCH_R8A7794) += rcar-sysc.o r8a7794-sysc.o
obj-$(CONFIG_ARCH_R8A7795) += rcar-sysc.o r8a7795-sysc.o
+obj-$(CONFIG_ARCH_R8A7796) += rcar-sysc.o r8a7796-sysc.o
--- /dev/null
+/*
+ * Renesas R-Car V2H (R8A7792) System Controller
+ *
+ * Copyright (C) 2016 Cogent Embedded Inc.
+ *
+ * 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; version 2 of the License.
+ */
+
+#include <linux/bug.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <dt-bindings/power/r8a7792-sysc.h>
+
+#include "rcar-sysc.h"
+
+static const struct rcar_sysc_area r8a7792_areas[] __initconst = {
+ { "always-on", 0, 0, R8A7792_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
+ { "ca15-scu", 0x180, 0, R8A7792_PD_CA15_SCU, R8A7792_PD_ALWAYS_ON,
+ PD_SCU },
+ { "ca15-cpu0", 0x40, 0, R8A7792_PD_CA15_CPU0, R8A7792_PD_CA15_SCU,
+ PD_CPU_NOCR },
+ { "ca15-cpu1", 0x40, 1, R8A7792_PD_CA15_CPU1, R8A7792_PD_CA15_SCU,
+ PD_CPU_NOCR },
+ { "sgx", 0xc0, 0, R8A7792_PD_SGX, R8A7792_PD_ALWAYS_ON },
+ { "imp", 0x140, 0, R8A7792_PD_IMP, R8A7792_PD_ALWAYS_ON },
+};
+
+const struct rcar_sysc_info r8a7792_sysc_info __initconst = {
+ .areas = r8a7792_areas,
+ .num_areas = ARRAY_SIZE(r8a7792_areas),
+};
--- /dev/null
+/*
+ * Renesas R-Car M3-W System Controller
+ *
+ * Copyright (C) 2016 Glider bvba
+ *
+ * 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; version 2 of the License.
+ */
+
+#include <linux/bug.h>
+#include <linux/kernel.h>
+
+#include <dt-bindings/power/r8a7796-sysc.h>
+
+#include "rcar-sysc.h"
+
+static const struct rcar_sysc_area r8a7796_areas[] __initconst = {
+ { "always-on", 0, 0, R8A7796_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
+ { "ca57-scu", 0x1c0, 0, R8A7796_PD_CA57_SCU, R8A7796_PD_ALWAYS_ON,
+ PD_SCU },
+ { "ca57-cpu0", 0x80, 0, R8A7796_PD_CA57_CPU0, R8A7796_PD_CA57_SCU,
+ PD_CPU_NOCR },
+ { "ca57-cpu1", 0x80, 1, R8A7796_PD_CA57_CPU1, R8A7796_PD_CA57_SCU,
+ PD_CPU_NOCR },
+ { "ca53-scu", 0x140, 0, R8A7796_PD_CA53_SCU, R8A7796_PD_ALWAYS_ON,
+ PD_SCU },
+ { "ca53-cpu0", 0x200, 0, R8A7796_PD_CA53_CPU0, R8A7796_PD_CA53_SCU,
+ PD_CPU_NOCR },
+ { "ca53-cpu1", 0x200, 1, R8A7796_PD_CA53_CPU1, R8A7796_PD_CA53_SCU,
+ PD_CPU_NOCR },
+ { "ca53-cpu2", 0x200, 2, R8A7796_PD_CA53_CPU2, R8A7796_PD_CA53_SCU,
+ PD_CPU_NOCR },
+ { "ca53-cpu3", 0x200, 3, R8A7796_PD_CA53_CPU3, R8A7796_PD_CA53_SCU,
+ PD_CPU_NOCR },
+ { "cr7", 0x240, 0, R8A7796_PD_CR7, R8A7796_PD_ALWAYS_ON },
+ { "a3vc", 0x380, 0, R8A7796_PD_A3VC, R8A7796_PD_ALWAYS_ON },
+ { "a2vc0", 0x3c0, 0, R8A7796_PD_A2VC0, R8A7796_PD_A3VC },
+ { "a2vc1", 0x3c0, 1, R8A7796_PD_A2VC1, R8A7796_PD_A3VC },
+ { "3dg-a", 0x100, 0, R8A7796_PD_3DG_A, R8A7796_PD_ALWAYS_ON },
+ { "3dg-b", 0x100, 1, R8A7796_PD_3DG_B, R8A7796_PD_3DG_A },
+ { "a3ir", 0x180, 0, R8A7796_PD_A3IR, R8A7796_PD_ALWAYS_ON },
+};
+
+const struct rcar_sysc_info r8a7796_sysc_info __initconst = {
+ .areas = r8a7796_areas,
+ .num_areas = ARRAY_SIZE(r8a7796_areas),
+};
return false;
}
-void __iomem *rcar_sysc_init(phys_addr_t base)
-{
- rcar_sysc_base = ioremap_nocache(base, PAGE_SIZE);
- if (!rcar_sysc_base)
- panic("unable to ioremap R-Car SYSC hardware block\n");
-
- return rcar_sysc_base;
-}
-
struct rcar_sysc_pd {
struct generic_pm_domain genpd;
struct rcar_sysc_ch ch;
#ifdef CONFIG_ARCH_R8A7791
{ .compatible = "renesas,r8a7791-sysc", .data = &r8a7791_sysc_info },
#endif
+#ifdef CONFIG_ARCH_R8A7792
+ { .compatible = "renesas,r8a7792-sysc", .data = &r8a7792_sysc_info },
+#endif
#ifdef CONFIG_ARCH_R8A7793
/* R-Car M2-N is identical to R-Car M2-W w.r.t. power domains. */
{ .compatible = "renesas,r8a7793-sysc", .data = &r8a7791_sysc_info },
#endif
#ifdef CONFIG_ARCH_R8A7795
{ .compatible = "renesas,r8a7795-sysc", .data = &r8a7795_sysc_info },
+#endif
+#ifdef CONFIG_ARCH_R8A7796
+ { .compatible = "renesas,r8a7796-sysc", .data = &r8a7796_sysc_info },
#endif
{ /* sentinel */ }
};
unsigned int i;
int error;
+ if (rcar_sysc_base)
+ return 0;
+
np = of_find_matching_node_and_match(NULL, rcar_sysc_matches, &match);
if (!np)
return -ENODEV;
domains->domains[area->isr_bit] = &pd->genpd;
}
- of_genpd_add_provider_onecell(np, &domains->onecell_data);
+ error = of_genpd_add_provider_onecell(np, &domains->onecell_data);
out_put:
of_node_put(np);
return error;
}
early_initcall(rcar_sysc_pd_init);
+
+void __init rcar_sysc_init(phys_addr_t base, u32 syscier)
+{
+ u32 syscimr;
+
+ if (!rcar_sysc_pd_init())
+ return;
+
+ rcar_sysc_base = ioremap_nocache(base, PAGE_SIZE);
+
+ /*
+ * Mask all interrupt sources to prevent the CPU from receiving them.
+ * Make sure not to clear reserved bits that were set before.
+ */
+ syscimr = ioread32(rcar_sysc_base + SYSCIMR);
+ syscimr |= syscier;
+ pr_debug("%s: syscimr = 0x%08x\n", __func__, syscimr);
+ iowrite32(syscimr, rcar_sysc_base + SYSCIMR);
+
+ /*
+ * SYSC needs all interrupt sources enabled to control power.
+ */
+ pr_debug("%s: syscier = 0x%08x\n", __func__, syscier);
+ iowrite32(syscier, rcar_sysc_base + SYSCIER);
+}
extern const struct rcar_sysc_info r8a7779_sysc_info;
extern const struct rcar_sysc_info r8a7790_sysc_info;
extern const struct rcar_sysc_info r8a7791_sysc_info;
+extern const struct rcar_sysc_info r8a7792_sysc_info;
extern const struct rcar_sysc_info r8a7794_sysc_info;
extern const struct rcar_sysc_info r8a7795_sysc_info;
+extern const struct rcar_sysc_info r8a7796_sysc_info;
#endif /* __SOC_RENESAS_RCAR_SYSC_H__ */
#define PMC_CNTRL_CPU_PWRREQ_POLARITY (1 << 15) /* CPU pwr req polarity */
#define PMC_CNTRL_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */
#define PMC_CNTRL_INTR_POLARITY (1 << 17) /* inverts INTR polarity */
+#define PMC_CNTRL_MAIN_RST (1 << 4)
#define DPD_SAMPLE 0x020
#define DPD_SAMPLE_ENABLE (1 << 0)
#define PMC_SENSOR_CTRL_SCRATCH_WRITE (1 << 2)
#define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1)
+#define PMC_RST_STATUS 0x1b4
+#define PMC_RST_STATUS_POR 0
+#define PMC_RST_STATUS_WATCHDOG 1
+#define PMC_RST_STATUS_SENSOR 2
+#define PMC_RST_STATUS_SW_MAIN 3
+#define PMC_RST_STATUS_LP0 4
+#define PMC_RST_STATUS_AOTAG 5
+
#define IO_DPD_REQ 0x1b8
#define IO_DPD_REQ_CODE_IDLE (0 << 30)
#define IO_DPD_REQ_CODE_OFF (1 << 30)
disable_clks:
tegra_powergate_disable_clocks(pg);
usleep_range(10, 20);
+
powergate_off:
tegra_powergate_set(pg->id, false);
usleep_range(10, 20);
tegra_powergate_reset_deassert(pg);
usleep_range(10, 20);
+
disable_clks:
tegra_powergate_disable_clocks(pg);
struct tegra_powergate pg;
int err;
+ if (!tegra_powergate_is_available(id))
+ return -EINVAL;
+
pg.id = id;
pg.clks = &clk;
pg.num_clks = 1;
tegra_pmc_writel(value, PMC_SCRATCH0);
- value = tegra_pmc_readl(0);
- value |= 0x10;
- tegra_pmc_writel(value, 0);
+ /* reset everything but PMC_SCRATCH0 and PMC_RST_STATUS */
+ value = tegra_pmc_readl(PMC_CNTRL);
+ value |= PMC_CNTRL_MAIN_RST;
+ tegra_pmc_writel(value, PMC_CNTRL);
return NOTIFY_DONE;
}
err:
while (i--)
clk_put(pg->clks[i]);
+
kfree(pg->clks);
return err;
}
static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
- struct device_node *np)
+ struct device_node *np, bool off)
{
struct reset_control *rst;
unsigned int i, count;
err = PTR_ERR(pg->resets[i]);
goto error;
}
+
+ if (off)
+ err = reset_control_assert(pg->resets[i]);
+ else
+ err = reset_control_deassert(pg->resets[i]);
+
+ if (err) {
+ reset_control_put(pg->resets[i]);
+ goto error;
+ }
}
pg->num_resets = count;
error:
while (i--)
reset_control_put(pg->resets[i]);
+
kfree(pg->resets);
return err;
static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
{
struct tegra_powergate *pg;
+ int id, err;
bool off;
- int id;
pg = kzalloc(sizeof(*pg), GFP_KERNEL);
if (!pg)
- goto error;
+ return;
id = tegra_powergate_lookup(pmc, np->name);
- if (id < 0)
+ if (id < 0) {
+ dev_err(pmc->dev, "powergate lookup failed for %s: %d\n",
+ np->name, id);
goto free_mem;
+ }
/*
* Clear the bit for this powergate so it cannot be managed
pg->genpd.power_on = tegra_genpd_power_on;
pg->pmc = pmc;
- if (tegra_powergate_of_get_clks(pg, np))
+ off = !tegra_powergate_is_powered(pg->id);
+
+ err = tegra_powergate_of_get_clks(pg, np);
+ if (err < 0) {
+ dev_err(pmc->dev, "failed to get clocks for %s: %d\n",
+ np->name, err);
goto set_available;
+ }
- if (tegra_powergate_of_get_resets(pg, np))
+ err = tegra_powergate_of_get_resets(pg, np, off);
+ if (err < 0) {
+ dev_err(pmc->dev, "failed to get resets for %s: %d\n",
+ np->name, err);
goto remove_clks;
+ }
- off = !tegra_powergate_is_powered(pg->id);
+ if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
+ goto power_on_cleanup;
+
+ /*
+ * FIXME: If XHCI is enabled for Tegra, then power-up the XUSB
+ * host and super-speed partitions. Once the XHCI driver
+ * manages the partitions itself this code can be removed. Note
+ * that we don't register these partitions with the genpd core
+ * to avoid it from powering down the partitions as they appear
+ * to be unused.
+ */
+ if (IS_ENABLED(CONFIG_USB_XHCI_TEGRA) &&
+ (id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC))
+ goto power_on_cleanup;
pm_genpd_init(&pg->genpd, NULL, off);
- if (of_genpd_add_provider_simple(np, &pg->genpd))
+ err = of_genpd_add_provider_simple(np, &pg->genpd);
+ if (err < 0) {
+ dev_err(pmc->dev, "failed to add genpd provider for %s: %d\n",
+ np->name, err);
goto remove_resets;
+ }
dev_dbg(pmc->dev, "added power domain %s\n", pg->genpd.name);
return;
+power_on_cleanup:
+ if (off)
+ WARN_ON(tegra_powergate_power_up(pg, true));
+
remove_resets:
while (pg->num_resets--)
reset_control_put(pg->resets[pg->num_resets]);
+
kfree(pg->resets);
remove_clks:
while (pg->num_clks--)
clk_put(pg->clks[pg->num_clks]);
+
kfree(pg->clks);
set_available:
free_mem:
kfree(pg);
-
-error:
- dev_err(pmc->dev, "failed to create power domain for %s\n", np->name);
}
-static void tegra_powergate_init(struct tegra_pmc *pmc)
+static void tegra_powergate_init(struct tegra_pmc *pmc,
+ struct device_node *parent)
{
struct device_node *np, *child;
+ unsigned int i;
+
+ /* Create a bitmap of the available and valid partitions */
+ for (i = 0; i < pmc->soc->num_powergates; i++)
+ if (pmc->soc->powergates[i])
+ set_bit(i, pmc->powergates_available);
- np = of_get_child_by_name(pmc->dev->of_node, "powergates");
+ np = of_get_child_by_name(parent, "powergates");
if (!np)
return;
struct resource *res;
int err;
+ /*
+ * Early initialisation should have configured an initial
+ * register mapping and setup the soc data pointer. If these
+ * are not valid then something went badly wrong!
+ */
+ if (WARN_ON(!pmc->base || !pmc->soc))
+ return -ENODEV;
+
err = tegra_pmc_parse_dt(pmc, pdev->dev.of_node);
if (err < 0)
return err;
return err;
}
- tegra_powergate_init(pmc);
-
mutex_lock(&pmc->powergates_lock);
iounmap(pmc->base);
pmc->base = base;
const struct of_device_id *match;
struct device_node *np;
struct resource regs;
- unsigned int i;
bool invert;
u32 value;
+ mutex_init(&pmc->powergates_lock);
+
np = of_find_matching_node_and_match(NULL, tegra_pmc_match, &match);
if (!np) {
/*
*/
if (of_address_to_resource(np, 0, ®s) < 0) {
pr_err("failed to get PMC registers\n");
+ of_node_put(np);
return -ENXIO;
}
-
- pmc->soc = match->data;
}
pmc->base = ioremap_nocache(regs.start, resource_size(®s));
if (!pmc->base) {
pr_err("failed to map PMC registers\n");
+ of_node_put(np);
return -ENXIO;
}
- /* Create a bit-map of the available and valid partitions */
- for (i = 0; i < pmc->soc->num_powergates; i++)
- if (pmc->soc->powergates[i])
- set_bit(i, pmc->powergates_available);
+ if (np) {
+ pmc->soc = match->data;
- mutex_init(&pmc->powergates_lock);
+ tegra_powergate_init(pmc, np);
- /*
- * Invert the interrupt polarity if a PMC device tree node exists and
- * contains the nvidia,invert-interrupt property.
- */
- invert = of_property_read_bool(np, "nvidia,invert-interrupt");
+ /*
+ * Invert the interrupt polarity if a PMC device tree node
+ * exists and contains the nvidia,invert-interrupt property.
+ */
+ invert = of_property_read_bool(np, "nvidia,invert-interrupt");
- value = tegra_pmc_readl(PMC_CNTRL);
+ value = tegra_pmc_readl(PMC_CNTRL);
- if (invert)
- value |= PMC_CNTRL_INTR_POLARITY;
- else
- value &= ~PMC_CNTRL_INTR_POLARITY;
+ if (invert)
+ value |= PMC_CNTRL_INTR_POLARITY;
+ else
+ value &= ~PMC_CNTRL_INTR_POLARITY;
- tegra_pmc_writel(value, PMC_CNTRL);
+ tegra_pmc_writel(value, PMC_CNTRL);
+
+ of_node_put(np);
+ }
return 0;
}
--- /dev/null
+config UX500_SOC_ID
+ bool "SoC bus for ST-Ericsson ux500"
+ depends on ARCH_U8500 || COMPILE_TEST
+ default ARCH_U8500
+ help
+ Include support for the SoC bus on the ARM RealView platforms
+ providing some sysfs information about the ASIC variant.
--- /dev/null
+obj-$(CONFIG_UX500_SOC_ID) += ux500-soc-id.o
--- /dev/null
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/sys_soc.h>
+
+#include <asm/cputype.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#include <asm/mach/map.h>
+
+/**
+ * struct dbx500_asic_id - fields of the ASIC ID
+ * @process: the manufacturing process, 0x40 is 40 nm 0x00 is "standard"
+ * @partnumber: hithereto 0x8500 for DB8500
+ * @revision: version code in the series
+ */
+struct dbx500_asic_id {
+ u16 partnumber;
+ u8 revision;
+ u8 process;
+};
+
+static struct dbx500_asic_id dbx500_id;
+
+static unsigned int __init ux500_read_asicid(phys_addr_t addr)
+{
+ void __iomem *virt = ioremap(addr, 4);
+ unsigned int asicid;
+
+ if (!virt)
+ return 0;
+
+ asicid = readl(virt);
+ iounmap(virt);
+
+ return asicid;
+}
+
+static void ux500_print_soc_info(unsigned int asicid)
+{
+ unsigned int rev = dbx500_id.revision;
+
+ pr_info("DB%4x ", dbx500_id.partnumber);
+
+ if (rev == 0x01)
+ pr_cont("Early Drop");
+ else if (rev >= 0xA0)
+ pr_cont("v%d.%d" , (rev >> 4) - 0xA + 1, rev & 0xf);
+ else
+ pr_cont("Unknown");
+
+ pr_cont(" [%#010x]\n", asicid);
+}
+
+static unsigned int partnumber(unsigned int asicid)
+{
+ return (asicid >> 8) & 0xffff;
+}
+
+/*
+ * SOC MIDR ASICID ADDRESS ASICID VALUE
+ * DB8500ed 0x410fc090 0x9001FFF4 0x00850001
+ * DB8500v1 0x411fc091 0x9001FFF4 0x008500A0
+ * DB8500v1.1 0x411fc091 0x9001FFF4 0x008500A1
+ * DB8500v2 0x412fc091 0x9001DBF4 0x008500B0
+ * DB8520v2.2 0x412fc091 0x9001DBF4 0x008500B2
+ * DB5500v1 0x412fc091 0x9001FFF4 0x005500A0
+ * DB9540 0x413fc090 0xFFFFDBF4 0x009540xx
+ */
+
+static void __init ux500_setup_id(void)
+{
+ unsigned int cpuid = read_cpuid_id();
+ unsigned int asicid = 0;
+ phys_addr_t addr = 0;
+
+ switch (cpuid) {
+ case 0x410fc090: /* DB8500ed */
+ case 0x411fc091: /* DB8500v1 */
+ addr = 0x9001FFF4;
+ break;
+
+ case 0x412fc091: /* DB8520 / DB8500v2 / DB5500v1 */
+ asicid = ux500_read_asicid(0x9001DBF4);
+ if (partnumber(asicid) == 0x8500 ||
+ partnumber(asicid) == 0x8520)
+ /* DB8500v2 */
+ break;
+
+ /* DB5500v1 */
+ addr = 0x9001FFF4;
+ break;
+
+ case 0x413fc090: /* DB9540 */
+ addr = 0xFFFFDBF4;
+ break;
+ }
+
+ if (addr)
+ asicid = ux500_read_asicid(addr);
+
+ if (!asicid) {
+ pr_err("Unable to identify SoC\n");
+ BUG();
+ }
+
+ dbx500_id.process = asicid >> 24;
+ dbx500_id.partnumber = partnumber(asicid);
+ dbx500_id.revision = asicid & 0xff;
+
+ ux500_print_soc_info(asicid);
+}
+
+static const char * __init ux500_get_machine(void)
+{
+ return kasprintf(GFP_KERNEL, "DB%4x", dbx500_id.partnumber);
+}
+
+static const char * __init ux500_get_family(void)
+{
+ return kasprintf(GFP_KERNEL, "ux500");
+}
+
+static const char * __init ux500_get_revision(void)
+{
+ unsigned int rev = dbx500_id.revision;
+
+ if (rev == 0x01)
+ return kasprintf(GFP_KERNEL, "%s", "ED");
+ else if (rev >= 0xA0)
+ return kasprintf(GFP_KERNEL, "%d.%d",
+ (rev >> 4) - 0xA + 1, rev & 0xf);
+
+ return kasprintf(GFP_KERNEL, "%s", "Unknown");
+}
+
+static ssize_t ux500_get_process(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ if (dbx500_id.process == 0x00)
+ return sprintf(buf, "Standard\n");
+
+ return sprintf(buf, "%02xnm\n", dbx500_id.process);
+}
+
+static const char *db8500_read_soc_id(struct device_node *backupram)
+{
+ void __iomem *base;
+ void __iomem *uid;
+ const char *retstr;
+
+ base = of_iomap(backupram, 0);
+ if (!base)
+ return NULL;
+ uid = base + 0x1fc0;
+
+ /* Throw these device-specific numbers into the entropy pool */
+ add_device_randomness(uid, 0x14);
+ retstr = kasprintf(GFP_KERNEL, "%08x%08x%08x%08x%08x",
+ readl((u32 *)uid+0),
+ readl((u32 *)uid+1), readl((u32 *)uid+2),
+ readl((u32 *)uid+3), readl((u32 *)uid+4));
+ iounmap(base);
+ return retstr;
+}
+
+static void __init soc_info_populate(struct soc_device_attribute *soc_dev_attr,
+ struct device_node *backupram)
+{
+ soc_dev_attr->soc_id = db8500_read_soc_id(backupram);
+ soc_dev_attr->machine = ux500_get_machine();
+ soc_dev_attr->family = ux500_get_family();
+ soc_dev_attr->revision = ux500_get_revision();
+}
+
+static const struct device_attribute ux500_soc_attr =
+ __ATTR(process, S_IRUGO, ux500_get_process, NULL);
+
+static int __init ux500_soc_device_init(void)
+{
+ struct device *parent;
+ struct soc_device *soc_dev;
+ struct soc_device_attribute *soc_dev_attr;
+ struct device_node *backupram;
+
+ backupram = of_find_compatible_node(NULL, NULL, "ste,dbx500-backupram");
+ if (!backupram)
+ return 0;
+
+ ux500_setup_id();
+
+ soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+ if (!soc_dev_attr)
+ return -ENOMEM;
+
+ soc_info_populate(soc_dev_attr, backupram);
+
+ soc_dev = soc_device_register(soc_dev_attr);
+ if (IS_ERR(soc_dev)) {
+ kfree(soc_dev_attr);
+ return PTR_ERR(soc_dev);
+ }
+
+ parent = soc_device_to_device(soc_dev);
+ device_create_file(parent, &ux500_soc_attr);
+
+ return 0;
+}
+subsys_initcall(ux500_soc_device_init);
}
static const struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = {
- { .compatible = "cirrus,clps711x-uart", },
+ { .compatible = "cirrus,ep7209-uart", },
{ }
};
MODULE_DEVICE_TABLE(of, clps711x_uart_dt_ids);
}
cfb->syscon =
- syscon_regmap_lookup_by_compatible("cirrus,clps711x-syscon1");
+ syscon_regmap_lookup_by_compatible("cirrus,ep7209-syscon1");
if (IS_ERR(cfb->syscon)) {
ret = PTR_ERR(cfb->syscon);
goto out_fb_release;
}
static const struct of_device_id clps711x_fb_dt_ids[] = {
- { .compatible = "cirrus,clps711x-fb", },
+ { .compatible = "cirrus,ep7209-fb", },
{ }
};
MODULE_DEVICE_TABLE(of, clps711x_fb_dt_ids);
--- /dev/null
+/*
+ * Copyright (C) 2016 Glider bvba
+ *
+ * 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; version 2 of the License.
+ */
+#ifndef __DT_BINDINGS_POWER_R8A7796_SYSC_H__
+#define __DT_BINDINGS_POWER_R8A7796_SYSC_H__
+
+/*
+ * These power domain indices match the numbers of the interrupt bits
+ * representing the power areas in the various Interrupt Registers
+ * (e.g. SYSCISR, Interrupt Status Register)
+ */
+
+#define R8A7796_PD_CA57_CPU0 0
+#define R8A7796_PD_CA57_CPU1 1
+#define R8A7796_PD_CA53_CPU0 5
+#define R8A7796_PD_CA53_CPU1 6
+#define R8A7796_PD_CA53_CPU2 7
+#define R8A7796_PD_CA53_CPU3 8
+#define R8A7796_PD_CA57_SCU 12
+#define R8A7796_PD_CR7 13
+#define R8A7796_PD_A3VC 14
+#define R8A7796_PD_3DG_A 17
+#define R8A7796_PD_3DG_B 18
+#define R8A7796_PD_CA53_SCU 21
+#define R8A7796_PD_A3IR 24
+#define R8A7796_PD_A2VC0 25
+#define R8A7796_PD_A2VC1 26
+
+/* Always-on power area */
+#define R8A7796_PD_ALWAYS_ON 32
+
+#endif /* __DT_BINDINGS_POWER_R8A7796_SYSC_H__ */
--- /dev/null
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright (c) 2016 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * BSD LICENSE
+ *
+ * Copyright (c) 2016 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _DT_BINDINGS_AMLOGIC_MESON_GXBB_RESET_H
+#define _DT_BINDINGS_AMLOGIC_MESON_GXBB_RESET_H
+
+/* RESET0 */
+#define RESET_HIU 0
+/* 1 */
+#define RESET_DOS_RESET 2
+#define RESET_DDR_TOP 3
+#define RESET_DCU_RESET 4
+#define RESET_VIU 5
+#define RESET_AIU 6
+#define RESET_VID_PLL_DIV 7
+/* 8 */
+#define RESET_PMUX 9
+#define RESET_VENC 10
+#define RESET_ASSIST 11
+#define RESET_AFIFO2 12
+#define RESET_VCBUS 13
+/* 14 */
+/* 15 */
+#define RESET_GIC 16
+#define RESET_CAPB3_DECODE 17
+#define RESET_NAND_CAPB3 18
+#define RESET_HDMITX_CAPB3 19
+#define RESET_MALI_CAPB3 20
+#define RESET_DOS_CAPB3 21
+#define RESET_SYS_CPU_CAPB3 22
+#define RESET_CBUS_CAPB3 23
+#define RESET_AHB_CNTL 24
+#define RESET_AHB_DATA 25
+#define RESET_VCBUS_CLK81 26
+#define RESET_MMC 27
+#define RESET_MIPI_0 28
+#define RESET_MIPI_1 29
+#define RESET_MIPI_2 30
+#define RESET_MIPI_3 31
+/* RESET1 */
+#define RESET_CPPM 32
+#define RESET_DEMUX 33
+#define RESET_USB_OTG 34
+#define RESET_DDR 35
+#define RESET_AO_RESET 36
+#define RESET_BT656 37
+#define RESET_AHB_SRAM 38
+/* 39 */
+#define RESET_PARSER 40
+#define RESET_BLKMV 41
+#define RESET_ISA 42
+#define RESET_ETHERNET 43
+#define RESET_SD_EMMC_A 44
+#define RESET_SD_EMMC_B 45
+#define RESET_SD_EMMC_C 46
+#define RESET_ROM_BOOT 47
+#define RESET_SYS_CPU_0 48
+#define RESET_SYS_CPU_1 49
+#define RESET_SYS_CPU_2 50
+#define RESET_SYS_CPU_3 51
+#define RESET_SYS_CPU_CORE_0 52
+#define RESET_SYS_CPU_CORE_1 53
+#define RESET_SYS_CPU_CORE_2 54
+#define RESET_SYS_CPU_CORE_3 55
+#define RESET_SYS_PLL_DIV 56
+#define RESET_SYS_CPU_AXI 57
+#define RESET_SYS_CPU_L2 58
+#define RESET_SYS_CPU_P 59
+#define RESET_SYS_CPU_MBIST 60
+/* 61 */
+/* 62 */
+/* 63 */
+/* RESET2 */
+#define RESET_VD_RMEM 64
+#define RESET_AUDIN 65
+#define RESET_HDMI_TX 66
+/* 67 */
+/* 68 */
+/* 69 */
+#define RESET_GE2D 70
+#define RESET_PARSER_REG 71
+#define RESET_PARSER_FETCH 72
+#define RESET_PARSER_CTL 73
+#define RESET_PARSER_TOP 74
+/* 75 */
+/* 76 */
+#define RESET_AO_CPU_RESET 77
+#define RESET_MALI 78
+#define RESET_HDMI_SYSTEM_RESET 79
+/* 80-95 */
+/* RESET3 */
+#define RESET_RING_OSCILLATOR 96
+#define RESET_SYS_CPU 97
+#define RESET_EFUSE 98
+#define RESET_SYS_CPU_BVCI 99
+#define RESET_AIFIFO 100
+#define RESET_TVFE 101
+#define RESET_AHB_BRIDGE_CNTL 102
+/* 103 */
+#define RESET_AUDIO_DAC 104
+#define RESET_DEMUX_TOP 105
+#define RESET_DEMUX_DES 106
+#define RESET_DEMUX_S2P_0 107
+#define RESET_DEMUX_S2P_1 108
+#define RESET_DEMUX_RESET_0 109
+#define RESET_DEMUX_RESET_1 110
+#define RESET_DEMUX_RESET_2 111
+/* 112-127 */
+/* RESET4 */
+/* 128 */
+/* 129 */
+/* 130 */
+/* 131 */
+#define RESET_DVIN_RESET 132
+#define RESET_RDMA 133
+#define RESET_VENCI 134
+#define RESET_VENCP 135
+/* 136 */
+#define RESET_VDAC 137
+#define RESET_RTC 138
+/* 139 */
+#define RESET_VDI6 140
+#define RESET_VENCL 141
+#define RESET_I2C_MASTER_2 142
+#define RESET_I2C_MASTER_1 143
+/* 144-159 */
+/* RESET5 */
+/* 160-191 */
+/* RESET6 */
+#define RESET_PERIPHS_GENERAL 192
+#define RESET_PERIPHS_SPICC 193
+#define RESET_PERIPHS_SMART_CARD 194
+#define RESET_PERIPHS_SAR_ADC 195
+#define RESET_PERIPHS_I2C_MASTER_0 196
+#define RESET_SANA 197
+/* 198 */
+#define RESET_PERIPHS_STREAM_INTERFACE 199
+#define RESET_PERIPHS_SDIO 200
+#define RESET_PERIPHS_UART_0 201
+#define RESET_PERIPHS_UART_1_2 202
+#define RESET_PERIPHS_ASYNC_0 203
+#define RESET_PERIPHS_ASYNC_1 204
+#define RESET_PERIPHS_SPI_0 205
+#define RESET_PERIPHS_SDHC 206
+#define RESET_UART_SLIP 207
+/* 208-223 */
+/* RESET7 */
+#define RESET_USB_DDR_0 224
+#define RESET_USB_DDR_1 225
+#define RESET_USB_DDR_2 226
+#define RESET_USB_DDR_3 227
+/* 228 */
+#define RESET_DEVICE_MMC_ARB 229
+/* 230 */
+#define RESET_VID_LOCK 231
+#define RESET_A9_DMC_PIPEL 232
+/* 233-255 */
+
+#endif
--- /dev/null
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright (c) 2016 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * BSD LICENSE
+ *
+ * Copyright (c) 2016 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _DT_BINDINGS_AMLOGIC_MESON8B_RESET_H
+#define _DT_BINDINGS_AMLOGIC_MESON8B_RESET_H
+
+/* RESET0 */
+#define RESET_HIU 0
+#define RESET_VLD 1
+#define RESET_IQIDCT 2
+#define RESET_MC 3
+/* 8 */
+#define RESET_VIU 5
+#define RESET_AIU 6
+#define RESET_MCPU 7
+#define RESET_CCPU 8
+#define RESET_PMUX 9
+#define RESET_VENC 10
+#define RESET_ASSIST 11
+#define RESET_AFIFO2 12
+#define RESET_MDEC 13
+#define RESET_VLD_PART 14
+#define RESET_VIFIFO 15
+/* 16-31 */
+/* RESET1 */
+/* 32 */
+#define RESET_DEMUX 33
+#define RESET_USB_OTG 34
+#define RESET_DDR 35
+#define RESET_VDAC_1 36
+#define RESET_BT656 37
+#define RESET_AHB_SRAM 38
+#define RESET_AHB_BRIDGE 39
+#define RESET_PARSER 40
+#define RESET_BLKMV 41
+#define RESET_ISA 42
+#define RESET_ETHERNET 43
+#define RESET_ABUF 44
+#define RESET_AHB_DATA 45
+#define RESET_AHB_CNTL 46
+#define RESET_ROM_BOOT 47
+/* 48-63 */
+/* RESET2 */
+#define RESET_VD_RMEM 64
+#define RESET_AUDIN 65
+#define RESET_DBLK 66
+#define RESET_PIC_DC 66
+#define RESET_PSC 66
+#define RESET_NAND 66
+#define RESET_GE2D 70
+#define RESET_PARSER_REG 71
+#define RESET_PARSER_FETCH 72
+#define RESET_PARSER_CTL 73
+#define RESET_PARSER_TOP 74
+#define RESET_HDMI_APB 75
+#define RESET_AUDIO_APB 76
+#define RESET_MEDIA_CPU 77
+#define RESET_MALI 78
+#define RESET_HDMI_SYSTEM_RESET 79
+/* 80-95 */
+/* RESET3 */
+#define RESET_RING_OSCILLATOR 96
+#define RESET_SYS_CPU_0 97
+#define RESET_EFUSE 98
+#define RESET_SYS_CPU_BVCI 99
+#define RESET_AIFIFO 100
+#define RESET_AUDIO_PLL_MODULATOR 101
+#define RESET_AHB_BRIDGE_CNTL 102
+#define RESET_SYS_CPU_1 103
+#define RESET_AUDIO_DAC 104
+#define RESET_DEMUX_TOP 105
+#define RESET_DEMUX_DES 106
+#define RESET_DEMUX_S2P_0 107
+#define RESET_DEMUX_S2P_1 108
+#define RESET_DEMUX_RESET_0 109
+#define RESET_DEMUX_RESET_1 110
+#define RESET_DEMUX_RESET_2 111
+/* 112-127 */
+/* RESET4 */
+#define RESET_PL310 128
+#define RESET_A5_APB 129
+#define RESET_A5_AXI 130
+#define RESET_A5 131
+#define RESET_DVIN 132
+#define RESET_RDMA 133
+#define RESET_VENCI 134
+#define RESET_VENCP 135
+#define RESET_VENCT 136
+#define RESET_VDAC_4 137
+#define RESET_RTC 138
+#define RESET_A5_DEBUG 139
+#define RESET_VDI6 140
+#define RESET_VENCL 141
+/* 142-159 */
+/* RESET5 */
+#define RESET_DDR_PLL 160
+#define RESET_MISC_PLL 161
+#define RESET_SYS_PLL 162
+#define RESET_HPLL_PLL 163
+#define RESET_AUDIO_PLL 164
+#define RESET_VID2_PLL 165
+/* 166-191 */
+/* RESET6 */
+#define RESET_PERIPHS_GENERAL 192
+#define RESET_PERIPHS_IR_REMOTE 193
+#define RESET_PERIPHS_SMART_CARD 194
+#define RESET_PERIPHS_SAR_ADC 195
+#define RESET_PERIPHS_I2C_MASTER_0 196
+#define RESET_PERIPHS_I2C_MASTER_1 197
+#define RESET_PERIPHS_I2C_SLAVE 198
+#define RESET_PERIPHS_STREAM_INTERFACE 199
+#define RESET_PERIPHS_SDIO 200
+#define RESET_PERIPHS_UART_0 201
+#define RESET_PERIPHS_UART_1 202
+#define RESET_PERIPHS_ASYNC_0 203
+#define RESET_PERIPHS_ASYNC_1 204
+#define RESET_PERIPHS_SPI_0 205
+#define RESET_PERIPHS_SPI_1 206
+#define RESET_PERIPHS_LED_PWM 207
+/* 208-223 */
+/* RESET7 */
+/* 224-255 */
+
+#endif
#define PERIPH_RSDIST9_CARM_SOCDBG 0x507
#define PERIPH_RSDIST9_CARM_ETM 0x508
+#define MEDIA_G3D 0
+#define MEDIA_CODEC_VPU 2
+#define MEDIA_CODEC_JPEG 3
+#define MEDIA_ISP 4
+#define MEDIA_ADE 5
+#define MEDIA_MMU 6
+#define MEDIA_XG2RAM1 7
+
#endif /*_DT_BINDINGS_RESET_CONTROLLER_HI6220*/
--- /dev/null
+/*
+ * TI Syscon Reset definitions
+ *
+ * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DT_BINDINGS_RESET_TI_SYSCON_H__
+#define __DT_BINDINGS_RESET_TI_SYSCON_H__
+
+/*
+ * The reset does not support the feature and corresponding
+ * values are not valid
+ */
+#define ASSERT_NONE (1 << 0)
+#define DEASSERT_NONE (1 << 1)
+#define STATUS_NONE (1 << 2)
+
+/* When set this function is activated by setting(vs clearing) this bit */
+#define ASSERT_SET (1 << 3)
+#define DEASSERT_SET (1 << 4)
+#define STATUS_SET (1 << 5)
+
+/* The following are the inverse of the above and are added for consistency */
+#define ASSERT_CLEAR (0 << 3)
+#define DEASSERT_CLEAR (0 << 4)
+#define STATUS_CLEAR (0 << 5)
+
+#endif
return ab8500_sysctrl_write(reg, bits, 0);
}
-/* Configuration data for SysClkReq1RfClkBuf - SysClkReq8RfClkBuf */
-struct ab8500_sysctrl_platform_data {
- u8 initial_req_buf_config[8];
- u16 (*reboot_reason_code)(const char *cmd);
-};
-
/* Registers */
#define AB8500_TURNONSTATUS 0x100
#define AB8500_RESETSTATUS 0x101
#define DB8500_PRCMU_LEGACY_OFFSET 0xDD4
-struct prcmu_pdata
-{
- bool enable_set_ddr_opp;
- bool enable_ape_opp_100_voltage;
- struct ab8500_platform_data *ab_platdata;
- u32 version_offset;
- u32 legacy_offset;
- u32 adt_offset;
-};
-
#define PRCMU_FW_PROJECT_U8500 2
#define PRCMU_FW_PROJECT_U8400 3
#define PRCMU_FW_PROJECT_U9500 4 /* Customer specific */
#ifndef __OF_RESERVED_MEM_H
#define __OF_RESERVED_MEM_H
-struct device;
+#include <linux/device.h>
+
struct of_phandle_args;
struct reserved_mem_ops;
_OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn)
#ifdef CONFIG_OF_RESERVED_MEM
-int of_reserved_mem_device_init(struct device *dev);
+
+int of_reserved_mem_device_init_by_idx(struct device *dev,
+ struct device_node *np, int idx);
void of_reserved_mem_device_release(struct device *dev);
void fdt_init_reserved_mem(void);
void fdt_reserved_mem_save_node(unsigned long node, const char *uname,
phys_addr_t base, phys_addr_t size);
#else
-static inline int of_reserved_mem_device_init(struct device *dev)
+static inline int of_reserved_mem_device_init_by_idx(struct device *dev,
+ struct device_node *np, int idx)
{
return -ENOSYS;
}
const char *uname, phys_addr_t base, phys_addr_t size) { }
#endif
+/**
+ * of_reserved_mem_device_init() - assign reserved memory region to given device
+ * @dev: Pointer to the device to configure
+ *
+ * This function assigns respective DMA-mapping operations based on the first
+ * reserved memory region specified by 'memory-region' property in device tree
+ * node of the given device.
+ *
+ * Returns error code or zero on success.
+ */
+static inline int of_reserved_mem_device_init(struct device *dev)
+{
+ return of_reserved_mem_device_init_by_idx(dev, dev->of_node, 0);
+}
+
#endif /* __OF_RESERVED_MEM_H */
+++ /dev/null
-/*
- * Clock definitions for ux500 platforms
- *
- * Copyright (C) 2012 ST-Ericsson SA
- * Author: Ulf Hansson <ulf.hansson@linaro.org>
- *
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#ifndef __CLK_UX500_H
-#define __CLK_UX500_H
-
-void u8500_clk_init(void);
-void u9540_clk_init(void);
-void u8540_clk_init(void);
-
-#endif /* __CLK_UX500_H */
#define _LIRC_RX51_H
struct lirc_rx51_platform_data {
- int pwm_timer;
-
int(*set_max_mpu_wakeup_lat)(struct device *dev, long t);
- struct pwm_omap_dmtimer_pdata *dmtimer;
};
#endif
extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
u32 *resp);
+extern bool qcom_scm_pas_supported(u32 peripheral);
+extern int qcom_scm_pas_init_image(u32 peripheral, const void *metadata,
+ size_t size);
+extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr,
+ phys_addr_t size);
+extern int qcom_scm_pas_auth_and_reset(u32 peripheral);
+extern int qcom_scm_pas_shutdown(u32 peripheral);
+
#define QCOM_SCM_CPU_PWR_DOWN_L2_ON 0x0
#define QCOM_SCM_CPU_PWR_DOWN_L2_OFF 0x1
int reset_controller_register(struct reset_controller_dev *rcdev);
void reset_controller_unregister(struct reset_controller_dev *rcdev);
+struct device;
+int devm_reset_controller_register(struct device *dev,
+ struct reset_controller_dev *rcdev);
+
#endif
struct device_node *node,
const char *id, int index, int shared)
{
- return ERR_PTR(-EINVAL);
+ return ERR_PTR(-ENOTSUPP);
}
static inline struct reset_control *__devm_reset_control_get(
struct device *dev,
const char *id, int index, int shared)
{
- return ERR_PTR(-EINVAL);
+ return ERR_PTR(-ENOTSUPP);
}
#endif /* CONFIG_RESET_CONTROLLER */
/**
- * reset_control_get - Lookup and obtain an exclusive reference to a
- * reset controller.
+ * reset_control_get_exclusive - Lookup and obtain an exclusive reference
+ * to a reset controller.
* @dev: device to be reset by the controller
* @id: reset line name
*
*
* Use of id names is optional.
*/
-static inline struct reset_control *__must_check reset_control_get(
- struct device *dev, const char *id)
+static inline struct reset_control *
+__must_check reset_control_get_exclusive(struct device *dev, const char *id)
{
#ifndef CONFIG_RESET_CONTROLLER
WARN_ON(1);
return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 0);
}
-static inline struct reset_control *reset_control_get_optional(
- struct device *dev, const char *id)
-{
- return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 0);
-}
-
/**
* reset_control_get_shared - Lookup and obtain a shared reference to a
* reset controller.
return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 1);
}
+static inline struct reset_control *reset_control_get_optional_exclusive(
+ struct device *dev, const char *id)
+{
+ return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 0);
+}
+
+static inline struct reset_control *reset_control_get_optional_shared(
+ struct device *dev, const char *id)
+{
+ return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 1);
+}
+
/**
- * of_reset_control_get - Lookup and obtain an exclusive reference to a
- * reset controller.
+ * of_reset_control_get_exclusive - Lookup and obtain an exclusive reference
+ * to a reset controller.
* @node: device to be reset by the controller
* @id: reset line name
*
*
* Use of id names is optional.
*/
-static inline struct reset_control *of_reset_control_get(
+static inline struct reset_control *of_reset_control_get_exclusive(
struct device_node *node, const char *id)
{
return __of_reset_control_get(node, id, 0, 0);
}
/**
- * of_reset_control_get_by_index - Lookup and obtain an exclusive reference to
- * a reset controller by index.
+ * of_reset_control_get_shared - Lookup and obtain an shared reference
+ * to a reset controller.
+ * @node: device to be reset by the controller
+ * @id: reset line name
+ *
+ * When a reset-control is shared, the behavior of reset_control_assert /
+ * deassert is changed, the reset-core will keep track of a deassert_count
+ * and only (re-)assert the reset after reset_control_assert has been called
+ * as many times as reset_control_deassert was called. Also see the remark
+ * about shared reset-controls in the reset_control_assert docs.
+ *
+ * Calling reset_control_assert without first calling reset_control_deassert
+ * is not allowed on a shared reset control. Calling reset_control_reset is
+ * also not allowed on a shared reset control.
+ * Returns a struct reset_control or IS_ERR() condition containing errno.
+ *
+ * Use of id names is optional.
+ */
+static inline struct reset_control *of_reset_control_get_shared(
+ struct device_node *node, const char *id)
+{
+ return __of_reset_control_get(node, id, 0, 1);
+}
+
+/**
+ * of_reset_control_get_exclusive_by_index - Lookup and obtain an exclusive
+ * reference to a reset controller
+ * by index.
* @node: device to be reset by the controller
* @index: index of the reset controller
*
* in whatever order. Returns a struct reset_control or IS_ERR() condition
* containing errno.
*/
-static inline struct reset_control *of_reset_control_get_by_index(
+static inline struct reset_control *of_reset_control_get_exclusive_by_index(
struct device_node *node, int index)
{
return __of_reset_control_get(node, NULL, index, 0);
}
/**
- * devm_reset_control_get - resource managed reset_control_get()
- * @dev: device to be reset by the controller
- * @id: reset line name
+ * of_reset_control_get_shared_by_index - Lookup and obtain an shared
+ * reference to a reset controller
+ * by index.
+ * @node: device to be reset by the controller
+ * @index: index of the reset controller
+ *
+ * When a reset-control is shared, the behavior of reset_control_assert /
+ * deassert is changed, the reset-core will keep track of a deassert_count
+ * and only (re-)assert the reset after reset_control_assert has been called
+ * as many times as reset_control_deassert was called. Also see the remark
+ * about shared reset-controls in the reset_control_assert docs.
+ *
+ * Calling reset_control_assert without first calling reset_control_deassert
+ * is not allowed on a shared reset control. Calling reset_control_reset is
+ * also not allowed on a shared reset control.
+ * Returns a struct reset_control or IS_ERR() condition containing errno.
*
- * Managed reset_control_get(). For reset controllers returned from this
- * function, reset_control_put() is called automatically on driver detach.
- * See reset_control_get() for more information.
+ * This is to be used to perform a list of resets for a device or power domain
+ * in whatever order. Returns a struct reset_control or IS_ERR() condition
+ * containing errno.
*/
-static inline struct reset_control *__must_check devm_reset_control_get(
- struct device *dev, const char *id)
-{
-#ifndef CONFIG_RESET_CONTROLLER
- WARN_ON(1);
-#endif
- return __devm_reset_control_get(dev, id, 0, 0);
-}
-
-static inline struct reset_control *devm_reset_control_get_optional(
- struct device *dev, const char *id)
+static inline struct reset_control *of_reset_control_get_shared_by_index(
+ struct device_node *node, int index)
{
- return __devm_reset_control_get(dev, id, 0, 0);
+ return __of_reset_control_get(node, NULL, index, 1);
}
/**
- * devm_reset_control_get_by_index - resource managed reset_control_get
+ * devm_reset_control_get_exclusive - resource managed
+ * reset_control_get_exclusive()
* @dev: device to be reset by the controller
- * @index: index of the reset controller
+ * @id: reset line name
*
- * Managed reset_control_get(). For reset controllers returned from this
- * function, reset_control_put() is called automatically on driver detach.
- * See reset_control_get() for more information.
+ * Managed reset_control_get_exclusive(). For reset controllers returned
+ * from this function, reset_control_put() is called automatically on driver
+ * detach.
+ *
+ * See reset_control_get_exclusive() for more information.
*/
-static inline struct reset_control *devm_reset_control_get_by_index(
- struct device *dev, int index)
+static inline struct reset_control *
+__must_check devm_reset_control_get_exclusive(struct device *dev,
+ const char *id)
{
- return __devm_reset_control_get(dev, NULL, index, 0);
+#ifndef CONFIG_RESET_CONTROLLER
+ WARN_ON(1);
+#endif
+ return __devm_reset_control_get(dev, id, 0, 0);
}
/**
return __devm_reset_control_get(dev, id, 0, 1);
}
+static inline struct reset_control *devm_reset_control_get_optional_exclusive(
+ struct device *dev, const char *id)
+{
+ return __devm_reset_control_get(dev, id, 0, 0);
+}
+
+static inline struct reset_control *devm_reset_control_get_optional_shared(
+ struct device *dev, const char *id)
+{
+ return __devm_reset_control_get(dev, id, 0, 1);
+}
+
+/**
+ * devm_reset_control_get_exclusive_by_index - resource managed
+ * reset_control_get_exclusive()
+ * @dev: device to be reset by the controller
+ * @index: index of the reset controller
+ *
+ * Managed reset_control_get_exclusive(). For reset controllers returned from
+ * this function, reset_control_put() is called automatically on driver
+ * detach.
+ *
+ * See reset_control_get_exclusive() for more information.
+ */
+static inline struct reset_control *
+devm_reset_control_get_exclusive_by_index(struct device *dev, int index)
+{
+ return __devm_reset_control_get(dev, NULL, index, 0);
+}
+
/**
* devm_reset_control_get_shared_by_index - resource managed
* reset_control_get_shared
* this function, reset_control_put() is called automatically on driver detach.
* See reset_control_get_shared() for more information.
*/
-static inline struct reset_control *devm_reset_control_get_shared_by_index(
- struct device *dev, int index)
+static inline struct reset_control *
+devm_reset_control_get_shared_by_index(struct device *dev, int index)
{
return __devm_reset_control_get(dev, NULL, index, 1);
}
+/*
+ * TEMPORARY calls to use during transition:
+ *
+ * of_reset_control_get() => of_reset_control_get_exclusive()
+ *
+ * These inline function calls will be removed once all consumers
+ * have been moved over to the new explicit API.
+ */
+static inline struct reset_control *reset_control_get(
+ struct device *dev, const char *id)
+{
+ return reset_control_get_exclusive(dev, id);
+}
+
+static inline struct reset_control *reset_control_get_optional(
+ struct device *dev, const char *id)
+{
+ return reset_control_get_optional_exclusive(dev, id);
+}
+
+static inline struct reset_control *of_reset_control_get(
+ struct device_node *node, const char *id)
+{
+ return of_reset_control_get_exclusive(node, id);
+}
+
+static inline struct reset_control *of_reset_control_get_by_index(
+ struct device_node *node, int index)
+{
+ return of_reset_control_get_exclusive_by_index(node, index);
+}
+
+static inline struct reset_control *devm_reset_control_get(
+ struct device *dev, const char *id)
+{
+ return devm_reset_control_get_exclusive(dev, id);
+}
+
+static inline struct reset_control *devm_reset_control_get_optional(
+ struct device *dev, const char *id)
+{
+ return devm_reset_control_get_optional_exclusive(dev, id);
+
+}
+
+static inline struct reset_control *devm_reset_control_get_by_index(
+ struct device *dev, int index)
+{
+ return devm_reset_control_get_exclusive_by_index(dev, index);
+}
#endif
int (*sensor_get_capability)(u16 *sensors);
int (*sensor_get_info)(u16 sensor_id, struct scpi_sensor_info *);
int (*sensor_get_value)(u16, u64 *);
+ int (*device_get_power_state)(u16);
+ int (*device_set_power_state)(u16, u8);
};
#if IS_REACHABLE(CONFIG_ARM_SCPI_PROTOCOL)
--- /dev/null
+#ifndef __WCNSS_CTRL_H__
+#define __WCNSS_CTRL_H__
+
+#include <linux/soc/qcom/smd.h>
+
+struct qcom_smd_channel *qcom_wcnss_open_channel(void *wcnss, const char *name, qcom_smd_cb_t cb);
+
+#endif
int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch);
int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch);
-void __iomem *rcar_sysc_init(phys_addr_t base);
+void rcar_sysc_init(phys_addr_t base, u32 syscier);
#endif /* __LINUX_SOC_RENESAS_RCAR_SYSC_H__ */
}
void vb2_dma_contig_cleanup_ctx(void *alloc_ctx);
+int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size);
+void vb2_dma_contig_clear_max_seg_size(struct device *dev);
extern const struct vb2_mem_ops vb2_dma_contig_memops;
#ifndef __SOC_TEGRA_CPUIDLE_H__
#define __SOC_TEGRA_CPUIDLE_H__
-#ifdef CONFIG_CPU_IDLE
+#if defined(CONFIG_ARM) && defined(CONFIG_CPU_IDLE)
void tegra_cpuidle_pcie_irqs_in_use(void);
#else
static inline void tegra_cpuidle_pcie_irqs_in_use(void)
struct device *dev = codec->dev;
struct device_node *np = dev->of_node;
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
- struct ab8500_platform_data *pdata;
+ struct ab8500_codec_platform_data codec_pdata;
struct filter_control *fc;
int status;
dev_dbg(dev, "%s: Enter.\n", __func__);
- /* Setup AB8500 according to board-settings */
- pdata = dev_get_platdata(dev->parent);
+ ab8500_codec_of_probe(dev, np, &codec_pdata);
- if (np) {
- if (!pdata)
- pdata = devm_kzalloc(dev,
- sizeof(struct ab8500_platform_data),
- GFP_KERNEL);
-
- if (pdata && !pdata->codec)
- pdata->codec
- = devm_kzalloc(dev,
- sizeof(struct ab8500_codec_platform_data),
- GFP_KERNEL);
-
- if (!(pdata && pdata->codec))
- return -ENOMEM;
-
- ab8500_codec_of_probe(dev, np, pdata->codec);
-
- } else {
- if (!(pdata && pdata->codec)) {
- dev_err(dev, "No codec platform data or DT found\n");
- return -EINVAL;
- }
- }
-
- status = ab8500_audio_setup_mics(codec, &pdata->codec->amics);
+ status = ab8500_audio_setup_mics(codec, &codec_pdata.amics);
if (status < 0) {
pr_err("%s: Failed to setup mics (%d)!\n", __func__, status);
return status;
}
- status = ab8500_audio_set_ear_cmv(codec, pdata->codec->ear_cmv);
+ status = ab8500_audio_set_ear_cmv(codec, codec_pdata.ear_cmv);
if (status < 0) {
pr_err("%s: Failed to set earpiece CM-voltage (%d)!\n",
__func__, status);