I am adding raw register access as an alternative, to keep supporting old device-tree specifying syscon handle. I considered writing helper functions for the if-not-error-syscon-else-raw, but between set_bits, clear_bits, global and per-port regs would have ended up with too many. > >> >> for (i = 0; i < UTMI_PHY_PORTS; i++) { >> - int test = regmap_test_bits(utmi->syscon, >> - SYSCON_UTMI_CFG_REG(i), >> - UTMI_PHY_CFG_PU_MASK); >> + if (!utmi->ports[i]) >> + continue; >> + >> + if (!IS_ERR(utmi->ports[i]->regs_cfg)) >> + reg = readl(utmi->ports[i]->regs_cfg); >> + else >> + regmap_read(utmi->syscon, SYSCON_UTMI_CFG_REG(i), ®); >> + int test = reg & UTMI_PHY_CFG_PU_MASK; >> /* skip PLL shutdown if there are active UTMI PHY ports */ >> if (test != 0) >> return 0; >> } >> >> /* PLL Power down if all UTMI PHYs are down */ >> - regmap_clear_bits(utmi->syscon, SYSCON_USB_CFG_REG, USB_CFG_PLL_MASK); >> + if (!IS_ERR(utmi->regs_usb)) { >> + reg = readl(utmi->regs_usb); >> + reg &= ~(USB_CFG_PLL_MASK); >> + writel(reg, utmi->regs_usb); >> + } else >> + regmap_clear_bits(utmi->syscon, SYSCON_USB_CFG_REG, USB_CFG_PLL_MASK); >> >> return 0; >> } >> @@ -191,8 +219,15 @@ static int mvebu_cp110_utmi_phy_power_on(struct phy *phy) >> struct mvebu_cp110_utmi_port *port = phy_get_drvdata(phy); >> struct mvebu_cp110_utmi *utmi = port->priv; >> struct device *dev = &phy->dev; >> + const void *match; >> + enum mvebu_cp110_utmi_type type; >> int ret; >> u32 reg; >> + u32 sel; >> + >> + match = device_get_match_data(utmi->dev); >> + if (match) >> + type = (enum mvebu_cp110_utmi_type)(uintptr_t)match; >> >> /* It is necessary to power off UTMI before configuration */ >> ret = mvebu_cp110_utmi_phy_power_off(phy); >> @@ -208,16 +243,45 @@ static int mvebu_cp110_utmi_phy_power_on(struct phy *phy) >> * to UTMI0 or to UTMI1 PHY port, but not to both. >> */ >> if (port->dr_mode == USB_DR_MODE_PERIPHERAL) { >> - regmap_update_bits(utmi->syscon, SYSCON_USB_CFG_REG, >> - USB_CFG_DEVICE_EN_MASK | USB_CFG_DEVICE_MUX_MASK, >> - USB_CFG_DEVICE_EN_MASK | >> - (port->id << USB_CFG_DEVICE_MUX_OFFSET)); >> + switch (type) { >> + case A380_UTMI: >> + /* >> + * A380 muxes between ports 0/2: >> + * - 0: Device mode on Port 2 >> + * - 1: Device mode on Port 0 >> + */ >> + if (port->id == 1) >> + return -EINVAL; >> + sel = !!(port->id == 0); >> + break; >> + case CP110_UTMI: >> + /* >> + * CP110 muxes between ports 0/1: >> + * - 0: Device mode on Port 0 >> + * - 1: Device mode on Port 1 >> + */ >> + sel = port->id; >> + break; >> + default: >> + return -EINVAL; >> + } >> + if (!IS_ERR(utmi->regs_usb)) { >> + reg = readl(utmi->regs_usb); >> + reg &= ~(USB_CFG_DEVICE_EN_MASK | USB_CFG_DEVICE_MUX_MASK); >> + reg |= USB_CFG_DEVICE_EN_MASK; >> + reg |= (sel << USB_CFG_DEVICE_MUX_OFFSET); >> + writel(reg, utmi->regs_usb); >> + } else >> + regmap_update_bits(utmi->syscon, SYSCON_USB_CFG_REG, >> + USB_CFG_DEVICE_EN_MASK | USB_CFG_DEVICE_MUX_MASK, >> + USB_CFG_DEVICE_EN_MASK | >> + (sel << USB_CFG_DEVICE_MUX_OFFSET)); >> } >> >> /* Set Test suspendm mode and enable Test UTMI select */ >> - reg = readl(PORT_REGS(port) + UTMI_CTRL_STATUS0_REG); >> + reg = readl(port->regs + UTMI_CTRL_STATUS0_REG); >> reg |= SUSPENDM | TEST_SEL; >> - writel(reg, PORT_REGS(port) + UTMI_CTRL_STATUS0_REG); >> + writel(reg, port->regs + UTMI_CTRL_STATUS0_REG); >> >> /* Wait for UTMI power down */ >> mdelay(1); >> @@ -226,16 +290,21 @@ static int mvebu_cp110_utmi_phy_power_on(struct phy *phy) >> mvebu_cp110_utmi_port_setup(port); >> >> /* Power UP UTMI PHY */ >> - regmap_set_bits(utmi->syscon, SYSCON_UTMI_CFG_REG(port->id), >> - UTMI_PHY_CFG_PU_MASK); >> + if (!IS_ERR(port->regs_cfg)) { >> + reg = readl(port->regs_cfg); >> + reg |= UTMI_PHY_CFG_PU_MASK; >> + writel(reg, port->regs_cfg); >> + } else >> + regmap_set_bits(utmi->syscon, SYSCON_UTMI_CFG_REG(port->id), >> + UTMI_PHY_CFG_PU_MASK); >> >> /* Disable Test UTMI select */ >> - reg = readl(PORT_REGS(port) + UTMI_CTRL_STATUS0_REG); >> + reg = readl(port->regs + UTMI_CTRL_STATUS0_REG); >> reg &= ~TEST_SEL; >> - writel(reg, PORT_REGS(port) + UTMI_CTRL_STATUS0_REG); >> + writel(reg, port->regs + UTMI_CTRL_STATUS0_REG); >> >> /* Wait for impedance calibration */ >> - ret = readl_poll_timeout(PORT_REGS(port) + UTMI_CAL_CTRL_REG, reg, >> + ret = readl_poll_timeout(port->regs + UTMI_CAL_CTRL_REG, reg, >> reg & IMPCAL_DONE, >> PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US); >> if (ret) { >> @@ -244,7 +313,7 @@ static int mvebu_cp110_utmi_phy_power_on(struct phy *phy) >> } >> >> /* Wait for PLL calibration */ >> - ret = readl_poll_timeout(PORT_REGS(port) + UTMI_CAL_CTRL_REG, reg, >> + ret = readl_poll_timeout(port->regs + UTMI_CAL_CTRL_REG, reg, >> reg & PLLCAL_DONE, >> PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US); >> if (ret) { >> @@ -253,7 +322,7 @@ static int mvebu_cp110_utmi_phy_power_on(struct phy *phy) >> } >> >> /* Wait for PLL ready */ >> - ret = readl_poll_timeout(PORT_REGS(port) + UTMI_PLL_CTRL_REG, reg, >> + ret = readl_poll_timeout(port->regs + UTMI_PLL_CTRL_REG, reg, >> reg & PLL_RDY, >> PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US); >> if (ret) { >> @@ -262,7 +331,12 @@ static int mvebu_cp110_utmi_phy_power_on(struct phy *phy) >> } >> >> /* PLL Power up */ >> - regmap_set_bits(utmi->syscon, SYSCON_USB_CFG_REG, USB_CFG_PLL_MASK); >> + if (!IS_ERR(utmi->regs_usb)) { >> + reg = readl(utmi->regs_usb); >> + reg |= USB_CFG_PLL_MASK; >> + writel(reg, utmi->regs_usb); >> + } else >> + regmap_set_bits(utmi->syscon, SYSCON_USB_CFG_REG, USB_CFG_PLL_MASK); >> >> return 0; >> } >> @@ -274,7 +348,8 @@ static const struct phy_ops mvebu_cp110_utmi_phy_ops = { >> }; >> >> static const struct of_device_id mvebu_cp110_utmi_of_match[] = { >> - { .compatible = "marvell,cp110-utmi-phy" }, >> + { .compatible = "marvell,a38x-utmi-phy", .data = (void *)A380_UTMI }, >> + { .compatible = "marvell,cp110-utmi-phy", .data = (void *)CP110_UTMI }, > Cast to void * are not required to be done Ack. > >> {}, >> }; >> MODULE_DEVICE_TABLE(of, mvebu_cp110_utmi_of_match); >> @@ -285,6 +360,10 @@ static int mvebu_cp110_utmi_phy_probe(struct platform_device *pdev) >> struct mvebu_cp110_utmi *utmi; >> struct phy_provider *provider; >> struct device_node *child; >> + void __iomem *regs_utmi; >> + void __iomem *regs_utmi_cfg; >> + const void *match; >> + enum mvebu_cp110_utmi_type type; >> u32 usb_devices = 0; >> >> utmi = devm_kzalloc(dev, sizeof(*utmi), GFP_KERNEL); >> @@ -293,18 +372,44 @@ static int mvebu_cp110_utmi_phy_probe(struct platform_device *pdev) >> >> utmi->dev = dev; >> >> + match = device_get_match_data(dev); >> + if (match) >> + type = (enum mvebu_cp110_utmi_type)(uintptr_t)match; >> + >> + /* Get UTMI memory region */ >> + regs_utmi = devm_platform_ioremap_resource(pdev, 0); >> + if (IS_ERR(regs_utmi)) { >> + dev_err(dev, "Failed to map utmi regs\n"); >> + return PTR_ERR(regs_utmi); >> + } >> + >> + /* Get usb config region */ >> + utmi->regs_usb = devm_platform_ioremap_resource_byname(pdev, "usb-cfg"); >> + if (IS_ERR(utmi->regs_usb) && PTR_ERR(utmi->regs_usb) != -EINVAL) { >> + dev_err(dev, "Failed to map usb config regs\n"); >> + return PTR_ERR(utmi->regs_usb); >> + } >> + >> + /* Get utmi config region */ >> + regs_utmi_cfg = devm_platform_ioremap_resource_byname(pdev, "utmi-cfg"); >> + if (IS_ERR(regs_utmi_cfg) && PTR_ERR(regs_utmi_cfg) != -EINVAL) { >> + dev_err(dev, "Failed to map usb config regs\n"); >> + return PTR_ERR(regs_utmi_cfg); >> + } >> + >> /* Get system controller region */ >> utmi->syscon = syscon_regmap_lookup_by_phandle(dev->of_node, >> "marvell,system-controller"); >> - if (IS_ERR(utmi->syscon)) { >> - dev_err(dev, "Missing UTMI system controller\n"); >> + if (IS_ERR(utmi->syscon) && PTR_ERR(utmi->syscon) != -ENODEV) { >> + dev_err(dev, "Failed to get system controller\n"); >> return PTR_ERR(utmi->syscon); >> } >> >> - /* Get UTMI memory region */ >> - utmi->regs = devm_platform_ioremap_resource(pdev, 0); >> - if (IS_ERR(utmi->regs)) >> - return PTR_ERR(utmi->regs); >> + if (IS_ERR(utmi->syscon) && >> + (IS_ERR(utmi->regs_usb) || IS_ERR(regs_utmi_cfg))) { >> + dev_err(dev, "Missing utmi system controller or config regs"); >> + return -EINVAL; >> + } >> >> for_each_available_child_of_node(dev->of_node, child) { >> struct mvebu_cp110_utmi_port *port; >> @@ -326,6 +431,24 @@ static int mvebu_cp110_utmi_phy_probe(struct platform_device *pdev) >> return -ENOMEM; >> } >> >> + utmi->ports[port_id] = port; >> + >> + /* Get port memory region */ >> + switch (type) { >> + case A380_UTMI: >> + port->regs = regs_utmi + port_id * 0x1000; >> + break; >> + case CP110_UTMI: >> + port->regs = regs_utmi + port_id * 0x2000; >> + break; >> + default: >> + return -EINVAL; >> + } >> + >> + /* assign utmi cfg reg */ >> + if (!IS_ERR(regs_utmi_cfg)) >> + port->regs_cfg = regs_utmi_cfg + port_id * 4; >> + >> port->dr_mode = of_usb_get_dr_mode_by_phy(child, -1); >> if ((port->dr_mode != USB_DR_MODE_HOST) && >> (port->dr_mode != USB_DR_MODE_PERIPHERAL)) { >> >> -- >> 2.43.0