Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright (C) 2013 Google Inc. |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 5 | * Copyright (C) 2015 Intel Corp. |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License as published by |
| 9 | * the Free Software Foundation; version 2 of the License. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 15 | */ |
| 16 | |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 17 | |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 18 | #include <console/console.h> |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 19 | #include <device/pci.h> |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 20 | #include <soc/gpio.h> |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 21 | #include <soc/pm.h> |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 22 | #include <soc/smm.h> |
| 23 | |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 24 | |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 25 | #define GPIO_DEBUG |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 26 | |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 27 | /* gpio map to pad number LUTs */ |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 28 | |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 29 | static const u8 gpncommunity_gpio_to_pad[GP_NORTH_COUNT] = { |
| 30 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 15, |
| 31 | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, |
| 32 | 26, 27, 30, 31, 32, 33, 34, 35, 36, 37, |
| 33 | 38, 39, 40, 41, 45, 46, 47, 48, 49, 50, |
| 34 | 51, 52, 53, 54, 55, 56, 60, 61, 62, 63, |
| 35 | 64, 65, 66, 67, 68, 69, 70, 71, 72 }; |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 36 | |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 37 | static const u8 gpsecommunity_gpio_to_pad[GP_SOUTHEAST_COUNT] = { |
| 38 | 0, 1, 2, 3, 4, 5, 6, 7, 15, 16, |
| 39 | 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, |
| 40 | 30, 31, 32, 33, 34, 35, 45, 46, 47, 48, |
| 41 | 49, 50, 51, 52, 60, 61, 62, 63, 64, 65, |
| 42 | 66, 67, 68, 69, 75, 76, 77, 78, 79, 80, |
| 43 | 81, 82, 83, 84, 85 }; |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 44 | |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 45 | |
| 46 | static const u8 gpswcommunity_gpio_to_pad[GP_SOUTHWEST_COUNT] = { |
| 47 | 0, 1, 2, 3, 4, 5, 6, 7, 15, 16, |
| 48 | 17, 18, 19, 20, 21, 22, 30, 31, 32, 33, |
| 49 | 34, 35, 36, 37, 45, 46, 47, 48, 49, 50, |
| 50 | 51, 52, 60, 61, 62, 63, 64, 65, 66, 67, |
| 51 | 75, 76, 77, 78, 79, 80, 81, 82, 90, 91, |
| 52 | 92, 93, 94, 95, 96, 97 }; |
| 53 | |
| 54 | static const u8 gpecommunity_gpio_to_pad[GP_EAST_COUNT] = { |
| 55 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
| 56 | 10, 11, 15, 16, 17, 18, 19, 20, 21, 22, |
| 57 | 23, 24, 25, 26 }; |
| 58 | |
| 59 | /* GPIO Community descriptions */ |
| 60 | static const struct gpio_bank gpnorth_community = { |
| 61 | .gpio_count = GP_NORTH_COUNT, |
| 62 | .gpio_to_pad = gpncommunity_gpio_to_pad , |
| 63 | .pad_base = COMMUNITY_GPNORTH_BASE , |
| 64 | .has_gpe_en = GPE_CAPABLE , |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 65 | .has_wake_en = 1, |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 66 | }; |
| 67 | |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 68 | static const struct gpio_bank gpsoutheast_community = { |
| 69 | .gpio_count = GP_SOUTHEAST_COUNT, |
| 70 | .gpio_to_pad = gpsecommunity_gpio_to_pad, |
| 71 | .pad_base = COMMUNITY_GPSOUTHEAST_BASE, |
| 72 | .has_gpe_en = GPE_CAPABLE_NONE, |
| 73 | .has_wake_en = 1, |
| 74 | }; |
| 75 | |
| 76 | static const struct gpio_bank gpsouthwest_community = { |
| 77 | .gpio_count = GP_SOUTHWEST_COUNT, |
| 78 | .gpio_to_pad = gpswcommunity_gpio_to_pad, |
| 79 | .pad_base = COMMUNITY_GPSOUTHWEST_BASE, |
| 80 | .has_gpe_en = GPE_CAPABLE, |
| 81 | .has_wake_en = 1, |
| 82 | }; |
| 83 | |
| 84 | static const struct gpio_bank gpeast_community = { |
| 85 | .gpio_count = GP_EAST_COUNT, |
| 86 | .gpio_to_pad = gpecommunity_gpio_to_pad, |
| 87 | .pad_base = COMMUNITY_GPEAST_BASE, |
| 88 | .has_gpe_en = GPE_CAPABLE_NONE, |
| 89 | .has_wake_en = 1, |
| 90 | }; |
| 91 | |
| 92 | static void setup_gpio_route(const struct soc_gpio_map *sw_gpios, |
| 93 | const struct soc_gpio_map *n_gpios) |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 94 | { |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 95 | const struct soc_gpio_map *n_config; |
| 96 | const struct soc_gpio_map *sw_config; |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 97 | uint32_t route_reg = 0; |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 98 | uint32_t int_selection = 0; |
| 99 | uint32_t alt_gpio_smi = 0; |
| 100 | uint32_t gpe0a_en = 0; |
| 101 | int gpio = 0; |
| 102 | int north_done = 0; |
| 103 | int south_done = 0; |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 104 | |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 105 | for (sw_config = sw_gpios, n_config = n_gpios; |
| 106 | (!north_done || !south_done); sw_config++, n_config++, gpio++) { |
| 107 | |
| 108 | /* when north config is done */ |
| 109 | if ((gpio > GP_NORTH_COUNT) || |
| 110 | (n_config->pad_conf0 == GPIO_LIST_END)) |
| 111 | north_done = 1; |
| 112 | |
| 113 | /* when sw is done */ |
| 114 | if ((gpio > GP_SOUTHWEST_COUNT) || |
| 115 | (sw_config->pad_conf0 == GPIO_LIST_END)) |
| 116 | south_done = 1; |
| 117 | |
| 118 | /* route north gpios */ |
| 119 | if (!north_done) { |
| 120 | /* Int select from 8 to 15 */ |
| 121 | int_selection = ((n_config->pad_conf0 >> 28) & 0xf); |
| 122 | if (n_config->gpe == SMI) { |
| 123 | /* |
| 124 | * Set the corresponding bits (01) as |
| 125 | * per the interrupt line |
| 126 | */ |
| 127 | route_reg |= (1 << ((int_selection - 8) * 2)); |
| 128 | /* reset the higher bit */ |
| 129 | route_reg &= |
| 130 | ~(1 << ((int_selection - 8) * 2 + 1)); |
| 131 | alt_gpio_smi |= (1 << (int_selection + 8)); |
| 132 | } else if (n_config->gpe == SCI) { |
| 133 | /* |
| 134 | * Set the corresponding bits as per the |
| 135 | * interrupt line |
| 136 | */ |
| 137 | route_reg |= |
| 138 | (1 << (((int_selection - 8) * 2) + 1)); |
| 139 | /* reset the bit */ |
| 140 | route_reg &= ~(1 << ((int_selection - 8) * 2)); |
| 141 | gpe0a_en |= (1 << (int_selection + 8)); |
| 142 | } |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 143 | } |
| 144 | |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 145 | /* route southwest gpios */ |
| 146 | if (!south_done) { |
| 147 | /* Int select from 8 to 15 */ |
| 148 | int_selection = ((sw_config->pad_conf0 >> 28) & 0xf); |
| 149 | if (sw_config->gpe == SMI) { |
| 150 | /* |
| 151 | * Set the corresponding bits (10) as |
| 152 | * per the interrupt line |
| 153 | */ |
| 154 | route_reg |= (1 << (int_selection * 2)); |
| 155 | route_reg &= ~(1 << (int_selection * 2 + 1)); |
| 156 | alt_gpio_smi |= (1 << (int_selection + 16)); |
| 157 | } else if (sw_config->gpe == SCI) { |
| 158 | /* |
| 159 | * Set the corresponding bits as |
| 160 | * per the interrupt line |
| 161 | */ |
| 162 | route_reg |= (1 << ((int_selection * 2) + 1)); |
| 163 | /* reset the bit */ |
| 164 | route_reg &= ~(1 << (int_selection * 2)); |
| 165 | gpe0a_en |= (1 << (int_selection + 16)); |
| 166 | } |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 167 | } |
| 168 | } |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 169 | |
| 170 | /* enable gpe bits in GPE0A_EN_REG */ |
| 171 | outl(gpe0a_en, ACPI_BASE_ADDRESS + GPE0A_EN_REG); |
| 172 | |
| 173 | #ifdef GPIO_DEBUG |
| 174 | printk(BIOS_DEBUG, "gpio_rout = %x alt_gpio_smi = %x gpe0a_en = %x\n", |
| 175 | route_reg, alt_gpio_smi, gpe0a_en); |
| 176 | #endif |
| 177 | /* Save as an smm param */ |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 178 | southcluster_smm_save_param(SMM_SAVE_PARAM_GPIO_ROUTE, route_reg); |
| 179 | } |
| 180 | |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 181 | |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 182 | static void setup_gpios(const struct soc_gpio_map *gpios, |
| 183 | const struct gpio_bank *community) |
| 184 | { |
| 185 | const struct soc_gpio_map *config; |
| 186 | int gpio = 0; |
| 187 | u32 reg, family, internal_pad_num; |
| 188 | u32 mmio_addr, int_selection; |
| 189 | u32 gpio_wake0 = 0; |
| 190 | u32 gpio_wake1 = 0; |
| 191 | u32 gpio_int_mask = 0; |
| 192 | |
| 193 | if (!gpios) |
| 194 | return; |
| 195 | for (config = gpios; config->pad_conf0 != GPIO_LIST_END; |
| 196 | config++, gpio++) { |
| 197 | if (gpio > community->gpio_count) |
| 198 | break; |
| 199 | |
| 200 | /* Pad configuration registers */ |
| 201 | family = community->gpio_to_pad[gpio] / MAX_FAMILY_PAD_GPIO_NO; |
| 202 | internal_pad_num = community->gpio_to_pad[gpio] % |
| 203 | MAX_FAMILY_PAD_GPIO_NO; |
| 204 | |
| 205 | /* |
| 206 | * Calculate the MMIO Address for specific GPIO pin |
| 207 | * control register pointed by index. |
| 208 | * REG = (IOBASE + COMMUNITY_BASE + (0X04400)) + |
| 209 | * (0X400*FAMILY_NUM) + (8 * PAD_NUM) |
| 210 | */ |
| 211 | mmio_addr = FAMILY_PAD_REGS_OFF |
| 212 | + (FAMILY_PAD_REGS_SIZE * family) |
| 213 | + (GPIO_REGS_SIZE * internal_pad_num); |
| 214 | |
| 215 | reg = community->pad_base + mmio_addr; |
| 216 | |
| 217 | /* get int selection value */ |
| 218 | int_selection = ((config->pad_conf0 >> 28) & 0xf); |
| 219 | |
| 220 | /* get int mask register value */ |
| 221 | gpio_int_mask |= (config->int_mask << int_selection); |
| 222 | |
| 223 | /* |
| 224 | * wake capable programming |
| 225 | * some communities have 2 wake regs |
| 226 | */ |
| 227 | if (gpio > 31) |
| 228 | gpio_wake1 |= config->wake_mask << (gpio % 32); |
| 229 | else |
| 230 | gpio_wake0 |= config->wake_mask << gpio; |
| 231 | |
| 232 | if (!config->skip_config) { |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 233 | #ifdef GPIO_DEBUG |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 234 | printk(BIOS_DEBUG, |
| 235 | "Write Pad: Base(%x) - conf0 = %x conf1= %x gpio #- %d pad # = %d\n", |
| 236 | reg, config->pad_conf0, config->pad_conf1, |
| 237 | community->gpio_to_pad[gpio], gpio); |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 238 | #endif |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 239 | /* |
| 240 | * write pad configurations to conf0 and conf1 register |
| 241 | */ |
| 242 | write32((void *)(reg + PAD_CONF0_REG), |
| 243 | config->pad_conf0); |
| 244 | write32((void *)(reg + PAD_CONF1_REG), |
| 245 | config->pad_conf1); |
| 246 | } |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 247 | } |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 248 | |
| 249 | #ifdef GPIO_DEBUG |
| 250 | printk(BIOS_DEBUG, |
| 251 | "gpio_wake_mask0 = %x gpio_wake_mask1 = %x gpio_int_mask = %x\n", |
| 252 | gpio_wake0, gpio_wake1, gpio_int_mask); |
| 253 | #endif |
| 254 | |
| 255 | /* Wake */ |
| 256 | write32((void *)(community->pad_base + GPIO_WAKE_MASK_REG0), |
| 257 | gpio_wake0); |
| 258 | |
| 259 | /* wake mask config for communities with 2 regs */ |
| 260 | if (community->gpio_count > 32) |
| 261 | write32((void *)(community->pad_base + GPIO_WAKE_MASK_REG1), |
| 262 | gpio_wake1); |
| 263 | |
| 264 | /* Interrupt */ |
| 265 | write32((void *)(community->pad_base + GPIO_INTERRUPT_MASK), |
| 266 | gpio_int_mask); |
| 267 | |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 268 | } |
| 269 | |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 270 | |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 271 | void setup_soc_gpios(struct soc_gpio_config *config, u8 enable_xdp_tap) |
| 272 | { |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 273 | |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 274 | if (config) { |
| 275 | |
| 276 | /* |
| 277 | * Write the default value 0xffffff to the SW |
| 278 | * write_access_policy_interrupt_reg to allow the SW interrupt |
| 279 | * mask register to be set |
| 280 | */ |
| 281 | write32((void *)(COMMUNITY_GPSOUTHWEST_BASE + 0x108), |
| 282 | 0xffffffff); |
| 283 | |
| 284 | printk(BIOS_DEBUG, "north\n"); |
| 285 | setup_gpios(config->north, &gpnorth_community); |
| 286 | |
| 287 | printk(BIOS_DEBUG, "southwest\n"); |
| 288 | setup_gpios(config->southwest, &gpsouthwest_community); |
| 289 | |
| 290 | printk(BIOS_DEBUG, "southeast\n"); |
| 291 | setup_gpios(config->southeast, &gpsoutheast_community); |
| 292 | |
| 293 | printk(BIOS_DEBUG, "east\n"); |
| 294 | setup_gpios(config->east, &gpeast_community); |
| 295 | |
| 296 | printk(BIOS_DEBUG, "Routing SW and N gpios\n"); |
| 297 | setup_gpio_route(config->southwest, config->north); |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 298 | } |
| 299 | |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 300 | /* |
| 301 | * Set on die termination feature with pull up value and |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 302 | * drive the pad high for TAP_TDO and TAP_TMS |
| 303 | */ |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 304 | if (!enable_xdp_tap) |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 305 | printk(BIOS_DEBUG, "Tri-state TDO and TMS\n"); |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 306 | } |
| 307 | |
Lee Leahy | 3247172 | 2015-04-20 15:20:28 -0700 | [diff] [blame] | 308 | __attribute__((weak)) struct soc_gpio_config *mainboard_get_gpios(void) |
Lee Leahy | 77ff0b1 | 2015-05-05 15:07:29 -0700 | [diff] [blame] | 309 | { |
| 310 | printk(BIOS_DEBUG, "Default/empty GPIO config\n"); |
| 311 | return NULL; |
| 312 | } |