X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=drivers%2Fusb%2Fdwc3%2Fdwc3-rockchip-inno.c;h=79537cc69a3353e63688882ca55f30996059a005;hb=ec42359f2660cfd0afa81c4e38b9e3695a1828a0;hp=5c907b97d6a661fb107f4eb2a83d7505a378bc99;hpb=0cbdc8c1daf2bd9a42e653f4d85ad70c549b7265;p=firefly-linux-kernel-4.4.55.git diff --git a/drivers/usb/dwc3/dwc3-rockchip-inno.c b/drivers/usb/dwc3/dwc3-rockchip-inno.c index 5c907b97d6a6..79537cc69a33 100644 --- a/drivers/usb/dwc3/dwc3-rockchip-inno.c +++ b/drivers/usb/dwc3/dwc3-rockchip-inno.c @@ -21,28 +21,227 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include +#include #include "core.h" #include "../host/xhci.h" +#define XHCI_TSTCTRL_MASK (0xf << 28) struct dwc3_rockchip { struct device *dev; struct clk **clks; int num_clocks; struct dwc3 *dwc; + struct dentry *root; struct usb_phy *phy; struct notifier_block u3phy_nb; struct work_struct u3_work; struct mutex lock; }; +static int dwc3_rockchip_host_testmode_show(struct seq_file *s, void *unused) +{ + struct dwc3_rockchip *rockchip = s->private; + struct dwc3 *dwc = rockchip->dwc; + struct usb_hcd *hcd = dev_get_drvdata(&dwc->xhci->dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + __le32 __iomem **port_array; + u32 reg; + + if (rockchip->dwc->dr_mode == USB_DR_MODE_PERIPHERAL) { + dev_warn(rockchip->dev, "USB HOST not support!\n"); + return 0; + } + + if (hcd->state == HC_STATE_HALT) { + dev_warn(rockchip->dev, "HOST is halted!\n"); + return 0; + } + + port_array = xhci->usb2_ports; + reg = readl(port_array[0] + 1); + reg &= XHCI_TSTCTRL_MASK; + reg >>= 28; + + switch (reg) { + case 0: + seq_puts(s, "U2: no test\n"); + break; + case TEST_J: + seq_puts(s, "U2: test_j\n"); + break; + case TEST_K: + seq_puts(s, "U2: test_k\n"); + break; + case TEST_SE0_NAK: + seq_puts(s, "U2: test_se0_nak\n"); + break; + case TEST_PACKET: + seq_puts(s, "U2: test_packet\n"); + break; + case TEST_FORCE_EN: + seq_puts(s, "U2: test_force_enable\n"); + break; + default: + seq_printf(s, "U2: UNKNOWN %d\n", reg); + } + + port_array = xhci->usb3_ports; + reg = readl(port_array[0]); + reg &= PORT_PLS_MASK; + if (reg == USB_SS_PORT_LS_COMP_MOD) + seq_puts(s, "U3: compliance mode\n"); + else + seq_printf(s, "U3: UNKNOWN %d\n", reg >> 5); + + return 0; +} + +static int dwc3_rockchip_host_testmode_open(struct inode *inode, + struct file *file) +{ + return single_open(file, dwc3_rockchip_host_testmode_show, + inode->i_private); +} + +/** + * dwc3_rockchip_set_test_mode - Enables USB2/USB3 HOST Test Modes + * @rockchip: pointer to our context structure + * @mode: the mode to set (U2: J, K SE0 NAK, Test_packet, + * Force Enable; U3: Compliance mode) + * + * This function will return 0 on success or -EINVAL if wrong Test + * Selector is passed. + */ +static int dwc3_rockchip_set_test_mode(struct dwc3_rockchip *rockchip, + u32 mode) +{ + struct dwc3 *dwc = rockchip->dwc; + struct usb_hcd *hcd = dev_get_drvdata(&dwc->xhci->dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + __le32 __iomem **port_array; + int ret; + u32 reg; + + if (hcd->state == HC_STATE_HALT) { + dev_err(rockchip->dev, "HOST is halted!\n"); + return -EINVAL; + } + + switch (mode) { + case TEST_J: + case TEST_K: + case TEST_SE0_NAK: + case TEST_PACKET: + case TEST_FORCE_EN: + port_array = xhci->usb2_ports; + reg = readl(port_array[0] + 1); + reg &= ~XHCI_TSTCTRL_MASK; + reg |= mode << 28; + writel(reg, port_array[0] + 1); + break; + case USB_SS_PORT_LS_COMP_MOD: + /* + * Enable Inno U3 PHY to toggle CP test pattern + * before set XHCI controller enter compliance mode. + */ + ret = phy_cp_test(dwc->usb3_generic_phy); + if (ret) { + dev_err(rockchip->dev, "phy cp test fail!\n"); + return ret; + } + + port_array = xhci->usb3_ports; + xhci_set_link_state(xhci, port_array, 0, mode); + break; + default: + return -EINVAL; + } + + dev_info(rockchip->dev, "set USB HOST test mode successfully!\n"); + + return 0; +} + +static ssize_t dwc3_rockchip_host_testmode_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct dwc3_rockchip *rockchip = s->private; + u32 testmode = 0; + char buf[32]; + + if (rockchip->dwc->dr_mode == USB_DR_MODE_PERIPHERAL) { + dev_warn(rockchip->dev, "USB HOST not support!\n"); + return -EINVAL; + } + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "test_j", 6)) { + testmode = TEST_J; + } else if (!strncmp(buf, "test_k", 6)) { + testmode = TEST_K; + } else if (!strncmp(buf, "test_se0_nak", 12)) { + testmode = TEST_SE0_NAK; + } else if (!strncmp(buf, "test_packet", 11)) { + testmode = TEST_PACKET; + } else if (!strncmp(buf, "test_force_enable", 17)) { + testmode = TEST_FORCE_EN; + } else if (!strncmp(buf, "test_u3", 7)) { + testmode = USB_SS_PORT_LS_COMP_MOD; + } else { + dev_warn(rockchip->dev, "Test cmd not support!\n"); + return -EINVAL; + } + + dwc3_rockchip_set_test_mode(rockchip, testmode); + + return count; +} + +static const struct file_operations dwc3_host_testmode_fops = { + .open = dwc3_rockchip_host_testmode_open, + .write = dwc3_rockchip_host_testmode_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void dwc3_rockchip_debugfs_init(struct dwc3_rockchip *rockchip) +{ + struct dentry *root; + struct dentry *file; + + root = debugfs_create_dir(dev_name(rockchip->dev), NULL); + if (IS_ERR_OR_NULL(root)) { + if (!root) + dev_err(rockchip->dev, "Can't create debugfs root\n"); + return; + } + rockchip->root = root; + + if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) || + IS_ENABLED(CONFIG_USB_DWC3_HOST)) { + file = debugfs_create_file("host_testmode", S_IRUSR | S_IWUSR, + root, rockchip, + &dwc3_host_testmode_fops); + if (!file) + dev_dbg(rockchip->dev, "Can't create debugfs host_testmode\n"); + } +} + static int u3phy_disconnect_det_notifier(struct notifier_block *nb, unsigned long event, void *p) { @@ -183,6 +382,8 @@ static int dwc3_rockchip_probe(struct platform_device *pdev) usb_register_notifier(rockchip->phy, &rockchip->u3phy_nb); } + dwc3_rockchip_debugfs_init(rockchip); + return 0; err2: @@ -209,6 +410,8 @@ static int dwc3_rockchip_remove(struct platform_device *pdev) of_platform_depopulate(dev); + debugfs_remove_recursive(rockchip->root); + pm_runtime_put_sync(dev); pm_runtime_disable(dev);