/* * Enable or disable ULPI PHY reset from USB Controller. * This does not actually reset the phy, but just controls * whether USB controller can or cannot reset ULPI PHY.
*/
reg = readl(priv_data->regs + XLNX_USB_PHY_RST_EN);
if (mask)
reg &= ~XLNX_PHY_RST_MASK; else
reg |= XLNX_PHY_RST_MASK;
/* * This routes the USB DMA traffic to go through FPD path instead * of reaching DDR directly. This traffic routing is needed to * make SMMU and CCI work with USB DMA.
*/ if (of_dma_is_coherent(dev->of_node) || device_iommu_mapped(dev)) {
reg = readl(priv_data->regs + coherency_offset);
reg |= XLNX_USB_TRAFFIC_ROUTE_FPD;
writel(reg, priv_data->regs + coherency_offset);
}
}
priv_data->usb3_phy = devm_phy_optional_get(dev, "usb3-phy"); if (IS_ERR(priv_data->usb3_phy)) {
ret = PTR_ERR(priv_data->usb3_phy);
dev_err_probe(dev, ret, "failed to get USB3 PHY\n"); goto err;
}
/* * The following core resets are not required unless a USB3 PHY * is used, and the subsequent register settings are not required * unless a core reset is performed (they should be set properly * by the first-stage boot loader, but may be reverted by a core * reset). They may also break the configuration if USB3 is actually * in use but the usb3-phy entry is missing from the device tree. * Therefore, skip these operations in this case.
*/ if (!priv_data->usb3_phy) { /* Deselect the PIPE Clock Select bit in FPD PIPE Clock register */
writel(PIPE_CLK_DESELECT, priv_data->regs + XLNX_USB_FPD_PIPE_CLK); goto skip_usb3_phy;
}
crst = devm_reset_control_get_exclusive(dev, "usb_crst"); if (IS_ERR(crst)) {
ret = PTR_ERR(crst);
dev_err_probe(dev, ret, "failed to get core reset signal\n"); goto err;
}
hibrst = devm_reset_control_get_exclusive(dev, "usb_hibrst"); if (IS_ERR(hibrst)) {
ret = PTR_ERR(hibrst);
dev_err_probe(dev, ret, "failed to get hibernation reset signal\n"); goto err;
}
apbrst = devm_reset_control_get_exclusive(dev, "usb_apbrst"); if (IS_ERR(apbrst)) {
ret = PTR_ERR(apbrst);
dev_err_probe(dev, ret, "failed to get APB reset signal\n"); goto err;
}
ret = reset_control_assert(crst); if (ret < 0) {
dev_err(dev, "Failed to assert core reset\n"); goto err;
}
ret = reset_control_assert(hibrst); if (ret < 0) {
dev_err(dev, "Failed to assert hibernation reset\n"); goto err;
}
ret = reset_control_assert(apbrst); if (ret < 0) {
dev_err(dev, "Failed to assert APB reset\n"); goto err;
}
ret = phy_init(priv_data->usb3_phy); if (ret < 0) {
phy_exit(priv_data->usb3_phy); goto err;
}
ret = reset_control_deassert(apbrst); if (ret < 0) {
dev_err(dev, "Failed to release APB reset\n"); goto err;
}
/* Set PIPE Power Present signal in FPD Power Present Register*/
writel(FPD_POWER_PRSNT_OPTION, priv_data->regs + XLNX_USB_FPD_POWER_PRSNT);
/* Set the PIPE Clock Select bit in FPD PIPE Clock register */
writel(PIPE_CLK_SELECT, priv_data->regs + XLNX_USB_FPD_PIPE_CLK);
ret = reset_control_deassert(crst); if (ret < 0) {
dev_err(dev, "Failed to release core reset\n"); goto err;
}
ret = reset_control_deassert(hibrst); if (ret < 0) {
dev_err(dev, "Failed to release hibernation reset\n"); goto err;
}
ret = phy_power_on(priv_data->usb3_phy); if (ret < 0) {
phy_exit(priv_data->usb3_phy); goto err;
}
skip_usb3_phy: /* ulpi reset via gpio-modepin or gpio-framework driver */
reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(reset_gpio)) { return dev_err_probe(dev, PTR_ERR(reset_gpio), "Failed to request reset GPIO\n");
}
if (reset_gpio) {
usleep_range(5000, 10000);
gpiod_set_value_cansleep(reset_gpio, 0);
usleep_range(5000, 10000);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.