Commit 280da705 authored by Michael Turquette's avatar Michael Turquette

Merge branch 'clk-next-mmp' into clk-next

parents baeb0d9b d41ef540
* Marvell MMP2 Clock Controller
The MMP2 clock subsystem generates and supplies clock to various
controllers within the MMP2 SoC.
Required Properties:
- compatible: should be one of the following.
- "marvell,mmp2-clock" - controller compatible with MMP2 SoC.
- reg: physical base address of the clock subsystem and length of memory mapped
region. There are 3 places in SOC has clock control logic:
"mpmu", "apmu", "apbc". So three reg spaces need to be defined.
- #clock-cells: should be 1.
- #reset-cells: should be 1.
Each clock is assigned an identifier and client nodes use this identifier
to specify the clock which they consume.
All these identifier could be found in <dt-bindings/clock/marvell-mmp2.h>.
* Marvell PXA168 Clock Controller
The PXA168 clock subsystem generates and supplies clock to various
controllers within the PXA168 SoC.
Required Properties:
- compatible: should be one of the following.
- "marvell,pxa168-clock" - controller compatible with PXA168 SoC.
- reg: physical base address of the clock subsystem and length of memory mapped
region. There are 3 places in SOC has clock control logic:
"mpmu", "apmu", "apbc". So three reg spaces need to be defined.
- #clock-cells: should be 1.
- #reset-cells: should be 1.
Each clock is assigned an identifier and client nodes use this identifier
to specify the clock which they consume.
All these identifier could be found in <dt-bindings/clock/marvell,pxa168.h>.
* Marvell PXA910 Clock Controller
The PXA910 clock subsystem generates and supplies clock to various
controllers within the PXA910 SoC.
Required Properties:
- compatible: should be one of the following.
- "marvell,pxa910-clock" - controller compatible with PXA910 SoC.
- reg: physical base address of the clock subsystem and length of memory mapped
region. There are 4 places in SOC has clock control logic:
"mpmu", "apmu", "apbc", "apbcp". So four reg spaces need to be defined.
- #clock-cells: should be 1.
- #reset-cells: should be 1.
Each clock is assigned an identifier and client nodes use this identifier
to specify the clock which they consume.
All these identifier could be found in <dt-bindings/clock/marvell-pxa910.h>.
...@@ -164,6 +164,9 @@ dtb-$(CONFIG_MACH_KIRKWOOD) += kirkwood-b3.dtb \ ...@@ -164,6 +164,9 @@ dtb-$(CONFIG_MACH_KIRKWOOD) += kirkwood-b3.dtb \
dtb-$(CONFIG_ARCH_LPC32XX) += ea3250.dtb phy3250.dtb dtb-$(CONFIG_ARCH_LPC32XX) += ea3250.dtb phy3250.dtb
dtb-$(CONFIG_ARCH_MARCO) += marco-evb.dtb dtb-$(CONFIG_ARCH_MARCO) += marco-evb.dtb
dtb-$(CONFIG_MACH_MESON6) += meson6-atv1200.dtb dtb-$(CONFIG_MACH_MESON6) += meson6-atv1200.dtb
dtb-$(CONFIG_ARCH_MMP) += pxa168-aspenite.dtb \
pxa910-dkb.dtb \
mmp2-brownstone.dtb
dtb-$(CONFIG_ARCH_MOXART) += moxart-uc7112lx.dtb dtb-$(CONFIG_ARCH_MOXART) += moxart-uc7112lx.dtb
dtb-$(CONFIG_ARCH_MXC) += \ dtb-$(CONFIG_ARCH_MXC) += \
imx1-ads.dtb \ imx1-ads.dtb \
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
*/ */
/dts-v1/; /dts-v1/;
/include/ "mmp2.dtsi" #include "mmp2.dtsi"
/ { / {
model = "Marvell MMP2 Brownstone Development Board"; model = "Marvell MMP2 Brownstone Development Board";
......
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
* publishhed by the Free Software Foundation. * publishhed by the Free Software Foundation.
*/ */
/include/ "skeleton.dtsi" #include "skeleton.dtsi"
#include <dt-bindings/clock/marvell,mmp2.h>
/ { / {
aliases { aliases {
...@@ -135,6 +136,8 @@ uart1: uart@d4030000 { ...@@ -135,6 +136,8 @@ uart1: uart@d4030000 {
compatible = "mrvl,mmp-uart"; compatible = "mrvl,mmp-uart";
reg = <0xd4030000 0x1000>; reg = <0xd4030000 0x1000>;
interrupts = <27>; interrupts = <27>;
clocks = <&soc_clocks MMP2_CLK_UART0>;
resets = <&soc_clocks MMP2_CLK_UART0>;
status = "disabled"; status = "disabled";
}; };
...@@ -142,6 +145,8 @@ uart2: uart@d4017000 { ...@@ -142,6 +145,8 @@ uart2: uart@d4017000 {
compatible = "mrvl,mmp-uart"; compatible = "mrvl,mmp-uart";
reg = <0xd4017000 0x1000>; reg = <0xd4017000 0x1000>;
interrupts = <28>; interrupts = <28>;
clocks = <&soc_clocks MMP2_CLK_UART1>;
resets = <&soc_clocks MMP2_CLK_UART1>;
status = "disabled"; status = "disabled";
}; };
...@@ -149,6 +154,8 @@ uart3: uart@d4018000 { ...@@ -149,6 +154,8 @@ uart3: uart@d4018000 {
compatible = "mrvl,mmp-uart"; compatible = "mrvl,mmp-uart";
reg = <0xd4018000 0x1000>; reg = <0xd4018000 0x1000>;
interrupts = <24>; interrupts = <24>;
clocks = <&soc_clocks MMP2_CLK_UART2>;
resets = <&soc_clocks MMP2_CLK_UART2>;
status = "disabled"; status = "disabled";
}; };
...@@ -156,6 +163,8 @@ uart4: uart@d4016000 { ...@@ -156,6 +163,8 @@ uart4: uart@d4016000 {
compatible = "mrvl,mmp-uart"; compatible = "mrvl,mmp-uart";
reg = <0xd4016000 0x1000>; reg = <0xd4016000 0x1000>;
interrupts = <46>; interrupts = <46>;
clocks = <&soc_clocks MMP2_CLK_UART3>;
resets = <&soc_clocks MMP2_CLK_UART3>;
status = "disabled"; status = "disabled";
}; };
...@@ -168,6 +177,8 @@ gpio@d4019000 { ...@@ -168,6 +177,8 @@ gpio@d4019000 {
#gpio-cells = <2>; #gpio-cells = <2>;
interrupts = <49>; interrupts = <49>;
interrupt-names = "gpio_mux"; interrupt-names = "gpio_mux";
clocks = <&soc_clocks MMP2_CLK_GPIO>;
resets = <&soc_clocks MMP2_CLK_GPIO>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <1>; #interrupt-cells = <1>;
ranges; ranges;
...@@ -201,6 +212,8 @@ twsi1: i2c@d4011000 { ...@@ -201,6 +212,8 @@ twsi1: i2c@d4011000 {
compatible = "mrvl,mmp-twsi"; compatible = "mrvl,mmp-twsi";
reg = <0xd4011000 0x1000>; reg = <0xd4011000 0x1000>;
interrupts = <7>; interrupts = <7>;
clocks = <&soc_clocks MMP2_CLK_TWSI0>;
resets = <&soc_clocks MMP2_CLK_TWSI0>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
mrvl,i2c-fast-mode; mrvl,i2c-fast-mode;
...@@ -211,6 +224,8 @@ twsi2: i2c@d4025000 { ...@@ -211,6 +224,8 @@ twsi2: i2c@d4025000 {
compatible = "mrvl,mmp-twsi"; compatible = "mrvl,mmp-twsi";
reg = <0xd4025000 0x1000>; reg = <0xd4025000 0x1000>;
interrupts = <58>; interrupts = <58>;
clocks = <&soc_clocks MMP2_CLK_TWSI1>;
resets = <&soc_clocks MMP2_CLK_TWSI1>;
status = "disabled"; status = "disabled";
}; };
...@@ -220,8 +235,20 @@ rtc: rtc@d4010000 { ...@@ -220,8 +235,20 @@ rtc: rtc@d4010000 {
interrupts = <1 0>; interrupts = <1 0>;
interrupt-names = "rtc 1Hz", "rtc alarm"; interrupt-names = "rtc 1Hz", "rtc alarm";
interrupt-parent = <&intcmux5>; interrupt-parent = <&intcmux5>;
clocks = <&soc_clocks MMP2_CLK_RTC>;
resets = <&soc_clocks MMP2_CLK_RTC>;
status = "disabled"; status = "disabled";
}; };
}; };
soc_clocks: clocks{
compatible = "marvell,mmp2-clock";
reg = <0xd4050000 0x1000>,
<0xd4282800 0x400>,
<0xd4015000 0x1000>;
reg-names = "mpmu", "apmu", "apbc";
#clock-cells = <1>;
#reset-cells = <1>;
};
}; };
}; };
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
*/ */
/dts-v1/; /dts-v1/;
/include/ "pxa168.dtsi" #include "pxa168.dtsi"
/ { / {
model = "Marvell PXA168 Aspenite Development Board"; model = "Marvell PXA168 Aspenite Development Board";
......
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
* publishhed by the Free Software Foundation. * publishhed by the Free Software Foundation.
*/ */
/include/ "skeleton.dtsi" #include "skeleton.dtsi"
#include <dt-bindings/clock/marvell,pxa168.h>
/ { / {
aliases { aliases {
...@@ -59,6 +60,8 @@ uart1: uart@d4017000 { ...@@ -59,6 +60,8 @@ uart1: uart@d4017000 {
compatible = "mrvl,mmp-uart"; compatible = "mrvl,mmp-uart";
reg = <0xd4017000 0x1000>; reg = <0xd4017000 0x1000>;
interrupts = <27>; interrupts = <27>;
clocks = <&soc_clocks PXA168_CLK_UART0>;
resets = <&soc_clocks PXA168_CLK_UART0>;
status = "disabled"; status = "disabled";
}; };
...@@ -66,6 +69,8 @@ uart2: uart@d4018000 { ...@@ -66,6 +69,8 @@ uart2: uart@d4018000 {
compatible = "mrvl,mmp-uart"; compatible = "mrvl,mmp-uart";
reg = <0xd4018000 0x1000>; reg = <0xd4018000 0x1000>;
interrupts = <28>; interrupts = <28>;
clocks = <&soc_clocks PXA168_CLK_UART1>;
resets = <&soc_clocks PXA168_CLK_UART1>;
status = "disabled"; status = "disabled";
}; };
...@@ -73,6 +78,8 @@ uart3: uart@d4026000 { ...@@ -73,6 +78,8 @@ uart3: uart@d4026000 {
compatible = "mrvl,mmp-uart"; compatible = "mrvl,mmp-uart";
reg = <0xd4026000 0x1000>; reg = <0xd4026000 0x1000>;
interrupts = <29>; interrupts = <29>;
clocks = <&soc_clocks PXA168_CLK_UART2>;
resets = <&soc_clocks PXA168_CLK_UART2>;
status = "disabled"; status = "disabled";
}; };
...@@ -84,6 +91,8 @@ gpio@d4019000 { ...@@ -84,6 +91,8 @@ gpio@d4019000 {
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
interrupts = <49>; interrupts = <49>;
clocks = <&soc_clocks PXA168_CLK_GPIO>;
resets = <&soc_clocks PXA168_CLK_GPIO>;
interrupt-names = "gpio_mux"; interrupt-names = "gpio_mux";
interrupt-controller; interrupt-controller;
#interrupt-cells = <1>; #interrupt-cells = <1>;
...@@ -110,6 +119,8 @@ twsi1: i2c@d4011000 { ...@@ -110,6 +119,8 @@ twsi1: i2c@d4011000 {
compatible = "mrvl,mmp-twsi"; compatible = "mrvl,mmp-twsi";
reg = <0xd4011000 0x1000>; reg = <0xd4011000 0x1000>;
interrupts = <7>; interrupts = <7>;
clocks = <&soc_clocks PXA168_CLK_TWSI0>;
resets = <&soc_clocks PXA168_CLK_TWSI0>;
mrvl,i2c-fast-mode; mrvl,i2c-fast-mode;
status = "disabled"; status = "disabled";
}; };
...@@ -118,6 +129,8 @@ twsi2: i2c@d4025000 { ...@@ -118,6 +129,8 @@ twsi2: i2c@d4025000 {
compatible = "mrvl,mmp-twsi"; compatible = "mrvl,mmp-twsi";
reg = <0xd4025000 0x1000>; reg = <0xd4025000 0x1000>;
interrupts = <58>; interrupts = <58>;
clocks = <&soc_clocks PXA168_CLK_TWSI1>;
resets = <&soc_clocks PXA168_CLK_TWSI1>;
status = "disabled"; status = "disabled";
}; };
...@@ -126,8 +139,20 @@ rtc: rtc@d4010000 { ...@@ -126,8 +139,20 @@ rtc: rtc@d4010000 {
reg = <0xd4010000 0x1000>; reg = <0xd4010000 0x1000>;
interrupts = <5 6>; interrupts = <5 6>;
interrupt-names = "rtc 1Hz", "rtc alarm"; interrupt-names = "rtc 1Hz", "rtc alarm";
clocks = <&soc_clocks PXA168_CLK_RTC>;
resets = <&soc_clocks PXA168_CLK_RTC>;
status = "disabled"; status = "disabled";
}; };
}; };
soc_clocks: clocks{
compatible = "marvell,pxa168-clock";
reg = <0xd4050000 0x1000>,
<0xd4282800 0x400>,
<0xd4015000 0x1000>;
reg-names = "mpmu", "apmu", "apbc";
#clock-cells = <1>;
#reset-cells = <1>;
};
}; };
}; };
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
*/ */
/dts-v1/; /dts-v1/;
/include/ "pxa910.dtsi" #include "pxa910.dtsi"
/ { / {
model = "Marvell PXA910 DKB Development Board"; model = "Marvell PXA910 DKB Development Board";
......
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
* publishhed by the Free Software Foundation. * publishhed by the Free Software Foundation.
*/ */
/include/ "skeleton.dtsi" #include "skeleton.dtsi"
#include <dt-bindings/clock/marvell,pxa910.h>
/ { / {
aliases { aliases {
...@@ -71,6 +72,8 @@ uart1: uart@d4017000 { ...@@ -71,6 +72,8 @@ uart1: uart@d4017000 {
compatible = "mrvl,mmp-uart"; compatible = "mrvl,mmp-uart";
reg = <0xd4017000 0x1000>; reg = <0xd4017000 0x1000>;
interrupts = <27>; interrupts = <27>;
clocks = <&soc_clocks PXA910_CLK_UART0>;
resets = <&soc_clocks PXA910_CLK_UART0>;
status = "disabled"; status = "disabled";
}; };
...@@ -78,6 +81,8 @@ uart2: uart@d4018000 { ...@@ -78,6 +81,8 @@ uart2: uart@d4018000 {
compatible = "mrvl,mmp-uart"; compatible = "mrvl,mmp-uart";
reg = <0xd4018000 0x1000>; reg = <0xd4018000 0x1000>;
interrupts = <28>; interrupts = <28>;
clocks = <&soc_clocks PXA910_CLK_UART1>;
resets = <&soc_clocks PXA910_CLK_UART1>;
status = "disabled"; status = "disabled";
}; };
...@@ -85,6 +90,8 @@ uart3: uart@d4036000 { ...@@ -85,6 +90,8 @@ uart3: uart@d4036000 {
compatible = "mrvl,mmp-uart"; compatible = "mrvl,mmp-uart";
reg = <0xd4036000 0x1000>; reg = <0xd4036000 0x1000>;
interrupts = <59>; interrupts = <59>;
clocks = <&soc_clocks PXA910_CLK_UART2>;
resets = <&soc_clocks PXA910_CLK_UART2>;
status = "disabled"; status = "disabled";
}; };
...@@ -97,6 +104,8 @@ gpio@d4019000 { ...@@ -97,6 +104,8 @@ gpio@d4019000 {
#gpio-cells = <2>; #gpio-cells = <2>;
interrupts = <49>; interrupts = <49>;
interrupt-names = "gpio_mux"; interrupt-names = "gpio_mux";
clocks = <&soc_clocks PXA910_CLK_GPIO>;
resets = <&soc_clocks PXA910_CLK_GPIO>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <1>; #interrupt-cells = <1>;
ranges; ranges;
...@@ -124,6 +133,8 @@ twsi1: i2c@d4011000 { ...@@ -124,6 +133,8 @@ twsi1: i2c@d4011000 {
#size-cells = <0>; #size-cells = <0>;
reg = <0xd4011000 0x1000>; reg = <0xd4011000 0x1000>;
interrupts = <7>; interrupts = <7>;
clocks = <&soc_clocks PXA910_CLK_TWSI0>;
resets = <&soc_clocks PXA910_CLK_TWSI0>;
mrvl,i2c-fast-mode; mrvl,i2c-fast-mode;
status = "disabled"; status = "disabled";
}; };
...@@ -134,6 +145,8 @@ twsi2: i2c@d4037000 { ...@@ -134,6 +145,8 @@ twsi2: i2c@d4037000 {
#size-cells = <0>; #size-cells = <0>;
reg = <0xd4037000 0x1000>; reg = <0xd4037000 0x1000>;
interrupts = <54>; interrupts = <54>;
clocks = <&soc_clocks PXA910_CLK_TWSI1>;
resets = <&soc_clocks PXA910_CLK_TWSI1>;
status = "disabled"; status = "disabled";
}; };
...@@ -142,8 +155,21 @@ rtc: rtc@d4010000 { ...@@ -142,8 +155,21 @@ rtc: rtc@d4010000 {
reg = <0xd4010000 0x1000>; reg = <0xd4010000 0x1000>;
interrupts = <5 6>; interrupts = <5 6>;
interrupt-names = "rtc 1Hz", "rtc alarm"; interrupt-names = "rtc 1Hz", "rtc alarm";
clocks = <&soc_clocks PXA910_CLK_RTC>;
resets = <&soc_clocks PXA910_CLK_RTC>;
status = "disabled"; status = "disabled";
}; };
}; };
soc_clocks: clocks{
compatible = "marvell,pxa910-clock";
reg = <0xd4050000 0x1000>,
<0xd4282800 0x400>,
<0xd4015000 0x1000>,
<0xd403b000 0x1000>;
reg-names = "mpmu", "apmu", "apbc", "apbcp";
#clock-cells = <1>;
#reset-cells = <1>;
};
}; };
}; };
...@@ -86,11 +86,12 @@ config MACH_GPLUGD ...@@ -86,11 +86,12 @@ config MACH_GPLUGD
config MACH_MMP_DT config MACH_MMP_DT
bool "Support MMP (ARMv5) platforms from device tree" bool "Support MMP (ARMv5) platforms from device tree"
select CPU_PXA168
select CPU_PXA910
select USE_OF select USE_OF
select PINCTRL select PINCTRL
select PINCTRL_SINGLE select PINCTRL_SINGLE
select COMMON_CLK
select ARCH_HAS_RESET_CONTROLLER
select CPU_MOHAWK
help help
Include support for Marvell MMP2 based platforms using Include support for Marvell MMP2 based platforms using
the device tree. Needn't select any other machine while the device tree. Needn't select any other machine while
...@@ -99,10 +100,12 @@ config MACH_MMP_DT ...@@ -99,10 +100,12 @@ config MACH_MMP_DT
config MACH_MMP2_DT config MACH_MMP2_DT
bool "Support MMP2 (ARMv7) platforms from device tree" bool "Support MMP2 (ARMv7) platforms from device tree"
depends on !CPU_MOHAWK depends on !CPU_MOHAWK
select CPU_MMP2
select USE_OF select USE_OF
select PINCTRL select PINCTRL
select PINCTRL_SINGLE select PINCTRL_SINGLE
select COMMON_CLK
select ARCH_HAS_RESET_CONTROLLER
select CPU_PJ4
help help
Include support for Marvell MMP2 based platforms using Include support for Marvell MMP2 based platforms using
the device tree. the device tree.
...@@ -111,21 +114,18 @@ endmenu ...@@ -111,21 +114,18 @@ endmenu
config CPU_PXA168 config CPU_PXA168
bool bool
select COMMON_CLK
select CPU_MOHAWK select CPU_MOHAWK
help help
Select code specific to PXA168 Select code specific to PXA168
config CPU_PXA910 config CPU_PXA910
bool bool
select COMMON_CLK
select CPU_MOHAWK select CPU_MOHAWK
help help
Select code specific to PXA910 Select code specific to PXA910
config CPU_MMP2 config CPU_MMP2
bool bool
select COMMON_CLK
select CPU_PJ4 select CPU_PJ4
help help
Select code specific to MMP2. MMP2 is ARMv7 compatible. Select code specific to MMP2. MMP2 is ARMv7 compatible.
......
...@@ -11,63 +11,42 @@ ...@@ -11,63 +11,42 @@
#include <linux/irqchip.h> #include <linux/irqchip.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/clk-provider.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include <asm/hardware/cache-tauros2.h>
#include "common.h" #include "common.h"
extern void __init mmp_dt_init_timer(void); extern void __init mmp_dt_init_timer(void);
static const struct of_dev_auxdata pxa168_auxdata_lookup[] __initconst = { static const char *pxa168_dt_board_compat[] __initdata = {
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL), "mrvl,pxa168-aspenite",
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL), NULL,
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4026000, "pxa2xx-uart.2", NULL),
OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4025000, "pxa2xx-i2c.1", NULL),
OF_DEV_AUXDATA("marvell,mmp-gpio", 0xd4019000, "mmp-gpio", NULL),
OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
{}
}; };
static const struct of_dev_auxdata pxa910_auxdata_lookup[] __initconst = { static const char *pxa910_dt_board_compat[] __initdata = {
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL), "mrvl,pxa910-dkb",
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL), NULL,
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4036000, "pxa2xx-uart.2", NULL),
OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4037000, "pxa2xx-i2c.1", NULL),
OF_DEV_AUXDATA("marvell,mmp-gpio", 0xd4019000, "mmp-gpio", NULL),
OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
{}
}; };
static void __init pxa168_dt_init(void) static void __init mmp_init_time(void)
{
of_platform_populate(NULL, of_default_bus_match_table,
pxa168_auxdata_lookup, NULL);
}
static void __init pxa910_dt_init(void)
{ {
of_platform_populate(NULL, of_default_bus_match_table, #ifdef CONFIG_CACHE_TAUROS2
pxa910_auxdata_lookup, NULL); tauros2_init(0);
#endif
mmp_dt_init_timer();
of_clk_init(NULL);
} }
static const char *mmp_dt_board_compat[] __initdata = {
"mrvl,pxa168-aspenite",
"mrvl,pxa910-dkb",
NULL,
};
DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)") DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)")
.map_io = mmp_map_io, .map_io = mmp_map_io,
.init_time = mmp_dt_init_timer, .init_time = mmp_init_time,
.init_machine = pxa168_dt_init, .dt_compat = pxa168_dt_board_compat,
.dt_compat = mmp_dt_board_compat,
MACHINE_END MACHINE_END
DT_MACHINE_START(PXA910_DT, "Marvell PXA910 (Device Tree Support)") DT_MACHINE_START(PXA910_DT, "Marvell PXA910 (Device Tree Support)")
.map_io = mmp_map_io, .map_io = mmp_map_io,
.init_time = mmp_dt_init_timer, .init_time = mmp_init_time,
.init_machine = pxa910_dt_init, .dt_compat = pxa910_dt_board_compat,
.dt_compat = mmp_dt_board_compat,
MACHINE_END MACHINE_END
...@@ -12,29 +12,22 @@ ...@@ -12,29 +12,22 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/irqchip.h> #include <linux/irqchip.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/clk-provider.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include <asm/hardware/cache-tauros2.h>
#include "common.h" #include "common.h"
extern void __init mmp_dt_init_timer(void); extern void __init mmp_dt_init_timer(void);
static const struct of_dev_auxdata mmp2_auxdata_lookup[] __initconst = { static void __init mmp_init_time(void)
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4030000, "pxa2xx-uart.0", NULL),
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.1", NULL),
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.2", NULL),
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4016000, "pxa2xx-uart.3", NULL),
OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4025000, "pxa2xx-i2c.1", NULL),
OF_DEV_AUXDATA("marvell,mmp-gpio", 0xd4019000, "mmp2-gpio", NULL),
OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
{}
};
static void __init mmp2_dt_init(void)
{ {
of_platform_populate(NULL, of_default_bus_match_table, #ifdef CONFIG_CACHE_TAUROS2
mmp2_auxdata_lookup, NULL); tauros2_init(0);
#endif
mmp_dt_init_timer();
of_clk_init(NULL);
} }
static const char *mmp2_dt_board_compat[] __initdata = { static const char *mmp2_dt_board_compat[] __initdata = {
...@@ -44,7 +37,6 @@ static const char *mmp2_dt_board_compat[] __initdata = { ...@@ -44,7 +37,6 @@ static const char *mmp2_dt_board_compat[] __initdata = {
DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)") DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)")
.map_io = mmp_map_io, .map_io = mmp_map_io,
.init_time = mmp_dt_init_timer, .init_time = mmp_init_time,
.init_machine = mmp2_dt_init,
.dt_compat = mmp2_dt_board_compat, .dt_compat = mmp2_dt_board_compat,
MACHINE_END MACHINE_END
...@@ -2,7 +2,12 @@ ...@@ -2,7 +2,12 @@
# Makefile for mmp specific clk # Makefile for mmp specific clk
# #
obj-y += clk-apbc.o clk-apmu.o clk-frac.o obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o clk.o
obj-$(CONFIG_RESET_CONTROLLER) += reset.o
obj-$(CONFIG_MACH_MMP_DT) += clk-of-pxa168.o clk-of-pxa910.o
obj-$(CONFIG_MACH_MMP2_DT) += clk-of-mmp2.o
obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
......
...@@ -22,19 +22,12 @@ ...@@ -22,19 +22,12 @@
* numerator/denominator = Fin / (Fout * factor) * numerator/denominator = Fin / (Fout * factor)
*/ */
#define to_clk_factor(hw) container_of(hw, struct clk_factor, hw) #define to_clk_factor(hw) container_of(hw, struct mmp_clk_factor, hw)
struct clk_factor {
struct clk_hw hw;
void __iomem *base;
struct clk_factor_masks *masks;
struct clk_factor_tbl *ftbl;
unsigned int ftbl_cnt;
};
static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate, static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate,
unsigned long *prate) unsigned long *prate)
{ {
struct clk_factor *factor = to_clk_factor(hw); struct mmp_clk_factor *factor = to_clk_factor(hw);
unsigned long rate = 0, prev_rate; unsigned long rate = 0, prev_rate;
int i; int i;
...@@ -58,8 +51,8 @@ static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate, ...@@ -58,8 +51,8 @@ static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate,
static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_factor *factor = to_clk_factor(hw); struct mmp_clk_factor *factor = to_clk_factor(hw);
struct clk_factor_masks *masks = factor->masks; struct mmp_clk_factor_masks *masks = factor->masks;
unsigned int val, num, den; unsigned int val, num, den;
val = readl_relaxed(factor->base); val = readl_relaxed(factor->base);
...@@ -81,11 +74,12 @@ static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, ...@@ -81,11 +74,12 @@ static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate, static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
unsigned long prate) unsigned long prate)
{ {
struct clk_factor *factor = to_clk_factor(hw); struct mmp_clk_factor *factor = to_clk_factor(hw);
struct clk_factor_masks *masks = factor->masks; struct mmp_clk_factor_masks *masks = factor->masks;
int i; int i;
unsigned long val; unsigned long val;
unsigned long prev_rate, rate = 0; unsigned long prev_rate, rate = 0;
unsigned long flags = 0;
for (i = 0; i < factor->ftbl_cnt; i++) { for (i = 0; i < factor->ftbl_cnt; i++) {
prev_rate = rate; prev_rate = rate;
...@@ -97,6 +91,9 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate, ...@@ -97,6 +91,9 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
if (i > 0) if (i > 0)
i--; i--;
if (factor->lock)
spin_lock_irqsave(factor->lock, flags);
val = readl_relaxed(factor->base); val = readl_relaxed(factor->base);
val &= ~(masks->num_mask << masks->num_shift); val &= ~(masks->num_mask << masks->num_shift);
...@@ -107,21 +104,65 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate, ...@@ -107,21 +104,65 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
writel_relaxed(val, factor->base); writel_relaxed(val, factor->base);
if (factor->lock)
spin_unlock_irqrestore(factor->lock, flags);
return 0; return 0;
} }
void clk_factor_init(struct clk_hw *hw)
{
struct mmp_clk_factor *factor = to_clk_factor(hw);
struct mmp_clk_factor_masks *masks = factor->masks;
u32 val, num, den;
int i;
unsigned long flags = 0;
if (factor->lock)
spin_lock_irqsave(factor->lock, flags);
val = readl(factor->base);
/* calculate numerator */
num = (val >> masks->num_shift) & masks->num_mask;
/* calculate denominator */
den = (val >> masks->den_shift) & masks->den_mask;
for (i = 0; i < factor->ftbl_cnt; i++)
if (den == factor->ftbl[i].den && num == factor->ftbl[i].num)
break;
if (i >= factor->ftbl_cnt) {
val &= ~(masks->num_mask << masks->num_shift);
val |= (factor->ftbl[0].num & masks->num_mask) <<
masks->num_shift;
val &= ~(masks->den_mask << masks->den_shift);
val |= (factor->ftbl[0].den & masks->den_mask) <<
masks->den_shift;
writel(val, factor->base);
}
if (factor->lock)
spin_unlock_irqrestore(factor->lock, flags);
}
static struct clk_ops clk_factor_ops = { static struct clk_ops clk_factor_ops = {
.recalc_rate = clk_factor_recalc_rate, .recalc_rate = clk_factor_recalc_rate,
.round_rate = clk_factor_round_rate, .round_rate = clk_factor_round_rate,
.set_rate = clk_factor_set_rate, .set_rate = clk_factor_set_rate,
.init = clk_factor_init,
}; };
struct clk *mmp_clk_register_factor(const char *name, const char *parent_name, struct clk *mmp_clk_register_factor(const char *name, const char *parent_name,
unsigned long flags, void __iomem *base, unsigned long flags, void __iomem *base,
struct clk_factor_masks *masks, struct clk_factor_tbl *ftbl, struct mmp_clk_factor_masks *masks,
unsigned int ftbl_cnt) struct mmp_clk_factor_tbl *ftbl,
unsigned int ftbl_cnt, spinlock_t *lock)
{ {
struct clk_factor *factor; struct mmp_clk_factor *factor;
struct clk_init_data init; struct clk_init_data init;
struct clk *clk; struct clk *clk;
...@@ -142,6 +183,7 @@ struct clk *mmp_clk_register_factor(const char *name, const char *parent_name, ...@@ -142,6 +183,7 @@ struct clk *mmp_clk_register_factor(const char *name, const char *parent_name,
factor->ftbl = ftbl; factor->ftbl = ftbl;
factor->ftbl_cnt = ftbl_cnt; factor->ftbl_cnt = ftbl_cnt;
factor->hw.init = &init; factor->hw.init = &init;
factor->lock = lock;
init.name = name; init.name = name;
init.ops = &clk_factor_ops; init.ops = &clk_factor_ops;
......
/*
* mmp gate clock operation source file
*
* Copyright (C) 2014 Marvell
* Chao Xie <chao.xie@marvell.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/delay.h>
#include "clk.h"
/*
* Some clocks will have mutiple bits to enable the clocks, and
* the bits to disable the clock is not same as enabling bits.
*/
#define to_clk_mmp_gate(hw) container_of(hw, struct mmp_clk_gate, hw)
static int mmp_clk_gate_enable(struct clk_hw *hw)
{
struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
struct clk *clk = hw->clk;
unsigned long flags = 0;
unsigned long rate;
u32 tmp;
if (gate->lock)
spin_lock_irqsave(gate->lock, flags);
tmp = readl(gate->reg);
tmp &= ~gate->mask;
tmp |= gate->val_enable;
writel(tmp, gate->reg);
if (gate->lock)
spin_unlock_irqrestore(gate->lock, flags);
if (gate->flags & MMP_CLK_GATE_NEED_DELAY) {
rate = __clk_get_rate(clk);
/* Need delay 2 cycles. */
udelay(2000000/rate);
}
return 0;
}
static void mmp_clk_gate_disable(struct clk_hw *hw)
{
struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
unsigned long flags = 0;
u32 tmp;
if (gate->lock)
spin_lock_irqsave(gate->lock, flags);
tmp = readl(gate->reg);
tmp &= ~gate->mask;
tmp |= gate->val_disable;
writel(tmp, gate->reg);
if (gate->lock)
spin_unlock_irqrestore(gate->lock, flags);
}
static int mmp_clk_gate_is_enabled(struct clk_hw *hw)
{
struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
unsigned long flags = 0;
u32 tmp;
if (gate->lock)
spin_lock_irqsave(gate->lock, flags);
tmp = readl(gate->reg);
if (gate->lock)
spin_unlock_irqrestore(gate->lock, flags);
return (tmp & gate->mask) == gate->val_enable;
}
const struct clk_ops mmp_clk_gate_ops = {
.enable = mmp_clk_gate_enable,
.disable = mmp_clk_gate_disable,
.is_enabled = mmp_clk_gate_is_enabled,
};
struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u32 mask, u32 val_enable, u32 val_disable,
unsigned int gate_flags, spinlock_t *lock)
{
struct mmp_clk_gate *gate;
struct clk *clk;
struct clk_init_data init;
/* allocate the gate */
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate) {
pr_err("%s:%s could not allocate gate clk\n", __func__, name);
return ERR_PTR(-ENOMEM);
}
init.name = name;
init.ops = &mmp_clk_gate_ops;
init.flags = flags | CLK_IS_BASIC;
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
/* struct clk_gate assignments */
gate->reg = reg;
gate->mask = mask;
gate->val_enable = val_enable;
gate->val_disable = val_disable;
gate->flags = gate_flags;
gate->lock = lock;
gate->hw.init = &init;
clk = clk_register(dev, &gate->hw);
if (IS_ERR(clk))
kfree(gate);
return clk;
}
/*
* mmp mix(div and mux) clock operation source file
*
* Copyright (C) 2014 Marvell
* Chao Xie <chao.xie@marvell.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/err.h>
#include "clk.h"
/*
* The mix clock is a clock combined mux and div type clock.
* Because the div field and mux field need to be set at same
* time, we can not divide it into 2 types of clock
*/
#define to_clk_mix(hw) container_of(hw, struct mmp_clk_mix, hw)
static unsigned int _get_maxdiv(struct mmp_clk_mix *mix)
{
unsigned int div_mask = (1 << mix->reg_info.width_div) - 1;
unsigned int maxdiv = 0;
struct clk_div_table *clkt;
if (mix->div_flags & CLK_DIVIDER_ONE_BASED)
return div_mask;
if (mix->div_flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << div_mask;
if (mix->div_table) {
for (clkt = mix->div_table; clkt->div; clkt++)
if (clkt->div > maxdiv)
maxdiv = clkt->div;
return maxdiv;
}
return div_mask + 1;
}
static unsigned int _get_div(struct mmp_clk_mix *mix, unsigned int val)
{
struct clk_div_table *clkt;
if (mix->div_flags & CLK_DIVIDER_ONE_BASED)
return val;
if (mix->div_flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << val;
if (mix->div_table) {
for (clkt = mix->div_table; clkt->div; clkt++)
if (clkt->val == val)
return clkt->div;
if (clkt->div == 0)
return 0;
}
return val + 1;
}
static unsigned int _get_mux(struct mmp_clk_mix *mix, unsigned int val)
{
int num_parents = __clk_get_num_parents(mix->hw.clk);
int i;
if (mix->mux_flags & CLK_MUX_INDEX_BIT)
return ffs(val) - 1;
if (mix->mux_flags & CLK_MUX_INDEX_ONE)
return val - 1;
if (mix->mux_table) {
for (i = 0; i < num_parents; i++)
if (mix->mux_table[i] == val)
return i;
if (i == num_parents)
return 0;
}
return val;
}
static unsigned int _get_div_val(struct mmp_clk_mix *mix, unsigned int div)
{
struct clk_div_table *clkt;
if (mix->div_flags & CLK_DIVIDER_ONE_BASED)
return div;
if (mix->div_flags & CLK_DIVIDER_POWER_OF_TWO)
return __ffs(div);
if (mix->div_table) {
for (clkt = mix->div_table; clkt->div; clkt++)
if (clkt->div == div)
return clkt->val;
if (clkt->div == 0)
return 0;
}
return div - 1;
}
static unsigned int _get_mux_val(struct mmp_clk_mix *mix, unsigned int mux)
{
if (mix->mux_table)
return mix->mux_table[mux];
return mux;
}
static void _filter_clk_table(struct mmp_clk_mix *mix,
struct mmp_clk_mix_clk_table *table,
unsigned int table_size)
{
int i;
struct mmp_clk_mix_clk_table *item;
struct clk *parent, *clk;
unsigned long parent_rate;
clk = mix->hw.clk;
for (i = 0; i < table_size; i++) {
item = &table[i];
parent = clk_get_parent_by_index(clk, item->parent_index);
parent_rate = __clk_get_rate(parent);
if (parent_rate % item->rate) {
item->valid = 0;
} else {
item->divisor = parent_rate / item->rate;
item->valid = 1;
}
}
}
static int _set_rate(struct mmp_clk_mix *mix, u32 mux_val, u32 div_val,
unsigned int change_mux, unsigned int change_div)
{
struct mmp_clk_mix_reg_info *ri = &mix->reg_info;
u8 width, shift;
u32 mux_div, fc_req;
int ret, timeout = 50;
unsigned long flags = 0;
if (!change_mux && !change_div)
return -EINVAL;
if (mix->lock)
spin_lock_irqsave(mix->lock, flags);
if (mix->type == MMP_CLK_MIX_TYPE_V1
|| mix->type == MMP_CLK_MIX_TYPE_V2)
mux_div = readl(ri->reg_clk_ctrl);
else
mux_div = readl(ri->reg_clk_sel);
if (change_div) {
width = ri->width_div;
shift = ri->shift_div;
mux_div &= ~MMP_CLK_BITS_MASK(width, shift);
mux_div |= MMP_CLK_BITS_SET_VAL(div_val, width, shift);
}
if (change_mux) {
width = ri->width_mux;
shift = ri->shift_mux;
mux_div &= ~MMP_CLK_BITS_MASK(width, shift);
mux_div |= MMP_CLK_BITS_SET_VAL(mux_val, width, shift);
}
if (mix->type == MMP_CLK_MIX_TYPE_V1) {
writel(mux_div, ri->reg_clk_ctrl);
} else if (mix->type == MMP_CLK_MIX_TYPE_V2) {
mux_div |= (1 << ri->bit_fc);
writel(mux_div, ri->reg_clk_ctrl);
do {
fc_req = readl(ri->reg_clk_ctrl);
timeout--;
if (!(fc_req & (1 << ri->bit_fc)))
break;
} while (timeout);
if (timeout == 0) {
pr_err("%s:%s cannot do frequency change\n",
__func__, __clk_get_name(mix->hw.clk));
ret = -EBUSY;
goto error;
}
} else {
fc_req = readl(ri->reg_clk_ctrl);
fc_req |= 1 << ri->bit_fc;
writel(fc_req, ri->reg_clk_ctrl);
writel(mux_div, ri->reg_clk_sel);
fc_req &= ~(1 << ri->bit_fc);
}
ret = 0;
error:
if (mix->lock)
spin_unlock_irqrestore(mix->lock, flags);
return ret;
}
static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_clk)
{
struct mmp_clk_mix *mix = to_clk_mix(hw);
struct mmp_clk_mix_clk_table *item;
struct clk *parent, *parent_best, *mix_clk;
unsigned long parent_rate, mix_rate, mix_rate_best, parent_rate_best;
unsigned long gap, gap_best;
u32 div_val_max;
unsigned int div;
int i, j;
mix_clk = hw->clk;
parent = NULL;
mix_rate_best = 0;
parent_rate_best = 0;
gap_best = rate;
parent_best = NULL;
if (mix->table) {
for (i = 0; i < mix->table_size; i++) {
item = &mix->table[i];
if (item->valid == 0)
continue;
parent = clk_get_parent_by_index(mix_clk,
item->parent_index);
parent_rate = __clk_get_rate(parent);
mix_rate = parent_rate / item->divisor;
gap = abs(mix_rate - rate);
if (parent_best == NULL || gap < gap_best) {
parent_best = parent;
parent_rate_best = parent_rate;
mix_rate_best = mix_rate;
gap_best = gap;
if (gap_best == 0)
goto found;
}
}
} else {
for (i = 0; i < __clk_get_num_parents(mix_clk); i++) {
parent = clk_get_parent_by_index(mix_clk, i);
parent_rate = __clk_get_rate(parent);
div_val_max = _get_maxdiv(mix);
for (j = 0; j < div_val_max; j++) {
div = _get_div(mix, j);
mix_rate = parent_rate / div;
gap = abs(mix_rate - rate);
if (parent_best == NULL || gap < gap_best) {
parent_best = parent;
parent_rate_best = parent_rate;
mix_rate_best = mix_rate;
gap_best = gap;
if (gap_best == 0)
goto found;
}
}
}
}
found:
*best_parent_rate = parent_rate_best;
*best_parent_clk = parent_best;
return mix_rate_best;
}
static int mmp_clk_mix_set_rate_and_parent(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate,
u8 index)
{
struct mmp_clk_mix *mix = to_clk_mix(hw);
unsigned int div;
u32 div_val, mux_val;
div = parent_rate / rate;
div_val = _get_div_val(mix, div);
mux_val = _get_mux_val(mix, index);
return _set_rate(mix, mux_val, div_val, 1, 1);
}
static u8 mmp_clk_mix_get_parent(struct clk_hw *hw)
{
struct mmp_clk_mix *mix = to_clk_mix(hw);
struct mmp_clk_mix_reg_info *ri = &mix->reg_info;
unsigned long flags = 0;
u32 mux_div = 0;
u8 width, shift;
u32 mux_val;
if (mix->lock)
spin_lock_irqsave(mix->lock, flags);
if (mix->type == MMP_CLK_MIX_TYPE_V1
|| mix->type == MMP_CLK_MIX_TYPE_V2)
mux_div = readl(ri->reg_clk_ctrl);
else
mux_div = readl(ri->reg_clk_sel);
if (mix->lock)
spin_unlock_irqrestore(mix->lock, flags);
width = mix->reg_info.width_mux;
shift = mix->reg_info.shift_mux;
mux_val = MMP_CLK_BITS_GET_VAL(mux_div, width, shift);
return _get_mux(mix, mux_val);
}
static unsigned long mmp_clk_mix_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct mmp_clk_mix *mix = to_clk_mix(hw);
struct mmp_clk_mix_reg_info *ri = &mix->reg_info;
unsigned long flags = 0;
u32 mux_div = 0;
u8 width, shift;
unsigned int div;
if (mix->lock)
spin_lock_irqsave(mix->lock, flags);
if (mix->type == MMP_CLK_MIX_TYPE_V1
|| mix->type == MMP_CLK_MIX_TYPE_V2)
mux_div = readl(ri->reg_clk_ctrl);
else
mux_div = readl(ri->reg_clk_sel);
if (mix->lock)
spin_unlock_irqrestore(mix->lock, flags);
width = mix->reg_info.width_div;
shift = mix->reg_info.shift_div;
div = _get_div(mix, MMP_CLK_BITS_GET_VAL(mux_div, width, shift));
return parent_rate / div;
}
static int mmp_clk_set_parent(struct clk_hw *hw, u8 index)
{
struct mmp_clk_mix *mix = to_clk_mix(hw);
struct mmp_clk_mix_clk_table *item;
int i;
u32 div_val, mux_val;
if (mix->table) {
for (i = 0; i < mix->table_size; i++) {
item = &mix->table[i];
if (item->valid == 0)
continue;
if (item->parent_index == index)
break;
}
if (i < mix->table_size) {
div_val = _get_div_val(mix, item->divisor);
mux_val = _get_mux_val(mix, item->parent_index);
} else
return -EINVAL;
} else {
mux_val = _get_mux_val(mix, index);
div_val = 0;
}
return _set_rate(mix, mux_val, div_val, 1, div_val ? 1 : 0);
}
static int mmp_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long best_parent_rate)
{
struct mmp_clk_mix *mix = to_clk_mix(hw);
struct mmp_clk_mix_clk_table *item;
unsigned long parent_rate;
unsigned int best_divisor;
struct clk *mix_clk, *parent;
int i;
best_divisor = best_parent_rate / rate;
mix_clk = hw->clk;
if (mix->table) {
for (i = 0; i < mix->table_size; i++) {
item = &mix->table[i];
if (item->valid == 0)
continue;
parent = clk_get_parent_by_index(mix_clk,
item->parent_index);
parent_rate = __clk_get_rate(parent);
if (parent_rate == best_parent_rate
&& item->divisor == best_divisor)
break;
}
if (i < mix->table_size)
return _set_rate(mix,
_get_mux_val(mix, item->parent_index),
_get_div_val(mix, item->divisor),
1, 1);
else
return -EINVAL;
} else {
for (i = 0; i < __clk_get_num_parents(mix_clk); i++) {
parent = clk_get_parent_by_index(mix_clk, i);
parent_rate = __clk_get_rate(parent);
if (parent_rate == best_parent_rate)
break;
}
if (i < __clk_get_num_parents(mix_clk))
return _set_rate(mix, _get_mux_val(mix, i),
_get_div_val(mix, best_divisor), 1, 1);
else
return -EINVAL;
}
}
static void mmp_clk_mix_init(struct clk_hw *hw)
{
struct mmp_clk_mix *mix = to_clk_mix(hw);
if (mix->table)
_filter_clk_table(mix, mix->table, mix->table_size);
}
const struct clk_ops mmp_clk_mix_ops = {
.determine_rate = mmp_clk_mix_determine_rate,
.set_rate_and_parent = mmp_clk_mix_set_rate_and_parent,
.set_rate = mmp_clk_set_rate,
.set_parent = mmp_clk_set_parent,
.get_parent = mmp_clk_mix_get_parent,
.recalc_rate = mmp_clk_mix_recalc_rate,
.init = mmp_clk_mix_init,
};
struct clk *mmp_clk_register_mix(struct device *dev,
const char *name,
const char **parent_names,
u8 num_parents,
unsigned long flags,
struct mmp_clk_mix_config *config,
spinlock_t *lock)
{
struct mmp_clk_mix *mix;
struct clk *clk;
struct clk_init_data init;
size_t table_bytes;
mix = kzalloc(sizeof(*mix), GFP_KERNEL);
if (!mix) {
pr_err("%s:%s: could not allocate mmp mix clk\n",
__func__, name);
return ERR_PTR(-ENOMEM);
}
init.name = name;
init.flags = flags | CLK_GET_RATE_NOCACHE;
init.parent_names = parent_names;
init.num_parents = num_parents;
init.ops = &mmp_clk_mix_ops;
memcpy(&mix->reg_info, &config->reg_info, sizeof(config->reg_info));
if (config->table) {
table_bytes = sizeof(*config->table) * config->table_size;
mix->table = kzalloc(table_bytes, GFP_KERNEL);
if (!mix->table) {
pr_err("%s:%s: could not allocate mmp mix table\n",
__func__, name);
kfree(mix);
return ERR_PTR(-ENOMEM);
}
memcpy(mix->table, config->table, table_bytes);
mix->table_size = config->table_size;
}
if (config->mux_table) {
table_bytes = sizeof(u32) * num_parents;
mix->mux_table = kzalloc(table_bytes, GFP_KERNEL);
if (!mix->mux_table) {
pr_err("%s:%s: could not allocate mmp mix mux-table\n",
__func__, name);
kfree(mix->table);
kfree(mix);
return ERR_PTR(-ENOMEM);
}
memcpy(mix->mux_table, config->mux_table, table_bytes);
}
mix->div_flags = config->div_flags;
mix->mux_flags = config->mux_flags;
mix->lock = lock;
mix->hw.init = &init;
if (config->reg_info.bit_fc >= 32)
mix->type = MMP_CLK_MIX_TYPE_V1;
else if (config->reg_info.reg_clk_sel)
mix->type = MMP_CLK_MIX_TYPE_V3;
else
mix->type = MMP_CLK_MIX_TYPE_V2;
clk = clk_register(dev, &mix->hw);
if (IS_ERR(clk)) {
kfree(mix->mux_table);
kfree(mix->table);
kfree(mix);
}
return clk;
}
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
static DEFINE_SPINLOCK(clk_lock); static DEFINE_SPINLOCK(clk_lock);
static struct clk_factor_masks uart_factor_masks = { static struct mmp_clk_factor_masks uart_factor_masks = {
.factor = 2, .factor = 2,
.num_mask = 0x1fff, .num_mask = 0x1fff,
.den_mask = 0x1fff, .den_mask = 0x1fff,
...@@ -62,7 +62,7 @@ static struct clk_factor_masks uart_factor_masks = { ...@@ -62,7 +62,7 @@ static struct clk_factor_masks uart_factor_masks = {
.den_shift = 0, .den_shift = 0,
}; };
static struct clk_factor_tbl uart_factor_tbl[] = { static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
{.num = 14634, .den = 2165}, /*14.745MHZ */ {.num = 14634, .den = 2165}, /*14.745MHZ */
{.num = 3521, .den = 689}, /*19.23MHZ */ {.num = 3521, .den = 689}, /*19.23MHZ */
{.num = 9679, .den = 5728}, /*58.9824MHZ */ {.num = 9679, .den = 5728}, /*58.9824MHZ */
...@@ -191,7 +191,7 @@ void __init mmp2_clk_init(void) ...@@ -191,7 +191,7 @@ void __init mmp2_clk_init(void)
clk = mmp_clk_register_factor("uart_pll", "pll1_4", 0, clk = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
mpmu_base + MPMU_UART_PLL, mpmu_base + MPMU_UART_PLL,
&uart_factor_masks, uart_factor_tbl, &uart_factor_masks, uart_factor_tbl,
ARRAY_SIZE(uart_factor_tbl)); ARRAY_SIZE(uart_factor_tbl), &clk_lock);
clk_set_rate(clk, 14745600); clk_set_rate(clk, 14745600);
clk_register_clkdev(clk, "uart_pll", NULL); clk_register_clkdev(clk, "uart_pll", NULL);
......
/*
* mmp2 clock framework source file
*
* Copyright (C) 2012 Marvell
* Chao Xie <xiechao.mail@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/module.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/of_address.h>
#include <dt-bindings/clock/marvell,mmp2.h>
#include "clk.h"
#include "reset.h"
#define APBC_RTC 0x0
#define APBC_TWSI0 0x4
#define APBC_TWSI1 0x8
#define APBC_TWSI2 0xc
#define APBC_TWSI3 0x10
#define APBC_TWSI4 0x7c
#define APBC_TWSI5 0x80
#define APBC_KPC 0x18
#define APBC_UART0 0x2c
#define APBC_UART1 0x30
#define APBC_UART2 0x34
#define APBC_UART3 0x88
#define APBC_GPIO 0x38
#define APBC_PWM0 0x3c
#define APBC_PWM1 0x40
#define APBC_PWM2 0x44
#define APBC_PWM3 0x48
#define APBC_SSP0 0x50
#define APBC_SSP1 0x54
#define APBC_SSP2 0x58
#define APBC_SSP3 0x5c
#define APMU_SDH0 0x54
#define APMU_SDH1 0x58
#define APMU_SDH2 0xe8
#define APMU_SDH3 0xec
#define APMU_USB 0x5c
#define APMU_DISP0 0x4c
#define APMU_DISP1 0x110
#define APMU_CCIC0 0x50
#define APMU_CCIC1 0xf4
#define MPMU_UART_PLL 0x14
struct mmp2_clk_unit {
struct mmp_clk_unit unit;
void __iomem *mpmu_base;
void __iomem *apmu_base;
void __iomem *apbc_base;
};
static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
{MMP2_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768},
{MMP2_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000},
{MMP2_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 800000000},
{MMP2_CLK_PLL2, "pll2", NULL, CLK_IS_ROOT, 960000000},
{MMP2_CLK_USB_PLL, "usb_pll", NULL, CLK_IS_ROOT, 480000000},
};
static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
{MMP2_CLK_PLL1_2, "pll1_2", "pll1", 1, 2, 0},
{MMP2_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0},
{MMP2_CLK_PLL1_8, "pll1_8", "pll1_4", 1, 2, 0},
{MMP2_CLK_PLL1_16, "pll1_16", "pll1_8", 1, 2, 0},
{MMP2_CLK_PLL1_20, "pll1_20", "pll1_4", 1, 5, 0},
{MMP2_CLK_PLL1_3, "pll1_3", "pll1", 1, 3, 0},
{MMP2_CLK_PLL1_6, "pll1_6", "pll1_3", 1, 2, 0},
{MMP2_CLK_PLL1_12, "pll1_12", "pll1_6", 1, 2, 0},
{MMP2_CLK_PLL2_2, "pll2_2", "pll2", 1, 2, 0},
{MMP2_CLK_PLL2_4, "pll2_4", "pll2_2", 1, 2, 0},
{MMP2_CLK_PLL2_8, "pll2_8", "pll2_4", 1, 2, 0},
{MMP2_CLK_PLL2_16, "pll2_16", "pll2_8", 1, 2, 0},
{MMP2_CLK_PLL2_3, "pll2_3", "pll2", 1, 3, 0},
{MMP2_CLK_PLL2_6, "pll2_6", "pll2_3", 1, 2, 0},
{MMP2_CLK_PLL2_12, "pll2_12", "pll2_6", 1, 2, 0},
{MMP2_CLK_VCTCXO_2, "vctcxo_2", "vctcxo", 1, 2, 0},
{MMP2_CLK_VCTCXO_4, "vctcxo_4", "vctcxo_2", 1, 2, 0},
};
static struct mmp_clk_factor_masks uart_factor_masks = {
.factor = 2,
.num_mask = 0x1fff,
.den_mask = 0x1fff,
.num_shift = 16,
.den_shift = 0,
};
static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
{.num = 14634, .den = 2165}, /*14.745MHZ */
{.num = 3521, .den = 689}, /*19.23MHZ */
{.num = 9679, .den = 5728}, /*58.9824MHZ */
{.num = 15850, .den = 9451}, /*59.429MHZ */
};
static void mmp2_pll_init(struct mmp2_clk_unit *pxa_unit)
{
struct clk *clk;
struct mmp_clk_unit *unit = &pxa_unit->unit;
mmp_register_fixed_rate_clks(unit, fixed_rate_clks,
ARRAY_SIZE(fixed_rate_clks));
mmp_register_fixed_factor_clks(unit, fixed_factor_clks,
ARRAY_SIZE(fixed_factor_clks));
clk = mmp_clk_register_factor("uart_pll", "pll1_4",
CLK_SET_RATE_PARENT,
pxa_unit->mpmu_base + MPMU_UART_PLL,
&uart_factor_masks, uart_factor_tbl,
ARRAY_SIZE(uart_factor_tbl), NULL);
mmp_clk_add(unit, MMP2_CLK_UART_PLL, clk);
}
static DEFINE_SPINLOCK(uart0_lock);
static DEFINE_SPINLOCK(uart1_lock);
static DEFINE_SPINLOCK(uart2_lock);
static const char *uart_parent_names[] = {"uart_pll", "vctcxo"};
static DEFINE_SPINLOCK(ssp0_lock);
static DEFINE_SPINLOCK(ssp1_lock);
static DEFINE_SPINLOCK(ssp2_lock);
static DEFINE_SPINLOCK(ssp3_lock);
static const char *ssp_parent_names[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"};
static DEFINE_SPINLOCK(reset_lock);
static struct mmp_param_mux_clk apbc_mux_clks[] = {
{0, "uart0_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock},
{0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock},
{0, "uart2_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART2, 4, 3, 0, &uart2_lock},
{0, "uart3_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART3, 4, 3, 0, &uart2_lock},
{0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP0, 4, 3, 0, &ssp0_lock},
{0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock},
{0, "ssp2_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP2, 4, 3, 0, &ssp2_lock},
{0, "ssp3_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP3, 4, 3, 0, &ssp3_lock},
};
static struct mmp_param_gate_clk apbc_gate_clks[] = {
{MMP2_CLK_TWSI0, "twsi0_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x7, 0x3, 0x0, 0, &reset_lock},
{MMP2_CLK_TWSI1, "twsi1_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI1, 0x7, 0x3, 0x0, 0, &reset_lock},
{MMP2_CLK_TWSI2, "twsi2_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI2, 0x7, 0x3, 0x0, 0, &reset_lock},
{MMP2_CLK_TWSI3, "twsi3_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI3, 0x7, 0x3, 0x0, 0, &reset_lock},
{MMP2_CLK_TWSI4, "twsi4_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI4, 0x7, 0x3, 0x0, 0, &reset_lock},
{MMP2_CLK_TWSI5, "twsi5_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI5, 0x7, 0x3, 0x0, 0, &reset_lock},
{MMP2_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x7, 0x3, 0x0, 0, &reset_lock},
{MMP2_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_KPC, 0x7, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock},
{MMP2_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x87, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock},
{MMP2_CLK_PWM0, "pwm0_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM0, 0x7, 0x3, 0x0, 0, &reset_lock},
{MMP2_CLK_PWM1, "pwm1_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM1, 0x7, 0x3, 0x0, 0, &reset_lock},
{MMP2_CLK_PWM2, "pwm2_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM2, 0x7, 0x3, 0x0, 0, &reset_lock},
{MMP2_CLK_PWM3, "pwm3_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM3, 0x7, 0x3, 0x0, 0, &reset_lock},
/* The gate clocks has mux parent. */
{MMP2_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x7, 0x3, 0x0, 0, &uart0_lock},
{MMP2_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x7, 0x3, 0x0, 0, &uart1_lock},
{MMP2_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBC_UART2, 0x7, 0x3, 0x0, 0, &uart2_lock},
{MMP2_CLK_UART3, "uart3_clk", "uart3_mux", CLK_SET_RATE_PARENT, APBC_UART3, 0x7, 0x3, 0x0, 0, &uart2_lock},
{MMP2_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0x7, 0x3, 0x0, 0, &ssp0_lock},
{MMP2_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x7, 0x3, 0x0, 0, &ssp1_lock},
{MMP2_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0x7, 0x3, 0x0, 0, &ssp2_lock},
{MMP2_CLK_SSP3, "ssp3_clk", "ssp3_mux", CLK_SET_RATE_PARENT, APBC_SSP3, 0x7, 0x3, 0x0, 0, &ssp3_lock},
};
static void mmp2_apb_periph_clk_init(struct mmp2_clk_unit *pxa_unit)
{
struct mmp_clk_unit *unit = &pxa_unit->unit;
mmp_register_mux_clks(unit, apbc_mux_clks, pxa_unit->apbc_base,
ARRAY_SIZE(apbc_mux_clks));
mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base,
ARRAY_SIZE(apbc_gate_clks));
}
static DEFINE_SPINLOCK(sdh_lock);
static const char *sdh_parent_names[] = {"pll1_4", "pll2", "usb_pll", "pll1"};
static struct mmp_clk_mix_config sdh_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(4, 10, 2, 8, 32),
};
static DEFINE_SPINLOCK(usb_lock);
static DEFINE_SPINLOCK(disp0_lock);
static DEFINE_SPINLOCK(disp1_lock);
static const char *disp_parent_names[] = {"pll1", "pll1_16", "pll2", "vctcxo"};
static DEFINE_SPINLOCK(ccic0_lock);
static DEFINE_SPINLOCK(ccic1_lock);
static const char *ccic_parent_names[] = {"pll1_2", "pll1_16", "vctcxo"};
static struct mmp_clk_mix_config ccic0_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(4, 17, 2, 6, 32),
};
static struct mmp_clk_mix_config ccic1_mix_config = {
.reg_info = DEFINE_MIX_REG_INFO(4, 16, 2, 6, 32),
};
static struct mmp_param_mux_clk apmu_mux_clks[] = {
{MMP2_CLK_DISP0_MUX, "disp0_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP0, 6, 2, 0, &disp0_lock},
{MMP2_CLK_DISP1_MUX, "disp1_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP1, 6, 2, 0, &disp1_lock},
};
static struct mmp_param_div_clk apmu_div_clks[] = {
{0, "disp0_div", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 8, 4, 0, &disp0_lock},
{0, "disp0_sphy_div", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 15, 5, 0, &disp0_lock},
{0, "disp1_div", "disp1_mux", CLK_SET_RATE_PARENT, APMU_DISP1, 8, 4, 0, &disp1_lock},
{0, "ccic0_sphy_div", "ccic0_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC0, 10, 5, 0, &ccic0_lock},
{0, "ccic1_sphy_div", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 10, 5, 0, &ccic1_lock},
};
static struct mmp_param_gate_clk apmu_gate_clks[] = {
{MMP2_CLK_USB, "usb_clk", "usb_pll", 0, APMU_USB, 0x9, 0x9, 0x0, 0, &usb_lock},
/* The gate clocks has mux parent. */
{MMP2_CLK_SDH0, "sdh0_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP2_CLK_SDH1, "sdh1_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP2_CLK_SDH1, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP2_CLK_SDH1, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP2_CLK_DISP0, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock},
{MMP2_CLK_DISP0_SPHY, "disp0_sphy_clk", "disp0_sphy_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1024, 0x1024, 0x0, 0, &disp0_lock},
{MMP2_CLK_DISP1, "disp1_clk", "disp1_div", CLK_SET_RATE_PARENT, APMU_DISP1, 0x1b, 0x1b, 0x0, 0, &disp1_lock},
{MMP2_CLK_CCIC_ARBITER, "ccic_arbiter", "vctcxo", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1800, 0x1800, 0x0, 0, &ccic0_lock},
{MMP2_CLK_CCIC0, "ccic0_clk", "ccic0_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1b, 0x1b, 0x0, 0, &ccic0_lock},
{MMP2_CLK_CCIC0_PHY, "ccic0_phy_clk", "ccic0_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x24, 0x24, 0x0, 0, &ccic0_lock},
{MMP2_CLK_CCIC0_SPHY, "ccic0_sphy_clk", "ccic0_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x300, 0x300, 0x0, 0, &ccic0_lock},
{MMP2_CLK_CCIC1, "ccic1_clk", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x1b, 0x1b, 0x0, 0, &ccic1_lock},
{MMP2_CLK_CCIC1_PHY, "ccic1_phy_clk", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x24, 0x24, 0x0, 0, &ccic1_lock},
{MMP2_CLK_CCIC1_SPHY, "ccic1_sphy_clk", "ccic1_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x300, 0x300, 0x0, 0, &ccic1_lock},
};
static void mmp2_axi_periph_clk_init(struct mmp2_clk_unit *pxa_unit)
{
struct clk *clk;
struct mmp_clk_unit *unit = &pxa_unit->unit;
sdh_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_SDH0;
clk = mmp_clk_register_mix(NULL, "sdh_mix_clk", sdh_parent_names,
ARRAY_SIZE(sdh_parent_names),
CLK_SET_RATE_PARENT,
&sdh_mix_config, &sdh_lock);
ccic0_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_CCIC0;
clk = mmp_clk_register_mix(NULL, "ccic0_mix_clk", ccic_parent_names,
ARRAY_SIZE(ccic_parent_names),
CLK_SET_RATE_PARENT,
&ccic0_mix_config, &ccic0_lock);
mmp_clk_add(unit, MMP2_CLK_CCIC0_MIX, clk);
ccic1_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_CCIC1;
clk = mmp_clk_register_mix(NULL, "ccic1_mix_clk", ccic_parent_names,
ARRAY_SIZE(ccic_parent_names),
CLK_SET_RATE_PARENT,
&ccic1_mix_config, &ccic1_lock);
mmp_clk_add(unit, MMP2_CLK_CCIC1_MIX, clk);
mmp_register_mux_clks(unit, apmu_mux_clks, pxa_unit->apmu_base,
ARRAY_SIZE(apmu_mux_clks));
mmp_register_div_clks(unit, apmu_div_clks, pxa_unit->apmu_base,
ARRAY_SIZE(apmu_div_clks));
mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->apmu_base,
ARRAY_SIZE(apmu_gate_clks));
}
static void mmp2_clk_reset_init(struct device_node *np,
struct mmp2_clk_unit *pxa_unit)
{
struct mmp_clk_reset_cell *cells;
int i, nr_resets;
nr_resets = ARRAY_SIZE(apbc_gate_clks);
cells = kcalloc(nr_resets, sizeof(*cells), GFP_KERNEL);
if (!cells)
return;
for (i = 0; i < nr_resets; i++) {
cells[i].clk_id = apbc_gate_clks[i].id;
cells[i].reg = pxa_unit->apbc_base + apbc_gate_clks[i].offset;
cells[i].flags = 0;
cells[i].lock = apbc_gate_clks[i].lock;
cells[i].bits = 0x4;
}
mmp_clk_reset_register(np, cells, nr_resets);
}
static void __init mmp2_clk_init(struct device_node *np)
{
struct mmp2_clk_unit *pxa_unit;
pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL);
if (!pxa_unit)
return;
pxa_unit->mpmu_base = of_iomap(np, 0);
if (!pxa_unit->mpmu_base) {
pr_err("failed to map mpmu registers\n");
return;
}
pxa_unit->apmu_base = of_iomap(np, 1);
if (!pxa_unit->mpmu_base) {
pr_err("failed to map apmu registers\n");
return;
}
pxa_unit->apbc_base = of_iomap(np, 2);
if (!pxa_unit->apbc_base) {
pr_err("failed to map apbc registers\n");
return;
}
mmp_clk_init(np, &pxa_unit->unit, MMP2_NR_CLKS);
mmp2_pll_init(pxa_unit);
mmp2_apb_periph_clk_init(pxa_unit);
mmp2_axi_periph_clk_init(pxa_unit);
mmp2_clk_reset_init(np, pxa_unit);
}
CLK_OF_DECLARE(mmp2_clk, "marvell,mmp2-clock", mmp2_clk_init);
/*
* pxa168 clock framework source file
*
* Copyright (C) 2012 Marvell
* Chao Xie <xiechao.mail@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/module.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/of_address.h>
#include <dt-bindings/clock/marvell,pxa168.h>
#include "clk.h"
#include "reset.h"
#define APBC_RTC 0x28
#define APBC_TWSI0 0x2c
#define APBC_KPC 0x30
#define APBC_UART0 0x0
#define APBC_UART1 0x4
#define APBC_GPIO 0x8
#define APBC_PWM0 0xc
#define APBC_PWM1 0x10
#define APBC_PWM2 0x14
#define APBC_PWM3 0x18
#define APBC_SSP0 0x81c
#define APBC_SSP1 0x820
#define APBC_SSP2 0x84c
#define APBC_SSP3 0x858
#define APBC_SSP4 0x85c
#define APBC_TWSI1 0x6c
#define APBC_UART2 0x70
#define APMU_SDH0 0x54
#define APMU_SDH1 0x58
#define APMU_USB 0x5c
#define APMU_DISP0 0x4c
#define APMU_CCIC0 0x50
#define APMU_DFC 0x60
#define MPMU_UART_PLL 0x14
struct pxa168_clk_unit {
struct mmp_clk_unit unit;
void __iomem *mpmu_base;
void __iomem *apmu_base;
void __iomem *apbc_base;
};
static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
{PXA168_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768},
{PXA168_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000},
{PXA168_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000},
};
static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
{PXA168_CLK_PLL1_2, "pll1_2", "pll1", 1, 2, 0},
{PXA168_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0},
{PXA168_CLK_PLL1_8, "pll1_8", "pll1_4", 1, 2, 0},
{PXA168_CLK_PLL1_16, "pll1_16", "pll1_8", 1, 2, 0},
{PXA168_CLK_PLL1_6, "pll1_6", "pll1_2", 1, 3, 0},
{PXA168_CLK_PLL1_12, "pll1_12", "pll1_6", 1, 2, 0},
{PXA168_CLK_PLL1_24, "pll1_24", "pll1_12", 1, 2, 0},
{PXA168_CLK_PLL1_48, "pll1_48", "pll1_24", 1, 2, 0},
{PXA168_CLK_PLL1_96, "pll1_96", "pll1_48", 1, 2, 0},
{PXA168_CLK_PLL1_13, "pll1_13", "pll1", 1, 13, 0},
{PXA168_CLK_PLL1_13_1_5, "pll1_13_1_5", "pll1_13", 2, 3, 0},
{PXA168_CLK_PLL1_2_1_5, "pll1_2_1_5", "pll1_2", 2, 3, 0},
{PXA168_CLK_PLL1_3_16, "pll1_3_16", "pll1", 3, 16, 0},
};
static struct mmp_clk_factor_masks uart_factor_masks = {
.factor = 2,
.num_mask = 0x1fff,
.den_mask = 0x1fff,
.num_shift = 16,
.den_shift = 0,
};
static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
{.num = 8125, .den = 1536}, /*14.745MHZ */
};
static void pxa168_pll_init(struct pxa168_clk_unit *pxa_unit)
{
struct clk *clk;
struct mmp_clk_unit *unit = &pxa_unit->unit;
mmp_register_fixed_rate_clks(unit, fixed_rate_clks,
ARRAY_SIZE(fixed_rate_clks));
mmp_register_fixed_factor_clks(unit, fixed_factor_clks,
ARRAY_SIZE(fixed_factor_clks));
clk = mmp_clk_register_factor("uart_pll", "pll1_4",
CLK_SET_RATE_PARENT,
pxa_unit->mpmu_base + MPMU_UART_PLL,
&uart_factor_masks, uart_factor_tbl,
ARRAY_SIZE(uart_factor_tbl), NULL);
mmp_clk_add(unit, PXA168_CLK_UART_PLL, clk);
}
static DEFINE_SPINLOCK(uart0_lock);
static DEFINE_SPINLOCK(uart1_lock);
static DEFINE_SPINLOCK(uart2_lock);
static const char *uart_parent_names[] = {"pll1_3_16", "uart_pll"};
static DEFINE_SPINLOCK(ssp0_lock);
static DEFINE_SPINLOCK(ssp1_lock);
static DEFINE_SPINLOCK(ssp2_lock);
static DEFINE_SPINLOCK(ssp3_lock);
static DEFINE_SPINLOCK(ssp4_lock);
static const char *ssp_parent_names[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"};
static DEFINE_SPINLOCK(reset_lock);
static struct mmp_param_mux_clk apbc_mux_clks[] = {
{0, "uart0_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock},
{0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock},
{0, "uart2_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART2, 4, 3, 0, &uart2_lock},
{0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP0, 4, 3, 0, &ssp0_lock},
{0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock},
{0, "ssp2_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP2, 4, 3, 0, &ssp2_lock},
{0, "ssp3_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP3, 4, 3, 0, &ssp3_lock},
{0, "ssp4_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP4, 4, 3, 0, &ssp4_lock},
};
static struct mmp_param_gate_clk apbc_gate_clks[] = {
{PXA168_CLK_TWSI0, "twsi0_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x3, 0x3, 0x0, 0, &reset_lock},
{PXA168_CLK_TWSI1, "twsi1_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI1, 0x3, 0x3, 0x0, 0, &reset_lock},
{PXA168_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x3, 0x3, 0x0, 0, &reset_lock},
{PXA168_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_KPC, 0x3, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL},
{PXA168_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x83, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL},
{PXA168_CLK_PWM0, "pwm0_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM0, 0x3, 0x3, 0x0, 0, &reset_lock},
{PXA168_CLK_PWM1, "pwm1_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM1, 0x3, 0x3, 0x0, 0, &reset_lock},
{PXA168_CLK_PWM2, "pwm2_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM2, 0x3, 0x3, 0x0, 0, &reset_lock},
{PXA168_CLK_PWM3, "pwm3_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM3, 0x3, 0x3, 0x0, 0, &reset_lock},
/* The gate clocks has mux parent. */
{PXA168_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x3, 0x3, 0x0, 0, &uart0_lock},
{PXA168_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x3, 0x3, 0x0, 0, &uart1_lock},
{PXA168_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBC_UART2, 0x3, 0x3, 0x0, 0, &uart2_lock},
{PXA168_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0x3, 0x3, 0x0, 0, &ssp0_lock},
{PXA168_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x3, 0x3, 0x0, 0, &ssp1_lock},
{PXA168_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0x3, 0x3, 0x0, 0, &ssp2_lock},
{PXA168_CLK_SSP3, "ssp3_clk", "ssp3_mux", CLK_SET_RATE_PARENT, APBC_SSP3, 0x3, 0x3, 0x0, 0, &ssp3_lock},
{PXA168_CLK_SSP4, "ssp4_clk", "ssp4_mux", CLK_SET_RATE_PARENT, APBC_SSP4, 0x3, 0x3, 0x0, 0, &ssp4_lock},
};
static void pxa168_apb_periph_clk_init(struct pxa168_clk_unit *pxa_unit)
{
struct mmp_clk_unit *unit = &pxa_unit->unit;
mmp_register_mux_clks(unit, apbc_mux_clks, pxa_unit->apbc_base,
ARRAY_SIZE(apbc_mux_clks));
mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base,
ARRAY_SIZE(apbc_gate_clks));
}
static DEFINE_SPINLOCK(sdh0_lock);
static DEFINE_SPINLOCK(sdh1_lock);
static const char *sdh_parent_names[] = {"pll1_12", "pll1_13"};
static DEFINE_SPINLOCK(usb_lock);
static DEFINE_SPINLOCK(disp0_lock);
static const char *disp_parent_names[] = {"pll1_2", "pll1_12"};
static DEFINE_SPINLOCK(ccic0_lock);
static const char *ccic_parent_names[] = {"pll1_2", "pll1_12"};
static const char *ccic_phy_parent_names[] = {"pll1_6", "pll1_12"};
static struct mmp_param_mux_clk apmu_mux_clks[] = {
{0, "sdh0_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH0, 6, 1, 0, &sdh0_lock},
{0, "sdh1_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH1, 6, 1, 0, &sdh1_lock},
{0, "disp0_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP0, 6, 1, 0, &disp0_lock},
{0, "ccic0_mux", ccic_parent_names, ARRAY_SIZE(ccic_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 6, 1, 0, &ccic0_lock},
{0, "ccic0_phy_mux", ccic_phy_parent_names, ARRAY_SIZE(ccic_phy_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 7, 1, 0, &ccic0_lock},
};
static struct mmp_param_div_clk apmu_div_clks[] = {
{0, "ccic0_sphy_div", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 10, 5, 0, &ccic0_lock},
};
static struct mmp_param_gate_clk apmu_gate_clks[] = {
{PXA168_CLK_DFC, "dfc_clk", "pll1_4", CLK_SET_RATE_PARENT, APMU_DFC, 0x19b, 0x19b, 0x0, 0, NULL},
{PXA168_CLK_USB, "usb_clk", "usb_pll", 0, APMU_USB, 0x9, 0x9, 0x0, 0, &usb_lock},
{PXA168_CLK_SPH, "sph_clk", "usb_pll", 0, APMU_USB, 0x12, 0x12, 0x0, 0, &usb_lock},
/* The gate clocks has mux parent. */
{PXA168_CLK_SDH0, "sdh0_clk", "sdh0_mux", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh0_lock},
{PXA168_CLK_SDH1, "sdh1_clk", "sdh1_mux", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh1_lock},
{PXA168_CLK_DISP0, "disp0_clk", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock},
{PXA168_CLK_CCIC0, "ccic0_clk", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1b, 0x1b, 0x0, 0, &ccic0_lock},
{PXA168_CLK_CCIC0_PHY, "ccic0_phy_clk", "ccic0_phy_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x24, 0x24, 0x0, 0, &ccic0_lock},
{PXA168_CLK_CCIC0_SPHY, "ccic0_sphy_clk", "ccic0_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x300, 0x300, 0x0, 0, &ccic0_lock},
};
static void pxa168_axi_periph_clk_init(struct pxa168_clk_unit *pxa_unit)
{
struct mmp_clk_unit *unit = &pxa_unit->unit;
mmp_register_mux_clks(unit, apmu_mux_clks, pxa_unit->apmu_base,
ARRAY_SIZE(apmu_mux_clks));
mmp_register_div_clks(unit, apmu_div_clks, pxa_unit->apmu_base,
ARRAY_SIZE(apmu_div_clks));
mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->apmu_base,
ARRAY_SIZE(apmu_gate_clks));
}
static void pxa168_clk_reset_init(struct device_node *np,
struct pxa168_clk_unit *pxa_unit)
{
struct mmp_clk_reset_cell *cells;
int i, nr_resets;
nr_resets = ARRAY_SIZE(apbc_gate_clks);
cells = kcalloc(nr_resets, sizeof(*cells), GFP_KERNEL);
if (!cells)
return;
for (i = 0; i < nr_resets; i++) {
cells[i].clk_id = apbc_gate_clks[i].id;
cells[i].reg = pxa_unit->apbc_base + apbc_gate_clks[i].offset;
cells[i].flags = 0;
cells[i].lock = apbc_gate_clks[i].lock;
cells[i].bits = 0x4;
}
mmp_clk_reset_register(np, cells, nr_resets);
}
static void __init pxa168_clk_init(struct device_node *np)
{
struct pxa168_clk_unit *pxa_unit;
pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL);
if (!pxa_unit)
return;
pxa_unit->mpmu_base = of_iomap(np, 0);
if (!pxa_unit->mpmu_base) {
pr_err("failed to map mpmu registers\n");
return;
}
pxa_unit->apmu_base = of_iomap(np, 1);
if (!pxa_unit->mpmu_base) {
pr_err("failed to map apmu registers\n");
return;
}
pxa_unit->apbc_base = of_iomap(np, 2);
if (!pxa_unit->apbc_base) {
pr_err("failed to map apbc registers\n");
return;
}
mmp_clk_init(np, &pxa_unit->unit, PXA168_NR_CLKS);
pxa168_pll_init(pxa_unit);
pxa168_apb_periph_clk_init(pxa_unit);
pxa168_axi_periph_clk_init(pxa_unit);
pxa168_clk_reset_init(np, pxa_unit);
}
CLK_OF_DECLARE(pxa168_clk, "marvell,pxa168-clock", pxa168_clk_init);
/*
* pxa910 clock framework source file
*
* Copyright (C) 2012 Marvell
* Chao Xie <xiechao.mail@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/module.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/of_address.h>
#include <dt-bindings/clock/marvell,pxa910.h>
#include "clk.h"
#include "reset.h"
#define APBC_RTC 0x28
#define APBC_TWSI0 0x2c
#define APBC_KPC 0x18
#define APBC_UART0 0x0
#define APBC_UART1 0x4
#define APBC_GPIO 0x8
#define APBC_PWM0 0xc
#define APBC_PWM1 0x10
#define APBC_PWM2 0x14
#define APBC_PWM3 0x18
#define APBC_SSP0 0x1c
#define APBC_SSP1 0x20
#define APBC_SSP2 0x4c
#define APBCP_TWSI1 0x28
#define APBCP_UART2 0x1c
#define APMU_SDH0 0x54
#define APMU_SDH1 0x58
#define APMU_USB 0x5c
#define APMU_DISP0 0x4c
#define APMU_CCIC0 0x50
#define APMU_DFC 0x60
#define MPMU_UART_PLL 0x14
struct pxa910_clk_unit {
struct mmp_clk_unit unit;
void __iomem *mpmu_base;
void __iomem *apmu_base;
void __iomem *apbc_base;
void __iomem *apbcp_base;
};
static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
{PXA910_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768},
{PXA910_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000},
{PXA910_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000},
};
static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
{PXA910_CLK_PLL1_2, "pll1_2", "pll1", 1, 2, 0},
{PXA910_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0},
{PXA910_CLK_PLL1_8, "pll1_8", "pll1_4", 1, 2, 0},
{PXA910_CLK_PLL1_16, "pll1_16", "pll1_8", 1, 2, 0},
{PXA910_CLK_PLL1_6, "pll1_6", "pll1_2", 1, 3, 0},
{PXA910_CLK_PLL1_12, "pll1_12", "pll1_6", 1, 2, 0},
{PXA910_CLK_PLL1_24, "pll1_24", "pll1_12", 1, 2, 0},
{PXA910_CLK_PLL1_48, "pll1_48", "pll1_24", 1, 2, 0},
{PXA910_CLK_PLL1_96, "pll1_96", "pll1_48", 1, 2, 0},
{PXA910_CLK_PLL1_13, "pll1_13", "pll1", 1, 13, 0},
{PXA910_CLK_PLL1_13_1_5, "pll1_13_1_5", "pll1_13", 2, 3, 0},
{PXA910_CLK_PLL1_2_1_5, "pll1_2_1_5", "pll1_2", 2, 3, 0},
{PXA910_CLK_PLL1_3_16, "pll1_3_16", "pll1", 3, 16, 0},
};
static struct mmp_clk_factor_masks uart_factor_masks = {
.factor = 2,
.num_mask = 0x1fff,
.den_mask = 0x1fff,
.num_shift = 16,
.den_shift = 0,
};
static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
{.num = 8125, .den = 1536}, /*14.745MHZ */
};
static void pxa910_pll_init(struct pxa910_clk_unit *pxa_unit)
{
struct clk *clk;
struct mmp_clk_unit *unit = &pxa_unit->unit;
mmp_register_fixed_rate_clks(unit, fixed_rate_clks,
ARRAY_SIZE(fixed_rate_clks));
mmp_register_fixed_factor_clks(unit, fixed_factor_clks,
ARRAY_SIZE(fixed_factor_clks));
clk = mmp_clk_register_factor("uart_pll", "pll1_4",
CLK_SET_RATE_PARENT,
pxa_unit->mpmu_base + MPMU_UART_PLL,
&uart_factor_masks, uart_factor_tbl,
ARRAY_SIZE(uart_factor_tbl), NULL);
mmp_clk_add(unit, PXA910_CLK_UART_PLL, clk);
}
static DEFINE_SPINLOCK(uart0_lock);
static DEFINE_SPINLOCK(uart1_lock);
static DEFINE_SPINLOCK(uart2_lock);
static const char *uart_parent_names[] = {"pll1_3_16", "uart_pll"};
static DEFINE_SPINLOCK(ssp0_lock);
static DEFINE_SPINLOCK(ssp1_lock);
static const char *ssp_parent_names[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"};
static DEFINE_SPINLOCK(reset_lock);
static struct mmp_param_mux_clk apbc_mux_clks[] = {
{0, "uart0_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock},
{0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock},
{0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP0, 4, 3, 0, &ssp0_lock},
{0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock},
};
static struct mmp_param_mux_clk apbcp_mux_clks[] = {
{0, "uart2_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBCP_UART2, 4, 3, 0, &uart2_lock},
};
static struct mmp_param_gate_clk apbc_gate_clks[] = {
{PXA910_CLK_TWSI0, "twsi0_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x3, 0x3, 0x0, 0, &reset_lock},
{PXA910_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x3, 0x3, 0x0, 0, &reset_lock},
{PXA910_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_KPC, 0x3, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL},
{PXA910_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x83, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL},
{PXA910_CLK_PWM0, "pwm0_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM0, 0x3, 0x3, 0x0, 0, &reset_lock},
{PXA910_CLK_PWM1, "pwm1_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM1, 0x3, 0x3, 0x0, 0, &reset_lock},
{PXA910_CLK_PWM2, "pwm2_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM2, 0x3, 0x3, 0x0, 0, &reset_lock},
{PXA910_CLK_PWM3, "pwm3_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM3, 0x3, 0x3, 0x0, 0, &reset_lock},
/* The gate clocks has mux parent. */
{PXA910_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x3, 0x3, 0x0, 0, &uart0_lock},
{PXA910_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x3, 0x3, 0x0, 0, &uart1_lock},
{PXA910_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0x3, 0x3, 0x0, 0, &ssp0_lock},
{PXA910_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x3, 0x3, 0x0, 0, &ssp1_lock},
};
static struct mmp_param_gate_clk apbcp_gate_clks[] = {
{PXA910_CLK_TWSI1, "twsi1_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBCP_TWSI1, 0x3, 0x3, 0x0, 0, &reset_lock},
/* The gate clocks has mux parent. */
{PXA910_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBCP_UART2, 0x3, 0x3, 0x0, 0, &uart2_lock},
};
static void pxa910_apb_periph_clk_init(struct pxa910_clk_unit *pxa_unit)
{
struct mmp_clk_unit *unit = &pxa_unit->unit;
mmp_register_mux_clks(unit, apbc_mux_clks, pxa_unit->apbc_base,
ARRAY_SIZE(apbc_mux_clks));
mmp_register_mux_clks(unit, apbcp_mux_clks, pxa_unit->apbcp_base,
ARRAY_SIZE(apbcp_mux_clks));
mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base,
ARRAY_SIZE(apbc_gate_clks));
mmp_register_gate_clks(unit, apbcp_gate_clks, pxa_unit->apbcp_base,
ARRAY_SIZE(apbcp_gate_clks));
}
static DEFINE_SPINLOCK(sdh0_lock);
static DEFINE_SPINLOCK(sdh1_lock);
static const char *sdh_parent_names[] = {"pll1_12", "pll1_13"};
static DEFINE_SPINLOCK(usb_lock);
static DEFINE_SPINLOCK(disp0_lock);
static const char *disp_parent_names[] = {"pll1_2", "pll1_12"};
static DEFINE_SPINLOCK(ccic0_lock);
static const char *ccic_parent_names[] = {"pll1_2", "pll1_12"};
static const char *ccic_phy_parent_names[] = {"pll1_6", "pll1_12"};
static struct mmp_param_mux_clk apmu_mux_clks[] = {
{0, "sdh0_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH0, 6, 1, 0, &sdh0_lock},
{0, "sdh1_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH1, 6, 1, 0, &sdh1_lock},
{0, "disp0_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP0, 6, 1, 0, &disp0_lock},
{0, "ccic0_mux", ccic_parent_names, ARRAY_SIZE(ccic_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 6, 1, 0, &ccic0_lock},
{0, "ccic0_phy_mux", ccic_phy_parent_names, ARRAY_SIZE(ccic_phy_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 7, 1, 0, &ccic0_lock},
};
static struct mmp_param_div_clk apmu_div_clks[] = {
{0, "ccic0_sphy_div", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 10, 5, 0, &ccic0_lock},
};
static struct mmp_param_gate_clk apmu_gate_clks[] = {
{PXA910_CLK_DFC, "dfc_clk", "pll1_4", CLK_SET_RATE_PARENT, APMU_DFC, 0x19b, 0x19b, 0x0, 0, NULL},
{PXA910_CLK_USB, "usb_clk", "usb_pll", 0, APMU_USB, 0x9, 0x9, 0x0, 0, &usb_lock},
{PXA910_CLK_SPH, "sph_clk", "usb_pll", 0, APMU_USB, 0x12, 0x12, 0x0, 0, &usb_lock},
/* The gate clocks has mux parent. */
{PXA910_CLK_SDH0, "sdh0_clk", "sdh0_mux", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh0_lock},
{PXA910_CLK_SDH1, "sdh1_clk", "sdh1_mux", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh1_lock},
{PXA910_CLK_DISP0, "disp0_clk", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock},
{PXA910_CLK_CCIC0, "ccic0_clk", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1b, 0x1b, 0x0, 0, &ccic0_lock},
{PXA910_CLK_CCIC0_PHY, "ccic0_phy_clk", "ccic0_phy_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x24, 0x24, 0x0, 0, &ccic0_lock},
{PXA910_CLK_CCIC0_SPHY, "ccic0_sphy_clk", "ccic0_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x300, 0x300, 0x0, 0, &ccic0_lock},
};
static void pxa910_axi_periph_clk_init(struct pxa910_clk_unit *pxa_unit)
{
struct mmp_clk_unit *unit = &pxa_unit->unit;
mmp_register_mux_clks(unit, apmu_mux_clks, pxa_unit->apmu_base,
ARRAY_SIZE(apmu_mux_clks));
mmp_register_div_clks(unit, apmu_div_clks, pxa_unit->apmu_base,
ARRAY_SIZE(apmu_div_clks));
mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->apmu_base,
ARRAY_SIZE(apmu_gate_clks));
}
static void pxa910_clk_reset_init(struct device_node *np,
struct pxa910_clk_unit *pxa_unit)
{
struct mmp_clk_reset_cell *cells;
int i, base, nr_resets_apbc, nr_resets_apbcp, nr_resets;
nr_resets_apbc = ARRAY_SIZE(apbc_gate_clks);
nr_resets_apbcp = ARRAY_SIZE(apbcp_gate_clks);
nr_resets = nr_resets_apbc + nr_resets_apbcp;
cells = kcalloc(nr_resets, sizeof(*cells), GFP_KERNEL);
if (!cells)
return;
base = 0;
for (i = 0; i < nr_resets_apbc; i++) {
cells[base + i].clk_id = apbc_gate_clks[i].id;
cells[base + i].reg =
pxa_unit->apbc_base + apbc_gate_clks[i].offset;
cells[base + i].flags = 0;
cells[base + i].lock = apbc_gate_clks[i].lock;
cells[base + i].bits = 0x4;
}
base = nr_resets_apbc;
for (i = 0; i < nr_resets_apbcp; i++) {
cells[base + i].clk_id = apbcp_gate_clks[i].id;
cells[base + i].reg =
pxa_unit->apbc_base + apbc_gate_clks[i].offset;
cells[base + i].flags = 0;
cells[base + i].lock = apbc_gate_clks[i].lock;
cells[base + i].bits = 0x4;
}
mmp_clk_reset_register(np, cells, nr_resets);
}
static void __init pxa910_clk_init(struct device_node *np)
{
struct pxa910_clk_unit *pxa_unit;
pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL);
if (!pxa_unit)
return;
pxa_unit->mpmu_base = of_iomap(np, 0);
if (!pxa_unit->mpmu_base) {
pr_err("failed to map mpmu registers\n");
return;
}
pxa_unit->apmu_base = of_iomap(np, 1);
if (!pxa_unit->mpmu_base) {
pr_err("failed to map apmu registers\n");
return;
}
pxa_unit->apbc_base = of_iomap(np, 2);
if (!pxa_unit->apbc_base) {
pr_err("failed to map apbc registers\n");
return;
}
pxa_unit->apbcp_base = of_iomap(np, 3);
if (!pxa_unit->mpmu_base) {
pr_err("failed to map apbcp registers\n");
return;
}
mmp_clk_init(np, &pxa_unit->unit, PXA910_NR_CLKS);
pxa910_pll_init(pxa_unit);
pxa910_apb_periph_clk_init(pxa_unit);
pxa910_axi_periph_clk_init(pxa_unit);
pxa910_clk_reset_init(np, pxa_unit);
}
CLK_OF_DECLARE(pxa910_clk, "marvell,pxa910-clock", pxa910_clk_init);
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
static DEFINE_SPINLOCK(clk_lock); static DEFINE_SPINLOCK(clk_lock);
static struct clk_factor_masks uart_factor_masks = { static struct mmp_clk_factor_masks uart_factor_masks = {
.factor = 2, .factor = 2,
.num_mask = 0x1fff, .num_mask = 0x1fff,
.den_mask = 0x1fff, .den_mask = 0x1fff,
...@@ -55,7 +55,7 @@ static struct clk_factor_masks uart_factor_masks = { ...@@ -55,7 +55,7 @@ static struct clk_factor_masks uart_factor_masks = {
.den_shift = 0, .den_shift = 0,
}; };
static struct clk_factor_tbl uart_factor_tbl[] = { static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
{.num = 8125, .den = 1536}, /*14.745MHZ */ {.num = 8125, .den = 1536}, /*14.745MHZ */
}; };
...@@ -158,7 +158,7 @@ void __init pxa168_clk_init(void) ...@@ -158,7 +158,7 @@ void __init pxa168_clk_init(void)
uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0, uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
mpmu_base + MPMU_UART_PLL, mpmu_base + MPMU_UART_PLL,
&uart_factor_masks, uart_factor_tbl, &uart_factor_masks, uart_factor_tbl,
ARRAY_SIZE(uart_factor_tbl)); ARRAY_SIZE(uart_factor_tbl), &clk_lock);
clk_set_rate(uart_pll, 14745600); clk_set_rate(uart_pll, 14745600);
clk_register_clkdev(uart_pll, "uart_pll", NULL); clk_register_clkdev(uart_pll, "uart_pll", NULL);
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
static DEFINE_SPINLOCK(clk_lock); static DEFINE_SPINLOCK(clk_lock);
static struct clk_factor_masks uart_factor_masks = { static struct mmp_clk_factor_masks uart_factor_masks = {
.factor = 2, .factor = 2,
.num_mask = 0x1fff, .num_mask = 0x1fff,
.den_mask = 0x1fff, .den_mask = 0x1fff,
...@@ -53,7 +53,7 @@ static struct clk_factor_masks uart_factor_masks = { ...@@ -53,7 +53,7 @@ static struct clk_factor_masks uart_factor_masks = {
.den_shift = 0, .den_shift = 0,
}; };
static struct clk_factor_tbl uart_factor_tbl[] = { static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
{.num = 8125, .den = 1536}, /*14.745MHZ */ {.num = 8125, .den = 1536}, /*14.745MHZ */
}; };
...@@ -163,7 +163,7 @@ void __init pxa910_clk_init(void) ...@@ -163,7 +163,7 @@ void __init pxa910_clk_init(void)
uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0, uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
mpmu_base + MPMU_UART_PLL, mpmu_base + MPMU_UART_PLL,
&uart_factor_masks, uart_factor_tbl, &uart_factor_masks, uart_factor_tbl,
ARRAY_SIZE(uart_factor_tbl)); ARRAY_SIZE(uart_factor_tbl), &clk_lock);
clk_set_rate(uart_pll, 14745600); clk_set_rate(uart_pll, 14745600);
clk_register_clkdev(uart_pll, "uart_pll", NULL); clk_register_clkdev(uart_pll, "uart_pll", NULL);
......
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include "clk.h"
void mmp_clk_init(struct device_node *np, struct mmp_clk_unit *unit,
int nr_clks)
{
static struct clk **clk_table;
clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
if (!clk_table)
return;
unit->clk_table = clk_table;
unit->nr_clks = nr_clks;
unit->clk_data.clks = clk_table;
unit->clk_data.clk_num = nr_clks;
of_clk_add_provider(np, of_clk_src_onecell_get, &unit->clk_data);
}
void mmp_register_fixed_rate_clks(struct mmp_clk_unit *unit,
struct mmp_param_fixed_rate_clk *clks,
int size)
{
int i;
struct clk *clk;
for (i = 0; i < size; i++) {
clk = clk_register_fixed_rate(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags,
clks[i].fixed_rate);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].id)
unit->clk_table[clks[i].id] = clk;
}
}
void mmp_register_fixed_factor_clks(struct mmp_clk_unit *unit,
struct mmp_param_fixed_factor_clk *clks,
int size)
{
struct clk *clk;
int i;
for (i = 0; i < size; i++) {
clk = clk_register_fixed_factor(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags, clks[i].mult,
clks[i].div);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].id)
unit->clk_table[clks[i].id] = clk;
}
}
void mmp_register_general_gate_clks(struct mmp_clk_unit *unit,
struct mmp_param_general_gate_clk *clks,
void __iomem *base, int size)
{
struct clk *clk;
int i;
for (i = 0; i < size; i++) {
clk = clk_register_gate(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags,
base + clks[i].offset,
clks[i].bit_idx,
clks[i].gate_flags,
clks[i].lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].id)
unit->clk_table[clks[i].id] = clk;
}
}
void mmp_register_gate_clks(struct mmp_clk_unit *unit,
struct mmp_param_gate_clk *clks,
void __iomem *base, int size)
{
struct clk *clk;
int i;
for (i = 0; i < size; i++) {
clk = mmp_clk_register_gate(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags,
base + clks[i].offset,
clks[i].mask,
clks[i].val_enable,
clks[i].val_disable,
clks[i].gate_flags,
clks[i].lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].id)
unit->clk_table[clks[i].id] = clk;
}
}
void mmp_register_mux_clks(struct mmp_clk_unit *unit,
struct mmp_param_mux_clk *clks,
void __iomem *base, int size)
{
struct clk *clk;
int i;
for (i = 0; i < size; i++) {
clk = clk_register_mux(NULL, clks[i].name,
clks[i].parent_name,
clks[i].num_parents,
clks[i].flags,
base + clks[i].offset,
clks[i].shift,
clks[i].width,
clks[i].mux_flags,
clks[i].lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].id)
unit->clk_table[clks[i].id] = clk;
}
}
void mmp_register_div_clks(struct mmp_clk_unit *unit,
struct mmp_param_div_clk *clks,
void __iomem *base, int size)
{
struct clk *clk;
int i;
for (i = 0; i < size; i++) {
clk = clk_register_divider(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags,
base + clks[i].offset,
clks[i].shift,
clks[i].width,
clks[i].div_flags,
clks[i].lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].id)
unit->clk_table[clks[i].id] = clk;
}
}
void mmp_clk_add(struct mmp_clk_unit *unit, unsigned int id,
struct clk *clk)
{
if (IS_ERR_OR_NULL(clk)) {
pr_err("CLK %d has invalid pointer %p\n", id, clk);
return;
}
if (id > unit->nr_clks) {
pr_err("CLK %d is invalid\n", id);
return;
}
unit->clk_table[id] = clk;
}
...@@ -7,19 +7,123 @@ ...@@ -7,19 +7,123 @@
#define APBC_NO_BUS_CTRL BIT(0) #define APBC_NO_BUS_CTRL BIT(0)
#define APBC_POWER_CTRL BIT(1) #define APBC_POWER_CTRL BIT(1)
struct clk_factor_masks {
unsigned int factor; /* Clock type "factor" */
unsigned int num_mask; struct mmp_clk_factor_masks {
unsigned int den_mask; unsigned int factor;
unsigned int num_shift; unsigned int num_mask;
unsigned int den_shift; unsigned int den_mask;
unsigned int num_shift;
unsigned int den_shift;
}; };
struct clk_factor_tbl { struct mmp_clk_factor_tbl {
unsigned int num; unsigned int num;
unsigned int den; unsigned int den;
}; };
struct mmp_clk_factor {
struct clk_hw hw;
void __iomem *base;
struct mmp_clk_factor_masks *masks;
struct mmp_clk_factor_tbl *ftbl;
unsigned int ftbl_cnt;
spinlock_t *lock;
};
extern struct clk *mmp_clk_register_factor(const char *name,
const char *parent_name, unsigned long flags,
void __iomem *base, struct mmp_clk_factor_masks *masks,
struct mmp_clk_factor_tbl *ftbl, unsigned int ftbl_cnt,
spinlock_t *lock);
/* Clock type "mix" */
#define MMP_CLK_BITS_MASK(width, shift) \
(((1 << (width)) - 1) << (shift))
#define MMP_CLK_BITS_GET_VAL(data, width, shift) \
((data & MMP_CLK_BITS_MASK(width, shift)) >> (shift))
#define MMP_CLK_BITS_SET_VAL(val, width, shift) \
(((val) << (shift)) & MMP_CLK_BITS_MASK(width, shift))
enum {
MMP_CLK_MIX_TYPE_V1,
MMP_CLK_MIX_TYPE_V2,
MMP_CLK_MIX_TYPE_V3,
};
/* The register layout */
struct mmp_clk_mix_reg_info {
void __iomem *reg_clk_ctrl;
void __iomem *reg_clk_sel;
u8 width_div;
u8 shift_div;
u8 width_mux;
u8 shift_mux;
u8 bit_fc;
};
/* The suggested clock table from user. */
struct mmp_clk_mix_clk_table {
unsigned long rate;
u8 parent_index;
unsigned int divisor;
unsigned int valid;
};
struct mmp_clk_mix_config {
struct mmp_clk_mix_reg_info reg_info;
struct mmp_clk_mix_clk_table *table;
unsigned int table_size;
u32 *mux_table;
struct clk_div_table *div_table;
u8 div_flags;
u8 mux_flags;
};
struct mmp_clk_mix {
struct clk_hw hw;
struct mmp_clk_mix_reg_info reg_info;
struct mmp_clk_mix_clk_table *table;
u32 *mux_table;
struct clk_div_table *div_table;
unsigned int table_size;
u8 div_flags;
u8 mux_flags;
unsigned int type;
spinlock_t *lock;
};
extern const struct clk_ops mmp_clk_mix_ops;
extern struct clk *mmp_clk_register_mix(struct device *dev,
const char *name,
const char **parent_names,
u8 num_parents,
unsigned long flags,
struct mmp_clk_mix_config *config,
spinlock_t *lock);
/* Clock type "gate". MMP private gate */
#define MMP_CLK_GATE_NEED_DELAY BIT(0)
struct mmp_clk_gate {
struct clk_hw hw;
void __iomem *reg;
u32 mask;
u32 val_enable;
u32 val_disable;
unsigned int flags;
spinlock_t *lock;
};
extern const struct clk_ops mmp_clk_gate_ops;
extern struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u32 mask, u32 val_enable,
u32 val_disable, unsigned int gate_flags,
spinlock_t *lock);
extern struct clk *mmp_clk_register_pll2(const char *name, extern struct clk *mmp_clk_register_pll2(const char *name,
const char *parent_name, unsigned long flags); const char *parent_name, unsigned long flags);
extern struct clk *mmp_clk_register_apbc(const char *name, extern struct clk *mmp_clk_register_apbc(const char *name,
...@@ -28,8 +132,108 @@ extern struct clk *mmp_clk_register_apbc(const char *name, ...@@ -28,8 +132,108 @@ extern struct clk *mmp_clk_register_apbc(const char *name,
extern struct clk *mmp_clk_register_apmu(const char *name, extern struct clk *mmp_clk_register_apmu(const char *name,
const char *parent_name, void __iomem *base, u32 enable_mask, const char *parent_name, void __iomem *base, u32 enable_mask,
spinlock_t *lock); spinlock_t *lock);
extern struct clk *mmp_clk_register_factor(const char *name,
const char *parent_name, unsigned long flags, struct mmp_clk_unit {
void __iomem *base, struct clk_factor_masks *masks, unsigned int nr_clks;
struct clk_factor_tbl *ftbl, unsigned int ftbl_cnt); struct clk **clk_table;
struct clk_onecell_data clk_data;
};
struct mmp_param_fixed_rate_clk {
unsigned int id;
char *name;
const char *parent_name;
unsigned long flags;
unsigned long fixed_rate;
};
void mmp_register_fixed_rate_clks(struct mmp_clk_unit *unit,
struct mmp_param_fixed_rate_clk *clks,
int size);
struct mmp_param_fixed_factor_clk {
unsigned int id;
char *name;
const char *parent_name;
unsigned long mult;
unsigned long div;
unsigned long flags;
};
void mmp_register_fixed_factor_clks(struct mmp_clk_unit *unit,
struct mmp_param_fixed_factor_clk *clks,
int size);
struct mmp_param_general_gate_clk {
unsigned int id;
const char *name;
const char *parent_name;
unsigned long flags;
unsigned long offset;
u8 bit_idx;
u8 gate_flags;
spinlock_t *lock;
};
void mmp_register_general_gate_clks(struct mmp_clk_unit *unit,
struct mmp_param_general_gate_clk *clks,
void __iomem *base, int size);
struct mmp_param_gate_clk {
unsigned int id;
char *name;
const char *parent_name;
unsigned long flags;
unsigned long offset;
u32 mask;
u32 val_enable;
u32 val_disable;
unsigned int gate_flags;
spinlock_t *lock;
};
void mmp_register_gate_clks(struct mmp_clk_unit *unit,
struct mmp_param_gate_clk *clks,
void __iomem *base, int size);
struct mmp_param_mux_clk {
unsigned int id;
char *name;
const char **parent_name;
u8 num_parents;
unsigned long flags;
unsigned long offset;
u8 shift;
u8 width;
u8 mux_flags;
spinlock_t *lock;
};
void mmp_register_mux_clks(struct mmp_clk_unit *unit,
struct mmp_param_mux_clk *clks,
void __iomem *base, int size);
struct mmp_param_div_clk {
unsigned int id;
char *name;
const char *parent_name;
unsigned long flags;
unsigned long offset;
u8 shift;
u8 width;
u8 div_flags;
spinlock_t *lock;
};
void mmp_register_div_clks(struct mmp_clk_unit *unit,
struct mmp_param_div_clk *clks,
void __iomem *base, int size);
#define DEFINE_MIX_REG_INFO(w_d, s_d, w_m, s_m, fc) \
{ \
.width_div = (w_d), \
.shift_div = (s_d), \
.width_mux = (w_m), \
.shift_mux = (s_m), \
.bit_fc = (fc), \
}
void mmp_clk_init(struct device_node *np, struct mmp_clk_unit *unit,
int nr_clks);
void mmp_clk_add(struct mmp_clk_unit *unit, unsigned int id,
struct clk *clk);
#endif #endif
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/reset-controller.h>
#include "reset.h"
#define rcdev_to_unit(rcdev) container_of(rcdev, struct mmp_clk_reset_unit, rcdev)
static int mmp_of_reset_xlate(struct reset_controller_dev *rcdev,
const struct of_phandle_args *reset_spec)
{
struct mmp_clk_reset_unit *unit = rcdev_to_unit(rcdev);
struct mmp_clk_reset_cell *cell;
int i;
if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
return -EINVAL;
for (i = 0; i < rcdev->nr_resets; i++) {
cell = &unit->cells[i];
if (cell->clk_id == reset_spec->args[0])
break;
}
if (i == rcdev->nr_resets)
return -EINVAL;
return i;
}
static int mmp_clk_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct mmp_clk_reset_unit *unit = rcdev_to_unit(rcdev);
struct mmp_clk_reset_cell *cell;
unsigned long flags = 0;
u32 val;
cell = &unit->cells[id];
if (cell->lock)
spin_lock_irqsave(cell->lock, flags);
val = readl(cell->reg);
val |= cell->bits;
writel(val, cell->reg);
if (cell->lock)
spin_unlock_irqrestore(cell->lock, flags);
return 0;
}
static int mmp_clk_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct mmp_clk_reset_unit *unit = rcdev_to_unit(rcdev);
struct mmp_clk_reset_cell *cell;
unsigned long flags = 0;
u32 val;
cell = &unit->cells[id];
if (cell->lock)
spin_lock_irqsave(cell->lock, flags);
val = readl(cell->reg);
val &= ~cell->bits;
writel(val, cell->reg);
if (cell->lock)
spin_unlock_irqrestore(cell->lock, flags);
return 0;
}
static struct reset_control_ops mmp_clk_reset_ops = {
.assert = mmp_clk_reset_assert,
.deassert = mmp_clk_reset_deassert,
};
void mmp_clk_reset_register(struct device_node *np,
struct mmp_clk_reset_cell *cells, int nr_resets)
{
struct mmp_clk_reset_unit *unit;
unit = kzalloc(sizeof(*unit), GFP_KERNEL);
if (!unit)
return;
unit->cells = cells;
unit->rcdev.of_reset_n_cells = 1;
unit->rcdev.nr_resets = nr_resets;
unit->rcdev.ops = &mmp_clk_reset_ops;
unit->rcdev.of_node = np;
unit->rcdev.of_xlate = mmp_of_reset_xlate;
reset_controller_register(&unit->rcdev);
}
#ifndef __MACH_MMP_CLK_RESET_H
#define __MACH_MMP_CLK_RESET_H
#include <linux/reset-controller.h>
#define MMP_RESET_INVERT 1
struct mmp_clk_reset_cell {
unsigned int clk_id;
void __iomem *reg;
u32 bits;
unsigned int flags;
spinlock_t *lock;
};
struct mmp_clk_reset_unit {
struct reset_controller_dev rcdev;
struct mmp_clk_reset_cell *cells;
};
#ifdef CONFIG_RESET_CONTROLLER
void mmp_clk_reset_register(struct device_node *np,
struct mmp_clk_reset_cell *cells, int nr_resets);
#else
static inline void mmp_clk_reset_register(struct device_node *np,
struct mmp_clk_reset_cell *cells, int nr_resets)
{
}
#endif
#endif
#ifndef __DTS_MARVELL_MMP2_CLOCK_H
#define __DTS_MARVELL_MMP2_CLOCK_H
/* fixed clocks and plls */
#define MMP2_CLK_CLK32 1
#define MMP2_CLK_VCTCXO 2
#define MMP2_CLK_PLL1 3
#define MMP2_CLK_PLL1_2 8
#define MMP2_CLK_PLL1_4 9
#define MMP2_CLK_PLL1_8 10
#define MMP2_CLK_PLL1_16 11
#define MMP2_CLK_PLL1_3 12
#define MMP2_CLK_PLL1_6 13
#define MMP2_CLK_PLL1_12 14
#define MMP2_CLK_PLL1_20 15
#define MMP2_CLK_PLL2 16
#define MMP2_CLK_PLL2_2 17
#define MMP2_CLK_PLL2_4 18
#define MMP2_CLK_PLL2_8 19
#define MMP2_CLK_PLL2_16 20
#define MMP2_CLK_PLL2_3 21
#define MMP2_CLK_PLL2_6 22
#define MMP2_CLK_PLL2_12 23
#define MMP2_CLK_VCTCXO_2 24
#define MMP2_CLK_VCTCXO_4 25
#define MMP2_CLK_UART_PLL 26
#define MMP2_CLK_USB_PLL 27
/* apb periphrals */
#define MMP2_CLK_TWSI0 60
#define MMP2_CLK_TWSI1 61
#define MMP2_CLK_TWSI2 62
#define MMP2_CLK_TWSI3 63
#define MMP2_CLK_TWSI4 64
#define MMP2_CLK_TWSI5 65
#define MMP2_CLK_GPIO 66
#define MMP2_CLK_KPC 67
#define MMP2_CLK_RTC 68
#define MMP2_CLK_PWM0 69
#define MMP2_CLK_PWM1 70
#define MMP2_CLK_PWM2 71
#define MMP2_CLK_PWM3 72
#define MMP2_CLK_UART0 73
#define MMP2_CLK_UART1 74
#define MMP2_CLK_UART2 75
#define MMP2_CLK_UART3 76
#define MMP2_CLK_SSP0 77
#define MMP2_CLK_SSP1 78
#define MMP2_CLK_SSP2 79
#define MMP2_CLK_SSP3 80
/* axi periphrals */
#define MMP2_CLK_SDH0 101
#define MMP2_CLK_SDH1 102
#define MMP2_CLK_SDH2 103
#define MMP2_CLK_SDH3 104
#define MMP2_CLK_USB 105
#define MMP2_CLK_DISP0 106
#define MMP2_CLK_DISP0_MUX 107
#define MMP2_CLK_DISP0_SPHY 108
#define MMP2_CLK_DISP1 109
#define MMP2_CLK_DISP1_MUX 110
#define MMP2_CLK_CCIC_ARBITER 111
#define MMP2_CLK_CCIC0 112
#define MMP2_CLK_CCIC0_MIX 113
#define MMP2_CLK_CCIC0_PHY 114
#define MMP2_CLK_CCIC0_SPHY 115
#define MMP2_CLK_CCIC1 116
#define MMP2_CLK_CCIC1_MIX 117
#define MMP2_CLK_CCIC1_PHY 118
#define MMP2_CLK_CCIC1_SPHY 119
#define MMP2_NR_CLKS 200
#endif
#ifndef __DTS_MARVELL_PXA168_CLOCK_H
#define __DTS_MARVELL_PXA168_CLOCK_H
/* fixed clocks and plls */
#define PXA168_CLK_CLK32 1
#define PXA168_CLK_VCTCXO 2
#define PXA168_CLK_PLL1 3
#define PXA168_CLK_PLL1_2 8
#define PXA168_CLK_PLL1_4 9
#define PXA168_CLK_PLL1_8 10
#define PXA168_CLK_PLL1_16 11
#define PXA168_CLK_PLL1_6 12
#define PXA168_CLK_PLL1_12 13
#define PXA168_CLK_PLL1_24 14
#define PXA168_CLK_PLL1_48 15
#define PXA168_CLK_PLL1_96 16
#define PXA168_CLK_PLL1_13 17
#define PXA168_CLK_PLL1_13_1_5 18
#define PXA168_CLK_PLL1_2_1_5 19
#define PXA168_CLK_PLL1_3_16 20
#define PXA168_CLK_UART_PLL 27
/* apb periphrals */
#define PXA168_CLK_TWSI0 60
#define PXA168_CLK_TWSI1 61
#define PXA168_CLK_TWSI2 62
#define PXA168_CLK_TWSI3 63
#define PXA168_CLK_GPIO 64
#define PXA168_CLK_KPC 65
#define PXA168_CLK_RTC 66
#define PXA168_CLK_PWM0 67
#define PXA168_CLK_PWM1 68
#define PXA168_CLK_PWM2 69
#define PXA168_CLK_PWM3 70
#define PXA168_CLK_UART0 71
#define PXA168_CLK_UART1 72
#define PXA168_CLK_UART2 73
#define PXA168_CLK_SSP0 74
#define PXA168_CLK_SSP1 75
#define PXA168_CLK_SSP2 76
#define PXA168_CLK_SSP3 77
#define PXA168_CLK_SSP4 78
/* axi periphrals */
#define PXA168_CLK_DFC 100
#define PXA168_CLK_SDH0 101
#define PXA168_CLK_SDH1 102
#define PXA168_CLK_SDH2 103
#define PXA168_CLK_USB 104
#define PXA168_CLK_SPH 105
#define PXA168_CLK_DISP0 106
#define PXA168_CLK_CCIC0 107
#define PXA168_CLK_CCIC0_PHY 108
#define PXA168_CLK_CCIC0_SPHY 109
#define PXA168_NR_CLKS 200
#endif
#ifndef __DTS_MARVELL_PXA910_CLOCK_H
#define __DTS_MARVELL_PXA910_CLOCK_H
/* fixed clocks and plls */
#define PXA910_CLK_CLK32 1
#define PXA910_CLK_VCTCXO 2
#define PXA910_CLK_PLL1 3
#define PXA910_CLK_PLL1_2 8
#define PXA910_CLK_PLL1_4 9
#define PXA910_CLK_PLL1_8 10
#define PXA910_CLK_PLL1_16 11
#define PXA910_CLK_PLL1_6 12
#define PXA910_CLK_PLL1_12 13
#define PXA910_CLK_PLL1_24 14
#define PXA910_CLK_PLL1_48 15
#define PXA910_CLK_PLL1_96 16
#define PXA910_CLK_PLL1_13 17
#define PXA910_CLK_PLL1_13_1_5 18
#define PXA910_CLK_PLL1_2_1_5 19
#define PXA910_CLK_PLL1_3_16 20
#define PXA910_CLK_UART_PLL 27
/* apb periphrals */
#define PXA910_CLK_TWSI0 60
#define PXA910_CLK_TWSI1 61
#define PXA910_CLK_TWSI2 62
#define PXA910_CLK_TWSI3 63
#define PXA910_CLK_GPIO 64
#define PXA910_CLK_KPC 65
#define PXA910_CLK_RTC 66
#define PXA910_CLK_PWM0 67
#define PXA910_CLK_PWM1 68
#define PXA910_CLK_PWM2 69
#define PXA910_CLK_PWM3 70
#define PXA910_CLK_UART0 71
#define PXA910_CLK_UART1 72
#define PXA910_CLK_UART2 73
#define PXA910_CLK_SSP0 74
#define PXA910_CLK_SSP1 75
/* axi periphrals */
#define PXA910_CLK_DFC 100
#define PXA910_CLK_SDH0 101
#define PXA910_CLK_SDH1 102
#define PXA910_CLK_SDH2 103
#define PXA910_CLK_USB 104
#define PXA910_CLK_SPH 105
#define PXA910_CLK_DISP0 106
#define PXA910_CLK_CCIC0 107
#define PXA910_CLK_CCIC0_PHY 108
#define PXA910_CLK_CCIC0_SPHY 109
#define PXA910_NR_CLKS 200
#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