Angel Pons | c3f58f6 | 2020-04-05 15:46:41 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 2 | |
Furquan Shaikh | 76cedd2 | 2020-05-02 10:24:23 -0700 | [diff] [blame] | 3 | #include <acpi/acpi.h> |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 4 | #include <console/console.h> |
| 5 | #include <device/device.h> |
| 6 | #include <device/pci.h> |
Kyösti Mälkki | f1b58b7 | 2019-03-01 13:43:02 +0200 | [diff] [blame] | 7 | #include <device/pci_ops.h> |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 8 | #include <device/pci_ids.h> |
| 9 | #include <stdint.h> |
| 10 | #include <reg_script.h> |
| 11 | |
Julius Werner | 18ea2d3 | 2014-10-07 16:42:17 -0700 | [diff] [blame] | 12 | #include <soc/iomap.h> |
| 13 | #include <soc/iosf.h> |
| 14 | #include <soc/lpc.h> |
| 15 | #include <soc/pattrs.h> |
| 16 | #include <soc/pci_devs.h> |
Angel Pons | b5320b2 | 2020-07-07 18:27:30 +0200 | [diff] [blame] | 17 | #include <soc/pm.h> |
Julius Werner | 18ea2d3 | 2014-10-07 16:42:17 -0700 | [diff] [blame] | 18 | #include <soc/ramstage.h> |
| 19 | #include <soc/xhci.h> |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 20 | |
| 21 | #include "chip.h" |
| 22 | |
| 23 | struct reg_script usb3_phy_script[] = { |
| 24 | /* USB3PHYInit() */ |
| 25 | REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_CDN_PLL_CONTROL, |
| 26 | ~0x00700000, 0x00500000), |
| 27 | REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_CDN_VCO_START_CAL_POINT, |
| 28 | ~0x001f0000, 0x000A0000), |
| 29 | REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_CCDRLF, |
| 30 | ~0x0000000f, 0x0000000b), |
| 31 | REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_PEAKING_AMP_CONFIG_DIAG, |
| 32 | ~0x000000f0, 0x000000f0), |
| 33 | REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_OFFSET_COR_CONFIG_DIAG, |
| 34 | ~0x000001c0, 0x00000000), |
| 35 | REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_VGA_GAIN_CONFIG_DIAG, |
| 36 | ~0x00000070, 0x00000020), |
| 37 | REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_REE_DAC_CONTROL, |
| 38 | ~0x00000002, 0x00000002), |
| 39 | REG_IOSF_RMW(IOSF_PORT_USHPHY, USHPHY_CDN_U1_POWER_STATE_DEF, |
| 40 | ~0x00000000, 0x00040000), |
| 41 | REG_SCRIPT_END |
| 42 | }; |
| 43 | |
| 44 | const struct reg_script xhci_init_script[] = { |
| 45 | /* CommonXhciHcInit() */ |
| 46 | /* BAR + 0x0c[31:16] = 0x0200 */ |
| 47 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x000c, 0x0000ffff, 0x02000000), |
| 48 | /* BAR + 0x0c[7:0] = 0x0a */ |
| 49 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x000c, 0xffffff00, 0x0000000a), |
| 50 | /* BAR + 0x8094[23,21,14]=111b */ |
| 51 | REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x8094, 0x00a04000), |
| 52 | /* BAR + 0x8110[20,11,8,2]=1100b */ |
| 53 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x8110, ~0x00000104, 0x00100800), |
| 54 | /* BAR + 0x8144[8,7,6]=111b */ |
| 55 | REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x8144, 0x000001c0), |
| 56 | /* BAR + 0x8154[21,13,3]=010b */ |
| 57 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x8154, ~0x00200008, 0x80002000), |
| 58 | /* BAR + 0x816c[19:0]=1110x100000000111100b */ |
| 59 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x816c, 0xfff08000, 0x000e0030), |
| 60 | /* BAR + 0x8188[26,24]=11b */ |
| 61 | REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x8188, 0x05000000), |
| 62 | /* BAR + 0x8174=0x1000c0a*/ |
| 63 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x8174, 0xfe000000, 0x01000c0a), |
| 64 | /* BAR + 0x854c[29]=0b */ |
| 65 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x854c, ~0x20000000, 0), |
| 66 | /* BAR + 0x8178[12:0]=0b */ |
| 67 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x8178, ~0xffffe000, 0), |
| 68 | /* BAR + 0x8164[7:0]=0xff */ |
| 69 | REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x8164, 0x000000ff), |
| 70 | /* BAR + 0x0010[10,9,5]=110b */ |
| 71 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x0010, ~0x00000020, 0x00000600), |
| 72 | /* BAR + 0x8058[20,16,8]=110b */ |
Duncan Laurie | a90a59f5 | 2013-11-04 11:22:27 -0800 | [diff] [blame] | 73 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x8058, ~0x00000100, 0x00110000), |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 74 | /* BAR + 0x8060[25]=1b */ |
| 75 | REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x8060, 0x02000000), |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 76 | /* BAR + 0x80f0[20]=0b */ |
| 77 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x80f0, ~0x00100000, 0), |
| 78 | /* BAR + 0x8008[19]=1b (to enable LPM) */ |
| 79 | REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x8008, 0x00080000), |
| 80 | /* BAR + 0x80fc[25]=1b */ |
| 81 | REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x80fc, 0x02000000), |
| 82 | /* 0x40/0x44 are written as bytes to avoid touching bit31 */ |
| 83 | /* D20:F0:40[21,20,18,10,9,8]=111001b (don't write byte3) */ |
| 84 | REG_PCI_RMW8(0x41, ~0x06, 0x01), |
| 85 | /* Except [21,20,19,18]=0001b USB wake W/A is disable IIL1E */ |
| 86 | REG_PCI_RMW8(0x42, 0x3c, 0x04), |
| 87 | /* D20:F0:44[19:14,10,9,7,3:0]=1 (don't write byte3) */ |
| 88 | REG_PCI_RMW8(0x44, 0x00, 0x8f), |
| 89 | REG_PCI_RMW8(0x45, ~0xcf, 0xc6), |
| 90 | REG_PCI_RMW8(0x46, ~0x0f, 0x0f), |
| 91 | /* BAR + 0x8140 = 0xff00f03c */ |
| 92 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x8140, 0, 0xff00f03c), |
| 93 | REG_SCRIPT_END |
| 94 | }; |
| 95 | |
Shawn Nematbakhsh | 51d787a | 2014-01-16 17:52:21 -0800 | [diff] [blame] | 96 | const struct reg_script xhci_init_boot_script[] = { |
| 97 | /* Setup USB3 phy */ |
| 98 | REG_SCRIPT_NEXT(usb3_phy_script), |
| 99 | /* Initialize host controller */ |
| 100 | REG_SCRIPT_NEXT(xhci_init_script), |
| 101 | /* BAR + 0x80e0[16,9,6]=001b, toggle bit 24=1 */ |
| 102 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x80e0, ~0x00010200, 0x01000040), |
| 103 | /* BAR + 0x80e0 toggle bit 24=0 */ |
| 104 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x80e0, ~0x01000000, 0), |
| 105 | REG_SCRIPT_END |
| 106 | }; |
| 107 | |
| 108 | const struct reg_script xhci_init_resume_script[] = { |
| 109 | /* Setup USB3 phy */ |
| 110 | REG_SCRIPT_NEXT(usb3_phy_script), |
| 111 | /* Initialize host controller */ |
| 112 | REG_SCRIPT_NEXT(xhci_init_script), |
| 113 | /* BAR + 0x80e0[16,9,6]=001b, leave bit 24=0 to prevent HC reset */ |
| 114 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x80e0, ~0x01010200, 0x00000040), |
| 115 | REG_SCRIPT_END |
| 116 | }; |
| 117 | |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 118 | const struct reg_script xhci_clock_gating_script[] = { |
| 119 | /* ConfigureXhciClockGating() */ |
| 120 | /* D20:F0:40[21:19,18,10:8]=000,1,001 (don't write byte 3) */ |
Duncan Laurie | a90a59f5 | 2013-11-04 11:22:27 -0800 | [diff] [blame] | 121 | REG_PCI_RMW16(0x40, ~0x0600, 0x0100), |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 122 | REG_PCI_RMW8(0x42, ~0x38, 0x04), |
| 123 | /* D20:F0:44[5:3]=001b */ |
| 124 | REG_PCI_RMW16(0x44, ~0x0030, 0x0008), |
| 125 | /* D20:F0:A0[19:18]=01b */ |
| 126 | REG_PCI_RMW32(0xa0, ~0x00080000, 0x00040000), |
| 127 | /* D20:F0:A4[15:0]=0x00 */ |
| 128 | REG_PCI_WRITE16(0xa4, 0x0000), |
| 129 | /* D20:F0:B0[21:17,14:13]=0000000b */ |
| 130 | REG_PCI_RMW32(0xb0, ~0x00376000, 0x00000000), |
| 131 | /* D20:F0:50[31:0]=0x0bce6e5f */ |
| 132 | REG_PCI_WRITE32(0x50, 0x0bce6e5f), |
| 133 | REG_SCRIPT_END |
| 134 | }; |
| 135 | |
| 136 | /* Warm Reset a USB3 port */ |
Elyes HAOUAS | 17a3ceb | 2018-05-22 10:42:28 +0200 | [diff] [blame] | 137 | static void xhci_reset_port_usb3(struct device *dev, int port) |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 138 | { |
| 139 | struct reg_script reset_port_usb3_script[] = { |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 140 | /* Issue Warm Port Rest to the port */ |
| 141 | REG_RES_OR32(PCI_BASE_ADDRESS_0, XHCI_USB3_PORTSC(port), |
| 142 | XHCI_USB3_PORTSC_WPR), |
| 143 | /* Wait up to 100ms for it to complete */ |
| 144 | REG_RES_POLL32(PCI_BASE_ADDRESS_0, XHCI_USB3_PORTSC(port), |
| 145 | XHCI_USB3_PORTSC_WRC, XHCI_USB3_PORTSC_WRC, |
| 146 | XHCI_RESET_TIMEOUT), |
| 147 | /* Clear change status bits, do not set PED */ |
| 148 | REG_RES_RMW32(PCI_BASE_ADDRESS_0, XHCI_USB3_PORTSC(port), |
| 149 | ~XHCI_USB3_PORTSC_PED, XHCI_USB3_PORTSC_CHST), |
| 150 | REG_SCRIPT_END |
| 151 | }; |
Aaron Durbin | 616f394 | 2013-12-10 17:12:44 -0800 | [diff] [blame] | 152 | reg_script_run_on_dev(dev, reset_port_usb3_script); |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 153 | } |
| 154 | |
| 155 | /* Prepare ports to be routed to EHCI or XHCI */ |
Elyes HAOUAS | 17a3ceb | 2018-05-22 10:42:28 +0200 | [diff] [blame] | 156 | static void xhci_route_all(struct device *dev) |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 157 | { |
Aaron Durbin | 616f394 | 2013-12-10 17:12:44 -0800 | [diff] [blame] | 158 | static const struct reg_script xhci_route_all_script[] = { |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 159 | /* USB3 SuperSpeed Enable */ |
| 160 | REG_PCI_WRITE32(XHCI_USB3PR, BYTM_USB3_PORT_MAP), |
| 161 | /* USB2 Port Route to XHCI */ |
| 162 | REG_PCI_WRITE32(XHCI_USB2PR, BYTM_USB2_PORT_MAP), |
| 163 | REG_SCRIPT_END |
| 164 | }; |
| 165 | u32 port_disabled; |
| 166 | int port; |
| 167 | |
| 168 | printk(BIOS_INFO, "USB: Route ports to XHCI controller\n"); |
| 169 | |
| 170 | /* Route ports to XHCI controller */ |
Aaron Durbin | 616f394 | 2013-12-10 17:12:44 -0800 | [diff] [blame] | 171 | reg_script_run_on_dev(dev, xhci_route_all_script); |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 172 | |
Kyösti Mälkki | 9e94dbf | 2015-01-08 20:03:18 +0200 | [diff] [blame] | 173 | if (acpi_is_wakeup_s3()) |
Shawn Nematbakhsh | 51d787a | 2014-01-16 17:52:21 -0800 | [diff] [blame] | 174 | return; |
| 175 | |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 176 | /* Reset enabled USB3 ports */ |
| 177 | port_disabled = pci_read_config32(dev, XHCI_USB3PDO); |
| 178 | for (port = 0; port < BYTM_USB3_PORT_COUNT; port++) { |
| 179 | if (port_disabled & (1 << port)) |
| 180 | continue; |
| 181 | xhci_reset_port_usb3(dev, port); |
| 182 | } |
| 183 | } |
| 184 | |
Elyes HAOUAS | 17a3ceb | 2018-05-22 10:42:28 +0200 | [diff] [blame] | 185 | static void xhci_init(struct device *dev) |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 186 | { |
Kyösti Mälkki | 8950cfb | 2019-07-13 22:16:25 +0300 | [diff] [blame] | 187 | struct soc_intel_baytrail_config *config = config_of(dev); |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 188 | struct reg_script xhci_hc_init[] = { |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 189 | /* Initialize clock gating */ |
| 190 | REG_SCRIPT_NEXT(xhci_clock_gating_script), |
Duncan Laurie | a90a59f5 | 2013-11-04 11:22:27 -0800 | [diff] [blame] | 191 | /* Finalize XHCC1 and XHCC2 */ |
| 192 | REG_PCI_RMW32(0x44, ~0x00000000, 0x83c00000), |
| 193 | REG_PCI_RMW32(0x40, ~0x00800000, 0x80000000), |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 194 | /* Set USB2 Port Routing Mask */ |
| 195 | REG_PCI_WRITE32(XHCI_USB2PRM, BYTM_USB2_PORT_MAP), |
| 196 | /* Set USB3 Port Routing Mask */ |
| 197 | REG_PCI_WRITE32(XHCI_USB3PRM, BYTM_USB3_PORT_MAP), |
| 198 | /* |
| 199 | * Disable ports if requested |
| 200 | */ |
| 201 | /* Open per-port disable control override */ |
| 202 | REG_IO_RMW16(ACPI_BASE_ADDRESS + UPRWC, ~0, UPRWC_WR_EN), |
| 203 | REG_PCI_WRITE32(XHCI_USB2PDO, config->usb2_port_disable_mask), |
| 204 | REG_PCI_WRITE32(XHCI_USB3PDO, config->usb3_port_disable_mask), |
| 205 | /* Close per-port disable control override */ |
| 206 | REG_IO_RMW16(ACPI_BASE_ADDRESS + UPRWC, ~UPRWC_WR_EN, 0), |
| 207 | REG_SCRIPT_END |
| 208 | }; |
| 209 | |
Shawn Nematbakhsh | 51d787a | 2014-01-16 17:52:21 -0800 | [diff] [blame] | 210 | /* Initialize XHCI controller for boot or resume path */ |
Kyösti Mälkki | 9e94dbf | 2015-01-08 20:03:18 +0200 | [diff] [blame] | 211 | if (acpi_is_wakeup_s3()) |
Shawn Nematbakhsh | 51d787a | 2014-01-16 17:52:21 -0800 | [diff] [blame] | 212 | reg_script_run_on_dev(dev, xhci_init_resume_script); |
| 213 | else |
| 214 | reg_script_run_on_dev(dev, xhci_init_boot_script); |
| 215 | |
Kein Yuan | c9bf446 | 2014-06-27 09:12:57 -0700 | [diff] [blame] | 216 | /* C0 steppings change iCLK/USB PLL VCO settings from 5 to 7 */ |
| 217 | if (pattrs_get()->stepping == STEP_C0) { |
| 218 | uint32_t reg = iosf_ushphy_read(USHPHY_CDN_PLL_CONTROL); |
| 219 | reg |= 0x00700000; |
| 220 | iosf_ushphy_write(USHPHY_CDN_PLL_CONTROL, reg); |
| 221 | } |
| 222 | |
Shawn Nematbakhsh | 51d787a | 2014-01-16 17:52:21 -0800 | [diff] [blame] | 223 | /* Finalize Initialization */ |
Aaron Durbin | 616f394 | 2013-12-10 17:12:44 -0800 | [diff] [blame] | 224 | reg_script_run_on_dev(dev, xhci_hc_init); |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 225 | |
| 226 | /* Route all ports to XHCI if requested */ |
| 227 | if (config->usb_route_to_xhci) |
| 228 | xhci_route_all(dev); |
| 229 | } |
| 230 | |
| 231 | static struct device_operations xhci_device_ops = { |
| 232 | .read_resources = pci_dev_read_resources, |
| 233 | .set_resources = pci_dev_set_resources, |
| 234 | .enable_resources = pci_dev_enable_resources, |
| 235 | .init = xhci_init, |
| 236 | .ops_pci = &soc_pci_ops, |
| 237 | }; |
| 238 | |
| 239 | static const struct pci_driver baytrail_xhci __pci_driver = { |
| 240 | .ops = &xhci_device_ops, |
Felix Singer | 43b7f41 | 2022-03-07 04:34:52 +0100 | [diff] [blame] | 241 | .vendor = PCI_VID_INTEL, |
Duncan Laurie | f81a91a | 2013-11-01 13:32:53 -0700 | [diff] [blame] | 242 | .device = XHCI_DEVID |
| 243 | }; |