From dfaf6a57974f5b4bcdc2a2a347b192573ffb5135 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 12 Aug 2020 11:55:46 +0200 Subject: CONFIG_NR_DRAM_BANKS: Remove unreferenced code as its always defined MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 86cf1c82850f ("configs: Migrate CONFIG_NR_DRAM_BANKS") & commit 999a772d9f24 ("Kconfig: Migrate CONFIG_NR_DRAM_BANKS"), CONFIG_NR_DRAM_BANKS is always defined with a value (4 is default). It makes no sense to still carry code that is guarded with "#ifndef CONFIG_NR_DRAM_BANKS" (and similar). This patch removes all these unreferenced code paths. Signed-off-by: Stefan Roese Reviewed-by: Pali Rohár Reviewed-by: Andy Shevchenko Reviewed-by: Bin Meng --- drivers/pci/pci-uclass.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index d8a6647a1d..eb07d25301 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -911,8 +911,8 @@ static void decode_regions(struct pci_controller *hose, ofnode parent_node, ofnode node) { int pci_addr_cells, addr_cells, size_cells; - struct bd_info *bd = gd->bd; int cells_per_record; + struct bd_info *bd; const u32 *prop; int max_regions; int len; @@ -989,6 +989,7 @@ static void decode_regions(struct pci_controller *hose, ofnode parent_node, } /* Add a region for our local memory */ + bd = gd->bd; if (!bd) return; -- cgit v1.2.3 From 063d547cac33bd9393c395ea57871a744ab78c1d Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 12 Aug 2020 13:32:41 +0200 Subject: video: cfb_console.c: Use bi_dram[] values on all platforms All platforms support bi_dram[] since quite some time. Lets remove the and bi_memsize values completely. Signed-off-by: Stefan Roese Reviewed-by: Simon Glass --- drivers/video/cfb_console.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index badade353e..3f07f4eb29 100644 --- a/drivers/video/cfb_console.c +++ b/drivers/video/cfb_console.c @@ -1983,8 +1983,6 @@ static void *video_logo(void) static int cfb_fb_is_in_dram(void) { struct bd_info *bd = gd->bd; -#if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || \ -defined(CONFIG_SANDBOX) || defined(CONFIG_X86) ulong start, end; int i; @@ -1995,11 +1993,7 @@ defined(CONFIG_SANDBOX) || defined(CONFIG_X86) (ulong)video_fb_address < end) return 1; } -#else - if ((ulong)video_fb_address >= bd->bi_memstart && - (ulong)video_fb_address < bd->bi_memstart + bd->bi_memsize) - return 1; -#endif + return 0; } -- cgit v1.2.3 From 2041ae5a5a84a2461b4754250d4301d8d0533fdd Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 3 Jul 2020 17:36:40 +0200 Subject: phy: generic: add error trace to detect PHY issue in uclass Add an error trace for PHY errors directly in generic phy functions provided by PHY uclass. Signed-off-by: Patrick Delaunay --- drivers/phy/phy-uclass.c | 45 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index db7f39cd0b..8f456f33d2 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -117,56 +117,91 @@ int generic_phy_get_by_name(struct udevice *dev, const char *phy_name, int generic_phy_init(struct phy *phy) { struct phy_ops const *ops; + int ret; if (!generic_phy_valid(phy)) return 0; ops = phy_dev_ops(phy->dev); + if (!ops->init) + return 0; + ret = ops->init(phy); + if (ret) + dev_err(phy->dev, "PHY: Failed to init %s: %d.\n", + phy->dev->name, ret); - return ops->init ? ops->init(phy) : 0; + return ret; } int generic_phy_reset(struct phy *phy) { struct phy_ops const *ops; + int ret; if (!generic_phy_valid(phy)) return 0; ops = phy_dev_ops(phy->dev); + if (!ops->reset) + return 0; + ret = ops->reset(phy); + if (ret) + dev_err(phy->dev, "PHY: Failed to reset %s: %d.\n", + phy->dev->name, ret); - return ops->reset ? ops->reset(phy) : 0; + return ret; } int generic_phy_exit(struct phy *phy) { struct phy_ops const *ops; + int ret; if (!generic_phy_valid(phy)) return 0; ops = phy_dev_ops(phy->dev); + if (!ops->exit) + return 0; + ret = ops->exit(phy); + if (ret) + dev_err(phy->dev, "PHY: Failed to exit %s: %d.\n", + phy->dev->name, ret); - return ops->exit ? ops->exit(phy) : 0; + return ret; } int generic_phy_power_on(struct phy *phy) { struct phy_ops const *ops; + int ret; if (!generic_phy_valid(phy)) return 0; ops = phy_dev_ops(phy->dev); + if (!ops->power_on) + return 0; + ret = ops->power_on(phy); + if (ret) + dev_err(phy->dev, "PHY: Failed to power on %s: %d.\n", + phy->dev->name, ret); - return ops->power_on ? ops->power_on(phy) : 0; + return ret; } int generic_phy_power_off(struct phy *phy) { struct phy_ops const *ops; + int ret; if (!generic_phy_valid(phy)) return 0; ops = phy_dev_ops(phy->dev); + if (!ops->power_off) + return 0; + ret = ops->power_off(phy); + if (ret) + dev_err(phy->dev, "PHY: Failed to power off %s: %d.\n", + phy->dev->name, ret); - return ops->power_off ? ops->power_off(phy) : 0; + return ret; } int generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk) -- cgit v1.2.3 From 3b417a7d8298a79b147fec92b76fb90f74e7c732 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 3 Jul 2020 17:36:42 +0200 Subject: usb: host: ohci: change trace level for phy errors managed by uclass As the error message is now displayed by generic phy functions, the dev_err can be change to dev_dbg. Signed-off-by: Patrick Delaunay --- drivers/usb/host/ohci-generic.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c index b84bf8ac0f..ed5e500b2c 100644 --- a/drivers/usb/host/ohci-generic.c +++ b/drivers/usb/host/ohci-generic.c @@ -41,13 +41,13 @@ static int ohci_setup_phy(struct udevice *dev, int index) } else { ret = generic_phy_init(&priv->phy); if (ret) { - dev_err(dev, "failed to init usb phy\n"); + dev_dbg(dev, "failed to init usb phy\n"); return ret; } ret = generic_phy_power_on(&priv->phy); if (ret) { - dev_err(dev, "failed to power on usb phy\n"); + dev_dbg(dev, "failed to power on usb phy\n"); return generic_phy_exit(&priv->phy); } } @@ -63,13 +63,13 @@ static int ohci_shutdown_phy(struct udevice *dev) if (generic_phy_valid(&priv->phy)) { ret = generic_phy_power_off(&priv->phy); if (ret) { - dev_err(dev, "failed to power off usb phy\n"); + dev_dbg(dev, "failed to power off usb phy\n"); return ret; } ret = generic_phy_exit(&priv->phy); if (ret) { - dev_err(dev, "failed to power off usb phy\n"); + dev_dbg(dev, "failed to power off usb phy\n"); return ret; } } -- cgit v1.2.3 From 890fc370a9c922fbf529b2dc2ee48da3da4704ff Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 3 Jul 2020 17:36:43 +0200 Subject: usb: host: ehci-hcd: change trace level for phy errors managed by uclass As the error message is now displayed by generic phy functions, the pr_err can be change to pr_debug. Signed-off-by: Patrick Delaunay --- drivers/usb/host/ehci-hcd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index f79f06320b..8933f60843 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1762,13 +1762,13 @@ int ehci_setup_phy(struct udevice *dev, struct phy *phy, int index) } else { ret = generic_phy_init(phy); if (ret) { - dev_err(dev, "failed to init usb phy\n"); + dev_dbg(dev, "failed to init usb phy\n"); return ret; } ret = generic_phy_power_on(phy); if (ret) { - dev_err(dev, "failed to power on usb phy\n"); + dev_dbg(dev, "failed to power on usb phy\n"); return generic_phy_exit(phy); } } @@ -1786,13 +1786,13 @@ int ehci_shutdown_phy(struct udevice *dev, struct phy *phy) if (generic_phy_valid(phy)) { ret = generic_phy_power_off(phy); if (ret) { - dev_err(dev, "failed to power off usb phy\n"); + dev_dbg(dev, "failed to power off usb phy\n"); return ret; } ret = generic_phy_exit(phy); if (ret) { - dev_err(dev, "failed to power off usb phy\n"); + dev_dbg(dev, "failed to power off usb phy\n"); return ret; } } -- cgit v1.2.3 From fc8ead1a0af42be784f75917231752c6c74cf15f Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 3 Jul 2020 17:36:44 +0200 Subject: ata: dwc-ahci: change trace level for phy errors managed by uclass As the error message is now displayed by generic phy functions, the pr_err can be change to pr_debug. Signed-off-by: Patrick Delaunay --- drivers/ata/dwc_ahci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/dwc_ahci.c b/drivers/ata/dwc_ahci.c index 825fe57f85..ed0527c976 100644 --- a/drivers/ata/dwc_ahci.c +++ b/drivers/ata/dwc_ahci.c @@ -62,13 +62,13 @@ static int dwc_ahci_probe(struct udevice *dev) ret = generic_phy_init(&phy); if (ret) { - pr_err("unable to initialize the sata phy\n"); + pr_debug("unable to initialize the sata phy\n"); return ret; } ret = generic_phy_power_on(&phy); if (ret) { - pr_err("unable to power on the sata phy\n"); + pr_debug("unable to power on the sata phy\n"); return ret; } -- cgit v1.2.3 From c1e1dbb8f3e8e278c61d7bfc3a41973c7e87377c Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 3 Jul 2020 17:36:45 +0200 Subject: usb: musb-new: sunxi: change trace level for phy errors managed by uclass As the error message is now displayed by generic phy functions, the dev_err/pr_err can be change to dev_dbg/pr_debug. Signed-off-by: Patrick Delaunay --- drivers/usb/musb-new/sunxi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c index 53c336fc3f..06a55bf6ee 100644 --- a/drivers/usb/musb-new/sunxi.c +++ b/drivers/usb/musb-new/sunxi.c @@ -257,7 +257,7 @@ static int sunxi_musb_enable(struct musb *musb) ret = generic_phy_power_on(&glue->phy); if (ret) { - pr_err("failed to power on USB PHY\n"); + pr_debug("failed to power on USB PHY\n"); return ret; } } @@ -281,7 +281,7 @@ static void sunxi_musb_disable(struct musb *musb) if (is_host_enabled(musb)) { ret = generic_phy_power_off(&glue->phy); if (ret) { - pr_err("failed to power off USB PHY\n"); + pr_debug("failed to power off USB PHY\n"); return; } } @@ -315,7 +315,7 @@ static int sunxi_musb_init(struct musb *musb) ret = generic_phy_init(&glue->phy); if (ret) { - dev_err(dev, "failed to init USB PHY\n"); + dev_dbg(dev, "failed to init USB PHY\n"); goto err_rst; } @@ -352,7 +352,7 @@ static int sunxi_musb_exit(struct musb *musb) if (generic_phy_valid(&glue->phy)) { ret = generic_phy_exit(&glue->phy); if (ret) { - dev_err(dev, "failed to power off usb phy\n"); + dev_dbg(dev, "failed to power off usb phy\n"); return ret; } } -- cgit v1.2.3 From 15b87feb2b7923ef679e9da3f956e7a836fbaa40 Mon Sep 17 00:00:00 2001 From: Ryan Chen Date: Mon, 31 Aug 2020 14:03:03 +0800 Subject: cosmetic: aspeed: ast2500: Rename clock header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the ast2500-scu.h to aspeed-clock.h. Signed-off-by: Ryan Chen Reviewed-by: Chia-Wei, Wang Reviewed-by: Cédric Le Goater --- arch/arm/dts/ast2500-u-boot.dtsi | 2 +- arch/arm/mach-aspeed/ast2500/sdram_ast2500.c | 2 +- drivers/clk/aspeed/clk_ast2500.c | 2 +- include/dt-bindings/clock/aspeed-clock.h | 30 ++++++++++++++++++++++++++++ include/dt-bindings/clock/ast2500-scu.h | 30 ---------------------------- 5 files changed, 33 insertions(+), 33 deletions(-) create mode 100644 include/dt-bindings/clock/aspeed-clock.h delete mode 100644 include/dt-bindings/clock/ast2500-scu.h (limited to 'drivers') diff --git a/arch/arm/dts/ast2500-u-boot.dtsi b/arch/arm/dts/ast2500-u-boot.dtsi index 8ac4215745..3b119e4ace 100644 --- a/arch/arm/dts/ast2500-u-boot.dtsi +++ b/arch/arm/dts/ast2500-u-boot.dtsi @@ -1,4 +1,4 @@ -#include +#include #include #include "ast2500.dtsi" diff --git a/arch/arm/mach-aspeed/ast2500/sdram_ast2500.c b/arch/arm/mach-aspeed/ast2500/sdram_ast2500.c index a3adaa8a99..8536a70a19 100644 --- a/arch/arm/mach-aspeed/ast2500/sdram_ast2500.c +++ b/arch/arm/mach-aspeed/ast2500/sdram_ast2500.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include /* These configuration parameters are taken from Aspeed SDK */ #define DDR4_MR46_MODE 0x08000000 diff --git a/drivers/clk/aspeed/clk_ast2500.c b/drivers/clk/aspeed/clk_ast2500.c index d1940f1884..392fe76b27 100644 --- a/drivers/clk/aspeed/clk_ast2500.c +++ b/drivers/clk/aspeed/clk_ast2500.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/clock/aspeed-clock.h new file mode 100644 index 0000000000..4803abe9f6 --- /dev/null +++ b/include/dt-bindings/clock/aspeed-clock.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2016 Google Inc. + */ + +/* Core Clocks */ +#define PLL_HPLL 1 +#define PLL_DPLL 2 +#define PLL_D2PLL 3 +#define PLL_MPLL 4 +#define ARMCLK 5 + + +/* Bus Clocks, derived from core clocks */ +#define BCLK_PCLK 101 +#define BCLK_LHCLK 102 +#define BCLK_MACCLK 103 +#define BCLK_SDCLK 104 +#define BCLK_ARMCLK 105 + +#define MCLK_DDR 201 + +/* Special clocks */ +#define PCLK_UART1 501 +#define PCLK_UART2 502 +#define PCLK_UART3 503 +#define PCLK_UART4 504 +#define PCLK_UART5 505 +#define PCLK_MAC1 506 +#define PCLK_MAC2 507 diff --git a/include/dt-bindings/clock/ast2500-scu.h b/include/dt-bindings/clock/ast2500-scu.h deleted file mode 100644 index 4803abe9f6..0000000000 --- a/include/dt-bindings/clock/ast2500-scu.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright 2016 Google Inc. - */ - -/* Core Clocks */ -#define PLL_HPLL 1 -#define PLL_DPLL 2 -#define PLL_D2PLL 3 -#define PLL_MPLL 4 -#define ARMCLK 5 - - -/* Bus Clocks, derived from core clocks */ -#define BCLK_PCLK 101 -#define BCLK_LHCLK 102 -#define BCLK_MACCLK 103 -#define BCLK_SDCLK 104 -#define BCLK_ARMCLK 105 - -#define MCLK_DDR 201 - -/* Special clocks */ -#define PCLK_UART1 501 -#define PCLK_UART2 502 -#define PCLK_UART3 503 -#define PCLK_UART4 504 -#define PCLK_UART5 505 -#define PCLK_MAC1 506 -#define PCLK_MAC2 507 -- cgit v1.2.3 From c39c9a94cba01d9fbbe359a8922d2ae85061a4e1 Mon Sep 17 00:00:00 2001 From: Ryan Chen Date: Mon, 31 Aug 2020 14:03:04 +0800 Subject: clock:aspeed: Sync with Linux kernel clock header define v2: modify title description aspeed:clock -> clock:aspeed Use kernel include/dt-bindings/clock/aspeed-clock.h define for clock driver. Signed-off-by: Ryan Chen Reviewed-by: Chia-Wei, Wang --- arch/arm/dts/ast2500-u-boot.dtsi | 20 +++++----- drivers/clk/aspeed/clk_ast2500.c | 38 +++++++++--------- include/dt-bindings/clock/aspeed-clock.h | 68 +++++++++++++++++++------------- 3 files changed, 68 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/arch/arm/dts/ast2500-u-boot.dtsi b/arch/arm/dts/ast2500-u-boot.dtsi index 3b119e4ace..29b08f16ac 100644 --- a/arch/arm/dts/ast2500-u-boot.dtsi +++ b/arch/arm/dts/ast2500-u-boot.dtsi @@ -25,7 +25,7 @@ reg = <0x1e6e0000 0x174 0x1e6e0200 0x1d4 >; #reset-cells = <1>; - clocks = <&scu PLL_MPLL>; + clocks = <&scu ASPEED_CLK_MPLL>; resets = <&rst AST_RESET_SDRAM>; }; @@ -39,7 +39,7 @@ compatible = "aspeed,ast2500-sdhci"; reg = <0x1e740100>; #reset-cells = <1>; - clocks = <&scu BCLK_SDCLK>; + clocks = <&scu ASPEED_CLK_SDIO>; resets = <&rst AST_RESET_SDIO>; }; @@ -47,7 +47,7 @@ compatible = "aspeed,ast2500-sdhci"; reg = <0x1e740200>; #reset-cells = <1>; - clocks = <&scu BCLK_SDCLK>; + clocks = <&scu ASPEED_CLK_SDIO>; resets = <&rst AST_RESET_SDIO>; }; }; @@ -56,23 +56,23 @@ }; &uart1 { - clocks = <&scu PCLK_UART1>; + clocks = <&scu ASPEED_CLK_GATE_UART1CLK>; }; &uart2 { - clocks = <&scu PCLK_UART2>; + clocks = <&scu ASPEED_CLK_GATE_UART2CLK>; }; &uart3 { - clocks = <&scu PCLK_UART3>; + clocks = <&scu ASPEED_CLK_GATE_UART3CLK>; }; &uart4 { - clocks = <&scu PCLK_UART4>; + clocks = <&scu ASPEED_CLK_GATE_UART4CLK>; }; &uart5 { - clocks = <&scu PCLK_UART5>; + clocks = <&scu ASPEED_CLK_GATE_UART5CLK>; }; &timer { @@ -80,9 +80,9 @@ }; &mac0 { - clocks = <&scu PCLK_MAC1>, <&scu PLL_D2PLL>; + clocks = <&scu ASPEED_CLK_GATE_MAC1CLK>, <&scu ASPEED_CLK_D2PLL>; }; &mac1 { - clocks = <&scu PCLK_MAC2>, <&scu PLL_D2PLL>; + clocks = <&scu ASPEED_CLK_GATE_MAC1CLK>, <&scu ASPEED_CLK_D2PLL>; }; diff --git a/drivers/clk/aspeed/clk_ast2500.c b/drivers/clk/aspeed/clk_ast2500.c index 392fe76b27..aab7d14deb 100644 --- a/drivers/clk/aspeed/clk_ast2500.c +++ b/drivers/clk/aspeed/clk_ast2500.c @@ -122,8 +122,7 @@ static ulong ast2500_clk_get_rate(struct clk *clk) ulong rate; switch (clk->id) { - case PLL_HPLL: - case ARMCLK: + case ASPEED_CLK_HPLL: /* * This ignores dynamic/static slowdown of ARMCLK and may * be inaccurate. @@ -131,11 +130,11 @@ static ulong ast2500_clk_get_rate(struct clk *clk) rate = ast2500_get_hpll_rate(clkin, readl(&priv->scu->h_pll_param)); break; - case MCLK_DDR: + case ASPEED_CLK_MPLL: rate = ast2500_get_mpll_rate(clkin, readl(&priv->scu->m_pll_param)); break; - case BCLK_PCLK: + case ASPEED_CLK_APB: { ulong apb_div = 4 + 4 * ((readl(&priv->scu->clk_sel1) & SCU_PCLK_DIV_MASK) @@ -146,7 +145,7 @@ static ulong ast2500_clk_get_rate(struct clk *clk) rate = rate / apb_div; } break; - case BCLK_SDCLK: + case ASPEED_CLK_SDIO: { ulong apb_div = 4 + 4 * ((readl(&priv->scu->clk_sel1) & SCU_SDCLK_DIV_MASK) @@ -157,19 +156,19 @@ static ulong ast2500_clk_get_rate(struct clk *clk) rate = rate / apb_div; } break; - case PCLK_UART1: + case ASPEED_CLK_GATE_UART1CLK: rate = ast2500_get_uart_clk_rate(priv->scu, 1); break; - case PCLK_UART2: + case ASPEED_CLK_GATE_UART2CLK: rate = ast2500_get_uart_clk_rate(priv->scu, 2); break; - case PCLK_UART3: + case ASPEED_CLK_GATE_UART3CLK: rate = ast2500_get_uart_clk_rate(priv->scu, 3); break; - case PCLK_UART4: + case ASPEED_CLK_GATE_UART4CLK: rate = ast2500_get_uart_clk_rate(priv->scu, 4); break; - case PCLK_UART5: + case ASPEED_CLK_GATE_UART5CLK: rate = ast2500_get_uart_clk_rate(priv->scu, 5); break; default: @@ -431,11 +430,10 @@ static ulong ast2500_clk_set_rate(struct clk *clk, ulong rate) ulong new_rate; switch (clk->id) { - case PLL_MPLL: - case MCLK_DDR: + case ASPEED_CLK_MPLL: new_rate = ast2500_configure_ddr(priv->scu, rate); break; - case PLL_D2PLL: + case ASPEED_CLK_D2PLL: new_rate = ast2500_configure_d2pll(priv->scu, rate); break; default: @@ -450,7 +448,7 @@ static int ast2500_clk_enable(struct clk *clk) struct ast2500_clk_priv *priv = dev_get_priv(clk->dev); switch (clk->id) { - case BCLK_SDCLK: + case ASPEED_CLK_SDIO: if (readl(&priv->scu->clk_stop_ctrl1) & SCU_CLKSTOP_SDCLK) { ast_scu_unlock(priv->scu); @@ -471,13 +469,13 @@ static int ast2500_clk_enable(struct clk *clk) * configured based on whether RGMII or RMII mode has been selected * through hardware strapping. */ - case PCLK_MAC1: + case ASPEED_CLK_GATE_MAC1CLK: ast2500_configure_mac(priv->scu, 1); break; - case PCLK_MAC2: + case ASPEED_CLK_GATE_MAC2CLK: ast2500_configure_mac(priv->scu, 2); break; - case PLL_D2PLL: + case ASPEED_CLK_D2PLL: ast2500_configure_d2pll(priv->scu, D2PLL_DEFAULT_RATE); break; default: @@ -497,9 +495,9 @@ static int ast2500_clk_ofdata_to_platdata(struct udevice *dev) { struct ast2500_clk_priv *priv = dev_get_priv(dev); - priv->scu = dev_read_addr_ptr(dev); - if (!priv->scu) - return -EINVAL; + priv->scu = devfdt_get_addr_ptr(dev); + if (IS_ERR(priv->scu)) + return PTR_ERR(priv->scu); return 0; } diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/clock/aspeed-clock.h index 4803abe9f6..e6599deeb9 100644 --- a/include/dt-bindings/clock/aspeed-clock.h +++ b/include/dt-bindings/clock/aspeed-clock.h @@ -1,30 +1,42 @@ /* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright 2016 Google Inc. - */ -/* Core Clocks */ -#define PLL_HPLL 1 -#define PLL_DPLL 2 -#define PLL_D2PLL 3 -#define PLL_MPLL 4 -#define ARMCLK 5 - - -/* Bus Clocks, derived from core clocks */ -#define BCLK_PCLK 101 -#define BCLK_LHCLK 102 -#define BCLK_MACCLK 103 -#define BCLK_SDCLK 104 -#define BCLK_ARMCLK 105 - -#define MCLK_DDR 201 - -/* Special clocks */ -#define PCLK_UART1 501 -#define PCLK_UART2 502 -#define PCLK_UART3 503 -#define PCLK_UART4 504 -#define PCLK_UART5 505 -#define PCLK_MAC1 506 -#define PCLK_MAC2 507 +#define ASPEED_CLK_GATE_ECLK 0 +#define ASPEED_CLK_GATE_GCLK 1 +#define ASPEED_CLK_GATE_MCLK 2 +#define ASPEED_CLK_GATE_VCLK 3 +#define ASPEED_CLK_GATE_BCLK 4 +#define ASPEED_CLK_GATE_DCLK 5 +#define ASPEED_CLK_GATE_REFCLK 6 +#define ASPEED_CLK_GATE_USBPORT2CLK 7 +#define ASPEED_CLK_GATE_LCLK 8 +#define ASPEED_CLK_GATE_USBUHCICLK 9 +#define ASPEED_CLK_GATE_D1CLK 10 +#define ASPEED_CLK_GATE_YCLK 11 +#define ASPEED_CLK_GATE_USBPORT1CLK 12 +#define ASPEED_CLK_GATE_UART1CLK 13 +#define ASPEED_CLK_GATE_UART2CLK 14 +#define ASPEED_CLK_GATE_UART5CLK 15 +#define ASPEED_CLK_GATE_ESPICLK 16 +#define ASPEED_CLK_GATE_MAC1CLK 17 +#define ASPEED_CLK_GATE_MAC2CLK 18 +#define ASPEED_CLK_GATE_RSACLK 19 +#define ASPEED_CLK_GATE_UART3CLK 20 +#define ASPEED_CLK_GATE_UART4CLK 21 +#define ASPEED_CLK_GATE_SDCLK 22 +#define ASPEED_CLK_GATE_LHCCLK 23 +#define ASPEED_CLK_HPLL 24 +#define ASPEED_CLK_AHB 25 +#define ASPEED_CLK_APB 26 +#define ASPEED_CLK_UART 27 +#define ASPEED_CLK_SDIO 28 +#define ASPEED_CLK_ECLK 29 +#define ASPEED_CLK_ECLK_MUX 30 +#define ASPEED_CLK_LHCLK 31 +#define ASPEED_CLK_MAC 32 +#define ASPEED_CLK_BCLK 33 +#define ASPEED_CLK_MPLL 34 +#define ASPEED_CLK_24M 35 +#define ASPEED_CLK_MAC1RCLK 36 +#define ASPEED_CLK_MAC2RCLK 37 +#define ASPEED_CLK_DPLL 38 +#define ASPEED_CLK_D2PLL 39 -- cgit v1.2.3 From df85e9576c18e868c7d42c224a0967cd31f489c0 Mon Sep 17 00:00:00 2001 From: Chuanjia Liu Date: Mon, 31 Aug 2020 15:53:12 +0800 Subject: PCI: mediatek: Release the resource when PCIe enable port fail On the mt7623 platform, if one port enable fail and other port enable succeed. It will hang on when using pci enum because the resource was not released correctly. Signed-off-by: Chuanjia Liu Tested-by: Frank Wunderlich --- drivers/pci/pcie_mediatek.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie_mediatek.c b/drivers/pci/pcie_mediatek.c index ad34f7c597..55b6a40f25 100644 --- a/drivers/pci/pcie_mediatek.c +++ b/drivers/pci/pcie_mediatek.c @@ -443,29 +443,36 @@ static void mtk_pcie_enable_port(struct mtk_pcie_port *port) err = clk_enable(&port->sys_ck); if (err) - goto exit; + goto err_sys_clk; err = reset_assert(&port->reset); if (err) - goto exit; + goto err_reset; err = reset_deassert(&port->reset); if (err) - goto exit; + goto err_reset; err = generic_phy_init(&port->phy); if (err) - goto exit; + goto err_phy_init; err = generic_phy_power_on(&port->phy); if (err) - goto exit; + goto err_phy_on; if (!mtk_pcie_startup_port(port)) return; pr_err("Port%d link down\n", port->slot); -exit: + + generic_phy_power_off(&port->phy); +err_phy_on: + generic_phy_exit(&port->phy); +err_phy_init: +err_reset: + clk_disable(&port->sys_ck); +err_sys_clk: mtk_pcie_port_free(port); } -- cgit v1.2.3 From 6aa3b740c3e04256d5e22dbae8bc5a802aa3b9b9 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 17 Aug 2020 18:15:08 -0500 Subject: remoteproc: k3-r5: Add support for J7200 R5Fs The K3 J7200 SoC family has a revised R5F sub-system and contains a subset of the R5F clusters present on J721E SoCs. The integration of these clusters is very much similar to J721E SoCs otherwise. The revised IP has the following two new features: 1. TCMs are auto-initialized during module power-up, and the behavior is programmable through a MMR bit controlled by System Firmware. 2. The LockStep-mode allows the Core1 TCMs to be combined with the Core0 TCMs effectively doubling the amount of TCMs available. The LockStep-mode on previous SoCs could only use the Core0 TCMs. This combined TCMs appear contiguous at the respective Core0 TCM addresses. Add the support to these clusters in the K3 R5F remoteproc driver using J7200 specific compatibles and revised logic accounting for the above IP features/differences. Signed-off-by: Suman Anna --- drivers/remoteproc/ti_k3_r5f_rproc.c | 99 ++++++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c index 1a7f1f8a00..8e21a38be7 100644 --- a/drivers/remoteproc/ti_k3_r5f_rproc.c +++ b/drivers/remoteproc/ti_k3_r5f_rproc.c @@ -2,8 +2,9 @@ /* * Texas Instruments' K3 R5 Remoteproc driver * - * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2018-2020 Texas Instruments Incorporated - https://www.ti.com/ * Lokesh Vutla + * Suman Anna */ #include @@ -37,6 +38,8 @@ #define PROC_BOOT_CFG_FLAG_R5_BTCM_EN 0x00001000 #define PROC_BOOT_CFG_FLAG_R5_ATCM_EN 0x00002000 #define PROC_BOOT_CFG_FLAG_GEN_IGN_BOOTVECTOR 0x10000000 +/* Available from J7200 SoCs onwards */ +#define PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS 0x00004000 /* R5 TI-SCI Processor Control Flags */ #define PROC_BOOT_CTRL_FLAG_R5_CORE_HALT 0x00000001 @@ -54,6 +57,16 @@ enum cluster_mode { CLUSTER_MODE_LOCKSTEP, }; +/** + * struct k3_r5f_ip_data - internal data structure used for IP variations + * @tcm_is_double: flag to denote the larger unified TCMs in certain modes + * @tcm_ecc_autoinit: flag to denote the auto-initialization of TCMs for ECC + */ +struct k3_r5f_ip_data { + bool tcm_is_double; + bool tcm_ecc_autoinit; +}; + /** * struct k3_r5_mem - internal memory structure * @cpu_addr: MPU virtual address of the memory region @@ -74,6 +87,7 @@ struct k3_r5f_mem { * @cluster: pointer to the parent cluster. * @reset: reset control handle * @tsp: TI-SCI processor control handle + * @ipdata: cached pointer to R5F IP specific feature data * @mem: Array of available internal memories * @num_mem: Number of available memories * @atcm_enable: flag to control ATCM enablement @@ -86,6 +100,7 @@ struct k3_r5f_core { struct k3_r5f_cluster *cluster; struct reset_ctl reset; struct ti_sci_proc tsp; + struct k3_r5f_ip_data *ipdata; struct k3_r5f_mem *mem; int num_mems; u32 atcm_enable; @@ -257,6 +272,18 @@ static int k3_r5f_core_sanity_check(struct k3_r5f_core *core) return 0; } +/* Zero out TCMs so that ECC can be effective on all TCM addresses */ +void k3_r5f_init_tcm_memories(struct k3_r5f_core *core, bool auto_inited) +{ + if (core->ipdata->tcm_ecc_autoinit && auto_inited) + return; + + if (core->atcm_enable) + memset(core->mem[0].cpu_addr, 0x00, core->mem[0].size); + if (core->btcm_enable) + memset(core->mem[1].cpu_addr, 0x00, core->mem[1].size); +} + /** * k3_r5f_load() - Load up the Remote processor image * @dev: rproc device pointer @@ -268,7 +295,9 @@ static int k3_r5f_core_sanity_check(struct k3_r5f_core *core) static int k3_r5f_load(struct udevice *dev, ulong addr, ulong size) { struct k3_r5f_core *core = dev_get_priv(dev); - u32 boot_vector; + u64 boot_vector; + u32 ctrl, sts, cfg = 0; + bool mem_auto_init; int ret; dev_dbg(dev, "%s addr = 0x%lx, size = 0x%lx\n", __func__, addr, size); @@ -281,6 +310,12 @@ static int k3_r5f_load(struct udevice *dev, ulong addr, ulong size) if (ret) return ret; + ret = ti_sci_proc_get_status(&core->tsp, &boot_vector, &cfg, &ctrl, + &sts); + if (ret) + return ret; + mem_auto_init = !(cfg & PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS); + ret = k3_r5f_prepare(dev); if (ret) { dev_err(dev, "R5f prepare failed for core %d\n", @@ -288,11 +323,7 @@ static int k3_r5f_load(struct udevice *dev, ulong addr, ulong size) goto proc_release; } - /* Zero out TCMs so that ECC can be effective on all TCM addresses */ - if (core->atcm_enable) - memset(core->mem[0].cpu_addr, 0x00, core->mem[0].size); - if (core->btcm_enable) - memset(core->mem[1].cpu_addr, 0x00, core->mem[1].size); + k3_r5f_init_tcm_memories(core, mem_auto_init); ret = rproc_elf_load_image(dev, addr, size); if (ret < 0) { @@ -302,7 +333,7 @@ static int k3_r5f_load(struct udevice *dev, ulong addr, ulong size) boot_vector = rproc_elf_get_boot_addr(dev, addr); - dev_dbg(dev, "%s: Boot vector = 0x%x\n", __func__, boot_vector); + dev_dbg(dev, "%s: Boot vector = 0x%llx\n", __func__, boot_vector); ret = ti_sci_proc_set_config(&core->tsp, boot_vector, 0, 0); @@ -657,6 +688,8 @@ static int k3_r5f_of_to_priv(struct k3_r5f_core *core) return ret; } + core->ipdata = (struct k3_r5f_ip_data *)dev_get_driver_data(core->dev); + return 0; } @@ -702,6 +735,38 @@ static int k3_r5f_core_of_get_memories(struct k3_r5f_core *core) return 0; } +/* + * Each R5F core within a typical R5FSS instance has a total of 64 KB of TCMs, + * split equally into two 32 KB banks between ATCM and BTCM. The TCMs from both + * cores are usable in Split-mode, but only the Core0 TCMs can be used in + * LockStep-mode. The newer revisions of the R5FSS IP maximizes these TCMs by + * leveraging the Core1 TCMs as well in certain modes where they would have + * otherwise been unusable (Eg: LockStep-mode on J7200 SoCs). This is done by + * making a Core1 TCM visible immediately after the corresponding Core0 TCM. + * The SoC memory map uses the larger 64 KB sizes for the Core0 TCMs, and the + * dts representation reflects this increased size on supported SoCs. The Core0 + * TCM sizes therefore have to be adjusted to only half the original size in + * Split mode. + */ +static void k3_r5f_core_adjust_tcm_sizes(struct k3_r5f_core *core) +{ + struct k3_r5f_cluster *cluster = core->cluster; + + if (cluster->mode == CLUSTER_MODE_LOCKSTEP) + return; + + if (!core->ipdata->tcm_is_double) + return; + + if (core == cluster->cores[0]) { + core->mem[0].size /= 2; + core->mem[1].size /= 2; + + dev_dbg(core->dev, "adjusted TCM sizes, ATCM = 0x%zx BTCM = 0x%zx\n", + core->mem[0].size, core->mem[1].size); + } +} + /** * k3_r5f_probe() - Basic probe * @dev: corresponding k3 remote processor device @@ -755,6 +820,8 @@ static int k3_r5f_probe(struct udevice *dev) return ret; } + k3_r5f_core_adjust_tcm_sizes(core); + dev_dbg(dev, "Remoteproc successfully probed\n"); return 0; @@ -771,9 +838,20 @@ static int k3_r5f_remove(struct udevice *dev) return 0; } +static const struct k3_r5f_ip_data k3_data = { + .tcm_is_double = false, + .tcm_ecc_autoinit = false, +}; + +static const struct k3_r5f_ip_data j7200_data = { + .tcm_is_double = true, + .tcm_ecc_autoinit = true, +}; + static const struct udevice_id k3_r5f_rproc_ids[] = { - { .compatible = "ti,am654-r5f"}, - { .compatible = "ti,j721e-r5f"}, + { .compatible = "ti,am654-r5f", .data = (ulong)&k3_data, }, + { .compatible = "ti,j721e-r5f", .data = (ulong)&k3_data, }, + { .compatible = "ti,j7200-r5f", .data = (ulong)&j7200_data, }, {} }; @@ -810,6 +888,7 @@ static int k3_r5f_cluster_probe(struct udevice *dev) static const struct udevice_id k3_r5fss_ids[] = { { .compatible = "ti,am654-r5fss"}, { .compatible = "ti,j721e-r5fss"}, + { .compatible = "ti,j7200-r5fss"}, {} }; -- cgit v1.2.3 From 280af011563574844fa3c20acd2cbbd7ee669da8 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Mon, 14 Sep 2020 12:11:14 +0530 Subject: spi: spi-uclass: Block dm_scan_fdt_dev with OF_CONTROL to prevent build failures There are devices which don't use OF_CONTROL or OF_PLATDATA but instead rely on statically defined platdata. Block dm_scan_fdt_dev() with both configs to avoid build failures under this condition. Signed-off-by: Faiz Abbas Reviewed-by: Jagan Teki --- drivers/spi/spi-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index cffd9cf0b0..55a8eed890 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -497,7 +497,7 @@ UCLASS_DRIVER(spi) = { .id = UCLASS_SPI, .name = "spi", .flags = DM_UC_FLAG_SEQ_ALIAS, -#if !CONFIG_IS_ENABLED(OF_PLATDATA) +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) .post_bind = dm_scan_fdt_dev, #endif .post_probe = spi_post_probe, -- cgit v1.2.3 From 41cf3cb39ddbb8a0b892781388e1054653d33ed1 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Mon, 14 Sep 2020 12:11:15 +0530 Subject: arm: mach-omap2: am33xx: Add device structure for spi Add platform data and a device structure for the spi device present on am335x-icev2. This requires moving all omap3_spi platform data structures and symbols to an omap3_spi.h so that the board file can access them. Signed-off-by: Faiz Abbas --- arch/arm/mach-omap2/am33xx/board.c | 18 +++++++++ drivers/spi/omap3_spi.c | 70 +--------------------------------- include/configs/am335x_evm.h | 2 - include/omap3_spi.h | 78 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 71 deletions(-) create mode 100644 include/omap3_spi.h (limited to 'drivers') diff --git a/arch/arm/mach-omap2/am33xx/board.c b/arch/arm/mach-omap2/am33xx/board.c index a7b56b6bb3..2888390d24 100644 --- a/arch/arm/mach-omap2/am33xx/board.c +++ b/arch/arm/mach-omap2/am33xx/board.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,12 @@ #define AM43XX_READ_WRITE_LEVELING_CTRL_OFFSET 0xDC #define AM43XX_RDWRLVLFULL_START 0x80000000 +/* SPI flash. */ +#if CONFIG_IS_ENABLED(DM_SPI) && !CONFIG_IS_ENABLED(OF_CONTROL) +#define AM33XX_SPI0_BASE 0x48030000 +#define AM33XX_SPI0_OFFSET (AM33XX_SPI0_BASE + OMAP4_MCSPI_REG_OFFSET) +#endif + DECLARE_GLOBAL_DATA_PTR; int dram_init(void) @@ -142,6 +149,17 @@ U_BOOT_DEVICES(am33xx_gpios) = { #endif }; #endif +#if CONFIG_IS_ENABLED(DM_SPI) && !CONFIG_IS_ENABLED(OF_CONTROL) +static const struct omap3_spi_plat omap3_spi_pdata = { + .regs = (struct mcspi *)AM33XX_SPI0_OFFSET, + .pin_dir = MCSPI_PINDIR_D0_IN_D1_OUT, +}; + +U_BOOT_DEVICE(am33xx_spi) = { + .name = "omap3_spi", + .platdata = &omap3_spi_pdata, +}; +#endif #endif #if !CONFIG_IS_ENABLED(DM_GPIO) diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index fbf9575851..fb1cf360fc 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -22,82 +22,14 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; -#define OMAP4_MCSPI_REG_OFFSET 0x100 - struct omap2_mcspi_platform_config { unsigned int regs_offset; }; -/* per-register bitmasks */ -#define OMAP3_MCSPI_SYSCONFIG_SMARTIDLE (2 << 3) -#define OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP BIT(2) -#define OMAP3_MCSPI_SYSCONFIG_AUTOIDLE BIT(0) -#define OMAP3_MCSPI_SYSCONFIG_SOFTRESET BIT(1) - -#define OMAP3_MCSPI_SYSSTATUS_RESETDONE BIT(0) - -#define OMAP3_MCSPI_MODULCTRL_SINGLE BIT(0) -#define OMAP3_MCSPI_MODULCTRL_MS BIT(2) -#define OMAP3_MCSPI_MODULCTRL_STEST BIT(3) - -#define OMAP3_MCSPI_CHCONF_PHA BIT(0) -#define OMAP3_MCSPI_CHCONF_POL BIT(1) -#define OMAP3_MCSPI_CHCONF_CLKD_MASK GENMASK(5, 2) -#define OMAP3_MCSPI_CHCONF_EPOL BIT(6) -#define OMAP3_MCSPI_CHCONF_WL_MASK GENMASK(11, 7) -#define OMAP3_MCSPI_CHCONF_TRM_RX_ONLY BIT(12) -#define OMAP3_MCSPI_CHCONF_TRM_TX_ONLY BIT(13) -#define OMAP3_MCSPI_CHCONF_TRM_MASK GENMASK(13, 12) -#define OMAP3_MCSPI_CHCONF_DMAW BIT(14) -#define OMAP3_MCSPI_CHCONF_DMAR BIT(15) -#define OMAP3_MCSPI_CHCONF_DPE0 BIT(16) -#define OMAP3_MCSPI_CHCONF_DPE1 BIT(17) -#define OMAP3_MCSPI_CHCONF_IS BIT(18) -#define OMAP3_MCSPI_CHCONF_TURBO BIT(19) -#define OMAP3_MCSPI_CHCONF_FORCE BIT(20) - -#define OMAP3_MCSPI_CHSTAT_RXS BIT(0) -#define OMAP3_MCSPI_CHSTAT_TXS BIT(1) -#define OMAP3_MCSPI_CHSTAT_EOT BIT(2) - -#define OMAP3_MCSPI_CHCTRL_EN BIT(0) -#define OMAP3_MCSPI_CHCTRL_DIS (0 << 0) - -#define OMAP3_MCSPI_WAKEUPENABLE_WKEN BIT(0) -#define MCSPI_PINDIR_D0_IN_D1_OUT 0 -#define MCSPI_PINDIR_D0_OUT_D1_IN 1 - -#define OMAP3_MCSPI_MAX_FREQ 48000000 -#define SPI_WAIT_TIMEOUT 10 - -/* OMAP3 McSPI registers */ -struct mcspi_channel { - unsigned int chconf; /* 0x2C, 0x40, 0x54, 0x68 */ - unsigned int chstat; /* 0x30, 0x44, 0x58, 0x6C */ - unsigned int chctrl; /* 0x34, 0x48, 0x5C, 0x70 */ - unsigned int tx; /* 0x38, 0x4C, 0x60, 0x74 */ - unsigned int rx; /* 0x3C, 0x50, 0x64, 0x78 */ -}; - -struct mcspi { - unsigned char res1[0x10]; - unsigned int sysconfig; /* 0x10 */ - unsigned int sysstatus; /* 0x14 */ - unsigned int irqstatus; /* 0x18 */ - unsigned int irqenable; /* 0x1C */ - unsigned int wakeupenable; /* 0x20 */ - unsigned int syst; /* 0x24 */ - unsigned int modulctrl; /* 0x28 */ - struct mcspi_channel channel[4]; - /* channel0: 0x2C - 0x3C, bus 0 & 1 & 2 & 3 */ - /* channel1: 0x40 - 0x50, bus 0 & 1 */ - /* channel2: 0x54 - 0x64, bus 0 & 1 */ - /* channel3: 0x68 - 0x78, bus 0 */ -}; - struct omap3_spi_priv { struct mcspi *regs; unsigned int cs; diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h index 103c046137..5af90d932d 100644 --- a/include/configs/am335x_evm.h +++ b/include/configs/am335x_evm.h @@ -287,8 +287,6 @@ #define CONFIG_SYS_ENV_SECT_SIZE CONFIG_SYS_NAND_BLOCK_SIZE #endif -/* SPI flash. */ - /* Network. */ /* Enable Atheros phy driver */ diff --git a/include/omap3_spi.h b/include/omap3_spi.h new file mode 100644 index 0000000000..cae3770583 --- /dev/null +++ b/include/omap3_spi.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +#ifndef __OMAP3_SPI_H_ +#define __OMAP3_SPI_H_ + +/* per-register bitmasks */ +#define OMAP3_MCSPI_SYSCONFIG_SMARTIDLE (2 << 3) +#define OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP BIT(2) +#define OMAP3_MCSPI_SYSCONFIG_AUTOIDLE BIT(0) +#define OMAP3_MCSPI_SYSCONFIG_SOFTRESET BIT(1) + +#define OMAP3_MCSPI_SYSSTATUS_RESETDONE BIT(0) + +#define OMAP3_MCSPI_MODULCTRL_SINGLE BIT(0) +#define OMAP3_MCSPI_MODULCTRL_MS BIT(2) +#define OMAP3_MCSPI_MODULCTRL_STEST BIT(3) + +#define OMAP3_MCSPI_CHCONF_PHA BIT(0) +#define OMAP3_MCSPI_CHCONF_POL BIT(1) +#define OMAP3_MCSPI_CHCONF_CLKD_MASK GENMASK(5, 2) +#define OMAP3_MCSPI_CHCONF_EPOL BIT(6) +#define OMAP3_MCSPI_CHCONF_WL_MASK GENMASK(11, 7) +#define OMAP3_MCSPI_CHCONF_TRM_RX_ONLY BIT(12) +#define OMAP3_MCSPI_CHCONF_TRM_TX_ONLY BIT(13) +#define OMAP3_MCSPI_CHCONF_TRM_MASK GENMASK(13, 12) +#define OMAP3_MCSPI_CHCONF_DMAW BIT(14) +#define OMAP3_MCSPI_CHCONF_DMAR BIT(15) +#define OMAP3_MCSPI_CHCONF_DPE0 BIT(16) +#define OMAP3_MCSPI_CHCONF_DPE1 BIT(17) +#define OMAP3_MCSPI_CHCONF_IS BIT(18) +#define OMAP3_MCSPI_CHCONF_TURBO BIT(19) +#define OMAP3_MCSPI_CHCONF_FORCE BIT(20) + +#define OMAP3_MCSPI_CHSTAT_RXS BIT(0) +#define OMAP3_MCSPI_CHSTAT_TXS BIT(1) +#define OMAP3_MCSPI_CHSTAT_EOT BIT(2) + +#define OMAP3_MCSPI_CHCTRL_EN BIT(0) +#define OMAP3_MCSPI_CHCTRL_DIS (0 << 0) + +#define OMAP3_MCSPI_WAKEUPENABLE_WKEN BIT(0) +#define MCSPI_PINDIR_D0_IN_D1_OUT 0 +#define MCSPI_PINDIR_D0_OUT_D1_IN 1 + +#define OMAP3_MCSPI_MAX_FREQ 48000000 +#define SPI_WAIT_TIMEOUT 10 + +#define OMAP4_MCSPI_REG_OFFSET 0x100 + +/* OMAP3 McSPI registers */ +struct mcspi_channel { + unsigned int chconf; /* 0x2C, 0x40, 0x54, 0x68 */ + unsigned int chstat; /* 0x30, 0x44, 0x58, 0x6C */ + unsigned int chctrl; /* 0x34, 0x48, 0x5C, 0x70 */ + unsigned int tx; /* 0x38, 0x4C, 0x60, 0x74 */ + unsigned int rx; /* 0x3C, 0x50, 0x64, 0x78 */ +}; + +struct mcspi { + unsigned char res1[0x10]; + unsigned int sysconfig; /* 0x10 */ + unsigned int sysstatus; /* 0x14 */ + unsigned int irqstatus; /* 0x18 */ + unsigned int irqenable; /* 0x1C */ + unsigned int wakeupenable; /* 0x20 */ + unsigned int syst; /* 0x24 */ + unsigned int modulctrl; /* 0x28 */ + struct mcspi_channel channel[4]; + /* channel0: 0x2C - 0x3C, bus 0 & 1 & 2 & 3 */ + /* channel1: 0x40 - 0x50, bus 0 & 1 */ + /* channel2: 0x54 - 0x64, bus 0 & 1 */ + /* channel3: 0x68 - 0x78, bus 0 */ +}; + +struct omap3_spi_plat { + struct mcspi *regs; + unsigned int pin_dir:1; +}; +#endif -- cgit v1.2.3 From afd4f15a39de0fa572792a3037545afbac386ee5 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Mon, 14 Sep 2020 12:11:16 +0530 Subject: spi: omap3_spi: Read platform data in ofdata_to_platdata() Add an ofdata_to_platdata() callback to access dts in U-boot and access all platform data in it. This prepares the driver for supporting both device tree as well as static platform data structures in SPL. Signed-off-by: Faiz Abbas --- drivers/spi/omap3_spi.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index fb1cf360fc..56cb217486 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -414,17 +414,10 @@ static int omap3_spi_set_wordlen(struct udevice *dev, unsigned int wordlen) static int omap3_spi_probe(struct udevice *dev) { struct omap3_spi_priv *priv = dev_get_priv(dev); - const void *blob = gd->fdt_blob; - int node = dev_of_offset(dev); + struct omap3_spi_plat *plat = dev_get_platdata(dev); - struct omap2_mcspi_platform_config* data = - (struct omap2_mcspi_platform_config*)dev_get_driver_data(dev); - - priv->regs = (struct mcspi *)(dev_read_addr(dev) + data->regs_offset); - if (fdtdec_get_bool(blob, node, "ti,pindir-d0-out-d1-in")) - priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; - else - priv->pin_dir = MCSPI_PINDIR_D0_IN_D1_OUT; + priv->regs = plat->regs; + priv->pin_dir = plat->pin_dir; priv->wordlen = SPI_DEFAULT_WORDLEN; spi_reset(priv->regs); @@ -476,6 +469,7 @@ static const struct dm_spi_ops omap3_spi_ops = { */ }; +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) static struct omap2_mcspi_platform_config omap2_pdata = { .regs_offset = 0, }; @@ -484,16 +478,37 @@ static struct omap2_mcspi_platform_config omap4_pdata = { .regs_offset = OMAP4_MCSPI_REG_OFFSET, }; +static int omap3_spi_ofdata_to_platdata(struct udevice *dev) +{ + struct omap2_mcspi_platform_config *data = + (struct omap2_mcspi_platform_config *)dev_get_driver_data(dev); + struct omap3_spi_plat *plat = dev_get_platdata(dev); + + plat->regs = (struct mcspi *)(dev_read_addr(dev) + data->regs_offset); + + if (dev_read_bool(dev, "ti,pindir-d0-out-d1-in")) + plat->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; + else + plat->pin_dir = MCSPI_PINDIR_D0_IN_D1_OUT; + + return 0; +} + static const struct udevice_id omap3_spi_ids[] = { { .compatible = "ti,omap2-mcspi", .data = (ulong)&omap2_pdata }, { .compatible = "ti,omap4-mcspi", .data = (ulong)&omap4_pdata }, { } }; - +#endif U_BOOT_DRIVER(omap3_spi) = { .name = "omap3_spi", .id = UCLASS_SPI, + .flags = DM_FLAG_PRE_RELOC, +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) .of_match = omap3_spi_ids, + .ofdata_to_platdata = omap3_spi_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct omap3_spi_plat), +#endif .probe = omap3_spi_probe, .ops = &omap3_spi_ops, .priv_auto_alloc_size = sizeof(struct omap3_spi_priv), -- cgit v1.2.3 From 9bd6444826acc476110b81a16d9d16bfa57d9fbd Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Mon, 25 May 2020 07:27:26 +0200 Subject: powerpc, qe: fix codingstyle issues for drivers/qe fix Codingstyle for files in drivers/qe, remaining following check warnings: $ ./scripts/checkpatch.pl -f drivers/qe/uec.h CHECK: Macro argument reuse '_bd' - possible side-effects? +#define BD_ADVANCE(_bd, _status, _base) \ + (((_status) & BD_WRAP) ? (_bd) = \ + ((struct buffer_descriptor *)(_base)) : ++(_bd)) total: 0 errors, 0 warnings, 1 checks, 692 lines checked $ ./scripts/checkpatch.pl -f drivers/qe/uec_phy.h total: 0 errors, 0 warnings, 0 checks, 214 lines checked $ ./scripts/checkpatch.pl -f drivers/qe/uccf.c total: 0 errors, 0 warnings, 0 checks, 507 lines checked $ ./scripts/checkpatch.pl -f drivers/qe/uec.c total: 0 errors, 0 warnings, 0 checks, 1434 lines checked $ ./scripts/checkpatch.pl -f drivers/qe/uec_phy.c total: 0 errors, 0 warnings, 0 checks, 927 lines checked $ ./scripts/checkpatch.pl -f drivers/qe/qe.c CHECK: Lines should not end with a '(' +U_BOOT_CMD( total: 0 errors, 0 warnings, 1 checks, 830 lines checked Signed-off-by: Heiko Schocher --- arch/powerpc/cpu/mpc83xx/qe_io.c | 63 +++-- drivers/qe/qe.c | 96 ++++--- drivers/qe/uccf.c | 447 ++++++++++++++++++----------- drivers/qe/uccf.h | 90 +++--- drivers/qe/uec.c | 596 ++++++++++++++++++++------------------- drivers/qe/uec.h | 381 +++++++++++-------------- drivers/qe/uec_phy.c | 331 +++++++++++----------- drivers/qe/uec_phy.h | 71 ++--- 8 files changed, 1073 insertions(+), 1002 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/cpu/mpc83xx/qe_io.c b/arch/powerpc/cpu/mpc83xx/qe_io.c index 88aa689551..1079ae128a 100644 --- a/arch/powerpc/cpu/mpc83xx/qe_io.c +++ b/arch/powerpc/cpu/mpc83xx/qe_io.c @@ -14,55 +14,58 @@ #define NUM_OF_PINS 32 void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign) { - u32 pin_2bit_mask; - u32 pin_2bit_dir; - u32 pin_2bit_assign; - u32 pin_1bit_mask; - u32 tmp_val; - volatile immap_t *im = (volatile immap_t *)CONFIG_SYS_IMMR; - volatile qepio83xx_t *par_io = (volatile qepio83xx_t *)&im->qepio; + u32 2bit_mask; + u32 2bit_dir; + u32 2bit_assign; + u32 1bit_mask; + u32 tmp_val; + immap_t *im; + qepio83xx_t *par_io; + int offset; + + im = (immap_t *)CONFIG_SYS_IMMR; + par_io = (qepio83xx_t *)&im->qepio; + offset = (NUM_OF_PINS - (pin % (NUM_OF_PINS / 2) + 1) * 2); /* Calculate pin location and 2bit mask and dir */ - pin_2bit_mask = (u32)(0x3 << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2)); - pin_2bit_dir = (u32)(dir << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2)); + 2bit_mask = (u32)(0x3 << offset); + 2bit_dir = (u32)(dir << offset); /* Setup the direction */ - tmp_val = (pin > (NUM_OF_PINS/2) - 1) ? \ + tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ? in_be32(&par_io->ioport[port].dir2) : in_be32(&par_io->ioport[port].dir1); - if (pin > (NUM_OF_PINS/2) -1) { - out_be32(&par_io->ioport[port].dir2, ~pin_2bit_mask & tmp_val); - out_be32(&par_io->ioport[port].dir2, pin_2bit_dir | tmp_val); + if (pin > (NUM_OF_PINS / 2) - 1) { + out_be32(&par_io->ioport[port].dir2, ~2bit_mask & tmp_val); + out_be32(&par_io->ioport[port].dir2, 2bit_dir | tmp_val); } else { - out_be32(&par_io->ioport[port].dir1, ~pin_2bit_mask & tmp_val); - out_be32(&par_io->ioport[port].dir1, pin_2bit_dir | tmp_val); + out_be32(&par_io->ioport[port].dir1, ~2bit_mask & tmp_val); + out_be32(&par_io->ioport[port].dir1, 2bit_dir | tmp_val); } /* Calculate pin location for 1bit mask */ - pin_1bit_mask = (u32)(1 << (NUM_OF_PINS - (pin+1))); + 1bit_mask = (u32)(1 << (NUM_OF_PINS - (pin + 1))); /* Setup the open drain */ tmp_val = in_be32(&par_io->ioport[port].podr); - if (open_drain) { - out_be32(&par_io->ioport[port].podr, pin_1bit_mask | tmp_val); - } else { - out_be32(&par_io->ioport[port].podr, ~pin_1bit_mask & tmp_val); - } + if (open_drain) + out_be32(&par_io->ioport[port].podr, 1bit_mask | tmp_val); + else + out_be32(&par_io->ioport[port].podr, ~1bit_mask & tmp_val); /* Setup the assignment */ - tmp_val = (pin > (NUM_OF_PINS/2) - 1) ? - in_be32(&par_io->ioport[port].ppar2): + tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ? + in_be32(&par_io->ioport[port].ppar2) : in_be32(&par_io->ioport[port].ppar1); - pin_2bit_assign = (u32)(assign - << (NUM_OF_PINS - (pin%(NUM_OF_PINS/2)+1)*2)); + 2bit_assign = (u32)(assign << offset); /* Clear and set 2 bits mask */ - if (pin > (NUM_OF_PINS/2) - 1) { - out_be32(&par_io->ioport[port].ppar2, ~pin_2bit_mask & tmp_val); - out_be32(&par_io->ioport[port].ppar2, pin_2bit_assign | tmp_val); + if (pin > (NUM_OF_PINS / 2) - 1) { + out_be32(&par_io->ioport[port].ppar2, ~2bit_mask & tmp_val); + out_be32(&par_io->ioport[port].ppar2, 2bit_assign | tmp_val); } else { - out_be32(&par_io->ioport[port].ppar1, ~pin_2bit_mask & tmp_val); - out_be32(&par_io->ioport[port].ppar1, pin_2bit_assign | tmp_val); + out_be32(&par_io->ioport[port].ppar1, ~2bit_mask & tmp_val); + out_be32(&par_io->ioport[port].ppar1, 2bit_assign | tmp_val); } } diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c index 61ca4760c8..1a829b5a4c 100644 --- a/drivers/qe/qe.c +++ b/drivers/qe/qe.c @@ -26,7 +26,7 @@ #define MPC85xx_DEVDISR_QE_DISABLE 0x1 -qe_map_t *qe_immr = NULL; +qe_map_t *qe_immr; #ifdef CONFIG_QE static qe_snum_t snums[QE_NUM_OF_SNUM]; #endif @@ -38,18 +38,16 @@ void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data) u32 cecr; if (cmd == QE_RESET) { - out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG)); + out_be32(&qe_immr->cp.cecr, (u32)(cmd | QE_CR_FLG)); } else { out_be32(&qe_immr->cp.cecdr, cmd_data); out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG | - ((u32) mcn<cp.cecr); } while (cecr & QE_CR_FLG); - - return; } #ifdef CONFIG_QE @@ -66,12 +64,13 @@ uint qe_muram_alloc(uint size, uint align) if (off != 0) gd->arch.mp_alloc_base += (align - off); - if ((off = size & align_mask) != 0) + off = size & align_mask; + if (off != 0) size += (align - off); if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) { gd->arch.mp_alloc_base = savebase; - printf("%s: ran out of ram.\n", __FUNCTION__); + printf("%s: ran out of ram.\n", __func__); } retloc = gd->arch.mp_alloc_base; @@ -93,10 +92,10 @@ void *qe_muram_addr(uint offset) #ifdef CONFIG_QE static void qe_sdma_init(void) { - volatile sdma_t *p; - uint sdma_buffer_base; + sdma_t *p; + uint sdma_buffer_base; - p = (volatile sdma_t *)&qe_immr->sdma; + p = (sdma_t *)&qe_immr->sdma; /* All of DMA transaction in bus 1 */ out_be32(&p->sdaqr, 0); @@ -212,7 +211,7 @@ void qe_init(uint qe_base) qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR); /* enable the microcode in IRAM */ - out_be32(&qe_immr->iram.iready,QE_IRAM_READY); + out_be32(&qe_immr->iram.iready, QE_IRAM_READY); #endif gd->arch.mp_alloc_base = QE_DATAONLY_BASE; @@ -235,10 +234,12 @@ void u_qe_init(void) void *addr = (void *)CONFIG_SYS_QE_FW_ADDR; if (src == BOOT_SOURCE_IFC_NOR) - addr = (void *)(CONFIG_SYS_QE_FW_ADDR + CONFIG_SYS_FSL_IFC_BASE); + addr = (void *)(CONFIG_SYS_QE_FW_ADDR + + CONFIG_SYS_FSL_IFC_BASE); if (src == BOOT_SOURCE_QSPI_NOR) - addr = (void *)(CONFIG_SYS_QE_FW_ADDR + CONFIG_SYS_FSL_QSPI_BASE); + addr = (void *)(CONFIG_SYS_QE_FW_ADDR + + CONFIG_SYS_FSL_QSPI_BASE); if (src == BOOT_SOURCE_SD_MMC) { int dev = CONFIG_SYS_MMC_ENV_DEV; @@ -320,7 +321,7 @@ void u_qe_resume(void) void qe_reset(void) { qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID, - (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0); + (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0); } #ifdef CONFIG_QE @@ -329,24 +330,22 @@ void qe_assign_page(uint snum, uint para_ram_base) u32 cecr; out_be32(&qe_immr->cp.cecdr, para_ram_base); - out_be32(&qe_immr->cp.cecr, ((u32) snum<cp.cecr, ((u32)snum << QE_CR_ASSIGN_PAGE_SNUM_SHIFT) | QE_CR_FLG | QE_ASSIGN_PAGE); /* Wait for the QE_CR_FLG to clear */ do { cecr = in_be32(&qe_immr->cp.cecr); - } while (cecr & QE_CR_FLG ); - - return; + } while (cecr & QE_CR_FLG); } #endif /* * brg: 0~15 as BRG1~BRG16 - rate: baud rate + * rate: baud rate * BRG input clock comes from the BRGCLK (internal clock generated from - the QE clock, it is one-half of the QE clock), If need the clock source - from CLKn pin, we have te change the function. + * the QE clock, it is one-half of the QE clock), If need the clock source + * from CLKn pin, we have te change the function. */ #define BRG_CLK (gd->arch.brg_clk) @@ -354,12 +353,14 @@ void qe_assign_page(uint snum, uint para_ram_base) #ifdef CONFIG_QE int qe_set_brg(uint brg, uint rate) { - volatile uint *bp; - u32 divisor; - int div16 = 0; + uint *bp; + u32 divisor; + u32 val; + int div16 = 0; if (brg >= QE_NUM_OF_BRGS) return -EINVAL; + bp = (uint *)&qe_immr->brg.brgc1; bp += brg; @@ -369,33 +370,37 @@ int qe_set_brg(uint brg, uint rate) divisor /= 16; } - *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE; - __asm__ __volatile__("sync"); + /* CHECK TODO */ + /* + * was + * *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE; + * __asm__ __volatile__("sync"); + */ - if (div16) { - *bp |= QE_BRGC_DIV16; - __asm__ __volatile__("sync"); - } + val = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE; + if (div16) + val |= QE_BRGC_DIV16; + + out_be32(bp, val); return 0; } #endif -/* Set ethernet MII clock master -*/ +/* Set ethernet MII clock master */ int qe_set_mii_clk_src(int ucc_num) { u32 cmxgcr; /* check if the UCC number is in range. */ - if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) { - printf("%s: ucc num not in ranges\n", __FUNCTION__); + if ((ucc_num > UCC_MAX_NUM - 1) || ucc_num < 0) { + printf("%s: ucc num not in ranges\n", __func__); return -EINVAL; } cmxgcr = in_be32(&qe_immr->qmx.cmxgcr); cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK; - cmxgcr |= (ucc_num <qmx.cmxgcr, cmxgcr); return 0; @@ -417,7 +422,7 @@ static int qe_firmware_uploaded; * the actual uploading of the microcode. */ static void qe_upload_microcode(const void *base, - const struct qe_microcode *ucode) + const struct qe_microcode *ucode) { const u32 *code = base + be32_to_cpu(ucode->code_offset); unsigned int i; @@ -494,7 +499,7 @@ int qe_upload_firmware(const struct qe_firmware *firmware) } /* Validate some of the fields */ - if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) { + if (firmware->count < 1 || firmware->count > MAX_QE_RISC) { printf("Invalid data\n"); return -EINVAL; } @@ -522,7 +527,7 @@ int qe_upload_firmware(const struct qe_firmware *firmware) * function isn't available unless you turn on JFFS support. */ crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size)); - if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) { + if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) { printf("Firmware CRC is invalid\n"); return -EIO; } @@ -532,12 +537,12 @@ int qe_upload_firmware(const struct qe_firmware *firmware) */ if (!firmware->split) { out_be16(&qe_immr->cp.cercr, - in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR); + in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR); } if (firmware->soc.model) printf("Firmware '%s' for %u V%u.%u\n", - firmware->id, be16_to_cpu(firmware->soc.model), + firmware->id, be16_to_cpu(firmware->soc.model), firmware->soc.major, firmware->soc.minor); else printf("Firmware '%s'\n", firmware->id); @@ -550,7 +555,7 @@ int qe_upload_firmware(const struct qe_firmware *firmware) strncpy(qe_firmware_info.id, (char *)firmware->id, 62); qe_firmware_info.extended_modes = firmware->extended_modes; memcpy(qe_firmware_info.vtraps, firmware->vtraps, - sizeof(firmware->vtraps)); + sizeof(firmware->vtraps)); qe_firmware_uploaded = 1; /* Loop through each microcode. */ @@ -634,7 +639,7 @@ int u_qe_upload_firmware(const struct qe_firmware *firmware) } /* Validate some of the fields */ - if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) { + if (firmware->count < 1 || firmware->count > MAX_QE_RISC) { printf("Invalid data\n"); return -EINVAL; } @@ -803,7 +808,7 @@ static int qe_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) if (argc > 3) { ulong length = simple_strtoul(argv[3], NULL, 16); - struct qe_firmware *firmware = (void *) addr; + struct qe_firmware *firmware = (void *)addr; if (length != be32_to_cpu(firmware->header.length)) { printf("Length mismatch\n"); @@ -811,7 +816,7 @@ static int qe_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) } } - return qe_upload_firmware((const struct qe_firmware *) addr); + return qe_upload_firmware((const struct qe_firmware *)addr); } return cmd_usage(cmdtp); @@ -820,7 +825,6 @@ static int qe_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) U_BOOT_CMD( qe, 4, 0, qe_cmd, "QUICC Engine commands", - "fw [] - Upload firmware binary at address to " - "the QE,\n" + "fw [] - Upload firmware binary at address to the QE,\n" "\twith optional length verification." ); diff --git a/drivers/qe/uccf.c b/drivers/qe/uccf.c index 9beb5d90ac..306f1ea1db 100644 --- a/drivers/qe/uccf.c +++ b/drivers/qe/uccf.c @@ -14,7 +14,7 @@ #include "uccf.h" #include -void ucc_fast_transmit_on_demand(ucc_fast_private_t *uccf) +void ucc_fast_transmit_on_demand(struct ucc_fast_priv *uccf) { out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD); } @@ -22,170 +22,271 @@ void ucc_fast_transmit_on_demand(ucc_fast_private_t *uccf) u32 ucc_fast_get_qe_cr_subblock(int ucc_num) { switch (ucc_num) { - case 0: return QE_CR_SUBBLOCK_UCCFAST1; - case 1: return QE_CR_SUBBLOCK_UCCFAST2; - case 2: return QE_CR_SUBBLOCK_UCCFAST3; - case 3: return QE_CR_SUBBLOCK_UCCFAST4; - case 4: return QE_CR_SUBBLOCK_UCCFAST5; - case 5: return QE_CR_SUBBLOCK_UCCFAST6; - case 6: return QE_CR_SUBBLOCK_UCCFAST7; - case 7: return QE_CR_SUBBLOCK_UCCFAST8; - default: return QE_CR_SUBBLOCK_INVALID; + case 0: + return QE_CR_SUBBLOCK_UCCFAST1; + case 1: + return QE_CR_SUBBLOCK_UCCFAST2; + case 2: + return QE_CR_SUBBLOCK_UCCFAST3; + case 3: + return QE_CR_SUBBLOCK_UCCFAST4; + case 4: + return QE_CR_SUBBLOCK_UCCFAST5; + case 5: + return QE_CR_SUBBLOCK_UCCFAST6; + case 6: + return QE_CR_SUBBLOCK_UCCFAST7; + case 7: + return QE_CR_SUBBLOCK_UCCFAST8; + default: + return QE_CR_SUBBLOCK_INVALID; } } -static void ucc_get_cmxucr_reg(int ucc_num, volatile u32 **p_cmxucr, - u8 *reg_num, u8 *shift) +static void ucc_get_cmxucr_reg(int ucc_num, u32 **p_cmxucr, + u8 *reg_num, u8 *shift) { switch (ucc_num) { - case 0: /* UCC1 */ - *p_cmxucr = &(qe_immr->qmx.cmxucr1); - *reg_num = 1; - *shift = 16; - break; - case 2: /* UCC3 */ - *p_cmxucr = &(qe_immr->qmx.cmxucr1); - *reg_num = 1; - *shift = 0; - break; - case 4: /* UCC5 */ - *p_cmxucr = &(qe_immr->qmx.cmxucr2); - *reg_num = 2; - *shift = 16; - break; - case 6: /* UCC7 */ - *p_cmxucr = &(qe_immr->qmx.cmxucr2); - *reg_num = 2; - *shift = 0; - break; - case 1: /* UCC2 */ - *p_cmxucr = &(qe_immr->qmx.cmxucr3); - *reg_num = 3; - *shift = 16; - break; - case 3: /* UCC4 */ - *p_cmxucr = &(qe_immr->qmx.cmxucr3); - *reg_num = 3; - *shift = 0; - break; - case 5: /* UCC6 */ - *p_cmxucr = &(qe_immr->qmx.cmxucr4); - *reg_num = 4; - *shift = 16; - break; - case 7: /* UCC8 */ - *p_cmxucr = &(qe_immr->qmx.cmxucr4); - *reg_num = 4; - *shift = 0; - break; - default: - break; + case 0: /* UCC1 */ + *p_cmxucr = &qe_immr->qmx.cmxucr1; + *reg_num = 1; + *shift = 16; + break; + case 2: /* UCC3 */ + *p_cmxucr = &qe_immr->qmx.cmxucr1; + *reg_num = 1; + *shift = 0; + break; + case 4: /* UCC5 */ + *p_cmxucr = &qe_immr->qmx.cmxucr2; + *reg_num = 2; + *shift = 16; + break; + case 6: /* UCC7 */ + *p_cmxucr = &qe_immr->qmx.cmxucr2; + *reg_num = 2; + *shift = 0; + break; + case 1: /* UCC2 */ + *p_cmxucr = &qe_immr->qmx.cmxucr3; + *reg_num = 3; + *shift = 16; + break; + case 3: /* UCC4 */ + *p_cmxucr = &qe_immr->qmx.cmxucr3; + *reg_num = 3; + *shift = 0; + break; + case 5: /* UCC6 */ + *p_cmxucr = &qe_immr->qmx.cmxucr4; + *reg_num = 4; + *shift = 16; + break; + case 7: /* UCC8 */ + *p_cmxucr = &qe_immr->qmx.cmxucr4; + *reg_num = 4; + *shift = 0; + break; + default: + break; } } static int ucc_set_clk_src(int ucc_num, qe_clock_e clock, comm_dir_e mode) { - volatile u32 *p_cmxucr = NULL; - u8 reg_num = 0; - u8 shift = 0; - u32 clockBits; - u32 clockMask; - int source = -1; + u32 *p_cmxucr = NULL; + u8 reg_num = 0; + u8 shift = 0; + u32 clk_bits; + u32 clk_mask; + int source = -1; /* check if the UCC number is in range. */ - if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) + if ((ucc_num > UCC_MAX_NUM - 1) || ucc_num < 0) return -EINVAL; - if (! ((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX))) { - printf("%s: bad comm mode type passed\n", __FUNCTION__); + if (!(mode == COMM_DIR_RX || mode == COMM_DIR_TX)) { + printf("%s: bad comm mode type passed\n", __func__); return -EINVAL; } ucc_get_cmxucr_reg(ucc_num, &p_cmxucr, ®_num, &shift); switch (reg_num) { - case 1: - switch (clock) { - case QE_BRG1: source = 1; break; - case QE_BRG2: source = 2; break; - case QE_BRG7: source = 3; break; - case QE_BRG8: source = 4; break; - case QE_CLK9: source = 5; break; - case QE_CLK10: source = 6; break; - case QE_CLK11: source = 7; break; - case QE_CLK12: source = 8; break; - case QE_CLK15: source = 9; break; - case QE_CLK16: source = 10; break; - default: source = -1; break; - } - break; - case 2: - switch (clock) { - case QE_BRG5: source = 1; break; - case QE_BRG6: source = 2; break; - case QE_BRG7: source = 3; break; - case QE_BRG8: source = 4; break; - case QE_CLK13: source = 5; break; - case QE_CLK14: source = 6; break; - case QE_CLK19: source = 7; break; - case QE_CLK20: source = 8; break; - case QE_CLK15: source = 9; break; - case QE_CLK16: source = 10; break; - default: source = -1; break; - } - break; - case 3: - switch (clock) { - case QE_BRG9: source = 1; break; - case QE_BRG10: source = 2; break; - case QE_BRG15: source = 3; break; - case QE_BRG16: source = 4; break; - case QE_CLK3: source = 5; break; - case QE_CLK4: source = 6; break; - case QE_CLK17: source = 7; break; - case QE_CLK18: source = 8; break; - case QE_CLK7: source = 9; break; - case QE_CLK8: source = 10; break; - case QE_CLK16: source = 11; break; - default: source = -1; break; - } - break; - case 4: - switch (clock) { - case QE_BRG13: source = 1; break; - case QE_BRG14: source = 2; break; - case QE_BRG15: source = 3; break; - case QE_BRG16: source = 4; break; - case QE_CLK5: source = 5; break; - case QE_CLK6: source = 6; break; - case QE_CLK21: source = 7; break; - case QE_CLK22: source = 8; break; - case QE_CLK7: source = 9; break; - case QE_CLK8: source = 10; break; - case QE_CLK16: source = 11; break; - default: source = -1; break; - } + case 1: + switch (clock) { + case QE_BRG1: + source = 1; + break; + case QE_BRG2: + source = 2; + break; + case QE_BRG7: + source = 3; + break; + case QE_BRG8: + source = 4; + break; + case QE_CLK9: + source = 5; + break; + case QE_CLK10: + source = 6; + break; + case QE_CLK11: + source = 7; + break; + case QE_CLK12: + source = 8; + break; + case QE_CLK15: + source = 9; + break; + case QE_CLK16: + source = 10; + break; + default: + source = -1; + break; + } + break; + case 2: + switch (clock) { + case QE_BRG5: + source = 1; + break; + case QE_BRG6: + source = 2; + break; + case QE_BRG7: + source = 3; + break; + case QE_BRG8: + source = 4; + break; + case QE_CLK13: + source = 5; + break; + case QE_CLK14: + source = 6; + break; + case QE_CLK19: + source = 7; + break; + case QE_CLK20: + source = 8; + break; + case QE_CLK15: + source = 9; + break; + case QE_CLK16: + source = 10; break; default: source = -1; break; + } + break; + case 3: + switch (clock) { + case QE_BRG9: + source = 1; + break; + case QE_BRG10: + source = 2; + break; + case QE_BRG15: + source = 3; + break; + case QE_BRG16: + source = 4; + break; + case QE_CLK3: + source = 5; + break; + case QE_CLK4: + source = 6; + break; + case QE_CLK17: + source = 7; + break; + case QE_CLK18: + source = 8; + break; + case QE_CLK7: + source = 9; + break; + case QE_CLK8: + source = 10; + break; + case QE_CLK16: + source = 11; + break; + default: + source = -1; + break; + } + break; + case 4: + switch (clock) { + case QE_BRG13: + source = 1; + break; + case QE_BRG14: + source = 2; + break; + case QE_BRG15: + source = 3; + break; + case QE_BRG16: + source = 4; + break; + case QE_CLK5: + source = 5; + break; + case QE_CLK6: + source = 6; + break; + case QE_CLK21: + source = 7; + break; + case QE_CLK22: + source = 8; + break; + case QE_CLK7: + source = 9; + break; + case QE_CLK8: + source = 10; + break; + case QE_CLK16: + source = 11; + break; + default: + source = -1; + break; + } + break; + default: + source = -1; + break; } if (source == -1) { - printf("%s: Bad combination of clock and UCC\n", __FUNCTION__); + printf("%s: Bad combination of clock and UCC\n", __func__); return -ENOENT; } - clockBits = (u32) source; - clockMask = QE_CMXUCR_TX_CLK_SRC_MASK; + clk_bits = (u32)source; + clk_mask = QE_CMXUCR_TX_CLK_SRC_MASK; if (mode == COMM_DIR_RX) { - clockBits <<= 4; /* Rx field is 4 bits to left of Tx field */ - clockMask <<= 4; /* Rx field is 4 bits to left of Tx field */ + clk_bits <<= 4; /* Rx field is 4 bits to left of Tx field */ + clk_mask <<= 4; /* Rx field is 4 bits to left of Tx field */ } - clockBits <<= shift; - clockMask <<= shift; + clk_bits <<= shift; + clk_mask <<= shift; - out_be32(p_cmxucr, (in_be32(p_cmxucr) & ~clockMask) | clockBits); + out_be32(p_cmxucr, (in_be32(p_cmxucr) & ~clk_mask) | clk_bits); return 0; } @@ -195,28 +296,45 @@ static uint ucc_get_reg_baseaddr(int ucc_num) uint base = 0; /* check if the UCC number is in range */ - if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) { - printf("%s: the UCC num not in ranges\n", __FUNCTION__); + if ((ucc_num > UCC_MAX_NUM - 1) || ucc_num < 0) { + printf("%s: the UCC num not in ranges\n", __func__); return 0; } switch (ucc_num) { - case 0: base = 0x00002000; break; - case 1: base = 0x00003000; break; - case 2: base = 0x00002200; break; - case 3: base = 0x00003200; break; - case 4: base = 0x00002400; break; - case 5: base = 0x00003400; break; - case 6: base = 0x00002600; break; - case 7: base = 0x00003600; break; - default: break; + case 0: + base = 0x00002000; + break; + case 1: + base = 0x00003000; + break; + case 2: + base = 0x00002200; + break; + case 3: + base = 0x00003200; + break; + case 4: + base = 0x00002400; + break; + case 5: + base = 0x00003400; + break; + case 6: + base = 0x00002600; + break; + case 7: + base = 0x00003600; + break; + default: + break; } base = (uint)qe_immr + base; return base; } -void ucc_fast_enable(ucc_fast_private_t *uccf, comm_dir_e mode) +void ucc_fast_enable(struct ucc_fast_priv *uccf, comm_dir_e mode) { ucc_fast_t *uf_regs; u32 gumr; @@ -236,7 +354,7 @@ void ucc_fast_enable(ucc_fast_private_t *uccf, comm_dir_e mode) out_be32(&uf_regs->gumr, gumr); } -void ucc_fast_disable(ucc_fast_private_t *uccf, comm_dir_e mode) +void ucc_fast_disable(struct ucc_fast_priv *uccf, comm_dir_e mode) { ucc_fast_t *uf_regs; u32 gumr; @@ -256,34 +374,35 @@ void ucc_fast_disable(ucc_fast_private_t *uccf, comm_dir_e mode) out_be32(&uf_regs->gumr, gumr); } -int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret) +int ucc_fast_init(struct ucc_fast_inf *uf_info, + struct ucc_fast_priv **uccf_ret) { - ucc_fast_private_t *uccf; + struct ucc_fast_priv *uccf; ucc_fast_t *uf_regs; if (!uf_info) return -EINVAL; - if ((uf_info->ucc_num < 0) || (uf_info->ucc_num > UCC_MAX_NUM - 1)) { - printf("%s: Illagal UCC number!\n", __FUNCTION__); + if (uf_info->ucc_num < 0 || (uf_info->ucc_num > UCC_MAX_NUM - 1)) { + printf("%s: Illagal UCC number!\n", __func__); return -EINVAL; } - uccf = (ucc_fast_private_t *)malloc(sizeof(ucc_fast_private_t)); + uccf = (struct ucc_fast_priv *)malloc(sizeof(struct ucc_fast_priv)); if (!uccf) { printf("%s: No memory for UCC fast data structure!\n", - __FUNCTION__); + __func__); return -ENOMEM; } - memset(uccf, 0, sizeof(ucc_fast_private_t)); + memset(uccf, 0, sizeof(struct ucc_fast_priv)); /* Save fast UCC structure */ uccf->uf_info = uf_info; uccf->uf_regs = (ucc_fast_t *)ucc_get_reg_baseaddr(uf_info->ucc_num); - if (uccf->uf_regs == NULL) { + if (!uccf->uf_regs) { printf("%s: No memory map for UCC fast controller!\n", - __FUNCTION__); + __func__); return -ENOMEM; } @@ -291,8 +410,8 @@ int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret) uccf->enabled_rx = 0; uf_regs = uccf->uf_regs; - uccf->p_ucce = (u32 *) &(uf_regs->ucce); - uccf->p_uccm = (u32 *) &(uf_regs->uccm); + uccf->p_ucce = (u32 *)&uf_regs->ucce; + uccf->p_uccm = (u32 *)&uf_regs->uccm; /* Init GUEMR register, UCC both Rx and Tx is Fast protocol */ out_8(&uf_regs->guemr, UCC_GUEMR_SET_RESERVED3 | UCC_GUEMR_MODE_FAST_RX @@ -306,13 +425,13 @@ int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret) /* Allocate memory for Tx Virtual Fifo */ uccf->ucc_fast_tx_virtual_fifo_base_offset = qe_muram_alloc(UCC_GETH_UTFS_GIGA_INIT, - UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); + UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); /* Allocate memory for Rx Virtual Fifo */ uccf->ucc_fast_rx_virtual_fifo_base_offset = qe_muram_alloc(UCC_GETH_URFS_GIGA_INIT + - UCC_FAST_RX_VIRTUAL_FIFO_SIZE_PAD, - UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); + UCC_FAST_RX_VIRTUAL_FIFO_SIZE_PAD, + UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); /* utfb, urfb are offsets from MURAM base */ out_be32(&uf_regs->utfb, @@ -334,7 +453,7 @@ int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret) /* Allocate memory for Tx Virtual Fifo */ uccf->ucc_fast_tx_virtual_fifo_base_offset = qe_muram_alloc(UCC_GETH_UTFS_INIT, - UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); + UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); /* Allocate memory for Rx Virtual Fifo */ uccf->ucc_fast_rx_virtual_fifo_base_offset = @@ -360,9 +479,9 @@ int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret) /* Rx clock routing */ if (uf_info->rx_clock != QE_CLK_NONE) { if (ucc_set_clk_src(uf_info->ucc_num, - uf_info->rx_clock, COMM_DIR_RX)) { + uf_info->rx_clock, COMM_DIR_RX)) { printf("%s: Illegal value for parameter 'RxClock'.\n", - __FUNCTION__); + __func__); return -EINVAL; } } @@ -370,9 +489,9 @@ int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret) /* Tx clock routing */ if (uf_info->tx_clock != QE_CLK_NONE) { if (ucc_set_clk_src(uf_info->ucc_num, - uf_info->tx_clock, COMM_DIR_TX)) { + uf_info->tx_clock, COMM_DIR_TX)) { printf("%s: Illegal value for parameter 'TxClock'.\n", - __FUNCTION__); + __func__); return -EINVAL; } } diff --git a/drivers/qe/uccf.h b/drivers/qe/uccf.h index 4098c66317..99f8458edf 100644 --- a/drivers/qe/uccf.h +++ b/drivers/qe/uccf.h @@ -13,25 +13,23 @@ #include "linux/immap_qe.h" #include -/* Fast or Giga ethernet -*/ -typedef enum enet_type { +/* Fast or Giga ethernet */ +enum enet_type { FAST_ETH, GIGA_ETH, -} enet_type_e; +}; -/* General UCC Extended Mode Register -*/ +/* General UCC Extended Mode Register */ #define UCC_GUEMR_MODE_MASK_RX 0x02 #define UCC_GUEMR_MODE_MASK_TX 0x01 #define UCC_GUEMR_MODE_FAST_RX 0x02 #define UCC_GUEMR_MODE_FAST_TX 0x01 #define UCC_GUEMR_MODE_SLOW_RX 0x00 #define UCC_GUEMR_MODE_SLOW_TX 0x00 -#define UCC_GUEMR_SET_RESERVED3 0x10 /* Bit 3 must be set 1 */ +/* Bit 3 must be set 1 */ +#define UCC_GUEMR_SET_RESERVED3 0x10 -/* General UCC FAST Mode Register -*/ +/* General UCC FAST Mode Register */ #define UCC_FAST_GUMR_TCI 0x20000000 #define UCC_FAST_GUMR_TRX 0x10000000 #define UCC_FAST_GUMR_TTX 0x08000000 @@ -46,8 +44,7 @@ typedef enum enet_type { #define UCC_FAST_GUMR_ENR 0x00000020 #define UCC_FAST_GUMR_ENT 0x00000010 -/* GUMR [MODE] bit maps -*/ +/* GUMR [MODE] bit maps */ #define UCC_FAST_GUMR_HDLC 0x00000000 #define UCC_FAST_GUMR_QMC 0x00000002 #define UCC_FAST_GUMR_UART 0x00000004 @@ -55,50 +52,54 @@ typedef enum enet_type { #define UCC_FAST_GUMR_ATM 0x0000000a #define UCC_FAST_GUMR_ETH 0x0000000c -/* Transmit On Demand (UTORD) -*/ +/* Transmit On Demand (UTORD) */ #define UCC_SLOW_TOD 0x8000 #define UCC_FAST_TOD 0x8000 -/* Fast Ethernet (10/100 Mbps) -*/ -#define UCC_GETH_URFS_INIT 512 /* Rx virtual FIFO size */ -#define UCC_GETH_URFET_INIT 256 /* 1/2 urfs */ -#define UCC_GETH_URFSET_INIT 384 /* 3/4 urfs */ -#define UCC_GETH_UTFS_INIT 512 /* Tx virtual FIFO size */ -#define UCC_GETH_UTFET_INIT 256 /* 1/2 utfs */ +/* Fast Ethernet (10/100 Mbps) */ +/* Rx virtual FIFO size */ +#define UCC_GETH_URFS_INIT 512 +/* 1/2 urfs */ +#define UCC_GETH_URFET_INIT 256 +/* 3/4 urfs */ +#define UCC_GETH_URFSET_INIT 384 +/* Tx virtual FIFO size */ +#define UCC_GETH_UTFS_INIT 512 +/* 1/2 utfs */ +#define UCC_GETH_UTFET_INIT 256 #define UCC_GETH_UTFTT_INIT 128 -/* Gigabit Ethernet (1000 Mbps) -*/ -#define UCC_GETH_URFS_GIGA_INIT 4096/*2048*/ /* Rx virtual FIFO size */ -#define UCC_GETH_URFET_GIGA_INIT 2048/*1024*/ /* 1/2 urfs */ -#define UCC_GETH_URFSET_GIGA_INIT 3072/*1536*/ /* 3/4 urfs */ -#define UCC_GETH_UTFS_GIGA_INIT 8192/*2048*/ /* Tx virtual FIFO size */ -#define UCC_GETH_UTFET_GIGA_INIT 4096/*1024*/ /* 1/2 utfs */ -#define UCC_GETH_UTFTT_GIGA_INIT 0x400/*0x40*/ /* */ +/* Gigabit Ethernet (1000 Mbps) */ +/* Rx virtual FIFO size */ +#define UCC_GETH_URFS_GIGA_INIT 4096/*2048*/ +/* 1/2 urfs */ +#define UCC_GETH_URFET_GIGA_INIT 2048/*1024*/ +/* 3/4 urfs */ +#define UCC_GETH_URFSET_GIGA_INIT 3072/*1536*/ +/* Tx virtual FIFO size */ +#define UCC_GETH_UTFS_GIGA_INIT 8192/*2048*/ +/* 1/2 utfs */ +#define UCC_GETH_UTFET_GIGA_INIT 4096/*1024*/ +#define UCC_GETH_UTFTT_GIGA_INIT 0x400/*0x40*/ -/* UCC fast alignment -*/ +/* UCC fast alignment */ #define UCC_FAST_RX_ALIGN 4 #define UCC_FAST_MRBLR_ALIGNMENT 4 #define UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT 8 -/* Sizes -*/ +/* Sizes */ #define UCC_FAST_RX_VIRTUAL_FIFO_SIZE_PAD 8 -/* UCC fast structure. -*/ -typedef struct ucc_fast_info { +/* UCC fast structure. */ +struct ucc_fast_inf { int ucc_num; qe_clock_e rx_clock; qe_clock_e tx_clock; - enet_type_e eth_type; -} ucc_fast_info_t; + enum enet_type eth_type; +}; -typedef struct ucc_fast_private { - ucc_fast_info_t *uf_info; +struct ucc_fast_priv { + struct ucc_fast_inf *uf_info; ucc_fast_t *uf_regs; /* a pointer to memory map of UCC regs */ u32 *p_ucce; /* a pointer to the event register */ u32 *p_uccm; /* a pointer to the mask register */ @@ -106,12 +107,13 @@ typedef struct ucc_fast_private { int enabled_rx; /* whether UCC is enabled for Rx (ENR) */ u32 ucc_fast_tx_virtual_fifo_base_offset; u32 ucc_fast_rx_virtual_fifo_base_offset; -} ucc_fast_private_t; +}; -void ucc_fast_transmit_on_demand(ucc_fast_private_t *uccf); +void ucc_fast_transmit_on_demand(struct ucc_fast_priv *uccf); u32 ucc_fast_get_qe_cr_subblock(int ucc_num); -void ucc_fast_enable(ucc_fast_private_t *uccf, comm_dir_e mode); -void ucc_fast_disable(ucc_fast_private_t *uccf, comm_dir_e mode); -int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret); +void ucc_fast_enable(struct ucc_fast_priv *uccf, comm_dir_e mode); +void ucc_fast_disable(struct ucc_fast_priv *uccf, comm_dir_e mode); +int ucc_fast_init(struct ucc_fast_inf *uf_info, + struct ucc_fast_priv **uccf_ret); #endif /* __UCCF_H__ */ diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c index 0143454387..cfd5397044 100644 --- a/drivers/qe/uec.c +++ b/drivers/qe/uec.c @@ -25,7 +25,7 @@ #define CONFIG_UTBIPAR_INIT_TBIPA 0x1F #endif -static uec_info_t uec_info[] = { +static struct uec_inf uec_info[] = { #ifdef CONFIG_UEC_ETH1 STD_UEC_INFO(1), /* UEC1 */ #endif @@ -56,13 +56,13 @@ static uec_info_t uec_info[] = { static struct eth_device *devlist[MAXCONTROLLERS]; -static int uec_mac_enable(uec_private_t *uec, comm_dir_e mode) +static int uec_mac_enable(struct uec_priv *uec, comm_dir_e mode) { uec_t *uec_regs; u32 maccfg1; if (!uec) { - printf("%s: uec not initial\n", __FUNCTION__); + printf("%s: uec not initial\n", __func__); return -EINVAL; } uec_regs = uec->uec_regs; @@ -84,13 +84,13 @@ static int uec_mac_enable(uec_private_t *uec, comm_dir_e mode) return 0; } -static int uec_mac_disable(uec_private_t *uec, comm_dir_e mode) +static int uec_mac_disable(struct uec_priv *uec, comm_dir_e mode) { uec_t *uec_regs; u32 maccfg1; if (!uec) { - printf("%s: uec not initial\n", __FUNCTION__); + printf("%s: uec not initial\n", __func__); return -EINVAL; } uec_regs = uec->uec_regs; @@ -112,14 +112,14 @@ static int uec_mac_disable(uec_private_t *uec, comm_dir_e mode) return 0; } -static int uec_graceful_stop_tx(uec_private_t *uec) +static int uec_graceful_stop_tx(struct uec_priv *uec) { ucc_fast_t *uf_regs; u32 cecr_subblock; u32 ucce; if (!uec || !uec->uccf) { - printf("%s: No handle passed.\n", __FUNCTION__); + printf("%s: No handle passed.\n", __func__); return -EINVAL; } @@ -132,30 +132,30 @@ static int uec_graceful_stop_tx(uec_private_t *uec) cecr_subblock = ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num); qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock, - (u8)QE_CR_PROTOCOL_ETHERNET, 0); + (u8)QE_CR_PROTOCOL_ETHERNET, 0); /* Wait for command to complete */ do { ucce = in_be32(&uf_regs->ucce); - } while (! (ucce & UCCE_GRA)); + } while (!(ucce & UCCE_GRA)); uec->grace_stopped_tx = 1; return 0; } -static int uec_graceful_stop_rx(uec_private_t *uec) +static int uec_graceful_stop_rx(struct uec_priv *uec) { u32 cecr_subblock; u8 ack; if (!uec) { - printf("%s: No handle passed.\n", __FUNCTION__); + printf("%s: No handle passed.\n", __func__); return -EINVAL; } if (!uec->p_rx_glbl_pram) { - printf("%s: No init rx global parameter\n", __FUNCTION__); + printf("%s: No init rx global parameter\n", __func__); return -EINVAL; } @@ -170,66 +170,66 @@ static int uec_graceful_stop_rx(uec_private_t *uec) cecr_subblock = ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num); qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock, - (u8)QE_CR_PROTOCOL_ETHERNET, 0); + (u8)QE_CR_PROTOCOL_ETHERNET, 0); ack = uec->p_rx_glbl_pram->rxgstpack; - } while (! (ack & GRACEFUL_STOP_ACKNOWLEDGE_RX )); + } while (!(ack & GRACEFUL_STOP_ACKNOWLEDGE_RX)); uec->grace_stopped_rx = 1; return 0; } -static int uec_restart_tx(uec_private_t *uec) +static int uec_restart_tx(struct uec_priv *uec) { u32 cecr_subblock; if (!uec || !uec->uec_info) { - printf("%s: No handle passed.\n", __FUNCTION__); + printf("%s: No handle passed.\n", __func__); return -EINVAL; } cecr_subblock = ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num); qe_issue_cmd(QE_RESTART_TX, cecr_subblock, - (u8)QE_CR_PROTOCOL_ETHERNET, 0); + (u8)QE_CR_PROTOCOL_ETHERNET, 0); uec->grace_stopped_tx = 0; return 0; } -static int uec_restart_rx(uec_private_t *uec) +static int uec_restart_rx(struct uec_priv *uec) { u32 cecr_subblock; if (!uec || !uec->uec_info) { - printf("%s: No handle passed.\n", __FUNCTION__); + printf("%s: No handle passed.\n", __func__); return -EINVAL; } cecr_subblock = ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num); qe_issue_cmd(QE_RESTART_RX, cecr_subblock, - (u8)QE_CR_PROTOCOL_ETHERNET, 0); + (u8)QE_CR_PROTOCOL_ETHERNET, 0); uec->grace_stopped_rx = 0; return 0; } -static int uec_open(uec_private_t *uec, comm_dir_e mode) +static int uec_open(struct uec_priv *uec, comm_dir_e mode) { - ucc_fast_private_t *uccf; + struct ucc_fast_priv *uccf; if (!uec || !uec->uccf) { - printf("%s: No handle passed.\n", __FUNCTION__); + printf("%s: No handle passed.\n", __func__); return -EINVAL; } uccf = uec->uccf; /* check if the UCC number is in range. */ if (uec->uec_info->uf_info.ucc_num >= UCC_MAX_NUM) { - printf("%s: ucc_num out of range.\n", __FUNCTION__); + printf("%s: ucc_num out of range.\n", __func__); return -EINVAL; } @@ -240,36 +240,33 @@ static int uec_open(uec_private_t *uec, comm_dir_e mode) ucc_fast_enable(uccf, mode); /* RISC microcode start */ - if ((mode & COMM_DIR_TX) && uec->grace_stopped_tx) { + if ((mode & COMM_DIR_TX) && uec->grace_stopped_tx) uec_restart_tx(uec); - } - if ((mode & COMM_DIR_RX) && uec->grace_stopped_rx) { + if ((mode & COMM_DIR_RX) && uec->grace_stopped_rx) uec_restart_rx(uec); - } return 0; } -static int uec_stop(uec_private_t *uec, comm_dir_e mode) +static int uec_stop(struct uec_priv *uec, comm_dir_e mode) { if (!uec || !uec->uccf) { - printf("%s: No handle passed.\n", __FUNCTION__); + printf("%s: No handle passed.\n", __func__); return -EINVAL; } /* check if the UCC number is in range. */ if (uec->uec_info->uf_info.ucc_num >= UCC_MAX_NUM) { - printf("%s: ucc_num out of range.\n", __FUNCTION__); + printf("%s: ucc_num out of range.\n", __func__); return -EINVAL; } /* Stop any transmissions */ - if ((mode & COMM_DIR_TX) && !uec->grace_stopped_tx) { + if ((mode & COMM_DIR_TX) && !uec->grace_stopped_tx) uec_graceful_stop_tx(uec); - } + /* Stop any receptions */ - if ((mode & COMM_DIR_RX) && !uec->grace_stopped_rx) { + if ((mode & COMM_DIR_RX) && !uec->grace_stopped_rx) uec_graceful_stop_rx(uec); - } /* Disable the UCC fast */ ucc_fast_disable(uec->uccf, mode); @@ -280,13 +277,13 @@ static int uec_stop(uec_private_t *uec, comm_dir_e mode) return 0; } -static int uec_set_mac_duplex(uec_private_t *uec, int duplex) +static int uec_set_mac_duplex(struct uec_priv *uec, int duplex) { uec_t *uec_regs; u32 maccfg2; if (!uec) { - printf("%s: uec not initial\n", __FUNCTION__); + printf("%s: uec not initial\n", __func__); return -EINVAL; } uec_regs = uec->uec_regs; @@ -306,8 +303,8 @@ static int uec_set_mac_duplex(uec_private_t *uec, int duplex) return 0; } -static int uec_set_mac_if_mode(uec_private_t *uec, - phy_interface_t if_mode, int speed) +static int uec_set_mac_if_mode(struct uec_priv *uec, + phy_interface_t if_mode, int speed) { phy_interface_t enet_if_mode; uec_t *uec_regs; @@ -315,7 +312,7 @@ static int uec_set_mac_if_mode(uec_private_t *uec, u32 maccfg2; if (!uec) { - printf("%s: uec not initial\n", __FUNCTION__); + printf("%s: uec not initial\n", __func__); return -EINVAL; } @@ -329,66 +326,62 @@ static int uec_set_mac_if_mode(uec_private_t *uec, upsmr &= ~(UPSMR_RPM | UPSMR_TBIM | UPSMR_R10M | UPSMR_RMM); switch (speed) { - case SPEED_10: - maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; - switch (enet_if_mode) { - case PHY_INTERFACE_MODE_MII: - break; - case PHY_INTERFACE_MODE_RGMII: - upsmr |= (UPSMR_RPM | UPSMR_R10M); - break; - case PHY_INTERFACE_MODE_RMII: - upsmr |= (UPSMR_R10M | UPSMR_RMM); - break; - default: - return -EINVAL; - break; - } + case SPEED_10: + maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; + switch (enet_if_mode) { + case PHY_INTERFACE_MODE_MII: break; - case SPEED_100: - maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; - switch (enet_if_mode) { - case PHY_INTERFACE_MODE_MII: - break; - case PHY_INTERFACE_MODE_RGMII: - upsmr |= UPSMR_RPM; - break; - case PHY_INTERFACE_MODE_RMII: - upsmr |= UPSMR_RMM; - break; - default: - return -EINVAL; - break; - } + case PHY_INTERFACE_MODE_RGMII: + upsmr |= (UPSMR_RPM | UPSMR_R10M); break; - case SPEED_1000: - maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; - switch (enet_if_mode) { - case PHY_INTERFACE_MODE_GMII: - break; - case PHY_INTERFACE_MODE_TBI: - upsmr |= UPSMR_TBIM; - break; - case PHY_INTERFACE_MODE_RTBI: - upsmr |= (UPSMR_RPM | UPSMR_TBIM); - break; - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_TXID: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII: - upsmr |= UPSMR_RPM; - break; - case PHY_INTERFACE_MODE_SGMII: - upsmr |= UPSMR_SGMM; - break; - default: - return -EINVAL; - break; - } + case PHY_INTERFACE_MODE_RMII: + upsmr |= (UPSMR_R10M | UPSMR_RMM); break; default: return -EINVAL; + } + break; + case SPEED_100: + maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; + switch (enet_if_mode) { + case PHY_INTERFACE_MODE_MII: + break; + case PHY_INTERFACE_MODE_RGMII: + upsmr |= UPSMR_RPM; + break; + case PHY_INTERFACE_MODE_RMII: + upsmr |= UPSMR_RMM; + break; + default: + return -EINVAL; + } + break; + case SPEED_1000: + maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; + switch (enet_if_mode) { + case PHY_INTERFACE_MODE_GMII: + break; + case PHY_INTERFACE_MODE_TBI: + upsmr |= UPSMR_TBIM; + break; + case PHY_INTERFACE_MODE_RTBI: + upsmr |= (UPSMR_RPM | UPSMR_TBIM); + break; + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII: + upsmr |= UPSMR_RPM; break; + case PHY_INTERFACE_MODE_SGMII: + upsmr |= UPSMR_SGMM; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; } out_be32(&uec_regs->maccfg2, maccfg2); @@ -407,9 +400,10 @@ static int init_mii_management_configuration(uec_mii_t *uec_mii_regs) out_be32(&uec_mii_regs->miimcfg, miimcfg); /* Wait until the bus is free */ - while ((in_be32(&uec_mii_regs->miimcfg) & MIIMIND_BUSY) && timeout--); + while ((in_be32(&uec_mii_regs->miimcfg) & MIIMIND_BUSY) && timeout--) + ; if (timeout <= 0) { - printf("%s: The MII Bus is stuck!", __FUNCTION__); + printf("%s: The MII Bus is stuck!", __func__); return -ETIMEDOUT; } @@ -418,13 +412,13 @@ static int init_mii_management_configuration(uec_mii_t *uec_mii_regs) static int init_phy(struct eth_device *dev) { - uec_private_t *uec; + struct uec_priv *uec; uec_mii_t *umii_regs; struct uec_mii_info *mii_info; struct phy_info *curphy; int err; - uec = (uec_private_t *)dev->priv; + uec = (struct uec_priv *)dev->priv; umii_regs = uec->uec_mii_regs; uec->oldlink = 0; @@ -438,11 +432,10 @@ static int init_phy(struct eth_device *dev) } memset(mii_info, 0, sizeof(*mii_info)); - if (uec->uec_info->uf_info.eth_type == GIGA_ETH) { + if (uec->uec_info->uf_info.eth_type == GIGA_ETH) mii_info->speed = SPEED_1000; - } else { + else mii_info->speed = SPEED_100; - } mii_info->duplex = DUPLEX_FULL; mii_info->pause = 0; @@ -498,15 +491,14 @@ bus_fail: static void adjust_link(struct eth_device *dev) { - uec_private_t *uec = (uec_private_t *)dev->priv; + struct uec_priv *uec = (struct uec_priv *)dev->priv; struct uec_mii_info *mii_info = uec->mii_info; - extern void change_phy_interface_mode(struct eth_device *dev, - phy_interface_t mode, int speed); - if (mii_info->link) { - /* Now we make sure that we can be in full duplex mode. - * If not, we operate in half-duplex mode. */ + /* + * Now we make sure that we can be in full duplex mode. + * If not, we operate in half-duplex mode. + */ if (mii_info->duplex != uec->oldduplex) { if (!(mii_info->duplex)) { uec_set_mac_duplex(uec, DUPLEX_HALF); @@ -526,16 +518,16 @@ static void adjust_link(struct eth_device *dev) case SPEED_1000: break; case SPEED_100: - printf ("switching to rgmii 100\n"); + printf("switching to rgmii 100\n"); mode = PHY_INTERFACE_MODE_RGMII; break; case SPEED_10: - printf ("switching to rgmii 10\n"); + printf("switching to rgmii 10\n"); mode = PHY_INTERFACE_MODE_RGMII; break; default: printf("%s: Ack,Speed(%d)is illegal\n", - dev->name, mii_info->speed); + dev->name, mii_info->speed); break; } } @@ -566,12 +558,12 @@ static void adjust_link(struct eth_device *dev) static void phy_change(struct eth_device *dev) { - uec_private_t *uec = (uec_private_t *)dev->priv; + struct uec_priv *uec = (struct uec_priv *)dev->priv; #if defined(CONFIG_ARCH_P1021) || defined(CONFIG_ARCH_P1025) ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); - /* QE9 and QE12 need to be set for enabling QE MII managment signals */ + /* QE9 and QE12 need to be set for enabling QE MII management signals */ setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE9); setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE12); #endif @@ -604,14 +596,14 @@ static int uec_miiphy_find_dev_by_name(const char *devname) int i; for (i = 0; i < MAXCONTROLLERS; i++) { - if (strncmp(devname, devlist[i]->name, strlen(devname)) == 0) { + if (strncmp(devname, devlist[i]->name, strlen(devname)) == 0) break; - } } /* If device cannot be found, returns -1 */ if (i == MAXCONTROLLERS) { - debug ("%s: device %s not found in devlist\n", __FUNCTION__, devname); + debug("%s: device %s not found in devlist\n", __func__, + devname); i = -1; } @@ -629,13 +621,12 @@ static int uec_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg) unsigned short value = 0; int devindex = 0; - if (bus->name == NULL) { - debug("%s: NULL pointer given\n", __FUNCTION__); + if (!bus->name) { + debug("%s: NULL pointer given\n", __func__); } else { devindex = uec_miiphy_find_dev_by_name(bus->name); - if (devindex >= 0) { + if (devindex >= 0) value = uec_read_phy_reg(devlist[devindex], addr, reg); - } } return value; } @@ -651,36 +642,37 @@ static int uec_miiphy_write(struct mii_dev *bus, int addr, int devad, int reg, { int devindex = 0; - if (bus->name == NULL) { - debug("%s: NULL pointer given\n", __FUNCTION__); + if (!bus->name) { + debug("%s: NULL pointer given\n", __func__); } else { devindex = uec_miiphy_find_dev_by_name(bus->name); - if (devindex >= 0) { + if (devindex >= 0) uec_write_phy_reg(devlist[devindex], addr, reg, value); - } } return 0; } #endif -static int uec_set_mac_address(uec_private_t *uec, u8 *mac_addr) +static int uec_set_mac_address(struct uec_priv *uec, u8 *mac_addr) { uec_t *uec_regs; u32 mac_addr1; u32 mac_addr2; if (!uec) { - printf("%s: uec not initial\n", __FUNCTION__); + printf("%s: uec not initial\n", __func__); return -EINVAL; } uec_regs = uec->uec_regs; - /* if a station address of 0x12345678ABCD, perform a write to - MACSTNADDR1 of 0xCDAB7856, - MACSTNADDR2 of 0x34120000 */ + /* + * if a station address of 0x12345678ABCD, perform a write to + * MACSTNADDR1 of 0xCDAB7856, + * MACSTNADDR2 of 0x34120000 + */ - mac_addr1 = (mac_addr[5] << 24) | (mac_addr[4] << 16) | \ + mac_addr1 = (mac_addr[5] << 24) | (mac_addr[4] << 16) | (mac_addr[3] << 8) | (mac_addr[2]); out_be32(&uec_regs->macstnaddr1, mac_addr1); @@ -690,31 +682,31 @@ static int uec_set_mac_address(uec_private_t *uec, u8 *mac_addr) return 0; } -static int uec_convert_threads_num(uec_num_of_threads_e threads_num, - int *threads_num_ret) +static int uec_convert_threads_num(enum uec_num_of_threads threads_num, + int *threads_num_ret) { int num_threads_numerica; switch (threads_num) { - case UEC_NUM_OF_THREADS_1: - num_threads_numerica = 1; - break; - case UEC_NUM_OF_THREADS_2: - num_threads_numerica = 2; - break; - case UEC_NUM_OF_THREADS_4: - num_threads_numerica = 4; - break; - case UEC_NUM_OF_THREADS_6: - num_threads_numerica = 6; - break; - case UEC_NUM_OF_THREADS_8: - num_threads_numerica = 8; - break; - default: - printf("%s: Bad number of threads value.", - __FUNCTION__); - return -EINVAL; + case UEC_NUM_OF_THREADS_1: + num_threads_numerica = 1; + break; + case UEC_NUM_OF_THREADS_2: + num_threads_numerica = 2; + break; + case UEC_NUM_OF_THREADS_4: + num_threads_numerica = 4; + break; + case UEC_NUM_OF_THREADS_6: + num_threads_numerica = 6; + break; + case UEC_NUM_OF_THREADS_8: + num_threads_numerica = 8; + break; + default: + printf("%s: Bad number of threads value.", + __func__); + return -EINVAL; } *threads_num_ret = num_threads_numerica; @@ -722,9 +714,9 @@ static int uec_convert_threads_num(uec_num_of_threads_e threads_num, return 0; } -static void uec_init_tx_parameter(uec_private_t *uec, int num_threads_tx) +static void uec_init_tx_parameter(struct uec_priv *uec, int num_threads_tx) { - uec_info_t *uec_info; + struct uec_inf *uec_info; u32 end_bd; u8 bmrx = 0; int i; @@ -732,14 +724,14 @@ static void uec_init_tx_parameter(uec_private_t *uec, int num_threads_tx) uec_info = uec->uec_info; /* Alloc global Tx parameter RAM page */ - uec->tx_glbl_pram_offset = qe_muram_alloc( - sizeof(uec_tx_global_pram_t), - UEC_TX_GLOBAL_PRAM_ALIGNMENT); - uec->p_tx_glbl_pram = (uec_tx_global_pram_t *) + uec->tx_glbl_pram_offset = + qe_muram_alloc(sizeof(struct uec_tx_global_pram), + UEC_TX_GLOBAL_PRAM_ALIGNMENT); + uec->p_tx_glbl_pram = (struct uec_tx_global_pram *) qe_muram_addr(uec->tx_glbl_pram_offset); /* Zero the global Tx prameter RAM */ - memset(uec->p_tx_glbl_pram, 0, sizeof(uec_tx_global_pram_t)); + memset(uec->p_tx_glbl_pram, 0, sizeof(struct uec_tx_global_pram)); /* Init global Tx parameter RAM */ @@ -747,10 +739,10 @@ static void uec_init_tx_parameter(uec_private_t *uec, int num_threads_tx) out_be16(&uec->p_tx_glbl_pram->temoder, TEMODER_INIT_VALUE); /* SQPTR */ - uec->send_q_mem_reg_offset = qe_muram_alloc( - sizeof(uec_send_queue_qd_t), - UEC_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT); - uec->p_send_q_mem_reg = (uec_send_queue_mem_region_t *) + uec->send_q_mem_reg_offset = + qe_muram_alloc(sizeof(struct uec_send_queue_qd), + UEC_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT); + uec->p_send_q_mem_reg = (struct uec_send_queue_mem_region *) qe_muram_addr(uec->send_q_mem_reg_offset); out_be32(&uec->p_tx_glbl_pram->sqptr, uec->send_q_mem_reg_offset); @@ -758,9 +750,9 @@ static void uec_init_tx_parameter(uec_private_t *uec, int num_threads_tx) end_bd = (u32)uec->p_tx_bd_ring + (uec_info->tx_bd_ring_len - 1) * SIZEOFBD; out_be32(&uec->p_send_q_mem_reg->sqqd[0].bd_ring_base, - (u32)(uec->p_tx_bd_ring)); + (u32)(uec->p_tx_bd_ring)); out_be32(&uec->p_send_q_mem_reg->sqqd[0].last_bd_completed_address, - end_bd); + end_bd); /* Scheduler Base Pointer, we have only one Tx queue, no need it */ out_be32(&uec->p_tx_glbl_pram->schedulerbasepointer, 0); @@ -773,54 +765,57 @@ static void uec_init_tx_parameter(uec_private_t *uec, int num_threads_tx) out_be32(&uec->p_tx_glbl_pram->tstate, ((u32)(bmrx) << BMR_SHIFT)); /* IPH_Offset */ - for (i = 0; i < MAX_IPH_OFFSET_ENTRY; i++) { + for (i = 0; i < MAX_IPH_OFFSET_ENTRY; i++) out_8(&uec->p_tx_glbl_pram->iphoffset[i], 0); - } /* VTAG table */ - for (i = 0; i < UEC_TX_VTAG_TABLE_ENTRY_MAX; i++) { + for (i = 0; i < UEC_TX_VTAG_TABLE_ENTRY_MAX; i++) out_be32(&uec->p_tx_glbl_pram->vtagtable[i], 0); - } /* TQPTR */ - uec->thread_dat_tx_offset = qe_muram_alloc( - num_threads_tx * sizeof(uec_thread_data_tx_t) + - 32 *(num_threads_tx == 1), UEC_THREAD_DATA_ALIGNMENT); + uec->thread_dat_tx_offset = + qe_muram_alloc(num_threads_tx * + sizeof(struct uec_thread_data_tx) + + 32 * (num_threads_tx == 1), + UEC_THREAD_DATA_ALIGNMENT); - uec->p_thread_data_tx = (uec_thread_data_tx_t *) + uec->p_thread_data_tx = (struct uec_thread_data_tx *) qe_muram_addr(uec->thread_dat_tx_offset); out_be32(&uec->p_tx_glbl_pram->tqptr, uec->thread_dat_tx_offset); } -static void uec_init_rx_parameter(uec_private_t *uec, int num_threads_rx) +static void uec_init_rx_parameter(struct uec_priv *uec, int num_threads_rx) { u8 bmrx = 0; int i; - uec_82xx_address_filtering_pram_t *p_af_pram; + struct uec_82xx_add_filtering_pram *p_af_pram; /* Allocate global Rx parameter RAM page */ - uec->rx_glbl_pram_offset = qe_muram_alloc( - sizeof(uec_rx_global_pram_t), UEC_RX_GLOBAL_PRAM_ALIGNMENT); - uec->p_rx_glbl_pram = (uec_rx_global_pram_t *) + uec->rx_glbl_pram_offset = + qe_muram_alloc(sizeof(struct uec_rx_global_pram), + UEC_RX_GLOBAL_PRAM_ALIGNMENT); + uec->p_rx_glbl_pram = (struct uec_rx_global_pram *) qe_muram_addr(uec->rx_glbl_pram_offset); /* Zero Global Rx parameter RAM */ - memset(uec->p_rx_glbl_pram, 0, sizeof(uec_rx_global_pram_t)); + memset(uec->p_rx_glbl_pram, 0, sizeof(struct uec_rx_global_pram)); /* Init global Rx parameter RAM */ - /* REMODER, Extended feature mode disable, VLAN disable, - LossLess flow control disable, Receive firmware statisic disable, - Extended address parsing mode disable, One Rx queues, - Dynamic maximum/minimum frame length disable, IP checksum check - disable, IP address alignment disable - */ + /* + * REMODER, Extended feature mode disable, VLAN disable, + * LossLess flow control disable, Receive firmware statisic disable, + * Extended address parsing mode disable, One Rx queues, + * Dynamic maximum/minimum frame length disable, IP checksum check + * disable, IP address alignment disable + */ out_be32(&uec->p_rx_glbl_pram->remoder, REMODER_INIT_VALUE); /* RQPTR */ - uec->thread_dat_rx_offset = qe_muram_alloc( - num_threads_rx * sizeof(uec_thread_data_rx_t), - UEC_THREAD_DATA_ALIGNMENT); - uec->p_thread_data_rx = (uec_thread_data_rx_t *) + uec->thread_dat_rx_offset = + qe_muram_alloc(num_threads_rx * + sizeof(struct uec_thread_data_rx), + UEC_THREAD_DATA_ALIGNMENT); + uec->p_thread_data_rx = (struct uec_thread_data_rx *) qe_muram_addr(uec->thread_dat_rx_offset); out_be32(&uec->p_rx_glbl_pram->rqptr, uec->thread_dat_rx_offset); @@ -841,16 +836,16 @@ static void uec_init_rx_parameter(uec_private_t *uec, int num_threads_rx) out_be16(&uec->p_rx_glbl_pram->mrblr, MAX_RXBUF_LEN); /* RBDQPTR */ - uec->rx_bd_qs_tbl_offset = qe_muram_alloc( - sizeof(uec_rx_bd_queues_entry_t) + \ - sizeof(uec_rx_prefetched_bds_t), - UEC_RX_BD_QUEUES_ALIGNMENT); - uec->p_rx_bd_qs_tbl = (uec_rx_bd_queues_entry_t *) + uec->rx_bd_qs_tbl_offset = + qe_muram_alloc(sizeof(struct uec_rx_bd_queues_entry) + + sizeof(struct uec_rx_pref_bds), + UEC_RX_BD_QUEUES_ALIGNMENT); + uec->p_rx_bd_qs_tbl = (struct uec_rx_bd_queues_entry *) qe_muram_addr(uec->rx_bd_qs_tbl_offset); /* Zero it */ - memset(uec->p_rx_bd_qs_tbl, 0, sizeof(uec_rx_bd_queues_entry_t) + \ - sizeof(uec_rx_prefetched_bds_t)); + memset(uec->p_rx_bd_qs_tbl, 0, sizeof(struct uec_rx_bd_queues_entry) + + sizeof(struct uec_rx_pref_bds)); out_be32(&uec->p_rx_glbl_pram->rbdqptr, uec->rx_bd_qs_tbl_offset); out_be32(&uec->p_rx_bd_qs_tbl->externalbdbaseptr, (u32)uec->p_rx_bd_ring); @@ -868,9 +863,8 @@ static void uec_init_rx_parameter(uec_private_t *uec, int num_threads_rx) /* L2QT */ out_be32(&uec->p_rx_glbl_pram->l2qt, 0); /* L3QT */ - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) out_be32(&uec->p_rx_glbl_pram->l3qt[i], 0); - } /* VLAN_TYPE */ out_be16(&uec->p_rx_glbl_pram->vlantype, 0x8100); @@ -878,7 +872,7 @@ static void uec_init_rx_parameter(uec_private_t *uec, int num_threads_rx) out_be16(&uec->p_rx_glbl_pram->vlantci, 0); /* Clear PQ2 style address filtering hash table */ - p_af_pram = (uec_82xx_address_filtering_pram_t *) \ + p_af_pram = (struct uec_82xx_add_filtering_pram *) uec->p_rx_glbl_pram->addressfiltering; p_af_pram->iaddr_h = 0; @@ -887,30 +881,33 @@ static void uec_init_rx_parameter(uec_private_t *uec, int num_threads_rx) p_af_pram->gaddr_l = 0; } -static int uec_issue_init_enet_rxtx_cmd(uec_private_t *uec, - int thread_tx, int thread_rx) +static int uec_issue_init_enet_rxtx_cmd(struct uec_priv *uec, + int thread_tx, int thread_rx) { - uec_init_cmd_pram_t *p_init_enet_param; + struct uec_init_cmd_pram *p_init_enet_param; u32 init_enet_param_offset; - uec_info_t *uec_info; + struct uec_inf *uec_info; + struct ucc_fast_inf *uf_info; int i; int snum; - u32 init_enet_offset; + u32 off; u32 entry_val; u32 command; u32 cecr_subblock; uec_info = uec->uec_info; + uf_info = &uec_info->uf_info; /* Allocate init enet command parameter */ - uec->init_enet_param_offset = qe_muram_alloc( - sizeof(uec_init_cmd_pram_t), 4); + uec->init_enet_param_offset = + qe_muram_alloc(sizeof(struct uec_init_cmd_pram), 4); init_enet_param_offset = uec->init_enet_param_offset; - uec->p_init_enet_param = (uec_init_cmd_pram_t *) + uec->p_init_enet_param = (struct uec_init_cmd_pram *) qe_muram_addr(uec->init_enet_param_offset); /* Zero init enet command struct */ - memset((void *)uec->p_init_enet_param, 0, sizeof(uec_init_cmd_pram_t)); + memset((void *)uec->p_init_enet_param, 0, + sizeof(struct uec_init_cmd_pram)); /* Init the command struct */ p_init_enet_param = uec->p_init_enet_param; @@ -932,21 +929,21 @@ static int uec_issue_init_enet_rxtx_cmd(uec_private_t *uec, /* Init Rx threads */ for (i = 0; i < (thread_rx + 1); i++) { - if ((snum = qe_get_snum()) < 0) { - printf("%s can not get snum\n", __FUNCTION__); + snum = qe_get_snum(); + if (snum < 0) { + printf("%s can not get snum\n", __func__); return -ENOMEM; } - if (i==0) { - init_enet_offset = 0; + if (i == 0) { + off = 0; } else { - init_enet_offset = qe_muram_alloc( - sizeof(uec_thread_rx_pram_t), - UEC_THREAD_RX_PRAM_ALIGNMENT); + off = qe_muram_alloc(sizeof(struct uec_thread_rx_pram), + UEC_THREAD_RX_PRAM_ALIGNMENT); } entry_val = ((u32)snum << ENET_INIT_PARAM_SNUM_SHIFT) | - init_enet_offset | (u32)uec_info->risc_rx; + off | (u32)uec_info->risc_rx; p_init_enet_param->rxthread[i] = entry_val; } @@ -956,16 +953,17 @@ static int uec_issue_init_enet_rxtx_cmd(uec_private_t *uec, /* Init Tx threads */ for (i = 0; i < thread_tx; i++) { - if ((snum = qe_get_snum()) < 0) { - printf("%s can not get snum\n", __FUNCTION__); + snum = qe_get_snum(); + if (snum < 0) { + printf("%s can not get snum\n", __func__); return -ENOMEM; } - init_enet_offset = qe_muram_alloc(sizeof(uec_thread_tx_pram_t), - UEC_THREAD_TX_PRAM_ALIGNMENT); + off = qe_muram_alloc(sizeof(struct uec_thread_tx_pram), + UEC_THREAD_TX_PRAM_ALIGNMENT); entry_val = ((u32)snum << ENET_INIT_PARAM_SNUM_SHIFT) | - init_enet_offset | (u32)uec_info->risc_tx; + off | (u32)uec_info->risc_tx; p_init_enet_param->txthread[i] = entry_val; } @@ -973,19 +971,18 @@ static int uec_issue_init_enet_rxtx_cmd(uec_private_t *uec, /* Issue QE command */ command = QE_INIT_TX_RX; - cecr_subblock = ucc_fast_get_qe_cr_subblock( - uec->uec_info->uf_info.ucc_num); - qe_issue_cmd(command, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET, - init_enet_param_offset); + cecr_subblock = ucc_fast_get_qe_cr_subblock(uf_info->ucc_num); + qe_issue_cmd(command, cecr_subblock, (u8)QE_CR_PROTOCOL_ETHERNET, + init_enet_param_offset); return 0; } -static int uec_startup(uec_private_t *uec) +static int uec_startup(struct uec_priv *uec) { - uec_info_t *uec_info; - ucc_fast_info_t *uf_info; - ucc_fast_private_t *uccf; + struct uec_inf *uec_info; + struct ucc_fast_inf *uf_info; + struct ucc_fast_priv *uccf; ucc_fast_t *uf_regs; uec_t *uec_regs; int num_threads_tx; @@ -993,37 +990,37 @@ static int uec_startup(uec_private_t *uec) u32 utbipar; u32 length; u32 align; - qe_bd_t *bd; + struct buffer_descriptor *bd; u8 *buf; int i; if (!uec || !uec->uec_info) { - printf("%s: uec or uec_info not initial\n", __FUNCTION__); + printf("%s: uec or uec_info not initial\n", __func__); return -EINVAL; } uec_info = uec->uec_info; - uf_info = &(uec_info->uf_info); + uf_info = &uec_info->uf_info; /* Check if Rx BD ring len is illegal */ - if ((uec_info->rx_bd_ring_len < UEC_RX_BD_RING_SIZE_MIN) || \ - (uec_info->rx_bd_ring_len % UEC_RX_BD_RING_SIZE_ALIGNMENT)) { + if (uec_info->rx_bd_ring_len < UEC_RX_BD_RING_SIZE_MIN || + (uec_info->rx_bd_ring_len % UEC_RX_BD_RING_SIZE_ALIGNMENT)) { printf("%s: Rx BD ring len must be multiple of 4, and > 8.\n", - __FUNCTION__); + __func__); return -EINVAL; } /* Check if Tx BD ring len is illegal */ if (uec_info->tx_bd_ring_len < UEC_TX_BD_RING_SIZE_MIN) { printf("%s: Tx BD ring length must not be smaller than 2.\n", - __FUNCTION__); + __func__); return -EINVAL; } /* Check if MRBLR is illegal */ - if ((MAX_RXBUF_LEN == 0) || (MAX_RXBUF_LEN % UEC_MRBLR_ALIGNMENT)) { + if (MAX_RXBUF_LEN == 0 || MAX_RXBUF_LEN % UEC_MRBLR_ALIGNMENT) { printf("%s: max rx buffer length must be mutliple of 128.\n", - __FUNCTION__); + __func__); return -EINVAL; } @@ -1033,7 +1030,7 @@ static int uec_startup(uec_private_t *uec) /* Init UCC fast */ if (ucc_fast_init(uf_info, &uccf)) { - printf("%s: failed to init ucc fast\n", __FUNCTION__); + printf("%s: failed to init ucc fast\n", __func__); return -ENOMEM; } @@ -1042,13 +1039,13 @@ static int uec_startup(uec_private_t *uec) /* Convert the Tx threads number */ if (uec_convert_threads_num(uec_info->num_threads_tx, - &num_threads_tx)) { + &num_threads_tx)) { return -EINVAL; } /* Convert the Rx threads number */ if (uec_convert_threads_num(uec_info->num_threads_rx, - &num_threads_rx)) { + &num_threads_rx)) { return -EINVAL; } @@ -1070,13 +1067,14 @@ static int uec_startup(uec_private_t *uec) out_be32(&uec_regs->maccfg2, MACCFG2_INIT_VALUE); /* Setup MAC interface mode */ - uec_set_mac_if_mode(uec, uec_info->enet_interface_type, uec_info->speed); + uec_set_mac_if_mode(uec, uec_info->enet_interface_type, + uec_info->speed); /* Setup MII management base */ #ifndef CONFIG_eTSEC_MDIO_BUS uec->uec_mii_regs = (uec_mii_t *)(&uec_regs->miimcfg); #else - uec->uec_mii_regs = (uec_mii_t *) CONFIG_MIIM_ADDRESS; + uec->uec_mii_regs = (uec_mii_t *)CONFIG_MIIM_ADDRESS; #endif /* Setup MII master clock source */ @@ -1093,16 +1091,16 @@ static int uec_startup(uec_private_t *uec) out_be32(&uec_regs->utbipar, utbipar); /* Configure the TBI for SGMII operation */ - if ((uec->uec_info->enet_interface_type == PHY_INTERFACE_MODE_SGMII) && - (uec->uec_info->speed == SPEED_1000)) { + if (uec->uec_info->enet_interface_type == PHY_INTERFACE_MODE_SGMII && + uec->uec_info->speed == SPEED_1000) { uec_write_phy_reg(uec->dev, uec_regs->utbipar, - ENET_TBI_MII_ANA, TBIANA_SETTINGS); + ENET_TBI_MII_ANA, TBIANA_SETTINGS); uec_write_phy_reg(uec->dev, uec_regs->utbipar, - ENET_TBI_MII_TBICON, TBICON_CLK_SELECT); + ENET_TBI_MII_TBICON, TBICON_CLK_SELECT); uec_write_phy_reg(uec->dev, uec_regs->utbipar, - ENET_TBI_MII_CR, TBICR_SETTINGS); + ENET_TBI_MII_CR, TBICR_SETTINGS); } /* Allocate Tx BDs */ @@ -1149,29 +1147,29 @@ static int uec_startup(uec_private_t *uec) memset((void *)(uec->rx_buf_offset), 0, length + align); /* Init TxBD ring */ - bd = (qe_bd_t *)uec->p_tx_bd_ring; - uec->txBd = bd; + bd = (struct buffer_descriptor *)uec->p_tx_bd_ring; + uec->tx_bd = bd; for (i = 0; i < uec_info->tx_bd_ring_len; i++) { BD_DATA_CLEAR(bd); BD_STATUS_SET(bd, 0); BD_LENGTH_SET(bd, 0); - bd ++; + bd++; } - BD_STATUS_SET((--bd), TxBD_WRAP); + BD_STATUS_SET((--bd), TX_BD_WRAP); /* Init RxBD ring */ - bd = (qe_bd_t *)uec->p_rx_bd_ring; - uec->rxBd = bd; + bd = (struct buffer_descriptor *)uec->p_rx_bd_ring; + uec->rx_bd = bd; buf = uec->p_rx_buf; for (i = 0; i < uec_info->rx_bd_ring_len; i++) { BD_DATA_SET(bd, buf); BD_LENGTH_SET(bd, 0); - BD_STATUS_SET(bd, RxBD_EMPTY); + BD_STATUS_SET(bd, RX_BD_EMPTY); buf += MAX_RXBUF_LEN; - bd ++; + bd++; } - BD_STATUS_SET((--bd), RxBD_WRAP | RxBD_EMPTY); + BD_STATUS_SET((--bd), RX_BD_WRAP | RX_BD_EMPTY); /* Init global Tx parameter RAM */ uec_init_tx_parameter(uec, num_threads_tx); @@ -1182,29 +1180,32 @@ static int uec_startup(uec_private_t *uec) /* Init ethernet Tx and Rx parameter command */ if (uec_issue_init_enet_rxtx_cmd(uec, num_threads_tx, num_threads_rx)) { - printf("%s issue init enet cmd failed\n", __FUNCTION__); + printf("%s issue init enet cmd failed\n", __func__); return -ENOMEM; } return 0; } -static int uec_init(struct eth_device* dev, struct bd_info *bd) +static int uec_init(struct eth_device *dev, struct bd_info *bd) { - uec_private_t *uec; + struct uec_priv *uec; int err, i; struct phy_info *curphy; #if defined(CONFIG_ARCH_P1021) || defined(CONFIG_ARCH_P1025) ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); #endif - uec = (uec_private_t *)dev->priv; + uec = (struct uec_priv *)dev->priv; - if (uec->the_first_run == 0) { + if (!uec->the_first_run) { #if defined(CONFIG_ARCH_P1021) || defined(CONFIG_ARCH_P1025) - /* QE9 and QE12 need to be set for enabling QE MII managment signals */ - setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE9); - setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE12); + /* + * QE9 and QE12 need to be set for enabling QE MII + * management signals + */ + setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE9); + setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE12); #endif err = init_phy(dev); @@ -1230,7 +1231,7 @@ static int uec_init(struct eth_device* dev, struct bd_info *bd) err = curphy->read_status(uec->mii_info); if (!(((i-- > 0) && !uec->mii_info->link) || err)) break; - udelay(100000); + mdelay(100); } while (1); #if defined(CONFIG_ARCH_P1021) || defined(CONFIG_ARCH_P1025) @@ -1248,12 +1249,11 @@ static int uec_init(struct eth_device* dev, struct bd_info *bd) /* Set up the MAC address */ if (dev->enetaddr[0] & 0x01) { printf("%s: MacAddress is multcast address\n", - __FUNCTION__); + __func__); return -1; } uec_set_mac_address(uec, dev->enetaddr); - err = uec_open(uec, COMM_DIR_RX_AND_TX); if (err) { printf("%s: cannot enable UEC device\n", dev->name); @@ -1262,30 +1262,31 @@ static int uec_init(struct eth_device* dev, struct bd_info *bd) phy_change(dev); - return (uec->mii_info->link ? 0 : -1); + return uec->mii_info->link ? 0 : -1; } -static void uec_halt(struct eth_device* dev) +static void uec_halt(struct eth_device *dev) { - uec_private_t *uec = (uec_private_t *)dev->priv; + struct uec_priv *uec = (struct uec_priv *)dev->priv; + uec_stop(uec, COMM_DIR_RX_AND_TX); } static int uec_send(struct eth_device *dev, void *buf, int len) { - uec_private_t *uec; - ucc_fast_private_t *uccf; - volatile qe_bd_t *bd; + struct uec_priv *uec; + struct ucc_fast_priv *uccf; + struct buffer_descriptor *bd; u16 status; int i; int result = 0; - uec = (uec_private_t *)dev->priv; + uec = (struct uec_priv *)dev->priv; uccf = uec->uccf; - bd = uec->txBd; + bd = uec->tx_bd; /* Find an empty TxBD */ - for (i = 0; bd->status & TxBD_READY; i++) { + for (i = 0; BD_STATUS(bd) & TX_BD_READY; i++) { if (i > 0x100000) { printf("%s: tx buffer not ready\n", dev->name); return result; @@ -1295,16 +1296,16 @@ static int uec_send(struct eth_device *dev, void *buf, int len) /* Init TxBD */ BD_DATA_SET(bd, buf); BD_LENGTH_SET(bd, len); - status = bd->status; + status = BD_STATUS(bd); status &= BD_WRAP; - status |= (TxBD_READY | TxBD_LAST); + status |= (TX_BD_READY | TX_BD_LAST); BD_STATUS_SET(bd, status); /* Tell UCC to transmit the buffer */ ucc_fast_transmit_on_demand(uccf); /* Wait for buffer to be transmitted */ - for (i = 0; bd->status & TxBD_READY; i++) { + for (i = 0; BD_STATUS(bd) & TX_BD_READY; i++) { if (i > 0x100000) { printf("%s: tx error\n", dev->name); return result; @@ -1313,25 +1314,25 @@ static int uec_send(struct eth_device *dev, void *buf, int len) /* Ok, the buffer be transimitted */ BD_ADVANCE(bd, status, uec->p_tx_bd_ring); - uec->txBd = bd; + uec->tx_bd = bd; result = 1; return result; } -static int uec_recv(struct eth_device* dev) +static int uec_recv(struct eth_device *dev) { - uec_private_t *uec = dev->priv; - volatile qe_bd_t *bd; + struct uec_priv *uec = dev->priv; + struct buffer_descriptor *bd; u16 status; u16 len; u8 *data; - bd = uec->rxBd; - status = bd->status; + bd = uec->rx_bd; + status = BD_STATUS(bd); - while (!(status & RxBD_EMPTY)) { - if (!(status & RxBD_ERROR)) { + while (!(status & RX_BD_EMPTY)) { + if (!(status & RX_BD_ERROR)) { data = BD_DATA(bd); len = BD_LENGTH(bd); net_process_received_packet(data, len); @@ -1340,20 +1341,20 @@ static int uec_recv(struct eth_device* dev) } status &= BD_CLEAN; BD_LENGTH_SET(bd, 0); - BD_STATUS_SET(bd, status | RxBD_EMPTY); + BD_STATUS_SET(bd, status | RX_BD_EMPTY); BD_ADVANCE(bd, status, uec->p_rx_bd_ring); - status = bd->status; + status = BD_STATUS(bd); } - uec->rxBd = bd; + uec->rx_bd = bd; return 1; } -int uec_initialize(struct bd_info *bis, uec_info_t *uec_info) +int uec_initialize(struct bd_info *bis, struct uec_inf *uec_info) { struct eth_device *dev; int i; - uec_private_t *uec; + struct uec_priv *uec; int err; dev = (struct eth_device *)malloc(sizeof(struct eth_device)); @@ -1362,11 +1363,11 @@ int uec_initialize(struct bd_info *bis, uec_info_t *uec_info) memset(dev, 0, sizeof(struct eth_device)); /* Allocate the UEC private struct */ - uec = (uec_private_t *)malloc(sizeof(uec_private_t)); - if (!uec) { + uec = (struct uec_priv *)malloc(sizeof(struct uec_priv)); + if (!uec) return -ENOMEM; - } - memset(uec, 0, sizeof(uec_private_t)); + + memset(uec, 0, sizeof(struct uec_priv)); /* Adjust uec_info */ #if (MAX_QE_RISC == 4) @@ -1395,13 +1396,14 @@ int uec_initialize(struct bd_info *bis, uec_info_t *uec_info) err = uec_startup(uec); if (err) { - printf("%s: Cannot configure net device, aborting.",dev->name); + printf("%s: Cannot configure net device, aborting.", dev->name); return err; } #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) int retval; struct mii_dev *mdiodev = mdio_alloc(); + if (!mdiodev) return -ENOMEM; strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN); @@ -1416,7 +1418,7 @@ int uec_initialize(struct bd_info *bis, uec_info_t *uec_info) return 1; } -int uec_eth_init(struct bd_info *bis, uec_info_t *uecs, int num) +int uec_eth_init(struct bd_info *bis, struct uec_inf *uecs, int num) { int i; diff --git a/drivers/qe/uec.h b/drivers/qe/uec.h index 6de2ac44f8..83461c024c 100644 --- a/drivers/qe/uec.h +++ b/drivers/qe/uec.h @@ -76,8 +76,7 @@ #define MACCFG2_INIT_VALUE (MACCFG2_PREL | MACCFG2_RESERVED_1 | \ MACCFG2_LC | MACCFG2_PAD_CRC | MACCFG2_FDX) -/* UEC Event Register -*/ +/* UEC Event Register */ #define UCCE_MPD 0x80000000 #define UCCE_SCAR 0x40000000 #define UCCE_GRA 0x20000000 @@ -120,26 +119,24 @@ #define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY | \ UCCE_RXC | UCCE_TXC | UCCE_TXE) -/* UEC TEMODR Register -*/ +/* UEC TEMODR Register */ #define TEMODER_SCHEDULER_ENABLE 0x2000 #define TEMODER_IP_CHECKSUM_GENERATE 0x0400 #define TEMODER_PERFORMANCE_OPTIMIZATION_MODE1 0x0200 #define TEMODER_RMON_STATISTICS 0x0100 -#define TEMODER_NUM_OF_QUEUES_SHIFT (15-15) +#define TEMODER_NUM_OF_QUEUES_SHIFT (15 - 15) #define TEMODER_INIT_VALUE 0xc000 -/* UEC REMODR Register -*/ +/* UEC REMODR Register */ #define REMODER_RX_RMON_STATISTICS_ENABLE 0x00001000 #define REMODER_RX_EXTENDED_FEATURES 0x80000000 -#define REMODER_VLAN_OPERATION_TAGGED_SHIFT (31-9 ) -#define REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT (31-10) -#define REMODER_RX_QOS_MODE_SHIFT (31-15) +#define REMODER_VLAN_OPERATION_TAGGED_SHIFT (31 - 9) +#define REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT (31 - 10) +#define REMODER_RX_QOS_MODE_SHIFT (31 - 15) #define REMODER_RMON_STATISTICS 0x00001000 #define REMODER_RX_EXTENDED_FILTERING 0x00000800 -#define REMODER_NUM_OF_QUEUES_SHIFT (31-23) +#define REMODER_NUM_OF_QUEUES_SHIFT (31 - 23) #define REMODER_DYNAMIC_MAX_FRAME_LENGTH 0x00000008 #define REMODER_DYNAMIC_MIN_FRAME_LENGTH 0x00000004 #define REMODER_IP_CHECKSUM_CHECK 0x00000002 @@ -213,35 +210,31 @@ #define UESCR_SCOV_SHIFT (15 - 15) /****** Tx data struct collection ******/ -/* Tx thread data, each Tx thread has one this struct. -*/ -typedef struct uec_thread_data_tx { +/* Tx thread data, each Tx thread has one this struct. */ +struct uec_thread_data_tx { u8 res0[136]; -} __attribute__ ((packed)) uec_thread_data_tx_t; +} __packed; -/* Tx thread parameter, each Tx thread has one this struct. -*/ -typedef struct uec_thread_tx_pram { +/* Tx thread parameter, each Tx thread has one this struct. */ +struct uec_thread_tx_pram { u8 res0[64]; -} __attribute__ ((packed)) uec_thread_tx_pram_t; +} __packed; -/* Send queue queue-descriptor, each Tx queue has one this QD -*/ -typedef struct uec_send_queue_qd { +/* Send queue queue-descriptor, each Tx queue has one this QD */ +struct uec_send_queue_qd { u32 bd_ring_base; /* pointer to BD ring base address */ u8 res0[0x8]; u32 last_bd_completed_address; /* last entry in BD ring */ u8 res1[0x30]; -} __attribute__ ((packed)) uec_send_queue_qd_t; +} __packed; /* Send queue memory region */ -typedef struct uec_send_queue_mem_region { - uec_send_queue_qd_t sqqd[MAX_TX_QUEUES]; -} __attribute__ ((packed)) uec_send_queue_mem_region_t; +struct uec_send_queue_mem_region { + struct uec_send_queue_qd sqqd[MAX_TX_QUEUES]; +} __packed; -/* Scheduler struct -*/ -typedef struct uec_scheduler { +/* Scheduler struct */ +struct uec_scheduler { u16 cpucount0; /* CPU packet counter */ u16 cpucount1; /* CPU packet counter */ u16 cecount0; /* QE packet counter */ @@ -272,12 +265,11 @@ typedef struct uec_scheduler { u8 oldwfqmask; /* temporary variable handled by QE */ u8 weightfactor[MAX_TX_QUEUES]; /**< weight factor for queues */ u32 minw; /* temporary variable handled by QE */ - u8 res1[0x70-0x64]; -} __attribute__ ((packed)) uec_scheduler_t; + u8 res1[0x70 - 0x64]; +} __packed; -/* Tx firmware counters -*/ -typedef struct uec_tx_firmware_statistics_pram { +/* Tx firmware counters */ +struct uec_tx_firmware_statistics_pram { u32 sicoltx; /* single collision */ u32 mulcoltx; /* multiple collision */ u32 latecoltxfr; /* late collision */ @@ -290,13 +282,12 @@ typedef struct uec_tx_firmware_statistics_pram { u32 txpkts512; /* total packets(including bad) 512~1023B */ u32 txpkts1024; /* total packets(including bad) 1024~1518B */ u32 txpktsjumbo; /* total packets(including bad) >1024 */ -} __attribute__ ((packed)) uec_tx_firmware_statistics_pram_t; +} __packed; -/* Tx global parameter table -*/ -typedef struct uec_tx_global_pram { +/* Tx global parameter table */ +struct uec_tx_global_pram { u16 temoder; - u8 res0[0x38-0x02]; + u8 res0[0x38 - 0x02]; u32 sqptr; u32 schedulerbasepointer; u32 txrmonbaseptr; @@ -304,26 +295,22 @@ typedef struct uec_tx_global_pram { u8 iphoffset[MAX_IPH_OFFSET_ENTRY]; u32 vtagtable[0x8]; u32 tqptr; - u8 res2[0x80-0x74]; -} __attribute__ ((packed)) uec_tx_global_pram_t; - + u8 res2[0x80 - 0x74]; +} __packed; /****** Rx data struct collection ******/ -/* Rx thread data, each Rx thread has one this struct. -*/ -typedef struct uec_thread_data_rx { +/* Rx thread data, each Rx thread has one this struct. */ +struct uec_thread_data_rx { u8 res0[40]; -} __attribute__ ((packed)) uec_thread_data_rx_t; +} __packed; -/* Rx thread parameter, each Rx thread has one this struct. -*/ -typedef struct uec_thread_rx_pram { +/* Rx thread parameter, each Rx thread has one this struct. */ +struct uec_thread_rx_pram { u8 res0[128]; -} __attribute__ ((packed)) uec_thread_rx_pram_t; +} __packed; -/* Rx firmware counters -*/ -typedef struct uec_rx_firmware_statistics_pram { +/* Rx firmware counters */ +struct uec_rx_firmware_statistics_pram { u32 frrxfcser; /* frames with crc error */ u32 fraligner; /* frames with alignment error */ u32 inrangelenrxer; /* in range length error */ @@ -346,44 +333,41 @@ typedef struct uec_rx_firmware_statistics_pram { u32 removevlan; u32 replacevlan; u32 insertvlan; -} __attribute__ ((packed)) uec_rx_firmware_statistics_pram_t; +} __packed; -/* Rx interrupt coalescing entry, each Rx queue has one this entry. -*/ -typedef struct uec_rx_interrupt_coalescing_entry { +/* Rx interrupt coalescing entry, each Rx queue has one this entry. */ +struct uec_rx_interrupt_coalescing_entry { u32 maxvalue; u32 counter; -} __attribute__ ((packed)) uec_rx_interrupt_coalescing_entry_t; +} __packed; -typedef struct uec_rx_interrupt_coalescing_table { - uec_rx_interrupt_coalescing_entry_t entry[MAX_RX_QUEUES]; -} __attribute__ ((packed)) uec_rx_interrupt_coalescing_table_t; +struct uec_rx_interrupt_coalescing_table { + struct uec_rx_interrupt_coalescing_entry entry[MAX_RX_QUEUES]; +} __packed; -/* RxBD queue entry, each Rx queue has one this entry. -*/ -typedef struct uec_rx_bd_queues_entry { +/* RxBD queue entry, each Rx queue has one this entry. */ +struct uec_rx_bd_queues_entry { u32 bdbaseptr; /* BD base pointer */ u32 bdptr; /* BD pointer */ u32 externalbdbaseptr; /* external BD base pointer */ u32 externalbdptr; /* external BD pointer */ -} __attribute__ ((packed)) uec_rx_bd_queues_entry_t; +} __packed; -/* Rx global paramter table -*/ -typedef struct uec_rx_global_pram { +/* Rx global parameter table */ +struct uec_rx_global_pram { u32 remoder; /* ethernet mode reg. */ u32 rqptr; /* base pointer to the Rx Queues */ u32 res0[0x1]; - u8 res1[0x20-0xC]; + u8 res1[0x20 - 0xc]; u16 typeorlen; u8 res2[0x1]; u8 rxgstpack; /* ack on GRACEFUL STOP RX command */ u32 rxrmonbaseptr; /* Rx RMON statistics base */ - u8 res3[0x30-0x28]; + u8 res3[0x30 - 0x28]; u32 intcoalescingptr; /* Interrupt coalescing table pointer */ - u8 res4[0x36-0x34]; + u8 res4[0x36 - 0x34]; u8 rstate; - u8 res5[0x46-0x37]; + u8 res5[0x46 - 0x37]; u16 mrblr; /* max receive buffer length reg. */ u32 rbdqptr; /* RxBD parameter table description */ u16 mflr; /* max frame length reg. */ @@ -396,17 +380,15 @@ typedef struct uec_rx_global_pram { u16 vlantype; /* vlan type */ u16 vlantci; /* default vlan tci */ u8 addressfiltering[64];/* address filtering data structure */ - u32 exfGlobalParam; /* extended filtering global parameters */ - u8 res6[0x100-0xC4]; /* Initialize to zero */ -} __attribute__ ((packed)) uec_rx_global_pram_t; + u32 exf_global_param; /* extended filtering global parameters */ + u8 res6[0x100 - 0xc4]; /* Initialize to zero */ +} __packed; #define GRACEFUL_STOP_ACKNOWLEDGE_RX 0x01 - /****** UEC common ******/ -/* UCC statistics - hardware counters -*/ -typedef struct uec_hardware_statistics { +/* UCC statistics - hardware counters */ +struct uec_hardware_statistics { u32 tx64; u32 tx127; u32 tx255; @@ -422,11 +404,10 @@ typedef struct uec_hardware_statistics { u32 rbyt; u32 rmca; u32 rbca; -} __attribute__ ((packed)) uec_hardware_statistics_t; +} __packed; -/* InitEnet command parameter -*/ -typedef struct uec_init_cmd_pram { +/* InitEnet command parameter */ +struct uec_init_cmd_pram { u8 resinit0; u8 resinit1; u8 resinit2; @@ -440,7 +421,7 @@ typedef struct uec_init_cmd_pram { u32 txglobal; /* tx global */ u32 txthread[MAX_ENET_INIT_PARAM_ENTRIES_TX]; /* tx threads */ u8 res3[0x1]; -} __attribute__ ((packed)) uec_init_cmd_pram_t; +} __packed; #define ENET_INIT_PARAM_RGF_SHIFT (32 - 4) #define ENET_INIT_PARAM_TGF_SHIFT (32 - 8) @@ -456,105 +437,96 @@ typedef struct uec_init_cmd_pram { #define ENET_INIT_PARAM_MAGIC_RES_INIT3 0x00 #define ENET_INIT_PARAM_MAGIC_RES_INIT4 0x0400 -/* structure representing 82xx Address Filtering Enet Address in PRAM -*/ -typedef struct uec_82xx_enet_address { +/* structure representing 82xx Address Filtering Enet Address in PRAM */ +struct uec_82xx_enet_addr { u8 res1[0x2]; u16 h; /* address (MSB) */ u16 m; /* address */ u16 l; /* address (LSB) */ -} __attribute__ ((packed)) uec_82xx_enet_address_t; +} __packed; -/* structure representing 82xx Address Filtering PRAM -*/ -typedef struct uec_82xx_address_filtering_pram { +/* structure representing 82xx Address Filtering PRAM */ +struct uec_82xx_add_filtering_pram { u32 iaddr_h; /* individual address filter, high */ u32 iaddr_l; /* individual address filter, low */ u32 gaddr_h; /* group address filter, high */ u32 gaddr_l; /* group address filter, low */ - uec_82xx_enet_address_t taddr; - uec_82xx_enet_address_t paddr[4]; - u8 res0[0x40-0x38]; -} __attribute__ ((packed)) uec_82xx_address_filtering_pram_t; - -/* Buffer Descriptor -*/ -typedef struct buffer_descriptor { + struct uec_82xx_enet_addr taddr; + struct uec_82xx_enet_addr paddr[4]; + u8 res0[0x40 - 0x38]; +} __packed; + +/* Buffer Descriptor */ +struct buffer_descriptor { u16 status; u16 len; u32 data; -} __attribute__ ((packed)) qe_bd_t, *p_bd_t; +} __packed; -#define SIZEOFBD sizeof(qe_bd_t) +#define SIZEOFBD sizeof(struct buffer_descriptor) -/* Common BD flags -*/ +/* Common BD flags */ #define BD_WRAP 0x2000 #define BD_INT 0x1000 #define BD_LAST 0x0800 #define BD_CLEAN 0x3000 -/* TxBD status flags -*/ -#define TxBD_READY 0x8000 -#define TxBD_PADCRC 0x4000 -#define TxBD_WRAP BD_WRAP -#define TxBD_INT BD_INT -#define TxBD_LAST BD_LAST -#define TxBD_TXCRC 0x0400 -#define TxBD_DEF 0x0200 -#define TxBD_PP 0x0100 -#define TxBD_LC 0x0080 -#define TxBD_RL 0x0040 -#define TxBD_RC 0x003C -#define TxBD_UNDERRUN 0x0002 -#define TxBD_TRUNC 0x0001 - -#define TxBD_ERROR (TxBD_UNDERRUN | TxBD_TRUNC) - -/* RxBD status flags -*/ -#define RxBD_EMPTY 0x8000 -#define RxBD_OWNER 0x4000 -#define RxBD_WRAP BD_WRAP -#define RxBD_INT BD_INT -#define RxBD_LAST BD_LAST -#define RxBD_FIRST 0x0400 -#define RxBD_CMR 0x0200 -#define RxBD_MISS 0x0100 -#define RxBD_BCAST 0x0080 -#define RxBD_MCAST 0x0040 -#define RxBD_LG 0x0020 -#define RxBD_NO 0x0010 -#define RxBD_SHORT 0x0008 -#define RxBD_CRCERR 0x0004 -#define RxBD_OVERRUN 0x0002 -#define RxBD_IPCH 0x0001 - -#define RxBD_ERROR (RxBD_LG | RxBD_NO | RxBD_SHORT | \ - RxBD_CRCERR | RxBD_OVERRUN) - -/* BD access macros -*/ -#define BD_STATUS(_bd) (((p_bd_t)(_bd))->status) -#define BD_STATUS_SET(_bd, _val) (((p_bd_t)(_bd))->status = _val) -#define BD_LENGTH(_bd) (((p_bd_t)(_bd))->len) -#define BD_LENGTH_SET(_bd, _val) (((p_bd_t)(_bd))->len = _val) -#define BD_DATA_CLEAR(_bd) (((p_bd_t)(_bd))->data = 0) -#define BD_IS_DATA(_bd) (((p_bd_t)(_bd))->data) -#define BD_DATA(_bd) ((u8 *)(((p_bd_t)(_bd))->data)) -#define BD_DATA_SET(_bd, _data) (((p_bd_t)(_bd))->data = (u32)(_data)) -#define BD_ADVANCE(_bd,_status,_base) \ - (((_status) & BD_WRAP) ? (_bd) = ((p_bd_t)(_base)) : ++(_bd)) - -/* Rx Prefetched BDs -*/ -typedef struct uec_rx_prefetched_bds { - qe_bd_t bd[MAX_PREFETCHED_BDS]; /* prefetched bd */ -} __attribute__ ((packed)) uec_rx_prefetched_bds_t; - -/* Alignments - */ +/* TxBD status flags */ +#define TX_BD_READY 0x8000 +#define TX_BD_PADCRC 0x4000 +#define TX_BD_WRAP BD_WRAP +#define TX_BD_INT BD_INT +#define TX_BD_LAST BD_LAST +#define TX_BD_TXCRC 0x0400 +#define TX_BD_DEF 0x0200 +#define TX_BD_PP 0x0100 +#define TX_BD_LC 0x0080 +#define TX_BD_RL 0x0040 +#define TX_BD_RC 0x003C +#define TX_BD_UNDERRUN 0x0002 +#define TX_BD_TRUNC 0x0001 + +#define TX_BD_ERROR (TX_BD_UNDERRUN | TX_BD_TRUNC) + +/* RxBD status flags */ +#define RX_BD_EMPTY 0x8000 +#define RX_BD_OWNER 0x4000 +#define RX_BD_WRAP BD_WRAP +#define RX_BD_INT BD_INT +#define RX_BD_LAST BD_LAST +#define RX_BD_FIRST 0x0400 +#define RX_BD_CMR 0x0200 +#define RX_BD_MISS 0x0100 +#define RX_BD_BCAST 0x0080 +#define RX_BD_MCAST 0x0040 +#define RX_BD_LG 0x0020 +#define RX_BD_NO 0x0010 +#define RX_BD_SHORT 0x0008 +#define RX_BD_CRCERR 0x0004 +#define RX_BD_OVERRUN 0x0002 +#define RX_BD_IPCH 0x0001 + +#define RX_BD_ERROR (RX_BD_LG | RX_BD_NO | RX_BD_SHORT | \ + RX_BD_CRCERR | RX_BD_OVERRUN) + +/* BD access macros */ +#define BD_STATUS(_bd) (in_be16(&((_bd)->status))) +#define BD_STATUS_SET(_bd, _v) (out_be16(&((_bd)->status), _v)) +#define BD_LENGTH(_bd) (in_be16(&((_bd)->len))) +#define BD_LENGTH_SET(_bd, _v) (out_be16(&((_bd)->len), _v)) +#define BD_DATA_CLEAR(_bd) (out_be32(&((_bd)->data), 0)) +#define BD_DATA(_bd) ((u8 *)(((_bd)->data))) +#define BD_DATA_SET(_bd, _data) (out_be32(&((_bd)->data), (u32)_data)) +#define BD_ADVANCE(_bd, _status, _base) \ + (((_status) & BD_WRAP) ? (_bd) = \ + ((struct buffer_descriptor *)(_base)) : ++(_bd)) + +/* Rx Prefetched BDs */ +struct uec_rx_pref_bds { + struct buffer_descriptor bd[MAX_PREFETCHED_BDS]; /* prefetched bd */ +} __packed; + +/* Alignments */ #define UEC_RX_GLOBAL_PRAM_ALIGNMENT 64 #define UEC_TX_GLOBAL_PRAM_ALIGNMENT 64 #define UEC_THREAD_RX_PRAM_ALIGNMENT 128 @@ -581,25 +553,8 @@ typedef struct uec_rx_prefetched_bds { #define UEC_RX_BD_RING_SIZE_MIN 8 #define UEC_TX_BD_RING_SIZE_MIN 2 -/* Ethernet speed -*/ -typedef enum enet_speed { - ENET_SPEED_10BT, /* 10 Base T */ - ENET_SPEED_100BT, /* 100 Base T */ - ENET_SPEED_1000BT /* 1000 Base T */ -} enet_speed_e; - -/* Ethernet Address Type. -*/ -typedef enum enet_addr_type { - ENET_ADDR_TYPE_INDIVIDUAL, - ENET_ADDR_TYPE_GROUP, - ENET_ADDR_TYPE_BROADCAST -} enet_addr_type_e; - -/* TBI / MII Set Register -*/ -typedef enum enet_tbi_mii_reg { +/* TBI / MII Set Register */ +enum enet_tbi_mii_reg { ENET_TBI_MII_CR = 0x00, ENET_TBI_MII_SR = 0x01, ENET_TBI_MII_ANA = 0x04, @@ -610,7 +565,7 @@ typedef enum enet_tbi_mii_reg { ENET_TBI_MII_EXST = 0x0F, ENET_TBI_MII_JD = 0x10, ENET_TBI_MII_TBICON = 0x11 -} enet_tbi_mii_reg_e; +}; /* TBI MDIO register bit fields*/ #define TBICON_CLK_SELECT 0x0020 @@ -637,18 +592,16 @@ typedef enum enet_tbi_mii_reg { | TBICR_SPEED1_SET \ ) -/* UEC number of threads -*/ -typedef enum uec_num_of_threads { +/* UEC number of threads */ +enum uec_num_of_threads { UEC_NUM_OF_THREADS_1 = 0x1, /* 1 */ UEC_NUM_OF_THREADS_2 = 0x2, /* 2 */ UEC_NUM_OF_THREADS_4 = 0x0, /* 4 */ UEC_NUM_OF_THREADS_6 = 0x3, /* 6 */ UEC_NUM_OF_THREADS_8 = 0x4 /* 8 */ -} uec_num_of_threads_e; +}; -/* UEC initialization info struct -*/ +/* UEC initialization info struct */ #define STD_UEC_INFO(num) \ { \ .uf_info = { \ @@ -668,10 +621,10 @@ typedef enum uec_num_of_threads { .speed = CONFIG_SYS_UEC##num##_INTERFACE_SPEED, \ } -typedef struct uec_info { - ucc_fast_info_t uf_info; - uec_num_of_threads_e num_threads_tx; - uec_num_of_threads_e num_threads_rx; +struct uec_inf { + struct ucc_fast_inf uf_info; + enum uec_num_of_threads num_threads_tx; + enum uec_num_of_threads num_threads_rx; unsigned int risc_tx; unsigned int risc_rx; u16 rx_bd_ring_len; @@ -679,39 +632,37 @@ typedef struct uec_info { u8 phy_address; phy_interface_t enet_interface_type; int speed; -} uec_info_t; +}; -/* UEC driver initialized info -*/ +/* UEC driver initialized info */ #define MAX_RXBUF_LEN 1536 #define MAX_FRAME_LEN 1518 #define MIN_FRAME_LEN 64 #define MAX_DMA1_LEN 1520 #define MAX_DMA2_LEN 1520 -/* UEC driver private struct -*/ -typedef struct uec_private { - uec_info_t *uec_info; - ucc_fast_private_t *uccf; +/* UEC driver private struct */ +struct uec_priv { + struct uec_inf *uec_info; + struct ucc_fast_priv *uccf; struct eth_device *dev; uec_t *uec_regs; uec_mii_t *uec_mii_regs; /* enet init command parameter */ - uec_init_cmd_pram_t *p_init_enet_param; + struct uec_init_cmd_pram *p_init_enet_param; u32 init_enet_param_offset; - /* Rx and Tx paramter */ - uec_rx_global_pram_t *p_rx_glbl_pram; + /* Rx and Tx parameter */ + struct uec_rx_global_pram *p_rx_glbl_pram; u32 rx_glbl_pram_offset; - uec_tx_global_pram_t *p_tx_glbl_pram; + struct uec_tx_global_pram *p_tx_glbl_pram; u32 tx_glbl_pram_offset; - uec_send_queue_mem_region_t *p_send_q_mem_reg; + struct uec_send_queue_mem_region *p_send_q_mem_reg; u32 send_q_mem_reg_offset; - uec_thread_data_tx_t *p_thread_data_tx; + struct uec_thread_data_tx *p_thread_data_tx; u32 thread_dat_tx_offset; - uec_thread_data_rx_t *p_thread_data_rx; + struct uec_thread_data_rx *p_thread_data_rx; u32 thread_dat_rx_offset; - uec_rx_bd_queues_entry_t *p_rx_bd_qs_tbl; + struct uec_rx_bd_queues_entry *p_rx_bd_qs_tbl; u32 rx_bd_qs_tbl_offset; /* BDs specific */ u8 *p_tx_bd_ring; @@ -720,8 +671,8 @@ typedef struct uec_private { u32 rx_bd_ring_offset; u8 *p_rx_buf; u32 rx_buf_offset; - volatile qe_bd_t *txBd; - volatile qe_bd_t *rxBd; + struct buffer_descriptor *tx_bd; + struct buffer_descriptor *rx_bd; /* Status */ int mac_tx_enabled; int mac_rx_enabled; @@ -733,9 +684,9 @@ typedef struct uec_private { int oldspeed; int oldduplex; int oldlink; -} uec_private_t; +}; -int uec_initialize(struct bd_info *bis, uec_info_t *uec_info); -int uec_eth_init(struct bd_info *bis, uec_info_t *uecs, int num); +int uec_initialize(struct bd_info *bis, struct uec_inf *uec_info); +int uec_eth_init(struct bd_info *bis, struct uec_inf *uecs, int num); int uec_standard_init(struct bd_info *bis); #endif /* __UEC_H__ */ diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c index 69c22dd5e2..b5ca5f76f9 100644 --- a/drivers/qe/uec_phy.c +++ b/drivers/qe/uec_phy.c @@ -27,13 +27,13 @@ printf(format "\n", ## arg) #define ugphy_dbg(format, arg...) \ - ugphy_printk(format , ## arg) + ugphy_printk(format, ## arg) #define ugphy_err(format, arg...) \ - ugphy_printk(format , ## arg) + ugphy_printk(format, ## arg) #define ugphy_info(format, arg...) \ - ugphy_printk(format , ## arg) + ugphy_printk(format, ## arg) #define ugphy_warn(format, arg...) \ - ugphy_printk(format , ## arg) + ugphy_printk(format, ## arg) #ifdef UEC_VERBOSE_DEBUG #define ugphy_vdbg ugphy_dbg @@ -41,13 +41,13 @@ #define ugphy_vdbg(ugeth, fmt, args...) do { } while (0) #endif /* UEC_VERBOSE_DEBUG */ -/*--------------------------------------------------------------------+ +/* + * -------------------------------------------------------------------- * Fixed PHY (PHY-less) support for Ethernet Ports. * * Copied from arch/powerpc/cpu/ppc4xx/4xx_enet.c - *--------------------------------------------------------------------*/ - -/* + *-------------------------------------------------------------------- + * * Some boards do not have a PHY for each ethernet port. These ports are known * as Fixed PHY (or PHY-less) ports. For such ports, set the appropriate * CONFIG_SYS_UECx_PHY_ADDR equal to CONFIG_FIXED_PHY_ADDR (an unused address) @@ -90,54 +90,58 @@ static const struct fixed_phy_port fixed_phy_port[] = { CONFIG_SYS_FIXED_PHY_PORTS /* defined in board configuration file */ }; -/*--------------------------------------------------------------------+ +/* + * ------------------------------------------------------------------- * BitBang MII support for ethernet ports * * Based from MPC8560ADS implementation - *--------------------------------------------------------------------*/ -/* + *-------------------------------------------------------------------- + * * Example board header file to define bitbang ethernet ports: * * #define CONFIG_SYS_BITBANG_PHY_PORT(name) name, * #define CONFIG_SYS_BITBANG_PHY_PORTS CONFIG_SYS_BITBANG_PHY_PORT("UEC0") -*/ + */ #ifndef CONFIG_SYS_BITBANG_PHY_PORTS #define CONFIG_SYS_BITBANG_PHY_PORTS /* default is an empty array */ #endif #if defined(CONFIG_BITBANGMII) -static const char *bitbang_phy_port[] = { +static const char * const bitbang_phy_port[] = { CONFIG_SYS_BITBANG_PHY_PORTS /* defined in board configuration file */ }; #endif /* CONFIG_BITBANGMII */ -static void config_genmii_advert (struct uec_mii_info *mii_info); -static void genmii_setup_forced (struct uec_mii_info *mii_info); -static void genmii_restart_aneg (struct uec_mii_info *mii_info); -static int gbit_config_aneg (struct uec_mii_info *mii_info); -static int genmii_config_aneg (struct uec_mii_info *mii_info); -static int genmii_update_link (struct uec_mii_info *mii_info); -static int genmii_read_status (struct uec_mii_info *mii_info); -u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum); -void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum, u16 val); - -/* Write value to the PHY for this device to the register at regnum, */ -/* waiting until the write is done before it returns. All PHY */ -/* configuration has to be done through the TSEC1 MIIM regs */ -void uec_write_phy_reg (struct eth_device *dev, int mii_id, int regnum, int value) -{ - uec_private_t *ugeth = (uec_private_t *) dev->priv; +static void config_genmii_advert(struct uec_mii_info *mii_info); +static void genmii_setup_forced(struct uec_mii_info *mii_info); +static void genmii_restart_aneg(struct uec_mii_info *mii_info); +static int gbit_config_aneg(struct uec_mii_info *mii_info); +static int genmii_config_aneg(struct uec_mii_info *mii_info); +static int genmii_update_link(struct uec_mii_info *mii_info); +static int genmii_read_status(struct uec_mii_info *mii_info); +static u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum); +static void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum, + u16 val); + +/* + * Write value to the PHY for this device to the register at regnum, + * waiting until the write is done before it returns. All PHY + * configuration has to be done through the TSEC1 MIIM regs + */ +void uec_write_phy_reg(struct eth_device *dev, int mii_id, int regnum, + int value) +{ + struct uec_priv *ugeth = (struct uec_priv *)dev->priv; uec_mii_t *ug_regs; - enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum; + enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg)regnum; u32 tmp_reg; - #if defined(CONFIG_BITBANGMII) u32 i = 0; for (i = 0; i < ARRAY_SIZE(bitbang_phy_port); i++) { if (strncmp(dev->name, bitbang_phy_port[i], - sizeof(dev->name)) == 0) { + sizeof(dev->name)) == 0) { (void)bb_miiphy_write(NULL, mii_id, regnum, value); return; } @@ -148,46 +152,48 @@ void uec_write_phy_reg (struct eth_device *dev, int mii_id, int regnum, int valu /* Stop the MII management read cycle */ out_be32 (&ug_regs->miimcom, 0); - /* Setting up the MII Mangement Address Register */ - tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; + /* Setting up the MII Management Address Register */ + tmp_reg = ((u32)mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; out_be32 (&ug_regs->miimadd, tmp_reg); - /* Setting up the MII Mangement Control Register with the value */ - out_be32 (&ug_regs->miimcon, (u32) value); + /* Setting up the MII Management Control Register with the value */ + out_be32 (&ug_regs->miimcon, (u32)value); sync(); /* Wait till MII management write is complete */ - while ((in_be32 (&ug_regs->miimind)) & MIIMIND_BUSY); + while ((in_be32 (&ug_regs->miimind)) & MIIMIND_BUSY) + ; } -/* Reads from register regnum in the PHY for device dev, */ -/* returning the value. Clears miimcom first. All PHY */ -/* configuration has to be done through the TSEC1 MIIM regs */ -int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum) +/* + * Reads from register regnum in the PHY for device dev, + * returning the value. Clears miimcom first. All PHY + * configuration has to be done through the TSEC1 MIIM regs + */ +int uec_read_phy_reg(struct eth_device *dev, int mii_id, int regnum) { - uec_private_t *ugeth = (uec_private_t *) dev->priv; + struct uec_priv *ugeth = (struct uec_priv *)dev->priv; uec_mii_t *ug_regs; - enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum; + enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg)regnum; u32 tmp_reg; u16 value; - #if defined(CONFIG_BITBANGMII) u32 i = 0; for (i = 0; i < ARRAY_SIZE(bitbang_phy_port); i++) { if (strncmp(dev->name, bitbang_phy_port[i], - sizeof(dev->name)) == 0) { + sizeof(dev->name)) == 0) { (void)bb_miiphy_read(NULL, mii_id, regnum, &value); - return (value); + return value; } } #endif /* CONFIG_BITBANGMII */ ug_regs = ugeth->uec_mii_regs; - /* Setting up the MII Mangement Address Register */ - tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; + /* Setting up the MII Management Address Register */ + tmp_reg = ((u32)mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; out_be32 (&ug_regs->miimadd, tmp_reg); /* clear MII management command cycle */ @@ -199,37 +205,38 @@ int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum) /* Wait till MII management write is complete */ while ((in_be32 (&ug_regs->miimind)) & - (MIIMIND_NOT_VALID | MIIMIND_BUSY)); + (MIIMIND_NOT_VALID | MIIMIND_BUSY)) + ; /* Read MII management status */ - value = (u16) in_be32 (&ug_regs->miimstat); + value = (u16)in_be32 (&ug_regs->miimstat); if (value == 0xffff) ugphy_vdbg ("read wrong value : mii_id %d,mii_reg %d, base %08x", - mii_id, mii_reg, (u32) & (ug_regs->miimcfg)); + mii_id, mii_reg, (u32)&ug_regs->miimcfg); - return (value); + return value; } -void mii_clear_phy_interrupt (struct uec_mii_info *mii_info) +void mii_clear_phy_interrupt(struct uec_mii_info *mii_info) { if (mii_info->phyinfo->ack_interrupt) - mii_info->phyinfo->ack_interrupt (mii_info); + mii_info->phyinfo->ack_interrupt(mii_info); } -void mii_configure_phy_interrupt (struct uec_mii_info *mii_info, - u32 interrupts) +void mii_configure_phy_interrupt(struct uec_mii_info *mii_info, + u32 interrupts) { mii_info->interrupts = interrupts; if (mii_info->phyinfo->config_intr) - mii_info->phyinfo->config_intr (mii_info); + mii_info->phyinfo->config_intr(mii_info); } /* Writes MII_ADVERTISE with the appropriate values, after * sanitizing advertise to make sure only supported features * are advertised */ -static void config_genmii_advert (struct uec_mii_info *mii_info) +static void config_genmii_advert(struct uec_mii_info *mii_info) { u32 advertise; u16 adv; @@ -252,7 +259,7 @@ static void config_genmii_advert (struct uec_mii_info *mii_info) uec_phy_write(mii_info, MII_ADVERTISE, adv); } -static void genmii_setup_forced (struct uec_mii_info *mii_info) +static void genmii_setup_forced(struct uec_mii_info *mii_info) { u16 ctrl; u32 features = mii_info->phyinfo->features; @@ -283,7 +290,7 @@ static void genmii_setup_forced (struct uec_mii_info *mii_info) | SUPPORTED_10baseT_Full)) break; default: /* Unsupported speed! */ - ugphy_err ("%s: Bad speed!", mii_info->dev->name); + ugphy_err("%s: Bad speed!", mii_info->dev->name); break; } @@ -291,7 +298,7 @@ static void genmii_setup_forced (struct uec_mii_info *mii_info) } /* Enable and Restart Autonegotiation */ -static void genmii_restart_aneg (struct uec_mii_info *mii_info) +static void genmii_restart_aneg(struct uec_mii_info *mii_info) { u16 ctl; @@ -300,14 +307,14 @@ static void genmii_restart_aneg (struct uec_mii_info *mii_info) uec_phy_write(mii_info, MII_BMCR, ctl); } -static int gbit_config_aneg (struct uec_mii_info *mii_info) +static int gbit_config_aneg(struct uec_mii_info *mii_info) { u16 adv; u32 advertise; if (mii_info->autoneg) { /* Configure the ADVERTISE register */ - config_genmii_advert (mii_info); + config_genmii_advert(mii_info); advertise = mii_info->advertising; adv = uec_phy_read(mii_info, MII_CTRL1000); @@ -320,18 +327,21 @@ static int gbit_config_aneg (struct uec_mii_info *mii_info) uec_phy_write(mii_info, MII_CTRL1000, adv); /* Start/Restart aneg */ - genmii_restart_aneg (mii_info); - } else - genmii_setup_forced (mii_info); + genmii_restart_aneg(mii_info); + } else { + genmii_setup_forced(mii_info); + } return 0; } -static int marvell_config_aneg (struct uec_mii_info *mii_info) +static int marvell_config_aneg(struct uec_mii_info *mii_info) { - /* The Marvell PHY has an errata which requires + /* + * The Marvell PHY has an errata which requires * that certain registers get written in order - * to restart autonegotiation */ + * to restart autonegotiation + */ uec_phy_write(mii_info, MII_BMCR, BMCR_RESET); uec_phy_write(mii_info, 0x1d, 0x1f); @@ -340,16 +350,18 @@ static int marvell_config_aneg (struct uec_mii_info *mii_info) uec_phy_write(mii_info, 0x1e, 0); uec_phy_write(mii_info, 0x1e, 0x100); - gbit_config_aneg (mii_info); + gbit_config_aneg(mii_info); return 0; } -static int genmii_config_aneg (struct uec_mii_info *mii_info) +static int genmii_config_aneg(struct uec_mii_info *mii_info) { if (mii_info->autoneg) { - /* Speed up the common case, if link is already up, speed and - duplex match, skip auto neg as it already matches */ + /* + * Speed up the common case, if link is already up, speed and + * duplex match, skip auto neg as it already matches + */ if (!genmii_read_status(mii_info) && mii_info->link) if (mii_info->duplex == DUPLEX_FULL && mii_info->speed == SPEED_100) @@ -357,15 +369,16 @@ static int genmii_config_aneg (struct uec_mii_info *mii_info) ADVERTISED_100baseT_Full) return 0; - config_genmii_advert (mii_info); - genmii_restart_aneg (mii_info); - } else - genmii_setup_forced (mii_info); + config_genmii_advert(mii_info); + genmii_restart_aneg(mii_info); + } else { + genmii_setup_forced(mii_info); + } return 0; } -static int genmii_update_link (struct uec_mii_info *mii_info) +static int genmii_update_link(struct uec_mii_info *mii_info) { u16 status; @@ -377,8 +390,8 @@ static int genmii_update_link (struct uec_mii_info *mii_info) * (ie - we're capable and it's not done) */ status = uec_phy_read(mii_info, MII_BMSR); - if ((status & BMSR_LSTATUS) && (status & BMSR_ANEGCAPABLE) - && !(status & BMSR_ANEGCOMPLETE)) { + if ((status & BMSR_LSTATUS) && (status & BMSR_ANEGCAPABLE) && + !(status & BMSR_ANEGCOMPLETE)) { int i = 0; while (!(status & BMSR_ANEGCOMPLETE)) { @@ -405,14 +418,13 @@ static int genmii_update_link (struct uec_mii_info *mii_info) return 0; } -static int genmii_read_status (struct uec_mii_info *mii_info) +static int genmii_read_status(struct uec_mii_info *mii_info) { u16 status; int err; - /* Update the link, but return if there - * was an error */ - err = genmii_update_link (mii_info); + /* Update the link, but return if there was an error */ + err = genmii_update_link(mii_info); if (err) return err; @@ -449,13 +461,13 @@ static int genmii_read_status (struct uec_mii_info *mii_info) static int bcm_init(struct uec_mii_info *mii_info) { struct eth_device *edev = mii_info->dev; - uec_private_t *uec = edev->priv; + struct uec_priv *uec = edev->priv; gbit_config_aneg(mii_info); - if ((uec->uec_info->enet_interface_type == - PHY_INTERFACE_MODE_RGMII_RXID) && - (uec->uec_info->speed == SPEED_1000)) { + if (uec->uec_info->enet_interface_type == + PHY_INTERFACE_MODE_RGMII_RXID && + uec->uec_info->speed == SPEED_1000) { u16 val; int cnt = 50; @@ -476,18 +488,18 @@ static int bcm_init(struct uec_mii_info *mii_info) uec_phy_write(mii_info, 0x18, val); } - return 0; + return 0; } static int uec_marvell_init(struct uec_mii_info *mii_info) { struct eth_device *edev = mii_info->dev; - uec_private_t *uec = edev->priv; + struct uec_priv *uec = edev->priv; phy_interface_t iface = uec->uec_info->enet_interface_type; int speed = uec->uec_info->speed; - if ((speed == SPEED_1000) && - (iface == PHY_INTERFACE_MODE_RGMII_ID || + if (speed == SPEED_1000 && + (iface == PHY_INTERFACE_MODE_RGMII_ID || iface == PHY_INTERFACE_MODE_RGMII_RXID || iface == PHY_INTERFACE_MODE_RGMII_TXID)) { int temp; @@ -515,20 +527,21 @@ static int uec_marvell_init(struct uec_mii_info *mii_info) return 0; } -static int marvell_read_status (struct uec_mii_info *mii_info) +static int marvell_read_status(struct uec_mii_info *mii_info) { u16 status; int err; - /* Update the link, but return if there - * was an error */ - err = genmii_update_link (mii_info); + /* Update the link, but return if there was an error */ + err = genmii_update_link(mii_info); if (err) return err; - /* If the link is up, read the speed and duplex */ - /* If we aren't autonegotiating, assume speeds - * are as set */ + /* + * If the link is up, read the speed and duplex + * If we aren't autonegotiating, assume speeds + * are as set + */ if (mii_info->autoneg && mii_info->link) { int speed; @@ -559,7 +572,7 @@ static int marvell_read_status (struct uec_mii_info *mii_info) return 0; } -static int marvell_ack_interrupt (struct uec_mii_info *mii_info) +static int marvell_ack_interrupt(struct uec_mii_info *mii_info) { /* Clear the interrupts by reading the reg */ uec_phy_read(mii_info, MII_M1011_IEVENT); @@ -567,18 +580,18 @@ static int marvell_ack_interrupt (struct uec_mii_info *mii_info) return 0; } -static int marvell_config_intr (struct uec_mii_info *mii_info) +static int marvell_config_intr(struct uec_mii_info *mii_info) { if (mii_info->interrupts == MII_INTERRUPT_ENABLED) uec_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); else uec_phy_write(mii_info, MII_M1011_IMASK, - MII_M1011_IMASK_CLEAR); + MII_M1011_IMASK_CLEAR); return 0; } -static int dm9161_init (struct uec_mii_info *mii_info) +static int dm9161_init(struct uec_mii_info *mii_info) { /* Reset the PHY */ uec_phy_write(mii_info, MII_BMCR, uec_phy_read(mii_info, MII_BMCR) | @@ -589,29 +602,31 @@ static int dm9161_init (struct uec_mii_info *mii_info) uec_phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT); - config_genmii_advert (mii_info); + config_genmii_advert(mii_info); /* Start/restart aneg */ - genmii_config_aneg (mii_info); + genmii_config_aneg(mii_info); return 0; } -static int dm9161_config_aneg (struct uec_mii_info *mii_info) +static int dm9161_config_aneg(struct uec_mii_info *mii_info) { return 0; } -static int dm9161_read_status (struct uec_mii_info *mii_info) +static int dm9161_read_status(struct uec_mii_info *mii_info) { u16 status; int err; /* Update the link, but return if there was an error */ - err = genmii_update_link (mii_info); + err = genmii_update_link(mii_info); if (err) return err; - /* If the link is up, read the speed and duplex - If we aren't autonegotiating assume speeds are as set */ + /* + * If the link is up, read the speed and duplex + * If we aren't autonegotiating assume speeds are as set + */ if (mii_info->autoneg && mii_info->link) { status = uec_phy_read(mii_info, MII_DM9161_SCSR); if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) @@ -628,7 +643,7 @@ static int dm9161_read_status (struct uec_mii_info *mii_info) return 0; } -static int dm9161_ack_interrupt (struct uec_mii_info *mii_info) +static int dm9161_ack_interrupt(struct uec_mii_info *mii_info) { /* Clear the interrupt by reading the reg */ uec_phy_read(mii_info, MII_DM9161_INTR); @@ -636,7 +651,7 @@ static int dm9161_ack_interrupt (struct uec_mii_info *mii_info) return 0; } -static int dm9161_config_intr (struct uec_mii_info *mii_info) +static int dm9161_config_intr(struct uec_mii_info *mii_info) { if (mii_info->interrupts == MII_INTERRUPT_ENABLED) uec_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT); @@ -646,23 +661,23 @@ static int dm9161_config_intr (struct uec_mii_info *mii_info) return 0; } -static void dm9161_close (struct uec_mii_info *mii_info) +static void dm9161_close(struct uec_mii_info *mii_info) { } -static int fixed_phy_aneg (struct uec_mii_info *mii_info) +static int fixed_phy_aneg(struct uec_mii_info *mii_info) { mii_info->autoneg = 0; /* Turn off auto negotiation for fixed phy */ return 0; } -static int fixed_phy_read_status (struct uec_mii_info *mii_info) +static int fixed_phy_read_status(struct uec_mii_info *mii_info) { int i = 0; for (i = 0; i < ARRAY_SIZE(fixed_phy_port); i++) { if (strncmp(mii_info->dev->name, fixed_phy_port[i].name, - strlen(mii_info->dev->name)) == 0) { + strlen(mii_info->dev->name)) == 0) { mii_info->speed = fixed_phy_port[i].speed; mii_info->duplex = fixed_phy_port[i].duplex; mii_info->link = 1; /* Link is always UP */ @@ -673,25 +688,26 @@ static int fixed_phy_read_status (struct uec_mii_info *mii_info) return 0; } -static int smsc_config_aneg (struct uec_mii_info *mii_info) +static int smsc_config_aneg(struct uec_mii_info *mii_info) { return 0; } -static int smsc_read_status (struct uec_mii_info *mii_info) +static int smsc_read_status(struct uec_mii_info *mii_info) { u16 status; int err; - /* Update the link, but return if there - * was an error */ - err = genmii_update_link (mii_info); + /* Update the link, but return if there was an error */ + err = genmii_update_link(mii_info); if (err) return err; - /* If the link is up, read the speed and duplex */ - /* If we aren't autonegotiating, assume speeds - * are as set */ + /* + * If the link is up, read the speed and duplex + * If we aren't autonegotiating, assume speeds + * are as set + */ if (mii_info->autoneg && mii_info->link) { int val; @@ -699,22 +715,22 @@ static int smsc_read_status (struct uec_mii_info *mii_info) val = (status & 0x1c) >> 2; switch (val) { - case 1: - mii_info->duplex = DUPLEX_HALF; - mii_info->speed = SPEED_10; - break; - case 5: - mii_info->duplex = DUPLEX_FULL; - mii_info->speed = SPEED_10; - break; - case 2: - mii_info->duplex = DUPLEX_HALF; - mii_info->speed = SPEED_100; - break; - case 6: - mii_info->duplex = DUPLEX_FULL; - mii_info->speed = SPEED_100; - break; + case 1: + mii_info->duplex = DUPLEX_HALF; + mii_info->speed = SPEED_10; + break; + case 5: + mii_info->duplex = DUPLEX_FULL; + mii_info->speed = SPEED_10; + break; + case 2: + mii_info->duplex = DUPLEX_HALF; + mii_info->speed = SPEED_100; + break; + case 6: + mii_info->duplex = DUPLEX_FULL; + mii_info->speed = SPEED_100; + break; } mii_info->pause = 0; } @@ -803,25 +819,25 @@ static struct phy_info *phy_info[] = { NULL }; -u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum) +static u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum) { - return mii_info->mdio_read (mii_info->dev, mii_info->mii_id, regnum); + return mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); } -void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum, u16 val) +static void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum, u16 val) { - mii_info->mdio_write (mii_info->dev, mii_info->mii_id, regnum, val); + mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val); } /* Use the PHY ID registers to determine what type of PHY is attached * to device dev. return a struct phy_info structure describing that PHY */ -struct phy_info *uec_get_phy_info (struct uec_mii_info *mii_info) +struct phy_info *uec_get_phy_info(struct uec_mii_info *mii_info) { u16 phy_reg; u32 phy_ID; int i; - struct phy_info *theInfo = NULL; + struct phy_info *info = NULL; /* Grab the bits from PHYIR1, and put them in the upper half */ phy_reg = uec_phy_read(mii_info, MII_PHYSID1); @@ -836,30 +852,29 @@ struct phy_info *uec_get_phy_info (struct uec_mii_info *mii_info) for (i = 0; phy_info[i]; i++) if (phy_info[i]->phy_id == (phy_ID & phy_info[i]->phy_id_mask)) { - theInfo = phy_info[i]; + info = phy_info[i]; break; } /* This shouldn't happen, as we have generic PHY support */ - if (theInfo == NULL) { - ugphy_info ("UEC: PHY id %x is not supported!", phy_ID); + if (!info) { + ugphy_info("UEC: PHY id %x is not supported!", phy_ID); return NULL; - } else { - ugphy_info ("UEC: PHY is %s (%x)", theInfo->name, phy_ID); } + ugphy_info("UEC: PHY is %s (%x)", info->name, phy_ID); - return theInfo; + return info; } void marvell_phy_interface_mode(struct eth_device *dev, phy_interface_t type, - int speed) + int speed) { - uec_private_t *uec = (uec_private_t *) dev->priv; + struct uec_priv *uec = (struct uec_priv *)dev->priv; struct uec_mii_info *mii_info; u16 status; if (!uec->mii_info) { - printf ("%s: the PHY not initialized\n", __FUNCTION__); + printf("%s: the PHY not initialized\n", __func__); return; } mii_info = uec->mii_info; @@ -903,10 +918,10 @@ void marvell_phy_interface_mode(struct eth_device *dev, phy_interface_t type, /* now the B2 will correctly report autoneg completion status */ } -void change_phy_interface_mode (struct eth_device *dev, - phy_interface_t type, int speed) +void change_phy_interface_mode(struct eth_device *dev, + phy_interface_t type, int speed) { #ifdef CONFIG_PHY_MODE_NEED_CHANGE - marvell_phy_interface_mode (dev, type, speed); + marvell_phy_interface_mode(dev, type, speed); #endif } diff --git a/drivers/qe/uec_phy.h b/drivers/qe/uec_phy.h index 83a7ccd981..7fd0e2c544 100644 --- a/drivers/qe/uec_phy.h +++ b/drivers/qe/uec_phy.h @@ -11,6 +11,8 @@ #ifndef __UEC_PHY_H__ #define __UEC_PHY_H__ +#include + #define MII_end ((u32)-2) #define MII_read ((u32)-1) @@ -93,8 +95,8 @@ #define MII_DM9161_INTR_LINK_CHANGE 0x0004 #define MII_DM9161_INTR_INIT 0x0000 #define MII_DM9161_INTR_STOP \ -(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ - | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) + (MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK | \ + MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) /* DM9161 10BT Configuration/Status */ #define MII_DM9161_10BTCSR 0x12 @@ -125,35 +127,6 @@ #define DUPLEX_HALF 0x00 #define DUPLEX_FULL 0x01 -/* Indicates what features are supported by the interface. */ -#define SUPPORTED_10baseT_Half (1 << 0) -#define SUPPORTED_10baseT_Full (1 << 1) -#define SUPPORTED_100baseT_Half (1 << 2) -#define SUPPORTED_100baseT_Full (1 << 3) -#define SUPPORTED_1000baseT_Half (1 << 4) -#define SUPPORTED_1000baseT_Full (1 << 5) -#define SUPPORTED_Autoneg (1 << 6) -#define SUPPORTED_TP (1 << 7) -#define SUPPORTED_AUI (1 << 8) -#define SUPPORTED_MII (1 << 9) -#define SUPPORTED_FIBRE (1 << 10) -#define SUPPORTED_BNC (1 << 11) -#define SUPPORTED_10000baseT_Full (1 << 12) - -#define ADVERTISED_10baseT_Half (1 << 0) -#define ADVERTISED_10baseT_Full (1 << 1) -#define ADVERTISED_100baseT_Half (1 << 2) -#define ADVERTISED_100baseT_Full (1 << 3) -#define ADVERTISED_1000baseT_Half (1 << 4) -#define ADVERTISED_1000baseT_Full (1 << 5) -#define ADVERTISED_Autoneg (1 << 6) -#define ADVERTISED_TP (1 << 7) -#define ADVERTISED_AUI (1 << 8) -#define ADVERTISED_MII (1 << 9) -#define ADVERTISED_FIBRE (1 << 10) -#define ADVERTISED_BNC (1 << 11) -#define ADVERTISED_10000baseT_Full (1 << 12) - /* Taken from mii_if_info and sungem_phy.h */ struct uec_mii_info { /* Information about the PHY type */ @@ -184,9 +157,9 @@ struct uec_mii_info { void *priv; /* Provided by ethernet driver */ - int (*mdio_read) (struct eth_device * dev, int mii_id, int reg); - void (*mdio_write) (struct eth_device * dev, int mii_id, int reg, - int val); + int (*mdio_read)(struct eth_device *dev, int mii_id, int reg); + void (*mdio_write)(struct eth_device *dev, int mii_id, int reg, + int val); }; /* struct phy_info: a structure which defines attributes for a PHY @@ -208,32 +181,34 @@ struct phy_info { u32 features; /* Called to initialize the PHY */ - int (*init) (struct uec_mii_info * mii_info); + int (*init)(struct uec_mii_info *mii_info); /* Called to suspend the PHY for power */ - int (*suspend) (struct uec_mii_info * mii_info); + int (*suspend)(struct uec_mii_info *mii_info); /* Reconfigures autonegotiation (or disables it) */ - int (*config_aneg) (struct uec_mii_info * mii_info); + int (*config_aneg)(struct uec_mii_info *mii_info); /* Determines the negotiated speed and duplex */ - int (*read_status) (struct uec_mii_info * mii_info); + int (*read_status)(struct uec_mii_info *mii_info); /* Clears any pending interrupts */ - int (*ack_interrupt) (struct uec_mii_info * mii_info); + int (*ack_interrupt)(struct uec_mii_info *mii_info); /* Enables or disables interrupts */ - int (*config_intr) (struct uec_mii_info * mii_info); + int (*config_intr)(struct uec_mii_info *mii_info); /* Clears up any memory if needed */ - void (*close) (struct uec_mii_info * mii_info); + void (*close)(struct uec_mii_info *mii_info); }; -struct phy_info *uec_get_phy_info (struct uec_mii_info *mii_info); -void uec_write_phy_reg (struct eth_device *dev, int mii_id, int regnum, - int value); -int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum); -void mii_clear_phy_interrupt (struct uec_mii_info *mii_info); -void mii_configure_phy_interrupt (struct uec_mii_info *mii_info, - u32 interrupts); +struct phy_info *uec_get_phy_info(struct uec_mii_info *mii_info); +void uec_write_phy_reg(struct eth_device *dev, int mii_id, int regnum, + int value); +int uec_read_phy_reg(struct eth_device *dev, int mii_id, int regnum); +void mii_clear_phy_interrupt(struct uec_mii_info *mii_info); +void mii_configure_phy_interrupt(struct uec_mii_info *mii_info, + u32 interrupts); +void change_phy_interface_mode(struct eth_device *dev, + phy_interface_t type, int speed); #endif /* __UEC_PHY_H__ */ -- cgit v1.2.3 From 5990b059516c233bf845ad510decd6a44ba9864b Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Mon, 3 Feb 2020 10:23:53 +0100 Subject: powerpc, qe: add DTS support for parallel I/O ports add DM support for parallel I/O ports on QUICC Engine Block Signed-off-by: Heiko Schocher Patch-cc: Mario Six Patch-cc: Qiang Zhao Patch-cc: Holger Brunck Series-changes: 2 - remove RFC - fixed Codingstyle errors, therefore new patch powerpc, mpc83xx: fix codingstyle issues for qe_io.c - moved DM part to drivers/pinctrl Commit-notes: Open questions / discussion: - I let the old none DM based implementation in code so boards should work with old implementation. This should be removed if all boards are converted to DM/DTS. - Unfortunately linux DTS does not use "pinctrl-" properties, instead "pio-handle" properties. Even worser old U-Boot code initializes all pins defined in "const qe_iop_conf_t qe_iop_conf_tab[]" table in board code. As linux does the same I decided to also scan through all subnodes containing "pio-map" property and initialize them too. The proper solution would be to check for "pio-handle" when a device is probed. END --- arch/powerpc/cpu/mpc83xx/Makefile | 2 + arch/powerpc/cpu/mpc83xx/cpu_init.c | 8 ++ arch/powerpc/cpu/mpc83xx/qe_io.c | 83 ++++++++---- drivers/pinctrl/Kconfig | 7 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-qe-io.c | 255 ++++++++++++++++++++++++++++++++++++ include/fsl_qe.h | 3 + 7 files changed, 334 insertions(+), 25 deletions(-) create mode 100644 drivers/pinctrl/pinctrl-qe-io.c (limited to 'drivers') diff --git a/arch/powerpc/cpu/mpc83xx/Makefile b/arch/powerpc/cpu/mpc83xx/Makefile index 304029977e..aeb42b109d 100644 --- a/arch/powerpc/cpu/mpc83xx/Makefile +++ b/arch/powerpc/cpu/mpc83xx/Makefile @@ -27,7 +27,9 @@ obj-y += cpu_init.o obj-y += speed.o obj-y += interrupts.o obj-y += ecc.o +ifndef CONFIG_PINCTRL obj-$(CONFIG_QE) += qe_io.o +endif obj-$(CONFIG_FSL_SERDES) += serdes.o ifndef CONFIG_ARCH_MPC8308 obj-$(CONFIG_PCI) += pci.o diff --git a/arch/powerpc/cpu/mpc83xx/cpu_init.c b/arch/powerpc/cpu/mpc83xx/cpu_init.c index b21b0b0324..840f907acb 100644 --- a/arch/powerpc/cpu/mpc83xx/cpu_init.c +++ b/arch/powerpc/cpu/mpc83xx/cpu_init.c @@ -14,6 +14,9 @@ #include #endif #include +#ifdef CONFIG_QE +#include +#endif #include "lblaw/lblaw.h" #include "elbc/elbc.h" @@ -28,6 +31,7 @@ extern qe_iop_conf_t qe_iop_conf_tab[]; extern void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign); +#if !defined(CONFIG_PINCTRL) static void config_qe_ioports(void) { u8 port, pin; @@ -44,6 +48,7 @@ static void config_qe_ioports(void) } } #endif +#endif /* * Breathe some life into the CPU... @@ -190,10 +195,13 @@ void cpu_init_f (volatile immap_t * im) __raw_writel(CONFIG_SYS_OBIR, &im->sysconf.obir); #endif +#if !defined(CONFIG_PINCTRL) #ifdef CONFIG_QE /* Config QE ioports */ config_qe_ioports(); #endif +#endif + /* Set up preliminary BR/OR regs */ init_early_memctl_regs(); diff --git a/arch/powerpc/cpu/mpc83xx/qe_io.c b/arch/powerpc/cpu/mpc83xx/qe_io.c index 1079ae128a..52360703a7 100644 --- a/arch/powerpc/cpu/mpc83xx/qe_io.c +++ b/arch/powerpc/cpu/mpc83xx/qe_io.c @@ -12,24 +12,35 @@ #include #define NUM_OF_PINS 32 -void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign) + +/** qe_cfg_iopin configure one io pin setting + * + * @par_io: pointer to parallel I/O base + * @port: io pin port + * @pin: io pin number which get configured + * @dir: direction of io pin 2 bits valid + * 00 = pin disabled + * 01 = output + * 10 = input + * 11 = pin is I/O + * @open_drain: is pin open drain + * @assign: pin assignment registers select the function of the pin + */ +static void qe_cfg_iopin(qepio83xx_t *par_io, u8 port, u8 pin, int dir, + int open_drain, int assign) { - u32 2bit_mask; - u32 2bit_dir; - u32 2bit_assign; - u32 1bit_mask; - u32 tmp_val; - immap_t *im; - qepio83xx_t *par_io; - int offset; + u32 dbit_mask; + u32 dbit_dir; + u32 dbit_asgn; + u32 bit_mask; + u32 tmp_val; + int offset; - im = (immap_t *)CONFIG_SYS_IMMR; - par_io = (qepio83xx_t *)&im->qepio; offset = (NUM_OF_PINS - (pin % (NUM_OF_PINS / 2) + 1) * 2); /* Calculate pin location and 2bit mask and dir */ - 2bit_mask = (u32)(0x3 << offset); - 2bit_dir = (u32)(dir << offset); + dbit_mask = (u32)(0x3 << offset); + dbit_dir = (u32)(dir << offset); /* Setup the direction */ tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ? @@ -37,35 +48,57 @@ void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign) in_be32(&par_io->ioport[port].dir1); if (pin > (NUM_OF_PINS / 2) - 1) { - out_be32(&par_io->ioport[port].dir2, ~2bit_mask & tmp_val); - out_be32(&par_io->ioport[port].dir2, 2bit_dir | tmp_val); + out_be32(&par_io->ioport[port].dir2, ~dbit_mask & tmp_val); + out_be32(&par_io->ioport[port].dir2, dbit_dir | tmp_val); } else { - out_be32(&par_io->ioport[port].dir1, ~2bit_mask & tmp_val); - out_be32(&par_io->ioport[port].dir1, 2bit_dir | tmp_val); + out_be32(&par_io->ioport[port].dir1, ~dbit_mask & tmp_val); + out_be32(&par_io->ioport[port].dir1, dbit_dir | tmp_val); } /* Calculate pin location for 1bit mask */ - 1bit_mask = (u32)(1 << (NUM_OF_PINS - (pin + 1))); + bit_mask = (u32)(1 << (NUM_OF_PINS - (pin + 1))); /* Setup the open drain */ tmp_val = in_be32(&par_io->ioport[port].podr); if (open_drain) - out_be32(&par_io->ioport[port].podr, 1bit_mask | tmp_val); + out_be32(&par_io->ioport[port].podr, bit_mask | tmp_val); else - out_be32(&par_io->ioport[port].podr, ~1bit_mask & tmp_val); + out_be32(&par_io->ioport[port].podr, ~bit_mask & tmp_val); /* Setup the assignment */ tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ? in_be32(&par_io->ioport[port].ppar2) : in_be32(&par_io->ioport[port].ppar1); - 2bit_assign = (u32)(assign << offset); + dbit_asgn = (u32)(assign << offset); /* Clear and set 2 bits mask */ if (pin > (NUM_OF_PINS / 2) - 1) { - out_be32(&par_io->ioport[port].ppar2, ~2bit_mask & tmp_val); - out_be32(&par_io->ioport[port].ppar2, 2bit_assign | tmp_val); + out_be32(&par_io->ioport[port].ppar2, ~dbit_mask & tmp_val); + out_be32(&par_io->ioport[port].ppar2, dbit_asgn | tmp_val); } else { - out_be32(&par_io->ioport[port].ppar1, ~2bit_mask & tmp_val); - out_be32(&par_io->ioport[port].ppar1, 2bit_assign | tmp_val); + out_be32(&par_io->ioport[port].ppar1, ~dbit_mask & tmp_val); + out_be32(&par_io->ioport[port].ppar1, dbit_asgn | tmp_val); } } + +#if !defined(CONFIG_PINCTRL) +/** qe_config_iopin configure one io pin setting + * + * @port: io pin port + * @pin: io pin number which get configured + * @dir: direction of io pin 2 bits valid + * 00 = pin disabled + * 01 = output + * 10 = input + * 11 = pin is I/O + * @open_drain: is pin open drain + * @assign: pin assignment registers select the function of the pin + */ +void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign) +{ + immap_t *im = (immap_t *)CONFIG_SYS_IMMR; + qepio83xx_t *par_io = (qepio83xx_t *)&im->qepio; + + qe_cfg_iopin(par_io, port, pin, dir, open_drain, assign); +} +#endif diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index cdbccfd285..048583f39b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -205,6 +205,13 @@ config PINCTRL_QCA953X the GPIO definitions and pin control functions for each available multiplex function. +config PINCTRL_QE + bool "QE based pinctrl driver, like on mpc83xx" + depends on DM + help + This option is to enable the QE pinctrl driver for QE based io + controller. + config PINCTRL_ROCKCHIP_RV1108 bool "Rockchip rv1108 pin control driver" depends on DM diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 92cff1b100..507dd3a926 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_PINCTRL_MTK) += mediatek/ obj-$(CONFIG_PINCTRL_MSCC) += mscc/ obj-$(CONFIG_ARCH_MVEBU) += mvebu/ obj-$(CONFIG_ARCH_NEXELL) += nexell/ +obj-$(CONFIG_PINCTRL_QE) += pinctrl-qe-io.o obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o obj-$(CONFIG_PINCTRL_STI) += pinctrl-sti.o obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o diff --git a/drivers/pinctrl/pinctrl-qe-io.c b/drivers/pinctrl/pinctrl-qe-io.c new file mode 100644 index 0000000000..85521eabd4 --- /dev/null +++ b/drivers/pinctrl/pinctrl-qe-io.c @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2006 Freescale Semiconductor, Inc. + * + * Dave Liu + * based on source code of Shlomi Gridish + */ + +#include +#include +#include +#include + +#if defined(CONFIG_PINCTRL) +#include +#include +#include +#include + +/** + * struct qe_io_platdata + * + * @base: Base register address + * @num_par_io_ports number of io ports + */ +struct qe_io_platdata { + qepio83xx_t *base; + u32 num_io_ports; +}; +#endif + +#define NUM_OF_PINS 32 + +/** qe_cfg_iopin configure one io pin setting + * + * @par_io: pointer to parallel I/O base + * @port: io pin port + * @pin: io pin number which get configured + * @dir: direction of io pin 2 bits valid + * 00 = pin disabled + * 01 = output + * 10 = input + * 11 = pin is I/O + * @open_drain: is pin open drain + * @assign: pin assignment registers select the function of the pin + */ +static void qe_cfg_iopin(qepio83xx_t *par_io, u8 port, u8 pin, int dir, + int open_drain, int assign) +{ + u32 dbit_mask; + u32 dbit_dir; + u32 dbit_asgn; + u32 bit_mask; + u32 tmp_val; + int offset; + + offset = (NUM_OF_PINS - (pin % (NUM_OF_PINS / 2) + 1) * 2); + + /* Calculate pin location and 2bit mask and dir */ + dbit_mask = (u32)(0x3 << offset); + dbit_dir = (u32)(dir << offset); + + /* Setup the direction */ + tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ? + in_be32(&par_io->ioport[port].dir2) : + in_be32(&par_io->ioport[port].dir1); + + if (pin > (NUM_OF_PINS / 2) - 1) { + out_be32(&par_io->ioport[port].dir2, ~dbit_mask & tmp_val); + out_be32(&par_io->ioport[port].dir2, dbit_dir | tmp_val); + } else { + out_be32(&par_io->ioport[port].dir1, ~dbit_mask & tmp_val); + out_be32(&par_io->ioport[port].dir1, dbit_dir | tmp_val); + } + + /* Calculate pin location for 1bit mask */ + bit_mask = (u32)(1 << (NUM_OF_PINS - (pin + 1))); + + /* Setup the open drain */ + tmp_val = in_be32(&par_io->ioport[port].podr); + if (open_drain) + out_be32(&par_io->ioport[port].podr, bit_mask | tmp_val); + else + out_be32(&par_io->ioport[port].podr, ~bit_mask & tmp_val); + + /* Setup the assignment */ + tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ? + in_be32(&par_io->ioport[port].ppar2) : + in_be32(&par_io->ioport[port].ppar1); + dbit_asgn = (u32)(assign << offset); + + /* Clear and set 2 bits mask */ + if (pin > (NUM_OF_PINS / 2) - 1) { + out_be32(&par_io->ioport[port].ppar2, ~dbit_mask & tmp_val); + out_be32(&par_io->ioport[port].ppar2, dbit_asgn | tmp_val); + } else { + out_be32(&par_io->ioport[port].ppar1, ~dbit_mask & tmp_val); + out_be32(&par_io->ioport[port].ppar1, dbit_asgn | tmp_val); + } +} + +#if !defined(CONFIG_PINCTRL) +/** qe_config_iopin configure one io pin setting + * + * @port: io pin port + * @pin: io pin number which get configured + * @dir: direction of io pin 2 bits valid + * 00 = pin disabled + * 01 = output + * 10 = input + * 11 = pin is I/O + * @open_drain: is pin open drain + * @assign: pin assignment registers select the function of the pin + */ +void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign) +{ + immap_t *im = (immap_t *)CONFIG_SYS_IMMR; + qepio83xx_t *par_io = (qepio83xx_t *)&im->qepio; + + qe_cfg_iopin(par_io, port, pin, dir, open_drain, assign); +} +#else +static int qe_io_ofdata_to_platdata(struct udevice *dev) +{ + struct qe_io_platdata *plat = dev->platdata; + fdt_addr_t addr; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + plat->base = (qepio83xx_t *)addr; + if (dev_read_u32(dev, "num-ports", &plat->num_io_ports)) + return -EINVAL; + + return 0; +} + +/** + * par_io_of_config_node config + * @dev: pointer to pinctrl device + * @pio: ofnode of pinconfig property + */ +static int par_io_of_config_node(struct udevice *dev, ofnode pio) +{ + struct qe_io_platdata *plat = dev->platdata; + qepio83xx_t *par_io = plat->base; + const unsigned int *pio_map; + int pio_map_len; + + pio_map = ofnode_get_property(pio, "pio-map", &pio_map_len); + if (!pio_map) + return -ENOENT; + + pio_map_len /= sizeof(unsigned int); + if ((pio_map_len % 6) != 0) { + dev_err(dev, "%s: pio-map format wrong!\n", __func__); + return -EINVAL; + } + + while (pio_map_len > 0) { + /* + * column pio_map[5] from linux (has_irq) not + * supported in u-boot yet. + */ + qe_cfg_iopin(par_io, (u8)pio_map[0], (u8)pio_map[1], + (int)pio_map[2], (int)pio_map[3], + (int)pio_map[4]); + pio_map += 6; + pio_map_len -= 6; + } + return 0; +} + +int par_io_of_config(struct udevice *dev) +{ + u32 phandle; + ofnode pio; + int err; + + err = ofnode_read_u32(dev_ofnode(dev), "pio-handle", &phandle); + if (err) { + dev_err(dev, "%s: pio-handle not available\n", __func__); + return err; + } + + pio = ofnode_get_by_phandle(phandle); + if (!ofnode_valid(pio)) { + dev_err(dev, "%s: unable to find node\n", __func__); + return -EINVAL; + } + + /* To Do: find pinctrl device and pass it */ + return par_io_of_config_node(NULL, pio); +} + +/* + * This is not nice! + * pinsettings should work with "pinctrl-" properties. + * Unfortunately on mpc83xx powerpc linux device trees + * devices handle this with "pio-handle" properties ... + * + * Even worser, old board code inits all par_io + * pins in one step, if U-Boot uses the device + * or not. So init all par_io definitions here too + * as linux does this also. + */ +static void config_qe_ioports(struct udevice *dev) +{ + ofnode ofn; + + for (ofn = dev_read_first_subnode(dev); ofnode_valid(ofn); + ofn = dev_read_next_subnode(ofn)) { + /* + * ignore errors here, as may the subnode + * has no pio-handle + */ + par_io_of_config_node(dev, ofn); + } +} + +static int par_io_pinctrl_probe(struct udevice *dev) +{ + config_qe_ioports(dev); + + return 0; +} + +static int par_io_pinctrl_set_state(struct udevice *dev, struct udevice *config) +{ + return 0; +} + +const struct pinctrl_ops par_io_pinctrl_ops = { + .set_state = par_io_pinctrl_set_state, +}; + +static const struct udevice_id par_io_pinctrl_match[] = { + { .compatible = "fsl,mpc8360-par_io"}, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(par_io_pinctrl) = { + .name = "par-io-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(par_io_pinctrl_match), + .probe = par_io_pinctrl_probe, + .ofdata_to_platdata = qe_io_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct qe_io_platdata), + .ops = &par_io_pinctrl_ops, +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) + .flags = DM_FLAG_PRE_RELOC, +#endif +}; +#endif diff --git a/include/fsl_qe.h b/include/fsl_qe.h index 6e44cbdb56..1c6941347f 100644 --- a/include/fsl_qe.h +++ b/include/fsl_qe.h @@ -296,4 +296,7 @@ int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr); #endif +#if defined(CONFIG_PINCTRL) +int par_io_of_config(struct udevice *dev); +#endif #endif /* __QE_H__ */ -- cgit v1.2.3 From 6e31c62a175ca24f74b89a684c82cbb4bf423f16 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Thu, 6 Feb 2020 09:48:16 +0100 Subject: net, qe: add DM support for QE UEC ethernet add DM/DTS support for the UEC ethernet on QUICC Engine Block. Signed-off-by: Heiko Schocher Patch-cc: Mario Six Patch-cc: Qiang Zhao Patch-cc: Holger Brunck Patch-cc: Madalin Bucur Series-changes: 3 - revert: commit "3374264df97b" ("drivers: net: qe: deselect QE when DM_ETH is enabled") as now qe works with DM and DM_ETH support. - fix mailaddress from Holger Series-changes: 2 - add comments from Qiang Zhao: - add device node documentation - I did not drop the dm_qe_uec_phy.c and use drivers/net/fsl_mdio.c because using drivers/net/fsl_mdio.c leads in none existent udevice mdio@3320 instead boards with DM ETH support should use now this driver. - remove RFC tag Commit-notes: - I let the old none DM based implementation in code so boards should work with old implementation. This Code should be removed if all boards are converted to DM/DTS. - add the DM based qe uec driver under drivers/net/qe - Therefore copied the files uccf.c uccf.h uec.h from drivers/qe. So there are a lot of Codingstyle problems currently. I fix them in next version if this RFC patch is OK or it needs some changes. - The dm based driver code is now under drivers/net/qe/dm_qe_uec.c Used a lot of functions from drivers/qe/uec.c - seperated the PHY specific code into seperate file drivers/net/qe/dm_qe_uec_phy.c END --- doc/device-tree-bindings/soc/fsl/cpm_qe/qe/ucc.txt | 53 + drivers/net/Kconfig | 2 + drivers/net/Makefile | 1 + drivers/net/qe/Kconfig | 9 + drivers/net/qe/Makefile | 5 + drivers/net/qe/dm_qe_uec.c | 1167 ++++++++++++++++++++ drivers/net/qe/dm_qe_uec.h | 22 + drivers/net/qe/dm_qe_uec_phy.c | 163 +++ drivers/net/qe/uccf.c | 507 +++++++++ drivers/net/qe/uccf.h | 119 ++ drivers/net/qe/uec.h | 693 ++++++++++++ drivers/qe/Kconfig | 2 +- drivers/qe/uccf.c | 2 + drivers/qe/uec.c | 2 + drivers/qe/uec_phy.c | 3 + 15 files changed, 2749 insertions(+), 1 deletion(-) create mode 100644 doc/device-tree-bindings/soc/fsl/cpm_qe/qe/ucc.txt create mode 100644 drivers/net/qe/Kconfig create mode 100644 drivers/net/qe/Makefile create mode 100644 drivers/net/qe/dm_qe_uec.c create mode 100644 drivers/net/qe/dm_qe_uec.h create mode 100644 drivers/net/qe/dm_qe_uec_phy.c create mode 100644 drivers/net/qe/uccf.c create mode 100644 drivers/net/qe/uccf.h create mode 100644 drivers/net/qe/uec.h (limited to 'drivers') diff --git a/doc/device-tree-bindings/soc/fsl/cpm_qe/qe/ucc.txt b/doc/device-tree-bindings/soc/fsl/cpm_qe/qe/ucc.txt new file mode 100644 index 0000000000..2758f86437 --- /dev/null +++ b/doc/device-tree-bindings/soc/fsl/cpm_qe/qe/ucc.txt @@ -0,0 +1,53 @@ +* UCC (Unified Communications Controllers) + +Required properties: +- compatible : ucc_geth +- cell-index : the ucc number(1-8), corresponding to UCCx in UM. +- reg : Offset and length of the register set for the device +- rx-clock-name: the UCC receive clock source + "none": clock source is disabled + "brg1" through "brg16": clock source is BRG1-BRG16, respectively + "clk1" through "clk24": clock source is CLK1-CLK24, respectively +- tx-clock-name: the UCC transmit clock source + "none": clock source is disabled + "brg1" through "brg16": clock source is BRG1-BRG16, respectively + "clk1" through "clk24": clock source is CLK1-CLK24, respectively +The following two properties are deprecated. rx-clock has been replaced +with rx-clock-name, and tx-clock has been replaced with tx-clock-name. +Drivers that currently use the deprecated properties should continue to +do so, in order to support older device trees, but they should be updated +to check for the new properties first. +- rx-clock : represents the UCC receive clock source. + 0x00 : clock source is disabled; + 0x1~0x10 : clock source is BRG1~BRG16 respectively; + 0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively. +- tx-clock: represents the UCC transmit clock source; + 0x00 : clock source is disabled; + 0x1~0x10 : clock source is BRG1~BRG16 respectively; + 0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively. +- phy-handle : The phandle for the PHY connected to this controller. +- phy-connection-type : a string naming the controller/PHY interface type, + i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id" (Internal + Delay), "rgmii-txid" (delay on TX only), "rgmii-rxid" (delay on RX only), + "tbi", or "rtbi". +- pio-handle : The phandle for the Parallel I/O port configuration. + +Deprecated properties: +- device-id : the ucc number(1-8), corresponding to UCCx in UM. + you should use cell-index + +Example: + ucc@2000 { + device_type = "network"; + compatible = "ucc_geth"; + cell-index = <1>; + reg = <2000 200>; + interrupts = ; + interrupt-parent = <700>; + mac-address = [ 00 04 9f 00 23 23 ]; + rx-clock = "none"; + tx-clock = "clk9"; + phy-handle = <212000>; + phy-connection-type = "gmii"; + pio-handle = <140001>; + }; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 039f9fb058..a0d2d21a55 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -432,6 +432,8 @@ config PCNET This driver supports AMD PCnet series fast ethernet family of PCI chipsets/adapters. +source "drivers/net/qe/Kconfig" + config RTL8139 bool "Realtek 8139 series Ethernet controller driver" help diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 1ecdc40b8f..03f01921ea 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_VSC9953) += vsc9953.o obj-$(CONFIG_PIC32_ETH) += pic32_mdio.o pic32_eth.o obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o obj-$(CONFIG_FSL_PFE) += pfe_eth/ +obj-y += qe/ obj-$(CONFIG_SNI_AVE) += sni_ave.o obj-y += ti/ obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o diff --git a/drivers/net/qe/Kconfig b/drivers/net/qe/Kconfig new file mode 100644 index 0000000000..dec88dea2a --- /dev/null +++ b/drivers/net/qe/Kconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2020 Heiko Schocher + +config QE_UEC + bool "NXP QE UEC Ethernet controller" + depends on DM_ETH + help + This driver supports the NXP QE UEC ethernet controller diff --git a/drivers/net/qe/Makefile b/drivers/net/qe/Makefile new file mode 100644 index 0000000000..7d84757c17 --- /dev/null +++ b/drivers/net/qe/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2020 Heiko Schocher + +obj-$(CONFIG_QE_UEC) += dm_qe_uec.o dm_qe_uec_phy.o uccf.o diff --git a/drivers/net/qe/dm_qe_uec.c b/drivers/net/qe/dm_qe_uec.c new file mode 100644 index 0000000000..3482b3ff17 --- /dev/null +++ b/drivers/net/qe/dm_qe_uec.c @@ -0,0 +1,1167 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * QE UEC ethernet controller driver + * + * based on drivers/qe/uec.c from NXP + * + * Copyright (C) 2020 Heiko Schocher + */ + +#include +#include +#include +#include +#include +#include + +#include "dm_qe_uec.h" + +#define QE_UEC_DRIVER_NAME "ucc_geth" + +/* Default UTBIPAR SMI address */ +#ifndef CONFIG_UTBIPAR_INIT_TBIPA +#define CONFIG_UTBIPAR_INIT_TBIPA 0x1F +#endif + +static int uec_mac_enable(struct uec_priv *uec, comm_dir_e mode) +{ + uec_t *uec_regs; + u32 maccfg1; + + uec_regs = uec->uec_regs; + maccfg1 = in_be32(&uec_regs->maccfg1); + + if (mode & COMM_DIR_TX) { + maccfg1 |= MACCFG1_ENABLE_TX; + out_be32(&uec_regs->maccfg1, maccfg1); + uec->mac_tx_enabled = 1; + } + + if (mode & COMM_DIR_RX) { + maccfg1 |= MACCFG1_ENABLE_RX; + out_be32(&uec_regs->maccfg1, maccfg1); + uec->mac_rx_enabled = 1; + } + + return 0; +} + +static int uec_mac_disable(struct uec_priv *uec, comm_dir_e mode) +{ + uec_t *uec_regs; + u32 maccfg1; + + uec_regs = uec->uec_regs; + maccfg1 = in_be32(&uec_regs->maccfg1); + + if (mode & COMM_DIR_TX) { + maccfg1 &= ~MACCFG1_ENABLE_TX; + out_be32(&uec_regs->maccfg1, maccfg1); + uec->mac_tx_enabled = 0; + } + + if (mode & COMM_DIR_RX) { + maccfg1 &= ~MACCFG1_ENABLE_RX; + out_be32(&uec_regs->maccfg1, maccfg1); + uec->mac_rx_enabled = 0; + } + + return 0; +} + +static int uec_restart_tx(struct uec_priv *uec) +{ + struct uec_inf *ui = uec->uec_info; + u32 cecr_subblock; + + cecr_subblock = ucc_fast_get_qe_cr_subblock(ui->uf_info.ucc_num); + qe_issue_cmd(QE_RESTART_TX, cecr_subblock, + (u8)QE_CR_PROTOCOL_ETHERNET, 0); + + uec->grace_stopped_tx = 0; + + return 0; +} + +static int uec_restart_rx(struct uec_priv *uec) +{ + struct uec_inf *ui = uec->uec_info; + u32 cecr_subblock; + + cecr_subblock = ucc_fast_get_qe_cr_subblock(ui->uf_info.ucc_num); + qe_issue_cmd(QE_RESTART_RX, cecr_subblock, + (u8)QE_CR_PROTOCOL_ETHERNET, 0); + + uec->grace_stopped_rx = 0; + + return 0; +} + +static int uec_open(struct uec_priv *uec, comm_dir_e mode) +{ + struct ucc_fast_priv *uccf; + + uccf = uec->uccf; + + /* check if the UCC number is in range. */ + if (uec->uec_info->uf_info.ucc_num >= UCC_MAX_NUM) { + printf("%s: ucc_num out of range.\n", __func__); + return -EINVAL; + } + + /* Enable MAC */ + uec_mac_enable(uec, mode); + + /* Enable UCC fast */ + ucc_fast_enable(uccf, mode); + + /* RISC microcode start */ + if ((mode & COMM_DIR_TX) && uec->grace_stopped_tx) + uec_restart_tx(uec); + + if ((mode & COMM_DIR_RX) && uec->grace_stopped_rx) + uec_restart_rx(uec); + + return 0; +} + +static int uec_set_mac_if_mode(struct uec_priv *uec) +{ + struct uec_inf *uec_info = uec->uec_info; + phy_interface_t enet_if_mode; + uec_t *uec_regs; + u32 upsmr; + u32 maccfg2; + + uec_regs = uec->uec_regs; + enet_if_mode = uec_info->enet_interface_type; + + maccfg2 = in_be32(&uec_regs->maccfg2); + maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK; + + upsmr = in_be32(&uec->uccf->uf_regs->upsmr); + upsmr &= ~(UPSMR_RPM | UPSMR_TBIM | UPSMR_R10M | UPSMR_RMM); + + switch (uec_info->speed) { + case SPEED_10: + maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; + switch (enet_if_mode) { + case PHY_INTERFACE_MODE_MII: + break; + case PHY_INTERFACE_MODE_RGMII: + upsmr |= (UPSMR_RPM | UPSMR_R10M); + break; + case PHY_INTERFACE_MODE_RMII: + upsmr |= (UPSMR_R10M | UPSMR_RMM); + break; + default: + return -EINVAL; + } + break; + case SPEED_100: + maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; + switch (enet_if_mode) { + case PHY_INTERFACE_MODE_MII: + break; + case PHY_INTERFACE_MODE_RGMII: + upsmr |= UPSMR_RPM; + break; + case PHY_INTERFACE_MODE_RMII: + upsmr |= UPSMR_RMM; + break; + default: + return -EINVAL; + } + break; + case SPEED_1000: + maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; + switch (enet_if_mode) { + case PHY_INTERFACE_MODE_GMII: + break; + case PHY_INTERFACE_MODE_TBI: + upsmr |= UPSMR_TBIM; + break; + case PHY_INTERFACE_MODE_RTBI: + upsmr |= (UPSMR_RPM | UPSMR_TBIM); + break; + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII: + upsmr |= UPSMR_RPM; + break; + case PHY_INTERFACE_MODE_SGMII: + upsmr |= UPSMR_SGMM; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + out_be32(&uec_regs->maccfg2, maccfg2); + out_be32(&uec->uccf->uf_regs->upsmr, upsmr); + + return 0; +} + +static int qe_uec_start(struct udevice *dev) +{ + struct qe_uec_priv *priv = dev_get_priv(dev); + struct uec_priv *uec = priv->uec; + struct phy_device *phydev = priv->phydev; + struct uec_inf *uec_info = uec->uec_info; + int err; + + if (!phydev) + return -ENODEV; + + /* Setup MAC interface mode */ + genphy_update_link(phydev); + genphy_parse_link(phydev); + uec_info->speed = phydev->speed; + uec_set_mac_if_mode(uec); + + err = uec_open(uec, COMM_DIR_RX_AND_TX); + if (err) { + printf("%s: cannot enable UEC device\n", dev->name); + return -EINVAL; + } + + return (phydev->link ? 0 : -EINVAL); +} + +static int qe_uec_send(struct udevice *dev, void *packet, int length) +{ + struct qe_uec_priv *priv = dev_get_priv(dev); + struct uec_priv *uec = priv->uec; + struct ucc_fast_priv *uccf = uec->uccf; + struct buffer_descriptor *bd; + u16 status; + int i; + int result = 0; + + uccf = uec->uccf; + bd = uec->tx_bd; + + /* Find an empty TxBD */ + for (i = 0; BD_STATUS(bd) & TX_BD_READY; i++) { + if (i > 0x100000) { + printf("%s: tx buffer not ready\n", dev->name); + return result; + } + } + + /* Init TxBD */ + BD_DATA_SET(bd, packet); + BD_LENGTH_SET(bd, length); + status = BD_STATUS(bd); + status &= BD_WRAP; + status |= (TX_BD_READY | TX_BD_LAST); + BD_STATUS_SET(bd, status); + + /* Tell UCC to transmit the buffer */ + ucc_fast_transmit_on_demand(uccf); + + /* Wait for buffer to be transmitted */ + for (i = 0; BD_STATUS(bd) & TX_BD_READY; i++) { + if (i > 0x100000) { + printf("%s: tx error\n", dev->name); + return result; + } + } + + /* Ok, the buffer be transimitted */ + BD_ADVANCE(bd, status, uec->p_tx_bd_ring); + uec->tx_bd = bd; + result = 1; + + return result; +} + +/* + * Receive frame: + * - wait for the next BD to get ready bit set + * - clean up the descriptor + * - move on and indicate to HW that the cleaned BD is available for Rx + */ +static int qe_uec_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct qe_uec_priv *priv = dev_get_priv(dev); + struct uec_priv *uec = priv->uec; + struct buffer_descriptor *bd; + u16 status; + u16 len = 0; + u8 *data; + + *packetp = memalign(ARCH_DMA_MINALIGN, MAX_RXBUF_LEN); + if (*packetp == 0) { + printf("%s: error allocating packetp\n", __func__); + return -ENOMEM; + } + + bd = uec->rx_bd; + status = BD_STATUS(bd); + + while (!(status & RX_BD_EMPTY)) { + if (!(status & RX_BD_ERROR)) { + data = BD_DATA(bd); + len = BD_LENGTH(bd); + memcpy(*packetp, (char *)data, len); + } else { + printf("%s: Rx error\n", dev->name); + } + status &= BD_CLEAN; + BD_LENGTH_SET(bd, 0); + BD_STATUS_SET(bd, status | RX_BD_EMPTY); + BD_ADVANCE(bd, status, uec->p_rx_bd_ring); + status = BD_STATUS(bd); + } + uec->rx_bd = bd; + + return len; +} + +static int uec_graceful_stop_tx(struct uec_priv *uec) +{ + ucc_fast_t *uf_regs; + u32 cecr_subblock; + u32 ucce; + + uf_regs = uec->uccf->uf_regs; + + /* Clear the grace stop event */ + out_be32(&uf_regs->ucce, UCCE_GRA); + + /* Issue host command */ + cecr_subblock = + ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num); + qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock, + (u8)QE_CR_PROTOCOL_ETHERNET, 0); + + /* Wait for command to complete */ + do { + ucce = in_be32(&uf_regs->ucce); + } while (!(ucce & UCCE_GRA)); + + uec->grace_stopped_tx = 1; + + return 0; +} + +static int uec_graceful_stop_rx(struct uec_priv *uec) +{ + u32 cecr_subblock; + u8 ack; + + if (!uec->p_rx_glbl_pram) { + printf("%s: No init rx global parameter\n", __func__); + return -EINVAL; + } + + /* Clear acknowledge bit */ + ack = uec->p_rx_glbl_pram->rxgstpack; + ack &= ~GRACEFUL_STOP_ACKNOWLEDGE_RX; + uec->p_rx_glbl_pram->rxgstpack = ack; + + /* Keep issuing cmd and checking ack bit until it is asserted */ + do { + /* Issue host command */ + cecr_subblock = + ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num); + qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock, + (u8)QE_CR_PROTOCOL_ETHERNET, 0); + ack = uec->p_rx_glbl_pram->rxgstpack; + } while (!(ack & GRACEFUL_STOP_ACKNOWLEDGE_RX)); + + uec->grace_stopped_rx = 1; + + return 0; +} + +static int uec_stop(struct uec_priv *uec, comm_dir_e mode) +{ + /* check if the UCC number is in range. */ + if (uec->uec_info->uf_info.ucc_num >= UCC_MAX_NUM) { + printf("%s: ucc_num out of range.\n", __func__); + return -EINVAL; + } + /* Stop any transmissions */ + if ((mode & COMM_DIR_TX) && !uec->grace_stopped_tx) + uec_graceful_stop_tx(uec); + + /* Stop any receptions */ + if ((mode & COMM_DIR_RX) && !uec->grace_stopped_rx) + uec_graceful_stop_rx(uec); + + /* Disable the UCC fast */ + ucc_fast_disable(uec->uccf, mode); + + /* Disable the MAC */ + uec_mac_disable(uec, mode); + + return 0; +} + +static void qe_uec_stop(struct udevice *dev) +{ + struct qe_uec_priv *priv = dev_get_priv(dev); + struct uec_priv *uec = priv->uec; + + uec_stop(uec, COMM_DIR_RX_AND_TX); +} + +static int qe_uec_set_hwaddr(struct udevice *dev) +{ + struct qe_uec_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + struct uec_priv *uec = priv->uec; + uec_t *uec_regs = uec->uec_regs; + uchar *mac = pdata->enetaddr; + u32 mac_addr1; + u32 mac_addr2; + + /* + * if a station address of 0x12345678ABCD, perform a write to + * MACSTNADDR1 of 0xCDAB7856, + * MACSTNADDR2 of 0x34120000 + */ + + mac_addr1 = (mac[5] << 24) | (mac[4] << 16) | + (mac[3] << 8) | (mac[2]); + out_be32(&uec_regs->macstnaddr1, mac_addr1); + + mac_addr2 = ((mac[1] << 24) | (mac[0] << 16)) & 0xffff0000; + out_be32(&uec_regs->macstnaddr2, mac_addr2); + + return 0; +} + +static int qe_uec_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + if (packet) + free(packet); + + return 0; +} + +static const struct eth_ops qe_uec_eth_ops = { + .start = qe_uec_start, + .send = qe_uec_send, + .recv = qe_uec_recv, + .free_pkt = qe_uec_free_pkt, + .stop = qe_uec_stop, + .write_hwaddr = qe_uec_set_hwaddr, +}; + +static int uec_convert_threads_num(enum uec_num_of_threads threads_num, + int *threads_num_ret) +{ + int num_threads_numerica; + + switch (threads_num) { + case UEC_NUM_OF_THREADS_1: + num_threads_numerica = 1; + break; + case UEC_NUM_OF_THREADS_2: + num_threads_numerica = 2; + break; + case UEC_NUM_OF_THREADS_4: + num_threads_numerica = 4; + break; + case UEC_NUM_OF_THREADS_6: + num_threads_numerica = 6; + break; + case UEC_NUM_OF_THREADS_8: + num_threads_numerica = 8; + break; + default: + printf("%s: Bad number of threads value.", + __func__); + return -EINVAL; + } + + *threads_num_ret = num_threads_numerica; + + return 0; +} + +static void uec_init_tx_parameter(struct uec_priv *uec, int num_threads_tx) +{ + struct uec_inf *uec_info; + u32 end_bd; + u8 bmrx = 0; + int i; + + uec_info = uec->uec_info; + + /* Alloc global Tx parameter RAM page */ + uec->tx_glbl_pram_offset = + qe_muram_alloc(sizeof(struct uec_tx_global_pram), + UEC_TX_GLOBAL_PRAM_ALIGNMENT); + uec->p_tx_glbl_pram = (struct uec_tx_global_pram *) + qe_muram_addr(uec->tx_glbl_pram_offset); + + /* Zero the global Tx prameter RAM */ + memset(uec->p_tx_glbl_pram, 0, sizeof(struct uec_tx_global_pram)); + + /* Init global Tx parameter RAM */ + + /* TEMODER, RMON statistics disable, one Tx queue */ + out_be16(&uec->p_tx_glbl_pram->temoder, TEMODER_INIT_VALUE); + + /* SQPTR */ + uec->send_q_mem_reg_offset = + qe_muram_alloc(sizeof(struct uec_send_queue_qd), + UEC_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT); + uec->p_send_q_mem_reg = (struct uec_send_queue_mem_region *) + qe_muram_addr(uec->send_q_mem_reg_offset); + out_be32(&uec->p_tx_glbl_pram->sqptr, uec->send_q_mem_reg_offset); + + /* Setup the table with TxBDs ring */ + end_bd = (u32)uec->p_tx_bd_ring + (uec_info->tx_bd_ring_len - 1) + * SIZEOFBD; + out_be32(&uec->p_send_q_mem_reg->sqqd[0].bd_ring_base, + (u32)(uec->p_tx_bd_ring)); + out_be32(&uec->p_send_q_mem_reg->sqqd[0].last_bd_completed_address, + end_bd); + + /* Scheduler Base Pointer, we have only one Tx queue, no need it */ + out_be32(&uec->p_tx_glbl_pram->schedulerbasepointer, 0); + + /* TxRMON Base Pointer, TxRMON disable, we don't need it */ + out_be32(&uec->p_tx_glbl_pram->txrmonbaseptr, 0); + + /* TSTATE, global snooping, big endian, the CSB bus selected */ + bmrx = BMR_INIT_VALUE; + out_be32(&uec->p_tx_glbl_pram->tstate, ((u32)(bmrx) << BMR_SHIFT)); + + /* IPH_Offset */ + for (i = 0; i < MAX_IPH_OFFSET_ENTRY; i++) + out_8(&uec->p_tx_glbl_pram->iphoffset[i], 0); + + /* VTAG table */ + for (i = 0; i < UEC_TX_VTAG_TABLE_ENTRY_MAX; i++) + out_be32(&uec->p_tx_glbl_pram->vtagtable[i], 0); + + /* TQPTR */ + uec->thread_dat_tx_offset = + qe_muram_alloc(num_threads_tx * + sizeof(struct uec_thread_data_tx) + + 32 * (num_threads_tx == 1), + UEC_THREAD_DATA_ALIGNMENT); + + uec->p_thread_data_tx = (struct uec_thread_data_tx *) + qe_muram_addr(uec->thread_dat_tx_offset); + out_be32(&uec->p_tx_glbl_pram->tqptr, uec->thread_dat_tx_offset); +} + +static void uec_init_rx_parameter(struct uec_priv *uec, int num_threads_rx) +{ + u8 bmrx = 0; + int i; + struct uec_82xx_add_filtering_pram *p_af_pram; + + /* Allocate global Rx parameter RAM page */ + uec->rx_glbl_pram_offset = + qe_muram_alloc(sizeof(struct uec_rx_global_pram), + UEC_RX_GLOBAL_PRAM_ALIGNMENT); + uec->p_rx_glbl_pram = (struct uec_rx_global_pram *) + qe_muram_addr(uec->rx_glbl_pram_offset); + + /* Zero Global Rx parameter RAM */ + memset(uec->p_rx_glbl_pram, 0, sizeof(struct uec_rx_global_pram)); + + /* Init global Rx parameter RAM */ + /* + * REMODER, Extended feature mode disable, VLAN disable, + * LossLess flow control disable, Receive firmware statisic disable, + * Extended address parsing mode disable, One Rx queues, + * Dynamic maximum/minimum frame length disable, IP checksum check + * disable, IP address alignment disable + */ + out_be32(&uec->p_rx_glbl_pram->remoder, REMODER_INIT_VALUE); + + /* RQPTR */ + uec->thread_dat_rx_offset = + qe_muram_alloc(num_threads_rx * + sizeof(struct uec_thread_data_rx), + UEC_THREAD_DATA_ALIGNMENT); + uec->p_thread_data_rx = (struct uec_thread_data_rx *) + qe_muram_addr(uec->thread_dat_rx_offset); + out_be32(&uec->p_rx_glbl_pram->rqptr, uec->thread_dat_rx_offset); + + /* Type_or_Len */ + out_be16(&uec->p_rx_glbl_pram->typeorlen, 3072); + + /* RxRMON base pointer, we don't need it */ + out_be32(&uec->p_rx_glbl_pram->rxrmonbaseptr, 0); + + /* IntCoalescingPTR, we don't need it, no interrupt */ + out_be32(&uec->p_rx_glbl_pram->intcoalescingptr, 0); + + /* RSTATE, global snooping, big endian, the CSB bus selected */ + bmrx = BMR_INIT_VALUE; + out_8(&uec->p_rx_glbl_pram->rstate, bmrx); + + /* MRBLR */ + out_be16(&uec->p_rx_glbl_pram->mrblr, MAX_RXBUF_LEN); + + /* RBDQPTR */ + uec->rx_bd_qs_tbl_offset = + qe_muram_alloc(sizeof(struct uec_rx_bd_queues_entry) + + sizeof(struct uec_rx_pref_bds), + UEC_RX_BD_QUEUES_ALIGNMENT); + uec->p_rx_bd_qs_tbl = (struct uec_rx_bd_queues_entry *) + qe_muram_addr(uec->rx_bd_qs_tbl_offset); + + /* Zero it */ + memset(uec->p_rx_bd_qs_tbl, 0, sizeof(struct uec_rx_bd_queues_entry) + + sizeof(struct uec_rx_pref_bds)); + out_be32(&uec->p_rx_glbl_pram->rbdqptr, uec->rx_bd_qs_tbl_offset); + out_be32(&uec->p_rx_bd_qs_tbl->externalbdbaseptr, + (u32)uec->p_rx_bd_ring); + + /* MFLR */ + out_be16(&uec->p_rx_glbl_pram->mflr, MAX_FRAME_LEN); + /* MINFLR */ + out_be16(&uec->p_rx_glbl_pram->minflr, MIN_FRAME_LEN); + /* MAXD1 */ + out_be16(&uec->p_rx_glbl_pram->maxd1, MAX_DMA1_LEN); + /* MAXD2 */ + out_be16(&uec->p_rx_glbl_pram->maxd2, MAX_DMA2_LEN); + /* ECAM_PTR */ + out_be32(&uec->p_rx_glbl_pram->ecamptr, 0); + /* L2QT */ + out_be32(&uec->p_rx_glbl_pram->l2qt, 0); + /* L3QT */ + for (i = 0; i < 8; i++) + out_be32(&uec->p_rx_glbl_pram->l3qt[i], 0); + + /* VLAN_TYPE */ + out_be16(&uec->p_rx_glbl_pram->vlantype, 0x8100); + /* TCI */ + out_be16(&uec->p_rx_glbl_pram->vlantci, 0); + + /* Clear PQ2 style address filtering hash table */ + p_af_pram = (struct uec_82xx_add_filtering_pram *) + uec->p_rx_glbl_pram->addressfiltering; + + p_af_pram->iaddr_h = 0; + p_af_pram->iaddr_l = 0; + p_af_pram->gaddr_h = 0; + p_af_pram->gaddr_l = 0; +} + +static int uec_issue_init_enet_rxtx_cmd(struct uec_priv *uec, + int thread_tx, int thread_rx) +{ + struct uec_init_cmd_pram *p_init_enet_param; + u32 init_enet_param_offset; + struct uec_inf *uec_info; + struct ucc_fast_inf *uf_info; + int i; + int snum; + u32 off; + u32 entry_val; + u32 command; + u32 cecr_subblock; + + uec_info = uec->uec_info; + uf_info = &uec_info->uf_info; + + /* Allocate init enet command parameter */ + uec->init_enet_param_offset = + qe_muram_alloc(sizeof(struct uec_init_cmd_pram), 4); + init_enet_param_offset = uec->init_enet_param_offset; + uec->p_init_enet_param = (struct uec_init_cmd_pram *) + qe_muram_addr(uec->init_enet_param_offset); + + /* Zero init enet command struct */ + memset((void *)uec->p_init_enet_param, 0, + sizeof(struct uec_init_cmd_pram)); + + /* Init the command struct */ + p_init_enet_param = uec->p_init_enet_param; + p_init_enet_param->resinit0 = ENET_INIT_PARAM_MAGIC_RES_INIT0; + p_init_enet_param->resinit1 = ENET_INIT_PARAM_MAGIC_RES_INIT1; + p_init_enet_param->resinit2 = ENET_INIT_PARAM_MAGIC_RES_INIT2; + p_init_enet_param->resinit3 = ENET_INIT_PARAM_MAGIC_RES_INIT3; + p_init_enet_param->resinit4 = ENET_INIT_PARAM_MAGIC_RES_INIT4; + p_init_enet_param->largestexternallookupkeysize = 0; + + p_init_enet_param->rgftgfrxglobal |= ((u32)uec_info->num_threads_rx) + << ENET_INIT_PARAM_RGF_SHIFT; + p_init_enet_param->rgftgfrxglobal |= ((u32)uec_info->num_threads_tx) + << ENET_INIT_PARAM_TGF_SHIFT; + + /* Init Rx global parameter pointer */ + p_init_enet_param->rgftgfrxglobal |= uec->rx_glbl_pram_offset | + (u32)uec_info->risc_rx; + + /* Init Rx threads */ + for (i = 0; i < (thread_rx + 1); i++) { + snum = qe_get_snum(); + if (snum < 0) { + printf("%s can not get snum\n", __func__); + return -ENOMEM; + } + + if (i == 0) { + off = 0; + } else { + off = qe_muram_alloc(sizeof(struct uec_thread_rx_pram), + UEC_THREAD_RX_PRAM_ALIGNMENT); + } + + entry_val = ((u32)snum << ENET_INIT_PARAM_SNUM_SHIFT) | + off | (u32)uec_info->risc_rx; + p_init_enet_param->rxthread[i] = entry_val; + } + + /* Init Tx global parameter pointer */ + p_init_enet_param->txglobal = uec->tx_glbl_pram_offset | + (u32)uec_info->risc_tx; + + /* Init Tx threads */ + for (i = 0; i < thread_tx; i++) { + snum = qe_get_snum(); + if (snum < 0) { + printf("%s can not get snum\n", __func__); + return -ENOMEM; + } + + off = qe_muram_alloc(sizeof(struct uec_thread_tx_pram), + UEC_THREAD_TX_PRAM_ALIGNMENT); + + entry_val = ((u32)snum << ENET_INIT_PARAM_SNUM_SHIFT) | + off | (u32)uec_info->risc_tx; + p_init_enet_param->txthread[i] = entry_val; + } + + __asm__ __volatile__("sync"); + + /* Issue QE command */ + command = QE_INIT_TX_RX; + cecr_subblock = ucc_fast_get_qe_cr_subblock(uf_info->ucc_num); + qe_issue_cmd(command, cecr_subblock, (u8)QE_CR_PROTOCOL_ETHERNET, + init_enet_param_offset); + + return 0; +} + +static int uec_startup(struct udevice *dev) +{ + struct qe_uec_priv *priv = dev_get_priv(dev); + struct uec_priv *uec = priv->uec; + struct uec_inf *uec_info; + struct ucc_fast_inf *uf_info; + struct ucc_fast_priv *uccf; + ucc_fast_t *uf_regs; + uec_t *uec_regs; + int num_threads_tx; + int num_threads_rx; + u32 utbipar; + u32 length; + u32 align; + struct buffer_descriptor *bd; + u8 *buf; + int i; + + uec_info = uec->uec_info; + uf_info = &uec_info->uf_info; + + /* Check if Rx BD ring len is illegal */ + if (uec_info->rx_bd_ring_len < UEC_RX_BD_RING_SIZE_MIN || + uec_info->rx_bd_ring_len % UEC_RX_BD_RING_SIZE_ALIGNMENT) { + printf("%s: Rx BD ring len must be multiple of 4, and > 8.\n", + __func__); + return -EINVAL; + } + + /* Check if Tx BD ring len is illegal */ + if (uec_info->tx_bd_ring_len < UEC_TX_BD_RING_SIZE_MIN) { + printf("%s: Tx BD ring length must not be smaller than 2.\n", + __func__); + return -EINVAL; + } + + /* Check if MRBLR is illegal */ + if (MAX_RXBUF_LEN == 0 || (MAX_RXBUF_LEN % UEC_MRBLR_ALIGNMENT)) { + printf("%s: max rx buffer length must be mutliple of 128.\n", + __func__); + return -EINVAL; + } + + /* Both Rx and Tx are stopped */ + uec->grace_stopped_rx = 1; + uec->grace_stopped_tx = 1; + + /* Init UCC fast */ + if (ucc_fast_init(uf_info, &uccf)) { + printf("%s: failed to init ucc fast\n", __func__); + return -ENOMEM; + } + + /* Save uccf */ + uec->uccf = uccf; + + /* Convert the Tx threads number */ + if (uec_convert_threads_num(uec_info->num_threads_tx, + &num_threads_tx)) + return -EINVAL; + + /* Convert the Rx threads number */ + if (uec_convert_threads_num(uec_info->num_threads_rx, + &num_threads_rx)) + return -EINVAL; + + uf_regs = uccf->uf_regs; + + /* UEC register is following UCC fast registers */ + uec_regs = (uec_t *)(&uf_regs->ucc_eth); + + /* Save the UEC register pointer to UEC private struct */ + uec->uec_regs = uec_regs; + + /* Init UPSMR, enable hardware statistics (UCC) */ + out_be32(&uec->uccf->uf_regs->upsmr, UPSMR_INIT_VALUE); + + /* Init MACCFG1, flow control disable, disable Tx and Rx */ + out_be32(&uec_regs->maccfg1, MACCFG1_INIT_VALUE); + + /* Init MACCFG2, length check, MAC PAD and CRC enable */ + out_be32(&uec_regs->maccfg2, MACCFG2_INIT_VALUE); + + /* Setup UTBIPAR */ + utbipar = in_be32(&uec_regs->utbipar); + utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK; + + /* Initialize UTBIPAR address to CONFIG_UTBIPAR_INIT_TBIPA for ALL UEC. + * This frees up the remaining SMI addresses for use. + */ + utbipar |= CONFIG_UTBIPAR_INIT_TBIPA << UTBIPAR_PHY_ADDRESS_SHIFT; + out_be32(&uec_regs->utbipar, utbipar); + + /* Allocate Tx BDs */ + length = ((uec_info->tx_bd_ring_len * SIZEOFBD) / + UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT) * + UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT; + if ((uec_info->tx_bd_ring_len * SIZEOFBD) % + UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT) + length += UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT; + + align = UEC_TX_BD_RING_ALIGNMENT; + uec->tx_bd_ring_offset = (u32)malloc((u32)(length + align)); + if (uec->tx_bd_ring_offset != 0) + uec->p_tx_bd_ring = (u8 *)((uec->tx_bd_ring_offset + align) + & ~(align - 1)); + + /* Zero all of Tx BDs */ + memset((void *)(uec->tx_bd_ring_offset), 0, length + align); + + /* Allocate Rx BDs */ + length = uec_info->rx_bd_ring_len * SIZEOFBD; + align = UEC_RX_BD_RING_ALIGNMENT; + uec->rx_bd_ring_offset = (u32)(malloc((u32)(length + align))); + if (uec->rx_bd_ring_offset != 0) + uec->p_rx_bd_ring = (u8 *)((uec->rx_bd_ring_offset + align) + & ~(align - 1)); + + /* Zero all of Rx BDs */ + memset((void *)(uec->rx_bd_ring_offset), 0, length + align); + + /* Allocate Rx buffer */ + length = uec_info->rx_bd_ring_len * MAX_RXBUF_LEN; + align = UEC_RX_DATA_BUF_ALIGNMENT; + uec->rx_buf_offset = (u32)malloc(length + align); + if (uec->rx_buf_offset != 0) + uec->p_rx_buf = (u8 *)((uec->rx_buf_offset + align) + & ~(align - 1)); + + /* Zero all of the Rx buffer */ + memset((void *)(uec->rx_buf_offset), 0, length + align); + + /* Init TxBD ring */ + bd = (struct buffer_descriptor *)uec->p_tx_bd_ring; + uec->tx_bd = bd; + + for (i = 0; i < uec_info->tx_bd_ring_len; i++) { + BD_DATA_CLEAR(bd); + BD_STATUS_SET(bd, 0); + BD_LENGTH_SET(bd, 0); + bd++; + } + BD_STATUS_SET((--bd), TX_BD_WRAP); + + /* Init RxBD ring */ + bd = (struct buffer_descriptor *)uec->p_rx_bd_ring; + uec->rx_bd = bd; + buf = uec->p_rx_buf; + for (i = 0; i < uec_info->rx_bd_ring_len; i++) { + BD_DATA_SET(bd, buf); + BD_LENGTH_SET(bd, 0); + BD_STATUS_SET(bd, RX_BD_EMPTY); + buf += MAX_RXBUF_LEN; + bd++; + } + BD_STATUS_SET((--bd), RX_BD_WRAP | RX_BD_EMPTY); + + /* Init global Tx parameter RAM */ + uec_init_tx_parameter(uec, num_threads_tx); + + /* Init global Rx parameter RAM */ + uec_init_rx_parameter(uec, num_threads_rx); + + /* Init ethernet Tx and Rx parameter command */ + if (uec_issue_init_enet_rxtx_cmd(uec, num_threads_tx, + num_threads_rx)) { + printf("%s issue init enet cmd failed\n", __func__); + return -ENOMEM; + } + return 0; +} + +/* Convert a string to a QE clock source enum + * + * This function takes a string, typically from a property in the device + * tree, and returns the corresponding "enum qe_clock" value. + */ +enum qe_clock qe_clock_source(const char *source) +{ + unsigned int i; + + if (strcasecmp(source, "none") == 0) + return QE_CLK_NONE; + + if (strncasecmp(source, "brg", 3) == 0) { + i = simple_strtoul(source + 3, NULL, 10); + if (i >= 1 && i <= 16) + return (QE_BRG1 - 1) + i; + else + return QE_CLK_DUMMY; + } + + if (strncasecmp(source, "clk", 3) == 0) { + i = simple_strtoul(source + 3, NULL, 10); + if (i >= 1 && i <= 24) + return (QE_CLK1 - 1) + i; + else + return QE_CLK_DUMMY; + } + + return QE_CLK_DUMMY; +} + +static void qe_uec_set_eth_type(struct udevice *dev) +{ + struct qe_uec_priv *priv = dev_get_priv(dev); + struct uec_priv *uec = priv->uec; + struct uec_inf *uec_info = uec->uec_info; + struct ucc_fast_inf *uf_info = &uec_info->uf_info; + + switch (uec_info->enet_interface_type) { + case PHY_INTERFACE_MODE_GMII: + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_TBI: + case PHY_INTERFACE_MODE_RTBI: + case PHY_INTERFACE_MODE_SGMII: + uf_info->eth_type = GIGA_ETH; + break; + default: + uf_info->eth_type = FAST_ETH; + break; + } +} + +static int qe_uec_set_uec_info(struct udevice *dev) +{ + struct qe_uec_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + struct uec_priv *uec = priv->uec; + struct uec_inf *uec_info; + struct ucc_fast_inf *uf_info; + const char *s; + int ret; + u32 val; + + uec_info = (struct uec_inf *)malloc(sizeof(struct uec_inf)); + if (!uec_info) + return -ENOMEM; + + uf_info = &uec_info->uf_info; + + ret = dev_read_u32(dev, "cell-index", &val); + if (ret) { + ret = dev_read_u32(dev, "device-id", &val); + if (ret) { + pr_err("no cell-index nor device-id found!"); + goto out; + } + } + + uf_info->ucc_num = val - 1; + if (uf_info->ucc_num < 0 || uf_info->ucc_num > 7) { + ret = -ENODEV; + goto out; + } + + ret = dev_read_string_index(dev, "rx-clock-name", 0, &s); + if (!ret) { + uf_info->rx_clock = qe_clock_source(s); + if (uf_info->rx_clock < QE_CLK_NONE || + uf_info->rx_clock > QE_CLK24) { + pr_err("invalid rx-clock-name property\n"); + ret = -EINVAL; + goto out; + } + } else { + ret = dev_read_u32(dev, "rx-clock", &val); + if (ret) { + /* + * If both rx-clock-name and rx-clock are missing, + * we want to tell people to use rx-clock-name. + */ + pr_err("missing rx-clock-name property\n"); + goto out; + } + if (val < QE_CLK_NONE || val > QE_CLK24) { + pr_err("invalid rx-clock property\n"); + ret = -EINVAL; + goto out; + } + uf_info->rx_clock = val; + } + + ret = dev_read_string_index(dev, "tx-clock-name", 0, &s); + if (!ret) { + uf_info->tx_clock = qe_clock_source(s); + if (uf_info->tx_clock < QE_CLK_NONE || + uf_info->tx_clock > QE_CLK24) { + pr_err("invalid tx-clock-name property\n"); + ret = -EINVAL; + goto out; + } + } else { + ret = dev_read_u32(dev, "tx-clock", &val); + if (ret) { + pr_err("missing tx-clock-name property\n"); + goto out; + } + if (val < QE_CLK_NONE || val > QE_CLK24) { + pr_err("invalid tx-clock property\n"); + ret = -EINVAL; + goto out; + } + uf_info->tx_clock = val; + } + + uec_info->num_threads_tx = UEC_NUM_OF_THREADS_1; + uec_info->num_threads_rx = UEC_NUM_OF_THREADS_1; + uec_info->risc_tx = QE_RISC_ALLOCATION_RISC1_AND_RISC2; + uec_info->risc_rx = QE_RISC_ALLOCATION_RISC1_AND_RISC2; + uec_info->tx_bd_ring_len = 16; + uec_info->rx_bd_ring_len = 16; +#if (MAX_QE_RISC == 4) + uec_info->risc_tx = QE_RISC_ALLOCATION_FOUR_RISCS; + uec_info->risc_rx = QE_RISC_ALLOCATION_FOUR_RISCS; +#endif + + uec_info->enet_interface_type = pdata->phy_interface; + + uec->uec_info = uec_info; + qe_uec_set_eth_type(dev); + + return 0; +out: + free(uec_info); + return ret; +} + +static int qe_uec_probe(struct udevice *dev) +{ + struct qe_uec_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + struct uec_priv *uec; + int ret; + + /* Allocate the UEC private struct */ + uec = (struct uec_priv *)malloc(sizeof(struct uec_priv)); + if (!uec) + return -ENOMEM; + + memset(uec, 0, sizeof(struct uec_priv)); + priv->uec = uec; + uec->uec_regs = (uec_t *)pdata->iobase; + + /* setup uec info struct */ + ret = qe_uec_set_uec_info(dev); + if (ret) { + free(uec); + return ret; + } + + ret = uec_startup(dev); + if (ret) { + free(uec->uec_info); + free(uec); + return ret; + } + + priv->phydev = dm_eth_phy_connect(dev); + return 0; +} + +/* + * Remove the driver from an interface: + * - free up allocated memory + */ +static int qe_uec_remove(struct udevice *dev) +{ + struct qe_uec_priv *priv = dev_get_priv(dev); + + free(priv->uec); + return 0; +} + +static int qe_uec_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + const char *phy_mode; + + pdata->iobase = (phys_addr_t)devfdt_get_addr(dev); + + pdata->phy_interface = -1; + phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), + "phy-connection-type", NULL); + if (phy_mode) + pdata->phy_interface = phy_get_interface_by_name(phy_mode); + if (pdata->phy_interface == -1) { + debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); + return -EINVAL; + } + + return 0; +} + +static const struct udevice_id qe_uec_ids[] = { + { .compatible = QE_UEC_DRIVER_NAME }, + { } +}; + +U_BOOT_DRIVER(eth_qe_uec) = { + .name = QE_UEC_DRIVER_NAME, + .id = UCLASS_ETH, + .of_match = qe_uec_ids, + .ofdata_to_platdata = qe_uec_ofdata_to_platdata, + .probe = qe_uec_probe, + .remove = qe_uec_remove, + .ops = &qe_uec_eth_ops, + .priv_auto_alloc_size = sizeof(struct qe_uec_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/drivers/net/qe/dm_qe_uec.h b/drivers/net/qe/dm_qe_uec.h new file mode 100644 index 0000000000..690093caa2 --- /dev/null +++ b/drivers/net/qe/dm_qe_uec.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * QE UEC ethernet controller driver + * + * based on drivers/qe/uec.c from NXP + * + * Copyright (C) 2020 Heiko Schocher + */ + +#ifndef _DM_QE_UEC_H +#define _DM_QE_UEC_H + +#define qe_uec_dbg(dev, fmt, args...) debug("%s:" fmt, dev->name, ##args) + +#include "uec.h" + +/* QE UEC private structure */ +struct qe_uec_priv { + struct uec_priv *uec; + struct phy_device *phydev; +}; +#endif diff --git a/drivers/net/qe/dm_qe_uec_phy.c b/drivers/net/qe/dm_qe_uec_phy.c new file mode 100644 index 0000000000..02ce08edad --- /dev/null +++ b/drivers/net/qe/dm_qe_uec_phy.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * QE UEC ethernet phy controller driver + * + * based on phy parts of drivers/qe/uec.c and drivers/qe/uec_phy.c + * from NXP + * + * Copyright (C) 2020 Heiko Schocher + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "dm_qe_uec.h" + +struct qe_uec_mdio_priv { + struct ucc_mii_mng *base; +}; + +static int +qe_uec_mdio_read(struct udevice *dev, int addr, int devad, int reg) +{ + struct qe_uec_mdio_priv *priv = dev_get_priv(dev); + struct ucc_mii_mng *regs = priv->base; + u32 tmp_reg; + u16 value; + + debug("%s: regs: %p addr: %x devad: %x reg: %x\n", __func__, regs, + addr, devad, reg); + /* Setting up the MII management Address Register */ + tmp_reg = ((u32)addr << MIIMADD_PHY_ADDRESS_SHIFT) | reg; + out_be32(®s->miimadd, tmp_reg); + + /* clear MII management command cycle */ + out_be32(®s->miimcom, 0); + sync(); + + /* Perform an MII management read cycle */ + out_be32(®s->miimcom, MIIMCOM_READ_CYCLE); + + /* Wait till MII management write is complete */ + while ((in_be32(®s->miimind)) & + (MIIMIND_NOT_VALID | MIIMIND_BUSY)) + ; + + /* Read MII management status */ + value = (u16)in_be32(®s->miimstat); + if (value == 0xffff) + return -EINVAL; + + return value; +}; + +static int +qe_uec_mdio_write(struct udevice *dev, int addr, int devad, int reg, + u16 value) +{ + struct qe_uec_mdio_priv *priv = dev_get_priv(dev); + struct ucc_mii_mng *regs = priv->base; + u32 tmp_reg; + + debug("%s: regs: %p addr: %x devad: %x reg: %x val: %x\n", __func__, + regs, addr, devad, reg, value); + + /* Stop the MII management read cycle */ + out_be32(®s->miimcom, 0); + /* Setting up the MII management Address Register */ + tmp_reg = ((u32)addr << MIIMADD_PHY_ADDRESS_SHIFT) | reg; + out_be32(®s->miimadd, tmp_reg); + + /* Setting up the MII management Control Register with the value */ + out_be32(®s->miimcon, (u32)value); + sync(); + + /* Wait till MII management write is complete */ + while ((in_be32(®s->miimind)) & MIIMIND_BUSY) + ; + + return 0; +}; + +static const struct mdio_ops qe_uec_mdio_ops = { + .read = qe_uec_mdio_read, + .write = qe_uec_mdio_write, +}; + +static int qe_uec_mdio_probe(struct udevice *dev) +{ + struct qe_uec_mdio_priv *priv = dev_get_priv(dev); + fdt_size_t base; + ofnode node; + u32 num = 0; + int ret = -ENODEV; + + priv->base = (struct ucc_mii_mng *)dev_read_addr(dev); + base = (fdt_size_t)priv->base; + + /* + * idea from linux: + * drivers/net/ethernet/freescale/fsl_pq_mdio.c + * + * Find the UCC node that controls the given MDIO node + * + * For some reason, the QE MDIO nodes are not children of the UCC + * devices that control them. Therefore, we need to scan all UCC + * nodes looking for the one that encompases the given MDIO node. + * We do this by comparing physical addresses. The 'start' and + * 'end' addresses of the MDIO node are passed, and the correct + * UCC node will cover the entire address range. + */ + node = ofnode_by_compatible(ofnode_null(), "ucc_geth"); + while (ofnode_valid(node)) { + fdt_size_t size; + fdt_addr_t addr; + + addr = ofnode_get_addr_index(node, 0); + ret = ofnode_get_addr_size_index(node, 0, &size); + + if (addr == FDT_ADDR_T_NONE) { + node = ofnode_by_compatible(node, "ucc_geth"); + continue; + } + + /* check if priv->base in start end */ + if (base > addr && base < (addr + size)) { + ret = ofnode_read_u32(node, "cell-index", &num); + if (ret) + ret = ofnode_read_u32(node, "device-id", + &num); + break; + } + node = ofnode_by_compatible(node, "ucc_geth"); + } + + if (ret) { + printf("%s: no cell-index nor device-id found!", __func__); + return ret; + } + + /* Setup MII master clock source */ + qe_set_mii_clk_src(num - 1); + + return 0; +} + +static const struct udevice_id qe_uec_mdio_ids[] = { + { .compatible = "fsl,ucc-mdio" }, + { } +}; + +U_BOOT_DRIVER(mvmdio) = { + .name = "qe_uec_mdio", + .id = UCLASS_MDIO, + .of_match = qe_uec_mdio_ids, + .probe = qe_uec_mdio_probe, + .ops = &qe_uec_mdio_ops, + .priv_auto_alloc_size = sizeof(struct qe_uec_mdio_priv), +}; diff --git a/drivers/net/qe/uccf.c b/drivers/net/qe/uccf.c new file mode 100644 index 0000000000..306f1ea1db --- /dev/null +++ b/drivers/net/qe/uccf.c @@ -0,0 +1,507 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2006 Freescale Semiconductor, Inc. + * + * Dave Liu + * based on source code of Shlomi Gridish + */ + +#include +#include +#include +#include +#include +#include "uccf.h" +#include + +void ucc_fast_transmit_on_demand(struct ucc_fast_priv *uccf) +{ + out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD); +} + +u32 ucc_fast_get_qe_cr_subblock(int ucc_num) +{ + switch (ucc_num) { + case 0: + return QE_CR_SUBBLOCK_UCCFAST1; + case 1: + return QE_CR_SUBBLOCK_UCCFAST2; + case 2: + return QE_CR_SUBBLOCK_UCCFAST3; + case 3: + return QE_CR_SUBBLOCK_UCCFAST4; + case 4: + return QE_CR_SUBBLOCK_UCCFAST5; + case 5: + return QE_CR_SUBBLOCK_UCCFAST6; + case 6: + return QE_CR_SUBBLOCK_UCCFAST7; + case 7: + return QE_CR_SUBBLOCK_UCCFAST8; + default: + return QE_CR_SUBBLOCK_INVALID; + } +} + +static void ucc_get_cmxucr_reg(int ucc_num, u32 **p_cmxucr, + u8 *reg_num, u8 *shift) +{ + switch (ucc_num) { + case 0: /* UCC1 */ + *p_cmxucr = &qe_immr->qmx.cmxucr1; + *reg_num = 1; + *shift = 16; + break; + case 2: /* UCC3 */ + *p_cmxucr = &qe_immr->qmx.cmxucr1; + *reg_num = 1; + *shift = 0; + break; + case 4: /* UCC5 */ + *p_cmxucr = &qe_immr->qmx.cmxucr2; + *reg_num = 2; + *shift = 16; + break; + case 6: /* UCC7 */ + *p_cmxucr = &qe_immr->qmx.cmxucr2; + *reg_num = 2; + *shift = 0; + break; + case 1: /* UCC2 */ + *p_cmxucr = &qe_immr->qmx.cmxucr3; + *reg_num = 3; + *shift = 16; + break; + case 3: /* UCC4 */ + *p_cmxucr = &qe_immr->qmx.cmxucr3; + *reg_num = 3; + *shift = 0; + break; + case 5: /* UCC6 */ + *p_cmxucr = &qe_immr->qmx.cmxucr4; + *reg_num = 4; + *shift = 16; + break; + case 7: /* UCC8 */ + *p_cmxucr = &qe_immr->qmx.cmxucr4; + *reg_num = 4; + *shift = 0; + break; + default: + break; + } +} + +static int ucc_set_clk_src(int ucc_num, qe_clock_e clock, comm_dir_e mode) +{ + u32 *p_cmxucr = NULL; + u8 reg_num = 0; + u8 shift = 0; + u32 clk_bits; + u32 clk_mask; + int source = -1; + + /* check if the UCC number is in range. */ + if ((ucc_num > UCC_MAX_NUM - 1) || ucc_num < 0) + return -EINVAL; + + if (!(mode == COMM_DIR_RX || mode == COMM_DIR_TX)) { + printf("%s: bad comm mode type passed\n", __func__); + return -EINVAL; + } + + ucc_get_cmxucr_reg(ucc_num, &p_cmxucr, ®_num, &shift); + + switch (reg_num) { + case 1: + switch (clock) { + case QE_BRG1: + source = 1; + break; + case QE_BRG2: + source = 2; + break; + case QE_BRG7: + source = 3; + break; + case QE_BRG8: + source = 4; + break; + case QE_CLK9: + source = 5; + break; + case QE_CLK10: + source = 6; + break; + case QE_CLK11: + source = 7; + break; + case QE_CLK12: + source = 8; + break; + case QE_CLK15: + source = 9; + break; + case QE_CLK16: + source = 10; + break; + default: + source = -1; + break; + } + break; + case 2: + switch (clock) { + case QE_BRG5: + source = 1; + break; + case QE_BRG6: + source = 2; + break; + case QE_BRG7: + source = 3; + break; + case QE_BRG8: + source = 4; + break; + case QE_CLK13: + source = 5; + break; + case QE_CLK14: + source = 6; + break; + case QE_CLK19: + source = 7; + break; + case QE_CLK20: + source = 8; + break; + case QE_CLK15: + source = 9; + break; + case QE_CLK16: + source = 10; + break; + default: + source = -1; + break; + } + break; + case 3: + switch (clock) { + case QE_BRG9: + source = 1; + break; + case QE_BRG10: + source = 2; + break; + case QE_BRG15: + source = 3; + break; + case QE_BRG16: + source = 4; + break; + case QE_CLK3: + source = 5; + break; + case QE_CLK4: + source = 6; + break; + case QE_CLK17: + source = 7; + break; + case QE_CLK18: + source = 8; + break; + case QE_CLK7: + source = 9; + break; + case QE_CLK8: + source = 10; + break; + case QE_CLK16: + source = 11; + break; + default: + source = -1; + break; + } + break; + case 4: + switch (clock) { + case QE_BRG13: + source = 1; + break; + case QE_BRG14: + source = 2; + break; + case QE_BRG15: + source = 3; + break; + case QE_BRG16: + source = 4; + break; + case QE_CLK5: + source = 5; + break; + case QE_CLK6: + source = 6; + break; + case QE_CLK21: + source = 7; + break; + case QE_CLK22: + source = 8; + break; + case QE_CLK7: + source = 9; + break; + case QE_CLK8: + source = 10; + break; + case QE_CLK16: + source = 11; + break; + default: + source = -1; + break; + } + break; + default: + source = -1; + break; + } + + if (source == -1) { + printf("%s: Bad combination of clock and UCC\n", __func__); + return -ENOENT; + } + + clk_bits = (u32)source; + clk_mask = QE_CMXUCR_TX_CLK_SRC_MASK; + if (mode == COMM_DIR_RX) { + clk_bits <<= 4; /* Rx field is 4 bits to left of Tx field */ + clk_mask <<= 4; /* Rx field is 4 bits to left of Tx field */ + } + clk_bits <<= shift; + clk_mask <<= shift; + + out_be32(p_cmxucr, (in_be32(p_cmxucr) & ~clk_mask) | clk_bits); + + return 0; +} + +static uint ucc_get_reg_baseaddr(int ucc_num) +{ + uint base = 0; + + /* check if the UCC number is in range */ + if ((ucc_num > UCC_MAX_NUM - 1) || ucc_num < 0) { + printf("%s: the UCC num not in ranges\n", __func__); + return 0; + } + + switch (ucc_num) { + case 0: + base = 0x00002000; + break; + case 1: + base = 0x00003000; + break; + case 2: + base = 0x00002200; + break; + case 3: + base = 0x00003200; + break; + case 4: + base = 0x00002400; + break; + case 5: + base = 0x00003400; + break; + case 6: + base = 0x00002600; + break; + case 7: + base = 0x00003600; + break; + default: + break; + } + + base = (uint)qe_immr + base; + return base; +} + +void ucc_fast_enable(struct ucc_fast_priv *uccf, comm_dir_e mode) +{ + ucc_fast_t *uf_regs; + u32 gumr; + + uf_regs = uccf->uf_regs; + + /* Enable reception and/or transmission on this UCC. */ + gumr = in_be32(&uf_regs->gumr); + if (mode & COMM_DIR_TX) { + gumr |= UCC_FAST_GUMR_ENT; + uccf->enabled_tx = 1; + } + if (mode & COMM_DIR_RX) { + gumr |= UCC_FAST_GUMR_ENR; + uccf->enabled_rx = 1; + } + out_be32(&uf_regs->gumr, gumr); +} + +void ucc_fast_disable(struct ucc_fast_priv *uccf, comm_dir_e mode) +{ + ucc_fast_t *uf_regs; + u32 gumr; + + uf_regs = uccf->uf_regs; + + /* Disable reception and/or transmission on this UCC. */ + gumr = in_be32(&uf_regs->gumr); + if (mode & COMM_DIR_TX) { + gumr &= ~UCC_FAST_GUMR_ENT; + uccf->enabled_tx = 0; + } + if (mode & COMM_DIR_RX) { + gumr &= ~UCC_FAST_GUMR_ENR; + uccf->enabled_rx = 0; + } + out_be32(&uf_regs->gumr, gumr); +} + +int ucc_fast_init(struct ucc_fast_inf *uf_info, + struct ucc_fast_priv **uccf_ret) +{ + struct ucc_fast_priv *uccf; + ucc_fast_t *uf_regs; + + if (!uf_info) + return -EINVAL; + + if (uf_info->ucc_num < 0 || (uf_info->ucc_num > UCC_MAX_NUM - 1)) { + printf("%s: Illagal UCC number!\n", __func__); + return -EINVAL; + } + + uccf = (struct ucc_fast_priv *)malloc(sizeof(struct ucc_fast_priv)); + if (!uccf) { + printf("%s: No memory for UCC fast data structure!\n", + __func__); + return -ENOMEM; + } + memset(uccf, 0, sizeof(struct ucc_fast_priv)); + + /* Save fast UCC structure */ + uccf->uf_info = uf_info; + uccf->uf_regs = (ucc_fast_t *)ucc_get_reg_baseaddr(uf_info->ucc_num); + + if (!uccf->uf_regs) { + printf("%s: No memory map for UCC fast controller!\n", + __func__); + return -ENOMEM; + } + + uccf->enabled_tx = 0; + uccf->enabled_rx = 0; + + uf_regs = uccf->uf_regs; + uccf->p_ucce = (u32 *)&uf_regs->ucce; + uccf->p_uccm = (u32 *)&uf_regs->uccm; + + /* Init GUEMR register, UCC both Rx and Tx is Fast protocol */ + out_8(&uf_regs->guemr, UCC_GUEMR_SET_RESERVED3 | UCC_GUEMR_MODE_FAST_RX + | UCC_GUEMR_MODE_FAST_TX); + + /* Set GUMR, disable UCC both Rx and Tx, Ethernet protocol */ + out_be32(&uf_regs->gumr, UCC_FAST_GUMR_ETH); + + /* Set the Giga ethernet VFIFO stuff */ + if (uf_info->eth_type == GIGA_ETH) { + /* Allocate memory for Tx Virtual Fifo */ + uccf->ucc_fast_tx_virtual_fifo_base_offset = + qe_muram_alloc(UCC_GETH_UTFS_GIGA_INIT, + UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); + + /* Allocate memory for Rx Virtual Fifo */ + uccf->ucc_fast_rx_virtual_fifo_base_offset = + qe_muram_alloc(UCC_GETH_URFS_GIGA_INIT + + UCC_FAST_RX_VIRTUAL_FIFO_SIZE_PAD, + UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); + + /* utfb, urfb are offsets from MURAM base */ + out_be32(&uf_regs->utfb, + uccf->ucc_fast_tx_virtual_fifo_base_offset); + out_be32(&uf_regs->urfb, + uccf->ucc_fast_rx_virtual_fifo_base_offset); + + /* Set Virtual Fifo registers */ + out_be16(&uf_regs->urfs, UCC_GETH_URFS_GIGA_INIT); + out_be16(&uf_regs->urfet, UCC_GETH_URFET_GIGA_INIT); + out_be16(&uf_regs->urfset, UCC_GETH_URFSET_GIGA_INIT); + out_be16(&uf_regs->utfs, UCC_GETH_UTFS_GIGA_INIT); + out_be16(&uf_regs->utfet, UCC_GETH_UTFET_GIGA_INIT); + out_be16(&uf_regs->utftt, UCC_GETH_UTFTT_GIGA_INIT); + } + + /* Set the Fast ethernet VFIFO stuff */ + if (uf_info->eth_type == FAST_ETH) { + /* Allocate memory for Tx Virtual Fifo */ + uccf->ucc_fast_tx_virtual_fifo_base_offset = + qe_muram_alloc(UCC_GETH_UTFS_INIT, + UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); + + /* Allocate memory for Rx Virtual Fifo */ + uccf->ucc_fast_rx_virtual_fifo_base_offset = + qe_muram_alloc(UCC_GETH_URFS_INIT + + UCC_FAST_RX_VIRTUAL_FIFO_SIZE_PAD, + UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); + + /* utfb, urfb are offsets from MURAM base */ + out_be32(&uf_regs->utfb, + uccf->ucc_fast_tx_virtual_fifo_base_offset); + out_be32(&uf_regs->urfb, + uccf->ucc_fast_rx_virtual_fifo_base_offset); + + /* Set Virtual Fifo registers */ + out_be16(&uf_regs->urfs, UCC_GETH_URFS_INIT); + out_be16(&uf_regs->urfet, UCC_GETH_URFET_INIT); + out_be16(&uf_regs->urfset, UCC_GETH_URFSET_INIT); + out_be16(&uf_regs->utfs, UCC_GETH_UTFS_INIT); + out_be16(&uf_regs->utfet, UCC_GETH_UTFET_INIT); + out_be16(&uf_regs->utftt, UCC_GETH_UTFTT_INIT); + } + + /* Rx clock routing */ + if (uf_info->rx_clock != QE_CLK_NONE) { + if (ucc_set_clk_src(uf_info->ucc_num, + uf_info->rx_clock, COMM_DIR_RX)) { + printf("%s: Illegal value for parameter 'RxClock'.\n", + __func__); + return -EINVAL; + } + } + + /* Tx clock routing */ + if (uf_info->tx_clock != QE_CLK_NONE) { + if (ucc_set_clk_src(uf_info->ucc_num, + uf_info->tx_clock, COMM_DIR_TX)) { + printf("%s: Illegal value for parameter 'TxClock'.\n", + __func__); + return -EINVAL; + } + } + + /* Clear interrupt mask register to disable all of interrupts */ + out_be32(&uf_regs->uccm, 0x0); + + /* Writing '1' to clear all of envents */ + out_be32(&uf_regs->ucce, 0xffffffff); + + *uccf_ret = uccf; + return 0; +} diff --git a/drivers/net/qe/uccf.h b/drivers/net/qe/uccf.h new file mode 100644 index 0000000000..99f8458edf --- /dev/null +++ b/drivers/net/qe/uccf.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2006 Freescale Semiconductor, Inc. + * + * Dave Liu + * based on source code of Shlomi Gridish + */ + +#ifndef __UCCF_H__ +#define __UCCF_H__ + +#include "common.h" +#include "linux/immap_qe.h" +#include + +/* Fast or Giga ethernet */ +enum enet_type { + FAST_ETH, + GIGA_ETH, +}; + +/* General UCC Extended Mode Register */ +#define UCC_GUEMR_MODE_MASK_RX 0x02 +#define UCC_GUEMR_MODE_MASK_TX 0x01 +#define UCC_GUEMR_MODE_FAST_RX 0x02 +#define UCC_GUEMR_MODE_FAST_TX 0x01 +#define UCC_GUEMR_MODE_SLOW_RX 0x00 +#define UCC_GUEMR_MODE_SLOW_TX 0x00 +/* Bit 3 must be set 1 */ +#define UCC_GUEMR_SET_RESERVED3 0x10 + +/* General UCC FAST Mode Register */ +#define UCC_FAST_GUMR_TCI 0x20000000 +#define UCC_FAST_GUMR_TRX 0x10000000 +#define UCC_FAST_GUMR_TTX 0x08000000 +#define UCC_FAST_GUMR_CDP 0x04000000 +#define UCC_FAST_GUMR_CTSP 0x02000000 +#define UCC_FAST_GUMR_CDS 0x01000000 +#define UCC_FAST_GUMR_CTSS 0x00800000 +#define UCC_FAST_GUMR_TXSY 0x00020000 +#define UCC_FAST_GUMR_RSYN 0x00010000 +#define UCC_FAST_GUMR_RTSM 0x00002000 +#define UCC_FAST_GUMR_REVD 0x00000400 +#define UCC_FAST_GUMR_ENR 0x00000020 +#define UCC_FAST_GUMR_ENT 0x00000010 + +/* GUMR [MODE] bit maps */ +#define UCC_FAST_GUMR_HDLC 0x00000000 +#define UCC_FAST_GUMR_QMC 0x00000002 +#define UCC_FAST_GUMR_UART 0x00000004 +#define UCC_FAST_GUMR_BISYNC 0x00000008 +#define UCC_FAST_GUMR_ATM 0x0000000a +#define UCC_FAST_GUMR_ETH 0x0000000c + +/* Transmit On Demand (UTORD) */ +#define UCC_SLOW_TOD 0x8000 +#define UCC_FAST_TOD 0x8000 + +/* Fast Ethernet (10/100 Mbps) */ +/* Rx virtual FIFO size */ +#define UCC_GETH_URFS_INIT 512 +/* 1/2 urfs */ +#define UCC_GETH_URFET_INIT 256 +/* 3/4 urfs */ +#define UCC_GETH_URFSET_INIT 384 +/* Tx virtual FIFO size */ +#define UCC_GETH_UTFS_INIT 512 +/* 1/2 utfs */ +#define UCC_GETH_UTFET_INIT 256 +#define UCC_GETH_UTFTT_INIT 128 + +/* Gigabit Ethernet (1000 Mbps) */ +/* Rx virtual FIFO size */ +#define UCC_GETH_URFS_GIGA_INIT 4096/*2048*/ +/* 1/2 urfs */ +#define UCC_GETH_URFET_GIGA_INIT 2048/*1024*/ +/* 3/4 urfs */ +#define UCC_GETH_URFSET_GIGA_INIT 3072/*1536*/ +/* Tx virtual FIFO size */ +#define UCC_GETH_UTFS_GIGA_INIT 8192/*2048*/ +/* 1/2 utfs */ +#define UCC_GETH_UTFET_GIGA_INIT 4096/*1024*/ +#define UCC_GETH_UTFTT_GIGA_INIT 0x400/*0x40*/ + +/* UCC fast alignment */ +#define UCC_FAST_RX_ALIGN 4 +#define UCC_FAST_MRBLR_ALIGNMENT 4 +#define UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT 8 + +/* Sizes */ +#define UCC_FAST_RX_VIRTUAL_FIFO_SIZE_PAD 8 + +/* UCC fast structure. */ +struct ucc_fast_inf { + int ucc_num; + qe_clock_e rx_clock; + qe_clock_e tx_clock; + enum enet_type eth_type; +}; + +struct ucc_fast_priv { + struct ucc_fast_inf *uf_info; + ucc_fast_t *uf_regs; /* a pointer to memory map of UCC regs */ + u32 *p_ucce; /* a pointer to the event register */ + u32 *p_uccm; /* a pointer to the mask register */ + int enabled_tx; /* whether UCC is enabled for Tx (ENT) */ + int enabled_rx; /* whether UCC is enabled for Rx (ENR) */ + u32 ucc_fast_tx_virtual_fifo_base_offset; + u32 ucc_fast_rx_virtual_fifo_base_offset; +}; + +void ucc_fast_transmit_on_demand(struct ucc_fast_priv *uccf); +u32 ucc_fast_get_qe_cr_subblock(int ucc_num); +void ucc_fast_enable(struct ucc_fast_priv *uccf, comm_dir_e mode); +void ucc_fast_disable(struct ucc_fast_priv *uccf, comm_dir_e mode); +int ucc_fast_init(struct ucc_fast_inf *uf_info, + struct ucc_fast_priv **uccf_ret); + +#endif /* __UCCF_H__ */ diff --git a/drivers/net/qe/uec.h b/drivers/net/qe/uec.h new file mode 100644 index 0000000000..7cd4b8737a --- /dev/null +++ b/drivers/net/qe/uec.h @@ -0,0 +1,693 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2006-2010 Freescale Semiconductor, Inc. + * + * Dave Liu + * based on source code of Shlomi Gridish + */ + +#ifndef __UEC_H__ +#define __UEC_H__ + +#include "uccf.h" +#include +#include + +#define MAX_TX_THREADS 8 +#define MAX_RX_THREADS 8 +#define MAX_TX_QUEUES 8 +#define MAX_RX_QUEUES 8 +#define MAX_PREFETCHED_BDS 4 +#define MAX_IPH_OFFSET_ENTRY 8 +#define MAX_ENET_INIT_PARAM_ENTRIES_RX 9 +#define MAX_ENET_INIT_PARAM_ENTRIES_TX 8 + +/* UEC UPSMR (Protocol Specific Mode Register) + */ +#define UPSMR_ECM 0x04000000 /* Enable CAM Miss */ +#define UPSMR_HSE 0x02000000 /* Hardware Statistics Enable */ +#define UPSMR_PRO 0x00400000 /* Promiscuous */ +#define UPSMR_CAP 0x00200000 /* CAM polarity */ +#define UPSMR_RSH 0x00100000 /* Receive Short Frames */ +#define UPSMR_RPM 0x00080000 /* Reduced Pin Mode interfaces */ +#define UPSMR_R10M 0x00040000 /* RGMII/RMII 10 Mode */ +#define UPSMR_RLPB 0x00020000 /* RMII Loopback Mode */ +#define UPSMR_TBIM 0x00010000 /* Ten-bit Interface Mode */ +#define UPSMR_RMM 0x00001000 /* RMII/RGMII Mode */ +#define UPSMR_CAM 0x00000400 /* CAM Address Matching */ +#define UPSMR_BRO 0x00000200 /* Broadcast Address */ +#define UPSMR_RES1 0x00002000 /* Reserved feild - must be 1 */ +#define UPSMR_SGMM 0x00000020 /* SGMII mode */ + +#define UPSMR_INIT_VALUE (UPSMR_HSE | UPSMR_RES1) + +/* UEC MACCFG1 (MAC Configuration 1 Register) + */ +#define MACCFG1_FLOW_RX 0x00000020 /* Flow Control Rx */ +#define MACCFG1_FLOW_TX 0x00000010 /* Flow Control Tx */ +#define MACCFG1_ENABLE_SYNCHED_RX 0x00000008 /* Enable Rx Sync */ +#define MACCFG1_ENABLE_RX 0x00000004 /* Enable Rx */ +#define MACCFG1_ENABLE_SYNCHED_TX 0x00000002 /* Enable Tx Sync */ +#define MACCFG1_ENABLE_TX 0x00000001 /* Enable Tx */ + +#define MACCFG1_INIT_VALUE (0) + +/* UEC MACCFG2 (MAC Configuration 2 Register) + */ +#define MACCFG2_PREL 0x00007000 +#define MACCFG2_PREL_SHIFT (31 - 19) +#define MACCFG2_PREL_MASK 0x0000f000 +#define MACCFG2_SRP 0x00000080 +#define MACCFG2_STP 0x00000040 +#define MACCFG2_RESERVED_1 0x00000020 /* must be set */ +#define MACCFG2_LC 0x00000010 /* Length Check */ +#define MACCFG2_MPE 0x00000008 +#define MACCFG2_FDX 0x00000001 /* Full Duplex */ +#define MACCFG2_FDX_MASK 0x00000001 +#define MACCFG2_PAD_CRC 0x00000004 +#define MACCFG2_CRC_EN 0x00000002 +#define MACCFG2_PAD_AND_CRC_MODE_NONE 0x00000000 +#define MACCFG2_PAD_AND_CRC_MODE_CRC_ONLY 0x00000002 +#define MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC 0x00000004 +#define MACCFG2_INTERFACE_MODE_NIBBLE 0x00000100 +#define MACCFG2_INTERFACE_MODE_BYTE 0x00000200 +#define MACCFG2_INTERFACE_MODE_MASK 0x00000300 + +#define MACCFG2_INIT_VALUE (MACCFG2_PREL | MACCFG2_RESERVED_1 | \ + MACCFG2_LC | MACCFG2_PAD_CRC | MACCFG2_FDX) + +/* UEC Event Register */ +#define UCCE_MPD 0x80000000 +#define UCCE_SCAR 0x40000000 +#define UCCE_GRA 0x20000000 +#define UCCE_CBPR 0x10000000 +#define UCCE_BSY 0x08000000 +#define UCCE_RXC 0x04000000 +#define UCCE_TXC 0x02000000 +#define UCCE_TXE 0x01000000 +#define UCCE_TXB7 0x00800000 +#define UCCE_TXB6 0x00400000 +#define UCCE_TXB5 0x00200000 +#define UCCE_TXB4 0x00100000 +#define UCCE_TXB3 0x00080000 +#define UCCE_TXB2 0x00040000 +#define UCCE_TXB1 0x00020000 +#define UCCE_TXB0 0x00010000 +#define UCCE_RXB7 0x00008000 +#define UCCE_RXB6 0x00004000 +#define UCCE_RXB5 0x00002000 +#define UCCE_RXB4 0x00001000 +#define UCCE_RXB3 0x00000800 +#define UCCE_RXB2 0x00000400 +#define UCCE_RXB1 0x00000200 +#define UCCE_RXB0 0x00000100 +#define UCCE_RXF7 0x00000080 +#define UCCE_RXF6 0x00000040 +#define UCCE_RXF5 0x00000020 +#define UCCE_RXF4 0x00000010 +#define UCCE_RXF3 0x00000008 +#define UCCE_RXF2 0x00000004 +#define UCCE_RXF1 0x00000002 +#define UCCE_RXF0 0x00000001 + +#define UCCE_TXB (UCCE_TXB7 | UCCE_TXB6 | UCCE_TXB5 | UCCE_TXB4 | \ + UCCE_TXB3 | UCCE_TXB2 | UCCE_TXB1 | UCCE_TXB0) +#define UCCE_RXB (UCCE_RXB7 | UCCE_RXB6 | UCCE_RXB5 | UCCE_RXB4 | \ + UCCE_RXB3 | UCCE_RXB2 | UCCE_RXB1 | UCCE_RXB0) +#define UCCE_RXF (UCCE_RXF7 | UCCE_RXF6 | UCCE_RXF5 | UCCE_RXF4 | \ + UCCE_RXF3 | UCCE_RXF2 | UCCE_RXF1 | UCCE_RXF0) +#define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY | \ + UCCE_RXC | UCCE_TXC | UCCE_TXE) + +/* UEC TEMODR Register */ +#define TEMODER_SCHEDULER_ENABLE 0x2000 +#define TEMODER_IP_CHECKSUM_GENERATE 0x0400 +#define TEMODER_PERFORMANCE_OPTIMIZATION_MODE1 0x0200 +#define TEMODER_RMON_STATISTICS 0x0100 +#define TEMODER_NUM_OF_QUEUES_SHIFT (15 - 15) + +#define TEMODER_INIT_VALUE 0xc000 + +/* UEC REMODR Register */ +#define REMODER_RX_RMON_STATISTICS_ENABLE 0x00001000 +#define REMODER_RX_EXTENDED_FEATURES 0x80000000 +#define REMODER_VLAN_OPERATION_TAGGED_SHIFT (31 - 9) +#define REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT (31 - 10) +#define REMODER_RX_QOS_MODE_SHIFT (31 - 15) +#define REMODER_RMON_STATISTICS 0x00001000 +#define REMODER_RX_EXTENDED_FILTERING 0x00000800 +#define REMODER_NUM_OF_QUEUES_SHIFT (31 - 23) +#define REMODER_DYNAMIC_MAX_FRAME_LENGTH 0x00000008 +#define REMODER_DYNAMIC_MIN_FRAME_LENGTH 0x00000004 +#define REMODER_IP_CHECKSUM_CHECK 0x00000002 +#define REMODER_IP_ADDRESS_ALIGNMENT 0x00000001 + +#define REMODER_INIT_VALUE 0 + +/* BMRx - Bus Mode Register */ +#define BMR_GLB 0x20 +#define BMR_BO_BE 0x10 +#define BMR_DTB_SECONDARY_BUS 0x02 +#define BMR_BDB_SECONDARY_BUS 0x01 + +#define BMR_SHIFT 24 +#define BMR_INIT_VALUE (BMR_GLB | BMR_BO_BE) + +/* UEC UCCS (Ethernet Status Register) + */ +#define UCCS_BPR 0x02 +#define UCCS_PAU 0x02 +#define UCCS_MPD 0x01 + +/* UEC MIIMCFG (MII Management Configuration Register) + */ +#define MIIMCFG_RESET_MANAGEMENT 0x80000000 +#define MIIMCFG_NO_PREAMBLE 0x00000010 +#define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) +#define MIIMCFG_CLOCK_DIVIDE_MASK 0x0000000f +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007 + +#define MIIMCFG_MNGMNT_CLC_DIV_INIT_VALUE \ + MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 + +/* UEC MIIMCOM (MII Management Command Register) + */ +#define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */ +#define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */ + +/* UEC MIIMADD (MII Management Address Register) + */ +#define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) +#define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) + +/* UEC MIIMCON (MII Management Control Register) + */ +#define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) +#define MIIMCON_PHY_STATUS_SHIFT (31 - 31) + +/* UEC MIIMIND (MII Management Indicator Register) + */ +#define MIIMIND_NOT_VALID 0x00000004 +#define MIIMIND_SCAN 0x00000002 +#define MIIMIND_BUSY 0x00000001 + +/* UEC UTBIPAR (Ten Bit Interface Physical Address Register) + */ +#define UTBIPAR_PHY_ADDRESS_SHIFT (31 - 31) +#define UTBIPAR_PHY_ADDRESS_MASK 0x0000001f + +/* UEC UESCR (Ethernet Statistics Control Register) + */ +#define UESCR_AUTOZ 0x8000 +#define UESCR_CLRCNT 0x4000 +#define UESCR_MAXCOV_SHIFT (15 - 7) +#define UESCR_SCOV_SHIFT (15 - 15) + +/****** Tx data struct collection ******/ +/* Tx thread data, each Tx thread has one this struct. */ +struct uec_thread_data_tx { + u8 res0[136]; +} __packed; + +/* Tx thread parameter, each Tx thread has one this struct. */ +struct uec_thread_tx_pram { + u8 res0[64]; +} __packed; + +/* Send queue queue-descriptor, each Tx queue has one this QD */ +struct uec_send_queue_qd { + u32 bd_ring_base; /* pointer to BD ring base address */ + u8 res0[0x8]; + u32 last_bd_completed_address; /* last entry in BD ring */ + u8 res1[0x30]; +} __packed; + +/* Send queue memory region */ +struct uec_send_queue_mem_region { + struct uec_send_queue_qd sqqd[MAX_TX_QUEUES]; +} __packed; + +/* Scheduler struct */ +struct uec_scheduler { + u16 cpucount0; /* CPU packet counter */ + u16 cpucount1; /* CPU packet counter */ + u16 cecount0; /* QE packet counter */ + u16 cecount1; /* QE packet counter */ + u16 cpucount2; /* CPU packet counter */ + u16 cpucount3; /* CPU packet counter */ + u16 cecount2; /* QE packet counter */ + u16 cecount3; /* QE packet counter */ + u16 cpucount4; /* CPU packet counter */ + u16 cpucount5; /* CPU packet counter */ + u16 cecount4; /* QE packet counter */ + u16 cecount5; /* QE packet counter */ + u16 cpucount6; /* CPU packet counter */ + u16 cpucount7; /* CPU packet counter */ + u16 cecount6; /* QE packet counter */ + u16 cecount7; /* QE packet counter */ + u32 weightstatus[MAX_TX_QUEUES]; /* accumulated weight factor */ + u32 rtsrshadow; /* temporary variable handled by QE */ + u32 time; /* temporary variable handled by QE */ + u32 ttl; /* temporary variable handled by QE */ + u32 mblinterval; /* max burst length interval */ + u16 nortsrbytetime; /* normalized value of byte time in tsr units */ + u8 fracsiz; + u8 res0[1]; + u8 strictpriorityq; /* Strict Priority Mask register */ + u8 txasap; /* Transmit ASAP register */ + u8 extrabw; /* Extra BandWidth register */ + u8 oldwfqmask; /* temporary variable handled by QE */ + u8 weightfactor[MAX_TX_QUEUES]; /**< weight factor for queues */ + u32 minw; /* temporary variable handled by QE */ + u8 res1[0x70 - 0x64]; +} __packed; + +/* Tx firmware counters */ +struct uec_tx_firmware_statistics_pram { + u32 sicoltx; /* single collision */ + u32 mulcoltx; /* multiple collision */ + u32 latecoltxfr; /* late collision */ + u32 frabortduecol; /* frames aborted due to tx collision */ + u32 frlostinmactxer; /* frames lost due to internal MAC error tx */ + u32 carriersenseertx; /* carrier sense error */ + u32 frtxok; /* frames transmitted OK */ + u32 txfrexcessivedefer; + u32 txpkts256; /* total packets(including bad) 256~511 B */ + u32 txpkts512; /* total packets(including bad) 512~1023B */ + u32 txpkts1024; /* total packets(including bad) 1024~1518B */ + u32 txpktsjumbo; /* total packets(including bad) >1024 */ +} __packed; + +/* Tx global parameter table */ +struct uec_tx_global_pram { + u16 temoder; + u8 res0[0x38 - 0x02]; + u32 sqptr; + u32 schedulerbasepointer; + u32 txrmonbaseptr; + u32 tstate; + u8 iphoffset[MAX_IPH_OFFSET_ENTRY]; + u32 vtagtable[0x8]; + u32 tqptr; + u8 res2[0x80 - 0x74]; +} __packed; + +/****** Rx data struct collection ******/ +/* Rx thread data, each Rx thread has one this struct. */ +struct uec_thread_data_rx { + u8 res0[40]; +} __packed; + +/* Rx thread parameter, each Rx thread has one this struct. */ +struct uec_thread_rx_pram { + u8 res0[128]; +} __packed; + +/* Rx firmware counters */ +struct uec_rx_firmware_statistics_pram { + u32 frrxfcser; /* frames with crc error */ + u32 fraligner; /* frames with alignment error */ + u32 inrangelenrxer; /* in range length error */ + u32 outrangelenrxer; /* out of range length error */ + u32 frtoolong; /* frame too long */ + u32 runt; /* runt */ + u32 verylongevent; /* very long event */ + u32 symbolerror; /* symbol error */ + u32 dropbsy; /* drop because of BD not ready */ + u8 res0[0x8]; + u32 mismatchdrop; /* drop because of MAC filtering */ + u32 underpkts; /* total frames less than 64 octets */ + u32 pkts256; /* total frames(including bad)256~511 B */ + u32 pkts512; /* total frames(including bad)512~1023 B */ + u32 pkts1024; /* total frames(including bad)1024~1518 B */ + u32 pktsjumbo; /* total frames(including bad) >1024 B */ + u32 frlossinmacer; + u32 pausefr; /* pause frames */ + u8 res1[0x4]; + u32 removevlan; + u32 replacevlan; + u32 insertvlan; +} __packed; + +/* Rx interrupt coalescing entry, each Rx queue has one this entry. */ +struct uec_rx_interrupt_coalescing_entry { + u32 maxvalue; + u32 counter; +} __packed; + +struct uec_rx_interrupt_coalescing_table { + struct uec_rx_interrupt_coalescing_entry entry[MAX_RX_QUEUES]; +} __packed; + +/* RxBD queue entry, each Rx queue has one this entry. */ +struct uec_rx_bd_queues_entry { + u32 bdbaseptr; /* BD base pointer */ + u32 bdptr; /* BD pointer */ + u32 externalbdbaseptr; /* external BD base pointer */ + u32 externalbdptr; /* external BD pointer */ +} __packed; + +/* Rx global parameter table */ +struct uec_rx_global_pram { + u32 remoder; /* ethernet mode reg. */ + u32 rqptr; /* base pointer to the Rx Queues */ + u32 res0[0x1]; + u8 res1[0x20 - 0xc]; + u16 typeorlen; + u8 res2[0x1]; + u8 rxgstpack; /* ack on GRACEFUL STOP RX command */ + u32 rxrmonbaseptr; /* Rx RMON statistics base */ + u8 res3[0x30 - 0x28]; + u32 intcoalescingptr; /* Interrupt coalescing table pointer */ + u8 res4[0x36 - 0x34]; + u8 rstate; + u8 res5[0x46 - 0x37]; + u16 mrblr; /* max receive buffer length reg. */ + u32 rbdqptr; /* RxBD parameter table description */ + u16 mflr; /* max frame length reg. */ + u16 minflr; /* min frame length reg. */ + u16 maxd1; /* max dma1 length reg. */ + u16 maxd2; /* max dma2 length reg. */ + u32 ecamptr; /* external CAM address */ + u32 l2qt; /* VLAN priority mapping table. */ + u32 l3qt[0x8]; /* IP priority mapping table. */ + u16 vlantype; /* vlan type */ + u16 vlantci; /* default vlan tci */ + u8 addressfiltering[64];/* address filtering data structure */ + u32 exf_global_param; /* extended filtering global parameters */ + u8 res6[0x100 - 0xc4]; /* Initialize to zero */ +} __packed; + +#define GRACEFUL_STOP_ACKNOWLEDGE_RX 0x01 + +/****** UEC common ******/ +/* UCC statistics - hardware counters */ +struct uec_hardware_statistics { + u32 tx64; + u32 tx127; + u32 tx255; + u32 rx64; + u32 rx127; + u32 rx255; + u32 txok; + u16 txcf; + u32 tmca; + u32 tbca; + u32 rxfok; + u32 rxbok; + u32 rbyt; + u32 rmca; + u32 rbca; +} __packed; + +/* InitEnet command parameter */ +struct uec_init_cmd_pram { + u8 resinit0; + u8 resinit1; + u8 resinit2; + u8 resinit3; + u16 resinit4; + u8 res1[0x1]; + u8 largestexternallookupkeysize; + u32 rgftgfrxglobal; + u32 rxthread[MAX_ENET_INIT_PARAM_ENTRIES_RX]; /* rx threads */ + u8 res2[0x38 - 0x30]; + u32 txglobal; /* tx global */ + u32 txthread[MAX_ENET_INIT_PARAM_ENTRIES_TX]; /* tx threads */ + u8 res3[0x1]; +} __packed; + +#define ENET_INIT_PARAM_RGF_SHIFT (32 - 4) +#define ENET_INIT_PARAM_TGF_SHIFT (32 - 8) + +#define ENET_INIT_PARAM_RISC_MASK 0x0000003f +#define ENET_INIT_PARAM_PTR_MASK 0x00ffffc0 +#define ENET_INIT_PARAM_SNUM_MASK 0xff000000 +#define ENET_INIT_PARAM_SNUM_SHIFT 24 + +#define ENET_INIT_PARAM_MAGIC_RES_INIT0 0x06 +#define ENET_INIT_PARAM_MAGIC_RES_INIT1 0x30 +#define ENET_INIT_PARAM_MAGIC_RES_INIT2 0xff +#define ENET_INIT_PARAM_MAGIC_RES_INIT3 0x00 +#define ENET_INIT_PARAM_MAGIC_RES_INIT4 0x0400 + +/* structure representing 82xx Address Filtering Enet Address in PRAM */ +struct uec_82xx_enet_addr { + u8 res1[0x2]; + u16 h; /* address (MSB) */ + u16 m; /* address */ + u16 l; /* address (LSB) */ +} __packed; + +/* structure representing 82xx Address Filtering PRAM */ +struct uec_82xx_add_filtering_pram { + u32 iaddr_h; /* individual address filter, high */ + u32 iaddr_l; /* individual address filter, low */ + u32 gaddr_h; /* group address filter, high */ + u32 gaddr_l; /* group address filter, low */ + struct uec_82xx_enet_addr taddr; + struct uec_82xx_enet_addr paddr[4]; + u8 res0[0x40 - 0x38]; +} __packed; + +/* Buffer Descriptor */ +struct buffer_descriptor { + u16 status; + u16 len; + u32 data; +} __packed; + +#define SIZEOFBD sizeof(struct buffer_descriptor) + +/* Common BD flags */ +#define BD_WRAP 0x2000 +#define BD_INT 0x1000 +#define BD_LAST 0x0800 +#define BD_CLEAN 0x3000 + +/* TxBD status flags */ +#define TX_BD_READY 0x8000 +#define TX_BD_PADCRC 0x4000 +#define TX_BD_WRAP BD_WRAP +#define TX_BD_INT BD_INT +#define TX_BD_LAST BD_LAST +#define TX_BD_TXCRC 0x0400 +#define TX_BD_DEF 0x0200 +#define TX_BD_PP 0x0100 +#define TX_BD_LC 0x0080 +#define TX_BD_RL 0x0040 +#define TX_BD_RC 0x003C +#define TX_BD_UNDERRUN 0x0002 +#define TX_BD_TRUNC 0x0001 + +#define TX_BD_ERROR (TX_BD_UNDERRUN | TX_BD_TRUNC) + +/* RxBD status flags */ +#define RX_BD_EMPTY 0x8000 +#define RX_BD_OWNER 0x4000 +#define RX_BD_WRAP BD_WRAP +#define RX_BD_INT BD_INT +#define RX_BD_LAST BD_LAST +#define RX_BD_FIRST 0x0400 +#define RX_BD_CMR 0x0200 +#define RX_BD_MISS 0x0100 +#define RX_BD_BCAST 0x0080 +#define RX_BD_MCAST 0x0040 +#define RX_BD_LG 0x0020 +#define RX_BD_NO 0x0010 +#define RX_BD_SHORT 0x0008 +#define RX_BD_CRCERR 0x0004 +#define RX_BD_OVERRUN 0x0002 +#define RX_BD_IPCH 0x0001 + +#define RX_BD_ERROR (RX_BD_LG | RX_BD_NO | RX_BD_SHORT | \ + RX_BD_CRCERR | RX_BD_OVERRUN) + +/* BD access macros */ +#define BD_STATUS(_bd) (in_be16(&((_bd)->status))) +#define BD_STATUS_SET(_bd, _v) (out_be16(&((_bd)->status), _v)) +#define BD_LENGTH(_bd) (in_be16(&((_bd)->len))) +#define BD_LENGTH_SET(_bd, _v) (out_be16(&((_bd)->len), _v)) +#define BD_DATA_CLEAR(_bd) (out_be32(&((_bd)->data), 0)) +#define BD_DATA(_bd) ((u8 *)(((_bd)->data))) +#define BD_DATA_SET(_bd, _data) (out_be32(&((_bd)->data), (u32)_data)) +#define BD_ADVANCE(_bd, _status, _base) \ + (((_status) & BD_WRAP) ? (_bd) = \ + ((struct buffer_descriptor *)(_base)) : ++(_bd)) + +/* Rx Prefetched BDs */ +struct uec_rx_pref_bds { + struct buffer_descriptor bd[MAX_PREFETCHED_BDS]; /* prefetched bd */ +} __packed; + +/* Alignments */ +#define UEC_RX_GLOBAL_PRAM_ALIGNMENT 64 +#define UEC_TX_GLOBAL_PRAM_ALIGNMENT 64 +#define UEC_THREAD_RX_PRAM_ALIGNMENT 128 +#define UEC_THREAD_TX_PRAM_ALIGNMENT 64 +#define UEC_THREAD_DATA_ALIGNMENT 256 +#define UEC_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT 32 +#define UEC_SCHEDULER_ALIGNMENT 4 +#define UEC_TX_STATISTICS_ALIGNMENT 4 +#define UEC_RX_STATISTICS_ALIGNMENT 4 +#define UEC_RX_INTERRUPT_COALESCING_ALIGNMENT 4 +#define UEC_RX_BD_QUEUES_ALIGNMENT 8 +#define UEC_RX_PREFETCHED_BDS_ALIGNMENT 128 +#define UEC_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT 4 +#define UEC_RX_BD_RING_ALIGNMENT 32 +#define UEC_TX_BD_RING_ALIGNMENT 32 +#define UEC_MRBLR_ALIGNMENT 128 +#define UEC_RX_BD_RING_SIZE_ALIGNMENT 4 +#define UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT 32 +#define UEC_RX_DATA_BUF_ALIGNMENT 64 + +#define UEC_VLAN_PRIORITY_MAX 8 +#define UEC_IP_PRIORITY_MAX 64 +#define UEC_TX_VTAG_TABLE_ENTRY_MAX 8 +#define UEC_RX_BD_RING_SIZE_MIN 8 +#define UEC_TX_BD_RING_SIZE_MIN 2 + +/* TBI / MII Set Register */ +enum enet_tbi_mii_reg { + ENET_TBI_MII_CR = 0x00, + ENET_TBI_MII_SR = 0x01, + ENET_TBI_MII_ANA = 0x04, + ENET_TBI_MII_ANLPBPA = 0x05, + ENET_TBI_MII_ANEX = 0x06, + ENET_TBI_MII_ANNPT = 0x07, + ENET_TBI_MII_ANLPANP = 0x08, + ENET_TBI_MII_EXST = 0x0F, + ENET_TBI_MII_JD = 0x10, + ENET_TBI_MII_TBICON = 0x11 +}; + +/* TBI MDIO register bit fields*/ +#define TBICON_CLK_SELECT 0x0020 +#define TBIANA_ASYMMETRIC_PAUSE 0x0100 +#define TBIANA_SYMMETRIC_PAUSE 0x0080 +#define TBIANA_HALF_DUPLEX 0x0040 +#define TBIANA_FULL_DUPLEX 0x0020 +#define TBICR_PHY_RESET 0x8000 +#define TBICR_ANEG_ENABLE 0x1000 +#define TBICR_RESTART_ANEG 0x0200 +#define TBICR_FULL_DUPLEX 0x0100 +#define TBICR_SPEED1_SET 0x0040 + +#define TBIANA_SETTINGS ( \ + TBIANA_ASYMMETRIC_PAUSE \ + | TBIANA_SYMMETRIC_PAUSE \ + | TBIANA_FULL_DUPLEX \ + ) + +#define TBICR_SETTINGS ( \ + TBICR_PHY_RESET \ + | TBICR_ANEG_ENABLE \ + | TBICR_FULL_DUPLEX \ + | TBICR_SPEED1_SET \ + ) + +/* UEC number of threads */ +enum uec_num_of_threads { + UEC_NUM_OF_THREADS_1 = 0x1, /* 1 */ + UEC_NUM_OF_THREADS_2 = 0x2, /* 2 */ + UEC_NUM_OF_THREADS_4 = 0x0, /* 4 */ + UEC_NUM_OF_THREADS_6 = 0x3, /* 6 */ + UEC_NUM_OF_THREADS_8 = 0x4 /* 8 */ +}; + +/* UEC initialization info struct */ +#define STD_UEC_INFO(num) \ +{ \ + .uf_info = { \ + .ucc_num = CONFIG_SYS_UEC##num##_UCC_NUM,\ + .rx_clock = CONFIG_SYS_UEC##num##_RX_CLK, \ + .tx_clock = CONFIG_SYS_UEC##num##_TX_CLK, \ + .eth_type = CONFIG_SYS_UEC##num##_ETH_TYPE,\ + }, \ + .num_threads_tx = UEC_NUM_OF_THREADS_1, \ + .num_threads_rx = UEC_NUM_OF_THREADS_1, \ + .risc_tx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, \ + .risc_rx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, \ + .tx_bd_ring_len = 16, \ + .rx_bd_ring_len = 16, \ + .phy_address = CONFIG_SYS_UEC##num##_PHY_ADDR, \ + .enet_interface_type = CONFIG_SYS_UEC##num##_INTERFACE_TYPE, \ + .speed = CONFIG_SYS_UEC##num##_INTERFACE_SPEED, \ +} + +struct uec_inf { + struct ucc_fast_inf uf_info; + enum uec_num_of_threads num_threads_tx; + enum uec_num_of_threads num_threads_rx; + unsigned int risc_tx; + unsigned int risc_rx; + u16 rx_bd_ring_len; + u16 tx_bd_ring_len; + u8 phy_address; + phy_interface_t enet_interface_type; + int speed; +}; + +/* UEC driver initialized info */ +#define MAX_RXBUF_LEN 1536 +#define MAX_FRAME_LEN 1518 +#define MIN_FRAME_LEN 64 +#define MAX_DMA1_LEN 1520 +#define MAX_DMA2_LEN 1520 + +/* UEC driver private struct */ +struct uec_priv { + struct uec_inf *uec_info; + struct ucc_fast_priv *uccf; + struct eth_device *dev; + uec_t *uec_regs; + /* enet init command parameter */ + struct uec_init_cmd_pram *p_init_enet_param; + u32 init_enet_param_offset; + /* Rx and Tx parameter */ + struct uec_rx_global_pram *p_rx_glbl_pram; + u32 rx_glbl_pram_offset; + struct uec_tx_global_pram *p_tx_glbl_pram; + u32 tx_glbl_pram_offset; + struct uec_send_queue_mem_region *p_send_q_mem_reg; + u32 send_q_mem_reg_offset; + struct uec_thread_data_tx *p_thread_data_tx; + u32 thread_dat_tx_offset; + struct uec_thread_data_rx *p_thread_data_rx; + u32 thread_dat_rx_offset; + struct uec_rx_bd_queues_entry *p_rx_bd_qs_tbl; + u32 rx_bd_qs_tbl_offset; + /* BDs specific */ + u8 *p_tx_bd_ring; + u32 tx_bd_ring_offset; + u8 *p_rx_bd_ring; + u32 rx_bd_ring_offset; + u8 *p_rx_buf; + u32 rx_buf_offset; + struct buffer_descriptor *tx_bd; + struct buffer_descriptor *rx_bd; + /* Status */ + int mac_tx_enabled; + int mac_rx_enabled; + int grace_stopped_tx; + int grace_stopped_rx; + int the_first_run; +#if !defined(COFIG_DM) + /* PHY specific */ + struct uec_mii_info *mii_info; + int oldspeed; + int oldduplex; + int oldlink; +#endif +}; + +int uec_initialize(struct bd_info *bis, struct uec_inf *uec_info); +int uec_eth_init(struct bd_info *bis, struct uec_inf *uecs, int num); +int uec_standard_init(struct bd_info *bis); +#endif /* __UEC_H__ */ diff --git a/drivers/qe/Kconfig b/drivers/qe/Kconfig index 44c9f010bd..864b36b822 100644 --- a/drivers/qe/Kconfig +++ b/drivers/qe/Kconfig @@ -3,7 +3,7 @@ # config QE bool "Enable support for QUICC Engine" - depends on PPC && !DM_ETH + depends on PPC default y if ARCH_T1040 || ARCH_T1042 || ARCH_T1024 || ARCH_P1021 \ || ARCH_P1025 help diff --git a/drivers/qe/uccf.c b/drivers/qe/uccf.c index 306f1ea1db..d5d734439c 100644 --- a/drivers/qe/uccf.c +++ b/drivers/qe/uccf.c @@ -14,6 +14,7 @@ #include "uccf.h" #include +#if !defined(CONFIG_DM_ETH) void ucc_fast_transmit_on_demand(struct ucc_fast_priv *uccf) { out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD); @@ -505,3 +506,4 @@ int ucc_fast_init(struct ucc_fast_inf *uf_info, *uccf_ret = uccf; return 0; } +#endif diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c index cfd5397044..5da971ddc0 100644 --- a/drivers/qe/uec.c +++ b/drivers/qe/uec.c @@ -20,6 +20,7 @@ #include #include +#if !defined(CONFIG_DM_ETH) /* Default UTBIPAR SMI address */ #ifndef CONFIG_UTBIPAR_INIT_TBIPA #define CONFIG_UTBIPAR_INIT_TBIPA 0x1F @@ -1432,3 +1433,4 @@ int uec_standard_init(struct bd_info *bis) { return uec_eth_init(bis, uec_info, ARRAY_SIZE(uec_info)); } +#endif diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c index b5ca5f76f9..9d429c832f 100644 --- a/drivers/qe/uec_phy.c +++ b/drivers/qe/uec_phy.c @@ -23,6 +23,8 @@ #include #include +#if !defined(CONFIG_DM_ETH) + #define ugphy_printk(format, arg...) \ printf(format "\n", ## arg) @@ -925,3 +927,4 @@ void change_phy_interface_mode(struct eth_device *dev, marvell_phy_interface_mode(dev, type, speed); #endif } +#endif -- cgit v1.2.3 From 6ef099b29e153f664b1de829020b4410b9ec709d Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Thu, 10 Sep 2020 16:00:01 +0200 Subject: IPQ40xx: Add SMEM support There is already existing driver for SMEM so lets enable it for IPQ40xx as well. Signed-off-by: Robert Marko Cc: Luka Perkov --- arch/arm/Kconfig | 2 ++ arch/arm/dts/qcom-ipq4019.dtsi | 5 +++++ drivers/smem/Kconfig | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 80702c23d3..ee378f03f4 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -767,8 +767,10 @@ config ARCH_IPQ40XX select DM select DM_GPIO select DM_SERIAL + select MSM_SMEM select PINCTRL select CLK + select SMEM select OF_CONTROL imply CMD_DM diff --git a/arch/arm/dts/qcom-ipq4019.dtsi b/arch/arm/dts/qcom-ipq4019.dtsi index 7b3b5e0248..dd69d0a5b2 100644 --- a/arch/arm/dts/qcom-ipq4019.dtsi +++ b/arch/arm/dts/qcom-ipq4019.dtsi @@ -39,6 +39,11 @@ }; }; + smem { + compatible = "qcom,smem"; + memory-region = <&smem_mem>; + }; + soc: soc { #address-cells = <1>; #size-cells = <1>; diff --git a/drivers/smem/Kconfig b/drivers/smem/Kconfig index 7169d0f205..73d51b3a7a 100644 --- a/drivers/smem/Kconfig +++ b/drivers/smem/Kconfig @@ -15,7 +15,7 @@ config SANDBOX_SMEM config MSM_SMEM bool "Qualcomm Shared Memory Manager (SMEM)" depends on DM - depends on ARCH_SNAPDRAGON + depends on ARCH_SNAPDRAGON || ARCH_IPQ40XX help Enable support for the Qualcomm Shared Memory Manager. The driver provides an interface to items in a heap shared among all -- cgit v1.2.3 From 8ef7df5df39edbeb1367409cc340646810d2369b Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Thu, 10 Sep 2020 16:00:02 +0200 Subject: reset: Add IPQ40xx reset controller driver On Qualcomm IPQ40xx SoC series, GCC clock IP also handles the resets. So since this will be needed by further drivers, lets add a driver for the reset controller. Signed-off-by: Robert Marko Cc: Luka Perkov --- MAINTAINERS | 2 + drivers/reset/Kconfig | 8 ++ drivers/reset/Makefile | 1 + drivers/reset/reset-ipq4019.c | 173 +++++++++++++++++++++++++ include/dt-bindings/reset/qcom,ipq4019-reset.h | 92 +++++++++++++ 5 files changed, 276 insertions(+) create mode 100644 drivers/reset/reset-ipq4019.c create mode 100644 include/dt-bindings/reset/qcom,ipq4019-reset.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 80e6e54e25..fcad3e45f3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -238,6 +238,8 @@ M: Luka Perkov S: Maintained F: arch/arm/mach-ipq40xx/ F: include/dt-bindings/clock/qcom,ipq4019-gcc.h +F: include/dt-bindings/reset/qcom,ipq4019-reset.h +F: drivers/reset/reset-ipq4019.c ARM MARVELL KIRKWOOD ARMADA-XP ARMADA-38X ARMADA-37XX ARMADA-7K/8K M: Stefan Roese diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 253902ff57..3fdfe4a6cb 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -148,6 +148,14 @@ config RESET_IMX7 help Support for reset controller on i.MX7/8 SoCs. +config RESET_IPQ419 + bool "Reset driver for Qualcomm IPQ40xx SoCs" + depends on DM_RESET && ARCH_IPQ40XX + default y + help + Support for reset controller on Qualcomm + IPQ40xx SoCs. + config RESET_SIFIVE bool "Reset Driver for SiFive SoC's" depends on DM_RESET && CLK_SIFIVE_FU540_PRCI && TARGET_SIFIVE_FU540 diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 3c7f066ae3..5176da5885 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_RESET_MTMIPS) += reset-mtmips.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o obj-$(CONFIG_RESET_HISILICON) += reset-hisilicon.o obj-$(CONFIG_RESET_IMX7) += reset-imx7.o +obj-$(CONFIG_RESET_IPQ419) += reset-ipq4019.o obj-$(CONFIG_RESET_SIFIVE) += reset-sifive.o obj-$(CONFIG_RESET_SYSCON) += reset-syscon.o obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o diff --git a/drivers/reset/reset-ipq4019.c b/drivers/reset/reset-ipq4019.c new file mode 100644 index 0000000000..f216db4ce5 --- /dev/null +++ b/drivers/reset/reset-ipq4019.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Sartura Ltd. + * + * Author: Robert Marko + * + * Based on Linux driver + */ + +#include +#include +#include +#include +#include +#include +#include + +struct ipq4019_reset_priv { + phys_addr_t base; +}; + +struct qcom_reset_map { + unsigned int reg; + u8 bit; +}; + +static const struct qcom_reset_map gcc_ipq4019_resets[] = { + [WIFI0_CPU_INIT_RESET] = { 0x1f008, 5 }, + [WIFI0_RADIO_SRIF_RESET] = { 0x1f008, 4 }, + [WIFI0_RADIO_WARM_RESET] = { 0x1f008, 3 }, + [WIFI0_RADIO_COLD_RESET] = { 0x1f008, 2 }, + [WIFI0_CORE_WARM_RESET] = { 0x1f008, 1 }, + [WIFI0_CORE_COLD_RESET] = { 0x1f008, 0 }, + [WIFI1_CPU_INIT_RESET] = { 0x20008, 5 }, + [WIFI1_RADIO_SRIF_RESET] = { 0x20008, 4 }, + [WIFI1_RADIO_WARM_RESET] = { 0x20008, 3 }, + [WIFI1_RADIO_COLD_RESET] = { 0x20008, 2 }, + [WIFI1_CORE_WARM_RESET] = { 0x20008, 1 }, + [WIFI1_CORE_COLD_RESET] = { 0x20008, 0 }, + [USB3_UNIPHY_PHY_ARES] = { 0x1e038, 5 }, + [USB3_HSPHY_POR_ARES] = { 0x1e038, 4 }, + [USB3_HSPHY_S_ARES] = { 0x1e038, 2 }, + [USB2_HSPHY_POR_ARES] = { 0x1e01c, 4 }, + [USB2_HSPHY_S_ARES] = { 0x1e01c, 2 }, + [PCIE_PHY_AHB_ARES] = { 0x1d010, 11 }, + [PCIE_AHB_ARES] = { 0x1d010, 10 }, + [PCIE_PWR_ARES] = { 0x1d010, 9 }, + [PCIE_PIPE_STICKY_ARES] = { 0x1d010, 8 }, + [PCIE_AXI_M_STICKY_ARES] = { 0x1d010, 7 }, + [PCIE_PHY_ARES] = { 0x1d010, 6 }, + [PCIE_PARF_XPU_ARES] = { 0x1d010, 5 }, + [PCIE_AXI_S_XPU_ARES] = { 0x1d010, 4 }, + [PCIE_AXI_M_VMIDMT_ARES] = { 0x1d010, 3 }, + [PCIE_PIPE_ARES] = { 0x1d010, 2 }, + [PCIE_AXI_S_ARES] = { 0x1d010, 1 }, + [PCIE_AXI_M_ARES] = { 0x1d010, 0 }, + [ESS_RESET] = { 0x12008, 0}, + [GCC_BLSP1_BCR] = {0x01000, 0}, + [GCC_BLSP1_QUP1_BCR] = {0x02000, 0}, + [GCC_BLSP1_UART1_BCR] = {0x02038, 0}, + [GCC_BLSP1_QUP2_BCR] = {0x03008, 0}, + [GCC_BLSP1_UART2_BCR] = {0x03028, 0}, + [GCC_BIMC_BCR] = {0x04000, 0}, + [GCC_TLMM_BCR] = {0x05000, 0}, + [GCC_IMEM_BCR] = {0x0E000, 0}, + [GCC_ESS_BCR] = {0x12008, 0}, + [GCC_PRNG_BCR] = {0x13000, 0}, + [GCC_BOOT_ROM_BCR] = {0x13008, 0}, + [GCC_CRYPTO_BCR] = {0x16000, 0}, + [GCC_SDCC1_BCR] = {0x18000, 0}, + [GCC_SEC_CTRL_BCR] = {0x1A000, 0}, + [GCC_AUDIO_BCR] = {0x1B008, 0}, + [GCC_QPIC_BCR] = {0x1C000, 0}, + [GCC_PCIE_BCR] = {0x1D000, 0}, + [GCC_USB2_BCR] = {0x1E008, 0}, + [GCC_USB2_PHY_BCR] = {0x1E018, 0}, + [GCC_USB3_BCR] = {0x1E024, 0}, + [GCC_USB3_PHY_BCR] = {0x1E034, 0}, + [GCC_SYSTEM_NOC_BCR] = {0x21000, 0}, + [GCC_PCNOC_BCR] = {0x2102C, 0}, + [GCC_DCD_BCR] = {0x21038, 0}, + [GCC_SNOC_BUS_TIMEOUT0_BCR] = {0x21064, 0}, + [GCC_SNOC_BUS_TIMEOUT1_BCR] = {0x2106C, 0}, + [GCC_SNOC_BUS_TIMEOUT2_BCR] = {0x21074, 0}, + [GCC_SNOC_BUS_TIMEOUT3_BCR] = {0x2107C, 0}, + [GCC_PCNOC_BUS_TIMEOUT0_BCR] = {0x21084, 0}, + [GCC_PCNOC_BUS_TIMEOUT1_BCR] = {0x2108C, 0}, + [GCC_PCNOC_BUS_TIMEOUT2_BCR] = {0x21094, 0}, + [GCC_PCNOC_BUS_TIMEOUT3_BCR] = {0x2109C, 0}, + [GCC_PCNOC_BUS_TIMEOUT4_BCR] = {0x210A4, 0}, + [GCC_PCNOC_BUS_TIMEOUT5_BCR] = {0x210AC, 0}, + [GCC_PCNOC_BUS_TIMEOUT6_BCR] = {0x210B4, 0}, + [GCC_PCNOC_BUS_TIMEOUT7_BCR] = {0x210BC, 0}, + [GCC_PCNOC_BUS_TIMEOUT8_BCR] = {0x210C4, 0}, + [GCC_PCNOC_BUS_TIMEOUT9_BCR] = {0x210CC, 0}, + [GCC_TCSR_BCR] = {0x22000, 0}, + [GCC_MPM_BCR] = {0x24000, 0}, + [GCC_SPDM_BCR] = {0x25000, 0}, +}; + +static int ipq4019_reset_assert(struct reset_ctl *rst) +{ + struct ipq4019_reset_priv *priv = dev_get_priv(rst->dev); + const struct qcom_reset_map *reset_map = gcc_ipq4019_resets; + const struct qcom_reset_map *map; + u32 value; + + map = &reset_map[rst->id]; + + value = readl(priv->base + map->reg); + value |= BIT(map->bit); + writel(value, priv->base + map->reg); + + return 0; +} + +static int ipq4019_reset_deassert(struct reset_ctl *rst) +{ + struct ipq4019_reset_priv *priv = dev_get_priv(rst->dev); + const struct qcom_reset_map *reset_map = gcc_ipq4019_resets; + const struct qcom_reset_map *map; + u32 value; + + map = &reset_map[rst->id]; + + value = readl(priv->base + map->reg); + value &= ~BIT(map->bit); + writel(value, priv->base + map->reg); + + return 0; +} + +static int ipq4019_reset_free(struct reset_ctl *rst) +{ + return 0; +} + +static int ipq4019_reset_request(struct reset_ctl *rst) +{ + return 0; +} + +static const struct reset_ops ipq4019_reset_ops = { + .request = ipq4019_reset_request, + .rfree = ipq4019_reset_free, + .rst_assert = ipq4019_reset_assert, + .rst_deassert = ipq4019_reset_deassert, +}; + +static const struct udevice_id ipq4019_reset_ids[] = { + { .compatible = "qcom,gcc-reset-ipq4019" }, + { } +}; + +static int ipq4019_reset_probe(struct udevice *dev) +{ + struct ipq4019_reset_priv *priv = dev_get_priv(dev); + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + return 0; +} + +U_BOOT_DRIVER(ipq4019_reset) = { + .name = "ipq4019_reset", + .id = UCLASS_RESET, + .of_match = ipq4019_reset_ids, + .ops = &ipq4019_reset_ops, + .probe = ipq4019_reset_probe, + .priv_auto_alloc_size = sizeof(struct ipq4019_reset_priv), +}; diff --git a/include/dt-bindings/reset/qcom,ipq4019-reset.h b/include/dt-bindings/reset/qcom,ipq4019-reset.h new file mode 100644 index 0000000000..ed047d7402 --- /dev/null +++ b/include/dt-bindings/reset/qcom,ipq4019-reset.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ +#ifndef __QCOM_RESET_IPQ4019_H__ +#define __QCOM_RESET_IPQ4019_H__ + +#define WIFI0_CPU_INIT_RESET 0 +#define WIFI0_RADIO_SRIF_RESET 1 +#define WIFI0_RADIO_WARM_RESET 2 +#define WIFI0_RADIO_COLD_RESET 3 +#define WIFI0_CORE_WARM_RESET 4 +#define WIFI0_CORE_COLD_RESET 5 +#define WIFI1_CPU_INIT_RESET 6 +#define WIFI1_RADIO_SRIF_RESET 7 +#define WIFI1_RADIO_WARM_RESET 8 +#define WIFI1_RADIO_COLD_RESET 9 +#define WIFI1_CORE_WARM_RESET 10 +#define WIFI1_CORE_COLD_RESET 11 +#define USB3_UNIPHY_PHY_ARES 12 +#define USB3_HSPHY_POR_ARES 13 +#define USB3_HSPHY_S_ARES 14 +#define USB2_HSPHY_POR_ARES 15 +#define USB2_HSPHY_S_ARES 16 +#define PCIE_PHY_AHB_ARES 17 +#define PCIE_AHB_ARES 18 +#define PCIE_PWR_ARES 19 +#define PCIE_PIPE_STICKY_ARES 20 +#define PCIE_AXI_M_STICKY_ARES 21 +#define PCIE_PHY_ARES 22 +#define PCIE_PARF_XPU_ARES 23 +#define PCIE_AXI_S_XPU_ARES 24 +#define PCIE_AXI_M_VMIDMT_ARES 25 +#define PCIE_PIPE_ARES 26 +#define PCIE_AXI_S_ARES 27 +#define PCIE_AXI_M_ARES 28 +#define ESS_RESET 29 +#define GCC_BLSP1_BCR 30 +#define GCC_BLSP1_QUP1_BCR 31 +#define GCC_BLSP1_UART1_BCR 32 +#define GCC_BLSP1_QUP2_BCR 33 +#define GCC_BLSP1_UART2_BCR 34 +#define GCC_BIMC_BCR 35 +#define GCC_TLMM_BCR 36 +#define GCC_IMEM_BCR 37 +#define GCC_ESS_BCR 38 +#define GCC_PRNG_BCR 39 +#define GCC_BOOT_ROM_BCR 40 +#define GCC_CRYPTO_BCR 41 +#define GCC_SDCC1_BCR 42 +#define GCC_SEC_CTRL_BCR 43 +#define GCC_AUDIO_BCR 44 +#define GCC_QPIC_BCR 45 +#define GCC_PCIE_BCR 46 +#define GCC_USB2_BCR 47 +#define GCC_USB2_PHY_BCR 48 +#define GCC_USB3_BCR 49 +#define GCC_USB3_PHY_BCR 50 +#define GCC_SYSTEM_NOC_BCR 51 +#define GCC_PCNOC_BCR 52 +#define GCC_DCD_BCR 53 +#define GCC_SNOC_BUS_TIMEOUT0_BCR 54 +#define GCC_SNOC_BUS_TIMEOUT1_BCR 55 +#define GCC_SNOC_BUS_TIMEOUT2_BCR 56 +#define GCC_SNOC_BUS_TIMEOUT3_BCR 57 +#define GCC_PCNOC_BUS_TIMEOUT0_BCR 58 +#define GCC_PCNOC_BUS_TIMEOUT1_BCR 59 +#define GCC_PCNOC_BUS_TIMEOUT2_BCR 60 +#define GCC_PCNOC_BUS_TIMEOUT3_BCR 61 +#define GCC_PCNOC_BUS_TIMEOUT4_BCR 62 +#define GCC_PCNOC_BUS_TIMEOUT5_BCR 63 +#define GCC_PCNOC_BUS_TIMEOUT6_BCR 64 +#define GCC_PCNOC_BUS_TIMEOUT7_BCR 65 +#define GCC_PCNOC_BUS_TIMEOUT8_BCR 66 +#define GCC_PCNOC_BUS_TIMEOUT9_BCR 67 +#define GCC_TCSR_BCR 68 +#define GCC_QDSS_BCR 69 +#define GCC_MPM_BCR 70 +#define GCC_SPDM_BCR 71 + +#endif -- cgit v1.2.3 From dec042028e8aff9a4f12d1b2ae48a373ab4c4ff9 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Thu, 10 Sep 2020 16:00:04 +0200 Subject: phy: add driver for Qualcomm IPQ40xx USB PHY Add a driver to setup the USB PHY-s on Qualcomm IPQ40xx series SoCs. The driver sets up HS and SS phys. Signed-off-by: Robert Marko Cc: Luka Perkov --- MAINTAINERS | 1 + drivers/phy/Kconfig | 6 ++ drivers/phy/Makefile | 1 + drivers/phy/phy-qcom-ipq4019-usb.c | 145 +++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 drivers/phy/phy-qcom-ipq4019-usb.c (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index fcad3e45f3..1ba71093f7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -240,6 +240,7 @@ F: arch/arm/mach-ipq40xx/ F: include/dt-bindings/clock/qcom,ipq4019-gcc.h F: include/dt-bindings/reset/qcom,ipq4019-reset.h F: drivers/reset/reset-ipq4019.c +F: drivers/phy/phy-qcom-ipq4019-usb.c ARM MARVELL KIRKWOOD ARMADA-XP ARMADA-38X ARMADA-37XX ARMADA-7K/8K M: Stefan Roese diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 9c775107e9..8da00a259d 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -125,6 +125,12 @@ config STI_USB_PHY used by USB2 and USB3 Host controllers available on STiH407 SoC families. +config PHY_QCOM_IPQ4019_USB + tristate "Qualcomm IPQ4019 USB PHY driver" + depends on PHY && ARCH_IPQ40XX + help + Support for the USB PHY-s on Qualcomm IPQ40xx SoC-s. + config PHY_RCAR_GEN2 tristate "Renesas R-Car Gen2 USB PHY" depends on PHY && RCAR_GEN2 diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 74e8d931d3..009f353baf 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o obj-$(CONFIG_$(SPL_)PIPE3_PHY) += ti-pipe3-phy.o obj-$(CONFIG_AM654_PHY) += phy-ti-am654.o obj-$(CONFIG_STI_USB_PHY) += sti_usb_phy.o +obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o obj-$(CONFIG_PHY_RCAR_GEN3) += phy-rcar-gen3.o obj-$(CONFIG_PHY_STM32_USBPHYC) += phy-stm32-usbphyc.o diff --git a/drivers/phy/phy-qcom-ipq4019-usb.c b/drivers/phy/phy-qcom-ipq4019-usb.c new file mode 100644 index 0000000000..465f0d3a01 --- /dev/null +++ b/drivers/phy/phy-qcom-ipq4019-usb.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 Sartura Ltd. + * + * Author: Robert Marko + * + * Based on Linux driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct ipq4019_usb_phy { + phys_addr_t base; + struct reset_ctl por_rst; + struct reset_ctl srif_rst; +}; + +static int ipq4019_ss_phy_power_off(struct phy *_phy) +{ + struct ipq4019_usb_phy *phy = dev_get_priv(_phy->dev); + + reset_assert(&phy->por_rst); + mdelay(10); + + return 0; +} + +static int ipq4019_ss_phy_power_on(struct phy *_phy) +{ + struct ipq4019_usb_phy *phy = dev_get_priv(_phy->dev); + + ipq4019_ss_phy_power_off(_phy); + + reset_deassert(&phy->por_rst); + + return 0; +} + +static struct phy_ops ipq4019_usb_ss_phy_ops = { + .power_on = ipq4019_ss_phy_power_on, + .power_off = ipq4019_ss_phy_power_off, +}; + +static int ipq4019_usb_ss_phy_probe(struct udevice *dev) +{ + struct ipq4019_usb_phy *phy = dev_get_priv(dev); + int ret; + + phy->base = dev_read_addr(dev); + if (phy->base == FDT_ADDR_T_NONE) + return -EINVAL; + + ret = reset_get_by_name(dev, "por_rst", &phy->por_rst); + if (ret) + return ret; + + return 0; +} + +static const struct udevice_id ipq4019_usb_ss_phy_ids[] = { + { .compatible = "qcom,usb-ss-ipq4019-phy" }, + { } +}; + +U_BOOT_DRIVER(ipq4019_usb_ss_phy) = { + .name = "ipq4019-usb-ss-phy", + .id = UCLASS_PHY, + .of_match = ipq4019_usb_ss_phy_ids, + .ops = &ipq4019_usb_ss_phy_ops, + .probe = ipq4019_usb_ss_phy_probe, + .priv_auto_alloc_size = sizeof(struct ipq4019_usb_phy), +}; + +static int ipq4019_hs_phy_power_off(struct phy *_phy) +{ + struct ipq4019_usb_phy *phy = dev_get_priv(_phy->dev); + + reset_assert(&phy->por_rst); + mdelay(10); + + reset_assert(&phy->srif_rst); + mdelay(10); + + return 0; +} + +static int ipq4019_hs_phy_power_on(struct phy *_phy) +{ + struct ipq4019_usb_phy *phy = dev_get_priv(_phy->dev); + + ipq4019_hs_phy_power_off(_phy); + + reset_deassert(&phy->srif_rst); + mdelay(10); + + reset_deassert(&phy->por_rst); + + return 0; +} + +static struct phy_ops ipq4019_usb_hs_phy_ops = { + .power_on = ipq4019_hs_phy_power_on, + .power_off = ipq4019_hs_phy_power_off, +}; + +static int ipq4019_usb_hs_phy_probe(struct udevice *dev) +{ + struct ipq4019_usb_phy *phy = dev_get_priv(dev); + int ret; + + phy->base = dev_read_addr(dev); + if (phy->base == FDT_ADDR_T_NONE) + return -EINVAL; + + ret = reset_get_by_name(dev, "por_rst", &phy->por_rst); + if (ret) + return ret; + + ret = reset_get_by_name(dev, "srif_rst", &phy->srif_rst); + if (ret) + return ret; + + return 0; +} + +static const struct udevice_id ipq4019_usb_hs_phy_ids[] = { + { .compatible = "qcom,usb-hs-ipq4019-phy" }, + { } +}; + +U_BOOT_DRIVER(ipq4019_usb_hs_phy) = { + .name = "ipq4019-usb-hs-phy", + .id = UCLASS_PHY, + .of_match = ipq4019_usb_hs_phy_ids, + .ops = &ipq4019_usb_hs_phy_ops, + .probe = ipq4019_usb_hs_phy_probe, + .priv_auto_alloc_size = sizeof(struct ipq4019_usb_phy), +}; -- cgit v1.2.3 From 74a703a8aded58dac2ed3373447c6a4fc2d467c9 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Thu, 10 Sep 2020 16:00:05 +0200 Subject: usb: dwc3: Add Qualcomm DWC3 compatible string Lot of Qualcomm SoC-s use DWC3 controller for both USB2.0 and USB3.0 ports. Qualcomm has some custom config registers on top of the generic ones, but for host mode these are not needed. So lets add the neccessary compatible string. Signed-off-by: Robert Marko Cc: Luka Perkov --- drivers/usb/dwc3/dwc3-generic.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 551f682024..7fbf2502fa 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -449,6 +449,7 @@ static const struct udevice_id dwc3_glue_ids[] = { { .compatible = "ti,am654-dwc3" }, { .compatible = "rockchip,rk3328-dwc3" }, { .compatible = "rockchip,rk3399-dwc3" }, + { .compatible = "qcom,dwc3" }, { } }; -- cgit v1.2.3 From b04da9fcf78e233e70ea5ace757c0b8b95bb2459 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:32 +0300 Subject: 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(+) (limited to 'drivers') 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; } -- cgit v1.2.3 From cfecbaf4e768991056a88d3a7a3daf4b4baf8038 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:33 +0300 Subject: 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(+) (limited to 'drivers') 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) { -- cgit v1.2.3 From 4d139f3838b4ee48d7df9ca9c37ccd1a57202a52 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:34 +0300 Subject: 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(-) (limited to 'drivers') 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; -- cgit v1.2.3 From 9a5d59dfc6475c4770bf702e4f30e338499310fd Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:35 +0300 Subject: 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(-) (limited to 'drivers') 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; -- cgit v1.2.3 From b364134f87a2b3d021746b86b1f81278b15fa296 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:36 +0300 Subject: 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(-) (limited to 'drivers') 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", -- cgit v1.2.3 From 5d729f96299321af2c132fae4b56306e19a3f52b Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:38 +0300 Subject: 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(+) (limited to 'drivers') 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 -- cgit v1.2.3 From 653bcce4085a5816a9fee560412fbfaa171db7bb Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:39 +0300 Subject: 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 (limited to 'drivers') 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, -}; -- cgit v1.2.3 From e9885aa7cc23c21f1fa254c7c8cc459eca67db84 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:40 +0300 Subject: 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 (limited to 'drivers') 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, +}; -- cgit v1.2.3 From f1218f0b4fe95379d54312348c97865cab5ba1cd Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:41 +0300 Subject: 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 (limited to 'drivers') 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); -- cgit v1.2.3 From e6547a6d0c24129543ec58ed9cc5fcd6ebffc7ad Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:42 +0300 Subject: 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 (limited to 'drivers') 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); -- cgit v1.2.3 From b4c4e18dbda178a86bd88e96f20874c6fd51ca56 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:43 +0300 Subject: 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 (limited to 'drivers') 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); -- cgit v1.2.3 From dd4d19ddfb6590c4504a7d80f2e4dffe56c28337 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:44 +0300 Subject: 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(-) (limited to 'drivers') 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); -- cgit v1.2.3 From ad4d39a964e1d3abb4f2c3d933234f86a7960d54 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:45 +0300 Subject: 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 (limited to 'drivers') 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); -- cgit v1.2.3 From 03417335702b50d70b57d8594efd61239e88c362 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:46 +0300 Subject: 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(-) (limited to 'drivers') 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); -- cgit v1.2.3 From 2a1a579bde83f0ab6a6eb61a4189820972bfe691 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:47 +0300 Subject: 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 (limited to 'drivers') 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); -- cgit v1.2.3 From 16502bfa7c969cff366f92de67c048d2b0c626b8 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:48 +0300 Subject: 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 (limited to 'drivers') 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); -- cgit v1.2.3 From f89268e46814a56323ca78b85eb0e32e6ef3cbd0 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:49 +0300 Subject: 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 (limited to 'drivers') 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); -- cgit v1.2.3 From 36a9630fcbb0bfb2d3fc6c04ae9de666846ced32 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:50 +0300 Subject: 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 (limited to 'drivers') 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); -- cgit v1.2.3 From 7b7e226739104347a69d88dc3414c16e5fb1fe9d Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:51 +0300 Subject: 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(+) (limited to 'drivers') 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, -- cgit v1.2.3 From 6a6fe3ed4d80afba7efc65a87aca5344672768c5 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 17:46:52 +0300 Subject: 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 (limited to 'drivers') 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, +}; -- cgit v1.2.3 From 36da81e0c189a924663d1218455388566d8413e4 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 22 Aug 2020 07:16:26 +0200 Subject: dm: syscon: typo alerady * Fix typo: %s/alerady/already/. * Add missing 'the'. * Reformat a comment. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- drivers/core/syscon-uclass.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c index b5cd763b6b..9cbda4ebda 100644 --- a/drivers/core/syscon-uclass.c +++ b/drivers/core/syscon-uclass.c @@ -18,12 +18,16 @@ /* * Caution: - * This API requires the given device has alerady been bound to syscon driver. - * For example, + * This API requires the given device has already been bound to the syscon + * driver. For example, + * * compatible = "syscon", "simple-mfd"; + * * works, but + * * compatible = "simple-mfd", "syscon"; - * does not. The behavior is different from Linux. + * + * does not. The behavior is different from Linux. */ struct regmap *syscon_get_regmap(struct udevice *dev) { -- cgit v1.2.3 From 01d89e3d12e07a1a1ee0f8528706441a84eee328 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 10 Sep 2020 18:26:17 +0200 Subject: dm: add cells_count parameter in live DT APIs of_parse_phandle_with_args In the live tree API ofnode_parse_phandle_with_args, the cell_count argument must be used when cells_name is NULL. But this argument is not provided to the live DT function of_parse_phandle_with_args even it is provided to fdtdec_parse_phandle_with_args. This patch adds support of the cells_count parameter in dev_ and of_node API to allow migration and support of live DT: - of_parse_phandle_with_args Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass --- drivers/core/of_access.c | 7 ++++--- drivers/core/ofnode.c | 3 ++- include/dm/of_access.h | 4 +++- 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c index 922e78f99b..bcf1644d05 100644 --- a/drivers/core/of_access.c +++ b/drivers/core/of_access.c @@ -745,13 +745,14 @@ struct device_node *of_parse_phandle(const struct device_node *np, int of_parse_phandle_with_args(const struct device_node *np, const char *list_name, const char *cells_name, - int index, struct of_phandle_args *out_args) + int cell_count, int index, + struct of_phandle_args *out_args) { if (index < 0) return -EINVAL; - return __of_parse_phandle_with_args(np, list_name, cells_name, 0, - index, out_args); + return __of_parse_phandle_with_args(np, list_name, cells_name, + cell_count, index, out_args); } int of_count_phandle_with_args(const struct device_node *np, diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index d02d8d33fe..79fcdf5ce2 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -409,7 +409,8 @@ int ofnode_parse_phandle_with_args(ofnode node, const char *list_name, int ret; ret = of_parse_phandle_with_args(ofnode_to_np(node), - list_name, cells_name, index, + list_name, cells_name, + cell_count, index, &args); if (ret) return ret; diff --git a/include/dm/of_access.h b/include/dm/of_access.h index f95a00d065..2fa65c9332 100644 --- a/include/dm/of_access.h +++ b/include/dm/of_access.h @@ -407,6 +407,7 @@ struct device_node *of_parse_phandle(const struct device_node *np, * @np: pointer to a device tree node containing a list * @list_name: property name that contains a list * @cells_name: property name that specifies phandles' arguments count + * @cells_count: Cell count to use if @cells_name is NULL * @index: index of a phandle to parse out * @out_args: optional pointer to output arguments structure (will be filled) * @return 0 on success (with @out_args filled out if not NULL), -ENOENT if @@ -440,7 +441,8 @@ struct device_node *of_parse_phandle(const struct device_node *np, */ int of_parse_phandle_with_args(const struct device_node *np, const char *list_name, const char *cells_name, - int index, struct of_phandle_args *out_args); + int cells_count, int index, + struct of_phandle_args *out_args); /** * of_count_phandle_with_args() - Count the number of phandle in a list -- cgit v1.2.3 From 6c0e59fcd9bfc258c2ec4cad4971352a17a58411 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 7 Jan 2020 08:50:34 +0100 Subject: xilinx: drivers: Use '_' instead of '-' in driver name The most of drivers are using '_' instead of '-' in driver name. That's why sync up these names to be aligned. It looks quite bad to see both in use. It is visible via dm tree command. Signed-off-by: Michal Simek Reviewed-by: Simon Glass --- drivers/clk/clk_zynqmp.c | 2 +- drivers/firmware/firmware-zynqmp.c | 2 +- drivers/i2c/i2c-cdns.c | 2 +- drivers/mailbox/zynqmp-ipi.c | 2 +- drivers/mtd/nand/raw/arasan_nfc.c | 2 +- drivers/mtd/nand/raw/zynq_nand.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk_zynqmp.c b/drivers/clk/clk_zynqmp.c index 2313ac0bc0..7795119756 100644 --- a/drivers/clk/clk_zynqmp.c +++ b/drivers/clk/clk_zynqmp.c @@ -710,7 +710,7 @@ static const struct udevice_id zynqmp_clk_ids[] = { }; U_BOOT_DRIVER(zynqmp_clk) = { - .name = "zynqmp-clk", + .name = "zynqmp_clk", .id = UCLASS_CLK, .of_match = zynqmp_clk_ids, .probe = zynqmp_clk_probe, diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index 903a8f5878..7583f24a20 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -202,6 +202,6 @@ static const struct udevice_id zynqmp_firmware_ids[] = { U_BOOT_DRIVER(zynqmp_firmware) = { .id = UCLASS_FIRMWARE, - .name = "zynqmp-firmware", + .name = "zynqmp_firmware", .of_match = zynqmp_firmware_ids, }; diff --git a/drivers/i2c/i2c-cdns.c b/drivers/i2c/i2c-cdns.c index 024c63c4ea..7144d39984 100644 --- a/drivers/i2c/i2c-cdns.c +++ b/drivers/i2c/i2c-cdns.c @@ -500,7 +500,7 @@ static const struct udevice_id cdns_i2c_of_match[] = { }; U_BOOT_DRIVER(cdns_i2c) = { - .name = "i2c-cdns", + .name = "i2c_cdns", .id = UCLASS_I2C, .of_match = cdns_i2c_of_match, .ofdata_to_platdata = cdns_i2c_ofdata_to_platdata, diff --git a/drivers/mailbox/zynqmp-ipi.c b/drivers/mailbox/zynqmp-ipi.c index 746377e557..9483ed9cef 100644 --- a/drivers/mailbox/zynqmp-ipi.c +++ b/drivers/mailbox/zynqmp-ipi.c @@ -133,7 +133,7 @@ struct mbox_ops zynqmp_ipi_mbox_ops = { }; U_BOOT_DRIVER(zynqmp_ipi) = { - .name = "zynqmp-ipi", + .name = "zynqmp_ipi", .id = UCLASS_MAILBOX, .of_match = zynqmp_ipi_ids, .probe = zynqmp_ipi_probe, diff --git a/drivers/mtd/nand/raw/arasan_nfc.c b/drivers/mtd/nand/raw/arasan_nfc.c index 6c1d64054c..0615e50378 100644 --- a/drivers/mtd/nand/raw/arasan_nfc.c +++ b/drivers/mtd/nand/raw/arasan_nfc.c @@ -1306,7 +1306,7 @@ static const struct udevice_id arasan_nand_dt_ids[] = { }; U_BOOT_DRIVER(arasan_nand) = { - .name = "arasan-nand", + .name = "arasan_nand", .id = UCLASS_MTD, .of_match = arasan_nand_dt_ids, .probe = arasan_probe, diff --git a/drivers/mtd/nand/raw/zynq_nand.c b/drivers/mtd/nand/raw/zynq_nand.c index fa59455210..92db2aa19c 100644 --- a/drivers/mtd/nand/raw/zynq_nand.c +++ b/drivers/mtd/nand/raw/zynq_nand.c @@ -1282,7 +1282,7 @@ static const struct udevice_id zynq_nand_dt_ids[] = { }; U_BOOT_DRIVER(zynq_nand) = { - .name = "zynq-nand", + .name = "zynq_nand", .id = UCLASS_MTD, .of_match = zynq_nand_dt_ids, .probe = zynq_nand_probe, -- cgit v1.2.3 From 8c40e07aab8763d9a61d98bcce4bdf4a69566fe4 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 30 May 2016 10:43:11 +0200 Subject: net: gem: Add support for more PHYs on MDIO bus Find out MDIO bus and enable MDIO access to it if this is done via different GEM controller. Only works across GEM instances. Signed-off-by: Michal Simek --- drivers/net/zynq_gem.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index da4b6fba9f..8afec8bbfc 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -758,6 +758,9 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) if (!dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, &phandle_args)) { + fdt_addr_t addr; + ofnode parent; + debug("phy-handle does exist %s\n", dev->name); priv->phyaddr = ofnode_read_u32_default(phandle_args.node, "reg", -1); @@ -765,6 +768,13 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev) priv->max_speed = ofnode_read_u32_default(phandle_args.node, "max-speed", SPEED_1000); + + parent = ofnode_get_parent(phandle_args.node); + addr = ofnode_get_addr(parent); + if (addr != FDT_ADDR_T_NONE) { + debug("MDIO bus not found %s\n", dev->name); + priv->mdiobase = (struct zynq_gem_regs *)addr; + } } phy_mode = dev_read_prop(dev, "phy-mode", NULL); -- cgit v1.2.3 From 54fdef242fdcda8792b7c05d687dc79a624fcc32 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 24 Aug 2020 14:41:51 +0200 Subject: xilinx: kconfig: Change Kconfig dependencies for Xilinx drivers Zynq/ZynqMP/Versal IPs should be possible to called also from Microblaze in PL and vice versa. That's why change dependencies and do not limit enabling just for some platforms. This is follow up patch based on commit 664e16ce99a0 ("xilinx: kconfig: Change Kconfig dependencies for Xilinx drivers"). Signed-off-by: Michal Simek --- drivers/serial/Kconfig | 4 ++-- drivers/spi/Kconfig | 3 --- drivers/usb/host/Kconfig | 3 +-- 3 files changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index e344677f91..b4805a2e4e 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -734,7 +734,7 @@ config UNIPHIER_SERIAL config XILINX_UARTLITE bool "Xilinx Uarlite support" - depends on DM_SERIAL && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP || 4xx) + depends on DM_SERIAL help If you have a Xilinx based board and want to use the uartlite serial ports, say Y to this option. If unsure, say N. @@ -802,7 +802,7 @@ config STM32_SERIAL config ZYNQ_SERIAL bool "Cadence (Xilinx Zynq) UART support" - depends on DM_SERIAL && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_ZYNQMP_R5) + depends on DM_SERIAL help This driver supports the Cadence UART. It is found e.g. in Xilinx Zynq/ZynqMP. diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 3fc2d0674a..5df97c80fa 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -407,7 +407,6 @@ config XILINX_SPI config ZYNQ_SPI bool "Zynq SPI driver" - depends on ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL help Enable the Zynq SPI driver. This driver can be used to access the SPI NOR flash on platforms embedding this Zynq @@ -415,7 +414,6 @@ config ZYNQ_SPI config ZYNQ_QSPI bool "Zynq QSPI driver" - depends on ARCH_ZYNQ imply SPI_FLASH_BAR help Enable the Zynq Quad-SPI (QSPI) driver. This driver can be @@ -425,7 +423,6 @@ config ZYNQ_QSPI config ZYNQMP_GQSPI bool "Configure ZynqMP Generic QSPI" - depends on ARCH_ZYNQMP || ARCH_VERSAL help This option is used to enable ZynqMP QSPI controller driver which is used to communicate with qspi flash devices. diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 1c374a7bd8..4eb7b34e24 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -200,8 +200,7 @@ config USB_EHCI_TEGRA config USB_EHCI_ZYNQ bool "Support for Xilinx Zynq on-chip EHCI USB controller" - depends on ARCH_ZYNQ - default y + default y if ARCH_ZYNQ ---help--- Enable support for Zynq on-chip EHCI USB controller -- cgit v1.2.3 From 31a359f87eaa66caf44dd10f89885736186537dd Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Fri, 14 Aug 2020 03:02:15 -0600 Subject: serial: uartlite: Add support to work with any endianness This endinness changes are taken from linux uartlite driver. Reset TX fifo in control register and check TX fifo empty flag in lower byte of the status register to detect if it is a little endian system. Based on this check, program the registers with le32 or be32 through out the driver. Signed-off-by: T Karthik Reddy Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek --- drivers/serial/serial_xuartlite.c | 64 +++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/serial_xuartlite.c b/drivers/serial/serial_xuartlite.c index 5116d13751..236ab860ad 100644 --- a/drivers/serial/serial_xuartlite.c +++ b/drivers/serial/serial_xuartlite.c @@ -23,6 +23,8 @@ #define ULITE_CONTROL_RST_TX 0x01 #define ULITE_CONTROL_RST_RX 0x02 +static bool little_endian; + struct uartlite { unsigned int rx_fifo; unsigned int tx_fifo; @@ -34,15 +36,31 @@ struct uartlite_platdata { struct uartlite *regs; }; +static u32 uart_in32(void __iomem *addr) +{ + if (little_endian) + return in_le32(addr); + else + return in_be32(addr); +} + +static void uart_out32(void __iomem *addr, u32 val) +{ + if (little_endian) + out_le32(addr, val); + else + out_be32(addr, val); +} + static int uartlite_serial_putc(struct udevice *dev, const char ch) { struct uartlite_platdata *plat = dev_get_platdata(dev); struct uartlite *regs = plat->regs; - if (in_be32(®s->status) & SR_TX_FIFO_FULL) + if (uart_in32(®s->status) & SR_TX_FIFO_FULL) return -EAGAIN; - out_be32(®s->tx_fifo, ch & 0xff); + uart_out32(®s->tx_fifo, ch & 0xff); return 0; } @@ -52,10 +70,10 @@ static int uartlite_serial_getc(struct udevice *dev) struct uartlite_platdata *plat = dev_get_platdata(dev); struct uartlite *regs = plat->regs; - if (!(in_be32(®s->status) & SR_RX_FIFO_VALID_DATA)) + if (!(uart_in32(®s->status) & SR_RX_FIFO_VALID_DATA)) return -EAGAIN; - return in_be32(®s->rx_fifo) & 0xff; + return uart_in32(®s->rx_fifo) & 0xff; } static int uartlite_serial_pending(struct udevice *dev, bool input) @@ -64,19 +82,26 @@ static int uartlite_serial_pending(struct udevice *dev, bool input) struct uartlite *regs = plat->regs; if (input) - return in_be32(®s->status) & SR_RX_FIFO_VALID_DATA; + return uart_in32(®s->status) & SR_RX_FIFO_VALID_DATA; - return !(in_be32(®s->status) & SR_TX_FIFO_EMPTY); + return !(uart_in32(®s->status) & SR_TX_FIFO_EMPTY); } static int uartlite_serial_probe(struct udevice *dev) { struct uartlite_platdata *plat = dev_get_platdata(dev); struct uartlite *regs = plat->regs; - - out_be32(®s->control, 0); - out_be32(®s->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX); - in_be32(®s->control); + int ret; + + uart_out32(®s->control, 0); + uart_out32(®s->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX); + ret = uart_in32(®s->status); + /* Endianness detection */ + if ((ret & SR_TX_FIFO_EMPTY) != SR_TX_FIFO_EMPTY) { + little_endian = true; + uart_out32(®s->control, ULITE_CONTROL_RST_RX | + ULITE_CONTROL_RST_TX); + } return 0; } @@ -119,20 +144,27 @@ U_BOOT_DRIVER(serial_uartlite) = { static inline void _debug_uart_init(void) { struct uartlite *regs = (struct uartlite *)CONFIG_DEBUG_UART_BASE; - - out_be32(®s->control, 0); - out_be32(®s->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX); - in_be32(®s->control); + int ret; + + uart_out32(®s->control, 0); + uart_out32(®s->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX); + uart_in32(®s->status); + /* Endianness detection */ + if ((ret & SR_TX_FIFO_EMPTY) != SR_TX_FIFO_EMPTY) { + little_endian = true; + uart_out32(®s->control, ULITE_CONTROL_RST_RX | + ULITE_CONTROL_RST_TX); + } } static inline void _debug_uart_putc(int ch) { struct uartlite *regs = (struct uartlite *)CONFIG_DEBUG_UART_BASE; - while (in_be32(®s->status) & SR_TX_FIFO_FULL) + while (uart_in32(®s->status) & SR_TX_FIFO_FULL) ; - out_be32(®s->tx_fifo, ch & 0xff); + uart_out32(®s->tx_fifo, ch & 0xff); } DEBUG_UART_FUNCS -- cgit v1.2.3 From a253092d499969bcf774de98dc5374328bf74d15 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 19 Aug 2020 09:59:52 +0200 Subject: nand: Kconfig: Change dependency for NAND_ARASAN NAND_ARASAN selecting DM_MTD uunconditionally. Driver can be enabled with !DM that's why Kconfig it showing it as error: WARNING: unmet direct dependencies detected for DM_MTD Depends on [n]: DM [=n] Selected by [y]: - NAND_ARASAN [=y] && MTD_RAW_NAND [=y] Signed-off-by: Michal Simek Reviewed-by: Tom Rini --- configs/xilinx_zynqmp_mini_nand_defconfig | 1 + configs/xilinx_zynqmp_mini_nand_single_defconfig | 1 + configs/xilinx_zynqmp_virt_defconfig | 1 + drivers/mtd/nand/raw/Kconfig | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/configs/xilinx_zynqmp_mini_nand_defconfig b/configs/xilinx_zynqmp_mini_nand_defconfig index a7cd93ebed..6ada8623ab 100644 --- a/configs/xilinx_zynqmp_mini_nand_defconfig +++ b/configs/xilinx_zynqmp_mini_nand_defconfig @@ -49,6 +49,7 @@ CONFIG_SYS_RELOC_GD_ENV_ADDR=y # CONFIG_DM_DEVICE_REMOVE is not set # CONFIG_MMC is not set CONFIG_MTD=y +CONFIG_DM_MTD=y CONFIG_MTD_RAW_NAND=y CONFIG_NAND_ARASAN=y CONFIG_SYS_NAND_MAX_CHIPS=2 diff --git a/configs/xilinx_zynqmp_mini_nand_single_defconfig b/configs/xilinx_zynqmp_mini_nand_single_defconfig index fb657bf1b2..04e17482fa 100644 --- a/configs/xilinx_zynqmp_mini_nand_single_defconfig +++ b/configs/xilinx_zynqmp_mini_nand_single_defconfig @@ -49,6 +49,7 @@ CONFIG_SYS_RELOC_GD_ENV_ADDR=y # CONFIG_DM_DEVICE_REMOVE is not set # CONFIG_MMC is not set CONFIG_MTD=y +CONFIG_DM_MTD=y CONFIG_MTD_RAW_NAND=y CONFIG_NAND_ARASAN=y CONFIG_ARM_DCC=y diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index 23d7ddf2d0..2f72d04f47 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -95,6 +95,7 @@ CONFIG_MMC_HS200_SUPPORT=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ZYNQ=y CONFIG_MTD=y +CONFIG_DM_MTD=y CONFIG_MTD_RAW_NAND=y CONFIG_NAND_ARASAN=y CONFIG_SYS_NAND_MAX_CHIPS=2 diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 06b2ff972c..df4cbd52cf 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -233,7 +233,7 @@ endif config NAND_ARASAN bool "Configure Arasan Nand" select SYS_NAND_SELF_INIT - select DM_MTD + depends on DM_MTD imply CMD_NAND help This enables Nand driver support for Arasan nand flash -- cgit v1.2.3 From f9d3b318832762ec8005b702b1724c0166e0aa36 Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Thu, 3 Sep 2020 08:36:43 -0600 Subject: net: xilinx: axi_emac: Fix dma descriptors for 64bit and compilation warnings There are compilation warnings showing up when we compile AXI ethernet driver for 64bit architectures. Fix them, so that it works on both 32 and 64 bit architectures. DMA descriptors are not taking care of 64bit addresses. To fix it, change axidma_bd members as below: next ==> next_desc reserverd1 ==> next_desc_msb phys ==> buf_addr reserverd2 ==> buf_addr_msb and update next_desc and buf_addr with lower 32 bits of the addresses, update next_desc_msb and buf_addr_msb with upper 32 bits of the 64bit addresses. Signed-off-by: Ashok Reddy Soma Reviewed-by: Ramon Fried --- drivers/net/xilinx_axi_emac.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c index 99d4d85c52..c56c4d0d83 100644 --- a/drivers/net/xilinx_axi_emac.c +++ b/drivers/net/xilinx_axi_emac.c @@ -101,10 +101,10 @@ struct axidma_priv { /* BD descriptors */ struct axidma_bd { - u32 next; /* Next descriptor pointer */ - u32 reserved1; - u32 phys; /* Buffer address */ - u32 reserved2; + u32 next_desc; /* Next descriptor pointer */ + u32 next_desc_msb; + u32 buf_addr; /* Buffer address */ + u32 buf_addr_msb; u32 reserved3; u32 reserved4; u32 cntrl; /* Control */ @@ -182,7 +182,7 @@ static inline int mdio_wait(struct axi_regs *regs) static inline void axienet_dma_write(struct axidma_bd *bd, u32 *desc) { #if defined(CONFIG_PHYS_64BIT) - writeq(bd, desc); + writeq((unsigned long)bd, desc); #else writel((u32)bd, desc); #endif @@ -492,8 +492,12 @@ static int axiemac_start(struct udevice *dev) /* Setup the BD. */ memset(&rx_bd, 0, sizeof(rx_bd)); - rx_bd.next = (u32)&rx_bd; - rx_bd.phys = (u32)&rxframe; + rx_bd.next_desc = lower_32_bits((unsigned long)&rx_bd); + rx_bd.buf_addr = lower_32_bits((unsigned long)&rxframe); +#if defined(CONFIG_PHYS_64BIT) + rx_bd.next_desc_msb = upper_32_bits((unsigned long)&rx_bd); + rx_bd.buf_addr_msb = upper_32_bits((unsigned long)&rxframe); +#endif rx_bd.cntrl = sizeof(rxframe); /* Flush the last BD so DMA core could see the updates */ flush_cache((u32)&rx_bd, sizeof(rx_bd)); @@ -539,8 +543,12 @@ static int axiemac_send(struct udevice *dev, void *ptr, int len) /* Setup Tx BD */ memset(&tx_bd, 0, sizeof(tx_bd)); /* At the end of the ring, link the last BD back to the top */ - tx_bd.next = (u32)&tx_bd; - tx_bd.phys = (u32)ptr; + tx_bd.next_desc = lower_32_bits((unsigned long)&tx_bd); + tx_bd.buf_addr = lower_32_bits((unsigned long)ptr); +#if defined(CONFIG_PHYS_64BIT) + tx_bd.next_desc_msb = upper_32_bits((unsigned long)&tx_bd); + tx_bd.buf_addr_msb = upper_32_bits((unsigned long)ptr); +#endif /* Save len */ tx_bd.cntrl = len | XAXIDMA_BD_CTRL_TXSOF_MASK | XAXIDMA_BD_CTRL_TXEOF_MASK; @@ -637,8 +645,12 @@ static int axiemac_free_pkt(struct udevice *dev, uchar *packet, int length) /* Setup RxBD */ /* Clear the whole buffer and setup it again - all flags are cleared */ memset(&rx_bd, 0, sizeof(rx_bd)); - rx_bd.next = (u32)&rx_bd; - rx_bd.phys = (u32)&rxframe; + rx_bd.next_desc = lower_32_bits((unsigned long)&rx_bd); + rx_bd.buf_addr = lower_32_bits((unsigned long)&rxframe); +#if defined(CONFIG_PHYS_64BIT) + rx_bd.next_desc_msb = upper_32_bits((unsigned long)&rx_bd); + rx_bd.buf_addr_msb = upper_32_bits((unsigned long)&rxframe); +#endif rx_bd.cntrl = sizeof(rxframe); /* Write bd to HW */ @@ -738,7 +750,7 @@ static int axi_emac_ofdata_to_platdata(struct udevice *dev) return -EINVAL; } /* RX channel offset is 0x30 */ - priv->dmarx = (struct axidma_reg *)((u32)priv->dmatx + 0x30); + priv->dmarx = (struct axidma_reg *)((phys_addr_t)priv->dmatx + 0x30); priv->phyaddr = -1; -- cgit v1.2.3 From 315a3c337749a45daf900ec8fca642a861521e7d Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Thu, 3 Sep 2020 08:36:44 -0600 Subject: net: xilinx: axi_emac: Typecast flush_cache arguments flush_cache() arguments are not type casted to take care of 64 bit systems. Use phys_addr_t to type cast for it to work properly for 32 bit and 64 bit systems. Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek Reviewed-by: Ramon Fried --- drivers/net/xilinx_axi_emac.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c index c56c4d0d83..8af3711204 100644 --- a/drivers/net/xilinx_axi_emac.c +++ b/drivers/net/xilinx_axi_emac.c @@ -500,11 +500,11 @@ static int axiemac_start(struct udevice *dev) #endif rx_bd.cntrl = sizeof(rxframe); /* Flush the last BD so DMA core could see the updates */ - flush_cache((u32)&rx_bd, sizeof(rx_bd)); + flush_cache((phys_addr_t)&rx_bd, sizeof(rx_bd)); /* It is necessary to flush rxframe because if you don't do it * then cache can contain uninitialized data */ - flush_cache((u32)&rxframe, sizeof(rxframe)); + flush_cache((phys_addr_t)&rxframe, sizeof(rxframe)); /* Start the hardware */ temp = readl(&priv->dmarx->control); @@ -538,7 +538,7 @@ static int axiemac_send(struct udevice *dev, void *ptr, int len) len = PKTSIZE_ALIGN; /* Flush packet to main memory to be trasfered by DMA */ - flush_cache((u32)ptr, len); + flush_cache((phys_addr_t)ptr, len); /* Setup Tx BD */ memset(&tx_bd, 0, sizeof(tx_bd)); @@ -554,7 +554,7 @@ static int axiemac_send(struct udevice *dev, void *ptr, int len) XAXIDMA_BD_CTRL_TXEOF_MASK; /* Flush the last BD so DMA core could see the updates */ - flush_cache((u32)&tx_bd, sizeof(tx_bd)); + flush_cache((phys_addr_t)&tx_bd, sizeof(tx_bd)); if (readl(&priv->dmatx->status) & XAXIDMA_HALTED_MASK) { u32 temp; @@ -654,11 +654,11 @@ static int axiemac_free_pkt(struct udevice *dev, uchar *packet, int length) rx_bd.cntrl = sizeof(rxframe); /* Write bd to HW */ - flush_cache((u32)&rx_bd, sizeof(rx_bd)); + flush_cache((phys_addr_t)&rx_bd, sizeof(rx_bd)); /* It is necessary to flush rxframe because if you don't do it * then cache will contain previous packet */ - flush_cache((u32)&rxframe, sizeof(rxframe)); + flush_cache((phys_addr_t)&rxframe, sizeof(rxframe)); /* Rx BD is ready - start again */ axienet_dma_write(&rx_bd, &priv->dmarx->tail); -- cgit v1.2.3 From b7d4518eed716a483b4efa1e282033f37244ab2d Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 9 Sep 2020 13:25:40 +0200 Subject: fpga: zynqmp: Get rid of ZYNQMP_SIP_SVC* macros There is no need to use these macros because enum pm_api_id can be used instead. Signed-off-by: Michal Simek --- drivers/fpga/zynqmppl.c | 8 ++++---- include/zynqmppl.h | 3 --- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/fpga/zynqmppl.c b/drivers/fpga/zynqmppl.c index 5b103cfeaf..03878d32ec 100644 --- a/drivers/fpga/zynqmppl.c +++ b/drivers/fpga/zynqmppl.c @@ -231,11 +231,11 @@ static int zynqmp_load(xilinx_desc *desc, const void *buf, size_t bsize, buf_hi = upper_32_bits(bin_buf); if (xilfpga_old) - ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo, + ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo, buf_hi, (u32)(uintptr_t)bsizeptr, bstype, ret_payload); else - ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo, + ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo, buf_hi, (u32)bsize, 0, ret_payload); if (ret) @@ -277,7 +277,7 @@ static int zynqmp_loads(xilinx_desc *desc, const void *buf, size_t bsize, buf_lo = lower_32_bits((ulong)buf); buf_hi = upper_32_bits((ulong)buf); - ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo, + ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo, buf_hi, (u32)(uintptr_t)fpga_sec_info->userkey_addr, flag, ret_payload); @@ -295,7 +295,7 @@ static int zynqmp_pcap_info(xilinx_desc *desc) int ret; u32 ret_payload[PAYLOAD_ARG_CNT]; - ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_STATUS, 0, 0, 0, + ret = xilinx_pm_request(PM_FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload); if (!ret) printf("PCAP status\t0x%x\n", ret_payload[1]); diff --git a/include/zynqmppl.h b/include/zynqmppl.h index a0a52ec4c1..35cfe17d44 100644 --- a/include/zynqmppl.h +++ b/include/zynqmppl.h @@ -10,9 +10,6 @@ #include #include -#define ZYNQMP_SIP_SVC_CSU_DMA_CHIPID 0xC2000018 -#define ZYNQMP_SIP_SVC_PM_FPGA_LOAD 0xC2000016 -#define ZYNQMP_SIP_SVC_PM_FPGA_STATUS 0xC2000017 #define ZYNQMP_FPGA_OP_INIT (1 << 0) #define ZYNQMP_FPGA_OP_LOAD (1 << 1) #define ZYNQMP_FPGA_OP_DONE (1 << 2) -- cgit v1.2.3 From 29bd8ada52e186ea6b7f8b633d7aa6296fb097d1 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 9 Sep 2020 14:41:56 +0200 Subject: fpga: kconfig: Rename SPL_FPGA_SUPPORT to SPL_FPGA The patch does sed 's/SPL_FPGA_SUPPORT/SPL_FPGA/g' but also fixing Makefile and zynqmp.c to simplify if/endif logic in zynqmp.c. This change is mostly done to be able to use CONFIG_IS_ENABLED macro and obj-$(CONFIG_$(SPL_)FPGA) in Makefile. For them symbols need to be in sync. And removing one line from Topic Miami boards which is not needed because symbol is not enabled via Kconfig. Signed-off-by: Michal Simek Reviewed-by: Simon Glass --- arch/arm/mach-zynq/cpu.c | 6 ++---- arch/arm/mach-zynq/spl.c | 2 +- board/xilinx/zynqmp/zynqmp.c | 9 ++------- common/spl/Kconfig | 2 +- common/spl/spl_fit.c | 4 ++-- configs/socfpga_arria10_defconfig | 2 +- configs/xilinx_zynq_virt_defconfig | 2 +- drivers/Makefile | 3 +-- include/configs/topic_miami.h | 1 - 9 files changed, 11 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-zynq/cpu.c b/arch/arm/mach-zynq/cpu.c index 77b7cb1307..3befc12028 100644 --- a/arch/arm/mach-zynq/cpu.c +++ b/arch/arm/mach-zynq/cpu.c @@ -17,8 +17,7 @@ #define ZYNQ_SILICON_VER_MASK 0xF0000000 #define ZYNQ_SILICON_VER_SHIFT 28 -#if (defined(CONFIG_FPGA) && !defined(CONFIG_SPL_BUILD)) || \ - (defined(CONFIG_SPL_FPGA_SUPPORT) && defined(CONFIG_SPL_BUILD)) +#if CONFIG_IS_ENABLED(FPGA) xilinx_desc fpga = { .family = xilinx_zynq, .iface = devcfg, @@ -111,8 +110,7 @@ static int __maybe_unused cpu_desc_id(void) #if defined(CONFIG_ARCH_EARLY_INIT_R) int arch_early_init_r(void) { -#if (defined(CONFIG_FPGA) && !defined(CONFIG_SPL_BUILD)) || \ - (defined(CONFIG_SPL_FPGA_SUPPORT) && defined(CONFIG_SPL_BUILD)) +#if CONFIG_IS_ENABLED(FPGA) int cpu_id = cpu_desc_id(); if (cpu_id < 0) diff --git a/arch/arm/mach-zynq/spl.c b/arch/arm/mach-zynq/spl.c index 239ce3436a..cb8cfd2f35 100644 --- a/arch/arm/mach-zynq/spl.c +++ b/arch/arm/mach-zynq/spl.c @@ -34,7 +34,7 @@ void board_init_f(ulong dummy) void spl_board_init(void) { preloader_console_init(); -#if defined(CONFIG_ARCH_EARLY_INIT_R) && defined(CONFIG_SPL_FPGA_SUPPORT) +#if defined(CONFIG_ARCH_EARLY_INIT_R) && defined(CONFIG_SPL_FPGA) arch_early_init_r(); #endif board_init(); diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index e95d13a14c..30f757627f 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -49,10 +49,7 @@ DECLARE_GLOBAL_DATA_PTR; -#if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \ - !defined(CONFIG_SPL_BUILD) || (defined(CONFIG_SPL_FPGA_SUPPORT) && \ - defined(CONFIG_SPL_BUILD)) - +#if CONFIG_IS_ENABLED(FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) static xilinx_desc zynqmppl = XILINX_ZYNQMP_DESC; enum { @@ -331,9 +328,7 @@ int board_init(void) /* Bug in ROM sets wrong value in this register */ writel(PS_SYSMON_ANALOG_BUS_VAL, PS_SYSMON_ANALOG_BUS_REG); -#if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \ - !defined(CONFIG_SPL_BUILD) || (defined(CONFIG_SPL_FPGA_SUPPORT) && \ - defined(CONFIG_SPL_BUILD)) +#if CONFIG_IS_ENABLED(FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) zynqmppl.name = zynqmp_get_silicon_idcode_name(); printf("Chip ID:\t%s\n", zynqmppl.name); fpga_init(); diff --git a/common/spl/Kconfig b/common/spl/Kconfig index af8255a8d6..6e31d75629 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -602,7 +602,7 @@ config SPL_FAT_WRITE Support for the underlying block device (e.g. MMC or USB) must be enabled separately. -config SPL_FPGA_SUPPORT +config SPL_FPGA bool "Support FPGAs" help Enable support for FPGAs in SPL. Field-programmable Gate Arrays diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index a8bfd388b1..0e27ad1d6a 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -253,7 +253,7 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector, const void *data; bool external_data = false; - if (IS_ENABLED(CONFIG_SPL_FPGA_SUPPORT) || + if (IS_ENABLED(CONFIG_SPL_FPGA) || (IS_ENABLED(CONFIG_SPL_OS_BOOT) && IS_ENABLED(CONFIG_SPL_GZIP))) { if (fit_image_get_type(fit, node, &type)) puts("Cannot get image type.\n"); @@ -546,7 +546,7 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, return -1; } -#ifdef CONFIG_SPL_FPGA_SUPPORT +#ifdef CONFIG_SPL_FPGA node = spl_fit_get_image_node(fit, images, "fpga", 0); if (node >= 0) { /* Load the image and set up the spl_image structure */ diff --git a/configs/socfpga_arria10_defconfig b/configs/socfpga_arria10_defconfig index 8fdd21c0d3..5d6fe4f35a 100644 --- a/configs/socfpga_arria10_defconfig +++ b/configs/socfpga_arria10_defconfig @@ -23,7 +23,7 @@ CONFIG_DEFAULT_FDT_FILE="socfpga_arria10_socdk_sdmmc.dtb" CONFIG_VERSION_VARIABLE=y CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_SPL_ENV_SUPPORT=y -CONFIG_SPL_FPGA_SUPPORT=y +CONFIG_SPL_FPGA=y CONFIG_CMD_ASKENV=y CONFIG_CMD_GREPENV=y # CONFIG_CMD_FLASH is not set diff --git a/configs/xilinx_zynq_virt_defconfig b/configs/xilinx_zynq_virt_defconfig index 8acdab25b7..b127945297 100644 --- a/configs/xilinx_zynq_virt_defconfig +++ b/configs/xilinx_zynq_virt_defconfig @@ -20,7 +20,7 @@ CONFIG_SPL_LOAD_FIT_ADDRESS=0x10000000 CONFIG_LEGACY_IMAGE_FORMAT=y CONFIG_USE_PREBOOT=y CONFIG_SPL_STACK_R=y -CONFIG_SPL_FPGA_SUPPORT=y +CONFIG_SPL_FPGA=y CONFIG_SPL_OS_BOOT=y CONFIG_SPL_SPI_LOAD=y # CONFIG_BOOTM_NETBSD is not set diff --git a/drivers/Makefile b/drivers/Makefile index 33126b2da7..9eb51453e5 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm/ obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC) += power/acpi_pmc/ obj-$(CONFIG_$(SPL_)BOARD) += board/ obj-$(CONFIG_XEN) += xen/ +obj-$(CONFIG_$(SPL_)FPGA) += fpga/ ifndef CONFIG_TPL_BUILD ifdef CONFIG_SPL_BUILD @@ -60,7 +61,6 @@ obj-$(CONFIG_SPL_USB_HOST_SUPPORT) += usb/host/ obj-$(CONFIG_OMAP_USB_PHY) += usb/phy/ obj-$(CONFIG_SPL_SATA_SUPPORT) += ata/ scsi/ obj-$(CONFIG_HAVE_BLOCK_DEVICE) += block/ -obj-$(CONFIG_SPL_FPGA_SUPPORT) += fpga/ obj-$(CONFIG_SPL_THERMAL) += thermal/ endif @@ -85,7 +85,6 @@ obj-y += cache/ obj-$(CONFIG_CPU) += cpu/ obj-y += crypto/ obj-$(CONFIG_FASTBOOT) += fastboot/ -obj-$(CONFIG_FPGA) += fpga/ obj-y += misc/ obj-$(CONFIG_MMC) += mmc/ obj-$(CONFIG_NVME) += nvme/ diff --git a/include/configs/topic_miami.h b/include/configs/topic_miami.h index 6e3953835d..010d28ac86 100644 --- a/include/configs/topic_miami.h +++ b/include/configs/topic_miami.h @@ -24,7 +24,6 @@ /* No falcon support */ #undef CONFIG_SPL_OS_BOOT -#undef CONFIG_SPL_FPGA_SUPPORT /* FPGA commands that we don't use */ -- cgit v1.2.3 From a798b8aaf322f5c7818a1d963d63b7516dd5056f Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 10 Sep 2020 12:57:16 +0200 Subject: fpga: zynqmp: Protect zynqmp_loads() for SPL if conditions should match. Fixes: a18d09ea384f ("fpga: zynqmp: Add secure bitstream loading for ZynqMP") Signed-off-by: Michal Simek --- drivers/fpga/zynqmppl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/fpga/zynqmppl.c b/drivers/fpga/zynqmppl.c index 03878d32ec..8ce140a2e1 100644 --- a/drivers/fpga/zynqmppl.c +++ b/drivers/fpga/zynqmppl.c @@ -305,7 +305,7 @@ static int zynqmp_pcap_info(xilinx_desc *desc) struct xilinx_fpga_op zynqmp_op = { .load = zynqmp_load, -#if defined CONFIG_CMD_FPGA_LOAD_SECURE +#if defined(CONFIG_CMD_FPGA_LOAD_SECURE) && !defined(CONFIG_SPL_BUILD) .loads = zynqmp_loads, #endif .info = zynqmp_pcap_info, -- cgit v1.2.3 From 0981ef71bdf2028e4d03cbba54eea8168ab0c77e Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 14 Sep 2020 13:00:40 +0200 Subject: mmc: zynq: Fix incorrect indentation Trivial fix. Fixes: d1f4e39d58db ("mmc: zynq_sdhci: Add support for SD3.0" Signed-off-by: Michal Simek --- drivers/mmc/zynq_sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index e9381b9493..775c17baac 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -191,7 +191,7 @@ static void arasan_sdhci_set_control_reg(struct sdhci_host *host) #if defined(CONFIG_ARCH_ZYNQMP) const struct sdhci_ops arasan_ops = { - .platform_execute_tuning = &arasan_sdhci_execute_tuning, + .platform_execute_tuning = &arasan_sdhci_execute_tuning, .set_delay = &arasan_sdhci_set_tapdelay, .set_control_reg = &arasan_sdhci_set_control_reg, }; -- cgit v1.2.3 From 4ab3817ff16a154981f9394a2c4a0f8f6a72713b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 16 Sep 2020 13:20:55 +0200 Subject: clk: fixed-rate: Enable DM_FLAG_PRE_RELOC flag fixed-rate driver is not different from clk_fixed_factor and it is required very early in boot that's why setup flag for it. Signed-off-by: Michal Simek --- drivers/clk/clk_fixed_rate.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c index 2c20eddb0b..55e1f8caa5 100644 --- a/drivers/clk/clk_fixed_rate.c +++ b/drivers/clk/clk_fixed_rate.c @@ -53,4 +53,5 @@ U_BOOT_DRIVER(clk_fixed_rate) = { .ofdata_to_platdata = clk_fixed_rate_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct clk_fixed_rate), .ops = &clk_fixed_rate_ops, + .flags = DM_FLAG_PRE_RELOC, }; -- cgit v1.2.3 From 15c49df8d4cfbcc02ed28fff2703fb382545caf1 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 16 Jul 2020 18:09:08 +0800 Subject: phy: make phy_connect_fixed work with a null mdio bus It is utterly pointless to require an MDIO bus pointer for a fixed PHY device. The fixed.c implementation does not require it, only phy_device_create. Fix that. Signed-off-by: Vladimir Oltean Signed-off-by: Hou Zhiqiang Reviewed-by: Priyanka Jain --- drivers/net/phy/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 67789897c2..9587e6b9fa 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -664,7 +664,7 @@ static struct phy_device *phy_device_create(struct mii_dev *bus, int addr, dev = malloc(sizeof(*dev)); if (!dev) { printf("Failed to allocate PHY device for %s:%d\n", - bus->name, addr); + bus ? bus->name : "(null bus)", addr); return NULL; } @@ -692,7 +692,7 @@ static struct phy_device *phy_device_create(struct mii_dev *bus, int addr, return NULL; } - if (addr >= 0 && addr < PHY_MAX_ADDR) + if (addr >= 0 && addr < PHY_MAX_ADDR && phy_id != PHY_FIXED_ID) bus->phymap[addr] = dev; return dev; -- cgit v1.2.3 From c54f6139ede01116179bbf1aa2058bc409e59c8a Mon Sep 17 00:00:00 2001 From: Hou Zhiqiang Date: Thu, 16 Jul 2020 18:09:10 +0800 Subject: net: fsl_mdio: Change to use virtual address Use virtual address to access the MII block registers instead of physical address. Signed-off-by: Hou Zhiqiang Reviewed-by: Vladimir Oltean Reviewed-by: Priyanka Jain --- drivers/net/fsl_mdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/fsl_mdio.c b/drivers/net/fsl_mdio.c index d2edd1751c..ae96ce4c7b 100644 --- a/drivers/net/fsl_mdio.c +++ b/drivers/net/fsl_mdio.c @@ -213,7 +213,7 @@ static int tsec_mdio_probe(struct udevice *dev) printf("dev_get_priv(dev %p) = NULL\n", dev); return -1; } - priv->regs = (void *)(uintptr_t)dev_read_addr(dev); + priv->regs = dev_remap_addr(dev); debug("%s priv %p @ regs %p, pdata %p\n", __func__, priv, priv->regs, pdata); -- cgit v1.2.3 From 16c53ce7129b9362a801ffaf1abd496ffb7a5ef5 Mon Sep 17 00:00:00 2001 From: Hou Zhiqiang Date: Thu, 16 Jul 2020 18:09:11 +0800 Subject: net: fsl_mdio: Correct the MII management register block address The MII management register block offset is different between gianfar and etsec2 compatible devices, this patch is to fix this issue by adding driver data for different compatible string. Fixes: 2932c5a802a9 ("net: tsec: fsl_mdio: add DM MDIO support") Signed-off-by: Hou Zhiqiang Reviewed-by: Vladimir Oltean Reviewed-by: Priyanka Jain --- drivers/net/fsl_mdio.c | 28 ++++++++++++++++++++++------ include/fsl_mdio.h | 4 ++++ 2 files changed, 26 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fsl_mdio.c b/drivers/net/fsl_mdio.c index ae96ce4c7b..77f1a96a2e 100644 --- a/drivers/net/fsl_mdio.c +++ b/drivers/net/fsl_mdio.c @@ -11,6 +11,7 @@ #include #include #include +#include #ifdef CONFIG_DM_MDIO struct tsec_mdio_priv { @@ -190,17 +191,30 @@ static const struct mdio_ops tsec_mdio_ops = { .reset = tsec_mdio_reset, }; +static struct fsl_pq_mdio_data etsec2_data = { + .mdio_regs_off = TSEC_MDIO_REGS_OFFSET, +}; + +static struct fsl_pq_mdio_data gianfar_data = { + .mdio_regs_off = 0x0, +}; + +static struct fsl_pq_mdio_data fman_data = { + .mdio_regs_off = 0x0, +}; + static const struct udevice_id tsec_mdio_ids[] = { - { .compatible = "fsl,gianfar-tbi" }, - { .compatible = "fsl,gianfar-mdio" }, - { .compatible = "fsl,etsec2-tbi" }, - { .compatible = "fsl,etsec2-mdio" }, - { .compatible = "fsl,fman-mdio" }, + { .compatible = "fsl,gianfar-tbi", .data = (ulong)&gianfar_data }, + { .compatible = "fsl,gianfar-mdio", .data = (ulong)&gianfar_data }, + { .compatible = "fsl,etsec2-tbi", .data = (ulong)&etsec2_data }, + { .compatible = "fsl,etsec2-mdio", .data = (ulong)&etsec2_data }, + { .compatible = "fsl,fman-mdio", .data = (ulong)&fman_data }, {} }; static int tsec_mdio_probe(struct udevice *dev) { + struct fsl_pq_mdio_data *data; struct tsec_mdio_priv *priv = (dev) ? dev_get_priv(dev) : NULL; struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) : NULL; @@ -213,7 +227,9 @@ static int tsec_mdio_probe(struct udevice *dev) printf("dev_get_priv(dev %p) = NULL\n", dev); return -1; } - priv->regs = dev_remap_addr(dev); + + data = (struct fsl_pq_mdio_data *)dev_get_driver_data(dev); + priv->regs = dev_remap_addr(dev) + data->mdio_regs_off; debug("%s priv %p @ regs %p, pdata %p\n", __func__, priv, priv->regs, pdata); diff --git a/include/fsl_mdio.h b/include/fsl_mdio.h index 41cb73717b..b6c02cf342 100644 --- a/include/fsl_mdio.h +++ b/include/fsl_mdio.h @@ -55,6 +55,10 @@ int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr, int regnum); int memac_mdio_reset(struct mii_dev *bus); +struct fsl_pq_mdio_data { + u32 mdio_regs_off; +}; + struct fsl_pq_mdio_info { struct tsec_mii_mng __iomem *regs; char *name; -- cgit v1.2.3 From b4eb9cfc0978fe77c989f7f3dc86ec86d2ee5006 Mon Sep 17 00:00:00 2001 From: Hou Zhiqiang Date: Thu, 16 Jul 2020 18:09:12 +0800 Subject: net: tsec: convert to use DM_MDIO when DM_ETH enabled For the platforms on which the eTSEC driver uses DM_ETH, convert its MDIO controller code to also use DM_MDIO. Note that for handling the TBI PHY (the MAC PCS for SGMII), we still don't register a udevice for it, since we can drive it locally and there is no point in doing otherwise. Signed-off-by: Vladimir Oltean Signed-off-by: Hou Zhiqiang [Reworked to fix gazerbeam config] Signed-off-by: Priyanka Jain --- drivers/net/tsec.c | 38 +++++--------------------------------- 1 file changed, 5 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 5d12e4b775..6ca399532e 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -681,8 +682,12 @@ static int init_phy(struct tsec_private *priv) if (priv->interface == PHY_INTERFACE_MODE_SGMII) tsec_configure_serdes(priv); +#if defined(CONFIG_DM_ETH) && defined(CONFIG_DM_MDIO) + phydev = dm_eth_phy_connect(priv->dev); +#else phydev = phy_connect(priv->bus, priv->phyaddr, priv->dev, priv->interface); +#endif if (!phydev) return 0; @@ -793,10 +798,8 @@ int tsec_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); struct tsec_private *priv = dev_get_priv(dev); - struct tsec_mii_mng __iomem *ext_phyregs_mii; struct ofnode_phandle_args phandle_args; u32 tbiaddr = CONFIG_SYS_TBIPA_VALUE; - struct fsl_pq_mdio_info mdio_info; const char *phy_mode; fdt_addr_t reg; ofnode parent; @@ -805,31 +808,6 @@ int tsec_probe(struct udevice *dev) pdata->iobase = (phys_addr_t)dev_read_addr(dev); priv->regs = dev_remap_addr(dev); - if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, - &phandle_args)) { - printf("phy-handle does not exist under tsec %s\n", dev->name); - return -ENOENT; - } else { - int reg = ofnode_read_u32_default(phandle_args.node, "reg", 0); - - priv->phyaddr = reg; - } - - parent = ofnode_get_parent(phandle_args.node); - if (!ofnode_valid(parent)) { - printf("No parent node for PHY?\n"); - return -ENOENT; - } - - reg = ofnode_get_addr_index(parent, 0); - if (reg == FDT_ADDR_T_NONE) { - printf("No 'reg' property of MII for external PHY\n"); - return -ENOENT; - } - - ext_phyregs_mii = map_physmem(reg + TSEC_MDIO_REGS_OFFSET, 0, - MAP_NOCACHE); - ret = dev_read_phandle_with_args(dev, "tbi-handle", NULL, 0, 0, &phandle_args); if (ret == 0) { @@ -867,12 +845,6 @@ int tsec_probe(struct udevice *dev) if (priv->interface == PHY_INTERFACE_MODE_SGMII) priv->flags |= TSEC_SGMII; - mdio_info.regs = ext_phyregs_mii; - mdio_info.name = (char *)dev->name; - ret = fsl_pq_mdio_init(NULL, &mdio_info); - if (ret) - return ret; - /* Reset the MAC */ setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ -- cgit v1.2.3 From 25a2e24e942e002353d370489cfeaf0bfcbb0159 Mon Sep 17 00:00:00 2001 From: Hou Zhiqiang Date: Thu, 16 Jul 2020 18:09:13 +0800 Subject: net: tsec: Add fixed-link PHY support The info of fixed-link PHY is described in DT node instead of getting from MII, so detect the fixed-link PHY DT node first, if it doesn't exist then probe the MII. Signed-off-by: Vladimir Oltean Signed-off-by: Hou Zhiqiang [Rebased] Signed-off-by: Priyanka Jain --- drivers/net/tsec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 6ca399532e..af0d27a8e3 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -683,7 +683,10 @@ static int init_phy(struct tsec_private *priv) tsec_configure_serdes(priv); #if defined(CONFIG_DM_ETH) && defined(CONFIG_DM_MDIO) - phydev = dm_eth_phy_connect(priv->dev); + if (ofnode_valid(ofnode_find_subnode(priv->dev->node, "fixed-link"))) + phydev = phy_connect(NULL, 0, priv->dev, priv->interface); + else + phydev = dm_eth_phy_connect(priv->dev); #else phydev = phy_connect(priv->bus, priv->phyaddr, priv->dev, priv->interface); -- cgit v1.2.3 From 7fb568de53cd0276c3e616a9cbf942b71007ed4b Mon Sep 17 00:00:00 2001 From: Hou Zhiqiang Date: Thu, 16 Jul 2020 18:09:14 +0800 Subject: net: tsec: Add the compatible string "gianfar" support Add compatible string "gianfar" support and update the device-tree-bindings doc. Signed-off-by: Hou Zhiqiang Reviewed-by: Vladimir Oltean Reviewed-by: Priyanka Jain --- doc/device-tree-bindings/net/fsl-tsec-phy.txt | 2 +- drivers/net/tsec.c | 16 ++++++++++++++-- include/tsec.h | 4 ++++ 3 files changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/doc/device-tree-bindings/net/fsl-tsec-phy.txt b/doc/device-tree-bindings/net/fsl-tsec-phy.txt index 8e8574bc97..a44c5fd9d9 100644 --- a/doc/device-tree-bindings/net/fsl-tsec-phy.txt +++ b/doc/device-tree-bindings/net/fsl-tsec-phy.txt @@ -2,7 +2,7 @@ Properties: - - compatible : Should be "fsl,etsec2" + - compatible : Should be "fsl,etsec2" or "gianfar" - reg : Offset and length of the register set for the device - phy-handle : See ethernet.txt file in the same directory. - phy-connection-type : See ethernet.txt file in the same directory. This diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index af0d27a8e3..c436b8317d 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -803,11 +803,14 @@ int tsec_probe(struct udevice *dev) struct tsec_private *priv = dev_get_priv(dev); struct ofnode_phandle_args phandle_args; u32 tbiaddr = CONFIG_SYS_TBIPA_VALUE; + struct tsec_data *data; const char *phy_mode; fdt_addr_t reg; ofnode parent; int ret; + data = (struct tsec_data *)dev_get_driver_data(dev); + pdata->iobase = (phys_addr_t)dev_read_addr(dev); priv->regs = dev_remap_addr(dev); @@ -828,7 +831,7 @@ int tsec_probe(struct udevice *dev) return -ENOENT; } - priv->phyregs_sgmii = map_physmem(reg + TSEC_MDIO_REGS_OFFSET, + priv->phyregs_sgmii = map_physmem(reg + data->mdio_regs_off, 0, MAP_NOCACHE); } @@ -880,8 +883,17 @@ static const struct eth_ops tsec_ops = { .mcast = tsec_mcast_addr, }; +static struct tsec_data etsec2_data = { + .mdio_regs_off = TSEC_MDIO_REGS_OFFSET, +}; + +static struct tsec_data gianfar_data = { + .mdio_regs_off = 0x0, +}; + static const struct udevice_id tsec_ids[] = { - { .compatible = "fsl,etsec2" }, + { .compatible = "fsl,etsec2", .data = (ulong)&etsec2_data }, + { .compatible = "gianfar", .data = (ulong)&gianfar_data }, { } }; diff --git a/include/tsec.h b/include/tsec.h index 43255e538f..5433cfd966 100644 --- a/include/tsec.h +++ b/include/tsec.h @@ -394,6 +394,10 @@ struct tsec { #define TX_BUF_CNT 2 +struct tsec_data { + u32 mdio_regs_off; +}; + struct tsec_private { struct txbd8 __iomem txbd[TX_BUF_CNT]; struct rxbd8 __iomem rxbd[PKTBUFSRX]; -- cgit v1.2.3 From 23dd0ea4c7edbde5bc05a1567ba0bf41734ea524 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 22 Sep 2020 12:44:59 -0600 Subject: dm: acpi: Use correct GPIO polarity type in acpi_dp_add_gpio() This function currently accepts the IRQ-polarity type. Fix it to use the GPIO type instead. Signed-off-by: Simon Glass --- drivers/sound/max98357a.c | 2 +- include/acpi/acpi_dp.h | 2 +- lib/acpi/acpi_dp.c | 4 ++-- test/dm/acpi_dp.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/sound/max98357a.c b/drivers/sound/max98357a.c index 841bc6ef68..827262d235 100644 --- a/drivers/sound/max98357a.c +++ b/drivers/sound/max98357a.c @@ -81,7 +81,7 @@ static int max98357a_acpi_fill_ssdt(const struct udevice *dev, dp = acpi_dp_new_table("_DSD"); acpi_dp_add_gpio(dp, "sdmode-gpio", path, 0, 0, priv->sdmode_gpio.flags & GPIOD_ACTIVE_LOW ? - ACPI_IRQ_ACTIVE_LOW : ACPI_IRQ_ACTIVE_HIGH); + ACPI_GPIO_ACTIVE_LOW : ACPI_GPIO_ACTIVE_HIGH); acpi_dp_add_integer(dp, "sdmode-delay", dev_read_u32_default(dev, "sdmode-delay", 0)); acpi_dp_write(ctx, dp); diff --git a/include/acpi/acpi_dp.h b/include/acpi/acpi_dp.h index 0b514bce59..5e539b1d21 100644 --- a/include/acpi/acpi_dp.h +++ b/include/acpi/acpi_dp.h @@ -221,7 +221,7 @@ struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name, */ struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name, const char *ref, int index, int pin, - enum acpi_irq_polarity polarity); + enum acpi_gpio_polarity polarity); /** * acpi_dp_write() - Write Device Property hierarchy and clean up resources diff --git a/lib/acpi/acpi_dp.c b/lib/acpi/acpi_dp.c index 579cab4771..7e3e3259d8 100644 --- a/lib/acpi/acpi_dp.c +++ b/lib/acpi/acpi_dp.c @@ -324,7 +324,7 @@ struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name, struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name, const char *ref, int index, int pin, - enum acpi_irq_polarity polarity) + enum acpi_gpio_polarity polarity) { struct acpi_dp *gpio; @@ -336,7 +336,7 @@ struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name, if (!acpi_dp_add_reference(gpio, NULL, ref) || !acpi_dp_add_integer(gpio, NULL, index) || !acpi_dp_add_integer(gpio, NULL, pin) || - !acpi_dp_add_integer(gpio, NULL, polarity == ACPI_IRQ_ACTIVE_LOW)) + !acpi_dp_add_integer(gpio, NULL, polarity == ACPI_GPIO_ACTIVE_LOW)) return NULL; if (!acpi_dp_add_array(dp, gpio)) diff --git a/test/dm/acpi_dp.c b/test/dm/acpi_dp.c index e0fa61263c..44bcabda6b 100644 --- a/test/dm/acpi_dp.c +++ b/test/dm/acpi_dp.c @@ -398,9 +398,9 @@ static int dm_test_acpi_dp_gpio(struct unit_test_state *uts) /* Try a few different parameters */ ut_assertnonnull(acpi_dp_add_gpio(dp, "reset", TEST_REF, 0x23, 0x24, - ACPI_IRQ_ACTIVE_HIGH)); + ACPI_GPIO_ACTIVE_HIGH)); ut_assertnonnull(acpi_dp_add_gpio(dp, "allow", TEST_REF, 0, 0, - ACPI_IRQ_ACTIVE_LOW)); + ACPI_GPIO_ACTIVE_LOW)); ptr = acpigen_get_current(ctx); ut_assertok(acpi_dp_write(ctx, dp)); -- cgit v1.2.3 From fd42f263cef9fd6bba9ded76a82d4ac66450e156 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 22 Sep 2020 12:45:01 -0600 Subject: i2c: Add a generic driver to generate ACPI info Many I2C devices produce roughly the same ACPI data with just things like the GPIO/interrupt information being different. This can be handled by a generic driver along with some information in the device tree. Add a generic i2c driver for this purpose. Signed-off-by: Simon Glass Reviewed-by: Heiko Schocher --- doc/device-tree-bindings/i2c/generic-acpi.txt | 42 +++++ drivers/i2c/Makefile | 3 + drivers/i2c/acpi_i2c.c | 226 ++++++++++++++++++++++++++ drivers/i2c/acpi_i2c.h | 15 ++ drivers/i2c/i2c-uclass.c | 17 ++ include/acpi/acpi_device.h | 55 +++++++ include/i2c.h | 23 +++ 7 files changed, 381 insertions(+) create mode 100644 doc/device-tree-bindings/i2c/generic-acpi.txt create mode 100644 drivers/i2c/acpi_i2c.c create mode 100644 drivers/i2c/acpi_i2c.h (limited to 'drivers') diff --git a/doc/device-tree-bindings/i2c/generic-acpi.txt b/doc/device-tree-bindings/i2c/generic-acpi.txt new file mode 100644 index 0000000000..3510a71b57 --- /dev/null +++ b/doc/device-tree-bindings/i2c/generic-acpi.txt @@ -0,0 +1,42 @@ +I2C generic device +================== + +This is used only to generate ACPI tables for an I2C device. + +Required properties : + + - compatible : "i2c-chip"; + - reg : I2C chip address + - acpi,hid : HID name for the device + +Optional properies in addition to device.txt: + + - reset-gpios : GPIO used to assert reset to the device + - irq-gpios : GPIO used for interrupt (if Interrupt is not used) + - stop-gpios : GPIO used to stop the device + - interrupts-extended : Interrupt to use for the device + - reset-delay-ms : Delay after de-asserting reset, in ms + - reset-off-delay-ms : Delay after asserting reset (during power off) + - enable-delay-ms : Delay after asserting enable + - enable-off-delay-ms : Delay after de-asserting enable (during power off) + - stop-delay-ms : Delay after de-aserting stop + - stop-off-delay-ms : Delay after asserting stop (during power off) + - hid-descr-addr : HID register offset (for Human Interface Devices) + +Example +------- + + elan-touchscreen@10 { + compatible = "i2c-chip"; + reg = <0x10>; + acpi,hid = "ELAN0001"; + acpi,ddn = "ELAN Touchscreen"; + interrupts-extended = <&acpi_gpe GPIO_21_IRQ + IRQ_TYPE_EDGE_FALLING>; + linux,probed; + reset-gpios = <&gpio_n GPIO_36 GPIO_ACTIVE_HIGH>; + reset-delay-ms = <20>; + enable-gpios = <&gpio_n GPIO_152 GPIO_ACTIVE_HIGH>; + enable-delay-ms = <1>; + acpi,has-power-resource; + }; diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index f7b2786448..bd248cbf52 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -3,6 +3,9 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. obj-$(CONFIG_DM_I2C) += i2c-uclass.o +ifdef CONFIG_ACPIGEN +obj-$(CONFIG_DM_I2C) += acpi_i2c.o +endif obj-$(CONFIG_DM_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_$(SPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o obj-$(CONFIG_$(SPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o diff --git a/drivers/i2c/acpi_i2c.c b/drivers/i2c/acpi_i2c.c new file mode 100644 index 0000000000..57d29683cb --- /dev/null +++ b/drivers/i2c/acpi_i2c.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_X86 +#include +#endif +#include +#include + +static bool acpi_i2c_add_gpios_to_crs(struct acpi_i2c_priv *priv) +{ + /* + * Return false if: + * 1. Request to explicitly disable export of GPIOs in CRS, or + * 2. Both reset and enable GPIOs are not provided. + */ + if (priv->disable_gpio_export_in_crs || + (!dm_gpio_is_valid(&priv->reset_gpio) && + !dm_gpio_is_valid(&priv->enable_gpio))) + return false; + + return true; +} + +static int acpi_i2c_write_gpio(struct acpi_ctx *ctx, struct gpio_desc *gpio, + int *curindex) +{ + int ret; + + if (!dm_gpio_is_valid(gpio)) + return -ENOENT; + + acpi_device_write_gpio_desc(ctx, gpio); + ret = *curindex; + (*curindex)++; + + return ret; +} + +int acpi_i2c_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx) +{ + int reset_gpio_index = -1, enable_gpio_index = -1, irq_gpio_index = -1; + enum i2c_device_t type = dev_get_driver_data(dev); + struct acpi_i2c_priv *priv = dev_get_priv(dev); + struct acpi_dp *dsd = NULL; + char scope[ACPI_PATH_MAX]; + char name[ACPI_NAME_MAX]; + int tx_state_val; + int curindex = 0; + int ret; + +#ifdef CONFIG_X86 + tx_state_val = PAD_CFG0_TX_STATE; +#elif defined(CONFIG_SANDBOX) + tx_state_val = BIT(7); /* test value */ +#else +#error "Not supported on this architecture" +#endif + ret = acpi_get_name(dev, name); + if (ret) + return log_msg_ret("name", ret); + ret = acpi_device_scope(dev, scope, sizeof(scope)); + if (ret) + return log_msg_ret("scope", ret); + + /* Device */ + acpigen_write_scope(ctx, scope); + acpigen_write_device(ctx, name); + acpigen_write_name_string(ctx, "_HID", priv->hid); + if (type == I2C_DEVICE_HID_OVER_I2C) + acpigen_write_name_string(ctx, "_CID", "PNP0C50"); + acpigen_write_name_integer(ctx, "_UID", priv->uid); + acpigen_write_name_string(ctx, "_DDN", priv->desc); + acpigen_write_sta(ctx, acpi_device_status(dev)); + + /* Resources */ + acpigen_write_name(ctx, "_CRS"); + acpigen_write_resourcetemplate_header(ctx); + acpi_device_write_i2c_dev(ctx, dev); + + /* Use either Interrupt() or GpioInt() */ + if (dm_gpio_is_valid(&priv->irq_gpio)) { + irq_gpio_index = acpi_i2c_write_gpio(ctx, &priv->irq_gpio, + &curindex); + } else { + ret = acpi_device_write_interrupt_irq(ctx, &priv->irq); + if (ret < 0) + return log_msg_ret("irq", ret); + } + + if (acpi_i2c_add_gpios_to_crs(priv)) { + reset_gpio_index = acpi_i2c_write_gpio(ctx, &priv->reset_gpio, + &curindex); + enable_gpio_index = acpi_i2c_write_gpio(ctx, &priv->enable_gpio, + &curindex); + } + acpigen_write_resourcetemplate_footer(ctx); + + /* Wake capabilities */ + if (priv->wake) { + acpigen_write_name_integer(ctx, "_S0W", 4); + acpigen_write_prw(ctx, priv->wake, 3); + } + + /* DSD */ + if (priv->probed || priv->property_count || priv->compat_string || + reset_gpio_index >= 0 || enable_gpio_index >= 0 || + irq_gpio_index >= 0) { + char path[ACPI_PATH_MAX]; + + ret = acpi_device_path(dev, path, sizeof(path)); + if (ret) + return log_msg_ret("path", ret); + + dsd = acpi_dp_new_table("_DSD"); + if (priv->compat_string) + acpi_dp_add_string(dsd, "compatible", + priv->compat_string); + if (priv->probed) + acpi_dp_add_integer(dsd, "linux,probed", 1); + if (irq_gpio_index >= 0) + acpi_dp_add_gpio(dsd, "irq-gpios", path, + irq_gpio_index, 0, + priv->irq_gpio.flags & + GPIOD_ACTIVE_LOW ? + ACPI_GPIO_ACTIVE_LOW : 0); + if (reset_gpio_index >= 0) + acpi_dp_add_gpio(dsd, "reset-gpios", path, + reset_gpio_index, 0, + priv->reset_gpio.flags & + GPIOD_ACTIVE_LOW ? + ACPI_GPIO_ACTIVE_LOW : 0); + if (enable_gpio_index >= 0) + acpi_dp_add_gpio(dsd, "enable-gpios", path, + enable_gpio_index, 0, + priv->enable_gpio.flags & + GPIOD_ACTIVE_LOW ? + ACPI_GPIO_ACTIVE_LOW : 0); + /* Generic property list is not supported */ + acpi_dp_write(ctx, dsd); + } + + /* Power Resource */ + if (priv->has_power_resource) { + ret = acpi_device_add_power_res(ctx, tx_state_val, + "\\_SB.GPC0", "\\_SB.SPC0", + &priv->reset_gpio, priv->reset_delay_ms, + priv->reset_off_delay_ms, &priv->enable_gpio, + priv->enable_delay_ms, priv->enable_off_delay_ms, + &priv->stop_gpio, priv->stop_delay_ms, + priv->stop_off_delay_ms); + if (ret) + return log_msg_ret("power", ret); + } + if (priv->hid_desc_reg_offset) { + ret = acpi_device_write_dsm_i2c_hid(ctx, + priv->hid_desc_reg_offset); + if (ret) + return log_msg_ret("dsm", ret); + } + + acpigen_pop_len(ctx); /* Device */ + acpigen_pop_len(ctx); /* Scope */ + + return 0; +} + +int acpi_i2c_ofdata_to_platdata(struct udevice *dev) +{ + struct acpi_i2c_priv *priv = dev_get_priv(dev); + + gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset_gpio, + GPIOD_IS_OUT); + gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable_gpio, + GPIOD_IS_OUT); + gpio_request_by_name(dev, "irq-gpios", 0, &priv->irq_gpio, GPIOD_IS_IN); + gpio_request_by_name(dev, "stop-gpios", 0, &priv->stop_gpio, + GPIOD_IS_OUT); + irq_get_by_index(dev, 0, &priv->irq); + priv->hid = dev_read_string(dev, "acpi,hid"); + if (!priv->hid) + return log_msg_ret("hid", -EINVAL); + dev_read_u32(dev, "acpi,uid", &priv->uid); + priv->desc = dev_read_string(dev, "acpi,ddn"); + dev_read_u32(dev, "acpi,wake", &priv->wake); + priv->probed = dev_read_bool(dev, "linux,probed"); + priv->compat_string = dev_read_string(dev, "acpi,compatible"); + priv->has_power_resource = dev_read_bool(dev, + "acpi,has-power-resource"); + dev_read_u32(dev, "hid-descr-addr", &priv->hid_desc_reg_offset); + dev_read_u32(dev, "reset-delay-ms", &priv->reset_delay_ms); + dev_read_u32(dev, "reset-off-delay-ms", &priv->reset_off_delay_ms); + dev_read_u32(dev, "enable-delay-ms", &priv->enable_delay_ms); + dev_read_u32(dev, "enable-off-delay-ms", &priv->enable_off_delay_ms); + dev_read_u32(dev, "stop-delay-ms", &priv->stop_delay_ms); + dev_read_u32(dev, "stop-off-delay-ms", &priv->stop_off_delay_ms); + + return 0; +} + +/* Use name specified in priv or build one from I2C address */ +static int acpi_i2c_get_name(const struct udevice *dev, char *out_name) +{ + struct dm_i2c_chip *chip = dev_get_parent_platdata(dev); + struct acpi_i2c_priv *priv = dev_get_priv(dev); + + snprintf(out_name, ACPI_NAME_MAX, + priv->hid_desc_reg_offset ? "H%03X" : "D%03X", + chip->chip_addr); + + return 0; +} + +struct acpi_ops acpi_i2c_ops = { + .fill_ssdt = acpi_i2c_fill_ssdt, + .get_name = acpi_i2c_get_name, +}; diff --git a/drivers/i2c/acpi_i2c.h b/drivers/i2c/acpi_i2c.h new file mode 100644 index 0000000000..1f4be29601 --- /dev/null +++ b/drivers/i2c/acpi_i2c.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2019 Google LLC + */ + +#ifndef __ACPI_I2C_H +#define __ACPI_I2C_H + +#include + +extern struct acpi_ops acpi_i2c_ops; + +int acpi_i2c_ofdata_to_platdata(struct udevice *dev); + +#endif diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index 2373aa2ea4..5c4626b044 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -16,6 +18,7 @@ #include #endif #include +#include "acpi_i2c.h" #define I2C_MAX_OFFSET_LEN 4 @@ -749,7 +752,21 @@ UCLASS_DRIVER(i2c_generic) = { .name = "i2c_generic", }; +static const struct udevice_id generic_chip_i2c_ids[] = { + { .compatible = "i2c-chip", .data = I2C_DEVICE_GENERIC }, +#if CONFIG_IS_ENABLED(ACPIGEN) + { .compatible = "hid-over-i2c", .data = I2C_DEVICE_HID_OVER_I2C }, +#endif + { } +}; + U_BOOT_DRIVER(i2c_generic_chip_drv) = { .name = "i2c_generic_chip_drv", .id = UCLASS_I2C_GENERIC, + .of_match = generic_chip_i2c_ids, +#if CONFIG_IS_ENABLED(ACPIGEN) + .ofdata_to_platdata = acpi_i2c_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct acpi_i2c_priv), +#endif + ACPI_OPS_PTR(&acpi_i2c_ops) }; diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h index a5b1221782..1b838fcb85 100644 --- a/include/acpi/acpi_device.h +++ b/include/acpi/acpi_device.h @@ -10,7 +10,9 @@ #define __ACPI_DEVICE_H #include +#include #include +#include #include struct acpi_ctx; @@ -235,6 +237,59 @@ struct acpi_spi { const char *resource; }; +/** + * struct acpi_i2c_priv - Information read from device tree + * + * This is used by devices which want to specify various pieces of ACPI + * information, including power control. It allows a generic function to + * generate the information for ACPI, based on device-tree properties. + * + * @disable_gpio_export_in_crs: Don't export GPIOs in the CRS + * @reset_gpio: GPIO used to assert reset to the device + * @enable_gpio: GPIO used to enable the device + * @stop_gpio: GPIO used to stop the device + * @irq_gpio: GPIO used for interrupt (if @irq is not used) + * @irq: IRQ used for interrupt (if @irq_gpio is not used) + * @hid: _HID value for device (required) + * @uid: _UID value for device + * @desc: _DDN value for device + * @wake: Wake event, e.g. GPE0_DW1_15; 0 if none + * @property_count: Number of other DSD properties (currently always 0) + * @probed: true set set 'linux,probed' property + * @compat_string: Device tree compatible string to report through ACPI + * @has_power_resource: true if this device has a power resource + * @reset_delay_ms: Delay after de-asserting reset, in ms + * @reset_off_delay_ms: Delay after asserting reset (during power off) + * @enable_delay_ms: Delay after asserting enable + * @enable_off_delay_ms: Delay after de-asserting enable (during power off) + * @stop_delay_ms: Delay after de-aserting stop + * @stop_off_delay_ms: Delay after asserting stop (during power off) + * @hid_desc_reg_offset: HID register offset (for Human Interface Devices) + */ +struct acpi_i2c_priv { + bool disable_gpio_export_in_crs; + struct gpio_desc reset_gpio; + struct gpio_desc enable_gpio; + struct gpio_desc irq_gpio; + struct gpio_desc stop_gpio; + struct irq irq; + const char *hid; + u32 uid; + const char *desc; + u32 wake; + u32 property_count; + bool probed; + const char *compat_string; + bool has_power_resource; + u32 reset_delay_ms; + u32 reset_off_delay_ms; + u32 enable_delay_ms; + u32 enable_off_delay_ms; + u32 stop_delay_ms; + u32 stop_off_delay_ms; + u32 hid_desc_reg_offset; +}; + /** * acpi_device_path() - Get the full path to an ACPI device * diff --git a/include/i2c.h b/include/i2c.h index 1d792db454..880aa8032b 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -58,6 +58,12 @@ enum i2c_address_mode { I2C_MODE_10_BIT }; +/** enum i2c_device_t - Types of I2C devices, used for compatible strings */ +enum i2c_device_t { + I2C_DEVICE_GENERIC, + I2C_DEVICE_HID_OVER_I2C, +}; + struct udevice; /** * struct dm_i2c_chip - information about an i2c chip @@ -558,6 +564,23 @@ int i2c_emul_find(struct udevice *dev, struct udevice **emulp); */ struct udevice *i2c_emul_get_device(struct udevice *emul); +/* ACPI operations for generic I2C devices */ +extern struct acpi_ops i2c_acpi_ops; + +/** + * acpi_i2c_ofdata_to_platdata() - Read properties intended for ACPI + * + * This reads the generic I2C properties from the device tree, so that these + * can be used to create ACPI information for the device. + * + * See the i2c/generic-acpi.txt binding file for information about the + * properties. + * + * @dev: I2C device to process + * @return 0 if OK, -EINVAL if acpi,hid is not present + */ +int acpi_i2c_ofdata_to_platdata(struct udevice *dev); + #ifndef CONFIG_DM_I2C /* -- cgit v1.2.3 From 9b3e6d4c1f86b27f320ef9c5857a9ef223b2b356 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 22 Sep 2020 12:45:14 -0600 Subject: x86: acpi: Add common Intel ACPI tables Add various tables that are common to Intel CPUs. These functions can be used by arch-specific CPU code. Signed-off-by: Simon Glass --- arch/x86/cpu/intel_common/Makefile | 2 + arch/x86/cpu/intel_common/acpi.c | 377 +++++++++++++++++++++++++++++++++++++ arch/x86/cpu/intel_common/cpu.c | 14 ++ arch/x86/include/asm/acpi_table.h | 22 +++ arch/x86/include/asm/cpu_common.h | 7 + arch/x86/include/asm/intel_acpi.h | 52 +++++ drivers/core/Kconfig | 9 + 7 files changed, 483 insertions(+) create mode 100644 arch/x86/cpu/intel_common/acpi.c create mode 100644 arch/x86/include/asm/intel_acpi.h (limited to 'drivers') diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index f1d1513a98..4a5cf17e41 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -2,6 +2,8 @@ # # Copyright (c) 2016 Google, Inc +obj-$(CONFIG_INTEL_ACPIGEN) += acpi.o + ifdef CONFIG_HAVE_MRC obj-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += car.o obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += me_status.o diff --git a/arch/x86/cpu/intel_common/acpi.c b/arch/x86/cpu/intel_common/acpi.c new file mode 100644 index 0000000000..a4d5fbd38a --- /dev/null +++ b/arch/x86/cpu/intel_common/acpi.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Generic Intel ACPI table generation + * + * Copyright (C) 2017 Intel Corp. + * Copyright 2019 Google LLC + * + * Modified from coreboot src/soc/intel/common/block/acpi.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +u32 acpi_fill_mcfg(u32 current) +{ + /* PCI Segment Group 0, Start Bus Number 0, End Bus Number is 255 */ + current += acpi_create_mcfg_mmconfig((void *)current, + CONFIG_MMCONF_BASE_ADDRESS, 0, 0, + (CONFIG_SA_PCIEX_LENGTH >> 20) + - 1); + return current; +} + +static int acpi_sci_irq(void) +{ + int sci_irq = 9; + uint scis; + int ret; + + ret = arch_read_sci_irq_select(); + if (IS_ERR_VALUE(ret)) + return log_msg_ret("sci_irq", ret); + scis = ret; + scis &= SCI_IRQ_MASK; + scis >>= SCI_IRQ_SHIFT; + + /* Determine how SCI is routed. */ + switch (scis) { + case SCIS_IRQ9: + case SCIS_IRQ10: + case SCIS_IRQ11: + sci_irq = scis - SCIS_IRQ9 + 9; + break; + case SCIS_IRQ20: + case SCIS_IRQ21: + case SCIS_IRQ22: + case SCIS_IRQ23: + sci_irq = scis - SCIS_IRQ20 + 20; + break; + default: + log_warning("Invalid SCI route! Defaulting to IRQ9\n"); + sci_irq = 9; + break; + } + + log_debug("SCI is IRQ%d\n", sci_irq); + + return sci_irq; +} + +static unsigned long acpi_madt_irq_overrides(unsigned long current) +{ + int sci = acpi_sci_irq(); + u16 flags = MP_IRQ_TRIGGER_LEVEL; + + if (sci < 0) + return log_msg_ret("sci irq", sci); + + /* INT_SRC_OVR */ + current += acpi_create_madt_irqoverride((void *)current, 0, 0, 2, 0); + + flags |= arch_madt_sci_irq_polarity(sci); + + /* SCI */ + current += + acpi_create_madt_irqoverride((void *)current, 0, sci, sci, flags); + + return current; +} + +u32 acpi_fill_madt(u32 current) +{ + /* Local APICs */ + current += acpi_create_madt_lapics(current); + + /* IOAPIC */ + current += acpi_create_madt_ioapic((void *)current, 2, IO_APIC_ADDR, 0); + + return acpi_madt_irq_overrides(current); +} + +void intel_acpi_fill_fadt(struct acpi_fadt *fadt) +{ + const u16 pmbase = IOMAP_ACPI_BASE; + + /* Use ACPI 3.0 revision. */ + fadt->header.revision = acpi_get_table_revision(ACPITAB_FADT); + + fadt->sci_int = acpi_sci_irq(); + fadt->smi_cmd = APM_CNT; + fadt->acpi_enable = APM_CNT_ACPI_ENABLE; + fadt->acpi_disable = APM_CNT_ACPI_DISABLE; + fadt->s4bios_req = 0x0; + fadt->pstate_cnt = 0; + + fadt->pm1a_evt_blk = pmbase + PM1_STS; + fadt->pm1b_evt_blk = 0x0; + fadt->pm1a_cnt_blk = pmbase + PM1_CNT; + fadt->pm1b_cnt_blk = 0x0; + + fadt->gpe0_blk = pmbase + GPE0_STS; + + fadt->pm1_evt_len = 4; + fadt->pm1_cnt_len = 2; + + /* GPE0 STS/EN pairs each 32 bits wide. */ + fadt->gpe0_blk_len = 2 * GPE0_REG_MAX * sizeof(uint32_t); + + fadt->flush_size = 0x400; /* twice of cache size */ + fadt->flush_stride = 0x10; /* Cache line width */ + fadt->duty_offset = 1; + fadt->day_alrm = 0xd; + + fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED | + ACPI_FADT_C2_MP_SUPPORTED | ACPI_FADT_SLEEP_BUTTON | + ACPI_FADT_RESET_REGISTER | ACPI_FADT_SEALED_CASE | + ACPI_FADT_S4_RTC_WAKE | ACPI_FADT_PLATFORM_CLOCK; + + fadt->reset_reg.space_id = 1; + fadt->reset_reg.bit_width = 8; + fadt->reset_reg.addrl = IO_PORT_RESET; + fadt->reset_value = RST_CPU | SYS_RST; + + fadt->x_pm1a_evt_blk.space_id = 1; + fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8; + fadt->x_pm1a_evt_blk.addrl = pmbase + PM1_STS; + + fadt->x_pm1b_evt_blk.space_id = 1; + + fadt->x_pm1a_cnt_blk.space_id = 1; + fadt->x_pm1a_cnt_blk.bit_width = fadt->pm1_cnt_len * 8; + fadt->x_pm1a_cnt_blk.addrl = pmbase + PM1_CNT; + + fadt->x_pm1b_cnt_blk.space_id = 1; + + fadt->x_gpe1_blk.space_id = 1; +} + +int intel_southbridge_write_acpi_tables(const struct udevice *dev, + struct acpi_ctx *ctx) +{ + int ret; + + ret = acpi_write_dbg2_pci_uart(ctx, gd->cur_serial_dev, + ACPI_ACCESS_SIZE_DWORD_ACCESS); + if (ret) + return log_msg_ret("dbg2", ret); + + ret = acpi_write_hpet(ctx); + if (ret) + return log_msg_ret("hpet", ret); + + return 0; +} + +__weak u32 acpi_fill_soc_wake(u32 generic_pm1_en, + const struct chipset_power_state *ps) +{ + return generic_pm1_en; +} + +__weak int acpi_create_gnvs(struct acpi_global_nvs *gnvs) +{ + return 0; +} + +int southbridge_inject_dsdt(const struct udevice *dev, struct acpi_ctx *ctx) +{ + struct acpi_global_nvs *gnvs; + int ret; + + ret = bloblist_ensure_size(BLOBLISTT_ACPI_GNVS, sizeof(*gnvs), + (void **)&gnvs); + if (ret) + return log_msg_ret("bloblist", ret); + memset(gnvs, '\0', sizeof(*gnvs)); + + ret = acpi_create_gnvs(gnvs); + if (ret) + return log_msg_ret("gnvs", ret); + + /* + * TODO(sjg@chromum.org): tell SMI about it + * smm_setup_structures(gnvs, NULL, NULL); + */ + + /* Add it to DSDT */ + acpigen_write_scope(ctx, "\\"); + acpigen_write_name_dword(ctx, "NVSA", (uintptr_t)gnvs); + acpigen_pop_len(ctx); + + return 0; +} + +static int calculate_power(int tdp, int p1_ratio, int ratio) +{ + u32 m; + u32 power; + + /* + * M = ((1.1 - ((p1_ratio - ratio) * 0.00625)) / 1.1) ^ 2 + * + * Power = (ratio / p1_ratio) * m * tdp + */ + + m = (110000 - ((p1_ratio - ratio) * 625)) / 11; + m = (m * m) / 1000; + + power = ((ratio * 100000 / p1_ratio) / 100); + power *= (m / 100) * (tdp / 1000); + power /= 1000; + + return power; +} + +void generate_p_state_entries(struct acpi_ctx *ctx, int core, + int cores_per_package) +{ + int ratio_min, ratio_max, ratio_turbo, ratio_step; + int coord_type, power_max, num_entries; + int ratio, power, clock, clock_max; + bool turbo; + + coord_type = cpu_get_coord_type(); + ratio_min = cpu_get_min_ratio(); + ratio_max = cpu_get_max_ratio(); + clock_max = (ratio_max * cpu_get_bus_clock_khz()) / 1000; + turbo = (turbo_get_state() == TURBO_ENABLED); + + /* Calculate CPU TDP in mW */ + power_max = cpu_get_power_max(); + + /* Write _PCT indicating use of FFixedHW */ + acpigen_write_empty_pct(ctx); + + /* Write _PPC with no limit on supported P-state */ + acpigen_write_ppc_nvs(ctx); + /* Write PSD indicating configured coordination type */ + acpigen_write_psd_package(ctx, core, 1, coord_type); + + /* Add P-state entries in _PSS table */ + acpigen_write_name(ctx, "_PSS"); + + /* Determine ratio points */ + ratio_step = PSS_RATIO_STEP; + do { + num_entries = ((ratio_max - ratio_min) / ratio_step) + 1; + if (((ratio_max - ratio_min) % ratio_step) > 0) + num_entries += 1; + if (turbo) + num_entries += 1; + if (num_entries > PSS_MAX_ENTRIES) + ratio_step += 1; + } while (num_entries > PSS_MAX_ENTRIES); + + /* _PSS package count depends on Turbo */ + acpigen_write_package(ctx, num_entries); + + /* P[T] is Turbo state if enabled */ + if (turbo) { + ratio_turbo = cpu_get_max_turbo_ratio(); + + /* Add entry for Turbo ratio */ + acpigen_write_pss_package(ctx, clock_max + 1, /* MHz */ + power_max, /* mW */ + PSS_LATENCY_TRANSITION,/* lat1 */ + PSS_LATENCY_BUSMASTER,/* lat2 */ + ratio_turbo << 8, /* control */ + ratio_turbo << 8); /* status */ + num_entries -= 1; + } + + /* First regular entry is max non-turbo ratio */ + acpigen_write_pss_package(ctx, clock_max, /* MHz */ + power_max, /* mW */ + PSS_LATENCY_TRANSITION,/* lat1 */ + PSS_LATENCY_BUSMASTER,/* lat2 */ + ratio_max << 8, /* control */ + ratio_max << 8); /* status */ + num_entries -= 1; + + /* Generate the remaining entries */ + for (ratio = ratio_min + ((num_entries - 1) * ratio_step); + ratio >= ratio_min; ratio -= ratio_step) { + /* Calculate power at this ratio */ + power = calculate_power(power_max, ratio_max, ratio); + clock = (ratio * cpu_get_bus_clock_khz()) / 1000; + + acpigen_write_pss_package(ctx, clock, /* MHz */ + power, /* mW */ + PSS_LATENCY_TRANSITION,/* lat1 */ + PSS_LATENCY_BUSMASTER,/* lat2 */ + ratio << 8, /* control */ + ratio << 8); /* status */ + } + /* Fix package length */ + acpigen_pop_len(ctx); +} + +void generate_t_state_entries(struct acpi_ctx *ctx, int core, + int cores_per_package, struct acpi_tstate *entry, + int nentries) +{ + if (!nentries) + return; + + /* Indicate SW_ALL coordination for T-states */ + acpigen_write_tsd_package(ctx, core, cores_per_package, SW_ALL); + + /* Indicate FixedHW so OS will use MSR */ + acpigen_write_empty_ptc(ctx); + + /* Set NVS controlled T-state limit */ + acpigen_write_tpc(ctx, "\\TLVL"); + + /* Write TSS table for MSR access */ + acpigen_write_tss_package(ctx, entry, nentries); +} + +int acpi_generate_cpu_header(struct acpi_ctx *ctx, int core_id, + const struct acpi_cstate *c_state_map, + int num_cstates) +{ + bool is_first = !core_id; + + /* Generate processor \_PR.CPUx */ + acpigen_write_processor(ctx, core_id, is_first ? ACPI_BASE_ADDRESS : 0, + is_first ? 6 : 0); + + /* Generate C-state tables */ + acpigen_write_cst_package(ctx, c_state_map, num_cstates); + + return 0; +} + +int acpi_generate_cpu_package_final(struct acpi_ctx *ctx, int cores_per_package) +{ + /* + * PPKG is usually used for thermal management of the first and only + * package + */ + acpigen_write_processor_package(ctx, "PPKG", 0, cores_per_package); + + /* Add a method to notify processor nodes */ + acpigen_write_processor_cnot(ctx, cores_per_package); + + return 0; +} diff --git a/arch/x86/cpu/intel_common/cpu.c b/arch/x86/cpu/intel_common/cpu.c index cb4ef84013..d8a3d60ae7 100644 --- a/arch/x86/cpu/intel_common/cpu.c +++ b/arch/x86/cpu/intel_common/cpu.c @@ -291,3 +291,17 @@ int cpu_get_max_turbo_ratio(void) return msr.lo & 0xff; } + +int cpu_get_cores_per_package(void) +{ + struct cpuid_result result; + int cores = 1; + + if (gd->arch.x86_vendor != X86_VENDOR_INTEL) + return 1; + + result = cpuid_ext(0xb, 1); + cores = result.ebx & 0xff; + + return cores; +} diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h index 1b7ff50951..3245e44781 100644 --- a/arch/x86/include/asm/acpi_table.h +++ b/arch/x86/include/asm/acpi_table.h @@ -76,4 +76,26 @@ ulong write_acpi_tables(ulong start); */ ulong acpi_get_rsdp_addr(void); +/** + * arch_read_sci_irq_select() - Read the system-control interrupt number + * + * @returns value of IRQ register in the PMC + */ +int arch_read_sci_irq_select(void); + +/** + * arch_write_sci_irq_select() - Set the system-control interrupt number + * + * @scis: New value for IRQ register in the PMC + */ +int arch_write_sci_irq_select(uint scis); + +/** + * arch_madt_sci_irq_polarity() - Return the priority to use for the MADT + * + * @sci: System-control interrupt number + * @return priority to use (MP_IRQ_POLARITY_...) + */ +int arch_madt_sci_irq_polarity(int sci); + #endif /* __ASM_ACPI_TABLE_H__ */ diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h index a7b7112d41..48f56c2aad 100644 --- a/arch/x86/include/asm/cpu_common.h +++ b/arch/x86/include/asm/cpu_common.h @@ -177,4 +177,11 @@ int cpu_get_power_max(void); */ int cpu_get_max_turbo_ratio(void); +/** + * cpu_get_cores_per_package() - Get the number of CPU cores in each package + * + * @return number of cores + */ +int cpu_get_cores_per_package(void); + #endif diff --git a/arch/x86/include/asm/intel_acpi.h b/arch/x86/include/asm/intel_acpi.h new file mode 100644 index 0000000000..a5781f1af4 --- /dev/null +++ b/arch/x86/include/asm/intel_acpi.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018, Bin Meng + */ + +#ifndef __ASM_INTEL_ACPI_H__ +#define __ASM_INTEL_ACPI_H__ + +struct acpi_cstate; +struct acpi_ctx; +struct acpi_tstate; +struct udevice; + +/** + * acpi_generate_cpu_header() - Start generating an ACPI CPU entry + * + * Generates the ACPI information for a CPU. After this, the caller should + * generate_p_state_entries(), generate_t_state_entries and then + * acpigen_pop_len() to close off this package. + * + * @ctx: ACPI context pointer + * @core_id: CPU core number, as numbered by the SoC + * @c_state_map: Information about each C state + * @num_cstates: Number of entries in @c_state_map + * @return 0 if OK, -ve on error + */ +int acpi_generate_cpu_header(struct acpi_ctx *ctx, int core_id, + const struct acpi_cstate *c_state_map, + int num_cstates); + +/** + * acpi_generate_cpu_package_final() - Write out the CPU PPKG entry + * + * This writes information about the CPUs in the package + * + * @ctx: ACPI context pointer + * @cores_per_package: Number of CPU cores in each package in the SoC + */ +int acpi_generate_cpu_package_final(struct acpi_ctx *ctx, + int cores_per_package); + +void generate_p_state_entries(struct acpi_ctx *ctx, int core, + int cores_per_package); +void generate_t_state_entries(struct acpi_ctx *ctx, int core, + int cores_per_package, struct acpi_tstate *entry, + int nentries); +int southbridge_inject_dsdt(const struct udevice *dev, struct acpi_ctx *ctx); + +int intel_southbridge_write_acpi_tables(const struct udevice *dev, + struct acpi_ctx *ctx); + +#endif /* __ASM_INTEL_ACPI_H__ */ diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 00d1d80dc3..1ca5d66141 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -277,4 +277,13 @@ config ACPIGEN things like generating device-specific tables and returning the ACPI name of a device. +config INTEL_ACPIGEN + bool "Support ACPI table generation for Intel SoCs" + depends on ACPIGEN + help + This option adds some functions used for programatic generation of + ACPI tables on Intel SoCs. This provides features for writing CPU + information such as P states and T stages. Also included is a way + to create a GNVS table and set it up. + endmenu -- cgit v1.2.3 From eaac9717369c6ed9e6c5d9c7ed5effb420cb4840 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 22 Sep 2020 12:45:24 -0600 Subject: tpm: cr50: Add ACPI support Generate ACPI information for this device so that Linux can use it correctly. Signed-off-by: Simon Glass --- drivers/tpm/cr50_i2c.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'drivers') diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c index 1942c07c60..64831a4223 100644 --- a/drivers/tpm/cr50_i2c.c +++ b/drivers/tpm/cr50_i2c.c @@ -14,11 +14,14 @@ #include #include #include +#include +#include #include #include #include #include #include +#include enum { TIMEOUT_INIT_MS = 30000, /* Very long timeout for TPM init */ @@ -581,6 +584,53 @@ static int cr50_i2c_cleanup(struct udevice *dev) return 0; } +static int cr50_acpi_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx) +{ + char scope[ACPI_PATH_MAX]; + char name[ACPI_NAME_MAX]; + const char *hid; + int ret; + + ret = acpi_device_scope(dev, scope, sizeof(scope)); + if (ret) + return log_msg_ret("scope", ret); + ret = acpi_get_name(dev, name); + if (ret) + return log_msg_ret("name", ret); + + hid = dev_read_string(dev, "acpi,hid"); + if (!hid) + return log_msg_ret("hid", ret); + + /* Device */ + acpigen_write_scope(ctx, scope); + acpigen_write_device(ctx, name); + acpigen_write_name_string(ctx, "_HID", hid); + acpigen_write_name_integer(ctx, "_UID", + dev_read_u32_default(dev, "acpi,uid", 0)); + acpigen_write_name_string(ctx, "_DDN", + dev_read_string(dev, "acpi,ddn")); + acpigen_write_sta(ctx, acpi_device_status(dev)); + + /* Resources */ + acpigen_write_name(ctx, "_CRS"); + acpigen_write_resourcetemplate_header(ctx); + ret = acpi_device_write_i2c_dev(ctx, dev); + if (ret < 0) + return log_msg_ret("i2c", ret); + ret = acpi_device_write_interrupt_or_gpio(ctx, (struct udevice *)dev, + "ready-gpios"); + if (ret < 0) + return log_msg_ret("irq_gpio", ret); + + acpigen_write_resourcetemplate_footer(ctx); + + acpigen_pop_len(ctx); /* Device */ + acpigen_pop_len(ctx); /* Scope */ + + return 0; +} + enum { TPM_TIMEOUT_MS = 5, SHORT_TIMEOUT_MS = 750, @@ -653,6 +703,10 @@ static int cr50_i2c_probe(struct udevice *dev) return 0; } +struct acpi_ops cr50_acpi_ops = { + .fill_ssdt = cr50_acpi_fill_ssdt, +}; + static const struct tpm_ops cr50_i2c_ops = { .open = cr50_i2c_open, .get_desc = cr50_i2c_get_desc, @@ -675,5 +729,6 @@ U_BOOT_DRIVER(cr50_i2c) = { .probe = cr50_i2c_probe, .remove = cr50_i2c_cleanup, .priv_auto_alloc_size = sizeof(struct cr50_priv), + ACPI_OPS_PTR(&cr50_acpi_ops) .flags = DM_FLAG_OS_PREPARE, }; -- cgit v1.2.3 From 63ef81625ea9553b0fea83cd7915ced8788d4fb4 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 27 Aug 2020 12:04:40 +0300 Subject: 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(+) (limited to 'drivers') 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" }, {} }; -- cgit v1.2.3 From 4cc08258758c4d7f5a624aa99cb2435022def761 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 27 Aug 2020 12:04:41 +0300 Subject: 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(+) (limited to 'drivers') 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" }, { } }; -- cgit v1.2.3 From 2e00608ca4cde8b39a92740539a7417814d851b4 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 27 Aug 2020 12:16:15 +0300 Subject: 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(-) (limited to 'drivers') 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) -- cgit v1.2.3 From 81f16438d48f4690339ae47adc72dfcd4aa63ba0 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 27 Aug 2020 12:25:56 +0300 Subject: 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(+) (limited to 'drivers') 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; -- cgit v1.2.3 From 3710b464e43abe27ed9ab40c39f98a309a7db055 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 27 Aug 2020 12:25:57 +0300 Subject: 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(+) (limited to 'drivers') 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; -- cgit v1.2.3 From 953a3be7680e10b83cbf72e39cc30e096d849031 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 15 Sep 2020 15:36:27 +0100 Subject: pinctrl: renesas: Fix PINCTRL_PFC_R8A774A1 help description R8A774A1 is part of Renesas RZ/G2 series and not R-Car, reflect the same for PINCTRL_PFC_R8A774A1 help description Alongside, sort the PINCTRL_PFC_R8A774A1 config option as per increasing number of the SoC. Signed-off-by: Biju Das Reviewed-by: Lad Prabhakar --- drivers/pinctrl/renesas/Kconfig | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/renesas/Kconfig b/drivers/pinctrl/renesas/Kconfig index 8327bcabd6..e14294b6e7 100644 --- a/drivers/pinctrl/renesas/Kconfig +++ b/drivers/pinctrl/renesas/Kconfig @@ -57,6 +57,16 @@ config PINCTRL_PFC_R8A7794 the GPIO definitions and pin control functions for each available multiplex function. +config PINCTRL_PFC_R8A774A1 + bool "Renesas RZ/G2 R8A774A1 pin control driver" + depends on PINCTRL_PFC + help + Support pin multiplexing control on Renesas RZ/G2M R8A774A1 SoCs. + + The driver is controlled by a device tree node which contains both + the GPIO definitions and pin control functions for each available + multiplex function. + config PINCTRL_PFC_R8A7795 bool "Renesas RCar Gen3 R8A7795 pin control driver" depends on PINCTRL_PFC @@ -77,16 +87,6 @@ config PINCTRL_PFC_R8A7796 the GPIO definitions and pin control functions for each available multiplex function. -config PINCTRL_PFC_R8A774A1 - bool "Renesas RCar Gen3 R8A774A1 pin control driver" - depends on PINCTRL_PFC - help - Support pin multiplexing control on Renesas RZG2M R8A774A1 SoCs. - - The driver is controlled by a device tree node which contains both - the GPIO definitions and pin control functions for each available - multiplex function. - config PINCTRL_PFC_R8A77965 bool "Renesas RCar Gen3 R8A77965 pin control driver" depends on PINCTRL_PFC -- cgit v1.2.3 From 9275a963d448562a80213639c73e2dc34c6d1835 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 22 Sep 2020 07:51:41 +0100 Subject: net: ravb: Remove writeext function call The micrel phy driver is already configuring this values from device tree. So remove the redundant phy configuration call from this driver. Signed-off-by: Biju Das Reviewed-by: Lad Prabhakar --- drivers/net/ravb.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index 886f53ee82..98883cd15b 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -438,8 +438,6 @@ static int ravb_config(struct udevice *dev) writel(mask, eth->iobase + RAVB_REG_ECMR); - phy->drv->writeext(phy, -1, 0x02, 0x08, (0x0f << 5) | 0x19); - return 0; } -- cgit v1.2.3 From ed1b726683e7d9104498b724230ebeb6c533ba70 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 7 Sep 2020 18:36:33 +0300 Subject: 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 (limited to 'drivers') 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, +}; -- cgit v1.2.3 From f8c9660bfe17100a27ca4cf28f957a25cb420255 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 15 Sep 2020 16:05:06 +0800 Subject: ram: sifive: Check return value on clk_enable() The return value should be checked otherwise it's useless to assign the return value to 'ret'. Signed-off-by: Bin Meng --- drivers/ram/sifive/fu540_ddr.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/ram/sifive/fu540_ddr.c b/drivers/ram/sifive/fu540_ddr.c index 5ff88692a8..f5b2873b33 100644 --- a/drivers/ram/sifive/fu540_ddr.c +++ b/drivers/ram/sifive/fu540_ddr.c @@ -369,6 +369,11 @@ static int fu540_ddr_probe(struct udevice *dev) } ret = clk_enable(&priv->ddr_clk); + if (ret < 0) { + debug("Could not enable DDR clock\n"); + return ret; + } + priv->ctl = regmap_get_range(map, 0); priv->phy = regmap_get_range(map, 1); priv->physical_filter_ctrl = regmap_get_range(map, 2); -- cgit v1.2.3 From 9981a8009e17fd51b74a4a58ba436998ebbf81ed Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 15 Sep 2020 16:05:07 +0800 Subject: ram: sifive: Remove regmap dependency The usage of regmap API in the SiFive RAM driver is not correct. The reg address should be obtained via dev_read_addr_index() API. Signed-off-by: Bin Meng --- drivers/ram/sifive/fu540_ddr.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/ram/sifive/fu540_ddr.c b/drivers/ram/sifive/fu540_ddr.c index f5b2873b33..60d4945f84 100644 --- a/drivers/ram/sifive/fu540_ddr.c +++ b/drivers/ram/sifive/fu540_ddr.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -339,17 +338,12 @@ static int fu540_ddr_probe(struct udevice *dev) priv->info.size = gd->ram_size; #if defined(CONFIG_SPL_BUILD) - struct regmap *map; int ret; u32 clock = 0; debug("FU540 DDR probe\n"); priv->dev = dev; - ret = regmap_init_mem(dev_ofnode(dev), &map); - if (ret) - return ret; - ret = clk_get_by_index(dev, 0, &priv->ddr_clk); if (ret) { debug("clk get failed %d\n", ret); @@ -374,9 +368,9 @@ static int fu540_ddr_probe(struct udevice *dev) return ret; } - priv->ctl = regmap_get_range(map, 0); - priv->phy = regmap_get_range(map, 1); - priv->physical_filter_ctrl = regmap_get_range(map, 2); + priv->ctl = (struct fu540_ddrctl *)dev_read_addr_index(dev, 0); + priv->phy = (struct fu540_ddrphy *)dev_read_addr_index(dev, 1); + priv->physical_filter_ctrl = (u32 *)dev_read_addr_index(dev, 2); return fu540_ddr_setup(dev); #endif -- cgit v1.2.3 From c33efafaf949ef11fc525cd5be018ea48c40898c Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 28 Sep 2020 10:52:21 -0400 Subject: riscv: Rework riscv timer driver to only support S-mode The riscv-timer driver currently serves as a shim for several riscv timer drivers. This is not too desirable because it bypasses the usual timer selection via the driver model. There is no easy way to specify an alternate timing driver, or have the tick rate depend on the cpu's configured frequency. The timer drivers also do not have device structs, and so have to rely on storing parameters in gd_t. Lastly, there is no initialization call, so driver init is done in the same function which reads the time. This can result in confusing error messages. To a user, it looks like the driver failed when trying to read the time, whereas it may have failed while initializing. This patch removes the shim functionality from the riscv-timer driver, and has it instead implement the former rdtime.c timer driver. This is because existing u-boot users who pass in a device tree (e.g. qemu) do not create a timer device for S-mode u-boot. The existing behavior of creating the riscv-timer device in the riscv cpu driver must be kept. The actual reading of the CSRs has been redone in the style of Linux's get_cycles64. Signed-off-by: Sean Anderson Reviewed-by: Bin Meng Reviewed-by: Rick Chen --- arch/riscv/Kconfig | 8 -------- arch/riscv/cpu/ax25/Kconfig | 2 +- arch/riscv/cpu/fu540/Kconfig | 2 +- arch/riscv/cpu/generic/Kconfig | 2 +- arch/riscv/lib/Makefile | 1 - arch/riscv/lib/rdtime.c | 38 -------------------------------------- drivers/timer/Kconfig | 4 ++-- drivers/timer/riscv_timer.c | 39 ++++++++++++++++++++------------------- 8 files changed, 25 insertions(+), 71 deletions(-) delete mode 100644 arch/riscv/lib/rdtime.c (limited to 'drivers') diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 009a545fcf..21e6690f4d 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -185,14 +185,6 @@ config ANDES_PLMT The Andes PLMT block holds memory-mapped mtime register associated with timer tick. -config RISCV_RDTIME - bool - default y if RISCV_SMODE || SPL_RISCV_SMODE - help - The provides the riscv_get_time() API that is implemented using the - standard rdtime instruction. This is the case for S-mode U-Boot, and - is useful for processors that support rdtime in M-mode too. - config SYS_MALLOC_F_LEN default 0x1000 diff --git a/arch/riscv/cpu/ax25/Kconfig b/arch/riscv/cpu/ax25/Kconfig index 8d8d71dcbf..5cb5bb51eb 100644 --- a/arch/riscv/cpu/ax25/Kconfig +++ b/arch/riscv/cpu/ax25/Kconfig @@ -3,7 +3,7 @@ config RISCV_NDS select ARCH_EARLY_INIT_R imply CPU imply CPU_RISCV - imply RISCV_TIMER + imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE) imply ANDES_PLIC if (RISCV_MMODE || SPL_RISCV_MMODE) imply ANDES_PLMT if (RISCV_MMODE || SPL_RISCV_MMODE) imply SPL_CPU_SUPPORT diff --git a/arch/riscv/cpu/fu540/Kconfig b/arch/riscv/cpu/fu540/Kconfig index 53e19635c8..ac3f183342 100644 --- a/arch/riscv/cpu/fu540/Kconfig +++ b/arch/riscv/cpu/fu540/Kconfig @@ -10,7 +10,7 @@ config SIFIVE_FU540 select SPL_RAM if SPL imply CPU imply CPU_RISCV - imply RISCV_TIMER + imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE) imply SIFIVE_CLINT if (RISCV_MMODE || SPL_RISCV_MMODE) imply CMD_CPU imply SPL_CPU_SUPPORT diff --git a/arch/riscv/cpu/generic/Kconfig b/arch/riscv/cpu/generic/Kconfig index b2cb155d6d..f4c2e2643c 100644 --- a/arch/riscv/cpu/generic/Kconfig +++ b/arch/riscv/cpu/generic/Kconfig @@ -7,7 +7,7 @@ config GENERIC_RISCV select ARCH_EARLY_INIT_R imply CPU imply CPU_RISCV - imply RISCV_TIMER + imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE) imply SIFIVE_CLINT if (RISCV_MMODE || SPL_RISCV_MMODE) imply CMD_CPU imply SPL_CPU_SUPPORT diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile index 6c503ff2b2..10ac5b06d3 100644 --- a/arch/riscv/lib/Makefile +++ b/arch/riscv/lib/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_SIFIVE_CLINT) += sifive_clint.o obj-$(CONFIG_ANDES_PLIC) += andes_plic.o obj-$(CONFIG_ANDES_PLMT) += andes_plmt.o else -obj-$(CONFIG_RISCV_RDTIME) += rdtime.o obj-$(CONFIG_SBI) += sbi.o obj-$(CONFIG_SBI_IPI) += sbi_ipi.o endif diff --git a/arch/riscv/lib/rdtime.c b/arch/riscv/lib/rdtime.c deleted file mode 100644 index e128d7fce6..0000000000 --- a/arch/riscv/lib/rdtime.c +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2018, Anup Patel - * Copyright (C) 2018, Bin Meng - * - * The riscv_get_time() API implementation that is using the - * standard rdtime instruction. - */ - -#include - -/* Implement the API required by RISC-V timer driver */ -int riscv_get_time(u64 *time) -{ -#ifdef CONFIG_64BIT - u64 n; - - __asm__ __volatile__ ( - "rdtime %0" - : "=r" (n)); - - *time = n; -#else - u32 lo, hi, tmp; - - __asm__ __volatile__ ( - "1:\n" - "rdtimeh %0\n" - "rdtime %1\n" - "rdtimeh %2\n" - "bne %0, %2, 1b" - : "=&r" (hi), "=&r" (lo), "=&r" (tmp)); - - *time = ((u64)hi << 32) | lo; -#endif - - return 0; -} diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 637024445c..d40d313011 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -146,8 +146,8 @@ config RISCV_TIMER bool "RISC-V timer support" depends on TIMER && RISCV help - Select this to enable support for the timer as defined - by the RISC-V privileged architecture spec. + Select this to enable support for a generic RISC-V S-Mode timer + driver. config ROCKCHIP_TIMER bool "Rockchip timer support" diff --git a/drivers/timer/riscv_timer.c b/drivers/timer/riscv_timer.c index 9f9f070e0b..449fcfcfd5 100644 --- a/drivers/timer/riscv_timer.c +++ b/drivers/timer/riscv_timer.c @@ -1,36 +1,37 @@ // SPDX-License-Identifier: GPL-2.0+ /* + * Copyright (C) 2020, Sean Anderson * Copyright (C) 2018, Bin Meng + * Copyright (C) 2018, Anup Patel + * Copyright (C) 2012 Regents of the University of California * - * RISC-V privileged architecture defined generic timer driver + * RISC-V architecturally-defined generic timer driver * - * This driver relies on RISC-V platform codes to provide the essential API - * riscv_get_time() which is supposed to return the timer counter as defined - * by the RISC-V privileged architecture spec. - * - * This driver can be used in both M-mode and S-mode U-Boot. + * This driver provides generic timer support for S-mode U-Boot. */ #include #include #include #include -#include - -/** - * riscv_get_time() - get the timer counter - * - * Platform codes should provide this API in order to make this driver function. - * - * @time: the 64-bit timer count as defined by the RISC-V privileged - * architecture spec. - * @return: 0 on success, -ve on error. - */ -extern int riscv_get_time(u64 *time); +#include static int riscv_timer_get_count(struct udevice *dev, u64 *count) { - return riscv_get_time(count); + if (IS_ENABLED(CONFIG_64BIT)) { + *count = csr_read(CSR_TIME); + } else { + u32 hi, lo; + + do { + hi = csr_read(CSR_TIMEH); + lo = csr_read(CSR_TIME); + } while (hi != csr_read(CSR_TIMEH)); + + *count = ((u64)hi << 32) | lo; + } + + return 0; } static int riscv_timer_probe(struct udevice *dev) -- cgit v1.2.3 From 3576121687965ffe580fc44f5dd1d8e9ab434c5b Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 28 Sep 2020 10:52:22 -0400 Subject: timer: Add helper for drivers using timebase fallback This function is designed to be used when a timer used to be initialized by the cpu (e.g. RISC-V timers), but now is initialized by dm_timer_init. In such a case, the timer may prefer to use the clocks and clock-frequency properties, but should be able to fall back on using the cpu's timebase-frequency. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass Reviewed-by: Bin Meng Reviewed-by: Rick Chen --- drivers/timer/timer-uclass.c | 31 +++++++++++++++++++++++++++++++ include/timer.h | 15 +++++++++++++++ 2 files changed, 46 insertions(+) (limited to 'drivers') diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c index 14dde950a1..e9802c8b43 100644 --- a/drivers/timer/timer-uclass.c +++ b/drivers/timer/timer-uclass.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -79,6 +80,36 @@ static int timer_post_probe(struct udevice *dev) return 0; } +/* + * TODO: should be CONFIG_IS_ENABLED(CPU), but the SPL config has _SUPPORT on + * the end... + */ +#if defined(CONFIG_CPU) || defined(CONFIG_SPL_CPU_SUPPORT) +int timer_timebase_fallback(struct udevice *dev) +{ + struct udevice *cpu; + struct cpu_platdata *cpu_plat; + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + /* Did we get our clock rate from the device tree? */ + if (uc_priv->clock_rate) + return 0; + + /* Fall back to timebase-frequency */ + dev_dbg(dev, "missing clocks or clock-frequency property; falling back on timebase-frequency\n"); + cpu = cpu_get_current_dev(); + if (!cpu) + return -ENODEV; + + cpu_plat = dev_get_parent_platdata(cpu); + if (!cpu_plat) + return -ENODEV; + + uc_priv->clock_rate = cpu_plat->timebase_freq; + return 0; +} +#endif + u64 timer_conv_64(u32 count) { /* increment tbh if tbl has rolled over */ diff --git a/include/timer.h b/include/timer.h index a49b500ce3..8b9fa51c53 100644 --- a/include/timer.h +++ b/include/timer.h @@ -15,6 +15,21 @@ */ int dm_timer_init(void); +/** + * timer_timebase_fallback() - Helper for timers using timebase fallback + * @dev: A timer partially-probed timer device + * + * This is a helper function designed for timers which need to fall back on the + * cpu's timebase. This function is designed to be called during the driver's + * probe(). If there is a clocks or clock-frequency property in the timer's + * binding, then it will be used. Otherwise, the timebase of the current cpu + * will be used. This is initialized by the cpu driver, and usually gotten from + * ``/cpus/timebase-frequency`` or ``/cpus/cpu@X/timebase-frequency``. + * + * Return: 0 if OK, or negative error code on failure + */ +int timer_timebase_fallback(struct udevice *dev); + /* * timer_conv_64 - convert 32-bit counter value to 64-bit * -- cgit v1.2.3 From 7616e3687e447b5a838f472afb5275fe6a841f5b Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 28 Sep 2020 10:52:23 -0400 Subject: timer: Add a test for timer_timebase_fallback To test this function, sandbox CPU must set cpu_platdata.timebase_freq on bind. It also needs to expose a method to set the current cpu. I also make some most members of cpu_sandbox_ops static. On the timer side, the device tree property sandbox,timebase-frequency-fallback controls whether sandbox_timer_probe falls back to time_timebase_fallback or to SANDBOX_TIMER_RATE. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- arch/sandbox/dts/test.dts | 9 ++++++++- arch/sandbox/include/asm/cpu.h | 11 +++++++++++ drivers/cpu/cpu_sandbox.c | 39 ++++++++++++++++++++++++++++++++------- drivers/timer/sandbox_timer.c | 4 +++- test/dm/timer.c | 27 ++++++++++++++++++++++++++- 5 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 arch/sandbox/include/asm/cpu.h (limited to 'drivers') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 9f45c48e4e..2f559265a5 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -533,7 +533,9 @@ }; cpus { + timebase-frequency = <2000000>; cpu-test1 { + timebase-frequency = <3000000>; compatible = "sandbox,cpu_sandbox"; u-boot,dm-pre-reloc; }; @@ -839,11 +841,16 @@ 0x58 8>; }; - timer { + timer@0 { compatible = "sandbox,timer"; clock-frequency = <1000000>; }; + timer@1 { + compatible = "sandbox,timer"; + sandbox,timebase-frequency-fallback; + }; + tpm2 { compatible = "sandbox,tpm2"; }; diff --git a/arch/sandbox/include/asm/cpu.h b/arch/sandbox/include/asm/cpu.h new file mode 100644 index 0000000000..c97ac7ba95 --- /dev/null +++ b/arch/sandbox/include/asm/cpu.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2020 Sean Anderson + */ + +#ifndef __SANDBOX_CPU_H +#define __SANDBOX_CPU_H + +void cpu_sandbox_set_current(const char *name); + +#endif /* __SANDBOX_CPU_H */ diff --git a/drivers/cpu/cpu_sandbox.c b/drivers/cpu/cpu_sandbox.c index caa26e50f2..4ba0d1b99e 100644 --- a/drivers/cpu/cpu_sandbox.c +++ b/drivers/cpu/cpu_sandbox.c @@ -8,14 +8,15 @@ #include #include -int cpu_sandbox_get_desc(const struct udevice *dev, char *buf, int size) +static int cpu_sandbox_get_desc(const struct udevice *dev, char *buf, int size) { snprintf(buf, size, "LEG Inc. SuperMegaUltraTurbo CPU No. 1"); return 0; } -int cpu_sandbox_get_info(const struct udevice *dev, struct cpu_info *info) +static int cpu_sandbox_get_info(const struct udevice *dev, + struct cpu_info *info) { info->cpu_freq = 42 * 42 * 42 * 42 * 42; info->features = 0x42424242; @@ -24,21 +25,29 @@ int cpu_sandbox_get_info(const struct udevice *dev, struct cpu_info *info) return 0; } -int cpu_sandbox_get_count(const struct udevice *dev) +static int cpu_sandbox_get_count(const struct udevice *dev) { return 42; } -int cpu_sandbox_get_vendor(const struct udevice *dev, char *buf, int size) +static int cpu_sandbox_get_vendor(const struct udevice *dev, char *buf, + int size) { snprintf(buf, size, "Languid Example Garbage Inc."); return 0; } -int cpu_sandbox_is_current(struct udevice *dev) +static const char *cpu_current = "cpu-test1"; + +void cpu_sandbox_set_current(const char *name) { - if (!strcmp(dev->name, "cpu-test1")) + cpu_current = name; +} + +static int cpu_sandbox_is_current(struct udevice *dev) +{ + if (!strcmp(dev->name, cpu_current)) return 1; return 0; @@ -52,7 +61,22 @@ static const struct cpu_ops cpu_sandbox_ops = { .is_current = cpu_sandbox_is_current, }; -int cpu_sandbox_probe(struct udevice *dev) +static int cpu_sandbox_bind(struct udevice *dev) +{ + int ret; + struct cpu_platdata *plat = dev_get_parent_platdata(dev); + + /* first examine the property in current cpu node */ + ret = dev_read_u32(dev, "timebase-frequency", &plat->timebase_freq); + /* if not found, then look at the parent /cpus node */ + if (ret) + ret = dev_read_u32(dev->parent, "timebase-frequency", + &plat->timebase_freq); + + return ret; +} + +static int cpu_sandbox_probe(struct udevice *dev) { return 0; } @@ -67,5 +91,6 @@ U_BOOT_DRIVER(cpu_sandbox) = { .id = UCLASS_CPU, .ops = &cpu_sandbox_ops, .of_match = cpu_sandbox_ids, + .bind = cpu_sandbox_bind, .probe = cpu_sandbox_probe, }; diff --git a/drivers/timer/sandbox_timer.c b/drivers/timer/sandbox_timer.c index 5228486082..6a503c2f15 100644 --- a/drivers/timer/sandbox_timer.c +++ b/drivers/timer/sandbox_timer.c @@ -40,7 +40,9 @@ static int sandbox_timer_probe(struct udevice *dev) { struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); - if (!uc_priv->clock_rate) + if (dev_read_bool(dev, "sandbox,timebase-frequency-fallback")) + return timer_timebase_fallback(dev); + else if (!uc_priv->clock_rate) uc_priv->clock_rate = SANDBOX_TIMER_RATE; return 0; diff --git a/test/dm/timer.c b/test/dm/timer.c index 95dab97665..70043b9eee 100644 --- a/test/dm/timer.c +++ b/test/dm/timer.c @@ -7,8 +7,10 @@ #include #include #include +#include #include #include +#include /* * Basic test of the timer uclass. @@ -17,9 +19,32 @@ static int dm_test_timer_base(struct unit_test_state *uts) { struct udevice *dev; - ut_assertok(uclass_get_device(UCLASS_TIMER, 0, &dev)); + ut_assertok(uclass_get_device_by_name(UCLASS_TIMER, "timer@0", &dev)); ut_asserteq(1000000, timer_get_rate(dev)); return 0; } DM_TEST(dm_test_timer_base, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +/* + * Test of timebase fallback + */ +static int dm_test_timer_timebase_fallback(struct unit_test_state *uts) +{ + struct udevice *dev; + + cpu_sandbox_set_current("cpu-test1"); + ut_assertok(uclass_get_device_by_name(UCLASS_TIMER, "timer@1", &dev)); + ut_asserteq(3000000, timer_get_rate(dev)); + ut_assertok(device_remove(dev, DM_REMOVE_NORMAL)); + + cpu_sandbox_set_current("cpu-test2"); + ut_assertok(uclass_get_device_by_name(UCLASS_TIMER, "timer@1", &dev)); + ut_asserteq(2000000, timer_get_rate(dev)); + + cpu_sandbox_set_current("cpu-test1"); + + return 0; +} +DM_TEST(dm_test_timer_timebase_fallback, + UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); -- cgit v1.2.3 From a952c3a4546ba1d6c5a487cae2e73760ecfd0c60 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 28 Sep 2020 10:52:27 -0400 Subject: riscv: clk: Add CLINT clock to kendryte clock driver Another "virtual" clock (in the sense that it isn't configurable). This could possibly be done as a clock in the device tree, but I think this is a bit cleaner. Signed-off-by: Sean Anderson --- drivers/clk/kendryte/clk.c | 4 ++++ include/dt-bindings/clock/k210-sysctl.h | 1 + 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/kendryte/clk.c b/drivers/clk/kendryte/clk.c index 981b3b7699..bb196961af 100644 --- a/drivers/clk/kendryte/clk.c +++ b/drivers/clk/kendryte/clk.c @@ -646,6 +646,10 @@ static int k210_clk_probe(struct udevice *dev) REGISTER_GATE(K210_CLK_RTC, "rtc", in0); #undef REGISTER_GATE + /* The MTIME register in CLINT runs at one 50th the CPU clock speed */ + clk_dm(K210_CLK_CLINT, + clk_register_fixed_factor(NULL, "clint", "cpu", 0, 1, 50)); + return 0; } diff --git a/include/dt-bindings/clock/k210-sysctl.h b/include/dt-bindings/clock/k210-sysctl.h index 0e3ed3fb9f..fe852bbd92 100644 --- a/include/dt-bindings/clock/k210-sysctl.h +++ b/include/dt-bindings/clock/k210-sysctl.h @@ -55,5 +55,6 @@ #define K210_CLK_OTP 43 #define K210_CLK_RTC 44 #define K210_CLK_ACLK 45 +#define K210_CLK_CLINT 46 #endif /* CLOCK_K210_SYSCTL_H */ -- cgit v1.2.3 From 46df2f87bd9697a49b49f53d54a9e39da0684a7d Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:37 -0400 Subject: dm: syscon: Fix calling dev_dbg with an uninitialized device We can't use dev_dbg here because we haven't bound to the device yet. Use log_debug instead. Signed-off-by: Sean Anderson Reviewed-by: Patrick Delaunay Tested-by: Patrick Delaunay --- drivers/core/syscon-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c index 9cbda4ebda..5be1d527a0 100644 --- a/drivers/core/syscon-uclass.c +++ b/drivers/core/syscon-uclass.c @@ -70,7 +70,7 @@ static int syscon_probe_by_ofnode(ofnode node, struct udevice **devp) /* found node with "syscon" compatible, not bounded to SYSCON UCLASS */ if (!ofnode_device_is_compatible(node, "syscon")) { - dev_dbg(dev, "invalid compatible for syscon device\n"); + log_debug("invalid compatible for syscon device\n"); return -EINVAL; } -- cgit v1.2.3 From e579230b37cc04cef866a74985e9523d2a4079fe Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:38 -0400 Subject: firmware: ti_sci: Fix not calling dev_err with a device This converts calls to dev_err to get the device from ti_sci_info where appropriate. Signed-off-by: Sean Anderson Reviewed-by: Nishanth Menon Tested-by: Patrick Delaunay --- drivers/firmware/ti_sci.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index e311f55ef8..a2beb0079d 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -619,7 +619,7 @@ static int ti_sci_get_device_state(const struct ti_sci_handle *handle, ret = ti_sci_do_xfer(info, xfer); if (ret) { - dev_err(dev, "Mbox send fail %d\n", ret); + dev_err(info->dev, "Mbox send fail %d\n", ret); return ret; } @@ -1591,7 +1591,7 @@ static int ti_sci_cmd_core_reboot(const struct ti_sci_handle *handle) ret = ti_sci_do_xfer(info, xfer); if (ret) { - dev_err(dev, "Mbox send fail %d\n", ret); + dev_err(info->dev, "Mbox send fail %d\n", ret); return ret; } @@ -1639,7 +1639,7 @@ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle, (u32 *)&req, sizeof(req), sizeof(*resp)); if (IS_ERR(xfer)) { ret = PTR_ERR(xfer); - dev_err(dev, "Message alloc failed(%d)\n", ret); + dev_err(info->dev, "Message alloc failed(%d)\n", ret); return ret; } @@ -1649,7 +1649,7 @@ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle, ret = ti_sci_do_xfer(info, xfer); if (ret) { - dev_err(dev, "Mbox send fail %d\n", ret); + dev_err(info->dev, "Mbox send fail %d\n", ret); goto fail; } @@ -1745,7 +1745,7 @@ static int ti_sci_cmd_query_msmc(const struct ti_sci_handle *handle, ret = ti_sci_do_xfer(info, xfer); if (ret) { - dev_err(dev, "Mbox send fail %d\n", ret); + dev_err(info->dev, "Mbox send fail %d\n", ret); return ret; } @@ -2229,6 +2229,14 @@ static int ti_sci_cmd_proc_shutdown_no_wait(const struct ti_sci_handle *handle, u8 proc_id) { int ret; + struct ti_sci_info *info; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); /* * Send the core boot status wait message waiting for either WFE or @@ -2554,7 +2562,8 @@ static int ti_sci_cmd_rm_udmap_rx_flow_cfg( (u32 *)&req, sizeof(req), sizeof(*resp)); if (IS_ERR(xfer)) { ret = PTR_ERR(xfer); - dev_err(dev, "RX_FL_CFG: Message alloc failed(%d)\n", ret); + dev_err(info->dev, "RX_FL_CFG: Message alloc failed(%d)\n", + ret); return ret; } @@ -2583,7 +2592,7 @@ static int ti_sci_cmd_rm_udmap_rx_flow_cfg( ret = ti_sci_do_xfer(info, xfer); if (ret) { - dev_err(dev, "RX_FL_CFG: Mbox send fail %d\n", ret); + dev_err(info->dev, "RX_FL_CFG: Mbox send fail %d\n", ret); goto fail; } -- cgit v1.2.3 From b4f11dfcbd0129e16e6548eabee2d8482190835f Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:39 -0400 Subject: i2c: mxc: Fix dev_err being called on a nonexistant variable The udevice we are working with is called `bus` and not `dev`. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass Reviewed-by: Heiko Schocher Tested-by: Patrick Delaunay --- drivers/i2c/mxc_i2c.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index e3d980a9df..7609594bd0 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -941,7 +941,8 @@ static int mxc_i2c_probe(struct udevice *bus) */ ret = fdt_stringlist_search(fdt, node, "pinctrl-names", "gpio"); if (ret < 0) { - debug("i2c bus %d at 0x%2lx, no gpio pinctrl state.\n", bus->seq, i2c_bus->base); + debug("i2c bus %d at 0x%2lx, no gpio pinctrl state.\n", + bus->seq, i2c_bus->base); } else { ret = gpio_request_by_name_nodev(offset_to_ofnode(node), "scl-gpios", 0, &i2c_bus->scl_gpio, @@ -952,7 +953,9 @@ static int mxc_i2c_probe(struct udevice *bus) if (!dm_gpio_is_valid(&i2c_bus->sda_gpio) || !dm_gpio_is_valid(&i2c_bus->scl_gpio) || ret || ret2) { - dev_err(dev, "i2c bus %d at %lu, fail to request scl/sda gpio\n", bus->seq, i2c_bus->base); + dev_err(bus, + "i2c bus %d at %lu, fail to request scl/sda gpio\n", + bus->seq, i2c_bus->base); return -EINVAL; } } -- cgit v1.2.3 From 661c98121d49c643a1b7b4427d152e2586a220b2 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:40 -0400 Subject: mtd: nand: pxa3xx: Fix not calling dev_xxx with a device Use the device from any mtd already available, or from the active mtd via pxa3xx_nand_info if one is not. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/mtd/nand/raw/pxa3xx_nand.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c index a30e82166b..5fb3081c83 100644 --- a/drivers/mtd/nand/raw/pxa3xx_nand.c +++ b/drivers/mtd/nand/raw/pxa3xx_nand.c @@ -512,7 +512,7 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) } if (i == ntypes) { - dev_err(&info->pdev->dev, "Error: timings not found\n"); + dev_err(mtd->dev, "Error: timings not found\n"); return -EINVAL; } @@ -603,7 +603,7 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len) ts = get_timer(0); while (!(nand_readl(info, NDSR) & NDSR_RDDREQ)) { if (get_timer(ts) > TIMEOUT_DRAIN_FIFO) { - dev_err(&info->pdev->dev, + dev_err(info->controller.active->mtd.dev, "Timeout on RDDREQ while draining the FIFO\n"); return; } @@ -656,8 +656,8 @@ static void handle_data_pio(struct pxa3xx_nand_info *info) DIV_ROUND_UP(info->step_spare_size, 4)); break; default: - dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, - info->state); + dev_err(info->controller.active->mtd.dev, + "%s: invalid state %d\n", __func__, info->state); BUG(); } @@ -1027,7 +1027,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, default: exec_cmd = 0; - dev_err(&info->pdev->dev, "non-supported command %x\n", + dev_err(mtd->dev, "non-supported command %x\n", command); break; } @@ -1087,7 +1087,7 @@ static void nand_cmdfunc(struct mtd_info *mtd, unsigned command, break; if (get_timer(ts) > CHIP_DELAY_TIMEOUT) { - dev_err(&info->pdev->dev, "Wait timeout!!!\n"); + dev_err(mtd->dev, "Wait timeout!!!\n"); return; } } @@ -1180,7 +1180,7 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd, break; if (get_timer(ts) > CHIP_DELAY_TIMEOUT) { - dev_err(&info->pdev->dev, "Wait timeout!!!\n"); + dev_err(mtd->dev, "Wait timeout!!!\n"); return; } } @@ -1426,7 +1426,7 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) break; if (get_timer(ts) > CHIP_DELAY_TIMEOUT) { - dev_err(&info->pdev->dev, "Ready timeout!!!\n"); + dev_err(mtd->dev, "Ready timeout!!!\n"); return NAND_STATUS_FAIL; } } @@ -1633,7 +1633,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->strength = 16; } else { - dev_err(&info->pdev->dev, + dev_err(info->controller.active->mtd.dev, "ECC strength %d at page size %d is not supported\n", strength, page_size); return -ENODEV; @@ -1659,8 +1659,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) return ret; ret = pxa3xx_nand_sensing(host); if (ret) { - dev_info(&info->pdev->dev, - "There is no chip on cs %d!\n", + dev_info(mtd->dev, "There is no chip on cs %d!\n", info->cs); return ret; } @@ -1676,7 +1675,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) if (!pdata->keep_config) { ret = pxa3xx_nand_init_timings(host); if (ret) { - dev_err(&info->pdev->dev, + dev_err(mtd->dev, "Failed to set timings: %d\n", ret); return ret; } @@ -1720,7 +1719,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) { chip->cmdfunc = nand_cmdfunc_extended; } else { - dev_err(&info->pdev->dev, + dev_err(mtd->dev, "unsupported page size on this variant\n"); return -ENODEV; } @@ -1873,6 +1872,7 @@ static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info) static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info) { + struct mtd_info *mtd = &info->controller.active->mtd; struct pxa3xx_nand_platform_data *pdata; int ret, cs, probe_success; @@ -1884,7 +1884,7 @@ static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info) ret = alloc_nand_resource(info); if (ret) { - dev_err(&pdev->dev, "alloc nand resource failed\n"); + dev_err(mtd->dev, "alloc nand resource failed\n"); return ret; } @@ -1901,7 +1901,7 @@ static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info) info->cs = cs; ret = pxa3xx_nand_scan(mtd); if (ret) { - dev_info(&pdev->dev, "failed to scan nand at cs %d\n", + dev_info(mtd->dev, "failed to scan nand at cs %d\n", cs); continue; } -- cgit v1.2.3 From 75eed1a113a29436f90a838b55f92209a126ea26 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:41 -0400 Subject: mtd: nand: sunxi: Fix not calling dev_err with a device Usually the device is gotten from sunxi_nfc. This is a struct device and not a struct udevice, but the whole driver seems to be written wihout DM anyway... In a few instances, this patch modifies functions to take an nfc to log with. In once instance we use mtd_info's device since there is no nfc. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/mtd/nand/raw/sunxi_nand.c | 45 ++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 004b6f17a5..12fc065b32 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -1226,7 +1226,8 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration, #define sunxi_nand_lookup_timing(l, p, c) \ _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c) -static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, +static int sunxi_nand_chip_set_timings(struct sunxi_nfc *nfc, + struct sunxi_nand_chip *chip, const struct nand_sdr_timings *timings) { u32 min_clk_period = 0; @@ -1349,7 +1350,8 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, return 0; } -static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip) +static int sunxi_nand_chip_init_timings(struct sunxi_nfc *nfc, + struct sunxi_nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(&chip->nand); const struct nand_sdr_timings *timings; @@ -1384,7 +1386,7 @@ static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip) if (IS_ERR(timings)) return PTR_ERR(timings); - return sunxi_nand_chip_set_timings(chip, timings); + return sunxi_nand_chip_set_timings(nfc, chip, timings); } static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, @@ -1423,7 +1425,7 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, } if (i >= ARRAY_SIZE(strengths)) { - dev_err(nfc->dev, "unsupported strength\n"); + dev_err(mtd->dev, "unsupported strength\n"); ret = -ENOTSUPP; goto err; } @@ -1619,7 +1621,7 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum) nsels /= sizeof(u32); if (!nsels || nsels > 8) { - dev_err(dev, "invalid reg property size\n"); + dev_err(nfc->dev, "invalid reg property size\n"); return -EINVAL; } @@ -1627,7 +1629,7 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum) (nsels * sizeof(struct sunxi_nand_chip_sel)), GFP_KERNEL); if (!chip) { - dev_err(dev, "could not allocate chip\n"); + dev_err(nfc->dev, "could not allocate chip\n"); return -ENOMEM; } @@ -1641,14 +1643,14 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum) ret = fdtdec_get_int_array(gd->fdt_blob, node, "reg", cs, nsels); if (ret) { - dev_err(dev, "could not retrieve reg property: %d\n", ret); + dev_err(nfc->dev, "could not retrieve reg property: %d\n", ret); return ret; } ret = fdtdec_get_int_array(gd->fdt_blob, node, "allwinner,rb", rb, nsels); if (ret) { - dev_err(dev, "could not retrieve reg property: %d\n", ret); + dev_err(nfc->dev, "could not retrieve reg property: %d\n", ret); return ret; } @@ -1656,14 +1658,13 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum) int tmp = cs[i]; if (tmp > NFC_MAX_CS) { - dev_err(dev, - "invalid reg value: %u (max CS = 7)\n", - tmp); + dev_err(nfc->dev, + "invalid reg value: %u (max CS = 7)\n", tmp); return -EINVAL; } if (test_and_set_bit(tmp, &nfc->assigned_cs)) { - dev_err(dev, "CS %d already assigned\n", tmp); + dev_err(nfc->dev, "CS %d already assigned\n", tmp); return -EINVAL; } @@ -1688,15 +1689,15 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum) timings = onfi_async_timing_mode_to_sdr_timings(0); if (IS_ERR(timings)) { ret = PTR_ERR(timings); - dev_err(dev, + dev_err(nfc->dev, "could not retrieve timings for ONFI mode 0: %d\n", ret); return ret; } - ret = sunxi_nand_chip_set_timings(chip, timings); + ret = sunxi_nand_chip_set_timings(nfc, chip, timings); if (ret) { - dev_err(dev, "could not configure chip timings: %d\n", ret); + dev_err(nfc->dev, "could not configure chip timings: %d\n", ret); return ret; } @@ -1729,27 +1730,27 @@ static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum) nand->options |= NAND_SUBPAGE_READ; - ret = sunxi_nand_chip_init_timings(chip); + ret = sunxi_nand_chip_init_timings(nfc, chip); if (ret) { - dev_err(dev, "could not configure chip timings: %d\n", ret); + dev_err(nfc->dev, "could not configure chip timings: %d\n", ret); return ret; } ret = sunxi_nand_ecc_init(mtd, &nand->ecc); if (ret) { - dev_err(dev, "ECC init failed: %d\n", ret); + dev_err(nfc->dev, "ECC init failed: %d\n", ret); return ret; } ret = nand_scan_tail(mtd); if (ret) { - dev_err(dev, "nand_scan_tail failed: %d\n", ret); + dev_err(nfc->dev, "nand_scan_tail failed: %d\n", ret); return ret; } ret = nand_register(devnum, mtd); if (ret) { - dev_err(dev, "failed to register mtd device: %d\n", ret); + dev_err(nfc->dev, "failed to register mtd device: %d\n", ret); return ret; } @@ -1769,7 +1770,7 @@ static int sunxi_nand_chips_init(int node, struct sunxi_nfc *nfc) i++; if (i > 8) { - dev_err(dev, "too many NAND chips: %d (max = 8)\n", i); + dev_err(nfc->dev, "too many NAND chips: %d (max = 8)\n", i); return -EINVAL; } @@ -1841,7 +1842,7 @@ void sunxi_nand_init(void) ret = sunxi_nand_chips_init(node, nfc); if (ret) { - dev_err(dev, "failed to init nand chips\n"); + dev_err(nfc->dev, "failed to init nand chips\n"); goto err; } -- cgit v1.2.3 From c64633644edfeb348b8c79a66268ec805f4280c2 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:42 -0400 Subject: mtd: spi: Include dm.h in spi-nor-core.c This header is needed so struct udevice can be used in dev_xxx(). Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/mtd/spi/spi-nor-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 0113e70037..e16b0e1462 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include -- cgit v1.2.3 From 8985e1cf91db9826508a48ceb0ae764a81ea10c4 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:43 -0400 Subject: mtd: spi: Fix logging in spi-nor-tiny This fixes dev_xxx() not always being called with a device. In spi_nor_reg_read, a the slave device may not always be available, so we use bus and cs instead. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/mtd/spi/spi-nor-tiny.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c index fa26ea33c8..07c8c7b82b 100644 --- a/drivers/mtd/spi/spi-nor-tiny.c +++ b/drivers/mtd/spi/spi-nor-tiny.c @@ -55,9 +55,19 @@ static int spi_nor_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len) int ret; ret = spi_nor_read_write_reg(nor, &op, val); - if (ret < 0) - dev_dbg(&flash->spimem->spi->dev, "error %d reading %x\n", ret, + if (ret < 0) { + /* + * spi_slave does not have a struct udevice member without DM, + * so use the bus and cs instead. + */ +#if CONFIG_IS_ENABLED(DM_SPI) + dev_dbg(nor->spi->dev, "error %d reading %x\n", ret, code); +#else + log_debug("spi%u.%u: error %d reading %x\n", + nor->spi->bus, nor->spi->cs, ret, code); +#endif + } return ret; } @@ -512,7 +522,8 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor) /* Check current Quad Enable bit value. */ ret = read_cr(nor); if (ret < 0) { - dev_dbg(dev, "error while reading configuration register\n"); + dev_dbg(nor->dev, + "error while reading configuration register\n"); return -EINVAL; } @@ -524,7 +535,7 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor) /* Keep the current value of the Status Register. */ ret = read_sr(nor); if (ret < 0) { - dev_dbg(dev, "error while reading status register\n"); + dev_dbg(nor->dev, "error while reading status register\n"); return -EINVAL; } sr_cr[0] = ret; @@ -785,7 +796,7 @@ int spi_nor_scan(struct spi_nor *nor) } if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) { - dev_dbg(dev, "address width is too large: %u\n", + dev_dbg(nor->dev, "address width is too large: %u\n", nor->addr_width); return -EINVAL; } -- cgit v1.2.3 From 6dcc2819ae984ddbcdd63cee0a4319f150f46a9f Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:44 -0400 Subject: mtd: spi-nand: Fix not calling dev_err with a device Get it from spinand->slave->dev. Another option would be to use spinand_to_mtd(spinand)->dev, but this is what the existing code uses. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass Tested-by: Patrick Delaunay --- drivers/mtd/nand/spi/core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 93371fdde0..8c7e07d463 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -984,13 +984,13 @@ static int spinand_detect(struct spinand_device *spinand) ret = spinand_manufacturer_detect(spinand); if (ret) { - dev_err(dev, "unknown raw ID %*phN\n", SPINAND_MAX_ID_LEN, - spinand->id.data); + dev_err(spinand->slave->dev, "unknown raw ID %*phN\n", + SPINAND_MAX_ID_LEN, spinand->id.data); return ret; } if (nand->memorg.ntargets > 1 && !spinand->select_target) { - dev_err(dev, + dev_err(spinand->slave->dev, "SPI NANDs with more than one die must implement ->select_target()\n"); return -EINVAL; } @@ -1076,7 +1076,7 @@ static int spinand_init(struct spinand_device *spinand) ret = spinand_manufacturer_init(spinand); if (ret) { - dev_err(dev, + dev_err(spinand->slave->dev, "Failed to initialize the SPI NAND chip (err = %d)\n", ret); goto err_free_bufs; -- cgit v1.2.3 From 48a4eb802a213ed23bfdd20161a0e5a9a995a601 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:46 -0400 Subject: mmc: bcm2835-host: Fix not calling dev_dbg with a device dev needs to be qualified as a member of host. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/mmc/bcm2835_sdhost.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/bcm2835_sdhost.c b/drivers/mmc/bcm2835_sdhost.c index b793028ab5..ea8b385d7e 100644 --- a/drivers/mmc/bcm2835_sdhost.c +++ b/drivers/mmc/bcm2835_sdhost.c @@ -185,22 +185,22 @@ struct bcm2835_host { static void bcm2835_dumpregs(struct bcm2835_host *host) { - dev_dbg(dev, "=========== REGISTER DUMP ===========\n"); - dev_dbg(dev, "SDCMD 0x%08x\n", readl(host->ioaddr + SDCMD)); - dev_dbg(dev, "SDARG 0x%08x\n", readl(host->ioaddr + SDARG)); - dev_dbg(dev, "SDTOUT 0x%08x\n", readl(host->ioaddr + SDTOUT)); - dev_dbg(dev, "SDCDIV 0x%08x\n", readl(host->ioaddr + SDCDIV)); - dev_dbg(dev, "SDRSP0 0x%08x\n", readl(host->ioaddr + SDRSP0)); - dev_dbg(dev, "SDRSP1 0x%08x\n", readl(host->ioaddr + SDRSP1)); - dev_dbg(dev, "SDRSP2 0x%08x\n", readl(host->ioaddr + SDRSP2)); - dev_dbg(dev, "SDRSP3 0x%08x\n", readl(host->ioaddr + SDRSP3)); - dev_dbg(dev, "SDHSTS 0x%08x\n", readl(host->ioaddr + SDHSTS)); - dev_dbg(dev, "SDVDD 0x%08x\n", readl(host->ioaddr + SDVDD)); - dev_dbg(dev, "SDEDM 0x%08x\n", readl(host->ioaddr + SDEDM)); - dev_dbg(dev, "SDHCFG 0x%08x\n", readl(host->ioaddr + SDHCFG)); - dev_dbg(dev, "SDHBCT 0x%08x\n", readl(host->ioaddr + SDHBCT)); - dev_dbg(dev, "SDHBLC 0x%08x\n", readl(host->ioaddr + SDHBLC)); - dev_dbg(dev, "===========================================\n"); + dev_dbg(host->dev, "=========== REGISTER DUMP ===========\n"); + dev_dbg(host->dev, "SDCMD 0x%08x\n", readl(host->ioaddr + SDCMD)); + dev_dbg(host->dev, "SDARG 0x%08x\n", readl(host->ioaddr + SDARG)); + dev_dbg(host->dev, "SDTOUT 0x%08x\n", readl(host->ioaddr + SDTOUT)); + dev_dbg(host->dev, "SDCDIV 0x%08x\n", readl(host->ioaddr + SDCDIV)); + dev_dbg(host->dev, "SDRSP0 0x%08x\n", readl(host->ioaddr + SDRSP0)); + dev_dbg(host->dev, "SDRSP1 0x%08x\n", readl(host->ioaddr + SDRSP1)); + dev_dbg(host->dev, "SDRSP2 0x%08x\n", readl(host->ioaddr + SDRSP2)); + dev_dbg(host->dev, "SDRSP3 0x%08x\n", readl(host->ioaddr + SDRSP3)); + dev_dbg(host->dev, "SDHSTS 0x%08x\n", readl(host->ioaddr + SDHSTS)); + dev_dbg(host->dev, "SDVDD 0x%08x\n", readl(host->ioaddr + SDVDD)); + dev_dbg(host->dev, "SDEDM 0x%08x\n", readl(host->ioaddr + SDEDM)); + dev_dbg(host->dev, "SDHCFG 0x%08x\n", readl(host->ioaddr + SDHCFG)); + dev_dbg(host->dev, "SDHBCT 0x%08x\n", readl(host->ioaddr + SDHBCT)); + dev_dbg(host->dev, "SDHBLC 0x%08x\n", readl(host->ioaddr + SDHBLC)); + dev_dbg(host->dev, "===========================================\n"); } static void bcm2835_reset_internal(struct bcm2835_host *host) @@ -738,7 +738,7 @@ static void bcm2835_add_host(struct bcm2835_host *host) cfg->f_min = host->max_clk / SDCDIV_MAX_CDIV; cfg->b_max = 65535; - dev_dbg(dev, "f_max %d, f_min %d\n", + dev_dbg(host->dev, "f_max %d, f_min %d\n", cfg->f_max, cfg->f_min); /* host controller capabilities */ -- cgit v1.2.3 From e1ce7901280b01c3d9532adf377cb9d3b2e04127 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:47 -0400 Subject: mmc: mtk-sd: Fix not calling dev_err with a device This adds a udevice parameter to get_best_delay and msdc_set_mclk so they can call dev_err properly. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass Tested-by: Patrick Delaunay --- drivers/mmc/mtk-sd.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c index bd1fb09d1c..30fe7a0aa2 100644 --- a/drivers/mmc/mtk-sd.c +++ b/drivers/mmc/mtk-sd.c @@ -774,7 +774,8 @@ static void msdc_set_buswidth(struct msdc_host *host, u32 width) writel(val, &host->base->sdc_cfg); } -static void msdc_set_mclk(struct msdc_host *host, enum bus_mode timing, u32 hz) +static void msdc_set_mclk(struct udevice *dev, + struct msdc_host *host, enum bus_mode timing, u32 hz) { u32 mode; u32 div; @@ -897,7 +898,7 @@ static int msdc_ops_set_ios(struct udevice *dev) clock = mmc->cfg->f_min; if (host->mclk != clock || host->timing != mmc->selected_mode) - msdc_set_mclk(host, mmc->selected_mode, clock); + msdc_set_mclk(dev, host, mmc->selected_mode, clock); return 0; } @@ -957,7 +958,8 @@ static int get_delay_len(u32 delay, u32 start_bit) return PAD_DELAY_MAX - start_bit; } -static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay) +static struct msdc_delay_phase get_best_delay(struct udevice *dev, + struct msdc_host *host, u32 delay) { int start = 0, len = 0; int start_final = 0, len_final = 0; @@ -1067,7 +1069,7 @@ static int hs400_tune_response(struct udevice *dev, u32 opcode) } } - final_cmd_delay = get_best_delay(host, cmd_delay); + final_cmd_delay = get_best_delay(dev, host, cmd_delay); clrsetbits_le32(tune_reg, PAD_CMD_TUNE_RX_DLY3, final_cmd_delay.final_phase << PAD_CMD_TUNE_RX_DLY3_S); @@ -1117,7 +1119,7 @@ static int msdc_tune_response(struct udevice *dev, u32 opcode) } } - final_rise_delay = get_best_delay(host, rise_delay); + final_rise_delay = get_best_delay(dev, host, rise_delay); /* if rising edge has enough margin, do not scan falling edge */ if (final_rise_delay.maxlen >= 12 || (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4)) @@ -1139,7 +1141,7 @@ static int msdc_tune_response(struct udevice *dev, u32 opcode) } } - final_fall_delay = get_best_delay(host, fall_delay); + final_fall_delay = get_best_delay(dev, host, fall_delay); skip_fall: final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen); @@ -1171,7 +1173,7 @@ skip_fall: dev_err(dev, "Final internal delay: 0x%x\n", internal_delay); - internal_delay_phase = get_best_delay(host, internal_delay); + internal_delay_phase = get_best_delay(dev, host, internal_delay); clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRRDLY_M, internal_delay_phase.final_phase << MSDC_PAD_TUNE_CMDRRDLY_S); @@ -1214,7 +1216,7 @@ static int msdc_tune_data(struct udevice *dev, u32 opcode) } } - final_rise_delay = get_best_delay(host, rise_delay); + final_rise_delay = get_best_delay(dev, host, rise_delay); if (final_rise_delay.maxlen >= 12 || (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4)) goto skip_fall; @@ -1237,7 +1239,7 @@ static int msdc_tune_data(struct udevice *dev, u32 opcode) } } - final_fall_delay = get_best_delay(host, fall_delay); + final_fall_delay = get_best_delay(dev, host, fall_delay); skip_fall: final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen); @@ -1293,7 +1295,7 @@ static int msdc_tune_together(struct udevice *dev, u32 opcode) rise_delay |= (1 << i); } - final_rise_delay = get_best_delay(host, rise_delay); + final_rise_delay = get_best_delay(dev, host, rise_delay); if (final_rise_delay.maxlen >= 12 || (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4)) goto skip_fall; @@ -1309,7 +1311,7 @@ static int msdc_tune_together(struct udevice *dev, u32 opcode) fall_delay |= (1 << i); } - final_fall_delay = get_best_delay(host, fall_delay); + final_fall_delay = get_best_delay(dev, host, fall_delay); skip_fall: final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen); -- cgit v1.2.3 From fe6e209a2785ae2d9e8a33c47dbf9c7940f369d7 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:48 -0400 Subject: mailbox: k3: Fix not calling dev_err with a device dev needs to be gotten from mbox_chan Signed-off-by: Sean Anderson Reviewed-by: Simon Glass Tested-by: Patrick Delaunay --- drivers/mailbox/k3-sec-proxy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/k3-sec-proxy.c b/drivers/mailbox/k3-sec-proxy.c index 3f9afaed32..27ccc6eab0 100644 --- a/drivers/mailbox/k3-sec-proxy.c +++ b/drivers/mailbox/k3-sec-proxy.c @@ -212,14 +212,16 @@ static int k3_sec_proxy_send(struct mbox_chan *chan, const void *data) ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX); if (ret) { - dev_err(dev, "%s: Thread%d verification failed. ret = %d\n", + dev_err(chan->dev, + "%s: Thread%d verification failed. ret = %d\n", __func__, spt->id, ret); return ret; } /* Check the message size. */ if (msg->len > spm->desc->max_msg_size) { - printf("%s: Thread %ld message length %zu > max msg size %d\n", + dev_err(chan->dev, + "%s: Thread %ld message length %zu > max msg size %d\n", __func__, chan->id, msg->len, spm->desc->max_msg_size); return -EINVAL; } -- cgit v1.2.3 From 2e8c907aba5ec66e96dc33611072b7876da0e0ff Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:49 -0400 Subject: nand: atmel: Fix not calling dev_xxx with a device Use mtd_info to get a device to log with. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass Tested-by: Patrick Delaunay --- drivers/mtd/nand/raw/atmel_nand.c | 69 ++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/raw/atmel_nand.c b/drivers/mtd/nand/raw/atmel_nand.c index 5e95901e27..abc432c862 100644 --- a/drivers/mtd/nand/raw/atmel_nand.c +++ b/drivers/mtd/nand/raw/atmel_nand.c @@ -424,7 +424,8 @@ static int pmecc_err_location(struct mtd_info *mtd) } if (!timeout) { - dev_err(host->dev, "atmel_nand : Timeout to calculate PMECC error location\n"); + dev_err(mtd->dev, + "Timeout to calculate PMECC error location\n"); return -1; } @@ -464,7 +465,8 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, *(buf + byte_pos) ^= (1 << bit_pos); pos = sector_num * host->pmecc_sector_size + byte_pos; - dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", + dev_dbg(mtd->dev, + "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", pos, bit_pos, err_byte, *(buf + byte_pos)); } else { /* Bit flip in OOB area */ @@ -474,7 +476,8 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, ecc[tmp] ^= (1 << bit_pos); pos = tmp + nand_chip->ecc.layout->eccpos[0]; - dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", + dev_dbg(mtd->dev, + "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", pos, bit_pos, err_byte, ecc[tmp]); } @@ -516,7 +519,7 @@ normal_check: err_nbr = pmecc_err_location(mtd); if (err_nbr == -1) { - dev_err(host->dev, "PMECC: Too many errors\n"); + dev_err(mtd->dev, "PMECC: Too many errors\n"); mtd->ecc_stats.failed++; return -EBADMSG; } else { @@ -560,7 +563,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, } if (!timeout) { - dev_err(host->dev, "atmel_nand : Timeout to read PMECC page\n"); + dev_err(mtd->dev, "Timeout to read PMECC page\n"); return -1; } @@ -600,7 +603,8 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, } if (!timeout) { - dev_err(host->dev, "atmel_nand : Timeout to read PMECC status, fail to write PMECC in oob\n"); + dev_err(mtd->dev, + "Timeout to read PMECC status, fail to write PMECC in oob\n"); goto out; } @@ -713,7 +717,8 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host, if (*cap == 0 && *sector_size == 0) { /* Non-ONFI compliant */ - dev_info(host->dev, "NAND chip is not ONFI compliant, assume ecc_bits is 2 in 512 bytes\n"); + dev_info(chip->mtd.dev, + "NAND chip is not ONFI compliant, assume ecc_bits is 2 in 512 bytes\n"); *cap = 2; *sector_size = 512; } @@ -835,17 +840,20 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, * from ONFI. */ if (pmecc_choose_ecc(host, nand, &cap, §or_size)) { - dev_err(host->dev, "Required ECC %d bits in %d bytes not supported!\n", + dev_err(mtd->dev, + "Required ECC %d bits in %d bytes not supported!\n", cap, sector_size); return -EINVAL; } if (cap > host->pmecc_corr_cap) - dev_info(host->dev, "WARNING: Using different ecc correct bits(%d bit) from Nand ONFI ECC reqirement (%d bit).\n", - host->pmecc_corr_cap, cap); + dev_info(mtd->dev, + "WARNING: Using different ecc correct bits(%d bit) from Nand ONFI ECC reqirement (%d bit).\n", + host->pmecc_corr_cap, cap); if (sector_size < host->pmecc_sector_size) - dev_info(host->dev, "WARNING: Using different ecc correct sector size (%d bytes) from Nand ONFI ECC reqirement (%d bytes).\n", - host->pmecc_sector_size, sector_size); + dev_info(mtd->dev, + "WARNING: Using different ecc correct sector size (%d bytes) from Nand ONFI ECC reqirement (%d bytes).\n", + host->pmecc_sector_size, sector_size); #else /* CONFIG_SYS_NAND_ONFI_DETECTION */ host->pmecc_corr_cap = CONFIG_PMECC_CAP; host->pmecc_sector_size = CONFIG_PMECC_SECTOR_SIZE; @@ -877,7 +885,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, #if defined(NO_GALOIS_TABLE_IN_ROM) pmecc_galois_table = create_lookup_table(host->pmecc_sector_size); if (!pmecc_galois_table) { - dev_err(host->dev, "out of memory\n"); + dev_err(mtd->dev, "out of memory\n"); return -ENOMEM; } @@ -909,13 +917,14 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, host->pmecc_sector_number; if (nand->ecc.bytes > MTD_MAX_ECCPOS_ENTRIES_LARGE) { - dev_err(host->dev, "too large eccpos entries. max support ecc.bytes is %d\n", - MTD_MAX_ECCPOS_ENTRIES_LARGE); + dev_err(mtd->dev, + "too large eccpos entries. max support ecc.bytes is %d\n", + MTD_MAX_ECCPOS_ENTRIES_LARGE); return -EINVAL; } if (nand->ecc.bytes > mtd->oobsize - PMECC_OOB_RESERVED_BYTES) { - dev_err(host->dev, "No room for ECC bytes\n"); + dev_err(mtd->dev, "No room for ECC bytes\n"); return -EINVAL; } pmecc_config_ecc_layout(&atmel_pmecc_oobinfo, @@ -926,7 +935,8 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, case 512: case 1024: /* TODO */ - dev_err(host->dev, "Unsupported page size for PMECC, use Software ECC\n"); + dev_err(mtd->dev, + "Unsupported page size for PMECC, use Software ECC\n"); default: /* page size not handled by HW ECC */ /* switching back to soft ECC */ @@ -940,7 +950,8 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, /* Allocate data for PMECC computation */ if (pmecc_data_alloc(host)) { - dev_err(host->dev, "Cannot allocate memory for PMECC computation!\n"); + dev_err(mtd->dev, + "Cannot allocate memory for PMECC computation!\n"); return -ENOMEM; } @@ -951,7 +962,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, /* Check the PMECC ip version */ host->pmecc_version = pmecc_readl(host->pmerrloc, version); - dev_dbg(host->dev, "PMECC IP version is: %x\n", host->pmecc_version); + dev_dbg(mtd->dev, "PMECC IP version is: %x\n", host->pmecc_version); atmel_pmecc_core_init(mtd); @@ -1114,8 +1125,8 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, /* it doesn't seems to be a freshly * erased block. * We can't correct so many errors */ - dev_warn(host->dev, "atmel_nand : multiple errors detected." - " Unable to correct.\n"); + dev_warn(mtd->dev, + "multiple errors detected. Unable to correct.\n"); return -EBADMSG; } @@ -1124,15 +1135,14 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, /* there's nothing much to do here. * the bit error is on the ECC itself. */ - dev_warn(host->dev, "atmel_nand : one bit error on ECC code." - " Nothing to correct\n"); + dev_warn(mtd->dev, + "one bit error on ECC code. Nothing to correct\n"); return 0; } - dev_warn(host->dev, "atmel_nand : one bit error on data." - " (word offset in the page :" - " 0x%x bit offset : 0x%x)\n", - ecc_word, ecc_bit); + dev_warn(mtd->dev, + "one bit error on data. (word offset in the page : 0x%x bit offset : 0x%x)\n", + ecc_word, ecc_bit); /* correct the error */ if (nand_chip->options & NAND_BUSWIDTH_16) { /* 16 bits words */ @@ -1141,7 +1151,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, /* 8 bits words */ dat[ecc_word] ^= (1 << ecc_bit); } - dev_warn(host->dev, "atmel_nand : error corrected\n"); + dev_warn(mtd->dev, "error corrected\n"); return 1; } @@ -1511,7 +1521,6 @@ void board_nand_init(void) int i; for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) if (atmel_nand_chip_init(i, base_addr[i])) - dev_err(host->dev, "atmel_nand: Fail to initialize #%d chip", - i); + log_err("atmel_nand: Fail to initialize #%d chip", i); } #endif /* CONFIG_SPL_BUILD */ -- cgit v1.2.3 From 15b6ab4cee2a0aba62ef30eebda534063f183c5a Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:50 -0400 Subject: nand: brcmnand: Fix not calling dev_err() with a device There are too many levels of indirection when calling dev_err. This is an artifact of the conversion of brcmnand_host.pdev from a struct platform_device (which has a member `dev` pointing to a struct device) to struct udevice. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 48c0ca69de..7349a9bc99 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -956,7 +956,7 @@ static struct nand_ecclayout *brcmnand_create_layout(int ecc_level, */ req = DIV_ROUND_UP(ecc_level * 14, 8); if (req >= sas) { - dev_err(&host->pdev->dev, + dev_err(host->pdev, "error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n", req, sas); return NULL; @@ -1012,8 +1012,8 @@ static struct nand_ecclayout *brcmstb_choose_ecc_layout( layout = brcmnand_create_layout(ecc_level, host); if (!layout) { - dev_err(&host->pdev->dev, - "no proper ecc_layout for this NAND cfg\n"); + dev_err(host->pdev, + "no proper ecc_layout for this NAND cfg\n"); return NULL; } @@ -1056,17 +1056,9 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp) NAND_CTRL_RDY | NAND_STATUS_READY | (wp ? 0 : NAND_STATUS_WP), 0); -#ifndef __UBOOT__ - if (ret) - dev_err_ratelimited(&host->pdev->dev, - "nand #WP expected %s\n", - wp ? "on" : "off"); -#else if (ret) - dev_err(&host->pdev->dev, - "nand #WP expected %s\n", - wp ? "on" : "off"); -#endif /* __UBOOT__ */ + dev_err(host->pdev, "nand #WP expected %s\n", + wp ? "on" : "off"); } } @@ -2257,7 +2249,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host, ofnode dn) ret = ofnode_read_s32(dn, "reg", &host->cs); #endif if (ret) { - dev_err(&pdev->dev, "can't get chip-select\n"); + dev_err(pdev, "can't get chip-select\n"); return -ENXIO; } -- cgit v1.2.3 From 7f36806c9bd3c99e615456d04ee7480873d73a3b Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:51 -0400 Subject: nand: vybrid: Re-introduce vf610_nfc.dev This member was presumably dropped when this driver was converted from Linux. However, it is still used in log statements during initialization. This patch adds the member back. In addition, allocation of struct vf610_nfc has been moved to the callers of vf610_nfc_nand_init. This allows it to be allocated by DM (if it is being used) and for dev to be initialized. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/mtd/nand/raw/vf610_nfc.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c index 52c8a94778..4e6fdc607f 100644 --- a/drivers/mtd/nand/raw/vf610_nfc.c +++ b/drivers/mtd/nand/raw/vf610_nfc.c @@ -152,6 +152,8 @@ enum vf610_nfc_alt_buf { struct vf610_nfc { struct nand_chip chip; + /* NULL without CONFIG_NAND_VF610_NFC_DT */ + struct udevice *dev; void __iomem *regs; uint buf_offset; int write_sz; @@ -631,11 +633,10 @@ struct vf610_nfc_config { int flash_bbt; }; -static int vf610_nfc_nand_init(int devnum, void __iomem *addr) +static int vf610_nfc_nand_init(struct vf610_nfc *nfc, int devnum) { - struct mtd_info *mtd; - struct nand_chip *chip; - struct vf610_nfc *nfc; + struct nand_chip *chip = &nfc->chip; + struct mtd_info *mtd = nand_to_mtd(chip); int err = 0; struct vf610_nfc_config cfg = { .hardware_ecc = 1, @@ -647,16 +648,6 @@ static int vf610_nfc_nand_init(int devnum, void __iomem *addr) .flash_bbt = 1, }; - nfc = calloc(1, sizeof(*nfc)); - if (!nfc) { - printf(KERN_ERR "%s: Memory exhausted!\n", __func__); - return -ENOMEM; - } - - chip = &nfc->chip; - nfc->regs = addr; - - mtd = nand_to_mtd(chip); nand_set_controller_data(chip, nfc); if (cfg.width == 16) @@ -777,20 +768,23 @@ static const struct udevice_id vf610_nfc_dt_ids[] = { static int vf610_nfc_dt_probe(struct udevice *dev) { struct resource res; + struct vf610_nfc *nfc = dev_get_priv(dev); int ret; ret = dev_read_resource(dev, 0, &res); if (ret) return ret; - return vf610_nfc_nand_init(0, devm_ioremap(dev, res.start, - resource_size(&res))); + nfc->regs = devm_ioremap(dev, res.start, resource_size(&res)); + nfc->dev = dev; + return vf610_nfc_nand_init(nfc, 0); } U_BOOT_DRIVER(vf610_nfc_dt) = { .name = "vf610-nfc-dt", .id = UCLASS_MTD, .of_match = vf610_nfc_dt_ids, + .priv_auto_alloc_size = sizeof(struct vf610_nfc), .probe = vf610_nfc_dt_probe, }; @@ -809,7 +803,17 @@ void board_nand_init(void) #else void board_nand_init(void) { - int err = vf610_nfc_nand_init(0, (void __iomem *)CONFIG_SYS_NAND_BASE); + int err; + struct vf610_nfc *nfc; + + nfc = calloc(1, sizeof(*nfc)); + if (!nfc) { + printf("%s: Out of memory\n", __func__); + return; + } + + nfc->regs = (void __iomem *)CONFIG_SYS_NAND_BASE; + err = vf610_nfc_nand_init(nfc, 0); if (err) printf("VF610 NAND init failed (err %d)\n", err); } -- cgit v1.2.3 From 1485d6492359f8ea39c7f3a96076f6a1a3d060f1 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:52 -0400 Subject: net: bcm6368: Fix not calling dev_info with a device Remove the pdev indirection. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/net/bcm6368-eth.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bcm6368-eth.c b/drivers/net/bcm6368-eth.c index 648fafd3e0..38a2a30fe6 100644 --- a/drivers/net/bcm6368-eth.c +++ b/drivers/net/bcm6368-eth.c @@ -249,8 +249,7 @@ static int bcm6368_eth_adjust_link(struct udevice *dev) /* link changed */ if (!up) { - dev_info(&priv->pdev->dev, "link DOWN on %s\n", - port->name); + dev_info(dev, "link DOWN on %s\n", port->name); writeb_be(ETH_PORTOV_ENABLE_MASK, priv->base + ETH_PORTOV_REG(i)); writeb_be(ETH_PTCTRL_RXDIS_MASK | -- cgit v1.2.3 From 13cbe299d0e03687b1b7c66316aa851cb23a6bd6 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:54 -0400 Subject: net: mvneta: Fix not always calling dev_err with a device No need for indirection here. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass Tested-by: Patrick Delaunay --- drivers/net/mvneta.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c index 4c7d06ca40..2c93fe42f7 100644 --- a/drivers/net/mvneta.c +++ b/drivers/net/mvneta.c @@ -1402,7 +1402,7 @@ static int mvneta_init(struct udevice *dev) err = mvneta_init2(pp); if (err < 0) { - dev_err(&pdev->dev, "can't init eth hal\n"); + dev_err(dev, "can't init eth hal\n"); return err; } @@ -1410,7 +1410,7 @@ static int mvneta_init(struct udevice *dev) err = mvneta_port_power_up(pp, pp->phy_interface); if (err < 0) { - dev_err(&pdev->dev, "can't power up port\n"); + dev_err(dev, "can't power up port\n"); return err; } -- cgit v1.2.3 From c519cbf5c2eb7d96d62489db952f8a63b5f068f8 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:55 -0400 Subject: net: mvneta: Convert netdev_xxx to dev_xxx netdev_xxx evaluates to printf in U-Boot, so there is no extra info printed. mvneta is one of two drivers which use these functions in U-Boot. Convert these functions to dev_xxx where possible (and to log_xxx where not). Signed-off-by: Sean Anderson Reviewed-by: Simon Glass Tested-by: Patrick Delaunay --- drivers/net/mvneta.c | 52 ++++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c index 2c93fe42f7..83f99e5d8a 100644 --- a/drivers/net/mvneta.c +++ b/drivers/net/mvneta.c @@ -625,9 +625,9 @@ static void mvneta_port_down(struct mvneta_port *pp) count = 0; do { if (count++ >= MVNETA_RX_DISABLE_TIMEOUT_MSEC) { - netdev_warn(pp->dev, - "TIMEOUT for RX stopped ! rx_queue_cmd: 0x08%x\n", - val); + dev_warn(pp->phydev->dev, + "TIMEOUT for RX stopped ! rx_queue_cmd: 0x08%x\n", + val); break; } mdelay(1); @@ -648,9 +648,9 @@ static void mvneta_port_down(struct mvneta_port *pp) count = 0; do { if (count++ >= MVNETA_TX_DISABLE_TIMEOUT_MSEC) { - netdev_warn(pp->dev, - "TIMEOUT for TX stopped status=0x%08x\n", - val); + dev_warn(pp->phydev->dev, + "TIMEOUT for TX stopped status=0x%08x\n", + val); break; } mdelay(1); @@ -664,9 +664,9 @@ static void mvneta_port_down(struct mvneta_port *pp) count = 0; do { if (count++ >= MVNETA_TX_FIFO_EMPTY_TIMEOUT) { - netdev_warn(pp->dev, - "TX FIFO empty timeout status=0x08%x\n", - val); + dev_warn(pp->phydev->dev, + "TX FIFO empty timeout status=0x08%x\n", + val); break; } mdelay(1); @@ -949,28 +949,32 @@ static void mvneta_rx_error(struct mvneta_port *pp, u32 status = rx_desc->status; if (!mvneta_rxq_desc_is_first_last(status)) { - netdev_err(pp->dev, - "bad rx status %08x (buffer oversize), size=%d\n", - status, rx_desc->data_size); + dev_err(pp->phydev->dev, + "bad rx status %08x (buffer oversize), size=%d\n", + status, rx_desc->data_size); return; } switch (status & MVNETA_RXD_ERR_CODE_MASK) { case MVNETA_RXD_ERR_CRC: - netdev_err(pp->dev, "bad rx status %08x (crc error), size=%d\n", - status, rx_desc->data_size); + dev_err(pp->phydev->dev, + "bad rx status %08x (crc error), size=%d\n", status, + rx_desc->data_size); break; case MVNETA_RXD_ERR_OVERRUN: - netdev_err(pp->dev, "bad rx status %08x (overrun error), size=%d\n", - status, rx_desc->data_size); + dev_err(pp->phydev->dev, + "bad rx status %08x (overrun error), size=%d\n", status, + rx_desc->data_size); break; case MVNETA_RXD_ERR_LEN: - netdev_err(pp->dev, "bad rx status %08x (max frame length error), size=%d\n", - status, rx_desc->data_size); + dev_err(pp->phydev->dev, + "bad rx status %08x (max frame length error), size=%d\n", + status, rx_desc->data_size); break; case MVNETA_RXD_ERR_RESOURCE: - netdev_err(pp->dev, "bad rx status %08x (resource error), size=%d\n", - status, rx_desc->data_size); + dev_err(pp->phydev->dev, + "bad rx status %08x (resource error), size=%d\n", + status, rx_desc->data_size); break; } } @@ -1127,8 +1131,8 @@ static int mvneta_setup_rxqs(struct mvneta_port *pp) for (queue = 0; queue < rxq_number; queue++) { int err = mvneta_rxq_init(pp, &pp->rxqs[queue]); if (err) { - netdev_err(pp->dev, "%s: can't create rxq=%d\n", - __func__, queue); + dev_err(pp->phydev->dev, "%s: can't create rxq=%d\n", + __func__, queue); mvneta_cleanup_rxqs(pp); return err; } @@ -1145,8 +1149,8 @@ static int mvneta_setup_txqs(struct mvneta_port *pp) for (queue = 0; queue < txq_number; queue++) { int err = mvneta_txq_init(pp, &pp->txqs[queue]); if (err) { - netdev_err(pp->dev, "%s: can't create txq=%d\n", - __func__, queue); + dev_err(pp->phydev->dev, "%s: can't create txq=%d\n", + __func__, queue); mvneta_cleanup_txqs(pp); return err; } -- cgit v1.2.3 From ddc48c135527e930460d56192617b27704d6332d Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:56 -0400 Subject: net: mvpp2: Fix not calling dev_xxx with a device Remove some prefixes, or get the device from the phy. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass Tested-by: Patrick Delaunay --- drivers/net/mvpp2.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c index a5747a25ab..6f3ee235d1 100644 --- a/drivers/net/mvpp2.c +++ b/drivers/net/mvpp2.c @@ -2568,7 +2568,7 @@ static int mvpp2_bm_pool_create(struct udevice *dev, if (!IS_ALIGNED((unsigned long)bm_pool->virt_addr, MVPP2_BM_POOL_PTR_ALIGN)) { - dev_err(&pdev->dev, "BM pool %d is not %d bytes aligned\n", + dev_err(dev, "BM pool %d is not %d bytes aligned\n", bm_pool->id, MVPP2_BM_POOL_PTR_ALIGN); return -ENOMEM; } @@ -2659,7 +2659,7 @@ static int mvpp2_bm_pools_init(struct udevice *dev, return 0; err_unroll_pools: - dev_err(&pdev->dev, "failed to create BM pool %d, size %d\n", i, size); + dev_err(dev, "failed to create BM pool %d, size %d\n", i, size); for (i = i - 1; i >= 0; i--) mvpp2_bm_pool_destroy(dev, priv, &priv->bm_pools[i]); return err; @@ -2834,8 +2834,9 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type, /* Allocate buffers for this pool */ num = mvpp2_bm_bufs_add(port, new_pool, pkts_num); if (num != pkts_num) { - dev_err(dev, "pool %d: %d of %d allocated\n", - new_pool->id, num, pkts_num); + dev_err(port->phy_dev->dev, + "pool %d: %d of %d allocated\n", new_pool->id, + num, pkts_num); return NULL; } } @@ -4725,7 +4726,7 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port) int parent; phyaddr = fdtdec_get_int(gd->fdt_blob, phy_node, "reg", 0); if (phyaddr < 0) { - dev_err(&pdev->dev, "could not find phy address\n"); + dev_err(dev, "could not find phy address\n"); return -1; } parent = fdt_parent_offset(gd->fdt_blob, phy_node); @@ -4742,13 +4743,13 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port) if (phy_mode_str) phy_mode = phy_get_interface_by_name(phy_mode_str); if (phy_mode == -1) { - dev_err(&pdev->dev, "incorrect phy mode\n"); + dev_err(dev, "incorrect phy mode\n"); return -EINVAL; } id = fdtdec_get_int(gd->fdt_blob, port_node, "port-id", -1); if (id == -1) { - dev_err(&pdev->dev, "missing port-id value\n"); + dev_err(dev, "missing port-id value\n"); return -EINVAL; } @@ -4807,7 +4808,7 @@ static int mvpp2_port_probe(struct udevice *dev, err = mvpp2_port_init(dev, port); if (err < 0) { - dev_err(&pdev->dev, "failed to init port %d\n", port->id); + dev_err(dev, "failed to init port %d\n", port->id); return err; } mvpp2_port_power_up(port); @@ -4978,7 +4979,7 @@ static int mvpp2_init(struct udevice *dev, struct mvpp2 *priv) /* Checks for hardware constraints (U-Boot uses only one rxq) */ if ((rxq_number > priv->max_port_rxqs) || (txq_number > MVPP2_MAX_TXQ)) { - dev_err(&pdev->dev, "invalid queue size parameter\n"); + dev_err(dev, "invalid queue size parameter\n"); return -EINVAL; } @@ -5345,7 +5346,7 @@ static int mvpp2_probe(struct udevice *dev) port->gop_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "gop-port-id", -1); if (port->id == -1) { - dev_err(&pdev->dev, "missing gop-port-id value\n"); + dev_err(dev, "missing gop-port-id value\n"); return -EINVAL; } @@ -5364,7 +5365,7 @@ static int mvpp2_probe(struct udevice *dev) /* Initialize network controller */ err = mvpp2_init(dev, priv); if (err < 0) { - dev_err(&pdev->dev, "failed to initialize controller\n"); + dev_err(dev, "failed to initialize controller\n"); return err; } priv->num_ports = 0; -- cgit v1.2.3 From 9db60ee470c2d28a71ca23d1c453b033c07e3870 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:57 -0400 Subject: net: mvpp2: Convert netdev_xxx to dev_xxx netdev_xxx evaluates to printf in U-Boot, so there is no extra info printed. mvpp2 one of only two drivers which use these functions in U-Boot. Convert these functions to dev_xxx where possible (and to log_xxx where not). Signed-off-by: Sean Anderson Reviewed-by: Simon Glass Tested-by: Patrick Delaunay --- drivers/net/mvpp2.c | 64 +++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c index 6f3ee235d1..8f790a8b44 100644 --- a/drivers/net/mvpp2.c +++ b/drivers/net/mvpp2.c @@ -2773,9 +2773,9 @@ static int mvpp2_bm_bufs_add(struct mvpp2_port *port, if (buf_num < 0 || (buf_num + bm_pool->buf_num > bm_pool->size)) { - netdev_err(port->dev, - "cannot allocate %d buffers for pool %d\n", - buf_num, bm_pool->id); + dev_err(port->phy_dev->dev, + "cannot allocate %d buffers for pool %d\n", buf_num, + bm_pool->id); return 0; } @@ -2803,7 +2803,7 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type, int num; if (new_pool->type != MVPP2_BM_FREE && new_pool->type != type) { - netdev_err(port->dev, "mixing pool types is forbidden\n"); + dev_err(port->phy_dev->dev, "mixing pool types is forbidden\n"); return NULL; } @@ -3345,8 +3345,7 @@ static int gop_port_init(struct mvpp2_port *port) int num_of_act_lanes; if (mac_num >= MVPP22_GOP_MAC_NUM) { - netdev_err(NULL, "%s: illegal port number %d", __func__, - mac_num); + log_err("illegal port number %d", mac_num); return -1; } @@ -3400,8 +3399,8 @@ static int gop_port_init(struct mvpp2_port *port) break; default: - netdev_err(NULL, "%s: Requested port mode (%d) not supported\n", - __func__, port->phy_interface); + log_err("Requested port mode (%d) not supported\n", + port->phy_interface); return -1; } @@ -3441,8 +3440,8 @@ static void gop_port_enable(struct mvpp2_port *port, int enable) break; default: - netdev_err(NULL, "%s: Wrong port mode (%d)\n", __func__, - port->phy_interface); + log_err("%s: Wrong port mode (%d)\n", __func__, + port->phy_interface); return; } } @@ -3812,9 +3811,9 @@ static void mvpp2_egress_disable(struct mvpp2_port *port) delay = 0; do { if (delay >= MVPP2_TX_DISABLE_TIMEOUT_MSEC) { - netdev_warn(port->dev, - "Tx stop timed out, status=0x%08x\n", - reg_data); + dev_warn(port->phy_dev->dev, + "Tx stop timed out, status=0x%08x\n", + reg_data); break; } mdelay(1); @@ -4262,9 +4261,9 @@ static void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) delay = 0; do { if (delay >= MVPP2_TX_PENDING_TIMEOUT_MSEC) { - netdev_warn(port->dev, - "port %d: cleaning queue %d timed out\n", - port->id, txq->log_id); + dev_warn(port->phy_dev->dev, + "port %d: cleaning queue %d timed out\n", + port->id, txq->log_id); break; } mdelay(1); @@ -4431,16 +4430,19 @@ static void mvpp2_rx_error(struct mvpp2_port *port, switch (status & MVPP2_RXD_ERR_CODE_MASK) { case MVPP2_RXD_ERR_CRC: - netdev_err(port->dev, "bad rx status %08x (crc error), size=%zu\n", - status, sz); + dev_err(port->phy_dev->dev, + "bad rx status %08x (crc error), size=%zu\n", status, + sz); break; case MVPP2_RXD_ERR_OVERRUN: - netdev_err(port->dev, "bad rx status %08x (overrun error), size=%zu\n", - status, sz); + dev_err(port->phy_dev->dev, + "bad rx status %08x (overrun error), size=%zu\n", + status, sz); break; case MVPP2_RXD_ERR_RESOURCE: - netdev_err(port->dev, "bad rx status %08x (resource error), size=%zu\n", - status, sz); + dev_err(port->phy_dev->dev, + "bad rx status %08x (resource error), size=%zu\n", + status, sz); break; } } @@ -4508,8 +4510,8 @@ static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) */ if (phy_dev && phy_dev->drv->uid == 0xffffffff) {/* Generic phy */ - netdev_warn(port->dev, - "Marking phy as invalid, link will not be checked\n"); + dev_warn(port->phy_dev->dev, + "Marking phy as invalid, link will not be checked\n"); /* set phy_addr to invalid value */ port->phyaddr = PHY_MAX_ADDR; mvpp2_egress_enable(port); @@ -4520,7 +4522,7 @@ static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) port->phy_dev = phy_dev; if (!phy_dev) { - netdev_err(port->dev, "cannot connect to phy\n"); + dev_err(port->phy_dev->dev, "cannot connect to phy\n"); return; } phy_dev->supported &= PHY_GBIT_FEATURES; @@ -4551,31 +4553,31 @@ static int mvpp2_open(struct udevice *dev, struct mvpp2_port *port) err = mvpp2_prs_mac_da_accept(port->priv, port->id, mac_bcast, true); if (err) { - netdev_err(dev, "mvpp2_prs_mac_da_accept BC failed\n"); + dev_err(dev, "mvpp2_prs_mac_da_accept BC failed\n"); return err; } err = mvpp2_prs_mac_da_accept(port->priv, port->id, port->dev_addr, true); if (err) { - netdev_err(dev, "mvpp2_prs_mac_da_accept MC failed\n"); + dev_err(dev, "mvpp2_prs_mac_da_accept MC failed\n"); return err; } err = mvpp2_prs_def_flow(port); if (err) { - netdev_err(dev, "mvpp2_prs_def_flow failed\n"); + dev_err(dev, "mvpp2_prs_def_flow failed\n"); return err; } /* Allocate the Rx/Tx queues */ err = mvpp2_setup_rxqs(port); if (err) { - netdev_err(port->dev, "cannot allocate Rx queues\n"); + dev_err(port->phy_dev->dev, "cannot allocate Rx queues\n"); return err; } err = mvpp2_setup_txqs(port); if (err) { - netdev_err(port->dev, "cannot allocate Tx queues\n"); + dev_err(port->phy_dev->dev, "cannot allocate Tx queues\n"); return err; } @@ -5100,7 +5102,7 @@ static int mvpp2_recv(struct udevice *dev, int flags, uchar **packetp) err = mvpp2_rx_refill(port, bm_pool, bm, dma_addr); if (err) { - netdev_err(port->dev, "failed to refill BM pools\n"); + dev_err(port->phy_dev->dev, "failed to refill BM pools\n"); return 0; } -- cgit v1.2.3 From e2f74215227e971491bce6860771fd2736b4cfc8 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:44:59 -0400 Subject: net: sunxi: Fix not calling dev_xxx with a device There's no dev to log with, so pass the device along with the priv data. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass Tested-by: Patrick Delaunay --- drivers/net/sunxi_emac.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c index df18ecc064..8e66ce2461 100644 --- a/drivers/net/sunxi_emac.c +++ b/drivers/net/sunxi_emac.c @@ -505,7 +505,8 @@ static int _sunxi_emac_eth_send(struct emac_eth_dev *priv, void *packet, return 0; } -static int sunxi_emac_board_setup(struct emac_eth_dev *priv) +static int sunxi_emac_board_setup(struct udevice *dev, + struct emac_eth_dev *priv) { struct sunxi_sramc_regs *sram = (struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE; @@ -576,7 +577,7 @@ static int sunxi_emac_eth_probe(struct udevice *dev) return ret; } - ret = sunxi_emac_board_setup(priv); + ret = sunxi_emac_board_setup(dev, priv); if (ret) return ret; -- cgit v1.2.3 From ef043693c6b8ffbf0d17caac5c99855cfaeaef3c Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:00 -0400 Subject: net: sun8i_emac: Fix not calling dev_xxx with a device Pass a udevice into a few functions so `dev` is defined. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass Tested-by: Patrick Delaunay --- drivers/net/sun8i_emac.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index 546cc6ccb6..1dae81c7bf 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -663,7 +663,8 @@ static int sun8i_eth_write_hwaddr(struct udevice *dev) return _sun8i_write_hwaddr(priv, pdata->enetaddr); } -static int sun8i_emac_board_setup(struct emac_eth_dev *priv) +static int sun8i_emac_board_setup(struct udevice *dev, + struct emac_eth_dev *priv) { int ret; @@ -833,7 +834,7 @@ static int sun8i_emac_eth_probe(struct udevice *dev) priv->mac_reg = (void *)pdata->iobase; - ret = sun8i_emac_board_setup(priv); + ret = sun8i_emac_board_setup(dev, priv); if (ret) return ret; @@ -854,7 +855,7 @@ static const struct eth_ops sun8i_emac_eth_ops = { .stop = sun8i_emac_eth_stop, }; -static int sun8i_get_ephy_nodes(struct emac_eth_dev *priv) +static int sun8i_get_ephy_nodes(struct udevice *dev, struct emac_eth_dev *priv) { int emac_node, ephy_node, ret, ephy_handle; @@ -986,7 +987,7 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) } if (priv->variant == H3_EMAC) { - ret = sun8i_get_ephy_nodes(priv); + ret = sun8i_get_ephy_nodes(dev, priv); if (ret) return ret; } -- cgit v1.2.3 From 143d81dc8602198b567357160b8dd61edf1bfc48 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:01 -0400 Subject: net: ti: cpsw: Fix not calling dev_dbg with a device Without DM_ETH, cpsw_priv.dev is an eth_device. Just use its name instead. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/net/ti/cpsw.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ti/cpsw.c b/drivers/net/ti/cpsw.c index d6fefe5306..1c11257839 100644 --- a/drivers/net/ti/cpsw.c +++ b/drivers/net/ti/cpsw.c @@ -856,8 +856,14 @@ static int cpsw_phy_init(struct cpsw_priv *priv, struct cpsw_slave *slave) ret = phy_set_supported(phydev, slave->data->max_speed); if (ret) return ret; +#if CONFIG_IS_ENABLED(DM_ETH) dev_dbg(priv->dev, "Port %u speed forced to %uMbit\n", slave->slave_num + 1, slave->data->max_speed); +#else + log_debug("%s: Port %u speed forced to %uMbit\n", + priv->dev->name, slave->slave_num + 1, + slave->data->max_speed); +#endif } phydev->advertising = phydev->supported; -- cgit v1.2.3 From b9442a01f5e825a892ff78ba0d57cac00033a247 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:02 -0400 Subject: phy: marvell: Fix not calling dev_err with a device No need for indirection here. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/phy/marvell/comphy_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/marvell/comphy_core.c b/drivers/phy/marvell/comphy_core.c index 27bff27ff7..5e8ce740cd 100644 --- a/drivers/phy/marvell/comphy_core.c +++ b/drivers/phy/marvell/comphy_core.c @@ -98,14 +98,14 @@ static int comphy_probe(struct udevice *dev) chip_cfg->comphy_lanes_count = fdtdec_get_int(blob, node, "max-lanes", 0); if (chip_cfg->comphy_lanes_count <= 0) { - dev_err(&dev->dev, "comphy max lanes is wrong\n"); + dev_err(dev, "comphy max lanes is wrong\n"); return -EINVAL; } chip_cfg->comphy_mux_bitcount = fdtdec_get_int(blob, node, "mux-bitcount", 0); if (chip_cfg->comphy_mux_bitcount <= 0) { - dev_err(&dev->dev, "comphy mux bit count is wrong\n"); + dev_err(dev, "comphy mux bit count is wrong\n"); return -EINVAL; } @@ -124,7 +124,7 @@ static int comphy_probe(struct udevice *dev) * compatible node is found */ if (!chip_cfg->ptr_comphy_chip_init) { - dev_err(&dev->dev, "comphy: No compatible DT node found\n"); + dev_err(dev, "comphy: No compatible DT node found\n"); return -ENODEV; } -- cgit v1.2.3 From e9e1bd1f754af80379507af10d8f1b1d4c9cac29 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:03 -0400 Subject: phy: rockchip: Fix not calling dev_err with a device Get the device from phy, or pass the phy in. Signed-off-by: Sean Anderson Reviewed-by: Kever Yang Tested-by: Patrick Delaunay --- drivers/phy/rockchip/phy-rockchip-pcie.c | 14 +++++++------- drivers/phy/rockchip/phy-rockchip-typec.c | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/rockchip/phy-rockchip-pcie.c b/drivers/phy/rockchip/phy-rockchip-pcie.c index 83928cffe0..617943fd82 100644 --- a/drivers/phy/rockchip/phy-rockchip-pcie.c +++ b/drivers/phy/rockchip/phy-rockchip-pcie.c @@ -98,7 +98,7 @@ static int rockchip_pcie_phy_power_on(struct phy *phy) ret = reset_deassert(&priv->phy_rst); if (ret) { - dev_err(dev, "failed to assert phy reset\n"); + dev_err(phy->dev, "failed to assert phy reset\n"); return ret; } @@ -119,7 +119,7 @@ static int rockchip_pcie_phy_power_on(struct phy *phy) 20 * 1000, 50); if (ret) { - dev_err(&priv->dev, "pll lock timeout!\n"); + dev_err(phy->dev, "pll lock timeout!\n"); goto err_pll_lock; } @@ -133,7 +133,7 @@ static int rockchip_pcie_phy_power_on(struct phy *phy) 20 * 1000, 50); if (ret) { - dev_err(&priv->dev, "pll output enable timeout!\n"); + dev_err(phy->dev, "pll output enable timeout!\n"); goto err_pll_lock; } @@ -149,7 +149,7 @@ static int rockchip_pcie_phy_power_on(struct phy *phy) 20 * 1000, 50); if (ret) { - dev_err(&priv->dev, "pll relock timeout!\n"); + dev_err(phy->dev, "pll relock timeout!\n"); goto err_pll_lock; } @@ -173,7 +173,7 @@ static int rockchip_pcie_phy_power_off(struct phy *phy) ret = reset_assert(&priv->phy_rst); if (ret) { - dev_err(dev, "failed to assert phy reset\n"); + dev_err(phy->dev, "failed to assert phy reset\n"); return ret; } @@ -187,13 +187,13 @@ static int rockchip_pcie_phy_init(struct phy *phy) ret = clk_enable(&priv->refclk); if (ret) { - dev_err(dev, "failed to enable refclk clock\n"); + dev_err(phy->dev, "failed to enable refclk clock\n"); return ret; } ret = reset_assert(&priv->phy_rst); if (ret) { - dev_err(dev, "failed to assert phy reset\n"); + dev_err(phy->dev, "failed to assert phy reset\n"); goto err_reset; } diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index c9c8e1c542..da00daa447 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -448,7 +448,7 @@ static void rockchip_tcphy_rx_usb3_cfg_lane(struct rockchip_tcphy *priv, writel(0xfb, priv->reg_base + XCVR_DIAG_BIDI_CTRL(lane)); } -static int rockchip_tcphy_init(struct rockchip_tcphy *priv) +static int rockchip_tcphy_init(struct phy *phy, struct rockchip_tcphy *priv) { const struct rockchip_usb3phy_port_cfg *cfg = priv->port_cfgs; u32 val; @@ -559,9 +559,9 @@ static int rockchip_usb3_phy_power_on(struct phy *phy) return 0; if (priv->mode == MODE_DISCONNECT) { - ret = rockchip_tcphy_init(priv); + ret = rockchip_tcphy_init(phy, priv); if (ret) { - dev_err(dev, "failed to init tcphy (ret=%d)\n", ret); + dev_err(phy->dev, "failed to init tcphy (ret=%d)\n", ret); return ret; } } -- cgit v1.2.3 From 73345173101e870df8b816aadc94651e105b00bc Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:04 -0400 Subject: phy: sun4i-usb: Fix not calling dev_err with a device This uses phy's device Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/phy/allwinner/phy-sun4i-usb.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index f050645044..7b9d3eefc5 100644 --- a/drivers/phy/allwinner/phy-sun4i-usb.c +++ b/drivers/phy/allwinner/phy-sun4i-usb.c @@ -272,13 +272,15 @@ static int sun4i_usb_phy_init(struct phy *phy) ret = clk_enable(&usb_phy->clocks); if (ret) { - dev_err(dev, "failed to enable usb_%ldphy clock\n", phy->id); + dev_err(phy->dev, "failed to enable usb_%ldphy clock\n", + phy->id); return ret; } ret = reset_deassert(&usb_phy->resets); if (ret) { - dev_err(dev, "failed to deassert usb_%ldreset reset\n", phy->id); + dev_err(phy->dev, "failed to deassert usb_%ldreset reset\n", + phy->id); return ret; } @@ -338,13 +340,15 @@ static int sun4i_usb_phy_exit(struct phy *phy) ret = clk_disable(&usb_phy->clocks); if (ret) { - dev_err(dev, "failed to disable usb_%ldphy clock\n", phy->id); + dev_err(phy->dev, "failed to disable usb_%ldphy clock\n", + phy->id); return ret; } ret = reset_assert(&usb_phy->resets); if (ret) { - dev_err(dev, "failed to assert usb_%ldreset reset\n", phy->id); + dev_err(phy->dev, "failed to assert usb_%ldreset reset\n", + phy->id); return ret; } -- cgit v1.2.3 From 29e0969bbd1e406afadc145a61a427d1d528bd64 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:05 -0400 Subject: phy: ti: Fix not calling dev_err with a device `phy` doesn't exist; we need to use `x` instead. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/phy/phy-ti-am654.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/phy-ti-am654.c b/drivers/phy/phy-ti-am654.c index 6907c1afb3..cc73760c8b 100644 --- a/drivers/phy/phy-ti-am654.c +++ b/drivers/phy/phy-ti-am654.c @@ -318,13 +318,13 @@ static int serdes_am654_of_xlate(struct phy *x, struct serdes_am654 *phy = dev_get_priv(x->dev); if (args->args_count != 2) { - dev_err(phy->dev, "Invalid DT PHY argument count: %d\n", + dev_err(x->dev, "Invalid DT PHY argument count: %d\n", args->args_count); return -EINVAL; } if (args->args[0] != PHY_TYPE_PCIE) { - dev_err(phy->dev, "Unrecognized PHY type: %d\n", + dev_err(x->dev, "Unrecognized PHY type: %d\n", args->args[0]); return -EINVAL; } -- cgit v1.2.3 From 0aeaca622a7caabe1a5d6f81f9c740ff9abd5cad Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:06 -0400 Subject: phy: usbphyc: Fix not calling dev_err with a device Use the phy's device. Signed-off-by: Sean Anderson Reviewed-by: Patrice Chotard Reviewed-by: Patrick Delaunay Tested-by: Patrick Delaunay --- drivers/phy/phy-stm32-usbphyc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c index c6d3048602..9d4296d649 100644 --- a/drivers/phy/phy-stm32-usbphyc.c +++ b/drivers/phy/phy-stm32-usbphyc.c @@ -311,7 +311,7 @@ static int stm32_usbphyc_of_xlate(struct phy *phy, if ((phy->id == 0 && args->args_count != 1) || (phy->id == 1 && args->args_count != 2)) { - dev_err(dev, "invalid number of cells for phy port%ld\n", + dev_err(phy->dev, "invalid number of cells for phy port%ld\n", phy->id); return -EINVAL; } -- cgit v1.2.3 From b608c54b522c04098ba34471beed214127672931 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:07 -0400 Subject: remoteproc: Remove unused function rproc_elf_sanity_check This function is never used anywhere, and it also tries to log with a nonexistant device. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/remoteproc/rproc-elf-loader.c | 16 ---------------- include/remoteproc.h | 13 ------------- 2 files changed, 29 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/rproc-elf-loader.c b/drivers/remoteproc/rproc-elf-loader.c index c464ecebb7..b185a6cafb 100644 --- a/drivers/remoteproc/rproc-elf-loader.c +++ b/drivers/remoteproc/rproc-elf-loader.c @@ -158,22 +158,6 @@ int rproc_elf64_sanity_check(ulong addr, ulong size) return 0; } -/* Basic function to verify ELF image format */ -int rproc_elf_sanity_check(ulong addr, ulong size) -{ - Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr; - - if (!addr) { - dev_err(dev, "Invalid firmware address\n"); - return -EFAULT; - } - - if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) - return rproc_elf64_sanity_check(addr, size); - else - return rproc_elf32_sanity_check(addr, size); -} - int rproc_elf32_load_image(struct udevice *dev, unsigned long addr, ulong size) { Elf32_Ehdr *ehdr; /* Elf header structure pointer */ diff --git a/include/remoteproc.h b/include/remoteproc.h index a903acb9b2..74d01723f6 100644 --- a/include/remoteproc.h +++ b/include/remoteproc.h @@ -226,19 +226,6 @@ int rproc_elf32_sanity_check(ulong addr, ulong size); */ int rproc_elf64_sanity_check(ulong addr, ulong size); -/** - * rproc_elf_sanity_check() - Verify if an image is a valid ELF one - * - * Check if a valid ELF image exists at the given memory location. Auto - * detects ELF32/ELF64 and verifies basic ELF64/ELF32 format requirements - * like magic number and sections size. - * - * @addr: address of the image to verify - * @size: size of the image - * @return 0 if the image looks good, else appropriate error value. - */ -int rproc_elf_sanity_check(ulong addr, ulong size); - /** * rproc_elf32_load_image() - load an ELF32 image * @dev: device loading the ELF32 image -- cgit v1.2.3 From 44f1c38a32b21c00af435625ba8885f3dc008107 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:08 -0400 Subject: remoteproc: k3-r5: Fix not calling dev_xxx with a device Usually we can get a device from the current core, but some dev_dbg calls have been converted to debug, since we are called on a cluster. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/remoteproc/ti_k3_r5f_rproc.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c index 8e21a38be7..9332a63d21 100644 --- a/drivers/remoteproc/ti_k3_r5f_rproc.c +++ b/drivers/remoteproc/ti_k3_r5f_rproc.c @@ -165,7 +165,7 @@ static int k3_r5f_lockstep_release(struct k3_r5f_cluster *cluster) { int ret, c; - dev_dbg(dev, "%s\n", __func__); + debug("%s\n", __func__); for (c = NR_CORES - 1; c >= 0; c--) { ret = ti_sci_proc_power_domain_on(&cluster->cores[c]->tsp); @@ -201,7 +201,7 @@ static int k3_r5f_split_release(struct k3_r5f_core *core) { int ret; - dev_dbg(dev, "%s\n", __func__); + dev_dbg(core->dev, "%s\n", __func__); ret = ti_sci_proc_power_domain_on(&core->tsp); if (ret) { @@ -246,25 +246,29 @@ static int k3_r5f_core_sanity_check(struct k3_r5f_core *core) struct k3_r5f_cluster *cluster = core->cluster; if (core->in_use) { - dev_err(dev, "Invalid op: Trying to load/start on already running core %d\n", + dev_err(core->dev, + "Invalid op: Trying to load/start on already running core %d\n", core->tsp.proc_id); return -EINVAL; } if (cluster->mode == CLUSTER_MODE_LOCKSTEP && !cluster->cores[1]) { - printf("Secondary core is not probed in this cluster\n"); + dev_err(core->dev, + "Secondary core is not probed in this cluster\n"); return -EAGAIN; } if (cluster->mode == CLUSTER_MODE_LOCKSTEP && !is_primary_core(core)) { - dev_err(dev, "Invalid op: Trying to start secondary core %d in lockstep mode\n", + dev_err(core->dev, + "Invalid op: Trying to start secondary core %d in lockstep mode\n", core->tsp.proc_id); return -EINVAL; } if (cluster->mode == CLUSTER_MODE_SPLIT && !is_primary_core(core)) { if (!core->cluster->cores[0]->in_use) { - dev_err(dev, "Invalid seq: Enable primary core before loading secondary core\n"); + dev_err(core->dev, + "Invalid seq: Enable primary core before loading secondary core\n"); return -EINVAL; } } @@ -432,7 +436,7 @@ static int k3_r5f_split_reset(struct k3_r5f_core *core) { int ret; - dev_dbg(dev, "%s\n", __func__); + dev_dbg(core->dev, "%s\n", __func__); if (reset_assert(&core->reset)) ret = -EINVAL; @@ -447,7 +451,7 @@ static int k3_r5f_lockstep_reset(struct k3_r5f_cluster *cluster) { int ret = 0, c; - dev_dbg(dev, "%s\n", __func__); + debug("%s\n", __func__); for (c = 0; c < NR_CORES; c++) if (reset_assert(&cluster->cores[c]->reset)) @@ -579,7 +583,7 @@ static int k3_r5f_rproc_configure(struct k3_r5f_core *core) u64 boot_vec = 0; int ret; - dev_dbg(dev, "%s\n", __func__); + dev_dbg(core->dev, "%s\n", __func__); ret = ti_sci_proc_request(&core->tsp); if (ret < 0) @@ -672,7 +676,7 @@ static int k3_r5f_of_to_priv(struct k3_r5f_core *core) { int ret; - dev_dbg(dev, "%s\n", __func__); + dev_dbg(core->dev, "%s\n", __func__); core->atcm_enable = dev_read_u32_default(core->dev, "atcm-enable", 0); core->btcm_enable = dev_read_u32_default(core->dev, "btcm-enable", 1); -- cgit v1.2.3 From d7bd29c912d111ca5b43d4d5c0ebd6f8bc3b1f8f Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:09 -0400 Subject: remoteproc: k3: Fix not calling dev_xxx with a device Pass a device to functions which log with one. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/remoteproc/k3_system_controller.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/k3_system_controller.c b/drivers/remoteproc/k3_system_controller.c index 54209fccb3..702d98d1a8 100644 --- a/drivers/remoteproc/k3_system_controller.c +++ b/drivers/remoteproc/k3_system_controller.c @@ -100,7 +100,7 @@ void k3_sysctrler_load_msg_setup(struct k3_sysctrler_load_msg *fw, fw->buffer_size = size; } -static int k3_sysctrler_load_response(u32 *buf) +static int k3_sysctrler_load_response(struct udevice *dev, u32 *buf) { struct k3_sysctrler_load_msg *fw; @@ -129,7 +129,8 @@ static int k3_sysctrler_load_response(u32 *buf) return 0; } -static int k3_sysctrler_boot_notification_response(u32 *buf) +static int k3_sysctrler_boot_notification_response(struct udevice *dev, + u32 *buf) { struct k3_sysctrler_boot_notification_msg *boot; @@ -193,7 +194,7 @@ static int k3_sysctrler_load(struct udevice *dev, ulong addr, ulong size) } /* Process the response */ - ret = k3_sysctrler_load_response(msg.buf); + ret = k3_sysctrler_load_response(dev, msg.buf); if (ret) return ret; @@ -230,7 +231,7 @@ static int k3_sysctrler_start(struct udevice *dev) } /* Process the response */ - ret = k3_sysctrler_boot_notification_response(msg.buf); + ret = k3_sysctrler_boot_notification_response(dev, msg.buf); if (ret) return ret; -- cgit v1.2.3 From cc6c2904b297abb02f25c5e20af13f4af0254db1 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:10 -0400 Subject: soc: qualcomm: Fix not calling dev_err with a device Remove the indirection. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass Tested-by: Patrick Delaunay --- drivers/smem/msm_smem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/smem/msm_smem.c b/drivers/smem/msm_smem.c index 2557269bc5..597d425d11 100644 --- a/drivers/smem/msm_smem.c +++ b/drivers/smem/msm_smem.c @@ -879,7 +879,7 @@ static int qcom_smem_probe(struct udevice *dev) header = smem->regions[0].virt_base; if (le32_to_cpu(header->initialized) != 1 || le32_to_cpu(header->reserved)) { - dev_err(&pdev->dev, "SMEM is not initialized by SBL\n"); + dev_err(dev, "SMEM is not initialized by SBL\n"); return -EINVAL; } -- cgit v1.2.3 From 32bbe5b5d32f5d1e44ced680b0a03acd212f39ee Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:11 -0400 Subject: spi: sunxi: Fix not calling dev_err with a device Use `bus` and not `dev`. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/spi/spi-sunxi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c index cd2e17bfd1..0844a5a0a6 100644 --- a/drivers/spi/spi-sunxi.c +++ b/drivers/spi/spi-sunxi.c @@ -489,19 +489,19 @@ static int sun4i_spi_probe(struct udevice *bus) ret = clk_get_by_name(bus, "ahb", &priv->clk_ahb); if (ret) { - dev_err(dev, "failed to get ahb clock\n"); + dev_err(bus, "failed to get ahb clock\n"); return ret; } ret = clk_get_by_name(bus, "mod", &priv->clk_mod); if (ret) { - dev_err(dev, "failed to get mod clock\n"); + dev_err(bus, "failed to get mod clock\n"); return ret; } ret = reset_get_by_index(bus, 0, &priv->reset); if (ret && ret != -ENOENT) { - dev_err(dev, "failed to get reset\n"); + dev_err(bus, "failed to get reset\n"); return ret; } -- cgit v1.2.3 From 49dfbe924ca0e54d03866dfc2208072a8ecf38ed Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:12 -0400 Subject: spi: zynqmp_gqspi: Fix not calling dev_err with a device Use `bus` instead of `dev`. Signed-off-by: Sean Anderson Reviewed-by: Michal Simek Tested-by: Patrick Delaunay --- drivers/spi/zynqmp_gqspi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index a72986be90..e0e6687037 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -346,20 +346,20 @@ static int zynqmp_qspi_probe(struct udevice *bus) ret = clk_get_by_index(bus, 0, &clk); if (ret < 0) { - dev_err(dev, "failed to get clock\n"); + dev_err(bus, "failed to get clock\n"); return ret; } clock = clk_get_rate(&clk); if (IS_ERR_VALUE(clock)) { - dev_err(dev, "failed to get rate\n"); + dev_err(bus, "failed to get rate\n"); return clock; } debug("%s: CLK %ld\n", __func__, clock); ret = clk_enable(&clk); if (ret && ret != -ENOSYS) { - dev_err(dev, "failed to enable clock\n"); + dev_err(bus, "failed to enable clock\n"); return ret; } plat->frequency = clock; -- cgit v1.2.3 From 9c610289b61b289dec16d4adc5e2381212784e48 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:13 -0400 Subject: sysreset: ti: Fix not calling dev_err with a device The rst variable doesn't exist. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/sysreset/sysreset-ti-sci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/sysreset/sysreset-ti-sci.c b/drivers/sysreset/sysreset-ti-sci.c index 3877b9bc12..7707c72bb5 100644 --- a/drivers/sysreset/sysreset-ti-sci.c +++ b/drivers/sysreset/sysreset-ti-sci.c @@ -51,8 +51,7 @@ static int ti_sci_sysreset_request(struct udevice *dev, enum sysreset_t type) ret = cops->reboot_device(sci); if (ret) - dev_err(rst->dev, "%s: reboot_device failed (%d)\n", - __func__, ret); + dev_err(dev, "%s: reboot_device failed (%d)\n", __func__, ret); return ret; } -- cgit v1.2.3 From df8395a01fa7a15cd82aa4571b56213bfa131779 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:14 -0400 Subject: usb: cdns3: Fix not calling dev_xxx with a device ep0.c also need to include dm.h so dev_xxx can access udevice fields. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/usb/cdns3/ep0.c | 5 +++-- drivers/usb/cdns3/gadget.c | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c index a08c694559..acff79ae1c 100644 --- a/drivers/usb/cdns3/ep0.c +++ b/drivers/usb/cdns3/ep0.c @@ -11,8 +11,9 @@ */ #include -#include +#include #include +#include #include #include #include @@ -810,7 +811,7 @@ int cdns3_gadget_ep_set_wedge(struct usb_ep *ep) { struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); - dev_dbg(priv_dev->dev, "Wedge for %s\n", ep->name); + dev_dbg(priv_ep->cdns3_dev->dev, "Wedge for %s\n", ep->name); cdns3_gadget_ep_set_halt(ep, 1); priv_ep->flags |= EP_WEDGE; diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index 8f81d17ec8..83dbb5a103 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -2399,8 +2399,7 @@ static void cdns3_gadget_udc_set_speed(struct usb_gadget *gadget, case USB_SPEED_SUPER: break; default: - dev_err(cdns->dev, "invalid speed parameter %d\n", - speed); + dev_err(priv_dev->dev, "invalid speed parameter %d\n", speed); } priv_dev->gadget.speed = speed; -- cgit v1.2.3 From 046ade8103b904b75096b8c2af10266af0468be8 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:15 -0400 Subject: usb: dwc2: Fix not calling dev_xxx with a device This adds a dev argument to some functions so dev_xxx always has a device to log with. In one instance we must use use a different log function when we are compiled without DM_USB. Signed-off-by: Sean Anderson Reviewed-by: Patrice Chotard Reviewed-by: Patrick Delaunay Tested-by: Patrick Delaunay --- drivers/usb/host/dwc2.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index cefe9d83b1..f1d13b1c1d 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -114,7 +114,8 @@ static void init_fslspclksel(struct dwc2_core_regs *regs) * @param regs Programming view of DWC_otg controller. * @param num Tx FIFO to flush. */ -static void dwc_otg_flush_tx_fifo(struct dwc2_core_regs *regs, const int num) +static void dwc_otg_flush_tx_fifo(struct udevice *dev, + struct dwc2_core_regs *regs, const int num) { int ret; @@ -134,7 +135,8 @@ static void dwc_otg_flush_tx_fifo(struct dwc2_core_regs *regs, const int num) * * @param regs Programming view of DWC_otg controller. */ -static void dwc_otg_flush_rx_fifo(struct dwc2_core_regs *regs) +static void dwc_otg_flush_rx_fifo(struct udevice *dev, + struct dwc2_core_regs *regs) { int ret; @@ -152,7 +154,8 @@ static void dwc_otg_flush_rx_fifo(struct dwc2_core_regs *regs) * Do core a soft reset of the core. Be careful with this because it * resets all the internal state machines of the core. */ -static void dwc_otg_core_reset(struct dwc2_core_regs *regs) +static void dwc_otg_core_reset(struct udevice *dev, + struct dwc2_core_regs *regs) { int ret; @@ -284,8 +287,8 @@ static void dwc_otg_core_host_init(struct udevice *dev, clrbits_le32(®s->gotgctl, DWC2_GOTGCTL_HSTSETHNPEN); /* Make sure the FIFOs are flushed. */ - dwc_otg_flush_tx_fifo(regs, 0x10); /* All Tx FIFOs */ - dwc_otg_flush_rx_fifo(regs); + dwc_otg_flush_tx_fifo(dev, regs, 0x10); /* All Tx FIFOs */ + dwc_otg_flush_rx_fifo(dev, regs); /* Flush out any leftover queued requests. */ num_channels = readl(®s->ghwcfg2); @@ -306,7 +309,7 @@ static void dwc_otg_core_host_init(struct udevice *dev, ret = wait_for_bit_le32(®s->hc_regs[i].hcchar, DWC2_HCCHAR_CHEN, false, 1000, false); if (ret) - dev_info("%s: Timeout!\n", __func__); + dev_info(dev, "%s: Timeout!\n", __func__); } /* Turn on the vbus power. */ @@ -330,8 +333,9 @@ static void dwc_otg_core_host_init(struct udevice *dev, * * @param regs Programming view of the DWC_otg controller */ -static void dwc_otg_core_init(struct dwc2_priv *priv) +static void dwc_otg_core_init(struct udevice *dev) { + struct dwc2_priv *priv = dev_get_priv(dev); struct dwc2_core_regs *regs = priv->regs; uint32_t ahbcfg = 0; uint32_t usbcfg = 0; @@ -360,7 +364,7 @@ static void dwc_otg_core_init(struct dwc2_priv *priv) writel(usbcfg, ®s->gusbcfg); /* Reset the Controller */ - dwc_otg_core_reset(regs); + dwc_otg_core_reset(dev, regs); /* * This programming sequence needs to happen in FS mode before @@ -372,7 +376,7 @@ static void dwc_otg_core_init(struct dwc2_priv *priv) setbits_le32(®s->gusbcfg, DWC2_GUSBCFG_PHYSEL); /* Reset after a PHY select */ - dwc_otg_core_reset(regs); + dwc_otg_core_reset(dev, regs); /* * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. @@ -419,7 +423,7 @@ static void dwc_otg_core_init(struct dwc2_priv *priv) writel(usbcfg, ®s->gusbcfg); /* Reset after setting the PHY parameters */ - dwc_otg_core_reset(regs); + dwc_otg_core_reset(dev, regs); #endif usbcfg = readl(®s->gusbcfg); @@ -1128,7 +1132,12 @@ int _submit_int_msg(struct dwc2_priv *priv, struct usb_device *dev, timeout = get_timer(0) + USB_TIMEOUT_MS(pipe); for (;;) { if (get_timer(0) > timeout) { - dev_err(dev, "Timeout poll on interrupt endpoint\n"); +#if CONFIG_IS_ENABLED(DM_USB) + dev_err(dev->dev, + "Timeout poll on interrupt endpoint\n"); +#else + log_err("Timeout poll on interrupt endpoint\n"); +#endif return -ETIMEDOUT; } ret = _submit_bulk_msg(priv, dev, pipe, buffer, len); @@ -1194,7 +1203,7 @@ static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv) priv->ext_vbus = 0; #endif - dwc_otg_core_init(priv); + dwc_otg_core_init(dev); dwc_otg_core_host_init(dev, regs); clrsetbits_le32(®s->hprt0, DWC2_HPRT0_PRTENA | @@ -1320,12 +1329,10 @@ static int dwc2_submit_int_msg(struct udevice *dev, struct usb_device *udev, static int dwc2_usb_ofdata_to_platdata(struct udevice *dev) { struct dwc2_priv *priv = dev_get_priv(dev); - fdt_addr_t addr; - addr = dev_read_addr(dev); - if (addr == FDT_ADDR_T_NONE) + priv->regs = dev_read_addr_ptr(dev); + if (!priv->regs) return -EINVAL; - priv->regs = (struct dwc2_core_regs *)addr; priv->oc_disable = dev_read_bool(dev, "disable-over-current"); priv->hnp_srp_disable = dev_read_bool(dev, "hnp-srp-disable"); -- cgit v1.2.3 From df5eabcbf797c6645dd097cfbc9a2b22a2ba79ff Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:16 -0400 Subject: usb: dwc3: Fix not calling dev_xxx with a device This logs with the device from struct dwc3. Some files also need to include dm.h so fields in udevice can be accessed. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/usb/dwc3/core.c | 15 ++++++++------- drivers/usb/dwc3/ep0.c | 1 + drivers/usb/dwc3/gadget.c | 23 ++++++++++++----------- 3 files changed, 21 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 8682556589..2e003530a1 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -592,7 +592,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { - dev_err(dev, "failed to initialize gadget\n"); + dev_err(dwc->dev, "failed to initialize gadget\n"); return ret; } break; @@ -600,7 +600,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { - dev_err(dev, "failed to initialize host\n"); + dev_err(dwc->dev, "failed to initialize host\n"); return ret; } break; @@ -608,18 +608,19 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { - dev_err(dev, "failed to initialize host\n"); + dev_err(dwc->dev, "failed to initialize host\n"); return ret; } ret = dwc3_gadget_init(dwc); if (ret) { - dev_err(dev, "failed to initialize gadget\n"); + dev_err(dwc->dev, "failed to initialize gadget\n"); return ret; } break; default: - dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); + dev_err(dwc->dev, + "Unsupported mode of operation %d\n", dwc->dr_mode); return -EINVAL; } @@ -768,7 +769,7 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev) ret = dwc3_core_init(dwc); if (ret) { - dev_err(dev, "failed to initialize core\n"); + dev_err(dwc->dev, "failed to initialize core\n"); goto err0; } @@ -974,7 +975,7 @@ int dwc3_init(struct dwc3 *dwc) ret = dwc3_core_init(dwc); if (ret) { - dev_err(dev, "failed to initialize core\n"); + dev_err(dwc->dev, "failed to initialize core\n"); goto core_fail; } diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 385bed3e34..75ac993bc6 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -14,6 +14,7 @@ */ #include #include +#include #include #include #include diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 2aec874e1d..4e68fb0a82 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -633,7 +634,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, strlcat(dep->name, "-int", sizeof(dep->name)); break; default: - dev_err(dwc->dev, "invalid endpoint transfer type\n"); + dev_err(dep->dwc->dev, "invalid endpoint transfer type\n"); } spin_lock_irqsave(&dwc->lock, flags); @@ -708,10 +709,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, { struct dwc3_trb *trb; - dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n", - dep->name, req, (unsigned long long) dma, - length, last ? " last" : "", - chain ? " chain" : ""); + dev_vdbg(dep->dwc->dev, "%s: req %p dma %08llx length %d%s%s\n", + dep->name, req, (unsigned long long)dma, + length, last ? " last" : "", chain ? " chain" : ""); trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK]; @@ -1074,21 +1074,22 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, spin_lock_irqsave(&dwc->lock, flags); if (!dep->endpoint.desc) { - dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n", - request, ep->name); + dev_dbg(dep->dwc->dev, + "trying to queue request %p to disabled %s\n", request, + ep->name); ret = -ESHUTDOWN; goto out; } if (req->dep != dep) { - WARN(true, "request %p belongs to '%s'\n", - request, req->dep->name); + WARN(true, "request %p belongs to '%s'\n", request, + req->dep->name); ret = -EINVAL; goto out; } - dev_vdbg(dwc->dev, "queing request %p to %s length %d\n", - request, ep->name, request->length); + dev_vdbg(dep->dwc->dev, "queing request %p to %s length %d\n", + request, ep->name, request->length); ret = __dwc3_gadget_ep_queue(dep, req); -- cgit v1.2.3 From 44003f88a9be236dff8449f048bb25432f2d6bb2 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:17 -0400 Subject: usb: dwc3: ti: Fix not calling dev_err with a device This driver does not use DM, so use log_xxx instead. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/usb/dwc3/ti_usb_phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/ti_usb_phy.c b/drivers/usb/dwc3/ti_usb_phy.c index f8ab06482c..f476810763 100644 --- a/drivers/usb/dwc3/ti_usb_phy.c +++ b/drivers/usb/dwc3/ti_usb_phy.c @@ -129,7 +129,7 @@ static struct usb3_dpll_params *ti_usb3_get_dpll_params(struct ti_usb_phy *phy) return &dpll_map->params; } - dev_err(phy->dev, "No DPLL configuration for %lu Hz SYS CLK\n", rate); + log_err("No DPLL configuration for %lu Hz SYS CLK\n", rate); return NULL; } @@ -269,7 +269,7 @@ int ti_usb_phy_uboot_init(struct ti_usb_phy_device *dev) phy = devm_kzalloc(NULL, sizeof(*phy), GFP_KERNEL); if (!phy) { - dev_err(NULL, "unable to alloc mem for TI USB3 PHY\n"); + log_err("unable to alloc mem for TI USB3 PHY\n"); return -ENOMEM; } -- cgit v1.2.3 From 2667dacb423e7883969f3d5454b2b1e13ffb7e02 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:18 -0400 Subject: usb: dwc3: Don't include asm-generic/io.h This can conflict with asm/io.h on some archs, and it isn't needed to build dwc3-generic.c Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/usb/dwc3/dwc3-generic.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 7fbf2502fa..36fa16ad4e 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 7fe8cfdc7737430c30be689aa01be1711af99e20 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:19 -0400 Subject: usb: musb-new: sunxi: Fix not calling dev_err with a device This driver does not use DM, so we need to use a struct device instead of a struct udevice. Not ideal, but it'll have to do for now. Signed-off-by: Sean Anderson Tested-by: Patrick Delaunay --- drivers/usb/musb-new/sunxi.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c index 06a55bf6ee..187db7794b 100644 --- a/drivers/usb/musb-new/sunxi.c +++ b/drivers/usb/musb-new/sunxi.c @@ -301,21 +301,21 @@ static int sunxi_musb_init(struct musb *musb) ret = clk_enable(&glue->clk); if (ret) { - dev_err(dev, "failed to enable clock\n"); + dev_err(musb->controller, "failed to enable clock\n"); return ret; } if (reset_valid(&glue->rst)) { ret = reset_deassert(&glue->rst); if (ret) { - dev_err(dev, "failed to deassert reset\n"); + dev_err(musb->controller, "failed to deassert reset\n"); goto err_clk; } } ret = generic_phy_init(&glue->phy); if (ret) { - dev_dbg(dev, "failed to init USB PHY\n"); + dev_dbg(musb->controller, "failed to init USB PHY\n"); goto err_rst; } @@ -352,7 +352,8 @@ static int sunxi_musb_exit(struct musb *musb) if (generic_phy_valid(&glue->phy)) { ret = generic_phy_exit(&glue->phy); if (ret) { - dev_dbg(dev, "failed to power off usb phy\n"); + dev_dbg(musb->controller, + "failed to power off usb phy\n"); return ret; } } -- cgit v1.2.3 From 4723fd58dc545c7da4c1916a3784011ac4fa596f Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 15 Sep 2020 10:45:20 -0400 Subject: video: stm32: Fix not calling dev_xxx with a device There is no member `dev` in dw_mipi_dsi, but there is one in mipi_dsi_host, so use that. Signed-off-by: Sean Anderson Reviewed-by: Patrick Delaunay Tested-by: Patrick Delaunay --- drivers/video/dw_mipi_dsi.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/video/dw_mipi_dsi.c b/drivers/video/dw_mipi_dsi.c index b7bfbb5e50..2743836fb4 100644 --- a/drivers/video/dw_mipi_dsi.c +++ b/drivers/video/dw_mipi_dsi.c @@ -314,7 +314,8 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) val, !(val & GEN_CMD_FULL), CMD_PKT_STATUS_TIMEOUT_US); if (ret) { - dev_err(dsi->dev, "failed to get available command FIFO\n"); + dev_err(dsi->dsi_host.dev, + "failed to get available command FIFO\n"); return ret; } @@ -325,7 +326,7 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) val, (val & mask) == mask, CMD_PKT_STATUS_TIMEOUT_US); if (ret) { - dev_err(dsi->dev, "failed to write command FIFO\n"); + dev_err(dsi->dsi_host.dev, "failed to write command FIFO\n"); return ret; } @@ -357,7 +358,7 @@ static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, val, !(val & GEN_PLD_W_FULL), CMD_PKT_STATUS_TIMEOUT_US); if (ret) { - dev_err(dsi->dev, + dev_err(dsi->dsi_host.dev, "failed to get available write payload FIFO\n"); return ret; } @@ -380,7 +381,7 @@ static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi, val, !(val & GEN_RD_CMD_BUSY), CMD_PKT_STATUS_TIMEOUT_US); if (ret) { - dev_err(dsi->dev, "Timeout during read operation\n"); + dev_err(dsi->dsi_host.dev, "Timeout during read operation\n"); return ret; } @@ -390,7 +391,8 @@ static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi, val, !(val & GEN_PLD_R_EMPTY), CMD_PKT_STATUS_TIMEOUT_US); if (ret) { - dev_err(dsi->dev, "Read payload FIFO is empty\n"); + dev_err(dsi->dsi_host.dev, + "Read payload FIFO is empty\n"); return ret; } @@ -411,7 +413,7 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, ret = mipi_dsi_create_packet(&packet, msg); if (ret) { - dev_err(dsi->dev, "failed to create packet: %d\n", ret); + dev_err(host->dev, "failed to create packet: %d\n", ret); return ret; } @@ -702,13 +704,15 @@ static void dw_mipi_dsi_dphy_enable(struct dw_mipi_dsi *dsi) ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val, val & PHY_LOCK, PHY_STATUS_TIMEOUT_US); if (ret) - dev_warn(dsi->dev, "failed to wait phy lock state\n"); + dev_warn(dsi->dsi_host.dev, + "failed to wait phy lock state\n"); ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val, val & PHY_STOP_STATE_CLK_LANE, PHY_STATUS_TIMEOUT_US); if (ret) - dev_warn(dsi->dev, "failed to wait phy clk lane stop state\n"); + dev_warn(dsi->dsi_host.dev, + "failed to wait phy clk lane stop state\n"); } static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi) @@ -729,7 +733,7 @@ static void dw_mipi_dsi_bridge_set(struct dw_mipi_dsi *dsi, ret = phy_ops->get_lane_mbps(dsi->device, timings, device->lanes, device->format, &dsi->lane_mbps); if (ret) - dev_warn(dsi->dev, "Phy get_lane_mbps() failed\n"); + dev_warn(dsi->dsi_host.dev, "Phy get_lane_mbps() failed\n"); dw_mipi_dsi_init_pll(dsi); dw_mipi_dsi_dpi_config(dsi, timings); @@ -748,7 +752,7 @@ static void dw_mipi_dsi_bridge_set(struct dw_mipi_dsi *dsi, ret = phy_ops->init(dsi->device); if (ret) - dev_warn(dsi->dev, "Phy init() failed\n"); + dev_warn(dsi->dsi_host.dev, "Phy init() failed\n"); dw_mipi_dsi_dphy_enable(dsi); -- cgit v1.2.3 From 139e4a1cbe60de96d4febbc6db5882929801ca46 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Wed, 9 Sep 2020 15:37:03 +0530 Subject: drivers: reset: Add a managed API to get reset controllers from the DT Add managed functions to get a reset_ctl from the device-tree, based on a name or an index. Also add a managed functions to get a reset_ctl_bulk (array of reset_ctl) from the device-tree. When the device is unbound, the reset controllers are automatically released and the data structure is freed. Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Simon Glass Signed-off-by: Pratyush Yadav --- drivers/reset/reset-uclass.c | 118 +++++++++++++++++++++++++++++++++++-- include/reset.h | 135 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 248 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c index 5e38ce5c06..e7e407ca35 100644 --- a/drivers/reset/reset-uclass.c +++ b/drivers/reset/reset-uclass.c @@ -11,6 +11,7 @@ #include #include #include +#include static inline struct reset_ops *reset_dev_ops(struct udevice *dev) { @@ -100,13 +101,14 @@ int reset_get_by_index_nodev(ofnode node, int index, index > 0, reset_ctl); } -int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk) +static int __reset_get_bulk(struct udevice *dev, ofnode node, + struct reset_ctl_bulk *bulk) { int i, ret, err, count; - + bulk->count = 0; - count = dev_count_phandle_with_args(dev, "resets", "#reset-cells"); + count = ofnode_count_phandle_with_args(node, "resets", "#reset-cells"); if (count < 1) return count; @@ -116,7 +118,7 @@ int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk) return -ENOMEM; for (i = 0; i < count; i++) { - ret = reset_get_by_index(dev, i, &bulk->resets[i]); + ret = reset_get_by_index_nodev(node, i, &bulk->resets[i]); if (ret < 0) goto bulk_get_err; @@ -134,6 +136,11 @@ bulk_get_err: return ret; } +int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk) +{ + return __reset_get_bulk(dev, dev_ofnode(dev), bulk); +} + int reset_get_by_name(struct udevice *dev, const char *name, struct reset_ctl *reset_ctl) { @@ -246,6 +253,109 @@ int reset_release_all(struct reset_ctl *reset_ctl, int count) return 0; } +static void devm_reset_release(struct udevice *dev, void *res) +{ + reset_free(res); +} + +struct reset_ctl *devm_reset_control_get_by_index(struct udevice *dev, + int index) +{ + int rc; + struct reset_ctl *reset_ctl; + + reset_ctl = devres_alloc(devm_reset_release, sizeof(struct reset_ctl), + __GFP_ZERO); + if (unlikely(!reset_ctl)) + return ERR_PTR(-ENOMEM); + + rc = reset_get_by_index(dev, index, reset_ctl); + if (rc) + return ERR_PTR(rc); + + devres_add(dev, reset_ctl); + return reset_ctl; +} + +struct reset_ctl *devm_reset_control_get(struct udevice *dev, const char *id) +{ + int rc; + struct reset_ctl *reset_ctl; + + reset_ctl = devres_alloc(devm_reset_release, sizeof(struct reset_ctl), + __GFP_ZERO); + if (unlikely(!reset_ctl)) + return ERR_PTR(-ENOMEM); + + rc = reset_get_by_name(dev, id, reset_ctl); + if (rc) + return ERR_PTR(rc); + + devres_add(dev, reset_ctl); + return reset_ctl; +} + +struct reset_ctl *devm_reset_control_get_optional(struct udevice *dev, + const char *id) +{ + struct reset_ctl *r = devm_reset_control_get(dev, id); + + if (IS_ERR(r)) + return NULL; + + return r; +} + +static void devm_reset_bulk_release(struct udevice *dev, void *res) +{ + struct reset_ctl_bulk *bulk = res; + + reset_release_all(bulk->resets, bulk->count); +} + +struct reset_ctl_bulk *devm_reset_bulk_get_by_node(struct udevice *dev, + ofnode node) +{ + int rc; + struct reset_ctl_bulk *bulk; + + bulk = devres_alloc(devm_reset_bulk_release, + sizeof(struct reset_ctl_bulk), + __GFP_ZERO); + if (unlikely(!bulk)) + return ERR_PTR(-ENOMEM); + + rc = __reset_get_bulk(dev, node, bulk); + if (rc) + return ERR_PTR(rc); + + devres_add(dev, bulk); + return bulk; +} + +struct reset_ctl_bulk *devm_reset_bulk_get_optional_by_node(struct udevice *dev, + ofnode node) +{ + struct reset_ctl_bulk *bulk; + + bulk = devm_reset_bulk_get_by_node(dev, node); + + if (IS_ERR(bulk)) + return NULL; + + return bulk; +} + +struct reset_ctl_bulk *devm_reset_bulk_get(struct udevice *dev) +{ + return devm_reset_bulk_get_by_node(dev, dev_ofnode(dev)); +} + +struct reset_ctl_bulk *devm_reset_bulk_get_optional(struct udevice *dev) +{ + return devm_reset_bulk_get_optional_by_node(dev, dev_ofnode(dev)); +} + UCLASS_DRIVER(reset) = { .id = UCLASS_RESET, .name = "reset", diff --git a/include/reset.h b/include/reset.h index 4fac4e6a20..cde2c4b4a8 100644 --- a/include/reset.h +++ b/include/reset.h @@ -7,7 +7,7 @@ #define _RESET_H #include -#include +#include /** * A reset is a hardware signal indicating that a HW module (or IP block, or @@ -84,6 +84,98 @@ struct reset_ctl_bulk { }; #if CONFIG_IS_ENABLED(DM_RESET) + +/** + * devm_reset_control_get - resource managed reset_get_by_name() + * @dev: device to be reset by the controller + * @id: reset line name + * + * Managed reset_get_by_name(). For reset controllers returned + * from this function, reset_free() is called automatically on driver + * detach. + * + * Returns a struct reset_ctl or IS_ERR() condition containing errno. + */ +struct reset_ctl *devm_reset_control_get(struct udevice *dev, const char *id); + +/** + * devm_reset_control_get_optional - resource managed reset_get_by_name() that + * can fail + * @dev: The client device. + * @id: reset line name + * + * Managed reset_get_by_name(). For reset controllers returned + * from this function, reset_free() is called automatically on driver + * detach. + * + * Returns a struct reset_ctl or a dummy reset controller if it failed. + */ +struct reset_ctl *devm_reset_control_get_optional(struct udevice *dev, + const char *id); + +/** + * devm_reset_control_get - resource managed reset_get_by_index() + * @dev: The client device. + * @index: The index of the reset signal to request, within the client's + * list of reset signals. + * + * Managed reset_get_by_index(). For reset controllers returned + * from this function, reset_free() is called automatically on driver + * detach. + * + * Returns a struct reset_ctl or IS_ERR() condition containing errno. + */ +struct reset_ctl *devm_reset_control_get_by_index(struct udevice *dev, + int index); + +/** + * devm_reset_bulk_get - resource managed reset_get_bulk() + * @dev: device to be reset by the controller + * + * Managed reset_get_bulk(). For reset controllers returned + * from this function, reset_free() is called automatically on driver + * detach. + * + * Returns a struct reset_ctl or IS_ERR() condition containing errno. + */ +struct reset_ctl_bulk *devm_reset_bulk_get(struct udevice *dev); + +/** + * devm_reset_bulk_get_optional - resource managed reset_get_bulk() that + * can fail + * @dev: The client device. + * + * Managed reset_get_bulk(). For reset controllers returned + * from this function, reset_free() is called automatically on driver + * detach. + * + * Returns a struct reset_ctl or NULL if it failed. + */ +struct reset_ctl_bulk *devm_reset_bulk_get_optional(struct udevice *dev); + +/** + * devm_reset_bulk_get_by_node - resource managed reset_get_bulk() + * @dev: device to be reset by the controller + * @node: ofnode where the "resets" property is. Usually a sub-node of + * the dev's node. + * + * see devm_reset_bulk_get() + */ +struct reset_ctl_bulk *devm_reset_bulk_get_by_node(struct udevice *dev, + ofnode node); + +/** + * devm_reset_bulk_get_optional_by_node - resource managed reset_get_bulk() + * that can fail + * @dev: device to be reset by the controller + * @node: ofnode where the "resets" property is. Usually a sub-node of + * the dev's node. + * + * see devm_reset_bulk_get_optional() + */ +struct reset_ctl_bulk *devm_reset_bulk_get_optional_by_node(struct udevice *dev, + ofnode node); + /** * reset_get_by_index - Get/request a reset signal by integer index. * @@ -265,7 +357,48 @@ static inline int reset_release_bulk(struct reset_ctl_bulk *bulk) { return reset_release_all(bulk->resets, bulk->count); } + #else +static inline struct reset_ctl *devm_reset_control_get(struct udevice *dev, + const char *id) +{ + return ERR_PTR(-ENOTSUPP); +} + +static inline struct reset_ctl *devm_reset_control_get_optional(struct udevice *dev, + const char *id) +{ + return NULL; +} + +static inline struct reset_ctl *devm_reset_control_get_by_index(struct udevice *dev, + int index) +{ + return ERR_PTR(-ENOTSUPP); +} + +static inline struct reset_ctl_bulk *devm_reset_bulk_get(struct udevice *dev) +{ + return ERR_PTR(-ENOTSUPP); +} + +static inline struct reset_ctl_bulk *devm_reset_bulk_get_optional(struct udevice *dev) +{ + return NULL; +} + +static inline struct reset_ctl_bulk *devm_reset_bulk_get_by_node(struct udevice *dev, + ofnode node) +{ + return ERR_PTR(-ENOTSUPP); +} + +static inline struct reset_ctl_bulk *devm_reset_bulk_get_optional_by_node(struct udevice *dev, + ofnode node) +{ + return NULL; +} + static inline int reset_get_by_index(struct udevice *dev, int index, struct reset_ctl *reset_ctl) { -- cgit v1.2.3 From bad2433151021315e04bcbb72c6c5bd2b938656b Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Wed, 9 Sep 2020 15:37:04 +0530 Subject: test: reset: Add tests for the managed API The tests are basically the same as for the regular API. Except that the reset are initialized using the managed API, and no freed manually. Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Simon Glass Signed-off-by: Pratyush Yadav --- arch/sandbox/include/asm/reset.h | 3 ++ drivers/reset/sandbox-reset-test.c | 51 ++++++++++++++++++++++++++++---- drivers/reset/sandbox-reset.c | 19 ++++++++++++ test/dm/reset.c | 60 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/arch/sandbox/include/asm/reset.h b/arch/sandbox/include/asm/reset.h index c4205eabef..40d3e61c11 100644 --- a/arch/sandbox/include/asm/reset.h +++ b/arch/sandbox/include/asm/reset.h @@ -11,9 +11,12 @@ struct udevice; int sandbox_reset_query(struct udevice *dev, unsigned long id); +int sandbox_reset_is_requested(struct udevice *dev, unsigned long id); int sandbox_reset_test_get(struct udevice *dev); +int sandbox_reset_test_get_devm(struct udevice *dev); int sandbox_reset_test_get_bulk(struct udevice *dev); +int sandbox_reset_test_get_bulk_devm(struct udevice *dev); int sandbox_reset_test_assert(struct udevice *dev); int sandbox_reset_test_assert_bulk(struct udevice *dev); int sandbox_reset_test_deassert(struct udevice *dev); diff --git a/drivers/reset/sandbox-reset-test.c b/drivers/reset/sandbox-reset-test.c index 9bc4a7e0de..10e02f1036 100644 --- a/drivers/reset/sandbox-reset-test.c +++ b/drivers/reset/sandbox-reset-test.c @@ -10,66 +10,105 @@ #include #include #include +#include struct sandbox_reset_test { struct reset_ctl ctl; struct reset_ctl_bulk bulk; + + struct reset_ctl *ctlp; + struct reset_ctl_bulk *bulkp; }; int sandbox_reset_test_get(struct udevice *dev) { struct sandbox_reset_test *sbrt = dev_get_priv(dev); + sbrt->ctlp = &sbrt->ctl; return reset_get_by_name(dev, "test", &sbrt->ctl); } +int sandbox_reset_test_get_devm(struct udevice *dev) +{ + struct sandbox_reset_test *sbrt = dev_get_priv(dev); + struct reset_ctl *r; + + r = devm_reset_control_get(dev, "not-a-valid-reset-ctl"); + if (!IS_ERR(r)) + return -EINVAL; + + r = devm_reset_control_get_optional(dev, "not-a-valid-reset-ctl"); + if (r) + return -EINVAL; + + sbrt->ctlp = devm_reset_control_get(dev, "test"); + if (IS_ERR(sbrt->ctlp)) + return PTR_ERR(sbrt->ctlp); + + return 0; +} + int sandbox_reset_test_get_bulk(struct udevice *dev) { struct sandbox_reset_test *sbrt = dev_get_priv(dev); + sbrt->bulkp = &sbrt->bulk; return reset_get_bulk(dev, &sbrt->bulk); } +int sandbox_reset_test_get_bulk_devm(struct udevice *dev) +{ + struct sandbox_reset_test *sbrt = dev_get_priv(dev); + struct reset_ctl_bulk *r; + + r = devm_reset_bulk_get_optional(dev); + if (IS_ERR(r)) + return PTR_ERR(r); + + sbrt->bulkp = r; + return 0; +} + int sandbox_reset_test_assert(struct udevice *dev) { struct sandbox_reset_test *sbrt = dev_get_priv(dev); - return reset_assert(&sbrt->ctl); + return reset_assert(sbrt->ctlp); } int sandbox_reset_test_assert_bulk(struct udevice *dev) { struct sandbox_reset_test *sbrt = dev_get_priv(dev); - return reset_assert_bulk(&sbrt->bulk); + return reset_assert_bulk(sbrt->bulkp); } int sandbox_reset_test_deassert(struct udevice *dev) { struct sandbox_reset_test *sbrt = dev_get_priv(dev); - return reset_deassert(&sbrt->ctl); + return reset_deassert(sbrt->ctlp); } int sandbox_reset_test_deassert_bulk(struct udevice *dev) { struct sandbox_reset_test *sbrt = dev_get_priv(dev); - return reset_deassert_bulk(&sbrt->bulk); + return reset_deassert_bulk(sbrt->bulkp); } int sandbox_reset_test_free(struct udevice *dev) { struct sandbox_reset_test *sbrt = dev_get_priv(dev); - return reset_free(&sbrt->ctl); + return reset_free(sbrt->ctlp); } int sandbox_reset_test_release_bulk(struct udevice *dev) { struct sandbox_reset_test *sbrt = dev_get_priv(dev); - return reset_release_bulk(&sbrt->bulk); + return reset_release_bulk(sbrt->bulkp); } static const struct udevice_id sandbox_reset_test_ids[] = { diff --git a/drivers/reset/sandbox-reset.c b/drivers/reset/sandbox-reset.c index 7a6f7f676c..08008d875a 100644 --- a/drivers/reset/sandbox-reset.c +++ b/drivers/reset/sandbox-reset.c @@ -15,6 +15,7 @@ struct sandbox_reset_signal { bool asserted; + bool requested; }; struct sandbox_reset { @@ -23,18 +24,24 @@ struct sandbox_reset { static int sandbox_reset_request(struct reset_ctl *reset_ctl) { + struct sandbox_reset *sbr = dev_get_priv(reset_ctl->dev); + debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); if (reset_ctl->id >= SANDBOX_RESET_SIGNALS) return -EINVAL; + sbr->signals[reset_ctl->id].requested = true; return 0; } static int sandbox_reset_free(struct reset_ctl *reset_ctl) { + struct sandbox_reset *sbr = dev_get_priv(reset_ctl->dev); + debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); + sbr->signals[reset_ctl->id].requested = false; return 0; } @@ -107,3 +114,15 @@ int sandbox_reset_query(struct udevice *dev, unsigned long id) return sbr->signals[id].asserted; } + +int sandbox_reset_is_requested(struct udevice *dev, unsigned long id) +{ + struct sandbox_reset *sbr = dev_get_priv(dev); + + debug("%s(dev=%p, id=%ld)\n", __func__, dev, id); + + if (id >= SANDBOX_RESET_SIGNALS) + return -EINVAL; + + return sbr->signals[id].requested; +} diff --git a/test/dm/reset.c b/test/dm/reset.c index f5f366151f..fc8e9250b0 100644 --- a/test/dm/reset.c +++ b/test/dm/reset.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -60,12 +61,39 @@ static int dm_test_reset(struct unit_test_state *uts) ut_assertok(sandbox_reset_test_deassert(dev_test)); ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + ut_asserteq(1, sandbox_reset_is_requested(dev_reset, TEST_RESET_ID)); ut_assertok(sandbox_reset_test_free(dev_test)); + ut_asserteq(0, sandbox_reset_is_requested(dev_reset, TEST_RESET_ID)); return 0; } DM_TEST(dm_test_reset, UT_TESTF_SCAN_FDT); +static int dm_test_reset_devm(struct unit_test_state *uts) +{ + struct udevice *dev_reset; + struct udevice *dev_test; + + ut_assertok(uclass_get_device_by_name(UCLASS_RESET, "reset-ctl", + &dev_reset)); + ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "reset-ctl-test", + &dev_test)); + ut_assertok(sandbox_reset_test_get_devm(dev_test)); + + ut_assertok(sandbox_reset_test_assert(dev_test)); + ut_asserteq(1, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + ut_assertok(sandbox_reset_test_deassert(dev_test)); + ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + + ut_asserteq(1, sandbox_reset_is_requested(dev_reset, TEST_RESET_ID)); + ut_assertok(device_remove(dev_test, DM_REMOVE_NORMAL)); + ut_asserteq(0, sandbox_reset_is_requested(dev_reset, TEST_RESET_ID)); + + return 0; +} +DM_TEST(dm_test_reset_devm, UT_TESTF_SCAN_FDT); + static int dm_test_reset_bulk(struct unit_test_state *uts) { struct udevice *dev_reset; @@ -95,3 +123,35 @@ static int dm_test_reset_bulk(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_reset_bulk, UT_TESTF_SCAN_FDT); + +static int dm_test_reset_bulk_devm(struct unit_test_state *uts) +{ + struct udevice *dev_reset; + struct udevice *dev_test; + + ut_assertok(uclass_get_device_by_name(UCLASS_RESET, "reset-ctl", + &dev_reset)); + ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + ut_asserteq(0, sandbox_reset_query(dev_reset, OTHER_RESET_ID)); + + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "reset-ctl-test", + &dev_test)); + ut_assertok(sandbox_reset_test_get_bulk_devm(dev_test)); + + ut_assertok(sandbox_reset_test_assert_bulk(dev_test)); + ut_asserteq(1, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + ut_asserteq(1, sandbox_reset_query(dev_reset, OTHER_RESET_ID)); + + ut_assertok(sandbox_reset_test_deassert_bulk(dev_test)); + ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + ut_asserteq(0, sandbox_reset_query(dev_reset, OTHER_RESET_ID)); + + ut_asserteq(1, sandbox_reset_is_requested(dev_reset, OTHER_RESET_ID)); + ut_asserteq(1, sandbox_reset_is_requested(dev_reset, TEST_RESET_ID)); + ut_assertok(device_remove(dev_test, DM_REMOVE_NORMAL)); + ut_asserteq(0, sandbox_reset_is_requested(dev_reset, TEST_RESET_ID)); + ut_asserteq(0, sandbox_reset_is_requested(dev_reset, OTHER_RESET_ID)); + + return 0; +} +DM_TEST(dm_test_reset_bulk_devm, UT_TESTF_SCAN_FDT); -- cgit v1.2.3 From d4b722e3a85f3a5704501f3a71faa43db1979209 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Fri, 11 Sep 2020 13:43:34 +0530 Subject: drivers: gpio: Add a managed API to get a GPIO from the device-tree Add managed functions to get a gpio from the devce-tree, based on a property name (minus the '-gpios' suffix) and optionally an index. When the device is unbound, the GPIO is automatically released and the data structure is freed. Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Simon Glass Signed-off-by: Pratyush Yadav --- drivers/gpio/gpio-uclass.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++ include/asm-generic/gpio.h | 47 ++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 9c53299b6a..0c01413b58 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include #include @@ -1209,6 +1211,75 @@ int gpio_dev_request_index(struct udevice *dev, const char *nodename, flags, 0, dev); } +static void devm_gpiod_release(struct udevice *dev, void *res) +{ + dm_gpio_free(dev, res); +} + +static int devm_gpiod_match(struct udevice *dev, void *res, void *data) +{ + return res == data; +} + +struct gpio_desc *devm_gpiod_get_index(struct udevice *dev, const char *id, + unsigned int index, int flags) +{ + int rc; + struct gpio_desc *desc; + char *propname; + static const char suffix[] = "-gpios"; + + propname = malloc(strlen(id) + sizeof(suffix)); + if (!propname) { + rc = -ENOMEM; + goto end; + } + + strcpy(propname, id); + strcat(propname, suffix); + + desc = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc), + __GFP_ZERO); + if (unlikely(!desc)) { + rc = -ENOMEM; + goto end; + } + + rc = gpio_request_by_name(dev, propname, index, desc, flags); + +end: + if (propname) + free(propname); + + if (rc) + return ERR_PTR(rc); + + devres_add(dev, desc); + + return desc; +} + +struct gpio_desc *devm_gpiod_get_index_optional(struct udevice *dev, + const char *id, + unsigned int index, + int flags) +{ + struct gpio_desc *desc = devm_gpiod_get_index(dev, id, index, flags); + + if (IS_ERR(desc)) + return NULL; + + return desc; +} + +void devm_gpiod_put(struct udevice *dev, struct gpio_desc *desc) +{ + int rc; + + rc = devres_release(dev, devm_gpiod_release, devm_gpiod_match, desc); + WARN_ON(rc); +} + static int gpio_post_bind(struct udevice *dev) { struct udevice *child; diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index a57dd2665c..3ae1894a98 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -701,4 +701,51 @@ int gpio_get_number(const struct gpio_desc *desc); */ int gpio_get_acpi(const struct gpio_desc *desc, struct acpi_gpio *gpio); +/** + * devm_gpiod_get_index - Resource-managed gpiod_get() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * @index: index of the GPIO to obtain in the consumer + * @flags: optional GPIO initialization flags + * + * Managed gpiod_get(). GPIO descriptors returned from this function are + * automatically disposed on device unbind. + * Return the GPIO descriptor corresponding to the function con_id of device + * dev, -ENOENT if no GPIO has been assigned to the requested function, or + * another IS_ERR() code if an error occurred while trying to acquire the GPIO. + */ +struct gpio_desc *devm_gpiod_get_index(struct udevice *dev, const char *id, + unsigned int index, int flags); + +#define devm_gpiod_get(dev, id, flags) devm_gpiod_get_index(dev, id, 0, flags) +/** + * gpiod_get_optional - obtain an optional GPIO for a given GPIO function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + * @index: index of the GPIO to obtain in the consumer + * @flags: optional GPIO initialization flags + * + * This is equivalent to devm_gpiod_get(), except that when no GPIO was + * assigned to the requested function it will return NULL. This is convenient + * for drivers that need to handle optional GPIOs. + */ +struct gpio_desc *devm_gpiod_get_index_optional(struct udevice *dev, + const char *id, + unsigned int index, + int flags); + +#define devm_gpiod_get_optional(dev, id, flags) \ + devm_gpiod_get_index_optional(dev, id, 0, flags) + +/** + * devm_gpiod_put - Resource-managed gpiod_put() + * @dev: GPIO consumer + * @desc: GPIO descriptor to dispose of + * + * Dispose of a GPIO descriptor obtained with devm_gpiod_get() or + * devm_gpiod_get_index(). Normally this function will not be called as the GPIO + * will be disposed of by the resource management code. + */ +void devm_gpiod_put(struct udevice *dev, struct gpio_desc *desc); + #endif /* _ASM_GENERIC_GPIO_H_ */ -- cgit v1.2.3 From ffb22f6b847d21b30831c91294ec21d6a5e80ed4 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 24 Sep 2020 10:04:10 +0530 Subject: regmap: Add devm_regmap_init() Most of new linux drivers are using managed-API to allocate resources. To ease porting drivers from linux to U-Boot, introduce devm_regmap_init() as a managed API to get a regmap from the device tree. Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Simon Glass Signed-off-by: Pratyush Yadav --- drivers/core/regmap.c | 29 +++++++++++++++++++++++++++++ include/regmap.h | 18 ++++++++++++++++++ 2 files changed, 47 insertions(+) (limited to 'drivers') diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index a67a237b88..74225361fd 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -14,7 +14,10 @@ #include #include #include +#include #include +#include +#include DECLARE_GLOBAL_DATA_PTR; @@ -228,6 +231,32 @@ err: return ret; } + +static void devm_regmap_release(struct udevice *dev, void *res) +{ + regmap_uninit(*(struct regmap **)res); +} + +struct regmap *devm_regmap_init(struct udevice *dev, + const struct regmap_bus *bus, + void *bus_context, + const struct regmap_config *config) +{ + int rc; + struct regmap **mapp; + + mapp = devres_alloc(devm_regmap_release, sizeof(struct regmap *), + __GFP_ZERO); + if (unlikely(!mapp)) + return ERR_PTR(-ENOMEM); + + rc = regmap_init_mem(dev_ofnode(dev), mapp); + if (rc) + return ERR_PTR(rc); + + devres_add(dev, mapp); + return *mapp; +} #endif void *regmap_get_range(struct regmap *map, unsigned int range_num) diff --git a/include/regmap.h b/include/regmap.h index 30183c5e71..c7dd240a74 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -75,6 +75,9 @@ struct regmap_range { ulong size; }; +struct regmap_bus; +struct regmap_config; + /** * struct regmap - a way of accessing hardware/bus registers * @@ -335,6 +338,21 @@ int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count, int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index); +/** + * devm_regmap_init() - Initialise register map (device managed) + * + * @dev: Device that will be interacted with + * @bus: Bus-specific callbacks to use with device (IGNORED) + * @bus_context: Data passed to bus-specific callbacks (IGNORED) + * @config: Configuration for register map (IGNORED) + * + * @Return a valid pointer to a struct regmap or a ERR_PTR() on error. + * The structure is automatically freed when the device is unbound + */ +struct regmap *devm_regmap_init(struct udevice *dev, + const struct regmap_bus *bus, + void *bus_context, + const struct regmap_config *config); /** * regmap_get_range() - Obtain the base memory address of a regmap range * -- cgit v1.2.3 From 97d8a6970a3da5856633f2a705f0687fca4af9a5 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Thu, 24 Sep 2020 10:04:11 +0530 Subject: regmap: zero out the regmap on allocation Some fields will be introduced in the regmap structure that should be set to 0 by default. So, once we allocate a regmap, make sure it is zeroed out to avoid unexpected defaults for those values. Signed-off-by: Pratyush Yadav Reviewed-by: Simon Glass --- drivers/core/regmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index 74225361fd..809f58489f 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -30,8 +30,9 @@ DECLARE_GLOBAL_DATA_PTR; static struct regmap *regmap_alloc(int count) { struct regmap *map; + size_t size = sizeof(*map) + sizeof(map->ranges[0]) * count; - map = malloc(sizeof(*map) + sizeof(map->ranges[0]) * count); + map = calloc(1, size); if (!map) return NULL; map->range_count = count; -- cgit v1.2.3 From 78aaedba9f1b92335a4f0ce8344f6abf7a63dccb Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Thu, 24 Sep 2020 10:04:12 +0530 Subject: regmap: Allow specifying read/write width Right now, regmap_read() and regmap_write() read/write a 32-bit value only. To write other lengths, regmap_raw_read() and regmap_raw_write() need to be used. This means that any driver ported from Linux that relies on regmap_{read,write}() to know the size already has to be updated at each callsite. This makes the port harder to maintain. So, allow specifying the read/write width to make it easier to port the drivers, since now the only change needed is when initializing the regmap. Signed-off-by: Pratyush Yadav Reviewed-by: Simon Glass --- drivers/core/regmap.c | 15 ++++++++++++--- include/regmap.h | 38 ++++++++++++++++++++++---------------- 2 files changed, 34 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index 809f58489f..c71b961234 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -25,6 +25,10 @@ DECLARE_GLOBAL_DATA_PTR; * regmap_alloc() - Allocate a regmap with a given number of ranges. * * @count: Number of ranges to be allocated for the regmap. + * + * The default regmap width is set to REGMAP_SIZE_32. Callers can override it + * if they need. + * * Return: A pointer to the newly allocated regmap, or NULL on error. */ static struct regmap *regmap_alloc(int count) @@ -36,6 +40,7 @@ static struct regmap *regmap_alloc(int count) if (!map) return NULL; map->range_count = count; + map->width = REGMAP_SIZE_32; return map; } @@ -244,7 +249,7 @@ struct regmap *devm_regmap_init(struct udevice *dev, const struct regmap_config *config) { int rc; - struct regmap **mapp; + struct regmap **mapp, *map; mapp = devres_alloc(devm_regmap_release, sizeof(struct regmap *), __GFP_ZERO); @@ -255,6 +260,10 @@ struct regmap *devm_regmap_init(struct udevice *dev, if (rc) return ERR_PTR(rc); + map = *mapp; + if (config) + map->width = config->width; + devres_add(dev, mapp); return *mapp; } @@ -377,7 +386,7 @@ int regmap_raw_read(struct regmap *map, uint offset, void *valp, size_t val_len) int regmap_read(struct regmap *map, uint offset, uint *valp) { - return regmap_raw_read(map, offset, valp, REGMAP_SIZE_32); + return regmap_raw_read(map, offset, valp, map->width); } static inline void __write_8(u8 *addr, const u8 *val, @@ -487,7 +496,7 @@ int regmap_raw_write(struct regmap *map, uint offset, const void *val, int regmap_write(struct regmap *map, uint offset, uint val) { - return regmap_raw_write(map, offset, &val, REGMAP_SIZE_32); + return regmap_raw_write(map, offset, &val, map->width); } int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val) diff --git a/include/regmap.h b/include/regmap.h index c7dd240a74..19474e6de1 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -76,16 +76,28 @@ struct regmap_range { }; struct regmap_bus; -struct regmap_config; + +/** + * struct regmap_config - Configure the behaviour of a regmap + * + * @width: Width of the read/write operations. Defaults to + * REGMAP_SIZE_32 if set to 0. + */ +struct regmap_config { + enum regmap_size_t width; +}; /** * struct regmap - a way of accessing hardware/bus registers * + * @width: Width of the read/write operations. Defaults to + * REGMAP_SIZE_32 if set to 0. * @range_count: Number of ranges available within the map * @ranges: Array of ranges */ struct regmap { enum regmap_endianness_t endianness; + enum regmap_size_t width; int range_count; struct regmap_range ranges[0]; }; @@ -96,32 +108,24 @@ struct regmap { */ /** - * regmap_write() - Write a 32-bit value to a regmap + * regmap_write() - Write a value to a regmap * * @map: Regmap to write to * @offset: Offset in the regmap to write to * @val: Data to write to the regmap at the specified offset * - * Note that this function will only write values of 32 bit width to the - * regmap; if the size of data to be read is different, the regmap_raw_write - * function can be used. - * * Return: 0 if OK, -ve on error */ int regmap_write(struct regmap *map, uint offset, uint val); /** - * regmap_read() - Read a 32-bit value from a regmap + * regmap_read() - Read a value from a regmap * * @map: Regmap to read from * @offset: Offset in the regmap to read from * @valp: Pointer to the buffer to receive the data read from the regmap * at the specified offset * - * Note that this function will only read values of 32 bit width from the - * regmap; if the size of data to be read is different, the regmap_raw_read - * function can be used. - * * Return: 0 if OK, -ve on error */ int regmap_read(struct regmap *map, uint offset, uint *valp); @@ -135,8 +139,9 @@ int regmap_read(struct regmap *map, uint offset, uint *valp); * @val_len: Length of the data to be written to the regmap * * Note that this function will, as opposed to regmap_write, write data of - * arbitrary length to the regmap, and not just 32-bit values, and is thus a - * generalized version of regmap_write. + * arbitrary length to the regmap, and not just the size configured in the + * regmap (defaults to 32-bit) and is thus a generalized version of + * regmap_write. * * Return: 0 if OK, -ve on error */ @@ -153,8 +158,9 @@ int regmap_raw_write(struct regmap *map, uint offset, const void *val, * @val_len: Length of the data to be read from the regmap * * Note that this function will, as opposed to regmap_read, read data of - * arbitrary length from the regmap, and not just 32-bit values, and is thus a - * generalized version of regmap_read. + * arbitrary length from the regmap, and not just the size configured in the + * regmap (defaults to 32-bit) and is thus a generalized version of + * regmap_read. * * Return: 0 if OK, -ve on error */ @@ -344,7 +350,7 @@ int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index); * @dev: Device that will be interacted with * @bus: Bus-specific callbacks to use with device (IGNORED) * @bus_context: Data passed to bus-specific callbacks (IGNORED) - * @config: Configuration for register map (IGNORED) + * @config: Configuration for register map * * @Return a valid pointer to a struct regmap or a ERR_PTR() on error. * The structure is automatically freed when the device is unbound -- cgit v1.2.3 From 7aa5ddffe7fbafe7ef828088ba1dbc76270300c5 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Thu, 24 Sep 2020 10:04:13 +0530 Subject: regmap: Allow left shifting register offset before access Drivers can configure it to adjust the final read/write location. Signed-off-by: Pratyush Yadav Reviewed-by: Simon Glass --- drivers/core/regmap.c | 6 +++++- include/regmap.h | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index c71b961234..173ae80890 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -261,8 +261,10 @@ struct regmap *devm_regmap_init(struct udevice *dev, return ERR_PTR(rc); map = *mapp; - if (config) + if (config) { map->width = config->width; + map->reg_offset_shift = config->reg_offset_shift; + } devres_add(dev, mapp); return *mapp; @@ -349,6 +351,7 @@ int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset, } range = &map->ranges[range_num]; + offset <<= map->reg_offset_shift; if (offset + val_len > range->size) { debug("%s: offset/size combination invalid\n", __func__); return -ERANGE; @@ -458,6 +461,7 @@ int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset, } range = &map->ranges[range_num]; + offset <<= map->reg_offset_shift; if (offset + val_len > range->size) { debug("%s: offset/size combination invalid\n", __func__); return -ERANGE; diff --git a/include/regmap.h b/include/regmap.h index 19474e6de1..e6c59dfbce 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -82,9 +82,12 @@ struct regmap_bus; * * @width: Width of the read/write operations. Defaults to * REGMAP_SIZE_32 if set to 0. + * @reg_offset_shift Left shift the register offset by this value before + * performing read or write. */ struct regmap_config { enum regmap_size_t width; + u32 reg_offset_shift; }; /** @@ -92,12 +95,15 @@ struct regmap_config { * * @width: Width of the read/write operations. Defaults to * REGMAP_SIZE_32 if set to 0. + * @reg_offset_shift Left shift the register offset by this value before + * performing read or write. * @range_count: Number of ranges available within the map * @ranges: Array of ranges */ struct regmap { enum regmap_endianness_t endianness; enum regmap_size_t width; + u32 reg_offset_shift; int range_count; struct regmap_range ranges[0]; }; -- cgit v1.2.3 From 0e01a7c3f4b6a42f768a19f7fc1df92d3e3b5d37 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Thu, 24 Sep 2020 10:04:14 +0530 Subject: regmap: Add regmap_init_mem_range() Right now, the base of a regmap can only be obtained from the device tree. This makes it impossible for devices which calculate the base at runtime to use a regmap. An example of such a device is the Cadence Sierra PHY. Allow creating a regmap with one range whose start and size can be specified by the driver based on calculations at runtime. Signed-off-by: Pratyush Yadav Reviewed-by: Simon Glass --- drivers/core/regmap.c | 27 +++++++++++++++++++++++++++ include/regmap.h | 19 +++++++++++++++++++ 2 files changed, 46 insertions(+) (limited to 'drivers') diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index 173ae80890..a9087df32b 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -164,6 +164,33 @@ err: return ret; } +int regmap_init_mem_range(ofnode node, ulong r_start, ulong r_size, + struct regmap **mapp) +{ + struct regmap *map; + struct regmap_range *range; + + map = regmap_alloc(1); + if (!map) + return -ENOMEM; + + range = &map->ranges[0]; + range->start = r_start; + range->size = r_size; + + if (ofnode_read_bool(node, "little-endian")) + map->endianness = REGMAP_LITTLE_ENDIAN; + else if (ofnode_read_bool(node, "big-endian")) + map->endianness = REGMAP_BIG_ENDIAN; + else if (ofnode_read_bool(node, "native-endian")) + map->endianness = REGMAP_NATIVE_ENDIAN; + else /* Default: native endianness */ + map->endianness = REGMAP_NATIVE_ENDIAN; + + *mapp = map; + return 0; +} + int regmap_init_mem(ofnode node, struct regmap **mapp) { struct regmap_range *range; diff --git a/include/regmap.h b/include/regmap.h index e6c59dfbce..7c8ad04759 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -350,6 +350,25 @@ int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count, int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index); +/** + * regmap_init_mem_range() - Set up a new memory region for ofnode with the + * specified range. + * + * @node: The ofnode for the map. + * @r_start: Start of the range. + * @r_size: Size of the range. + * @mapp: Returns allocated map. + * + * Return: 0 in success, -errno otherwise + * + * This creates a regmap with one range where instead of extracting the range + * from 'node', it is created based on the parameters specified. This is + * useful when a driver needs to calculate the base of the regmap at runtime, + * and can't specify it in device tree. + */ +int regmap_init_mem_range(ofnode node, ulong r_start, ulong r_size, + struct regmap **mapp); + /** * devm_regmap_init() - Initialise register map (device managed) * -- cgit v1.2.3 From d8babb9598ce237ffb1feccb576c66a21c52e5f7 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Thu, 24 Sep 2020 10:04:15 +0530 Subject: regmap: Allow devices to specify regmap range start and size in config Some devices need to calculate the regmap base address at runtime. This makes it impossible to use device tree to get the regmap base. Instead, allow devices to specify it in the regmap config. This will create a regmap with a single range that corresponds to the start and size given by the driver. Signed-off-by: Pratyush Yadav Reviewed-by: Simon Glass --- drivers/core/regmap.c | 6 +++++- include/regmap.h | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index a9087df32b..a3da0cf7c3 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -283,7 +283,11 @@ struct regmap *devm_regmap_init(struct udevice *dev, if (unlikely(!mapp)) return ERR_PTR(-ENOMEM); - rc = regmap_init_mem(dev_ofnode(dev), mapp); + if (config && config->r_size != 0) + rc = regmap_init_mem_range(dev_ofnode(dev), config->r_start, + config->r_size, mapp); + else + rc = regmap_init_mem(dev_ofnode(dev), mapp); if (rc) return ERR_PTR(rc); diff --git a/include/regmap.h b/include/regmap.h index 7c8ad04759..7a6fcc7f53 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -84,10 +84,16 @@ struct regmap_bus; * REGMAP_SIZE_32 if set to 0. * @reg_offset_shift Left shift the register offset by this value before * performing read or write. + * @r_start: If specified, the regmap is created with one range + * which starts at this address, instead of finding the + * start from device tree. + * @r_size: Same as above for the range size */ struct regmap_config { enum regmap_size_t width; u32 reg_offset_shift; + ulong r_start; + ulong r_size; }; /** -- cgit v1.2.3 From 1c4db59d9bf711e7f8902eaa145959429d659679 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 24 Sep 2020 10:04:16 +0530 Subject: regmap: Add support for regmap fields A regmap field is an abstraction available in Linux. It provides to access bitfields in a regmap without having to worry about shifts and masks. Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Simon Glass Signed-off-by: Pratyush Yadav --- drivers/core/regmap.c | 83 ++++++++++++++++++++++++++++++++++ include/regmap.h | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+) (limited to 'drivers') diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index a3da0cf7c3..c2bed88eac 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -18,6 +18,20 @@ #include #include #include +#include + +/* + * Internal representation of a regmap field. Instead of storing the MSB and + * LSB, store the shift and mask. This makes the code a bit cleaner and faster + * because the shift and mask don't have to be calculated every time. + */ +struct regmap_field { + struct regmap *regmap; + unsigned int mask; + /* lsb */ + unsigned int shift; + unsigned int reg; +}; DECLARE_GLOBAL_DATA_PTR; @@ -547,3 +561,72 @@ int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val) return regmap_write(map, offset, reg | (val & mask)); } + +int regmap_field_read(struct regmap_field *field, unsigned int *val) +{ + int ret; + unsigned int reg_val; + + ret = regmap_read(field->regmap, field->reg, ®_val); + if (ret != 0) + return ret; + + reg_val &= field->mask; + reg_val >>= field->shift; + *val = reg_val; + + return ret; +} + +int regmap_field_write(struct regmap_field *field, unsigned int val) +{ + return regmap_update_bits(field->regmap, field->reg, field->mask, + val << field->shift); +} + +static void regmap_field_init(struct regmap_field *rm_field, + struct regmap *regmap, + struct reg_field reg_field) +{ + rm_field->regmap = regmap; + rm_field->reg = reg_field.reg; + rm_field->shift = reg_field.lsb; + rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb); +} + +struct regmap_field *devm_regmap_field_alloc(struct udevice *dev, + struct regmap *regmap, + struct reg_field reg_field) +{ + struct regmap_field *rm_field = devm_kzalloc(dev, sizeof(*rm_field), + GFP_KERNEL); + if (!rm_field) + return ERR_PTR(-ENOMEM); + + regmap_field_init(rm_field, regmap, reg_field); + + return rm_field; +} + +void devm_regmap_field_free(struct udevice *dev, struct regmap_field *field) +{ + devm_kfree(dev, field); +} + +struct regmap_field *regmap_field_alloc(struct regmap *regmap, + struct reg_field reg_field) +{ + struct regmap_field *rm_field = kzalloc(sizeof(*rm_field), GFP_KERNEL); + + if (!rm_field) + return ERR_PTR(-ENOMEM); + + regmap_field_init(rm_field, regmap, reg_field); + + return rm_field; +} + +void regmap_field_free(struct regmap_field *field) +{ + kfree(field); +} diff --git a/include/regmap.h b/include/regmap.h index 7a6fcc7f53..c6258face3 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -312,6 +312,43 @@ int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset, regmap_read_poll_timeout_test(map, addr, val, cond, sleep_us, \ timeout_ms, 0) \ +/** + * regmap_field_read_poll_timeout - Poll until a condition is met or a timeout + * occurs + * + * @field: Regmap field to read from + * @val: Unsigned integer variable to read the value into + * @cond: Break condition (usually involving @val) + * @sleep_us: Maximum time to sleep between reads in us (0 tight-loops). + * @timeout_ms: Timeout in ms, 0 means never timeout + * + * Returns 0 on success and -ETIMEDOUT upon a timeout or the regmap_field_read + * error return value in case of a error read. In the two former cases, + * the last read value at @addr is stored in @val. + * + * This is modelled after the regmap_read_poll_timeout macros in linux but + * with millisecond timeout. + */ +#define regmap_field_read_poll_timeout(field, val, cond, sleep_us, timeout_ms) \ +({ \ + unsigned long __start = get_timer(0); \ + int __ret; \ + for (;;) { \ + __ret = regmap_field_read((field), &(val)); \ + if (__ret) \ + break; \ + if (cond) \ + break; \ + if ((timeout_ms) && get_timer(__start) > (timeout_ms)) { \ + __ret = regmap_field_read((field), &(val)); \ + break; \ + } \ + if ((sleep_us)) \ + udelay((sleep_us)); \ + } \ + __ret ?: ((cond) ? 0 : -ETIMEDOUT); \ +}) + /** * regmap_update_bits() - Perform a read/modify/write using a mask * @@ -407,4 +444,89 @@ void *regmap_get_range(struct regmap *map, unsigned int range_num); */ int regmap_uninit(struct regmap *map); +/** + * struct reg_field - Description of an register field + * + * @reg: Offset of the register within the regmap bank + * @lsb: lsb of the register field. + * @msb: msb of the register field. + */ +struct reg_field { + unsigned int reg; + unsigned int lsb; + unsigned int msb; +}; + +struct regmap_field; + +/** + * REG_FIELD() - A convenient way to initialize a 'struct reg_feild'. + * + * @_reg: Offset of the register within the regmap bank + * @_lsb: lsb of the register field. + * @_msb: msb of the register field. + * + * Register fields are often described in terms of 3 things: the register it + * belongs to, its LSB, and its MSB. This macro can be used by drivers to + * clearly and easily initialize a 'struct regmap_field'. + * + * For example, say a device has a register at offset DEV_REG1 (0x100) and a + * field of DEV_REG1 is on bits [7:3]. So a driver can initialize a regmap + * field for this by doing: + * struct reg_field field = REG_FIELD(DEV_REG1, 3, 7); + */ +#define REG_FIELD(_reg, _lsb, _msb) { \ + .reg = _reg, \ + .lsb = _lsb, \ + .msb = _msb, \ + } + +/** + * devm_regmap_field_alloc() - Allocate and initialise a register field. + * + * @dev: Device that will be interacted with + * @regmap: regmap bank in which this register field is located. + * @reg_field: Register field with in the bank. + * + * The return value will be an ERR_PTR() on error or a valid pointer + * to a struct regmap_field. The regmap_field will be automatically freed + * by the device management code. + */ +struct regmap_field *devm_regmap_field_alloc(struct udevice *dev, + struct regmap *regmap, + struct reg_field reg_field); +/** + * devm_regmap_field_free() - Free a register field allocated using + * devm_regmap_field_alloc. + * + * @dev: Device that will be interacted with + * @field: regmap field which should be freed. + * + * Free register field allocated using devm_regmap_field_alloc(). Usually + * drivers need not call this function, as the memory allocated via devm + * will be freed as per device-driver life-cyle. + */ +void devm_regmap_field_free(struct udevice *dev, struct regmap_field *field); + +/** + * regmap_field_write() - Write a value to a regmap field + * + * @field: Regmap field to write to + * @val: Data to write to the regmap at the specified offset + * + * Return: 0 if OK, -ve on error + */ +int regmap_field_write(struct regmap_field *field, unsigned int val); + +/** + * regmap_read() - Read a 32-bit value from a regmap + * + * @field: Regmap field to write to + * @valp: Pointer to the buffer to receive the data read from the regmap + * field + * + * Return: 0 if OK, -ve on error + */ +int regmap_field_read(struct regmap_field *field, unsigned int *val); + #endif -- cgit v1.2.3 From 358599efd827b0ee48af864537cc86facc9167c0 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 9 Sep 2020 18:44:00 +0200 Subject: firmware: add SCMI agent uclass This change introduces SCMI agent uclass to interact with a firmware using the SCMI protocols [1]. SCMI agent uclass currently supports a single method to request processing of the SCMI message by an identified server. A SCMI message is made of a byte payload associated to a protocol ID and a message ID, all defined by the SCMI specification [1]. On return from process_msg() method, the caller gets the service response. SCMI agent uclass defines a post bind generic sequence for all devices. The sequence binds all the SCMI protocols listed in the FDT for that SCMI agent device. Currently none, but later change will introduce protocols. This change implements a simple sandbox device for the SCMI agent uclass. The sandbox nicely answers SCMI_NOT_SUPPORTED to SCMI messages. To prepare for further test support, the sandbox exposes a architecture function for test application to read the sandbox emulated devices state. Currently supports 2 SCMI agents, identified by an ID in the FDT device name. The simplistic DM test does nothing yet. SCMI agent uclass is designed for platforms that embed a SCMI server in a firmware hosted somewhere, for example in a companion co-processor or in the secure world of the executing processor. SCMI protocols allow an SCMI agent to discover and access external resources as clock, reset controllers and more. SCMI agent and server communicate following the SCMI specification [1]. This SCMI agent implementation complies with the DT bindings defined in the Linux kernel source tree regarding SCMI agent description since v5.8. Links: [1] https://developer.arm.com/architectures/system-architectures/software-standards/scmi Signed-off-by: Etienne Carriere Cc: Simon Glass Cc: Peng Fan Cc: Sudeep Holla Reviewed-by: Simon Glass --- arch/sandbox/dts/test.dts | 16 ++++ arch/sandbox/include/asm/scmi_test.h | 43 +++++++++ configs/sandbox_defconfig | 2 + drivers/firmware/Kconfig | 2 + drivers/firmware/Makefile | 1 + drivers/firmware/scmi/Kconfig | 17 ++++ drivers/firmware/scmi/Makefile | 2 + drivers/firmware/scmi/sandbox-scmi_agent.c | 142 +++++++++++++++++++++++++++++ drivers/firmware/scmi/scmi_agent-uclass.c | 107 ++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/scmi_agent-uclass.h | 24 +++++ include/scmi_agent.h | 68 ++++++++++++++ include/scmi_protocols.h | 41 +++++++++ test/dm/Makefile | 1 + test/dm/scmi.c | 38 ++++++++ 15 files changed, 505 insertions(+) create mode 100644 arch/sandbox/include/asm/scmi_test.h create mode 100644 drivers/firmware/scmi/Kconfig create mode 100644 drivers/firmware/scmi/Makefile create mode 100644 drivers/firmware/scmi/sandbox-scmi_agent.c create mode 100644 drivers/firmware/scmi/scmi_agent-uclass.c create mode 100644 include/scmi_agent-uclass.h create mode 100644 include/scmi_agent.h create mode 100644 include/scmi_protocols.h create mode 100644 test/dm/scmi.c (limited to 'drivers') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 2523e59723..4769ec0866 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -366,6 +366,22 @@ sandbox_firmware: sandbox-firmware { compatible = "sandbox,firmware"; }; + + sandbox-scmi-agent@0 { + compatible = "sandbox,scmi-agent"; + #address-cells = <1>; + #size-cells = <0>; + }; + + sandbox-scmi-agent@1 { + compatible = "sandbox,scmi-agent"; + #address-cells = <1>; + #size-cells = <0>; + + protocol@10 { + reg = <0x10>; + }; + }; }; pinctrl-gpio { diff --git a/arch/sandbox/include/asm/scmi_test.h b/arch/sandbox/include/asm/scmi_test.h new file mode 100644 index 0000000000..a811fe19c3 --- /dev/null +++ b/arch/sandbox/include/asm/scmi_test.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020, Linaro Limited + */ + +#ifndef __SANDBOX_SCMI_TEST_H +#define __SANDBOX_SCMI_TEST_H + +struct udevice; +struct sandbox_scmi_agent; +struct sandbox_scmi_service; + +/** + * struct sandbox_scmi_agent - Simulated SCMI service seen by SCMI agent + * @idx: Identifier for the SCMI agent, its index + */ +struct sandbox_scmi_agent { + uint idx; +}; + +/** + * struct sandbox_scmi_service - Reference to simutaed SCMI agents/services + * @agent: Pointer to SCMI sandbox agent pointers array + * @agent_count: Number of emulated agents exposed in array @agent. + */ +struct sandbox_scmi_service { + struct sandbox_scmi_agent **agent; + size_t agent_count; +}; + +#ifdef CONFIG_SCMI_FIRMWARE +/** + * sandbox_scmi_service_context - Get the simulated SCMI services context + * @return: Reference to backend simulated resources state + */ +struct sandbox_scmi_service *sandbox_scmi_service_ctx(void); +#else +static inline struct sandbox_scmi_service *sandbox_scmi_service_ctx(void) +{ + return NULL; +} +#endif /* CONFIG_SCMI_FIRMWARE */ +#endif /* __SANDBOX_SCMI_TEST_H */ diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 6e9f029cc9..2c130c01f0 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -132,6 +132,8 @@ CONFIG_BOARD_SANDBOX=y CONFIG_DMA=y CONFIG_DMA_CHANNELS=y CONFIG_SANDBOX_DMA=y +CONFIG_FIRMWARE=y +CONFIG_SCMI_FIRMWARE=y CONFIG_GPIO_HOG=y CONFIG_DM_GPIO_LOOKUP_LABEL=y CONFIG_PM8916_GPIO=y diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index b70a206355..ef958b3a7a 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -36,3 +36,5 @@ config ZYNQMP_FIRMWARE various platform management services. Say yes to enable ZynqMP firmware interface driver. If in doubt, say N. + +source "drivers/firmware/scmi/Kconfig" diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index a0c250a473..7ce83d72bd 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_$(SPL_)ARM_PSCI_FW) += psci.o obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o obj-$(CONFIG_SANDBOX) += firmware-sandbox.o obj-$(CONFIG_ZYNQMP_FIRMWARE) += firmware-zynqmp.o +obj-$(CONFIG_SCMI_FIRMWARE) += scmi/ diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig new file mode 100644 index 0000000000..57e2ebbe42 --- /dev/null +++ b/drivers/firmware/scmi/Kconfig @@ -0,0 +1,17 @@ +config SCMI_FIRMWARE + bool "Enable SCMI support" + select FIRMWARE + select OF_TRANSLATE + depends on SANDBOX + help + System Control and Management Interface (SCMI) is a communication + protocol that defines standard interfaces for power, performance + and system management. The SCMI specification is available at + https://developer.arm.com/architectures/system-architectures/software-standards/scmi + + An SCMI agent communicates with a related SCMI server firmware + located in another sub-system, as a companion micro controller + or a companion host in the CPU system. + + Communications between agent (client) and the SCMI server are + based on message exchange. diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile new file mode 100644 index 0000000000..336ea1f2a3 --- /dev/null +++ b/drivers/firmware/scmi/Makefile @@ -0,0 +1,2 @@ +obj-y += scmi_agent-uclass.o +obj-$(CONFIG_SANDBOX) += sandbox-scmi_agent.o diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c new file mode 100644 index 0000000000..3179438aab --- /dev/null +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The sandbox SCMI agent driver simulates to some extend a SCMI message + * processing. It simulates few of the SCMI services for some of the + * SCMI protocols embedded in U-Boot. Currently none. + * + * This driver simulates 2 SCMI agents for test purpose. + * + * This Driver exports sandbox_scmi_service_ct() for the test sequence to + * get the state of the simulated services (clock state, rate, ...) and + * check back-end device state reflects the request send through the + * various uclass devices, currently nothing. + */ + +#define SANDBOX_SCMI_AGENT_COUNT 2 + +/* The list saves to simulted end devices references for test purpose */ +struct sandbox_scmi_agent *sandbox_scmi_agent_list[SANDBOX_SCMI_AGENT_COUNT]; + +static struct sandbox_scmi_service sandbox_scmi_service_state = { + .agent = sandbox_scmi_agent_list, + .agent_count = SANDBOX_SCMI_AGENT_COUNT, +}; + +struct sandbox_scmi_service *sandbox_scmi_service_ctx(void) +{ + return &sandbox_scmi_service_state; +} + +static void debug_print_agent_state(struct udevice *dev, char *str) +{ + struct sandbox_scmi_agent *agent = dev_get_priv(dev); + + dev_dbg(dev, "Dump sandbox_scmi_agent %u: %s\n", agent->idx, str); +}; + +static int sandbox_scmi_test_process_msg(struct udevice *dev, + struct scmi_msg *msg) +{ + switch (msg->protocol_id) { + case SCMI_PROTOCOL_ID_BASE: + case SCMI_PROTOCOL_ID_POWER_DOMAIN: + case SCMI_PROTOCOL_ID_SYSTEM: + case SCMI_PROTOCOL_ID_PERF: + case SCMI_PROTOCOL_ID_CLOCK: + case SCMI_PROTOCOL_ID_SENSOR: + case SCMI_PROTOCOL_ID_RESET_DOMAIN: + *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED; + return 0; + default: + break; + } + + dev_err(dev, "%s(%s): Unhandled protocol_id %#x/message_id %#x\n", + __func__, dev->name, msg->protocol_id, msg->message_id); + + if (msg->out_msg_sz < sizeof(u32)) + return -EINVAL; + + /* Intentionnaly report unhandled IDs through the SCMI return code */ + *(u32 *)msg->out_msg = SCMI_PROTOCOL_ERROR; + return 0; +} + +static int sandbox_scmi_test_remove(struct udevice *dev) +{ + struct sandbox_scmi_agent *agent = dev_get_priv(dev); + + debug_print_agent_state(dev, "removed"); + + /* We only need to dereference the agent in the context */ + sandbox_scmi_service_ctx()->agent[agent->idx] = NULL; + + return 0; +} + +static int sandbox_scmi_test_probe(struct udevice *dev) +{ + static const char basename[] = "sandbox-scmi-agent@"; + struct sandbox_scmi_agent *agent = dev_get_priv(dev); + const size_t basename_size = sizeof(basename) - 1; + + if (strncmp(basename, dev->name, basename_size)) + return -ENOENT; + + switch (dev->name[basename_size]) { + case '0': + *agent = (struct sandbox_scmi_agent){ + .idx = 0, + }; + break; + case '1': + *agent = (struct sandbox_scmi_agent){ + .idx = 1, + }; + break; + default: + dev_err(dev, "%s(): Unexpected agent ID %s\n", + __func__, dev->name + basename_size); + return -ENOENT; + } + + debug_print_agent_state(dev, "probed"); + + /* Save reference for tests purpose */ + sandbox_scmi_service_ctx()->agent[agent->idx] = agent; + + return 0; +}; + +static const struct udevice_id sandbox_scmi_test_ids[] = { + { .compatible = "sandbox,scmi-agent" }, + { } +}; + +struct scmi_agent_ops sandbox_scmi_test_ops = { + .process_msg = sandbox_scmi_test_process_msg, +}; + +U_BOOT_DRIVER(sandbox_scmi_agent) = { + .name = "sandbox-scmi_agent", + .id = UCLASS_SCMI_AGENT, + .of_match = sandbox_scmi_test_ids, + .priv_auto_alloc_size = sizeof(struct sandbox_scmi_agent), + .probe = sandbox_scmi_test_probe, + .remove = sandbox_scmi_test_remove, + .ops = &sandbox_scmi_test_ops, +}; diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c new file mode 100644 index 0000000000..67a6f907c9 --- /dev/null +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Linaro Limited. + */ + +#include +#include +#include +#include +#include + +#include +#include + +/** + * struct error_code - Helper structure for SCMI error code conversion + * @scmi: SCMI error code + * @errno: Related standard error number + */ +struct error_code { + int scmi; + int errno; +}; + +static const struct error_code scmi_linux_errmap[] = { + { .scmi = SCMI_NOT_SUPPORTED, .errno = -EOPNOTSUPP, }, + { .scmi = SCMI_INVALID_PARAMETERS, .errno = -EINVAL, }, + { .scmi = SCMI_DENIED, .errno = -EACCES, }, + { .scmi = SCMI_NOT_FOUND, .errno = -ENOENT, }, + { .scmi = SCMI_OUT_OF_RANGE, .errno = -ERANGE, }, + { .scmi = SCMI_BUSY, .errno = -EBUSY, }, + { .scmi = SCMI_COMMS_ERROR, .errno = -ECOMM, }, + { .scmi = SCMI_GENERIC_ERROR, .errno = -EIO, }, + { .scmi = SCMI_HARDWARE_ERROR, .errno = -EREMOTEIO, }, + { .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, }, +}; + +int scmi_to_linux_errno(s32 scmi_code) +{ + int n; + + if (!scmi_code) + return 0; + + for (n = 0; n < ARRAY_SIZE(scmi_linux_errmap); n++) + if (scmi_code == scmi_linux_errmap[n].scmi) + return scmi_linux_errmap[1].errno; + + return -EPROTO; +} + +/* + * SCMI agent devices binds devices of various uclasses depeding on + * the FDT description. scmi_bind_protocol() is a generic bind sequence + * called by the uclass at bind stage, that is uclass post_bind. + */ +static int scmi_bind_protocols(struct udevice *dev) +{ + int ret = 0; + ofnode node; + struct driver *drv; + + dev_for_each_subnode(node, dev) { + u32 protocol_id; + + if (!ofnode_is_available(node)) + continue; + + if (ofnode_read_u32(node, "reg", &protocol_id)) + continue; + + switch (protocol_id) { + default: + dev_info(dev, "Ignore unsupported SCMI protocol %#x\n", + protocol_id); + continue; + } + + ret = device_bind_ofnode(dev, drv, ofnode_get_name(node), + NULL, node, NULL); + if (ret) + break; + } + + return ret; +} + +static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev) +{ + return (const struct scmi_agent_ops *)dev->driver->ops; +} + +int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg) +{ + const struct scmi_agent_ops *ops = transport_dev_ops(dev); + + if (ops->process_msg) + return ops->process_msg(dev, msg); + + return -EPROTONOSUPPORT; +} + +UCLASS_DRIVER(scmi_agent) = { + .id = UCLASS_SCMI_AGENT, + .name = "scmi_agent", + .post_bind = scmi_bind_protocols, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 4ec5fa6670..88f10c4622 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -94,6 +94,7 @@ enum uclass_id { UCLASS_RESET, /* Reset controller device */ UCLASS_RNG, /* Random Number Generator */ UCLASS_RTC, /* Real time clock device */ + UCLASS_SCMI_AGENT, /* Interface with an SCMI server */ UCLASS_SCSI, /* SCSI device */ UCLASS_SERIAL, /* Serial UART */ UCLASS_SIMPLE_BUS, /* Bus with child devices */ diff --git a/include/scmi_agent-uclass.h b/include/scmi_agent-uclass.h new file mode 100644 index 0000000000..a501d1b482 --- /dev/null +++ b/include/scmi_agent-uclass.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2019-2020 Linaro Limited. + */ +#ifndef _SCMI_AGENT_UCLASS_H +#define _SCMI_AGENT_UCLASS_H + +struct udevice; +struct scmi_msg; + +/** + * struct scmi_transport_ops - The functions that a SCMI transport layer must implement. + */ +struct scmi_agent_ops { + /* + * process_msg - Request transport to get the SCMI message processed + * + * @agent: Agent using the transport + * @msg: SCMI message to be transmitted + */ + int (*process_msg)(struct udevice *dev, struct scmi_msg *msg); +}; + +#endif /* _SCMI_TRANSPORT_UCLASS_H */ diff --git a/include/scmi_agent.h b/include/scmi_agent.h new file mode 100644 index 0000000000..f1be9ff209 --- /dev/null +++ b/include/scmi_agent.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. + * Copyright (C) 2019-2020, Linaro Limited + * + * An SCMI agent device represent on communication path from a + * device driver to the remote SCMI server which driver sends + * messages to and receives response messages from. + */ +#ifndef SCMI_AGENT_H +#define SCMI_AGENT_H + +#include + +struct udevice; + +/* + * struct scmi_msg - Context of a SCMI message sent and the response received + * + * @protocol_id: SCMI protocol ID + * @message_id: SCMI message ID for a defined protocol ID + * @in_msg: Pointer to the message payload sent by the driver + * @in_msg_sz: Byte size of the message payload sent + * @out_msg: Pointer to buffer to store response message payload + * @out_msg_sz: Byte size of the response buffer and response payload + */ +struct scmi_msg { + unsigned int protocol_id; + unsigned int message_id; + u8 *in_msg; + size_t in_msg_sz; + u8 *out_msg; + size_t out_msg_sz; +}; + +/* Helper macro to match a message on input/output array references */ +#define SCMI_MSG_IN(_protocol, _message, _in_array, _out_array) \ + (struct scmi_msg){ \ + .protocol_id = (_protocol), \ + .message_id = (_message), \ + .in_msg = (uint8_t *)&(_in_array), \ + .in_msg_sz = sizeof(_in_array), \ + .out_msg = (uint8_t *)&(_out_array), \ + .out_msg_sz = sizeof(_out_array), \ + } + +/** + * scmi_send_and_process_msg() - send and process a SCMI message + * + * Send a message to a SCMI server through a target SCMI agent device. + * Caller sets scmi_msg::out_msg_sz to the output message buffer size. + * On return, scmi_msg::out_msg_sz stores the response payload size. + * + * @dev: SCMI agent device + * @msg: Message structure reference + * @return 0 on success and a negative errno on failure + */ +int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg); + +/** + * scmi_to_linux_errno() - Convert an SCMI error code into a Linux errno code + * + * @scmi_errno: SCMI error code value + * @return 0 for successful status and a negative errno otherwise + */ +int scmi_to_linux_errno(s32 scmi_errno); + +#endif /* SCMI_H */ diff --git a/include/scmi_protocols.h b/include/scmi_protocols.h new file mode 100644 index 0000000000..86a2d109c8 --- /dev/null +++ b/include/scmi_protocols.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. + * Copyright (C) 2019-2020, Linaro Limited + */ +#ifndef _SCMI_PROTOCOLS_H +#define _SCMI_PROTOCOLS_H + +#include + +/* + * Subset the SCMI protocols definition + * based on SCMI specification v2.0 (DEN0056B) + * https://developer.arm.com/docs/den0056/b + */ + +enum scmi_std_protocol { + SCMI_PROTOCOL_ID_BASE = 0x10, + SCMI_PROTOCOL_ID_POWER_DOMAIN = 0x11, + SCMI_PROTOCOL_ID_SYSTEM = 0x12, + SCMI_PROTOCOL_ID_PERF = 0x13, + SCMI_PROTOCOL_ID_CLOCK = 0x14, + SCMI_PROTOCOL_ID_SENSOR = 0x15, + SCMI_PROTOCOL_ID_RESET_DOMAIN = 0x16, +}; + +enum scmi_status_code { + SCMI_SUCCESS = 0, + SCMI_NOT_SUPPORTED = -1, + SCMI_INVALID_PARAMETERS = -2, + SCMI_DENIED = -3, + SCMI_NOT_FOUND = -4, + SCMI_OUT_OF_RANGE = -5, + SCMI_BUSY = -6, + SCMI_COMMS_ERROR = -7, + SCMI_GENERIC_ERROR = -8, + SCMI_HARDWARE_ERROR = -9, + SCMI_PROTOCOL_ERROR = -10, +}; + +#endif /* _SCMI_PROTOCOLS_H */ diff --git a/test/dm/Makefile b/test/dm/Makefile index 864c8d0b4c..70ba1b6695 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -80,4 +80,5 @@ obj-$(CONFIG_DM_RNG) += rng.o obj-$(CONFIG_CLK_K210_SET_RATE) += k210_pll.o obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o obj-$(CONFIG_RESET_SYSCON) += syscon-reset.o +obj-$(CONFIG_SCMI_FIRMWARE) += scmi.o endif diff --git a/test/dm/scmi.c b/test/dm/scmi.c new file mode 100644 index 0000000000..d8c1e71f12 --- /dev/null +++ b/test/dm/scmi.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020, Linaro Limited + * + * Tests scmi_agent uclass and the SCMI drivers implemented in other + * uclass devices probe when a SCMI server exposes resources. + * + * Note in test.dts the protocol@10 node in agent 1. Protocol 0x10 is not + * implemented in U-Boot SCMI components but the implementation is exepected + * to not complain on unknown protocol IDs, as long as it is not used. Note + * in test.dts tests that SCMI drivers probing does not fail for such an + * unknown SCMI protocol ID. + */ + +#include +#include +#include +#include +#include +#include + +/* + * Test SCMI states when loading and releasing resources + * related to SCMI drivers. + */ +static int dm_test_scmi_sandbox_agent(struct unit_test_state *uts) +{ + struct sandbox_scmi_service *scmi_ctx = sandbox_scmi_service_ctx(); + + ut_assertnonnull(scmi_ctx); + ut_asserteq(2, scmi_ctx->agent_count); + ut_assertnull(scmi_ctx->agent[0]); + ut_assertnull(scmi_ctx->agent[1]); + + return 0; +} + +DM_TEST(dm_test_scmi_sandbox_agent, UT_TESTF_SCAN_FDT); -- cgit v1.2.3 From 240720e9052fa7459e4d8a46d508db1ae41ed238 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 9 Sep 2020 18:44:01 +0200 Subject: firmware: scmi: mailbox/smt agent device This change implements a mailbox transport using SMT format for SCMI exchanges. This implementation follows the Linux kernel and SCP-firmware [1] as references implementation for SCMI message processing using SMT format for communication channel meta-data. Use of mailboxes in SCMI FDT bindings are defined in the Linux kernel DT bindings since v4.17. Links: [1] https://github.com/ARM-software/SCP-firmware Signed-off-by: Etienne Carriere Cc: Simon Glass Cc: Peng Fan Cc: Sudeep Holla Reviewed-by: Simon Glass --- drivers/firmware/scmi/Kconfig | 6 +- drivers/firmware/scmi/Makefile | 2 + drivers/firmware/scmi/mailbox_agent.c | 102 +++++++++++++++++++++++++ drivers/firmware/scmi/smt.c | 139 ++++++++++++++++++++++++++++++++++ drivers/firmware/scmi/smt.h | 86 +++++++++++++++++++++ 5 files changed, 333 insertions(+), 2 deletions(-) create mode 100644 drivers/firmware/scmi/mailbox_agent.c create mode 100644 drivers/firmware/scmi/smt.c create mode 100644 drivers/firmware/scmi/smt.h (limited to 'drivers') diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig index 57e2ebbe42..c501bf4943 100644 --- a/drivers/firmware/scmi/Kconfig +++ b/drivers/firmware/scmi/Kconfig @@ -2,7 +2,7 @@ config SCMI_FIRMWARE bool "Enable SCMI support" select FIRMWARE select OF_TRANSLATE - depends on SANDBOX + depends on SANDBOX || DM_MAILBOX help System Control and Management Interface (SCMI) is a communication protocol that defines standard interfaces for power, performance @@ -14,4 +14,6 @@ config SCMI_FIRMWARE or a companion host in the CPU system. Communications between agent (client) and the SCMI server are - based on message exchange. + based on message exchange. Messages can be exchange over tranport + channels as a mailbox device with some piece of identified shared + memory. diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile index 336ea1f2a3..d22f53efe7 100644 --- a/drivers/firmware/scmi/Makefile +++ b/drivers/firmware/scmi/Makefile @@ -1,2 +1,4 @@ obj-y += scmi_agent-uclass.o +obj-y += smt.o +obj-$(CONFIG_DM_MAILBOX) += mailbox_agent.o obj-$(CONFIG_SANDBOX) += sandbox-scmi_agent.o diff --git a/drivers/firmware/scmi/mailbox_agent.c b/drivers/firmware/scmi/mailbox_agent.c new file mode 100644 index 0000000000..7d9fb3622e --- /dev/null +++ b/drivers/firmware/scmi/mailbox_agent.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Linaro Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "smt.h" + +#define TIMEOUT_US_10MS 10000 + +/** + * struct scmi_mbox_channel - Description of an SCMI mailbox transport + * @smt: Shared memory buffer + * @mbox: Mailbox channel description + * @timeout_us: Timeout in microseconds for the mailbox transfer + */ +struct scmi_mbox_channel { + struct scmi_smt smt; + struct mbox_chan mbox; + ulong timeout_us; +}; + +static int scmi_mbox_process_msg(struct udevice *dev, struct scmi_msg *msg) +{ + struct scmi_mbox_channel *chan = dev_get_priv(dev); + int ret; + + ret = scmi_write_msg_to_smt(dev, &chan->smt, msg); + if (ret) + return ret; + + /* Give shm addr to mbox in case it is meaningful */ + ret = mbox_send(&chan->mbox, chan->smt.buf); + if (ret) { + dev_err(dev, "Message send failed: %d\n", ret); + goto out; + } + + /* Receive the response */ + ret = mbox_recv(&chan->mbox, chan->smt.buf, chan->timeout_us); + if (ret) { + dev_err(dev, "Response failed: %d, abort\n", ret); + goto out; + } + + ret = scmi_read_resp_from_smt(dev, &chan->smt, msg); + +out: + scmi_clear_smt_channel(&chan->smt); + + return ret; +} + +int scmi_mbox_probe(struct udevice *dev) +{ + struct scmi_mbox_channel *chan = dev_get_priv(dev); + int ret; + + chan->timeout_us = TIMEOUT_US_10MS; + + ret = mbox_get_by_index(dev, 0, &chan->mbox); + if (ret) { + dev_err(dev, "Failed to find mailbox: %d\n", ret); + goto out; + } + + ret = scmi_dt_get_smt_buffer(dev, &chan->smt); + if (ret) + dev_err(dev, "Failed to get shm resources: %d\n", ret); + +out: + if (ret) + devm_kfree(dev, chan); + + return ret; +} + +static const struct udevice_id scmi_mbox_ids[] = { + { .compatible = "arm,scmi" }, + { } +}; + +static const struct scmi_agent_ops scmi_mbox_ops = { + .process_msg = scmi_mbox_process_msg, +}; + +U_BOOT_DRIVER(scmi_mbox) = { + .name = "scmi-over-mailbox", + .id = UCLASS_SCMI_AGENT, + .of_match = scmi_mbox_ids, + .priv_auto_alloc_size = sizeof(struct scmi_mbox_channel), + .probe = scmi_mbox_probe, + .ops = &scmi_mbox_ops, +}; diff --git a/drivers/firmware/scmi/smt.c b/drivers/firmware/scmi/smt.c new file mode 100644 index 0000000000..ce8fe49939 --- /dev/null +++ b/drivers/firmware/scmi/smt.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. + * Copyright (C) 2019-2020 Linaro Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "smt.h" + +/** + * Get shared memory configuration defined by the referred DT phandle + * Return with a errno compliant value. + */ +int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt) +{ + int ret; + struct ofnode_phandle_args args; + struct resource resource; + fdt32_t faddr; + phys_addr_t paddr; + + ret = dev_read_phandle_with_args(dev, "shmem", NULL, 0, 0, &args); + if (ret) + return ret; + + ret = ofnode_read_resource(args.node, 0, &resource); + if (ret) + return ret; + + faddr = cpu_to_fdt32(resource.start); + paddr = ofnode_translate_address(args.node, &faddr); + + smt->size = resource_size(&resource); + if (smt->size < sizeof(struct scmi_smt_header)) { + dev_err(dev, "Shared memory buffer too small\n"); + return -EINVAL; + } + + smt->buf = devm_ioremap(dev, paddr, smt->size); + if (!smt->buf) + return -ENOMEM; + +#ifdef CONFIG_ARM + if (dcache_status()) + mmu_set_region_dcache_behaviour((uintptr_t)smt->buf, + smt->size, DCACHE_OFF); +#endif + + return 0; +} + +/** + * Write SCMI message @msg into a SMT shared buffer @smt. + * Return 0 on success and with a negative errno in case of error. + */ +int scmi_write_msg_to_smt(struct udevice *dev, struct scmi_smt *smt, + struct scmi_msg *msg) +{ + struct scmi_smt_header *hdr = (void *)smt->buf; + + if ((!msg->in_msg && msg->in_msg_sz) || + (!msg->out_msg && msg->out_msg_sz)) + return -EINVAL; + + if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) { + dev_dbg(dev, "Channel busy\n"); + return -EBUSY; + } + + if (smt->size < (sizeof(*hdr) + msg->in_msg_sz) || + smt->size < (sizeof(*hdr) + msg->out_msg_sz)) { + dev_dbg(dev, "Buffer too small\n"); + return -ETOOSMALL; + } + + /* Load message in shared memory */ + hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE; + hdr->length = msg->in_msg_sz + sizeof(hdr->msg_header); + hdr->msg_header = SMT_HEADER_TOKEN(0) | + SMT_HEADER_MESSAGE_TYPE(0) | + SMT_HEADER_PROTOCOL_ID(msg->protocol_id) | + SMT_HEADER_MESSAGE_ID(msg->message_id); + + memcpy_toio(hdr->msg_payload, msg->in_msg, msg->in_msg_sz); + + return 0; +} + +/** + * Read SCMI message from a SMT shared buffer @smt and copy it into @msg. + * Return 0 on success and with a negative errno in case of error. + */ +int scmi_read_resp_from_smt(struct udevice *dev, struct scmi_smt *smt, + struct scmi_msg *msg) +{ + struct scmi_smt_header *hdr = (void *)smt->buf; + + if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) { + dev_err(dev, "Channel unexpectedly busy\n"); + return -EBUSY; + } + + if (hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR) { + dev_err(dev, "Channel error reported, reset channel\n"); + return -ECOMM; + } + + if (hdr->length > msg->out_msg_sz + sizeof(hdr->msg_header)) { + dev_err(dev, "Buffer to small\n"); + return -ETOOSMALL; + } + + /* Get the data */ + msg->out_msg_sz = hdr->length - sizeof(hdr->msg_header); + memcpy_fromio(msg->out_msg, hdr->msg_payload, msg->out_msg_sz); + + return 0; +} + +/** + * Clear SMT flags in shared buffer to allow further message exchange + */ +void scmi_clear_smt_channel(struct scmi_smt *smt) +{ + struct scmi_smt_header *hdr = (void *)smt->buf; + + hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR; +} diff --git a/drivers/firmware/scmi/smt.h b/drivers/firmware/scmi/smt.h new file mode 100644 index 0000000000..a8c0987bd3 --- /dev/null +++ b/drivers/firmware/scmi/smt.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. + * Copyright (C) 2019-2020 Linaro Limited. + */ +#ifndef SCMI_SMT_H +#define SCMI_SMT_H + +#include + +/** + * struct scmi_smt_header - Description of the shared memory message buffer + * + * SMT stands for Shared Memory based Transport. + * SMT uses 28 byte header prior message payload to handle the state of + * the communication channel realized by the shared memory area and + * to define SCMI protocol information the payload relates to. + */ +struct scmi_smt_header { + __le32 reserved; + __le32 channel_status; +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR BIT(1) +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE BIT(0) + __le32 reserved1[2]; + __le32 flags; +#define SCMI_SHMEM_FLAG_INTR_ENABLED BIT(0) + __le32 length; + __le32 msg_header; + u8 msg_payload[0]; +}; + +#define SMT_HEADER_TOKEN(token) (((token) << 18) & GENMASK(31, 18)) +#define SMT_HEADER_PROTOCOL_ID(proto) (((proto) << 10) & GENMASK(17, 10)) +#define SMT_HEADER_MESSAGE_TYPE(type) (((type) << 18) & GENMASK(9, 8)) +#define SMT_HEADER_MESSAGE_ID(id) ((id) & GENMASK(7, 0)) + +/** + * struct scmi_smt - Description of a SMT memory buffer + * @buf: Shared memory base address + * @size: Shared memory byte size + */ +struct scmi_smt { + u8 *buf; + size_t size; +}; + +static inline bool scmi_smt_channel_is_free(struct scmi_smt *smt) +{ + struct scmi_smt_header *hdr = (void *)smt->buf; + + return hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE; +} + +static inline bool scmi_smt_channel_reports_error(struct scmi_smt *smt) +{ + struct scmi_smt_header *hdr = (void *)smt->buf; + + return hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR; +} + +static inline void scmi_smt_get_channel(struct scmi_smt *smt) +{ + struct scmi_smt_header *hdr = (void *)smt->buf; + + hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE; +} + +static inline void scmi_smt_put_channel(struct scmi_smt *smt) +{ + struct scmi_smt_header *hdr = (void *)smt->buf; + + hdr->channel_status |= SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE; + hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR; +} + +int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt); + +int scmi_write_msg_to_smt(struct udevice *dev, struct scmi_smt *smt, + struct scmi_msg *msg); + +int scmi_read_resp_from_smt(struct udevice *dev, struct scmi_smt *smt, + struct scmi_msg *msg); + +void scmi_clear_smt_channel(struct scmi_smt *smt); + +#endif /* SCMI_SMT_H */ -- cgit v1.2.3 From 1e35913a2677b1d0511769425a53cd9ae113c238 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 9 Sep 2020 18:44:02 +0200 Subject: firmware: scmi: support Arm SMCCC transport This change implements a SMCCC transport for SCMI exchanges. This implementation follows the Linux kernel as references implementation for SCMI message processing, using the SMT format for communication channel meta-data. Use of SMCCC transport in SCMI FDT bindings are defined in the Linux kernel DT bindings since v5.8. SMCCC with SMT is implemented in OP-TEE from tag 3.9.0 [2]. Links: [2] https://github.com/OP-TEE/optee_os/commit/a58c4d706d23 Signed-off-by: Etienne Carriere Cc: Simon Glass Cc: Peng Fan Cc: Sudeep Holla Reviewed-by: Simon Glass --- drivers/firmware/scmi/Kconfig | 6 +-- drivers/firmware/scmi/Makefile | 1 + drivers/firmware/scmi/smccc_agent.c | 89 +++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 drivers/firmware/scmi/smccc_agent.c (limited to 'drivers') diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig index c501bf4943..c3a109beac 100644 --- a/drivers/firmware/scmi/Kconfig +++ b/drivers/firmware/scmi/Kconfig @@ -2,7 +2,7 @@ config SCMI_FIRMWARE bool "Enable SCMI support" select FIRMWARE select OF_TRANSLATE - depends on SANDBOX || DM_MAILBOX + depends on SANDBOX || DM_MAILBOX || ARM_SMCCC help System Control and Management Interface (SCMI) is a communication protocol that defines standard interfaces for power, performance @@ -15,5 +15,5 @@ config SCMI_FIRMWARE Communications between agent (client) and the SCMI server are based on message exchange. Messages can be exchange over tranport - channels as a mailbox device with some piece of identified shared - memory. + channels as a mailbox device or an Arm SMCCC service with some + piece of identified shared memory. diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile index d22f53efe7..2f782bbd55 100644 --- a/drivers/firmware/scmi/Makefile +++ b/drivers/firmware/scmi/Makefile @@ -1,4 +1,5 @@ obj-y += scmi_agent-uclass.o obj-y += smt.o +obj-$(CONFIG_ARM_SMCCC) += smccc_agent.o obj-$(CONFIG_DM_MAILBOX) += mailbox_agent.o obj-$(CONFIG_SANDBOX) += sandbox-scmi_agent.o diff --git a/drivers/firmware/scmi/smccc_agent.c b/drivers/firmware/scmi/smccc_agent.c new file mode 100644 index 0000000000..85dbf9195e --- /dev/null +++ b/drivers/firmware/scmi/smccc_agent.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Linaro Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "smt.h" + +#define SMCCC_RET_NOT_SUPPORTED ((unsigned long)-1) + +/** + * struct scmi_smccc_channel - Description of an SCMI SMCCC transport + * @func_id: SMCCC function ID used by the SCMI transport + * @smt: Shared memory buffer + */ +struct scmi_smccc_channel { + ulong func_id; + struct scmi_smt smt; +}; + +static int scmi_smccc_process_msg(struct udevice *dev, struct scmi_msg *msg) +{ + struct scmi_smccc_channel *chan = dev_get_priv(dev); + struct arm_smccc_res res; + int ret; + + ret = scmi_write_msg_to_smt(dev, &chan->smt, msg); + if (ret) + return ret; + + arm_smccc_smc(chan->func_id, 0, 0, 0, 0, 0, 0, 0, &res); + if (res.a0 == SMCCC_RET_NOT_SUPPORTED) + ret = -ENXIO; + else + ret = scmi_read_resp_from_smt(dev, &chan->smt, msg); + + scmi_clear_smt_channel(&chan->smt); + + return ret; +} + +static int scmi_smccc_probe(struct udevice *dev) +{ + struct scmi_smccc_channel *chan = dev_get_priv(dev); + u32 func_id; + int ret; + + if (dev_read_u32(dev, "arm,smc-id", &func_id)) { + dev_err(dev, "Missing property func-id\n"); + return -EINVAL; + } + + chan->func_id = func_id; + + ret = scmi_dt_get_smt_buffer(dev, &chan->smt); + if (ret) { + dev_err(dev, "Failed to get smt resources: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct udevice_id scmi_smccc_ids[] = { + { .compatible = "arm,scmi-smc" }, + { } +}; + +static const struct scmi_agent_ops scmi_smccc_ops = { + .process_msg = scmi_smccc_process_msg, +}; + +U_BOOT_DRIVER(scmi_smccc) = { + .name = "scmi-over-smccc", + .id = UCLASS_SCMI_AGENT, + .of_match = scmi_smccc_ids, + .priv_auto_alloc_size = sizeof(struct scmi_smccc_channel), + .probe = scmi_smccc_probe, + .ops = &scmi_smccc_ops, +}; -- cgit v1.2.3 From 60388844836f5639e6c9a4331335ff22298128da Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 9 Sep 2020 18:44:04 +0200 Subject: clk: add clock driver for SCMI agents This change introduces a clock driver for SCMI agent devices. When SCMI agent and SCMI clock drivers are enabled, SCMI agent binds a clock device for each SCMI clock protocol devices enabled in the FDT. SCMI clock driver is embedded upon CONFIG_CLK_SCMI=y. If enabled, CONFIG_SCMI_AGENT is also enabled. SCMI Clock protocol is defined in the SCMI specification [1]. Links: [1] https://developer.arm.com/architectures/system-architectures/software-standards/scmi Signed-off-by: Etienne Carriere Cc: Lukasz Majewski Cc: Simon Glass Cc: Peng Fan Cc: Sudeep Holla Reviewed-by: Simon Glass --- drivers/clk/Kconfig | 8 +++ drivers/clk/Makefile | 1 + drivers/clk/clk_scmi.c | 99 +++++++++++++++++++++++++++++++ drivers/firmware/scmi/scmi_agent-uclass.c | 14 ++++- include/scmi_protocols.h | 78 ++++++++++++++++++++++++ 5 files changed, 197 insertions(+), 3 deletions(-) create mode 100644 drivers/clk/clk_scmi.c (limited to 'drivers') diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 6003e140b5..4dfbad7986 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -159,6 +159,14 @@ config CLK_CDCE9XX Enable the clock synthesizer driver for CDCE913/925/937/949 series of chips. +config CLK_SCMI + bool "Enable SCMI clock driver" + depends on SCMI_FIRMWARE + help + Enable this option if you want to support clock devices exposed + by a SCMI agent based on SCMI clock protocol communication + with a SCMI server. + source "drivers/clk/analogbits/Kconfig" source "drivers/clk/at91/Kconfig" source "drivers/clk/exynos/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index cda4b4b605..d1e295ac7c 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o obj-$(CONFIG_CLK_OCTEON) += clk_octeon.o obj-$(CONFIG_CLK_OWL) += owl/ obj-$(CONFIG_CLK_RENESAS) += renesas/ +obj-$(CONFIG_CLK_SCMI) += clk_scmi.o obj-$(CONFIG_CLK_SIFIVE) += sifive/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c new file mode 100644 index 0000000000..93a4819501 --- /dev/null +++ b/drivers/clk/clk_scmi.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019-2020 Linaro Limited + */ +#include +#include +#include +#include +#include +#include + +static int scmi_clk_gate(struct clk *clk, int enable) +{ + struct scmi_clk_state_in in = { + .clock_id = clk->id, + .attributes = enable, + }; + struct scmi_clk_state_out out; + struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, + SCMI_CLOCK_CONFIG_SET, + in, out); + int ret; + + ret = devm_scmi_process_msg(clk->dev->parent, &msg); + if (ret) + return ret; + + return scmi_to_linux_errno(out.status); +} + +static int scmi_clk_enable(struct clk *clk) +{ + return scmi_clk_gate(clk, 1); +} + +static int scmi_clk_disable(struct clk *clk) +{ + return scmi_clk_gate(clk, 0); +} + +static ulong scmi_clk_get_rate(struct clk *clk) +{ + struct scmi_clk_rate_get_in in = { + .clock_id = clk->id, + }; + struct scmi_clk_rate_get_out out; + struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, + SCMI_CLOCK_RATE_GET, + in, out); + int ret; + + ret = devm_scmi_process_msg(clk->dev->parent, &msg); + if (ret < 0) + return ret; + + ret = scmi_to_linux_errno(out.status); + if (ret < 0) + return ret; + + return (ulong)(((u64)out.rate_msb << 32) | out.rate_lsb); +} + +static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) +{ + struct scmi_clk_rate_set_in in = { + .clock_id = clk->id, + .flags = SCMI_CLK_RATE_ROUND_CLOSEST, + .rate_lsb = (u32)rate, + .rate_msb = (u32)((u64)rate >> 32), + }; + struct scmi_clk_rate_set_out out; + struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, + SCMI_CLOCK_RATE_SET, + in, out); + int ret; + + ret = devm_scmi_process_msg(clk->dev->parent, &msg); + if (ret < 0) + return ret; + + ret = scmi_to_linux_errno(out.status); + if (ret < 0) + return ret; + + return scmi_clk_get_rate(clk); +} + +static const struct clk_ops scmi_clk_ops = { + .enable = scmi_clk_enable, + .disable = scmi_clk_disable, + .get_rate = scmi_clk_get_rate, + .set_rate = scmi_clk_set_rate, +}; + +U_BOOT_DRIVER(scmi_clock) = { + .name = "scmi_clk", + .id = UCLASS_CLK, + .ops = &scmi_clk_ops, +}; diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 67a6f907c9..1f36f23b6d 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -58,9 +58,9 @@ static int scmi_bind_protocols(struct udevice *dev) { int ret = 0; ofnode node; - struct driver *drv; dev_for_each_subnode(node, dev) { + struct driver *drv = NULL; u32 protocol_id; if (!ofnode_is_available(node)) @@ -70,9 +70,17 @@ static int scmi_bind_protocols(struct udevice *dev) continue; switch (protocol_id) { + case SCMI_PROTOCOL_ID_CLOCK: + if (IS_ENABLED(CONFIG_CLK_SCMI)) + drv = DM_GET_DRIVER(scmi_clock); + break; default: - dev_info(dev, "Ignore unsupported SCMI protocol %#x\n", - protocol_id); + break; + } + + if (!drv) { + dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n", + protocol_id); continue; } diff --git a/include/scmi_protocols.h b/include/scmi_protocols.h index 86a2d109c8..4778bcfc47 100644 --- a/include/scmi_protocols.h +++ b/include/scmi_protocols.h @@ -7,6 +7,7 @@ #define _SCMI_PROTOCOLS_H #include +#include /* * Subset the SCMI protocols definition @@ -38,4 +39,81 @@ enum scmi_status_code { SCMI_PROTOCOL_ERROR = -10, }; +/* + * SCMI Clock Protocol + */ + +enum scmi_clock_message_id { + SCMI_CLOCK_RATE_SET = 0x5, + SCMI_CLOCK_RATE_GET = 0x6, + SCMI_CLOCK_CONFIG_SET = 0x7, +}; + +#define SCMI_CLK_RATE_ASYNC_NOTIFY BIT(0) +#define SCMI_CLK_RATE_ASYNC_NORESP (BIT(0) | BIT(1)) +#define SCMI_CLK_RATE_ROUND_DOWN 0 +#define SCMI_CLK_RATE_ROUND_UP BIT(2) +#define SCMI_CLK_RATE_ROUND_CLOSEST BIT(3) + +/** + * struct scmi_clk_state_in - Message payload for CLOCK_CONFIG_SET command + * @clock_id: SCMI clock ID + * @attributes: Attributes of the targets clock state + */ +struct scmi_clk_state_in { + u32 clock_id; + u32 attributes; +}; + +/** + * struct scmi_clk_state_out - Response payload for CLOCK_CONFIG_SET command + * @status: SCMI command status + */ +struct scmi_clk_state_out { + s32 status; +}; + +/** + * struct scmi_clk_state_in - Message payload for CLOCK_RATE_GET command + * @clock_id: SCMI clock ID + * @attributes: Attributes of the targets clock state + */ +struct scmi_clk_rate_get_in { + u32 clock_id; +}; + +/** + * struct scmi_clk_rate_get_out - Response payload for CLOCK_RATE_GET command + * @status: SCMI command status + * @rate_lsb: 32bit LSB of the clock rate in Hertz + * @rate_msb: 32bit MSB of the clock rate in Hertz + */ +struct scmi_clk_rate_get_out { + s32 status; + u32 rate_lsb; + u32 rate_msb; +}; + +/** + * struct scmi_clk_state_in - Message payload for CLOCK_RATE_SET command + * @clock_id: SCMI clock ID + * @flags: Flags for the clock rate set request + * @rate_lsb: 32bit LSB of the clock rate in Hertz + * @rate_msb: 32bit MSB of the clock rate in Hertz + */ +struct scmi_clk_rate_set_in { + u32 clock_id; + u32 flags; + u32 rate_lsb; + u32 rate_msb; +}; + +/** + * struct scmi_clk_rate_set_out - Response payload for CLOCK_RATE_SET command + * @status: SCMI command status + */ +struct scmi_clk_rate_set_out { + s32 status; +}; + #endif /* _SCMI_PROTOCOLS_H */ -- cgit v1.2.3 From 87d4f277d4101c995e198ed3313da48690df5bb7 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 9 Sep 2020 18:44:05 +0200 Subject: firmware: scmi: sandbox test for SCMI clocks Add tests for SCMI clocks. A test device driver sandbox-scmi_devices.c is used to get clock resources, allowing further clock manipulation. Change sandbox-smci_agent to emulate 3 clocks exposed through 2 agents. Add DM test scmi_clocks to test these 3 clocks. Update DM test sandbox_scmi_agent with load/remove test sequences factorized by {load|remove}_sandbox_scmi_test_devices() helper functions. Signed-off-by: Etienne Carriere Cc: Simon Glass Cc: Peng Fan Cc: Sudeep Holla Reviewed-by: Simon Glass --- arch/sandbox/dts/test.dts | 15 +++ arch/sandbox/include/asm/scmi_test.h | 39 +++++++ configs/sandbox_defconfig | 1 + drivers/firmware/scmi/Makefile | 2 +- drivers/firmware/scmi/sandbox-scmi_agent.c | 169 ++++++++++++++++++++++++++- drivers/firmware/scmi/sandbox-scmi_devices.c | 75 ++++++++++++ test/dm/scmi.c | 141 +++++++++++++++++++++- 7 files changed, 431 insertions(+), 11 deletions(-) create mode 100644 drivers/firmware/scmi/sandbox-scmi_devices.c (limited to 'drivers') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 4769ec0866..5ed364ff03 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -371,6 +371,11 @@ compatible = "sandbox,scmi-agent"; #address-cells = <1>; #size-cells = <0>; + + clk_scmi0: protocol@14 { + reg = <0x14>; + #clock-cells = <1>; + }; }; sandbox-scmi-agent@1 { @@ -378,6 +383,11 @@ #address-cells = <1>; #size-cells = <0>; + clk_scmi1: protocol@14 { + reg = <0x14>; + #clock-cells = <1>; + }; + protocol@10 { reg = <0x10>; }; @@ -1069,6 +1079,11 @@ compatible = "sandbox,virtio2"; }; + sandbox_scmi { + compatible = "sandbox,scmi-devices"; + clocks = <&clk_scmi0 7>, <&clk_scmi0 3>, <&clk_scmi1 1>; + }; + pinctrl { compatible = "sandbox,pinctrl"; diff --git a/arch/sandbox/include/asm/scmi_test.h b/arch/sandbox/include/asm/scmi_test.h index a811fe19c3..63093fdb4d 100644 --- a/arch/sandbox/include/asm/scmi_test.h +++ b/arch/sandbox/include/asm/scmi_test.h @@ -10,12 +10,28 @@ struct udevice; struct sandbox_scmi_agent; struct sandbox_scmi_service; +/** + * struct sandbox_scmi_clk - Simulated clock exposed by SCMI + * @id: Identifier of the clock used in the SCMI protocol + * @enabled: Clock state: true if enabled, false if disabled + * @rate: Clock rate in Hertz + */ +struct sandbox_scmi_clk { + uint id; + bool enabled; + ulong rate; +}; + /** * struct sandbox_scmi_agent - Simulated SCMI service seen by SCMI agent * @idx: Identifier for the SCMI agent, its index + * @clk: Simulated clocks + * @clk_count: Simulated clocks array size */ struct sandbox_scmi_agent { uint idx; + struct sandbox_scmi_clk *clk; + size_t clk_count; }; /** @@ -28,16 +44,39 @@ struct sandbox_scmi_service { size_t agent_count; }; +/** + * struct sandbox_scmi_devices - Reference to devices probed through SCMI + * @clk: Array the clock devices + * @clk_count: Number of clock devices probed + */ +struct sandbox_scmi_devices { + struct clk *clk; + size_t clk_count; +}; + #ifdef CONFIG_SCMI_FIRMWARE /** * sandbox_scmi_service_context - Get the simulated SCMI services context * @return: Reference to backend simulated resources state */ struct sandbox_scmi_service *sandbox_scmi_service_ctx(void); + +/** + * sandbox_scmi_devices_get_ref - Get references to devices accessed through SCMI + * @dev: Reference to the test device used get test resources + * @return: Reference to the devices probed by the SCMI test + */ +struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev); #else static inline struct sandbox_scmi_service *sandbox_scmi_service_ctx(void) { return NULL; } + +static inline +struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev) +{ + return NULL; +} #endif /* CONFIG_SCMI_FIRMWARE */ #endif /* __SANDBOX_SCMI_TEST_H */ diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 2c130c01f0..7d71c805dc 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -122,6 +122,7 @@ CONFIG_BUTTON=y CONFIG_BUTTON_GPIO=y CONFIG_CLK=y CONFIG_CLK_COMPOSITE_CCF=y +CONFIG_CLK_SCMI=y CONFIG_SANDBOX_CLK_CCF=y CONFIG_CPU=y CONFIG_DM_DEMO=y diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile index 2f782bbd55..e1e0224066 100644 --- a/drivers/firmware/scmi/Makefile +++ b/drivers/firmware/scmi/Makefile @@ -2,4 +2,4 @@ obj-y += scmi_agent-uclass.o obj-y += smt.o obj-$(CONFIG_ARM_SMCCC) += smccc_agent.o obj-$(CONFIG_DM_MAILBOX) += mailbox_agent.o -obj-$(CONFIG_SANDBOX) += sandbox-scmi_agent.o +obj-$(CONFIG_SANDBOX) += sandbox-scmi_agent.o sandbox-scmi_devices.o diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c index 3179438aab..ff590988a6 100644 --- a/drivers/firmware/scmi/sandbox-scmi_agent.c +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -16,18 +16,34 @@ /* * The sandbox SCMI agent driver simulates to some extend a SCMI message * processing. It simulates few of the SCMI services for some of the - * SCMI protocols embedded in U-Boot. Currently none. + * SCMI protocols embedded in U-Boot. Currently: + * - SCMI clock protocol: emulate 2 agents each exposing few clocks * - * This driver simulates 2 SCMI agents for test purpose. + * Agent #0 simulates 2 clocks. + * See IDs in scmi0_clk[] and "sandbox-scmi-agent@0" in test.dts. + * + * Agent #1 simulates 1 clock. + * See IDs in scmi1_clk[] and "sandbox-scmi-agent@1" in test.dts. + * + * All clocks are default disabled. * * This Driver exports sandbox_scmi_service_ct() for the test sequence to * get the state of the simulated services (clock state, rate, ...) and * check back-end device state reflects the request send through the - * various uclass devices, currently nothing. + * various uclass devices, currently only clock controllers. */ #define SANDBOX_SCMI_AGENT_COUNT 2 +static struct sandbox_scmi_clk scmi0_clk[] = { + { .id = 7, .rate = 1000 }, + { .id = 3, .rate = 333 }, +}; + +static struct sandbox_scmi_clk scmi1_clk[] = { + { .id = 1, .rate = 44 }, +}; + /* The list saves to simulted end devices references for test purpose */ struct sandbox_scmi_agent *sandbox_scmi_agent_list[SANDBOX_SCMI_AGENT_COUNT]; @@ -46,17 +62,158 @@ static void debug_print_agent_state(struct udevice *dev, char *str) struct sandbox_scmi_agent *agent = dev_get_priv(dev); dev_dbg(dev, "Dump sandbox_scmi_agent %u: %s\n", agent->idx, str); + dev_dbg(dev, " scmi%u_clk (%zu): %d/%ld, %d/%ld, %d/%ld, ...\n", + agent->idx, + agent->clk_count, + agent->clk_count ? agent->clk[0].enabled : -1, + agent->clk_count ? agent->clk[0].rate : -1, + agent->clk_count > 1 ? agent->clk[1].enabled : -1, + agent->clk_count > 1 ? agent->clk[1].rate : -1, + agent->clk_count > 2 ? agent->clk[2].enabled : -1, + agent->clk_count > 2 ? agent->clk[2].rate : -1); }; +static struct sandbox_scmi_clk *get_scmi_clk_state(uint agent_id, uint clock_id) +{ + struct sandbox_scmi_clk *target = NULL; + size_t target_count = 0; + size_t n; + + switch (agent_id) { + case 0: + target = scmi0_clk; + target_count = ARRAY_SIZE(scmi0_clk); + break; + case 1: + target = scmi1_clk; + target_count = ARRAY_SIZE(scmi1_clk); + break; + default: + return NULL; + } + + for (n = 0; n < target_count; n++) + if (target[n].id == clock_id) + return target + n; + + return NULL; +} + +/* + * Sandbox SCMI agent ops + */ + +static int sandbox_scmi_clock_rate_set(struct udevice *dev, + struct scmi_msg *msg) +{ + struct sandbox_scmi_agent *agent = dev_get_priv(dev); + struct scmi_clk_rate_set_in *in = NULL; + struct scmi_clk_rate_set_out *out = NULL; + struct sandbox_scmi_clk *clk_state = NULL; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + in = (struct scmi_clk_rate_set_in *)msg->in_msg; + out = (struct scmi_clk_rate_set_out *)msg->out_msg; + + clk_state = get_scmi_clk_state(agent->idx, in->clock_id); + if (!clk_state) { + dev_err(dev, "Unexpected clock ID %u\n", in->clock_id); + + out->status = SCMI_NOT_FOUND; + } else { + u64 rate = ((u64)in->rate_msb << 32) + in->rate_lsb; + + clk_state->rate = (ulong)rate; + + out->status = SCMI_SUCCESS; + } + + return 0; +} + +static int sandbox_scmi_clock_rate_get(struct udevice *dev, + struct scmi_msg *msg) +{ + struct sandbox_scmi_agent *agent = dev_get_priv(dev); + struct scmi_clk_rate_get_in *in = NULL; + struct scmi_clk_rate_get_out *out = NULL; + struct sandbox_scmi_clk *clk_state = NULL; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + in = (struct scmi_clk_rate_get_in *)msg->in_msg; + out = (struct scmi_clk_rate_get_out *)msg->out_msg; + + clk_state = get_scmi_clk_state(agent->idx, in->clock_id); + if (!clk_state) { + dev_err(dev, "Unexpected clock ID %u\n", in->clock_id); + + out->status = SCMI_NOT_FOUND; + } else { + out->rate_msb = (u32)((u64)clk_state->rate >> 32); + out->rate_lsb = (u32)clk_state->rate; + + out->status = SCMI_SUCCESS; + } + + return 0; +} + +static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg) +{ + struct sandbox_scmi_agent *agent = dev_get_priv(dev); + struct scmi_clk_state_in *in = NULL; + struct scmi_clk_state_out *out = NULL; + struct sandbox_scmi_clk *clk_state = NULL; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + in = (struct scmi_clk_state_in *)msg->in_msg; + out = (struct scmi_clk_state_out *)msg->out_msg; + + clk_state = get_scmi_clk_state(agent->idx, in->clock_id); + if (!clk_state) { + dev_err(dev, "Unexpected clock ID %u\n", in->clock_id); + + out->status = SCMI_NOT_FOUND; + } else if (in->attributes > 1) { + out->status = SCMI_PROTOCOL_ERROR; + } else { + clk_state->enabled = in->attributes; + + out->status = SCMI_SUCCESS; + } + + return 0; +} + static int sandbox_scmi_test_process_msg(struct udevice *dev, struct scmi_msg *msg) { switch (msg->protocol_id) { + case SCMI_PROTOCOL_ID_CLOCK: + switch (msg->message_id) { + case SCMI_CLOCK_RATE_SET: + return sandbox_scmi_clock_rate_set(dev, msg); + case SCMI_CLOCK_RATE_GET: + return sandbox_scmi_clock_rate_get(dev, msg); + case SCMI_CLOCK_CONFIG_SET: + return sandbox_scmi_clock_gate(dev, msg); + default: + break; + } + break; case SCMI_PROTOCOL_ID_BASE: case SCMI_PROTOCOL_ID_POWER_DOMAIN: case SCMI_PROTOCOL_ID_SYSTEM: case SCMI_PROTOCOL_ID_PERF: - case SCMI_PROTOCOL_ID_CLOCK: case SCMI_PROTOCOL_ID_SENSOR: case SCMI_PROTOCOL_ID_RESET_DOMAIN: *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED; @@ -101,11 +258,15 @@ static int sandbox_scmi_test_probe(struct udevice *dev) case '0': *agent = (struct sandbox_scmi_agent){ .idx = 0, + .clk = scmi0_clk, + .clk_count = ARRAY_SIZE(scmi0_clk), }; break; case '1': *agent = (struct sandbox_scmi_agent){ .idx = 1, + .clk = scmi1_clk, + .clk_count = ARRAY_SIZE(scmi1_clk), }; break; default: diff --git a/drivers/firmware/scmi/sandbox-scmi_devices.c b/drivers/firmware/scmi/sandbox-scmi_devices.c new file mode 100644 index 0000000000..b3e411c5ac --- /dev/null +++ b/drivers/firmware/scmi/sandbox-scmi_devices.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Simulate to some extent a SCMI exchange. + * This drivers gets SCMI resources and offers API function to the + * SCMI test sequence manipulate the resources, currently clocks. + */ + +#define SCMI_TEST_DEVICES_CLK_COUNT 3 + +/* + * struct sandbox_scmi_device_priv - Storage for device handles used by test + * @clk: Array of clock instances used by tests + * @devices: Resources exposed by sandbox_scmi_devices_ctx() + */ +struct sandbox_scmi_device_priv { + struct clk clk[SCMI_TEST_DEVICES_CLK_COUNT]; + struct sandbox_scmi_devices devices; +}; + +struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev) +{ + struct sandbox_scmi_device_priv *priv = dev_get_priv(dev); + + if (priv) + return &priv->devices; + + return NULL; +} + +static int sandbox_scmi_devices_probe(struct udevice *dev) +{ + struct sandbox_scmi_device_priv *priv = dev_get_priv(dev); + int ret; + size_t n; + + priv->devices = (struct sandbox_scmi_devices){ + .clk = priv->clk, + .clk_count = SCMI_TEST_DEVICES_CLK_COUNT, + }; + + for (n = 0; n < SCMI_TEST_DEVICES_CLK_COUNT; n++) { + ret = clk_get_by_index(dev, n, priv->devices.clk + n); + if (ret) { + dev_err(dev, "%s: Failed on clk %zu\n", __func__, n); + return ret; + } + } + + return 0; +} + +static const struct udevice_id sandbox_scmi_devices_ids[] = { + { .compatible = "sandbox,scmi-devices" }, + { } +}; + +U_BOOT_DRIVER(sandbox_scmi_devices) = { + .name = "sandbox-scmi_devices", + .id = UCLASS_MISC, + .of_match = sandbox_scmi_devices_ids, + .priv_auto_alloc_size = sizeof(struct sandbox_scmi_device_priv), + .probe = sandbox_scmi_devices_probe, +}; diff --git a/test/dm/scmi.c b/test/dm/scmi.c index d8c1e71f12..aa46f31a47 100644 --- a/test/dm/scmi.c +++ b/test/dm/scmi.c @@ -13,26 +13,155 @@ */ #include +#include #include #include #include #include +#include #include +static int ut_assert_scmi_state_preprobe(struct unit_test_state *uts) +{ + struct sandbox_scmi_service *scmi_ctx = sandbox_scmi_service_ctx(); + + ut_assertnonnull(scmi_ctx); + if (scmi_ctx->agent_count) + ut_asserteq(2, scmi_ctx->agent_count); + + return 0; +} + +static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts, + struct udevice *dev) +{ + struct sandbox_scmi_devices *scmi_devices; + struct sandbox_scmi_service *scmi_ctx; + + /* Device references to check context against test sequence */ + scmi_devices = sandbox_scmi_devices_ctx(dev); + + ut_assertnonnull(scmi_devices); + if (IS_ENABLED(CONFIG_CLK_SCMI)) + ut_asserteq(3, scmi_devices->clk_count); + + /* State of the simulated SCMI server exposed */ + scmi_ctx = sandbox_scmi_service_ctx(); + + ut_asserteq(2, scmi_ctx->agent_count); + + ut_assertnonnull(scmi_ctx->agent[0]); + ut_asserteq(2, scmi_ctx->agent[0]->clk_count); + ut_assertnonnull(scmi_ctx->agent[0]->clk); + + ut_assertnonnull(scmi_ctx->agent[1]); + ut_assertnonnull(scmi_ctx->agent[1]->clk); + ut_asserteq(1, scmi_ctx->agent[1]->clk_count); + + return 0; +} + +static int load_sandbox_scmi_test_devices(struct unit_test_state *uts, + struct udevice **dev) +{ + int ret; + + ret = ut_assert_scmi_state_preprobe(uts); + if (ret) + return ret; + + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "sandbox_scmi", + dev)); + ut_assertnonnull(*dev); + + return ut_assert_scmi_state_postprobe(uts, *dev); +} + +static int release_sandbox_scmi_test_devices(struct unit_test_state *uts, + struct udevice *dev) +{ + ut_assertok(device_remove(dev, DM_REMOVE_NORMAL)); + + /* Not sure test devices are fully removed, agent may not be visible */ + return 0; +} + /* * Test SCMI states when loading and releasing resources * related to SCMI drivers. */ static int dm_test_scmi_sandbox_agent(struct unit_test_state *uts) { - struct sandbox_scmi_service *scmi_ctx = sandbox_scmi_service_ctx(); + struct udevice *dev = NULL; + int ret; - ut_assertnonnull(scmi_ctx); - ut_asserteq(2, scmi_ctx->agent_count); - ut_assertnull(scmi_ctx->agent[0]); - ut_assertnull(scmi_ctx->agent[1]); + ret = load_sandbox_scmi_test_devices(uts, &dev); + if (!ret) + ret = release_sandbox_scmi_test_devices(uts, dev); - return 0; + return ret; } DM_TEST(dm_test_scmi_sandbox_agent, UT_TESTF_SCAN_FDT); + +static int dm_test_scmi_clocks(struct unit_test_state *uts) +{ + struct sandbox_scmi_devices *scmi_devices; + struct sandbox_scmi_service *scmi_ctx; + struct udevice *dev = NULL; + int ret_dev; + int ret; + + if (!IS_ENABLED(CONFIG_CLK_SCMI)) + return 0; + + ret = load_sandbox_scmi_test_devices(uts, &dev); + if (ret) + return ret; + + scmi_devices = sandbox_scmi_devices_ctx(dev); + scmi_ctx = sandbox_scmi_service_ctx(); + + /* Test SCMI clocks rate manipulation */ + ut_asserteq(1000, clk_get_rate(&scmi_devices->clk[0])); + ut_asserteq(333, clk_get_rate(&scmi_devices->clk[1])); + ut_asserteq(44, clk_get_rate(&scmi_devices->clk[2])); + + ret_dev = clk_set_rate(&scmi_devices->clk[1], 1088); + ut_assert(!ret_dev || ret_dev == 1088); + + ut_asserteq(1000, scmi_ctx->agent[0]->clk[0].rate); + ut_asserteq(1088, scmi_ctx->agent[0]->clk[1].rate); + ut_asserteq(44, scmi_ctx->agent[1]->clk[0].rate); + + ut_asserteq(1000, clk_get_rate(&scmi_devices->clk[0])); + ut_asserteq(1088, clk_get_rate(&scmi_devices->clk[1])); + ut_asserteq(44, clk_get_rate(&scmi_devices->clk[2])); + + /* restore original rate for further tests */ + ret_dev = clk_set_rate(&scmi_devices->clk[1], 333); + ut_assert(!ret_dev || ret_dev == 333); + + /* Test SCMI clocks gating manipulation */ + ut_assert(!scmi_ctx->agent[0]->clk[0].enabled); + ut_assert(!scmi_ctx->agent[0]->clk[1].enabled); + ut_assert(!scmi_ctx->agent[1]->clk[0].enabled); + + ut_asserteq(0, clk_enable(&scmi_devices->clk[1])); + ut_asserteq(0, clk_enable(&scmi_devices->clk[2])); + + ut_assert(!scmi_ctx->agent[0]->clk[0].enabled); + ut_assert(scmi_ctx->agent[0]->clk[1].enabled); + ut_assert(scmi_ctx->agent[1]->clk[0].enabled); + + ut_assertok(clk_disable(&scmi_devices->clk[1])); + ut_assertok(clk_disable(&scmi_devices->clk[2])); + + ut_assert(!scmi_ctx->agent[0]->clk[0].enabled); + ut_assert(!scmi_ctx->agent[0]->clk[1].enabled); + ut_assert(!scmi_ctx->agent[1]->clk[0].enabled); + + return release_sandbox_scmi_test_devices(uts, dev); +} + +DM_TEST(dm_test_scmi_clocks, UT_TESTF_SCAN_FDT); -- cgit v1.2.3 From 34d76fefb2667d0ca138ff4fcf8bc8443032449f Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 9 Sep 2020 18:44:06 +0200 Subject: reset: add reset controller driver for SCMI agents This change introduces a reset controller driver for SCMI agent devices. When SCMI agent and SCMI reset domain drivers are enabled, SCMI agent binds a reset controller device for each SCMI reset domain protocol devices enabled in the FDT. SCMI reset driver is embedded upon CONFIG_RESET_SCMI=y. If enabled, CONFIG_SCMI_AGENT is also enabled. SCMI Reset Domain protocol is defined in the SCMI specification [1]. Links: [1] https://developer.arm.com/architectures/system-architectures/software-standards/scmi Signed-off-by: Etienne Carriere Cc: Simon Glass Cc: Peng Fan Cc: Sudeep Holla Reviewed-by: Simon Glass --- drivers/firmware/scmi/scmi_agent-uclass.c | 4 ++ drivers/reset/Kconfig | 8 +++ drivers/reset/Makefile | 1 + drivers/reset/reset-scmi.c | 81 +++++++++++++++++++++++++++++++ include/scmi_protocols.h | 60 +++++++++++++++++++++++ 5 files changed, 154 insertions(+) create mode 100644 drivers/reset/reset-scmi.c (limited to 'drivers') diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 1f36f23b6d..77160b1999 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -74,6 +74,10 @@ static int scmi_bind_protocols(struct udevice *dev) if (IS_ENABLED(CONFIG_CLK_SCMI)) drv = DM_GET_DRIVER(scmi_clock); break; + case SCMI_PROTOCOL_ID_RESET_DOMAIN: + if (IS_ENABLED(CONFIG_RESET_SCMI)) + drv = DM_GET_DRIVER(scmi_reset_domain); + break; default: break; } diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 3fdfe4a6cb..b60e11f98b 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -181,4 +181,12 @@ config RESET_RASPBERRYPI relevant. This driver provides a reset controller capable of interfacing with RPi4's co-processor and model these firmware initialization routines as reset lines. + +config RESET_SCMI + bool "Enable SCMI reset domain driver" + select SCMI_FIRMWARE + help + Enable this option if you want to support reset controller + devices exposed by a SCMI agent based on SCMI reset domain + protocol communication with a SCMI server. endmenu diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 5176da5885..10a7973f82 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -27,3 +27,4 @@ obj-$(CONFIG_RESET_IPQ419) += reset-ipq4019.o obj-$(CONFIG_RESET_SIFIVE) += reset-sifive.o obj-$(CONFIG_RESET_SYSCON) += reset-syscon.o obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o +obj-$(CONFIG_RESET_SCMI) += reset-scmi.o diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c new file mode 100644 index 0000000000..1bff8075ee --- /dev/null +++ b/drivers/reset/reset-scmi.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019-2020 Linaro Limited + */ +#include +#include +#include +#include +#include +#include +#include + +static int scmi_reset_set_level(struct reset_ctl *rst, bool assert_not_deassert) +{ + struct scmi_rd_reset_in in = { + .domain_id = rst->id, + .flags = assert_not_deassert ? SCMI_RD_RESET_FLAG_ASSERT : 0, + .reset_state = 0, + }; + struct scmi_rd_reset_out out; + struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_RESET_DOMAIN, + SCMI_RESET_DOMAIN_RESET, + in, out); + int ret; + + ret = devm_scmi_process_msg(rst->dev->parent, &msg); + if (ret) + return ret; + + return scmi_to_linux_errno(out.status); +} + +static int scmi_reset_assert(struct reset_ctl *rst) +{ + return scmi_reset_set_level(rst, true); +} + +static int scmi_reset_deassert(struct reset_ctl *rst) +{ + return scmi_reset_set_level(rst, false); +} + +static int scmi_reset_request(struct reset_ctl *rst) +{ + struct scmi_rd_attr_in in = { + .domain_id = rst->id, + }; + struct scmi_rd_attr_out out; + struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_RESET_DOMAIN, + SCMI_RESET_DOMAIN_ATTRIBUTES, + in, out); + int ret; + + /* + * We don't really care about the attribute, just check + * the reset domain exists. + */ + ret = devm_scmi_process_msg(rst->dev->parent, &msg); + if (ret) + return ret; + + return scmi_to_linux_errno(out.status); +} + +static int scmi_reset_rfree(struct reset_ctl *rst) +{ + return 0; +} + +static const struct reset_ops scmi_reset_domain_ops = { + .request = scmi_reset_request, + .rfree = scmi_reset_rfree, + .rst_assert = scmi_reset_assert, + .rst_deassert = scmi_reset_deassert, +}; + +U_BOOT_DRIVER(scmi_reset_domain) = { + .name = "scmi_reset_domain", + .id = UCLASS_RESET, + .ops = &scmi_reset_domain_ops, +}; diff --git a/include/scmi_protocols.h b/include/scmi_protocols.h index 4778bcfc47..ccab97c96c 100644 --- a/include/scmi_protocols.h +++ b/include/scmi_protocols.h @@ -116,4 +116,64 @@ struct scmi_clk_rate_set_out { s32 status; }; +/* + * SCMI Reset Domain Protocol + */ + +enum scmi_reset_domain_message_id { + SCMI_RESET_DOMAIN_ATTRIBUTES = 0x3, + SCMI_RESET_DOMAIN_RESET = 0x4, +}; + +#define SCMI_RD_NAME_LEN 16 + +#define SCMI_RD_ATTRIBUTES_FLAG_ASYNC BIT(31) +#define SCMI_RD_ATTRIBUTES_FLAG_NOTIF BIT(30) + +#define SCMI_RD_RESET_FLAG_ASYNC BIT(2) +#define SCMI_RD_RESET_FLAG_ASSERT BIT(1) +#define SCMI_RD_RESET_FLAG_CYCLE BIT(0) + +/** + * struct scmi_rd_attr_in - Payload for RESET_DOMAIN_ATTRIBUTES message + * @domain_id: SCMI reset domain ID + */ +struct scmi_rd_attr_in { + u32 domain_id; +}; + +/** + * struct scmi_rd_attr_out - Payload for RESET_DOMAIN_ATTRIBUTES response + * @status: SCMI command status + * @attributes: Retrieved attributes of the reset domain + * @latency: Reset cycle max lantency + * @name: Reset domain name + */ +struct scmi_rd_attr_out { + s32 status; + u32 attributes; + u32 latency; + char name[SCMI_RD_NAME_LEN]; +}; + +/** + * struct scmi_rd_reset_in - Message payload for RESET command + * @domain_id: SCMI reset domain ID + * @flags: Flags for the reset request + * @reset_state: Reset target state + */ +struct scmi_rd_reset_in { + u32 domain_id; + u32 flags; + u32 reset_state; +}; + +/** + * struct scmi_rd_reset_out - Response payload for RESET command + * @status: SCMI command status + */ +struct scmi_rd_reset_out { + s32 status; +}; + #endif /* _SCMI_PROTOCOLS_H */ -- cgit v1.2.3 From c0dd177a9986b97dab42f07b3db0ed1d2fe6e540 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 9 Sep 2020 18:44:07 +0200 Subject: firmware: smci: sandbox test for SCMI reset controllers Add tests for SCMI reset controllers. A test device driver sandbox-scmi_devices.c is used to get reset resources, allowing further resets manipulation. Change sandbox-smci_agent to emulate 1 reset controller exposed through an agent. Add DM test scmi_resets to test this reset controller. Signed-off-by: Etienne Carriere Cc: Simon Glass Cc: Peng Fan Cc: Sudeep Holla Reviewed-by: Simon Glass --- arch/sandbox/dts/test.dts | 6 ++ arch/sandbox/include/asm/scmi_test.h | 17 ++++ configs/sandbox_defconfig | 1 + drivers/firmware/scmi/sandbox-scmi_agent.c | 117 +++++++++++++++++++++++++-- drivers/firmware/scmi/sandbox-scmi_devices.c | 40 ++++++++- test/dm/scmi.c | 36 +++++++++ 6 files changed, 211 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 5ed364ff03..e6da47d592 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -376,6 +376,11 @@ reg = <0x14>; #clock-cells = <1>; }; + + reset_scmi0: protocol@16 { + reg = <0x16>; + #reset-cells = <1>; + }; }; sandbox-scmi-agent@1 { @@ -1082,6 +1087,7 @@ sandbox_scmi { compatible = "sandbox,scmi-devices"; clocks = <&clk_scmi0 7>, <&clk_scmi0 3>, <&clk_scmi1 1>; + resets = <&reset_scmi0 3>; }; pinctrl { diff --git a/arch/sandbox/include/asm/scmi_test.h b/arch/sandbox/include/asm/scmi_test.h index 63093fdb4d..3e8b0068fd 100644 --- a/arch/sandbox/include/asm/scmi_test.h +++ b/arch/sandbox/include/asm/scmi_test.h @@ -22,16 +22,29 @@ struct sandbox_scmi_clk { ulong rate; }; +/** + * struct sandbox_scmi_reset - Simulated reset controller exposed by SCMI + * @asserted: Reset control state: true if asserted, false if desasserted + */ +struct sandbox_scmi_reset { + uint id; + bool asserted; +}; + /** * struct sandbox_scmi_agent - Simulated SCMI service seen by SCMI agent * @idx: Identifier for the SCMI agent, its index * @clk: Simulated clocks * @clk_count: Simulated clocks array size + * @clk: Simulated reset domains + * @clk_count: Simulated reset domains array size */ struct sandbox_scmi_agent { uint idx; struct sandbox_scmi_clk *clk; size_t clk_count; + struct sandbox_scmi_reset *reset; + size_t reset_count; }; /** @@ -48,10 +61,14 @@ struct sandbox_scmi_service { * struct sandbox_scmi_devices - Reference to devices probed through SCMI * @clk: Array the clock devices * @clk_count: Number of clock devices probed + * @reset: Array the reset controller devices + * @reset_count: Number of reset controller devices probed */ struct sandbox_scmi_devices { struct clk *clk; size_t clk_count; + struct reset_ctl *reset; + size_t reset_count; }; #ifdef CONFIG_SCMI_FIRMWARE diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 7d71c805dc..a2ebb3c971 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -220,6 +220,7 @@ CONFIG_REMOTEPROC_SANDBOX=y CONFIG_DM_RESET=y CONFIG_SANDBOX_RESET=y CONFIG_RESET_SYSCON=y +CONFIG_RESET_SCMI=y CONFIG_DM_RNG=y CONFIG_DM_RTC=y CONFIG_RTC_RV8803=y diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c index ff590988a6..5b6a4232af 100644 --- a/drivers/firmware/scmi/sandbox-scmi_agent.c +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -18,19 +18,20 @@ * processing. It simulates few of the SCMI services for some of the * SCMI protocols embedded in U-Boot. Currently: * - SCMI clock protocol: emulate 2 agents each exposing few clocks + * - SCMI reset protocol: emulate 1 agents each exposing a reset * - * Agent #0 simulates 2 clocks. - * See IDs in scmi0_clk[] and "sandbox-scmi-agent@0" in test.dts. + * Agent #0 simulates 2 clocks and 1 reset domain. + * See IDs in scmi0_clk[]/scmi0_reset[] and "sandbox-scmi-agent@0" in test.dts. * * Agent #1 simulates 1 clock. * See IDs in scmi1_clk[] and "sandbox-scmi-agent@1" in test.dts. * - * All clocks are default disabled. + * All clocks are default disabled and reset levels down. * * This Driver exports sandbox_scmi_service_ct() for the test sequence to * get the state of the simulated services (clock state, rate, ...) and * check back-end device state reflects the request send through the - * various uclass devices, currently only clock controllers. + * various uclass devices, as clocks and reset controllers. */ #define SANDBOX_SCMI_AGENT_COUNT 2 @@ -40,6 +41,10 @@ static struct sandbox_scmi_clk scmi0_clk[] = { { .id = 3, .rate = 333 }, }; +static struct sandbox_scmi_reset scmi0_reset[] = { + { .id = 3 }, +}; + static struct sandbox_scmi_clk scmi1_clk[] = { { .id = 1, .rate = 44 }, }; @@ -71,6 +76,11 @@ static void debug_print_agent_state(struct udevice *dev, char *str) agent->clk_count > 1 ? agent->clk[1].rate : -1, agent->clk_count > 2 ? agent->clk[2].enabled : -1, agent->clk_count > 2 ? agent->clk[2].rate : -1); + dev_dbg(dev, " scmi%u_reset (%zu): %d, %d, ...\n", + agent->idx, + agent->reset_count, + agent->reset_count ? agent->reset[0].asserted : -1, + agent->reset_count > 1 ? agent->reset[1].asserted : -1); }; static struct sandbox_scmi_clk *get_scmi_clk_state(uint agent_id, uint clock_id) @@ -99,6 +109,20 @@ static struct sandbox_scmi_clk *get_scmi_clk_state(uint agent_id, uint clock_id) return NULL; } +static struct sandbox_scmi_reset *get_scmi_reset_state(uint agent_id, + uint reset_id) +{ + size_t n; + + if (agent_id == 0) { + for (n = 0; n < ARRAY_SIZE(scmi0_reset); n++) + if (scmi0_reset[n].id == reset_id) + return scmi0_reset + n; + } + + return NULL; +} + /* * Sandbox SCMI agent ops */ @@ -194,6 +218,78 @@ static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg) return 0; } +static int sandbox_scmi_rd_attribs(struct udevice *dev, struct scmi_msg *msg) +{ + struct sandbox_scmi_agent *agent = dev_get_priv(dev); + struct scmi_rd_attr_in *in = NULL; + struct scmi_rd_attr_out *out = NULL; + struct sandbox_scmi_reset *reset_state = NULL; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + in = (struct scmi_rd_attr_in *)msg->in_msg; + out = (struct scmi_rd_attr_out *)msg->out_msg; + + reset_state = get_scmi_reset_state(agent->idx, in->domain_id); + if (!reset_state) { + dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id); + + out->status = SCMI_NOT_FOUND; + } else { + memset(out, 0, sizeof(*out)); + snprintf(out->name, sizeof(out->name), "rd%u", in->domain_id); + + out->status = SCMI_SUCCESS; + } + + return 0; +} + +static int sandbox_scmi_rd_reset(struct udevice *dev, struct scmi_msg *msg) +{ + struct sandbox_scmi_agent *agent = dev_get_priv(dev); + struct scmi_rd_reset_in *in = NULL; + struct scmi_rd_reset_out *out = NULL; + struct sandbox_scmi_reset *reset_state = NULL; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + in = (struct scmi_rd_reset_in *)msg->in_msg; + out = (struct scmi_rd_reset_out *)msg->out_msg; + + reset_state = get_scmi_reset_state(agent->idx, in->domain_id); + if (!reset_state) { + dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id); + + out->status = SCMI_NOT_FOUND; + } else if (in->reset_state > 1) { + dev_err(dev, "Invalid reset domain input attribute value\n"); + + out->status = SCMI_INVALID_PARAMETERS; + } else { + if (in->flags & SCMI_RD_RESET_FLAG_CYCLE) { + if (in->flags & SCMI_RD_RESET_FLAG_ASYNC) { + out->status = SCMI_NOT_SUPPORTED; + } else { + /* Ends deasserted whatever current state */ + reset_state->asserted = false; + out->status = SCMI_SUCCESS; + } + } else { + reset_state->asserted = in->flags & + SCMI_RD_RESET_FLAG_ASSERT; + + out->status = SCMI_SUCCESS; + } + } + + return 0; +} + static int sandbox_scmi_test_process_msg(struct udevice *dev, struct scmi_msg *msg) { @@ -210,12 +306,21 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev, break; } break; + case SCMI_PROTOCOL_ID_RESET_DOMAIN: + switch (msg->message_id) { + case SCMI_RESET_DOMAIN_ATTRIBUTES: + return sandbox_scmi_rd_attribs(dev, msg); + case SCMI_RESET_DOMAIN_RESET: + return sandbox_scmi_rd_reset(dev, msg); + default: + break; + } + break; case SCMI_PROTOCOL_ID_BASE: case SCMI_PROTOCOL_ID_POWER_DOMAIN: case SCMI_PROTOCOL_ID_SYSTEM: case SCMI_PROTOCOL_ID_PERF: case SCMI_PROTOCOL_ID_SENSOR: - case SCMI_PROTOCOL_ID_RESET_DOMAIN: *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED; return 0; default: @@ -260,6 +365,8 @@ static int sandbox_scmi_test_probe(struct udevice *dev) .idx = 0, .clk = scmi0_clk, .clk_count = ARRAY_SIZE(scmi0_clk), + .reset = scmi0_reset, + .reset_count = ARRAY_SIZE(scmi0_reset), }; break; case '1': diff --git a/drivers/firmware/scmi/sandbox-scmi_devices.c b/drivers/firmware/scmi/sandbox-scmi_devices.c index b3e411c5ac..c69967bf69 100644 --- a/drivers/firmware/scmi/sandbox-scmi_devices.c +++ b/drivers/firmware/scmi/sandbox-scmi_devices.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -14,18 +15,22 @@ /* * Simulate to some extent a SCMI exchange. * This drivers gets SCMI resources and offers API function to the - * SCMI test sequence manipulate the resources, currently clocks. + * SCMI test sequence manipulate the resources, currently clock + * and reset controllers. */ #define SCMI_TEST_DEVICES_CLK_COUNT 3 +#define SCMI_TEST_DEVICES_RD_COUNT 1 /* * struct sandbox_scmi_device_priv - Storage for device handles used by test * @clk: Array of clock instances used by tests + * @reset_clt: Array of the reset controller instances used by tests * @devices: Resources exposed by sandbox_scmi_devices_ctx() */ struct sandbox_scmi_device_priv { struct clk clk[SCMI_TEST_DEVICES_CLK_COUNT]; + struct reset_ctl reset_ctl[SCMI_TEST_DEVICES_RD_COUNT]; struct sandbox_scmi_devices devices; }; @@ -39,6 +44,22 @@ struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev) return NULL; } +static int sandbox_scmi_devices_remove(struct udevice *dev) +{ + struct sandbox_scmi_devices *devices = sandbox_scmi_devices_ctx(dev); + int ret = 0; + size_t n; + + for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) { + int ret2 = reset_free(devices->reset + n); + + if (ret2 && !ret) + ret = ret2; + } + + return ret; +} + static int sandbox_scmi_devices_probe(struct udevice *dev) { struct sandbox_scmi_device_priv *priv = dev_get_priv(dev); @@ -48,6 +69,8 @@ static int sandbox_scmi_devices_probe(struct udevice *dev) priv->devices = (struct sandbox_scmi_devices){ .clk = priv->clk, .clk_count = SCMI_TEST_DEVICES_CLK_COUNT, + .reset = priv->reset_ctl, + .reset_count = SCMI_TEST_DEVICES_RD_COUNT, }; for (n = 0; n < SCMI_TEST_DEVICES_CLK_COUNT; n++) { @@ -58,7 +81,21 @@ static int sandbox_scmi_devices_probe(struct udevice *dev) } } + for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) { + ret = reset_get_by_index(dev, n, priv->devices.reset + n); + if (ret) { + dev_err(dev, "%s: Failed on reset %zu\n", __func__, n); + goto err_reset; + } + } + return 0; + +err_reset: + for (; n > 0; n--) + reset_free(priv->devices.reset + n - 1); + + return ret; } static const struct udevice_id sandbox_scmi_devices_ids[] = { @@ -71,5 +108,6 @@ U_BOOT_DRIVER(sandbox_scmi_devices) = { .id = UCLASS_MISC, .of_match = sandbox_scmi_devices_ids, .priv_auto_alloc_size = sizeof(struct sandbox_scmi_device_priv), + .remove = sandbox_scmi_devices_remove, .probe = sandbox_scmi_devices_probe, }; diff --git a/test/dm/scmi.c b/test/dm/scmi.c index aa46f31a47..be60b44b3b 100644 --- a/test/dm/scmi.c +++ b/test/dm/scmi.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,8 @@ static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts, ut_assertnonnull(scmi_devices); if (IS_ENABLED(CONFIG_CLK_SCMI)) ut_asserteq(3, scmi_devices->clk_count); + if (IS_ENABLED(CONFIG_RESET_SCMI)) + ut_asserteq(1, scmi_devices->reset_count); /* State of the simulated SCMI server exposed */ scmi_ctx = sandbox_scmi_service_ctx(); @@ -53,6 +56,8 @@ static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts, ut_assertnonnull(scmi_ctx->agent[0]); ut_asserteq(2, scmi_ctx->agent[0]->clk_count); ut_assertnonnull(scmi_ctx->agent[0]->clk); + ut_asserteq(1, scmi_ctx->agent[0]->reset_count); + ut_assertnonnull(scmi_ctx->agent[0]->reset); ut_assertnonnull(scmi_ctx->agent[1]); ut_assertnonnull(scmi_ctx->agent[1]->clk); @@ -165,3 +170,34 @@ static int dm_test_scmi_clocks(struct unit_test_state *uts) } DM_TEST(dm_test_scmi_clocks, UT_TESTF_SCAN_FDT); + +static int dm_test_scmi_resets(struct unit_test_state *uts) +{ + struct sandbox_scmi_devices *scmi_devices; + struct sandbox_scmi_service *scmi_ctx; + struct udevice *dev = NULL; + int ret; + + if (!IS_ENABLED(CONFIG_RESET_SCMI)) + return 0; + + ret = load_sandbox_scmi_test_devices(uts, &dev); + if (ret) + return ret; + + scmi_devices = sandbox_scmi_devices_ctx(dev); + scmi_ctx = sandbox_scmi_service_ctx(); + + /* Test SCMI resect controller manipulation */ + ut_assert(!scmi_ctx->agent[0]->reset[0].asserted) + + ut_assertok(reset_assert(&scmi_devices->reset[0])); + ut_assert(scmi_ctx->agent[0]->reset[0].asserted) + + ut_assertok(reset_deassert(&scmi_devices->reset[0])); + ut_assert(!scmi_ctx->agent[0]->reset[0].asserted); + + return release_sandbox_scmi_test_devices(uts, dev); +} + +DM_TEST(dm_test_scmi_resets, UT_TESTF_SCAN_FDT); -- cgit v1.2.3 From 9a499b2bfa684abe77033c76740a597da8f09f11 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 9 Jun 2020 15:37:39 +0200 Subject: net: phy: mscc: make clock-output configurable on vsc85xx The vsc8530/8531/8540/8541 phys have a configurable clock output that can emit 25, 50 and 125 MHz rates, which in turn may be needed for stable network connections. This follows a similar change introduced into the Linux kernel at https://lore.kernel.org/netdev/20200609133140.1421109-2-heiko@sntech.de Signed-off-by: Heiko Stuebner Reviewed-by: Philipp Tomsich --- drivers/net/phy/mscc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 709979f48c..64e9093827 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -157,6 +157,14 @@ #define INT_MEM_DATA_M GENMASK(7, 0) #define INT_MEM_DATA(x) (INT_MEM_DATA_M & (x)) +/* Extended page GPIO register 13G */ +#define MSCC_CLKOUT_CNTL 13 +#define CLKOUT_ENABLE BIT(15) +#define CLKOUT_FREQ_MASK GENMASK(14, 13) +#define CLKOUT_FREQ_25M (0x0 << 13) +#define CLKOUT_FREQ_50M (0x1 << 13) +#define CLKOUT_FREQ_125M (0x2 << 13) + /* Extended page GPIO register 18G */ #define MSCC_PHY_PROC_CMD 18 #define PROC_CMD_NCOMPLETED BIT(15) @@ -1210,6 +1218,47 @@ static int vsc8531_vsc8541_mac_config(struct phy_device *phydev) return 0; } +static int vsc8531_vsc8541_clkout_config(struct phy_device *phydev) +{ + struct ofnode_phandle_args phandle_args; + u32 clkout_rate = 0; + u16 reg_val; + int retval; + + retval = dev_read_phandle_with_args(phydev->dev, "phy-handle", NULL, + 0, 0, &phandle_args); + if (!retval) + clkout_rate = ofnode_read_u32_default(phandle_args.node, + "vsc8531,clk-out-frequency", 0); + + switch (clkout_rate) { + case 0: + reg_val = 0; + break; + case 25000000: + reg_val = CLKOUT_FREQ_25M | CLKOUT_ENABLE; + break; + case 50000000: + reg_val = CLKOUT_FREQ_50M | CLKOUT_ENABLE; + break; + case 125000000: + reg_val = CLKOUT_FREQ_125M | CLKOUT_ENABLE; + break; + default: + printf("PHY 8530/31 invalid clkout rate %u\n", + clkout_rate); + return -EINVAL; + } + + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_GPIO); + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_CLKOUT_CNTL, reg_val); + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_STD); + + return 0; +} + static int vsc8531_config(struct phy_device *phydev) { int retval = -EINVAL; @@ -1267,6 +1316,11 @@ static int vsc8531_config(struct phy_device *phydev) phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STD); + /* Configure the clk output */ + retval = vsc8531_vsc8541_clkout_config(phydev); + if (retval != 0) + return retval; + return genphy_config_aneg(phydev); } @@ -1327,6 +1381,11 @@ static int vsc8541_config(struct phy_device *phydev) phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STD); + /* Configure the clk output */ + retval = vsc8531_vsc8541_clkout_config(phydev); + if (retval != 0) + return retval; + return genphy_config_aneg(phydev); } -- cgit v1.2.3 From d63c14cc3f24f56139bd385b0c35c9b264f0e83b Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 9 Jun 2020 15:37:40 +0200 Subject: net: phy: mscc: sync rx/tx delay settings with Linux on vsc85xx The Linux kernel does set the clock delays to - 0.2 ns (their default, and lowest, hardware value) if delays should not be enabled - 2.0 ns (which causes the data to be sampled at exactly half way between clock transitions at 1000 Mbps) if delays should be enabled depending on the interface mode See https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/phy/mscc/mscc_main.c#n523 So instead of using arbitrary delay values like now, mimic this behaviour. The behaviour is the same for all of vsc8530/8531/8540/8541 so move that to a shared function while at it. Signed-off-by: Heiko Stuebner Reviewed-by: Philipp Tomsich --- drivers/net/phy/mscc.c | 70 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 64e9093827..d1a643cf5a 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -1176,6 +1176,9 @@ static int vsc8531_vsc8541_mac_config(struct phy_device *phydev) rx_clk_out = RX_CLK_OUT_NORMAL; break; + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII: /* Set Reg23.12:11=2 */ mac_if = MAC_IF_SELECTION_RGMII; @@ -1259,13 +1262,43 @@ static int vsc8531_vsc8541_clkout_config(struct phy_device *phydev) return 0; } +static int vsc8531_vsc8541_clk_skew_config(struct phy_device *phydev) +{ + enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_200_PS; + enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_200_PS; + u16 reg_val; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + rx_clk_skew = VSC_PHY_RGMII_DELAY_2000_PS; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + tx_clk_skew = VSC_PHY_RGMII_DELAY_2000_PS; + + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXT2); + reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG); + + /* Reg20E2 - Update RGMII RX_Clk Skews. */ + reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS, + RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew); + /* Reg20E2 - Update RGMII TX_Clk Skews. */ + reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS, + RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew); + + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val); + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_STD); + + return 0; +} + static int vsc8531_config(struct phy_device *phydev) { int retval = -EINVAL; u16 reg_val; u16 rmii_clk_out; - enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_1700_PS; - enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_800_PS; enum vsc_phy_clk_slew edge_rate = VSC_PHY_CLK_SLEW_RATE_4; /* For VSC8530/31 and VSC8540/41 the init scripts are the same */ @@ -1275,6 +1308,9 @@ static int vsc8531_config(struct phy_device *phydev) switch (phydev->interface) { case PHY_INTERFACE_MODE_RMII: case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_ID: retval = vsc8531_vsc8541_mac_config(phydev); if (retval != 0) return retval; @@ -1291,19 +1327,12 @@ static int vsc8531_config(struct phy_device *phydev) /* Default RMII Clk Output to 0=OFF/1=ON */ rmii_clk_out = 0; + retval = vsc8531_vsc8541_clk_skew_config(phydev); + if (retval != 0) + return retval; + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXT2); - reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG); - - /* Reg20E2 - Update RGMII RX_Clk Skews. */ - reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS, - RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew); - /* Reg20E2 - Update RGMII TX_Clk Skews. */ - reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS, - RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew); - - phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val); - reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL); /* Reg27E2 - Update Clk Slew Rate. */ reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS, @@ -1329,8 +1358,6 @@ static int vsc8541_config(struct phy_device *phydev) int retval = -EINVAL; u16 reg_val; u16 rmii_clk_out; - enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_1700_PS; - enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_800_PS; enum vsc_phy_clk_slew edge_rate = VSC_PHY_CLK_SLEW_RATE_4; /* For VSC8530/31 and VSC8540/41 the init scripts are the same */ @@ -1358,17 +1385,12 @@ static int vsc8541_config(struct phy_device *phydev) /* Default RMII Clk Output to 0=OFF/1=ON */ rmii_clk_out = 0; + retval = vsc8531_vsc8541_clk_skew_config(phydev); + if (retval != 0) + return retval; + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXT2); - reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG); - /* Reg20E2 - Update RGMII RX_Clk Skews. */ - reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS, - RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew); - /* Reg20E2 - Update RGMII TX_Clk Skews. */ - reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS, - RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew); - phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val); - reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL); /* Reg27E2 - Update Clk Slew Rate. */ reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS, -- cgit v1.2.3 From 66e036bab503cddd6afbfecc8b7fcd8941d8bd7d Mon Sep 17 00:00:00 2001 From: Thirupathaiah Annapureddy Date: Mon, 17 Aug 2020 17:08:26 -0700 Subject: net: ftgmac100: Add support for board specific PHY interface address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ftgmac100 driver is using hard-coded PHY interface address of zero. Each board can have different PHY interface address (phy_addr). This commit modifies the driver to make use of board specific address by leveraging CONFIG_PHY_ADDR. Signed-off-by: Thirupathaiah Annapureddy Reviewed-by: Cédric Le Goater --- drivers/net/ftgmac100.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c index 5676a5b3ba..00bda24f1f 100644 --- a/drivers/net/ftgmac100.c +++ b/drivers/net/ftgmac100.c @@ -551,6 +551,10 @@ static int ftgmac100_probe(struct udevice *dev) priv->max_speed = pdata->max_speed; priv->phy_addr = 0; +#ifdef CONFIG_PHY_ADDR + priv->phy_addr = CONFIG_PHY_ADDR; +#endif + ret = clk_enable_bulk(&priv->clks); if (ret) goto out; -- cgit v1.2.3 From 387cbf096e443705fa66776027273ed257ec6ca3 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Tue, 18 Aug 2020 08:19:02 -0500 Subject: net: smc911x: Automatically Update ethaddr with MAC The ethernet controller can read the MAC from EEPROM and display it, but if ethaddr is not set, the ethernet is still unavailable. This patch checks will automatically set the MAC address if it has not already been set. Signed-off-by: Adam Ford Acked-by: Joe Hershberger --- drivers/net/smc911x.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 09372d7f6b..1fa3667b77 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -185,6 +186,8 @@ static void smc911x_handle_mac_address(struct smc911x_priv *priv) smc911x_set_mac_csr(priv, ADDRH, addrh); printf(DRIVERNAME ": MAC %pM\n", m); + if (!env_get("ethaddr")) + env_set("ethaddr", (const char *)m); } static bool smc911x_read_mac_address(struct smc911x_priv *priv) -- cgit v1.2.3 From 3151fdd7f4ad0cdb14e3aa35eae9908efa0b572e Mon Sep 17 00:00:00 2001 From: Srinath Mannam Date: Thu, 2 Apr 2020 16:08:12 +0530 Subject: phy: add support for stingray PAXB PHY controller Add support for stingray PAXB PHY controller driver. This driver supports maximum 8 PAXB phys using pipemux data. Signed-off-by: Srinath Mannam Signed-off-by: Rayagonda Kokatanur Reviewed-by: Stefan Roese --- drivers/phy/Kconfig | 7 ++ drivers/phy/Makefile | 1 + drivers/phy/phy-bcm-sr-pcie.c | 177 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 drivers/phy/phy-bcm-sr-pcie.c (limited to 'drivers') diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 8da00a259d..d66aa07392 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -84,6 +84,13 @@ config BCM6368_USBH_PHY help Support for the Broadcom MIPS BCM6368 USBH PHY. +config BCM_SR_PCIE_PHY + bool "Broadcom Stingray PCIe PHY driver" + depends on PHY + help + Enable this to support the Broadcom Stingray PCIe PHY + If unsure, say N. + config PHY_DA8XX_USB tristate "TI DA8xx USB PHY Driver" depends on PHY && ARCH_DAVINCI diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 009f353baf..8dabefd776 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_BCM6318_USBH_PHY) += bcm6318-usbh-phy.o obj-$(CONFIG_BCM6348_USBH_PHY) += bcm6348-usbh-phy.o obj-$(CONFIG_BCM6358_USBH_PHY) += bcm6358-usbh-phy.o obj-$(CONFIG_BCM6368_USBH_PHY) += bcm6368-usbh-phy.o +obj-$(CONFIG_BCM_SR_PCIE_PHY) += phy-bcm-sr-pcie.o obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o obj-$(CONFIG_$(SPL_)PIPE3_PHY) += ti-pipe3-phy.o obj-$(CONFIG_AM654_PHY) += phy-ti-am654.o diff --git a/drivers/phy/phy-bcm-sr-pcie.c b/drivers/phy/phy-bcm-sr-pcie.c new file mode 100644 index 0000000000..36c77c4b63 --- /dev/null +++ b/drivers/phy/phy-bcm-sr-pcie.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Broadcom + */ + +#include +#include +#include +#include +#include + +/* we have up to 8 PAXB based RC. The 9th one is always PAXC */ +#define SR_NR_PCIE_PHYS 8 + +#define PCIE_PIPEMUX_CFG_OFFSET 0x10c +#define PCIE_PIPEMUX_SELECT_STRAP GENMASK(3, 0) + +#define CDRU_STRAP_DATA_LSW_OFFSET 0x5c +#define PCIE_PIPEMUX_SHIFT 19 +#define PCIE_PIPEMUX_MASK GENMASK(3, 0) + +/** + * struct sr_pcie_phy_core - Stingray PCIe PHY core control + * + * @dev: pointer to device + * @base: base register of PCIe SS + * @cdru: CDRU base address + * @pipemux: pipemuex strap + */ +struct sr_pcie_phy_core { + struct udevice *dev; + void __iomem *base; + void __iomem *cdru; + u32 pipemux; +}; + +/* + * PCIe PIPEMUX lookup table + * + * Each array index represents a PIPEMUX strap setting + * The array element represents a bitmap where a set bit means the PCIe + * core and associated serdes has been enabled as RC and is available for use + */ +static const u8 pipemux_table[] = { + /* PIPEMUX = 0, EP 1x16 */ + 0x00, + /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */ + 0x80, + /* PIPEMUX = 2, EP 4x4 */ + 0x00, + /* PIPEMUX = 3, RC 2x8, cores 0, 7 */ + 0x81, + /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */ + 0xc3, + /* PIPEMUX = 5, RC 8x2, all 8 cores */ + 0xff, + /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */ + 0xcd, + /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */ + 0xfd, + /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */ + 0xf0, + /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */ + 0xc0, + /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */ + 0x42, + /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */ + 0x3c, + /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */ + 0xfc, + /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */ + 0x4c, +}; + +/* + * Return true if the strap setting is valid + */ +static bool pipemux_strap_is_valid(u32 pipemux) +{ + return !!(pipemux < ARRAY_SIZE(pipemux_table)); +} + +/* + * Read the PCIe PIPEMUX from strap + */ +static u32 pipemux_strap_read(struct sr_pcie_phy_core *core) +{ + u32 pipemux; + + /* + * Read PIPEMUX configuration register to determine the pipemux setting + * + * In the case when the value indicates using HW strap, fall back to + * use HW strap + */ + pipemux = readl(core->base + PCIE_PIPEMUX_CFG_OFFSET); + pipemux &= PCIE_PIPEMUX_MASK; + if (pipemux == PCIE_PIPEMUX_SELECT_STRAP) { + pipemux = readl(core->cdru + CDRU_STRAP_DATA_LSW_OFFSET); + pipemux >>= PCIE_PIPEMUX_SHIFT; + pipemux &= PCIE_PIPEMUX_MASK; + } + + return pipemux; +} + +static int sr_pcie_phy_init(struct phy *phy) +{ + struct sr_pcie_phy_core *core = dev_get_priv(phy->dev); + unsigned int core_idx = phy->id; + + debug("%s %lx\n", __func__, phy->id); + /* + * Check whether this PHY is for root complex or not. If yes, return + * zero so the host driver can proceed to enumeration. If not, return + * an error and that will force the host driver to bail out + */ + if (!!((pipemux_table[core->pipemux] >> core_idx) & 0x1)) + return 0; + + return -ENODEV; +} + +static int sr_pcie_phy_xlate(struct phy *phy, struct ofnode_phandle_args *args) +{ + debug("%s %d\n", __func__, args->args[0]); + if (args->args_count && args->args[0] < SR_NR_PCIE_PHYS) + phy->id = args->args[0]; + else + return -ENODEV; + + return 0; +} + +static const struct phy_ops sr_pcie_phy_ops = { + .of_xlate = sr_pcie_phy_xlate, + .init = sr_pcie_phy_init, +}; + +static int sr_pcie_phy_probe(struct udevice *dev) +{ + struct sr_pcie_phy_core *core = dev_get_priv(dev); + + core->dev = dev; + + core->base = (void __iomem *)devfdt_get_addr_name(dev, "reg_base"); + core->cdru = (void __iomem *)devfdt_get_addr_name(dev, "cdru_base"); + debug("ip base %p\n", core->base); + debug("cdru base %p\n", core->cdru); + + /* read the PCIe PIPEMUX strap setting */ + core->pipemux = pipemux_strap_read(core); + if (!pipemux_strap_is_valid(core->pipemux)) { + pr_err("invalid PCIe PIPEMUX strap %u\n", core->pipemux); + return -EIO; + } + debug("%s %#x\n", __func__, core->pipemux); + + pr_info("Stingray PCIe PHY driver initialized\n"); + + return 0; +} + +static const struct udevice_id sr_pcie_phy_match_table[] = { + { .compatible = "brcm,sr-pcie-phy" }, + { } +}; + +U_BOOT_DRIVER(sr_pcie_phy) = { + .name = "sr-pcie-phy", + .id = UCLASS_PHY, + .probe = sr_pcie_phy_probe, + .of_match = sr_pcie_phy_match_table, + .ops = &sr_pcie_phy_ops, + .platdata_auto_alloc_size = sizeof(struct sr_pcie_phy_core), + .priv_auto_alloc_size = sizeof(struct sr_pcie_phy_core), +}; -- cgit v1.2.3 From cafaa301c98aa8f1b81cf61a91d22d5d68b4b1d3 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 9 Sep 2020 18:30:06 +0200 Subject: net: dwc_eth_qos: Convert to use APIs which support live DT Use ofnode_ or dev_ APIs instead of fdt_ and fdtdec_ APIs so that the driver can support live DT. Signed-off-by: Patrick Delaunay --- drivers/net/dwc_eth_qos.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 810a2b95b1..db1102562f 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -26,6 +26,7 @@ * supports a single RGMII PHY. This configuration also has SW control over * all clock and reset signals to the HW block. */ + #include #include #include @@ -1893,8 +1894,7 @@ static phy_interface_t eqos_get_interface_stm32(struct udevice *dev) debug("%s(dev=%p):\n", __func__, dev); - phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", - NULL); + phy_mode = dev_read_prop(dev, "phy-mode", NULL); if (phy_mode) interface = phy_get_interface_by_name(phy_mode); @@ -1931,8 +1931,7 @@ static phy_interface_t eqos_get_interface_imx(struct udevice *dev) debug("%s(dev=%p):\n", __func__, dev); - phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", - NULL); + phy_mode = dev_read_prop(dev, "phy-mode", NULL); if (phy_mode) interface = phy_get_interface_by_name(phy_mode); -- cgit v1.2.3 From 719d7d8df41d2f20be599c38c3ab3e7a904c92c6 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 8 Sep 2020 18:59:55 +0200 Subject: usb: xhci: add a member hci_version in xhci_ctrl struct Add a member to save xHCI version, it's used some times. Signed-off-by: Chunfeng Yun Reviewed-by: Bin Meng --- drivers/usb/host/xhci-ring.c | 4 ++-- drivers/usb/host/xhci.c | 1 + include/usb/xhci.h | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 092ed6eaf1..79bfc349f4 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -682,7 +682,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, field |= TRB_ISP; /* Set the TRB length, TD size, and interrupter fields. */ - if (HC_VERSION(xhci_readl(&ctrl->hccr->cr_capbase)) < 0x100) + if (ctrl->hci_version < 0x100) remainder = xhci_td_remainder(length - running_total); else remainder = xhci_v1_0_td_remainder(running_total, @@ -830,7 +830,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, field |= 0x1; /* xHCI 1.0 6.4.1.2.1: Transfer Type field */ - if (HC_VERSION(xhci_readl(&ctrl->hccr->cr_capbase)) >= 0x100) { + if (ctrl->hci_version >= 0x100) { if (length > 0) { if (req->requesttype & USB_DIR_IN) field |= (TRB_DATA_IN << TRB_TX_TYPE_SHIFT); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 126dabc11b..4be1411243 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1283,6 +1283,7 @@ static int xhci_lowlevel_init(struct xhci_ctrl *ctrl) reg = HC_VERSION(xhci_readl(&hccr->cr_capbase)); printf("USB XHCI %x.%02x\n", reg >> 8, reg & 0xff); + ctrl->hci_version = reg; return 0; } diff --git a/include/usb/xhci.h b/include/usb/xhci.h index 7d34103fd5..a3e5914b10 100644 --- a/include/usb/xhci.h +++ b/include/usb/xhci.h @@ -1227,6 +1227,7 @@ struct xhci_ctrl { struct xhci_scratchpad *scratchpad; struct xhci_virt_device *devs[MAX_HC_SLOTS]; int rootdev; + u16 hci_version; }; unsigned long trb_addr(struct xhci_segment *seg, union xhci_trb *trb); -- cgit v1.2.3 From e3ea481bee1fbc8f090f46c38354838a64958af4 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 8 Sep 2020 18:59:56 +0200 Subject: usb: xhci: create one unified function to calculate TRB TD remainder xhci versions 1.0 and later report the untransferred data remaining in a TD a bit differently than older hosts. We used to have separate functions for these, and needed to check host version before calling the right function. Now Mediatek host has an additional quirk on how it uses the TD Size field for remaining data. To prevent yet another function for calculating remainder we instead want to make one quirk friendly unified function. Porting from the Linux: c840d6ce772d("xhci: create one unified function to calculate TRB TD remainder.") 124c39371114("xhci: use boolean to indicate last trb in td remainder calculation") Signed-off-by: Chunfeng Yun Reviewed-by: Bin Meng --- drivers/usb/host/xhci-ring.c | 105 +++++++++++++++++++++---------------------- include/usb/xhci.h | 2 + 2 files changed, 52 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 79bfc349f4..603e0e5b76 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -298,55 +298,52 @@ void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr, u32 slot_id, xhci_writel(&ctrl->dba->doorbell[0], DB_VALUE_HOST); } -/** - * The TD size is the number of bytes remaining in the TD (including this TRB), - * right shifted by 10. - * It must fit in bits 21:17, so it can't be bigger than 31. +/* + * For xHCI 1.0 host controllers, TD size is the number of max packet sized + * packets remaining in the TD (*not* including this TRB). * - * @param remainder remaining packets to be sent - * @return remainder if remainder is less than max else max - */ -static u32 xhci_td_remainder(unsigned int remainder) -{ - u32 max = (1 << (21 - 17 + 1)) - 1; - - if ((remainder >> 10) >= max) - return max << 17; - else - return (remainder >> 10) << 17; -} - -/** - * Finds out the remanining packets to be sent + * Total TD packet count = total_packet_count = + * DIV_ROUND_UP(TD size in bytes / wMaxPacketSize) + * + * Packets transferred up to and including this TRB = packets_transferred = + * rounddown(total bytes transferred including this TRB / wMaxPacketSize) + * + * TD size = total_packet_count - packets_transferred * - * @param running_total total size sent so far + * For xHCI 0.96 and older, TD size field should be the remaining bytes + * including this TRB, right shifted by 10 + * + * For all hosts it must fit in bits 21:17, so it can't be bigger than 31. + * This is taken care of in the TRB_TD_SIZE() macro + * + * The last TRB in a TD must have the TD size set to zero. + * + * @param ctrl host controller data structure + * @param transferred total size sent so far * @param trb_buff_len length of the TRB Buffer - * @param total_packet_count total packet count - * @param maxpacketsize max packet size of current pipe - * @param num_trbs_left number of TRBs left to be processed - * @return 0 if running_total or trb_buff_len is 0, else remainder + * @param td_total_len total packet count + * @param maxp max packet size of current pipe + * @param more_trbs_coming indicate last trb in TD + * @return remainder */ -static u32 xhci_v1_0_td_remainder(int running_total, - int trb_buff_len, - unsigned int total_packet_count, - int maxpacketsize, - unsigned int num_trbs_left) +static u32 xhci_td_remainder(struct xhci_ctrl *ctrl, int transferred, + int trb_buff_len, unsigned int td_total_len, + int maxp, bool more_trbs_coming) { - int packets_transferred; + u32 total_packet_count; + + if (ctrl->hci_version < 0x100) + return ((td_total_len - transferred) >> 10); /* One TRB with a zero-length data packet. */ - if (num_trbs_left == 0 || (running_total == 0 && trb_buff_len == 0)) + if (!more_trbs_coming || (transferred == 0 && trb_buff_len == 0) || + trb_buff_len == td_total_len) return 0; - /* - * All the TRB queueing functions don't count the current TRB in - * running_total. - */ - packets_transferred = (running_total + trb_buff_len) / maxpacketsize; + total_packet_count = DIV_ROUND_UP(td_total_len, maxp); - if ((total_packet_count - packets_transferred) > 31) - return 31 << 17; - return (total_packet_count - packets_transferred) << 17; + /* Queueing functions don't count the current TRB into transferred */ + return (total_packet_count - ((transferred + trb_buff_len) / maxp)); } /** @@ -572,7 +569,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, union xhci_trb *event; int running_total, trb_buff_len; - unsigned int total_packet_count; + bool more_trbs_coming = true; int maxpacketsize; u64 addr; int ret; @@ -636,8 +633,6 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, running_total = 0; maxpacketsize = usb_maxpacket(udev, pipe); - total_packet_count = DIV_ROUND_UP(length, maxpacketsize); - /* How much data is in the first TRB? */ /* * How much data is (potentially) left before the 64KB boundary? @@ -672,27 +667,24 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, * Chain all the TRBs together; clear the chain bit in the last * TRB to indicate it's the last TRB in the chain. */ - if (num_trbs > 1) + if (num_trbs > 1) { field |= TRB_CHAIN; - else + } else { field |= TRB_IOC; + more_trbs_coming = false; + } /* Only set interrupt on short packet for IN endpoints */ if (usb_pipein(pipe)) field |= TRB_ISP; /* Set the TRB length, TD size, and interrupter fields. */ - if (ctrl->hci_version < 0x100) - remainder = xhci_td_remainder(length - running_total); - else - remainder = xhci_v1_0_td_remainder(running_total, - trb_buff_len, - total_packet_count, - maxpacketsize, - num_trbs - 1); + remainder = xhci_td_remainder(ctrl, running_total, trb_buff_len, + length, maxpacketsize, + more_trbs_coming); length_field = ((trb_buff_len & TRB_LEN_MASK) | - remainder | + TRB_TD_SIZE(remainder) | ((0 & TRB_INTR_TARGET_MASK) << TRB_INTR_TARGET_SHIFT)); @@ -764,6 +756,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, struct xhci_virt_device *virt_dev = ctrl->devs[slot_id]; struct xhci_ring *ep_ring; union xhci_trb *event; + u32 remainder; debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n", req->request, req->request, @@ -866,12 +859,14 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, else field = (TRB_DATA << TRB_TYPE_SHIFT); - length_field = (length & TRB_LEN_MASK) | xhci_td_remainder(length) | + remainder = xhci_td_remainder(ctrl, 0, length, length, + usb_maxpacket(udev, pipe), true); + length_field = (length & TRB_LEN_MASK) | TRB_TD_SIZE(remainder) | ((0 & TRB_INTR_TARGET_MASK) << TRB_INTR_TARGET_SHIFT); debug("length_field = %d, length = %d," "xhci_td_remainder(length) = %d , TRB_INTR_TARGET(0) = %d\n", length_field, (length & TRB_LEN_MASK), - xhci_td_remainder(length), 0); + TRB_TD_SIZE(remainder), 0); if (length > 0) { if (req->requesttype & USB_DIR_IN) diff --git a/include/usb/xhci.h b/include/usb/xhci.h index a3e5914b10..15926eb9f4 100644 --- a/include/usb/xhci.h +++ b/include/usb/xhci.h @@ -850,6 +850,8 @@ struct xhci_event_cmd { /* transfer_len bitmasks - bits 0:16 */ #define TRB_LEN(p) ((p) & 0x1ffff) #define TRB_LEN_MASK (0x1ffff) +/* TD Size, packets remaining in this TD, bits 21:17 (5 bits, so max 31) */ +#define TRB_TD_SIZE(p) (min((p), (u32)31) << 17) /* Interrupter Target - which MSI-X vector to target the completion event at */ #define TRB_INTR_TARGET_SHIFT (22) #define TRB_INTR_TARGET_MASK (0x3ff) -- cgit v1.2.3 From 740820519c69d84b320199a8a4348e47c447ebfb Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 8 Sep 2020 18:59:57 +0200 Subject: usb: xhci: add quirks flag to support MediaTek xHCI 0.96 There some vendor quirks for MTK xHCI 0.96 host controller: 1. It defines some extra SW scheduling parameters for HW to minimize the scheduling effort for synchronous and interrupt endpoints. The parameters are put into reserved DWs of slot context and endpoint context. 2. Its TDS in Normal TRB defines a number of packets that remains to be transferred for a TD after processing all Max packets in all previous TRBs. Signed-off-by: Chunfeng Yun Tested-by: Frank Wunderlich Reviewed-by: Bin Meng --- drivers/usb/host/xhci-mtk.c | 1 + drivers/usb/host/xhci-ring.c | 9 +++++++-- drivers/usb/host/xhci.c | 2 +- include/usb/xhci.h | 2 ++ 4 files changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 8ff71854fc..f3f181dae0 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -258,6 +258,7 @@ static int xhci_mtk_probe(struct udevice *dev) if (ret) goto ssusb_init_err; + mtk->ctrl.quirks = XHCI_MTK_HOST; hcor = (struct xhci_hcor *)((uintptr_t)mtk->hcd + HC_LENGTH(xhci_readl(&mtk->hcd->cr_capbase))); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 603e0e5b76..3f915ae115 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -332,7 +332,8 @@ static u32 xhci_td_remainder(struct xhci_ctrl *ctrl, int transferred, { u32 total_packet_count; - if (ctrl->hci_version < 0x100) + /* MTK xHCI 0.96 contains some features from 1.0 */ + if (ctrl->hci_version < 0x100 && !(ctrl->quirks & XHCI_MTK_HOST)) return ((td_total_len - transferred) >> 10); /* One TRB with a zero-length data packet. */ @@ -340,6 +341,10 @@ static u32 xhci_td_remainder(struct xhci_ctrl *ctrl, int transferred, trb_buff_len == td_total_len) return 0; + /* for MTK xHCI 0.96, TD size include this TRB, but not in 1.x */ + if ((ctrl->quirks & XHCI_MTK_HOST) && (ctrl->hci_version < 0x100)) + trb_buff_len = 0; + total_packet_count = DIV_ROUND_UP(td_total_len, maxp); /* Queueing functions don't count the current TRB into transferred */ @@ -823,7 +828,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, field |= 0x1; /* xHCI 1.0 6.4.1.2.1: Transfer Type field */ - if (ctrl->hci_version >= 0x100) { + if (ctrl->hci_version >= 0x100 || ctrl->quirks & XHCI_MTK_HOST) { if (length > 0) { if (req->requesttype & USB_DIR_IN) field |= (TRB_DATA_IN << TRB_TX_TYPE_SHIFT); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 4be1411243..51edeb22c1 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -650,7 +650,7 @@ static int xhci_set_configuration(struct usb_device *udev) * are put into reserved DWs in Slot and Endpoint Contexts * for synchronous endpoints. */ - if (IS_ENABLED(CONFIG_USB_XHCI_MTK)) { + if (ctrl->quirks & XHCI_MTK_HOST) { ep_ctx[ep_index]->reserved[0] = cpu_to_le32(EP_BPKTS(1) | EP_BBM(1)); } diff --git a/include/usb/xhci.h b/include/usb/xhci.h index 15926eb9f4..3de46cd95e 100644 --- a/include/usb/xhci.h +++ b/include/usb/xhci.h @@ -1230,6 +1230,8 @@ struct xhci_ctrl { struct xhci_virt_device *devs[MAX_HC_SLOTS]; int rootdev; u16 hci_version; + u32 quirks; +#define XHCI_MTK_HOST BIT(0) }; unsigned long trb_addr(struct xhci_segment *seg, union xhci_trb *trb); -- cgit v1.2.3 From 86d1fa17fb91d2579ed059db0125a198c7a388fd Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 8 Sep 2020 18:59:58 +0200 Subject: usb: xhci: convert to HCS_MAX_PORTS() Use HCS_MAX_PORTS(p) instead of ((p & HCS_MAX_PORTS_MASK) >> HCS_MAX_PORTS_SHIFT) Signed-off-by: Chunfeng Yun Reviewed-by: Bin Meng --- drivers/usb/host/xhci.c | 3 +-- include/usb/xhci.h | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 51edeb22c1..5f3a0fba4b 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1257,8 +1257,7 @@ static int xhci_lowlevel_init(struct xhci_ctrl *ctrl) return -ENOMEM; reg = xhci_readl(&hccr->cr_hcsparams1); - descriptor.hub.bNbrPorts = ((reg & HCS_MAX_PORTS_MASK) >> - HCS_MAX_PORTS_SHIFT); + descriptor.hub.bNbrPorts = HCS_MAX_PORTS(reg); printf("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts); /* Port Indicators */ diff --git a/include/usb/xhci.h b/include/usb/xhci.h index 3de46cd95e..cf4c0208b2 100644 --- a/include/usb/xhci.h +++ b/include/usb/xhci.h @@ -101,8 +101,6 @@ struct xhci_hccr { /* bits 8:18, Max Interrupters */ #define HCS_MAX_INTRS(p) (((p) >> 8) & 0x7ff) /* bits 24:31, Max Ports - max value is 0x7F = 127 ports */ -#define HCS_MAX_PORTS_SHIFT 24 -#define HCS_MAX_PORTS_MASK (0xff << HCS_MAX_PORTS_SHIFT) #define HCS_MAX_PORTS(p) (((p) >> 24) & 0xff) /* HCSPARAMS2 - hcs_params2 - bitmasks */ -- cgit v1.2.3 From a826d76f2bab971b293b4ba6bf45b81871051383 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 8 Sep 2020 18:59:59 +0200 Subject: usb: xhci: convert to TRB_TYPE() Use TRB_TYPE(p) instead of ((p) << TRB_TYPE_SHIFT) Signed-off-by: Chunfeng Yun Reviewed-by: Bin Meng --- drivers/usb/host/xhci-mem.c | 3 +-- drivers/usb/host/xhci-ring.c | 11 +++++------ include/usb/xhci.h | 1 - 3 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 1da0524aa0..d627aa5555 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -236,8 +236,7 @@ static void xhci_link_segments(struct xhci_segment *prev, */ val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control); val &= ~TRB_TYPE_BITMASK; - val |= (TRB_LINK << TRB_TYPE_SHIFT); - + val |= TRB_TYPE(TRB_LINK); prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val); } } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 3f915ae115..13c98fb09a 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -696,7 +696,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, trb_fields[0] = lower_32_bits(addr); trb_fields[1] = upper_32_bits(addr); trb_fields[2] = length_field; - trb_fields[3] = field | (TRB_NORMAL << TRB_TYPE_SHIFT); + trb_fields[3] = field | TRB_TYPE(TRB_NORMAL); queue_trb(ctrl, ring, (num_trbs > 1), trb_fields); @@ -823,7 +823,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, /* Queue setup TRB - see section 6.4.1.2.1 */ /* FIXME better way to translate setup_packet into two u32 fields? */ field = 0; - field |= TRB_IDT | (TRB_SETUP << TRB_TYPE_SHIFT); + field |= TRB_IDT | TRB_TYPE(TRB_SETUP); if (start_cycle == 0) field |= 0x1; @@ -860,9 +860,9 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, /* If there's data, queue data TRBs */ /* Only set interrupt on short packet for IN endpoints */ if (usb_pipein(pipe)) - field = TRB_ISP | (TRB_DATA << TRB_TYPE_SHIFT); + field = TRB_ISP | TRB_TYPE(TRB_DATA); else - field = (TRB_DATA << TRB_TYPE_SHIFT); + field = TRB_TYPE(TRB_DATA); remainder = xhci_td_remainder(ctrl, 0, length, length, usb_maxpacket(udev, pipe), true); @@ -904,8 +904,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, trb_fields[2] = ((0 & TRB_INTR_TARGET_MASK) << TRB_INTR_TARGET_SHIFT); /* Event on completion */ trb_fields[3] = field | TRB_IOC | - (TRB_STATUS << TRB_TYPE_SHIFT) | - ep_ring->cycle_state; + TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state; queue_trb(ctrl, ep_ring, false, trb_fields); diff --git a/include/usb/xhci.h b/include/usb/xhci.h index cf4c0208b2..bdba51df59 100644 --- a/include/usb/xhci.h +++ b/include/usb/xhci.h @@ -903,7 +903,6 @@ union xhci_trb { /* TRB bit mask */ #define TRB_TYPE_BITMASK (0xfc00) #define TRB_TYPE(p) ((p) << 10) -#define TRB_TYPE_SHIFT (10) #define TRB_FIELD_TO_TYPE(p) (((p) & TRB_TYPE_BITMASK) >> 10) /* TRB type IDs */ -- cgit v1.2.3 From 4312638eaf7f0bd29ffa8c7957bd51c5eb7d5a32 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 8 Sep 2020 19:00:00 +0200 Subject: usb: xhci: convert to TRB_LEN() and TRB_INTR_TARGET() For normal TRB fields: use TRB_LEN(x) instead of ((x) & TRB_LEN_MASK); and use TRB_INTR_TARGET(x) instead of (((x) & TRB_INTR_TARGET_MASK) << TRB_INTR_TARGET_SHIFT) Signed-off-by: Chunfeng Yun Reviewed-by: Bin Meng --- drivers/usb/host/xhci-ring.c | 16 +++++++--------- include/usb/xhci.h | 3 --- 2 files changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 13c98fb09a..9ef72efe95 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -688,10 +688,9 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, length, maxpacketsize, more_trbs_coming); - length_field = ((trb_buff_len & TRB_LEN_MASK) | + length_field = (TRB_LEN(trb_buff_len) | TRB_TD_SIZE(remainder) | - ((0 & TRB_INTR_TARGET_MASK) << - TRB_INTR_TARGET_SHIFT)); + TRB_INTR_TARGET(0)); trb_fields[0] = lower_32_bits(addr); trb_fields[1] = upper_32_bits(addr); @@ -849,8 +848,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, trb_fields[1] = le16_to_cpu(req->index) | le16_to_cpu(req->length) << 16; /* TRB_LEN | (TRB_INTR_TARGET) */ - trb_fields[2] = (8 | ((0 & TRB_INTR_TARGET_MASK) << - TRB_INTR_TARGET_SHIFT)); + trb_fields[2] = (TRB_LEN(8) | TRB_INTR_TARGET(0)); /* Immediate data in pointer */ trb_fields[3] = field; queue_trb(ctrl, ep_ring, true, trb_fields); @@ -866,11 +864,11 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, remainder = xhci_td_remainder(ctrl, 0, length, length, usb_maxpacket(udev, pipe), true); - length_field = (length & TRB_LEN_MASK) | TRB_TD_SIZE(remainder) | - ((0 & TRB_INTR_TARGET_MASK) << TRB_INTR_TARGET_SHIFT); + length_field = TRB_LEN(length) | TRB_TD_SIZE(remainder) | + TRB_INTR_TARGET(0); debug("length_field = %d, length = %d," "xhci_td_remainder(length) = %d , TRB_INTR_TARGET(0) = %d\n", - length_field, (length & TRB_LEN_MASK), + length_field, TRB_LEN(length), TRB_TD_SIZE(remainder), 0); if (length > 0) { @@ -901,7 +899,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, trb_fields[0] = 0; trb_fields[1] = 0; - trb_fields[2] = ((0 & TRB_INTR_TARGET_MASK) << TRB_INTR_TARGET_SHIFT); + trb_fields[2] = TRB_INTR_TARGET(0); /* Event on completion */ trb_fields[3] = field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state; diff --git a/include/usb/xhci.h b/include/usb/xhci.h index bdba51df59..35c66042ba 100644 --- a/include/usb/xhci.h +++ b/include/usb/xhci.h @@ -847,12 +847,9 @@ struct xhci_event_cmd { /* Normal TRB fields */ /* transfer_len bitmasks - bits 0:16 */ #define TRB_LEN(p) ((p) & 0x1ffff) -#define TRB_LEN_MASK (0x1ffff) /* TD Size, packets remaining in this TD, bits 21:17 (5 bits, so max 31) */ #define TRB_TD_SIZE(p) (min((p), (u32)31) << 17) /* Interrupter Target - which MSI-X vector to target the completion event at */ -#define TRB_INTR_TARGET_SHIFT (22) -#define TRB_INTR_TARGET_MASK (0x3ff) #define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22) #define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff) #define TRB_TBC(p) (((p) & 0x3) << 7) -- cgit v1.2.3 From bf58cf9ab1bf13654815d9db35d73c16d4651609 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 8 Sep 2020 19:00:01 +0200 Subject: usb: xhci: convert to TRB_TX_TYPE() Use TRB_TX_TYPE() instead of (TRB_DATA_OUT/IN << TRB_TX_TYPE_SHIFT) Signed-off-by: Chunfeng Yun Reviewed-by: Bin Meng --- drivers/usb/host/xhci-ring.c | 4 ++-- include/usb/xhci.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 9ef72efe95..b118207d93 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -830,9 +830,9 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, if (ctrl->hci_version >= 0x100 || ctrl->quirks & XHCI_MTK_HOST) { if (length > 0) { if (req->requesttype & USB_DIR_IN) - field |= (TRB_DATA_IN << TRB_TX_TYPE_SHIFT); + field |= TRB_TX_TYPE(TRB_DATA_IN); else - field |= (TRB_DATA_OUT << TRB_TX_TYPE_SHIFT); + field |= TRB_TX_TYPE(TRB_DATA_OUT); } } diff --git a/include/usb/xhci.h b/include/usb/xhci.h index 35c66042ba..07b1aebc69 100644 --- a/include/usb/xhci.h +++ b/include/usb/xhci.h @@ -879,7 +879,6 @@ struct xhci_event_cmd { /* Control transfer TRB specific fields */ #define TRB_DIR_IN (1<<16) #define TRB_TX_TYPE(p) ((p) << 16) -#define TRB_TX_TYPE_SHIFT (16) #define TRB_DATA_OUT 2 #define TRB_DATA_IN 3 -- cgit v1.2.3 From 23a54ccfb6da1c011c42359b2d20928617928902 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 8 Sep 2020 19:00:02 +0200 Subject: usb: xhci: use macros with parameter to fill ep_info2 Use macros with parameter to fill ep_info2, then some macros for MASK and SHIFT can be removed Signed-off-by: Chunfeng Yun Reviewed-by: Bin Meng --- drivers/usb/host/xhci-mem.c | 15 +++++---------- drivers/usb/host/xhci.c | 6 ++---- include/usb/xhci.h | 6 ------ 3 files changed, 7 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d627aa5555..0b49614995 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -825,25 +825,22 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, /* Step 4 - ring already allocated */ /* Step 5 */ - ep0_ctx->ep_info2 = cpu_to_le32(CTRL_EP << EP_TYPE_SHIFT); + ep0_ctx->ep_info2 = cpu_to_le32(EP_TYPE(CTRL_EP)); debug("SPEED = %d\n", speed); switch (speed) { case USB_SPEED_SUPER: - ep0_ctx->ep_info2 |= cpu_to_le32(((512 & MAX_PACKET_MASK) << - MAX_PACKET_SHIFT)); + ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(512)); debug("Setting Packet size = 512bytes\n"); break; case USB_SPEED_HIGH: /* USB core guesses at a 64-byte max packet first for FS devices */ case USB_SPEED_FULL: - ep0_ctx->ep_info2 |= cpu_to_le32(((64 & MAX_PACKET_MASK) << - MAX_PACKET_SHIFT)); + ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(64)); debug("Setting Packet size = 64bytes\n"); break; case USB_SPEED_LOW: - ep0_ctx->ep_info2 |= cpu_to_le32(((8 & MAX_PACKET_MASK) << - MAX_PACKET_SHIFT)); + ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(8)); debug("Setting Packet size = 8bytes\n"); break; default: @@ -852,9 +849,7 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, } /* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */ - ep0_ctx->ep_info2 |= - cpu_to_le32(((0 & MAX_BURST_MASK) << MAX_BURST_SHIFT) | - ((3 & ERROR_COUNT_MASK) << ERROR_COUNT_SHIFT)); + ep0_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(0) | ERROR_COUNT(3)); trb_64 = virt_to_phys(virt_dev->eps[0].ring->first_seg->trbs); ep0_ctx->deq = cpu_to_le64(trb_64 | virt_dev->eps[0].ring->cycle_state); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 5f3a0fba4b..fe30101d93 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -618,8 +618,7 @@ static int xhci_set_configuration(struct usb_device *udev) cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) | EP_INTERVAL(interval) | EP_MULT(mult)); - ep_ctx[ep_index]->ep_info2 = - cpu_to_le32(ep_type << EP_TYPE_SHIFT); + ep_ctx[ep_index]->ep_info2 = cpu_to_le32(EP_TYPE(ep_type)); ep_ctx[ep_index]->ep_info2 |= cpu_to_le32(MAX_PACKET (get_unaligned(&endpt_desc->wMaxPacketSize))); @@ -832,8 +831,7 @@ int xhci_check_maxpacket(struct usb_device *udev) ctrl->devs[slot_id]->out_ctx, ep_index); in_ctx = ctrl->devs[slot_id]->in_ctx; ep_ctx = xhci_get_ep_ctx(ctrl, in_ctx, ep_index); - ep_ctx->ep_info2 &= cpu_to_le32(~((0xffff & MAX_PACKET_MASK) - << MAX_PACKET_SHIFT)); + ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET(MAX_PACKET_MASK)); ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size)); /* diff --git a/include/usb/xhci.h b/include/usb/xhci.h index 07b1aebc69..e1d382369a 100644 --- a/include/usb/xhci.h +++ b/include/usb/xhci.h @@ -632,11 +632,8 @@ struct xhci_ep_ctx { */ #define FORCE_EVENT (0x1) #define ERROR_COUNT(p) (((p) & 0x3) << 1) -#define ERROR_COUNT_SHIFT (1) -#define ERROR_COUNT_MASK (0x3) #define CTX_TO_EP_TYPE(p) (((p) >> 3) & 0x7) #define EP_TYPE(p) ((p) << 3) -#define EP_TYPE_SHIFT (3) #define ISOC_OUT_EP 1 #define BULK_OUT_EP 2 #define INT_OUT_EP 3 @@ -647,13 +644,10 @@ struct xhci_ep_ctx { /* bit 6 reserved */ /* bit 7 is Host Initiate Disable - for disabling stream selection */ #define MAX_BURST(p) (((p)&0xff) << 8) -#define MAX_BURST_MASK (0xff) -#define MAX_BURST_SHIFT (8) #define CTX_TO_MAX_BURST(p) (((p) >> 8) & 0xff) #define MAX_PACKET(p) (((p)&0xffff) << 16) #define MAX_PACKET_MASK (0xffff) #define MAX_PACKET_DECODED(p) (((p) >> 16) & 0xffff) -#define MAX_PACKET_SHIFT (16) /* Get max packet size from ep desc. Bit 10..0 specify the max packet size. * USB2.0 spec 9.6.6. -- cgit v1.2.3 From a6837a0370ae656d87a7be34599d9afd7189f9db Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 8 Sep 2020 19:00:03 +0200 Subject: usb: xhci: convert to readx_poll_sleep_timeout() Use readx_poll_sleep_timeout() to poll the register status Signed-off-by: Chunfeng Yun Reviewed-by: Bin Meng --- drivers/usb/host/xhci.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index fe30101d93..3547a9bad1 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #ifndef CONFIG_USB_MAX_CONTROLLER_COUNT @@ -143,23 +144,19 @@ struct xhci_ctrl *xhci_get_ctrl(struct usb_device *udev) * @param usec time to wait till * @return 0 if handshake is success else < 0 on failure */ -static int handshake(uint32_t volatile *ptr, uint32_t mask, - uint32_t done, int usec) +static int +handshake(uint32_t volatile *ptr, uint32_t mask, uint32_t done, int usec) { uint32_t result; + int ret; + + ret = readx_poll_sleep_timeout(xhci_readl, ptr, result, + (result & mask) == done || result == U32_MAX, + 1, usec); + if (result == U32_MAX) /* card removed */ + return -ENODEV; - do { - result = xhci_readl(ptr); - if (result == ~(uint32_t)0) - return -ENODEV; - result &= mask; - if (result == done) - return 0; - usec--; - udelay(1); - } while (usec > 0); - - return -ETIMEDOUT; + return ret; } /** -- cgit v1.2.3 From e15e817f3eb13dd4b58f465b009164ecd8b997cf Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 21 Sep 2020 18:24:09 +0100 Subject: usb: xhci-rcar: Add support for R8A774A1 SoC The R8A774A1 is compatible with the generic rcar-gen3-xhci controller. This patch adds the compatibility flag, to support the xHCI controller. Signed-off-by: Lad Prabhakar Reviewed-by: Biju Das --- drivers/usb/host/xhci-rcar.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index 8fc51df3d1..5379dba566 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -146,6 +146,7 @@ static int xhci_rcar_ofdata_to_platdata(struct udevice *dev) } static const struct udevice_id xhci_rcar_ids[] = { + { .compatible = "renesas,rcar-gen3-xhci" }, { .compatible = "renesas,xhci-r8a7795" }, { .compatible = "renesas,xhci-r8a7796" }, { .compatible = "renesas,xhci-r8a77965" }, -- cgit v1.2.3 From f352c51f575e13a3117d8d5867cbe59fd6f2bd13 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 1 Oct 2020 14:51:58 -0400 Subject: Revert "net: smc911x: Automatically Update ethaddr with MAC" Upon further discussion on the mailing list, we should not get in the situation where the generic code path to set ethaddr/etc correctly does not work. Revert this until someone can further debug the smc911x driver regarding this issue. This reverts commit 387cbf096e443705fa66776027273ed257ec6ca3. Signed-off-by: Tom Rini --- drivers/net/smc911x.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 1fa3667b77..09372d7f6b 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include @@ -186,8 +185,6 @@ static void smc911x_handle_mac_address(struct smc911x_priv *priv) smc911x_set_mac_csr(priv, ADDRH, addrh); printf(DRIVERNAME ": MAC %pM\n", m); - if (!env_get("ethaddr")) - env_set("ethaddr", (const char *)m); } static bool smc911x_read_mac_address(struct smc911x_priv *priv) -- cgit v1.2.3 From 15c8cbfc7482c07db0ba5307f31ea2423399fba9 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 9 Sep 2020 18:28:33 +0200 Subject: gpio: stm32: cosmetic: cleanup gpio_stm32_probe Move the variables definition at the beggining of the function gpio_stm32_probe(). Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/gpio/stm32_gpio.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c index 5bff27f75b..aa70b1d2a9 100644 --- a/drivers/gpio/stm32_gpio.c +++ b/drivers/gpio/stm32_gpio.c @@ -273,9 +273,12 @@ static const struct dm_gpio_ops gpio_stm32_ops = { static int gpio_stm32_probe(struct udevice *dev) { struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct ofnode_phandle_args args; + const char *name; struct clk clk; fdt_addr_t addr; - int ret; + int ret, i; addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) @@ -283,11 +286,6 @@ static int gpio_stm32_probe(struct udevice *dev) priv->regs = (struct stm32_gpio_regs *)addr; - struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); - struct ofnode_phandle_args args; - const char *name; - int i; - name = dev_read_string(dev, "st,bank-name"); if (!name) return -EINVAL; -- cgit v1.2.3 From cb08e84d68ca64608fddb1ceec611f520e47b67e Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 9 Sep 2020 18:28:34 +0200 Subject: gpio: stm32: check result of ofnode_phandle_args Add test on the size of ofnode_phandle_args result to avoid access to uninitialized elements in args[] field. This patch avoids the issue when gpio-ranges cell size is not 3 as expected, for example: gpio-ranges = <&pinctrl 0>; instead of gpio-ranges = <&pinctrl 0 112 16>; Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/gpio/stm32_gpio.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c index aa70b1d2a9..473e364796 100644 --- a/drivers/gpio/stm32_gpio.c +++ b/drivers/gpio/stm32_gpio.c @@ -295,6 +295,9 @@ static int gpio_stm32_probe(struct udevice *dev) ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3, i, &args); + if (!ret && args.args_count < 3) + return -EINVAL; + if (ret == -ENOENT) { uc_priv->gpio_count = STM32_GPIOS_PER_BANK; priv->gpio_range = GENMASK(STM32_GPIOS_PER_BANK - 1, 0); @@ -308,6 +311,8 @@ static int gpio_stm32_probe(struct udevice *dev) ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3, ++i, &args); + if (!ret && args.args_count < 3) + return -EINVAL; } dev_dbg(dev, "addr = 0x%p bank_name = %s gpio_count = %d gpio_range = 0x%x\n", -- cgit v1.2.3 From d3bfad266c49aa826ddb0106bbf763f1ce9af9c4 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 9 Sep 2020 17:50:14 +0200 Subject: pinctrl: stm32: Convert to use APIs which support live DT Use ofnode_ or dev_ APIs instead of fdt_ and fdtdec_ APIs so that the driver can support live DT. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/pinctrl/pinctrl_stm32.c | 43 ++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index 71fa29a389..24ed83dd46 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -13,8 +13,6 @@ #include #include -DECLARE_GLOBAL_DATA_PTR; - #define MAX_PINS_ONE_IP 70 #define MODE_BITS_MASK 3 #define OSPEED_MASK 3 @@ -308,7 +306,8 @@ static int prep_gpio_dsc(struct stm32_gpio_dsc *gpio_dsc, u32 port_pin) return 0; } -static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn, int node) +static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn, + ofnode node) { gpio_fn &= 0x00FF; gpio_ctl->af = 0; @@ -329,16 +328,16 @@ static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn, int node) break; } - gpio_ctl->speed = fdtdec_get_int(gd->fdt_blob, node, "slew-rate", 0); + gpio_ctl->speed = ofnode_read_u32_default(node, "slew-rate", 0); - if (fdtdec_get_bool(gd->fdt_blob, node, "drive-open-drain")) + if (ofnode_read_bool(node, "drive-open-drain")) gpio_ctl->otype = STM32_GPIO_OTYPE_OD; else gpio_ctl->otype = STM32_GPIO_OTYPE_PP; - if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-up")) + if (ofnode_read_bool(node, "bias-pull-up")) gpio_ctl->pupd = STM32_GPIO_PUPD_UP; - else if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-down")) + else if (ofnode_read_bool(node, "bias-pull-down")) gpio_ctl->pupd = STM32_GPIO_PUPD_DOWN; else gpio_ctl->pupd = STM32_GPIO_PUPD_NO; @@ -350,32 +349,37 @@ static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn, int node) return 0; } -static int stm32_pinctrl_config(int offset) +static int stm32_pinctrl_config(ofnode node) { u32 pin_mux[MAX_PINS_ONE_IP]; int rv, len; + ofnode subnode; /* * check for "pinmux" property in each subnode (e.g. pins1 and pins2 for * usart1) of pin controller phandle "pinctrl-0" * */ - fdt_for_each_subnode(offset, gd->fdt_blob, offset) { + ofnode_for_each_subnode(subnode, node) { struct stm32_gpio_dsc gpio_dsc; struct stm32_gpio_ctl gpio_ctl; int i; - len = fdtdec_get_int_array_count(gd->fdt_blob, offset, - "pinmux", pin_mux, - ARRAY_SIZE(pin_mux)); + rv = ofnode_read_size(subnode, "pinmux"); + if (rv < 0) + return rv; + len = rv / sizeof(pin_mux[0]); debug("%s: no of pinmux entries= %d\n", __func__, len); - if (len < 0) + if (len > MAX_PINS_ONE_IP) return -EINVAL; + rv = ofnode_read_u32_array(subnode, "pinmux", pin_mux, len); + if (rv < 0) + return rv; for (i = 0; i < len; i++) { struct gpio_desc desc; debug("%s: pinmux = %x\n", __func__, *(pin_mux + i)); prep_gpio_dsc(&gpio_dsc, *(pin_mux + i)); - prep_gpio_ctl(&gpio_ctl, *(pin_mux + i), offset); + prep_gpio_ctl(&gpio_ctl, *(pin_mux + i), subnode); rv = uclass_get_device_by_seq(UCLASS_GPIO, gpio_dsc.port, &desc.dev); @@ -424,19 +428,18 @@ static int stm32_pinctrl_bind(struct udevice *dev) #if CONFIG_IS_ENABLED(PINCTRL_FULL) static int stm32_pinctrl_set_state(struct udevice *dev, struct udevice *config) { - return stm32_pinctrl_config(dev_of_offset(config)); + return stm32_pinctrl_config(dev_ofnode(config)); } #else /* PINCTRL_FULL */ static int stm32_pinctrl_set_state_simple(struct udevice *dev, struct udevice *periph) { - const void *fdt = gd->fdt_blob; const fdt32_t *list; uint32_t phandle; - int config_node; + ofnode config_node; int size, i, ret; - list = fdt_getprop(fdt, dev_of_offset(periph), "pinctrl-0", &size); + list = ofnode_get_property(dev_ofnode(periph), "pinctrl-0", &size); if (!list) return -EINVAL; @@ -446,8 +449,8 @@ static int stm32_pinctrl_set_state_simple(struct udevice *dev, for (i = 0; i < size; i++) { phandle = fdt32_to_cpu(*list++); - config_node = fdt_node_offset_by_phandle(fdt, phandle); - if (config_node < 0) { + config_node = ofnode_get_by_phandle(phandle); + if (!ofnode_valid(config_node)) { pr_err("prop pinctrl-0 index %d invalid phandle\n", i); return -EINVAL; } -- cgit v1.2.3 From 10bccd0dd3b91b27b752b48bbff6e725c8393467 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 9 Sep 2020 17:50:15 +0200 Subject: pinctrl: stm32: Add header with SPDX licence Cosmetics: Add header with SPDX licence Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/pinctrl/pinctrl_stm32.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index 24ed83dd46..dbea99532c 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017-2020 STMicroelectronics - All Rights Reserved + */ + #include #include #include -- cgit v1.2.3 From 28c6ba861c7aa8345e7266104776a4f259abe5b6 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 9 Sep 2020 17:44:12 +0200 Subject: video: stm32_ltdc: Convert to use APIs which support live DT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use ofnode_ or dev_ APIs instead of fdt_ and fdtdec_ APIs so that the driver can support live DT. Signed-off-by: Patrick Delaunay Reviewed-by: Yannick Fertré Reviewed-by: Patrice Chotard --- drivers/video/stm32/stm32_ltdc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/stm32/stm32_ltdc.c b/drivers/video/stm32/stm32_ltdc.c index 2f3427a32e..7fff735930 100644 --- a/drivers/video/stm32/stm32_ltdc.c +++ b/drivers/video/stm32/stm32_ltdc.c @@ -366,8 +366,7 @@ static int stm32_ltdc_probe(struct udevice *dev) ret = panel_get_display_timing(panel, &timings); if (ret) { - ret = fdtdec_decode_display_timing(gd->fdt_blob, - dev_of_offset(panel), + ret = ofnode_decode_display_timing(dev_ofnode(panel), 0, &timings); if (ret) { dev_err(dev, "decode display timing error %d\n", ret); -- cgit v1.2.3 From a04616be1b56512e407a86bade58c3e6cd948be0 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 9 Sep 2020 17:44:13 +0200 Subject: video: stm32_dsi: Convert to use APIs which support live DT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use ofnode_ or dev_ APIs instead of fdt_ and fdtdec_ APIs so that the driver can support live DT. Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass Reviewed-by: Yannick Fertré --- drivers/video/stm32/stm32_dsi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/stm32/stm32_dsi.c b/drivers/video/stm32/stm32_dsi.c index 283151398b..9d5abacc2b 100644 --- a/drivers/video/stm32/stm32_dsi.c +++ b/drivers/video/stm32/stm32_dsi.c @@ -359,8 +359,7 @@ static int stm32_dsi_attach(struct udevice *dev) ret = panel_get_display_timing(priv->panel, &timings); if (ret) { - ret = fdtdec_decode_display_timing(gd->fdt_blob, - dev_of_offset(priv->panel), + ret = ofnode_decode_display_timing(dev_ofnode(priv->panel), 0, &timings); if (ret) { dev_err(dev, "decode display timing error %d\n", ret); -- cgit v1.2.3 From 04e29ca5bbb82f15d7a32d4130214c6a15db69aa Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Wed, 9 Sep 2020 17:48:15 +0200 Subject: mailbox: stm32_ipcc: Convert to use APIs which support live DT Use ofnode_ or dev_ APIs instead of fdt_ and fdtdec_ APIs so that the driver can support live DT. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/mailbox/stm32-ipcc.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c index b8bf356b4a..81a4115986 100644 --- a/drivers/mailbox/stm32-ipcc.c +++ b/drivers/mailbox/stm32-ipcc.c @@ -101,9 +101,8 @@ static int stm32_ipcc_probe(struct udevice *dev) { struct stm32_ipcc *ipcc = dev_get_priv(dev); fdt_addr_t addr; - const fdt32_t *cell; struct clk clk; - int len, ret; + int ret; debug("%s(dev=%p)\n", __func__, dev); @@ -114,14 +113,12 @@ static int stm32_ipcc_probe(struct udevice *dev) ipcc->reg_base = (void __iomem *)addr; /* proc_id */ - cell = dev_read_prop(dev, "st,proc_id", &len); - if (len < sizeof(fdt32_t)) { + ret = dev_read_u32_index(dev, "st,proc_id", 1, &ipcc->proc_id); + if (ret) { dev_dbg(dev, "Missing st,proc_id\n"); return -EINVAL; } - ipcc->proc_id = fdtdec_get_number(cell, 1); - if (ipcc->proc_id >= STM32_MAX_PROCS) { dev_err(dev, "Invalid proc_id (%d)\n", ipcc->proc_id); return -EINVAL; -- cgit v1.2.3 From bab9be9e0de733e9c063d1b9b7284be484cd64df Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Tue, 29 Sep 2020 20:27:11 +0300 Subject: pinctrl: bcm283x: DM_FLAG_PRE_RELOC: Remove OF_CONTROL check Remove CONFIG_IS_ENABLED(OF_CONTROL) check from DM_FLAG_PRE_RELOC, since this driver only supports OF_CONTROL. drivers/pinctrl/broadcom/Kconfig: config PINCTRL_BCM283X depends on ARCH_BCM283X && PINCTRL_FULL && OF_CONTROL Cc: Matthias Brugger Signed-off-by: Ovidiu Panait Signed-off-by: Matthias Brugger --- drivers/pinctrl/broadcom/pinctrl-bcm283x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/broadcom/pinctrl-bcm283x.c b/drivers/pinctrl/broadcom/pinctrl-bcm283x.c index c22d534da9..9eaf56a390 100644 --- a/drivers/pinctrl/broadcom/pinctrl-bcm283x.c +++ b/drivers/pinctrl/broadcom/pinctrl-bcm283x.c @@ -150,7 +150,7 @@ U_BOOT_DRIVER(pinctrl_bcm283x) = { .priv_auto_alloc_size = sizeof(struct bcm283x_pinctrl_priv), .ops = &bcm283x_pinctrl_ops, .probe = bcm283x_pinctl_probe, -#if !CONFIG_IS_ENABLED(OF_CONTROL) || CONFIG_IS_ENABLED(OF_BOARD) +#if CONFIG_IS_ENABLED(OF_BOARD) .flags = DM_FLAG_PRE_RELOC, #endif }; -- cgit v1.2.3 From e020c07a020000d9b9cbba8ea56109b37c3926c6 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Tue, 29 Sep 2020 20:27:12 +0300 Subject: pinctrl: bcm283x: Read address from DT in ofdata_to_platdata Factor out reading IP base address to ofdata_to_platdata function, which is designed for this purpose. Also, drop the dev->priv NULL check, since this is already done by the dm core when allocating space using priv_auto_alloc_size feature. (in drivers/core/device.c -> device_ofdata_to_platdata). Cc: Matthias Brugger Signed-off-by: Ovidiu Panait Signed-off-by: Matthias Brugger --- drivers/pinctrl/broadcom/pinctrl-bcm283x.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/broadcom/pinctrl-bcm283x.c b/drivers/pinctrl/broadcom/pinctrl-bcm283x.c index 9eaf56a390..49791c5962 100644 --- a/drivers/pinctrl/broadcom/pinctrl-bcm283x.c +++ b/drivers/pinctrl/broadcom/pinctrl-bcm283x.c @@ -104,17 +104,11 @@ static const struct udevice_id bcm2835_pinctrl_id[] = { {} }; -int bcm283x_pinctl_probe(struct udevice *dev) +int bcm283x_pinctl_ofdata_to_platdata(struct udevice *dev) { struct bcm283x_pinctrl_priv *priv; - int ret; - struct udevice *pdev; priv = dev_get_priv(dev); - if (!priv) { - debug("%s: Failed to get private\n", __func__); - return -EINVAL; - } priv->base_reg = dev_read_addr_ptr(dev); if (!priv->base_reg) { @@ -122,6 +116,14 @@ int bcm283x_pinctl_probe(struct udevice *dev) return -EINVAL; } + return 0; +} + +int bcm283x_pinctl_probe(struct udevice *dev) +{ + int ret; + struct udevice *pdev; + /* Create GPIO device as well */ ret = device_bind(dev, lists_driver_lookup_name("gpio_bcm2835"), "gpio_bcm2835", NULL, dev_of_offset(dev), &pdev); @@ -147,6 +149,7 @@ U_BOOT_DRIVER(pinctrl_bcm283x) = { .name = "bcm283x_pinctrl", .id = UCLASS_PINCTRL, .of_match = of_match_ptr(bcm2835_pinctrl_id), + .ofdata_to_platdata = bcm283x_pinctl_ofdata_to_platdata, .priv_auto_alloc_size = sizeof(struct bcm283x_pinctrl_priv), .ops = &bcm283x_pinctrl_ops, .probe = bcm283x_pinctl_probe, -- cgit v1.2.3 From 0db912de153743e2ec97bd022640c5722eb07737 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Tue, 29 Sep 2020 20:27:13 +0300 Subject: pinctrl: bcm283x: Store the return value of dev_read_u32_default to int Currently, the return value of dev_read_u32_default is stored in an u32, causing the subsequent "if (function < 0)" to always be false: u32 function; ... function = dev_read_u32_default(config, "brcm,function", -1); if (function < 0) { debug("Failed reading function for pinconfig %s (%d)\n", config->name, function); return -EINVAL; } Make "function" variable an int to fix this. Cc: Matthias Brugger Signed-off-by: Ovidiu Panait Signed-off-by: Matthias Brugger --- drivers/pinctrl/broadcom/pinctrl-bcm283x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/broadcom/pinctrl-bcm283x.c b/drivers/pinctrl/broadcom/pinctrl-bcm283x.c index 49791c5962..41da814123 100644 --- a/drivers/pinctrl/broadcom/pinctrl-bcm283x.c +++ b/drivers/pinctrl/broadcom/pinctrl-bcm283x.c @@ -63,7 +63,7 @@ static int bcm2835_gpio_get_func_id(struct udevice *dev, unsigned int gpio) int bcm283x_pinctrl_set_state(struct udevice *dev, struct udevice *config) { u32 pin_arr[MAX_PINS_PER_BANK]; - u32 function; + int function; int i, len, pin_count = 0; if (!dev_read_prop(config, "brcm,pins", &len) || !len || -- cgit v1.2.3 From 01c35f269f21398fa9d1db1b90b73f7e95a3bf22 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 1 Oct 2020 13:27:25 +0300 Subject: 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 (limited to 'drivers') 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, +}; -- cgit v1.2.3