Commit dedca6ab authored by Mike Turquette's avatar Mike Turquette

Merge remote-tracking branch 'linaro/clk-next' into clk-next

parents 4b660a7f fb8abb7a
...@@ -68,21 +68,27 @@ the operations defined in clk.h: ...@@ -68,21 +68,27 @@ the operations defined in clk.h:
int (*is_enabled)(struct clk_hw *hw); int (*is_enabled)(struct clk_hw *hw);
unsigned long (*recalc_rate)(struct clk_hw *hw, unsigned long (*recalc_rate)(struct clk_hw *hw,
unsigned long parent_rate); unsigned long parent_rate);
long (*round_rate)(struct clk_hw *hw, unsigned long, long (*round_rate)(struct clk_hw *hw,
unsigned long *); unsigned long rate,
unsigned long *parent_rate);
long (*determine_rate)(struct clk_hw *hw, long (*determine_rate)(struct clk_hw *hw,
unsigned long rate, unsigned long rate,
unsigned long *best_parent_rate, unsigned long *best_parent_rate,
struct clk **best_parent_clk); struct clk **best_parent_clk);
int (*set_parent)(struct clk_hw *hw, u8 index); int (*set_parent)(struct clk_hw *hw, u8 index);
u8 (*get_parent)(struct clk_hw *hw); u8 (*get_parent)(struct clk_hw *hw);
int (*set_rate)(struct clk_hw *hw, unsigned long); int (*set_rate)(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate);
int (*set_rate_and_parent)(struct clk_hw *hw, int (*set_rate_and_parent)(struct clk_hw *hw,
unsigned long rate, unsigned long rate,
unsigned long parent_rate, u8 index); unsigned long parent_rate,
u8 index);
unsigned long (*recalc_accuracy)(struct clk_hw *hw, unsigned long (*recalc_accuracy)(struct clk_hw *hw,
unsigned long parent_accuracy); unsigned long parent_accuracy);
void (*init)(struct clk_hw *hw); void (*init)(struct clk_hw *hw);
int (*debug_init)(struct clk_hw *hw,
struct dentry *dentry);
}; };
Part 3 - hardware clk implementations Part 3 - hardware clk implementations
......
...@@ -10,12 +10,12 @@ This binding uses the common clock binding: ...@@ -10,12 +10,12 @@ This binding uses the common clock binding:
Required properties: Required properties:
- compatible - compatible
Shall have one of the following values: Shall have a value of the form "brcm,<model>-<which>-ccu",
- "brcm,bcm11351-root-ccu" where <model> is a Broadcom SoC model number and <which> is
- "brcm,bcm11351-aon-ccu" the name of a defined CCU. For example:
- "brcm,bcm11351-hub-ccu" "brcm,bcm11351-root-ccu"
- "brcm,bcm11351-master-ccu" The compatible strings used for each supported SoC family
- "brcm,bcm11351-slave-ccu" are defined below.
- reg - reg
Shall define the base and range of the address space Shall define the base and range of the address space
containing clock control registers containing clock control registers
...@@ -26,12 +26,48 @@ Required properties: ...@@ -26,12 +26,48 @@ Required properties:
Shall be an ordered list of strings defining the names of Shall be an ordered list of strings defining the names of
the clocks provided by the CCU. the clocks provided by the CCU.
Device tree example:
slave_ccu: slave_ccu {
compatible = "brcm,bcm11351-slave-ccu";
reg = <0x3e011000 0x0f00>;
#clock-cells = <1>;
clock-output-names = "uartb",
"uartb2",
"uartb3",
"uartb4";
};
ref_crystal_clk: ref_crystal {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <26000000>;
};
uart@3e002000 {
compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart";
status = "disabled";
reg = <0x3e002000 0x1000>;
clocks = <&slave_ccu BCM281XX_SLAVE_CCU_UARTB3>;
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
};
BCM281XX family
---------------
CCU compatible string values for SoCs in the BCM281XX family are:
"brcm,bcm11351-root-ccu"
"brcm,bcm11351-aon-ccu"
"brcm,bcm11351-hub-ccu"
"brcm,bcm11351-master-ccu"
"brcm,bcm11351-slave-ccu"
BCM281XX family SoCs use Kona CCUs. The following table defines The following table defines the set of CCUs and clock specifiers for
the set of CCUs and clock specifiers for BCM281XX clocks. When BCM281XX family clocks. When a clock consumer references a clocks,
a clock consumer references a clocks, its symbolic specifier its symbolic specifier (rather than its numeric index value) should
(rather than its numeric index value) should be used. These be used. These specifiers are defined in:
specifiers are defined in "include/dt-bindings/clock/bcm281xx.h". "include/dt-bindings/clock/bcm281xx.h"
CCU Clock Type Index Specifier CCU Clock Type Index Specifier
--- ----- ---- ----- --------- --- ----- ---- ----- ---------
...@@ -64,30 +100,40 @@ specifiers are defined in "include/dt-bindings/clock/bcm281xx.h". ...@@ -64,30 +100,40 @@ specifiers are defined in "include/dt-bindings/clock/bcm281xx.h".
slave pwm peri 9 BCM281XX_SLAVE_CCU_PWM slave pwm peri 9 BCM281XX_SLAVE_CCU_PWM
Device tree example: BCM21664 family
---------------
CCU compatible string values for SoCs in the BCM21664 family are:
"brcm,bcm21664-root-ccu"
"brcm,bcm21664-aon-ccu"
"brcm,bcm21664-master-ccu"
"brcm,bcm21664-slave-ccu"
slave_ccu: slave_ccu { The following table defines the set of CCUs and clock specifiers for
compatible = "brcm,bcm11351-slave-ccu"; BCM21664 family clocks. When a clock consumer references a clocks,
reg = <0x3e011000 0x0f00>; its symbolic specifier (rather than its numeric index value) should
#clock-cells = <1>; be used. These specifiers are defined in:
clock-output-names = "uartb", "include/dt-bindings/clock/bcm21664.h"
"uartb2",
"uartb3",
"uartb4";
};
ref_crystal_clk: ref_crystal { CCU Clock Type Index Specifier
#clock-cells = <0>; --- ----- ---- ----- ---------
compatible = "fixed-clock"; root frac_1m peri 0 BCM21664_ROOT_CCU_FRAC_1M
clock-frequency = <26000000>;
};
uart@3e002000 { aon hub_timer peri 0 BCM21664_AON_CCU_HUB_TIMER
compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart";
status = "disabled"; master sdio1 peri 0 BCM21664_MASTER_CCU_SDIO1
reg = <0x3e002000 0x1000>; master sdio2 peri 1 BCM21664_MASTER_CCU_SDIO2
clocks = <&slave_ccu BCM281XX_SLAVE_CCU_UARTB3>; master sdio3 peri 2 BCM21664_MASTER_CCU_SDIO3
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; master sdio4 peri 3 BCM21664_MASTER_CCU_SDIO4
reg-shift = <2>; master sdio1_sleep peri 4 BCM21664_MASTER_CCU_SDIO1_SLEEP
reg-io-width = <4>; master sdio2_sleep peri 5 BCM21664_MASTER_CCU_SDIO2_SLEEP
}; master sdio3_sleep peri 6 BCM21664_MASTER_CCU_SDIO3_SLEEP
master sdio4_sleep peri 7 BCM21664_MASTER_CCU_SDIO4_SLEEP
slave uartb peri 0 BCM21664_SLAVE_CCU_UARTB
slave uartb2 peri 1 BCM21664_SLAVE_CCU_UARTB2
slave uartb3 peri 2 BCM21664_SLAVE_CCU_UARTB3
slave uartb4 peri 3 BCM21664_SLAVE_CCU_UARTB4
slave bsc1 peri 4 BCM21664_SLAVE_CCU_BSC1
slave bsc2 peri 5 BCM21664_SLAVE_CCU_BSC2
slave bsc3 peri 6 BCM21664_SLAVE_CCU_BSC3
slave bsc4 peri 7 BCM21664_SLAVE_CCU_BSC4
...@@ -44,10 +44,9 @@ For example: ...@@ -44,10 +44,9 @@ For example:
clocks by index. The names should reflect the clock output signal clocks by index. The names should reflect the clock output signal
names for the device. names for the device.
clock-indices: If the identifyng number for the clocks in the node clock-indices: If the identifying number for the clocks in the node
is not linear from zero, then the this mapping allows is not linear from zero, then this allows the mapping of
the mapping of identifiers into the clock-output-names identifiers into the clock-output-names array.
array.
For example, if we have two clocks <&oscillator 1> and <&oscillator 3>: For example, if we have two clocks <&oscillator 1> and <&oscillator 3>:
...@@ -58,7 +57,7 @@ For example, if we have two clocks <&oscillator 1> and <&oscillator 3>: ...@@ -58,7 +57,7 @@ For example, if we have two clocks <&oscillator 1> and <&oscillator 3>:
clock-output-names = "clka", "clkb"; clock-output-names = "clka", "clkb";
} }
This ensures we do not have any empty nodes in clock-output-names This ensures we do not have any empty strings in clock-output-names
==Clock consumers== ==Clock consumers==
......
...@@ -12,7 +12,6 @@ Required properties: ...@@ -12,7 +12,6 @@ Required properties:
Optional properties: Optional properties:
- clock-accuracy : accuracy of clock in ppb (parts per billion). - clock-accuracy : accuracy of clock in ppb (parts per billion).
Should be a single cell. Should be a single cell.
- gpios : From common gpio binding; gpio connection to clock enable pin.
- clock-output-names : From common clock binding. - clock-output-names : From common clock binding.
Example: Example:
......
* Hisilicon Hix5hd2 Clock Controller
The hix5hd2 clock controller generates and supplies clock to various
controllers within the hix5hd2 SoC.
Required Properties:
- compatible: should be "hisilicon,hix5hd2-clock"
- reg: Address and length of the register set
- #clock-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/hix5hd2-clock.h>.
Examples:
clock: clock@f8a22000 {
compatible = "hisilicon,hix5hd2-clock";
reg = <0xf8a22000 0x1000>;
#clock-cells = <1>;
};
uart0: uart@f8b00000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0xf8b00000 0x1000>;
interrupts = <0 49 4>;
clocks = <&clock HIX5HD2_FIXED_83M>;
clock-names = "apb_pclk";
status = "disabled";
};
AXM5516 clock driver bindings
-----------------------------
Required properties :
- compatible : shall contain "lsi,axm5516-clks"
- reg : shall contain base register location and length
- #clock-cells : shall contain 1
The consumer specifies the desired clock by having the clock ID in its "clocks"
phandle cell. See <dt-bindings/clock/lsi,axxia-clock.h> for the list of
supported clock IDs.
Example:
clks: clock-controller@2010020000 {
compatible = "lsi,axm5516-clks";
#clock-cells = <1>;
reg = <0x20 0x10020000 0 0x20000>;
};
serial0: uart@2010080000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x20 0x10080000 0 0x1000>;
interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks AXXIA_CLK_PER>;
clock-names = "apb_pclk";
};
};
...@@ -29,6 +29,11 @@ The following is a list of provided IDs and clock names on Kirkwood and Dove: ...@@ -29,6 +29,11 @@ The following is a list of provided IDs and clock names on Kirkwood and Dove:
2 = l2clk (L2 Cache clock derived from CPU0 clock) 2 = l2clk (L2 Cache clock derived from CPU0 clock)
3 = ddrclk (DDR controller clock derived from CPU0 clock) 3 = ddrclk (DDR controller clock derived from CPU0 clock)
The following is a list of provided IDs and clock names on Orion5x:
0 = tclk (Internal Bus clock)
1 = cpuclk (CPU0 clock)
2 = ddrclk (DDR controller clock derived from CPU0 clock)
Required properties: Required properties:
- compatible : shall be one of the following: - compatible : shall be one of the following:
"marvell,armada-370-core-clock" - For Armada 370 SoC core clocks "marvell,armada-370-core-clock" - For Armada 370 SoC core clocks
...@@ -38,6 +43,9 @@ Required properties: ...@@ -38,6 +43,9 @@ Required properties:
"marvell,dove-core-clock" - for Dove SoC core clocks "marvell,dove-core-clock" - for Dove SoC core clocks
"marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180) "marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180)
"marvell,mv88f6180-core-clock" - for Kirkwood MV88f6180 SoC "marvell,mv88f6180-core-clock" - for Kirkwood MV88f6180 SoC
"marvell,mv88f5182-core-clock" - for Orion MV88F5182 SoC
"marvell,mv88f5281-core-clock" - for Orion MV88F5281 SoC
"marvell,mv88f6183-core-clock" - for Orion MV88F6183 SoC
- reg : shall be the register address of the Sample-At-Reset (SAR) register - reg : shall be the register address of the Sample-At-Reset (SAR) register
- #clock-cells : from common clock binding; shall be set to 1 - #clock-cells : from common clock binding; shall be set to 1
......
...@@ -4,6 +4,7 @@ Qualcomm Global Clock & Reset Controller Binding ...@@ -4,6 +4,7 @@ Qualcomm Global Clock & Reset Controller Binding
Required properties : Required properties :
- compatible : shall contain only one of the following: - compatible : shall contain only one of the following:
"qcom,gcc-apq8064"
"qcom,gcc-msm8660" "qcom,gcc-msm8660"
"qcom,gcc-msm8960" "qcom,gcc-msm8960"
"qcom,gcc-msm8974" "qcom,gcc-msm8974"
......
...@@ -10,6 +10,7 @@ index in the group, from 0 to 31. ...@@ -10,6 +10,7 @@ index in the group, from 0 to 31.
Required Properties: Required Properties:
- compatible: Must be one of the following - compatible: Must be one of the following
- "renesas,r8a7779-mstp-clocks" for R8A7779 (R-Car H1) MSTP gate clocks
- "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks - "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks
- "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2) MSTP gate clocks - "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2) MSTP gate clocks
- "renesas,cpg-mstp-clock" for generic MSTP gate clocks - "renesas,cpg-mstp-clock" for generic MSTP gate clocks
......
These bindings should be considered EXPERIMENTAL for now.
* Renesas R8A7740 Clock Pulse Generator (CPG)
The CPG generates core clocks for the R8A7740 SoC. It includes three PLLs
and several fixed ratio and variable ratio dividers.
Required Properties:
- compatible: Must be "renesas,r8a7740-cpg-clocks"
- reg: Base address and length of the memory resource used by the CPG
- clocks: Reference to the three parent clocks
- #clock-cells: Must be 1
- clock-output-names: The names of the clocks. Supported clocks are
"system", "pllc0", "pllc1", "pllc2", "r", "usb24s", "i", "zg", "b",
"m1", "hp", "hpp", "usbp", "s", "zb", "m3", and "cp".
- renesas,mode: board-specific settings of the MD_CK* bits
Example
-------
cpg_clocks: cpg_clocks@e6150000 {
compatible = "renesas,r8a7740-cpg-clocks";
reg = <0xe6150000 0x10000>;
clocks = <&extal1_clk>, <&extal2_clk>, <&extalr_clk>;
#clock-cells = <1>;
clock-output-names = "system", "pllc0", "pllc1",
"pllc2", "r",
"usb24s",
"i", "zg", "b", "m1", "hp",
"hpp", "usbp", "s", "zb", "m3",
"cp";
};
&cpg_clocks {
renesas,mode = <0x05>;
};
* Renesas R8A7779 Clock Pulse Generator (CPG)
The CPG generates core clocks for the R8A7779. It includes one PLL and
several fixed ratio dividers
Required Properties:
- compatible: Must be "renesas,r8a7779-cpg-clocks"
- reg: Base address and length of the memory resource used by the CPG
- clocks: Reference to the parent clock
- #clock-cells: Must be 1
- clock-output-names: The names of the clocks. Supported clocks are "plla",
"z", "zs", "s", "s1", "p", "b", "out".
Example
-------
cpg_clocks: cpg_clocks@ffc80000 {
compatible = "renesas,r8a7779-cpg-clocks";
reg = <0 0xffc80000 0 0x30>;
clocks = <&extal_clk>;
#clock-cells = <1>;
clock-output-names = "plla", "z", "zs", "s", "s1", "p",
"b", "out";
};
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/irq.h>
#include "dt-bindings/clock/bcm21664.h"
#include "skeleton.dtsi" #include "skeleton.dtsi"
/ { / {
...@@ -43,7 +45,7 @@ uart@3e000000 { ...@@ -43,7 +45,7 @@ uart@3e000000 {
compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart"; compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart";
status = "disabled"; status = "disabled";
reg = <0x3e000000 0x118>; reg = <0x3e000000 0x118>;
clocks = <&uartb_clk>; clocks = <&slave_ccu BCM21664_SLAVE_CCU_UARTB>;
interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>; reg-shift = <2>;
reg-io-width = <4>; reg-io-width = <4>;
...@@ -53,7 +55,7 @@ uart@3e001000 { ...@@ -53,7 +55,7 @@ uart@3e001000 {
compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart"; compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart";
status = "disabled"; status = "disabled";
reg = <0x3e001000 0x118>; reg = <0x3e001000 0x118>;
clocks = <&uartb2_clk>; clocks = <&slave_ccu BCM21664_SLAVE_CCU_UARTB2>;
interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>; reg-shift = <2>;
reg-io-width = <4>; reg-io-width = <4>;
...@@ -63,7 +65,7 @@ uart@3e002000 { ...@@ -63,7 +65,7 @@ uart@3e002000 {
compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart"; compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart";
status = "disabled"; status = "disabled";
reg = <0x3e002000 0x118>; reg = <0x3e002000 0x118>;
clocks = <&uartb3_clk>; clocks = <&slave_ccu BCM21664_SLAVE_CCU_UARTB3>;
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>; reg-shift = <2>;
reg-io-width = <4>; reg-io-width = <4>;
...@@ -85,7 +87,7 @@ timer@35006000 { ...@@ -85,7 +87,7 @@ timer@35006000 {
compatible = "brcm,kona-timer"; compatible = "brcm,kona-timer";
reg = <0x35006000 0x1c>; reg = <0x35006000 0x1c>;
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&hub_timer_clk>; clocks = <&aon_ccu BCM21664_AON_CCU_HUB_TIMER>;
}; };
gpio: gpio@35003000 { gpio: gpio@35003000 {
...@@ -106,7 +108,7 @@ sdio1: sdio@3f180000 { ...@@ -106,7 +108,7 @@ sdio1: sdio@3f180000 {
compatible = "brcm,kona-sdhci"; compatible = "brcm,kona-sdhci";
reg = <0x3f180000 0x801c>; reg = <0x3f180000 0x801c>;
interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sdio1_clk>; clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO1>;
status = "disabled"; status = "disabled";
}; };
...@@ -114,7 +116,7 @@ sdio2: sdio@3f190000 { ...@@ -114,7 +116,7 @@ sdio2: sdio@3f190000 {
compatible = "brcm,kona-sdhci"; compatible = "brcm,kona-sdhci";
reg = <0x3f190000 0x801c>; reg = <0x3f190000 0x801c>;
interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sdio2_clk>; clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO2>;
status = "disabled"; status = "disabled";
}; };
...@@ -122,7 +124,7 @@ sdio3: sdio@3f1a0000 { ...@@ -122,7 +124,7 @@ sdio3: sdio@3f1a0000 {
compatible = "brcm,kona-sdhci"; compatible = "brcm,kona-sdhci";
reg = <0x3f1a0000 0x801c>; reg = <0x3f1a0000 0x801c>;
interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sdio3_clk>; clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO3>;
status = "disabled"; status = "disabled";
}; };
...@@ -130,7 +132,7 @@ sdio4: sdio@3f1b0000 { ...@@ -130,7 +132,7 @@ sdio4: sdio@3f1b0000 {
compatible = "brcm,kona-sdhci"; compatible = "brcm,kona-sdhci";
reg = <0x3f1b0000 0x801c>; reg = <0x3f1b0000 0x801c>;
interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sdio4_clk>; clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO4>;
status = "disabled"; status = "disabled";
}; };
...@@ -140,7 +142,7 @@ i2c@3e016000 { ...@@ -140,7 +142,7 @@ i2c@3e016000 {
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
clocks = <&bsc1_clk>; clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC1>;
status = "disabled"; status = "disabled";
}; };
...@@ -150,7 +152,7 @@ i2c@3e017000 { ...@@ -150,7 +152,7 @@ i2c@3e017000 {
interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
clocks = <&bsc2_clk>; clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC2>;
status = "disabled"; status = "disabled";
}; };
...@@ -160,7 +162,7 @@ i2c@3e018000 { ...@@ -160,7 +162,7 @@ i2c@3e018000 {
interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
clocks = <&bsc3_clk>; clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC3>;
status = "disabled"; status = "disabled";
}; };
...@@ -170,105 +172,149 @@ i2c@3e01c000 { ...@@ -170,105 +172,149 @@ i2c@3e01c000 {
interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
clocks = <&bsc4_clk>; clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC4>;
status = "disabled"; status = "disabled";
}; };
clocks { clocks {
bsc1_clk: bsc1 { #address-cells = <1>;
compatible = "fixed-clock"; #size-cells = <1>;
clock-frequency = <13000000>; ranges;
#clock-cells = <0>;
};
bsc2_clk: bsc2 { /*
compatible = "fixed-clock"; * Fixed clocks are defined before CCUs whose
clock-frequency = <13000000>; * clocks may depend on them.
*/
ref_32k_clk: ref_32k {
#clock-cells = <0>; #clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <32768>;
}; };
bsc3_clk: bsc3 { bbl_32k_clk: bbl_32k {
compatible = "fixed-clock";
clock-frequency = <13000000>;
#clock-cells = <0>; #clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <32768>;
}; };
bsc4_clk: bsc4 { ref_13m_clk: ref_13m {
#clock-cells = <0>;
compatible = "fixed-clock"; compatible = "fixed-clock";
clock-frequency = <13000000>; clock-frequency = <13000000>;
#clock-cells = <0>;
}; };
pmu_bsc_clk: pmu_bsc { var_13m_clk: var_13m {
#clock-cells = <0>;
compatible = "fixed-clock"; compatible = "fixed-clock";
clock-frequency = <13000000>; clock-frequency = <13000000>;
#clock-cells = <0>;
}; };
hub_timer_clk: hub_timer { dft_19_5m_clk: dft_19_5m {
compatible = "fixed-clock";
clock-frequency = <32768>;
#clock-cells = <0>; #clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <19500000>;
}; };
pwm_clk: pwm { ref_crystal_clk: ref_crystal {
#clock-cells = <0>;
compatible = "fixed-clock"; compatible = "fixed-clock";
clock-frequency = <26000000>; clock-frequency = <26000000>;
#clock-cells = <0>;
}; };
sdio1_clk: sdio1 { ref_52m_clk: ref_52m {
compatible = "fixed-clock";
clock-frequency = <48000000>;
#clock-cells = <0>; #clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <52000000>;
}; };
sdio2_clk: sdio2 { var_52m_clk: var_52m {
compatible = "fixed-clock";
clock-frequency = <48000000>;
#clock-cells = <0>; #clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <52000000>;
}; };
sdio3_clk: sdio3 { usb_otg_ahb_clk: usb_otg_ahb {
compatible = "fixed-clock";
clock-frequency = <48000000>;
#clock-cells = <0>; #clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <52000000>;
}; };
sdio4_clk: sdio4 { ref_96m_clk: ref_96m {
compatible = "fixed-clock";
clock-frequency = <48000000>;
#clock-cells = <0>; #clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <96000000>;
}; };
tmon_1m_clk: tmon_1m { var_96m_clk: var_96m {
compatible = "fixed-clock";
clock-frequency = <1000000>;
#clock-cells = <0>; #clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <96000000>;
}; };
uartb_clk: uartb { ref_104m_clk: ref_104m {
compatible = "fixed-clock";
clock-frequency = <13000000>;
#clock-cells = <0>; #clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <104000000>;
}; };
uartb2_clk: uartb2 { var_104m_clk: var_104m {
compatible = "fixed-clock";
clock-frequency = <13000000>;
#clock-cells = <0>; #clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <104000000>;
}; };
uartb3_clk: uartb3 { ref_156m_clk: ref_156m {
compatible = "fixed-clock";
clock-frequency = <13000000>;
#clock-cells = <0>; #clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <156000000>;
}; };
usb_otg_ahb_clk: usb_otg_ahb { var_156m_clk: var_156m {
compatible = "fixed-clock";
clock-frequency = <52000000>;
#clock-cells = <0>; #clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <156000000>;
};
root_ccu: root_ccu {
compatible = BCM21664_DT_ROOT_CCU_COMPAT;
reg = <0x35001000 0x0f00>;
#clock-cells = <1>;
clock-output-names = "frac_1m";
};
aon_ccu: aon_ccu {
compatible = BCM21664_DT_AON_CCU_COMPAT;
reg = <0x35002000 0x0f00>;
#clock-cells = <1>;
clock-output-names = "hub_timer";
};
master_ccu: master_ccu {
compatible = BCM21664_DT_MASTER_CCU_COMPAT;
reg = <0x3f001000 0x0f00>;
#clock-cells = <1>;
clock-output-names = "sdio1",
"sdio2",
"sdio3",
"sdio4",
"sdio1_sleep",
"sdio2_sleep",
"sdio3_sleep",
"sdio4_sleep";
};
slave_ccu: slave_ccu {
compatible = BCM21664_DT_SLAVE_CCU_COMPAT;
reg = <0x3e011000 0x0f00>;
#clock-cells = <1>;
clock-output-names = "uartb",
"uartb2",
"uartb3",
"bsc1",
"bsc2",
"bsc3",
"bsc4";
}; };
}; };
......
...@@ -12,6 +12,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-composite.o ...@@ -12,6 +12,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-composite.o
# hardware specific clock types # hardware specific clock types
# please keep this section sorted lexicographically by file/directory path name # please keep this section sorted lexicographically by file/directory path name
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
...@@ -33,6 +34,7 @@ obj-$(CONFIG_COMMON_CLK_AT91) += at91/ ...@@ -33,6 +34,7 @@ obj-$(CONFIG_COMMON_CLK_AT91) += at91/
obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/ obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/
obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
obj-$(CONFIG_ARCH_HIP04) += hisilicon/ obj-$(CONFIG_ARCH_HIP04) += hisilicon/
obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
ifeq ($(CONFIG_COMMON_CLK), y) ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/ obj-$(CONFIG_ARCH_MMP) += mmp/
......
...@@ -6,4 +6,4 @@ config CLK_BCM_KONA ...@@ -6,4 +6,4 @@ config CLK_BCM_KONA
help help
Enable common clock framework support for Broadcom SoCs Enable common clock framework support for Broadcom SoCs
using "Kona" style clock control units, including those using "Kona" style clock control units, including those
in the BCM281xx family. in the BCM281xx and BCM21664 families.
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
/*
* Copyright (C) 2014 Broadcom Corporation
* Copyright 2014 Linaro Limited
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "clk-kona.h"
#include "dt-bindings/clock/bcm21664.h"
#define BCM21664_CCU_COMMON(_name, _capname) \
KONA_CCU_COMMON(BCM21664, _name, _capname)
/* Root CCU */
static struct peri_clk_data frac_1m_data = {
.gate = HW_SW_GATE(0x214, 16, 0, 1),
.clocks = CLOCKS("ref_crystal"),
};
static struct ccu_data root_ccu_data = {
BCM21664_CCU_COMMON(root, ROOT),
/* no policy control */
.kona_clks = {
[BCM21664_ROOT_CCU_FRAC_1M] =
KONA_CLK(root, frac_1m, peri),
[BCM21664_ROOT_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
},
};
/* AON CCU */
static struct peri_clk_data hub_timer_data = {
.gate = HW_SW_GATE(0x0414, 16, 0, 1),
.hyst = HYST(0x0414, 8, 9),
.clocks = CLOCKS("bbl_32k",
"frac_1m",
"dft_19_5m"),
.sel = SELECTOR(0x0a10, 0, 2),
.trig = TRIGGER(0x0a40, 4),
};
static struct ccu_data aon_ccu_data = {
BCM21664_CCU_COMMON(aon, AON),
.policy = {
.enable = CCU_LVM_EN(0x0034, 0),
.control = CCU_POLICY_CTL(0x000c, 0, 1, 2),
},
.kona_clks = {
[BCM21664_AON_CCU_HUB_TIMER] =
KONA_CLK(aon, hub_timer, peri),
[BCM21664_AON_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
},
};
/* Master CCU */
static struct peri_clk_data sdio1_data = {
.gate = HW_SW_GATE(0x0358, 18, 2, 3),
.clocks = CLOCKS("ref_crystal",
"var_52m",
"ref_52m",
"var_96m",
"ref_96m"),
.sel = SELECTOR(0x0a28, 0, 3),
.div = DIVIDER(0x0a28, 4, 14),
.trig = TRIGGER(0x0afc, 9),
};
static struct peri_clk_data sdio2_data = {
.gate = HW_SW_GATE(0x035c, 18, 2, 3),
.clocks = CLOCKS("ref_crystal",
"var_52m",
"ref_52m",
"var_96m",
"ref_96m"),
.sel = SELECTOR(0x0a2c, 0, 3),
.div = DIVIDER(0x0a2c, 4, 14),
.trig = TRIGGER(0x0afc, 10),
};
static struct peri_clk_data sdio3_data = {
.gate = HW_SW_GATE(0x0364, 18, 2, 3),
.clocks = CLOCKS("ref_crystal",
"var_52m",
"ref_52m",
"var_96m",
"ref_96m"),
.sel = SELECTOR(0x0a34, 0, 3),
.div = DIVIDER(0x0a34, 4, 14),
.trig = TRIGGER(0x0afc, 12),
};
static struct peri_clk_data sdio4_data = {
.gate = HW_SW_GATE(0x0360, 18, 2, 3),
.clocks = CLOCKS("ref_crystal",
"var_52m",
"ref_52m",
"var_96m",
"ref_96m"),
.sel = SELECTOR(0x0a30, 0, 3),
.div = DIVIDER(0x0a30, 4, 14),
.trig = TRIGGER(0x0afc, 11),
};
static struct peri_clk_data sdio1_sleep_data = {
.clocks = CLOCKS("ref_32k"), /* Verify */
.gate = HW_SW_GATE(0x0358, 18, 2, 3),
};
static struct peri_clk_data sdio2_sleep_data = {
.clocks = CLOCKS("ref_32k"), /* Verify */
.gate = HW_SW_GATE(0x035c, 18, 2, 3),
};
static struct peri_clk_data sdio3_sleep_data = {
.clocks = CLOCKS("ref_32k"), /* Verify */
.gate = HW_SW_GATE(0x0364, 18, 2, 3),
};
static struct peri_clk_data sdio4_sleep_data = {
.clocks = CLOCKS("ref_32k"), /* Verify */
.gate = HW_SW_GATE(0x0360, 18, 2, 3),
};
static struct ccu_data master_ccu_data = {
BCM21664_CCU_COMMON(master, MASTER),
.policy = {
.enable = CCU_LVM_EN(0x0034, 0),
.control = CCU_POLICY_CTL(0x000c, 0, 1, 2),
},
.kona_clks = {
[BCM21664_MASTER_CCU_SDIO1] =
KONA_CLK(master, sdio1, peri),
[BCM21664_MASTER_CCU_SDIO2] =
KONA_CLK(master, sdio2, peri),
[BCM21664_MASTER_CCU_SDIO3] =
KONA_CLK(master, sdio3, peri),
[BCM21664_MASTER_CCU_SDIO4] =
KONA_CLK(master, sdio4, peri),
[BCM21664_MASTER_CCU_SDIO1_SLEEP] =
KONA_CLK(master, sdio1_sleep, peri),
[BCM21664_MASTER_CCU_SDIO2_SLEEP] =
KONA_CLK(master, sdio2_sleep, peri),
[BCM21664_MASTER_CCU_SDIO3_SLEEP] =
KONA_CLK(master, sdio3_sleep, peri),
[BCM21664_MASTER_CCU_SDIO4_SLEEP] =
KONA_CLK(master, sdio4_sleep, peri),
[BCM21664_MASTER_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
},
};
/* Slave CCU */
static struct peri_clk_data uartb_data = {
.gate = HW_SW_GATE(0x0400, 18, 2, 3),
.clocks = CLOCKS("ref_crystal",
"var_156m",
"ref_156m"),
.sel = SELECTOR(0x0a10, 0, 2),
.div = FRAC_DIVIDER(0x0a10, 4, 12, 8),
.trig = TRIGGER(0x0afc, 2),
};
static struct peri_clk_data uartb2_data = {
.gate = HW_SW_GATE(0x0404, 18, 2, 3),
.clocks = CLOCKS("ref_crystal",
"var_156m",
"ref_156m"),
.sel = SELECTOR(0x0a14, 0, 2),
.div = FRAC_DIVIDER(0x0a14, 4, 12, 8),
.trig = TRIGGER(0x0afc, 3),
};
static struct peri_clk_data uartb3_data = {
.gate = HW_SW_GATE(0x0408, 18, 2, 3),
.clocks = CLOCKS("ref_crystal",
"var_156m",
"ref_156m"),
.sel = SELECTOR(0x0a18, 0, 2),
.div = FRAC_DIVIDER(0x0a18, 4, 12, 8),
.trig = TRIGGER(0x0afc, 4),
};
static struct peri_clk_data bsc1_data = {
.gate = HW_SW_GATE(0x0458, 18, 2, 3),
.clocks = CLOCKS("ref_crystal",
"var_104m",
"ref_104m",
"var_13m",
"ref_13m"),
.sel = SELECTOR(0x0a64, 0, 3),
.trig = TRIGGER(0x0afc, 23),
};
static struct peri_clk_data bsc2_data = {
.gate = HW_SW_GATE(0x045c, 18, 2, 3),
.clocks = CLOCKS("ref_crystal",
"var_104m",
"ref_104m",
"var_13m",
"ref_13m"),
.sel = SELECTOR(0x0a68, 0, 3),
.trig = TRIGGER(0x0afc, 24),
};
static struct peri_clk_data bsc3_data = {
.gate = HW_SW_GATE(0x0470, 18, 2, 3),
.clocks = CLOCKS("ref_crystal",
"var_104m",
"ref_104m",
"var_13m",
"ref_13m"),
.sel = SELECTOR(0x0a7c, 0, 3),
.trig = TRIGGER(0x0afc, 18),
};
static struct peri_clk_data bsc4_data = {
.gate = HW_SW_GATE(0x0474, 18, 2, 3),
.clocks = CLOCKS("ref_crystal",
"var_104m",
"ref_104m",
"var_13m",
"ref_13m"),
.sel = SELECTOR(0x0a80, 0, 3),
.trig = TRIGGER(0x0afc, 19),
};
static struct ccu_data slave_ccu_data = {
BCM21664_CCU_COMMON(slave, SLAVE),
.policy = {
.enable = CCU_LVM_EN(0x0034, 0),
.control = CCU_POLICY_CTL(0x000c, 0, 1, 2),
},
.kona_clks = {
[BCM21664_SLAVE_CCU_UARTB] =
KONA_CLK(slave, uartb, peri),
[BCM21664_SLAVE_CCU_UARTB2] =
KONA_CLK(slave, uartb2, peri),
[BCM21664_SLAVE_CCU_UARTB3] =
KONA_CLK(slave, uartb3, peri),
[BCM21664_SLAVE_CCU_BSC1] =
KONA_CLK(slave, bsc1, peri),
[BCM21664_SLAVE_CCU_BSC2] =
KONA_CLK(slave, bsc2, peri),
[BCM21664_SLAVE_CCU_BSC3] =
KONA_CLK(slave, bsc3, peri),
[BCM21664_SLAVE_CCU_BSC4] =
KONA_CLK(slave, bsc4, peri),
[BCM21664_SLAVE_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
},
};
/* Device tree match table callback functions */
static void __init kona_dt_root_ccu_setup(struct device_node *node)
{
kona_dt_ccu_setup(&root_ccu_data, node);
}
static void __init kona_dt_aon_ccu_setup(struct device_node *node)
{
kona_dt_ccu_setup(&aon_ccu_data, node);
}
static void __init kona_dt_master_ccu_setup(struct device_node *node)
{
kona_dt_ccu_setup(&master_ccu_data, node);
}
static void __init kona_dt_slave_ccu_setup(struct device_node *node)
{
kona_dt_ccu_setup(&slave_ccu_data, node);
}
CLK_OF_DECLARE(bcm21664_root_ccu, BCM21664_DT_ROOT_CCU_COMPAT,
kona_dt_root_ccu_setup);
CLK_OF_DECLARE(bcm21664_aon_ccu, BCM21664_DT_AON_CCU_COMPAT,
kona_dt_aon_ccu_setup);
CLK_OF_DECLARE(bcm21664_master_ccu, BCM21664_DT_MASTER_CCU_COMPAT,
kona_dt_master_ccu_setup);
CLK_OF_DECLARE(bcm21664_slave_ccu, BCM21664_DT_SLAVE_CCU_COMPAT,
kona_dt_slave_ccu_setup);
...@@ -15,14 +15,10 @@ ...@@ -15,14 +15,10 @@
#include "clk-kona.h" #include "clk-kona.h"
#include "dt-bindings/clock/bcm281xx.h" #include "dt-bindings/clock/bcm281xx.h"
/* bcm11351 CCU device tree "compatible" strings */ #define BCM281XX_CCU_COMMON(_name, _ucase_name) \
#define BCM11351_DT_ROOT_CCU_COMPAT "brcm,bcm11351-root-ccu" KONA_CCU_COMMON(BCM281XX, _name, _ucase_name)
#define BCM11351_DT_AON_CCU_COMPAT "brcm,bcm11351-aon-ccu"
#define BCM11351_DT_HUB_CCU_COMPAT "brcm,bcm11351-hub-ccu"
#define BCM11351_DT_MASTER_CCU_COMPAT "brcm,bcm11351-master-ccu"
#define BCM11351_DT_SLAVE_CCU_COMPAT "brcm,bcm11351-slave-ccu"
/* Root CCU clocks */ /* Root CCU */
static struct peri_clk_data frac_1m_data = { static struct peri_clk_data frac_1m_data = {
.gate = HW_SW_GATE(0x214, 16, 0, 1), .gate = HW_SW_GATE(0x214, 16, 0, 1),
...@@ -31,7 +27,16 @@ static struct peri_clk_data frac_1m_data = { ...@@ -31,7 +27,16 @@ static struct peri_clk_data frac_1m_data = {
.clocks = CLOCKS("ref_crystal"), .clocks = CLOCKS("ref_crystal"),
}; };
/* AON CCU clocks */ static struct ccu_data root_ccu_data = {
BCM281XX_CCU_COMMON(root, ROOT),
.kona_clks = {
[BCM281XX_ROOT_CCU_FRAC_1M] =
KONA_CLK(root, frac_1m, peri),
[BCM281XX_ROOT_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
},
};
/* AON CCU */
static struct peri_clk_data hub_timer_data = { static struct peri_clk_data hub_timer_data = {
.gate = HW_SW_GATE(0x0414, 16, 0, 1), .gate = HW_SW_GATE(0x0414, 16, 0, 1),
...@@ -60,7 +65,20 @@ static struct peri_clk_data pmu_bsc_var_data = { ...@@ -60,7 +65,20 @@ static struct peri_clk_data pmu_bsc_var_data = {
.trig = TRIGGER(0x0a40, 2), .trig = TRIGGER(0x0a40, 2),
}; };
/* Hub CCU clocks */ static struct ccu_data aon_ccu_data = {
BCM281XX_CCU_COMMON(aon, AON),
.kona_clks = {
[BCM281XX_AON_CCU_HUB_TIMER] =
KONA_CLK(aon, hub_timer, peri),
[BCM281XX_AON_CCU_PMU_BSC] =
KONA_CLK(aon, pmu_bsc, peri),
[BCM281XX_AON_CCU_PMU_BSC_VAR] =
KONA_CLK(aon, pmu_bsc_var, peri),
[BCM281XX_AON_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
},
};
/* Hub CCU */
static struct peri_clk_data tmon_1m_data = { static struct peri_clk_data tmon_1m_data = {
.gate = HW_SW_GATE(0x04a4, 18, 2, 3), .gate = HW_SW_GATE(0x04a4, 18, 2, 3),
...@@ -70,7 +88,16 @@ static struct peri_clk_data tmon_1m_data = { ...@@ -70,7 +88,16 @@ static struct peri_clk_data tmon_1m_data = {
.trig = TRIGGER(0x0e84, 1), .trig = TRIGGER(0x0e84, 1),
}; };
/* Master CCU clocks */ static struct ccu_data hub_ccu_data = {
BCM281XX_CCU_COMMON(hub, HUB),
.kona_clks = {
[BCM281XX_HUB_CCU_TMON_1M] =
KONA_CLK(hub, tmon_1m, peri),
[BCM281XX_HUB_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
},
};
/* Master CCU */
static struct peri_clk_data sdio1_data = { static struct peri_clk_data sdio1_data = {
.gate = HW_SW_GATE(0x0358, 18, 2, 3), .gate = HW_SW_GATE(0x0358, 18, 2, 3),
...@@ -153,7 +180,28 @@ static struct peri_clk_data hsic2_12m_data = { ...@@ -153,7 +180,28 @@ static struct peri_clk_data hsic2_12m_data = {
.trig = TRIGGER(0x0afc, 5), .trig = TRIGGER(0x0afc, 5),
}; };
/* Slave CCU clocks */ static struct ccu_data master_ccu_data = {
BCM281XX_CCU_COMMON(master, MASTER),
.kona_clks = {
[BCM281XX_MASTER_CCU_SDIO1] =
KONA_CLK(master, sdio1, peri),
[BCM281XX_MASTER_CCU_SDIO2] =
KONA_CLK(master, sdio2, peri),
[BCM281XX_MASTER_CCU_SDIO3] =
KONA_CLK(master, sdio3, peri),
[BCM281XX_MASTER_CCU_SDIO4] =
KONA_CLK(master, sdio4, peri),
[BCM281XX_MASTER_CCU_USB_IC] =
KONA_CLK(master, usb_ic, peri),
[BCM281XX_MASTER_CCU_HSIC2_48M] =
KONA_CLK(master, hsic2_48m, peri),
[BCM281XX_MASTER_CCU_HSIC2_12M] =
KONA_CLK(master, hsic2_12m, peri),
[BCM281XX_MASTER_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
},
};
/* Slave CCU */
static struct peri_clk_data uartb_data = { static struct peri_clk_data uartb_data = {
.gate = HW_SW_GATE(0x0400, 18, 2, 3), .gate = HW_SW_GATE(0x0400, 18, 2, 3),
...@@ -261,156 +309,67 @@ static struct peri_clk_data pwm_data = { ...@@ -261,156 +309,67 @@ static struct peri_clk_data pwm_data = {
.trig = TRIGGER(0x0afc, 15), .trig = TRIGGER(0x0afc, 15),
}; };
/* static struct ccu_data slave_ccu_data = {
* CCU setup routines BCM281XX_CCU_COMMON(slave, SLAVE),
* .kona_clks = {
* These are called from kona_dt_ccu_setup() to initialize the array [BCM281XX_SLAVE_CCU_UARTB] =
* of clocks provided by the CCU. Once allocated, the entries in KONA_CLK(slave, uartb, peri),
* the array are initialized by calling kona_clk_setup() with the [BCM281XX_SLAVE_CCU_UARTB2] =
* initialization data for each clock. They return 0 if successful KONA_CLK(slave, uartb2, peri),
* or an error code otherwise. [BCM281XX_SLAVE_CCU_UARTB3] =
*/ KONA_CLK(slave, uartb3, peri),
static int __init bcm281xx_root_ccu_clks_setup(struct ccu_data *ccu) [BCM281XX_SLAVE_CCU_UARTB4] =
{ KONA_CLK(slave, uartb4, peri),
struct clk **clks; [BCM281XX_SLAVE_CCU_SSP0] =
size_t count = BCM281XX_ROOT_CCU_CLOCK_COUNT; KONA_CLK(slave, ssp0, peri),
[BCM281XX_SLAVE_CCU_SSP2] =
clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); KONA_CLK(slave, ssp2, peri),
if (!clks) { [BCM281XX_SLAVE_CCU_BSC1] =
pr_err("%s: failed to allocate root clocks\n", __func__); KONA_CLK(slave, bsc1, peri),
return -ENOMEM; [BCM281XX_SLAVE_CCU_BSC2] =
} KONA_CLK(slave, bsc2, peri),
ccu->data.clks = clks; [BCM281XX_SLAVE_CCU_BSC3] =
ccu->data.clk_num = count; KONA_CLK(slave, bsc3, peri),
[BCM281XX_SLAVE_CCU_PWM] =
PERI_CLK_SETUP(clks, ccu, BCM281XX_ROOT_CCU_FRAC_1M, frac_1m); KONA_CLK(slave, pwm, peri),
[BCM281XX_SLAVE_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
return 0; },
} };
static int __init bcm281xx_aon_ccu_clks_setup(struct ccu_data *ccu)
{
struct clk **clks;
size_t count = BCM281XX_AON_CCU_CLOCK_COUNT;
clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
if (!clks) {
pr_err("%s: failed to allocate aon clocks\n", __func__);
return -ENOMEM;
}
ccu->data.clks = clks;
ccu->data.clk_num = count;
PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_HUB_TIMER, hub_timer);
PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC, pmu_bsc);
PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC_VAR, pmu_bsc_var);
return 0;
}
static int __init bcm281xx_hub_ccu_clks_setup(struct ccu_data *ccu)
{
struct clk **clks;
size_t count = BCM281XX_HUB_CCU_CLOCK_COUNT;
clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
if (!clks) {
pr_err("%s: failed to allocate hub clocks\n", __func__);
return -ENOMEM;
}
ccu->data.clks = clks;
ccu->data.clk_num = count;
PERI_CLK_SETUP(clks, ccu, BCM281XX_HUB_CCU_TMON_1M, tmon_1m);
return 0;
}
static int __init bcm281xx_master_ccu_clks_setup(struct ccu_data *ccu)
{
struct clk **clks;
size_t count = BCM281XX_MASTER_CCU_CLOCK_COUNT;
clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
if (!clks) {
pr_err("%s: failed to allocate master clocks\n", __func__);
return -ENOMEM;
}
ccu->data.clks = clks;
ccu->data.clk_num = count;
PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO1, sdio1);
PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO2, sdio2);
PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO3, sdio3);
PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO4, sdio4);
PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_USB_IC, usb_ic);
PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_48M, hsic2_48m);
PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_12M, hsic2_12m);
return 0;
}
static int __init bcm281xx_slave_ccu_clks_setup(struct ccu_data *ccu)
{
struct clk **clks;
size_t count = BCM281XX_SLAVE_CCU_CLOCK_COUNT;
clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
if (!clks) {
pr_err("%s: failed to allocate slave clocks\n", __func__);
return -ENOMEM;
}
ccu->data.clks = clks;
ccu->data.clk_num = count;
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB, uartb);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB2, uartb2);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB3, uartb3);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB4, uartb4);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP0, ssp0);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP2, ssp2);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC1, bsc1);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC2, bsc2);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC3, bsc3);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_PWM, pwm);
return 0;
}
/* Device tree match table callback functions */ /* Device tree match table callback functions */
static void __init kona_dt_root_ccu_setup(struct device_node *node) static void __init kona_dt_root_ccu_setup(struct device_node *node)
{ {
kona_dt_ccu_setup(node, bcm281xx_root_ccu_clks_setup); kona_dt_ccu_setup(&root_ccu_data, node);
} }
static void __init kona_dt_aon_ccu_setup(struct device_node *node) static void __init kona_dt_aon_ccu_setup(struct device_node *node)
{ {
kona_dt_ccu_setup(node, bcm281xx_aon_ccu_clks_setup); kona_dt_ccu_setup(&aon_ccu_data, node);
} }
static void __init kona_dt_hub_ccu_setup(struct device_node *node) static void __init kona_dt_hub_ccu_setup(struct device_node *node)
{ {
kona_dt_ccu_setup(node, bcm281xx_hub_ccu_clks_setup); kona_dt_ccu_setup(&hub_ccu_data, node);
} }
static void __init kona_dt_master_ccu_setup(struct device_node *node) static void __init kona_dt_master_ccu_setup(struct device_node *node)
{ {
kona_dt_ccu_setup(node, bcm281xx_master_ccu_clks_setup); kona_dt_ccu_setup(&master_ccu_data, node);
} }
static void __init kona_dt_slave_ccu_setup(struct device_node *node) static void __init kona_dt_slave_ccu_setup(struct device_node *node)
{ {
kona_dt_ccu_setup(node, bcm281xx_slave_ccu_clks_setup); kona_dt_ccu_setup(&slave_ccu_data, node);
} }
CLK_OF_DECLARE(bcm11351_root_ccu, BCM11351_DT_ROOT_CCU_COMPAT, CLK_OF_DECLARE(bcm281xx_root_ccu, BCM281XX_DT_ROOT_CCU_COMPAT,
kona_dt_root_ccu_setup); kona_dt_root_ccu_setup);
CLK_OF_DECLARE(bcm11351_aon_ccu, BCM11351_DT_AON_CCU_COMPAT, CLK_OF_DECLARE(bcm281xx_aon_ccu, BCM281XX_DT_AON_CCU_COMPAT,
kona_dt_aon_ccu_setup); kona_dt_aon_ccu_setup);
CLK_OF_DECLARE(bcm11351_hub_ccu, BCM11351_DT_HUB_CCU_COMPAT, CLK_OF_DECLARE(bcm281xx_hub_ccu, BCM281XX_DT_HUB_CCU_COMPAT,
kona_dt_hub_ccu_setup); kona_dt_hub_ccu_setup);
CLK_OF_DECLARE(bcm11351_master_ccu, BCM11351_DT_MASTER_CCU_COMPAT, CLK_OF_DECLARE(bcm281xx_master_ccu, BCM281XX_DT_MASTER_CCU_COMPAT,
kona_dt_master_ccu_setup); kona_dt_master_ccu_setup);
CLK_OF_DECLARE(bcm11351_slave_ccu, BCM11351_DT_SLAVE_CCU_COMPAT, CLK_OF_DECLARE(bcm281xx_slave_ccu, BCM281XX_DT_SLAVE_CCU_COMPAT,
kona_dt_slave_ccu_setup); kona_dt_slave_ccu_setup);
This diff is collapsed.
...@@ -16,6 +16,14 @@ ...@@ -16,6 +16,14 @@
#include <linux/delay.h> #include <linux/delay.h>
/*
* "Policies" affect the frequencies of bus clocks provided by a
* CCU. (I believe these polices are named "Deep Sleep", "Economy",
* "Normal", and "Turbo".) A lower policy number has lower power
* consumption, and policy 2 is the default.
*/
#define CCU_POLICY_COUNT 4
#define CCU_ACCESS_PASSWORD 0xA5A500 #define CCU_ACCESS_PASSWORD 0xA5A500
#define CLK_GATE_DELAY_LOOP 2000 #define CLK_GATE_DELAY_LOOP 2000
...@@ -207,7 +215,152 @@ __ccu_wait_bit(struct ccu_data *ccu, u32 reg_offset, u32 bit, bool want) ...@@ -207,7 +215,152 @@ __ccu_wait_bit(struct ccu_data *ccu, u32 reg_offset, u32 bit, bool want)
return true; return true;
udelay(1); udelay(1);
} }
pr_warn("%s: %s/0x%04x bit %u was never %s\n", __func__,
ccu->name, reg_offset, bit, want ? "set" : "clear");
return false;
}
/* Policy operations */
static bool __ccu_policy_engine_start(struct ccu_data *ccu, bool sync)
{
struct bcm_policy_ctl *control = &ccu->policy.control;
u32 offset;
u32 go_bit;
u32 mask;
bool ret;
/* If we don't need to control policy for this CCU, we're done. */
if (!policy_ctl_exists(control))
return true;
offset = control->offset;
go_bit = control->go_bit;
/* Ensure we're not busy before we start */
ret = __ccu_wait_bit(ccu, offset, go_bit, false);
if (!ret) {
pr_err("%s: ccu %s policy engine wouldn't go idle\n",
__func__, ccu->name);
return false;
}
/*
* If it's a synchronous request, we'll wait for the voltage
* and frequency of the active load to stabilize before
* returning. To do this we select the active load by
* setting the ATL bit.
*
* An asynchronous request instead ramps the voltage in the
* background, and when that process stabilizes, the target
* load is copied to the active load and the CCU frequency
* is switched. We do this by selecting the target load
* (ATL bit clear) and setting the request auto-copy (AC bit
* set).
*
* Note, we do NOT read-modify-write this register.
*/
mask = (u32)1 << go_bit;
if (sync)
mask |= 1 << control->atl_bit;
else
mask |= 1 << control->ac_bit;
__ccu_write(ccu, offset, mask);
/* Wait for indication that operation is complete. */
ret = __ccu_wait_bit(ccu, offset, go_bit, false);
if (!ret)
pr_err("%s: ccu %s policy engine never started\n",
__func__, ccu->name);
return ret;
}
static bool __ccu_policy_engine_stop(struct ccu_data *ccu)
{
struct bcm_lvm_en *enable = &ccu->policy.enable;
u32 offset;
u32 enable_bit;
bool ret;
/* If we don't need to control policy for this CCU, we're done. */
if (!policy_lvm_en_exists(enable))
return true;
/* Ensure we're not busy before we start */
offset = enable->offset;
enable_bit = enable->bit;
ret = __ccu_wait_bit(ccu, offset, enable_bit, false);
if (!ret) {
pr_err("%s: ccu %s policy engine already stopped\n",
__func__, ccu->name);
return false;
}
/* Now set the bit to stop the engine (NO read-modify-write) */
__ccu_write(ccu, offset, (u32)1 << enable_bit);
/* Wait for indication that it has stopped. */
ret = __ccu_wait_bit(ccu, offset, enable_bit, false);
if (!ret)
pr_err("%s: ccu %s policy engine never stopped\n",
__func__, ccu->name);
return ret;
}
/*
* A CCU has four operating conditions ("policies"), and some clocks
* can be disabled or enabled based on which policy is currently in
* effect. Such clocks have a bit in a "policy mask" register for
* each policy indicating whether the clock is enabled for that
* policy or not. The bit position for a clock is the same for all
* four registers, and the 32-bit registers are at consecutive
* addresses.
*/
static bool policy_init(struct ccu_data *ccu, struct bcm_clk_policy *policy)
{
u32 offset;
u32 mask;
int i;
bool ret;
if (!policy_exists(policy))
return true;
/*
* We need to stop the CCU policy engine to allow update
* of our policy bits.
*/
if (!__ccu_policy_engine_stop(ccu)) {
pr_err("%s: unable to stop CCU %s policy engine\n",
__func__, ccu->name);
return false; return false;
}
/*
* For now, if a clock defines its policy bit we just mark
* it "enabled" for all four policies.
*/
offset = policy->offset;
mask = (u32)1 << policy->bit;
for (i = 0; i < CCU_POLICY_COUNT; i++) {
u32 reg_val;
reg_val = __ccu_read(ccu, offset);
reg_val |= mask;
__ccu_write(ccu, offset, reg_val);
offset += sizeof(u32);
}
/* We're done updating; fire up the policy engine again. */
ret = __ccu_policy_engine_start(ccu, true);
if (!ret)
pr_err("%s: unable to restart CCU %s policy engine\n",
__func__, ccu->name);
return ret;
} }
/* Gate operations */ /* Gate operations */
...@@ -374,6 +527,35 @@ static int clk_gate(struct ccu_data *ccu, const char *name, ...@@ -374,6 +527,35 @@ static int clk_gate(struct ccu_data *ccu, const char *name,
return -EIO; return -EIO;
} }
/* Hysteresis operations */
/*
* If a clock gate requires a turn-off delay it will have
* "hysteresis" register bits defined. The first, if set, enables
* the delay; and if enabled, the second bit determines whether the
* delay is "low" or "high" (1 means high). For now, if it's
* defined for a clock, we set it.
*/
static bool hyst_init(struct ccu_data *ccu, struct bcm_clk_hyst *hyst)
{
u32 offset;
u32 reg_val;
u32 mask;
if (!hyst_exists(hyst))
return true;
offset = hyst->offset;
mask = (u32)1 << hyst->en_bit;
mask |= (u32)1 << hyst->val_bit;
reg_val = __ccu_read(ccu, offset);
reg_val |= mask;
__ccu_write(ccu, offset, reg_val);
return true;
}
/* Trigger operations */ /* Trigger operations */
/* /*
...@@ -806,7 +988,7 @@ static int kona_peri_clk_enable(struct clk_hw *hw) ...@@ -806,7 +988,7 @@ static int kona_peri_clk_enable(struct clk_hw *hw)
struct kona_clk *bcm_clk = to_kona_clk(hw); struct kona_clk *bcm_clk = to_kona_clk(hw);
struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate; struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate;
return clk_gate(bcm_clk->ccu, bcm_clk->name, gate, true); return clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, true);
} }
static void kona_peri_clk_disable(struct clk_hw *hw) static void kona_peri_clk_disable(struct clk_hw *hw)
...@@ -814,7 +996,7 @@ static void kona_peri_clk_disable(struct clk_hw *hw) ...@@ -814,7 +996,7 @@ static void kona_peri_clk_disable(struct clk_hw *hw)
struct kona_clk *bcm_clk = to_kona_clk(hw); struct kona_clk *bcm_clk = to_kona_clk(hw);
struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate; struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate;
(void)clk_gate(bcm_clk->ccu, bcm_clk->name, gate, false); (void)clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, false);
} }
static int kona_peri_clk_is_enabled(struct clk_hw *hw) static int kona_peri_clk_is_enabled(struct clk_hw *hw)
...@@ -872,12 +1054,13 @@ static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) ...@@ -872,12 +1054,13 @@ static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index)
ret = selector_write(bcm_clk->ccu, &data->gate, sel, trig, index); ret = selector_write(bcm_clk->ccu, &data->gate, sel, trig, index);
if (ret == -ENXIO) { if (ret == -ENXIO) {
pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name); pr_err("%s: gating failure for %s\n", __func__,
bcm_clk->init_data.name);
ret = -EIO; /* Don't proliferate weird errors */ ret = -EIO; /* Don't proliferate weird errors */
} else if (ret == -EIO) { } else if (ret == -EIO) {
pr_err("%s: %strigger failed for %s\n", __func__, pr_err("%s: %strigger failed for %s\n", __func__,
trig == &data->pre_trig ? "pre-" : "", trig == &data->pre_trig ? "pre-" : "",
bcm_clk->name); bcm_clk->init_data.name);
} }
return ret; return ret;
...@@ -936,10 +1119,12 @@ static int kona_peri_clk_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -936,10 +1119,12 @@ static int kona_peri_clk_set_rate(struct clk_hw *hw, unsigned long rate,
ret = divider_write(bcm_clk->ccu, &data->gate, &data->div, ret = divider_write(bcm_clk->ccu, &data->gate, &data->div,
&data->trig, scaled_div); &data->trig, scaled_div);
if (ret == -ENXIO) { if (ret == -ENXIO) {
pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name); pr_err("%s: gating failure for %s\n", __func__,
bcm_clk->init_data.name);
ret = -EIO; /* Don't proliferate weird errors */ ret = -EIO; /* Don't proliferate weird errors */
} else if (ret == -EIO) { } else if (ret == -EIO) {
pr_err("%s: trigger failed for %s\n", __func__, bcm_clk->name); pr_err("%s: trigger failed for %s\n", __func__,
bcm_clk->init_data.name);
} }
return ret; return ret;
...@@ -961,15 +1146,24 @@ static bool __peri_clk_init(struct kona_clk *bcm_clk) ...@@ -961,15 +1146,24 @@ static bool __peri_clk_init(struct kona_clk *bcm_clk)
{ {
struct ccu_data *ccu = bcm_clk->ccu; struct ccu_data *ccu = bcm_clk->ccu;
struct peri_clk_data *peri = bcm_clk->u.peri; struct peri_clk_data *peri = bcm_clk->u.peri;
const char *name = bcm_clk->name; const char *name = bcm_clk->init_data.name;
struct bcm_clk_trig *trig; struct bcm_clk_trig *trig;
BUG_ON(bcm_clk->type != bcm_clk_peri); BUG_ON(bcm_clk->type != bcm_clk_peri);
if (!policy_init(ccu, &peri->policy)) {
pr_err("%s: error initializing policy for %s\n",
__func__, name);
return false;
}
if (!gate_init(ccu, &peri->gate)) { if (!gate_init(ccu, &peri->gate)) {
pr_err("%s: error initializing gate for %s\n", __func__, name); pr_err("%s: error initializing gate for %s\n", __func__, name);
return false; return false;
} }
if (!hyst_init(ccu, &peri->hyst)) {
pr_err("%s: error initializing hyst for %s\n", __func__, name);
return false;
}
if (!div_init(ccu, &peri->gate, &peri->div, &peri->trig)) { if (!div_init(ccu, &peri->gate, &peri->div, &peri->trig)) {
pr_err("%s: error initializing divider for %s\n", __func__, pr_err("%s: error initializing divider for %s\n", __func__,
name); name);
...@@ -1014,13 +1208,13 @@ bool __init kona_ccu_init(struct ccu_data *ccu) ...@@ -1014,13 +1208,13 @@ bool __init kona_ccu_init(struct ccu_data *ccu)
{ {
unsigned long flags; unsigned long flags;
unsigned int which; unsigned int which;
struct clk **clks = ccu->data.clks; struct clk **clks = ccu->clk_data.clks;
bool success = true; bool success = true;
flags = ccu_lock(ccu); flags = ccu_lock(ccu);
__ccu_write_enable(ccu); __ccu_write_enable(ccu);
for (which = 0; which < ccu->data.clk_num; which++) { for (which = 0; which < ccu->clk_data.clk_num; which++) {
struct kona_clk *bcm_clk; struct kona_clk *bcm_clk;
if (!clks[which]) if (!clks[which])
......
...@@ -43,8 +43,14 @@ ...@@ -43,8 +43,14 @@
#define FLAG_FLIP(obj, type, flag) ((obj)->flags ^= FLAG(type, flag)) #define FLAG_FLIP(obj, type, flag) ((obj)->flags ^= FLAG(type, flag))
#define FLAG_TEST(obj, type, flag) (!!((obj)->flags & FLAG(type, flag))) #define FLAG_TEST(obj, type, flag) (!!((obj)->flags & FLAG(type, flag)))
/* CCU field state tests */
#define ccu_policy_exists(ccu_policy) ((ccu_policy)->enable.offset != 0)
/* Clock field state tests */ /* Clock field state tests */
#define policy_exists(policy) ((policy)->offset != 0)
#define gate_exists(gate) FLAG_TEST(gate, GATE, EXISTS) #define gate_exists(gate) FLAG_TEST(gate, GATE, EXISTS)
#define gate_is_enabled(gate) FLAG_TEST(gate, GATE, ENABLED) #define gate_is_enabled(gate) FLAG_TEST(gate, GATE, ENABLED)
#define gate_is_hw_controllable(gate) FLAG_TEST(gate, GATE, HW) #define gate_is_hw_controllable(gate) FLAG_TEST(gate, GATE, HW)
...@@ -54,6 +60,8 @@ ...@@ -54,6 +60,8 @@
#define gate_flip_enabled(gate) FLAG_FLIP(gate, GATE, ENABLED) #define gate_flip_enabled(gate) FLAG_FLIP(gate, GATE, ENABLED)
#define hyst_exists(hyst) ((hyst)->offset != 0)
#define divider_exists(div) FLAG_TEST(div, DIV, EXISTS) #define divider_exists(div) FLAG_TEST(div, DIV, EXISTS)
#define divider_is_fixed(div) FLAG_TEST(div, DIV, FIXED) #define divider_is_fixed(div) FLAG_TEST(div, DIV, FIXED)
#define divider_has_fraction(div) (!divider_is_fixed(div) && \ #define divider_has_fraction(div) (!divider_is_fixed(div) && \
...@@ -62,6 +70,9 @@ ...@@ -62,6 +70,9 @@
#define selector_exists(sel) ((sel)->width != 0) #define selector_exists(sel) ((sel)->width != 0)
#define trigger_exists(trig) FLAG_TEST(trig, TRIG, EXISTS) #define trigger_exists(trig) FLAG_TEST(trig, TRIG, EXISTS)
#define policy_lvm_en_exists(enable) ((enable)->offset != 0)
#define policy_ctl_exists(control) ((control)->offset != 0)
/* Clock type, used to tell common block what it's part of */ /* Clock type, used to tell common block what it's part of */
enum bcm_clk_type { enum bcm_clk_type {
bcm_clk_none, /* undefined clock type */ bcm_clk_none, /* undefined clock type */
...@@ -71,25 +82,26 @@ enum bcm_clk_type { ...@@ -71,25 +82,26 @@ enum bcm_clk_type {
}; };
/* /*
* Each CCU defines a mapped area of memory containing registers * CCU policy control for clocks. Clocks can be enabled or disabled
* used to manage clocks implemented by the CCU. Access to memory * based on the CCU policy in effect. One bit in each policy mask
* within the CCU's space is serialized by a spinlock. Before any * register (one per CCU policy) represents whether the clock is
* (other) address can be written, a special access "password" value * enabled when that policy is effect or not. The CCU policy engine
* must be written to its WR_ACCESS register (located at the base * must be stopped to update these bits, and must be restarted again
* address of the range). We keep track of the name of each CCU as * afterward.
* it is set up, and maintain them in a list.
*/ */
struct ccu_data { struct bcm_clk_policy {
void __iomem *base; /* base of mapped address space */ u32 offset; /* first policy mask register offset */
spinlock_t lock; /* serialization lock */ u32 bit; /* bit used in all mask registers */
bool write_enabled; /* write access is currently enabled */
struct list_head links; /* for ccu_list */
struct device_node *node;
struct clk_onecell_data data;
const char *name;
u32 range; /* byte range of address space */
}; };
/* Policy initialization macro */
#define POLICY(_offset, _bit) \
{ \
.offset = (_offset), \
.bit = (_bit), \
}
/* /*
* Gating control and status is managed by a 32-bit gate register. * Gating control and status is managed by a 32-bit gate register.
* *
...@@ -195,6 +207,22 @@ struct bcm_clk_gate { ...@@ -195,6 +207,22 @@ struct bcm_clk_gate {
.flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS), \ .flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS), \
} }
/* Gate hysteresis for clocks */
struct bcm_clk_hyst {
u32 offset; /* hyst register offset (normally CLKGATE) */
u32 en_bit; /* bit used to enable hysteresis */
u32 val_bit; /* if enabled: 0 = low delay; 1 = high delay */
};
/* Hysteresis initialization macro */
#define HYST(_offset, _en_bit, _val_bit) \
{ \
.offset = (_offset), \
.en_bit = (_en_bit), \
.val_bit = (_val_bit), \
}
/* /*
* Each clock can have zero, one, or two dividers which change the * Each clock can have zero, one, or two dividers which change the
* output rate of the clock. Each divider can be either fixed or * output rate of the clock. Each divider can be either fixed or
...@@ -360,7 +388,9 @@ struct bcm_clk_trig { ...@@ -360,7 +388,9 @@ struct bcm_clk_trig {
} }
struct peri_clk_data { struct peri_clk_data {
struct bcm_clk_policy policy;
struct bcm_clk_gate gate; struct bcm_clk_gate gate;
struct bcm_clk_hyst hyst;
struct bcm_clk_trig pre_trig; struct bcm_clk_trig pre_trig;
struct bcm_clk_div pre_div; struct bcm_clk_div pre_div;
struct bcm_clk_trig trig; struct bcm_clk_trig trig;
...@@ -373,8 +403,7 @@ struct peri_clk_data { ...@@ -373,8 +403,7 @@ struct peri_clk_data {
struct kona_clk { struct kona_clk {
struct clk_hw hw; struct clk_hw hw;
struct clk_init_data init_data; struct clk_init_data init_data; /* includes name of this clock */
const char *name; /* name of this clock */
struct ccu_data *ccu; /* ccu this clock is associated with */ struct ccu_data *ccu; /* ccu this clock is associated with */
enum bcm_clk_type type; enum bcm_clk_type type;
union { union {
...@@ -385,14 +414,92 @@ struct kona_clk { ...@@ -385,14 +414,92 @@ struct kona_clk {
#define to_kona_clk(_hw) \ #define to_kona_clk(_hw) \
container_of(_hw, struct kona_clk, hw) container_of(_hw, struct kona_clk, hw)
/* Exported globals */ /* Initialization macro for an entry in a CCU's kona_clks[] array. */
#define KONA_CLK(_ccu_name, _clk_name, _type) \
{ \
.init_data = { \
.name = #_clk_name, \
.ops = &kona_ ## _type ## _clk_ops, \
}, \
.ccu = &_ccu_name ## _ccu_data, \
.type = bcm_clk_ ## _type, \
.u.data = &_clk_name ## _data, \
}
#define LAST_KONA_CLK { .type = bcm_clk_none }
extern struct clk_ops kona_peri_clk_ops; /*
* CCU policy control. To enable software update of the policy
* tables the CCU policy engine must be stopped by setting the
* software update enable bit (LVM_EN). After an update the engine
* is restarted using the GO bit and either the GO_ATL or GO_AC bit.
*/
struct bcm_lvm_en {
u32 offset; /* LVM_EN register offset */
u32 bit; /* POLICY_CONFIG_EN bit in register */
};
/* Policy enable initialization macro */
#define CCU_LVM_EN(_offset, _bit) \
{ \
.offset = (_offset), \
.bit = (_bit), \
}
struct bcm_policy_ctl {
u32 offset; /* POLICY_CTL register offset */
u32 go_bit;
u32 atl_bit; /* GO, GO_ATL, and GO_AC bits */
u32 ac_bit;
};
/* Policy control initialization macro */
#define CCU_POLICY_CTL(_offset, _go_bit, _ac_bit, _atl_bit) \
{ \
.offset = (_offset), \
.go_bit = (_go_bit), \
.ac_bit = (_ac_bit), \
.atl_bit = (_atl_bit), \
}
struct ccu_policy {
struct bcm_lvm_en enable;
struct bcm_policy_ctl control;
};
/*
* Each CCU defines a mapped area of memory containing registers
* used to manage clocks implemented by the CCU. Access to memory
* within the CCU's space is serialized by a spinlock. Before any
* (other) address can be written, a special access "password" value
* must be written to its WR_ACCESS register (located at the base
* address of the range). We keep track of the name of each CCU as
* it is set up, and maintain them in a list.
*/
struct ccu_data {
void __iomem *base; /* base of mapped address space */
spinlock_t lock; /* serialization lock */
bool write_enabled; /* write access is currently enabled */
struct ccu_policy policy;
struct list_head links; /* for ccu_list */
struct device_node *node;
struct clk_onecell_data clk_data;
const char *name;
u32 range; /* byte range of address space */
struct kona_clk kona_clks[]; /* must be last */
};
/* Help functions */ /* Initialization for common fields in a Kona ccu_data structure */
#define KONA_CCU_COMMON(_prefix, _name, _ccuname) \
.name = #_name "_ccu", \
.lock = __SPIN_LOCK_UNLOCKED(_name ## _ccu_data.lock), \
.links = LIST_HEAD_INIT(_name ## _ccu_data.links), \
.clk_data = { \
.clk_num = _prefix ## _ ## _ccuname ## _CCU_CLOCK_COUNT, \
}
/* Exported globals */
#define PERI_CLK_SETUP(clks, ccu, id, name) \ extern struct clk_ops kona_peri_clk_ops;
clks[id] = kona_clk_setup(ccu, #name, bcm_clk_peri, &name ## _data)
/* Externally visible functions */ /* Externally visible functions */
...@@ -401,10 +508,9 @@ extern u64 scaled_div_max(struct bcm_clk_div *div); ...@@ -401,10 +508,9 @@ extern u64 scaled_div_max(struct bcm_clk_div *div);
extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value, extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value,
u32 billionths); u32 billionths);
extern struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name, extern struct clk *kona_clk_setup(struct kona_clk *bcm_clk);
enum bcm_clk_type type, void *data); extern void __init kona_dt_ccu_setup(struct ccu_data *ccu,
extern void __init kona_dt_ccu_setup(struct device_node *node, struct device_node *node);
int (*ccu_clks_setup)(struct ccu_data *));
extern bool __init kona_ccu_init(struct ccu_data *ccu); extern bool __init kona_ccu_init(struct ccu_data *ccu);
#endif /* _CLK_KONA_H */ #endif /* _CLK_KONA_H */
This diff is collapsed.
...@@ -43,6 +43,17 @@ static unsigned int _get_table_maxdiv(const struct clk_div_table *table) ...@@ -43,6 +43,17 @@ static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
return maxdiv; return maxdiv;
} }
static unsigned int _get_table_mindiv(const struct clk_div_table *table)
{
unsigned int mindiv = UINT_MAX;
const struct clk_div_table *clkt;
for (clkt = table; clkt->div; clkt++)
if (clkt->div < mindiv)
mindiv = clkt->div;
return mindiv;
}
static unsigned int _get_maxdiv(struct clk_divider *divider) static unsigned int _get_maxdiv(struct clk_divider *divider)
{ {
if (divider->flags & CLK_DIVIDER_ONE_BASED) if (divider->flags & CLK_DIVIDER_ONE_BASED)
...@@ -162,6 +173,24 @@ static int _round_up_table(const struct clk_div_table *table, int div) ...@@ -162,6 +173,24 @@ static int _round_up_table(const struct clk_div_table *table, int div)
return up; return up;
} }
static int _round_down_table(const struct clk_div_table *table, int div)
{
const struct clk_div_table *clkt;
int down = _get_table_mindiv(table);
for (clkt = table; clkt->div; clkt++) {
if (clkt->div == div)
return clkt->div;
else if (clkt->div > div)
continue;
if ((div - clkt->div) < (div - down))
down = clkt->div;
}
return down;
}
static int _div_round_up(struct clk_divider *divider, static int _div_round_up(struct clk_divider *divider,
unsigned long parent_rate, unsigned long rate) unsigned long parent_rate, unsigned long rate)
{ {
...@@ -175,6 +204,54 @@ static int _div_round_up(struct clk_divider *divider, ...@@ -175,6 +204,54 @@ static int _div_round_up(struct clk_divider *divider,
return div; return div;
} }
static int _div_round_closest(struct clk_divider *divider,
unsigned long parent_rate, unsigned long rate)
{
int up, down, div;
up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) {
up = __roundup_pow_of_two(div);
down = __rounddown_pow_of_two(div);
} else if (divider->table) {
up = _round_up_table(divider->table, div);
down = _round_down_table(divider->table, div);
}
return (up - div) <= (div - down) ? up : down;
}
static int _div_round(struct clk_divider *divider, unsigned long parent_rate,
unsigned long rate)
{
if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
return _div_round_closest(divider, parent_rate, rate);
return _div_round_up(divider, parent_rate, rate);
}
static bool _is_best_div(struct clk_divider *divider,
int rate, int now, int best)
{
if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
return abs(rate - now) < abs(rate - best);
return now <= rate && now > best;
}
static int _next_div(struct clk_divider *divider, int div)
{
div++;
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
return __roundup_pow_of_two(div);
if (divider->table)
return _round_up_table(divider->table, div);
return div;
}
static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate) unsigned long *best_parent_rate)
{ {
...@@ -190,7 +267,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, ...@@ -190,7 +267,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
parent_rate = *best_parent_rate; parent_rate = *best_parent_rate;
bestdiv = _div_round_up(divider, parent_rate, rate); bestdiv = _div_round(divider, parent_rate, rate);
bestdiv = bestdiv == 0 ? 1 : bestdiv; bestdiv = bestdiv == 0 ? 1 : bestdiv;
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
return bestdiv; return bestdiv;
...@@ -202,7 +279,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, ...@@ -202,7 +279,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
*/ */
maxdiv = min(ULONG_MAX / rate, maxdiv); maxdiv = min(ULONG_MAX / rate, maxdiv);
for (i = 1; i <= maxdiv; i++) { for (i = 1; i <= maxdiv; i = _next_div(divider, i)) {
if (!_is_valid_div(divider, i)) if (!_is_valid_div(divider, i))
continue; continue;
if (rate * i == parent_rate_saved) { if (rate * i == parent_rate_saved) {
...@@ -217,7 +294,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, ...@@ -217,7 +294,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
MULT_ROUND_UP(rate, i)); MULT_ROUND_UP(rate, i));
now = DIV_ROUND_UP(parent_rate, i); now = DIV_ROUND_UP(parent_rate, i);
if (now <= rate && now > best) { if (_is_best_div(divider, rate, now, best)) {
bestdiv = i; bestdiv = i;
best = now; best = now;
*best_parent_rate = parent_rate; *best_parent_rate = parent_rate;
...@@ -284,6 +361,11 @@ const struct clk_ops clk_divider_ops = { ...@@ -284,6 +361,11 @@ const struct clk_ops clk_divider_ops = {
}; };
EXPORT_SYMBOL_GPL(clk_divider_ops); EXPORT_SYMBOL_GPL(clk_divider_ops);
const struct clk_ops clk_divider_ro_ops = {
.recalc_rate = clk_divider_recalc_rate,
};
EXPORT_SYMBOL_GPL(clk_divider_ro_ops);
static struct clk *_register_divider(struct device *dev, const char *name, static struct clk *_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags, const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width, void __iomem *reg, u8 shift, u8 width,
...@@ -309,6 +391,9 @@ static struct clk *_register_divider(struct device *dev, const char *name, ...@@ -309,6 +391,9 @@ static struct clk *_register_divider(struct device *dev, const char *name,
} }
init.name = name; init.name = name;
if (clk_divider_flags & CLK_DIVIDER_READ_ONLY)
init.ops = &clk_divider_ro_ops;
else
init.ops = &clk_divider_ops; init.ops = &clk_divider_ops;
init.flags = flags | CLK_IS_BASIC; init.flags = flags | CLK_IS_BASIC;
init.parent_names = (parent_name ? &parent_name: NULL); init.parent_names = (parent_name ? &parent_name: NULL);
......
...@@ -526,6 +526,6 @@ static struct i2c_driver si570_driver = { ...@@ -526,6 +526,6 @@ static struct i2c_driver si570_driver = {
module_i2c_driver(si570_driver); module_i2c_driver(si570_driver);
MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>"); MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com"); MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com>");
MODULE_DESCRIPTION("Si570 driver"); MODULE_DESCRIPTION("Si570 driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -106,12 +106,11 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level) ...@@ -106,12 +106,11 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
if (!c) if (!c)
return; return;
seq_printf(s, "%*s%-*s %-11d %-12d %-10lu %-11lu", seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu\n",
level * 3 + 1, "", level * 3 + 1, "",
30 - level * 3, c->name, 30 - level * 3, c->name,
c->enable_count, c->prepare_count, clk_get_rate(c), c->enable_count, c->prepare_count, clk_get_rate(c),
clk_get_accuracy(c)); clk_get_accuracy(c));
seq_printf(s, "\n");
} }
static void clk_summary_show_subtree(struct seq_file *s, struct clk *c, static void clk_summary_show_subtree(struct seq_file *s, struct clk *c,
...@@ -132,8 +131,8 @@ static int clk_summary_show(struct seq_file *s, void *data) ...@@ -132,8 +131,8 @@ static int clk_summary_show(struct seq_file *s, void *data)
{ {
struct clk *c; struct clk *c;
seq_printf(s, " clock enable_cnt prepare_cnt rate accuracy\n"); seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy\n");
seq_printf(s, "---------------------------------------------------------------------------------\n"); seq_puts(s, "--------------------------------------------------------------------------------\n");
clk_prepare_lock(); clk_prepare_lock();
...@@ -822,6 +821,9 @@ void __clk_unprepare(struct clk *clk) ...@@ -822,6 +821,9 @@ void __clk_unprepare(struct clk *clk)
*/ */
void clk_unprepare(struct clk *clk) void clk_unprepare(struct clk *clk)
{ {
if (IS_ERR_OR_NULL(clk))
return;
clk_prepare_lock(); clk_prepare_lock();
__clk_unprepare(clk); __clk_unprepare(clk);
clk_prepare_unlock(); clk_prepare_unlock();
...@@ -883,9 +885,6 @@ static void __clk_disable(struct clk *clk) ...@@ -883,9 +885,6 @@ static void __clk_disable(struct clk *clk)
if (!clk) if (!clk)
return; return;
if (WARN_ON(IS_ERR(clk)))
return;
if (WARN_ON(clk->enable_count == 0)) if (WARN_ON(clk->enable_count == 0))
return; return;
...@@ -914,6 +913,9 @@ void clk_disable(struct clk *clk) ...@@ -914,6 +913,9 @@ void clk_disable(struct clk *clk)
{ {
unsigned long flags; unsigned long flags;
if (IS_ERR_OR_NULL(clk))
return;
flags = clk_enable_lock(); flags = clk_enable_lock();
__clk_disable(clk); __clk_disable(clk);
clk_enable_unlock(flags); clk_enable_unlock(flags);
...@@ -1115,6 +1117,13 @@ long clk_get_accuracy(struct clk *clk) ...@@ -1115,6 +1117,13 @@ long clk_get_accuracy(struct clk *clk)
} }
EXPORT_SYMBOL_GPL(clk_get_accuracy); EXPORT_SYMBOL_GPL(clk_get_accuracy);
static unsigned long clk_recalc(struct clk *clk, unsigned long parent_rate)
{
if (clk->ops->recalc_rate)
return clk->ops->recalc_rate(clk->hw, parent_rate);
return parent_rate;
}
/** /**
* __clk_recalc_rates * __clk_recalc_rates
* @clk: first clk in the subtree * @clk: first clk in the subtree
...@@ -1140,10 +1149,7 @@ static void __clk_recalc_rates(struct clk *clk, unsigned long msg) ...@@ -1140,10 +1149,7 @@ static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
if (clk->parent) if (clk->parent)
parent_rate = clk->parent->rate; parent_rate = clk->parent->rate;
if (clk->ops->recalc_rate) clk->rate = clk_recalc(clk, parent_rate);
clk->rate = clk->ops->recalc_rate(clk->hw, parent_rate);
else
clk->rate = parent_rate;
/* /*
* ignore NOTIFY_STOP and NOTIFY_BAD return values for POST_RATE_CHANGE * ignore NOTIFY_STOP and NOTIFY_BAD return values for POST_RATE_CHANGE
...@@ -1334,10 +1340,7 @@ static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate) ...@@ -1334,10 +1340,7 @@ static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate)
unsigned long new_rate; unsigned long new_rate;
int ret = NOTIFY_DONE; int ret = NOTIFY_DONE;
if (clk->ops->recalc_rate) new_rate = clk_recalc(clk, parent_rate);
new_rate = clk->ops->recalc_rate(clk->hw, parent_rate);
else
new_rate = parent_rate;
/* abort rate change if a driver returns NOTIFY_BAD or NOTIFY_STOP */ /* abort rate change if a driver returns NOTIFY_BAD or NOTIFY_STOP */
if (clk->notifier_count) if (clk->notifier_count)
...@@ -1373,10 +1376,7 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate, ...@@ -1373,10 +1376,7 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
new_parent->new_child = clk; new_parent->new_child = clk;
hlist_for_each_entry(child, &clk->children, child_node) { hlist_for_each_entry(child, &clk->children, child_node) {
if (child->ops->recalc_rate) child->new_rate = clk_recalc(child, new_rate);
child->new_rate = child->ops->recalc_rate(child->hw, new_rate);
else
child->new_rate = new_rate;
clk_calc_subtree(child, child->new_rate, NULL, 0); clk_calc_subtree(child, child->new_rate, NULL, 0);
} }
} }
...@@ -1524,10 +1524,7 @@ static void clk_change_rate(struct clk *clk) ...@@ -1524,10 +1524,7 @@ static void clk_change_rate(struct clk *clk)
if (!skip_set_rate && clk->ops->set_rate) if (!skip_set_rate && clk->ops->set_rate)
clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate); clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate);
if (clk->ops->recalc_rate) clk->rate = clk_recalc(clk, best_parent_rate);
clk->rate = clk->ops->recalc_rate(clk->hw, best_parent_rate);
else
clk->rate = best_parent_rate;
if (clk->notifier_count && old_rate != clk->rate) if (clk->notifier_count && old_rate != clk->rate)
__clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate); __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
...@@ -1716,9 +1713,6 @@ int clk_set_parent(struct clk *clk, struct clk *parent) ...@@ -1716,9 +1713,6 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
if (!clk) if (!clk)
return 0; return 0;
if (!clk->ops)
return -EINVAL;
/* verify ops for for multi-parent clks */ /* verify ops for for multi-parent clks */
if ((clk->num_parents > 1) && (!clk->ops->set_parent)) if ((clk->num_parents > 1) && (!clk->ops->set_parent))
return -ENOSYS; return -ENOSYS;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
*/ */
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec);
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec); struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec);
void of_clk_lock(void); void of_clk_lock(void);
void of_clk_unlock(void); void of_clk_unlock(void);
......
...@@ -27,6 +27,32 @@ static LIST_HEAD(clocks); ...@@ -27,6 +27,32 @@ static LIST_HEAD(clocks);
static DEFINE_MUTEX(clocks_mutex); static DEFINE_MUTEX(clocks_mutex);
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
/**
* of_clk_get_by_clkspec() - Lookup a clock form a clock provider
* @clkspec: pointer to a clock specifier data structure
*
* This function looks up a struct clk from the registered list of clock
* providers, an input is a clock specifier data structure as returned
* from the of_parse_phandle_with_args() function call.
*/
struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec)
{
struct clk *clk;
if (!clkspec)
return ERR_PTR(-EINVAL);
of_clk_lock();
clk = __of_clk_get_from_provider(clkspec);
if (!IS_ERR(clk) && !__clk_get(clk))
clk = ERR_PTR(-ENOENT);
of_clk_unlock();
return clk;
}
struct clk *of_clk_get(struct device_node *np, int index) struct clk *of_clk_get(struct device_node *np, int index)
{ {
struct of_phandle_args clkspec; struct of_phandle_args clkspec;
...@@ -41,13 +67,7 @@ struct clk *of_clk_get(struct device_node *np, int index) ...@@ -41,13 +67,7 @@ struct clk *of_clk_get(struct device_node *np, int index)
if (rc) if (rc)
return ERR_PTR(rc); return ERR_PTR(rc);
of_clk_lock(); clk = of_clk_get_by_clkspec(&clkspec);
clk = __of_clk_get_from_provider(&clkspec);
if (!IS_ERR(clk) && !__clk_get(clk))
clk = ERR_PTR(-ENOENT);
of_clk_unlock();
of_node_put(clkspec.np); of_node_put(clkspec.np);
return clk; return clk;
} }
......
...@@ -6,3 +6,4 @@ obj-y += clk.o clkgate-separated.o ...@@ -6,3 +6,4 @@ obj-y += clk.o clkgate-separated.o
obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o
obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
/*
* Copyright (c) 2014 Linaro Ltd.
* Copyright (c) 2014 Hisilicon Limited.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*/
#include <linux/of_address.h>
#include <dt-bindings/clock/hix5hd2-clock.h>
#include "clk.h"
static struct hisi_fixed_rate_clock hix5hd2_fixed_rate_clks[] __initdata = {
{ HIX5HD2_FIXED_1200M, "1200m", NULL, CLK_IS_ROOT, 1200000000, },
{ HIX5HD2_FIXED_400M, "400m", NULL, CLK_IS_ROOT, 400000000, },
{ HIX5HD2_FIXED_48M, "48m", NULL, CLK_IS_ROOT, 48000000, },
{ HIX5HD2_FIXED_24M, "24m", NULL, CLK_IS_ROOT, 24000000, },
{ HIX5HD2_FIXED_600M, "600m", NULL, CLK_IS_ROOT, 600000000, },
{ HIX5HD2_FIXED_300M, "300m", NULL, CLK_IS_ROOT, 300000000, },
{ HIX5HD2_FIXED_75M, "75m", NULL, CLK_IS_ROOT, 75000000, },
{ HIX5HD2_FIXED_200M, "200m", NULL, CLK_IS_ROOT, 200000000, },
{ HIX5HD2_FIXED_100M, "100m", NULL, CLK_IS_ROOT, 100000000, },
{ HIX5HD2_FIXED_40M, "40m", NULL, CLK_IS_ROOT, 40000000, },
{ HIX5HD2_FIXED_150M, "150m", NULL, CLK_IS_ROOT, 150000000, },
{ HIX5HD2_FIXED_1728M, "1728m", NULL, CLK_IS_ROOT, 1728000000, },
{ HIX5HD2_FIXED_28P8M, "28p8m", NULL, CLK_IS_ROOT, 28000000, },
{ HIX5HD2_FIXED_432M, "432m", NULL, CLK_IS_ROOT, 432000000, },
{ HIX5HD2_FIXED_345P6M, "345p6m", NULL, CLK_IS_ROOT, 345000000, },
{ HIX5HD2_FIXED_288M, "288m", NULL, CLK_IS_ROOT, 288000000, },
{ HIX5HD2_FIXED_60M, "60m", NULL, CLK_IS_ROOT, 60000000, },
{ HIX5HD2_FIXED_750M, "750m", NULL, CLK_IS_ROOT, 750000000, },
{ HIX5HD2_FIXED_500M, "500m", NULL, CLK_IS_ROOT, 500000000, },
{ HIX5HD2_FIXED_54M, "54m", NULL, CLK_IS_ROOT, 54000000, },
{ HIX5HD2_FIXED_27M, "27m", NULL, CLK_IS_ROOT, 27000000, },
{ HIX5HD2_FIXED_1500M, "1500m", NULL, CLK_IS_ROOT, 1500000000, },
{ HIX5HD2_FIXED_375M, "375m", NULL, CLK_IS_ROOT, 375000000, },
{ HIX5HD2_FIXED_187M, "187m", NULL, CLK_IS_ROOT, 187000000, },
{ HIX5HD2_FIXED_250M, "250m", NULL, CLK_IS_ROOT, 250000000, },
{ HIX5HD2_FIXED_125M, "125m", NULL, CLK_IS_ROOT, 125000000, },
{ HIX5HD2_FIXED_2P02M, "2m", NULL, CLK_IS_ROOT, 2000000, },
{ HIX5HD2_FIXED_50M, "50m", NULL, CLK_IS_ROOT, 50000000, },
{ HIX5HD2_FIXED_25M, "25m", NULL, CLK_IS_ROOT, 25000000, },
{ HIX5HD2_FIXED_83M, "83m", NULL, CLK_IS_ROOT, 83333333, },
};
static const char *sfc_mux_p[] __initconst = {
"24m", "150m", "200m", "100m", "75m", };
static u32 sfc_mux_table[] = {0, 4, 5, 6, 7};
static const char *sdio1_mux_p[] __initconst = {
"75m", "100m", "50m", "15m", };
static u32 sdio1_mux_table[] = {0, 1, 2, 3};
static const char *fephy_mux_p[] __initconst = { "25m", "125m"};
static u32 fephy_mux_table[] = {0, 1};
static struct hisi_mux_clock hix5hd2_mux_clks[] __initdata = {
{ HIX5HD2_SFC_MUX, "sfc_mux", sfc_mux_p, ARRAY_SIZE(sfc_mux_p),
CLK_SET_RATE_PARENT, 0x5c, 8, 3, 0, sfc_mux_table, },
{ HIX5HD2_MMC_MUX, "mmc_mux", sdio1_mux_p, ARRAY_SIZE(sdio1_mux_p),
CLK_SET_RATE_PARENT, 0xa0, 8, 2, 0, sdio1_mux_table, },
{ HIX5HD2_FEPHY_MUX, "fephy_mux",
fephy_mux_p, ARRAY_SIZE(fephy_mux_p),
CLK_SET_RATE_PARENT, 0x120, 8, 2, 0, fephy_mux_table, },
};
static struct hisi_gate_clock hix5hd2_gate_clks[] __initdata = {
/*sfc*/
{ HIX5HD2_SFC_CLK, "clk_sfc", "sfc_mux",
CLK_SET_RATE_PARENT, 0x5c, 0, 0, },
{ HIX5HD2_SFC_RST, "rst_sfc", "clk_sfc",
CLK_SET_RATE_PARENT, 0x5c, 4, CLK_GATE_SET_TO_DISABLE, },
/*sdio1*/
{ HIX5HD2_MMC_BIU_CLK, "clk_mmc_biu", "200m",
CLK_SET_RATE_PARENT, 0xa0, 0, 0, },
{ HIX5HD2_MMC_CIU_CLK, "clk_mmc_ciu", "mmc_mux",
CLK_SET_RATE_PARENT, 0xa0, 1, 0, },
{ HIX5HD2_MMC_CIU_RST, "rst_mmc_ciu", "clk_mmc_ciu",
CLK_SET_RATE_PARENT, 0xa0, 4, CLK_GATE_SET_TO_DISABLE, },
};
static void __init hix5hd2_clk_init(struct device_node *np)
{
struct hisi_clock_data *clk_data;
clk_data = hisi_clk_init(np, HIX5HD2_NR_CLKS);
if (!clk_data)
return;
hisi_clk_register_fixed_rate(hix5hd2_fixed_rate_clks,
ARRAY_SIZE(hix5hd2_fixed_rate_clks),
clk_data);
hisi_clk_register_mux(hix5hd2_mux_clks, ARRAY_SIZE(hix5hd2_mux_clks),
clk_data);
hisi_clk_register_gate(hix5hd2_gate_clks,
ARRAY_SIZE(hix5hd2_gate_clks), clk_data);
}
CLK_OF_DECLARE(hix5hd2_clk, "hisilicon,hix5hd2-clock", hix5hd2_clk_init);
...@@ -127,11 +127,14 @@ void __init hisi_clk_register_mux(struct hisi_mux_clock *clks, ...@@ -127,11 +127,14 @@ void __init hisi_clk_register_mux(struct hisi_mux_clock *clks,
int i; int i;
for (i = 0; i < nums; i++) { for (i = 0; i < nums; i++) {
clk = clk_register_mux(NULL, clks[i].name, clks[i].parent_names, u32 mask = BIT(clks[i].width) - 1;
clk = clk_register_mux_table(NULL, clks[i].name,
clks[i].parent_names,
clks[i].num_parents, clks[i].flags, clks[i].num_parents, clks[i].flags,
base + clks[i].offset, clks[i].shift, base + clks[i].offset, clks[i].shift,
clks[i].width, clks[i].mux_flags, mask, clks[i].mux_flags,
&hisi_clk_lock); clks[i].table, &hisi_clk_lock);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n", pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name); __func__, clks[i].name);
...@@ -174,6 +177,34 @@ void __init hisi_clk_register_divider(struct hisi_divider_clock *clks, ...@@ -174,6 +177,34 @@ void __init hisi_clk_register_divider(struct hisi_divider_clock *clks,
} }
} }
void __init hisi_clk_register_gate(struct hisi_gate_clock *clks,
int nums, struct hisi_clock_data *data)
{
struct clk *clk;
void __iomem *base = data->base;
int i;
for (i = 0; i < nums; 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,
&hisi_clk_lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].alias)
clk_register_clkdev(clk, clks[i].alias, NULL);
data->clk_data.clks[clks[i].id] = clk;
}
}
void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks, void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
int nums, struct hisi_clock_data *data) int nums, struct hisi_clock_data *data)
{ {
......
...@@ -62,6 +62,7 @@ struct hisi_mux_clock { ...@@ -62,6 +62,7 @@ struct hisi_mux_clock {
u8 shift; u8 shift;
u8 width; u8 width;
u8 mux_flags; u8 mux_flags;
u32 *table;
const char *alias; const char *alias;
}; };
...@@ -103,6 +104,8 @@ void __init hisi_clk_register_mux(struct hisi_mux_clock *, int, ...@@ -103,6 +104,8 @@ void __init hisi_clk_register_mux(struct hisi_mux_clock *, int,
struct hisi_clock_data *); struct hisi_clock_data *);
void __init hisi_clk_register_divider(struct hisi_divider_clock *, void __init hisi_clk_register_divider(struct hisi_divider_clock *,
int, struct hisi_clock_data *); int, struct hisi_clock_data *);
void __init hisi_clk_register_gate(struct hisi_gate_clock *,
int, struct hisi_clock_data *);
void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *, void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *,
int, struct hisi_clock_data *); int, struct hisi_clock_data *);
#endif /* __HISI_CLK_H */ #endif /* __HISI_CLK_H */
...@@ -34,3 +34,7 @@ config DOVE_CLK ...@@ -34,3 +34,7 @@ config DOVE_CLK
config KIRKWOOD_CLK config KIRKWOOD_CLK
bool bool
select MVEBU_CLK_COMMON select MVEBU_CLK_COMMON
config ORION_CLK
bool
select MVEBU_CLK_COMMON
...@@ -8,3 +8,4 @@ obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o ...@@ -8,3 +8,4 @@ obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o
obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o
obj-$(CONFIG_DOVE_CLK) += dove.o obj-$(CONFIG_DOVE_CLK) += dove.o
obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o
obj-$(CONFIG_ORION_CLK) += orion.o
/*
* Marvell Orion SoC clocks
*
* Copyright (C) 2014 Thomas Petazzoni
*
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
#include "common.h"
static const struct coreclk_ratio orion_coreclk_ratios[] __initconst = {
{ .id = 0, .name = "ddrclk", }
};
/*
* Orion 5182
*/
#define SAR_MV88F5182_TCLK_FREQ 8
#define SAR_MV88F5182_TCLK_FREQ_MASK 0x3
static u32 __init mv88f5182_get_tclk_freq(void __iomem *sar)
{
u32 opt = (readl(sar) >> SAR_MV88F5182_TCLK_FREQ) &
SAR_MV88F5182_TCLK_FREQ_MASK;
if (opt == 1)
return 150000000;
else if (opt == 2)
return 166666667;
else
return 0;
}
#define SAR_MV88F5182_CPU_FREQ 4
#define SAR_MV88F5182_CPU_FREQ_MASK 0xf
static u32 __init mv88f5182_get_cpu_freq(void __iomem *sar)
{
u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) &
SAR_MV88F5182_CPU_FREQ_MASK;
if (opt == 0)
return 333333333;
else if (opt == 1 || opt == 2)
return 400000000;
else if (opt == 3)
return 500000000;
else
return 0;
}
static void __init mv88f5182_get_clk_ratio(void __iomem *sar, int id,
int *mult, int *div)
{
u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) &
SAR_MV88F5182_CPU_FREQ_MASK;
if (opt == 0 || opt == 1) {
*mult = 1;
*div = 2;
} else if (opt == 2 || opt == 3) {
*mult = 1;
*div = 3;
} else {
*mult = 0;
*div = 1;
}
}
static const struct coreclk_soc_desc mv88f5182_coreclks = {
.get_tclk_freq = mv88f5182_get_tclk_freq,
.get_cpu_freq = mv88f5182_get_cpu_freq,
.get_clk_ratio = mv88f5182_get_clk_ratio,
.ratios = orion_coreclk_ratios,
.num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
};
static void __init mv88f5182_clk_init(struct device_node *np)
{
return mvebu_coreclk_setup(np, &mv88f5182_coreclks);
}
CLK_OF_DECLARE(mv88f5182_clk, "marvell,mv88f5182-core-clock", mv88f5182_clk_init);
/*
* Orion 5281
*/
static u32 __init mv88f5281_get_tclk_freq(void __iomem *sar)
{
/* On 5281, tclk is always 166 Mhz */
return 166666667;
}
#define SAR_MV88F5281_CPU_FREQ 4
#define SAR_MV88F5281_CPU_FREQ_MASK 0xf
static u32 __init mv88f5281_get_cpu_freq(void __iomem *sar)
{
u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) &
SAR_MV88F5281_CPU_FREQ_MASK;
if (opt == 1 || opt == 2)
return 400000000;
else if (opt == 3)
return 500000000;
else
return 0;
}
static void __init mv88f5281_get_clk_ratio(void __iomem *sar, int id,
int *mult, int *div)
{
u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) &
SAR_MV88F5281_CPU_FREQ_MASK;
if (opt == 1) {
*mult = 1;
*div = 2;
} else if (opt == 2 || opt == 3) {
*mult = 1;
*div = 3;
} else {
*mult = 0;
*div = 1;
}
}
static const struct coreclk_soc_desc mv88f5281_coreclks = {
.get_tclk_freq = mv88f5281_get_tclk_freq,
.get_cpu_freq = mv88f5281_get_cpu_freq,
.get_clk_ratio = mv88f5281_get_clk_ratio,
.ratios = orion_coreclk_ratios,
.num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
};
static void __init mv88f5281_clk_init(struct device_node *np)
{
return mvebu_coreclk_setup(np, &mv88f5281_coreclks);
}
CLK_OF_DECLARE(mv88f5281_clk, "marvell,mv88f5281-core-clock", mv88f5281_clk_init);
/*
* Orion 6183
*/
#define SAR_MV88F6183_TCLK_FREQ 9
#define SAR_MV88F6183_TCLK_FREQ_MASK 0x1
static u32 __init mv88f6183_get_tclk_freq(void __iomem *sar)
{
u32 opt = (readl(sar) >> SAR_MV88F6183_TCLK_FREQ) &
SAR_MV88F6183_TCLK_FREQ_MASK;
if (opt == 0)
return 133333333;
else if (opt == 1)
return 166666667;
else
return 0;
}
#define SAR_MV88F6183_CPU_FREQ 1
#define SAR_MV88F6183_CPU_FREQ_MASK 0x3f
static u32 __init mv88f6183_get_cpu_freq(void __iomem *sar)
{
u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) &
SAR_MV88F6183_CPU_FREQ_MASK;
if (opt == 9)
return 333333333;
else if (opt == 17)
return 400000000;
else
return 0;
}
static void __init mv88f6183_get_clk_ratio(void __iomem *sar, int id,
int *mult, int *div)
{
u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) &
SAR_MV88F6183_CPU_FREQ_MASK;
if (opt == 9 || opt == 17) {
*mult = 1;
*div = 2;
} else {
*mult = 0;
*div = 1;
}
}
static const struct coreclk_soc_desc mv88f6183_coreclks = {
.get_tclk_freq = mv88f6183_get_tclk_freq,
.get_cpu_freq = mv88f6183_get_cpu_freq,
.get_clk_ratio = mv88f6183_get_clk_ratio,
.ratios = orion_coreclk_ratios,
.num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
};
static void __init mv88f6183_clk_init(struct device_node *np)
{
return mvebu_coreclk_setup(np, &mv88f6183_coreclks);
}
CLK_OF_DECLARE(mv88f6183_clk, "marvell,mv88f6183-core-clock", mv88f6183_clk_init);
...@@ -13,10 +13,10 @@ config MSM_GCC_8660 ...@@ -13,10 +13,10 @@ config MSM_GCC_8660
i2c, USB, SD/eMMC, etc. i2c, USB, SD/eMMC, etc.
config MSM_GCC_8960 config MSM_GCC_8960
tristate "MSM8960 Global Clock Controller" tristate "APQ8064/MSM8960 Global Clock Controller"
depends on COMMON_CLK_QCOM depends on COMMON_CLK_QCOM
help help
Support for the global clock controller on msm8960 devices. Support for the global clock controller on apq8064/msm8960 devices.
Say Y if you want to use peripheral devices such as UART, SPI, Say Y if you want to use peripheral devices such as UART, SPI,
i2c, USB, SD/eMMC, SATA, PCIe, etc. i2c, USB, SD/eMMC, SATA, PCIe, etc.
......
obj-$(CONFIG_COMMON_CLK_QCOM) += clk-qcom.o obj-$(CONFIG_COMMON_CLK_QCOM) += clk-qcom.o
clk-qcom-y += common.o
clk-qcom-y += clk-regmap.o clk-qcom-y += clk-regmap.o
clk-qcom-y += clk-pll.o clk-qcom-y += clk-pll.o
clk-qcom-y += clk-rcg.o clk-qcom-y += clk-rcg.o
......
/*
* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/export.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
#include <linux/clk-provider.h>
#include <linux/reset-controller.h>
#include "common.h"
#include "clk-regmap.h"
#include "reset.h"
struct qcom_cc {
struct qcom_reset_controller reset;
struct clk_onecell_data data;
struct clk *clks[];
};
int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc)
{
void __iomem *base;
struct resource *res;
int i, ret;
struct device *dev = &pdev->dev;
struct clk *clk;
struct clk_onecell_data *data;
struct clk **clks;
struct regmap *regmap;
struct qcom_reset_controller *reset;
struct qcom_cc *cc;
size_t num_clks = desc->num_clks;
struct clk_regmap **rclks = desc->clks;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
regmap = devm_regmap_init_mmio(dev, base, desc->config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
GFP_KERNEL);
if (!cc)
return -ENOMEM;
clks = cc->clks;
data = &cc->data;
data->clks = clks;
data->clk_num = num_clks;
for (i = 0; i < num_clks; i++) {
if (!rclks[i])
continue;
clk = devm_clk_register_regmap(dev, rclks[i]);
if (IS_ERR(clk))
return PTR_ERR(clk);
clks[i] = clk;
}
ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
if (ret)
return ret;
reset = &cc->reset;
reset->rcdev.of_node = dev->of_node;
reset->rcdev.ops = &qcom_reset_ops;
reset->rcdev.owner = dev->driver->owner;
reset->rcdev.nr_resets = desc->num_resets;
reset->regmap = regmap;
reset->reset_map = desc->resets;
platform_set_drvdata(pdev, &reset->rcdev);
ret = reset_controller_register(&reset->rcdev);
if (ret)
of_clk_del_provider(dev->of_node);
return ret;
}
EXPORT_SYMBOL_GPL(qcom_cc_probe);
void qcom_cc_remove(struct platform_device *pdev)
{
of_clk_del_provider(pdev->dev.of_node);
reset_controller_unregister(platform_get_drvdata(pdev));
}
EXPORT_SYMBOL_GPL(qcom_cc_remove);
/*
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __QCOM_CLK_COMMON_H__
#define __QCOM_CLK_COMMON_H__
struct platform_device;
struct regmap_config;
struct clk_regmap;
struct qcom_reset_map;
struct qcom_cc_desc {
const struct regmap_config *config;
struct clk_regmap **clks;
size_t num_clks;
const struct qcom_reset_map *resets;
size_t num_resets;
};
extern int qcom_cc_probe(struct platform_device *pdev,
const struct qcom_cc_desc *desc);
extern void qcom_cc_remove(struct platform_device *pdev);
#endif
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <dt-bindings/clock/qcom,gcc-msm8660.h> #include <dt-bindings/clock/qcom,gcc-msm8660.h>
#include <dt-bindings/reset/qcom,gcc-msm8660.h> #include <dt-bindings/reset/qcom,gcc-msm8660.h>
#include "common.h"
#include "clk-regmap.h" #include "clk-regmap.h"
#include "clk-pll.h" #include "clk-pll.h"
#include "clk-rcg.h" #include "clk-rcg.h"
...@@ -2701,51 +2702,24 @@ static const struct regmap_config gcc_msm8660_regmap_config = { ...@@ -2701,51 +2702,24 @@ static const struct regmap_config gcc_msm8660_regmap_config = {
.fast_io = true, .fast_io = true,
}; };
static const struct qcom_cc_desc gcc_msm8660_desc = {
.config = &gcc_msm8660_regmap_config,
.clks = gcc_msm8660_clks,
.num_clks = ARRAY_SIZE(gcc_msm8660_clks),
.resets = gcc_msm8660_resets,
.num_resets = ARRAY_SIZE(gcc_msm8660_resets),
};
static const struct of_device_id gcc_msm8660_match_table[] = { static const struct of_device_id gcc_msm8660_match_table[] = {
{ .compatible = "qcom,gcc-msm8660" }, { .compatible = "qcom,gcc-msm8660" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, gcc_msm8660_match_table); MODULE_DEVICE_TABLE(of, gcc_msm8660_match_table);
struct qcom_cc {
struct qcom_reset_controller reset;
struct clk_onecell_data data;
struct clk *clks[];
};
static int gcc_msm8660_probe(struct platform_device *pdev) static int gcc_msm8660_probe(struct platform_device *pdev)
{ {
void __iomem *base;
struct resource *res;
int i, ret;
struct device *dev = &pdev->dev;
struct clk *clk; struct clk *clk;
struct clk_onecell_data *data; struct device *dev = &pdev->dev;
struct clk **clks;
struct regmap *regmap;
size_t num_clks;
struct qcom_reset_controller *reset;
struct qcom_cc *cc;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8660_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
num_clks = ARRAY_SIZE(gcc_msm8660_clks);
cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
GFP_KERNEL);
if (!cc)
return -ENOMEM;
clks = cc->clks;
data = &cc->data;
data->clks = clks;
data->clk_num = num_clks;
/* Temporary until RPM clocks supported */ /* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000); clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000);
...@@ -2756,39 +2730,12 @@ static int gcc_msm8660_probe(struct platform_device *pdev) ...@@ -2756,39 +2730,12 @@ static int gcc_msm8660_probe(struct platform_device *pdev)
if (IS_ERR(clk)) if (IS_ERR(clk))
return PTR_ERR(clk); return PTR_ERR(clk);
for (i = 0; i < num_clks; i++) { return qcom_cc_probe(pdev, &gcc_msm8660_desc);
if (!gcc_msm8660_clks[i])
continue;
clk = devm_clk_register_regmap(dev, gcc_msm8660_clks[i]);
if (IS_ERR(clk))
return PTR_ERR(clk);
clks[i] = clk;
}
ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
if (ret)
return ret;
reset = &cc->reset;
reset->rcdev.of_node = dev->of_node;
reset->rcdev.ops = &qcom_reset_ops,
reset->rcdev.owner = THIS_MODULE,
reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8660_resets),
reset->regmap = regmap;
reset->reset_map = gcc_msm8660_resets,
platform_set_drvdata(pdev, &reset->rcdev);
ret = reset_controller_register(&reset->rcdev);
if (ret)
of_clk_del_provider(dev->of_node);
return ret;
} }
static int gcc_msm8660_remove(struct platform_device *pdev) static int gcc_msm8660_remove(struct platform_device *pdev)
{ {
of_clk_del_provider(pdev->dev.of_node); qcom_cc_remove(pdev);
reset_controller_unregister(platform_get_drvdata(pdev));
return 0; return 0;
} }
......
/* /*
* Copyright (c) 2013, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
* *
* This software is licensed under the terms of the GNU General Public * This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and * License version 2, as published by the Free Software Foundation, and
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <dt-bindings/clock/qcom,gcc-msm8960.h> #include <dt-bindings/clock/qcom,gcc-msm8960.h>
#include <dt-bindings/reset/qcom,gcc-msm8960.h> #include <dt-bindings/reset/qcom,gcc-msm8960.h>
#include "common.h"
#include "clk-regmap.h" #include "clk-regmap.h"
#include "clk-pll.h" #include "clk-pll.h"
#include "clk-rcg.h" #include "clk-rcg.h"
...@@ -2809,7 +2810,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = { ...@@ -2809,7 +2810,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = {
[PPSS_PROC_RESET] = { 0x2594, 1 }, [PPSS_PROC_RESET] = { 0x2594, 1 },
[PPSS_RESET] = { 0x2594}, [PPSS_RESET] = { 0x2594},
[DMA_BAM_RESET] = { 0x25c0, 7 }, [DMA_BAM_RESET] = { 0x25c0, 7 },
[SIC_TIC_RESET] = { 0x2600, 7 }, [SPS_TIC_H_RESET] = { 0x2600, 7 },
[SLIMBUS_H_RESET] = { 0x2620, 7 }, [SLIMBUS_H_RESET] = { 0x2620, 7 },
[SFAB_CFPB_M_RESET] = { 0x2680, 7 }, [SFAB_CFPB_M_RESET] = { 0x2680, 7 },
[SFAB_CFPB_S_RESET] = { 0x26c0, 7 }, [SFAB_CFPB_S_RESET] = { 0x26c0, 7 },
...@@ -2822,7 +2823,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = { ...@@ -2822,7 +2823,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = {
[SFAB_SFPB_M_RESET] = { 0x2780, 7 }, [SFAB_SFPB_M_RESET] = { 0x2780, 7 },
[SFAB_SFPB_S_RESET] = { 0x27a0, 7 }, [SFAB_SFPB_S_RESET] = { 0x27a0, 7 },
[RPM_PROC_RESET] = { 0x27c0, 7 }, [RPM_PROC_RESET] = { 0x27c0, 7 },
[PMIC_SSBI2_RESET] = { 0x270c, 12 }, [PMIC_SSBI2_RESET] = { 0x280c, 12 },
[SDC1_RESET] = { 0x2830 }, [SDC1_RESET] = { 0x2830 },
[SDC2_RESET] = { 0x2850 }, [SDC2_RESET] = { 0x2850 },
[SDC3_RESET] = { 0x2870 }, [SDC3_RESET] = { 0x2870 },
...@@ -2867,6 +2868,16 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = { ...@@ -2867,6 +2868,16 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = {
[RIVA_RESET] = { 0x35e0 }, [RIVA_RESET] = { 0x35e0 },
}; };
static struct clk_regmap *gcc_apq8064_clks[] = {
[PLL8] = &pll8.clkr,
[PLL8_VOTE] = &pll8_vote,
[GSBI7_UART_SRC] = &gsbi7_uart_src.clkr,
[GSBI7_UART_CLK] = &gsbi7_uart_clk.clkr,
[GSBI7_QUP_SRC] = &gsbi7_qup_src.clkr,
[GSBI7_QUP_CLK] = &gsbi7_qup_clk.clkr,
[GSBI7_H_CLK] = &gsbi7_h_clk.clkr,
};
static const struct regmap_config gcc_msm8960_regmap_config = { static const struct regmap_config gcc_msm8960_regmap_config = {
.reg_bits = 32, .reg_bits = 32,
.reg_stride = 4, .reg_stride = 4,
...@@ -2875,51 +2886,38 @@ static const struct regmap_config gcc_msm8960_regmap_config = { ...@@ -2875,51 +2886,38 @@ static const struct regmap_config gcc_msm8960_regmap_config = {
.fast_io = true, .fast_io = true,
}; };
static const struct qcom_cc_desc gcc_msm8960_desc = {
.config = &gcc_msm8960_regmap_config,
.clks = gcc_msm8960_clks,
.num_clks = ARRAY_SIZE(gcc_msm8960_clks),
.resets = gcc_msm8960_resets,
.num_resets = ARRAY_SIZE(gcc_msm8960_resets),
};
static const struct qcom_cc_desc gcc_apq8064_desc = {
.config = &gcc_msm8960_regmap_config,
.clks = gcc_apq8064_clks,
.num_clks = ARRAY_SIZE(gcc_apq8064_clks),
.resets = gcc_msm8960_resets,
.num_resets = ARRAY_SIZE(gcc_msm8960_resets),
};
static const struct of_device_id gcc_msm8960_match_table[] = { static const struct of_device_id gcc_msm8960_match_table[] = {
{ .compatible = "qcom,gcc-msm8960" }, { .compatible = "qcom,gcc-msm8960", .data = &gcc_msm8960_desc },
{ .compatible = "qcom,gcc-apq8064", .data = &gcc_apq8064_desc },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, gcc_msm8960_match_table); MODULE_DEVICE_TABLE(of, gcc_msm8960_match_table);
struct qcom_cc {
struct qcom_reset_controller reset;
struct clk_onecell_data data;
struct clk *clks[];
};
static int gcc_msm8960_probe(struct platform_device *pdev) static int gcc_msm8960_probe(struct platform_device *pdev)
{ {
void __iomem *base;
struct resource *res;
int i, ret;
struct device *dev = &pdev->dev;
struct clk *clk; struct clk *clk;
struct clk_onecell_data *data; struct device *dev = &pdev->dev;
struct clk **clks; const struct of_device_id *match;
struct regmap *regmap;
size_t num_clks; match = of_match_device(gcc_msm8960_match_table, &pdev->dev);
struct qcom_reset_controller *reset; if (!match)
struct qcom_cc *cc; return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8960_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
num_clks = ARRAY_SIZE(gcc_msm8960_clks);
cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
GFP_KERNEL);
if (!cc)
return -ENOMEM;
clks = cc->clks;
data = &cc->data;
data->clks = clks;
data->clk_num = num_clks;
/* Temporary until RPM clocks supported */ /* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000); clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000);
...@@ -2930,39 +2928,12 @@ static int gcc_msm8960_probe(struct platform_device *pdev) ...@@ -2930,39 +2928,12 @@ static int gcc_msm8960_probe(struct platform_device *pdev)
if (IS_ERR(clk)) if (IS_ERR(clk))
return PTR_ERR(clk); return PTR_ERR(clk);
for (i = 0; i < num_clks; i++) { return qcom_cc_probe(pdev, match->data);
if (!gcc_msm8960_clks[i])
continue;
clk = devm_clk_register_regmap(dev, gcc_msm8960_clks[i]);
if (IS_ERR(clk))
return PTR_ERR(clk);
clks[i] = clk;
}
ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
if (ret)
return ret;
reset = &cc->reset;
reset->rcdev.of_node = dev->of_node;
reset->rcdev.ops = &qcom_reset_ops,
reset->rcdev.owner = THIS_MODULE,
reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8960_resets),
reset->regmap = regmap;
reset->reset_map = gcc_msm8960_resets,
platform_set_drvdata(pdev, &reset->rcdev);
ret = reset_controller_register(&reset->rcdev);
if (ret)
of_clk_del_provider(dev->of_node);
return ret;
} }
static int gcc_msm8960_remove(struct platform_device *pdev) static int gcc_msm8960_remove(struct platform_device *pdev)
{ {
of_clk_del_provider(pdev->dev.of_node); qcom_cc_remove(pdev);
reset_controller_unregister(platform_get_drvdata(pdev));
return 0; return 0;
} }
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <dt-bindings/clock/qcom,gcc-msm8974.h> #include <dt-bindings/clock/qcom,gcc-msm8974.h>
#include <dt-bindings/reset/qcom,gcc-msm8974.h> #include <dt-bindings/reset/qcom,gcc-msm8974.h>
#include "common.h"
#include "clk-regmap.h" #include "clk-regmap.h"
#include "clk-pll.h" #include "clk-pll.h"
#include "clk-rcg.h" #include "clk-rcg.h"
...@@ -2574,51 +2575,24 @@ static const struct regmap_config gcc_msm8974_regmap_config = { ...@@ -2574,51 +2575,24 @@ static const struct regmap_config gcc_msm8974_regmap_config = {
.fast_io = true, .fast_io = true,
}; };
static const struct qcom_cc_desc gcc_msm8974_desc = {
.config = &gcc_msm8974_regmap_config,
.clks = gcc_msm8974_clocks,
.num_clks = ARRAY_SIZE(gcc_msm8974_clocks),
.resets = gcc_msm8974_resets,
.num_resets = ARRAY_SIZE(gcc_msm8974_resets),
};
static const struct of_device_id gcc_msm8974_match_table[] = { static const struct of_device_id gcc_msm8974_match_table[] = {
{ .compatible = "qcom,gcc-msm8974" }, { .compatible = "qcom,gcc-msm8974" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, gcc_msm8974_match_table); MODULE_DEVICE_TABLE(of, gcc_msm8974_match_table);
struct qcom_cc {
struct qcom_reset_controller reset;
struct clk_onecell_data data;
struct clk *clks[];
};
static int gcc_msm8974_probe(struct platform_device *pdev) static int gcc_msm8974_probe(struct platform_device *pdev)
{ {
void __iomem *base;
struct resource *res;
int i, ret;
struct device *dev = &pdev->dev;
struct clk *clk; struct clk *clk;
struct clk_onecell_data *data; struct device *dev = &pdev->dev;
struct clk **clks;
struct regmap *regmap;
size_t num_clks;
struct qcom_reset_controller *reset;
struct qcom_cc *cc;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8974_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
num_clks = ARRAY_SIZE(gcc_msm8974_clocks);
cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
GFP_KERNEL);
if (!cc)
return -ENOMEM;
clks = cc->clks;
data = &cc->data;
data->clks = clks;
data->clk_num = num_clks;
/* Temporary until RPM clocks supported */ /* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000); clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000);
...@@ -2631,39 +2605,12 @@ static int gcc_msm8974_probe(struct platform_device *pdev) ...@@ -2631,39 +2605,12 @@ static int gcc_msm8974_probe(struct platform_device *pdev)
if (IS_ERR(clk)) if (IS_ERR(clk))
return PTR_ERR(clk); return PTR_ERR(clk);
for (i = 0; i < num_clks; i++) { return qcom_cc_probe(pdev, &gcc_msm8974_desc);
if (!gcc_msm8974_clocks[i])
continue;
clk = devm_clk_register_regmap(dev, gcc_msm8974_clocks[i]);
if (IS_ERR(clk))
return PTR_ERR(clk);
clks[i] = clk;
}
ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
if (ret)
return ret;
reset = &cc->reset;
reset->rcdev.of_node = dev->of_node;
reset->rcdev.ops = &qcom_reset_ops,
reset->rcdev.owner = THIS_MODULE,
reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8974_resets),
reset->regmap = regmap;
reset->reset_map = gcc_msm8974_resets,
platform_set_drvdata(pdev, &reset->rcdev);
ret = reset_controller_register(&reset->rcdev);
if (ret)
of_clk_del_provider(dev->of_node);
return ret;
} }
static int gcc_msm8974_remove(struct platform_device *pdev) static int gcc_msm8974_remove(struct platform_device *pdev)
{ {
of_clk_del_provider(pdev->dev.of_node); qcom_cc_remove(pdev);
reset_controller_unregister(platform_get_drvdata(pdev));
return 0; return 0;
} }
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <dt-bindings/clock/qcom,mmcc-msm8960.h> #include <dt-bindings/clock/qcom,mmcc-msm8960.h>
#include <dt-bindings/reset/qcom,mmcc-msm8960.h> #include <dt-bindings/reset/qcom,mmcc-msm8960.h>
#include "common.h"
#include "clk-regmap.h" #include "clk-regmap.h"
#include "clk-pll.h" #include "clk-pll.h"
#include "clk-rcg.h" #include "clk-rcg.h"
...@@ -2222,85 +2223,28 @@ static const struct regmap_config mmcc_msm8960_regmap_config = { ...@@ -2222,85 +2223,28 @@ static const struct regmap_config mmcc_msm8960_regmap_config = {
.fast_io = true, .fast_io = true,
}; };
static const struct qcom_cc_desc mmcc_msm8960_desc = {
.config = &mmcc_msm8960_regmap_config,
.clks = mmcc_msm8960_clks,
.num_clks = ARRAY_SIZE(mmcc_msm8960_clks),
.resets = mmcc_msm8960_resets,
.num_resets = ARRAY_SIZE(mmcc_msm8960_resets),
};
static const struct of_device_id mmcc_msm8960_match_table[] = { static const struct of_device_id mmcc_msm8960_match_table[] = {
{ .compatible = "qcom,mmcc-msm8960" }, { .compatible = "qcom,mmcc-msm8960" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, mmcc_msm8960_match_table); MODULE_DEVICE_TABLE(of, mmcc_msm8960_match_table);
struct qcom_cc {
struct qcom_reset_controller reset;
struct clk_onecell_data data;
struct clk *clks[];
};
static int mmcc_msm8960_probe(struct platform_device *pdev) static int mmcc_msm8960_probe(struct platform_device *pdev)
{ {
void __iomem *base; return qcom_cc_probe(pdev, &mmcc_msm8960_desc);
struct resource *res;
int i, ret;
struct device *dev = &pdev->dev;
struct clk *clk;
struct clk_onecell_data *data;
struct clk **clks;
struct regmap *regmap;
size_t num_clks;
struct qcom_reset_controller *reset;
struct qcom_cc *cc;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
regmap = devm_regmap_init_mmio(dev, base, &mmcc_msm8960_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
num_clks = ARRAY_SIZE(mmcc_msm8960_clks);
cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
GFP_KERNEL);
if (!cc)
return -ENOMEM;
clks = cc->clks;
data = &cc->data;
data->clks = clks;
data->clk_num = num_clks;
for (i = 0; i < num_clks; i++) {
if (!mmcc_msm8960_clks[i])
continue;
clk = devm_clk_register_regmap(dev, mmcc_msm8960_clks[i]);
if (IS_ERR(clk))
return PTR_ERR(clk);
clks[i] = clk;
}
ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
if (ret)
return ret;
reset = &cc->reset;
reset->rcdev.of_node = dev->of_node;
reset->rcdev.ops = &qcom_reset_ops,
reset->rcdev.owner = THIS_MODULE,
reset->rcdev.nr_resets = ARRAY_SIZE(mmcc_msm8960_resets),
reset->regmap = regmap;
reset->reset_map = mmcc_msm8960_resets,
platform_set_drvdata(pdev, &reset->rcdev);
ret = reset_controller_register(&reset->rcdev);
if (ret)
of_clk_del_provider(dev->of_node);
return ret;
} }
static int mmcc_msm8960_remove(struct platform_device *pdev) static int mmcc_msm8960_remove(struct platform_device *pdev)
{ {
of_clk_del_provider(pdev->dev.of_node); qcom_cc_remove(pdev);
reset_controller_unregister(platform_get_drvdata(pdev));
return 0; return 0;
} }
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <dt-bindings/clock/qcom,mmcc-msm8974.h> #include <dt-bindings/clock/qcom,mmcc-msm8974.h>
#include <dt-bindings/reset/qcom,mmcc-msm8974.h> #include <dt-bindings/reset/qcom,mmcc-msm8974.h>
#include "common.h"
#include "clk-regmap.h" #include "clk-regmap.h"
#include "clk-pll.h" #include "clk-pll.h"
#include "clk-rcg.h" #include "clk-rcg.h"
...@@ -2524,88 +2525,39 @@ static const struct regmap_config mmcc_msm8974_regmap_config = { ...@@ -2524,88 +2525,39 @@ static const struct regmap_config mmcc_msm8974_regmap_config = {
.fast_io = true, .fast_io = true,
}; };
static const struct qcom_cc_desc mmcc_msm8974_desc = {
.config = &mmcc_msm8974_regmap_config,
.clks = mmcc_msm8974_clocks,
.num_clks = ARRAY_SIZE(mmcc_msm8974_clocks),
.resets = mmcc_msm8974_resets,
.num_resets = ARRAY_SIZE(mmcc_msm8974_resets),
};
static const struct of_device_id mmcc_msm8974_match_table[] = { static const struct of_device_id mmcc_msm8974_match_table[] = {
{ .compatible = "qcom,mmcc-msm8974" }, { .compatible = "qcom,mmcc-msm8974" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, mmcc_msm8974_match_table); MODULE_DEVICE_TABLE(of, mmcc_msm8974_match_table);
struct qcom_cc {
struct qcom_reset_controller reset;
struct clk_onecell_data data;
struct clk *clks[];
};
static int mmcc_msm8974_probe(struct platform_device *pdev) static int mmcc_msm8974_probe(struct platform_device *pdev)
{ {
void __iomem *base; int ret;
struct resource *res;
int i, ret;
struct device *dev = &pdev->dev;
struct clk *clk;
struct clk_onecell_data *data;
struct clk **clks;
struct regmap *regmap; struct regmap *regmap;
size_t num_clks;
struct qcom_reset_controller *reset;
struct qcom_cc *cc;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
regmap = devm_regmap_init_mmio(dev, base, &mmcc_msm8974_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
num_clks = ARRAY_SIZE(mmcc_msm8974_clocks);
cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
GFP_KERNEL);
if (!cc)
return -ENOMEM;
clks = cc->clks;
data = &cc->data;
data->clks = clks;
data->clk_num = num_clks;
clk_pll_configure_sr_hpm_lp(&mmpll1, regmap, &mmpll1_config, true);
clk_pll_configure_sr_hpm_lp(&mmpll3, regmap, &mmpll3_config, false);
for (i = 0; i < num_clks; i++) { ret = qcom_cc_probe(pdev, &mmcc_msm8974_desc);
if (!mmcc_msm8974_clocks[i])
continue;
clk = devm_clk_register_regmap(dev, mmcc_msm8974_clocks[i]);
if (IS_ERR(clk))
return PTR_ERR(clk);
clks[i] = clk;
}
ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
if (ret) if (ret)
return ret; return ret;
reset = &cc->reset; regmap = dev_get_regmap(&pdev->dev, NULL);
reset->rcdev.of_node = dev->of_node; clk_pll_configure_sr_hpm_lp(&mmpll1, regmap, &mmpll1_config, true);
reset->rcdev.ops = &qcom_reset_ops, clk_pll_configure_sr_hpm_lp(&mmpll3, regmap, &mmpll3_config, false);
reset->rcdev.owner = THIS_MODULE,
reset->rcdev.nr_resets = ARRAY_SIZE(mmcc_msm8974_resets),
reset->regmap = regmap;
reset->reset_map = mmcc_msm8974_resets,
platform_set_drvdata(pdev, &reset->rcdev);
ret = reset_controller_register(&reset->rcdev);
if (ret)
of_clk_del_provider(dev->of_node);
return ret; return 0;
} }
static int mmcc_msm8974_remove(struct platform_device *pdev) static int mmcc_msm8974_remove(struct platform_device *pdev)
{ {
of_clk_del_provider(pdev->dev.of_node); qcom_cc_remove(pdev);
reset_controller_unregister(platform_get_drvdata(pdev));
return 0; return 0;
} }
......
obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o
obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o
obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o
obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o
obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o
......
...@@ -112,7 +112,7 @@ static int cpg_mstp_clock_is_enabled(struct clk_hw *hw) ...@@ -112,7 +112,7 @@ static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
else else
value = clk_readl(group->smstpcr); value = clk_readl(group->smstpcr);
return !!(value & BIT(clock->bit_index)); return !(value & BIT(clock->bit_index));
} }
static const struct clk_ops cpg_mstp_clock_ops = { static const struct clk_ops cpg_mstp_clock_ops = {
......
/*
* r8a7740 Core CPG Clocks
*
* Copyright (C) 2014 Ulrich Hecht
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/shmobile.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/spinlock.h>
struct r8a7740_cpg {
struct clk_onecell_data data;
spinlock_t lock;
void __iomem *reg;
};
#define CPG_FRQCRA 0x00
#define CPG_FRQCRB 0x04
#define CPG_PLLC2CR 0x2c
#define CPG_USBCKCR 0x8c
#define CPG_FRQCRC 0xe0
#define CLK_ENABLE_ON_INIT BIT(0)
struct div4_clk {
const char *name;
unsigned int reg;
unsigned int shift;
int flags;
};
static struct div4_clk div4_clks[] = {
{ "i", CPG_FRQCRA, 20, CLK_ENABLE_ON_INIT },
{ "zg", CPG_FRQCRA, 16, CLK_ENABLE_ON_INIT },
{ "b", CPG_FRQCRA, 8, CLK_ENABLE_ON_INIT },
{ "m1", CPG_FRQCRA, 4, CLK_ENABLE_ON_INIT },
{ "hp", CPG_FRQCRB, 4, 0 },
{ "hpp", CPG_FRQCRC, 20, 0 },
{ "usbp", CPG_FRQCRC, 16, 0 },
{ "s", CPG_FRQCRC, 12, 0 },
{ "zb", CPG_FRQCRC, 8, 0 },
{ "m3", CPG_FRQCRC, 4, 0 },
{ "cp", CPG_FRQCRC, 0, 0 },
{ NULL, 0, 0, 0 },
};
static const struct clk_div_table div4_div_table[] = {
{ 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 12 },
{ 6, 16 }, { 7, 18 }, { 8, 24 }, { 9, 32 }, { 10, 36 }, { 11, 48 },
{ 13, 72 }, { 14, 96 }, { 0, 0 }
};
static u32 cpg_mode __initdata;
static struct clk * __init
r8a7740_cpg_register_clock(struct device_node *np, struct r8a7740_cpg *cpg,
const char *name)
{
const struct clk_div_table *table = NULL;
const char *parent_name;
unsigned int shift, reg;
unsigned int mult = 1;
unsigned int div = 1;
if (!strcmp(name, "r")) {
switch (cpg_mode & (BIT(2) | BIT(1))) {
case BIT(1) | BIT(2):
/* extal1 */
parent_name = of_clk_get_parent_name(np, 0);
div = 2048;
break;
case BIT(2):
/* extal1 */
parent_name = of_clk_get_parent_name(np, 0);
div = 1024;
break;
default:
/* extalr */
parent_name = of_clk_get_parent_name(np, 2);
break;
}
} else if (!strcmp(name, "system")) {
parent_name = of_clk_get_parent_name(np, 0);
if (cpg_mode & BIT(1))
div = 2;
} else if (!strcmp(name, "pllc0")) {
/* PLLC0/1 are configurable multiplier clocks. Register them as
* fixed factor clocks for now as there's no generic multiplier
* clock implementation and we currently have no need to change
* the multiplier value.
*/
u32 value = clk_readl(cpg->reg + CPG_FRQCRC);
parent_name = "system";
mult = ((value >> 24) & 0x7f) + 1;
} else if (!strcmp(name, "pllc1")) {
u32 value = clk_readl(cpg->reg + CPG_FRQCRA);
parent_name = "system";
mult = ((value >> 24) & 0x7f) + 1;
div = 2;
} else if (!strcmp(name, "pllc2")) {
u32 value = clk_readl(cpg->reg + CPG_PLLC2CR);
parent_name = "system";
mult = ((value >> 24) & 0x3f) + 1;
} else if (!strcmp(name, "usb24s")) {
u32 value = clk_readl(cpg->reg + CPG_USBCKCR);
if (value & BIT(7))
/* extal2 */
parent_name = of_clk_get_parent_name(np, 1);
else
parent_name = "system";
if (!(value & BIT(6)))
div = 2;
} else {
struct div4_clk *c;
for (c = div4_clks; c->name; c++) {
if (!strcmp(name, c->name)) {
parent_name = "pllc1";
table = div4_div_table;
reg = c->reg;
shift = c->shift;
break;
}
}
if (!c->name)
return ERR_PTR(-EINVAL);
}
if (!table) {
return clk_register_fixed_factor(NULL, name, parent_name, 0,
mult, div);
} else {
return clk_register_divider_table(NULL, name, parent_name, 0,
cpg->reg + reg, shift, 4, 0,
table, &cpg->lock);
}
}
static void __init r8a7740_cpg_clocks_init(struct device_node *np)
{
struct r8a7740_cpg *cpg;
struct clk **clks;
unsigned int i;
int num_clks;
if (of_property_read_u32(np, "renesas,mode", &cpg_mode))
pr_warn("%s: missing renesas,mode property\n", __func__);
num_clks = of_property_count_strings(np, "clock-output-names");
if (num_clks < 0) {
pr_err("%s: failed to count clocks\n", __func__);
return;
}
cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL);
if (cpg == NULL || clks == NULL) {
/* We're leaking memory on purpose, there's no point in cleaning
* up as the system won't boot anyway.
*/
return;
}
spin_lock_init(&cpg->lock);
cpg->data.clks = clks;
cpg->data.clk_num = num_clks;
cpg->reg = of_iomap(np, 0);
if (WARN_ON(cpg->reg == NULL))
return;
for (i = 0; i < num_clks; ++i) {
const char *name;
struct clk *clk;
of_property_read_string_index(np, "clock-output-names", i,
&name);
clk = r8a7740_cpg_register_clock(np, cpg, name);
if (IS_ERR(clk))
pr_err("%s: failed to register %s %s clock (%ld)\n",
__func__, np->name, name, PTR_ERR(clk));
else
cpg->data.clks[i] = clk;
}
of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
}
CLK_OF_DECLARE(r8a7740_cpg_clks, "renesas,r8a7740-cpg-clocks",
r8a7740_cpg_clocks_init);
/*
* r8a7779 Core CPG Clocks
*
* Copyright (C) 2013, 2014 Horms Solutions Ltd.
*
* Contact: Simon Horman <horms@verge.net.au>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/shmobile.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/spinlock.h>
#include <dt-bindings/clock/r8a7779-clock.h>
#define CPG_NUM_CLOCKS (R8A7779_CLK_OUT + 1)
struct r8a7779_cpg {
struct clk_onecell_data data;
spinlock_t lock;
void __iomem *reg;
};
/* -----------------------------------------------------------------------------
* CPG Clock Data
*/
/*
* MD1 = 1 MD1 = 0
* (PLLA = 1500) (PLLA = 1600)
* (MHz) (MHz)
*------------------------------------------------+--------------------
* clkz 1000 (2/3) 800 (1/2)
* clkzs 250 (1/6) 200 (1/8)
* clki 750 (1/2) 800 (1/2)
* clks 250 (1/6) 200 (1/8)
* clks1 125 (1/12) 100 (1/16)
* clks3 187.5 (1/8) 200 (1/8)
* clks4 93.7 (1/16) 100 (1/16)
* clkp 62.5 (1/24) 50 (1/32)
* clkg 62.5 (1/24) 66.6 (1/24)
* clkb, CLKOUT
* (MD2 = 0) 62.5 (1/24) 66.6 (1/24)
* (MD2 = 1) 41.6 (1/36) 50 (1/32)
*/
#define CPG_CLK_CONFIG_INDEX(md) (((md) & (BIT(2)|BIT(1))) >> 1)
struct cpg_clk_config {
unsigned int z_mult;
unsigned int z_div;
unsigned int zs_and_s_div;
unsigned int s1_div;
unsigned int p_div;
unsigned int b_and_out_div;
};
static const struct cpg_clk_config cpg_clk_configs[4] __initconst = {
{ 1, 2, 8, 16, 32, 24 },
{ 2, 3, 6, 12, 24, 24 },
{ 1, 2, 8, 16, 32, 32 },
{ 2, 3, 6, 12, 24, 36 },
};
/*
* MD PLLA Ratio
* 12 11
*------------------------
* 0 0 x42
* 0 1 x48
* 1 0 x56
* 1 1 x64
*/
#define CPG_PLLA_MULT_INDEX(md) (((md) & (BIT(12)|BIT(11))) >> 11)
static const unsigned int cpg_plla_mult[4] __initconst = { 42, 48, 56, 64 };
/* -----------------------------------------------------------------------------
* Initialization
*/
static u32 cpg_mode __initdata;
static struct clk * __init
r8a7779_cpg_register_clock(struct device_node *np, struct r8a7779_cpg *cpg,
const struct cpg_clk_config *config,
unsigned int plla_mult, const char *name)
{
const char *parent_name = "plla";
unsigned int mult = 1;
unsigned int div = 1;
if (!strcmp(name, "plla")) {
parent_name = of_clk_get_parent_name(np, 0);
mult = plla_mult;
} else if (!strcmp(name, "z")) {
div = config->z_div;
mult = config->z_mult;
} else if (!strcmp(name, "zs") || !strcmp(name, "s")) {
div = config->zs_and_s_div;
} else if (!strcmp(name, "s1")) {
div = config->s1_div;
} else if (!strcmp(name, "p")) {
div = config->p_div;
} else if (!strcmp(name, "b") || !strcmp(name, "out")) {
div = config->b_and_out_div;
} else {
return ERR_PTR(-EINVAL);
}
return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, div);
}
static void __init r8a7779_cpg_clocks_init(struct device_node *np)
{
const struct cpg_clk_config *config;
struct r8a7779_cpg *cpg;
struct clk **clks;
unsigned int i, plla_mult;
int num_clks;
num_clks = of_property_count_strings(np, "clock-output-names");
if (num_clks < 0) {
pr_err("%s: failed to count clocks\n", __func__);
return;
}
cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
clks = kzalloc(CPG_NUM_CLOCKS * sizeof(*clks), GFP_KERNEL);
if (cpg == NULL || clks == NULL) {
/* We're leaking memory on purpose, there's no point in cleaning
* up as the system won't boot anyway.
*/
return;
}
spin_lock_init(&cpg->lock);
cpg->data.clks = clks;
cpg->data.clk_num = num_clks;
config = &cpg_clk_configs[CPG_CLK_CONFIG_INDEX(cpg_mode)];
plla_mult = cpg_plla_mult[CPG_PLLA_MULT_INDEX(cpg_mode)];
for (i = 0; i < num_clks; ++i) {
const char *name;
struct clk *clk;
of_property_read_string_index(np, "clock-output-names", i,
&name);
clk = r8a7779_cpg_register_clock(np, cpg, config,
plla_mult, name);
if (IS_ERR(clk))
pr_err("%s: failed to register %s %s clock (%ld)\n",
__func__, np->name, name, PTR_ERR(clk));
else
cpg->data.clks[i] = clk;
}
of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
}
CLK_OF_DECLARE(r8a7779_cpg_clks, "renesas,r8a7779-cpg-clocks",
r8a7779_cpg_clocks_init);
void __init r8a7779_clocks_init(u32 mode)
{
cpg_mode = mode;
of_clk_init(NULL);
}
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#define SOCFPGA_MMC_CLK "sdmmc_clk" #define SOCFPGA_MMC_CLK "sdmmc_clk"
#define SOCFPGA_GPIO_DB_CLK_OFFSET 0xA8 #define SOCFPGA_GPIO_DB_CLK_OFFSET 0xA8
#define div_mask(width) ((1 << (width)) - 1)
#define streq(a, b) (strcmp((a), (b)) == 0) #define streq(a, b) (strcmp((a), (b)) == 0)
#define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw) #define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw)
......
...@@ -29,12 +29,18 @@ static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk, ...@@ -29,12 +29,18 @@ static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct socfpga_periph_clk *socfpgaclk = to_socfpga_periph_clk(hwclk); struct socfpga_periph_clk *socfpgaclk = to_socfpga_periph_clk(hwclk);
u32 div; u32 div, val;
if (socfpgaclk->fixed_div) if (socfpgaclk->fixed_div) {
div = socfpgaclk->fixed_div; div = socfpgaclk->fixed_div;
else } else {
if (socfpgaclk->div_reg) {
val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
val &= div_mask(socfpgaclk->width);
parent_rate /= (val + 1);
}
div = ((readl(socfpgaclk->hw.reg) & 0x1ff) + 1); div = ((readl(socfpgaclk->hw.reg) & 0x1ff) + 1);
}
return parent_rate / div; return parent_rate / div;
} }
...@@ -54,6 +60,7 @@ static __init void __socfpga_periph_init(struct device_node *node, ...@@ -54,6 +60,7 @@ static __init void __socfpga_periph_init(struct device_node *node,
struct clk_init_data init; struct clk_init_data init;
int rc; int rc;
u32 fixed_div; u32 fixed_div;
u32 div_reg[3];
of_property_read_u32(node, "reg", &reg); of_property_read_u32(node, "reg", &reg);
...@@ -63,6 +70,15 @@ static __init void __socfpga_periph_init(struct device_node *node, ...@@ -63,6 +70,15 @@ static __init void __socfpga_periph_init(struct device_node *node,
periph_clk->hw.reg = clk_mgr_base_addr + reg; periph_clk->hw.reg = clk_mgr_base_addr + reg;
rc = of_property_read_u32_array(node, "div-reg", div_reg, 3);
if (!rc) {
periph_clk->div_reg = clk_mgr_base_addr + div_reg[0];
periph_clk->shift = div_reg[1];
periph_clk->width = div_reg[2];
} else {
periph_clk->div_reg = 0;
}
rc = of_property_read_u32(node, "fixed-divider", &fixed_div); rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
if (rc) if (rc)
periph_clk->fixed_div = 0; periph_clk->fixed_div = 0;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#define CLKMGR_PERPLL_SRC 0xAC #define CLKMGR_PERPLL_SRC 0xAC
#define SOCFPGA_MAX_PARENTS 3 #define SOCFPGA_MAX_PARENTS 3
#define div_mask(width) ((1 << (width)) - 1)
extern void __iomem *clk_mgr_base_addr; extern void __iomem *clk_mgr_base_addr;
...@@ -52,6 +53,9 @@ struct socfpga_periph_clk { ...@@ -52,6 +53,9 @@ struct socfpga_periph_clk {
struct clk_gate hw; struct clk_gate hw;
char *parent_name; char *parent_name;
u32 fixed_div; u32 fixed_div;
void __iomem *div_reg;
u32 width; /* only valid if div_reg != 0 */
u32 shift; /* only valid if div_reg != 0 */
}; };
#endif /* SOCFPGA_CLK_H */ #endif /* SOCFPGA_CLK_H */
...@@ -77,6 +77,41 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -77,6 +77,41 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
return rate; return rate;
} }
static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_p)
{
struct clk *clk = hw->clk, *parent, *best_parent = NULL;
int i, num_parents;
unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
/* find the parent that can help provide the fastest rate <= rate */
num_parents = __clk_get_num_parents(clk);
for (i = 0; i < num_parents; i++) {
parent = clk_get_parent_by_index(clk, i);
if (!parent)
continue;
if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT)
parent_rate = __clk_round_rate(parent, rate);
else
parent_rate = __clk_get_rate(parent);
child_rate = clk_factors_round_rate(hw, rate, &parent_rate);
if (child_rate <= rate && child_rate > best_child_rate) {
best_parent = parent;
best = parent_rate;
best_child_rate = child_rate;
}
}
if (best_parent)
*best_parent_p = best_parent;
*best_parent_rate = best;
return best_child_rate;
}
static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
...@@ -113,6 +148,7 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -113,6 +148,7 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
} }
const struct clk_ops clk_factors_ops = { const struct clk_ops clk_factors_ops = {
.determine_rate = clk_factors_determine_rate,
.recalc_rate = clk_factors_recalc_rate, .recalc_rate = clk_factors_recalc_rate,
.round_rate = clk_factors_round_rate, .round_rate = clk_factors_round_rate,
.set_rate = clk_factors_set_rate, .set_rate = clk_factors_set_rate,
......
...@@ -506,6 +506,43 @@ CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk", ...@@ -506,6 +506,43 @@ CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk",
/**
* clk_sunxi_mmc_phase_control() - configures MMC clock phase control
*/
void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output)
{
#define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw)
#define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
struct clk_hw *hw = __clk_get_hw(clk);
struct clk_composite *composite = to_clk_composite(hw);
struct clk_hw *rate_hw = composite->rate_hw;
struct clk_factors *factors = to_clk_factors(rate_hw);
unsigned long flags = 0;
u32 reg;
if (factors->lock)
spin_lock_irqsave(factors->lock, flags);
reg = readl(factors->reg);
/* set sample clock phase control */
reg &= ~(0x7 << 20);
reg |= ((sample & 0x7) << 20);
/* set output clock phase control */
reg &= ~(0x7 << 8);
reg |= ((output & 0x7) << 8);
writel(reg, factors->reg);
if (factors->lock)
spin_unlock_irqrestore(factors->lock, flags);
}
EXPORT_SYMBOL(clk_sunxi_mmc_phase_control);
/** /**
* sunxi_factors_clk_setup() - Setup function for factor clocks * sunxi_factors_clk_setup() - Setup function for factor clocks
*/ */
......
...@@ -233,6 +233,7 @@ enum clk_id { ...@@ -233,6 +233,7 @@ enum clk_id {
tegra_clk_xusb_hs_src, tegra_clk_xusb_hs_src,
tegra_clk_xusb_ss, tegra_clk_xusb_ss,
tegra_clk_xusb_ss_src, tegra_clk_xusb_ss_src,
tegra_clk_xusb_ss_div2,
tegra_clk_max, tegra_clk_max,
}; };
......
...@@ -96,10 +96,20 @@ ...@@ -96,10 +96,20 @@
(PLLE_SS_MAX_VAL | PLLE_SS_INC_VAL | PLLE_SS_INCINTRV_VAL) (PLLE_SS_MAX_VAL | PLLE_SS_INC_VAL | PLLE_SS_INCINTRV_VAL)
#define PLLE_AUX_PLLP_SEL BIT(2) #define PLLE_AUX_PLLP_SEL BIT(2)
#define PLLE_AUX_USE_LOCKDET BIT(3)
#define PLLE_AUX_ENABLE_SWCTL BIT(4) #define PLLE_AUX_ENABLE_SWCTL BIT(4)
#define PLLE_AUX_SS_SWCTL BIT(6)
#define PLLE_AUX_SEQ_ENABLE BIT(24) #define PLLE_AUX_SEQ_ENABLE BIT(24)
#define PLLE_AUX_SEQ_START_STATE BIT(25)
#define PLLE_AUX_PLLRE_SEL BIT(28) #define PLLE_AUX_PLLRE_SEL BIT(28)
#define XUSBIO_PLL_CFG0 0x51c
#define XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL BIT(0)
#define XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL BIT(2)
#define XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET BIT(6)
#define XUSBIO_PLL_CFG0_SEQ_ENABLE BIT(24)
#define XUSBIO_PLL_CFG0_SEQ_START_STATE BIT(25)
#define PLLE_MISC_PLLE_PTS BIT(8) #define PLLE_MISC_PLLE_PTS BIT(8)
#define PLLE_MISC_IDDQ_SW_VALUE BIT(13) #define PLLE_MISC_IDDQ_SW_VALUE BIT(13)
#define PLLE_MISC_IDDQ_SW_CTRL BIT(14) #define PLLE_MISC_IDDQ_SW_CTRL BIT(14)
...@@ -1318,7 +1328,28 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw) ...@@ -1318,7 +1328,28 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
pll_writel(val, PLLE_SS_CTRL, pll); pll_writel(val, PLLE_SS_CTRL, pll);
udelay(1); udelay(1);
/* TODO: enable hw control of xusb brick pll */ /* Enable hw control of xusb brick pll */
val = pll_readl_misc(pll);
val &= ~PLLE_MISC_IDDQ_SW_CTRL;
pll_writel_misc(val, pll);
val = pll_readl(pll->params->aux_reg, pll);
val |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SEQ_START_STATE);
val &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL);
pll_writel(val, pll->params->aux_reg, pll);
udelay(1);
val |= PLLE_AUX_SEQ_ENABLE;
pll_writel(val, pll->params->aux_reg, pll);
val = pll_readl(XUSBIO_PLL_CFG0, pll);
val |= (XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET |
XUSBIO_PLL_CFG0_SEQ_START_STATE);
val &= ~(XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL |
XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL);
pll_writel(val, XUSBIO_PLL_CFG0, pll);
udelay(1);
val |= XUSBIO_PLL_CFG0_SEQ_ENABLE;
pll_writel(val, XUSBIO_PLL_CFG0, pll);
out: out:
if (pll->lock) if (pll->lock)
......
...@@ -329,7 +329,9 @@ static u32 mux_clkm_pllp_pllc_pllre_idx[] = { ...@@ -329,7 +329,9 @@ static u32 mux_clkm_pllp_pllc_pllre_idx[] = {
static const char *mux_clkm_48M_pllp_480M[] = { static const char *mux_clkm_48M_pllp_480M[] = {
"clk_m", "pll_u_48M", "pll_p", "pll_u_480M" "clk_m", "pll_u_48M", "pll_p", "pll_u_480M"
}; };
#define mux_clkm_48M_pllp_480M_idx NULL static u32 mux_clkm_48M_pllp_480M_idx[] = {
[0] = 0, [1] = 2, [2] = 4, [3] = 6,
};
static const char *mux_clkm_pllre_clk32_480M_pllc_ref[] = { static const char *mux_clkm_pllre_clk32_480M_pllc_ref[] = {
"clk_m", "pll_re_out", "clk_32k", "pll_u_480M", "pll_c", "pll_ref" "clk_m", "pll_re_out", "clk_32k", "pll_u_480M", "pll_c", "pll_ref"
...@@ -338,6 +340,11 @@ static u32 mux_clkm_pllre_clk32_480M_pllc_ref_idx[] = { ...@@ -338,6 +340,11 @@ static u32 mux_clkm_pllre_clk32_480M_pllc_ref_idx[] = {
[0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 4, [5] = 7, [0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 4, [5] = 7,
}; };
static const char *mux_ss_60M[] = {
"xusb_ss_div2", "pll_u_60M"
};
#define mux_ss_60M_idx NULL
static const char *mux_d_audio_clk[] = { static const char *mux_d_audio_clk[] = {
"pll_a_out0", "pll_p", "clk_m", "spdif_in_sync", "i2s0_sync", "pll_a_out0", "pll_p", "clk_m", "spdif_in_sync", "i2s0_sync",
"i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync", "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync",
...@@ -499,6 +506,7 @@ static struct tegra_periph_init_data periph_clks[] = { ...@@ -499,6 +506,7 @@ static struct tegra_periph_init_data periph_clks[] = {
XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src), XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src),
XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src), XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src),
XUSB("xusb_ss_src", mux_clkm_pllre_clk32_480M_pllc_ref, CLK_SOURCE_XUSB_SS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ss_src), XUSB("xusb_ss_src", mux_clkm_pllre_clk32_480M_pllc_ref, CLK_SOURCE_XUSB_SS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ss_src),
NODIV("xusb_hs_src", mux_ss_60M, CLK_SOURCE_XUSB_SS_SRC, 25, MASK(1), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_hs_src, NULL),
XUSB("xusb_dev_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src), XUSB("xusb_dev_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src),
}; };
......
...@@ -142,7 +142,6 @@ ...@@ -142,7 +142,6 @@
#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL BIT(0) #define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL BIT(0)
#define CLK_SOURCE_CSITE 0x1d4 #define CLK_SOURCE_CSITE 0x1d4
#define CLK_SOURCE_XUSB_SS_SRC 0x610
#define CLK_SOURCE_EMC 0x19c #define CLK_SOURCE_EMC 0x19c
/* PLLM override registers */ /* PLLM override registers */
...@@ -834,6 +833,7 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = { ...@@ -834,6 +833,7 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
[tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA114_CLK_XUSB_FALCON_SRC, .present = true }, [tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA114_CLK_XUSB_FALCON_SRC, .present = true },
[tegra_clk_xusb_fs_src] = { .dt_id = TEGRA114_CLK_XUSB_FS_SRC, .present = true }, [tegra_clk_xusb_fs_src] = { .dt_id = TEGRA114_CLK_XUSB_FS_SRC, .present = true },
[tegra_clk_xusb_ss_src] = { .dt_id = TEGRA114_CLK_XUSB_SS_SRC, .present = true }, [tegra_clk_xusb_ss_src] = { .dt_id = TEGRA114_CLK_XUSB_SS_SRC, .present = true },
[tegra_clk_xusb_ss_div2] = { .dt_id = TEGRA114_CLK_XUSB_SS_DIV2, .present = true},
[tegra_clk_xusb_dev_src] = { .dt_id = TEGRA114_CLK_XUSB_DEV_SRC, .present = true }, [tegra_clk_xusb_dev_src] = { .dt_id = TEGRA114_CLK_XUSB_DEV_SRC, .present = true },
[tegra_clk_xusb_dev] = { .dt_id = TEGRA114_CLK_XUSB_DEV, .present = true }, [tegra_clk_xusb_dev] = { .dt_id = TEGRA114_CLK_XUSB_DEV, .present = true },
[tegra_clk_xusb_hs_src] = { .dt_id = TEGRA114_CLK_XUSB_HS_SRC, .present = true }, [tegra_clk_xusb_hs_src] = { .dt_id = TEGRA114_CLK_XUSB_HS_SRC, .present = true },
...@@ -1182,16 +1182,11 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base, ...@@ -1182,16 +1182,11 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base,
void __iomem *pmc_base) void __iomem *pmc_base)
{ {
struct clk *clk; struct clk *clk;
u32 val;
/* xusb_hs_src */
val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC);
val |= BIT(25); /* always select PLLU_60M */
writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC);
clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0, /* xusb_ss_div2 */
1, 1); clk = clk_register_fixed_factor(NULL, "xusb_ss_div2", "xusb_ss_src", 0,
clks[TEGRA114_CLK_XUSB_HS_SRC] = clk; 1, 2);
clks[TEGRA114_CLK_XUSB_SS_DIV2] = clk;
/* dsia mux */ /* dsia mux */
clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0, clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0,
...@@ -1301,7 +1296,12 @@ static struct tegra_clk_init_table init_table[] __initdata = { ...@@ -1301,7 +1296,12 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{TEGRA114_CLK_GR3D, TEGRA114_CLK_PLL_C2, 300000000, 0}, {TEGRA114_CLK_GR3D, TEGRA114_CLK_PLL_C2, 300000000, 0},
{TEGRA114_CLK_DSIALP, TEGRA114_CLK_PLL_P, 68000000, 0}, {TEGRA114_CLK_DSIALP, TEGRA114_CLK_PLL_P, 68000000, 0},
{TEGRA114_CLK_DSIBLP, TEGRA114_CLK_PLL_P, 68000000, 0}, {TEGRA114_CLK_DSIBLP, TEGRA114_CLK_PLL_P, 68000000, 0},
{TEGRA114_CLK_PLL_RE_VCO, TEGRA114_CLK_CLK_MAX, 612000000, 0},
{TEGRA114_CLK_XUSB_SS_SRC, TEGRA114_CLK_PLL_RE_OUT, 122400000, 0},
{TEGRA114_CLK_XUSB_FS_SRC, TEGRA114_CLK_PLL_U_48M, 48000000, 0},
{TEGRA114_CLK_XUSB_HS_SRC, TEGRA114_CLK_XUSB_SS_DIV2, 61200000, 0},
{TEGRA114_CLK_XUSB_FALCON_SRC, TEGRA114_CLK_PLL_P, 204000000, 0},
{TEGRA114_CLK_XUSB_HOST_SRC, TEGRA114_CLK_PLL_P, 102000000, 0},
/* This MUST be the last entry. */ /* This MUST be the last entry. */
{TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0}, {TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0},
}; };
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#define CLK_SOURCE_CSITE 0x1d4 #define CLK_SOURCE_CSITE 0x1d4
#define CLK_SOURCE_EMC 0x19c #define CLK_SOURCE_EMC 0x19c
#define CLK_SOURCE_XUSB_SS_SRC 0x610
#define PLLC_BASE 0x80 #define PLLC_BASE 0x80
#define PLLC_OUT 0x84 #define PLLC_OUT 0x84
...@@ -925,6 +924,7 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = { ...@@ -925,6 +924,7 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
[tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA124_CLK_XUSB_FALCON_SRC, .present = true }, [tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA124_CLK_XUSB_FALCON_SRC, .present = true },
[tegra_clk_xusb_fs_src] = { .dt_id = TEGRA124_CLK_XUSB_FS_SRC, .present = true }, [tegra_clk_xusb_fs_src] = { .dt_id = TEGRA124_CLK_XUSB_FS_SRC, .present = true },
[tegra_clk_xusb_ss_src] = { .dt_id = TEGRA124_CLK_XUSB_SS_SRC, .present = true }, [tegra_clk_xusb_ss_src] = { .dt_id = TEGRA124_CLK_XUSB_SS_SRC, .present = true },
[tegra_clk_xusb_ss_div2] = { .dt_id = TEGRA124_CLK_XUSB_SS_DIV2, .present = true },
[tegra_clk_xusb_dev_src] = { .dt_id = TEGRA124_CLK_XUSB_DEV_SRC, .present = true }, [tegra_clk_xusb_dev_src] = { .dt_id = TEGRA124_CLK_XUSB_DEV_SRC, .present = true },
[tegra_clk_xusb_dev] = { .dt_id = TEGRA124_CLK_XUSB_DEV, .present = true }, [tegra_clk_xusb_dev] = { .dt_id = TEGRA124_CLK_XUSB_DEV, .present = true },
[tegra_clk_xusb_hs_src] = { .dt_id = TEGRA124_CLK_XUSB_HS_SRC, .present = true }, [tegra_clk_xusb_hs_src] = { .dt_id = TEGRA124_CLK_XUSB_HS_SRC, .present = true },
...@@ -1105,16 +1105,11 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base, ...@@ -1105,16 +1105,11 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base,
void __iomem *pmc_base) void __iomem *pmc_base)
{ {
struct clk *clk; struct clk *clk;
u32 val;
/* xusb_hs_src */
val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC);
val |= BIT(25); /* always select PLLU_60M */
writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC);
clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0, /* xusb_ss_div2 */
1, 1); clk = clk_register_fixed_factor(NULL, "xusb_ss_div2", "xusb_ss_src", 0,
clks[TEGRA124_CLK_XUSB_HS_SRC] = clk; 1, 2);
clks[TEGRA124_CLK_XUSB_SS_DIV2] = clk;
/* dsia mux */ /* dsia mux */
clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0, clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0,
...@@ -1368,6 +1363,12 @@ static struct tegra_clk_init_table init_table[] __initdata = { ...@@ -1368,6 +1363,12 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{TEGRA124_CLK_SBC4, TEGRA124_CLK_PLL_P, 12000000, 1}, {TEGRA124_CLK_SBC4, TEGRA124_CLK_PLL_P, 12000000, 1},
{TEGRA124_CLK_TSEC, TEGRA124_CLK_PLL_C3, 0, 0}, {TEGRA124_CLK_TSEC, TEGRA124_CLK_PLL_C3, 0, 0},
{TEGRA124_CLK_MSENC, TEGRA124_CLK_PLL_C3, 0, 0}, {TEGRA124_CLK_MSENC, TEGRA124_CLK_PLL_C3, 0, 0},
{TEGRA124_CLK_PLL_RE_VCO, TEGRA124_CLK_CLK_MAX, 672000000, 0},
{TEGRA124_CLK_XUSB_SS_SRC, TEGRA124_CLK_PLL_U_480M, 120000000, 0},
{TEGRA124_CLK_XUSB_FS_SRC, TEGRA124_CLK_PLL_U_48M, 48000000, 0},
{TEGRA124_CLK_XUSB_HS_SRC, TEGRA124_CLK_PLL_U_60M, 60000000, 0},
{TEGRA124_CLK_XUSB_FALCON_SRC, TEGRA124_CLK_PLL_RE_OUT, 224000000, 0},
{TEGRA124_CLK_XUSB_HOST_SRC, TEGRA124_CLK_PLL_RE_OUT, 112000000, 0},
/* This MUST be the last entry. */ /* This MUST be the last entry. */
{TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0}, {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
}; };
......
...@@ -160,3 +160,4 @@ struct clk *icst_clk_register(struct device *dev, ...@@ -160,3 +160,4 @@ struct clk *icst_clk_register(struct device *dev,
return clk; return clk;
} }
EXPORT_SYMBOL_GPL(icst_clk_register);
This diff is collapsed.
...@@ -53,6 +53,9 @@ static void __iomem *zynq_clkc_base; ...@@ -53,6 +53,9 @@ static void __iomem *zynq_clkc_base;
#define NUM_MIO_PINS 54 #define NUM_MIO_PINS 54
#define DBG_CLK_CTRL_CLKACT_TRC BIT(0)
#define DBG_CLK_CTRL_CPU_1XCLKACT BIT(1)
enum zynq_clk { enum zynq_clk {
armpll, ddrpll, iopll, armpll, ddrpll, iopll,
cpu_6or4x, cpu_3or2x, cpu_2x, cpu_1x, cpu_6or4x, cpu_3or2x, cpu_2x, cpu_1x,
...@@ -499,6 +502,15 @@ static void __init zynq_clk_setup(struct device_node *np) ...@@ -499,6 +502,15 @@ static void __init zynq_clk_setup(struct device_node *np)
clk_output_name[cpu_1x], 0, SLCR_DBG_CLK_CTRL, 1, 0, clk_output_name[cpu_1x], 0, SLCR_DBG_CLK_CTRL, 1, 0,
&dbgclk_lock); &dbgclk_lock);
/* leave debug clocks in the state the bootloader set them up to */
tmp = clk_readl(SLCR_DBG_CLK_CTRL);
if (tmp & DBG_CLK_CTRL_CLKACT_TRC)
if (clk_prepare_enable(clks[dbg_trc]))
pr_warn("%s: trace clk enable failed\n", __func__);
if (tmp & DBG_CLK_CTRL_CPU_1XCLKACT)
if (clk_prepare_enable(clks[dbg_apb]))
pr_warn("%s: debug APB clk enable failed\n", __func__);
/* One gated clock for all APER clocks. */ /* One gated clock for all APER clocks. */
clks[dma] = clk_register_gate(NULL, clk_output_name[dma], clks[dma] = clk_register_gate(NULL, clk_output_name[dma],
clk_output_name[cpu_2x], 0, SLCR_APER_CLK_CTRL, 0, 0, clk_output_name[cpu_2x], 0, SLCR_APER_CLK_CTRL, 0, 0,
......
This diff is collapsed.
...@@ -20,6 +20,18 @@ ...@@ -20,6 +20,18 @@
* the clock control units (CCUs) on Broadcom BCM281XX family SoCs. * the clock control units (CCUs) on Broadcom BCM281XX family SoCs.
*/ */
/*
* These are the bcm281xx CCU device tree "compatible" strings.
* We're stuck with using "bcm11351" in the string because wild
* cards aren't allowed, and that name was the first one defined
* in this family of devices.
*/
#define BCM281XX_DT_ROOT_CCU_COMPAT "brcm,bcm11351-root-ccu"
#define BCM281XX_DT_AON_CCU_COMPAT "brcm,bcm11351-aon-ccu"
#define BCM281XX_DT_HUB_CCU_COMPAT "brcm,bcm11351-hub-ccu"
#define BCM281XX_DT_MASTER_CCU_COMPAT "brcm,bcm11351-master-ccu"
#define BCM281XX_DT_SLAVE_CCU_COMPAT "brcm,bcm11351-slave-ccu"
/* root CCU clock ids */ /* root CCU clock ids */
#define BCM281XX_ROOT_CCU_FRAC_1M 0 #define BCM281XX_ROOT_CCU_FRAC_1M 0
......
This diff is collapsed.
...@@ -337,6 +337,7 @@ ...@@ -337,6 +337,7 @@
#define TEGRA114_CLK_CLK_OUT_3_MUX 308 #define TEGRA114_CLK_CLK_OUT_3_MUX 308
#define TEGRA114_CLK_DSIA_MUX 309 #define TEGRA114_CLK_DSIA_MUX 309
#define TEGRA114_CLK_DSIB_MUX 310 #define TEGRA114_CLK_DSIB_MUX 310
#define TEGRA114_CLK_CLK_MAX 311 #define TEGRA114_CLK_XUSB_SS_DIV2 311
#define TEGRA114_CLK_CLK_MAX 312
#endif /* _DT_BINDINGS_CLOCK_TEGRA114_CAR_H */ #endif /* _DT_BINDINGS_CLOCK_TEGRA114_CAR_H */
...@@ -336,6 +336,7 @@ ...@@ -336,6 +336,7 @@
#define TEGRA124_CLK_DSIA_MUX 309 #define TEGRA124_CLK_DSIA_MUX 309
#define TEGRA124_CLK_DSIB_MUX 310 #define TEGRA124_CLK_DSIB_MUX 310
#define TEGRA124_CLK_SOR0_LVDS 311 #define TEGRA124_CLK_SOR0_LVDS 311
#define TEGRA124_CLK_CLK_MAX 312 #define TEGRA124_CLK_XUSB_SS_DIV2 312
#define TEGRA124_CLK_CLK_MAX 313
#endif /* _DT_BINDINGS_CLOCK_TEGRA124_CAR_H */ #endif /* _DT_BINDINGS_CLOCK_TEGRA124_CAR_H */
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
#define PPSS_PROC_RESET 41 #define PPSS_PROC_RESET 41
#define PPSS_RESET 42 #define PPSS_RESET 42
#define DMA_BAM_RESET 43 #define DMA_BAM_RESET 43
#define SIC_TIC_RESET 44 #define SPS_TIC_H_RESET 44
#define SLIMBUS_H_RESET 45 #define SLIMBUS_H_RESET 45
#define SFAB_CFPB_M_RESET 46 #define SFAB_CFPB_M_RESET 46
#define SFAB_CFPB_S_RESET 47 #define SFAB_CFPB_S_RESET 47
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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