pll-setting-1 = <0x09400414>;
pll-setting-2 = <0x927E0000>;
pll-setting-3 = <0xac5f49e5>;
+ pll-setting-4 = <0xfe18>;
+ pll-setting-5 = <0xfff>;
+ pll-setting-6 = <0xc8000>;
+ pll-setting-7 = <0xe0004>;
+ pll-setting-8 = <0xe000c>;
};
usb3_phy_v2: usb3phy@ffe09080 {
if (core_if->srp_timer)
DWC_TIMER_FREE(core_if->srp_timer);
+ if (core_if->device_connect_timer)
+ DWC_TIMER_FREE(core_if->device_connect_timer);
+
DWC_FREE(core_if);
core_if = NULL;
}
intr_mask.b.enumdone = 1;
/* Disable Disconnect interrupt in Device mode */
intr_mask.b.disconnect = 0;
+ if (core_if->phy_interface == 0)
+ intr_mask.b.sofintr = 1;
if (!core_if->multiproc_int_enable) {
intr_mask.b.inepintr = 1;
int controller_type;
uint32_t phy_interface;
+
+ dwc_timer_t *device_connect_timer;
};
#ifdef DEBUG
struct delayed_work work;
- u32 host_plug;
} dwc_otg_device_t;
/*We must clear S3C24XX_EINTPEND external interrupt register
}
}
+static void sof_timeout(void *ptr)
+{
+#ifdef CONFIG_AMLOGIC_USB3PHY
+ dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
+
+ if (core_if->phy_interface == 0)
+ set_usb_phy_device_tuning(1, 1);
+#endif
+}
+
/**
* Tasklet
*
/* Initialize SRP timer */
core_if->srp_timer = DWC_TIMER_ALLOC("SRP TIMER", srp_timeout, core_if);
+ /* Initialize SRP timer */
+ core_if->device_connect_timer =
+ DWC_TIMER_ALLOC("DEVICE CONNECT TIMER", sof_timeout, core_if);
+
if (core_if->core_params->dev_out_nak) {
/**
* Initialize xfer timeout timer. Implemented for
void *req_handle);
extern void do_test_mode(void *data);
+#ifdef CONFIG_AMLOGIC_USB3PHY
+extern void set_usb_phy_device_tuning(int port, int default_val);
+#endif
#endif
#endif /* DWC_HOST_ONLY */
gintsts_data_t gintsts;
DWC_DEBUGPL(DBG_PCD, "SOF\n");
+ DWC_TIMER_CANCEL(core_if->device_connect_timer);
/* Clear interrupt */
gintsts.d32 = 0;
gintsts.b.sofintr = 1;
DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
+ DWC_TIMER_SCHEDULE(core_if->device_connect_timer, 10);
+
return 1;
}
core_if->otg_sts = 0;
DWC_PRINTF("USB RESET\n");
+
+ if (core_if->phy_interface == 0)
+ DWC_TIMER_SCHEDULE(core_if->device_connect_timer, 100);
+
#ifdef DWC_EN_ISOC
for (i = 1; i < 16; ++i) {
dwc_otg_pcd_ep_t *ep;
GET_CORE_IF(pcd)->core_global_regs;
uint8_t utmi16b, utmi8b;
int speed;
- dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n");
- if (core_if->controller_type == USB_OTG) {
- if (core_if->phy_interface == 0) {
- if (pcd->otg_dev->host_plug) {
- gintsts.d32 = 0;
- gintsts.b.enumdone = 1;
- DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
- core_global_regs->gintsts, gintsts.d32);
- DWC_DEBUGPL(DBG_PCD, "false speed emun\n");
- return 1;
- }
+
+#ifdef CONFIG_AMLOGIC_USB3PHY
+ if (GET_CORE_IF(pcd)->phy_interface == 0) {
+ speed = get_device_speed(GET_CORE_IF(pcd));
+ if (speed != USB_SPEED_HIGH) {
+ gintsts.d32 = 0;
+ gintsts.b.enumdone = 1;
+ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
+ core_global_regs->gintsts, gintsts.d32);
+ DWC_DEBUGPL(DBG_PCD, "false speed emun\n");
+ return 1;
}
+
+ set_usb_phy_device_tuning(1, 0);
}
+#endif
if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_2_60a) {
utmi16b = 6;
if (value) {
DWC_DEBUGPL(DBG_PCDV, "start usb device\n");
- otg_dev->host_plug = 0;
dwc_otg_enable_global_interrupts(otg_dev->core_if);
if (otg_dev->core_if->phy_interface == 0)
dwc_otg_enable_device_interrupts(otg_dev->core_if);
otg_dev->pcd->core_if->pcd_cb->start(otg_dev->pcd);
} else {
- otg_dev->host_plug = 1;
DWC_DEBUGPL(DBG_PCDV, "stop usb device\n");
dwc_otg_disable_global_interrupts(otg_dev->core_if);
#include <linux/amlogic/usb-v2.h>
#include "phy-aml-new-usb-v2.h"
+struct amlogic_usb_v2 *g_phy2_v2;
+
+void set_usb_phy_host_tuning(int port, int default_val)
+{
+ void __iomem *phy_reg_base;
+
+ if (!g_phy2_v2)
+ return;
+ if (port > g_phy2_v2->portnum)
+ return;
+ if (default_val == g_phy2_v2->phy_cfg_state[port])
+ return;
+
+ phy_reg_base = g_phy2_v2->phy_cfg[port];
+ dev_info(g_phy2_v2->dev, "---%s port(%d) tuning for host cf(%pf)--\n",
+ default_val ? "Recovery" : "Set",
+ port, __builtin_return_address(0));
+ if (!default_val) {
+ writel(g_phy2_v2->pll_setting[3], phy_reg_base + 0x50);
+ writel(g_phy2_v2->pll_setting[4], phy_reg_base + 0x10);
+ writel(g_phy2_v2->pll_setting[6], phy_reg_base + 0x38);
+ writel(g_phy2_v2->pll_setting[5], phy_reg_base + 0x34);
+ } else {
+ writel(0, phy_reg_base + 0x38);
+ writel(g_phy2_v2->pll_setting[5], phy_reg_base + 0x34);
+ }
+ g_phy2_v2->phy_cfg_state[port] = default_val;
+}
+
+void set_usb_phy_device_tuning(int port, int default_val)
+{
+ void __iomem *phy_reg_base;
+
+ if (!g_phy2_v2)
+ return;
+ if (port > g_phy2_v2->portnum)
+ return;
+ if (default_val == g_phy2_v2->phy_cfg_state[port])
+ return;
+
+ phy_reg_base = g_phy2_v2->phy_cfg[port];
+ dev_info(g_phy2_v2->dev, "---%s port(%d) tuning for device cf(%pf)--\n",
+ default_val ? "Recovery" : "Set",
+ port, __builtin_return_address(0));
+ if (!default_val) {
+ writel(g_phy2_v2->pll_setting[3], phy_reg_base + 0x50);
+ writel(g_phy2_v2->pll_setting[4], phy_reg_base + 0x10);
+ writel(g_phy2_v2->pll_setting[7], phy_reg_base + 0x38);
+ writel(g_phy2_v2->pll_setting[5], phy_reg_base + 0x34);
+ } else {
+ writel(0, phy_reg_base + 0x38);
+ writel(g_phy2_v2->pll_setting[5], phy_reg_base + 0x34);
+ }
+ g_phy2_v2->phy_cfg_state[port] = default_val;
+}
+
+
void set_usb_pll(struct amlogic_usb_v2 *phy, void __iomem *reg)
{
/* TO DO set usb PLL */
const void *prop;
int i = 0;
u32 retval;
- u32 pll_setting[3];
+ u32 pll_setting[8];
prop = of_get_property(dev->of_node, "portnum", NULL);
if (prop)
if (retval < 0)
return -EINVAL;
+ retval = of_property_read_u32(dev->of_node,
+ "pll-setting-4", &(pll_setting[3]));
+ if (retval < 0)
+ return -EINVAL;
+
+ retval = of_property_read_u32(dev->of_node,
+ "pll-setting-5", &(pll_setting[4]));
+ if (retval < 0)
+ return -EINVAL;
+
+ retval = of_property_read_u32(dev->of_node,
+ "pll-setting-6", &(pll_setting[5]));
+ if (retval < 0)
+ return -EINVAL;
+
+ retval = of_property_read_u32(dev->of_node,
+ "pll-setting-7", &(pll_setting[6]));
+ if (retval < 0)
+ return -EINVAL;
+
+ retval = of_property_read_u32(dev->of_node,
+ "pll-setting-8", &(pll_setting[7]));
+ if (retval < 0)
+ return -EINVAL;
+
dev_info(&pdev->dev, "USB2 phy probe:phy_mem:0x%lx, iomap phy_base:0x%lx\n",
(unsigned long)phy_mem->start, (unsigned long)phy_base);
phy->pll_setting[0] = pll_setting[0];
phy->pll_setting[1] = pll_setting[1];
phy->pll_setting[2] = pll_setting[2];
+ phy->pll_setting[3] = pll_setting[3];
+ phy->pll_setting[4] = pll_setting[4];
+ phy->pll_setting[5] = pll_setting[5];
+ phy->pll_setting[6] = pll_setting[6];
+ phy->pll_setting[7] = pll_setting[7];
phy->suspend_flag = 0;
- for (i = 0; i < portnum; i++)
+ for (i = 0; i < portnum; i++) {
phy->phy_cfg[i] = phy_cfg_base[i];
+ /* set port default tuning state */
+ phy->phy_cfg_state[i] = 1;
+ }
usb_add_phy_dev(&phy->phy);
pm_runtime_enable(phy->dev);
+ g_phy2_v2 = phy;
+
return 0;
}
port_status = readl(addr);
xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n",
port_change_bit, wIndex, port_status);
+#ifdef CONFIG_AMLOGIC_USB
+ if (DEV_HIGHSPEED(port_status) &&
+ (wValue == USB_PORT_FEAT_C_RESET))
+ set_usb_phy_host_tuning(wIndex, 0);
+#endif
}
static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
* bits are still set. When an event occurs, switch over to
* polling to avoid losing status changes.
*/
+#ifdef CONFIG_AMLOGIC_USB
+ if (!(temp & PORT_CONNECT) || !(temp & PORT_PE))
+ set_usb_phy_host_tuning(faked_port_index, 1);
+#endif
xhci_dbg(xhci, "%s: starting port polling.\n", __func__);
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
spin_unlock(&xhci->lock);
int xhci_test_single_step(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id,
unsigned int ep_index, int testflag);
+extern void set_usb_phy_host_tuning(int port, int default_val);
#endif
#endif /* __LINUX_XHCI_HCD_H */
void __iomem *phy3_cfg_r4;
void __iomem *phy3_cfg_r5;
void __iomem *usb2_phy_cfg;
- u32 pll_setting[3];
+ u32 pll_setting[8];
+ int phy_cfg_state[4];
/* Set VBus Power though GPIO */
int vbus_power_pin;
int vbus_power_pin_work_mask;