174c68741SSarah Sharp /* 274c68741SSarah Sharp * xHCI host controller driver 374c68741SSarah Sharp * 474c68741SSarah Sharp * Copyright (C) 2008 Intel Corp. 574c68741SSarah Sharp * 674c68741SSarah Sharp * Author: Sarah Sharp 774c68741SSarah Sharp * Some code borrowed from the Linux EHCI driver. 874c68741SSarah Sharp * 974c68741SSarah Sharp * This program is free software; you can redistribute it and/or modify 1074c68741SSarah Sharp * it under the terms of the GNU General Public License version 2 as 1174c68741SSarah Sharp * published by the Free Software Foundation. 1274c68741SSarah Sharp * 1374c68741SSarah Sharp * This program is distributed in the hope that it will be useful, but 1474c68741SSarah Sharp * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 1574c68741SSarah Sharp * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1674c68741SSarah Sharp * for more details. 1774c68741SSarah Sharp * 1874c68741SSarah Sharp * You should have received a copy of the GNU General Public License 1974c68741SSarah Sharp * along with this program; if not, write to the Free Software Foundation, 2074c68741SSarah Sharp * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 2174c68741SSarah Sharp */ 22bdfca502SAndiry Xu /* Up to 16 ms to halt an HC */ 23bdfca502SAndiry Xu #define XHCI_MAX_HALT_USEC (16*1000) 2474c68741SSarah Sharp /* HC not running - set to 1 when run/stop bit is cleared. */ 2574c68741SSarah Sharp #define XHCI_STS_HALT (1<<0) 2674c68741SSarah Sharp 2774c68741SSarah Sharp /* HCCPARAMS offset from PCI base address */ 2874c68741SSarah Sharp #define XHCI_HCC_PARAMS_OFFSET 0x10 2974c68741SSarah Sharp /* HCCPARAMS contains the first extended capability pointer */ 3074c68741SSarah Sharp #define XHCI_HCC_EXT_CAPS(p) (((p)>>16)&0xffff) 3174c68741SSarah Sharp 3274c68741SSarah Sharp /* Command and Status registers offset from the Operational Registers address */ 3374c68741SSarah Sharp #define XHCI_CMD_OFFSET 0x00 3474c68741SSarah Sharp #define XHCI_STS_OFFSET 0x04 3574c68741SSarah Sharp 3674c68741SSarah Sharp #define XHCI_MAX_EXT_CAPS 50 3774c68741SSarah Sharp 3874c68741SSarah Sharp /* Capability Register */ 3974c68741SSarah Sharp /* bits 7:0 - how long is the Capabilities register */ 4074c68741SSarah Sharp #define XHCI_HC_LENGTH(p) (((p)>>00)&0x00ff) 4174c68741SSarah Sharp 4274c68741SSarah Sharp /* Extended capability register fields */ 4374c68741SSarah Sharp #define XHCI_EXT_CAPS_ID(p) (((p)>>0)&0xff) 4474c68741SSarah Sharp #define XHCI_EXT_CAPS_NEXT(p) (((p)>>8)&0xff) 4574c68741SSarah Sharp #define XHCI_EXT_CAPS_VAL(p) ((p)>>16) 4674c68741SSarah Sharp /* Extended capability IDs - ID 0 reserved */ 4774c68741SSarah Sharp #define XHCI_EXT_CAPS_LEGACY 1 4874c68741SSarah Sharp #define XHCI_EXT_CAPS_PROTOCOL 2 4974c68741SSarah Sharp #define XHCI_EXT_CAPS_PM 3 5074c68741SSarah Sharp #define XHCI_EXT_CAPS_VIRT 4 5174c68741SSarah Sharp #define XHCI_EXT_CAPS_ROUTE 5 5274c68741SSarah Sharp /* IDs 6-9 reserved */ 5374c68741SSarah Sharp #define XHCI_EXT_CAPS_DEBUG 10 5474c68741SSarah Sharp /* USB Legacy Support Capability - section 7.1.1 */ 5574c68741SSarah Sharp #define XHCI_HC_BIOS_OWNED (1 << 16) 5674c68741SSarah Sharp #define XHCI_HC_OS_OWNED (1 << 24) 5774c68741SSarah Sharp 5874c68741SSarah Sharp /* USB Legacy Support Capability - section 7.1.1 */ 5974c68741SSarah Sharp /* Add this offset, plus the value of xECP in HCCPARAMS to the base address */ 6074c68741SSarah Sharp #define XHCI_LEGACY_SUPPORT_OFFSET (0x00) 6174c68741SSarah Sharp 6274c68741SSarah Sharp /* USB Legacy Support Control and Status Register - section 7.1.2 */ 6374c68741SSarah Sharp /* Add this offset, plus the value of xECP in HCCPARAMS to the base address */ 6474c68741SSarah Sharp #define XHCI_LEGACY_CONTROL_OFFSET (0x04) 6574c68741SSarah Sharp /* bits 1:2, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */ 6674c68741SSarah Sharp #define XHCI_LEGACY_DISABLE_SMI ((0x3 << 1) + (0xff << 5) + (0x7 << 17)) 6774c68741SSarah Sharp 6874c68741SSarah Sharp /* command register values to disable interrupts and halt the HC */ 6974c68741SSarah Sharp /* start/stop HC execution - do not write unless HC is halted*/ 7074c68741SSarah Sharp #define XHCI_CMD_RUN (1 << 0) 7174c68741SSarah Sharp /* Event Interrupt Enable - get irq when EINT bit is set in USBSTS register */ 7274c68741SSarah Sharp #define XHCI_CMD_EIE (1 << 2) 7374c68741SSarah Sharp /* Host System Error Interrupt Enable - get irq when HSEIE bit set in USBSTS */ 7474c68741SSarah Sharp #define XHCI_CMD_HSEIE (1 << 3) 7574c68741SSarah Sharp /* Enable Wrap Event - '1' means xHC generates an event when MFINDEX wraps. */ 7674c68741SSarah Sharp #define XHCI_CMD_EWE (1 << 10) 7774c68741SSarah Sharp 7874c68741SSarah Sharp #define XHCI_IRQS (XHCI_CMD_EIE | XHCI_CMD_HSEIE | XHCI_CMD_EWE) 7974c68741SSarah Sharp 8074c68741SSarah Sharp /* true: Controller Not Ready to accept doorbell or op reg writes after reset */ 8174c68741SSarah Sharp #define XHCI_STS_CNR (1 << 11) 8274c68741SSarah Sharp 8374c68741SSarah Sharp #include <linux/io.h> 8474c68741SSarah Sharp 8574c68741SSarah Sharp /** 8674c68741SSarah Sharp * Return the next extended capability pointer register. 8774c68741SSarah Sharp * 8874c68741SSarah Sharp * @base PCI register base address. 8974c68741SSarah Sharp * 9074c68741SSarah Sharp * @ext_offset Offset of the 32-bit register that contains the extended 9174c68741SSarah Sharp * capabilites pointer. If searching for the first extended capability, pass 9274c68741SSarah Sharp * in XHCI_HCC_PARAMS_OFFSET. If searching for the next extended capability, 9374c68741SSarah Sharp * pass in the offset of the current extended capability register. 9474c68741SSarah Sharp * 9574c68741SSarah Sharp * Returns 0 if there is no next extended capability register or returns the register offset 9674c68741SSarah Sharp * from the PCI registers base address. 9774c68741SSarah Sharp */ 9874c68741SSarah Sharp static inline int xhci_find_next_cap_offset(void __iomem *base, int ext_offset) 9974c68741SSarah Sharp { 10074c68741SSarah Sharp u32 next; 10174c68741SSarah Sharp 10274c68741SSarah Sharp next = readl(base + ext_offset); 10374c68741SSarah Sharp 10405197921SEdward Shao if (ext_offset == XHCI_HCC_PARAMS_OFFSET) { 10574c68741SSarah Sharp /* Find the first extended capability */ 10674c68741SSarah Sharp next = XHCI_HCC_EXT_CAPS(next); 10705197921SEdward Shao ext_offset = 0; 10805197921SEdward Shao } else { 10974c68741SSarah Sharp /* Find the next extended capability */ 11074c68741SSarah Sharp next = XHCI_EXT_CAPS_NEXT(next); 11105197921SEdward Shao } 11205197921SEdward Shao 11374c68741SSarah Sharp if (!next) 11474c68741SSarah Sharp return 0; 11574c68741SSarah Sharp /* 11674c68741SSarah Sharp * Address calculation from offset of extended capabilities 11774c68741SSarah Sharp * (or HCCPARAMS) register - see section 5.3.6 and section 7. 11874c68741SSarah Sharp */ 11974c68741SSarah Sharp return ext_offset + (next << 2); 12074c68741SSarah Sharp } 12174c68741SSarah Sharp 12274c68741SSarah Sharp /** 12374c68741SSarah Sharp * Find the offset of the extended capabilities with capability ID id. 12474c68741SSarah Sharp * 12574c68741SSarah Sharp * @base PCI MMIO registers base address. 12674c68741SSarah Sharp * @ext_offset Offset from base of the first extended capability to look at, 12774c68741SSarah Sharp * or the address of HCCPARAMS. 12874c68741SSarah Sharp * @id Extended capability ID to search for. 12974c68741SSarah Sharp * 13074c68741SSarah Sharp * This uses an arbitrary limit of XHCI_MAX_EXT_CAPS extended capabilities 13174c68741SSarah Sharp * to make sure that the list doesn't contain a loop. 13274c68741SSarah Sharp */ 13374c68741SSarah Sharp static inline int xhci_find_ext_cap_by_id(void __iomem *base, int ext_offset, int id) 13474c68741SSarah Sharp { 13574c68741SSarah Sharp u32 val; 13674c68741SSarah Sharp int limit = XHCI_MAX_EXT_CAPS; 13774c68741SSarah Sharp 13874c68741SSarah Sharp while (ext_offset && limit > 0) { 13974c68741SSarah Sharp val = readl(base + ext_offset); 14074c68741SSarah Sharp if (XHCI_EXT_CAPS_ID(val) == id) 14174c68741SSarah Sharp break; 14274c68741SSarah Sharp ext_offset = xhci_find_next_cap_offset(base, ext_offset); 14374c68741SSarah Sharp limit--; 14474c68741SSarah Sharp } 14574c68741SSarah Sharp if (limit > 0) 14674c68741SSarah Sharp return ext_offset; 14774c68741SSarah Sharp return 0; 14874c68741SSarah Sharp } 149