Skip to content

Commit 58ee6ba

Browse files
tretterbebarino
authored andcommitted
soc: xilinx: vcu: make the PLL configurable
Do not configure the PLL when probing the driver, but register the clock in the clock framework and do the configuration based on the respective callbacks. This is necessary to allow the consumers, i.e., encoder and decoder drivers, of the xlnx_vcu clock provider to set the clock rate and actually enable the clocks without relying on some pre-configuration. Signed-off-by: Michael Tretter <m.tretter@pengutronix.de> Acked-by: Michal Simek <michal.simek@xilinx.com> Link: https://lore.kernel.org/r/20210121071659.1226489-11-m.tretter@pengutronix.de Signed-off-by: Stephen Boyd <sboyd@kernel.org>
1 parent 4472e18 commit 58ee6ba

1 file changed

Lines changed: 103 additions & 37 deletions

File tree

drivers/soc/xilinx/xlnx_vcu.c

Lines changed: 103 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,18 @@ static void xvcu_write_field_reg(void __iomem *iomem, int offset,
260260
xvcu_write(iomem, offset, val);
261261
}
262262

263-
static int xvcu_pll_wait_for_lock(struct xvcu_device *xvcu)
263+
#define to_vcu_pll(_hw) container_of(_hw, struct vcu_pll, hw)
264+
265+
struct vcu_pll {
266+
struct clk_hw hw;
267+
void __iomem *reg_base;
268+
unsigned long fvco_min;
269+
unsigned long fvco_max;
270+
};
271+
272+
static int xvcu_pll_wait_for_lock(struct vcu_pll *pll)
264273
{
265-
void __iomem *base = xvcu->vcu_slcr_ba;
274+
void __iomem *base = pll->reg_base;
266275
unsigned long timeout;
267276
u32 lock_status;
268277

@@ -311,9 +320,9 @@ static const struct xvcu_pll_cfg *xvcu_find_cfg(int div)
311320
return cfg;
312321
}
313322

314-
static int xvcu_pll_set_div(struct xvcu_device *xvcu, int div)
323+
static int xvcu_pll_set_div(struct vcu_pll *pll, int div)
315324
{
316-
void __iomem *base = xvcu->vcu_slcr_ba;
325+
void __iomem *base = pll->reg_base;
317326
const struct xvcu_pll_cfg *cfg = NULL;
318327
u32 vcu_pll_ctrl;
319328
u32 cfg_val;
@@ -338,24 +347,49 @@ static int xvcu_pll_set_div(struct xvcu_device *xvcu, int div)
338347
return 0;
339348
}
340349

341-
static int xvcu_pll_set_rate(struct xvcu_device *xvcu,
350+
static long xvcu_pll_round_rate(struct clk_hw *hw,
351+
unsigned long rate, unsigned long *parent_rate)
352+
{
353+
struct vcu_pll *pll = to_vcu_pll(hw);
354+
unsigned int feedback_div;
355+
356+
rate = clamp_t(unsigned long, rate, pll->fvco_min, pll->fvco_max);
357+
358+
feedback_div = DIV_ROUND_CLOSEST_ULL(rate, *parent_rate);
359+
feedback_div = clamp_t(unsigned int, feedback_div, 25, 125);
360+
361+
return *parent_rate * feedback_div;
362+
}
363+
364+
static unsigned long xvcu_pll_recalc_rate(struct clk_hw *hw,
365+
unsigned long parent_rate)
366+
{
367+
struct vcu_pll *pll = to_vcu_pll(hw);
368+
void __iomem *base = pll->reg_base;
369+
unsigned int div;
370+
u32 vcu_pll_ctrl;
371+
372+
vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
373+
div = (vcu_pll_ctrl >> VCU_PLL_CTRL_FBDIV_SHIFT) & VCU_PLL_CTRL_FBDIV_MASK;
374+
375+
return div * parent_rate;
376+
}
377+
378+
static int xvcu_pll_set_rate(struct clk_hw *hw,
342379
unsigned long rate, unsigned long parent_rate)
343380
{
344-
return xvcu_pll_set_div(xvcu, rate / parent_rate);
381+
struct vcu_pll *pll = to_vcu_pll(hw);
382+
383+
return xvcu_pll_set_div(pll, rate / parent_rate);
345384
}
346385

347-
static int xvcu_pll_enable(struct xvcu_device *xvcu)
386+
static int xvcu_pll_enable(struct clk_hw *hw)
348387
{
349-
void __iomem *base = xvcu->vcu_slcr_ba;
388+
struct vcu_pll *pll = to_vcu_pll(hw);
389+
void __iomem *base = pll->reg_base;
350390
u32 vcu_pll_ctrl;
351391
int ret;
352392

353-
ret = clk_prepare_enable(xvcu->pll_ref);
354-
if (ret) {
355-
dev_err(xvcu->dev, "failed to enable pll_ref clock source\n");
356-
return ret;
357-
}
358-
359393
xvcu_write_field_reg(base, VCU_PLL_CTRL,
360394
1, VCU_PLL_CTRL_BYPASS_MASK,
361395
VCU_PLL_CTRL_BYPASS_SHIFT);
@@ -375,25 +409,24 @@ static int xvcu_pll_enable(struct xvcu_device *xvcu)
375409
vcu_pll_ctrl |= (0 & VCU_PLL_CTRL_RESET_MASK) << VCU_PLL_CTRL_RESET_SHIFT;
376410
xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
377411

378-
ret = xvcu_pll_wait_for_lock(xvcu);
412+
ret = xvcu_pll_wait_for_lock(pll);
379413
if (ret) {
380-
dev_err(xvcu->dev, "PLL is not locked\n");
414+
pr_err("VCU PLL is not locked\n");
381415
goto err;
382416
}
383417

384418
xvcu_write_field_reg(base, VCU_PLL_CTRL,
385419
0, VCU_PLL_CTRL_BYPASS_MASK,
386420
VCU_PLL_CTRL_BYPASS_SHIFT);
387421

388-
return ret;
389422
err:
390-
clk_disable_unprepare(xvcu->pll_ref);
391423
return ret;
392424
}
393425

394-
static void xvcu_pll_disable(struct xvcu_device *xvcu)
426+
static void xvcu_pll_disable(struct clk_hw *hw)
395427
{
396-
void __iomem *base = xvcu->vcu_slcr_ba;
428+
struct vcu_pll *pll = to_vcu_pll(hw);
429+
void __iomem *base = pll->reg_base;
397430
u32 vcu_pll_ctrl;
398431

399432
vcu_pll_ctrl = xvcu_read(base, VCU_PLL_CTRL);
@@ -404,8 +437,49 @@ static void xvcu_pll_disable(struct xvcu_device *xvcu)
404437
vcu_pll_ctrl &= ~(VCU_PLL_CTRL_RESET_MASK << VCU_PLL_CTRL_RESET_SHIFT);
405438
vcu_pll_ctrl |= (1 & VCU_PLL_CTRL_RESET_MASK) << VCU_PLL_CTRL_RESET_SHIFT;
406439
xvcu_write(base, VCU_PLL_CTRL, vcu_pll_ctrl);
440+
}
441+
442+
static const struct clk_ops vcu_pll_ops = {
443+
.enable = xvcu_pll_enable,
444+
.disable = xvcu_pll_disable,
445+
.round_rate = xvcu_pll_round_rate,
446+
.recalc_rate = xvcu_pll_recalc_rate,
447+
.set_rate = xvcu_pll_set_rate,
448+
};
407449

408-
clk_disable_unprepare(xvcu->pll_ref);
450+
static struct clk_hw *xvcu_register_pll(struct device *dev,
451+
void __iomem *reg_base,
452+
const char *name, const char *parent,
453+
unsigned long flags)
454+
{
455+
struct vcu_pll *pll;
456+
struct clk_hw *hw;
457+
struct clk_init_data init;
458+
int ret;
459+
460+
init.name = name;
461+
init.parent_names = &parent;
462+
init.ops = &vcu_pll_ops;
463+
init.num_parents = 1;
464+
init.flags = flags;
465+
466+
pll = devm_kmalloc(dev, sizeof(*pll), GFP_KERNEL);
467+
if (!pll)
468+
return ERR_PTR(-ENOMEM);
469+
470+
pll->hw.init = &init;
471+
pll->reg_base = reg_base;
472+
pll->fvco_min = FVCO_MIN;
473+
pll->fvco_max = FVCO_MAX;
474+
475+
hw = &pll->hw;
476+
ret = devm_clk_hw_register(dev, hw);
477+
if (ret)
478+
return ERR_PTR(ret);
479+
480+
clk_hw_set_rate_range(hw, pll->fvco_min, pll->fvco_max);
481+
482+
return hw;
409483
}
410484

411485
/**
@@ -430,9 +504,7 @@ static int xvcu_set_vcu_pll_info(struct xvcu_device *xvcu)
430504
u32 pll_clk;
431505
u32 mod;
432506
int i;
433-
int ret;
434507
const struct xvcu_pll_cfg *found = NULL;
435-
struct clk_hw *hw;
436508

437509
regmap_read(xvcu->logicore_reg_ba, VCU_PLL_CLK, &inte);
438510
regmap_read(xvcu->logicore_reg_ba, VCU_PLL_CLK_DEC, &deci);
@@ -490,17 +562,6 @@ static int xvcu_set_vcu_pll_info(struct xvcu_device *xvcu)
490562
dev_dbg(xvcu->dev, "Actual Core clock freq is %uHz\n", coreclk);
491563
dev_dbg(xvcu->dev, "Actual Mcu clock freq is %uHz\n", mcuclk);
492564

493-
ret = xvcu_pll_set_rate(xvcu, fvco, refclk);
494-
if (ret)
495-
return ret;
496-
497-
hw = clk_hw_register_fixed_rate(xvcu->dev, "vcu_pll",
498-
__clk_get_name(xvcu->pll_ref),
499-
0, fvco);
500-
if (IS_ERR(hw))
501-
return PTR_ERR(hw);
502-
xvcu->pll = hw;
503-
504565
return 0;
505566
}
506567

@@ -523,7 +584,7 @@ static int xvcu_set_pll(struct xvcu_device *xvcu)
523584
return ret;
524585
}
525586

526-
return xvcu_pll_enable(xvcu);
587+
return 0;
527588
}
528589

529590
static struct clk_hw *xvcu_clk_hw_register_leaf(struct device *dev,
@@ -630,6 +691,13 @@ static int xvcu_register_clock_provider(struct xvcu_device *xvcu)
630691

631692
xvcu->clk_data = data;
632693

694+
hw = xvcu_register_pll(dev, reg_base,
695+
"vcu_pll", __clk_get_name(xvcu->pll_ref),
696+
CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE);
697+
if (IS_ERR(hw))
698+
return PTR_ERR(hw);
699+
xvcu->pll = hw;
700+
633701
hw = xvcu_register_pll_post(dev, "vcu_pll_post", xvcu->pll, reg_base);
634702
if (IS_ERR(hw))
635703
return PTR_ERR(hw);
@@ -811,8 +879,6 @@ static int xvcu_remove(struct platform_device *pdev)
811879
/* Add the the Gasket isolation and put the VCU in reset. */
812880
regmap_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, 0);
813881

814-
clk_hw_unregister_fixed_rate(xvcu->pll);
815-
xvcu_pll_disable(xvcu);
816882
clk_disable_unprepare(xvcu->aclk);
817883

818884
return 0;

0 commit comments

Comments
 (0)