Commit 4ee961a3 authored by Thomas Petazzoni's avatar Thomas Petazzoni

Merge tag 'marvell-mvebu-clk-3.8' of...

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
parents f4a75d2e 1611f872
......@@ -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
......
* 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>;
};
......@@ -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 @@ serial@d0012000 {
clock-frequency = <200000000>;
status = "okay";
};
timer@d0020300 {
clock-frequency = <600000000>;
status = "okay";
};
};
};
......@@ -62,6 +62,7 @@ timer@d0020300 {
compatible = "marvell,armada-370-xp-timer";
reg = <0xd0020300 0x30>;
interrupts = <37>, <38>, <39>, <40>;
clocks = <&coreclk 2>;
};
addr-decoding@d0020000 {
......
......@@ -75,5 +75,20 @@ gpio2: gpio@d0018180 {
#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 @@ aliases {
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 @@ aliases {
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 @@ aliases {
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 @@ timer@d0020300 {
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 @@ intc: interrupt-controller {
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 @@ spi0: spi@10600 {
cell-index = <0>;
interrupts = <6>;
reg = <0x10600 0x28>;
clocks = <&core_clk 0>;
status = "disabled";
};
......@@ -110,6 +124,7 @@ spi1: spi@14600 {
cell-index = <1>;
interrupts = <5>;
reg = <0x14600 0x28>;
clocks = <&core_clk 0>;
status = "disabled";
};
......@@ -121,6 +136,7 @@ i2c0: i2c@11000 {
interrupts = <11>;
clock-frequency = <400000>;
timeout-ms = <1000>;
clocks = <&core_clk 0>;
status = "disabled";
};
......@@ -128,6 +144,7 @@ sdio0: sdio@92000 {
compatible = "marvell,dove-sdhci";
reg = <0x92000 0x100>;
interrupts = <35>, <37>;
clocks = <&gate_clk 8>;
status = "disabled";
};
......@@ -135,6 +152,7 @@ sdio1: sdio@90000 {
compatible = "marvell,dove-sdhci";
reg = <0x90000 0x100>;
interrupts = <36>, <38>;
clocks = <&gate_clk 9>;
status = "disabled";
};
......@@ -142,6 +160,7 @@ sata0: sata@a0000 {
compatible = "marvell,orion-sata";
reg = <0xa0000 0x2400>;
interrupts = <62>;
clocks = <&gate_clk 3>;
nr-ports = <1>;
status = "disabled";
};
......@@ -152,6 +171,7 @@ crypto: crypto@30000 {
<0xc8000000 0x800>;
reg-names = "regs", "sram";
interrupts = <31>;
clocks = <&gate_clk 15>;
status = "okay";
};
};
......
......@@ -19,6 +19,12 @@ ocp@f1000000 {
#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 @@ serial@12000 {
reg = <0x12000 0x100>;
reg-shift = <2>;
interrupts = <33>;
clocks = <&gate_clk 7>;
/* set clock-frequency in board dts */
status = "disabled";
};
......@@ -51,6 +58,7 @@ serial@12100 {
reg = <0x12100 0x100>;
reg-shift = <2>;
interrupts = <34>;
clocks = <&gate_clk 7>;
/* set clock-frequency in board dts */
status = "disabled";
};
......@@ -68,12 +76,21 @@ spi@10600 {
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 @@ sata@80000 {
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 @@ nand@3000000 {
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 @@ i2c@11000 {
#size-cells = <0>;
interrupts = <29>;
clock-frequency = <100000>;
clocks = <&gate_clk 7>;
status = "disabled";
};
......@@ -113,6 +134,7 @@ crypto@30000 {
<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
......
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
This diff is collapsed.
/*
* * 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 @@
#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
......
/*
* 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment