From: "Ooi, Joyce" <joyce....@intel.com> commit 80f73e5d68c8acdc53d812bb6ca0d8ac9d0d12df from https://github.com/altera-opensource/linux-socfpga.git
As there is restriction to access to EMAC System Manager registers in the kernel, the use of SMC calls are required and added in dwmac-socfpga driver. Signed-off-by: Ooi, Joyce <joyce....@intel.com> Signed-off-by: Meng Li <meng...@windriver.com> --- .../net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 146 ++++++++++++++++++++- 1 file changed, 143 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 5b3b06a..afdd482 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -15,6 +15,9 @@ * Adopted from dwmac-sti.c */ +#ifdef CONFIG_HAVE_ARM_SMCCC +#include <linux/arm-smccc.h> +#endif #include <linux/mfd/syscon.h> #include <linux/of.h> #include <linux/of_address.h> @@ -52,6 +55,7 @@ struct socfpga_dwmac { int interface; u32 reg_offset; u32 reg_shift; + u32 sysmgr_reg; struct device *dev; struct regmap *sys_mgr_base_addr; struct reset_control *stmmac_rst; @@ -61,6 +65,122 @@ struct socfpga_dwmac { struct tse_pcs pcs; }; +#ifdef CONFIG_HAVE_ARM_SMCCC +/* Functions specified by ARM SMC Calling convention: + * + * FAST call executes atomic operations, returns when the requested operation + * has completed. + * STD call starts a operation which can be preempted by a non-secure + * interrupt. The call can return before the requested operation has completed. + * a0..a7 is used as register names in the descriptions below, on arm32 that + * translates to r0..r7 and on arm64 to w0..w7. + */ + +#define INTEL_SIP_SMC_STD_CALL_VAL(func_num) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_SIP, (func_num)) + +#define INTEL_SIP_SMC_FAST_CALL_VAL(func_num) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_SIP, (func_num)) + +#define INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION 0xFFFFFFFF +#define INTEL_SIP_SMC_STATUS_OK 0x0 +#define INTEL_SIP_SMC_REG_ERROR 0x5 + +/* Request INTEL_SIP_SMC_REG_READ + * + * Read a protected register using SMCCC + * + * Call register usage: + * a0: INTEL_SIP_SMC_REG_READ. + * a1: register address. + * a2-7: not used. + * + * Return status: + * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_REG_ERROR, or + * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION + * a1: Value in the register + * a2-3: not used. + */ +#define INTEL_SIP_SMC_FUNCID_REG_READ 7 +#define INTEL_SIP_SMC_REG_READ \ + INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_READ) + +/* Request INTEL_SIP_SMC_REG_WRITE + * + * Write a protected register using SMCCC + * + * Call register usage: + * a0: INTEL_SIP_SMC_REG_WRITE. + * a1: register address + * a2: value to program into register. + * a3-7: not used. + * + * Return status: + * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_REG_ERROR, or + * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION + * a1-3: not used. + */ +#define INTEL_SIP_SMC_FUNCID_REG_WRITE 8 +#define INTEL_SIP_SMC_REG_WRITE \ + INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_WRITE) + +/**************** Stratix 10 EMAC Memory Controller Functions ************/ + +/* s10_protected_reg_write + * Write to a protected SMC register. + * @context: Not used + * @reg: Address of register + * @value: Value to write + * Return: INTEL_SIP_SMC_STATUS_OK (0) on success + * INTEL_SIP_SMC_REG_ERROR on error + * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION if not supported + */ +static int s10_protected_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct arm_smccc_res result; + + arm_smccc_smc(INTEL_SIP_SMC_REG_WRITE, reg, val, 0, 0, + 0, 0, 0, &result); + + return (int)result.a0; +} + +/* s10_protected_reg_read + * Read the status of a protected SMC register + * @context: Not used + * @reg: Address of register + * @value: Value read. + * Return: INTEL_SIP_SMC_STATUS_OK (0) on success + * INTEL_SIP_SMC_REG_ERROR on error + * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION if not supported + */ +static int s10_protected_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct arm_smccc_res result; + + arm_smccc_smc(INTEL_SIP_SMC_REG_READ, reg, 0, 0, 0, + 0, 0, 0, &result); + + *val = (unsigned int)result.a1; + + return (int)result.a0; +} + +static const struct regmap_config s10_emac_regmap_cfg = { + .name = "s10_emac", + .reg_bits = 32, + .val_bits = 32, + .max_register = 0xffffffff, + .reg_read = s10_protected_reg_read, + .reg_write = s10_protected_reg_write, + .use_single_rw = true, +}; +#endif + static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed) { struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv; @@ -104,21 +224,39 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device * { struct device_node *np = dev->of_node; struct regmap *sys_mgr_base_addr; - u32 reg_offset, reg_shift; + u32 reg_offset, reg_shift, sysmgr_reg = 0; int ret, index; struct device_node *np_splitter = NULL; struct device_node *np_sgmii_adapter = NULL; + struct device_node *np_sysmgr = NULL; struct resource res_splitter; struct resource res_tse_pcs; struct resource res_sgmii_adapter; dwmac->interface = of_get_phy_mode(np); +#ifdef CONFIG_HAVE_ARM_SMCCC + sys_mgr_base_addr = devm_regmap_init(dev, NULL, (void *)dwmac, + &s10_emac_regmap_cfg); + if (IS_ERR(sys_mgr_base_addr)) + return PTR_ERR(sys_mgr_base_addr); + + np_sysmgr = of_parse_phandle(np, "altr,sysmgr-syscon", 0); + if (np_sysmgr) { + ret = of_property_read_u32_index(np_sysmgr, "reg", 0, + &sysmgr_reg); + if (ret) { + dev_info(dev, "Could not read sysmgr register address\n"); + return -EINVAL; + } + } +#else sys_mgr_base_addr = syscon_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon"); if (IS_ERR(sys_mgr_base_addr)) { dev_info(dev, "No sysmgr-syscon node found\n"); return PTR_ERR(sys_mgr_base_addr); } +#endif ret = of_property_read_u32_index(np, "altr,sysmgr-syscon", 1, ®_offset); if (ret) { @@ -222,6 +360,7 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device * dwmac->reg_offset = reg_offset; dwmac->reg_shift = reg_shift; dwmac->sys_mgr_base_addr = sys_mgr_base_addr; + dwmac->sysmgr_reg = sysmgr_reg; dwmac->dev = dev; of_node_put(np_sgmii_adapter); @@ -238,6 +377,7 @@ static int socfpga_dwmac_set_phy_mode(struct socfpga_dwmac *dwmac) int phymode = dwmac->interface; u32 reg_offset = dwmac->reg_offset; u32 reg_shift = dwmac->reg_shift; + u32 sysmgr_reg = dwmac->sysmgr_reg; u32 ctrl, val, module; switch (phymode) { @@ -266,7 +406,7 @@ static int socfpga_dwmac_set_phy_mode(struct socfpga_dwmac *dwmac) reset_control_assert(dwmac->stmmac_ocp_rst); reset_control_assert(dwmac->stmmac_rst); - regmap_read(sys_mgr_base_addr, reg_offset, &ctrl); + regmap_read(sys_mgr_base_addr, sysmgr_reg + reg_offset, &ctrl); ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << reg_shift); ctrl |= val << reg_shift; @@ -284,7 +424,7 @@ static int socfpga_dwmac_set_phy_mode(struct socfpga_dwmac *dwmac) ctrl &= ~(SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK << (reg_shift / 2)); } - regmap_write(sys_mgr_base_addr, reg_offset, ctrl); + regmap_write(sys_mgr_base_addr, sysmgr_reg + reg_offset, ctrl); /* Deassert reset for the phy configuration to be sampled by * the enet controller, and operation to start in requested mode -- 2.7.4 -- _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto