diff options
author | Michał Żygowski <michal.zygowski@3mdeb.com> | 2024-07-15 12:03:32 +0200 |
---|---|---|
committer | Michał Żygowski <michal.zygowski@3mdeb.com> | 2024-07-19 14:35:09 +0000 |
commit | d1efb66be6fb79d2e22395d03dff269448b636b9 (patch) | |
tree | ab653f5201e9638e832486f0551713d3de2150f4 | |
parent | eff64c675723c740381ebcbe904f513c5cb671c3 (diff) |
superio/ite/common: Add common driver for GPIO and LED configuration
Add a generic driver to configure GPIOs and LEDs on common ITE
SuperIOs. The driver supports most ITE SuperIOs, except Embedded
Controllers. The driver allows configuring every GPIO property
with pin granularity.
Verified against datasheets of all ITE SIOs currently supported by
coreboot, except IT8721F (assumed to be the same as IT8720F),
IT8623E and IT8629E.
Change-Id: If610d2809b56c63444c3406c26fad412c94136a5
Signed-off-by: Michał Żygowski <michal.zygowski@3mdeb.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/83355
Reviewed-by: Nicholas Sudsgaard <devel+coreboot@nsudsgaard.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nico Huber <nico.h@gmx.de>
-rw-r--r-- | src/superio/ite/Makefile.mk | 4 | ||||
-rw-r--r-- | src/superio/ite/common/Kconfig | 27 | ||||
-rw-r--r-- | src/superio/ite/common/gpio.c | 191 | ||||
-rw-r--r-- | src/superio/ite/common/ite_gpio.h | 75 |
4 files changed, 297 insertions, 0 deletions
diff --git a/src/superio/ite/Makefile.mk b/src/superio/ite/Makefile.mk index 678ea95203..afbce8a527 100644 --- a/src/superio/ite/Makefile.mk +++ b/src/superio/ite/Makefile.mk @@ -4,11 +4,15 @@ bootblock-$(CONFIG_SUPERIO_ITE_COMMON_PRE_RAM) += common/early_serial.c romstage-$(CONFIG_SUPERIO_ITE_COMMON_PRE_RAM) += common/early_serial.c +bootblock-$(CONFIG_SUPERIO_ITE_COMMON_GPIO_PRE_RAM) += common/gpio.c +romstage-$(CONFIG_SUPERIO_ITE_COMMON_GPIO_PRE_RAM) += common/gpio.c + ## include generic ite environment controller driver ramstage-$(CONFIG_SUPERIO_ITE_ENV_CTRL) += common/env_ctrl.c ## include generic ite driver to smm to control S3-relevant functions smm-$(CONFIG_SUPERIO_ITE_COMMON_PRE_RAM) += common/early_serial.c +smm-$(CONFIG_SUPERIO_ITE_COMMON_GPIO_PRE_RAM) += common/gpio.c subdirs-y += it8528e subdirs-y += it8613e diff --git a/src/superio/ite/common/Kconfig b/src/superio/ite/common/Kconfig index 4701056bfa..c5eeec6c87 100644 --- a/src/superio/ite/common/Kconfig +++ b/src/superio/ite/common/Kconfig @@ -5,6 +5,33 @@ config SUPERIO_ITE_COMMON_PRE_RAM bool +config SUPERIO_ITE_COMMON_GPIO_PRE_RAM + bool + help + Enable generic pre-ram driver for configuring ITE SIO GPIOs. + It applies only to ITE SIOs not ITE ECs using LDN 7 (typically) + to configure GPIO Simple I/O mode. + +if SUPERIO_ITE_COMMON_GPIO_PRE_RAM + +config SUPERIO_ITE_COMMON_NUM_GPIO_SETS + int + help + The maximum number of GPIO sets supported by ITE SIO chip. + Each SIO chip must set this config option to a proper values + if it intends to enable SUPERIO_ITE_COMMON_GPIO_PRE_RAM. + +config SUPERIO_ITE_COMMON_GPIO_LED_FREQ_5BIT + bool + default n + help + Selected ITE SIOs control the GPIO LED frequency using 5 bits + instead of two. The LED register layout is also different for + these chips. Select this if the SIO GP LED Frequency control + field has 5 bits and support duty cycle as well. + +endif + # Generic ITE environment controller driver config SUPERIO_ITE_ENV_CTRL bool diff --git a/src/superio/ite/common/gpio.c b/src/superio/ite/common/gpio.c new file mode 100644 index 0000000000..11c02ba1c8 --- /dev/null +++ b/src/superio/ite/common/gpio.c @@ -0,0 +1,191 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <device/pnp_ops.h> +#include <device/pnp.h> +#include <stdint.h> + +#include "ite.h" +#include "ite_gpio.h" + +/* Catch ITE SIOs that enable the driver but do not configure the number of sets */ +#if CONFIG_SUPERIO_ITE_COMMON_NUM_GPIO_SETS == 0 +#error "Maximum number of ITE SIO GPIO sets not provided" +#endif + +#if CONFIG_SUPERIO_ITE_COMMON_NUM_GPIO_SETS > 10 +#error "ITE SIO GPIO drivers only support up to 10 GPIO sets" +#endif + +/* GPIO Polarity Select: 1: Inverting, 0: Non-inverting */ +#define ITE_GPIO_REG_POLARITY(x) \ + (((x) > 8) ? (0xd1 + ((x) - 9) * 5) \ + : (0xb0 + ((x) - 1)) \ + ) + +/* GPIO Internal Pull-up: 1: Enable, 0: Disable */ +#define ITE_GPIO_REG_PULLUP(x) \ + (((x) > 8) ? (0xd4 + ((x) - 9) * 5) \ + : (0xb8 + ((x) - 1)) \ + ) + +/* GPIO Function Select: 1: Simple I/O, 0: Alternate function */ +#define ITE_GPIO_REG_FN_SELECT(x) \ + (((x) > 8) ? (0xd3 + ((x) - 9) * 5) \ + : (0xc0 + ((x) - 1)) \ + ) + +/* GPIO Mode: 0: input mode, 1: output mode */ +#define ITE_GPIO_REG_OUTPUT(x) \ + (((x) > 8) ? (0xd2 + ((x) - 9) * 5) \ + : (0xc8 + ((x) - 1)) \ + ) + +/* GPIO LED pin mapping register */ +#define ITE_GPIO_REG_LED_PINMAP(x) (0xf8 + ((x) & 1) * 2) +#define ITE_GPIO_LED_PIN_LOC(set, pin) ((((set) & 7) << 3) | ((pin) & 7)) +#define ITE_GPIO_LED_PIN_LOC_MASK 0x3f +/* GPIO LED control register */ +#define ITE_GPIO_REG_LED_CONTROL(x) (0xf9 + ((x) & 1) * 2) +#define ITE_GPIO_LED_OUTPUT_LOW (1 << 0) +#define ITE_GPIO_LED_PINMAP_CLEAR (1 << 4) +#define ITE_GPIO_LED_SHORT_LOW_PULSE \ + (CONFIG(SUPERIO_ITE_COMMON_GPIO_LED_FREQ_5BIT) ? (1 << 5) \ + : (1 << 3) \ + ) +#define ITE_GPIO_LED_FREQ_SEL(x) \ + (CONFIG(SUPERIO_ITE_COMMON_GPIO_LED_FREQ_5BIT) \ + ? ((((x) & 0x18) << 3) | (((x) & 0x7) << 1)) \ + : (((x) & 0x3) << 1) \ + ) +#define ITE_GPIO_LED_FREQ_SEL_MASK \ + (CONFIG(SUPERIO_ITE_COMMON_GPIO_LED_FREQ_5BIT) ? 0xce : 0x06) + +static bool ite_has_gpio_fn_select_reg(u8 set) +{ + /* IT8718F has all registers for all sets. */ + if (CONFIG(SUPERIO_ITE_IT8718F)) + return true; + + /* Typically ITE GPIO sets 6 to 8 don't have enable and polarity registers. */ + if (set < 6 || set > 8) + return true; + + return false; +} + +static bool ite_has_gpio_polarity_reg(u8 set) +{ + /* IT8718F has all registers for all sets. */ + if (CONFIG(SUPERIO_ITE_IT8718F)) + return true; + + /* IT8720F/IT8721F has polarity register for all GPIO sets */ + if (CONFIG(SUPERIO_ITE_IT8720F) || CONFIG(SUPERIO_ITE_IT8721F)) + return true; + + /* Typically ITE GPIO sets 6 to 8 don't have enable and polarity registers. */ + if (set < 6 || set > 8) + return true; + + return false; +} + +static bool ite_has_gpio_pullup_reg(u8 set) +{ + /* IT8718F/IT8720F does not have pull-up register for set 2 */ + if ((CONFIG(SUPERIO_ITE_IT8718F) || CONFIG(SUPERIO_ITE_IT8720F)) && (set == 2)) + return false; + + /* IT8783E/F does not have pull-up register for set 6 */ + if (CONFIG(SUPERIO_ITE_IT8783EF) && (set == 6)) + return false; + + /* + * ITE GPIO Sets 7 and 8 don't have a pullup register. + * See IT8786/IT8625 datasheet section 8.10.10. + * Also applies to IT8728F. + */ + if (set != 7 && set != 8) + return true; + + return false; +} + +/* + * Configures a single GPIO given its number as gpio_num, direction ("in_out" + * parameter) and properties, such as polarity and pull ("gpio_ctrl" + * parameter). The "enable" parameter can configure the GPIO in Simple I/O + * mode when set or Alternate function mode when clear. Some chips may also + * not support configuring all properties for a particular GPIO. It is left to + * the implementer to check if GPIO settings are valid for given gpio_num. + */ +void ite_gpio_setup(pnp_devfn_t gpiodev, u8 gpio_num, enum ite_gpio_direction in_out, + enum ite_gpio_mode enable, u8 gpio_ctrl) +{ + u8 set = (gpio_num / 10); + u8 pin = (gpio_num % 10); + + /* Number of configurable sets is chip dependent, 8 pins each */ + if (gpio_num < 10 || set > CONFIG_SUPERIO_ITE_COMMON_NUM_GPIO_SETS || pin > 7) + return; + + pnp_enter_conf_state(gpiodev); + pnp_set_logical_device(gpiodev); + + if (ite_has_gpio_fn_select_reg(set)) + pnp_unset_and_set_config(gpiodev, ITE_GPIO_REG_FN_SELECT(set), + 1 << pin, (enable & 1) << pin); + + if (ite_has_gpio_polarity_reg(set)) + pnp_unset_and_set_config(gpiodev, ITE_GPIO_REG_POLARITY(set), + 1 << pin, + (gpio_ctrl & ITE_GPIO_POL_INVERT) ? 1 << pin : 0); + + + pnp_unset_and_set_config(gpiodev, ITE_GPIO_REG_OUTPUT(set), 1 << pin, (in_out & 1) << pin); + + if (ite_has_gpio_pullup_reg(set)) + pnp_unset_and_set_config(gpiodev, ITE_GPIO_REG_PULLUP(set), 1 << pin, + (gpio_ctrl & ITE_GPIO_PULLUP_ENABLE) ? 1 << pin : 0); + + pnp_exit_conf_state(gpiodev); +} + +void ite_gpio_setup_led(pnp_devfn_t gpiodev, u8 gpio_num, + enum ite_gpio_led led_no, + enum ite_led_frequency freq, + u8 led_ctrl) +{ + u8 set = (gpio_num / 10); + u8 pin = (gpio_num % 10); + u8 reg = 0; + + /* Number of configurable sets is chip dependent, 8 pins each */ + if (gpio_num < 10 || set > CONFIG_SUPERIO_ITE_COMMON_NUM_GPIO_SETS || pin > 7) + return; + + /* LED is available only for GPIO sets 1-5 */ + if (set > 5) + return; + + pnp_enter_conf_state(gpiodev); + pnp_set_logical_device(gpiodev); + + /* Pinmap clear bit is only available when frequency is controlled with 5 bits */ + if (CONFIG(SUPERIO_ITE_COMMON_GPIO_LED_FREQ_5BIT) && (led_ctrl & ITE_LED_PINMAP_CLEAR)) + reg |= ITE_GPIO_LED_PINMAP_CLEAR; + + if (led_ctrl & ITE_LED_OUTPUT_LOW) + reg |= ITE_GPIO_LED_OUTPUT_LOW; + + if (led_ctrl & ITE_LED_SHORT_LOW_PULSE) + reg |= ITE_GPIO_LED_SHORT_LOW_PULSE; + + reg |= ITE_GPIO_LED_FREQ_SEL(freq); + pnp_write_config(gpiodev, ITE_GPIO_REG_LED_CONTROL(led_no), reg); + + reg = ITE_GPIO_LED_PIN_LOC(set, pin); + pnp_write_config(gpiodev, ITE_GPIO_REG_LED_PINMAP(led_no), reg); + + pnp_exit_conf_state(gpiodev); +} diff --git a/src/superio/ite/common/ite_gpio.h b/src/superio/ite/common/ite_gpio.h new file mode 100644 index 0000000000..ca1b209953 --- /dev/null +++ b/src/superio/ite/common/ite_gpio.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef SUPERIO_ITE_COMMON_GPIO_PRE_RAM_H +#define SUPERIO_ITE_COMMON_GPIO_PRE_RAM_H + +#include <device/pnp_type.h> +#include <stdint.h> + +#define ITE_GPIO_REG_SELECT(x) (0x25 + (x)) + +enum ite_gpio_control { + ITE_GPIO_CONTROL_DEFAULT = 0, + ITE_GPIO_POL_INVERT = (1 << 0), + ITE_GPIO_PULLUP_ENABLE = (1 << 1), +}; + +enum ite_gpio_direction { + ITE_GPIO_INPUT, + ITE_GPIO_OUTPUT +}; + +enum ite_gpio_mode { + ITE_GPIO_ALT_FN_MODE, + ITE_GPIO_SIMPLE_IO_MODE +}; + +/* There are two GP LED blink register sets */ +enum ite_gpio_led { + ITE_GPIO_LED_1, + ITE_GPIO_LED_2 +}; + +enum ite_led_control { + ITE_LED_CONTROL_DEFAULT = 0, + ITE_LED_SHORT_LOW_PULSE = (1 << 0), + ITE_LED_OUTPUT_LOW = (1 << 1), + /* + * Only for ITE SIOs with 5-bit frequency selection. + * When enabled, the LED pin mapping register is cleared when PANSWH# is low for over 4s. + */ + ITE_LED_PINMAP_CLEAR = (1 << 2), +}; + +enum ite_led_frequency { + /* Most ITE SIOs have 2-bit frequency selection */ + ITE_LED_FREQ_4HZ = 0, + ITE_LED_FREQ_1HZ = 1, + ITE_LED_FREQ_0P25HZ = 2, + ITE_LED_FREQ_0P125HZ = 3, + /* ITE SIOs with 5-bit frequency selection: IT8625, IT8613 */ + ITE_LED_FREQ_4HZ_DUTY_50 = 0, + ITE_LED_FREQ_1HZ_DUTY_50 = 1, + ITE_LED_FREQ_0P25HZ_DUTY_50 = 2, + ITE_LED_FREQ_2HZ_DUTY_50 = 3, + ITE_LED_FREQ_0P25HZ_DUTY_25 = 4, + ITE_LED_FREQ_0P25HZ_DUTY_75 = 5, + ITE_LED_FREQ_0P125HZ_DUTY_25 = 6, + ITE_LED_FREQ_0P125HZ_DUTY_75 = 7, + ITE_LED_FREQ_0P4HZ_DUTY_20 = 8, + ITE_LED_FREQ_0P5HZ_DUTY_50 = 16, + ITE_LED_FREQ_0P125HZ_DUTY_50 = 24, +}; + +void ite_gpio_setup(pnp_devfn_t gpiodev, u8 gpio_num, + enum ite_gpio_direction output, + enum ite_gpio_mode enable, + u8 gpio_ctrl); + +void ite_gpio_setup_led(pnp_devfn_t gpiodev, u8 gpio_num, + enum ite_gpio_led led_no, + enum ite_led_frequency freq, + u8 led_ctrl); + + +#endif /* SUPERIO_ITE_COMMON_PRE_RAM_H */ |