Hi, On Mon, Aug 05, 2013 at 04:58:43PM -0500, dinguyen@xxxxxxxxxx wrote: > From: Dinh Nguyen <dinguyen@xxxxxxxxxx> > > Use the PHYLIB to set the correct clock and skew values to the Micrel PHY. Add > platform specific intilization to put the STMMAC ethernet controller into the > correct PHY mode. > > Signed-off-by: Dinh Nguyen <dinguyen@xxxxxxxxxx> > Tested-by: Jack Mitchell <jack.mitchell@xxxxxxxxxxxxxxxxx> > CC: Arnd Bergmann <arnd@xxxxxxxx> > CC: Olof Johansson <olof@xxxxxxxxx> > Cc: Rob Herring <rob.herring@xxxxxxxxxxx> > Cc: Pawel Moll <pawel.moll@xxxxxxx> > Cc: Mark Rutland <mark.rutland@xxxxxxx> > Cc: Stephen Warren <swarren@xxxxxxxxxxxxx> > Cc: Ian Campbell <ian.campbell@xxxxxxxxxx> > Cc: devicetree@xxxxxxxxxxxxxxx > Cc: Thomas Petazzoni <thomas.petazzoni@xxxxxxxxxxxxxxxxxx> > Cc: Pavel Machek <pavel@xxxxxxx> > Cc: Jack Mitchell <jack.mitchell@xxxxxxxxxxxxxxxxx> > --- > arch/arm/mach-socfpga/core.h | 8 ++++ > arch/arm/mach-socfpga/socfpga.c | 85 ++++++++++++++++++++++++++++++++++++++- > 2 files changed, 92 insertions(+), 1 deletion(-) > > diff --git a/arch/arm/mach-socfpga/core.h b/arch/arm/mach-socfpga/core.h > index 572b8f7..505b8fe5 100644 > --- a/arch/arm/mach-socfpga/core.h > +++ b/arch/arm/mach-socfpga/core.h > @@ -28,6 +28,14 @@ > #define RSTMGR_CTRL_SWCOLDRSTREQ 0x1 /* Cold Reset */ > #define RSTMGR_CTRL_SWWARMRSTREQ 0x2 /* Warm Reset */ > > +#define SYSMGR_EMACGRP_CTRL_OFFSET 0x60 > +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 > +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 > +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2 > +#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2 > + > +#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003 > + > extern void socfpga_secondary_startup(void); > extern void __iomem *socfpga_scu_base_addr; > > diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c > index bfce964..abbde76 100644 > --- a/arch/arm/mach-socfpga/socfpga.c > +++ b/arch/arm/mach-socfpga/socfpga.c > @@ -16,10 +16,14 @@ > */ > #include <linux/clk-provider.h> > #include <linux/irqchip.h> > +#include <linux/micrel_phy.h> > #include <linux/of_address.h> > #include <linux/of_irq.h> > +#include <linux/of_net.h> > #include <linux/of_platform.h> > #include <linux/reboot.h> > +#include <linux/stmmac.h> > +#include <linux/phy.h> > > #include <asm/hardware/cache-l2x0.h> > #include <asm/mach/arch.h> > @@ -33,6 +37,22 @@ void __iomem *rst_manager_base_addr; > void __iomem *clk_mgr_base_addr; > unsigned long cpu1start_addr; > > +static int stmmac_plat_init(struct platform_device *pdev); > + > +static struct plat_stmmacenet_data stmmacenet0_data = { > + .init = &stmmac_plat_init, > +}; > + > +static struct plat_stmmacenet_data stmmacenet1_data = { > + .init = &stmmac_plat_init, > +}; I would prefer to see refactoring of the driver such that it gets the phy configuration data out of the devicetree instead of needing per-board callbacks. > + > +static const struct of_dev_auxdata socfpga_auxdata_lookup[] __initconst = { > + OF_DEV_AUXDATA("snps,dwmac-3.70a", 0xff700000, NULL, &stmmacenet0_data), > + OF_DEV_AUXDATA("snps,dwmac-3.70a", 0xff702000, NULL, &stmmacenet1_data), > + {/* sentinel */} > +}; > + > static struct map_desc scu_io_desc __initdata = { > .virtual = SOCFPGA_SCU_VIRT_BASE, > .pfn = 0, /* run-time */ > @@ -58,6 +78,65 @@ static void __init socfpga_scu_map_io(void) > iotable_init(&scu_io_desc, 1); > } > > +static int ksz9021rlrn_phy_fixup(struct phy_device *phydev) > +{ > + if (IS_BUILTIN(CONFIG_PHYLIB)) { So what happens if PHYLIB is a module? > + /* min rx data delay */ > + phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL, > + MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW | 0x8000); > + phy_write(phydev, MICREL_KSZ9021_EXTREG_DATA_WRITE, 0x0000); > + > + /* max rx/tx clock delay, min rx/tx control delay */ > + phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL, > + MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW | 0x8000); > + phy_write(phydev, MICREL_KSZ9021_EXTREG_DATA_WRITE, 0xa0d0); > + phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL, 0x104); > + } > + > + return 0; > +} > + > +static int stmmac_plat_init(struct platform_device *pdev) > +{ > + u32 ctrl, val, shift; > + int phymode; > + > + if (of_machine_is_compatible("altr,socfpga-vt")) > + return 0; > + > + phymode = of_get_phy_mode(pdev->dev.of_node); > + > + switch (phymode) { > + case PHY_INTERFACE_MODE_RGMII: > + val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII; > + break; > + case PHY_INTERFACE_MODE_MII: > + case PHY_INTERFACE_MODE_GMII: > + val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; > + break; > + default: > + pr_err("%s bad phy mode %d", __func__, phymode); > + return -EINVAL; > + } > + > + if (&stmmacenet1_data == pdev->dev.platform_data) > + shift = SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH; > + else if (&stmmacenet0_data == pdev->dev.platform_data) > + shift = 0; This is awkward too, comparing back to the platform data to figure out which of the two devices you're on. > + else { > + pr_err("%s unexpected platform data pointer\n", __func__); > + return -EINVAL; > + } > + > + ctrl = readl(sys_manager_base_addr + SYSMGR_EMACGRP_CTRL_OFFSET); > + ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << shift); > + ctrl |= (val << shift); > + > + writel(ctrl, (sys_manager_base_addr + SYSMGR_EMACGRP_CTRL_OFFSET)); > + > + return 0; > +} > + > static void __init socfpga_map_io(void) > { > socfpga_scu_map_io(); > @@ -106,9 +185,13 @@ static void socfpga_cyclone5_restart(enum reboot_mode mode, const char *cmd) > static void __init socfpga_cyclone5_init(void) > { > l2x0_of_init(0, ~0UL); > - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); > + of_platform_populate(NULL, of_default_bus_match_table, > + socfpga_auxdata_lookup, NULL); > of_clk_init(NULL); > socfpga_init_clocks(); > + if (IS_BUILTIN(CONFIG_PHYLIB)) > + phy_register_fixup_for_uid(PHY_ID_KSZ9021RLRN, > + MICREL_PHY_ID_MASK, ksz9021rlrn_phy_fixup); -Olof -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html