From b04da9fcf78e233e70ea5ace757c0b8b95bb2459 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:32 +0300 Subject: [PATCH 01/32] clk: check hw and hw->dev before dereference it Check hw and hw->dev before dereference it. Signed-off-by: Claudiu Beznea Reviewed-by: Simon Glass --- drivers/clk/clk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 786f4e887e..319808d433 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -57,6 +57,9 @@ ulong clk_generic_get_rate(struct clk *clk) const char *clk_hw_get_name(const struct clk *hw) { + assert(hw); + assert(hw->dev); + return hw->dev->name; } From cfecbaf4e768991056a88d3a7a3daf4b4baf8038 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:33 +0300 Subject: [PATCH 02/32] dm: core: add support for device re-parenting In common clock framework the relation b/w parent and child clocks is determined based on the udevice parent/child information. A clock parent could be changed based on devices needs. In case this is happen the functionalities for clock who's parent is changed are broken. Add a function that reparent a device. This will be used in clk-uclass.c to reparent a clock device. Signed-off-by: Claudiu Beznea Reviewed-by: Simon Glass --- drivers/core/device.c | 22 +++++ include/dm/device-internal.h | 9 ++ test/dm/core.c | 160 +++++++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) diff --git a/drivers/core/device.c b/drivers/core/device.c index 355dbd147a..e90d70101c 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -276,6 +276,28 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, return ret; } +int device_reparent(struct udevice *dev, struct udevice *new_parent) +{ + struct udevice *pos, *n; + + assert(dev); + assert(new_parent); + + list_for_each_entry_safe(pos, n, &dev->parent->child_head, + sibling_node) { + if (pos->driver != dev->driver) + continue; + + list_del(&dev->sibling_node); + list_add_tail(&dev->sibling_node, &new_parent->child_head); + dev->parent = new_parent; + + break; + } + + return 0; +} + static void *alloc_priv(int size, uint flags) { void *priv; diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index 5145fb4e14..1dcc22f689 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -83,6 +83,15 @@ int device_bind_with_driver_data(struct udevice *parent, int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, struct driver_info *info, struct udevice **devp); +/** + * device_reparent: reparent the device to a new parent + * + * @dev: pointer to device to be reparented + * @new_parent: pointer to new parent device + * @return 0 if OK, -ve on error + */ +int device_reparent(struct udevice *dev, struct udevice *new_parent); + /** * device_ofdata_to_platdata() - Read platform data for a device * diff --git a/test/dm/core.c b/test/dm/core.c index 8ed5bf7370..6f380a574c 100644 --- a/test/dm/core.c +++ b/test/dm/core.c @@ -643,6 +643,166 @@ static int dm_test_children(struct unit_test_state *uts) } DM_TEST(dm_test_children, 0); +static int dm_test_device_reparent(struct unit_test_state *uts) +{ + struct dm_test_state *dms = uts->priv; + struct udevice *top[NODE_COUNT]; + struct udevice *child[NODE_COUNT]; + struct udevice *grandchild[NODE_COUNT]; + struct udevice *dev; + int total; + int ret; + int i; + + /* We don't care about the numbering for this test */ + dms->skip_post_probe = 1; + + ut_assert(NODE_COUNT > 5); + + /* First create 10 top-level children */ + ut_assertok(create_children(uts, dms->root, NODE_COUNT, 0, top)); + + /* Now a few have their own children */ + ut_assertok(create_children(uts, top[2], NODE_COUNT, 2, NULL)); + ut_assertok(create_children(uts, top[5], NODE_COUNT, 5, child)); + + /* And grandchildren */ + for (i = 0; i < NODE_COUNT; i++) + ut_assertok(create_children(uts, child[i], NODE_COUNT, 50 * i, + i == 2 ? grandchild : NULL)); + + /* Check total number of devices */ + total = NODE_COUNT * (3 + NODE_COUNT); + ut_asserteq(total, dm_testdrv_op_count[DM_TEST_OP_BIND]); + + /* Probe everything */ + for (i = 0; i < total; i++) + ut_assertok(uclass_get_device(UCLASS_TEST, i, &dev)); + + /* Re-parent top-level children with no grandchildren. */ + ut_assertok(device_reparent(top[3], top[0])); + /* try to get devices */ + for (ret = uclass_find_first_device(UCLASS_TEST, &dev); + dev; + ret = uclass_find_next_device(&dev)) { + ut_assert(!ret); + ut_assertnonnull(dev); + } + + ut_assertok(device_reparent(top[4], top[0])); + /* try to get devices */ + for (ret = uclass_find_first_device(UCLASS_TEST, &dev); + dev; + ret = uclass_find_next_device(&dev)) { + ut_assert(!ret); + ut_assertnonnull(dev); + } + + /* Re-parent top-level children with grandchildren. */ + ut_assertok(device_reparent(top[2], top[0])); + /* try to get devices */ + for (ret = uclass_find_first_device(UCLASS_TEST, &dev); + dev; + ret = uclass_find_next_device(&dev)) { + ut_assert(!ret); + ut_assertnonnull(dev); + } + + ut_assertok(device_reparent(top[5], top[2])); + /* try to get devices */ + for (ret = uclass_find_first_device(UCLASS_TEST, &dev); + dev; + ret = uclass_find_next_device(&dev)) { + ut_assert(!ret); + ut_assertnonnull(dev); + } + + /* Re-parent grandchildren. */ + ut_assertok(device_reparent(grandchild[0], top[1])); + /* try to get devices */ + for (ret = uclass_find_first_device(UCLASS_TEST, &dev); + dev; + ret = uclass_find_next_device(&dev)) { + ut_assert(!ret); + ut_assertnonnull(dev); + } + + ut_assertok(device_reparent(grandchild[1], top[1])); + /* try to get devices */ + for (ret = uclass_find_first_device(UCLASS_TEST, &dev); + dev; + ret = uclass_find_next_device(&dev)) { + ut_assert(!ret); + ut_assertnonnull(dev); + } + + /* Remove re-pareneted devices. */ + ut_assertok(device_remove(top[3], DM_REMOVE_NORMAL)); + /* try to get devices */ + for (ret = uclass_find_first_device(UCLASS_TEST, &dev); + dev; + ret = uclass_find_next_device(&dev)) { + ut_assert(!ret); + ut_assertnonnull(dev); + } + + ut_assertok(device_remove(top[4], DM_REMOVE_NORMAL)); + /* try to get devices */ + for (ret = uclass_find_first_device(UCLASS_TEST, &dev); + dev; + ret = uclass_find_next_device(&dev)) { + ut_assert(!ret); + ut_assertnonnull(dev); + } + + ut_assertok(device_remove(top[5], DM_REMOVE_NORMAL)); + /* try to get devices */ + for (ret = uclass_find_first_device(UCLASS_TEST, &dev); + dev; + ret = uclass_find_next_device(&dev)) { + ut_assert(!ret); + ut_assertnonnull(dev); + } + + ut_assertok(device_remove(top[2], DM_REMOVE_NORMAL)); + for (ret = uclass_find_first_device(UCLASS_TEST, &dev); + dev; + ret = uclass_find_next_device(&dev)) { + ut_assert(!ret); + ut_assertnonnull(dev); + } + + ut_assertok(device_remove(grandchild[0], DM_REMOVE_NORMAL)); + /* try to get devices */ + for (ret = uclass_find_first_device(UCLASS_TEST, &dev); + dev; + ret = uclass_find_next_device(&dev)) { + ut_assert(!ret); + ut_assertnonnull(dev); + } + + ut_assertok(device_remove(grandchild[1], DM_REMOVE_NORMAL)); + /* try to get devices */ + for (ret = uclass_find_first_device(UCLASS_TEST, &dev); + dev; + ret = uclass_find_next_device(&dev)) { + ut_assert(!ret); + ut_assertnonnull(dev); + } + + /* Try the same with unbind */ + ut_assertok(device_unbind(top[3])); + ut_assertok(device_unbind(top[4])); + ut_assertok(device_unbind(top[5])); + ut_assertok(device_unbind(top[2])); + + ut_assertok(device_unbind(grandchild[0])); + ut_assertok(device_unbind(grandchild[1])); + + return 0; +} +DM_TEST(dm_test_device_reparent, 0); + /* Test that pre-relocation devices work as expected */ static int dm_test_pre_reloc(struct unit_test_state *uts) { From 4d139f3838b4ee48d7df9ca9c37ccd1a57202a52 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:34 +0300 Subject: [PATCH 03/32] clk: bind clk to new parent device Clock re-parenting is not binding the clock's device to its new parent device, it only calls the clock's ops->set_parent() API. The changes in this commit re-parent the clock device to its new parent so that subsequent operations like clk_get_parent() to point to the proper parent. Signed-off-by: Claudiu Beznea Reviewed-by: Simon Glass --- drivers/clk/clk-uclass.c | 11 ++++++++++- test/dm/clk_ccf.c | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 934cd5787a..5e0c8419d6 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -512,6 +513,7 @@ ulong clk_set_rate(struct clk *clk, ulong rate) int clk_set_parent(struct clk *clk, struct clk *parent) { const struct clk_ops *ops; + int ret; debug("%s(clk=%p, parent=%p)\n", __func__, clk, parent); if (!clk_valid(clk)) @@ -521,7 +523,14 @@ int clk_set_parent(struct clk *clk, struct clk *parent) if (!ops->set_parent) return -ENOSYS; - return ops->set_parent(clk, parent); + ret = ops->set_parent(clk, parent); + if (ret) + return ret; + + if (CONFIG_IS_ENABLED(CLK_CCF)) + ret = device_reparent(clk->dev, parent->dev); + + return ret; } int clk_enable(struct clk *clk) diff --git a/test/dm/clk_ccf.c b/test/dm/clk_ccf.c index 32bc4d2b8a..1ce28d747d 100644 --- a/test/dm/clk_ccf.c +++ b/test/dm/clk_ccf.c @@ -22,6 +22,10 @@ static int dm_test_clk_ccf(struct unit_test_state *uts) struct udevice *dev; long long rate; int ret; +#if CONFIG_IS_ENABLED(CLK_CCF) + const char *clkname; + int clkid; +#endif /* Get the device using the clk device */ ut_assertok(uclass_get_device_by_name(UCLASS_CLK, "clk-ccf", &dev)); @@ -130,6 +134,29 @@ static int dm_test_clk_ccf(struct unit_test_state *uts) ret = sandbox_clk_enable_count(pclk); ut_asserteq(ret, 0); + + /* Test clock re-parenting. */ + ret = clk_get_by_id(SANDBOX_CLK_USDHC1_SEL, &clk); + ut_assertok(ret); + ut_asserteq_str("usdhc1_sel", clk->dev->name); + + pclk = clk_get_parent(clk); + ut_assertok_ptr(pclk); + if (!strcmp(pclk->dev->name, "pll3_60m")) { + clkname = "pll3_80m"; + clkid = SANDBOX_CLK_PLL3_80M; + } else { + clkname = "pll3_60m"; + clkid = SANDBOX_CLK_PLL3_60M; + } + + ret = clk_get_by_id(clkid, &pclk); + ut_assertok(ret); + ret = clk_set_parent(clk, pclk); + ut_assertok(ret); + pclk = clk_get_parent(clk); + ut_assertok_ptr(pclk); + ut_asserteq_str(clkname, pclk->dev->name); #endif return 1; From 9a5d59dfc6475c4770bf702e4f30e338499310fd Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:35 +0300 Subject: [PATCH 04/32] clk: do not disable clock if it is critical Do not disable clock if it is a critical one. Signed-off-by: Claudiu Beznea Reviewed-by: Simon Glass --- drivers/clk/clk-uclass.c | 3 +++ test/dm/clk_ccf.c | 32 +++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 5e0c8419d6..b8538f342a 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -606,6 +606,9 @@ int clk_disable(struct clk *clk) if (CONFIG_IS_ENABLED(CLK_CCF)) { if (clk->id && !clk_get_by_id(clk->id, &clkp)) { + if (clkp->flags & CLK_IS_CRITICAL) + return 0; + if (clkp->enable_count == 0) { printf("clk %s already disabled\n", clkp->dev->name); diff --git a/test/dm/clk_ccf.c b/test/dm/clk_ccf.c index 1ce28d747d..e4ebb93cda 100644 --- a/test/dm/clk_ccf.c +++ b/test/dm/clk_ccf.c @@ -24,7 +24,7 @@ static int dm_test_clk_ccf(struct unit_test_state *uts) int ret; #if CONFIG_IS_ENABLED(CLK_CCF) const char *clkname; - int clkid; + int clkid, i; #endif /* Get the device using the clk device */ @@ -157,6 +157,36 @@ static int dm_test_clk_ccf(struct unit_test_state *uts) pclk = clk_get_parent(clk); ut_assertok_ptr(pclk); ut_asserteq_str(clkname, pclk->dev->name); + + /* Test disabling critical clock. */ + ret = clk_get_by_id(SANDBOX_CLK_I2C_ROOT, &clk); + ut_assertok(ret); + ut_asserteq_str("i2c_root", clk->dev->name); + + /* Disable it, if any. */ + ret = sandbox_clk_enable_count(clk); + for (i = 0; i < ret; i++) { + ret = clk_disable(clk); + ut_assertok(ret); + } + + ret = sandbox_clk_enable_count(clk); + ut_asserteq(ret, 0); + + clk->flags = CLK_IS_CRITICAL; + ret = clk_enable(clk); + ut_assertok(ret); + + ret = clk_disable(clk); + ut_assertok(ret); + ret = sandbox_clk_enable_count(clk); + ut_asserteq(ret, 1); + clk->flags &= ~CLK_IS_CRITICAL; + + ret = clk_disable(clk); + ut_assertok(ret); + ret = sandbox_clk_enable_count(clk); + ut_asserteq(ret, 0); #endif return 1; From b364134f87a2b3d021746b86b1f81278b15fa296 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:36 +0300 Subject: [PATCH 05/32] clk: get clock pointer before proceeding clk_get_by_indexed_prop() retrieves a clock with dev member being set with the pointer to the udevice for the clock controller driver. But in case of CCF each clock driver has set in dev member the reference to its parent (the root of the clock tree is a fixed clock, every node in clock tree is a clock registered with clk_register()). In this case the subsequent operations like dev_get_clk_ptr() on clocks retrieved by clk_get_by_indexed_prop() will fail. For this, get the pointer to the proper clock registered (with clk_register()) using clk_get_by_id() before proceeding. Fixes: 1d7993d1d0ef ("clk: Port Linux common clock framework [CCF] for imx6q to U-boot (tag: v5.1.12)") Signed-off-by: Claudiu Beznea Reviewed-by: Simon Glass --- drivers/clk/clk-uclass.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index b8538f342a..4076535271 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -188,9 +188,26 @@ bulk_get_err: return ret; } +static struct clk *clk_set_default_get_by_id(struct clk *clk) +{ + struct clk *c = clk; + + if (CONFIG_IS_ENABLED(CLK_CCF)) { + int ret = clk_get_by_id(clk->id, &c); + + if (ret) { + debug("%s(): could not get parent clock pointer, id %lu\n", + __func__, clk->id); + ERR_PTR(ret); + } + } + + return c; +} + static int clk_set_default_parents(struct udevice *dev, int stage) { - struct clk clk, parent_clk; + struct clk clk, parent_clk, *c, *p; int index; int num_parents; int ret; @@ -216,6 +233,10 @@ static int clk_set_default_parents(struct udevice *dev, int stage) return ret; } + p = clk_set_default_get_by_id(&parent_clk); + if (IS_ERR(p)) + return PTR_ERR(p); + ret = clk_get_by_indexed_prop(dev, "assigned-clocks", index, &clk); if (ret) { @@ -235,7 +256,11 @@ static int clk_set_default_parents(struct udevice *dev, int stage) /* do not setup twice the parent clocks */ continue; - ret = clk_set_parent(&clk, &parent_clk); + c = clk_set_default_get_by_id(&clk); + if (IS_ERR(c)) + return PTR_ERR(c); + + ret = clk_set_parent(c, p); /* * Not all drivers may support clock-reparenting (as of now). * Ignore errors due to this. @@ -255,7 +280,7 @@ static int clk_set_default_parents(struct udevice *dev, int stage) static int clk_set_default_rates(struct udevice *dev, int stage) { - struct clk clk; + struct clk clk, *c; int index; int num_rates; int size; @@ -299,7 +324,11 @@ static int clk_set_default_rates(struct udevice *dev, int stage) /* do not setup twice the parent clocks */ continue; - ret = clk_set_rate(&clk, rates[index]); + c = clk_set_default_get_by_id(&clk); + if (IS_ERR(c)) + return PTR_ERR(c); + + ret = clk_set_rate(c, rates[index]); if (ret < 0) { debug("%s: failed to set rate on clock index %d (%ld) for %s\n", From 643966a8fa620b763ad2c20c4d328aaefa23901d Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:37 +0300 Subject: [PATCH 06/32] clk: at91: add pre-requisite headers for AT91 clock architecture Add pre-requisite headers for AT91 clock architecture. These are based on already present files on Linux and will be used by following commits for AT91 CCF clock drivers. Signed-off-by: Claudiu Beznea --- include/dt-bindings/clk/at91.h | 22 +++ include/linux/clk/at91_pmc.h | 247 +++++++++++++++++++++++++++++++++ 2 files changed, 269 insertions(+) create mode 100644 include/dt-bindings/clk/at91.h create mode 100644 include/linux/clk/at91_pmc.h diff --git a/include/dt-bindings/clk/at91.h b/include/dt-bindings/clk/at91.h new file mode 100644 index 0000000000..e30756b280 --- /dev/null +++ b/include/dt-bindings/clk/at91.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * This header provides constants for AT91 pmc status. + * The constants defined in this header are being used in dts and PMC code. + * + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + * + * Based on include/dt-bindings/clock/at91.h on Linux. + */ + +#ifndef _DT_BINDINGS_CLK_AT91_H +#define _DT_BINDINGS_CLK_AT91_H + +#define PMC_TYPE_CORE 1 +#define PMC_TYPE_SYSTEM 2 +#define PMC_TYPE_PERIPHERAL 3 +#define PMC_TYPE_GCK 4 +#define PMC_TYPE_SLOW 5 + +#endif diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h new file mode 100644 index 0000000000..ee39e72e2b --- /dev/null +++ b/include/linux/clk/at91_pmc.h @@ -0,0 +1,247 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Power Management Controller (PMC) - System peripherals registers. + * + * Copyright (C) 2005 Ivan Kokshaysky + * Copyright (C) SAN People + * + * Based on AT91RM9200 datasheet revision E. + * Based on include/linux/clk/at91_pmc.h on Linux. + */ + +#ifndef AT91_PMC_H_ +#define AT91_PMC_H_ + +#define AT91_PMC_V1 (1) /* PMC version 1 */ +#define AT91_PMC_V2 (2) /* PMC version 2 [SAM9X60] */ + +#define AT91_PMC_SCER 0x00 /* System Clock Enable Register */ +#define AT91_PMC_SCDR 0x04 /* System Clock Disable Register */ + +#define AT91_PMC_SCSR 0x08 /* System Clock Status Register */ +#define AT91_PMC_PCK (1 << 0) /* Processor Clock */ +#define AT91RM9200_PMC_UDP (1 << 1) /* USB Devcice Port Clock [AT91RM9200 only] */ +#define AT91RM9200_PMC_MCKUDP (1 << 2) /* USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] */ +#define AT91RM9200_PMC_UHP (1 << 4) /* USB Host Port Clock [AT91RM9200 only] */ +#define AT91SAM926x_PMC_UHP (1 << 6) /* USB Host Port Clock [AT91SAM926x only] */ +#define AT91SAM926x_PMC_UDP (1 << 7) /* USB Devcice Port Clock [AT91SAM926x only] */ +#define AT91_PMC_PCK0 (1 << 8) /* Programmable Clock 0 */ +#define AT91_PMC_PCK1 (1 << 9) /* Programmable Clock 1 */ +#define AT91_PMC_PCK2 (1 << 10) /* Programmable Clock 2 */ +#define AT91_PMC_PCK3 (1 << 11) /* Programmable Clock 3 */ +#define AT91_PMC_PCK4 (1 << 12) /* Programmable Clock 4 [AT572D940HF only] */ +#define AT91_PMC_HCK0 (1 << 16) /* AHB Clock (USB host) [AT91SAM9261 only] */ +#define AT91_PMC_HCK1 (1 << 17) /* AHB Clock (LCD) [AT91SAM9261 only] */ + +#define AT91_PMC_PLL_CTRL0 0x0C /* PLL Control Register 0 [for SAM9X60] */ +#define AT91_PMC_PLL_CTRL0_ENPLL (1 << 28) /* Enable PLL */ +#define AT91_PMC_PLL_CTRL0_ENPLLCK (1 << 29) /* Enable PLL clock for PMC */ +#define AT91_PMC_PLL_CTRL0_ENLOCK (1 << 31) /* Enable PLL lock */ + +#define AT91_PMC_PLL_CTRL1 0x10 /* PLL Control Register 1 [for SAM9X60] */ + +#define AT91_PMC_PCER 0x10 /* Peripheral Clock Enable Register */ +#define AT91_PMC_PCDR 0x14 /* Peripheral Clock Disable Register */ +#define AT91_PMC_PCSR 0x18 /* Peripheral Clock Status Register */ + +#define AT91_PMC_PLL_ACR 0x18 /* PLL Analog Control Register [for SAM9X60] */ +#define AT91_PMC_PLL_ACR_DEFAULT_UPLL 0x12020010UL /* Default PLL ACR value for UPLL */ +#define AT91_PMC_PLL_ACR_DEFAULT_PLLA 0x00020010UL /* Default PLL ACR value for PLLA */ +#define AT91_PMC_PLL_ACR_UTMIVR (1 << 12) /* UPLL Voltage regulator Control */ +#define AT91_PMC_PLL_ACR_UTMIBG (1 << 13) /* UPLL Bandgap Control */ + +#define AT91_CKGR_UCKR 0x1C /* UTMI Clock Register [some SAM9] */ +#define AT91_PMC_UPLLEN (1 << 16) /* UTMI PLL Enable */ +#define AT91_PMC_UPLLCOUNT (0xf << 20) /* UTMI PLL Start-up Time */ +#define AT91_PMC_BIASEN (1 << 24) /* UTMI BIAS Enable */ +#define AT91_PMC_BIASCOUNT (0xf << 28) /* UTMI BIAS Start-up Time */ + +#define AT91_PMC_PLL_UPDT 0x1C /* PMC PLL update register [for SAM9X60] */ +#define AT91_PMC_PLL_UPDT_ID_MSK (0xf) +#define AT91_PMC_PLL_UPDT_UPDATE (1 << 8) /* Update PLL settings */ +#define AT91_PMC_PLL_UPDT_ID (1 << 0) /* PLL ID */ +#define AT91_PMC_PLL_UPDT_STUPTIM(n) ((n) << 16) /* Startup time */ +#define AT91_PMC_PMM_UPDT_STUPTIM_MSK (0xff << 16) + +#define AT91_CKGR_MOR 0x20 /* Main Oscillator Register [not on SAM9RL] */ +#define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */ +#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass */ +#define AT91_PMC_WAITMODE (1 << 2) /* Wait Mode Command */ +#define AT91_PMC_MOSCRCEN (1 << 3) /* Main On-Chip RC Oscillator Enable [some SAM9] */ +#define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */ +#define AT91_PMC_KEY_MASK (0xff << 16) +#define AT91_PMC_KEY (0x37 << 16) /* MOR Writing Key */ +#define AT91_PMC_MOSCSEL (1 << 24) /* Main Oscillator Selection [some SAM9] */ +#define AT91_PMC_CFDEN (1 << 25) /* Clock Failure Detector Enable [some SAM9] */ + +#define AT91_CKGR_MCFR 0x24 /* Main Clock Frequency Register */ +#define AT91_PMC_MAINF (0xffff << 0) /* Main Clock Frequency */ +#define AT91_PMC_MAINRDY (1 << 16) /* Main Clock Ready */ + +#define AT91_CKGR_PLLAR 0x28 /* PLL A Register */ +#define AT91_CKGR_PLLBR 0x2c /* PLL B Register */ +#define AT91_PMC_DIV (0xff << 0) /* Divider */ +#define AT91_PMC_PLLCOUNT (0x3f << 8) /* PLL Counter */ +#define AT91_PMC_OUT (3 << 14) /* PLL Clock Frequency Range */ +#define AT91_PMC_MUL (0x7ff << 16) /* PLL Multiplier */ +#define AT91_PMC_MUL_GET(n) ((n) >> 16 & 0x7ff) +#define AT91_PMC3_MUL (0x7f << 18) /* PLL Multiplier [SAMA5 only] */ +#define AT91_PMC3_MUL_GET(n) ((n) >> 18 & 0x7f) +#define AT91_PMC_USBDIV (3 << 28) /* USB Divisor (PLLB only) */ +#define AT91_PMC_USBDIV_1 (0 << 28) +#define AT91_PMC_USBDIV_2 (1 << 28) +#define AT91_PMC_USBDIV_4 (2 << 28) +#define AT91_PMC_USB96M (1 << 28) /* Divider by 2 Enable (PLLB only) */ + +#define AT91_PMC_CPU_CKR 0x28 /* CPU Clock Register */ + +#define AT91_PMC_MCKR 0x30 /* Master Clock Register */ +#define AT91_PMC_CSS (3 << 0) /* Master Clock Selection */ +#define AT91_PMC_CSS_SLOW (0 << 0) +#define AT91_PMC_CSS_MAIN (1 << 0) +#define AT91_PMC_CSS_PLLA (2 << 0) +#define AT91_PMC_CSS_PLLB (3 << 0) +#define AT91_PMC_CSS_UPLL (3 << 0) /* [some SAM9 only] */ +#define PMC_PRES_OFFSET 2 +#define AT91_PMC_PRES (7 << PMC_PRES_OFFSET) /* Master Clock Prescaler */ +#define AT91_PMC_PRES_1 (0 << PMC_PRES_OFFSET) +#define AT91_PMC_PRES_2 (1 << PMC_PRES_OFFSET) +#define AT91_PMC_PRES_4 (2 << PMC_PRES_OFFSET) +#define AT91_PMC_PRES_8 (3 << PMC_PRES_OFFSET) +#define AT91_PMC_PRES_16 (4 << PMC_PRES_OFFSET) +#define AT91_PMC_PRES_32 (5 << PMC_PRES_OFFSET) +#define AT91_PMC_PRES_64 (6 << PMC_PRES_OFFSET) +#define PMC_ALT_PRES_OFFSET 4 +#define AT91_PMC_ALT_PRES (7 << PMC_ALT_PRES_OFFSET) /* Master Clock Prescaler [alternate location] */ +#define AT91_PMC_ALT_PRES_1 (0 << PMC_ALT_PRES_OFFSET) +#define AT91_PMC_ALT_PRES_2 (1 << PMC_ALT_PRES_OFFSET) +#define AT91_PMC_ALT_PRES_4 (2 << PMC_ALT_PRES_OFFSET) +#define AT91_PMC_ALT_PRES_8 (3 << PMC_ALT_PRES_OFFSET) +#define AT91_PMC_ALT_PRES_16 (4 << PMC_ALT_PRES_OFFSET) +#define AT91_PMC_ALT_PRES_32 (5 << PMC_ALT_PRES_OFFSET) +#define AT91_PMC_ALT_PRES_64 (6 << PMC_ALT_PRES_OFFSET) +#define AT91_PMC_MDIV (3 << 8) /* Master Clock Division */ +#define AT91RM9200_PMC_MDIV_1 (0 << 8) /* [AT91RM9200 only] */ +#define AT91RM9200_PMC_MDIV_2 (1 << 8) +#define AT91RM9200_PMC_MDIV_3 (2 << 8) +#define AT91RM9200_PMC_MDIV_4 (3 << 8) +#define AT91SAM9_PMC_MDIV_1 (0 << 8) /* [SAM9 only] */ +#define AT91SAM9_PMC_MDIV_2 (1 << 8) +#define AT91SAM9_PMC_MDIV_4 (2 << 8) +#define AT91SAM9_PMC_MDIV_6 (3 << 8) /* [some SAM9 only] */ +#define AT91SAM9_PMC_MDIV_3 (3 << 8) /* [some SAM9 only] */ +#define AT91_PMC_PDIV (1 << 12) /* Processor Clock Division [some SAM9 only] */ +#define AT91_PMC_PDIV_1 (0 << 12) +#define AT91_PMC_PDIV_2 (1 << 12) +#define AT91_PMC_PLLADIV2 (1 << 12) /* PLLA divisor by 2 [some SAM9 only] */ +#define AT91_PMC_PLLADIV2_OFF (0 << 12) +#define AT91_PMC_PLLADIV2_ON (1 << 12) +#define AT91_PMC_H32MXDIV BIT(24) + +#define AT91_PMC_XTALF 0x34 /* Main XTAL Frequency Register [SAMA7G5 only] */ + +#define AT91_PMC_USB 0x38 /* USB Clock Register [some SAM9 only] */ +#define AT91_PMC_USBS (0x1 << 0) /* USB OHCI Input clock selection */ +#define AT91_PMC_USBS_PLLA (0 << 0) +#define AT91_PMC_USBS_UPLL (1 << 0) +#define AT91_PMC_USBS_PLLB (1 << 0) /* [AT91SAMN12 only] */ +#define AT91_PMC_OHCIUSBDIV (0xF << 8) /* Divider for USB OHCI Clock */ +#define AT91_PMC_OHCIUSBDIV_1 (0x0 << 8) +#define AT91_PMC_OHCIUSBDIV_2 (0x1 << 8) + +#define AT91_PMC_SMD 0x3c /* Soft Modem Clock Register [some SAM9 only] */ +#define AT91_PMC_SMDS (0x1 << 0) /* SMD input clock selection */ +#define AT91_PMC_SMD_DIV (0x1f << 8) /* SMD input clock divider */ +#define AT91_PMC_SMDDIV(n) (((n) << 8) & AT91_PMC_SMD_DIV) + +#define AT91_PMC_PCKR(n) (0x40 + ((n) * 4)) /* Programmable Clock 0-N Registers */ +#define AT91_PMC_ALT_PCKR_CSS (0x7 << 0) /* Programmable Clock Source Selection [alternate length] */ +#define AT91_PMC_CSS_MASTER (4 << 0) /* [some SAM9 only] */ +#define AT91_PMC_CSSMCK (0x1 << 8) /* CSS or Master Clock Selection */ +#define AT91_PMC_CSSMCK_CSS (0 << 8) +#define AT91_PMC_CSSMCK_MCK (1 << 8) + +#define AT91_PMC_IER 0x60 /* Interrupt Enable Register */ +#define AT91_PMC_IDR 0x64 /* Interrupt Disable Register */ +#define AT91_PMC_SR 0x68 /* Status Register */ +#define AT91_PMC_MOSCS (1 << 0) /* MOSCS Flag */ +#define AT91_PMC_LOCKA (1 << 1) /* PLLA Lock */ +#define AT91_PMC_LOCKB (1 << 2) /* PLLB Lock */ +#define AT91_PMC_MCKRDY (1 << 3) /* Master Clock */ +#define AT91_PMC_LOCKU (1 << 6) /* UPLL Lock [some SAM9] */ +#define AT91_PMC_OSCSEL (1 << 7) /* Slow Oscillator Selection [some SAM9] */ +#define AT91_PMC_PCK0RDY (1 << 8) /* Programmable Clock 0 */ +#define AT91_PMC_PCK1RDY (1 << 9) /* Programmable Clock 1 */ +#define AT91_PMC_PCK2RDY (1 << 10) /* Programmable Clock 2 */ +#define AT91_PMC_PCK3RDY (1 << 11) /* Programmable Clock 3 */ +#define AT91_PMC_MOSCSELS (1 << 16) /* Main Oscillator Selection [some SAM9] */ +#define AT91_PMC_MOSCRCS (1 << 17) /* Main On-Chip RC [some SAM9] */ +#define AT91_PMC_CFDEV (1 << 18) /* Clock Failure Detector Event [some SAM9] */ +#define AT91_PMC_GCKRDY (1 << 24) /* Generated Clocks */ +#define AT91_PMC_MCKXRDY (1 << 26) /* Master Clock x [x=1..4] Ready Status */ +#define AT91_PMC_IMR 0x6c /* Interrupt Mask Register */ + +#define AT91_PMC_FSMR 0x70 /* Fast Startup Mode Register */ +#define AT91_PMC_FSTT(n) BIT(n) +#define AT91_PMC_RTTAL BIT(16) +#define AT91_PMC_RTCAL BIT(17) /* RTC Alarm Enable */ +#define AT91_PMC_USBAL BIT(18) /* USB Resume Enable */ +#define AT91_PMC_SDMMC_CD BIT(19) /* SDMMC Card Detect Enable */ +#define AT91_PMC_LPM BIT(20) /* Low-power Mode */ +#define AT91_PMC_RXLP_MCE BIT(24) /* Backup UART Receive Enable */ +#define AT91_PMC_ACC_CE BIT(25) /* ACC Enable */ + +#define AT91_PMC_FSPR 0x74 /* Fast Startup Polarity Reg */ + +#define AT91_PMC_FS_INPUT_MASK 0x7ff + +#define AT91_PMC_PLLICPR 0x80 /* PLL Charge Pump Current Register */ + +#define AT91_PMC_PROT 0xe4 /* Write Protect Mode Register [some SAM9] */ +#define AT91_PMC_WPEN (0x1 << 0) /* Write Protect Enable */ +#define AT91_PMC_WPKEY (0xffffff << 8) /* Write Protect Key */ +#define AT91_PMC_PROTKEY (0x504d43 << 8) /* Activation Code */ + +#define AT91_PMC_WPSR 0xe8 /* Write Protect Status Register [some SAM9] */ +#define AT91_PMC_WPVS (0x1 << 0) /* Write Protect Violation Status */ +#define AT91_PMC_WPVSRC (0xffff << 8) /* Write Protect Violation Source */ + +#define AT91_PMC_PLL_ISR0 0xEC /* PLL Interrupt Status Register 0 [SAM9X60 only] */ + +#define AT91_PMC_PCER1 0x100 /* Peripheral Clock Enable Register 1 [SAMA5 only]*/ +#define AT91_PMC_PCDR1 0x104 /* Peripheral Clock Enable Register 1 */ +#define AT91_PMC_PCSR1 0x108 /* Peripheral Clock Enable Register 1 */ + +#define AT91_PMC_PCR 0x10c /* Peripheral Control Register [some SAM9 and SAMA5] */ +#define AT91_PMC_PCR_PID_MASK 0x3f +#define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */ +#define AT91_PMC_PCR_GCKDIV_MASK GENMASK(27, 20) +#define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */ +#define AT91_PMC_PCR_GCKEN (0x1 << 29) /* GCK Enable */ + +#define AT91_PMC_AUDIO_PLL0 0x14c +#define AT91_PMC_AUDIO_PLL_PLLEN (1 << 0) +#define AT91_PMC_AUDIO_PLL_PADEN (1 << 1) +#define AT91_PMC_AUDIO_PLL_PMCEN (1 << 2) +#define AT91_PMC_AUDIO_PLL_RESETN (1 << 3) +#define AT91_PMC_AUDIO_PLL_ND_OFFSET 8 +#define AT91_PMC_AUDIO_PLL_ND_MASK (0x7f << AT91_PMC_AUDIO_PLL_ND_OFFSET) +#define AT91_PMC_AUDIO_PLL_ND(n) ((n) << AT91_PMC_AUDIO_PLL_ND_OFFSET) +#define AT91_PMC_AUDIO_PLL_QDPMC_OFFSET 16 +#define AT91_PMC_AUDIO_PLL_QDPMC_MASK (0x7f << AT91_PMC_AUDIO_PLL_QDPMC_OFFSET) +#define AT91_PMC_AUDIO_PLL_QDPMC(n) ((n) << AT91_PMC_AUDIO_PLL_QDPMC_OFFSET) + +#define AT91_PMC_AUDIO_PLL1 0x150 +#define AT91_PMC_AUDIO_PLL_FRACR_MASK 0x3fffff +#define AT91_PMC_AUDIO_PLL_QDPAD_OFFSET 24 +#define AT91_PMC_AUDIO_PLL_QDPAD_MASK (0x7f << AT91_PMC_AUDIO_PLL_QDPAD_OFFSET) +#define AT91_PMC_AUDIO_PLL_QDPAD(n) ((n) << AT91_PMC_AUDIO_PLL_QDPAD_OFFSET) +#define AT91_PMC_AUDIO_PLL_QDPAD_DIV_OFFSET AT91_PMC_AUDIO_PLL_QDPAD_OFFSET +#define AT91_PMC_AUDIO_PLL_QDPAD_DIV_MASK (0x3 << AT91_PMC_AUDIO_PLL_QDPAD_DIV_OFFSET) +#define AT91_PMC_AUDIO_PLL_QDPAD_DIV(n) ((n) << AT91_PMC_AUDIO_PLL_QDPAD_DIV_OFFSET) +#define AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_OFFSET 26 +#define AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MAX 0x1f +#define AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MASK (AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MAX << AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_OFFSET) +#define AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV(n) ((n) << AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_OFFSET) + +#endif From 5d729f96299321af2c132fae4b56306e19a3f52b Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:38 +0300 Subject: [PATCH 07/32] clk: at91: pmc: add helpers for clock drivers Add helper for clock drivers. These will be used by following commits in the process of switching AT91 clock drivers to CCF. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/pmc.c | 91 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 13 ++++++ 2 files changed, 104 insertions(+) diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index ca90abef2d..e403baea0e 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -120,3 +120,94 @@ int at91_clk_probe(struct udevice *dev) return 0; } + +/** + * pmc_read() - read content at address base + off into val + * + * @base: base address + * @off: offset to read from + * @val: where the content of base + off is stored + * + * @return: void + */ +void pmc_read(void __iomem *base, unsigned int off, unsigned int *val) +{ + *val = readl(base + off); +} + +/** + * pmc_write() - write content of val at address base + off + * + * @base: base address + * @off: offset to write to + * @val: content to be written at base + off + * + * @return: void + */ +void pmc_write(void __iomem *base, unsigned int off, unsigned int val) +{ + writel(val, base + off); +} + +/** + * pmc_update_bits() - update a set of bits at address base + off + * + * @base: base address + * @off: offset to be updated + * @mask: mask of bits to be updated + * @bits: the new value to be updated + * + * @return: void + */ +void pmc_update_bits(void __iomem *base, unsigned int off, + unsigned int mask, unsigned int bits) +{ + unsigned int tmp; + + tmp = readl(base + off); + tmp &= ~mask; + writel(tmp | (bits & mask), base + off); +} + +/** + * at91_clk_mux_val_to_index() - get parent index in mux table + * + * @table: clock mux table + * @num_parents: clock number of parents + * @val: clock id who's mux index should be retrieved + * + * @return: clock index in mux table or a negative error number in case of + * failure + */ +int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val) +{ + int i; + + if (!table || !num_parents) + return -EINVAL; + + for (i = 0; i < num_parents; i++) { + if (table[i] == val) + return i; + } + + return -EINVAL; +} + +/** + * at91_clk_mux_index_to_val() - get parent ID corresponding to an entry in + * clock's mux table + * + * @table: clock's mux table + * @num_parents: clock's number of parents + * @index: index in mux table which clock's ID should be retrieved + * + * @return: clock ID or a negative error number in case of failure + */ +int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index) +{ + if (!table || !num_parents || index < 0 || index > num_parents) + return -EINVAL; + + return table[index]; +} diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 517ba1d6b4..b1ab0a95c8 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -8,6 +8,12 @@ #define __AT91_PMC_H__ #include +#include +#include + +/* Keep a range of 256 available clocks for every clock type. */ +#define AT91_TO_CLK_ID(_t, _i) (((_t) << 8) | ((_i) & 0xff)) +#define AT91_CLK_ID_TO_DID(_i) ((_i) & 0xff) struct pmc_platdata { struct at91_pmc *reg_base; @@ -20,4 +26,11 @@ int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name); int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args); int at91_clk_probe(struct udevice *dev); +int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val); +int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index); + +void pmc_read(void __iomem *base, unsigned int off, unsigned int *val); +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); #endif From 653bcce4085a5816a9fee560412fbfaa171db7bb Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:39 +0300 Subject: [PATCH 08/32] clk: at91: move clock code to compat.c Move clock code to compat.c to allow switching to CCF without mixing CCF code with non CCF code. This prepares the field for next commits. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/Makefile | 13 +- drivers/clk/at91/clk-generated.c | 178 ----- drivers/clk/at91/clk-h32mx.c | 56 -- drivers/clk/at91/clk-main.c | 54 -- drivers/clk/at91/clk-master.c | 33 - drivers/clk/at91/clk-peripheral.c | 113 ---- drivers/clk/at91/clk-plla.c | 54 -- drivers/clk/at91/clk-plladiv.c | 85 --- drivers/clk/at91/clk-slow.c | 36 - drivers/clk/at91/clk-system.c | 111 ---- drivers/clk/at91/clk-usb.c | 147 ----- drivers/clk/at91/clk-utmi.c | 142 ---- drivers/clk/at91/compat.c | 1023 +++++++++++++++++++++++++++++ drivers/clk/at91/pmc.c | 116 +--- drivers/clk/at91/pmc.h | 13 +- drivers/clk/at91/sckc.c | 19 - 16 files changed, 1030 insertions(+), 1163 deletions(-) delete mode 100644 drivers/clk/at91/clk-generated.c delete mode 100644 drivers/clk/at91/clk-h32mx.c delete mode 100644 drivers/clk/at91/clk-main.c delete mode 100644 drivers/clk/at91/clk-master.c delete mode 100644 drivers/clk/at91/clk-peripheral.c delete mode 100644 drivers/clk/at91/clk-plla.c delete mode 100644 drivers/clk/at91/clk-plladiv.c delete mode 100644 drivers/clk/at91/clk-slow.c delete mode 100644 drivers/clk/at91/clk-system.c delete mode 100644 drivers/clk/at91/clk-usb.c delete mode 100644 drivers/clk/at91/clk-utmi.c create mode 100644 drivers/clk/at91/compat.c delete mode 100644 drivers/clk/at91/sckc.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 8c197ff949..e2413af403 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -2,11 +2,8 @@ # Makefile for at91 specific clk # -obj-y += pmc.o sckc.o -obj-y += clk-slow.o clk-main.o clk-plla.o clk-plladiv.o clk-master.o -obj-y += clk-system.o clk-peripheral.o - -obj-$(CONFIG_AT91_UTMI) += clk-utmi.o -obj-$(CONFIG_AT91_USB_CLK) += clk-usb.o -obj-$(CONFIG_AT91_H32MX) += clk-h32mx.o -obj-$(CONFIG_AT91_GENERIC_CLK) += clk-generated.o +ifdef CONFIG_CLK_CCF +obj-y += pmc.o +else +obj-y += compat.o +endif diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c deleted file mode 100644 index c0610940c3..0000000000 --- a/drivers/clk/at91/clk-generated.c +++ /dev/null @@ -1,178 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2016 Atmel Corporation - * Wenyou.Yang - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "pmc.h" - -DECLARE_GLOBAL_DATA_PTR; - -#define GENERATED_SOURCE_MAX 6 -#define GENERATED_MAX_DIV 255 - -/** - * generated_clk_bind() - for the generated clock driver - * Recursively bind its children as clk devices. - * - * @return: 0 on success, or negative error code on failure - */ -static int generated_clk_bind(struct udevice *dev) -{ - return at91_clk_sub_device_bind(dev, "generic-clk"); -} - -static const struct udevice_id generated_clk_match[] = { - { .compatible = "atmel,sama5d2-clk-generated" }, - {} -}; - -U_BOOT_DRIVER(generated_clk) = { - .name = "generated-clk", - .id = UCLASS_MISC, - .of_match = generated_clk_match, - .bind = generated_clk_bind, -}; - -/*-------------------------------------------------------------*/ - -struct generic_clk_priv { - u32 num_parents; -}; - -static ulong generic_clk_get_rate(struct clk *clk) -{ - struct pmc_platdata *plat = dev_get_platdata(clk->dev); - struct at91_pmc *pmc = plat->reg_base; - struct clk parent; - ulong clk_rate; - u32 tmp, gckdiv; - u8 clock_source, parent_index; - int ret; - - writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr); - tmp = readl(&pmc->pcr); - clock_source = (tmp >> AT91_PMC_PCR_GCKCSS_OFFSET) & - AT91_PMC_PCR_GCKCSS_MASK; - gckdiv = (tmp >> AT91_PMC_PCR_GCKDIV_OFFSET) & AT91_PMC_PCR_GCKDIV_MASK; - - parent_index = clock_source - 1; - ret = clk_get_by_index(dev_get_parent(clk->dev), parent_index, &parent); - if (ret) - return 0; - - clk_rate = clk_get_rate(&parent) / (gckdiv + 1); - - clk_free(&parent); - - return clk_rate; -} - -static ulong generic_clk_set_rate(struct clk *clk, ulong rate) -{ - struct pmc_platdata *plat = dev_get_platdata(clk->dev); - struct at91_pmc *pmc = plat->reg_base; - struct generic_clk_priv *priv = dev_get_priv(clk->dev); - struct clk parent, best_parent; - ulong tmp_rate, best_rate = rate, parent_rate; - int tmp_diff, best_diff = -1; - u32 div, best_div = 0; - u8 best_parent_index, best_clock_source = 0; - u8 i; - u32 tmp; - int ret; - - for (i = 0; i < priv->num_parents; i++) { - ret = clk_get_by_index(dev_get_parent(clk->dev), i, &parent); - if (ret) - return ret; - - parent_rate = clk_get_rate(&parent); - if (IS_ERR_VALUE(parent_rate)) - return parent_rate; - - for (div = 1; div < GENERATED_MAX_DIV + 2; div++) { - tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div); - tmp_diff = abs(rate - tmp_rate); - - if (best_diff < 0 || best_diff > tmp_diff) { - best_rate = tmp_rate; - best_diff = tmp_diff; - - best_div = div - 1; - best_parent = parent; - best_parent_index = i; - best_clock_source = best_parent_index + 1; - } - - if (!best_diff || tmp_rate < rate) - break; - } - - if (!best_diff) - break; - } - - debug("GCK: best parent: %s, best_rate = %ld, best_div = %d\n", - best_parent.dev->name, best_rate, best_div); - - ret = clk_enable(&best_parent); - if (ret) - return ret; - - writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr); - tmp = readl(&pmc->pcr); - tmp &= ~(AT91_PMC_PCR_GCKDIV | AT91_PMC_PCR_GCKCSS); - tmp |= AT91_PMC_PCR_GCKCSS_(best_clock_source) | - AT91_PMC_PCR_CMD_WRITE | - AT91_PMC_PCR_GCKDIV_(best_div) | - AT91_PMC_PCR_GCKEN; - writel(tmp, &pmc->pcr); - - while (!(readl(&pmc->sr) & AT91_PMC_GCKRDY)) - ; - - return 0; -} - -static struct clk_ops generic_clk_ops = { - .of_xlate = at91_clk_of_xlate, - .get_rate = generic_clk_get_rate, - .set_rate = generic_clk_set_rate, -}; - -static int generic_clk_ofdata_to_platdata(struct udevice *dev) -{ - struct generic_clk_priv *priv = dev_get_priv(dev); - u32 cells[GENERATED_SOURCE_MAX]; - u32 num_parents; - - num_parents = fdtdec_get_int_array_count(gd->fdt_blob, - dev_of_offset(dev_get_parent(dev)), "clocks", cells, - GENERATED_SOURCE_MAX); - - if (!num_parents) - return -1; - - priv->num_parents = num_parents; - - return 0; -} - -U_BOOT_DRIVER(generic_clk) = { - .name = "generic-clk", - .id = UCLASS_CLK, - .probe = at91_clk_probe, - .ofdata_to_platdata = generic_clk_ofdata_to_platdata, - .priv_auto_alloc_size = sizeof(struct generic_clk_priv), - .platdata_auto_alloc_size = sizeof(struct pmc_platdata), - .ops = &generic_clk_ops, -}; diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c deleted file mode 100644 index 86bb71f612..0000000000 --- a/drivers/clk/at91/clk-h32mx.c +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2016 Atmel Corporation - * Wenyou.Yang - */ - -#include -#include -#include -#include -#include -#include -#include -#include "pmc.h" - -DECLARE_GLOBAL_DATA_PTR; - -#define H32MX_MAX_FREQ 90000000 - -static ulong sama5d4_h32mx_clk_get_rate(struct clk *clk) -{ - struct pmc_platdata *plat = dev_get_platdata(clk->dev); - struct at91_pmc *pmc = plat->reg_base; - ulong rate = gd->arch.mck_rate_hz; - - if (readl(&pmc->mckr) & AT91_PMC_MCKR_H32MXDIV) - rate /= 2; - - if (rate > H32MX_MAX_FREQ) - dev_dbg(clk->dev, "H32MX clock is too fast\n"); - - return rate; -} - -static struct clk_ops sama5d4_h32mx_clk_ops = { - .get_rate = sama5d4_h32mx_clk_get_rate, -}; - -static int sama5d4_h32mx_clk_probe(struct udevice *dev) -{ - return at91_pmc_core_probe(dev); -} - -static const struct udevice_id sama5d4_h32mx_clk_match[] = { - { .compatible = "atmel,sama5d4-clk-h32mx" }, - {} -}; - -U_BOOT_DRIVER(sama5d4_h32mx_clk) = { - .name = "sama5d4-h32mx-clk", - .id = UCLASS_CLK, - .of_match = sama5d4_h32mx_clk_match, - .probe = sama5d4_h32mx_clk_probe, - .platdata_auto_alloc_size = sizeof(struct pmc_platdata), - .ops = &sama5d4_h32mx_clk_ops, -}; diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c deleted file mode 100644 index b31a1cb682..0000000000 --- a/drivers/clk/at91/clk-main.c +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2016 Atmel Corporation - * Wenyou.Yang - */ - -#include -#include -#include -#include -#include -#include "pmc.h" - -DECLARE_GLOBAL_DATA_PTR; - -static int main_osc_clk_enable(struct clk *clk) -{ - struct pmc_platdata *plat = dev_get_platdata(clk->dev); - struct at91_pmc *pmc = plat->reg_base; - - if (readl(&pmc->sr) & AT91_PMC_MOSCSELS) - return 0; - - return -EINVAL; -} - -static ulong main_osc_clk_get_rate(struct clk *clk) -{ - return gd->arch.main_clk_rate_hz; -} - -static struct clk_ops main_osc_clk_ops = { - .enable = main_osc_clk_enable, - .get_rate = main_osc_clk_get_rate, -}; - -static int main_osc_clk_probe(struct udevice *dev) -{ - return at91_pmc_core_probe(dev); -} - -static const struct udevice_id main_osc_clk_match[] = { - { .compatible = "atmel,at91sam9x5-clk-main" }, - {} -}; - -U_BOOT_DRIVER(at91sam9x5_main_osc_clk) = { - .name = "at91sam9x5-main-osc-clk", - .id = UCLASS_CLK, - .of_match = main_osc_clk_match, - .probe = main_osc_clk_probe, - .platdata_auto_alloc_size = sizeof(struct pmc_platdata), - .ops = &main_osc_clk_ops, -}; diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c deleted file mode 100644 index e078fab7b4..0000000000 --- a/drivers/clk/at91/clk-master.c +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2016 Atmel Corporation - * Wenyou.Yang - */ - -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -static ulong at91_master_clk_get_rate(struct clk *clk) -{ - return gd->arch.mck_rate_hz; -} - -static struct clk_ops at91_master_clk_ops = { - .get_rate = at91_master_clk_get_rate, -}; - -static const struct udevice_id at91_master_clk_match[] = { - { .compatible = "atmel,at91rm9200-clk-master" }, - { .compatible = "atmel,at91sam9x5-clk-master" }, - {} -}; - -U_BOOT_DRIVER(atmel_at91rm9200_clk_master) = { - .name = "atmel_at91rm9200_clk_master", - .id = UCLASS_CLK, - .of_match = at91_master_clk_match, - .ops = &at91_master_clk_ops, -}; diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c deleted file mode 100644 index cd9d5e77c0..0000000000 --- a/drivers/clk/at91/clk-peripheral.c +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2016 Atmel Corporation - * Wenyou.Yang - */ - -#include -#include -#include -#include -#include -#include -#include "pmc.h" - -#define PERIPHERAL_ID_MIN 2 -#define PERIPHERAL_ID_MAX 31 -#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX)) - -enum periph_clk_type { - CLK_PERIPH_AT91RM9200 = 0, - CLK_PERIPH_AT91SAM9X5, -}; -/** - * sam9x5_periph_clk_bind() - for the periph clock driver - * Recursively bind its children as clk devices. - * - * @return: 0 on success, or negative error code on failure - */ -static int sam9x5_periph_clk_bind(struct udevice *dev) -{ - return at91_clk_sub_device_bind(dev, "periph-clk"); -} - -static const struct udevice_id sam9x5_periph_clk_match[] = { - { - .compatible = "atmel,at91rm9200-clk-peripheral", - .data = CLK_PERIPH_AT91RM9200, - }, - { - .compatible = "atmel,at91sam9x5-clk-peripheral", - .data = CLK_PERIPH_AT91SAM9X5, - }, - {} -}; - -U_BOOT_DRIVER(atmel_at91rm9200_clk_peripheral) = { - .name = "atmel_at91rm9200_clk_peripheral", - .id = UCLASS_MISC, - .of_match = sam9x5_periph_clk_match, - .bind = sam9x5_periph_clk_bind, -}; - -/*---------------------------------------------------------*/ - -static int periph_clk_enable(struct clk *clk) -{ - struct pmc_platdata *plat = dev_get_platdata(clk->dev); - struct at91_pmc *pmc = plat->reg_base; - enum periph_clk_type clk_type; - void *addr; - - if (clk->id < PERIPHERAL_ID_MIN) - return -1; - - clk_type = dev_get_driver_data(dev_get_parent(clk->dev)); - if (clk_type == CLK_PERIPH_AT91RM9200) { - addr = &pmc->pcer; - if (clk->id > PERIPHERAL_ID_MAX) - addr = &pmc->pcer1; - - setbits_le32(addr, PERIPHERAL_MASK(clk->id)); - } else { - writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr); - setbits_le32(&pmc->pcr, - AT91_PMC_PCR_CMD_WRITE | AT91_PMC_PCR_EN); - } - - return 0; -} - -static ulong periph_get_rate(struct clk *clk) -{ - struct udevice *dev; - struct clk clk_dev; - ulong clk_rate; - int ret; - - dev = dev_get_parent(clk->dev); - - ret = clk_get_by_index(dev, 0, &clk_dev); - if (ret) - return ret; - - clk_rate = clk_get_rate(&clk_dev); - - clk_free(&clk_dev); - - return clk_rate; -} - -static struct clk_ops periph_clk_ops = { - .of_xlate = at91_clk_of_xlate, - .enable = periph_clk_enable, - .get_rate = periph_get_rate, -}; - -U_BOOT_DRIVER(clk_periph) = { - .name = "periph-clk", - .id = UCLASS_CLK, - .platdata_auto_alloc_size = sizeof(struct pmc_platdata), - .probe = at91_clk_probe, - .ops = &periph_clk_ops, -}; diff --git a/drivers/clk/at91/clk-plla.c b/drivers/clk/at91/clk-plla.c deleted file mode 100644 index 79d725819f..0000000000 --- a/drivers/clk/at91/clk-plla.c +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2016 Atmel Corporation - * Wenyou.Yang - */ - -#include -#include -#include -#include -#include -#include "pmc.h" - -DECLARE_GLOBAL_DATA_PTR; - -static int plla_clk_enable(struct clk *clk) -{ - struct pmc_platdata *plat = dev_get_platdata(clk->dev); - struct at91_pmc *pmc = plat->reg_base; - - if (readl(&pmc->sr) & AT91_PMC_LOCKA) - return 0; - - return -EINVAL; -} - -static ulong plla_clk_get_rate(struct clk *clk) -{ - return gd->arch.plla_rate_hz; -} - -static struct clk_ops plla_clk_ops = { - .enable = plla_clk_enable, - .get_rate = plla_clk_get_rate, -}; - -static int plla_clk_probe(struct udevice *dev) -{ - return at91_pmc_core_probe(dev); -} - -static const struct udevice_id plla_clk_match[] = { - { .compatible = "atmel,sama5d3-clk-pll" }, - {} -}; - -U_BOOT_DRIVER(at91_plla_clk) = { - .name = "at91-plla-clk", - .id = UCLASS_CLK, - .of_match = plla_clk_match, - .probe = plla_clk_probe, - .platdata_auto_alloc_size = sizeof(struct pmc_platdata), - .ops = &plla_clk_ops, -}; diff --git a/drivers/clk/at91/clk-plladiv.c b/drivers/clk/at91/clk-plladiv.c deleted file mode 100644 index ca6158ef6a..0000000000 --- a/drivers/clk/at91/clk-plladiv.c +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2018 Microhip / Atmel Corporation - * Wenyou.Yang - */ - -#include -#include -#include -#include -#include -#include "pmc.h" - -static int at91_plladiv_clk_enable(struct clk *clk) -{ - return 0; -} - -static ulong at91_plladiv_clk_get_rate(struct clk *clk) -{ - struct pmc_platdata *plat = dev_get_platdata(clk->dev); - struct at91_pmc *pmc = plat->reg_base; - struct clk source; - ulong clk_rate; - int ret; - - ret = clk_get_by_index(clk->dev, 0, &source); - if (ret) - return -EINVAL; - - clk_rate = clk_get_rate(&source); - if (readl(&pmc->mckr) & AT91_PMC_MCKR_PLLADIV_2) - clk_rate /= 2; - - return clk_rate; -} - -static ulong at91_plladiv_clk_set_rate(struct clk *clk, ulong rate) -{ - struct pmc_platdata *plat = dev_get_platdata(clk->dev); - struct at91_pmc *pmc = plat->reg_base; - struct clk source; - ulong parent_rate; - int ret; - - ret = clk_get_by_index(clk->dev, 0, &source); - if (ret) - return -EINVAL; - - parent_rate = clk_get_rate(&source); - if ((parent_rate != rate) && ((parent_rate) / 2 != rate)) - return -EINVAL; - - if (parent_rate != rate) { - writel((readl(&pmc->mckr) | AT91_PMC_MCKR_PLLADIV_2), - &pmc->mckr); - } - - return 0; -} - -static struct clk_ops at91_plladiv_clk_ops = { - .enable = at91_plladiv_clk_enable, - .get_rate = at91_plladiv_clk_get_rate, - .set_rate = at91_plladiv_clk_set_rate, -}; - -static int at91_plladiv_clk_probe(struct udevice *dev) -{ - return at91_pmc_core_probe(dev); -} - -static const struct udevice_id at91_plladiv_clk_match[] = { - { .compatible = "atmel,at91sam9x5-clk-plldiv" }, - {} -}; - -U_BOOT_DRIVER(at91_plladiv_clk) = { - .name = "at91-plladiv-clk", - .id = UCLASS_CLK, - .of_match = at91_plladiv_clk_match, - .probe = at91_plladiv_clk_probe, - .platdata_auto_alloc_size = sizeof(struct pmc_platdata), - .ops = &at91_plladiv_clk_ops, -}; diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c deleted file mode 100644 index 1f8665768b..0000000000 --- a/drivers/clk/at91/clk-slow.c +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2016 Atmel Corporation - * Wenyou.Yang - */ - -#include -#include -#include - -static int at91_slow_clk_enable(struct clk *clk) -{ - return 0; -} - -static ulong at91_slow_clk_get_rate(struct clk *clk) -{ - return CONFIG_SYS_AT91_SLOW_CLOCK; -} - -static struct clk_ops at91_slow_clk_ops = { - .enable = at91_slow_clk_enable, - .get_rate = at91_slow_clk_get_rate, -}; - -static const struct udevice_id at91_slow_clk_match[] = { - { .compatible = "atmel,at91sam9x5-clk-slow" }, - {} -}; - -U_BOOT_DRIVER(at91_slow_clk) = { - .name = "at91-slow-clk", - .id = UCLASS_CLK, - .of_match = at91_slow_clk_match, - .ops = &at91_slow_clk_ops, -}; diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c deleted file mode 100644 index 76b1958670..0000000000 --- a/drivers/clk/at91/clk-system.c +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2016 Atmel Corporation - * Wenyou.Yang - */ - -#include -#include -#include -#include -#include -#include -#include "pmc.h" - -#define SYSTEM_MAX_ID 31 - -/** - * at91_system_clk_bind() - for the system clock driver - * Recursively bind its children as clk devices. - * - * @return: 0 on success, or negative error code on failure - */ -static int at91_system_clk_bind(struct udevice *dev) -{ - return at91_clk_sub_device_bind(dev, "system-clk"); -} - -static const struct udevice_id at91_system_clk_match[] = { - { .compatible = "atmel,at91rm9200-clk-system" }, - {} -}; - -U_BOOT_DRIVER(at91_system_clk) = { - .name = "at91-system-clk", - .id = UCLASS_MISC, - .of_match = at91_system_clk_match, - .bind = at91_system_clk_bind, -}; - -/*----------------------------------------------------------*/ - -static inline int is_pck(int id) -{ - return (id >= 8) && (id <= 15); -} - -static ulong system_clk_get_rate(struct clk *clk) -{ - struct clk clk_dev; - int ret; - - ret = clk_get_by_index(clk->dev, 0, &clk_dev); - if (ret) - return -EINVAL; - - return clk_get_rate(&clk_dev); -} - -static ulong system_clk_set_rate(struct clk *clk, ulong rate) -{ - struct clk clk_dev; - int ret; - - ret = clk_get_by_index(clk->dev, 0, &clk_dev); - if (ret) - return -EINVAL; - - return clk_set_rate(&clk_dev, rate); -} - -static int system_clk_enable(struct clk *clk) -{ - struct pmc_platdata *plat = dev_get_platdata(clk->dev); - struct at91_pmc *pmc = plat->reg_base; - u32 mask; - - if (clk->id > SYSTEM_MAX_ID) - return -EINVAL; - - mask = BIT(clk->id); - - writel(mask, &pmc->scer); - - /** - * For the programmable clocks the Ready status in the PMC - * status register should be checked after enabling. - * For other clocks this is unnecessary. - */ - if (!is_pck(clk->id)) - return 0; - - while (!(readl(&pmc->sr) & mask)) - ; - - return 0; -} - -static struct clk_ops system_clk_ops = { - .of_xlate = at91_clk_of_xlate, - .get_rate = system_clk_get_rate, - .set_rate = system_clk_set_rate, - .enable = system_clk_enable, -}; - -U_BOOT_DRIVER(system_clk) = { - .name = "system-clk", - .id = UCLASS_CLK, - .probe = at91_clk_probe, - .platdata_auto_alloc_size = sizeof(struct pmc_platdata), - .ops = &system_clk_ops, -}; diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c deleted file mode 100644 index af9d724369..0000000000 --- a/drivers/clk/at91/clk-usb.c +++ /dev/null @@ -1,147 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2018 Microhip / Atmel Corporation - * Wenyou.Yang - */ - -#include -#include -#include -#include -#include -#include -#include -#include "pmc.h" - -DECLARE_GLOBAL_DATA_PTR; - -#define AT91_USB_CLK_SOURCE_MAX 2 -#define AT91_USB_CLK_MAX_DIV 15 - -struct at91_usb_clk_priv { - u32 num_clksource; -}; - -static ulong at91_usb_clk_get_rate(struct clk *clk) -{ - struct pmc_platdata *plat = dev_get_platdata(clk->dev); - struct at91_pmc *pmc = plat->reg_base; - struct clk source; - u32 tmp, usbdiv; - u8 source_index; - int ret; - - tmp = readl(&pmc->pcr); - source_index = (tmp >> AT91_PMC_USB_USBS_OFFSET) & - AT91_PMC_USB_USBS_MASK; - usbdiv = (tmp >> AT91_PMC_USB_DIV_OFFSET) & AT91_PMC_USB_DIV_MASK; - - ret = clk_get_by_index(clk->dev, source_index, &source); - if (ret) - return 0; - - return clk_get_rate(&source) / (usbdiv + 1); -} - -static ulong at91_usb_clk_set_rate(struct clk *clk, ulong rate) -{ - struct pmc_platdata *plat = dev_get_platdata(clk->dev); - struct at91_pmc *pmc = plat->reg_base; - struct at91_usb_clk_priv *priv = dev_get_priv(clk->dev); - struct clk source, best_source; - ulong tmp_rate, best_rate = rate, source_rate; - int tmp_diff, best_diff = -1; - u32 div, best_div = 0; - u8 best_source_index = 0; - u8 i; - u32 tmp; - int ret; - - for (i = 0; i < priv->num_clksource; i++) { - ret = clk_get_by_index(clk->dev, i, &source); - if (ret) - return ret; - - source_rate = clk_get_rate(&source); - if (IS_ERR_VALUE(source_rate)) - return source_rate; - - for (div = 1; div < AT91_USB_CLK_MAX_DIV + 2; div++) { - tmp_rate = DIV_ROUND_CLOSEST(source_rate, div); - tmp_diff = abs(rate - tmp_rate); - - if (best_diff < 0 || best_diff > tmp_diff) { - best_rate = tmp_rate; - best_diff = tmp_diff; - - best_div = div - 1; - best_source = source; - best_source_index = i; - } - - if (!best_diff || tmp_rate < rate) - break; - } - - if (!best_diff) - break; - } - - debug("AT91 USB: best sourc: %s, best_rate = %ld, best_div = %d\n", - best_source.dev->name, best_rate, best_div); - - ret = clk_enable(&best_source); - if (ret) - return ret; - - tmp = AT91_PMC_USB_USBS_(best_source_index) | - AT91_PMC_USB_DIV_(best_div); - writel(tmp, &pmc->usb); - - return 0; -} - -static struct clk_ops at91_usb_clk_ops = { - .get_rate = at91_usb_clk_get_rate, - .set_rate = at91_usb_clk_set_rate, -}; - -static int at91_usb_clk_ofdata_to_platdata(struct udevice *dev) -{ - struct at91_usb_clk_priv *priv = dev_get_priv(dev); - u32 cells[AT91_USB_CLK_SOURCE_MAX]; - u32 num_clksource; - - num_clksource = fdtdec_get_int_array_count(gd->fdt_blob, - dev_of_offset(dev), - "clocks", cells, - AT91_USB_CLK_SOURCE_MAX); - - if (!num_clksource) - return -1; - - priv->num_clksource = num_clksource; - - return 0; -} - -static int at91_usb_clk_probe(struct udevice *dev) -{ - return at91_pmc_core_probe(dev); -} - -static const struct udevice_id at91_usb_clk_match[] = { - { .compatible = "atmel,at91sam9x5-clk-usb" }, - {} -}; - -U_BOOT_DRIVER(at91_usb_clk) = { - .name = "at91-usb-clk", - .id = UCLASS_CLK, - .of_match = at91_usb_clk_match, - .probe = at91_usb_clk_probe, - .ofdata_to_platdata = at91_usb_clk_ofdata_to_platdata, - .priv_auto_alloc_size = sizeof(struct at91_usb_clk_priv), - .platdata_auto_alloc_size = sizeof(struct pmc_platdata), - .ops = &at91_usb_clk_ops, -}; diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c deleted file mode 100644 index 18af0bfeaa..0000000000 --- a/drivers/clk/at91/clk-utmi.c +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2016 Atmel Corporation - * Wenyou.Yang - */ - -#include -#include -#include -#include -#include -#include -#include -#include "pmc.h" - -/* - * The purpose of this clock is to generate a 480 MHz signal. A different - * rate can't be configured. - */ -#define UTMI_RATE 480000000 - -static int utmi_clk_enable(struct clk *clk) -{ - struct pmc_platdata *plat = dev_get_platdata(clk->dev); - struct at91_pmc *pmc = plat->reg_base; - struct clk clk_dev; - ulong clk_rate; - u32 utmi_ref_clk_freq; - u32 tmp; - int err; - int timeout = 2000000; - - if (readl(&pmc->sr) & AT91_PMC_LOCKU) - return 0; - - /* - * If mainck rate is different from 12 MHz, we have to configure the - * FREQ field of the SFR_UTMICKTRIM register to generate properly - * the utmi clock. - */ - err = clk_get_by_index(clk->dev, 0, &clk_dev); - if (err) - return -EINVAL; - - clk_rate = clk_get_rate(&clk_dev); - switch (clk_rate) { - case 12000000: - utmi_ref_clk_freq = 0; - break; - case 16000000: - utmi_ref_clk_freq = 1; - break; - case 24000000: - utmi_ref_clk_freq = 2; - break; - /* - * Not supported on SAMA5D2 but it's not an issue since MAINCK - * maximum value is 24 MHz. - */ - case 48000000: - utmi_ref_clk_freq = 3; - break; - default: - printf("UTMICK: unsupported mainck rate\n"); - return -EINVAL; - } - - if (plat->regmap_sfr) { - err = regmap_read(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, &tmp); - if (err) - return -EINVAL; - - tmp &= ~AT91_UTMICKTRIM_FREQ; - tmp |= utmi_ref_clk_freq; - err = regmap_write(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, tmp); - if (err) - return -EINVAL; - } else if (utmi_ref_clk_freq) { - printf("UTMICK: sfr node required\n"); - return -EINVAL; - } - - tmp = readl(&pmc->uckr); - tmp |= AT91_PMC_UPLLEN | - AT91_PMC_UPLLCOUNT | - AT91_PMC_BIASEN; - writel(tmp, &pmc->uckr); - - while ((--timeout) && !(readl(&pmc->sr) & AT91_PMC_LOCKU)) - ; - if (!timeout) { - printf("UTMICK: timeout waiting for UPLL lock\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static ulong utmi_clk_get_rate(struct clk *clk) -{ - /* UTMI clk rate is fixed. */ - return UTMI_RATE; -} - -static struct clk_ops utmi_clk_ops = { - .enable = utmi_clk_enable, - .get_rate = utmi_clk_get_rate, -}; - -static int utmi_clk_ofdata_to_platdata(struct udevice *dev) -{ - struct pmc_platdata *plat = dev_get_platdata(dev); - struct udevice *syscon; - - uclass_get_device_by_phandle(UCLASS_SYSCON, dev, - "regmap-sfr", &syscon); - - if (syscon) - plat->regmap_sfr = syscon_get_regmap(syscon); - - return 0; -} - -static int utmi_clk_probe(struct udevice *dev) -{ - return at91_pmc_core_probe(dev); -} - -static const struct udevice_id utmi_clk_match[] = { - { .compatible = "atmel,at91sam9x5-clk-utmi" }, - {} -}; - -U_BOOT_DRIVER(at91sam9x5_utmi_clk) = { - .name = "at91sam9x5-utmi-clk", - .id = UCLASS_CLK, - .of_match = utmi_clk_match, - .probe = utmi_clk_probe, - .ofdata_to_platdata = utmi_clk_ofdata_to_platdata, - .platdata_auto_alloc_size = sizeof(struct pmc_platdata), - .ops = &utmi_clk_ops, -}; diff --git a/drivers/clk/at91/compat.c b/drivers/clk/at91/compat.c new file mode 100644 index 0000000000..8cf6254046 --- /dev/null +++ b/drivers/clk/at91/compat.c @@ -0,0 +1,1023 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Compatible code for non CCF AT91 platforms. + * + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +DECLARE_GLOBAL_DATA_PTR; + +struct pmc_platdata { + struct at91_pmc *reg_base; + struct regmap *regmap_sfr; +}; + +static const struct udevice_id at91_pmc_match[] = { + { .compatible = "atmel,at91rm9200-pmc" }, + { .compatible = "atmel,at91sam9260-pmc" }, + { .compatible = "atmel,at91sam9g45-pmc" }, + { .compatible = "atmel,at91sam9n12-pmc" }, + { .compatible = "atmel,at91sam9x5-pmc" }, + { .compatible = "atmel,sama5d3-pmc" }, + { .compatible = "atmel,sama5d2-pmc" }, + {} +}; + +U_BOOT_DRIVER(at91_pmc) = { + .name = "at91-pmc", + .id = UCLASS_SIMPLE_BUS, + .of_match = at91_pmc_match, +}; + +static int at91_pmc_core_probe(struct udevice *dev) +{ + struct pmc_platdata *plat = dev_get_platdata(dev); + + dev = dev_get_parent(dev); + + plat->reg_base = dev_read_addr_ptr(dev); + + return 0; +} + +/** + * at91_clk_sub_device_bind() - for the at91 clock driver + * Recursively bind its children as clk devices. + * + * @return: 0 on success, or negative error code on failure + */ +int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name) +{ + const void *fdt = gd->fdt_blob; + int offset = dev_of_offset(dev); + bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC); + const char *name; + int ret; + + for (offset = fdt_first_subnode(fdt, offset); + offset > 0; + offset = fdt_next_subnode(fdt, offset)) { + if (pre_reloc_only && + !ofnode_pre_reloc(offset_to_ofnode(offset))) + continue; + /* + * If this node has "compatible" property, this is not + * a clock sub-node, but a normal device. skip. + */ + fdt_get_property(fdt, offset, "compatible", &ret); + if (ret >= 0) + continue; + + if (ret != -FDT_ERR_NOTFOUND) + return ret; + + name = fdt_get_name(fdt, offset, NULL); + if (!name) + return -EINVAL; + ret = device_bind_driver_to_node(dev, drv_name, name, + offset_to_ofnode(offset), NULL); + if (ret) + return ret; + } + + return 0; +} + +int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) +{ + int periph; + + if (args->args_count) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + periph = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(clk->dev), "reg", + -1); + if (periph < 0) + return -EINVAL; + + clk->id = periph; + + return 0; +} + +int at91_clk_probe(struct udevice *dev) +{ + struct udevice *dev_periph_container, *dev_pmc; + struct pmc_platdata *plat = dev_get_platdata(dev); + + dev_periph_container = dev_get_parent(dev); + dev_pmc = dev_get_parent(dev_periph_container); + + plat->reg_base = dev_read_addr_ptr(dev_pmc); + + return 0; +} + +/* SCKC specific code. */ +static const struct udevice_id at91_sckc_match[] = { + { .compatible = "atmel,at91sam9x5-sckc" }, + {} +}; + +U_BOOT_DRIVER(at91_sckc) = { + .name = "at91-sckc", + .id = UCLASS_SIMPLE_BUS, + .of_match = at91_sckc_match, +}; + +/* Slow clock specific code. */ +static int at91_slow_clk_enable(struct clk *clk) +{ + return 0; +} + +static ulong at91_slow_clk_get_rate(struct clk *clk) +{ + return CONFIG_SYS_AT91_SLOW_CLOCK; +} + +static struct clk_ops at91_slow_clk_ops = { + .enable = at91_slow_clk_enable, + .get_rate = at91_slow_clk_get_rate, +}; + +static const struct udevice_id at91_slow_clk_match[] = { + { .compatible = "atmel,at91sam9x5-clk-slow" }, + {} +}; + +U_BOOT_DRIVER(at91_slow_clk) = { + .name = "at91-slow-clk", + .id = UCLASS_CLK, + .of_match = at91_slow_clk_match, + .ops = &at91_slow_clk_ops, +}; + +/* Master clock specific code. */ +static ulong at91_master_clk_get_rate(struct clk *clk) +{ + return gd->arch.mck_rate_hz; +} + +static struct clk_ops at91_master_clk_ops = { + .get_rate = at91_master_clk_get_rate, +}; + +static const struct udevice_id at91_master_clk_match[] = { + { .compatible = "atmel,at91rm9200-clk-master" }, + { .compatible = "atmel,at91sam9x5-clk-master" }, + {} +}; + +U_BOOT_DRIVER(at91_master_clk) = { + .name = "at91-master-clk", + .id = UCLASS_CLK, + .of_match = at91_master_clk_match, + .ops = &at91_master_clk_ops, +}; + +/* Main osc clock specific code. */ +static int main_osc_clk_enable(struct clk *clk) +{ + struct pmc_platdata *plat = dev_get_platdata(clk->dev); + struct at91_pmc *pmc = plat->reg_base; + + if (readl(&pmc->sr) & AT91_PMC_MOSCSELS) + return 0; + + return -EINVAL; +} + +static ulong main_osc_clk_get_rate(struct clk *clk) +{ + return gd->arch.main_clk_rate_hz; +} + +static struct clk_ops main_osc_clk_ops = { + .enable = main_osc_clk_enable, + .get_rate = main_osc_clk_get_rate, +}; + +static int main_osc_clk_probe(struct udevice *dev) +{ + return at91_pmc_core_probe(dev); +} + +static const struct udevice_id main_osc_clk_match[] = { + { .compatible = "atmel,at91sam9x5-clk-main" }, + {} +}; + +U_BOOT_DRIVER(at91sam9x5_main_osc_clk) = { + .name = "at91sam9x5-main-osc-clk", + .id = UCLASS_CLK, + .of_match = main_osc_clk_match, + .probe = main_osc_clk_probe, + .platdata_auto_alloc_size = sizeof(struct pmc_platdata), + .ops = &main_osc_clk_ops, +}; + +/* PLLA clock specific code. */ +static int plla_clk_enable(struct clk *clk) +{ + struct pmc_platdata *plat = dev_get_platdata(clk->dev); + struct at91_pmc *pmc = plat->reg_base; + + if (readl(&pmc->sr) & AT91_PMC_LOCKA) + return 0; + + return -EINVAL; +} + +static ulong plla_clk_get_rate(struct clk *clk) +{ + return gd->arch.plla_rate_hz; +} + +static struct clk_ops plla_clk_ops = { + .enable = plla_clk_enable, + .get_rate = plla_clk_get_rate, +}; + +static int plla_clk_probe(struct udevice *dev) +{ + return at91_pmc_core_probe(dev); +} + +static const struct udevice_id plla_clk_match[] = { + { .compatible = "atmel,sama5d3-clk-pll" }, + {} +}; + +U_BOOT_DRIVER(at91_plla_clk) = { + .name = "at91-plla-clk", + .id = UCLASS_CLK, + .of_match = plla_clk_match, + .probe = plla_clk_probe, + .platdata_auto_alloc_size = sizeof(struct pmc_platdata), + .ops = &plla_clk_ops, +}; + +/* PLLA DIV clock specific code. */ +static int at91_plladiv_clk_enable(struct clk *clk) +{ + return 0; +} + +static ulong at91_plladiv_clk_get_rate(struct clk *clk) +{ + struct pmc_platdata *plat = dev_get_platdata(clk->dev); + struct at91_pmc *pmc = plat->reg_base; + struct clk source; + ulong clk_rate; + int ret; + + ret = clk_get_by_index(clk->dev, 0, &source); + if (ret) + return -EINVAL; + + clk_rate = clk_get_rate(&source); + if (readl(&pmc->mckr) & AT91_PMC_MCKR_PLLADIV_2) + clk_rate /= 2; + + return clk_rate; +} + +static ulong at91_plladiv_clk_set_rate(struct clk *clk, ulong rate) +{ + struct pmc_platdata *plat = dev_get_platdata(clk->dev); + struct at91_pmc *pmc = plat->reg_base; + struct clk source; + ulong parent_rate; + int ret; + + ret = clk_get_by_index(clk->dev, 0, &source); + if (ret) + return -EINVAL; + + parent_rate = clk_get_rate(&source); + if ((parent_rate != rate) && ((parent_rate) / 2 != rate)) + return -EINVAL; + + if (parent_rate != rate) { + writel((readl(&pmc->mckr) | AT91_PMC_MCKR_PLLADIV_2), + &pmc->mckr); + } + + return 0; +} + +static struct clk_ops at91_plladiv_clk_ops = { + .enable = at91_plladiv_clk_enable, + .get_rate = at91_plladiv_clk_get_rate, + .set_rate = at91_plladiv_clk_set_rate, +}; + +static int at91_plladiv_clk_probe(struct udevice *dev) +{ + return at91_pmc_core_probe(dev); +} + +static const struct udevice_id at91_plladiv_clk_match[] = { + { .compatible = "atmel,at91sam9x5-clk-plldiv" }, + {} +}; + +U_BOOT_DRIVER(at91_plladiv_clk) = { + .name = "at91-plladiv-clk", + .id = UCLASS_CLK, + .of_match = at91_plladiv_clk_match, + .probe = at91_plladiv_clk_probe, + .platdata_auto_alloc_size = sizeof(struct pmc_platdata), + .ops = &at91_plladiv_clk_ops, +}; + +/* System clock specific code. */ +#define SYSTEM_MAX_ID 31 + +/** + * at91_system_clk_bind() - for the system clock driver + * Recursively bind its children as clk devices. + * + * @return: 0 on success, or negative error code on failure + */ +static int at91_system_clk_bind(struct udevice *dev) +{ + return at91_clk_sub_device_bind(dev, "system-clk"); +} + +static const struct udevice_id at91_system_clk_match[] = { + { .compatible = "atmel,at91rm9200-clk-system" }, + {} +}; + +U_BOOT_DRIVER(at91_system_clk) = { + .name = "at91-system-clk", + .id = UCLASS_MISC, + .of_match = at91_system_clk_match, + .bind = at91_system_clk_bind, +}; + +static inline int is_pck(int id) +{ + return (id >= 8) && (id <= 15); +} + +static ulong system_clk_get_rate(struct clk *clk) +{ + struct clk clk_dev; + int ret; + + ret = clk_get_by_index(clk->dev, 0, &clk_dev); + if (ret) + return -EINVAL; + + return clk_get_rate(&clk_dev); +} + +static ulong system_clk_set_rate(struct clk *clk, ulong rate) +{ + struct clk clk_dev; + int ret; + + ret = clk_get_by_index(clk->dev, 0, &clk_dev); + if (ret) + return -EINVAL; + + return clk_set_rate(&clk_dev, rate); +} + +static int system_clk_enable(struct clk *clk) +{ + struct pmc_platdata *plat = dev_get_platdata(clk->dev); + struct at91_pmc *pmc = plat->reg_base; + u32 mask; + + if (clk->id > SYSTEM_MAX_ID) + return -EINVAL; + + mask = BIT(clk->id); + + writel(mask, &pmc->scer); + + /** + * For the programmable clocks the Ready status in the PMC + * status register should be checked after enabling. + * For other clocks this is unnecessary. + */ + if (!is_pck(clk->id)) + return 0; + + while (!(readl(&pmc->sr) & mask)) + ; + + return 0; +} + +static struct clk_ops system_clk_ops = { + .of_xlate = at91_clk_of_xlate, + .get_rate = system_clk_get_rate, + .set_rate = system_clk_set_rate, + .enable = system_clk_enable, +}; + +U_BOOT_DRIVER(system_clk) = { + .name = "system-clk", + .id = UCLASS_CLK, + .probe = at91_clk_probe, + .platdata_auto_alloc_size = sizeof(struct pmc_platdata), + .ops = &system_clk_ops, +}; + +/* Peripheral clock specific code. */ +#define PERIPHERAL_ID_MIN 2 +#define PERIPHERAL_ID_MAX 31 +#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX)) + +enum periph_clk_type { + CLK_PERIPH_AT91RM9200 = 0, + CLK_PERIPH_AT91SAM9X5, +}; + +/** + * sam9x5_periph_clk_bind() - for the periph clock driver + * Recursively bind its children as clk devices. + * + * @return: 0 on success, or negative error code on failure + */ +static int sam9x5_periph_clk_bind(struct udevice *dev) +{ + return at91_clk_sub_device_bind(dev, "periph-clk"); +} + +static const struct udevice_id sam9x5_periph_clk_match[] = { + { + .compatible = "atmel,at91rm9200-clk-peripheral", + .data = CLK_PERIPH_AT91RM9200, + }, + { + .compatible = "atmel,at91sam9x5-clk-peripheral", + .data = CLK_PERIPH_AT91SAM9X5, + }, + {} +}; + +U_BOOT_DRIVER(sam9x5_periph_clk) = { + .name = "sam9x5-periph-clk", + .id = UCLASS_MISC, + .of_match = sam9x5_periph_clk_match, + .bind = sam9x5_periph_clk_bind, +}; + +static int periph_clk_enable(struct clk *clk) +{ + struct pmc_platdata *plat = dev_get_platdata(clk->dev); + struct at91_pmc *pmc = plat->reg_base; + enum periph_clk_type clk_type; + void *addr; + + if (clk->id < PERIPHERAL_ID_MIN) + return -1; + + clk_type = dev_get_driver_data(dev_get_parent(clk->dev)); + if (clk_type == CLK_PERIPH_AT91RM9200) { + addr = &pmc->pcer; + if (clk->id > PERIPHERAL_ID_MAX) + addr = &pmc->pcer1; + + setbits_le32(addr, PERIPHERAL_MASK(clk->id)); + } else { + writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr); + setbits_le32(&pmc->pcr, + AT91_PMC_PCR_CMD_WRITE | AT91_PMC_PCR_EN); + } + + return 0; +} + +static ulong periph_get_rate(struct clk *clk) +{ + struct udevice *dev; + struct clk clk_dev; + ulong clk_rate; + int ret; + + dev = dev_get_parent(clk->dev); + + ret = clk_get_by_index(dev, 0, &clk_dev); + if (ret) + return ret; + + clk_rate = clk_get_rate(&clk_dev); + + clk_free(&clk_dev); + + return clk_rate; +} + +static struct clk_ops periph_clk_ops = { + .of_xlate = at91_clk_of_xlate, + .enable = periph_clk_enable, + .get_rate = periph_get_rate, +}; + +U_BOOT_DRIVER(clk_periph) = { + .name = "periph-clk", + .id = UCLASS_CLK, + .platdata_auto_alloc_size = sizeof(struct pmc_platdata), + .probe = at91_clk_probe, + .ops = &periph_clk_ops, +}; + +/* UTMI clock specific code. */ +#ifdef CONFIG_AT91_UTMI + +/* + * The purpose of this clock is to generate a 480 MHz signal. A different + * rate can't be configured. + */ +#define UTMI_RATE 480000000 + +static int utmi_clk_enable(struct clk *clk) +{ + struct pmc_platdata *plat = dev_get_platdata(clk->dev); + struct at91_pmc *pmc = plat->reg_base; + struct clk clk_dev; + ulong clk_rate; + u32 utmi_ref_clk_freq; + u32 tmp; + int err; + int timeout = 2000000; + + if (readl(&pmc->sr) & AT91_PMC_LOCKU) + return 0; + + /* + * If mainck rate is different from 12 MHz, we have to configure the + * FREQ field of the SFR_UTMICKTRIM register to generate properly + * the utmi clock. + */ + err = clk_get_by_index(clk->dev, 0, &clk_dev); + if (err) + return -EINVAL; + + clk_rate = clk_get_rate(&clk_dev); + switch (clk_rate) { + case 12000000: + utmi_ref_clk_freq = 0; + break; + case 16000000: + utmi_ref_clk_freq = 1; + break; + case 24000000: + utmi_ref_clk_freq = 2; + break; + /* + * Not supported on SAMA5D2 but it's not an issue since MAINCK + * maximum value is 24 MHz. + */ + case 48000000: + utmi_ref_clk_freq = 3; + break; + default: + printf("UTMICK: unsupported mainck rate\n"); + return -EINVAL; + } + + if (plat->regmap_sfr) { + err = regmap_read(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, &tmp); + if (err) + return -EINVAL; + + tmp &= ~AT91_UTMICKTRIM_FREQ; + tmp |= utmi_ref_clk_freq; + err = regmap_write(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, tmp); + if (err) + return -EINVAL; + } else if (utmi_ref_clk_freq) { + printf("UTMICK: sfr node required\n"); + return -EINVAL; + } + + tmp = readl(&pmc->uckr); + tmp |= AT91_PMC_UPLLEN | + AT91_PMC_UPLLCOUNT | + AT91_PMC_BIASEN; + writel(tmp, &pmc->uckr); + + while ((--timeout) && !(readl(&pmc->sr) & AT91_PMC_LOCKU)) + ; + if (!timeout) { + printf("UTMICK: timeout waiting for UPLL lock\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static ulong utmi_clk_get_rate(struct clk *clk) +{ + /* UTMI clk rate is fixed. */ + return UTMI_RATE; +} + +static struct clk_ops utmi_clk_ops = { + .enable = utmi_clk_enable, + .get_rate = utmi_clk_get_rate, +}; + +static int utmi_clk_ofdata_to_platdata(struct udevice *dev) +{ + struct pmc_platdata *plat = dev_get_platdata(dev); + struct udevice *syscon; + + uclass_get_device_by_phandle(UCLASS_SYSCON, dev, + "regmap-sfr", &syscon); + + if (syscon) + plat->regmap_sfr = syscon_get_regmap(syscon); + + return 0; +} + +static int utmi_clk_probe(struct udevice *dev) +{ + return at91_pmc_core_probe(dev); +} + +static const struct udevice_id utmi_clk_match[] = { + { .compatible = "atmel,at91sam9x5-clk-utmi" }, + {} +}; + +U_BOOT_DRIVER(at91sam9x5_utmi_clk) = { + .name = "at91sam9x5-utmi-clk", + .id = UCLASS_CLK, + .of_match = utmi_clk_match, + .probe = utmi_clk_probe, + .ofdata_to_platdata = utmi_clk_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct pmc_platdata), + .ops = &utmi_clk_ops, +}; + +#endif /* CONFIG_AT91_UTMI */ + +/* H32MX clock specific code. */ +#ifdef CONFIG_AT91_H32MX + +#define H32MX_MAX_FREQ 90000000 + +static ulong sama5d4_h32mx_clk_get_rate(struct clk *clk) +{ + struct pmc_platdata *plat = dev_get_platdata(clk->dev); + struct at91_pmc *pmc = plat->reg_base; + ulong rate = gd->arch.mck_rate_hz; + + if (readl(&pmc->mckr) & AT91_PMC_MCKR_H32MXDIV) + rate /= 2; + + if (rate > H32MX_MAX_FREQ) + dev_dbg(clk->dev, "H32MX clock is too fast\n"); + + return rate; +} + +static struct clk_ops sama5d4_h32mx_clk_ops = { + .get_rate = sama5d4_h32mx_clk_get_rate, +}; + +static int sama5d4_h32mx_clk_probe(struct udevice *dev) +{ + return at91_pmc_core_probe(dev); +} + +static const struct udevice_id sama5d4_h32mx_clk_match[] = { + { .compatible = "atmel,sama5d4-clk-h32mx" }, + {} +}; + +U_BOOT_DRIVER(sama5d4_h32mx_clk) = { + .name = "sama5d4-h32mx-clk", + .id = UCLASS_CLK, + .of_match = sama5d4_h32mx_clk_match, + .probe = sama5d4_h32mx_clk_probe, + .platdata_auto_alloc_size = sizeof(struct pmc_platdata), + .ops = &sama5d4_h32mx_clk_ops, +}; + +#endif /* CONFIG_AT91_H32MX */ + +/* Generic clock specific code. */ +#ifdef CONFIG_AT91_GENERIC_CLK + +#define GENERATED_SOURCE_MAX 6 +#define GENERATED_MAX_DIV 255 + +/** + * generated_clk_bind() - for the generated clock driver + * Recursively bind its children as clk devices. + * + * @return: 0 on success, or negative error code on failure + */ +static int generated_clk_bind(struct udevice *dev) +{ + return at91_clk_sub_device_bind(dev, "generic-clk"); +} + +static const struct udevice_id generated_clk_match[] = { + { .compatible = "atmel,sama5d2-clk-generated" }, + {} +}; + +U_BOOT_DRIVER(generated_clk) = { + .name = "generated-clk", + .id = UCLASS_MISC, + .of_match = generated_clk_match, + .bind = generated_clk_bind, +}; + +struct generic_clk_priv { + u32 num_parents; +}; + +static ulong generic_clk_get_rate(struct clk *clk) +{ + struct pmc_platdata *plat = dev_get_platdata(clk->dev); + struct at91_pmc *pmc = plat->reg_base; + struct clk parent; + ulong clk_rate; + u32 tmp, gckdiv; + u8 clock_source, parent_index; + int ret; + + writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr); + tmp = readl(&pmc->pcr); + clock_source = (tmp >> AT91_PMC_PCR_GCKCSS_OFFSET) & + AT91_PMC_PCR_GCKCSS_MASK; + gckdiv = (tmp >> AT91_PMC_PCR_GCKDIV_OFFSET) & AT91_PMC_PCR_GCKDIV_MASK; + + parent_index = clock_source - 1; + ret = clk_get_by_index(dev_get_parent(clk->dev), parent_index, &parent); + if (ret) + return 0; + + clk_rate = clk_get_rate(&parent) / (gckdiv + 1); + + clk_free(&parent); + + return clk_rate; +} + +static ulong generic_clk_set_rate(struct clk *clk, ulong rate) +{ + struct pmc_platdata *plat = dev_get_platdata(clk->dev); + struct at91_pmc *pmc = plat->reg_base; + struct generic_clk_priv *priv = dev_get_priv(clk->dev); + struct clk parent, best_parent; + ulong tmp_rate, best_rate = rate, parent_rate; + int tmp_diff, best_diff = -1; + u32 div, best_div = 0; + u8 best_parent_index, best_clock_source = 0; + u8 i; + u32 tmp; + int ret; + + for (i = 0; i < priv->num_parents; i++) { + ret = clk_get_by_index(dev_get_parent(clk->dev), i, &parent); + if (ret) + return ret; + + parent_rate = clk_get_rate(&parent); + if (IS_ERR_VALUE(parent_rate)) + return parent_rate; + + for (div = 1; div < GENERATED_MAX_DIV + 2; div++) { + tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div); + tmp_diff = abs(rate - tmp_rate); + + if (best_diff < 0 || best_diff > tmp_diff) { + best_rate = tmp_rate; + best_diff = tmp_diff; + + best_div = div - 1; + best_parent = parent; + best_parent_index = i; + best_clock_source = best_parent_index + 1; + } + + if (!best_diff || tmp_rate < rate) + break; + } + + if (!best_diff) + break; + } + + debug("GCK: best parent: %s, best_rate = %ld, best_div = %d\n", + best_parent.dev->name, best_rate, best_div); + + ret = clk_enable(&best_parent); + if (ret) + return ret; + + writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr); + tmp = readl(&pmc->pcr); + tmp &= ~(AT91_PMC_PCR_GCKDIV | AT91_PMC_PCR_GCKCSS); + tmp |= AT91_PMC_PCR_GCKCSS_(best_clock_source) | + AT91_PMC_PCR_CMD_WRITE | + AT91_PMC_PCR_GCKDIV_(best_div) | + AT91_PMC_PCR_GCKEN; + writel(tmp, &pmc->pcr); + + while (!(readl(&pmc->sr) & AT91_PMC_GCKRDY)) + ; + + return 0; +} + +static struct clk_ops generic_clk_ops = { + .of_xlate = at91_clk_of_xlate, + .get_rate = generic_clk_get_rate, + .set_rate = generic_clk_set_rate, +}; + +static int generic_clk_ofdata_to_platdata(struct udevice *dev) +{ + struct generic_clk_priv *priv = dev_get_priv(dev); + u32 cells[GENERATED_SOURCE_MAX]; + u32 num_parents; + + num_parents = fdtdec_get_int_array_count(gd->fdt_blob, + dev_of_offset(dev_get_parent(dev)), "clocks", cells, + GENERATED_SOURCE_MAX); + + if (!num_parents) + return -1; + + priv->num_parents = num_parents; + + return 0; +} + +U_BOOT_DRIVER(generic_clk) = { + .name = "generic-clk", + .id = UCLASS_CLK, + .probe = at91_clk_probe, + .ofdata_to_platdata = generic_clk_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct generic_clk_priv), + .platdata_auto_alloc_size = sizeof(struct pmc_platdata), + .ops = &generic_clk_ops, +}; + +#endif /* CONFIG_AT91_GENERIC_CLK */ + +/* USB clock specific code. */ +#ifdef CONFIG_AT91_USB_CLK + +#define AT91_USB_CLK_SOURCE_MAX 2 +#define AT91_USB_CLK_MAX_DIV 15 + +struct at91_usb_clk_priv { + u32 num_clksource; +}; + +static ulong at91_usb_clk_get_rate(struct clk *clk) +{ + struct pmc_platdata *plat = dev_get_platdata(clk->dev); + struct at91_pmc *pmc = plat->reg_base; + struct clk source; + u32 tmp, usbdiv; + u8 source_index; + int ret; + + tmp = readl(&pmc->pcr); + source_index = (tmp >> AT91_PMC_USB_USBS_OFFSET) & + AT91_PMC_USB_USBS_MASK; + usbdiv = (tmp >> AT91_PMC_USB_DIV_OFFSET) & AT91_PMC_USB_DIV_MASK; + + ret = clk_get_by_index(clk->dev, source_index, &source); + if (ret) + return 0; + + return clk_get_rate(&source) / (usbdiv + 1); +} + +static ulong at91_usb_clk_set_rate(struct clk *clk, ulong rate) +{ + struct pmc_platdata *plat = dev_get_platdata(clk->dev); + struct at91_pmc *pmc = plat->reg_base; + struct at91_usb_clk_priv *priv = dev_get_priv(clk->dev); + struct clk source, best_source; + ulong tmp_rate, best_rate = rate, source_rate; + int tmp_diff, best_diff = -1; + u32 div, best_div = 0; + u8 best_source_index = 0; + u8 i; + u32 tmp; + int ret; + + for (i = 0; i < priv->num_clksource; i++) { + ret = clk_get_by_index(clk->dev, i, &source); + if (ret) + return ret; + + source_rate = clk_get_rate(&source); + if (IS_ERR_VALUE(source_rate)) + return source_rate; + + for (div = 1; div < AT91_USB_CLK_MAX_DIV + 2; div++) { + tmp_rate = DIV_ROUND_CLOSEST(source_rate, div); + tmp_diff = abs(rate - tmp_rate); + + if (best_diff < 0 || best_diff > tmp_diff) { + best_rate = tmp_rate; + best_diff = tmp_diff; + + best_div = div - 1; + best_source = source; + best_source_index = i; + } + + if (!best_diff || tmp_rate < rate) + break; + } + + if (!best_diff) + break; + } + + debug("AT91 USB: best sourc: %s, best_rate = %ld, best_div = %d\n", + best_source.dev->name, best_rate, best_div); + + ret = clk_enable(&best_source); + if (ret) + return ret; + + tmp = AT91_PMC_USB_USBS_(best_source_index) | + AT91_PMC_USB_DIV_(best_div); + writel(tmp, &pmc->usb); + + return 0; +} + +static struct clk_ops at91_usb_clk_ops = { + .get_rate = at91_usb_clk_get_rate, + .set_rate = at91_usb_clk_set_rate, +}; + +static int at91_usb_clk_ofdata_to_platdata(struct udevice *dev) +{ + struct at91_usb_clk_priv *priv = dev_get_priv(dev); + u32 cells[AT91_USB_CLK_SOURCE_MAX]; + u32 num_clksource; + + num_clksource = fdtdec_get_int_array_count(gd->fdt_blob, + dev_of_offset(dev), + "clocks", cells, + AT91_USB_CLK_SOURCE_MAX); + + if (!num_clksource) + return -1; + + priv->num_clksource = num_clksource; + + return 0; +} + +static int at91_usb_clk_probe(struct udevice *dev) +{ + return at91_pmc_core_probe(dev); +} + +static const struct udevice_id at91_usb_clk_match[] = { + { .compatible = "atmel,at91sam9x5-clk-usb" }, + {} +}; + +U_BOOT_DRIVER(at91_usb_clk) = { + .name = "at91-usb-clk", + .id = UCLASS_CLK, + .of_match = at91_usb_clk_match, + .probe = at91_usb_clk_probe, + .ofdata_to_platdata = at91_usb_clk_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct at91_usb_clk_priv), + .platdata_auto_alloc_size = sizeof(struct pmc_platdata), + .ops = &at91_usb_clk_ops, +}; + +#endif /* CONFIG_AT91_USB_CLK */ diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index e403baea0e..29c6452497 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -4,122 +4,8 @@ * Wenyou.Yang */ +#include #include -#include -#include -#include -#include -#include -#include "pmc.h" - -DECLARE_GLOBAL_DATA_PTR; - -static const struct udevice_id at91_pmc_match[] = { - { .compatible = "atmel,at91rm9200-pmc" }, - { .compatible = "atmel,at91sam9260-pmc" }, - { .compatible = "atmel,at91sam9g45-pmc" }, - { .compatible = "atmel,at91sam9n12-pmc" }, - { .compatible = "atmel,at91sam9x5-pmc" }, - { .compatible = "atmel,sama5d3-pmc" }, - { .compatible = "atmel,sama5d2-pmc" }, - {} -}; - -U_BOOT_DRIVER(atmel_at91rm9200_pmc) = { - .name = "atmel_at91rm9200_pmc", - .id = UCLASS_SIMPLE_BUS, - .of_match = at91_pmc_match, -}; - -U_BOOT_DRIVER_ALIAS(atmel_at91rm9200_pmc, atmel_at91sam9260_pmc) - -/*---------------------------------------------------------*/ - -int at91_pmc_core_probe(struct udevice *dev) -{ - struct pmc_platdata *plat = dev_get_platdata(dev); - - dev = dev_get_parent(dev); - - plat->reg_base = dev_read_addr_ptr(dev); - - return 0; -} - -/** - * at91_clk_sub_device_bind() - for the at91 clock driver - * Recursively bind its children as clk devices. - * - * @return: 0 on success, or negative error code on failure - */ -int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name) -{ - const void *fdt = gd->fdt_blob; - int offset = dev_of_offset(dev); - bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC); - const char *name; - int ret; - - for (offset = fdt_first_subnode(fdt, offset); - offset > 0; - offset = fdt_next_subnode(fdt, offset)) { - if (pre_reloc_only && - !ofnode_pre_reloc(offset_to_ofnode(offset))) - continue; - /* - * If this node has "compatible" property, this is not - * a clock sub-node, but a normal device. skip. - */ - fdt_get_property(fdt, offset, "compatible", &ret); - if (ret >= 0) - continue; - - if (ret != -FDT_ERR_NOTFOUND) - return ret; - - name = fdt_get_name(fdt, offset, NULL); - if (!name) - return -EINVAL; - ret = device_bind_driver_to_node(dev, drv_name, name, - offset_to_ofnode(offset), NULL); - if (ret) - return ret; - } - - return 0; -} - -int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) -{ - int periph; - - if (args->args_count) { - debug("Invalid args_count: %d\n", args->args_count); - return -EINVAL; - } - - periph = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(clk->dev), "reg", - -1); - if (periph < 0) - return -EINVAL; - - clk->id = periph; - - return 0; -} - -int at91_clk_probe(struct udevice *dev) -{ - struct udevice *dev_periph_container, *dev_pmc; - struct pmc_platdata *plat = dev_get_platdata(dev); - - dev_periph_container = dev_get_parent(dev); - dev_pmc = dev_get_parent(dev_periph_container); - - plat->reg_base = dev_read_addr_ptr(dev_pmc); - - return 0; -} /** * pmc_read() - read content at address base + off into val diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index b1ab0a95c8..33ded02156 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -7,7 +7,6 @@ #ifndef __AT91_PMC_H__ #define __AT91_PMC_H__ -#include #include #include @@ -15,17 +14,6 @@ #define AT91_TO_CLK_ID(_t, _i) (((_t) << 8) | ((_i) & 0xff)) #define AT91_CLK_ID_TO_DID(_i) ((_i) & 0xff) -struct pmc_platdata { - struct at91_pmc *reg_base; - struct regmap *regmap_sfr; -}; - -int at91_pmc_core_probe(struct udevice *dev); -int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name); - -int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args); -int at91_clk_probe(struct udevice *dev); - int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val); int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index); @@ -33,4 +21,5 @@ void pmc_read(void __iomem *base, unsigned int off, unsigned int *val); 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); + #endif diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c deleted file mode 100644 index a879b008ff..0000000000 --- a/drivers/clk/at91/sckc.c +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2016 Atmel Corporation - * Wenyou.Yang - */ - -#include -#include - -static const struct udevice_id at91_sckc_match[] = { - { .compatible = "atmel,at91sam9x5-sckc" }, - {} -}; - -U_BOOT_DRIVER(at91_sckc) = { - .name = "at91-sckc", - .id = UCLASS_SIMPLE_BUS, - .of_match = at91_sckc_match, -}; From e9885aa7cc23c21f1fa254c7c8cc459eca67db84 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:40 +0300 Subject: [PATCH 09/32] clk: at91: sckc: add driver compatible with ccf Add sckc driver compatible with common clock framework. Driver implements slow clock support for SAM9X60 compatible IPs (in this list it is also present SAMA7G5's slow clock IP). Signed-off-by: Claudiu Beznea --- drivers/clk/at91/Makefile | 2 +- drivers/clk/at91/sckc.c | 172 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/at91/sckc.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index e2413af403..7083ce2890 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -3,7 +3,7 @@ # ifdef CONFIG_CLK_CCF -obj-y += pmc.o +obj-y += pmc.o sckc.o else obj-y += compat.o endif diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c new file mode 100644 index 0000000000..dd62dc5510 --- /dev/null +++ b/drivers/clk/at91/sckc.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Slow clock support for AT91 architectures. + * + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + */ + +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK "at91-sam9x60-td-slck" +#define UBOOT_DM_CLK_AT91_SCKC "at91-sckc" + +#define AT91_OSC_SEL BIT(24) +#define AT91_OSC_SEL_SHIFT (24) + +struct sam9x60_sckc { + void __iomem *reg; + const char **parent_names; + unsigned int num_parents; + struct clk clk; +}; + +#define to_sam9x60_sckc(c) container_of(c, struct sam9x60_sckc, clk) + +static int sam9x60_sckc_of_xlate(struct clk *clk, + struct ofnode_phandle_args *args) +{ + if (args->args_count != 1) { + debug("AT91: SCKC: Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + clk->id = AT91_TO_CLK_ID(PMC_TYPE_SLOW, args->args[0]); + + return 0; +} + +static const struct clk_ops sam9x60_sckc_ops = { + .of_xlate = sam9x60_sckc_of_xlate, + .get_rate = clk_generic_get_rate, +}; + +static int sam9x60_td_slck_set_parent(struct clk *clk, struct clk *parent) +{ + struct sam9x60_sckc *sckc = to_sam9x60_sckc(clk); + u32 i; + + for (i = 0; i < sckc->num_parents; i++) { + if (!strcmp(parent->dev->name, sckc->parent_names[i])) + break; + } + if (i == sckc->num_parents) + return -EINVAL; + + pmc_update_bits(sckc->reg, 0, AT91_OSC_SEL, (i << AT91_OSC_SEL_SHIFT)); + + return 0; +} + +static const struct clk_ops sam9x60_td_slck_ops = { + .get_rate = clk_generic_get_rate, + .set_parent = sam9x60_td_slck_set_parent, +}; + +static struct clk *at91_sam9x60_clk_register_td_slck(struct sam9x60_sckc *sckc, + const char *name, const char * const *parent_names, + int num_parents) +{ + struct clk *clk; + int ret = -ENOMEM; + u32 val, i; + + if (!sckc || !name || !parent_names || num_parents != 2) + return ERR_PTR(-EINVAL); + + sckc->parent_names = kzalloc(sizeof(*sckc->parent_names) * num_parents, + GFP_KERNEL); + if (!sckc->parent_names) + return ERR_PTR(ret); + + for (i = 0; i < num_parents; i++) { + sckc->parent_names[i] = kmemdup(parent_names[i], + strlen(parent_names[i]) + 1, GFP_KERNEL); + if (!sckc->parent_names[i]) + goto free; + } + sckc->num_parents = num_parents; + + pmc_read(sckc->reg, 0, &val); + val = (val & AT91_OSC_SEL) >> AT91_OSC_SEL_SHIFT; + + clk = &sckc->clk; + ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK, name, + parent_names[val]); + if (ret) + goto free; + + return clk; + +free: + for (; i >= 0; i--) + kfree(sckc->parent_names[i]); + kfree(sckc->parent_names); + + return ERR_PTR(ret); +} + +U_BOOT_DRIVER(at91_sam9x60_td_slck) = { + .name = UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK, + .id = UCLASS_CLK, + .ops = &sam9x60_td_slck_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +static int at91_sam9x60_sckc_probe(struct udevice *dev) +{ + struct sam9x60_sckc *sckc = dev_get_priv(dev); + void __iomem *base = (void *)devfdt_get_addr(dev); + const char *slow_rc_osc, *slow_osc; + const char *parents[2]; + struct clk *clk, c; + int ret; + + ret = clk_get_by_index(dev, 0, &c); + if (ret) + return ret; + slow_rc_osc = clk_hw_get_name(&c); + + ret = clk_get_by_index(dev, 1, &c); + if (ret) + return ret; + slow_osc = clk_hw_get_name(&c); + + clk = clk_register_fixed_factor(NULL, "md_slck", slow_rc_osc, 0, 1, 1); + if (IS_ERR(clk)) + return PTR_ERR(clk); + clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 0), clk); + + parents[0] = slow_rc_osc; + parents[1] = slow_osc; + sckc[1].reg = base; + clk = at91_sam9x60_clk_register_td_slck(&sckc[1], "td_slck", + parents, 2); + if (IS_ERR(clk)) + return PTR_ERR(clk); + clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 1), clk); + + return 0; +} + +static const struct udevice_id sam9x60_sckc_ids[] = { + { .compatible = "microchip,sam9x60-sckc" }, + { /* Sentinel. */ }, +}; + +U_BOOT_DRIVER(at91_sckc) = { + .name = UBOOT_DM_CLK_AT91_SCKC, + .id = UCLASS_CLK, + .of_match = sam9x60_sckc_ids, + .priv_auto_alloc_size = sizeof(struct sam9x60_sckc) * 2, + .ops = &sam9x60_sckc_ops, + .probe = at91_sam9x60_sckc_probe, + .flags = DM_FLAG_PRE_RELOC, +}; From f1218f0b4fe95379d54312348c97865cab5ba1cd Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:41 +0300 Subject: [PATCH 10/32] clk: at91: clk-main: add driver compatible with ccf Add clk-main driver compatible with common clock framework. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/Makefile | 2 +- drivers/clk/at91/clk-main.c | 387 ++++++++++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 10 + 3 files changed, 398 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/at91/clk-main.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 7083ce2890..805f67677a 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -3,7 +3,7 @@ # ifdef CONFIG_CLK_CCF -obj-y += pmc.o sckc.o +obj-y += pmc.o sckc.o clk-main.o else obj-y += compat.o endif diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c new file mode 100644 index 0000000000..b52d926f33 --- /dev/null +++ b/drivers/clk/at91/clk-main.c @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Main clock support for AT91 architectures. + * + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + * + * Based on drivers/clk/at91/clk-main.c from Linux. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pmc.h" + +#define UBOOT_DM_CLK_AT91_MAIN_RC "at91-main-rc-clk" +#define UBOOT_DM_CLK_AT91_MAIN_OSC "at91-main-osc-clk" +#define UBOOT_DM_CLK_AT91_RM9200_MAIN "at91-rm9200-main-clk" +#define UBOOT_DM_CLK_AT91_SAM9X5_MAIN "at91-sam9x5-main-clk" + +#define MOR_KEY_MASK GENMASK(23, 16) +#define USEC_PER_SEC 1000000UL +#define SLOW_CLOCK_FREQ 32768 + +#define clk_main_parent_select(s) (((s) & \ + (AT91_PMC_MOSCEN | \ + AT91_PMC_OSCBYPASS)) ? 1 : 0) + +struct clk_main_rc { + void __iomem *reg; + struct clk clk; +}; + +#define to_clk_main_rc(_clk) container_of(_clk, struct clk_main_rc, clk) + +struct clk_main_osc { + void __iomem *reg; + struct clk clk; +}; + +#define to_clk_main_osc(_clk) container_of(_clk, struct clk_main_osc, clk) + +struct clk_main { + void __iomem *reg; + const unsigned int *clk_mux_table; + const char * const *parent_names; + unsigned int num_parents; + int type; + struct clk clk; +}; + +#define to_clk_main(_clk) container_of(_clk, struct clk_main, clk) + +static int main_rc_enable(struct clk *clk) +{ + struct clk_main_rc *main_rc = to_clk_main_rc(clk); + void __iomem *reg = main_rc->reg; + unsigned int val; + + pmc_read(reg, AT91_CKGR_MOR, &val); + + if (!(val & AT91_PMC_MOSCRCEN)) { + pmc_update_bits(reg, AT91_CKGR_MOR, + MOR_KEY_MASK | AT91_PMC_MOSCRCEN, + AT91_PMC_KEY | AT91_PMC_MOSCRCEN); + } + + pmc_read(reg, AT91_PMC_SR, &val); + while (!(val & AT91_PMC_MOSCRCS)) { + pmc_read(reg, AT91_PMC_SR, &val); + debug("waiting for main rc...\n"); + cpu_relax(); + } + + return 0; +} + +static int main_rc_disable(struct clk *clk) +{ + struct clk_main_rc *main_rc = to_clk_main_rc(clk); + struct reg *reg = main_rc->reg; + unsigned int val; + + pmc_read(reg, AT91_CKGR_MOR, &val); + + if (!(val & AT91_PMC_MOSCRCEN)) + return 0; + + pmc_update_bits(reg, AT91_CKGR_MOR, MOR_KEY_MASK | AT91_PMC_MOSCRCEN, + AT91_PMC_KEY); + + return 0; +} + +static const struct clk_ops main_rc_clk_ops = { + .enable = main_rc_enable, + .disable = main_rc_disable, + .get_rate = clk_generic_get_rate, +}; + +struct clk *at91_clk_main_rc(void __iomem *reg, const char *name, + const char *parent_name) +{ + struct clk_main_rc *main_rc; + struct clk *clk; + int ret; + + if (!reg || !name || !parent_name) + return ERR_PTR(-EINVAL); + + main_rc = kzalloc(sizeof(*main_rc), GFP_KERNEL); + if (!main_rc) + return ERR_PTR(-ENOMEM); + + main_rc->reg = reg; + clk = &main_rc->clk; + + ret = clk_register(clk, UBOOT_DM_CLK_AT91_MAIN_RC, name, + parent_name); + if (ret) { + kfree(main_rc); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_main_rc_clk) = { + .name = UBOOT_DM_CLK_AT91_MAIN_RC, + .id = UCLASS_CLK, + .ops = &main_rc_clk_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +static int clk_main_osc_enable(struct clk *clk) +{ + struct clk_main_osc *main = to_clk_main_osc(clk); + void __iomem *reg = main->reg; + unsigned int val; + + pmc_read(reg, AT91_CKGR_MOR, &val); + val &= ~MOR_KEY_MASK; + + if (val & AT91_PMC_OSCBYPASS) + return 0; + + if (!(val & AT91_PMC_MOSCEN)) { + val |= AT91_PMC_MOSCEN | AT91_PMC_KEY; + pmc_write(reg, AT91_CKGR_MOR, val); + } + + pmc_read(reg, AT91_PMC_SR, &val); + while (!(val & AT91_PMC_MOSCS)) { + pmc_read(reg, AT91_PMC_SR, &val); + debug("waiting for main osc..\n"); + cpu_relax(); + } + + return 0; +} + +static int clk_main_osc_disable(struct clk *clk) +{ + struct clk_main_osc *main = to_clk_main_osc(clk); + void __iomem *reg = main->reg; + unsigned int val; + + pmc_read(reg, AT91_CKGR_MOR, &val); + if (val & AT91_PMC_OSCBYPASS) + return 0; + + if (!(val & AT91_PMC_MOSCEN)) + return 0; + + val &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN); + pmc_write(reg, AT91_CKGR_MOR, val | AT91_PMC_KEY); + + return 0; +} + +static const struct clk_ops main_osc_clk_ops = { + .enable = clk_main_osc_enable, + .disable = clk_main_osc_disable, + .get_rate = clk_generic_get_rate, +}; + +struct clk *at91_clk_main_osc(void __iomem *reg, const char *name, + const char *parent_name, bool bypass) +{ + struct clk_main_osc *main; + struct clk *clk; + int ret; + + if (!reg || !name || !parent_name) + return ERR_PTR(-EINVAL); + + main = kzalloc(sizeof(*main), GFP_KERNEL); + if (!main) + return ERR_PTR(-ENOMEM); + + main->reg = reg; + clk = &main->clk; + + if (bypass) { + pmc_update_bits(reg, AT91_CKGR_MOR, + MOR_KEY_MASK | AT91_PMC_OSCBYPASS, + AT91_PMC_KEY | AT91_PMC_OSCBYPASS); + } + + ret = clk_register(clk, UBOOT_DM_CLK_AT91_MAIN_OSC, name, parent_name); + if (ret) { + kfree(main); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_main_osc_clk) = { + .name = UBOOT_DM_CLK_AT91_MAIN_OSC, + .id = UCLASS_CLK, + .ops = &main_osc_clk_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +static int clk_main_probe_frequency(void __iomem *reg) +{ + unsigned int cycles = 16; + unsigned int cycle = DIV_ROUND_UP(USEC_PER_SEC, SLOW_CLOCK_FREQ); + unsigned int mcfr; + + while (cycles--) { + pmc_read(reg, AT91_CKGR_MCFR, &mcfr); + if (mcfr & AT91_PMC_MAINRDY) + return 0; + udelay(cycle); + } + + return -ETIMEDOUT; +} + +static int clk_rm9200_main_enable(struct clk *clk) +{ + struct clk_main *main = to_clk_main(clk); + + return clk_main_probe_frequency(main->reg); +} + +static const struct clk_ops rm9200_main_clk_ops = { + .enable = clk_rm9200_main_enable, +}; + +struct clk *at91_clk_rm9200_main(void __iomem *reg, const char *name, + const char *parent_name) +{ + struct clk_main *main; + struct clk *clk; + int ret; + + if (!reg || !name || !parent_name) + return ERR_PTR(-EINVAL); + + main = kzalloc(sizeof(*main), GFP_KERNEL); + if (!main) + return ERR_PTR(-ENOMEM); + + main->reg = reg; + clk = &main->clk; + + ret = clk_register(clk, UBOOT_DM_CLK_AT91_RM9200_MAIN, name, + parent_name); + if (ret) { + kfree(main); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_rm9200_main_clk) = { + .name = UBOOT_DM_CLK_AT91_RM9200_MAIN, + .id = UCLASS_CLK, + .ops = &rm9200_main_clk_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +static inline bool clk_sam9x5_main_ready(void __iomem *reg) +{ + unsigned int val; + + pmc_read(reg, AT91_PMC_SR, &val); + + return !!(val & AT91_PMC_MOSCSELS); +} + +static int clk_sam9x5_main_enable(struct clk *clk) +{ + struct clk_main *main = to_clk_main(clk); + void __iomem *reg = main->reg; + + while (!clk_sam9x5_main_ready(reg)) { + debug("waiting for main..."); + cpu_relax(); + } + + return clk_main_probe_frequency(reg); +} + +static int clk_sam9x5_main_set_parent(struct clk *clk, struct clk *parent) +{ + struct clk_main *main = to_clk_main(clk); + void __iomem *reg = main->reg; + unsigned int tmp, index; + + index = at91_clk_mux_val_to_index(main->clk_mux_table, + main->num_parents, AT91_CLK_ID_TO_DID(parent->id)); + if (index < 0) + return index; + + pmc_read(reg, AT91_CKGR_MOR, &tmp); + tmp &= ~MOR_KEY_MASK; + tmp |= AT91_PMC_KEY; + + if (index && !(tmp & AT91_PMC_MOSCSEL)) + pmc_write(reg, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL); + else if (!index && (tmp & AT91_PMC_MOSCSEL)) + pmc_write(reg, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL); + + while (!clk_sam9x5_main_ready(reg)) + cpu_relax(); + + return 0; +} + +static const struct clk_ops sam9x5_main_clk_ops = { + .enable = clk_sam9x5_main_enable, + .set_parent = clk_sam9x5_main_set_parent, + .get_rate = clk_generic_get_rate, +}; + +struct clk *at91_clk_sam9x5_main(void __iomem *reg, const char *name, + const char * const *parent_names, + int num_parents, const u32 *clk_mux_table, + int type) +{ + struct clk *clk = ERR_PTR(-ENOMEM); + struct clk_main *main = NULL; + unsigned int val; + int ret; + + if (!reg || !name || !parent_names || !num_parents || !clk_mux_table) + return ERR_PTR(-EINVAL); + + main = kzalloc(sizeof(*main), GFP_KERNEL); + if (!main) + return ERR_PTR(-ENOMEM); + + main->reg = reg; + main->parent_names = parent_names; + main->num_parents = num_parents; + main->clk_mux_table = clk_mux_table; + main->type = type; + clk = &main->clk; + clk->flags = CLK_GET_RATE_NOCACHE; + pmc_read(reg, AT91_CKGR_MOR, &val); + ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X5_MAIN, name, + main->parent_names[clk_main_parent_select(val)]); + if (ret) { + kfree(main); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_sam9x5_main_clk) = { + .name = UBOOT_DM_CLK_AT91_SAM9X5_MAIN, + .id = UCLASS_CLK, + .ops = &sam9x5_main_clk_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 33ded02156..62bfc4b305 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -14,6 +14,16 @@ #define AT91_TO_CLK_ID(_t, _i) (((_t) << 8) | ((_i) & 0xff)) #define AT91_CLK_ID_TO_DID(_i) ((_i) & 0xff) +struct clk *at91_clk_main_rc(void __iomem *reg, const char *name, + const char *parent_name); +struct clk *at91_clk_main_osc(void __iomem *reg, const char *name, + const char *parent_name, bool bypass); +struct clk *at91_clk_rm9200_main(void __iomem *reg, const char *name, + const char *parent_name); +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); + int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val); int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index); From e6547a6d0c24129543ec58ed9cc5fcd6ebffc7ad Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:42 +0300 Subject: [PATCH 11/32] clk: at91: sam9x60-pll: add driver compatible with ccf Add sam9x60-pll driver compatible with common clock framework. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/Kconfig | 7 + drivers/clk/at91/Makefile | 1 + drivers/clk/at91/clk-sam9x60-pll.c | 442 +++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 36 +++ 4 files changed, 486 insertions(+) create mode 100644 drivers/clk/at91/clk-sam9x60-pll.c diff --git a/drivers/clk/at91/Kconfig b/drivers/clk/at91/Kconfig index 8d482a2752..4abc8026b4 100644 --- a/drivers/clk/at91/Kconfig +++ b/drivers/clk/at91/Kconfig @@ -54,3 +54,10 @@ config AT91_GENERIC_CLK that may be different from the system clock. This second clock is the generic clock (GCLK) and is managed by the PMC via PMC_PCR register. + +config AT91_SAM9X60_PLL + bool "PLL support for SAM9X60 SoCs" + depends on CLK_AT91 + help + This option is used to enable the AT91 SAM9X60's PLL clock + driver. diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 805f67677a..338582b88a 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -4,6 +4,7 @@ ifdef CONFIG_CLK_CCF obj-y += pmc.o sckc.o clk-main.o +obj-$(CONFIG_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o else obj-y += compat.o endif diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c new file mode 100644 index 0000000000..1bfae5fd01 --- /dev/null +++ b/drivers/clk/at91/clk-sam9x60-pll.c @@ -0,0 +1,442 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SAM9X60's PLL clock support. + * + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + * + * Based on drivers/clk/at91/clk-sam9x60-pll.c from Linux. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL "at91-sam9x60-div-pll-clk" +#define UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL "at91-sam9x60-frac-pll-clk" + +#define PMC_PLL_CTRL0_DIV_MSK GENMASK(7, 0) +#define PMC_PLL_CTRL1_MUL_MSK GENMASK(31, 24) +#define PMC_PLL_CTRL1_FRACR_MSK GENMASK(21, 0) + +#define PLL_DIV_MAX (FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1) +#define UPLL_DIV 2 +#define PLL_MUL_MAX (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1) + +#define FCORE_MIN (600000000) +#define FCORE_MAX (1200000000) + +#define PLL_MAX_ID 7 + +struct sam9x60_pll { + void __iomem *base; + const struct clk_pll_characteristics *characteristics; + const struct clk_pll_layout *layout; + struct clk clk; + u8 id; +}; + +#define to_sam9x60_pll(_clk) container_of(_clk, struct sam9x60_pll, clk) + +static inline bool sam9x60_pll_ready(void __iomem *base, int id) +{ + unsigned int status; + + pmc_read(base, AT91_PMC_PLL_ISR0, &status); + + return !!(status & BIT(id)); +} + +static long sam9x60_frac_pll_compute_mul_frac(u32 *mul, u32 *frac, ulong rate, + ulong parent_rate) +{ + unsigned long tmprate, remainder; + unsigned long nmul = 0; + unsigned long nfrac = 0; + + if (rate < FCORE_MIN || rate > FCORE_MAX) + return -ERANGE; + + /* + * Calculate the multiplier associated with the current + * divider that provide the closest rate to the requested one. + */ + nmul = mult_frac(rate, 1, parent_rate); + tmprate = mult_frac(parent_rate, nmul, 1); + remainder = rate - tmprate; + + if (remainder) { + nfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * (1 << 22), + parent_rate); + + tmprate += DIV_ROUND_CLOSEST_ULL((u64)nfrac * parent_rate, + (1 << 22)); + } + + /* Check if resulted rate is valid. */ + if (tmprate < FCORE_MIN || tmprate > FCORE_MAX) + return -ERANGE; + + *mul = nmul - 1; + *frac = nfrac; + + return tmprate; +} + +static ulong sam9x60_frac_pll_set_rate(struct clk *clk, ulong rate) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(clk); + void __iomem *base = pll->base; + ulong parent_rate = clk_get_parent_rate(clk); + u32 nmul, cmul, nfrac, cfrac, val; + bool ready = sam9x60_pll_ready(base, pll->id); + long ret; + + if (!parent_rate) + return 0; + + ret = sam9x60_frac_pll_compute_mul_frac(&nmul, &nfrac, rate, + parent_rate); + if (ret < 0) + return 0; + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, + pll->id); + pmc_read(base, AT91_PMC_PLL_CTRL1, &val); + cmul = (val & pll->layout->mul_mask) >> pll->layout->mul_shift; + cfrac = (val & pll->layout->frac_mask) >> pll->layout->frac_shift; + + /* Check against current values. */ + if (sam9x60_pll_ready(base, pll->id) && + nmul == cmul && nfrac == cfrac) + return 0; + + /* Update it to hardware. */ + pmc_write(base, AT91_PMC_PLL_CTRL1, + (nmul << pll->layout->mul_shift) | + (nfrac << pll->layout->frac_shift)); + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | pll->id); + + while (ready && !sam9x60_pll_ready(base, pll->id)) { + debug("waiting for pll %u...\n", pll->id); + cpu_relax(); + } + + return parent_rate * (nmul + 1) + ((u64)parent_rate * nfrac >> 22); +} + +static ulong sam9x60_frac_pll_get_rate(struct clk *clk) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(clk); + void __iomem *base = pll->base; + ulong parent_rate = clk_get_parent_rate(clk); + u32 mul, frac, val; + + if (!parent_rate) + return 0; + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, + pll->id); + pmc_read(base, AT91_PMC_PLL_CTRL1, &val); + mul = (val & pll->layout->mul_mask) >> pll->layout->mul_shift; + frac = (val & pll->layout->frac_mask) >> pll->layout->frac_shift; + + return (parent_rate * (mul + 1) + ((u64)parent_rate * frac >> 22)); +} + +static int sam9x60_frac_pll_enable(struct clk *clk) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(clk); + void __iomem *base = pll->base; + unsigned int val; + ulong crate; + + crate = sam9x60_frac_pll_get_rate(clk); + if (crate < FCORE_MIN || crate > FCORE_MAX) + return -ERANGE; + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, + pll->id); + pmc_read(base, AT91_PMC_PLL_CTRL1, &val); + + if (sam9x60_pll_ready(base, pll->id)) + return 0; + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, + AT91_PMC_PMM_UPDT_STUPTIM_MSK | + AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_STUPTIM(0x3f) | pll->id); + + /* Recommended value for AT91_PMC_PLL_ACR */ + if (pll->characteristics->upll) + val = AT91_PMC_PLL_ACR_DEFAULT_UPLL; + else + val = AT91_PMC_PLL_ACR_DEFAULT_PLLA; + pmc_write(base, AT91_PMC_PLL_ACR, val); + + if (pll->characteristics->upll) { + /* Enable the UTMI internal bandgap */ + val |= AT91_PMC_PLL_ACR_UTMIBG; + pmc_write(base, AT91_PMC_PLL_ACR, val); + + udelay(10); + + /* Enable the UTMI internal regulator */ + val |= AT91_PMC_PLL_ACR_UTMIVR; + pmc_write(base, AT91_PMC_PLL_ACR, val); + + udelay(10); + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | + AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | pll->id); + } + + pmc_update_bits(base, AT91_PMC_PLL_CTRL0, + AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL, + AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL); + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | pll->id); + + while (!sam9x60_pll_ready(base, pll->id)) { + debug("waiting for pll %u...\n", pll->id); + cpu_relax(); + } + + return 0; +} + +static int sam9x60_frac_pll_disable(struct clk *clk) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(clk); + void __iomem *base = pll->base; + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, + pll->id); + + pmc_update_bits(base, AT91_PMC_PLL_CTRL0, + AT91_PMC_PLL_CTRL0_ENPLL, 0); + + if (pll->characteristics->upll) + pmc_update_bits(base, AT91_PMC_PLL_ACR, + AT91_PMC_PLL_ACR_UTMIBG | + AT91_PMC_PLL_ACR_UTMIVR, 0); + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | pll->id); + + return 0; +} + +static const struct clk_ops sam9x60_frac_pll_ops = { + .enable = sam9x60_frac_pll_enable, + .disable = sam9x60_frac_pll_disable, + .set_rate = sam9x60_frac_pll_set_rate, + .get_rate = sam9x60_frac_pll_get_rate, +}; + +static int sam9x60_div_pll_enable(struct clk *clk) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(clk); + void __iomem *base = pll->base; + unsigned int val; + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, + pll->id); + pmc_read(base, AT91_PMC_PLL_CTRL0, &val); + + /* Stop if enabled. */ + if (val & pll->layout->endiv_mask) + return 0; + + pmc_update_bits(base, AT91_PMC_PLL_CTRL0, + pll->layout->endiv_mask, + (1 << pll->layout->endiv_shift)); + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | pll->id); + + while (!sam9x60_pll_ready(base, pll->id)) { + debug("waiting for pll %u...\n", pll->id); + cpu_relax(); + } + + return 0; +} + +static int sam9x60_div_pll_disable(struct clk *clk) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(clk); + void __iomem *base = pll->base; + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, + pll->id); + + pmc_update_bits(base, AT91_PMC_PLL_CTRL0, + pll->layout->endiv_mask, 0); + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | pll->id); + + return 0; +} + +static ulong sam9x60_div_pll_set_rate(struct clk *clk, ulong rate) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(clk); + void __iomem *base = pll->base; + const struct clk_pll_characteristics *characteristics = + pll->characteristics; + ulong parent_rate = clk_get_parent_rate(clk); + u8 div = DIV_ROUND_CLOSEST_ULL(parent_rate, rate) - 1; + ulong req_rate = parent_rate / (div + 1); + bool ready = sam9x60_pll_ready(base, pll->id); + u32 val; + + if (!parent_rate || div > pll->layout->div_mask || + req_rate < characteristics->output[0].min || + req_rate > characteristics->output[0].max) + return 0; + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, + pll->id); + pmc_read(base, AT91_PMC_PLL_CTRL0, &val); + /* Compare against current value. */ + if (div == ((val & pll->layout->div_mask) >> pll->layout->div_shift)) + return 0; + + /* Update it to hardware. */ + pmc_update_bits(base, AT91_PMC_PLL_CTRL0, + pll->layout->div_mask, + div << pll->layout->div_shift); + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | pll->id); + + while (ready && !sam9x60_pll_ready(base, pll->id)) { + debug("waiting for pll %u...\n", pll->id); + cpu_relax(); + } + + return req_rate; +} + +static ulong sam9x60_div_pll_get_rate(struct clk *clk) +{ + struct sam9x60_pll *pll = to_sam9x60_pll(clk); + void __iomem *base = pll->base; + ulong parent_rate = clk_get_parent_rate(clk); + u32 val; + u8 div; + + if (!parent_rate) + return 0; + + pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, + pll->id); + + pmc_read(base, AT91_PMC_PLL_CTRL0, &val); + + div = (val & pll->layout->div_mask) >> pll->layout->div_shift; + + return parent_rate / (div + 1); +} + +static const struct clk_ops sam9x60_div_pll_ops = { + .enable = sam9x60_div_pll_enable, + .disable = sam9x60_div_pll_disable, + .set_rate = sam9x60_div_pll_set_rate, + .get_rate = sam9x60_div_pll_get_rate, +}; + +static struct clk * +sam9x60_clk_register_pll(void __iomem *base, const char *type, + const char *name, const char *parent_name, u8 id, + const struct clk_pll_characteristics *characteristics, + const struct clk_pll_layout *layout, u32 flags) +{ + struct sam9x60_pll *pll; + struct clk *clk; + int ret; + + if (!base || !type || !name || !parent_name || !characteristics || + !layout || id > PLL_MAX_ID) + return ERR_PTR(-EINVAL); + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + pll->id = id; + pll->characteristics = characteristics; + pll->layout = layout; + pll->base = base; + clk = &pll->clk; + clk->flags = flags; + + ret = clk_register(clk, type, name, parent_name); + if (ret) { + kfree(pll); + clk = ERR_PTR(ret); + } + + return clk; +} + +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, + const struct clk_pll_layout *layout, bool critical) +{ + return sam9x60_clk_register_pll(base, + UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL, name, parent_name, id, + characteristics, layout, + CLK_GET_RATE_NOCACHE | (critical ? CLK_IS_CRITICAL : 0)); +} + +struct clk * +sam9x60_clk_register_frac_pll(void __iomem *base, const char *name, + const char *parent_name, u8 id, + const struct clk_pll_characteristics *characteristics, + const struct clk_pll_layout *layout, bool critical) +{ + return sam9x60_clk_register_pll(base, + UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL, name, parent_name, id, + characteristics, layout, + CLK_GET_RATE_NOCACHE | (critical ? CLK_IS_CRITICAL : 0)); +} + +U_BOOT_DRIVER(at91_sam9x60_div_pll_clk) = { + .name = UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL, + .id = UCLASS_CLK, + .ops = &sam9x60_div_pll_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRIVER(at91_sam9x60_frac_pll_clk) = { + .name = UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL, + .id = UCLASS_CLK, + .ops = &sam9x60_frac_pll_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 62bfc4b305..b24d2d8990 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -14,6 +14,32 @@ #define AT91_TO_CLK_ID(_t, _i) (((_t) << 8) | ((_i) & 0xff)) #define AT91_CLK_ID_TO_DID(_i) ((_i) & 0xff) +struct clk_range { + unsigned long min; + unsigned long max; +}; + +struct clk_pll_characteristics { + struct clk_range input; + int num_output; + const struct clk_range *output; + u16 *icpll; + u8 *out; + u8 upll : 1; +}; + +struct clk_pll_layout { + u32 pllr_mask; + u32 mul_mask; + u32 frac_mask; + u32 div_mask; + u32 endiv_mask; + u8 mul_shift; + u8 frac_shift; + u8 div_shift; + u8 endiv_shift; +}; + struct clk *at91_clk_main_rc(void __iomem *reg, const char *name, const char *parent_name); struct clk *at91_clk_main_osc(void __iomem *reg, const char *name, @@ -23,6 +49,16 @@ struct clk *at91_clk_rm9200_main(void __iomem *reg, const char *name, 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_div_pll(void __iomem *base, const char *name, + const char *parent_name, u8 id, + const struct clk_pll_characteristics *characteristics, + const struct clk_pll_layout *layout, bool critical); +struct clk * +sam9x60_clk_register_frac_pll(void __iomem *base, const char *name, + const char *parent_name, u8 id, + const struct clk_pll_characteristics *characteristics, + const struct clk_pll_layout *layout, bool critical); int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val); int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index); From b4c4e18dbda178a86bd88e96f20874c6fd51ca56 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:43 +0300 Subject: [PATCH 12/32] clk: at91: clk-master: add driver compatible with ccf Add clk-master driver compatible with common clock framework. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/Makefile | 2 +- drivers/clk/at91/clk-master.c | 156 ++++++++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 21 +++++ 3 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/at91/clk-master.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 338582b88a..a4e397066e 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -3,7 +3,7 @@ # ifdef CONFIG_CLK_CCF -obj-y += pmc.o sckc.o clk-main.o +obj-y += pmc.o sckc.o clk-main.o clk-master.o obj-$(CONFIG_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o else obj-y += compat.o diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c new file mode 100644 index 0000000000..1d388b6b25 --- /dev/null +++ b/drivers/clk/at91/clk-master.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Master clock support for AT91 architectures. + * + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + * + * Based on drivers/clk/at91/clk-master.c from Linux. + */ + +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define UBOOT_DM_CLK_AT91_MASTER "at91-master-clk" + +#define MASTER_PRES_MASK 0x7 +#define MASTER_PRES_MAX MASTER_PRES_MASK +#define MASTER_DIV_SHIFT 8 +#define MASTER_DIV_MASK 0x3 + +struct clk_master { + void __iomem *base; + const struct clk_master_layout *layout; + const struct clk_master_characteristics *characteristics; + const u32 *mux_table; + const u32 *clk_mux_table; + u32 num_parents; + struct clk clk; + u8 id; +}; + +#define to_clk_master(_clk) container_of(_clk, struct clk_master, clk) + +static inline bool clk_master_ready(struct clk_master *master) +{ + unsigned int status; + + pmc_read(master->base, AT91_PMC_SR, &status); + + return !!(status & AT91_PMC_MCKRDY); +} + +static int clk_master_enable(struct clk *clk) +{ + struct clk_master *master = to_clk_master(clk); + + while (!clk_master_ready(master)) { + debug("waiting for mck %d\n", master->id); + cpu_relax(); + } + + return 0; +} + +static ulong clk_master_get_rate(struct clk *clk) +{ + struct clk_master *master = to_clk_master(clk); + const struct clk_master_layout *layout = master->layout; + const struct clk_master_characteristics *characteristics = + master->characteristics; + ulong rate = clk_get_parent_rate(clk); + unsigned int mckr; + u8 pres, div; + + if (!rate) + return 0; + + pmc_read(master->base, master->layout->offset, &mckr); + mckr &= layout->mask; + + pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK; + div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK; + + if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX) + rate /= 3; + else + rate >>= pres; + + rate /= characteristics->divisors[div]; + + if (rate < characteristics->output.min) + pr_warn("master clk is underclocked"); + else if (rate > characteristics->output.max) + pr_warn("master clk is overclocked"); + + return rate; +} + +static const struct clk_ops master_ops = { + .enable = clk_master_enable, + .get_rate = clk_master_get_rate, +}; + +struct clk *at91_clk_register_master(void __iomem *base, + const char *name, const char * const *parent_names, + int num_parents, const struct clk_master_layout *layout, + const struct clk_master_characteristics *characteristics, + const u32 *mux_table) +{ + struct clk_master *master; + struct clk *clk; + unsigned int val; + int ret; + + if (!base || !name || !num_parents || !parent_names || + !layout || !characteristics || !mux_table) + return ERR_PTR(-EINVAL); + + master = kzalloc(sizeof(*master), GFP_KERNEL); + if (!master) + return ERR_PTR(-ENOMEM); + + master->layout = layout; + master->characteristics = characteristics; + master->base = base; + master->num_parents = num_parents; + master->mux_table = mux_table; + + pmc_read(master->base, master->layout->offset, &val); + clk = &master->clk; + clk->flags = CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL; + ret = clk_register(clk, UBOOT_DM_CLK_AT91_MASTER, name, + parent_names[val & AT91_PMC_CSS]); + if (ret) { + kfree(master); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_master_clk) = { + .name = UBOOT_DM_CLK_AT91_MASTER, + .id = UCLASS_CLK, + .ops = &master_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +const struct clk_master_layout at91rm9200_master_layout = { + .mask = 0x31F, + .pres_shift = 2, + .offset = AT91_PMC_MCKR, +}; + +const struct clk_master_layout at91sam9x5_master_layout = { + .mask = 0x373, + .pres_shift = 4, + .offset = AT91_PMC_MCKR, +}; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index b24d2d8990..33c7a66e84 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -19,6 +19,21 @@ struct clk_range { unsigned long max; }; +struct clk_master_layout { + u32 offset; + u32 mask; + u8 pres_shift; +}; + +extern const struct clk_master_layout at91rm9200_master_layout; +extern const struct clk_master_layout at91sam9x5_master_layout; + +struct clk_master_characteristics { + struct clk_range output; + u32 divisors[4]; + u8 have_div3_pres; +}; + struct clk_pll_characteristics { struct clk_range input; int num_output; @@ -59,6 +74,12 @@ sam9x60_clk_register_frac_pll(void __iomem *base, const char *name, const char *parent_name, u8 id, const struct clk_pll_characteristics *characteristics, const struct clk_pll_layout *layout, bool critical); +struct clk * +at91_clk_register_master(void __iomem *base, const char *name, + const char * const *parent_names, int num_parents, + const struct clk_master_layout *layout, + const struct clk_master_characteristics *characteristics, + const u32 *mux_table); int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val); int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index); From dd4d19ddfb6590c4504a7d80f2e4dffe56c28337 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:44 +0300 Subject: [PATCH 13/32] clk: at91: clk-master: add support for sama7g5 Add master clock (MCK1..MCK4) support for SAMA7G5. SAMA7G5's PMC has multiple master clocks feeding different subsystems. One of them feeds image subsystem and is changeable based on image subsystem needs. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/clk-master.c | 178 +++++++++++++++++++++++++++++++++- drivers/clk/at91/pmc.h | 5 + 2 files changed, 182 insertions(+), 1 deletion(-) diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index 1d388b6b25..759df93697 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -19,12 +19,25 @@ #include "pmc.h" #define UBOOT_DM_CLK_AT91_MASTER "at91-master-clk" +#define UBOOT_DM_CLK_AT91_SAMA7G5_MASTER "at91-sama7g5-master-clk" #define MASTER_PRES_MASK 0x7 #define MASTER_PRES_MAX MASTER_PRES_MASK #define MASTER_DIV_SHIFT 8 #define MASTER_DIV_MASK 0x3 +#define PMC_MCR 0x30 +#define PMC_MCR_ID_MSK GENMASK(3, 0) +#define PMC_MCR_CMD BIT(7) +#define PMC_MCR_DIV GENMASK(10, 8) +#define PMC_MCR_CSS GENMASK(20, 16) +#define PMC_MCR_CSS_SHIFT (16) +#define PMC_MCR_EN BIT(28) + +#define PMC_MCR_ID(x) ((x) & PMC_MCR_ID_MSK) + +#define MASTER_MAX_ID 4 + struct clk_master { void __iomem *base; const struct clk_master_layout *layout; @@ -40,11 +53,12 @@ struct clk_master { static inline bool clk_master_ready(struct clk_master *master) { + unsigned int bit = master->id ? AT91_PMC_MCKXRDY : AT91_PMC_MCKRDY; unsigned int status; pmc_read(master->base, AT91_PMC_SR, &status); - return !!(status & AT91_PMC_MCKRDY); + return !!(status & bit); } static int clk_master_enable(struct clk *clk) @@ -143,6 +157,168 @@ U_BOOT_DRIVER(at91_master_clk) = { .flags = DM_FLAG_PRE_RELOC, }; +static int clk_sama7g5_master_set_parent(struct clk *clk, struct clk *parent) +{ + struct clk_master *master = to_clk_master(clk); + int index; + + index = at91_clk_mux_val_to_index(master->clk_mux_table, + master->num_parents, parent->id); + if (index < 0) + return index; + + index = at91_clk_mux_index_to_val(master->mux_table, + master->num_parents, index); + if (index < 0) + return index; + + pmc_write(master->base, PMC_MCR, PMC_MCR_ID(master->id)); + pmc_update_bits(master->base, PMC_MCR, + PMC_MCR_CSS | PMC_MCR_CMD | PMC_MCR_ID_MSK, + (index << PMC_MCR_CSS_SHIFT) | PMC_MCR_CMD | + PMC_MCR_ID(master->id)); + return 0; +} + +static int clk_sama7g5_master_enable(struct clk *clk) +{ + struct clk_master *master = to_clk_master(clk); + + pmc_write(master->base, PMC_MCR, PMC_MCR_ID(master->id)); + pmc_update_bits(master->base, PMC_MCR, + PMC_MCR_EN | PMC_MCR_CMD | PMC_MCR_ID_MSK, + PMC_MCR_EN | PMC_MCR_CMD | PMC_MCR_ID(master->id)); + + return 0; +} + +static int clk_sama7g5_master_disable(struct clk *clk) +{ + struct clk_master *master = to_clk_master(clk); + + pmc_write(master->base, PMC_MCR, master->id); + pmc_update_bits(master->base, PMC_MCR, + PMC_MCR_EN | PMC_MCR_CMD | PMC_MCR_ID_MSK, + PMC_MCR_CMD | PMC_MCR_ID(master->id)); + + return 0; +} + +static ulong clk_sama7g5_master_set_rate(struct clk *clk, ulong rate) +{ + struct clk_master *master = to_clk_master(clk); + ulong parent_rate = clk_get_parent_rate(clk); + ulong div, rrate; + + if (!parent_rate) + return 0; + + div = DIV_ROUND_CLOSEST(parent_rate, rate); + if ((div > (1 << (MASTER_PRES_MAX - 1))) || (div & (div - 1))) { + return 0; + } else if (div == 3) { + rrate = DIV_ROUND_CLOSEST(parent_rate, MASTER_PRES_MAX); + div = MASTER_PRES_MAX; + } else { + rrate = DIV_ROUND_CLOSEST(parent_rate, div); + div = ffs(div) - 1; + } + + pmc_write(master->base, PMC_MCR, master->id); + pmc_update_bits(master->base, PMC_MCR, + PMC_MCR_DIV | PMC_MCR_CMD | PMC_MCR_ID_MSK, + (div << MASTER_DIV_SHIFT) | PMC_MCR_CMD | + PMC_MCR_ID(master->id)); + + return rrate; +} + +static ulong clk_sama7g5_master_get_rate(struct clk *clk) +{ + struct clk_master *master = to_clk_master(clk); + ulong parent_rate = clk_get_parent_rate(clk); + unsigned int val; + ulong div; + + if (!parent_rate) + return 0; + + pmc_write(master->base, PMC_MCR, master->id); + pmc_read(master->base, PMC_MCR, &val); + + div = (val >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK; + + if (div == MASTER_PRES_MAX) + div = 3; + else + div = 1 << div; + + return DIV_ROUND_CLOSEST(parent_rate, div); +} + +static const struct clk_ops sama7g5_master_ops = { + .enable = clk_sama7g5_master_enable, + .disable = clk_sama7g5_master_disable, + .set_rate = clk_sama7g5_master_set_rate, + .get_rate = clk_sama7g5_master_get_rate, + .set_parent = clk_sama7g5_master_set_parent, +}; + +struct clk *at91_clk_sama7g5_register_master(void __iomem *base, + const char *name, const char * const *parent_names, + int num_parents, const u32 *mux_table, const u32 *clk_mux_table, + bool critical, u8 id) +{ + struct clk_master *master; + struct clk *clk; + u32 val, index; + int ret; + + if (!base || !name || !num_parents || !parent_names || + !mux_table || !clk_mux_table || id > MASTER_MAX_ID) + return ERR_PTR(-EINVAL); + + master = kzalloc(sizeof(*master), GFP_KERNEL); + if (!master) + return ERR_PTR(-ENOMEM); + + master->base = base; + master->id = id; + master->mux_table = mux_table; + master->clk_mux_table = clk_mux_table; + master->num_parents = num_parents; + + pmc_write(master->base, PMC_MCR, master->id); + pmc_read(master->base, PMC_MCR, &val); + + index = at91_clk_mux_val_to_index(master->mux_table, + master->num_parents, + (val & PMC_MCR_CSS) >> PMC_MCR_CSS_SHIFT); + if (index < 0) { + kfree(master); + return ERR_PTR(index); + } + + clk = &master->clk; + clk->flags = CLK_GET_RATE_NOCACHE | (critical ? CLK_IS_CRITICAL : 0); + + ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAMA7G5_MASTER, name, + parent_names[index]); + if (ret) { + kfree(master); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_sama7g5_master_clk) = { + .name = UBOOT_DM_CLK_AT91_SAMA7G5_MASTER, + .id = UCLASS_CLK, + .ops = &sama7g5_master_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + const struct clk_master_layout at91rm9200_master_layout = { .mask = 0x31F, .pres_shift = 2, diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 33c7a66e84..49e1e372b8 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -80,6 +80,11 @@ at91_clk_register_master(void __iomem *base, const char *name, const struct clk_master_layout *layout, const struct clk_master_characteristics *characteristics, const u32 *mux_table); +struct clk * +at91_clk_sama7g5_register_master(void __iomem *base, const char *name, + const char * const *parent_names, int num_parents, + const u32 *mux_table, const u32 *clk_mux_table, + bool critical, u8 id); int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val); int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index); From ad4d39a964e1d3abb4f2c3d933234f86a7960d54 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:45 +0300 Subject: [PATCH 14/32] clk: at91: clk-utmi: add driver compatible with ccf Add clk-utmi driver compatible with common clock framework. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/Makefile | 1 + drivers/clk/at91/clk-utmi.c | 165 ++++++++++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 3 + 3 files changed, 169 insertions(+) create mode 100644 drivers/clk/at91/clk-utmi.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index a4e397066e..9c38bda5e6 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -4,6 +4,7 @@ ifdef CONFIG_CLK_CCF obj-y += pmc.o sckc.o clk-main.o clk-master.o +obj-$(CONFIG_AT91_UTMI) += clk-utmi.o obj-$(CONFIG_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o else obj-y += compat.o diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c new file mode 100644 index 0000000000..b60fd35b6b --- /dev/null +++ b/drivers/clk/at91/clk-utmi.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * UTMI clock support for AT91 architectures. + * + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + * + * Based on drivers/clk/at91/clk-utmi.c from Linux. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define UBOOT_DM_CLK_AT91_UTMI "at91-utmi-clk" + +/* + * The purpose of this clock is to generate a 480 MHz signal. A different + * rate can't be configured. + */ +#define UTMI_RATE 480000000 + +struct clk_utmi { + void __iomem *base; + struct regmap *regmap_sfr; + struct clk clk; +}; + +#define to_clk_utmi(_clk) container_of(_clk, struct clk_utmi, clk) + +static inline bool clk_utmi_ready(struct regmap *regmap) +{ + unsigned int status; + + pmc_read(regmap, AT91_PMC_SR, &status); + + return !!(status & AT91_PMC_LOCKU); +} + +static int clk_utmi_enable(struct clk *clk) +{ + struct clk_utmi *utmi = to_clk_utmi(clk); + unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT | + AT91_PMC_BIASEN; + unsigned int utmi_ref_clk_freq; + ulong parent_rate = clk_get_parent_rate(clk); + + /* + * If mainck rate is different from 12 MHz, we have to configure the + * FREQ field of the SFR_UTMICKTRIM register to generate properly + * the utmi clock. + */ + switch (parent_rate) { + case 12000000: + utmi_ref_clk_freq = 0; + break; + case 16000000: + utmi_ref_clk_freq = 1; + break; + case 24000000: + utmi_ref_clk_freq = 2; + break; + /* + * Not supported on SAMA5D2 but it's not an issue since MAINCK + * maximum value is 24 MHz. + */ + case 48000000: + utmi_ref_clk_freq = 3; + break; + default: + debug("UTMICK: unsupported mainck rate\n"); + return -EINVAL; + } + + if (utmi->regmap_sfr) { + regmap_update_bits(utmi->regmap_sfr, AT91_SFR_UTMICKTRIM, + AT91_UTMICKTRIM_FREQ, utmi_ref_clk_freq); + } else if (utmi_ref_clk_freq) { + debug("UTMICK: sfr node required\n"); + return -EINVAL; + } + + pmc_update_bits(utmi->base, AT91_CKGR_UCKR, uckr, uckr); + + while (!clk_utmi_ready(utmi->base)) { + debug("waiting for utmi...\n"); + cpu_relax(); + } + + return 0; +} + +static int clk_utmi_disable(struct clk *clk) +{ + struct clk_utmi *utmi = to_clk_utmi(clk); + + pmc_update_bits(utmi->base, AT91_CKGR_UCKR, AT91_PMC_UPLLEN, 0); + + return 0; +} + +static ulong clk_utmi_get_rate(struct clk *clk) +{ + /* UTMI clk rate is fixed. */ + return UTMI_RATE; +} + +static const struct clk_ops utmi_ops = { + .enable = clk_utmi_enable, + .disable = clk_utmi_disable, + .get_rate = clk_utmi_get_rate, +}; + +struct clk *at91_clk_register_utmi(void __iomem *base, struct udevice *dev, + const char *name, const char *parent_name) +{ + struct udevice *syscon; + struct clk_utmi *utmi; + struct clk *clk; + int ret; + + if (!base || !dev || !name || !parent_name) + return ERR_PTR(-EINVAL); + + ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, + "regmap-sfr", &syscon); + if (ret) + return ERR_PTR(ret); + + utmi = kzalloc(sizeof(*utmi), GFP_KERNEL); + if (!utmi) + return ERR_PTR(-ENOMEM); + + utmi->base = base; + utmi->regmap_sfr = syscon_get_regmap(syscon); + if (!utmi->regmap_sfr) { + kfree(utmi); + return ERR_PTR(-ENODEV); + } + + clk = &utmi->clk; + clk->flags = CLK_GET_RATE_NOCACHE; + ret = clk_register(clk, UBOOT_DM_CLK_AT91_UTMI, name, parent_name); + if (ret) { + kfree(utmi); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_utmi_clk) = { + .name = UBOOT_DM_CLK_AT91_UTMI, + .id = UCLASS_CLK, + .ops = &utmi_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 49e1e372b8..264b36c7b4 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -85,6 +85,9 @@ at91_clk_sama7g5_register_master(void __iomem *base, const char *name, const char * const *parent_names, int num_parents, const u32 *mux_table, const u32 *clk_mux_table, bool critical, u8 id); +struct clk * +at91_clk_register_utmi(void __iomem *base, struct udevice *dev, + const char *name, const char *parent_name); int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val); int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index); From 03417335702b50d70b57d8594efd61239e88c362 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:46 +0300 Subject: [PATCH 15/32] clk: at91: clk-utmi: add support for sama7g5 Add UTMI support for SAMA7G5. SAMA7G5's UTMI control is done via XTALF register. Values written at bits 2..0 in this register correspond to the on board crystal oscillator frequency. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/clk-utmi.c | 71 ++++++++++++++++++++++++++++++++++++- drivers/clk/at91/pmc.h | 3 ++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c index b60fd35b6b..7c8bcfb51d 100644 --- a/drivers/clk/at91/clk-utmi.c +++ b/drivers/clk/at91/clk-utmi.c @@ -20,7 +20,8 @@ #include "pmc.h" -#define UBOOT_DM_CLK_AT91_UTMI "at91-utmi-clk" +#define UBOOT_DM_CLK_AT91_UTMI "at91-utmi-clk" +#define UBOOT_DM_CLK_AT91_SAMA7G5_UTMI "at91-sama7g5-utmi-clk" /* * The purpose of this clock is to generate a 480 MHz signal. A different @@ -163,3 +164,71 @@ U_BOOT_DRIVER(at91_utmi_clk) = { .ops = &utmi_ops, .flags = DM_FLAG_PRE_RELOC, }; + +static int clk_utmi_sama7g5_enable(struct clk *clk) +{ + struct clk_utmi *utmi = to_clk_utmi(clk); + ulong parent_rate = clk_get_parent_rate(clk); + unsigned int val; + + switch (parent_rate) { + case 16000000: + val = 0; + break; + case 20000000: + val = 2; + break; + case 24000000: + val = 3; + break; + case 32000000: + val = 5; + break; + default: + debug("UTMICK: unsupported main_xtal rate\n"); + return -EINVAL; + } + + pmc_write(utmi->base, AT91_PMC_XTALF, val); + + return 0; +} + +static const struct clk_ops sama7g5_utmi_ops = { + .enable = clk_utmi_sama7g5_enable, + .get_rate = clk_utmi_get_rate, +}; + +struct clk *at91_clk_sama7g5_register_utmi(void __iomem *base, + const char *name, const char *parent_name) +{ + struct clk_utmi *utmi; + struct clk *clk; + int ret; + + if (!base || !name || !parent_name) + return ERR_PTR(-EINVAL); + + utmi = kzalloc(sizeof(*utmi), GFP_KERNEL); + if (!utmi) + return ERR_PTR(-ENOMEM); + + utmi->base = base; + + clk = &utmi->clk; + ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAMA7G5_UTMI, name, + parent_name); + if (ret) { + kfree(utmi); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_sama7g5_utmi_clk) = { + .name = UBOOT_DM_CLK_AT91_SAMA7G5_UTMI, + .id = UCLASS_CLK, + .ops = &sama7g5_utmi_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 264b36c7b4..d34005f698 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -88,6 +88,9 @@ at91_clk_sama7g5_register_master(void __iomem *base, const char *name, struct clk * at91_clk_register_utmi(void __iomem *base, struct udevice *dev, const char *name, const char *parent_name); +struct clk * +at91_clk_sama7g5_register_utmi(void __iomem *base, const char *name, + const char *parent_name); int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val); int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index); From 2a1a579bde83f0ab6a6eb61a4189820972bfe691 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:47 +0300 Subject: [PATCH 16/32] clk: at91: clk-programmable: add driver compatible with ccf Add clk-programmable driver compatible with common clock framework. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/Makefile | 2 +- drivers/clk/at91/clk-programmable.c | 208 ++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 17 +++ 3 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/at91/clk-programmable.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 9c38bda5e6..8951052eb0 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -3,7 +3,7 @@ # ifdef CONFIG_CLK_CCF -obj-y += pmc.o sckc.o clk-main.o clk-master.o +obj-y += pmc.o sckc.o clk-main.o clk-master.o clk-programmable.o obj-$(CONFIG_AT91_UTMI) += clk-utmi.o obj-$(CONFIG_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o else diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c new file mode 100644 index 0000000000..868de4b177 --- /dev/null +++ b/drivers/clk/at91/clk-programmable.c @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Programmable clock support for AT91 architectures. + * + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + * + * Based on drivers/clk/at91/clk-programmable.c from Linux. + */ +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define UBOOT_DM_CLK_AT91_PROG "at91-prog-clk" + +#define PROG_ID_MAX 7 + +#define PROG_STATUS_MASK(id) (1 << ((id) + 8)) +#define PROG_PRES(_l, _p) (((_p) >> (_l)->pres_shift) & (_l)->pres_mask) +#define PROG_MAX_RM9200_CSS 3 + +struct clk_programmable { + void __iomem *base; + const u32 *clk_mux_table; + const u32 *mux_table; + const struct clk_programmable_layout *layout; + u32 num_parents; + struct clk clk; + u8 id; +}; + +#define to_clk_programmable(_c) container_of(_c, struct clk_programmable, clk) + +static ulong clk_programmable_get_rate(struct clk *clk) +{ + struct clk_programmable *prog = to_clk_programmable(clk); + const struct clk_programmable_layout *layout = prog->layout; + ulong rate, parent_rate = clk_get_parent_rate(clk); + unsigned int pckr; + + pmc_read(prog->base, AT91_PMC_PCKR(prog->id), &pckr); + + if (layout->is_pres_direct) + rate = parent_rate / (PROG_PRES(layout, pckr) + 1); + else + rate = parent_rate >> PROG_PRES(layout, pckr); + + return rate; +} + +static int clk_programmable_set_parent(struct clk *clk, struct clk *parent) +{ + struct clk_programmable *prog = to_clk_programmable(clk); + const struct clk_programmable_layout *layout = prog->layout; + unsigned int mask = layout->css_mask; + int index; + + index = at91_clk_mux_val_to_index(prog->clk_mux_table, + prog->num_parents, parent->id); + if (index < 0) + return index; + + index = at91_clk_mux_index_to_val(prog->mux_table, prog->num_parents, + index); + if (index < 0) + return index; + + if (layout->have_slck_mck) + mask |= AT91_PMC_CSSMCK_MCK; + + if (index > layout->css_mask) { + if (index > PROG_MAX_RM9200_CSS && !layout->have_slck_mck) + return -EINVAL; + + index |= AT91_PMC_CSSMCK_MCK; + } + + pmc_update_bits(prog->base, AT91_PMC_PCKR(prog->id), mask, index); + + return 0; +} + +static ulong clk_programmable_set_rate(struct clk *clk, ulong rate) +{ + struct clk_programmable *prog = to_clk_programmable(clk); + const struct clk_programmable_layout *layout = prog->layout; + ulong parent_rate = clk_get_parent_rate(clk); + ulong div = parent_rate / rate; + int shift = 0; + + if (!parent_rate || !div) + return -EINVAL; + + if (layout->is_pres_direct) { + shift = div - 1; + + if (shift > layout->pres_mask) + return -EINVAL; + } else { + shift = fls(div) - 1; + + if (div != (1 << shift)) + return -EINVAL; + + if (shift >= layout->pres_mask) + return -EINVAL; + } + + pmc_update_bits(prog->base, AT91_PMC_PCKR(prog->id), + layout->pres_mask << layout->pres_shift, + shift << layout->pres_shift); + + if (layout->is_pres_direct) + return (parent_rate / shift + 1); + + return parent_rate >> shift; +} + +static const struct clk_ops programmable_ops = { + .get_rate = clk_programmable_get_rate, + .set_parent = clk_programmable_set_parent, + .set_rate = clk_programmable_set_rate, +}; + +struct clk *at91_clk_register_programmable(void __iomem *base, const char *name, + const char *const *parent_names, u8 num_parents, u8 id, + const struct clk_programmable_layout *layout, + const u32 *clk_mux_table, const u32 *mux_table) +{ + struct clk_programmable *prog; + struct clk *clk; + u32 val, tmp; + int ret; + + if (!base || !name || !parent_names || !num_parents || + !layout || !clk_mux_table || !mux_table || id > PROG_ID_MAX) + return ERR_PTR(-EINVAL); + + prog = kzalloc(sizeof(*prog), GFP_KERNEL); + if (!prog) + return ERR_PTR(-ENOMEM); + + prog->id = id; + prog->layout = layout; + prog->base = base; + prog->clk_mux_table = clk_mux_table; + prog->mux_table = mux_table; + prog->num_parents = num_parents; + + pmc_read(prog->base, AT91_PMC_PCKR(prog->id), &tmp); + val = tmp & prog->layout->css_mask; + if (layout->have_slck_mck && (tmp & AT91_PMC_CSSMCK_MCK) && !val) + ret = PROG_MAX_RM9200_CSS + 1; + else + ret = at91_clk_mux_val_to_index(prog->mux_table, + prog->num_parents, val); + if (ret < 0) { + kfree(prog); + return ERR_PTR(ret); + } + + clk = &prog->clk; + clk->flags = CLK_GET_RATE_NOCACHE; + ret = clk_register(clk, UBOOT_DM_CLK_AT91_PROG, name, + parent_names[ret]); + if (ret) { + kfree(prog); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_prog_clk) = { + .name = UBOOT_DM_CLK_AT91_PROG, + .id = UCLASS_CLK, + .ops = &programmable_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +const struct clk_programmable_layout at91rm9200_programmable_layout = { + .pres_mask = 0x7, + .pres_shift = 2, + .css_mask = 0x3, + .have_slck_mck = 0, + .is_pres_direct = 0, +}; + +const struct clk_programmable_layout at91sam9g45_programmable_layout = { + .pres_mask = 0x7, + .pres_shift = 2, + .css_mask = 0x3, + .have_slck_mck = 1, + .is_pres_direct = 0, +}; + +const struct clk_programmable_layout at91sam9x5_programmable_layout = { + .pres_mask = 0x7, + .pres_shift = 4, + .css_mask = 0x7, + .have_slck_mck = 0, + .is_pres_direct = 0, +}; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index d34005f698..a443b65257 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -55,6 +55,18 @@ struct clk_pll_layout { u8 endiv_shift; }; +struct clk_programmable_layout { + u8 pres_mask; + u8 pres_shift; + u8 css_mask; + u8 have_slck_mck; + u8 is_pres_direct; +}; + +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; + struct clk *at91_clk_main_rc(void __iomem *reg, const char *name, const char *parent_name); struct clk *at91_clk_main_osc(void __iomem *reg, const char *name, @@ -91,6 +103,11 @@ at91_clk_register_utmi(void __iomem *base, struct udevice *dev, struct clk * at91_clk_sama7g5_register_utmi(void __iomem *base, const char *name, const char *parent_name); +struct clk * +at91_clk_register_programmable(void __iomem *base, const char *name, + const char * const *parent_names, u8 num_parents, u8 id, + const struct clk_programmable_layout *layout, + const u32 *clk_mux_table, const u32 *mux_table); int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val); int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index); From 16502bfa7c969cff366f92de67c048d2b0c626b8 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:48 +0300 Subject: [PATCH 17/32] clk: at91: clk-system: add driver compatible with ccf Add clk-system driver compatible with common clock framework. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/Makefile | 2 +- drivers/clk/at91/clk-system.c | 112 ++++++++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 3 + 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/at91/clk-system.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 8951052eb0..1d59531e0c 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -3,7 +3,7 @@ # ifdef CONFIG_CLK_CCF -obj-y += pmc.o sckc.o clk-main.o clk-master.o clk-programmable.o +obj-y += pmc.o sckc.o clk-main.o clk-master.o clk-programmable.o clk-system.o obj-$(CONFIG_AT91_UTMI) += clk-utmi.o obj-$(CONFIG_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o else diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c new file mode 100644 index 0000000000..82f79e74a1 --- /dev/null +++ b/drivers/clk/at91/clk-system.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * System clock support for AT91 architectures. + * + * Copyright (C) Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + * + * Based on drivers/clk/at91/clk-system.c from Linux. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define UBOOT_DM_CLK_AT91_SYSTEM "at91-system-clk" + +#define SYSTEM_MAX_ID 31 + +struct clk_system { + void __iomem *base; + struct clk clk; + u8 id; +}; + +#define to_clk_system(_c) container_of(_c, struct clk_system, clk) + +static inline int is_pck(int id) +{ + return (id >= 8) && (id <= 15); +} + +static inline bool clk_system_ready(void __iomem *base, int id) +{ + unsigned int status; + + pmc_read(base, AT91_PMC_SR, &status); + + return !!(status & (1 << id)); +} + +static int clk_system_enable(struct clk *clk) +{ + struct clk_system *sys = to_clk_system(clk); + + pmc_write(sys->base, AT91_PMC_SCER, 1 << sys->id); + + if (!is_pck(sys->id)) + return 0; + + while (!clk_system_ready(sys->base, sys->id)) { + debug("waiting for pck%u\n", sys->id); + cpu_relax(); + } + + return 0; +} + +static int clk_system_disable(struct clk *clk) +{ + struct clk_system *sys = to_clk_system(clk); + + pmc_write(sys->base, AT91_PMC_SCDR, 1 << sys->id); + + return 0; +} + +static const struct clk_ops system_ops = { + .enable = clk_system_enable, + .disable = clk_system_disable, + .get_rate = clk_generic_get_rate, +}; + +struct clk *at91_clk_register_system(void __iomem *base, const char *name, + const char *parent_name, u8 id) +{ + struct clk_system *sys; + struct clk *clk; + int ret; + + if (!base || !name || !parent_name || id > SYSTEM_MAX_ID) + return ERR_PTR(-EINVAL); + + sys = kzalloc(sizeof(*sys), GFP_KERNEL); + if (!sys) + return ERR_PTR(-ENOMEM); + + sys->id = id; + sys->base = base; + + clk = &sys->clk; + clk->flags = CLK_GET_RATE_NOCACHE; + ret = clk_register(clk, UBOOT_DM_CLK_AT91_SYSTEM, name, parent_name); + if (ret) { + kfree(sys); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_system_clk) = { + .name = UBOOT_DM_CLK_AT91_SYSTEM, + .id = UCLASS_CLK, + .ops = &system_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index a443b65257..c372f39fc9 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -108,6 +108,9 @@ at91_clk_register_programmable(void __iomem *base, const char *name, const char * const *parent_names, u8 num_parents, u8 id, const struct clk_programmable_layout *layout, const u32 *clk_mux_table, const u32 *mux_table); +struct clk * +at91_clk_register_system(void __iomem *base, const char *name, + const char *parent_name, u8 id); int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val); int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index); From f89268e46814a56323ca78b85eb0e32e6ef3cbd0 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:49 +0300 Subject: [PATCH 18/32] clk: at91: clk-peripheral: add driver compatible with ccf Add clk-peripheral compatible with common clock framework. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/Makefile | 2 + drivers/clk/at91/clk-peripheral.c | 254 ++++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 16 ++ 3 files changed, 272 insertions(+) create mode 100644 drivers/clk/at91/clk-peripheral.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 1d59531e0c..b5529065b5 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -4,6 +4,8 @@ ifdef CONFIG_CLK_CCF obj-y += pmc.o sckc.o clk-main.o clk-master.o clk-programmable.o clk-system.o +obj-y += clk-peripheral.o + obj-$(CONFIG_AT91_UTMI) += clk-utmi.o obj-$(CONFIG_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o else diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c new file mode 100644 index 0000000000..52cbc520ce --- /dev/null +++ b/drivers/clk/at91/clk-peripheral.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Peripheral clock support for AT91 architectures. + * + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + * + * Based on drivers/clk/at91/clk-peripheral.c from Linux. + */ +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define UBOOT_DM_CLK_AT91_PERIPH "at91-periph-clk" +#define UBOOT_DM_CLK_AT91_SAM9X5_PERIPH "at91-sam9x5-periph-clk" + +#define PERIPHERAL_ID_MIN 2 +#define PERIPHERAL_ID_MAX 31 +#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX)) + +#define PERIPHERAL_MAX_SHIFT 3 + +struct clk_peripheral { + void __iomem *base; + struct clk clk; + u32 id; +}; + +#define to_clk_peripheral(_c) container_of(_c, struct clk_peripheral, clk) + +struct clk_sam9x5_peripheral { + const struct clk_pcr_layout *layout; + void __iomem *base; + struct clk clk; + struct clk_range range; + u32 id; + u32 div; + bool auto_div; +}; + +#define to_clk_sam9x5_peripheral(_c) \ + container_of(_c, struct clk_sam9x5_peripheral, clk) + +static int clk_peripheral_enable(struct clk *clk) +{ + struct clk_peripheral *periph = to_clk_peripheral(clk); + int offset = AT91_PMC_PCER; + u32 id = periph->id; + + if (id < PERIPHERAL_ID_MIN) + return 0; + if (id > PERIPHERAL_ID_MAX) + offset = AT91_PMC_PCER1; + pmc_write(periph->base, offset, PERIPHERAL_MASK(id)); + + return 0; +} + +static int clk_peripheral_disable(struct clk *clk) +{ + struct clk_peripheral *periph = to_clk_peripheral(clk); + int offset = AT91_PMC_PCDR; + u32 id = periph->id; + + if (id < PERIPHERAL_ID_MIN) + return -EINVAL; + + if (id > PERIPHERAL_ID_MAX) + offset = AT91_PMC_PCDR1; + pmc_write(periph->base, offset, PERIPHERAL_MASK(id)); + + return 0; +} + +static const struct clk_ops peripheral_ops = { + .enable = clk_peripheral_enable, + .disable = clk_peripheral_disable, + .get_rate = clk_generic_get_rate, +}; + +struct clk * +at91_clk_register_peripheral(void __iomem *base, const char *name, + const char *parent_name, u32 id) +{ + struct clk_peripheral *periph; + struct clk *clk; + int ret; + + if (!base || !name || !parent_name || id > PERIPHERAL_ID_MAX) + return ERR_PTR(-EINVAL); + + periph = kzalloc(sizeof(*periph), GFP_KERNEL); + if (!periph) + return ERR_PTR(-ENOMEM); + + periph->id = id; + periph->base = base; + + clk = &periph->clk; + clk->flags = CLK_GET_RATE_NOCACHE; + ret = clk_register(clk, UBOOT_DM_CLK_AT91_PERIPH, name, parent_name); + if (ret) { + kfree(periph); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_periph_clk) = { + .name = UBOOT_DM_CLK_AT91_PERIPH, + .id = UCLASS_CLK, + .ops = &peripheral_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +static int clk_sam9x5_peripheral_enable(struct clk *clk) +{ + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk); + + if (periph->id < PERIPHERAL_ID_MIN) + return 0; + + pmc_write(periph->base, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + pmc_update_bits(periph->base, periph->layout->offset, + periph->layout->cmd | AT91_PMC_PCR_EN, + periph->layout->cmd | AT91_PMC_PCR_EN); + + return 0; +} + +static int clk_sam9x5_peripheral_disable(struct clk *clk) +{ + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk); + + if (periph->id < PERIPHERAL_ID_MIN) + return -EINVAL; + + pmc_write(periph->base, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + pmc_update_bits(periph->base, periph->layout->offset, + AT91_PMC_PCR_EN | periph->layout->cmd, + periph->layout->cmd); + + return 0; +} + +static ulong clk_sam9x5_peripheral_get_rate(struct clk *clk) +{ + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk); + ulong parent_rate = clk_get_parent_rate(clk); + u32 val, shift = ffs(periph->layout->div_mask) - 1; + + if (!parent_rate) + return 0; + + pmc_write(periph->base, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + pmc_read(periph->base, periph->layout->offset, &val); + shift = (val & periph->layout->div_mask) >> shift; + + return parent_rate >> shift; +} + +static ulong clk_sam9x5_peripheral_set_rate(struct clk *clk, ulong rate) +{ + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk); + ulong parent_rate = clk_get_parent_rate(clk); + int shift; + + if (!parent_rate) + return 0; + + if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) { + if (parent_rate == rate) + return rate; + else + return 0; + } + + if (periph->range.max && rate > periph->range.max) + return 0; + + for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) { + if (parent_rate >> shift <= rate) + break; + } + if (shift == PERIPHERAL_MAX_SHIFT + 1) + return 0; + + pmc_write(periph->base, periph->layout->offset, + (periph->id & periph->layout->pid_mask)); + pmc_update_bits(periph->base, periph->layout->offset, + periph->layout->div_mask | periph->layout->cmd, + (shift << (ffs(periph->layout->div_mask) - 1)) | + periph->layout->cmd); + + return parent_rate >> shift; +} + +static const struct clk_ops sam9x5_peripheral_ops = { + .enable = clk_sam9x5_peripheral_enable, + .disable = clk_sam9x5_peripheral_disable, + .get_rate = clk_sam9x5_peripheral_get_rate, + .set_rate = clk_sam9x5_peripheral_set_rate, +}; + +struct clk * +at91_clk_register_sam9x5_peripheral(void __iomem *base, + const struct clk_pcr_layout *layout, + const char *name, const char *parent_name, + u32 id, const struct clk_range *range) +{ + struct clk_sam9x5_peripheral *periph; + struct clk *clk; + int ret; + + if (!base || !layout || !name || !parent_name || !range) + return ERR_PTR(-EINVAL); + + periph = kzalloc(sizeof(*periph), GFP_KERNEL); + if (!periph) + return ERR_PTR(-ENOMEM); + + periph->id = id; + periph->base = base; + periph->layout = layout; + periph->range = *range; + + clk = &periph->clk; + clk->flags = CLK_GET_RATE_NOCACHE; + ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X5_PERIPH, name, + parent_name); + if (ret) { + kfree(periph); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_sam9x5_periph_clk) = { + .name = UBOOT_DM_CLK_AT91_SAM9X5_PERIPH, + .id = UCLASS_CLK, + .ops = &sam9x5_peripheral_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index c372f39fc9..5e80f353e6 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -63,6 +63,14 @@ struct clk_programmable_layout { u8 is_pres_direct; }; +struct clk_pcr_layout { + u32 offset; + u32 cmd; + u32 div_mask; + u32 gckcss_mask; + u32 pid_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; @@ -111,6 +119,14 @@ at91_clk_register_programmable(void __iomem *base, const char *name, struct clk * at91_clk_register_system(void __iomem *base, const char *name, const char *parent_name, u8 id); +struct clk * +at91_clk_register_peripheral(void __iomem *base, const char *name, + const char *parent_name, u32 id); +struct clk * +at91_clk_register_sam9x5_peripheral(void __iomem *base, + const struct clk_pcr_layout *layout, + const char *name, const char *parent_name, + u32 id, const struct clk_range *range); int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val); int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index); From 36a9630fcbb0bfb2d3fc6c04ae9de666846ced32 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:50 +0300 Subject: [PATCH 19/32] clk: at91: clk-generic: add driver compatible with ccf Add clk-generic driver compatible with common clock framework. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/Makefile | 1 + drivers/clk/at91/clk-generic.c | 202 +++++++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 6 + 3 files changed, 209 insertions(+) create mode 100644 drivers/clk/at91/clk-generic.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index b5529065b5..2cd840af38 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -6,6 +6,7 @@ ifdef CONFIG_CLK_CCF obj-y += pmc.o sckc.o clk-main.o clk-master.o clk-programmable.o clk-system.o 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 else diff --git a/drivers/clk/at91/clk-generic.c b/drivers/clk/at91/clk-generic.c new file mode 100644 index 0000000000..87738b7b5b --- /dev/null +++ b/drivers/clk/at91/clk-generic.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Generic clock support for AT91 architectures. + * + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + * + * Based on drivers/clk/at91/clk-generated.c from Linux. + */ +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define UBOOT_DM_CLK_AT91_GCK "at91-gck-clk" + +#define GENERATED_MAX_DIV 255 + +struct clk_gck { + void __iomem *base; + const u32 *clk_mux_table; + const u32 *mux_table; + const struct clk_pcr_layout *layout; + struct clk_range range; + struct clk clk; + u32 num_parents; + u32 id; +}; + +#define to_clk_gck(_c) container_of(_c, struct clk_gck, clk) + +static int clk_gck_enable(struct clk *clk) +{ + struct clk_gck *gck = to_clk_gck(clk); + + pmc_write(gck->base, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + pmc_update_bits(gck->base, gck->layout->offset, + gck->layout->cmd | AT91_PMC_PCR_GCKEN, + gck->layout->cmd | AT91_PMC_PCR_GCKEN); + + return 0; +} + +static int clk_gck_disable(struct clk *clk) +{ + struct clk_gck *gck = to_clk_gck(clk); + + pmc_write(gck->base, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + pmc_update_bits(gck->base, gck->layout->offset, + gck->layout->cmd | AT91_PMC_PCR_GCKEN, + gck->layout->cmd); + + return 0; +} + +static int clk_gck_set_parent(struct clk *clk, struct clk *parent) +{ + struct clk_gck *gck = to_clk_gck(clk); + int index; + + index = at91_clk_mux_val_to_index(gck->clk_mux_table, gck->num_parents, + parent->id); + if (index < 0) + return index; + + index = at91_clk_mux_index_to_val(gck->mux_table, gck->num_parents, + index); + if (index < 0) + return index; + + pmc_write(gck->base, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + pmc_update_bits(gck->base, gck->layout->offset, + gck->layout->gckcss_mask | gck->layout->cmd, + (index << (ffs(gck->layout->gckcss_mask) - 1)) | + gck->layout->cmd); + + return 0; +} + +static ulong clk_gck_set_rate(struct clk *clk, ulong rate) +{ + struct clk_gck *gck = to_clk_gck(clk); + ulong parent_rate = clk_get_parent_rate(clk); + u32 div; + + if (!rate || !parent_rate) + return 0; + + if (gck->range.max && rate > gck->range.max) + return 0; + + div = DIV_ROUND_CLOSEST(parent_rate, rate); + if (div > GENERATED_MAX_DIV + 1 || !div) + return 0; + + pmc_write(gck->base, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + pmc_update_bits(gck->base, gck->layout->offset, + AT91_PMC_PCR_GCKDIV_MASK | gck->layout->cmd, + ((div - 1) << (ffs(AT91_PMC_PCR_GCKDIV_MASK) - 1)) | + gck->layout->cmd); + + return parent_rate / div; +} + +static ulong clk_gck_get_rate(struct clk *clk) +{ + struct clk_gck *gck = to_clk_gck(clk); + ulong parent_rate = clk_get_parent_rate(clk); + u32 val, div; + + if (!parent_rate) + return 0; + + pmc_write(gck->base, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + pmc_read(gck->base, gck->layout->offset, &val); + + div = (val & AT91_PMC_PCR_GCKDIV_MASK) >> + (ffs(AT91_PMC_PCR_GCKDIV_MASK) - 1); + + return parent_rate / (div + 1); +} + +static const struct clk_ops gck_ops = { + .enable = clk_gck_enable, + .disable = clk_gck_disable, + .set_parent = clk_gck_set_parent, + .set_rate = clk_gck_set_rate, + .get_rate = clk_gck_get_rate, +}; + +struct clk * +at91_clk_register_generic(void __iomem *base, + const struct clk_pcr_layout *layout, + const char *name, const char * const *parent_names, + const u32 *clk_mux_table, const u32 *mux_table, + u8 num_parents, u8 id, + const struct clk_range *range) +{ + struct clk_gck *gck; + struct clk *clk; + int ret, index; + u32 val; + + if (!base || !layout || !name || !parent_names || !num_parents || + !clk_mux_table || !mux_table || !range) + return ERR_PTR(-EINVAL); + + gck = kzalloc(sizeof(*gck), GFP_KERNEL); + if (!gck) + return ERR_PTR(-ENOMEM); + + gck->id = id; + gck->base = base; + gck->range = *range; + gck->layout = layout; + gck->clk_mux_table = clk_mux_table; + gck->mux_table = mux_table; + gck->num_parents = num_parents; + + clk = &gck->clk; + clk->flags = CLK_GET_RATE_NOCACHE; + + pmc_write(gck->base, gck->layout->offset, + (gck->id & gck->layout->pid_mask)); + pmc_read(gck->base, gck->layout->offset, &val); + + val = (val & gck->layout->gckcss_mask) >> + (ffs(gck->layout->gckcss_mask) - 1); + + index = at91_clk_mux_val_to_index(gck->mux_table, gck->num_parents, + val); + if (index < 0) { + kfree(gck); + return ERR_PTR(index); + } + + ret = clk_register(clk, UBOOT_DM_CLK_AT91_GCK, name, + parent_names[index]); + if (ret) { + kfree(gck); + clk = ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(at91_gck_clk) = { + .name = UBOOT_DM_CLK_AT91_GCK, + .id = UCLASS_CLK, + .ops = &gck_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 5e80f353e6..176855e7a0 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -127,6 +127,12 @@ at91_clk_register_sam9x5_peripheral(void __iomem *base, const struct clk_pcr_layout *layout, const char *name, const char *parent_name, u32 id, const struct clk_range *range); +struct clk * +at91_clk_register_generic(void __iomem *base, + const struct clk_pcr_layout *layout, const char *name, + const char * const *parent_names, + const u32 *clk_mux_table, const u32 *mux_table, + u8 num_parents, u8 id, const struct clk_range *range); int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val); int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index); From 7b7e226739104347a69d88dc3414c16e5fb1fe9d Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:51 +0300 Subject: [PATCH 20/32] clk: at91: pmc: add generic clock ops Add generic clock ops to be used by every AT91 PMC driver built on top of CCF. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/pmc.c | 71 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 2 ++ 2 files changed, 73 insertions(+) diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index 29c6452497..660e231921 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -5,8 +5,79 @@ */ #include +#include #include +#include "pmc.h" + +static int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) +{ + if (args->args_count != 2) { + debug("AT91: clk: Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + clk->id = AT91_TO_CLK_ID(args->args[0], args->args[1]); + + return 0; +} + +static ulong at91_clk_get_rate(struct clk *clk) +{ + struct clk *c; + int ret; + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + return clk_get_rate(c); +} + +static ulong at91_clk_set_rate(struct clk *clk, ulong rate) +{ + struct clk *c; + int ret; + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + return clk_set_rate(c, rate); +} + +static int at91_clk_enable(struct clk *clk) +{ + struct clk *c; + int ret; + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + return clk_enable(c); +} + +static int at91_clk_disable(struct clk *clk) +{ + struct clk *c; + int ret; + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + return clk_disable(c); +} + +const struct clk_ops at91_clk_ops = { + .of_xlate = at91_clk_of_xlate, + .set_rate = at91_clk_set_rate, + .get_rate = at91_clk_get_rate, + .enable = at91_clk_enable, + .disable = at91_clk_disable, +}; + /** * pmc_read() - read content at address base + off into val * diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 176855e7a0..a6a714fd22 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -75,6 +75,8 @@ 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; +extern const struct clk_ops at91_clk_ops; + struct clk *at91_clk_main_rc(void __iomem *reg, const char *name, const char *parent_name); struct clk *at91_clk_main_osc(void __iomem *reg, const char *name, From 6a6fe3ed4d80afba7efc65a87aca5344672768c5 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:52 +0300 Subject: [PATCH 21/32] clk: at91: sama7g5: add clock support Add clock support for SAMA7G5. Signed-off-by: Claudiu Beznea --- drivers/clk/at91/Makefile | 1 + drivers/clk/at91/sama7g5.c | 1401 ++++++++++++++++++++++++++++++++++++ 2 files changed, 1402 insertions(+) create mode 100644 drivers/clk/at91/sama7g5.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 2cd840af38..2453c38af1 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_SAMA7G5) += sama7g5.o else obj-y += compat.o endif diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c new file mode 100644 index 0000000000..b96937673b --- /dev/null +++ b/drivers/clk/at91/sama7g5.c @@ -0,0 +1,1401 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SAMA7G5 PMC clock support. + * + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + * + * Based on drivers/clk/at91/sama7g5.c from Linux. + */ + +#include +#include +#include +#include +#include + +#include "pmc.h" + +/** + * Clock identifiers to be used in conjunction with macros like + * AT91_TO_CLK_ID() + * + * @ID_MD_SLCK: TD slow clock identifier + * @ID_TD_SLCK: MD slow clock identifier + * @ID_MAIN_XTAL: Main Xtal clock identifier + * @ID_MAIN_RC: Main RC clock identifier + * @ID_MAIN_RC_OSC: Main RC Oscillator clock identifier + * @ID_MAIN_OSC: Main Oscillator clock identifier + * @ID_MAINCK: MAINCK clock identifier + * @ID_PLL_CPU_FRAC: CPU PLL fractional clock identifier + * @ID_PLL_CPU_DIV: CPU PLL divider clock identifier + * @ID_PLL_SYS_FRAC: SYS PLL fractional clock identifier + * @ID_PLL_SYS_DIV: SYS PLL divider clock identifier + * @ID_PLL_DDR_FRAC: DDR PLL fractional clock identifier + * @ID_PLL_DDR_DIV: DDR PLL divider clock identifier + * @ID_PLL_IMG_FRAC: IMC PLL fractional clock identifier + * @ID_PLL_IMG_DIV: IMG PLL divider clock identifier + * @ID_PLL_BAUD_FRAC: Baud PLL fractional clock identifier + * @ID_PLL_BAUD_DIV: Baud PLL divider clock identifier + * @ID_PLL_AUDIO_FRAC: Audio PLL fractional clock identifier + * @ID_PLL_AUDIO_DIVPMC: Audio PLL PMC divider clock identifier + * @ID_PLL_AUDIO_DIVIO: Audio PLL IO divider clock identifier + * @ID_PLL_ETH_FRAC: Ethernet PLL fractional clock identifier + * @ID_PLL_ETH_DIV: Ethernet PLL divider clock identifier + + * @ID_MCK0: MCK0 clock identifier + * @ID_MCK1: MCK1 clock identifier + * @ID_MCK2: MCK2 clock identifier + * @ID_MCK3: MCK3 clock identifier + * @ID_MCK4: MCK4 clock identifier + + * @ID_UTMI: UTMI clock identifier + + * @ID_PROG0: Programmable 0 clock identifier + * @ID_PROG1: Programmable 1 clock identifier + * @ID_PROG2: Programmable 2 clock identifier + * @ID_PROG3: Programmable 3 clock identifier + * @ID_PROG4: Programmable 4 clock identifier + * @ID_PROG5: Programmable 5 clock identifier + * @ID_PROG6: Programmable 6 clock identifier + * @ID_PROG7: Programmable 7 clock identifier + + * @ID_PCK0: System clock 0 clock identifier + * @ID_PCK1: System clock 1 clock identifier + * @ID_PCK2: System clock 2 clock identifier + * @ID_PCK3: System clock 3 clock identifier + * @ID_PCK4: System clock 4 clock identifier + * @ID_PCK5: System clock 5 clock identifier + * @ID_PCK6: System clock 6 clock identifier + * @ID_PCK7: System clock 7 clock identifier + */ +enum pmc_clk_ids { + ID_MD_SLCK = 0, + ID_TD_SLCK = 1, + ID_MAIN_XTAL = 2, + ID_MAIN_RC = 3, + ID_MAIN_RC_OSC = 4, + ID_MAIN_OSC = 5, + ID_MAINCK = 6, + + ID_PLL_CPU_FRAC = 7, + ID_PLL_CPU_DIV = 8, + ID_PLL_SYS_FRAC = 9, + ID_PLL_SYS_DIV = 10, + ID_PLL_DDR_FRAC = 11, + ID_PLL_DDR_DIV = 12, + ID_PLL_IMG_FRAC = 13, + ID_PLL_IMG_DIV = 14, + ID_PLL_BAUD_FRAC = 15, + ID_PLL_BAUD_DIV = 16, + ID_PLL_AUDIO_FRAC = 17, + ID_PLL_AUDIO_DIVPMC = 18, + ID_PLL_AUDIO_DIVIO = 19, + ID_PLL_ETH_FRAC = 20, + ID_PLL_ETH_DIV = 21, + + ID_MCK0 = 22, + ID_MCK1 = 23, + ID_MCK2 = 24, + ID_MCK3 = 25, + ID_MCK4 = 26, + + ID_UTMI = 27, + + ID_PROG0 = 28, + ID_PROG1 = 29, + ID_PROG2 = 30, + ID_PROG3 = 31, + ID_PROG4 = 32, + ID_PROG5 = 33, + ID_PROG6 = 34, + ID_PROG7 = 35, + + ID_PCK0 = 36, + ID_PCK1 = 37, + ID_PCK2 = 38, + ID_PCK3 = 39, + ID_PCK4 = 40, + ID_PCK5 = 41, + ID_PCK6 = 42, + ID_PCK7 = 43, + + ID_MAX, +}; + +/** + * PLL type identifiers + * @PLL_TYPE_FRAC: fractional PLL identifier + * @PLL_TYPE_DIV: divider PLL identifier + */ +enum pll_type { + PLL_TYPE_FRAC, + PLL_TYPE_DIV, +}; + +/* Clock names used as parents for multiple clocks. */ +static const char *clk_names[] = { + [ID_MAIN_RC_OSC] = "main_rc_osc", + [ID_MAIN_OSC] = "main_osc", + [ID_MAINCK] = "mainck", + [ID_PLL_CPU_DIV] = "cpupll_divpmcck", + [ID_PLL_SYS_DIV] = "syspll_divpmcck", + [ID_PLL_DDR_DIV] = "ddrpll_divpmcck", + [ID_PLL_IMG_DIV] = "imgpll_divpmcck", + [ID_PLL_BAUD_DIV] = "baudpll_divpmcck", + [ID_PLL_AUDIO_DIVPMC] = "audiopll_divpmcck", + [ID_PLL_AUDIO_DIVIO] = "audiopll_diviock", + [ID_PLL_ETH_DIV] = "ethpll_divpmcck", + [ID_MCK0] = "mck0", +}; + +/* Fractional PLL output range. */ +static const struct clk_range pll_outputs[] = { + { .min = 2343750, .max = 1200000000 }, +}; + +/* PLL characteristics. */ +static const struct clk_pll_characteristics pll_characteristics = { + .input = { .min = 12000000, .max = 50000000 }, + .num_output = ARRAY_SIZE(pll_outputs), + .output = pll_outputs, +}; + +/* Layout for fractional PLLs. */ +static const struct clk_pll_layout pll_layout_frac = { + .mul_mask = GENMASK(31, 24), + .frac_mask = GENMASK(21, 0), + .mul_shift = 24, + .frac_shift = 0, +}; + +/* Layout for DIVPMC dividers. */ +static const struct clk_pll_layout pll_layout_divpmc = { + .div_mask = GENMASK(7, 0), + .endiv_mask = BIT(29), + .div_shift = 0, + .endiv_shift = 29, +}; + +/* Layout for DIVIO dividers. */ +static const struct clk_pll_layout pll_layout_divio = { + .div_mask = GENMASK(19, 12), + .endiv_mask = BIT(30), + .div_shift = 12, + .endiv_shift = 30, +}; + +/* MCK0 characteristics. */ +static const struct clk_master_characteristics mck0_characteristics = { + .output = { .min = 140000000, .max = 200000000 }, + .divisors = { 1, 2, 4, 3 }, + .have_div3_pres = 1, +}; + +/* MCK0 layout. */ +static const struct clk_master_layout mck0_layout = { + .mask = 0x373, + .pres_shift = 4, + .offset = 0x28, +}; + +/* Programmable clock layout. */ +static const struct clk_programmable_layout programmable_layout = { + .pres_mask = 0xff, + .pres_shift = 8, + .css_mask = 0x1f, + .have_slck_mck = 0, + .is_pres_direct = 1, +}; + +/* Peripheral clock layout. */ +static const struct clk_pcr_layout sama7g5_pcr_layout = { + .offset = 0x88, + .cmd = BIT(31), + .gckcss_mask = GENMASK(12, 8), + .pid_mask = GENMASK(6, 0), + .div_mask = GENMASK(15, 14), +}; + +/** + * PLL clocks description + * @n: clock name + * @p: clock parent + * @l: clock layout + * @t: clock type + * @c: true if clock is critical and cannot be disabled + * @id: clock id corresponding to PLL driver + * @cid: clock id corresponding to clock subsystem + */ +static const struct { + const char *n; + const char *p; + const struct clk_pll_layout *l; + u8 t; + u8 c; + u8 id; + u8 cid; +} sama7g5_plls[] = { + { + .n = "cpupll_fracck", + .p = "mainck", + .l = &pll_layout_frac, + .t = PLL_TYPE_FRAC, + .c = 1, + .id = 0, + .cid = ID_PLL_CPU_FRAC, + }, + + { + .n = "cpupll_divpmcck", + .p = "cpupll_fracck", + .l = &pll_layout_divpmc, + .t = PLL_TYPE_DIV, + .c = 1, + .id = 0, + .cid = ID_PLL_CPU_DIV, + }, + + { + .n = "syspll_fracck", + .p = "mainck", + .l = &pll_layout_frac, + .t = PLL_TYPE_FRAC, + .c = 1, + .id = 1, + .cid = ID_PLL_SYS_FRAC, + }, + + { + .n = "syspll_divpmcck", + .p = "syspll_fracck", + .l = &pll_layout_divpmc, + .t = PLL_TYPE_DIV, + .c = 1, + .id = 1, + .cid = ID_PLL_SYS_DIV, + }, + + { + .n = "ddrpll_fracck", + .p = "mainck", + .l = &pll_layout_frac, + .t = PLL_TYPE_FRAC, + .c = 1, + .id = 2, + .cid = ID_PLL_DDR_FRAC, + }, + + { + .n = "ddrpll_divpmcck", + .p = "ddrpll_fracck", + .l = &pll_layout_divpmc, + .t = PLL_TYPE_DIV, + .c = 1, + .id = 2, + .cid = ID_PLL_DDR_DIV, + }, + + { + .n = "imgpll_fracck", + .p = "mainck", + .l = &pll_layout_frac, + .t = PLL_TYPE_FRAC, + .id = 3, + .cid = ID_PLL_IMG_FRAC, + }, + + { + .n = "imgpll_divpmcck", + .p = "imgpll_fracck", + .l = &pll_layout_divpmc, + .t = PLL_TYPE_DIV, + .id = 3, + .cid = ID_PLL_IMG_DIV + }, + + { + .n = "baudpll_fracck", + .p = "mainck", + .l = &pll_layout_frac, + .t = PLL_TYPE_FRAC, + .id = 4, + .cid = ID_PLL_BAUD_FRAC, + }, + + { + .n = "baudpll_divpmcck", + .p = "baudpll_fracck", + .l = &pll_layout_divpmc, + .t = PLL_TYPE_DIV, + .id = 4, + .cid = ID_PLL_BAUD_DIV, + }, + + { + .n = "audiopll_fracck", + .p = "main_osc", + .l = &pll_layout_frac, + .t = PLL_TYPE_FRAC, + .id = 5, + .cid = ID_PLL_AUDIO_FRAC, + }, + + { + .n = "audiopll_divpmcck", + .p = "audiopll_fracck", + .l = &pll_layout_divpmc, + .t = PLL_TYPE_DIV, + .id = 5, + .cid = ID_PLL_AUDIO_DIVPMC, + }, + + { + .n = "audiopll_diviock", + .p = "audiopll_fracck", + .l = &pll_layout_divio, + .t = PLL_TYPE_DIV, + .id = 5, + .cid = ID_PLL_AUDIO_DIVIO, + }, + + { + .n = "ethpll_fracck", + .p = "main_osc", + .l = &pll_layout_frac, + .t = PLL_TYPE_FRAC, + .id = 6, + .cid = ID_PLL_ETH_FRAC, + }, + + { + .n = "ethpll_divpmcck", + .p = "ethpll_fracck", + .l = &pll_layout_divpmc, + .t = PLL_TYPE_DIV, + .id = 6, + .cid = ID_PLL_ETH_DIV, + }, +}; + +/** + * Master clock (MCK[1..4]) description + * @n: clock name + * @ep: extra parents names array + * @ep_chg_chg_id: index in parents array that specifies the changeable + * parent + * @ep_count: extra parents count + * @ep_mux_table: mux table for extra parents + * @ep_clk_mux_table: mux table to deal with subsystem clock ids + * @id: clock id corresponding to MCK driver + * @cid: clock id corresponding to clock subsystem + * @c: true if clock is critical and cannot be disabled + */ +static const struct { + const char *n; + const char *ep[4]; + u8 ep_count; + u8 ep_mux_table[4]; + u8 ep_clk_mux_table[4]; + u8 id; + u8 cid; + u8 c; +} sama7g5_mckx[] = { + { + .n = "mck1", + .id = 1, + .cid = ID_MCK1, + .ep = { "syspll_divpmcck", }, + .ep_mux_table = { 5, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, }, + .ep_count = 1, + .c = 1, + }, + + { + .n = "mck2", + .id = 2, + .cid = ID_MCK2, + .ep = { "ddrpll_divpmcck", }, + .ep_mux_table = { 6, }, + .ep_clk_mux_table = { ID_PLL_DDR_DIV, }, + .ep_count = 1, + .c = 1, + }, + + { + .n = "mck3", + .id = 3, + .cid = ID_MCK3, + .ep = { "syspll_divpmcck", "ddrpll_divpmcck", "imgpll_divpmcck", }, + .ep_mux_table = { 5, 6, 7, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_DDR_DIV, ID_PLL_IMG_DIV, }, + .ep_count = 3, + }, + + { + .n = "mck4", + .id = 4, + .cid = ID_MCK4, + .ep = { "syspll_divpmcck", }, + .ep_mux_table = { 5, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, }, + .ep_count = 1, + .c = 1, + }, +}; + +/** + * Programmable clock description + * @n: clock name + * @cid: clock id corresponding to clock subsystem + */ +static const struct { + const char *n; + u8 cid; +} sama7g5_prog[] = { + { .n = "prog0", .cid = ID_PROG0, }, + { .n = "prog1", .cid = ID_PROG1, }, + { .n = "prog2", .cid = ID_PROG2, }, + { .n = "prog3", .cid = ID_PROG3, }, + { .n = "prog4", .cid = ID_PROG4, }, + { .n = "prog5", .cid = ID_PROG5, }, + { .n = "prog6", .cid = ID_PROG6, }, + { .n = "prog7", .cid = ID_PROG7, }, +}; + +/* Mux table for programmable clocks. */ +static u32 sama7g5_prog_mux_table[] = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, }; + +/** + * System clock description + * @n: clock name + * @p: parent clock name + * @id: clock id corresponding to system clock driver + * @cid: clock id corresponding to clock subsystem + */ +static const struct { + const char *n; + const char *p; + u8 id; + u8 cid; +} sama7g5_systemck[] = { + { .n = "pck0", .p = "prog0", .id = 8, .cid = ID_PCK0, }, + { .n = "pck1", .p = "prog1", .id = 9, .cid = ID_PCK1, }, + { .n = "pck2", .p = "prog2", .id = 10, .cid = ID_PCK2, }, + { .n = "pck3", .p = "prog3", .id = 11, .cid = ID_PCK3, }, + { .n = "pck4", .p = "prog4", .id = 12, .cid = ID_PCK4, }, + { .n = "pck5", .p = "prog5", .id = 13, .cid = ID_PCK5, }, + { .n = "pck6", .p = "prog6", .id = 14, .cid = ID_PCK6, }, + { .n = "pck7", .p = "prog7", .id = 15, .cid = ID_PCK7, }, +}; + +/** + * Peripheral clock description + * @n: clock name + * @p: clock parent name + * @r: clock range values + * @id: clock id + */ +static const struct { + const char *n; + const char *p; + struct clk_range r; + u8 id; +} sama7g5_periphck[] = { + { .n = "pioA_clk", .p = "mck0", .id = 11, }, + { .n = "sfr_clk", .p = "mck1", .id = 19, }, + { .n = "hsmc_clk", .p = "mck1", .id = 21, }, + { .n = "xdmac0_clk", .p = "mck1", .id = 22, }, + { .n = "xdmac1_clk", .p = "mck1", .id = 23, }, + { .n = "xdmac2_clk", .p = "mck1", .id = 24, }, + { .n = "acc_clk", .p = "mck1", .id = 25, }, + { .n = "aes_clk", .p = "mck1", .id = 27, }, + { .n = "tzaesbasc_clk", .p = "mck1", .id = 28, }, + { .n = "asrc_clk", .p = "mck1", .id = 30, .r = { .max = 200000000, }, }, + { .n = "cpkcc_clk", .p = "mck0", .id = 32, }, + { .n = "csi_clk", .p = "mck3", .id = 33, .r = { .max = 266000000, }, }, + { .n = "csi2dc_clk", .p = "mck3", .id = 34, .r = { .max = 266000000, }, }, + { .n = "eic_clk", .p = "mck1", .id = 37, }, + { .n = "flex0_clk", .p = "mck1", .id = 38, }, + { .n = "flex1_clk", .p = "mck1", .id = 39, }, + { .n = "flex2_clk", .p = "mck1", .id = 40, }, + { .n = "flex3_clk", .p = "mck1", .id = 41, }, + { .n = "flex4_clk", .p = "mck1", .id = 42, }, + { .n = "flex5_clk", .p = "mck1", .id = 43, }, + { .n = "flex6_clk", .p = "mck1", .id = 44, }, + { .n = "flex7_clk", .p = "mck1", .id = 45, }, + { .n = "flex8_clk", .p = "mck1", .id = 46, }, + { .n = "flex9_clk", .p = "mck1", .id = 47, }, + { .n = "flex10_clk", .p = "mck1", .id = 48, }, + { .n = "flex11_clk", .p = "mck1", .id = 49, }, + { .n = "gmac0_clk", .p = "mck1", .id = 51, }, + { .n = "gmac1_clk", .p = "mck1", .id = 52, }, + { .n = "gmac0_tsu_clk", .p = "mck1", .id = 53, }, + { .n = "gmac1_tsu_clk", .p = "mck1", .id = 54, }, + { .n = "icm_clk", .p = "mck1", .id = 55, }, + { .n = "isc_clk", .p = "mck3", .id = 56, .r = { .max = 266000000, }, }, + { .n = "i2smcc0_clk", .p = "mck1", .id = 57, .r = { .max = 200000000, }, }, + { .n = "i2smcc1_clk", .p = "mck1", .id = 58, .r = { .max = 200000000, }, }, + { .n = "matrix_clk", .p = "mck1", .id = 60, }, + { .n = "mcan0_clk", .p = "mck1", .id = 61, .r = { .max = 200000000, }, }, + { .n = "mcan1_clk", .p = "mck1", .id = 62, .r = { .max = 200000000, }, }, + { .n = "mcan2_clk", .p = "mck1", .id = 63, .r = { .max = 200000000, }, }, + { .n = "mcan3_clk", .p = "mck1", .id = 64, .r = { .max = 200000000, }, }, + { .n = "mcan4_clk", .p = "mck1", .id = 65, .r = { .max = 200000000, }, }, + { .n = "mcan5_clk", .p = "mck1", .id = 66, .r = { .max = 200000000, }, }, + { .n = "pdmc0_clk", .p = "mck1", .id = 68, .r = { .max = 200000000, }, }, + { .n = "pdmc1_clk", .p = "mck1", .id = 69, .r = { .max = 200000000, }, }, + { .n = "pit64b0_clk", .p = "mck1", .id = 70, }, + { .n = "pit64b1_clk", .p = "mck1", .id = 71, }, + { .n = "pit64b2_clk", .p = "mck1", .id = 72, }, + { .n = "pit64b3_clk", .p = "mck1", .id = 73, }, + { .n = "pit64b4_clk", .p = "mck1", .id = 74, }, + { .n = "pit64b5_clk", .p = "mck1", .id = 75, }, + { .n = "pwm_clk", .p = "mck1", .id = 77, }, + { .n = "qspi0_clk", .p = "mck1", .id = 78, }, + { .n = "qspi1_clk", .p = "mck1", .id = 79, }, + { .n = "sdmmc0_clk", .p = "mck1", .id = 80, }, + { .n = "sdmmc1_clk", .p = "mck1", .id = 81, }, + { .n = "sdmmc2_clk", .p = "mck1", .id = 82, }, + { .n = "sha_clk", .p = "mck1", .id = 83, }, + { .n = "spdifrx_clk", .p = "mck1", .id = 84, .r = { .max = 200000000, }, }, + { .n = "spdiftx_clk", .p = "mck1", .id = 85, .r = { .max = 200000000, }, }, + { .n = "ssc0_clk", .p = "mck1", .id = 86, .r = { .max = 200000000, }, }, + { .n = "ssc1_clk", .p = "mck1", .id = 87, .r = { .max = 200000000, }, }, + { .n = "tcb0_ch0_clk", .p = "mck1", .id = 88, .r = { .max = 200000000, }, }, + { .n = "tcb0_ch1_clk", .p = "mck1", .id = 89, .r = { .max = 200000000, }, }, + { .n = "tcb0_ch2_clk", .p = "mck1", .id = 90, .r = { .max = 200000000, }, }, + { .n = "tcb1_ch0_clk", .p = "mck1", .id = 91, .r = { .max = 200000000, }, }, + { .n = "tcb1_ch1_clk", .p = "mck1", .id = 92, .r = { .max = 200000000, }, }, + { .n = "tcb1_ch2_clk", .p = "mck1", .id = 93, .r = { .max = 200000000, }, }, + { .n = "tcpca_clk", .p = "mck1", .id = 94, }, + { .n = "tcpcb_clk", .p = "mck1", .id = 95, }, + { .n = "tdes_clk", .p = "mck1", .id = 96, }, + { .n = "trng_clk", .p = "mck1", .id = 97, }, + { .n = "udphsa_clk", .p = "mck1", .id = 104, }, + { .n = "udphsb_clk", .p = "mck1", .id = 105, }, + { .n = "uhphs_clk", .p = "mck1", .id = 106, }, +}; + +/** + * Generic clock description + * @n: clock name + * @ep: extra parents names + * @ep_mux_table: extra parents mux table + * @ep_clk_mux_table: extra parents clock mux table (for CCF) + * @r: clock output range + * @ep_count: extra parents count + * @id: clock id + */ +static const struct { + const char *n; + const char *ep[8]; + const char ep_mux_table[8]; + const char ep_clk_mux_table[8]; + struct clk_range r; + u8 ep_count; + u8 id; +} sama7g5_gck[] = { + { + .n = "adc_gclk", + .id = 26, + .r = { .max = 100000000, }, + .ep = { "syspll_divpmcck", "imgpll_divpmcck", "audiopll_divpmcck", }, + .ep_mux_table = { 5, 7, 9, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV, + ID_PLL_AUDIO_DIVPMC, }, + .ep_count = 3, + }, + + { + .n = "asrc_gclk", + .id = 30, + .r = { .max = 200000000 }, + .ep = { "audiopll_divpmcck", }, + .ep_mux_table = { 9, }, + .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, }, + .ep_count = 1, + }, + + { + .n = "csi_gclk", + .id = 33, + .r = { .max = 27000000 }, + .ep = { "ddrpll_divpmcck", "imgpll_divpmcck", }, + .ep_clk_mux_table = { ID_PLL_DDR_DIV, ID_PLL_IMG_DIV, }, + .ep_mux_table = { 6, 7, }, + .ep_count = 2, + }, + + { + .n = "flex0_gclk", + .id = 38, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "flex1_gclk", + .id = 39, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "flex2_gclk", + .id = 40, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "flex3_gclk", + .id = 41, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "flex4_gclk", + .id = 42, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "flex5_gclk", + .id = 43, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "flex6_gclk", + .id = 44, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "flex7_gclk", + .id = 45, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "flex8_gclk", + .id = 46, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "flex9_gclk", + .id = 47, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "flex10_gclk", + .id = 48, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "flex11_gclk", + .id = 49, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "gmac0_gclk", + .id = 51, + .r = { .max = 125000000 }, + .ep = { "ethpll_divpmcck", }, + .ep_clk_mux_table = { ID_PLL_ETH_DIV, }, + .ep_mux_table = { 10, }, + .ep_count = 1, + }, + + { + .n = "gmac1_gclk", + .id = 52, + .r = { .max = 50000000 }, + .ep = { "ethpll_divpmcck", }, + .ep_mux_table = { 10, }, + .ep_clk_mux_table = { ID_PLL_ETH_DIV, }, + .ep_count = 1, + }, + + { + .n = "gmac0_tsu_gclk", + .id = 53, + .r = { .max = 300000000 }, + .ep = { "audiopll_divpmcck", "ethpll_divpmcck", }, + .ep_mux_table = { 9, 10, }, + .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_ETH_DIV, }, + .ep_count = 2, + }, + + { + .n = "gmac1_tsu_gclk", + .id = 54, + .r = { .max = 300000000 }, + .ep = { "audiopll_divpmcck", "ethpll_divpmcck", }, + .ep_mux_table = { 9, 10, }, + .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_ETH_DIV, }, + .ep_count = 2, + }, + + { + .n = "i2smcc0_gclk", + .id = 57, + .r = { .max = 100000000 }, + .ep = { "syspll_divpmcck", "audiopll_divpmcck", }, + .ep_mux_table = { 5, 9, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_AUDIO_DIVPMC, }, + .ep_count = 2, + }, + + { + .n = "i2smcc1_gclk", + .id = 58, + .r = { .max = 100000000 }, + .ep = { "syspll_divpmcck", "audiopll_divpmcck", }, + .ep_mux_table = { 5, 9, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_AUDIO_DIVPMC, }, + .ep_count = 2, + }, + + { + .n = "mcan0_gclk", + .id = 61, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "mcan1_gclk", + .id = 62, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "mcan2_gclk", + .id = 63, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "mcan3_gclk", + .id = 64, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "mcan4_gclk", + .id = 65, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "mcan5_gclk", + .id = 66, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "pdmc0_gclk", + .id = 68, + .r = { .max = 50000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "pdmc1_gclk", + .id = 69, + .r = { .max = 50000000, }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "pit64b0_gclk", + .id = 70, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", + "audiopll_divpmcck", "ethpll_divpmcck", }, + .ep_mux_table = { 5, 7, 8, 9, 10, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV, + ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC, + ID_PLL_ETH_DIV, }, + .ep_count = 5, + }, + + { + .n = "pit64b1_gclk", + .id = 71, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", + "audiopll_divpmcck", "ethpll_divpmcck", }, + .ep_mux_table = { 5, 7, 8, 9, 10, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV, + ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC, + ID_PLL_ETH_DIV, }, + .ep_count = 5, + }, + + { + .n = "pit64b2_gclk", + .id = 72, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", + "audiopll_divpmcck", "ethpll_divpmcck", }, + .ep_mux_table = { 5, 7, 8, 9, 10, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV, + ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC, + ID_PLL_ETH_DIV, }, + .ep_count = 5, + }, + + { + .n = "pit64b3_gclk", + .id = 73, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", + "audiopll_divpmcck", "ethpll_divpmcck", }, + .ep_mux_table = { 5, 7, 8, 9, 10, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV, + ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC, + ID_PLL_ETH_DIV, }, + .ep_count = 5, + }, + + { + .n = "pit64b4_gclk", + .id = 74, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", + "audiopll_divpmcck", "ethpll_divpmcck", }, + .ep_mux_table = { 5, 7, 8, 9, 10, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV, + ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC, + ID_PLL_ETH_DIV, }, + .ep_count = 5, + }, + + { + .n = "pit64b5_gclk", + .id = 75, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", + "audiopll_divpmcck", "ethpll_divpmcck", }, + .ep_mux_table = { 5, 7, 8, 9, 10, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV, + ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC, + ID_PLL_ETH_DIV, }, + .ep_count = 5, + }, + + { + .n = "qspi0_gclk", + .id = 78, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV, + ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC, + ID_PLL_ETH_DIV, }, + .ep_count = 2, + }, + + { + .n = "qspi1_gclk", + .id = 79, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "sdmmc0_gclk", + .id = 80, + .r = { .max = 208000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "sdmmc1_gclk", + .id = 81, + .r = { .max = 208000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "sdmmc2_gclk", + .id = 82, + .r = { .max = 208000000 }, + .ep = { "syspll_divpmcck", "baudpll_divpmcck", }, + .ep_mux_table = { 5, 8, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, }, + .ep_count = 2, + }, + + { + .n = "spdifrx_gclk", + .id = 84, + .r = { .max = 150000000 }, + .ep = { "syspll_divpmcck", "audiopll_divpmcck", }, + .ep_mux_table = { 5, 9, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_AUDIO_DIVPMC, }, + .ep_count = 2, + }, + + { + .n = "spdiftx_gclk", + .id = 85, + .r = { .max = 25000000 }, + .ep = { "syspll_divpmcck", "audiopll_divpmcck", }, + .ep_mux_table = { 5, 9, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_AUDIO_DIVPMC, }, + .ep_count = 2, + }, + + { + .n = "tcb0_ch0_gclk", + .id = 88, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", + "audiopll_divpmcck", "ethpll_divpmcck", }, + .ep_mux_table = { 5, 7, 8, 9, 10, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV, + ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC, + ID_PLL_ETH_DIV, }, + .ep_count = 5, + }, + + { + .n = "tcb1_ch0_gclk", + .id = 91, + .r = { .max = 200000000 }, + .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", + "audiopll_divpmcck", "ethpll_divpmcck", }, + .ep_mux_table = { 5, 7, 8, 9, 10, }, + .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV, + ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC, + ID_PLL_ETH_DIV, }, + .ep_count = 5, + }, +}; + +/** + * 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[] = { + { + .cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_ETH_FRAC), + .rate = 625000000, + }, + + { + .cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_ETH_DIV), + .rate = 625000000, + }, +}; + +#define SAMA7G5_MAX_MUX_ALLOCS (64) + +#define prepare_mux_table(_allocs, _index, _dst, _src, _num, _label) \ + do { \ + int _i; \ + if ((_index) >= SAMA7G5_MAX_MUX_ALLOCS) { \ + debug("%s(): AT91: MUX: insufficient space\n", \ + __func__); \ + goto _label; \ + } \ + (_dst) = kzalloc(sizeof(*(_dst)) * (_num), GFP_KERNEL); \ + if (!(_dst)) \ + goto _label; \ + (_allocs)[(_index)++] = (_dst); \ + for (_i = 0; _i < (_num); _i++) \ + (_dst)[_i] = (_src)[_i]; \ + } while (0) + +static int sama7g5_clk_probe(struct udevice *dev) +{ + void __iomem *base = (void *)devfdt_get_addr(dev); + unsigned int *clkmuxallocs[SAMA7G5_MAX_MUX_ALLOCS]; + unsigned int *muxallocs[SAMA7G5_MAX_MUX_ALLOCS]; + const char *p[10]; + unsigned int cm[10], m[10], *tmpclkmux, *tmpmux; + struct clk clk, *c, *parent; + bool main_osc_bypass; + int ret, muxallocindex = 0, clkmuxallocindex = 0, i, j; + + if (IS_ERR(base)) + return PTR_ERR(base); + + memset(muxallocs, 0, ARRAY_SIZE(muxallocs)); + memset(clkmuxallocs, 0, ARRAY_SIZE(clkmuxallocs)); + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + ret = clk_get_by_id(clk.id, &c); + if (ret) + return ret; + clk_names[ID_TD_SLCK] = kmemdup(clk_hw_get_name(c), + strlen(clk_hw_get_name(c)) + 1, GFP_KERNEL); + if (!clk_names[ID_TD_SLCK]) + return -ENOMEM; + + ret = clk_get_by_index(dev, 1, &clk); + if (ret) + return ret; + ret = clk_get_by_id(clk.id, &c); + if (ret) + return ret; + clk_names[ID_MD_SLCK] = kmemdup(clk_hw_get_name(c), + strlen(clk_hw_get_name(c)) + 1, GFP_KERNEL); + if (!clk_names[ID_MD_SLCK]) + return -ENOMEM; + + ret = clk_get_by_index(dev, 2, &clk); + if (ret) + return ret; + clk_names[ID_MAIN_XTAL] = kmemdup(clk_hw_get_name(&clk), + strlen(clk_hw_get_name(&clk)) + 1, GFP_KERNEL); + if (!clk_names[ID_MAIN_XTAL]) + return -ENOMEM; + + ret = clk_get_by_index(dev, 3, &clk); + if (ret) + goto fail; + clk_names[ID_MAIN_RC] = kmemdup(clk_hw_get_name(&clk), + strlen(clk_hw_get_name(&clk)) + 1, GFP_KERNEL); + if (ret) + goto fail; + + main_osc_bypass = dev_read_bool(dev, "atmel,main-osc-bypass"); + + /* Register main rc oscillator. */ + clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_RC_OSC), + at91_clk_main_rc(base, clk_names[ID_MAIN_RC_OSC], + clk_names[ID_MAIN_RC])); + + /* Register main oscillator. */ + clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_OSC), + at91_clk_main_osc(base, clk_names[ID_MAIN_OSC], + clk_names[ID_MAIN_XTAL], main_osc_bypass)); + + /* Register mainck. */ + p[0] = clk_names[ID_MAIN_RC_OSC]; + p[1] = clk_names[ID_MAIN_OSC]; + cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_RC_OSC); + cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_OSC); + prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm, 2, + fail); + clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK), + at91_clk_sam9x5_main(base, clk_names[ID_MAINCK], p, + 2, tmpclkmux, PMC_TYPE_CORE)); + + /* Register PLL fracs clocks. */ + for (i = 0; i < ARRAY_SIZE(sama7g5_plls); i++) { + if (sama7g5_plls[i].t != PLL_TYPE_FRAC) + continue; + + clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sama7g5_plls[i].cid), + sam9x60_clk_register_frac_pll(base, sama7g5_plls[i].n, + sama7g5_plls[i].p, sama7g5_plls[i].id, + &pll_characteristics, sama7g5_plls[i].l, + sama7g5_plls[i].c)); + } + + /* Register PLL div clocks. */ + for (i = 0; i < ARRAY_SIZE(sama7g5_plls); i++) { + if (sama7g5_plls[i].t != PLL_TYPE_DIV) + continue; + + clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sama7g5_plls[i].cid), + sam9x60_clk_register_div_pll(base, sama7g5_plls[i].n, + sama7g5_plls[i].p, sama7g5_plls[i].id, + &pll_characteristics, sama7g5_plls[i].l, + sama7g5_plls[i].c)); + } + + /* Register MCK0 clock. */ + p[0] = clk_names[ID_MD_SLCK]; + p[1] = clk_names[ID_MAINCK]; + p[2] = clk_names[ID_PLL_CPU_DIV]; + p[3] = clk_names[ID_PLL_SYS_DIV]; + cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK); + cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK); + cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_CPU_DIV); + cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_SYS_DIV); + prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm, 2, + fail); + clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK0), + at91_clk_register_master(base, clk_names[ID_MCK0], p, + 4, &mck0_layout, &mck0_characteristics, tmpclkmux)); + + /* Register MCK1-4 clocks. */ + p[0] = clk_names[ID_MD_SLCK]; + p[1] = clk_names[ID_TD_SLCK]; + p[2] = clk_names[ID_MAINCK]; + p[3] = clk_names[ID_MCK0]; + m[0] = 0; + m[1] = 1; + m[2] = 2; + m[3] = 3; + cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK); + cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_TD_SLCK); + cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK); + cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK0); + for (i = 0; i < ARRAY_SIZE(sama7g5_mckx); i++) { + for (j = 0; j < sama7g5_mckx[i].ep_count; j++) { + p[4 + j] = sama7g5_mckx[i].ep[j]; + m[4 + j] = sama7g5_mckx[i].ep_mux_table[j]; + cm[4 + j] = AT91_TO_CLK_ID(PMC_TYPE_CORE, + sama7g5_mckx[i].ep_clk_mux_table[j]); + } + + prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm, + 4 + sama7g5_mckx[i].ep_count, fail); + prepare_mux_table(muxallocs, muxallocindex, tmpmux, m, + 4 + sama7g5_mckx[i].ep_count, fail); + + clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sama7g5_mckx[i].cid), + at91_clk_sama7g5_register_master(base, + sama7g5_mckx[i].n, p, 4 + sama7g5_mckx[i].ep_count, + tmpmux, tmpclkmux, sama7g5_mckx[i].c, + sama7g5_mckx[i].id)); + } + + /* Register UTMI clock. */ + clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_UTMI), + at91_clk_sama7g5_register_utmi(base, "utmick", + clk_names[ID_MAIN_XTAL])); + + /* Register programmable clocks. */ + p[0] = clk_names[ID_MD_SLCK]; + p[1] = clk_names[ID_TD_SLCK]; + p[2] = clk_names[ID_MAINCK]; + p[3] = clk_names[ID_MCK0]; + p[4] = clk_names[ID_PLL_SYS_DIV]; + p[5] = clk_names[ID_PLL_DDR_DIV]; + p[6] = clk_names[ID_PLL_IMG_DIV]; + p[7] = clk_names[ID_PLL_BAUD_DIV]; + p[8] = clk_names[ID_PLL_AUDIO_DIVPMC]; + p[9] = clk_names[ID_PLL_ETH_DIV]; + cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK); + cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_TD_SLCK); + cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK); + cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK0); + cm[4] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_SYS_DIV); + cm[5] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_DDR_DIV); + cm[6] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_IMG_DIV); + cm[7] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_BAUD_DIV); + cm[8] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_AUDIO_DIVPMC); + cm[9] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_ETH_DIV); + for (i = 0; i < ARRAY_SIZE(sama7g5_prog); i++) { + prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm, + 10, fail); + + clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sama7g5_prog[i].cid), + at91_clk_register_programmable(base, sama7g5_prog[i].n, + p, 10, i, &programmable_layout, tmpclkmux, + sama7g5_prog_mux_table)); + } + + /* System clocks. */ + for (i = 0; i < ARRAY_SIZE(sama7g5_systemck); i++) { + clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SYSTEM, sama7g5_systemck[i].cid), + at91_clk_register_system(base, sama7g5_systemck[i].n, + sama7g5_systemck[i].p, sama7g5_systemck[i].id)); + } + + /* Peripheral clocks. */ + for (i = 0; i < ARRAY_SIZE(sama7g5_periphck); i++) { + clk_dm(AT91_TO_CLK_ID(PMC_TYPE_PERIPHERAL, + sama7g5_periphck[i].id), + at91_clk_register_sam9x5_peripheral(base, + &sama7g5_pcr_layout, sama7g5_periphck[i].n, + sama7g5_periphck[i].p, sama7g5_periphck[i].id, + &sama7g5_periphck[i].r)); + } + + /* Generic clocks. */ + p[0] = clk_names[ID_MD_SLCK]; + p[1] = clk_names[ID_TD_SLCK]; + p[2] = clk_names[ID_MAINCK]; + p[3] = clk_names[ID_MCK0]; + m[0] = 0; + m[1] = 1; + m[2] = 2; + m[3] = 3; + cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK); + cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_TD_SLCK); + cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK); + cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK0); + for (i = 0; i < ARRAY_SIZE(sama7g5_gck); i++) { + for (j = 0; j < sama7g5_gck[i].ep_count; j++) { + p[4 + j] = sama7g5_gck[i].ep[j]; + m[4 + j] = sama7g5_gck[i].ep_mux_table[j]; + cm[4 + j] = AT91_TO_CLK_ID(PMC_TYPE_CORE, + sama7g5_gck[i].ep_clk_mux_table[j]); + } + + prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm, + 4 + sama7g5_gck[i].ep_count, fail); + prepare_mux_table(muxallocs, muxallocindex, tmpmux, m, + 4 + sama7g5_gck[i].ep_count, fail); + + clk_dm(AT91_TO_CLK_ID(PMC_TYPE_GCK, sama7g5_gck[i].id), + at91_clk_register_generic(base, &sama7g5_pcr_layout, + sama7g5_gck[i].n, p, tmpclkmux, tmpmux, + 4 + sama7g5_gck[i].ep_count, sama7g5_gck[i].id, + &sama7g5_gck[i].r)); + } + + /* 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; + } + } + + return 0; + +fail: + for (i = 0; i < ARRAY_SIZE(muxallocs); i++) + kfree(muxallocs[i]); + + for (i = 0; i < ARRAY_SIZE(clkmuxallocs); i++) + kfree(clkmuxallocs[i]); + + return -ENOMEM; +} + +static const struct udevice_id sama7g5_clk_ids[] = { + { .compatible = "microchip,sama7g5-pmc" }, + { /* Sentinel. */ }, +}; + +U_BOOT_DRIVER(at91_sama7g5_pmc) = { + .name = "at91-sama7g5-pmc", + .id = UCLASS_CLK, + .of_match = sama7g5_clk_ids, + .ops = &at91_clk_ops, + .probe = sama7g5_clk_probe, + .flags = DM_FLAG_PRE_RELOC, +}; From 68d3ec599edff1c7ead539820efbc2234fb965ed Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Wed, 5 Aug 2020 15:30:34 +0300 Subject: [PATCH 22/32] board: atmel: common: introduce at91_set_eth1addr for second interface We already have a function to retrieve the mac address from one EEPROM. For boards with a second Ethernet interface, however, we would require another EEPROM with a second unique MAC address. Introduce at91_set_eth1addr which will look for a second EEPROM and set the 'eth1addr' variable with the obtained MAC address. Signed-off-by: Eugen Hristev --- arch/arm/mach-at91/include/mach/at91_common.h | 1 + board/atmel/common/mac_eeprom.c | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/arch/arm/mach-at91/include/mach/at91_common.h b/arch/arm/mach-at91/include/mach/at91_common.h index 01e00c508a..f7b411cf7d 100644 --- a/arch/arm/mach-at91/include/mach/at91_common.h +++ b/arch/arm/mach-at91/include/mach/at91_common.h @@ -40,6 +40,7 @@ void configure_ddrcfg_input_buffers(bool open); #endif int at91_set_ethaddr(int offset); +int at91_set_eth1addr(int offset); void at91_spi_nor_set_ethaddr(void); int at91_video_show_board_info(void); diff --git a/board/atmel/common/mac_eeprom.c b/board/atmel/common/mac_eeprom.c index 2205dd30f8..a723ba723c 100644 --- a/board/atmel/common/mac_eeprom.c +++ b/board/atmel/common/mac_eeprom.c @@ -36,3 +36,36 @@ int at91_set_ethaddr(int offset) return 0; } + +/* this function will set eth1addr from a second eeprom, if available */ +int at91_set_eth1addr(int offset) +{ + const int ETH_ADDR_LEN = 6; + unsigned char ethaddr[ETH_ADDR_LEN]; + /* configure eth1addr for second interface */ + const char *ETHADDR_NAME = "eth1addr"; + struct udevice *dev; + int ret; + + if (env_get(ETHADDR_NAME)) + return 0; + + /* first eeprom is retrieved, this is for the first interface */ + ret = uclass_first_device_err(UCLASS_I2C_EEPROM, &dev); + if (ret) + return ret; + + /* attempt to obtain a second eeprom device */ + ret = uclass_next_device(&dev); + if (ret) + return ret; + + ret = i2c_eeprom_read(dev, offset, ethaddr, 6); + if (ret) + return ret; + + if (is_valid_ethaddr(ethaddr)) + eth_env_set_enetaddr(ETHADDR_NAME, ethaddr); + + return 0; +} From 919c4f3639dba6e516591e8024a9392254744635 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 20 Aug 2020 16:11:52 +0300 Subject: [PATCH 23/32] ARM: at91: common: guard ATMEL_PIT code by ifdef Atmel PIT timer is not available for next products that have another timer hardware block. To be able to use the common at91 code, guard the code that uses PIT by ifdefs. Signed-off-by: Eugen Hristev --- arch/arm/mach-at91/armv7/cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-at91/armv7/cpu.c b/arch/arm/mach-at91/armv7/cpu.c index a8f4356ce9..8b7355042b 100644 --- a/arch/arm/mach-at91/armv7/cpu.c +++ b/arch/arm/mach-at91/armv7/cpu.c @@ -29,6 +29,7 @@ int arch_cpu_init(void) void arch_preboot_os(void) { +#if (IS_ENABLED(CONFIG_ATMEL_PIT_TIMER)) ulong cpiv; at91_pit_t *pit = (at91_pit_t *)ATMEL_BASE_PIT; @@ -40,6 +41,7 @@ void arch_preboot_os(void) * without waiting for wrapping back to 0 */ writel(cpiv + 0x1000, &pit->mr); +#endif } #if defined(CONFIG_DISPLAY_CPUINFO) From 558378a4cdd822958503752e8096f5e4fc447be7 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 27 Aug 2020 11:51:52 +0300 Subject: [PATCH 24/32] ARM: mach-at91: add support for new SoC sama7g5 Add support for new SoC sama7g5 Signed-off-by: Eugen Hristev --- arch/arm/dts/sama7g5-pinfunc.h | 924 +++++++++++++++++++++ arch/arm/mach-at91/Kconfig | 4 + arch/arm/mach-at91/armv7/Makefile | 1 + arch/arm/mach-at91/armv7/sama7g5_devices.c | 11 + arch/arm/mach-at91/include/mach/hardware.h | 2 + arch/arm/mach-at91/include/mach/sama7g5.h | 74 ++ 6 files changed, 1016 insertions(+) create mode 100644 arch/arm/dts/sama7g5-pinfunc.h create mode 100644 arch/arm/mach-at91/armv7/sama7g5_devices.c create mode 100644 arch/arm/mach-at91/include/mach/sama7g5.h diff --git a/arch/arm/dts/sama7g5-pinfunc.h b/arch/arm/dts/sama7g5-pinfunc.h new file mode 100644 index 0000000000..89293e5470 --- /dev/null +++ b/arch/arm/dts/sama7g5-pinfunc.h @@ -0,0 +1,924 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#define PINMUX_PIN(no, func, ioset) \ +(((no) & 0xffff) | (((func) & 0xf) << 16) | (((ioset) & 0xff) << 20)) + +#define PIN_PA0 0 +#define PIN_PA0__GPIO PINMUX_PIN(PIN_PA0, 0, 0) +#define PIN_PA0__SDMMC0_CK PINMUX_PIN(PIN_PA0, 1, 1) +#define PIN_PA0__FLEXCOM0_IO0 PINMUX_PIN(PIN_PA0, 2, 1) +#define PIN_PA0__CANTX3 PINMUX_PIN(PIN_PA0, 3, 1) +#define PIN_PA0__PWML0 PINMUX_PIN(PIN_PA0, 5, 2) +#define PIN_PA1 1 +#define PIN_PA1__GPIO PINMUX_PIN(PIN_PA1, 0, 0) +#define PIN_PA1__SDMMC0_CMD PINMUX_PIN(PIN_PA1, 1, 1) +#define PIN_PA1__FLEXCOM0_IO1 PINMUX_PIN(PIN_PA1, 2, 1) +#define PIN_PA1__CANRX3 PINMUX_PIN(PIN_PA1, 3, 1) +#define PIN_PA1__D14 PINMUX_PIN(PIN_PA1, 4, 1) +#define PIN_PA1__PWMH0 PINMUX_PIN(PIN_PA1, 5, 3) +#define PIN_PA2 2 +#define PIN_PA2__GPIO PINMUX_PIN(PIN_PA2, 0, 0) +#define PIN_PA2__SDMMC0_RSTN PINMUX_PIN(PIN_PA2, 1, 1) +#define PIN_PA2__FLEXCOM0_IO2 PINMUX_PIN(PIN_PA2, 2, 1) +#define PIN_PA2__PDMC1_CLK PINMUX_PIN(PIN_PA2, 3, 1) +#define PIN_PA2__D15 PINMUX_PIN(PIN_PA2, 4, 1) +#define PIN_PA2__PWMH1 PINMUX_PIN(PIN_PA2, 5, 3) +#define PIN_PA2__FLEXCOM1_IO0 PINMUX_PIN(PIN_PA2, 6, 3) +#define PIN_PA3 3 +#define PIN_PA3__GPIO PINMUX_PIN(PIN_PA3, 0, 0) +#define PIN_PA3__SDMMC0_DAT0 PINMUX_PIN(PIN_PA3, 1, 1) +#define PIN_PA3__FLEXCOM0_IO3 PINMUX_PIN(PIN_PA3, 2, 1) +#define PIN_PA3__PDMC1_DS0 PINMUX_PIN(PIN_PA3, 3, 1) +#define PIN_PA3__NWR1_NBS1 PINMUX_PIN(PIN_PA3, 4, 1) +#define PIN_PA3__PWML3 PINMUX_PIN(PIN_PA3, 5, 3) +#define PIN_PA3__FLEXCOM1_IO1 PINMUX_PIN(PIN_PA3, 6, 3) +#define PIN_PA4 4 +#define PIN_PA4__GPIO PINMUX_PIN(PIN_PA4, 0, 0) +#define PIN_PA4__SDMMC0_DAT1 PINMUX_PIN(PIN_PA4, 1, 1) +#define PIN_PA4__FLEXCOM0_IO4 PINMUX_PIN(PIN_PA4, 2, 1) +#define PIN_PA4__PDMC1_DS1 PINMUX_PIN(PIN_PA4, 3, 1) +#define PIN_PA4__NCS2 PINMUX_PIN(PIN_PA4, 4, 1) +#define PIN_PA4__PWMH3 PINMUX_PIN(PIN_PA4, 5, 3) +#define PIN_PA4__FLEXCOM2_IO0 PINMUX_PIN(PIN_PA4, 6, 3) +#define PIN_PA5 5 +#define PIN_PA5__GPIO PINMUX_PIN(PIN_PA5, 0, 0) +#define PIN_PA5__SDMMC0_DAT2 PINMUX_PIN(PIN_PA5, 1, 1) +#define PIN_PA5__FLEXCOM1_IO0 PINMUX_PIN(PIN_PA5, 2, 1) +#define PIN_PA5__CANTX2 PINMUX_PIN(PIN_PA5, 3, 1) +#define PIN_PA5__A23 PINMUX_PIN(PIN_PA5, 4, 1) +#define PIN_PA5__PWMEXTRG0 PINMUX_PIN(PIN_PA5, 5, 3) +#define PIN_PA5__FLEXCOM2_IO1 PINMUX_PIN(PIN_PA5, 6, 3) +#define PIN_PA6 6 +#define PIN_PA6__GPIO PINMUX_PIN(PIN_PA6, 0, 0) +#define PIN_PA6__SDMMC0_DAT3 PINMUX_PIN(PIN_PA6, 1, 1) +#define PIN_PA6__FLEXCOM1_IO1 PINMUX_PIN(PIN_PA6, 2, 1) +#define PIN_PA6__CANRX2 PINMUX_PIN(PIN_PA6, 3, 1) +#define PIN_PA6__A24 PINMUX_PIN(PIN_PA6, 4, 1) +#define PIN_PA6__PWMEXTRG1 PINMUX_PIN(PIN_PA6, 5, 3) +#define PIN_PA6__FLEXCOM3_IO0 PINMUX_PIN(PIN_PA6, 6, 3) +#define PIN_PA7 7 +#define PIN_PA7__GPIO PINMUX_PIN(PIN_PA7, 0, 0) +#define PIN_PA7__SDMMC0_DAT4 PINMUX_PIN(PIN_PA7, 1, 1) +#define PIN_PA7__FLEXCOM2_IO0 PINMUX_PIN(PIN_PA7, 2, 1) +#define PIN_PA7__CANTX1 PINMUX_PIN(PIN_PA7, 3, 1) +#define PIN_PA7__NWAIT PINMUX_PIN(PIN_PA7, 4, 1) +#define PIN_PA7__PWMFI0 PINMUX_PIN(PIN_PA7, 5, 3) +#define PIN_PA7__FLEXCOM3_IO1 PINMUX_PIN(PIN_PA7, 6, 3) +#define PIN_PA8 8 +#define PIN_PA8__GPIO PINMUX_PIN(PIN_PA8, 0, 0) +#define PIN_PA8__SDMMC0_DAT5 PINMUX_PIN(PIN_PA8, 1, 1) +#define PIN_PA8__FLEXCOM2_IO1 PINMUX_PIN(PIN_PA8, 2, 1) +#define PIN_PA8__CANRX1 PINMUX_PIN(PIN_PA8, 3, 1) +#define PIN_PA8__NCS0 PINMUX_PIN(PIN_PA8, 4, 1) +#define PIN_PA8__PWMIF1 PINMUX_PIN(PIN_PA8, 5, 3) +#define PIN_PA8__FLEXCOM4_IO0 PINMUX_PIN(PIN_PA8, 6, 3) +#define PIN_PA9 9 +#define PIN_PA9__GPIO PINMUX_PIN(PIN_PA9, 0, 0) +#define PIN_PA9__SDMMC0_DAT6 PINMUX_PIN(PIN_PA9, 1, 1) +#define PIN_PA9__FLEXCOM2_IO2 PINMUX_PIN(PIN_PA9, 2, 1) +#define PIN_PA9__CANTX0 PINMUX_PIN(PIN_PA9, 3, 1) +#define PIN_PA9__SMCK PINMUX_PIN(PIN_PA9, 4, 1) +#define PIN_PA9__SPDIF_RX PINMUX_PIN(PIN_PA9, 5, 1) +#define PIN_PA9__FLEXCOM4_IO1 PINMUX_PIN(PIN_PA9, 6, 3) +#define PIN_PA10 10 +#define PIN_PA10__GPIO PINMUX_PIN(PIN_PA10, 0, 0) +#define PIN_PA10__SDMMC0_DAT7 PINMUX_PIN(PIN_PA10, 1, 1) +#define PIN_PA10__FLEXCOM2_IO3 PINMUX_PIN(PIN_PA10, 2, 1) +#define PIN_PA10__CANRX0 PINMUX_PIN(PIN_PA10, 3, 1) +#define PIN_PA10__NCS1 PINMUX_PIN(PIN_PA10, 4, 1) +#define PIN_PA10__SPDIF_TX PINMUX_PIN(PIN_PA10, 5, 1) +#define PIN_PA10__FLEXCOM5_IO0 PINMUX_PIN(PIN_PA10, 6, 3) +#define PIN_PA11 11 +#define PIN_PA11__GPIO PINMUX_PIN(PIN_PA11, 0, 0) +#define PIN_PA11__SDMMC0_DS PINMUX_PIN(PIN_PA11, 1, 1) +#define PIN_PA11__FLEXCOM2_IO4 PINMUX_PIN(PIN_PA11, 2, 1) +#define PIN_PA11__A0_NBS0 PINMUX_PIN(PIN_PA11, 4, 1) +#define PIN_PA11__TIOA0 PINMUX_PIN(PIN_PA11, 5, 1) +#define PIN_PA11__FLEXCOM5_IO1 PINMUX_PIN(PIN_PA11, 6, 3) +#define PIN_PA12 12 +#define PIN_PA12__GPIO PINMUX_PIN(PIN_PA12, 0, 0) +#define PIN_PA12__SDMMC0_WP PINMUX_PIN(PIN_PA12, 1, 1) +#define PIN_PA12__FLEXCOM1_IO3 PINMUX_PIN(PIN_PA12, 2, 1) +#define PIN_PA12__FLEXCOM3_IO5 PINMUX_PIN(PIN_PA12, 4, 1) +#define PIN_PA12__PWML2 PINMUX_PIN(PIN_PA12, 5, 3) +#define PIN_PA12__FLEXCOM6_IO0 PINMUX_PIN(PIN_PA12, 6, 3) +#define PIN_PA13 13 +#define PIN_PA13__GPIO PINMUX_PIN(PIN_PA13, 0, 0) +#define PIN_PA13__SDMMC0_1V8SEL PINMUX_PIN(PIN_PA13, 1, 1) +#define PIN_PA13__FLEXCOM1_IO2 PINMUX_PIN(PIN_PA13, 2, 1) +#define PIN_PA13__FLEXCOM3_IO6 PINMUX_PIN(PIN_PA13, 4, 1) +#define PIN_PA13__PWMH2 PINMUX_PIN(PIN_PA13, 5, 3) +#define PIN_PA13__FLEXCOM6_IO1 PINMUX_PIN(PIN_PA13, 6, 3) +#define PIN_PA14 14 +#define PIN_PA14__GPIO PINMUX_PIN(PIN_PA14, 0, 0) +#define PIN_PA14__SDMMC0_CD PINMUX_PIN(PIN_PA14, 1, 1) +#define PIN_PA14__FLEXCOM1_IO4 PINMUX_PIN(PIN_PA14, 2, 1) +#define PIN_PA14__A25 PINMUX_PIN(PIN_PA14, 4, 1) +#define PIN_PA14__PWML1 PINMUX_PIN(PIN_PA14, 5, 3) +#define PIN_PA15 15 +#define PIN_PA15__GPIO PINMUX_PIN(PIN_PA15, 0, 0) +#define PIN_PA15__G0_TXEN PINMUX_PIN(PIN_PA15, 1, 1) +#define PIN_PA15__FLEXCOM3_IO0 PINMUX_PIN(PIN_PA15, 2, 1) +#define PIN_PA15__ISC_MCK PINMUX_PIN(PIN_PA15, 3, 1) +#define PIN_PA15__A1 PINMUX_PIN(PIN_PA15, 4, 1) +#define PIN_PA15__TIOB0 PINMUX_PIN(PIN_PA15, 5, 1) +#define PIN_PA16 16 +#define PIN_PA16__GPIO PINMUX_PIN(PIN_PA16, 0, 0) +#define PIN_PA16__G0_TX0 PINMUX_PIN(PIN_PA16, 1, 1) +#define PIN_PA16__FLEXCOM3_IO1 PINMUX_PIN(PIN_PA16, 2, 1) +#define PIN_PA16__ISC_D0 PINMUX_PIN(PIN_PA16, 3, 1) +#define PIN_PA16__A2 PINMUX_PIN(PIN_PA16, 4, 1) +#define PIN_PA16__TCLK0 PINMUX_PIN(PIN_PA16, 5, 1) +#define PIN_PA17 17 +#define PIN_PA17__GPIO PINMUX_PIN(PIN_PA17, 0, 0) +#define PIN_PA17__G0_TX1 PINMUX_PIN(PIN_PA17, 1, 1) +#define PIN_PA17__FLEXCOM3_IO2 PINMUX_PIN(PIN_PA17, 2, 1) +#define PIN_PA17__ISC_D1 PINMUX_PIN(PIN_PA17, 3, 1) +#define PIN_PA17__A3 PINMUX_PIN(PIN_PA17, 4, 1) +#define PIN_PA17__TIOA1 PINMUX_PIN(PIN_PA17, 5, 1) +#define PIN_PA18 18 +#define PIN_PA18__GPIO PINMUX_PIN(PIN_PA18, 0, 0) +#define PIN_PA18__G0_RXDV PINMUX_PIN(PIN_PA18, 1, 1) +#define PIN_PA18__FLEXCOM3_IO3 PINMUX_PIN(PIN_PA18, 2, 1) +#define PIN_PA18__ISC_D2 PINMUX_PIN(PIN_PA18, 3, 1) +#define PIN_PA18__A4 PINMUX_PIN(PIN_PA18, 4, 1) +#define PIN_PA18__TIOB1 PINMUX_PIN(PIN_PA18, 5, 1) +#define PIN_PA19 19 +#define PIN_PA19__GPIO PINMUX_PIN(PIN_PA19, 0, 0) +#define PIN_PA19__G0_RX0 PINMUX_PIN(PIN_PA19, 1, 1) +#define PIN_PA19__FLEXCOM3_IO4 PINMUX_PIN(PIN_PA19, 2, 1) +#define PIN_PA19__ISC_D3 PINMUX_PIN(PIN_PA19, 3, 1) +#define PIN_PA19__A5 PINMUX_PIN(PIN_PA19, 4, 1) +#define PIN_PA19__TCLK1 PINMUX_PIN(PIN_PA19, 5, 1) +#define PIN_PA20 20 +#define PIN_PA20__GPIO PINMUX_PIN(PIN_PA20, 0, 0) +#define PIN_PA20__G0_RX1 PINMUX_PIN(PIN_PA20, 1, 1) +#define PIN_PA20__FLEXCOM4_IO0 PINMUX_PIN(PIN_PA20, 2, 1) +#define PIN_PA20__ISC_D4 PINMUX_PIN(PIN_PA20, 3, 1) +#define PIN_PA20__A6 PINMUX_PIN(PIN_PA20, 4, 1) +#define PIN_PA20__TIOA2 PINMUX_PIN(PIN_PA20, 5, 1) +#define PIN_PA21 21 +#define PIN_PA21__GPIO PINMUX_PIN(PIN_PA21, 0, 0) +#define PIN_PA21__G0_RXER PINMUX_PIN(PIN_PA21, 1, 1) +#define PIN_PA21__FLEXCOM4_IO1 PINMUX_PIN(PIN_PA21, 2, 1) +#define PIN_PA21__ISC_D5 PINMUX_PIN(PIN_PA21, 3, 1) +#define PIN_PA21__A7 PINMUX_PIN(PIN_PA21, 4, 1) +#define PIN_PA21__TIOB2 PINMUX_PIN(PIN_PA21, 5, 1) +#define PIN_PA22 22 +#define PIN_PA22__GPIO PINMUX_PIN(PIN_PA22, 0, 0) +#define PIN_PA22__G0_MDC PINMUX_PIN(PIN_PA22, 1, 1) +#define PIN_PA22__FLEXCOM4_IO2 PINMUX_PIN(PIN_PA22, 2, 1) +#define PIN_PA22__ISC_D6 PINMUX_PIN(PIN_PA22, 3, 1) +#define PIN_PA22__A8 PINMUX_PIN(PIN_PA22, 4, 1) +#define PIN_PA22__TCLK2 PINMUX_PIN(PIN_PA22, 5, 1) +#define PIN_PA23 23 +#define PIN_PA23__GPIO PINMUX_PIN(PIN_PA23, 0, 0) +#define PIN_PA23__G0_MDIO PINMUX_PIN(PIN_PA23, 1, 1) +#define PIN_PA23__FLEXCOM4_IO3 PINMUX_PIN(PIN_PA23, 2, 1) +#define PIN_PA23__ISC_D7 PINMUX_PIN(PIN_PA23, 3, 1) +#define PIN_PA23__A9 PINMUX_PIN(PIN_PA23, 4, 1) +#define PIN_PA24 24 +#define PIN_PA24__GPIO PINMUX_PIN(PIN_PA24, 0, 0) +#define PIN_PA24__G0_TXCK PINMUX_PIN(PIN_PA24, 1, 1) +#define PIN_PA24__FLEXCOM4_IO4 PINMUX_PIN(PIN_PA24, 2, 1) +#define PIN_PA24__ISC_HSYNC PINMUX_PIN(PIN_PA24, 3, 1) +#define PIN_PA24__A10 PINMUX_PIN(PIN_PA24, 4, 1) +#define PIN_PA24__FLEXCOM0_IO5 PINMUX_PIN(PIN_PA24, 5, 1) +#define PIN_PA25 25 +#define PIN_PA25__GPIO PINMUX_PIN(PIN_PA25, 0, 0) +#define PIN_PA25__G0_125CK PINMUX_PIN(PIN_PA25, 1, 1) +#define PIN_PA25__FLEXCOM5_IO4 PINMUX_PIN(PIN_PA25, 2, 1) +#define PIN_PA25__ISC_VSYNC PINMUX_PIN(PIN_PA25, 3, 1) +#define PIN_PA25__A11 PINMUX_PIN(PIN_PA25, 4, 1) +#define PIN_PA25__FLEXCOM0_IO6 PINMUX_PIN(PIN_PA25, 5, 1) +#define PIN_PA25__FLEXCOM7_IO0 PINMUX_PIN(PIN_PA25, 6, 3) +#define PIN_PA26 26 +#define PIN_PA26__GPIO PINMUX_PIN(PIN_PA26, 0, 0) +#define PIN_PA26__G0_TX2 PINMUX_PIN(PIN_PA26, 1, 1) +#define PIN_PA26__FLEXCOM5_IO2 PINMUX_PIN(PIN_PA26, 2, 1) +#define PIN_PA26__ISC_FIELD PINMUX_PIN(PIN_PA26, 3, 1) +#define PIN_PA26__A12 PINMUX_PIN(PIN_PA26, 4, 1) +#define PIN_PA26__TF0 PINMUX_PIN(PIN_PA26, 5, 1) +#define PIN_PA26__FLEXCOM7_IO1 PINMUX_PIN(PIN_PA26, 6, 3) +#define PIN_PA27 27 +#define PIN_PA27__GPIO PINMUX_PIN(PIN_PA27, 0, 0) +#define PIN_PA27__G0_TX3 PINMUX_PIN(PIN_PA27, 1, 1) +#define PIN_PA27__FLEXCOM5_IO3 PINMUX_PIN(PIN_PA27, 2, 1) +#define PIN_PA27__ISC_PCK PINMUX_PIN(PIN_PA27, 3, 1) +#define PIN_PA27__A13 PINMUX_PIN(PIN_PA27, 4, 1) +#define PIN_PA27__TK0 PINMUX_PIN(PIN_PA27, 5, 1) +#define PIN_PA27__FLEXCOM8_IO0 PINMUX_PIN(PIN_PA27, 6, 3) +#define PIN_PA28 28 +#define PIN_PA28__GPIO PINMUX_PIN(PIN_PA28, 0, 0) +#define PIN_PA28__G0_RX2 PINMUX_PIN(PIN_PA28, 1, 1) +#define PIN_PA28__FLEXCOM5_IO0 PINMUX_PIN(PIN_PA28, 2, 1) +#define PIN_PA28__ISC_D8 PINMUX_PIN(PIN_PA28, 3, 1) +#define PIN_PA28__A14 PINMUX_PIN(PIN_PA28, 4, 1) +#define PIN_PA28__RD0 PINMUX_PIN(PIN_PA28, 5, 1) +#define PIN_PA28__FLEXCOM8_IO1 PINMUX_PIN(PIN_PA28, 6, 3) +#define PIN_PA29 29 +#define PIN_PA29__GPIO PINMUX_PIN(PIN_PA29, 0, 0) +#define PIN_PA29__G0_RX3 PINMUX_PIN(PIN_PA29, 1, 1) +#define PIN_PA29__FLEXCOM5_IO1 PINMUX_PIN(PIN_PA29, 2, 1) +#define PIN_PA29__ISC_D9 PINMUX_PIN(PIN_PA29, 3, 1) +#define PIN_PA29__A15 PINMUX_PIN(PIN_PA29, 4, 1) +#define PIN_PA29__RF0 PINMUX_PIN(PIN_PA29, 5, 1) +#define PIN_PA29__FLEXCOM9_IO0 PINMUX_PIN(PIN_PA29, 6, 3) +#define PIN_PA30 30 +#define PIN_PA30__GPIO PINMUX_PIN(PIN_PA30, 0, 0) +#define PIN_PA30__G0_RXCK PINMUX_PIN(PIN_PA30, 1, 1) +#define PIN_PA30__FLEXCOM6_IO4 PINMUX_PIN(PIN_PA30, 2, 1) +#define PIN_PA30__ISC_D10 PINMUX_PIN(PIN_PA30, 3, 1) +#define PIN_PA30__A16 PINMUX_PIN(PIN_PA30, 4, 1) +#define PIN_PA30__RK0 PINMUX_PIN(PIN_PA30, 5, 1) +#define PIN_PA30__FLEXCOM9_IO1 PINMUX_PIN(PIN_PA30, 6, 3) +#define PIN_PA31 31 +#define PIN_PA31__GPIO PINMUX_PIN(PIN_PA31, 0, 0) +#define PIN_PA31__G0_TXER PINMUX_PIN(PIN_PA31, 1, 1) +#define PIN_PA31__FLEXCOM6_IO2 PINMUX_PIN(PIN_PA31, 2, 1) +#define PIN_PA31__ISC_D11 PINMUX_PIN(PIN_PA31, 3, 1) +#define PIN_PA31__A17 PINMUX_PIN(PIN_PA31, 4, 1) +#define PIN_PA31__TD0 PINMUX_PIN(PIN_PA31, 5, 1) +#define PIN_PA31__FLEXCOM10_IO0 PINMUX_PIN(PIN_PA31, 6, 3) +#define PIN_PB0 32 +#define PIN_PB0__GPIO PINMUX_PIN(PIN_PB0, 0, 0) +#define PIN_PB0__G0_COL PINMUX_PIN(PIN_PB0, 1, 1) +#define PIN_PB0__FLEXCOM6_IO3 PINMUX_PIN(PIN_PB0, 2, 2) +#define PIN_PB0__EXT_IRQ0 PINMUX_PIN(PIN_PB0, 3, 1) +#define PIN_PB0__A18 PINMUX_PIN(PIN_PB0, 4, 1) +#define PIN_PB0__SPDIF_RX PINMUX_PIN(PIN_PB0, 5, 2) +#define PIN_PB0__FLEXCOM10_IO1 PINMUX_PIN(PIN_PB0, 6, 3) +#define PIN_PB1 33 +#define PIN_PB1__GPIO PINMUX_PIN(PIN_PB1, 0, 0) +#define PIN_PB1__G0_CRS PINMUX_PIN(PIN_PB1, 1, 1) +#define PIN_PB1__FLEXCOM6_IO1 PINMUX_PIN(PIN_PB1, 2, 2) +#define PIN_PB1__EXT_IRQ1 PINMUX_PIN(PIN_PB1, 3, 1) +#define PIN_PB1__A19 PINMUX_PIN(PIN_PB1, 4, 1) +#define PIN_PB1__SPDIF_TX PINMUX_PIN(PIN_PB1, 5, 2) +#define PIN_PB1__FLEXCOM11_IO0 PINMUX_PIN(PIN_PB1, 6, 3) +#define PIN_PB2 34 +#define PIN_PB2__GPIO PINMUX_PIN(PIN_PB2, 0, 0) +#define PIN_PB2__G0_TSUCOMP PINMUX_PIN(PIN_PB2, 1, 1) +#define PIN_PB2__FLEXCOM6_IO0 PINMUX_PIN(PIN_PB2, 2, 1) +#define PIN_PB2__ADTRG PINMUX_PIN(PIN_PB2, 3, 1) +#define PIN_PB2__A20 PINMUX_PIN(PIN_PB2, 4, 1) +#define PIN_PB2__FLEXCOM11_IO0 PINMUX_PIN(PIN_PB2, 6, 3) +#define PIN_PB3 35 +#define PIN_PB3__GPIO PINMUX_PIN(PIN_PB3, 0, 0) +#define PIN_PB3__RF1 PINMUX_PIN(PIN_PB3, 1, 1) +#define PIN_PB3__FLEXCOM11_IO0 PINMUX_PIN(PIN_PB3, 2, 1) +#define PIN_PB3__PCK2 PINMUX_PIN(PIN_PB3, 3, 2) +#define PIN_PB3__D8 PINMUX_PIN(PIN_PB3, 4, 1) +#define PIN_PB4 36 +#define PIN_PB4__GPIO PINMUX_PIN(PIN_PB4, 0, 0) +#define PIN_PB4__TF1 PINMUX_PIN(PIN_PB4, 1, 1) +#define PIN_PB4__FLEXCOM11_IO1 PINMUX_PIN(PIN_PB4, 2, 1) +#define PIN_PB4__PCK3 PINMUX_PIN(PIN_PB4, 3, 2) +#define PIN_PB4__D9 PINMUX_PIN(PIN_PB4, 4, 1) +#define PIN_PB5 37 +#define PIN_PB5__GPIO PINMUX_PIN(PIN_PB5, 0, 0) +#define PIN_PB5__TK1 PINMUX_PIN(PIN_PB5, 1, 1) +#define PIN_PB5__FLEXCOM11_IO2 PINMUX_PIN(PIN_PB5, 2, 1) +#define PIN_PB5__PCK4 PINMUX_PIN(PIN_PB5, 3, 2) +#define PIN_PB5__D10 PINMUX_PIN(PIN_PB5, 4, 1) +#define PIN_PB6 38 +#define PIN_PB6__GPIO PINMUX_PIN(PIN_PB6, 0, 0) +#define PIN_PB6__RK1 PINMUX_PIN(PIN_PB6, 1, 1) +#define PIN_PB6__FLEXCOM11_IO3 PINMUX_PIN(PIN_PB6, 2, 1) +#define PIN_PB6__PCK5 PINMUX_PIN(PIN_PB6, 3, 2) +#define PIN_PB6__D11 PINMUX_PIN(PIN_PB6, 4, 1) +#define PIN_PB7 39 +#define PIN_PB7__GPIO PINMUX_PIN(PIN_PB7, 0, 0) +#define PIN_PB7__TD1 PINMUX_PIN(PIN_PB7, 1, 1) +#define PIN_PB7__FLEXCOM11_IO4 PINMUX_PIN(PIN_PB7, 2, 1) +#define PIN_PB7__FLEXCOM3_IO5 PINMUX_PIN(PIN_PB7, 3, 2) +#define PIN_PB7__D12 PINMUX_PIN(PIN_PB7, 4, 1) +#define PIN_PB8 40 +#define PIN_PB8__GPIO PINMUX_PIN(PIN_PB8, 0, 0) +#define PIN_PB8__RD1 PINMUX_PIN(PIN_PB8, 1, 1) +#define PIN_PB8__FLEXCOM8_IO0 PINMUX_PIN(PIN_PB8, 2, 1) +#define PIN_PB8__FLEXCOM3_IO6 PINMUX_PIN(PIN_PB8, 3, 2) +#define PIN_PB8__D13 PINMUX_PIN(PIN_PB8, 4, 1) +#define PIN_PB9 41 +#define PIN_PB9__GPIO PINMUX_PIN(PIN_PB9, 0, 0) +#define PIN_PB9__QSPI0_IO3 PINMUX_PIN(PIN_PB9, 1, 1) +#define PIN_PB9__FLEXCOM8_IO1 PINMUX_PIN(PIN_PB9, 2, 1) +#define PIN_PB9__PDMC0_CLK PINMUX_PIN(PIN_PB9, 3, 1) +#define PIN_PB9__NCS3_NANDCS PINMUX_PIN(PIN_PB9, 4, 1) +#define PIN_PB9__PWML0 PINMUX_PIN(PIN_PB9, 5, 2) +#define PIN_PB10 42 +#define PIN_PB10__GPIO PINMUX_PIN(PIN_PB10, 0, 0) +#define PIN_PB10__QSPI0_IO2 PINMUX_PIN(PIN_PB10, 1, 1) +#define PIN_PB10__FLEXCOM8_IO2 PINMUX_PIN(PIN_PB10, 2, 1) +#define PIN_PB10__PDMC0_DS0 PINMUX_PIN(PIN_PB10, 3, 1) +#define PIN_PB10__NWE_NWR0_NANDWE PINMUX_PIN(PIN_PB10, 4, 1) +#define PIN_PB10__PWMH0 PINMUX_PIN(PIN_PB10, 5, 2) +#define PIN_PB11 43 +#define PIN_PB11__GPIO PINMUX_PIN(PIN_PB11, 0, 0) +#define PIN_PB11__QSPI0_IO1 PINMUX_PIN(PIN_PB11, 1, 1) +#define PIN_PB11__FLEXCOM8_IO3 PINMUX_PIN(PIN_PB11, 2, 1) +#define PIN_PB11__PDMC0_DS1 PINMUX_PIN(PIN_PB11, 3, 1) +#define PIN_PB11__NRD_NANDOE PINMUX_PIN(PIN_PB11, 4, 1) +#define PIN_PB11__PWML1 PINMUX_PIN(PIN_PB11, 5, 2) +#define PIN_PB12 44 +#define PIN_PB12__GPIO PINMUX_PIN(PIN_PB12, 0, 0) +#define PIN_PB12__QSPI0_IO0 PINMUX_PIN(PIN_PB12, 1, 1) +#define PIN_PB12__FLEXCOM8_IO4 PINMUX_PIN(PIN_PB12, 2, 1) +#define PIN_PB12__FLEXCOM6_IO5 PINMUX_PIN(PIN_PB12, 3, 1) +#define PIN_PB12__A21_NANDALE PINMUX_PIN(PIN_PB12, 4, 1) +#define PIN_PB12__PWMH1 PINMUX_PIN(PIN_PB12, 5, 2) +#define PIN_PB13 45 +#define PIN_PB13__GPIO PINMUX_PIN(PIN_PB13, 0, 0) +#define PIN_PB13__QSPI0_CS PINMUX_PIN(PIN_PB13, 1, 1) +#define PIN_PB13__FLEXCOM9_IO0 PINMUX_PIN(PIN_PB13, 2, 1) +#define PIN_PB13__FLEXCOM6_IO6 PINMUX_PIN(PIN_PB13, 3, 1) +#define PIN_PB13__A22_NANDCLE PINMUX_PIN(PIN_PB13, 4, 1) +#define PIN_PB13__PWML2 PINMUX_PIN(PIN_PB13, 5, 2) +#define PIN_PB14 46 +#define PIN_PB14__GPIO PINMUX_PIN(PIN_PB14, 0, 0) +#define PIN_PB14__QSPI0_SCK PINMUX_PIN(PIN_PB14, 1, 1) +#define PIN_PB14__FLEXCOM9_IO1 PINMUX_PIN(PIN_PB14, 2, 1) +#define PIN_PB14__D0 PINMUX_PIN(PIN_PB14, 4, 1) +#define PIN_PB14__PWMH2 PINMUX_PIN(PIN_PB14, 5, 2) +#define PIN_PB15 47 +#define PIN_PB15__GPIO PINMUX_PIN(PIN_PB15, 0, 0) +#define PIN_PB15__QSPI0_SCKN PINMUX_PIN(PIN_PB15, 1, 1) +#define PIN_PB15__FLEXCOM9_IO2 PINMUX_PIN(PIN_PB15, 2, 1) +#define PIN_PB15__D1 PINMUX_PIN(PIN_PB15, 4, 1) +#define PIN_PB15__PWML3 PINMUX_PIN(PIN_PB15, 5, 2) +#define PIN_PB16 48 +#define PIN_PB16__GPIO PINMUX_PIN(PIN_PB16, 0, 0) +#define PIN_PB16__QSPI0_IO4 PINMUX_PIN(PIN_PB16, 1, 1) +#define PIN_PB16__FLEXCOM9_IO3 PINMUX_PIN(PIN_PB16, 2, 1) +#define PIN_PB16__PCK0 PINMUX_PIN(PIN_PB16, 3, 1) +#define PIN_PB16__D2 PINMUX_PIN(PIN_PB16, 4, 1) +#define PIN_PB16__PWMH3 PINMUX_PIN(PIN_PB16, 5, 2) +#define PIN_PB16__EXT_IRQ0 PINMUX_PIN(PIN_PB16, 6, 2) +#define PIN_PB17 49 +#define PIN_PB17__GPIO PINMUX_PIN(PIN_PB17, 0, 0) +#define PIN_PB17__QSPI0_IO5 PINMUX_PIN(PIN_PB17, 1, 1) +#define PIN_PB17__FLEXCOM9_IO4 PINMUX_PIN(PIN_PB17, 2, 1) +#define PIN_PB17__PCK1 PINMUX_PIN(PIN_PB17, 3, 1) +#define PIN_PB17__D3 PINMUX_PIN(PIN_PB17, 4, 1) +#define PIN_PB17__PWMEXTRG0 PINMUX_PIN(PIN_PB17, 5, 2) +#define PIN_PB17__EXT_IRQ1 PINMUX_PIN(PIN_PB17, 6, 2) +#define PIN_PB18 50 +#define PIN_PB18__GPIO PINMUX_PIN(PIN_PB18, 0, 0) +#define PIN_PB18__QSPI0_IO6 PINMUX_PIN(PIN_PB18, 1, 1) +#define PIN_PB18__FLEXCOM10_IO0 PINMUX_PIN(PIN_PB18, 2, 1) +#define PIN_PB18__PCK2 PINMUX_PIN(PIN_PB18, 3, 1) +#define PIN_PB18__D4 PINMUX_PIN(PIN_PB18, 4, 1) +#define PIN_PB18__PWMEXTRG1 PINMUX_PIN(PIN_PB18, 5, 2) +#define PIN_PB19 51 +#define PIN_PB19__GPIO PINMUX_PIN(PIN_PB19, 0, 0) +#define PIN_PB19__QSPI0_IO7 PINMUX_PIN(PIN_PB19, 1, 1) +#define PIN_PB19__FLEXCOM10_IO1 PINMUX_PIN(PIN_PB19, 2, 1) +#define PIN_PB19__PCK3 PINMUX_PIN(PIN_PB19, 3, 1) +#define PIN_PB19__D5 PINMUX_PIN(PIN_PB19, 4, 1) +#define PIN_PB19__PWMFI0 PINMUX_PIN(PIN_PB19, 5, 2) +#define PIN_PB20 52 +#define PIN_PB20__GPIO PINMUX_PIN(PIN_PB20, 0, 0) +#define PIN_PB20__QSPI0_DQS PINMUX_PIN(PIN_PB20, 1, 1) +#define PIN_PB20__FLEXCOM10_IO2 PINMUX_PIN(PIN_PB20, 2, 1) +#define PIN_PB20__D6 PINMUX_PIN(PIN_PB20, 4, 1) +#define PIN_PB20__PWMFI1 PINMUX_PIN(PIN_PB20, 5, 2) +#define PIN_PB21 53 +#define PIN_PB21__GPIO PINMUX_PIN(PIN_PB21, 0, 0) +#define PIN_PB21__QSPI0_INT PINMUX_PIN(PIN_PB21, 1, 1) +#define PIN_PB21__FLEXCOM10_IO3 PINMUX_PIN(PIN_PB21, 2, 1) +#define PIN_PB21__FLEXCOM9_IO5 PINMUX_PIN(PIN_PB21, 3, 1) +#define PIN_PB21__D7 PINMUX_PIN(PIN_PB21, 4, 1) +#define PIN_PB22 54 +#define PIN_PB22__GPIO PINMUX_PIN(PIN_PB22, 0, 0) +#define PIN_PB22__QSPI1_IO3 PINMUX_PIN(PIN_PB22, 1, 1) +#define PIN_PB22__FLEXCOM10_IO4 PINMUX_PIN(PIN_PB22, 2, 1) +#define PIN_PB22__FLEXCOM9_IO6 PINMUX_PIN(PIN_PB22, 3, 1) +#define PIN_PB22__NANDRDY PINMUX_PIN(PIN_PB22, 4, 1) +#define PIN_PB23 55 +#define PIN_PB23__GPIO PINMUX_PIN(PIN_PB23, 0, 0) +#define PIN_PB23__QSPI1_IO2 PINMUX_PIN(PIN_PB23, 1, 1) +#define PIN_PB23__FLEXCOM7_IO0 PINMUX_PIN(PIN_PB23, 2, 1) +#define PIN_PB23__I2SMCC0_CK PINMUX_PIN(PIN_PB23, 3, 1) +#define PIN_PB23__PCK4 PINMUX_PIN(PIN_PB23, 6, 1) +#define PIN_PB24 56 +#define PIN_PB24__GPIO PINMUX_PIN(PIN_PB24, 0, 0) +#define PIN_PB24__QSPI1_IO1 PINMUX_PIN(PIN_PB24, 1, 1) +#define PIN_PB24__FLEXCOM7_IO1 PINMUX_PIN(PIN_PB24, 2, 1) +#define PIN_PB24__I2SMCC0_WS PINMUX_PIN(PIN_PB24, 3, 1) +#define PIN_PB24__PCK5 PINMUX_PIN(PIN_PB24, 6, 1) +#define PIN_PB25 57 +#define PIN_PB25__GPIO PINMUX_PIN(PIN_PB25, 0, 0) +#define PIN_PB25__QSPI1_IO0 PINMUX_PIN(PIN_PB25, 1, 1) +#define PIN_PB25__FLEXCOM7_IO2 PINMUX_PIN(PIN_PB25, 2, 1) +#define PIN_PB25__I2SMCC0_DOUT1 PINMUX_PIN(PIN_PB25, 3, 1) +#define PIN_PB25__PCK6 PINMUX_PIN(PIN_PB25, 6, 1) +#define PIN_PB26 58 +#define PIN_PB26__GPIO PINMUX_PIN(PIN_PB26, 0, 0) +#define PIN_PB26__QSPI1_CS PINMUX_PIN(PIN_PB26, 1, 1) +#define PIN_PB26__FLEXCOM7_IO3 PINMUX_PIN(PIN_PB26, 2, 1) +#define PIN_PB26__I2SMCC0_DOUT0 PINMUX_PIN(PIN_PB26, 3, 1) +#define PIN_PB26__PWMEXTRG0 PINMUX_PIN(PIN_PB26, 5, 1) +#define PIN_PB26__PCK7 PINMUX_PIN(PIN_PB26, 6, 1) +#define PIN_PB27 59 +#define PIN_PB27__GPIO PINMUX_PIN(PIN_PB27, 0, 0) +#define PIN_PB27__QSPI1_SCK PINMUX_PIN(PIN_PB27, 1, 1) +#define PIN_PB27__FLEXCOM7_IO4 PINMUX_PIN(PIN_PB27, 2, 1) +#define PIN_PB27__I2SMCC0_MCK PINMUX_PIN(PIN_PB27, 3, 1) +#define PIN_PB27__PWMEXTRG1 PINMUX_PIN(PIN_PB27, 5, 1) +#define PIN_PB28 60 +#define PIN_PB28__GPIO PINMUX_PIN(PIN_PB28, 0, 0) +#define PIN_PB28__SDMMC1_RSTN PINMUX_PIN(PIN_PB28, 1, 1) +#define PIN_PB28__ADTRG PINMUX_PIN(PIN_PB28, 2, 2) +#define PIN_PB28__PWMFI0 PINMUX_PIN(PIN_PB28, 5, 1) +#define PIN_PB28__FLEXCOM7_IO0 PINMUX_PIN(PIN_PB28, 6, 4) +#define PIN_PB29 61 +#define PIN_PB29__GPIO PINMUX_PIN(PIN_PB29, 0, 0) +#define PIN_PB29__SDMMC1_CMD PINMUX_PIN(PIN_PB29, 1, 1) +#define PIN_PB29__FLEXCOM3_IO2 PINMUX_PIN(PIN_PB29, 2, 2) +#define PIN_PB29__FLEXCOM0_IO5 PINMUX_PIN(PIN_PB29, 3, 2) +#define PIN_PB29__TIOA3 PINMUX_PIN(PIN_PB29, 4, 2) +#define PIN_PB29__PWMFI1 PINMUX_PIN(PIN_PB29, 5, 1) +#define PIN_PB29__FLEXCOM7_IO1 PINMUX_PIN(PIN_PB29, 6, 4) +#define PIN_PB30 62 +#define PIN_PB30__GPIO PINMUX_PIN(PIN_PB30, 0, 0) +#define PIN_PB30__SDMMC1_CK PINMUX_PIN(PIN_PB30, 1, 1) +#define PIN_PB30__FLEXCOM3_IO3 PINMUX_PIN(PIN_PB30, 2, 2) +#define PIN_PB30__FLEXCOM0_IO6 PINMUX_PIN(PIN_PB30, 3, 2) +#define PIN_PB30__TIOB3 PINMUX_PIN(PIN_PB30, 4, 1) +#define PIN_PB30__PWMH0 PINMUX_PIN(PIN_PB30, 5, 1) +#define PIN_PB30__FLEXCOM8_IO0 PINMUX_PIN(PIN_PB30, 6, 4) +#define PIN_PB31 63 +#define PIN_PB31__GPIO PINMUX_PIN(PIN_PB31, 0, 0) +#define PIN_PB31__SDMMC1_DAT0 PINMUX_PIN(PIN_PB31, 1, 1) +#define PIN_PB31__FLEXCOM3_IO4 PINMUX_PIN(PIN_PB31, 2, 2) +#define PIN_PB31__FLEXCOM9_IO5 PINMUX_PIN(PIN_PB31, 3, 2) +#define PIN_PB31__TCLK3 PINMUX_PIN(PIN_PB31, 4, 1) +#define PIN_PB31__PWML0 PINMUX_PIN(PIN_PB31, 5, 1) +#define PIN_PB31__FLEXCOM8_IO1 PINMUX_PIN(PIN_PB31, 6, 4) +#define PIN_PC0 64 +#define PIN_PC0__GPIO PINMUX_PIN(PIN_PC0, 0, 0) +#define PIN_PC0__SDMMC1_DAT1 PINMUX_PIN(PIN_PC0, 1, 1) +#define PIN_PC0__FLEXCOM3_IO0 PINMUX_PIN(PIN_PC0, 2, 2) +#define PIN_PC0__TIOA4 PINMUX_PIN(PIN_PC0, 4, 1) +#define PIN_PC0__PWML1 PINMUX_PIN(PIN_PC0, 5, 1) +#define PIN_PC0__FLEXCOM9_IO0 PINMUX_PIN(PIN_PC0, 6, 4) +#define PIN_PC1 65 +#define PIN_PC1__GPIO PINMUX_PIN(PIN_PC1, 0, 0) +#define PIN_PC1__SDMMC1_DAT2 PINMUX_PIN(PIN_PC1, 1, 1) +#define PIN_PC1__FLEXCOM3_IO1 PINMUX_PIN(PIN_PC1, 2, 2) +#define PIN_PC1__TIOB4 PINMUX_PIN(PIN_PC1, 4, 1) +#define PIN_PC1__PWMH1 PINMUX_PIN(PIN_PC1, 5, 1) +#define PIN_PC1__FLEXCOM9_IO1 PINMUX_PIN(PIN_PC1, 6, 4) +#define PIN_PC2 66 +#define PIN_PC2__GPIO PINMUX_PIN(PIN_PC2, 0, 0) +#define PIN_PC2__SDMMC1_DAT3 PINMUX_PIN(PIN_PC2, 1, 1) +#define PIN_PC2__FLEXCOM4_IO0 PINMUX_PIN(PIN_PC2, 2, 2) +#define PIN_PC2__TCLK4 PINMUX_PIN(PIN_PC2, 4, 1) +#define PIN_PC2__PWML2 PINMUX_PIN(PIN_PC2, 5, 1) +#define PIN_PC2__FLEXCOM10_IO0 PINMUX_PIN(PIN_PC2, 6, 4) +#define PIN_PC3 67 +#define PIN_PC3__GPIO PINMUX_PIN(PIN_PC3, 0, 0) +#define PIN_PC3__SDMMC1_WP PINMUX_PIN(PIN_PC3, 1, 1) +#define PIN_PC3__FLEXCOM4_IO1 PINMUX_PIN(PIN_PC3, 2, 2) +#define PIN_PC3__TIOA5 PINMUX_PIN(PIN_PC3, 4, 1) +#define PIN_PC3__PWMH2 PINMUX_PIN(PIN_PC3, 5, 1) +#define PIN_PC3__FLEXCOM10_IO1 PINMUX_PIN(PIN_PC3, 6, 4) +#define PIN_PC4 68 +#define PIN_PC4__GPIO PINMUX_PIN(PIN_PC4, 0, 0) +#define PIN_PC4__SDMMC1_CD PINMUX_PIN(PIN_PC4, 1, 1) +#define PIN_PC4__FLEXCOM4_IO2 PINMUX_PIN(PIN_PC4, 2, 2) +#define PIN_PC4__FLEXCOM9_IO6 PINMUX_PIN(PIN_PC4, 3, 2) +#define PIN_PC4__TIOB5 PINMUX_PIN(PIN_PC4, 4, 1) +#define PIN_PC4__PWML3 PINMUX_PIN(PIN_PC4, 5, 1) +#define PIN_PC4__FLEXCOM11_IO0 PINMUX_PIN(PIN_PC4, 6, 4) +#define PIN_PC5 69 +#define PIN_PC5__GPIO PINMUX_PIN(PIN_PC5, 0, 0) +#define PIN_PC5__SDMMC1_1V8SEL PINMUX_PIN(PIN_PC5, 1, 1) +#define PIN_PC5__FLEXCOM4_IO3 PINMUX_PIN(PIN_PC5, 2, 2) +#define PIN_PC5__FLEXCOM6_IO5 PINMUX_PIN(PIN_PC5, 3, 2) +#define PIN_PC5__TCLK5 PINMUX_PIN(PIN_PC5, 4, 1) +#define PIN_PC5__PWMH3 PINMUX_PIN(PIN_PC5, 5, 1) +#define PIN_PC5__FLEXCOM11_IO1 PINMUX_PIN(PIN_PC5, 6, 4) +#define PIN_PC6 70 +#define PIN_PC6__GPIO PINMUX_PIN(PIN_PC6, 0, 0) +#define PIN_PC6__FLEXCOM4_IO4 PINMUX_PIN(PIN_PC6, 2, 2) +#define PIN_PC6__FLEXCOM6_IO6 PINMUX_PIN(PIN_PC6, 3, 2) +#define PIN_PC7 71 +#define PIN_PC7__GPIO PINMUX_PIN(PIN_PC7, 0, 0) +#define PIN_PC7__I2SMCC0_DIN0 PINMUX_PIN(PIN_PC7, 1, 1) +#define PIN_PC7__FLEXCOM7_IO0 PINMUX_PIN(PIN_PC7, 2, 2) +#define PIN_PC8 72 +#define PIN_PC8__GPIO PINMUX_PIN(PIN_PC8, 0, 0) +#define PIN_PC8__I2SMCC0_DIN1 PINMUX_PIN(PIN_PC8, 1, 1) +#define PIN_PC8__FLEXCOM7_IO1 PINMUX_PIN(PIN_PC8, 2, 2) +#define PIN_PC9 73 +#define PIN_PC9__GPIO PINMUX_PIN(PIN_PC9, 0, 0) +#define PIN_PC9__I2SMCC0_DOUT3 PINMUX_PIN(PIN_PC9, 1, 1) +#define PIN_PC9__FLEXCOM7_IO2 PINMUX_PIN(PIN_PC9, 2, 2) +#define PIN_PC9__FLEXCOM1_IO0 PINMUX_PIN(PIN_PC9, 6, 4) +#define PIN_PC10 74 +#define PIN_PC10__GPIO PINMUX_PIN(PIN_PC10, 0, 0) +#define PIN_PC10__I2SMCC0_DOUT2 PINMUX_PIN(PIN_PC10, 1, 1) +#define PIN_PC10__FLEXCOM7_IO3 PINMUX_PIN(PIN_PC10, 2, 2) +#define PIN_PC10__FLEXCOM1_IO1 PINMUX_PIN(PIN_PC10, 6, 4) +#define PIN_PC11 75 +#define PIN_PC11__GPIO PINMUX_PIN(PIN_PC11, 0, 0) +#define PIN_PC11__I2SMCC1_CK PINMUX_PIN(PIN_PC11, 1, 1) +#define PIN_PC11__FLEXCOM7_IO4 PINMUX_PIN(PIN_PC11, 2, 2) +#define PIN_PC11__FLEXCOM2_IO0 PINMUX_PIN(PIN_PC11, 6, 4) +#define PIN_PC12 76 +#define PIN_PC12__GPIO PINMUX_PIN(PIN_PC12, 0, 0) +#define PIN_PC12__I2SMCC1_WS PINMUX_PIN(PIN_PC12, 1, 1) +#define PIN_PC12__FLEXCOM8_IO2 PINMUX_PIN(PIN_PC12, 2, 2) +#define PIN_PC12__FLEXCOM2_IO1 PINMUX_PIN(PIN_PC12, 6, 4) +#define PIN_PC13 77 +#define PIN_PC13__GPIO PINMUX_PIN(PIN_PC13, 0, 0) +#define PIN_PC13__I2SMCC1_MCK PINMUX_PIN(PIN_PC13, 1, 1) +#define PIN_PC13__FLEXCOM8_IO1 PINMUX_PIN(PIN_PC13, 2, 2) +#define PIN_PC13__FLEXCOM3_IO0 PINMUX_PIN(PIN_PC13, 6, 4) +#define PIN_PC14 78 +#define PIN_PC14__GPIO PINMUX_PIN(PIN_PC14, 0, 0) +#define PIN_PC14__I2SMCC1_DOUT0 PINMUX_PIN(PIN_PC14, 1, 1) +#define PIN_PC14__FLEXCOM8_IO0 PINMUX_PIN(PIN_PC14, 2, 2) +#define PIN_PC14__FLEXCOM3_IO1 PINMUX_PIN(PIN_PC14, 6, 4) +#define PIN_PC15 79 +#define PIN_PC15__GPIO PINMUX_PIN(PIN_PC15, 0, 0) +#define PIN_PC15__I2SMCC1_DOUT1 PINMUX_PIN(PIN_PC15, 1, 1) +#define PIN_PC15__FLEXCOM8_IO3 PINMUX_PIN(PIN_PC15, 2, 2) +#define PIN_PC15__FLEXCOM4_IO0 PINMUX_PIN(PIN_PC15, 6, 4) +#define PIN_PC16 80 +#define PIN_PC16__GPIO PINMUX_PIN(PIN_PC16, 0, 0) +#define PIN_PC16__I2SMCC_DOUT2 PINMUX_PIN(PIN_PC16, 1, 1) +#define PIN_PC16__FLEXCOM8_IO4 PINMUX_PIN(PIN_PC16, 2, 2) +#define PIN_PC16__FLEXCOM3_IO1 PINMUX_PIN(PIN_PC16, 6, 4) +#define PIN_PC17 81 +#define PIN_PC17__GPIO PINMUX_PIN(PIN_PC17, 0, 0) +#define PIN_PC17__I2SMCC1_DOUT3 PINMUX_PIN(PIN_PC17, 1, 1) +#define PIN_PC17__EXT_IRQ0 PINMUX_PIN(PIN_PC17, 2, 3) +#define PIN_PC17__FLEXCOM5_IO0 PINMUX_PIN(PIN_PC17, 6, 4) +#define PIN_PC18 82 +#define PIN_PC18__GPIO PINMUX_PIN(PIN_PC18, 0, 0) +#define PIN_PC18__I2SMCC1_DIN0 PINMUX_PIN(PIN_PC18, 1, 1) +#define PIN_PC18__FLEXCOM9_IO0 PINMUX_PIN(PIN_PC18, 2, 2) +#define PIN_PC18__FLEXCOM5_IO1 PINMUX_PIN(PIN_PC18, 6, 4) +#define PIN_PC19 83 +#define PIN_PC19__GPIO PINMUX_PIN(PIN_PC19, 0, 0) +#define PIN_PC19__I2SMCC1_DIN1 PINMUX_PIN(PIN_PC19, 1, 1) +#define PIN_PC19__FLEXCOM9_IO1 PINMUX_PIN(PIN_PC19, 2, 2) +#define PIN_PC19__FLEXCOM6_IO0 PINMUX_PIN(PIN_PC19, 6, 4) +#define PIN_PC20 84 +#define PIN_PC20__GPIO PINMUX_PIN(PIN_PC20, 0, 0) +#define PIN_PC20__I2SMCC1_DIN2 PINMUX_PIN(PIN_PC20, 1, 1) +#define PIN_PC20__FLEXCOM9_IO4 PINMUX_PIN(PIN_PC20, 2, 2) +#define PIN_PC20__FLEXCOM6_IO1 PINMUX_PIN(PIN_PC20, 6, 4) +#define PIN_PC21 85 +#define PIN_PC21__GPIO PINMUX_PIN(PIN_PC21, 0, 0) +#define PIN_PC21__I2SMCC1_DIN3 PINMUX_PIN(PIN_PC21, 1, 1) +#define PIN_PC21__FLEXCOM9_IO2 PINMUX_PIN(PIN_PC21, 2, 2) +#define PIN_PC21__D3 PINMUX_PIN(PIN_PC21, 4, 2) +#define PIN_PC21__FLEXCOM6_IO0 PINMUX_PIN(PIN_PC21, 6, 5) +#define PIN_PC22 86 +#define PIN_PC22__GPIO PINMUX_PIN(PIN_PC22, 0, 0) +#define PIN_PC22__I2SMCC0_DIN2 PINMUX_PIN(PIN_PC22, 1, 1) +#define PIN_PC22__FLEXCOM9_IO3 PINMUX_PIN(PIN_PC22, 2, 2) +#define PIN_PC22__D4 PINMUX_PIN(PIN_PC22, 4, 2) +#define PIN_PC22__FLEXCOM6_IO1 PINMUX_PIN(PIN_PC22, 6, 5) +#define PIN_PC23 87 +#define PIN_PC23__GPIO PINMUX_PIN(PIN_PC23, 0, 0) +#define PIN_PC23__I2SMCC0_DIN3 PINMUX_PIN(PIN_PC23, 1, 1) +#define PIN_PC23__FLEXCOM0_IO5 PINMUX_PIN(PIN_PC23, 2, 3) +#define PIN_PC23__D5 PINMUX_PIN(PIN_PC23, 4, 2) +#define PIN_PC23__FLEXCOM7_IO0 PINMUX_PIN(PIN_PC23, 6, 5) +#define PIN_PC24 88 +#define PIN_PC24__GPIO PINMUX_PIN(PIN_PC24, 0, 0) +#define PIN_PC24__FLEXCOM0_IO6 PINMUX_PIN(PIN_PC24, 2, 3) +#define PIN_PC24__EXT_IRQ1 PINMUX_PIN(PIN_PC24, 3, 3) +#define PIN_PC24__D6 PINMUX_PIN(PIN_PC24, 4, 2) +#define PIN_PC24__FLEXCOM7_IO1 PINMUX_PIN(PIN_PC24, 6, 5) +#define PIN_PC25 89 +#define PIN_PC25__GPIO PINMUX_PIN(PIN_PC25, 0, 0) +#define PIN_PC25__NTRST PINMUX_PIN(PIN_PC25, 1, 1) +#define PIN_PC26 90 +#define PIN_PC26__GPIO PINMUX_PIN(PIN_PC26, 0, 0) +#define PIN_PC26__TCK_SWCLK PINMUX_PIN(PIN_PC26, 1, 1) +#define PIN_PC27 91 +#define PIN_PC27__GPIO PINMUX_PIN(PIN_PC27, 0, 0) +#define PIN_PC27__TMS_SWDIO PINMUX_PIN(PIN_PC27, 1, 1) +#define PIN_PC28 92 +#define PIN_PC28__GPIO PINMUX_PIN(PIN_PC28, 0, 0) +#define PIN_PC28__TDI PINMUX_PIN(PIN_PC28, 1, 1) +#define PIN_PC29 93 +#define PIN_PC29__GPIO PINMUX_PIN(PIN_PC29, 0, 0) +#define PIN_PC29__TDO PINMUX_PIN(PIN_PC29, 1, 1) +#define PIN_PC30 94 +#define PIN_PC30__GPIO PINMUX_PIN(PIN_PC30, 0, 0) +#define PIN_PC30__FLEXCOM10_IO0 PINMUX_PIN(PIN_PC30, 2, 2) +#define PIN_PC31 95 +#define PIN_PC31__GPIO PINMUX_PIN(PIN_PC31, 0, 0) +#define PIN_PC31__FLEXCOM10_IO1 PINMUX_PIN(PIN_PC31, 2, 2) +#define PIN_PD0 96 +#define PIN_PD0__GPIO PINMUX_PIN(PIN_PD0, 0, 0) +#define PIN_PD0__FLEXCOM11_IO0 PINMUX_PIN(PIN_PD0, 2, 2) +#define PIN_PD1 97 +#define PIN_PD1__GPIO PINMUX_PIN(PIN_PD1, 0, 0) +#define PIN_PD1__FLEXCOM11_IO1 PINMUX_PIN(PIN_PD1, 2, 2) +#define PIN_PD2 98 +#define PIN_PD2__GPIO PINMUX_PIN(PIN_PD2, 0, 0) +#define PIN_PD2__SDMMC2_RSTN PINMUX_PIN(PIN_PD2, 1, 1) +#define PIN_PD2__PCK0 PINMUX_PIN(PIN_PD2, 2, 2) +#define PIN_PD2__CANTX4 PINMUX_PIN(PIN_PD2, 3, 1) +#define PIN_PD2__D7 PINMUX_PIN(PIN_PD2, 4, 2) +#define PIN_PD2__TIOA0 PINMUX_PIN(PIN_PD2, 5, 2) +#define PIN_PD2__FLEXCOM8_IO0 PINMUX_PIN(PIN_PD2, 6, 5) +#define PIN_PD3 99 +#define PIN_PD3__GPIO PINMUX_PIN(PIN_PD3, 0, 0) +#define PIN_PD3__SDMMC2_CMD PINMUX_PIN(PIN_PD3, 1, 1) +#define PIN_PD3__FLEXCOM0_IO0 PINMUX_PIN(PIN_PD3, 2, 2) +#define PIN_PD3__CANRX4 PINMUX_PIN(PIN_PD3, 3, 1) +#define PIN_PD3__NANDRDY PINMUX_PIN(PIN_PD3, 4, 2) +#define PIN_PD3__TIOB0 PINMUX_PIN(PIN_PD3, 5, 2) +#define PIN_PD3__FLEXCOM8_IO1 PINMUX_PIN(PIN_PD3, 6, 5) +#define PIN_PD4 100 +#define PIN_PD4__GPIO PINMUX_PIN(PIN_PD4, 0, 0) +#define PIN_PD4__SDMMC2_CK PINMUX_PIN(PIN_PD4, 1, 1) +#define PIN_PD4__FLEXCOM0_IO1 PINMUX_PIN(PIN_PD4, 2, 2) +#define PIN_PD4__CANTX5 PINMUX_PIN(PIN_PD4, 3, 1) +#define PIN_PD4__NCS3_NANDCS PINMUX_PIN(PIN_PD4, 4, 2) +#define PIN_PD4__TCLK0 PINMUX_PIN(PIN_PD4, 5, 2) +#define PIN_PD4__FLEXCOM9_IO0 PINMUX_PIN(PIN_PD4, 6, 5) +#define PIN_PD5 101 +#define PIN_PD5__GPIO PINMUX_PIN(PIN_PD5, 0, 0) +#define PIN_PD5__SDMMC2_DAT0 PINMUX_PIN(PIN_PD5, 1, 1) +#define PIN_PD5__FLEXCOM0_IO2 PINMUX_PIN(PIN_PD5, 2, 2) +#define PIN_PD5__CANRX5 PINMUX_PIN(PIN_PD5, 3, 1) +#define PIN_PD5__NWE_NWR0_NANDWE PINMUX_PIN(PIN_PD5, 4, 2) +#define PIN_PD5__TIOA1 PINMUX_PIN(PIN_PD5, 5, 2) +#define PIN_PD5__FLEXCOM9_IO1 PINMUX_PIN(PIN_PD5, 6, 5) +#define PIN_PD6 102 +#define PIN_PD6__GPIO PINMUX_PIN(PIN_PD6, 0, 0) +#define PIN_PD6__SDMMC2_DAT1 PINMUX_PIN(PIN_PD6, 1, 1) +#define PIN_PD6__FLEXCOM0_IO3 PINMUX_PIN(PIN_PD6, 2, 2) +#define PIN_PD6__SPDIF_RX PINMUX_PIN(PIN_PD6, 3, 3) +#define PIN_PD6__NRD_NANDOE PINMUX_PIN(PIN_PD6, 4, 2) +#define PIN_PD6__TIOB1 PINMUX_PIN(PIN_PD6, 5, 2) +#define PIN_PD6__FLEXCOM10_IO0 PINMUX_PIN(PIN_PD6, 6, 5) +#define PIN_PD7 103 +#define PIN_PD7__GPIO PINMUX_PIN(PIN_PD7, 0, 0) +#define PIN_PD7__SDMMC2_DAT2 PINMUX_PIN(PIN_PD7, 1, 1) +#define PIN_PD7__FLEXCOM0_IO4 PINMUX_PIN(PIN_PD7, 2, 2) +#define PIN_PD7__SPDIF_TX PINMUX_PIN(PIN_PD7, 2, 2) +#define PIN_PD7__A21_NANDALE PINMUX_PIN(PIN_PD7, 4, 2) +#define PIN_PD7__TCLK1 PINMUX_PIN(PIN_PD7, 5, 2) +#define PIN_PD7__FLEXCOM10_IO1 PINMUX_PIN(PIN_PD7, 6, 5) +#define PIN_PD8 104 +#define PIN_PD8__GPIO PINMUX_PIN(PIN_PD8, 0, 0) +#define PIN_PD8__SDMMC2_DAT3 PINMUX_PIN(PIN_PD8, 1, 1) +#define PIN_PD8__I2SMCC0_DIN0 PINMUX_PIN(PIN_PD8, 3, 1) +#define PIN_PD8__A11_NANDCLE PINMUX_PIN(PIN_PD8, 4, 2) +#define PIN_PD8__TIOA2 PINMUX_PIN(PIN_PD8, 5, 2) +#define PIN_PD8__FLEXCOM11_IO0 PINMUX_PIN(PIN_PD8, 6, 5) +#define PIN_PD9 105 +#define PIN_PD9__GPIO PINMUX_PIN(PIN_PD9, 0, 0) +#define PIN_PD9__SDMMC2_WP PINMUX_PIN(PIN_PD9, 1, 1) +#define PIN_PD9__I2SMCC0_DIN1 PINMUX_PIN(PIN_PD9, 3, 2) +#define PIN_PD9__D0 PINMUX_PIN(PIN_PD9, 4, 2) +#define PIN_PD9__TIOB2 PINMUX_PIN(PIN_PD9, 5, 2) +#define PIN_PD9__FLEXCOM11_IO1 PINMUX_PIN(PIN_PD9, 6, 5) +#define PIN_PD10 106 +#define PIN_PD10__GPIO PINMUX_PIN(PIN_PD10, 0, 0) +#define PIN_PD10__SDMMC2_CD PINMUX_PIN(PIN_PD10, 1, 1) +#define PIN_PD10__PCK6 PINMUX_PIN(PIN_PD10, 2, 2) +#define PIN_PD10__I2SMCC0_DIN2 PINMUX_PIN(PIN_PD10, 3, 2) +#define PIN_PD10__D1 PINMUX_PIN(PIN_PD10, 4, 2) +#define PIN_PD10__TCLK2 PINMUX_PIN(PIN_PD10, 5, 2) +#define PIN_PD10__FLEXCOM0_IO0 PINMUX_PIN(PIN_PD10, 6, 3) +#define PIN_PD11 107 +#define PIN_PD11__GPIO PINMUX_PIN(PIN_PD11, 0, 0) +#define PIN_PD11__SDMMC2_1V8SEL PINMUX_PIN(PIN_PD11, 1, 1) +#define PIN_PD11__PCK7 PINMUX_PIN(PIN_PD11, 2, 2) +#define PIN_PD11__I2SMCC0_DIN3 PINMUX_PIN(PIN_PD11, 3, 2) +#define PIN_PD11__D2 PINMUX_PIN(PIN_PD11, 4, 2) +#define PIN_PD11__TIOA3 PINMUX_PIN(PIN_PD11, 5, 2) +#define PIN_PD11__FLEXCOM0_IO1 PINMUX_PIN(PIN_PD11, 6, 3) +#define PIN_PD12 108 +#define PIN_PD12__GPIO PINMUX_PIN(PIN_PD12, 0, 0) +#define PIN_PD12__PCK1 PINMUX_PIN(PIN_PD12, 1, 2) +#define PIN_PD12__FLEXCOM1_IO0 PINMUX_PIN(PIN_PD12, 2, 2) +#define PIN_PD12__CANTX0 PINMUX_PIN(PIN_PD12, 4, 2) +#define PIN_PD12__TIOB3 PINMUX_PIN(PIN_PD12, 5, 2) +#define PIN_PD13 109 +#define PIN_PD13__GPIO PINMUX_PIN(PIN_PD13, 0, 0) +#define PIN_PD13__I2SMCC0_CK PINMUX_PIN(PIN_PD13, 1, 2) +#define PIN_PD13__FLEXCOM1_IO1 PINMUX_PIN(PIN_PD13, 2, 2) +#define PIN_PD13__PWML0 PINMUX_PIN(PIN_PD13, 3, 4) +#define PIN_PD13__CANRX0 PINMUX_PIN(PIN_PD13, 4, 2) +#define PIN_PD13__TCLK3 PINMUX_PIN(PIN_PD13, 5, 2) +#define PIN_PD14 110 +#define PIN_PD14__GPIO PINMUX_PIN(PIN_PD14, 0, 0) +#define PIN_PD14__I2SMCC0_MCK PINMUX_PIN(PIN_PD14, 1, 2) +#define PIN_PD14__FLEXCOM1_IO2 PINMUX_PIN(PIN_PD14, 2, 2) +#define PIN_PD14__PWMH0 PINMUX_PIN(PIN_PD14, 3, 4) +#define PIN_PD14__CANTX1 PINMUX_PIN(PIN_PD14, 4, 2) +#define PIN_PD14__TIOA4 PINMUX_PIN(PIN_PD14, 5, 2) +#define PIN_PD14__FLEXCOM2_IO0 PINMUX_PIN(PIN_PD14, 6, 5) +#define PIN_PD15 111 +#define PIN_PD15__GPIO PINMUX_PIN(PIN_PD15, 0, 0) +#define PIN_PD15__I2SMCC0_WS PINMUX_PIN(PIN_PD15, 1, 2) +#define PIN_PD15__FLEXCOM1_IO3 PINMUX_PIN(PIN_PD15, 2, 2) +#define PIN_PD15__PWML1 PINMUX_PIN(PIN_PD15, 3, 4) +#define PIN_PD15__CANRX1 PINMUX_PIN(PIN_PD15, 4, 2) +#define PIN_PD15__TIOB4 PINMUX_PIN(PIN_PD15, 5, 2) +#define PIN_PD15__FLEXCOM2_IO1 PINMUX_PIN(PIN_PD15, 6, 5) +#define PIN_PD16 112 +#define PIN_PD16__GPIO PINMUX_PIN(PIN_PD16, 0, 0) +#define PIN_PD16__I2SMCC0_DOUT0 PINMUX_PIN(PIN_PD16, 1, 2) +#define PIN_PD16__FLEXCOM1_IO4 PINMUX_PIN(PIN_PD16, 2, 2) +#define PIN_PD16__PWMH1 PINMUX_PIN(PIN_PD16, 3, 4) +#define PIN_PD16__CANTX2 PINMUX_PIN(PIN_PD16, 4, 2) +#define PIN_PD16__TCLK4 PINMUX_PIN(PIN_PD16, 5, 2) +#define PIN_PD16__FLEXCOM3_IO0 PINMUX_PIN(PIN_PD16, 6, 5) +#define PIN_PD17 113 +#define PIN_PD17__GPIO PINMUX_PIN(PIN_PD17, 0, 0) +#define PIN_PD17__I2SMCC0_DOUT1 PINMUX_PIN(PIN_PD17, 1, 2) +#define PIN_PD17__FLEXCOM2_IO0 PINMUX_PIN(PIN_PD17, 2, 2) +#define PIN_PD17__PWML2 PINMUX_PIN(PIN_PD17, 3, 4) +#define PIN_PD17__CANRX2 PINMUX_PIN(PIN_PD17, 4, 2) +#define PIN_PD17__TIOA5 PINMUX_PIN(PIN_PD17, 5, 2) +#define PIN_PD17__FLEXCOM3_IO1 PINMUX_PIN(PIN_PD17, 6, 5) +#define PIN_PD18 114 +#define PIN_PD18__GPIO PINMUX_PIN(PIN_PD18, 0, 0) +#define PIN_PD18__I2SMCC0_DOUT2 PINMUX_PIN(PIN_PD18, 1, 2) +#define PIN_PD18__FLEXCOM2_IO1 PINMUX_PIN(PIN_PD18, 2, 2) +#define PIN_PD18__PWMH2 PINMUX_PIN(PIN_PD18, 3, 4) +#define PIN_PD18__CANTX3 PINMUX_PIN(PIN_PD18, 4, 2) +#define PIN_PD18__TIOB5 PINMUX_PIN(PIN_PD18, 5, 2) +#define PIN_PD18__FLEXCOM4_IO0 PINMUX_PIN(PIN_PD18, 6, 5) +#define PIN_PD19 115 +#define PIN_PD19__GPIO PINMUX_PIN(PIN_PD19, 0, 0) +#define PIN_PD19__I2SMCC0_DOUT3 PINMUX_PIN(PIN_PD19, 1, 2) +#define PIN_PD19__FLEXCOM2_IO2 PINMUX_PIN(PIN_PD19, 2, 2) +#define PIN_PD19__PWML3 PINMUX_PIN(PIN_PD19, 3, 4) +#define PIN_PD19__CANRX3 PINMUX_PIN(PIN_PD19, 4, 2) +#define PIN_PD19__TCLK5 PINMUX_PIN(PIN_PD19, 5, 2) +#define PIN_PD19__FLEXCOM4_IO1 PINMUX_PIN(PIN_PD19, 6, 5) +#define PIN_PD20 116 +#define PIN_PD20__GPIO PINMUX_PIN(PIN_PD20, 0, 0) +#define PIN_PD20__PCK0 PINMUX_PIN(PIN_PD20, 1, 3) +#define PIN_PD20__FLEXCOM2_IO3 PINMUX_PIN(PIN_PD20, 2, 2) +#define PIN_PD20__PWMH3 PINMUX_PIN(PIN_PD20, 3, 4) +#define PIN_PD20__CANTX4 PINMUX_PIN(PIN_PD20, 5, 2) +#define PIN_PD20__FLEXCOM5_IO0 PINMUX_PIN(PIN_PD20, 6, 5) +#define PIN_PD21 117 +#define PIN_PD21__GPIO PINMUX_PIN(PIN_PD21, 0, 0) +#define PIN_PD21__PCK1 PINMUX_PIN(PIN_PD21, 1, 3) +#define PIN_PD21__FLEXCOM2_IO4 PINMUX_PIN(PIN_PD21, 2, 2) +#define PIN_PD21__CANRX4 PINMUX_PIN(PIN_PD21, 4, 2) +#define PIN_PD21__FLEXCOM5_IO1 PINMUX_PIN(PIN_PD21, 6, 5) +#define PIN_PD21__G1_TXEN PINMUX_PIN(PIN_PD21, 7, 1) +#define PIN_PD22 118 +#define PIN_PD22__GPIO PINMUX_PIN(PIN_PD22, 0, 0) +#define PIN_PD22__PDMC0_CLK PINMUX_PIN(PIN_PD22, 1, 2) +#define PIN_PD22__PWMEXTRG0 PINMUX_PIN(PIN_PD22, 3, 4) +#define PIN_PD22__RD1 PINMUX_PIN(PIN_PD22, 4, 2) +#define PIN_PD22__CANTX5 PINMUX_PIN(PIN_PD22, 6, 2) +#define PIN_PD22__G1_TX0 PINMUX_PIN(PIN_PD22, 7, 1) +#define PIN_PD23 119 +#define PIN_PD23__GPIO PINMUX_PIN(PIN_PD23, 0, 0) +#define PIN_PD23__PDMC0_DS0 PINMUX_PIN(PIN_PD23, 1, 2) +#define PIN_PD23__PWMEXTRG1 PINMUX_PIN(PIN_PD23, 3, 4) +#define PIN_PD23__RF1 PINMUX_PIN(PIN_PD23, 4, 2) +#define PIN_PD23__ISC_MCK PINMUX_PIN(PIN_PD23, 5, 2) +#define PIN_PD23__CANRX5 PINMUX_PIN(PIN_PD23, 6, 2) +#define PIN_PD23__G1_TX1 PINMUX_PIN(PIN_PD23, 7, 1) +#define PIN_PD24 120 +#define PIN_PD24__GPIO PINMUX_PIN(PIN_PD24, 0, 0) +#define PIN_PD24__PDMC0_DS1 PINMUX_PIN(PIN_PD24, 1, 2) +#define PIN_PD24__PWMFI0 PINMUX_PIN(PIN_PD24, 3, 4) +#define PIN_PD24__RK1 PINMUX_PIN(PIN_PD24, 4, 2) +#define PIN_PD24__ISC_D0 PINMUX_PIN(PIN_PD24, 5, 2) +#define PIN_PD24__G1_RXDV PINMUX_PIN(PIN_PD24, 7, 1) +#define PIN_PD25 121 +#define PIN_PD25__GPIO PINMUX_PIN(PIN_PD25, 0, 0) +#define PIN_PD25__PDMC1_CLK PINMUX_PIN(PIN_PD25, 1, 2) +#define PIN_PD25__FLEXCOM5_IO0 PINMUX_PIN(PIN_PD25, 2, 2) +#define PIN_PD25__PWMFI1 PINMUX_PIN(PIN_PD25, 3, 4) +#define PIN_PD25__TD1 PINMUX_PIN(PIN_PD25, 4, 2) +#define PIN_PD25__ISC_D1 PINMUX_PIN(PIN_PD25, 5, 2) +#define PIN_PD25__G1_RX0 PINMUX_PIN(PIN_PD25, 7, 1) +#define PIN_PD26 122 +#define PIN_PD26__GPIO PINMUX_PIN(PIN_PD26, 0, 0) +#define PIN_PD26__PDMC1_DS0 PINMUX_PIN(PIN_PD26, 1, 2) +#define PIN_PD26__FLEXCOM5_IO1 PINMUX_PIN(PIN_PD26, 2, 2) +#define PIN_PD26__ADTRG PINMUX_PIN(PIN_PD26, 3, 3) +#define PIN_PD26__TF1 PINMUX_PIN(PIN_PD26, 4, 2) +#define PIN_PD26__ISC_D2 PINMUX_PIN(PIN_PD26, 5, 2) +#define PIN_PD26__G1_RX1 PINMUX_PIN(PIN_PD26, 7, 1) +#define PIN_PD27 123 +#define PIN_PD27__GPIO PINMUX_PIN(PIN_PD27, 0, 0) +#define PIN_PD27__PDMC1_DS1 PINMUX_PIN(PIN_PD27, 1, 2) +#define PIN_PD27__FLEXCOM5_IO2 PINMUX_PIN(PIN_PD27, 2, 2) +#define PIN_PD27__TIOA0 PINMUX_PIN(PIN_PD27, 3, 3) +#define PIN_PD27__TK1 PINMUX_PIN(PIN_PD27, 4, 2) +#define PIN_PD27__ISC_D3 PINMUX_PIN(PIN_PD27, 5, 2) +#define PIN_PD27__G1_RXER PINMUX_PIN(PIN_PD27, 7, 1) +#define PIN_PD28 124 +#define PIN_PD28__GPIO PINMUX_PIN(PIN_PD28, 0, 0) +#define PIN_PD28__RD0 PINMUX_PIN(PIN_PD28, 1, 2) +#define PIN_PD28__FLEXCOM5_IO3 PINMUX_PIN(PIN_PD28, 2, 2) +#define PIN_PD28__TIOB0 PINMUX_PIN(PIN_PD28, 3, 3) +#define PIN_PD28__I2SMCC1_CK PINMUX_PIN(PIN_PD28, 4, 2) +#define PIN_PD28__ISC_D4 PINMUX_PIN(PIN_PD28, 5, 2) +#define PIN_PD28__PWML3 PINMUX_PIN(PIN_PD28, 6, 5) +#define PIN_PD28__G1_MDC PINMUX_PIN(PIN_PD28, 7, 1) +#define PIN_PD29 125 +#define PIN_PD29__GPIO PINMUX_PIN(PIN_PD29, 0, 0) +#define PIN_PD29__RF0 PINMUX_PIN(PIN_PD29, 1, 2) +#define PIN_PD29__FLEXCOM5_IO4 PINMUX_PIN(PIN_PD29, 2, 2) +#define PIN_PD29__TCLK0 PINMUX_PIN(PIN_PD29, 3, 3) +#define PIN_PD29__I2SMCC1_WS PINMUX_PIN(PIN_PD29, 4, 2) +#define PIN_PD29__ISC_D5 PINMUX_PIN(PIN_PD29, 5, 2) +#define PIN_PD29__PWMH3 PINMUX_PIN(PIN_PD29, 6, 5) +#define PIN_PD29__G1_MDIO PINMUX_PIN(PIN_PD29, 7, 1) +#define PIN_PD30 126 +#define PIN_PD30__GPIO PINMUX_PIN(PIN_PD30, 0, 0) +#define PIN_PD30__RK0 PINMUX_PIN(PIN_PD30, 1, 2) +#define PIN_PD30__FLEXCOM6_IO0 PINMUX_PIN(PIN_PD30, 2, 2) +#define PIN_PD30__TIOA1 PINMUX_PIN(PIN_PD30, 3, 3) +#define PIN_PD30__I2SMCC1_MCK PINMUX_PIN(PIN_PD30, 4, 2) +#define PIN_PD30__ISC_D6 PINMUX_PIN(PIN_PD30, 5, 2) +#define PIN_PD30__PWMEXTRG0 PINMUX_PIN(PIN_PD30, 6, 5) +#define PIN_PD30__G1_TXCK PINMUX_PIN(PIN_PD30, 7, 1) +#define PIN_PD31 127 +#define PIN_PD31__GPIO PINMUX_PIN(PIN_PD31, 0, 0) +#define PIN_PD31__TD0 PINMUX_PIN(PIN_PD31, 1, 2) +#define PIN_PD31__FLEXCOM6_IO1 PINMUX_PIN(PIN_PD31, 2, 2) +#define PIN_PD31__TIOB1 PINMUX_PIN(PIN_PD31, 3, 3) +#define PIN_PD31__I2SMCC1_DOUT0 PINMUX_PIN(PIN_PD31, 4, 2) +#define PIN_PD31__ISC_D7 PINMUX_PIN(PIN_PD31, 5, 2) +#define PIN_PD31__PWM_EXTRG1 PINMUX_PIN(PIN_PD31, 6, 5) +#define PIN_PD31__G1_TX2 PINMUX_PIN(PIN_PD31, 7, 1) +#define PIN_PE0 128 +#define PIN_PE0__GPIO PINMUX_PIN(PIN_PE0, 0, 0) +#define PIN_PE0__TF0 PINMUX_PIN(PIN_PE0, 1, 2) +#define PIN_PE0__FLEXCOM6_IO2 PINMUX_PIN(PIN_PE0, 2, 2) +#define PIN_PE0__TCLK1 PINMUX_PIN(PIN_PE0, 3, 3) +#define PIN_PE0__I2SMCC1_DOUT1 PINMUX_PIN(PIN_PE0, 4, 2) +#define PIN_PE0__ISC_HSYNC PINMUX_PIN(PIN_PE0, 5, 2) +#define PIN_PE0__PWMFI0 PINMUX_PIN(PIN_PE0, 6, 5) +#define PIN_PE0__G1_TX3 PINMUX_PIN(PIN_PE0, 7, 1) +#define PIN_PE1 129 +#define PIN_PE1__GPIO PINMUX_PIN(PIN_PE1, 0, 0) +#define PIN_PE1__TK0 PINMUX_PIN(PIN_PE1, 1, 2) +#define PIN_PE1__FLEXCOM6_IO3 PINMUX_PIN(PIN_PE1, 2, 2) +#define PIN_PE1__TIOA2 PINMUX_PIN(PIN_PE1, 3, 3) +#define PIN_PE1__I2SMCC1_DOUT2 PINMUX_PIN(PIN_PE1, 4, 2) +#define PIN_PE1__ISC_VSYNC PINMUX_PIN(PIN_PE1, 5, 2) +#define PIN_PE1__PWMFI1 PINMUX_PIN(PIN_PE1, 6, 5) +#define PIN_PE1__G1_RX2 PINMUX_PIN(PIN_PE1, 7, 1) +#define PIN_PE2 130 +#define PIN_PE2__GPIO PINMUX_PIN(PIN_PE2, 0, 0) +#define PIN_PE2__PWML0 PINMUX_PIN(PIN_PE2, 1, 5) +#define PIN_PE2__FLEXCOM6_IO4 PINMUX_PIN(PIN_PE2, 2, 2) +#define PIN_PE2__TIOB2 PINMUX_PIN(PIN_PE2, 3, 3) +#define PIN_PE2__I2SMCC1_DOUT3 PINMUX_PIN(PIN_PE2, 4, 2) +#define PIN_PE2__ISC_FIELD PINMUX_PIN(PIN_PE2, 5, 2) +#define PIN_PE2__G1_RX3 PINMUX_PIN(PIN_PE2, 7, 1) +#define PIN_PE3 131 +#define PIN_PE3__GPIO PINMUX_PIN(PIN_PE3, 0, 0) +#define PIN_PE3__PWMH0 PINMUX_PIN(PIN_PE3, 1, 5) +#define PIN_PE3__FLEXCOM0_IO0 PINMUX_PIN(PIN_PE3, 2, 4) +#define PIN_PE3__TCLK2 PINMUX_PIN(PIN_PE3, 3, 3) +#define PIN_PE3__I2SMCC1_DIN0 PINMUX_PIN(PIN_PE3, 4, 2) +#define PIN_PE3__ISC_PCK PINMUX_PIN(PIN_PE3, 5, 2) +#define PIN_PE3__G1_RXCK PINMUX_PIN(PIN_PE3, 7, 1) +#define PIN_PE4 132 +#define PIN_PE4__GPIO PINMUX_PIN(PIN_PE4, 0, 0) +#define PIN_PE4__PWML1 PINMUX_PIN(PIN_PE4, 1, 5) +#define PIN_PE4__FLEXCOM0_IO1 PINMUX_PIN(PIN_PE4, 2, 4) +#define PIN_PE4__TIOA3 PINMUX_PIN(PIN_PE4, 3, 3) +#define PIN_PE4__I2SMCC1_DIN1 PINMUX_PIN(PIN_PE4, 4, 2) +#define PIN_PE4__ISC_D8 PINMUX_PIN(PIN_PE4, 5, 2) +#define PIN_PE4__G1_TXER PINMUX_PIN(PIN_PE4, 7, 1) +#define PIN_PE5 133 +#define PIN_PE5__GPIO PINMUX_PIN(PIN_PE5, 0, 0) +#define PIN_PE5__PWMH1 PINMUX_PIN(PIN_PE5, 1, 5) +#define PIN_PE5__FLEXCOM0_IO2 PINMUX_PIN(PIN_PE5, 2, 4) +#define PIN_PE5__TIOB3 PINMUX_PIN(PIN_PE5, 3, 3) +#define PIN_PE5__I2SMCC1_DIN2 PINMUX_PIN(PIN_PE5, 4, 2) +#define PIN_PE5__ISC_D9 PINMUX_PIN(PIN_PE5, 5, 2) +#define PIN_PE5__G1_COL PINMUX_PIN(PIN_PE5, 7, 1) +#define PIN_PE6 134 +#define PIN_PE6__GPIO PINMUX_PIN(PIN_PE6, 0, 0) +#define PIN_PE6__PWML2 PINMUX_PIN(PIN_PE6, 1, 5) +#define PIN_PE6__FLEXCOM0_IO3 PINMUX_PIN(PIN_PE6, 2, 4) +#define PIN_PE6__TCLK3 PINMUX_PIN(PIN_PE6, 3, 3) +#define PIN_PE6__I2SMCC1_DIN3 PINMUX_PIN(PIN_PE6, 4, 2) +#define PIN_PE6__ISC_D10 PINMUX_PIN(PIN_PE6, 5, 2) +#define PIN_PE6__G1_CRS PINMUX_PIN(PIN_PE6, 7, 1) +#define PIN_PE7 135 +#define PIN_PE7__GPIO PINMUX_PIN(PIN_PE7, 0, 0) +#define PIN_PE7__PWMH2 PINMUX_PIN(PIN_PE7, 1, 5) +#define PIN_PE7__FLEXCOM0_IO4 PINMUX_PIN(PIN_PE7, 2, 4) +#define PIN_PE7__TIOA4 PINMUX_PIN(PIN_PE7, 3, 3) +#define PIN_PE7__ISC_D11 PINMUX_PIN(PIN_PE7, 5, 2) +#define PIN_PE7__G1_TSUCOMP PINMUX_PIN(PIN_PE7, 7, 1) + diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 85524004f9..be1415f909 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -47,6 +47,10 @@ config SAM9X60 bool select CPU_ARM926EJS +config SAMA7G5 + bool + select CPU_V7A + config SAMA5D2 bool select CPU_V7A diff --git a/arch/arm/mach-at91/armv7/Makefile b/arch/arm/mach-at91/armv7/Makefile index 9ced3dc0c1..55477560a8 100644 --- a/arch/arm/mach-at91/armv7/Makefile +++ b/arch/arm/mach-at91/armv7/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_SAMA5D2) += sama5d2_devices.o obj-$(CONFIG_SAMA5D3) += sama5d3_devices.o obj-$(CONFIG_SAMA5D4) += sama5d4_devices.o +obj-$(CONFIG_SAMA7G5) += sama7g5_devices.o obj-y += clock.o obj-y += cpu.o obj-y += reset.o diff --git a/arch/arm/mach-at91/armv7/sama7g5_devices.c b/arch/arm/mach-at91/armv7/sama7g5_devices.c new file mode 100644 index 0000000000..a58f671f72 --- /dev/null +++ b/arch/arm/mach-at91/armv7/sama7g5_devices.c @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Microchip Technology, Inc. + * Eugen Hristev + */ + +char *get_cpu_name(void) +{ + return "SAMA7G5"; +} + diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h index 88acca8549..0a16c8ff08 100644 --- a/arch/arm/mach-at91/include/mach/hardware.h +++ b/arch/arm/mach-at91/include/mach/hardware.h @@ -24,6 +24,8 @@ # include #elif defined(CONFIG_SAM9X60) # include +#elif defined(CONFIG_SAMA7G5) +# include #elif defined(CONFIG_SAMA5D2) # include #elif defined(CONFIG_SAMA5D3) diff --git a/arch/arm/mach-at91/include/mach/sama7g5.h b/arch/arm/mach-at91/include/mach/sama7g5.h new file mode 100644 index 0000000000..ae43e8700b --- /dev/null +++ b/arch/arm/mach-at91/include/mach/sama7g5.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Chip-specific header file for the SAMA7G5 SoC + * + * Copyright (C) 2020 Microchip Technology, Inc. and its subsidiaries + * Eugen Hristev + */ + +#ifndef __SAMA7G5_H__ +#define __SAMA7G5_H__ + +/* + * Peripheral identifiers/interrupts. + */ +#define ATMEL_ID_FLEXCOM0 38 +#define ATMEL_ID_FLEXCOM1 39 +#define ATMEL_ID_FLEXCOM2 40 +#define ATMEL_ID_FLEXCOM3 41 + +#define ATMEL_ID_SDMMC0 80 +#define ATMEL_ID_SDMMC1 81 + +#define ATMEL_ID_PIT64B0 70 +#define ATMEL_ID_PIT64B ATMEL_ID_PIT64B0 + +#define ATMEL_CHIPID_CIDR 0xe0020000 +#define ATMEL_CHIPID_EXID 0xe0020004 +/* + * User Peripherals physical base addresses. + */ +#define ATMEL_BASE_PIOA 0xe0014000 +#define ATMEL_BASE_PIOB (ATMEL_BASE_PIOA + 0x40) +#define ATMEL_BASE_PIOC (ATMEL_BASE_PIOB + 0x40) +#define ATMEL_BASE_PIOD (ATMEL_BASE_PIOC + 0x40) +#define ATMEL_BASE_PIOE (ATMEL_BASE_PIOD + 0x40) + +#define ATMEL_PIO_PORTS 5 + +#define CPU_HAS_PCR + +#define ATMEL_BASE_PMC 0xe0018000 + +#define ATMEL_BASE_WDT 0xe001c000 +#define ATMEL_BASE_RSTC 0xe001d000 +#define ATMEL_BASE_WDTS 0xe001d180 +#define ATMEL_BASE_SCKCR 0xe001d050 + +#define ATMEL_BASE_SDMMC0 0xe1204000 +#define ATMEL_BASE_SDMMC1 0xe1208000 + +#define ATMEL_BASE_PIT64B0 0xe1800000 + +#define ATMEL_BASE_FLEXCOM0 0xe1818000 +#define ATMEL_BASE_FLEXCOM1 0xe181c000 +#define ATMEL_BASE_FLEXCOM2 0xe1820000 +#define ATMEL_BASE_FLEXCOM3 0xe1824000 +#define ATMEL_BASE_FLEXCOM4 0xe2018000 + +#define ATMEL_BASE_TZC400 0xe3000000 + +#define ATMEL_BASE_UMCTL2 0xe3800000 +#define ATMEL_BASE_UMCTL2_MP 0xe38003f8 +#define ATMEL_BASE_PUBL 0xe3804000 + +#define ATMEL_NUM_FLEXCOM 12 +#define ATMEL_PIO_PORTS 5 + +#define ATMEL_BASE_PIT64BC ATMEL_BASE_PIT64B0 + +#ifndef __ASSEMBLY__ +char *get_cpu_name(void); +#endif + +#endif /* #ifndef __SAMA7G5_H__ */ From 63ef81625ea9553b0fea83cd7915ced8788d4fb4 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 27 Aug 2020 12:04:40 +0300 Subject: [PATCH 25/32] pinctrl: at91-pio4: add compatible for sama7g5 pinctrl block Add new compatible to microchip,sama7g5 new SoC. Signed-off-by: Eugen Hristev --- drivers/pinctrl/pinctrl-at91-pio4.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c index fdb7920b55..bf85cc916a 100644 --- a/drivers/pinctrl/pinctrl-at91-pio4.c +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -169,6 +169,7 @@ static int atmel_pinctrl_probe(struct udevice *dev) static const struct udevice_id atmel_pinctrl_match[] = { { .compatible = "atmel,sama5d2-pinctrl" }, + { .compatible = "microchip,sama7g5-pinctrl" }, {} }; From 4cc08258758c4d7f5a624aa99cb2435022def761 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 27 Aug 2020 12:04:41 +0300 Subject: [PATCH 26/32] mmc: atmel-sdhci: add sama7g5-sdhci compatibility string Add new compatibility string for matching sama7g5 product. Signed-off-by: Eugen Hristev Reviewed-by: Peng Fan --- drivers/mmc/atmel_sdhci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c index 0c53caf448..f03c0457e1 100644 --- a/drivers/mmc/atmel_sdhci.c +++ b/drivers/mmc/atmel_sdhci.c @@ -113,6 +113,7 @@ static int atmel_sdhci_bind(struct udevice *dev) static const struct udevice_id atmel_sdhci_ids[] = { { .compatible = "atmel,sama5d2-sdhci" }, { .compatible = "microchip,sam9x60-sdhci" }, + { .compatible = "microchip,sama7g5-sdhci" }, { } }; From 2e00608ca4cde8b39a92740539a7417814d851b4 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 27 Aug 2020 12:16:15 +0300 Subject: [PATCH 27/32] mmc: atmel-sdhci: do not check clk_set_rate return value clk_set_rate will return rate in case of success and zero in case of error, however it can also return -ev, but it's an ulong function. To avoid any issues, disregard the return value of this call. In case this call actually fails, nothing much we can do anyway, but we can at least try with the previous values (or DT assigned-clocks) Signed-off-by: Eugen Hristev --- drivers/mmc/atmel_sdhci.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c index f03c0457e1..54b660c34a 100644 --- a/drivers/mmc/atmel_sdhci.c +++ b/drivers/mmc/atmel_sdhci.c @@ -79,9 +79,7 @@ static int atmel_sdhci_probe(struct udevice *dev) if (ret) return ret; - ret = clk_set_rate(&clk, ATMEL_SDHC_GCK_RATE); - if (ret) - return ret; + clk_set_rate(&clk, ATMEL_SDHC_GCK_RATE); max_clk = clk_get_rate(&clk); if (!max_clk) From 81f16438d48f4690339ae47adc72dfcd4aa63ba0 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 27 Aug 2020 12:25:56 +0300 Subject: [PATCH 28/32] mmc: atmel-sdhci: enable the required generic clock The second clock of the IP block (the generic clock), must be explicitly enabled. Signed-off-by: Eugen Hristev Reviewed-by: Peng Fan --- drivers/mmc/atmel_sdhci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c index 54b660c34a..c67b065061 100644 --- a/drivers/mmc/atmel_sdhci.c +++ b/drivers/mmc/atmel_sdhci.c @@ -85,6 +85,10 @@ static int atmel_sdhci_probe(struct udevice *dev) if (!max_clk) return -EINVAL; + ret = clk_enable(&clk); + if (ret) + return ret; + host->max_clk = max_clk; host->mmc = &plat->mmc; host->mmc->dev = dev; From 3710b464e43abe27ed9ab40c39f98a309a7db055 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 27 Aug 2020 12:25:57 +0300 Subject: [PATCH 29/32] mmc: atmel-sdhci: use mmc_of_parse to get the DT properties Call mmc_of_parse at probe time to fetch all the host properties from the DT. Signed-off-by: Eugen Hristev Reviewed-by: Peng Fan --- drivers/mmc/atmel_sdhci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c index c67b065061..f56ae63bc2 100644 --- a/drivers/mmc/atmel_sdhci.c +++ b/drivers/mmc/atmel_sdhci.c @@ -89,6 +89,10 @@ static int atmel_sdhci_probe(struct udevice *dev) if (ret) return ret; + ret = mmc_of_parse(dev, &plat->cfg); + if (ret) + return ret; + host->max_clk = max_clk; host->mmc = &plat->mmc; host->mmc->dev = dev; From ed1b726683e7d9104498b724230ebeb6c533ba70 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 18:36:33 +0300 Subject: [PATCH 30/32] timer: mchp-pit64b: add support for pit64b Add support for Microchip PIT64B timer. The timer is 64 bit length and is used as a free running counter (in continuous mode with highest values for period registers). The clock feeding the timer would be no more than 12.5MHz. Signed-off-by: Claudiu Beznea --- drivers/timer/Kconfig | 7 ++ drivers/timer/Makefile | 1 + drivers/timer/mchp-pit64b-timer.c | 109 ++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 drivers/timer/mchp-pit64b-timer.c diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 637024445c..12020e4672 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -213,4 +213,11 @@ config MTK_TIMER Select this to enable support for the timer found on MediaTek devices. +config MCHP_PIT64B_TIMER + bool "Microchip 64-bit periodic interval timer support" + depends on TIMER + help + Select this to enable support for Microchip 64-bit periodic + interval timer. + endmenu diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index c22ffebcde..3a4d74b996 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_STI_TIMER) += sti-timer.o obj-$(CONFIG_STM32_TIMER) += stm32_timer.o obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o obj-$(CONFIG_MTK_TIMER) += mtk_timer.o +obj-$(CONFIG_MCHP_PIT64B_TIMER) += mchp-pit64b-timer.o diff --git a/drivers/timer/mchp-pit64b-timer.c b/drivers/timer/mchp-pit64b-timer.c new file mode 100644 index 0000000000..ead8c9b84a --- /dev/null +++ b/drivers/timer/mchp-pit64b-timer.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * 64-bit Periodic Interval Timer driver + * + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + */ + +#include +#include +#include +#include +#include + +#define MCHP_PIT64B_CR 0x00 /* Control Register */ +#define MCHP_PIT64B_CR_START BIT(0) +#define MCHP_PIT64B_CR_SWRST BIT(8) +#define MCHP_PIT64B_MR 0x04 /* Mode Register */ +#define MCHP_PIT64B_MR_CONT BIT(0) +#define MCHP_PIT64B_LSB_PR 0x08 /* LSB Period Register */ +#define MCHP_PIT64B_MSB_PR 0x0C /* MSB Period Register */ +#define MCHP_PIT64B_TLSBR 0x20 /* Timer LSB Register */ +#define MCHP_PIT64B_TMSBR 0x24 /* Timer MSB Register */ + +struct mchp_pit64b_priv { + void __iomem *base; +}; + +static int mchp_pit64b_get_count(struct udevice *dev, u64 *count) +{ + struct mchp_pit64b_priv *priv = dev_get_priv(dev); + + u32 lsb = readl(priv->base + MCHP_PIT64B_TLSBR); + u32 msb = readl(priv->base + MCHP_PIT64B_TMSBR); + + *count = ((u64)msb << 32) | lsb; + + return 0; +} + +static int mchp_pit64b_probe(struct udevice *dev) +{ + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct mchp_pit64b_priv *priv = dev_get_priv(dev); + struct clk clk; + ulong rate; + int ret; + + priv->base = dev_read_addr_ptr(dev); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + return ret; + + rate = clk_get_rate(&clk); + if (!rate) { + clk_disable(&clk); + return -ENOTSUPP; + } + + /* Reset the timer in case it was used by previous bootloaders. */ + writel(MCHP_PIT64B_CR_SWRST, priv->base + MCHP_PIT64B_CR); + + /* + * Use highest prescaller (for a peripheral clock running at 200MHz + * this will lead to the timer running at 12.5MHz) and continuous mode. + */ + writel((15 << 8) | MCHP_PIT64B_MR_CONT, priv->base + MCHP_PIT64B_MR); + uc_priv->clock_rate = rate / 16; + + /* + * Simulate free running counter by setting max values to period + * registers. + */ + writel(~0UL, priv->base + MCHP_PIT64B_MSB_PR); + writel(~0UL, priv->base + MCHP_PIT64B_LSB_PR); + + /* Start the timer. */ + writel(MCHP_PIT64B_CR_START, priv->base + MCHP_PIT64B_CR); + + return 0; +} + +static const struct timer_ops mchp_pit64b_ops = { + .get_count = mchp_pit64b_get_count, +}; + +static const struct udevice_id mchp_pit64b_ids[] = { + { .compatible = "microchip,sam9x60-pit64b", }, + { .compatible = "microchip,sama7g5-pit64b", }, + { } +}; + +U_BOOT_DRIVER(mchp_pit64b) = { + .name = "mchp-pit64b", + .id = UCLASS_TIMER, + .of_match = mchp_pit64b_ids, + .priv_auto_alloc_size = sizeof(struct mchp_pit64b_priv), + .probe = mchp_pit64b_probe, + .ops = &mchp_pit64b_ops, + .flags = DM_FLAG_PRE_RELOC, +}; From 96b9a5cdf8aa4c2dfbbbf496f20dc60cc78adf1a Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 23 Sep 2020 13:17:21 +0300 Subject: [PATCH 31/32] MAINTAINERS: add Microchip PIT64B timer Add Microchip PIT64B timer. Signed-off-by: Claudiu Beznea --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7e46470c70..85e51855c4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -292,6 +292,7 @@ T: git https://gitlab.denx.de/u-boot/custodians/u-boot-atmel.git F: arch/arm/mach-at91/ F: board/atmel/ F: drivers/misc/microchip_flexcom.c +F: drivers/timer/mchp-pit64b-timer.c ARM NEXELL S5P4418 M: Stefan Bosch From 01c35f269f21398fa9d1db1b90b73f7e95a3bf22 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 1 Oct 2020 13:27:25 +0300 Subject: [PATCH 32/32] cpu: at91: add driver for CPU Add basic CPU driver use to retrieve information about CPU itself. Signed-off-by: Claudiu Beznea --- MAINTAINERS | 1 + drivers/cpu/Makefile | 1 + drivers/cpu/at91_cpu.c | 123 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 drivers/cpu/at91_cpu.c diff --git a/MAINTAINERS b/MAINTAINERS index 85e51855c4..91b06b49bd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -291,6 +291,7 @@ S: Maintained T: git https://gitlab.denx.de/u-boot/custodians/u-boot-atmel.git F: arch/arm/mach-at91/ F: board/atmel/ +F: drivers/cpu/at91_cpu.c F: drivers/misc/microchip_flexcom.c F: drivers/timer/mchp-pit64b-timer.c diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile index 0b5dbc7c88..c8532637ca 100644 --- a/drivers/cpu/Makefile +++ b/drivers/cpu/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_CPU) += cpu-uclass.o obj-$(CONFIG_ARCH_BMIPS) += bmips_cpu.o obj-$(CONFIG_ARCH_IMX8) += imx8_cpu.o +obj-$(CONFIG_ARCH_AT91) += at91_cpu.o obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o obj-$(CONFIG_CPU_RISCV) += riscv_cpu.o obj-$(CONFIG_SANDBOX) += cpu_sandbox.o diff --git a/drivers/cpu/at91_cpu.c b/drivers/cpu/at91_cpu.c new file mode 100644 index 0000000000..058ae3a811 --- /dev/null +++ b/drivers/cpu/at91_cpu.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries + * + * Author: Claudiu Beznea + */ + +#include +#include +#include +#include +#include + +struct at91_cpu_platdata { + const char *name; + ulong cpufreq_mhz; + ulong mckfreq_mhz; + ulong xtalfreq_mhz; +}; + +extern char *get_cpu_name(void); + +const char *at91_cpu_get_name(void) +{ + return get_cpu_name(); +} + +int at91_cpu_get_desc(const struct udevice *dev, char *buf, int size) +{ + struct at91_cpu_platdata *plat = dev_get_platdata(dev); + + snprintf(buf, size, "%s\n" + "Crystal frequency: %8lu MHz\n" + "CPU clock : %8lu MHz\n" + "Master clock : %8lu MHz\n", + plat->name, plat->xtalfreq_mhz, plat->cpufreq_mhz, + plat->mckfreq_mhz); + + return 0; +} + +static int at91_cpu_get_info(const struct udevice *dev, struct cpu_info *info) +{ + struct at91_cpu_platdata *plat = dev_get_platdata(dev); + + info->cpu_freq = plat->cpufreq_mhz * 1000000; + info->features = BIT(CPU_FEAT_L1_CACHE); + + return 0; +} + +static int at91_cpu_get_count(const struct udevice *dev) +{ + return 1; +} + +static int at91_cpu_get_vendor(const struct udevice *dev, char *buf, int size) +{ + snprintf(buf, size, "Microchip Technology Inc."); + + return 0; +} + +static const struct cpu_ops at91_cpu_ops = { + .get_desc = at91_cpu_get_desc, + .get_info = at91_cpu_get_info, + .get_count = at91_cpu_get_count, + .get_vendor = at91_cpu_get_vendor, +}; + +static const struct udevice_id at91_cpu_ids[] = { + { .compatible = "arm,cortex-a7" }, + { /* Sentinel. */ } +}; + +static int at91_cpu_probe(struct udevice *dev) +{ + struct at91_cpu_platdata *plat = dev_get_platdata(dev); + struct clk clk; + ulong rate; + int ret; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + rate = clk_get_rate(&clk); + if (!rate) + return -ENOTSUPP; + plat->cpufreq_mhz = DIV_ROUND_CLOSEST_ULL(rate, 1000000); + + ret = clk_get_by_index(dev, 1, &clk); + if (ret) + return ret; + + rate = clk_get_rate(&clk); + if (!rate) + return -ENOTSUPP; + plat->mckfreq_mhz = DIV_ROUND_CLOSEST_ULL(rate, 1000000); + + ret = clk_get_by_index(dev, 2, &clk); + if (ret) + return ret; + + rate = clk_get_rate(&clk); + if (!rate) + return -ENOTSUPP; + plat->xtalfreq_mhz = DIV_ROUND_CLOSEST_ULL(rate, 1000000); + + plat->name = get_cpu_name(); + + return 0; +} + +U_BOOT_DRIVER(cpu_at91_drv) = { + .name = "at91-cpu", + .id = UCLASS_CPU, + .of_match = at91_cpu_ids, + .ops = &at91_cpu_ops, + .probe = at91_cpu_probe, + .platdata_auto_alloc_size = sizeof(struct at91_cpu_platdata), + .flags = DM_FLAG_PRE_RELOC, +};