Kyösti Mälkki | e8b4da2 | 2014-10-21 18:22:32 +0300 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright (C) 2010 Advanced Micro Devices, Inc. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; version 2 of the License. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
Kyösti Mälkki | e8b4da2 | 2014-10-21 18:22:32 +0300 | [diff] [blame] | 14 | */ |
| 15 | |
| 16 | #ifndef _HUDSON_EARLY_SETUP_C_ |
| 17 | #define _HUDSON_EARLY_SETUP_C_ |
| 18 | |
Marc Jones | f962aa5 | 2017-03-22 18:47:49 +0800 | [diff] [blame] | 19 | #include <assert.h> |
Kyösti Mälkki | e8b4da2 | 2014-10-21 18:22:32 +0300 | [diff] [blame] | 20 | #include <stdint.h> |
| 21 | #include <arch/io.h> |
| 22 | #include <arch/acpi.h> |
| 23 | #include <console/console.h> |
| 24 | #include <reset.h> |
| 25 | #include <arch/cpu.h> |
| 26 | #include <cbmem.h> |
| 27 | #include "hudson.h" |
Dave Frodin | f364fc7 | 2015-03-13 08:22:17 -0600 | [diff] [blame] | 28 | #include "pci_devs.h" |
Piotr Król | dcd2f17 | 2016-05-27 12:04:13 +0200 | [diff] [blame] | 29 | #include <Fch/Fch.h> |
Kyösti Mälkki | e8b4da2 | 2014-10-21 18:22:32 +0300 | [diff] [blame] | 30 | |
Zheng Bao | 2286138 | 2015-11-21 12:19:22 +0800 | [diff] [blame] | 31 | #if IS_ENABLED(CONFIG_HUDSON_UART) |
| 32 | |
| 33 | #include <cpu/x86/msr.h> |
| 34 | #include <delay.h> |
Zheng Bao | 2286138 | 2015-11-21 12:19:22 +0800 | [diff] [blame] | 35 | |
| 36 | void configure_hudson_uart(void) |
| 37 | { |
Zheng Bao | 2286138 | 2015-11-21 12:19:22 +0800 | [diff] [blame] | 38 | u8 byte; |
| 39 | |
Zheng Bao | 2286138 | 2015-11-21 12:19:22 +0800 | [diff] [blame] | 40 | byte = read8((void *)ACPI_MMIO_BASE + AOAC_BASE + FCH_AOAC_REG56 + CONFIG_UART_FOR_CONSOLE * 2); |
| 41 | byte |= 1 << 3; |
| 42 | write8((void *)ACPI_MMIO_BASE + AOAC_BASE + FCH_AOAC_REG56 + CONFIG_UART_FOR_CONSOLE * 2, byte); |
| 43 | byte = read8((void *)ACPI_MMIO_BASE + AOAC_BASE + FCH_AOAC_REG62); |
| 44 | byte |= 1 << 3; |
| 45 | write8((void *)ACPI_MMIO_BASE + AOAC_BASE + FCH_AOAC_REG62, byte); |
| 46 | write8((void *)FCH_IOMUXx89_UART0_RTS_L_EGPIO137, 0); |
| 47 | write8((void *)FCH_IOMUXx8A_UART0_TXD_EGPIO138, 0); |
| 48 | write8((void *)FCH_IOMUXx8E_UART1_RTS_L_EGPIO142, 0); |
| 49 | write8((void *)FCH_IOMUXx8F_UART1_TXD_EGPIO143, 0); |
| 50 | |
| 51 | udelay(2000); |
| 52 | write8((void *)0xFEDC6000 + 0x2000 * CONFIG_UART_FOR_CONSOLE + 0x88, 0x01); /* reset UART */ |
| 53 | } |
| 54 | |
| 55 | #endif |
| 56 | |
Kyösti Mälkki | e8b4da2 | 2014-10-21 18:22:32 +0300 | [diff] [blame] | 57 | void hudson_pci_port80(void) |
| 58 | { |
| 59 | u8 byte; |
Antonello Dettori | 1ac9728 | 2016-09-03 10:45:33 +0200 | [diff] [blame] | 60 | pci_devfn_t dev; |
Kyösti Mälkki | e8b4da2 | 2014-10-21 18:22:32 +0300 | [diff] [blame] | 61 | |
| 62 | /* P2P Bridge */ |
| 63 | dev = PCI_DEV(0, 0x14, 4); |
| 64 | |
| 65 | /* Chip Control: Enable subtractive decoding */ |
| 66 | byte = pci_read_config8(dev, 0x40); |
| 67 | byte |= 1 << 5; |
| 68 | pci_write_config8(dev, 0x40, byte); |
| 69 | |
| 70 | /* Misc Control: Enable subtractive decoding if 0x40 bit 5 is set */ |
| 71 | byte = pci_read_config8(dev, 0x4B); |
| 72 | byte |= 1 << 7; |
| 73 | pci_write_config8(dev, 0x4B, byte); |
| 74 | |
| 75 | /* The same IO Base and IO Limit here is meaningful because we set the |
| 76 | * bridge to be subtractive. During early setup stage, we have to make |
| 77 | * sure that data can go through port 0x80. |
| 78 | */ |
| 79 | /* IO Base: 0xf000 */ |
| 80 | byte = pci_read_config8(dev, 0x1C); |
| 81 | byte |= 0xF << 4; |
| 82 | pci_write_config8(dev, 0x1C, byte); |
| 83 | |
| 84 | /* IO Limit: 0xf000 */ |
| 85 | byte = pci_read_config8(dev, 0x1D); |
| 86 | byte |= 0xF << 4; |
| 87 | pci_write_config8(dev, 0x1D, byte); |
| 88 | |
| 89 | /* PCI Command: Enable IO response */ |
| 90 | byte = pci_read_config8(dev, 0x04); |
| 91 | byte |= 1 << 0; |
| 92 | pci_write_config8(dev, 0x04, byte); |
| 93 | |
| 94 | /* LPC controller */ |
| 95 | dev = PCI_DEV(0, 0x14, 3); |
| 96 | |
| 97 | byte = pci_read_config8(dev, 0x4A); |
| 98 | byte &= ~(1 << 5); /* disable lpc port 80 */ |
| 99 | pci_write_config8(dev, 0x4A, byte); |
| 100 | } |
| 101 | |
| 102 | void hudson_lpc_port80(void) |
| 103 | { |
| 104 | u8 byte; |
Antonello Dettori | 1ac9728 | 2016-09-03 10:45:33 +0200 | [diff] [blame] | 105 | pci_devfn_t dev; |
Kyösti Mälkki | e8b4da2 | 2014-10-21 18:22:32 +0300 | [diff] [blame] | 106 | |
| 107 | /* Enable LPC controller */ |
| 108 | outb(0xEC, 0xCD6); |
| 109 | byte = inb(0xCD7); |
| 110 | byte |= 1; |
| 111 | outb(0xEC, 0xCD6); |
| 112 | outb(byte, 0xCD7); |
| 113 | |
| 114 | /* Enable port 80 LPC decode in pci function 3 configuration space. */ |
| 115 | dev = PCI_DEV(0, 0x14, 3); |
| 116 | byte = pci_read_config8(dev, 0x4a); |
| 117 | byte |= 1 << 5; /* enable port 80 */ |
| 118 | pci_write_config8(dev, 0x4a, byte); |
| 119 | } |
| 120 | |
Dave Frodin | f364fc7 | 2015-03-13 08:22:17 -0600 | [diff] [blame] | 121 | void hudson_lpc_decode(void) |
| 122 | { |
Antonello Dettori | 1ac9728 | 2016-09-03 10:45:33 +0200 | [diff] [blame] | 123 | pci_devfn_t dev; |
Dave Frodin | f364fc7 | 2015-03-13 08:22:17 -0600 | [diff] [blame] | 124 | u32 tmp = 0; |
| 125 | |
| 126 | /* Enable I/O decode to LPC bus */ |
| 127 | dev = PCI_DEV(0, PCU_DEV, LPC_FUNC); |
| 128 | tmp = DECODE_ENABLE_PARALLEL_PORT0 | DECODE_ENABLE_PARALLEL_PORT2 |
| 129 | | DECODE_ENABLE_PARALLEL_PORT4 | DECODE_ENABLE_SERIAL_PORT0 |
| 130 | | DECODE_ENABLE_SERIAL_PORT1 | DECODE_ENABLE_SERIAL_PORT2 |
| 131 | | DECODE_ENABLE_SERIAL_PORT3 | DECODE_ENABLE_SERIAL_PORT4 |
| 132 | | DECODE_ENABLE_SERIAL_PORT5 | DECODE_ENABLE_SERIAL_PORT6 |
| 133 | | DECODE_ENABLE_SERIAL_PORT7 | DECODE_ENABLE_AUDIO_PORT0 |
| 134 | | DECODE_ENABLE_AUDIO_PORT1 | DECODE_ENABLE_AUDIO_PORT2 |
| 135 | | DECODE_ENABLE_AUDIO_PORT3 | DECODE_ENABLE_MSS_PORT2 |
| 136 | | DECODE_ENABLE_MSS_PORT3 | DECODE_ENABLE_FDC_PORT0 |
| 137 | | DECODE_ENABLE_FDC_PORT1 | DECODE_ENABLE_GAME_PORT |
| 138 | | DECODE_ENABLE_KBC_PORT | DECODE_ENABLE_ACPIUC_PORT |
| 139 | | DECODE_ENABLE_ADLIB_PORT; |
| 140 | |
| 141 | pci_write_config32(dev, LPC_IO_PORT_DECODE_ENABLE, tmp); |
| 142 | } |
| 143 | |
Marc Jones | f962aa5 | 2017-03-22 18:47:49 +0800 | [diff] [blame] | 144 | static void enable_wideio(uint8_t port, uint16_t size) |
| 145 | { |
| 146 | uint32_t wideio_enable[] = { |
| 147 | LPC_WIDEIO0_ENABLE, |
| 148 | LPC_WIDEIO1_ENABLE, |
| 149 | LPC_WIDEIO2_ENABLE |
| 150 | }; |
| 151 | uint32_t alt_wideio_enable[] = { |
| 152 | LPC_ALT_WIDEIO0_ENABLE, |
| 153 | LPC_ALT_WIDEIO1_ENABLE, |
| 154 | LPC_ALT_WIDEIO2_ENABLE |
| 155 | }; |
| 156 | pci_devfn_t dev = PCI_DEV(0, PCU_DEV, LPC_FUNC); |
| 157 | uint32_t tmp; |
| 158 | |
| 159 | /* Only allow port 0-2 */ |
| 160 | assert(port <= ARRAY_SIZE(wideio_enable)); |
| 161 | |
| 162 | if (size == 16) { |
| 163 | tmp = pci_read_config32(dev, LPC_ALT_WIDEIO_RANGE_ENABLE); |
| 164 | tmp |= alt_wideio_enable[port]; |
| 165 | pci_write_config32(dev, LPC_ALT_WIDEIO_RANGE_ENABLE, tmp); |
| 166 | } else { /* 512 */ |
| 167 | tmp = pci_read_config32(dev, LPC_ALT_WIDEIO_RANGE_ENABLE); |
| 168 | tmp &= ~alt_wideio_enable[port]; |
| 169 | pci_write_config32(dev, LPC_ALT_WIDEIO_RANGE_ENABLE, tmp); |
| 170 | } |
| 171 | |
| 172 | /* Enable the range */ |
| 173 | tmp = pci_read_config32(dev, LPC_IO_OR_MEM_DECODE_ENABLE); |
| 174 | tmp |= wideio_enable[port]; |
| 175 | pci_write_config32(dev, LPC_IO_OR_MEM_DECODE_ENABLE, tmp); |
| 176 | } |
| 177 | |
| 178 | /* |
| 179 | * lpc_wideio_window() may be called any point in romstage, but take |
| 180 | * care that AGESA doesn't overwrite the range this function used. |
| 181 | * The function checks if there is an empty range and if all ranges are |
| 182 | * used the function throws an assert. The function doesn't check for a |
| 183 | * duplicate range, for ranges that can be merged into a single |
| 184 | * range, or ranges that overlap. |
| 185 | * |
| 186 | * The developer is expected to ensure that there are no conflicts. |
| 187 | */ |
| 188 | static void lpc_wideio_window(uint16_t base, uint16_t size) |
| 189 | { |
| 190 | pci_devfn_t dev = PCI_DEV(0, PCU_DEV, LPC_FUNC); |
| 191 | u32 tmp; |
| 192 | |
| 193 | /* Support 512 or 16 bytes per range */ |
| 194 | assert(size == 512 || size == 16); |
| 195 | |
| 196 | /* Find and open Base Register and program it */ |
| 197 | tmp = pci_read_config32(dev, LPC_WIDEIO_GENERIC_PORT); |
| 198 | |
| 199 | if ((tmp & 0xFFFF) == 0) { /* WIDEIO0 */ |
| 200 | tmp |= base; |
| 201 | pci_write_config32(dev, LPC_WIDEIO_GENERIC_PORT, tmp); |
| 202 | enable_wideio(0, size); |
| 203 | } else if ((tmp & 0xFFFF0000) == 0) { /* WIDEIO1 */ |
| 204 | tmp |= (base << 16); |
| 205 | pci_write_config32(dev, LPC_WIDEIO_GENERIC_PORT, tmp); |
| 206 | enable_wideio(1, size); |
| 207 | } else { /* Check WIDEIO2 register */ |
| 208 | tmp = pci_read_config32(dev, LPC_WIDEIO2_GENERIC_PORT); |
| 209 | if ((tmp & 0xFFFF) == 0) { /* WIDEIO2 */ |
| 210 | tmp |= base; |
| 211 | pci_write_config32(dev, LPC_WIDEIO2_GENERIC_PORT, tmp); |
| 212 | enable_wideio(2, size); |
| 213 | } else { /* All WIDEIO locations used*/ |
| 214 | assert(0); |
| 215 | } |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | void lpc_wideio_512_window(uint16_t base) |
| 220 | { |
| 221 | assert(IS_ALIGNED(base, 512)); |
| 222 | lpc_wideio_window(base, 512); |
| 223 | } |
| 224 | |
| 225 | void lpc_wideio_16_window(uint16_t base) |
| 226 | { |
| 227 | assert(IS_ALIGNED(base, 16)); |
| 228 | lpc_wideio_window(base, 16); |
| 229 | } |
| 230 | |
Kyösti Mälkki | e8b4da2 | 2014-10-21 18:22:32 +0300 | [diff] [blame] | 231 | int s3_save_nvram_early(u32 dword, int size, int nvram_pos) |
| 232 | { |
| 233 | int i; |
| 234 | printk(BIOS_DEBUG, "Writing %x of size %d to nvram pos: %d\n", dword, size, nvram_pos); |
| 235 | |
Elyes HAOUAS | c021ffe | 2016-09-18 19:18:56 +0200 | [diff] [blame] | 236 | for (i = 0; i < size; i++) { |
Kyösti Mälkki | e8b4da2 | 2014-10-21 18:22:32 +0300 | [diff] [blame] | 237 | outb(nvram_pos, BIOSRAM_INDEX); |
| 238 | outb((dword >>(8 * i)) & 0xff , BIOSRAM_DATA); |
| 239 | nvram_pos++; |
| 240 | } |
| 241 | |
| 242 | return nvram_pos; |
| 243 | } |
| 244 | |
| 245 | int s3_load_nvram_early(int size, u32 *old_dword, int nvram_pos) |
| 246 | { |
| 247 | u32 data = *old_dword; |
| 248 | int i; |
Elyes HAOUAS | c021ffe | 2016-09-18 19:18:56 +0200 | [diff] [blame] | 249 | for (i = 0; i < size; i++) { |
Kyösti Mälkki | e8b4da2 | 2014-10-21 18:22:32 +0300 | [diff] [blame] | 250 | outb(nvram_pos, BIOSRAM_INDEX); |
| 251 | data &= ~(0xff << (i * 8)); |
| 252 | data |= inb(BIOSRAM_DATA) << (i *8); |
| 253 | nvram_pos++; |
| 254 | } |
| 255 | *old_dword = data; |
| 256 | printk(BIOS_DEBUG, "Loading %x of size %d to nvram pos:%d\n", *old_dword, size, |
| 257 | nvram_pos-size); |
| 258 | return nvram_pos; |
| 259 | } |
| 260 | |
Piotr Król | dcd2f17 | 2016-05-27 12:04:13 +0200 | [diff] [blame] | 261 | void hudson_clk_output_48Mhz(void) |
| 262 | { |
| 263 | u32 data, *memptr; |
| 264 | |
| 265 | /* |
| 266 | * Enable the X14M_25M_48M_OSC pin and leaving it at it's default so |
| 267 | * 48Mhz will be on ball AP13 (FT3b package) |
| 268 | */ |
| 269 | memptr = (u32 *)(ACPI_MMIO_BASE + MISC_BASE + FCH_MISC_REG40 ); |
| 270 | data = *memptr; |
| 271 | |
| 272 | /* clear the OSCOUT1_ClkOutputEnb to enable the 48 Mhz clock */ |
| 273 | data &= (u32)~(1<<2); |
| 274 | *memptr = data; |
| 275 | } |
| 276 | |
Marshall Dawson | 91dea4a | 2017-02-10 16:03:54 -0700 | [diff] [blame] | 277 | static uintptr_t hudson_spibase(void) |
| 278 | { |
| 279 | /* Make sure the base address is predictable */ |
| 280 | device_t dev = PCI_DEV(0, 0x14, 3); |
| 281 | |
| 282 | u32 base = pci_read_config32(dev, SPIROM_BASE_ADDRESS_REGISTER) |
| 283 | & 0xfffffff0; |
| 284 | if (!base){ |
| 285 | base = SPI_BASE_ADDRESS; |
| 286 | pci_write_config32(dev, SPIROM_BASE_ADDRESS_REGISTER, base |
| 287 | | SPI_ROM_ENABLE); |
| 288 | /* PCI_COMMAND_MEMORY is read-only and enabled. */ |
| 289 | } |
| 290 | return (uintptr_t)base; |
| 291 | } |
| 292 | |
| 293 | void hudson_set_spi100(u16 norm, u16 fast, u16 alt, u16 tpm) |
| 294 | { |
| 295 | uintptr_t base = hudson_spibase(); |
| 296 | write16((void *)base + SPI100_SPEED_CONFIG, |
| 297 | (norm << SPI_NORM_SPEED_NEW_SH) | |
| 298 | (fast << SPI_FAST_SPEED_NEW_SH) | |
| 299 | (alt << SPI_ALT_SPEED_NEW_SH) | |
| 300 | (tpm << SPI_TPM_SPEED_NEW_SH)); |
| 301 | write16((void *)base + SPI100_ENABLE, SPI_USE_SPI100); |
| 302 | } |
| 303 | |
| 304 | void hudson_disable_4dw_burst(void) |
| 305 | { |
| 306 | uintptr_t base = hudson_spibase(); |
| 307 | write16((void *)base + SPI100_HOST_PREF_CONFIG, |
| 308 | read16((void *)base + SPI100_HOST_PREF_CONFIG) |
| 309 | & ~SPI_RD4DW_EN_HOST); |
| 310 | } |
| 311 | |
| 312 | /* Hudson 1-3 only. For Hudson 1, call with fast=1 */ |
| 313 | void hudson_set_readspeed(u16 norm, u16 fast) |
| 314 | { |
| 315 | uintptr_t base = hudson_spibase(); |
| 316 | write16((void *)base + SPI_CNTRL1, (read16((void *)base + SPI_CNTRL1) |
| 317 | & ~SPI_CNTRL1_SPEED_MASK) |
| 318 | | (norm << SPI_NORM_SPEED_SH) |
| 319 | | (fast << SPI_FAST_SPEED_SH)); |
| 320 | } |
| 321 | |
| 322 | void hudson_read_mode(u32 mode) |
| 323 | { |
| 324 | uintptr_t base = hudson_spibase(); |
| 325 | write32((void *)base + SPI_CNTRL0, |
| 326 | (read32((void *)base + SPI_CNTRL0) |
| 327 | & ~SPI_READ_MODE_MASK) | mode); |
| 328 | } |
| 329 | |
Marc Jones | 6fcaaef | 2017-04-20 16:48:42 -0600 | [diff] [blame^] | 330 | void hudson_tpm_decode_spi(void) |
| 331 | { |
| 332 | device_t dev = PCI_DEV(0, 0x14, 3); /* LPC device */ |
| 333 | |
| 334 | u32 spibase = pci_read_config32(dev, SPIROM_BASE_ADDRESS_REGISTER); |
| 335 | pci_write_config32(dev, SPIROM_BASE_ADDRESS_REGISTER, spibase |
| 336 | | ROUTE_TPM_2_SPI); |
| 337 | } |
| 338 | |
Kyösti Mälkki | e8b4da2 | 2014-10-21 18:22:32 +0300 | [diff] [blame] | 339 | #endif |