diff options
author | Yann Gautier <yann.gautier@st.com> | 2019-01-17 19:17:47 +0100 |
---|---|---|
committer | Yann Gautier <yann.gautier@st.com> | 2019-01-18 15:45:08 +0100 |
commit | 1fc2130c5b8aad9abf54d71ce0124b19f44c69ce (patch) | |
tree | f29fe0872b519a367a978796f72577b6fce3b3f1 /drivers/st | |
parent | 59a1cdf16a49ef2bf1a505290cd8b689dfd3e5a1 (diff) |
stm32mp1: update device tree and gpio functions
Change fdt_check_status function to fdt_get_status.
Update GPIO defines.
Move some functions in gpio driver, instead of dt helper file.
Add GPIO bank helper functions.
Use only one status field in dt_node_info structure including both status
and secure status.
Change-Id: I34f93408dd4aac16ae722f564bc3f7d6ae978cf4
Signed-off-by: Yann Gautier <yann.gautier@st.com>
Signed-off-by: Etienne Carriere <etienne.carriere@st.com>
Signed-off-by: Lionel Debieve <lionel.debieve@st.com>
Signed-off-by: Nicolas Le Bayon <nicolas.le.bayon@st.com>
Diffstat (limited to 'drivers/st')
-rw-r--r-- | drivers/st/clk/stm32mp1_clkfunc.c | 24 | ||||
-rw-r--r-- | drivers/st/gpio/stm32_gpio.c | 224 | ||||
-rw-r--r-- | drivers/st/mmc/stm32_sdmmc2.c | 3 | ||||
-rw-r--r-- | drivers/st/pmic/stm32mp_pmic.c | 2 |
4 files changed, 225 insertions, 28 deletions
diff --git a/drivers/st/clk/stm32mp1_clkfunc.c b/drivers/st/clk/stm32mp1_clkfunc.c index e176f97d..19dfe1b2 100644 --- a/drivers/st/clk/stm32mp1_clkfunc.c +++ b/drivers/st/clk/stm32mp1_clkfunc.c @@ -32,6 +32,14 @@ const char *stm32mp_osc_node_label[NB_OSC] = { }; /******************************************************************************* + * This function returns the RCC node in the device tree. + ******************************************************************************/ +static int fdt_get_rcc_node(void *fdt) +{ + return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); +} + +/******************************************************************************* * This function reads the frequency of an oscillator from its name. * It reads the value indicated inside the device tree. * Returns 0 on success, and a negative FDT/ERRNO error code on failure. @@ -240,7 +248,7 @@ int fdt_rcc_read_uint32_array(const char *prop_name, /******************************************************************************* * This function gets the subnode offset in rcc-clk section from its name. * It reads the values indicated inside the device tree. - * Returns offset if success, and a negative value else. + * Returns offset on success, and a negative FDT/ERRNO error code on failure. ******************************************************************************/ int fdt_rcc_subnode_offset(const char *name) { @@ -251,7 +259,7 @@ int fdt_rcc_subnode_offset(const char *name) return -ENOENT; } - node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); + node = fdt_get_rcc_node(fdt); if (node < 0) { return -FDT_ERR_NOTFOUND; } @@ -280,7 +288,7 @@ const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) return NULL; } - node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); + node = fdt_get_rcc_node(fdt); if (node < 0) { return NULL; } @@ -297,7 +305,7 @@ const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) /******************************************************************************* * This function gets the secure status for rcc node. * It reads secure-status in device tree. - * Returns 1 if rcc is available from secure world, 0 else. + * Returns true if rcc is available from secure world, false if not. ******************************************************************************/ bool fdt_get_rcc_secure_status(void) { @@ -308,18 +316,18 @@ bool fdt_get_rcc_secure_status(void) return false; } - node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_COMPAT); + node = fdt_get_rcc_node(fdt); if (node < 0) { return false; } - return fdt_check_secure_status(node); + return (fdt_get_status(node) & DT_SECURE) != 0U; } /******************************************************************************* * This function reads the stgen base address. * It reads the value indicated inside the device tree. - * Returns address if success, and NULL value else. + * Returns address on success, and NULL value on failure. ******************************************************************************/ uintptr_t fdt_get_stgen_base(void) { @@ -347,7 +355,7 @@ uintptr_t fdt_get_stgen_base(void) /******************************************************************************* * This function gets the clock ID of the given node. * It reads the value indicated inside the device tree. - * Returns ID if success, and a negative value else. + * Returns ID on success, and a negative FDT/ERRNO error code on failure. ******************************************************************************/ int fdt_get_clock_id(int node) { diff --git a/drivers/st/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c index bbee1387..d217c450 100644 --- a/drivers/st/gpio/stm32_gpio.c +++ b/drivers/st/gpio/stm32_gpio.c @@ -4,44 +4,212 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include <assert.h> +#include <errno.h> #include <stdbool.h> +#include <libfdt.h> + +#include <platform_def.h> + #include <common/bl_common.h> #include <common/debug.h> #include <drivers/st/stm32_gpio.h> +#include <drivers/st/stm32mp1_clk.h> +#include <drivers/st/stm32mp1_clkfunc.h> #include <lib/mmio.h> +#include <lib/utils_def.h> -static bool check_gpio(uint32_t bank, uint32_t pin) +#define DT_GPIO_BANK_SHIFT 12 +#define DT_GPIO_BANK_MASK GENMASK(16, 12) +#define DT_GPIO_PIN_SHIFT 8 +#define DT_GPIO_PIN_MASK GENMASK(11, 8) +#define DT_GPIO_MODE_MASK GENMASK(7, 0) + +/******************************************************************************* + * This function gets GPIO bank node in DT. + * Returns node offset if status is okay in DT, else return 0 + ******************************************************************************/ +static int ckeck_gpio_bank(void *fdt, uint32_t bank, int pinctrl_node) { - if (pin > GPIO_PIN_MAX) { - ERROR("%s: wrong pin number (%d)\n", __func__, pin); - return false; - } + int pinctrl_subnode; + uint32_t bank_offset = stm32_get_gpio_bank_offset(bank); - if ((bank > GPIO_BANK_K) && (bank != GPIO_BANK_Z)) { - ERROR("%s: wrong GPIO bank number (%d)\n", __func__, bank); - return false; + fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) { + const fdt32_t *cuint; + + if (fdt_getprop(fdt, pinctrl_subnode, + "gpio-controller", NULL) == NULL) { + continue; + } + + cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL); + if (cuint == NULL) { + continue; + } + + if ((fdt32_to_cpu(*cuint) == bank_offset) && + (fdt_get_status(pinctrl_subnode) != DT_DISABLED)) { + return pinctrl_subnode; + } } - return true; + return 0; } -void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed, - uint32_t pull, uint32_t alternate) +/******************************************************************************* + * This function gets the pin settings from DT information. + * When analyze and parsing is done, set the GPIO registers. + * Returns 0 on success and a negative FDT error code on failure. + ******************************************************************************/ +static int dt_set_gpio_config(void *fdt, int node, uint8_t status) { - uintptr_t base; + const fdt32_t *cuint, *slewrate; + int len; + int pinctrl_node; + uint32_t i; + uint32_t speed = GPIO_SPEED_LOW; + uint32_t pull = GPIO_NO_PULL; - if (!check_gpio(bank, pin)) { - return; + cuint = fdt_getprop(fdt, node, "pinmux", &len); + if (cuint == NULL) { + return -FDT_ERR_NOTFOUND; } - if (bank == GPIO_BANK_Z) { - base = STM32_GPIOZ_BANK; + pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node)); + if (pinctrl_node < 0) { + return -FDT_ERR_NOTFOUND; + } + + slewrate = fdt_getprop(fdt, node, "slew-rate", NULL); + if (slewrate != NULL) { + speed = fdt32_to_cpu(*slewrate); + } + + if (fdt_getprop(fdt, node, "bias-pull-up", NULL) != NULL) { + pull = GPIO_PULL_UP; + } else if (fdt_getprop(fdt, node, "bias-pull-down", NULL) != NULL) { + pull = GPIO_PULL_DOWN; } else { - base = STM32_GPIOA_BANK + - (bank * STM32_GPIO_BANK_OFFSET); + VERBOSE("No bias configured in node %d\n", node); } + for (i = 0U; i < ((uint32_t)len / sizeof(uint32_t)); i++) { + uint32_t pincfg; + uint32_t bank; + uint32_t pin; + uint32_t mode; + uint32_t alternate = GPIO_ALTERNATE_(0); + int bank_node; + int clk; + + pincfg = fdt32_to_cpu(*cuint); + cuint++; + + bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT; + + pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT; + + mode = pincfg & DT_GPIO_MODE_MASK; + + switch (mode) { + case 0: + mode = GPIO_MODE_INPUT; + break; + case 1 ... 16: + alternate = mode - 1U; + mode = GPIO_MODE_ALTERNATE; + break; + case 17: + mode = GPIO_MODE_ANALOG; + break; + default: + mode = GPIO_MODE_OUTPUT; + break; + } + + if (fdt_getprop(fdt, node, "drive-open-drain", NULL) != NULL) { + mode |= GPIO_OPEN_DRAIN; + } + + bank_node = ckeck_gpio_bank(fdt, bank, pinctrl_node); + if (bank_node == 0) { + ERROR("PINCTRL inconsistent in DT\n"); + panic(); + } + + clk = fdt_get_clock_id(bank_node); + if (clk < 0) { + return -FDT_ERR_NOTFOUND; + } + + /* Platform knows the clock: assert it is okay */ + assert((unsigned long)clk == stm32_get_gpio_bank_clock(bank)); + + set_gpio(bank, pin, mode, speed, pull, alternate, status); + } + + return 0; +} + +/******************************************************************************* + * This function gets the pin settings from DT information. + * When analyze and parsing is done, set the GPIO registers. + * Returns 0 on success and a negative FDT/ERRNO error code on failure. + ******************************************************************************/ +int dt_set_pinctrl_config(int node) +{ + const fdt32_t *cuint; + int lenp = 0; + uint32_t i; + uint8_t status = fdt_get_status(node); + void *fdt; + + if (fdt_get_address(&fdt) == 0) { + return -ENOENT; + } + + if (status == DT_DISABLED) { + return -FDT_ERR_NOTFOUND; + } + + cuint = fdt_getprop(fdt, node, "pinctrl-0", &lenp); + if (cuint == NULL) { + return -FDT_ERR_NOTFOUND; + } + + for (i = 0; i < ((uint32_t)lenp / 4U); i++) { + int p_node, p_subnode; + + p_node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); + if (p_node < 0) { + return -FDT_ERR_NOTFOUND; + } + + fdt_for_each_subnode(p_subnode, fdt, p_node) { + int ret = dt_set_gpio_config(fdt, p_subnode, status); + + if (ret < 0) { + return ret; + } + } + + cuint++; + } + + return 0; +} + +void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed, + uint32_t pull, uint32_t alternate, uint8_t status) +{ + uintptr_t base = stm32_get_gpio_bank_base(bank); + unsigned long clock = stm32_get_gpio_bank_clock(bank); + + assert(pin <= GPIO_PIN_MAX); + + stm32mp1_clk_enable(clock); + mmio_clrbits_32(base + GPIO_MODE_OFFSET, ((uint32_t)GPIO_MODE_MASK << (pin << 1))); mmio_setbits_32(base + GPIO_MODE_OFFSET, @@ -85,4 +253,24 @@ void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed, mmio_read_32(base + GPIO_AFRL_OFFSET)); VERBOSE("GPIO %u mode alternate high to 0x%x\n", bank, mmio_read_32(base + GPIO_AFRH_OFFSET)); + + stm32mp1_clk_disable((unsigned long)clock); +} + +void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure) +{ + uintptr_t base = stm32_get_gpio_bank_base(bank); + int clock = stm32_get_gpio_bank_clock(bank); + + assert(pin <= GPIO_PIN_MAX); + + stm32mp1_clk_enable((unsigned long)clock); + + if (secure) { + mmio_setbits_32(base + GPIO_SECR_OFFSET, BIT(pin)); + } else { + mmio_clrbits_32(base + GPIO_SECR_OFFSET, BIT(pin)); + } + + stm32mp1_clk_disable((unsigned long)clock); } diff --git a/drivers/st/mmc/stm32_sdmmc2.c b/drivers/st/mmc/stm32_sdmmc2.c index 453455cd..57812d89 100644 --- a/drivers/st/mmc/stm32_sdmmc2.c +++ b/drivers/st/mmc/stm32_sdmmc2.c @@ -17,6 +17,7 @@ #include <common/debug.h> #include <drivers/delay_timer.h> #include <drivers/mmc.h> +#include <drivers/st/stm32_gpio.h> #include <drivers/st/stm32_sdmmc2.h> #include <drivers/st/stm32mp1_clk.h> #include <drivers/st/stm32mp1_rcc.h> @@ -642,7 +643,7 @@ static int stm32_sdmmc2_dt_get_config(void) return -FDT_ERR_NOTFOUND; } - if (fdt_check_status(sdmmc_node) == 0) { + if (fdt_get_status(sdmmc_node) == DT_DISABLED) { return -FDT_ERR_NOTFOUND; } diff --git a/drivers/st/pmic/stm32mp_pmic.c b/drivers/st/pmic/stm32mp_pmic.c index 80b4cab5..6beabc15 100644 --- a/drivers/st/pmic/stm32mp_pmic.c +++ b/drivers/st/pmic/stm32mp_pmic.c @@ -61,7 +61,7 @@ bool dt_check_pmic(void) return false; } - return fdt_check_status(node); + return fdt_get_status(node); } static int dt_pmic_i2c_config(struct dt_node_info *i2c_info) |