On Tue, Aug 22, 2023 at 6:53 PM Serge Semin <fancer.lancer@xxxxxxxxx> wrote: > > On Tue, Aug 22, 2023 at 03:58:32PM +0800, Keguang Zhang wrote: > > On Mon, Aug 21, 2023 at 10:16 PM Serge Semin <fancer.lancer@xxxxxxxxx> wrote: > > > > > > On Mon, Aug 21, 2023 at 09:24:17PM +0800, Keguang Zhang wrote: > > > > On Sat, Aug 19, 2023 at 12:19 AM Serge Semin <fancer.lancer@xxxxxxxxx> wrote: > > > > > > > > > > On Fri, Aug 18, 2023 at 08:37:27PM +0800, Keguang Zhang wrote: > > > > > > On Wed, Aug 16, 2023 at 9:30 PM Serge Semin <fancer.lancer@xxxxxxxxx> wrote: > > > > > > > > > > > > > > On Sat, Aug 12, 2023 at 11:11:34PM +0800, Keguang Zhang wrote: > > > > > > > > This glue driver is created based on the arch-code > > > > > > > > implemented earlier with the platform-specific settings. > > > > > > > > > > > > > > > > Use syscon for SYSCON register access. > > > > > > > > > > > > > > > > Partialy based on the previous work by Serge Semin. > > > > > > > > > > > > > > > > Signed-off-by: Keguang Zhang <keguang.zhang@xxxxxxxxx> > > > > > > > > --- > > > > > > > > drivers/net/ethernet/stmicro/stmmac/Kconfig | 11 + > > > > > > > > drivers/net/ethernet/stmicro/stmmac/Makefile | 1 + > > > > > > > > .../ethernet/stmicro/stmmac/dwmac-loongson1.c | 257 ++++++++++++++++++ > > > > > > > > 3 files changed, 269 insertions(+) > > > > > > > > create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c > > > > > > > > > > > > > > > > diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig > > > > > > > > index 06c6871f8788..a2b9e289aa36 100644 > > > > > > > > --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig > > > > > > > > +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig > > > > > > > > @@ -239,6 +239,17 @@ config DWMAC_INTEL_PLAT > > > > > > > > the stmmac device driver. This driver is used for the Intel Keem Bay > > > > > > > > SoC. > > > > > > > > > > > > > > > > +config DWMAC_LOONGSON1 > > > > > > > > + tristate "Loongson1 GMAC support" > > > > > > > > + default MACH_LOONGSON32 > > > > > > > > + depends on OF && (MACH_LOONGSON32 || COMPILE_TEST) > > > > > > > > + help > > > > > > > > + Support for ethernet controller on Loongson1 SoC. > > > > > > > > + > > > > > > > > + This selects Loongson1 SoC glue layer support for the stmmac > > > > > > > > + device driver. This driver is used for Loongson1-based boards > > > > > > > > + like Loongson LS1B/LS1C. > > > > > > > > + > > > > > > > > config DWMAC_TEGRA > > > > > > > > tristate "NVIDIA Tegra MGBE support" > > > > > > > > depends on ARCH_TEGRA || COMPILE_TEST > > > > > > > > diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile > > > > > > > > index 5b57aee19267..80e598bd4255 100644 > > > > > > > > --- a/drivers/net/ethernet/stmicro/stmmac/Makefile > > > > > > > > +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile > > > > > > > > @@ -29,6 +29,7 @@ obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o > > > > > > > > obj-$(CONFIG_DWMAC_SUN8I) += dwmac-sun8i.o > > > > > > > > obj-$(CONFIG_DWMAC_DWC_QOS_ETH) += dwmac-dwc-qos-eth.o > > > > > > > > obj-$(CONFIG_DWMAC_INTEL_PLAT) += dwmac-intel-plat.o > > > > > > > > +obj-$(CONFIG_DWMAC_LOONGSON1) += dwmac-loongson1.o > > > > > > > > obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o > > > > > > > > obj-$(CONFIG_DWMAC_IMX8) += dwmac-imx.o > > > > > > > > obj-$(CONFIG_DWMAC_TEGRA) += dwmac-tegra.o > > > > > > > > diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c > > > > > > > > new file mode 100644 > > > > > > > > index 000000000000..368d6cd2cb78 > > > > > > > > --- /dev/null > > > > > > > > +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c > > > > > > > > @@ -0,0 +1,257 @@ > > > > > > > > +// SPDX-License-Identifier: GPL-2.0-or-later > > > > > > > > +/* > > > > > > > > + * Loongson-1 DWMAC glue layer > > > > > > > > + * > > > > > > > > + * Copyright (C) 2011-2023 Keguang Zhang <keguang.zhang@xxxxxxxxx> > > > > > > > > + */ > > > > > > > > + > > > > > > > > +#include <linux/mfd/syscon.h> > > > > > > > > +#include <linux/module.h> > > > > > > > > +#include <linux/phy.h> > > > > > > > > +#include <linux/platform_device.h> > > > > > > > > +#include <linux/regmap.h> > > > > > > > > + > > > > > > > > +#include "stmmac.h" > > > > > > > > +#include "stmmac_platform.h" > > > > > > > > + > > > > > > > > +/* Loongson-1 SYSCON Registers */ > > > > > > > > +#define LS1X_SYSCON0 (0x0) > > > > > > > > +#define LS1X_SYSCON1 (0x4) > > > > > > > > + > > > > > > > > +struct ls1x_dwmac_syscon { > > > > > > > > + const struct reg_field *reg_fields; > > > > > > > > + unsigned int nr_reg_fields; > > > > > > > > + int (*syscon_init)(struct plat_stmmacenet_data *plat); > > > > > > > > +}; > > > > > > > > + > > > > > > > > +struct ls1x_dwmac { > > > > > > > > + struct device *dev; > > > > > > > > + struct plat_stmmacenet_data *plat_dat; > > > > > > > > + const struct ls1x_dwmac_syscon *syscon; > > > > > > > > + struct regmap *regmap; > > > > > > > > + struct regmap_field *regmap_fields[]; > > > > > > > > +}; > > > > > > > > + > > > > > > > > +enum ls1b_dwmac_syscon_regfield { > > > > > > > > + GMAC1_USE_UART1, > > > > > > > > + GMAC1_USE_UART0, > > > > > > > > + GMAC1_SHUT, > > > > > > > > + GMAC0_SHUT, > > > > > > > > + GMAC1_USE_TXCLK, > > > > > > > > + GMAC0_USE_TXCLK, > > > > > > > > + GMAC1_USE_PWM23, > > > > > > > > + GMAC0_USE_PWM01, > > > > > > > > +}; > > > > > > > > + > > > > > > > > +enum ls1c_dwmac_syscon_regfield { > > > > > > > > + GMAC_SHUT, > > > > > > > > + PHY_INTF_SELI, > > > > > > > > +}; > > > > > > > > + > > > > > > > > +const struct reg_field ls1b_dwmac_syscon_regfields[] = { > > > > > > > > + [GMAC1_USE_UART1] = REG_FIELD(LS1X_SYSCON0, 4, 4), > > > > > > > > + [GMAC1_USE_UART0] = REG_FIELD(LS1X_SYSCON0, 3, 3), > > > > > > > > + [GMAC1_SHUT] = REG_FIELD(LS1X_SYSCON1, 13, 13), > > > > > > > > + [GMAC0_SHUT] = REG_FIELD(LS1X_SYSCON1, 12, 12), > > > > > > > > + [GMAC1_USE_TXCLK] = REG_FIELD(LS1X_SYSCON1, 3, 3), > > > > > > > > + [GMAC0_USE_TXCLK] = REG_FIELD(LS1X_SYSCON1, 2, 2), > > > > > > > > + [GMAC1_USE_PWM23] = REG_FIELD(LS1X_SYSCON1, 1, 1), > > > > > > > > + [GMAC0_USE_PWM01] = REG_FIELD(LS1X_SYSCON1, 0, 0) > > > > > > > > +}; > > > > > > > > + > > > > > > > > +const struct reg_field ls1c_dwmac_syscon_regfields[] = { > > > > > > > > + [GMAC_SHUT] = REG_FIELD(LS1X_SYSCON0, 6, 6), > > > > > > > > + [PHY_INTF_SELI] = REG_FIELD(LS1X_SYSCON1, 28, 30) > > > > > > > > +}; > > > > > > > > > > > > > > Emm, using regmap fields looks so over-complicated in this case seeing > > > > > > > you only need to set/clear several bits in the syscon. What about > > > > > > > defining macros with the particular flag as it's already done in the > > > > > > > "asm/mach-loongson32/regs-mux.h" file and using regmap_update_bits()? > > > > > > > > > > > > > > > > > > To use regmap_update_bits(), I have to store and pass reg_offset and > > > > > > mask, which is similar to the definition of regmap fields. > > > > > > > > > > Em, not really. And what offset are you talking about? Anyway you > > > > > don't need one. Moreover you'll be able to reduce the number of IOs: > > > > > > > > > > +#define GMAC1_USE_UART1 BIT(4) > > > > > +#define GMAC1_USE_UART0 BIT(3) > > > > > ... > > > > > +#define GMAC1_SHUT BIT(13) > > > > > ... > > > > > +#define GMAC1_USE_TXCLK BIT(3) > > > > > +#define GMAC1_USE_PWM23 BIT(1) > > > > > > > > > > +static int ls1b_dwmac_syscon_init(struct plat_stmmacenet_data *plat) > > > > > +{ > > > > > + struct ls1x_dwmac *dwmac = plat->bsp_priv; > > > > > + struct regmap *syscon = dwmac->regmap; > > > > > + > > > > > + if (plat->bus_id) { > > > > > + regmap_update_bits(syscon, LS1X_SYSCON0, > > > > > + GMAC1_USE_UART1 | GMAC1_USE_UART0, > > > > > + GMAC1_USE_UART1 | GMAC1_USE_UART0); > > > > > + > > > > > + switch (plat->phy_interface) { > > > > > + case PHY_INTERFACE_MODE_RGMII: > > > > > + regmap_update_bits(syscon, LS1X_SYSCON1, > > > > > + GMAC1_USE_TXCLK | GMAC1_USE_TXCLK, 0); > > > > > + break; > > > > > + case PHY_INTERFACE_MODE_MII: > > > > > + regmap_update_bits(syscon, LS1X_SYSCON1, > > > > > + GMAC1_USE_TXCLK | GMAC1_USE_TXCLK > > > > > + GMAC1_USE_TXCLK | GMAC1_USE_TXCLK); > > > > > + break; > > > > > + default: > > > > > + dev_err(dwmac->dev, "Unsupported PHY mode %u\n", > > > > > + plat->phy_interface); > > > > > + return -EOPNOTSUPP; > > > > > + } > > > > > + > > > > > + regmap_field_write(syscon, LS1X_SYSCON1, GMAC1_SHUT, 0); > > > > > + } //... > > > > > + > > > > > + return 0; > > > > > +} > > > > > > > > > > This doesn't look in anyway less readable then your implementation > > > > > but in fact simpler. > > > > > > > > > > > In addition, the regmap fields are very clear and leave the trouble to > > > > > > the internal implementation. > > > > > > > > > > In this case it brings much more troubles and no clarity. You need to create > > > > > an additional mainly redundant abstraction, waste memory for it, > > > > > define additional const arrays. Using it won't improve the code > > > > > readability seeing you need to set/clear a few flags only. So all of > > > > > the troubles for nothing. See the code above. It's simple and clear. > > > > > Just several regmap_update_bits().. > > > > > > > > > OK. I will use regmap instead of regmap fields. > > > > > > > > > BTW why have you chosen to define syscon instead of creating a pinctrl > > > > > driver? What if Loongson1 is embedded into a platform with, for > > > > > instance, UART0 and UART1 utilized instead of the GMAC1? > > > > > > > > > > > > As you can see, the two registers contains miscellaneous settings. > > > > Besides ‘USE’ bits, there are ‘RESET‘ bits, 'EN' bits, 'SHUT' bits, ... > > > > So they are not pinctrl registers. > > > > > > You could have defined a device node which would export "reset", > > > "power" and "pinctrl" functionality, like it's normally done for the > > > RCU devices (Reset and Clock unit devices). > > > > > > > Actually, there is a dedicated pin controller which controls the > > > > multiplexing of pads. > > > > > > Do you mean that there is another controller in the Loongson1 SoC > > > which controls the pads multiplexing? > > > > > Yes. There is another contoller that really controls the pads multiplexing. > > > > > If so what is the purpose of the GMAC1_USE_UART1, GMAC1_USE_UART0 and > > > GMAC1_USE_TXCLK, GMAC1_USE_PWM23 flags in MUX controller then? Is it > > > just another pinctl space with additional reset/power controls or what? > > > > > > From my perspective, these ‘USE’ bits should be regarded as > > device/module multiplexing rather than pads multiplexing. > > Could you elaborate what does "device/module multiplexing" mean? > Pherhaps the device switch is more accurate. Just means which devices could not work at the time. > > Although the two registers were called MUX_CTRL in LS1B datasheet, > > they had beed renamed to MISC_CTRL in LS1C datasheet. > > So it is supposed to be considered syscon. > > > > > > > > > > > > > > > > > > + > > > > > > > > > > > > > > > +static int ls1b_dwmac_syscon_init(struct plat_stmmacenet_data *plat) > > > > > > > > +{ > > > > > > > > > > > > > > As I already told you this part is better to be called from the > > > > > > > plat_stmmacenet_data.fix_mac_speed() because PHY interface mode can > > > > > > > differ from one interface open cycle to another as per the phylink > > > > > > > design. > > > > > > > > > > > > > I have considered .fix_mac_speed(), which will be called every time > > > > > > the link is up, and passes the current speed. > > > > > > However, the PHY interface mode is determined by the hardware design - > > > > > > the schematic. > > > > > > In other words, once the schematic is done, the PHY interface mode is fixed. > > > > > > Therefore, PHY interface mode should be configured one time at the > > > > > > initialization. > > > > > > And the plat_stmmacenet_data.init() is the proper place to do this. > > > > > > > > > > Ok. If no actual clock change is needed then indeed init() will be the > > > > > proper place. > > > > > > > > > > > > > > > > > > > + struct ls1x_dwmac *dwmac = plat->bsp_priv; > > > > > > > > + struct regmap_field **regmap_fields = dwmac->regmap_fields; > > > > > > > > + > > > > > > > > > > > > > > > + if (plat->bus_id) { > > > > > > > > > > > > > > Using bus_id doesn't look correct to determine the CSRs responsible > > > > > > > for the interface mode selection because it's calculated based on the > > > > > > > DT ethernet-alias which doesn't guarantee to have a particular device > > > > > > > assigned with the alias. Alias node can be absent after all. What > > > > > > > could be better in this case is for instance to use the regs physical > > > > > > > address. Any better idea? > > > > > > > > > > > > > > > > > > The purpose of alias is to bind the a particular device with a > > > > > > particular alias even some aliases are absent. > > > > > > Because of_alias_get_id() gets the alias id. > > > > > > For example, LS1B has two GMAC controllers, gmac0 and gmac1. > > > > > > I have tried the Ethernet with only one alias as follows. > > > > > > aliases { > > > > > > ethernet1 = &gmac1; > > > > > > }; > > > > > > In this case, plat->bus_id is still 1. > > > > > > And both gmac0 and gmac1 work. > > > > > > > > > > If no alias specified? If both aliases a non zero? If the IDs are > > > > > confused? If any of these is true you are in trouble. Your code > > > > > shouldn't rely on the aliases in this case. You need to come up with a > > > > > way to certainly distinguish one MAC from another. A physical base > > > > > address is one possible option. > > > > > > > > > > > > I see. > > > > But It seems unusual to determine device IDs by physical base address. > > > > What about adding a new property? such as loongson,dwmac-id > > > > > > IMO It's better to have a DT-property-independent way for it. If I > > > were you I would have utilized the reg-space > > > physical-base-address-based approach since you need to have it > > > specified anyway and it determines the particular MAC for sure. > > > Thus your driver won't be dependent in the device tree in that aspect. > > > > > > The physical base address may vary from SoC to SoC. > > You've got only two SoCs, right? LS1C and LS1B. Each of them has > a specific set of NICs: two loongson,ls1b-gmac on LS1B and > one loongson,ls1c-mac on LS1C. So LS1B has only two physical addresses > you can use to distinguish one interface from another and find out > what flags to toggle in the syscon. LS1C has a single MAC so you won't > even need any additional info since there is only one flag to > toggle. > Is there any driver that uses the physical-base-address way? Could you provide me some existing examples? Thanks! > Physical address is constant from one LS1C instance to another, and > similarly from one LS1B instance to another. It's defined by means > of the macros: > LS1X_GMAC0_BASE > LS1X_GMAC1_BASE > What physical address varying are you talking about? I don't see that > in the current platform driver. > > > It means that the driver has to remember MAC base addresses for different SoCs. > > Yes. Just two physical addresses. > Two chips for now. What about the future chips? > > > > > Some DW *MAC drivers pass additional number to the syscon phandle node > > > in the syscon-property to identify the MAC on the board, like > > > dwmac-socfpga.c or dwmac-sti.c. If you get to implement a similar way > > > then you'll need to have the DT-bindings properly describing that. But > > > IMO my approach seems less clumsy and simpler. > > > > > > I prefer the DT-bindings property way. At least many off-the-shelf > > examples can be found. > > Just two examples with not the best solution implemented. > > Anyway it's up to you to decide after all. I don't mind if it will be > the property-based way. But as for me it looks redundant seeing there > is base address always available and which you can utilise. Moreover > if you get to add any new Loongson MAC to the driver you'll need to > update it anyway at least in a way the syscon flags are toggled. So > even from that perspective using the physical base address seems as at > least the equally complex and maintainable solution. > > > > > > > > > > > > Note the /alias node is an informational node. It doesn't describe > > > > > devices. Just recent Krzysztof comment in a similar situation: > > > > > https://lore.kernel.org/netdev/20230814112539.70453-1-sriranjani.p@xxxxxxxxxxx/T/#m3972e40bd2fa323a3bdb2fbf07bde47ba6752439 > > > > > > > > > > Aliases are normally used by OS to for instance fix the device > > > > > enumeration (see SPI, I2C, I3C, MTD, MMC, RTC, TTY/Serial, Watchdog, > > > > > MDIO-GPIO, etc) - pre-define the device ID from the kernel or OS point > > > > > of view. In your case the IDs can't be changed. GMAC0 must be assigned > > > > > with ID0 and GMAC1 must be assigned with non-zero. Doing otherwise > > > > > will be break the interfaces functionality which isn't acceptable. > > > > > > > > > > > > > > > > > > > + regmap_field_write(regmap_fields[GMAC1_USE_UART1], 1); > > > > > > > > + regmap_field_write(regmap_fields[GMAC1_USE_UART0], 1); > > > > > > > > + > > > > > > > > + switch (plat->phy_interface) { > > > > > > > > + case PHY_INTERFACE_MODE_RGMII: > > > > > > > > + regmap_field_write(regmap_fields[GMAC1_USE_TXCLK], 0); > > > > > > > > + regmap_field_write(regmap_fields[GMAC1_USE_PWM23], 0); > > > > > > > > + break; > > > > > > > > + case PHY_INTERFACE_MODE_MII: > > > > > > > > + regmap_field_write(regmap_fields[GMAC1_USE_TXCLK], 1); > > > > > > > > + regmap_field_write(regmap_fields[GMAC1_USE_PWM23], 1); > > > > > > > > + break; > > > > > > > > + default: > > > > > > > > + dev_err(dwmac->dev, "Unsupported PHY mode %u\n", > > > > > > > > + plat->phy_interface); > > > > > > > > + return -EOPNOTSUPP; > > > > > > > > + } > > > > > > > > + > > > > > > > > + regmap_field_write(regmap_fields[GMAC1_SHUT], 0); > > > > > > > > + } else { > > > > > > > > + switch (plat->phy_interface) { > > > > > > > > + case PHY_INTERFACE_MODE_RGMII: > > > > > > > > + regmap_field_write(regmap_fields[GMAC0_USE_TXCLK], 0); > > > > > > > > + regmap_field_write(regmap_fields[GMAC0_USE_PWM01], 0); > > > > > > > > + break; > > > > > > > > + case PHY_INTERFACE_MODE_MII: > > > > > > > > + regmap_field_write(regmap_fields[GMAC0_USE_TXCLK], 1); > > > > > > > > + regmap_field_write(regmap_fields[GMAC0_USE_PWM01], 1); > > > > > > > > + break; > > > > > > > > + default: > > > > > > > > + dev_err(dwmac->dev, "Unsupported PHY mode %u\n", > > > > > > > > + plat->phy_interface); > > > > > > > > + return -EOPNOTSUPP; > > > > > > > > + } > > > > > > > > + > > > > > > > > + regmap_field_write(regmap_fields[GMAC0_SHUT], 0); > > > > > > > > + } > > > > > > > > + > > > > > > > > + return 0; > > > > > > > > +} > > > > > > > > + > > > > > > > > +static int ls1c_dwmac_syscon_init(struct plat_stmmacenet_data *plat) > > > > > > > > +{ > > > > > > > > + struct ls1x_dwmac *dwmac = plat->bsp_priv; > > > > > > > > + struct regmap_field **regmap_fields = dwmac->regmap_fields; > > > > > > > > + > > > > > > > > + if (plat->phy_interface == PHY_INTERFACE_MODE_RMII) { > > > > > > > > + regmap_field_write(regmap_fields[PHY_INTF_SELI], 0x4); > > > > > > > > + } else { > > > > > > > > + dev_err(dwmac->dev, "Unsupported PHY-mode %u\n", > > > > > > > > + plat->phy_interface); > > > > > > > > + return -EOPNOTSUPP; > > > > > > > > + } > > > > > > > > + > > > > > > > > + regmap_field_write(regmap_fields[GMAC_SHUT], 0); > > > > > > > > + > > > > > > > > + return 0; > > > > > > > > +} > > > > > > > > + > > > > > > > > +static const struct ls1x_dwmac_syscon ls1b_dwmac_syscon = { > > > > > > > > + .reg_fields = ls1b_dwmac_syscon_regfields, > > > > > > > > + .nr_reg_fields = ARRAY_SIZE(ls1b_dwmac_syscon_regfields), > > > > > > > > + .syscon_init = ls1b_dwmac_syscon_init, > > > > > > > > +}; > > > > > > > > + > > > > > > > > +static const struct ls1x_dwmac_syscon ls1c_dwmac_syscon = { > > > > > > > > + .reg_fields = ls1c_dwmac_syscon_regfields, > > > > > > > > + .nr_reg_fields = ARRAY_SIZE(ls1c_dwmac_syscon_regfields), > > > > > > > > + .syscon_init = ls1c_dwmac_syscon_init, > > > > > > > > +}; > > > > > > > > + > > > > > > > > +static int ls1x_dwmac_init(struct platform_device *pdev, void *priv) > > > > > > > > +{ > > > > > > > > + struct ls1x_dwmac *dwmac = priv; > > > > > > > > + int ret; > > > > > > > > + > > > > > > > > > > > > > > > + ret = devm_regmap_field_bulk_alloc(dwmac->dev, dwmac->regmap, > > > > > > > > + dwmac->regmap_fields, > > > > > > > > + dwmac->syscon->reg_fields, > > > > > > > > + dwmac->syscon->nr_reg_fields); > > > > > > > > > > > > > > Please see my first comment about this. > > > > > > > > > > > > > > > + if (ret) > > > > > > > > + return ret; > > > > > > > > + > > > > > > > > + if (dwmac->syscon->syscon_init) { > > > > > > > > + ret = dwmac->syscon->syscon_init(dwmac->plat_dat); > > > > > > > > + if (ret) > > > > > > > > + return ret; > > > > > > > > + } > > > > > > > > + > > > > > > > > + return 0; > > > > > > > > +} > > > > > > > > + > > > > > > > > +static const struct of_device_id ls1x_dwmac_syscon_match[] = { > > > > > > > > + { .compatible = "loongson,ls1b-syscon", .data = &ls1b_dwmac_syscon }, > > > > > > > > + { .compatible = "loongson,ls1c-syscon", .data = &ls1c_dwmac_syscon }, > > > > > > > > + { } > > > > > > > > +}; > > > > > > > > + > > > > > > > > +static int ls1x_dwmac_probe(struct platform_device *pdev) > > > > > > > > +{ > > > > > > > > + struct plat_stmmacenet_data *plat_dat; > > > > > > > > + struct stmmac_resources stmmac_res; > > > > > > > > + struct device_node *syscon_np; > > > > > > > > + const struct of_device_id *match; > > > > > > > > + struct regmap *regmap; > > > > > > > > + struct ls1x_dwmac *dwmac; > > > > > > > > + const struct ls1x_dwmac_syscon *syscon; > > > > > > > > + size_t size; > > > > > > > > + int ret; > > > > > > > > + > > > > > > > > + ret = stmmac_get_platform_resources(pdev, &stmmac_res); > > > > > > > > + if (ret) > > > > > > > > + return ret; > > > > > > > > + > > > > > > > > > > > > > > > + /* Probe syscon */ > > > > > > > > + syscon_np = of_parse_phandle(pdev->dev.of_node, "syscon", 0); > > > > > > > > > > > > > > it's vendor-specific property so it is supposed to have a > > > > > > > vendor-specific prefix and possibly ls1-specific name. > > > > > > > > > > > > > This has been fixed in v2. > > > > > > Could you please review v2? > > > > > > Thanks! > > > > > > > > > > > > > > + if (!syscon_np) > > > > > > > > + return -ENODEV; > > > > > > > > + > > > > > > > > + match = of_match_node(ls1x_dwmac_syscon_match, syscon_np); > > > > > > > > + if (!match) { > > > > > > > > + of_node_put(syscon_np); > > > > > > > > + return -EINVAL; > > > > > > > > + } > > > > > > > > + syscon = (const struct ls1x_dwmac_syscon *)match->data; > > > > > > > > > > > Please note that of_match_node() is used for syscon matching. > > > > > > I noticed it in the first place. Please see my next comment. > > > > > > > > > > > > > > > + > > > > > > > > + regmap = syscon_node_to_regmap(syscon_np); > > > > > > > > + of_node_put(syscon_np); > > > > > > > > + if (IS_ERR(regmap)) { > > > > > > > > + ret = PTR_ERR(regmap); > > > > > > > > + dev_err(&pdev->dev, "Unable to map syscon: %d\n", ret); > > > > > > > > + return ret; > > > > > > > > + } > > > > > > > > > > > > > > or you can use syscon_regmap_lookup_by_phandle(). Using > > > > > > > of_match_node() doesn't seem necessary since it's unlikely to have > > > > > > > moee than one system controller available on the LS1b or LS1c chips. > > > > > > > > > > > > > > > > > > I planned to use syscon_regmap_lookup_by_phandle(). > > > > > > Thus the compatible > > > > > > "loongson,ls1b-dwmac-syscon"/"loongson,ls1c-dwmac-syscon" would become > > > > > > useless. > > > > > > I'm not sure about this. > > > > > > > > > > The compatible strings should be left despite of the > > > > > syscon_regmap_lookup_by_phandle() usage. But again "dwmac" suffix is > > > > > redundant. Based on the CSRs definition in regs-mux.h, selecting > > > > > (G)MAC pins mode is only a small part of the Loongson1 SoC system > > > > > controllers functionality. > > > > > "loongson,ls1b-syscon"/"loongson,ls1c-syscon" looks more appropriate. > > > > > > > > > That's what I did in PATCH 2/5. > > > > I've just explained this to Krzysztof. > > > > And will change back to "loongson,ls1b-syscon"/"loongson,ls1c-syscon" > > > > in next version. > > > > > > > > > > > In addition, syscon_regmap_lookup_by_phandle() returns regmap pointer directly. > > > > Then, there wil be no way to do syscon matching without its device_node. > > > > How will I know whether the syscon is loongson,ls1b-syscon or > > > > loongson,ls1c-syscon? > > > > > > Do you have both of these syscons available in the same SoC? I don't > > > think so. Thus you don't need such validation since the LS1C SoC dts > > > file will have the "loongson,ls1c-syscon" syscon node defined only and > > > the LS1B SoC dts file - "loongson,ls1b-syscon" only. > > > > > > I believe you have noticed the difference of syscon_init() between > > LS1B and LS1C. > > The syscon matching is for finding the right syscon_init(). > > There are other ways to select syscon_init(). Syscon node compatible > string is just one of them. You can do that by one of the next way: > 1. Based on the syscon-property name: "loongson,ls1b-syscon" property > always points to the LS1B syscon phandle so the > ls1b_dwmac_syscon_init() function is supposed to be selected; > "loongson,ls1c-syscon" property always points to the LS1C syscon so > ls1c_dwmac_syscon_init() is supposed to be utilized. > 2. Based on the MAC compatible string. loongson,ls1b-gmac can be found > on the LS1B SoC only which is equipped with the ls1b-syscon system > controller only so ls1b_dwmac_syscon_init() must be selected. Likewise > you can determine the init function on the LS1C SoC. > OK. I once used the second way for my draft version. static const struct of_device_id ls1x_dwmac_match[] = { { .compatible = "loongson,ls1b-gmac", .data = &ls1b_dwmac_syscon, }, { .compatible = "loongson,ls1c-mac" .data = &ls1c_dwmac_syscon, }, { } }; Then, I will change back to this implementation in the next version. > -Serge(y) > > > > > Thanks for your review! > > > > > -Serge(y) > > > > > > > > > > > Thanks for your review! > > > > > > > > > > > > > > > > > > > > > > > > > -Serge(y) > > > > > > > > > > > > > > > > > > > + > > > > > > > > + size = syscon->nr_reg_fields * sizeof(struct regmap_field *); > > > > > > > > + dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac) + size, GFP_KERNEL); > > > > > > > > + if (!dwmac) > > > > > > > > + return -ENOMEM; > > > > > > > > + > > > > > > > > + plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac); > > > > > > > > + if (IS_ERR(plat_dat)) { > > > > > > > > + dev_err(&pdev->dev, "dt configuration failed\n"); > > > > > > > > + return PTR_ERR(plat_dat); > > > > > > > > + } > > > > > > > > + > > > > > > > > + plat_dat->bsp_priv = dwmac; > > > > > > > > + plat_dat->init = ls1x_dwmac_init; > > > > > > > > + dwmac->dev = &pdev->dev; > > > > > > > > + dwmac->plat_dat = plat_dat; > > > > > > > > + dwmac->syscon = syscon; > > > > > > > > + dwmac->regmap = regmap; > > > > > > > > + > > > > > > > > + ret = stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); > > > > > > > > + if (ret) > > > > > > > > + goto err_remove_config_dt; > > > > > > > > + > > > > > > > > + return 0; > > > > > > > > + > > > > > > > > +err_remove_config_dt: > > > > > > > > > > > > > > > + if (pdev->dev.of_node) > > > > > > > > > > > > > > Is this conditional statement necessary here? > > > > > > > > > > > > > You're right. > > > > > > Will remove this condition in next version. > > > > > > Thanks! > > > > > > > > > > > > > -Serge > > > > > > > > > > > > > > > + stmmac_remove_config_dt(pdev, plat_dat); > > > > > > > > + > > > > > > > > + return ret; > > > > > > > > +} > > > > > > > > + > > > > > > > > +static const struct of_device_id ls1x_dwmac_match[] = { > > > > > > > > + { .compatible = "loongson,ls1b-dwmac" }, > > > > > > > > + { .compatible = "loongson,ls1c-dwmac" }, > > > > > > > > + { } > > > > > > > > +}; > > > > > > > > +MODULE_DEVICE_TABLE(of, ls1x_dwmac_match); > > > > > > > > + > > > > > > > > +static struct platform_driver ls1x_dwmac_driver = { > > > > > > > > + .probe = ls1x_dwmac_probe, > > > > > > > > + .remove_new = stmmac_pltfr_remove, > > > > > > > > + .driver = { > > > > > > > > + .name = "loongson1-dwmac", > > > > > > > > + .of_match_table = ls1x_dwmac_match, > > > > > > > > + }, > > > > > > > > +}; > > > > > > > > +module_platform_driver(ls1x_dwmac_driver); > > > > > > > > + > > > > > > > > +MODULE_AUTHOR("Keguang Zhang <keguang.zhang@xxxxxxxxx>"); > > > > > > > > +MODULE_DESCRIPTION("Loongson1 DWMAC glue layer"); > > > > > > > > +MODULE_LICENSE("GPL"); > > > > > > > > -- > > > > > > > > 2.39.2 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > -- > > > > > > Best regards, > > > > > > > > > > > > Keguang Zhang > > > > > > > > > > > > > > > > -- > > > > Best regards, > > > > > > > > Keguang Zhang > > > > > > > > -- > > Best regards, > > > > Keguang Zhang -- Best regards, Keguang Zhang