[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 = >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 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 = >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 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/hisilicon/pinctrl-hi3798mv2x.c @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * IOCONFIG driver for Hi3798MV2x SoCs + * + * Copyright 2024 (r) Yang Xiwen + */ + +#include + +#include "pinctrl-histb.h" + +// The sequence is important! +enum hi3798mv2x_ioconfig_pins { + HI3798MV2X_Y19, + HI3798MV2X_W19, +
[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, >phy, 0); + err = generic_setup_phy_bulk(dev, >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(>phy); + ret = generic_shutdown_phy_bulk(>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(>phy); + ret = generic_shutdown_phy_bulk(>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()); ut_asserteq(0, generic_phy_power_off_bulk()); ut_asserteq(0, generic_phy_exit_bulk()); + ut_asserteq(0, generic_setup_phy_bulk(parent, )); + ut_asserteq(0, generic_shutdown_phy_bulk()); /* 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()); ut_asserteq(-EIO, generic_phy_power_off_bulk()); ut_asserteq(0, generic_phy_exit_bulk()); + ut_asserteq(-EIO, generic_setup_phy_bulk(parent, )); + ut_asserteq(-EIO, generic_shutdown_phy_bulk()); 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([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 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(); 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)_ops }, { .compatible = "fsl,imx8mq-dwc3" }, { .compatible = "intel,tangier-dwc3" }, + { .compatible = "hisilicon,hi3798mv200-dwc3", .data = (ulong)_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
[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 = >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, >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 = >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(>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(>cfg, host, host->bus_hz, 40); host->mmc = >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 = >mmc; host->fifo_mode = mmc_data->use_fifo; + host->fifoth_val = mmc_data->fifoth_val; host->mmc->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)_mmc_data }, { .compatible = "hisilicon,hi3798cv200-dw-mshc", .data = (ulong)_mmc_data }, { .compatible = "hisilicon,hi3798mv200-dw-mshc", - .data = (ulong)_mmc_data }, + .data = (ulong)_mmc_data }, { .compatible = "hisilicon,hi3660-dw-mshc", .data = (ulong)_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()); ut_asserteq(0, generic_phy_power_off_bulk()); ut_asserteq(0, generic_phy_exit_bulk()); + ut_asserteq(0, generic_setup_phy_bulk(parent, )); + ut_asserteq(0, generic_shutdown_phy_bulk()); /* 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()); ut_asserteq(-EIO, generic_phy_power_off_bulk()); ut_asserteq(0, generic_phy_exit_bulk()); + ut_asserteq(-EIO, generic_setup_phy_bulk(parent, )); + ut_asserteq(-EIO, generic_shutdown_phy_bulk()); 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, >phy, 0); + err = generic_setup_phy_bulk(dev, >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(>phy); + ret = generic_shutdown_phy_bulk(>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(>phy); + ret = generic_shutdown_phy_bulk(>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, [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([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([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] 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 = >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 = _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, ); + 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[CLK_BUS]); - if (ret < 0) - return log_msg_ret("Failed to disable bus clock", ret); + if (ret < 0) { + pr_err("%s: Failed to disable bus clock %d\n", __func__, ret); + return log_msg_ret("clk", ret); + } udelay(delays[PRE_DELAY]); ret = reset_assert(rst); - if (ret < 0) - return log_msg_ret("Failed to assert reset", ret); + if (ret < 0) { +
[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, ); + 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[CLK_BUS]); - if (ret < 0) - return log_msg_ret("Failed to disable bus clock", ret); + if (ret < 0) { + pr_err("%s: Failed to disable bus clock %d\n", __func__, ret); + return log_msg_ret("clk", ret); + } udelay(delays[PRE_DELAY]); ret = reset_assert(rst); - if (ret < 0) - return log_msg_ret("Failed to assert reset", ret); + if (ret < 0) { +
[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 = _femac_mdio_ops, + .plat_auto = sizeof(struct mdio_perdev_priv), .priv_auto = sizeof(struct hisi_femac_mdio_data), }; -- 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, }, + { HISTB_APB_CLK, "clk_apb", 1, }, + { HISTB_AHB_CLK, "clk_ahb", 2, }, + { HI3798MV200_FIXED_12M, "12m",
[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, }, + { HISTB_APB_CLK, "clk_apb", 1, }, + { HISTB_AHB_CLK, "clk_ahb", 2, }, + { HI3798MV200_FIXED_12M, "12m",
[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, ); + 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[CLK_BUS]); - if (ret < 0) - return log_msg_ret("Failed to disable bus clock", ret); + if (ret < 0) { + pr_err("%s: Failed to disable bus clock %d\n", __func__, ret); + return log_msg_ret("clk", ret); + } udelay(delays[PRE_DELAY]); ret = reset_assert(rst); - if (ret < 0) - return log_msg_ret("Failed to assert reset", ret); + if (ret < 0) { +
[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 = _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 = >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, >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 = >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(>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(>cfg, host, host->bus_hz, 40); host->mmc = >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 = hisi_wdt_start, + .stop = hisi_wdt_stop, + .reset = hisi_wdt_reset, +
[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, )) { + 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, )) { + 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 = <_fixed>, <_sandbox 1>, <_sandbox 0>, +< 11>, <_sandbox 3>, <_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 = _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", )); + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "clk-test", _dev)); /* Test for clk_get_by_id() */ ret = clk_get_by_id(SANDBOX_CLK_ECSPI_ROOT, ); @@ -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, _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, ); 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(_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, )) { + 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, )) { + 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 = _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 @@ <_sandbox 1>, <_sandbox 0>, <_sandbox 3>, -<_sandbox 2>; - clock-names = "fixed", "i2c", "spi", "uart2", "uart1"; +<_sandbox 2>, +< 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 _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 v2 4/4] test: dm: clk_ccf: get "i2c_root" clock from _ccf
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", )); + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "clk-test", _dev)); /* Test for clk_get_by_id() */ ret = clk_get_by_id(SANDBOX_CLK_ECSPI_ROOT, ); @@ -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, _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, ); 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(_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 = _clk_ops, .probe = sandbox_clk_ccf_probe, .of_match = sandbox_clk_ccf_test_ids, }; -- 2.39.2
[PATCH 4/4] test: dm: clk_ccf: get "i2c_root" clock from _ccf
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", )); + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "clk-test", _dev)); /* Test for clk_get_by_id() */ ret = clk_get_by_id(SANDBOX_CLK_ECSPI_ROOT, ); @@ -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, _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, ); 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(_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 _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, )) { + 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, )) { + 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 @@ <_sandbox 1>, <_sandbox 0>, <_sandbox 3>, -<_sandbox 2>; - clock-names = "fixed", "i2c", "spi", "uart2", "uart1"; +<_sandbox 2>, +< 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, ); - 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, ); + 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
[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 | \ + IRQ_INT_TX_PER_PACKET | \ +
[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 = _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, ); 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, ); 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 | \ + IRQ_INT_TX_PER_PACKET | \ +
[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 = _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, ); 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, ); 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
[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
[PATCH 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 | 478 ++ 3 files changed, 488 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..bd0e3c5c5f --- /dev/null +++ b/drivers/net/hifemac.c @@ -0,0 +1,478 @@ +// 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 | \ + IRQ_INT_TX_PER_PACKET | \ +
[PATCH 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 --- 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 | 478 + drivers/net/hifemac_mdio.c | 116 +++ 4 files changed, 613 insertions(+) --- base-commit: 580eb31199be8a822e62f20965854a242f895d03 change-id: 20230724-wip-hisi_femac-trunk-1f57f0986f0c Best regards, -- Yang Xiwen
[PATCH 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 = _femac_mdio_ops, + .priv_auto = sizeof(struct hisi_femac_mdio_data), +}; -- 2.34.1
[PATCH 1/2] clk: move clk_get_ops() to a common header
From: Yang Xiwen This allows it to be used by other source files. Signed-off-by: Yang Xiwen --- drivers/clk/clk-uclass.c | 5 - include/clk.h| 17 + 2 files changed, 17 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/clk.h b/include/clk.h index d91285235f..bd3617e1e0 100644 --- a/include/clk.h +++ b/include/clk.h @@ -8,6 +8,7 @@ #ifndef _CLK_H_ #define _CLK_H_ +#include #include #include #include @@ -258,6 +259,17 @@ int clk_release_all(struct clk *clk, int count); */ void devm_clk_put(struct udevice *dev, struct clk *clk); +/** + * clk_dev_ops - get ops of a clock + * @dev: clock device + * + * Return: ops of the clk + */ +static inline const struct clk_ops *clk_dev_ops(struct udevice *dev) +{ + return (const struct clk_ops *)dev->driver->ops; +} + #else static inline int clk_get_by_phandle(struct udevice *dev, const @@ -315,6 +327,11 @@ static inline int clk_release_all(struct clk *clk, int count) static inline void devm_clk_put(struct udevice *dev, struct clk *clk) { } + +static inline const struct clk_ops *clk_dev_ops(struct udevice *dev) +{ + return ERR_PTR(-ENOSYS); +} #endif /** -- 2.34.1
[PATCH 2/2] clk: ccf: invoke ops provided by clk directly
From: Yang Xiwen Invoking clk_enable() or clk_disable() in clk->ops context causes a recursion, results in a clock being enabled twice. Signed-off-by: Yang Xiwen --- drivers/clk/clk.c | 10 -- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index a5a3461b66..bd455e44a4 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -115,11 +114,18 @@ 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 = clk_dev_ops(clk->dev); int err = clk_get_by_id(clk->id, ); if (err) return err; - return enable ? clk_enable(c) : clk_disable(c); + + if (enable && ops->enable) + return ops->enable(c); + else if (!enable && ops->disable) + return ops->disable(c); + + return 0; } int ccf_clk_enable(struct clk *clk) -- 2.34.1
[PATCH 0/2] clk: fix a bug in CCF which results in a clock being enabled twice.
Currently, ccf_clk_endisable() calls clk_enable() / clk_disable() directly depending on the request. However, this function is also referenced in clk->ops, which is also called in clk_enable() / clk_disable(). This caused a recursion and made the clock enabled twice if clk_enable() is invoked. So we have to call clk_disable() twice to disable the clock. It can be easily reproduced with few extra lines of debug code. Fix that by calling clk->ops->enable/disable directly in ccf_clk_endisable() rather than using the framework functions. Signed-off-by: Yang Xiwen --- Yang Xiwen (2): clk: move clk_get_ops() to a common header clk: ccf: invoke ops provided by clk directly drivers/clk/clk-uclass.c | 5 - drivers/clk/clk.c| 10 -- include/clk.h| 17 + 3 files changed, 25 insertions(+), 7 deletions(-) --- base-commit: 580eb31199be8a822e62f20965854a242f895d03 change-id: 20230724-clk_fix-1b7265d663a8 Best regards, -- Yang Xiwen