From f307c688ea951978ebcceb5536aa31c0249b33df Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 28 Feb 2022 17:13:15 +0100 Subject: 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(-) (limited to 'drivers') 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); -- cgit v1.2.3 From cbeba3515208c9e8db3dba3d5af5ec838c1065b3 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 25 Mar 2022 11:50:07 +0100 Subject: 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(-) (limited to 'drivers') 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); -- cgit v1.2.3 From 035d56f2386e009aaa41cd75022f8cddc04e5c1a Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Fri, 25 Mar 2022 13:11:10 +0100 Subject: 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(+) (limited to 'drivers') 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"); -- cgit v1.2.3 From dcbdd24259beaff903e7ffffde646a3c5bd756ac Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 15 Oct 2021 15:17:28 +0200 Subject: 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(+) (limited to 'drivers') 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, }; -- cgit v1.2.3 From fb92cc2c17724d66a32f7a033608a1bd2176a478 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 15 Oct 2021 15:17:29 +0200 Subject: 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 --- drivers/pwm/Kconfig | 7 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-cadence-ttc.c | 261 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 269 insertions(+) create mode 100644 drivers/pwm/pwm-cadence-ttc.c (limited to 'drivers') 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), +}; -- cgit v1.2.3 From 6f735e41785d5a8373b3cbad8f582966c9d1001f Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 29 Mar 2022 13:13:56 +0200 Subject: 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(+) (limited to 'drivers') 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: -- cgit v1.2.3 From 9b529a972d15af7dabfa2fffa69f0e2ed69b6220 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 29 Mar 2022 16:05:57 +0200 Subject: 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 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') 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 -- cgit v1.2.3 From 801725395ad07888fada4eaf2e0af0efcab5178a Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 30 Mar 2022 11:07:53 +0200 Subject: 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(-) (limited to 'drivers') 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", -- cgit v1.2.3 From ccc8656f7fb51d0f11cc7cea6c05daf1e30f6bad Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 30 Mar 2022 11:07:54 +0200 Subject: 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 | 45 +++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 19 deletions(-) (limited to 'drivers') 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); + udelay(assert); - ret = dm_gpio_set_value(&gpio, 0); - if (ret) { - dev_err(dev, "Failed deassert gpio, err: %d\n", ret); - return NULL; - } + ret = dm_gpio_set_value(&gpio, 0); + if (ret) { + dev_err(dev, + "Failed deassert gpio, err: %d\n", + ret); + return NULL; + } - udelay(deassert); + udelay(deassert); + } } id = vendor << 16 | device; -- cgit v1.2.3 From fc6e56283e141423797bbdcf39029c6e35bf5dc9 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 30 Mar 2022 11:07:55 +0200 Subject: 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(-) (limited to 'drivers') 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; -- cgit v1.2.3 From e949e789482352b14ff8842744e4322647da92c2 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 30 Mar 2022 11:07:56 +0200 Subject: 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(+) (limited to 'drivers') 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; } -- cgit v1.2.3 From 7011efce2390e2721819df8c4d35da99e43e86b7 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 30 Mar 2022 11:07:57 +0200 Subject: 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 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') 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; -- cgit v1.2.3 From a7379ba6505d70d887951be9ebb3f47e3792c708 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Wed, 30 Mar 2022 11:07:58 +0200 Subject: 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(+) (limited to 'drivers') 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; -- cgit v1.2.3