From c08ee14cc6634457948bc5e26584697208baa02a Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 12 Sep 2014 15:01:57 +0300 Subject: clk: ti: change clock init to use generic of_clk_init Previously, the TI clock driver initialized all the clocks hierarchically under each separate clock provider node. Now, each clock that requires IO access will instead check their parent node to find out which IO range to use. This patch allows the TI clock driver to use a few new features provided by the generic of_clk_init, and also allows registration of clock nodes outside the clock hierarchy (for example, any external clocks.) Signed-off-by: Tero Kristo Cc: Mike Turquette Cc: Paul Walmsley Cc: Tony Lindgren Cc: Mark Rutland Cc: Peter Ujfalusi Cc: Jyri Sarha Cc: Stefan Assmann Acked-by: Tony Lindgren --- drivers/clk/ti/clk.c | 68 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 25 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index b1a6f71..337abe5 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -25,8 +25,8 @@ #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ -static int ti_dt_clk_memmap_index; struct ti_clk_ll_ops *ti_clk_ll_ops; +static struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS]; /** * ti_dt_clocks_register - register DT alias clocks during boot @@ -108,9 +108,21 @@ void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) struct clk_omap_reg *reg; u32 val; u32 tmp; + int i; reg = (struct clk_omap_reg *)&tmp; - reg->index = ti_dt_clk_memmap_index; + + for (i = 0; i < CLK_MAX_MEMMAPS; i++) { + if (clocks_node_ptr[i] == node->parent) + break; + } + + if (i == CLK_MAX_MEMMAPS) { + pr_err("clk-provider not found for %s!\n", node->name); + return NULL; + } + + reg->index = i; if (of_property_read_u32_index(node, "reg", index, &val)) { pr_err("%s must have reg[%d]!\n", node->name, index); @@ -127,20 +139,14 @@ void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) * @parent: master node * @index: internal index for clk_reg_ops * - * Initializes a master clock IP block and its child clock nodes. - * Regmap is provided for accessing the register space for the - * IP block and all the clocks under it. + * Initializes a master clock IP block. This basically sets up the + * mapping from clocks node to the memory map index. All the clocks + * are then initialized through the common of_clk_init call, and the + * clocks will access their memory maps based on the node layout. */ void ti_dt_clk_init_provider(struct device_node *parent, int index) { - const struct of_device_id *match; - struct device_node *np; struct device_node *clocks; - of_clk_init_cb_t clk_init_cb; - struct clk_init_item *retry; - struct clk_init_item *tmp; - - ti_dt_clk_memmap_index = index; /* get clocks for this parent */ clocks = of_get_child_by_name(parent, "clocks"); @@ -149,19 +155,31 @@ void ti_dt_clk_init_provider(struct device_node *parent, int index) return; } - for_each_child_of_node(clocks, np) { - match = of_match_node(&__clk_of_table, np); - if (!match) - continue; - clk_init_cb = (of_clk_init_cb_t)match->data; - pr_debug("%s: initializing: %s\n", __func__, np->name); - clk_init_cb(np); - } + /* add clocks node info */ + clocks_node_ptr[index] = clocks; +} - list_for_each_entry_safe(retry, tmp, &retry_list, link) { - pr_debug("retry-init: %s\n", retry->node->name); - retry->func(retry->hw, retry->node); - list_del(&retry->link); - kfree(retry); +/** + * ti_dt_clk_init_retry_clks - init clocks from the retry list + * + * Initializes any clocks that have failed to initialize before, + * reasons being missing parent node(s) during earlier init. This + * typically happens only for DPLLs which need to have both of their + * parent clocks ready during init. + */ +void ti_dt_clk_init_retry_clks(void) +{ + struct clk_init_item *retry; + struct clk_init_item *tmp; + int retries = 5; + + while (!list_empty(&retry_list) && retries) { + list_for_each_entry_safe(retry, tmp, &retry_list, link) { + pr_debug("retry-init: %s\n", retry->node->name); + retry->func(retry->hw, retry->node); + list_del(&retry->link); + kfree(retry); + } + retries--; } } -- cgit v1.1 From 73b5d5f711f35617ff701bd88e887d3a1187e82b Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 12 Sep 2014 16:39:07 +0300 Subject: clk: ti: dra7-atl-clock: fix a memory leak of_clk_add_provider makes an internal copy of the parent_names property while its called, thus it is no longer needed after this call and can be freed. Signed-off-by: Tero Kristo Cc: Mike Turquette Cc: Peter Ujfalusi Acked-by: Peter Ujfalusi --- drivers/clk/ti/clk-dra7-atl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/clk') diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c index 4a65b41..3f9308a 100644 --- a/drivers/clk/ti/clk-dra7-atl.c +++ b/drivers/clk/ti/clk-dra7-atl.c @@ -199,6 +199,7 @@ static void __init of_dra7_atl_clock_setup(struct device_node *node) if (!IS_ERR(clk)) { of_clk_add_provider(node, of_clk_src_simple_get, clk); + kfree(parent_names); return; } cleanup: -- cgit v1.1 From 319f1276f9a392526d2f40ecd76c1c829d0cf5fa Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 18 Sep 2014 16:33:27 +0200 Subject: clk: ti: consider the fact that of_clk_get() might return an error I "forgot" to update the dtb and the kernel crashed: |Unable to handle kernel NULL pointer dereference at virtual address 0000002e |PC is at __clk_get_flags+0x4/0xc |LR is at ti_dt_clockdomains_setup+0x70/0xe8 because I did not have the clock nodes. of_clk_get() returns an error pointer which is not checked here. Acked-by: Nishanth Menon Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Tero Kristo --- drivers/clk/ti/clockdomain.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/clk') diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c index f1e0038..b4c5fac 100644 --- a/drivers/clk/ti/clockdomain.c +++ b/drivers/clk/ti/clockdomain.c @@ -36,6 +36,11 @@ static void __init of_ti_clockdomain_setup(struct device_node *node) for (i = 0; i < num_clks; i++) { clk = of_clk_get(node, i); + if (IS_ERR(clk)) { + pr_err("%s: Failed get %s' clock nr %d (%ld)\n", + __func__, node->full_name, i, PTR_ERR(clk)); + continue; + } if (__clk_get_flags(clk) & CLK_IS_BASIC) { pr_warn("can't setup clkdm for basic clk %s\n", __clk_get_name(clk)); -- cgit v1.1 From e8627a9ec397dd55f650e54e4956e25cfa8aab7c Mon Sep 17 00:00:00 2001 From: Behan Webster Date: Fri, 26 Sep 2014 17:31:48 -0700 Subject: clk: ti: LLVMLinux: Move __init outside of type definition As written, the __init for ti_clk_get_div_table is in the middle of the return type. The gcc documentation indicates that section attributes should be added to the end of the function declaration: extern void foobar (void) __attribute__ ((section ("bar"))); However gcc seems to be very permissive with where attributes can be placed. clang on the other hand isn't so permissive, and fails if you put the section definition in the middle of the return type: drivers/clk/ti/divider.c:298:28: error: expected ';' after struct static struct clk_div_table ^ ; drivers/clk/ti/divider.c:298:1: warning: 'static' ignored on this declaration [-Wmissing-declarations] static struct clk_div_table ^ drivers/clk/ti/divider.c:299:9: error: type specifier missing, defaults to 'int' [-Werror,-Wimplicit-int] __init *ti_clk_get_div_table(struct device_node *node) ~~~~~~ ^ drivers/clk/ti/divider.c:345:9: warning: incompatible pointer types returning 'struct clk_div_table *' from a function with result type 'int *' [-Wincompatible-pointer-types] return table; ^~~~~ drivers/clk/ti/divider.c:419:9: warning: incompatible pointer types assigning to 'const struct clk_div_table *' from 'int *' [-Wincompatible-pointer-types] *table = ti_clk_get_div_table(node); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 warnings and 2 errors generated. By convention, most of the kernel code puts section attributes between the return type and function name. In the case where the return type is a pointer, it's important to place the '*' on left of the __init. This updated code works for both gcc and clang. Signed-off-by: Behan Webster Reviewed-by: Mark Charlebois Reviewed-by: Felipe Balbi Signed-off-by: Tero Kristo --- drivers/clk/ti/divider.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index e6aa10d..636061e 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -295,8 +295,8 @@ static struct clk *_register_divider(struct device *dev, const char *name, return clk; } -static struct clk_div_table -__init *ti_clk_get_div_table(struct device_node *node) +static struct clk_div_table * +__init ti_clk_get_div_table(struct device_node *node) { struct clk_div_table *table; const __be32 *divspec; -- cgit v1.1 From 04ed831f224d4553682f48e1b4a6b68f2622b68e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 29 Sep 2014 11:10:33 +0300 Subject: clk: ti: dra7-atl-clock: Mark the device as pm_runtime_irq_safe It is safe to call the pm sync calls in interrupt context in this driver. Signed-off-by: Peter Ujfalusi Signed-off-by: Tero Kristo --- drivers/clk/ti/clk-dra7-atl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/clk') diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c index 3f9308a..c375cfb 100644 --- a/drivers/clk/ti/clk-dra7-atl.c +++ b/drivers/clk/ti/clk-dra7-atl.c @@ -225,6 +225,7 @@ static int of_dra7_atl_clk_probe(struct platform_device *pdev) cinfo->iobase = of_iomap(node, 0); cinfo->dev = &pdev->dev; pm_runtime_enable(cinfo->dev); + pm_runtime_irq_safe(cinfo->dev); pm_runtime_get_sync(cinfo->dev); atl_write(cinfo, DRA7_ATL_PCLKMUX_REG(0), DRA7_ATL_PCLKMUX); -- cgit v1.1