Driver for the MII/GMII/RGMII media converter blocks found in the Renesas RZ/N1 SoC. These converters sit in the Ethernet data path, and need to be configured with speed/duplex as detected by the PHY.
Signed-off-by: Ralph Siemsen <[email protected]> --- drivers/net/Kconfig | 6 ++ drivers/net/Makefile | 1 + drivers/net/rzn1_miic.c | 193 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 200 insertions(+) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index edc4cb29598..659e9fd82d0 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -886,6 +886,12 @@ config RZN1_A5PSW Support the Advanced 5-Port ethernet switch (A5PSW) found in the Renesas RZ/N1 SoC. +config RZN1_MIIC + bool "Renesas RZ/N1 MIIC ethernet accessory" + help + Support the MIIC ethernet accessory found in Renesas RZ/N1 SoC. + These are media converters for MII/GMII/RGMII. + config MPC8XX_FEC bool "Fast Ethernet Controller on MPC8XX" depends on MPC8xx diff --git a/drivers/net/Makefile b/drivers/net/Makefile index b8f270ae233..049212b1fd2 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -95,6 +95,7 @@ obj-$(CONFIG_PIC32_ETH) += pic32_mdio.o pic32_eth.o obj-$(CONFIG_RENESAS_ETHER_SWITCH) += rswitch.o obj-$(CONFIG_RENESAS_RAVB) += ravb.o obj-$(CONFIG_RZN1_A5PSW) += rzn1_a5psw.o +obj-$(CONFIG_RZN1_MIIC) += rzn1_miic.o obj-$(CONFIG_RTL8139) += rtl8139.o obj-$(CONFIG_RTL8169) += rtl8169.o obj-$(CONFIG_SH_ETHER) += sh_eth.o diff --git a/drivers/net/rzn1_miic.c b/drivers/net/rzn1_miic.c new file mode 100644 index 00000000000..491923d8511 --- /dev/null +++ b/drivers/net/rzn1_miic.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * MII/GMII/RGMII converter support + * + * Based loosely on Linux drivers/net/pcs/pcs-rzn1-miic.c + * and the older driver in Renesas u-boot. + */ + +#include <clk.h> +#include <dm/device.h> +#include <dm/device_compat.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/of_extra.h> +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <miiphy.h> +#include <net/dsa.h> +#include <regmap.h> + +struct rzn1_miic_plat { + struct clk_bulk bulk; + struct regmap *regmap; +}; + +/* RIN Ether Accessory (Switch Control) regs */ +#define PRCMD 0x0 /* Ethernet Protect */ +#define IDCODE 0x4 /* EtherSwitch IDCODE */ +#define MODCTRL 0x8 /* Mode Control */ +#define PTP_MODE_CTRL 0xc /* PTP Mode Control */ +#define PHY_LINK_MODE 0x14 /* Ethernet PHY Link Mode */ + +/* RIN RGMII/RMII Converter regs */ +#define CONVCTRL(x) (0x100 + ((x)) * 4) /* RGMII/RMII Converter */ +#define CONVCTRL_10_MBPS 0 +#define CONVCTRL_100_MBPS BIT(0) +#define CONVCTRL_1000_MBPS BIT(1) +#define CONVCTRL_MII 0 +#define CONVCTRL_RMII BIT(2) +#define CONVCTRL_RGMII BIT(3) +#define CONVCTRL_REF_CLK_OUT BIT(4) +#define CONVCTRL_HALF_DUPLEX 0 +#define CONVCTRL_FULL_DUPLEX BIT(8) +#define CONVRST 0x114 /* RGMII/RMII Converter RST */ +#define PHYIF_RST(x) BIT(x) + +static void rzn1_rin_prot_writel(struct udevice *dev, u32 reg, u32 val) +{ + struct rzn1_miic_plat *plat = dev_get_plat(dev); + struct regmap *regmap = plat->regmap; + + /* RIN: Unprotect register writes */ + regmap_write(regmap, PRCMD, 0x00a5); + regmap_write(regmap, PRCMD, 0x0001); + regmap_write(regmap, PRCMD, 0xfffe); + regmap_write(regmap, PRCMD, 0x0001); + + /* Do the write */ + regmap_write(regmap, reg, val); + + /* Re-enable protection */ + regmap_write(regmap, PRCMD, 0x0000); +} + +/* + * RIN RGMII/RMII Converter set speed + * RGMII/RMII Converter number: 0..4 + * speed: 10, 100, 1000 + */ +void rzn1_rgmii_rmii_conv_speed(struct udevice *dev, int phy, + int full_duplex, int speed) +{ + struct rzn1_miic_plat *plat = dev_get_plat(dev); + struct regmap *regmap = plat->regmap; + u32 val = 0; + + regmap_read(regmap, CONVCTRL(phy), &val); + + val &= CONVCTRL_MII | CONVCTRL_RMII | CONVCTRL_RGMII | + CONVCTRL_REF_CLK_OUT; + + /* The interface type and speed bits are somewhat intertwined */ + if (val != CONVCTRL_MII) { + if (speed == SPEED_1000) + val |= CONVCTRL_1000_MBPS; + else if (speed == SPEED_100) + val |= CONVCTRL_100_MBPS; + else if (speed == SPEED_10) + val |= CONVCTRL_10_MBPS; + } + + if (full_duplex) + val |= CONVCTRL_FULL_DUPLEX; + + regmap_write(regmap, CONVCTRL(phy), val); +} + +/* + * RIN RGMII/RMII Converter setup one + * RGMII/RMII Converter number: 0..4 + * if_type: Type of PHY interface, see phy_interface_t + */ +void rzn1_rgmii_rmii_conv_setup(struct udevice *dev, int phy, + u32 if_type, int rmii_ref_clk_out) +{ + struct rzn1_miic_plat *plat = dev_get_plat(dev); + struct regmap *regmap = plat->regmap; + u32 val = 0; + int speed = SPEED_100; + + switch (if_type) { + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + val |= CONVCTRL_RGMII; + speed = SPEED_1000; + break; + case PHY_INTERFACE_MODE_RMII: + val |= CONVCTRL_RMII; + break; + case PHY_INTERFACE_MODE_MII: + val |= CONVCTRL_MII; + break; + }; + + if (if_type == PHY_INTERFACE_MODE_RMII && rmii_ref_clk_out) + val |= CONVCTRL_REF_CLK_OUT; + + regmap_write(regmap, CONVCTRL(phy), val); + + rzn1_rgmii_rmii_conv_speed(dev, phy, DUPLEX_FULL, speed); + + /* reset */ + regmap_read(regmap, CONVRST, &val); + val &= ~PHYIF_RST(phy); + rzn1_rin_prot_writel(dev, CONVRST, val); + udelay(1000); + val |= PHYIF_RST(phy); + rzn1_rin_prot_writel(dev, CONVRST, val); +} + +static int rzn1_miic_probe(struct udevice *dev) +{ + struct rzn1_miic_plat *plat = dev_get_plat(dev); + int ret; + + dev_warn(dev, "%s:%d\n", __func__, __LINE__); + + /* Enable clocks */ + ret = clk_get_bulk(dev, &plat->bulk); + if (ret) { + dev_err(dev, "Failed to get clocks\n"); + return ret; + } + ret = clk_enable_bulk(&plat->bulk); + if (ret) { + dev_err(dev, "Failed to enable clocks\n"); + return ret; + } + + /* Access the registers */ + ret = regmap_init_mem(dev_ofnode(dev), &plat->regmap); + if (ret) { + dev_err(dev, "Failed to get regmap\n"); + return ret; + } + + /* Set PTP to use 125MHz PLL clock */ + rzn1_rin_prot_writel(dev, PTP_MODE_CTRL, 0x2); + + /* Setup RGMII/RMII Converters */ + rzn1_rgmii_rmii_conv_setup(dev, 3, PHY_INTERFACE_MODE_RGMII_ID, 0); + rzn1_rgmii_rmii_conv_setup(dev, 4, PHY_INTERFACE_MODE_RGMII_ID, 0); + + /* RIN: Mode Control - GMAC1 on all Switch ports */ + rzn1_rin_prot_writel(dev, MODCTRL, 0x13); + + return 0; +} + +static const struct udevice_id rzn1_miic_ids[] = { + { .compatible = "renesas,rzn1-miic" }, + { } +}; + +U_BOOT_DRIVER(rzn1_miic) = { + .name = "rzn1_miic", + .id = UCLASS_MISC, + .of_match = rzn1_miic_ids, + .probe = rzn1_miic_probe, + .plat_auto = sizeof(struct rzn1_miic_plat), +}; -- 2.55.0
