Re: [RESEND v7 14/37] clk: Compatible with narrow registers

From: Damien Le Moal
Date: Fri Apr 05 2024 - 09:07:52 EST


On 4/5/24 21:56, Geert Uytterhoeven wrote:
> Hi Sato-san,
>
> On Thu, Apr 4, 2024 at 7:15 AM Yoshinori Sato
> <ysato@xxxxxxxxxxxxxxxxxxxx> wrote:
>> divider and gate only support 32-bit registers.
>> Older hardware uses narrower registers, so I want to be able to handle
>> 8-bit and 16-bit wide registers.
>>
>> Seven clk_divider flags are used, and if I add flags for 8bit access and
>> 16bit access, 8bit will not be enough, so I expanded it to u16.
>>
>> Signed-off-by: Yoshinori Sato <ysato@xxxxxxxxxxxxxxxxxxxx>
>
> Thanks for the update!
>
>> --- a/drivers/clk/clk-divider.c
>> +++ b/drivers/clk/clk-divider.c
>> @@ -26,20 +26,38 @@
>> * parent - fixed parent. No clk_set_parent support
>> */
>>
>> -static inline u32 clk_div_readl(struct clk_divider *divider)
>> -{
>> - if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
>> - return ioread32be(divider->reg);
>> -
>> - return readl(divider->reg);
>> +static inline u32 clk_div_read(struct clk_divider *divider)
>> +{
>> + if (divider->flags & CLK_DIVIDER_REG_8BIT)
>
> When you need curly braces in one branch of an if/else statement,
> please use curly braces in all branches (everywhere).
>
>> + return readb(divider->reg);
>> + else if (divider->flags & CLK_DIVIDER_REG_16BIT) {

And no need for an else after a return...


>> + if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
>> + return ioread16be(divider->reg);
>> + else

and here.

>> + return readw(divider->reg);
>> + } else {
>> + if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
>> + return ioread32be(divider->reg);
>> + else

here too.

>> + return readl(divider->reg);
>> + }
>> }
>
>> --- a/drivers/clk/clk-gate.c
>> +++ b/drivers/clk/clk-gate.c
>
>> @@ -137,12 +155,30 @@ struct clk_hw *__clk_hw_register_gate(struct device *dev,
>> struct clk_init_data init = {};
>> int ret = -EINVAL;
>>
>> + /* validate register size option and bit_idx */
>> if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
>> if (bit_idx > 15) {
>> pr_err("gate bit exceeds LOWORD field\n");
>> return ERR_PTR(-EINVAL);
>> }
>> }
>> + if (clk_gate_flags & CLK_GATE_REG_16BIT) {
>> + if (bit_idx > 15) {
>> + pr_err("gate bit exceeds 16 bits\n");
>> + return ERR_PTR(-EINVAL);
>> + }
>> + }
>> + if (clk_gate_flags & CLK_GATE_REG_8BIT) {
>> + if (bit_idx > 7) {
>> + pr_err("gate bit exceeds 8 bits\n");
>> + return ERR_PTR(-EINVAL);
>> + }
>> + }
>> + if ((clk_gate_flags & CLK_GATE_HIWORD_MASK) &&
>
> If you use parentheses around "a & b" here...
>
>> + clk_gate_flags & (CLK_GATE_REG_8BIT | CLK_GATE_REG_16BIT)) {
>
> please add parentheses here, too.
>
>> + pr_err("HIWORD_MASK required 32-bit register\n");
>> + return ERR_PTR(-EINVAL);
>> + }
>>
>> /* allocate the gate */
>> gate = kzalloc(sizeof(*gate), GFP_KERNEL);
>> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
>> index 4a537260f655..eaa6ff1d0b2e 100644
>> --- a/include/linux/clk-provider.h
>> +++ b/include/linux/clk-provider.h
>> @@ -508,12 +508,16 @@ void of_fixed_clk_setup(struct device_node *np);
>> * CLK_GATE_BIG_ENDIAN - by default little endian register accesses are used for
>> * the gate register. Setting this flag makes the register accesses big
>> * endian.
>> + * CLK_GATE_REG_8BIT - by default 32bit register accesses are used for
>> + * the gate register. Setting this flag makes the register accesses 8bit.
>> + * CLK_GATE_REG_16BIT - by default 32bit register accesses are used for
>> + * the gate register. Setting this flag makes the register accesses 16bit.
>> */
>> struct clk_gate {
>> struct clk_hw hw;
>> void __iomem *reg;
>> u8 bit_idx;
>> - u8 flags;
>> + u32 flags;
>
> (from my comments on v6)
> There is no need to increase the size of the flags field for the gate clock.
>
>
>> spinlock_t *lock;
>> };
>>
>
>> @@ -675,13 +681,17 @@ struct clk_div_table {
>> * CLK_DIVIDER_BIG_ENDIAN - By default little endian register accesses are used
>> * for the divider register. Setting this flag makes the register accesses
>> * big endian.
>> + * CLK_DIVIDER_REG_8BIT - by default 32bit register accesses are used for
>> + * the gate register. Setting this flag makes the register accesses 8bit.
>> + * CLK_DIVIDER_REG_16BIT - by default 32bit register accesses are used for
>> + * the gate register. Setting this flag makes the register accesses 16bit.
>> */
>> struct clk_divider {
>> struct clk_hw hw;
>> void __iomem *reg;
>> u8 shift;
>> u8 width;
>> - u8 flags;
>> + u16 flags;
>> const struct clk_div_table *table;
>> spinlock_t *lock;
>> };
>
>> @@ -726,18 +738,18 @@ struct clk_hw *__clk_hw_register_divider(struct device *dev,
>> struct device_node *np, const char *name,
>> const char *parent_name, const struct clk_hw *parent_hw,
>> const struct clk_parent_data *parent_data, unsigned long flags,
>> - void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
>> + void __iomem *reg, u8 shift, u8 width, u32 clk_divider_flags,
>
> "u16 clk_divider_flags", to match clk_divider.flags.
>
>> const struct clk_div_table *table, spinlock_t *lock);
>> struct clk_hw *__devm_clk_hw_register_divider(struct device *dev,
>> struct device_node *np, const char *name,
>> const char *parent_name, const struct clk_hw *parent_hw,
>> const struct clk_parent_data *parent_data, unsigned long flags,
>> - void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
>> + void __iomem *reg, u8 shift, u8 width, u32 clk_divider_flags,
>
> Likewise.
>
>> const struct clk_div_table *table, spinlock_t *lock);
>> struct clk *clk_register_divider_table(struct device *dev, const char *name,
>> const char *parent_name, unsigned long flags,
>> void __iomem *reg, u8 shift, u8 width,
>> - u8 clk_divider_flags, const struct clk_div_table *table,
>> + u32 clk_divider_flags, const struct clk_div_table *table,
>
> Likewise.
>
>> spinlock_t *lock);
>> /**
>> * clk_register_divider - register a divider clock with the clock framework
>
> Gr{oetje,eeting}s,
>
> Geert
>

--
Damien Le Moal
Western Digital Research