From: deadman96385 Date: Thu, 22 Jul 2021 00:22:32 +0000 (-0500) Subject: drivers: amlogic: Import Google's OTG changes X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=2e548b8719973c86ffe5ee77bd3b0e751c2ee12d;p=GitHub%2FLineageOS%2FG12%2Fandroid_kernel_amlogic_linux-4.9.git drivers: amlogic: Import Google's OTG changes Change-Id: I79dfd43e7fae1f79cac2e45e5bf081b2d16240db --- diff --git a/drivers/amlogic/usb/phy/phy-aml-new-usb-v2.c b/drivers/amlogic/usb/phy/phy-aml-new-usb-v2.c old mode 100644 new mode 100755 index 60674dd49040..eaa2256a2bd8 --- a/drivers/amlogic/usb/phy/phy-aml-new-usb-v2.c +++ b/drivers/amlogic/usb/phy/phy-aml-new-usb-v2.c @@ -75,3 +75,28 @@ int amlogic_new_usbphy_reset_phycfg_v2(struct amlogic_usb_v2 *phy, int cnt) return 0; } EXPORT_SYMBOL_GPL(amlogic_new_usbphy_reset_phycfg_v2); + +int amlogic_reset_phycfg_otgport(struct amlogic_usb_v2 *phy, int cnt) +{ + u32 val; + u32 temp = 0; + + temp = temp | (1 << cnt); + + /* set usb phy to low power mode */ + val = readl((void __iomem *) + ((unsigned long)phy->reset_regs + (0x21 * 4 - 0x8))); + writel((val & (~temp)), (void __iomem *) + ((unsigned long)phy->reset_regs + (0x21 * 4 - 0x8))); + + udelay(100); + + val = readl((void __iomem *) + ((unsigned long)phy->reset_regs + (0x21 * 4 - 0x8))); + writel((val | temp), (void __iomem *) + ((unsigned long)phy->reset_regs + (0x21 * 4 - 0x8))); + + return 0; +} +EXPORT_SYMBOL_GPL(amlogic_reset_phycfg_otgport); + diff --git a/drivers/amlogic/usb/phy/phy-aml-new-usb-v2.h b/drivers/amlogic/usb/phy/phy-aml-new-usb-v2.h old mode 100644 new mode 100755 index dd0784362105..aeff54920934 --- a/drivers/amlogic/usb/phy/phy-aml-new-usb-v2.h +++ b/drivers/amlogic/usb/phy/phy-aml-new-usb-v2.h @@ -24,3 +24,4 @@ extern int amlogic_new_usbphy_reset_v2(struct amlogic_usb_v2 *phy); extern int amlogic_new_usbphy_reset_phycfg_v2 (struct amlogic_usb_v2 *phy, int cnt); void set_usb_phy_host_tuning(int port, int default_val); +int amlogic_reset_phycfg_otgport(struct amlogic_usb_v2 *phy, int cnt); diff --git a/drivers/amlogic/usb/phy/phy-aml-new-usb2-v2.c b/drivers/amlogic/usb/phy/phy-aml-new-usb2-v2.c old mode 100644 new mode 100755 index 44b33d737aa3..2f13620af828 --- a/drivers/amlogic/usb/phy/phy-aml-new-usb2-v2.c +++ b/drivers/amlogic/usb/phy/phy-aml-new-usb2-v2.c @@ -129,6 +129,13 @@ void set_usb_phy_host_low_reset(int port) } +void usb2_reset_otgport_phy(void) +{ + if (!g_phy2_v2) + return; + printk(KERN_ERR"%s\n", __func__); + amlogic_reset_phycfg_otgport(g_phy2_v2, 17); +} void set_usb_pll(struct amlogic_usb_v2 *phy, void __iomem *reg) { @@ -145,7 +152,7 @@ void set_usb_pll(struct amlogic_usb_v2 *phy, void __iomem *reg) /* PHY Tune */ if (g_phy2_v2) { if (g_phy2_v2->phy_version) { - /**tl1 g12b revB don't need set 0x10 ,0x38 and 0x34**/ + /**tl1 g12b revB don't need set 0x10 ,0x38**/ writel(phy->pll_setting[3], reg + 0x50); writel(0x2a, reg + 0x54); diff --git a/drivers/amlogic/usb/phy/phy-aml-new-usb3-v2.c b/drivers/amlogic/usb/phy/phy-aml-new-usb3-v2.c index 871e12de0ae7..7a14556fbe06 100644 --- a/drivers/amlogic/usb/phy/phy-aml-new-usb3-v2.c +++ b/drivers/amlogic/usb/phy/phy-aml-new-usb3-v2.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,10 @@ struct usb_aml_regs_v2 usb_new_aml_regs_v2; struct amlogic_usb_v2 *g_phy_v2; +struct usb_role_switch *host_mode_sw; +u32 typec_host_mode; +u32 idpin_host_mode; +u32 force_host_mode; static void power_switch_to_pcie(struct amlogic_usb_v2 *phy); @@ -110,22 +115,33 @@ static void amlogic_new_usb3phy_shutdown(struct usb_phy *x) phy->suspend_flag = 1; } +static void update_host_mode(struct amlogic_usb_v2 *phy) +{ + unsigned long reg_addr = ((unsigned long)phy->usb2_phy_cfg); + + if (idpin_host_mode || typec_host_mode || force_host_mode) { + dev_info(phy->dev, "host mode"); + amlogic_new_set_vbus_power(phy, 1); + aml_new_usb_notifier_call(0); + set_mode(reg_addr, HOST_MODE); + } else { + dev_info(phy->dev, "device mode"); + set_mode(reg_addr, DEVICE_MODE); + aml_new_usb_notifier_call(1); + amlogic_new_set_vbus_power(phy, 0); + } +} + void aml_new_usb_v2_init(void) { union usb_r5_v2 r5 = {.d32 = 0}; - unsigned long reg_addr; if (!g_phy_v2) return; - reg_addr = (unsigned long)g_phy_v2->usb2_phy_cfg; - r5.d32 = readl(usb_new_aml_regs_v2.usb_r_v2[5]); - if (r5.b.iddig_curr == 0) { - amlogic_new_set_vbus_power(g_phy_v2, 1); - aml_new_usb_notifier_call(0); - set_mode(reg_addr, HOST_MODE); - } + idpin_host_mode = (r5.b.iddig_curr == 0) ? 1 : 0; + update_host_mode(g_phy_v2); } EXPORT_SYMBOL(aml_new_usb_v2_init); @@ -435,23 +451,53 @@ static void set_mode(unsigned long reg_addr, int mode) udelay(500); } +static enum usb_role get_host_mode(struct device *dev) +{ + return (force_host_mode || typec_host_mode || idpin_host_mode) + ? USB_ROLE_HOST + : USB_ROLE_DEVICE; +} + +static int set_host_mode(struct device *dev, enum usb_role role) +{ + if (typec_host_mode || idpin_host_mode) { + dev_err(dev, "host mode was locked by typec or idpin"); + return -EPERM; + } + + force_host_mode = (role == USB_ROLE_HOST ? 1 : 0); + + if (g_phy_v2) + update_host_mode(g_phy_v2); + + return 0; +} + +static const struct usb_role_switch_desc host_mode_sw_desc = { + .get = get_host_mode, + .set = set_host_mode, + .allow_userspace_control = true, +}; + +void amlogic_typec_set_mode(int mode) +{ + if (!g_phy_v2) + return; + + typec_host_mode = (mode == HOST_MODE) ? 1 : 0; + update_host_mode(g_phy_v2); +} +EXPORT_SYMBOL(amlogic_typec_set_mode); + static void amlogic_gxl_work(struct work_struct *work) { struct amlogic_usb_v2 *phy = container_of(work, struct amlogic_usb_v2, work.work); union usb_r5_v2 r5 = {.d32 = 0}; - unsigned long reg_addr = ((unsigned long)phy->usb2_phy_cfg); r5.d32 = readl(usb_new_aml_regs_v2.usb_r_v2[5]); - if (r5.b.iddig_curr == 0) { - amlogic_new_set_vbus_power(phy, 1); - aml_new_usb_notifier_call(0); - set_mode(reg_addr, HOST_MODE); - } else { - set_mode(reg_addr, DEVICE_MODE); - aml_new_usb_notifier_call(1); - amlogic_new_set_vbus_power(phy, 0); - } + idpin_host_mode = (r5.b.iddig_curr == 0) ? 1 : 0; + update_host_mode(phy); r5.b.usb_iddig_irq = 0; writel(r5.d32, usb_new_aml_regs_v2.usb_r_v2[5]); } @@ -737,11 +783,20 @@ static int amlogic_new_usb3_v2_probe(struct platform_device *pdev) g_phy_v2 = phy; + host_mode_sw = usb_role_switch_register(dev, &host_mode_sw_desc); + if (IS_ERR(host_mode_sw)) { + dev_err(dev, "failed to register usb role switch\n"); + host_mode_sw = NULL; + } + return 0; } static int amlogic_new_usb3_remove(struct platform_device *pdev) { + if (host_mode_sw) + usb_role_switch_unregister(host_mode_sw); + return 0; } diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 4b12b6da3fab..779358c08ab3 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -689,6 +689,7 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) int ret, i; u8 buf[ETH_ALEN] = {0}, chipcode = 0; u32 phyid; + u16 psc; struct asix_common_private *priv; usbnet_get_endpoints(dev,intf); @@ -737,6 +738,11 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) return ret; } + asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x18, 0, 2, &psc, 0); + le16_to_cpus(&psc); + asix_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | + (psc & 0x7f00), 0, 0, NULL, 0); + /* Read PHYID register *AFTER* the PHY was reset properly */ phyid = asix_get_phyid(dev); netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 0b5fd1499ac0..b79f6f6ba586 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -91,6 +91,8 @@ MODULE_PARM_DESC (msg_level, "Override default message level"); /*-------------------------------------------------------------------------*/ +extern void usb2_reset_otgport_phy(void); + /* handles CDC Ethernet and many other network "bulk data" interfaces */ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) { @@ -187,18 +189,28 @@ static void intr_complete (struct urb *urb) struct usbnet *dev = urb->context; int status = urb->status; + if (status) + printk("### (%s) status: %d ###", __func__, status); + switch (status) { /* success */ case 0: dev->driver_info->status(dev, urb); break; + case -ECONNRESET: + usb2_reset_otgport_phy(); + return; + /* software-driven interface shutdown */ case -ENOENT: /* urb killed */ case -ESHUTDOWN: /* hardware gone */ netif_dbg(dev, ifdown, dev->net, "intr shutdown, code %d\n", status); return; + case -EPROTO: + usb2_reset_otgport_phy(); + return; /* NOTE: not throttling like RX/TX, since this endpoint * already polls infrequently @@ -598,6 +610,9 @@ static void rx_complete (struct urb *urb) state = rx_done; entry->urb = NULL; + if (urb_status) + printk("### (%s) urb_status: %d ###", __func__, urb_status); + switch (urb_status) { /* success */ case 0: @@ -615,6 +630,7 @@ static void rx_complete (struct urb *urb) /* software-driven interface shutdown */ case -ECONNRESET: /* async unlink */ + usb2_reset_otgport_phy(); case -ESHUTDOWN: /* hardware gone */ netif_dbg(dev, ifdown, dev->net, "rx shutdown, code %d\n", urb_status); @@ -625,6 +641,7 @@ static void rx_complete (struct urb *urb) * so we still recover when the fault isn't a hub_wq delay. */ case -EPROTO: + usb2_reset_otgport_phy(); case -ETIME: case -EILSEQ: dev->net->stats.rx_errors++; @@ -1228,6 +1245,7 @@ static void tx_complete (struct urb *urb) dev->net->stats.tx_packets += entry->packets; dev->net->stats.tx_bytes += entry->length; } else { + printk("### (%s) urb->status: %d ###", __func__, urb->status); dev->net->stats.tx_errors++; switch (urb->status) { @@ -1237,7 +1255,8 @@ static void tx_complete (struct urb *urb) /* software-driven interface shutdown */ case -ECONNRESET: // async unlink - case -ESHUTDOWN: // hardware gone + usb2_reset_otgport_phy(); + case -ESHUTDOWN: // hardware gone break; /* like rx, tx gets controller i/o faults during hub_wq diff --git a/include/linux/usb.h b/include/linux/usb.h old mode 100644 new mode 100755 index 425683cc6781..7172b6501a47 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1942,6 +1942,7 @@ extern void usb_led_activity(enum usb_led_event ev); #else static inline void usb_led_activity(enum usb_led_event ev) {} #endif +void usb2_reset_otgport_phy(void); #endif /* __KERNEL__ */