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