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

This commit is contained in:
Mike Turquette
2014-05-23 14:30:35 -07:00
69 changed files with 3413 additions and 837 deletions
+11 -5
View File
@@ -68,21 +68,27 @@ the operations defined in clk.h:
int (*is_enabled)(struct clk_hw *hw);
unsigned long (*recalc_rate)(struct clk_hw *hw,
unsigned long parent_rate);
long (*round_rate)(struct clk_hw *hw, unsigned long,
unsigned long *);
long (*round_rate)(struct clk_hw *hw,
unsigned long rate,
unsigned long *parent_rate);
long (*determine_rate)(struct clk_hw *hw,
unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_clk);
int (*set_parent)(struct clk_hw *hw, u8 index);
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,
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 parent_accuracy);
unsigned long parent_accuracy);
void (*init)(struct clk_hw *hw);
int (*debug_init)(struct clk_hw *hw,
struct dentry *dentry);
};
Part 3 - hardware clk implementations
@@ -10,12 +10,12 @@ This binding uses the common clock binding:
Required properties:
- compatible
Shall have one of the following values:
- "brcm,bcm11351-root-ccu"
- "brcm,bcm11351-aon-ccu"
- "brcm,bcm11351-hub-ccu"
- "brcm,bcm11351-master-ccu"
- "brcm,bcm11351-slave-ccu"
Shall have a value of the form "brcm,<model>-<which>-ccu",
where <model> is a Broadcom SoC model number and <which> is
the name of a defined CCU. For example:
"brcm,bcm11351-root-ccu"
The compatible strings used for each supported SoC family
are defined below.
- reg
Shall define the base and range of the address space
containing clock control registers
@@ -26,12 +26,48 @@ Required properties:
Shall be an ordered list of strings defining the names of
the clocks provided by the CCU.
Device tree example:
BCM281XX family SoCs use Kona CCUs. The following table defines
the set of CCUs and clock specifiers for BCM281XX clocks. When
a clock consumer references a clocks, its symbolic specifier
(rather than its numeric index value) should be used. These
specifiers are defined in "include/dt-bindings/clock/bcm281xx.h".
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"
The following table defines the set of CCUs and clock specifiers for
BCM281XX family clocks. When a clock consumer references a clocks,
its symbolic specifier (rather than its numeric index value) should
be used. These specifiers are defined in:
"include/dt-bindings/clock/bcm281xx.h"
CCU Clock Type Index Specifier
--- ----- ---- ----- ---------
@@ -64,30 +100,40 @@ specifiers are defined in "include/dt-bindings/clock/bcm281xx.h".
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 {
compatible = "brcm,bcm11351-slave-ccu";
reg = <0x3e011000 0x0f00>;
#clock-cells = <1>;
clock-output-names = "uartb",
"uartb2",
"uartb3",
"uartb4";
};
The following table defines the set of CCUs and clock specifiers for
BCM21664 family clocks. When a clock consumer references a clocks,
its symbolic specifier (rather than its numeric index value) should
be used. These specifiers are defined in:
"include/dt-bindings/clock/bcm21664.h"
ref_crystal_clk: ref_crystal {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <26000000>;
};
CCU Clock Type Index Specifier
--- ----- ---- ----- ---------
root frac_1m peri 0 BCM21664_ROOT_CCU_FRAC_1M
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>;
};
aon hub_timer peri 0 BCM21664_AON_CCU_HUB_TIMER
master sdio1 peri 0 BCM21664_MASTER_CCU_SDIO1
master sdio2 peri 1 BCM21664_MASTER_CCU_SDIO2
master sdio3 peri 2 BCM21664_MASTER_CCU_SDIO3
master sdio4 peri 3 BCM21664_MASTER_CCU_SDIO4
master sdio1_sleep peri 4 BCM21664_MASTER_CCU_SDIO1_SLEEP
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:
clocks by index. The names should reflect the clock output signal
names for the device.
clock-indices: If the identifyng number for the clocks in the node
is not linear from zero, then the this mapping allows
the mapping of identifiers into the clock-output-names
array.
clock-indices: If the identifying number for the clocks in the node
is not linear from zero, then this allows the mapping of
identifiers into the clock-output-names array.
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";
}
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==
@@ -12,7 +12,6 @@ Required properties:
Optional properties:
- clock-accuracy : accuracy of clock in ppb (parts per billion).
Should be a single cell.
- gpios : From common gpio binding; gpio connection to clock enable pin.
- clock-output-names : From common clock binding.
Example:
@@ -0,0 +1,31 @@
* 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";
};
@@ -0,0 +1,29 @@
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:
2 = l2clk (L2 Cache 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:
- compatible : shall be one of the following:
"marvell,armada-370-core-clock" - For Armada 370 SoC core clocks
@@ -38,6 +43,9 @@ Required properties:
"marvell,dove-core-clock" - for Dove SoC core clocks
"marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180)
"marvell,mv88f6180-core-clock" - for Kirkwood MV88f6180 SoC
"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
- #clock-cells : from common clock binding; shall be set to 1
@@ -4,6 +4,7 @@ Qualcomm Global Clock & Reset Controller Binding
Required properties :
- compatible : shall contain only one of the following:
"qcom,gcc-apq8064"
"qcom,gcc-msm8660"
"qcom,gcc-msm8960"
"qcom,gcc-msm8974"
@@ -10,6 +10,7 @@ index in the group, from 0 to 31.
Required Properties:
- 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,r8a7791-mstp-clocks" for R8A7791 (R-Car M2) MSTP gate clocks
- "renesas,cpg-mstp-clock" for generic MSTP gate clocks
@@ -0,0 +1,41 @@
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>;
};
@@ -0,0 +1,27 @@
* 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";
};
+130 -84
View File
@@ -14,6 +14,8 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include "dt-bindings/clock/bcm21664.h"
#include "skeleton.dtsi"
/ {
@@ -43,7 +45,7 @@
compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart";
status = "disabled";
reg = <0x3e000000 0x118>;
clocks = <&uartb_clk>;
clocks = <&slave_ccu BCM21664_SLAVE_CCU_UARTB>;
interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
@@ -53,7 +55,7 @@
compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart";
status = "disabled";
reg = <0x3e001000 0x118>;
clocks = <&uartb2_clk>;
clocks = <&slave_ccu BCM21664_SLAVE_CCU_UARTB2>;
interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
@@ -63,7 +65,7 @@
compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart";
status = "disabled";
reg = <0x3e002000 0x118>;
clocks = <&uartb3_clk>;
clocks = <&slave_ccu BCM21664_SLAVE_CCU_UARTB3>;
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
@@ -85,7 +87,7 @@
compatible = "brcm,kona-timer";
reg = <0x35006000 0x1c>;
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&hub_timer_clk>;
clocks = <&aon_ccu BCM21664_AON_CCU_HUB_TIMER>;
};
gpio: gpio@35003000 {
@@ -106,7 +108,7 @@
compatible = "brcm,kona-sdhci";
reg = <0x3f180000 0x801c>;
interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sdio1_clk>;
clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO1>;
status = "disabled";
};
@@ -114,7 +116,7 @@
compatible = "brcm,kona-sdhci";
reg = <0x3f190000 0x801c>;
interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sdio2_clk>;
clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO2>;
status = "disabled";
};
@@ -122,7 +124,7 @@
compatible = "brcm,kona-sdhci";
reg = <0x3f1a0000 0x801c>;
interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sdio3_clk>;
clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO3>;
status = "disabled";
};
@@ -130,7 +132,7 @@
compatible = "brcm,kona-sdhci";
reg = <0x3f1b0000 0x801c>;
interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sdio4_clk>;
clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO4>;
status = "disabled";
};
@@ -140,7 +142,7 @@
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&bsc1_clk>;
clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC1>;
status = "disabled";
};
@@ -150,7 +152,7 @@
interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&bsc2_clk>;
clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC2>;
status = "disabled";
};
@@ -160,7 +162,7 @@
interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&bsc3_clk>;
clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC3>;
status = "disabled";
};
@@ -170,105 +172,149 @@
interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&bsc4_clk>;
clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC4>;
status = "disabled";
};
clocks {
bsc1_clk: bsc1 {
compatible = "fixed-clock";
clock-frequency = <13000000>;
#clock-cells = <0>;
};
#address-cells = <1>;
#size-cells = <1>;
ranges;
bsc2_clk: bsc2 {
compatible = "fixed-clock";
clock-frequency = <13000000>;
#clock-cells = <0>;
};
/*
* Fixed clocks are defined before CCUs whose
* clocks may depend on them.
*/
bsc3_clk: bsc3 {
compatible = "fixed-clock";
clock-frequency = <13000000>;
ref_32k_clk: ref_32k {
#clock-cells = <0>;
};
bsc4_clk: bsc4 {
compatible = "fixed-clock";
clock-frequency = <13000000>;
#clock-cells = <0>;
};
pmu_bsc_clk: pmu_bsc {
compatible = "fixed-clock";
clock-frequency = <13000000>;
#clock-cells = <0>;
};
hub_timer_clk: hub_timer {
compatible = "fixed-clock";
clock-frequency = <32768>;
#clock-cells = <0>;
};
pwm_clk: pwm {
bbl_32k_clk: bbl_32k {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <32768>;
};
ref_13m_clk: ref_13m {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <13000000>;
};
var_13m_clk: var_13m {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <13000000>;
};
dft_19_5m_clk: dft_19_5m {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <19500000>;
};
ref_crystal_clk: ref_crystal {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <26000000>;
#clock-cells = <0>;
};
sdio1_clk: sdio1 {
compatible = "fixed-clock";
clock-frequency = <48000000>;
ref_52m_clk: ref_52m {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <52000000>;
};
sdio2_clk: sdio2 {
compatible = "fixed-clock";
clock-frequency = <48000000>;
var_52m_clk: var_52m {
#clock-cells = <0>;
};
sdio3_clk: sdio3 {
compatible = "fixed-clock";
clock-frequency = <48000000>;
#clock-cells = <0>;
};
sdio4_clk: sdio4 {
compatible = "fixed-clock";
clock-frequency = <48000000>;
#clock-cells = <0>;
};
tmon_1m_clk: tmon_1m {
compatible = "fixed-clock";
clock-frequency = <1000000>;
#clock-cells = <0>;
};
uartb_clk: uartb {
compatible = "fixed-clock";
clock-frequency = <13000000>;
#clock-cells = <0>;
};
uartb2_clk: uartb2 {
compatible = "fixed-clock";
clock-frequency = <13000000>;
#clock-cells = <0>;
};
uartb3_clk: uartb3 {
compatible = "fixed-clock";
clock-frequency = <13000000>;
#clock-cells = <0>;
clock-frequency = <52000000>;
};
usb_otg_ahb_clk: usb_otg_ahb {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <52000000>;
};
ref_96m_clk: ref_96m {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <96000000>;
};
var_96m_clk: var_96m {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <96000000>;
};
ref_104m_clk: ref_104m {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <104000000>;
};
var_104m_clk: var_104m {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <104000000>;
};
ref_156m_clk: ref_156m {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <156000000>;
};
var_156m_clk: var_156m {
#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";
};
};
+2
View File
@@ -12,6 +12,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-composite.o
# hardware specific clock types
# please keep this section sorted lexicographically by file/directory path name
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_EFM32) += clk-efm32gg.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
@@ -33,6 +34,7 @@ obj-$(CONFIG_COMMON_CLK_AT91) += at91/
obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/
obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
obj-$(CONFIG_ARCH_HIP04) += hisilicon/
obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
+1 -1
View File
@@ -6,4 +6,4 @@ config CLK_BCM_KONA
help
Enable common clock framework support for Broadcom SoCs
using "Kona" style clock control units, including those
in the BCM281xx family.
in the BCM281xx and BCM21664 families.
+1
View File
@@ -1,3 +1,4 @@
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
+290
View File
@@ -0,0 +1,290 @@
/*
* 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);
+95 -136
View File
@@ -15,14 +15,10 @@
#include "clk-kona.h"
#include "dt-bindings/clock/bcm281xx.h"
/* bcm11351 CCU device tree "compatible" strings */
#define BCM11351_DT_ROOT_CCU_COMPAT "brcm,bcm11351-root-ccu"
#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"
#define BCM281XX_CCU_COMMON(_name, _ucase_name) \
KONA_CCU_COMMON(BCM281XX, _name, _ucase_name)
/* Root CCU clocks */
/* Root CCU */
static struct peri_clk_data frac_1m_data = {
.gate = HW_SW_GATE(0x214, 16, 0, 1),
@@ -31,7 +27,16 @@ static struct peri_clk_data frac_1m_data = {
.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 = {
.gate = HW_SW_GATE(0x0414, 16, 0, 1),
@@ -60,7 +65,20 @@ static struct peri_clk_data pmu_bsc_var_data = {
.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 = {
.gate = HW_SW_GATE(0x04a4, 18, 2, 3),
@@ -70,7 +88,16 @@ static struct peri_clk_data tmon_1m_data = {
.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 = {
.gate = HW_SW_GATE(0x0358, 18, 2, 3),
@@ -153,7 +180,28 @@ static struct peri_clk_data hsic2_12m_data = {
.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 = {
.gate = HW_SW_GATE(0x0400, 18, 2, 3),
@@ -261,156 +309,67 @@ static struct peri_clk_data pwm_data = {
.trig = TRIGGER(0x0afc, 15),
};
/*
* CCU setup routines
*
* These are called from kona_dt_ccu_setup() to initialize the array
* of clocks provided by the CCU. Once allocated, the entries in
* the array are initialized by calling kona_clk_setup() with the
* initialization data for each clock. They return 0 if successful
* or an error code otherwise.
*/
static int __init bcm281xx_root_ccu_clks_setup(struct ccu_data *ccu)
{
struct clk **clks;
size_t count = BCM281XX_ROOT_CCU_CLOCK_COUNT;
clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
if (!clks) {
pr_err("%s: failed to allocate root clocks\n", __func__);
return -ENOMEM;
}
ccu->data.clks = clks;
ccu->data.clk_num = count;
PERI_CLK_SETUP(clks, ccu, BCM281XX_ROOT_CCU_FRAC_1M, frac_1m);
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;
}
static struct ccu_data slave_ccu_data = {
BCM281XX_CCU_COMMON(slave, SLAVE),
.kona_clks = {
[BCM281XX_SLAVE_CCU_UARTB] =
KONA_CLK(slave, uartb, peri),
[BCM281XX_SLAVE_CCU_UARTB2] =
KONA_CLK(slave, uartb2, peri),
[BCM281XX_SLAVE_CCU_UARTB3] =
KONA_CLK(slave, uartb3, peri),
[BCM281XX_SLAVE_CCU_UARTB4] =
KONA_CLK(slave, uartb4, peri),
[BCM281XX_SLAVE_CCU_SSP0] =
KONA_CLK(slave, ssp0, peri),
[BCM281XX_SLAVE_CCU_SSP2] =
KONA_CLK(slave, ssp2, peri),
[BCM281XX_SLAVE_CCU_BSC1] =
KONA_CLK(slave, bsc1, peri),
[BCM281XX_SLAVE_CCU_BSC2] =
KONA_CLK(slave, bsc2, peri),
[BCM281XX_SLAVE_CCU_BSC3] =
KONA_CLK(slave, bsc3, peri),
[BCM281XX_SLAVE_CCU_PWM] =
KONA_CLK(slave, pwm, peri),
[BCM281XX_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(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)
{
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)
{
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)
{
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)
{
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);
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);
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);
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);
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);
+168 -61
View File
@@ -25,6 +25,31 @@ LIST_HEAD(ccu_list); /* The list of set up CCUs */
/* Validity checking */
static bool ccu_data_offsets_valid(struct ccu_data *ccu)
{
struct ccu_policy *ccu_policy = &ccu->policy;
u32 limit;
limit = ccu->range - sizeof(u32);
limit = round_down(limit, sizeof(u32));
if (ccu_policy_exists(ccu_policy)) {
if (ccu_policy->enable.offset > limit) {
pr_err("%s: bad policy enable offset for %s "
"(%u > %u)\n", __func__,
ccu->name, ccu_policy->enable.offset, limit);
return false;
}
if (ccu_policy->control.offset > limit) {
pr_err("%s: bad policy control offset for %s "
"(%u > %u)\n", __func__,
ccu->name, ccu_policy->control.offset, limit);
return false;
}
}
return true;
}
static bool clk_requires_trigger(struct kona_clk *bcm_clk)
{
struct peri_clk_data *peri = bcm_clk->u.peri;
@@ -54,7 +79,9 @@ static bool clk_requires_trigger(struct kona_clk *bcm_clk)
static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk)
{
struct peri_clk_data *peri;
struct bcm_clk_policy *policy;
struct bcm_clk_gate *gate;
struct bcm_clk_hyst *hyst;
struct bcm_clk_div *div;
struct bcm_clk_sel *sel;
struct bcm_clk_trig *trig;
@@ -64,19 +91,41 @@ static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk)
BUG_ON(bcm_clk->type != bcm_clk_peri);
peri = bcm_clk->u.peri;
name = bcm_clk->name;
name = bcm_clk->init_data.name;
range = bcm_clk->ccu->range;
limit = range - sizeof(u32);
limit = round_down(limit, sizeof(u32));
policy = &peri->policy;
if (policy_exists(policy)) {
if (policy->offset > limit) {
pr_err("%s: bad policy offset for %s (%u > %u)\n",
__func__, name, policy->offset, limit);
return false;
}
}
gate = &peri->gate;
hyst = &peri->hyst;
if (gate_exists(gate)) {
if (gate->offset > limit) {
pr_err("%s: bad gate offset for %s (%u > %u)\n",
__func__, name, gate->offset, limit);
return false;
}
if (hyst_exists(hyst)) {
if (hyst->offset > limit) {
pr_err("%s: bad hysteresis offset for %s "
"(%u > %u)\n", __func__,
name, hyst->offset, limit);
return false;
}
}
} else if (hyst_exists(hyst)) {
pr_err("%s: hysteresis but no gate for %s\n", __func__, name);
return false;
}
div = &peri->div;
@@ -167,6 +216,36 @@ static bool bitfield_valid(u32 shift, u32 width, const char *field_name,
return true;
}
static bool
ccu_policy_valid(struct ccu_policy *ccu_policy, const char *ccu_name)
{
struct bcm_lvm_en *enable = &ccu_policy->enable;
struct bcm_policy_ctl *control;
if (!bit_posn_valid(enable->bit, "policy enable", ccu_name))
return false;
control = &ccu_policy->control;
if (!bit_posn_valid(control->go_bit, "policy control GO", ccu_name))
return false;
if (!bit_posn_valid(control->atl_bit, "policy control ATL", ccu_name))
return false;
if (!bit_posn_valid(control->ac_bit, "policy control AC", ccu_name))
return false;
return true;
}
static bool policy_valid(struct bcm_clk_policy *policy, const char *clock_name)
{
if (!bit_posn_valid(policy->bit, "policy", clock_name))
return false;
return true;
}
/*
* All gates, if defined, have a status bit, and for hardware-only
* gates, that's it. Gates that can be software controlled also
@@ -196,6 +275,17 @@ static bool gate_valid(struct bcm_clk_gate *gate, const char *field_name,
return true;
}
static bool hyst_valid(struct bcm_clk_hyst *hyst, const char *clock_name)
{
if (!bit_posn_valid(hyst->en_bit, "hysteresis enable", clock_name))
return false;
if (!bit_posn_valid(hyst->val_bit, "hysteresis value", clock_name))
return false;
return true;
}
/*
* A selector bitfield must be valid. Its parent_sel array must
* also be reasonable for the field.
@@ -312,7 +402,9 @@ static bool
peri_clk_data_valid(struct kona_clk *bcm_clk)
{
struct peri_clk_data *peri;
struct bcm_clk_policy *policy;
struct bcm_clk_gate *gate;
struct bcm_clk_hyst *hyst;
struct bcm_clk_sel *sel;
struct bcm_clk_div *div;
struct bcm_clk_div *pre_div;
@@ -330,11 +422,20 @@ peri_clk_data_valid(struct kona_clk *bcm_clk)
return false;
peri = bcm_clk->u.peri;
name = bcm_clk->name;
name = bcm_clk->init_data.name;
policy = &peri->policy;
if (policy_exists(policy) && !policy_valid(policy, name))
return false;
gate = &peri->gate;
if (gate_exists(gate) && !gate_valid(gate, "gate", name))
return false;
hyst = &peri->hyst;
if (hyst_exists(hyst) && !hyst_valid(hyst, name))
return false;
sel = &peri->sel;
if (selector_exists(sel)) {
if (!sel_valid(sel, "selector", name))
@@ -567,7 +668,6 @@ static void peri_clk_teardown(struct peri_clk_data *data,
struct clk_init_data *init_data)
{
clk_sel_teardown(&data->sel, init_data);
init_data->ops = NULL;
}
/*
@@ -576,10 +676,9 @@ static void peri_clk_teardown(struct peri_clk_data *data,
* that can be assigned if the clock has one or more parent clocks
* associated with it.
*/
static int peri_clk_setup(struct ccu_data *ccu, struct peri_clk_data *data,
struct clk_init_data *init_data)
static int
peri_clk_setup(struct peri_clk_data *data, struct clk_init_data *init_data)
{
init_data->ops = &kona_peri_clk_ops;
init_data->flags = CLK_IGNORE_UNUSED;
return clk_sel_setup(data->clocks, &data->sel, init_data);
@@ -617,39 +716,26 @@ static void kona_clk_teardown(struct clk *clk)
bcm_clk_teardown(bcm_clk);
}
struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
enum bcm_clk_type type, void *data)
struct clk *kona_clk_setup(struct kona_clk *bcm_clk)
{
struct kona_clk *bcm_clk;
struct clk_init_data *init_data;
struct clk_init_data *init_data = &bcm_clk->init_data;
struct clk *clk = NULL;
bcm_clk = kzalloc(sizeof(*bcm_clk), GFP_KERNEL);
if (!bcm_clk) {
pr_err("%s: failed to allocate bcm_clk for %s\n", __func__,
name);
return NULL;
}
bcm_clk->ccu = ccu;
bcm_clk->name = name;
init_data = &bcm_clk->init_data;
init_data->name = name;
switch (type) {
switch (bcm_clk->type) {
case bcm_clk_peri:
if (peri_clk_setup(ccu, data, init_data))
goto out_free;
if (peri_clk_setup(bcm_clk->u.data, init_data))
return NULL;
break;
default:
data = NULL;
break;
pr_err("%s: clock type %d invalid for %s\n", __func__,
(int)bcm_clk->type, init_data->name);
return NULL;
}
bcm_clk->type = type;
bcm_clk->u.data = data;
/* Make sure everything makes sense before we set it up */
if (!kona_clk_valid(bcm_clk)) {
pr_err("%s: clock data invalid for %s\n", __func__, name);
pr_err("%s: clock data invalid for %s\n", __func__,
init_data->name);
goto out_teardown;
}
@@ -657,7 +743,7 @@ struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
clk = clk_register(NULL, &bcm_clk->hw);
if (IS_ERR(clk)) {
pr_err("%s: error registering clock %s (%ld)\n", __func__,
name, PTR_ERR(clk));
init_data->name, PTR_ERR(clk));
goto out_teardown;
}
BUG_ON(!clk);
@@ -665,8 +751,6 @@ struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
return clk;
out_teardown:
bcm_clk_teardown(bcm_clk);
out_free:
kfree(bcm_clk);
return NULL;
}
@@ -675,50 +759,64 @@ static void ccu_clks_teardown(struct ccu_data *ccu)
{
u32 i;
for (i = 0; i < ccu->data.clk_num; i++)
kona_clk_teardown(ccu->data.clks[i]);
kfree(ccu->data.clks);
for (i = 0; i < ccu->clk_data.clk_num; i++)
kona_clk_teardown(ccu->clk_data.clks[i]);
kfree(ccu->clk_data.clks);
}
static void kona_ccu_teardown(struct ccu_data *ccu)
{
if (!ccu)
return;
kfree(ccu->clk_data.clks);
ccu->clk_data.clks = NULL;
if (!ccu->base)
goto done;
return;
of_clk_del_provider(ccu->node); /* safe if never added */
ccu_clks_teardown(ccu);
list_del(&ccu->links);
of_node_put(ccu->node);
ccu->node = NULL;
iounmap(ccu->base);
done:
kfree(ccu->name);
kfree(ccu);
ccu->base = NULL;
}
static bool ccu_data_valid(struct ccu_data *ccu)
{
struct ccu_policy *ccu_policy;
if (!ccu_data_offsets_valid(ccu))
return false;
ccu_policy = &ccu->policy;
if (ccu_policy_exists(ccu_policy))
if (!ccu_policy_valid(ccu_policy, ccu->name))
return false;
return true;
}
/*
* Set up a CCU. Call the provided ccu_clks_setup callback to
* initialize the array of clocks provided by the CCU.
*/
void __init kona_dt_ccu_setup(struct device_node *node,
int (*ccu_clks_setup)(struct ccu_data *))
void __init kona_dt_ccu_setup(struct ccu_data *ccu,
struct device_node *node)
{
struct ccu_data *ccu;
struct resource res = { 0 };
resource_size_t range;
unsigned int i;
int ret;
ccu = kzalloc(sizeof(*ccu), GFP_KERNEL);
if (ccu)
ccu->name = kstrdup(node->name, GFP_KERNEL);
if (!ccu || !ccu->name) {
pr_err("%s: unable to allocate CCU struct for %s\n",
__func__, node->name);
kfree(ccu);
if (ccu->clk_data.clk_num) {
size_t size;
return;
size = ccu->clk_data.clk_num * sizeof(*ccu->clk_data.clks);
ccu->clk_data.clks = kzalloc(size, GFP_KERNEL);
if (!ccu->clk_data.clks) {
pr_err("%s: unable to allocate %u clocks for %s\n",
__func__, ccu->clk_data.clk_num, node->name);
return;
}
}
ret = of_address_to_resource(node, 0, &res);
@@ -736,24 +834,33 @@ void __init kona_dt_ccu_setup(struct device_node *node,
}
ccu->range = (u32)range;
if (!ccu_data_valid(ccu)) {
pr_err("%s: ccu data not valid for %s\n", __func__, node->name);
goto out_err;
}
ccu->base = ioremap(res.start, ccu->range);
if (!ccu->base) {
pr_err("%s: unable to map CCU registers for %s\n", __func__,
node->name);
goto out_err;
}
spin_lock_init(&ccu->lock);
INIT_LIST_HEAD(&ccu->links);
ccu->node = of_node_get(node);
list_add_tail(&ccu->links, &ccu_list);
/* Set up clocks array (in ccu->data) */
if (ccu_clks_setup(ccu))
goto out_err;
/*
* Set up each defined kona clock and save the result in
* the clock framework clock array (in ccu->data). Then
* register as a provider for these clocks.
*/
for (i = 0; i < ccu->clk_data.clk_num; i++) {
if (!ccu->kona_clks[i].ccu)
continue;
ccu->clk_data.clks[i] = kona_clk_setup(&ccu->kona_clks[i]);
}
ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->data);
ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->clk_data);
if (ret) {
pr_err("%s: error adding ccu %s as provider (%d)\n", __func__,
node->name, ret);
+203 -9
View File
@@ -16,6 +16,14 @@
#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 CLK_GATE_DELAY_LOOP 2000
@@ -207,9 +215,154 @@ __ccu_wait_bit(struct ccu_data *ccu, u32 reg_offset, u32 bit, bool want)
return true;
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;
}
/*
* 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 */
/* Determine whether a clock is gated. CCU lock must be held. */
@@ -374,6 +527,35 @@ static int clk_gate(struct ccu_data *ccu, const char *name,
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 */
/*
@@ -806,7 +988,7 @@ static int kona_peri_clk_enable(struct clk_hw *hw)
struct kona_clk *bcm_clk = to_kona_clk(hw);
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)
@@ -814,7 +996,7 @@ static void kona_peri_clk_disable(struct clk_hw *hw)
struct kona_clk *bcm_clk = to_kona_clk(hw);
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)
@@ -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);
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 */
} else if (ret == -EIO) {
pr_err("%s: %strigger failed for %s\n", __func__,
trig == &data->pre_trig ? "pre-" : "",
bcm_clk->name);
bcm_clk->init_data.name);
}
return ret;
@@ -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,
&data->trig, scaled_div);
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 */
} 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;
@@ -961,15 +1146,24 @@ static bool __peri_clk_init(struct kona_clk *bcm_clk)
{
struct ccu_data *ccu = bcm_clk->ccu;
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;
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)) {
pr_err("%s: error initializing gate for %s\n", __func__, name);
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)) {
pr_err("%s: error initializing divider for %s\n", __func__,
name);
@@ -1014,13 +1208,13 @@ bool __init kona_ccu_init(struct ccu_data *ccu)
{
unsigned long flags;
unsigned int which;
struct clk **clks = ccu->data.clks;
struct clk **clks = ccu->clk_data.clks;
bool success = true;
flags = ccu_lock(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;
if (!clks[which])
+133 -27
View File
@@ -43,8 +43,14 @@
#define FLAG_FLIP(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 */
#define policy_exists(policy) ((policy)->offset != 0)
#define gate_exists(gate) FLAG_TEST(gate, GATE, EXISTS)
#define gate_is_enabled(gate) FLAG_TEST(gate, GATE, ENABLED)
#define gate_is_hw_controllable(gate) FLAG_TEST(gate, GATE, HW)
@@ -54,6 +60,8 @@
#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_is_fixed(div) FLAG_TEST(div, DIV, FIXED)
#define divider_has_fraction(div) (!divider_is_fixed(div) && \
@@ -62,6 +70,9 @@
#define selector_exists(sel) ((sel)->width != 0)
#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 */
enum bcm_clk_type {
bcm_clk_none, /* undefined clock type */
@@ -71,25 +82,26 @@ enum bcm_clk_type {
};
/*
* 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.
* CCU policy control for clocks. Clocks can be enabled or disabled
* based on the CCU policy in effect. One bit in each policy mask
* register (one per CCU policy) represents whether the clock is
* enabled when that policy is effect or not. The CCU policy engine
* must be stopped to update these bits, and must be restarted again
* afterward.
*/
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 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 */
struct bcm_clk_policy {
u32 offset; /* first policy mask register offset */
u32 bit; /* bit used in all mask registers */
};
/* Policy initialization macro */
#define POLICY(_offset, _bit) \
{ \
.offset = (_offset), \
.bit = (_bit), \
}
/*
* Gating control and status is managed by a 32-bit gate register.
*
@@ -195,6 +207,22 @@ struct bcm_clk_gate {
.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
* output rate of the clock. Each divider can be either fixed or
@@ -360,7 +388,9 @@ struct bcm_clk_trig {
}
struct peri_clk_data {
struct bcm_clk_policy policy;
struct bcm_clk_gate gate;
struct bcm_clk_hyst hyst;
struct bcm_clk_trig pre_trig;
struct bcm_clk_div pre_div;
struct bcm_clk_trig trig;
@@ -373,8 +403,7 @@ struct peri_clk_data {
struct kona_clk {
struct clk_hw hw;
struct clk_init_data init_data;
const char *name; /* name of this clock */
struct clk_init_data init_data; /* includes name of this clock */
struct ccu_data *ccu; /* ccu this clock is associated with */
enum bcm_clk_type type;
union {
@@ -385,15 +414,93 @@ struct kona_clk {
#define to_kona_clk(_hw) \
container_of(_hw, struct kona_clk, hw)
/* 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 }
/*
* 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 */
};
/* 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 */
extern struct clk_ops kona_peri_clk_ops;
/* Help functions */
#define PERI_CLK_SETUP(clks, ccu, id, name) \
clks[id] = kona_clk_setup(ccu, #name, bcm_clk_peri, &name ## _data)
/* Externally visible functions */
extern u64 do_div_round_closest(u64 dividend, unsigned long divisor);
@@ -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,
u32 billionths);
extern struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
enum bcm_clk_type type, void *data);
extern void __init kona_dt_ccu_setup(struct device_node *node,
int (*ccu_clks_setup)(struct ccu_data *));
extern struct clk *kona_clk_setup(struct kona_clk *bcm_clk);
extern void __init kona_dt_ccu_setup(struct ccu_data *ccu,
struct device_node *node);
extern bool __init kona_ccu_init(struct ccu_data *ccu);
#endif /* _CLK_KONA_H */

Some files were not shown because too many files have changed in this diff Show More