提交 c2714334 编写于 作者: L Linus Torvalds

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

Pull ARM SoC updates for Marvell mvebu/kirkwood from Olof Johansson:
 "This is a branch with updates for Marvell's mvebu/kirkwood platforms.
  They came in late-ish, and were heavily interdependent such that it
  didn't make sense to split them up across the cross-platform topic
  branches.  So here they are (for the second release in a row) in a
  branch on their own."

* tag 'mvebu' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (88 commits)
  arm: l2x0: add aurora related properties to OF binding
  arm: mvebu: add Aurora L2 Cache Controller to the DT
  arm: mvebu: add L2 cache support
  dma: mv_xor: fix error handling path
  dma: mv_xor: fix error checking of irq_of_parse_and_map()
  dma: mv_xor: use request_irq() instead of devm_request_irq()
  dma: mv_xor: clear the window override control registers
  arm: mvebu: fix address decoding armada_cfg_base() function
  ARM: mvebu: update defconfig with I2C and RTC support
  ARM: mvebu: Add SATA support for OpenBlocks AX3-4
  ARM: mvebu: Add support for the RTC in OpenBlocks AX3-4
  ARM: mvebu: Add support for I2C on OpenBlocks AX3-4
  ARM: mvebu: Add support for I2C controllers in Armada 370/XP
  arm: mvebu: Add hardware I/O Coherency support
  arm: plat-orion: Add coherency attribute when setup mbus target
  arm: dma mapping: Export a dma ops function arm_dma_set_mask
  arm: mvebu: Add SMP support for Armada XP
  arm: mm: Add support for PJ4B cpu and init routines
  arm: mvebu: Add IPI support via doorbells
  arm: mvebu: Add initial support for power managmement service unit
  ...
...@@ -6,9 +6,15 @@ Required properties: ...@@ -6,9 +6,15 @@ Required properties:
- interrupt-controller: Identifies the node as an interrupt controller. - interrupt-controller: Identifies the node as an interrupt controller.
- #interrupt-cells: The number of cells to define the interrupts. Should be 1. - #interrupt-cells: The number of cells to define the interrupts. Should be 1.
The cell is the IRQ number The cell is the IRQ number
- reg: Should contain PMIC registers location and length. First pair - reg: Should contain PMIC registers location and length. First pair
for the main interrupt registers, second pair for the per-CPU for the main interrupt registers, second pair for the per-CPU
interrupt registers interrupt registers. For this last pair, to be compliant with SMP
support, the "virtual" must be use (For the record, these registers
automatically map to the interrupt controller registers of the
current CPU)
Example: Example:
...@@ -18,6 +24,6 @@ Example: ...@@ -18,6 +24,6 @@ Example:
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
interrupt-controller; interrupt-controller;
reg = <0xd0020000 0x1000>, reg = <0xd0020a00 0x1d0>,
<0xd0021000 0x1000>; <0xd0021070 0x58>;
}; };
Power Management Service Unit(PMSU)
-----------------------------------
Available on Marvell SOCs: Armada 370 and Armada XP
Required properties:
- compatible: "marvell,armada-370-xp-pmsu"
- reg: Should contain PMSU registers location and length. First pair
for the per-CPU SW Reset Control registers, second pair for the
Power Management Service Unit.
Example:
armada-370-xp-pmsu@d0022000 {
compatible = "marvell,armada-370-xp-pmsu";
reg = <0xd0022100 0x430>,
<0xd0020800 0x20>;
};
...@@ -5,6 +5,7 @@ Required properties: ...@@ -5,6 +5,7 @@ Required properties:
- compatible: Should be "marvell,armada-370-xp-timer" - compatible: Should be "marvell,armada-370-xp-timer"
- interrupts: Should contain the list of Global Timer interrupts - interrupts: Should contain the list of Global Timer interrupts
- reg: Should contain the base address of the Global Timer registers - reg: Should contain the base address of the Global Timer registers
- clocks: clock driving the timer hardware
Optional properties: Optional properties:
- marvell,timer-25Mhz: Tells whether the Global timer supports the 25 - marvell,timer-25Mhz: Tells whether the Global timer supports the 25
......
Coherency fabric
----------------
Available on Marvell SOCs: Armada 370 and Armada XP
Required properties:
- compatible: "marvell,coherency-fabric"
- reg: Should contain coherency fabric registers location and
length. First pair for the coherency fabric registers, second pair
for the per-CPU fabric registers registers.
Example:
coherency-fabric@d0020200 {
compatible = "marvell,coherency-fabric";
reg = <0xd0020200 0xb0>,
<0xd0021810 0x1c>;
};
...@@ -10,6 +10,12 @@ Required properties: ...@@ -10,6 +10,12 @@ Required properties:
"arm,pl310-cache" "arm,pl310-cache"
"arm,l220-cache" "arm,l220-cache"
"arm,l210-cache" "arm,l210-cache"
"marvell,aurora-system-cache": Marvell Controller designed to be
compatible with the ARM one, with system cache mode (meaning
maintenance operations on L1 are broadcasted to the L2 and L2
performs the same operation).
"marvell,"aurora-outer-cache: Marvell Controller designed to be
compatible with the ARM one with outer cache mode.
- cache-unified : Specifies the cache is a unified cache. - cache-unified : Specifies the cache is a unified cache.
- cache-level : Should be set to 2 for a level 2 cache. - cache-level : Should be set to 2 for a level 2 cache.
- reg : Physical base address and size of cache controller's memory mapped - reg : Physical base address and size of cache controller's memory mapped
...@@ -29,6 +35,9 @@ Optional properties: ...@@ -29,6 +35,9 @@ Optional properties:
filter. Addresses in the filter window are directed to the M1 port. Other filter. Addresses in the filter window are directed to the M1 port. Other
addresses will go to the M0 port. addresses will go to the M0 port.
- interrupts : 1 combined interrupt. - interrupts : 1 combined interrupt.
- cache-id-part: cache id part number to be used if it is not present
on hardware
- wt-override: If present then L2 is forced to Write through mode
Example: Example:
......
* Core Clock bindings for Marvell MVEBU SoCs
Marvell MVEBU SoCs usually allow to determine core clock frequencies by
reading the Sample-At-Reset (SAR) register. The core clock consumer should
specify the desired clock by having the clock ID in its "clocks" phandle cell.
The following is a list of provided IDs and clock names on Armada 370/XP:
0 = tclk (Internal Bus clock)
1 = cpuclk (CPU clock)
2 = nbclk (L2 Cache clock)
3 = hclk (DRAM control clock)
4 = dramclk (DDR clock)
The following is a list of provided IDs and clock names on Kirkwood and Dove:
0 = tclk (Internal Bus clock)
1 = cpuclk (CPU0 clock)
2 = l2clk (L2 Cache clock derived from CPU0 clock)
3 = ddrclk (DDR controller clock derived from CPU0 clock)
Required properties:
- compatible : shall be one of the following:
"marvell,armada-370-core-clock" - For Armada 370 SoC core clocks
"marvell,armada-xp-core-clock" - For Armada XP SoC core clocks
"marvell,dove-core-clock" - for Dove SoC core clocks
"marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180)
"marvell,mv88f6180-core-clock" - for Kirkwood MV88f6180 SoC
- reg : shall be the register address of the Sample-At-Reset (SAR) register
- #clock-cells : from common clock binding; shall be set to 1
Optional properties:
- clock-output-names : from common clock binding; allows overwrite default clock
output names ("tclk", "cpuclk", "l2clk", "ddrclk")
Example:
core_clk: core-clocks@d0214 {
compatible = "marvell,dove-core-clock";
reg = <0xd0214 0x4>;
#clock-cells = <1>;
};
spi0: spi@10600 {
compatible = "marvell,orion-spi";
/* ... */
/* get tclk from core clock provider */
clocks = <&core_clk 0>;
};
Device Tree Clock bindings for cpu clock of Marvell EBU platforms
Required properties:
- compatible : shall be one of the following:
"marvell,armada-xp-cpu-clock" - cpu clocks for Armada XP
- reg : Address and length of the clock complex register set
- #clock-cells : should be set to 1.
- clocks : shall be the input parent clock phandle for the clock.
cpuclk: clock-complex@d0018700 {
#clock-cells = <1>;
compatible = "marvell,armada-xp-cpu-clock";
reg = <0xd0018700 0xA0>;
clocks = <&coreclk 1>;
}
cpu@0 {
compatible = "marvell,sheeva-v7";
reg = <0>;
clocks = <&cpuclk 0>;
};
* Gated Clock bindings for Marvell Orion SoCs
Marvell Dove and Kirkwood allow some peripheral clocks to be gated to save
some power. The clock consumer should specify the desired clock by having
the clock ID in its "clocks" phandle cell. The clock ID is directly mapped to
the corresponding clock gating control bit in HW to ease manual clock lookup
in datasheet.
The following is a list of provided IDs for Armada 370:
ID Clock Peripheral
-----------------------------------
0 Audio AC97 Cntrl
1 pex0_en PCIe 0 Clock out
2 pex1_en PCIe 1 Clock out
3 ge1 Gigabit Ethernet 1
4 ge0 Gigabit Ethernet 0
5 pex0 PCIe Cntrl 0
9 pex1 PCIe Cntrl 1
15 sata0 SATA Host 0
17 sdio SDHCI Host
25 tdm Time Division Mplx
28 ddr DDR Cntrl
30 sata1 SATA Host 0
The following is a list of provided IDs for Armada XP:
ID Clock Peripheral
-----------------------------------
0 audio Audio Cntrl
1 ge3 Gigabit Ethernet 3
2 ge2 Gigabit Ethernet 2
3 ge1 Gigabit Ethernet 1
4 ge0 Gigabit Ethernet 0
5 pex0 PCIe Cntrl 0
6 pex1 PCIe Cntrl 1
7 pex2 PCIe Cntrl 2
8 pex3 PCIe Cntrl 3
13 bp
14 sata0lnk
15 sata0 SATA Host 0
16 lcd LCD Cntrl
17 sdio SDHCI Host
18 usb0 USB Host 0
19 usb1 USB Host 1
20 usb2 USB Host 2
22 xor0 XOR DMA 0
23 crypto CESA engine
25 tdm Time Division Mplx
28 xor1 XOR DMA 1
29 sata1lnk
30 sata1 SATA Host 0
The following is a list of provided IDs for Dove:
ID Clock Peripheral
-----------------------------------
0 usb0 USB Host 0
1 usb1 USB Host 1
2 ge Gigabit Ethernet
3 sata SATA Host
4 pex0 PCIe Cntrl 0
5 pex1 PCIe Cntrl 1
8 sdio0 SDHCI Host 0
9 sdio1 SDHCI Host 1
10 nand NAND Cntrl
11 camera Camera Cntrl
12 i2s0 I2S Cntrl 0
13 i2s1 I2S Cntrl 1
15 crypto CESA engine
21 ac97 AC97 Cntrl
22 pdma Peripheral DMA
23 xor0 XOR DMA 0
24 xor1 XOR DMA 1
30 gephy Gigabit Ethernel PHY
Note: gephy(30) is implemented as a parent clock of ge(2)
The following is a list of provided IDs for Kirkwood:
ID Clock Peripheral
-----------------------------------
0 ge0 Gigabit Ethernet 0
2 pex0 PCIe Cntrl 0
3 usb0 USB Host 0
4 sdio SDIO Cntrl
5 tsu Transp. Stream Unit
6 dunit SDRAM Cntrl
7 runit Runit
8 xor0 XOR DMA 0
9 audio I2S Cntrl 0
14 sata0 SATA Host 0
15 sata1 SATA Host 1
16 xor1 XOR DMA 1
17 crypto CESA engine
18 pex1 PCIe Cntrl 1
19 ge1 Gigabit Ethernet 0
20 tdm Time Division Mplx
Required properties:
- compatible : shall be one of the following:
"marvell,dove-gating-clock" - for Dove SoC clock gating
"marvell,kirkwood-gating-clock" - for Kirkwood SoC clock gating
- reg : shall be the register address of the Clock Gating Control register
- #clock-cells : from common clock binding; shall be set to 1
Optional properties:
- clocks : default parent clock phandle (e.g. tclk)
Example:
gate_clk: clock-gating-control@d0038 {
compatible = "marvell,dove-gating-clock";
reg = <0xd0038 0x4>;
/* default parent clock is tclk */
clocks = <&core_clk 0>;
#clock-cells = <1>;
};
sdio0: sdio@92000 {
compatible = "marvell,dove-sdhci";
/* get clk gate bit 8 (sdio0) */
clocks = <&gate_clk 8>;
};
* Marvell XOR engines
Required properties:
- compatible: Should be "marvell,orion-xor"
- reg: Should contain registers location and length (two sets)
the first set is the low registers, the second set the high
registers for the XOR engine.
- clocks: pointer to the reference clock
The DT node must also contains sub-nodes for each XOR channel that the
XOR engine has. Those sub-nodes have the following required
properties:
- interrupts: interrupt of the XOR channel
And the following optional properties:
- dmacap,memcpy to indicate that the XOR channel is capable of memcpy operations
- dmacap,memset to indicate that the XOR channel is capable of memset operations
- dmacap,xor to indicate that the XOR channel is capable of xor operations
Example:
xor@d0060900 {
compatible = "marvell,orion-xor";
reg = <0xd0060900 0x100
0xd0060b00 0x100>;
clocks = <&coreclk 0>;
status = "okay";
xor00 {
interrupts = <51>;
dmacap,memcpy;
dmacap,xor;
};
xor01 {
interrupts = <52>;
dmacap,memcpy;
dmacap,xor;
dmacap,memset;
};
};
* Marvell Armada 370 / Armada XP Ethernet Controller (NETA)
Required properties:
- compatible: should be "marvell,armada-370-neta".
- reg: address and length of the register set for the device.
- interrupts: interrupt for the device
- phy: A phandle to a phy node defining the PHY address (as the reg
property, a single integer).
- phy-mode: The interface between the SoC and the PHY (a string that
of_get_phy_mode() can understand)
- clocks: a pointer to the reference clock for this device.
Example:
ethernet@d0070000 {
compatible = "marvell,armada-370-neta";
reg = <0xd0070000 0x2500>;
interrupts = <8>;
clocks = <&gate_clk 4>;
status = "okay";
phy = <&phy0>;
phy-mode = "rgmii-id";
};
* Marvell MDIO Ethernet Controller interface
The Ethernet controllers of the Marvel Kirkwood, Dove, Orion5x,
MV78xx0, Armada 370 and Armada XP have an identical unit that provides
an interface with the MDIO bus. This driver handles this MDIO
interface.
Required properties:
- compatible: "marvell,orion-mdio"
- reg: address and length of the SMI register
The child nodes of the MDIO driver are the individual PHY devices
connected to this MDIO bus. They must have a "reg" property given the
PHY address on the MDIO bus.
Example at the SoC level:
mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "marvell,orion-mdio";
reg = <0xd0072004 0x4>;
};
And at the board level:
mdio {
phy0: ethernet-phy@0 {
reg = <0>;
};
phy1: ethernet-phy@1 {
reg = <1>;
};
}
...@@ -4871,6 +4871,12 @@ S: Maintained ...@@ -4871,6 +4871,12 @@ S: Maintained
F: drivers/net/ethernet/marvell/mv643xx_eth.* F: drivers/net/ethernet/marvell/mv643xx_eth.*
F: include/linux/mv643xx.h F: include/linux/mv643xx.h
MARVELL MVNETA ETHERNET DRIVER
M: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/marvell/mvneta.*
MARVELL MWIFIEX WIRELESS DRIVER MARVELL MWIFIEX WIRELESS DRIVER
M: Bing Zhao <bzhao@marvell.com> M: Bing Zhao <bzhao@marvell.com>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
......
...@@ -533,6 +533,7 @@ config ARCH_IXP4XX ...@@ -533,6 +533,7 @@ config ARCH_IXP4XX
config ARCH_DOVE config ARCH_DOVE
bool "Marvell Dove" bool "Marvell Dove"
select ARCH_REQUIRE_GPIOLIB select ARCH_REQUIRE_GPIOLIB
select COMMON_CLK_DOVE
select CPU_V7 select CPU_V7
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select MIGHT_HAVE_PCI select MIGHT_HAVE_PCI
......
...@@ -77,7 +77,9 @@ dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-dns320.dtb \ ...@@ -77,7 +77,9 @@ dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-dns320.dtb \
dtb-$(CONFIG_ARCH_MSM) += msm8660-surf.dtb \ dtb-$(CONFIG_ARCH_MSM) += msm8660-surf.dtb \
msm8960-cdp.dtb msm8960-cdp.dtb
dtb-$(CONFIG_ARCH_MVEBU) += armada-370-db.dtb \ dtb-$(CONFIG_ARCH_MVEBU) += armada-370-db.dtb \
armada-xp-db.dtb armada-370-mirabox.dtb \
armada-xp-db.dtb \
armada-xp-openblocks-ax3-4.dtb
dtb-$(CONFIG_ARCH_MXC) += imx51-babbage.dtb \ dtb-$(CONFIG_ARCH_MXC) += imx51-babbage.dtb \
imx53-ard.dtb \ imx53-ard.dtb \
imx53-evk.dtb \ imx53-evk.dtb \
......
...@@ -34,9 +34,30 @@ ...@@ -34,9 +34,30 @@
clock-frequency = <200000000>; clock-frequency = <200000000>;
status = "okay"; status = "okay";
}; };
timer@d0020300 { sata@d00a0000 {
clock-frequency = <600000000>; nr-ports = <2>;
status = "okay"; status = "okay";
}; };
mdio {
phy0: ethernet-phy@0 {
reg = <0>;
};
phy1: ethernet-phy@1 {
reg = <1>;
};
};
ethernet@d0070000 {
status = "okay";
phy = <&phy0>;
phy-mode = "rgmii-id";
};
ethernet@d0074000 {
status = "okay";
phy = <&phy1>;
phy-mode = "rgmii-id";
};
}; };
}; };
/*
* Device Tree file for Globalscale Mirabox
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
/dts-v1/;
/include/ "armada-370.dtsi"
/ {
model = "Globalscale Mirabox";
compatible = "globalscale,mirabox", "marvell,armada370", "marvell,armada-370-xp";
chosen {
bootargs = "console=ttyS0,115200 earlyprintk";
};
memory {
device_type = "memory";
reg = <0x00000000 0x20000000>; /* 512 MB */
};
soc {
serial@d0012000 {
clock-frequency = <200000000>;
status = "okay";
};
timer@d0020300 {
clock-frequency = <600000000>;
status = "okay";
};
mdio {
phy0: ethernet-phy@0 {
reg = <0>;
};
phy1: ethernet-phy@1 {
reg = <1>;
};
};
ethernet@d0070000 {
status = "okay";
phy = <&phy0>;
phy-mode = "rgmii-id";
};
ethernet@d0074000 {
status = "okay";
phy = <&phy1>;
phy-mode = "rgmii-id";
};
};
};
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
/ { / {
model = "Marvell Armada 370 and XP SoC"; model = "Marvell Armada 370 and XP SoC";
compatible = "marvell,armada_370_xp"; compatible = "marvell,armada-370-xp";
cpus { cpus {
cpu@0 { cpu@0 {
...@@ -36,6 +36,12 @@ ...@@ -36,6 +36,12 @@
interrupt-controller; interrupt-controller;
}; };
coherency-fabric@d0020200 {
compatible = "marvell,coherency-fabric";
reg = <0xd0020200 0xb0>,
<0xd0021810 0x1c>;
};
soc { soc {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
...@@ -62,12 +68,67 @@ ...@@ -62,12 +68,67 @@
compatible = "marvell,armada-370-xp-timer"; compatible = "marvell,armada-370-xp-timer";
reg = <0xd0020300 0x30>; reg = <0xd0020300 0x30>;
interrupts = <37>, <38>, <39>, <40>; interrupts = <37>, <38>, <39>, <40>;
clocks = <&coreclk 2>;
}; };
addr-decoding@d0020000 { addr-decoding@d0020000 {
compatible = "marvell,armada-addr-decoding-controller"; compatible = "marvell,armada-addr-decoding-controller";
reg = <0xd0020000 0x258>; reg = <0xd0020000 0x258>;
}; };
sata@d00a0000 {
compatible = "marvell,orion-sata";
reg = <0xd00a0000 0x2400>;
interrupts = <55>;
clocks = <&gateclk 15>, <&gateclk 30>;
clock-names = "0", "1";
status = "disabled";
};
mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "marvell,orion-mdio";
reg = <0xd0072004 0x4>;
};
ethernet@d0070000 {
compatible = "marvell,armada-370-neta";
reg = <0xd0070000 0x2500>;
interrupts = <8>;
clocks = <&gateclk 4>;
status = "disabled";
};
ethernet@d0074000 {
compatible = "marvell,armada-370-neta";
reg = <0xd0074000 0x2500>;
interrupts = <10>;
clocks = <&gateclk 3>;
status = "disabled";
};
i2c0: i2c@d0011000 {
compatible = "marvell,mv64xxx-i2c";
reg = <0xd0011000 0x20>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <31>;
timeout-ms = <1000>;
clocks = <&coreclk 0>;
status = "disabled";
};
i2c1: i2c@d0011100 {
compatible = "marvell,mv64xxx-i2c";
reg = <0xd0011100 0x20>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <32>;
timeout-ms = <1000>;
clocks = <&coreclk 0>;
status = "disabled";
};
}; };
}; };
...@@ -20,6 +20,12 @@ ...@@ -20,6 +20,12 @@
/ { / {
model = "Marvell Armada 370 family SoC"; model = "Marvell Armada 370 family SoC";
compatible = "marvell,armada370", "marvell,armada-370-xp"; compatible = "marvell,armada370", "marvell,armada-370-xp";
L2: l2-cache {
compatible = "marvell,aurora-outer-cache";
reg = <0xd0008000 0x1000>;
cache-id-part = <0x100>;
wt-override;
};
aliases { aliases {
gpio0 = &gpio0; gpio0 = &gpio0;
...@@ -75,5 +81,56 @@ ...@@ -75,5 +81,56 @@
#interrupts-cells = <2>; #interrupts-cells = <2>;
interrupts = <91>; interrupts = <91>;
}; };
coreclk: mvebu-sar@d0018230 {
compatible = "marvell,armada-370-core-clock";
reg = <0xd0018230 0x08>;
#clock-cells = <1>;
};
gateclk: clock-gating-control@d0018220 {
compatible = "marvell,armada-370-gating-clock";
reg = <0xd0018220 0x4>;
clocks = <&coreclk 0>;
#clock-cells = <1>;
};
xor@d0060800 {
compatible = "marvell,orion-xor";
reg = <0xd0060800 0x100
0xd0060A00 0x100>;
status = "okay";
xor00 {
interrupts = <51>;
dmacap,memcpy;
dmacap,xor;
};
xor01 {
interrupts = <52>;
dmacap,memcpy;
dmacap,xor;
dmacap,memset;
};
};
xor@d0060900 {
compatible = "marvell,orion-xor";
reg = <0xd0060900 0x100
0xd0060b00 0x100>;
status = "okay";
xor10 {
interrupts = <94>;
dmacap,memcpy;
dmacap,xor;
};
xor11 {
interrupts = <95>;
dmacap,memcpy;
dmacap,xor;
dmacap,memset;
};
};
}; };
}; };
...@@ -46,5 +46,49 @@ ...@@ -46,5 +46,49 @@
clock-frequency = <250000000>; clock-frequency = <250000000>;
status = "okay"; status = "okay";
}; };
sata@d00a0000 {
nr-ports = <2>;
status = "okay";
};
mdio {
phy0: ethernet-phy@0 {
reg = <0>;
};
phy1: ethernet-phy@1 {
reg = <1>;
};
phy2: ethernet-phy@2 {
reg = <25>;
};
phy3: ethernet-phy@3 {
reg = <27>;
};
};
ethernet@d0070000 {
status = "okay";
phy = <&phy0>;
phy-mode = "rgmii-id";
};
ethernet@d0074000 {
status = "okay";
phy = <&phy1>;
phy-mode = "rgmii-id";
};
ethernet@d0030000 {
status = "okay";
phy = <&phy2>;
phy-mode = "sgmii";
};
ethernet@d0034000 {
status = "okay";
phy = <&phy3>;
phy-mode = "sgmii";
};
}; };
}; };
...@@ -24,6 +24,18 @@ ...@@ -24,6 +24,18 @@
gpio1 = &gpio1; gpio1 = &gpio1;
}; };
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "marvell,sheeva-v7";
reg = <0>;
clocks = <&cpuclk 0>;
};
}
soc { soc {
pinctrl { pinctrl {
compatible = "marvell,mv78230-pinctrl"; compatible = "marvell,mv78230-pinctrl";
......
...@@ -25,6 +25,25 @@ ...@@ -25,6 +25,25 @@
gpio2 = &gpio2; gpio2 = &gpio2;
}; };
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "marvell,sheeva-v7";
reg = <0>;
clocks = <&cpuclk 0>;
};
cpu@1 {
device_type = "cpu";
compatible = "marvell,sheeva-v7";
reg = <1>;
clocks = <&cpuclk 1>;
};
};
soc { soc {
pinctrl { pinctrl {
compatible = "marvell,mv78260-pinctrl"; compatible = "marvell,mv78260-pinctrl";
......
...@@ -25,6 +25,40 @@ ...@@ -25,6 +25,40 @@
gpio2 = &gpio2; gpio2 = &gpio2;
}; };
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "marvell,sheeva-v7";
reg = <0>;
clocks = <&cpuclk 0>;
};
cpu@1 {
device_type = "cpu";
compatible = "marvell,sheeva-v7";
reg = <1>;
clocks = <&cpuclk 1>;
};
cpu@2 {
device_type = "cpu";
compatible = "marvell,sheeva-v7";
reg = <2>;
clocks = <&cpuclk 2>;
};
cpu@3 {
device_type = "cpu";
compatible = "marvell,sheeva-v7";
reg = <3>;
clocks = <&cpuclk 3>;
};
};
soc { soc {
pinctrl { pinctrl {
compatible = "marvell,mv78460-pinctrl"; compatible = "marvell,mv78460-pinctrl";
......
/*
* Device Tree file for OpenBlocks AX3-4 board
*
* Copyright (C) 2012 Marvell
*
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
/dts-v1/;
/include/ "armada-xp-mv78260.dtsi"
/ {
model = "PlatHome OpenBlocks AX3-4 board";
compatible = "plathome,openblocks-ax3-4", "marvell,armadaxp-mv78260", "marvell,armadaxp", "marvell,armada-370-xp";
chosen {
bootargs = "console=ttyS0,115200 earlyprintk";
};
memory {
device_type = "memory";
reg = <0x00000000 0xC0000000>; /* 3 GB */
};
soc {
serial@d0012000 {
clock-frequency = <250000000>;
status = "okay";
};
serial@d0012100 {
clock-frequency = <250000000>;
status = "okay";
};
pinctrl {
led_pins: led-pins-0 {
marvell,pins = "mpp49", "mpp51", "mpp53";
marvell,function = "gpio";
};
};
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&led_pins>;
red_led {
label = "red_led";
gpios = <&gpio1 17 1>;
default-state = "off";
};
yellow_led {
label = "yellow_led";
gpios = <&gpio1 19 1>;
default-state = "off";
};
green_led {
label = "green_led";
gpios = <&gpio1 21 1>;
default-state = "off";
linux,default-trigger = "heartbeat";
};
};
mdio {
phy0: ethernet-phy@0 {
reg = <0>;
};
phy1: ethernet-phy@1 {
reg = <1>;
};
phy2: ethernet-phy@2 {
reg = <2>;
};
phy3: ethernet-phy@3 {
reg = <3>;
};
};
ethernet@d0070000 {
status = "okay";
phy = <&phy0>;
phy-mode = "sgmii";
};
ethernet@d0074000 {
status = "okay";
phy = <&phy1>;
phy-mode = "sgmii";
};
ethernet@d0030000 {
status = "okay";
phy = <&phy2>;
phy-mode = "sgmii";
};
ethernet@d0034000 {
status = "okay";
phy = <&phy3>;
phy-mode = "sgmii";
};
i2c@d0011000 {
status = "okay";
clock-frequency = <400000>;
};
i2c@d0011100 {
status = "okay";
clock-frequency = <400000>;
s35390a: s35390a@30 {
compatible = "s35390a";
reg = <0x30>;
};
};
sata@d00a0000 {
nr-ports = <2>;
status = "okay";
};
};
};
...@@ -22,9 +22,22 @@ ...@@ -22,9 +22,22 @@
model = "Marvell Armada XP family SoC"; model = "Marvell Armada XP family SoC";
compatible = "marvell,armadaxp", "marvell,armada-370-xp"; compatible = "marvell,armadaxp", "marvell,armada-370-xp";
L2: l2-cache {
compatible = "marvell,aurora-system-cache";
reg = <0xd0008000 0x1000>;
cache-id-part = <0x100>;
wt-override;
};
mpic: interrupt-controller@d0020000 { mpic: interrupt-controller@d0020000 {
reg = <0xd0020a00 0x1d0>, reg = <0xd0020a00 0x1d0>,
<0xd0021870 0x58>; <0xd0021070 0x58>;
};
armada-370-xp-pmsu@d0022000 {
compatible = "marvell,armada-370-xp-pmsu";
reg = <0xd0022100 0x430>,
<0xd0020800 0x20>;
}; };
soc { soc {
...@@ -47,9 +60,85 @@ ...@@ -47,9 +60,85 @@
marvell,timer-25Mhz; marvell,timer-25Mhz;
}; };
coreclk: mvebu-sar@d0018230 {
compatible = "marvell,armada-xp-core-clock";
reg = <0xd0018230 0x08>;
#clock-cells = <1>;
};
cpuclk: clock-complex@d0018700 {
#clock-cells = <1>;
compatible = "marvell,armada-xp-cpu-clock";
reg = <0xd0018700 0xA0>;
clocks = <&coreclk 1>;
};
gateclk: clock-gating-control@d0018220 {
compatible = "marvell,armada-xp-gating-clock";
reg = <0xd0018220 0x4>;
clocks = <&coreclk 0>;
#clock-cells = <1>;
};
system-controller@d0018200 { system-controller@d0018200 {
compatible = "marvell,armada-370-xp-system-controller"; compatible = "marvell,armada-370-xp-system-controller";
reg = <0xd0018200 0x500>; reg = <0xd0018200 0x500>;
}; };
ethernet@d0030000 {
compatible = "marvell,armada-370-neta";
reg = <0xd0030000 0x2500>;
interrupts = <12>;
clocks = <&gateclk 2>;
status = "disabled";
};
ethernet@d0034000 {
compatible = "marvell,armada-370-neta";
reg = <0xd0034000 0x2500>;
interrupts = <14>;
clocks = <&gateclk 1>;
status = "disabled";
};
xor@d0060900 {
compatible = "marvell,orion-xor";
reg = <0xd0060900 0x100
0xd0060b00 0x100>;
clocks = <&gateclk 22>;
status = "okay";
xor10 {
interrupts = <51>;
dmacap,memcpy;
dmacap,xor;
};
xor11 {
interrupts = <52>;
dmacap,memcpy;
dmacap,xor;
dmacap,memset;
};
};
xor@d00f0900 {
compatible = "marvell,orion-xor";
reg = <0xd00F0900 0x100
0xd00F0B00 0x100>;
clocks = <&gateclk 28>;
status = "okay";
xor00 {
interrupts = <94>;
dmacap,memcpy;
dmacap,xor;
};
xor01 {
interrupts = <95>;
dmacap,memcpy;
dmacap,xor;
dmacap,memset;
};
};
}; };
}; };
...@@ -37,6 +37,19 @@ ...@@ -37,6 +37,19 @@
reg = <0x20204 0x04>, <0x20214 0x04>; reg = <0x20204 0x04>, <0x20214 0x04>;
}; };
core_clk: core-clocks@d0214 {
compatible = "marvell,dove-core-clock";
reg = <0xd0214 0x4>;
#clock-cells = <1>;
};
gate_clk: clock-gating-control@d0038 {
compatible = "marvell,dove-gating-clock";
reg = <0xd0038 0x4>;
clocks = <&core_clk 0>;
#clock-cells = <1>;
};
uart0: serial@12000 { uart0: serial@12000 {
compatible = "ns16550a"; compatible = "ns16550a";
reg = <0x12000 0x100>; reg = <0x12000 0x100>;
...@@ -113,6 +126,7 @@ ...@@ -113,6 +126,7 @@
cell-index = <0>; cell-index = <0>;
interrupts = <6>; interrupts = <6>;
reg = <0x10600 0x28>; reg = <0x10600 0x28>;
clocks = <&core_clk 0>;
status = "disabled"; status = "disabled";
}; };
...@@ -123,6 +137,7 @@ ...@@ -123,6 +137,7 @@
cell-index = <1>; cell-index = <1>;
interrupts = <5>; interrupts = <5>;
reg = <0x14600 0x28>; reg = <0x14600 0x28>;
clocks = <&core_clk 0>;
status = "disabled"; status = "disabled";
}; };
...@@ -134,6 +149,7 @@ ...@@ -134,6 +149,7 @@
interrupts = <11>; interrupts = <11>;
clock-frequency = <400000>; clock-frequency = <400000>;
timeout-ms = <1000>; timeout-ms = <1000>;
clocks = <&core_clk 0>;
status = "disabled"; status = "disabled";
}; };
...@@ -141,6 +157,7 @@ ...@@ -141,6 +157,7 @@
compatible = "marvell,dove-sdhci"; compatible = "marvell,dove-sdhci";
reg = <0x92000 0x100>; reg = <0x92000 0x100>;
interrupts = <35>, <37>; interrupts = <35>, <37>;
clocks = <&gate_clk 8>;
status = "disabled"; status = "disabled";
}; };
...@@ -148,6 +165,7 @@ ...@@ -148,6 +165,7 @@
compatible = "marvell,dove-sdhci"; compatible = "marvell,dove-sdhci";
reg = <0x90000 0x100>; reg = <0x90000 0x100>;
interrupts = <36>, <38>; interrupts = <36>, <38>;
clocks = <&gate_clk 9>;
status = "disabled"; status = "disabled";
}; };
...@@ -155,6 +173,7 @@ ...@@ -155,6 +173,7 @@
compatible = "marvell,orion-sata"; compatible = "marvell,orion-sata";
reg = <0xa0000 0x2400>; reg = <0xa0000 0x2400>;
interrupts = <62>; interrupts = <62>;
clocks = <&gate_clk 3>;
nr-ports = <1>; nr-ports = <1>;
status = "disabled"; status = "disabled";
}; };
...@@ -165,7 +184,50 @@ ...@@ -165,7 +184,50 @@
<0xc8000000 0x800>; <0xc8000000 0x800>;
reg-names = "regs", "sram"; reg-names = "regs", "sram";
interrupts = <31>; interrupts = <31>;
clocks = <&gate_clk 15>;
status = "okay";
};
xor0: dma-engine@60800 {
compatible = "marvell,orion-xor";
reg = <0x60800 0x100
0x60a00 0x100>;
clocks = <&gate_clk 23>;
status = "okay"; status = "okay";
channel0 {
interrupts = <39>;
dmacap,memcpy;
dmacap,xor;
};
channel1 {
interrupts = <40>;
dmacap,memset;
dmacap,memcpy;
dmacap,xor;
};
};
xor1: dma-engine@60900 {
compatible = "marvell,orion-xor";
reg = <0x60900 0x100
0x60b00 0x100>;
clocks = <&gate_clk 24>;
status = "okay";
channel0 {
interrupts = <42>;
dmacap,memcpy;
dmacap,xor;
};
channel1 {
interrupts = <43>;
dmacap,memset;
dmacap,memcpy;
dmacap,xor;
};
}; };
}; };
}; };
...@@ -23,6 +23,12 @@ ...@@ -23,6 +23,12 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
core_clk: core-clocks@10030 {
compatible = "marvell,kirkwood-core-clock";
reg = <0x10030 0x4>;
#clock-cells = <1>;
};
gpio0: gpio@10100 { gpio0: gpio@10100 {
compatible = "marvell,orion-gpio"; compatible = "marvell,orion-gpio";
#gpio-cells = <2>; #gpio-cells = <2>;
...@@ -48,6 +54,7 @@ ...@@ -48,6 +54,7 @@
reg = <0x12000 0x100>; reg = <0x12000 0x100>;
reg-shift = <2>; reg-shift = <2>;
interrupts = <33>; interrupts = <33>;
clocks = <&gate_clk 7>;
/* set clock-frequency in board dts */ /* set clock-frequency in board dts */
status = "disabled"; status = "disabled";
}; };
...@@ -57,6 +64,7 @@ ...@@ -57,6 +64,7 @@
reg = <0x12100 0x100>; reg = <0x12100 0x100>;
reg-shift = <2>; reg-shift = <2>;
interrupts = <34>; interrupts = <34>;
clocks = <&gate_clk 7>;
/* set clock-frequency in board dts */ /* set clock-frequency in board dts */
status = "disabled"; status = "disabled";
}; };
...@@ -74,13 +82,62 @@ ...@@ -74,13 +82,62 @@
cell-index = <0>; cell-index = <0>;
interrupts = <23>; interrupts = <23>;
reg = <0x10600 0x28>; reg = <0x10600 0x28>;
clocks = <&gate_clk 7>;
status = "disabled"; status = "disabled";
}; };
gate_clk: clock-gating-control@2011c {
compatible = "marvell,kirkwood-gating-clock";
reg = <0x2011c 0x4>;
clocks = <&core_clk 0>;
#clock-cells = <1>;
};
wdt@20300 { wdt@20300 {
compatible = "marvell,orion-wdt"; compatible = "marvell,orion-wdt";
reg = <0x20300 0x28>; reg = <0x20300 0x28>;
clocks = <&gate_clk 7>;
status = "okay";
};
xor@60800 {
compatible = "marvell,orion-xor";
reg = <0x60800 0x100
0x60A00 0x100>;
status = "okay";
clocks = <&gate_clk 8>;
xor00 {
interrupts = <5>;
dmacap,memcpy;
dmacap,xor;
};
xor01 {
interrupts = <6>;
dmacap,memcpy;
dmacap,xor;
dmacap,memset;
};
};
xor@60900 {
compatible = "marvell,orion-xor";
reg = <0x60900 0x100
0xd0B00 0x100>;
status = "okay"; status = "okay";
clocks = <&gate_clk 16>;
xor00 {
interrupts = <7>;
dmacap,memcpy;
dmacap,xor;
};
xor01 {
interrupts = <8>;
dmacap,memcpy;
dmacap,xor;
dmacap,memset;
};
}; };
ehci@50000 { ehci@50000 {
...@@ -94,6 +151,8 @@ ...@@ -94,6 +151,8 @@
compatible = "marvell,orion-sata"; compatible = "marvell,orion-sata";
reg = <0x80000 0x5000>; reg = <0x80000 0x5000>;
interrupts = <21>; interrupts = <21>;
clocks = <&gate_clk 14>, <&gate_clk 15>;
clock-names = "0", "1";
status = "disabled"; status = "disabled";
}; };
...@@ -107,6 +166,7 @@ ...@@ -107,6 +166,7 @@
reg = <0x3000000 0x400>; reg = <0x3000000 0x400>;
chip-delay = <25>; chip-delay = <25>;
/* set partition map and/or chip-delay in board dts */ /* set partition map and/or chip-delay in board dts */
clocks = <&gate_clk 7>;
status = "disabled"; status = "disabled";
}; };
...@@ -117,6 +177,7 @@ ...@@ -117,6 +177,7 @@
#size-cells = <0>; #size-cells = <0>;
interrupts = <29>; interrupts = <29>;
clock-frequency = <100000>; clock-frequency = <100000>;
clocks = <&gate_clk 7>;
status = "disabled"; status = "disabled";
}; };
...@@ -126,6 +187,7 @@ ...@@ -126,6 +187,7 @@
<0xf5000000 0x800>; <0xf5000000 0x800>;
reg-names = "regs", "sram"; reg-names = "regs", "sram";
interrupts = <22>; interrupts = <22>;
clocks = <&gate_clk 17>;
status = "okay"; status = "okay";
}; };
}; };
......
...@@ -17,8 +17,10 @@ CONFIG_ARM_APPENDED_DTB=y ...@@ -17,8 +17,10 @@ CONFIG_ARM_APPENDED_DTB=y
CONFIG_VFP=y CONFIG_VFP=y
CONFIG_NEON=y CONFIG_NEON=y
CONFIG_NET=y CONFIG_NET=y
CONFIG_BLK_DEV_SD=y
CONFIG_ATA=y CONFIG_ATA=y
CONFIG_SATA_HIGHBANK=y CONFIG_SATA_HIGHBANK=y
CONFIG_SATA_MV=y
CONFIG_NETDEVICES=y CONFIG_NETDEVICES=y
CONFIG_NET_CALXEDA_XGMAC=y CONFIG_NET_CALXEDA_XGMAC=y
CONFIG_SMSC911X=y CONFIG_SMSC911X=y
......
...@@ -12,6 +12,9 @@ CONFIG_ARCH_MVEBU=y ...@@ -12,6 +12,9 @@ CONFIG_ARCH_MVEBU=y
CONFIG_MACH_ARMADA_370=y CONFIG_MACH_ARMADA_370=y
CONFIG_MACH_ARMADA_XP=y CONFIG_MACH_ARMADA_XP=y
# CONFIG_CACHE_L2X0 is not set # CONFIG_CACHE_L2X0 is not set
# CONFIG_SWP_EMULATE is not set
CONFIG_SMP=y
# CONFIG_LOCAL_TIMERS is not set
CONFIG_AEABI=y CONFIG_AEABI=y
CONFIG_HIGHMEM=y CONFIG_HIGHMEM=y
# CONFIG_COMPACTION is not set # CONFIG_COMPACTION is not set
...@@ -19,13 +22,27 @@ CONFIG_ZBOOT_ROM_TEXT=0x0 ...@@ -19,13 +22,27 @@ CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_ARM_APPENDED_DTB=y CONFIG_ARM_APPENDED_DTB=y
CONFIG_VFP=y CONFIG_VFP=y
CONFIG_NET=y
CONFIG_INET=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_BLK_DEV_SD=y
CONFIG_ATA=y
CONFIG_SATA_MV=y
CONFIG_NETDEVICES=y
CONFIG_MVNETA=y
CONFIG_MARVELL_PHY=y
CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_I2C=y
CONFIG_I2C_MV64XXX=y
CONFIG_GPIOLIB=y CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y CONFIG_GPIO_SYSFS=y
# CONFIG_USB_SUPPORT is not set # CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_S35390A=y
CONFIG_DMADEVICES=y
CONFIG_MV_XOR=y
# CONFIG_IOMMU_SUPPORT is not set # CONFIG_IOMMU_SUPPORT is not set
CONFIG_EXT2_FS=y CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y CONFIG_EXT3_FS=y
......
...@@ -111,6 +111,8 @@ static inline void dma_free_noncoherent(struct device *dev, size_t size, ...@@ -111,6 +111,8 @@ static inline void dma_free_noncoherent(struct device *dev, size_t size,
extern int dma_supported(struct device *dev, u64 mask); extern int dma_supported(struct device *dev, u64 mask);
extern int arm_dma_set_mask(struct device *dev, u64 dma_mask);
/** /**
* arm_dma_alloc - allocate consistent memory for DMA * arm_dma_alloc - allocate consistent memory for DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
......
...@@ -17,6 +17,8 @@ config MACH_CM_A510 ...@@ -17,6 +17,8 @@ config MACH_CM_A510
config MACH_DOVE_DT config MACH_DOVE_DT
bool "Marvell Dove Flattened Device Tree" bool "Marvell Dove Flattened Device Tree"
select MVEBU_CLK_CORE
select MVEBU_CLK_GATING
select USE_OF select USE_OF
help help
Say 'Y' here if you want your kernel to support the Say 'Y' here if you want your kernel to support the
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clk/mvebu.h>
#include <linux/ata_platform.h> #include <linux/ata_platform.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -32,6 +33,7 @@ ...@@ -32,6 +33,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <plat/time.h> #include <plat/time.h>
#include <linux/platform_data/usb-ehci-orion.h> #include <linux/platform_data/usb-ehci-orion.h>
#include <linux/platform_data/dma-mv_xor.h>
#include <plat/irq.h> #include <plat/irq.h>
#include <plat/common.h> #include <plat/common.h>
#include <plat/addr-map.h> #include <plat/addr-map.h>
...@@ -123,8 +125,8 @@ static void __init dove_clk_init(void) ...@@ -123,8 +125,8 @@ static void __init dove_clk_init(void)
orion_clkdev_add(NULL, "mv_crypto", crypto); orion_clkdev_add(NULL, "mv_crypto", crypto);
orion_clkdev_add(NULL, "dove-ac97", ac97); orion_clkdev_add(NULL, "dove-ac97", ac97);
orion_clkdev_add(NULL, "dove-pdma", pdma); orion_clkdev_add(NULL, "dove-pdma", pdma);
orion_clkdev_add(NULL, "mv_xor_shared.0", xor0); orion_clkdev_add(NULL, MV_XOR_NAME ".0", xor0);
orion_clkdev_add(NULL, "mv_xor_shared.1", xor1); orion_clkdev_add(NULL, MV_XOR_NAME ".1", xor1);
} }
/***************************************************************************** /*****************************************************************************
...@@ -376,19 +378,44 @@ void dove_restart(char mode, const char *cmd) ...@@ -376,19 +378,44 @@ void dove_restart(char mode, const char *cmd)
#if defined(CONFIG_MACH_DOVE_DT) #if defined(CONFIG_MACH_DOVE_DT)
/* /*
* Auxdata required until real OF clock provider * There are still devices that doesn't even know about DT,
* get clock gates here and add a clock lookup.
*/ */
struct of_dev_auxdata dove_auxdata_lookup[] __initdata = { static void __init dove_legacy_clk_init(void)
OF_DEV_AUXDATA("marvell,orion-spi", 0xf1010600, "orion_spi.0", NULL), {
OF_DEV_AUXDATA("marvell,orion-spi", 0xf1014600, "orion_spi.1", NULL), struct device_node *np = of_find_compatible_node(NULL, NULL,
OF_DEV_AUXDATA("marvell,orion-wdt", 0xf1020300, "orion_wdt", NULL), "marvell,dove-gating-clock");
OF_DEV_AUXDATA("marvell,mv64xxx-i2c", 0xf1011000, "mv64xxx_i2c.0", struct of_phandle_args clkspec;
NULL),
OF_DEV_AUXDATA("marvell,orion-sata", 0xf10a0000, "sata_mv.0", NULL), clkspec.np = np;
OF_DEV_AUXDATA("marvell,dove-sdhci", 0xf1092000, "sdhci-dove.0", NULL), clkspec.args_count = 1;
OF_DEV_AUXDATA("marvell,dove-sdhci", 0xf1090000, "sdhci-dove.1", NULL),
{}, clkspec.args[0] = CLOCK_GATING_BIT_USB0;
}; orion_clkdev_add(NULL, "orion-ehci.0",
of_clk_get_from_provider(&clkspec));
clkspec.args[0] = CLOCK_GATING_BIT_USB1;
orion_clkdev_add(NULL, "orion-ehci.1",
of_clk_get_from_provider(&clkspec));
clkspec.args[0] = CLOCK_GATING_BIT_GBE;
orion_clkdev_add(NULL, "mv643xx_eth_port.0",
of_clk_get_from_provider(&clkspec));
clkspec.args[0] = CLOCK_GATING_BIT_PCIE0;
orion_clkdev_add("0", "pcie",
of_clk_get_from_provider(&clkspec));
clkspec.args[0] = CLOCK_GATING_BIT_PCIE1;
orion_clkdev_add("1", "pcie",
of_clk_get_from_provider(&clkspec));
}
static void __init dove_of_clk_init(void)
{
mvebu_clocks_init();
dove_legacy_clk_init();
}
static struct mv643xx_eth_platform_data dove_dt_ge00_data = { static struct mv643xx_eth_platform_data dove_dt_ge00_data = {
.phy_addr = MV643XX_ETH_PHY_ADDR_DEFAULT, .phy_addr = MV643XX_ETH_PHY_ADDR_DEFAULT,
...@@ -405,20 +432,17 @@ static void __init dove_dt_init(void) ...@@ -405,20 +432,17 @@ static void __init dove_dt_init(void)
dove_setup_cpu_mbus(); dove_setup_cpu_mbus();
/* Setup root of clk tree */ /* Setup root of clk tree */
dove_clk_init(); dove_of_clk_init();
/* Internal devices not ported to DT yet */ /* Internal devices not ported to DT yet */
dove_rtc_init(); dove_rtc_init();
dove_xor0_init();
dove_xor1_init();
dove_ge00_init(&dove_dt_ge00_data); dove_ge00_init(&dove_dt_ge00_data);
dove_ehci0_init(); dove_ehci0_init();
dove_ehci1_init(); dove_ehci1_init();
dove_pcie_init(1, 1); dove_pcie_init(1, 1);
of_platform_populate(NULL, of_default_bus_match_table, of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
dove_auxdata_lookup, NULL);
} }
static const char * const dove_dt_board_compat[] = { static const char * const dove_dt_board_compat[] = {
......
...@@ -51,6 +51,8 @@ config ARCH_KIRKWOOD_DT ...@@ -51,6 +51,8 @@ config ARCH_KIRKWOOD_DT
select POWER_RESET_GPIO select POWER_RESET_GPIO
select REGULATOR select REGULATOR
select REGULATOR_FIXED_VOLTAGE select REGULATOR_FIXED_VOLTAGE
select MVEBU_CLK_CORE
select MVEBU_CLK_GATING
select USE_OF select USE_OF
help help
Say 'Y' here if you want your kernel to support the Say 'Y' here if you want your kernel to support the
......
...@@ -14,11 +14,15 @@ ...@@ -14,11 +14,15 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/clk-provider.h>
#include <linux/clk/mvebu.h>
#include <linux/kexec.h> #include <linux/kexec.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <mach/bridge-regs.h> #include <mach/bridge-regs.h>
#include <linux/platform_data/usb-ehci-orion.h>
#include <plat/irq.h> #include <plat/irq.h>
#include <plat/common.h>
#include "common.h" #include "common.h"
static struct of_device_id kirkwood_dt_match_table[] __initdata = { static struct of_device_id kirkwood_dt_match_table[] __initdata = {
...@@ -26,18 +30,50 @@ static struct of_device_id kirkwood_dt_match_table[] __initdata = { ...@@ -26,18 +30,50 @@ static struct of_device_id kirkwood_dt_match_table[] __initdata = {
{ } { }
}; };
static struct of_dev_auxdata kirkwood_auxdata_lookup[] __initdata = { /*
OF_DEV_AUXDATA("marvell,orion-spi", 0xf1010600, "orion_spi.0", NULL), * There are still devices that doesn't know about DT yet. Get clock
OF_DEV_AUXDATA("marvell,mv64xxx-i2c", 0xf1011000, "mv64xxx_i2c.0", * gates here and add a clock lookup alias, so that old platform
NULL), * devices still work.
OF_DEV_AUXDATA("marvell,mv64xxx-i2c", 0xf1011100, "mv64xxx_i2c.1", */
NULL),
OF_DEV_AUXDATA("marvell,orion-wdt", 0xf1020300, "orion_wdt", NULL), static void __init kirkwood_legacy_clk_init(void)
OF_DEV_AUXDATA("marvell,orion-sata", 0xf1080000, "sata_mv.0", NULL), {
OF_DEV_AUXDATA("marvell,orion-nand", 0xf4000000, "orion_nand", NULL),
OF_DEV_AUXDATA("marvell,orion-crypto", 0xf1030000, "mv_crypto", NULL), struct device_node *np = of_find_compatible_node(
{}, NULL, NULL, "marvell,kirkwood-gating-clock");
};
struct of_phandle_args clkspec;
clkspec.np = np;
clkspec.args_count = 1;
clkspec.args[0] = CGC_BIT_GE0;
orion_clkdev_add(NULL, "mv643xx_eth_port.0",
of_clk_get_from_provider(&clkspec));
clkspec.args[0] = CGC_BIT_PEX0;
orion_clkdev_add("0", "pcie",
of_clk_get_from_provider(&clkspec));
clkspec.args[0] = CGC_BIT_USB0;
orion_clkdev_add(NULL, "orion-ehci.0",
of_clk_get_from_provider(&clkspec));
clkspec.args[0] = CGC_BIT_PEX1;
orion_clkdev_add("1", "pcie",
of_clk_get_from_provider(&clkspec));
clkspec.args[0] = CGC_BIT_GE1;
orion_clkdev_add(NULL, "mv643xx_eth_port.1",
of_clk_get_from_provider(&clkspec));
}
static void __init kirkwood_of_clk_init(void)
{
mvebu_clocks_init();
kirkwood_legacy_clk_init();
}
static void __init kirkwood_dt_init(void) static void __init kirkwood_dt_init(void)
{ {
...@@ -56,11 +92,7 @@ static void __init kirkwood_dt_init(void) ...@@ -56,11 +92,7 @@ static void __init kirkwood_dt_init(void)
kirkwood_l2_init(); kirkwood_l2_init();
/* Setup root of clk tree */ /* Setup root of clk tree */
kirkwood_clk_init(); kirkwood_of_clk_init();
/* internal devices that every board has */
kirkwood_xor0_init();
kirkwood_xor1_init();
#ifdef CONFIG_KEXEC #ifdef CONFIG_KEXEC
kexec_reinit = kirkwood_enable_pcie; kexec_reinit = kirkwood_enable_pcie;
...@@ -115,8 +147,7 @@ static void __init kirkwood_dt_init(void) ...@@ -115,8 +147,7 @@ static void __init kirkwood_dt_init(void)
if (of_machine_is_compatible("zyxel,nsa310")) if (of_machine_is_compatible("zyxel,nsa310"))
nsa310_init(); nsa310_init();
of_platform_populate(NULL, kirkwood_dt_match_table, of_platform_populate(NULL, kirkwood_dt_match_table, NULL, NULL);
kirkwood_auxdata_lookup, NULL);
} }
static const char * const kirkwood_dt_board_compat[] = { static const char * const kirkwood_dt_board_compat[] = {
......
...@@ -260,8 +260,8 @@ void __init kirkwood_clk_init(void) ...@@ -260,8 +260,8 @@ void __init kirkwood_clk_init(void)
orion_clkdev_add(NULL, "orion_nand", runit); orion_clkdev_add(NULL, "orion_nand", runit);
orion_clkdev_add(NULL, "mvsdio", sdio); orion_clkdev_add(NULL, "mvsdio", sdio);
orion_clkdev_add(NULL, "mv_crypto", crypto); orion_clkdev_add(NULL, "mv_crypto", crypto);
orion_clkdev_add(NULL, MV_XOR_SHARED_NAME ".0", xor0); orion_clkdev_add(NULL, MV_XOR_NAME ".0", xor0);
orion_clkdev_add(NULL, MV_XOR_SHARED_NAME ".1", xor1); orion_clkdev_add(NULL, MV_XOR_NAME ".1", xor1);
orion_clkdev_add("0", "pcie", pex0); orion_clkdev_add("0", "pcie", pex0);
orion_clkdev_add("1", "pcie", pex1); orion_clkdev_add("1", "pcie", pex1);
orion_clkdev_add(NULL, "kirkwood-i2s", audio); orion_clkdev_add(NULL, "kirkwood-i2s", audio);
......
...@@ -9,6 +9,10 @@ config ARCH_MVEBU ...@@ -9,6 +9,10 @@ config ARCH_MVEBU
select PINCTRL select PINCTRL
select PLAT_ORION select PLAT_ORION
select SPARSE_IRQ select SPARSE_IRQ
select CLKDEV_LOOKUP
select MVEBU_CLK_CORE
select MVEBU_CLK_CPU
select MVEBU_CLK_GATING
if ARCH_MVEBU if ARCH_MVEBU
...@@ -17,7 +21,9 @@ menu "Marvell SOC with device tree" ...@@ -17,7 +21,9 @@ menu "Marvell SOC with device tree"
config MACH_ARMADA_370_XP config MACH_ARMADA_370_XP
bool bool
select ARMADA_370_XP_TIMER select ARMADA_370_XP_TIMER
select CPU_V7 select HAVE_SMP
select CACHE_L2X0
select CPU_PJ4B
config MACH_ARMADA_370 config MACH_ARMADA_370
bool "Marvell Armada 370 boards" bool "Marvell Armada 370 boards"
......
...@@ -2,4 +2,6 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \ ...@@ -2,4 +2,6 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
-I$(srctree)/arch/arm/plat-orion/include -I$(srctree)/arch/arm/plat-orion/include
obj-y += system-controller.o obj-y += system-controller.o
obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o irq-armada-370-xp.o addr-map.o obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o irq-armada-370-xp.o addr-map.o coherency.o coherency_ll.o pmsu.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
...@@ -78,7 +78,7 @@ armada_cfg_base(const struct orion_addr_map_cfg *cfg, int win) ...@@ -78,7 +78,7 @@ armada_cfg_base(const struct orion_addr_map_cfg *cfg, int win)
if (win < 8) if (win < 8)
offset = (win << 4); offset = (win << 4);
else else
offset = ARMADA_WINDOW_8_PLUS_OFFSET + (win << 3); offset = ARMADA_WINDOW_8_PLUS_OFFSET + ((win - 8) << 3);
return cfg->bridge_virt_base + offset; return cfg->bridge_virt_base + offset;
} }
...@@ -108,6 +108,9 @@ static int __init armada_setup_cpu_mbus(void) ...@@ -108,6 +108,9 @@ static int __init armada_setup_cpu_mbus(void)
addr_map_cfg.bridge_virt_base = mbus_unit_addr_decoding_base; addr_map_cfg.bridge_virt_base = mbus_unit_addr_decoding_base;
if (of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"))
addr_map_cfg.hw_io_coherency = 1;
/* /*
* Disable, clear and configure windows. * Disable, clear and configure windows.
*/ */
......
...@@ -17,11 +17,14 @@ ...@@ -17,11 +17,14 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/time-armada-370-xp.h> #include <linux/time-armada-370-xp.h>
#include <linux/clk/mvebu.h>
#include <linux/dma-mapping.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include "armada-370-xp.h" #include "armada-370-xp.h"
#include "common.h" #include "common.h"
#include "coherency.h"
static struct map_desc armada_370_xp_io_desc[] __initdata = { static struct map_desc armada_370_xp_io_desc[] __initdata = {
{ {
...@@ -37,27 +40,45 @@ void __init armada_370_xp_map_io(void) ...@@ -37,27 +40,45 @@ void __init armada_370_xp_map_io(void)
iotable_init(armada_370_xp_io_desc, ARRAY_SIZE(armada_370_xp_io_desc)); iotable_init(armada_370_xp_io_desc, ARRAY_SIZE(armada_370_xp_io_desc));
} }
void __init armada_370_xp_timer_and_clk_init(void)
{
mvebu_clocks_init();
armada_370_xp_timer_init();
}
void __init armada_370_xp_init_early(void)
{
/*
* Some Armada 370/XP devices allocate their coherent buffers
* from atomic context. Increase size of atomic coherent pool
* to make sure such the allocations won't fail.
*/
init_dma_coherent_pool_size(SZ_1M);
}
struct sys_timer armada_370_xp_timer = { struct sys_timer armada_370_xp_timer = {
.init = armada_370_xp_timer_init, .init = armada_370_xp_timer_and_clk_init,
}; };
static void __init armada_370_xp_dt_init(void) static void __init armada_370_xp_dt_init(void)
{ {
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
coherency_init();
} }
static const char * const armada_370_xp_dt_board_dt_compat[] = { static const char * const armada_370_xp_dt_compat[] = {
"marvell,a370-db", "marvell,armada-370-xp",
"marvell,axp-db",
NULL, NULL,
}; };
DT_MACHINE_START(ARMADA_XP_DT, "Marvell Aramada 370/XP (Device Tree)") DT_MACHINE_START(ARMADA_XP_DT, "Marvell Armada 370/XP (Device Tree)")
.smp = smp_ops(armada_xp_smp_ops),
.init_machine = armada_370_xp_dt_init, .init_machine = armada_370_xp_dt_init,
.map_io = armada_370_xp_map_io, .map_io = armada_370_xp_map_io,
.init_early = armada_370_xp_init_early,
.init_irq = armada_370_xp_init_irq, .init_irq = armada_370_xp_init_irq,
.handle_irq = armada_370_xp_handle_irq, .handle_irq = armada_370_xp_handle_irq,
.timer = &armada_370_xp_timer, .timer = &armada_370_xp_timer,
.restart = mvebu_restart, .restart = mvebu_restart,
.dt_compat = armada_370_xp_dt_board_dt_compat, .dt_compat = armada_370_xp_dt_compat,
MACHINE_END MACHINE_END
...@@ -19,4 +19,11 @@ ...@@ -19,4 +19,11 @@
#define ARMADA_370_XP_REGS_VIRT_BASE IOMEM(0xfeb00000) #define ARMADA_370_XP_REGS_VIRT_BASE IOMEM(0xfeb00000)
#define ARMADA_370_XP_REGS_SIZE SZ_1M #define ARMADA_370_XP_REGS_SIZE SZ_1M
#ifdef CONFIG_SMP
#include <linux/cpumask.h>
void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq);
void armada_xp_mpic_smp_cpu_init(void);
#endif
#endif /* __MACH_ARMADA_370_XP_H */ #endif /* __MACH_ARMADA_370_XP_H */
/*
* Coherency fabric (Aurora) support for Armada 370 and XP platforms.
*
* Copyright (C) 2012 Marvell
*
* Yehuda Yitschak <yehuday@marvell.com>
* Gregory Clement <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*
* The Armada 370 and Armada XP SOCs have a coherency fabric which is
* responsible for ensuring hardware coherency between all CPUs and between
* CPUs and I/O masters. This file initializes the coherency fabric and
* supplies basic routines for configuring and controlling hardware coherency
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/smp.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <asm/smp_plat.h>
#include "armada-370-xp.h"
/*
* Some functions in this file are called very early during SMP
* initialization. At that time the device tree framework is not yet
* ready, and it is not possible to get the register address to
* ioremap it. That's why the pointer below is given with an initial
* value matching its virtual mapping
*/
static void __iomem *coherency_base = ARMADA_370_XP_REGS_VIRT_BASE + 0x20200;
static void __iomem *coherency_cpu_base;
/* Coherency fabric registers */
#define COHERENCY_FABRIC_CFG_OFFSET 0x4
#define IO_SYNC_BARRIER_CTL_OFFSET 0x0
static struct of_device_id of_coherency_table[] = {
{.compatible = "marvell,coherency-fabric"},
{ /* end of list */ },
};
#ifdef CONFIG_SMP
int coherency_get_cpu_count(void)
{
int reg, cnt;
reg = readl(coherency_base + COHERENCY_FABRIC_CFG_OFFSET);
cnt = (reg & 0xF) + 1;
return cnt;
}
#endif
/* Function defined in coherency_ll.S */
int ll_set_cpu_coherent(void __iomem *base_addr, unsigned int hw_cpu_id);
int set_cpu_coherent(unsigned int hw_cpu_id, int smp_group_id)
{
if (!coherency_base) {
pr_warn("Can't make CPU %d cache coherent.\n", hw_cpu_id);
pr_warn("Coherency fabric is not initialized\n");
return 1;
}
return ll_set_cpu_coherent(coherency_base, hw_cpu_id);
}
static inline void mvebu_hwcc_sync_io_barrier(void)
{
writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET);
while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1);
}
static dma_addr_t mvebu_hwcc_dma_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction dir,
struct dma_attrs *attrs)
{
if (dir != DMA_TO_DEVICE)
mvebu_hwcc_sync_io_barrier();
return pfn_to_dma(dev, page_to_pfn(page)) + offset;
}
static void mvebu_hwcc_dma_unmap_page(struct device *dev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction dir,
struct dma_attrs *attrs)
{
if (dir != DMA_TO_DEVICE)
mvebu_hwcc_sync_io_barrier();
}
static void mvebu_hwcc_dma_sync(struct device *dev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction dir)
{
if (dir != DMA_TO_DEVICE)
mvebu_hwcc_sync_io_barrier();
}
static struct dma_map_ops mvebu_hwcc_dma_ops = {
.alloc = arm_dma_alloc,
.free = arm_dma_free,
.mmap = arm_dma_mmap,
.map_page = mvebu_hwcc_dma_map_page,
.unmap_page = mvebu_hwcc_dma_unmap_page,
.get_sgtable = arm_dma_get_sgtable,
.map_sg = arm_dma_map_sg,
.unmap_sg = arm_dma_unmap_sg,
.sync_single_for_cpu = mvebu_hwcc_dma_sync,
.sync_single_for_device = mvebu_hwcc_dma_sync,
.sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
.sync_sg_for_device = arm_dma_sync_sg_for_device,
.set_dma_mask = arm_dma_set_mask,
};
static int mvebu_hwcc_platform_notifier(struct notifier_block *nb,
unsigned long event, void *__dev)
{
struct device *dev = __dev;
if (event != BUS_NOTIFY_ADD_DEVICE)
return NOTIFY_DONE;
set_dma_ops(dev, &mvebu_hwcc_dma_ops);
return NOTIFY_OK;
}
static struct notifier_block mvebu_hwcc_platform_nb = {
.notifier_call = mvebu_hwcc_platform_notifier,
};
int __init coherency_init(void)
{
struct device_node *np;
np = of_find_matching_node(NULL, of_coherency_table);
if (np) {
pr_info("Initializing Coherency fabric\n");
coherency_base = of_iomap(np, 0);
coherency_cpu_base = of_iomap(np, 1);
set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0);
bus_register_notifier(&platform_bus_type,
&mvebu_hwcc_platform_nb);
}
return 0;
}
/*
* arch/arm/mach-mvebu/include/mach/coherency.h
*
*
* Coherency fabric (Aurora) support for Armada 370 and XP platforms.
*
* Copyright (C) 2012 Marvell
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __MACH_370_XP_COHERENCY_H
#define __MACH_370_XP_COHERENCY_H
#ifdef CONFIG_SMP
int coherency_get_cpu_count(void);
#endif
int set_cpu_coherent(int cpu_id, int smp_group_id);
int coherency_init(void);
#endif /* __MACH_370_XP_COHERENCY_H */
/*
* Coherency fabric: low level functions
*
* Copyright (C) 2012 Marvell
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*
* This file implements the assembly function to add a CPU to the
* coherency fabric. This function is called by each of the secondary
* CPUs during their early boot in an SMP kernel, this why this
* function have to callable from assembly. It can also be called by a
* primary CPU from C code during its boot.
*/
#include <linux/linkage.h>
#define ARMADA_XP_CFB_CTL_REG_OFFSET 0x0
#define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4
.text
/*
* r0: Coherency fabric base register address
* r1: HW CPU id
*/
ENTRY(ll_set_cpu_coherent)
/* Create bit by cpu index */
mov r3, #(1 << 24)
lsl r1, r3, r1
/* Add CPU to SMP group - Atomic */
add r3, r0, #ARMADA_XP_CFB_CTL_REG_OFFSET
ldr r2, [r3]
orr r2, r2, r1
str r2, [r3]
/* Enable coherency on CPU - Atomic */
add r3, r0, #ARMADA_XP_CFB_CFG_REG_OFFSET
ldr r2, [r3]
orr r2, r2, r1
str r2, [r3]
dsb
mov r0, #0
mov pc, lr
ENDPROC(ll_set_cpu_coherent)
...@@ -20,4 +20,9 @@ void mvebu_restart(char mode, const char *cmd); ...@@ -20,4 +20,9 @@ void mvebu_restart(char mode, const char *cmd);
void armada_370_xp_init_irq(void); void armada_370_xp_init_irq(void);
void armada_370_xp_handle_irq(struct pt_regs *regs); void armada_370_xp_handle_irq(struct pt_regs *regs);
void armada_xp_cpu_die(unsigned int cpu);
int armada_370_xp_coherency_init(void);
int armada_370_xp_pmsu_init(void);
void armada_xp_secondary_startup(void);
extern struct smp_operations armada_xp_smp_ops;
#endif #endif
/*
* SMP support: Entry point for secondary CPUs
*
* Copyright (C) 2012 Marvell
*
* Yehuda Yitschak <yehuday@marvell.com>
* Gregory CLEMENT <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*
* This file implements the assembly entry point for secondary CPUs in
* an SMP kernel. The only thing we need to do is to add the CPU to
* the coherency fabric by writing to 2 registers. Currently the base
* register addresses are hard coded due to the early initialisation
* problems.
*/
#include <linux/linkage.h>
#include <linux/init.h>
/*
* At this stage the secondary CPUs don't have acces yet to the MMU, so
* we have to provide physical addresses
*/
#define ARMADA_XP_CFB_BASE 0xD0020200
__CPUINIT
/*
* Armada XP specific entry point for secondary CPUs.
* We add the CPU to the coherency fabric and then jump to secondary
* startup
*/
ENTRY(armada_xp_secondary_startup)
/* Read CPU id */
mrc p15, 0, r1, c0, c0, 5
and r1, r1, #0xF
/* Add CPU to coherency fabric */
ldr r0, =ARMADA_XP_CFB_BASE
bl ll_set_cpu_coherent
b secondary_startup
ENDPROC(armada_xp_secondary_startup)
/*
* Symmetric Multi Processing (SMP) support for Armada XP
*
* Copyright (C) 2012 Marvell
*
* Lior Amsalem <alior@marvell.com>
* Gregory CLEMENT <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/smp.h>
#include <asm/proc-fns.h>
/*
* platform-specific code to shutdown a CPU
*
* Called with IRQs disabled
*/
void __ref armada_xp_cpu_die(unsigned int cpu)
{
cpu_do_idle();
/* We should never return from idle */
panic("mvebu: cpu %d unexpectedly exit from shutdown\n", cpu);
}
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/exception.h> #include <asm/exception.h>
#include <asm/smp_plat.h>
#include <asm/hardware/cache-l2x0.h>
/* Interrupt Controller Registers Map */ /* Interrupt Controller Registers Map */
#define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48) #define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48)
...@@ -35,6 +37,12 @@ ...@@ -35,6 +37,12 @@
#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44) #define ARMADA_370_XP_CPU_INTACK_OFFS (0x44)
#define ARMADA_370_XP_SW_TRIG_INT_OFFS (0x4)
#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc)
#define ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS (0x8)
#define ACTIVE_DOORBELLS (8)
static void __iomem *per_cpu_int_base; static void __iomem *per_cpu_int_base;
static void __iomem *main_int_base; static void __iomem *main_int_base;
static struct irq_domain *armada_370_xp_mpic_domain; static struct irq_domain *armada_370_xp_mpic_domain;
...@@ -51,11 +59,22 @@ static void armada_370_xp_irq_unmask(struct irq_data *d) ...@@ -51,11 +59,22 @@ static void armada_370_xp_irq_unmask(struct irq_data *d)
per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
} }
#ifdef CONFIG_SMP
static int armada_xp_set_affinity(struct irq_data *d,
const struct cpumask *mask_val, bool force)
{
return 0;
}
#endif
static struct irq_chip armada_370_xp_irq_chip = { static struct irq_chip armada_370_xp_irq_chip = {
.name = "armada_370_xp_irq", .name = "armada_370_xp_irq",
.irq_mask = armada_370_xp_irq_mask, .irq_mask = armada_370_xp_irq_mask,
.irq_mask_ack = armada_370_xp_irq_mask, .irq_mask_ack = armada_370_xp_irq_mask,
.irq_unmask = armada_370_xp_irq_unmask, .irq_unmask = armada_370_xp_irq_unmask,
#ifdef CONFIG_SMP
.irq_set_affinity = armada_xp_set_affinity,
#endif
}; };
static int armada_370_xp_mpic_irq_map(struct irq_domain *h, static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
...@@ -72,6 +91,41 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h, ...@@ -72,6 +91,41 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
return 0; return 0;
} }
#ifdef CONFIG_SMP
void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq)
{
int cpu;
unsigned long map = 0;
/* Convert our logical CPU mask into a physical one. */
for_each_cpu(cpu, mask)
map |= 1 << cpu_logical_map(cpu);
/*
* Ensure that stores to Normal memory are visible to the
* other CPUs before issuing the IPI.
*/
dsb();
/* submit softirq */
writel((map << 8) | irq, main_int_base +
ARMADA_370_XP_SW_TRIG_INT_OFFS);
}
void armada_xp_mpic_smp_cpu_init(void)
{
/* Clear pending IPIs */
writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
/* Enable first 8 IPIs */
writel((1 << ACTIVE_DOORBELLS) - 1, per_cpu_int_base +
ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
/* Unmask IPI interrupt */
writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
}
#endif /* CONFIG_SMP */
static struct irq_domain_ops armada_370_xp_mpic_irq_ops = { static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
.map = armada_370_xp_mpic_irq_map, .map = armada_370_xp_mpic_irq_map,
.xlate = irq_domain_xlate_onecell, .xlate = irq_domain_xlate_onecell,
...@@ -91,13 +145,18 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node, ...@@ -91,13 +145,18 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL); control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL);
armada_370_xp_mpic_domain = armada_370_xp_mpic_domain =
irq_domain_add_linear(node, (control >> 2) & 0x3ff, irq_domain_add_linear(node, (control >> 2) & 0x3ff,
&armada_370_xp_mpic_irq_ops, NULL); &armada_370_xp_mpic_irq_ops, NULL);
if (!armada_370_xp_mpic_domain) if (!armada_370_xp_mpic_domain)
panic("Unable to add Armada_370_Xp MPIC irq domain (DT)\n"); panic("Unable to add Armada_370_Xp MPIC irq domain (DT)\n");
irq_set_default_host(armada_370_xp_mpic_domain); irq_set_default_host(armada_370_xp_mpic_domain);
#ifdef CONFIG_SMP
armada_xp_mpic_smp_cpu_init();
#endif
return 0; return 0;
} }
...@@ -111,14 +170,36 @@ asmlinkage void __exception_irq_entry armada_370_xp_handle_irq(struct pt_regs ...@@ -111,14 +170,36 @@ asmlinkage void __exception_irq_entry armada_370_xp_handle_irq(struct pt_regs
ARMADA_370_XP_CPU_INTACK_OFFS); ARMADA_370_XP_CPU_INTACK_OFFS);
irqnr = irqstat & 0x3FF; irqnr = irqstat & 0x3FF;
if (irqnr < 1023) { if (irqnr > 1022)
irqnr = break;
irq_find_mapping(armada_370_xp_mpic_domain, irqnr);
if (irqnr >= 8) {
irqnr = irq_find_mapping(armada_370_xp_mpic_domain,
irqnr);
handle_IRQ(irqnr, regs); handle_IRQ(irqnr, regs);
continue; continue;
} }
#ifdef CONFIG_SMP
/* IPI Handling */
if (irqnr == 0) {
u32 ipimask, ipinr;
ipimask = readl_relaxed(per_cpu_int_base +
ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
& 0xFF;
writel(0x0, per_cpu_int_base +
ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
/* Handle all pending doorbells */
for (ipinr = 0; ipinr < ACTIVE_DOORBELLS; ipinr++) {
if (ipimask & (0x1 << ipinr))
handle_IPI(ipinr, regs);
}
continue;
}
#endif
break;
} while (1); } while (1);
} }
...@@ -130,4 +211,7 @@ static const struct of_device_id mpic_of_match[] __initconst = { ...@@ -130,4 +211,7 @@ static const struct of_device_id mpic_of_match[] __initconst = {
void __init armada_370_xp_init_irq(void) void __init armada_370_xp_init_irq(void)
{ {
of_irq_init(mpic_of_match); of_irq_init(mpic_of_match);
#ifdef CONFIG_CACHE_L2X0
l2x0_of_init(0, ~0UL);
#endif
} }
/*
* Symmetric Multi Processing (SMP) support for Armada XP
*
* Copyright (C) 2012 Marvell
*
* Lior Amsalem <alior@marvell.com>
* Yehuda Yitschak <yehuday@marvell.com>
* Gregory CLEMENT <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*
* The Armada XP SoC has 4 ARMv7 PJ4B CPUs running in full HW coherency
* This file implements the routines for preparing the SMP infrastructure
* and waking up the secondary CPUs
*/
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <asm/cacheflush.h>
#include <asm/smp_plat.h>
#include "common.h"
#include "armada-370-xp.h"
#include "pmsu.h"
#include "coherency.h"
void __init set_secondary_cpus_clock(void)
{
int thiscpu;
unsigned long rate;
struct clk *cpu_clk = NULL;
struct device_node *np = NULL;
thiscpu = smp_processor_id();
for_each_node_by_type(np, "cpu") {
int err;
int cpu;
err = of_property_read_u32(np, "reg", &cpu);
if (WARN_ON(err))
return;
if (cpu == thiscpu) {
cpu_clk = of_clk_get(np, 0);
break;
}
}
if (WARN_ON(IS_ERR(cpu_clk)))
return;
clk_prepare_enable(cpu_clk);
rate = clk_get_rate(cpu_clk);
/* set all the other CPU clk to the same rate than the boot CPU */
for_each_node_by_type(np, "cpu") {
int err;
int cpu;
err = of_property_read_u32(np, "reg", &cpu);
if (WARN_ON(err))
return;
if (cpu != thiscpu) {
cpu_clk = of_clk_get(np, 0);
clk_set_rate(cpu_clk, rate);
}
}
}
static void __cpuinit armada_xp_secondary_init(unsigned int cpu)
{
armada_xp_mpic_smp_cpu_init();
}
static int __cpuinit armada_xp_boot_secondary(unsigned int cpu,
struct task_struct *idle)
{
pr_info("Booting CPU %d\n", cpu);
armada_xp_boot_cpu(cpu, armada_xp_secondary_startup);
return 0;
}
static void __init armada_xp_smp_init_cpus(void)
{
unsigned int i, ncores;
ncores = coherency_get_cpu_count();
/* Limit possible CPUs to defconfig */
if (ncores > nr_cpu_ids) {
pr_warn("SMP: %d CPUs physically present. Only %d configured.",
ncores, nr_cpu_ids);
pr_warn("Clipping CPU count to %d\n", nr_cpu_ids);
ncores = nr_cpu_ids;
}
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
set_smp_cross_call(armada_mpic_send_doorbell);
}
void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
{
set_secondary_cpus_clock();
flush_cache_all();
set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0);
}
struct smp_operations armada_xp_smp_ops __initdata = {
.smp_init_cpus = armada_xp_smp_init_cpus,
.smp_prepare_cpus = armada_xp_smp_prepare_cpus,
.smp_secondary_init = armada_xp_secondary_init,
.smp_boot_secondary = armada_xp_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
.cpu_die = armada_xp_cpu_die,
#endif
};
/*
* Power Management Service Unit(PMSU) support for Armada 370/XP platforms.
*
* Copyright (C) 2012 Marvell
*
* Yehuda Yitschak <yehuday@marvell.com>
* Gregory Clement <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*
* The Armada 370 and Armada XP SOCs have a power management service
* unit which is responsible for powering down and waking up CPUs and
* other SOC units
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/smp.h>
#include <asm/smp_plat.h>
static void __iomem *pmsu_mp_base;
static void __iomem *pmsu_reset_base;
#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x24)
#define PMSU_RESET_CTL_OFFSET(cpu) (cpu * 0x8)
static struct of_device_id of_pmsu_table[] = {
{.compatible = "marvell,armada-370-xp-pmsu"},
{ /* end of list */ },
};
#ifdef CONFIG_SMP
int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr)
{
int reg, hw_cpu;
if (!pmsu_mp_base || !pmsu_reset_base) {
pr_warn("Can't boot CPU. PMSU is uninitialized\n");
return 1;
}
hw_cpu = cpu_logical_map(cpu_id);
writel(virt_to_phys(boot_addr), pmsu_mp_base +
PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
/* Release CPU from reset by clearing reset bit*/
reg = readl(pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu));
reg &= (~0x1);
writel(reg, pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu));
return 0;
}
#endif
int __init armada_370_xp_pmsu_init(void)
{
struct device_node *np;
np = of_find_matching_node(NULL, of_pmsu_table);
if (np) {
pr_info("Initializing Power Management Service Unit\n");
pmsu_mp_base = of_iomap(np, 0);
pmsu_reset_base = of_iomap(np, 1);
}
return 0;
}
early_initcall(armada_370_xp_pmsu_init);
/*
* Power Management Service Unit (PMSU) support for Armada 370/XP platforms.
*
* Copyright (C) 2012 Marvell
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __MACH_MVEBU_PMSU_H
#define __MACH_MVEBU_PMSU_H
int armada_xp_boot_cpu(unsigned int cpu_id, void *phys_addr);
#endif /* __MACH_370_XP_PMSU_H */
...@@ -352,6 +352,10 @@ config CPU_PJ4 ...@@ -352,6 +352,10 @@ config CPU_PJ4
select ARM_THUMBEE select ARM_THUMBEE
select CPU_V7 select CPU_V7
config CPU_PJ4B
bool
select CPU_V7
# ARMv6 # ARMv6
config CPU_V6 config CPU_V6
bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX
......
...@@ -124,8 +124,6 @@ static void arm_dma_sync_single_for_device(struct device *dev, ...@@ -124,8 +124,6 @@ static void arm_dma_sync_single_for_device(struct device *dev,
__dma_page_cpu_to_dev(page, offset, size, dir); __dma_page_cpu_to_dev(page, offset, size, dir);
} }
static int arm_dma_set_mask(struct device *dev, u64 dma_mask);
struct dma_map_ops arm_dma_ops = { struct dma_map_ops arm_dma_ops = {
.alloc = arm_dma_alloc, .alloc = arm_dma_alloc,
.free = arm_dma_free, .free = arm_dma_free,
...@@ -971,7 +969,7 @@ int dma_supported(struct device *dev, u64 mask) ...@@ -971,7 +969,7 @@ int dma_supported(struct device *dev, u64 mask)
} }
EXPORT_SYMBOL(dma_supported); EXPORT_SYMBOL(dma_supported);
static int arm_dma_set_mask(struct device *dev, u64 dma_mask) int arm_dma_set_mask(struct device *dev, u64 dma_mask)
{ {
if (!dev->dma_mask || !dma_supported(dev, dma_mask)) if (!dev->dma_mask || !dma_supported(dev, dma_mask))
return -EIO; return -EIO;
......
...@@ -169,6 +169,63 @@ __v7_ca15mp_setup: ...@@ -169,6 +169,63 @@ __v7_ca15mp_setup:
orreq r0, r0, r10 @ Enable CPU-specific SMP bits orreq r0, r0, r10 @ Enable CPU-specific SMP bits
mcreq p15, 0, r0, c1, c0, 1 mcreq p15, 0, r0, c1, c0, 1
#endif #endif
__v7_pj4b_setup:
#ifdef CONFIG_CPU_PJ4B
/* Auxiliary Debug Modes Control 1 Register */
#define PJ4B_STATIC_BP (1 << 2) /* Enable Static BP */
#define PJ4B_INTER_PARITY (1 << 8) /* Disable Internal Parity Handling */
#define PJ4B_BCK_OFF_STREX (1 << 5) /* Enable the back off of STREX instr */
#define PJ4B_CLEAN_LINE (1 << 16) /* Disable data transfer for clean line */
/* Auxiliary Debug Modes Control 2 Register */
#define PJ4B_FAST_LDR (1 << 23) /* Disable fast LDR */
#define PJ4B_SNOOP_DATA (1 << 25) /* Do not interleave write and snoop data */
#define PJ4B_CWF (1 << 27) /* Disable Critical Word First feature */
#define PJ4B_OUTSDNG_NC (1 << 29) /* Disable outstanding non cacheable rqst */
#define PJ4B_L1_REP_RR (1 << 30) /* L1 replacement - Strict round robin */
#define PJ4B_AUX_DBG_CTRL2 (PJ4B_SNOOP_DATA | PJ4B_CWF |\
PJ4B_OUTSDNG_NC | PJ4B_L1_REP_RR)
/* Auxiliary Functional Modes Control Register 0 */
#define PJ4B_SMP_CFB (1 << 1) /* Set SMP mode. Join the coherency fabric */
#define PJ4B_L1_PAR_CHK (1 << 2) /* Support L1 parity checking */
#define PJ4B_BROADCAST_CACHE (1 << 8) /* Broadcast Cache and TLB maintenance */
/* Auxiliary Debug Modes Control 0 Register */
#define PJ4B_WFI_WFE (1 << 22) /* WFI/WFE - serve the DVM and back to idle */
/* Auxiliary Debug Modes Control 1 Register */
mrc p15, 1, r0, c15, c1, 1
orr r0, r0, #PJ4B_CLEAN_LINE
orr r0, r0, #PJ4B_BCK_OFF_STREX
orr r0, r0, #PJ4B_INTER_PARITY
bic r0, r0, #PJ4B_STATIC_BP
mcr p15, 1, r0, c15, c1, 1
/* Auxiliary Debug Modes Control 2 Register */
mrc p15, 1, r0, c15, c1, 2
bic r0, r0, #PJ4B_FAST_LDR
orr r0, r0, #PJ4B_AUX_DBG_CTRL2
mcr p15, 1, r0, c15, c1, 2
/* Auxiliary Functional Modes Control Register 0 */
mrc p15, 1, r0, c15, c2, 0
#ifdef CONFIG_SMP
orr r0, r0, #PJ4B_SMP_CFB
#endif
orr r0, r0, #PJ4B_L1_PAR_CHK
orr r0, r0, #PJ4B_BROADCAST_CACHE
mcr p15, 1, r0, c15, c2, 0
/* Auxiliary Debug Modes Control 0 Register */
mrc p15, 1, r0, c15, c1, 0
orr r0, r0, #PJ4B_WFI_WFE
mcr p15, 1, r0, c15, c1, 0
#endif /* CONFIG_CPU_PJ4B */
__v7_setup: __v7_setup:
adr r12, __v7_setup_stack @ the local stack adr r12, __v7_setup_stack @ the local stack
stmia r12, {r0-r5, r7, r9, r11, lr} stmia r12, {r0-r5, r7, r9, r11, lr}
...@@ -342,6 +399,16 @@ __v7_ca9mp_proc_info: ...@@ -342,6 +399,16 @@ __v7_ca9mp_proc_info:
.long 0xff0ffff0 .long 0xff0ffff0
__v7_proc __v7_ca9mp_setup __v7_proc __v7_ca9mp_setup
.size __v7_ca9mp_proc_info, . - __v7_ca9mp_proc_info .size __v7_ca9mp_proc_info, . - __v7_ca9mp_proc_info
/*
* Marvell PJ4B processor.
*/
.type __v7_pj4b_proc_info, #object
__v7_pj4b_proc_info:
.long 0x562f5840
.long 0xfffffff0
__v7_proc __v7_pj4b_setup
.size __v7_pj4b_proc_info, . - __v7_pj4b_proc_info
#endif /* CONFIG_ARM_LPAE */ #endif /* CONFIG_ARM_LPAE */
/* /*
......
...@@ -42,6 +42,8 @@ EXPORT_SYMBOL_GPL(mv_mbus_dram_info); ...@@ -42,6 +42,8 @@ EXPORT_SYMBOL_GPL(mv_mbus_dram_info);
#define WIN_REMAP_LO_OFF 0x0008 #define WIN_REMAP_LO_OFF 0x0008
#define WIN_REMAP_HI_OFF 0x000c #define WIN_REMAP_HI_OFF 0x000c
#define ATTR_HW_COHERENCY (0x1 << 4)
/* /*
* Default implementation * Default implementation
*/ */
...@@ -163,6 +165,8 @@ void __init orion_setup_cpu_mbus_target(const struct orion_addr_map_cfg *cfg, ...@@ -163,6 +165,8 @@ void __init orion_setup_cpu_mbus_target(const struct orion_addr_map_cfg *cfg,
w = &orion_mbus_dram_info.cs[cs++]; w = &orion_mbus_dram_info.cs[cs++];
w->cs_index = i; w->cs_index = i;
w->mbus_attr = 0xf & ~(1 << i); w->mbus_attr = 0xf & ~(1 << i);
if (cfg->hw_io_coherency)
w->mbus_attr |= ATTR_HW_COHERENCY;
w->base = base & 0xffff0000; w->base = base & 0xffff0000;
w->size = (size | 0x0000ffff) + 1; w->size = (size | 0x0000ffff) + 1;
} }
......
...@@ -606,26 +606,6 @@ void __init orion_wdt_init(void) ...@@ -606,26 +606,6 @@ void __init orion_wdt_init(void)
****************************************************************************/ ****************************************************************************/
static u64 orion_xor_dmamask = DMA_BIT_MASK(32); static u64 orion_xor_dmamask = DMA_BIT_MASK(32);
void __init orion_xor_init_channels(
struct mv_xor_platform_data *orion_xor0_data,
struct platform_device *orion_xor0_channel,
struct mv_xor_platform_data *orion_xor1_data,
struct platform_device *orion_xor1_channel)
{
/*
* two engines can't do memset simultaneously, this limitation
* satisfied by removing memset support from one of the engines.
*/
dma_cap_set(DMA_MEMCPY, orion_xor0_data->cap_mask);
dma_cap_set(DMA_XOR, orion_xor0_data->cap_mask);
platform_device_register(orion_xor0_channel);
dma_cap_set(DMA_MEMCPY, orion_xor1_data->cap_mask);
dma_cap_set(DMA_MEMSET, orion_xor1_data->cap_mask);
dma_cap_set(DMA_XOR, orion_xor1_data->cap_mask);
platform_device_register(orion_xor1_channel);
}
/***************************************************************************** /*****************************************************************************
* XOR0 * XOR0
****************************************************************************/ ****************************************************************************/
...@@ -636,61 +616,30 @@ static struct resource orion_xor0_shared_resources[] = { ...@@ -636,61 +616,30 @@ static struct resource orion_xor0_shared_resources[] = {
}, { }, {
.name = "xor 0 high", .name = "xor 0 high",
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, {
.name = "irq channel 0",
.flags = IORESOURCE_IRQ,
}, {
.name = "irq channel 1",
.flags = IORESOURCE_IRQ,
}, },
}; };
static struct platform_device orion_xor0_shared = { static struct mv_xor_channel_data orion_xor0_channels_data[2];
.name = MV_XOR_SHARED_NAME,
.id = 0,
.num_resources = ARRAY_SIZE(orion_xor0_shared_resources),
.resource = orion_xor0_shared_resources,
};
static struct resource orion_xor00_resources[] = { static struct mv_xor_platform_data orion_xor0_pdata = {
[0] = { .channels = orion_xor0_channels_data,
.flags = IORESOURCE_IRQ,
},
};
static struct mv_xor_platform_data orion_xor00_data = {
.shared = &orion_xor0_shared,
.hw_id = 0,
.pool_size = PAGE_SIZE,
}; };
static struct platform_device orion_xor00_channel = { static struct platform_device orion_xor0_shared = {
.name = MV_XOR_NAME, .name = MV_XOR_NAME,
.id = 0, .id = 0,
.num_resources = ARRAY_SIZE(orion_xor00_resources), .num_resources = ARRAY_SIZE(orion_xor0_shared_resources),
.resource = orion_xor00_resources, .resource = orion_xor0_shared_resources,
.dev = { .dev = {
.dma_mask = &orion_xor_dmamask, .dma_mask = &orion_xor_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(64), .coherent_dma_mask = DMA_BIT_MASK(64),
.platform_data = &orion_xor00_data, .platform_data = &orion_xor0_pdata,
},
};
static struct resource orion_xor01_resources[] = {
[0] = {
.flags = IORESOURCE_IRQ,
},
};
static struct mv_xor_platform_data orion_xor01_data = {
.shared = &orion_xor0_shared,
.hw_id = 1,
.pool_size = PAGE_SIZE,
};
static struct platform_device orion_xor01_channel = {
.name = MV_XOR_NAME,
.id = 1,
.num_resources = ARRAY_SIZE(orion_xor01_resources),
.resource = orion_xor01_resources,
.dev = {
.dma_mask = &orion_xor_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(64),
.platform_data = &orion_xor01_data,
}, },
}; };
...@@ -704,15 +653,23 @@ void __init orion_xor0_init(unsigned long mapbase_low, ...@@ -704,15 +653,23 @@ void __init orion_xor0_init(unsigned long mapbase_low,
orion_xor0_shared_resources[1].start = mapbase_high; orion_xor0_shared_resources[1].start = mapbase_high;
orion_xor0_shared_resources[1].end = mapbase_high + 0xff; orion_xor0_shared_resources[1].end = mapbase_high + 0xff;
orion_xor00_resources[0].start = irq_0; orion_xor0_shared_resources[2].start = irq_0;
orion_xor00_resources[0].end = irq_0; orion_xor0_shared_resources[2].end = irq_0;
orion_xor01_resources[0].start = irq_1; orion_xor0_shared_resources[3].start = irq_1;
orion_xor01_resources[0].end = irq_1; orion_xor0_shared_resources[3].end = irq_1;
platform_device_register(&orion_xor0_shared); /*
* two engines can't do memset simultaneously, this limitation
* satisfied by removing memset support from one of the engines.
*/
dma_cap_set(DMA_MEMCPY, orion_xor0_channels_data[0].cap_mask);
dma_cap_set(DMA_XOR, orion_xor0_channels_data[0].cap_mask);
dma_cap_set(DMA_MEMSET, orion_xor0_channels_data[1].cap_mask);
dma_cap_set(DMA_MEMCPY, orion_xor0_channels_data[1].cap_mask);
dma_cap_set(DMA_XOR, orion_xor0_channels_data[1].cap_mask);
orion_xor_init_channels(&orion_xor00_data, &orion_xor00_channel, platform_device_register(&orion_xor0_shared);
&orion_xor01_data, &orion_xor01_channel);
} }
/***************************************************************************** /*****************************************************************************
...@@ -725,61 +682,30 @@ static struct resource orion_xor1_shared_resources[] = { ...@@ -725,61 +682,30 @@ static struct resource orion_xor1_shared_resources[] = {
}, { }, {
.name = "xor 1 high", .name = "xor 1 high",
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, {
.name = "irq channel 0",
.flags = IORESOURCE_IRQ,
}, {
.name = "irq channel 1",
.flags = IORESOURCE_IRQ,
}, },
}; };
static struct platform_device orion_xor1_shared = { static struct mv_xor_channel_data orion_xor1_channels_data[2];
.name = MV_XOR_SHARED_NAME,
.id = 1,
.num_resources = ARRAY_SIZE(orion_xor1_shared_resources),
.resource = orion_xor1_shared_resources,
};
static struct resource orion_xor10_resources[] = {
[0] = {
.flags = IORESOURCE_IRQ,
},
};
static struct mv_xor_platform_data orion_xor10_data = {
.shared = &orion_xor1_shared,
.hw_id = 0,
.pool_size = PAGE_SIZE,
};
static struct platform_device orion_xor10_channel = {
.name = MV_XOR_NAME,
.id = 2,
.num_resources = ARRAY_SIZE(orion_xor10_resources),
.resource = orion_xor10_resources,
.dev = {
.dma_mask = &orion_xor_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(64),
.platform_data = &orion_xor10_data,
},
};
static struct resource orion_xor11_resources[] = {
[0] = {
.flags = IORESOURCE_IRQ,
},
};
static struct mv_xor_platform_data orion_xor11_data = { static struct mv_xor_platform_data orion_xor1_pdata = {
.shared = &orion_xor1_shared, .channels = orion_xor1_channels_data,
.hw_id = 1,
.pool_size = PAGE_SIZE,
}; };
static struct platform_device orion_xor11_channel = { static struct platform_device orion_xor1_shared = {
.name = MV_XOR_NAME, .name = MV_XOR_NAME,
.id = 3, .id = 1,
.num_resources = ARRAY_SIZE(orion_xor11_resources), .num_resources = ARRAY_SIZE(orion_xor1_shared_resources),
.resource = orion_xor11_resources, .resource = orion_xor1_shared_resources,
.dev = { .dev = {
.dma_mask = &orion_xor_dmamask, .dma_mask = &orion_xor_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(64), .coherent_dma_mask = DMA_BIT_MASK(64),
.platform_data = &orion_xor11_data, .platform_data = &orion_xor1_pdata,
}, },
}; };
...@@ -793,15 +719,23 @@ void __init orion_xor1_init(unsigned long mapbase_low, ...@@ -793,15 +719,23 @@ void __init orion_xor1_init(unsigned long mapbase_low,
orion_xor1_shared_resources[1].start = mapbase_high; orion_xor1_shared_resources[1].start = mapbase_high;
orion_xor1_shared_resources[1].end = mapbase_high + 0xff; orion_xor1_shared_resources[1].end = mapbase_high + 0xff;
orion_xor10_resources[0].start = irq_0; orion_xor1_shared_resources[2].start = irq_0;
orion_xor10_resources[0].end = irq_0; orion_xor1_shared_resources[2].end = irq_0;
orion_xor11_resources[0].start = irq_1; orion_xor1_shared_resources[3].start = irq_1;
orion_xor11_resources[0].end = irq_1; orion_xor1_shared_resources[3].end = irq_1;
platform_device_register(&orion_xor1_shared); /*
* two engines can't do memset simultaneously, this limitation
* satisfied by removing memset support from one of the engines.
*/
dma_cap_set(DMA_MEMCPY, orion_xor1_channels_data[0].cap_mask);
dma_cap_set(DMA_XOR, orion_xor1_channels_data[0].cap_mask);
orion_xor_init_channels(&orion_xor10_data, &orion_xor10_channel, dma_cap_set(DMA_MEMSET, orion_xor1_channels_data[1].cap_mask);
&orion_xor11_data, &orion_xor11_channel); dma_cap_set(DMA_MEMCPY, orion_xor1_channels_data[1].cap_mask);
dma_cap_set(DMA_XOR, orion_xor1_channels_data[1].cap_mask);
platform_device_register(&orion_xor1_shared);
} }
/***************************************************************************** /*****************************************************************************
......
...@@ -17,6 +17,7 @@ struct orion_addr_map_cfg { ...@@ -17,6 +17,7 @@ struct orion_addr_map_cfg {
const int num_wins; /* Total number of windows */ const int num_wins; /* Total number of windows */
const int remappable_wins; const int remappable_wins;
void __iomem *bridge_virt_base; void __iomem *bridge_virt_base;
int hw_io_coherency;
/* If NULL, the default cpu_win_can_remap will be used, using /* If NULL, the default cpu_win_can_remap will be used, using
the value in remappable_wins */ the value in remappable_wins */
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/mv643xx_eth.h> #include <linux/mv643xx_eth.h>
struct dsa_platform_data; struct dsa_platform_data;
struct mv_sata_platform_data;
void __init orion_uart0_init(void __iomem *membase, void __init orion_uart0_init(void __iomem *membase,
resource_size_t mapbase, resource_size_t mapbase,
......
...@@ -64,3 +64,5 @@ config CLK_TWL6040 ...@@ -64,3 +64,5 @@ config CLK_TWL6040
as functional clock. as functional clock.
endmenu endmenu
source "drivers/clk/mvebu/Kconfig"
...@@ -13,6 +13,7 @@ obj-$(CONFIG_PLAT_SPEAR) += spear/ ...@@ -13,6 +13,7 @@ obj-$(CONFIG_PLAT_SPEAR) += spear/
obj-$(CONFIG_ARCH_U300) += clk-u300.o obj-$(CONFIG_ARCH_U300) += clk-u300.o
obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
obj-$(CONFIG_ARCH_PRIMA2) += clk-prima2.o obj-$(CONFIG_ARCH_PRIMA2) += clk-prima2.o
obj-$(CONFIG_PLAT_ORION) += mvebu/
ifeq ($(CONFIG_COMMON_CLK), y) ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/ obj-$(CONFIG_ARCH_MMP) += mmp/
endif endif
......
config MVEBU_CLK_CORE
bool
config MVEBU_CLK_CPU
bool
config MVEBU_CLK_GATING
bool
obj-$(CONFIG_MVEBU_CLK_CORE) += clk.o clk-core.o
obj-$(CONFIG_MVEBU_CLK_CPU) += clk-cpu.o
obj-$(CONFIG_MVEBU_CLK_GATING) += clk-gating-ctrl.o
/*
* Marvell EBU clock core handling defined at reset
*
* Copyright (C) 2012 Marvell
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/of.h>
#include "clk-core.h"
struct core_ratio {
int id;
const char *name;
};
struct core_clocks {
u32 (*get_tclk_freq)(void __iomem *sar);
u32 (*get_cpu_freq)(void __iomem *sar);
void (*get_clk_ratio)(void __iomem *sar, int id, int *mult, int *div);
const struct core_ratio *ratios;
int num_ratios;
};
static struct clk_onecell_data clk_data;
static void __init mvebu_clk_core_setup(struct device_node *np,
struct core_clocks *coreclk)
{
const char *tclk_name = "tclk";
const char *cpuclk_name = "cpuclk";
void __iomem *base;
unsigned long rate;
int n;
base = of_iomap(np, 0);
if (WARN_ON(!base))
return;
/*
* Allocate struct for TCLK, cpu clk, and core ratio clocks
*/
clk_data.clk_num = 2 + coreclk->num_ratios;
clk_data.clks = kzalloc(clk_data.clk_num * sizeof(struct clk *),
GFP_KERNEL);
if (WARN_ON(!clk_data.clks))
return;
/*
* Register TCLK
*/
of_property_read_string_index(np, "clock-output-names", 0,
&tclk_name);
rate = coreclk->get_tclk_freq(base);
clk_data.clks[0] = clk_register_fixed_rate(NULL, tclk_name, NULL,
CLK_IS_ROOT, rate);
WARN_ON(IS_ERR(clk_data.clks[0]));
/*
* Register CPU clock
*/
of_property_read_string_index(np, "clock-output-names", 1,
&cpuclk_name);
rate = coreclk->get_cpu_freq(base);
clk_data.clks[1] = clk_register_fixed_rate(NULL, cpuclk_name, NULL,
CLK_IS_ROOT, rate);
WARN_ON(IS_ERR(clk_data.clks[1]));
/*
* Register fixed-factor clocks derived from CPU clock
*/
for (n = 0; n < coreclk->num_ratios; n++) {
const char *rclk_name = coreclk->ratios[n].name;
int mult, div;
of_property_read_string_index(np, "clock-output-names",
2+n, &rclk_name);
coreclk->get_clk_ratio(base, coreclk->ratios[n].id,
&mult, &div);
clk_data.clks[2+n] = clk_register_fixed_factor(NULL, rclk_name,
cpuclk_name, 0, mult, div);
WARN_ON(IS_ERR(clk_data.clks[2+n]));
};
/*
* SAR register isn't needed anymore
*/
iounmap(base);
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
}
#ifdef CONFIG_MACH_ARMADA_370_XP
/*
* Armada 370/XP Sample At Reset is a 64 bit bitfiled split in two
* register of 32 bits
*/
#define SARL 0 /* Low part [0:31] */
#define SARL_AXP_PCLK_FREQ_OPT 21
#define SARL_AXP_PCLK_FREQ_OPT_MASK 0x7
#define SARL_A370_PCLK_FREQ_OPT 11
#define SARL_A370_PCLK_FREQ_OPT_MASK 0xF
#define SARL_AXP_FAB_FREQ_OPT 24
#define SARL_AXP_FAB_FREQ_OPT_MASK 0xF
#define SARL_A370_FAB_FREQ_OPT 15
#define SARL_A370_FAB_FREQ_OPT_MASK 0x1F
#define SARL_A370_TCLK_FREQ_OPT 20
#define SARL_A370_TCLK_FREQ_OPT_MASK 0x1
#define SARH 4 /* High part [32:63] */
#define SARH_AXP_PCLK_FREQ_OPT (52-32)
#define SARH_AXP_PCLK_FREQ_OPT_MASK 0x1
#define SARH_AXP_PCLK_FREQ_OPT_SHIFT 3
#define SARH_AXP_FAB_FREQ_OPT (51-32)
#define SARH_AXP_FAB_FREQ_OPT_MASK 0x1
#define SARH_AXP_FAB_FREQ_OPT_SHIFT 4
static const u32 __initconst armada_370_tclk_frequencies[] = {
16600000,
20000000,
};
static u32 __init armada_370_get_tclk_freq(void __iomem *sar)
{
u8 tclk_freq_select = 0;
tclk_freq_select = ((readl(sar) >> SARL_A370_TCLK_FREQ_OPT) &
SARL_A370_TCLK_FREQ_OPT_MASK);
return armada_370_tclk_frequencies[tclk_freq_select];
}
static const u32 __initconst armada_370_cpu_frequencies[] = {
400000000,
533000000,
667000000,
800000000,
1000000000,
1067000000,
1200000000,
};
static u32 __init armada_370_get_cpu_freq(void __iomem *sar)
{
u32 cpu_freq;
u8 cpu_freq_select = 0;
cpu_freq_select = ((readl(sar) >> SARL_A370_PCLK_FREQ_OPT) &
SARL_A370_PCLK_FREQ_OPT_MASK);
if (cpu_freq_select > ARRAY_SIZE(armada_370_cpu_frequencies)) {
pr_err("CPU freq select unsuported %d\n", cpu_freq_select);
cpu_freq = 0;
} else
cpu_freq = armada_370_cpu_frequencies[cpu_freq_select];
return cpu_freq;
}
enum { A370_XP_NBCLK, A370_XP_HCLK, A370_XP_DRAMCLK };
static const struct core_ratio __initconst armada_370_xp_core_ratios[] = {
{ .id = A370_XP_NBCLK, .name = "nbclk" },
{ .id = A370_XP_HCLK, .name = "hclk" },
{ .id = A370_XP_DRAMCLK, .name = "dramclk" },
};
static const int __initconst armada_370_xp_nbclk_ratios[32][2] = {
{0, 1}, {1, 2}, {2, 2}, {2, 2},
{1, 2}, {1, 2}, {1, 1}, {2, 3},
{0, 1}, {1, 2}, {2, 4}, {0, 1},
{1, 2}, {0, 1}, {0, 1}, {2, 2},
{0, 1}, {0, 1}, {0, 1}, {1, 1},
{2, 3}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {1, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
};
static const int __initconst armada_370_xp_hclk_ratios[32][2] = {
{0, 1}, {1, 2}, {2, 6}, {2, 3},
{1, 3}, {1, 4}, {1, 2}, {2, 6},
{0, 1}, {1, 6}, {2, 10}, {0, 1},
{1, 4}, {0, 1}, {0, 1}, {2, 5},
{0, 1}, {0, 1}, {0, 1}, {1, 2},
{2, 6}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {1, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
};
static const int __initconst armada_370_xp_dramclk_ratios[32][2] = {
{0, 1}, {1, 2}, {2, 3}, {2, 3},
{1, 3}, {1, 2}, {1, 2}, {2, 6},
{0, 1}, {1, 3}, {2, 5}, {0, 1},
{1, 4}, {0, 1}, {0, 1}, {2, 5},
{0, 1}, {0, 1}, {0, 1}, {1, 1},
{2, 3}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {1, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
};
static void __init armada_370_xp_get_clk_ratio(u32 opt,
void __iomem *sar, int id, int *mult, int *div)
{
switch (id) {
case A370_XP_NBCLK:
*mult = armada_370_xp_nbclk_ratios[opt][0];
*div = armada_370_xp_nbclk_ratios[opt][1];
break;
case A370_XP_HCLK:
*mult = armada_370_xp_hclk_ratios[opt][0];
*div = armada_370_xp_hclk_ratios[opt][1];
break;
case A370_XP_DRAMCLK:
*mult = armada_370_xp_dramclk_ratios[opt][0];
*div = armada_370_xp_dramclk_ratios[opt][1];
break;
}
}
static void __init armada_370_get_clk_ratio(
void __iomem *sar, int id, int *mult, int *div)
{
u32 opt = ((readl(sar) >> SARL_A370_FAB_FREQ_OPT) &
SARL_A370_FAB_FREQ_OPT_MASK);
armada_370_xp_get_clk_ratio(opt, sar, id, mult, div);
}
static const struct core_clocks armada_370_core_clocks = {
.get_tclk_freq = armada_370_get_tclk_freq,
.get_cpu_freq = armada_370_get_cpu_freq,
.get_clk_ratio = armada_370_get_clk_ratio,
.ratios = armada_370_xp_core_ratios,
.num_ratios = ARRAY_SIZE(armada_370_xp_core_ratios),
};
static const u32 __initconst armada_xp_cpu_frequencies[] = {
1000000000,
1066000000,
1200000000,
1333000000,
1500000000,
1666000000,
1800000000,
2000000000,
667000000,
0,
800000000,
1600000000,
};
/* For Armada XP TCLK frequency is fix: 250MHz */
static u32 __init armada_xp_get_tclk_freq(void __iomem *sar)
{
return 250 * 1000 * 1000;
}
static u32 __init armada_xp_get_cpu_freq(void __iomem *sar)
{
u32 cpu_freq;
u8 cpu_freq_select = 0;
cpu_freq_select = ((readl(sar) >> SARL_AXP_PCLK_FREQ_OPT) &
SARL_AXP_PCLK_FREQ_OPT_MASK);
/*
* The upper bit is not contiguous to the other ones and
* located in the high part of the SAR registers
*/
cpu_freq_select |= (((readl(sar+4) >> SARH_AXP_PCLK_FREQ_OPT) &
SARH_AXP_PCLK_FREQ_OPT_MASK)
<< SARH_AXP_PCLK_FREQ_OPT_SHIFT);
if (cpu_freq_select > ARRAY_SIZE(armada_xp_cpu_frequencies)) {
pr_err("CPU freq select unsuported: %d\n", cpu_freq_select);
cpu_freq = 0;
} else
cpu_freq = armada_xp_cpu_frequencies[cpu_freq_select];
return cpu_freq;
}
static void __init armada_xp_get_clk_ratio(
void __iomem *sar, int id, int *mult, int *div)
{
u32 opt = ((readl(sar) >> SARL_AXP_FAB_FREQ_OPT) &
SARL_AXP_FAB_FREQ_OPT_MASK);
/*
* The upper bit is not contiguous to the other ones and
* located in the high part of the SAR registers
*/
opt |= (((readl(sar+4) >> SARH_AXP_FAB_FREQ_OPT) &
SARH_AXP_FAB_FREQ_OPT_MASK)
<< SARH_AXP_FAB_FREQ_OPT_SHIFT);
armada_370_xp_get_clk_ratio(opt, sar, id, mult, div);
}
static const struct core_clocks armada_xp_core_clocks = {
.get_tclk_freq = armada_xp_get_tclk_freq,
.get_cpu_freq = armada_xp_get_cpu_freq,
.get_clk_ratio = armada_xp_get_clk_ratio,
.ratios = armada_370_xp_core_ratios,
.num_ratios = ARRAY_SIZE(armada_370_xp_core_ratios),
};
#endif /* CONFIG_MACH_ARMADA_370_XP */
/*
* Dove PLL sample-at-reset configuration
*
* SAR0[8:5] : CPU frequency
* 5 = 1000 MHz
* 6 = 933 MHz
* 7 = 933 MHz
* 8 = 800 MHz
* 9 = 800 MHz
* 10 = 800 MHz
* 11 = 1067 MHz
* 12 = 667 MHz
* 13 = 533 MHz
* 14 = 400 MHz
* 15 = 333 MHz
* others reserved.
*
* SAR0[11:9] : CPU to L2 Clock divider ratio
* 0 = (1/1) * CPU
* 2 = (1/2) * CPU
* 4 = (1/3) * CPU
* 6 = (1/4) * CPU
* others reserved.
*
* SAR0[15:12] : CPU to DDR DRAM Clock divider ratio
* 0 = (1/1) * CPU
* 2 = (1/2) * CPU
* 3 = (2/5) * CPU
* 4 = (1/3) * CPU
* 6 = (1/4) * CPU
* 8 = (1/5) * CPU
* 10 = (1/6) * CPU
* 12 = (1/7) * CPU
* 14 = (1/8) * CPU
* 15 = (1/10) * CPU
* others reserved.
*
* SAR0[24:23] : TCLK frequency
* 0 = 166 MHz
* 1 = 125 MHz
* others reserved.
*/
#ifdef CONFIG_ARCH_DOVE
#define SAR_DOVE_CPU_FREQ 5
#define SAR_DOVE_CPU_FREQ_MASK 0xf
#define SAR_DOVE_L2_RATIO 9
#define SAR_DOVE_L2_RATIO_MASK 0x7
#define SAR_DOVE_DDR_RATIO 12
#define SAR_DOVE_DDR_RATIO_MASK 0xf
#define SAR_DOVE_TCLK_FREQ 23
#define SAR_DOVE_TCLK_FREQ_MASK 0x3
static const u32 __initconst dove_tclk_frequencies[] = {
166666667,
125000000,
0, 0
};
static u32 __init dove_get_tclk_freq(void __iomem *sar)
{
u32 opt = (readl(sar) >> SAR_DOVE_TCLK_FREQ) &
SAR_DOVE_TCLK_FREQ_MASK;
return dove_tclk_frequencies[opt];
}
static const u32 __initconst dove_cpu_frequencies[] = {
0, 0, 0, 0, 0,
1000000000,
933333333, 933333333,
800000000, 800000000, 800000000,
1066666667,
666666667,
533333333,
400000000,
333333333
};
static u32 __init dove_get_cpu_freq(void __iomem *sar)
{
u32 opt = (readl(sar) >> SAR_DOVE_CPU_FREQ) &
SAR_DOVE_CPU_FREQ_MASK;
return dove_cpu_frequencies[opt];
}
enum { DOVE_CPU_TO_L2, DOVE_CPU_TO_DDR };
static const struct core_ratio __initconst dove_core_ratios[] = {
{ .id = DOVE_CPU_TO_L2, .name = "l2clk", },
{ .id = DOVE_CPU_TO_DDR, .name = "ddrclk", }
};
static const int __initconst dove_cpu_l2_ratios[8][2] = {
{ 1, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 },
{ 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 }
};
static const int __initconst dove_cpu_ddr_ratios[16][2] = {
{ 1, 1 }, { 0, 1 }, { 1, 2 }, { 2, 5 },
{ 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 },
{ 1, 5 }, { 0, 1 }, { 1, 6 }, { 0, 1 },
{ 1, 7 }, { 0, 1 }, { 1, 8 }, { 1, 10 }
};
static void __init dove_get_clk_ratio(
void __iomem *sar, int id, int *mult, int *div)
{
switch (id) {
case DOVE_CPU_TO_L2:
{
u32 opt = (readl(sar) >> SAR_DOVE_L2_RATIO) &
SAR_DOVE_L2_RATIO_MASK;
*mult = dove_cpu_l2_ratios[opt][0];
*div = dove_cpu_l2_ratios[opt][1];
break;
}
case DOVE_CPU_TO_DDR:
{
u32 opt = (readl(sar) >> SAR_DOVE_DDR_RATIO) &
SAR_DOVE_DDR_RATIO_MASK;
*mult = dove_cpu_ddr_ratios[opt][0];
*div = dove_cpu_ddr_ratios[opt][1];
break;
}
}
}
static const struct core_clocks dove_core_clocks = {
.get_tclk_freq = dove_get_tclk_freq,
.get_cpu_freq = dove_get_cpu_freq,
.get_clk_ratio = dove_get_clk_ratio,
.ratios = dove_core_ratios,
.num_ratios = ARRAY_SIZE(dove_core_ratios),
};
#endif /* CONFIG_ARCH_DOVE */
/*
* Kirkwood PLL sample-at-reset configuration
* (6180 has different SAR layout than other Kirkwood SoCs)
*
* SAR0[4:3,22,1] : CPU frequency (6281,6292,6282)
* 4 = 600 MHz
* 6 = 800 MHz
* 7 = 1000 MHz
* 9 = 1200 MHz
* 12 = 1500 MHz
* 13 = 1600 MHz
* 14 = 1800 MHz
* 15 = 2000 MHz
* others reserved.
*
* SAR0[19,10:9] : CPU to L2 Clock divider ratio (6281,6292,6282)
* 1 = (1/2) * CPU
* 3 = (1/3) * CPU
* 5 = (1/4) * CPU
* others reserved.
*
* SAR0[8:5] : CPU to DDR DRAM Clock divider ratio (6281,6292,6282)
* 2 = (1/2) * CPU
* 4 = (1/3) * CPU
* 6 = (1/4) * CPU
* 7 = (2/9) * CPU
* 8 = (1/5) * CPU
* 9 = (1/6) * CPU
* others reserved.
*
* SAR0[4:2] : Kirkwood 6180 cpu/l2/ddr clock configuration (6180 only)
* 5 = [CPU = 600 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/3) * CPU]
* 6 = [CPU = 800 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/4) * CPU]
* 7 = [CPU = 1000 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/5) * CPU]
* others reserved.
*
* SAR0[21] : TCLK frequency
* 0 = 200 MHz
* 1 = 166 MHz
* others reserved.
*/
#ifdef CONFIG_ARCH_KIRKWOOD
#define SAR_KIRKWOOD_CPU_FREQ(x) \
(((x & (1 << 1)) >> 1) | \
((x & (1 << 22)) >> 21) | \
((x & (3 << 3)) >> 1))
#define SAR_KIRKWOOD_L2_RATIO(x) \
(((x & (3 << 9)) >> 9) | \
(((x & (1 << 19)) >> 17)))
#define SAR_KIRKWOOD_DDR_RATIO 5
#define SAR_KIRKWOOD_DDR_RATIO_MASK 0xf
#define SAR_MV88F6180_CLK 2
#define SAR_MV88F6180_CLK_MASK 0x7
#define SAR_KIRKWOOD_TCLK_FREQ 21
#define SAR_KIRKWOOD_TCLK_FREQ_MASK 0x1
enum { KIRKWOOD_CPU_TO_L2, KIRKWOOD_CPU_TO_DDR };
static const struct core_ratio __initconst kirkwood_core_ratios[] = {
{ .id = KIRKWOOD_CPU_TO_L2, .name = "l2clk", },
{ .id = KIRKWOOD_CPU_TO_DDR, .name = "ddrclk", }
};
static u32 __init kirkwood_get_tclk_freq(void __iomem *sar)
{
u32 opt = (readl(sar) >> SAR_KIRKWOOD_TCLK_FREQ) &
SAR_KIRKWOOD_TCLK_FREQ_MASK;
return (opt) ? 166666667 : 200000000;
}
static const u32 __initconst kirkwood_cpu_frequencies[] = {
0, 0, 0, 0,
600000000,
0,
800000000,
1000000000,
0,
1200000000,
0, 0,
1500000000,
1600000000,
1800000000,
2000000000
};
static u32 __init kirkwood_get_cpu_freq(void __iomem *sar)
{
u32 opt = SAR_KIRKWOOD_CPU_FREQ(readl(sar));
return kirkwood_cpu_frequencies[opt];
}
static const int __initconst kirkwood_cpu_l2_ratios[8][2] = {
{ 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 },
{ 0, 1 }, { 1, 4 }, { 0, 1 }, { 0, 1 }
};
static const int __initconst kirkwood_cpu_ddr_ratios[16][2] = {
{ 0, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 },
{ 1, 3 }, { 0, 1 }, { 1, 4 }, { 2, 9 },
{ 1, 5 }, { 1, 6 }, { 0, 1 }, { 0, 1 },
{ 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }
};
static void __init kirkwood_get_clk_ratio(
void __iomem *sar, int id, int *mult, int *div)
{
switch (id) {
case KIRKWOOD_CPU_TO_L2:
{
u32 opt = SAR_KIRKWOOD_L2_RATIO(readl(sar));
*mult = kirkwood_cpu_l2_ratios[opt][0];
*div = kirkwood_cpu_l2_ratios[opt][1];
break;
}
case KIRKWOOD_CPU_TO_DDR:
{
u32 opt = (readl(sar) >> SAR_KIRKWOOD_DDR_RATIO) &
SAR_KIRKWOOD_DDR_RATIO_MASK;
*mult = kirkwood_cpu_ddr_ratios[opt][0];
*div = kirkwood_cpu_ddr_ratios[opt][1];
break;
}
}
}
static const struct core_clocks kirkwood_core_clocks = {
.get_tclk_freq = kirkwood_get_tclk_freq,
.get_cpu_freq = kirkwood_get_cpu_freq,
.get_clk_ratio = kirkwood_get_clk_ratio,
.ratios = kirkwood_core_ratios,
.num_ratios = ARRAY_SIZE(kirkwood_core_ratios),
};
static const u32 __initconst mv88f6180_cpu_frequencies[] = {
0, 0, 0, 0, 0,
600000000,
800000000,
1000000000
};
static u32 __init mv88f6180_get_cpu_freq(void __iomem *sar)
{
u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) & SAR_MV88F6180_CLK_MASK;
return mv88f6180_cpu_frequencies[opt];
}
static const int __initconst mv88f6180_cpu_ddr_ratios[8][2] = {
{ 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 },
{ 0, 1 }, { 1, 3 }, { 1, 4 }, { 1, 5 }
};
static void __init mv88f6180_get_clk_ratio(
void __iomem *sar, int id, int *mult, int *div)
{
switch (id) {
case KIRKWOOD_CPU_TO_L2:
{
/* mv88f6180 has a fixed 1:2 CPU-to-L2 ratio */
*mult = 1;
*div = 2;
break;
}
case KIRKWOOD_CPU_TO_DDR:
{
u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) &
SAR_MV88F6180_CLK_MASK;
*mult = mv88f6180_cpu_ddr_ratios[opt][0];
*div = mv88f6180_cpu_ddr_ratios[opt][1];
break;
}
}
}
static const struct core_clocks mv88f6180_core_clocks = {
.get_tclk_freq = kirkwood_get_tclk_freq,
.get_cpu_freq = mv88f6180_get_cpu_freq,
.get_clk_ratio = mv88f6180_get_clk_ratio,
.ratios = kirkwood_core_ratios,
.num_ratios = ARRAY_SIZE(kirkwood_core_ratios),
};
#endif /* CONFIG_ARCH_KIRKWOOD */
static const __initdata struct of_device_id clk_core_match[] = {
#ifdef CONFIG_MACH_ARMADA_370_XP
{
.compatible = "marvell,armada-370-core-clock",
.data = &armada_370_core_clocks,
},
{
.compatible = "marvell,armada-xp-core-clock",
.data = &armada_xp_core_clocks,
},
#endif
#ifdef CONFIG_ARCH_DOVE
{
.compatible = "marvell,dove-core-clock",
.data = &dove_core_clocks,
},
#endif
#ifdef CONFIG_ARCH_KIRKWOOD
{
.compatible = "marvell,kirkwood-core-clock",
.data = &kirkwood_core_clocks,
},
{
.compatible = "marvell,mv88f6180-core-clock",
.data = &mv88f6180_core_clocks,
},
#endif
{ }
};
void __init mvebu_core_clk_init(void)
{
struct device_node *np;
for_each_matching_node(np, clk_core_match) {
const struct of_device_id *match =
of_match_node(clk_core_match, np);
mvebu_clk_core_setup(np, (struct core_clocks *)match->data);
}
}
/*
* * Marvell EBU clock core handling defined at reset
*
* Copyright (C) 2012 Marvell
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __MVEBU_CLK_CORE_H
#define __MVEBU_CLK_CORE_H
void __init mvebu_core_clk_init(void);
#endif
/*
* Marvell MVEBU CPU clock handling.
*
* Copyright (C) 2012 Marvell
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/delay.h>
#include "clk-cpu.h"
#define SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET 0x0
#define SYS_CTRL_CLK_DIVIDER_VALUE_OFFSET 0xC
#define SYS_CTRL_CLK_DIVIDER_MASK 0x3F
#define MAX_CPU 4
struct cpu_clk {
struct clk_hw hw;
int cpu;
const char *clk_name;
const char *parent_name;
void __iomem *reg_base;
};
static struct clk **clks;
static struct clk_onecell_data clk_data;
#define to_cpu_clk(p) container_of(p, struct cpu_clk, hw)
static unsigned long clk_cpu_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate)
{
struct cpu_clk *cpuclk = to_cpu_clk(hwclk);
u32 reg, div;
reg = readl(cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_VALUE_OFFSET);
div = (reg >> (cpuclk->cpu * 8)) & SYS_CTRL_CLK_DIVIDER_MASK;
return parent_rate / div;
}
static long clk_cpu_round_rate(struct clk_hw *hwclk, unsigned long rate,
unsigned long *parent_rate)
{
/* Valid ratio are 1:1, 1:2 and 1:3 */
u32 div;
div = *parent_rate / rate;
if (div == 0)
div = 1;
else if (div > 3)
div = 3;
return *parent_rate / div;
}
static int clk_cpu_set_rate(struct clk_hw *hwclk, unsigned long rate,
unsigned long parent_rate)
{
struct cpu_clk *cpuclk = to_cpu_clk(hwclk);
u32 reg, div;
u32 reload_mask;
div = parent_rate / rate;
reg = (readl(cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_VALUE_OFFSET)
& (~(SYS_CTRL_CLK_DIVIDER_MASK << (cpuclk->cpu * 8))))
| (div << (cpuclk->cpu * 8));
writel(reg, cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_VALUE_OFFSET);
/* Set clock divider reload smooth bit mask */
reload_mask = 1 << (20 + cpuclk->cpu);
reg = readl(cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET)
| reload_mask;
writel(reg, cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET);
/* Now trigger the clock update */
reg = readl(cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET)
| 1 << 24;
writel(reg, cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET);
/* Wait for clocks to settle down then clear reload request */
udelay(1000);
reg &= ~(reload_mask | 1 << 24);
writel(reg, cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET);
udelay(1000);
return 0;
}
static const struct clk_ops cpu_ops = {
.recalc_rate = clk_cpu_recalc_rate,
.round_rate = clk_cpu_round_rate,
.set_rate = clk_cpu_set_rate,
};
void __init of_cpu_clk_setup(struct device_node *node)
{
struct cpu_clk *cpuclk;
void __iomem *clock_complex_base = of_iomap(node, 0);
int ncpus = 0;
struct device_node *dn;
if (clock_complex_base == NULL) {
pr_err("%s: clock-complex base register not set\n",
__func__);
return;
}
for_each_node_by_type(dn, "cpu")
ncpus++;
cpuclk = kzalloc(ncpus * sizeof(*cpuclk), GFP_KERNEL);
if (WARN_ON(!cpuclk))
return;
clks = kzalloc(ncpus * sizeof(*clks), GFP_KERNEL);
if (WARN_ON(!clks))
return;
for_each_node_by_type(dn, "cpu") {
struct clk_init_data init;
struct clk *clk;
struct clk *parent_clk;
char *clk_name = kzalloc(5, GFP_KERNEL);
int cpu, err;
if (WARN_ON(!clk_name))
return;
err = of_property_read_u32(dn, "reg", &cpu);
if (WARN_ON(err))
return;
sprintf(clk_name, "cpu%d", cpu);
parent_clk = of_clk_get(node, 0);
cpuclk[cpu].parent_name = __clk_get_name(parent_clk);
cpuclk[cpu].clk_name = clk_name;
cpuclk[cpu].cpu = cpu;
cpuclk[cpu].reg_base = clock_complex_base;
cpuclk[cpu].hw.init = &init;
init.name = cpuclk[cpu].clk_name;
init.ops = &cpu_ops;
init.flags = 0;
init.parent_names = &cpuclk[cpu].parent_name;
init.num_parents = 1;
clk = clk_register(NULL, &cpuclk[cpu].hw);
if (WARN_ON(IS_ERR(clk)))
goto bail_out;
clks[cpu] = clk;
}
clk_data.clk_num = MAX_CPU;
clk_data.clks = clks;
of_clk_add_provider(node, of_clk_src_onecell_get, &clk_data);
return;
bail_out:
kfree(clks);
kfree(cpuclk);
}
static const __initconst struct of_device_id clk_cpu_match[] = {
{
.compatible = "marvell,armada-xp-cpu-clock",
.data = of_cpu_clk_setup,
},
{
/* sentinel */
},
};
void __init mvebu_cpu_clk_init(void)
{
of_clk_init(clk_cpu_match);
}
/*
* Marvell MVEBU CPU clock handling.
*
* Copyright (C) 2012 Marvell
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __MVEBU_CLK_CPU_H
#define __MVEBU_CLK_CPU_H
#ifdef CONFIG_MVEBU_CLK_CPU
void __init mvebu_cpu_clk_init(void);
#else
static inline void mvebu_cpu_clk_init(void) {}
#endif
#endif
/*
* Marvell MVEBU clock gating control.
*
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/clk/mvebu.h>
#include <linux/of.h>
#include <linux/of_address.h>
struct mvebu_gating_ctrl {
spinlock_t lock;
struct clk **gates;
int num_gates;
};
struct mvebu_soc_descr {
const char *name;
const char *parent;
int bit_idx;
};
#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
static struct clk __init *mvebu_clk_gating_get_src(
struct of_phandle_args *clkspec, void *data)
{
struct mvebu_gating_ctrl *ctrl = (struct mvebu_gating_ctrl *)data;
int n;
if (clkspec->args_count < 1)
return ERR_PTR(-EINVAL);
for (n = 0; n < ctrl->num_gates; n++) {
struct clk_gate *gate =
to_clk_gate(__clk_get_hw(ctrl->gates[n]));
if (clkspec->args[0] == gate->bit_idx)
return ctrl->gates[n];
}
return ERR_PTR(-ENODEV);
}
static void __init mvebu_clk_gating_setup(
struct device_node *np, const struct mvebu_soc_descr *descr)
{
struct mvebu_gating_ctrl *ctrl;
struct clk *clk;
void __iomem *base;
const char *default_parent = NULL;
int n;
base = of_iomap(np, 0);
clk = of_clk_get(np, 0);
if (!IS_ERR(clk)) {
default_parent = __clk_get_name(clk);
clk_put(clk);
}
ctrl = kzalloc(sizeof(struct mvebu_gating_ctrl), GFP_KERNEL);
if (WARN_ON(!ctrl))
return;
spin_lock_init(&ctrl->lock);
/*
* Count, allocate, and register clock gates
*/
for (n = 0; descr[n].name;)
n++;
ctrl->num_gates = n;
ctrl->gates = kzalloc(ctrl->num_gates * sizeof(struct clk *),
GFP_KERNEL);
if (WARN_ON(!ctrl->gates)) {
kfree(ctrl);
return;
}
for (n = 0; n < ctrl->num_gates; n++) {
u8 flags = 0;
const char *parent =
(descr[n].parent) ? descr[n].parent : default_parent;
/*
* On Armada 370, the DDR clock is a special case: it
* isn't taken by any driver, but should anyway be
* kept enabled, so we mark it as IGNORE_UNUSED for
* now.
*/
if (!strcmp(descr[n].name, "ddr"))
flags |= CLK_IGNORE_UNUSED;
ctrl->gates[n] = clk_register_gate(NULL, descr[n].name, parent,
flags, base, descr[n].bit_idx, 0, &ctrl->lock);
WARN_ON(IS_ERR(ctrl->gates[n]));
}
of_clk_add_provider(np, mvebu_clk_gating_get_src, ctrl);
}
/*
* SoC specific clock gating control
*/
#ifdef CONFIG_MACH_ARMADA_370
static const struct mvebu_soc_descr __initconst armada_370_gating_descr[] = {
{ "audio", NULL, 0 },
{ "pex0_en", NULL, 1 },
{ "pex1_en", NULL, 2 },
{ "ge1", NULL, 3 },
{ "ge0", NULL, 4 },
{ "pex0", NULL, 5 },
{ "pex1", NULL, 9 },
{ "sata0", NULL, 15 },
{ "sdio", NULL, 17 },
{ "tdm", NULL, 25 },
{ "ddr", NULL, 28 },
{ "sata1", NULL, 30 },
{ }
};
#endif
#ifdef CONFIG_MACH_ARMADA_XP
static const struct mvebu_soc_descr __initconst armada_xp_gating_descr[] = {
{ "audio", NULL, 0 },
{ "ge3", NULL, 1 },
{ "ge2", NULL, 2 },
{ "ge1", NULL, 3 },
{ "ge0", NULL, 4 },
{ "pex0", NULL, 5 },
{ "pex1", NULL, 6 },
{ "pex2", NULL, 7 },
{ "pex3", NULL, 8 },
{ "bp", NULL, 13 },
{ "sata0lnk", NULL, 14 },
{ "sata0", "sata0lnk", 15 },
{ "lcd", NULL, 16 },
{ "sdio", NULL, 17 },
{ "usb0", NULL, 18 },
{ "usb1", NULL, 19 },
{ "usb2", NULL, 20 },
{ "xor0", NULL, 22 },
{ "crypto", NULL, 23 },
{ "tdm", NULL, 25 },
{ "xor1", NULL, 28 },
{ "sata1lnk", NULL, 29 },
{ "sata1", "sata1lnk", 30 },
{ }
};
#endif
#ifdef CONFIG_ARCH_DOVE
static const struct mvebu_soc_descr __initconst dove_gating_descr[] = {
{ "usb0", NULL, 0 },
{ "usb1", NULL, 1 },
{ "ge", "gephy", 2 },
{ "sata", NULL, 3 },
{ "pex0", NULL, 4 },
{ "pex1", NULL, 5 },
{ "sdio0", NULL, 8 },
{ "sdio1", NULL, 9 },
{ "nand", NULL, 10 },
{ "camera", NULL, 11 },
{ "i2s0", NULL, 12 },
{ "i2s1", NULL, 13 },
{ "crypto", NULL, 15 },
{ "ac97", NULL, 21 },
{ "pdma", NULL, 22 },
{ "xor0", NULL, 23 },
{ "xor1", NULL, 24 },
{ "gephy", NULL, 30 },
{ }
};
#endif
#ifdef CONFIG_ARCH_KIRKWOOD
static const struct mvebu_soc_descr __initconst kirkwood_gating_descr[] = {
{ "ge0", NULL, 0 },
{ "pex0", NULL, 2 },
{ "usb0", NULL, 3 },
{ "sdio", NULL, 4 },
{ "tsu", NULL, 5 },
{ "runit", NULL, 7 },
{ "xor0", NULL, 8 },
{ "audio", NULL, 9 },
{ "sata0", NULL, 14 },
{ "sata1", NULL, 15 },
{ "xor1", NULL, 16 },
{ "crypto", NULL, 17 },
{ "pex1", NULL, 18 },
{ "ge1", NULL, 19 },
{ "tdm", NULL, 20 },
{ }
};
#endif
static const __initdata struct of_device_id clk_gating_match[] = {
#ifdef CONFIG_MACH_ARMADA_370
{
.compatible = "marvell,armada-370-gating-clock",
.data = armada_370_gating_descr,
},
#endif
#ifdef CONFIG_MACH_ARMADA_XP
{
.compatible = "marvell,armada-xp-gating-clock",
.data = armada_xp_gating_descr,
},
#endif
#ifdef CONFIG_ARCH_DOVE
{
.compatible = "marvell,dove-gating-clock",
.data = dove_gating_descr,
},
#endif
#ifdef CONFIG_ARCH_KIRKWOOD
{
.compatible = "marvell,kirkwood-gating-clock",
.data = kirkwood_gating_descr,
},
#endif
{ }
};
void __init mvebu_gating_clk_init(void)
{
struct device_node *np;
for_each_matching_node(np, clk_gating_match) {
const struct of_device_id *match =
of_match_node(clk_gating_match, np);
mvebu_clk_gating_setup(np,
(const struct mvebu_soc_descr *)match->data);
}
}
/*
* Marvell EBU gating clock handling
*
* Copyright (C) 2012 Marvell
*
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __MVEBU_CLK_GATING_H
#define __MVEBU_CLK_GATING_H
#ifdef CONFIG_MVEBU_CLK_GATING
void __init mvebu_gating_clk_init(void);
#else
void mvebu_gating_clk_init(void) {}
#endif
#endif
/*
* Marvell EBU SoC clock handling.
*
* Copyright (C) 2012 Marvell
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/clk/mvebu.h>
#include <linux/of.h>
#include "clk-core.h"
#include "clk-cpu.h"
#include "clk-gating-ctrl.h"
void __init mvebu_clocks_init(void)
{
mvebu_core_clk_init();
mvebu_gating_clk_init();
mvebu_cpu_clk_init();
}
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/clockchips.h> #include <linux/clockchips.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -167,7 +168,6 @@ void __init armada_370_xp_timer_init(void) ...@@ -167,7 +168,6 @@ void __init armada_370_xp_timer_init(void)
u32 u; u32 u;
struct device_node *np; struct device_node *np;
unsigned int timer_clk; unsigned int timer_clk;
int ret;
np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer"); np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer");
timer_base = of_iomap(np, 0); timer_base = of_iomap(np, 0);
WARN_ON(!timer_base); WARN_ON(!timer_base);
...@@ -179,13 +179,14 @@ void __init armada_370_xp_timer_init(void) ...@@ -179,13 +179,14 @@ void __init armada_370_xp_timer_init(void)
timer_base + TIMER_CTRL_OFF); timer_base + TIMER_CTRL_OFF);
timer_clk = 25000000; timer_clk = 25000000;
} else { } else {
u32 clk = 0; unsigned long rate = 0;
ret = of_property_read_u32(np, "clock-frequency", &clk); struct clk *clk = of_clk_get(np, 0);
WARN_ON(!clk || ret < 0); WARN_ON(IS_ERR(clk));
rate = clk_get_rate(clk);
u = readl(timer_base + TIMER_CTRL_OFF); u = readl(timer_base + TIMER_CTRL_OFF);
writel(u & ~(TIMER0_25MHZ | TIMER1_25MHZ), writel(u & ~(TIMER0_25MHZ | TIMER1_25MHZ),
timer_base + TIMER_CTRL_OFF); timer_base + TIMER_CTRL_OFF);
timer_clk = clk / TIMER_DIVIDER; timer_clk = rate / TIMER_DIVIDER;
} }
/* We use timer 0 as clocksource, and timer 1 for /* We use timer 0 as clocksource, and timer 1 for
......
此差异已折叠。
...@@ -24,8 +24,10 @@ ...@@ -24,8 +24,10 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#define USE_TIMER #define USE_TIMER
#define MV_XOR_POOL_SIZE PAGE_SIZE
#define MV_XOR_SLOT_SIZE 64 #define MV_XOR_SLOT_SIZE 64
#define MV_XOR_THRESHOLD 1 #define MV_XOR_THRESHOLD 1
#define MV_XOR_MAX_CHANNELS 2
#define XOR_OPERATION_MODE_XOR 0 #define XOR_OPERATION_MODE_XOR 0
#define XOR_OPERATION_MODE_MEMCPY 2 #define XOR_OPERATION_MODE_MEMCPY 2
...@@ -51,29 +53,13 @@ ...@@ -51,29 +53,13 @@
#define WINDOW_SIZE(w) (0x270 + ((w) << 2)) #define WINDOW_SIZE(w) (0x270 + ((w) << 2))
#define WINDOW_REMAP_HIGH(w) (0x290 + ((w) << 2)) #define WINDOW_REMAP_HIGH(w) (0x290 + ((w) << 2))
#define WINDOW_BAR_ENABLE(chan) (0x240 + ((chan) << 2)) #define WINDOW_BAR_ENABLE(chan) (0x240 + ((chan) << 2))
#define WINDOW_OVERRIDE_CTRL(chan) (0x2A0 + ((chan) << 2))
struct mv_xor_shared_private {
void __iomem *xor_base;
void __iomem *xor_high_base;
struct clk *clk;
};
/**
* struct mv_xor_device - internal representation of a XOR device
* @pdev: Platform device
* @id: HW XOR Device selector
* @dma_desc_pool: base of DMA descriptor region (DMA address)
* @dma_desc_pool_virt: base of DMA descriptor region (CPU address)
* @common: embedded struct dma_device
*/
struct mv_xor_device { struct mv_xor_device {
struct platform_device *pdev; void __iomem *xor_base;
int id; void __iomem *xor_high_base;
dma_addr_t dma_desc_pool; struct clk *clk;
void *dma_desc_pool_virt; struct mv_xor_chan *channels[MV_XOR_MAX_CHANNELS];
struct dma_device common;
struct mv_xor_shared_private *shared;
}; };
/** /**
...@@ -96,11 +82,15 @@ struct mv_xor_chan { ...@@ -96,11 +82,15 @@ struct mv_xor_chan {
spinlock_t lock; /* protects the descriptor slot pool */ spinlock_t lock; /* protects the descriptor slot pool */
void __iomem *mmr_base; void __iomem *mmr_base;
unsigned int idx; unsigned int idx;
int irq;
enum dma_transaction_type current_type; enum dma_transaction_type current_type;
struct list_head chain; struct list_head chain;
struct list_head completed_slots; struct list_head completed_slots;
struct mv_xor_device *device; dma_addr_t dma_desc_pool;
struct dma_chan common; void *dma_desc_pool_virt;
size_t pool_size;
struct dma_device dmadev;
struct dma_chan dmachan;
struct mv_xor_desc_slot *last_used; struct mv_xor_desc_slot *last_used;
struct list_head all_slots; struct list_head all_slots;
int slots_allocated; int slots_allocated;
......
...@@ -31,6 +31,30 @@ config MV643XX_ETH ...@@ -31,6 +31,30 @@ config MV643XX_ETH
Some boards that use the Discovery chipset are the Momenco Some boards that use the Discovery chipset are the Momenco
Ocelot C and Jaguar ATX and Pegasos II. Ocelot C and Jaguar ATX and Pegasos II.
config MVMDIO
tristate "Marvell MDIO interface support"
---help---
This driver supports the MDIO interface found in the network
interface units of the Marvell EBU SoCs (Kirkwood, Orion5x,
Dove, Armada 370 and Armada XP).
For now, this driver is only needed for the MVNETA driver
(used on Armada 370 and XP), but it could be used in the
future by the MV643XX_ETH driver.
config MVNETA
tristate "Marvell Armada 370/XP network interface support"
depends on MACH_ARMADA_370_XP
select PHYLIB
select MVMDIO
---help---
This driver supports the network interface units in the
Marvell ARMADA XP and ARMADA 370 SoC family.
Note that this driver is distinct from the mv643xx_eth
driver, which should be used for the older Marvell SoCs
(Dove, Orion, Discovery, Kirkwood).
config PXA168_ETH config PXA168_ETH
tristate "Marvell pxa168 ethernet support" tristate "Marvell pxa168 ethernet support"
depends on CPU_PXA168 depends on CPU_PXA168
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
# #
obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
obj-$(CONFIG_MVMDIO) += mvmdio.o
obj-$(CONFIG_MVNETA) += mvneta.o
obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o
obj-$(CONFIG_SKGE) += skge.o obj-$(CONFIG_SKGE) += skge.o
obj-$(CONFIG_SKY2) += sky2.o obj-$(CONFIG_SKY2) += sky2.o
此差异已折叠。
此差异已折叠。
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CLK_MVEBU_H_
#define __CLK_MVEBU_H_
void __init mvebu_clocks_init(void);
#endif
...@@ -10,15 +10,14 @@ ...@@ -10,15 +10,14 @@
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/mbus.h> #include <linux/mbus.h>
#define MV_XOR_SHARED_NAME "mv_xor_shared" #define MV_XOR_NAME "mv_xor"
#define MV_XOR_NAME "mv_xor"
struct mv_xor_platform_data { struct mv_xor_channel_data {
struct platform_device *shared;
int hw_id;
dma_cap_mask_t cap_mask; dma_cap_mask_t cap_mask;
size_t pool_size;
}; };
struct mv_xor_platform_data {
struct mv_xor_channel_data *channels;
};
#endif #endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册