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