From fb3b38f7b86bbce3dd3b24e65c6b39e3722dc6d7 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 16 Mar 2023 14:42:07 +0100 Subject: net: dsa: add adjust_link support The required functionality is essential for cable hot plugging or asynchronous link detection. In its current state, DSA will only operate if the cable was connected prior to booting. Signed-off-by: Oleksij Rempel Link: https://lore.barebox.org/20230316134209.4068801-1-o.rempel@pengutronix.de Signed-off-by: Sascha Hauer --- drivers/net/dsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa.c b/drivers/net/dsa.c index 6a3b829e15..ccd7d87550 100644 --- a/drivers/net/dsa.c +++ b/drivers/net/dsa.c @@ -104,8 +104,8 @@ static int dsa_port_start(struct eth_device *edev) return ret; } - ret = phy_device_connect(edev, ds->slave_mii_bus, dp->index, NULL, 0, - interface); + ret = phy_device_connect(edev, ds->slave_mii_bus, dp->index, + ops->adjust_link, 0, interface); if (ret) return ret; -- cgit v1.2.1 From 37698671df22ba5ba266a41ce5125749c8054097 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 16 Mar 2023 14:42:08 +0100 Subject: net: dsa: sja1105: move port enable to adjust link code. Execute port enable code dynamically based on link detection status. This enables proper MAC configuration during link detection events. Signed-off-by: Oleksij Rempel Link: https://lore.barebox.org/20230316134209.4068801-2-o.rempel@pengutronix.de Signed-off-by: Sascha Hauer --- drivers/net/sja1105.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sja1105.c b/drivers/net/sja1105.c index b85184ed92..693730f96c 100644 --- a/drivers/net/sja1105.c +++ b/drivers/net/sja1105.c @@ -1432,7 +1432,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv) .top = {0x1FF, 0, 0, 0, 0, 0, 0}, .base = {0x0, 0, 0, 0, 0, 0, 0, 0}, .enabled = {1, 0, 0, 0, 0, 0, 0, 0}, - /* Will be overridden in sja1105_port_enable. */ + /* Will be overridden in sja1105_adjust_link. */ .speed = priv->dcfg->port_speed[SJA1105_SPEED_AUTO], .egress = true, .ingress = true, @@ -2727,14 +2727,16 @@ static int sja1105_port_pre_enable(struct dsa_port *dp, int port, return sja1105_static_config_reload(priv); } -static int sja1105_port_enable(struct dsa_port *dp, int port, - struct phy_device *phy) +static void sja1105_adjust_link(struct eth_device *edev) { + struct dsa_port *dp = edev->priv; struct device *dev = dp->ds->dev; struct sja1105_private *priv = dev_get_priv(dev); + struct phy_device *phy = dp->edev.phydev; phy_interface_t phy_mode = phy->interface; struct sja1105_xmii_params_entry *mii; struct sja1105_mac_config_entry *mac; + int port = dp->index; int ret; mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries; @@ -2742,7 +2744,7 @@ static int sja1105_port_enable(struct dsa_port *dp, int port, ret = sja1105_port_set_mode(dp, port, phy_mode); if (ret) - return ret; + goto error; /* Let the PHY handle the RGMII delays, if present. */ if (phy->phy_id == 0) { @@ -2758,7 +2760,7 @@ static int sja1105_port_enable(struct dsa_port *dp, int port, priv->rgmii_tx_delay[port]) && !priv->dcfg->setup_rgmii_delay) { dev_err(priv->dev, "Chip does not support internal RGMII delays\n"); - return -EINVAL; + return; } } @@ -2778,10 +2780,18 @@ static int sja1105_port_enable(struct dsa_port *dp, int port, } else { dev_err(priv->dev, "Invalid PHY speed %d on port %d\n", phy->speed, port); - return -EINVAL; + return; } - return sja1105_static_config_reload(priv); + ret = sja1105_static_config_reload(priv); + if (ret) + goto error; + + return; + +error: + dev_err(priv->dev, "Failed to adjust link on port %d, error %pe\n", + port, ERR_PTR(ret)); } static int sja1105_xmit(struct dsa_port *dp, int port, void *packet, int length) @@ -2816,7 +2826,7 @@ static int sja1105_rcv(struct dsa_switch *ds, int *port, void *packet, static const struct dsa_switch_ops sja1105_dsa_ops = { .port_pre_enable = sja1105_port_pre_enable, - .port_enable = sja1105_port_enable, + .adjust_link = sja1105_adjust_link, .xmit = sja1105_xmit, .rcv = sja1105_rcv, }; -- cgit v1.2.1 From bea0ec68ed1e5a1a2243de8c92077c766e9cefae Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 16 Mar 2023 14:42:09 +0100 Subject: net: dsa: sja1105: fall back to default speed configuration if no link was detected Rather than generating an error, revert to the default link configuration. Some configuration is performed during the port pre-enable sequence. Signed-off-by: Oleksij Rempel Link: https://lore.barebox.org/20230316134209.4068801-3-o.rempel@pengutronix.de Signed-off-by: Sascha Hauer --- drivers/net/sja1105.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sja1105.c b/drivers/net/sja1105.c index 693730f96c..328e5a6369 100644 --- a/drivers/net/sja1105.c +++ b/drivers/net/sja1105.c @@ -2778,8 +2778,7 @@ static void sja1105_adjust_link(struct eth_device *edev) mac[port].speed = priv->dcfg->port_speed[SJA1105_SPEED_10MBPS]; } else { - dev_err(priv->dev, "Invalid PHY speed %d on port %d\n", - phy->speed, port); + mac[port].speed = priv->dcfg->port_speed[SJA1105_SPEED_AUTO]; return; } -- cgit v1.2.1 From de309f3b50ce10ac5838a6e96443acc42dee5eb6 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 21 Mar 2023 10:50:56 +0100 Subject: mci: sdhci: Add and use common sdhci_wait_for_done() We have different driver specific variants of functions polling for the device ready in the tree. Add a common sdhci_wait_for_done() and use it where appropriate. This fixes a few deficiencies with the driver specific variants. rk_sdhci_wait_for_done() didn't check the SDHCI_INT_TIMEOUT bit and returned -EPERM instead when it ought to return -ETIMEDOUT. The core tries to detect a SD card first and expects a -ETIMEDOUT for the setup command when really a eMMC is connected. Only with a -ETIMEDOUT the core tries to detect a eMMC next. at91_sdhci_wait_for_done() returned the status instead of the expected 0 value for success. Link: https://lore.barebox.org/20230321095056.1333669-1-s.hauer@pengutronix.de Signed-off-by: Sascha Hauer --- drivers/mci/arasan-sdhci.c | 29 +---------------------------- drivers/mci/atmel-sdhci-common.c | 28 +--------------------------- drivers/mci/rockchip-dwcmshc-sdhci.c | 29 ++--------------------------- drivers/mci/sdhci.c | 27 +++++++++++++++++++++++++++ drivers/mci/sdhci.h | 1 + 5 files changed, 32 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c index 00a8ceed68..650de22b69 100644 --- a/drivers/mci/arasan-sdhci.c +++ b/drivers/mci/arasan-sdhci.c @@ -133,33 +133,6 @@ static void arasan_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios) sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val); } -static int arasan_sdhci_wait_for_done(struct arasan_sdhci_host *host, u32 mask) -{ - u64 start = get_time_ns(); - u32 stat; - - do { - stat = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS); - - if (stat & SDHCI_INT_TIMEOUT) - return -ETIMEDOUT; - - if (stat & SDHCI_INT_ERROR) { - dev_err(host->mci.hw_dev, "SDHCI_INT_ERROR: 0x%08x\n", - stat); - return -EPERM; - } - - if (is_timeout(start, 1000 * MSECOND)) { - dev_err(host->mci.hw_dev, - "SDHCI timeout while waiting for done\n"); - return -ETIMEDOUT; - } - } while ((stat & mask) != mask); - - return 0; -} - static void print_error(struct arasan_sdhci_host *host, int cmdidx, int ret) { if (ret == -ETIMEDOUT) @@ -213,7 +186,7 @@ static int arasan_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg); sdhci_write16(&host->sdhci, SDHCI_COMMAND, command); - ret = arasan_sdhci_wait_for_done(host, mask); + ret = sdhci_wait_for_done(&host->sdhci, mask); if (ret) goto error; diff --git a/drivers/mci/atmel-sdhci-common.c b/drivers/mci/atmel-sdhci-common.c index 05a019beb6..58ba0b9b3d 100644 --- a/drivers/mci/atmel-sdhci-common.c +++ b/drivers/mci/atmel-sdhci-common.c @@ -89,32 +89,6 @@ exit: return is_inserted; } -static int at91_sdhci_wait_for_done(struct at91_sdhci *host, u32 mask) -{ - struct sdhci *sdhci = &host->sdhci; - u32 status; - int ret; - - ret = sdhci_read32_poll_timeout(sdhci, SDHCI_INT_STATUS, status, - (status & mask) == mask || (status & SDHCI_INT_ERROR), - USEC_PER_SEC); - - if (ret < 0) { - dev_err(host->dev, "SDHCI timeout while waiting for done\n"); - return ret; - } - - if (status & SDHCI_INT_TIMEOUT) - return -ETIMEDOUT; - - if (status & SDHCI_INT_ERROR) { - dev_err(host->dev, "SDHCI_INT_STATUS: 0x%08x\n", status); - return -EPERM; - } - - return status & 0xFFFF; -} - int at91_sdhci_send_command(struct at91_sdhci *host, struct mci_cmd *cmd, struct mci_data *data) { @@ -158,7 +132,7 @@ int at91_sdhci_send_command(struct at91_sdhci *host, struct mci_cmd *cmd, sdhci_write32(sdhci, SDHCI_ARGUMENT, cmd->cmdarg); sdhci_write16(sdhci, SDHCI_COMMAND, command); - status = at91_sdhci_wait_for_done(host, mask); + status = sdhci_wait_for_done(&host->sdhci, mask); if (status < 0) goto error; diff --git a/drivers/mci/rockchip-dwcmshc-sdhci.c b/drivers/mci/rockchip-dwcmshc-sdhci.c index 4b4e8b7bd6..a98600cc4c 100644 --- a/drivers/mci/rockchip-dwcmshc-sdhci.c +++ b/drivers/mci/rockchip-dwcmshc-sdhci.c @@ -216,29 +216,6 @@ static void rk_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios) sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val); } -static int rk_sdhci_wait_for_done(struct rk_sdhci_host *host, u32 mask) -{ - u64 start = get_time_ns(); - u16 stat; - - do { - stat = sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS); - if (stat & SDHCI_INT_ERROR) { - dev_dbg(host->mci.hw_dev, "SDHCI_INT_ERROR: 0x%08x\n", - sdhci_read16(&host->sdhci, SDHCI_INT_ERROR_STATUS)); - return -EPERM; - } - - if (is_timeout(start, 1000 * MSECOND)) { - dev_err(host->mci.hw_dev, - "SDHCI timeout while waiting for done\n"); - return -ETIMEDOUT; - } - } while ((stat & mask) != mask); - - return 0; -} - static void print_error(struct rk_sdhci_host *host, int cmdidx) { dev_dbg(host->mci.hw_dev, @@ -285,11 +262,9 @@ static int rk_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg); sdhci_write16(&host->sdhci, SDHCI_COMMAND, command); - ret = rk_sdhci_wait_for_done(host, SDHCI_INT_CMD_COMPLETE); - if (ret == -EPERM) + ret = sdhci_wait_for_done(&host->sdhci, SDHCI_INT_CMD_COMPLETE); + if (ret) goto error; - else if (ret) - return ret; sdhci_read_response(&host->sdhci, cmd); sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, SDHCI_INT_CMD_COMPLETE); diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c index 2cdd3c3c8f..635884e2a2 100644 --- a/drivers/mci/sdhci.c +++ b/drivers/mci/sdhci.c @@ -124,6 +124,33 @@ void sdhci_set_bus_width(struct sdhci *host, int width) #endif +int sdhci_wait_for_done(struct sdhci *sdhci, u32 mask) +{ + u64 start = get_time_ns(); + u32 stat; + + do { + stat = sdhci_read32(sdhci, SDHCI_INT_STATUS); + + if (stat & SDHCI_INT_TIMEOUT) + return -ETIMEDOUT; + + if (stat & SDHCI_INT_ERROR) { + dev_err(sdhci->mci->hw_dev, "SDHCI_INT_ERROR: 0x%08x\n", + stat); + return -EPERM; + } + + if (is_timeout(start, 1000 * MSECOND)) { + dev_err(sdhci->mci->hw_dev, + "SDHCI timeout while waiting for done\n"); + return -ETIMEDOUT; + } + } while ((stat & mask) != mask); + + return 0; +} + void sdhci_setup_data_pio(struct sdhci *sdhci, struct mci_data *data) { if (!data) diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h index c538385939..fe8c25cb9c 100644 --- a/drivers/mci/sdhci.h +++ b/drivers/mci/sdhci.h @@ -257,6 +257,7 @@ static inline void sdhci_write8(struct sdhci *host, int reg, u32 val) } #define SDHCI_NO_DMA DMA_ERROR_CODE +int sdhci_wait_for_done(struct sdhci *host, u32 mask); void sdhci_read_response(struct sdhci *host, struct mci_cmd *cmd); void sdhci_set_cmd_xfer_mode(struct sdhci *host, struct mci_cmd *cmd, struct mci_data *data, bool dma, u32 *command, -- cgit v1.2.1 From e1b79d84bea0539a38fe1d7697dd0070659abb25 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 28 Mar 2023 11:47:56 +0200 Subject: mci: rockchip-dwcmshc-sdhci: use sdhci_reset() We have sdhci_reset() which does the same as the driver specific variant. Use the common function instead. Signed-off-by: Sascha Hauer --- drivers/mci/rockchip-dwcmshc-sdhci.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/mci/rockchip-dwcmshc-sdhci.c b/drivers/mci/rockchip-dwcmshc-sdhci.c index a98600cc4c..e1eb4fc788 100644 --- a/drivers/mci/rockchip-dwcmshc-sdhci.c +++ b/drivers/mci/rockchip-dwcmshc-sdhci.c @@ -87,26 +87,12 @@ static int rk_sdhci_card_present(struct mci_host *mci) return !!(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_CARD_DETECT); } -static int rk_sdhci_reset(struct rk_sdhci_host *host, u8 mask) -{ - sdhci_write8(&host->sdhci, SDHCI_SOFTWARE_RESET, mask); - - /* wait for reset completion */ - if (wait_on_timeout(100 * MSECOND, - !(sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) & mask))){ - dev_err(host->mci.hw_dev, "SDHCI reset timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - static int rk_sdhci_init(struct mci_host *mci, struct device *dev) { struct rk_sdhci_host *host = to_rk_sdhci_host(mci); int ret; - ret = rk_sdhci_reset(host, SDHCI_RESET_ALL); + ret = sdhci_reset(&host->sdhci, SDHCI_RESET_ALL); if (ret) return ret; @@ -274,8 +260,8 @@ static int rk_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, error: if (ret) { print_error(host, cmd->cmdidx); - rk_sdhci_reset(host, BIT(1)); /* SDHCI_RESET_CMD */ - rk_sdhci_reset(host, BIT(2)); /* SDHCI_RESET_DATA */ + sdhci_reset(&host->sdhci, SDHCI_RESET_CMD); + sdhci_reset(&host->sdhci, SDHCI_RESET_DATA); } sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); -- cgit v1.2.1 From 4331fe82a01336b863cd113573f97a839943f60a Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 28 Mar 2023 11:51:13 +0200 Subject: mci: arasan: use sdhci_reset() We have sdhci_reset(), use it instead of open coded variant in the driver. Signed-off-by: Sascha Hauer --- drivers/mci/arasan-sdhci.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c index 650de22b69..0b839ee7dc 100644 --- a/drivers/mci/arasan-sdhci.c +++ b/drivers/mci/arasan-sdhci.c @@ -73,14 +73,11 @@ static int arasan_sdhci_card_write_protected(struct mci_host *mci) static int arasan_sdhci_reset(struct arasan_sdhci_host *host, u8 mask) { - sdhci_write8(&host->sdhci, SDHCI_SOFTWARE_RESET, mask); + int ret; - /* wait for reset completion */ - if (wait_on_timeout(100 * MSECOND, - !(sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) & mask))) { - dev_err(host->mci.hw_dev, "SDHCI reset timeout\n"); - return -ETIMEDOUT; - } + ret = sdhci_reset(&host->sdhci, mask); + if (ret) + return ret; if (host->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) { u8 ctrl; @@ -199,8 +196,8 @@ static int arasan_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, error: if (ret) { print_error(host, cmd->cmdidx, ret); - arasan_sdhci_reset(host, BIT(1)); // SDHCI_RESET_CMD - arasan_sdhci_reset(host, BIT(2)); // SDHCI_RESET_DATA + arasan_sdhci_reset(host, SDHCI_RESET_CMD); + arasan_sdhci_reset(host, SDHCI_RESET_DATA); } sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); -- cgit v1.2.1 From 9190f984ec2cd0fee523a7be640672c8202bdf51 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 30 Mar 2023 14:46:41 +0200 Subject: video: Add of_get_display_timing Add a port of the kernel of_get_display_timing() that writes a struct fb_videomode instead of struct display_timing, which we don't have. Signed-off-by: Philipp Zabel Reviewed-by: Ahmad Fatoum Link: https://lore.barebox.org/20230330124643.3562397-2-p.zabel@pengutronix.de Signed-off-by: Sascha Hauer --- drivers/video/of_display_timing.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c index 6fe1e1b08b..6082d45493 100644 --- a/drivers/video/of_display_timing.c +++ b/drivers/video/of_display_timing.c @@ -98,6 +98,28 @@ static int of_parse_display_timing(const struct device_node *np, return 0; } +/** + * of_get_display_timing - parse a display_timing entry + * @np: device_node with the timing subnode + * @name: name of the timing node + * @mode: fb_videomode struct to fill + **/ +int of_get_display_timing(const struct device_node *np, const char *name, + struct fb_videomode *mode) +{ + struct device_node *timing_np; + + if (!np) + return -EINVAL; + + timing_np = of_get_child_by_name(np, name); + if (!timing_np) + return -ENOENT; + + return of_parse_display_timing(timing_np, mode); +} +EXPORT_SYMBOL_GPL(of_get_display_timing); + /** * of_get_display_timings - parse all display_timing entries from a device_node * @np: device_node with the subnodes -- cgit v1.2.1 From 0a4231985048fbac2d1d2fd375b640df2cfb0540 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 30 Mar 2023 14:46:42 +0200 Subject: video: add MIPI DBI framebuffer helpers Port helper functions for the panel-mipi-dbi driver from the Linux kernel. Signed-off-by: Philipp Zabel Link: https://lore.barebox.org/20230330124643.3562397-3-p.zabel@pengutronix.de Signed-off-by: Sascha Hauer --- drivers/video/mipi_dbi.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) (limited to 'drivers') diff --git a/drivers/video/mipi_dbi.c b/drivers/video/mipi_dbi.c index 50d2fc4b29..61b0fbcc49 100644 --- a/drivers/video/mipi_dbi.c +++ b/drivers/video/mipi_dbi.c @@ -8,11 +8,13 @@ #define pr_fmt(fmt) "mipi-dbi: " fmt #include +#include #include #include #include #include #include +#include