diff options
author | Tom Rini <trini@konsulko.com> | 2024-01-09 09:00:59 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2024-01-09 09:00:59 -0500 |
commit | cf476b6d988889f31785aa7fee70c2629386fd70 (patch) | |
tree | 76e5e97e37f2fb8c4a1839931adecbfc98a27b34 /drivers | |
parent | c7937a41992298752b9b424b9e4d222dfc157915 (diff) | |
parent | 5631d20e2ef1008d55569790f79672ea8cc6894b (diff) | |
download | u-boot-WIP/09Jan2024.zip u-boot-WIP/09Jan2024.tar.gz u-boot-WIP/09Jan2024.tar.bz2 |
Merge branch 'master' of https://gitlab.denx.de/u-boot/custodians/u-boot-samsungWIP/09Jan2024
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pinctrl/exynos/pinctrl-exynos.c | 125 | ||||
-rw-r--r-- | drivers/pinctrl/exynos/pinctrl-exynos.h | 36 | ||||
-rw-r--r-- | drivers/pinctrl/exynos/pinctrl-exynos7420.c | 2 |
3 files changed, 108 insertions, 55 deletions
diff --git a/drivers/pinctrl/exynos/pinctrl-exynos.c b/drivers/pinctrl/exynos/pinctrl-exynos.c index 8981854..8a045cd 100644 --- a/drivers/pinctrl/exynos/pinctrl-exynos.c +++ b/drivers/pinctrl/exynos/pinctrl-exynos.c @@ -9,11 +9,21 @@ #include <common.h> #include <dm.h> #include <errno.h> -#include <asm/global_data.h> #include <asm/io.h> #include "pinctrl-exynos.h" -DECLARE_GLOBAL_DATA_PTR; +/* CON, DAT, PUD, DRV */ +const struct samsung_pin_bank_type bank_type_alive = { + .fld_width = { 4, 1, 2, 2, }, + .reg_offset = { 0x00, 0x04, 0x08, 0x0c, }, +}; + +static const char * const exynos_pinctrl_props[PINCFG_TYPE_NUM] = { + [PINCFG_TYPE_FUNC] = "samsung,pin-function", + [PINCFG_TYPE_DAT] = "samsung,pin-val", + [PINCFG_TYPE_PUD] = "samsung,pin-pud", + [PINCFG_TYPE_DRV] = "samsung,pin-drv", +}; /** * exynos_pinctrl_setup_peri: setup pinctrl for a peripheral. @@ -34,30 +44,35 @@ void exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data *conf, } } -/* given a pin-name, return the address of pin config registers */ -static unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name, - u32 *pin) +static void parse_pin(const char *pin_name, u32 *pin, char *bank_name) { - struct exynos_pinctrl_priv *priv = dev_get_priv(dev); - const struct samsung_pin_ctrl *pin_ctrl_array = priv->pin_ctrl; - const struct samsung_pin_bank_data *bank_data; - u32 nr_banks, pin_ctrl_idx = 0, idx = 0, bank_base; - char bank[10]; + u32 idx = 0; /* - * The format of the pin name is <bank name>-<pin_number>. - * Example: gpa0-4 (gpa0 is the bank name and 4 is the pin number. + * The format of the pin name is <bank_name name>-<pin_number>. + * Example: gpa0-4 (gpa0 is the bank_name name and 4 is the pin number. */ while (pin_name[idx] != '-') { - bank[idx] = pin_name[idx]; + bank_name[idx] = pin_name[idx]; idx++; } - bank[idx] = '\0'; + bank_name[idx] = '\0'; *pin = pin_name[++idx] - '0'; +} + +/* given a bank name, find out the pin bank structure */ +static const struct samsung_pin_bank_data *get_bank(struct udevice *dev, + const char *bank_name) +{ + struct exynos_pinctrl_priv *priv = dev_get_priv(dev); + const struct samsung_pin_ctrl *pin_ctrl_array = priv->pin_ctrl; + const struct samsung_pin_bank_data *bank_data; + u32 nr_banks, pin_ctrl_idx = 0, idx = 0; /* lookup the pin bank data using the pin bank name */ while (true) { - const struct samsung_pin_ctrl *pin_ctrl = &pin_ctrl_array[pin_ctrl_idx]; + const struct samsung_pin_ctrl *pin_ctrl = + &pin_ctrl_array[pin_ctrl_idx]; nr_banks = pin_ctrl->nr_banks; if (!nr_banks) @@ -67,15 +82,29 @@ static unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name, for (idx = 0; idx < nr_banks; idx++) { debug("pinctrl[%d] bank_data[%d] name is: %s\n", pin_ctrl_idx, idx, bank_data[idx].name); - if (!strcmp(bank, bank_data[idx].name)) { - bank_base = priv->base + bank_data[idx].offset; - break; - } + if (!strcmp(bank_name, bank_data[idx].name)) + return &bank_data[idx]; } pin_ctrl_idx++; } - return bank_base; + return NULL; +} + +static void exynos_pinctrl_set_pincfg(unsigned long reg_base, u32 pin_num, + u32 val, enum pincfg_type pincfg, + const struct samsung_pin_bank_type *type) +{ + u32 width = type->fld_width[pincfg]; + u32 reg_offset = type->reg_offset[pincfg]; + u32 mask = (1 << width) - 1; + u32 shift = pin_num * width; + u32 data; + + data = readl(reg_base + reg_offset); + data &= ~(mask << shift); + data |= val << shift; + writel(data, reg_base + reg_offset); } /** @@ -85,50 +114,46 @@ static unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name, */ int exynos_pinctrl_set_state(struct udevice *dev, struct udevice *config) { - const void *fdt = gd->fdt_blob; - int node = dev_of_offset(config); - unsigned int count, idx, pin_num; - unsigned int pinfunc, pinpud, pindrv; - unsigned long reg, value; - const char *name; + struct exynos_pinctrl_priv *priv = dev_get_priv(dev); + unsigned int count, idx; + unsigned int pinvals[PINCFG_TYPE_NUM]; /* * refer to the following document for the pinctrl bindings * linux/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt */ - count = fdt_stringlist_count(fdt, node, "samsung,pins"); + count = dev_read_string_count(config, "samsung,pins"); if (count <= 0) return -EINVAL; - pinfunc = fdtdec_get_int(fdt, node, "samsung,pin-function", -1); - pinpud = fdtdec_get_int(fdt, node, "samsung,pin-pud", -1); - pindrv = fdtdec_get_int(fdt, node, "samsung,pin-drv", -1); + for (idx = 0; idx < PINCFG_TYPE_NUM; ++idx) { + pinvals[idx] = dev_read_u32_default(config, + exynos_pinctrl_props[idx], -1); + } + pinvals[PINCFG_TYPE_DAT] = -1; /* ignore GPIO data register */ for (idx = 0; idx < count; idx++) { - name = fdt_stringlist_get(fdt, node, "samsung,pins", idx, NULL); - if (!name) + const struct samsung_pin_bank_data *bank; + unsigned int pin_num; + char bank_name[10]; + unsigned long reg; + const char *name = NULL; + int pincfg, err; + + err = dev_read_string_index(config, "samsung,pins", idx, &name); + if (err || !name) continue; - reg = pin_to_bank_base(dev, name, &pin_num); - if (pinfunc != -1) { - value = readl(reg + PIN_CON); - value &= ~(0xf << (pin_num << 2)); - value |= (pinfunc << (pin_num << 2)); - writel(value, reg + PIN_CON); - } + parse_pin(name, &pin_num, bank_name); + bank = get_bank(dev, bank_name); + reg = priv->base + bank->offset; - if (pinpud != -1) { - value = readl(reg + PIN_PUD); - value &= ~(0x3 << (pin_num << 1)); - value |= (pinpud << (pin_num << 1)); - writel(value, reg + PIN_PUD); - } + for (pincfg = 0; pincfg < PINCFG_TYPE_NUM; ++pincfg) { + unsigned int val = pinvals[pincfg]; - if (pindrv != -1) { - value = readl(reg + PIN_DRV); - value &= ~(0x3 << (pin_num << 1)); - value |= (pindrv << (pin_num << 1)); - writel(value, reg + PIN_DRV); + if (val != -1) + exynos_pinctrl_set_pincfg(reg, pin_num, val, + pincfg, bank->type); } } diff --git a/drivers/pinctrl/exynos/pinctrl-exynos.h b/drivers/pinctrl/exynos/pinctrl-exynos.h index cbc5174..743bb55 100644 --- a/drivers/pinctrl/exynos/pinctrl-exynos.h +++ b/drivers/pinctrl/exynos/pinctrl-exynos.h @@ -8,26 +8,52 @@ #ifndef __PINCTRL_EXYNOS_H_ #define __PINCTRL_EXYNOS_H_ -#define PIN_CON 0x00 /* Offset of pin function register */ -#define PIN_DAT 0x04 /* Offset of pin data register */ -#define PIN_PUD 0x08 /* Offset of pin pull up/down config register */ -#define PIN_DRV 0x0C /* Offset of pin drive strength register */ +/** + * enum pincfg_type - possible pin configuration types supported. + * @PINCFG_TYPE_FUNC: Function configuration. + * @PINCFG_TYPE_DAT: Pin value configuration. + * @PINCFG_TYPE_PUD: Pull up/down configuration. + * @PINCFG_TYPE_DRV: Drive strength configuration. + */ +enum pincfg_type { + PINCFG_TYPE_FUNC, + PINCFG_TYPE_DAT, + PINCFG_TYPE_PUD, + PINCFG_TYPE_DRV, + + PINCFG_TYPE_NUM +}; + +/** + * struct samsung_pin_bank_type: pin bank type description + * @fld_width: widths of configuration bitfields (0 if unavailable) + * @reg_offset: offsets of configuration registers (don't care of width is 0) + */ +struct samsung_pin_bank_type { + u8 fld_width[PINCFG_TYPE_NUM]; + u8 reg_offset[PINCFG_TYPE_NUM]; +}; /** * struct samsung_pin_bank_data: represent a controller pin-bank data. + * @type: type of the bank (register offsets and bitfield widths) * @offset: starting offset of the pin-bank registers. * @nr_pins: number of pins included in this bank. * @name: name to be prefixed for each pin in this pin bank. */ struct samsung_pin_bank_data { + const struct samsung_pin_bank_type *type; u32 offset; u8 nr_pins; const char *name; }; +extern const struct samsung_pin_bank_type bank_type_alive; + #define EXYNOS_PIN_BANK(pins, reg, id) \ { \ - .offset = reg, \ + .type = &bank_type_alive, \ + .offset = reg, \ .nr_pins = pins, \ .name = id \ } diff --git a/drivers/pinctrl/exynos/pinctrl-exynos7420.c b/drivers/pinctrl/exynos/pinctrl-exynos7420.c index 07870b7..77d510d 100644 --- a/drivers/pinctrl/exynos/pinctrl-exynos7420.c +++ b/drivers/pinctrl/exynos/pinctrl-exynos7420.c @@ -16,6 +16,8 @@ #include "pinctrl-exynos.h" #define GPD1_OFFSET 0xc0 +#define PIN_CON 0x00 /* Offset of pin function register */ +#define PIN_PUD 0x08 /* Offset of pin pull up/down config register */ static struct exynos_pinctrl_config_data serial2_conf[] = { { |