[U-Boot] [PATCH v7 4/4] Add USB support for Efika

Marek Vasut marek.vasut.n900 at gmail.com
Wed Sep 28 02:43:02 CEST 2011


> This commit adds USB support for EfikaMX and EfikaSB.
> 
> Signed-off-by: Jana Rapava <fermata7 at gmail.com>
> Signed-off-by: Marek Vasut <marek.vasut at gmail.com>
> Cc: Remy Bohmer <linux at bohmer.net>
> Cc: Stefano Babic <sbabic at denx.de>
> ---
> Changes for v2:
>       - changed to proper patch
> Changes for v3:
>       - merged other USB patches from u-boot-pxa/efikasb
>       - offset-based access changed to struct-based access
>       - use {clrset,clr,set}bits_le32() calls
>       - CodingStyle and naming cleanup
> Changes for v4:
>         - split into patchset
>         - CodingStyle and naming cleanup
>         - remove endless loops
>         - silence compiler warnings
> Changes for v5:
>             - change order of arguments in ulpi* functions
>             - change type of reg argument
>             - rename offset macro
> Changes for v6:
>               - rebase on top of u-boot-imx/next
>               - cleanup of CodingStyle and comments
>               - use macro machine_is_efikasb()
>               - introduce header file efika.h
> Changes for v7:
>     - add proper header to efika.h
>     - include efika.h into efikamx.c
>     - check return values from ulpi_wait()
> 
>   board/efikamx/Makefile           |       3 +
>   board/efikamx/efika.h             |     30 ++++
>   board/efikamx/efikamx-usb.c |   397
> +++++++++++++++++++++++++++++++++++++++++++ board/efikamx/efikamx.c       
> |       3 + include/configs/efikamx.h     |     16 ++
>   5 files changed, 449 insertions(+), 0 deletions(-)
>   create mode 100644 board/efikamx/efika.h
>   create mode 100644 board/efikamx/efikamx-usb.c
> 
Dear Jana Rapava,

[...]

> +u32 ulpi_wait(struct usb_ehci *ehci, u32 ulpi_bit)
> +{
> +    int timeout = ULPI_TIMEOUT;
> +    u32 tmp;
> +
> +    /* Wait for the ulpi_bit to become zero. */
> +    while (--timeout) {
> +        tmp = readl(&ehci->ulpi_viewpoint);
> +        if (!(tmp & ulpi_bit))
> +            break;
> +        WATCHDOG_RESET();
> +    }
> +
> +    if (!timeout)
> +        return 0;
> +    else
> +        return tmp;

The logic here seems bogus, if the register is zero, this function returns zero either way.

> +}
> +
> +void ulpi_write(struct usb_ehci *ehci, u32 reg, u32 value)
> +{
> +    if (!(readl(&ehci->ulpi_viewpoint) & ULPI_SS)) {
> +        writel(ULPI_WU, &ehci->ulpi_viewpoint);
> +        if (!ulpi_wait(ehci, ULPI_WU))
> +            printf("ULPI wakeup timed out\n");
> +    }
> +
> +    writel(ULPI_RWRUN | ULPI_RWCTRL |
> +        reg << ULPI_ADDR_SHIFT | ulpi_write_mask(value),
> +        &ehci->ulpi_viewpoint);
> +    if (!ulpi_wait(ehci, ULPI_RWRUN))
> +        printf("ULPI write timed out\n");
> +}
> +
> +u32 ulpi_read(struct usb_ehci *ehci, u32 reg)
> +{
> +    u32 tmp;
> +    if (!(readl(&ehci->ulpi_viewpoint) & ULPI_SS)) {
> +        writel(ULPI_WU, &ehci->ulpi_viewpoint);
> +        if (!ulpi_wait(ehci, ULPI_WU))
> +            printf("ULPI wakeup timed out\n");
> +    }
> +
> +    writel(ULPI_RWRUN | reg << ULPI_ADDR_SHIFT, &ehci->ulpi_viewpoint);
> +    tmp = ulpi_wait(ehci, ULPI_RWRUN);
> +    if (!tmp)
> +        printf("ULPI read timed out\n");
> +    return ulpi_read_mask(tmp);
> +}
> +
> +void ulpi_init(struct usb_ehci *ehci, struct mxc_ulpi_regs *ulpi)
> +{
> +    u32 tmp = 0;
> +    int reg, i;
> +
> +    /* get ID from ULPI immediate registers */
> +    for (reg = ULPI_ID_REGS_COUNT - 1; reg >= 0; reg--)
> +        tmp |= ulpi_read(ehci, (u32)reg) << (reg * 8);

Are you ignoring my comment and picking only some of them? Is the cast here necessary?

> +    /* split into vendor and product ID */
> +    debug("Found ULPI TX, ID %04x:%04x\n", tmp >> 16, tmp & 0xffff);
> +
> +    /* ULPI check integrity */
> +    for (i = 0; i < 2; i++) {
> +        ulpi_write(ehci, (u32)&ulpi->scratch_write,
> +            ULPI_TEST_VALUE << i);
> +        tmp = ulpi_read(ehci, (u32)&ulpi->scratch_write);
> +
> +        if (tmp != (ULPI_TEST_VALUE << i)) {
> +            printf("ULPI integrity check failed\n");
> +            return;
> +        }
> +    }
> +
> +    /* ULPI set flags */
> +    ulpi_write(ehci, (u32)&ulpi->otg_ctrl_write,
> +        ULPI_OTG_EXT_VBUS_IND |
> +        ULPI_OTG_DM_PULLDOWN | ULPI_OTG_DP_PULLDOWN);
> +    ulpi_write(ehci, (u32)&ulpi->function_ctrl_write,
> +        ULPI_FC_XCVR_SELECT | ULPI_FC_OPMODE_NORMAL |
> +        ULPI_FC_SUSPENDM_PWRED);
> +    ulpi_write(ehci, (u32)&ulpi->iface_ctrl_write, 0);
> +    ulpi_write(ehci, (u32)&ulpi->otg_ctrl_set,
> +        ULPI_OTG_DRV_VBUS | ULPI_OTG_DRV_VBUS_EXT);
> +
> +    /*
> +     * NOTE: This violates USB specification, but otherwise, USB on Efika
> +     * doesn't charge VBUS and as a result, USB doesn't work.
> +     */
> +    ulpi_write(ehci, (u32)&ulpi->otg_ctrl_set, ULPI_OTG_CHRG_VBUS);
> +}
> +
> +/*
> + * Solve the VBUS reset problem on Efika
> + * by setting the CHRG_VBUS bit in the reset.
> + */
> +void ehci_fixup(uint32_t *status_reg, uint32_t *reg_ref)
> +{
> +    struct usb_ehci *ehci = (struct usb_ehci *)(OTG_BASE_ADDR +
> +        MX51_REGISTER_LAYOUT_LENGTH);
> +    struct mxc_ulpi_regs *ulpi = (struct mxc_ulpi_regs *)0;
> +
> +    u32 tmp = ulpi_read(ehci, (u32)&ulpi->otg_ctrl_write);
> +    tmp |= ULPI_OTG_CHRG_VBUS;
> +    ulpi_write(ehci, (u32)&ulpi->otg_ctrl_write, tmp);
> +
> +    /* USB 2.0 specification say 50 ms resets on root. */

Where can I read about this please?

> +    wait_ms(50);
> +
> +    /* Now terminate the reset. */
> +    *reg_ref = ehci_readl(status_reg);
> +    *reg_ref |= EHCI_PS_PE;
> +}
> +
> +void ehci0_init(struct usb_ehci *ehci)
> +{
> +    writel(MX51_16BIT_UTMI, &ehci->portsc);
> +}
> +
> +void ehci1_init(struct usb_ehci *ehci, struct mxc_ulpi_regs *ulpi)
> +{
> +    mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT2);
> +    mxc_iomux_set_pad(MX51_PIN_USBH1_STP, PAD_CTL_DRV_HIGH |
> +                PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST);
> +    gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_USBH1_STP), 0);
> +    udelay(1000);
> +    gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_USBH1_STP), 1);
> +    udelay(1000);
> +
> +    mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT0);
> +    mxc_iomux_set_pad(MX51_PIN_USBH1_STP, USB_PAD_CONFIG);
> +    udelay(10000);
> +
> +    clrbits_le32(&ehci->usbcmd, MX51_ITC_IMMEDIATE_MASK);
> +    udelay(10000);
> +
> +    writel(MX51_ULPI_MODE_MASK, &ehci->portsc);
> +    udelay(10000);
> +
> +    ulpi_init(ehci, ulpi);
> +}
> +
> +

remove newline

> +void ehci2_init(struct usb_ehci *ehci, struct mxc_ulpi_regs *ulpi)
> +{
> +    mxc_request_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_ALT1);
> +    mxc_iomux_set_pad(MX51_PIN_EIM_A26, PAD_CTL_DRV_HIGH |
> +                PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST);
> +    gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A26), 0);
> +    udelay(1000);
> +    gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A26), 1);
> +    udelay(1000);
> +
> +    mxc_request_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_ALT2);
> +    mxc_iomux_set_pad(MX51_PIN_EIM_A26, USB_PAD_CONFIG);
> +
> +    writel(MX51_ULPI_MODE_MASK, &ehci->portsc);
> +    udelay(10000);
> +
> +    ulpi_init(ehci, ulpi);
> +}
> +
> +int ehci_hcd_init(void)
> +{
> +    struct usb_ehci *ehci;
> +    struct mx5_usb_control_regs *mx5_usb_control_regs;
> +    struct mxc_ulpi_regs *ulpi;
> +
> +    mx5_usb_control_regs = (struct mx5_usb_control_regs *)(OTG_BASE_ADDR +
> +         MX5_CTRL_REGS_OFFSET);
> +    control_regs_setup(mx5_usb_control_regs);
> +    ulpi = (struct mxc_ulpi_regs *)0;
> +
> +    /* Init EHCI core */
> +    ehci = (struct usb_ehci *)(OTG_BASE_ADDR +
> +        (MX51_REGISTER_LAYOUT_LENGTH * CONFIG_MXC_USB_PORT));
> +    hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
> +    hcor = (struct ehci_hcor *)((uint32_t) hccr +
> +            HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
> +    setbits_le32(&ehci->usbmode, CM_HOST);
> +    setbits_le32(&ehci->control, USB_EN);
> +   
> +    /* Init iMX51 EHCI */
> +    efika_usb_phy_reset();
> +    efika_usb_hub_reset();
> +    efika_usb_enable_devices();
> +
> +    switch (CONFIG_MXC_USB_PORT) {
> +    case 0:
> +        ehci0_init(ehci);
> +        break;
> +    case 1:
> +        ehci1_init(ehci, ulpi);
> +        break;
> +    case 2:
> +        if (machine_is_efikasb()) {
> +            ehci2_init(ehci, ulpi);
> +            break;
> +        }

the break should be past the if, also you can drop the braces then.

> +    };
> +
> +    /* EfikaMX USB has issues ... */
> +    udelay(10000);
> +
> +    return 0;
> +}
> +
> +int ehci_hcd_stop(void)
> +{
> +    return 0;
> +}



More information about the U-Boot mailing list