/* * xhci-plat.c - xHCI host controller driver platform Bus Glue. * * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com * Author: Sebastian Andrzej Siewior * * A lot of code borrowed from the Linux xHCI driver. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */ /** * Some part of this file is modified by Ikanos Communications. * * Copyright (C) 2013-2014 Ikanos Communications. */ #include #include #include #include "xhci.h" #include #if defined(CONFIG_FUSIV_VX585) #include // SCU Registers #define SCU_USB_CONTROL_STATUS ((volatile uint *)0xb9000630) #define SCU_USB_PHY_CONFIG0 ((volatile uint *)0xb90000A0) #define SCU_USB_PHY_CONFIG1 ((volatile uint *)0xb90000A4) #define SCU_RESET_CONTROL_REGISTER ((volatile uint *)0xb9000204) #define SCU_USB2_PHY_CONTROL ((volatile uint *)0xb9000078) #define SCU_USB_CTRL_STAT ((volatile uint *)0xb9000634) // GLOBAL Registers #define GLB_USB2_PHY_CONFIG ((volatile uint *)0xb980C200) #define GLB_USB2_PHY_CONFIG_P2 ((volatile uint *)0xb980C204) #define GLB_USB3_PIPE_CTRL ((volatile uint *)0xb980C2C0) #define GLB_USB3_PIPE_CTRL_P2 ((volatile uint *)0xb980C2C4) #define GLB_CORE_CTRL ((volatile uint *)0xb980c110) #define GLB_SOC_BUS_CONFIG ((volatile uint *)0xb980c100) #define GLB_INT_STATUS_REG ((volatile uint *)0xb980C118) #endif #define IO(_x) (*(volatile unsigned int *) _x) static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) { /* * As of now platform drivers don't provide MSI support so we ensure * here that the generic code does not try to make a pci_dev from our * dev struct in order to setup MSI */ xhci->quirks |= XHCI_PLAT; } /* called during probe() after chip reset completes */ static int xhci_plat_setup(struct usb_hcd *hcd) { return xhci_gen_setup(hcd, xhci_plat_quirks); } static void wait_done_from_usb0_serdes(void) { volatile unsigned int read_data = 0; unsigned int Addr = 0; /* Serdes Wrapper Control Register 5 for USB0 SERDES */ /* If 29th bit is 1 then it means Ack for write access complete, Data valid for read data */ Addr = 0xB90E6014; read_data = IO(Addr); while ((read_data & 0x20000000) != 0x20000000)//29th bit { read_data = IO(Addr); } IO(Addr) = 0x20000000; } static void wait_done_from_usb1_serdes(void) { volatile unsigned int read_data = 0; unsigned int Addr = 0; /* Serdes Wrapper Control Register 5 for USB1/SATA SERDES */ /* If 29th bit is 1 then it means Ack for write access complete, Data valid for read data */ Addr = 0xB90EA014; read_data = IO(Addr); while ((read_data & 0x20000000) != 0x20000000)//29th bit { read_data = IO(Addr); } IO(Addr) = 0x20000000; } static void config_serdes0(void) { volatile uint regval = 0; /* Serdes Control 0 register */ /* 16th Bit - Power on reset to initialize memory register of USB0 Serdes */ regval = *(volatile unsigned int *)0xb9000070; regval = regval | 0x00010000 ; *(volatile unsigned int *)0xb9000070 = regval; mdelay(3); regval = 0x86a60703 ; *(volatile unsigned int *)0xb90e6010 = regval; regval = 0xA0BF0065; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80080066; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80080067; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80130068; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80130069; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x8001006A; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x8011006B; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x800C006C; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80AA806F; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80008070; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80348071; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80BF8072;// *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80088073; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80088074; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80138075; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80138076; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80038077; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80148078; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80108079; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x8000807A; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x8010807B; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x8000807C; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FF807D; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80CF807E; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80F7807F; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80E18080; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80F58081; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FD8082; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FD8083; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FF8084; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FF8085; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FF8086; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FF8087; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80E38088; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80E78089; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80DB808A; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80F5808B; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FD808C; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FD808D; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80F5808E; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80F5808F; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FF8090; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FF8091; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80E38092; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80E78093; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80DB8094; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80F58095; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FD8096; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FD8097; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80F58098; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80F58099; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FF809A; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FF809B; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80FF809C; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80F5809D; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x803F809E; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x8000809F; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x803280A0; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x800080A1; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x800280A2; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x800580A3; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x800480A4; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x800080A5; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x800080A6; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x801480A7; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x800480A8; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x800080A9; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x800080AA; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x800480AB; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x800380AC; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80EA0152; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80C20153; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80000015; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = *(volatile unsigned int *)0xb9000070; regval = regval | 0x00060000 ; *(volatile unsigned int *)0xb9000070 = regval; /* Rx Equalization Start*/ regval = 0x80070015; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); /* Rx Equalization End*/ regval = 0x80D90012; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80000013; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80000014; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x801b000b; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x8033000c; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = 0x80da8019; *(volatile unsigned int *)0xb90E6014 = regval ; wait_done_from_usb0_serdes(); regval = *(volatile unsigned int *)0xb90E6008 ; regval = regval | 0x00070000 ; *(volatile unsigned int *)0xb90E6008 = regval ; regval = *(volatile unsigned int *)0xb90E6000 ; regval = regval & 0xFFFFFFFE ; regval = regval | 0x00000002 ; *(volatile unsigned int *)0xb90E6000 = regval ; regval = *(volatile unsigned int *)0xb90E6004 ; regval = regval & 0xFFC0200F ; regval = regval | 0x00802000 ; *(volatile unsigned int *)0xb90E6004 = regval ; /* Latch on Reset 1: 0xb9000224: 13th bit: 1-USB3 : 0-SATA */ /* If the board is configured to use serDES1 as SATA then we should route the clock from serDES0 to serDES1 */ regval = *(volatile unsigned int *)0xb9000224; if((regval & 0x00002000) == 0x0) { // Route clock from Serdes0 to Serdes1 pr_debug("USB3: Routing clock from serDES0 to serDES1\n"); /* Set 'A' to [19:16](WP_CLK_CTRL_4) on Clock Control Write Protect Register */ regval = 0x000A0000; *(volatile unsigned int *)0xb9000120 = regval ; /* Set bit 20 - USB1 clocks will come from USB_0 Serdes */ regval = *(volatile unsigned int *)0xb9000134 ; regval = regval | 0x00100000 ; *(volatile unsigned int *)0xb9000134 = regval ; } mdelay(1); /* Serdes Wrapper status register for USB0 serDes */ /* Bit 0 represents SYNTHREDY */ regval = *(volatile unsigned int *)0xb90E601C ; while ((regval & 0x00000001) != 1) { regval = *(volatile unsigned int *)0xb90E601C ; } } static void config_serdes1(void) { volatile uint regval = 0; // Bydefault SERDES1 is SATA; select it as USB before configuring /* Set bit 0 to 1 - Power on reset to initialize memory register of SATA SERDES */ regval = *(volatile unsigned int *)0xb9000074; regval = regval | 0x00000001 ; *(volatile unsigned int *)0xb9000074 = regval; mdelay(3); regval = *(volatile unsigned int *)0xb90EA000; regval = regval & 0xFDFBFFFF; regval = regval | 0x01830000; *(volatile unsigned int *)0xb90EA000 = regval; regval = *(volatile unsigned int *)0xb90EA004; regval = regval & 0xDFFFFFF7; regval = regval | 0x18000006; *(volatile unsigned int *)0xb90EA004 = regval; regval = 0xA0BF0065; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80080066; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80080067; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80130068; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80130069; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x8001006A; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x8011006B; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x800C006C; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80AA806F; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80008070; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80348071; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80BF8072; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80088073; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80088074; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80138075; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80138076; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80038077; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80148078; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80108079; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x8000807A; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x8010807B; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x8000807C; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FF807D; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80CF807E; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80F7807F; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80E18080; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80F58081; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FD8082; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FD8083; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FF8084; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FF8085; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FF8086; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FF8087; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80E38088; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80E78089; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80DB808A; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80F5808B; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FD808C; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FD808D; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80F5808E; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80F5808F; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FF8090; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FF8091; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80E38092; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80E78093; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80DB8094; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80F58095; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FD8096; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FD8097; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80F58098; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80F58099; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FF809A; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FF809B; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80FF809C; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80F5809D; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x803F809E; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x8000809F; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x803280A0; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x800080A1; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x800280A2; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x800580A3; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x800480A4; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x800080A5; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x800080A6; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x801480A7; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x800480A8; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x800080A9; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x800080AA; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x800480AB; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x800380AC; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80EA0152; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80C20153; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80000015; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); /* 0xb9000074 : Serdes Control 1 Register */ /* set bit 1 : Lane hard reset signal for SATA Serdes */ /* set bit 2 : Synthesizer hard reset signal for SATA Serdes */ regval = *(volatile unsigned int *)0xb9000074; regval = regval | 0x00000006 ; *(volatile unsigned int *)0xb9000074 = regval; // RX Equalization Start regval = 0x80070015; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); // RX Equalization End regval = 0x80D90012; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80000013; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80000014; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x801B000B; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x8033000C; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = 0x80DA8019; *(volatile unsigned int *)0xb90EA014 = regval; wait_done_from_usb1_serdes(); regval = *(volatile unsigned int *)0xb90EA008; regval = regval | 0x00070000 ; *(volatile unsigned int *)0xb90EA008 = regval; regval = *(volatile unsigned int *)0xb90EA000; regval = regval | 0x00000002 ; *(volatile unsigned int *)0xb90EA000 = regval; regval = *(volatile unsigned int *)0xb90EA004; regval = regval & 0xFFC0200F; regval = regval | 0x00802000 ; *(volatile unsigned int *)0xb90EA004 = regval; mdelay(1); /* Serdes Wrapper status register for USB1/SATA serDes */ /* Bit 0 represents SYNTHREDY */ regval = *(volatile unsigned int *)0xb90EA01C ; while ((regval & 0x00000001) != 1) { regval = *(volatile unsigned int *)0xb90EA01C ; } } /* Bring up the UTMI PHY, host controller */ static void ikf75xx_start_xhci_hc(struct platform_device *dev) { volatile uint regval = 0; pr_debug(__FILE__ ": starting VX585 XHCI USB Controller\n"); // Disable USB Port Power /* 0xb903000c is GPIO Mode 1 Register; This is Read Modify Write Register */ /* Make GPIO 6 and GPIO 7 as "Normal Output"; Write "0101" to bits[15:12]*/ regval = *(volatile unsigned int *)0xb903000c; regval = regval | 0x00005000; *(volatile unsigned int *)0xb903000c = regval ; /* 0xb9030008 is GPIO Clear Register; This is sticky bit; Don't Read-Modify-Write */ /* Write 1 to Bits 6 and 7 to disable power for USB0 and USB1*/ regval = 0x000000c0; *(volatile unsigned int *)0xb9030008 = regval ; /* VCC reset */ /* 0xb9000200 is Reset Control 0 Mask */ /* Clearing Bit 17th: if this bit is 1, then the write to corresponding bit of Reset Control 0 Register is disabled */ *(volatile unsigned int *)0xb9000200 = 0xFFFDFFFF ; /* 0xb9000204 is Reset Control 0 Register */ /* Set bit 17 to 1. If this bit is 0 then asserts reset to USB */ regval = *(volatile unsigned int *)0xb9000204 ; regval = regval | 0x00020000 ; *(volatile unsigned int *)0xb9000204 = regval ; /* Setting bit 17th back to 1 on Reset Control 0 Mask register */ *(volatile unsigned int *)0xb9000200 = 0xFFFFFFFF ; mdelay(3); /* VCC reset end */ regval = 0x0F002202; *(volatile unsigned int *)0xb9000630 = regval ; regval = *(volatile unsigned int *)0xb9000074 ; regval = regval | 0x80000000 ; *(volatile unsigned int *)0xb9000074 = regval ; regval = *(volatile unsigned int *)0xb90ea010 ; regval ^= 0x004018FD ; *(volatile unsigned int *)0xb90ea010 = regval ; /* 0xb9000078 is USB2 PHY Control */ /* Clearing 0th and 16th Bit; if 1 then USB2PHY of USB0 and USB1 is under reset */ regval = *(volatile unsigned int *)0xb9000078 ; regval = regval & 0xFFFEFFFE ; *(volatile unsigned int *)0xb9000078 = regval ; regval = 0x00002000 ; *(volatile unsigned int *)0xb90e6000 = regval ; regval = *(volatile unsigned int *)0xb90e6018 ; regval = regval | 0x0F; *(volatile unsigned int *)0xb90e6018 = regval ; regval = 0x00002000 ; *(volatile unsigned int *)0xb90ea000 = regval ; ///USB0 SERDES CONIGURATION config_serdes0(); ///USB1 SERDES CONIGURATION /* Latch on Reset 1: 0xb9000224: 13th bit: 1 means USB3 : 0 means SATA */ regval = *(volatile unsigned int *)0xb9000224; if((regval & 0x00002000) == 0x00002000) { pr_debug("Configuring serDES1 for USB3\n"); config_serdes1(); } // Add 400ms delay between SerDes configuration and USP port power enable mdelay(400); //Enable Port Power for USB /* 0xb9030004 is GPIO Set Register; This is sticky bit; Don't Read-Modify-Write */ /* Write 1 to Bits 6 and 7 to enable power for USB0 and USB1*/ regval = 0x000000c0 ; *(volatile unsigned int *)0xb9030004 = regval ; ////USB Controller related code starts here regval = *GLB_USB2_PHY_CONFIG; regval = regval & 0x7FFFFFFF; *GLB_USB2_PHY_CONFIG = regval; regval = *(GLB_USB2_PHY_CONFIG_P2); regval = regval & 0x7FFFFFFF; *(GLB_USB2_PHY_CONFIG_P2) = regval; regval = *(GLB_USB3_PIPE_CTRL); regval = regval & 0x7FFFFFFF; regval = regval | 0x00020000; regval = regval & 0xFFBFFFFF; *(GLB_USB3_PIPE_CTRL) = regval; regval = *(GLB_USB3_PIPE_CTRL_P2); regval = regval & 0x7FFFFFFF; regval = regval | 0x00020000; regval = regval & 0xFFBFFFFF; *(GLB_USB3_PIPE_CTRL_P2) = regval; regval = *(GLB_CORE_CTRL); regval = regval | 0x00001000; regval = regval & 0xFFFFFFFB; *(GLB_CORE_CTRL) = regval; regval = *GLB_USB2_PHY_CONFIG; regval = regval & 0xFFFFFFBF; *GLB_USB2_PHY_CONFIG = regval; regval = *(GLB_USB2_PHY_CONFIG_P2); regval = regval & 0xFFFFFFBF; *(GLB_USB2_PHY_CONFIG_P2) = regval; // Enable Little endian regval = *GLB_SOC_BUS_CONFIG; regval = regval | 0x00000000; // set Little endian *GLB_SOC_BUS_CONFIG = regval; } static const struct hc_driver xhci_ikf75xx_hc_driver = { .description = "xhci-hcd", .product_desc = "Ikanos On-Chip xHCI Host Controller", .hcd_priv_size = sizeof(struct xhci_hcd ), /* * generic hardware linkage */ .irq = xhci_irq, .flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED, /* * basic lifecycle operations */ .reset = xhci_plat_setup, .start = xhci_run, .stop = xhci_stop, .shutdown = xhci_shutdown, /* * managing i/o requests and associated device resources */ .urb_enqueue = xhci_urb_enqueue, .urb_dequeue = xhci_urb_dequeue, .alloc_dev = xhci_alloc_dev, .free_dev = xhci_free_dev, .alloc_streams = xhci_alloc_streams, .free_streams = xhci_free_streams, .add_endpoint = xhci_add_endpoint, .drop_endpoint = xhci_drop_endpoint, .endpoint_reset = xhci_endpoint_reset, .check_bandwidth = xhci_check_bandwidth, .reset_bandwidth = xhci_reset_bandwidth, .address_device = xhci_address_device, .update_hub_device = xhci_update_hub_device, .reset_device = xhci_discover_or_reset_device, /* * scheduling support */ .get_frame_number = xhci_get_frame, /* Root hub support */ .hub_control = xhci_hub_control, .hub_status_data = xhci_hub_status_data, .bus_suspend = xhci_bus_suspend, .bus_resume = xhci_bus_resume, }; static int xhci_hcd_ikf75xx_drv_probe(struct platform_device *pdev) { const struct hc_driver *driver; struct xhci_hcd *xhci; struct resource *res; struct usb_hcd *hcd; int ret; int irq; ikf75xx_start_xhci_hc(pdev); if (usb_disabled()) return -ENODEV; driver = &xhci_ikf75xx_hc_driver; irq = platform_get_irq(pdev, 0); if (irq < 0) return -ENODEV; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { dev_dbg(&pdev->dev,"usb_create_hcd error\n"); return -ENOMEM; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) { dev_dbg(&pdev->dev, "controller already in use\n"); ret = -EBUSY; goto put_hcd; } hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { dev_dbg(&pdev->dev, "error mapping memory\n"); ret = -EFAULT; goto release_mem_region; } ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) goto unmap_registers; /* USB 2.0 roothub is stored in the platform_device now. */ hcd = dev_get_drvdata(&pdev->dev); xhci = hcd_to_xhci(hcd); xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev, dev_name(&pdev->dev), hcd); if (!xhci->shared_hcd) { dev_dbg(&pdev->dev,"usb_create_shared_hcd error\r\n"); ret = -ENOMEM; goto dealloc_usb2_hcd; } /* * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset) * is called by usb_add_hcd(). */ *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); if (ret) goto put_usb3_hcd; printk("xhci_hcd_ikf75xx_drv_probe completed successfully\n"); return 0; put_usb3_hcd: usb_put_hcd(xhci->shared_hcd); dealloc_usb2_hcd: usb_remove_hcd(hcd); unmap_registers: iounmap(hcd->regs); release_mem_region: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); put_hcd: usb_put_hcd(hcd); return ret; } static int xhci_hcd_ikf75xx_drv_remove(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct xhci_hcd *xhci = hcd_to_xhci(hcd); usb_remove_hcd(xhci->shared_hcd); usb_put_hcd(xhci->shared_hcd); usb_remove_hcd(hcd); iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); kfree(xhci); return 0; } static struct platform_driver xhci_hcd_ikf75xx_driver = { .probe = xhci_hcd_ikf75xx_drv_probe, .remove = xhci_hcd_ikf75xx_drv_remove, .driver = { .name = "fusiv-xhci-hcd", .bus = &platform_bus_type, } }; int xhci_register_plat(void) { return platform_driver_register(&xhci_hcd_ikf75xx_driver); } void xhci_unregister_plat(void) { platform_driver_unregister(&xhci_hcd_ikf75xx_driver); }