From 2251e0a1639e1eb38928906b2130ea601ca0ddd8 Mon Sep 17 00:00:00 2001 From: Mike Qin Date: Fri, 22 Jul 2016 19:14:08 +0800 Subject: [PATCH] zynq: add usb support for Zedboard Signed-off-by: Mike Qin --- .../100-dt-sync-dts-files-with-kernel.patch | 17 ++ ...latform-driver-support-for-ulpi-phys.patch | 146 ++++++++++++++++++ .../111-use-usb2-phy-for-zynq-platform.patch | 13 ++ ...dd-support-for-vbus-control-with-phy.patch | 62 ++++++++ 4 files changed, 238 insertions(+) create mode 100644 target/linux/zynq/patches/100-dt-sync-dts-files-with-kernel.patch create mode 100644 target/linux/zynq/patches/110-add-platform-driver-support-for-ulpi-phys.patch create mode 100644 target/linux/zynq/patches/111-use-usb2-phy-for-zynq-platform.patch create mode 100644 target/linux/zynq/patches/112-add-support-for-vbus-control-with-phy.patch diff --git a/target/linux/zynq/patches/100-dt-sync-dts-files-with-kernel.patch b/target/linux/zynq/patches/100-dt-sync-dts-files-with-kernel.patch new file mode 100644 index 0000000000..47959bd1db --- /dev/null +++ b/target/linux/zynq/patches/100-dt-sync-dts-files-with-kernel.patch @@ -0,0 +1,17 @@ +--- a/arch/arm/boot/dts/zynq-zed.dts ++++ b/arch/arm/boot/dts/zynq-zed.dts +@@ -32,10 +32,12 @@ + bootargs = "earlyprintk"; + stdout-path = "serial0:115200n8"; + }; +- + usb_phy0: phy0 { +- compatible = "usb-nop-xceiv"; ++ compatible = "ulpi-phy"; + #phy-cells = <0>; ++ reg = <0xe0002000 0x1000>; ++ view-port = <0x0170>; ++ drv-vbus; + }; + }; + diff --git a/target/linux/zynq/patches/110-add-platform-driver-support-for-ulpi-phys.patch b/target/linux/zynq/patches/110-add-platform-driver-support-for-ulpi-phys.patch new file mode 100644 index 0000000000..b2eb6aa5b7 --- /dev/null +++ b/target/linux/zynq/patches/110-add-platform-driver-support-for-ulpi-phys.patch @@ -0,0 +1,146 @@ +--- a/drivers/usb/phy/Kconfig ++++ b/drivers/usb/phy/Kconfig +@@ -202,6 +202,7 @@ config USB_RCAR_PHY + config USB_ULPI + bool "Generic ULPI Transceiver Driver" + depends on ARM || ARM64 ++ depends on USB_PHY + select USB_ULPI_VIEWPORT + help + Enable this to support ULPI connected USB OTG transceivers which +--- a/drivers/usb/phy/phy-ulpi.c ++++ b/drivers/usb/phy/phy-ulpi.c +@@ -26,9 +26,16 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++#include ++#include + #include + #include + #include ++#include + + + struct ulpi_info { +@@ -52,6 +59,13 @@ static struct ulpi_info ulpi_ids[] = { + ULPI_INFO(ULPI_ID(0x0451, 0x1507), "TI TUSB1210"), + }; + ++struct ulpi_phy { ++ struct usb_phy *usb_phy; ++ void __iomem *regs; ++ unsigned int vp_offset; ++ unsigned int flags; ++}; ++ + static int ulpi_set_otg_flags(struct usb_phy *phy) + { + unsigned int flags = ULPI_OTG_CTRL_DP_PULLDOWN | +@@ -253,6 +267,23 @@ static int ulpi_set_vbus(struct usb_otg + return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL); + } + ++static int usbphy_set_vbus(struct usb_phy *phy, int on) ++{ ++ unsigned int flags = usb_phy_io_read(phy, ULPI_OTG_CTRL); ++ ++ flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT); ++ ++ if (on) { ++ if (phy->flags & ULPI_OTG_DRVVBUS) ++ flags |= ULPI_OTG_CTRL_DRVVBUS; ++ ++ if (phy->flags & ULPI_OTG_DRVVBUS_EXT) ++ flags |= ULPI_OTG_CTRL_DRVVBUS_EXT; ++ } ++ ++ return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL); ++} ++ + struct usb_phy * + otg_ulpi_create(struct usb_phy_io_ops *ops, + unsigned int flags) +@@ -275,6 +306,7 @@ otg_ulpi_create(struct usb_phy_io_ops *o + phy->io_ops = ops; + phy->otg = otg; + phy->init = ulpi_init; ++ phy->set_vbus = usbphy_set_vbus; + + otg->usb_phy = phy; + otg->set_host = ulpi_set_host; +@@ -284,3 +316,70 @@ otg_ulpi_create(struct usb_phy_io_ops *o + } + EXPORT_SYMBOL_GPL(otg_ulpi_create); + ++static int ulpi_phy_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct resource *res; ++ struct ulpi_phy *uphy; ++ bool flag; ++ int ret; ++ ++ uphy = devm_kzalloc(&pdev->dev, sizeof(*uphy), GFP_KERNEL); ++ if (!uphy) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ uphy->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); ++ if (IS_ERR(uphy->regs)) ++ return PTR_ERR(uphy->regs); ++ ++ ret = of_property_read_u32(np, "view-port", &uphy->vp_offset); ++ if (IS_ERR(uphy->regs)) { ++ dev_err(&pdev->dev, "view-port register not specified\n"); ++ return PTR_ERR(uphy->regs); ++ } ++ ++ flag = of_property_read_bool(np, "drv-vbus"); ++ if (flag) ++ uphy->flags |= ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT; ++ ++ uphy->usb_phy = otg_ulpi_create(&ulpi_viewport_access_ops, uphy->flags); ++ ++ uphy->usb_phy->dev = &pdev->dev; ++ ++ uphy->usb_phy->io_priv = uphy->regs + uphy->vp_offset; ++ ++ ret = usb_add_phy_dev(uphy->usb_phy); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int ulpi_phy_remove(struct platform_device *pdev) ++{ ++ struct ulpi_phy *uphy = platform_get_drvdata(pdev); ++ ++ usb_remove_phy(uphy->usb_phy); ++ ++ return 0; ++} ++ ++static const struct of_device_id ulpi_phy_table[] = { ++ { .compatible = "ulpi-phy" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, ulpi_phy_table); ++ ++static struct platform_driver ulpi_phy_driver = { ++ .probe = ulpi_phy_probe, ++ .remove = ulpi_phy_remove, ++ .driver = { ++ .name = "ulpi-phy", ++ .of_match_table = ulpi_phy_table, ++ }, ++}; ++module_platform_driver(ulpi_phy_driver); ++ ++MODULE_DESCRIPTION("ULPI PHY driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/zynq/patches/111-use-usb2-phy-for-zynq-platform.patch b/target/linux/zynq/patches/111-use-usb2-phy-for-zynq-platform.patch new file mode 100644 index 0000000000..356dd0f872 --- /dev/null +++ b/target/linux/zynq/patches/111-use-usb2-phy-for-zynq-platform.patch @@ -0,0 +1,13 @@ +--- a/drivers/usb/chipidea/ci_hdrc_usb2.c ++++ b/drivers/usb/chipidea/ci_hdrc_usb2.c +@@ -59,6 +59,10 @@ static int ci_hdrc_usb2_probe(struct pla + if (match && match->data) { + /* struct copy */ + *ci_pdata = *(struct ci_hdrc_platform_data *)match->data; ++ ci_pdata->usb_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", ++ 0); ++ if (IS_ERR(ci_pdata->usb_phy)) ++ return PTR_ERR(ci_pdata->usb_phy); + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); diff --git a/target/linux/zynq/patches/112-add-support-for-vbus-control-with-phy.patch b/target/linux/zynq/patches/112-add-support-for-vbus-control-with-phy.patch new file mode 100644 index 0000000000..5dca10032a --- /dev/null +++ b/target/linux/zynq/patches/112-add-support-for-vbus-control-with-phy.patch @@ -0,0 +1,62 @@ +--- a/drivers/usb/chipidea/ci_hdrc_usb2.c ++++ b/drivers/usb/chipidea/ci_hdrc_usb2.c +@@ -33,6 +33,7 @@ static const struct ci_hdrc_platform_dat + + static struct ci_hdrc_platform_data ci_zynq_pdata = { + .capoffset = DEF_CAPOFFSET, ++ .flags = CI_HDRC_PHY_VBUS_CONTROL, + }; + + static const struct of_device_id ci_hdrc_usb2_of_match[] = { +--- a/drivers/usb/chipidea/host.c ++++ b/drivers/usb/chipidea/host.c +@@ -66,6 +66,14 @@ static int ehci_ci_portpower(struct usb_ + } + } + ++ if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL && ++ ci->usb_phy && ci->usb_phy->set_vbus) { ++ if (enable) ++ ci->usb_phy->set_vbus(ci->usb_phy, 1); ++ else ++ ci->usb_phy->set_vbus(ci->usb_phy, 0); ++ } ++ + if (enable && (ci->platdata->phy_mode == USBPHY_INTERFACE_MODE_HSIC)) { + /* + * Marvell 28nm HSIC PHY requires forcing the port to HS mode. +--- a/drivers/usb/chipidea/otg_fsm.c ++++ b/drivers/usb/chipidea/otg_fsm.c +@@ -456,6 +456,11 @@ static void ci_otg_drv_vbus(struct otg_f + return; + } + } ++ ++ if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL && ++ ci->usb_phy && ci->usb_phy->set_vbus) ++ ci->usb_phy->set_vbus(ci->usb_phy, 1); ++ + /* Disable data pulse irq */ + hw_write_otgsc(ci, OTGSC_DPIE, 0); + +@@ -465,6 +470,10 @@ static void ci_otg_drv_vbus(struct otg_f + if (ci->platdata->reg_vbus) + regulator_disable(ci->platdata->reg_vbus); + ++ if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL && ++ ci->usb_phy && ci->usb_phy->set_vbus) ++ ci->usb_phy->set_vbus(ci->usb_phy, 0); ++ + fsm->a_bus_drop = 1; + fsm->a_bus_req = 0; + } +--- a/include/linux/usb/chipidea.h ++++ b/include/linux/usb/chipidea.h +@@ -55,6 +55,7 @@ struct ci_hdrc_platform_data { + #define CI_HDRC_OVERRIDE_AHB_BURST BIT(9) + #define CI_HDRC_OVERRIDE_TX_BURST BIT(10) + #define CI_HDRC_OVERRIDE_RX_BURST BIT(11) ++#define CI_HDRC_PHY_VBUS_CONTROL BIT(12) + enum usb_dr_mode dr_mode; + #define CI_HDRC_CONTROLLER_RESET_EVENT 0 + #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 -- 2.35.1