Re: [PATCH v2 12/40] mmc: dw_mmc: Replace fifoth_val property with fifo-depth
drivers/mmc/ftsdc010_mci.h b/drivers/mmc/ftsdc010_mci.h index 782d92be2f5f..36187cfa04f6 100644 --- a/drivers/mmc/ftsdc010_mci.h +++ b/drivers/mmc/ftsdc010_mci.h @@ -28,7 +28,6 @@ struct ftsdc010_chip { int dev_index; int dev_id; int buswidth; - u32 fifoth_val; struct mmc *mmc; void *priv; bool fifo_mode; diff --git a/drivers/mmc/hi6220_dw_mmc.c b/drivers/mmc/hi6220_dw_mmc.c index dc0210402bd2..e0b473f3f55c 100644 --- a/drivers/mmc/hi6220_dw_mmc.c +++ b/drivers/mmc/hi6220_dw_mmc.c @@ -37,7 +37,7 @@ struct hi6220_dwmmc_priv_data { struct hisi_mmc_data { unsigned int clock; bool use_fifo; - u32 fifoth_val; + u32 fifo_depth; }; static int hi6220_dwmmc_of_to_plat(struct udevice *dev) @@ -126,7 +126,7 @@ static int hi6220_dwmmc_probe(struct udevice *dev) host->mmc = &plat->mmc; host->fifo_mode = mmc_data->use_fifo; - host->fifoth_val = mmc_data->fifoth_val; + host->fifo_depth = mmc_data->fifo_depth; host->mmc->priv = &priv->host; upriv->mmc = host->mmc; host->mmc->dev = dev; @@ -159,8 +159,7 @@ static const struct hisi_mmc_data hi6220_mmc_data = { static const struct hisi_mmc_data hi3798mv2x_mmc_data = { .clock = 5000, .use_fifo = false, - // FIFO depth is 256 - .fifoth_val = MSIZE(4) | RX_WMARK(0x7f) | TX_WMARK(0x80), + .fifo_depth = 256, }; For HiSilicon changes in hi6220_dw_mmc.c, Reviewed-by: Yang Xiwen static const struct udevice_id hi6220_dwmmc_ids[] = { diff --git a/drivers/mmc/nexell_dw_mmc.c b/drivers/mmc/nexell_dw_mmc.c index 2723e4887cf7..aad848ca2825 100644 --- a/drivers/mmc/nexell_dw_mmc.c +++ b/drivers/mmc/nexell_dw_mmc.c @@ -187,10 +187,7 @@ static int nexell_dwmmc_probe(struct udevice *dev) struct dwmci_host *host = &priv->host; struct udevice *pwr_dev __maybe_unused; - host->fifoth_val = MSIZE(0x2) | - RX_WMARK(priv->fifo_size / 2 - 1) | - TX_WMARK(priv->fifo_size / 2); - + host->fifo_depth = priv->fifo_size; host->fifo_mode = priv->fifo_mode; dwmci_setup_cfg(&plat->cfg, host, priv->max_freq, priv->min_freq); diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index ad4529d6afa8..d52ae9cb6fd8 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -139,10 +139,7 @@ static int rockchip_dwmmc_probe(struct udevice *dev) if (ret < 0) return ret; #endif - host->fifoth_val = MSIZE(0x2) | - RX_WMARK(priv->fifo_depth / 2 - 1) | - TX_WMARK(priv->fifo_depth / 2); - + host->fifo_depth = priv->fifo_depth; host->fifo_mode = priv->fifo_mode; #if CONFIG_IS_ENABLED(MMC_PWRSEQ) diff --git a/drivers/mmc/snps_dw_mmc.c b/drivers/mmc/snps_dw_mmc.c index 0134399e3934..4a72f41ef16f 100644 --- a/drivers/mmc/snps_dw_mmc.c +++ b/drivers/mmc/snps_dw_mmc.c @@ -82,7 +82,7 @@ static int snps_dwmmc_of_to_plat(struct udevice *dev) host->ioaddr = dev_read_addr_ptr(dev); /* -* If fifo-depth is unset don't set fifoth_val - we will try to +* If fifo-depth is unset don't set fifo_depth - we will try to * auto detect it. */ ret = dev_read_u32(dev, "fifo-depth", &fifo_depth); @@ -90,9 +90,7 @@ static int snps_dwmmc_of_to_plat(struct udevice *dev) if (fifo_depth < FIFO_MIN || fifo_depth > FIFO_MAX) return -EINVAL; - host->fifoth_val = MSIZE(0x2) | - RX_WMARK(fifo_depth / 2 - 1) | - TX_WMARK(fifo_depth / 2); + host->fifo_depth = fifo_depth; } host->buswidth = dev_read_u32_default(dev, "bus-width", 4); diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c index 387cb8b6b50a..f795472d10f7 100644 --- a/drivers/mmc/socfpga_dw_mmc.c +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -135,8 +135,8 @@ static int socfpga_dwmmc_of_to_plat(struct udevice *dev) * We only have one dwmmc block on gen5 SoCFPGA. */ host->dev_index = 0; - host->fifoth_val = MSIZE(0x2) | - RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2); + + host->fifo_depth = fifo_depth; priv->drvsel = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), "drvsel", 3); priv->smplsel = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), diff --git a/include/dwmmc.h b/include/dwmmc.h index de18fda68ac8..7bb456e792b4 100644 --- a/include/dwmmc.h +++ b/include/dwmmc.h @@ -187,7 +187,7 @@ struct dwmci_idmac_regs { * @dev_index:Arbitrary device index for use by controller * @dev_id: Arbi
Re: [PATCH v2 3/3] mmc: hi6220_dw_mmc: add fifoth_val to private data and set it in .probe
On 4/3/2024 8:43 AM, Jaehoon Chung wrote: Hi On 2/1/24 23:05, Yang Xiwen via B4 Relay wrote: From: Yang Xiwen The value defaults to 0 and is ignored by dw_mmc code, so the other users are not affected. Setting this explicitly fixes some weird reading error found on Hi3798MV200. Fixes: 8a5dc8140e62 ("mmc: hi6220_dw_mmc: add compatible for HC2910 support") Signed-off-by: Yang Xiwen --- drivers/mmc/hi6220_dw_mmc.c | 11 ++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/hi6220_dw_mmc.c b/drivers/mmc/hi6220_dw_mmc.c index a4b8072976..dc0210402b 100644 --- a/drivers/mmc/hi6220_dw_mmc.c +++ b/drivers/mmc/hi6220_dw_mmc.c @@ -37,6 +37,7 @@ struct hi6220_dwmmc_priv_data { struct hisi_mmc_data { unsigned int clock; bool use_fifo; + u32 fifoth_val; }; static int hi6220_dwmmc_of_to_plat(struct udevice *dev) @@ -125,6 +126,7 @@ static int hi6220_dwmmc_probe(struct udevice *dev) host->mmc = &plat->mmc; host->fifo_mode = mmc_data->use_fifo; + host->fifoth_val = mmc_data->fifoth_val; host->mmc->priv = &priv->host; upriv->mmc = host->mmc; host->mmc->dev = dev; @@ -154,13 +156,20 @@ static const struct hisi_mmc_data hi6220_mmc_data = { .use_fifo = false, }; +static const struct hisi_mmc_data hi3798mv2x_mmc_data = { + .clock = 5000, + .use_fifo = false, + // FIFO depth is 256 Removed unnecessary comment. Will do. It seems that this should also apply to hi3798cv200-dw-mshc. tests are needed from cv200 users. Best Regards, Jaehoon Chung + .fifoth_val = MSIZE(4) | RX_WMARK(0x7f) | TX_WMARK(0x80), +}; + static const struct udevice_id hi6220_dwmmc_ids[] = { { .compatible = "hisilicon,hi6220-dw-mshc", .data = (ulong)&hi6220_mmc_data }, { .compatible = "hisilicon,hi3798cv200-dw-mshc", .data = (ulong)&hi6220_mmc_data }, { .compatible = "hisilicon,hi3798mv200-dw-mshc", - .data = (ulong)&hi6220_mmc_data }, + .data = (ulong)&hi3798mv2x_mmc_data }, { .compatible = "hisilicon,hi3660-dw-mshc", .data = (ulong)&hi3660_mmc_data }, { } -- Regards, Yang Xiwen
Re: [PATCH v2 2/3] mmc: dw_mmc: Don't return error if data busy timeout
On 4/3/2024 8:41 AM, Jaehoon Chung wrote: Hi, On 2/1/24 23:05, Yang Xiwen via B4 Relay wrote: From: Yang Xiwen As described in [1], some poor hardware or cards would fail to release the bus and keep driving data lines low. Ignore it and send the next cmd directly seems okay for most cases. This patch seems to be same with previous patch, right? From my observation, this patch does fix some weird problems and is mostly okay for other dwmmc users. I can't say it is very well tested because of I can't come up of other tests i can do except some `mmc read` and `mmc write`. Best Regards, Jaehoon Chung [1]: https://patchwork.kernel.org/project/linux-mmc/patch/1424458179-5456-1-git-send-email-diand...@chromium.org/ Signed-off-by: Yang Xiwen --- drivers/mmc/dw_mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 400066fa99..e103664145 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -262,8 +262,8 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { if (get_timer(start) > timeout) { - debug("%s: Timeout on data busy\n", __func__); - return -ETIMEDOUT; + debug("%s: Timeout on data busy, continue anyway\n", __func__); + break; } } -- Regards, Yang Xiwen
Re: [PATCH v2 1/3] mmc: hi6220-dwmmc: handle clocks and resets if CONFIG_CLK and CONFIG_DM_RESET enabled
On 4/3/2024 8:39 AM, Jaehoon Chung wrote: Hi, On 2/1/24 23:05, Yang Xiwen via B4 Relay wrote: From: Yang Xiwen This can avoid hardcoding a clock rate in driver. Also can enable the clocks and deassert the resets if the pre-bootloader does not do this for us. Currently only enabled for Hi3798MV200. Signed-off-by: Yang Xiwen --- drivers/mmc/hi6220_dw_mmc.c | 61 - 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/hi6220_dw_mmc.c b/drivers/mmc/hi6220_dw_mmc.c index 71962cd47e..a4b8072976 100644 --- a/drivers/mmc/hi6220_dw_mmc.c +++ b/drivers/mmc/hi6220_dw_mmc.c @@ -5,15 +5,24 @@ */ #include +#include #include #include #include #include #include +#include #include +#include DECLARE_GLOBAL_DATA_PTR; +enum hi6220_dwmmc_clk_type { + HI6220_DWMMC_CLK_BIU, + HI6220_DWMMC_CLK_CIU, + HI6220_DWMMC_CLK_CNT, +}; + struct hi6220_dwmmc_plat { struct mmc_config cfg; struct mmc mmc; @@ -21,6 +30,8 @@ struct hi6220_dwmmc_plat { struct hi6220_dwmmc_priv_data { struct dwmci_host host; + struct clk *clks[HI6220_DWMMC_CLK_CNT]; + struct reset_ctl_bulk rsts; }; struct hisi_mmc_data { @@ -32,7 +43,29 @@ static int hi6220_dwmmc_of_to_plat(struct udevice *dev) { struct hi6220_dwmmc_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; + int ret; If CONFIG_CLK and DM_RESET aren't enabled, this value is a dead code. It also needs to initialize. I think a alternative solution is replacing the if stmt below with some `#ifdef`s just like some unittests code. So we can mask variable `ret' out if it's not used However, this seems not favored by checkpatch.pl. + if (CONFIG_IS_ENABLED(CLK) && CONFIG_IS_ENABLED(DM_RESET)) { + priv->clks[HI6220_DWMMC_CLK_BIU] = devm_clk_get(dev, "biu"); + if (IS_ERR(priv->clks[HI6220_DWMMC_CLK_BIU])) { + ret = PTR_ERR(priv->clks[HI6220_DWMMC_CLK_BIU]); + dev_err(dev, "Failed to get BIU clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + priv->clks[HI6220_DWMMC_CLK_CIU] = devm_clk_get(dev, "ciu"); + if (IS_ERR(priv->clks[HI6220_DWMMC_CLK_CIU])) { + ret = PTR_ERR(priv->clks[HI6220_DWMMC_CLK_CIU]); + dev_err(dev, "Failed to get CIU clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + ret = reset_get_bulk(dev, &priv->rsts); + if (ret) { + dev_err(dev, "Failed to get resets(ret = %d)", ret); + return log_msg_ret("rst", ret); + } + } host->name = dev->name; host->ioaddr = dev_read_addr_ptr(dev); host->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), @@ -56,11 +89,37 @@ static int hi6220_dwmmc_probe(struct udevice *dev) struct hi6220_dwmmc_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; struct hisi_mmc_data *mmc_data; + int ret; Ditto. Best Regards, Jaehoon Chung mmc_data = (struct hisi_mmc_data *)dev_get_driver_data(dev); - /* Use default bus speed due to absence of clk driver */ host->bus_hz = mmc_data->clock; + if (CONFIG_IS_ENABLED(CLK) && CONFIG_IS_ENABLED(DM_RESET)) { + ret = clk_prepare_enable(priv->clks[HI6220_DWMMC_CLK_BIU]); + if (ret) { + dev_err(dev, "Failed to enable biu clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + ret = clk_prepare_enable(priv->clks[HI6220_DWMMC_CLK_CIU]); + if (ret) { + dev_err(dev, "Failed to enable ciu clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + ret = reset_deassert_bulk(&priv->rsts); + if (ret) { + dev_err(dev, "Failed to deassert resets(ret = %d).\n", ret); + return log_msg_ret("rst", ret); + } + + host->bus_hz = clk_get_rate(priv->clks[HI6220_DWMMC_CLK_CIU]); + if (host->bus_hz <= 0) { + dev_err(dev, "Failed to get ciu clock rate(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + } + dev_dbg(dev, "bus clock rate: %d.\n", host->bus_hz); dwmci_setup_cfg(&plat->cfg, host, host->bus_hz, 40); host->mmc = &plat->mmc; -- Regards, Yang Xiwen
Re: [PATCH] clk: Propagate clk_set_rate() if CLK_SET_PARENT_RATE present
On 3/20/2024 2:42 AM, Sam Protsenko wrote: On Thu, Mar 7, 2024 at 6:04 PM Sam Protsenko wrote: Sometimes clocks provided to a consumer might not have .set_rate operation (like gate or mux clocks), but have CLK_SET_PARENT_RATE flag set. In that case it's usually possible to find a parent up the tree which is capable of setting the rate (div, pll, etc). Implement a simple lookup procedure for such cases, to traverse the clock tree until .set_rate capable parent is found, and use that parent to actually change the rate. The search will stop once the first .set_rate capable clock is found, which is usually enough to handle most cases. Signed-off-by: Sam Protsenko --- Hi Lukasz, Sean, Tom, If this patch looks good to you and there are no outstanding comments, can you please apply it? It's needed as a part of eMMC enablement for E850-96 board, as eMMC gate (leaf) clock is specified as ciu clock in dts, which requires further clock rate change propagation up to divider clock. Thanks! Please be patient. The release cycle is quite long. My patch set for HiSilicon clk framework has been ignored for ~2months already. drivers/clk/clk-uclass.c | 16 ++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index ed6e60bc4841..755f05f34669 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -571,8 +571,20 @@ ulong clk_set_rate(struct clk *clk, ulong rate) return 0; ops = clk_dev_ops(clk->dev); - if (!ops->set_rate) - return -ENOSYS; + /* Try to find parents which can set rate */ + while (!ops->set_rate) { + struct clk *parent; + + if (!(clk->flags & CLK_SET_RATE_PARENT)) + return -ENOSYS; + + parent = clk_get_parent(clk); + if (IS_ERR_OR_NULL(parent) || !clk_valid(parent)) + return -ENODEV; + + clk = parent; + ops = clk_dev_ops(clk->dev); + } /* get private clock struct used for cache */ clk_get_priv(clk, &clkp); -- 2.39.2 -- Regards, Yang Xiwen
Re: [PATCH v3] clk: set initial best mux parent to current parent with CLK_MUX_ROUND_CLOSEST
On 3/11/2024 5:34 PM, Maxime Ripard wrote: On Thu, Mar 07, 2024 at 07:18:05PM +0800, Yang Xiwen wrote: On 3/7/2024 4:48 PM, Maxime Ripard wrote: Hi, On Thu, Mar 07, 2024 at 10:03:50AM +0800, Yang Xiwen via B4 Relay wrote: From: Yang Xiwen Originally, the initial clock rate is hardcoded to 0, this can lead to some problem when setting a very small rate with CLK_MUX_ROUND_CLOSEST. For example, if the lowest possible rate provided by the mux is 1000Hz, setting a rate below 500Hz will fail, because no clock can provide a better rate than the non-existant 0Hz. But it should succeed with 1000Hz being set. Setting the initial best parent to current parent could solve this bug. Signed-off-by: Yang Xiwen I don't think it would be the way to go. The biggest issue to me is that it's inconsistent, and only changing the behaviour for a given flag doesn't solve that. I think the current behavior is odd but conforms to the document if CLK_MUX_ROUND_CLOSEST is not specified. clk_mux_determine_rate_flags isn't documented, and the determine_rate clk_ops documentation doesn't mention it can return an error. If i understand correctly, the default behavior of mux clocks is to select the closest rate lower than requested rate, and CLK_MUX_ROUND_CLOSEST removes the "lower than" limitation, which is what this version tries to accomplish. The situation is not as clear-cut as you make it to be, unfortunately. The determine_rate clk_ops implementation states: Given a target rate as input, returns the closest rate actually supported by the clock, and optionally the parent clock that should be used to provide the clock rate. So CLK_MUX_ROUND_CLOSEST shouldn't exist, because that's what determine_rate expects so it should always be there. Now, the "actually supported by the clock" can be interpreted in multiple ways, and most importantly, doesn't state what the behaviour is if we can't find a rate actually supported by the clock. But now, this situation has been ambiguous for a while and thus drivers kind of relied on that ambiguity. So the way to fix it up is: - Assess what drivers are relying on - Document the current behaviour in clk_ops determine_rate From my investigation, it's totally a mess, especially for platform clk drivers (PLL). Some drivers always round down, the others round to nearest, with or without a specific flag to switch between them, depend on the division functions they choose. Fixing all of them seems needs quite a lot of time and would probably introduce some regressions. We'd probably only have to say both rounding to nearest and rounding down are acceptable, though either one is preferred. - Make clk_mux_determine_rate_flags consistent with that I think we must keep existing flags and document the current behavior correctly because of the massive existing users of clk_mux. That's why i'm going to only fix CLK_MUX_ROUND_CLOSEST users. Hopefully it won't cause too many regressions. - Run that through kernelci to make sure we don't have any regression We don't. I run 'tools/testing/kunit/kunit.py run --kunitconfig drivers/clk/.kunitconfig' each time before i send patches. Over all, it seems quite a lot of work here. Maxime The situation here becomes even more complex when it comes to U-Boot clk framework. They chose slightly different prototypes and stated clk_set_rate() can fail with -ve. It's a great burden for clk driver authors and maintainers when they try to port their drivers to U-Boot. Let's Cc U-Boot clk maintainers as well, and see how we can resolve the mess here. -- Regards, Yang Xiwen
[PATCH v2] serial: pl01x: set baudrate when probing
From: Yang Xiwen It is found that when DM is enabled, only generic init function is called in .probe(). Baudrate is never honored. Add a function call to .setbrg() when probing so that we can update the baudrate of the serial device. Signed-off-by: Yang Xiwen --- Changes in v2: - reverse if statement (Dan Carpenter) - Link to v1: https://lore.kernel.org/r/20240123-b4-pl011-v1-1-fb576d0a7...@outlook.com --- drivers/serial/serial_pl01x.c | 11 --- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index 428a4d210de5..f04c21e08264 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -290,6 +290,7 @@ int pl01x_serial_probe(struct udevice *dev) { struct pl01x_serial_plat *plat = dev_get_plat(dev); struct pl01x_priv *priv = dev_get_priv(dev); + int ret; #if CONFIG_IS_ENABLED(OF_PLATDATA) struct dtd_serial_pl01x *dtplat = &plat->dtplat; @@ -301,10 +302,14 @@ int pl01x_serial_probe(struct udevice *dev) #endif priv->type = plat->type; - if (!plat->skip_init) - return pl01x_generic_serial_init(priv->regs, priv->type); - else + if (!plat->skip_init) { + ret = pl01x_generic_serial_init(priv->regs, priv->type); + if (ret) + return ret; + return pl01x_serial_setbrg(dev, gd->baudrate); + } else { return 0; + } } int pl01x_serial_getc(struct udevice *dev) --- base-commit: f7cca7ccc5117eaafcc2bde91ad1bed6fee7cfc3 change-id: 20240123-b4-pl011-ee9575ff2a38 Best regards, -- Yang Xiwen
Re: [PATCH RESEND] serial: pl01x: set baudrate when probing
On 2/26/2024 4:23 PM, Dan Carpenter wrote: > On Sun, Feb 25, 2024 at 08:38:33AM +0800, Yang Xiwen via B4 Relay wrote: >> #if CONFIG_IS_ENABLED(OF_PLATDATA) >> struct dtd_serial_pl01x *dtplat = &plat->dtplat; >> @@ -301,10 +302,14 @@ int pl01x_serial_probe(struct udevice *dev) >> #endif >> priv->type = plat->type; >> >> -if (!plat->skip_init) >> -return pl01x_generic_serial_init(priv->regs, priv->type); >> -else >> +if (!plat->skip_init) { >> +ret = pl01x_generic_serial_init(priv->regs, priv->type); >> +if (!ret) > > This if statement seems to be reversed. Seems correct. Maybe i sent the wrong version. > > regards, > dan carpenter > >> +return ret; >> + return pl01x_serial_setbrg(dev, gd->baudrate); >> +} else { >> return 0; >> +} >> } > -- Best regards, Yang Xiwen
[PATCH RESEND] serial: pl01x: set baudrate when probing
From: Yang Xiwen It is found that when DM is enabled, only generic init function is called in .probe(). Baudrate is never honored. Add a function call to .setbrg() when probing so that we can update the baudrate of the serial device. Signed-off-by: Yang Xiwen --- drivers/serial/serial_pl01x.c | 11 --- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index 428a4d210de5..57bbcaf3b619 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -290,6 +290,7 @@ int pl01x_serial_probe(struct udevice *dev) { struct pl01x_serial_plat *plat = dev_get_plat(dev); struct pl01x_priv *priv = dev_get_priv(dev); + int ret; #if CONFIG_IS_ENABLED(OF_PLATDATA) struct dtd_serial_pl01x *dtplat = &plat->dtplat; @@ -301,10 +302,14 @@ int pl01x_serial_probe(struct udevice *dev) #endif priv->type = plat->type; - if (!plat->skip_init) - return pl01x_generic_serial_init(priv->regs, priv->type); - else + if (!plat->skip_init) { + ret = pl01x_generic_serial_init(priv->regs, priv->type); + if (!ret) + return ret; + return pl01x_serial_setbrg(dev, gd->baudrate); + } else { return 0; + } } int pl01x_serial_getc(struct udevice *dev) --- base-commit: f7cca7ccc5117eaafcc2bde91ad1bed6fee7cfc3 change-id: 20240123-b4-pl011-ee9575ff2a38 Best regards, -- Yang Xiwen
Re: [PATCH RFC] pinctrl: add support for HiSilicon HiSTB SoCs
On 2/13/2024 1:08 AM, Tom Rini wrote: On Tue, Feb 13, 2024 at 01:02:50AM +0800, Yang Xiwen wrote: On 2/13/2024 12:58 AM, Tom Rini wrote: On Tue, Feb 13, 2024 at 12:30:15AM +0800, Yang Xiwen via B4 Relay wrote: From: Yang Xiwen The first supported SoC is Hi3798MV200. Signed-off-by: Yang Xiwen --- This patchset adds support for HiSTB ioconfig module. The module is used to set pins config(e.g. pull-up, pull-down, drive-strength etc..) and pinmux. The first supported chip is Hi3798MV200. Adding support for Hi3798CV200 should be also easy. Below is an example of the dts node: [snip] Has this binding already been accepted to the kernel? Thanks. No, I've not wrote the driver for linux yet. That's why it is RFC now. But it is expected to be soon. I'm going to finish u-boot part first and work on linux kernel later. After that, i can sync linux dts and bindings back to u-boot. How soon before you start on the Linux side of things? Given that this wouldn't be merged for v2024.04, there's plenty of time to get that Linux side going (or at least the binding reviewed and accepted to -next or similar) before merging here, and for U-Boot the biggest feedback (aside from anything checkpatch.pl may say) would be to get the binding reviewed. Sadly, it's not on my urgent list, since we only need to setup pinctrl stuff once during boot. Not even this SoC(Hi3798MV200) is supported in mainline Linux yet. I'm keeping working on this, but I really can't say how soon i can start working on Linux side. Though I can say it's not going to be very soon if i'm the only one who is working on this platform. Maybe Jorge and Igor can join and speed up the process. Since Hi3798CV200 is supported by mainline(This SoC is used by 96boards poplar), writing a pinctrl driver for that SoC would receive more comments and reviews. -- Regards, Yang Xiwen
Re: [PATCH RFC] pinctrl: add support for HiSilicon HiSTB SoCs
On 2/13/2024 12:58 AM, Tom Rini wrote: On Tue, Feb 13, 2024 at 12:30:15AM +0800, Yang Xiwen via B4 Relay wrote: From: Yang Xiwen The first supported SoC is Hi3798MV200. Signed-off-by: Yang Xiwen --- This patchset adds support for HiSTB ioconfig module. The module is used to set pins config(e.g. pull-up, pull-down, drive-strength etc..) and pinmux. The first supported chip is Hi3798MV200. Adding support for Hi3798CV200 should be also easy. Below is an example of the dts node: [snip] Has this binding already been accepted to the kernel? Thanks. No, I've not wrote the driver for linux yet. That's why it is RFC now. But it is expected to be soon. I'm going to finish u-boot part first and work on linux kernel later. After that, i can sync linux dts and bindings back to u-boot. -- Regards, Yang Xiwen
[PATCH RFC] pinctrl: add support for HiSilicon HiSTB SoCs
From: Yang Xiwen The first supported SoC is Hi3798MV200. Signed-off-by: Yang Xiwen --- This patchset adds support for HiSTB ioconfig module. The module is used to set pins config(e.g. pull-up, pull-down, drive-strength etc..) and pinmux. The first supported chip is Hi3798MV200. Adding support for Hi3798CV200 should be also easy. Below is an example of the dts node: ```dts ioconfig: pinctrl@8a21000 { compatible = "hisilicon,hi3798mv200-ioconfig"; reg = <0x8a21000 0x180>; #pinctrl-cells = <1>; emmc_default: emmc-default-state { cdata-pins { // CDATA0-7 pins = "W20", "V20", "U20", "V19", "Y21", "W21", "V21", "U21"; bias-pullup; slew-rate = <1>; drive-strength = <8>; function = "emmc_cdata"; }; cclk-pin { pins = "T18"; bias-pullup; slew-rate = <1>; drive-strength = <8>; function = "emmc_cclk"; }; ccmd-pin { pins = "T20"; bias-pullup; slew-rate = <1>; drive-strength = <6>; function = "emmc_ccmd"; }; reset-pin { pins = "R20"; bias-disable; slew-rate = <1>; drive-strength = <1>; function = "emmc_rst"; }; datastrobe-pin { pins = "R21"; bias-pullup; slew-rate; drive-strength = <1>; function = "emmc_datastrobe"; }; }; }; ``` --- drivers/pinctrl/Kconfig| 1 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/hisilicon/Kconfig | 21 ++ drivers/pinctrl/hisilicon/Makefile | 6 + drivers/pinctrl/hisilicon/pinctrl-hi3798mv2x.c | 319 + drivers/pinctrl/hisilicon/pinctrl-histb.c | 276 + drivers/pinctrl/hisilicon/pinctrl-histb.h | 132 ++ 7 files changed, 756 insertions(+) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index a1d53cfbdb..d600a30492 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -346,6 +346,7 @@ endif source "drivers/pinctrl/broadcom/Kconfig" source "drivers/pinctrl/exynos/Kconfig" +source "drivers/pinctrl/hisilicon/Kconfig" source "drivers/pinctrl/intel/Kconfig" source "drivers/pinctrl/mediatek/Kconfig" source "drivers/pinctrl/meson/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 0e929d8ca0..79fb800faf 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -36,3 +36,4 @@ obj-$(CONFIG_$(SPL_)PINCTRL_STMFX)+= pinctrl-stmfx.o obj-y += broadcom/ obj-$(CONFIG_PINCTRL_ZYNQMP) += pinctrl-zynqmp.o obj-$(CONFIG_PINCTRL_STARFIVE) += starfive/ +obj-$(CONFIG_PINCTRL_HISILICON)+= hisilicon/ diff --git a/drivers/pinctrl/hisilicon/Kconfig b/drivers/pinctrl/hisilicon/Kconfig new file mode 100644 index 00..33c3048940 --- /dev/null +++ b/drivers/pinctrl/hisilicon/Kconfig @@ -0,0 +1,21 @@ +config PINCTRL_HISILICON + bool + +config PINCTRL_HISTB + bool "HiSilicon HiSTB pinctrl framework" + depends on PINCTRL + select PINCTRL_HISILICON + imply PINCONF + help + Support HiSTB SoCs IOCONFIG module + +menu "HiSTB pinctrl drivers" + depends on PINCTRL_HISTB + +config PINCTRL_HI3798MV2X + bool "HiSilicon Hi3798MV2X pinctrl driver" + depends on ARCH_HI3798MV2X + help + Support IOCONFIG on Hi3798MV2X SoCs + +endmenu diff --git a/drivers/pinctrl/hisilicon/Makefile b/drivers/pinctrl/hisilicon/Makefile new file mode 100644 index 00..5afb64d4b6 --- /dev/null +++ b/drivers/pinctrl/hisilicon/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright 2024 (r) Yang Xiwen + +obj-$(CONFIG_PINCTRL_HISTB)+= pinctrl-histb.o +obj-$(CONFIG_PINCTRL_HI3798MV2X) += pinctrl-hi3798mv2x.o diff --git a/drivers/pinctrl/hisilicon/pinctrl-hi3798mv2x.c b/drivers/pinctrl/hisilicon/pinctrl-hi3798mv2x.c new file mode 100644 index 00..1e0a89675a --- /dev/null +++ b/drivers/pinctrl/hi
[PATCH v2 3/3] usb: ehci: Make usage of generic_{setup,shutdown}_phy_bulk() helpers
From: Yang Xiwen Replace generic_setup_phy() and generic_shutdown_phy() by respectively generic_setup_phy_bulk() and generic_shutdown_phy_bulk(). Signed-off-by: Yang Xiwen --- drivers/usb/host/ehci-generic.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/ehci-generic.c b/drivers/usb/host/ehci-generic.c index 936e30438d..e109d84d73 100644 --- a/drivers/usb/host/ehci-generic.c +++ b/drivers/usb/host/ehci-generic.c @@ -25,7 +25,7 @@ struct generic_ehci { struct ehci_ctrl ctrl; struct clk_bulk clocks; struct reset_ctl_bulk resets; - struct phy phy; + struct phy_bulk phys; struct udevice *vbus_supply; }; @@ -95,7 +95,7 @@ static int ehci_usb_probe(struct udevice *dev) if (err) goto reset_err; - err = generic_setup_phy(dev, &priv->phy, 0); + err = generic_setup_phy_bulk(dev, &priv->phys); if (err) goto regulator_err; @@ -110,7 +110,7 @@ static int ehci_usb_probe(struct udevice *dev) return 0; phy_err: - ret = generic_shutdown_phy(&priv->phy); + ret = generic_shutdown_phy_bulk(&priv->phys); if (ret) dev_err(dev, "failed to shutdown usb phy (ret=%d)\n", ret); @@ -140,7 +140,7 @@ static int ehci_usb_remove(struct udevice *dev) if (ret) return ret; - ret = generic_shutdown_phy(&priv->phy); + ret = generic_shutdown_phy_bulk(&priv->phys); if (ret) return ret; -- 2.43.0
[PATCH v2 0/3] usb: ehci-generic: setup a bulk of phy when possible
one USB controller can have multiple ports specified in dts, all of them should be setup to make use of all possible ports. Signed-off-by: Yang Xiwen --- Changes in v2: - Rewrite generic_phy_setup_bulk(): Actually v1 is doing things completely wrong. This series should work and it's tested on a real machine. - Link to v1: https://lore.kernel.org/r/20240201-ehci-v1-0-bb506cb0f...@outlook.com --- Yang Xiwen (3): phy: add generic_setup(shutdown)_phy_bulk() test: phy: test generic_setup(shutdown)_phy_bulk() usb: ehci: Make usage of generic_{setup,shutdown}_phy_bulk() helpers drivers/phy/phy-uclass.c| 41 + drivers/usb/host/ehci-generic.c | 8 include/generic-phy.h | 29 + test/dm/phy.c | 4 4 files changed, 78 insertions(+), 4 deletions(-) --- base-commit: b6d8969bcb94321dfed1399f2eaa8768ba42caaa change-id: 20240201-ehci-6c3aa7d97932 Best regards, -- Yang Xiwen
[PATCH v2 2/3] test: phy: test generic_setup(shutdown)_phy_bulk()
From: Yang Xiwen add unittests for the newly introduced helper functions. Signed-off-by: Yang Xiwen --- test/dm/phy.c | 4 1 file changed, 4 insertions(+) diff --git a/test/dm/phy.c b/test/dm/phy.c index 0cf3689fde..cb16844a0a 100644 --- a/test/dm/phy.c +++ b/test/dm/phy.c @@ -159,6 +159,8 @@ static int dm_test_phy_bulk(struct unit_test_state *uts) ut_asserteq(0, generic_phy_power_on_bulk(&phys)); ut_asserteq(0, generic_phy_power_off_bulk(&phys)); ut_asserteq(0, generic_phy_exit_bulk(&phys)); + ut_asserteq(0, generic_setup_phy_bulk(parent, &phys)); + ut_asserteq(0, generic_shutdown_phy_bulk(&phys)); /* has a known problem phy */ ut_assertok(uclass_get_device_by_name(UCLASS_SIMPLE_BUS, @@ -171,6 +173,8 @@ static int dm_test_phy_bulk(struct unit_test_state *uts) ut_asserteq(-EIO, generic_phy_power_on_bulk(&phys)); ut_asserteq(-EIO, generic_phy_power_off_bulk(&phys)); ut_asserteq(0, generic_phy_exit_bulk(&phys)); + ut_asserteq(-EIO, generic_setup_phy_bulk(parent, &phys)); + ut_asserteq(-EIO, generic_shutdown_phy_bulk(&phys)); return 0; } -- 2.43.0
[PATCH v2 1/3] phy: add generic_setup(shutdown)_phy_bulk()
From: Yang Xiwen They are the bulk version of generic_setup(shutdown)_phy(). Signed-off-by: Yang Xiwen --- drivers/phy/phy-uclass.c | 41 + include/generic-phy.h| 29 + 2 files changed, 70 insertions(+) diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index 0dcfe258bc..1a6bb54290 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -528,6 +528,36 @@ int generic_setup_phy(struct udevice *dev, struct phy *phy, int index) return ret; } +int generic_setup_phy_bulk(struct udevice *dev, struct phy_bulk *bulk) +{ + int ret; + + ret = generic_phy_get_bulk(dev, bulk); + if (ret) { + pr_err("Can't get PHY bulk: %d\n", ret); + goto phys_get_err; + } + + ret = generic_phy_init_bulk(bulk); + if (ret) { + pr_err("Can't init PHY bulk: %d\n", ret); + goto phys_get_err; + } + + ret = generic_phy_power_on_bulk(bulk); + if (ret) { + generic_phy_exit_bulk(bulk); + goto phys_setup_err; + } + + return 0; + +phys_setup_err: + generic_phy_exit_bulk(bulk); +phys_get_err: + return ret; +} + int generic_shutdown_phy(struct phy *phy) { int ret; @@ -542,6 +572,17 @@ int generic_shutdown_phy(struct phy *phy) return generic_phy_exit(phy); } +int generic_shutdown_phy_bulk(struct phy_bulk *bulk) +{ + struct phy *phys = bulk->phys; + int i, ret = 0; + + for (i = 0; i < bulk->count; i++) + ret |= generic_shutdown_phy(&phys[i]); + + return ret; +} + UCLASS_DRIVER(phy) = { .id = UCLASS_PHY, .name = "phy", diff --git a/include/generic-phy.h b/include/generic-phy.h index eaab749166..2d1bf7c1ea 100644 --- a/include/generic-phy.h +++ b/include/generic-phy.h @@ -420,6 +420,16 @@ int generic_phy_power_off_bulk(struct phy_bulk *bulk); */ int generic_setup_phy(struct udevice *dev, struct phy *phy, int index); +/** + * generic_setup_phy() - Get, initialize and power on all phys in a phy bulk. + * + * @dev: The consumer device. + * @bulk: A pointer to the PHY bulk + * + * Return: 0 if OK, or negative error code. + */ +int generic_setup_phy_bulk(struct udevice *dev, struct phy_bulk *bulk); + /** * generic_shutdown_phy() - Power off and de-initialize phy. * @@ -429,6 +439,15 @@ int generic_setup_phy(struct udevice *dev, struct phy *phy, int index); */ int generic_shutdown_phy(struct phy *phy); +/** + * generic_shutdown_phy_bulk() - Power off and de-initialize all phys in a phy bulk. + * + * @bulk: A pointer to the PHY bulk. + * + * Return: 0 if OK, or negative error code. + */ +int generic_shutdown_phy_bulk(struct phy_bulk *bulk); + #else /* CONFIG_PHY */ static inline int generic_phy_init(struct phy *phy) @@ -514,11 +533,21 @@ static inline int generic_setup_phy(struct udevice *dev, struct phy *phy, int in return 0; } +static inline int generic_setup_phy_bulk(struct udevice *dev, struct phy_bulk *bulk) +{ + return 0; +} + static inline int generic_shutdown_phy(struct phy *phy) { return 0; } +static inline int generic_shutdown_phy_bulk(struct phy_bulk *bulk) +{ + return 0; +} + #endif /* CONFIG_PHY */ /** -- 2.43.0
Re: [PATCH 1/3] usb: dwc3: handle return value of clk_get_rate() correctly
On 2/5/2024 3:25 PM, Dan Carpenter wrote: On Sat, Feb 03, 2024 at 07:01:54AM +0800, Yang Xiwen via B4 Relay wrote: From: Yang Xiwen clk_get_rate() return -ve on error, not 0. Fix it by replacing judging NULL with IS_ERR_VALUE(). s/NULL/zero/. I'd be surprised if clk_get_rate() *never* returns zero. The Linux kernel's clk_get_rate() function returns zero and not error codes, btw. Yes, it's really surprising. U-Boot clk APIs are a little different from Linux kernel's. Sadly it's a bit too late to fix it since there are really plenty of existing users. Maybe we need to put some hints in the docs. regards, dan carpenter -- Regards, Yang Xiwen
Re: [PATCH] poplar: add myself as co-maintainer
On 2/3/2024 6:19 PM, Jorge Ramirez-Ortiz, Gmail wrote: On 03/02/24 17:45:42, Yang Xiwen wrote: On 2/3/2024 4:32 PM, Jorge Ramirez-Ortiz, Gmail wrote: On 03/02/24 07:54:22, Shawn Guo wrote: On Sat, Feb 3, 2024 at 5:44 AM Igor Opaniuk wrote: Add myself as co-maintainer for Poplar board, as I'm currently working on it (re-testing releases, addressing issues etc). CC: Jorge Ramirez-Ortiz CC: Shawn Guo Signed-off-by: Igor Opaniuk Acked-by: Shawn Guo I'm not actively working on poplar any more, so maybe remove me in the meantime. hi Igor, Yes please go ahead and thanks for offering. I'll sync with you later next week (I found my Poplar in storage, so maybe we cam improve things a little) Also it would be good if we knew there are still users. Acked-by: Jorge Ramirez-Ortiz Hi, everyone. I'm working on a set-top box with a Hi3798MV200 SoC. It is very similar to the Hi3798CV200 SoC and many peripherals and drivers can be reused. I think you can try moving arch/arm/include/asm/arch-hi3798cv200 to arch/arm/mach-histb and let's maintain all HiSTB series SoCs/boards under it altogether? The same thing also applies to TF-A. Currently upstream code refers to poplar everywhere but actually the port is portable enough to handle a lot of other Hi3798-series SoCs such as Hi3798MV2x, Hi3798MV3x etc.. Sure, if this is indeed a family we should do that (documentation was scarce back them when I did the initial port). About docs, I've got some. But still, some critical datasheets are missing. Most peripherals are the common ones, like DWC3(USB), PL061(GPIO), DWMMC(eMMC/SD), PL011(serial), SP905(watchdog). But there are some cores that are difficult to find docs. e.g. USB2 INNO PHY, USB3 nano PHY, PMU, TZPC/TZASC, HDMI etc.. Please ping me if you find some documents about them. Especially PMU and USB PHYs, it's quite hard to write a mainline driver for them without datasheets. maybe you'd like to take a stab Igor? Shawn
Re: [PATCH] poplar: add myself as co-maintainer
On 2/3/2024 5:45 PM, Yang Xiwen wrote: On 2/3/2024 4:32 PM, Jorge Ramirez-Ortiz, Gmail wrote: On 03/02/24 07:54:22, Shawn Guo wrote: On Sat, Feb 3, 2024 at 5:44 AM Igor Opaniuk wrote: Add myself as co-maintainer for Poplar board, as I'm currently working on it (re-testing releases, addressing issues etc). CC: Jorge Ramirez-Ortiz CC: Shawn Guo Signed-off-by: Igor Opaniuk Acked-by: Shawn Guo I'm not actively working on poplar any more, so maybe remove me in the meantime. hi Igor, Yes please go ahead and thanks for offering. I'll sync with you later next week (I found my Poplar in storage, so maybe we cam improve things a little) Also it would be good if we knew there are still users. Acked-by: Jorge Ramirez-Ortiz Hi, everyone. I'm working on a set-top box with a Hi3798MV200 SoC. It is very similar to the Hi3798CV200 SoC and many peripherals and drivers can be reused. I think you can try moving arch/arm/include/asm/arch-hi3798cv200 to arch/arm/mach-histb and let's maintain all HiSTB series SoCs/boards under it altogether? The same thing also applies to TF-A. Currently upstream code refers to poplar everywhere but actually the port is portable enough to handle a lot of other Hi3798-series SoCs such as Hi3798MV2x, Hi3798MV3x etc.. There are some patches i sent pending for review. They are mostly originally sent just for Hi3798MV200, but the framework(such as drivers/clk/hisilicon) can be also used for poplar too. I hope you guys can take a look at them[1] and give your opinions about them(RBs and Acks are welcomed). [1] HiSi clk framework: https://lore.kernel.org/u-boot/20240119-b4-hisi-clk-v1-0-279e38c95...@outlook.com/ Shawn
Re: [PATCH] poplar: add myself as co-maintainer
On 2/3/2024 4:32 PM, Jorge Ramirez-Ortiz, Gmail wrote: On 03/02/24 07:54:22, Shawn Guo wrote: On Sat, Feb 3, 2024 at 5:44 AM Igor Opaniuk wrote: Add myself as co-maintainer for Poplar board, as I'm currently working on it (re-testing releases, addressing issues etc). CC: Jorge Ramirez-Ortiz CC: Shawn Guo Signed-off-by: Igor Opaniuk Acked-by: Shawn Guo I'm not actively working on poplar any more, so maybe remove me in the meantime. hi Igor, Yes please go ahead and thanks for offering. I'll sync with you later next week (I found my Poplar in storage, so maybe we cam improve things a little) Also it would be good if we knew there are still users. Acked-by: Jorge Ramirez-Ortiz Hi, everyone. I'm working on a set-top box with a Hi3798MV200 SoC. It is very similar to the Hi3798CV200 SoC and many peripherals and drivers can be reused. I think you can try moving arch/arm/include/asm/arch-hi3798cv200 to arch/arm/mach-histb and let's maintain all HiSTB series SoCs/boards under it altogether? The same thing also applies to TF-A. Currently upstream code refers to poplar everywhere but actually the port is portable enough to handle a lot of other Hi3798-series SoCs such as Hi3798MV2x, Hi3798MV3x etc.. Shawn
[PATCH 2/3] usb: dwc3: replace argument mode with child ofnode
From: Yang Xiwen child ofnode is more useful and can be used to query a lot of other props of child device. dr_mode can be also queried from it. Signed-off-by: Yang Xiwen --- drivers/usb/dwc3/dwc3-generic.c | 12 drivers/usb/dwc3/dwc3-generic.h | 3 +-- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 6fb2de8a5a..d892042b91 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -272,8 +272,7 @@ U_BOOT_DRIVER(dwc3_generic_host) = { }; #endif -void dwc3_imx8mp_glue_configure(struct udevice *dev, int index, - enum usb_dr_mode mode) +void dwc3_imx8mp_glue_configure(struct udevice *dev, ofnode child, int index) { /* USB glue registers */ #define USB_CTRL0 0x00 @@ -323,8 +322,7 @@ struct dwc3_glue_ops imx8mp_ops = { .glue_configure = dwc3_imx8mp_glue_configure, }; -void dwc3_ti_glue_configure(struct udevice *dev, int index, - enum usb_dr_mode mode) +void dwc3_ti_glue_configure(struct udevice *dev, ofnode child, int index) { #define USBOTGSS_UTMI_OTG_STATUS 0x0084 #define USBOTGSS_UTMI_OTG_OFFSET 0x0480 @@ -348,6 +346,7 @@ enum dwc3_omap_utmi_mode { u32 reg; u32 utmi_mode; u32 utmi_status_offset = USBOTGSS_UTMI_OTG_STATUS; + enum usb_dr_mode mode = usb_get_dr_mode(child); struct dwc3_glue_data *glue = dev_get_plat(dev); void *base = map_physmem(glue->regs, 0x1, MAP_NOCACHE); @@ -577,12 +576,9 @@ int dwc3_glue_probe(struct udevice *dev) } while (child) { - enum usb_dr_mode dr_mode; - - dr_mode = usb_get_dr_mode(dev_ofnode(child)); device_find_next_child(&child); if (ops && ops->glue_configure) - ops->glue_configure(dev, index, dr_mode); + ops->glue_configure(dev, dev_ofnode(child), index); index++; } diff --git a/drivers/usb/dwc3/dwc3-generic.h b/drivers/usb/dwc3/dwc3-generic.h index 40902c8923..46c14a338b 100644 --- a/drivers/usb/dwc3/dwc3-generic.h +++ b/drivers/usb/dwc3/dwc3-generic.h @@ -22,8 +22,7 @@ struct dwc3_glue_data { struct dwc3_glue_ops { int (*glue_get_ctrl_dev)(struct udevice *parent, ofnode *node); - void (*glue_configure)(struct udevice *dev, int index, - enum usb_dr_mode mode); + void (*glue_configure)(struct udevice *parent, ofnode node, int index); }; int dwc3_glue_bind(struct udevice *parent); -- 2.43.0
[PATCH 3/3] usb: dwc3: add glue driver for Hi3798MV200
From: Yang Xiwen It needs some platform-specific operations before generic initialization code. If nano PHY is not initialized properly, it must be disabled. Or else USB host will complain unable to reset port. USB2 is always supported, so it's never disabled. Signed-off-by: Yang Xiwen --- drivers/usb/dwc3/dwc3-generic.c | 40 1 file changed, 40 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index d892042b91..a3200ff1ab 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -419,6 +419,45 @@ struct dwc3_glue_ops rk_ops = { .glue_get_ctrl_dev = dwc3_rk_glue_get_ctrl_dev, }; +static void dwc3_hi3798mv200_glue_configure(struct udevice *dev, ofnode child, int index) +{ +#define HI3798MV200_PERI_CTRL_ADDR 0xf8a2 +#define HI3798MV200_PERI_USB5 0x134 +#define USB3_U3_PORT_DISABLE BIT(5) +#define USB3_U2_PORT_DISABLE BIT(4) + + // Disable super-speed port if maximum speed is high-speed + void __iomem *peri_base = map_physmem(HI3798MV200_PERI_CTRL_ADDR, 0x1000, MAP_NOCACHE); + enum usb_device_speed speed = usb_get_maximum_speed(child); + u32 reg; + + reg = readl(peri_base + HI3798MV200_PERI_USB5); + reg &= ~(USB3_U3_PORT_DISABLE | USB3_U2_PORT_DISABLE); + + switch (speed) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + // disable super-speed port + reg |= USB3_U3_PORT_DISABLE; + pr_info("%s: super-speed port disabled.\n", __func__); + break; + + case USB_SPEED_SUPER: + break; + + default: + pr_warn("%s: unknown speed class %d.\n", __func__, speed); + } + + writel(reg, peri_base + HI3798MV200_PERI_USB5); + unmap_physmem(peri_base, MAP_NOCACHE); +} + +const struct dwc3_glue_ops hi3798mv200_ops = { + .glue_configure = dwc3_hi3798mv200_glue_configure, +}; + static int dwc3_glue_bind_common(struct udevice *parent, ofnode node) { const char *name = ofnode_get_name(node); @@ -611,6 +650,7 @@ static const struct udevice_id dwc3_glue_ids[] = { { .compatible = "fsl,imx8mp-dwc3", .data = (ulong)&imx8mp_ops }, { .compatible = "fsl,imx8mq-dwc3" }, { .compatible = "intel,tangier-dwc3" }, + { .compatible = "hisilicon,hi3798mv200-dwc3", .data = (ulong)&hi3798mv200_ops }, { } }; -- 2.43.0
[PATCH 0/3] usb: dwv3: add glue driver for hi3798mv200
Also edit the prototype of .glue_configure to fulfill our needs. Signed-off-by: Yang Xiwen --- Yang Xiwen (3): usb: dwc3: handle return value of clk_get_rate() correctly usb: dwc3: replace argument mode with child ofnode usb: dwc3: add glue driver for Hi3798MV200 drivers/usb/dwc3/core.c | 2 +- drivers/usb/dwc3/dwc3-generic.c | 52 ++--- drivers/usb/dwc3/dwc3-generic.h | 3 +-- 3 files changed, 46 insertions(+), 11 deletions(-) --- base-commit: 050a9b981d6a835133521b599be3ae189ce70f41 change-id: 20240203-hisi-dwc3-3c47f734cd20 Best regards, -- Yang Xiwen
[PATCH 1/3] usb: dwc3: handle return value of clk_get_rate() correctly
From: Yang Xiwen clk_get_rate() return -ve on error, not 0. Fix it by replacing judging NULL with IS_ERR_VALUE(). Fixes: 6bae0eb5b8bd("usb: dwc3: Calculate REFCLKPER based on reference clock") Signed-off-by: Yang Xiwen --- drivers/usb/dwc3/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 4b4fcd8a22..06ff68105e 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -137,7 +137,7 @@ static void dwc3_ref_clk_period(struct dwc3 *dwc) if (dwc->ref_clk) { rate = clk_get_rate(dwc->ref_clk); - if (!rate) + if (IS_ERR_VALUE(rate)) return; period = NSEC_PER_SEC / rate; } else { -- 2.43.0
Re: [PATCH 0/3] usb: ehci-generic: setup a bulk of phy when possible
On 2/1/2024 10:07 PM, Marek Vasut wrote: On 2/1/24 14:16, Yang Xiwen via B4 Relay wrote: one USB controller can have multiple ports specified in dts, all of them should be setup to make use of all possible ports. Is there an example of such a system ? I'm going to send one, but not now because of some stuck patches. Running `grep 'phys = <.*>, <.*>' arch/arm/dts/*.dtsi` in the dts directory gives us some existing examples, though not very much. -- Regards, Yang Xiwen
[PATCH v2 1/3] mmc: hi6220-dwmmc: handle clocks and resets if CONFIG_CLK and CONFIG_DM_RESET enabled
From: Yang Xiwen This can avoid hardcoding a clock rate in driver. Also can enable the clocks and deassert the resets if the pre-bootloader does not do this for us. Currently only enabled for Hi3798MV200. Signed-off-by: Yang Xiwen --- drivers/mmc/hi6220_dw_mmc.c | 61 - 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/hi6220_dw_mmc.c b/drivers/mmc/hi6220_dw_mmc.c index 71962cd47e..a4b8072976 100644 --- a/drivers/mmc/hi6220_dw_mmc.c +++ b/drivers/mmc/hi6220_dw_mmc.c @@ -5,15 +5,24 @@ */ #include +#include #include #include #include #include #include +#include #include +#include DECLARE_GLOBAL_DATA_PTR; +enum hi6220_dwmmc_clk_type { + HI6220_DWMMC_CLK_BIU, + HI6220_DWMMC_CLK_CIU, + HI6220_DWMMC_CLK_CNT, +}; + struct hi6220_dwmmc_plat { struct mmc_config cfg; struct mmc mmc; @@ -21,6 +30,8 @@ struct hi6220_dwmmc_plat { struct hi6220_dwmmc_priv_data { struct dwmci_host host; + struct clk *clks[HI6220_DWMMC_CLK_CNT]; + struct reset_ctl_bulk rsts; }; struct hisi_mmc_data { @@ -32,7 +43,29 @@ static int hi6220_dwmmc_of_to_plat(struct udevice *dev) { struct hi6220_dwmmc_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; + int ret; + if (CONFIG_IS_ENABLED(CLK) && CONFIG_IS_ENABLED(DM_RESET)) { + priv->clks[HI6220_DWMMC_CLK_BIU] = devm_clk_get(dev, "biu"); + if (IS_ERR(priv->clks[HI6220_DWMMC_CLK_BIU])) { + ret = PTR_ERR(priv->clks[HI6220_DWMMC_CLK_BIU]); + dev_err(dev, "Failed to get BIU clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + priv->clks[HI6220_DWMMC_CLK_CIU] = devm_clk_get(dev, "ciu"); + if (IS_ERR(priv->clks[HI6220_DWMMC_CLK_CIU])) { + ret = PTR_ERR(priv->clks[HI6220_DWMMC_CLK_CIU]); + dev_err(dev, "Failed to get CIU clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + ret = reset_get_bulk(dev, &priv->rsts); + if (ret) { + dev_err(dev, "Failed to get resets(ret = %d)", ret); + return log_msg_ret("rst", ret); + } + } host->name = dev->name; host->ioaddr = dev_read_addr_ptr(dev); host->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), @@ -56,11 +89,37 @@ static int hi6220_dwmmc_probe(struct udevice *dev) struct hi6220_dwmmc_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; struct hisi_mmc_data *mmc_data; + int ret; mmc_data = (struct hisi_mmc_data *)dev_get_driver_data(dev); - /* Use default bus speed due to absence of clk driver */ host->bus_hz = mmc_data->clock; + if (CONFIG_IS_ENABLED(CLK) && CONFIG_IS_ENABLED(DM_RESET)) { + ret = clk_prepare_enable(priv->clks[HI6220_DWMMC_CLK_BIU]); + if (ret) { + dev_err(dev, "Failed to enable biu clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + ret = clk_prepare_enable(priv->clks[HI6220_DWMMC_CLK_CIU]); + if (ret) { + dev_err(dev, "Failed to enable ciu clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + ret = reset_deassert_bulk(&priv->rsts); + if (ret) { + dev_err(dev, "Failed to deassert resets(ret = %d).\n", ret); + return log_msg_ret("rst", ret); + } + + host->bus_hz = clk_get_rate(priv->clks[HI6220_DWMMC_CLK_CIU]); + if (host->bus_hz <= 0) { + dev_err(dev, "Failed to get ciu clock rate(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + } + dev_dbg(dev, "bus clock rate: %d.\n", host->bus_hz); dwmci_setup_cfg(&plat->cfg, host, host->bus_hz, 40); host->mmc = &plat->mmc; -- 2.43.0
[PATCH v2 3/3] mmc: hi6220_dw_mmc: add fifoth_val to private data and set it in .probe
From: Yang Xiwen The value defaults to 0 and is ignored by dw_mmc code, so the other users are not affected. Setting this explicitly fixes some weird reading error found on Hi3798MV200. Fixes: 8a5dc8140e62 ("mmc: hi6220_dw_mmc: add compatible for HC2910 support") Signed-off-by: Yang Xiwen --- drivers/mmc/hi6220_dw_mmc.c | 11 ++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/hi6220_dw_mmc.c b/drivers/mmc/hi6220_dw_mmc.c index a4b8072976..dc0210402b 100644 --- a/drivers/mmc/hi6220_dw_mmc.c +++ b/drivers/mmc/hi6220_dw_mmc.c @@ -37,6 +37,7 @@ struct hi6220_dwmmc_priv_data { struct hisi_mmc_data { unsigned int clock; bool use_fifo; + u32 fifoth_val; }; static int hi6220_dwmmc_of_to_plat(struct udevice *dev) @@ -125,6 +126,7 @@ static int hi6220_dwmmc_probe(struct udevice *dev) host->mmc = &plat->mmc; host->fifo_mode = mmc_data->use_fifo; + host->fifoth_val = mmc_data->fifoth_val; host->mmc->priv = &priv->host; upriv->mmc = host->mmc; host->mmc->dev = dev; @@ -154,13 +156,20 @@ static const struct hisi_mmc_data hi6220_mmc_data = { .use_fifo = false, }; +static const struct hisi_mmc_data hi3798mv2x_mmc_data = { + .clock = 5000, + .use_fifo = false, + // FIFO depth is 256 + .fifoth_val = MSIZE(4) | RX_WMARK(0x7f) | TX_WMARK(0x80), +}; + static const struct udevice_id hi6220_dwmmc_ids[] = { { .compatible = "hisilicon,hi6220-dw-mshc", .data = (ulong)&hi6220_mmc_data }, { .compatible = "hisilicon,hi3798cv200-dw-mshc", .data = (ulong)&hi6220_mmc_data }, { .compatible = "hisilicon,hi3798mv200-dw-mshc", - .data = (ulong)&hi6220_mmc_data }, + .data = (ulong)&hi3798mv2x_mmc_data }, { .compatible = "hisilicon,hi3660-dw-mshc", .data = (ulong)&hi3660_mmc_data }, { } -- 2.43.0
[PATCH v2 2/3] mmc: dw_mmc: Don't return error if data busy timeout
From: Yang Xiwen As described in [1], some poor hardware or cards would fail to release the bus and keep driving data lines low. Ignore it and send the next cmd directly seems okay for most cases. [1]: https://patchwork.kernel.org/project/linux-mmc/patch/1424458179-5456-1-git-send-email-diand...@chromium.org/ Signed-off-by: Yang Xiwen --- drivers/mmc/dw_mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 400066fa99..e103664145 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -262,8 +262,8 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { if (get_timer(start) > timeout) { - debug("%s: Timeout on data busy\n", __func__); - return -ETIMEDOUT; + debug("%s: Timeout on data busy, continue anyway\n", __func__); + break; } } -- 2.43.0
[PATCH v2 0/3] mmc: hi6220-dwmmc: handle resets and clocks
Also allow setup fifoth_val in driver Signed-off-by: Yang Xiwen --- Changes in v2: - dw-mmc: proceed if data busy found - hi6220-dw-mmc: add fifoth_val setup, separate hi3798mv200 data - Link to v1: https://lore.kernel.org/r/20240119-mmc-v1-1-aee6b2cf6...@outlook.com --- Yang Xiwen (3): mmc: hi6220-dwmmc: handle clocks and resets if CONFIG_CLK and CONFIG_DM_RESET enabled mmc: dw_mmc: Don't return error if data busy timeout mmc: hi6220_dw_mmc: add fifoth_val to private data and set it in .probe drivers/mmc/dw_mmc.c| 4 +-- drivers/mmc/hi6220_dw_mmc.c | 72 +++-- 2 files changed, 72 insertions(+), 4 deletions(-) --- base-commit: f7cca7ccc5117eaafcc2bde91ad1bed6fee7cfc3 change-id: 20240119-mmc-9cf7f3455cb4 Best regards, -- Yang Xiwen
[PATCH 2/3] test: phy: test generic_setup(shutdown)_phy_bulk()
From: Yang Xiwen add unittests for the newly introduced helper functions. Signed-off-by: Yang Xiwen --- test/dm/phy.c | 4 1 file changed, 4 insertions(+) diff --git a/test/dm/phy.c b/test/dm/phy.c index 0cf3689fde..cb16844a0a 100644 --- a/test/dm/phy.c +++ b/test/dm/phy.c @@ -159,6 +159,8 @@ static int dm_test_phy_bulk(struct unit_test_state *uts) ut_asserteq(0, generic_phy_power_on_bulk(&phys)); ut_asserteq(0, generic_phy_power_off_bulk(&phys)); ut_asserteq(0, generic_phy_exit_bulk(&phys)); + ut_asserteq(0, generic_setup_phy_bulk(parent, &phys)); + ut_asserteq(0, generic_shutdown_phy_bulk(&phys)); /* has a known problem phy */ ut_assertok(uclass_get_device_by_name(UCLASS_SIMPLE_BUS, @@ -171,6 +173,8 @@ static int dm_test_phy_bulk(struct unit_test_state *uts) ut_asserteq(-EIO, generic_phy_power_on_bulk(&phys)); ut_asserteq(-EIO, generic_phy_power_off_bulk(&phys)); ut_asserteq(0, generic_phy_exit_bulk(&phys)); + ut_asserteq(-EIO, generic_setup_phy_bulk(parent, &phys)); + ut_asserteq(-EIO, generic_shutdown_phy_bulk(&phys)); return 0; } -- 2.43.0
[PATCH 3/3] usb: ehci: Make usage of generic_{setup,shutdown}_phy_bulk() helpers
From: Yang Xiwen Replace generic_setup_phy() and generic_shutdown_phy() by respectively generic_setup_phy_bulk() and generic_shutdown_phy_bulk(). Signed-off-by: Yang Xiwen --- drivers/usb/host/ehci-generic.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/ehci-generic.c b/drivers/usb/host/ehci-generic.c index 936e30438d..e109d84d73 100644 --- a/drivers/usb/host/ehci-generic.c +++ b/drivers/usb/host/ehci-generic.c @@ -25,7 +25,7 @@ struct generic_ehci { struct ehci_ctrl ctrl; struct clk_bulk clocks; struct reset_ctl_bulk resets; - struct phy phy; + struct phy_bulk phys; struct udevice *vbus_supply; }; @@ -95,7 +95,7 @@ static int ehci_usb_probe(struct udevice *dev) if (err) goto reset_err; - err = generic_setup_phy(dev, &priv->phy, 0); + err = generic_setup_phy_bulk(dev, &priv->phys); if (err) goto regulator_err; @@ -110,7 +110,7 @@ static int ehci_usb_probe(struct udevice *dev) return 0; phy_err: - ret = generic_shutdown_phy(&priv->phy); + ret = generic_shutdown_phy_bulk(&priv->phys); if (ret) dev_err(dev, "failed to shutdown usb phy (ret=%d)\n", ret); @@ -140,7 +140,7 @@ static int ehci_usb_remove(struct udevice *dev) if (ret) return ret; - ret = generic_shutdown_phy(&priv->phy); + ret = generic_shutdown_phy_bulk(&priv->phys); if (ret) return ret; -- 2.43.0
[PATCH 1/3] phy: add generic_setup(shutdown)_phy_bulk()
From: Yang Xiwen They are the bulk version of generic_setup(shutdown)_phy(). Signed-off-by: Yang Xiwen --- drivers/phy/phy-uclass.c | 33 + include/generic-phy.h| 29 + 2 files changed, 62 insertions(+) diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index 0dcfe258bc..d50ebbe3a0 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -528,6 +528,28 @@ int generic_setup_phy(struct udevice *dev, struct phy *phy, int index) return ret; } +int generic_setup_phy_bulk(struct udevice *dev, struct phy_bulk *bulk) +{ + struct phy *phys = bulk->phys; + int i, ret; + + for (i = 0; i < bulk->count; i++) { + ret = generic_setup_phy(dev, &phys[i], i); + if (ret) { + pr_err("Can't setup PHY%d\n", i); + goto phys_setup_err; + } + } + + return 0; + +phys_setup_err: + for (; i > 0; i--) + generic_shutdown_phy(&phys[i - 1]); + + return ret; +} + int generic_shutdown_phy(struct phy *phy) { int ret; @@ -542,6 +564,17 @@ int generic_shutdown_phy(struct phy *phy) return generic_phy_exit(phy); } +int generic_shutdown_phy_bulk(struct phy_bulk *bulk) +{ + struct phy *phys = bulk->phys; + int i, ret = 0; + + for (i = 0; i < bulk->count; i++) + ret |= generic_shutdown_phy(&phys[i]); + + return ret; +} + UCLASS_DRIVER(phy) = { .id = UCLASS_PHY, .name = "phy", diff --git a/include/generic-phy.h b/include/generic-phy.h index eaab749166..2d1bf7c1ea 100644 --- a/include/generic-phy.h +++ b/include/generic-phy.h @@ -420,6 +420,16 @@ int generic_phy_power_off_bulk(struct phy_bulk *bulk); */ int generic_setup_phy(struct udevice *dev, struct phy *phy, int index); +/** + * generic_setup_phy() - Get, initialize and power on all phys in a phy bulk. + * + * @dev: The consumer device. + * @bulk: A pointer to the PHY bulk + * + * Return: 0 if OK, or negative error code. + */ +int generic_setup_phy_bulk(struct udevice *dev, struct phy_bulk *bulk); + /** * generic_shutdown_phy() - Power off and de-initialize phy. * @@ -429,6 +439,15 @@ int generic_setup_phy(struct udevice *dev, struct phy *phy, int index); */ int generic_shutdown_phy(struct phy *phy); +/** + * generic_shutdown_phy_bulk() - Power off and de-initialize all phys in a phy bulk. + * + * @bulk: A pointer to the PHY bulk. + * + * Return: 0 if OK, or negative error code. + */ +int generic_shutdown_phy_bulk(struct phy_bulk *bulk); + #else /* CONFIG_PHY */ static inline int generic_phy_init(struct phy *phy) @@ -514,11 +533,21 @@ static inline int generic_setup_phy(struct udevice *dev, struct phy *phy, int in return 0; } +static inline int generic_setup_phy_bulk(struct udevice *dev, struct phy_bulk *bulk) +{ + return 0; +} + static inline int generic_shutdown_phy(struct phy *phy) { return 0; } +static inline int generic_shutdown_phy_bulk(struct phy_bulk *bulk) +{ + return 0; +} + #endif /* CONFIG_PHY */ /** -- 2.43.0
[PATCH 0/3] usb: ehci-generic: setup a bulk of phy when possible
one USB controller can have multiple ports specified in dts, all of them should be setup to make use of all possible ports. Signed-off-by: Yang Xiwen --- Yang Xiwen (3): phy: add generic_setup(shutdown)_phy_bulk() test: phy: test generic_setup(shutdown)_phy_bulk() usb: ehci: Make usage of generic_{setup,shutdown}_phy_bulk() helpers drivers/phy/phy-uclass.c| 33 + drivers/usb/host/ehci-generic.c | 8 include/generic-phy.h | 29 + test/dm/phy.c | 4 4 files changed, 70 insertions(+), 4 deletions(-) --- base-commit: b6d8969bcb94321dfed1399f2eaa8768ba42caaa change-id: 20240201-ehci-6c3aa7d97932 Best regards, -- Yang Xiwen
[PATCH] mmc: dw_mmc: Don't return error if data busy timeout
As described in [1], some poor hardware or cards would fail to release the bus and keep driving data lines low. Ignore it and send the next cmd directly seems okay for most cases. [1]: https://patchwork.kernel.org/project/linux-mmc/patch/1424458179-5456-1-git-send-email-diand...@chromium.org/ Signed-off-by: Yang Xiwen --- drivers/mmc/dw_mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 400066fa99..e103664145 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -262,8 +262,8 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { if (get_timer(start) > timeout) { - debug("%s: Timeout on data busy\n", __func__); - return -ETIMEDOUT; + debug("%s: Timeout on data busy, continue anyway\n", __func__); + break; } } -- 2.43.0
[PATCH] serial: pl01x: set baudrate when probing
From: Yang Xiwen It is found that when DM is enabled, only generic init function is called in .probe(). Baudrate is never honored. Add a function call to .setbrg() when probing so that we can update the baudrate of the serial device. Signed-off-by: Yang Xiwen --- drivers/serial/serial_pl01x.c | 11 --- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index 428a4d210d..57bbcaf3b6 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -290,6 +290,7 @@ int pl01x_serial_probe(struct udevice *dev) { struct pl01x_serial_plat *plat = dev_get_plat(dev); struct pl01x_priv *priv = dev_get_priv(dev); + int ret; #if CONFIG_IS_ENABLED(OF_PLATDATA) struct dtd_serial_pl01x *dtplat = &plat->dtplat; @@ -301,10 +302,14 @@ int pl01x_serial_probe(struct udevice *dev) #endif priv->type = plat->type; - if (!plat->skip_init) - return pl01x_generic_serial_init(priv->regs, priv->type); - else + if (!plat->skip_init) { + ret = pl01x_generic_serial_init(priv->regs, priv->type); + if (!ret) + return ret; + return pl01x_serial_setbrg(dev, gd->baudrate); + } else { return 0; + } } int pl01x_serial_getc(struct udevice *dev) --- base-commit: f7cca7ccc5117eaafcc2bde91ad1bed6fee7cfc3 change-id: 20240123-b4-pl011-ee9575ff2a38 Best regards, -- Yang Xiwen
[PATCH v3 4/5] net: hifemac: implement `net stats` needed ops
From: Yang Xiwen 3 operations needed by `net stats` are implemented. New `net stats` output some useful info. Signed-off-by: Yang Xiwen --- drivers/net/hifemac.c | 87 +++ 1 file changed, 87 insertions(+) diff --git a/drivers/net/hifemac.c b/drivers/net/hifemac.c index 39c0233b62..d24023eefd 100644 --- a/drivers/net/hifemac.c +++ b/drivers/net/hifemac.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -125,6 +127,57 @@ struct hisi_femac_priv { u32 link_status; }; +struct hisi_femac_stat_entry { + const char *name; + u32 offset; + u32 mask; +}; + +/* please refer to the datasheet for the description of these entries */ +static const struct hisi_femac_stat_entry hisi_femac_stats_table[] = { + { "rxsof_cnt", 0x584, GENMASK(31, 28) }, + { "rxeof_cnt", 0x584, GENMASK(27, 24) }, + { "rxcrcok_cnt",0x584, GENMASK(23, 20) }, + { "rxcrcbad_cnt", 0x584, GENMASK(19, 16) }, + { "txsof_cnt", 0x584, GENMASK(15, 12) }, + { "txeof_cnt", 0x584, GENMASK(11, 8) }, + { "txcrcok_cnt",0x584, GENMASK(7, 4) }, + { "txcrcbad_cnt", 0x584, GENMASK(3, 0) }, + { "pkts_cpu", 0x5a0, GENMASK(15, 0) }, + { "addr_cpu", 0x5a4, GENMASK(15, 0) }, + { "pkts_port", 0x5a8, GENMASK(15, 0) }, + { "pkts_cpu2tx",0x5ac, GENMASK(15, 0) }, + { "rxdvrise", 0x600, GENMASK(31, 0) }, + { "ifinoctets", 0x604, GENMASK(31, 0) }, + { "octets_rx", 0x608, GENMASK(31, 0) }, + { "local_mac_match",0x60c, GENMASK(31, 0) }, + { "pkts", 0x610, GENMASK(31, 0) }, + { "broadcastpkts", 0x614, GENMASK(31, 0) }, + { "multicastpkts", 0x618, GENMASK(31, 0) }, + { "ifinucastpkts", 0x61c, GENMASK(31, 0) }, + { "ifinerrors", 0x620, GENMASK(31, 0) }, + { "crcerr", 0x624, GENMASK(31, 0) }, + { "abnormalsizepkts", 0x628, GENMASK(31, 0) }, + { "dot3alignmenterr", 0x62c, GENMASK(31, 0) }, + { "dot3pause", 0x630, GENMASK(31, 0) }, + { "dropevents", 0x634, GENMASK(31, 0) }, + { "flux_frame_cnt", 0x638, GENMASK(31, 0) }, + { "flux_drop_cnt", 0x63c, GENMASK(31, 0) }, + { "mac_not2cpu_pkts", 0x64c, GENMASK(31, 0) }, + { "pkts_tx",0x780, GENMASK(31, 0) }, + { "broadcastpkts_tx", 0x784, GENMASK(31, 0) }, + { "multicastpkts_tx", 0x788, GENMASK(31, 0) }, + { "ifoutucastpkts_tx", 0x78c, GENMASK(31, 0) }, + { "octets_tx", 0x790, GENMASK(31, 0) }, + { "dot3pause", 0x794, GENMASK(31, 0) }, + { "retry_times_tx", 0x798, GENMASK(31, 0) }, + { "collisions", 0x79c, GENMASK(31, 0) }, + { "dot3latecol",0x7a0, GENMASK(31, 0) }, + { "dot3colok", 0x7a4, GENMASK(31, 0) }, + { "dot3excessivecol", 0x7a8, GENMASK(31, 0) }, + { "dot3colcnt", 0x7ac, GENMASK(31, 0) }, +}; + static void hisi_femac_irq_enable(struct hisi_femac_priv *priv, int irqs) { u32 val; @@ -334,6 +387,37 @@ static void hisi_femac_stop(struct udevice *dev) writel(SOFT_RESET_ALL, priv->glb_base + GLB_SOFT_RESET); } +static int hisi_femac_get_sset_count(struct udevice *dev) +{ + return ARRAY_SIZE(hisi_femac_stats_table); +} + +static void hisi_femac_get_strings(struct udevice *dev, u8 *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hisi_femac_stats_table); i++) + strcpy(data + i * ETH_GSTRING_LEN, hisi_femac_stats_table[i].name); +} + +/* Non-constant mask variant of FIELD_GET/FIELD_PREP */ +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) + +static void hisi_femac_get_stats(struct udevice *dev, u64 *data) +{ + int i; + u32 mask, reg; + struct hisi_femac_priv *priv = dev_get_priv(dev); + void __iomem *port_base = priv->port_base; + + for (i = 0; i < ARRAY_SIZE(hisi_femac_stats_table); i++) { + mask = hisi_femac_stats_table[i].mask; + reg = readl(port_base + hisi_femac_stats_table[i].offset); + + data[i] = field_get(mask, reg); + } +} + int hisi_femac_of_to_plat(struct udevice *dev) { int ret, i; @@ -523,6 +607,9 @@ static const struct eth_ops hisi_femac_ops = { .free_pkt = hisi_femac_free_pkt, .stop = hisi_femac_stop, .write_hwaddr = hisi_femac_set_hw_mac_addr, + .get_sset_count = hisi_femac_get_sset_count, + .get_strings= hisi_femac_get_strings, + .get_stats = hisi_femac_get_stats, }; static const struct udevice_id hisi_femac_ids[] = { -- 2.43.0
[PATCH v3 1/5] net: hifemac_mdio: use log_msg_ret() correctly, report error by dev_err()
From: Yang Xiwen The initial commit used log_msg_ret() wrongly. Fix that by moving error report to a separate dev_err() call and shrink the first argument of log_msg_ret() to no more than 4 chars. Fixes: 6b5c8d98e204 ("net: add hifemac_mdio MDIO bus driver for HiSilicon platform") Signed-off-by: Yang Xiwen --- drivers/net/hifemac_mdio.c | 11 --- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/hifemac_mdio.c b/drivers/net/hifemac_mdio.c index 343c5f3a38..0b59d06091 100644 --- a/drivers/net/hifemac_mdio.c +++ b/drivers/net/hifemac_mdio.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -74,7 +75,8 @@ static int hisi_femac_mdio_of_to_plat(struct udevice *dev) data->membase = dev_remap_addr(dev); if (IS_ERR(data->membase)) { ret = PTR_ERR(data->membase); - return log_msg_ret("Failed to remap base addr", ret); + dev_err(dev, "Failed to remap base addr %d\n", ret); + return log_msg_ret("mdio", ret); } // clk is optional @@ -89,8 +91,10 @@ static int hisi_femac_mdio_probe(struct udevice *dev) int ret; ret = clk_prepare_enable(data->clk); - if (ret) - return log_msg_ret("Failed to enable clk", ret); + if (ret) { + dev_err(dev, "Failed to enable clock: %d\n", ret); + return log_msg_ret("clk", ret); + } return 0; } @@ -112,5 +116,6 @@ U_BOOT_DRIVER(hisi_femac_mdio_driver) = { .of_to_plat = hisi_femac_mdio_of_to_plat, .probe = hisi_femac_mdio_probe, .ops = &hisi_femac_mdio_ops, + .plat_auto = sizeof(struct mdio_perdev_priv), .priv_auto = sizeof(struct hisi_femac_mdio_data), }; -- 2.43.0
[PATCH v3 3/5] net: hifemac: register MDIO bus device for subnode
From: Yang Xiwen register internal MDIO bus device if it is a subnode. Signed-off-by: Yang Xiwen --- drivers/net/hifemac.c | 28 1 file changed, 28 insertions(+) diff --git a/drivers/net/hifemac.c b/drivers/net/hifemac.c index 1088f3eca3..39c0233b62 100644 --- a/drivers/net/hifemac.c +++ b/drivers/net/hifemac.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -337,6 +338,8 @@ int hisi_femac_of_to_plat(struct udevice *dev) { int ret, i; struct hisi_femac_priv *priv = dev_get_priv(dev); + ofnode mdio_node; + bool mdio_registered = false; static const char * const clk_strs[] = { [CLK_MAC] = "mac", [CLK_BUS] = "bus", @@ -388,6 +391,31 @@ int hisi_femac_of_to_plat(struct udevice *dev) MAC_RESET_DELAY_PROPERTY, MAC_RESET_ASSERT_PERIOD); + /* Create MDIO bus */ + ofnode_for_each_subnode(mdio_node, dev_ofnode(dev)) { + const char *subnode_name = ofnode_get_name(mdio_node); + struct udevice *mdiodev; + + // Skip subnodes not starting with "mdio" + if (strncmp(subnode_name, "mdio", 4)) + continue; + + ret = device_bind_driver_to_node(dev, "hisi-femac-mdio", +subnode_name, mdio_node, &mdiodev); + if (ret) { + dev_err(dev, "Failed to register MDIO bus device %d\n", ret); + return log_msg_ret("net", ret); + } + + mdio_registered = true; + break; + } + + if (!mdio_registered) { + dev_err(dev, "No MDIO subnode is found!\n"); + return log_msg_ret("mdio", -ENODATA); + } + return 0; } -- 2.43.0
[PATCH v3 2/5] net: hifemac: fix log reporting
From: Yang Xiwen shrink the first argument of log_msg_ret(), add dev_xxx() functions for error reporting. Fixes: 9d8f78a2a79f7 ("net: add hifemac Ethernet driver for HiSilicon platform") Signed-off-by: Yang Xiwen --- drivers/net/hifemac.c | 110 +- 1 file changed, 73 insertions(+), 37 deletions(-) diff --git a/drivers/net/hifemac.c b/drivers/net/hifemac.c index b61a29e636..1088f3eca3 100644 --- a/drivers/net/hifemac.c +++ b/drivers/net/hifemac.c @@ -245,8 +245,10 @@ static int hisi_femac_start(struct udevice *dev) hisi_femac_rx_refill(priv); ret = phy_startup(priv->phy); - if (ret) - return log_msg_ret("Failed to startup phy", ret); + if (ret) { + dev_err(dev, "Failed to startup phy: %d\n", ret); + return log_msg_ret("phy", ret); + } if (!priv->phy->link) { debug("%s: link down\n", __func__); @@ -281,8 +283,10 @@ static int hisi_femac_send(struct udevice *dev, void *packet, int length) // wait until FIFO is empty ret = wait_for_bit_le32(priv->glb_base + GLB_IRQ_RAW, IRQ_INT_TX_PER_PACKET, true, 50, false); - if (ret == -ETIMEDOUT) - return log_msg_ret("FIFO timeout", ret); + if (ret == -ETIMEDOUT) { + dev_err(dev, "FIFO timeout\n"); + return log_msg_ret("net", ret); + } return 0; } @@ -340,35 +344,45 @@ int hisi_femac_of_to_plat(struct udevice *dev) }; priv->port_base = dev_remap_addr_name(dev, "port"); - if (IS_ERR(priv->port_base)) - return log_msg_ret("Failed to remap port address space", PTR_ERR(priv->port_base)); + if (!priv->port_base) { + dev_err(dev, "Failed to remap port address space\n"); + return log_msg_ret("net", -EINVAL); + } priv->glb_base = dev_remap_addr_name(dev, "glb"); - if (IS_ERR(priv->glb_base)) - return log_msg_ret("Failed to remap global address space", PTR_ERR(priv->glb_base)); + if (IS_ERR(priv->glb_base)) { + dev_err(dev, "Failed to remap global address space\n"); + return log_msg_ret("net", -EINVAL); + } for (i = 0; i < ARRAY_SIZE(clk_strs); i++) { priv->clks[i] = devm_clk_get(dev, clk_strs[i]); if (IS_ERR(priv->clks[i])) { dev_err(dev, "Error getting clock %s\n", clk_strs[i]); - return log_msg_ret("Failed to get clocks", PTR_ERR(priv->clks[i])); + return log_msg_ret("clk", PTR_ERR(priv->clks[i])); } } priv->mac_rst = devm_reset_control_get(dev, "mac"); - if (IS_ERR(priv->mac_rst)) - return log_msg_ret("Failed to get MAC reset", PTR_ERR(priv->mac_rst)); + if (IS_ERR(priv->mac_rst)) { + dev_err(dev, "Failed to get MAC reset %ld\n", PTR_ERR(priv->mac_rst)); + return log_msg_ret("rst", PTR_ERR(priv->mac_rst)); + } priv->phy_rst = devm_reset_control_get(dev, "phy"); - if (IS_ERR(priv->phy_rst)) - return log_msg_ret("Failed to get PHY reset", PTR_ERR(priv->phy_rst)); + if (IS_ERR(priv->phy_rst)) { + dev_err(dev, "Failed to get PHY reset %ld\n", PTR_ERR(priv->phy_rst)); + return log_msg_ret("rst", PTR_ERR(priv->phy_rst)); + } ret = dev_read_u32_array(dev, PHY_RESET_DELAYS_PROPERTY, priv->phy_reset_delays, DELAYS_NUM); - if (ret < 0) - return log_msg_ret("Failed to get PHY reset delays", ret); + if (ret < 0) { + dev_err(dev, "Failed to get PHY reset delays %d\n", ret); + return log_msg_ret("rst", ret); + } priv->mac_reset_delay = dev_read_u32_default(dev, MAC_RESET_DELAY_PROPERTY, @@ -385,32 +399,44 @@ static int hisi_femac_phy_reset(struct hisi_femac_priv *priv) // Disable MAC clk before phy reset ret = clk_disable(priv->clks[CLK_MAC]); - if (ret < 0) - return log_msg_ret("Failed to disable MAC clock", ret); + if (ret < 0) { + pr_err("%s: Failed to disable MAC clock %d\n", __func__, ret); + return log_msg_ret("clk", ret); + } ret = clk_disable(priv->clks[CL
[PATCH v3 0/5] net: hifemac: a few cleanups
- Fix the use of log_msg_ret() and add dev_xxx() for error reporting. - Register mdio subnode as a mdio bus device for hifemac. - Implement ops needed by `net stats` - Make functions static. Signed-off-by: Yang Xiwen --- Changes in v3: - hisi-femac: add missing `static` to avoid polluting global namespace. - Link to v2: https://lore.kernel.org/r/20240122-net-v2-0-78a368896...@outlook.com Changes in v2: - hisi-femac: add statistics related operations - Link to v1: https://lore.kernel.org/r/20240119-net-v1-0-d1feb8e16...@outlook.com --- Yang Xiwen (5): net: hifemac_mdio: use log_msg_ret() correctly, report error by dev_err() net: hifemac: fix log reporting net: hifemac: register MDIO bus device for subnode net: hifemac: implement `net stats` needed ops net: hifemac: make some functions static drivers/net/hifemac.c | 229 + drivers/net/hifemac_mdio.c | 11 ++- 2 files changed, 198 insertions(+), 42 deletions(-) --- base-commit: f7cca7ccc5117eaafcc2bde91ad1bed6fee7cfc3 change-id: 20240119-net-72a32675eeb4 Best regards, -- Yang Xiwen
[PATCH v3 5/5] net: hifemac: make some functions static
From: Yang Xiwen They are not required to be global, make them static. Signed-off-by: Yang Xiwen --- drivers/net/hifemac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/hifemac.c b/drivers/net/hifemac.c index d24023eefd..90cc247b3b 100644 --- a/drivers/net/hifemac.c +++ b/drivers/net/hifemac.c @@ -418,7 +418,7 @@ static void hisi_femac_get_stats(struct udevice *dev, u64 *data) } } -int hisi_femac_of_to_plat(struct udevice *dev) +static int hisi_femac_of_to_plat(struct udevice *dev) { int ret, i; struct hisi_femac_priv *priv = dev_get_priv(dev); @@ -553,7 +553,7 @@ static int hisi_femac_phy_reset(struct hisi_femac_priv *priv) return 0; } -int hisi_femac_probe(struct udevice *dev) +static int hisi_femac_probe(struct udevice *dev) { struct hisi_femac_priv *priv = dev_get_priv(dev); int ret, i; -- 2.43.0
[PATCH v2 0/4] net: hifemac: a few cleanups
Fix the use of log_msg_ret() and add dev_xxx() for error reporting. Register mdio subnode as a mdio bus device for hifemac. Implement ops needed by `net stats` Signed-off-by: Yang Xiwen --- Changes in v2: - hisi-femac: add statistics related operations - Link to v1: https://lore.kernel.org/r/20240119-net-v1-0-d1feb8e16...@outlook.com --- Yang Xiwen (4): net: hifemac_mdio: use log_msg_ret() correctly, report error by dev_err() net: hifemac: fix log reporting net: hifemac: register MDIO bus device for subnode net: hifemac: implement `net stats` needed ops drivers/net/hifemac.c | 225 + drivers/net/hifemac_mdio.c | 11 ++- 2 files changed, 196 insertions(+), 40 deletions(-) --- base-commit: f7cca7ccc5117eaafcc2bde91ad1bed6fee7cfc3 change-id: 20240119-net-72a32675eeb4 Best regards, -- Yang Xiwen
[PATCH v2 4/4] net: hifemac: implement `net stats` needed ops
From: Yang Xiwen 3 operations needed by `net stats` are implemented. New `net stats` output some useful info. Signed-off-by: Yang Xiwen --- drivers/net/hifemac.c | 87 +++ 1 file changed, 87 insertions(+) diff --git a/drivers/net/hifemac.c b/drivers/net/hifemac.c index 39c0233b62..24108bee4b 100644 --- a/drivers/net/hifemac.c +++ b/drivers/net/hifemac.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -125,6 +127,57 @@ struct hisi_femac_priv { u32 link_status; }; +struct hisi_femac_stat_entry { + const char *name; + u32 offset; + u32 mask; +}; + +/* please refer to the datasheet for the description of these entries */ +const struct hisi_femac_stat_entry hisi_femac_stats_table[] = { + { "rxsof_cnt", 0x584, GENMASK(31, 28) }, + { "rxeof_cnt", 0x584, GENMASK(27, 24) }, + { "rxcrcok_cnt",0x584, GENMASK(23, 20) }, + { "rxcrcbad_cnt", 0x584, GENMASK(19, 16) }, + { "txsof_cnt", 0x584, GENMASK(15, 12) }, + { "txeof_cnt", 0x584, GENMASK(11, 8) }, + { "txcrcok_cnt",0x584, GENMASK(7, 4) }, + { "txcrcbad_cnt", 0x584, GENMASK(3, 0) }, + { "pkts_cpu", 0x5a0, GENMASK(15, 0) }, + { "addr_cpu", 0x5a4, GENMASK(15, 0) }, + { "pkts_port", 0x5a8, GENMASK(15, 0) }, + { "pkts_cpu2tx",0x5ac, GENMASK(15, 0) }, + { "rxdvrise", 0x600, GENMASK(31, 0) }, + { "ifinoctets", 0x604, GENMASK(31, 0) }, + { "octets_rx", 0x608, GENMASK(31, 0) }, + { "local_mac_match",0x60c, GENMASK(31, 0) }, + { "pkts", 0x610, GENMASK(31, 0) }, + { "broadcastpkts", 0x614, GENMASK(31, 0) }, + { "multicastpkts", 0x618, GENMASK(31, 0) }, + { "ifinucastpkts", 0x61c, GENMASK(31, 0) }, + { "ifinerrors", 0x620, GENMASK(31, 0) }, + { "crcerr", 0x624, GENMASK(31, 0) }, + { "abnormalsizepkts", 0x628, GENMASK(31, 0) }, + { "dot3alignmenterr", 0x62c, GENMASK(31, 0) }, + { "dot3pause", 0x630, GENMASK(31, 0) }, + { "dropevents", 0x634, GENMASK(31, 0) }, + { "flux_frame_cnt", 0x638, GENMASK(31, 0) }, + { "flux_drop_cnt", 0x63c, GENMASK(31, 0) }, + { "mac_not2cpu_pkts", 0x64c, GENMASK(31, 0) }, + { "pkts_tx",0x780, GENMASK(31, 0) }, + { "broadcastpkts_tx", 0x784, GENMASK(31, 0) }, + { "multicastpkts_tx", 0x788, GENMASK(31, 0) }, + { "ifoutucastpkts_tx", 0x78c, GENMASK(31, 0) }, + { "octets_tx", 0x790, GENMASK(31, 0) }, + { "dot3pause", 0x794, GENMASK(31, 0) }, + { "retry_times_tx", 0x798, GENMASK(31, 0) }, + { "collisions", 0x79c, GENMASK(31, 0) }, + { "dot3latecol",0x7a0, GENMASK(31, 0) }, + { "dot3colok", 0x7a4, GENMASK(31, 0) }, + { "dot3excessivecol", 0x7a8, GENMASK(31, 0) }, + { "dot3colcnt", 0x7ac, GENMASK(31, 0) }, +}; + static void hisi_femac_irq_enable(struct hisi_femac_priv *priv, int irqs) { u32 val; @@ -334,6 +387,37 @@ static void hisi_femac_stop(struct udevice *dev) writel(SOFT_RESET_ALL, priv->glb_base + GLB_SOFT_RESET); } +static int hisi_femac_get_sset_count(struct udevice *dev) +{ + return ARRAY_SIZE(hisi_femac_stats_table); +} + +static void hisi_femac_get_strings(struct udevice *dev, u8 *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hisi_femac_stats_table); i++) + strcpy(data + i * ETH_GSTRING_LEN, hisi_femac_stats_table[i].name); +} + +/* Non-constant mask variant of FIELD_GET/FIELD_PREP */ +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) + +static void hisi_femac_get_stats(struct udevice *dev, u64 *data) +{ + int i; + u32 mask, reg; + struct hisi_femac_priv *priv = dev_get_priv(dev); + void __iomem *port_base = priv->port_base; + + for (i = 0; i < ARRAY_SIZE(hisi_femac_stats_table); i++) { + mask = hisi_femac_stats_table[i].mask; + reg = readl(port_base + hisi_femac_stats_table[i].offset); + + data[i] = field_get(mask, reg); + } +} + int hisi_femac_of_to_plat(struct udevice *dev) { int ret, i; @@ -523,6 +607,9 @@ static const struct eth_ops hisi_femac_ops = { .free_pkt = hisi_femac_free_pkt, .stop = hisi_femac_stop, .write_hwaddr = hisi_femac_set_hw_mac_addr, + .get_sset_count = hisi_femac_get_sset_count, + .get_strings= hisi_femac_get_strings, + .get_stats = hisi_femac_get_stats, }; static const struct udevice_id hisi_femac_ids[] = { -- 2.43.0
[PATCH v2 3/4] net: hifemac: register MDIO bus device for subnode
From: Yang Xiwen register internal MDIO bus device if it is a subnode. Signed-off-by: Yang Xiwen --- drivers/net/hifemac.c | 28 1 file changed, 28 insertions(+) diff --git a/drivers/net/hifemac.c b/drivers/net/hifemac.c index 1088f3eca3..39c0233b62 100644 --- a/drivers/net/hifemac.c +++ b/drivers/net/hifemac.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -337,6 +338,8 @@ int hisi_femac_of_to_plat(struct udevice *dev) { int ret, i; struct hisi_femac_priv *priv = dev_get_priv(dev); + ofnode mdio_node; + bool mdio_registered = false; static const char * const clk_strs[] = { [CLK_MAC] = "mac", [CLK_BUS] = "bus", @@ -388,6 +391,31 @@ int hisi_femac_of_to_plat(struct udevice *dev) MAC_RESET_DELAY_PROPERTY, MAC_RESET_ASSERT_PERIOD); + /* Create MDIO bus */ + ofnode_for_each_subnode(mdio_node, dev_ofnode(dev)) { + const char *subnode_name = ofnode_get_name(mdio_node); + struct udevice *mdiodev; + + // Skip subnodes not starting with "mdio" + if (strncmp(subnode_name, "mdio", 4)) + continue; + + ret = device_bind_driver_to_node(dev, "hisi-femac-mdio", +subnode_name, mdio_node, &mdiodev); + if (ret) { + dev_err(dev, "Failed to register MDIO bus device %d\n", ret); + return log_msg_ret("net", ret); + } + + mdio_registered = true; + break; + } + + if (!mdio_registered) { + dev_err(dev, "No MDIO subnode is found!\n"); + return log_msg_ret("mdio", -ENODATA); + } + return 0; } -- 2.43.0
[PATCH v2 2/4] net: hifemac: fix log reporting
From: Yang Xiwen shrink the first argument of log_msg_ret(), add dev_xxx() functions for error reporting. Fixes: 9d8f78a2a79f7 ("net: add hifemac Ethernet driver for HiSilicon platform") Signed-off-by: Yang Xiwen --- drivers/net/hifemac.c | 110 +- 1 file changed, 73 insertions(+), 37 deletions(-) diff --git a/drivers/net/hifemac.c b/drivers/net/hifemac.c index b61a29e636..1088f3eca3 100644 --- a/drivers/net/hifemac.c +++ b/drivers/net/hifemac.c @@ -245,8 +245,10 @@ static int hisi_femac_start(struct udevice *dev) hisi_femac_rx_refill(priv); ret = phy_startup(priv->phy); - if (ret) - return log_msg_ret("Failed to startup phy", ret); + if (ret) { + dev_err(dev, "Failed to startup phy: %d\n", ret); + return log_msg_ret("phy", ret); + } if (!priv->phy->link) { debug("%s: link down\n", __func__); @@ -281,8 +283,10 @@ static int hisi_femac_send(struct udevice *dev, void *packet, int length) // wait until FIFO is empty ret = wait_for_bit_le32(priv->glb_base + GLB_IRQ_RAW, IRQ_INT_TX_PER_PACKET, true, 50, false); - if (ret == -ETIMEDOUT) - return log_msg_ret("FIFO timeout", ret); + if (ret == -ETIMEDOUT) { + dev_err(dev, "FIFO timeout\n"); + return log_msg_ret("net", ret); + } return 0; } @@ -340,35 +344,45 @@ int hisi_femac_of_to_plat(struct udevice *dev) }; priv->port_base = dev_remap_addr_name(dev, "port"); - if (IS_ERR(priv->port_base)) - return log_msg_ret("Failed to remap port address space", PTR_ERR(priv->port_base)); + if (!priv->port_base) { + dev_err(dev, "Failed to remap port address space\n"); + return log_msg_ret("net", -EINVAL); + } priv->glb_base = dev_remap_addr_name(dev, "glb"); - if (IS_ERR(priv->glb_base)) - return log_msg_ret("Failed to remap global address space", PTR_ERR(priv->glb_base)); + if (IS_ERR(priv->glb_base)) { + dev_err(dev, "Failed to remap global address space\n"); + return log_msg_ret("net", -EINVAL); + } for (i = 0; i < ARRAY_SIZE(clk_strs); i++) { priv->clks[i] = devm_clk_get(dev, clk_strs[i]); if (IS_ERR(priv->clks[i])) { dev_err(dev, "Error getting clock %s\n", clk_strs[i]); - return log_msg_ret("Failed to get clocks", PTR_ERR(priv->clks[i])); + return log_msg_ret("clk", PTR_ERR(priv->clks[i])); } } priv->mac_rst = devm_reset_control_get(dev, "mac"); - if (IS_ERR(priv->mac_rst)) - return log_msg_ret("Failed to get MAC reset", PTR_ERR(priv->mac_rst)); + if (IS_ERR(priv->mac_rst)) { + dev_err(dev, "Failed to get MAC reset %ld\n", PTR_ERR(priv->mac_rst)); + return log_msg_ret("rst", PTR_ERR(priv->mac_rst)); + } priv->phy_rst = devm_reset_control_get(dev, "phy"); - if (IS_ERR(priv->phy_rst)) - return log_msg_ret("Failed to get PHY reset", PTR_ERR(priv->phy_rst)); + if (IS_ERR(priv->phy_rst)) { + dev_err(dev, "Failed to get PHY reset %ld\n", PTR_ERR(priv->phy_rst)); + return log_msg_ret("rst", PTR_ERR(priv->phy_rst)); + } ret = dev_read_u32_array(dev, PHY_RESET_DELAYS_PROPERTY, priv->phy_reset_delays, DELAYS_NUM); - if (ret < 0) - return log_msg_ret("Failed to get PHY reset delays", ret); + if (ret < 0) { + dev_err(dev, "Failed to get PHY reset delays %d\n", ret); + return log_msg_ret("rst", ret); + } priv->mac_reset_delay = dev_read_u32_default(dev, MAC_RESET_DELAY_PROPERTY, @@ -385,32 +399,44 @@ static int hisi_femac_phy_reset(struct hisi_femac_priv *priv) // Disable MAC clk before phy reset ret = clk_disable(priv->clks[CLK_MAC]); - if (ret < 0) - return log_msg_ret("Failed to disable MAC clock", ret); + if (ret < 0) { + pr_err("%s: Failed to disable MAC clock %d\n", __func__, ret); + return log_msg_ret("clk", ret); + } ret = clk_disable(priv->clks[CL
[PATCH v2 1/4] net: hifemac_mdio: use log_msg_ret() correctly, report error by dev_err()
From: Yang Xiwen The initial commit used log_msg_ret() wrongly. Fix that by moving error report to a separate dev_err() call and shrink the first argument of log_msg_ret() to no more than 4 chars. Fixes: 6b5c8d98e204 ("net: add hifemac_mdio MDIO bus driver for HiSilicon platform") Signed-off-by: Yang Xiwen --- drivers/net/hifemac_mdio.c | 11 --- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/hifemac_mdio.c b/drivers/net/hifemac_mdio.c index 343c5f3a38..0b59d06091 100644 --- a/drivers/net/hifemac_mdio.c +++ b/drivers/net/hifemac_mdio.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -74,7 +75,8 @@ static int hisi_femac_mdio_of_to_plat(struct udevice *dev) data->membase = dev_remap_addr(dev); if (IS_ERR(data->membase)) { ret = PTR_ERR(data->membase); - return log_msg_ret("Failed to remap base addr", ret); + dev_err(dev, "Failed to remap base addr %d\n", ret); + return log_msg_ret("mdio", ret); } // clk is optional @@ -89,8 +91,10 @@ static int hisi_femac_mdio_probe(struct udevice *dev) int ret; ret = clk_prepare_enable(data->clk); - if (ret) - return log_msg_ret("Failed to enable clk", ret); + if (ret) { + dev_err(dev, "Failed to enable clock: %d\n", ret); + return log_msg_ret("clk", ret); + } return 0; } @@ -112,5 +116,6 @@ U_BOOT_DRIVER(hisi_femac_mdio_driver) = { .of_to_plat = hisi_femac_mdio_of_to_plat, .probe = hisi_femac_mdio_probe, .ops = &hisi_femac_mdio_ops, + .plat_auto = sizeof(struct mdio_perdev_priv), .priv_auto = sizeof(struct hisi_femac_mdio_data), }; -- 2.43.0
Re: [PATCH] wdt: add HiSilicon watchdog driver support
On 1/19/2024 12:24 PM, Yang Xiwen via B4 Relay wrote: From: Yang Xiwen This watchdog core is found on many HiSilicon SoCs. Add support for it. Signed-off-by: Yang Xiwen --- drivers/watchdog/Kconfig| 10 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/hisi_wdt.c | 196 3 files changed, 207 insertions(+) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 569726119c..ddf44f63d2 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -32,6 +32,7 @@ config WATCHDOG_TIMEOUT_MSECS default 16000 if ARCH_SUNXI default 5376 if ULP_WATCHDOG default 15000 if ARCH_BCM283X + range 500 18 if ARCH_HISI default 6 help Watchdog timeout in msec @@ -171,6 +172,15 @@ config WDT_GPIO doc/device-tree-bindings/watchdog/gpio-wdt.txt for information on how to describe the watchdog in device tree. +config WDT_HISI + bool "HiSilicon watchdog timer support" + depends on WDT + depends on CLK && DM_RESET + imply WATCHDOG + help + Select this to enable HiSilicon watchdog timer. + Currently supports Hi3798MV200 only. + config WDT_MAX6370 bool "MAX6370 watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 5520d3d9ae..3436aa6389 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o obj-$(CONFIG_WDT_FTWDT010) += ftwdt010_wdt.o obj-$(CONFIG_WDT_GPIO) += gpio_wdt.o +obj-$(CONFIG_WDT_HISI) += hisi_wdt.o obj-$(CONFIG_WDT_MAX6370) += max6370_wdt.o obj-$(CONFIG_WDT_MCF) += mcf_wdt.o obj-$(CONFIG_WDT_MESON_GXBB) += meson_gxbb_wdt.o diff --git a/drivers/watchdog/hisi_wdt.c b/drivers/watchdog/hisi_wdt.c new file mode 100644 index 00..5be9e90865 --- /dev/null +++ b/drivers/watchdog/hisi_wdt.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Watchdog driver for HiSilicon SoCs + * + * Copyright 2024 (r) Yang Xiwen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* CONTROL register definitions */ +#define HISI_WDG_RES_ENBIT(1) +#define HISI_WDG_INT_ENBIT(0) + +/* RIS(Raw Interrupt Status) register definitions */ +#define HISI_WDG_RIS BIT(0) + +/* MIS(Masked Interrupt Status) register definitions*/ +#define HISI_WDG_MIS BIT(0) + +/* LOCK register magic */ +// Write this value to unlock watchdog +#define HISI_WDG_LOCK_MAGIC0x1ACCE551 +// Read values +#define HISI_WDG_LOCK_WA 0x0 +#define HISI_WDG_LOCK_RO 0x1 + +struct hisi_wdg_reg { + u32 load; // 0x + u32 value; // 0x0004 + u32 control; // 0x0008 + u32 intclr; // 0x000c + u32 ris; // 0x0010 + u32 mis; // 0x0014 + u32 reserved[762]; // 0x0018 + u32 lock; // 0x0c00 +}; + +struct hisi_wdt_priv { + struct hisi_wdg_reg __iomem *reg; + struct clk *clk; + struct reset_ctl *rst; +}; + +static inline void hisi_wdt_unlock(struct hisi_wdg_reg __iomem *reg) +{ + reg->lock = HISI_WDG_LOCK_MAGIC; +} + +static inline void hisi_wdt_lock(struct hisi_wdg_reg __iomem *reg) +{ + // Any value other than HISI_WDG_LOCK_MAGIC would lock the registers + reg->lock = 0; +} + +static int hisi_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct hisi_wdt_priv *priv = dev_get_priv(dev); + u64 rate; + u64 val; + + rate = clk_get_rate(priv->clk); + + /* This may overflow */ + val = mul_u64_u32_div(timeout_ms, rate, 1000); + if (val > UINT32_MAX) { + dev_warn(dev, "timeout_ms too large, using maximum.\n"); + val = UINT32_MAX; + } + + hisi_wdt_unlock(priv->reg); + + priv->reg->load = (u32) val; + priv->reg->control |= (HISI_WDG_RES_EN | HISI_WDG_INT_EN); + + hisi_wdt_lock(priv->reg); + + return 0; +} + +static int hisi_wdt_stop(struct udevice *dev) +{ + struct hisi_wdt_priv *priv = dev_get_priv(dev); + + hisi_wdt_unlock(priv->reg); + // disabling interrupt also disables counting + priv->reg->control &= ~HISI_WDG_INT_EN; + + hisi_wdt_lock(priv->reg); + + return 0; +} + +static int hisi_wdt_reset(struct udevice *dev) +{ + struct hisi_wdt_priv *priv = dev_get_priv(dev); + + hisi_wdt_unlock(priv->reg); + + // any value written to INTCLR would result a counter reload + priv->reg->intclr = 0; + + hisi_wdt_lock(priv->reg); + + return 0; +} + +static int hisi_wdt_expire_now(struct udevice *dev, ulong flags) +{ + return hisi_wdt_start(dev, 1, flags); +} + +stat
[PATCH RFC 2/2] clk: add clock framework for HiSilicon SoCs
From: Yang Xiwen Hi3798 Series SoCs have a CRG (Clock Reset Generator) module which manages all clocks and resets of the SoC. The first supported chip is Hi3798MV200. The unused clocks are not registered to save space and time. Only necessary clocks are implemented right now. Signed-off-by: Yang Xiwen --- drivers/clk/Kconfig | 7 ++ drivers/clk/Makefile| 1 + drivers/clk/hisilicon/Kconfig | 14 +++ drivers/clk/hisilicon/Makefile | 8 ++ drivers/clk/hisilicon/clk-hi3798mv200.c | 213 drivers/clk/hisilicon/clk.c | 102 +++ drivers/clk/hisilicon/clk.h | 55 + include/dt-bindings/clock/histb-clock.h | 4 + 8 files changed, 404 insertions(+) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 017dd260a5..4c5ac46b26 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -127,6 +127,12 @@ config CLK_ICS8N3QV01 Crystal Oscillator). The output frequency can be programmed via an I2C interface. +config CLK_HISI + bool "Enable Hisilicon Clock Framework" + depends on CLK && CLK_CCF + help + Support for Hisilicon Clock Framework. + config CLK_INTEL bool "Enable clock driver for Intel x86" depends on CLK && X86 @@ -249,6 +255,7 @@ config CLK_ZYNQMP source "drivers/clk/analogbits/Kconfig" source "drivers/clk/at91/Kconfig" source "drivers/clk/exynos/Kconfig" +source "drivers/clk/hisilicon/Kconfig" source "drivers/clk/imx/Kconfig" source "drivers/clk/meson/Kconfig" source "drivers/clk/microchip/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 638ad04bae..90e7e1b5f4 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o obj-$(CONFIG_CLK_BOSTON) += clk_boston.o obj-$(CONFIG_CLK_CDCE9XX) += clk-cdce9xx.o obj-$(CONFIG_CLK_EXYNOS) += exynos/ +obj-$(CONFIG_CLK_HISI) += hisilicon/ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o obj-$(CONFIG_CLK_K210) += clk_k210.o obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig new file mode 100644 index 00..caa51b7831 --- /dev/null +++ b/drivers/clk/hisilicon/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +if CLK_HISI +menu "HiSilicon CRG Driver" + +config COMMON_CLK_HI3798MV200 + tristate "Hi3798MV200 CRG Driver" + select RESET_HISILICON + depends on ARCH_HISTB + help + Build the CRG driver for Hi3798MV200. + +endmenu +endif diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile new file mode 100644 index 00..85a0ffb4a1 --- /dev/null +++ b/drivers/clk/hisilicon/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Hisilicon Clock specific Makefile +# + +obj-y += clk.o + +obj-$(CONFIG_COMMON_CLK_HI3798MV200) += clk-hi3798mv200.o diff --git a/drivers/clk/hisilicon/clk-hi3798mv200.c b/drivers/clk/hisilicon/clk-hi3798mv200.c new file mode 100644 index 00..01bb20d940 --- /dev/null +++ b/drivers/clk/hisilicon/clk-hi3798mv200.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hi3798MV200 Clock and Reset Generator Driver. + * Adapted from clk-hi3798cv200.c. + * + * Copyright (c) 2024 Yang Xiwen + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. + */ + +#include +#include +#include +#include +#include + +#include "clk.h" + +/* hi3798MV200 core CRG */ +#define HI3798MV200_INNER_CLK_OFFSET 64 +#define HI3798MV200_FIXED_12M 65 +#define HI3798MV200_FIXED_24M 66 +#define HI3798MV200_FIXED_25M 67 +#define HI3798MV200_FIXED_27M 68 +#define HI3798MV200_FIXED_48M 69 +#define HI3798MV200_FIXED_50M 70 +#define HI3798MV200_FIXED_54M 71 +#define HI3798MV200_FIXED_60M 72 +#define HI3798MV200_FIXED_75M 73 +#define HI3798MV200_FIXED_100M 74 +#define HI3798MV200_FIXED_150M 75 +#define HI3798MV200_FIXED_166P5M 76 +#define HI3798MV200_FIXED_200M 77 +#define HI3798MV200_FIXED_250M 78 +#define HI3798MV200_FIXED_300M 79 +#define HI3798MV200_FIXED_400M 80 +#define HI3798MV200_MMC_MUX81 +#define HI3798MV200_COMBPHY1_MUX 82 +#define HI3798MV200_SDIO0_MUX 83 +#define HI3798MV200_COMBPHY0_MUX 84 +#define HI3798MV200_SDIO1_MUX 85 +#define HI3798MV200_ETH_MUX86 + +static const struct hisi_fixed_rate_clock hi3798mv200_fixed_rate_clks[] = { + { HISTB_OSC_CLK, "clk_osc", 2400
[PATCH RFC 0/2] clk: add HiSilicon CLK framework
The first supported chip is Hi3798MV200. Signed-off-by: Yang Xiwen --- Yang Xiwen (2): clk: ccf: Export clk_register_mux_table() in linux/clk-provider.h clk: add clock framework for HiSilicon SoCs drivers/clk/Kconfig | 7 ++ drivers/clk/Makefile| 1 + drivers/clk/hisilicon/Kconfig | 14 +++ drivers/clk/hisilicon/Makefile | 8 ++ drivers/clk/hisilicon/clk-hi3798mv200.c | 213 drivers/clk/hisilicon/clk.c | 102 +++ drivers/clk/hisilicon/clk.h | 55 + include/dt-bindings/clock/histb-clock.h | 4 + include/linux/clk-provider.h| 6 + 9 files changed, 410 insertions(+) --- base-commit: f7cca7ccc5117eaafcc2bde91ad1bed6fee7cfc3 change-id: 20240119-b4-hisi-clk-88075b46c359 Best regards, -- Yang Xiwen
[PATCH RFC 1/2] clk: ccf: Export clk_register_mux_table() in linux/clk-provider.h
From: Yang Xiwen This function is used by HiSilicon Clock Framework. Signed-off-by: Yang Xiwen --- include/linux/clk-provider.h | 6 ++ 1 file changed, 6 insertions(+) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index b8acacd49e..952439ad39 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -247,6 +247,12 @@ struct clk *clk_register_mux(struct device *dev, const char *name, void __iomem *reg, u8 shift, u8 width, u8 clk_mux_flags); +struct clk *clk_register_mux_table(struct device *dev, const char *name, + const char * const *parent_names, u8 num_parents, + unsigned long flags, + void __iomem *reg, u8 shift, u32 mask, + u8 clk_mux_flags, u32 *table); + struct clk *clk_register_fixed_rate(struct device *dev, const char *name, ulong rate); -- 2.43.0
[PATCH RFC 2/2] clk: add clock framework for HiSilicon SoCs
From: Yang Xiwen Hi3798 Series SoCs have a CRG (Clock Reset Generator) module which manages all clocks and resets of the SoC. The first supported chip is Hi3798MV200. The unused clocks are not registered to save space and time. Only necessary clocks are implemented right now. Signed-off-by: Yang Xiwen --- drivers/clk/Kconfig | 7 ++ drivers/clk/Makefile| 1 + drivers/clk/hisilicon/Kconfig | 14 +++ drivers/clk/hisilicon/Makefile | 8 ++ drivers/clk/hisilicon/clk-hi3798mv200.c | 213 drivers/clk/hisilicon/clk.c | 102 +++ drivers/clk/hisilicon/clk.h | 55 + include/dt-bindings/clock/histb-clock.h | 4 + 8 files changed, 404 insertions(+) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 017dd260a5..4c5ac46b26 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -127,6 +127,12 @@ config CLK_ICS8N3QV01 Crystal Oscillator). The output frequency can be programmed via an I2C interface. +config CLK_HISI + bool "Enable Hisilicon Clock Framework" + depends on CLK && CLK_CCF + help + Support for Hisilicon Clock Framework. + config CLK_INTEL bool "Enable clock driver for Intel x86" depends on CLK && X86 @@ -249,6 +255,7 @@ config CLK_ZYNQMP source "drivers/clk/analogbits/Kconfig" source "drivers/clk/at91/Kconfig" source "drivers/clk/exynos/Kconfig" +source "drivers/clk/hisilicon/Kconfig" source "drivers/clk/imx/Kconfig" source "drivers/clk/meson/Kconfig" source "drivers/clk/microchip/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 638ad04bae..90e7e1b5f4 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o obj-$(CONFIG_CLK_BOSTON) += clk_boston.o obj-$(CONFIG_CLK_CDCE9XX) += clk-cdce9xx.o obj-$(CONFIG_CLK_EXYNOS) += exynos/ +obj-$(CONFIG_CLK_HISI) += hisilicon/ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o obj-$(CONFIG_CLK_K210) += clk_k210.o obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig new file mode 100644 index 00..caa51b7831 --- /dev/null +++ b/drivers/clk/hisilicon/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +if CLK_HISI +menu "HiSilicon CRG Driver" + +config COMMON_CLK_HI3798MV200 + tristate "Hi3798MV200 CRG Driver" + select RESET_HISILICON + depends on ARCH_HISTB + help + Build the CRG driver for Hi3798MV200. + +endmenu +endif diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile new file mode 100644 index 00..85a0ffb4a1 --- /dev/null +++ b/drivers/clk/hisilicon/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Hisilicon Clock specific Makefile +# + +obj-y += clk.o + +obj-$(CONFIG_COMMON_CLK_HI3798MV200) += clk-hi3798mv200.o diff --git a/drivers/clk/hisilicon/clk-hi3798mv200.c b/drivers/clk/hisilicon/clk-hi3798mv200.c new file mode 100644 index 00..01bb20d940 --- /dev/null +++ b/drivers/clk/hisilicon/clk-hi3798mv200.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hi3798MV200 Clock and Reset Generator Driver. + * Adapted from clk-hi3798cv200.c. + * + * Copyright (c) 2024 Yang Xiwen + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. + */ + +#include +#include +#include +#include +#include + +#include "clk.h" + +/* hi3798MV200 core CRG */ +#define HI3798MV200_INNER_CLK_OFFSET 64 +#define HI3798MV200_FIXED_12M 65 +#define HI3798MV200_FIXED_24M 66 +#define HI3798MV200_FIXED_25M 67 +#define HI3798MV200_FIXED_27M 68 +#define HI3798MV200_FIXED_48M 69 +#define HI3798MV200_FIXED_50M 70 +#define HI3798MV200_FIXED_54M 71 +#define HI3798MV200_FIXED_60M 72 +#define HI3798MV200_FIXED_75M 73 +#define HI3798MV200_FIXED_100M 74 +#define HI3798MV200_FIXED_150M 75 +#define HI3798MV200_FIXED_166P5M 76 +#define HI3798MV200_FIXED_200M 77 +#define HI3798MV200_FIXED_250M 78 +#define HI3798MV200_FIXED_300M 79 +#define HI3798MV200_FIXED_400M 80 +#define HI3798MV200_MMC_MUX81 +#define HI3798MV200_COMBPHY1_MUX 82 +#define HI3798MV200_SDIO0_MUX 83 +#define HI3798MV200_COMBPHY0_MUX 84 +#define HI3798MV200_SDIO1_MUX 85 +#define HI3798MV200_ETH_MUX86 + +static const struct hisi_fixed_rate_clock hi3798mv200_fixed_rate_clks[] = { + { HISTB_OSC_CLK, "clk_osc", 2400
[PATCH RFC 0/2] clk: add HiSilicon CLK framework
The first supported chip is Hi3798MV200. Signed-off-by: Yang Xiwen --- Yang Xiwen (2): clk: ccf: Export clk_register_mux_table() in linux/clk-provider.h clk: add clock framework for HiSilicon SoCs drivers/clk/Kconfig | 7 ++ drivers/clk/Makefile| 1 + drivers/clk/hisilicon/Kconfig | 14 +++ drivers/clk/hisilicon/Makefile | 8 ++ drivers/clk/hisilicon/clk-hi3798mv200.c | 213 drivers/clk/hisilicon/clk.c | 102 +++ drivers/clk/hisilicon/clk.h | 55 + include/dt-bindings/clock/histb-clock.h | 4 + include/linux/clk-provider.h| 6 + 9 files changed, 410 insertions(+) --- base-commit: f7cca7ccc5117eaafcc2bde91ad1bed6fee7cfc3 change-id: 20240119-b4-hisi-clk-88075b46c359 Best regards, -- Yang Xiwen
[PATCH RFC 1/2] clk: ccf: Export clk_register_mux_table() in linux/clk-provider.h
From: Yang Xiwen This function is used by HiSilicon Clock Framework. Signed-off-by: Yang Xiwen --- include/linux/clk-provider.h | 6 ++ 1 file changed, 6 insertions(+) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index b8acacd49e..952439ad39 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -247,6 +247,12 @@ struct clk *clk_register_mux(struct device *dev, const char *name, void __iomem *reg, u8 shift, u8 width, u8 clk_mux_flags); +struct clk *clk_register_mux_table(struct device *dev, const char *name, + const char * const *parent_names, u8 num_parents, + unsigned long flags, + void __iomem *reg, u8 shift, u32 mask, + u8 clk_mux_flags, u32 *table); + struct clk *clk_register_fixed_rate(struct device *dev, const char *name, ulong rate); -- 2.43.0
[PATCH] reset: reset-hisilicon: also handle #reset-cells = <2>
From: Yang Xiwen It's also valid to have #reset-cells = <2> while the third arg defaults to ASSERT_SET. Signed-off-by: Yang Xiwen --- drivers/reset/reset-hisilicon.c | 15 +-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/reset/reset-hisilicon.c b/drivers/reset/reset-hisilicon.c index 8152cec227..85e02b296b 100644 --- a/drivers/reset/reset-hisilicon.c +++ b/drivers/reset/reset-hisilicon.c @@ -49,7 +49,18 @@ static int hisi_reset_assert(struct reset_ctl *rst) static int hisi_reset_of_xlate(struct reset_ctl *rst, struct ofnode_phandle_args *args) { - if (args->args_count != 3) { + unsigned long polarity; + + switch (args->args_count) { + case 2: + polarity = ASSERT_SET; + break; + + case 3: + polarity = args->args[2]; + break; + + default: debug("Invalid args_count: %d\n", args->args_count); return -EINVAL; } @@ -57,7 +68,7 @@ static int hisi_reset_of_xlate(struct reset_ctl *rst, /* Use .data field as register offset and .id field as bit shift */ rst->data = args->args[0]; rst->id = args->args[1]; - rst->polarity = args->args[2]; + rst->polarity = polarity; return 0; } --- base-commit: f7cca7ccc5117eaafcc2bde91ad1bed6fee7cfc3 change-id: 20240119-rst-0bc8097b847a Best regards, -- Yang Xiwen
[PATCH 0/3] net: hifemac: a few cleanups
Fix the use of log_msg_ret() and add dev_xxx() for error reporting. Register mdio subnode as a mdio bus device for hifemac. Signed-off-by: Yang Xiwen --- Yang Xiwen (3): net: hifemac_mdio: use log_msg_ret() correctly, report error by dev_err() net: hifemac: fix log reporting net: hifemac: register MDIO bus device for subnode drivers/net/hifemac.c | 138 + drivers/net/hifemac_mdio.c | 11 +++- 2 files changed, 109 insertions(+), 40 deletions(-) --- base-commit: f7cca7ccc5117eaafcc2bde91ad1bed6fee7cfc3 change-id: 20240119-net-72a32675eeb4 Best regards, -- Yang Xiwen
[PATCH 3/3] net: hifemac: register MDIO bus device for subnode
From: Yang Xiwen register internal MDIO bus device if it is a subnode. Signed-off-by: Yang Xiwen --- drivers/net/hifemac.c | 28 1 file changed, 28 insertions(+) diff --git a/drivers/net/hifemac.c b/drivers/net/hifemac.c index 1088f3eca3..39c0233b62 100644 --- a/drivers/net/hifemac.c +++ b/drivers/net/hifemac.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -337,6 +338,8 @@ int hisi_femac_of_to_plat(struct udevice *dev) { int ret, i; struct hisi_femac_priv *priv = dev_get_priv(dev); + ofnode mdio_node; + bool mdio_registered = false; static const char * const clk_strs[] = { [CLK_MAC] = "mac", [CLK_BUS] = "bus", @@ -388,6 +391,31 @@ int hisi_femac_of_to_plat(struct udevice *dev) MAC_RESET_DELAY_PROPERTY, MAC_RESET_ASSERT_PERIOD); + /* Create MDIO bus */ + ofnode_for_each_subnode(mdio_node, dev_ofnode(dev)) { + const char *subnode_name = ofnode_get_name(mdio_node); + struct udevice *mdiodev; + + // Skip subnodes not starting with "mdio" + if (strncmp(subnode_name, "mdio", 4)) + continue; + + ret = device_bind_driver_to_node(dev, "hisi-femac-mdio", +subnode_name, mdio_node, &mdiodev); + if (ret) { + dev_err(dev, "Failed to register MDIO bus device %d\n", ret); + return log_msg_ret("net", ret); + } + + mdio_registered = true; + break; + } + + if (!mdio_registered) { + dev_err(dev, "No MDIO subnode is found!\n"); + return log_msg_ret("mdio", -ENODATA); + } + return 0; } -- 2.43.0
[PATCH 2/3] net: hifemac: fix log reporting
From: Yang Xiwen shrink the first argument of log_msg_ret(), add dev_xxx() functions for error reporting. Fixes: 9d8f78a2a79f7 ("net: add hifemac Ethernet driver for HiSilicon platform") Signed-off-by: Yang Xiwen --- drivers/net/hifemac.c | 110 +- 1 file changed, 73 insertions(+), 37 deletions(-) diff --git a/drivers/net/hifemac.c b/drivers/net/hifemac.c index b61a29e636..1088f3eca3 100644 --- a/drivers/net/hifemac.c +++ b/drivers/net/hifemac.c @@ -245,8 +245,10 @@ static int hisi_femac_start(struct udevice *dev) hisi_femac_rx_refill(priv); ret = phy_startup(priv->phy); - if (ret) - return log_msg_ret("Failed to startup phy", ret); + if (ret) { + dev_err(dev, "Failed to startup phy: %d\n", ret); + return log_msg_ret("phy", ret); + } if (!priv->phy->link) { debug("%s: link down\n", __func__); @@ -281,8 +283,10 @@ static int hisi_femac_send(struct udevice *dev, void *packet, int length) // wait until FIFO is empty ret = wait_for_bit_le32(priv->glb_base + GLB_IRQ_RAW, IRQ_INT_TX_PER_PACKET, true, 50, false); - if (ret == -ETIMEDOUT) - return log_msg_ret("FIFO timeout", ret); + if (ret == -ETIMEDOUT) { + dev_err(dev, "FIFO timeout\n"); + return log_msg_ret("net", ret); + } return 0; } @@ -340,35 +344,45 @@ int hisi_femac_of_to_plat(struct udevice *dev) }; priv->port_base = dev_remap_addr_name(dev, "port"); - if (IS_ERR(priv->port_base)) - return log_msg_ret("Failed to remap port address space", PTR_ERR(priv->port_base)); + if (!priv->port_base) { + dev_err(dev, "Failed to remap port address space\n"); + return log_msg_ret("net", -EINVAL); + } priv->glb_base = dev_remap_addr_name(dev, "glb"); - if (IS_ERR(priv->glb_base)) - return log_msg_ret("Failed to remap global address space", PTR_ERR(priv->glb_base)); + if (IS_ERR(priv->glb_base)) { + dev_err(dev, "Failed to remap global address space\n"); + return log_msg_ret("net", -EINVAL); + } for (i = 0; i < ARRAY_SIZE(clk_strs); i++) { priv->clks[i] = devm_clk_get(dev, clk_strs[i]); if (IS_ERR(priv->clks[i])) { dev_err(dev, "Error getting clock %s\n", clk_strs[i]); - return log_msg_ret("Failed to get clocks", PTR_ERR(priv->clks[i])); + return log_msg_ret("clk", PTR_ERR(priv->clks[i])); } } priv->mac_rst = devm_reset_control_get(dev, "mac"); - if (IS_ERR(priv->mac_rst)) - return log_msg_ret("Failed to get MAC reset", PTR_ERR(priv->mac_rst)); + if (IS_ERR(priv->mac_rst)) { + dev_err(dev, "Failed to get MAC reset %ld\n", PTR_ERR(priv->mac_rst)); + return log_msg_ret("rst", PTR_ERR(priv->mac_rst)); + } priv->phy_rst = devm_reset_control_get(dev, "phy"); - if (IS_ERR(priv->phy_rst)) - return log_msg_ret("Failed to get PHY reset", PTR_ERR(priv->phy_rst)); + if (IS_ERR(priv->phy_rst)) { + dev_err(dev, "Failed to get PHY reset %ld\n", PTR_ERR(priv->phy_rst)); + return log_msg_ret("rst", PTR_ERR(priv->phy_rst)); + } ret = dev_read_u32_array(dev, PHY_RESET_DELAYS_PROPERTY, priv->phy_reset_delays, DELAYS_NUM); - if (ret < 0) - return log_msg_ret("Failed to get PHY reset delays", ret); + if (ret < 0) { + dev_err(dev, "Failed to get PHY reset delays %d\n", ret); + return log_msg_ret("rst", ret); + } priv->mac_reset_delay = dev_read_u32_default(dev, MAC_RESET_DELAY_PROPERTY, @@ -385,32 +399,44 @@ static int hisi_femac_phy_reset(struct hisi_femac_priv *priv) // Disable MAC clk before phy reset ret = clk_disable(priv->clks[CLK_MAC]); - if (ret < 0) - return log_msg_ret("Failed to disable MAC clock", ret); + if (ret < 0) { + pr_err("%s: Failed to disable MAC clock %d\n", __func__, ret); + return log_msg_ret("clk", ret); + } ret = clk_disable(priv->clks[CL
[PATCH 1/3] net: hifemac_mdio: use log_msg_ret() correctly, report error by dev_err()
From: Yang Xiwen The initial commit used log_msg_ret() wrongly. Fix that by moving error report to a separate dev_err() call and shrink the first argument of log_msg_ret() to no more than 4 chars. Fixes: 6b5c8d98e204 ("net: add hifemac_mdio MDIO bus driver for HiSilicon platform") Signed-off-by: Yang Xiwen --- drivers/net/hifemac_mdio.c | 11 --- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/hifemac_mdio.c b/drivers/net/hifemac_mdio.c index 343c5f3a38..0b59d06091 100644 --- a/drivers/net/hifemac_mdio.c +++ b/drivers/net/hifemac_mdio.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -74,7 +75,8 @@ static int hisi_femac_mdio_of_to_plat(struct udevice *dev) data->membase = dev_remap_addr(dev); if (IS_ERR(data->membase)) { ret = PTR_ERR(data->membase); - return log_msg_ret("Failed to remap base addr", ret); + dev_err(dev, "Failed to remap base addr %d\n", ret); + return log_msg_ret("mdio", ret); } // clk is optional @@ -89,8 +91,10 @@ static int hisi_femac_mdio_probe(struct udevice *dev) int ret; ret = clk_prepare_enable(data->clk); - if (ret) - return log_msg_ret("Failed to enable clk", ret); + if (ret) { + dev_err(dev, "Failed to enable clock: %d\n", ret); + return log_msg_ret("clk", ret); + } return 0; } @@ -112,5 +116,6 @@ U_BOOT_DRIVER(hisi_femac_mdio_driver) = { .of_to_plat = hisi_femac_mdio_of_to_plat, .probe = hisi_femac_mdio_probe, .ops = &hisi_femac_mdio_ops, + .plat_auto = sizeof(struct mdio_perdev_priv), .priv_auto = sizeof(struct hisi_femac_mdio_data), }; -- 2.43.0
[PATCH] mmc: hi6220-dwmmc: handle clocks and resets if CONFIG_CLK and CONFIG_DM_RESET enabled
From: Yang Xiwen This can avoid hardcoding a clock rate in driver. Also can enable the clocks and deassert the resets if the pre-bootloader does not do this for us. Currently only enabled for Hi3798MV200. Signed-off-by: Yang Xiwen --- drivers/mmc/hi6220_dw_mmc.c | 61 - 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/hi6220_dw_mmc.c b/drivers/mmc/hi6220_dw_mmc.c index 71962cd47e..a4b8072976 100644 --- a/drivers/mmc/hi6220_dw_mmc.c +++ b/drivers/mmc/hi6220_dw_mmc.c @@ -5,15 +5,24 @@ */ #include +#include #include #include #include #include #include +#include #include +#include DECLARE_GLOBAL_DATA_PTR; +enum hi6220_dwmmc_clk_type { + HI6220_DWMMC_CLK_BIU, + HI6220_DWMMC_CLK_CIU, + HI6220_DWMMC_CLK_CNT, +}; + struct hi6220_dwmmc_plat { struct mmc_config cfg; struct mmc mmc; @@ -21,6 +30,8 @@ struct hi6220_dwmmc_plat { struct hi6220_dwmmc_priv_data { struct dwmci_host host; + struct clk *clks[HI6220_DWMMC_CLK_CNT]; + struct reset_ctl_bulk rsts; }; struct hisi_mmc_data { @@ -32,7 +43,29 @@ static int hi6220_dwmmc_of_to_plat(struct udevice *dev) { struct hi6220_dwmmc_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; + int ret; + if (CONFIG_IS_ENABLED(CLK) && CONFIG_IS_ENABLED(DM_RESET)) { + priv->clks[HI6220_DWMMC_CLK_BIU] = devm_clk_get(dev, "biu"); + if (IS_ERR(priv->clks[HI6220_DWMMC_CLK_BIU])) { + ret = PTR_ERR(priv->clks[HI6220_DWMMC_CLK_BIU]); + dev_err(dev, "Failed to get BIU clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + priv->clks[HI6220_DWMMC_CLK_CIU] = devm_clk_get(dev, "ciu"); + if (IS_ERR(priv->clks[HI6220_DWMMC_CLK_CIU])) { + ret = PTR_ERR(priv->clks[HI6220_DWMMC_CLK_CIU]); + dev_err(dev, "Failed to get CIU clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + ret = reset_get_bulk(dev, &priv->rsts); + if (ret) { + dev_err(dev, "Failed to get resets(ret = %d)", ret); + return log_msg_ret("rst", ret); + } + } host->name = dev->name; host->ioaddr = dev_read_addr_ptr(dev); host->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), @@ -56,11 +89,37 @@ static int hi6220_dwmmc_probe(struct udevice *dev) struct hi6220_dwmmc_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; struct hisi_mmc_data *mmc_data; + int ret; mmc_data = (struct hisi_mmc_data *)dev_get_driver_data(dev); - /* Use default bus speed due to absence of clk driver */ host->bus_hz = mmc_data->clock; + if (CONFIG_IS_ENABLED(CLK) && CONFIG_IS_ENABLED(DM_RESET)) { + ret = clk_prepare_enable(priv->clks[HI6220_DWMMC_CLK_BIU]); + if (ret) { + dev_err(dev, "Failed to enable biu clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + ret = clk_prepare_enable(priv->clks[HI6220_DWMMC_CLK_CIU]); + if (ret) { + dev_err(dev, "Failed to enable ciu clock(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + + ret = reset_deassert_bulk(&priv->rsts); + if (ret) { + dev_err(dev, "Failed to deassert resets(ret = %d).\n", ret); + return log_msg_ret("rst", ret); + } + + host->bus_hz = clk_get_rate(priv->clks[HI6220_DWMMC_CLK_CIU]); + if (host->bus_hz <= 0) { + dev_err(dev, "Failed to get ciu clock rate(ret = %d).\n", ret); + return log_msg_ret("clk", ret); + } + } + dev_dbg(dev, "bus clock rate: %d.\n", host->bus_hz); dwmci_setup_cfg(&plat->cfg, host, host->bus_hz, 40); host->mmc = &plat->mmc; --- base-commit: f7cca7ccc5117eaafcc2bde91ad1bed6fee7cfc3 change-id: 20240119-mmc-9cf7f3455cb4 Best regards, -- Yang Xiwen
[PATCH] wdt: add HiSilicon watchdog driver support
From: Yang Xiwen This watchdog core is found on many HiSilicon SoCs. Add support for it. Signed-off-by: Yang Xiwen --- drivers/watchdog/Kconfig| 10 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/hisi_wdt.c | 196 3 files changed, 207 insertions(+) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 569726119c..ddf44f63d2 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -32,6 +32,7 @@ config WATCHDOG_TIMEOUT_MSECS default 16000 if ARCH_SUNXI default 5376 if ULP_WATCHDOG default 15000 if ARCH_BCM283X + range 500 18 if ARCH_HISI default 6 help Watchdog timeout in msec @@ -171,6 +172,15 @@ config WDT_GPIO doc/device-tree-bindings/watchdog/gpio-wdt.txt for information on how to describe the watchdog in device tree. +config WDT_HISI + bool "HiSilicon watchdog timer support" + depends on WDT + depends on CLK && DM_RESET + imply WATCHDOG + help + Select this to enable HiSilicon watchdog timer. + Currently supports Hi3798MV200 only. + config WDT_MAX6370 bool "MAX6370 watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 5520d3d9ae..3436aa6389 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o obj-$(CONFIG_WDT_FTWDT010) += ftwdt010_wdt.o obj-$(CONFIG_WDT_GPIO) += gpio_wdt.o +obj-$(CONFIG_WDT_HISI) += hisi_wdt.o obj-$(CONFIG_WDT_MAX6370) += max6370_wdt.o obj-$(CONFIG_WDT_MCF) += mcf_wdt.o obj-$(CONFIG_WDT_MESON_GXBB) += meson_gxbb_wdt.o diff --git a/drivers/watchdog/hisi_wdt.c b/drivers/watchdog/hisi_wdt.c new file mode 100644 index 00..5be9e90865 --- /dev/null +++ b/drivers/watchdog/hisi_wdt.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Watchdog driver for HiSilicon SoCs + * + * Copyright 2024 (r) Yang Xiwen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* CONTROL register definitions */ +#define HISI_WDG_RES_ENBIT(1) +#define HISI_WDG_INT_ENBIT(0) + +/* RIS(Raw Interrupt Status) register definitions */ +#define HISI_WDG_RIS BIT(0) + +/* MIS(Masked Interrupt Status) register definitions*/ +#define HISI_WDG_MIS BIT(0) + +/* LOCK register magic */ +// Write this value to unlock watchdog +#define HISI_WDG_LOCK_MAGIC0x1ACCE551 +// Read values +#define HISI_WDG_LOCK_WA 0x0 +#define HISI_WDG_LOCK_RO 0x1 + +struct hisi_wdg_reg { + u32 load; // 0x + u32 value; // 0x0004 + u32 control; // 0x0008 + u32 intclr; // 0x000c + u32 ris; // 0x0010 + u32 mis; // 0x0014 + u32 reserved[762]; // 0x0018 + u32 lock; // 0x0c00 +}; + +struct hisi_wdt_priv { + struct hisi_wdg_reg __iomem *reg; + struct clk *clk; + struct reset_ctl *rst; +}; + +static inline void hisi_wdt_unlock(struct hisi_wdg_reg __iomem *reg) +{ + reg->lock = HISI_WDG_LOCK_MAGIC; +} + +static inline void hisi_wdt_lock(struct hisi_wdg_reg __iomem *reg) +{ + // Any value other than HISI_WDG_LOCK_MAGIC would lock the registers + reg->lock = 0; +} + +static int hisi_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct hisi_wdt_priv *priv = dev_get_priv(dev); + u64 rate; + u64 val; + + rate = clk_get_rate(priv->clk); + + /* This may overflow */ + val = mul_u64_u32_div(timeout_ms, rate, 1000); + if (val > UINT32_MAX) { + dev_warn(dev, "timeout_ms too large, using maximum.\n"); + val = UINT32_MAX; + } + + hisi_wdt_unlock(priv->reg); + + priv->reg->load = (u32) val; + priv->reg->control |= (HISI_WDG_RES_EN | HISI_WDG_INT_EN); + + hisi_wdt_lock(priv->reg); + + return 0; +} + +static int hisi_wdt_stop(struct udevice *dev) +{ + struct hisi_wdt_priv *priv = dev_get_priv(dev); + + hisi_wdt_unlock(priv->reg); + // disabling interrupt also disables counting + priv->reg->control &= ~HISI_WDG_INT_EN; + + hisi_wdt_lock(priv->reg); + + return 0; +} + +static int hisi_wdt_reset(struct udevice *dev) +{ + struct hisi_wdt_priv *priv = dev_get_priv(dev); + + hisi_wdt_unlock(priv->reg); + + // any value written to INTCLR would result a counter reload + priv->reg->intclr = 0; + + hisi_wdt_lock(priv->reg); + + return 0; +} + +static int hisi_wdt_expire_now(struct udevice *dev, ulong flags) +{ + return hisi_wdt_start(dev, 1, flags); +} + +static const struct wdt_ops hisi_wdt_ops = { + .start = h
[PATCH] test: dm: clk_ccf: fix building error
From: Yang Xiwen Fix unused variable error produced by building tests Fixes: d3061824 (test: dm: clk_ccf: test ccf_clk_ops) Signed-off-by: Yang Xiwen --- it's detected by u-boot gitlab CI. --- test/dm/clk_ccf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/dm/clk_ccf.c b/test/dm/clk_ccf.c index b8be6d6572..5a3c58c6b5 100644 --- a/test/dm/clk_ccf.c +++ b/test/dm/clk_ccf.c @@ -18,11 +18,12 @@ /* Tests for Common Clock Framework driver */ static int dm_test_clk_ccf(struct unit_test_state *uts) { - struct clk *clk, *pclk, clk_ccf; + struct clk *clk, *pclk; struct udevice *dev, *test_dev; long long rate; int ret; #if CONFIG_IS_ENABLED(CLK_CCF) + struct clk clk_ccf; const char *clkname; int clkid, i; #endif --- base-commit: c9945276f77921feb8df7be75cced3338d08e8d4 change-id: 20231216-b4-fix_build-d05f2b26c8a7 Best regards, -- Yang Xiwen
[PATCH v3 0/2] clk: ccf: fix enable_count mismatch
As described in [1], enable_count is incremented by 2 when ccf_clk_enable() is called. This series of patch fixed this issue and added a testcase for that. [1]: https://lore.kernel.org/all/sezpr06mb695927a6deeef8489a06897396...@sezpr06mb6959.apcprd06.prod.outlook.com/ Signed-off-by: Yang Xiwen --- Changes in v3: - move i2v_root in front of devm clocks. So that clk_test driver needs a minimum modification - squash patch 1, 3 and 4. -- Suggested by Sean - rewrite commit log for clarity. - Link to v2: https://lore.kernel.org/r/2023-enable_count-v2-0-20e372860...@outlook.com Changes in v2: - add missing SoB in patch 1/4, no functional change - Link to v1: https://lore.kernel.org/r/2023-enable_count-v1-0-509f400a9...@outlook.com --- Yang Xiwen (2): clk: get correct ops for clk_enable() and clk_disable() test: dm: clk_ccf: test ccf_clk_ops arch/sandbox/dts/test.dts | 4 +++- arch/sandbox/include/asm/clk.h | 1 + drivers/clk/clk-uclass.c | 2 ++ drivers/clk/clk_sandbox_ccf.c | 1 + drivers/clk/clk_sandbox_test.c | 1 + test/dm/clk_ccf.c | 14 +++--- 6 files changed, 19 insertions(+), 4 deletions(-) --- base-commit: 3b913c148249a2b9d12ff25517ec311646e83bee change-id: 2023-enable_count-ad5001326815 Best regards, -- Yang Xiwen
[PATCH v3 1/2] clk: get correct ops for clk_enable() and clk_disable()
From: Yang Xiwen assign clk_dev_ops(clkp->dev) to ops to ensure correct clk operations are called on clocks. This fixes the incorrect enable_count issue as described in [1]. [1]: https://lore.kernel.org/all/sezpr06mb695927a6deeef8489a06897396...@sezpr06mb6959.apcprd06.prod.outlook.com/ Reviewed-by: Sean Anderson Signed-off-by: Yang Xiwen --- drivers/clk/clk-uclass.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 3b5e3f9c86..3e9d68feb3 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -640,6 +640,7 @@ int clk_enable(struct clk *clk) if (CONFIG_IS_ENABLED(CLK_CCF)) { /* Take id 0 as a non-valid clk, such as dummy */ if (clk->id && !clk_get_by_id(clk->id, &clkp)) { + ops = clk_dev_ops(clkp->dev); if (clkp->enable_count) { clkp->enable_count++; return 0; @@ -699,6 +700,7 @@ int clk_disable(struct clk *clk) if (CONFIG_IS_ENABLED(CLK_CCF)) { if (clk->id && !clk_get_by_id(clk->id, &clkp)) { + ops = clk_dev_ops(clkp->dev); if (clkp->flags & CLK_IS_CRITICAL) return 0; -- 2.39.2
[PATCH v3 2/2] test: dm: clk_ccf: test ccf_clk_ops
From: Yang Xiwen Assign ccf_clk_ops to .ops of clk_ccf driver so that it can act as an clk provider. Also add "#clock-cells=<1>" to its device tree node. Add "i2c_root" to clk_test in the device tree and driver for testing. Get "i2c_root" clock in CCF unit tests and add tests for it. Signed-off-by: Yang Xiwen --- arch/sandbox/dts/test.dts | 4 +++- arch/sandbox/include/asm/clk.h | 1 + drivers/clk/clk_sandbox_ccf.c | 1 + drivers/clk/clk_sandbox_test.c | 1 + test/dm/clk_ccf.c | 14 +++--- 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index c7197795ef..a3a865d65c 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -631,9 +631,10 @@ clocks = <&clk_fixed>, <&clk_sandbox 1>, <&clk_sandbox 0>, +<&ccf 11>, <&clk_sandbox 3>, <&clk_sandbox 2>; - clock-names = "fixed", "i2c", "spi", "uart2", "uart1"; + clock-names = "fixed", "i2c", "spi", "i2c_root", "uart2", "uart1"; }; clk-test2 { @@ -654,6 +655,7 @@ ccf: clk-ccf { compatible = "sandbox,clk-ccf"; + #clock-cells = <1>; }; efi-media { diff --git a/arch/sandbox/include/asm/clk.h b/arch/sandbox/include/asm/clk.h index df7156fe31..1daf2e7ac7 100644 --- a/arch/sandbox/include/asm/clk.h +++ b/arch/sandbox/include/asm/clk.h @@ -39,6 +39,7 @@ enum sandbox_clk_test_id { SANDBOX_CLK_TEST_ID_FIXED, SANDBOX_CLK_TEST_ID_SPI, SANDBOX_CLK_TEST_ID_I2C, + SANDBOX_CLK_TEST_ID_I2C_ROOT, SANDBOX_CLK_TEST_ID_DEVM1, SANDBOX_CLK_TEST_ID_DEVM2, SANDBOX_CLK_TEST_ID_DEVM_NULL, diff --git a/drivers/clk/clk_sandbox_ccf.c b/drivers/clk/clk_sandbox_ccf.c index fedcdd4044..38184e27aa 100644 --- a/drivers/clk/clk_sandbox_ccf.c +++ b/drivers/clk/clk_sandbox_ccf.c @@ -284,6 +284,7 @@ static int sandbox_clk_ccf_probe(struct udevice *dev) U_BOOT_DRIVER(sandbox_clk_ccf) = { .name = "sandbox_clk_ccf", .id = UCLASS_CLK, + .ops = &ccf_clk_ops, .probe = sandbox_clk_ccf_probe, .of_match = sandbox_clk_ccf_test_ids, }; diff --git a/drivers/clk/clk_sandbox_test.c b/drivers/clk/clk_sandbox_test.c index 5807a454f3..c695b69321 100644 --- a/drivers/clk/clk_sandbox_test.c +++ b/drivers/clk/clk_sandbox_test.c @@ -15,6 +15,7 @@ static const char * const sandbox_clk_test_names[] = { [SANDBOX_CLK_TEST_ID_FIXED] = "fixed", [SANDBOX_CLK_TEST_ID_SPI] = "spi", [SANDBOX_CLK_TEST_ID_I2C] = "i2c", + [SANDBOX_CLK_TEST_ID_I2C_ROOT] = "i2c_root", }; int sandbox_clk_test_get(struct udevice *dev) diff --git a/test/dm/clk_ccf.c b/test/dm/clk_ccf.c index e4ebb93cda..b8be6d6572 100644 --- a/test/dm/clk_ccf.c +++ b/test/dm/clk_ccf.c @@ -18,8 +18,8 @@ /* Tests for Common Clock Framework driver */ static int dm_test_clk_ccf(struct unit_test_state *uts) { - struct clk *clk, *pclk; - struct udevice *dev; + struct clk *clk, *pclk, clk_ccf; + struct udevice *dev, *test_dev; long long rate; int ret; #if CONFIG_IS_ENABLED(CLK_CCF) @@ -29,6 +29,7 @@ static int dm_test_clk_ccf(struct unit_test_state *uts) /* Get the device using the clk device */ ut_assertok(uclass_get_device_by_name(UCLASS_CLK, "clk-ccf", &dev)); + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "clk-test", &test_dev)); /* Test for clk_get_by_id() */ ret = clk_get_by_id(SANDBOX_CLK_ECSPI_ROOT, &clk); @@ -110,11 +111,18 @@ static int dm_test_clk_ccf(struct unit_test_state *uts) #if CONFIG_IS_ENABLED(CLK_CCF) /* Test clk tree enable/disable */ + + ret = clk_get_by_index(test_dev, SANDBOX_CLK_TEST_ID_I2C_ROOT, &clk_ccf); + ut_assertok(ret); + ut_asserteq_str("clk-ccf", clk_ccf.dev->name); + ut_asserteq(clk_ccf.id, SANDBOX_CLK_I2C_ROOT); + ret = clk_get_by_id(SANDBOX_CLK_I2C_ROOT, &clk); ut_assertok(ret); ut_asserteq_str("i2c_root", clk->dev->name); + ut_asserteq(clk->id, SANDBOX_CLK_I2C_ROOT); - ret = clk_enable(clk); + ret = clk_enable(&clk_ccf); ut_assertok(ret); ret = sandbox_clk_enable_count(clk); -- 2.39.2
[PATCH v2 2/4] clk: get correct ops for clk_enable() and clk_disable()
From: Yang Xiwen assign clk_dev_ops(clkp->dev) to ops to ensure correct clk operations are called on clocks. This fixes the incorrect enable_count issue as described in [1]. [1]: https://lore.kernel.org/all/sezpr06mb695927a6deeef8489a06897396...@sezpr06mb6959.apcprd06.prod.outlook.com/ Signed-off-by: Yang Xiwen --- drivers/clk/clk-uclass.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 3b5e3f9c86..3e9d68feb3 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -640,6 +640,7 @@ int clk_enable(struct clk *clk) if (CONFIG_IS_ENABLED(CLK_CCF)) { /* Take id 0 as a non-valid clk, such as dummy */ if (clk->id && !clk_get_by_id(clk->id, &clkp)) { + ops = clk_dev_ops(clkp->dev); if (clkp->enable_count) { clkp->enable_count++; return 0; @@ -699,6 +700,7 @@ int clk_disable(struct clk *clk) if (CONFIG_IS_ENABLED(CLK_CCF)) { if (clk->id && !clk_get_by_id(clk->id, &clkp)) { + ops = clk_dev_ops(clkp->dev); if (clkp->flags & CLK_IS_CRITICAL) return 0; -- 2.39.2
[PATCH v2 1/4] clk: clk_sandbox_ccf: assign ccf_clk_ops to .ops of the driver
From: Yang Xiwen It can now act as an clk provider on which ccf_clk_ops can be tested. Also add "#clock-cells=<1>" to test.dts. Signed-off-by: Yang Xiwen --- arch/sandbox/dts/test.dts | 1 + drivers/clk/clk_sandbox_ccf.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index c7197795ef..b1773f1bc2 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -654,6 +654,7 @@ ccf: clk-ccf { compatible = "sandbox,clk-ccf"; + #clock-cells = <1>; }; efi-media { diff --git a/drivers/clk/clk_sandbox_ccf.c b/drivers/clk/clk_sandbox_ccf.c index fedcdd4044..38184e27aa 100644 --- a/drivers/clk/clk_sandbox_ccf.c +++ b/drivers/clk/clk_sandbox_ccf.c @@ -284,6 +284,7 @@ static int sandbox_clk_ccf_probe(struct udevice *dev) U_BOOT_DRIVER(sandbox_clk_ccf) = { .name = "sandbox_clk_ccf", .id = UCLASS_CLK, + .ops = &ccf_clk_ops, .probe = sandbox_clk_ccf_probe, .of_match = sandbox_clk_ccf_test_ids, }; -- 2.39.2
[PATCH v2 3/4] clk: clk_sandbox: get devm clock i2c_root
From: Yang Xiwen This clock is added to dts. Get it in the devm group in the driver or the testcases will fail. Signed-off-by: Yang Xiwen --- arch/sandbox/dts/test.dts | 5 +++-- arch/sandbox/include/asm/clk.h | 1 + drivers/clk/clk_sandbox_test.c | 5 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index b1773f1bc2..f99397c528 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -632,8 +632,9 @@ <&clk_sandbox 1>, <&clk_sandbox 0>, <&clk_sandbox 3>, -<&clk_sandbox 2>; - clock-names = "fixed", "i2c", "spi", "uart2", "uart1"; +<&clk_sandbox 2>, +<&ccf 11>; + clock-names = "fixed", "i2c", "spi", "uart2", "uart1", "i2c_root"; }; clk-test2 { diff --git a/arch/sandbox/include/asm/clk.h b/arch/sandbox/include/asm/clk.h index df7156fe31..597bc528dc 100644 --- a/arch/sandbox/include/asm/clk.h +++ b/arch/sandbox/include/asm/clk.h @@ -41,6 +41,7 @@ enum sandbox_clk_test_id { SANDBOX_CLK_TEST_ID_I2C, SANDBOX_CLK_TEST_ID_DEVM1, SANDBOX_CLK_TEST_ID_DEVM2, + SANDBOX_CLK_TEST_ID_I2C_ROOT, SANDBOX_CLK_TEST_ID_DEVM_NULL, SANDBOX_CLK_TEST_ID_COUNT, diff --git a/drivers/clk/clk_sandbox_test.c b/drivers/clk/clk_sandbox_test.c index 5807a454f3..c0623dee10 100644 --- a/drivers/clk/clk_sandbox_test.c +++ b/drivers/clk/clk_sandbox_test.c @@ -53,6 +53,11 @@ int sandbox_clk_test_devm_get(struct udevice *dev) return PTR_ERR(clk); sbct->clkps[SANDBOX_CLK_TEST_ID_DEVM2] = clk; + clk = devm_clk_get_optional(dev, "i2c_root"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + sbct->clkps[SANDBOX_CLK_TEST_ID_I2C_ROOT] = clk; + sbct->clkps[SANDBOX_CLK_TEST_ID_DEVM_NULL] = NULL; clk = devm_clk_get_optional(dev, "not_an_existing_clock"); if (IS_ERR(clk)) -- 2.39.2
[PATCH v2 0/4] clk: ccf: fix enable_count mismatch
As described in [1], enable_count is incremented by 2 when ccf_clk_enable() is called. This series of patch fixed this issue and added a testcase for that. [1]: https://lore.kernel.org/all/sezpr06mb695927a6deeef8489a06897396...@sezpr06mb6959.apcprd06.prod.outlook.com/ Signed-off-by: Yang Xiwen --- Changes in v2: - add missing SoB in patch 1/4, no functional change - Link to v1: https://lore.kernel.org/r/2023-enable_count-v1-0-509f400a9...@outlook.com --- Yang Xiwen (4): clk: clk_sandbox_ccf: assign ccf_clk_ops to .ops of the driver clk: get correct ops for clk_enable() and clk_disable() clk: clk_sandbox: get devm clock i2c_root test: dm: clk_ccf: get "i2c_root" clock from &clk_ccf arch/sandbox/dts/test.dts | 6 -- arch/sandbox/include/asm/clk.h | 1 + drivers/clk/clk-uclass.c | 2 ++ drivers/clk/clk_sandbox_ccf.c | 1 + drivers/clk/clk_sandbox_test.c | 5 + test/dm/clk_ccf.c | 14 +++--- 6 files changed, 24 insertions(+), 5 deletions(-) --- base-commit: 3b913c148249a2b9d12ff25517ec311646e83bee change-id: 2023-enable_count-ad5001326815 Best regards, -- Yang Xiwen
u-boot@lists.denx.de
From: Yang Xiwen get i2c_root clock from device tree. In this way we get an CCF clock and also test ccf_clk_ops. Signed-off-by: Yang Xiwen --- test/dm/clk_ccf.c | 14 +++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/test/dm/clk_ccf.c b/test/dm/clk_ccf.c index e4ebb93cda..b8be6d6572 100644 --- a/test/dm/clk_ccf.c +++ b/test/dm/clk_ccf.c @@ -18,8 +18,8 @@ /* Tests for Common Clock Framework driver */ static int dm_test_clk_ccf(struct unit_test_state *uts) { - struct clk *clk, *pclk; - struct udevice *dev; + struct clk *clk, *pclk, clk_ccf; + struct udevice *dev, *test_dev; long long rate; int ret; #if CONFIG_IS_ENABLED(CLK_CCF) @@ -29,6 +29,7 @@ static int dm_test_clk_ccf(struct unit_test_state *uts) /* Get the device using the clk device */ ut_assertok(uclass_get_device_by_name(UCLASS_CLK, "clk-ccf", &dev)); + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "clk-test", &test_dev)); /* Test for clk_get_by_id() */ ret = clk_get_by_id(SANDBOX_CLK_ECSPI_ROOT, &clk); @@ -110,11 +111,18 @@ static int dm_test_clk_ccf(struct unit_test_state *uts) #if CONFIG_IS_ENABLED(CLK_CCF) /* Test clk tree enable/disable */ + + ret = clk_get_by_index(test_dev, SANDBOX_CLK_TEST_ID_I2C_ROOT, &clk_ccf); + ut_assertok(ret); + ut_asserteq_str("clk-ccf", clk_ccf.dev->name); + ut_asserteq(clk_ccf.id, SANDBOX_CLK_I2C_ROOT); + ret = clk_get_by_id(SANDBOX_CLK_I2C_ROOT, &clk); ut_assertok(ret); ut_asserteq_str("i2c_root", clk->dev->name); + ut_asserteq(clk->id, SANDBOX_CLK_I2C_ROOT); - ret = clk_enable(clk); + ret = clk_enable(&clk_ccf); ut_assertok(ret); ret = sandbox_clk_enable_count(clk); -- 2.39.2
[PATCH 1/4] clk: clk_sandbox_ccf: assign ccf_clk_ops to .ops of the driver
From: Yang Xiwen It can now act as an clk provider on which ccf_clk_ops can be tested. Also add "#clock-cells=<1>" to test.dts. --- arch/sandbox/dts/test.dts | 1 + drivers/clk/clk_sandbox_ccf.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index c7197795ef..b1773f1bc2 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -654,6 +654,7 @@ ccf: clk-ccf { compatible = "sandbox,clk-ccf"; + #clock-cells = <1>; }; efi-media { diff --git a/drivers/clk/clk_sandbox_ccf.c b/drivers/clk/clk_sandbox_ccf.c index fedcdd4044..38184e27aa 100644 --- a/drivers/clk/clk_sandbox_ccf.c +++ b/drivers/clk/clk_sandbox_ccf.c @@ -284,6 +284,7 @@ static int sandbox_clk_ccf_probe(struct udevice *dev) U_BOOT_DRIVER(sandbox_clk_ccf) = { .name = "sandbox_clk_ccf", .id = UCLASS_CLK, + .ops = &ccf_clk_ops, .probe = sandbox_clk_ccf_probe, .of_match = sandbox_clk_ccf_test_ids, }; -- 2.39.2
u-boot@lists.denx.de
From: Yang Xiwen get i2c_root clock from device tree. In this way we get an CCF clock and also test ccf_clk_ops. Signed-off-by: Yang Xiwen --- test/dm/clk_ccf.c | 14 +++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/test/dm/clk_ccf.c b/test/dm/clk_ccf.c index e4ebb93cda..b8be6d6572 100644 --- a/test/dm/clk_ccf.c +++ b/test/dm/clk_ccf.c @@ -18,8 +18,8 @@ /* Tests for Common Clock Framework driver */ static int dm_test_clk_ccf(struct unit_test_state *uts) { - struct clk *clk, *pclk; - struct udevice *dev; + struct clk *clk, *pclk, clk_ccf; + struct udevice *dev, *test_dev; long long rate; int ret; #if CONFIG_IS_ENABLED(CLK_CCF) @@ -29,6 +29,7 @@ static int dm_test_clk_ccf(struct unit_test_state *uts) /* Get the device using the clk device */ ut_assertok(uclass_get_device_by_name(UCLASS_CLK, "clk-ccf", &dev)); + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "clk-test", &test_dev)); /* Test for clk_get_by_id() */ ret = clk_get_by_id(SANDBOX_CLK_ECSPI_ROOT, &clk); @@ -110,11 +111,18 @@ static int dm_test_clk_ccf(struct unit_test_state *uts) #if CONFIG_IS_ENABLED(CLK_CCF) /* Test clk tree enable/disable */ + + ret = clk_get_by_index(test_dev, SANDBOX_CLK_TEST_ID_I2C_ROOT, &clk_ccf); + ut_assertok(ret); + ut_asserteq_str("clk-ccf", clk_ccf.dev->name); + ut_asserteq(clk_ccf.id, SANDBOX_CLK_I2C_ROOT); + ret = clk_get_by_id(SANDBOX_CLK_I2C_ROOT, &clk); ut_assertok(ret); ut_asserteq_str("i2c_root", clk->dev->name); + ut_asserteq(clk->id, SANDBOX_CLK_I2C_ROOT); - ret = clk_enable(clk); + ret = clk_enable(&clk_ccf); ut_assertok(ret); ret = sandbox_clk_enable_count(clk); -- 2.39.2
[PATCH 0/4] clk: ccf: fix enable_count mismatch
As described in [1], enable_count is incremented by 2 when ccf_clk_enable() is called. This series of patch fixed this issue and added a testcase for that. [1]: https://lore.kernel.org/all/sezpr06mb695927a6deeef8489a06897396...@sezpr06mb6959.apcprd06.prod.outlook.com/ Signed-off-by: Yang Xiwen --- Yang Xiwen (4): clk: clk_sandbox_ccf: assign ccf_clk_ops to .ops of the driver clk: get correct ops for clk_enable() and clk_disable() clk: clk_sandbox: get devm clock i2c_root test: dm: clk_ccf: get "i2c_root" clock from &clk_ccf arch/sandbox/dts/test.dts | 6 -- arch/sandbox/include/asm/clk.h | 1 + drivers/clk/clk-uclass.c | 2 ++ drivers/clk/clk_sandbox_ccf.c | 1 + drivers/clk/clk_sandbox_test.c | 5 + test/dm/clk_ccf.c | 14 +++--- 6 files changed, 24 insertions(+), 5 deletions(-) --- base-commit: 3b913c148249a2b9d12ff25517ec311646e83bee change-id: 2023-enable_count-ad5001326815 Best regards, -- Yang Xiwen
[PATCH 2/4] clk: get correct ops for clk_enable() and clk_disable()
From: Yang Xiwen assign clk_dev_ops(clkp->dev) to ops to ensure correct clk operations are called on clocks. This fixes the incorrect enable_count issue as described in [1]. [1]: https://lore.kernel.org/all/sezpr06mb695927a6deeef8489a06897396...@sezpr06mb6959.apcprd06.prod.outlook.com/ Signed-off-by: Yang Xiwen --- drivers/clk/clk-uclass.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 3b5e3f9c86..3e9d68feb3 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -640,6 +640,7 @@ int clk_enable(struct clk *clk) if (CONFIG_IS_ENABLED(CLK_CCF)) { /* Take id 0 as a non-valid clk, such as dummy */ if (clk->id && !clk_get_by_id(clk->id, &clkp)) { + ops = clk_dev_ops(clkp->dev); if (clkp->enable_count) { clkp->enable_count++; return 0; @@ -699,6 +700,7 @@ int clk_disable(struct clk *clk) if (CONFIG_IS_ENABLED(CLK_CCF)) { if (clk->id && !clk_get_by_id(clk->id, &clkp)) { + ops = clk_dev_ops(clkp->dev); if (clkp->flags & CLK_IS_CRITICAL) return 0; -- 2.39.2
[PATCH 3/4] clk: clk_sandbox: get devm clock i2c_root
From: Yang Xiwen This clock is added to dts. Get it in the devm group in the driver or the testcases will fail. Signed-off-by: Yang Xiwen --- arch/sandbox/dts/test.dts | 5 +++-- arch/sandbox/include/asm/clk.h | 1 + drivers/clk/clk_sandbox_test.c | 5 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index b1773f1bc2..f99397c528 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -632,8 +632,9 @@ <&clk_sandbox 1>, <&clk_sandbox 0>, <&clk_sandbox 3>, -<&clk_sandbox 2>; - clock-names = "fixed", "i2c", "spi", "uart2", "uart1"; +<&clk_sandbox 2>, +<&ccf 11>; + clock-names = "fixed", "i2c", "spi", "uart2", "uart1", "i2c_root"; }; clk-test2 { diff --git a/arch/sandbox/include/asm/clk.h b/arch/sandbox/include/asm/clk.h index df7156fe31..597bc528dc 100644 --- a/arch/sandbox/include/asm/clk.h +++ b/arch/sandbox/include/asm/clk.h @@ -41,6 +41,7 @@ enum sandbox_clk_test_id { SANDBOX_CLK_TEST_ID_I2C, SANDBOX_CLK_TEST_ID_DEVM1, SANDBOX_CLK_TEST_ID_DEVM2, + SANDBOX_CLK_TEST_ID_I2C_ROOT, SANDBOX_CLK_TEST_ID_DEVM_NULL, SANDBOX_CLK_TEST_ID_COUNT, diff --git a/drivers/clk/clk_sandbox_test.c b/drivers/clk/clk_sandbox_test.c index 5807a454f3..c0623dee10 100644 --- a/drivers/clk/clk_sandbox_test.c +++ b/drivers/clk/clk_sandbox_test.c @@ -53,6 +53,11 @@ int sandbox_clk_test_devm_get(struct udevice *dev) return PTR_ERR(clk); sbct->clkps[SANDBOX_CLK_TEST_ID_DEVM2] = clk; + clk = devm_clk_get_optional(dev, "i2c_root"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + sbct->clkps[SANDBOX_CLK_TEST_ID_I2C_ROOT] = clk; + sbct->clkps[SANDBOX_CLK_TEST_ID_DEVM_NULL] = NULL; clk = devm_clk_get_optional(dev, "not_an_existing_clock"); if (IS_ERR(clk)) -- 2.39.2
[PATCH v2] clk: check parent_name in clk_register to avoid confusing log_error() output
From: Yang Xiwen For some gate clocks and fixed clocks without a parent, calling clk_register will print an useless error message indicating that parent is missing. Fix that by gaurding log_xxx() with an if-statement. Signed-off-by: Yang Xiwen Suggested-by: Sean Anderson --- It's found during my development for HiSilicon clock driver. --- Changes in v2: - drop the commit which exports clk_mux_register. - drop the commit which is already merged - drop ccf enable_count fix as it'll be in another patchset - use Anderson's patch for clk_register() - Link to v1: https://lore.kernel.org/r/20230809-clk-fix-v1-0-808dbae54...@outlook.com --- drivers/clk/clk.c | 18 ++ 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index a5a3461b66..6ede1b4d4d 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -18,17 +18,19 @@ int clk_register(struct clk *clk, const char *drv_name, const char *name, const char *parent_name) { - struct udevice *parent; + struct udevice *parent = NULL; struct driver *drv; int ret; - ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &parent); - if (ret) { - log_err("%s: failed to get %s device (parent of %s)\n", - __func__, parent_name, name); - } else { - log_debug("%s: name: %s parent: %s [0x%p]\n", __func__, name, - parent->name, parent); + if (parent_name) { + ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &parent); + if (ret) { + log_err("%s: failed to get %s device (parent of %s)\n", + __func__, parent_name, name); + } else { + log_debug("%s: name: %s parent: %s [0x%p]\n", __func__, name, + parent->name, parent); + } } drv = lists_driver_lookup_name(drv_name); --- base-commit: 580eb31199be8a822e62f20965854a242f895d03 change-id: 20230807-clk-fix-17e895f79817 Best regards, -- Yang Xiwen
Re: [PATCH RESEND 5/5] clk: ccf: call clock provided ops directly for endisable()
On 11/2/2023 2:50 AM, Yang Xiwen wrote: > On 11/2/2023 2:19 AM, Sean Anderson wrote: >> On 8/17/23 13:04, Yang Xiwen via B4 Relay wrote: >>> From: Yang Xiwen >>> >>> Calling into CCF framework will cause a clock being enabled twice >>> instead of once (clk->enable_count becomes 2 rather than 1), thus making >>> it hard to disable (needs to call clk_disable() twice). >>> Fix that by calling clock provided ops directly. >> >> Can you describe this scenario more? From what I can tell, clk_enable >> doesn't >> increment enable_count for CCF clocks. >> > Well, it's hard to describe clearly. But I can only tell this patch > fixed the issue when i was trying to write an Ethernet driver[1] which > calls clk_disable() and expects the clock to be disabled after that. > Also I found that CCF driver does not have a corresponding test file. I > will try to write a test for that in next release. Okay, fine. I read the source again and let me try to explain the whole thing to you briefly. Let's see what happens when we are calling clk_enable(gate). The source of clk.c is listed below and labeled for clarity: ``` 1 if (CONFIG_IS_ENABLED(CLK_CCF)) { 2 /* Take id 0 as a non-valid clk, such as dummy */ 3 if (clk->id && !clk_get_by_id(clk->id, &clkp)) { 4 if (clkp->enable_count) { 5 clkp->enable_count++; 6 return 0; 7 } 8 if (clkp->dev->parent && 9 device_get_uclass_id(clkp->dev->parent) == UCLASS_CLK) { 10 ret = clk_enable(dev_get_clk_ptr(clkp->dev->parent)); 11 if (ret) { 12 printf("Enable %s failed\n", 13 clkp->dev->parent->name); 14 return ret; 15 } 16 } 17 } 18 19 if (ops->enable) { 20 ret = ops->enable(clk); 21 if (ret) { 22 printf("Enable %s failed\n", clk->dev->name); 23 return ret; 24 } 25 } 26 if (clkp) 27 clkp->enable_count++; 28 } else { 29 if (!ops->enable) 30 return -ENOSYS; 31 return ops->enable(clk); ``` The following steps are executed: 1. Actually, a "fake" clk is passed to clk_enable() and only clk->id is valid. The actual clk is "clkp"; 2. Initially, we runs till `ret = ops->enable(clk)`(line 20), i.e. ccf_clk_enable(clk); 3. Thankfully, ccf_clk_enable() calls clk_get_by_id() to get the real clk and call clk_enable(clkp) again so we won't have an endless loop here. 4. So ops->enable(clk) actually equals to clk_enable(clkp). It's obvious that there is a `clkp->enable_count++` inside the nested function call since it's still 0. Now it becomes 1; 5. The nested clk_enable(clkp) now returns to the outer clk_enable(clk); 6. Unfortunately, there is a `if (clkp) clkp->enable_count++;`(line 26) afterwards. Now it becomes 2. 7. Finally, we got a clk being enabled twice. "clkp->enable_count" is 2 now. Obviously it's not the intended behavior. We can either fix clk_enable() or ccf_clk_endisable() to resolve this. But I choose to touch ccf_clk_endisable() since it's less commonly used. >> --Sean >> >>> Signed-off-by: Yang Xiwen >>> --- >>> drivers/clk/clk.c | 12 +++- >>> 1 file changed, 11 insertions(+), 1 deletion(-) >>> >>> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c >>> index a38daaac0c..00d082c46f 100644 >>> --- a/drivers/clk/clk.c >>> +++ b/drivers/clk/clk.c >>> @@ -14,6 +14,7 @@ >>> #include >>> #include >>> #include >>> +#include >>> int clk_register(struct clk *clk, const char *drv_name, >>>const char *name, const char *parent_name) >>> @@ -115,11 +116,20 @@ int ccf_clk_set_parent(struct clk *clk, struct >>> clk *parent) >>> static int ccf_clk_endisable(struct clk *clk, bool enable) >>> { >>> struct clk *c; >>> +const struct clk_ops *ops; >>> int err = clk_get_by_id(clk->id, &c); >>> if (err) >>> return err; >>> -return enable ? clk_enable(c) : clk_disable(c); >>> +else >>> +ops = clk_dev_ops(c->dev); >>> + >>> +if (enable && ops->enable) >>> +return ops->enable(c); >>> +else if (!enable && ops->disable) >>> +return ops->disable(c); >>> + >>> +return -ENOSYS; >>> } >>> int ccf_clk_enable(struct clk *clk) >>> >> > [1] > https://lore.kernel.org/all/20230814-wip-hisi_femac-trunk-v2-0-1e29f4005...@outlook.com/ > -- Best regards, Yang Xiwen
Re: [PATCH RESEND 2/5] clk: call log_debug() instead to avoid console log printing
On 11/2/2023 2:01 AM, Sean Anderson wrote: > On 11/1/23 13:55, Sean Anderson wrote: >> On 8/17/23 13:04, Yang Xiwen via B4 Relay wrote: >>> From: Yang Xiwen >>> >>> it's a very common case to register a clock without a parent, such as >>> clk_register_fixed_rate(). >> >> Actually, that seems like the only place this is done. >> >>> Replace log_error() with log_debug() to avoid >>> useless console log if not debugging. >>> >>> Signed-off-by: Yang Xiwen >>> --- >>> drivers/clk/clk.c | 4 ++-- >>> 1 file changed, 2 insertions(+), 2 deletions(-) >>> >>> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c >>> index a5a3461b66..a38daaac0c 100644 >>> --- a/drivers/clk/clk.c >>> +++ b/drivers/clk/clk.c >>> @@ -24,8 +24,8 @@ int clk_register(struct clk *clk, const char >>> *drv_name, >>> ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &parent); >>> if (ret) { >>> - log_err("%s: failed to get %s device (parent of %s)\n", >>> - __func__, parent_name, name); >>> + log_debug("%s: failed to get %s device (parent of %s)\n", >>> + __func__, parent_name, name); >>> } else { >>> log_debug("%s: name: %s parent: %s [0x%p]\n", __func__, name, >>> parent->name, parent); >>> >> >> I think a correct fix would be >> >> diff --git i/drivers/clk/clk.c w/drivers/clk/clk.c >> index a5a3461b66c..cb333c83f66 100644 >> --- i/drivers/clk/clk.c >> +++ w/drivers/clk/clk.c >> @@ -18,17 +18,19 @@ >> int clk_register(struct clk *clk, const char *drv_name, >> const char *name, const char *parent_name) >> { >> - struct udevice *parent; >> + struct udevice *parent = NULL; >> struct driver *drv; >> int ret; >> >> - ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, >> &parent); >> - if (ret) { >> - log_err("%s: failed to get %s device (parent of %s)\n", >> - __func__, parent_name, name); >> - } else { >> - log_debug("%s: name: %s parent: %s [0x%p]\n", >> __func__, name, >> - parent->name, parent); >> + if (parent_name) { >> + ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, >> + &parent); >> + if (ret) >> + log_err("%s: failed to get %s device (parent >> of %s)\n", >> + __func__, parent_name, name); >> + else >> + log_debug("%s: name: %s parent: %s [0x%p]\n", >> __func__, >> + name, parent->name, parent); >> } >> >> drv = lists_driver_lookup_name(drv_name); >> >> --Sean > > or you could modify the condition to be `if (ret && parent_name)` with > appropriate > modification of the second debug message. > Thanks for your review. I'll use your patch with your SoB and drop mine in next release. > --Sean -- Best regards, Yang Xiwen
Re: [PATCH RESEND 5/5] clk: ccf: call clock provided ops directly for endisable()
On 11/2/2023 2:19 AM, Sean Anderson wrote: > On 8/17/23 13:04, Yang Xiwen via B4 Relay wrote: >> From: Yang Xiwen >> >> Calling into CCF framework will cause a clock being enabled twice >> instead of once (clk->enable_count becomes 2 rather than 1), thus making >> it hard to disable (needs to call clk_disable() twice). >> Fix that by calling clock provided ops directly. > > Can you describe this scenario more? From what I can tell, clk_enable > doesn't > increment enable_count for CCF clocks. > Well, it's hard to describe clearly. But I can only tell this patch fixed the issue when i was trying to write an Ethernet driver[1] which calls clk_disable() and expects the clock to be disabled after that. Also I found that CCF driver does not have a corresponding test file. I will try to write a test for that in next release. > --Sean > >> Signed-off-by: Yang Xiwen >> --- >> drivers/clk/clk.c | 12 +++- >> 1 file changed, 11 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c >> index a38daaac0c..00d082c46f 100644 >> --- a/drivers/clk/clk.c >> +++ b/drivers/clk/clk.c >> @@ -14,6 +14,7 @@ >> #include >> #include >> #include >> +#include >> int clk_register(struct clk *clk, const char *drv_name, >> const char *name, const char *parent_name) >> @@ -115,11 +116,20 @@ int ccf_clk_set_parent(struct clk *clk, struct >> clk *parent) >> static int ccf_clk_endisable(struct clk *clk, bool enable) >> { >> struct clk *c; >> + const struct clk_ops *ops; >> int err = clk_get_by_id(clk->id, &c); >> if (err) >> return err; >> - return enable ? clk_enable(c) : clk_disable(c); >> + else >> + ops = clk_dev_ops(c->dev); >> + >> + if (enable && ops->enable) >> + return ops->enable(c); >> + else if (!enable && ops->disable) >> + return ops->disable(c); >> + >> + return -ENOSYS; >> } >> int ccf_clk_enable(struct clk *clk) >> > [1] https://lore.kernel.org/all/20230814-wip-hisi_femac-trunk-v2-0-1e29f4005...@outlook.com/ -- Best regards, Yang Xiwen
Re: [PATCH RESEND 1/5] clk: export clk_register_mux_table()
On 11/2/2023 1:50 AM, Sean Anderson wrote: > On 8/17/23 13:04, Yang Xiwen via B4 Relay wrote: >> From: Yang Xiwen >> >> It's already implemented in clk-mux.c, export it in the header file. >> >> Signed-off-by: Yang Xiwen >> --- >> include/linux/clk-provider.h | 6 ++ >> 1 file changed, 6 insertions(+) >> >> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h >> index b8acacd49e..801404480b 100644 >> --- a/include/linux/clk-provider.h >> +++ b/include/linux/clk-provider.h >> @@ -247,6 +247,12 @@ struct clk *clk_register_mux(struct device *dev, >> const char *name, >> void __iomem *reg, u8 shift, u8 width, >> u8 clk_mux_flags); >> +struct clk *clk_register_mux_table(struct device *dev, const char >> *name, >> + const char * const *parent_names, u8 num_parents, >> + unsigned long flags, >> + void __iomem *reg, u8 shift, u32 mask, >> + u8 clk_mux_flags, u32 *table); >> + >> struct clk *clk_register_fixed_rate(struct device *dev, const char >> *name, >> ulong rate); >> > > Why do you want to export this? None of your other patches use it. It will be used in HiSilicon clk framework driver which i will send after this series is applied. And this function is exported in Linux kernel CCF. So i think it's fine to export it in U-Boot as well. > > --Sean -- Best regards, Yang Xiwen
Re: [PATCH RESEND 0/5] clk: A few bugfixes/enhancements for CCF
Why is this patchset completely ignored for more than half a month already? I have some other patches pending because of this one. Please tell me what's wrong with this patchset so that i can fix them. -- Regards, Yang Xiwen
[PATCH RESEND v2 0/2] net: add support for HiSilicon Fast Ethernet Controller driver
This core is found on many HiSilicon chips. This patchset adds support for it and the integrated MDIO bus. The driver code comes from linux kernel driver, downstream u-boot driver and the datasheet. It's already tested on a Hi3798MV200 based STB. Note that currently this driver can't be used for Hi3798MV200 since the clock driver is missing. I will implement and submit the clock driver and the framework in a later patchset. Signed-off-by: Yang Xiwen --- Changes in v2: - hisi_femac: clear previous irq before sending - Link to v1: https://lore.kernel.org/r/20230725-wip-hisi_femac-trunk-v1-0-88469a170...@outlook.com --- Yang Xiwen (2): net: add hifemac Ethernet driver for HiSilicon platform net: add hifemac_mdio MDIO bus driver for HiSilicon platform drivers/net/Kconfig| 17 ++ drivers/net/Makefile | 2 + drivers/net/hifemac.c | 481 + drivers/net/hifemac_mdio.c | 116 +++ 4 files changed, 616 insertions(+) --- base-commit: 580eb31199be8a822e62f20965854a242f895d03 change-id: 20230724-wip-hisi_femac-trunk-1f57f0986f0c Best regards, -- Yang Xiwen
[PATCH RESEND v2 1/2] net: add hifemac Ethernet driver for HiSilicon platform
From: Yang Xiwen It adds the driver for HIFEMAC Ethernet controller found on HiSilicon SoCs like Hi3798MV200. It's based on the mainstream linux driver, but quite a lot of code gets rewritten and cleaned up to adopt u-boot driver model. Signed-off-by: Yang Xiwen --- drivers/net/Kconfig | 9 + drivers/net/Makefile | 1 + drivers/net/hifemac.c | 481 ++ 3 files changed, 491 insertions(+) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 39eee98ca7..bc1d6e3905 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -886,6 +886,15 @@ config MEDIATEK_ETH This Driver support MediaTek Ethernet GMAC Say Y to enable support for the MediaTek Ethernet GMAC. +config HIFEMAC_ETH + bool "HiSilicon Fast Ethernet Controller" + select DM_CLK + select DM_RESET + select PHYLIB + help + This driver supports HIFEMAC Ethernet controller found on + HiSilicon SoCs. + config HIGMACV300_ETH bool "HiSilicon Gigabit Ethernet Controller" select DM_RESET diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 46a40e2ed9..de6bf1d014 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_FSL_PFE) += pfe_eth/ obj-$(CONFIG_FTGMAC100) += ftgmac100.o obj-$(CONFIG_FTMAC100) += ftmac100.o obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o +obj-$(CONFIG_HIFEMAC_ETH) += hifemac.o obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o obj-$(CONFIG_KSZ9477) += ksz9477.o diff --git a/drivers/net/hifemac.c b/drivers/net/hifemac.c new file mode 100644 index 00..b61a29e636 --- /dev/null +++ b/drivers/net/hifemac.c @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hisilicon Fast Ethernet MAC Driver + * Adapted from linux + * + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. + * Copyright (c) 2023 Yang Xiwen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* MAC control register list */ +#define MAC_PORTSEL0x0200 +#define MAC_PORTSEL_STAT_CPU BIT(0) +#define MAC_PORTSEL_RMII BIT(1) +#define MAC_PORTSET0x0208 +#define MAC_PORTSET_DUPLEX_FULLBIT(0) +#define MAC_PORTSET_LINKED BIT(1) +#define MAC_PORTSET_SPEED_100M BIT(2) +#define MAC_SET0x0210 +#define MAX_FRAME_SIZE 1600 +#define MAX_FRAME_SIZE_MASKGENMASK(10, 0) +#define BIT_PAUSE_EN BIT(18) +#define RX_COALESCE_SET0x0340 +#define RX_COALESCED_FRAME_OFFSET 24 +#define RX_COALESCED_FRAMES8 +#define RX_COALESCED_TIMER 0x74 +#define QLEN_SET 0x0344 +#define RX_DEPTH_OFFSET8 +#define MAX_HW_FIFO_DEPTH 64 +#define HW_TX_FIFO_DEPTH 1 +#define MAX_HW_RX_FIFO_DEPTH (MAX_HW_FIFO_DEPTH - HW_TX_FIFO_DEPTH) +#define HW_RX_FIFO_DEPTH min(PKTBUFSRX, MAX_HW_RX_FIFO_DEPTH) +#define IQFRM_DES 0x0354 +#define RX_FRAME_LEN_MASK GENMASK(11, 0) +#define RX_FRAME_IN_INDEX_MASK GENMASK(17, 12) +#define IQ_ADDR0x0358 +#define EQ_ADDR0x0360 +#define EQFRM_LEN 0x0364 +#define ADDRQ_STAT 0x036C +#define TX_CNT_INUSE_MASK GENMASK(5, 0) +#define BIT_TX_READY BIT(24) +#define BIT_RX_READY BIT(25) +/* global control register list */ +#define GLB_HOSTMAC_L320x +#define GLB_HOSTMAC_H160x0004 +#define GLB_SOFT_RESET 0x0008 +#define SOFT_RESET_ALL BIT(0) +#define GLB_FWCTRL 0x0010 +#define FWCTRL_VLAN_ENABLE BIT(0) +#define FWCTRL_FW2CPU_ENA BIT(5) +#define FWCTRL_FWALL2CPU BIT(7) +#define GLB_MACTCTRL 0x0014 +#define MACTCTRL_UNI2CPU BIT(1) +#define MACTCTRL_MULTI2CPU BIT(3) +#define MACTCTRL_BROAD2CPU BIT(5) +#define MACTCTRL_MACT_ENA BIT(7) +#define GLB_IRQ_STAT 0x0030 +#define GLB_IRQ_ENA0x0034 +#define IRQ_ENA_PORT0_MASK GENMASK(7, 0) +#define IRQ_ENA_PORT0 BIT(18) +#define IRQ_ENA_ALLBIT(19) +#define GLB_IRQ_RAW0x0038 +#define IRQ_INT_RX_RDY BIT(0) +#define IRQ_INT_TX_PER_PACKET BIT(1) +#define IRQ_INT_TX_FIFO_EMPTY BIT(6) +#define IRQ_INT_MULTI_RXRDYBIT(7) +#define DEF_INT_MASK (IRQ_INT_MULTI_RXRDY | \ +
[PATCH RESEND v2 2/2] net: add hifemac_mdio MDIO bus driver for HiSilicon platform
From: Yang Xiwen It adds the driver for the internal MDIO bus of HIFEMAC Ethernet controller. It's based on the mainstream linux driver. Signed-off-by: Yang Xiwen --- drivers/net/Kconfig| 8 drivers/net/Makefile | 1 + drivers/net/hifemac_mdio.c | 116 + 3 files changed, 125 insertions(+) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index bc1d6e3905..5c5bfb1263 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -895,6 +895,14 @@ config HIFEMAC_ETH This driver supports HIFEMAC Ethernet controller found on HiSilicon SoCs. +config HIFEMAC_MDIO + bool "HiSilicon Fast Ethernet Controller MDIO interface" + depends on DM_MDIO + select DM_CLK + help + This driver supports the internal MDIO interface of HIFEMAC + Ethernet controller. + config HIGMACV300_ETH bool "HiSilicon Gigabit Ethernet Controller" select DM_RESET diff --git a/drivers/net/Makefile b/drivers/net/Makefile index de6bf1d014..b2d3da6934 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_FTGMAC100) += ftgmac100.o obj-$(CONFIG_FTMAC100) += ftmac100.o obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o obj-$(CONFIG_HIFEMAC_ETH) += hifemac.o +obj-$(CONFIG_HIFEMAC_MDIO) += hifemac_mdio.o obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o obj-$(CONFIG_KSZ9477) += ksz9477.o diff --git a/drivers/net/hifemac_mdio.c b/drivers/net/hifemac_mdio.c new file mode 100644 index 00..343c5f3a38 --- /dev/null +++ b/drivers/net/hifemac_mdio.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Hisilicon Fast Ethernet MDIO Bus Driver + * + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. + */ + +#include +#include +#include +#include +#include + +#define MDIO_RWCTRL0x00 +#define MDIO_RO_DATA 0x04 +#define MDIO_WRITE BIT(13) +#define MDIO_RW_FINISH BIT(15) +#define BIT_PHY_ADDR_OFFSET8 +#define BIT_WR_DATA_OFFSET 16 + +struct hisi_femac_mdio_data { + struct clk *clk; + void __iomem *membase; +}; + +static int hisi_femac_mdio_wait_ready(struct hisi_femac_mdio_data *data) +{ + u32 val; + + return readl_poll_timeout(data->membase + MDIO_RWCTRL, + val, val & MDIO_RW_FINISH, 1); +} + +static int hisi_femac_mdio_read(struct udevice *dev, int addr, int devad, int reg) +{ + struct hisi_femac_mdio_data *data = dev_get_priv(dev); + int ret; + + ret = hisi_femac_mdio_wait_ready(data); + if (ret) + return ret; + + writel((addr << BIT_PHY_ADDR_OFFSET) | reg, + data->membase + MDIO_RWCTRL); + + ret = hisi_femac_mdio_wait_ready(data); + if (ret) + return ret; + + return readl(data->membase + MDIO_RO_DATA) & 0x; +} + +static int hisi_femac_mdio_write(struct udevice *dev, int addr, int devad, int reg, u16 val) +{ + struct hisi_femac_mdio_data *data = dev_get_priv(dev); + int ret; + + ret = hisi_femac_mdio_wait_ready(data); + if (ret) + return ret; + + writel(MDIO_WRITE | (val << BIT_WR_DATA_OFFSET) | + (addr << BIT_PHY_ADDR_OFFSET) | reg, + data->membase + MDIO_RWCTRL); + + return hisi_femac_mdio_wait_ready(data); +} + +static int hisi_femac_mdio_of_to_plat(struct udevice *dev) +{ + struct hisi_femac_mdio_data *data = dev_get_priv(dev); + int ret; + + data->membase = dev_remap_addr(dev); + if (IS_ERR(data->membase)) { + ret = PTR_ERR(data->membase); + return log_msg_ret("Failed to remap base addr", ret); + } + + // clk is optional + data->clk = devm_clk_get_optional(dev, NULL); + + return 0; +} + +static int hisi_femac_mdio_probe(struct udevice *dev) +{ + struct hisi_femac_mdio_data *data = dev_get_priv(dev); + int ret; + + ret = clk_prepare_enable(data->clk); + if (ret) + return log_msg_ret("Failed to enable clk", ret); + + return 0; +} + +static const struct mdio_ops hisi_femac_mdio_ops = { + .read = hisi_femac_mdio_read, + .write = hisi_femac_mdio_write, +}; + +static const struct udevice_id hisi_femac_mdio_dt_ids[] = { + { .compatible = "hisilicon,hisi-femac-mdio" }, + { } +}; + +U_BOOT_DRIVER(hisi_femac_mdio_driver) = { + .name = "hisi-femac-mdio", + .id = UCLASS_MDIO, + .of_match = hisi_femac_mdio_dt_ids, + .of_to_plat = hisi_femac_mdio_of_to_plat, + .probe = hisi_femac_mdio_probe, + .ops = &hisi_femac_mdio_ops, + .priv_auto = sizeof(struct hisi_femac_mdio_data), +}; -- 2.34.1
[PATCH RESEND 5/5] clk: ccf: call clock provided ops directly for endisable()
From: Yang Xiwen Calling into CCF framework will cause a clock being enabled twice instead of once (clk->enable_count becomes 2 rather than 1), thus making it hard to disable (needs to call clk_disable() twice). Fix that by calling clock provided ops directly. Signed-off-by: Yang Xiwen --- drivers/clk/clk.c | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index a38daaac0c..00d082c46f 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -14,6 +14,7 @@ #include #include #include +#include int clk_register(struct clk *clk, const char *drv_name, const char *name, const char *parent_name) @@ -115,11 +116,20 @@ int ccf_clk_set_parent(struct clk *clk, struct clk *parent) static int ccf_clk_endisable(struct clk *clk, bool enable) { struct clk *c; + const struct clk_ops *ops; int err = clk_get_by_id(clk->id, &c); if (err) return err; - return enable ? clk_enable(c) : clk_disable(c); + else + ops = clk_dev_ops(c->dev); + + if (enable && ops->enable) + return ops->enable(c); + else if (!enable && ops->disable) + return ops->disable(c); + + return -ENOSYS; } int ccf_clk_enable(struct clk *clk) -- 2.34.1
[PATCH RESEND 2/5] clk: call log_debug() instead to avoid console log printing
From: Yang Xiwen it's a very common case to register a clock without a parent, such as clk_register_fixed_rate(). Replace log_error() with log_debug() to avoid useless console log if not debugging. Signed-off-by: Yang Xiwen --- drivers/clk/clk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index a5a3461b66..a38daaac0c 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -24,8 +24,8 @@ int clk_register(struct clk *clk, const char *drv_name, ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &parent); if (ret) { - log_err("%s: failed to get %s device (parent of %s)\n", - __func__, parent_name, name); + log_debug("%s: failed to get %s device (parent of %s)\n", + __func__, parent_name, name); } else { log_debug("%s: name: %s parent: %s [0x%p]\n", __func__, name, parent->name, parent); -- 2.34.1
[PATCH RESEND 4/5] clk: promote clk_dev_ops to linux/clk-provider.h
From: Yang Xiwen So that it can be used by others. Signed-off-by: Yang Xiwen --- drivers/clk/clk-uclass.c | 5 - include/linux/clk-provider.h | 5 + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index dc3e9d6a26..5cc80e5e39 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -25,11 +25,6 @@ #include #include -static inline const struct clk_ops *clk_dev_ops(struct udevice *dev) -{ - return (const struct clk_ops *)dev->driver->ops; -} - struct clk *dev_get_clk_ptr(struct udevice *dev) { return (struct clk *)dev_get_uclass_priv(dev); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 801404480b..dfafb4cc9d 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -21,6 +21,11 @@ static inline void clk_dm(ulong id, struct clk *clk) clk->id = id; } +static inline const struct clk_ops *clk_dev_ops(struct udevice *dev) +{ + return (const struct clk_ops *)dev->driver->ops; +} + /* * flags used across common struct clk. these flags should only affect the * top-level framework. custom flags for dealing with hardware specifics -- 2.34.1
[PATCH RESEND 3/5] clk: also handle ENOENT in *_optional functions
From: Yang Xiwen If the device does not specify any clocks in device tree, these functions will return PTR_ERR(-ENOENT). This is not the intended behavior and does not comply with linux kernel CCF. Fix that by returning NULL under such circumstances instead. Signed-off-by: Yang Xiwen --- include/clk.h | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/clk.h b/include/clk.h index d91285235f..f95da0838d 100644 --- a/include/clk.h +++ b/include/clk.h @@ -223,9 +223,11 @@ struct clk *devm_clk_get(struct udevice *dev, const char *id); static inline struct clk *devm_clk_get_optional(struct udevice *dev, const char *id) { + int ret; struct clk *clk = devm_clk_get(dev, id); - if (PTR_ERR(clk) == -ENODATA) + ret = PTR_ERR(clk); + if (ret == -ENODATA || ret == -ENOENT) return NULL; return clk; @@ -335,7 +337,7 @@ static inline int clk_get_by_name_optional(struct udevice *dev, int ret; ret = clk_get_by_name(dev, name, clk); - if (ret == -ENODATA) + if (ret == -ENODATA || ret == -ENOENT) return 0; return ret; @@ -359,7 +361,7 @@ static inline int clk_get_by_name_nodev_optional(ofnode node, const char *name, int ret; ret = clk_get_by_name_nodev(node, name, clk); - if (ret == -ENODATA) + if (ret == -ENODATA || ret == -ENOENT) return 0; return ret; -- 2.34.1
[PATCH RESEND 1/5] clk: export clk_register_mux_table()
From: Yang Xiwen It's already implemented in clk-mux.c, export it in the header file. Signed-off-by: Yang Xiwen --- include/linux/clk-provider.h | 6 ++ 1 file changed, 6 insertions(+) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index b8acacd49e..801404480b 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -247,6 +247,12 @@ struct clk *clk_register_mux(struct device *dev, const char *name, void __iomem *reg, u8 shift, u8 width, u8 clk_mux_flags); +struct clk *clk_register_mux_table(struct device *dev, const char *name, + const char * const *parent_names, u8 num_parents, + unsigned long flags, + void __iomem *reg, u8 shift, u32 mask, + u8 clk_mux_flags, u32 *table); + struct clk *clk_register_fixed_rate(struct device *dev, const char *name, ulong rate); -- 2.34.1
[PATCH RESEND 0/5] clk: A few bugfixes/enhancements for CCF
They are found during my development for HiSilicon clock driver. Details are in commit logs. Signed-off-by: Yang Xiwen --- Yang Xiwen (5): clk: export clk_register_mux_table() clk: call log_debug() instead to avoid console log printing clk: also handle ENOENT in *_optional functions clk: promote clk_dev_ops to linux/clk-provider.h clk: ccf: call clock provided ops directly for endisable() drivers/clk/clk-uclass.c | 5 - drivers/clk/clk.c| 16 +--- include/clk.h| 8 +--- include/linux/clk-provider.h | 11 +++ 4 files changed, 29 insertions(+), 11 deletions(-) --- base-commit: 580eb31199be8a822e62f20965854a242f895d03 change-id: 20230807-clk-fix-17e895f79817 Best regards, -- Yang Xiwen
[PATCH v2 1/2] net: add hifemac Ethernet driver for HiSilicon platform
From: Yang Xiwen It adds the driver for HIFEMAC Ethernet controller found on HiSilicon SoCs like Hi3798MV200. It's based on the mainstream linux driver, but quite a lot of code gets rewritten and cleaned up to adopt u-boot driver model. Signed-off-by: Yang Xiwen --- drivers/net/Kconfig | 9 + drivers/net/Makefile | 1 + drivers/net/hifemac.c | 481 ++ 3 files changed, 491 insertions(+) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 39eee98ca7..bc1d6e3905 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -886,6 +886,15 @@ config MEDIATEK_ETH This Driver support MediaTek Ethernet GMAC Say Y to enable support for the MediaTek Ethernet GMAC. +config HIFEMAC_ETH + bool "HiSilicon Fast Ethernet Controller" + select DM_CLK + select DM_RESET + select PHYLIB + help + This driver supports HIFEMAC Ethernet controller found on + HiSilicon SoCs. + config HIGMACV300_ETH bool "HiSilicon Gigabit Ethernet Controller" select DM_RESET diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 46a40e2ed9..de6bf1d014 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_FSL_PFE) += pfe_eth/ obj-$(CONFIG_FTGMAC100) += ftgmac100.o obj-$(CONFIG_FTMAC100) += ftmac100.o obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o +obj-$(CONFIG_HIFEMAC_ETH) += hifemac.o obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o obj-$(CONFIG_KSZ9477) += ksz9477.o diff --git a/drivers/net/hifemac.c b/drivers/net/hifemac.c new file mode 100644 index 00..b61a29e636 --- /dev/null +++ b/drivers/net/hifemac.c @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hisilicon Fast Ethernet MAC Driver + * Adapted from linux + * + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. + * Copyright (c) 2023 Yang Xiwen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* MAC control register list */ +#define MAC_PORTSEL0x0200 +#define MAC_PORTSEL_STAT_CPU BIT(0) +#define MAC_PORTSEL_RMII BIT(1) +#define MAC_PORTSET0x0208 +#define MAC_PORTSET_DUPLEX_FULLBIT(0) +#define MAC_PORTSET_LINKED BIT(1) +#define MAC_PORTSET_SPEED_100M BIT(2) +#define MAC_SET0x0210 +#define MAX_FRAME_SIZE 1600 +#define MAX_FRAME_SIZE_MASKGENMASK(10, 0) +#define BIT_PAUSE_EN BIT(18) +#define RX_COALESCE_SET0x0340 +#define RX_COALESCED_FRAME_OFFSET 24 +#define RX_COALESCED_FRAMES8 +#define RX_COALESCED_TIMER 0x74 +#define QLEN_SET 0x0344 +#define RX_DEPTH_OFFSET8 +#define MAX_HW_FIFO_DEPTH 64 +#define HW_TX_FIFO_DEPTH 1 +#define MAX_HW_RX_FIFO_DEPTH (MAX_HW_FIFO_DEPTH - HW_TX_FIFO_DEPTH) +#define HW_RX_FIFO_DEPTH min(PKTBUFSRX, MAX_HW_RX_FIFO_DEPTH) +#define IQFRM_DES 0x0354 +#define RX_FRAME_LEN_MASK GENMASK(11, 0) +#define RX_FRAME_IN_INDEX_MASK GENMASK(17, 12) +#define IQ_ADDR0x0358 +#define EQ_ADDR0x0360 +#define EQFRM_LEN 0x0364 +#define ADDRQ_STAT 0x036C +#define TX_CNT_INUSE_MASK GENMASK(5, 0) +#define BIT_TX_READY BIT(24) +#define BIT_RX_READY BIT(25) +/* global control register list */ +#define GLB_HOSTMAC_L320x +#define GLB_HOSTMAC_H160x0004 +#define GLB_SOFT_RESET 0x0008 +#define SOFT_RESET_ALL BIT(0) +#define GLB_FWCTRL 0x0010 +#define FWCTRL_VLAN_ENABLE BIT(0) +#define FWCTRL_FW2CPU_ENA BIT(5) +#define FWCTRL_FWALL2CPU BIT(7) +#define GLB_MACTCTRL 0x0014 +#define MACTCTRL_UNI2CPU BIT(1) +#define MACTCTRL_MULTI2CPU BIT(3) +#define MACTCTRL_BROAD2CPU BIT(5) +#define MACTCTRL_MACT_ENA BIT(7) +#define GLB_IRQ_STAT 0x0030 +#define GLB_IRQ_ENA0x0034 +#define IRQ_ENA_PORT0_MASK GENMASK(7, 0) +#define IRQ_ENA_PORT0 BIT(18) +#define IRQ_ENA_ALLBIT(19) +#define GLB_IRQ_RAW0x0038 +#define IRQ_INT_RX_RDY BIT(0) +#define IRQ_INT_TX_PER_PACKET BIT(1) +#define IRQ_INT_TX_FIFO_EMPTY BIT(6) +#define IRQ_INT_MULTI_RXRDYBIT(7) +#define DEF_INT_MASK (IRQ_INT_MULTI_RXRDY | \ +
[PATCH v2 0/2] net: add support for HiSilicon Fast Ethernet Controller driver
This core is found on many HiSilicon chips. This patchset adds support for it and the integrated MDIO bus. The driver code comes from linux kernel driver, downstream u-boot driver and the datasheet. It's already tested on a Hi3798MV200 based STB. Note that currently this driver can't be used for Hi3798MV200 since the clock driver is missing. I will implement and submit the clock driver and the framework in a later patchset. Signed-off-by: Yang Xiwen --- Changes in v2: - hisi_femac: clear previous irq before sending - Link to v1: https://lore.kernel.org/r/20230725-wip-hisi_femac-trunk-v1-0-88469a170...@outlook.com --- Yang Xiwen (2): net: add hifemac Ethernet driver for HiSilicon platform net: add hifemac_mdio MDIO bus driver for HiSilicon platform drivers/net/Kconfig| 17 ++ drivers/net/Makefile | 2 + drivers/net/hifemac.c | 481 + drivers/net/hifemac_mdio.c | 116 +++ 4 files changed, 616 insertions(+) --- base-commit: 580eb31199be8a822e62f20965854a242f895d03 change-id: 20230724-wip-hisi_femac-trunk-1f57f0986f0c Best regards, -- Yang Xiwen
[PATCH v2 2/2] net: add hifemac_mdio MDIO bus driver for HiSilicon platform
From: Yang Xiwen It adds the driver for the internal MDIO bus of HIFEMAC Ethernet controller. It's based on the mainstream linux driver. Signed-off-by: Yang Xiwen --- drivers/net/Kconfig| 8 drivers/net/Makefile | 1 + drivers/net/hifemac_mdio.c | 116 + 3 files changed, 125 insertions(+) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index bc1d6e3905..5c5bfb1263 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -895,6 +895,14 @@ config HIFEMAC_ETH This driver supports HIFEMAC Ethernet controller found on HiSilicon SoCs. +config HIFEMAC_MDIO + bool "HiSilicon Fast Ethernet Controller MDIO interface" + depends on DM_MDIO + select DM_CLK + help + This driver supports the internal MDIO interface of HIFEMAC + Ethernet controller. + config HIGMACV300_ETH bool "HiSilicon Gigabit Ethernet Controller" select DM_RESET diff --git a/drivers/net/Makefile b/drivers/net/Makefile index de6bf1d014..b2d3da6934 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_FTGMAC100) += ftgmac100.o obj-$(CONFIG_FTMAC100) += ftmac100.o obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o obj-$(CONFIG_HIFEMAC_ETH) += hifemac.o +obj-$(CONFIG_HIFEMAC_MDIO) += hifemac_mdio.o obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o obj-$(CONFIG_KSZ9477) += ksz9477.o diff --git a/drivers/net/hifemac_mdio.c b/drivers/net/hifemac_mdio.c new file mode 100644 index 00..343c5f3a38 --- /dev/null +++ b/drivers/net/hifemac_mdio.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Hisilicon Fast Ethernet MDIO Bus Driver + * + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. + */ + +#include +#include +#include +#include +#include + +#define MDIO_RWCTRL0x00 +#define MDIO_RO_DATA 0x04 +#define MDIO_WRITE BIT(13) +#define MDIO_RW_FINISH BIT(15) +#define BIT_PHY_ADDR_OFFSET8 +#define BIT_WR_DATA_OFFSET 16 + +struct hisi_femac_mdio_data { + struct clk *clk; + void __iomem *membase; +}; + +static int hisi_femac_mdio_wait_ready(struct hisi_femac_mdio_data *data) +{ + u32 val; + + return readl_poll_timeout(data->membase + MDIO_RWCTRL, + val, val & MDIO_RW_FINISH, 1); +} + +static int hisi_femac_mdio_read(struct udevice *dev, int addr, int devad, int reg) +{ + struct hisi_femac_mdio_data *data = dev_get_priv(dev); + int ret; + + ret = hisi_femac_mdio_wait_ready(data); + if (ret) + return ret; + + writel((addr << BIT_PHY_ADDR_OFFSET) | reg, + data->membase + MDIO_RWCTRL); + + ret = hisi_femac_mdio_wait_ready(data); + if (ret) + return ret; + + return readl(data->membase + MDIO_RO_DATA) & 0x; +} + +static int hisi_femac_mdio_write(struct udevice *dev, int addr, int devad, int reg, u16 val) +{ + struct hisi_femac_mdio_data *data = dev_get_priv(dev); + int ret; + + ret = hisi_femac_mdio_wait_ready(data); + if (ret) + return ret; + + writel(MDIO_WRITE | (val << BIT_WR_DATA_OFFSET) | + (addr << BIT_PHY_ADDR_OFFSET) | reg, + data->membase + MDIO_RWCTRL); + + return hisi_femac_mdio_wait_ready(data); +} + +static int hisi_femac_mdio_of_to_plat(struct udevice *dev) +{ + struct hisi_femac_mdio_data *data = dev_get_priv(dev); + int ret; + + data->membase = dev_remap_addr(dev); + if (IS_ERR(data->membase)) { + ret = PTR_ERR(data->membase); + return log_msg_ret("Failed to remap base addr", ret); + } + + // clk is optional + data->clk = devm_clk_get_optional(dev, NULL); + + return 0; +} + +static int hisi_femac_mdio_probe(struct udevice *dev) +{ + struct hisi_femac_mdio_data *data = dev_get_priv(dev); + int ret; + + ret = clk_prepare_enable(data->clk); + if (ret) + return log_msg_ret("Failed to enable clk", ret); + + return 0; +} + +static const struct mdio_ops hisi_femac_mdio_ops = { + .read = hisi_femac_mdio_read, + .write = hisi_femac_mdio_write, +}; + +static const struct udevice_id hisi_femac_mdio_dt_ids[] = { + { .compatible = "hisilicon,hisi-femac-mdio" }, + { } +}; + +U_BOOT_DRIVER(hisi_femac_mdio_driver) = { + .name = "hisi-femac-mdio", + .id = UCLASS_MDIO, + .of_match = hisi_femac_mdio_dt_ids, + .of_to_plat = hisi_femac_mdio_of_to_plat, + .probe = hisi_femac_mdio_probe, + .ops = &hisi_femac_mdio_ops, + .priv_auto = sizeof(struct hisi_femac_mdio_data), +}; -- 2.34.1
[PATCH 4/5] clk: promote clk_dev_ops to linux/clk-provider.h
From: Yang Xiwen So that it can be used by others. Signed-off-by: Yang Xiwen --- drivers/clk/clk-uclass.c | 5 - include/linux/clk-provider.h | 5 + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index dc3e9d6a26..5cc80e5e39 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -25,11 +25,6 @@ #include #include -static inline const struct clk_ops *clk_dev_ops(struct udevice *dev) -{ - return (const struct clk_ops *)dev->driver->ops; -} - struct clk *dev_get_clk_ptr(struct udevice *dev) { return (struct clk *)dev_get_uclass_priv(dev); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 801404480b..dfafb4cc9d 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -21,6 +21,11 @@ static inline void clk_dm(ulong id, struct clk *clk) clk->id = id; } +static inline const struct clk_ops *clk_dev_ops(struct udevice *dev) +{ + return (const struct clk_ops *)dev->driver->ops; +} + /* * flags used across common struct clk. these flags should only affect the * top-level framework. custom flags for dealing with hardware specifics -- 2.34.1
[PATCH 5/5] clk: ccf: call clock provided ops directly for endisable()
From: Yang Xiwen Calling into CCF framework will cause a clock being enabled twice instead of once (clk->enable_count becomes 2 rather than 1), thus making it hard to disable (needs to call clk_disable() twice). Fix that by calling clock provided ops directly. Signed-off-by: Yang Xiwen --- drivers/clk/clk.c | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index a38daaac0c..00d082c46f 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -14,6 +14,7 @@ #include #include #include +#include int clk_register(struct clk *clk, const char *drv_name, const char *name, const char *parent_name) @@ -115,11 +116,20 @@ int ccf_clk_set_parent(struct clk *clk, struct clk *parent) static int ccf_clk_endisable(struct clk *clk, bool enable) { struct clk *c; + const struct clk_ops *ops; int err = clk_get_by_id(clk->id, &c); if (err) return err; - return enable ? clk_enable(c) : clk_disable(c); + else + ops = clk_dev_ops(c->dev); + + if (enable && ops->enable) + return ops->enable(c); + else if (!enable && ops->disable) + return ops->disable(c); + + return -ENOSYS; } int ccf_clk_enable(struct clk *clk) -- 2.34.1
[PATCH 2/5] clk: call log_debug() instead to avoid console log printing
From: Yang Xiwen it's a very common case to register a clock without a parent, such as clk_register_fixed_rate(). Replace log_error() with log_debug() to avoid useless console log if not debugging. Signed-off-by: Yang Xiwen --- drivers/clk/clk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index a5a3461b66..a38daaac0c 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -24,8 +24,8 @@ int clk_register(struct clk *clk, const char *drv_name, ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &parent); if (ret) { - log_err("%s: failed to get %s device (parent of %s)\n", - __func__, parent_name, name); + log_debug("%s: failed to get %s device (parent of %s)\n", + __func__, parent_name, name); } else { log_debug("%s: name: %s parent: %s [0x%p]\n", __func__, name, parent->name, parent); -- 2.34.1
[PATCH 3/5] clk: also handle ENOENT in *_optional functions
From: Yang Xiwen If the device does not specify any clocks in device tree, these functions will return PTR_ERR(-ENOENT). This is not the intended behavior and does not comply with linux kernel CCF. Fix that by returning NULL under such circumstances instead. Signed-off-by: Yang Xiwen --- include/clk.h | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/clk.h b/include/clk.h index d91285235f..f95da0838d 100644 --- a/include/clk.h +++ b/include/clk.h @@ -223,9 +223,11 @@ struct clk *devm_clk_get(struct udevice *dev, const char *id); static inline struct clk *devm_clk_get_optional(struct udevice *dev, const char *id) { + int ret; struct clk *clk = devm_clk_get(dev, id); - if (PTR_ERR(clk) == -ENODATA) + ret = PTR_ERR(clk); + if (ret == -ENODATA || ret == -ENOENT) return NULL; return clk; @@ -335,7 +337,7 @@ static inline int clk_get_by_name_optional(struct udevice *dev, int ret; ret = clk_get_by_name(dev, name, clk); - if (ret == -ENODATA) + if (ret == -ENODATA || ret == -ENOENT) return 0; return ret; @@ -359,7 +361,7 @@ static inline int clk_get_by_name_nodev_optional(ofnode node, const char *name, int ret; ret = clk_get_by_name_nodev(node, name, clk); - if (ret == -ENODATA) + if (ret == -ENODATA || ret == -ENOENT) return 0; return ret; -- 2.34.1
[PATCH 0/5] clk: A few bugfixes/enhancements for CCF
They are found during my development for HiSilicon clock driver. Details are in commit logs. Signed-off-by: Yang Xiwen --- Yang Xiwen (5): clk: export clk_register_mux_table() clk: call log_debug() instead to avoid console log printing clk: also handle ENOENT in *_optional functions clk: promote clk_dev_ops to linux/clk-provider.h clk: ccf: call clock provided ops directly for endisable() drivers/clk/clk-uclass.c | 5 - drivers/clk/clk.c| 16 +--- include/clk.h| 8 +--- include/linux/clk-provider.h | 11 +++ 4 files changed, 29 insertions(+), 11 deletions(-) --- base-commit: 580eb31199be8a822e62f20965854a242f895d03 change-id: 20230807-clk-fix-17e895f79817 Best regards, -- Yang Xiwen
[PATCH 1/5] clk: export clk_register_mux_table()
From: Yang Xiwen It's already implemented in clk-mux.c, export it in the header file. Signed-off-by: Yang Xiwen --- include/linux/clk-provider.h | 6 ++ 1 file changed, 6 insertions(+) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index b8acacd49e..801404480b 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -247,6 +247,12 @@ struct clk *clk_register_mux(struct device *dev, const char *name, void __iomem *reg, u8 shift, u8 width, u8 clk_mux_flags); +struct clk *clk_register_mux_table(struct device *dev, const char *name, + const char * const *parent_names, u8 num_parents, + unsigned long flags, + void __iomem *reg, u8 shift, u32 mask, + u8 clk_mux_flags, u32 *table); + struct clk *clk_register_fixed_rate(struct device *dev, const char *name, ulong rate); -- 2.34.1
Re: [PATCH] clk: also return NULL for -ENOENT in devm_clk_get_optional functions
On 7/25/2023 1:34 AM, Fabio Estevam wrote: On Mon, Jul 24, 2023 at 2:32 PM Yang Xiwen via B4 Relay wrote: From: Yang Xiwen As described by the doc. Which doc? Please mention the details in the commit log. It's in the source annotation of devm_clk_get_optional. The annotation says -ENOENT should be handled, but the code doesn't. It handles -ENODATA instead, which confuses me a lot. The optional functions are introduced to simplify clock consumer's code so that they can assume the struct clk * returned by these functional are either valid or NULL. Not handling ENOENT is not the intended case. -- Regards, Yang Xiwen
[PATCH] clk: also return NULL for -ENOENT in devm_clk_get_optional functions
From: Yang Xiwen As described by the doc. Signed-off-by: Yang Xiwen --- Handle both ENODATA and ENOENT. --- include/clk.h | 7 --- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/clk.h b/include/clk.h index d91285235f..c9aa2360e1 100644 --- a/include/clk.h +++ b/include/clk.h @@ -224,8 +224,9 @@ static inline struct clk *devm_clk_get_optional(struct udevice *dev, const char *id) { struct clk *clk = devm_clk_get(dev, id); + int ret = PTR_ERR(clk); - if (PTR_ERR(clk) == -ENODATA) + if (ret == -ENODATA || ret == -ENOENT) return NULL; return clk; @@ -335,7 +336,7 @@ static inline int clk_get_by_name_optional(struct udevice *dev, int ret; ret = clk_get_by_name(dev, name, clk); - if (ret == -ENODATA) + if (ret == -ENODATA || ret == -ENOENT) return 0; return ret; @@ -359,7 +360,7 @@ static inline int clk_get_by_name_nodev_optional(ofnode node, const char *name, int ret; ret = clk_get_by_name_nodev(node, name, clk); - if (ret == -ENODATA) + if (ret == -ENODATA || ret == -ENOENT) return 0; return ret; --- base-commit: 580eb31199be8a822e62f20965854a242f895d03 change-id: 20230725-clk-fix-inc-903aa0540739 Best regards, -- Yang Xiwen