From 8bd9e2f631a27791b3088e34fb9180e6e120d040 Mon Sep 17 00:00:00 2001 From: Sai Krishna Potthuri Date: Mon, 28 Feb 2022 15:59:29 +0100 Subject: [PATCH 01/21] arm64: zynqmp: Add resets property to sdhci nodes Add "resets" property to sdhci nodes. resets property is used to reset the SD host controller when dynamic configuration support is enabled. Signed-off-by: Sai Krishna Potthuri Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/f1fe39259c45a37aae56c2835ee8ba187c889d25.1646060367.git.michal.simek@xilinx.com --- arch/arm/dts/zynqmp.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/dts/zynqmp.dtsi b/arch/arm/dts/zynqmp.dtsi index 755a4ed2e51..c4426088502 100644 --- a/arch/arm/dts/zynqmp.dtsi +++ b/arch/arm/dts/zynqmp.dtsi @@ -742,6 +742,7 @@ #clock-cells = <1>; clock-output-names = "clk_out_sd0", "clk_in_sd0"; power-domains = <&zynqmp_firmware PD_SD_0>; + resets = <&zynqmp_reset ZYNQMP_RESET_SDIO0>; }; sdhci1: mmc@ff170000 { @@ -758,6 +759,7 @@ #clock-cells = <1>; clock-output-names = "clk_out_sd1", "clk_in_sd1"; power-domains = <&zynqmp_firmware PD_SD_1>; + resets = <&zynqmp_reset ZYNQMP_RESET_SDIO1>; }; smmu: iommu@fd800000 { From f307c688ea951978ebcceb5536aa31c0249b33df Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 28 Feb 2022 17:13:15 +0100 Subject: [PATCH 02/21] firmware: zynqmp: Do not bind PD driver in SPL if disabled Change if condition to cover SPL flow. SPL needs to have CONFIG_SPL_POWER_DOMAIN enabled to be able to bind CONFIG_ZYNQMP_POWER_DOMAIN driver. Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/8e1d381013a0ce39d736da166d2b401c4b12d38a.1646064792.git.michal.simek@xilinx.com --- drivers/firmware/firmware-zynqmp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index 8916c558963..78da5abc5d3 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -334,7 +334,11 @@ static int zynqmp_firmware_bind(struct udevice *dev) int ret; struct udevice *child; - if (IS_ENABLED(CONFIG_ZYNQMP_POWER_DOMAIN)) { + if ((IS_ENABLED(CONFIG_SPL_BUILD) && + IS_ENABLED(CONFIG_SPL_POWER_DOMAIN) && + IS_ENABLED(CONFIG_ZYNQMP_POWER_DOMAIN)) || + (!IS_ENABLED(CONFIG_SPL_BUILD) && + IS_ENABLED(CONFIG_ZYNQMP_POWER_DOMAIN))) { ret = device_bind_driver_to_node(dev, "zynqmp_power_domain", "zynqmp_power_domain", dev_ofnode(dev), &child); From f66d0b53462cdd209ec045c8dcf623046fa4f3cc Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 17 Mar 2022 15:25:31 +0100 Subject: [PATCH 03/21] arm64: versal: Do not place u-boot to reserved memory location Versal can also have reserved space in DT which u-boot has to avoid to placing self to that location. The same change was done in ZynqMP by commit ce39ee28ec31 ("zynqmp: Do not place u-boot to reserved memory location") and also for microblaze by commit d7b5cc89d329 ("microblaze: Do not place u-boot to reserved memory location"). The patch was tested by adding reserved-memory node to DT and check via bdinfo back. Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/15426fa6d64835dd23c5c8c12bbfc97306fb6098.1647527129.git.michal.simek@xilinx.com --- board/xilinx/versal/board.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/board/xilinx/versal/board.c b/board/xilinx/versal/board.c index 299e128f7b9..9940f2aeb33 100644 --- a/board/xilinx/versal/board.c +++ b/board/xilinx/versal/board.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -249,6 +250,25 @@ int dram_init(void) return 0; } +ulong board_get_usable_ram_top(ulong total_size) +{ + phys_size_t size; + phys_addr_t reg; + struct lmb lmb; + + /* found enough not-reserved memory to relocated U-Boot */ + lmb_init(&lmb); + lmb_add(&lmb, gd->ram_base, gd->ram_size); + boot_fdt_add_mem_rsv_regions(&lmb, (void *)gd->fdt_blob); + size = ALIGN(CONFIG_SYS_MALLOC_LEN + total_size, MMU_SECTION_SIZE); + reg = lmb_alloc(&lmb, size, MMU_SECTION_SIZE); + + if (!reg) + reg = gd->ram_top - size; + + return reg + size; +} + void reset_cpu(void) { } From 7ce9d921bd560d00a601bd751ced32f71f9bbd28 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 24 Mar 2022 10:17:51 +0100 Subject: [PATCH 04/21] dt-bindings: phy: Sync phy.h with Linux kernel Make sure that both files are in sync to have the same values in DTs. The patch is fixing SPDX license as is used in the kernel and adding new values for PHY_TYPE_DPHY and PHY_TYPE_CPHY. SPDX license change was done by: Link: https://lkml.kernel.org/r/20190528170027.447718015@linutronix.de and new value added by: Link: https://lore.kernel.org/r/20210617144349.28448-3-jonathan@marek.ca Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/06dbc03d4c9ac5d621341d8fb8cc16f489062b39.1648113469.git.michal.simek@xilinx.com --- include/dt-bindings/phy/phy.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h index d3714edd4bd..f48c9acf251 100644 --- a/include/dt-bindings/phy/phy.h +++ b/include/dt-bindings/phy/phy.h @@ -1,10 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * * This header provides constants for the phy framework * * Copyright (C) 2014 STMicroelectronics * Author: Gabriel Fernandez - * License terms: GNU General Public License (GPL), version 2 */ #ifndef _DT_BINDINGS_PHY @@ -20,5 +20,7 @@ #define PHY_TYPE_XPCS 7 #define PHY_TYPE_SGMII 8 #define PHY_TYPE_QSGMII 9 +#define PHY_TYPE_DPHY 10 +#define PHY_TYPE_CPHY 11 #endif /* _DT_BINDINGS_PHY */ From 0302a207c3129ff50c590fafe8bc46dfb4dbeac5 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 24 Mar 2022 13:31:26 +0100 Subject: [PATCH 05/21] arm64: zynqmp: Remove low level UART setting cont There is no reason to do serial initialization. Uart driver does it already based on DT. Good effect is that it is clear which interface is console. The same change was done in past by commit 84d2bbf082fa ("arm64: zynqmp: Remove low level UART setting"). Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/91a73f292bafc4b64ed09954cc23780496da4b65.1648125082.git.michal.simek@xilinx.com --- board/xilinx/zynqmp/zynqmp-dlc21-revA/psu_init_gpl.c | 4 ---- board/xilinx/zynqmp/zynqmp-e-a2197-00-revA/psu_init_gpl.c | 4 ---- .../zynqmp-topic-miamimp-xilinx-xdp-v1r1/psu_init_gpl.c | 8 -------- board/xilinx/zynqmp/zynqmp-zcu102-rev1.1/psu_init_gpl.c | 8 -------- board/xilinx/zynqmp/zynqmp-zcu111-revA/psu_init_gpl.c | 8 -------- board/xilinx/zynqmp/zynqmp-zcu208-revA/psu_init_gpl.c | 4 ---- board/xilinx/zynqmp/zynqmp-zcu216-revA/psu_init_gpl.c | 4 ---- 7 files changed, 40 deletions(-) diff --git a/board/xilinx/zynqmp/zynqmp-dlc21-revA/psu_init_gpl.c b/board/xilinx/zynqmp/zynqmp-dlc21-revA/psu_init_gpl.c index 528958d83ed..dae81e60ccb 100644 --- a/board/xilinx/zynqmp/zynqmp-dlc21-revA/psu_init_gpl.c +++ b/board/xilinx/zynqmp/zynqmp-dlc21-revA/psu_init_gpl.c @@ -509,10 +509,6 @@ static unsigned long psu_peripherals_init_data(void) psu_mask_write(0xFF5E0238, 0x00000008U, 0x00000000U); psu_mask_write(0xFF5E0238, 0x00007800U, 0x00000000U); psu_mask_write(0xFF5E0238, 0x00000002U, 0x00000000U); - psu_mask_write(0xFF000034, 0x000000FFU, 0x00000005U); - psu_mask_write(0xFF000018, 0x0000FFFFU, 0x0000008FU); - psu_mask_write(0xFF000000, 0x000001FFU, 0x00000017U); - psu_mask_write(0xFF000004, 0x000003FFU, 0x00000020U); psu_mask_write(0xFF5E0238, 0x00040000U, 0x00000000U); psu_mask_write(0xFF4B0024, 0x000000FFU, 0x000000FFU); psu_mask_write(0xFFCA5000, 0x00001FFFU, 0x00000000U); diff --git a/board/xilinx/zynqmp/zynqmp-e-a2197-00-revA/psu_init_gpl.c b/board/xilinx/zynqmp/zynqmp-e-a2197-00-revA/psu_init_gpl.c index 348f0e7789a..40d9279378b 100644 --- a/board/xilinx/zynqmp/zynqmp-e-a2197-00-revA/psu_init_gpl.c +++ b/board/xilinx/zynqmp/zynqmp-e-a2197-00-revA/psu_init_gpl.c @@ -521,10 +521,6 @@ static unsigned long psu_peripherals_init_data(void) psu_mask_write(0xFF180324, 0x03C00000U, 0x00000000U); psu_mask_write(0xFF5E0238, 0x00000600U, 0x00000000U); psu_mask_write(0xFF5E0238, 0x00000002U, 0x00000000U); - psu_mask_write(0xFF000034, 0x000000FFU, 0x00000006U); - psu_mask_write(0xFF000018, 0x0000FFFFU, 0x0000007CU); - psu_mask_write(0xFF000000, 0x000001FFU, 0x00000017U); - psu_mask_write(0xFF000004, 0x000003FFU, 0x00000020U); psu_mask_write(0xFF5E0238, 0x00040000U, 0x00000000U); psu_mask_write(0xFF4B0024, 0x000000FFU, 0x000000FFU); psu_mask_write(0xFFCA5000, 0x00001FFFU, 0x00000000U); diff --git a/board/xilinx/zynqmp/zynqmp-topic-miamimp-xilinx-xdp-v1r1/psu_init_gpl.c b/board/xilinx/zynqmp/zynqmp-topic-miamimp-xilinx-xdp-v1r1/psu_init_gpl.c index dbed7b789e3..333510bfe92 100644 --- a/board/xilinx/zynqmp/zynqmp-topic-miamimp-xilinx-xdp-v1r1/psu_init_gpl.c +++ b/board/xilinx/zynqmp/zynqmp-topic-miamimp-xilinx-xdp-v1r1/psu_init_gpl.c @@ -522,14 +522,6 @@ static unsigned long psu_peripherals_init_data(void) psu_mask_write(0xFF5E0238, 0x00000018U, 0x00000000U); psu_mask_write(0xFF5E0238, 0x00007800U, 0x00000000U); psu_mask_write(0xFF5E0238, 0x00000006U, 0x00000000U); - psu_mask_write(0xFF000034, 0x000000FFU, 0x00000005U); - psu_mask_write(0xFF000018, 0x0000FFFFU, 0x0000008FU); - psu_mask_write(0xFF000000, 0x000001FFU, 0x00000017U); - psu_mask_write(0xFF000004, 0x000003FFU, 0x00000020U); - psu_mask_write(0xFF010034, 0x000000FFU, 0x00000005U); - psu_mask_write(0xFF010018, 0x0000FFFFU, 0x0000008FU); - psu_mask_write(0xFF010000, 0x000001FFU, 0x00000017U); - psu_mask_write(0xFF010004, 0x000003FFU, 0x00000020U); psu_mask_write(0xFF5E0238, 0x00040000U, 0x00000000U); psu_mask_write(0xFF4B0024, 0x000000FFU, 0x000000FFU); psu_mask_write(0xFFCA5000, 0x00001FFFU, 0x00000000U); diff --git a/board/xilinx/zynqmp/zynqmp-zcu102-rev1.1/psu_init_gpl.c b/board/xilinx/zynqmp/zynqmp-zcu102-rev1.1/psu_init_gpl.c index 1f3f2e66b95..f1fdc7dad1a 100644 --- a/board/xilinx/zynqmp/zynqmp-zcu102-rev1.1/psu_init_gpl.c +++ b/board/xilinx/zynqmp/zynqmp-zcu102-rev1.1/psu_init_gpl.c @@ -516,14 +516,6 @@ static unsigned long psu_peripherals_init_data(void) psu_mask_write(0xFF5E0238, 0x00008000U, 0x00000000U); psu_mask_write(0xFF5E0238, 0x00007800U, 0x00000000U); psu_mask_write(0xFF5E0238, 0x00000006U, 0x00000000U); - psu_mask_write(0xFF000034, 0x000000FFU, 0x0000000CU); - psu_mask_write(0xFF000018, 0x0000FFFFU, 0x0000003EU); - psu_mask_write(0xFF000000, 0x000001FFU, 0x00000017U); - psu_mask_write(0xFF000004, 0x000003FFU, 0x00000020U); - psu_mask_write(0xFF010034, 0x000000FFU, 0x0000000CU); - psu_mask_write(0xFF010018, 0x0000FFFFU, 0x0000003EU); - psu_mask_write(0xFF010000, 0x000001FFU, 0x00000017U); - psu_mask_write(0xFF010004, 0x000003FFU, 0x00000020U); psu_mask_write(0xFF5E0238, 0x00040000U, 0x00000000U); psu_mask_write(0xFF4B0024, 0x000000FFU, 0x000000FFU); psu_mask_write(0xFFCA5000, 0x00001FFFU, 0x00000000U); diff --git a/board/xilinx/zynqmp/zynqmp-zcu111-revA/psu_init_gpl.c b/board/xilinx/zynqmp/zynqmp-zcu111-revA/psu_init_gpl.c index 7c6664dc988..8963aa4a073 100644 --- a/board/xilinx/zynqmp/zynqmp-zcu111-revA/psu_init_gpl.c +++ b/board/xilinx/zynqmp/zynqmp-zcu111-revA/psu_init_gpl.c @@ -512,14 +512,6 @@ static unsigned long psu_peripherals_init_data(void) psu_mask_write(0xFF5E0238, 0x00008000U, 0x00000000U); psu_mask_write(0xFF5E0238, 0x00007800U, 0x00000000U); psu_mask_write(0xFF5E0238, 0x00000006U, 0x00000000U); - psu_mask_write(0xFF000034, 0x000000FFU, 0x00000005U); - psu_mask_write(0xFF000018, 0x0000FFFFU, 0x0000008FU); - psu_mask_write(0xFF000000, 0x000001FFU, 0x00000017U); - psu_mask_write(0xFF000004, 0x000003FFU, 0x00000020U); - psu_mask_write(0xFF010034, 0x000000FFU, 0x00000005U); - psu_mask_write(0xFF010018, 0x0000FFFFU, 0x0000008FU); - psu_mask_write(0xFF010000, 0x000001FFU, 0x00000017U); - psu_mask_write(0xFF010004, 0x000003FFU, 0x00000020U); psu_mask_write(0xFF5E0238, 0x00040000U, 0x00000000U); psu_mask_write(0xFF4B0024, 0x000000FFU, 0x000000FFU); psu_mask_write(0xFFCA5000, 0x00001FFFU, 0x00000000U); diff --git a/board/xilinx/zynqmp/zynqmp-zcu208-revA/psu_init_gpl.c b/board/xilinx/zynqmp/zynqmp-zcu208-revA/psu_init_gpl.c index f07e60abb86..2adcad04d86 100644 --- a/board/xilinx/zynqmp/zynqmp-zcu208-revA/psu_init_gpl.c +++ b/board/xilinx/zynqmp/zynqmp-zcu208-revA/psu_init_gpl.c @@ -513,10 +513,6 @@ static unsigned long psu_peripherals_init_data(void) psu_mask_write(0xFF5E0238, 0x00008000U, 0x00000000U); psu_mask_write(0xFF5E0238, 0x00007800U, 0x00000000U); psu_mask_write(0xFF5E0238, 0x00000002U, 0x00000000U); - psu_mask_write(0xFF000034, 0x000000FFU, 0x00000006U); - psu_mask_write(0xFF000018, 0x0000FFFFU, 0x0000007CU); - psu_mask_write(0xFF000000, 0x000001FFU, 0x00000017U); - psu_mask_write(0xFF000004, 0x000003FFU, 0x00000020U); psu_mask_write(0xFF5E0238, 0x00040000U, 0x00000000U); psu_mask_write(0xFF4B0024, 0x000000FFU, 0x000000FFU); psu_mask_write(0xFFCA5000, 0x00001FFFU, 0x00000000U); diff --git a/board/xilinx/zynqmp/zynqmp-zcu216-revA/psu_init_gpl.c b/board/xilinx/zynqmp/zynqmp-zcu216-revA/psu_init_gpl.c index fc3605d602e..bd316872eb3 100644 --- a/board/xilinx/zynqmp/zynqmp-zcu216-revA/psu_init_gpl.c +++ b/board/xilinx/zynqmp/zynqmp-zcu216-revA/psu_init_gpl.c @@ -513,10 +513,6 @@ static unsigned long psu_peripherals_init_data(void) psu_mask_write(0xFF5E0238, 0x00008000U, 0x00000000U); psu_mask_write(0xFF5E0238, 0x00007800U, 0x00000000U); psu_mask_write(0xFF5E0238, 0x00000002U, 0x00000000U); - psu_mask_write(0xFF000034, 0x000000FFU, 0x00000006U); - psu_mask_write(0xFF000018, 0x0000FFFFU, 0x0000007CU); - psu_mask_write(0xFF000000, 0x000001FFU, 0x00000017U); - psu_mask_write(0xFF000004, 0x000003FFU, 0x00000020U); psu_mask_write(0xFF5E0238, 0x00040000U, 0x00000000U); psu_mask_write(0xFF4B0024, 0x000000FFU, 0x000000FFU); psu_mask_write(0xFFCA5000, 0x00001FFFU, 0x00000000U); From cbeba3515208c9e8db3dba3d5af5ec838c1065b3 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 25 Mar 2022 11:50:07 +0100 Subject: [PATCH 06/21] serial: zynq: Change fifo behavior in debug mode Serial IP has output buffer which status is indicated by two bits. If fifo if empty or full. Default configuration is that chars are pushed to fifo till it is full. Time to time it is visible that chars are scambled and logs are not visible. Not sure what it is exactly happening but all the time it helps to change driver behavior to write only one char at a time. That's why enable this mode when debug uart is enabled not to see scrambled chars in debug by default. Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/332b2106d7a8190dd1001b5387f8bd1fba2e061b.1648205405.git.michal.simek@xilinx.com --- drivers/serial/serial_zynq.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/serial/serial_zynq.c b/drivers/serial/serial_zynq.c index fd999368ab7..6bb003dc155 100644 --- a/drivers/serial/serial_zynq.c +++ b/drivers/serial/serial_zynq.c @@ -21,6 +21,7 @@ #define ZYNQ_UART_SR_TXACTIVE BIT(11) /* TX active */ #define ZYNQ_UART_SR_TXFULL BIT(4) /* TX FIFO full */ +#define ZYNQ_UART_SR_TXEMPTY BIT(3) /* TX FIFO empty */ #define ZYNQ_UART_SR_RXEMPTY BIT(1) /* RX FIFO empty */ #define ZYNQ_UART_CR_TX_EN BIT(4) /* TX enabled */ @@ -107,8 +108,13 @@ static void _uart_zynq_serial_init(struct uart_zynq *regs) static int _uart_zynq_serial_putc(struct uart_zynq *regs, const char c) { - if (readl(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) - return -EAGAIN; + if (CONFIG_IS_ENABLED(DEBUG_UART_ZYNQ)) { + if (!(readl(®s->channel_sts) & ZYNQ_UART_SR_TXEMPTY)) + return -EAGAIN; + } else { + if (readl(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) + return -EAGAIN; + } writel(c, ®s->tx_rx_fifo); From 035d56f2386e009aaa41cd75022f8cddc04e5c1a Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Fri, 25 Mar 2022 13:11:10 +0100 Subject: [PATCH 07/21] mmc: zynq_sdhci: Fix SDx_BASECLK configuration The DLL mode supported SD reference clocks are 50 MHz, 100 MHz and 200 MHz. When user select SD frequency as 200MHz in the design, the actual frequency is going to come around ~187MHz (<= 200MHz considering the parent clock and divisor selection). We need to set SDx_BASECLK as 200 in this case, setting 187 will result in tuning failures in mmc. Set SDx_BASECLK to exact value of 200, 100 or 50 based on the frequency range. Signed-off-by: Ashok Reddy Soma Signed-off-by: Michal Simek Reviewed-by: Jaehoon Chung Link: https://lore.kernel.org/r/6c1e5eeeedd2864a0c85e6b409d182031d8c6c1a.1648210268.git.michal.simek@xilinx.com --- drivers/mmc/zynq_sdhci.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index d96f5d543f5..a59d96c6bda 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -765,6 +765,15 @@ static int sdhci_zynqmp_set_dynamic_config(struct arasan_sdhci_priv *priv, mhz = DIV64_U64_ROUND_UP(clock, 1000000); + if (mhz > 100 && mhz <= 200) + mhz = 200; + else if (mhz > 50 && mhz <= 100) + mhz = 100; + else if (mhz > 25 && mhz <= 50) + mhz = 50; + else + mhz = 25; + ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_BASECLK, mhz); if (ret) { dev_err(dev, "SD_CONFIG_BASECLK failed\n"); From dcbdd24259beaff903e7ffffde646a3c5bd756ac Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 15 Oct 2021 15:17:28 +0200 Subject: [PATCH 08/21] timer: cadence: Add bind function to driver When DT node has pwm-cells property it shouldn't be bind as timer driver but as PWM driver. That's why make sure that this property is checked. Signed-off-by: Michal Simek Reviewed-by: Sean Anderson Reviewed-by: Simon Glass Link: https://lore.kernel.org/r/434ef195fbedea9f83672a12d1ace0da16e8832e.1634303847.git.michal.simek@xilinx.com --- drivers/timer/cadence-ttc.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/timer/cadence-ttc.c b/drivers/timer/cadence-ttc.c index 2f95d45ecd7..2eff45060ad 100644 --- a/drivers/timer/cadence-ttc.c +++ b/drivers/timer/cadence-ttc.c @@ -97,6 +97,17 @@ static int cadence_ttc_of_to_plat(struct udevice *dev) return 0; } +static int cadence_ttc_bind(struct udevice *dev) +{ + const char *cells; + + cells = dev_read_prop(dev, "#pwm-cells", NULL); + if (cells) + return -ENODEV; + + return 0; +} + static const struct timer_ops cadence_ttc_ops = { .get_count = cadence_ttc_get_count, }; @@ -114,4 +125,5 @@ U_BOOT_DRIVER(cadence_ttc) = { .priv_auto = sizeof(struct cadence_ttc_priv), .probe = cadence_ttc_probe, .ops = &cadence_ttc_ops, + .bind = cadence_ttc_bind, }; From fb92cc2c17724d66a32f7a033608a1bd2176a478 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 15 Oct 2021 15:17:29 +0200 Subject: [PATCH 09/21] pwm: Add driver for cadence TTC TTC has three modes of operations. Timer, PWM and input counters. There is already driver for timer under CADENCE_TTC_TIMER which is used for ZynqMP R5 configuration. This driver is targeting PWM which is for example configuration which can be used for fan control. The driver has been tested on Xilinx Kria SOM platform where fan is connected to one PL pin. When TTC output is connected via EMIO to PL pin TTC pwm can be configured and tested for example like this: pwm config 0 0 10000 1200 pwm enable 0 0 pwm config 0 0 10000 1400 pwm config 0 0 10000 1600 Signed-off-by: Michal Simek Reviewed-by: Sean Anderson Link: https://lore.kernel.org/r/915a662ddb88f7a958ca1f307e8fea59af9d7feb.1634303847.git.michal.simek@xilinx.com --- MAINTAINERS | 1 + drivers/pwm/Kconfig | 7 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-cadence-ttc.c | 261 ++++++++++++++++++++++++++++++++++ 4 files changed, 270 insertions(+) create mode 100644 drivers/pwm/pwm-cadence-ttc.c diff --git a/MAINTAINERS b/MAINTAINERS index 74d5263fb1a..36044f6d8f9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -655,6 +655,7 @@ F: drivers/net/phy/xilinx_phy.c F: drivers/net/zynq_gem.c F: drivers/phy/phy-zynqmp.c F: drivers/power/domain/zynqmp-power-domain.c +F: drivers/pwm/pwm-cadence-ttc.c F: drivers/serial/serial_zynq.c F: drivers/reset/reset-zynqmp.c F: drivers/rtc/zynqmp_rtc.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 6be612d58a9..cb54e67faeb 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -23,6 +23,13 @@ config PWM_AT91 help Support for PWM hardware on AT91 based SoC. +config PWM_CADENCE_TTC + bool "Enable support for the Cadence TTC PWM" + depends on DM_PWM && !CADENCE_TTC_TIMER + help + Cadence TTC can be configured as timer which is done via + CONFIG_CADENCE_TTC_TIMER or as PWM. This is covering only PWM now. + config PWM_CROS_EC bool "Enable support for the Chrome OS EC PWM" depends on DM_PWM diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 5d31812d52a..bd119a666a9 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_DM_PWM) += pwm-uclass.o obj-$(CONFIG_PWM_ASPEED) += pwm-aspeed.o obj-$(CONFIG_PWM_AT91) += pwm-at91.o +obj-$(CONFIG_PWM_CADENCE_TTC) += pwm-cadence-ttc.o obj-$(CONFIG_PWM_CROS_EC) += cros_ec_pwm.o obj-$(CONFIG_PWM_EXYNOS) += exynos_pwm.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o pwm-imx-util.o diff --git a/drivers/pwm/pwm-cadence-ttc.c b/drivers/pwm/pwm-cadence-ttc.c new file mode 100644 index 00000000000..dc3b314b0cc --- /dev/null +++ b/drivers/pwm/pwm-cadence-ttc.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) Copyright 2021 Xilinx, Inc. Michal Simek + */ + +#define LOG_CATEGORY UCLASS_PWM + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CLOCK_CONTROL 0 +#define COUNTER_CONTROL 0xc +#define INTERVAL_COUNTER 0x24 +#define MATCH_1_COUNTER 0x30 + +#define CLK_FALLING_EDGE BIT(6) +#define CLK_SRC_EXTERNAL BIT(5) +#define CLK_PRESCALE_MASK GENMASK(4, 1) +#define CLK_PRESCALE_ENABLE BIT(0) + +#define COUNTER_WAVE_POL BIT(6) +#define COUNTER_WAVE_DISABLE BIT(5) +#define COUNTER_RESET BIT(4) +#define COUNTER_MATCH_ENABLE BIT(3) +#define COUNTER_DECREMENT_ENABLE BIT(2) +#define COUNTER_INTERVAL_ENABLE BIT(1) +#define COUNTER_COUNTING_DISABLE BIT(0) + +#define NSEC_PER_SEC 1000000000L + +#define TTC_REG(reg, channel) ((reg) + (channel) * sizeof(u32)) +#define TTC_CLOCK_CONTROL(reg, channel) \ + TTC_REG((reg) + CLOCK_CONTROL, (channel)) +#define TTC_COUNTER_CONTROL(reg, channel) \ + TTC_REG((reg) + COUNTER_CONTROL, (channel)) +#define TTC_INTERVAL_COUNTER(reg, channel) \ + TTC_REG((reg) + INTERVAL_COUNTER, (channel)) +#define TTC_MATCH_1_COUNTER(reg, channel) \ + TTC_REG((reg) + MATCH_1_COUNTER, (channel)) + +struct cadence_ttc_pwm_plat { + u8 *regs; + u32 timer_width; +}; + +struct cadence_ttc_pwm_priv { + u8 *regs; + u32 timer_width; + u32 timer_mask; + unsigned long frequency; + bool invert[2]; +}; + +static int cadence_ttc_pwm_set_invert(struct udevice *dev, uint channel, + bool polarity) +{ + struct cadence_ttc_pwm_priv *priv = dev_get_priv(dev); + + if (channel > 2) { + dev_err(dev, "Unsupported channel number %d(max 2)\n", channel); + return -EINVAL; + } + + priv->invert[channel] = polarity; + + dev_dbg(dev, "polarity=%u. Please config PWM again\n", polarity); + + return 0; +} + +static int cadence_ttc_pwm_set_config(struct udevice *dev, uint channel, + uint period_ns, uint duty_ns) +{ + struct cadence_ttc_pwm_priv *priv = dev_get_priv(dev); + u32 counter_ctrl, clock_ctrl; + int period_clocks, duty_clocks, prescaler; + + dev_dbg(dev, "channel %d, duty %d/period %d ns\n", channel, + duty_ns, period_ns); + + if (channel > 2) { + dev_err(dev, "Unsupported channel number %d(max 2)\n", channel); + return -EINVAL; + } + + /* Make sure counter is stopped */ + counter_ctrl = readl(TTC_COUNTER_CONTROL(priv->regs, channel)); + setbits_le32(TTC_COUNTER_CONTROL(priv->regs, channel), + COUNTER_COUNTING_DISABLE | COUNTER_WAVE_DISABLE); + + /* Calculate period, prescaler and set clock control register */ + period_clocks = div64_u64(((int64_t)period_ns * priv->frequency), + NSEC_PER_SEC); + + prescaler = ilog2(period_clocks) + 1 - priv->timer_width; + if (prescaler < 0) + prescaler = 0; + + clock_ctrl = readl(TTC_CLOCK_CONTROL(priv->regs, channel)); + + if (!prescaler) { + clock_ctrl &= ~(CLK_PRESCALE_ENABLE | CLK_PRESCALE_MASK); + } else { + clock_ctrl &= ~CLK_PRESCALE_MASK; + clock_ctrl |= CLK_PRESCALE_ENABLE; + clock_ctrl |= FIELD_PREP(CLK_PRESCALE_MASK, prescaler - 1); + }; + + /* External source is not handled by this driver now */ + clock_ctrl &= ~CLK_SRC_EXTERNAL; + + writel(clock_ctrl, TTC_CLOCK_CONTROL(priv->regs, channel)); + + /* Calculate interval and set counter control value */ + duty_clocks = div64_u64(((int64_t)duty_ns * priv->frequency), + NSEC_PER_SEC); + + writel((period_clocks >> prescaler) & priv->timer_mask, + TTC_INTERVAL_COUNTER(priv->regs, channel)); + writel((duty_clocks >> prescaler) & priv->timer_mask, + TTC_MATCH_1_COUNTER(priv->regs, channel)); + + /* Restore/reset counter */ + counter_ctrl &= ~COUNTER_DECREMENT_ENABLE; + counter_ctrl |= COUNTER_INTERVAL_ENABLE | + COUNTER_RESET | + COUNTER_MATCH_ENABLE; + + if (priv->invert[channel]) + counter_ctrl |= COUNTER_WAVE_POL; + else + counter_ctrl &= ~COUNTER_WAVE_POL; + + writel(counter_ctrl, TTC_COUNTER_CONTROL(priv->regs, channel)); + + dev_dbg(dev, "%d/%d clocks, prescaler 2^%d\n", duty_clocks, + period_clocks, prescaler); + + return 0; +}; + +static int cadence_ttc_pwm_set_enable(struct udevice *dev, uint channel, + bool enable) +{ + struct cadence_ttc_pwm_priv *priv = dev_get_priv(dev); + + if (channel > 2) { + dev_err(dev, "Unsupported channel number %d(max 2)\n", channel); + return -EINVAL; + } + + dev_dbg(dev, "Enable: %d, channel %d\n", enable, channel); + + if (enable) { + clrbits_le32(TTC_COUNTER_CONTROL(priv->regs, channel), + COUNTER_COUNTING_DISABLE | + COUNTER_WAVE_DISABLE); + setbits_le32(TTC_COUNTER_CONTROL(priv->regs, channel), + COUNTER_RESET); + } else { + setbits_le32(TTC_COUNTER_CONTROL(priv->regs, channel), + COUNTER_COUNTING_DISABLE | + COUNTER_WAVE_DISABLE); + } + + return 0; +}; + +static int cadence_ttc_pwm_probe(struct udevice *dev) +{ + struct cadence_ttc_pwm_priv *priv = dev_get_priv(dev); + struct cadence_ttc_pwm_plat *plat = dev_get_plat(dev); + struct clk clk; + int ret; + + priv->regs = plat->regs; + priv->timer_width = plat->timer_width; + priv->timer_mask = GENMASK(priv->timer_width - 1, 0); + + ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) { + dev_err(dev, "failed to get clock\n"); + return ret; + } + + priv->frequency = clk_get_rate(&clk); + if (IS_ERR_VALUE(priv->frequency)) { + dev_err(dev, "failed to get rate\n"); + return priv->frequency; + } + dev_dbg(dev, "Clk frequency: %ld\n", priv->frequency); + + ret = clk_enable(&clk); + if (ret) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + + return 0; +} + +static int cadence_ttc_pwm_of_to_plat(struct udevice *dev) +{ + struct cadence_ttc_pwm_plat *plat = dev_get_plat(dev); + const char *cells; + + cells = dev_read_prop(dev, "#pwm-cells", NULL); + if (!cells) + return -EINVAL; + + plat->regs = dev_read_addr_ptr(dev); + + plat->timer_width = dev_read_u32_default(dev, "timer-width", 16); + + return 0; +} + +static int cadence_ttc_pwm_bind(struct udevice *dev) +{ + const char *cells; + + cells = dev_read_prop(dev, "#pwm-cells", NULL); + if (!cells) + return -ENODEV; + + return 0; +} + +static const struct pwm_ops cadence_ttc_pwm_ops = { + .set_invert = cadence_ttc_pwm_set_invert, + .set_config = cadence_ttc_pwm_set_config, + .set_enable = cadence_ttc_pwm_set_enable, +}; + +static const struct udevice_id cadence_ttc_pwm_ids[] = { + { .compatible = "cdns,ttc" }, + { } +}; + +U_BOOT_DRIVER(cadence_ttc_pwm) = { + .name = "cadence_ttc_pwm", + .id = UCLASS_PWM, + .of_match = cadence_ttc_pwm_ids, + .ops = &cadence_ttc_pwm_ops, + .bind = cadence_ttc_pwm_bind, + .of_to_plat = cadence_ttc_pwm_of_to_plat, + .probe = cadence_ttc_pwm_probe, + .priv_auto = sizeof(struct cadence_ttc_pwm_priv), + .plat_auto = sizeof(struct cadence_ttc_pwm_plat), +}; From 24d973c0c19c76ad5959a1ab212240acff54a930 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 15 Oct 2021 15:17:30 +0200 Subject: [PATCH 10/21] arm: zynqmp: Enable PWM command and cadence ttc pwm driver Enable PWM ttc driver and command in generic image. Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/a660c8f2010f4f07534753e0ac44a34b8ff0d3c3.1634303847.git.michal.simek@xilinx.com --- configs/xilinx_zynqmp_virt_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index b43b90ee3c5..906a8a7f2cb 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -52,6 +52,7 @@ CONFIG_CMD_FPGA_LOADBP=y CONFIG_CMD_FPGA_LOADP=y CONFIG_CMD_FPGA_LOAD_SECURE=y CONFIG_CMD_GPIO=y +CONFIG_CMD_PWM=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y @@ -163,6 +164,8 @@ CONFIG_XILINX_AXIEMAC=y CONFIG_ZYNQ_GEM=y CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_FIXED=y +CONFIG_DM_PWM=y +CONFIG_PWM_CADENCE_TTC=y CONFIG_DM_RTC=y CONFIG_RTC_EMULATION=y CONFIG_RTC_ZYNQMP=y From cf5ed341e44bdde29d380362f9d1b8fbd95b04fd Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 29 Mar 2022 12:54:41 +0200 Subject: [PATCH 11/21] xilinx: Increase max size of image from 60 to 100MB Recently big Linux kernels can have more then 60MB that's why increase this limit to also cover these large kernels. Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/f52f7c8ea419d69b248ba1460a96d1635194e128.1648551279.git.michal.simek@xilinx.com --- include/configs/xilinx_versal.h | 2 +- include/configs/xilinx_zynqmp.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/configs/xilinx_versal.h b/include/configs/xilinx_versal.h index 19e09e3cafa..9088b318ec8 100644 --- a/include/configs/xilinx_versal.h +++ b/include/configs/xilinx_versal.h @@ -43,7 +43,7 @@ # define PHY_ANEG_TIMEOUT 20000 #endif -#define CONFIG_SYS_BOOTM_LEN (60 * 1024 * 1024) +#define CONFIG_SYS_BOOTM_LEN (100 * 1024 * 1024) #define CONFIG_CLOCKS diff --git a/include/configs/xilinx_zynqmp.h b/include/configs/xilinx_zynqmp.h index 494a7c4b001..d1abe44c455 100644 --- a/include/configs/xilinx_zynqmp.h +++ b/include/configs/xilinx_zynqmp.h @@ -58,7 +58,7 @@ # define PHY_ANEG_TIMEOUT 20000 #endif -#define CONFIG_SYS_BOOTM_LEN (60 * 1024 * 1024) +#define CONFIG_SYS_BOOTM_LEN (100 * 1024 * 1024) #define CONFIG_CLOCKS From 6f735e41785d5a8373b3cbad8f582966c9d1001f Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 29 Mar 2022 13:13:56 +0200 Subject: [PATCH 12/21] clk: zynqmp: Add support for for DP audio/video clocks Add support for getting rate for DP audio and video clocks. Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/8792efe1fd9715f7c8a2e1e24f0454fb5b25d833.1648552434.git.michal.simek@xilinx.com --- drivers/clk/clk_zynqmp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/clk/clk_zynqmp.c b/drivers/clk/clk_zynqmp.c index 9038fb8befd..45c679a627b 100644 --- a/drivers/clk/clk_zynqmp.c +++ b/drivers/clk/clk_zynqmp.c @@ -238,6 +238,12 @@ static u32 zynqmp_clk_get_register(enum zynqmp_clk id) return CRF_APB_DBG_TRACE_CTRL; case dbg_tstmp: return CRF_APB_DBG_TSTMP_CTRL; + case dp_video_ref: + return CRF_APB_DP_VIDEO_REF_CTRL; + case dp_audio_ref: + return CRF_APB_DP_AUDIO_REF_CTRL; + case dp_stc_ref: + return CRF_APB_DP_STC_REF_CTRL; case gpu_ref ... gpu_pp1_ref: return CRF_APB_GPU_REF_CTRL; case ddr_ref: @@ -673,6 +679,7 @@ static ulong zynqmp_clk_get_rate(struct clk *clk) case dll_ref: return zynqmp_clk_get_dll_rate(priv); case gem_tsu_ref: + case dp_video_ref ... dp_stc_ref: case pl0 ... pl3: case gem0_ref ... gem3_ref: case gem0_tx ... gem3_tx: From 9b529a972d15af7dabfa2fffa69f0e2ed69b6220 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 29 Mar 2022 16:05:57 +0200 Subject: [PATCH 13/21] net: phy: Fix rgmii-id phy reset timeout issue While creating a phy device using phy_device_create(), we need to provide a valid phyaddr instead of 0 causing phy address being registered as 0 with mdio bus and shows mdio phy list as below ZynqMP> mdio list eth0: 0 - TI DP83867 <--> ethernet@ff0b0000 eth1: 0 - TI DP83867 <--> ethernet@ff0c0000 Also PHY soft reset is being requested on 0 instead of valid address causing "PHY reset timed out" error. So add phyaddr argument to phy_connect_phy_id() and to its prototype to create phy device with valid phyaddress. Fixes: a744a284e354 ("net: phy: Add support for ethernet-phy-id with gpio reset") Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek Reviewed-by: Bin Meng Link: https://lore.kernel.org/r/fe35fddb9faa5af577ffdfabaec6879c935a30f8.1648562755.git.michal.simek@xilinx.com --- drivers/net/phy/ethernet_id.c | 4 ++-- drivers/net/phy/phy.c | 2 +- include/phy.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/ethernet_id.c b/drivers/net/phy/ethernet_id.c index 5617ac3ad62..44abc5bfb30 100644 --- a/drivers/net/phy/ethernet_id.c +++ b/drivers/net/phy/ethernet_id.c @@ -12,7 +12,7 @@ #include struct phy_device *phy_connect_phy_id(struct mii_dev *bus, struct udevice *dev, - phy_interface_t interface) + int phyaddr, phy_interface_t interface) { struct phy_device *phydev; struct ofnode_phandle_args phandle_args; @@ -61,7 +61,7 @@ struct phy_device *phy_connect_phy_id(struct mii_dev *bus, struct udevice *dev, } id = vendor << 16 | device; - phydev = phy_device_create(bus, 0, id, false, interface); + phydev = phy_device_create(bus, phyaddr, id, false, interface); if (phydev) phydev->node = node; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 92fff5b72c0..d4731860f73 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1049,7 +1049,7 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr, #ifdef CONFIG_PHY_ETHERNET_ID if (!phydev) - phydev = phy_connect_phy_id(bus, dev, interface); + phydev = phy_connect_phy_id(bus, dev, addr, interface); #endif #ifdef CONFIG_PHY_XILINX_GMII2RGMII diff --git a/include/phy.h b/include/phy.h index 9ea4bd42db4..5e3da4b01b6 100644 --- a/include/phy.h +++ b/include/phy.h @@ -479,7 +479,7 @@ struct phy_device *phy_device_create(struct mii_dev *bus, int addr, * or NULL otherwise */ struct phy_device *phy_connect_phy_id(struct mii_dev *bus, struct udevice *dev, - phy_interface_t interface); + int phyaddr, phy_interface_t interface); static inline ofnode phy_get_ofnode(struct phy_device *phydev) { From ad8d48e981d2d86a58fb52382fb5910c75a19910 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 30 Mar 2022 07:51:58 +0200 Subject: [PATCH 14/21] arm64: zynqmp: Record ID code for XCZU1EG device Add ID code for 1eg device. Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/5b6c9f6a25bba076f304bc4699f6f676a929a683.1648619516.git.michal.simek@xilinx.com --- board/xilinx/zynqmp/zynqmp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index bc2090941d9..e7e8e91d2cf 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -69,6 +69,11 @@ static const struct { u8 device; u8 variants; } zynqmp_devices[] = { + { + .id = 0x04688093, + .device = 1, + .variants = ZYNQMP_VARIANT_EG, + }, { .id = 0x04711093, .device = 2, From d2f059c3dc3e651e8ec16ccadefa26a5e1109e5a Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 30 Mar 2022 09:56:23 +0200 Subject: [PATCH 15/21] dt-bindings: xilinx: Add missing ids for PD There are some new power domain IDs which are used in Linux kernel that's why add them here too. Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/e6092e1d3766c0ac11bf620820739c93ab677a85.1648626981.git.michal.simek@xilinx.com --- include/dt-bindings/power/xlnx-versal-power.h | 11 +++++++++++ include/dt-bindings/power/xlnx-zynqmp-power.h | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/dt-bindings/power/xlnx-versal-power.h b/include/dt-bindings/power/xlnx-versal-power.h index 4a727754ad0..51d1def6773 100644 --- a/include/dt-bindings/power/xlnx-versal-power.h +++ b/include/dt-bindings/power/xlnx-versal-power.h @@ -6,6 +6,16 @@ #ifndef _DT_BINDINGS_VERSAL_POWER_H #define _DT_BINDINGS_VERSAL_POWER_H +#define PM_DEV_RPU0_0 (0x18110005U) +#define PM_DEV_RPU0_1 (0x18110006U) +#define PM_DEV_OCM_0 (0x18314007U) +#define PM_DEV_OCM_1 (0x18314008U) +#define PM_DEV_OCM_2 (0x18314009U) +#define PM_DEV_OCM_3 (0x1831400aU) +#define PM_DEV_TCM_0_A (0x1831800bU) +#define PM_DEV_TCM_0_B (0x1831800cU) +#define PM_DEV_TCM_1_A (0x1831800dU) +#define PM_DEV_TCM_1_B (0x1831800eU) #define PM_DEV_USB_0 (0x18224018U) #define PM_DEV_GEM_0 (0x18224019U) #define PM_DEV_GEM_1 (0x1822401aU) @@ -38,6 +48,7 @@ #define PM_DEV_ADMA_5 (0x1822403aU) #define PM_DEV_ADMA_6 (0x1822403bU) #define PM_DEV_ADMA_7 (0x1822403cU) +#define PM_DEV_AMS_ROOT (0x18224055U) #define PM_DEV_AI (0x18224072U) #endif diff --git a/include/dt-bindings/power/xlnx-zynqmp-power.h b/include/dt-bindings/power/xlnx-zynqmp-power.h index 0d9a412fd5e..e7eb0960480 100644 --- a/include/dt-bindings/power/xlnx-zynqmp-power.h +++ b/include/dt-bindings/power/xlnx-zynqmp-power.h @@ -6,6 +6,16 @@ #ifndef _DT_BINDINGS_ZYNQMP_POWER_H #define _DT_BINDINGS_ZYNQMP_POWER_H +#define PD_RPU_0 6 +#define PD_RPU_1 7 +#define PD_OCM_BANK_0 11 +#define PD_OCM_BANK_1 12 +#define PD_OCM_BANK_2 13 +#define PD_OCM_BANK_3 14 +#define PD_TCM_BANK_0 15 +#define PD_TCM_BANK_1 16 +#define PD_TCM_BANK_2 17 +#define PD_TCM_BANK_3 18 #define PD_USB_0 22 #define PD_USB_1 23 #define PD_TTC_0 24 @@ -35,5 +45,6 @@ #define PD_CAN_1 48 #define PD_GPU 58 #define PD_PCIE 59 +#define PD_PL 69 #endif From 801725395ad07888fada4eaf2e0af0efcab5178a Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 30 Mar 2022 11:07:53 +0200 Subject: [PATCH 16/21] net: zynq_gem: Use shared MDIO bus support for zynqmp CONFIG_ETH_PHY enables support to utilize generic ethernet phy framework. Though if ethernet PHY node is in other ethernet node, it will use shared MDIO to access the PHY of other ethernet. Signed-off-by: Michal Simek Signed-off-by: T Karthik Reddy Link: https://lore.kernel.org/r/337b1a38ba36cde1951739af62fb3d2736d97f53.1648631275.git.michal.simek@xilinx.com --- drivers/net/zynq_gem.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 3118d147266..168aabbdd00 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -33,6 +33,7 @@ #include #include #include +#include /* Bit/mask specification */ #define ZYNQ_GEM_PHYMNTNC_OP_MASK 0x40020000 /* operation mask bits */ @@ -321,6 +322,9 @@ static int zynq_phy_init(struct udevice *dev) /* Enable only MDIO bus */ writel(ZYNQ_GEM_NWCTRL_MDEN_MASK, ®s_mdio->nwctrl); + if (IS_ENABLED(CONFIG_DM_ETH_PHY)) + priv->phyaddr = eth_phy_get_addr(dev); + priv->phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface); if (!priv->phydev) @@ -771,14 +775,22 @@ static int zynq_gem_probe(struct udevice *dev) } } - priv->bus = mdio_alloc(); - priv->bus->read = zynq_gem_miiphy_read; - priv->bus->write = zynq_gem_miiphy_write; - priv->bus->priv = priv; + if (IS_ENABLED(CONFIG_DM_ETH_PHY)) + priv->bus = eth_phy_get_mdio_bus(dev); - ret = mdio_register_seq(priv->bus, dev_seq(dev)); - if (ret) - goto err2; + if (!priv->bus) { + priv->bus = mdio_alloc(); + priv->bus->read = zynq_gem_miiphy_read; + priv->bus->write = zynq_gem_miiphy_write; + priv->bus->priv = priv; + + ret = mdio_register_seq(priv->bus, dev_seq(dev)); + if (ret) + goto err2; + } + + if (IS_ENABLED(CONFIG_DM_ETH_PHY)) + eth_phy_set_mdio_bus(dev, priv->bus); ret = zynq_phy_init(dev); if (ret) @@ -841,8 +853,10 @@ static int zynq_gem_of_to_plat(struct udevice *dev) ofnode parent; debug("phy-handle does exist %s\n", dev->name); - priv->phyaddr = ofnode_read_u32_default(phandle_args.node, - "reg", -1); + if (!(IS_ENABLED(CONFIG_DM_ETH_PHY))) + priv->phyaddr = ofnode_read_u32_default + (phandle_args.node, "reg", -1); + priv->phy_of_node = phandle_args.node; priv->max_speed = ofnode_read_u32_default(phandle_args.node, "max-speed", From ccc8656f7fb51d0f11cc7cea6c05daf1e30f6bad Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 30 Mar 2022 11:07:54 +0200 Subject: [PATCH 17/21] net: phy: Avoid phy gpio reset sequence if DM_ETH_PHY is enabled If DM_ETH_PHY config is enabled PHY gpio reset is taken care by the eth-phy-uclass driver, so use the PHY gpio reset functionality from ethernet_id file when this config is disabled to reset the PHY. Use debug() print instead of dev_err() to avoid warning incase if phy-id compatible string is not present. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/4d0fd3f9f886c1d943776025e5efb5438b0eb389.1648631275.git.michal.simek@xilinx.com --- drivers/net/phy/ethernet_id.c | 49 ++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/drivers/net/phy/ethernet_id.c b/drivers/net/phy/ethernet_id.c index 44abc5bfb30..1a78a751ede 100644 --- a/drivers/net/phy/ethernet_id.c +++ b/drivers/net/phy/ethernet_id.c @@ -33,31 +33,38 @@ struct phy_device *phy_connect_phy_id(struct mii_dev *bus, struct udevice *dev, ret = ofnode_read_eth_phy_id(node, &vendor, &device); if (ret) { - dev_err(dev, "Failed to read eth PHY id, err: %d\n", ret); + debug("Failed to read eth PHY id, err: %d\n", ret); return NULL; } - ret = gpio_request_by_name_nodev(node, "reset-gpios", 0, &gpio, - GPIOD_ACTIVE_LOW); - if (!ret) { - assert = ofnode_read_u32_default(node, "reset-assert-us", 0); - deassert = ofnode_read_u32_default(node, - "reset-deassert-us", 0); - ret = dm_gpio_set_value(&gpio, 1); - if (ret) { - dev_err(dev, "Failed assert gpio, err: %d\n", ret); - return NULL; + if (!IS_ENABLED(CONFIG_DM_ETH_PHY)) { + ret = gpio_request_by_name_nodev(node, "reset-gpios", 0, &gpio, + GPIOD_ACTIVE_LOW); + if (!ret) { + assert = ofnode_read_u32_default(node, + "reset-assert-us", 0); + deassert = ofnode_read_u32_default(node, + "reset-deassert-us", + 0); + ret = dm_gpio_set_value(&gpio, 1); + if (ret) { + dev_err(dev, + "Failed assert gpio, err: %d\n", ret); + return NULL; + } + + udelay(assert); + + ret = dm_gpio_set_value(&gpio, 0); + if (ret) { + dev_err(dev, + "Failed deassert gpio, err: %d\n", + ret); + return NULL; + } + + udelay(deassert); } - - udelay(assert); - - ret = dm_gpio_set_value(&gpio, 0); - if (ret) { - dev_err(dev, "Failed deassert gpio, err: %d\n", ret); - return NULL; - } - - udelay(deassert); } id = vendor << 16 | device; From fc6e56283e141423797bbdcf39029c6e35bf5dc9 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 30 Mar 2022 11:07:55 +0200 Subject: [PATCH 18/21] net: zynq_gem: Move ethernet info print statement As we are not reading the PHY address in case of CONFIG_ETH_PHY in plat function, phy address always prints as -1. So move the ethernet info print statement to probe function, to display proper phy address. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/f6efc6719d767b1bebe65987c22c6d52329f4225.1648631275.git.michal.simek@xilinx.com --- drivers/net/zynq_gem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 168aabbdd00..07de1bf0a40 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -802,6 +802,10 @@ static int zynq_gem_probe(struct udevice *dev) return ret; } + printf("\nZYNQ GEM: %lx, mdio bus %lx, phyaddr %d, interface %s\n", + (ulong)priv->iobase, (ulong)priv->mdiobase, priv->phydev->addr, + phy_string_for_interface(priv->interface)); + return ret; err3: @@ -884,10 +888,6 @@ static int zynq_gem_of_to_plat(struct udevice *dev) priv->int_pcs = dev_read_bool(dev, "is-internal-pcspma"); - printf("\nZYNQ GEM: %lx, mdio bus %lx, phyaddr %d, interface %s\n", - (ulong)priv->iobase, (ulong)priv->mdiobase, priv->phyaddr, - phy_string_for_interface(priv->interface)); - priv->clk_en_info = dev_get_driver_data(dev); return 0; From e949e789482352b14ff8842744e4322647da92c2 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 30 Mar 2022 11:07:56 +0200 Subject: [PATCH 19/21] gpio: slg7xl45106: Update gpio desc flags from DT In current slg7xl45106 gpio driver xlate() function we are not updating gpio flags from DT. Read the given flag from DT and update the gpio desc flags variable with required gpio direction state. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/a8d7b4799337bd99f61ace509889f02b192a9414.1648631275.git.michal.simek@xilinx.com --- drivers/gpio/gpio_slg7xl45106.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpio_slg7xl45106.c b/drivers/gpio/gpio_slg7xl45106.c index 2cbf7488ad6..4ad06c18b4b 100644 --- a/drivers/gpio/gpio_slg7xl45106.c +++ b/drivers/gpio/gpio_slg7xl45106.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #define SLG7XL45106_REG 0xdb @@ -26,6 +27,7 @@ static int slg7xl45106_i2c_gpo_xlate(struct udevice *dev, struct ofnode_phandle_args *args) { desc->offset = (unsigned int)args->args[0]; + desc->flags = (args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0); return 0; } From 7011efce2390e2721819df8c4d35da99e43e86b7 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 30 Mar 2022 11:07:57 +0200 Subject: [PATCH 20/21] firmware: firmware-zynqmp: Add zynqmp_pm_set_gem_config api Add zynqmp_pm_set_gem_config() api to configure GEM secure registers. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/f69e32355c6a6be7d2780663353c52757530207d.1648631275.git.michal.simek@xilinx.com --- drivers/firmware/firmware-zynqmp.c | 13 +++++++++++++ include/zynqmp_firmware.h | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index 78da5abc5d3..0f0d2b07c00 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -140,6 +140,19 @@ unsigned int zynqmp_firmware_version(void) return pm_api_version; }; +int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, u32 value) +{ + int ret; + + ret = xilinx_pm_request(PM_IOCTL, node, IOCTL_SET_GEM_CONFIG, + config, value, NULL); + if (ret) + printf("%s: node %d: set_gem_config %d failed\n", + __func__, node, config); + + return ret; +} + int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value) { int ret; diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h index f577008736d..76ec2141ff6 100644 --- a/include/zynqmp_firmware.h +++ b/include/zynqmp_firmware.h @@ -408,6 +408,11 @@ enum pm_sd_config_type { SD_CONFIG_FIXED = 4, /* To set fixed config registers */ }; +enum pm_gem_config_type { + GEM_CONFIG_SGMII_MODE = 1, /* To set GEM_SGMII_MODE in GEM_CLK_CTRL */ + GEM_CONFIG_FIXED = 2, /* To set fixed config registers */ +}; + #define PM_SIP_SVC 0xc2000000 #define ZYNQMP_PM_VERSION_MAJOR 1 @@ -439,6 +444,8 @@ void zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size); int xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 *ret_payload); int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value); +int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, + u32 value); int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id); /* Type of Config Object */ From a7379ba6505d70d887951be9ebb3f47e3792c708 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 30 Mar 2022 11:07:58 +0200 Subject: [PATCH 21/21] net: zynq_gem: Add SGMII dynamic config support Add support for SGMII dynamic configuration which will takes care of configuring SGMII in the GEM secure (GEM_CLK_CTRL) configuration register. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/a8915186e44015959978d080a31de652f544cd4a.1648631275.git.michal.simek@xilinx.com --- drivers/net/zynq_gem.c | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 07de1bf0a40..4c83ccc1dfb 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -34,6 +34,7 @@ #include #include #include +#include /* Bit/mask specification */ #define ZYNQ_GEM_PHYMNTNC_OP_MASK 0x40020000 /* operation mask bits */ @@ -714,6 +715,40 @@ static int zynq_gem_reset_init(struct udevice *dev) return 0; } +static int gem_zynqmp_set_dynamic_config(struct udevice *dev) +{ + u32 pm_info[2]; + int ret; + + if (IS_ENABLED(CONFIG_ARCH_ZYNQMP)) { + if (!zynqmp_pm_is_function_supported(PM_IOCTL, + IOCTL_SET_GEM_CONFIG)) { + ret = ofnode_read_u32_array(dev_ofnode(dev), + "power-domains", + pm_info, + ARRAY_SIZE(pm_info)); + if (ret) { + dev_err(dev, + "Failed to read power-domains info\n"); + return ret; + } + + ret = zynqmp_pm_set_gem_config(pm_info[1], + GEM_CONFIG_FIXED, 0); + if (ret) + return ret; + + ret = zynqmp_pm_set_gem_config(pm_info[1], + GEM_CONFIG_SGMII_MODE, + 1); + if (ret) + return ret; + } + } + + return 0; +} + static int zynq_gem_probe(struct udevice *dev) { void *bd_space; @@ -797,6 +832,17 @@ static int zynq_gem_probe(struct udevice *dev) goto err3; if (priv->interface == PHY_INTERFACE_MODE_SGMII && phy.dev) { + if (IS_ENABLED(CONFIG_DM_ETH_PHY)) { + if (device_is_compatible(dev, "cdns,zynqmp-gem")) { + ret = gem_zynqmp_set_dynamic_config(dev); + if (ret) { + dev_err + (dev, + "Failed to set gem dynamic config\n"); + return ret; + } + } + } ret = generic_phy_power_on(&phy); if (ret) return ret;