Marvell MVEBU clk support, for 3.8
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iEYEABECAAYFAlCrkvYACgkQ9lPLMJjT96cRqwCgsFUezgEynwbaLSddexWTF/Mf gEgAn1PP+InuSXnqziKHmLd3cc4tSkh+ =jxyJ -----END PGP SIGNATURE----- Merge tag 'marvell-mvebu-clk-3.8' of github.com:MISL-EBU-System-SW/mainline-public into test-the-merge Marvell MVEBU clk support, for 3.8
This commit is contained in:
commit
4ee961a35a
@ -5,6 +5,7 @@ Required properties:
|
||||
- compatible: Should be "marvell,armada-370-xp-timer"
|
||||
- interrupts: Should contain the list of Global Timer interrupts
|
||||
- reg: Should contain the base address of the Global Timer registers
|
||||
- clocks: clock driving the timer hardware
|
||||
|
||||
Optional properties:
|
||||
- marvell,timer-25Mhz: Tells whether the Global timer supports the 25
|
||||
|
47
Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
Normal file
47
Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
Normal file
@ -0,0 +1,47 @@
|
||||
* 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>;
|
||||
};
|
21
Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt
Normal file
21
Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt
Normal file
@ -0,0 +1,21 @@
|
||||
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>;
|
||||
};
|
119
Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt
Normal file
119
Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt
Normal file
@ -0,0 +1,119 @@
|
||||
* 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>;
|
||||
};
|
@ -533,6 +533,7 @@ config ARCH_IXP4XX
|
||||
config ARCH_DOVE
|
||||
bool "Marvell Dove"
|
||||
select ARCH_REQUIRE_GPIOLIB
|
||||
select COMMON_CLK_DOVE
|
||||
select CPU_V7
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select MIGHT_HAVE_PCI
|
||||
|
@ -34,9 +34,5 @@
|
||||
clock-frequency = <200000000>;
|
||||
status = "okay";
|
||||
};
|
||||
timer@d0020300 {
|
||||
clock-frequency = <600000000>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -62,6 +62,7 @@
|
||||
compatible = "marvell,armada-370-xp-timer";
|
||||
reg = <0xd0020300 0x30>;
|
||||
interrupts = <37>, <38>, <39>, <40>;
|
||||
clocks = <&coreclk 2>;
|
||||
};
|
||||
|
||||
addr-decoding@d0020000 {
|
||||
|
@ -75,5 +75,20 @@
|
||||
#interrupts-cells = <2>;
|
||||
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>;
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
|
@ -24,6 +24,18 @@
|
||||
gpio1 = &gpio1;
|
||||
};
|
||||
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cpu@0 {
|
||||
device_type = "cpu";
|
||||
compatible = "marvell,sheeva-v7";
|
||||
reg = <0>;
|
||||
clocks = <&cpuclk 0>;
|
||||
};
|
||||
}
|
||||
|
||||
soc {
|
||||
pinctrl {
|
||||
compatible = "marvell,mv78230-pinctrl";
|
||||
|
@ -25,6 +25,25 @@
|
||||
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 {
|
||||
pinctrl {
|
||||
compatible = "marvell,mv78260-pinctrl";
|
||||
|
@ -25,6 +25,40 @@
|
||||
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 {
|
||||
pinctrl {
|
||||
compatible = "marvell,mv78460-pinctrl";
|
||||
|
@ -47,6 +47,26 @@
|
||||
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 {
|
||||
compatible = "marvell,armada-370-xp-system-controller";
|
||||
reg = <0xd0018200 0x500>;
|
||||
|
@ -31,6 +31,19 @@
|
||||
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 {
|
||||
compatible = "ns16550a";
|
||||
reg = <0x12000 0x100>;
|
||||
@ -100,6 +113,7 @@
|
||||
cell-index = <0>;
|
||||
interrupts = <6>;
|
||||
reg = <0x10600 0x28>;
|
||||
clocks = <&core_clk 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -110,6 +124,7 @@
|
||||
cell-index = <1>;
|
||||
interrupts = <5>;
|
||||
reg = <0x14600 0x28>;
|
||||
clocks = <&core_clk 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -121,6 +136,7 @@
|
||||
interrupts = <11>;
|
||||
clock-frequency = <400000>;
|
||||
timeout-ms = <1000>;
|
||||
clocks = <&core_clk 0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -128,6 +144,7 @@
|
||||
compatible = "marvell,dove-sdhci";
|
||||
reg = <0x92000 0x100>;
|
||||
interrupts = <35>, <37>;
|
||||
clocks = <&gate_clk 8>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -135,6 +152,7 @@
|
||||
compatible = "marvell,dove-sdhci";
|
||||
reg = <0x90000 0x100>;
|
||||
interrupts = <36>, <38>;
|
||||
clocks = <&gate_clk 9>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -142,6 +160,7 @@
|
||||
compatible = "marvell,orion-sata";
|
||||
reg = <0xa0000 0x2400>;
|
||||
interrupts = <62>;
|
||||
clocks = <&gate_clk 3>;
|
||||
nr-ports = <1>;
|
||||
status = "disabled";
|
||||
};
|
||||
@ -152,6 +171,7 @@
|
||||
<0xc8000000 0x800>;
|
||||
reg-names = "regs", "sram";
|
||||
interrupts = <31>;
|
||||
clocks = <&gate_clk 15>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
@ -19,6 +19,12 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
core_clk: core-clocks@10030 {
|
||||
compatible = "marvell,kirkwood-core-clock";
|
||||
reg = <0x10030 0x4>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
gpio0: gpio@10100 {
|
||||
compatible = "marvell,orion-gpio";
|
||||
#gpio-cells = <2>;
|
||||
@ -42,6 +48,7 @@
|
||||
reg = <0x12000 0x100>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <33>;
|
||||
clocks = <&gate_clk 7>;
|
||||
/* set clock-frequency in board dts */
|
||||
status = "disabled";
|
||||
};
|
||||
@ -51,6 +58,7 @@
|
||||
reg = <0x12100 0x100>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <34>;
|
||||
clocks = <&gate_clk 7>;
|
||||
/* set clock-frequency in board dts */
|
||||
status = "disabled";
|
||||
};
|
||||
@ -68,12 +76,21 @@
|
||||
cell-index = <0>;
|
||||
interrupts = <23>;
|
||||
reg = <0x10600 0x28>;
|
||||
clocks = <&gate_clk 7>;
|
||||
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 {
|
||||
compatible = "marvell,orion-wdt";
|
||||
reg = <0x20300 0x28>;
|
||||
clocks = <&gate_clk 7>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@ -81,6 +98,8 @@
|
||||
compatible = "marvell,orion-sata";
|
||||
reg = <0x80000 0x5000>;
|
||||
interrupts = <21>;
|
||||
clocks = <&gate_clk 14>, <&gate_clk 15>;
|
||||
clock-names = "0", "1";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -94,6 +113,7 @@
|
||||
reg = <0x3000000 0x400>;
|
||||
chip-delay = <25>;
|
||||
/* set partition map and/or chip-delay in board dts */
|
||||
clocks = <&gate_clk 7>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -104,6 +124,7 @@
|
||||
#size-cells = <0>;
|
||||
interrupts = <29>;
|
||||
clock-frequency = <100000>;
|
||||
clocks = <&gate_clk 7>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -113,6 +134,7 @@
|
||||
<0xf5000000 0x800>;
|
||||
reg-names = "regs", "sram";
|
||||
interrupts = <22>;
|
||||
clocks = <&gate_clk 17>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
@ -17,6 +17,8 @@ config MACH_CM_A510
|
||||
|
||||
config MACH_DOVE_DT
|
||||
bool "Marvell Dove Flattened Device Tree"
|
||||
select MVEBU_CLK_CORE
|
||||
select MVEBU_CLK_GATING
|
||||
select USE_OF
|
||||
help
|
||||
Say 'Y' here if you want your kernel to support the
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/mvebu.h>
|
||||
#include <linux/ata_platform.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of.h>
|
||||
@ -376,19 +377,52 @@ void dove_restart(char mode, const char *cmd)
|
||||
|
||||
#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 = {
|
||||
OF_DEV_AUXDATA("marvell,orion-spi", 0xf1010600, "orion_spi.0", NULL),
|
||||
OF_DEV_AUXDATA("marvell,orion-spi", 0xf1014600, "orion_spi.1", NULL),
|
||||
OF_DEV_AUXDATA("marvell,orion-wdt", 0xf1020300, "orion_wdt", NULL),
|
||||
OF_DEV_AUXDATA("marvell,mv64xxx-i2c", 0xf1011000, "mv64xxx_i2c.0",
|
||||
NULL),
|
||||
OF_DEV_AUXDATA("marvell,orion-sata", 0xf10a0000, "sata_mv.0", NULL),
|
||||
OF_DEV_AUXDATA("marvell,dove-sdhci", 0xf1092000, "sdhci-dove.0", NULL),
|
||||
OF_DEV_AUXDATA("marvell,dove-sdhci", 0xf1090000, "sdhci-dove.1", NULL),
|
||||
{},
|
||||
};
|
||||
static void __init dove_legacy_clk_init(void)
|
||||
{
|
||||
struct device_node *np = of_find_compatible_node(NULL, NULL,
|
||||
"marvell,dove-gating-clock");
|
||||
struct of_phandle_args clkspec;
|
||||
|
||||
clkspec.np = np;
|
||||
clkspec.args_count = 1;
|
||||
|
||||
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));
|
||||
|
||||
clkspec.args[0] = CLOCK_GATING_BIT_XOR0;
|
||||
orion_clkdev_add(NULL, "mv_xor_shared.0",
|
||||
of_clk_get_from_provider(&clkspec));
|
||||
|
||||
clkspec.args[0] = CLOCK_GATING_BIT_XOR1;
|
||||
orion_clkdev_add(NULL, "mv_xor_shared.1",
|
||||
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 = {
|
||||
.phy_addr = MV643XX_ETH_PHY_ADDR_DEFAULT,
|
||||
@ -405,7 +439,7 @@ static void __init dove_dt_init(void)
|
||||
dove_setup_cpu_mbus();
|
||||
|
||||
/* Setup root of clk tree */
|
||||
dove_clk_init();
|
||||
dove_of_clk_init();
|
||||
|
||||
/* Internal devices not ported to DT yet */
|
||||
dove_rtc_init();
|
||||
@ -417,8 +451,7 @@ static void __init dove_dt_init(void)
|
||||
dove_ehci1_init();
|
||||
dove_pcie_init(1, 1);
|
||||
|
||||
of_platform_populate(NULL, of_default_bus_match_table,
|
||||
dove_auxdata_lookup, NULL);
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||
}
|
||||
|
||||
static const char * const dove_dt_board_compat[] = {
|
||||
|
@ -46,6 +46,8 @@ config MACH_GURUPLUG
|
||||
|
||||
config ARCH_KIRKWOOD_DT
|
||||
bool "Marvell Kirkwood Flattened Device Tree"
|
||||
select MVEBU_CLK_CORE
|
||||
select MVEBU_CLK_GATING
|
||||
select USE_OF
|
||||
help
|
||||
Say 'Y' here if you want your kernel to support the
|
||||
|
@ -14,11 +14,15 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/mvebu.h>
|
||||
#include <linux/kexec.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
#include <mach/bridge-regs.h>
|
||||
#include <linux/platform_data/usb-ehci-orion.h>
|
||||
#include <plat/irq.h>
|
||||
#include <plat/common.h>
|
||||
#include "common.h"
|
||||
|
||||
static struct of_device_id kirkwood_dt_match_table[] __initdata = {
|
||||
@ -26,16 +30,58 @@ static struct of_device_id kirkwood_dt_match_table[] __initdata = {
|
||||
{ }
|
||||
};
|
||||
|
||||
struct of_dev_auxdata kirkwood_auxdata_lookup[] __initdata = {
|
||||
OF_DEV_AUXDATA("marvell,orion-spi", 0xf1010600, "orion_spi.0", NULL),
|
||||
OF_DEV_AUXDATA("marvell,mv64xxx-i2c", 0xf1011000, "mv64xxx_i2c.0",
|
||||
NULL),
|
||||
OF_DEV_AUXDATA("marvell,orion-wdt", 0xf1020300, "orion_wdt", NULL),
|
||||
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),
|
||||
{},
|
||||
};
|
||||
/*
|
||||
* There are still devices that doesn't know about DT yet. Get clock
|
||||
* gates here and add a clock lookup alias, so that old platform
|
||||
* devices still work.
|
||||
*/
|
||||
|
||||
static void __init kirkwood_legacy_clk_init(void)
|
||||
{
|
||||
|
||||
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_XOR0;
|
||||
orion_clkdev_add(NULL, "mv_xor_shared.0",
|
||||
of_clk_get_from_provider(&clkspec));
|
||||
|
||||
clkspec.args[0] = CGC_BIT_XOR1;
|
||||
orion_clkdev_add(NULL, "mv_xor_shared.1",
|
||||
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)
|
||||
{
|
||||
@ -54,7 +100,7 @@ static void __init kirkwood_dt_init(void)
|
||||
kirkwood_l2_init();
|
||||
|
||||
/* Setup root of clk tree */
|
||||
kirkwood_clk_init();
|
||||
kirkwood_of_clk_init();
|
||||
|
||||
/* internal devices that every board has */
|
||||
kirkwood_xor0_init();
|
||||
@ -94,8 +140,7 @@ static void __init kirkwood_dt_init(void)
|
||||
if (of_machine_is_compatible("keymile,km_kirkwood"))
|
||||
km_kirkwood_init();
|
||||
|
||||
of_platform_populate(NULL, kirkwood_dt_match_table,
|
||||
kirkwood_auxdata_lookup, NULL);
|
||||
of_platform_populate(NULL, kirkwood_dt_match_table, NULL, NULL);
|
||||
}
|
||||
|
||||
static const char *kirkwood_dt_board_compat[] = {
|
||||
|
@ -9,6 +9,10 @@ config ARCH_MVEBU
|
||||
select PINCTRL
|
||||
select PLAT_ORION
|
||||
select SPARSE_IRQ
|
||||
select CLKDEV_LOOKUP
|
||||
select MVEBU_CLK_CORE
|
||||
select MVEBU_CLK_CPU
|
||||
select MVEBU_CLK_GATING
|
||||
|
||||
if ARCH_MVEBU
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/time-armada-370-xp.h>
|
||||
#include <linux/clk/mvebu.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
#include <asm/mach/time.h>
|
||||
@ -37,8 +38,14 @@ void __init armada_370_xp_map_io(void)
|
||||
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();
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/mv643xx_eth.h>
|
||||
|
||||
struct dsa_platform_data;
|
||||
struct mv_sata_platform_data;
|
||||
|
||||
void __init orion_uart0_init(void __iomem *membase,
|
||||
resource_size_t mapbase,
|
||||
|
@ -54,3 +54,5 @@ config COMMON_CLK_MAX77686
|
||||
This driver supports Maxim 77686 crystal oscillator clock.
|
||||
|
||||
endmenu
|
||||
|
||||
source "drivers/clk/mvebu/Kconfig"
|
||||
|
@ -13,6 +13,7 @@ obj-$(CONFIG_PLAT_SPEAR) += spear/
|
||||
obj-$(CONFIG_ARCH_U300) += clk-u300.o
|
||||
obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
|
||||
obj-$(CONFIG_ARCH_PRIMA2) += clk-prima2.o
|
||||
obj-$(CONFIG_PLAT_ORION) += mvebu/
|
||||
ifeq ($(CONFIG_COMMON_CLK), y)
|
||||
obj-$(CONFIG_ARCH_MMP) += mmp/
|
||||
endif
|
||||
|
8
drivers/clk/mvebu/Kconfig
Normal file
8
drivers/clk/mvebu/Kconfig
Normal file
@ -0,0 +1,8 @@
|
||||
config MVEBU_CLK_CORE
|
||||
bool
|
||||
|
||||
config MVEBU_CLK_CPU
|
||||
bool
|
||||
|
||||
config MVEBU_CLK_GATING
|
||||
bool
|
3
drivers/clk/mvebu/Makefile
Normal file
3
drivers/clk/mvebu/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
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
|
675
drivers/clk/mvebu/clk-core.c
Normal file
675
drivers/clk/mvebu/clk-core.c
Normal file
@ -0,0 +1,675 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
18
drivers/clk/mvebu/clk-core.h
Normal file
18
drivers/clk/mvebu/clk-core.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* * 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
|
186
drivers/clk/mvebu/clk-cpu.c
Normal file
186
drivers/clk/mvebu/clk-cpu.c
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
22
drivers/clk/mvebu/clk-cpu.h
Normal file
22
drivers/clk/mvebu/clk-cpu.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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
|
249
drivers/clk/mvebu/clk-gating-ctrl.c
Normal file
249
drivers/clk/mvebu/clk-gating-ctrl.c
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
22
drivers/clk/mvebu/clk-gating-ctrl.h
Normal file
22
drivers/clk/mvebu/clk-gating-ctrl.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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
|
27
drivers/clk/mvebu/clk.c
Normal file
27
drivers/clk/mvebu/clk.c
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/interrupt.h>
|
||||
@ -167,7 +168,6 @@ void __init armada_370_xp_timer_init(void)
|
||||
u32 u;
|
||||
struct device_node *np;
|
||||
unsigned int timer_clk;
|
||||
int ret;
|
||||
np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer");
|
||||
timer_base = of_iomap(np, 0);
|
||||
WARN_ON(!timer_base);
|
||||
@ -179,13 +179,14 @@ void __init armada_370_xp_timer_init(void)
|
||||
timer_base + TIMER_CTRL_OFF);
|
||||
timer_clk = 25000000;
|
||||
} else {
|
||||
u32 clk = 0;
|
||||
ret = of_property_read_u32(np, "clock-frequency", &clk);
|
||||
WARN_ON(!clk || ret < 0);
|
||||
unsigned long rate = 0;
|
||||
struct clk *clk = of_clk_get(np, 0);
|
||||
WARN_ON(IS_ERR(clk));
|
||||
rate = clk_get_rate(clk);
|
||||
u = readl(timer_base + TIMER_CTRL_OFF);
|
||||
writel(u & ~(TIMER0_25MHZ | TIMER1_25MHZ),
|
||||
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
|
||||
|
22
include/linux/clk/mvebu.h
Normal file
22
include/linux/clk/mvebu.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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
|
Loading…
Reference in New Issue
Block a user