Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers: clk: sam: update main, generic and PLL clocks for Microchip sama7g54 #6651

Merged
merged 3 commits into from
Feb 28, 2024

Conversation

TonyHan11
Copy link
Contributor

No description provided.

@TonyHan11 TonyHan11 force-pushed the sama7g5_clk_pll branch 2 times, most recently from 9af5c20 to aeb9792 Compare January 29, 2024 07:09
@TonyHan11
Copy link
Contributor Author

Some definitions added in core/drivers/clk/sam/at91_pmc.h in #6630 are used by the files updated in this PR, please apply the commits in #6630 first before build.

Copy link
Contributor

@jforissier jforissier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on "drivers: clk: sam: update to support main system bus clock for sama7g5". Once addressed, please add to this commit:

Acked-by: Jerome Forissier <[email protected]>

struct clk_master *master = hw->priv;
size_t i = 0;

for (; i < hw->num_parents; i++)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for (i = 0; i < hw->num_parents; i++) (and please keep the initialization size_t i = 0; regardless).

return i;

EMSG("Can't get correct parent of clock \"%s\"", hw->name);
return -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return type size_t is unsigned, should be changed.

uint8_t safe_div;
};

static inline bool sam9x60_pll_ready(vaddr_t base, int id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove inline keyword. Not needed from a source file, it's rather used only from header files.

{
unsigned int status = io_read32(base + AT91_PMC_PLL_ISR0);

return !!(status & BIT(id));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return status & BIT(id); is enough.
Or even return io_read32(base + AT91_PMC_PLL_ISR0) & BIT(id);


freq = parent_rate * (frac->mul + 1) +
UDIV_ROUND_NEAREST((unsigned long long)parent_rate * frac->frac,
(1 << 22));

This comment was marked as resolved.

{
struct sam9x60_pll_core *core = &frac->core;
vaddr_t regmap = frac->core.base;
unsigned int val = 0, cfrac = 0, cmul = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

define 1 local variable per line.

io_write32(master->base + AT91_PMC_MCR_V2, master->id);
val = io_read32(master->base + AT91_PMC_MCR_V2);
master->parent = (val & AT91_PMC_MCR_V2_CSS_MSK)
>> AT91_PMC_MCR_V2_CSS_SHIFT;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-	master->parent = (val & AT91_PMC_MCR_V2_CSS_MSK)
-			>> AT91_PMC_MCR_V2_CSS_SHIFT;
+	master->parent = (val & AT91_PMC_MCR_V2_CSS_MSK) >>
+			 AT91_PMC_MCR_V2_CSS_SHIFT;

unsigned int i = 0;

if (gck->mux_table) {
for (; i < 8; i++)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some comment as for previous commit: for (i = 0; i < 8; i++)

if (gck->mux_table[i] == gck->parent_id)
return i;
EMSG("Can't get correct parent of clock \"%s\"", clk->name);
return -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

size_t is unsigned.

#define PLL_DIV_MAX PLL_DIV_MASK
#define PLL_DIV(reg) ((reg) & PLL_DIV_MASK)
#define PLL_MUL(reg, layout) ({ \
typeof(layout) __layout = layout; \

This comment was marked as resolved.

#define PLL_MUL_MASK(layout) ((layout)->mul_mask)
#define PLL_MUL_MAX(layout) (PLL_MUL_MASK(layout) + 1)
#define PLL_ICPR_SHIFT(id) ((id) * 16)
#define PLL_ICPR_MASK(id) (0xffff << PLL_ICPR_SHIFT(id))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SHIFT_U64(0xffff, PLL_ICPR_SHIFT(id))

@TonyHan11
Copy link
Contributor Author

@etienne-lms Updated according to the comments, review tags added and rebased on the latest master branch, thank you very much.

@TonyHan11
Copy link
Contributor Author

Timeout added for waiting PLL clock ready.

return i;

EMSG("Can't get correct parent of clock \"%s\"", hw->name);
return 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 seems a valid return index. I think it's safe to panic() here since this is not awaited.

if (gck->mux_table[i] == gck->parent_id)
return i;
EMSG("Can't get correct parent of clock \"%s\"", clk->name);
return 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could safely panic here IMHO.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can remove the useless return 0 instruction.
Ditto in clk_sama7g5_master_get_parent().

cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift;

if (sam9x60_frac_pll_ready(regmap, core->id) &&
(cmul == frac->mul && cfrac == frac->frac))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could remove the inner parentheses:

	if (sam9x60_frac_pll_ready(regmap, core->id) &&
	    cmul == frac->mul && cfrac == frac->frac)

AT91_PMC_PLL_UPDT_UPDATE | core->id);

while (!sam9x60_pll_ready(regmap, core->id))
if (timeout_elapsed(timeout))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend to use IO_READ32_POLL_TIMEOUT() macro the handle case where this function is called from a threaded context that is rescheduled between sam9x60_pll_ready() call and timeout_elapsed() call.

* divider that provide the closest rate to the requested one.
*/
nmul = rate / parent_rate;
nmul += (rate % parent_rate) / parent_rate;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think (rate % parent_rate) / parent_rate will always be 0.

(1 << 22));
}

/* Check if resulted rate is a valid. */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-	/* Check if resulted rate is a valid.  */
+	/* Check if resulted rate is a valid. */

AT91_PMC_PLL_UPDT_UPDATE | core->id);

while (!sam9x60_pll_ready(regmap, core->id))
;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handle timeout with IO_READ32_POLL_TIMEOUT()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank for your comments.

Commits updated according to the comments expect the using of IO_READ32_POLL_TIMEOUT(). The reason is that udelay() is used in the macro and there will be an assert failure while booting.

udelay() depends on plat_get_freq() which requires the initialization of freq (done by early_init_late(get_freq_from_dt);). Some PLL clocks need to be initialized before calling get_freq_from_dt, once the delay is called with non-initialized freq an assert failure will occur.

AT91_PMC_PLL_UPDT_UPDATE | core->id);

while (!sam9x60_pll_ready(regmap, core->id))
;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto about timeout handling

{
struct sam9x60_pll_core *core = &div->core;
vaddr_t regmap = core->base;
unsigned int val = 0, cdiv = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

	unsigned int cdiv = 0;
	unsigned int val = 0;

@TonyHan11 TonyHan11 force-pushed the sama7g5_clk_pll branch 2 times, most recently from 02aa760 to 7839069 Compare February 4, 2024 02:52
@TonyHan11
Copy link
Contributor Author

Update AT91_PMC_MCR_V2_DIV to AT91_PMC_MCR_V2_DIV_MSK according to the macro name changed in #6630

@TonyHan11
Copy link
Contributor Author

Missing offset of PLL ISR register while adding WAIT_PLL_READY_TIMEOUT macro, fixed.

if (gck->mux_table[i] == gck->parent_id)
return i;
EMSG("Can't get correct parent of clock \"%s\"", clk->name);
return 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can remove the useless return 0 instruction.
Ditto in clk_sama7g5_master_get_parent().

AT91_PMC_PLL_UPDT_UPDATE | core->id);

if (WAIT_PLL_READY_TIMEOUT(regmap, core->id))
EMSG("PLL not ready");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ret = TEE_ERROR_xxx if WAIT_PLL_READY_TIMEOUT() returns true?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return TEE_ERROR_BUSY; added, thanks.

AT91_PMC_PLL_UPDT_UPDATE | core->id);

if (WAIT_PLL_READY_TIMEOUT(regmap, core->id))
EMSG("PLL not ready");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return an error to code sam9x60_div_pll_set() and sam9x60_div_pll_set_rate_chg()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the return code.

struct sam9x60_div *div = hw->priv;
struct sam9x60_pll_core *core = &div->core;
vaddr_t regmap = core->base;
unsigned int val, cdiv;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

	unsigned int cdiv = 0;
	unsigned int val = 0;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

@@ -0,0 +1,517 @@
// SPDX-License-Identifier: GPL-2.0+
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

license model issue

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Microchip Technology Inc.
*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can remove this empty inline comment line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the empty line and updated the license model, thanks.

master->chg_pid = chg_pid;
master->mux_table = mux_table;

io_write32(master->base + AT91_PMC_MCR_V2, master->id);
Copy link
Contributor

@etienne-lms etienne-lms Feb 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI make builds fail on AT91_PMC_MCR_V2* macros not being defined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The definitions of these macros are added in #6630, you can find them in core/drivers/clk/sam/at91_pmc.h.
It's better to integrate #6630 before this PR, thanks.

@jforissier
Copy link
Contributor

Some definitions added in core/drivers/clk/sam/at91_pmc.h in #6630 are used by the files updated in this PR, please apply the commits in #6630 first before build.

That's not how it works. If you need a commit from another PR, please add it here too, and mention that it does not need to be reviewed here due to being in pending PR xxx. This way things are clear and CI can be trusted.

if (_c) \
break; \
} \
!(_c); \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would replace !(_c); with !io_read32((base) + AT91_PMC_PLL_ISR0) & BIT(id);. Explanations in #6297 (comment).

I would also replace base and id arguments name with _base and _id.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_base and _id updated. The !(_c) not replaced due to interrupt status register AT91_PMC_PLL_ISR0 has read-clear behavior.

Copy link
Contributor

@etienne-lms etienne-lms Feb 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then, you need to find another way to address the case where the TEE thread has been rescheduled while this macro is executing.

Edited: Discard this comment, it was stupid as your timeout detection based on a trial counter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As delay by a timer/counter can not be used here, add wait_cycles() to determine the timeout.

{
vaddr_t regmap = core->base;
uint32_t ena_msk = enable ? core->layout->endiv_mask : 0;
uint32_t ena_val = enable ? (1 << core->layout->endiv_shift) : 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uint32_t ena_val = enable ? BIT(core->layout->endiv_shift) : 0;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, thanks.

bool enable)
{
vaddr_t regmap = core->base;
uint32_t ena_msk = enable ? core->layout->endiv_mask : 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpicking: s/ena_msk/enable_mask/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced msk with mask.

@etienne-lms
Copy link
Contributor

@TonyHan11, could you rebase your series now that #6630 is merged?

@TonyHan11
Copy link
Contributor Author

Rebased to the latest master branch with some minor fixes.

@TonyHan11 TonyHan11 force-pushed the sama7g5_clk_pll branch 2 times, most recently from 856d518 to f0f0b94 Compare February 22, 2024 07:21
@TonyHan11
Copy link
Contributor Author

Last update of WAIT_PLL_READY_TIMEOUT macro introduced a failure of eth0 in u-boot, fixed by extending the timeout value.

free(master);
return NULL;
}
return hw;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpicking: we usually add an empty line before the final return instruction in a function block.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty lines added before each of the final return, thanks.

@@ -140,6 +151,7 @@ struct clk *
at91_clk_register_generated(struct pmc_data *pmc,
const struct clk_pcr_layout *layout,
const char *name, struct clk **parents,
uint32_t *mux_table,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems mux_parent here is always a 8 cell array reference. I suggest you define that in the argument type, if applicable: s/uin32t_t *mux_parent/uint32_t mux_parent[8]/
This would ensure line 76 and 90 will not overflow gck->mux_table size.

From clk_generated_set_parent() above, gck->mux_table size is related to the number of possible parents for the clock. Maybe use this info in clk_generated_get_parent(), instead of 8?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added mux_table_size variable after uint32_t *mux_table in the struct and use it to avoid accessing beyond gck->mux_table.

The mux_table is used for sama7g5 support as the clock source of sama7g5_gck are from different PLL. For sama5d2 the sources are fixed and no mux is used.

@@ -186,6 +186,14 @@ at91_clk_register_master_div(struct pmc_data *pmc,
const struct clk_master_layout *layout,
const struct clk_master_charac *charac);

struct clk *at91_clk_sama7g5_register_master(struct pmc_data *pmc,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It suggest that you state somewhere that both parent and mux_table have num_parents cells.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mux_table_size added and assigned equal to num_parents in at91_clk_register_generated().

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An inline description comment could clarify that when mux_table is not NULL it shall hold num_parents cells. This is only a suggestion.

parent_rate);

tmprate += UDIV_ROUND_NEAREST((uint64_t)nfrac * parent_rate,
(1 << 22));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could remove the inner parentheses

@@ -72,16 +73,30 @@ static TEE_Result clk_generated_set_parent(struct clk *clk, size_t index)
if (index >= clk_get_num_parents(clk))
return TEE_ERROR_BAD_PARAMETERS;

gck->parent_id = index;
if (gck->mux_table) {
if (index > gck->mux_table_size)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function get read clk->num_parents hence I think it's not needed to duplicate that info in struct clk_generated.

@@ -186,6 +186,14 @@ at91_clk_register_master_div(struct pmc_data *pmc,
const struct clk_master_layout *layout,
const struct clk_master_charac *charac);

struct clk *at91_clk_sama7g5_register_master(struct pmc_data *pmc,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An inline description comment could clarify that when mux_table is not NULL it shall hold num_parents cells. This is only a suggestion.

@TonyHan11
Copy link
Contributor Author

Updated according to the comments, thank you @etienne-lms

@@ -186,6 +186,17 @@ at91_clk_register_master_div(struct pmc_data *pmc,
const struct clk_master_layout *layout,
const struct clk_master_charac *charac);

/*
* @mux_table: when mux_table is not NULL it shll hold 'num_prents' cells
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* @mux_table: when @mux_table is not NULL it shall hold @num_parents cells

unsigned long div = 0;

div = UDIV_ROUND_NEAREST(parent_rate, rate);
if ((div > (1 << (MASTER_PRES_MAX - 1))) || (div & (div - 1)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: s/div & (div - 1)/!IS_POWER_OF_TWO(div)/

wait_cycles(100); \
} \
!(_c); \
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add an indentation tab to each line

#define WAIT_PLL_READY_TIMEOUT(_base, _id) \
	({ \
		uint32_t __timeout = 0; \
		uint32_t _c = 0; \
		\
		while (__timeout++ < 500) { \
			_c = io_read32((_base) + AT91_PMC_PLL_ISR0) & BIT(_id); \
			if (_c) \
				break; \
			wait_cycles(100); \
		} \
		!(_c); \
	})

unsigned int i = 0;

if (gck->mux_table) {
for (i = 0; i < gck->mux_table_size; i++)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpicking: clk_generated_set_parent() relies on index >= clk_get_num_parents(clk) and here on gck->mux_table_size. For consistency, I think you could remove field mux_table_size from struct clk_generated and use clk_get_num_parents(clk) here also (or use straight clk->num_parents as done in clk_sama7g5_master_xxx()).

typeof(layout) __layout = layout; \
\
(((reg) >> (__layout)->mul_shift) & (__layout)->mul_mask); \
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an indentation tab (and can drop a pair of parentheses):

#define PLL_MUL(reg, layout) \
	({ \
		typeof(layout) __layout = layout; \
		\
		((reg) >> (__layout)->mul_shift) & (__layout)->mul_mask; \
	})

@TonyHan11
Copy link
Contributor Author

Updated according to the comments, thanks.

Copy link
Contributor

@etienne-lms etienne-lms left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acked-by: Etienne Carriere <[email protected]> with this last comment addressed.

@@ -186,6 +203,17 @@ at91_clk_register_master_div(struct pmc_data *pmc,
const struct clk_master_layout *layout,
const struct clk_master_charac *charac);

/*
* @mux_table: when @mux_table is not NULL it shall hold @num_prents cells
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/@num_prents/@num_parents/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated and added Acked-by, thank you.

Add functions for configuring sama7g5 main system bus clock.

Signed-off-by: Tony Han <[email protected]>
Acked-by: Jerome Forissier <[email protected]>
Acked-by: Etienne Carriere <[email protected]>
Add a mux table for select from different generic clock source.

Signed-off-by: Tony Han <[email protected]>
Acked-by: Jerome Forissier <[email protected]>
Acked-by: Etienne Carriere <[email protected]>
As PLL is compatible for sama7g5 and sam9x60, add sam9x60 PLL functions for
configuring sama7g5 PLL.

Signed-off-by: Tony Han <[email protected]>
Acked-by: Jerome Forissier <[email protected]>
Acked-by: Etienne Carriere <[email protected]>
@jforissier
Copy link
Contributor

IBART error ignored, branch needs re-basing.

@jforissier jforissier merged commit 4318c69 into OP-TEE:master Feb 28, 2024
6 of 7 checks passed
@TonyHan11 TonyHan11 deleted the sama7g5_clk_pll branch February 29, 2024 02:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants