From patchwork Tue Oct 18 15:46:04 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tero Kristo X-Patchwork-Id: 9382507 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A0FAA600CA for ; Tue, 18 Oct 2016 15:54:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8E80C29672 for ; Tue, 18 Oct 2016 15:54:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 832E229679; Tue, 18 Oct 2016 15:54:07 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 563B929672 for ; Tue, 18 Oct 2016 15:54:06 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bwWgi-0002b0-T6; Tue, 18 Oct 2016 15:52:24 +0000 Received: from comal.ext.ti.com ([198.47.26.152]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bwWbh-0006Fo-As for linux-arm-kernel@lists.infradead.org; Tue, 18 Oct 2016 15:47:19 +0000 Received: from dflxv15.itg.ti.com ([128.247.5.124]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id u9IFkr1c026787; Tue, 18 Oct 2016 10:46:53 -0500 Received: from DLEE71.ent.ti.com (dlee71.ent.ti.com [157.170.170.114]) by dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id u9IFkrZT023715; Tue, 18 Oct 2016 10:46:53 -0500 Received: from dlep33.itg.ti.com (157.170.170.75) by DLEE71.ent.ti.com (157.170.170.114) with Microsoft SMTP Server id 14.3.294.0; Tue, 18 Oct 2016 10:46:53 -0500 Received: from gomoku.home (ileax41-snat.itg.ti.com [10.172.224.153]) by dlep33.itg.ti.com (8.14.3/8.13.8) with ESMTP id u9IFkJXG006114; Tue, 18 Oct 2016 10:46:46 -0500 From: Tero Kristo To: , , , , Subject: [PATCHv4 11/15] clk: ti: clockdomain: add clock provider support to clockdomains Date: Tue, 18 Oct 2016 18:46:04 +0300 Message-ID: <1476805568-19264-12-git-send-email-t-kristo@ti.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1476805568-19264-1-git-send-email-t-kristo@ti.com> References: <1476805568-19264-1-git-send-email-t-kristo@ti.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161018_084714_031244_4989E8DE X-CRM114-Status: GOOD ( 20.01 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Clockdomains can now be used as clock providers in the system. This patch initializes the provider data during init, and parses the clocks while they are being registered. An xlate function for the provider is also given. Signed-off-by: Tero Kristo Acked-by: Tony Lindgren --- .../devicetree/bindings/arm/omap/prcm.txt | 13 ++ .../devicetree/bindings/clock/ti/clockdomain.txt | 12 +- arch/arm/mach-omap2/io.c | 2 + drivers/clk/ti/clock.h | 1 + drivers/clk/ti/clockdomain.c | 147 +++++++++++++++++++++ include/linux/clk/ti.h | 3 + 6 files changed, 177 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/omap/prcm.txt b/Documentation/devicetree/bindings/arm/omap/prcm.txt index 3eb6d7a..301f576 100644 --- a/Documentation/devicetree/bindings/arm/omap/prcm.txt +++ b/Documentation/devicetree/bindings/arm/omap/prcm.txt @@ -47,6 +47,19 @@ cm: cm@48004000 { }; } +cm2: cm2@8000 { + compatible = "ti,omap4-cm2"; + reg = <0x8000 0x3000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x8000 0x3000>; + + l4_per_clkdm: l4_per_clkdm { + compatible = "ti,clockdomain"; + reg = <0x1400 0x200>; + }; +}; + &cm_clocks { omap2_32k_fck: omap_32k_fck { #clock-cells = <0>; diff --git a/Documentation/devicetree/bindings/clock/ti/clockdomain.txt b/Documentation/devicetree/bindings/clock/ti/clockdomain.txt index cb76b3f..5d8ca61 100644 --- a/Documentation/devicetree/bindings/clock/ti/clockdomain.txt +++ b/Documentation/devicetree/bindings/clock/ti/clockdomain.txt @@ -14,11 +14,21 @@ hardware hierarchy. Required properties: - compatible : shall be "ti,clockdomain" -- #clock-cells : from common clock binding; shall be set to 0. +- #clock-cells : from common clock binding; shall be set to 1 if this + clockdomain acts as a clock provider. + +Optional properties: - clocks : link phandles of clocks within this domain +- reg : address for the clockdomain Examples: dss_clkdm: dss_clkdm { compatible = "ti,clockdomain"; clocks = <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>; }; + + l4_per_clkdm: l4_per_clkdm { + compatible = "ti,clockdomain"; + #clock-cells = <1>; + reg = <0x1400 0x200>; + }; diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 0e9acdd..c1a5cfb 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -794,6 +794,8 @@ int __init omap_clk_init(void) if (ret) return ret; + ti_dt_clockdomains_early_setup(); + of_clk_init(NULL); ti_dt_clk_init_retry_clks(); diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 9b8a5f2..f6383ab 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -205,6 +205,7 @@ struct clk *ti_clk_register(struct device *dev, struct clk_hw *hw, int ti_clk_get_memmap_index(struct device_node *node); void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index); +void __iomem *ti_clk_get_reg_addr_clkdm(const char *clkdm_name, u16 offset); void ti_dt_clocks_register(struct ti_dt_clk *oclks); int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, ti_of_clk_init_cb_t func); diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c index 704157d..7b0a6c3 100644 --- a/drivers/clk/ti/clockdomain.c +++ b/drivers/clk/ti/clockdomain.c @@ -28,6 +28,23 @@ #define pr_fmt(fmt) "%s: " fmt, __func__ /** + * struct ti_clkdm - TI clockdomain data structure + * @name: name of the clockdomain + * @index: index of the clk_iomap struct for this clkdm + * @offset: clockdomain offset from the beginning of the iomap + * @link: link to the list + */ +struct ti_clkdm { + const char *name; + int index; + u32 offset; + struct list_head link; + struct list_head clocks; +}; + +static LIST_HEAD(clkdms); + +/** * omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw * @hw: struct clk_hw * of the clock being enabled * @@ -116,6 +133,8 @@ void omap2_init_clk_clkdm(struct clk_hw *hw) struct clk_hw_omap *clk = to_clk_hw_omap(hw); struct clockdomain *clkdm; const char *clk_name; + struct ti_clkdm *ti_clkdm; + bool match = false; if (!clk->clkdm_name) return; @@ -130,7 +149,21 @@ void omap2_init_clk_clkdm(struct clk_hw *hw) } else { pr_debug("clock: could not associate clk %s to clkdm %s\n", clk_name, clk->clkdm_name); + return; } + + list_for_each_entry(ti_clkdm, &clkdms, link) { + if (!strcmp(ti_clkdm->name, clk->clkdm_name)) { + match = true; + break; + } + } + + if (!match) + return; + + /* Add clock to the list of provided clocks */ + list_add(&clk->clkdm_link, &ti_clkdm->clocks); } static void __init of_ti_clockdomain_setup(struct device_node *node) @@ -161,11 +194,125 @@ static void __init of_ti_clockdomain_setup(struct device_node *node) } } +static struct clk_hw *clkdm_clk_xlate(struct of_phandle_args *clkspec, + void *data) +{ + struct ti_clkdm *clkdm = data; + struct clk_hw_omap *clk; + u16 offset = clkspec->args[0]; + + list_for_each_entry(clk, &clkdm->clocks, clkdm_link) + if (((u32)clk->enable_reg & 0xffff) - clkdm->offset == offset) + return &clk->hw; + + return ERR_PTR(-EINVAL); +} + +static int ti_clk_register_clkdm(struct device_node *node) +{ + u64 clkdm_addr; + u64 inst_addr; + const __be32 *reg; + u32 offset; + int idx; + struct ti_clkdm *clkdm; + int ret; + + reg = of_get_address(node, 0, NULL, NULL); + if (!reg) + return -ENOENT; + + clkdm_addr = of_translate_address(node, reg); + + reg = of_get_address(node->parent, 0, NULL, NULL); + if (!reg) + return -EINVAL; + + inst_addr = of_translate_address(node->parent, reg); + + offset = clkdm_addr - inst_addr; + + idx = ti_clk_get_memmap_index(node->parent); + + if (idx < 0) { + pr_err("bad memmap index for %s\n", node->name); + return idx; + } + + clkdm = kzalloc(sizeof(*clkdm), GFP_KERNEL); + if (!clkdm) + return -ENOMEM; + + clkdm->name = node->name; + clkdm->index = idx; + clkdm->offset = offset; + + INIT_LIST_HEAD(&clkdm->clocks); + + list_add(&clkdm->link, &clkdms); + + ret = of_clk_add_hw_provider(node, clkdm_clk_xlate, clkdm); + if (ret) { + list_del(&clkdm->link); + kfree(clkdm); + return ret; + } + + return 0; +} + +/** + * ti_clk_get_reg_addr_clkdm - get register address relative to clockdomain + * @clkdm_name: parent clockdomain + * @offset: offset from the clockdomain + * + * Gets a register address relative to parent clockdomain. Searches the + * list of available clockdomain, and if match is found, calculates the + * register address from the iomap relative to the clockdomain. + * Returns the register address, or NULL if not found. + */ +void __iomem *ti_clk_get_reg_addr_clkdm(const char *clkdm_name, u16 offset) +{ + u32 reg; + struct clk_omap_reg *reg_setup; + struct ti_clkdm *clkdm; + bool match = false; + + reg_setup = (struct clk_omap_reg *)® + + /* XXX: get offset from clkdm, get base for instance */ + list_for_each_entry(clkdm, &clkdms, link) { + if (!strcmp(clkdm->name, clkdm_name)) { + match = true; + break; + } + } + + if (!match) { + pr_err("%s: no entry for %s\n", __func__, clkdm_name); + return NULL; + } + + reg_setup->offset = clkdm->offset + offset; + reg_setup->index = clkdm->index; + + return (void __iomem *)reg; +} + static const struct of_device_id ti_clkdm_match_table[] __initconst = { { .compatible = "ti,clockdomain" }, { } }; +void __init ti_dt_clockdomains_early_setup(void) +{ + struct device_node *np; + + for_each_matching_node(np, ti_clkdm_match_table) { + ti_clk_register_clkdm(np); + } +} + /** * ti_dt_clockdomains_setup - setup device tree clockdomains * diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 626ae94..afccb48 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -125,6 +125,7 @@ struct clk_hw_omap_ops { /** * struct clk_hw_omap - OMAP struct clk * @node: list_head connecting this clock into the full clock list + * @clkdm_link: list_head connecting this clock into the clockdomain * @enable_reg: register to write to enable the clock (see @enable_bit) * @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg) * @flags: see "struct clk.flags possibilities" above @@ -137,6 +138,7 @@ struct clk_hw_omap_ops { struct clk_hw_omap { struct clk_hw hw; struct list_head node; + struct list_head clkdm_link; unsigned long fixed_rate; u8 fixed_div; void __iomem *enable_reg; @@ -251,6 +253,7 @@ int omap2_reprogram_dpllcore(struct clk_hw *clk, unsigned long rate, unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk); void ti_dt_clk_init_retry_clks(void); +void ti_dt_clockdomains_early_setup(void); void ti_dt_clockdomains_setup(void); int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops);