aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiko Stuebner <heiko@sntech.de>2015-08-19 09:06:55 -0400
committerMichael Turquette <mturquette@baylibre.com>2015-08-24 19:49:15 -0400
commit10897370345b792c00ccba6aa7ea86ae6bfa2c7a (patch)
tree55a74d034e9fe791976ccf2d0f9a00dde649420a
parent67c9a1b5dadf05e22d7e2d32604fb2b21bf3f666 (diff)
clk: rockchip: register pll mux before pll itself
The structure is xin24m -> pll -> pll-mux (xin24m,pll,xin32k). The pll does have an init callback to make sure the boot-selected frequency is using the expected pll settings and resets the same frequency using the values provided in the driver if necessary. The setting itself also involves remuxing the pll-mux temporarily to the xin24m source to let the new pll rate settle. Until now this worked flawlessly, even when it had the flaw of accessing the mux settings before the mux actually got registered. With the recent clock-core conversions this flaw became apparent in null pointer dereference in [<c03fc400>] (clk_hw_get_num_parents) from [<c0400df0>] (clk_mux_get_parent+0x14/0xc8) [<c0400ddc>] (clk_mux_get_parent) from [<c040246c>] (rockchip_rk3066_pll_set_rate+0xd8/0x320) So to fix that, simply register the pll-mux before the pll, so that it will be fully initialized when the pll clock executes its init- callback and possibly touches the pll-mux clock. Signed-off-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Michael Turquette <mturquette@baylibre.com>
-rw-r--r--drivers/clk/rockchip/clk-pll.c63
1 files changed, 32 insertions, 31 deletions
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index eab430452c52..7737a1df1e4b 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -353,6 +353,35 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
353 if (!pll) 353 if (!pll)
354 return ERR_PTR(-ENOMEM); 354 return ERR_PTR(-ENOMEM);
355 355
356 /* create the mux on top of the real pll */
357 pll->pll_mux_ops = &clk_mux_ops;
358 pll_mux = &pll->pll_mux;
359 pll_mux->reg = base + mode_offset;
360 pll_mux->shift = mode_shift;
361 pll_mux->mask = PLL_MODE_MASK;
362 pll_mux->flags = 0;
363 pll_mux->lock = lock;
364 pll_mux->hw.init = &init;
365
366 if (pll_type == pll_rk3066)
367 pll_mux->flags |= CLK_MUX_HIWORD_MASK;
368
369 /* the actual muxing is xin24m, pll-output, xin32k */
370 pll_parents[0] = parent_names[0];
371 pll_parents[1] = pll_name;
372 pll_parents[2] = parent_names[1];
373
374 init.name = name;
375 init.flags = CLK_SET_RATE_PARENT;
376 init.ops = pll->pll_mux_ops;
377 init.parent_names = pll_parents;
378 init.num_parents = ARRAY_SIZE(pll_parents);
379
380 mux_clk = clk_register(NULL, &pll_mux->hw);
381 if (IS_ERR(mux_clk))
382 goto err_mux;
383
384 /* now create the actual pll */
356 init.name = pll_name; 385 init.name = pll_name;
357 386
358 /* keep all plls untouched for now */ 387 /* keep all plls untouched for now */
@@ -398,47 +427,19 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
398 pll->flags = clk_pll_flags; 427 pll->flags = clk_pll_flags;
399 pll->lock = lock; 428 pll->lock = lock;
400 429
401 /* create the mux on top of the real pll */
402 pll->pll_mux_ops = &clk_mux_ops;
403 pll_mux = &pll->pll_mux;
404 pll_mux->reg = base + mode_offset;
405 pll_mux->shift = mode_shift;
406 pll_mux->mask = PLL_MODE_MASK;
407 pll_mux->flags = 0;
408 pll_mux->lock = lock;
409 pll_mux->hw.init = &init;
410
411 if (pll_type == pll_rk3066)
412 pll_mux->flags |= CLK_MUX_HIWORD_MASK;
413
414 pll_clk = clk_register(NULL, &pll->hw); 430 pll_clk = clk_register(NULL, &pll->hw);
415 if (IS_ERR(pll_clk)) { 431 if (IS_ERR(pll_clk)) {
416 pr_err("%s: failed to register pll clock %s : %ld\n", 432 pr_err("%s: failed to register pll clock %s : %ld\n",
417 __func__, name, PTR_ERR(pll_clk)); 433 __func__, name, PTR_ERR(pll_clk));
418 mux_clk = pll_clk;
419 goto err_pll; 434 goto err_pll;
420 } 435 }
421 436
422 /* the actual muxing is xin24m, pll-output, xin32k */
423 pll_parents[0] = parent_names[0];
424 pll_parents[1] = pll_name;
425 pll_parents[2] = parent_names[1];
426
427 init.name = name;
428 init.flags = CLK_SET_RATE_PARENT;
429 init.ops = pll->pll_mux_ops;
430 init.parent_names = pll_parents;
431 init.num_parents = ARRAY_SIZE(pll_parents);
432
433 mux_clk = clk_register(NULL, &pll_mux->hw);
434 if (IS_ERR(mux_clk))
435 goto err_mux;
436
437 return mux_clk; 437 return mux_clk;
438 438
439err_mux:
440 clk_unregister(pll_clk);
441err_pll: 439err_pll:
440 clk_unregister(mux_clk);
441 mux_clk = pll_clk;
442err_mux:
442 kfree(pll); 443 kfree(pll);
443 return mux_clk; 444 return mux_clk;
444} 445}