uboot/drivers/usb/host/ehci-mpc512x.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2010, Damien Dusha, <d.dusha@gmail.com>
   3 *
   4 * (C) Copyright 2009, Value Team S.p.A.
   5 * Francesco Rendine, <francesco.rendine@valueteam.com>
   6 *
   7 * (C) Copyright 2009 Freescale Semiconductor, Inc.
   8 *
   9 * (C) Copyright 2008, Excito Elektronik i Sk=E5ne AB
  10 *
  11 * Author: Tor Krill tor@excito.com
  12 *
  13 * SPDX-License-Identifier:     GPL-2.0+
  14 */
  15
  16#include <common.h>
  17#include <pci.h>
  18#include <usb.h>
  19#include <asm/io.h>
  20#include <usb/ehci-ci.h>
  21
  22#include "ehci.h"
  23
  24static void fsl_setup_phy(volatile struct ehci_hcor *);
  25static void fsl_platform_set_host_mode(volatile struct usb_ehci *ehci);
  26static int reset_usb_controller(volatile struct usb_ehci *ehci);
  27static void usb_platform_dr_init(volatile struct usb_ehci *ehci);
  28
  29/*
  30 * Initialize SOC FSL EHCI Controller
  31 *
  32 * This code is derived from EHCI FSL USB Linux driver for MPC5121
  33 *
  34 */
  35int ehci_hcd_init(int index, enum usb_init_type init,
  36                struct ehci_hccr **hccr, struct ehci_hcor **hcor)
  37{
  38        volatile struct usb_ehci *ehci;
  39
  40        /* Hook the memory mapped registers for EHCI-Controller */
  41        ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB1_ADDR;
  42        *hccr = (struct ehci_hccr *)((uint32_t)&(ehci->caplength));
  43        *hcor = (struct ehci_hcor *)((uint32_t) *hccr +
  44                                HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
  45
  46        /* configure interface for UTMI_WIDE */
  47        usb_platform_dr_init(ehci);
  48
  49        /* Init Phy USB0 to UTMI+ */
  50        fsl_setup_phy(*hcor);
  51
  52        /* Set to host mode */
  53        fsl_platform_set_host_mode(ehci);
  54
  55        /*
  56         * Setting the burst size seems to be required to prevent the
  57         * USB from hanging when communicating with certain USB Mass
  58         * storage devices. This was determined by analysing the
  59         * EHCI registers under Linux vs U-Boot and burstsize was the
  60         * major non-interrupt related difference between the two
  61         * implementations.
  62         *
  63         * Some USB sticks behave better than others. In particular,
  64         * the following USB stick is especially problematic:
  65         * 0930:6545 Toshiba Corp
  66         *
  67         * The burstsize is set here to match the Linux implementation.
  68         */
  69        out_be32(&ehci->burstsize, FSL_EHCI_TXPBURST(8) |
  70                                   FSL_EHCI_RXPBURST(8));
  71
  72        return 0;
  73}
  74
  75/*
  76 * Destroy the appropriate control structures corresponding
  77 * the the EHCI host controller.
  78 */
  79int ehci_hcd_stop(int index)
  80{
  81        volatile struct usb_ehci *ehci;
  82        int exit_status = 0;
  83
  84        /* Reset the USB controller */
  85        ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB1_ADDR;
  86        exit_status = reset_usb_controller(ehci);
  87
  88        return exit_status;
  89}
  90
  91static int reset_usb_controller(volatile struct usb_ehci *ehci)
  92{
  93        unsigned int i;
  94
  95        /* Command a reset of the USB Controller */
  96        out_be32(&(ehci->usbcmd), CMD_RESET);
  97
  98        /* Wait for the reset process to finish */
  99        for (i = 65535 ; i > 0 ; i--) {
 100                /*
 101                 * The host will set this bit to zero once the
 102                 * reset process is complete
 103                 */
 104                if ((in_be32(&(ehci->usbcmd)) & CMD_RESET) == 0)
 105                        return 0;
 106        }
 107
 108        /* Hub did not reset in time */
 109        return -1;
 110}
 111
 112static void fsl_setup_phy(volatile struct ehci_hcor *hcor)
 113{
 114        uint32_t portsc;
 115
 116        portsc  = ehci_readl(&hcor->or_portsc[0]);
 117        portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
 118
 119        /* Enable the phy mode to UTMI Wide */
 120        portsc |= PORT_PTS_PTW;
 121        portsc |= PORT_PTS_UTMI;
 122
 123        ehci_writel(&hcor->or_portsc[0], portsc);
 124}
 125
 126static void fsl_platform_set_host_mode(volatile struct usb_ehci *ehci)
 127{
 128        uint32_t temp;
 129
 130        temp  = in_le32(&ehci->usbmode);
 131        temp |= CM_HOST | ES_BE;
 132        out_le32(&ehci->usbmode, temp);
 133}
 134
 135static void usb_platform_dr_init(volatile struct usb_ehci *ehci)
 136{
 137        /* Configure interface for UTMI_WIDE */
 138        out_be32(&ehci->isiphyctrl, PHYCTRL_PHYE | PHYCTRL_PXE);
 139        out_be32(&ehci->usbgenctrl, GC_PPP | GC_PFP );
 140}
 141