uboot/drivers/usb/host/ehci-faraday.c
<<
>>
Prefs
   1/*
   2 * Faraday USB 2.0 EHCI Controller
   3 *
   4 * (C) Copyright 2010 Faraday Technology
   5 * Dante Su <dantesu@faraday-tech.com>
   6 *
   7 * SPDX-License-Identifier:     GPL-2.0+
   8 */
   9
  10#include <common.h>
  11#include <asm/io.h>
  12#include <usb.h>
  13#include <usb/fusbh200.h>
  14#include <usb/fotg210.h>
  15
  16#include "ehci.h"
  17
  18#ifndef CONFIG_USB_EHCI_BASE_LIST
  19#define CONFIG_USB_EHCI_BASE_LIST       { CONFIG_USB_EHCI_BASE }
  20#endif
  21
  22union ehci_faraday_regs {
  23        struct fusbh200_regs usb;
  24        struct fotg210_regs  otg;
  25};
  26
  27static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs)
  28{
  29        return !readl(&regs->usb.easstr);
  30}
  31
  32void faraday_ehci_set_usbmode(struct ehci_ctrl *ctrl)
  33{
  34        /* nothing needs to be done */
  35}
  36
  37int faraday_ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
  38{
  39        int spd, ret = PORTSC_PSPD_HS;
  40        union ehci_faraday_regs *regs;
  41
  42        ret = (void __iomem *)((ulong)ctrl->hcor - 0x10);
  43        if (ehci_is_fotg2xx(regs))
  44                spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
  45        else
  46                spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
  47
  48        switch (spd) {
  49        case 0:    /* full speed */
  50                ret = PORTSC_PSPD_FS;
  51                break;
  52        case 1:    /* low  speed */
  53                ret = PORTSC_PSPD_LS;
  54                break;
  55        case 2:    /* high speed */
  56                ret = PORTSC_PSPD_HS;
  57                break;
  58        default:
  59                printf("ehci-faraday: invalid device speed\n");
  60                break;
  61        }
  62
  63        return ret;
  64}
  65
  66uint32_t *faraday_ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
  67{
  68        /* Faraday EHCI has one and only one portsc register */
  69        if (port) {
  70                /* Printing the message would cause a scan failure! */
  71                debug("The request port(%d) is not configured\n", port);
  72                return NULL;
  73        }
  74
  75        /* Faraday EHCI PORTSC register offset is 0x20 from hcor */
  76        return (uint32_t *)((uint8_t *)ctrl->hcor + 0x20);
  77}
  78
  79static const struct ehci_ops faraday_ehci_ops = {
  80        .set_usb_mode           = faraday_ehci_set_usbmode,
  81        .get_port_speed         = faraday_ehci_get_port_speed,
  82        .get_portsc_register    = faraday_ehci_get_portsc_register,
  83};
  84
  85/*
  86 * Create the appropriate control structures to manage
  87 * a new EHCI host controller.
  88 */
  89int ehci_hcd_init(int index, enum usb_init_type init,
  90                struct ehci_hccr **ret_hccr, struct ehci_hcor **ret_hcor)
  91{
  92        struct ehci_hccr *hccr;
  93        struct ehci_hcor *hcor;
  94        union ehci_faraday_regs *regs;
  95        uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
  96
  97        if (index < 0 || index >= ARRAY_SIZE(base_list))
  98                return -1;
  99        ehci_set_controller_priv(index, NULL, &faraday_ehci_ops);
 100        regs = (void __iomem *)base_list[index];
 101        hccr = (struct ehci_hccr *)&regs->usb.hccr;
 102        hcor = (struct ehci_hcor *)&regs->usb.hcor;
 103
 104        if (ehci_is_fotg2xx(regs)) {
 105                /* A-device bus reset */
 106                /* ... Power off A-device */
 107                setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
 108                /* ... Drop vbus and bus traffic */
 109                clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
 110                mdelay(1);
 111                /* ... Power on A-device */
 112                clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
 113                /* ... Drive vbus and bus traffic */
 114                setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
 115                mdelay(1);
 116                /* Disable OTG & DEV interrupts, triggered at level-high */
 117                writel(IMR_IRQLH | IMR_OTG | IMR_DEV, &regs->otg.imr);
 118                /* Clear all interrupt status */
 119                writel(ISR_HOST | ISR_OTG | ISR_DEV, &regs->otg.isr);
 120        } else {
 121                /* Interrupt=level-high */
 122                setbits_le32(&regs->usb.bmcsr, BMCSR_IRQLH);
 123                /* VBUS on */
 124                clrbits_le32(&regs->usb.bmcsr, BMCSR_VBUS_OFF);
 125                /* Disable all interrupts */
 126                writel(0x00, &regs->usb.bmier);
 127                writel(0x1f, &regs->usb.bmisr);
 128        }
 129
 130        *ret_hccr = hccr;
 131        *ret_hcor = hcor;
 132
 133        return 0;
 134}
 135
 136/*
 137 * Destroy the appropriate control structures corresponding
 138 * the the EHCI host controller.
 139 */
 140int ehci_hcd_stop(int index)
 141{
 142        return 0;
 143}
 144