drivers: amlogic: Import Google's OTG changes
authordeadman96385 <seanhoyt963@gmail.com>
Thu, 22 Jul 2021 00:22:32 +0000 (19:22 -0500)
committerNolen Johnson <johnsonnolen@gmail.com>
Tue, 27 Jul 2021 14:50:17 +0000 (10:50 -0400)
Change-Id: I79dfd43e7fae1f79cac2e45e5bf081b2d16240db

drivers/amlogic/usb/phy/phy-aml-new-usb-v2.c [changed mode: 0644->0755]
drivers/amlogic/usb/phy/phy-aml-new-usb-v2.h [changed mode: 0644->0755]
drivers/amlogic/usb/phy/phy-aml-new-usb2-v2.c [changed mode: 0644->0755]
drivers/amlogic/usb/phy/phy-aml-new-usb3-v2.c
drivers/net/usb/asix_devices.c
drivers/net/usb/usbnet.c
include/linux/usb.h [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index 60674dd..eaa2256
@@ -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);
+
old mode 100644 (file)
new mode 100755 (executable)
index dd07843..aeff549
@@ -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);
old mode 100644 (file)
new mode 100755 (executable)
index 44b33d7..2f13620
@@ -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);
 
index 871e12de0ae700c8e716c43af2920bcf8ac5c820..7a14556fbe0671917e697905fc732c088396c479 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/delay.h>
 #include <linux/usb/phy.h>
+#include <linux/usb/role.h>
 #include <linux/amlogic/usb-v2.h>
 #include <linux/amlogic/aml_gpio_consumer.h>
 #include <linux/workqueue.h>
 
 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;
 }
 
index 393fd3ed6b94cd836ebb9e1e9eb688f47213ff6b..bff18278775d8b1b72984ae885db7ce65ae5c3ce 100644 (file)
@@ -689,6 +689,7 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
        int ret, i;
        u8 buf[ETH_ALEN], 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);
index 4ab82b998a0f02bfc00bc96f2c275cedfdd354f2..536c8ce8dff536feebd01c3a57093c08c437b0ac 100644 (file)
@@ -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)
 {
@@ -182,18 +184,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
@@ -589,6 +601,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:
@@ -606,6 +621,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);
@@ -616,6 +632,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++;
@@ -1219,6 +1236,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) {
@@ -1228,7 +1246,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
old mode 100644 (file)
new mode 100755 (executable)
index d308652..212e365
@@ -1905,6 +1905,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__ */