drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.cAlso absolutely vital to look at are the device tree files:
arch/arm/boot/dts arch/arm/boot/dts/sunxi-h3-h5.dtsiI originally tracked these down in a snapshot of the 5.4.43 sources I have on disk, but I see the C driver (with about 100 extra lines) in the latest git as well, and I will focus my study on the latest git.
Apparently the current source has been reworked by various linux people. Originally source was contributed by "sunxi", but that code has been polished up for whatever reasons in the current linux sources.
It is curious that this is in the ST micro subdirectory. I have not idea what the connection there might be given that this is an Allwinner chip, but this remains a mystery for the time being.
I have learned several things just skimming this driver:
The crucial action is in mdio_mux_syscon_switch_fn(). The code I need to understand is:
regmap_field_read(gmac->regmap_field, ®); switch (desired_child) { case DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID: dev_info(priv->device, "Switch mux to internal PHY"); val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SELECT; need_power_ephy = true; regmap_field_write(gmac->regmap_field, val); if (need_power_ephy) ret = sun8i_dwmac_power_internal_phy(priv); /* After changing syscon value, the MAC need reset or it will * use the last value (and so the last PHY set). */ ret = sun8i_dwmac_reset(priv);
This regmap business is set up in the sun8i_dwmac_probe() function. The following is the code with as much error handling and such removed.
static int sun8i_dwmac_probe(struct platform_device *pdev) { struct regmap *regmap; struct sunxi_priv_data *gmac; gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); gmac->variant = of_device_get_match_data(&pdev->dev); regmap = sun8i_dwmac_get_syscon_from_dev(pdev->dev.of_node); if (IS_ERR(regmap)) regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "syscon"); gmac->regmap_field = devm_regmap_field_alloc(dev, regmap, *gmac->variant->syscon_field); }When we dig into the sun8i_dwmac_get_syscon_from_dev() routine above, we see various references to "of_" routines. Here "of_" denotes "open firmware" and this is the linux device tree API.
arch/arm/boot/dts arch/arm/boot/dts/sunxi-h3-h5.dtsiThis includes many other files from "dt-bindings/reset/sun8i-h3-ccu.h" and such like.
/u1/linux/linux-git/include/dt-bindings/clock/sun8i-h3-ccu.h /u1/linux/linux-git/include/dt-bindings/reset/sun8i-h3-ccu.hThe h3-h5 file is included from:
sun8i-h3.dtsiThis file has a lot more useful addresses and such, including:
syscon: system-control@1c00000 { compatible = "allwinner,sun8i-h3-system-control"; reg = <0x01c00000 0x1000>; #address-cells = <1>; #size-cells = <1>; ranges;It would certainly be worth our while to spend a day or two getting familiar with the linux device tree framework, along with the regmap scheme. But I am going to take a break from all that and look at the H3 datasheet.
While we are at it, we take a look at the CCU beginning at page 87.
The clock diagram shows the emac hung on the AHB2 bus.
Offset 0x5c is the AHB2 config register, but just controls the bus clock in general.
Offset 0x60 is the bus clock gate register 0, and has a bit for the EMAC.
Offset 0x70 is the bus clock gate register 4, and has a bit for the EPHY.
Offset 0x2c0 is the bus reset register 0, and has a bit for the EMAC.
Offset 0x2c8 is the bus reset register 2, and has a bit for the EPHY.
I made the guess initially that "EPHY" denoted "external PHY". This is entirely wrong, it is the internal PHY. Look at these definitions from the top of dwmac-sun8i.c
/* H3 specific bits for EPHY */ #define H3_EPHY_ADDR_SHIFT 20 #define H3_EPHY_CLK_SEL BIT(18) /* 1: 24MHz, 0: 25MHz */ #define H3_EPHY_LED_POL BIT(17) /* 1: active low, 0: active high */ #define H3_EPHY_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */ #define H3_EPHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */ #define H3_EPHY_MUX_MASK (H3_EPHY_SHUTDOWN | H3_EPHY_SELECT) #define DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID 1 #define DWMAC_SUN8I_MDIO_MUX_EXTERNAL_ID 2When we switch to the internal PHY we do this:
val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SELECT;Note also that these bits (15 and 16) are in the syscon register (offset 0x30)
Kyu / [email protected]