diff options
-rw-r--r-- | arch/arm/cpu/armv7/s5p4418/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/s5p4418/relocate.S | 24 | ||||
-rw-r--r-- | common/board_f.c | 2 | ||||
-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 |
6 files changed, 136 insertions, 56 deletions
diff --git a/arch/arm/cpu/armv7/s5p4418/Makefile b/arch/arm/cpu/armv7/s5p4418/Makefile index 321b257..5804258 100644 --- a/arch/arm/cpu/armv7/s5p4418/Makefile +++ b/arch/arm/cpu/armv7/s5p4418/Makefile @@ -2,5 +2,8 @@ # # (C) Copyright 2016 Nexell # Hyunseok, Jung <hsjung@nexell.co.kr> +# +# Copyright (C) 2023 Stefan Bosch <stefan_b@posteo.net> obj-y += cpu.o +obj-y += relocate.o diff --git a/arch/arm/cpu/armv7/s5p4418/relocate.S b/arch/arm/cpu/armv7/s5p4418/relocate.S new file mode 100644 index 0000000..d6e76ad --- /dev/null +++ b/arch/arm/cpu/armv7/s5p4418/relocate.S @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * relocate - S5P4418 specific relocation for ARM U-Boot + * + * Copyright (c) 2013 Albert ARIBAUD <albert.u.boot@aribaud.net> + * Copyright (C) 2023 Stefan Bosch <stefan_b@posteo.net> + */ + +#include <asm-offsets.h> +#include <asm/assembler.h> +#include <linux/linkage.h> + +ENTRY(relocate_vectors) + + /* + * The s5p4418 SoC has the security extensions, so use VBAR to relocate + * the exception vectors. + */ + ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */ + add r0, #0x400 /* vectors are after NSIH + 0x200 */ + mcr p15, 0, r0, c12, c0, 0 /* Set VBAR */ + ret lr + +ENDPROC(relocate_vectors) diff --git a/common/board_f.c b/common/board_f.c index d4d7d01..d2e4d9e 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -283,7 +283,7 @@ static int init_func_i2c(void) static int setup_mon_len(void) { #if defined(__ARM__) || defined(__MICROBLAZE__) - gd->mon_len = (ulong)__bss_end - (ulong)_start; + gd->mon_len = (ulong)__bss_end - (ulong)__image_copy_start; #elif defined(CONFIG_SANDBOX) && !defined(__riscv) gd->mon_len = (ulong)_end - (ulong)_init; #elif defined(CONFIG_SANDBOX) 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[] = { { |