1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12#include <platsupport/io.h> 13#include <pci/pci.h> 14 15#include <usb/usb_host.h> 16#include "../../ehci/ehci.h" 17#include "../../services.h" 18 19#define USBLEGSUP 0x0 20#define USBLEGSUP_OS BIT(24) 21#define USBLEGSUP_BIOS BIT(16) 22#define USBLEGSUP_NEXT_SHF BIT(8) 23#define USBLEGSUP_NEXT_MASK 0xFF 24#define USBLEGSUP_ID_SHF BIT(0) 25#define USBLEGSUP_ID_MASK 0xFF 26 27#define USBLEGCTLSTS 0x4 28#define USBLEGCTLSTS_BAR BIT(31) 29#define USBLEGCTLSTS_PCICMD BIT(30) 30#define USBLEGCTLSTS_OSOC BIT(29) 31#define USBLEGCTLSTS_AA BIT(21) 32#define USBLEGCTLSTS_HSE BIT(20) 33#define USBLEGCTLSTS_FLR BIT(19) 34#define USBLEGCTLSTS_PCD BIT(18) 35#define USBLEGCTLSTS_ERR BIT(17) 36#define USBLEGCTLSTS_COMP BIT(16) 37#define USBLEGCTLSTS_BAR_EN BIT(15) 38#define USBLEGCTLSTS_PCICMD_EN BIT(14) 39#define USBLEGCTLSTS_OSOC_EN BIT(13) 40#define USBLEGCTLSTS_AA_EN BIT(5) 41#define USBLEGCTLSTS_HSE_EN BIT(4) 42#define USBLEGCTLSTS_FLR_EN BIT(3) 43#define USBLEGCTLSTS_PC_EN BIT(2) 44#define USBLEGCTLSTS_ERR_EN BIT(1) 45#define USBLEGCTLSTS_SIM_EN BIT(0) 46 47/* Host vendor ID and device ID */ 48#define USB_HOST1_VID 0x8086 49#define USB_HOST1_DID 0x1E26 50#define USB_HOST2_VID 0x8086 51#define USB_HOST2_DID 0x1E2D 52 53/* 54 * TODO: Should get these numbers from IOAPIC tables. Remove them once we have a 55 * proper parser for the IOAPIC tables. 56 */ 57#define USB_HOST1_IRQ 23 58#define USB_HOST2_IRQ 16 59 60static int _irq_line; 61 62static uintptr_t ehci_pci_init(uint16_t vid, uint16_t did, 63 ps_io_ops_t *io_ops) 64{ 65 int err; 66 libpci_device_t *dev; 67 volatile struct ehci_host_cap *cap_regs; 68 uint32_t val; 69 uint8_t reg; 70 71 /* Find the device */ 72 libpci_scan(io_ops->io_port_ops); 73 dev = libpci_find_device(vid, did); 74 if (dev) { 75 libpci_read_ioconfig(&dev->cfg, dev->bus, dev->dev, dev->fun); 76 /* Map device memory */ 77 cap_regs = (volatile struct echi_host_cap*)MAP_DEVICE(io_ops, 78 dev->cfg.base_addr[0], 79 dev->cfg.base_addr_size[0]); 80 if (!cap_regs) { 81 ZF_LOGF("Invalid Registers\n"); 82 } 83 _irq_line = dev->interrupt_line; 84 } else { 85 ZF_LOGF("EHCI: Host device not found!\n"); 86 } 87 88 /* Check EHCI Extend Capabilities Pointer(Section 2.2.4) */ 89 reg = EHCI_HCC_EECP(cap_regs->hccparams); 90 if (reg) { 91 reg += USBLEGSUP; 92 /* Take the ownership from BIOS */ 93 val = libpci_read_reg32(dev->bus, dev->dev, dev->fun, reg); 94 val |= USBLEGSUP_OS; 95 libpci_write_reg32(dev->bus, dev->dev, dev->fun, reg, val); 96 do { 97 val = libpci_read_reg32(dev->bus, dev->dev, 98 dev->fun, reg); 99 } while (val & USBLEGSUP_BIOS); 100 101 if ((val >> USBLEGSUP_NEXT_SHF) & USBLEGSUP_NEXT_MASK) { 102 ZF_LOGW("EHCI: Warning! More Capability Registers.\n"); 103 } 104 } 105 106 return (uintptr_t)cap_regs; 107} 108 109int 110usb_host_init(enum usb_host_id id, ps_io_ops_t* io_ops, ps_mutex_ops_t *sync, 111 usb_host_t* hdev) 112{ 113 int err; 114 uint16_t vid, did; 115 uintptr_t usb_regs; 116 117 if (id < 0 || id > USB_NHOSTS) { 118 return -1; 119 } 120 121 if (!io_ops || !hdev) { 122 ZF_LOGF("Invalid arguments\n"); 123 } 124 125 hdev->id = id; 126 hdev->dman = &io_ops->dma_manager; 127 hdev->sync = sync; 128 129 switch (id) { 130 case USB_HOST1: 131 vid = USB_HOST1_VID; 132 did = USB_HOST1_DID; 133 break; 134 case USB_HOST2: 135 vid = USB_HOST2_VID; 136 did = USB_HOST2_DID; 137 break; 138 default: 139 ZF_LOGF("Invalid host\n"); 140 break; 141 } 142 143 /* Check device mappings */ 144 usb_regs = ehci_pci_init(vid, did, io_ops); 145 if (!usb_regs) { 146 return -1; 147 } 148 149 err = ehci_host_init(hdev, usb_regs, NULL); 150 151 return err; 152} 153 154const int* 155usb_host_irqs(usb_host_t* host, int* nirqs) 156{ 157 if (host->id < 0 || host->id > USB_NHOSTS) { 158 return NULL; 159 } 160 161 if (nirqs) { 162 *nirqs = 1; 163 } 164 165#ifdef CONFIG_IRQ_IOAPIC 166 switch (host->id) { 167 case USB_HOST1: 168 _irq_line = USB_HOST1_IRQ; 169 break; 170 case USB_HOST2: 171 _irq_line = USB_HOST2_IRQ; 172 break; 173 default: 174 ZF_LOGF("Invalid host\n"); 175 break; 176 } 177#endif 178 179 host->irqs = &_irq_line; 180 return host->irqs; 181} 182 183