* [PATCH v5 0/3] clk: Add APM X-Gene SoC clock driver
@ 2013-06-26 17:56 Loc Ho
2013-06-26 17:56 ` [PATCH v5 1/3] " Loc Ho
0 siblings, 1 reply; 6+ messages in thread
From: Loc Ho @ 2013-06-26 17:56 UTC (permalink / raw)
To: linux-arm-kernel
This patch adds APM X-Gene SoC clock driver support. Reference,
PCP PLL, SoC PCP, and Ethernet clocks are defined via the DTS.
-v5:
* Remove duplicate code for soc/pcp clk init function
* Remove un-used flags field from structure
* Merge error handler code for device clock init function
* Update binding documentation
-v4:
* Remove flags from DTS and check status instead
* Change DTS reg entry to be identified by reg-names property
-v3:
* Make DTS compatible type for SoC PLL and PCP PLL
* Make use of of_iomap instead direct ioremap call
* Make kzalloc with variable instead structure
* Remove DTS binding for fixed-clock and fixed_factor_clock
* Remove unnecessary arch_initcall
-v2:
* Make depends on ARM64
* Fix duplicate registration
-v1 - Initial post
Loc Ho (3):
clk: Add APM X-Gene SoC clock driver for reference, PLL, and device
clocks.
clk: arm64: Add DTS clock entry for APM X-Gene Storm SoC with
reference to
Documentation: Add documentation for APM X-Gene clock binding with
PLL and
Documentation/devicetree/bindings/clock/xgene.txt | 111 +++++
arch/arm64/boot/dts/apm-storm.dtsi | 75 +++
drivers/clk/Kconfig | 7 +
drivers/clk/Makefile | 1 +
drivers/clk/clk-xgene.c | 521 +++++++++++++++++++++
5 files changed, 715 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/xgene.txt
create mode 100644 drivers/clk/clk-xgene.c
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v5 1/3] clk: Add APM X-Gene SoC clock driver 2013-06-26 17:56 [PATCH v5 0/3] clk: Add APM X-Gene SoC clock driver Loc Ho @ 2013-06-26 17:56 ` Loc Ho 2013-06-26 17:56 ` [PATCH v5 2/3] clk: arm64: Add DTS clock entry for APM X-Gene Storm SoC Loc Ho 0 siblings, 1 reply; 6+ messages in thread From: Loc Ho @ 2013-06-26 17:56 UTC (permalink / raw) To: linux-arm-kernel clk: Add APM X-Gene SoC clock driver for reference, PLL, and device clocks. Signed-off-by: Loc Ho <lho@apm.com> Signed-off-by: Kumar Sankaran <ksankaran@apm.com> Signed-off-by: Vinayak Kale <vkale@apm.com> Signed-off-by: Feng Kan <fkan@apm.com> --- drivers/clk/Kconfig | 7 + drivers/clk/Makefile | 1 + drivers/clk/clk-xgene.c | 521 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 529 insertions(+), 0 deletions(-) create mode 100644 drivers/clk/clk-xgene.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 0357ac4..534a722 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -81,6 +81,13 @@ config COMMON_CLK_AXI_CLKGEN Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx FPGAs. It is commonly used in Analog Devices' reference designs. +config COMMON_CLK_XGENE + bool "Clock driver for APM XGene SoC" + default y + depends on ARM64 + ---help--- + Sypport for the APM X-Gene SoC reference, PLL, and device clocks. + endmenu source "drivers/clk/mvebu/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 137d3e7..4c96337 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -39,3 +39,4 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o +obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c new file mode 100644 index 0000000..dd8a62d --- /dev/null +++ b/drivers/clk/clk-xgene.c @@ -0,0 +1,521 @@ +/* + * clk-xgene.c - AppliedMicro X-Gene Clock Interface + * + * Copyright (c) 2013, Applied Micro Circuits Corporation + * Author: Loc Ho <lho@apm.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/of_address.h> +#include <asm/setup.h> + +/* Register SCU_PCPPLL bit fields */ +#define N_DIV_RD(src) (((src) & 0x000001ff)) + +/* Register SCU_SOCPLL bit fields */ +#define CLKR_RD(src) (((src) & 0x07000000)>>24) +#define CLKOD_RD(src) (((src) & 0x00300000)>>20) +#define REGSPEC_RESET_F1_MASK 0x00010000 +#define CLKF_RD(src) (((src) & 0x000001ff)) + +#define XGENE_CLK_DRIVER_VER "0.1" + +static DEFINE_SPINLOCK(clk_lock); + +static inline u32 xgene_clk_read(void *csr) +{ + return readl_relaxed(csr); +} + +static inline void xgene_clk_write(u32 data, void *csr) +{ + return writel_relaxed(data, csr); +} + +/* PLL Clock */ +enum xgene_pll_type { + PLL_TYPE_PCP = 0, + PLL_TYPE_SOC = 1, +}; + +struct xgene_clk_pll { + struct clk_hw hw; + const char *name; + void __iomem *reg; + spinlock_t *lock; + u32 pll_offset; + enum xgene_pll_type type; +}; + +#define to_xgene_clk_pll(_hw) container_of(_hw, struct xgene_clk_pll, hw) + +static int xgene_clk_pll_is_enabled(struct clk_hw *hw) +{ + struct xgene_clk_pll *pllclk = to_xgene_clk_pll(hw); + u32 data; + + data = xgene_clk_read(pllclk->reg + pllclk->pll_offset); + pr_debug("%s pll %s\n", pllclk->name, + data & REGSPEC_RESET_F1_MASK ? "disabled" : "enabled"); + + return data & REGSPEC_RESET_F1_MASK ? 0 : 1; +} + +static unsigned long xgene_clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct xgene_clk_pll *pllclk = to_xgene_clk_pll(hw); + unsigned long fref; + unsigned long fvco; + u32 pll; + u32 nref; + u32 nout; + u32 nfb; + + pll = xgene_clk_read(pllclk->reg + pllclk->pll_offset); + + if (pllclk->type == PLL_TYPE_PCP) { + /* + * PLL VCO = Reference clock * NF + * PCP PLL = PLL_VCO / 2 + */ + nout = 2; + fvco = parent_rate * (N_DIV_RD(pll) + 4); + } else { + /* + * Fref = Reference Clock / NREF; + * Fvco = Fref * NFB; + * Fout = Fvco / NOUT; + */ + nref = CLKR_RD(pll) + 1; + nout = CLKOD_RD(pll) + 1; + nfb = CLKF_RD(pll); + fref = parent_rate / nref; + fvco = fref * nfb; + } + pr_debug("%s pll recalc rate %ld parent %ld\n", pllclk->name, + fvco / nout, parent_rate); + + return fvco / nout; +} + +const struct clk_ops xgene_clk_pll_ops = { + .is_enabled = xgene_clk_pll_is_enabled, + .recalc_rate = xgene_clk_pll_recalc_rate, +}; + +static struct clk *xgene_register_clk_pll(struct device *dev, + const char *name, const char *parent_name, + unsigned long flags, void __iomem *reg, u32 pll_offset, + u32 type, spinlock_t *lock) +{ + struct xgene_clk_pll *apmclk; + struct clk *clk; + struct clk_init_data init; + + /* allocate the APM clock structure */ + apmclk = kzalloc(sizeof(*apmclk), GFP_KERNEL); + if (!apmclk) { + pr_err("%s: could not allocate APM clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &xgene_clk_pll_ops; + init.flags = flags; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + apmclk->name = name; + apmclk->reg = reg; + apmclk->lock = lock; + apmclk->pll_offset = pll_offset; + apmclk->type = type; + apmclk->hw.init = &init; + + /* Register the clock */ + clk = clk_register(dev, &apmclk->hw); + if (IS_ERR(clk)) { + pr_err("%s: could not register clk %s\n", __func__, name); + kfree(apmclk); + return NULL; + } + return clk; +} + +static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_type) +{ + const char *clk_name = np->full_name; + struct clk *clk; + void *reg; + + reg = of_iomap(np, 0); + if (reg == NULL) { + pr_err("Unable to map CSR register for %s\n", np->full_name); + return; + } + of_property_read_string(np, "clock-output-names", &clk_name); + clk = xgene_register_clk_pll(NULL, + clk_name, of_clk_get_parent_name(np, 0), + CLK_IS_ROOT, reg, 0, pll_type, &clk_lock); + if (!IS_ERR(clk)) { + of_clk_add_provider(np, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + pr_debug("Add %s clock PLL\n", clk_name); + } +} + +static void xgene_socpllclk_init(struct device_node *np) +{ + xgene_pllclk_init(np, PLL_TYPE_SOC); +} + +static void xgene_pcppllclk_init(struct device_node *np) +{ + xgene_pllclk_init(np, PLL_TYPE_PCP); +} + +/* IP Clock */ +struct xgene_dev_parameters { + void __iomem *csr_reg; /* CSR for IP clock */ + u32 reg_clk_offset; /* Offset to clock enable CSR */ + u32 reg_clk_mask; /* Mask bit for clock enable */ + u32 reg_csr_offset; /* Offset to CSR reset */ + u32 reg_csr_mask; /* Mask bit for disable CSR reset */ + void __iomem *divider_reg; /* CSR for divider */ + u32 reg_divider_offset; /* Offset to divider register */ + u32 reg_divider_shift; /* Bit shift to divider field */ + u32 reg_divider_width; /* Width of the bit to divider field */ +}; + +struct xgene_clk { + struct clk_hw hw; + const char *name; + spinlock_t *lock; + struct xgene_dev_parameters param; +}; + +#define to_xgene_clk(_hw) container_of(_hw, struct xgene_clk, hw) + +static int xgene_clk_enable(struct clk_hw *hw) +{ + struct xgene_clk *pclk = to_xgene_clk(hw); + unsigned long flags = 0; + u32 data; + + if (pclk->lock) + spin_lock_irqsave(pclk->lock, flags); + + if (pclk->param.csr_reg != NULL) { + pr_debug("%s clock enabled\n", pclk->name); + /* First enable the clock */ + data = xgene_clk_read(pclk->param.csr_reg + + pclk->param.reg_clk_offset); + data |= pclk->param.reg_clk_mask; + xgene_clk_write(data, pclk->param.csr_reg + + pclk->param.reg_clk_offset); + pr_debug("%s clock PADDR base 0x%016LX clk offset 0x%08X mask 0x%08X value 0x%08X\n", + pclk->name, __pa(pclk->param.csr_reg), + pclk->param.reg_clk_offset, pclk->param.reg_clk_mask, + data); + + /* Second enable the CSR */ + data = xgene_clk_read(pclk->param.csr_reg + + pclk->param.reg_csr_offset); + data &= ~pclk->param.reg_csr_mask; + xgene_clk_write(data, pclk->param.csr_reg + + pclk->param.reg_csr_offset); + pr_debug("%s CSR RESET PADDR base 0x%016LX csr offset 0x%08X mask 0x%08X value 0x%08X\n", + pclk->name, __pa(pclk->param.csr_reg), + pclk->param.reg_csr_offset, pclk->param.reg_csr_mask, + data); + } + + if (pclk->lock) + spin_unlock_irqrestore(pclk->lock, flags); + + return 0; +} + +static void xgene_clk_disable(struct clk_hw *hw) +{ + struct xgene_clk *pclk = to_xgene_clk(hw); + unsigned long flags = 0; + u32 data; + + if (pclk->lock) + spin_lock_irqsave(pclk->lock, flags); + + if (pclk->param.csr_reg != NULL) { + pr_debug("%s clock disabled\n", pclk->name); + /* First put the CSR in reset */ + data = xgene_clk_read(pclk->param.csr_reg + + pclk->param.reg_csr_offset); + data |= pclk->param.reg_csr_mask; + xgene_clk_write(data, pclk->param.csr_reg + + pclk->param.reg_csr_offset); + + /* Second disable the clock */ + data = xgene_clk_read(pclk->param.csr_reg + + pclk->param.reg_clk_offset); + data &= ~pclk->param.reg_clk_mask; + xgene_clk_write(data, pclk->param.csr_reg + + pclk->param.reg_clk_offset); + } + + if (pclk->lock) + spin_unlock_irqrestore(pclk->lock, flags); +} + +static int xgene_clk_is_enabled(struct clk_hw *hw) +{ + struct xgene_clk *pclk = to_xgene_clk(hw); + u32 data = 0; + + if (pclk->param.csr_reg != NULL) { + pr_debug("%s clock checking\n", pclk->name); + data = xgene_clk_read(pclk->param.csr_reg + + pclk->param.reg_clk_offset); + pr_debug("%s clock is %s\n", pclk->name, + data & pclk->param.reg_clk_mask ? "enabled" : + "disabled"); + } + + if (pclk->param.csr_reg == NULL) + return 1; + return data & pclk->param.reg_clk_mask ? 1 : 0; +} + +static unsigned long xgene_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct xgene_clk *pclk = to_xgene_clk(hw); + u32 data; + + if (pclk->param.divider_reg) { + data = xgene_clk_read(pclk->param.divider_reg + + pclk->param.reg_divider_offset); + data >>= pclk->param.reg_divider_shift; + data &= (1 << pclk->param.reg_divider_width) - 1; + + pr_debug("%s clock recalc rate %ld parent %ld\n", + pclk->name, parent_rate / data, parent_rate); + return parent_rate / data; + } else { + pr_debug("%s clock recalc rate %ld parent %ld\n", + pclk->name, parent_rate, parent_rate); + return parent_rate; + } +} + +static int xgene_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct xgene_clk *pclk = to_xgene_clk(hw); + unsigned long flags = 0; + u32 data; + u32 divider; + u32 divider_save; + + if (pclk->lock) + spin_lock_irqsave(pclk->lock, flags); + + if (pclk->param.divider_reg) { + /* Let's compute the divider */ + if (rate > parent_rate) + rate = parent_rate; + divider_save = divider = parent_rate / rate; /* Rounded down */ + divider &= (1 << pclk->param.reg_divider_width) - 1; + divider <<= pclk->param.reg_divider_shift; + + /* Set new divider */ + data = xgene_clk_read(pclk->param.divider_reg + + pclk->param.reg_divider_offset); + data &= ~((1 << pclk->param.reg_divider_width) - 1); + data |= divider; + xgene_clk_write(data, pclk->param.divider_reg + + pclk->param.reg_divider_offset); + pr_debug("%s clock set rate %ld\n", pclk->name, + parent_rate / divider_save); + } else { + divider_save = 1; + } + + if (pclk->lock) + spin_unlock_irqrestore(pclk->lock, flags); + + return parent_rate / divider_save; +} + +static long xgene_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct xgene_clk *pclk = to_xgene_clk(hw); + unsigned long parent_rate = *prate; + u32 divider; + + if (pclk->param.divider_reg) { + /* Let's compute the divider */ + if (rate > parent_rate) + rate = parent_rate; + divider = parent_rate / rate; /* Rounded down */ + } else { + divider = 1; + } + + return parent_rate / divider; +} + +const struct clk_ops xgene_clk_ops = { + .enable = xgene_clk_enable, + .disable = xgene_clk_disable, + .is_enabled = xgene_clk_is_enabled, + .recalc_rate = xgene_clk_recalc_rate, + .set_rate = xgene_clk_set_rate, + .round_rate = xgene_clk_round_rate, +}; + +static struct clk *xgene_register_clk(struct device *dev, + const char *name, const char *parent_name, + struct xgene_dev_parameters *parameters, spinlock_t *lock) +{ + struct xgene_clk *apmclk; + struct clk *clk; + struct clk_init_data init; + int rc; + + /* allocate the APM clock structure */ + apmclk = kzalloc(sizeof(*apmclk), GFP_KERNEL); + if (!apmclk) { + pr_err("%s: could not allocate APM clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &xgene_clk_ops; + init.flags = 0; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + apmclk->name = name; + apmclk->lock = lock; + apmclk->hw.init = &init; + apmclk->param = *parameters; + + /* Register the clock */ + clk = clk_register(dev, &apmclk->hw); + if (IS_ERR(clk)) { + pr_err("%s: could not register clk %s\n", __func__, name); + kfree(apmclk); + return clk; + } + + /* Register the clock for lookup */ + rc = clk_register_clkdev(clk, name, NULL); + if (rc != 0) { + pr_err("%s: could not register lookup clk %s\n", + __func__, name); + } + return clk; +} + +static void __init xgene_devclk_init(struct device_node *np) +{ + const char *clk_name = np->full_name; + struct clk *clk; + struct resource res; + int rc; + struct xgene_dev_parameters parameters; + int i; + + /* Check if the entry is disabled */ + if (!of_device_is_available(np)) + return; + + /* Parse the DTS register for resource */ + parameters.csr_reg = NULL; + parameters.divider_reg = NULL; + for (i = 0; i < 2; i++) { + void *map_res; + rc = of_address_to_resource(np, i, &res); + if (rc != 0) { + if (i == 0) { + pr_err("no DTS register for %s\n", + np->full_name); + return; + } + break; + } + map_res = of_iomap(np, i); + if (map_res == NULL) { + pr_err("Unable to map resource %d for %s\n", + i, np->full_name); + goto err; + } + if (strcmp(res.name, "div-reg") == 0) + parameters.divider_reg = map_res; + else /* if (strcmp(res->name, "csr-reg") == 0) */ + parameters.csr_reg = map_res; + } + if (of_property_read_u32(np, "csr-offset", ¶meters.reg_csr_offset)) + parameters.reg_csr_offset = 0; + if (of_property_read_u32(np, "csr-mask", ¶meters.reg_csr_mask)) + parameters.reg_csr_mask = 0xF; + if (of_property_read_u32(np, "enable-offset", + ¶meters.reg_clk_offset)) + parameters.reg_clk_offset = 0x8; + if (of_property_read_u32(np, "enable-mask", ¶meters.reg_clk_mask)) + parameters.reg_clk_mask = 0xF; + if (of_property_read_u32(np, "divider-offset", + ¶meters.reg_divider_offset)) + parameters.reg_divider_offset = 0; + if (of_property_read_u32(np, "divider-width", + ¶meters.reg_divider_width)) + parameters.reg_divider_width = 0; + if (of_property_read_u32(np, "divider-shift", + ¶meters.reg_divider_shift)) + parameters.reg_divider_shift = 0; + of_property_read_string(np, "clock-output-names", &clk_name); + + clk = xgene_register_clk(NULL, clk_name, + of_clk_get_parent_name(np, 0), ¶meters, &clk_lock); + if (IS_ERR(clk)) + goto err; + pr_debug("Add %s clock\n", clk_name); + rc = of_clk_add_provider(np, of_clk_src_simple_get, clk); + if (rc != 0) + pr_err("%s: could register provider clk %s\n", __func__, + np->full_name); + + return; + +err: + if (parameters.csr_reg) + iounmap(parameters.csr_reg); + if (parameters.divider_reg) + iounmap(parameters.divider_reg); +} + +CLK_OF_DECLARE(xgene_socpll_clock, "apm,xgene-socpll-clock", xgene_socpllclk_init); +CLK_OF_DECLARE(xgene_pcppll_clock, "apm,xgene-pcppll-clock", xgene_pcppllclk_init); +CLK_OF_DECLARE(xgene_dev_clock, "apm,xgene-device-clock", xgene_devclk_init); -- 1.5.5 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v5 2/3] clk: arm64: Add DTS clock entry for APM X-Gene Storm SoC 2013-06-26 17:56 ` [PATCH v5 1/3] " Loc Ho @ 2013-06-26 17:56 ` Loc Ho 2013-06-26 17:56 ` [PATCH v5 3/3] Documentation: Add documentation for APM X-Gene clock binding Loc Ho 0 siblings, 1 reply; 6+ messages in thread From: Loc Ho @ 2013-06-26 17:56 UTC (permalink / raw) To: linux-arm-kernel clk: arm64: Add DTS clock entry for APM X-Gene Storm SoC with reference to reference, PCP PLL, SoC PLL, and Ethernet clocks. Signed-off-by: Loc Ho <lho@apm.com> Signed-off-by: Kumar Sankaran <ksankaran@apm.com> Signed-off-by: Vinayak Kale <vkale@apm.com> Signed-off-by: Feng Kan <fkan@apm.com> --- arch/arm64/boot/dts/apm-storm.dtsi | 75 ++++++++++++++++++++++++++++++++++++ 1 files changed, 75 insertions(+), 0 deletions(-) diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi index bfdc578..d37d736 100644 --- a/arch/arm64/boot/dts/apm-storm.dtsi +++ b/arch/arm64/boot/dts/apm-storm.dtsi @@ -103,6 +103,81 @@ #size-cells = <2>; ranges; + clocks { + #address-cells = <2>; + #size-cells = <2>; + ranges; + refclk: refclk { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <100000000>; + clock-output-names = "refclk"; + }; + + pcppll: pcppll at 17000100 { + compatible = "apm,xgene-pcppll-clock"; + #clock-cells = <1>; + clocks = <&refclk 0>; + clock-names = "pcppll"; + reg = <0x0 0x17000100 0x0 0x1000>; + clock-output-names = "pcppll"; + type = <0>; + }; + + socpll: socpll at 17000120 { + compatible = "apm,xgene-socpll-clock"; + #clock-cells = <1>; + clocks = <&refclk 0>; + clock-names = "socpll"; + reg = <0x0 0x17000120 0x0 0x1000>; + clock-output-names = "socpll"; + type = <1>; + }; + + socplldiv2: socplldiv2 { + compatible = "fixed-factor-clock"; + #clock-cells = <1>; + clocks = <&socpll 0>; + clock-names = "socplldiv2"; + clock-mult = <1>; + clock-div = <2>; + clock-output-names = "socplldiv2"; + }; + + qmlclk: qmlclk { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + clock-names = "qmlclk"; + reg = <0x0 0x1703C000 0x0 0x1000>; + reg-names = "csr-reg"; + clock-output-names = "qmlclk"; + }; + + ethclk: ethclk { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + clock-names = "ethclk"; + reg = <0x0 0x17000000 0x0 0x1000>; + reg-names = "div-reg"; + divider-offset = <0x238>; + divider-width = <0x9>; + divider-shift = <0x0>; + clock-output-names = "ethclk"; + }; + + eth8clk: eth8clk { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <ðclk 0>; + clock-names = "eth8clk"; + reg = <0x0 0x1702C000 0x0 0x1000>; + reg-names = "csr-reg"; + clock-output-names = "eth8clk"; + }; + }; + serial0: serial at 1c020000 { device_type = "serial"; compatible = "ns16550"; -- 1.5.5 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v5 3/3] Documentation: Add documentation for APM X-Gene clock binding 2013-06-26 17:56 ` [PATCH v5 2/3] clk: arm64: Add DTS clock entry for APM X-Gene Storm SoC Loc Ho @ 2013-06-26 17:56 ` Loc Ho 2013-07-25 20:59 ` Mike Turquette 0 siblings, 1 reply; 6+ messages in thread From: Loc Ho @ 2013-06-26 17:56 UTC (permalink / raw) To: linux-arm-kernel Documentation: Add documentation for APM X-Gene clock binding with PLL and device clocks. Signed-off-by: Loc Ho <lho@apm.com> Signed-off-by: Kumar Sankaran <ksankaran@apm.com> Signed-off-by: Vinayak Kale <vkale@apm.com> Signed-off-by: Feng Kan <fkan@apm.com> --- Documentation/devicetree/bindings/clock/xgene.txt | 111 +++++++++++++++++++++ 1 files changed, 111 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/xgene.txt diff --git a/Documentation/devicetree/bindings/clock/xgene.txt b/Documentation/devicetree/bindings/clock/xgene.txt new file mode 100644 index 0000000..1c4ef77 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/xgene.txt @@ -0,0 +1,111 @@ +Device Tree Clock bindings for APM X-Gene + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of the following: + "apm,xgene-socpll-clock" - for a X-Gene SoC PLL clock + "apm,xgene-pcppll-clock" - for a X-Gene PCP PLL clock + "apm,xgene-device-clock" - for a X-Gene device clock + +Required properties for SoC or PCP PLL clocks: +- reg : shall be the physical PLL register address for the pll clock. +- clocks : shall be the input parent clock phandle for the clock. This should + be the reference clock. +- #clock-cells : shall be set to 1. +- clock-output-names : shall be the name of the PLL referenced by derive + clock. +Optional properties for PLL clocks: +- clock-names : shall be the name of the PLL. If missing, use the device name. + +Required properties for device clocks: +- reg : shall be a list of address and length pairs describing the CSR + reset and/or the divider. Either may be omitted, but at least + one must be present. + - reg-names : shall be a string list describing the reg resource. This + may include "csr-reg" and/or "div-reg". If this property + is not present, the reg property is assumed to describe + only "csr-reg". +- clocks : shall be the input parent clock phandle for the clock. +- #clock-cells : shall be set to 1. +- clock-output-names : shall be the name of the device referenced. +Optional properties for device clocks: +- clock-names : shall be the name of the device clock. If missing, use the + device name. +- csr-offset : Offset to the CSR reset register from the reset address base. + Default is 0. +- csr-mask : CSR reset mask bit. Default is 0xF. +- enable-offset : Offset to the enable register from the reset address base. + Default is 0x8. +- enable-mask : CSR enable mask bit. Default is 0xF. +- divider-offset : Offset to the divider CSR register from the divider base. + Default is 0x0. +- divider-width : Width of the divider register. Default is 0. +- divider-shift : Bit shift of the divider register. Default is 0. + +For example: + + pcppll: pcppll at 17000100 { + compatible = "apm,xgene-pcppll-clock"; + #clock-cells = <1>; + clocks = <&refclk 0>; + clock-names = "pcppll"; + reg = <0x0 0x17000100 0x0 0x1000>; + clock-output-names = "pcppll"; + type = <0>; + }; + + socpll: socpll at 17000120 { + compatible = "apm,xgene-socpll-clock"; + #clock-cells = <1>; + clocks = <&refclk 0>; + clock-names = "socpll"; + reg = <0x0 0x17000120 0x0 0x1000>; + clock-output-names = "socpll"; + type = <1>; + }; + + qmlclk: qmlclk { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + clock-names = "qmlclk"; + reg = <0x0 0x1703C000 0x0 0x1000>; + reg-name = "csr-reg"; + clock-output-names = "qmlclk"; + }; + + ethclk: ethclk { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + clock-names = "ethclk"; + reg = <0x0 0x17000000 0x0 0x1000>; + reg-names = "div-reg"; + divider-offset = <0x238>; + divider-width = <0x9>; + divider-shift = <0x0>; + clock-output-names = "ethclk"; + }; + + apbclk: apbclk { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&ahbclk 0>; + clock-names = "apbclk"; + reg = <0x0 0x1F2AC000 0x0 0x1000 + 0x0 0x1F2AC000 0x0 0x1000>; + reg-names = "csr-reg", "div-reg"; + csr-offset = <0x0>; + csr-mask = <0x200>; + enable-offset = <0x8>; + enable-mask = <0x200>; + divider-offset = <0x10>; + divider-width = <0x2>; + divider-shift = <0x0>; + flags = <0x8>; + clock-output-names = "apbclk"; + }; + -- 1.5.5 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v5 3/3] Documentation: Add documentation for APM X-Gene clock binding 2013-06-26 17:56 ` [PATCH v5 3/3] Documentation: Add documentation for APM X-Gene clock binding Loc Ho @ 2013-07-25 20:59 ` Mike Turquette [not found] ` <CAPw-ZT=8TL2bJABd6_76JyZcDS+NTk+vJzj0YCGNNujKx+JqOA@mail.gmail.com> 0 siblings, 1 reply; 6+ messages in thread From: Mike Turquette @ 2013-07-25 20:59 UTC (permalink / raw) To: linux-arm-kernel Quoting Loc Ho (2013-06-26 10:56:11) > Documentation: Add documentation for APM X-Gene clock binding with PLL and > device clocks. > > Signed-off-by: Loc Ho <lho@apm.com> > Signed-off-by: Kumar Sankaran <ksankaran@apm.com> > Signed-off-by: Vinayak Kale <vkale@apm.com> > Signed-off-by: Feng Kan <fkan@apm.com> > --- > Documentation/devicetree/bindings/clock/xgene.txt | 111 +++++++++++++++++++++ > 1 files changed, 111 insertions(+), 0 deletions(-) > create mode 100644 Documentation/devicetree/bindings/clock/xgene.txt > > diff --git a/Documentation/devicetree/bindings/clock/xgene.txt b/Documentation/devicetree/bindings/clock/xgene.txt > new file mode 100644 > index 0000000..1c4ef77 > --- /dev/null > +++ b/Documentation/devicetree/bindings/clock/xgene.txt > @@ -0,0 +1,111 @@ > +Device Tree Clock bindings for APM X-Gene > + > +This binding uses the common clock binding[1]. > + > +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt > + > +Required properties: > +- compatible : shall be one of the following: > + "apm,xgene-socpll-clock" - for a X-Gene SoC PLL clock > + "apm,xgene-pcppll-clock" - for a X-Gene PCP PLL clock > + "apm,xgene-device-clock" - for a X-Gene device clock > + > +Required properties for SoC or PCP PLL clocks: > +- reg : shall be the physical PLL register address for the pll clock. > +- clocks : shall be the input parent clock phandle for the clock. This should > + be the reference clock. > +- #clock-cells : shall be set to 1. > +- clock-output-names : shall be the name of the PLL referenced by derive > + clock. > +Optional properties for PLL clocks: > +- clock-names : shall be the name of the PLL. If missing, use the device name. > + > +Required properties for device clocks: > +- reg : shall be a list of address and length pairs describing the CSR > + reset and/or the divider. Either may be omitted, but at least > + one must be present. > + - reg-names : shall be a string list describing the reg resource. This > + may include "csr-reg" and/or "div-reg". If this property > + is not present, the reg property is assumed to describe > + only "csr-reg". Where is reg-names used? I see it used in your DTS but I don't see clk-xgene.c doing anything with it. > +- clocks : shall be the input parent clock phandle for the clock. > +- #clock-cells : shall be set to 1. > +- clock-output-names : shall be the name of the device referenced. > +Optional properties for device clocks: > +- clock-names : shall be the name of the device clock. If missing, use the > + device name. > +- csr-offset : Offset to the CSR reset register from the reset address base. > + Default is 0. > +- csr-mask : CSR reset mask bit. Default is 0xF. > +- enable-offset : Offset to the enable register from the reset address base. > + Default is 0x8. > +- enable-mask : CSR enable mask bit. Default is 0xF. > +- divider-offset : Offset to the divider CSR register from the divider base. > + Default is 0x0. > +- divider-width : Width of the divider register. Default is 0. > +- divider-shift : Bit shift of the divider register. Default is 0. There is a general push to not have register-level details in DT. How many clocks do you think you'll end up defining in the future? If you have a lot then this binding could grow fairly large. Regards, Mike > + > +For example: > + > + pcppll: pcppll at 17000100 { > + compatible = "apm,xgene-pcppll-clock"; > + #clock-cells = <1>; > + clocks = <&refclk 0>; > + clock-names = "pcppll"; > + reg = <0x0 0x17000100 0x0 0x1000>; > + clock-output-names = "pcppll"; > + type = <0>; > + }; > + > + socpll: socpll at 17000120 { > + compatible = "apm,xgene-socpll-clock"; > + #clock-cells = <1>; > + clocks = <&refclk 0>; > + clock-names = "socpll"; > + reg = <0x0 0x17000120 0x0 0x1000>; > + clock-output-names = "socpll"; > + type = <1>; > + }; > + > + qmlclk: qmlclk { > + compatible = "apm,xgene-device-clock"; > + #clock-cells = <1>; > + clocks = <&socplldiv2 0>; > + clock-names = "qmlclk"; > + reg = <0x0 0x1703C000 0x0 0x1000>; > + reg-name = "csr-reg"; > + clock-output-names = "qmlclk"; > + }; > + > + ethclk: ethclk { > + compatible = "apm,xgene-device-clock"; > + #clock-cells = <1>; > + clocks = <&socplldiv2 0>; > + clock-names = "ethclk"; > + reg = <0x0 0x17000000 0x0 0x1000>; > + reg-names = "div-reg"; > + divider-offset = <0x238>; > + divider-width = <0x9>; > + divider-shift = <0x0>; > + clock-output-names = "ethclk"; > + }; > + > + apbclk: apbclk { > + compatible = "apm,xgene-device-clock"; > + #clock-cells = <1>; > + clocks = <&ahbclk 0>; > + clock-names = "apbclk"; > + reg = <0x0 0x1F2AC000 0x0 0x1000 > + 0x0 0x1F2AC000 0x0 0x1000>; > + reg-names = "csr-reg", "div-reg"; > + csr-offset = <0x0>; > + csr-mask = <0x200>; > + enable-offset = <0x8>; > + enable-mask = <0x200>; > + divider-offset = <0x10>; > + divider-width = <0x2>; > + divider-shift = <0x0>; > + flags = <0x8>; > + clock-output-names = "apbclk"; > + }; > + > -- > 1.5.5 ^ permalink raw reply [flat|nested] 6+ messages in thread
[parent not found: <CAPw-ZT=8TL2bJABd6_76JyZcDS+NTk+vJzj0YCGNNujKx+JqOA@mail.gmail.com>]
* [PATCH v5 3/3] Documentation: Add documentation for APM X-Gene clock binding [not found] ` <CAPw-ZT=8TL2bJABd6_76JyZcDS+NTk+vJzj0YCGNNujKx+JqOA@mail.gmail.com> @ 2013-10-07 7:58 ` Mike Turquette 0 siblings, 0 replies; 6+ messages in thread From: Mike Turquette @ 2013-10-07 7:58 UTC (permalink / raw) To: linux-arm-kernel Quoting Loc Ho (2013-07-31 11:49:07) > With the latest version, this is used to determine whether it is > divider register or csr register. In the file clk-xgene.c, grep for > "div-reg". It is around line 521. Thanks for the rework, I've taken this for 3.13. Regards, Mike ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2013-10-07 7:58 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-26 17:56 [PATCH v5 0/3] clk: Add APM X-Gene SoC clock driver Loc Ho
2013-06-26 17:56 ` [PATCH v5 1/3] " Loc Ho
2013-06-26 17:56 ` [PATCH v5 2/3] clk: arm64: Add DTS clock entry for APM X-Gene Storm SoC Loc Ho
2013-06-26 17:56 ` [PATCH v5 3/3] Documentation: Add documentation for APM X-Gene clock binding Loc Ho
2013-07-25 20:59 ` Mike Turquette
[not found] ` <CAPw-ZT=8TL2bJABd6_76JyZcDS+NTk+vJzj0YCGNNujKx+JqOA@mail.gmail.com>
2013-10-07 7:58 ` Mike Turquette
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).