Merge branch 'vexpress-clk-soc' of git://git.linaro.org/people/pawelmoll/linux into next/soc
From Pawel Moll: * 'vexpress-clk-soc' of git://git.linaro.org/people/pawelmoll/linux: ARM: vexpress: Remove motherboard dependencies in the DTS files ARM: vexpress: Start using new Versatile Express infrastructure ARM: vexpress: Add config bus components and clocks to DTs mfd: Versatile Express system registers driver mfd: Versatile Express config infrastructure
This commit is contained in:
commit
06f31cb0f6
50
Documentation/devicetree/bindings/arm/vexpress-sysreg.txt
Normal file
50
Documentation/devicetree/bindings/arm/vexpress-sysreg.txt
Normal file
@ -0,0 +1,50 @@
|
||||
ARM Versatile Express system registers
|
||||
--------------------------------------
|
||||
|
||||
This is a system control registers block, providing multiple low level
|
||||
platform functions like board detection and identification, software
|
||||
interrupt generation, MMC and NOR Flash control etc.
|
||||
|
||||
Required node properties:
|
||||
- compatible value : = "arm,vexpress,sysreg";
|
||||
- reg : physical base address and the size of the registers window
|
||||
- gpio-controller : specifies that the node is a GPIO controller
|
||||
- #gpio-cells : size of the GPIO specifier, should be 2:
|
||||
- first cell is the pseudo-GPIO line number:
|
||||
0 - MMC CARDIN
|
||||
1 - MMC WPROT
|
||||
2 - NOR FLASH WPn
|
||||
- second cell can take standard GPIO flags (currently ignored).
|
||||
|
||||
Example:
|
||||
v2m_sysreg: sysreg@10000000 {
|
||||
compatible = "arm,vexpress-sysreg";
|
||||
reg = <0x10000000 0x1000>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
This block also can also act a bridge to the platform's configuration
|
||||
bus via "system control" interface, addressing devices with site number,
|
||||
position in the board stack, config controller, function and device
|
||||
numbers - see motherboard's TRM for more details.
|
||||
|
||||
The node describing a config device must refer to the sysreg node via
|
||||
"arm,vexpress,config-bridge" phandle (can be also defined in the node's
|
||||
parent) and relies on the board topology properties - see main vexpress
|
||||
node documentation for more details. It must must also define the
|
||||
following property:
|
||||
- arm,vexpress-sysreg,func : must contain two cells:
|
||||
- first cell defines function number (eg. 1 for clock generator,
|
||||
2 for voltage regulators etc.)
|
||||
- device number (eg. osc 0, osc 1 etc.)
|
||||
|
||||
Example:
|
||||
mcc {
|
||||
arm,vexpress,config-bridge = <&v2m_sysreg>;
|
||||
|
||||
osc@0 {
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 0>;
|
||||
};
|
||||
};
|
@ -11,6 +11,10 @@ the motherboard file using a /include/ directive. As the motherboard
|
||||
can be initialized in one of two different configurations ("memory
|
||||
maps"), care must be taken to include the correct one.
|
||||
|
||||
|
||||
Root node
|
||||
---------
|
||||
|
||||
Required properties in the root node:
|
||||
- compatible value:
|
||||
compatible = "arm,vexpress,<model>", "arm,vexpress";
|
||||
@ -45,6 +49,10 @@ Optional properties in the root node:
|
||||
- Coretile Express A9x4 (V2P-CA9) HBI-0225:
|
||||
arm,hbi = <0x225>;
|
||||
|
||||
|
||||
CPU nodes
|
||||
---------
|
||||
|
||||
Top-level standard "cpus" node is required. It must contain a node
|
||||
with device_type = "cpu" property for every available core, eg.:
|
||||
|
||||
@ -59,6 +67,52 @@ with device_type = "cpu" property for every available core, eg.:
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Configuration infrastructure
|
||||
----------------------------
|
||||
|
||||
The platform has an elaborated configuration system, consisting of
|
||||
microcontrollers residing on the mother- and daughterboards known
|
||||
as Motherboard/Daughterboard Configuration Controller (MCC and DCC).
|
||||
The controllers are responsible for the platform initialization
|
||||
(reset generation, flash programming, FPGA bitfiles loading etc.)
|
||||
but also control clock generators, voltage regulators, gather
|
||||
environmental data like temperature, power consumption etc. Even
|
||||
the video output switch (FPGA) is controlled that way.
|
||||
|
||||
Nodes describing devices controlled by this infrastructure should
|
||||
point at the bridge device node:
|
||||
- bridge phandle:
|
||||
arm,vexpress,config-bridge = <phandle>;
|
||||
This property can be also defined in a parent node (eg. for a DCC)
|
||||
and is effective for all children.
|
||||
|
||||
|
||||
Platform topology
|
||||
-----------------
|
||||
|
||||
As Versatile Express can be configured in number of physically
|
||||
different setups, the device tree should describe platform topology.
|
||||
Root node and main motherboard node must define the following
|
||||
property, describing physical location of the children nodes:
|
||||
- site number:
|
||||
arm,vexpress,site = <number>;
|
||||
where 0 means motherboard, 1 or 2 are daugtherboard sites,
|
||||
0xf means "master" site (site containing main CPU tile)
|
||||
- when daughterboards are stacked on one site, their position
|
||||
in the stack be be described with:
|
||||
arm,vexpress,position = <number>;
|
||||
- when describing tiles consisting more than one DCC, its number
|
||||
can be described with:
|
||||
arm,vexpress,dcc = <number>;
|
||||
|
||||
Any of the numbers above defaults to zero if not defined in
|
||||
the node or any of its parent.
|
||||
|
||||
|
||||
Motherboard
|
||||
-----------
|
||||
|
||||
The motherboard description file provides a single "motherboard" node
|
||||
using 2 address cells corresponding to the Static Memory Bus used
|
||||
between the motherboard and the tile. The first cell defines the Chip
|
||||
@ -87,22 +141,30 @@ can be used to obtain required phandle in the tile's "aliases" node:
|
||||
- SP804 timers:
|
||||
v2m_timer01 and v2m_timer23
|
||||
|
||||
Current Linux implementation requires a "arm,v2m_timer" alias
|
||||
pointing at one of the motherboard's SP804 timers, if it is to be
|
||||
used as the system timer. This alias should be defined in the
|
||||
motherboard files.
|
||||
The tile description should define a "smb" node, describing the
|
||||
Static Memory Bus between the tile and motherboard. It must define
|
||||
the following properties:
|
||||
- "simple-bus" compatible value (to ensure creation of the children)
|
||||
compatible = "simple-bus";
|
||||
- mapping of the SMB CS/offset addresses into main address space:
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
ranges = <...>;
|
||||
- interrupts mapping:
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 63>;
|
||||
interrupt-map = <...>;
|
||||
|
||||
The tile description must define "ranges", "interrupt-map-mask" and
|
||||
"interrupt-map" properties to translate the motherboard's address
|
||||
and interrupt space into one used by the tile's processor.
|
||||
|
||||
Abbreviated example:
|
||||
Example of a VE tile description (simplified)
|
||||
---------------------------------------------
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
model = "V2P-CA5s";
|
||||
arm,hbi = <0x225>;
|
||||
arm,vexpress,site = <0xf>;
|
||||
compatible = "arm,vexpress-v2p-ca5s", "arm,vexpress";
|
||||
interrupt-parent = <&gic>;
|
||||
#address-cells = <1>;
|
||||
@ -134,13 +196,29 @@ Abbreviated example:
|
||||
<0x2c000100 0x100>;
|
||||
};
|
||||
|
||||
motherboard {
|
||||
dcc {
|
||||
compatible = "simple-bus";
|
||||
arm,vexpress,config-bridge = <&v2m_sysreg>;
|
||||
|
||||
osc@0 {
|
||||
compatible = "arm,vexpress-osc";
|
||||
};
|
||||
};
|
||||
|
||||
smb {
|
||||
compatible = "simple-bus";
|
||||
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
/* CS0 is visible at 0x08000000 */
|
||||
ranges = <0 0 0x08000000 0x04000000>;
|
||||
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 63>;
|
||||
/* Active high IRQ 0 is connected to GIC's SPI0 */
|
||||
interrupt-map = <0 0 0 &gic 0 0 4>;
|
||||
|
||||
/include/ "vexpress-v2m-rs1.dtsi"
|
||||
};
|
||||
};
|
||||
|
||||
/include/ "vexpress-v2m-rs1.dtsi"
|
||||
|
@ -17,17 +17,16 @@
|
||||
* CHANGES TO vexpress-v2m.dtsi!
|
||||
*/
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
arm,v2m_timer = &v2m_timer01;
|
||||
};
|
||||
|
||||
motherboard {
|
||||
compatible = "simple-bus";
|
||||
model = "V2M-P1";
|
||||
arm,hbi = <0x190>;
|
||||
arm,vexpress,site = <0>;
|
||||
arm,v2m-memory-map = "rs1";
|
||||
compatible = "arm,vexpress,v2m-p1", "simple-bus";
|
||||
#address-cells = <2>; /* SMB chipselect number and offset */
|
||||
#size-cells = <1>;
|
||||
#interrupt-cells = <1>;
|
||||
ranges;
|
||||
|
||||
flash@0,00000000 {
|
||||
compatible = "arm,vexpress-flash", "cfi-flash";
|
||||
@ -72,14 +71,20 @@
|
||||
#size-cells = <1>;
|
||||
ranges = <0 3 0 0x200000>;
|
||||
|
||||
sysreg@010000 {
|
||||
v2m_sysreg: sysreg@010000 {
|
||||
compatible = "arm,vexpress-sysreg";
|
||||
reg = <0x010000 0x1000>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
sysctl@020000 {
|
||||
v2m_sysctl: sysctl@020000 {
|
||||
compatible = "arm,sp810", "arm,primecell";
|
||||
reg = <0x020000 0x1000>;
|
||||
clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&smbclk>;
|
||||
clock-names = "refclk", "timclk", "apb_pclk";
|
||||
#clock-cells = <1>;
|
||||
clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
|
||||
};
|
||||
|
||||
/* PCI-E I2C bus */
|
||||
@ -100,66 +105,92 @@
|
||||
compatible = "arm,pl041", "arm,primecell";
|
||||
reg = <0x040000 0x1000>;
|
||||
interrupts = <11>;
|
||||
clocks = <&smbclk>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
mmci@050000 {
|
||||
compatible = "arm,pl180", "arm,primecell";
|
||||
reg = <0x050000 0x1000>;
|
||||
interrupts = <9 10>;
|
||||
cd-gpios = <&v2m_sysreg 0 0>;
|
||||
wp-gpios = <&v2m_sysreg 1 0>;
|
||||
max-frequency = <12000000>;
|
||||
vmmc-supply = <&v2m_fixed_3v3>;
|
||||
clocks = <&v2m_clk24mhz>, <&smbclk>;
|
||||
clock-names = "mclk", "apb_pclk";
|
||||
};
|
||||
|
||||
kmi@060000 {
|
||||
compatible = "arm,pl050", "arm,primecell";
|
||||
reg = <0x060000 0x1000>;
|
||||
interrupts = <12>;
|
||||
clocks = <&v2m_clk24mhz>, <&smbclk>;
|
||||
clock-names = "KMIREFCLK", "apb_pclk";
|
||||
};
|
||||
|
||||
kmi@070000 {
|
||||
compatible = "arm,pl050", "arm,primecell";
|
||||
reg = <0x070000 0x1000>;
|
||||
interrupts = <13>;
|
||||
clocks = <&v2m_clk24mhz>, <&smbclk>;
|
||||
clock-names = "KMIREFCLK", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_serial0: uart@090000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x090000 0x1000>;
|
||||
interrupts = <5>;
|
||||
clocks = <&v2m_oscclk2>, <&smbclk>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_serial1: uart@0a0000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x0a0000 0x1000>;
|
||||
interrupts = <6>;
|
||||
clocks = <&v2m_oscclk2>, <&smbclk>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_serial2: uart@0b0000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x0b0000 0x1000>;
|
||||
interrupts = <7>;
|
||||
clocks = <&v2m_oscclk2>, <&smbclk>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_serial3: uart@0c0000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x0c0000 0x1000>;
|
||||
interrupts = <8>;
|
||||
clocks = <&v2m_oscclk2>, <&smbclk>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
wdt@0f0000 {
|
||||
compatible = "arm,sp805", "arm,primecell";
|
||||
reg = <0x0f0000 0x1000>;
|
||||
interrupts = <0>;
|
||||
clocks = <&v2m_refclk32khz>, <&smbclk>;
|
||||
clock-names = "wdogclk", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_timer01: timer@110000 {
|
||||
compatible = "arm,sp804", "arm,primecell";
|
||||
reg = <0x110000 0x1000>;
|
||||
interrupts = <2>;
|
||||
clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&smbclk>;
|
||||
clock-names = "timclken1", "timclken2", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_timer23: timer@120000 {
|
||||
compatible = "arm,sp804", "arm,primecell";
|
||||
reg = <0x120000 0x1000>;
|
||||
interrupts = <3>;
|
||||
clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&smbclk>;
|
||||
clock-names = "timclken1", "timclken2", "apb_pclk";
|
||||
};
|
||||
|
||||
/* DVI I2C bus */
|
||||
@ -185,6 +216,8 @@
|
||||
compatible = "arm,pl031", "arm,primecell";
|
||||
reg = <0x170000 0x1000>;
|
||||
interrupts = <4>;
|
||||
clocks = <&smbclk>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
compact-flash@1a0000 {
|
||||
@ -198,6 +231,8 @@
|
||||
compatible = "arm,pl111", "arm,primecell";
|
||||
reg = <0x1f0000 0x1000>;
|
||||
interrupts = <14>;
|
||||
clocks = <&v2m_oscclk1>, <&smbclk>;
|
||||
clock-names = "clcdclk", "apb_pclk";
|
||||
};
|
||||
};
|
||||
|
||||
@ -208,5 +243,98 @@
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
v2m_clk24mhz: clk24mhz {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <24000000>;
|
||||
clock-output-names = "v2m:clk24mhz";
|
||||
};
|
||||
|
||||
v2m_refclk1mhz: refclk1mhz {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <1000000>;
|
||||
clock-output-names = "v2m:refclk1mhz";
|
||||
};
|
||||
|
||||
v2m_refclk32khz: refclk32khz {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
clock-output-names = "v2m:refclk32khz";
|
||||
};
|
||||
|
||||
mcc {
|
||||
compatible = "arm,vexpress,config-bus";
|
||||
arm,vexpress,config-bridge = <&v2m_sysreg>;
|
||||
|
||||
osc@0 {
|
||||
/* MCC static memory clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 0>;
|
||||
freq-range = <25000000 60000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "v2m:oscclk0";
|
||||
};
|
||||
|
||||
v2m_oscclk1: osc@1 {
|
||||
/* CLCD clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 1>;
|
||||
freq-range = <23750000 63500000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "v2m:oscclk1";
|
||||
};
|
||||
|
||||
v2m_oscclk2: osc@2 {
|
||||
/* IO FPGA peripheral clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 2>;
|
||||
freq-range = <24000000 24000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "v2m:oscclk2";
|
||||
};
|
||||
|
||||
volt@0 {
|
||||
/* Logic level voltage */
|
||||
compatible = "arm,vexpress-volt";
|
||||
arm,vexpress-sysreg,func = <2 0>;
|
||||
regulator-name = "VIO";
|
||||
regulator-always-on;
|
||||
label = "VIO";
|
||||
};
|
||||
|
||||
temp@0 {
|
||||
/* MCC internal operating temperature */
|
||||
compatible = "arm,vexpress-temp";
|
||||
arm,vexpress-sysreg,func = <4 0>;
|
||||
label = "MCC";
|
||||
};
|
||||
|
||||
reset@0 {
|
||||
compatible = "arm,vexpress-reset";
|
||||
arm,vexpress-sysreg,func = <5 0>;
|
||||
};
|
||||
|
||||
muxfpga@0 {
|
||||
compatible = "arm,vexpress-muxfpga";
|
||||
arm,vexpress-sysreg,func = <7 0>;
|
||||
};
|
||||
|
||||
shutdown@0 {
|
||||
compatible = "arm,vexpress-shutdown";
|
||||
arm,vexpress-sysreg,func = <8 0>;
|
||||
};
|
||||
|
||||
reboot@0 {
|
||||
compatible = "arm,vexpress-reboot";
|
||||
arm,vexpress-sysreg,func = <9 0>;
|
||||
};
|
||||
|
||||
dvimode@0 {
|
||||
compatible = "arm,vexpress-dvimode";
|
||||
arm,vexpress-sysreg,func = <11 0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -17,16 +17,15 @@
|
||||
* CHANGES TO vexpress-v2m-rs1.dtsi!
|
||||
*/
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
arm,v2m_timer = &v2m_timer01;
|
||||
};
|
||||
|
||||
motherboard {
|
||||
compatible = "simple-bus";
|
||||
model = "V2M-P1";
|
||||
arm,hbi = <0x190>;
|
||||
arm,vexpress,site = <0>;
|
||||
compatible = "arm,vexpress,v2m-p1", "simple-bus";
|
||||
#address-cells = <2>; /* SMB chipselect number and offset */
|
||||
#size-cells = <1>;
|
||||
#interrupt-cells = <1>;
|
||||
ranges;
|
||||
|
||||
flash@0,00000000 {
|
||||
compatible = "arm,vexpress-flash", "cfi-flash";
|
||||
@ -71,14 +70,20 @@
|
||||
#size-cells = <1>;
|
||||
ranges = <0 7 0 0x20000>;
|
||||
|
||||
sysreg@00000 {
|
||||
v2m_sysreg: sysreg@00000 {
|
||||
compatible = "arm,vexpress-sysreg";
|
||||
reg = <0x00000 0x1000>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
sysctl@01000 {
|
||||
v2m_sysctl: sysctl@01000 {
|
||||
compatible = "arm,sp810", "arm,primecell";
|
||||
reg = <0x01000 0x1000>;
|
||||
clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&smbclk>;
|
||||
clock-names = "refclk", "timclk", "apb_pclk";
|
||||
#clock-cells = <1>;
|
||||
clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
|
||||
};
|
||||
|
||||
/* PCI-E I2C bus */
|
||||
@ -99,66 +104,92 @@
|
||||
compatible = "arm,pl041", "arm,primecell";
|
||||
reg = <0x04000 0x1000>;
|
||||
interrupts = <11>;
|
||||
clocks = <&smbclk>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
mmci@05000 {
|
||||
compatible = "arm,pl180", "arm,primecell";
|
||||
reg = <0x05000 0x1000>;
|
||||
interrupts = <9 10>;
|
||||
cd-gpios = <&v2m_sysreg 0 0>;
|
||||
wp-gpios = <&v2m_sysreg 1 0>;
|
||||
max-frequency = <12000000>;
|
||||
vmmc-supply = <&v2m_fixed_3v3>;
|
||||
clocks = <&v2m_clk24mhz>, <&smbclk>;
|
||||
clock-names = "mclk", "apb_pclk";
|
||||
};
|
||||
|
||||
kmi@06000 {
|
||||
compatible = "arm,pl050", "arm,primecell";
|
||||
reg = <0x06000 0x1000>;
|
||||
interrupts = <12>;
|
||||
clocks = <&v2m_clk24mhz>, <&smbclk>;
|
||||
clock-names = "KMIREFCLK", "apb_pclk";
|
||||
};
|
||||
|
||||
kmi@07000 {
|
||||
compatible = "arm,pl050", "arm,primecell";
|
||||
reg = <0x07000 0x1000>;
|
||||
interrupts = <13>;
|
||||
clocks = <&v2m_clk24mhz>, <&smbclk>;
|
||||
clock-names = "KMIREFCLK", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_serial0: uart@09000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x09000 0x1000>;
|
||||
interrupts = <5>;
|
||||
clocks = <&v2m_oscclk2>, <&smbclk>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_serial1: uart@0a000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x0a000 0x1000>;
|
||||
interrupts = <6>;
|
||||
clocks = <&v2m_oscclk2>, <&smbclk>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_serial2: uart@0b000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x0b000 0x1000>;
|
||||
interrupts = <7>;
|
||||
clocks = <&v2m_oscclk2>, <&smbclk>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_serial3: uart@0c000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x0c000 0x1000>;
|
||||
interrupts = <8>;
|
||||
clocks = <&v2m_oscclk2>, <&smbclk>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
wdt@0f000 {
|
||||
compatible = "arm,sp805", "arm,primecell";
|
||||
reg = <0x0f000 0x1000>;
|
||||
interrupts = <0>;
|
||||
clocks = <&v2m_refclk32khz>, <&smbclk>;
|
||||
clock-names = "wdogclk", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_timer01: timer@11000 {
|
||||
compatible = "arm,sp804", "arm,primecell";
|
||||
reg = <0x11000 0x1000>;
|
||||
interrupts = <2>;
|
||||
clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&smbclk>;
|
||||
clock-names = "timclken1", "timclken2", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_timer23: timer@12000 {
|
||||
compatible = "arm,sp804", "arm,primecell";
|
||||
reg = <0x12000 0x1000>;
|
||||
interrupts = <3>;
|
||||
clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&smbclk>;
|
||||
clock-names = "timclken1", "timclken2", "apb_pclk";
|
||||
};
|
||||
|
||||
/* DVI I2C bus */
|
||||
@ -184,6 +215,8 @@
|
||||
compatible = "arm,pl031", "arm,primecell";
|
||||
reg = <0x17000 0x1000>;
|
||||
interrupts = <4>;
|
||||
clocks = <&smbclk>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
compact-flash@1a000 {
|
||||
@ -197,6 +230,8 @@
|
||||
compatible = "arm,pl111", "arm,primecell";
|
||||
reg = <0x1f000 0x1000>;
|
||||
interrupts = <14>;
|
||||
clocks = <&v2m_oscclk1>, <&smbclk>;
|
||||
clock-names = "clcdclk", "apb_pclk";
|
||||
};
|
||||
};
|
||||
|
||||
@ -207,5 +242,98 @@
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
v2m_clk24mhz: clk24mhz {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <24000000>;
|
||||
clock-output-names = "v2m:clk24mhz";
|
||||
};
|
||||
|
||||
v2m_refclk1mhz: refclk1mhz {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <1000000>;
|
||||
clock-output-names = "v2m:refclk1mhz";
|
||||
};
|
||||
|
||||
v2m_refclk32khz: refclk32khz {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
clock-output-names = "v2m:refclk32khz";
|
||||
};
|
||||
|
||||
mcc {
|
||||
compatible = "arm,vexpress,config-bus";
|
||||
arm,vexpress,config-bridge = <&v2m_sysreg>;
|
||||
|
||||
osc@0 {
|
||||
/* MCC static memory clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 0>;
|
||||
freq-range = <25000000 60000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "v2m:oscclk0";
|
||||
};
|
||||
|
||||
v2m_oscclk1: osc@1 {
|
||||
/* CLCD clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 1>;
|
||||
freq-range = <23750000 63500000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "v2m:oscclk1";
|
||||
};
|
||||
|
||||
v2m_oscclk2: osc@2 {
|
||||
/* IO FPGA peripheral clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 2>;
|
||||
freq-range = <24000000 24000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "v2m:oscclk2";
|
||||
};
|
||||
|
||||
volt@0 {
|
||||
/* Logic level voltage */
|
||||
compatible = "arm,vexpress-volt";
|
||||
arm,vexpress-sysreg,func = <2 0>;
|
||||
regulator-name = "VIO";
|
||||
regulator-always-on;
|
||||
label = "VIO";
|
||||
};
|
||||
|
||||
temp@0 {
|
||||
/* MCC internal operating temperature */
|
||||
compatible = "arm,vexpress-temp";
|
||||
arm,vexpress-sysreg,func = <4 0>;
|
||||
label = "MCC";
|
||||
};
|
||||
|
||||
reset@0 {
|
||||
compatible = "arm,vexpress-reset";
|
||||
arm,vexpress-sysreg,func = <5 0>;
|
||||
};
|
||||
|
||||
muxfpga@0 {
|
||||
compatible = "arm,vexpress-muxfpga";
|
||||
arm,vexpress-sysreg,func = <7 0>;
|
||||
};
|
||||
|
||||
shutdown@0 {
|
||||
compatible = "arm,vexpress-shutdown";
|
||||
arm,vexpress-sysreg,func = <8 0>;
|
||||
};
|
||||
|
||||
reboot@0 {
|
||||
compatible = "arm,vexpress-reboot";
|
||||
arm,vexpress-sysreg,func = <9 0>;
|
||||
};
|
||||
|
||||
dvimode@0 {
|
||||
compatible = "arm,vexpress-dvimode";
|
||||
arm,vexpress-sysreg,func = <11 0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -12,6 +12,7 @@
|
||||
/ {
|
||||
model = "V2P-CA15";
|
||||
arm,hbi = <0x237>;
|
||||
arm,vexpress,site = <0xf>;
|
||||
compatible = "arm,vexpress,v2p-ca15,tc1", "arm,vexpress,v2p-ca15", "arm,vexpress";
|
||||
interrupt-parent = <&gic>;
|
||||
#address-cells = <2>;
|
||||
@ -54,17 +55,24 @@
|
||||
compatible = "arm,hdlcd";
|
||||
reg = <0 0x2b000000 0 0x1000>;
|
||||
interrupts = <0 85 4>;
|
||||
clocks = <&oscclk5>;
|
||||
clock-names = "pxlclk";
|
||||
};
|
||||
|
||||
memory-controller@2b0a0000 {
|
||||
compatible = "arm,pl341", "arm,primecell";
|
||||
reg = <0 0x2b0a0000 0 0x1000>;
|
||||
clocks = <&oscclk7>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
wdt@2b060000 {
|
||||
compatible = "arm,sp805", "arm,primecell";
|
||||
status = "disabled";
|
||||
reg = <0 0x2b060000 0 0x1000>;
|
||||
interrupts = <98>;
|
||||
clocks = <&oscclk7>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
gic: interrupt-controller@2c001000 {
|
||||
@ -84,6 +92,8 @@
|
||||
reg = <0 0x7ffd0000 0 0x1000>;
|
||||
interrupts = <0 86 4>,
|
||||
<0 87 4>;
|
||||
clocks = <&oscclk7>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
dma@7ffb0000 {
|
||||
@ -94,6 +104,8 @@
|
||||
<0 89 4>,
|
||||
<0 90 4>,
|
||||
<0 91 4>;
|
||||
clocks = <&oscclk7>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
timer {
|
||||
@ -110,7 +122,109 @@
|
||||
<0 69 4>;
|
||||
};
|
||||
|
||||
motherboard {
|
||||
dcc {
|
||||
compatible = "arm,vexpress,config-bus";
|
||||
arm,vexpress,config-bridge = <&v2m_sysreg>;
|
||||
|
||||
osc@0 {
|
||||
/* CPU PLL reference clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 0>;
|
||||
freq-range = <50000000 60000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk0";
|
||||
};
|
||||
|
||||
osc@4 {
|
||||
/* Multiplexed AXI master clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 4>;
|
||||
freq-range = <20000000 40000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk4";
|
||||
};
|
||||
|
||||
oscclk5: osc@5 {
|
||||
/* HDLCD PLL reference clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 5>;
|
||||
freq-range = <23750000 165000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk5";
|
||||
};
|
||||
|
||||
smbclk: osc@6 {
|
||||
/* SMB clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 6>;
|
||||
freq-range = <20000000 50000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk6";
|
||||
};
|
||||
|
||||
oscclk7: osc@7 {
|
||||
/* SYS PLL reference clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 7>;
|
||||
freq-range = <20000000 60000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk7";
|
||||
};
|
||||
|
||||
osc@8 {
|
||||
/* DDR2 PLL reference clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 8>;
|
||||
freq-range = <40000000 40000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk8";
|
||||
};
|
||||
|
||||
volt@0 {
|
||||
/* CPU core voltage */
|
||||
compatible = "arm,vexpress-volt";
|
||||
arm,vexpress-sysreg,func = <2 0>;
|
||||
regulator-name = "Cores";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <1050000>;
|
||||
regulator-always-on;
|
||||
label = "Cores";
|
||||
};
|
||||
|
||||
amp@0 {
|
||||
/* Total current for the two cores */
|
||||
compatible = "arm,vexpress-amp";
|
||||
arm,vexpress-sysreg,func = <3 0>;
|
||||
label = "Cores";
|
||||
};
|
||||
|
||||
temp@0 {
|
||||
/* DCC internal temperature */
|
||||
compatible = "arm,vexpress-temp";
|
||||
arm,vexpress-sysreg,func = <4 0>;
|
||||
label = "DCC";
|
||||
};
|
||||
|
||||
power@0 {
|
||||
/* Total power */
|
||||
compatible = "arm,vexpress-power";
|
||||
arm,vexpress-sysreg,func = <12 0>;
|
||||
label = "Cores";
|
||||
};
|
||||
|
||||
energy@0 {
|
||||
/* Total energy */
|
||||
compatible = "arm,vexpress-energy";
|
||||
arm,vexpress-sysreg,func = <13 0>;
|
||||
label = "Cores";
|
||||
};
|
||||
};
|
||||
|
||||
smb {
|
||||
compatible = "simple-bus";
|
||||
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0 0 0 0x08000000 0x04000000>,
|
||||
<1 0 0 0x14000000 0x04000000>,
|
||||
<2 0 0 0x18000000 0x04000000>,
|
||||
@ -118,6 +232,7 @@
|
||||
<4 0 0 0x0c000000 0x04000000>,
|
||||
<5 0 0 0x10000000 0x04000000>;
|
||||
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 63>;
|
||||
interrupt-map = <0 0 0 &gic 0 0 4>,
|
||||
<0 0 1 &gic 0 1 4>,
|
||||
@ -162,7 +277,7 @@
|
||||
<0 0 40 &gic 0 40 4>,
|
||||
<0 0 41 &gic 0 41 4>,
|
||||
<0 0 42 &gic 0 42 4>;
|
||||
|
||||
/include/ "vexpress-v2m-rs1.dtsi"
|
||||
};
|
||||
};
|
||||
|
||||
/include/ "vexpress-v2m-rs1.dtsi"
|
||||
|
@ -12,6 +12,7 @@
|
||||
/ {
|
||||
model = "V2P-CA15_CA7";
|
||||
arm,hbi = <0x249>;
|
||||
arm,vexpress,site = <0xf>;
|
||||
compatible = "arm,vexpress,v2p-ca15_a7", "arm,vexpress";
|
||||
interrupt-parent = <&gic>;
|
||||
#address-cells = <2>;
|
||||
@ -74,17 +75,23 @@
|
||||
compatible = "arm,sp805", "arm,primecell";
|
||||
reg = <0 0x2a490000 0 0x1000>;
|
||||
interrupts = <98>;
|
||||
clocks = <&oscclk6a>, <&oscclk6a>;
|
||||
clock-names = "wdogclk", "apb_pclk";
|
||||
};
|
||||
|
||||
hdlcd@2b000000 {
|
||||
compatible = "arm,hdlcd";
|
||||
reg = <0 0x2b000000 0 0x1000>;
|
||||
interrupts = <0 85 4>;
|
||||
clocks = <&oscclk5>;
|
||||
clock-names = "pxlclk";
|
||||
};
|
||||
|
||||
memory-controller@2b0a0000 {
|
||||
compatible = "arm,pl341", "arm,primecell";
|
||||
reg = <0 0x2b0a0000 0 0x1000>;
|
||||
clocks = <&oscclk6a>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
gic: interrupt-controller@2c001000 {
|
||||
@ -104,6 +111,8 @@
|
||||
reg = <0 0x7ffd0000 0 0x1000>;
|
||||
interrupts = <0 86 4>,
|
||||
<0 87 4>;
|
||||
clocks = <&oscclk6a>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
dma@7ff00000 {
|
||||
@ -114,6 +123,8 @@
|
||||
<0 89 4>,
|
||||
<0 90 4>,
|
||||
<0 91 4>;
|
||||
clocks = <&oscclk6a>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
timer {
|
||||
@ -130,7 +141,175 @@
|
||||
<0 69 4>;
|
||||
};
|
||||
|
||||
motherboard {
|
||||
oscclk6a: oscclk6a {
|
||||
/* Reference 24MHz clock */
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <24000000>;
|
||||
clock-output-names = "oscclk6a";
|
||||
};
|
||||
|
||||
dcc {
|
||||
compatible = "arm,vexpress,config-bus";
|
||||
arm,vexpress,config-bridge = <&v2m_sysreg>;
|
||||
|
||||
osc@0 {
|
||||
/* A15 PLL 0 reference clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 0>;
|
||||
freq-range = <17000000 50000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk0";
|
||||
};
|
||||
|
||||
osc@1 {
|
||||
/* A15 PLL 1 reference clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 1>;
|
||||
freq-range = <17000000 50000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk1";
|
||||
};
|
||||
|
||||
osc@2 {
|
||||
/* A7 PLL 0 reference clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 2>;
|
||||
freq-range = <17000000 50000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk2";
|
||||
};
|
||||
|
||||
osc@3 {
|
||||
/* A7 PLL 1 reference clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 3>;
|
||||
freq-range = <17000000 50000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk3";
|
||||
};
|
||||
|
||||
osc@4 {
|
||||
/* External AXI master clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 4>;
|
||||
freq-range = <20000000 40000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk4";
|
||||
};
|
||||
|
||||
oscclk5: osc@5 {
|
||||
/* HDLCD PLL reference clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 5>;
|
||||
freq-range = <23750000 165000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk5";
|
||||
};
|
||||
|
||||
smbclk: osc@6 {
|
||||
/* Static memory controller clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 6>;
|
||||
freq-range = <20000000 40000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk6";
|
||||
};
|
||||
|
||||
osc@7 {
|
||||
/* SYS PLL reference clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 7>;
|
||||
freq-range = <17000000 50000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk7";
|
||||
};
|
||||
|
||||
osc@8 {
|
||||
/* DDR2 PLL reference clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 8>;
|
||||
freq-range = <20000000 50000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk8";
|
||||
};
|
||||
|
||||
volt@0 {
|
||||
/* A15 CPU core voltage */
|
||||
compatible = "arm,vexpress-volt";
|
||||
arm,vexpress-sysreg,func = <2 0>;
|
||||
regulator-name = "A15 Vcore";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <1050000>;
|
||||
regulator-always-on;
|
||||
label = "A15 Vcore";
|
||||
};
|
||||
|
||||
volt@1 {
|
||||
/* A7 CPU core voltage */
|
||||
compatible = "arm,vexpress-volt";
|
||||
arm,vexpress-sysreg,func = <2 1>;
|
||||
regulator-name = "A7 Vcore";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <1050000>;
|
||||
regulator-always-on;
|
||||
label = "A7 Vcore";
|
||||
};
|
||||
|
||||
amp@0 {
|
||||
/* Total current for the two A15 cores */
|
||||
compatible = "arm,vexpress-amp";
|
||||
arm,vexpress-sysreg,func = <3 0>;
|
||||
label = "A15 Icore";
|
||||
};
|
||||
|
||||
amp@1 {
|
||||
/* Total current for the three A7 cores */
|
||||
compatible = "arm,vexpress-amp";
|
||||
arm,vexpress-sysreg,func = <3 1>;
|
||||
label = "A7 Icore";
|
||||
};
|
||||
|
||||
temp@0 {
|
||||
/* DCC internal temperature */
|
||||
compatible = "arm,vexpress-temp";
|
||||
arm,vexpress-sysreg,func = <4 0>;
|
||||
label = "DCC";
|
||||
};
|
||||
|
||||
power@0 {
|
||||
/* Total power for the two A15 cores */
|
||||
compatible = "arm,vexpress-power";
|
||||
arm,vexpress-sysreg,func = <12 0>;
|
||||
label = "A15 Pcore";
|
||||
};
|
||||
power@1 {
|
||||
/* Total power for the three A7 cores */
|
||||
compatible = "arm,vexpress-power";
|
||||
arm,vexpress-sysreg,func = <12 1>;
|
||||
label = "A7 Pcore";
|
||||
};
|
||||
|
||||
energy@0 {
|
||||
/* Total energy for the two A15 cores */
|
||||
compatible = "arm,vexpress-energy";
|
||||
arm,vexpress-sysreg,func = <13 0>;
|
||||
label = "A15 Jcore";
|
||||
};
|
||||
|
||||
energy@2 {
|
||||
/* Total energy for the three A7 cores */
|
||||
compatible = "arm,vexpress-energy";
|
||||
arm,vexpress-sysreg,func = <13 2>;
|
||||
label = "A7 Jcore";
|
||||
};
|
||||
};
|
||||
|
||||
smb {
|
||||
compatible = "simple-bus";
|
||||
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0 0 0 0x08000000 0x04000000>,
|
||||
<1 0 0 0x14000000 0x04000000>,
|
||||
<2 0 0 0x18000000 0x04000000>,
|
||||
@ -138,6 +317,7 @@
|
||||
<4 0 0 0x0c000000 0x04000000>,
|
||||
<5 0 0 0x10000000 0x04000000>;
|
||||
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 63>;
|
||||
interrupt-map = <0 0 0 &gic 0 0 4>,
|
||||
<0 0 1 &gic 0 1 4>,
|
||||
@ -182,7 +362,7 @@
|
||||
<0 0 40 &gic 0 40 4>,
|
||||
<0 0 41 &gic 0 41 4>,
|
||||
<0 0 42 &gic 0 42 4>;
|
||||
|
||||
/include/ "vexpress-v2m-rs1.dtsi"
|
||||
};
|
||||
};
|
||||
|
||||
/include/ "vexpress-v2m-rs1.dtsi"
|
||||
|
@ -12,6 +12,7 @@
|
||||
/ {
|
||||
model = "V2P-CA5s";
|
||||
arm,hbi = <0x225>;
|
||||
arm,vexpress,site = <0xf>;
|
||||
compatible = "arm,vexpress,v2p-ca5s", "arm,vexpress";
|
||||
interrupt-parent = <&gic>;
|
||||
#address-cells = <1>;
|
||||
@ -56,11 +57,15 @@
|
||||
compatible = "arm,hdlcd";
|
||||
reg = <0x2a110000 0x1000>;
|
||||
interrupts = <0 85 4>;
|
||||
clocks = <&oscclk3>;
|
||||
clock-names = "pxlclk";
|
||||
};
|
||||
|
||||
memory-controller@2a150000 {
|
||||
compatible = "arm,pl341", "arm,primecell";
|
||||
reg = <0x2a150000 0x1000>;
|
||||
clocks = <&oscclk1>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
memory-controller@2a190000 {
|
||||
@ -68,6 +73,8 @@
|
||||
reg = <0x2a190000 0x1000>;
|
||||
interrupts = <0 86 4>,
|
||||
<0 87 4>;
|
||||
clocks = <&oscclk1>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
scu@2c000000 {
|
||||
@ -109,7 +116,77 @@
|
||||
<0 69 4>;
|
||||
};
|
||||
|
||||
motherboard {
|
||||
dcc {
|
||||
compatible = "arm,vexpress,config-bus";
|
||||
arm,vexpress,config-bridge = <&v2m_sysreg>;
|
||||
|
||||
osc@0 {
|
||||
/* CPU and internal AXI reference clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 0>;
|
||||
freq-range = <50000000 100000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk0";
|
||||
};
|
||||
|
||||
oscclk1: osc@1 {
|
||||
/* Multiplexed AXI master clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 1>;
|
||||
freq-range = <5000000 50000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk1";
|
||||
};
|
||||
|
||||
osc@2 {
|
||||
/* DDR2 */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 2>;
|
||||
freq-range = <80000000 120000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk2";
|
||||
};
|
||||
|
||||
oscclk3: osc@3 {
|
||||
/* HDLCD */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 3>;
|
||||
freq-range = <23750000 165000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk3";
|
||||
};
|
||||
|
||||
osc@4 {
|
||||
/* Test chip gate configuration */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 4>;
|
||||
freq-range = <80000000 80000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk4";
|
||||
};
|
||||
|
||||
smbclk: osc@5 {
|
||||
/* SMB clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 5>;
|
||||
freq-range = <25000000 60000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "oscclk5";
|
||||
};
|
||||
|
||||
temp@0 {
|
||||
/* DCC internal operating temperature */
|
||||
compatible = "arm,vexpress-temp";
|
||||
arm,vexpress-sysreg,func = <4 0>;
|
||||
label = "DCC";
|
||||
};
|
||||
};
|
||||
|
||||
smb {
|
||||
compatible = "simple-bus";
|
||||
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0 0 0x08000000 0x04000000>,
|
||||
<1 0 0x14000000 0x04000000>,
|
||||
<2 0 0x18000000 0x04000000>,
|
||||
@ -117,6 +194,7 @@
|
||||
<4 0 0x0c000000 0x04000000>,
|
||||
<5 0 0x10000000 0x04000000>;
|
||||
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 63>;
|
||||
interrupt-map = <0 0 0 &gic 0 0 4>,
|
||||
<0 0 1 &gic 0 1 4>,
|
||||
@ -161,7 +239,7 @@
|
||||
<0 0 40 &gic 0 40 4>,
|
||||
<0 0 41 &gic 0 41 4>,
|
||||
<0 0 42 &gic 0 42 4>;
|
||||
|
||||
/include/ "vexpress-v2m-rs1.dtsi"
|
||||
};
|
||||
};
|
||||
|
||||
/include/ "vexpress-v2m-rs1.dtsi"
|
||||
|
@ -12,6 +12,7 @@
|
||||
/ {
|
||||
model = "V2P-CA9";
|
||||
arm,hbi = <0x191>;
|
||||
arm,vexpress,site = <0xf>;
|
||||
compatible = "arm,vexpress,v2p-ca9", "arm,vexpress";
|
||||
interrupt-parent = <&gic>;
|
||||
#address-cells = <1>;
|
||||
@ -70,11 +71,15 @@
|
||||
compatible = "arm,pl111", "arm,primecell";
|
||||
reg = <0x10020000 0x1000>;
|
||||
interrupts = <0 44 4>;
|
||||
clocks = <&oscclk1>, <&oscclk2>;
|
||||
clock-names = "clcdclk", "apb_pclk";
|
||||
};
|
||||
|
||||
memory-controller@100e0000 {
|
||||
compatible = "arm,pl341", "arm,primecell";
|
||||
reg = <0x100e0000 0x1000>;
|
||||
clocks = <&oscclk2>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
memory-controller@100e1000 {
|
||||
@ -82,6 +87,8 @@
|
||||
reg = <0x100e1000 0x1000>;
|
||||
interrupts = <0 45 4>,
|
||||
<0 46 4>;
|
||||
clocks = <&oscclk2>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
timer@100e4000 {
|
||||
@ -89,12 +96,16 @@
|
||||
reg = <0x100e4000 0x1000>;
|
||||
interrupts = <0 48 4>,
|
||||
<0 49 4>;
|
||||
clocks = <&oscclk2>, <&oscclk2>;
|
||||
clock-names = "timclk", "apb_pclk";
|
||||
};
|
||||
|
||||
watchdog@100e5000 {
|
||||
compatible = "arm,sp805", "arm,primecell";
|
||||
reg = <0x100e5000 0x1000>;
|
||||
interrupts = <0 51 4>;
|
||||
clocks = <&oscclk2>, <&oscclk2>;
|
||||
clock-names = "wdogclk", "apb_pclk";
|
||||
};
|
||||
|
||||
scu@1e000000 {
|
||||
@ -140,13 +151,132 @@
|
||||
<0 63 4>;
|
||||
};
|
||||
|
||||
motherboard {
|
||||
dcc {
|
||||
compatible = "arm,vexpress,config-bus";
|
||||
arm,vexpress,config-bridge = <&v2m_sysreg>;
|
||||
|
||||
osc@0 {
|
||||
/* ACLK clock to the AXI master port on the test chip */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 0>;
|
||||
freq-range = <30000000 50000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "extsaxiclk";
|
||||
};
|
||||
|
||||
oscclk1: osc@1 {
|
||||
/* Reference clock for the CLCD */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 1>;
|
||||
freq-range = <10000000 80000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "clcdclk";
|
||||
};
|
||||
|
||||
smbclk: oscclk2: osc@2 {
|
||||
/* Reference clock for the test chip internal PLLs */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 2>;
|
||||
freq-range = <33000000 100000000>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "tcrefclk";
|
||||
};
|
||||
|
||||
volt@0 {
|
||||
/* Test Chip internal logic voltage */
|
||||
compatible = "arm,vexpress-volt";
|
||||
arm,vexpress-sysreg,func = <2 0>;
|
||||
regulator-name = "VD10";
|
||||
regulator-always-on;
|
||||
label = "VD10";
|
||||
};
|
||||
|
||||
volt@1 {
|
||||
/* PL310, L2 cache, RAM cell supply (not PL310 logic) */
|
||||
compatible = "arm,vexpress-volt";
|
||||
arm,vexpress-sysreg,func = <2 1>;
|
||||
regulator-name = "VD10_S2";
|
||||
regulator-always-on;
|
||||
label = "VD10_S2";
|
||||
};
|
||||
|
||||
volt@2 {
|
||||
/* Cortex-A9 system supply, Cores, MPEs, SCU and PL310 logic */
|
||||
compatible = "arm,vexpress-volt";
|
||||
arm,vexpress-sysreg,func = <2 2>;
|
||||
regulator-name = "VD10_S3";
|
||||
regulator-always-on;
|
||||
label = "VD10_S3";
|
||||
};
|
||||
|
||||
volt@3 {
|
||||
/* DDR2 SDRAM and Test Chip DDR2 I/O supply */
|
||||
compatible = "arm,vexpress-volt";
|
||||
arm,vexpress-sysreg,func = <2 3>;
|
||||
regulator-name = "VCC1V8";
|
||||
regulator-always-on;
|
||||
label = "VCC1V8";
|
||||
};
|
||||
|
||||
volt@4 {
|
||||
/* DDR2 SDRAM VTT termination voltage */
|
||||
compatible = "arm,vexpress-volt";
|
||||
arm,vexpress-sysreg,func = <2 4>;
|
||||
regulator-name = "DDR2VTT";
|
||||
regulator-always-on;
|
||||
label = "DDR2VTT";
|
||||
};
|
||||
|
||||
volt@5 {
|
||||
/* Local board supply for miscellaneous logic external to the Test Chip */
|
||||
arm,vexpress-sysreg,func = <2 5>;
|
||||
compatible = "arm,vexpress-volt";
|
||||
regulator-name = "VCC3V3";
|
||||
regulator-always-on;
|
||||
label = "VCC3V3";
|
||||
};
|
||||
|
||||
amp@0 {
|
||||
/* PL310, L2 cache, RAM cell supply (not PL310 logic) */
|
||||
compatible = "arm,vexpress-amp";
|
||||
arm,vexpress-sysreg,func = <3 0>;
|
||||
label = "VD10_S2";
|
||||
};
|
||||
|
||||
amp@1 {
|
||||
/* Cortex-A9 system supply, Cores, MPEs, SCU and PL310 logic */
|
||||
compatible = "arm,vexpress-amp";
|
||||
arm,vexpress-sysreg,func = <3 1>;
|
||||
label = "VD10_S3";
|
||||
};
|
||||
|
||||
power@0 {
|
||||
/* PL310, L2 cache, RAM cell supply (not PL310 logic) */
|
||||
compatible = "arm,vexpress-power";
|
||||
arm,vexpress-sysreg,func = <12 0>;
|
||||
label = "PVD10_S2";
|
||||
};
|
||||
|
||||
power@1 {
|
||||
/* Cortex-A9 system supply, Cores, MPEs, SCU and PL310 logic */
|
||||
compatible = "arm,vexpress-power";
|
||||
arm,vexpress-sysreg,func = <12 1>;
|
||||
label = "PVD10_S3";
|
||||
};
|
||||
};
|
||||
|
||||
smb {
|
||||
compatible = "simple-bus";
|
||||
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0 0 0x40000000 0x04000000>,
|
||||
<1 0 0x44000000 0x04000000>,
|
||||
<2 0 0x48000000 0x04000000>,
|
||||
<3 0 0x4c000000 0x04000000>,
|
||||
<7 0 0x10000000 0x00020000>;
|
||||
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 63>;
|
||||
interrupt-map = <0 0 0 &gic 0 0 4>,
|
||||
<0 0 1 &gic 0 1 4>,
|
||||
@ -191,7 +321,7 @@
|
||||
<0 0 40 &gic 0 40 4>,
|
||||
<0 0 41 &gic 0 41 4>,
|
||||
<0 0 42 &gic 0 42 4>;
|
||||
|
||||
/include/ "vexpress-v2m.dtsi"
|
||||
};
|
||||
};
|
||||
|
||||
/include/ "vexpress-v2m.dtsi"
|
||||
|
@ -50,12 +50,6 @@
|
||||
#define SCPCELLID2 0xFF8
|
||||
#define SCPCELLID3 0xFFC
|
||||
|
||||
#define SCCTRL_TIMEREN0SEL_REFCLK (0 << 15)
|
||||
#define SCCTRL_TIMEREN0SEL_TIMCLK (1 << 15)
|
||||
|
||||
#define SCCTRL_TIMEREN1SEL_REFCLK (0 << 17)
|
||||
#define SCCTRL_TIMEREN1SEL_TIMCLK (1 << 17)
|
||||
|
||||
#define SCCTRL_TIMERENnSEL_SHIFT(n) (15 + ((n) * 2))
|
||||
|
||||
static inline void sysctl_soft_reset(void __iomem *base)
|
||||
|
@ -1,11 +1,12 @@
|
||||
config ARCH_VEXPRESS
|
||||
bool "ARM Ltd. Versatile Express family" if ARCH_MULTI_V7
|
||||
select ARCH_WANT_OPTIONAL_GPIOLIB
|
||||
select ARCH_REQUIRE_GPIOLIB
|
||||
select ARM_AMBA
|
||||
select ARM_GIC
|
||||
select ARM_TIMER_SP804
|
||||
select CLKDEV_LOOKUP
|
||||
select COMMON_CLK
|
||||
select COMMON_CLK_VERSATILE
|
||||
select CPU_V7
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select HAVE_CLK
|
||||
@ -17,6 +18,7 @@ config ARCH_VEXPRESS
|
||||
select PLAT_VERSATILE
|
||||
select PLAT_VERSATILE_CLCD
|
||||
select REGULATOR_FIXED_VOLTAGE if REGULATOR
|
||||
select VEXPRESS_CONFIG
|
||||
help
|
||||
This option enables support for systems using Cortex processor based
|
||||
ARM core and logic (FPGA) tiles on the Versatile Express motherboard,
|
||||
|
@ -4,7 +4,7 @@
|
||||
ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
|
||||
-I$(srctree)/arch/arm/plat-versatile/include
|
||||
|
||||
obj-y := v2m.o
|
||||
obj-y := v2m.o reset.o
|
||||
obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o
|
||||
obj-$(CONFIG_SMP) += platsmp.o
|
||||
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <linux/amba/bus.h>
|
||||
#include <linux/amba/clcd.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/vexpress.h>
|
||||
|
||||
#include <asm/hardware/arm_timer.h>
|
||||
#include <asm/hardware/cache-l2x0.h>
|
||||
@ -64,19 +65,6 @@ static void __init ct_ca9x4_init_irq(void)
|
||||
ca9x4_twd_init();
|
||||
}
|
||||
|
||||
static void ct_ca9x4_clcd_enable(struct clcd_fb *fb)
|
||||
{
|
||||
u32 site = v2m_get_master_site();
|
||||
|
||||
/*
|
||||
* Old firmware was using the "site" component of the command
|
||||
* to control the DVI muxer (while it should be always 0 ie. MB).
|
||||
* Newer firmware uses the data register. Keep both for compatibility.
|
||||
*/
|
||||
v2m_cfg_write(SYS_CFG_MUXFPGA | SYS_CFG_SITE(site), site);
|
||||
v2m_cfg_write(SYS_CFG_DVIMODE | SYS_CFG_SITE(SYS_CFG_SITE_MB), 2);
|
||||
}
|
||||
|
||||
static int ct_ca9x4_clcd_setup(struct clcd_fb *fb)
|
||||
{
|
||||
unsigned long framesize = 1024 * 768 * 2;
|
||||
@ -93,7 +81,6 @@ static struct clcd_board ct_ca9x4_clcd_data = {
|
||||
.caps = CLCD_CAP_5551 | CLCD_CAP_565,
|
||||
.check = clcdfb_check,
|
||||
.decode = clcdfb_decode,
|
||||
.enable = ct_ca9x4_clcd_enable,
|
||||
.setup = ct_ca9x4_clcd_setup,
|
||||
.mmap = versatile_clcd_mmap_dma,
|
||||
.remove = versatile_clcd_remove_dma,
|
||||
@ -111,14 +98,6 @@ static struct amba_device *ct_ca9x4_amba_devs[] __initdata = {
|
||||
&gpio_device,
|
||||
};
|
||||
|
||||
|
||||
static struct v2m_osc ct_osc1 = {
|
||||
.osc = 1,
|
||||
.rate_min = 10000000,
|
||||
.rate_max = 80000000,
|
||||
.rate_default = 23750000,
|
||||
};
|
||||
|
||||
static struct resource pmu_resources[] = {
|
||||
[0] = {
|
||||
.start = IRQ_CT_CA9X4_PMU_CPU0,
|
||||
@ -149,10 +128,18 @@ static struct platform_device pmu_device = {
|
||||
.resource = pmu_resources,
|
||||
};
|
||||
|
||||
static struct platform_device osc1_device = {
|
||||
.name = "vexpress-osc",
|
||||
.id = 1,
|
||||
.num_resources = 1,
|
||||
.resource = (struct resource []) {
|
||||
VEXPRESS_RES_FUNC(0xf, 1),
|
||||
},
|
||||
};
|
||||
|
||||
static void __init ct_ca9x4_init(void)
|
||||
{
|
||||
int i;
|
||||
struct clk *clk;
|
||||
|
||||
#ifdef CONFIG_CACHE_L2X0
|
||||
void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K);
|
||||
@ -164,14 +151,14 @@ static void __init ct_ca9x4_init(void)
|
||||
l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff);
|
||||
#endif
|
||||
|
||||
ct_osc1.site = v2m_get_master_site();
|
||||
clk = v2m_osc_register("ct:osc1", &ct_osc1);
|
||||
clk_register_clkdev(clk, NULL, "ct:clcd");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++)
|
||||
amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource);
|
||||
|
||||
platform_device_register(&pmu_device);
|
||||
platform_device_register(&osc1_device);
|
||||
|
||||
WARN_ON(clk_register_clkdev(vexpress_osc_setup(&osc1_device.dev),
|
||||
NULL, "ct:clcd"));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
@ -1,8 +1,6 @@
|
||||
#ifndef __MACH_MOTHERBOARD_H
|
||||
#define __MACH_MOTHERBOARD_H
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
/*
|
||||
* Physical addresses, offset from V2M_PA_CS0-3
|
||||
*/
|
||||
@ -41,31 +39,6 @@
|
||||
#define V2M_CF (V2M_PA_CS7 + 0x0001a000)
|
||||
#define V2M_CLCD (V2M_PA_CS7 + 0x0001f000)
|
||||
|
||||
/*
|
||||
* Offsets from SYSREGS base
|
||||
*/
|
||||
#define V2M_SYS_ID 0x000
|
||||
#define V2M_SYS_SW 0x004
|
||||
#define V2M_SYS_LED 0x008
|
||||
#define V2M_SYS_100HZ 0x024
|
||||
#define V2M_SYS_FLAGS 0x030
|
||||
#define V2M_SYS_FLAGSSET 0x030
|
||||
#define V2M_SYS_FLAGSCLR 0x034
|
||||
#define V2M_SYS_NVFLAGS 0x038
|
||||
#define V2M_SYS_NVFLAGSSET 0x038
|
||||
#define V2M_SYS_NVFLAGSCLR 0x03c
|
||||
#define V2M_SYS_MCI 0x048
|
||||
#define V2M_SYS_FLASH 0x03c
|
||||
#define V2M_SYS_CFGSW 0x058
|
||||
#define V2M_SYS_24MHZ 0x05c
|
||||
#define V2M_SYS_MISC 0x060
|
||||
#define V2M_SYS_DMA 0x064
|
||||
#define V2M_SYS_PROCID0 0x084
|
||||
#define V2M_SYS_PROCID1 0x088
|
||||
#define V2M_SYS_CFGDATA 0x0a0
|
||||
#define V2M_SYS_CFGCTRL 0x0a4
|
||||
#define V2M_SYS_CFGSTAT 0x0a8
|
||||
|
||||
|
||||
/*
|
||||
* Interrupts. Those in {} are for AMBA devices
|
||||
@ -90,43 +63,6 @@
|
||||
#define IRQ_V2M_PCIE (32 + 17)
|
||||
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
#define SYS_CFG_START (1 << 31)
|
||||
#define SYS_CFG_WRITE (1 << 30)
|
||||
#define SYS_CFG_OSC (1 << 20)
|
||||
#define SYS_CFG_VOLT (2 << 20)
|
||||
#define SYS_CFG_AMP (3 << 20)
|
||||
#define SYS_CFG_TEMP (4 << 20)
|
||||
#define SYS_CFG_RESET (5 << 20)
|
||||
#define SYS_CFG_SCC (6 << 20)
|
||||
#define SYS_CFG_MUXFPGA (7 << 20)
|
||||
#define SYS_CFG_SHUTDOWN (8 << 20)
|
||||
#define SYS_CFG_REBOOT (9 << 20)
|
||||
#define SYS_CFG_DVIMODE (11 << 20)
|
||||
#define SYS_CFG_POWER (12 << 20)
|
||||
#define SYS_CFG_SITE(n) ((n) << 16)
|
||||
#define SYS_CFG_SITE_MB 0
|
||||
#define SYS_CFG_SITE_DB1 1
|
||||
#define SYS_CFG_SITE_DB2 2
|
||||
#define SYS_CFG_STACK(n) ((n) << 12)
|
||||
|
||||
#define SYS_CFG_ERR (1 << 1)
|
||||
#define SYS_CFG_COMPLETE (1 << 0)
|
||||
|
||||
int v2m_cfg_write(u32 devfn, u32 data);
|
||||
int v2m_cfg_read(u32 devfn, u32 *data);
|
||||
void v2m_flags_set(u32 data);
|
||||
|
||||
/*
|
||||
* Miscellaneous
|
||||
*/
|
||||
#define SYS_MISC_MASTERSITE (1 << 14)
|
||||
#define SYS_PROCIDx_HBI_MASK 0xfff
|
||||
|
||||
int v2m_get_master_site(void);
|
||||
|
||||
/*
|
||||
* Core tile IDs
|
||||
*/
|
||||
@ -149,21 +85,4 @@ struct ct_desc {
|
||||
|
||||
extern struct ct_desc *ct_desc;
|
||||
|
||||
/*
|
||||
* OSC clock provider
|
||||
*/
|
||||
struct v2m_osc {
|
||||
struct clk_hw hw;
|
||||
u8 site; /* 0 = motherboard, 1 = site 1, 2 = site 2 */
|
||||
u8 stack; /* board stack position */
|
||||
u16 osc;
|
||||
unsigned long rate_min;
|
||||
unsigned long rate_max;
|
||||
unsigned long rate_default;
|
||||
};
|
||||
|
||||
#define to_v2m_osc(osc) container_of(osc, struct v2m_osc, hw)
|
||||
|
||||
struct clk *v2m_osc_register(const char *name, struct v2m_osc *osc);
|
||||
|
||||
#endif
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/smp.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/vexpress.h>
|
||||
|
||||
#include <asm/smp_scu.h>
|
||||
#include <asm/hardware/gic.h>
|
||||
@ -193,7 +194,7 @@ static void __init vexpress_smp_prepare_cpus(unsigned int max_cpus)
|
||||
* until it receives a soft interrupt, and then the
|
||||
* secondary CPU branches to this address.
|
||||
*/
|
||||
v2m_flags_set(virt_to_phys(versatile_secondary_startup));
|
||||
vexpress_flags_set(virt_to_phys(versatile_secondary_startup));
|
||||
}
|
||||
|
||||
struct smp_operations __initdata vexpress_smp_ops = {
|
||||
|
@ -16,11 +16,10 @@
|
||||
#include <linux/smsc911x.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/usb/isp1760.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/regulator/fixed.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/vexpress.h>
|
||||
|
||||
#include <asm/arch_timer.h>
|
||||
#include <asm/mach-types.h>
|
||||
@ -33,7 +32,6 @@
|
||||
#include <asm/hardware/cache-l2x0.h>
|
||||
#include <asm/hardware/gic.h>
|
||||
#include <asm/hardware/timer-sp.h>
|
||||
#include <asm/hardware/sp810.h>
|
||||
|
||||
#include <mach/ct-ca9x4.h>
|
||||
#include <mach/motherboard.h>
|
||||
@ -58,22 +56,6 @@ static struct map_desc v2m_io_desc[] __initdata = {
|
||||
},
|
||||
};
|
||||
|
||||
static void __iomem *v2m_sysreg_base;
|
||||
|
||||
static void __init v2m_sysctl_init(void __iomem *base)
|
||||
{
|
||||
u32 scctrl;
|
||||
|
||||
if (WARN_ON(!base))
|
||||
return;
|
||||
|
||||
/* Select 1MHz TIMCLK as the reference clock for SP804 timers */
|
||||
scctrl = readl(base + SCCTRL);
|
||||
scctrl |= SCCTRL_TIMEREN0SEL_TIMCLK;
|
||||
scctrl |= SCCTRL_TIMEREN1SEL_TIMCLK;
|
||||
writel(scctrl, base + SCCTRL);
|
||||
}
|
||||
|
||||
static void __init v2m_sp804_init(void __iomem *base, unsigned int irq)
|
||||
{
|
||||
if (WARN_ON(!base || irq == NO_IRQ))
|
||||
@ -87,69 +69,6 @@ static void __init v2m_sp804_init(void __iomem *base, unsigned int irq)
|
||||
}
|
||||
|
||||
|
||||
static DEFINE_SPINLOCK(v2m_cfg_lock);
|
||||
|
||||
int v2m_cfg_write(u32 devfn, u32 data)
|
||||
{
|
||||
/* Configuration interface broken? */
|
||||
u32 val;
|
||||
|
||||
printk("%s: writing %08x to %08x\n", __func__, data, devfn);
|
||||
|
||||
devfn |= SYS_CFG_START | SYS_CFG_WRITE;
|
||||
|
||||
spin_lock(&v2m_cfg_lock);
|
||||
val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
|
||||
writel(val & ~SYS_CFG_COMPLETE, v2m_sysreg_base + V2M_SYS_CFGSTAT);
|
||||
|
||||
writel(data, v2m_sysreg_base + V2M_SYS_CFGDATA);
|
||||
writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
|
||||
|
||||
do {
|
||||
val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
|
||||
} while (val == 0);
|
||||
spin_unlock(&v2m_cfg_lock);
|
||||
|
||||
return !!(val & SYS_CFG_ERR);
|
||||
}
|
||||
|
||||
int v2m_cfg_read(u32 devfn, u32 *data)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
devfn |= SYS_CFG_START;
|
||||
|
||||
spin_lock(&v2m_cfg_lock);
|
||||
writel(0, v2m_sysreg_base + V2M_SYS_CFGSTAT);
|
||||
writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
|
||||
|
||||
mb();
|
||||
|
||||
do {
|
||||
cpu_relax();
|
||||
val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
|
||||
} while (val == 0);
|
||||
|
||||
*data = readl(v2m_sysreg_base + V2M_SYS_CFGDATA);
|
||||
spin_unlock(&v2m_cfg_lock);
|
||||
|
||||
return !!(val & SYS_CFG_ERR);
|
||||
}
|
||||
|
||||
void __init v2m_flags_set(u32 data)
|
||||
{
|
||||
writel(~0, v2m_sysreg_base + V2M_SYS_FLAGSCLR);
|
||||
writel(data, v2m_sysreg_base + V2M_SYS_FLAGSSET);
|
||||
}
|
||||
|
||||
int v2m_get_master_site(void)
|
||||
{
|
||||
u32 misc = readl(v2m_sysreg_base + V2M_SYS_MISC);
|
||||
|
||||
return misc & SYS_MISC_MASTERSITE ? SYS_CFG_SITE_DB2 : SYS_CFG_SITE_DB1;
|
||||
}
|
||||
|
||||
|
||||
static struct resource v2m_pcie_i2c_resource = {
|
||||
.start = V2M_SERIAL_BUS_PCI,
|
||||
.end = V2M_SERIAL_BUS_PCI + SZ_4K - 1,
|
||||
@ -237,14 +156,8 @@ static struct platform_device v2m_usb_device = {
|
||||
.dev.platform_data = &v2m_usb_config,
|
||||
};
|
||||
|
||||
static void v2m_flash_set_vpp(struct platform_device *pdev, int on)
|
||||
{
|
||||
writel(on != 0, v2m_sysreg_base + V2M_SYS_FLASH);
|
||||
}
|
||||
|
||||
static struct physmap_flash_data v2m_flash_data = {
|
||||
.width = 4,
|
||||
.set_vpp = v2m_flash_set_vpp,
|
||||
};
|
||||
|
||||
static struct resource v2m_flash_resources[] = {
|
||||
@ -291,14 +204,61 @@ static struct platform_device v2m_cf_device = {
|
||||
.dev.platform_data = &v2m_pata_data,
|
||||
};
|
||||
|
||||
static unsigned int v2m_mmci_status(struct device *dev)
|
||||
{
|
||||
return readl(v2m_sysreg_base + V2M_SYS_MCI) & (1 << 0);
|
||||
}
|
||||
|
||||
static struct mmci_platform_data v2m_mmci_data = {
|
||||
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
|
||||
.status = v2m_mmci_status,
|
||||
.gpio_wp = VEXPRESS_GPIO_MMC_WPROT,
|
||||
.gpio_cd = VEXPRESS_GPIO_MMC_CARDIN,
|
||||
};
|
||||
|
||||
static struct resource v2m_sysreg_resources[] = {
|
||||
{
|
||||
.start = V2M_SYSREGS,
|
||||
.end = V2M_SYSREGS + 0xfff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device v2m_sysreg_device = {
|
||||
.name = "vexpress-sysreg",
|
||||
.id = -1,
|
||||
.resource = v2m_sysreg_resources,
|
||||
.num_resources = ARRAY_SIZE(v2m_sysreg_resources),
|
||||
};
|
||||
|
||||
static struct platform_device v2m_muxfpga_device = {
|
||||
.name = "vexpress-muxfpga",
|
||||
.id = 0,
|
||||
.num_resources = 1,
|
||||
.resource = (struct resource []) {
|
||||
VEXPRESS_RES_FUNC(0, 7),
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device v2m_shutdown_device = {
|
||||
.name = "vexpress-shutdown",
|
||||
.id = 0,
|
||||
.num_resources = 1,
|
||||
.resource = (struct resource []) {
|
||||
VEXPRESS_RES_FUNC(0, 8),
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device v2m_reboot_device = {
|
||||
.name = "vexpress-reboot",
|
||||
.id = 0,
|
||||
.num_resources = 1,
|
||||
.resource = (struct resource []) {
|
||||
VEXPRESS_RES_FUNC(0, 9),
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device v2m_dvimode_device = {
|
||||
.name = "vexpress-dvimode",
|
||||
.id = 0,
|
||||
.num_resources = 1,
|
||||
.resource = (struct resource []) {
|
||||
VEXPRESS_RES_FUNC(0, 11),
|
||||
}
|
||||
};
|
||||
|
||||
static AMBA_APB_DEVICE(aaci, "mb:aaci", 0, V2M_AACI, IRQ_V2M_AACI, NULL);
|
||||
@ -325,123 +285,9 @@ static struct amba_device *v2m_amba_devs[] __initdata = {
|
||||
&rtc_device,
|
||||
};
|
||||
|
||||
|
||||
static unsigned long v2m_osc_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct v2m_osc *osc = to_v2m_osc(hw);
|
||||
|
||||
return !parent_rate ? osc->rate_default : parent_rate;
|
||||
}
|
||||
|
||||
static long v2m_osc_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct v2m_osc *osc = to_v2m_osc(hw);
|
||||
|
||||
if (WARN_ON(rate < osc->rate_min))
|
||||
rate = osc->rate_min;
|
||||
|
||||
if (WARN_ON(rate > osc->rate_max))
|
||||
rate = osc->rate_max;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int v2m_osc_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct v2m_osc *osc = to_v2m_osc(hw);
|
||||
|
||||
v2m_cfg_write(SYS_CFG_OSC | SYS_CFG_SITE(osc->site) |
|
||||
SYS_CFG_STACK(osc->stack) | osc->osc, rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_ops v2m_osc_ops = {
|
||||
.recalc_rate = v2m_osc_recalc_rate,
|
||||
.round_rate = v2m_osc_round_rate,
|
||||
.set_rate = v2m_osc_set_rate,
|
||||
};
|
||||
|
||||
struct clk * __init v2m_osc_register(const char *name, struct v2m_osc *osc)
|
||||
{
|
||||
struct clk_init_data init;
|
||||
|
||||
WARN_ON(osc->site > 2);
|
||||
WARN_ON(osc->stack > 15);
|
||||
WARN_ON(osc->osc > 4095);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &v2m_osc_ops;
|
||||
init.flags = CLK_IS_ROOT;
|
||||
init.num_parents = 0;
|
||||
|
||||
osc->hw.init = &init;
|
||||
|
||||
return clk_register(NULL, &osc->hw);
|
||||
}
|
||||
|
||||
static struct v2m_osc v2m_mb_osc1 = {
|
||||
.site = SYS_CFG_SITE_MB,
|
||||
.osc = 1,
|
||||
.rate_min = 23750000,
|
||||
.rate_max = 63500000,
|
||||
.rate_default = 23750000,
|
||||
};
|
||||
|
||||
static const char *v2m_ref_clk_periphs[] __initconst = {
|
||||
"mb:wdt", "1000f000.wdt", "1c0f0000.wdt", /* SP805 WDT */
|
||||
};
|
||||
|
||||
static const char *v2m_osc1_periphs[] __initconst = {
|
||||
"mb:clcd", "1001f000.clcd", "1c1f0000.clcd", /* PL111 CLCD */
|
||||
};
|
||||
|
||||
static const char *v2m_osc2_periphs[] __initconst = {
|
||||
"mb:mmci", "10005000.mmci", "1c050000.mmci", /* PL180 MMCI */
|
||||
"mb:kmi0", "10006000.kmi", "1c060000.kmi", /* PL050 KMI0 */
|
||||
"mb:kmi1", "10007000.kmi", "1c070000.kmi", /* PL050 KMI1 */
|
||||
"mb:uart0", "10009000.uart", "1c090000.uart", /* PL011 UART0 */
|
||||
"mb:uart1", "1000a000.uart", "1c0a0000.uart", /* PL011 UART1 */
|
||||
"mb:uart2", "1000b000.uart", "1c0b0000.uart", /* PL011 UART2 */
|
||||
"mb:uart3", "1000c000.uart", "1c0c0000.uart", /* PL011 UART3 */
|
||||
};
|
||||
|
||||
static void __init v2m_clk_init(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
int i;
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "dummy_apb_pclk", NULL,
|
||||
CLK_IS_ROOT, 0);
|
||||
WARN_ON(clk_register_clkdev(clk, "apb_pclk", NULL));
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "mb:ref_clk", NULL,
|
||||
CLK_IS_ROOT, 32768);
|
||||
for (i = 0; i < ARRAY_SIZE(v2m_ref_clk_periphs); i++)
|
||||
WARN_ON(clk_register_clkdev(clk, NULL, v2m_ref_clk_periphs[i]));
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "mb:sp804_clk", NULL,
|
||||
CLK_IS_ROOT, 1000000);
|
||||
WARN_ON(clk_register_clkdev(clk, "v2m-timer0", "sp804"));
|
||||
WARN_ON(clk_register_clkdev(clk, "v2m-timer1", "sp804"));
|
||||
|
||||
clk = v2m_osc_register("mb:osc1", &v2m_mb_osc1);
|
||||
for (i = 0; i < ARRAY_SIZE(v2m_osc1_periphs); i++)
|
||||
WARN_ON(clk_register_clkdev(clk, NULL, v2m_osc1_periphs[i]));
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "mb:osc2", NULL,
|
||||
CLK_IS_ROOT, 24000000);
|
||||
for (i = 0; i < ARRAY_SIZE(v2m_osc2_periphs); i++)
|
||||
WARN_ON(clk_register_clkdev(clk, NULL, v2m_osc2_periphs[i]));
|
||||
}
|
||||
|
||||
static void __init v2m_timer_init(void)
|
||||
{
|
||||
v2m_sysctl_init(ioremap(V2M_SYSCTL, SZ_4K));
|
||||
v2m_clk_init();
|
||||
vexpress_clk_init(ioremap(V2M_SYSCTL, SZ_4K));
|
||||
v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0);
|
||||
}
|
||||
|
||||
@ -453,19 +299,7 @@ static void __init v2m_init_early(void)
|
||||
{
|
||||
if (ct_desc->init_early)
|
||||
ct_desc->init_early();
|
||||
versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
|
||||
}
|
||||
|
||||
static void v2m_power_off(void)
|
||||
{
|
||||
if (v2m_cfg_write(SYS_CFG_SHUTDOWN | SYS_CFG_SITE(SYS_CFG_SITE_MB), 0))
|
||||
printk(KERN_EMERG "Unable to shutdown\n");
|
||||
}
|
||||
|
||||
static void v2m_restart(char str, const char *cmd)
|
||||
{
|
||||
if (v2m_cfg_write(SYS_CFG_REBOOT | SYS_CFG_SITE(SYS_CFG_SITE_MB), 0))
|
||||
printk(KERN_EMERG "Unable to reboot\n");
|
||||
versatile_sched_clock_init(vexpress_get_24mhz_clock_base(), 24000000);
|
||||
}
|
||||
|
||||
struct ct_desc *ct_desc;
|
||||
@ -482,7 +316,7 @@ static void __init v2m_populate_ct_desc(void)
|
||||
u32 current_tile_id;
|
||||
|
||||
ct_desc = NULL;
|
||||
current_tile_id = readl(v2m_sysreg_base + V2M_SYS_PROCID0)
|
||||
current_tile_id = vexpress_get_procid(VEXPRESS_SITE_MASTER)
|
||||
& V2M_CT_ID_MASK;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ct_descs) && !ct_desc; ++i)
|
||||
@ -498,7 +332,7 @@ static void __init v2m_populate_ct_desc(void)
|
||||
static void __init v2m_map_io(void)
|
||||
{
|
||||
iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
|
||||
v2m_sysreg_base = ioremap(V2M_SYSREGS, SZ_4K);
|
||||
vexpress_sysreg_early_init(ioremap(V2M_SYSREGS, SZ_4K));
|
||||
v2m_populate_ct_desc();
|
||||
ct_desc->map_io();
|
||||
}
|
||||
@ -515,6 +349,12 @@ static void __init v2m_init(void)
|
||||
regulator_register_fixed(0, v2m_eth_supplies,
|
||||
ARRAY_SIZE(v2m_eth_supplies));
|
||||
|
||||
platform_device_register(&v2m_muxfpga_device);
|
||||
platform_device_register(&v2m_shutdown_device);
|
||||
platform_device_register(&v2m_reboot_device);
|
||||
platform_device_register(&v2m_dvimode_device);
|
||||
|
||||
platform_device_register(&v2m_sysreg_device);
|
||||
platform_device_register(&v2m_pcie_i2c_device);
|
||||
platform_device_register(&v2m_ddc_i2c_device);
|
||||
platform_device_register(&v2m_flash_device);
|
||||
@ -525,7 +365,7 @@ static void __init v2m_init(void)
|
||||
for (i = 0; i < ARRAY_SIZE(v2m_amba_devs); i++)
|
||||
amba_device_register(v2m_amba_devs[i], &iomem_resource);
|
||||
|
||||
pm_power_off = v2m_power_off;
|
||||
pm_power_off = vexpress_power_off;
|
||||
|
||||
ct_desc->init_tile();
|
||||
}
|
||||
@ -539,7 +379,7 @@ MACHINE_START(VEXPRESS, "ARM-Versatile Express")
|
||||
.timer = &v2m_timer,
|
||||
.handle_irq = gic_handle_irq,
|
||||
.init_machine = v2m_init,
|
||||
.restart = v2m_restart,
|
||||
.restart = vexpress_restart,
|
||||
MACHINE_END
|
||||
|
||||
static struct map_desc v2m_rs1_io_desc __initdata = {
|
||||
@ -580,20 +420,13 @@ void __init v2m_dt_map_io(void)
|
||||
|
||||
void __init v2m_dt_init_early(void)
|
||||
{
|
||||
struct device_node *node;
|
||||
u32 dt_hbi;
|
||||
|
||||
node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg");
|
||||
v2m_sysreg_base = of_iomap(node, 0);
|
||||
if (WARN_ON(!v2m_sysreg_base))
|
||||
return;
|
||||
vexpress_sysreg_of_early_init();
|
||||
|
||||
/* Confirm board type against DT property, if available */
|
||||
if (of_property_read_u32(allnodes, "arm,hbi", &dt_hbi) == 0) {
|
||||
int site = v2m_get_master_site();
|
||||
u32 id = readl(v2m_sysreg_base + (site == SYS_CFG_SITE_DB2 ?
|
||||
V2M_SYS_PROCID1 : V2M_SYS_PROCID0));
|
||||
u32 hbi = id & SYS_PROCIDx_HBI_MASK;
|
||||
u32 hbi = vexpress_get_hbi(VEXPRESS_SITE_MASTER);
|
||||
|
||||
if (WARN_ON(dt_hbi != hbi))
|
||||
pr_warning("vexpress: DT HBI (%x) is not matching "
|
||||
@ -613,51 +446,47 @@ static void __init v2m_dt_init_irq(void)
|
||||
|
||||
static void __init v2m_dt_timer_init(void)
|
||||
{
|
||||
struct device_node *node;
|
||||
const char *path;
|
||||
int err;
|
||||
struct device_node *node = NULL;
|
||||
|
||||
node = of_find_compatible_node(NULL, NULL, "arm,sp810");
|
||||
v2m_sysctl_init(of_iomap(node, 0));
|
||||
vexpress_clk_of_init();
|
||||
|
||||
v2m_clk_init();
|
||||
do {
|
||||
node = of_find_compatible_node(node, NULL, "arm,sp804");
|
||||
} while (node && vexpress_get_site_by_node(node) != VEXPRESS_SITE_MB);
|
||||
if (node) {
|
||||
pr_info("Using SP804 '%s' as a clock & events source\n",
|
||||
node->full_name);
|
||||
v2m_sp804_init(of_iomap(node, 0),
|
||||
irq_of_parse_and_map(node, 0));
|
||||
}
|
||||
|
||||
err = of_property_read_string(of_aliases, "arm,v2m_timer", &path);
|
||||
if (WARN_ON(err))
|
||||
return;
|
||||
node = of_find_node_by_path(path);
|
||||
v2m_sp804_init(of_iomap(node, 0), irq_of_parse_and_map(node, 0));
|
||||
if (arch_timer_of_register() != 0)
|
||||
twd_local_timer_of_register();
|
||||
|
||||
if (arch_timer_sched_clock_init() != 0)
|
||||
versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
|
||||
versatile_sched_clock_init(vexpress_get_24mhz_clock_base(),
|
||||
24000000);
|
||||
}
|
||||
|
||||
static struct sys_timer v2m_dt_timer = {
|
||||
.init = v2m_dt_timer_init,
|
||||
};
|
||||
|
||||
static struct of_dev_auxdata v2m_dt_auxdata_lookup[] __initdata = {
|
||||
OF_DEV_AUXDATA("arm,vexpress-flash", V2M_NOR0, "physmap-flash",
|
||||
&v2m_flash_data),
|
||||
OF_DEV_AUXDATA("arm,primecell", V2M_MMCI, "mb:mmci", &v2m_mmci_data),
|
||||
/* RS1 memory map */
|
||||
OF_DEV_AUXDATA("arm,vexpress-flash", 0x08000000, "physmap-flash",
|
||||
&v2m_flash_data),
|
||||
OF_DEV_AUXDATA("arm,primecell", 0x1c050000, "mb:mmci", &v2m_mmci_data),
|
||||
static const struct of_device_id v2m_dt_bus_match[] __initconst = {
|
||||
{ .compatible = "simple-bus", },
|
||||
{ .compatible = "arm,amba-bus", },
|
||||
{ .compatible = "arm,vexpress,config-bus", },
|
||||
{}
|
||||
};
|
||||
|
||||
static void __init v2m_dt_init(void)
|
||||
{
|
||||
l2x0_of_init(0x00400000, 0xfe0fffff);
|
||||
of_platform_populate(NULL, of_default_bus_match_table,
|
||||
v2m_dt_auxdata_lookup, NULL);
|
||||
pm_power_off = v2m_power_off;
|
||||
of_platform_populate(NULL, v2m_dt_bus_match, NULL, NULL);
|
||||
pm_power_off = vexpress_power_off;
|
||||
}
|
||||
|
||||
const static char *v2m_dt_match[] __initconst = {
|
||||
static const char * const v2m_dt_match[] __initconst = {
|
||||
"arm,vexpress",
|
||||
"xen,xenvm",
|
||||
NULL,
|
||||
@ -672,5 +501,5 @@ DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express")
|
||||
.timer = &v2m_dt_timer,
|
||||
.init_machine = v2m_dt_init,
|
||||
.handle_irq = gic_handle_irq,
|
||||
.restart = v2m_restart,
|
||||
.restart = vexpress_restart,
|
||||
MACHINE_END
|
||||
|
@ -1070,3 +1070,9 @@ config MCP_UCB1200_TS
|
||||
depends on MCP_UCB1200 && INPUT
|
||||
|
||||
endmenu
|
||||
|
||||
config VEXPRESS_CONFIG
|
||||
bool
|
||||
help
|
||||
Platform configuration infrastructure for the ARM Ltd.
|
||||
Versatile Express.
|
||||
|
@ -138,3 +138,4 @@ obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
|
||||
obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
|
||||
obj-$(CONFIG_MFD_SYSCON) += syscon.o
|
||||
obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
|
||||
obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o vexpress-sysreg.o
|
||||
|
277
drivers/mfd/vexpress-config.c
Normal file
277
drivers/mfd/vexpress-config.c
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
* 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 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.
|
||||
*
|
||||
* Copyright (C) 2012 ARM Limited
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "vexpress-config: " fmt
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/vexpress.h>
|
||||
|
||||
|
||||
#define VEXPRESS_CONFIG_MAX_BRIDGES 2
|
||||
|
||||
struct vexpress_config_bridge {
|
||||
struct device_node *node;
|
||||
struct vexpress_config_bridge_info *info;
|
||||
struct list_head transactions;
|
||||
spinlock_t transactions_lock;
|
||||
} vexpress_config_bridges[VEXPRESS_CONFIG_MAX_BRIDGES];
|
||||
|
||||
static DECLARE_BITMAP(vexpress_config_bridges_map,
|
||||
ARRAY_SIZE(vexpress_config_bridges));
|
||||
static DEFINE_MUTEX(vexpress_config_bridges_mutex);
|
||||
|
||||
struct vexpress_config_bridge *vexpress_config_bridge_register(
|
||||
struct device_node *node,
|
||||
struct vexpress_config_bridge_info *info)
|
||||
{
|
||||
struct vexpress_config_bridge *bridge;
|
||||
int i;
|
||||
|
||||
pr_debug("Registering bridge '%s'\n", info->name);
|
||||
|
||||
mutex_lock(&vexpress_config_bridges_mutex);
|
||||
i = find_first_zero_bit(vexpress_config_bridges_map,
|
||||
ARRAY_SIZE(vexpress_config_bridges));
|
||||
if (i >= ARRAY_SIZE(vexpress_config_bridges)) {
|
||||
pr_err("Can't register more bridges!\n");
|
||||
mutex_unlock(&vexpress_config_bridges_mutex);
|
||||
return NULL;
|
||||
}
|
||||
__set_bit(i, vexpress_config_bridges_map);
|
||||
bridge = &vexpress_config_bridges[i];
|
||||
|
||||
bridge->node = node;
|
||||
bridge->info = info;
|
||||
INIT_LIST_HEAD(&bridge->transactions);
|
||||
spin_lock_init(&bridge->transactions_lock);
|
||||
|
||||
mutex_unlock(&vexpress_config_bridges_mutex);
|
||||
|
||||
return bridge;
|
||||
}
|
||||
|
||||
void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge)
|
||||
{
|
||||
struct vexpress_config_bridge __bridge = *bridge;
|
||||
int i;
|
||||
|
||||
mutex_lock(&vexpress_config_bridges_mutex);
|
||||
for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++)
|
||||
if (&vexpress_config_bridges[i] == bridge)
|
||||
__clear_bit(i, vexpress_config_bridges_map);
|
||||
mutex_unlock(&vexpress_config_bridges_mutex);
|
||||
|
||||
WARN_ON(!list_empty(&__bridge.transactions));
|
||||
while (!list_empty(&__bridge.transactions))
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
|
||||
struct vexpress_config_func {
|
||||
struct vexpress_config_bridge *bridge;
|
||||
void *func;
|
||||
};
|
||||
|
||||
struct vexpress_config_func *__vexpress_config_func_get(struct device *dev,
|
||||
struct device_node *node)
|
||||
{
|
||||
struct device_node *bridge_node;
|
||||
struct vexpress_config_func *func;
|
||||
int i;
|
||||
|
||||
if (WARN_ON(dev && node && dev->of_node != node))
|
||||
return NULL;
|
||||
if (dev && !node)
|
||||
node = dev->of_node;
|
||||
|
||||
func = kzalloc(sizeof(*func), GFP_KERNEL);
|
||||
if (!func)
|
||||
return NULL;
|
||||
|
||||
bridge_node = of_node_get(node);
|
||||
while (bridge_node) {
|
||||
const __be32 *prop = of_get_property(bridge_node,
|
||||
"arm,vexpress,config-bridge", NULL);
|
||||
|
||||
if (prop) {
|
||||
bridge_node = of_find_node_by_phandle(
|
||||
be32_to_cpup(prop));
|
||||
break;
|
||||
}
|
||||
|
||||
bridge_node = of_get_next_parent(bridge_node);
|
||||
}
|
||||
|
||||
mutex_lock(&vexpress_config_bridges_mutex);
|
||||
for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++) {
|
||||
struct vexpress_config_bridge *bridge =
|
||||
&vexpress_config_bridges[i];
|
||||
|
||||
if (test_bit(i, vexpress_config_bridges_map) &&
|
||||
bridge->node == bridge_node) {
|
||||
func->bridge = bridge;
|
||||
func->func = bridge->info->func_get(dev, node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&vexpress_config_bridges_mutex);
|
||||
|
||||
if (!func->func) {
|
||||
of_node_put(node);
|
||||
kfree(func);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
void vexpress_config_func_put(struct vexpress_config_func *func)
|
||||
{
|
||||
func->bridge->info->func_put(func->func);
|
||||
of_node_put(func->bridge->node);
|
||||
kfree(func);
|
||||
}
|
||||
|
||||
|
||||
struct vexpress_config_trans {
|
||||
struct vexpress_config_func *func;
|
||||
int offset;
|
||||
bool write;
|
||||
u32 *data;
|
||||
int status;
|
||||
struct completion completion;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static void vexpress_config_dump_trans(const char *what,
|
||||
struct vexpress_config_trans *trans)
|
||||
{
|
||||
pr_debug("%s %s trans %p func 0x%p offset %d data 0x%x status %d\n",
|
||||
what, trans->write ? "write" : "read", trans,
|
||||
trans->func->func, trans->offset,
|
||||
trans->data ? *trans->data : 0, trans->status);
|
||||
}
|
||||
|
||||
static int vexpress_config_schedule(struct vexpress_config_trans *trans)
|
||||
{
|
||||
int status;
|
||||
struct vexpress_config_bridge *bridge = trans->func->bridge;
|
||||
unsigned long flags;
|
||||
|
||||
init_completion(&trans->completion);
|
||||
trans->status = -EFAULT;
|
||||
|
||||
spin_lock_irqsave(&bridge->transactions_lock, flags);
|
||||
|
||||
vexpress_config_dump_trans("Executing", trans);
|
||||
|
||||
if (list_empty(&bridge->transactions))
|
||||
status = bridge->info->func_exec(trans->func->func,
|
||||
trans->offset, trans->write, trans->data);
|
||||
else
|
||||
status = VEXPRESS_CONFIG_STATUS_WAIT;
|
||||
|
||||
switch (status) {
|
||||
case VEXPRESS_CONFIG_STATUS_DONE:
|
||||
vexpress_config_dump_trans("Finished", trans);
|
||||
trans->status = status;
|
||||
break;
|
||||
case VEXPRESS_CONFIG_STATUS_WAIT:
|
||||
list_add_tail(&trans->list, &bridge->transactions);
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&bridge->transactions_lock, flags);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void vexpress_config_complete(struct vexpress_config_bridge *bridge,
|
||||
int status)
|
||||
{
|
||||
struct vexpress_config_trans *trans;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&bridge->transactions_lock, flags);
|
||||
|
||||
trans = list_first_entry(&bridge->transactions,
|
||||
struct vexpress_config_trans, list);
|
||||
vexpress_config_dump_trans("Completed", trans);
|
||||
|
||||
trans->status = status;
|
||||
list_del(&trans->list);
|
||||
|
||||
if (!list_empty(&bridge->transactions)) {
|
||||
vexpress_config_dump_trans("Pending", trans);
|
||||
|
||||
bridge->info->func_exec(trans->func->func, trans->offset,
|
||||
trans->write, trans->data);
|
||||
}
|
||||
spin_unlock_irqrestore(&bridge->transactions_lock, flags);
|
||||
|
||||
complete(&trans->completion);
|
||||
}
|
||||
|
||||
int vexpress_config_wait(struct vexpress_config_trans *trans)
|
||||
{
|
||||
wait_for_completion(&trans->completion);
|
||||
|
||||
return trans->status;
|
||||
}
|
||||
|
||||
|
||||
int vexpress_config_read(struct vexpress_config_func *func, int offset,
|
||||
u32 *data)
|
||||
{
|
||||
struct vexpress_config_trans trans = {
|
||||
.func = func,
|
||||
.offset = offset,
|
||||
.write = false,
|
||||
.data = data,
|
||||
.status = 0,
|
||||
};
|
||||
int status = vexpress_config_schedule(&trans);
|
||||
|
||||
if (status == VEXPRESS_CONFIG_STATUS_WAIT)
|
||||
status = vexpress_config_wait(&trans);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(vexpress_config_read);
|
||||
|
||||
int vexpress_config_write(struct vexpress_config_func *func, int offset,
|
||||
u32 data)
|
||||
{
|
||||
struct vexpress_config_trans trans = {
|
||||
.func = func,
|
||||
.offset = offset,
|
||||
.write = true,
|
||||
.data = &data,
|
||||
.status = 0,
|
||||
};
|
||||
int status = vexpress_config_schedule(&trans);
|
||||
|
||||
if (status == VEXPRESS_CONFIG_STATUS_WAIT)
|
||||
status = vexpress_config_wait(&trans);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(vexpress_config_write);
|
552
drivers/mfd/vexpress-sysreg.c
Normal file
552
drivers/mfd/vexpress-sysreg.c
Normal file
@ -0,0 +1,552 @@
|
||||
/*
|
||||
* 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 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.
|
||||
*
|
||||
* Copyright (C) 2012 ARM Limited
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/vexpress.h>
|
||||
|
||||
#define SYS_ID 0x000
|
||||
#define SYS_SW 0x004
|
||||
#define SYS_LED 0x008
|
||||
#define SYS_100HZ 0x024
|
||||
#define SYS_FLAGS 0x030
|
||||
#define SYS_FLAGSSET 0x030
|
||||
#define SYS_FLAGSCLR 0x034
|
||||
#define SYS_NVFLAGS 0x038
|
||||
#define SYS_NVFLAGSSET 0x038
|
||||
#define SYS_NVFLAGSCLR 0x03c
|
||||
#define SYS_MCI 0x048
|
||||
#define SYS_FLASH 0x04c
|
||||
#define SYS_CFGSW 0x058
|
||||
#define SYS_24MHZ 0x05c
|
||||
#define SYS_MISC 0x060
|
||||
#define SYS_DMA 0x064
|
||||
#define SYS_PROCID0 0x084
|
||||
#define SYS_PROCID1 0x088
|
||||
#define SYS_CFGDATA 0x0a0
|
||||
#define SYS_CFGCTRL 0x0a4
|
||||
#define SYS_CFGSTAT 0x0a8
|
||||
|
||||
#define SYS_HBI_MASK 0xfff
|
||||
#define SYS_ID_HBI_SHIFT 16
|
||||
#define SYS_PROCIDx_HBI_SHIFT 0
|
||||
|
||||
#define SYS_MCI_CARDIN (1 << 0)
|
||||
#define SYS_MCI_WPROT (1 << 1)
|
||||
|
||||
#define SYS_FLASH_WPn (1 << 0)
|
||||
|
||||
#define SYS_MISC_MASTERSITE (1 << 14)
|
||||
|
||||
#define SYS_CFGCTRL_START (1 << 31)
|
||||
#define SYS_CFGCTRL_WRITE (1 << 30)
|
||||
#define SYS_CFGCTRL_DCC(n) (((n) & 0xf) << 26)
|
||||
#define SYS_CFGCTRL_FUNC(n) (((n) & 0x3f) << 20)
|
||||
#define SYS_CFGCTRL_SITE(n) (((n) & 0x3) << 16)
|
||||
#define SYS_CFGCTRL_POSITION(n) (((n) & 0xf) << 12)
|
||||
#define SYS_CFGCTRL_DEVICE(n) (((n) & 0xfff) << 0)
|
||||
|
||||
#define SYS_CFGSTAT_ERR (1 << 1)
|
||||
#define SYS_CFGSTAT_COMPLETE (1 << 0)
|
||||
|
||||
|
||||
static void __iomem *vexpress_sysreg_base;
|
||||
static struct device *vexpress_sysreg_dev;
|
||||
static int vexpress_master_site;
|
||||
|
||||
|
||||
void vexpress_flags_set(u32 data)
|
||||
{
|
||||
writel(~0, vexpress_sysreg_base + SYS_FLAGSCLR);
|
||||
writel(data, vexpress_sysreg_base + SYS_FLAGSSET);
|
||||
}
|
||||
|
||||
u32 vexpress_get_procid(int site)
|
||||
{
|
||||
if (site == VEXPRESS_SITE_MASTER)
|
||||
site = vexpress_master_site;
|
||||
|
||||
return readl(vexpress_sysreg_base + (site == VEXPRESS_SITE_DB1 ?
|
||||
SYS_PROCID0 : SYS_PROCID1));
|
||||
}
|
||||
|
||||
u32 vexpress_get_hbi(int site)
|
||||
{
|
||||
u32 id;
|
||||
|
||||
switch (site) {
|
||||
case VEXPRESS_SITE_MB:
|
||||
id = readl(vexpress_sysreg_base + SYS_ID);
|
||||
return (id >> SYS_ID_HBI_SHIFT) & SYS_HBI_MASK;
|
||||
case VEXPRESS_SITE_MASTER:
|
||||
case VEXPRESS_SITE_DB1:
|
||||
case VEXPRESS_SITE_DB2:
|
||||
id = vexpress_get_procid(site);
|
||||
return (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK;
|
||||
}
|
||||
|
||||
return ~0;
|
||||
}
|
||||
|
||||
void __iomem *vexpress_get_24mhz_clock_base(void)
|
||||
{
|
||||
return vexpress_sysreg_base + SYS_24MHZ;
|
||||
}
|
||||
|
||||
|
||||
static void vexpress_sysreg_find_prop(struct device_node *node,
|
||||
const char *name, u32 *val)
|
||||
{
|
||||
of_node_get(node);
|
||||
while (node) {
|
||||
if (of_property_read_u32(node, name, val) == 0) {
|
||||
of_node_put(node);
|
||||
return;
|
||||
}
|
||||
node = of_get_next_parent(node);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned __vexpress_get_site(struct device *dev, struct device_node *node)
|
||||
{
|
||||
u32 site = 0;
|
||||
|
||||
WARN_ON(dev && node && dev->of_node != node);
|
||||
if (dev && !node)
|
||||
node = dev->of_node;
|
||||
|
||||
if (node) {
|
||||
vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site);
|
||||
} else if (dev && dev->bus == &platform_bus_type) {
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
if (pdev->num_resources == 1 &&
|
||||
pdev->resource[0].flags == IORESOURCE_BUS)
|
||||
site = pdev->resource[0].start;
|
||||
} else if (dev && strncmp(dev_name(dev), "ct:", 3) == 0) {
|
||||
site = VEXPRESS_SITE_MASTER;
|
||||
}
|
||||
|
||||
if (site == VEXPRESS_SITE_MASTER)
|
||||
site = vexpress_master_site;
|
||||
|
||||
return site;
|
||||
}
|
||||
|
||||
|
||||
struct vexpress_sysreg_config_func {
|
||||
u32 template;
|
||||
u32 device;
|
||||
};
|
||||
|
||||
static struct vexpress_config_bridge *vexpress_sysreg_config_bridge;
|
||||
static struct timer_list vexpress_sysreg_config_timer;
|
||||
static u32 *vexpress_sysreg_config_data;
|
||||
static int vexpress_sysreg_config_tries;
|
||||
|
||||
static void *vexpress_sysreg_config_func_get(struct device *dev,
|
||||
struct device_node *node)
|
||||
{
|
||||
struct vexpress_sysreg_config_func *config_func;
|
||||
u32 site;
|
||||
u32 position = 0;
|
||||
u32 dcc = 0;
|
||||
u32 func_device[2];
|
||||
int err = -EFAULT;
|
||||
|
||||
if (node) {
|
||||
of_node_get(node);
|
||||
vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site);
|
||||
vexpress_sysreg_find_prop(node, "arm,vexpress,position",
|
||||
&position);
|
||||
vexpress_sysreg_find_prop(node, "arm,vexpress,dcc", &dcc);
|
||||
err = of_property_read_u32_array(node,
|
||||
"arm,vexpress-sysreg,func", func_device,
|
||||
ARRAY_SIZE(func_device));
|
||||
of_node_put(node);
|
||||
} else if (dev && dev->bus == &platform_bus_type) {
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
if (pdev->num_resources == 1 &&
|
||||
pdev->resource[0].flags == IORESOURCE_BUS) {
|
||||
site = pdev->resource[0].start;
|
||||
func_device[0] = pdev->resource[0].end;
|
||||
func_device[1] = pdev->id;
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
config_func = kzalloc(sizeof(*config_func), GFP_KERNEL);
|
||||
if (!config_func)
|
||||
return NULL;
|
||||
|
||||
config_func->template = SYS_CFGCTRL_DCC(dcc);
|
||||
config_func->template |= SYS_CFGCTRL_FUNC(func_device[0]);
|
||||
config_func->template |= SYS_CFGCTRL_SITE(site == VEXPRESS_SITE_MASTER ?
|
||||
vexpress_master_site : site);
|
||||
config_func->template |= SYS_CFGCTRL_POSITION(position);
|
||||
config_func->device |= func_device[1];
|
||||
|
||||
dev_dbg(vexpress_sysreg_dev, "func 0x%p = 0x%x, %d\n", config_func,
|
||||
config_func->template, config_func->device);
|
||||
|
||||
return config_func;
|
||||
}
|
||||
|
||||
static void vexpress_sysreg_config_func_put(void *func)
|
||||
{
|
||||
kfree(func);
|
||||
}
|
||||
|
||||
static int vexpress_sysreg_config_func_exec(void *func, int offset,
|
||||
bool write, u32 *data)
|
||||
{
|
||||
int status;
|
||||
struct vexpress_sysreg_config_func *config_func = func;
|
||||
u32 command;
|
||||
|
||||
if (WARN_ON(!vexpress_sysreg_base))
|
||||
return -ENOENT;
|
||||
|
||||
command = readl(vexpress_sysreg_base + SYS_CFGCTRL);
|
||||
if (WARN_ON(command & SYS_CFGCTRL_START))
|
||||
return -EBUSY;
|
||||
|
||||
command = SYS_CFGCTRL_START;
|
||||
command |= write ? SYS_CFGCTRL_WRITE : 0;
|
||||
command |= config_func->template;
|
||||
command |= SYS_CFGCTRL_DEVICE(config_func->device + offset);
|
||||
|
||||
/* Use a canary for reads */
|
||||
if (!write)
|
||||
*data = 0xdeadbeef;
|
||||
|
||||
dev_dbg(vexpress_sysreg_dev, "command %x, data %x\n",
|
||||
command, *data);
|
||||
writel(*data, vexpress_sysreg_base + SYS_CFGDATA);
|
||||
writel(0, vexpress_sysreg_base + SYS_CFGSTAT);
|
||||
writel(command, vexpress_sysreg_base + SYS_CFGCTRL);
|
||||
mb();
|
||||
|
||||
if (vexpress_sysreg_dev) {
|
||||
/* Schedule completion check */
|
||||
if (!write)
|
||||
vexpress_sysreg_config_data = data;
|
||||
vexpress_sysreg_config_tries = 100;
|
||||
mod_timer(&vexpress_sysreg_config_timer,
|
||||
jiffies + usecs_to_jiffies(100));
|
||||
status = VEXPRESS_CONFIG_STATUS_WAIT;
|
||||
} else {
|
||||
/* Early execution, no timer available, have to spin */
|
||||
u32 cfgstat;
|
||||
|
||||
do {
|
||||
cpu_relax();
|
||||
cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT);
|
||||
} while (!cfgstat);
|
||||
|
||||
if (!write && (cfgstat & SYS_CFGSTAT_COMPLETE))
|
||||
*data = readl(vexpress_sysreg_base + SYS_CFGDATA);
|
||||
status = VEXPRESS_CONFIG_STATUS_DONE;
|
||||
|
||||
if (cfgstat & SYS_CFGSTAT_ERR)
|
||||
status = -EINVAL;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
struct vexpress_config_bridge_info vexpress_sysreg_config_bridge_info = {
|
||||
.name = "vexpress-sysreg",
|
||||
.func_get = vexpress_sysreg_config_func_get,
|
||||
.func_put = vexpress_sysreg_config_func_put,
|
||||
.func_exec = vexpress_sysreg_config_func_exec,
|
||||
};
|
||||
|
||||
static void vexpress_sysreg_config_complete(unsigned long data)
|
||||
{
|
||||
int status = VEXPRESS_CONFIG_STATUS_DONE;
|
||||
u32 cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT);
|
||||
|
||||
if (cfgstat & SYS_CFGSTAT_ERR)
|
||||
status = -EINVAL;
|
||||
if (!vexpress_sysreg_config_tries--)
|
||||
status = -ETIMEDOUT;
|
||||
|
||||
if (status < 0) {
|
||||
dev_err(vexpress_sysreg_dev, "error %d\n", status);
|
||||
} else if (!(cfgstat & SYS_CFGSTAT_COMPLETE)) {
|
||||
mod_timer(&vexpress_sysreg_config_timer,
|
||||
jiffies + usecs_to_jiffies(50));
|
||||
return;
|
||||
}
|
||||
|
||||
if (vexpress_sysreg_config_data) {
|
||||
*vexpress_sysreg_config_data = readl(vexpress_sysreg_base +
|
||||
SYS_CFGDATA);
|
||||
dev_dbg(vexpress_sysreg_dev, "read data %x\n",
|
||||
*vexpress_sysreg_config_data);
|
||||
vexpress_sysreg_config_data = NULL;
|
||||
}
|
||||
|
||||
vexpress_config_complete(vexpress_sysreg_config_bridge, status);
|
||||
}
|
||||
|
||||
|
||||
void __init vexpress_sysreg_early_init(void __iomem *base)
|
||||
{
|
||||
struct device_node *node = of_find_compatible_node(NULL, NULL,
|
||||
"arm,vexpress-sysreg");
|
||||
|
||||
if (node)
|
||||
base = of_iomap(node, 0);
|
||||
|
||||
if (WARN_ON(!base))
|
||||
return;
|
||||
|
||||
vexpress_sysreg_base = base;
|
||||
|
||||
if (readl(vexpress_sysreg_base + SYS_MISC) & SYS_MISC_MASTERSITE)
|
||||
vexpress_master_site = VEXPRESS_SITE_DB2;
|
||||
else
|
||||
vexpress_master_site = VEXPRESS_SITE_DB1;
|
||||
|
||||
vexpress_sysreg_config_bridge = vexpress_config_bridge_register(
|
||||
node, &vexpress_sysreg_config_bridge_info);
|
||||
WARN_ON(!vexpress_sysreg_config_bridge);
|
||||
}
|
||||
|
||||
void __init vexpress_sysreg_of_early_init(void)
|
||||
{
|
||||
vexpress_sysreg_early_init(NULL);
|
||||
}
|
||||
|
||||
|
||||
static struct vexpress_sysreg_gpio {
|
||||
unsigned long reg;
|
||||
u32 value;
|
||||
} vexpress_sysreg_gpios[] = {
|
||||
[VEXPRESS_GPIO_MMC_CARDIN] = {
|
||||
.reg = SYS_MCI,
|
||||
.value = SYS_MCI_CARDIN,
|
||||
},
|
||||
[VEXPRESS_GPIO_MMC_WPROT] = {
|
||||
.reg = SYS_MCI,
|
||||
.value = SYS_MCI_WPROT,
|
||||
},
|
||||
[VEXPRESS_GPIO_FLASH_WPn] = {
|
||||
.reg = SYS_FLASH,
|
||||
.value = SYS_FLASH_WPn,
|
||||
},
|
||||
};
|
||||
|
||||
static int vexpress_sysreg_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vexpress_sysreg_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vexpress_sysreg_gpio_get(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
{
|
||||
struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset];
|
||||
u32 reg_value = readl(vexpress_sysreg_base + gpio->reg);
|
||||
|
||||
return !!(reg_value & gpio->value);
|
||||
}
|
||||
|
||||
static void vexpress_sysreg_gpio_set(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset];
|
||||
u32 reg_value = readl(vexpress_sysreg_base + gpio->reg);
|
||||
|
||||
if (value)
|
||||
reg_value |= gpio->value;
|
||||
else
|
||||
reg_value &= ~gpio->value;
|
||||
|
||||
writel(reg_value, vexpress_sysreg_base + gpio->reg);
|
||||
}
|
||||
|
||||
static struct gpio_chip vexpress_sysreg_gpio_chip = {
|
||||
.label = "vexpress-sysreg",
|
||||
.direction_input = vexpress_sysreg_gpio_direction_input,
|
||||
.direction_output = vexpress_sysreg_gpio_direction_output,
|
||||
.get = vexpress_sysreg_gpio_get,
|
||||
.set = vexpress_sysreg_gpio_set,
|
||||
.ngpio = ARRAY_SIZE(vexpress_sysreg_gpios),
|
||||
.base = 0,
|
||||
};
|
||||
|
||||
|
||||
static ssize_t vexpress_sysreg_sys_id_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "0x%08x\n", readl(vexpress_sysreg_base + SYS_ID));
|
||||
}
|
||||
|
||||
DEVICE_ATTR(sys_id, S_IRUGO, vexpress_sysreg_sys_id_show, NULL);
|
||||
|
||||
static int __devinit vexpress_sysreg_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
struct resource *res = platform_get_resource(pdev,
|
||||
IORESOURCE_MEM, 0);
|
||||
|
||||
if (!devm_request_mem_region(&pdev->dev, res->start,
|
||||
resource_size(res), pdev->name)) {
|
||||
dev_err(&pdev->dev, "Failed to request memory region!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (!vexpress_sysreg_base)
|
||||
vexpress_sysreg_base = devm_ioremap(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
|
||||
if (!vexpress_sysreg_base) {
|
||||
dev_err(&pdev->dev, "Failed to obtain base address!\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
setup_timer(&vexpress_sysreg_config_timer,
|
||||
vexpress_sysreg_config_complete, 0);
|
||||
|
||||
vexpress_sysreg_gpio_chip.dev = &pdev->dev;
|
||||
err = gpiochip_add(&vexpress_sysreg_gpio_chip);
|
||||
if (err) {
|
||||
vexpress_config_bridge_unregister(
|
||||
vexpress_sysreg_config_bridge);
|
||||
dev_err(&pdev->dev, "Failed to register GPIO chip! (%d)\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
vexpress_sysreg_dev = &pdev->dev;
|
||||
|
||||
device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id vexpress_sysreg_match[] = {
|
||||
{ .compatible = "arm,vexpress-sysreg", },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver vexpress_sysreg_driver = {
|
||||
.driver = {
|
||||
.name = "vexpress-sysreg",
|
||||
.of_match_table = vexpress_sysreg_match,
|
||||
},
|
||||
.probe = vexpress_sysreg_probe,
|
||||
};
|
||||
|
||||
static int __init vexpress_sysreg_init(void)
|
||||
{
|
||||
return platform_driver_register(&vexpress_sysreg_driver);
|
||||
}
|
||||
core_initcall(vexpress_sysreg_init);
|
||||
|
||||
|
||||
#if defined(CONFIG_LEDS_CLASS)
|
||||
|
||||
struct vexpress_sysreg_led {
|
||||
u32 mask;
|
||||
struct led_classdev cdev;
|
||||
} vexpress_sysreg_leds[] = {
|
||||
{ .mask = 1 << 0, .cdev.name = "v2m:green:user1",
|
||||
.cdev.default_trigger = "heartbeat", },
|
||||
{ .mask = 1 << 1, .cdev.name = "v2m:green:user2",
|
||||
.cdev.default_trigger = "mmc0", },
|
||||
{ .mask = 1 << 2, .cdev.name = "v2m:green:user3",
|
||||
.cdev.default_trigger = "cpu0", },
|
||||
{ .mask = 1 << 3, .cdev.name = "v2m:green:user4",
|
||||
.cdev.default_trigger = "cpu1", },
|
||||
{ .mask = 1 << 4, .cdev.name = "v2m:green:user5",
|
||||
.cdev.default_trigger = "cpu2", },
|
||||
{ .mask = 1 << 5, .cdev.name = "v2m:green:user6",
|
||||
.cdev.default_trigger = "cpu3", },
|
||||
{ .mask = 1 << 6, .cdev.name = "v2m:green:user7",
|
||||
.cdev.default_trigger = "cpu4", },
|
||||
{ .mask = 1 << 7, .cdev.name = "v2m:green:user8",
|
||||
.cdev.default_trigger = "cpu5", },
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(vexpress_sysreg_leds_lock);
|
||||
|
||||
static void vexpress_sysreg_led_brightness_set(struct led_classdev *cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct vexpress_sysreg_led *led = container_of(cdev,
|
||||
struct vexpress_sysreg_led, cdev);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&vexpress_sysreg_leds_lock, flags);
|
||||
|
||||
val = readl(vexpress_sysreg_base + SYS_LED);
|
||||
if (brightness == LED_OFF)
|
||||
val &= ~led->mask;
|
||||
else
|
||||
val |= led->mask;
|
||||
writel(val, vexpress_sysreg_base + SYS_LED);
|
||||
|
||||
spin_unlock_irqrestore(&vexpress_sysreg_leds_lock, flags);
|
||||
}
|
||||
|
||||
static int __init vexpress_sysreg_init_leds(void)
|
||||
{
|
||||
struct vexpress_sysreg_led *led;
|
||||
int i;
|
||||
|
||||
/* Clear all user LEDs */
|
||||
writel(0, vexpress_sysreg_base + SYS_LED);
|
||||
|
||||
for (i = 0, led = vexpress_sysreg_leds;
|
||||
i < ARRAY_SIZE(vexpress_sysreg_leds); i++, led++) {
|
||||
int err;
|
||||
|
||||
led->cdev.brightness_set = vexpress_sysreg_led_brightness_set;
|
||||
err = led_classdev_register(vexpress_sysreg_dev, &led->cdev);
|
||||
if (err) {
|
||||
dev_err(vexpress_sysreg_dev,
|
||||
"Failed to register LED %d! (%d)\n",
|
||||
i, err);
|
||||
while (led--, i--)
|
||||
led_classdev_unregister(&led->cdev);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
device_initcall(vexpress_sysreg_init_leds);
|
||||
|
||||
#endif
|
121
include/linux/vexpress.h
Normal file
121
include/linux/vexpress.h
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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 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.
|
||||
*
|
||||
* Copyright (C) 2012 ARM Limited
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_VEXPRESS_H
|
||||
#define _LINUX_VEXPRESS_H
|
||||
|
||||
#include <linux/device.h>
|
||||
|
||||
#define VEXPRESS_SITE_MB 0
|
||||
#define VEXPRESS_SITE_DB1 1
|
||||
#define VEXPRESS_SITE_DB2 2
|
||||
#define VEXPRESS_SITE_MASTER 0xf
|
||||
|
||||
#define VEXPRESS_CONFIG_STATUS_DONE 0
|
||||
#define VEXPRESS_CONFIG_STATUS_WAIT 1
|
||||
|
||||
#define VEXPRESS_GPIO_MMC_CARDIN 0
|
||||
#define VEXPRESS_GPIO_MMC_WPROT 1
|
||||
#define VEXPRESS_GPIO_FLASH_WPn 2
|
||||
|
||||
#define VEXPRESS_RES_FUNC(_site, _func) \
|
||||
{ \
|
||||
.start = (_site), \
|
||||
.end = (_func), \
|
||||
.flags = IORESOURCE_BUS, \
|
||||
}
|
||||
|
||||
/* Config bridge API */
|
||||
|
||||
/**
|
||||
* struct vexpress_config_bridge_info - description of the platform
|
||||
* configuration infrastructure bridge.
|
||||
*
|
||||
* @name: Bridge name
|
||||
*
|
||||
* @func_get: Obtains pointer to a configuration function for a given
|
||||
* device or a Device Tree node, to be used with @func_put
|
||||
* and @func_exec. The node pointer should take precedence
|
||||
* over device pointer when both are passed.
|
||||
*
|
||||
* @func_put: Tells the bridge that the function will not be used any
|
||||
* more, so all allocated resources can be released.
|
||||
*
|
||||
* @func_exec: Executes a configuration function read or write operation.
|
||||
* The offset selects a 32 bit word of the value accessed.
|
||||
* Must return VEXPRESS_CONFIG_STATUS_DONE when operation
|
||||
* is finished immediately, VEXPRESS_CONFIG_STATUS_WAIT when
|
||||
* will be completed in some time or negative value in case
|
||||
* of error.
|
||||
*/
|
||||
struct vexpress_config_bridge_info {
|
||||
const char *name;
|
||||
void *(*func_get)(struct device *dev, struct device_node *node);
|
||||
void (*func_put)(void *func);
|
||||
int (*func_exec)(void *func, int offset, bool write, u32 *data);
|
||||
};
|
||||
|
||||
struct vexpress_config_bridge;
|
||||
|
||||
struct vexpress_config_bridge *vexpress_config_bridge_register(
|
||||
struct device_node *node,
|
||||
struct vexpress_config_bridge_info *info);
|
||||
void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge);
|
||||
|
||||
void vexpress_config_complete(struct vexpress_config_bridge *bridge,
|
||||
int status);
|
||||
|
||||
/* Config function API */
|
||||
|
||||
struct vexpress_config_func;
|
||||
|
||||
struct vexpress_config_func *__vexpress_config_func_get(struct device *dev,
|
||||
struct device_node *node);
|
||||
#define vexpress_config_func_get_by_dev(dev) \
|
||||
__vexpress_config_func_get(dev, NULL)
|
||||
#define vexpress_config_func_get_by_node(node) \
|
||||
__vexpress_config_func_get(NULL, node)
|
||||
void vexpress_config_func_put(struct vexpress_config_func *func);
|
||||
|
||||
/* Both may sleep! */
|
||||
int vexpress_config_read(struct vexpress_config_func *func, int offset,
|
||||
u32 *data);
|
||||
int vexpress_config_write(struct vexpress_config_func *func, int offset,
|
||||
u32 data);
|
||||
|
||||
/* Platform control */
|
||||
|
||||
u32 vexpress_get_procid(int site);
|
||||
u32 vexpress_get_hbi(int site);
|
||||
void *vexpress_get_24mhz_clock_base(void);
|
||||
void vexpress_flags_set(u32 data);
|
||||
|
||||
#define vexpress_get_site_by_node(node) __vexpress_get_site(NULL, node)
|
||||
#define vexpress_get_site_by_dev(dev) __vexpress_get_site(dev, NULL)
|
||||
unsigned __vexpress_get_site(struct device *dev, struct device_node *node);
|
||||
|
||||
void vexpress_sysreg_early_init(void __iomem *base);
|
||||
void vexpress_sysreg_of_early_init(void);
|
||||
|
||||
void vexpress_power_off(void);
|
||||
void vexpress_restart(char str, const char *cmd);
|
||||
|
||||
/* Clocks */
|
||||
|
||||
struct clk *vexpress_osc_setup(struct device *dev);
|
||||
void vexpress_osc_of_setup(struct device_node *node);
|
||||
|
||||
void vexpress_clk_init(void __iomem *sp810_base);
|
||||
void vexpress_clk_of_init(void);
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user