static void ulpi_set_trimmer(struct tegra_usb_phy *phy) { struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi; void __iomem *base = phy->regs; unsigned long val; val = ULPI_DATA_TRIMMER_SEL(config->data_trimmer); val |= ULPI_STPDIRNXT_TRIMMER_SEL(config->stpdirnxt_trimmer); val |= ULPI_DIR_TRIMMER_SEL(config->dir_trimmer); writel(val, base + ULPI_TIMING_CTRL_1); udelay(10); val |= ULPI_DATA_TRIMMER_LOAD; val |= ULPI_STPDIRNXT_TRIMMER_LOAD; val |= ULPI_DIR_TRIMMER_LOAD; writel(val, base + ULPI_TIMING_CTRL_1); }
/* set up the ULPI USB controller with the parameters provided */ static int init_ulpi_usb_controller(struct fdt_usb *config, struct usb_ctlr *usbctlr) { u32 val; int loop_count; struct ulpi_viewport ulpi_vp; /* set up ULPI reference clock on pllp_out4 */ clock_enable(PERIPH_ID_DEV2_OUT); clock_set_pllout(CLOCK_ID_PERIPH, PLL_OUT4, CONFIG_ULPI_REF_CLK); /* reset ULPI phy */ if (fdt_gpio_isvalid(&config->phy_reset_gpio)) { fdtdec_setup_gpio(&config->phy_reset_gpio); gpio_direction_output(config->phy_reset_gpio.gpio, 0); mdelay(5); gpio_set_value(config->phy_reset_gpio.gpio, 1); } /* Reset the usb controller */ clock_enable(config->periph_id); usbf_reset_controller(config, usbctlr); /* enable pinmux bypass */ setbits_le32(&usbctlr->ulpi_timing_ctrl_0, ULPI_CLKOUT_PINMUX_BYP | ULPI_OUTPUT_PINMUX_BYP); /* Select ULPI parallel interface */ clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK, PTS_ULPI << PTS_SHIFT); /* enable ULPI transceiver */ setbits_le32(&usbctlr->susp_ctrl, ULPI_PHY_ENB); /* configure ULPI transceiver timings */ val = 0; writel(val, &usbctlr->ulpi_timing_ctrl_1); val |= ULPI_DATA_TRIMMER_SEL(4); val |= ULPI_STPDIRNXT_TRIMMER_SEL(4); val |= ULPI_DIR_TRIMMER_SEL(4); writel(val, &usbctlr->ulpi_timing_ctrl_1); udelay(10); val |= ULPI_DATA_TRIMMER_LOAD; val |= ULPI_STPDIRNXT_TRIMMER_LOAD; val |= ULPI_DIR_TRIMMER_LOAD; writel(val, &usbctlr->ulpi_timing_ctrl_1); /* set up phy for host operation with external vbus supply */ ulpi_vp.port_num = 0; ulpi_vp.viewport_addr = (u32)&usbctlr->ulpi_viewport; if (ulpi_init(&ulpi_vp)) { printf("Tegra ULPI viewport init failed\n"); return -1; } ulpi_set_vbus(&ulpi_vp, 1, 1); ulpi_set_vbus_indicator(&ulpi_vp, 1, 1, 0); /* enable wakeup events */ setbits_le32(&usbctlr->port_sc1, WKCN | WKDS | WKOC); /* Enable and wait for the phy clock to become valid in 100 ms */ setbits_le32(&usbctlr->susp_ctrl, USB_SUSP_CLR); for (loop_count = 100000; loop_count != 0; loop_count--) { if (readl(&usbctlr->susp_ctrl) & USB_PHY_CLK_VALID) break; udelay(1); } if (!loop_count) return -1; clrbits_le32(&usbctlr->susp_ctrl, USB_SUSP_CLR); return 0; }
// ulpi phy power on static void ulpi_phy_power_on(void) { uint32_t val; uint32_t base = USBADDR2; udelay(1000); usb_reset(base); val = readl(base + ULPI_TIMING_CTRL_0); val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP; writel(val, base + ULPI_TIMING_CTRL_0); val = readl(base + USB_SUSP_CTRL); val |= ULPI_PHY_ENABLE; writel(val, base + USB_SUSP_CTRL); val = 0; writel(val, base + ULPI_TIMING_CTRL_1); val |= ULPI_DATA_TRIMMER_SEL(4); val |= ULPI_STPDIRNXT_TRIMMER_SEL(4); val |= ULPI_DIR_TRIMMER_SEL(4); writel(val, base + ULPI_TIMING_CTRL_1); udelay(10); val |= ULPI_DATA_TRIMMER_LOAD; val |= ULPI_STPDIRNXT_TRIMMER_LOAD; val |= ULPI_DIR_TRIMMER_LOAD; writel(val, base + ULPI_TIMING_CTRL_1); val = ULPI_WAKEUP | ULPI_RD_RW_WRITE | ULPI_PORT(0); writel(val, base + ULPI_VIEWPORT); if (wait_for_register(base + ULPI_VIEWPORT, ULPI_WAKEUP, 0, 1000)) { printf("%s: timeout waiting for ulpi phy wakeup\n", __func__); return; } /* Fix VbusInvalid due to floating VBUS */ val = ULPI_RUN | ULPI_RD_RW_WRITE | ULPI_PORT(0) | ULPI_ADDR(0x08) | ULPI_DATA_WR(0x40); writel(val, base + ULPI_VIEWPORT); if (wait_for_register(base + ULPI_VIEWPORT, ULPI_RUN, 0, 1000)) { printf("%s: timeout accessing ulpi phy\n", __func__); return; } val = ULPI_RUN | ULPI_RD_RW_WRITE | ULPI_PORT(0) | ULPI_ADDR(0x0B) | ULPI_DATA_WR(0x80); writel(val, base + ULPI_VIEWPORT); if (wait_for_register(base + ULPI_VIEWPORT, ULPI_RUN, 0, 1000)) { printf("%s: timeout accessing ulpi phy\n", __func__); return; } val = readl(base + USB_PORTSC1); val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN; writel(val, base + USB_PORTSC1); val = readl(base + USB_SUSP_CTRL); val |= USB_SUSP_CLR; writel(val, base + USB_SUSP_CTRL); udelay(100); val = readl(base + USB_SUSP_CTRL); val &= ~USB_SUSP_CLR; writel(val, base + USB_SUSP_CTRL); }