diff --git a/arch/arm/mach-socfpga/generic.c b/arch/arm/mach-socfpga/generic.c index 234dc52..2d4afd0 100644 --- a/arch/arm/mach-socfpga/generic.c +++ b/arch/arm/mach-socfpga/generic.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -55,16 +56,43 @@ return 0; } -static int socfpga_init(void) +/* Some initialization for the EMAC */ +static void socfpga_init_emac(void) { - uint32_t val; + uint32_t rst, val; - /* Clearing emac0 PHY interface select to 0 */ + /* No need for this without network support, e.g. xloader build */ + if (!IS_ENABLED(CONFIG_NET)) + return; + + /* According to Cyclone V datasheet, 17-60 "EMAC HPS Interface + * Initialization", changing PHYSEL should be done with EMAC in reset + * via permodrst. */ + + /* Everything, except L4WD0/1, is out of reset via socfpga_lowlevel_init() */ + rst = readl(CYCLONE5_RSTMGR_ADDRESS + RESET_MGR_PER_MOD_RESET_OFS); + rst |= RSTMGR_PERMODRST_EMAC0 | RSTMGR_PERMODRST_EMAC1; + writel(rst, CYCLONE5_RSTMGR_ADDRESS + RESET_MGR_PER_MOD_RESET_OFS); + + /* Set emac0/1 PHY interface select to RGMII. We could read phy-mode + * from the device tree, if it was desired to support interfaces other + * than RGMII. */ val = readl(CONFIG_SYSMGR_EMAC_CTRL); + val &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << SYSMGR_EMACGRP_CTRL_PHYSEL0_LSB); val &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << SYSMGR_EMACGRP_CTRL_PHYSEL1_LSB); + val |= SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII << SYSMGR_EMACGRP_CTRL_PHYSEL0_LSB; val |= SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII << SYSMGR_EMACGRP_CTRL_PHYSEL1_LSB; writel(val, CONFIG_SYSMGR_EMAC_CTRL); + /* Take emac0 and emac1 out of reset */ + rst &= ~(RSTMGR_PERMODRST_EMAC0 | RSTMGR_PERMODRST_EMAC1); + writel(rst, CYCLONE5_RSTMGR_ADDRESS + RESET_MGR_PER_MOD_RESET_OFS); +} + +static int socfpga_init(void) +{ + socfpga_init_emac(); + writel(SYSMGR_SDMMC_CTRL_DRVSEL(3) | SYSMGR_SDMMC_CTRL_SMPLSEL(0), SYSMGR_SDMMCGRP_CTRL_REG); diff --git a/drivers/firmware/socfpga.c b/drivers/firmware/socfpga.c index 14a7a14..159644b 100644 --- a/drivers/firmware/socfpga.c +++ b/drivers/firmware/socfpga.c @@ -79,9 +79,10 @@ struct fpgamgr { struct firmware_handler fh; - struct device_d *dev; + struct device_d dev; void __iomem *regs; void __iomem *regs_data; + int programmed; }; /* Get the FPGA mode */ @@ -303,12 +304,12 @@ /* unmap the bridges from NIC-301 */ writel(0x1, CYCLONE5_L3REGS_ADDRESS); - dev_dbg(mgr->dev, "start programming...\n"); + dev_dbg(&mgr->dev, "start programming...\n"); /* initialize the FPGA Manager */ status = fpgamgr_program_init(mgr); if (status) { - dev_err(mgr->dev, "program init failed with: %s\n", + dev_err(&mgr->dev, "program init failed with: %s\n", strerror(-status)); return status; } @@ -356,27 +357,27 @@ /* Ensure the FPGA entering config done */ status = fpgamgr_program_poll_cd(mgr); if (status) { - dev_err(mgr->dev, "poll for config done failed with: %s\n", + dev_err(&mgr->dev, "poll for config done failed with: %s\n", strerror(-status)); return status; } - dev_dbg(mgr->dev, "waiting for init phase...\n"); + dev_dbg(&mgr->dev, "waiting for init phase...\n"); /* Ensure the FPGA entering init phase */ status = fpgamgr_program_poll_initphase(mgr); if (status) { - dev_err(mgr->dev, "poll for init phase failed with: %s\n", + dev_err(&mgr->dev, "poll for init phase failed with: %s\n", strerror(-status)); return status; } - dev_dbg(mgr->dev, "waiting for user mode...\n"); + dev_dbg(&mgr->dev, "waiting for user mode...\n"); /* Ensure the FPGA entering user mode */ status = fpgamgr_program_poll_usermode(mgr); if (status) { - dev_err(mgr->dev, "poll for user mode with: %s\n", + dev_err(&mgr->dev, "poll for user mode with: %s\n", strerror(-status)); return status; } @@ -384,12 +385,21 @@ return 0; } +/* Get current programmed state of fpga and put in "programmed" parameter */ +static int programmed_get(struct param_d *p, void *priv) +{ + struct fpgamgr *mgr = priv; + mgr->programmed = fpgamgr_get_mode(mgr) == FPGAMGRREGS_MODE_USERMODE; + return 0; +} + static int fpgamgr_probe(struct device_d *dev) { struct fpgamgr *mgr; struct firmware_handler *fh; const char *alias = of_alias_get(dev->device_node); const char *model = NULL; + struct param_d *p; int ret; dev_dbg(dev, "Probing FPGA firmware programmer\n"); @@ -422,17 +432,31 @@ fh->model = xstrdup(model); fh->dev = dev; - mgr->dev = dev; - dev_dbg(dev, "Registering FPGA firmware programmer\n"); + mgr->dev.id = DEVICE_ID_SINGLE; + strcpy(mgr->dev.name, "fpga"); + mgr->dev.parent = dev; + ret = register_device(&mgr->dev); + if (ret) + goto out; + + p = dev_add_param_bool(&mgr->dev, "programmed", NULL, programmed_get, &mgr->programmed, mgr); + if (IS_ERR(p)) { + ret = PTR_ERR(p); + goto out_unreg; + } + + fh->dev = &mgr->dev; ret = firmwaremgr_register(fh); if (ret != 0) { free(mgr); - goto out; + goto out_unreg; } return 0; +out_unreg: + unregister_device(&mgr->dev); out: free(fh->id); free(mgr);