From b799eabc7ee3086a708297d2309ebfe0be9adb68 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Thu, 12 Aug 2021 20:09:43 -0500 Subject: [PATCH 01/40] sunxi: pinctrl: Create the driver skeleton Create a do-nothing driver for each sunxi pin controller variant. Since only one driver can automatically bind to a DT node, since the GPIO driver already requires a manual binding process, and since the pinctrl driver needs access to some of the same information, refactor the GPIO driver to be bound by the pinctrl driver. This commit should cause no functional change. Signed-off-by: Samuel Holland Signed-off-by: Andre Przywara --- MAINTAINERS | 1 + arch/arm/Kconfig | 1 + arch/arm/include/asm/arch-sunxi/gpio.h | 5 + drivers/gpio/sunxi_gpio.c | 130 +-------- drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Makefile | 2 +- drivers/pinctrl/sunxi/Kconfig | 125 +++++++++ drivers/pinctrl/sunxi/Makefile | 3 + drivers/pinctrl/sunxi/pinctrl-sunxi.c | 362 +++++++++++++++++++++++++ 9 files changed, 501 insertions(+), 129 deletions(-) create mode 100644 drivers/pinctrl/sunxi/Kconfig create mode 100644 drivers/pinctrl/sunxi/Makefile create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi.c diff --git a/MAINTAINERS b/MAINTAINERS index 96582fc6777..712c2b19790 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -520,6 +520,7 @@ F: arch/arm/mach-sunxi/ F: board/sunxi/ F: drivers/clk/sunxi/ F: drivers/phy/allwinner/ +F: drivers/pinctrl/sunxi/ F: drivers/video/sunxi/ ARM TEGRA diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4567c183fb8..ea3d7ece910 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1072,6 +1072,7 @@ config ARCH_SUNXI select OF_BOARD_SETUP select OF_CONTROL select OF_SEPARATE + select PINCTRL select SPECIFY_CONSOLE_INDEX select SPL_SEPARATE_BSS if SPL select SPL_STACK_R if SPL diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index edd0fbf49fe..773711b6a3f 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -224,6 +224,11 @@ enum sunxi_gpio_number { #define SUNXI_GPIO_AXP0_VBUS_ENABLE 5 #define SUNXI_GPIO_AXP0_GPIO_COUNT 6 +struct sunxi_gpio_plat { + struct sunxi_gpio *regs; + char bank_name[3]; +}; + void sunxi_gpio_set_cfgbank(struct sunxi_gpio *pio, int bank_offset, u32 val); void sunxi_gpio_set_cfgpin(u32 pin, u32 val); int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset); diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index 6c3c10862c4..1e85db179a6 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -16,15 +16,8 @@ #include #include #include -#include #include -struct sunxi_gpio_plat { - struct sunxi_gpio *regs; - const char *bank_name; /* Name of bank, e.g. "B" */ - int gpio_count; -}; - #if !CONFIG_IS_ENABLED(DM_GPIO) static int sunxi_gpio_output(u32 pin, u32 val) { @@ -211,28 +204,6 @@ static const struct dm_gpio_ops gpio_sunxi_ops = { .set_flags = sunxi_gpio_set_flags, }; -/** - * Returns the name of a GPIO bank - * - * GPIO banks are named A, B, C, ... - * - * @bank: Bank number (0, 1..n-1) - * Return: allocated string containing the name - */ -static char *gpio_bank_name(int bank) -{ - char *name; - - name = malloc(3); - if (name) { - name[0] = 'P'; - name[1] = 'A' + bank; - name[2] = '\0'; - } - - return name; -} - static int gpio_sunxi_probe(struct udevice *dev) { struct sunxi_gpio_plat *plat = dev_get_plat(dev); @@ -240,114 +211,17 @@ static int gpio_sunxi_probe(struct udevice *dev) /* Tell the uclass how many GPIOs we have */ if (plat) { - uc_priv->gpio_count = plat->gpio_count; + uc_priv->gpio_count = SUNXI_GPIOS_PER_BANK; uc_priv->bank_name = plat->bank_name; } return 0; } -struct sunxi_gpio_soc_data { - int start; - int no_banks; -}; - -/** - * We have a top-level GPIO device with no actual GPIOs. It has a child - * device for each Sunxi bank. - */ -static int gpio_sunxi_bind(struct udevice *parent) -{ - struct sunxi_gpio_soc_data *soc_data = - (struct sunxi_gpio_soc_data *)dev_get_driver_data(parent); - struct sunxi_gpio_plat *plat = dev_get_plat(parent); - struct sunxi_gpio_reg *ctlr; - int bank, ret; - - /* If this is a child device, there is nothing to do here */ - if (plat) - return 0; - - ctlr = dev_read_addr_ptr(parent); - for (bank = 0; bank < soc_data->no_banks; bank++) { - struct sunxi_gpio_plat *plat; - struct udevice *dev; - - plat = calloc(1, sizeof(*plat)); - if (!plat) - return -ENOMEM; - plat->regs = &ctlr->gpio_bank[bank]; - plat->bank_name = gpio_bank_name(soc_data->start + bank); - plat->gpio_count = SUNXI_GPIOS_PER_BANK; - - ret = device_bind(parent, parent->driver, plat->bank_name, plat, - dev_ofnode(parent), &dev); - if (ret) - return ret; - } - - return 0; -} - -static const struct sunxi_gpio_soc_data soc_data_a_all = { - .start = 0, - .no_banks = SUNXI_GPIO_BANKS, -}; - -static const struct sunxi_gpio_soc_data soc_data_l_1 = { - .start = 'L' - 'A', - .no_banks = 1, -}; - -static const struct sunxi_gpio_soc_data soc_data_l_2 = { - .start = 'L' - 'A', - .no_banks = 2, -}; - -static const struct sunxi_gpio_soc_data soc_data_l_3 = { - .start = 'L' - 'A', - .no_banks = 3, -}; - -#define ID(_compat_, _soc_data_) \ - { .compatible = _compat_, .data = (ulong)&soc_data_##_soc_data_ } - -static const struct udevice_id sunxi_gpio_ids[] = { - ID("allwinner,sun4i-a10-pinctrl", a_all), - ID("allwinner,sun5i-a10s-pinctrl", a_all), - ID("allwinner,sun5i-a13-pinctrl", a_all), - ID("allwinner,sun50i-h5-pinctrl", a_all), - ID("allwinner,sun6i-a31-pinctrl", a_all), - ID("allwinner,sun6i-a31s-pinctrl", a_all), - ID("allwinner,sun7i-a20-pinctrl", a_all), - ID("allwinner,sun8i-a23-pinctrl", a_all), - ID("allwinner,sun8i-a33-pinctrl", a_all), - ID("allwinner,sun8i-a83t-pinctrl", a_all), - ID("allwinner,sun8i-h3-pinctrl", a_all), - ID("allwinner,sun8i-r40-pinctrl", a_all), - ID("allwinner,sun8i-v3-pinctrl", a_all), - ID("allwinner,sun8i-v3s-pinctrl", a_all), - ID("allwinner,sun9i-a80-pinctrl", a_all), - ID("allwinner,sun50i-a64-pinctrl", a_all), - ID("allwinner,sun50i-h6-pinctrl", a_all), - ID("allwinner,sun50i-h616-pinctrl", a_all), - ID("allwinner,sun6i-a31-r-pinctrl", l_2), - ID("allwinner,sun8i-a23-r-pinctrl", l_1), - ID("allwinner,sun8i-a83t-r-pinctrl", l_1), - ID("allwinner,sun8i-h3-r-pinctrl", l_1), - ID("allwinner,sun9i-a80-r-pinctrl", l_3), - ID("allwinner,sun50i-a64-r-pinctrl", l_1), - ID("allwinner,sun50i-h6-r-pinctrl", l_2), - ID("allwinner,sun50i-h616-r-pinctrl", l_1), - { } -}; - U_BOOT_DRIVER(gpio_sunxi) = { .name = "gpio_sunxi", .id = UCLASS_GPIO, - .ops = &gpio_sunxi_ops, - .of_match = sunxi_gpio_ids, - .bind = gpio_sunxi_bind, .probe = gpio_sunxi_probe, + .ops = &gpio_sunxi_ops, }; #endif /* DM_GPIO */ diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 03946245c7d..6a640ba3a21 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -332,6 +332,7 @@ source "drivers/pinctrl/nexell/Kconfig" source "drivers/pinctrl/nxp/Kconfig" source "drivers/pinctrl/renesas/Kconfig" source "drivers/pinctrl/rockchip/Kconfig" +source "drivers/pinctrl/sunxi/Kconfig" source "drivers/pinctrl/uniphier/Kconfig" endmenu diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index df37c32033f..32283ddd88d 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -14,7 +14,7 @@ obj-$(CONFIG_PINCTRL_INTEL) += intel/ obj-$(CONFIG_ARCH_MTMIPS) += mtmips/ obj-$(CONFIG_ARCH_RMOBILE) += renesas/ obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o - +obj-$(CONFIG_PINCTRL_SUNXI) += sunxi/ obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_PINCTRL_PIC32) += pinctrl_pic32.o obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig new file mode 100644 index 00000000000..96c2f35f3a5 --- /dev/null +++ b/drivers/pinctrl/sunxi/Kconfig @@ -0,0 +1,125 @@ +# SPDX-License-Identifier: GPL-2.0 + +if ARCH_SUNXI + +config PINCTRL_SUNXI + select PINCTRL_FULL + select PINCTRL_GENERIC + bool + +config PINCTRL_SUNIV_F1C100S + bool "Support for the Allwinner F1C100s PIO" + default MACH_SUNIV + select PINCTRL_SUNXI + +config PINCTRL_SUN4I_A10 + bool "Support for the Allwinner A10 PIO" + default MACH_SUN4I + select PINCTRL_SUNXI + +config PINCTRL_SUN5I_A13 + bool "Support for the Allwinner A10s/A13 PIO" + default MACH_SUN5I + select PINCTRL_SUNXI + +config PINCTRL_SUN6I_A31 + bool "Support for the Allwinner A31 PIO" + default MACH_SUN6I + select PINCTRL_SUNXI + +config PINCTRL_SUN6I_A31_R + bool "Support for the Allwinner A31 R-PIO" + default MACH_SUN6I + select PINCTRL_SUNXI + +config PINCTRL_SUN7I_A20 + bool "Support for the Allwinner A20/R40 PIO" + default MACH_SUN7I || MACH_SUN8I_R40 + select PINCTRL_SUNXI + +config PINCTRL_SUN8I_A23 + bool "Support for the Allwinner A23 PIO" + default MACH_SUN8I_A23 + select PINCTRL_SUNXI + +config PINCTRL_SUN8I_A23_R + bool "Support for the Allwinner A23/A33 R-PIO" + default MACH_SUN8I_A23 || MACH_SUN8I_A33 + select PINCTRL_SUNXI + +config PINCTRL_SUN8I_A33 + bool "Support for the Allwinner A33 PIO" + default MACH_SUN8I_A33 + select PINCTRL_SUNXI + +config PINCTRL_SUN8I_A83T + bool "Support for the Allwinner A83T PIO" + default MACH_SUN8I_A83T + select PINCTRL_SUNXI + +config PINCTRL_SUN8I_A83T_R + bool "Support for the Allwinner A83T R-PIO" + default MACH_SUN8I_A83T + select PINCTRL_SUNXI + +config PINCTRL_SUN8I_H3 + bool "Support for the Allwinner H3 PIO" + default MACH_SUN8I_H3 + select PINCTRL_SUNXI + +config PINCTRL_SUN8I_H3_R + bool "Support for the Allwinner H3/H5 R-PIO" + default MACH_SUN8I_H3 || MACH_SUN50I_H5 + select PINCTRL_SUNXI + +config PINCTRL_SUN8I_V3S + bool "Support for the Allwinner V3s PIO" + default MACH_SUN8I_V3S + select PINCTRL_SUNXI + +config PINCTRL_SUN9I_A80 + bool "Support for the Allwinner A80 PIO" + default MACH_SUN9I + select PINCTRL_SUNXI + +config PINCTRL_SUN9I_A80_R + bool "Support for the Allwinner A80 R-PIO" + default MACH_SUN9I + select PINCTRL_SUNXI + +config PINCTRL_SUN50I_A64 + bool "Support for the Allwinner A64 PIO" + default MACH_SUN50I + select PINCTRL_SUNXI + +config PINCTRL_SUN50I_A64_R + bool "Support for the Allwinner A64 R-PIO" + default MACH_SUN50I + select PINCTRL_SUNXI + +config PINCTRL_SUN50I_H5 + bool "Support for the Allwinner H5 PIO" + default MACH_SUN50I_H5 + select PINCTRL_SUNXI + +config PINCTRL_SUN50I_H6 + bool "Support for the Allwinner H6 PIO" + default MACH_SUN50I_H6 + select PINCTRL_SUNXI + +config PINCTRL_SUN50I_H6_R + bool "Support for the Allwinner H6 R-PIO" + default MACH_SUN50I_H6 + select PINCTRL_SUNXI + +config PINCTRL_SUN50I_H616 + bool "Support for the Allwinner H616 PIO" + default MACH_SUN50I_H616 + select PINCTRL_SUNXI + +config PINCTRL_SUN50I_H616_R + bool "Support for the Allwinner H616 R-PIO" + default MACH_SUN50I_H616 + select PINCTRL_SUNXI + +endif diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile new file mode 100644 index 00000000000..6a8c01f3729 --- /dev/null +++ b/drivers/pinctrl/sunxi/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += pinctrl-sunxi.o diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c new file mode 100644 index 00000000000..43bb1ec650a --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include + +#include + +extern U_BOOT_DRIVER(gpio_sunxi); + +struct sunxi_pinctrl_desc { + u8 first_bank; + u8 num_banks; +}; + +struct sunxi_pinctrl_plat { + struct sunxi_gpio __iomem *base; +}; + +static const struct pinctrl_ops sunxi_pinctrl_ops = { + .set_state = pinctrl_generic_set_state, +}; + +static int sunxi_pinctrl_bind(struct udevice *dev) +{ + struct sunxi_pinctrl_plat *plat = dev_get_plat(dev); + struct sunxi_pinctrl_desc *desc; + struct sunxi_gpio_plat *gpio_plat; + struct udevice *gpio_dev; + int i, ret; + + desc = (void *)dev_get_driver_data(dev); + if (!desc) + return -EINVAL; + dev_set_priv(dev, desc); + + plat->base = dev_read_addr_ptr(dev); + + ret = device_bind_driver_to_node(dev, "gpio_sunxi", dev->name, + dev_ofnode(dev), &gpio_dev); + if (ret) + return ret; + + for (i = 0; i < desc->num_banks; ++i) { + gpio_plat = malloc(sizeof(*gpio_plat)); + if (!gpio_plat) + return -ENOMEM; + + gpio_plat->regs = plat->base + i; + gpio_plat->bank_name[0] = 'P'; + gpio_plat->bank_name[1] = 'A' + desc->first_bank + i; + gpio_plat->bank_name[2] = '\0'; + + ret = device_bind(gpio_dev, DM_DRIVER_REF(gpio_sunxi), + gpio_plat->bank_name, gpio_plat, + ofnode_null(), NULL); + if (ret) + return ret; + } + + return 0; +} + +static int sunxi_pinctrl_probe(struct udevice *dev) +{ + struct clk *apb_clk; + + apb_clk = devm_clk_get(dev, "apb"); + if (!IS_ERR(apb_clk)) + clk_enable(apb_clk); + + return 0; +} + +static const struct sunxi_pinctrl_desc __maybe_unused suniv_f1c100s_pinctrl_desc = { + .first_bank = SUNXI_GPIO_A, + .num_banks = 6, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun4i_a10_pinctrl_desc = { + .first_bank = SUNXI_GPIO_A, + .num_banks = 9, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun5i_a13_pinctrl_desc = { + .first_bank = SUNXI_GPIO_A, + .num_banks = 7, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun6i_a31_pinctrl_desc = { + .first_bank = SUNXI_GPIO_A, + .num_banks = 8, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun6i_a31_r_pinctrl_desc = { + .first_bank = SUNXI_GPIO_L, + .num_banks = 2, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun7i_a20_pinctrl_desc = { + .first_bank = SUNXI_GPIO_A, + .num_banks = 9, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a23_pinctrl_desc = { + .first_bank = SUNXI_GPIO_A, + .num_banks = 8, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a23_r_pinctrl_desc = { + .first_bank = SUNXI_GPIO_L, + .num_banks = 1, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a33_pinctrl_desc = { + .first_bank = SUNXI_GPIO_A, + .num_banks = 8, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a83t_pinctrl_desc = { + .first_bank = SUNXI_GPIO_A, + .num_banks = 8, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a83t_r_pinctrl_desc = { + .first_bank = SUNXI_GPIO_L, + .num_banks = 1, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun8i_h3_pinctrl_desc = { + .first_bank = SUNXI_GPIO_A, + .num_banks = 7, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun8i_h3_r_pinctrl_desc = { + .first_bank = SUNXI_GPIO_L, + .num_banks = 1, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun8i_v3s_pinctrl_desc = { + .first_bank = SUNXI_GPIO_A, + .num_banks = 7, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun9i_a80_pinctrl_desc = { + .first_bank = SUNXI_GPIO_A, + .num_banks = 8, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun9i_a80_r_pinctrl_desc = { + .first_bank = SUNXI_GPIO_L, + .num_banks = 3, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun50i_a64_pinctrl_desc = { + .first_bank = SUNXI_GPIO_A, + .num_banks = 8, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun50i_a64_r_pinctrl_desc = { + .first_bank = SUNXI_GPIO_L, + .num_banks = 1, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h5_pinctrl_desc = { + .first_bank = SUNXI_GPIO_A, + .num_banks = 7, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h6_pinctrl_desc = { + .first_bank = SUNXI_GPIO_A, + .num_banks = 8, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h6_r_pinctrl_desc = { + .first_bank = SUNXI_GPIO_L, + .num_banks = 2, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h616_pinctrl_desc = { + .first_bank = SUNXI_GPIO_A, + .num_banks = 9, +}; + +static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h616_r_pinctrl_desc = { + .first_bank = SUNXI_GPIO_L, + .num_banks = 1, +}; + +static const struct udevice_id sunxi_pinctrl_ids[] = { +#ifdef CONFIG_PINCTRL_SUNIV_F1C100S + { + .compatible = "allwinner,suniv-f1c100s-pinctrl", + .data = (ulong)&suniv_f1c100s_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN4I_A10 + { + .compatible = "allwinner,sun4i-a10-pinctrl", + .data = (ulong)&sun4i_a10_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN5I_A13 + { + .compatible = "allwinner,sun5i-a10s-pinctrl", + .data = (ulong)&sun5i_a13_pinctrl_desc, + }, + { + .compatible = "allwinner,sun5i-a13-pinctrl", + .data = (ulong)&sun5i_a13_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN6I_A31 + { + .compatible = "allwinner,sun6i-a31-pinctrl", + .data = (ulong)&sun6i_a31_pinctrl_desc, + }, + { + .compatible = "allwinner,sun6i-a31s-pinctrl", + .data = (ulong)&sun6i_a31_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN6I_A31_R + { + .compatible = "allwinner,sun6i-a31-r-pinctrl", + .data = (ulong)&sun6i_a31_r_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN7I_A20 + { + .compatible = "allwinner,sun7i-a20-pinctrl", + .data = (ulong)&sun7i_a20_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN8I_A23 + { + .compatible = "allwinner,sun8i-a23-pinctrl", + .data = (ulong)&sun8i_a23_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN8I_A23_R + { + .compatible = "allwinner,sun8i-a23-r-pinctrl", + .data = (ulong)&sun8i_a23_r_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN8I_A33 + { + .compatible = "allwinner,sun8i-a33-pinctrl", + .data = (ulong)&sun8i_a33_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN8I_A83T + { + .compatible = "allwinner,sun8i-a83t-pinctrl", + .data = (ulong)&sun8i_a83t_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN8I_A83T_R + { + .compatible = "allwinner,sun8i-a83t-r-pinctrl", + .data = (ulong)&sun8i_a83t_r_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN8I_H3 + { + .compatible = "allwinner,sun8i-h3-pinctrl", + .data = (ulong)&sun8i_h3_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN8I_H3_R + { + .compatible = "allwinner,sun8i-h3-r-pinctrl", + .data = (ulong)&sun8i_h3_r_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN7I_A20 + { + .compatible = "allwinner,sun8i-r40-pinctrl", + .data = (ulong)&sun7i_a20_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN8I_V3S + { + .compatible = "allwinner,sun8i-v3-pinctrl", + .data = (ulong)&sun8i_v3s_pinctrl_desc, + }, + { + .compatible = "allwinner,sun8i-v3s-pinctrl", + .data = (ulong)&sun8i_v3s_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN9I_A80 + { + .compatible = "allwinner,sun9i-a80-pinctrl", + .data = (ulong)&sun9i_a80_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN9I_A80_R + { + .compatible = "allwinner,sun9i-a80-r-pinctrl", + .data = (ulong)&sun9i_a80_r_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN50I_A64 + { + .compatible = "allwinner,sun50i-a64-pinctrl", + .data = (ulong)&sun50i_a64_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN50I_A64_R + { + .compatible = "allwinner,sun50i-a64-r-pinctrl", + .data = (ulong)&sun50i_a64_r_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN50I_H5 + { + .compatible = "allwinner,sun50i-h5-pinctrl", + .data = (ulong)&sun50i_h5_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN50I_H6 + { + .compatible = "allwinner,sun50i-h6-pinctrl", + .data = (ulong)&sun50i_h6_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN50I_H6_R + { + .compatible = "allwinner,sun50i-h6-r-pinctrl", + .data = (ulong)&sun50i_h6_r_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN50I_H616 + { + .compatible = "allwinner,sun50i-h616-pinctrl", + .data = (ulong)&sun50i_h616_pinctrl_desc, + }, +#endif +#ifdef CONFIG_PINCTRL_SUN50I_H616_R + { + .compatible = "allwinner,sun50i-h616-r-pinctrl", + .data = (ulong)&sun50i_h616_r_pinctrl_desc, + }, +#endif + {} +}; + +U_BOOT_DRIVER(sunxi_pinctrl) = { + .name = "sunxi-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = sunxi_pinctrl_ids, + .bind = sunxi_pinctrl_bind, + .probe = sunxi_pinctrl_probe, + .plat_auto = sizeof(struct sunxi_pinctrl_plat), + .ops = &sunxi_pinctrl_ops, +}; From 29babfd92b25883ce45f294b8eeacc04113389e7 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Mon, 16 Aug 2021 23:56:47 -0500 Subject: [PATCH 02/40] sunxi: pinctrl: Implement pin muxing functions Implement the operations to get pin and function names, and to set the mux for a pin. The pin count and pin names are calculated as if each bank has the maximum number of pins. Function names are simply the index into a list of { function name, mux value } pairs. We assume all pins associated with a function use the same mux value for that function. This is generally true within a group of pins on a single port, but generally false when some peripheral can be muxed to multiple ports. For example, A64 UART3 uses mux 3 on port D, and mux 2 on port H. But all of the port D pins use the same mux value, and so do all of the port H pins. This applies even when the pins for some function are not contiguous, and when the lower-numbered mux values are unused. A good example of both of these cases is SPI0 on most SoCs. This strategy saves a lot of space (which is especially important for SPL), but where the mux value for a certain function differs across ports, it forces us to choose a single port for that function at build time. Since almost all boards use the default (i.e. reference design) pin muxes[1], this is unlikely to be a problem. [1]: See commit dda9fa734f81 ("sunxi: Simplify MMC pinmux selection") Signed-off-by: Samuel Holland [Andre: add comment summarising the commit message] Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/pinctrl/sunxi/Kconfig | 1 + drivers/pinctrl/sunxi/pinctrl-sunxi.c | 237 ++++++++++++++++++++++++++ 2 files changed, 238 insertions(+) diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig index 96c2f35f3a5..f4949f89e0d 100644 --- a/drivers/pinctrl/sunxi/Kconfig +++ b/drivers/pinctrl/sunxi/Kconfig @@ -5,6 +5,7 @@ if ARCH_SUNXI config PINCTRL_SUNXI select PINCTRL_FULL select PINCTRL_GENERIC + select PINMUX bool config PINCTRL_SUNIV_F1C100S diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 43bb1ec650a..fe6c46cdd5b 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -12,7 +12,24 @@ extern U_BOOT_DRIVER(gpio_sunxi); +/* + * This structure implements a simplified view of the possible pinmux settings: + * Each mux value is assumed to be the same for a given function, across the + * pins in each group (almost universally true, with same rare exceptions not + * relevant to U-Boot), but also across different ports (not true in many + * cases). We ignore the first problem, and work around the latter by just + * supporting one particular port for a each function. This works fine for all + * board configurations so far. If this would need to be revisited, we could + * add a "u8 port;" below and match that, with 0 encoding the "don't care" case. + */ +struct sunxi_pinctrl_function { + const char name[sizeof("gpio_out")]; + u8 mux; +}; + struct sunxi_pinctrl_desc { + const struct sunxi_pinctrl_function *functions; + u8 num_functions; u8 first_bank; u8 num_banks; }; @@ -21,7 +38,66 @@ struct sunxi_pinctrl_plat { struct sunxi_gpio __iomem *base; }; +static int sunxi_pinctrl_get_pins_count(struct udevice *dev) +{ + const struct sunxi_pinctrl_desc *desc = dev_get_priv(dev); + + return desc->num_banks * SUNXI_GPIOS_PER_BANK; +} + +static const char *sunxi_pinctrl_get_pin_name(struct udevice *dev, + uint pin_selector) +{ + const struct sunxi_pinctrl_desc *desc = dev_get_priv(dev); + static char pin_name[sizeof("PN31")]; + + snprintf(pin_name, sizeof(pin_name), "P%c%d", + pin_selector / SUNXI_GPIOS_PER_BANK + desc->first_bank + 'A', + pin_selector % SUNXI_GPIOS_PER_BANK); + + return pin_name; +} + +static int sunxi_pinctrl_get_functions_count(struct udevice *dev) +{ + const struct sunxi_pinctrl_desc *desc = dev_get_priv(dev); + + return desc->num_functions; +} + +static const char *sunxi_pinctrl_get_function_name(struct udevice *dev, + uint func_selector) +{ + const struct sunxi_pinctrl_desc *desc = dev_get_priv(dev); + + return desc->functions[func_selector].name; +} + +static int sunxi_pinctrl_pinmux_set(struct udevice *dev, uint pin_selector, + uint func_selector) +{ + const struct sunxi_pinctrl_desc *desc = dev_get_priv(dev); + struct sunxi_pinctrl_plat *plat = dev_get_plat(dev); + int bank = pin_selector / SUNXI_GPIOS_PER_BANK; + int pin = pin_selector % SUNXI_GPIOS_PER_BANK; + + debug("set mux: %-4s => %s (%d)\n", + sunxi_pinctrl_get_pin_name(dev, pin_selector), + sunxi_pinctrl_get_function_name(dev, func_selector), + desc->functions[func_selector].mux); + + sunxi_gpio_set_cfgbank(plat->base + bank, pin, + desc->functions[func_selector].mux); + + return 0; +} + static const struct pinctrl_ops sunxi_pinctrl_ops = { + .get_pins_count = sunxi_pinctrl_get_pins_count, + .get_pin_name = sunxi_pinctrl_get_pin_name, + .get_functions_count = sunxi_pinctrl_get_functions_count, + .get_function_name = sunxi_pinctrl_get_function_name, + .pinmux_set = sunxi_pinctrl_pinmux_set, .set_state = pinctrl_generic_set_state, }; @@ -76,117 +152,278 @@ static int sunxi_pinctrl_probe(struct udevice *dev) return 0; } +static const struct sunxi_pinctrl_function suniv_f1c100s_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused suniv_f1c100s_pinctrl_desc = { + .functions = suniv_f1c100s_pinctrl_functions, + .num_functions = ARRAY_SIZE(suniv_f1c100s_pinctrl_functions), .first_bank = SUNXI_GPIO_A, .num_banks = 6, }; +static const struct sunxi_pinctrl_function sun4i_a10_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun4i_a10_pinctrl_desc = { + .functions = sun4i_a10_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun4i_a10_pinctrl_functions), .first_bank = SUNXI_GPIO_A, .num_banks = 9, }; +static const struct sunxi_pinctrl_function sun5i_a13_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun5i_a13_pinctrl_desc = { + .functions = sun5i_a13_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun5i_a13_pinctrl_functions), .first_bank = SUNXI_GPIO_A, .num_banks = 7, }; +static const struct sunxi_pinctrl_function sun6i_a31_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun6i_a31_pinctrl_desc = { + .functions = sun6i_a31_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun6i_a31_pinctrl_functions), .first_bank = SUNXI_GPIO_A, .num_banks = 8, }; +static const struct sunxi_pinctrl_function sun6i_a31_r_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun6i_a31_r_pinctrl_desc = { + .functions = sun6i_a31_r_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun6i_a31_r_pinctrl_functions), .first_bank = SUNXI_GPIO_L, .num_banks = 2, }; +static const struct sunxi_pinctrl_function sun7i_a20_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun7i_a20_pinctrl_desc = { + .functions = sun7i_a20_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun7i_a20_pinctrl_functions), .first_bank = SUNXI_GPIO_A, .num_banks = 9, }; +static const struct sunxi_pinctrl_function sun8i_a23_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a23_pinctrl_desc = { + .functions = sun8i_a23_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun8i_a23_pinctrl_functions), .first_bank = SUNXI_GPIO_A, .num_banks = 8, }; +static const struct sunxi_pinctrl_function sun8i_a23_r_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a23_r_pinctrl_desc = { + .functions = sun8i_a23_r_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun8i_a23_r_pinctrl_functions), .first_bank = SUNXI_GPIO_L, .num_banks = 1, }; +static const struct sunxi_pinctrl_function sun8i_a33_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a33_pinctrl_desc = { + .functions = sun8i_a33_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun8i_a33_pinctrl_functions), .first_bank = SUNXI_GPIO_A, .num_banks = 8, }; +static const struct sunxi_pinctrl_function sun8i_a83t_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a83t_pinctrl_desc = { + .functions = sun8i_a83t_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun8i_a83t_pinctrl_functions), .first_bank = SUNXI_GPIO_A, .num_banks = 8, }; +static const struct sunxi_pinctrl_function sun8i_a83t_r_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a83t_r_pinctrl_desc = { + .functions = sun8i_a83t_r_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun8i_a83t_r_pinctrl_functions), .first_bank = SUNXI_GPIO_L, .num_banks = 1, }; +static const struct sunxi_pinctrl_function sun8i_h3_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun8i_h3_pinctrl_desc = { + .functions = sun8i_h3_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun8i_h3_pinctrl_functions), .first_bank = SUNXI_GPIO_A, .num_banks = 7, }; +static const struct sunxi_pinctrl_function sun8i_h3_r_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun8i_h3_r_pinctrl_desc = { + .functions = sun8i_h3_r_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun8i_h3_r_pinctrl_functions), .first_bank = SUNXI_GPIO_L, .num_banks = 1, }; +static const struct sunxi_pinctrl_function sun8i_v3s_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun8i_v3s_pinctrl_desc = { + .functions = sun8i_v3s_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun8i_v3s_pinctrl_functions), .first_bank = SUNXI_GPIO_A, .num_banks = 7, }; +static const struct sunxi_pinctrl_function sun9i_a80_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun9i_a80_pinctrl_desc = { + .functions = sun9i_a80_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun9i_a80_pinctrl_functions), .first_bank = SUNXI_GPIO_A, .num_banks = 8, }; +static const struct sunxi_pinctrl_function sun9i_a80_r_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun9i_a80_r_pinctrl_desc = { + .functions = sun9i_a80_r_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun9i_a80_r_pinctrl_functions), .first_bank = SUNXI_GPIO_L, .num_banks = 3, }; +static const struct sunxi_pinctrl_function sun50i_a64_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun50i_a64_pinctrl_desc = { + .functions = sun50i_a64_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun50i_a64_pinctrl_functions), .first_bank = SUNXI_GPIO_A, .num_banks = 8, }; +static const struct sunxi_pinctrl_function sun50i_a64_r_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun50i_a64_r_pinctrl_desc = { + .functions = sun50i_a64_r_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun50i_a64_r_pinctrl_functions), .first_bank = SUNXI_GPIO_L, .num_banks = 1, }; +static const struct sunxi_pinctrl_function sun50i_h5_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h5_pinctrl_desc = { + .functions = sun50i_h5_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun50i_h5_pinctrl_functions), .first_bank = SUNXI_GPIO_A, .num_banks = 7, }; +static const struct sunxi_pinctrl_function sun50i_h6_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h6_pinctrl_desc = { + .functions = sun50i_h6_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun50i_h6_pinctrl_functions), .first_bank = SUNXI_GPIO_A, .num_banks = 8, }; +static const struct sunxi_pinctrl_function sun50i_h6_r_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h6_r_pinctrl_desc = { + .functions = sun50i_h6_r_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun50i_h6_r_pinctrl_functions), .first_bank = SUNXI_GPIO_L, .num_banks = 2, }; +static const struct sunxi_pinctrl_function sun50i_h616_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h616_pinctrl_desc = { + .functions = sun50i_h616_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun50i_h616_pinctrl_functions), .first_bank = SUNXI_GPIO_A, .num_banks = 9, }; +static const struct sunxi_pinctrl_function sun50i_h616_r_pinctrl_functions[] = { + { "gpio_in", 0 }, + { "gpio_out", 1 }, +}; + static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h616_r_pinctrl_desc = { + .functions = sun50i_h616_r_pinctrl_functions, + .num_functions = ARRAY_SIZE(sun50i_h616_r_pinctrl_functions), .first_bank = SUNXI_GPIO_L, .num_banks = 1, }; From d4b388244abfb7580a00967147fc5e45baf2f41f Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 17 Aug 2021 00:52:00 -0500 Subject: [PATCH 03/40] sunxi: pinctrl: Implement get_pin_muxing function The pinmux command uses this function to display pinmux status. Since the driver cannot map pin numbers to a list of supported functions, only functions which are common across all pins can be reported by name. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index fe6c46cdd5b..789cfbacbbc 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -92,6 +92,32 @@ static int sunxi_pinctrl_pinmux_set(struct udevice *dev, uint pin_selector, return 0; } +static int sunxi_pinctrl_get_pin_muxing(struct udevice *dev, uint pin_selector, + char *buf, int size) +{ + struct sunxi_pinctrl_plat *plat = dev_get_plat(dev); + int bank = pin_selector / SUNXI_GPIOS_PER_BANK; + int pin = pin_selector % SUNXI_GPIOS_PER_BANK; + int mux = sunxi_gpio_get_cfgbank(plat->base + bank, pin); + + switch (mux) { + case SUNXI_GPIO_INPUT: + strlcpy(buf, "gpio input", size); + break; + case SUNXI_GPIO_OUTPUT: + strlcpy(buf, "gpio output", size); + break; + case SUNXI_GPIO_DISABLE: + strlcpy(buf, "disabled", size); + break; + default: + snprintf(buf, size, "function %d", mux); + break; + } + + return 0; +} + static const struct pinctrl_ops sunxi_pinctrl_ops = { .get_pins_count = sunxi_pinctrl_get_pins_count, .get_pin_name = sunxi_pinctrl_get_pin_name, @@ -99,6 +125,7 @@ static const struct pinctrl_ops sunxi_pinctrl_ops = { .get_function_name = sunxi_pinctrl_get_function_name, .pinmux_set = sunxi_pinctrl_pinmux_set, .set_state = pinctrl_generic_set_state, + .get_pin_muxing = sunxi_pinctrl_get_pin_muxing, }; static int sunxi_pinctrl_bind(struct udevice *dev) From 50c195ee851b35264df4bb8089a459470da491b5 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 28 Aug 2021 21:10:47 -0500 Subject: [PATCH 04/40] sunxi: pinctrl: Implement pin configuration The sunxi pinctrl hardware has bias and drive control. Add driver support for configuring those options. Reviewed-by: Simon Glass Signed-off-by: Samuel Holland Signed-off-by: Andre Przywara --- drivers/pinctrl/sunxi/Kconfig | 1 + drivers/pinctrl/sunxi/pinctrl-sunxi.c | 53 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig index f4949f89e0d..77da90836b6 100644 --- a/drivers/pinctrl/sunxi/Kconfig +++ b/drivers/pinctrl/sunxi/Kconfig @@ -5,6 +5,7 @@ if ARCH_SUNXI config PINCTRL_SUNXI select PINCTRL_FULL select PINCTRL_GENERIC + select PINCONF select PINMUX bool diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 789cfbacbbc..ffb0375be32 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -92,6 +92,56 @@ static int sunxi_pinctrl_pinmux_set(struct udevice *dev, uint pin_selector, return 0; } +static const struct pinconf_param sunxi_pinctrl_pinconf_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 2 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 10 }, +}; + +static int sunxi_pinctrl_pinconf_set_pull(struct sunxi_pinctrl_plat *plat, + uint bank, uint pin, uint bias) +{ + struct sunxi_gpio *regs = &plat->base[bank]; + + sunxi_gpio_set_pull_bank(regs, pin, bias); + + return 0; +} + +static int sunxi_pinctrl_pinconf_set_drive(struct sunxi_pinctrl_plat *plat, + uint bank, uint pin, uint drive) +{ + struct sunxi_gpio *regs = &plat->base[bank]; + + if (drive < 10 || drive > 40) + return -EINVAL; + + /* Convert mA to the register value, rounding down. */ + sunxi_gpio_set_drv_bank(regs, pin, drive / 10 - 1); + + return 0; +} + +static int sunxi_pinctrl_pinconf_set(struct udevice *dev, uint pin_selector, + uint param, uint val) +{ + struct sunxi_pinctrl_plat *plat = dev_get_plat(dev); + int bank = pin_selector / SUNXI_GPIOS_PER_BANK; + int pin = pin_selector % SUNXI_GPIOS_PER_BANK; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + return sunxi_pinctrl_pinconf_set_pull(plat, bank, pin, val); + case PIN_CONFIG_DRIVE_STRENGTH: + return sunxi_pinctrl_pinconf_set_drive(plat, bank, pin, val); + } + + return -EINVAL; +} + static int sunxi_pinctrl_get_pin_muxing(struct udevice *dev, uint pin_selector, char *buf, int size) { @@ -124,6 +174,9 @@ static const struct pinctrl_ops sunxi_pinctrl_ops = { .get_functions_count = sunxi_pinctrl_get_functions_count, .get_function_name = sunxi_pinctrl_get_function_name, .pinmux_set = sunxi_pinctrl_pinmux_set, + .pinconf_num_params = ARRAY_SIZE(sunxi_pinctrl_pinconf_params), + .pinconf_params = sunxi_pinctrl_pinconf_params, + .pinconf_set = sunxi_pinctrl_pinconf_set, .set_state = pinctrl_generic_set_state, .get_pin_muxing = sunxi_pinctrl_get_pin_muxing, }; From 470a7bdb61b7eaff62bac70819e7b8190eb48e6a Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 28 Aug 2021 13:00:45 -0500 Subject: [PATCH 05/40] pinctrl: sunxi: Add UART pinmuxes This includes UART0 and R_UART (s_uart) on all supported platforms, plus the additional UART configurations from arch/arm/mach-sunxi/board.c. Pin lists and mux values were taken from the Linux drivers. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 98 +++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index ffb0375be32..4c638f1ec81 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -235,6 +235,11 @@ static int sunxi_pinctrl_probe(struct udevice *dev) static const struct sunxi_pinctrl_function suniv_f1c100s_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 3 }, /* PF2-PF4 */ +#else + { "uart0", 5 }, /* PE0-PE1 */ +#endif }; static const struct sunxi_pinctrl_desc __maybe_unused suniv_f1c100s_pinctrl_desc = { @@ -247,6 +252,11 @@ static const struct sunxi_pinctrl_desc __maybe_unused suniv_f1c100s_pinctrl_desc static const struct sunxi_pinctrl_function sun4i_a10_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 4 }, /* PF2-PF4 */ +#else + { "uart0", 2 }, /* PB22-PB23 */ +#endif }; static const struct sunxi_pinctrl_desc __maybe_unused sun4i_a10_pinctrl_desc = { @@ -259,6 +269,12 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun4i_a10_pinctrl_desc = { static const struct sunxi_pinctrl_function sun5i_a13_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 4 }, /* PF2-PF4 */ +#else + { "uart0", 2 }, /* PB19-PB20 */ +#endif + { "uart1", 4 }, /* PG3-PG4 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun5i_a13_pinctrl_desc = { @@ -271,6 +287,11 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun5i_a13_pinctrl_desc = { static const struct sunxi_pinctrl_function sun6i_a31_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 3 }, /* PF2-PF4 */ +#else + { "uart0", 2 }, /* PH20-PH21 */ +#endif }; static const struct sunxi_pinctrl_desc __maybe_unused sun6i_a31_pinctrl_desc = { @@ -283,6 +304,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun6i_a31_pinctrl_desc = { static const struct sunxi_pinctrl_function sun6i_a31_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_uart", 2 }, /* PL2-PL3 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun6i_a31_r_pinctrl_desc = { @@ -295,6 +317,11 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun6i_a31_r_pinctrl_desc = static const struct sunxi_pinctrl_function sun7i_a20_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 4 }, /* PF2-PF4 */ +#else + { "uart0", 2 }, /* PB22-PB23 */ +#endif }; static const struct sunxi_pinctrl_desc __maybe_unused sun7i_a20_pinctrl_desc = { @@ -307,6 +334,11 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun7i_a20_pinctrl_desc = { static const struct sunxi_pinctrl_function sun8i_a23_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 3 }, /* PF2-PF4 */ +#endif + { "uart1", 2 }, /* PG6-PG7 */ + { "uart2", 2 }, /* PB0-PB1 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a23_pinctrl_desc = { @@ -319,6 +351,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a23_pinctrl_desc = { static const struct sunxi_pinctrl_function sun8i_a23_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_uart", 2 }, /* PL2-PL3 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a23_r_pinctrl_desc = { @@ -331,6 +364,13 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a23_r_pinctrl_desc = static const struct sunxi_pinctrl_function sun8i_a33_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 3 }, /* PF2-PF4 */ +#else + { "uart0", 3 }, /* PB0-PB1 */ +#endif + { "uart1", 2 }, /* PG6-PG7 */ + { "uart2", 2 }, /* PB0-PB1 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a33_pinctrl_desc = { @@ -343,6 +383,13 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a33_pinctrl_desc = { static const struct sunxi_pinctrl_function sun8i_a83t_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 3 }, /* PF2-PF4 */ +#else + { "uart0", 2 }, /* PB9-PB10 */ +#endif + { "uart1", 2 }, /* PG6-PG7 */ + { "uart2", 2 }, /* PB0-PB1 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a83t_pinctrl_desc = { @@ -355,6 +402,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a83t_pinctrl_desc = static const struct sunxi_pinctrl_function sun8i_a83t_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_uart", 2 }, /* PL2-PL3 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a83t_r_pinctrl_desc = { @@ -367,6 +415,13 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a83t_r_pinctrl_desc static const struct sunxi_pinctrl_function sun8i_h3_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 3 }, /* PF2-PF4 */ +#else + { "uart0", 2 }, /* PA4-PA5 */ +#endif + { "uart1", 2 }, /* PG6-PG7 */ + { "uart2", 2 }, /* PA0-PA1 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun8i_h3_pinctrl_desc = { @@ -379,6 +434,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_h3_pinctrl_desc = { static const struct sunxi_pinctrl_function sun8i_h3_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_uart", 2 }, /* PL2-PL3 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun8i_h3_r_pinctrl_desc = { @@ -391,6 +447,13 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_h3_r_pinctrl_desc = static const struct sunxi_pinctrl_function sun8i_v3s_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 3 }, /* PF2-PF4 */ +#else + { "uart0", 3 }, /* PB8-PB9 */ +#endif + { "uart1", 2 }, /* PG6-PG7 */ + { "uart2", 2 }, /* PB0-PB1 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun8i_v3s_pinctrl_desc = { @@ -403,6 +466,11 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_v3s_pinctrl_desc = { static const struct sunxi_pinctrl_function sun9i_a80_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 4 }, /* PF2-PF4 */ +#else + { "uart0", 2 }, /* PH12-PH13 */ +#endif }; static const struct sunxi_pinctrl_desc __maybe_unused sun9i_a80_pinctrl_desc = { @@ -415,6 +483,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun9i_a80_pinctrl_desc = { static const struct sunxi_pinctrl_function sun9i_a80_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_uart", 3 }, /* PL0-PL1 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun9i_a80_r_pinctrl_desc = { @@ -427,6 +496,13 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun9i_a80_r_pinctrl_desc = static const struct sunxi_pinctrl_function sun50i_a64_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 3 }, /* PF2-PF4 */ +#else + { "uart0", 4 }, /* PB8-PB9 */ +#endif + { "uart1", 2 }, /* PG6-PG7 */ + { "uart2", 2 }, /* PB0-PB1 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun50i_a64_pinctrl_desc = { @@ -439,6 +515,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_a64_pinctrl_desc = static const struct sunxi_pinctrl_function sun50i_a64_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_uart", 2 }, /* PL2-PL3 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun50i_a64_r_pinctrl_desc = { @@ -451,6 +528,13 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_a64_r_pinctrl_desc static const struct sunxi_pinctrl_function sun50i_h5_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 3 }, /* PF2-PF4 */ +#else + { "uart0", 2 }, /* PA4-PA5 */ +#endif + { "uart1", 2 }, /* PG6-PG7 */ + { "uart2", 2 }, /* PA0-PA1 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h5_pinctrl_desc = { @@ -463,6 +547,12 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h5_pinctrl_desc = { static const struct sunxi_pinctrl_function sun50i_h6_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 3 }, /* PF2-PF4 */ +#else + { "uart0", 2 }, /* PH0-PH1 */ +#endif + { "uart1", 2 }, /* PG6-PG7 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h6_pinctrl_desc = { @@ -475,6 +565,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h6_pinctrl_desc = { static const struct sunxi_pinctrl_function sun50i_h6_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_uart", 2 }, /* PL2-PL3 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h6_r_pinctrl_desc = { @@ -487,6 +578,12 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h6_r_pinctrl_desc = static const struct sunxi_pinctrl_function sun50i_h616_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, +#if IS_ENABLED(CONFIG_UART0_PORT_F) + { "uart0", 3 }, /* PF2-PF4 */ +#else + { "uart0", 2 }, /* PH0-PH1 */ +#endif + { "uart1", 2 }, /* PG6-PG7 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h616_pinctrl_desc = { @@ -499,6 +596,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h616_pinctrl_desc = static const struct sunxi_pinctrl_function sun50i_h616_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_uart", 2 }, /* PL2-PL3 */ }; static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h616_r_pinctrl_desc = { From fcdbbd68d389e9696e707706917b72c21f9f946b Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 28 Aug 2021 13:21:36 -0500 Subject: [PATCH 06/40] pinctrl: sunxi: Add sun4i EMAC pinmuxes Pin lists and mux values were taken from the Linux drivers. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 4c638f1ec81..ce7119931da 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -250,6 +250,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused suniv_f1c100s_pinctrl_desc }; static const struct sunxi_pinctrl_function sun4i_a10_pinctrl_functions[] = { + { "emac", 2 }, /* PA0-PA17 */ { "gpio_in", 0 }, { "gpio_out", 1 }, #if IS_ENABLED(CONFIG_UART0_PORT_F) @@ -267,6 +268,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun4i_a10_pinctrl_desc = { }; static const struct sunxi_pinctrl_function sun5i_a13_pinctrl_functions[] = { + { "emac", 2 }, /* PA0-PA17 */ { "gpio_in", 0 }, { "gpio_out", 1 }, #if IS_ENABLED(CONFIG_UART0_PORT_F) @@ -315,6 +317,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun6i_a31_r_pinctrl_desc = }; static const struct sunxi_pinctrl_function sun7i_a20_pinctrl_functions[] = { + { "emac", 2 }, /* PA0-PA17 */ { "gpio_in", 0 }, { "gpio_out", 1 }, #if IS_ENABLED(CONFIG_UART0_PORT_F) From 12bd00aafc5a0848d21dbc096b6481d62bba976c Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 28 Aug 2021 13:22:41 -0500 Subject: [PATCH 07/40] net: sunxi_emac: Remove non-DM pin setup This is now handled automatically by the pinctrl driver. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- arch/arm/include/asm/arch-sunxi/gpio.h | 1 - drivers/net/sunxi_emac.c | 7 +------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 773711b6a3f..e93c9e84c98 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -135,7 +135,6 @@ enum sunxi_gpio_number { #define SUNXI_GPIO_OUTPUT 1 #define SUNXI_GPIO_DISABLE 7 -#define SUNXI_GPA_EMAC 2 #define SUN6I_GPA_GMAC 2 #define SUN7I_GPA_GMAC 5 #define SUN8I_H3_GPA_UART0 2 diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c index 17ad88e732e..d15b0add7c9 100644 --- a/drivers/net/sunxi_emac.c +++ b/drivers/net/sunxi_emac.c @@ -17,7 +17,6 @@ #include #include #include -#include /* EMAC register */ struct emac_regs { @@ -511,15 +510,11 @@ static int sunxi_emac_board_setup(struct udevice *dev, struct sunxi_sramc_regs *sram = (struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE; struct emac_regs *regs = priv->regs; - int pin, ret; + int ret; /* Map SRAM to EMAC */ setbits_le32(&sram->ctrl1, 0x5 << 2); - /* Configure pin mux settings for MII Ethernet */ - for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++) - sunxi_gpio_set_cfgpin(pin, SUNXI_GPA_EMAC); - /* Set up clock gating */ ret = clk_enable(&priv->clk); if (ret) { From 7a93644c69f5d856951ae366d4123c44b068716c Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 28 Aug 2021 13:13:52 -0500 Subject: [PATCH 08/40] pinctrl: sunxi: Add sunxi GMAC pinmuxes Pin lists and mux values were taken from the Linux drivers. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index ce7119931da..01627494f94 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -287,6 +287,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun5i_a13_pinctrl_desc = { }; static const struct sunxi_pinctrl_function sun6i_a31_pinctrl_functions[] = { + { "gmac", 2 }, /* PA0-PA27 */ { "gpio_in", 0 }, { "gpio_out", 1 }, #if IS_ENABLED(CONFIG_UART0_PORT_F) @@ -318,6 +319,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun6i_a31_r_pinctrl_desc = static const struct sunxi_pinctrl_function sun7i_a20_pinctrl_functions[] = { { "emac", 2 }, /* PA0-PA17 */ + { "gmac", 5 }, /* PA0-PA17 */ { "gpio_in", 0 }, { "gpio_out", 1 }, #if IS_ENABLED(CONFIG_UART0_PORT_F) @@ -467,6 +469,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_v3s_pinctrl_desc = { }; static const struct sunxi_pinctrl_function sun9i_a80_pinctrl_functions[] = { + { "gmac", 2 }, /* PA0-PA17 */ { "gpio_in", 0 }, { "gpio_out", 1 }, #if IS_ENABLED(CONFIG_UART0_PORT_F) From 3e42d919af576cad0b17ec321ec95a0e72f97e5f Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 28 Aug 2021 13:16:44 -0500 Subject: [PATCH 09/40] sunxi: Remove non-DM GMAC pin setup This is now handled automatically by the pinctrl driver. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- arch/arm/include/asm/arch-sunxi/gpio.h | 2 - board/sunxi/gmac.c | 55 -------------------------- 2 files changed, 57 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index e93c9e84c98..2aa6bbb1785 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -135,8 +135,6 @@ enum sunxi_gpio_number { #define SUNXI_GPIO_OUTPUT 1 #define SUNXI_GPIO_DISABLE 7 -#define SUN6I_GPA_GMAC 2 -#define SUN7I_GPA_GMAC 5 #define SUN8I_H3_GPA_UART0 2 #define SUN4I_GPB_PWM 2 diff --git a/board/sunxi/gmac.c b/board/sunxi/gmac.c index 1fa54ed72de..2a885305ebe 100644 --- a/board/sunxi/gmac.c +++ b/board/sunxi/gmac.c @@ -1,13 +1,11 @@ #include #include #include -#include #include #include void eth_init_board(void) { - int pin; struct sunxi_ccm_reg *const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; @@ -21,57 +19,4 @@ void eth_init_board(void) setbits_le32(&ccm->gmac_clk_cfg, CCM_GMAC_CTRL_TX_CLK_SRC_MII | CCM_GMAC_CTRL_GPIT_MII); #endif - -#ifndef CONFIG_MACH_SUN6I - /* Configure pin mux settings for GMAC */ -#ifdef CONFIG_SUN7I_GMAC_FORCE_TXERR - for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++) { -#else - for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(16); pin++) { -#endif -#ifdef CONFIG_RGMII - /* skip unused pins in RGMII mode */ - if (pin == SUNXI_GPA(9) || pin == SUNXI_GPA(14)) - continue; -#endif - sunxi_gpio_set_cfgpin(pin, SUN7I_GPA_GMAC); - sunxi_gpio_set_drv(pin, 3); - } -#elif defined CONFIG_RGMII - /* Configure sun6i RGMII mode pin mux settings */ - for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(3); pin++) { - sunxi_gpio_set_cfgpin(pin, SUN6I_GPA_GMAC); - sunxi_gpio_set_drv(pin, 3); - } - for (pin = SUNXI_GPA(9); pin <= SUNXI_GPA(14); pin++) { - sunxi_gpio_set_cfgpin(pin, SUN6I_GPA_GMAC); - sunxi_gpio_set_drv(pin, 3); - } - for (pin = SUNXI_GPA(19); pin <= SUNXI_GPA(20); pin++) { - sunxi_gpio_set_cfgpin(pin, SUN6I_GPA_GMAC); - sunxi_gpio_set_drv(pin, 3); - } - for (pin = SUNXI_GPA(25); pin <= SUNXI_GPA(27); pin++) { - sunxi_gpio_set_cfgpin(pin, SUN6I_GPA_GMAC); - sunxi_gpio_set_drv(pin, 3); - } -#elif defined CONFIG_GMII - /* Configure sun6i GMII mode pin mux settings */ - for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(27); pin++) { - sunxi_gpio_set_cfgpin(pin, SUN6I_GPA_GMAC); - sunxi_gpio_set_drv(pin, 2); - } -#else - /* Configure sun6i MII mode pin mux settings */ - for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(3); pin++) - sunxi_gpio_set_cfgpin(pin, SUN6I_GPA_GMAC); - for (pin = SUNXI_GPA(8); pin <= SUNXI_GPA(9); pin++) - sunxi_gpio_set_cfgpin(pin, SUN6I_GPA_GMAC); - for (pin = SUNXI_GPA(11); pin <= SUNXI_GPA(14); pin++) - sunxi_gpio_set_cfgpin(pin, SUN6I_GPA_GMAC); - for (pin = SUNXI_GPA(19); pin <= SUNXI_GPA(24); pin++) - sunxi_gpio_set_cfgpin(pin, SUN6I_GPA_GMAC); - for (pin = SUNXI_GPA(26); pin <= SUNXI_GPA(27); pin++) - sunxi_gpio_set_cfgpin(pin, SUN6I_GPA_GMAC); -#endif } From 37b3de432f2ddbcfcebb9bb2ca1d6e783da191f5 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 28 Aug 2021 13:34:29 -0500 Subject: [PATCH 10/40] pinctrl: sunxi: Add sun8i EMAC pinmuxes Pin lists and mux values were taken from the Linux drivers. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 01627494f94..01d658ea6e9 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -386,6 +386,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a33_pinctrl_desc = { }; static const struct sunxi_pinctrl_function sun8i_a83t_pinctrl_functions[] = { + { "gmac", 4 }, /* PD2-PD23 */ { "gpio_in", 0 }, { "gpio_out", 1 }, #if IS_ENABLED(CONFIG_UART0_PORT_F) @@ -418,6 +419,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a83t_r_pinctrl_desc }; static const struct sunxi_pinctrl_function sun8i_h3_pinctrl_functions[] = { + { "emac", 2 }, /* PD0-PD17 */ { "gpio_in", 0 }, { "gpio_out", 1 }, #if IS_ENABLED(CONFIG_UART0_PORT_F) @@ -450,6 +452,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_h3_r_pinctrl_desc = }; static const struct sunxi_pinctrl_function sun8i_v3s_pinctrl_functions[] = { + { "emac", 4 }, /* PD0-PD17 */ { "gpio_in", 0 }, { "gpio_out", 1 }, #if IS_ENABLED(CONFIG_UART0_PORT_F) @@ -500,6 +503,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun9i_a80_r_pinctrl_desc = }; static const struct sunxi_pinctrl_function sun50i_a64_pinctrl_functions[] = { + { "emac", 4 }, /* PD8-PD23 */ { "gpio_in", 0 }, { "gpio_out", 1 }, #if IS_ENABLED(CONFIG_UART0_PORT_F) @@ -532,6 +536,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_a64_r_pinctrl_desc }; static const struct sunxi_pinctrl_function sun50i_h5_pinctrl_functions[] = { + { "emac", 2 }, /* PD0-PD17 */ { "gpio_in", 0 }, { "gpio_out", 1 }, #if IS_ENABLED(CONFIG_UART0_PORT_F) @@ -551,6 +556,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h5_pinctrl_desc = { }; static const struct sunxi_pinctrl_function sun50i_h6_pinctrl_functions[] = { + { "emac", 5 }, /* PD0-PD20 */ { "gpio_in", 0 }, { "gpio_out", 1 }, #if IS_ENABLED(CONFIG_UART0_PORT_F) @@ -582,6 +588,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h6_r_pinctrl_desc = }; static const struct sunxi_pinctrl_function sun50i_h616_pinctrl_functions[] = { + { "emac0", 2 }, /* PI0-PI16 */ { "gpio_in", 0 }, { "gpio_out", 1 }, #if IS_ENABLED(CONFIG_UART0_PORT_F) From ae022e8366a3173c57b3701e4269fa55094e0be7 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 28 Aug 2021 11:49:40 -0500 Subject: [PATCH 11/40] net: sun8i_emac: Remove non-DM pin setup This is now handled automatically by the pinctrl driver. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/net/sun8i_emac.c | 90 ---------------------------------------- 1 file changed, 90 deletions(-) diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index 2e24d122141..b23faa228e0 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #define MDIO_CMD_MII_BUSY BIT(0) @@ -81,13 +80,6 @@ #define AHB_GATE_OFFSET_EPHY 0 -/* IO mux settings */ -#define SUN8I_IOMUX_H3 2 -#define SUN8I_IOMUX_R40 5 -#define SUN8I_IOMUX_H6 5 -#define SUN8I_IOMUX_H616 2 -#define SUN8I_IOMUX 4 - /* H3/A64 EMAC Register's offset */ #define EMAC_CTL0 0x00 #define EMAC_CTL0_FULL_DUPLEX BIT(0) @@ -519,85 +511,6 @@ static int sun8i_emac_eth_start(struct udevice *dev) return 0; } -static int parse_phy_pins(struct udevice *dev) -{ - int offset; - const char *pin_name; - int drive, pull = SUN4I_PINCTRL_NO_PULL, i; - u32 iomux; - - offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev), - "pinctrl-0"); - if (offset < 0) { - printf("WARNING: emac: cannot find pinctrl-0 node\n"); - return offset; - } - - drive = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0, - "drive-strength", ~0); - if (drive != ~0) { - if (drive <= 10) - drive = SUN4I_PINCTRL_10_MA; - else if (drive <= 20) - drive = SUN4I_PINCTRL_20_MA; - else if (drive <= 30) - drive = SUN4I_PINCTRL_30_MA; - else - drive = SUN4I_PINCTRL_40_MA; - } - - if (fdt_get_property(gd->fdt_blob, offset, "bias-pull-up", NULL)) - pull = SUN4I_PINCTRL_PULL_UP; - else if (fdt_get_property(gd->fdt_blob, offset, "bias-pull-down", NULL)) - pull = SUN4I_PINCTRL_PULL_DOWN; - - /* - * The GPIO pinmux value is an integration choice, so depends on the - * SoC, not the EMAC variant. - */ - if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5)) - iomux = SUN8I_IOMUX_H3; - else if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) - iomux = SUN8I_IOMUX_R40; - else if (IS_ENABLED(CONFIG_MACH_SUN50I_H6)) - iomux = SUN8I_IOMUX_H6; - else if (IS_ENABLED(CONFIG_MACH_SUN50I_H616)) - iomux = SUN8I_IOMUX_H616; - else if (IS_ENABLED(CONFIG_MACH_SUN8I_A83T)) - iomux = SUN8I_IOMUX; - else if (IS_ENABLED(CONFIG_MACH_SUN50I)) - iomux = SUN8I_IOMUX; - else - BUILD_BUG_ON_MSG(1, "missing pinmux value for Ethernet pins"); - - for (i = 0; ; i++) { - int pin; - - pin_name = fdt_stringlist_get(gd->fdt_blob, offset, - "pins", i, NULL); - if (!pin_name) - break; - - pin = sunxi_name_to_gpio(pin_name); - if (pin < 0) - continue; - - sunxi_gpio_set_cfgpin(pin, iomux); - - if (drive != ~0) - sunxi_gpio_set_drv(pin, drive); - if (pull != ~0) - sunxi_gpio_set_pull(pin, pull); - } - - if (!i) { - printf("WARNING: emac: cannot find pins property\n"); - return -2; - } - - return 0; -} - static int sun8i_emac_eth_recv(struct udevice *dev, int flags, uchar **packetp) { struct emac_eth_dev *priv = dev_get_priv(dev); @@ -965,9 +878,6 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev) priv->interface = pdata->phy_interface; - if (!priv->use_internal_phy) - parse_phy_pins(dev); - sun8i_pdata->tx_delay_ps = fdtdec_get_int(gd->fdt_blob, node, "allwinner,tx-delay-ps", 0); if (sun8i_pdata->tx_delay_ps < 0 || sun8i_pdata->tx_delay_ps > 700) From 4c8f11d4afc799f78d8f6a82efcff618bed03f6c Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 28 Aug 2021 15:17:32 -0500 Subject: [PATCH 12/40] pinctrl: sunxi: Add I2C pinmuxes Where multiple options were available, the one matching board.c and the device trees was chosen. Pin lists and mux values were taken from the Linux drivers. Signed-off-by: Samuel Holland [Andre: fixup H5 I2C1 pinmux] Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 37 +++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 01d658ea6e9..d19cf27746a 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -235,6 +235,8 @@ static int sunxi_pinctrl_probe(struct udevice *dev) static const struct sunxi_pinctrl_function suniv_f1c100s_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "i2c0", 3 }, /* PE11-PE12 */ + { "i2c1", 3 }, /* PD5-PD6 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -253,6 +255,8 @@ static const struct sunxi_pinctrl_function sun4i_a10_pinctrl_functions[] = { { "emac", 2 }, /* PA0-PA17 */ { "gpio_in", 0 }, { "gpio_out", 1 }, + { "i2c0", 2 }, /* PB0-PB1 */ + { "i2c1", 2 }, /* PB18-PB19 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 4 }, /* PF2-PF4 */ #else @@ -271,6 +275,8 @@ static const struct sunxi_pinctrl_function sun5i_a13_pinctrl_functions[] = { { "emac", 2 }, /* PA0-PA17 */ { "gpio_in", 0 }, { "gpio_out", 1 }, + { "i2c0", 2 }, /* PB0-PB1 */ + { "i2c1", 2 }, /* PB15-PB16 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 4 }, /* PF2-PF4 */ #else @@ -290,6 +296,8 @@ static const struct sunxi_pinctrl_function sun6i_a31_pinctrl_functions[] = { { "gmac", 2 }, /* PA0-PA27 */ { "gpio_in", 0 }, { "gpio_out", 1 }, + { "i2c0", 2 }, /* PH14-PH15 */ + { "i2c1", 2 }, /* PH16-PH17 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -307,6 +315,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun6i_a31_pinctrl_desc = { static const struct sunxi_pinctrl_function sun6i_a31_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_i2c", 2 }, /* PL0-PL1 */ { "s_uart", 2 }, /* PL2-PL3 */ }; @@ -322,6 +331,8 @@ static const struct sunxi_pinctrl_function sun7i_a20_pinctrl_functions[] = { { "gmac", 5 }, /* PA0-PA17 */ { "gpio_in", 0 }, { "gpio_out", 1 }, + { "i2c0", 2 }, /* PB0-PB1 */ + { "i2c1", 2 }, /* PB18-PB19 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 4 }, /* PF2-PF4 */ #else @@ -339,6 +350,8 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun7i_a20_pinctrl_desc = { static const struct sunxi_pinctrl_function sun8i_a23_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "i2c0", 2 }, /* PH2-PH3 */ + { "i2c1", 2 }, /* PH4-PH5 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #endif @@ -356,6 +369,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a23_pinctrl_desc = { static const struct sunxi_pinctrl_function sun8i_a23_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_i2c", 3 }, /* PL0-PL1 */ { "s_uart", 2 }, /* PL2-PL3 */ }; @@ -369,6 +383,8 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a23_r_pinctrl_desc = static const struct sunxi_pinctrl_function sun8i_a33_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "i2c0", 2 }, /* PH2-PH3 */ + { "i2c1", 2 }, /* PH4-PH5 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -389,6 +405,8 @@ static const struct sunxi_pinctrl_function sun8i_a83t_pinctrl_functions[] = { { "gmac", 4 }, /* PD2-PD23 */ { "gpio_in", 0 }, { "gpio_out", 1 }, + { "i2c0", 2 }, /* PH0-PH1 */ + { "i2c1", 2 }, /* PH2-PH3 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -408,6 +426,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_a83t_pinctrl_desc = static const struct sunxi_pinctrl_function sun8i_a83t_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_i2c", 2 }, /* PL8-PL9 */ { "s_uart", 2 }, /* PL2-PL3 */ }; @@ -422,6 +441,8 @@ static const struct sunxi_pinctrl_function sun8i_h3_pinctrl_functions[] = { { "emac", 2 }, /* PD0-PD17 */ { "gpio_in", 0 }, { "gpio_out", 1 }, + { "i2c0", 2 }, /* PA11-PA12 */ + { "i2c1", 3 }, /* PA18-PA19 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -441,6 +462,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun8i_h3_pinctrl_desc = { static const struct sunxi_pinctrl_function sun8i_h3_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_i2c", 2 }, /* PL0-PL1 */ { "s_uart", 2 }, /* PL2-PL3 */ }; @@ -455,6 +477,8 @@ static const struct sunxi_pinctrl_function sun8i_v3s_pinctrl_functions[] = { { "emac", 4 }, /* PD0-PD17 */ { "gpio_in", 0 }, { "gpio_out", 1 }, + { "i2c0", 2 }, /* PB6-PB7 */ + { "i2c1", 2 }, /* PB8-PB9 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -475,6 +499,8 @@ static const struct sunxi_pinctrl_function sun9i_a80_pinctrl_functions[] = { { "gmac", 2 }, /* PA0-PA17 */ { "gpio_in", 0 }, { "gpio_out", 1 }, + { "i2c0", 2 }, /* PH0-PH1 */ + { "i2c1", 2 }, /* PH2-PH3 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 4 }, /* PF2-PF4 */ #else @@ -492,6 +518,8 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun9i_a80_pinctrl_desc = { static const struct sunxi_pinctrl_function sun9i_a80_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_i2c0", 2 }, /* PN0-PN1 */ + { "s_i2c1", 3 }, /* PM8-PM9 */ { "s_uart", 3 }, /* PL0-PL1 */ }; @@ -506,6 +534,8 @@ static const struct sunxi_pinctrl_function sun50i_a64_pinctrl_functions[] = { { "emac", 4 }, /* PD8-PD23 */ { "gpio_in", 0 }, { "gpio_out", 1 }, + { "i2c0", 2 }, /* PH0-PH1 */ + { "i2c1", 2 }, /* PH2-PH3 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -525,6 +555,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_a64_pinctrl_desc = static const struct sunxi_pinctrl_function sun50i_a64_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_i2c", 2 }, /* PL8-PL9 */ { "s_uart", 2 }, /* PL2-PL3 */ }; @@ -539,6 +570,8 @@ static const struct sunxi_pinctrl_function sun50i_h5_pinctrl_functions[] = { { "emac", 2 }, /* PD0-PD17 */ { "gpio_in", 0 }, { "gpio_out", 1 }, + { "i2c0", 2 }, /* PA11-PA12 */ + { "i2c1", 3 }, /* PA18-PA19 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -559,6 +592,8 @@ static const struct sunxi_pinctrl_function sun50i_h6_pinctrl_functions[] = { { "emac", 5 }, /* PD0-PD20 */ { "gpio_in", 0 }, { "gpio_out", 1 }, + { "i2c0", 2 }, /* PD25-PD26 */ + { "i2c1", 4 }, /* PH5-PH6 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -577,6 +612,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h6_pinctrl_desc = { static const struct sunxi_pinctrl_function sun50i_h6_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_i2c", 3 }, /* PL0-PL1 */ { "s_uart", 2 }, /* PL2-PL3 */ }; @@ -609,6 +645,7 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h616_pinctrl_desc = static const struct sunxi_pinctrl_function sun50i_h616_r_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, + { "s_i2c", 3 }, /* PL0-PL1 */ { "s_uart", 2 }, /* PL2-PL3 */ }; From aadf3d53830c9ce0787ed6d9c711141d17f9ad29 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 20 Oct 2021 22:55:06 -0500 Subject: [PATCH 13/40] sunxi: Remove options and setup code for I2C2-I2C4 These options are not currently enabled anywhere. Any new users should use DM clocks and pinctrl. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- arch/arm/include/asm/arch-sunxi/gpio.h | 8 ----- arch/arm/include/asm/arch-sunxi/i2c.h | 11 +----- arch/arm/mach-sunxi/Kconfig | 22 ------------ board/sunxi/board.c | 48 -------------------------- 4 files changed, 1 insertion(+), 88 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 2aa6bbb1785..cf5afdac6a2 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -141,8 +141,6 @@ enum sunxi_gpio_number { #define SUN4I_GPB_TWI0 2 #define SUN4I_GPB_TWI1 2 #define SUN5I_GPB_TWI1 2 -#define SUN4I_GPB_TWI2 2 -#define SUN5I_GPB_TWI2 2 #define SUN8I_V3S_GPB_TWI0 2 #define SUN4I_GPB_UART0 2 #define SUN5I_GPB_UART0 2 @@ -164,8 +162,6 @@ enum sunxi_gpio_number { #define SUNXI_GPD_PWM 2 #define SUNIV_GPE_UART0 5 -#define SUN8I_GPE_TWI2 3 -#define SUN50I_GPE_TWI2 3 #define SUNXI_GPF_SDC0 2 #define SUNXI_GPF_UART0 4 @@ -176,7 +172,6 @@ enum sunxi_gpio_number { #define SUN6I_GPG_SDC1 2 #define SUN8I_GPG_SDC1 2 #define SUN8I_GPG_UART1 2 -#define SUN6I_GPG_TWI3 2 #define SUN5I_GPG_UART1 4 #define SUN6I_GPH_PWM 2 @@ -188,15 +183,12 @@ enum sunxi_gpio_number { #define SUN6I_GPH_TWI1 2 #define SUN8I_GPH_TWI1 2 #define SUN50I_GPH_TWI1 2 -#define SUN6I_GPH_TWI2 2 #define SUN6I_GPH_UART0 2 #define SUN9I_GPH_UART0 2 #define SUN50I_H6_GPH_UART0 2 #define SUN50I_H616_GPH_UART0 2 #define SUNXI_GPI_SDC3 2 -#define SUN7I_GPI_TWI3 3 -#define SUN7I_GPI_TWI4 3 #define SUN6I_GPL0_R_P2WI_SCK 3 #define SUN6I_GPL1_R_P2WI_SDA 3 diff --git a/arch/arm/include/asm/arch-sunxi/i2c.h b/arch/arm/include/asm/arch-sunxi/i2c.h index 1cb2ba6b0ab..3525f22e7df 100644 --- a/arch/arm/include/asm/arch-sunxi/i2c.h +++ b/arch/arm/include/asm/arch-sunxi/i2c.h @@ -13,17 +13,8 @@ #ifdef CONFIG_I2C1_ENABLE #define CONFIG_I2C_MVTWSI_BASE1 SUNXI_TWI1_BASE #endif -#ifdef CONFIG_I2C2_ENABLE -#define CONFIG_I2C_MVTWSI_BASE2 SUNXI_TWI2_BASE -#endif -#ifdef CONFIG_I2C3_ENABLE -#define CONFIG_I2C_MVTWSI_BASE3 SUNXI_TWI3_BASE -#endif -#ifdef CONFIG_I2C4_ENABLE -#define CONFIG_I2C_MVTWSI_BASE4 SUNXI_TWI4_BASE -#endif #ifdef CONFIG_R_I2C_ENABLE -#define CONFIG_I2C_MVTWSI_BASE5 SUNXI_R_TWI_BASE +#define CONFIG_I2C_MVTWSI_BASE2 SUNXI_R_TWI_BASE #endif /* This is abp0-clk on sun4i/5i/7i / abp1-clk on sun6i/sun8i which is 24MHz */ diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 73da6b8f615..e5ed1d97e89 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -755,20 +755,6 @@ config I2C1_ENABLE ---help--- See I2C0_ENABLE help text. -config I2C2_ENABLE - bool "Enable I2C/TWI controller 2" - select CMD_I2C - ---help--- - See I2C0_ENABLE help text. - -if MACH_SUN6I || MACH_SUN7I -config I2C3_ENABLE - bool "Enable I2C/TWI controller 3" - select CMD_I2C - ---help--- - See I2C0_ENABLE help text. -endif - if SUNXI_GEN_SUN6I || SUN50I_GEN_H6 config R_I2C_ENABLE bool "Enable the PRCM I2C/TWI controller" @@ -779,14 +765,6 @@ config R_I2C_ENABLE Set this to y to enable the I2C controller which is part of the PRCM. endif -if MACH_SUN7I -config I2C4_ENABLE - bool "Enable I2C/TWI controller 4" - select CMD_I2C - ---help--- - See I2C0_ENABLE help text. -endif - config AXP_GPIO bool "Enable support for gpio-s on axp PMICs" depends on AXP_PMIC_BUS diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 28f702bc296..982ec44e034 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -107,54 +107,6 @@ void i2c_init_board(void) #endif #endif -#ifdef CONFIG_I2C2_ENABLE -#if defined(CONFIG_MACH_SUN4I) || \ - defined(CONFIG_MACH_SUN7I) || \ - defined(CONFIG_MACH_SUN8I_R40) - sunxi_gpio_set_cfgpin(SUNXI_GPB(20), SUN4I_GPB_TWI2); - sunxi_gpio_set_cfgpin(SUNXI_GPB(21), SUN4I_GPB_TWI2); - clock_twi_onoff(2, 1); -#elif defined(CONFIG_MACH_SUN5I) - sunxi_gpio_set_cfgpin(SUNXI_GPB(17), SUN5I_GPB_TWI2); - sunxi_gpio_set_cfgpin(SUNXI_GPB(18), SUN5I_GPB_TWI2); - clock_twi_onoff(2, 1); -#elif defined(CONFIG_MACH_SUN6I) - sunxi_gpio_set_cfgpin(SUNXI_GPH(18), SUN6I_GPH_TWI2); - sunxi_gpio_set_cfgpin(SUNXI_GPH(19), SUN6I_GPH_TWI2); - clock_twi_onoff(2, 1); -#elif defined(CONFIG_MACH_SUN8I) - sunxi_gpio_set_cfgpin(SUNXI_GPE(12), SUN8I_GPE_TWI2); - sunxi_gpio_set_cfgpin(SUNXI_GPE(13), SUN8I_GPE_TWI2); - clock_twi_onoff(2, 1); -#elif defined(CONFIG_MACH_SUN50I) - sunxi_gpio_set_cfgpin(SUNXI_GPE(14), SUN50I_GPE_TWI2); - sunxi_gpio_set_cfgpin(SUNXI_GPE(15), SUN50I_GPE_TWI2); - clock_twi_onoff(2, 1); -#endif -#endif - -#ifdef CONFIG_I2C3_ENABLE -#if defined(CONFIG_MACH_SUN6I) - sunxi_gpio_set_cfgpin(SUNXI_GPG(10), SUN6I_GPG_TWI3); - sunxi_gpio_set_cfgpin(SUNXI_GPG(11), SUN6I_GPG_TWI3); - clock_twi_onoff(3, 1); -#elif defined(CONFIG_MACH_SUN7I) || \ - defined(CONFIG_MACH_SUN8I_R40) - sunxi_gpio_set_cfgpin(SUNXI_GPI(0), SUN7I_GPI_TWI3); - sunxi_gpio_set_cfgpin(SUNXI_GPI(1), SUN7I_GPI_TWI3); - clock_twi_onoff(3, 1); -#endif -#endif - -#ifdef CONFIG_I2C4_ENABLE -#if defined(CONFIG_MACH_SUN7I) || \ - defined(CONFIG_MACH_SUN8I_R40) - sunxi_gpio_set_cfgpin(SUNXI_GPI(2), SUN7I_GPI_TWI4); - sunxi_gpio_set_cfgpin(SUNXI_GPI(3), SUN7I_GPI_TWI4); - clock_twi_onoff(4, 1); -#endif -#endif - #ifdef CONFIG_R_I2C_ENABLE #ifdef CONFIG_MACH_SUN50I clock_twi_onoff(5, 1); From 923d89316ae6e48a4ce5abd4324c74aae38dddde Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 20 Oct 2021 23:01:29 -0500 Subject: [PATCH 14/40] i2c: sun6i_p2wi: Only do non-DM pin setup for non-DM I2C When the DM_I2C driver is loaded, the pin setup is done automatically from the device tree by the pinctrl driver. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/i2c/sun6i_p2wi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/sun6i_p2wi.c b/drivers/i2c/sun6i_p2wi.c index c9e1b3fcd5f..73b808b09bf 100644 --- a/drivers/i2c/sun6i_p2wi.c +++ b/drivers/i2c/sun6i_p2wi.c @@ -102,12 +102,6 @@ static int sun6i_p2wi_change_to_p2wi_mode(struct sunxi_p2wi_reg *base, static void sun6i_p2wi_init(struct sunxi_p2wi_reg *base) { - /* Enable p2wi and PIO clk, and de-assert their resets */ - prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_P2WI); - - sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN6I_GPL0_R_P2WI_SCK); - sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN6I_GPL1_R_P2WI_SDA); - /* Reset p2wi controller and set clock to CLKIN(12)/8 = 1.5 MHz */ writel(P2WI_CTRL_RESET, &base->ctrl); sdelay(0x100); @@ -142,6 +136,12 @@ void p2wi_init(void) { struct sunxi_p2wi_reg *base = (struct sunxi_p2wi_reg *)SUN6I_P2WI_BASE; + /* Enable p2wi and PIO clk, and de-assert their resets */ + prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_P2WI); + + sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN6I_GPL0_R_P2WI_SCK); + sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN6I_GPL1_R_P2WI_SDA); + sun6i_p2wi_init(base); } #endif From af2ec35c4179620e2655f195ec0fd41e7a1ff784 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 20 Oct 2021 23:01:29 -0500 Subject: [PATCH 15/40] i2c: sun8i_rsb: Only do non-DM pin setup for non-DM I2C When the DM_I2C driver is loaded, the pin setup is done automatically from the device tree by the pinctrl driver. Clean up the code in the process: remove #ifdefs and recognize that the pin configuration is the same for all sun8i/sun50i SoCs, not just those which select CONFIG_MACH_SUN8I. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/i2c/sun8i_rsb.c | 46 +++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/drivers/i2c/sun8i_rsb.c b/drivers/i2c/sun8i_rsb.c index 716b245a003..0dea8f7a923 100644 --- a/drivers/i2c/sun8i_rsb.c +++ b/drivers/i2c/sun8i_rsb.c @@ -95,27 +95,6 @@ static int sun8i_rsb_set_device_address(struct sunxi_rsb_reg *base, return sun8i_rsb_do_trans(base); } -static void sun8i_rsb_cfg_io(void) -{ -#ifdef CONFIG_MACH_SUN8I - sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_GPL_R_RSB); - sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN8I_GPL_R_RSB); - sunxi_gpio_set_pull(SUNXI_GPL(0), 1); - sunxi_gpio_set_pull(SUNXI_GPL(1), 1); - sunxi_gpio_set_drv(SUNXI_GPL(0), 2); - sunxi_gpio_set_drv(SUNXI_GPL(1), 2); -#elif defined CONFIG_MACH_SUN9I - sunxi_gpio_set_cfgpin(SUNXI_GPN(0), SUN9I_GPN_R_RSB); - sunxi_gpio_set_cfgpin(SUNXI_GPN(1), SUN9I_GPN_R_RSB); - sunxi_gpio_set_pull(SUNXI_GPN(0), 1); - sunxi_gpio_set_pull(SUNXI_GPN(1), 1); - sunxi_gpio_set_drv(SUNXI_GPN(0), 2); - sunxi_gpio_set_drv(SUNXI_GPN(1), 2); -#else -#error unsupported MACH_SUNXI -#endif -} - static void sun8i_rsb_set_clk(struct sunxi_rsb_reg *base) { u32 div = 0; @@ -147,12 +126,6 @@ static int sun8i_rsb_set_device_mode(struct sunxi_rsb_reg *base) static int sun8i_rsb_init(struct sunxi_rsb_reg *base) { - /* Enable RSB and PIO clk, and de-assert their resets */ - prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_RSB); - - /* Setup external pins */ - sun8i_rsb_cfg_io(); - writel(RSB_CTRL_SOFT_RST, &base->ctrl); sun8i_rsb_set_clk(base); @@ -185,6 +158,25 @@ int rsb_init(void) { struct sunxi_rsb_reg *base = (struct sunxi_rsb_reg *)SUNXI_RSB_BASE; + /* Enable RSB and PIO clk, and de-assert their resets */ + prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_RSB); + + if (IS_ENABLED(CONFIG_MACH_SUN9I)) { + sunxi_gpio_set_cfgpin(SUNXI_GPN(0), SUN9I_GPN_R_RSB); + sunxi_gpio_set_cfgpin(SUNXI_GPN(1), SUN9I_GPN_R_RSB); + sunxi_gpio_set_pull(SUNXI_GPN(0), 1); + sunxi_gpio_set_pull(SUNXI_GPN(1), 1); + sunxi_gpio_set_drv(SUNXI_GPN(0), 2); + sunxi_gpio_set_drv(SUNXI_GPN(1), 2); + } else { + sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_GPL_R_RSB); + sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN8I_GPL_R_RSB); + sunxi_gpio_set_pull(SUNXI_GPL(0), 1); + sunxi_gpio_set_pull(SUNXI_GPL(1), 1); + sunxi_gpio_set_drv(SUNXI_GPL(0), 2); + sunxi_gpio_set_drv(SUNXI_GPL(1), 2); + } + return sun8i_rsb_init(base); } #endif From 7570c54e46a76a853a1e3f89a7a3e9960e6a511b Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 28 Aug 2021 16:51:03 -0500 Subject: [PATCH 16/40] pinctrl: sunxi: Add MMC pinmuxes Pin lists and mux values were taken from the Linux drivers. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 54 +++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index d19cf27746a..7e66c30f859 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -237,6 +237,8 @@ static const struct sunxi_pinctrl_function suniv_f1c100s_pinctrl_functions[] = { { "gpio_out", 1 }, { "i2c0", 3 }, /* PE11-PE12 */ { "i2c1", 3 }, /* PD5-PD6 */ + { "mmc0", 2 }, /* PF0-PF5 */ + { "mmc1", 3 }, /* PC0-PC2 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -257,6 +259,14 @@ static const struct sunxi_pinctrl_function sun4i_a10_pinctrl_functions[] = { { "gpio_out", 1 }, { "i2c0", 2 }, /* PB0-PB1 */ { "i2c1", 2 }, /* PB18-PB19 */ + { "mmc0", 2 }, /* PF0-PF5 */ +#if IS_ENABLED(CONFIG_MMC1_PINS_PH) + { "mmc1", 5 }, /* PH22-PH27 */ +#else + { "mmc1", 4 }, /* PG0-PG5 */ +#endif + { "mmc2", 3 }, /* PC6-PC15 */ + { "mmc3", 2 }, /* PI4-PI9 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 4 }, /* PF2-PF4 */ #else @@ -277,6 +287,9 @@ static const struct sunxi_pinctrl_function sun5i_a13_pinctrl_functions[] = { { "gpio_out", 1 }, { "i2c0", 2 }, /* PB0-PB1 */ { "i2c1", 2 }, /* PB15-PB16 */ + { "mmc0", 2 }, /* PF0-PF5 */ + { "mmc1", 2 }, /* PG3-PG8 */ + { "mmc2", 3 }, /* PC6-PC15 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 4 }, /* PF2-PF4 */ #else @@ -298,6 +311,10 @@ static const struct sunxi_pinctrl_function sun6i_a31_pinctrl_functions[] = { { "gpio_out", 1 }, { "i2c0", 2 }, /* PH14-PH15 */ { "i2c1", 2 }, /* PH16-PH17 */ + { "mmc0", 2 }, /* PF0-PF5 */ + { "mmc1", 2 }, /* PG0-PG5 */ + { "mmc2", 3 }, /* PC6-PC15, PC24 */ + { "mmc3", 4 }, /* PC6-PC15, PC24 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -333,6 +350,13 @@ static const struct sunxi_pinctrl_function sun7i_a20_pinctrl_functions[] = { { "gpio_out", 1 }, { "i2c0", 2 }, /* PB0-PB1 */ { "i2c1", 2 }, /* PB18-PB19 */ + { "mmc0", 2 }, /* PF0-PF5 */ +#if IS_ENABLED(CONFIG_MMC1_PINS_PH) + { "mmc1", 5 }, /* PH22-PH27 */ +#else + { "mmc1", 4 }, /* PG0-PG5 */ +#endif + { "mmc2", 3 }, /* PC5-PC15, PC24 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 4 }, /* PF2-PF4 */ #else @@ -352,6 +376,9 @@ static const struct sunxi_pinctrl_function sun8i_a23_pinctrl_functions[] = { { "gpio_out", 1 }, { "i2c0", 2 }, /* PH2-PH3 */ { "i2c1", 2 }, /* PH4-PH5 */ + { "mmc0", 2 }, /* PF0-PF5 */ + { "mmc1", 2 }, /* PG0-PG5 */ + { "mmc2", 3 }, /* PC5-PC16 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #endif @@ -385,6 +412,9 @@ static const struct sunxi_pinctrl_function sun8i_a33_pinctrl_functions[] = { { "gpio_out", 1 }, { "i2c0", 2 }, /* PH2-PH3 */ { "i2c1", 2 }, /* PH4-PH5 */ + { "mmc0", 2 }, /* PF0-PF5 */ + { "mmc1", 2 }, /* PG0-PG5 */ + { "mmc2", 3 }, /* PC5-PC16 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -407,6 +437,9 @@ static const struct sunxi_pinctrl_function sun8i_a83t_pinctrl_functions[] = { { "gpio_out", 1 }, { "i2c0", 2 }, /* PH0-PH1 */ { "i2c1", 2 }, /* PH2-PH3 */ + { "mmc0", 2 }, /* PF0-PF5 */ + { "mmc1", 2 }, /* PG0-PG5 */ + { "mmc2", 3 }, /* PC5-PC16 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -443,6 +476,9 @@ static const struct sunxi_pinctrl_function sun8i_h3_pinctrl_functions[] = { { "gpio_out", 1 }, { "i2c0", 2 }, /* PA11-PA12 */ { "i2c1", 3 }, /* PA18-PA19 */ + { "mmc0", 2 }, /* PF0-PF5 */ + { "mmc1", 2 }, /* PG0-PG5 */ + { "mmc2", 3 }, /* PC5-PC16 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -479,6 +515,9 @@ static const struct sunxi_pinctrl_function sun8i_v3s_pinctrl_functions[] = { { "gpio_out", 1 }, { "i2c0", 2 }, /* PB6-PB7 */ { "i2c1", 2 }, /* PB8-PB9 */ + { "mmc0", 2 }, /* PF0-PF5 */ + { "mmc1", 2 }, /* PG0-PG5 */ + { "mmc2", 2 }, /* PC0-PC10 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -501,6 +540,9 @@ static const struct sunxi_pinctrl_function sun9i_a80_pinctrl_functions[] = { { "gpio_out", 1 }, { "i2c0", 2 }, /* PH0-PH1 */ { "i2c1", 2 }, /* PH2-PH3 */ + { "mmc0", 2 }, /* PF0-PF5 */ + { "mmc1", 2 }, /* PG0-PG5 */ + { "mmc2", 3 }, /* PC6-PC16 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 4 }, /* PF2-PF4 */ #else @@ -536,6 +578,9 @@ static const struct sunxi_pinctrl_function sun50i_a64_pinctrl_functions[] = { { "gpio_out", 1 }, { "i2c0", 2 }, /* PH0-PH1 */ { "i2c1", 2 }, /* PH2-PH3 */ + { "mmc0", 2 }, /* PF0-PF5 */ + { "mmc1", 2 }, /* PG0-PG5 */ + { "mmc2", 3 }, /* PC1-PC16 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -572,6 +617,9 @@ static const struct sunxi_pinctrl_function sun50i_h5_pinctrl_functions[] = { { "gpio_out", 1 }, { "i2c0", 2 }, /* PA11-PA12 */ { "i2c1", 3 }, /* PA18-PA19 */ + { "mmc0", 2 }, /* PF0-PF5 */ + { "mmc1", 2 }, /* PG0-PG5 */ + { "mmc2", 3 }, /* PC1-PC16 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -594,6 +642,9 @@ static const struct sunxi_pinctrl_function sun50i_h6_pinctrl_functions[] = { { "gpio_out", 1 }, { "i2c0", 2 }, /* PD25-PD26 */ { "i2c1", 4 }, /* PH5-PH6 */ + { "mmc0", 2 }, /* PF0-PF5 */ + { "mmc1", 2 }, /* PG0-PG5 */ + { "mmc2", 3 }, /* PC1-PC14 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -627,6 +678,9 @@ static const struct sunxi_pinctrl_function sun50i_h616_pinctrl_functions[] = { { "emac0", 2 }, /* PI0-PI16 */ { "gpio_in", 0 }, { "gpio_out", 1 }, + { "mmc0", 2 }, /* PF0-PF5 */ + { "mmc1", 2 }, /* PG0-PG5 */ + { "mmc2", 3 }, /* PC0-PC16 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else From 8c2bdff48392f71b18812f519635cbf2003801e5 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 28 Aug 2021 11:49:03 -0500 Subject: [PATCH 17/40] sunxi: Remove non-DM MMC pin setup This is now handled automatically by the pinctrl driver. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- board/sunxi/board.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 982ec44e034..89324159d55 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -250,17 +250,6 @@ int board_init(void) i2c_init_board(); #endif -#ifdef CONFIG_DM_MMC - /* - * Temporary workaround for enabling MMC clocks until a sunxi DM - * pinctrl driver lands. - */ - mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT); -#if CONFIG_MMC_SUNXI_SLOT_EXTRA != -1 - mmc_pinmux_setup(CONFIG_MMC_SUNXI_SLOT_EXTRA); -#endif -#endif /* CONFIG_DM_MMC */ - eth_init_board(); return 0; From aa4823ce483f1c277775200846c5684697a4669a Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 28 Aug 2021 15:52:52 -0500 Subject: [PATCH 18/40] pinctrl: sunxi: Add the A64 PWM pinmux This is the only possible mux setting for the A64's PWM peripheral. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 7e66c30f859..b8ca452e83a 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -581,6 +581,7 @@ static const struct sunxi_pinctrl_function sun50i_a64_pinctrl_functions[] = { { "mmc0", 2 }, /* PF0-PF5 */ { "mmc1", 2 }, /* PG0-PG5 */ { "mmc2", 3 }, /* PC1-PC16 */ + { "pwm", 2 }, /* PD22 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else From 458e59da5d8dfc9da49601cb50688b7e71a1242d Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 28 Aug 2021 11:50:51 -0500 Subject: [PATCH 19/40] pwm: sunxi: Remove non-DM pin setup This is now handled automatically by the pinctrl driver. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- arch/arm/include/asm/arch-sunxi/gpio.h | 1 - drivers/pwm/sunxi_pwm.c | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index cf5afdac6a2..9f07d907e5a 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -159,7 +159,6 @@ enum sunxi_gpio_number { #define SUNXI_GPD_LCD0 2 #define SUNXI_GPD_LVDS0 3 -#define SUNXI_GPD_PWM 2 #define SUNIV_GPE_UART0 5 diff --git a/drivers/pwm/sunxi_pwm.c b/drivers/pwm/sunxi_pwm.c index e3d5ee456b0..bb1bec05ec3 100644 --- a/drivers/pwm/sunxi_pwm.c +++ b/drivers/pwm/sunxi_pwm.c @@ -13,7 +13,6 @@ #include #include #include -#include #include DECLARE_GLOBAL_DATA_PTR; @@ -45,14 +44,6 @@ static const u32 prescaler_table[] = { 1, /* 1111 */ }; -static int sunxi_pwm_config_pinmux(void) -{ -#ifdef CONFIG_MACH_SUN50I - sunxi_gpio_set_cfgpin(SUNXI_GPD(22), SUNXI_GPD_PWM); -#endif - return 0; -} - static int sunxi_pwm_set_invert(struct udevice *dev, uint channel, bool polarity) { @@ -137,8 +128,6 @@ static int sunxi_pwm_set_enable(struct udevice *dev, uint channel, bool enable) return 0; } - sunxi_pwm_config_pinmux(); - if (priv->invert) v &= ~SUNXI_PWM_CTRL_CH0_ACT_STA; else From 77834dcc5bafb3928d3caa02f676b43487eb36a4 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 28 Aug 2021 17:05:35 -0500 Subject: [PATCH 20/40] pinctrl: sunxi: Add SPI0 pinmuxes Pin lists and mux values were taken from the Linux drivers. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index b8ca452e83a..9ce2bc1b3af 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -239,6 +239,7 @@ static const struct sunxi_pinctrl_function suniv_f1c100s_pinctrl_functions[] = { { "i2c1", 3 }, /* PD5-PD6 */ { "mmc0", 2 }, /* PF0-PF5 */ { "mmc1", 3 }, /* PC0-PC2 */ + { "spi0", 2 }, /* PC0-PC3 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -267,6 +268,7 @@ static const struct sunxi_pinctrl_function sun4i_a10_pinctrl_functions[] = { #endif { "mmc2", 3 }, /* PC6-PC15 */ { "mmc3", 2 }, /* PI4-PI9 */ + { "spi0", 3 }, /* PC0-PC2, PC23 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 4 }, /* PF2-PF4 */ #else @@ -290,6 +292,7 @@ static const struct sunxi_pinctrl_function sun5i_a13_pinctrl_functions[] = { { "mmc0", 2 }, /* PF0-PF5 */ { "mmc1", 2 }, /* PG3-PG8 */ { "mmc2", 3 }, /* PC6-PC15 */ + { "spi0", 3 }, /* PC0-PC3 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 4 }, /* PF2-PF4 */ #else @@ -315,6 +318,7 @@ static const struct sunxi_pinctrl_function sun6i_a31_pinctrl_functions[] = { { "mmc1", 2 }, /* PG0-PG5 */ { "mmc2", 3 }, /* PC6-PC15, PC24 */ { "mmc3", 4 }, /* PC6-PC15, PC24 */ + { "spi0", 3 }, /* PC0-PC2, PC27 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -357,6 +361,7 @@ static const struct sunxi_pinctrl_function sun7i_a20_pinctrl_functions[] = { { "mmc1", 4 }, /* PG0-PG5 */ #endif { "mmc2", 3 }, /* PC5-PC15, PC24 */ + { "spi0", 3 }, /* PC0-PC2, PC23 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 4 }, /* PF2-PF4 */ #else @@ -379,6 +384,7 @@ static const struct sunxi_pinctrl_function sun8i_a23_pinctrl_functions[] = { { "mmc0", 2 }, /* PF0-PF5 */ { "mmc1", 2 }, /* PG0-PG5 */ { "mmc2", 3 }, /* PC5-PC16 */ + { "spi0", 3 }, /* PC0-PC3 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #endif @@ -415,6 +421,7 @@ static const struct sunxi_pinctrl_function sun8i_a33_pinctrl_functions[] = { { "mmc0", 2 }, /* PF0-PF5 */ { "mmc1", 2 }, /* PG0-PG5 */ { "mmc2", 3 }, /* PC5-PC16 */ + { "spi0", 3 }, /* PC0-PC3 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -440,6 +447,7 @@ static const struct sunxi_pinctrl_function sun8i_a83t_pinctrl_functions[] = { { "mmc0", 2 }, /* PF0-PF5 */ { "mmc1", 2 }, /* PG0-PG5 */ { "mmc2", 3 }, /* PC5-PC16 */ + { "spi0", 3 }, /* PC0-PC3 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -479,6 +487,7 @@ static const struct sunxi_pinctrl_function sun8i_h3_pinctrl_functions[] = { { "mmc0", 2 }, /* PF0-PF5 */ { "mmc1", 2 }, /* PG0-PG5 */ { "mmc2", 3 }, /* PC5-PC16 */ + { "spi0", 3 }, /* PC0-PC3 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -518,6 +527,7 @@ static const struct sunxi_pinctrl_function sun8i_v3s_pinctrl_functions[] = { { "mmc0", 2 }, /* PF0-PF5 */ { "mmc1", 2 }, /* PG0-PG5 */ { "mmc2", 2 }, /* PC0-PC10 */ + { "spi0", 3 }, /* PC0-PC3 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -543,6 +553,7 @@ static const struct sunxi_pinctrl_function sun9i_a80_pinctrl_functions[] = { { "mmc0", 2 }, /* PF0-PF5 */ { "mmc1", 2 }, /* PG0-PG5 */ { "mmc2", 3 }, /* PC6-PC16 */ + { "spi0", 3 }, /* PC0-PC2, PC19 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 4 }, /* PF2-PF4 */ #else @@ -582,6 +593,7 @@ static const struct sunxi_pinctrl_function sun50i_a64_pinctrl_functions[] = { { "mmc1", 2 }, /* PG0-PG5 */ { "mmc2", 3 }, /* PC1-PC16 */ { "pwm", 2 }, /* PD22 */ + { "spi0", 4 }, /* PC0-PC3 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -621,6 +633,7 @@ static const struct sunxi_pinctrl_function sun50i_h5_pinctrl_functions[] = { { "mmc0", 2 }, /* PF0-PF5 */ { "mmc1", 2 }, /* PG0-PG5 */ { "mmc2", 3 }, /* PC1-PC16 */ + { "spi0", 3 }, /* PC0-PC3 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -646,6 +659,7 @@ static const struct sunxi_pinctrl_function sun50i_h6_pinctrl_functions[] = { { "mmc0", 2 }, /* PF0-PF5 */ { "mmc1", 2 }, /* PG0-PG5 */ { "mmc2", 3 }, /* PC1-PC14 */ + { "spi0", 4 }, /* PC0-PC7 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else @@ -682,6 +696,7 @@ static const struct sunxi_pinctrl_function sun50i_h616_pinctrl_functions[] = { { "mmc0", 2 }, /* PF0-PF5 */ { "mmc1", 2 }, /* PG0-PG5 */ { "mmc2", 3 }, /* PC0-PC16 */ + { "spi0", 4 }, /* PC0-PC7, PC15-PC16 */ #if IS_ENABLED(CONFIG_UART0_PORT_F) { "uart0", 3 }, /* PF2-PF4 */ #else From f64233e9a54ae4b36b7fe4c739275005187f27b5 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 28 Aug 2021 11:50:28 -0500 Subject: [PATCH 21/40] spi: sun4i_spi: Remove non-DM pin setup This is now handled automatically by the pinctrl driver. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/spi/spi-sunxi.c | 84 ----------------------------------------- 1 file changed, 84 deletions(-) diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c index d62355ec6fb..b6cd7ddafad 100644 --- a/drivers/spi/spi-sunxi.c +++ b/drivers/spi/spi-sunxi.c @@ -32,7 +32,6 @@ #include #include -#include #include #include @@ -180,87 +179,6 @@ static void sun4i_spi_set_cs(struct udevice *bus, u8 cs, bool enable) writel(reg, SPI_REG(priv, SPI_TCR)); } -static int sun4i_spi_parse_pins(struct udevice *dev) -{ - const void *fdt = gd->fdt_blob; - const char *pin_name; - const fdt32_t *list; - u32 phandle; - int drive, pull = 0, pin, i; - int offset; - int size; - - list = fdt_getprop(fdt, dev_of_offset(dev), "pinctrl-0", &size); - if (!list) { - printf("WARNING: sun4i_spi: cannot find pinctrl-0 node\n"); - return -EINVAL; - } - - while (size) { - phandle = fdt32_to_cpu(*list++); - size -= sizeof(*list); - - offset = fdt_node_offset_by_phandle(fdt, phandle); - if (offset < 0) - return offset; - - drive = fdt_getprop_u32_default_node(fdt, offset, 0, - "drive-strength", 0); - if (drive) { - if (drive <= 10) - drive = 0; - else if (drive <= 20) - drive = 1; - else if (drive <= 30) - drive = 2; - else - drive = 3; - } else { - drive = fdt_getprop_u32_default_node(fdt, offset, 0, - "allwinner,drive", - 0); - drive = min(drive, 3); - } - - if (fdt_get_property(fdt, offset, "bias-disable", NULL)) - pull = 0; - else if (fdt_get_property(fdt, offset, "bias-pull-up", NULL)) - pull = 1; - else if (fdt_get_property(fdt, offset, "bias-pull-down", NULL)) - pull = 2; - else - pull = fdt_getprop_u32_default_node(fdt, offset, 0, - "allwinner,pull", - 0); - pull = min(pull, 2); - - for (i = 0; ; i++) { - pin_name = fdt_stringlist_get(fdt, offset, - "pins", i, NULL); - if (!pin_name) { - pin_name = fdt_stringlist_get(fdt, offset, - "allwinner,pins", - i, NULL); - if (!pin_name) - break; - } - - pin = sunxi_name_to_gpio(pin_name); - if (pin < 0) - break; - - if (IS_ENABLED(CONFIG_MACH_SUN50I) || - IS_ENABLED(CONFIG_SUN50I_GEN_H6)) - sunxi_gpio_set_cfgpin(pin, SUN50I_GPC_SPI0); - else - sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SPI0); - sunxi_gpio_set_drv(pin, drive); - sunxi_gpio_set_pull(pin, pull); - } - } - return 0; -} - static inline int sun4i_spi_set_clock(struct udevice *dev, bool enable) { struct sun4i_spi_priv *priv = dev_get_priv(dev); @@ -507,8 +425,6 @@ static int sun4i_spi_probe(struct udevice *bus) return ret; } - sun4i_spi_parse_pins(bus); - priv->variant = plat->variant; priv->base = plat->base; priv->freq = plat->max_hz; From c2d08f01100a13de87f6745250db3a50fc3fbb97 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 14 Oct 2021 20:53:04 -0500 Subject: [PATCH 22/40] mkimage: add a flag to describe whether -A is specified The sunxi_egon type used to take no -A argument (because we assume sunxi targets are all ARM). However, as Allwinner D1 appears as the first RISC-V sunxi target, we need to support -A; in addition, as external projects rely on U-Boot mkimage to generate sunxi eGON.BT0 header, we need to keep compatibility with command line without -A. As the default value of arch in mkimage is not proper (IH_ARCH_PPC instead of IH_ARCH_INVALID), to keep more compatibility, add an Aflag field to image parameters to describe whether an architecture is explicitly specified. Reviewed-by: Tom Rini Signed-off-by: Icenowy Zheng Signed-off-by: Samuel Holland Signed-off-by: Andre Przywara --- tools/imagetool.h | 1 + tools/mkimage.c | 1 + 2 files changed, 2 insertions(+) diff --git a/tools/imagetool.h b/tools/imagetool.h index 5169b0245da..05dd94d1084 100644 --- a/tools/imagetool.h +++ b/tools/imagetool.h @@ -53,6 +53,7 @@ struct image_tool_params { int pflag; int vflag; int xflag; + int Aflag; int skipcpy; int os; int arch; diff --git a/tools/mkimage.c b/tools/mkimage.c index 74bd072832c..b46216fdc59 100644 --- a/tools/mkimage.c +++ b/tools/mkimage.c @@ -172,6 +172,7 @@ static void process_args(int argc, char **argv) show_valid_options(IH_ARCH); usage("Invalid architecture"); } + params.Aflag = 1; break; case 'b': if (add_content(IH_TYPE_FLATDT, optarg)) { From 82ae151aeefed596196b6163ac23d97141931b64 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 14 Oct 2021 20:53:05 -0500 Subject: [PATCH 23/40] mkimage: sunxi_egon: refactor for multi-architecture support Refactor some functions in mkimage sunxi_egon type, in order to prepare for adding support for more CPU architectures (e.g. RISC-V). In addition, compatibility for operation w/o specified architecture is kept, in this case the architecture is assumed as ARM. Reviewed-by: Andre Przywara Signed-off-by: Icenowy Zheng Signed-off-by: Samuel Holland Signed-off-by: Andre Przywara --- tools/sunxi_egon.c | 50 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/tools/sunxi_egon.c b/tools/sunxi_egon.c index d1398c07fb0..0c4540cc20b 100644 --- a/tools/sunxi_egon.c +++ b/tools/sunxi_egon.c @@ -15,9 +15,28 @@ #define PAD_SIZE 8192 #define PAD_SIZE_MIN 512 +static int egon_get_arch(struct image_tool_params *params) +{ + if (params->Aflag) + return params->arch; + + /* For compatibility, assume ARM when no architecture specified */ + return IH_ARCH_ARM; +} + static int egon_check_params(struct image_tool_params *params) { - /* We just need a binary image file. */ + /* + * Check whether the architecture is supported. + */ + switch (egon_get_arch(params)) { + case IH_ARCH_ARM: + break; + default: + return EXIT_FAILURE; + } + + /* We need a binary image file. */ return !params->dflag; } @@ -27,9 +46,18 @@ static int egon_verify_header(unsigned char *ptr, int image_size, const struct boot_file_head *header = (void *)ptr; uint32_t length; - /* First 4 bytes must be an ARM branch instruction. */ - if ((le32_to_cpu(header->b_instruction) & 0xff000000) != 0xea000000) - return EXIT_FAILURE; + /* + * First 4 bytes must be a branch instruction of the corresponding + * architecture. + */ + switch (egon_get_arch(params)) { + case IH_ARCH_ARM: + if ((le32_to_cpu(header->b_instruction) & 0xff000000) != 0xea000000) + return EXIT_FAILURE; + break; + default: + return EXIT_FAILURE; /* Unknown architecture */ + } if (memcmp(header->magic, BOOT0_MAGIC, sizeof(header->magic))) return EXIT_FAILURE; @@ -78,9 +106,17 @@ static void egon_set_header(void *buf, struct stat *sbuf, int infd, uint32_t checksum = 0, value; int i; - /* Generate an ARM branch instruction to jump over the header. */ - value = 0xea000000 | (sizeof(struct boot_file_head) / 4 - 2); - header->b_instruction = cpu_to_le32(value); + /* + * Different architectures need different first instruction to + * branch to the body. + */ + switch (egon_get_arch(params)) { + case IH_ARCH_ARM: + /* Generate an ARM branch instruction to jump over the header. */ + value = 0xea000000 | (sizeof(struct boot_file_head) / 4 - 2); + header->b_instruction = cpu_to_le32(value); + break; + } memcpy(header->magic, BOOT0_MAGIC, sizeof(header->magic)); header->check_sum = cpu_to_le32(BROM_STAMP_VALUE); From 78ac2c0fd0662f021fc99e8ee066525ed115a8e2 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 14 Oct 2021 20:53:06 -0500 Subject: [PATCH 24/40] mkimage: sunxi_egon: add support for riscv There's now a sun20i family in sunxi, which uses RISC-V CPU. Add support for making eGON.BT0 image for RISC-V. Reviewed-by: Andre Przywara Signed-off-by: Icenowy Zheng Signed-off-by: Samuel Holland Signed-off-by: Andre Przywara --- tools/sunxi_egon.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tools/sunxi_egon.c b/tools/sunxi_egon.c index 0c4540cc20b..d45b6f5e435 100644 --- a/tools/sunxi_egon.c +++ b/tools/sunxi_egon.c @@ -31,6 +31,7 @@ static int egon_check_params(struct image_tool_params *params) */ switch (egon_get_arch(params)) { case IH_ARCH_ARM: + case IH_ARCH_RISCV: break; default: return EXIT_FAILURE; @@ -55,6 +56,10 @@ static int egon_verify_header(unsigned char *ptr, int image_size, if ((le32_to_cpu(header->b_instruction) & 0xff000000) != 0xea000000) return EXIT_FAILURE; break; + case IH_ARCH_RISCV: + if ((le32_to_cpu(header->b_instruction) & 0x00000fff) != 0x0000006f) + return EXIT_FAILURE; + break; default: return EXIT_FAILURE; /* Unknown architecture */ } @@ -116,6 +121,24 @@ static void egon_set_header(void *buf, struct stat *sbuf, int infd, value = 0xea000000 | (sizeof(struct boot_file_head) / 4 - 2); header->b_instruction = cpu_to_le32(value); break; + case IH_ARCH_RISCV: + /* + * Generate a RISC-V JAL instruction with rd=x0 + * (pseudo instruction J, jump without side effects). + * + * The following weird bit operation maps imm[20] + * to inst[31], imm[10:1] to inst[30:21], + * imm[11] to inst[20], imm[19:12] to inst[19:12], + * and imm[0] is dropped (because 1-byte RISC-V instruction + * is not allowed). + */ + value = 0x0000006f | + ((sizeof(struct boot_file_head) & 0x00100000) << 11) | + ((sizeof(struct boot_file_head) & 0x000007fe) << 20) | + ((sizeof(struct boot_file_head) & 0x00000800) << 9) | + ((sizeof(struct boot_file_head) & 0x000ff000) << 0); + header->b_instruction = cpu_to_le32(value); + break; } memcpy(header->magic, BOOT0_MAGIC, sizeof(header->magic)); From 8c621f4c3b794973a0dd76623cab6069d89fb3d7 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 14 Oct 2021 20:53:07 -0500 Subject: [PATCH 25/40] sunxi: specify architecture when generating SPL boot image As mkimage -T sunxi_egon now gains support for -A parameter, specify the architecture when generating SPL boot image for sunxi. Reviewed-by: Andre Przywara Signed-off-by: Icenowy Zheng Signed-off-by: Samuel Holland Signed-off-by: Andre Przywara --- scripts/Makefile.spl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index 83a95ee4aa2..16b5a3ddf9b 100644 --- a/scripts/Makefile.spl +++ b/scripts/Makefile.spl @@ -411,7 +411,7 @@ endif $(obj)/$(SPL_BIN).sfp: $(obj)/$(SPL_BIN).bin FORCE $(call if_changed,mkimage) -MKIMAGEFLAGS_sunxi-spl.bin = -T sunxi_egon \ +MKIMAGEFLAGS_sunxi-spl.bin = -A $(ARCH) -T sunxi_egon \ -n $(CONFIG_DEFAULT_DEVICE_TREE) OBJCOPYFLAGS_u-boot-spl-dtb.hex := -I binary -O ihex --change-address=$(CONFIG_SPL_TEXT_BASE) From e9e87ec47c756b1ee2b0a6680488d60adb2079a9 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Fri, 18 Mar 2022 00:00:43 -0500 Subject: [PATCH 26/40] tools: mkimage: Add Allwinner TOC0 support Most Allwinner sunxi SoCs have separate boot ROMs in non-secure and secure mode. The "non-secure" or "normal" boot ROM (NBROM) uses the existing sunxi_egon image type. The secure boot ROM (SBROM) uses a completely different image type, known as TOC0. A TOC0 image is composed of a header and two or more items. One item is the firmware binary. The others form a chain linking the firmware signature to the root-of-trust public key (ROTPK), which has its hash burned in the SoC's eFuses. Signatures are made using RSA-2048 + SHA256. The pseudo-ASN.1 structure is manually assembled; this is done to work around bugs/quirks in the boot ROM, which vary between SoCs. This TOC0 implementation has been verified to work with the A50, A64, H5, H6, and H616 SBROMs, and it may work with other SoCs. Signed-off-by: Samuel Holland Acked-by: Andre Przywara Signed-off-by: Andre Przywara --- MAINTAINERS | 1 + boot/image.c | 1 + include/image.h | 1 + include/sunxi_image.h | 37 ++ tools/Makefile | 7 +- tools/sunxi_toc0.c | 907 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 951 insertions(+), 3 deletions(-) create mode 100644 tools/sunxi_toc0.c diff --git a/MAINTAINERS b/MAINTAINERS index 712c2b19790..cf26d8bd3dd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -522,6 +522,7 @@ F: drivers/clk/sunxi/ F: drivers/phy/allwinner/ F: drivers/pinctrl/sunxi/ F: drivers/video/sunxi/ +F: tools/sunxi* ARM TEGRA M: Tom Warren diff --git a/boot/image.c b/boot/image.c index 121df0c8384..5dcb55ba46a 100644 --- a/boot/image.c +++ b/boot/image.c @@ -178,6 +178,7 @@ static const table_entry_t uimage_type[] = { { IH_TYPE_MTKIMAGE, "mtk_image", "MediaTek BootROM loadable Image" }, { IH_TYPE_COPRO, "copro", "Coprocessor Image"}, { IH_TYPE_SUNXI_EGON, "sunxi_egon", "Allwinner eGON Boot Image" }, + { IH_TYPE_SUNXI_TOC0, "sunxi_toc0", "Allwinner TOC0 Boot Image" }, { -1, "", "", }, }; diff --git a/include/image.h b/include/image.h index 97e5f2eb24d..720737f633c 100644 --- a/include/image.h +++ b/include/image.h @@ -227,6 +227,7 @@ enum { IH_TYPE_IMX8IMAGE, /* Freescale IMX8Boot Image */ IH_TYPE_COPRO, /* Coprocessor Image for remoteproc*/ IH_TYPE_SUNXI_EGON, /* Allwinner eGON Boot Image */ + IH_TYPE_SUNXI_TOC0, /* Allwinner TOC0 Boot Image */ IH_TYPE_COUNT, /* Number of image types */ }; diff --git a/include/sunxi_image.h b/include/sunxi_image.h index 5b2055c0af3..379ca9196e0 100644 --- a/include/sunxi_image.h +++ b/include/sunxi_image.h @@ -9,9 +9,13 @@ * * Shared between mkimage and the SPL. */ + #ifndef SUNXI_IMAGE_H #define SUNXI_IMAGE_H +#include +#include + #define BOOT0_MAGIC "eGON.BT0" #define BROM_STAMP_VALUE 0x5f0a6c39 #define SPL_SIGNATURE "SPL" /* marks "sunxi" SPL header */ @@ -79,4 +83,37 @@ struct boot_file_head { /* Compile time check to assure proper alignment of structure */ typedef char boot_file_head_not_multiple_of_32[1 - 2*(sizeof(struct boot_file_head) % 32)]; +struct __packed toc0_main_info { + uint8_t name[8]; + __le32 magic; + __le32 checksum; + __le32 serial; + __le32 status; + __le32 num_items; + __le32 length; + uint8_t platform[4]; + uint8_t reserved[8]; + uint8_t end[4]; +}; + +#define TOC0_MAIN_INFO_NAME "TOC0.GLH" +#define TOC0_MAIN_INFO_MAGIC 0x89119800 +#define TOC0_MAIN_INFO_END "MIE;" + +struct __packed toc0_item_info { + __le32 name; + __le32 offset; + __le32 length; + __le32 status; + __le32 type; + __le32 load_addr; + uint8_t reserved[4]; + uint8_t end[4]; +}; + +#define TOC0_ITEM_INFO_NAME_CERT 0x00010101 +#define TOC0_ITEM_INFO_NAME_FIRMWARE 0x00010202 +#define TOC0_ITEM_INFO_NAME_KEY 0x00010303 +#define TOC0_ITEM_INFO_END "IIE;" + #endif diff --git a/tools/Makefile b/tools/Makefile index 60231c728ce..e17271be8bc 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -94,9 +94,10 @@ ECDSA_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix lib/ecdsa/, ecdsa-libcrypto. AES_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix lib/aes/, \ aes-encrypt.o aes-decrypt.o) -# Cryptographic helpers that depend on openssl/libcrypto -LIBCRYPTO_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix lib/, \ - fdt-libcrypto.o) +# Cryptographic helpers and image types that depend on openssl/libcrypto +LIBCRYPTO_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := \ + lib/fdt-libcrypto.o \ + sunxi_toc0.o ROCKCHIP_OBS = lib/rc4.o rkcommon.o rkimage.o rksd.o rkspi.o diff --git a/tools/sunxi_toc0.c b/tools/sunxi_toc0.c new file mode 100644 index 00000000000..58a6e7a0a10 --- /dev/null +++ b/tools/sunxi_toc0.c @@ -0,0 +1,907 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 Arm Ltd. + * (C) Copyright 2020-2021 Samuel Holland + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "imagetool.h" +#include "mkimage.h" + +/* + * NAND requires 8K padding. For other devices, BROM requires only + * 512B padding, but let's use the larger padding to cover everything. + */ +#define PAD_SIZE 8192 + +#define pr_fmt(fmt) "mkimage (TOC0): %s: " fmt +#define pr_err(fmt, args...) fprintf(stderr, pr_fmt(fmt), "error", ##args) +#define pr_warn(fmt, args...) fprintf(stderr, pr_fmt(fmt), "warning", ##args) +#define pr_info(fmt, args...) fprintf(stderr, pr_fmt(fmt), "info", ##args) + +struct __packed toc0_key_item { + __le32 vendor_id; + __le32 key0_n_len; + __le32 key0_e_len; + __le32 key1_n_len; + __le32 key1_e_len; + __le32 sig_len; + uint8_t key0[512]; + uint8_t key1[512]; + uint8_t reserved[32]; + uint8_t sig[256]; +}; + +/* + * This looks somewhat like an X.509 certificate, but it is not valid BER. + * + * Some differences: + * - Some X.509 certificate fields are missing or rearranged. + * - Some sequences have the wrong tag. + * - Zero-length sequences are accepted. + * - Large strings and integers must be an even number of bytes long. + * - Positive integers are not zero-extended to maintain their sign. + * + * See https://linux-sunxi.org/TOC0 for more information. + */ +struct __packed toc0_small_tag { + uint8_t tag; + uint8_t length; +}; + +typedef struct toc0_small_tag toc0_small_int; +typedef struct toc0_small_tag toc0_small_oct; +typedef struct toc0_small_tag toc0_small_seq; +typedef struct toc0_small_tag toc0_small_exp; + +#define TOC0_SMALL_INT(len) { 0x02, (len) } +#define TOC0_SMALL_SEQ(len) { 0x30, (len) } +#define TOC0_SMALL_EXP(tag, len) { 0xa0 | (tag), len } + +struct __packed toc0_large_tag { + uint8_t tag; + uint8_t prefix; + uint8_t length_hi; + uint8_t length_lo; +}; + +typedef struct toc0_large_tag toc0_large_int; +typedef struct toc0_large_tag toc0_large_bit; +typedef struct toc0_large_tag toc0_large_seq; + +#define TOC0_LARGE_INT(len) { 0x02, 0x82, (len) >> 8, (len) & 0xff } +#define TOC0_LARGE_BIT(len) { 0x03, 0x82, (len) >> 8, (len) & 0xff } +#define TOC0_LARGE_SEQ(len) { 0x30, 0x82, (len) >> 8, (len) & 0xff } + +struct __packed toc0_cert_item { + toc0_large_seq tag_totalSequence; + struct __packed toc0_totalSequence { + toc0_large_seq tag_mainSequence; + struct __packed toc0_mainSequence { + toc0_small_exp tag_explicit0; + struct __packed toc0_explicit0 { + toc0_small_int tag_version; + uint8_t version; + } explicit0; + toc0_small_int tag_serialNumber; + uint8_t serialNumber; + toc0_small_seq tag_signature; + toc0_small_seq tag_issuer; + toc0_small_seq tag_validity; + toc0_small_seq tag_subject; + toc0_large_seq tag_subjectPublicKeyInfo; + struct __packed toc0_subjectPublicKeyInfo { + toc0_small_seq tag_algorithm; + toc0_large_seq tag_publicKey; + struct __packed toc0_publicKey { + toc0_large_int tag_n; + uint8_t n[256]; + toc0_small_int tag_e; + uint8_t e[3]; + } publicKey; + } subjectPublicKeyInfo; + toc0_small_exp tag_explicit3; + struct __packed toc0_explicit3 { + toc0_small_seq tag_extension; + struct __packed toc0_extension { + toc0_small_int tag_digest; + uint8_t digest[32]; + } extension; + } explicit3; + } mainSequence; + toc0_large_bit tag_sigSequence; + struct __packed toc0_sigSequence { + toc0_small_seq tag_algorithm; + toc0_large_bit tag_signature; + uint8_t signature[256]; + } sigSequence; + } totalSequence; +}; + +#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) + +static const struct toc0_cert_item cert_item_template = { + TOC0_LARGE_SEQ(sizeof(struct toc0_totalSequence)), + { + TOC0_LARGE_SEQ(sizeof(struct toc0_mainSequence)), + { + TOC0_SMALL_EXP(0, sizeof(struct toc0_explicit0)), + { + TOC0_SMALL_INT(sizeof_field(struct toc0_explicit0, version)), + 0, + }, + TOC0_SMALL_INT(sizeof_field(struct toc0_mainSequence, serialNumber)), + 0, + TOC0_SMALL_SEQ(0), + TOC0_SMALL_SEQ(0), + TOC0_SMALL_SEQ(0), + TOC0_SMALL_SEQ(0), + TOC0_LARGE_SEQ(sizeof(struct toc0_subjectPublicKeyInfo)), + { + TOC0_SMALL_SEQ(0), + TOC0_LARGE_SEQ(sizeof(struct toc0_publicKey)), + { + TOC0_LARGE_INT(sizeof_field(struct toc0_publicKey, n)), + {}, + TOC0_SMALL_INT(sizeof_field(struct toc0_publicKey, e)), + {}, + }, + }, + TOC0_SMALL_EXP(3, sizeof(struct toc0_explicit3)), + { + TOC0_SMALL_SEQ(sizeof(struct toc0_extension)), + { + TOC0_SMALL_INT(sizeof_field(struct toc0_extension, digest)), + {}, + }, + }, + }, + TOC0_LARGE_BIT(sizeof(struct toc0_sigSequence)), + { + TOC0_SMALL_SEQ(0), + TOC0_LARGE_BIT(sizeof_field(struct toc0_sigSequence, signature)), + {}, + }, + }, +}; + +#define TOC0_DEFAULT_NUM_ITEMS 3 +#define TOC0_DEFAULT_HEADER_LEN \ + ALIGN( \ + sizeof(struct toc0_main_info) + \ + sizeof(struct toc0_item_info) * TOC0_DEFAULT_NUM_ITEMS + \ + sizeof(struct toc0_cert_item) + \ + sizeof(struct toc0_key_item), \ + 32) + +static char *fw_key_file = "fw_key.pem"; +static char *key_item_file = "key_item.bin"; +static char *root_key_file = "root_key.pem"; + +/* + * Create a key item in @buf, containing the public keys @root_key and @fw_key, + * and signed by the RSA key @root_key. + */ +static int toc0_create_key_item(uint8_t *buf, uint32_t *len, + RSA *root_key, RSA *fw_key) +{ + struct toc0_key_item *key_item = (void *)buf; + uint8_t digest[SHA256_DIGEST_LENGTH]; + int ret = EXIT_FAILURE; + unsigned int sig_len; + int n_len, e_len; + + /* Store key 0. */ + n_len = BN_bn2bin(RSA_get0_n(root_key), key_item->key0); + e_len = BN_bn2bin(RSA_get0_e(root_key), key_item->key0 + n_len); + if (n_len + e_len > sizeof(key_item->key0)) { + pr_err("Root key is too big for key item\n"); + goto err; + } + key_item->key0_n_len = cpu_to_le32(n_len); + key_item->key0_e_len = cpu_to_le32(e_len); + + /* Store key 1. */ + n_len = BN_bn2bin(RSA_get0_n(fw_key), key_item->key1); + e_len = BN_bn2bin(RSA_get0_e(fw_key), key_item->key1 + n_len); + if (n_len + e_len > sizeof(key_item->key1)) { + pr_err("Firmware key is too big for key item\n"); + goto err; + } + key_item->key1_n_len = cpu_to_le32(n_len); + key_item->key1_e_len = cpu_to_le32(e_len); + + /* Sign the key item. */ + key_item->sig_len = cpu_to_le32(RSA_size(root_key)); + SHA256(buf, key_item->sig - buf, digest); + if (!RSA_sign(NID_sha256, digest, sizeof(digest), + key_item->sig, &sig_len, root_key)) { + pr_err("Failed to sign key item\n"); + goto err; + } + if (sig_len != sizeof(key_item->sig)) { + pr_err("Bad key item signature length\n"); + goto err; + } + + *len = sizeof(*key_item); + ret = EXIT_SUCCESS; + +err: + return ret; +} + +/* + * Verify the key item in @buf, containing two public keys @key0 and @key1, + * and signed by the RSA key @key0. If @root_key is provided, only signatures + * by that key will be accepted. @key1 is returned in @key. + */ +static int toc0_verify_key_item(const uint8_t *buf, uint32_t len, + RSA *root_key, RSA **fw_key) +{ + struct toc0_key_item *key_item = (void *)buf; + uint8_t digest[SHA256_DIGEST_LENGTH]; + int ret = EXIT_FAILURE; + int n_len, e_len; + RSA *key0 = NULL; + RSA *key1 = NULL; + BIGNUM *n, *e; + + if (len < sizeof(*key_item)) + goto err; + + /* Load key 0. */ + n_len = le32_to_cpu(key_item->key0_n_len); + e_len = le32_to_cpu(key_item->key0_e_len); + if (n_len + e_len > sizeof(key_item->key0)) { + pr_err("Bad root key size in key item\n"); + goto err; + } + n = BN_bin2bn(key_item->key0, n_len, NULL); + e = BN_bin2bn(key_item->key0 + n_len, e_len, NULL); + key0 = RSA_new(); + if (!key0) + goto err; + if (!RSA_set0_key(key0, n, e, NULL)) + goto err; + + /* If a root key was provided, compare it to key 0. */ + if (root_key && (BN_cmp(n, RSA_get0_n(root_key)) || + BN_cmp(e, RSA_get0_e(root_key)))) { + pr_err("Wrong root key in key item\n"); + goto err; + } + + /* Verify the key item signature. */ + SHA256(buf, key_item->sig - buf, digest); + if (!RSA_verify(NID_sha256, digest, sizeof(digest), + key_item->sig, le32_to_cpu(key_item->sig_len), key0)) { + pr_err("Bad key item signature\n"); + goto err; + } + + if (fw_key) { + /* Load key 1. */ + n_len = le32_to_cpu(key_item->key1_n_len); + e_len = le32_to_cpu(key_item->key1_e_len); + if (n_len + e_len > sizeof(key_item->key1)) { + pr_err("Bad firmware key size in key item\n"); + goto err; + } + n = BN_bin2bn(key_item->key1, n_len, NULL); + e = BN_bin2bn(key_item->key1 + n_len, e_len, NULL); + key1 = RSA_new(); + if (!key1) + goto err; + if (!RSA_set0_key(key1, n, e, NULL)) + goto err; + + if (*fw_key) { + /* If a FW key was provided, compare it to key 1. */ + if (BN_cmp(n, RSA_get0_n(*fw_key)) || + BN_cmp(e, RSA_get0_e(*fw_key))) { + pr_err("Wrong firmware key in key item\n"); + goto err; + } + } else { + /* Otherwise, send key1 back to the caller. */ + *fw_key = key1; + key1 = NULL; + } + } + + ret = EXIT_SUCCESS; + +err: + RSA_free(key0); + RSA_free(key1); + + return ret; +} + +/* + * Create a certificate in @buf, describing the firmware with SHA256 digest + * @digest, and signed by the RSA key @fw_key. + */ +static int toc0_create_cert_item(uint8_t *buf, uint32_t *len, RSA *fw_key, + uint8_t digest[static SHA256_DIGEST_LENGTH]) +{ + struct toc0_cert_item *cert_item = (void *)buf; + uint8_t cert_digest[SHA256_DIGEST_LENGTH]; + struct toc0_totalSequence *totalSequence; + struct toc0_sigSequence *sigSequence; + struct toc0_extension *extension; + struct toc0_publicKey *publicKey; + int ret = EXIT_FAILURE; + unsigned int sig_len; + + memcpy(cert_item, &cert_item_template, sizeof(*cert_item)); + *len = sizeof(*cert_item); + + /* + * Fill in the public key. + * + * Only 2048-bit RSA keys are supported. Since this uses a fixed-size + * structure, it may fail for non-standard exponents. + */ + totalSequence = &cert_item->totalSequence; + publicKey = &totalSequence->mainSequence.subjectPublicKeyInfo.publicKey; + if (BN_bn2binpad(RSA_get0_n(fw_key), publicKey->n, sizeof(publicKey->n)) < 0 || + BN_bn2binpad(RSA_get0_e(fw_key), publicKey->e, sizeof(publicKey->e)) < 0) { + pr_err("Firmware key is too big for certificate\n"); + goto err; + } + + /* Fill in the firmware digest. */ + extension = &totalSequence->mainSequence.explicit3.extension; + memcpy(&extension->digest, digest, SHA256_DIGEST_LENGTH); + + /* + * Sign the certificate. + * + * In older SBROM versions (and by default in newer versions), + * the last 4 bytes of the certificate are not signed. + * + * (The buffer passed to SHA256 starts at tag_mainSequence, but + * the buffer size does not include the length of that tag.) + */ + SHA256((uint8_t *)totalSequence, sizeof(struct toc0_mainSequence), cert_digest); + sigSequence = &totalSequence->sigSequence; + if (!RSA_sign(NID_sha256, cert_digest, SHA256_DIGEST_LENGTH, + sigSequence->signature, &sig_len, fw_key)) { + pr_err("Failed to sign certificate\n"); + goto err; + } + if (sig_len != sizeof(sigSequence->signature)) { + pr_err("Bad certificate signature length\n"); + goto err; + } + + ret = EXIT_SUCCESS; + +err: + return ret; +} + +/* + * Verify the certificate in @buf, describing the firmware with SHA256 digest + * @digest, and signed by the RSA key contained within. If @fw_key is provided, + * only that key will be accepted. + * + * This function is only expected to work with images created by mkimage. + */ +static int toc0_verify_cert_item(const uint8_t *buf, uint32_t len, RSA *fw_key, + uint8_t digest[static SHA256_DIGEST_LENGTH]) +{ + const struct toc0_cert_item *cert_item = (const void *)buf; + uint8_t cert_digest[SHA256_DIGEST_LENGTH]; + const struct toc0_totalSequence *totalSequence; + const struct toc0_sigSequence *sigSequence; + const struct toc0_extension *extension; + const struct toc0_publicKey *publicKey; + int ret = EXIT_FAILURE; + RSA *key = NULL; + BIGNUM *n, *e; + + /* Extract the public key from the certificate. */ + totalSequence = &cert_item->totalSequence; + publicKey = &totalSequence->mainSequence.subjectPublicKeyInfo.publicKey; + n = BN_bin2bn(publicKey->n, sizeof(publicKey->n), NULL); + e = BN_bin2bn(publicKey->e, sizeof(publicKey->e), NULL); + key = RSA_new(); + if (!key) + goto err; + if (!RSA_set0_key(key, n, e, NULL)) + goto err; + + /* If a key was provided, compare it to the embedded key. */ + if (fw_key && (BN_cmp(RSA_get0_n(key), RSA_get0_n(fw_key)) || + BN_cmp(RSA_get0_e(key), RSA_get0_e(fw_key)))) { + pr_err("Wrong firmware key in certificate\n"); + goto err; + } + + /* If a digest was provided, compare it to the embedded digest. */ + extension = &totalSequence->mainSequence.explicit3.extension; + if (digest && memcmp(&extension->digest, digest, SHA256_DIGEST_LENGTH)) { + pr_err("Wrong firmware digest in certificate\n"); + goto err; + } + + /* Verify the certificate's signature. See the comment above. */ + SHA256((uint8_t *)totalSequence, sizeof(struct toc0_mainSequence), cert_digest); + sigSequence = &totalSequence->sigSequence; + if (!RSA_verify(NID_sha256, cert_digest, SHA256_DIGEST_LENGTH, + sigSequence->signature, + sizeof(sigSequence->signature), key)) { + pr_err("Bad certificate signature\n"); + goto err; + } + + ret = EXIT_SUCCESS; + +err: + RSA_free(key); + + return ret; +} + +/* + * Always create a TOC0 containing 3 items. The extra item will be ignored on + * SoCs which do not support it. + */ +static int toc0_create(uint8_t *buf, uint32_t len, RSA *root_key, RSA *fw_key, + uint8_t *key_item, uint32_t key_item_len, + uint8_t *fw_item, uint32_t fw_item_len, uint32_t fw_addr) +{ + struct toc0_main_info *main_info = (void *)buf; + struct toc0_item_info *item_info = (void *)(main_info + 1); + uint8_t digest[SHA256_DIGEST_LENGTH]; + uint32_t *buf32 = (void *)buf; + RSA *orig_fw_key = fw_key; + int ret = EXIT_FAILURE; + uint32_t checksum = 0; + uint32_t item_offset; + uint32_t item_length; + int i; + + /* Hash the firmware for inclusion in the certificate. */ + SHA256(fw_item, fw_item_len, digest); + + /* Create the main TOC0 header, containing three items. */ + memcpy(main_info->name, TOC0_MAIN_INFO_NAME, sizeof(main_info->name)); + main_info->magic = cpu_to_le32(TOC0_MAIN_INFO_MAGIC); + main_info->checksum = cpu_to_le32(BROM_STAMP_VALUE); + main_info->num_items = cpu_to_le32(TOC0_DEFAULT_NUM_ITEMS); + memcpy(main_info->end, TOC0_MAIN_INFO_END, sizeof(main_info->end)); + + /* The first item links the ROTPK to the signing key. */ + item_offset = sizeof(*main_info) + + sizeof(*item_info) * TOC0_DEFAULT_NUM_ITEMS; + /* Using an existing key item avoids needing the root private key. */ + if (key_item) { + item_length = sizeof(*key_item); + if (toc0_verify_key_item(key_item, item_length, + root_key, &fw_key)) + goto err; + memcpy(buf + item_offset, key_item, item_length); + } else if (toc0_create_key_item(buf + item_offset, &item_length, + root_key, fw_key)) { + goto err; + } + + item_info->name = cpu_to_le32(TOC0_ITEM_INFO_NAME_KEY); + item_info->offset = cpu_to_le32(item_offset); + item_info->length = cpu_to_le32(item_length); + memcpy(item_info->end, TOC0_ITEM_INFO_END, sizeof(item_info->end)); + + /* The second item contains a certificate signed by the firmware key. */ + item_offset = item_offset + item_length; + if (toc0_create_cert_item(buf + item_offset, &item_length, + fw_key, digest)) + goto err; + + item_info++; + item_info->name = cpu_to_le32(TOC0_ITEM_INFO_NAME_CERT); + item_info->offset = cpu_to_le32(item_offset); + item_info->length = cpu_to_le32(item_length); + memcpy(item_info->end, TOC0_ITEM_INFO_END, sizeof(item_info->end)); + + /* The third item contains the actual boot code. */ + item_offset = ALIGN(item_offset + item_length, 32); + item_length = fw_item_len; + if (buf + item_offset != fw_item) + memmove(buf + item_offset, fw_item, item_length); + + item_info++; + item_info->name = cpu_to_le32(TOC0_ITEM_INFO_NAME_FIRMWARE); + item_info->offset = cpu_to_le32(item_offset); + item_info->length = cpu_to_le32(item_length); + item_info->load_addr = cpu_to_le32(fw_addr); + memcpy(item_info->end, TOC0_ITEM_INFO_END, sizeof(item_info->end)); + + /* Pad to the required block size with 0xff to be flash-friendly. */ + item_offset = item_offset + item_length; + item_length = ALIGN(item_offset, PAD_SIZE) - item_offset; + memset(buf + item_offset, 0xff, item_length); + + /* Fill in the total padded file length. */ + item_offset = item_offset + item_length; + main_info->length = cpu_to_le32(item_offset); + + /* Verify enough space was provided when creating the image. */ + assert(len >= item_offset); + + /* Calculate the checksum. Yes, it's that simple. */ + for (i = 0; i < item_offset / 4; ++i) + checksum += le32_to_cpu(buf32[i]); + main_info->checksum = cpu_to_le32(checksum); + + ret = EXIT_SUCCESS; + +err: + if (fw_key != orig_fw_key) + RSA_free(fw_key); + + return ret; +} + +static const struct toc0_item_info * +toc0_find_item(const struct toc0_main_info *main_info, uint32_t name, + uint32_t *offset, uint32_t *length) +{ + const struct toc0_item_info *item_info = (void *)(main_info + 1); + uint32_t item_offset, item_length; + uint32_t num_items, main_length; + int i; + + num_items = le32_to_cpu(main_info->num_items); + main_length = le32_to_cpu(main_info->length); + + for (i = 0; i < num_items; ++i, ++item_info) { + if (le32_to_cpu(item_info->name) != name) + continue; + + item_offset = le32_to_cpu(item_info->offset); + item_length = le32_to_cpu(item_info->length); + + if (item_offset > main_length || + item_length > main_length - item_offset) + continue; + + *offset = item_offset; + *length = item_length; + + return item_info; + } + + return NULL; +} + +static int toc0_verify(const uint8_t *buf, uint32_t len, RSA *root_key) +{ + const struct toc0_main_info *main_info = (void *)buf; + const struct toc0_item_info *item_info; + uint8_t digest[SHA256_DIGEST_LENGTH]; + uint32_t main_length = le32_to_cpu(main_info->length); + uint32_t checksum = BROM_STAMP_VALUE; + uint32_t *buf32 = (void *)buf; + uint32_t length, offset; + int ret = EXIT_FAILURE; + RSA *fw_key = NULL; + int i; + + if (len < main_length) + goto err; + + /* Verify the main header. */ + if (memcmp(main_info->name, TOC0_MAIN_INFO_NAME, sizeof(main_info->name))) + goto err; + if (le32_to_cpu(main_info->magic) != TOC0_MAIN_INFO_MAGIC) + goto err; + /* Verify the checksum without modifying the buffer. */ + for (i = 0; i < main_length / 4; ++i) + checksum += le32_to_cpu(buf32[i]); + if (checksum != 2 * le32_to_cpu(main_info->checksum)) + goto err; + /* The length must be at least 512 byte aligned. */ + if (main_length % 512) + goto err; + if (memcmp(main_info->end, TOC0_MAIN_INFO_END, sizeof(main_info->end))) + goto err; + + /* Verify the key item if present (it is optional). */ + item_info = toc0_find_item(main_info, TOC0_ITEM_INFO_NAME_KEY, + &offset, &length); + if (!item_info) + fw_key = root_key; + else if (toc0_verify_key_item(buf + offset, length, root_key, &fw_key)) + goto err; + + /* Hash the firmware to compare with the certificate. */ + item_info = toc0_find_item(main_info, TOC0_ITEM_INFO_NAME_FIRMWARE, + &offset, &length); + if (!item_info) { + pr_err("Missing firmware item\n"); + goto err; + } + SHA256(buf + offset, length, digest); + + /* Verify the certificate item. */ + item_info = toc0_find_item(main_info, TOC0_ITEM_INFO_NAME_CERT, + &offset, &length); + if (!item_info) { + pr_err("Missing certificate item\n"); + goto err; + } + if (toc0_verify_cert_item(buf + offset, length, fw_key, digest)) + goto err; + + ret = EXIT_SUCCESS; + +err: + if (fw_key != root_key) + RSA_free(fw_key); + + return ret; +} + +static int toc0_check_params(struct image_tool_params *params) +{ + if (!params->dflag) + return -EINVAL; + + /* + * If a key directory was provided, look for key files there. + * Otherwise, look for them in the current directory. The key files are + * the "quoted" terms in the description below. + * + * A summary of the chain of trust on most SoCs: + * 1) eFuse contains a SHA256 digest of the public "root key". + * 2) Private "root key" signs the certificate item (generated here). + * 3) Certificate item contains a SHA256 digest of the firmware item. + * + * A summary of the chain of trust on the H6 (by default; a bit in the + * BROM_CONFIG eFuse makes it work like above): + * 1) eFuse contains a SHA256 digest of the public "root key". + * 2) Private "root key" signs the "key item" (generated here). + * 3) "Key item" contains the public "root key" and public "fw key". + * 4) Private "fw key" signs the certificate item (generated here). + * 5) Certificate item contains a SHA256 digest of the firmware item. + * + * This means there are three valid ways to generate a TOC0: + * 1) Provide the private "root key" only. This works everywhere. + * For H6, the "root key" will also be used as the "fw key". + * 2) FOR H6 ONLY: Provide the private "root key" and a separate + * private "fw key". + * 3) FOR H6 ONLY: Provide the private "fw key" and a pre-existing + * "key item" containing the corresponding public "fw key". + * In this case, the private "root key" can be kept offline. The + * "key item" can be extracted from a TOC0 image generated using + * method #2 above. + * + * Note that until the ROTPK_HASH eFuse is programmed, any "root key" + * will be accepted by the BROM. + */ + if (params->keydir) { + if (asprintf(&fw_key_file, "%s/%s", params->keydir, fw_key_file) < 0) + return -ENOMEM; + if (asprintf(&key_item_file, "%s/%s", params->keydir, key_item_file) < 0) + return -ENOMEM; + if (asprintf(&root_key_file, "%s/%s", params->keydir, root_key_file) < 0) + return -ENOMEM; + } + + return 0; +} + +static int toc0_verify_header(unsigned char *buf, int image_size, + struct image_tool_params *params) +{ + int ret = EXIT_FAILURE; + RSA *root_key = NULL; + FILE *fp; + + /* A root public key is optional. */ + fp = fopen(root_key_file, "rb"); + if (fp) { + pr_info("Verifying image with existing root key\n"); + root_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); + if (!root_key) + root_key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL); + fclose(fp); + if (!root_key) { + pr_err("Failed to read public key from '%s'\n", + root_key_file); + goto err; + } + } + + ret = toc0_verify(buf, image_size, root_key); + +err: + RSA_free(root_key); + + return ret; +} + +static const char *toc0_item_name(uint32_t name) +{ + if (name == TOC0_ITEM_INFO_NAME_CERT) + return "Certificate"; + if (name == TOC0_ITEM_INFO_NAME_FIRMWARE) + return "Firmware"; + if (name == TOC0_ITEM_INFO_NAME_KEY) + return "Key"; + return "(unknown)"; +} + +static void toc0_print_header(const void *buf) +{ + const struct toc0_main_info *main_info = buf; + const struct toc0_item_info *item_info = (void *)(main_info + 1); + uint32_t head_length, main_length, num_items; + uint32_t item_offset, item_length, item_name; + int load_addr = -1; + int i; + + num_items = le32_to_cpu(main_info->num_items); + head_length = sizeof(*main_info) + num_items * sizeof(*item_info); + main_length = le32_to_cpu(main_info->length); + + printf("Allwinner TOC0 Image\n" + "Size: %d bytes\n" + "Contents: %d items\n" + " 00000000:%08x Headers\n", + main_length, num_items, head_length); + + for (i = 0; i < num_items; ++i, ++item_info) { + item_offset = le32_to_cpu(item_info->offset); + item_length = le32_to_cpu(item_info->length); + item_name = le32_to_cpu(item_info->name); + + if (item_name == TOC0_ITEM_INFO_NAME_FIRMWARE) + load_addr = le32_to_cpu(item_info->load_addr); + + printf(" %08x:%08x %s\n", + item_offset, item_length, + toc0_item_name(item_name)); + } + + if (num_items && item_offset + item_length < main_length) { + item_offset = item_offset + item_length; + item_length = main_length - item_offset; + + printf(" %08x:%08x Padding\n", + item_offset, item_length); + } + + if (load_addr != -1) + printf("Load address: 0x%08x\n", load_addr); +} + +static void toc0_set_header(void *buf, struct stat *sbuf, int ifd, + struct image_tool_params *params) +{ + uint32_t key_item_len = 0; + uint8_t *key_item = NULL; + int ret = EXIT_FAILURE; + RSA *root_key = NULL; + RSA *fw_key = NULL; + FILE *fp; + + /* Either a key item or the root private key is required. */ + fp = fopen(key_item_file, "rb"); + if (fp) { + pr_info("Creating image using existing key item\n"); + key_item_len = sizeof(struct toc0_key_item); + key_item = OPENSSL_malloc(key_item_len); + if (!key_item || fread(key_item, key_item_len, 1, fp) != 1) { + pr_err("Failed to read key item from '%s'\n", + root_key_file); + goto err; + } + fclose(fp); + fp = NULL; + } + + fp = fopen(root_key_file, "rb"); + if (fp) { + root_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); + if (!root_key) + root_key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL); + fclose(fp); + fp = NULL; + } + + /* When using an existing key item, the root key is optional. */ + if (!key_item && (!root_key || !RSA_get0_d(root_key))) { + pr_err("Failed to read private key from '%s'\n", + root_key_file); + pr_info("Try 'openssl genrsa -out root_key.pem'\n"); + goto err; + } + + /* The certificate/firmware private key is always required. */ + fp = fopen(fw_key_file, "rb"); + if (fp) { + fw_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); + fclose(fp); + fp = NULL; + } + if (!fw_key) { + /* If the root key is a private key, it can be used instead. */ + if (root_key && RSA_get0_d(root_key)) { + pr_info("Using root key as firmware key\n"); + fw_key = root_key; + } else { + pr_err("Failed to read private key from '%s'\n", + fw_key_file); + goto err; + } + } + + /* Warn about potential compatibility issues. */ + if (key_item || fw_key != root_key) + pr_warn("Only H6 supports separate root and firmware keys\n"); + + ret = toc0_create(buf, params->file_size, root_key, fw_key, + key_item, key_item_len, + buf + TOC0_DEFAULT_HEADER_LEN, + params->orig_file_size, params->addr); + +err: + OPENSSL_free(key_item); + OPENSSL_free(root_key); + if (fw_key != root_key) + OPENSSL_free(fw_key); + if (fp) + fclose(fp); + + if (ret != EXIT_SUCCESS) + exit(ret); +} + +static int toc0_check_image_type(uint8_t type) +{ + return type == IH_TYPE_SUNXI_TOC0 ? 0 : 1; +} + +static int toc0_vrec_header(struct image_tool_params *params, + struct image_type_params *tparams) +{ + tparams->hdr = calloc(tparams->header_size, 1); + + /* Save off the unpadded data size for SHA256 calculation. */ + params->orig_file_size = params->file_size - TOC0_DEFAULT_HEADER_LEN; + + /* Return padding to 8K blocks. */ + return ALIGN(params->file_size, PAD_SIZE) - params->file_size; +} + +U_BOOT_IMAGE_TYPE( + sunxi_toc0, + "Allwinner TOC0 Boot Image support", + TOC0_DEFAULT_HEADER_LEN, + NULL, + toc0_check_params, + toc0_verify_header, + toc0_print_header, + toc0_set_header, + NULL, + toc0_check_image_type, + NULL, + toc0_vrec_header +); From 44de13d9459afedd85334d7ba83c13451af0977d Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Fri, 18 Mar 2022 00:00:44 -0500 Subject: [PATCH 27/40] sunxi: Support SPL in both eGON and TOC0 images SPL uses the image header to detect the boot device and to find the offset of the next U-Boot stage. Since this information is stored differently in the eGON and TOC0 image headers, add code to find the correct value based on the image type currently in use. Signed-off-by: Samuel Holland Signed-off-by: Andre Przywara --- arch/arm/include/asm/arch-sunxi/spl.h | 3 +-- arch/arm/mach-sunxi/board.c | 39 ++++++++++++++++++++------- arch/arm/mach-sunxi/spl_spi_sunxi.c | 4 +-- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h index b543d24e5a0..14944a20eac 100644 --- a/arch/arm/include/asm/arch-sunxi/spl.h +++ b/arch/arm/include/asm/arch-sunxi/spl.h @@ -28,8 +28,7 @@ #define SUNIV_BOOTED_FROM_SPI 0xffff4130 #define SUNIV_BOOTED_FROM_MMC1 0xffff4150 -#define is_boot0_magic(addr) (memcmp((void *)(addr), BOOT0_MAGIC, 8) == 0) - uint32_t sunxi_get_boot_device(void); +uint32_t sunxi_get_spl_size(void); #endif diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index 9a7673d82dc..ffe578d5c3a 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -213,8 +213,21 @@ static int suniv_get_boot_source(void) return SUNXI_INVALID_BOOT_SOURCE; } +static int sunxi_egon_valid(struct boot_file_head *egon_head) +{ + return !memcmp(egon_head->magic, BOOT0_MAGIC, 8); /* eGON.BT0 */ +} + +static int sunxi_toc0_valid(struct toc0_main_info *toc0_info) +{ + return !memcmp(toc0_info->name, TOC0_MAIN_INFO_NAME, 8); /* TOC0.GLH */ +} + static int sunxi_get_boot_source(void) { + struct boot_file_head *egon_head = (void *)SPL_ADDR; + struct toc0_main_info *toc0_info = (void *)SPL_ADDR; + /* * On the ARMv5 SoCs, the SPL header in SRAM is overwritten by the * exception vectors in U-Boot proper, so we won't find any @@ -226,13 +239,15 @@ static int sunxi_get_boot_source(void) !IS_ENABLED(CONFIG_SPL_BUILD)) return SUNXI_BOOTED_FROM_MMC0; - if (!is_boot0_magic(SPL_ADDR + 4)) /* eGON.BT0 */ - return SUNXI_INVALID_BOOT_SOURCE; - if (IS_ENABLED(CONFIG_MACH_SUNIV)) return suniv_get_boot_source(); - else - return readb(SPL_ADDR + 0x28); + if (sunxi_egon_valid(egon_head)) + return readb(&egon_head->boot_media); + if (sunxi_toc0_valid(toc0_info)) + return readb(&toc0_info->platform[0]); + + /* Not a valid image, so we must have been booted via FEL. */ + return SUNXI_INVALID_BOOT_SOURCE; } /* The sunxi internal brom will try to loader external bootloader @@ -278,12 +293,18 @@ uint32_t sunxi_get_boot_device(void) } #ifdef CONFIG_SPL_BUILD -static u32 sunxi_get_spl_size(void) +uint32_t sunxi_get_spl_size(void) { - if (!is_boot0_magic(SPL_ADDR + 4)) /* eGON.BT0 */ - return 0; + struct boot_file_head *egon_head = (void *)SPL_ADDR; + struct toc0_main_info *toc0_info = (void *)SPL_ADDR; - return readl(SPL_ADDR + 0x10); + if (sunxi_egon_valid(egon_head)) + return readl(&egon_head->length); + if (sunxi_toc0_valid(toc0_info)) + return readl(&toc0_info->length); + + /* Not a valid image, so use the default U-Boot offset. */ + return 0; } /* diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c index 734c165e5d2..de9aa68c4ac 100644 --- a/arch/arm/mach-sunxi/spl_spi_sunxi.c +++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c @@ -337,9 +337,9 @@ static int spl_spi_load_image(struct spl_image_info *spl_image, int ret = 0; struct image_header *header; header = (struct image_header *)(CONFIG_SYS_TEXT_BASE); - int load_offset = readl(SPL_ADDR + 0x10); + uint32_t load_offset = sunxi_get_spl_size(); - load_offset = max(load_offset, CONFIG_SYS_SPI_U_BOOT_OFFS); + load_offset = max_t(uint32_t, load_offset, CONFIG_SYS_SPI_U_BOOT_OFFS); spi0_init(); From a0ca51f70b7559733c65cef1069f1b39aa410a0f Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Fri, 18 Mar 2022 00:00:45 -0500 Subject: [PATCH 28/40] sunxi: Support building a SPL as a TOC0 image Now that mkimage can generate TOC0 images, and the SPL can interpret them, hook up the build infrastructure so the user can choose which image type to build. Since the absolute load address is stored in the TOC0 header, that information must be passed to mkimage. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- arch/arm/mach-sunxi/Kconfig | 2 ++ board/sunxi/Kconfig | 24 ++++++++++++++++++++++++ scripts/Makefile.spl | 5 ++++- 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 board/sunxi/Kconfig diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index e5ed1d97e89..1f43b253248 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -1047,6 +1047,8 @@ config BLUETOOTH_DT_DEVICE_FIXUP The used address is "bdaddr" if set, and "ethaddr" with the LSB flipped elsewise. +source "board/sunxi/Kconfig" + endif config CHIP_DIP_SCAN diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig new file mode 100644 index 00000000000..084a8b0c6ca --- /dev/null +++ b/board/sunxi/Kconfig @@ -0,0 +1,24 @@ +choice + prompt "SPL Image Type" + default SPL_IMAGE_TYPE_SUNXI_EGON + +config SPL_IMAGE_TYPE_SUNXI_EGON + bool "eGON (normal)" + help + Select this option to embed the SPL binary in an eGON.BT0 image, + which is compatible with the normal boot ROM (NBROM). + + This is usually the correct option to choose. + +config SPL_IMAGE_TYPE_SUNXI_TOC0 + bool "TOC0 (secure)" + help + Select this option to embed the SPL binary in a TOC0 image, + which is compatible with the secure boot ROM (SBROM). + +endchoice + +config SPL_IMAGE_TYPE + string + default "sunxi_egon" if SPL_IMAGE_TYPE_SUNXI_EGON + default "sunxi_toc0" if SPL_IMAGE_TYPE_SUNXI_TOC0 diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index 16b5a3ddf9b..6ad82cecfb7 100644 --- a/scripts/Makefile.spl +++ b/scripts/Makefile.spl @@ -411,7 +411,10 @@ endif $(obj)/$(SPL_BIN).sfp: $(obj)/$(SPL_BIN).bin FORCE $(call if_changed,mkimage) -MKIMAGEFLAGS_sunxi-spl.bin = -A $(ARCH) -T sunxi_egon \ +MKIMAGEFLAGS_sunxi-spl.bin = \ + -A $(ARCH) \ + -T $(CONFIG_SPL_IMAGE_TYPE) \ + -a $(CONFIG_SPL_TEXT_BASE) \ -n $(CONFIG_DEFAULT_DEVICE_TREE) OBJCOPYFLAGS_u-boot-spl-dtb.hex := -I binary -O ihex --change-address=$(CONFIG_SPL_TEXT_BASE) From 48457f7ab031884d749e84440f4e5ae798e77c39 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Thu, 17 Mar 2022 23:52:33 -0500 Subject: [PATCH 29/40] i2c: sun6i_p2wi: Initialize chips in .child_pre_probe Chips attached to the P2WI bus require an initialization command before they can be used. (Specifically, this switches the chip from I2C mode to P2WI mode.) The driver does this in its .probe_chip hook, under the assumption that .probe_chip is called during child probe. This is not the case; .probe_chip is only called by dm_i2c_probe, which is intended for use by board-level code, not for chips with OF nodes. Since this initialization command must be run before a child chip can be used, do it before probing each child. Signed-off-by: Samuel Holland Acked-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/i2c/sun6i_p2wi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/sun6i_p2wi.c b/drivers/i2c/sun6i_p2wi.c index 73b808b09bf..064d82a6d1f 100644 --- a/drivers/i2c/sun6i_p2wi.c +++ b/drivers/i2c/sun6i_p2wi.c @@ -191,11 +191,12 @@ static int sun6i_p2wi_probe(struct udevice *bus) static int sun6i_p2wi_child_pre_probe(struct udevice *child) { struct dm_i2c_chip *chip = dev_get_parent_plat(child); + struct udevice *bus = child->parent; /* Ensure each transfer is for a single register. */ chip->flags |= DM_I2C_CHIP_RD_ADDRESS | DM_I2C_CHIP_WR_ADDRESS; - return 0; + return sun6i_p2wi_probe_chip(bus, chip->chip_addr, 0); } static const struct dm_i2c_ops sun6i_p2wi_ops = { From 07c411346cb2493e4f59a8affbd35f5efc2ec736 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Thu, 17 Mar 2022 23:52:34 -0500 Subject: [PATCH 30/40] i2c: sun6i_p2wi: Add support for DM clocks and resets Currently, clock/reset setup for this device is handled by a platform-specific function and is intermixed with non-DM pinctrl setup. Use the devicetree to get clocks/resets, which disentagles it from the pinctrl setup in preparation for moving to DM_PINCTRL. Signed-off-by: Samuel Holland Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/i2c/sun6i_p2wi.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/i2c/sun6i_p2wi.c b/drivers/i2c/sun6i_p2wi.c index 064d82a6d1f..d221323295d 100644 --- a/drivers/i2c/sun6i_p2wi.c +++ b/drivers/i2c/sun6i_p2wi.c @@ -14,10 +14,12 @@ */ #include +#include #include #include #include #include +#include #include #include #include @@ -180,9 +182,19 @@ static int sun6i_p2wi_probe_chip(struct udevice *bus, uint chip_addr, static int sun6i_p2wi_probe(struct udevice *bus) { struct sun6i_p2wi_priv *priv = dev_get_priv(bus); + struct reset_ctl *reset; + struct clk *clk; priv->base = dev_read_addr_ptr(bus); + reset = devm_reset_control_get(bus, NULL); + if (!IS_ERR(reset)) + reset_deassert(reset); + + clk = devm_clk_get(bus, NULL); + if (!IS_ERR(clk)) + clk_enable(clk); + sun6i_p2wi_init(priv->base); return 0; From c9dd3caae3119c9f77081b5c1ef42553b44ddf20 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Thu, 17 Mar 2022 23:52:35 -0500 Subject: [PATCH 31/40] i2c: sun8i_rsb: Initialize chips in .child_pre_probe Chips attached to the RSB bus require an initialization command before they can be used. (Specifically, this command programs the chip's runtime address.) The driver does this in its .probe_chip hook, under the assumption that .probe_chip is called during child probe. This is not the case; .probe_chip is only called by dm_i2c_probe, which is intended for use by board-level code, not for chips with OF nodes. Since this initialization command must be run before a child chip can be used, do it before probing each child. Signed-off-by: Samuel Holland Acked-by: Andre Przywara Signed-off-by: Andre Przywara --- drivers/i2c/sun8i_rsb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/sun8i_rsb.c b/drivers/i2c/sun8i_rsb.c index 0dea8f7a923..38d6e87577d 100644 --- a/drivers/i2c/sun8i_rsb.c +++ b/drivers/i2c/sun8i_rsb.c @@ -244,11 +244,12 @@ static int sun8i_rsb_probe(struct udevice *bus) static int sun8i_rsb_child_pre_probe(struct udevice *child) { struct dm_i2c_chip *chip = dev_get_parent_plat(child); + struct udevice *bus = child->parent; /* Ensure each transfer is for a single register. */ chip->flags |= DM_I2C_CHIP_RD_ADDRESS | DM_I2C_CHIP_WR_ADDRESS; - return 0; + return sun8i_rsb_probe_chip(bus, chip->chip_addr, 0); } static const struct dm_i2c_ops sun8i_rsb_ops = { From f5bfe1575078cea8de0fa4affb529b360a511094 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Thu, 17 Mar 2022 23:52:36 -0500 Subject: [PATCH 32/40] i2c: sun8i_rsb: Add support for DM clocks and resets Currently, clock/reset setup for this device is handled by a platform-specific function and is intermixed with non-DM pinctrl setup. Use the devicetree to get clocks/resets, which disentagles it from the pinctrl setup in preparation for moving to DM_PINCTRL. This also has the added benefit of picking the right clock/reset bits for H6 and new SoCs that have a rearranged PRCM MMIO space. Signed-off-by: Samuel Holland Signed-off-by: Andre Przywara --- drivers/i2c/sun8i_rsb.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/i2c/sun8i_rsb.c b/drivers/i2c/sun8i_rsb.c index 38d6e87577d..47fa05b6d1c 100644 --- a/drivers/i2c/sun8i_rsb.c +++ b/drivers/i2c/sun8i_rsb.c @@ -9,10 +9,12 @@ */ #include +#include #include #include #include #include +#include #include #include #include @@ -235,9 +237,19 @@ static int sun8i_rsb_probe_chip(struct udevice *bus, uint chip_addr, static int sun8i_rsb_probe(struct udevice *bus) { struct sun8i_rsb_priv *priv = dev_get_priv(bus); + struct reset_ctl *reset; + struct clk *clk; priv->base = dev_read_addr_ptr(bus); + reset = devm_reset_control_get(bus, NULL); + if (!IS_ERR(reset)) + reset_deassert(reset); + + clk = devm_clk_get(bus, NULL); + if (!IS_ERR(clk)) + clk_enable(clk); + return sun8i_rsb_init(priv->base); } From fbc8acf644ceb41e92d67558c7bb86d730fb8135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Baltaz=C3=A1r=20Radics?= Date: Sat, 26 Mar 2022 13:09:10 +0100 Subject: [PATCH 33/40] Add ethernet0 alias in Nanopi NEO's device tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This syncs the sun8i-h3-nanopi-neo.dts from the Linux tree, from tag v5.18-rc1. The alias is required to enable automatic MAC address generation. Signed-off-by: Baltazár Radics Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- arch/arm/dts/sun8i-h3-nanopi-neo.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/dts/sun8i-h3-nanopi-neo.dts b/arch/arm/dts/sun8i-h3-nanopi-neo.dts index 9f33f6fae59..df71fab3cf4 100644 --- a/arch/arm/dts/sun8i-h3-nanopi-neo.dts +++ b/arch/arm/dts/sun8i-h3-nanopi-neo.dts @@ -45,6 +45,10 @@ / { model = "FriendlyARM NanoPi NEO"; compatible = "friendlyarm,nanopi-neo", "allwinner,sun8i-h3"; + + aliases { + ethernet0 = &emac; + }; }; &ehci0 { From 482c1ccd1ce450f8c56a891f4067a6db8fb499fd Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Sat, 9 Oct 2021 14:18:59 +0200 Subject: [PATCH 34/40] sunxi: H3: fix non working console on uart2 Fix non working console on uart2, that seems releated to both Allwinner H2+ and H3. Signed-off-by: Angelo Dureghello [Andre: remove H2+, rearrange pin setup order] Signed-off-by: Andre Przywara --- arch/arm/include/asm/arch-sunxi/gpio.h | 1 + arch/arm/mach-sunxi/board.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 9f07d907e5a..437e86479ce 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -136,6 +136,7 @@ enum sunxi_gpio_number { #define SUNXI_GPIO_DISABLE 7 #define SUN8I_H3_GPA_UART0 2 +#define SUN8I_H3_GPA_UART2 2 #define SUN4I_GPB_PWM 2 #define SUN4I_GPB_TWI0 2 diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index ffe578d5c3a..755d7d78ff1 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -150,6 +150,10 @@ static int gpio_init(void) sunxi_gpio_set_cfgpin(SUNXI_GPG(3), SUN5I_GPG_UART1); sunxi_gpio_set_cfgpin(SUNXI_GPG(4), SUN5I_GPG_UART1); sunxi_gpio_set_pull(SUNXI_GPG(4), SUNXI_GPIO_PULL_UP); +#elif CONFIG_CONS_INDEX == 3 && defined(CONFIG_MACH_SUN8I_H3) + sunxi_gpio_set_cfgpin(SUNXI_GPA(0), SUN8I_H3_GPA_UART2); + sunxi_gpio_set_cfgpin(SUNXI_GPA(1), SUN8I_H3_GPA_UART2); + sunxi_gpio_set_pull(SUNXI_GPA(1), SUNXI_GPIO_PULL_UP); #elif CONFIG_CONS_INDEX == 3 && defined(CONFIG_MACH_SUN8I) sunxi_gpio_set_cfgpin(SUNXI_GPB(0), SUN8I_GPB_UART2); sunxi_gpio_set_cfgpin(SUNXI_GPB(1), SUN8I_GPB_UART2); From 1772771ac00150c474a0936f675dc553f44be549 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 30 Jan 2022 15:27:13 +0100 Subject: [PATCH 35/40] sunxi: prcm: Add a few registers H6 and H616 SPL code has a few writes to unknown PRCM registers. Now that we know what they are, let's replace magic offsets with proper register names. Signed-off-by: Jernej Skrabec Reviewed-by: Samuel Holland Signed-off-by: Andre Przywara --- arch/arm/include/asm/arch-sunxi/prcm_sun50i.h | 10 ++++++++++ arch/arm/mach-sunxi/clock_sun50i_h6.c | 4 +++- arch/arm/mach-sunxi/dram_sun50i_h6.c | 8 +++++--- arch/arm/mach-sunxi/dram_sun50i_h616.c | 7 +++++-- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/prcm_sun50i.h b/arch/arm/include/asm/arch-sunxi/prcm_sun50i.h index 5f636e83845..fd63d3aad83 100644 --- a/arch/arm/include/asm/arch-sunxi/prcm_sun50i.h +++ b/arch/arm/include/asm/arch-sunxi/prcm_sun50i.h @@ -37,8 +37,18 @@ struct sunxi_prcm_reg { u32 w1_gate_reset; /* 0x1ec */ u8 res10[0x1c]; /* 0x1f0 */ u32 rtc_gate_reset; /* 0x20c */ + u8 res11[0x34]; /* 0x210 */ + u32 pll_ldo_cfg; /* 0x244 */ + u8 res12[0x8]; /* 0x248 */ + u32 sys_pwroff_gating; /* 0x250 */ + u8 res13[0xbc]; /* 0x254 */ + u32 res_cal_ctrl; /* 0x310 */ + u32 ohms200; /* 0x314 */ + u32 ohms240; /* 0x318 */ + u32 res_cal_status; /* 0x31c */ }; check_member(sunxi_prcm_reg, rtc_gate_reset, 0x20c); +check_member(sunxi_prcm_reg, res_cal_status, 0x31c); #define PRCM_TWI_GATE (1 << 0) #define PRCM_TWI_RESET (1 << 16) diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c index a947463e0a5..e5846e6381f 100644 --- a/arch/arm/mach-sunxi/clock_sun50i_h6.c +++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c @@ -9,10 +9,12 @@ void clock_init_safe(void) { struct sunxi_ccm_reg *const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + struct sunxi_prcm_reg *const prcm = + (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE; /* this seems to enable PLLs on H616 */ if (IS_ENABLED(CONFIG_MACH_SUN50I_H616)) - setbits_le32(SUNXI_PRCM_BASE + 0x250, 0x10); + setbits_le32(&prcm->sys_pwroff_gating, 0x10); clock_set_pll1(408000000); diff --git a/arch/arm/mach-sunxi/dram_sun50i_h6.c b/arch/arm/mach-sunxi/dram_sun50i_h6.c index d05375c9027..b332f3a3e4a 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h6.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h6.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -665,6 +666,8 @@ unsigned long sunxi_dram_init(void) { struct sunxi_mctl_com_reg * const mctl_com = (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; + struct sunxi_prcm_reg *const prcm = + (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE; struct dram_para para = { .clk = CONFIG_DRAM_CLK, #ifdef CONFIG_SUNXI_DRAM_H6_LPDDR3 @@ -680,9 +683,8 @@ unsigned long sunxi_dram_init(void) unsigned long size; - /* RES_CAL_CTRL_REG in BSP U-boot*/ - setbits_le32(0x7010310, BIT(8)); - clrbits_le32(0x7010318, 0x3f); + setbits_le32(&prcm->res_cal_ctrl, BIT(8)); + clrbits_le32(&prcm->ohms240, 0x3f); mctl_auto_detect_rank_width(¶); mctl_auto_detect_dram_size(¶); diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 83e8abc2f8d..454c845a001 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1001,14 +1002,16 @@ static unsigned long mctl_calc_size(struct dram_para *para) unsigned long sunxi_dram_init(void) { + struct sunxi_prcm_reg *const prcm = + (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE; struct dram_para para = { .clk = CONFIG_DRAM_CLK, .type = SUNXI_DRAM_TYPE_DDR3, }; unsigned long size; - setbits_le32(0x7010310, BIT(8)); - clrbits_le32(0x7010318, 0x3f); + setbits_le32(&prcm->res_cal_ctrl, BIT(8)); + clrbits_le32(&prcm->ohms240, 0x3f); mctl_auto_detect_rank_width(¶); mctl_auto_detect_dram_size(¶); From 40a9c200aff1b855f66745a1b9961668739ef6fb Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 30 Jan 2022 15:27:14 +0100 Subject: [PATCH 36/40] sunxi: clock: H6/H616: Add resistor calibration BSP boot0 executes resistor calibration before clocks are initialized. Let's do that. Signed-off-by: Jernej Skrabec Signed-off-by: Andre Przywara --- arch/arm/mach-sunxi/clock_sun50i_h6.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c index e5846e6381f..32119ad1655 100644 --- a/arch/arm/mach-sunxi/clock_sun50i_h6.c +++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c @@ -12,9 +12,14 @@ void clock_init_safe(void) struct sunxi_prcm_reg *const prcm = (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE; - /* this seems to enable PLLs on H616 */ - if (IS_ENABLED(CONFIG_MACH_SUN50I_H616)) + if (IS_ENABLED(CONFIG_MACH_SUN50I_H616)) { + /* this seems to enable PLLs on H616 */ setbits_le32(&prcm->sys_pwroff_gating, 0x10); + setbits_le32(&prcm->res_cal_ctrl, 2); + } + + clrbits_le32(&prcm->res_cal_ctrl, 1); + setbits_le32(&prcm->res_cal_ctrl, 1); clock_set_pll1(408000000); From 35b786c1ba97ea2548ea1418352e02f7b9dfbc8b Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 30 Jan 2022 15:27:15 +0100 Subject: [PATCH 37/40] sunxi: clock: H6: Adjust PLL LDO before clock setup BSP boot0 adjust PLL LDO regulator before clocks are initialized. Let's do that. Signed-off-by: Jernej Skrabec Signed-off-by: Andre Przywara --- arch/arm/mach-sunxi/clock_sun50i_h6.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c index 32119ad1655..7926394cf76 100644 --- a/arch/arm/mach-sunxi/clock_sun50i_h6.c +++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c @@ -21,6 +21,13 @@ void clock_init_safe(void) clrbits_le32(&prcm->res_cal_ctrl, 1); setbits_le32(&prcm->res_cal_ctrl, 1); + if (IS_ENABLED(CONFIG_MACH_SUN50I_H6)) { + /* set key field for ldo enable */ + setbits_le32(&prcm->pll_ldo_cfg, 0xA7000000); + /* set PLL VDD LDO output to 1.14 V */ + setbits_le32(&prcm->pll_ldo_cfg, 0x60000); + } + clock_set_pll1(408000000); writel(CCM_PLL6_DEFAULT, &ccm->pll6_cfg); From 59073573227ce7aeae3957744146cdf23849c8b9 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 12 Jul 2021 11:06:49 +0100 Subject: [PATCH 38/40] spl: mmc: extend spl_mmc_boot_mode() to take mmc argument Platforms can overwrite the weak definition of spl_mmc_boot_mode() to determine where to load U-Boot proper from. For most of them this is a trivial decision based on Kconfig variables, but it might be desirable the probe the actual device to answer this question. Pass the pointer to the mmc struct to that function, so implementations can make use of that. Compile-tested for all users changed. Signed-off-by: Andre Przywara Reviewed-by: Stefano Babic Reviewed-by: Ley Foon Tan (for SoCFPGA) Acked-by: Lokesh Vutla (for OMAP and K3) Reviewed-by: Simon Glass --- arch/arm/mach-imx/spl.c | 2 +- arch/arm/mach-k3/am642_init.c | 2 +- arch/arm/mach-k3/am6_init.c | 2 +- arch/arm/mach-k3/j721e_init.c | 2 +- arch/arm/mach-k3/j721s2_init.c | 2 +- arch/arm/mach-mvebu/spl.c | 2 +- arch/arm/mach-omap2/boot-common.c | 2 +- arch/arm/mach-rockchip/spl.c | 2 +- arch/arm/mach-socfpga/spl_a10.c | 2 +- arch/arm/mach-socfpga/spl_gen5.c | 2 +- arch/arm/mach-stm32mp/spl.c | 2 +- arch/arm/mach-uniphier/mmc-boot-mode.c | 5 +---- common/spl/spl_mmc.c | 4 ++-- include/spl.h | 3 ++- 14 files changed, 16 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-imx/spl.c b/arch/arm/mach-imx/spl.c index 2832b735096..64ca2967721 100644 --- a/arch/arm/mach-imx/spl.c +++ b/arch/arm/mach-imx/spl.c @@ -201,7 +201,7 @@ int g_dnl_get_board_bcd_device_number(int gcnum) #if defined(CONFIG_SPL_MMC) /* called from spl_mmc to see type of boot mode for storage (RAW or FAT) */ -u32 spl_mmc_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) { #if defined(CONFIG_MX7) || defined(CONFIG_IMX8M) || defined(CONFIG_IMX8) switch (get_boot_device()) { diff --git a/arch/arm/mach-k3/am642_init.c b/arch/arm/mach-k3/am642_init.c index 543dea02bca..eabfd570a6b 100644 --- a/arch/arm/mach-k3/am642_init.c +++ b/arch/arm/mach-k3/am642_init.c @@ -208,7 +208,7 @@ void board_init_f(ulong dummy) } } -u32 spl_mmc_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) { switch (boot_device) { case BOOT_DEVICE_MMC1: diff --git a/arch/arm/mach-k3/am6_init.c b/arch/arm/mach-k3/am6_init.c index 8a6b1de7641..86c1a349f1f 100644 --- a/arch/arm/mach-k3/am6_init.c +++ b/arch/arm/mach-k3/am6_init.c @@ -269,7 +269,7 @@ void board_init_f(ulong dummy) spl_enable_dcache(); } -u32 spl_mmc_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) { #if defined(CONFIG_SUPPORT_EMMC_BOOT) u32 devstat = readl(CTRLMMR_MAIN_DEVSTAT); diff --git a/arch/arm/mach-k3/j721e_init.c b/arch/arm/mach-k3/j721e_init.c index c4b6b180505..f503f15f192 100644 --- a/arch/arm/mach-k3/j721e_init.c +++ b/arch/arm/mach-k3/j721e_init.c @@ -291,7 +291,7 @@ void board_init_f(ulong dummy) spl_enable_dcache(); } -u32 spl_mmc_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) { switch (boot_device) { case BOOT_DEVICE_MMC1: diff --git a/arch/arm/mach-k3/j721s2_init.c b/arch/arm/mach-k3/j721s2_init.c index 58a86541b79..2e64e44a80e 100644 --- a/arch/arm/mach-k3/j721s2_init.c +++ b/arch/arm/mach-k3/j721s2_init.c @@ -173,7 +173,7 @@ void board_init_f(ulong dummy) spl_enable_dcache(); } -u32 spl_mmc_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) { switch (boot_device) { case BOOT_DEVICE_MMC1: diff --git a/arch/arm/mach-mvebu/spl.c b/arch/arm/mach-mvebu/spl.c index 5ad323f9d9d..fa9a1d7ab65 100644 --- a/arch/arm/mach-mvebu/spl.c +++ b/arch/arm/mach-mvebu/spl.c @@ -96,7 +96,7 @@ struct kwbimage_main_hdr_v1 { } __packed; #ifdef CONFIG_SPL_MMC -u32 spl_mmc_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) { return MMCSD_MODE_RAW; } diff --git a/arch/arm/mach-omap2/boot-common.c b/arch/arm/mach-omap2/boot-common.c index afc35856419..c463c96c74c 100644 --- a/arch/arm/mach-omap2/boot-common.c +++ b/arch/arm/mach-omap2/boot-common.c @@ -196,7 +196,7 @@ u32 spl_boot_device(void) return gd->arch.omap_boot_device; } -u32 spl_mmc_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) { return gd->arch.omap_boot_mode; } diff --git a/arch/arm/mach-rockchip/spl.c b/arch/arm/mach-rockchip/spl.c index 7a8db632b80..d51a0727b47 100644 --- a/arch/arm/mach-rockchip/spl.c +++ b/arch/arm/mach-rockchip/spl.c @@ -66,7 +66,7 @@ u32 spl_boot_device(void) return boot_device; } -u32 spl_mmc_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) { return MMCSD_MODE_RAW; } diff --git a/arch/arm/mach-socfpga/spl_a10.c b/arch/arm/mach-socfpga/spl_a10.c index d2f454cd246..ec67a5b0eb7 100644 --- a/arch/arm/mach-socfpga/spl_a10.c +++ b/arch/arm/mach-socfpga/spl_a10.c @@ -99,7 +99,7 @@ u32 spl_boot_device(void) } #ifdef CONFIG_SPL_MMC -u32 spl_mmc_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) { #if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4) return MMCSD_MODE_FS; diff --git a/arch/arm/mach-socfpga/spl_gen5.c b/arch/arm/mach-socfpga/spl_gen5.c index 441d893333c..287fbd1713c 100644 --- a/arch/arm/mach-socfpga/spl_gen5.c +++ b/arch/arm/mach-socfpga/spl_gen5.c @@ -53,7 +53,7 @@ u32 spl_boot_device(void) } #ifdef CONFIG_SPL_MMC -u32 spl_mmc_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) { #if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4) return MMCSD_MODE_FS; diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c index 51fe0698fab..78fa9d7edd2 100644 --- a/arch/arm/mach-stm32mp/spl.c +++ b/arch/arm/mach-stm32mp/spl.c @@ -55,7 +55,7 @@ u32 spl_boot_device(void) return BOOT_DEVICE_MMC1; } -u32 spl_mmc_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) { return MMCSD_MODE_RAW; } diff --git a/arch/arm/mach-uniphier/mmc-boot-mode.c b/arch/arm/mach-uniphier/mmc-boot-mode.c index e47e5df6480..09cad743c55 100644 --- a/arch/arm/mach-uniphier/mmc-boot-mode.c +++ b/arch/arm/mach-uniphier/mmc-boot-mode.c @@ -7,10 +7,8 @@ #include #include -u32 spl_mmc_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) { - struct mmc *mmc; - /* * work around a bug in the Boot ROM of LD4, Pro4, and sLD8: * @@ -24,7 +22,6 @@ u32 spl_mmc_boot_mode(const u32 boot_device) * Fixup mmc->part_config here because it is used to determine the * partition which the U-Boot image is read from. */ - mmc = find_mmc_device(0); mmc->part_config &= ~EXT_CSD_BOOT_PART_NUM(PART_ACCESS_MASK); mmc->part_config |= EXT_CSD_BOOT_PARTITION_ENABLE; diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 1c41d24ff45..1bb785a80f0 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -327,7 +327,7 @@ static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, } #endif -u32 __weak spl_mmc_boot_mode(const u32 boot_device) +u32 __weak spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) { #if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4) return MMCSD_MODE_FS; @@ -401,7 +401,7 @@ int spl_mmc_load(struct spl_image_info *spl_image, } } - boot_mode = spl_mmc_boot_mode(bootdev->boot_device); + boot_mode = spl_mmc_boot_mode(mmc, bootdev->boot_device); err = -EINVAL; switch (boot_mode) { case MMCSD_MODE_EMMCBOOT: diff --git a/include/spl.h b/include/spl.h index 8ceb3c0f095..6134aba8571 100644 --- a/include/spl.h +++ b/include/spl.h @@ -14,6 +14,7 @@ #include #include #include +#include struct blk_desc; struct image_header; @@ -375,7 +376,7 @@ u32 spl_boot_device(void); * Note: It is important to use the boot_device parameter instead of e.g. * spl_boot_device() as U-Boot is not always loaded from the same device as SPL. */ -u32 spl_mmc_boot_mode(const u32 boot_device); +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device); /** * spl_mmc_boot_partition() - MMC partition to load U-Boot from. From b9a2e1853351218b80cd647253a8c97bad0e31ac Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 12 Jul 2021 11:06:50 +0100 Subject: [PATCH 39/40] sunxi: eMMC: Improve automatic boot source detection When the Allwinner BROM loads the SPL from an eMMC boot partition, it sets the boot source byte to the same value as when booting from the user data partition. This prevents us from determining the boot source to load U-Boot proper from the proper partition for sure. The generic SPL MMC code already looks at the enabled boot partition number, to load U-Boot proper from the same partition, but this fails if there is nothing bootable in this partition, as the BROM then silently falls back to the user data partition, which the SPL misses. To learn about the actual boot source anyway, we repeat the algorithm the BROM used to select the boot partition in the first place: - Test EXT_CSD[179] to check if an eMMC boot partition is enabled. - Test EXT_CSD[177] to check for valid MMC interface settings. - Check if BOOT_ACK is enabled. - Check the beginning of the first sector for a valid eGON signature. - Load the whole SPL. - Recalculate the checksum to verify the SPL is valid. If one of those steps fails, we bail out and continue loading from the user data partition. Otherwise we load from the selected boot partition. Since the boot source is needed twice in the boot process, we cache the result of this test to avoid doing this costly test multiple times. This allows the very same image file to be put onto an SD card, into the eMMC user data partition or into the eMMC boot partition, and safely loads the whole of U-Boot from there. Signed-off-by: Andre Przywara --- arch/arm/mach-sunxi/board.c | 83 +++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index 755d7d78ff1..173e946465d 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -346,6 +346,89 @@ __weak void sunxi_sram_init(void) { } +/* + * When booting from an eMMC boot partition, the SPL puts the same boot + * source code into SRAM A1 as when loading the SPL from the normal + * eMMC user data partition: 0x2. So to know where we have been loaded + * from, we repeat the BROM algorithm here: checking for a valid eGON boot + * image at offset 0 of a (potentially) selected boot partition. + * If any of the conditions is not met, it must have been the eMMC user + * data partition. + */ +static bool sunxi_valid_emmc_boot(struct mmc *mmc) +{ + struct blk_desc *bd = mmc_get_blk_desc(mmc); + uint32_t *buffer = (void *)(uintptr_t)CONFIG_SYS_TEXT_BASE; + struct boot_file_head *egon_head = (void *)buffer; + int bootpart = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config); + uint32_t spl_size, emmc_checksum, chksum = 0; + ulong count; + + /* The BROM requires BOOT_ACK to be enabled. */ + if (!EXT_CSD_EXTRACT_BOOT_ACK(mmc->part_config)) + return false; + + /* + * The BOOT_BUS_CONDITION register must be 4-bit SDR, with (0x09) + * or without (0x01) high speed timings. + */ + if ((mmc->ext_csd[EXT_CSD_BOOT_BUS_WIDTH] & 0x1b) != 0x01 && + (mmc->ext_csd[EXT_CSD_BOOT_BUS_WIDTH] & 0x1b) != 0x09) + return false; + + /* Partition 0 is the user data partition, bootpart must be 1 or 2. */ + if (bootpart != 1 && bootpart != 2) + return false; + + /* Failure to switch to the boot partition is fatal. */ + if (mmc_switch_part(mmc, bootpart)) + return false; + + /* Read the first block to do some sanity checks on the eGON header. */ + count = blk_dread(bd, 0, 1, buffer); + if (count != 1 || !sunxi_egon_valid(egon_head)) + return false; + + /* Read the rest of the SPL now we know it's halfway sane. */ + spl_size = buffer[4]; + count = blk_dread(bd, 1, DIV_ROUND_UP(spl_size, bd->blksz) - 1, + buffer + bd->blksz / 4); + + /* Save the checksum and replace it with the "stamp value". */ + emmc_checksum = buffer[3]; + buffer[3] = 0x5f0a6c39; + + /* The checksum is a simple ignore-carry addition of all words. */ + for (count = 0; count < spl_size / 4; count++) + chksum += buffer[count]; + + debug("eMMC boot part SPL checksum: stored: 0x%08x, computed: 0x%08x\n", + emmc_checksum, chksum); + + return emmc_checksum == chksum; +} + +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) +{ + static u32 result = ~0; + + if (result != ~0) + return result; + + result = MMCSD_MODE_RAW; + if (!IS_SD(mmc) && IS_ENABLED(CONFIG_SUPPORT_EMMC_BOOT)) { + if (sunxi_valid_emmc_boot(mmc)) + result = MMCSD_MODE_EMMCBOOT; + else + mmc_switch_part(mmc, 0); + } + + debug("%s(): %s part\n", __func__, + result == MMCSD_MODE_RAW ? "user" : "boot"); + + return result; +} + void board_init_f(ulong dummy) { sunxi_sram_init(); From 69a0ea007826bf27584943591e61ee087683fdca Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 12 Jul 2021 11:06:51 +0100 Subject: [PATCH 40/40] sunxi: defconfig: enable eMMC boot partition support Now that the SPL can safely detect whether it was loaded from an eMMC boot partition or the normal user data partition, let's enable this feature on some boards that feature eMMC storage. That covers the boards where I could test this on, and allows the same build to be written to an SD card, eMMC user partition, eMMC boot partition, or into SPI NOR flash. Signed-off-by: Andre Przywara --- configs/bananapi_m64_defconfig | 1 + configs/emlid_neutis_n5_devboard_defconfig | 1 + configs/pine64-lts_defconfig | 1 + configs/pine_h64_defconfig | 1 + configs/sopine_baseboard_defconfig | 1 + 5 files changed, 5 insertions(+) diff --git a/configs/bananapi_m64_defconfig b/configs/bananapi_m64_defconfig index 292044d7b8b..5463b046fdb 100644 --- a/configs/bananapi_m64_defconfig +++ b/configs/bananapi_m64_defconfig @@ -7,6 +7,7 @@ CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y CONFIG_MMC0_CD_PIN="PH13" CONFIG_MMC_SUNXI_SLOT_EXTRA=2 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_SUN8I_EMAC=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y diff --git a/configs/emlid_neutis_n5_devboard_defconfig b/configs/emlid_neutis_n5_devboard_defconfig index e2d3b1397e2..a3b43dffc63 100644 --- a/configs/emlid_neutis_n5_devboard_defconfig +++ b/configs/emlid_neutis_n5_devboard_defconfig @@ -8,3 +8,4 @@ CONFIG_DRAM_ZQ=3881977 # CONFIG_DRAM_ODT_EN is not set CONFIG_MMC_SUNXI_SLOT_EXTRA=2 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_SUPPORT_EMMC_BOOT=y diff --git a/configs/pine64-lts_defconfig b/configs/pine64-lts_defconfig index 45a9e77e0ea..7e7c2d79104 100644 --- a/configs/pine64-lts_defconfig +++ b/configs/pine64-lts_defconfig @@ -10,6 +10,7 @@ CONFIG_MMC0_CD_PIN="" CONFIG_MMC_SUNXI_SLOT_EXTRA=2 CONFIG_SPL_SPI_SUNXI=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_SUN8I_EMAC=y CONFIG_SPI=y diff --git a/configs/pine_h64_defconfig b/configs/pine_h64_defconfig index 1e730dd9fa1..09a4275f0e7 100644 --- a/configs/pine_h64_defconfig +++ b/configs/pine_h64_defconfig @@ -11,6 +11,7 @@ CONFIG_USB3_VBUS_PIN="PL5" CONFIG_SPL_SPI_SUNXI=y # CONFIG_PSCI_RESET is not set # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_SUN8I_EMAC=y CONFIG_PHY_SUN50I_USB3=y diff --git a/configs/sopine_baseboard_defconfig b/configs/sopine_baseboard_defconfig index 982f7b0b67e..fbbef7a9f9a 100644 --- a/configs/sopine_baseboard_defconfig +++ b/configs/sopine_baseboard_defconfig @@ -11,6 +11,7 @@ CONFIG_MMC0_CD_PIN="" CONFIG_MMC_SUNXI_SLOT_EXTRA=2 CONFIG_SPL_SPI_SUNXI=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_SPI_FLASH_WINBOND=y CONFIG_SUN8I_EMAC=y CONFIG_SPI=y