From f81a91a768f54ef25aa6019fb40d3b98a3cb18c2 Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Fri, 1 Nov 2013 13:32:53 -0700 Subject: baytrail: Add XHCI initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds required steps to initialize the XHCI controller on the baytrail platform. Actually using XHCI is causing lots of bad behavior including apparent memory corruption. BUG=chrome-os-partner:23635 BRANCH=rambi TEST=build and boot on rambi Change-Id: Ic43e04f4b47e107ec3bb0c387a9fc72c3cae0271 Signed-off-by: Duncan Laurie Reviewed-on: https://chromium-review.googlesource.com/175511 Signed-off-by: Aaron Durbin Reviewed-on: http://review.coreboot.org/4929 Tested-by: build bot (Jenkins) Reviewed-by: Kyösti Mälkki --- src/soc/intel/baytrail/Makefile.inc | 1 + src/soc/intel/baytrail/baytrail/iosf.h | 12 ++ src/soc/intel/baytrail/baytrail/pmc.h | 1 + src/soc/intel/baytrail/baytrail/xhci.h | 56 ++++++++ src/soc/intel/baytrail/chip.h | 7 + src/soc/intel/baytrail/xhci.c | 226 +++++++++++++++++++++++++++++++++ 6 files changed, 303 insertions(+) create mode 100644 src/soc/intel/baytrail/baytrail/xhci.h create mode 100644 src/soc/intel/baytrail/xhci.c (limited to 'src/soc') diff --git a/src/soc/intel/baytrail/Makefile.inc b/src/soc/intel/baytrail/Makefile.inc index 2149e975ce..9a8231652b 100644 --- a/src/soc/intel/baytrail/Makefile.inc +++ b/src/soc/intel/baytrail/Makefile.inc @@ -31,6 +31,7 @@ ramstage-y += pmutil.c smm-y += pmutil.c smm-y += smihandler.c ramstage-y += smm.c +ramstage-y += xhci.c ramstage-y += southcluster.c ramstage-$(CONFIG_HAVE_REFCODE_BLOB) += refcode.c ramstage-y += sata.c diff --git a/src/soc/intel/baytrail/baytrail/iosf.h b/src/soc/intel/baytrail/baytrail/iosf.h index 83e03a5a8c..f26902289b 100644 --- a/src/soc/intel/baytrail/baytrail/iosf.h +++ b/src/soc/intel/baytrail/baytrail/iosf.h @@ -214,4 +214,16 @@ void iosf_ccu_write(int reg, uint32_t val); # define PLT_CLK_CTRL_25MHZ_FREQ (1 << 1) # define PLT_CLK_CTRL_SELECT_FREQ (1 << 0) +/* + * USHPHY Registers + */ +#define USHPHY_CDN_PLL_CONTROL 0x03c0 +#define USHPHY_CDN_VCO_START_CAL_POINT 0x0054 +#define USHPHY_CCDRLF 0x8040 +#define USHPHY_PEAKING_AMP_CONFIG_DIAG 0x80a8 +#define USHPHY_OFFSET_COR_CONFIG_DIAG 0x80b0 +#define USHPHY_VGA_GAIN_CONFIG_DIAG 0x8080 +#define USHPHY_REE_DAC_CONTROL 0x80b8 +#define USHPHY_CDN_U1_POWER_STATE_DEF 0x0000 + #endif /* _BAYTRAIL_IOSF_H_ */ diff --git a/src/soc/intel/baytrail/baytrail/pmc.h b/src/soc/intel/baytrail/baytrail/pmc.h index 51f888730c..92edb6ef64 100644 --- a/src/soc/intel/baytrail/baytrail/pmc.h +++ b/src/soc/intel/baytrail/baytrail/pmc.h @@ -165,6 +165,7 @@ #define SMI_STS 0x34 #define ALT_GPIO_SMI 0x38 #define UPRWC 0x3c +# define UPRWC_WR_EN (1 << 1) // USB Per-Port Registers Write Enable #define GPE_CTRL 0x40 #define PM2A_CNT_BLK 0x50 #define TCO_RLD 0x60 diff --git a/src/soc/intel/baytrail/baytrail/xhci.h b/src/soc/intel/baytrail/baytrail/xhci.h new file mode 100644 index 0000000000..b317361c08 --- /dev/null +++ b/src/soc/intel/baytrail/baytrail/xhci.h @@ -0,0 +1,56 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef BAYTRAIL_XHCI_H +#define BAYTRAIL_XHCI_H + +/* XHCI PCI Registers */ +#define XHCI_PWR_CTL_STS 0x74 +#define XHCI_USB2PR 0xd0 +#define XHCI_USB2PRM 0xd4 +#define XHCI_USB3PR 0xd8 +#define XHCI_USB3PRM 0xdc +#define XHCI_USB2PDO 0xe4 +#define XHCI_USB3PDO 0xe8 + +/* XHCI Memory Registers */ +#define XHCI_USB3_PORTSC(port) (0x4e0 + (port * 0x10)) +# define XHCI_USB3_PORTSC_CHST (0x7f << 17) +# define XHCI_USB3_PORTSC_WCE (1 << 25) /* Wake on Connect */ +# define XHCI_USB3_PORTSC_WDE (1 << 26) /* Wake on Disconnect */ +# define XHCI_USB3_PORTSC_WOE (1 << 27) /* Wake on Overcurrent */ +# define XHCI_USB3_PORTSC_WRC (1 << 19) /* Warm Reset Complete */ +# define XHCI_USB3_PORTSC_LWS (1 << 16) /* Link Write Strobe */ +# define XHCI_USB3_PORTSC_PED (1 << 1) /* Port Enabled/Disabled */ +# define XHCI_USB3_PORTSC_WPR (1 << 31) /* Warm Port Reset */ +# define XHCI_USB3_PORTSC_PLS (0xf << 5) /* Port Link State */ +# define XHCI_PLSR_DISABLED (4 << 5) /* Port is disabled */ +# define XHCI_PLSR_RXDETECT (5 << 5) /* Port is disconnected */ +# define XHCI_PLSR_POLLING (7 << 5) /* Port is polling */ +# define XHCI_PLSW_ENABLE (5 << 5) /* Enable port */ + +/* The Fuse register is incorrect for Baytrail-M so use hardcoded values */ +#define BYTM_USB2_PORT_COUNT 4 +#define BYTM_USB2_PORT_MAP 0xf +#define BYTM_USB3_PORT_COUNT 1 +#define BYTM_USB3_PORT_MAP 0x1 + +#define XHCI_RESET_TIMEOUT 100000 /* 100ms */ + +#endif /* BAYTRAIL_XHCI_H */ diff --git a/src/soc/intel/baytrail/chip.h b/src/soc/intel/baytrail/chip.h index d17474faba..38dd8068bd 100644 --- a/src/soc/intel/baytrail/chip.h +++ b/src/soc/intel/baytrail/chip.h @@ -29,6 +29,13 @@ struct soc_intel_baytrail_config { uint8_t sata_port_map; uint8_t sata_ahci; uint8_t ide_legacy_combined; + + /* USB Port Disable mask */ + uint16_t usb2_port_disable_mask; + uint16_t usb3_port_disable_mask; + + /* USB routing */ + int usb_route_to_xhci; }; extern struct chip_operations soc_intel_baytrail_ops; diff --git a/src/soc/intel/baytrail/xhci.c b/src/soc/intel/baytrail/xhci.c new file mode 100644 index 0000000000..244a4dcec7 --- /dev/null +++ b/src/soc/intel/baytrail/xhci.c @@ -0,0 +1,226 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2013 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "chip.h" + +struct reg_script usb3_phy_script[] = { + /* USB3PHYInit() */ + REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_CDN_PLL_CONTROL, + ~0x00700000, 0x00500000), + REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_CDN_VCO_START_CAL_POINT, + ~0x001f0000, 0x000A0000), + REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_CCDRLF, + ~0x0000000f, 0x0000000b), + REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_PEAKING_AMP_CONFIG_DIAG, + ~0x000000f0, 0x000000f0), + REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_OFFSET_COR_CONFIG_DIAG, + ~0x000001c0, 0x00000000), + REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_VGA_GAIN_CONFIG_DIAG, + ~0x00000070, 0x00000020), + REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_REE_DAC_CONTROL, + ~0x00000002, 0x00000002), + REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_CDN_U1_POWER_STATE_DEF, + ~0x00000000, 0x00040000), + REG_SCRIPT_END +}; + +const struct reg_script xhci_init_script[] = { + /* CommonXhciHcInit() */ + /* BAR + 0x0c[31:16] = 0x0200 */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x000c, 0x0000ffff, 0x02000000), + /* BAR + 0x0c[7:0] = 0x0a */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x000c, 0xffffff00, 0x0000000a), + /* BAR + 0x8094[23,21,14]=111b */ + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x8094, 0x00a04000), + /* BAR + 0x8110[20,11,8,2]=1100b */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x8110, ~0x00000104, 0x00100800), + /* BAR + 0x8144[8,7,6]=111b */ + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x8144, 0x000001c0), + /* BAR + 0x8154[21,13,3]=010b */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x8154, ~0x00200008, 0x80002000), + /* BAR + 0x816c[19:0]=1110x100000000111100b */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x816c, 0xfff08000, 0x000e0030), + /* BAR + 0x8188[26,24]=11b */ + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x8188, 0x05000000), + /* BAR + 0x8174=0x1000c0a*/ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x8174, 0xfe000000, 0x01000c0a), + /* BAR + 0x854c[29]=0b */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x854c, ~0x20000000, 0), + /* BAR + 0x8178[12:0]=0b */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x8178, ~0xffffe000, 0), + /* BAR + 0x8164[7:0]=0xff */ + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x8164, 0x000000ff), + /* BAR + 0x0010[10,9,5]=110b */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x0010, ~0x00000020, 0x00000600), + /* BAR + 0x8058[20,16,8]=110b */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x8058, ~0x00000010, 0x00110000), + /* BAR + 0x8060[25]=1b */ + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x8060, 0x02000000), + /* BAR + 0x80e0[19,9,6]=001b, toggle bit 24=1 */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x80e0, ~0x00010020, 0x01000040), + /* BAR + 0x80e0 toggle bit 24=0 */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x80e0, ~0x01000000, 0), + /* BAR + 0x80f0[20]=0b */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x80f0, ~0x00100000, 0), + /* BAR + 0x8008[19]=1b (to enable LPM) */ + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x8008, 0x00080000), + /* BAR + 0x80fc[25]=1b */ + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x80fc, 0x02000000), + /* 0x40/0x44 are written as bytes to avoid touching bit31 */ + /* D20:F0:40[21,20,18,10,9,8]=111001b (don't write byte3) */ + REG_PCI_RMW8(0x41, ~0x06, 0x01), + /* Except [21,20,19,18]=0001b USB wake W/A is disable IIL1E */ + REG_PCI_RMW8(0x42, 0x3c, 0x04), + /* D20:F0:44[19:14,10,9,7,3:0]=1 (don't write byte3) */ + REG_PCI_RMW8(0x44, 0x00, 0x8f), + REG_PCI_RMW8(0x45, ~0xcf, 0xc6), + REG_PCI_RMW8(0x46, ~0x0f, 0x0f), + /* BAR + 0x8140 = 0xff00f03c */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x8140, 0, 0xff00f03c), + REG_SCRIPT_END +}; + +const struct reg_script xhci_clock_gating_script[] = { + /* ConfigureXhciClockGating() */ + /* D20:F0:40[21:19,18,10:8]=000,1,001 (don't write byte 3) */ + REG_PCI_RMW16(0x40, ~0x0300, 0x0010), + REG_PCI_RMW8(0x42, ~0x38, 0x04), + /* D20:F0:44[5:3]=001b */ + REG_PCI_RMW16(0x44, ~0x0030, 0x0008), + /* D20:F0:A0[19:18]=01b */ + REG_PCI_RMW32(0xa0, ~0x00080000, 0x00040000), + /* D20:F0:A4[15:0]=0x00 */ + REG_PCI_WRITE16(0xa4, 0x0000), + /* D20:F0:B0[21:17,14:13]=0000000b */ + REG_PCI_RMW32(0xb0, ~0x00376000, 0x00000000), + /* D20:F0:50[31:0]=0x0bce6e5f */ + REG_PCI_WRITE32(0x50, 0x0bce6e5f), + REG_SCRIPT_END +}; + +/* Warm Reset a USB3 port */ +static void xhci_reset_port_usb3(device_t dev, int port) +{ + struct reg_script reset_port_usb3_script[] = { + REG_SCRIPT_SET_DEV(dev), + /* Issue Warm Port Rest to the port */ + REG_RES_OR32(PCI_BASE_ADDRESS_0, XHCI_USB3_PORTSC(port), + XHCI_USB3_PORTSC_WPR), + /* Wait up to 100ms for it to complete */ + REG_RES_POLL32(PCI_BASE_ADDRESS_0, XHCI_USB3_PORTSC(port), + XHCI_USB3_PORTSC_WRC, XHCI_USB3_PORTSC_WRC, + XHCI_RESET_TIMEOUT), + /* Clear change status bits, do not set PED */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, XHCI_USB3_PORTSC(port), + ~XHCI_USB3_PORTSC_PED, XHCI_USB3_PORTSC_CHST), + REG_SCRIPT_END + }; + reg_script_run(reset_port_usb3_script); +} + +/* Prepare ports to be routed to EHCI or XHCI */ +static void xhci_route_all(device_t dev) +{ + struct reg_script xhci_route_all_script[] = { + REG_SCRIPT_SET_DEV(dev), + /* USB3 SuperSpeed Enable */ + REG_PCI_WRITE32(XHCI_USB3PR, BYTM_USB3_PORT_MAP), + /* USB2 Port Route to XHCI */ + REG_PCI_WRITE32(XHCI_USB2PR, BYTM_USB2_PORT_MAP), + REG_SCRIPT_END + }; + u32 port_disabled; + int port; + + printk(BIOS_INFO, "USB: Route ports to XHCI controller\n"); + + /* Route ports to XHCI controller */ + reg_script_run(xhci_route_all_script); + + /* Reset enabled USB3 ports */ + port_disabled = pci_read_config32(dev, XHCI_USB3PDO); + for (port = 0; port < BYTM_USB3_PORT_COUNT; port++) { + if (port_disabled & (1 << port)) + continue; + xhci_reset_port_usb3(dev, port); + } +} + +static void xhci_init(device_t dev) +{ + struct soc_intel_baytrail_config *config = dev->chip_info; + struct reg_script xhci_hc_init[] = { + REG_SCRIPT_SET_DEV(dev), + /* Setup USB3 phy */ + REG_SCRIPT_NEXT(usb3_phy_script), + /* Initialize host controller */ + REG_SCRIPT_NEXT(xhci_init_script), + /* Initialize clock gating */ + REG_SCRIPT_NEXT(xhci_clock_gating_script), + /* Set USB2 Port Routing Mask */ + REG_PCI_WRITE32(XHCI_USB2PRM, BYTM_USB2_PORT_MAP), + /* Set USB3 Port Routing Mask */ + REG_PCI_WRITE32(XHCI_USB3PRM, BYTM_USB3_PORT_MAP), + /* + * Disable ports if requested + */ + /* Open per-port disable control override */ + REG_IO_RMW16(ACPI_BASE_ADDRESS + UPRWC, ~0, UPRWC_WR_EN), + REG_PCI_WRITE32(XHCI_USB2PDO, config->usb2_port_disable_mask), + REG_PCI_WRITE32(XHCI_USB3PDO, config->usb3_port_disable_mask), + /* Close per-port disable control override */ + REG_IO_RMW16(ACPI_BASE_ADDRESS + UPRWC, ~UPRWC_WR_EN, 0), + REG_SCRIPT_END + }; + + /* Initialize XHCI controller */ + reg_script_run(xhci_hc_init); + + /* Route all ports to XHCI if requested */ + if (config->usb_route_to_xhci) + xhci_route_all(dev); +} + +static struct device_operations xhci_device_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = xhci_init, + .ops_pci = &soc_pci_ops, +}; + +static const struct pci_driver baytrail_xhci __pci_driver = { + .ops = &xhci_device_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = XHCI_DEVID +}; -- cgit v1.2.3