[PATCH 0/5] Support the required clocks to enable USB on SAM9X60

This patch series originates from a bigger patch series: https://lists.denx.de/pipermail/u-boot/2022-December/502865.html
A driver for clock operations on SAM9X60's USB clock has been added as well as its registration on CCF. In order for USB to work properly, the UPLL and USBCK need an initial frequency before probing the OHCI/EHCI driver. Furthermore enable this driver in the defconfigs.
Claudiu Beznea (1): clk: at91: pmc: export clock setup to pmc
Sergiu Moga (4): clk: at91: Add support for sam9x60 USB clock clk: at91: sam9x60: Register the required clocks for USB clk: at91: sam9x60: Add initial setup of UPLL and USBCK rates configs: at91: sam9x60: Add required configs for the USB clock
configs/sam9x60_curiosity_mmc_defconfig | 1 + configs/sam9x60ek_mmc_defconfig | 1 + configs/sam9x60ek_nandflash_defconfig | 1 + configs/sam9x60ek_qspiflash_defconfig | 1 + drivers/clk/at91/Kconfig | 7 ++ drivers/clk/at91/Makefile | 1 + drivers/clk/at91/clk-sam9x60-usb.c | 157 ++++++++++++++++++++++++ drivers/clk/at91/pmc.c | 42 +++++++ drivers/clk/at91/pmc.h | 27 ++++ drivers/clk/at91/sam9x60.c | 63 ++++++++++ drivers/clk/at91/sama7g5.c | 48 +------- 11 files changed, 307 insertions(+), 42 deletions(-) create mode 100644 drivers/clk/at91/clk-sam9x60-usb.c

Implement sam9x60 USB clock driver. This clock has three parents: PLLA, UPLL and MAINXTAL. The driver is aware of the three possible parents with the help of the two mux tables provied to the driver during the registration of the clock.
Signed-off-by: Sergiu Moga sergiu.moga@microchip.com --- drivers/clk/at91/Kconfig | 7 ++ drivers/clk/at91/Makefile | 1 + drivers/clk/at91/clk-sam9x60-usb.c | 157 +++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 11 ++ 4 files changed, 176 insertions(+) create mode 100644 drivers/clk/at91/clk-sam9x60-usb.c
diff --git a/drivers/clk/at91/Kconfig b/drivers/clk/at91/Kconfig index 4abc8026b4..4563892647 100644 --- a/drivers/clk/at91/Kconfig +++ b/drivers/clk/at91/Kconfig @@ -61,3 +61,10 @@ config AT91_SAM9X60_PLL help This option is used to enable the AT91 SAM9X60's PLL clock driver. + +config AT91_SAM9X60_USB + bool "USB Clock support for SAM9X60 SoCs" + depends on CLK_AT91 + help + This option is used to enable the AT91 SAM9X60's USB clock + driver. diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 580b406d7b..e53dcb4ca7 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -9,6 +9,7 @@ obj-y += clk-peripheral.o obj-$(CONFIG_AT91_GENERIC_CLK) += clk-generic.o obj-$(CONFIG_AT91_UTMI) += clk-utmi.o obj-$(CONFIG_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o +obj-$(CONFIG_AT91_SAM9X60_USB) += clk-sam9x60-usb.o obj-$(CONFIG_SAMA7G5) += sama7g5.o obj-$(CONFIG_SAM9X60) += sam9x60.o else diff --git a/drivers/clk/at91/clk-sam9x60-usb.c b/drivers/clk/at91/clk-sam9x60-usb.c new file mode 100644 index 0000000000..798fa9eb3c --- /dev/null +++ b/drivers/clk/at91/clk-sam9x60-usb.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SAM9X60's USB Clock support. + * + * Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries + * + * Author: Sergiu Moga sergiu.moga@microchip.com + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <linux/clk-provider.h> + +#include "pmc.h" + +#define UBOOT_DM_CLK_AT91_SAM9X60_USB "at91-sam9x60-usb-clk" + +struct sam9x60_usb { + const struct clk_usbck_layout *layout; + void __iomem *base; + struct clk clk; + const u32 *clk_mux_table; + const u32 *mux_table; + const char * const *parent_names; + u32 num_parents; + u8 id; +}; + +#define to_sam9x60_usb(_clk) container_of(_clk, struct sam9x60_usb, clk) +#define USB_MAX_DIV 15 + +static int sam9x60_usb_clk_set_parent(struct clk *clk, struct clk *parent) +{ + struct sam9x60_usb *usb = to_sam9x60_usb(clk); + int index; + u32 val; + + index = at91_clk_mux_val_to_index(usb->clk_mux_table, usb->num_parents, + parent->id); + if (index < 0) + return index; + + index = at91_clk_mux_index_to_val(usb->mux_table, usb->num_parents, + index); + if (index < 0) + return index; + + pmc_read(usb->base, usb->layout->offset, &val); + val &= ~usb->layout->usbs_mask; + val |= index << (ffs(usb->layout->usbs_mask - 1)); + pmc_write(usb->base, usb->layout->offset, val); + + return 0; +} + +static ulong sam9x60_usb_clk_get_rate(struct clk *clk) +{ + struct sam9x60_usb *usb = to_sam9x60_usb(clk); + ulong parent_rate = clk_get_parent_rate(clk); + u32 val, usbdiv; + + if (!parent_rate) + return 0; + + pmc_read(usb->base, usb->layout->offset, &val); + usbdiv = (val & usb->layout->usbdiv_mask) >> + (ffs(usb->layout->usbdiv_mask) - 1); + return parent_rate / (usbdiv + 1); +} + +static ulong sam9x60_usb_clk_set_rate(struct clk *clk, ulong rate) +{ + struct sam9x60_usb *usb = to_sam9x60_usb(clk); + ulong parent_rate = clk_get_parent_rate(clk); + u32 usbdiv, val; + + if (!parent_rate) + return 0; + + usbdiv = DIV_ROUND_CLOSEST(parent_rate, rate); + if (usbdiv > USB_MAX_DIV + 1 || !usbdiv) + return 0; + + pmc_read(usb->base, usb->layout->offset, &val); + val &= usb->layout->usbdiv_mask; + val |= (usbdiv - 1) << (ffs(usb->layout->usbdiv_mask) - 1); + pmc_write(usb->base, usb->layout->offset, val); + + return parent_rate / usbdiv; +} + +static const struct clk_ops sam9x60_usb_ops = { + .set_parent = sam9x60_usb_clk_set_parent, + .set_rate = sam9x60_usb_clk_set_rate, + .get_rate = sam9x60_usb_clk_get_rate, +}; + +struct clk * +sam9x60_clk_register_usb(void __iomem *base, const char *name, + const char * const *parent_names, u8 num_parents, + const struct clk_usbck_layout *usbck_layout, + const u32 *clk_mux_table, const u32 *mux_table, u8 id) +{ + struct sam9x60_usb *usb; + struct clk *clk; + int ret, index; + u32 val; + + if (!base || !name || !parent_names || !num_parents || + !clk_mux_table || !mux_table) + return ERR_PTR(-EINVAL); + + usb = kzalloc(sizeof(*usb), GFP_KERNEL); + if (!usb) + return ERR_PTR(-ENOMEM); + + usb->id = id; + usb->base = base; + usb->layout = usbck_layout; + usb->parent_names = parent_names; + usb->num_parents = num_parents; + usb->clk_mux_table = clk_mux_table; + usb->mux_table = mux_table; + + clk = &usb->clk; + clk->flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | + CLK_SET_RATE_PARENT; + + pmc_read(usb->base, usb->layout->offset, &val); + + val = (val & usb->layout->usbs_mask) >> + (ffs(usb->layout->usbs_mask) - 1); + + index = at91_clk_mux_val_to_index(usb->mux_table, usb->num_parents, + val); + + if (index < 0) { + kfree(usb); + return ERR_PTR(index); + } + + ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X60_USB, name, + parent_names[index]); + if (ret) { + kfree(usb); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_sam9x60_usb_clk) = { + .name = UBOOT_DM_CLK_AT91_SAM9X60_USB, + .id = UCLASS_CLK, + .ops = &sam9x60_usb_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 2b4dd9a3d9..17793b8802 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -71,6 +71,12 @@ struct clk_pcr_layout { u32 pid_mask; };
+struct clk_usbck_layout { + u32 offset; + u32 usbs_mask; + u32 usbdiv_mask; +}; + extern const struct clk_programmable_layout at91rm9200_programmable_layout; extern const struct clk_programmable_layout at91sam9g45_programmable_layout; extern const struct clk_programmable_layout at91sam9x5_programmable_layout; @@ -87,6 +93,11 @@ struct clk *at91_clk_sam9x5_main(void __iomem *reg, const char *name, const char * const *parent_names, int num_parents, const u32 *mux_table, int type); struct clk * +sam9x60_clk_register_usb(void __iomem *base, const char *name, + const char * const *parent_names, u8 num_parents, + const struct clk_usbck_layout *usbck_layout, + const u32 *clk_mux_table, const u32 *mux_table, u8 id); +struct clk * sam9x60_clk_register_div_pll(void __iomem *base, const char *name, const char *parent_name, u8 id, const struct clk_pll_characteristics *characteristics,

On 23.12.2022 14:33, Sergiu Moga wrote:
Implement sam9x60 USB clock driver. This clock has three parents: PLLA, UPLL and MAINXTAL. The driver is aware of the three possible parents with the help of the two mux tables provied to the driver during the registration of the clock.
Signed-off-by: Sergiu Moga sergiu.moga@microchip.com
Reviewed-by: Claudiu Beznea claudiu.beznea@microchip.com
drivers/clk/at91/Kconfig | 7 ++ drivers/clk/at91/Makefile | 1 + drivers/clk/at91/clk-sam9x60-usb.c | 157 +++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 11 ++ 4 files changed, 176 insertions(+) create mode 100644 drivers/clk/at91/clk-sam9x60-usb.c
diff --git a/drivers/clk/at91/Kconfig b/drivers/clk/at91/Kconfig index 4abc8026b4..4563892647 100644 --- a/drivers/clk/at91/Kconfig +++ b/drivers/clk/at91/Kconfig @@ -61,3 +61,10 @@ config AT91_SAM9X60_PLL help This option is used to enable the AT91 SAM9X60's PLL clock driver.
+config AT91_SAM9X60_USB
- bool "USB Clock support for SAM9X60 SoCs"
- depends on CLK_AT91
- help
This option is used to enable the AT91 SAM9X60's USB clock
driver.
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 580b406d7b..e53dcb4ca7 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -9,6 +9,7 @@ obj-y += clk-peripheral.o obj-$(CONFIG_AT91_GENERIC_CLK) += clk-generic.o obj-$(CONFIG_AT91_UTMI) += clk-utmi.o obj-$(CONFIG_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o +obj-$(CONFIG_AT91_SAM9X60_USB) += clk-sam9x60-usb.o obj-$(CONFIG_SAMA7G5) += sama7g5.o obj-$(CONFIG_SAM9X60) += sam9x60.o else diff --git a/drivers/clk/at91/clk-sam9x60-usb.c b/drivers/clk/at91/clk-sam9x60-usb.c new file mode 100644 index 0000000000..798fa9eb3c --- /dev/null +++ b/drivers/clk/at91/clk-sam9x60-usb.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- SAM9X60's USB Clock support.
- Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries
- Author: Sergiu Moga sergiu.moga@microchip.com
- */
+#include <clk-uclass.h> +#include <dm.h> +#include <linux/clk-provider.h>
+#include "pmc.h"
+#define UBOOT_DM_CLK_AT91_SAM9X60_USB "at91-sam9x60-usb-clk"
+struct sam9x60_usb {
- const struct clk_usbck_layout *layout;
- void __iomem *base;
- struct clk clk;
- const u32 *clk_mux_table;
- const u32 *mux_table;
- const char * const *parent_names;
- u32 num_parents;
- u8 id;
+};
+#define to_sam9x60_usb(_clk) container_of(_clk, struct sam9x60_usb, clk) +#define USB_MAX_DIV 15
+static int sam9x60_usb_clk_set_parent(struct clk *clk, struct clk *parent) +{
- struct sam9x60_usb *usb = to_sam9x60_usb(clk);
- int index;
- u32 val;
- index = at91_clk_mux_val_to_index(usb->clk_mux_table, usb->num_parents,
parent->id);
- if (index < 0)
return index;
- index = at91_clk_mux_index_to_val(usb->mux_table, usb->num_parents,
index);
- if (index < 0)
return index;
- pmc_read(usb->base, usb->layout->offset, &val);
- val &= ~usb->layout->usbs_mask;
- val |= index << (ffs(usb->layout->usbs_mask - 1));
- pmc_write(usb->base, usb->layout->offset, val);
- return 0;
+}
+static ulong sam9x60_usb_clk_get_rate(struct clk *clk) +{
- struct sam9x60_usb *usb = to_sam9x60_usb(clk);
- ulong parent_rate = clk_get_parent_rate(clk);
- u32 val, usbdiv;
- if (!parent_rate)
return 0;
- pmc_read(usb->base, usb->layout->offset, &val);
- usbdiv = (val & usb->layout->usbdiv_mask) >>
(ffs(usb->layout->usbdiv_mask) - 1);
- return parent_rate / (usbdiv + 1);
+}
+static ulong sam9x60_usb_clk_set_rate(struct clk *clk, ulong rate) +{
- struct sam9x60_usb *usb = to_sam9x60_usb(clk);
- ulong parent_rate = clk_get_parent_rate(clk);
- u32 usbdiv, val;
- if (!parent_rate)
return 0;
- usbdiv = DIV_ROUND_CLOSEST(parent_rate, rate);
- if (usbdiv > USB_MAX_DIV + 1 || !usbdiv)
return 0;
- pmc_read(usb->base, usb->layout->offset, &val);
- val &= usb->layout->usbdiv_mask;
- val |= (usbdiv - 1) << (ffs(usb->layout->usbdiv_mask) - 1);
- pmc_write(usb->base, usb->layout->offset, val);
- return parent_rate / usbdiv;
+}
+static const struct clk_ops sam9x60_usb_ops = {
- .set_parent = sam9x60_usb_clk_set_parent,
- .set_rate = sam9x60_usb_clk_set_rate,
- .get_rate = sam9x60_usb_clk_get_rate,
+};
+struct clk * +sam9x60_clk_register_usb(void __iomem *base, const char *name,
const char * const *parent_names, u8 num_parents,
const struct clk_usbck_layout *usbck_layout,
const u32 *clk_mux_table, const u32 *mux_table, u8 id)
+{
- struct sam9x60_usb *usb;
- struct clk *clk;
- int ret, index;
- u32 val;
- if (!base || !name || !parent_names || !num_parents ||
!clk_mux_table || !mux_table)
return ERR_PTR(-EINVAL);
- usb = kzalloc(sizeof(*usb), GFP_KERNEL);
- if (!usb)
return ERR_PTR(-ENOMEM);
- usb->id = id;
- usb->base = base;
- usb->layout = usbck_layout;
- usb->parent_names = parent_names;
- usb->num_parents = num_parents;
- usb->clk_mux_table = clk_mux_table;
- usb->mux_table = mux_table;
- clk = &usb->clk;
- clk->flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
CLK_SET_RATE_PARENT;
- pmc_read(usb->base, usb->layout->offset, &val);
- val = (val & usb->layout->usbs_mask) >>
(ffs(usb->layout->usbs_mask) - 1);
- index = at91_clk_mux_val_to_index(usb->mux_table, usb->num_parents,
val);
- if (index < 0) {
kfree(usb);
return ERR_PTR(index);
- }
- ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X60_USB, name,
parent_names[index]);
- if (ret) {
kfree(usb);
clk = ERR_PTR(ret);
- }
- return clk;
+}
+U_BOOT_DRIVER(at91_sam9x60_usb_clk) = {
- .name = UBOOT_DM_CLK_AT91_SAM9X60_USB,
- .id = UCLASS_CLK,
- .ops = &sam9x60_usb_ops,
- .flags = DM_FLAG_PRE_RELOC,
+}; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 2b4dd9a3d9..17793b8802 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -71,6 +71,12 @@ struct clk_pcr_layout { u32 pid_mask; };
+struct clk_usbck_layout {
- u32 offset;
- u32 usbs_mask;
- u32 usbdiv_mask;
+};
extern const struct clk_programmable_layout at91rm9200_programmable_layout; extern const struct clk_programmable_layout at91sam9g45_programmable_layout; extern const struct clk_programmable_layout at91sam9x5_programmable_layout; @@ -87,6 +93,11 @@ struct clk *at91_clk_sam9x5_main(void __iomem *reg, const char *name, const char * const *parent_names, int num_parents, const u32 *mux_table, int type); struct clk * +sam9x60_clk_register_usb(void __iomem *base, const char *name,
const char * const *parent_names, u8 num_parents,
const struct clk_usbck_layout *usbck_layout,
const u32 *clk_mux_table, const u32 *mux_table, u8 id);
+struct clk * sam9x60_clk_register_div_pll(void __iomem *base, const char *name, const char *parent_name, u8 id, const struct clk_pll_characteristics *characteristics,

Register into DM the clocks required to properly enable USB functionality within the bootloader.
Signed-off-by: Sergiu Moga sergiu.moga@microchip.com --- drivers/clk/at91/sam9x60.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c index 6b5486c6c9..14c2ffcac1 100644 --- a/drivers/clk/at91/sam9x60.c +++ b/drivers/clk/at91/sam9x60.c @@ -76,6 +76,8 @@ enum pmc_clk_ids { ID_QSPI = 18,
ID_MCK_PRES = 19, + ID_USBCK = 20, + ID_UHPCK = 21,
ID_MAX, }; @@ -99,6 +101,7 @@ static const char *clk_names[] = { [ID_PLL_A_DIV] = "plla_divpmcck", [ID_MCK_PRES] = "mck_pres", [ID_MCK_DIV] = "mck_div", + [ID_USBCK] = "usbck", };
/* Fractional PLL output range. */ @@ -171,6 +174,13 @@ static const struct clk_pcr_layout pcr_layout = { .pid_mask = GENMASK(6, 0), };
+/* USB clock layout */ +static const struct clk_usbck_layout usbck_layout = { + .offset = 0x38, + .usbs_mask = GENMASK(1, 0), + .usbdiv_mask = GENMASK(11, 8), +}; + /** * PLL clocks description * @n: clock name @@ -266,6 +276,7 @@ static const struct { u8 cid; } sam9x60_systemck[] = { { .n = "ddrck", .p = "mck_div", .id = 2, .cid = ID_DDR, }, + { .n = "uhpck", .p = "usbck", .id = 6, .cid = ID_UHPCK }, { .n = "pck0", .p = "prog0", .id = 8, .cid = ID_PCK0, }, { .n = "pck1", .p = "prog1", .id = 9, .cid = ID_PCK1, }, { .n = "qspick", .p = "mck_div", .id = 19, .cid = ID_QSPI, }, @@ -543,6 +554,28 @@ static int sam9x60_clk_probe(struct udevice *dev) } clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK_DIV), c);
+ /* Register usbck. */ + p[0] = clk_names[ID_PLL_A_DIV]; + p[1] = clk_names[ID_PLL_U_DIV]; + p[2] = clk_names[ID_MAIN_XTAL]; + m[0] = 0; + m[1] = 1; + m[2] = 2; + cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_A_DIV); + cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_DIV); + cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_XTAL); + prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm, + 3, fail); + prepare_mux_table(muxallocs, muxallocindex, tmpmux, m, 3, fail); + c = sam9x60_clk_register_usb(base, clk_names[ID_USBCK], p, 3, + &usbck_layout, tmpclkmux, tmpmux, + ID_USBCK); + if (IS_ERR(c)) { + ret = PTR_ERR(c); + goto fail; + } + clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_USBCK), c); + /* Register programmable clocks. */ p[0] = clk_names[ID_MD_SLCK]; p[1] = clk_names[ID_TD_SLCK];

On 23.12.2022 14:33, Sergiu Moga wrote:
Register into DM the clocks required to properly enable USB functionality within the bootloader.
Signed-off-by: Sergiu Moga sergiu.moga@microchip.com
Reviewed-by: Claudiu Beznea claudiu.beznea@microchip.com
drivers/clk/at91/sam9x60.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c index 6b5486c6c9..14c2ffcac1 100644 --- a/drivers/clk/at91/sam9x60.c +++ b/drivers/clk/at91/sam9x60.c @@ -76,6 +76,8 @@ enum pmc_clk_ids { ID_QSPI = 18,
ID_MCK_PRES = 19,
ID_USBCK = 20,
ID_UHPCK = 21,
ID_MAX,
}; @@ -99,6 +101,7 @@ static const char *clk_names[] = { [ID_PLL_A_DIV] = "plla_divpmcck", [ID_MCK_PRES] = "mck_pres", [ID_MCK_DIV] = "mck_div",
- [ID_USBCK] = "usbck",
};
/* Fractional PLL output range. */ @@ -171,6 +174,13 @@ static const struct clk_pcr_layout pcr_layout = { .pid_mask = GENMASK(6, 0), };
+/* USB clock layout */ +static const struct clk_usbck_layout usbck_layout = {
- .offset = 0x38,
- .usbs_mask = GENMASK(1, 0),
- .usbdiv_mask = GENMASK(11, 8),
+};
/**
- PLL clocks description
- @n: clock name
@@ -266,6 +276,7 @@ static const struct { u8 cid; } sam9x60_systemck[] = { { .n = "ddrck", .p = "mck_div", .id = 2, .cid = ID_DDR, },
- { .n = "uhpck", .p = "usbck", .id = 6, .cid = ID_UHPCK }, { .n = "pck0", .p = "prog0", .id = 8, .cid = ID_PCK0, }, { .n = "pck1", .p = "prog1", .id = 9, .cid = ID_PCK1, }, { .n = "qspick", .p = "mck_div", .id = 19, .cid = ID_QSPI, },
@@ -543,6 +554,28 @@ static int sam9x60_clk_probe(struct udevice *dev) } clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK_DIV), c);
- /* Register usbck. */
- p[0] = clk_names[ID_PLL_A_DIV];
- p[1] = clk_names[ID_PLL_U_DIV];
- p[2] = clk_names[ID_MAIN_XTAL];
- m[0] = 0;
- m[1] = 1;
- m[2] = 2;
- cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_A_DIV);
- cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_DIV);
- cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_XTAL);
- prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm,
3, fail);
- prepare_mux_table(muxallocs, muxallocindex, tmpmux, m, 3, fail);
- c = sam9x60_clk_register_usb(base, clk_names[ID_USBCK], p, 3,
&usbck_layout, tmpclkmux, tmpmux,
ID_USBCK);
- if (IS_ERR(c)) {
ret = PTR_ERR(c);
goto fail;
- }
- clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_USBCK), c);
- /* Register programmable clocks. */ p[0] = clk_names[ID_MD_SLCK]; p[1] = clk_names[ID_TD_SLCK];

From: Claudiu Beznea claudiu.beznea@microchip.com
Clock setup was intended for setting clocks at boot time on SAMA7G5, e.g. for root clocks like PLLs, that were used to feed IPs needed alive in u-boot (e.g. Ethernet clock feed by a PLL). Export this functionality to all at91 clocks as it may be necessary on other SoCs.
Signed-off-by: Claudiu Beznea claudiu.beznea@microchip.com Signed-off-by: Sergiu Moga sergiu.moga@microchip.com --- drivers/clk/at91/pmc.c | 42 +++++++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 16 +++++++++++++ drivers/clk/at91/sama7g5.c | 48 +++++--------------------------------- 3 files changed, 64 insertions(+), 42 deletions(-)
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index 270892517a..87d2069d89 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -120,3 +120,45 @@ int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index)
return table[index]; } + +int at91_clk_setup(const struct pmc_clk_setup *setup, int size) +{ + struct clk *c, *parent; + int i, ret; + + if (!size) + return 0; + + if (!setup) + return -EINVAL; + + for (i = 0; i < size; i++) { + ret = clk_get_by_id(setup[i].cid, &c); + if (ret) + return ret; + + if (setup[i].pid) { + ret = clk_get_by_id(setup[i].pid, &parent); + if (ret) + return ret; + + ret = clk_set_parent(c, parent); + if (ret) + return ret; + + if (setup[i].prate) { + ret = clk_set_rate(parent, setup[i].prate); + if (ret < 0) + return ret; + } + } + + if (setup[i].rate) { + ret = clk_set_rate(c, setup[i].rate); + if (ret < 0) + return ret; + } + } + + return 0; +} diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 17793b8802..ff464522aa 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -77,6 +77,20 @@ struct clk_usbck_layout { u32 usbdiv_mask; };
+/** + * Clock setup description + * @cid: clock id corresponding to clock subsystem + * @pid: parent clock id corresponding to clock subsystem + * @rate: clock rate + * @prate: parent rate + */ +struct pmc_clk_setup { + unsigned int cid; + unsigned int pid; + unsigned long rate; + unsigned long prate; +}; + extern const struct clk_programmable_layout at91rm9200_programmable_layout; extern const struct clk_programmable_layout at91sam9g45_programmable_layout; extern const struct clk_programmable_layout at91sam9x5_programmable_layout; @@ -160,4 +174,6 @@ void pmc_write(void __iomem *base, unsigned int off, unsigned int val); void pmc_update_bits(void __iomem *base, unsigned int off, unsigned int mask, unsigned int bits);
+int at91_clk_setup(const struct pmc_clk_setup *setup, int size); + #endif diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index d1ec3c82b5..8bd9c14156 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -1070,19 +1070,8 @@ static const struct { }, };
-/** - * Clock setup description - * @cid: clock id corresponding to clock subsystem - * @pid: parent clock id corresponding to clock subsystem - * @rate: clock rate - * @prate: parent rate - */ -static const struct pmc_clk_setup { - unsigned int cid; - unsigned int pid; - unsigned long rate; - unsigned long prate; -} sama7g5_clk_setup[] = { +/* Clock setup description */ +static const struct pmc_clk_setup sama7g5_clk_setup[] = { { .cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_ETH_FRAC), .rate = 625000000, @@ -1119,7 +1108,7 @@ static int sama7g5_clk_probe(struct udevice *dev) unsigned int *muxallocs[SAMA7G5_MAX_MUX_ALLOCS]; const char *p[10]; unsigned int cm[10], m[10], *tmpclkmux, *tmpmux; - struct clk clk, *c, *parent; + struct clk clk, *c; bool main_osc_bypass; int ret, muxallocindex = 0, clkmuxallocindex = 0, i, j;
@@ -1353,34 +1342,9 @@ static int sama7g5_clk_probe(struct udevice *dev) }
/* Setup clocks. */ - for (i = 0; i < ARRAY_SIZE(sama7g5_clk_setup); i++) { - ret = clk_get_by_id(sama7g5_clk_setup[i].cid, &c); - if (ret) - goto fail; - - if (sama7g5_clk_setup[i].pid) { - ret = clk_get_by_id(sama7g5_clk_setup[i].pid, &parent); - if (ret) - goto fail; - - ret = clk_set_parent(c, parent); - if (ret) - goto fail; - - if (sama7g5_clk_setup[i].prate) { - ret = clk_set_rate(parent, - sama7g5_clk_setup[i].prate); - if (ret < 0) - goto fail; - } - } - - if (sama7g5_clk_setup[i].rate) { - ret = clk_set_rate(c, sama7g5_clk_setup[i].rate); - if (ret < 0) - goto fail; - } - } + ret = at91_clk_setup(sama7g5_clk_setup, ARRAY_SIZE(sama7g5_clk_setup)); + if (ret) + goto fail;
return 0;

In order for some of the functionalities, such as the USB clocks, to work properly we need some clocks to be properly initialised at the very beginning of booting.
Signed-off-by: Sergiu Moga sergiu.moga@microchip.com --- drivers/clk/at91/sam9x60.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c index 14c2ffcac1..e2f72446d5 100644 --- a/drivers/clk/at91/sam9x60.c +++ b/drivers/clk/at91/sam9x60.c @@ -378,6 +378,31 @@ static const struct { { .n = "dbgu_gclk", .id = 47, }, };
+/** + * Clock setup description + * @cid: clock id corresponding to clock subsystem + * @pid: parent clock id corresponding to clock subsystem + * @rate: clock rate + * @prate: parent rate + */ +static const struct pmc_clk_setup sam9x60_clk_setup[] = { + { + .cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_FRAC), + .rate = 960000000, + }, + + { + .cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_DIV), + .rate = 480000000, + }, + + { + .cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_USBCK), + .pid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_DIV), + .rate = 48000000, + }, +}; + #define prepare_mux_table(_allocs, _index, _dst, _src, _num, _label) \ do { \ int _i; \ @@ -668,6 +693,11 @@ static int sam9x60_clk_probe(struct udevice *dev) clk_dm(AT91_TO_CLK_ID(PMC_TYPE_GCK, sam9x60_gck[i].id), c); }
+ /* Setup clocks. */ + ret = at91_clk_setup(sam9x60_clk_setup, ARRAY_SIZE(sam9x60_clk_setup)); + if (ret) + goto fail; + return 0;
fail:

On 23.12.2022 14:33, Sergiu Moga wrote:
In order for some of the functionalities, such as the USB clocks, to work properly we need some clocks to be properly initialised at the very beginning of booting.
Signed-off-by: Sergiu Moga sergiu.moga@microchip.com
Reviewed-by: Claudiu Beznea claudiu.beznea@microchip.com
drivers/clk/at91/sam9x60.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c index 14c2ffcac1..e2f72446d5 100644 --- a/drivers/clk/at91/sam9x60.c +++ b/drivers/clk/at91/sam9x60.c @@ -378,6 +378,31 @@ static const struct { { .n = "dbgu_gclk", .id = 47, }, };
+/**
- Clock setup description
- @cid: clock id corresponding to clock subsystem
- @pid: parent clock id corresponding to clock subsystem
- @rate: clock rate
- @prate: parent rate
- */
+static const struct pmc_clk_setup sam9x60_clk_setup[] = {
- {
.cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_FRAC),
.rate = 960000000,
- },
- {
.cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_DIV),
.rate = 480000000,
- },
- {
.cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_USBCK),
.pid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_DIV),
.rate = 48000000,
- },
+};
#define prepare_mux_table(_allocs, _index, _dst, _src, _num, _label) \ do { \ int _i; \ @@ -668,6 +693,11 @@ static int sam9x60_clk_probe(struct udevice *dev) clk_dm(AT91_TO_CLK_ID(PMC_TYPE_GCK, sam9x60_gck[i].id), c); }
- /* Setup clocks. */
- ret = at91_clk_setup(sam9x60_clk_setup, ARRAY_SIZE(sam9x60_clk_setup));
- if (ret)
goto fail;
- return 0;
fail:

Add the configs required to use the SAM9X60's USB clock.
Signed-off-by: Sergiu Moga sergiu.moga@microchip.com --- configs/sam9x60_curiosity_mmc_defconfig | 1 + configs/sam9x60ek_mmc_defconfig | 1 + configs/sam9x60ek_nandflash_defconfig | 1 + configs/sam9x60ek_qspiflash_defconfig | 1 + 4 files changed, 4 insertions(+)
diff --git a/configs/sam9x60_curiosity_mmc_defconfig b/configs/sam9x60_curiosity_mmc_defconfig index 732b5adf26..2bb196a5b6 100644 --- a/configs/sam9x60_curiosity_mmc_defconfig +++ b/configs/sam9x60_curiosity_mmc_defconfig @@ -54,6 +54,7 @@ CONFIG_CLK_CCF=y CONFIG_CLK_AT91=y CONFIG_AT91_GENERIC_CLK=y CONFIG_AT91_SAM9X60_PLL=y +CONFIG_AT91_SAM9X60_USB=y CONFIG_CPU=y CONFIG_AT91_GPIO=y CONFIG_DM_I2C=y diff --git a/configs/sam9x60ek_mmc_defconfig b/configs/sam9x60ek_mmc_defconfig index 268a485456..9dcceebc9b 100644 --- a/configs/sam9x60ek_mmc_defconfig +++ b/configs/sam9x60ek_mmc_defconfig @@ -59,6 +59,7 @@ CONFIG_CLK_CCF=y CONFIG_CLK_AT91=y CONFIG_AT91_GENERIC_CLK=y CONFIG_AT91_SAM9X60_PLL=y +CONFIG_AT91_SAM9X60_USB=y CONFIG_CPU=y CONFIG_AT91_GPIO=y CONFIG_DM_I2C=y diff --git a/configs/sam9x60ek_nandflash_defconfig b/configs/sam9x60ek_nandflash_defconfig index a9cbb6e953..86b3751072 100644 --- a/configs/sam9x60ek_nandflash_defconfig +++ b/configs/sam9x60ek_nandflash_defconfig @@ -61,6 +61,7 @@ CONFIG_CLK_CCF=y CONFIG_CLK_AT91=y CONFIG_AT91_GENERIC_CLK=y CONFIG_AT91_SAM9X60_PLL=y +CONFIG_AT91_SAM9X60_USB=y CONFIG_CPU=y CONFIG_AT91_GPIO=y CONFIG_DM_I2C=y diff --git a/configs/sam9x60ek_qspiflash_defconfig b/configs/sam9x60ek_qspiflash_defconfig index 72f08f1375..8b66dd22cd 100644 --- a/configs/sam9x60ek_qspiflash_defconfig +++ b/configs/sam9x60ek_qspiflash_defconfig @@ -61,6 +61,7 @@ CONFIG_CLK_CCF=y CONFIG_CLK_AT91=y CONFIG_AT91_GENERIC_CLK=y CONFIG_AT91_SAM9X60_PLL=y +CONFIG_AT91_SAM9X60_USB=y CONFIG_CPU=y CONFIG_AT91_GPIO=y CONFIG_DM_I2C=y

On 23.12.2022 14:33, Sergiu Moga wrote:
Add the configs required to use the SAM9X60's USB clock.
Signed-off-by: Sergiu Moga sergiu.moga@microchip.com
Reviewed-by: Claudiu Beznea claudiu.beznea@microchip.com
configs/sam9x60_curiosity_mmc_defconfig | 1 + configs/sam9x60ek_mmc_defconfig | 1 + configs/sam9x60ek_nandflash_defconfig | 1 + configs/sam9x60ek_qspiflash_defconfig | 1 + 4 files changed, 4 insertions(+)
diff --git a/configs/sam9x60_curiosity_mmc_defconfig b/configs/sam9x60_curiosity_mmc_defconfig index 732b5adf26..2bb196a5b6 100644 --- a/configs/sam9x60_curiosity_mmc_defconfig +++ b/configs/sam9x60_curiosity_mmc_defconfig @@ -54,6 +54,7 @@ CONFIG_CLK_CCF=y CONFIG_CLK_AT91=y CONFIG_AT91_GENERIC_CLK=y CONFIG_AT91_SAM9X60_PLL=y +CONFIG_AT91_SAM9X60_USB=y CONFIG_CPU=y CONFIG_AT91_GPIO=y CONFIG_DM_I2C=y diff --git a/configs/sam9x60ek_mmc_defconfig b/configs/sam9x60ek_mmc_defconfig index 268a485456..9dcceebc9b 100644 --- a/configs/sam9x60ek_mmc_defconfig +++ b/configs/sam9x60ek_mmc_defconfig @@ -59,6 +59,7 @@ CONFIG_CLK_CCF=y CONFIG_CLK_AT91=y CONFIG_AT91_GENERIC_CLK=y CONFIG_AT91_SAM9X60_PLL=y +CONFIG_AT91_SAM9X60_USB=y CONFIG_CPU=y CONFIG_AT91_GPIO=y CONFIG_DM_I2C=y diff --git a/configs/sam9x60ek_nandflash_defconfig b/configs/sam9x60ek_nandflash_defconfig index a9cbb6e953..86b3751072 100644 --- a/configs/sam9x60ek_nandflash_defconfig +++ b/configs/sam9x60ek_nandflash_defconfig @@ -61,6 +61,7 @@ CONFIG_CLK_CCF=y CONFIG_CLK_AT91=y CONFIG_AT91_GENERIC_CLK=y CONFIG_AT91_SAM9X60_PLL=y +CONFIG_AT91_SAM9X60_USB=y CONFIG_CPU=y CONFIG_AT91_GPIO=y CONFIG_DM_I2C=y diff --git a/configs/sam9x60ek_qspiflash_defconfig b/configs/sam9x60ek_qspiflash_defconfig index 72f08f1375..8b66dd22cd 100644 --- a/configs/sam9x60ek_qspiflash_defconfig +++ b/configs/sam9x60ek_qspiflash_defconfig @@ -61,6 +61,7 @@ CONFIG_CLK_CCF=y CONFIG_CLK_AT91=y CONFIG_AT91_GENERIC_CLK=y CONFIG_AT91_SAM9X60_PLL=y +CONFIG_AT91_SAM9X60_USB=y CONFIG_CPU=y CONFIG_AT91_GPIO=y CONFIG_DM_I2C=y

On Fri, 23 Dec 2022 14:33:09 +0200, Sergiu Moga wrote:
This patch series originates from a bigger patch series: https://lists.denx.de/pipermail/u-boot/2022-December/502865.html
A driver for clock operations on SAM9X60's USB clock has been added as well as its registration on CCF. In order for USB to work properly, the UPLL and USBCK need an initial frequency before probing the OHCI/EHCI driver. Furthermore enable this driver in the defconfigs.
[...]
Applied, thanks!
[1/5] clk: at91: Add support for sam9x60 USB clock commit: e9a2c657e6ac573386564aacd4836e2a65f4cfd0 [2/5] clk: at91: sam9x60: Register the required clocks for USB commit: 8b95d78f7727f6da6d518ea92a78f717f5293ac5 [3/5] clk: at91: pmc: export clock setup to pmc commit: 521548fb920a95ca167722986da0d76609a4a968 [4/5] clk: at91: sam9x60: Add initial setup of UPLL and USBCK rates commit: 548e4fd59f3ee6e06b1263b446ba11e15a980c7c [5/5] configs: at91: sam9x60: Add required configs for the USB clock commit: 96d3bc43d8ec5effbc3f8c1ced83c8e3e6dcbfb8
Best regards,

On 12/23/22 07:33, Sergiu Moga wrote:
This patch series originates from a bigger patch series: https://lists.denx.de/pipermail/u-boot/2022-December/502865.html
A driver for clock operations on SAM9X60's USB clock has been added as well as its registration on CCF. In order for USB to work properly, the UPLL and USBCK need an initial frequency before probing the OHCI/EHCI driver. Furthermore enable this driver in the defconfigs.
Claudiu Beznea (1): clk: at91: pmc: export clock setup to pmc
Sergiu Moga (4): clk: at91: Add support for sam9x60 USB clock clk: at91: sam9x60: Register the required clocks for USB clk: at91: sam9x60: Add initial setup of UPLL and USBCK rates configs: at91: sam9x60: Add required configs for the USB clock
configs/sam9x60_curiosity_mmc_defconfig | 1 + configs/sam9x60ek_mmc_defconfig | 1 + configs/sam9x60ek_nandflash_defconfig | 1 + configs/sam9x60ek_qspiflash_defconfig | 1 + drivers/clk/at91/Kconfig | 7 ++ drivers/clk/at91/Makefile | 1 + drivers/clk/at91/clk-sam9x60-usb.c | 157 ++++++++++++++++++++++++ drivers/clk/at91/pmc.c | 42 +++++++ drivers/clk/at91/pmc.h | 27 ++++ drivers/clk/at91/sam9x60.c | 63 ++++++++++ drivers/clk/at91/sama7g5.c | 48 +------- 11 files changed, 307 insertions(+), 42 deletions(-) create mode 100644 drivers/clk/at91/clk-sam9x60-usb.c
Failing CI pipeline: https://source.denx.de/u-boot/custodians/u-boot-clk/-/jobs/559107
arm-linux-gnueabi-ld.bfd: drivers/clk/at91/sam9x60.o: in function `sam9x60_clk_probe': drivers/clk/at91/sam9x60.c:595: undefined reference to `sam9x60_clk_register_usb'
--Sean
participants (3)
-
Claudiu.Beznea@microchip.com
-
Sean Anderson
-
Sergiu Moga