18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2003-2013 Broadcom Corporation 38c2ecf20Sopenharmony_ci * All Rights Reserved 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 68c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 78c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 88c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the Broadcom 98c2ecf20Sopenharmony_ci * license below: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 128c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 138c2ecf20Sopenharmony_ci * are met: 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 168c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 178c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 188c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 198c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 208c2ecf20Sopenharmony_ci * distribution. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR 238c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 248c2ecf20Sopenharmony_ci * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 258c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE 268c2ecf20Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 278c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 288c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 298c2ecf20Sopenharmony_ci * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 308c2ecf20Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 318c2ecf20Sopenharmony_ci * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 328c2ecf20Sopenharmony_ci * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 368c2ecf20Sopenharmony_ci#include <linux/kernel.h> 378c2ecf20Sopenharmony_ci#include <linux/delay.h> 388c2ecf20Sopenharmony_ci#include <linux/init.h> 398c2ecf20Sopenharmony_ci#include <linux/pci.h> 408c2ecf20Sopenharmony_ci#include <linux/pci_ids.h> 418c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 428c2ecf20Sopenharmony_ci#include <linux/irq.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#include <asm/netlogic/common.h> 458c2ecf20Sopenharmony_ci#include <asm/netlogic/haldefs.h> 468c2ecf20Sopenharmony_ci#include <asm/netlogic/xlp-hal/iomap.h> 478c2ecf20Sopenharmony_ci#include <asm/netlogic/xlp-hal/xlp.h> 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define XLPII_USB3_CTL_0 0xc0 508c2ecf20Sopenharmony_ci#define XLPII_VAUXRST BIT(0) 518c2ecf20Sopenharmony_ci#define XLPII_VCCRST BIT(1) 528c2ecf20Sopenharmony_ci#define XLPII_NUM2PORT 9 538c2ecf20Sopenharmony_ci#define XLPII_NUM3PORT 13 548c2ecf20Sopenharmony_ci#define XLPII_RTUNEREQ BIT(20) 558c2ecf20Sopenharmony_ci#define XLPII_MS_CSYSREQ BIT(21) 568c2ecf20Sopenharmony_ci#define XLPII_XS_CSYSREQ BIT(22) 578c2ecf20Sopenharmony_ci#define XLPII_RETENABLEN BIT(23) 588c2ecf20Sopenharmony_ci#define XLPII_TX2RX BIT(24) 598c2ecf20Sopenharmony_ci#define XLPII_XHCIREV BIT(25) 608c2ecf20Sopenharmony_ci#define XLPII_ECCDIS BIT(26) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define XLPII_USB3_INT_REG 0xc2 638c2ecf20Sopenharmony_ci#define XLPII_USB3_INT_MASK 0xc3 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define XLPII_USB_PHY_TEST 0xc6 668c2ecf20Sopenharmony_ci#define XLPII_PRESET BIT(0) 678c2ecf20Sopenharmony_ci#define XLPII_ATERESET BIT(1) 688c2ecf20Sopenharmony_ci#define XLPII_LOOPEN BIT(2) 698c2ecf20Sopenharmony_ci#define XLPII_TESTPDHSP BIT(3) 708c2ecf20Sopenharmony_ci#define XLPII_TESTPDSSP BIT(4) 718c2ecf20Sopenharmony_ci#define XLPII_TESTBURNIN BIT(5) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define XLPII_USB_PHY_LOS_LV 0xc9 748c2ecf20Sopenharmony_ci#define XLPII_LOSLEV 0 758c2ecf20Sopenharmony_ci#define XLPII_LOSBIAS 5 768c2ecf20Sopenharmony_ci#define XLPII_SQRXTX 8 778c2ecf20Sopenharmony_ci#define XLPII_TXBOOST 11 788c2ecf20Sopenharmony_ci#define XLPII_RSLKSEL 16 798c2ecf20Sopenharmony_ci#define XLPII_FSEL 20 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define XLPII_USB_RFCLK_REG 0xcc 828c2ecf20Sopenharmony_ci#define XLPII_VVLD 30 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define nlm_read_usb_reg(b, r) nlm_read_reg(b, r) 858c2ecf20Sopenharmony_ci#define nlm_write_usb_reg(b, r, v) nlm_write_reg(b, r, v) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#define nlm_xlpii_get_usb_pcibase(node, inst) \ 888c2ecf20Sopenharmony_ci nlm_pcicfg_base(cpu_is_xlp9xx() ? \ 898c2ecf20Sopenharmony_ci XLP9XX_IO_USB_OFFSET(node, inst) : \ 908c2ecf20Sopenharmony_ci XLP2XX_IO_USB_OFFSET(node, inst)) 918c2ecf20Sopenharmony_ci#define nlm_xlpii_get_usb_regbase(node, inst) \ 928c2ecf20Sopenharmony_ci (nlm_xlpii_get_usb_pcibase(node, inst) + XLP_IO_PCI_HDRSZ) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic void xlp2xx_usb_ack(struct irq_data *data) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci u64 port_addr; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci switch (data->irq) { 998c2ecf20Sopenharmony_ci case PIC_2XX_XHCI_0_IRQ: 1008c2ecf20Sopenharmony_ci port_addr = nlm_xlpii_get_usb_regbase(0, 1); 1018c2ecf20Sopenharmony_ci break; 1028c2ecf20Sopenharmony_ci case PIC_2XX_XHCI_1_IRQ: 1038c2ecf20Sopenharmony_ci port_addr = nlm_xlpii_get_usb_regbase(0, 2); 1048c2ecf20Sopenharmony_ci break; 1058c2ecf20Sopenharmony_ci case PIC_2XX_XHCI_2_IRQ: 1068c2ecf20Sopenharmony_ci port_addr = nlm_xlpii_get_usb_regbase(0, 3); 1078c2ecf20Sopenharmony_ci break; 1088c2ecf20Sopenharmony_ci default: 1098c2ecf20Sopenharmony_ci pr_err("No matching USB irq!\n"); 1108c2ecf20Sopenharmony_ci return; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci nlm_write_usb_reg(port_addr, XLPII_USB3_INT_REG, 0xffffffff); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic void xlp9xx_usb_ack(struct irq_data *data) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci u64 port_addr; 1188c2ecf20Sopenharmony_ci int node, irq; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* Find the node and irq on the node */ 1218c2ecf20Sopenharmony_ci irq = data->irq % NLM_IRQS_PER_NODE; 1228c2ecf20Sopenharmony_ci node = data->irq / NLM_IRQS_PER_NODE; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci switch (irq) { 1258c2ecf20Sopenharmony_ci case PIC_9XX_XHCI_0_IRQ: 1268c2ecf20Sopenharmony_ci port_addr = nlm_xlpii_get_usb_regbase(node, 1); 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci case PIC_9XX_XHCI_1_IRQ: 1298c2ecf20Sopenharmony_ci port_addr = nlm_xlpii_get_usb_regbase(node, 2); 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci case PIC_9XX_XHCI_2_IRQ: 1328c2ecf20Sopenharmony_ci port_addr = nlm_xlpii_get_usb_regbase(node, 3); 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci default: 1358c2ecf20Sopenharmony_ci pr_err("No matching USB irq %d node %d!\n", irq, node); 1368c2ecf20Sopenharmony_ci return; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci nlm_write_usb_reg(port_addr, XLPII_USB3_INT_REG, 0xffffffff); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic void nlm_xlpii_usb_hw_reset(int node, int port) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci u64 port_addr, xhci_base, pci_base; 1448c2ecf20Sopenharmony_ci void __iomem *corebase; 1458c2ecf20Sopenharmony_ci u32 val; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci port_addr = nlm_xlpii_get_usb_regbase(node, port); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* Set frequency */ 1508c2ecf20Sopenharmony_ci val = nlm_read_usb_reg(port_addr, XLPII_USB_PHY_LOS_LV); 1518c2ecf20Sopenharmony_ci val &= ~(0x3f << XLPII_FSEL); 1528c2ecf20Sopenharmony_ci val |= (0x27 << XLPII_FSEL); 1538c2ecf20Sopenharmony_ci nlm_write_usb_reg(port_addr, XLPII_USB_PHY_LOS_LV, val); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci val = nlm_read_usb_reg(port_addr, XLPII_USB_RFCLK_REG); 1568c2ecf20Sopenharmony_ci val |= (1 << XLPII_VVLD); 1578c2ecf20Sopenharmony_ci nlm_write_usb_reg(port_addr, XLPII_USB_RFCLK_REG, val); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* PHY reset */ 1608c2ecf20Sopenharmony_ci val = nlm_read_usb_reg(port_addr, XLPII_USB_PHY_TEST); 1618c2ecf20Sopenharmony_ci val &= (XLPII_ATERESET | XLPII_LOOPEN | XLPII_TESTPDHSP 1628c2ecf20Sopenharmony_ci | XLPII_TESTPDSSP | XLPII_TESTBURNIN); 1638c2ecf20Sopenharmony_ci nlm_write_usb_reg(port_addr, XLPII_USB_PHY_TEST, val); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* Setup control register */ 1668c2ecf20Sopenharmony_ci val = XLPII_VAUXRST | XLPII_VCCRST | (1 << XLPII_NUM2PORT) 1678c2ecf20Sopenharmony_ci | (1 << XLPII_NUM3PORT) | XLPII_MS_CSYSREQ | XLPII_XS_CSYSREQ 1688c2ecf20Sopenharmony_ci | XLPII_RETENABLEN | XLPII_XHCIREV; 1698c2ecf20Sopenharmony_ci nlm_write_usb_reg(port_addr, XLPII_USB3_CTL_0, val); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* Enable interrupts */ 1728c2ecf20Sopenharmony_ci nlm_write_usb_reg(port_addr, XLPII_USB3_INT_MASK, 0x00000001); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* Clear all interrupts */ 1758c2ecf20Sopenharmony_ci nlm_write_usb_reg(port_addr, XLPII_USB3_INT_REG, 0xffffffff); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci udelay(2000); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* XHCI configuration at PCI mem */ 1808c2ecf20Sopenharmony_ci pci_base = nlm_xlpii_get_usb_pcibase(node, port); 1818c2ecf20Sopenharmony_ci xhci_base = nlm_read_usb_reg(pci_base, 0x4) & ~0xf; 1828c2ecf20Sopenharmony_ci corebase = ioremap(xhci_base, 0x10000); 1838c2ecf20Sopenharmony_ci if (!corebase) 1848c2ecf20Sopenharmony_ci return; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci writel(0x240002, corebase + 0xc2c0); 1878c2ecf20Sopenharmony_ci /* GCTL 0xc110 */ 1888c2ecf20Sopenharmony_ci val = readl(corebase + 0xc110); 1898c2ecf20Sopenharmony_ci val &= ~(0x3 << 12); 1908c2ecf20Sopenharmony_ci val |= (1 << 12); 1918c2ecf20Sopenharmony_ci writel(val, corebase + 0xc110); 1928c2ecf20Sopenharmony_ci udelay(100); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* PHYCFG 0xc200 */ 1958c2ecf20Sopenharmony_ci val = readl(corebase + 0xc200); 1968c2ecf20Sopenharmony_ci val &= ~(1 << 6); 1978c2ecf20Sopenharmony_ci writel(val, corebase + 0xc200); 1988c2ecf20Sopenharmony_ci udelay(100); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* PIPECTL 0xc2c0 */ 2018c2ecf20Sopenharmony_ci val = readl(corebase + 0xc2c0); 2028c2ecf20Sopenharmony_ci val &= ~(1 << 17); 2038c2ecf20Sopenharmony_ci writel(val, corebase + 0xc2c0); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci iounmap(corebase); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int __init nlm_platform_xlpii_usb_init(void) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci int node; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (!cpu_is_xlpii()) 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (!cpu_is_xlp9xx()) { 2168c2ecf20Sopenharmony_ci /* XLP 2XX single node */ 2178c2ecf20Sopenharmony_ci pr_info("Initializing 2XX USB Interface\n"); 2188c2ecf20Sopenharmony_ci nlm_xlpii_usb_hw_reset(0, 1); 2198c2ecf20Sopenharmony_ci nlm_xlpii_usb_hw_reset(0, 2); 2208c2ecf20Sopenharmony_ci nlm_xlpii_usb_hw_reset(0, 3); 2218c2ecf20Sopenharmony_ci nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_0_IRQ, xlp2xx_usb_ack); 2228c2ecf20Sopenharmony_ci nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_1_IRQ, xlp2xx_usb_ack); 2238c2ecf20Sopenharmony_ci nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_2_IRQ, xlp2xx_usb_ack); 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* XLP 9XX, multi-node */ 2288c2ecf20Sopenharmony_ci pr_info("Initializing 9XX/5XX USB Interface\n"); 2298c2ecf20Sopenharmony_ci for (node = 0; node < NLM_NR_NODES; node++) { 2308c2ecf20Sopenharmony_ci if (!nlm_node_present(node)) 2318c2ecf20Sopenharmony_ci continue; 2328c2ecf20Sopenharmony_ci nlm_xlpii_usb_hw_reset(node, 1); 2338c2ecf20Sopenharmony_ci nlm_xlpii_usb_hw_reset(node, 2); 2348c2ecf20Sopenharmony_ci nlm_xlpii_usb_hw_reset(node, 3); 2358c2ecf20Sopenharmony_ci nlm_set_pic_extra_ack(node, PIC_9XX_XHCI_0_IRQ, xlp9xx_usb_ack); 2368c2ecf20Sopenharmony_ci nlm_set_pic_extra_ack(node, PIC_9XX_XHCI_1_IRQ, xlp9xx_usb_ack); 2378c2ecf20Sopenharmony_ci nlm_set_pic_extra_ack(node, PIC_9XX_XHCI_2_IRQ, xlp9xx_usb_ack); 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ciarch_initcall(nlm_platform_xlpii_usb_init); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic u64 xlp_usb_dmamask = ~(u32)0; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci/* Fixup the IRQ for USB devices which is exist on XLP9XX SOC PCIE bus */ 2478c2ecf20Sopenharmony_cistatic void nlm_xlp9xx_usb_fixup_final(struct pci_dev *dev) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci int node; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci node = xlp_socdev_to_node(dev); 2528c2ecf20Sopenharmony_ci dev->dev.dma_mask = &xlp_usb_dmamask; 2538c2ecf20Sopenharmony_ci dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); 2548c2ecf20Sopenharmony_ci switch (dev->devfn) { 2558c2ecf20Sopenharmony_ci case 0x21: 2568c2ecf20Sopenharmony_ci dev->irq = nlm_irq_to_xirq(node, PIC_9XX_XHCI_0_IRQ); 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci case 0x22: 2598c2ecf20Sopenharmony_ci dev->irq = nlm_irq_to_xirq(node, PIC_9XX_XHCI_1_IRQ); 2608c2ecf20Sopenharmony_ci break; 2618c2ecf20Sopenharmony_ci case 0x23: 2628c2ecf20Sopenharmony_ci dev->irq = nlm_irq_to_xirq(node, PIC_9XX_XHCI_2_IRQ); 2638c2ecf20Sopenharmony_ci break; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* Fixup the IRQ for USB devices which is exist on XLP2XX SOC PCIE bus */ 2688c2ecf20Sopenharmony_cistatic void nlm_xlp2xx_usb_fixup_final(struct pci_dev *dev) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci dev->dev.dma_mask = &xlp_usb_dmamask; 2718c2ecf20Sopenharmony_ci dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); 2728c2ecf20Sopenharmony_ci switch (dev->devfn) { 2738c2ecf20Sopenharmony_ci case 0x21: 2748c2ecf20Sopenharmony_ci dev->irq = PIC_2XX_XHCI_0_IRQ; 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci case 0x22: 2778c2ecf20Sopenharmony_ci dev->irq = PIC_2XX_XHCI_1_IRQ; 2788c2ecf20Sopenharmony_ci break; 2798c2ecf20Sopenharmony_ci case 0x23: 2808c2ecf20Sopenharmony_ci dev->irq = PIC_2XX_XHCI_2_IRQ; 2818c2ecf20Sopenharmony_ci break; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_XLP9XX_XHCI, 2868c2ecf20Sopenharmony_ci nlm_xlp9xx_usb_fixup_final); 2878c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_XHCI, 2888c2ecf20Sopenharmony_ci nlm_xlp2xx_usb_fixup_final); 289