From ebe3b3cfe212a2e985e12f1ab93bdef4487733f5 Mon Sep 17 00:00:00 2001 From: Shawn Nematbakhsh Date: Thu, 26 Sep 2013 16:44:14 -0700 Subject: baytrail: Add GPIO initial configuration infrastructure. During ramstage, call mainboard_get_gpios to get initial GPIO configuration from the mainboard code, then initialize GPIOs as requested. BUG=chrome-os-partner:22863 TEST=Manual. Using bayleybay GPIO table, set UART GPIOs to 'function 1', and verify UART still works after GPIO configuration. Also, verify legacy GPIO config is functional by toggling test pin. Change-Id: Ic58d8ddd15c4dc48a751a83f6d26c7809c1efc42 Reviewed-on: https://chromium-review.googlesource.com/170306 Reviewed-by: Aaron Durbin Commit-Queue: Shawn Nematbakhsh Signed-off-by: Shawn Nematbakhsh Tested-by: Shawn Nematbakhsh Signed-off-by: Aaron Durbin Reviewed-on: http://review.coreboot.org/4855 Tested-by: build bot (Jenkins) Reviewed-by: Alexandru Gagniuc --- src/soc/intel/baytrail/Makefile.inc | 2 +- src/soc/intel/baytrail/baytrail/gpio.h | 178 +++++++++++++++++++++++++++++++-- src/soc/intel/baytrail/gpio.c | 166 ++++++++++++++++++++++++++++++ src/soc/intel/baytrail/ramstage.c | 8 ++ 4 files changed, 342 insertions(+), 12 deletions(-) create mode 100644 src/soc/intel/baytrail/gpio.c diff --git a/src/soc/intel/baytrail/Makefile.inc b/src/soc/intel/baytrail/Makefile.inc index 756fd39f8f..ebcda6b93e 100644 --- a/src/soc/intel/baytrail/Makefile.inc +++ b/src/soc/intel/baytrail/Makefile.inc @@ -18,7 +18,7 @@ ramstage-y += iosf.c romstage-y += iosf.c ramstage-y += northcluster.c ramstage-y += ramstage.c - +ramstage-y += gpio.c # Remove as ramstage gets fleshed out ramstage-y += placeholders.c diff --git a/src/soc/intel/baytrail/baytrail/gpio.h b/src/soc/intel/baytrail/baytrail/gpio.h index 68e32416fc..32b991edd9 100644 --- a/src/soc/intel/baytrail/baytrail/gpio.h +++ b/src/soc/intel/baytrail/baytrail/gpio.h @@ -24,20 +24,181 @@ #include #include -/* Registers sitting behind the IO_BASE_ADDRESS */ +/* #define GPIO_DEBUG */ -#define SCORE_PCONF_OFFSET 0x0000 -#define SSUS_PCONF_OFFSET 0x2000 +/* Pad base, ex. PAD_CONF0[n]= PAD_BASE+16*n */ +#define GPSCORE_PAD_BASE IO_BASE_ADDRESS + 0x0000 +#define GPNCORE_PAD_BASE IO_BASE_ADDRESS + 0x1000 +#define GPSSUS_PAD_BASE IO_BASE_ADDRESS + 0x2000 + +/* Pad register offset */ +#define PAD_CONF0_REG 0x0 +#define PAD_CONF1_REG 0x4 +#define PAD_VAL_REG 0x8 + +/* Legacy IO register base */ +#define GPSCORE_LEGACY_BASE GPIO_BASE_ADDRESS + 0x00 +#define GPSSUS_LEGACY_BASE GPIO_BASE_ADDRESS + 0x80 +/* Some banks have no legacy GPIO interface */ +#define GP_LEGACY_BASE_NONE 0xFFFF + +#define LEGACY_USE_SEL_REG 0x00 +#define LEGACY_IO_SEL_REG 0x04 +#define LEGACY_GP_LVL_REG 0x08 +#define LEGACY_TPE_REG 0x0C +#define LEGACY_TNE_REG 0x10 +#define LEGACY_TS_REG 0x14 +#define LEGACY_WAKE_EN_REG 0x18 + +/* Number of GPIOs in each bank */ +#define GPNCORE_COUNT 27 +#define GPSCORE_COUNT 102 +#define GPSSUS_COUNT 44 + +/* GPIO legacy IO register settings */ +#define GPIO_USE_PAD 0 +#define GPIO_USE_LEGACY 1 + +#define GPIO_DIR_OUTPUT 0 +#define GPIO_DIR_INPUT 1 + +#define GPIO_LEVEL_LOW 0 +#define GPIO_LEVEL_HIGH 1 + +#define GPIO_PEDGE_DISABLE 0 +#define GPIO_PEDGE_ENABLE 1 + +#define GPIO_NEDGE_DISABLE 0 +#define GPIO_NEDGE_ENABLE 1 + +/* PAD_CONF0 settings */ +#define PAD_IRQ_EN (1 << 27) +#define PAD_LEVEL_IRQ (1 << 24) + +#define PAD_PU_2K (0 << 9) +#define PAD_PU_10K (1 << 9) +#define PAD_PU_20K (2 << 9) +#define PAD_PU_40K (3 << 9) + +#define PAD_PU_DISABLE (0 << 7) +#define PAD_PU_UP (1 << 7) +#define PAD_PU_DOWN (2 << 7) + +#define PAD_FUNC0 0x0 +#define PAD_FUNC1 0x1 +#define PAD_FUNC2 0x2 +#define PAD_FUNC3 0x3 +#define PAD_FUNC4 0x4 +#define PAD_FUNC5 0x5 +#define PAD_FUNC6 0x6 + +/* PAD_VAL settings */ +#define PAD_INPUT_ENABLE (1 << 2) +#define PAD_OUTPUT_ENABLE (1 << 1) + +/* End marker */ +#define GPIO_LIST_END 0xffffffff + +#define GPIO_INPUT_PU_10K \ + { .pad_conf0 = PAD_PU_10K | PAD_PU_UP, \ + .pad_val = PAD_INPUT_ENABLE, \ + .use_sel = GPIO_USE_LEGACY, \ + .io_sel = GPIO_DIR_INPUT } + +#define GPIO_OUT_LOW \ + { .pad_conf0 = PAD_PU_DISABLE, \ + .pad_val = PAD_OUTPUT_ENABLE, \ + .use_sel = GPIO_USE_LEGACY, \ + .io_sel = GPIO_DIR_OUTPUT, \ + .gp_lvl = GPIO_LEVEL_LOW } + +#define GPIO_OUT_HIGH \ + { .pad_conf0 = PAD_PU_DISABLE, \ + .pad_val = PAD_OUTPUT_ENABLE, \ + .use_sel = GPIO_USE_LEGACY, \ + .io_sel = GPIO_DIR_OUTPUT, \ + .gp_lvl = GPIO_LEVEL_HIGH } + +#define GPIO_FUNC0 \ + { .use_sel = GPIO_USE_PAD, \ + .pad_conf0 = PAD_FUNC0 } + +#define GPIO_FUNC1 \ + { .use_sel = GPIO_USE_PAD, \ + .pad_conf0 = PAD_FUNC1 } + +#define GPIO_FUNC2 \ + { .use_sel = GPIO_USE_PAD, \ + .pad_conf0 = PAD_FUNC2 } + +#define GPIO_FUNC3 \ + { .use_sel = GPIO_USE_PAD, \ + .pad_conf0 = PAD_FUNC3 } + +#define GPIO_FUNC4 \ + { .use_sel = GPIO_USE_PAD, \ + .pad_conf0 = PAD_FUNC4 } + +#define GPIO_FUNC5 \ + { .use_sel = GPIO_USE_PAD, \ + .pad_conf0 = PAD_FUNC5 } + +#define GPIO_FUNC6 \ + { .use_sel = GPIO_USE_PAD, \ + .pad_conf0 = PAD_FUNC6 } + +#define GPIO_END \ + { .pad_conf0 = GPIO_LIST_END } + +/* Common default GPIO settings */ +#define GPIO_INPUT GPIO_INPUT_PU_10K +#define GPIO_UNUSED GPIO_INPUT_PU_10K +#define GPIO_DEFAULT GPIO_FUNC0 + +struct soc_gpio_map { + u32 pad_conf0; + u32 pad_conf1; + u32 pad_val; + u8 use_sel : 1; + u8 io_sel : 1; + u8 gp_lvl : 1; + u8 tpe : 1; + u8 tne : 1; + u8 wake_en : 1; +} __attribute__ ((packed)); + +struct soc_gpio_config { + const struct soc_gpio_map *ncore; + const struct soc_gpio_map *score; + const struct soc_gpio_map *ssus; +}; + +/* Description of GPIO 'bank' ex. {ncore, score. ssus} */ +struct gpio_bank { + const int gpio_count; + const u8* gpio_to_pad; + const int legacy_base; + const unsigned long pad_base; + const u8 has_wake_en :1; +}; + +void setup_soc_gpios(struct soc_gpio_config *config); +/* This function is weak and can be overridden by a mainboard function. */ +struct soc_gpio_config* mainboard_get_gpios(void); + +/* Functions / defines for changing GPIOs in romstage */ +/* SCORE Pad definitions. */ +#define PCU_SMB_CLK_PAD 88 +#define PCU_SMB_DATA_PAD 90 static inline unsigned int score_pconf0(int pad_num) { - return IO_BASE_ADDRESS + SCORE_PCONF_OFFSET + pad_num * 16; + return GPSCORE_PAD_BASE + pad_num * 16; } - static inline unsigned int ssus_pconf0(int pad_num) { - return IO_BASE_ADDRESS + SSUS_PCONF_OFFSET + pad_num * 16; + return GPSSUS_PAD_BASE + pad_num * 16; } static inline void score_select_func(int pad, int func) @@ -62,9 +223,4 @@ static inline void ssus_select_func(int pad, int func) write32(pconf0_addr, reg); } -/* SCORE Pad definitions. */ -#define PCU_SMB_CLK_PAD 88 -#define PCU_SMB_DATA_PAD 90 -#define PCU_SMB_ALERT_PAD 92 - #endif /* _BAYTRAIL_GPIO_H_ */ diff --git a/src/soc/intel/baytrail/gpio.c b/src/soc/intel/baytrail/gpio.c new file mode 100644 index 0000000000..8118aeb755 --- /dev/null +++ b/src/soc/intel/baytrail/gpio.c @@ -0,0 +1,166 @@ +/* + * 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 + */ + +#include +#include +#include + +/* GPIO-to-Pad LUTs */ +static const u8 gpncore_gpio_to_pad[GPNCORE_COUNT] = + { 25, 24, 23, 32, 33, 34, 36, 37, 35, 22, + 20, 21, 18, 38, 39, 1, 4, 8, 17, 0, + 3, 6, 16, 19, 2, 5, 9 }; + +static const u8 gpscore_gpio_to_pad[GPSCORE_COUNT] = + { 85, 89, 93, 96, 99, 102, 98, 101, 34, 37, + 36, 38, 39, 35, 40, 84, 62, 61, 64, 59, + 54, 56, 60, 55, 63, 57, 51, 50, 53, 47, + 52, 49, 48, 43, 46, 41, 45, 42, 58, 44, + 95, 105, 70, 68, 67, 66, 69, 71, 65, 72, + 86, 90, 88, 92, 103, 77, 79, 83, 78, 81, + 80, 82, 13, 12, 15, 14, 17, 18, 19, 16, + 2, 1, 0, 4, 6, 7, 9, 8, 33, 32, + 31, 30, 29, 27, 25, 28, 26, 23, 21, 20, + 24, 22, 5, 3, 10, 11, 106, 87, 91, 104, + 97, 100 }; + +static const u8 gpssus_gpio_to_pad[GPSSUS_COUNT] = + { 29, 33, 30, 31, 32, 34, 36, 35, 38, 37, + 18, 7, 11, 20, 17, 1, 8, 10, 19, 12, + 0, 2, 23, 39, 28, 27, 22, 21, 24, 25, + 26, 51, 56, 54, 49, 55, 48, 47, 50, 58, + 52, 53, 59, 40 }; + +/* GPIO bank descriptions */ +static const struct gpio_bank gpncore_bank = { + .gpio_count = GPNCORE_COUNT, + .gpio_to_pad = gpncore_gpio_to_pad, + .legacy_base = GP_LEGACY_BASE_NONE, + .pad_base = GPNCORE_PAD_BASE, + .has_wake_en = 0, +}; + +static const struct gpio_bank gpscore_bank = { + .gpio_count = GPSCORE_COUNT, + .gpio_to_pad = gpscore_gpio_to_pad, + .legacy_base = GPSCORE_LEGACY_BASE, + .pad_base = GPSCORE_PAD_BASE, + .has_wake_en = 0, +}; + +static const struct gpio_bank gpssus_bank = { + .gpio_count = GPSSUS_COUNT, + .gpio_to_pad = gpssus_gpio_to_pad, + .legacy_base = GPSSUS_LEGACY_BASE, + .pad_base = GPSSUS_PAD_BASE, + .has_wake_en = 1, +}; + +static void setup_gpios(const struct soc_gpio_map *gpios, + const struct gpio_bank *bank) +{ + const struct soc_gpio_map *config; + int gpio = 0; + u32 reg; + u8 set, bit; + + u32 use_sel[4] = {0}; + u32 io_sel[4] = {0}; + u32 gp_lvl[4] = {0}; + u32 tpe[4] = {0}; + u32 tne[4] = {0}; + u32 wake_en[4] = {0}; + + if (!gpios) + return; + + for (config = gpios; config->pad_conf0 != GPIO_LIST_END; + config++, gpio++) { + if (gpio > bank->gpio_count) + break; + + set = gpio >> 5; + bit = gpio % 32; + + if (bank->legacy_base != GP_LEGACY_BASE_NONE) { + /* Legacy IO configuration */ + use_sel[set] |= config->use_sel << bit; + io_sel[set] |= config->io_sel << bit; + gp_lvl[set] |= config->gp_lvl << bit; + tpe[set] |= config->tpe << bit; + tne[set] |= config->tne << bit; + + /* Some banks do not have wake_en ability */ + if (bank->has_wake_en) + wake_en[set] |= config->wake_en << bit; + } + + /* Pad configuration registers */ + reg = bank->pad_base + 16 * bank->gpio_to_pad[gpio]; + +#ifdef GPIO_DEBUG + printk(BIOS_DEBUG, "Write Pad: Base(%x) - %x %x %x\n", + reg, config->pad_conf0, config->pad_conf1, + config->pad_val ); +#endif + + write32(reg + PAD_CONF0_REG, config->pad_conf0); + write32(reg + PAD_CONF1_REG, config->pad_conf1); + write32(reg + PAD_VAL_REG, config->pad_val); + } + + if (bank->legacy_base != GP_LEGACY_BASE_NONE) + for (set = 0; set <= (bank->gpio_count - 1) / 32; ++set) { + reg = bank->legacy_base + 0x20 * set; + +#ifdef GPIO_DEBUG + printk(BIOS_DEBUG, + "Write GPIO: Reg(%x) - %x %x %x %x %x\n", + reg, use_sel[set], io_sel[set], gp_lvl[set], + tpe[set], tne[set]); +#endif + + outl(use_sel[set], reg + LEGACY_USE_SEL_REG); + outl(io_sel[set], reg + LEGACY_IO_SEL_REG); + outl(gp_lvl[set], reg + LEGACY_GP_LVL_REG); + outl(tpe[set], reg + LEGACY_TPE_REG); + outl(tne[set], reg + LEGACY_TNE_REG); + + /* TS registers are WOC */ + outl(0, reg + LEGACY_TS_REG); + + if (bank->has_wake_en) + outl(wake_en[set], reg + LEGACY_WAKE_EN_REG); + } +} + +void setup_soc_gpios(struct soc_gpio_config *config) +{ + if (config) { + setup_gpios(config->ncore, &gpncore_bank); + setup_gpios(config->score, &gpscore_bank); + setup_gpios(config->ssus, &gpssus_bank); + } +} + +struct soc_gpio_config* __attribute__((weak)) mainboard_get_gpios(void) +{ + printk(BIOS_DEBUG, "Default/empty GPIO config\n"); + return NULL; +} diff --git a/src/soc/intel/baytrail/ramstage.c b/src/soc/intel/baytrail/ramstage.c index e30fc89bc2..10c030fcb3 100644 --- a/src/soc/intel/baytrail/ramstage.c +++ b/src/soc/intel/baytrail/ramstage.c @@ -31,6 +31,7 @@ #include #include #include +#include /* Global PATTRS */ DEFINE_PATTRS; @@ -101,7 +102,14 @@ static void fill_in_pattrs(void) fill_in_msr(&attrs->iacore_vids, MSR_IACORE_VIDS); } + void baytrail_init_pre_device(void) { + struct soc_gpio_config *config; + fill_in_pattrs(); + + /* Get GPIO initial states from mainboard */ + config = mainboard_get_gpios(); + setup_soc_gpios(config); } -- cgit v1.2.3