From 2b9d6a18435f4472bb79409ffdb24095ee6b5f10 Mon Sep 17 00:00:00 2001 From: Maksim Kiselev Date: Sat, 11 Nov 2023 16:33:08 +0300 Subject: spi: sunxi: Add support for R329/D1/R528/T113 SPI controller These SoCs have two SPI controllers that are quite similar to the SPI on previous Allwinner SoCs. The main difference is that new SoCs don't have a clock divider (SPI_CCR register) inside SPI IP. Instead SPI sample mode should be configured depending on the input clock. For now SPI input clock source selection is not supported by this driver, and only HOSC@24MHz can be used as input clock. Therefore, according to the, manual we could change the SPI sample mode from delay half cycle(default) to normal. This patch adds a quirk for this kind of SPI controllers Signed-off-by: Maksim Kiselev Tested-by: Sam Edwards Reviewed-by: Andre Przywara --- drivers/spi/spi-sunxi.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c index c56d82d998a..9ec6b359e22 100644 --- a/drivers/spi/spi-sunxi.c +++ b/drivers/spi/spi-sunxi.c @@ -117,6 +117,8 @@ enum sun4i_spi_bits { SPI_TCR_XCH, SPI_TCR_CS_MANUAL, SPI_TCR_CS_LEVEL, + SPI_TCR_SDC, + SPI_TCR_SDM, SPI_FCR_TF_RST, SPI_FCR_RF_RST, SPI_FSR_RF_CNT_MASK, @@ -128,6 +130,7 @@ struct sun4i_spi_variant { u32 fifo_depth; bool has_soft_reset; bool has_burst_ctl; + bool has_clk_ctl; }; struct sun4i_spi_plat { @@ -302,7 +305,19 @@ static int sun4i_spi_claim_bus(struct udevice *dev) setbits_le32(SPI_REG(priv, SPI_TCR), SPI_BIT(priv, SPI_TCR_CS_MANUAL) | SPI_BIT(priv, SPI_TCR_CS_ACTIVE_LOW)); - sun4i_spi_set_speed_mode(dev->parent); + if (priv->variant->has_clk_ctl) { + sun4i_spi_set_speed_mode(dev->parent); + } else { + /* + * At this moment there is no ability to change input clock. + * Therefore, we can only use default HOSC@24MHz clock and + * set SPI sampling mode to normal + */ + clrsetbits_le32(SPI_REG(priv, SPI_TCR), + SPI_BIT(priv, SPI_TCR_SDC) | + SPI_BIT(priv, SPI_TCR_SDM), + SPI_BIT(priv, SPI_TCR_SDM)); + } return 0; } @@ -516,6 +531,8 @@ static const u32 sun6i_spi_bits[] = { [SPI_TCR_CS_MASK] = 0x30, [SPI_TCR_CS_MANUAL] = BIT(6), [SPI_TCR_CS_LEVEL] = BIT(7), + [SPI_TCR_SDC] = BIT(11), + [SPI_TCR_SDM] = BIT(13), [SPI_TCR_XCH] = BIT(31), [SPI_FCR_RF_RST] = BIT(15), [SPI_FCR_TF_RST] = BIT(31), @@ -526,6 +543,7 @@ static const struct sun4i_spi_variant sun4i_a10_spi_variant = { .regs = sun4i_spi_regs, .bits = sun4i_spi_bits, .fifo_depth = 64, + .has_clk_ctl = true, }; static const struct sun4i_spi_variant sun6i_a31_spi_variant = { @@ -534,6 +552,7 @@ static const struct sun4i_spi_variant sun6i_a31_spi_variant = { .fifo_depth = 128, .has_soft_reset = true, .has_burst_ctl = true, + .has_clk_ctl = true, }; static const struct sun4i_spi_variant sun8i_h3_spi_variant = { @@ -542,6 +561,15 @@ static const struct sun4i_spi_variant sun8i_h3_spi_variant = { .fifo_depth = 64, .has_soft_reset = true, .has_burst_ctl = true, + .has_clk_ctl = true, +}; + +static const struct sun4i_spi_variant sun50i_r329_spi_variant = { + .regs = sun6i_spi_regs, + .bits = sun6i_spi_bits, + .fifo_depth = 64, + .has_soft_reset = true, + .has_burst_ctl = true, }; static const struct udevice_id sun4i_spi_ids[] = { @@ -557,6 +585,10 @@ static const struct udevice_id sun4i_spi_ids[] = { .compatible = "allwinner,sun8i-h3-spi", .data = (ulong)&sun8i_h3_spi_variant, }, + { + .compatible = "allwinner,sun50i-r329-spi", + .data = (ulong)&sun50i_r329_spi_variant, + }, { /* sentinel */ } }; -- cgit v1.3.1 From c93a6fc8f5313b2aa7081d53c3061c7c1b94afca Mon Sep 17 00:00:00 2001 From: Philippe Coval Date: Sun, 11 Feb 2024 21:52:13 +0100 Subject: arm: sunxi: Reduce inrush current on Olimex A20-OLinuXino_MICRO configs This change fix reboot, both configurations were tested on my Olimex A20 Micro Rev E with debian-12. This issue was also present and fixed on A20 Lime2 (in 8311e84b18), quoting Olliver Schinagl: The lime2 features a too large capacitor on the LDO3 output, which causes the PMIC to shutdown when enabling power. To be able to still boot up however, we must gradually enable power on LDO3 for this board. We do this by enabling both the inrush quirk and the maximum slope the AXP209 supports. Link: https://bugs.debian.org/1060752 Cc: Olliver Schinagl Cc: Priit Laes Cc: Maxime Ripard Signed-off-by: Philippe Coval Reviewed-by: Andre Przywara --- configs/A20-OLinuXino_MICRO-eMMC_defconfig | 1 + configs/A20-OLinuXino_MICRO_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/configs/A20-OLinuXino_MICRO-eMMC_defconfig b/configs/A20-OLinuXino_MICRO-eMMC_defconfig index ca5869f43d9..2f26b0ca01f 100644 --- a/configs/A20-OLinuXino_MICRO-eMMC_defconfig +++ b/configs/A20-OLinuXino_MICRO-eMMC_defconfig @@ -20,6 +20,7 @@ CONFIG_ETH_DESIGNWARE=y CONFIG_MII=y CONFIG_SUN7I_GMAC=y CONFIG_SUN7I_GMAC_FORCE_TXERR=y +CONFIG_AXP_ALDO3_INRUSH_QUIRK=y CONFIG_AXP_ALDO3_VOLT=2800 CONFIG_AXP_ALDO4_VOLT=2800 CONFIG_SCSI=y diff --git a/configs/A20-OLinuXino_MICRO_defconfig b/configs/A20-OLinuXino_MICRO_defconfig index db4270f9b27..673ab85c8a3 100644 --- a/configs/A20-OLinuXino_MICRO_defconfig +++ b/configs/A20-OLinuXino_MICRO_defconfig @@ -20,6 +20,7 @@ CONFIG_ETH_DESIGNWARE=y CONFIG_MII=y CONFIG_SUN7I_GMAC=y CONFIG_SUN7I_GMAC_FORCE_TXERR=y +CONFIG_AXP_ALDO3_INRUSH_QUIRK=y CONFIG_AXP_ALDO3_VOLT=2800 CONFIG_AXP_ALDO4_VOLT=2800 CONFIG_SCSI=y -- cgit v1.3.1 From 3b08e66f69f3bb8a14f771483d3718f67e22709f Mon Sep 17 00:00:00 2001 From: Ludwig Kormann Date: Thu, 1 Feb 2024 09:45:50 +0100 Subject: sunxi: sun4i: add missing sdelay() to clock_init_safe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This delay is required after switching the clock source. See “A20 Reference manual v1.4” Page 50 / section “1.5.4.16. CPU/AHB/APB0 CLOCK RATIO”: “If the clock source is changed, at most to wait for 8 present running clock cycles.” This is already implemented in clock_set_pll1(), but was still missing in clock_init_safe(). Signed-off-by: Ludwig Kormann Reviewed-by: Andre Przywara --- arch/arm/mach-sunxi/clock_sun4i.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-sunxi/clock_sun4i.c b/arch/arm/mach-sunxi/clock_sun4i.c index 8f1d1b65f00..ac3b7a801f4 100644 --- a/arch/arm/mach-sunxi/clock_sun4i.c +++ b/arch/arm/mach-sunxi/clock_sun4i.c @@ -25,6 +25,7 @@ void clock_init_safe(void) APB0_DIV_1 << APB0_DIV_SHIFT | CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT, &ccm->cpu_ahb_apb0_cfg); + sdelay(20); writel(PLL1_CFG_DEFAULT, &ccm->pll1_cfg); sdelay(200); writel(AXI_DIV_1 << AXI_DIV_SHIFT | @@ -32,6 +33,7 @@ void clock_init_safe(void) APB0_DIV_1 << APB0_DIV_SHIFT | CPU_CLK_SRC_PLL1 << CPU_CLK_SRC_SHIFT, &ccm->cpu_ahb_apb0_cfg); + sdelay(20); #ifdef CONFIG_MACH_SUN7I setbits_le32(&ccm->ahb_gate0, 0x1 << AHB_GATE_OFFSET_DMA); #endif -- cgit v1.3.1 From bc6e594104caaa25b3b2b53ea1db3df69623dc61 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 30 Jan 2024 14:16:42 +0000 Subject: sunxi: H616: Add OrangePi Zero 2W board support The OrangePi Zero 2W is a tiny development board featuring the Allwinner H618 SoC, shipping with up to 4GB of LPDDR4 DRAM, a mini-HDMI connector, two USB Type-C sockets and a 16MB SPI NOR flash. There is an FPC connector to connect an expansion board, which sports two more USB Type-A sockets and a 100MBit Ethernet port. Support for the expansion board is not in the DT yet, probably a DT overlay would cover this in the future. Add a defconfig file selecting the right drivers and DRAM options. Since the .dts file was synced from the Linux kernel repo already, we just need to add one line to the Makefile to actually build the .dtb. The DRAM parameters were derived from the values found in the BSP DRAM drivers on the SPI NOR flash. Signed-off-by: Andre Przywara Reviewed-by: Jernej Skrabec --- arch/arm/dts/Makefile | 1 + board/sunxi/MAINTAINERS | 5 +++++ configs/orangepi_zero2w_defconfig | 30 ++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 configs/orangepi_zero2w_defconfig diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index d9725030d5a..b102ffb5f68 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -839,6 +839,7 @@ dtb-$(CONFIG_MACH_SUN50I_H6) += \ sun50i-h6-tanix-tx6-mini.dtb dtb-$(CONFIG_MACH_SUN50I_H616) += \ sun50i-h616-orangepi-zero2.dtb \ + sun50i-h618-orangepi-zero2w.dtb \ sun50i-h618-orangepi-zero3.dtb \ sun50i-h618-transpeed-8k618-t.dtb \ sun50i-h616-x96-mate.dtb diff --git a/board/sunxi/MAINTAINERS b/board/sunxi/MAINTAINERS index a2da6a4a7a2..4bcd9b9af7f 100644 --- a/board/sunxi/MAINTAINERS +++ b/board/sunxi/MAINTAINERS @@ -460,6 +460,11 @@ M: Jernej Skrabec S: Maintained F: configs/orangepi_zero2_defconfig +ORANGEPI ZERO 2W BOARD +M: Andre Przywara +S: Maintained +F: configs/orangepi_zero2w_defconfig + ORANGEPI ZERO 3 BOARD M: Andre Przywara S: Maintained diff --git a/configs/orangepi_zero2w_defconfig b/configs/orangepi_zero2w_defconfig new file mode 100644 index 00000000000..5734d9d839c --- /dev/null +++ b/configs/orangepi_zero2w_defconfig @@ -0,0 +1,30 @@ +CONFIG_ARM=y +CONFIG_ARCH_SUNXI=y +CONFIG_DEFAULT_DEVICE_TREE="sun50i-h618-orangepi-zero2w" +CONFIG_SPL=y +CONFIG_DRAM_SUN50I_H616_DX_ODT=0x07070707 +CONFIG_DRAM_SUN50I_H616_DX_DRI=0x0e0e0e0e +CONFIG_DRAM_SUN50I_H616_CA_DRI=0x0e0e +CONFIG_DRAM_SUN50I_H616_ODT_EN=0xaaaaeeee +CONFIG_DRAM_SUN50I_H616_TPR6=0x48808080 +CONFIG_DRAM_SUN50I_H616_TPR10=0x402f6663 +CONFIG_DRAM_SUN50I_H616_TPR11=0x26262524 +CONFIG_DRAM_SUN50I_H616_TPR12=0x100f100f +CONFIG_MACH_SUN50I_H616=y +CONFIG_SUNXI_DRAM_H616_LPDDR4=y +CONFIG_DRAM_CLK=792 +CONFIG_R_I2C_ENABLE=y +CONFIG_SPL_SPI_SUNXI=y +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_SPL_I2C=y +CONFIG_SPL_SYS_I2C_LEGACY=y +CONFIG_SYS_I2C_MVTWSI=y +CONFIG_SYS_I2C_SLAVE=0x7f +CONFIG_SYS_I2C_SPEED=400000 +CONFIG_MTD=y +CONFIG_SPI_FLASH_ZBIT=y +CONFIG_AXP313_POWER=y +CONFIG_SPI=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_MUSB_GADGET=y -- cgit v1.3.1 From 978808d2b9f46db5e9782090ed3c168e6d4183e6 Mon Sep 17 00:00:00 2001 From: Andrey Skvortsov Date: Thu, 28 Dec 2023 00:28:42 +0300 Subject: sunxi: reorganize mctl_mem_matches_* functions mctl_mem_matches and mctl_mem_matches_base identical functions. To avoid code duplication move them to dram_helpers and make mctl_mem_matches use generic mctl_mem_matches_base. Signed-off-by: Andrey Skvortsov Reviewed-by: Andre Przywara --- arch/arm/include/asm/arch-sunxi/dram.h | 1 + arch/arm/mach-sunxi/dram_helpers.c | 20 ++++++++++++++------ arch/arm/mach-sunxi/dram_sunxi_dw.c | 13 ------------- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h index 682daae6b1a..9d21b492418 100644 --- a/arch/arm/include/asm/arch-sunxi/dram.h +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -40,5 +40,6 @@ unsigned long sunxi_dram_init(void); void mctl_await_completion(u32 *reg, u32 mask, u32 val); bool mctl_mem_matches(u32 offset); +bool mctl_mem_matches_base(u32 offset, ulong base); #endif /* _SUNXI_DRAM_H */ diff --git a/arch/arm/mach-sunxi/dram_helpers.c b/arch/arm/mach-sunxi/dram_helpers.c index 4a867df7af8..110825b344f 100644 --- a/arch/arm/mach-sunxi/dram_helpers.c +++ b/arch/arm/mach-sunxi/dram_helpers.c @@ -26,19 +26,27 @@ void mctl_await_completion(u32 *reg, u32 mask, u32 val) } /* - * Test if memory at offset offset matches memory at begin of DRAM + * Test if memory at offset matches memory at a certain base * * Note: dsb() is not available on ARMv5 in Thumb mode */ #ifndef CONFIG_MACH_SUNIV -bool mctl_mem_matches(u32 offset) +bool mctl_mem_matches_base(u32 offset, ulong base) { /* Try to write different values to RAM at two addresses */ - writel(0, CFG_SYS_SDRAM_BASE); - writel(0xaa55aa55, (ulong)CFG_SYS_SDRAM_BASE + offset); + writel(0, base); + writel(0xaa55aa55, base + offset); dsb(); /* Check if the same value is actually observed when reading back */ - return readl(CFG_SYS_SDRAM_BASE) == - readl((ulong)CFG_SYS_SDRAM_BASE + offset); + return readl(base) == + readl(base + offset); +} + +/* + * Test if memory at offset matches memory at begin of DRAM + */ +bool mctl_mem_matches(u32 offset) +{ + return mctl_mem_matches_base(offset, CFG_SYS_SDRAM_BASE); } #endif diff --git a/arch/arm/mach-sunxi/dram_sunxi_dw.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c index 3bfcc632119..e064ef329e6 100644 --- a/arch/arm/mach-sunxi/dram_sunxi_dw.c +++ b/arch/arm/mach-sunxi/dram_sunxi_dw.c @@ -650,19 +650,6 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para) return 0; } -/* - * Test if memory at offset offset matches memory at a certain base - */ -static bool mctl_mem_matches_base(u32 offset, ulong base) -{ - /* Try to write different values to RAM at two addresses */ - writel(0, base); - writel(0xaa55aa55, base + offset); - dsb(); - /* Check if the same value is actually observed when reading back */ - return readl(base) == - readl(base + offset); -} static void mctl_auto_detect_dram_size_rank(uint16_t socid, struct dram_para *para, ulong base, struct rank_para *rank) { -- cgit v1.3.1 From f1e6a718ebab0682d80601db404e8d842767becf Mon Sep 17 00:00:00 2001 From: Andrey Skvortsov Date: Thu, 28 Dec 2023 00:28:43 +0300 Subject: sunxi: restore modified memory Current sunxi DRAM initialisation code does several test accesses to the DRAM array to detect aliasing effects and so determine the correct row/column configuration. This changes the DRAM content, which breaks use cases like soft reset and Linux's ramoops mechanism. Fix this problem by saving and restoring the content of the DRAM cells that is used for the test writes. Signed-off-by: Andrey Skvortsov Reviewed-by: Andre Przywara --- arch/arm/mach-sunxi/dram_helpers.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-sunxi/dram_helpers.c b/arch/arm/mach-sunxi/dram_helpers.c index 110825b344f..83dbe4ca98f 100644 --- a/arch/arm/mach-sunxi/dram_helpers.c +++ b/arch/arm/mach-sunxi/dram_helpers.c @@ -33,13 +33,25 @@ void mctl_await_completion(u32 *reg, u32 mask, u32 val) #ifndef CONFIG_MACH_SUNIV bool mctl_mem_matches_base(u32 offset, ulong base) { + u32 val_base; + u32 val_offset; + bool ret; + + /* Save original values */ + val_base = readl(base); + val_offset = readl(base + offset); + /* Try to write different values to RAM at two addresses */ writel(0, base); writel(0xaa55aa55, base + offset); dsb(); /* Check if the same value is actually observed when reading back */ - return readl(base) == - readl(base + offset); + ret = readl(base) == readl(base + offset); + + /* Restore original values */ + writel(val_base, base); + writel(val_offset, base + offset); + return ret; } /* -- cgit v1.3.1