[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <6b3e8322-40fa-0d79-3212-fae76d04de64@linux.intel.com>
Date: Thu, 13 Feb 2020 16:04:46 +0800
From: "Tanwar, Rahul" <rahul.tanwar@...ux.intel.com>
To: Stephen Boyd <sboyd@...nel.org>, linux-clk@...r.kernel.org,
mark.rutland@....com, mturquette@...libre.com, robh+dt@...nel.org,
robh@...nel.org
Cc: linux-kernel@...r.kernel.org, devicetree@...r.kernel.org,
andriy.shevchenko@...el.com, qi-ming.wu@...el.com,
yixin.zhu@...ux.intel.com, cheol.yong.kim@...el.com,
rtanwar <rahul.tanwar@...el.com>
Subject: Re: [PATCH v4 1/2] clk: intel: Add CGU clock driver for a new SoC
Hi Stephen,
Thanks a lot for taking time out to review and providing feedback. I have
tried to address all your review concerns except few below mentioned points
where i need more clarification.
On 31/1/2020 10:24 AM, Stephen Boyd wrote:
> Quoting Rahul Tanwar (2020-01-30 01:04:02)
>> From: rtanwar <rahul.tanwar@...el.com>
>>
>> Clock Generation Unit(CGU) is a new clock controller IP of a forthcoming
(...)
>> + raw_spin_unlock_irqrestore(&ctx->lock, flags);
>> + }
>> +
>> + return clk_hw_register_fixed_rate(NULL, list->name,
>> + list->parent_names[0],
>> + list->flags, list->mux_flags);
> Can fixed rate clks come from DT? Or does this value change sometimes?
Fixed rate clks may need enable/disable clk ops. That's the only reason
for making it visible to clock driver.
>> +lgm_clk_ddiv_set_rate(struct clk_hw *hw, unsigned long rate,
>> + unsigned long prate)
>> +{
>> + struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw);
>> + u32 div, ddiv1, ddiv2;
>> + unsigned long flags;
>> +
>> + div = DIV_ROUND_CLOSEST_ULL((u64)prate, rate);
>> +
>> + raw_spin_lock_irqsave(&ddiv->lock, flags);
>> + if (lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift2, 1)) {
>> + div = DIV_ROUND_CLOSEST_ULL((u64)div, 5);
>> + div = div * 2;
>> + }
>> + raw_spin_unlock_irqrestore(&ddiv->lock, flags);
> Does the math need to be inside the spinlock? Should probably not have
> any spinlock at all and just read it with lgm_get_clk_val() and trust
> that the hardware will return us something sane?
>
>> +
>> + if (div <= 0)
>> + return -EINVAL;
>> +
>> + if (lgm_clk_get_ddiv_val(div, &ddiv1, &ddiv2))
>> + return -EINVAL;
>> +
>> + raw_spin_lock_irqsave(&ddiv->lock, flags);
>> + lgm_set_clk_val(ddiv->membase, ddiv->reg, ddiv->shift0, ddiv->width0,
>> + ddiv1 - 1);
>> +
>> + lgm_set_clk_val(ddiv->membase, ddiv->reg, ddiv->shift1, ddiv->width1,
>> + ddiv2 - 1);
> Can this not be combined? lgm_set_clk_val is sort of obfuscating the
> code. Please consider inlining it and then holding the spinlock across
> this entire function while doing the read/modify/write.
These two set_clk_val's can not be combined because they have different
non-contiguous bitmaps (shifts) and lgm_set_clk_val() is defined to handle
only one shift. However, i have addressed your other comment i.e. inline it
and hold spinlock across the function during read/modify/write.
>> +struct lgm_clk_mux {
>> + struct clk_hw hw;
>> + struct device *dev;
>> + void __iomem *membase;
>> + unsigned int reg;
>> + u8 shift;
>> + u8 width;
>> + unsigned long flags;
>> + raw_spinlock_t lock;
>> +};
>> +
>> +struct lgm_clk_divider {
>> + struct clk_hw hw;
>> + struct device *dev;
>> + void __iomem *membase;
>> + unsigned int reg;
>> + u8 shift;
>> + u8 width;
>> + u8 shift_gate;
>> + u8 width_gate;
>> + unsigned long flags;
>> + const struct clk_div_table *table;
>> + raw_spinlock_t lock;
>> +};
>> +
>> +struct lgm_clk_ddiv {
>> + struct clk_hw hw;
>> + struct device *dev;
>> + void __iomem *membase;
>> + unsigned int reg;
>> + u8 shift0;
>> + u8 width0;
>> + u8 shift1;
>> + u8 width1;
>> + u8 shift2;
>> + u8 width2;
>> + u8 shift_gate;
>> + u8 width_gate;
>> + unsigned int mult;
>> + unsigned int div;
>> + unsigned long flags;
>> + raw_spinlock_t lock;
>> +};
>> +
>> +struct lgm_clk_gate {
>> + struct clk_hw hw;
>> + struct device *dev;
> These all have dev pointers, is it necessary? In theory we can have a
> clk_hw API that gets the dev pointer out for you if you want it, now
> that we store the dev pointer when a clk registers
We needed dev pointers just for dev_err() in clk_ops when they are called
back from core. I have now removed dev_err() calls from the driver clk_ops
as i believe the error info was not that useful. And so i have removed dev
pointers from above structures.
However, i think it would be good to have a clk_hw API which returns dev
pointer for drivers. Presently, dev pointer is stored inside clk_hw->clk_core
and clk_core is private to core, inaccessible from clk drivers.
>> +enum pll_type {
>> + TYPE_ROPLL,
>> + TYPE_LJPLL,
>> + TYPE_NONE,
> Is this used? Remove it if not.
It is actually used.
>> +struct lgm_pll_clk_data {
>> + unsigned int id;
>> + const char *name;
>> + const char *const *parent_names;
> Can you use the new way of specifying clk parents instead of using plain
> strings? Reminder to self, write that document.
I have changed it to new way i.e. by using fw_name. Only exception is where we
use clk API's clk_hw_register_fixed_rate() & clk_hw_register_fixed_factor().
In these API's, i am, for now, passing parent_data[0].name as parent_name.
>> +/* clock flags definition */
>> +#define CLOCK_FLAG_VAL_INIT BIT(16)
>> +#define GATE_CLK_HW BIT(17)
>> +#define GATE_CLK_SW BIT(18)
>> +#define MUX_CLK_SW GATE_CLK_SW
> Why do these bits start at 16?
To avoid the conflict with clk_flags used across common struct clk
defined in clk-provider.h. Bits 0~13 are already used there. So
we keep some gap and start with 16 :). We don't maintain a separate
pure driver only flags bitmask as that would make it confusing.
> What does _HW and _SW mean? Is there
> hardware control of clks?
GATE_CLK_HW & GATE_CLK_SW is no longer needed for this SoC. So i have
removed it. MUX_CLK_SW is still needed. It is more of a workaround for
one particular combophy module for which get_parent/set_parent does not
apply (no hardware translation to select/query input clk source).
However, other MUX clks in this clk group have valid hardware translation
for parent clock sources.
>> +static const struct clk_div_table dcl_div[] = {
>> + { .val = 0, .div = 6 },
>> + { .val = 1, .div = 12 },
>> + { .val = 2, .div = 24 },
>> + { .val = 3, .div = 32 },
>> + { .val = 4, .div = 48 },
>> + { .val = 5, .div = 96 },
>> + {}
> I guess 'div' being equal to 0 is the terminator?
Yes, but i am missing your point. Can you please elaborate more ?
>> + ctx->np = np;
>> + ctx->dev = dev;
>> + raw_spin_lock_init(&ctx->lock);
> Why is it a raw spinlock?
Agree. We use CONFIG_SMP with no PREEMPT_RT. So i think it is same.
Have switched to normal spinlocks.
Regards,
Rahul
Powered by blists - more mailing lists