[PATCH v2 07/10] sunxi: Parameterize bit delay code in H616 DRAM driver
These values are highly board specific and thus make sense to add parameter for them. To ease adding support for new boards, let's make them same as in vendor DRAM settings. Signed-off-by: Jernej Skrabec --- .../include/asm/arch-sunxi/dram_sun50i_h616.h | 3 + arch/arm/mach-sunxi/Kconfig | 18 ++ arch/arm/mach-sunxi/dram_sun50i_h616.c| 189 +- configs/x96_mate_defconfig| 2 + 4 files changed, 163 insertions(+), 49 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h index dbdc6b694ec1..034ba98bc243 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h @@ -155,7 +155,10 @@ struct dram_para { u32 dx_odt; u32 dx_dri; u32 ca_dri; + u32 odt_en; u32 tpr10; + u32 tpr11; + u32 tpr12; }; diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 4300d388e066..7b38e83c2d7e 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -67,11 +67,29 @@ config DRAM_SUN50I_H616_CA_DRI help CA DRI value from vendor DRAM settings. +config DRAM_SUN50I_H616_ODT_EN + hex "H616 DRAM ODT EN parameter" + default 0x1 + help + ODT EN value from vendor DRAM settings. + config DRAM_SUN50I_H616_TPR10 hex "H616 DRAM TPR10 parameter" help TPR10 value from vendor DRAM settings. It tells which features should be configured, like write leveling, read calibration, etc. + +config DRAM_SUN50I_H616_TPR11 + hex "H616 DRAM TPR11 parameter" + default 0x0 + help + TPR11 value from vendor DRAM settings. + +config DRAM_SUN50I_H616_TPR12 + hex "H616 DRAM TPR12 parameter" + default 0x0 + help + TPR12 value from vendor DRAM settings. endif config SUN6I_PRCM diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 3fe45845b78e..f5d8718fefff 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -574,7 +574,7 @@ static bool mctl_phy_write_training(struct dram_para *para) static void mctl_phy_bit_delay_compensation(struct dram_para *para) { - u32 *ptr; + u32 *ptr, val; int i; if (para->tpr10 & TPR10_DX_BIT_DELAY1) { @@ -582,49 +582,93 @@ static void mctl_phy_bit_delay_compensation(struct dram_para *para) setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 8); clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10); + if (para->tpr10 & BIT(30)) + val = para->tpr11 & 0x3f; + else + val = (para->tpr11 & 0xf) << 1; + ptr = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x484); for (i = 0; i < 9; i++) { - writel_relaxed(0x16, ptr); - writel_relaxed(0x16, ptr + 0x30); + writel_relaxed(val, ptr); + writel_relaxed(val, ptr + 0x30); ptr += 2; } - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x4d0); - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x590); - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x4cc); - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x58c); + + if (para->tpr10 & BIT(30)) + val = (para->odt_en >> 15) & 0x1e; + else + val = (para->tpr11 >> 15) & 0x1e; + + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x4d0); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x590); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x4cc); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x58c); + + if (para->tpr10 & BIT(30)) + val = (para->tpr11 >> 8) & 0x3f; + else + val = (para->tpr11 >> 3) & 0x1e; ptr = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x4d8); for (i = 0; i < 9; i++) { - writel_relaxed(0x1a, ptr); - writel_relaxed(0x1a, ptr + 0x30); + writel_relaxed(val, ptr); + writel_relaxed(val, ptr + 0x30); ptr += 2; } - writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x524); - writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x5e4); - writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x520); - writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x5e0); + + if (para->tpr10 & BIT(30)) +
[PATCH v2 10/10] sunxi: Add TPR2 parameter for H616 DRAM driver
It turns out that some H616 and related SoCs (like H313) need TPR2 parameter for proper working. Add it. Signed-off-by: Jernej Skrabec --- .../include/asm/arch-sunxi/dram_sun50i_h616.h | 1 + arch/arm/mach-sunxi/Kconfig | 6 ++ arch/arm/mach-sunxi/dram_sun50i_h616.c| 75 +-- .../mach-sunxi/dram_timings/h616_ddr3_1333.c | 17 - 4 files changed, 75 insertions(+), 24 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h index 615532c6eebb..6db869c0985b 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h @@ -157,6 +157,7 @@ struct dram_para { u32 ca_dri; u32 odt_en; u32 tpr0; + u32 tpr2; u32 tpr10; u32 tpr11; u32 tpr12; diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index fe34755f88ec..6be8a4de53fe 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -79,6 +79,12 @@ config DRAM_SUN50I_H616_TPR0 help TPR0 value from vendor DRAM settings. +config DRAM_SUN50I_H616_TPR2 + hex "H616 DRAM TPR2 parameter" + default 0x0 + help + TPR2 value from vendor DRAM settings. + config DRAM_SUN50I_H616_TPR10 hex "H616 DRAM TPR10 parameter" help diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 44bb15367beb..1f9416d6eaf5 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -788,21 +788,37 @@ static void mctl_phy_ca_bit_delay_compensation(struct dram_para *para) writel(val, [i]); val = (para->tpr10 << 1) & 0x1e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7d8); writel(val, SUNXI_DRAM_PHY0_BASE + 0x7dc); writel(val, SUNXI_DRAM_PHY0_BASE + 0x7e0); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7f4); /* following configuration is DDR3 specific */ val = (para->tpr10 >> 7) & 0x1e; - writel(val, SUNXI_DRAM_PHY0_BASE + 0x7d4); - if (para->ranks == 2) { - val = (para->tpr10 >> 11) & 0x1e; - writel(val, SUNXI_DRAM_PHY0_BASE + 0x79c); - } - if (para->tpr0 & BIT(31)) { - val = (para->tpr0 << 1) & 0x3e; - writel(val, SUNXI_DRAM_PHY0_BASE + 0x78c); - writel(val, SUNXI_DRAM_PHY0_BASE + 0x7a4); - writel(val, SUNXI_DRAM_PHY0_BASE + 0x7b8); + if (para->tpr2 & 1) { + writel(val, SUNXI_DRAM_PHY0_BASE + 0x794); + if (para->ranks == 2) { + val = (para->tpr10 >> 11) & 0x1e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7e4); + } + if (para->tpr0 & BIT(31)) { + val = (para->tpr0 << 1) & 0x3e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x790); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7b8); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7cc); + } + } else { + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7d4); + if (para->ranks == 2) { + val = (para->tpr10 >> 11) & 0x1e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x79c); + } + if (para->tpr0 & BIT(31)) { + val = (para->tpr0 << 1) & 0x3e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x78c); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7a4); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7b8); + } } } @@ -812,7 +828,7 @@ static bool mctl_phy_init(struct dram_para *para) (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; struct sunxi_mctl_ctl_reg * const mctl_ctl = (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE; - u32 val, *ptr; + u32 val, val2, *ptr, mr0, mr2; int i; if (para->bus_full_width) @@ -821,20 +837,28 @@ static bool mctl_phy_init(struct dram_para *para) val = 3; clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x3c, 0xf, val); - writel(0xd, SUNXI_DRAM_PHY0_BASE + 0x14); - writel(0xd, SUNXI_DRAM_PHY0_BASE + 0x35c); - writel(0xd, SUNXI_DRAM_PHY0_BASE + 0x368); - writel(0xd, SUNXI_DRAM_PHY0_BASE + 0x374); + if (para->tpr2 & 0x100) { + val = 9; + val2 = 7; + } else { + val = 13; + val2 = 9; + } + + writel(val, SUNXI_DRAM_PHY0_BASE + 0x14); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x35c); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x3
[PATCH v2 09/10] sunxi: Parameterize some of H616 DDR3 timings
Currently twr2rd, trd2wr and twtp are constants, but according to vendor driver they are calculated from other values. Do that here too, in preparation for later introduction of new parameter. While at it, introduce constant for t_wr_lat, which was incorrectly calculated from tcl before. Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c | 9 + 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c b/arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c index 8f508344bc17..f109e920820b 100644 --- a/arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c +++ b/arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c @@ -48,10 +48,11 @@ void mctl_set_timing_params(struct dram_para *para) u8 tcl = 7;/* JEDEC: CL / 2 => 6 */ u8 tcwl = 5;/* JEDEC: 8 */ u8 t_rdata_en = 9;/* ? */ + u8 t_wr_lat = 5;/* ? */ - u8 twtp = 14; /* (WL + BL / 2 + tWR) / 2 */ - u8 twr2rd = trtp + 7; /* (WL + BL / 2 + tWTR) / 2 */ - u8 trd2wr = 5;/* (RL + BL / 2 + 2 - WL) / 2 */ + u8 twtp = tcl + 2 + tcwl; /* (WL + BL / 2 + tWR) / 2 */ + u8 twr2rd = trtp + 2 + tcwl; /* (WL + BL / 2 + tWTR) / 2 */ + u8 trd2wr = tcl + 3 - tcwl; /* (RL + BL / 2 + 2 - WL) / 2 */ /* set DRAM timing */ writel((twtp << 24) | (tfaw << 16) | (trasmax << 8) | tras, @@ -85,7 +86,7 @@ void mctl_set_timing_params(struct dram_para *para) clrsetbits_le32(_ctl->rankctl, 0xff0, 0x660); /* Configure DFI timing */ - writel((tcl - 2) | 0x200 | (t_rdata_en << 16) | 0x808000, + writel(t_wr_lat | 0x200 | (t_rdata_en << 16) | 0x808000, _ctl->dfitmg0); writel(0x100202, _ctl->dfitmg1); -- 2.40.0
[PATCH v2 04/10] sunxi: Convert H616 DRAM options to single setting
Vendor DRAM settings use TPR10 parameter to enable various features. There are many mores features that just those that are currently mentioned. Since new will be added later and most are not known, let's reuse value from vendor DRAM driver as-is. This will also help adding support for new boards. Signed-off-by: Jernej Skrabec --- .../include/asm/arch-sunxi/dram_sun50i_h616.h | 9 + arch/arm/mach-sunxi/Kconfig | 38 +--- arch/arm/mach-sunxi/dram_sun50i_h616.c| 197 +- configs/orangepi_zero2_defconfig | 5 +- configs/x96_mate_defconfig| 1 + 5 files changed, 117 insertions(+), 133 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h index c9e1f84bfcdd..dbdc6b694ec1 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h @@ -137,6 +137,14 @@ check_member(sunxi_mctl_ctl_reg, unk_0x4240, 0x4240); #define MSTR_ACTIVE_RANKS(x) (((x == 2) ? 3 : 1) << 24) #define MSTR_BURST_LENGTH(x) (((x) >> 1) << 16) +#define TPR10_CA_BIT_DELAY BIT(16) +#define TPR10_DX_BIT_DELAY0BIT(17) +#define TPR10_DX_BIT_DELAY1BIT(18) +#define TPR10_WRITE_LEVELING BIT(20) +#define TPR10_READ_CALIBRATION BIT(21) +#define TPR10_READ_TRAININGBIT(22) +#define TPR10_WRITE_TRAINING BIT(23) + struct dram_para { u32 clk; enum sunxi_dram_type type; @@ -147,6 +155,7 @@ struct dram_para { u32 dx_odt; u32 dx_dri; u32 ca_dri; + u32 tpr10; }; diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 14fb9a95905a..1b47a49f938c 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -52,38 +52,6 @@ config DRAM_SUN50I_H616 like H616. if DRAM_SUN50I_H616 -config DRAM_SUN50I_H616_WRITE_LEVELING - bool "H616 DRAM write leveling" - ---help--- - Select this when DRAM on your H616 board needs write leveling. - -config DRAM_SUN50I_H616_READ_CALIBRATION - bool "H616 DRAM read calibration" - ---help--- - Select this when DRAM on your H616 board needs read calibration. - -config DRAM_SUN50I_H616_READ_TRAINING - bool "H616 DRAM read training" - ---help--- - Select this when DRAM on your H616 board needs read training. - -config DRAM_SUN50I_H616_WRITE_TRAINING - bool "H616 DRAM write training" - ---help--- - Select this when DRAM on your H616 board needs write training. - -config DRAM_SUN50I_H616_BIT_DELAY_COMPENSATION - bool "H616 DRAM bit delay compensation" - ---help--- - Select this when DRAM on your H616 board needs bit delay - compensation. - -config DRAM_SUN50I_H616_UNKNOWN_FEATURE - bool "H616 DRAM unknown feature" - ---help--- - Select this when DRAM on your H616 board needs this unknown - feature. - config DRAM_SUN50I_H616_DX_ODT hex "H616 DRAM DX ODT parameter" help @@ -98,6 +66,12 @@ config DRAM_SUN50I_H616_CA_DRI hex "H616 DRAM CA DRI parameter" help CA DRI value from vendor DRAM settings. + +config DRAM_SUN50I_H616_TPR10 + hex "H616 DRAM TPR10 parameter" + help + TPR10 value from vendor DRAM settings. It tells which features + should be configured, like write leveling, read calibration, etc. endif config SUN6I_PRCM diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 06a07dfbf9cc..630c7c3be882 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -577,109 +577,112 @@ static bool mctl_phy_bit_delay_compensation(struct dram_para *para) u32 *ptr; int i; - clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x60, 1); - setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 8); - clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10); + if (para->tpr10 & TPR10_DX_BIT_DELAY1) { + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x60, 1); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 8); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10); - ptr = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x484); - for (i = 0; i < 9; i++) { - writel_relaxed(0x16, ptr); - writel_relaxed(0x16, ptr + 0x30); - ptr += 2; - } - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x4d0); - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x590); - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x4cc); - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x58c); + ptr = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x484); + for (i = 0; i < 9; i++) { + writel_relaxed(0x16, ptr); +
[PATCH v2 05/10] sunxi: Always configure ODT on H616 DRAM
Vendor H616 DRAM code always configure part which we call ODT configuration. Let's reflect that here too. Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/Kconfig| 2 +- arch/arm/mach-sunxi/dram_sun50i_h616.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 1b47a49f938c..4300d388e066 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -488,12 +488,12 @@ config DRAM_ZQ config DRAM_ODT_EN bool "sunxi dram odt enable" + depends on !MACH_SUN50I_H616 default y if MACH_SUN8I_A23 default y if MACH_SUNXI_H3_H5 default y if MACH_SUN8I_R40 default y if MACH_SUN50I default y if MACH_SUN50I_H6 - default y if MACH_SUN50I_H616 ---help--- Select this to enable dram odt (on die termination). diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 630c7c3be882..7d2434309b07 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -736,8 +736,7 @@ static bool mctl_phy_init(struct dram_para *para) writel(0x80, SUNXI_DRAM_PHY0_BASE + 0x3dc); writel(0x80, SUNXI_DRAM_PHY0_BASE + 0x45c); - if (IS_ENABLED(CONFIG_DRAM_ODT_EN)) - mctl_phy_configure_odt(para); + mctl_phy_configure_odt(para); clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 7, 0xa); -- 2.40.0
[PATCH v2 08/10] sunxi: Parameterize "unknown feature" in H616 DRAM driver
Part of the code, previously known as "unknown feature", also doesn't have constant values. They are derived from TPR0 parameter in vendor DRAM code. Let's move that code to separate function and introduce TPR0 parameter here too, to ease adding new boards. Signed-off-by: Jernej Skrabec --- .../include/asm/arch-sunxi/dram_sun50i_h616.h | 1 + arch/arm/mach-sunxi/Kconfig | 6 +++ arch/arm/mach-sunxi/dram_sun50i_h616.c| 47 ++- configs/x96_mate_defconfig| 1 + 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h index 034ba98bc243..615532c6eebb 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h @@ -156,6 +156,7 @@ struct dram_para { u32 dx_dri; u32 ca_dri; u32 odt_en; + u32 tpr0; u32 tpr10; u32 tpr11; u32 tpr12; diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 7b38e83c2d7e..fe34755f88ec 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -73,6 +73,12 @@ config DRAM_SUN50I_H616_ODT_EN help ODT EN value from vendor DRAM settings. +config DRAM_SUN50I_H616_TPR0 + hex "H616 DRAM TPR0 parameter" + default 0x0 + help + TPR0 value from vendor DRAM settings. + config DRAM_SUN50I_H616_TPR10 hex "H616 DRAM TPR10 parameter" help diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index f5d8718fefff..44bb15367beb 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -773,6 +773,39 @@ static void mctl_phy_bit_delay_compensation(struct dram_para *para) } } +static void mctl_phy_ca_bit_delay_compensation(struct dram_para *para) +{ + u32 val, *ptr; + int i; + + if (para->tpr0 & BIT(30)) + val = (para->tpr0 >> 7) & 0x3e; + else + val = (para->tpr10 >> 3) & 0x1e; + + ptr = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x780); + for (i = 0; i < 32; i++) + writel(val, [i]); + + val = (para->tpr10 << 1) & 0x1e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7dc); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7e0); + + /* following configuration is DDR3 specific */ + val = (para->tpr10 >> 7) & 0x1e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7d4); + if (para->ranks == 2) { + val = (para->tpr10 >> 11) & 0x1e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x79c); + } + if (para->tpr0 & BIT(31)) { + val = (para->tpr0 << 1) & 0x3e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x78c); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7a4); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7b8); + } +} + static bool mctl_phy_init(struct dram_para *para) { struct sunxi_mctl_com_reg * const mctl_com = @@ -807,17 +840,8 @@ static bool mctl_phy_init(struct dram_para *para) for (i = 0; i < ARRAY_SIZE(phy_init); i++) writel(phy_init[i], [i]); - if (para->tpr10 & TPR10_CA_BIT_DELAY) { - ptr = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x780); - for (i = 0; i < 32; i++) - writel(0x16, [i]); - writel(0xe, SUNXI_DRAM_PHY0_BASE + 0x78c); - writel(0xe, SUNXI_DRAM_PHY0_BASE + 0x7a4); - writel(0xe, SUNXI_DRAM_PHY0_BASE + 0x7b8); - writel(0x8, SUNXI_DRAM_PHY0_BASE + 0x7d4); - writel(0xe, SUNXI_DRAM_PHY0_BASE + 0x7dc); - writel(0xe, SUNXI_DRAM_PHY0_BASE + 0x7e0); - } + if (para->tpr10 & TPR10_CA_BIT_DELAY) + mctl_phy_ca_bit_delay_compensation(para); writel(0x80, SUNXI_DRAM_PHY0_BASE + 0x3dc); writel(0x80, SUNXI_DRAM_PHY0_BASE + 0x45c); @@ -1110,6 +1134,7 @@ unsigned long sunxi_dram_init(void) .dx_dri = CONFIG_DRAM_SUN50I_H616_DX_DRI, .ca_dri = CONFIG_DRAM_SUN50I_H616_CA_DRI, .odt_en = CONFIG_DRAM_SUN50I_H616_ODT_EN, + .tpr0 = CONFIG_DRAM_SUN50I_H616_TPR0, .tpr10 = CONFIG_DRAM_SUN50I_H616_TPR10, .tpr11 = CONFIG_DRAM_SUN50I_H616_TPR11, .tpr12 = CONFIG_DRAM_SUN50I_H616_TPR12, diff --git a/configs/x96_mate_defconfig b/configs/x96_mate_defconfig index acc64898da19..aedb3277022a 100644 --- a/configs/x96_mate_defconfig +++ b/configs/x96_mate_defconfig @@ -6,6 +6,7 @@ CONFIG_DRAM_SUN50I_H616_READ_CALIBRATION=y CONFIG_DRAM_SUN50I_H616_DX_ODT=0x03030303 CONFIG_DRAM_SUN50I_H616_DX_DRI=0x0e0e0e0e CONFIG_DRAM_SUN50I_H616_CA_DRI=0x1c12 +CONF
[PATCH v2 06/10] sunxi: Make bit delay function in H616 DRAM code void
Mentioned function result is always true and result isn't checked anyway. Let's make it void. Reviewed-by: Andre Przywara Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/dram_sun50i_h616.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 7d2434309b07..3fe45845b78e 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -572,7 +572,7 @@ static bool mctl_phy_write_training(struct dram_para *para) return result; } -static bool mctl_phy_bit_delay_compensation(struct dram_para *para) +static void mctl_phy_bit_delay_compensation(struct dram_para *para) { u32 *ptr; int i; @@ -683,8 +683,6 @@ static bool mctl_phy_bit_delay_compensation(struct dram_para *para) setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x54, 0x80); } - - return true; } static bool mctl_phy_init(struct dram_para *para) -- 2.40.0
[PATCH v2 03/10] sunxi: parameterize H616 DRAM ODT values
While ODT values for same memory type are similar, they are not necessary the same. Let's parameterize them and make parameter same as in vendor DRAM settings. That way it will be easy to introduce new board support. Reviewed-by: Andre Przywara Signed-off-by: Jernej Skrabec --- .../include/asm/arch-sunxi/dram_sun50i_h616.h | 3 + arch/arm/mach-sunxi/Kconfig | 15 + arch/arm/mach-sunxi/dram_sun50i_h616.c| 59 --- configs/orangepi_zero2_defconfig | 3 + configs/x96_mate_defconfig| 3 + 5 files changed, 61 insertions(+), 22 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h index 134679d55205..c9e1f84bfcdd 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h @@ -144,6 +144,9 @@ struct dram_para { u8 rows; u8 ranks; u8 bus_full_width; + u32 dx_odt; + u32 dx_dri; + u32 ca_dri; }; diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 6417aee944bc..14fb9a95905a 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -83,6 +83,21 @@ config DRAM_SUN50I_H616_UNKNOWN_FEATURE ---help--- Select this when DRAM on your H616 board needs this unknown feature. + +config DRAM_SUN50I_H616_DX_ODT + hex "H616 DRAM DX ODT parameter" + help + DX ODT value from vendor DRAM settings. + +config DRAM_SUN50I_H616_DX_DRI + hex "H616 DRAM DX DRI parameter" + help + DX DRI value from vendor DRAM settings. + +config DRAM_SUN50I_H616_CA_DRI + hex "H616 DRAM CA DRI parameter" + help + CA DRI value from vendor DRAM settings. endif config SUN6I_PRCM diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 49983bf7a1b8..06a07dfbf9cc 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -234,37 +234,49 @@ static const u8 phy_init[] = { 0x09, 0x05, 0x18 }; -static void mctl_phy_configure_odt(void) +static void mctl_phy_configure_odt(struct dram_para *para) { - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x388); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x38c); + unsigned int val; - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x3c8); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x3cc); + val = para->dx_dri & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x388); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x38c); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x408); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x40c); + val = (para->dx_dri >> 8) & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x3c8); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x3cc); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x448); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x44c); + val = (para->dx_dri >> 16) & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x408); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x40c); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x340); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x344); + val = (para->dx_dri >> 24) & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x448); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x44c); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x348); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x34c); + val = para->ca_dri & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x340); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x344); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x380); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x384); + val = (para->ca_dri >> 8) & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x348); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x34c); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x3c0); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x3c4); + val = para->dx_odt & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x380); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x384); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x400); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x404); + val = (para->dx_odt >> 8) & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x3c0); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x3c4); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x440); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x444); + val = (para->dx_odt >> 16) & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x400); +
[PATCH v2 02/10] sunxi: cosmetic: Fix H616 DRAM driver code style
Fix code style for pointer declaration. This is just cosmetic change to avoid checkpatch errors in later commits. Reviewed-by: Andre Przywara Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/dram_sun50i_h616.c | 74 +- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 039e76224367..49983bf7a1b8 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -285,7 +285,7 @@ static bool mctl_phy_write_leveling(struct dram_para *para) else val = 3; - mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x188), val, val); + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x188), val, val); clrbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 4); @@ -314,7 +314,7 @@ static bool mctl_phy_write_leveling(struct dram_para *para) else val = 3; - mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x188), val, val); + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x188), val, val); clrbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 4); } @@ -398,26 +398,26 @@ static bool mctl_phy_read_training(struct dram_para *para) setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 6); setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 1); - mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x840), 0xc, 0xc); + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x840), 0xc, 0xc); if (readl(SUNXI_DRAM_PHY0_BASE + 0x840) & 3) result = false; if (para->bus_full_width) { - mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0xa40), 0xc, 0xc); + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa40), 0xc, 0xc); if (readl(SUNXI_DRAM_PHY0_BASE + 0xa40) & 3) result = false; } - ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x898); - ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x850); + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x898); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x850); for (i = 0; i < 9; i++) { val1 = readl([i]); val2 = readl([i]); if (val1 - val2 <= 6) result = false; } - ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x8bc); - ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x874); + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x8bc); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x874); for (i = 0; i < 9; i++) { val1 = readl([i]); val2 = readl([i]); @@ -426,8 +426,8 @@ static bool mctl_phy_read_training(struct dram_para *para) } if (para->bus_full_width) { - ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xa98); - ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xa50); + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa98); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa50); for (i = 0; i < 9; i++) { val1 = readl([i]); val2 = readl([i]); @@ -435,8 +435,8 @@ static bool mctl_phy_read_training(struct dram_para *para) result = false; } - ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xabc); - ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xa74); + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xabc); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa74); for (i = 0; i < 9; i++) { val1 = readl([i]); val2 = readl([i]); @@ -454,12 +454,12 @@ static bool mctl_phy_read_training(struct dram_para *para) setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 6); setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 1); - mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x840), 0xc, 0xc); + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x840), 0xc, 0xc); if (readl(SUNXI_DRAM_PHY0_BASE + 0x840) & 3) result = false; if (para->bus_full_width) { - mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0xa40), 0xc, 0xc); + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa40), 0xc, 0xc); if (readl(SUNXI_DRAM_PHY0_BASE + 0xa40) & 3) result = false; } @@ -488,26 +488,26 @@ static bool mctl_phy_write_training(struct dram_para *para) setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10); setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x20); - mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x8e0), 3, 3); + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0
[PATCH v2 01/10] sunxi: Fix write to H616 DRAM CR register
Vendor DRAM code actually writes to whole CR register and not just sets bit 31 in mctl_ctrl_init(). Just to be safe, do that here too. Acked-by: Andre Przywara Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/dram_sun50i_h616.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 454c845a0010..039e76224367 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -873,7 +873,7 @@ static bool mctl_ctrl_init(struct dram_para *para) writel(0x06000400, _ctl->unk_0x3240); writel(0x06000400, _ctl->unk_0x4240); - setbits_le32(_com->cr, BIT(31)); + writel(BIT(31), _com->cr); mctl_set_addrmap(para); -- 2.40.0
[PATCH v2 00/10] sunxi: Update H616 DRAM driver
Current H616 DRAM driver is completely customized to Orange Pi Zero2 board, which is only one of two H616 boards supported by U-Boot. Needless to say, this is not ideal for adding new boards. With changes in this series, all DDR3 boards are supported and all that is needed is just vendor DRAM values extracted from Android image. New DRAM types should also be easier to support, since a lot of constants used before are not really DRAM type dependent. Changes were verified by decompiling driver and generated values were compared to previous, hard coded ones. This was done without dram_para structures, so compiler was able to heavily optimize code and produce constants. Please take a look. Best regards, Jernej Changes from v1: - added tags - updated dram config macros to have 8 or 4 nibbles - renamed unknown macros to something useful when known - removed unknown macro when not known what it does - added patch 9 and 10 which introduces TPR2 (needed on one h313 board) - update commit subjects Jernej Skrabec (10): sunxi: Fix write to H616 DRAM CR register sunxi: cosmetic: Fix H616 DRAM driver code style sunxi: parameterize H616 DRAM ODT values sunxi: Convert H616 DRAM options to single setting sunxi: Always configure ODT on H616 DRAM sunxi: Make bit delay function in H616 DRAM code void sunxi: Parameterize bit delay code in H616 DRAM driver sunxi: Parameterize "unknown feature" in H616 DRAM driver sunxi: Parameterize some of H616 DDR3 timings sunxi: Add TPR2 parameter for H616 DRAM driver .../include/asm/arch-sunxi/dram_sun50i_h616.h | 17 + arch/arm/mach-sunxi/Kconfig | 83 +-- arch/arm/mach-sunxi/dram_sun50i_h616.c| 530 -- .../mach-sunxi/dram_timings/h616_ddr3_1333.c | 20 +- configs/orangepi_zero2_defconfig | 8 +- configs/x96_mate_defconfig| 7 + 6 files changed, 442 insertions(+), 223 deletions(-) -- 2.40.0
[PATCH 7/8] sunxi: Parameterize bit delay code in H616 DRAM driver
These values are highly board specific and thus make sense to add parameter for them. To ease adding support for new boards, let's make them same as in vendor DRAM settings. Signed-off-by: Jernej Skrabec --- .../include/asm/arch-sunxi/dram_sun50i_h616.h | 4 + arch/arm/mach-sunxi/Kconfig | 18 ++ arch/arm/mach-sunxi/dram_sun50i_h616.c| 189 +- 3 files changed, 162 insertions(+), 49 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h index b5140c79b70e..c7890c83391f 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h @@ -145,6 +145,7 @@ check_member(sunxi_mctl_ctl_reg, unk_0x4240, 0x4240); #define TPR10_READ_CALIBRATION BIT(21) #define TPR10_READ_TRAININGBIT(22) #define TPR10_WRITE_TRAINING BIT(23) +#define TPR10_UNKNOWN_FEAT3BIT(30) struct dram_para { u32 clk; @@ -156,7 +157,10 @@ struct dram_para { u32 dx_odt; u32 dx_dri; u32 ca_dri; + u32 odt_en; u32 tpr10; + u32 tpr11; + u32 tpr12; }; diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 778304b77e26..b050f0a56971 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -67,11 +67,29 @@ config DRAM_SUN50I_H616_CA_DRI help CA DRI value from vendor DRAM settings. +config DRAM_SUN50I_H616_ODT_EN + hex "H616 DRAM ODT EN parameter" + default 0x1 + help + ODT EN value from vendor DRAM settings. + config DRAM_SUN50I_H616_TPR10 hex "H616 DRAM TPR10 parameter" help TPR10 value from vendor DRAM settings. It tells which features should be configured, like write leveling, read calibration, etc. + +config DRAM_SUN50I_H616_TPR11 + hex "H616 DRAM TPR11 parameter" + default 0x0 + help + TPR11 value from vendor DRAM settings. + +config DRAM_SUN50I_H616_TPR12 + hex "H616 DRAM TPR12 parameter" + default 0x0 + help + TPR12 value from vendor DRAM settings. endif config SUN6I_PRCM diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 3b2ba168498c..df06cea42464 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -574,7 +574,7 @@ static bool mctl_phy_write_training(struct dram_para *para) static void mctl_phy_bit_delay_compensation(struct dram_para *para) { - u32 *ptr; + u32 *ptr, val; int i; if (para->tpr10 & TPR10_UNKNOWN_FEAT2) { @@ -582,49 +582,93 @@ static void mctl_phy_bit_delay_compensation(struct dram_para *para) setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 8); clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10); + if (para->tpr10 & TPR10_UNKNOWN_FEAT3) + val = para->tpr11 & 0x3f; + else + val = (para->tpr11 & 0xf) << 1; + ptr = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x484); for (i = 0; i < 9; i++) { - writel_relaxed(0x16, ptr); - writel_relaxed(0x16, ptr + 0x30); + writel_relaxed(val, ptr); + writel_relaxed(val, ptr + 0x30); ptr += 2; } - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x4d0); - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x590); - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x4cc); - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x58c); + + if (para->tpr10 & TPR10_UNKNOWN_FEAT3) + val = (para->odt_en >> 15) & 0x1e; + else + val = (para->tpr11 >> 15) & 0x1e; + + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x4d0); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x590); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x4cc); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x58c); + + if (para->tpr10 & TPR10_UNKNOWN_FEAT3) + val = (para->tpr11 >> 8) & 0x3f; + else + val = (para->tpr11 >> 3) & 0x1e; ptr = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x4d8); for (i = 0; i < 9; i++) { - writel_relaxed(0x1a, ptr); - writel_relaxed(0x1a, ptr + 0x30); + writel_relaxed(val, ptr); + writel_relaxed(val, ptr + 0x30); ptr += 2; } - writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x524); - writ
[PATCH 8/8] sunxi: Parameterize H616 DRAM code some more
Part of the code, previously known as "unknown feature" also doesn't have constant values. They are derived from TPR0 parameter in vendor DRAM code. Introduce that parameter here too, to ease adding new boards. Signed-off-by: Jernej Skrabec --- .../include/asm/arch-sunxi/dram_sun50i_h616.h | 1 + arch/arm/mach-sunxi/Kconfig | 6 arch/arm/mach-sunxi/dram_sun50i_h616.c| 35 +++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h index c7890c83391f..ff736bd88d10 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h @@ -158,6 +158,7 @@ struct dram_para { u32 dx_dri; u32 ca_dri; u32 odt_en; + u32 tpr0; u32 tpr10; u32 tpr11; u32 tpr12; diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index b050f0a56971..7858a7045f7e 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -73,6 +73,12 @@ config DRAM_SUN50I_H616_ODT_EN help ODT EN value from vendor DRAM settings. +config DRAM_SUN50I_H616_TPR0 + hex "H616 DRAM TPR0 parameter" + default 0x0 + help + TPR0 value from vendor DRAM settings. + config DRAM_SUN50I_H616_TPR10 hex "H616 DRAM TPR10 parameter" help diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index df06cea42464..6d8f8d371bfe 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -808,15 +808,35 @@ static bool mctl_phy_init(struct dram_para *para) writel(phy_init[i], [i]); if (para->tpr10 & TPR10_UNKNOWN_FEAT0) { + if (para->tpr0 & BIT(30)) + val = (para->tpr0 >> 7) & 0x3e; + else + val = (para->tpr10 >> 3) & 0x1e; + ptr = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x780); for (i = 0; i < 32; i++) - writel(0x16, [i]); - writel(0xe, SUNXI_DRAM_PHY0_BASE + 0x78c); - writel(0xe, SUNXI_DRAM_PHY0_BASE + 0x7a4); - writel(0xe, SUNXI_DRAM_PHY0_BASE + 0x7b8); - writel(0x8, SUNXI_DRAM_PHY0_BASE + 0x7d4); - writel(0xe, SUNXI_DRAM_PHY0_BASE + 0x7dc); - writel(0xe, SUNXI_DRAM_PHY0_BASE + 0x7e0); + writel(val, [i]); + + val = (para->tpr10 << 1) & 0x1e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7dc); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7e0); + + /* following configuration is DDR3 specific */ + val = (para->tpr10 >> 7) & 0x1e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7d4); + /* +* TODO: Offsets 0x79c, 0x794 and 0x7e4 may need +* to be set here. However, this doesn't seem to +* be needed by any board seen in the wild for now. +* It's not implemented because it would unnecessarily +* introduce PARA2 and TPR2 options. +*/ + if (para->tpr0 & BIT(31)) { + val = (para->tpr0 << 1) & 0x3e; + writel(val, SUNXI_DRAM_PHY0_BASE + 0x78c); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7a4); + writel(val, SUNXI_DRAM_PHY0_BASE + 0x7b8); + } } writel(0x80, SUNXI_DRAM_PHY0_BASE + 0x3dc); @@ -1110,6 +1130,7 @@ unsigned long sunxi_dram_init(void) .dx_dri = CONFIG_DRAM_SUN50I_H616_DX_DRI, .ca_dri = CONFIG_DRAM_SUN50I_H616_CA_DRI, .odt_en = CONFIG_DRAM_SUN50I_H616_ODT_EN, + .tpr0 = CONFIG_DRAM_SUN50I_H616_TPR0, .tpr10 = CONFIG_DRAM_SUN50I_H616_TPR10, .tpr11 = CONFIG_DRAM_SUN50I_H616_TPR11, .tpr12 = CONFIG_DRAM_SUN50I_H616_TPR12, -- 2.38.1
[PATCH 6/8] sunxi: Make bit delay function in H616 DRAM code void
Mentioned function result is always true and result isn't checked anyway. Let's make it void. Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/dram_sun50i_h616.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index bf5b4ddfb5c2..3b2ba168498c 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -572,7 +572,7 @@ static bool mctl_phy_write_training(struct dram_para *para) return result; } -static bool mctl_phy_bit_delay_compensation(struct dram_para *para) +static void mctl_phy_bit_delay_compensation(struct dram_para *para) { u32 *ptr; int i; @@ -683,8 +683,6 @@ static bool mctl_phy_bit_delay_compensation(struct dram_para *para) setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x54, 0x80); } - - return true; } static bool mctl_phy_init(struct dram_para *para) -- 2.38.1
[PATCH 5/8] sunxi: Always configure ODT on H616 DRAM
Vendor H616 DRAM code always configure part which we call ODT configuration. Let's reflect that here too. Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/Kconfig| 2 +- arch/arm/mach-sunxi/dram_sun50i_h616.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index abcbd0fb9061..778304b77e26 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -488,12 +488,12 @@ config DRAM_ZQ config DRAM_ODT_EN bool "sunxi dram odt enable" + depends on !MACH_SUN50I_H616 default y if MACH_SUN8I_A23 default y if MACH_SUNXI_H3_H5 default y if MACH_SUN8I_R40 default y if MACH_SUN50I default y if MACH_SUN50I_H6 - default y if MACH_SUN50I_H616 ---help--- Select this to enable dram odt (on die termination). diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 14a01a3c4e54..bf5b4ddfb5c2 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -736,8 +736,7 @@ static bool mctl_phy_init(struct dram_para *para) writel(0x80, SUNXI_DRAM_PHY0_BASE + 0x3dc); writel(0x80, SUNXI_DRAM_PHY0_BASE + 0x45c); - if (IS_ENABLED(CONFIG_DRAM_ODT_EN)) - mctl_phy_configure_odt(para); + mctl_phy_configure_odt(para); clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 7, 0xa); -- 2.38.1
[PATCH 3/8] sunxi: parameterize H616 DRAM ODT values
While ODT values for same memory type are similar, they are not necessary the same. Let's parameterize them and make parameter same as in vendor DRAM settings. That way it will be easy to introduce new board support. Signed-off-by: Jernej Skrabec --- .../include/asm/arch-sunxi/dram_sun50i_h616.h | 3 + arch/arm/mach-sunxi/Kconfig | 15 + arch/arm/mach-sunxi/dram_sun50i_h616.c| 59 --- configs/orangepi_zero2_defconfig | 3 + 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h index 134679d55205..c9e1f84bfcdd 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h @@ -144,6 +144,9 @@ struct dram_para { u8 rows; u8 ranks; u8 bus_full_width; + u32 dx_odt; + u32 dx_dri; + u32 ca_dri; }; diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index dbe6005daab1..cad53f19912c 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -83,6 +83,21 @@ config DRAM_SUN50I_H616_UNKNOWN_FEATURE ---help--- Select this when DRAM on your H616 board needs this unknown feature. + +config DRAM_SUN50I_H616_DX_ODT + hex "H616 DRAM DX ODT parameter" + help + DX ODT value from vendor DRAM settings. + +config DRAM_SUN50I_H616_DX_DRI + hex "H616 DRAM DX DRI parameter" + help + DX DRI value from vendor DRAM settings. + +config DRAM_SUN50I_H616_CA_DRI + hex "H616 DRAM CA DRI parameter" + help + CA DRI value from vendor DRAM settings. endif config SUN6I_PRCM diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 49983bf7a1b8..06a07dfbf9cc 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -234,37 +234,49 @@ static const u8 phy_init[] = { 0x09, 0x05, 0x18 }; -static void mctl_phy_configure_odt(void) +static void mctl_phy_configure_odt(struct dram_para *para) { - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x388); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x38c); + unsigned int val; - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x3c8); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x3cc); + val = para->dx_dri & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x388); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x38c); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x408); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x40c); + val = (para->dx_dri >> 8) & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x3c8); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x3cc); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x448); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x44c); + val = (para->dx_dri >> 16) & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x408); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x40c); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x340); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x344); + val = (para->dx_dri >> 24) & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x448); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x44c); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x348); - writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x34c); + val = para->ca_dri & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x340); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x344); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x380); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x384); + val = (para->ca_dri >> 8) & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x348); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x34c); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x3c0); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x3c4); + val = para->dx_odt & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x380); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x384); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x400); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x404); + val = (para->dx_odt >> 8) & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x3c0); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x3c4); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x440); - writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x444); + val = (para->dx_odt >> 16) & 0x1f; + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x400); + writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x404); + + val = (para->dx_od
[PATCH 4/8] sunxi: Convert H616 DRAM options to single setting
Vendor DRAM settings use TPR10 parameter to enable various features. There are many mores features that just those that are currently mentioned. Since new will be added later and most are not known, let's reuse value from vendor DRAM driver as-is. This will also help adding support for new boards. Signed-off-by: Jernej Skrabec --- .../include/asm/arch-sunxi/dram_sun50i_h616.h | 10 + arch/arm/mach-sunxi/Kconfig | 38 +--- arch/arm/mach-sunxi/dram_sun50i_h616.c| 197 +- configs/orangepi_zero2_defconfig | 5 +- 4 files changed, 117 insertions(+), 133 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h index c9e1f84bfcdd..b5140c79b70e 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h @@ -137,6 +137,15 @@ check_member(sunxi_mctl_ctl_reg, unk_0x4240, 0x4240); #define MSTR_ACTIVE_RANKS(x) (((x == 2) ? 3 : 1) << 24) #define MSTR_BURST_LENGTH(x) (((x) >> 1) << 16) +/* TODO: figure out what unknown features do */ +#define TPR10_UNKNOWN_FEAT0BIT(16) +#define TPR10_UNKNOWN_FEAT1BIT(17) +#define TPR10_UNKNOWN_FEAT2BIT(18) +#define TPR10_WRITE_LEVELING BIT(20) +#define TPR10_READ_CALIBRATION BIT(21) +#define TPR10_READ_TRAININGBIT(22) +#define TPR10_WRITE_TRAINING BIT(23) + struct dram_para { u32 clk; enum sunxi_dram_type type; @@ -147,6 +156,7 @@ struct dram_para { u32 dx_odt; u32 dx_dri; u32 ca_dri; + u32 tpr10; }; diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index cad53f19912c..abcbd0fb9061 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -52,38 +52,6 @@ config DRAM_SUN50I_H616 like H616. if DRAM_SUN50I_H616 -config DRAM_SUN50I_H616_WRITE_LEVELING - bool "H616 DRAM write leveling" - ---help--- - Select this when DRAM on your H616 board needs write leveling. - -config DRAM_SUN50I_H616_READ_CALIBRATION - bool "H616 DRAM read calibration" - ---help--- - Select this when DRAM on your H616 board needs read calibration. - -config DRAM_SUN50I_H616_READ_TRAINING - bool "H616 DRAM read training" - ---help--- - Select this when DRAM on your H616 board needs read training. - -config DRAM_SUN50I_H616_WRITE_TRAINING - bool "H616 DRAM write training" - ---help--- - Select this when DRAM on your H616 board needs write training. - -config DRAM_SUN50I_H616_BIT_DELAY_COMPENSATION - bool "H616 DRAM bit delay compensation" - ---help--- - Select this when DRAM on your H616 board needs bit delay - compensation. - -config DRAM_SUN50I_H616_UNKNOWN_FEATURE - bool "H616 DRAM unknown feature" - ---help--- - Select this when DRAM on your H616 board needs this unknown - feature. - config DRAM_SUN50I_H616_DX_ODT hex "H616 DRAM DX ODT parameter" help @@ -98,6 +66,12 @@ config DRAM_SUN50I_H616_CA_DRI hex "H616 DRAM CA DRI parameter" help CA DRI value from vendor DRAM settings. + +config DRAM_SUN50I_H616_TPR10 + hex "H616 DRAM TPR10 parameter" + help + TPR10 value from vendor DRAM settings. It tells which features + should be configured, like write leveling, read calibration, etc. endif config SUN6I_PRCM diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 06a07dfbf9cc..14a01a3c4e54 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -577,109 +577,112 @@ static bool mctl_phy_bit_delay_compensation(struct dram_para *para) u32 *ptr; int i; - clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x60, 1); - setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 8); - clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10); + if (para->tpr10 & TPR10_UNKNOWN_FEAT2) { + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x60, 1); + setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 8); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10); - ptr = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x484); - for (i = 0; i < 9; i++) { - writel_relaxed(0x16, ptr); - writel_relaxed(0x16, ptr + 0x30); - ptr += 2; - } - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x4d0); - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x590); - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x4cc); - writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x58c); + ptr = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x484); + for (i = 0; i < 9; i++) { + writel_relaxed(0x16, ptr); +
[PATCH 2/8] sunxi: cosmetic: Fix H616 DRAM driver code style
Fix code style for pointer declaration. This is just cosmetic change to avoid checkpatch errors in later commits. Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/dram_sun50i_h616.c | 74 +- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 039e76224367..49983bf7a1b8 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -285,7 +285,7 @@ static bool mctl_phy_write_leveling(struct dram_para *para) else val = 3; - mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x188), val, val); + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x188), val, val); clrbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 4); @@ -314,7 +314,7 @@ static bool mctl_phy_write_leveling(struct dram_para *para) else val = 3; - mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x188), val, val); + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x188), val, val); clrbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 4); } @@ -398,26 +398,26 @@ static bool mctl_phy_read_training(struct dram_para *para) setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 6); setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 1); - mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x840), 0xc, 0xc); + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x840), 0xc, 0xc); if (readl(SUNXI_DRAM_PHY0_BASE + 0x840) & 3) result = false; if (para->bus_full_width) { - mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0xa40), 0xc, 0xc); + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa40), 0xc, 0xc); if (readl(SUNXI_DRAM_PHY0_BASE + 0xa40) & 3) result = false; } - ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x898); - ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x850); + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x898); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x850); for (i = 0; i < 9; i++) { val1 = readl([i]); val2 = readl([i]); if (val1 - val2 <= 6) result = false; } - ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x8bc); - ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x874); + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x8bc); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x874); for (i = 0; i < 9; i++) { val1 = readl([i]); val2 = readl([i]); @@ -426,8 +426,8 @@ static bool mctl_phy_read_training(struct dram_para *para) } if (para->bus_full_width) { - ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xa98); - ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xa50); + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa98); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa50); for (i = 0; i < 9; i++) { val1 = readl([i]); val2 = readl([i]); @@ -435,8 +435,8 @@ static bool mctl_phy_read_training(struct dram_para *para) result = false; } - ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xabc); - ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xa74); + ptr1 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xabc); + ptr2 = (u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa74); for (i = 0; i < 9; i++) { val1 = readl([i]); val2 = readl([i]); @@ -454,12 +454,12 @@ static bool mctl_phy_read_training(struct dram_para *para) setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 6); setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 1); - mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x840), 0xc, 0xc); + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x840), 0xc, 0xc); if (readl(SUNXI_DRAM_PHY0_BASE + 0x840) & 3) result = false; if (para->bus_full_width) { - mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0xa40), 0xc, 0xc); + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0xa40), 0xc, 0xc); if (readl(SUNXI_DRAM_PHY0_BASE + 0xa40) & 3) result = false; } @@ -488,26 +488,26 @@ static bool mctl_phy_write_training(struct dram_para *para) setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10); setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x20); - mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x8e0), 3, 3); + mctl_await_completion((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x8e0), 3, 3); if (r
[PATCH 1/8] sunxi: Fix write to H616 DRAM CR register
Vendor DRAM code actually writes to whole CR register and not just sets bit 31 in mctl_ctrl_init(). Just to be safe, do that here too. Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/dram_sun50i_h616.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 454c845a0010..039e76224367 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -873,7 +873,7 @@ static bool mctl_ctrl_init(struct dram_para *para) writel(0x06000400, _ctl->unk_0x3240); writel(0x06000400, _ctl->unk_0x4240); - setbits_le32(_com->cr, BIT(31)); + writel(BIT(31), _com->cr); mctl_set_addrmap(para); -- 2.38.1
[PATCH 0/8] sunxi: Update H616 DRAM driver
Current H616 DRAM driver is completely customized to Orange Pi Zero2 board, which is currently the only H616 board supported by U-Boot. Needless to say, this is not ideal for adding new boards. With changes in this series, all DDR3 boards are supported and all that is needed is just vendor DRAM values extracted from Android image. New DRAM types should also be easier to support, since a lot of constants used before are not really DRAM type dependent. Changes were verified by decompiling driver and generated values were compared to previous, hard coded ones. This was done without dram_para structures, so compiler was able to heavily optimize code and produce constants. Please take a look. Best regards, Jernej Jernej Skrabec (8): sunxi: Fix write to H616 DRAM CR register sunxi: cosmetic: Fix H616 DRAM driver code style sunxi: parameterize H616 DRAM ODT values sunxi: Convert H616 DRAM options to single setting sunxi: Always configure ODT on H616 DRAM sunxi: Make bit delay function in H616 DRAM code void sunxi: Parameterize bit delay code in H616 DRAM driver sunxi: Parameterize H616 DRAM code some more .../include/asm/arch-sunxi/dram_sun50i_h616.h | 18 + arch/arm/mach-sunxi/Kconfig | 67 +-- arch/arm/mach-sunxi/dram_sun50i_h616.c| 445 +++--- configs/orangepi_zero2_defconfig | 8 +- 4 files changed, 348 insertions(+), 190 deletions(-) -- 2.38.1
[PATCH 3/3] 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 --- 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 32119ad16555..7926394cf762 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(>res_cal_ctrl, 1); setbits_le32(>res_cal_ctrl, 1); + if (IS_ENABLED(CONFIG_MACH_SUN50I_H6)) { + /* set key field for ldo enable */ + setbits_le32(>pll_ldo_cfg, 0xA700); + /* set PLL VDD LDO output to 1.14 V */ + setbits_le32(>pll_ldo_cfg, 0x6); + } + clock_set_pll1(40800); writel(CCM_PLL6_DEFAULT, >pll6_cfg); -- 2.35.1
[PATCH 2/3] 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 --- 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 e5846e6381ff..32119ad16555 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(>sys_pwroff_gating, 0x10); + setbits_le32(>res_cal_ctrl, 2); + } + + clrbits_le32(>res_cal_ctrl, 1); + setbits_le32(>res_cal_ctrl, 1); clock_set_pll1(40800); -- 2.35.1
[PATCH 1/3] 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 --- 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 5f636e83845a..fd63d3aad839 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 a947463e0a53..e5846e6381ff 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(>sys_pwroff_gating, 0x10); clock_set_pll1(40800); diff --git a/arch/arm/mach-sunxi/dram_sun50i_h6.c b/arch/arm/mach-sunxi/dram_sun50i_h6.c index d05375c90277..b332f3a3e4aa 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(>res_cal_ctrl, BIT(8)); + clrbits_le32(>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 83e8abc2f8d8..454c845a0010 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(>res_cal_ctrl, BIT(8)); + clrbits_le32(>ohms240, 0x3f); mctl_auto_detect_rank_width(); mctl_auto_detect_dram_size(); -- 2.35.1
[PATCH 0/3] sunxi: H6/H616: PRCM updates
During H616 boot0 blob and H6 boot0 sources analysis, I noticed that SPL doesn't set resistor calibration and PLL LDO on H6. Tests didn't show any observable difference, but nevertheless it's better to mimick boot0 behaviour. In the process I also added names for few PRCM registers so it's clearer what code does. Please take a look. Best regards, Jernej Jernej Skrabec (3): sunxi: prcm: Add a few registers sunxi: clock: H6/H616: Add resistor calibration sunxi: clock: H6: Adjust PLL LDO before clock setup arch/arm/include/asm/arch-sunxi/prcm_sun50i.h | 10 ++ arch/arm/mach-sunxi/clock_sun50i_h6.c | 20 --- arch/arm/mach-sunxi/dram_sun50i_h6.c | 8 +--- arch/arm/mach-sunxi/dram_sun50i_h616.c| 7 +-- 4 files changed, 37 insertions(+), 8 deletions(-) -- 2.35.1
[PATCH 2/2] sunxi: Fix H616 DRAM read calibration for dual rank
Although it isn't known what bit 0 in PHY reg 8 does, it's obvious that it has to be set before read calibration and cleared afterwards. This is already done for first rank, but not for second (copy & paste error.) Fix it. Fixes: f4317dbd06b6 ("sunxi: Add H616 DRAM support") Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/dram_sun50i_h616.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index 76f520f4e780..83e8abc2f8d8 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -360,7 +360,7 @@ static bool mctl_phy_read_calibration(struct dram_para *para) } } - setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 1); + clrbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 1); } clrbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 0x30); -- 2.35.0
[PATCH 1/2] sunxi: fix H616 DRAM ODT support
Kconfig symbol is missing CONFIG_ prefix, so compiler will always skip ODT configuration. Fix symbol name. Fixes: f4317dbd06b6 ("sunxi: Add H616 DRAM support") Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/dram_sun50i_h616.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index acdfb3ceef8c..76f520f4e780 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -720,7 +720,7 @@ static bool mctl_phy_init(struct dram_para *para) writel(0x80, SUNXI_DRAM_PHY0_BASE + 0x3dc); writel(0x80, SUNXI_DRAM_PHY0_BASE + 0x45c); - if (IS_ENABLED(DRAM_ODT_EN)) + if (IS_ENABLED(CONFIG_DRAM_ODT_EN)) mctl_phy_configure_odt(); clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 7, 0xa); -- 2.35.0
[PATCH 0/2] sunxi: Fix two H616 DRAM bugs
At closer inspection of H616 DRAM code I found two issues: 1. ODT is never configured due to missing CONFIG_ prefix in check 2. Dual rank read calibration never exits calibration mode Only first issue is important to fix for currently supported boards. Fixing second one is future proofing. Please take a look. Best regards, Jernej Jernej Skrabec (2): sunxi: fix H616 DRAM ODT support sunxi: Fix H616 DRAM read calibration for dual rank arch/arm/mach-sunxi/dram_sun50i_h616.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) -- 2.35.0
[PATCH] sunxi: call fdt_fixup_ethernet again to set macaddr for more aliases
From: Icenowy Zheng Sometimes some ethernet aliases do not exist in U-Boot DT but they exist in the DT used to boot the system (for example, modified via DT overlays). In this situation setup_environment is called again in ft_board_setup() to generate macaddr environment variable for them. However now the call to fdt_fixup_ethernet() is moved before the call of ft_board_setup(). Call fdt_fixup_ethernet() again to add MAC addresses for the extra ethernet aliases. Signed-off-by: Icenowy Zheng [updated commit message] Signed-off-by: Jernej Skrabec --- Hi all, this is effectively resend of: https://patchwork.ozlabs.org/project/uboot/patch/20171027093439.12414-1-icen...@aosc.io/ On at least one board, namely BananaPi M2 Zero, adding ethernet connector is pretty popular after market modification. Since this is not something that is already present on the board, ethernet node will never be part of upstream DT. Thus, the only sensible solution is to use DT overlay, which adds node to DT (maintaining patches is tedious). However, when overlays are used, U-Boot misses injecting MAC address, as described in commit message. Please reconsider this patch for inclusion in upstream. Best regards, Jernej board/sunxi/board.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 1a46100e408d..97554d4642ed 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -997,10 +997,12 @@ int ft_board_setup(void *blob, struct bd_info *bd) int __maybe_unused r; /* -* Call setup_environment again in case the boot fdt has -* ethernet aliases the u-boot copy does not have. +* Call setup_environment and fdt_fixup_ethernet again +* in case the boot fdt has ethernet aliases the u-boot +* copy does not have. */ setup_environment(blob); + fdt_fixup_ethernet(blob); bluetooth_dt_fixup(blob); -- 2.33.0
[PATCH] mailmap: Update e-mail for Jernej Skrabec
Old address doesn't exist anymore. Map it to new one. Signed-off-by: Jernej Skrabec --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index b76f02283c57..3d15a09d1c2d 100644 --- a/.mailmap +++ b/.mailmap @@ -29,6 +29,7 @@ Jagan Teki Jagan Teki Jagan Teki Jagan Teki +Jernej Skrabec Igor Opaniuk Igor Opaniuk Markus Klotzbuecher -- 2.33.0
[PATCH] configs: OrangePi PC2: Update defaults
OrangePi PC2 board has DRAM with ODT, so enable it. ZQ value is also slightly different in vendor images, so update it as well. H5 SoC is also connected to voltage regulator. It's default value is pretty low, so in order to avoid instability, enable driver for it and set it to appropriate voltage. Signed-off-by: Jernej Skrabec --- configs/orangepi_pc2_defconfig | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/configs/orangepi_pc2_defconfig b/configs/orangepi_pc2_defconfig index f72ffe27b26c..5e4cca793f53 100644 --- a/configs/orangepi_pc2_defconfig +++ b/configs/orangepi_pc2_defconfig @@ -3,13 +3,15 @@ CONFIG_ARCH_SUNXI=y CONFIG_SPL=y CONFIG_MACH_SUN50I_H5=y CONFIG_DRAM_CLK=672 -CONFIG_DRAM_ZQ=3881977 -# CONFIG_DRAM_ODT_EN is not set +CONFIG_DRAM_ZQ=4145117 CONFIG_MACPWR="PD6" CONFIG_SPL_SPI_SUNXI=y +CONFIG_SPL_I2C_SUPPORT=y CONFIG_DEFAULT_DEVICE_TREE="sun50i-h5-orangepi-pc2" # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set CONFIG_SUN8I_EMAC=y +CONFIG_SY8106A_POWER=y +CONFIG_SY8106A_VOUT1_VOLT=1100 CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_MUSB_GADGET=y -- 2.31.1
[PATCH v2] sunxi: add fdtoverlay_addr_r environment variable
Commit 69076dff2284 ("cmd: pxe: add support for FDT overlays") added support for loading DT overlay files to PXE boot. However, it needs additional environment variable which points to memory location which can be used to temporary store overlay data. Add it and in the process unify alignment using spaces and fix comment. Reviewed-by: Andre Przywara Signed-off-by: Jernej Skrabec --- Changes from v1: - added r-b tag - fixed comment include/configs/sunxi-common.h | 49 ++ 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index ded5aea551d3..3e1dc47c9c55 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -62,7 +62,7 @@ #define SDRAM_OFFSET(x) 0x2##x #define CONFIG_SYS_SDRAM_BASE 0x2000 #define CONFIG_SYS_LOAD_ADDR 0x2200 /* default load address */ -/* Note SPL_STACK_R_ADDR is set through Kconfig, we include it here +/* Note SPL_STACK_R_ADDR is set through Kconfig, we include it here * since it needs to fit in with the other values. By also #defining it * we get warnings if the Kconfig value mismatches. */ #define CONFIG_SPL_STACK_R_ADDR0x2fe0 @@ -72,7 +72,7 @@ #define CONFIG_SYS_SDRAM_BASE 0x4000 #define CONFIG_SYS_LOAD_ADDR 0x4200 /* default load address */ /* V3s do not have enough memory to place code at 0x4a00 */ -/* Note SPL_STACK_R_ADDR is set through Kconfig, we include it here +/* Note SPL_STACK_R_ADDR is set through Kconfig, we include it here * since it needs to fit in with the other values. By also #defining it * we get warnings if the Kconfig value mismatches. */ #define CONFIG_SPL_STACK_R_ADDR0x4fe0 @@ -257,40 +257,42 @@ extern int soft_i2c_gpio_scl; * There is no compression for arm64 kernels (yet), so leave some space * for really big kernels, say 256MB for now. * Scripts, PXE and DTBs should go afterwards, leaving the rest for the initrd. - * Align the initrd to a 2MB page. */ -#define BOOTM_SIZE __stringify(0xa00) -#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(008)) -#define FDT_ADDR_R __stringify(SDRAM_OFFSET(FA0)) -#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(FC0)) -#define PXEFILE_ADDR_R __stringify(SDRAM_OFFSET(FD0)) -#define RAMDISK_ADDR_R __stringify(SDRAM_OFFSET(FE0)) +#define BOOTM_SIZE__stringify(0xa00) +#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(008)) +#define FDT_ADDR_R__stringify(SDRAM_OFFSET(FA0)) +#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(FC0)) +#define PXEFILE_ADDR_R__stringify(SDRAM_OFFSET(FD0)) +#define FDTOVERLAY_ADDR_R __stringify(SDRAM_OFFSET(FE0)) +#define RAMDISK_ADDR_R__stringify(SDRAM_OFFSET(FF0)) #else /* * 160M RAM (256M minimum minus 64MB heap + 32MB for u-boot, stack, fb, etc. * 32M uncompressed kernel, 16M compressed kernel, 1M fdt, - * 1M script, 1M pxe and the ramdisk at the end. + * 1M script, 1M pxe, 1M dt overlay and the ramdisk at the end. */ #ifndef CONFIG_MACH_SUN8I_V3S -#define BOOTM_SIZE __stringify(0xa00) -#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(200)) -#define FDT_ADDR_R __stringify(SDRAM_OFFSET(300)) -#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(310)) -#define PXEFILE_ADDR_R __stringify(SDRAM_OFFSET(320)) -#define RAMDISK_ADDR_R __stringify(SDRAM_OFFSET(330)) +#define BOOTM_SIZE__stringify(0xa00) +#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(200)) +#define FDT_ADDR_R__stringify(SDRAM_OFFSET(300)) +#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(310)) +#define PXEFILE_ADDR_R__stringify(SDRAM_OFFSET(320)) +#define FDTOVERLAY_ADDR_R __stringify(SDRAM_OFFSET(330)) +#define RAMDISK_ADDR_R__stringify(SDRAM_OFFSET(340)) #else /* * 64M RAM minus 2MB heap + 16MB for u-boot, stack, fb, etc. * 16M uncompressed kernel, 8M compressed kernel, 1M fdt, - * 1M script, 1M pxe and the ramdisk at the end. + * 1M script, 1M pxe, 1M dt overlay and the ramdisk at the end. */ -#define BOOTM_SIZE __stringify(0x2e0) -#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(100)) -#define FDT_ADDR_R __stringify(SDRAM_OFFSET(180)) -#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(190)) -#define PXEFILE_ADDR_R __stringify(SDRAM_OFFSET(1A0)) -#define RAMDISK_ADDR_R __stringify(SDRAM_OFFSET(1B0)) +#define BOOTM_SIZE__stringify(0x2e0) +#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(100)) +#define FDT_ADDR_R__stringify(SDRAM_OFFSET(180)) +#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(190)) +#define PXEFILE_ADDR_R__stringify(SDRAM_OFFSET(1A0)) +#define FDTOVERLAY_ADDR_R __stringify(SDRAM_OFFSET(1B0)) +#define RAMDISK_ADDR_R__stringify(SDRAM_OFFSET(1C0)) #endif #endif @@ -300,6 +302,7 @@
[PATCH v2 19/19] video: sunxi: dw-hdmi: Use new PHY driver
Remove direct PHY managing from dw-hdmi platform driver and use dedicated driver instead. While at it, enable clocks and deassert reset lines through clk and reset framework instead of manually configuring bits. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_dw_hdmi.c | 225 +--- 1 file changed, 36 insertions(+), 189 deletions(-) diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 483d57293155..16051baca8c5 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -5,190 +5,26 @@ * (C) Copyright 2017 Jernej Skrabec */ +#include #include #include #include #include #include -#include -#include +#include +#include #include #include #include #include -#include +#include "sunxi_dw_hdmi_phy.h" struct sunxi_dw_hdmi_priv { struct dw_hdmi hdmi; int mux; + struct phy phy; }; -struct sunxi_hdmi_phy { - u32 pol; - u32 res1[3]; - u32 read_en; - u32 unscramble; - u32 res2[2]; - u32 ctrl; - u32 unk1; - u32 unk2; - u32 pll; - u32 clk; - u32 unk3; - u32 status; -}; - -#define HDMI_PHY_OFFS 0x1 - -static int sunxi_dw_hdmi_get_divider(uint clock) -{ - /* -* Due to missing documentaion of HDMI PHY, we know correct -* settings only for following four PHY dividers. Select one -* based on clock speed. -*/ - if (clock <= 2700) - return 11; - else if (clock <= 7425) - return 4; - else if (clock <= 14850) - return 2; - else - return 1; -} - -static void sunxi_dw_hdmi_phy_init(struct dw_hdmi *hdmi) -{ - struct sunxi_hdmi_phy * const phy = - (struct sunxi_hdmi_phy *)(hdmi->ioaddr + HDMI_PHY_OFFS); - unsigned long tmo; - u32 tmp; - - /* -* HDMI PHY settings are taken as-is from Allwinner BSP code. -* There is no documentation. -*/ - writel(0, >ctrl); - setbits_le32(>ctrl, BIT(0)); - udelay(5); - setbits_le32(>ctrl, BIT(16)); - setbits_le32(>ctrl, BIT(1)); - udelay(10); - setbits_le32(>ctrl, BIT(2)); - udelay(5); - setbits_le32(>ctrl, BIT(3)); - udelay(40); - setbits_le32(>ctrl, BIT(19)); - udelay(100); - setbits_le32(>ctrl, BIT(18)); - setbits_le32(>ctrl, 7 << 4); - - /* Note that Allwinner code doesn't fail in case of timeout */ - tmo = timer_get_us() + 2000; - while ((readl(>status) & 0x80) == 0) { - if (timer_get_us() > tmo) { - printf("Warning: HDMI PHY init timeout!\n"); - break; - } - } - - setbits_le32(>ctrl, 0xf << 8); - setbits_le32(>ctrl, BIT(7)); - - writel(0x39dc5040, >pll); - writel(0x80084343, >clk); - udelay(1); - writel(1, >unk3); - setbits_le32(>pll, BIT(25)); - udelay(10); - tmp = (readl(>status) & 0x1f800) >> 11; - setbits_le32(>pll, BIT(31) | BIT(30)); - setbits_le32(>pll, tmp); - writel(0x01FF0F7F, >ctrl); - writel(0x80639000, >unk1); - writel(0x0F81C405, >unk2); - - /* enable read access to HDMI controller */ - writel(0x54524545, >read_en); - /* descramble register offsets */ - writel(0x42494E47, >unscramble); -} - -static void sunxi_dw_hdmi_phy_set(struct dw_hdmi *hdmi, uint clock, int phy_div) -{ - struct sunxi_hdmi_phy * const phy = - (struct sunxi_hdmi_phy *)(hdmi->ioaddr + HDMI_PHY_OFFS); - int div = sunxi_dw_hdmi_get_divider(clock); - u32 tmp; - - /* -* Unfortunately, we don't know much about those magic -* numbers. They are taken from Allwinner BSP driver. -*/ - switch (div) { - case 1: - writel(0x30dc5fc0, >pll); - writel(0x800863C0 | (phy_div - 1), >clk); - mdelay(10); - writel(0x0001, >unk3); - setbits_le32(>pll, BIT(25)); - mdelay(200); - tmp = (readl(>status) & 0x1f800) >> 11; - setbits_le32(>pll, BIT(31) | BIT(30)); - if (tmp < 0x3d) - setbits_le32(>pll, tmp + 2); - else - setbits_le32(>pll, 0x3f); - mdelay(100); - writel(0x017F, >ctrl); - writel(0x8063b000, >unk1); - writel(0x0F8246B5, >unk2); - break; - case 2: - writel(0x39dc5040, >pll); - writel(0x80084380 | (phy_div - 1), >clk); -
[PATCH v2 18/19] video: sunxi: Add DW HDMI PHY driver
This commit adds standalone driver for DW HDMI PHY. It deprecates code which is included in sunxi dw-hdmi platform driver. Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/Kconfig | 1 + drivers/video/sunxi/Makefile| 2 +- drivers/video/sunxi/sunxi_dw_hdmi_phy.c | 423 drivers/video/sunxi/sunxi_dw_hdmi_phy.h | 24 ++ 4 files changed, 449 insertions(+), 1 deletion(-) create mode 100644 drivers/video/sunxi/sunxi_dw_hdmi_phy.c create mode 100644 drivers/video/sunxi/sunxi_dw_hdmi_phy.h diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 34ef1f4b030f..5f2df7727357 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -973,6 +973,7 @@ config VIDEO_DE2 select CLK_SUN8I_DE2 select DM_VIDEO select DISPLAY + select PHY select VIDEO_DW_HDMI imply VIDEO_DT_SIMPLEFB default y diff --git a/drivers/video/sunxi/Makefile b/drivers/video/sunxi/Makefile index 4321673312bf..22ec17fb4fd2 100644 --- a/drivers/video/sunxi/Makefile +++ b/drivers/video/sunxi/Makefile @@ -4,4 +4,4 @@ # Wolfgang Denk, DENX Software Engineering, w...@denx.de. obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o simplefb_common.o lcdc.o tve_common.o ../videomodes.o -obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o simplefb_common.o lcdc.o sunxi_lcd.o +obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o sunxi_dw_hdmi_phy.o simplefb_common.o lcdc.o sunxi_lcd.o diff --git a/drivers/video/sunxi/sunxi_dw_hdmi_phy.c b/drivers/video/sunxi/sunxi_dw_hdmi_phy.c new file mode 100644 index ..bed5c2fdfe81 --- /dev/null +++ b/drivers/video/sunxi/sunxi_dw_hdmi_phy.c @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Allwinner DW HDMI PHY driver + * + * (C) Copyright 2021 Jernej Skrabec + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sunxi_dw_hdmi_phy.h" + +#define SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCKBIT(0) +#define SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK GENMASK(15, 8) +#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC BIT(8) +#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC BIT(9) +#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK GENMASK(23, 16) +#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR(addr) (addr << 16) + +#define SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN BIT(31) + +#define SUN8I_HDMI_PHY_READ_EN_MAGIC 0x54524545 + +#define SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC0x42494E47 + +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SWIBIT(31) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_PWEND BIT(30) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_PWENC BIT(29) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW BIT(28) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SVRCAL(x) ((x) << 26) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(x)((x) << 24) +#define SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPTBIT(23) +#define SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPTBIT(22) +#define SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT BIT(21) +#define SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT BIT(20) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL BIT(19) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENCALOGBIT(18) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDSBIT(17) +#define SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN BIT(16) +#define SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK GENMASK(15, 12) +#define SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL (0xf << 12) +#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK BIT(11) +#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 BIT(10) +#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 BIT(9) +#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 BIT(8) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK BIT(7) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2BIT(6) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1BIT(5) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0BIT(4) +#define SUN8I_HDMI_PHY_ANA_CFG1_CKEN BIT(3) +#define SUN8I_HDMI_PHY_ANA_CFG1_LDOEN BIT(2) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENVBS BIT(1) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENBI BIT(0) + +#define SUN8I_HDMI_PHY_ANA_CFG2_M_EN BIT(31) +#define SUN8I_HDMI_PHY_ANA_CFG2_PLLDBENBIT(30) +#define SUN8I_HDMI_PHY_ANA_CFG2_SENBIT(29) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_HPDPD BIT(28) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_HPDEN BIT(27) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_PLRCK BIT(26) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_PLR(x) ((x) << 23) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK BIT(22) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_DENBIT(21) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CD(x) ((x) << 19) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(x)((x) << 17) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCKBIT(16) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW BIT(15) +#define SUN8I_H
[PATCH v2 17/19] video: dw-hdmi: modify phy init callback to include full timings
Currently PHY init callback has only pixel clock as a parameter, but other timing parameters may be needed for custom PHYs. Modify callback signature to include full timings. Cc: Neil Armstrong Signed-off-by: Jernej Skrabec --- drivers/video/dw_hdmi.c | 6 +++--- drivers/video/meson/meson_dw_hdmi.c | 5 +++-- drivers/video/sunxi/sunxi_dw_hdmi.c | 7 --- include/dw_hdmi.h | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/video/dw_hdmi.c b/drivers/video/dw_hdmi.c index c4fbb1829446..8d71f713f99f 100644 --- a/drivers/video/dw_hdmi.c +++ b/drivers/video/dw_hdmi.c @@ -901,7 +901,7 @@ static const u8 pre_buf[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, }; -int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock) +int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, const struct display_timing *edid) { int i, ret; @@ -912,7 +912,7 @@ int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock) hdmi_phy_enable_tmds(hdmi, 0); hdmi_phy_enable_power(hdmi, 0); - ret = hdmi_phy_configure(hdmi, mpixelclock); + ret = hdmi_phy_configure(hdmi, edid->pixelclock.typ); if (ret) { debug("hdmi phy config failure %d\n", ret); return ret; @@ -988,7 +988,7 @@ int dw_hdmi_enable(struct dw_hdmi *hdmi, const struct display_timing *edid) hdmi_av_composer(hdmi, edid); - ret = hdmi->phy_set(hdmi, edid->pixelclock.typ); + ret = hdmi->phy_set(hdmi, edid); if (ret) return ret; diff --git a/drivers/video/meson/meson_dw_hdmi.c b/drivers/video/meson/meson_dw_hdmi.c index e5f281320534..7558814b3491 100644 --- a/drivers/video/meson/meson_dw_hdmi.c +++ b/drivers/video/meson/meson_dw_hdmi.c @@ -292,7 +292,8 @@ static void meson_dw_hdmi_phy_setup_mode(struct meson_dw_hdmi *priv, } } -static int meson_dw_hdmi_phy_init(struct dw_hdmi *hdmi, uint pixel_clock) +static int meson_dw_hdmi_phy_init(struct dw_hdmi *hdmi, + const struct display_timing *edid) { struct meson_dw_hdmi *priv = container_of(hdmi, struct meson_dw_hdmi, hdmi); @@ -322,7 +323,7 @@ static int meson_dw_hdmi_phy_init(struct dw_hdmi *hdmi, uint pixel_clock) dw_hdmi_top_write(hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); /* Setup PHY parameters */ - meson_dw_hdmi_phy_setup_mode(priv, pixel_clock); + meson_dw_hdmi_phy_setup_mode(priv, edid->pixelclock.typ); /* Setup PHY */ dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1, diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 0744954fa15f..483d57293155 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -266,12 +266,13 @@ static void sunxi_dw_hdmi_lcdc_init(int mux, const struct display_timing *edid, lcdc_enable(lcdc, bpp); } -static int sunxi_dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock) +static int sunxi_dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, +const struct display_timing *edid) { int phy_div; - sunxi_dw_hdmi_pll_set(mpixelclock / 1000, _div); - sunxi_dw_hdmi_phy_set(hdmi, mpixelclock, phy_div); + sunxi_dw_hdmi_pll_set(edid->pixelclock.typ / 1000, _div); + sunxi_dw_hdmi_phy_set(hdmi, edid->pixelclock.typ, phy_div); return 0; } diff --git a/include/dw_hdmi.h b/include/dw_hdmi.h index 8acae3839fb3..46b87916b8bb 100644 --- a/include/dw_hdmi.h +++ b/include/dw_hdmi.h @@ -544,12 +544,12 @@ struct dw_hdmi { struct hdmi_data_info hdmi_data; struct udevice *ddc_bus; - int (*phy_set)(struct dw_hdmi *hdmi, uint mpixelclock); + int (*phy_set)(struct dw_hdmi *hdmi, const struct display_timing *edid); void (*write_reg)(struct dw_hdmi *hdmi, u8 val, int offset); u8 (*read_reg)(struct dw_hdmi *hdmi, int offset); }; -int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock); +int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, const struct display_timing *edid); int dw_hdmi_phy_wait_for_hpd(struct dw_hdmi *hdmi); void dw_hdmi_phy_init(struct dw_hdmi *hdmi); -- 2.30.1
[PATCH v2 16/19] video: sunxi: de2: switch clock setup to DM model
Now that proper DM clock and reset driver exists for Display Engine 2 and 3, remove all clock and reset related code and use appropriate framework instead. Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/Kconfig | 1 + drivers/video/sunxi/sunxi_de2.c | 67 +++-- 2 files changed, 23 insertions(+), 45 deletions(-) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 9149196b223e..34ef1f4b030f 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -970,6 +970,7 @@ config SUNXI_DE2 config VIDEO_DE2 bool "Display Engine 2 video driver" depends on SUNXI_DE2 + select CLK_SUN8I_DE2 select DM_VIDEO select DISPLAY select VIDEO_DW_HDMI diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index f6c8ca075aba..cee9b46b1259 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -14,10 +15,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include "simplefb_common.h" @@ -36,40 +37,10 @@ struct sunxi_de2_data { const char *disp_drv_name; }; -static void sunxi_de2_composer_init(void) -{ - struct sunxi_ccm_reg * const ccm = - (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; - -#ifdef CONFIG_MACH_SUN50I - u32 reg_value; - - /* set SRAM for video use (A64 only) */ - reg_value = readl(SUNXI_SRAMC_BASE + 0x04); - reg_value &= ~(0x01 << 24); - writel(reg_value, SUNXI_SRAMC_BASE + 0x04); -#endif - - clock_set_pll10(43200); - - /* Set DE parent to pll10 */ - clrsetbits_le32(>de_clk_cfg, CCM_DE2_CTRL_PLL_MASK, - CCM_DE2_CTRL_PLL10); - - /* Set ahb gating to pass */ - setbits_le32(>ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE); - setbits_le32(>ahb_gate1, 1 << AHB_GATE_OFFSET_DE); - - /* Clock on */ - setbits_le32(>de_clk_cfg, CCM_DE2_CTRL_GATE); -} - -static void sunxi_de2_mode_set(ulong de_mux_base, int mux, +static void sunxi_de2_mode_set(ulong de_mux_base, const struct display_timing *mode, int bpp, ulong address, bool is_composite) { - struct de_clk * const de_clk_regs = - (struct de_clk *)(SUNXI_DE2_BASE); struct de_glb * const de_glb_regs = (struct de_glb *)(de_mux_base + SUNXI_DE2_MUX_GLB_REGS); @@ -87,17 +58,6 @@ static void sunxi_de2_mode_set(ulong de_mux_base, int mux, int channel; u32 format; - /* enable clock */ -#ifdef CONFIG_MACH_SUN8I_H3 - setbits_le32(_clk_regs->rst_cfg, (mux == 0) ? 1 : 4); -#else - setbits_le32(_clk_regs->rst_cfg, BIT(mux)); -#endif - setbits_le32(_clk_regs->gate_cfg, BIT(mux)); - setbits_le32(_clk_regs->bus_cfg, BIT(mux)); - - clrbits_le32(_clk_regs->sel_cfg, 1); - writel(SUNXI_DE2_MUX_GLB_CTL_EN, _glb_regs->ctl); writel(0, _glb_regs->status); writel(1, _glb_regs->dbuff); @@ -189,6 +149,8 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase, struct video_priv *uc_priv = dev_get_uclass_priv(dev); struct display_timing timing; struct display_plat *disp_uc_plat; + struct reset_ctl_bulk resets; + struct clk_bulk clocks; int ret; disp_uc_plat = dev_get_uclass_plat(disp); @@ -206,8 +168,23 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase, return ret; } - sunxi_de2_composer_init(); - sunxi_de2_mode_set((ulong)dev_read_addr(dev), mux, , + ret = reset_get_bulk(dev, ); + if (ret) + return ret; + + ret = clk_get_bulk(dev, ); + if (ret) + return ret; + + ret = clk_enable_bulk(); + if (ret) + return ret; + + ret = reset_deassert_bulk(); + if (ret) + return ret; + + sunxi_de2_mode_set((ulong)dev_read_addr(dev), , 1 << l2bpp, fbbase, is_composite); ret = display_enable(disp, 1 << l2bpp, ); -- 2.30.1
[PATCH v2 15/19] clk: sunxi: add DE2 clock driver
Video driver currently manages clocks and resets by directly writing to registers. This is already a bit messy because each SoC has some specifics. It's much better to implement proper clock and reset driver which takes information from device tree file. Note that this driver is not perfect yet. It still sets PLL and parent by hand. Sunxi clock framework still doesn't know how to set parents or rates. However, this is already big step in right direction. Cc: Lukasz Majewski Signed-off-by: Jernej Skrabec --- drivers/clk/sunxi/Kconfig | 5 +++ drivers/clk/sunxi/Makefile | 1 + drivers/clk/sunxi/clk_de2.c | 85 + 3 files changed, 91 insertions(+) create mode 100644 drivers/clk/sunxi/clk_de2.c diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig index bf084fa7a84a..6c96affb1f87 100644 --- a/drivers/clk/sunxi/Kconfig +++ b/drivers/clk/sunxi/Kconfig @@ -44,6 +44,11 @@ config CLK_SUN8I_A83T This enables common clock driver support for platforms based on Allwinner A83T SoC. +config CLK_SUN8I_DE2 + bool "Clock driver for Allwinner Display Engine 2 and 3" + help + This enables common clock driver support for Display Engine 2 and 3. + config CLK_SUN8I_R40 bool "Clock driver for Allwinner R40" default MACH_SUN8I_R40 diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 0dfc0593fb1c..620ff96ac6f5 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_CLK_SUN5I_A10S) += clk_a10s.o obj-$(CONFIG_CLK_SUN6I_A31) += clk_a31.o obj-$(CONFIG_CLK_SUN8I_A23) += clk_a23.o obj-$(CONFIG_CLK_SUN8I_A83T) += clk_a83t.o +obj-$(CONFIG_CLK_SUN8I_DE2) += clk_de2.o obj-$(CONFIG_CLK_SUN8I_R40) += clk_r40.o obj-$(CONFIG_CLK_SUN8I_V3S) += clk_v3s.o obj-$(CONFIG_CLK_SUN9I_A80) += clk_a80.o diff --git a/drivers/clk/sunxi/clk_de2.c b/drivers/clk/sunxi/clk_de2.c new file mode 100644 index ..b8c45404c1b6 --- /dev/null +++ b/drivers/clk/sunxi/clk_de2.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2021 Jernej Skrabec + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct ccu_clk_gate de2_gates[] = { + [CLK_MIXER0]= GATE(0x00, BIT(0)), + [CLK_MIXER1]= GATE(0x00, BIT(1)), + [CLK_WB]= GATE(0x00, BIT(2)), + + [CLK_BUS_MIXER0]= GATE(0x04, BIT(0)), + [CLK_BUS_MIXER1]= GATE(0x04, BIT(1)), + [CLK_BUS_WB]= GATE(0x04, BIT(2)), +}; + +static struct ccu_reset de2_resets[] = { + [RST_MIXER0]= RESET(0x08, BIT(0)), + [RST_MIXER1]= RESET(0x08, BIT(1)), + [RST_WB]= RESET(0x08, BIT(2)), +}; + +static const struct ccu_desc de2_ccu_desc = { + .gates = de2_gates, + .resets = de2_resets, +}; + +static int de2_clk_probe(struct udevice *dev) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + u32 val; + + if (device_is_compatible(dev_get_parent(dev), +"allwinner,sun50i-a64-de2")) { + /* set SRAM for video use */ + val = readl(SUNXI_SRAMC_BASE + 0x04); + val &= ~(0x01 << 24); + writel(val, SUNXI_SRAMC_BASE + 0x04); + } + + /* clock driver doesn't know how to set rate or parent yet */ + clock_set_pll10(43200); + + /* Set DE parent to pll10 */ + clrsetbits_le32(>de_clk_cfg, CCM_DE2_CTRL_PLL_MASK, + CCM_DE2_CTRL_PLL10); + + return sunxi_clk_probe(dev); +} + +static int de2_clk_bind(struct udevice *dev) +{ + return sunxi_reset_bind(dev, ARRAY_SIZE(de2_resets)); +} + +static const struct udevice_id de2_ccu_ids[] = { + { .compatible = "allwinner,sun8i-h3-de2-clk", + .data = (ulong)_ccu_desc }, + { .compatible = "allwinner,sun50i-a64-de2-clk", + .data = (ulong)_ccu_desc }, + { .compatible = "allwinner,sun50i-h5-de2-clk", + .data = (ulong)_ccu_desc }, + { } +}; + +U_BOOT_DRIVER(clk_sun8i_de2) = { + .name = "sun8i_de2_ccu", + .id = UCLASS_CLK, + .of_match = de2_ccu_ids, + .priv_auto = sizeof(struct ccu_priv), + .ops= _clk_ops, + .probe = de2_clk_probe, + .bind = de2_clk_bind, +}; -- 2.30.1
[PATCH v2 14/19] clk: sunxi: Add DE2 and HDMI clocks to H3 and A64
These clocks and resets are needed for video drivers. Cc: Lukasz Majewski Signed-off-by: Jernej Skrabec --- drivers/clk/sunxi/clk_a64.c | 12 drivers/clk/sunxi/clk_h3.c | 12 2 files changed, 24 insertions(+) diff --git a/drivers/clk/sunxi/clk_a64.c b/drivers/clk/sunxi/clk_a64.c index 0553ffa4399a..28131240652f 100644 --- a/drivers/clk/sunxi/clk_a64.c +++ b/drivers/clk/sunxi/clk_a64.c @@ -26,6 +26,9 @@ static const struct ccu_clk_gate a64_gates[] = { [CLK_BUS_OHCI0] = GATE(0x060, BIT(28)), [CLK_BUS_OHCI1] = GATE(0x060, BIT(29)), + [CLK_BUS_HDMI] = GATE(0x064, BIT(11)), + [CLK_BUS_DE]= GATE(0x064, BIT(12)), + [CLK_BUS_UART0] = GATE(0x06c, BIT(16)), [CLK_BUS_UART1] = GATE(0x06c, BIT(17)), [CLK_BUS_UART2] = GATE(0x06c, BIT(18)), @@ -41,6 +44,11 @@ static const struct ccu_clk_gate a64_gates[] = { [CLK_USB_HSIC_12M] = GATE(0x0cc, BIT(11)), [CLK_USB_OHCI0] = GATE(0x0cc, BIT(16)), [CLK_USB_OHCI1] = GATE(0x0cc, BIT(17)), + + [CLK_DE]= GATE(0x104, BIT(31)), + + [CLK_HDMI] = GATE(0x150, BIT(31)), + [CLK_HDMI_DDC] = GATE(0x154, BIT(31)), }; static const struct ccu_reset a64_resets[] = { @@ -60,6 +68,10 @@ static const struct ccu_reset a64_resets[] = { [RST_BUS_OHCI0] = RESET(0x2c0, BIT(28)), [RST_BUS_OHCI1] = RESET(0x2c0, BIT(29)), + [RST_BUS_HDMI0] = RESET(0x2c4, BIT(10)), + [RST_BUS_HDMI1] = RESET(0x2c4, BIT(11)), + [RST_BUS_DE]= RESET(0x2c4, BIT(12)), + [RST_BUS_UART0] = RESET(0x2d8, BIT(16)), [RST_BUS_UART1] = RESET(0x2d8, BIT(17)), [RST_BUS_UART2] = RESET(0x2d8, BIT(18)), diff --git a/drivers/clk/sunxi/clk_h3.c b/drivers/clk/sunxi/clk_h3.c index f81633b92d5a..806a35b37435 100644 --- a/drivers/clk/sunxi/clk_h3.c +++ b/drivers/clk/sunxi/clk_h3.c @@ -30,6 +30,9 @@ static struct ccu_clk_gate h3_gates[] = { [CLK_BUS_OHCI2] = GATE(0x060, BIT(30)), [CLK_BUS_OHCI3] = GATE(0x060, BIT(31)), + [CLK_BUS_HDMI] = GATE(0x064, BIT(11)), + [CLK_BUS_DE]= GATE(0x064, BIT(12)), + [CLK_BUS_UART0] = GATE(0x06c, BIT(16)), [CLK_BUS_UART1] = GATE(0x06c, BIT(17)), [CLK_BUS_UART2] = GATE(0x06c, BIT(18)), @@ -48,6 +51,11 @@ static struct ccu_clk_gate h3_gates[] = { [CLK_USB_OHCI1] = GATE(0x0cc, BIT(17)), [CLK_USB_OHCI2] = GATE(0x0cc, BIT(18)), [CLK_USB_OHCI3] = GATE(0x0cc, BIT(19)), + + [CLK_DE]= GATE(0x104, BIT(31)), + + [CLK_HDMI] = GATE(0x150, BIT(31)), + [CLK_HDMI_DDC] = GATE(0x154, BIT(31)), }; static struct ccu_reset h3_resets[] = { @@ -72,6 +80,10 @@ static struct ccu_reset h3_resets[] = { [RST_BUS_OHCI2] = RESET(0x2c0, BIT(30)), [RST_BUS_OHCI3] = RESET(0x2c0, BIT(31)), + [RST_BUS_HDMI0] = RESET(0x2c4, BIT(10)), + [RST_BUS_HDMI1] = RESET(0x2c4, BIT(11)), + [RST_BUS_DE]= RESET(0x2c4, BIT(12)), + [RST_BUS_EPHY] = RESET(0x2c8, BIT(2)), [RST_BUS_UART0] = RESET(0x2d8, BIT(16)), -- 2.30.1
[PATCH v2 13/19] video: sunxi: de2: read address from DT node
Currently DE2 uses hardcoded address based on SoC for which U-Boot is built. Read it from DT instead so there is no need to specify it when support for new SoC is added. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_de2.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index 81576e45e9ef..f6c8ca075aba 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -64,11 +64,10 @@ static void sunxi_de2_composer_init(void) setbits_le32(>de_clk_cfg, CCM_DE2_CTRL_GATE); } -static void sunxi_de2_mode_set(int mux, const struct display_timing *mode, +static void sunxi_de2_mode_set(ulong de_mux_base, int mux, + const struct display_timing *mode, int bpp, ulong address, bool is_composite) { - ulong de_mux_base = (mux == 0) ? - SUNXI_DE2_MUX0_BASE : SUNXI_DE2_MUX1_BASE; struct de_clk * const de_clk_regs = (struct de_clk *)(SUNXI_DE2_BASE); struct de_glb * const de_glb_regs = @@ -208,7 +207,8 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase, } sunxi_de2_composer_init(); - sunxi_de2_mode_set(mux, , 1 << l2bpp, fbbase, is_composite); + sunxi_de2_mode_set((ulong)dev_read_addr(dev), mux, , + 1 << l2bpp, fbbase, is_composite); ret = display_enable(disp, 1 << l2bpp, ); if (ret) { -- 2.30.1
[PATCH v2 12/19] video: sunxi: de2: switch to DT probing
Currently DE2 driver is probed via driver info. Switch probing to device tree compatible string method. Display is now searched via driver name which has same limitation as previous method. This can be improved only when all drivers in chain are probed via device tree compatible strings. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_de2.c | 88 +++-- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index e02d359cd259..81576e45e9ef 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -31,6 +31,11 @@ enum { LCD_MAX_LOG2_BPP= VIDEO_BPP32, }; +struct sunxi_de2_data { + int id; + const char *disp_drv_name; +}; + static void sunxi_de2_composer_init(void) { struct sunxi_ccm_reg * const ccm = @@ -228,51 +233,34 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase, static int sunxi_de2_probe(struct udevice *dev) { + const struct sunxi_de2_data *data = + (const struct sunxi_de2_data *)dev_get_driver_data(dev); struct video_uc_plat *plat = dev_get_uclass_plat(dev); struct udevice *disp; - int ret; + int ret, index = 0; /* Before relocation we don't need to do anything */ if (!(gd->flags & GD_FLG_RELOC)) return 0; - ret = uclass_get_device_by_driver(UCLASS_DISPLAY, - DM_DRIVER_GET(sunxi_lcd), ); - if (!ret) { - int mux; + while (!(ret = uclass_get_device(UCLASS_DISPLAY, index++, ))) { + if (strcmp(disp->driver->name, data->disp_drv_name)) + continue; - mux = 0; + ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, +data->id, false); + if (ret) + return ret; - ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux, -false); - if (!ret) { - video_set_flush_dcache(dev, 1); - return 0; - } - } - - debug("%s: lcd display not found (ret=%d)\n", __func__, ret); - - ret = uclass_get_device_by_driver(UCLASS_DISPLAY, - DM_DRIVER_GET(sunxi_dw_hdmi), ); - if (!ret) { - int mux; - if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5)) - mux = 0; - else - mux = 1; + video_set_flush_dcache(dev, 1); - ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux, -false); - if (!ret) { - video_set_flush_dcache(dev, 1); - return 0; - } + return 0; } - debug("%s: hdmi display not found (ret=%d)\n", __func__, ret); + debug("%s: %s not found (ret=%d)\n", __func__, + data->disp_drv_name, ret); - return -ENODEV; + return ret; } static int sunxi_de2_bind(struct udevice *dev) @@ -285,22 +273,50 @@ static int sunxi_de2_bind(struct udevice *dev) return 0; } +const struct sunxi_de2_data h3_mixer_0 = { + .id = 0, + .disp_drv_name = "sunxi_dw_hdmi", +}; + +const struct sunxi_de2_data a64_mixer_0 = { + .id = 0, + .disp_drv_name = "sunxi_lcd", +}; + +const struct sunxi_de2_data a64_mixer_1 = { + .id = 1, + .disp_drv_name = "sunxi_dw_hdmi", +}; + +static const struct udevice_id sunxi_de2_ids[] = { + { + .compatible = "allwinner,sun8i-h3-de2-mixer-0", + .data = (ulong)_mixer_0, + }, + { + .compatible = "allwinner,sun50i-a64-de2-mixer-0", + .data = (ulong)_mixer_0, + }, + { + .compatible = "allwinner,sun50i-a64-de2-mixer-1", + .data = (ulong)_mixer_1, + }, + { } +}; + static const struct video_ops sunxi_de2_ops = { }; U_BOOT_DRIVER(sunxi_de2) = { .name = "sunxi_de2", .id = UCLASS_VIDEO, + .of_match = sunxi_de2_ids, .ops= _de2_ops, .bind = sunxi_de2_bind, .probe = sunxi_de2_probe, .flags = DM_FLAG_PRE_RELOC, }; -U_BOOT_DRVINFO(sunxi_de2) = { - .name = "sunxi_de2" -}; - /* * Simplefb support. */ -- 2.30.1
[PATCH v2 11/19] video: sunxi: dw-hdmi: read address from DT node
Currently HDMI controller MMIO address is hardcoded. Change that so address is read from DT node. That will make adding support for new variants a bit easier. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_dw_hdmi.c | 38 ++--- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 6f77b2a43b40..0744954fa15f 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -57,10 +57,10 @@ static int sunxi_dw_hdmi_get_divider(uint clock) return 1; } -static void sunxi_dw_hdmi_phy_init(void) +static void sunxi_dw_hdmi_phy_init(struct dw_hdmi *hdmi) { struct sunxi_hdmi_phy * const phy = - (struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS); + (struct sunxi_hdmi_phy *)(hdmi->ioaddr + HDMI_PHY_OFFS); unsigned long tmo; u32 tmp; @@ -114,10 +114,10 @@ static void sunxi_dw_hdmi_phy_init(void) writel(0x42494E47, >unscramble); } -static void sunxi_dw_hdmi_phy_set(uint clock, int phy_div) +static void sunxi_dw_hdmi_phy_set(struct dw_hdmi *hdmi, uint clock, int phy_div) { struct sunxi_hdmi_phy * const phy = - (struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS); + (struct sunxi_hdmi_phy *)(hdmi->ioaddr + HDMI_PHY_OFFS); int div = sunxi_dw_hdmi_get_divider(clock); u32 tmp; @@ -271,7 +271,7 @@ static int sunxi_dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock) int phy_div; sunxi_dw_hdmi_pll_set(mpixelclock / 1000, _div); - sunxi_dw_hdmi_phy_set(mpixelclock, phy_div); + sunxi_dw_hdmi_phy_set(hdmi, mpixelclock, phy_div); return 0; } @@ -292,9 +292,9 @@ static bool sunxi_dw_hdmi_mode_valid(struct udevice *dev, static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp, const struct display_timing *edid) { - struct sunxi_hdmi_phy * const phy = - (struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS); struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev); + struct sunxi_hdmi_phy * const phy = + (struct sunxi_hdmi_phy *)(priv->hdmi.ioaddr + HDMI_PHY_OFFS); int ret; ret = dw_hdmi_enable(>hdmi, edid); @@ -316,12 +316,26 @@ static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp, * again or othwerwise BSP driver won't work. Dummy read is * needed or otherwise last write doesn't get written correctly. */ - (void)readb(SUNXI_HDMI_BASE); + (void)readb(priv->hdmi.ioaddr); writel(0, >unscramble); return 0; } +static int sunxi_dw_hdmi_of_to_plat(struct udevice *dev) +{ + struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev); + struct dw_hdmi *hdmi = >hdmi; + + hdmi->ioaddr = (ulong)dev_read_addr(dev); + hdmi->i2c_clk_high = 0xd8; + hdmi->i2c_clk_low = 0xfe; + hdmi->reg_io_width = 1; + hdmi->phy_set = sunxi_dw_hdmi_phy_cfg; + + return 0; +} + static int sunxi_dw_hdmi_probe(struct udevice *dev) { struct display_plat *uc_plat = dev_get_uclass_plat(dev); @@ -346,13 +360,8 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev) /* Clock on */ setbits_le32(>hdmi_clk_cfg, CCM_HDMI_CTRL_GATE); - sunxi_dw_hdmi_phy_init(); + sunxi_dw_hdmi_phy_init(>hdmi); - priv->hdmi.ioaddr = SUNXI_HDMI_BASE; - priv->hdmi.i2c_clk_high = 0xd8; - priv->hdmi.i2c_clk_low = 0xfe; - priv->hdmi.reg_io_width = 1; - priv->hdmi.phy_set = sunxi_dw_hdmi_phy_cfg; priv->mux = uc_plat->source_id; ret = dw_hdmi_phy_wait_for_hpd(>hdmi); @@ -382,6 +391,7 @@ U_BOOT_DRIVER(sunxi_dw_hdmi) = { .id = UCLASS_DISPLAY, .of_match = sunxi_dw_hdmi_ids, .ops= _dw_hdmi_ops, + .of_to_plat = sunxi_dw_hdmi_of_to_plat, .probe = sunxi_dw_hdmi_probe, .priv_auto = sizeof(struct sunxi_dw_hdmi_priv), }; -- 2.30.1
[PATCH v2 10/19] video: sunxi: dw-hdmi: probe driver by compatible
Currently sunxi dw-hdmi driver is probed unconditionally, even if there is no such device. Switch driver to probing via compatible string. This brings many benefits - driver can read DT node and allows driver to be always enabled. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_dw_hdmi.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 6d2bc206fc2c..6f77b2a43b40 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -372,14 +372,16 @@ static const struct dm_display_ops sunxi_dw_hdmi_ops = { .mode_valid = sunxi_dw_hdmi_mode_valid, }; +static const struct udevice_id sunxi_dw_hdmi_ids[] = { + { .compatible = "allwinner,sun8i-a83t-dw-hdmi" }, + { } +}; + U_BOOT_DRIVER(sunxi_dw_hdmi) = { .name = "sunxi_dw_hdmi", .id = UCLASS_DISPLAY, + .of_match = sunxi_dw_hdmi_ids, .ops= _dw_hdmi_ops, .probe = sunxi_dw_hdmi_probe, .priv_auto = sizeof(struct sunxi_dw_hdmi_priv), }; - -U_BOOT_DRVINFO(sunxi_dw_hdmi) = { - .name = "sunxi_dw_hdmi" -}; -- 2.30.1
[PATCH v2 09/19] video: sunxi: de2: switch to public uclass functions
Currently DE2 driver uses functions which are defined in internal headers. They are not meant to be used outside of uclass framework. Switch DE2 driver to public ones. This has additional benefit that device_probe doesn't need to be called manually. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_de2.c | 29 ++--- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index 6b836a011944..e02d359cd259 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -19,8 +19,6 @@ #include #include #include -#include -#include #include #include "simplefb_common.h" @@ -198,13 +196,6 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase, disp_uc_plat->source_id = mux; - ret = device_probe(disp); - if (ret) { - debug("%s: device '%s' display won't probe (ret=%d)\n", - __func__, dev->name, ret); - return ret; - } - ret = display_read_timing(disp, ); if (ret) { debug("%s: Failed to read timings\n", __func__); @@ -245,8 +236,8 @@ static int sunxi_de2_probe(struct udevice *dev) if (!(gd->flags & GD_FLG_RELOC)) return 0; - ret = uclass_find_device_by_name(UCLASS_DISPLAY, -"sunxi_lcd", ); + ret = uclass_get_device_by_driver(UCLASS_DISPLAY, + DM_DRIVER_GET(sunxi_lcd), ); if (!ret) { int mux; @@ -262,8 +253,8 @@ static int sunxi_de2_probe(struct udevice *dev) debug("%s: lcd display not found (ret=%d)\n", __func__, ret); - ret = uclass_find_device_by_name(UCLASS_DISPLAY, -"sunxi_dw_hdmi", ); + ret = uclass_get_device_by_driver(UCLASS_DISPLAY, + DM_DRIVER_GET(sunxi_dw_hdmi), ); if (!ret) { int mux; if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5)) @@ -332,8 +323,8 @@ int sunxi_simplefb_setup(void *blob) mux = 1; /* Skip simplefb setting if DE2 / HDMI is not present */ - ret = uclass_find_device_by_name(UCLASS_VIDEO, -"sunxi_de2", ); + ret = uclass_get_device_by_driver(UCLASS_VIDEO, + DM_DRIVER_GET(sunxi_de2), ); if (ret) { debug("DE2 not present\n"); return 0; @@ -342,8 +333,8 @@ int sunxi_simplefb_setup(void *blob) return 0; } - ret = uclass_find_device_by_name(UCLASS_DISPLAY, -"sunxi_dw_hdmi", ); + ret = uclass_get_device_by_driver(UCLASS_DISPLAY, + DM_DRIVER_GET(sunxi_dw_hdmi), ); if (ret) { debug("HDMI not present\n"); } else if (device_active(hdmi)) { @@ -355,8 +346,8 @@ int sunxi_simplefb_setup(void *blob) debug("HDMI present but not probed\n"); } - ret = uclass_find_device_by_name(UCLASS_DISPLAY, -"sunxi_lcd", ); + ret = uclass_get_device_by_driver(UCLASS_DISPLAY, + DM_DRIVER_GET(sunxi_lcd), ); if (ret) debug("LCD not present\n"); else if (device_active(lcd)) -- 2.30.1
[PATCH v2 08/19] video: sunxi: Remove TV probe from DE2
TV driver was never fully implemented. Remove search for it from DE2 driver. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_de2.c | 15 +-- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index a3e21aa5f13e..6b836a011944 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -281,20 +281,7 @@ static int sunxi_de2_probe(struct udevice *dev) debug("%s: hdmi display not found (ret=%d)\n", __func__, ret); - ret = uclass_find_device_by_name(UCLASS_DISPLAY, - "sunxi_tve", ); - if (ret) { - debug("%s: tv not found (ret=%d)\n", __func__, ret); - return ret; - } - - ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, 1, true); - if (ret) - return ret; - - video_set_flush_dcache(dev, 1); - - return 0; + return -ENODEV; } static int sunxi_de2_bind(struct udevice *dev) -- 2.30.1
[PATCH v2 07/19] video: sunxi: Remove check for ddc-i2c-bus property
No Allwinner board with DW-HDMI controller use separate I2C bus for EDID read. Remove that check. Reviewed-by: Andre Przywara Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_dw_hdmi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 37e78ff24111..6d2bc206fc2c 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -361,9 +361,6 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev) return -1; } - uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus", ->hdmi.ddc_bus); - dw_hdmi_init(>hdmi); return 0; -- 2.30.1
[PATCH v2 06/19] video: sunxi: Use DW-HDMI hpd function
It turns out that there are two ways how hot plug detection can be done. One is standard way for DW HDMI controller - checking bit 2 in 0x3004 register. Another way is applicable only to Allwinner custom PHY - by checking bit 19 in register 0x10038. Both method are equally good as far as we know. Use standard method in order to reduce amount of custom code. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_dw_hdmi.c | 34 + 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index e3811a2ec15f..37e78ff24111 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -114,28 +114,6 @@ static void sunxi_dw_hdmi_phy_init(void) writel(0x42494E47, >unscramble); } -static int sunxi_dw_hdmi_get_plug_in_status(void) -{ - struct sunxi_hdmi_phy * const phy = - (struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS); - - return !!(readl(>status) & (1 << 19)); -} - -static int sunxi_dw_hdmi_wait_for_hpd(void) -{ - ulong start; - - start = get_timer(0); - do { - if (sunxi_dw_hdmi_get_plug_in_status()) - return 0; - udelay(100); - } while (get_timer(start) < 300); - - return -1; -} - static void sunxi_dw_hdmi_phy_set(uint clock, int phy_div) { struct sunxi_hdmi_phy * const phy = @@ -370,12 +348,6 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev) sunxi_dw_hdmi_phy_init(); - ret = sunxi_dw_hdmi_wait_for_hpd(); - if (ret < 0) { - debug("hdmi can not get hpd signal\n"); - return -1; - } - priv->hdmi.ioaddr = SUNXI_HDMI_BASE; priv->hdmi.i2c_clk_high = 0xd8; priv->hdmi.i2c_clk_low = 0xfe; @@ -383,6 +355,12 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev) priv->hdmi.phy_set = sunxi_dw_hdmi_phy_cfg; priv->mux = uc_plat->source_id; + ret = dw_hdmi_phy_wait_for_hpd(>hdmi); + if (ret < 0) { + debug("hdmi can not get hpd signal\n"); + return -1; + } + uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus", >hdmi.ddc_bus); -- 2.30.1
[PATCH v2 05/19] common: edid: Search for valid timing in extension block
One of my monitors have only 4k@60 timing in base EDID block which is out of range for devices with HDMI 1.4. It turns out that it has additional detailed timings in CTA-861 Extension Block and two of them are appropriate for HDMI 1.4. Add additional search for valid detailed timing in extension block. Signed-off-by: Jernej Skrabec --- common/edid.c | 18 ++ 1 file changed, 18 insertions(+) diff --git a/common/edid.c b/common/edid.c index a6c875d9c8e8..14d8836c360e 100644 --- a/common/edid.c +++ b/common/edid.c @@ -220,6 +220,24 @@ int edid_get_timing_validate(u8 *buf, int buf_size, /* Look for detailed timing in base EDID */ found = edid_find_valid_timing(edid->monitor_details.descriptor, 4, timing, mode_valid, mode_valid_priv); + + /* Look for detailed timing in CTA-861 Extension Block */ + if (!found && edid->extension_flag && buf_size >= EDID_EXT_SIZE) { + struct edid_cea861_info *info = + (struct edid_cea861_info *)(buf + sizeof(*edid)); + + if (info->extension_tag == EDID_CEA861_EXTENSION_TAG) { + int count = EDID_CEA861_DTD_COUNT(*info); + int offset = info->dtd_offset; + int size = count * sizeof(struct edid_detailed_timing); + + if (offset >= 4 && offset + size < EDID_SIZE) + found = edid_find_valid_timing( + (u8*)info + offset, count, timing, + mode_valid, mode_valid_priv); + } + } + if (!found) return -EINVAL; -- 2.30.1
[PATCH v2 04/19] common: edid: extract code for detailed timing search
Code which searches for valid detailed timing entry will be used in more places. Extract it. No functional change is made. However, descriptors are casted to edid_detailed_timing instead of edid_monitor_descriptor. Descriptor can be of either type, but since we're interested only in DTD, it is more fitting to cast to edid_detailed_timing. Signed-off-by: Jernej Skrabec --- common/edid.c | 49 - 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/common/edid.c b/common/edid.c index 1cb7177742e8..a6c875d9c8e8 100644 --- a/common/edid.c +++ b/common/edid.c @@ -169,6 +169,29 @@ static bool cea_is_hdmi_vsdb_present(struct edid_cea861_info *info) return false; } +static bool edid_find_valid_timing(void *buf, int count, + struct display_timing *timing, + bool (*mode_valid)(void *priv, + const struct display_timing *timing), + void *mode_valid_priv) +{ + struct edid_detailed_timing *t = buf; + bool found = false; + int i; + + for (i = 0; i < count && !found; i++, t++) + if (EDID_DETAILED_TIMING_PIXEL_CLOCK(*t) != 0) { + decode_timing((u8 *)t, timing); + if (mode_valid) + found = mode_valid(mode_valid_priv, + timing); + else + found = true; + } + + return found; +} + int edid_get_timing_validate(u8 *buf, int buf_size, struct display_timing *timing, int *panel_bits_per_colourp, @@ -177,8 +200,7 @@ int edid_get_timing_validate(u8 *buf, int buf_size, void *mode_valid_priv) { struct edid1_info *edid = (struct edid1_info *)buf; - bool timing_done; - int i; + bool found; if (buf_size < sizeof(*edid) || edid_check_info(edid)) { debug("%s: Invalid buffer\n", __func__); @@ -195,25 +217,10 @@ int edid_get_timing_validate(u8 *buf, int buf_size, return -ENOENT; } - /* Look for detailed timing */ - timing_done = false; - for (i = 0; i < 4; i++) { - struct edid_monitor_descriptor *desc; - - desc = >monitor_details.descriptor[i]; - if (desc->zero_flag_1 != 0) { - decode_timing((u8 *)desc, timing); - if (mode_valid) - timing_done = mode_valid(mode_valid_priv, -timing); - else - timing_done = true; - - if (timing_done) - break; - } - } - if (!timing_done) + /* Look for detailed timing in base EDID */ + found = edid_find_valid_timing(edid->monitor_details.descriptor, 4, + timing, mode_valid, mode_valid_priv); + if (!found) return -EINVAL; if (edid->version != 1 || edid->revision < 4) { -- 2.30.1
[PATCH v2 03/19] common: edid: check for digital display earlier
When searching for detailed timing in EDID, check for digital display earlier. There is no point parsing other parameters if this flag is not present. Reviewed-by: Andre Przywara Signed-off-by: Jernej Skrabec --- common/edid.c | 9 + 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/common/edid.c b/common/edid.c index 553ab8fd01a1..1cb7177742e8 100644 --- a/common/edid.c +++ b/common/edid.c @@ -185,6 +185,11 @@ int edid_get_timing_validate(u8 *buf, int buf_size, return -EINVAL; } + if (!EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid)) { + debug("%s: Not a digital display\n", __func__); + return -ENOSYS; + } + if (!EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(*edid)) { debug("%s: No preferred timing\n", __func__); return -ENOENT; @@ -211,10 +216,6 @@ int edid_get_timing_validate(u8 *buf, int buf_size, if (!timing_done) return -EINVAL; - if (!EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid)) { - debug("%s: Not a digital display\n", __func__); - return -ENOSYS; - } if (edid->version != 1 || edid->revision < 4) { debug("%s: EDID version %d.%d does not have required info\n", __func__, edid->version, edid->revision); -- 2.30.1
[PATCH v2 02/19] video: sunxi: Add mode_valid callback to sunxi_dw_hdmi
Currently driver accepts all resolution which won't work on 4k screens. Add validation callback which limits acceptable resolutions to 297 MHz. Reviewed-by: Andre Przywara Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_dw_hdmi.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 0b8cefc311ef..e3811a2ec15f 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -305,6 +305,12 @@ static int sunxi_dw_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size) return dw_hdmi_read_edid(>hdmi, buf, buf_size); } +static bool sunxi_dw_hdmi_mode_valid(struct udevice *dev, +const struct display_timing *timing) +{ + return timing->pixelclock.typ <= 29700; +} + static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp, const struct display_timing *edid) { @@ -388,6 +394,7 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev) static const struct dm_display_ops sunxi_dw_hdmi_ops = { .read_edid = sunxi_dw_hdmi_read_edid, .enable = sunxi_dw_hdmi_enable, + .mode_valid = sunxi_dw_hdmi_mode_valid, }; U_BOOT_DRIVER(sunxi_dw_hdmi) = { -- 2.30.1
[PATCH v2 01/19] sunxi: video: select dw-hdmi in Kconfig, not Makefile
Currently sunxi Makefile manually specifies full path to dw-hdmi common code. However, that is not needed because it can be selected in Kconfig instead. Select proper symbol in Kconfig and drop path from Makefile. Reviewed-by: Andre Przywara Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/Kconfig | 1 + drivers/video/sunxi/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 0135575ca1eb..9149196b223e 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -972,6 +972,7 @@ config VIDEO_DE2 depends on SUNXI_DE2 select DM_VIDEO select DISPLAY + select VIDEO_DW_HDMI imply VIDEO_DT_SIMPLEFB default y ---help--- diff --git a/drivers/video/sunxi/Makefile b/drivers/video/sunxi/Makefile index 147e18799229..4321673312bf 100644 --- a/drivers/video/sunxi/Makefile +++ b/drivers/video/sunxi/Makefile @@ -4,4 +4,4 @@ # Wolfgang Denk, DENX Software Engineering, w...@denx.de. obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o simplefb_common.o lcdc.o tve_common.o ../videomodes.o -obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o simplefb_common.o lcdc.o ../dw_hdmi.o sunxi_lcd.o +obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o simplefb_common.o lcdc.o sunxi_lcd.o -- 2.30.1
[PATCH v2 00/19] video: sunxi: rework DE2 driver
This series greatly reworks DE2 mixer and accompanying DW-HDMI platform driver. Main goal was to use as many information from device tree as possible and thus removing SoC speficic ifdefs from the code. This was largely accomplished for mixer, HDMI and HDMI PHY driver. Most of these changes are not user visible. Only improvements relevant to the user are filtering HDMI modes based on pixel clock and searching for additional detailed timings in EDID extension block. This change allows me to use 4k monitor that I have - base EDID block on this monitor holds only 4k@60 detailed timing. Other detailed timings, which are appropriate for HDMI 1.4 controller, are contained in extension block. There is plenty of work to do. TCON handling should go to dedicated driver and clock related code in TCON and DW-HDMI code should be moved to clock drivers. Testing was done only on H3. Best regards, Jernej Changes from v1: - collected tags - reword some commit messages - dropped patch 13 and 14 from v1 - 2 new patches, first add HDMI PHY driver and another drops PHY code from sunxi dw-hdmi driver and uses separate driver instead Jernej Skrabec (19): sunxi: video: select dw-hdmi in Kconfig, not Makefile video: sunxi: Add mode_valid callback to sunxi_dw_hdmi common: edid: check for digital display earlier common: edid: extract code for detailed timing search common: edid: Search for valid timing in extension block video: sunxi: Use DW-HDMI hpd function video: sunxi: Remove check for ddc-i2c-bus property video: sunxi: Remove TV probe from DE2 video: sunxi: de2: switch to public uclass functions video: sunxi: dw-hdmi: probe driver by compatible video: sunxi: dw-hdmi: read address from DT node video: sunxi: de2: switch to DT probing video: sunxi: de2: read address from DT node clk: sunxi: Add DE2 and HDMI clocks to H3 and A64 clk: sunxi: add DE2 clock driver video: sunxi: de2: switch clock setup to DM model video: dw-hdmi: modify phy init callback to include full timings video: sunxi: Add DW HDMI PHY driver video: sunxi: dw-hdmi: Use new PHY driver arch/arm/mach-sunxi/Kconfig | 3 + common/edid.c | 82 +++-- drivers/clk/sunxi/Kconfig | 5 + drivers/clk/sunxi/Makefile | 1 + drivers/clk/sunxi/clk_a64.c | 12 + drivers/clk/sunxi/clk_de2.c | 85 + drivers/clk/sunxi/clk_h3.c | 12 + drivers/video/dw_hdmi.c | 6 +- drivers/video/meson/meson_dw_hdmi.c | 5 +- drivers/video/sunxi/Makefile| 2 +- drivers/video/sunxi/sunxi_de2.c | 191 +-- drivers/video/sunxi/sunxi_dw_hdmi.c | 300 - drivers/video/sunxi/sunxi_dw_hdmi_phy.c | 423 drivers/video/sunxi/sunxi_dw_hdmi_phy.h | 24 ++ include/dw_hdmi.h | 4 +- 15 files changed, 780 insertions(+), 375 deletions(-) create mode 100644 drivers/clk/sunxi/clk_de2.c create mode 100644 drivers/video/sunxi/sunxi_dw_hdmi_phy.c create mode 100644 drivers/video/sunxi/sunxi_dw_hdmi_phy.h -- 2.30.1
[PATCH 19/19] video: sunxi: de2: switch clock setup to DM model
Now that proper DM clock and reset driver exists for Display Engine 2 and 3, remove all clock and reset related code and use appropriate framework instead. Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/Kconfig | 1 + drivers/video/sunxi/sunxi_de2.c | 67 +++-- 2 files changed, 23 insertions(+), 45 deletions(-) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 9149196b223e..34ef1f4b030f 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -970,6 +970,7 @@ config SUNXI_DE2 config VIDEO_DE2 bool "Display Engine 2 video driver" depends on SUNXI_DE2 + select CLK_SUN8I_DE2 select DM_VIDEO select DISPLAY select VIDEO_DW_HDMI diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index f6c8ca075aba..cee9b46b1259 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -14,10 +15,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include "simplefb_common.h" @@ -36,40 +37,10 @@ struct sunxi_de2_data { const char *disp_drv_name; }; -static void sunxi_de2_composer_init(void) -{ - struct sunxi_ccm_reg * const ccm = - (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; - -#ifdef CONFIG_MACH_SUN50I - u32 reg_value; - - /* set SRAM for video use (A64 only) */ - reg_value = readl(SUNXI_SRAMC_BASE + 0x04); - reg_value &= ~(0x01 << 24); - writel(reg_value, SUNXI_SRAMC_BASE + 0x04); -#endif - - clock_set_pll10(43200); - - /* Set DE parent to pll10 */ - clrsetbits_le32(>de_clk_cfg, CCM_DE2_CTRL_PLL_MASK, - CCM_DE2_CTRL_PLL10); - - /* Set ahb gating to pass */ - setbits_le32(>ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE); - setbits_le32(>ahb_gate1, 1 << AHB_GATE_OFFSET_DE); - - /* Clock on */ - setbits_le32(>de_clk_cfg, CCM_DE2_CTRL_GATE); -} - -static void sunxi_de2_mode_set(ulong de_mux_base, int mux, +static void sunxi_de2_mode_set(ulong de_mux_base, const struct display_timing *mode, int bpp, ulong address, bool is_composite) { - struct de_clk * const de_clk_regs = - (struct de_clk *)(SUNXI_DE2_BASE); struct de_glb * const de_glb_regs = (struct de_glb *)(de_mux_base + SUNXI_DE2_MUX_GLB_REGS); @@ -87,17 +58,6 @@ static void sunxi_de2_mode_set(ulong de_mux_base, int mux, int channel; u32 format; - /* enable clock */ -#ifdef CONFIG_MACH_SUN8I_H3 - setbits_le32(_clk_regs->rst_cfg, (mux == 0) ? 1 : 4); -#else - setbits_le32(_clk_regs->rst_cfg, BIT(mux)); -#endif - setbits_le32(_clk_regs->gate_cfg, BIT(mux)); - setbits_le32(_clk_regs->bus_cfg, BIT(mux)); - - clrbits_le32(_clk_regs->sel_cfg, 1); - writel(SUNXI_DE2_MUX_GLB_CTL_EN, _glb_regs->ctl); writel(0, _glb_regs->status); writel(1, _glb_regs->dbuff); @@ -189,6 +149,8 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase, struct video_priv *uc_priv = dev_get_uclass_priv(dev); struct display_timing timing; struct display_plat *disp_uc_plat; + struct reset_ctl_bulk resets; + struct clk_bulk clocks; int ret; disp_uc_plat = dev_get_uclass_plat(disp); @@ -206,8 +168,23 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase, return ret; } - sunxi_de2_composer_init(); - sunxi_de2_mode_set((ulong)dev_read_addr(dev), mux, , + ret = reset_get_bulk(dev, ); + if (ret) + return ret; + + ret = clk_get_bulk(dev, ); + if (ret) + return ret; + + ret = clk_enable_bulk(); + if (ret) + return ret; + + ret = reset_deassert_bulk(); + if (ret) + return ret; + + sunxi_de2_mode_set((ulong)dev_read_addr(dev), , 1 << l2bpp, fbbase, is_composite); ret = display_enable(disp, 1 << l2bpp, ); -- 2.30.1
[PATCH 18/19] clk: sunxi: add DE2 clock driver
Video driver currently manages clocks and resets by directly writing to registers. This is already a bit messy because each SoC has some specifics. It's much better to implement proper clock and reset driver which takes information from device tree file. Note that this driver is not perfect yet. It still sets PLL and parent by hand. Sunxi clock framework still doesn't know how to set parents or rates. However, this is already big step in right direction. Cc: Lukasz Majewski Signed-off-by: Jernej Skrabec --- drivers/clk/sunxi/Kconfig | 5 +++ drivers/clk/sunxi/Makefile | 1 + drivers/clk/sunxi/clk_de2.c | 85 + 3 files changed, 91 insertions(+) create mode 100644 drivers/clk/sunxi/clk_de2.c diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig index bf084fa7a84a..6c96affb1f87 100644 --- a/drivers/clk/sunxi/Kconfig +++ b/drivers/clk/sunxi/Kconfig @@ -44,6 +44,11 @@ config CLK_SUN8I_A83T This enables common clock driver support for platforms based on Allwinner A83T SoC. +config CLK_SUN8I_DE2 + bool "Clock driver for Allwinner Display Engine 2 and 3" + help + This enables common clock driver support for Display Engine 2 and 3. + config CLK_SUN8I_R40 bool "Clock driver for Allwinner R40" default MACH_SUN8I_R40 diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 0dfc0593fb1c..620ff96ac6f5 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_CLK_SUN5I_A10S) += clk_a10s.o obj-$(CONFIG_CLK_SUN6I_A31) += clk_a31.o obj-$(CONFIG_CLK_SUN8I_A23) += clk_a23.o obj-$(CONFIG_CLK_SUN8I_A83T) += clk_a83t.o +obj-$(CONFIG_CLK_SUN8I_DE2) += clk_de2.o obj-$(CONFIG_CLK_SUN8I_R40) += clk_r40.o obj-$(CONFIG_CLK_SUN8I_V3S) += clk_v3s.o obj-$(CONFIG_CLK_SUN9I_A80) += clk_a80.o diff --git a/drivers/clk/sunxi/clk_de2.c b/drivers/clk/sunxi/clk_de2.c new file mode 100644 index ..b8c45404c1b6 --- /dev/null +++ b/drivers/clk/sunxi/clk_de2.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2021 Jernej Skrabec + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct ccu_clk_gate de2_gates[] = { + [CLK_MIXER0]= GATE(0x00, BIT(0)), + [CLK_MIXER1]= GATE(0x00, BIT(1)), + [CLK_WB]= GATE(0x00, BIT(2)), + + [CLK_BUS_MIXER0]= GATE(0x04, BIT(0)), + [CLK_BUS_MIXER1]= GATE(0x04, BIT(1)), + [CLK_BUS_WB]= GATE(0x04, BIT(2)), +}; + +static struct ccu_reset de2_resets[] = { + [RST_MIXER0]= RESET(0x08, BIT(0)), + [RST_MIXER1]= RESET(0x08, BIT(1)), + [RST_WB]= RESET(0x08, BIT(2)), +}; + +static const struct ccu_desc de2_ccu_desc = { + .gates = de2_gates, + .resets = de2_resets, +}; + +static int de2_clk_probe(struct udevice *dev) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + u32 val; + + if (device_is_compatible(dev_get_parent(dev), +"allwinner,sun50i-a64-de2")) { + /* set SRAM for video use */ + val = readl(SUNXI_SRAMC_BASE + 0x04); + val &= ~(0x01 << 24); + writel(val, SUNXI_SRAMC_BASE + 0x04); + } + + /* clock driver doesn't know how to set rate or parent yet */ + clock_set_pll10(43200); + + /* Set DE parent to pll10 */ + clrsetbits_le32(>de_clk_cfg, CCM_DE2_CTRL_PLL_MASK, + CCM_DE2_CTRL_PLL10); + + return sunxi_clk_probe(dev); +} + +static int de2_clk_bind(struct udevice *dev) +{ + return sunxi_reset_bind(dev, ARRAY_SIZE(de2_resets)); +} + +static const struct udevice_id de2_ccu_ids[] = { + { .compatible = "allwinner,sun8i-h3-de2-clk", + .data = (ulong)_ccu_desc }, + { .compatible = "allwinner,sun50i-a64-de2-clk", + .data = (ulong)_ccu_desc }, + { .compatible = "allwinner,sun50i-h5-de2-clk", + .data = (ulong)_ccu_desc }, + { } +}; + +U_BOOT_DRIVER(clk_sun8i_de2) = { + .name = "sun8i_de2_ccu", + .id = UCLASS_CLK, + .of_match = de2_ccu_ids, + .priv_auto = sizeof(struct ccu_priv), + .ops= _clk_ops, + .probe = de2_clk_probe, + .bind = de2_clk_bind, +}; -- 2.30.1
[PATCH 14/19] video: sunxi: dw-hdmi: rework PHY initialization
Now that bit meanings are somewhat known, rework PHY initialization. This is modelled after Linux driver. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_dw_hdmi.c | 411 +++- 1 file changed, 279 insertions(+), 132 deletions(-) diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 4cc175d714ea..c4cded569bfb 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -18,100 +18,200 @@ #include #include +#define SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCKBIT(0) +#define SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK GENMASK(15, 8) +#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC BIT(8) +#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC BIT(9) +#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK GENMASK(23, 16) +#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR(addr) (addr << 16) + +#define SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN BIT(31) + +#define SUN8I_HDMI_PHY_READ_EN_MAGIC 0x54524545 + +#define SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC0x42494E47 + +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SWIBIT(31) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_PWEND BIT(30) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_PWENC BIT(29) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW BIT(28) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SVRCAL(x) ((x) << 26) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(x)((x) << 24) +#define SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPTBIT(23) +#define SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPTBIT(22) +#define SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT BIT(21) +#define SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT BIT(20) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL BIT(19) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENCALOGBIT(18) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDSBIT(17) +#define SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN BIT(16) +#define SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK GENMASK(15, 12) +#define SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL (0xf << 12) +#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK BIT(11) +#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 BIT(10) +#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 BIT(9) +#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 BIT(8) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK BIT(7) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2BIT(6) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1BIT(5) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0BIT(4) +#define SUN8I_HDMI_PHY_ANA_CFG1_CKEN BIT(3) +#define SUN8I_HDMI_PHY_ANA_CFG1_LDOEN BIT(2) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENVBS BIT(1) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENBI BIT(0) + +#define SUN8I_HDMI_PHY_ANA_CFG2_M_EN BIT(31) +#define SUN8I_HDMI_PHY_ANA_CFG2_PLLDBENBIT(30) +#define SUN8I_HDMI_PHY_ANA_CFG2_SENBIT(29) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_HPDPD BIT(28) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_HPDEN BIT(27) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_PLRCK BIT(26) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_PLR(x) ((x) << 23) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK BIT(22) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_DENBIT(21) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CD(x) ((x) << 19) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(x)((x) << 17) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCKBIT(16) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW BIT(15) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CSMPS(x) ((x) << 13) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(x) ((x) << 10) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BOOSTCK(x) ((x) << 8) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BOOST(x) ((x) << 6) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(x) ((x) << 0) + +#define SUN8I_HDMI_PHY_ANA_CFG3_REG_SLOWCK(x) ((x) << 30) +#define SUN8I_HDMI_PHY_ANA_CFG3_REG_SLOW(x)((x) << 28) +#define SUN8I_HDMI_PHY_ANA_CFG3_REG_WIRE(x)((x) << 18) +#define SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(x) ((x) << 14) +#define SUN8I_HDMI_PHY_ANA_CFG3_REG_EMPCK(x) ((x) << 11) +#define SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(x) ((x) << 7) +#define SUN8I_HDMI_PHY_ANA_CFG3_REG_EMP(x) ((x) << 4) +#define SUN8I_HDMI_PHY_ANA_CFG3_SDAPD BIT(3) +#define SUN8I_HDMI_PHY_ANA_CFG3_SDAEN BIT(2) +#define SUN8I_HDMI_PHY_ANA_CFG3_SCLPD BIT(1) +#define SUN8I_HDMI_PHY_ANA_CFG3_SCLEN BIT(0) + +#define SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1BIT(31) +#define SUN8I_HDMI_PHY_PLL_CFG1_REG_OD BIT(30) +#define SUN8I_HDMI_PHY_PLL_CFG1_LDO2_ENBIT(29) +#define SUN8I_HDMI_PHY_PLL_CFG1_LDO1_ENBIT(28) +#define SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 BIT(27) +#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK BIT(26) +#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT 26 +#define SUN8I_HDMI_PHY_PLL_CFG1_PLLEN BIT(25) +#define SUN8I
[PATCH 17/19] clk: sunxi: Add DE2 clocks to H3 and A64
With the next commit another clock and reset driver will be implemented which requires DE2 related clocks and resets. Add them. Cc: Lukasz Majewski Signed-off-by: Jernej Skrabec --- drivers/clk/sunxi/clk_a64.c | 6 ++ drivers/clk/sunxi/clk_h3.c | 6 ++ 2 files changed, 12 insertions(+) diff --git a/drivers/clk/sunxi/clk_a64.c b/drivers/clk/sunxi/clk_a64.c index 0553ffa4399a..c7cf88ce3436 100644 --- a/drivers/clk/sunxi/clk_a64.c +++ b/drivers/clk/sunxi/clk_a64.c @@ -26,6 +26,8 @@ static const struct ccu_clk_gate a64_gates[] = { [CLK_BUS_OHCI0] = GATE(0x060, BIT(28)), [CLK_BUS_OHCI1] = GATE(0x060, BIT(29)), + [CLK_BUS_DE]= GATE(0x064, BIT(12)), + [CLK_BUS_UART0] = GATE(0x06c, BIT(16)), [CLK_BUS_UART1] = GATE(0x06c, BIT(17)), [CLK_BUS_UART2] = GATE(0x06c, BIT(18)), @@ -41,6 +43,8 @@ static const struct ccu_clk_gate a64_gates[] = { [CLK_USB_HSIC_12M] = GATE(0x0cc, BIT(11)), [CLK_USB_OHCI0] = GATE(0x0cc, BIT(16)), [CLK_USB_OHCI1] = GATE(0x0cc, BIT(17)), + + [CLK_DE]= GATE(0x104, BIT(31)), }; static const struct ccu_reset a64_resets[] = { @@ -60,6 +64,8 @@ static const struct ccu_reset a64_resets[] = { [RST_BUS_OHCI0] = RESET(0x2c0, BIT(28)), [RST_BUS_OHCI1] = RESET(0x2c0, BIT(29)), + [RST_BUS_DE]= RESET(0x2c4, BIT(12)), + [RST_BUS_UART0] = RESET(0x2d8, BIT(16)), [RST_BUS_UART1] = RESET(0x2d8, BIT(17)), [RST_BUS_UART2] = RESET(0x2d8, BIT(18)), diff --git a/drivers/clk/sunxi/clk_h3.c b/drivers/clk/sunxi/clk_h3.c index f81633b92d5a..bf8d963d18b6 100644 --- a/drivers/clk/sunxi/clk_h3.c +++ b/drivers/clk/sunxi/clk_h3.c @@ -30,6 +30,8 @@ static struct ccu_clk_gate h3_gates[] = { [CLK_BUS_OHCI2] = GATE(0x060, BIT(30)), [CLK_BUS_OHCI3] = GATE(0x060, BIT(31)), + [CLK_BUS_DE]= GATE(0x064, BIT(12)), + [CLK_BUS_UART0] = GATE(0x06c, BIT(16)), [CLK_BUS_UART1] = GATE(0x06c, BIT(17)), [CLK_BUS_UART2] = GATE(0x06c, BIT(18)), @@ -48,6 +50,8 @@ static struct ccu_clk_gate h3_gates[] = { [CLK_USB_OHCI1] = GATE(0x0cc, BIT(17)), [CLK_USB_OHCI2] = GATE(0x0cc, BIT(18)), [CLK_USB_OHCI3] = GATE(0x0cc, BIT(19)), + + [CLK_DE]= GATE(0x104, BIT(31)), }; static struct ccu_reset h3_resets[] = { @@ -72,6 +76,8 @@ static struct ccu_reset h3_resets[] = { [RST_BUS_OHCI2] = RESET(0x2c0, BIT(30)), [RST_BUS_OHCI3] = RESET(0x2c0, BIT(31)), + [RST_BUS_DE]= RESET(0x2c4, BIT(12)), + [RST_BUS_EPHY] = RESET(0x2c8, BIT(2)), [RST_BUS_UART0] = RESET(0x2d8, BIT(16)), -- 2.30.1
[PATCH 16/19] video: sunxi: de2: read address from DT node
Currently DE2 uses hardcoded address based on SoC for which U-Boot is built. Read it from DT instead so there is no need to specify it when support for new SoC is added. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_de2.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index 81576e45e9ef..f6c8ca075aba 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -64,11 +64,10 @@ static void sunxi_de2_composer_init(void) setbits_le32(>de_clk_cfg, CCM_DE2_CTRL_GATE); } -static void sunxi_de2_mode_set(int mux, const struct display_timing *mode, +static void sunxi_de2_mode_set(ulong de_mux_base, int mux, + const struct display_timing *mode, int bpp, ulong address, bool is_composite) { - ulong de_mux_base = (mux == 0) ? - SUNXI_DE2_MUX0_BASE : SUNXI_DE2_MUX1_BASE; struct de_clk * const de_clk_regs = (struct de_clk *)(SUNXI_DE2_BASE); struct de_glb * const de_glb_regs = @@ -208,7 +207,8 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase, } sunxi_de2_composer_init(); - sunxi_de2_mode_set(mux, , 1 << l2bpp, fbbase, is_composite); + sunxi_de2_mode_set((ulong)dev_read_addr(dev), mux, , + 1 << l2bpp, fbbase, is_composite); ret = display_enable(disp, 1 << l2bpp, ); if (ret) { -- 2.30.1
[PATCH 15/19] video: sunxi: de2: switch to DT probing
Currently DE2 driver is probed via driver info. Switch probing to device tree compatible string method. Display is now searched via driver name which has same limitation as previous method. This can be improved only when all drivers in chain are probed via device tree compatible strings. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_de2.c | 88 +++-- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index e02d359cd259..81576e45e9ef 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -31,6 +31,11 @@ enum { LCD_MAX_LOG2_BPP= VIDEO_BPP32, }; +struct sunxi_de2_data { + int id; + const char *disp_drv_name; +}; + static void sunxi_de2_composer_init(void) { struct sunxi_ccm_reg * const ccm = @@ -228,51 +233,34 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase, static int sunxi_de2_probe(struct udevice *dev) { + const struct sunxi_de2_data *data = + (const struct sunxi_de2_data *)dev_get_driver_data(dev); struct video_uc_plat *plat = dev_get_uclass_plat(dev); struct udevice *disp; - int ret; + int ret, index = 0; /* Before relocation we don't need to do anything */ if (!(gd->flags & GD_FLG_RELOC)) return 0; - ret = uclass_get_device_by_driver(UCLASS_DISPLAY, - DM_DRIVER_GET(sunxi_lcd), ); - if (!ret) { - int mux; + while (!(ret = uclass_get_device(UCLASS_DISPLAY, index++, ))) { + if (strcmp(disp->driver->name, data->disp_drv_name)) + continue; - mux = 0; + ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, +data->id, false); + if (ret) + return ret; - ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux, -false); - if (!ret) { - video_set_flush_dcache(dev, 1); - return 0; - } - } - - debug("%s: lcd display not found (ret=%d)\n", __func__, ret); - - ret = uclass_get_device_by_driver(UCLASS_DISPLAY, - DM_DRIVER_GET(sunxi_dw_hdmi), ); - if (!ret) { - int mux; - if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5)) - mux = 0; - else - mux = 1; + video_set_flush_dcache(dev, 1); - ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux, -false); - if (!ret) { - video_set_flush_dcache(dev, 1); - return 0; - } + return 0; } - debug("%s: hdmi display not found (ret=%d)\n", __func__, ret); + debug("%s: %s not found (ret=%d)\n", __func__, + data->disp_drv_name, ret); - return -ENODEV; + return ret; } static int sunxi_de2_bind(struct udevice *dev) @@ -285,22 +273,50 @@ static int sunxi_de2_bind(struct udevice *dev) return 0; } +const struct sunxi_de2_data h3_mixer_0 = { + .id = 0, + .disp_drv_name = "sunxi_dw_hdmi", +}; + +const struct sunxi_de2_data a64_mixer_0 = { + .id = 0, + .disp_drv_name = "sunxi_lcd", +}; + +const struct sunxi_de2_data a64_mixer_1 = { + .id = 1, + .disp_drv_name = "sunxi_dw_hdmi", +}; + +static const struct udevice_id sunxi_de2_ids[] = { + { + .compatible = "allwinner,sun8i-h3-de2-mixer-0", + .data = (ulong)_mixer_0, + }, + { + .compatible = "allwinner,sun50i-a64-de2-mixer-0", + .data = (ulong)_mixer_0, + }, + { + .compatible = "allwinner,sun50i-a64-de2-mixer-1", + .data = (ulong)_mixer_1, + }, + { } +}; + static const struct video_ops sunxi_de2_ops = { }; U_BOOT_DRIVER(sunxi_de2) = { .name = "sunxi_de2", .id = UCLASS_VIDEO, + .of_match = sunxi_de2_ids, .ops= _de2_ops, .bind = sunxi_de2_bind, .probe = sunxi_de2_probe, .flags = DM_FLAG_PRE_RELOC, }; -U_BOOT_DRVINFO(sunxi_de2) = { - .name = "sunxi_de2" -}; - /* * Simplefb support. */ -- 2.30.1
[PATCH 09/19] video: sunxi: de2: switch to public uclass functions
Currently DE2 driver uses functions which are defined in -internal header. They are not meant to be used outside of uclass framework. Switch DE2 driver to public ones. This has additional benefit that device_probe doesn't need to be called manually. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_de2.c | 29 ++--- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index 6b836a011944..e02d359cd259 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -19,8 +19,6 @@ #include #include #include -#include -#include #include #include "simplefb_common.h" @@ -198,13 +196,6 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase, disp_uc_plat->source_id = mux; - ret = device_probe(disp); - if (ret) { - debug("%s: device '%s' display won't probe (ret=%d)\n", - __func__, dev->name, ret); - return ret; - } - ret = display_read_timing(disp, ); if (ret) { debug("%s: Failed to read timings\n", __func__); @@ -245,8 +236,8 @@ static int sunxi_de2_probe(struct udevice *dev) if (!(gd->flags & GD_FLG_RELOC)) return 0; - ret = uclass_find_device_by_name(UCLASS_DISPLAY, -"sunxi_lcd", ); + ret = uclass_get_device_by_driver(UCLASS_DISPLAY, + DM_DRIVER_GET(sunxi_lcd), ); if (!ret) { int mux; @@ -262,8 +253,8 @@ static int sunxi_de2_probe(struct udevice *dev) debug("%s: lcd display not found (ret=%d)\n", __func__, ret); - ret = uclass_find_device_by_name(UCLASS_DISPLAY, -"sunxi_dw_hdmi", ); + ret = uclass_get_device_by_driver(UCLASS_DISPLAY, + DM_DRIVER_GET(sunxi_dw_hdmi), ); if (!ret) { int mux; if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5)) @@ -332,8 +323,8 @@ int sunxi_simplefb_setup(void *blob) mux = 1; /* Skip simplefb setting if DE2 / HDMI is not present */ - ret = uclass_find_device_by_name(UCLASS_VIDEO, -"sunxi_de2", ); + ret = uclass_get_device_by_driver(UCLASS_VIDEO, + DM_DRIVER_GET(sunxi_de2), ); if (ret) { debug("DE2 not present\n"); return 0; @@ -342,8 +333,8 @@ int sunxi_simplefb_setup(void *blob) return 0; } - ret = uclass_find_device_by_name(UCLASS_DISPLAY, -"sunxi_dw_hdmi", ); + ret = uclass_get_device_by_driver(UCLASS_DISPLAY, + DM_DRIVER_GET(sunxi_dw_hdmi), ); if (ret) { debug("HDMI not present\n"); } else if (device_active(hdmi)) { @@ -355,8 +346,8 @@ int sunxi_simplefb_setup(void *blob) debug("HDMI present but not probed\n"); } - ret = uclass_find_device_by_name(UCLASS_DISPLAY, -"sunxi_lcd", ); + ret = uclass_get_device_by_driver(UCLASS_DISPLAY, + DM_DRIVER_GET(sunxi_lcd), ); if (ret) debug("LCD not present\n"); else if (device_active(lcd)) -- 2.30.1
[PATCH 13/19] video: sunxi: dw-hdmi: move PHY config to appropriate place
Currently sunxi_dw_hdmi_enable() configures PHY timing related parameters. However, sunxi_dw_hdmi_phy_cfg() is better suited place for that. Move the code there. This also allows to easier driver expansion when controller uses different PHY than currently supported (like that in H6). Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_dw_hdmi.c | 24 +--- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 483d57293155..4cc175d714ea 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -114,11 +114,13 @@ static void sunxi_dw_hdmi_phy_init(struct dw_hdmi *hdmi) writel(0x42494E47, >unscramble); } -static void sunxi_dw_hdmi_phy_set(struct dw_hdmi *hdmi, uint clock, int phy_div) +static void sunxi_dw_hdmi_phy_set(struct dw_hdmi *hdmi, + const struct display_timing *edid, + int phy_div) { struct sunxi_hdmi_phy * const phy = (struct sunxi_hdmi_phy *)(hdmi->ioaddr + HDMI_PHY_OFFS); - int div = sunxi_dw_hdmi_get_divider(clock); + int div = sunxi_dw_hdmi_get_divider(edid->pixelclock.typ); u32 tmp; /* @@ -187,6 +189,14 @@ static void sunxi_dw_hdmi_phy_set(struct dw_hdmi *hdmi, uint clock, int phy_div) writel(0x0F81C405, >unk2); break; } + + if (edid->flags & DISPLAY_FLAGS_VSYNC_LOW) + setbits_le32(>pol, 0x200); + + if (edid->flags & DISPLAY_FLAGS_HSYNC_LOW) + setbits_le32(>pol, 0x100); + + setbits_le32(>ctrl, 0xf << 12); } static void sunxi_dw_hdmi_pll_set(uint clk_khz, int *phy_div) @@ -272,7 +282,7 @@ static int sunxi_dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, int phy_div; sunxi_dw_hdmi_pll_set(edid->pixelclock.typ / 1000, _div); - sunxi_dw_hdmi_phy_set(hdmi, edid->pixelclock.typ, phy_div); + sunxi_dw_hdmi_phy_set(hdmi, edid, phy_div); return 0; } @@ -304,14 +314,6 @@ static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp, sunxi_dw_hdmi_lcdc_init(priv->mux, edid, panel_bpp); - if (edid->flags & DISPLAY_FLAGS_VSYNC_LOW) - setbits_le32(>pol, 0x200); - - if (edid->flags & DISPLAY_FLAGS_HSYNC_LOW) - setbits_le32(>pol, 0x100); - - setbits_le32(>ctrl, 0xf << 12); - /* * This is last hdmi access before boot, so scramble addresses * again or othwerwise BSP driver won't work. Dummy read is -- 2.30.1
[PATCH 11/19] video: sunxi: dw-hdmi: read address from DT node
Currently HDMI controller MMIO address is hardcoded. Change that so address is read from DT node. That will make adding support for new variants a bit easier. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_dw_hdmi.c | 38 ++--- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 6f77b2a43b40..0744954fa15f 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -57,10 +57,10 @@ static int sunxi_dw_hdmi_get_divider(uint clock) return 1; } -static void sunxi_dw_hdmi_phy_init(void) +static void sunxi_dw_hdmi_phy_init(struct dw_hdmi *hdmi) { struct sunxi_hdmi_phy * const phy = - (struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS); + (struct sunxi_hdmi_phy *)(hdmi->ioaddr + HDMI_PHY_OFFS); unsigned long tmo; u32 tmp; @@ -114,10 +114,10 @@ static void sunxi_dw_hdmi_phy_init(void) writel(0x42494E47, >unscramble); } -static void sunxi_dw_hdmi_phy_set(uint clock, int phy_div) +static void sunxi_dw_hdmi_phy_set(struct dw_hdmi *hdmi, uint clock, int phy_div) { struct sunxi_hdmi_phy * const phy = - (struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS); + (struct sunxi_hdmi_phy *)(hdmi->ioaddr + HDMI_PHY_OFFS); int div = sunxi_dw_hdmi_get_divider(clock); u32 tmp; @@ -271,7 +271,7 @@ static int sunxi_dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock) int phy_div; sunxi_dw_hdmi_pll_set(mpixelclock / 1000, _div); - sunxi_dw_hdmi_phy_set(mpixelclock, phy_div); + sunxi_dw_hdmi_phy_set(hdmi, mpixelclock, phy_div); return 0; } @@ -292,9 +292,9 @@ static bool sunxi_dw_hdmi_mode_valid(struct udevice *dev, static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp, const struct display_timing *edid) { - struct sunxi_hdmi_phy * const phy = - (struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS); struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev); + struct sunxi_hdmi_phy * const phy = + (struct sunxi_hdmi_phy *)(priv->hdmi.ioaddr + HDMI_PHY_OFFS); int ret; ret = dw_hdmi_enable(>hdmi, edid); @@ -316,12 +316,26 @@ static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp, * again or othwerwise BSP driver won't work. Dummy read is * needed or otherwise last write doesn't get written correctly. */ - (void)readb(SUNXI_HDMI_BASE); + (void)readb(priv->hdmi.ioaddr); writel(0, >unscramble); return 0; } +static int sunxi_dw_hdmi_of_to_plat(struct udevice *dev) +{ + struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev); + struct dw_hdmi *hdmi = >hdmi; + + hdmi->ioaddr = (ulong)dev_read_addr(dev); + hdmi->i2c_clk_high = 0xd8; + hdmi->i2c_clk_low = 0xfe; + hdmi->reg_io_width = 1; + hdmi->phy_set = sunxi_dw_hdmi_phy_cfg; + + return 0; +} + static int sunxi_dw_hdmi_probe(struct udevice *dev) { struct display_plat *uc_plat = dev_get_uclass_plat(dev); @@ -346,13 +360,8 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev) /* Clock on */ setbits_le32(>hdmi_clk_cfg, CCM_HDMI_CTRL_GATE); - sunxi_dw_hdmi_phy_init(); + sunxi_dw_hdmi_phy_init(>hdmi); - priv->hdmi.ioaddr = SUNXI_HDMI_BASE; - priv->hdmi.i2c_clk_high = 0xd8; - priv->hdmi.i2c_clk_low = 0xfe; - priv->hdmi.reg_io_width = 1; - priv->hdmi.phy_set = sunxi_dw_hdmi_phy_cfg; priv->mux = uc_plat->source_id; ret = dw_hdmi_phy_wait_for_hpd(>hdmi); @@ -382,6 +391,7 @@ U_BOOT_DRIVER(sunxi_dw_hdmi) = { .id = UCLASS_DISPLAY, .of_match = sunxi_dw_hdmi_ids, .ops= _dw_hdmi_ops, + .of_to_plat = sunxi_dw_hdmi_of_to_plat, .probe = sunxi_dw_hdmi_probe, .priv_auto = sizeof(struct sunxi_dw_hdmi_priv), }; -- 2.30.1
[PATCH 10/19] video: sunxi: dw-hdmi: probe driver by compatible
Currently sunxi dw-hdmi driver is probed unconditionally, even if there is no such device. Switch driver to probing via compatible string. This brings many benefits - driver can read DT node and allows driver to be always enabled. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_dw_hdmi.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 6d2bc206fc2c..6f77b2a43b40 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -372,14 +372,16 @@ static const struct dm_display_ops sunxi_dw_hdmi_ops = { .mode_valid = sunxi_dw_hdmi_mode_valid, }; +static const struct udevice_id sunxi_dw_hdmi_ids[] = { + { .compatible = "allwinner,sun8i-a83t-dw-hdmi" }, + { } +}; + U_BOOT_DRIVER(sunxi_dw_hdmi) = { .name = "sunxi_dw_hdmi", .id = UCLASS_DISPLAY, + .of_match = sunxi_dw_hdmi_ids, .ops= _dw_hdmi_ops, .probe = sunxi_dw_hdmi_probe, .priv_auto = sizeof(struct sunxi_dw_hdmi_priv), }; - -U_BOOT_DRVINFO(sunxi_dw_hdmi) = { - .name = "sunxi_dw_hdmi" -}; -- 2.30.1
[PATCH 12/19] video: dw-hdmi: modify phy init callback to include full timings
Currently PHY init callback has only pixel clock as a parameter, but other timing parameters may be needed for custom PHYs. Modify callback signature to include full timings. Cc: Neil Armstrong Signed-off-by: Jernej Skrabec --- drivers/video/dw_hdmi.c | 6 +++--- drivers/video/meson/meson_dw_hdmi.c | 5 +++-- drivers/video/sunxi/sunxi_dw_hdmi.c | 7 --- include/dw_hdmi.h | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/video/dw_hdmi.c b/drivers/video/dw_hdmi.c index c4fbb1829446..8d71f713f99f 100644 --- a/drivers/video/dw_hdmi.c +++ b/drivers/video/dw_hdmi.c @@ -901,7 +901,7 @@ static const u8 pre_buf[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, }; -int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock) +int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, const struct display_timing *edid) { int i, ret; @@ -912,7 +912,7 @@ int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock) hdmi_phy_enable_tmds(hdmi, 0); hdmi_phy_enable_power(hdmi, 0); - ret = hdmi_phy_configure(hdmi, mpixelclock); + ret = hdmi_phy_configure(hdmi, edid->pixelclock.typ); if (ret) { debug("hdmi phy config failure %d\n", ret); return ret; @@ -988,7 +988,7 @@ int dw_hdmi_enable(struct dw_hdmi *hdmi, const struct display_timing *edid) hdmi_av_composer(hdmi, edid); - ret = hdmi->phy_set(hdmi, edid->pixelclock.typ); + ret = hdmi->phy_set(hdmi, edid); if (ret) return ret; diff --git a/drivers/video/meson/meson_dw_hdmi.c b/drivers/video/meson/meson_dw_hdmi.c index e5f281320534..7558814b3491 100644 --- a/drivers/video/meson/meson_dw_hdmi.c +++ b/drivers/video/meson/meson_dw_hdmi.c @@ -292,7 +292,8 @@ static void meson_dw_hdmi_phy_setup_mode(struct meson_dw_hdmi *priv, } } -static int meson_dw_hdmi_phy_init(struct dw_hdmi *hdmi, uint pixel_clock) +static int meson_dw_hdmi_phy_init(struct dw_hdmi *hdmi, + const struct display_timing *edid) { struct meson_dw_hdmi *priv = container_of(hdmi, struct meson_dw_hdmi, hdmi); @@ -322,7 +323,7 @@ static int meson_dw_hdmi_phy_init(struct dw_hdmi *hdmi, uint pixel_clock) dw_hdmi_top_write(hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); /* Setup PHY parameters */ - meson_dw_hdmi_phy_setup_mode(priv, pixel_clock); + meson_dw_hdmi_phy_setup_mode(priv, edid->pixelclock.typ); /* Setup PHY */ dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1, diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 0744954fa15f..483d57293155 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -266,12 +266,13 @@ static void sunxi_dw_hdmi_lcdc_init(int mux, const struct display_timing *edid, lcdc_enable(lcdc, bpp); } -static int sunxi_dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock) +static int sunxi_dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, +const struct display_timing *edid) { int phy_div; - sunxi_dw_hdmi_pll_set(mpixelclock / 1000, _div); - sunxi_dw_hdmi_phy_set(hdmi, mpixelclock, phy_div); + sunxi_dw_hdmi_pll_set(edid->pixelclock.typ / 1000, _div); + sunxi_dw_hdmi_phy_set(hdmi, edid->pixelclock.typ, phy_div); return 0; } diff --git a/include/dw_hdmi.h b/include/dw_hdmi.h index 8acae3839fb3..46b87916b8bb 100644 --- a/include/dw_hdmi.h +++ b/include/dw_hdmi.h @@ -544,12 +544,12 @@ struct dw_hdmi { struct hdmi_data_info hdmi_data; struct udevice *ddc_bus; - int (*phy_set)(struct dw_hdmi *hdmi, uint mpixelclock); + int (*phy_set)(struct dw_hdmi *hdmi, const struct display_timing *edid); void (*write_reg)(struct dw_hdmi *hdmi, u8 val, int offset); u8 (*read_reg)(struct dw_hdmi *hdmi, int offset); }; -int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock); +int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, const struct display_timing *edid); int dw_hdmi_phy_wait_for_hpd(struct dw_hdmi *hdmi); void dw_hdmi_phy_init(struct dw_hdmi *hdmi); -- 2.30.1
[PATCH 08/19] video: sunxi: Remove TV probe from DE2
TV driver was never fully implemented. Remove search for it from DE2 driver. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_de2.c | 15 +-- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index a3e21aa5f13e..6b836a011944 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -281,20 +281,7 @@ static int sunxi_de2_probe(struct udevice *dev) debug("%s: hdmi display not found (ret=%d)\n", __func__, ret); - ret = uclass_find_device_by_name(UCLASS_DISPLAY, - "sunxi_tve", ); - if (ret) { - debug("%s: tv not found (ret=%d)\n", __func__, ret); - return ret; - } - - ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, 1, true); - if (ret) - return ret; - - video_set_flush_dcache(dev, 1); - - return 0; + return -ENODEV; } static int sunxi_de2_bind(struct udevice *dev) -- 2.30.1
[PATCH 06/19] video: sunxi: Use DW-HDMI hpd function
It turns out that even though A64, H3 and H5 have custom PHY, standard hot plug detection for DW-HDMI works just fine. Remove custom hpd method to reduce amount of custom code. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_dw_hdmi.c | 34 + 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index e3811a2ec15f..37e78ff24111 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -114,28 +114,6 @@ static void sunxi_dw_hdmi_phy_init(void) writel(0x42494E47, >unscramble); } -static int sunxi_dw_hdmi_get_plug_in_status(void) -{ - struct sunxi_hdmi_phy * const phy = - (struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS); - - return !!(readl(>status) & (1 << 19)); -} - -static int sunxi_dw_hdmi_wait_for_hpd(void) -{ - ulong start; - - start = get_timer(0); - do { - if (sunxi_dw_hdmi_get_plug_in_status()) - return 0; - udelay(100); - } while (get_timer(start) < 300); - - return -1; -} - static void sunxi_dw_hdmi_phy_set(uint clock, int phy_div) { struct sunxi_hdmi_phy * const phy = @@ -370,12 +348,6 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev) sunxi_dw_hdmi_phy_init(); - ret = sunxi_dw_hdmi_wait_for_hpd(); - if (ret < 0) { - debug("hdmi can not get hpd signal\n"); - return -1; - } - priv->hdmi.ioaddr = SUNXI_HDMI_BASE; priv->hdmi.i2c_clk_high = 0xd8; priv->hdmi.i2c_clk_low = 0xfe; @@ -383,6 +355,12 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev) priv->hdmi.phy_set = sunxi_dw_hdmi_phy_cfg; priv->mux = uc_plat->source_id; + ret = dw_hdmi_phy_wait_for_hpd(>hdmi); + if (ret < 0) { + debug("hdmi can not get hpd signal\n"); + return -1; + } + uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus", >hdmi.ddc_bus); -- 2.30.1
[PATCH 05/19] common: edid: Search for valid timing in extension block
One of my monitors have only 4k@60 timing in base EDID block which is out of range for devices with HDMI 1.4. It turns out that it has additional detailed timings in CTA-861 Extension Block and two of them are appropriate for HDMI 1.4. Add additional search for valid detailed timing in extension block. Signed-off-by: Jernej Skrabec --- common/edid.c | 18 ++ 1 file changed, 18 insertions(+) diff --git a/common/edid.c b/common/edid.c index a6c875d9c8e8..14d8836c360e 100644 --- a/common/edid.c +++ b/common/edid.c @@ -220,6 +220,24 @@ int edid_get_timing_validate(u8 *buf, int buf_size, /* Look for detailed timing in base EDID */ found = edid_find_valid_timing(edid->monitor_details.descriptor, 4, timing, mode_valid, mode_valid_priv); + + /* Look for detailed timing in CTA-861 Extension Block */ + if (!found && edid->extension_flag && buf_size >= EDID_EXT_SIZE) { + struct edid_cea861_info *info = + (struct edid_cea861_info *)(buf + sizeof(*edid)); + + if (info->extension_tag == EDID_CEA861_EXTENSION_TAG) { + int count = EDID_CEA861_DTD_COUNT(*info); + int offset = info->dtd_offset; + int size = count * sizeof(struct edid_detailed_timing); + + if (offset >= 4 && offset + size < EDID_SIZE) + found = edid_find_valid_timing( + (u8*)info + offset, count, timing, + mode_valid, mode_valid_priv); + } + } + if (!found) return -EINVAL; -- 2.30.1
[PATCH 07/19] video: sunxi: Remove check for ddc-i2c-bus property
No Allwinner boards with DW-HDMI controller use separate I2C bus for EDID read. Remove that check. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_dw_hdmi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 37e78ff24111..6d2bc206fc2c 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -361,9 +361,6 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev) return -1; } - uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus", ->hdmi.ddc_bus); - dw_hdmi_init(>hdmi); return 0; -- 2.30.1
[PATCH 04/19] common: edid: extract code for detailed timing search
Code which searches for valid detailed timing entry will be used in more places. Extract it. Signed-off-by: Jernej Skrabec --- common/edid.c | 49 - 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/common/edid.c b/common/edid.c index 1cb7177742e8..a6c875d9c8e8 100644 --- a/common/edid.c +++ b/common/edid.c @@ -169,6 +169,29 @@ static bool cea_is_hdmi_vsdb_present(struct edid_cea861_info *info) return false; } +static bool edid_find_valid_timing(void *buf, int count, + struct display_timing *timing, + bool (*mode_valid)(void *priv, + const struct display_timing *timing), + void *mode_valid_priv) +{ + struct edid_detailed_timing *t = buf; + bool found = false; + int i; + + for (i = 0; i < count && !found; i++, t++) + if (EDID_DETAILED_TIMING_PIXEL_CLOCK(*t) != 0) { + decode_timing((u8 *)t, timing); + if (mode_valid) + found = mode_valid(mode_valid_priv, + timing); + else + found = true; + } + + return found; +} + int edid_get_timing_validate(u8 *buf, int buf_size, struct display_timing *timing, int *panel_bits_per_colourp, @@ -177,8 +200,7 @@ int edid_get_timing_validate(u8 *buf, int buf_size, void *mode_valid_priv) { struct edid1_info *edid = (struct edid1_info *)buf; - bool timing_done; - int i; + bool found; if (buf_size < sizeof(*edid) || edid_check_info(edid)) { debug("%s: Invalid buffer\n", __func__); @@ -195,25 +217,10 @@ int edid_get_timing_validate(u8 *buf, int buf_size, return -ENOENT; } - /* Look for detailed timing */ - timing_done = false; - for (i = 0; i < 4; i++) { - struct edid_monitor_descriptor *desc; - - desc = >monitor_details.descriptor[i]; - if (desc->zero_flag_1 != 0) { - decode_timing((u8 *)desc, timing); - if (mode_valid) - timing_done = mode_valid(mode_valid_priv, -timing); - else - timing_done = true; - - if (timing_done) - break; - } - } - if (!timing_done) + /* Look for detailed timing in base EDID */ + found = edid_find_valid_timing(edid->monitor_details.descriptor, 4, + timing, mode_valid, mode_valid_priv); + if (!found) return -EINVAL; if (edid->version != 1 || edid->revision < 4) { -- 2.30.1
[PATCH 03/19] common: edid: check for digital display earlier
When searching for detailed timing in EDID, check for digital display earlier. There is no point parsing other parameters if this flag is not present. Signed-off-by: Jernej Skrabec --- common/edid.c | 9 + 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/common/edid.c b/common/edid.c index 553ab8fd01a1..1cb7177742e8 100644 --- a/common/edid.c +++ b/common/edid.c @@ -185,6 +185,11 @@ int edid_get_timing_validate(u8 *buf, int buf_size, return -EINVAL; } + if (!EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid)) { + debug("%s: Not a digital display\n", __func__); + return -ENOSYS; + } + if (!EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(*edid)) { debug("%s: No preferred timing\n", __func__); return -ENOENT; @@ -211,10 +216,6 @@ int edid_get_timing_validate(u8 *buf, int buf_size, if (!timing_done) return -EINVAL; - if (!EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid)) { - debug("%s: Not a digital display\n", __func__); - return -ENOSYS; - } if (edid->version != 1 || edid->revision < 4) { debug("%s: EDID version %d.%d does not have required info\n", __func__, edid->version, edid->revision); -- 2.30.1
[PATCH 02/19] video: sunxi: Add mode_valid callback to sunxi_dw_hdmi
Currently driver accepts all resolution which won't work on 4k screens. Add validation callback which limits acceptable resolutions to 297 MHz. Signed-off-by: Jernej Skrabec --- drivers/video/sunxi/sunxi_dw_hdmi.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 0b8cefc311ef..e3811a2ec15f 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -305,6 +305,12 @@ static int sunxi_dw_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size) return dw_hdmi_read_edid(>hdmi, buf, buf_size); } +static bool sunxi_dw_hdmi_mode_valid(struct udevice *dev, +const struct display_timing *timing) +{ + return timing->pixelclock.typ <= 29700; +} + static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp, const struct display_timing *edid) { @@ -388,6 +394,7 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev) static const struct dm_display_ops sunxi_dw_hdmi_ops = { .read_edid = sunxi_dw_hdmi_read_edid, .enable = sunxi_dw_hdmi_enable, + .mode_valid = sunxi_dw_hdmi_mode_valid, }; U_BOOT_DRIVER(sunxi_dw_hdmi) = { -- 2.30.1
[PATCH 01/19] sunxi: video: select dw-hdmi in Kconfig, not Makefile
Currently sunxi Makefile manually specifies full path to dw-hdmi common code. However, that is not needed because it can be selected in Kconfig instead. Select proper symbol in Kconfig and drop path from Makefile. Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/Kconfig | 1 + drivers/video/sunxi/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 0135575ca1eb..9149196b223e 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -972,6 +972,7 @@ config VIDEO_DE2 depends on SUNXI_DE2 select DM_VIDEO select DISPLAY + select VIDEO_DW_HDMI imply VIDEO_DT_SIMPLEFB default y ---help--- diff --git a/drivers/video/sunxi/Makefile b/drivers/video/sunxi/Makefile index 147e18799229..4321673312bf 100644 --- a/drivers/video/sunxi/Makefile +++ b/drivers/video/sunxi/Makefile @@ -4,4 +4,4 @@ # Wolfgang Denk, DENX Software Engineering, w...@denx.de. obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o simplefb_common.o lcdc.o tve_common.o ../videomodes.o -obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o simplefb_common.o lcdc.o ../dw_hdmi.o sunxi_lcd.o +obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o simplefb_common.o lcdc.o sunxi_lcd.o -- 2.30.1
[PATCH 00/19] video: sunxi: Rework DE2 driver
This series greatly reworks DE2 mixer and accompanying DW-HDMI platform driver. Main goal was to use as many information from device tree as possible and thus removing SoC speficic ifdefs from the code. This was largely accomplished for mixer driver and mostly for HDMI driver. Most of these changes are not user visible. Only improvements relevant to the user are filtering HDMI modes based on pixel clock and searching for additional detailed timings in EDID extension block. This change allows me to use 4k monitor that I have - base EDID block on this monitor holds only 4k@60 detailed timing. Other detailed timings, which are appropriate for HDMI 1.4 controller, are contained in extension block. There is plenty of work to do. TCON handling should go to dedicated driver and clock related code in TCON and DW-HDMI code should be moved to clock drivers. Testing was done only on H3. Best regards, Jernej Jernej Skrabec (19): sunxi: video: select dw-hdmi in Kconfig, not Makefile video: sunxi: Add mode_valid callback to sunxi_dw_hdmi common: edid: check for digital display earlier common: edid: extract code for detailed timing search common: edid: Search for valid timing in extension block video: sunxi: Use DW-HDMI hpd function video: sunxi: Remove check for ddc-i2c-bus property video: sunxi: Remove TV probe from DE2 video: sunxi: de2: switch to public uclass functions video: sunxi: dw-hdmi: probe driver by compatible video: sunxi: dw-hdmi: read address from DT node video: dw-hdmi: modify phy init callback to include full timings video: sunxi: dw-hdmi: move PHY config to appropriate place video: sunxi: dw-hdmi: rework PHY initialization video: sunxi: de2: switch to DT probing video: sunxi: de2: read address from DT node clk: sunxi: Add DE2 clocks to H3 and A64 clk: sunxi: add DE2 clock driver video: sunxi: de2: switch clock setup to DM model arch/arm/mach-sunxi/Kconfig | 2 + common/edid.c | 82 +++-- drivers/clk/sunxi/Kconfig | 5 + drivers/clk/sunxi/Makefile | 1 + drivers/clk/sunxi/clk_a64.c | 6 + drivers/clk/sunxi/clk_de2.c | 85 + drivers/clk/sunxi/clk_h3.c | 6 + drivers/video/dw_hdmi.c | 6 +- drivers/video/meson/meson_dw_hdmi.c | 5 +- drivers/video/sunxi/Makefile| 2 +- drivers/video/sunxi/sunxi_de2.c | 191 +-- drivers/video/sunxi/sunxi_dw_hdmi.c | 498 ++-- include/dw_hdmi.h | 4 +- 13 files changed, 570 insertions(+), 323 deletions(-) create mode 100644 drivers/clk/sunxi/clk_de2.c -- 2.30.1
[PATCH] sunxi: add fdtoverlay_addr_r environment variable
Commit 69076dff2284 ("cmd: pxe: add support for FDT overlays") added support for loading DT overlay files to PXE boot. However, it needs additional environment variable which points to memory location which can be used to temporary store overlay data. Add it and in the process unify alignment using spaces. Signed-off-by: Jernej Skrabec --- include/configs/sunxi-common.h | 48 ++ 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index ded5aea551d3..4814e898c6ea 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -62,7 +62,7 @@ #define SDRAM_OFFSET(x) 0x2##x #define CONFIG_SYS_SDRAM_BASE 0x2000 #define CONFIG_SYS_LOAD_ADDR 0x2200 /* default load address */ -/* Note SPL_STACK_R_ADDR is set through Kconfig, we include it here +/* Note SPL_STACK_R_ADDR is set through Kconfig, we include it here * since it needs to fit in with the other values. By also #defining it * we get warnings if the Kconfig value mismatches. */ #define CONFIG_SPL_STACK_R_ADDR0x2fe0 @@ -72,7 +72,7 @@ #define CONFIG_SYS_SDRAM_BASE 0x4000 #define CONFIG_SYS_LOAD_ADDR 0x4200 /* default load address */ /* V3s do not have enough memory to place code at 0x4a00 */ -/* Note SPL_STACK_R_ADDR is set through Kconfig, we include it here +/* Note SPL_STACK_R_ADDR is set through Kconfig, we include it here * since it needs to fit in with the other values. By also #defining it * we get warnings if the Kconfig value mismatches. */ #define CONFIG_SPL_STACK_R_ADDR0x4fe0 @@ -259,38 +259,41 @@ extern int soft_i2c_gpio_scl; * Scripts, PXE and DTBs should go afterwards, leaving the rest for the initrd. * Align the initrd to a 2MB page. */ -#define BOOTM_SIZE __stringify(0xa00) -#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(008)) -#define FDT_ADDR_R __stringify(SDRAM_OFFSET(FA0)) -#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(FC0)) -#define PXEFILE_ADDR_R __stringify(SDRAM_OFFSET(FD0)) -#define RAMDISK_ADDR_R __stringify(SDRAM_OFFSET(FE0)) +#define BOOTM_SIZE__stringify(0xa00) +#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(008)) +#define FDT_ADDR_R__stringify(SDRAM_OFFSET(FA0)) +#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(FC0)) +#define PXEFILE_ADDR_R__stringify(SDRAM_OFFSET(FD0)) +#define FDTOVERLAY_ADDR_R __stringify(SDRAM_OFFSET(FE0)) +#define RAMDISK_ADDR_R__stringify(SDRAM_OFFSET(FF0)) #else /* * 160M RAM (256M minimum minus 64MB heap + 32MB for u-boot, stack, fb, etc. * 32M uncompressed kernel, 16M compressed kernel, 1M fdt, - * 1M script, 1M pxe and the ramdisk at the end. + * 1M script, 1M pxe, 1M dt overlay and the ramdisk at the end. */ #ifndef CONFIG_MACH_SUN8I_V3S -#define BOOTM_SIZE __stringify(0xa00) -#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(200)) -#define FDT_ADDR_R __stringify(SDRAM_OFFSET(300)) -#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(310)) -#define PXEFILE_ADDR_R __stringify(SDRAM_OFFSET(320)) -#define RAMDISK_ADDR_R __stringify(SDRAM_OFFSET(330)) +#define BOOTM_SIZE__stringify(0xa00) +#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(200)) +#define FDT_ADDR_R__stringify(SDRAM_OFFSET(300)) +#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(310)) +#define PXEFILE_ADDR_R__stringify(SDRAM_OFFSET(320)) +#define FDTOVERLAY_ADDR_R __stringify(SDRAM_OFFSET(330)) +#define RAMDISK_ADDR_R__stringify(SDRAM_OFFSET(340)) #else /* * 64M RAM minus 2MB heap + 16MB for u-boot, stack, fb, etc. * 16M uncompressed kernel, 8M compressed kernel, 1M fdt, - * 1M script, 1M pxe and the ramdisk at the end. + * 1M script, 1M pxe, 1M dt overlay and the ramdisk at the end. */ -#define BOOTM_SIZE __stringify(0x2e0) -#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(100)) -#define FDT_ADDR_R __stringify(SDRAM_OFFSET(180)) -#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(190)) -#define PXEFILE_ADDR_R __stringify(SDRAM_OFFSET(1A0)) -#define RAMDISK_ADDR_R __stringify(SDRAM_OFFSET(1B0)) +#define BOOTM_SIZE__stringify(0x2e0) +#define KERNEL_ADDR_R __stringify(SDRAM_OFFSET(100)) +#define FDT_ADDR_R__stringify(SDRAM_OFFSET(180)) +#define SCRIPT_ADDR_R __stringify(SDRAM_OFFSET(190)) +#define PXEFILE_ADDR_R__stringify(SDRAM_OFFSET(1A0)) +#define FDTOVERLAY_ADDR_R __stringify(SDRAM_OFFSET(1B0)) +#define RAMDISK_ADDR_R__stringify(SDRAM_OFFSET(1C0)) #endif #endif @@ -300,6 +303,7 @@ extern int soft_i2c_gpio_scl; "fdt_addr_r=" FDT_ADDR_R "\0" \ "scriptaddr=" SCRIPT_ADDR_R "\0" \ "pxefile_addr_r=" PXEFILE_ADDR
[PATCH v2] sunxi: spl: Fix H616 clock initialization
It turns out that there is a magic bit in PRCM region which seemingly makes PLLs work if it's enabled. Sadly, there is no documentation what it does exactly, so we'll just mimick BSP boot0 behaviour and enable it before any clock is set up. Fixes: b18bd53d6cde ("sunxi: introduce support for H616 clocks") Signed-off-by: Jernej Skrabec --- Changes from v1: - use if (IS_ENABLED()) instead of #ifdef #endif arch/arm/mach-sunxi/clock_sun50i_h6.c | 5 + 1 file changed, 5 insertions(+) diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c index 06d84eb158d7..492fc4a3fca8 100644 --- a/arch/arm/mach-sunxi/clock_sun50i_h6.c +++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c @@ -9,6 +9,11 @@ void clock_init_safe(void) { struct sunxi_ccm_reg *const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + + /* this seems to enable PLLs on H616 */ + if (IS_ENABLED(CONFIG_MACH_SUN50I_H616)) + setbits_le32(SUNXI_PRCM_BASE + 0x250, 0x10); + clock_set_pll1(40800); writel(CCM_PLL6_DEFAULT, >pll6_cfg); -- 2.30.0
[PATCH] sunxi: spl: Fix H616 clock initialization
It turns out that there is a magic bit in PRCM region which seemingly makes PLLs work if it's enabled. Sadly, there is no documentation what it does exactly, so we'll just mimick BSP boot0 behaviour and enable it before any clock is set up. Fixes: b18bd53d6cde ("sunxi: introduce support for H616 clocks") Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/clock_sun50i_h6.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c index 06d84eb158d7..68c8e7f2afbe 100644 --- a/arch/arm/mach-sunxi/clock_sun50i_h6.c +++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c @@ -9,6 +9,12 @@ void clock_init_safe(void) { struct sunxi_ccm_reg *const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + +#ifdef CONFIG_MACH_SUN50I_H616 + /* this seems to enable PLLs */ + setbits_le32(SUNXI_PRCM_BASE + 0x250, 0x10); +#endif + clock_set_pll1(40800); writel(CCM_PLL6_DEFAULT, >pll6_cfg); -- 2.30.0
[PATCH v2 21/21] sunxi: Add support for OrangePi Zero2
OrangePi Zero2 is SBC based on Allwinner H616 with 1 GiB of RAM, SD card support, gigabit ethernet, micro HDMI, WIFI, Bluetooth and 1 USB 2.0 port. It also has two GPIO headers which allows further peripherals to be used. Device Tree file is taken from initial OrangePi Zero2 Linux submission and it's not yet merged. Signed-off-by: Jernej Skrabec --- arch/arm/dts/Makefile | 2 + arch/arm/dts/sun50i-h616-orangepi-zero2.dts | 240 board/sunxi/MAINTAINERS | 5 + configs/orangepi_zero2_defconfig| 15 ++ 4 files changed, 262 insertions(+) create mode 100644 arch/arm/dts/sun50i-h616-orangepi-zero2.dts create mode 100644 configs/orangepi_zero2_defconfig diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 1a62e4c0708a..ed6150dca38d 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -609,6 +609,8 @@ dtb-$(CONFIG_MACH_SUN50I_H6) += \ sun50i-h6-orangepi-lite2.dtb \ sun50i-h6-orangepi-one-plus.dtb \ sun50i-h6-pine-h64.dtb +dtb-$(CONFIG_MACH_SUN50I_H616) += \ + sun50i-h616-orangepi-zero2.dtb dtb-$(CONFIG_MACH_SUN50I) += \ sun50i-a64-amarula-relic.dtb \ sun50i-a64-bananapi-m64.dtb \ diff --git a/arch/arm/dts/sun50i-h616-orangepi-zero2.dts b/arch/arm/dts/sun50i-h616-orangepi-zero2.dts new file mode 100644 index ..2afc036059b4 --- /dev/null +++ b/arch/arm/dts/sun50i-h616-orangepi-zero2.dts @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2020 Arm Ltd. + */ + +/dts-v1/; + +#include "sun50i-h616.dtsi" + +#include +#include +#include + +/ { + model = "OrangePi Zero2"; + compatible = "xunlong,orangepi-zero2", "allwinner,sun50i-h616"; + + aliases { + ethernet0 = + serial0 = + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + leds { + compatible = "gpio-leds"; + + power { + function = LED_FUNCTION_POWER; + color = ; + gpios = < 2 12 GPIO_ACTIVE_HIGH>; /* PC12 */ + default-state = "on"; + }; + + status { + function = LED_FUNCTION_STATUS; + color = ; + gpios = < 2 13 GPIO_ACTIVE_HIGH>; /* PC13 */ + }; + }; + + reg_vcc5v: vcc5v { + /* board wide 5V supply directly from the USB-C socket */ + compatible = "regulator-fixed"; + regulator-name = "vcc-5v"; + regulator-min-microvolt = <500>; + regulator-max-microvolt = <500>; + regulator-always-on; + }; + + reg_usb1_vbus: usb1-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb1-vbus"; + regulator-min-microvolt = <500>; + regulator-max-microvolt = <500>; + vin-supply = <_vcc5v>; + enable-active-high; + gpio = < 2 16 GPIO_ACTIVE_HIGH>; /* PC16 */ + status = "okay"; + }; +}; + + { + status = "okay"; +}; + + { + status = "okay"; +}; + +/* USB 2 & 3 are on headers only. */ + + { + pinctrl-names = "default"; + pinctrl-0 = <_rgmii_pins>; + phy-mode = "rgmii"; + phy-handle = <_rgmii_phy>; + phy-supply = <_dcdce>; + allwinner,rx-delay-ps = <3100>; + allwinner,tx-delay-ps = <700>; + status = "okay"; +}; + + { + ext_rgmii_phy: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; +}; + + { + vmmc-supply = <_dcdce>; + cd-gpios = < 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ + bus-width = <4>; + status = "okay"; +}; + + { + status = "okay"; +}; + + { + status = "okay"; +}; + +_i2c { + status = "okay"; + + axp305: pmic@36 { + compatible = "x-powers,axp305", "x-powers,axp805", +"x-powers,axp806"; + reg = <0x36>; + + x-powers,self-working-mode; + vina-supply = <_vcc5v>; + vinb-supply = <_vcc5v>; + vinc-supply = <_vcc5v>; + vind-supply = <_vcc5v>; + vine-supply = <_vcc5v>; + aldoin-supply = <_vcc5v>; + bldoin-supply = <_vcc5v>; + cldoin-supply = <_vcc5v>; + +
[PATCH v2 20/21] clk: sunxi: Add support for H616 clocks
This commit introduces DM H616 clock driver. Reviewed-by: Andre Przywara Signed-off-by: Jernej Skrabec --- drivers/clk/sunxi/Kconfig| 7 ++ drivers/clk/sunxi/Makefile | 1 + drivers/clk/sunxi/clk_h616.c | 120 +++ 3 files changed, 128 insertions(+) create mode 100644 drivers/clk/sunxi/clk_h616.c diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig index 5ff101b99305..bf084fa7a84a 100644 --- a/drivers/clk/sunxi/Kconfig +++ b/drivers/clk/sunxi/Kconfig @@ -79,6 +79,13 @@ config CLK_SUN50I_H6 This enables common clock driver support for platforms based on Allwinner H6 SoC. +config CLK_SUN50I_H616 + bool "Clock driver for Allwinner H616" + default MACH_SUN50I_H616 + help + This enables common clock driver support for platforms based + on Allwinner H616 SoC. + config CLK_SUN50I_A64 bool "Clock driver for Allwinner A64" default MACH_SUN50I diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 36fb2aeb56c5..0dfc0593fb1c 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -16,4 +16,5 @@ obj-$(CONFIG_CLK_SUN8I_V3S) += clk_v3s.o obj-$(CONFIG_CLK_SUN9I_A80) += clk_a80.o obj-$(CONFIG_CLK_SUN8I_H3) += clk_h3.o obj-$(CONFIG_CLK_SUN50I_H6) += clk_h6.o +obj-$(CONFIG_CLK_SUN50I_H616) += clk_h616.o obj-$(CONFIG_CLK_SUN50I_A64) += clk_a64.o diff --git a/drivers/clk/sunxi/clk_h616.c b/drivers/clk/sunxi/clk_h616.c new file mode 100644 index ..e2e3a5c78c95 --- /dev/null +++ b/drivers/clk/sunxi/clk_h616.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2021 Jernej Skrabec + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct ccu_clk_gate h616_gates[] = { + [CLK_BUS_MMC0] = GATE(0x84c, BIT(0)), + [CLK_BUS_MMC1] = GATE(0x84c, BIT(1)), + [CLK_BUS_MMC2] = GATE(0x84c, BIT(2)), + + [CLK_BUS_UART0] = GATE(0x90c, BIT(0)), + [CLK_BUS_UART1] = GATE(0x90c, BIT(1)), + [CLK_BUS_UART2] = GATE(0x90c, BIT(2)), + [CLK_BUS_UART3] = GATE(0x90c, BIT(3)), + [CLK_BUS_UART4] = GATE(0x90c, BIT(4)), + [CLK_BUS_UART5] = GATE(0x90c, BIT(5)), + + [CLK_SPI0] = GATE(0x940, BIT(31)), + [CLK_SPI1] = GATE(0x944, BIT(31)), + + [CLK_BUS_SPI0] = GATE(0x96c, BIT(0)), + [CLK_BUS_SPI1] = GATE(0x96c, BIT(1)), + + [CLK_BUS_EMAC0] = GATE(0x97c, BIT(0)), + [CLK_BUS_EMAC1] = GATE(0x97c, BIT(1)), + + [CLK_USB_PHY0] = GATE(0xa70, BIT(29)), + [CLK_USB_OHCI0] = GATE(0xa70, BIT(31)), + + [CLK_USB_PHY1] = GATE(0xa74, BIT(29)), + [CLK_USB_OHCI1] = GATE(0xa74, BIT(31)), + + [CLK_USB_PHY2] = GATE(0xa78, BIT(29)), + [CLK_USB_OHCI2] = GATE(0xa78, BIT(31)), + + [CLK_USB_PHY3] = GATE(0xa7c, BIT(29)), + [CLK_USB_OHCI3] = GATE(0xa7c, BIT(31)), + + [CLK_BUS_OHCI0] = GATE(0xa8c, BIT(0)), + [CLK_BUS_OHCI1] = GATE(0xa8c, BIT(1)), + [CLK_BUS_OHCI2] = GATE(0xa8c, BIT(2)), + [CLK_BUS_OHCI3] = GATE(0xa8c, BIT(3)), + [CLK_BUS_EHCI0] = GATE(0xa8c, BIT(4)), + [CLK_BUS_EHCI1] = GATE(0xa8c, BIT(5)), + [CLK_BUS_EHCI2] = GATE(0xa8c, BIT(6)), + [CLK_BUS_EHCI3] = GATE(0xa8c, BIT(7)), + [CLK_BUS_OTG] = GATE(0xa8c, BIT(8)), +}; + +static struct ccu_reset h616_resets[] = { + [RST_BUS_MMC0] = RESET(0x84c, BIT(16)), + [RST_BUS_MMC1] = RESET(0x84c, BIT(17)), + [RST_BUS_MMC2] = RESET(0x84c, BIT(18)), + + [RST_BUS_UART0] = RESET(0x90c, BIT(16)), + [RST_BUS_UART1] = RESET(0x90c, BIT(17)), + [RST_BUS_UART2] = RESET(0x90c, BIT(18)), + [RST_BUS_UART3] = RESET(0x90c, BIT(19)), + [RST_BUS_UART4] = RESET(0x90c, BIT(20)), + [RST_BUS_UART5] = RESET(0x90c, BIT(21)), + + [RST_BUS_SPI0] = RESET(0x96c, BIT(16)), + [RST_BUS_SPI1] = RESET(0x96c, BIT(17)), + + [RST_BUS_EMAC0] = RESET(0x97c, BIT(16)), + [RST_BUS_EMAC1] = RESET(0x97c, BIT(17)), + + [RST_USB_PHY0] = RESET(0xa70, BIT(30)), + + [RST_USB_PHY1] = RESET(0xa74, BIT(30)), + + [RST_USB_PHY2] = RESET(0xa78, BIT(30)), + + [RST_USB_PHY3] = RESET(0xa7c, BIT(30)), + + [RST_BUS_OHCI0] = RESET(0xa8c, BIT(16)), + [RST_BUS_OHCI1] = RESET(0xa8c, BIT(17)), + [RST_BUS_OHCI2] = RESET(0xa8c, BIT(18)), + [RST_BUS_OHCI3] = RESET(0xa8c, BIT(19)), + [RST_BUS_EHCI0] = RESET(0xa8c, BIT(20)), + [RST_BUS_EH
[PATCH v2 18/21] arm: sunxi: add initial H616 DTSI and headers
This commit introduces H616 DTSI file and dt-bindings headers needed for device tree files. Files are taken from initial Linux H616 support submission with minor change - emac0 fallback has H6 compatible instead of A64, otherwise network doesn't work. H616 DTSI is not merged upstream yet. Signed-off-by: Jernej Skrabec --- arch/arm/dts/sun50i-h616.dtsi | 716 include/dt-bindings/clock/sun50i-h616-ccu.h | 115 include/dt-bindings/reset/sun50i-h616-ccu.h | 70 ++ 3 files changed, 901 insertions(+) create mode 100644 arch/arm/dts/sun50i-h616.dtsi create mode 100644 include/dt-bindings/clock/sun50i-h616-ccu.h create mode 100644 include/dt-bindings/reset/sun50i-h616-ccu.h diff --git a/arch/arm/dts/sun50i-h616.dtsi b/arch/arm/dts/sun50i-h616.dtsi new file mode 100644 index ..d416e9a3d3e6 --- /dev/null +++ b/arch/arm/dts/sun50i-h616.dtsi @@ -0,0 +1,716 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +// Copyright (C) 2020 Arm Ltd. +// based on the H6 dtsi, which is: +// Copyright (C) 2017 Icenowy Zheng + +#include +#include +#include +#include +#include + +/ { + interrupt-parent = <>; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <0>; + enable-method = "psci"; + clocks = < CLK_CPUX>; + }; + + cpu1: cpu@1 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <1>; + enable-method = "psci"; + clocks = < CLK_CPUX>; + }; + + cpu2: cpu@2 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <2>; + enable-method = "psci"; + clocks = < CLK_CPUX>; + }; + + cpu3: cpu@3 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <3>; + enable-method = "psci"; + clocks = < CLK_CPUX>; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* 512KiB reserved for ARM Trusted Firmware (BL31) */ + secmon_reserved: secmon@4000 { + reg = <0x0 0x4000 0x0 0x8>; + no-map; + }; + }; + + osc24M: osc24M_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <2400>; + clock-output-names = "osc24M"; + }; + + pmu { + compatible = "arm,cortex-a53-pmu"; + interrupts = , +, +, +; + interrupt-affinity = <>, <>, <>, <>; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + arm,no-tick-in-suspend; + interrupts = , +, +, +; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x0 0x4000>; + + syscon: syscon@300 { + compatible = "allwinner,sun50i-h616-system-control"; + reg = <0x0300 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + sram_c: sram@28000 { + compatible = "mmio-sram"; + reg = <0x00028000 0x3>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x00028000 0x3>; + }; + }; + + ccu: clock@3001000 { + compatible = "
[PATCH v2 19/21] sunxi: gpio: introduce compatible for H616
H616 pinctrl is no different configuration wise than others, so just add compatible for it. Reviewed-by: Andre Przywara Signed-off-by: Jernej Skrabec --- drivers/gpio/sunxi_gpio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index 02c3471b5684..1985ee5d2fc9 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -356,6 +356,7 @@ static const struct udevice_id sunxi_gpio_ids[] = { 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), -- 2.30.0
[PATCH v2 16/21] sunxi: Add H616 FEL support
H616 uses different address for reset. Add it. Signed-off-by: Jernej Skrabec --- arch/arm/cpu/armv8/fel_utils.S | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/cpu/armv8/fel_utils.S b/arch/arm/cpu/armv8/fel_utils.S index 9510dcd9e4c1..2dbd4b365221 100644 --- a/arch/arm/cpu/armv8/fel_utils.S +++ b/arch/arm/cpu/armv8/fel_utils.S @@ -40,7 +40,10 @@ ENTRY(return_to_fel) str w2, [x1] ldr x0, =0xfa50392f // CPU hotplug magic -#ifdef CONFIG_MACH_SUN50I_H6 +#ifdef CONFIG_MACH_SUN50I_H616 + ldr x2, =(SUNXI_RTC_BASE + 0x5c0) + str w0, [x2], #0x4 +#elif CONFIG_MACH_SUN50I_H6 ldr x2, =(SUNXI_RTC_BASE + 0x1b8) // BOOT_CPU_HP_FLAG_REG str w0, [x2], #0x4 #else -- 2.30.0
[PATCH v2 17/21] net: sun8i-emac: Determine pinmux based on SoC, not EMAC type
From: Andre Przywara --- drivers/net/sun8i_emac.c | 28 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index e0bf19e34c17..4867a8425404 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -85,7 +85,9 @@ /* IO mux settings */ #define SUN8I_IOMUX_H3 2 -#define SUN8I_IOMUX_R405 +#define SUN8I_IOMUX_R405 +#define SUN8I_IOMUX_H6 5 +#define SUN8I_IOMUX_H616 2 #define SUN8I_IOMUX4 /* H3/A64 EMAC Register's offset */ @@ -514,10 +516,10 @@ static int sun8i_emac_eth_start(struct udevice *dev) static int parse_phy_pins(struct udevice *dev) { - struct emac_eth_dev *priv = dev_get_priv(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"); @@ -544,6 +546,21 @@ static int parse_phy_pins(struct udevice *dev) 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_SUN8I_H3)) + 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 + iomux = SUN8I_IOMUX; + for (i = 0; ; i++) { int pin; @@ -556,12 +573,7 @@ static int parse_phy_pins(struct udevice *dev) if (pin < 0) continue; - if (priv->variant == H3_EMAC) - sunxi_gpio_set_cfgpin(pin, SUN8I_IOMUX_H3); - else if (priv->variant == R40_GMAC || priv->variant == H6_EMAC) - sunxi_gpio_set_cfgpin(pin, SUN8I_IOMUX_R40); - else - sunxi_gpio_set_cfgpin(pin, SUN8I_IOMUX); + sunxi_gpio_set_cfgpin(pin, iomux); if (drive != ~0) sunxi_gpio_set_drv(pin, drive); -- 2.30.0
[PATCH v2 15/21] mmc: sunxi: Add H616 clock offset
H616 mmc clock is on same address as H6. Signed-off-by: Jernej Skrabec --- drivers/mmc/sunxi_mmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index d632b2332ca3..8458d154afd8 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -601,7 +601,8 @@ static unsigned get_mclk_offset(void) if (IS_ENABLED(CONFIG_MACH_SUN9I_A80)) return 0x410; - if (IS_ENABLED(CONFIG_MACH_SUN50I_H6)) + if (IS_ENABLED(CONFIG_MACH_SUN50I_H6) || + IS_ENABLED(CONFIG_MACH_SUN50I_H616)) return 0x830; return 0x88; -- 2.30.0
[PATCH v2 14/21] sunxi: Add support for H616 SoC
H616 is very similar to H6 so most of the infrastructure can be reused. However, two big differences are that it doesn't have functional SRAM A2 which is usually used for TF-A and it doesn't have ARISC co-processor. It also needs bigger SPL size - 48 KiB. Signed-off-by: Jernej Skrabec --- arch/arm/dts/sunxi-u-boot.dtsi | 8 arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h | 7 +++ arch/arm/mach-sunxi/Kconfig | 11 ++- arch/arm/mach-sunxi/clock_sun50i_h6.c | 2 +- arch/arm/mach-sunxi/cpu_info.c | 2 ++ drivers/power/Kconfig | 1 + include/configs/sunxi-common.h | 7 +++ 7 files changed, 36 insertions(+), 2 deletions(-) diff --git a/arch/arm/dts/sunxi-u-boot.dtsi b/arch/arm/dts/sunxi-u-boot.dtsi index c77cf7cacf0c..abe629c55e57 100644 --- a/arch/arm/dts/sunxi-u-boot.dtsi +++ b/arch/arm/dts/sunxi-u-boot.dtsi @@ -3,6 +3,8 @@ #ifdef CONFIG_MACH_SUN50I_H6 #define BL31_ADDR 0x104000 #define SCP_ADDR 0x114000 +#elif defined(CONFIG_MACH_SUN50I_H616) +#define BL31_ADDR 0x40004000 #else #define BL31_ADDR 0x44000 #define SCP_ADDR 0x5 @@ -61,6 +63,7 @@ }; }; +#ifndef CONFIG_MACH_SUN50I_H616 scp { description = "SCP firmware"; type = "firmware"; @@ -73,6 +76,7 @@ missing-msg = "scp-sunxi"; }; }; +#endif @fdt-SEQ { description = "NAME"; @@ -87,7 +91,11 @@ @config-SEQ { description = "NAME"; firmware = "atf"; +#ifdef CONFIG_MACH_SUN50I_H616 + loadables = "uboot"; +#else loadables = "scp", "uboot"; +#endif fdt = "fdt-SEQ"; }; }; diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h index 6392cb07b472..d9cf8ae04288 100644 --- a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h +++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h @@ -28,13 +28,20 @@ #define SUNXI_GIC400_BASE 0x0302 #define SUNXI_IOMMU_BASE 0x030F +#ifdef CONFIG_MACH_SUN50I_H6 #define SUNXI_DRAM_COM_BASE0x04002000 #define SUNXI_DRAM_CTL0_BASE 0x04003000 #define SUNXI_DRAM_PHY0_BASE 0x04005000 +#endif #define SUNXI_NFC_BASE 0x04011000 #define SUNXI_MMC0_BASE0x0402 #define SUNXI_MMC1_BASE0x04021000 #define SUNXI_MMC2_BASE0x04022000 +#ifdef CONFIG_MACH_SUN50I_H616 +#define SUNXI_DRAM_COM_BASE0x047FA000 +#define SUNXI_DRAM_CTL0_BASE 0x047FB000 +#define SUNXI_DRAM_PHY0_BASE 0x0480 +#endif #define SUNXI_UART0_BASE 0x0500 #define SUNXI_UART1_BASE 0x05000400 diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index a8571d180259..1415355750c4 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -190,9 +190,10 @@ config MACH_SUNXI_H3_H5 select SUPPORT_SPL # TODO: try out A80's 8GiB DRAM space +# TODO: H616 supports 4 GiB DRAM space config SUNXI_DRAM_MAX_SIZE hex - default 0xC000 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN50I_H6 + default 0xC000 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN50I_H6 || MACH_SUN50I_H616 default 0x8000 choice @@ -355,6 +356,12 @@ config MACH_SUN50I_H6 select DRAM_SUN50I_H6 select SUN50I_GEN_H6 +config MACH_SUN50I_H616 + bool "sun50i (Allwinner H616)" + select ARM64 + select DRAM_SUN50I_H616 + select SUN50I_GEN_H6 + endchoice # The sun8i SoCs share a lot, this helps to avoid a lot of "if A23 || A33" @@ -591,6 +598,7 @@ config SYS_CLK_FREQ default 100800 if MACH_SUN8I default 100800 if MACH_SUN9I default 88800 if MACH_SUN50I_H6 + default 100800 if MACH_SUN50I_H616 config SYS_CONFIG_NAME default "sun4i" if MACH_SUN4I @@ -601,6 +609,7 @@ config SYS_CONFIG_NAME default "sun9i" if MACH_SUN9I default "sun50i" if MACH_SUN50I default "sun50i" if MACH_SUN50I_H6 + default "sun50i" if MACH_SUN50I_H616 config SYS_BOARD default "sunxi" d
[PATCH v2 11/21] sunxi: Add H616 DRAM support
Allwinner H616 supports many types of DRAM. Most notably it supports LPDDR4. However, all commercially available boards at this time use only DDR3, so this commit adds only DDR3 support. Controller and MBUS are very similar to H6 but PHY is completely unknown. Signed-off-by: Jernej Skrabec --- arch/arm/include/asm/arch-sunxi/dram.h|2 + .../include/asm/arch-sunxi/dram_sun50i_h616.h | 159 +++ arch/arm/mach-sunxi/Kconfig | 43 + arch/arm/mach-sunxi/Makefile |2 + arch/arm/mach-sunxi/dram_sun50i_h616.c| 1023 + arch/arm/mach-sunxi/dram_timings/Makefile |2 + .../mach-sunxi/dram_timings/h616_ddr3_1333.c | 94 ++ 7 files changed, 1325 insertions(+) create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h create mode 100644 arch/arm/mach-sunxi/dram_sun50i_h616.c create mode 100644 arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h index 8002b7efdc19..c3b3e1f512b2 100644 --- a/arch/arm/include/asm/arch-sunxi/dram.h +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -29,6 +29,8 @@ #include #elif defined(CONFIG_MACH_SUN50I_H6) #include +#elif defined(CONFIG_MACH_SUN50I_H616) +#include #else #include #endif diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h new file mode 100644 index ..134679d55205 --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h @@ -0,0 +1,159 @@ +/* + * H616 dram controller register and constant defines + * + * (C) Copyright 2020 Jernej Skrabec + * + * Based on H6 one, which is: + * (C) Copyright 2017 Icenowy Zheng + * + * SPDX-License-Identifier:GPL-2.0+ + */ + +#ifndef _SUNXI_DRAM_SUN50I_H616_H +#define _SUNXI_DRAM_SUN50I_H616_H + +#include +#ifndef __ASSEMBLY__ +#include +#endif + +enum sunxi_dram_type { + SUNXI_DRAM_TYPE_DDR3 = 3, + SUNXI_DRAM_TYPE_DDR4, + SUNXI_DRAM_TYPE_LPDDR3 = 7, + SUNXI_DRAM_TYPE_LPDDR4 +}; + +/* MBUS part is largely the same as in H6, except for one special register */ +struct sunxi_mctl_com_reg { + u32 cr; /* 0x000 control register */ + u8 reserved_0x004[4]; /* 0x004 */ + u32 unk_0x008; /* 0x008 */ + u32 tmr;/* 0x00c timer register */ + u8 reserved_0x010[4]; /* 0x010 */ + u32 unk_0x014; /* 0x014 */ + u8 reserved_0x018[8]; /* 0x018 */ + u32 maer0; /* 0x020 master enable register 0 */ + u32 maer1; /* 0x024 master enable register 1 */ + u32 maer2; /* 0x028 master enable register 2 */ + u8 reserved_0x02c[468]; /* 0x02c */ + u32 bwcr; /* 0x200 bandwidth control register */ + u8 reserved_0x204[12]; /* 0x204 */ + /* +* The last master configured by BSP libdram is at 0x49x, so the +* size of this struct array is set to 41 (0x29) now. +*/ + struct { + u32 cfg0; /* 0x0 */ + u32 cfg1; /* 0x4 */ + u8 reserved_0x8[8]; /* 0x8 */ + } master[41]; /* 0x210 + index * 0x10 */ + u8 reserved_0x4a0[96]; /* 0x4a0 */ + u32 unk_0x500; /* 0x500 */ +}; +check_member(sunxi_mctl_com_reg, unk_0x500, 0x500); + +/* + * Controller registers seems to be the same or at least very similar + * to those in H6. + */ +struct sunxi_mctl_ctl_reg { + u32 mstr; /* 0x000 */ + u32 statr; /* 0x004 unused */ + u32 mstr1; /* 0x008 unused */ + u32 clken; /* 0x00c */ + u32 mrctrl0;/* 0x010 unused */ + u32 mrctrl1;/* 0x014 unused */ + u32 mrstatr;/* 0x018 unused */ + u32 mrctrl2;/* 0x01c unused */ + u32 derateen; /* 0x020 unused */ + u32 derateint; /* 0x024 unused */ + u8 reserved_0x028[8]; /* 0x028 */ + u32 pwrctl; /* 0x030 unused */ + u32 pwrtmg; /* 0x034 unused */ + u32 hwlpctl;/* 0x038 unused */ + u8 reserved_0x03c[20]; /* 0x03c */ + u32 rfshctl0; /* 0x050 unused */ + u32 rfshctl1; /* 0x054 unused */ + u8 reserved_0x058[8]; /* 0x05c */ + u32 rfshctl3; /* 0x060 */ + u32 rfshtmg;/* 0x064 */ + u8 reserved_0x068[104]; /* 0x068 */ + u32 init[8];/* 0x0d0 */ + u32 dimmctl;/* 0x0f0 unused */ + u32 rankctl;/* 0x0f4 */ + u8 reserved_0x0f8[8]; /* 0x0f8 */ + u32 dramtmg[17];/* 0x100 */ + u8 reserved_0x144[60]; /* 0x144 */ + u32 zqctl[3]; /* 0x180 */ + u32 zqstat; /* 0x18c unused */ + u32 dfitmg0;/* 0x190
[PATCH v2 13/21] net: sun8i-emac: Always clear syscon EPHY register
From: Andre Przywara At the moment we only consider the EPHY register for those SoCs were we actually have an internal PHY to configure. However even other SoCs have this register, an expect a bit to be cleared for proper operation with an external PHY. Rework sun8i_emac_set_syscon_ephy() to be called regardless of the EMAC model, and clear the H3_EPHY_SELECT bit if no internal PHY is used. This helps with the upcoming H616 support, were we need to consider two EMACs. Signed-off-by: Andre Przywara --- drivers/net/sun8i_emac.c | 31 +-- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index 4524604126c9..e0bf19e34c17 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -297,30 +297,29 @@ static void sun8i_adjust_link(struct emac_eth_dev *priv, writel(v, priv->mac_reg + EMAC_CTL0); } -static int sun8i_emac_set_syscon_ephy(struct emac_eth_dev *priv, u32 *reg) +static u32 sun8i_emac_set_syscon_ephy(struct emac_eth_dev *priv, u32 reg) { if (priv->use_internal_phy) { /* H3 based SoC's that has an Internal 100MBit PHY * needs to be configured and powered up before use */ - *reg &= ~H3_EPHY_DEFAULT_MASK; - *reg |= H3_EPHY_DEFAULT_VALUE; - *reg |= priv->phyaddr << H3_EPHY_ADDR_SHIFT; - *reg &= ~H3_EPHY_SHUTDOWN; - *reg |= H3_EPHY_SELECT; - } else - /* This is to select External Gigabit PHY on -* the boards with H3 SoC. - */ - *reg &= ~H3_EPHY_SELECT; + reg &= ~H3_EPHY_DEFAULT_MASK; + reg |= H3_EPHY_DEFAULT_VALUE; + reg |= priv->phyaddr << H3_EPHY_ADDR_SHIFT; + reg &= ~H3_EPHY_SHUTDOWN; + return reg | H3_EPHY_SELECT; + } - return 0; + /* This is to select External Gigabit PHY on those boards with +* an internal PHY. Does not hurt on other SoCs. Linux does +* it as well. +*/ + return reg & ~H3_EPHY_SELECT; } static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata, struct emac_eth_dev *priv) { - int ret; u32 reg; if (priv->variant == R40_GMAC) { @@ -336,11 +335,7 @@ static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata, reg = readl(priv->sysctl_reg + 0x30); - if (priv->variant == H3_EMAC || priv->variant == H6_EMAC) { - ret = sun8i_emac_set_syscon_ephy(priv, ); - if (ret) - return ret; - } + reg = sun8i_emac_set_syscon_ephy(priv, reg); reg &= ~(SC_ETCS_MASK | SC_EPIT); if (priv->variant == H3_EMAC || -- 2.30.0
[PATCH v2 12/21] mmc: sunxi: Refactor mod clock register offset
From: Andre Przywara So far the only difference between the various Allwinner MMC controller we are concerned about is the mod clock register offset. This is actually not directly related to the MMC controller IP, but an integration choice, dependent on the SoC this appears in. To avoid becoming trapped with some compatible fallback strings, let's remove the whole struct sunxi_mmc_variant, and replace this with a SoC based choice, which we can derive from the CONFIG_MACH_SUNx_y symbols. This will later simplify H616 support. Signed-off-by: Andre Przywara Reviewed-by: Jaehoon Chung --- drivers/mmc/sunxi_mmc.c | 84 +++-- 1 file changed, 23 insertions(+), 61 deletions(-) diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 3767a39277c1..d632b2332ca3 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -23,12 +23,6 @@ #include #include -#ifdef CONFIG_DM_MMC -struct sunxi_mmc_variant { - u16 mclk_offset; -}; -#endif - struct sunxi_mmc_plat { struct mmc_config cfg; struct mmc mmc; @@ -42,9 +36,6 @@ struct sunxi_mmc_priv { int cd_inverted;/* Inverted Card Detect */ struct sunxi_mmc *reg; struct mmc_config cfg; -#ifdef CONFIG_DM_MMC - const struct sunxi_mmc_variant *variant; -#endif }; #if !CONFIG_IS_ENABLED(DM_MMC) @@ -605,6 +596,17 @@ static const struct dm_mmc_ops sunxi_mmc_ops = { .get_cd = sunxi_mmc_getcd, }; +static unsigned get_mclk_offset(void) +{ + if (IS_ENABLED(CONFIG_MACH_SUN9I_A80)) + return 0x410; + + if (IS_ENABLED(CONFIG_MACH_SUN50I_H6)) + return 0x830; + + return 0x88; +}; + static int sunxi_mmc_probe(struct udevice *dev) { struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); @@ -633,8 +635,6 @@ static int sunxi_mmc_probe(struct udevice *dev) cfg->f_max = 5200; priv->reg = (void *)dev_read_addr(dev); - priv->variant = - (const struct sunxi_mmc_variant *)dev_get_driver_data(dev); /* We don't have a sunxi clock driver so find the clock address here */ ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0, @@ -644,8 +644,7 @@ static int sunxi_mmc_probe(struct udevice *dev) ccu_reg = (u32 *)ofnode_get_addr(args.node); priv->mmc_no = ((uintptr_t)priv->reg - SUNXI_MMC0_BASE) / 0x1000; - priv->mclkreg = (void *)ccu_reg + - (priv->variant->mclk_offset + (priv->mmc_no * 4)); + priv->mclkreg = (void *)ccu_reg + get_mclk_offset() + priv->mmc_no * 4; ret = clk_get_by_name(dev, "ahb", _clk); if (!ret) @@ -687,55 +686,18 @@ static int sunxi_mmc_bind(struct udevice *dev) return mmc_bind(dev, >mmc, >cfg); } -static const struct sunxi_mmc_variant sun4i_a10_variant = { - .mclk_offset = 0x88, -}; - -static const struct sunxi_mmc_variant sun9i_a80_variant = { - .mclk_offset = 0x410, -}; - -static const struct sunxi_mmc_variant sun50i_h6_variant = { - .mclk_offset = 0x830, -}; - static const struct udevice_id sunxi_mmc_ids[] = { - { - .compatible = "allwinner,sun4i-a10-mmc", - .data = (ulong)_a10_variant, - }, - { - .compatible = "allwinner,sun5i-a13-mmc", - .data = (ulong)_a10_variant, - }, - { - .compatible = "allwinner,sun7i-a20-mmc", - .data = (ulong)_a10_variant, - }, - { - .compatible = "allwinner,sun8i-a83t-emmc", - .data = (ulong)_a10_variant, - }, - { - .compatible = "allwinner,sun9i-a80-mmc", - .data = (ulong)_a80_variant, - }, - { - .compatible = "allwinner,sun50i-a64-mmc", - .data = (ulong)_a10_variant, - }, - { - .compatible = "allwinner,sun50i-a64-emmc", - .data = (ulong)_a10_variant, - }, - { - .compatible = "allwinner,sun50i-h6-mmc", - .data = (ulong)_h6_variant, - }, - { - .compatible = "allwinner,sun50i-h6-emmc", - .data = (ulong)_h6_variant, - }, + { .compatible = "allwinner,sun4i-a10-mmc" }, + { .compatible = "allwinner,sun5i-a13-mmc" }, + { .compatible = "allwinner,sun7i-a20-mmc" }, + { .compatible = "allwinner,sun8i-a83t-emmc" }, + { .compatible = "allwinner,sun9i-a80-mmc" }, + { .compatible = "allwinner,sun50i-a64-mmc" }, + { .compatible = "allwinner,sun50i-a64-emmc" }, + { .compatible = "allwinner,sun50i-h6-mmc" }, + { .compatible = "allwinner,sun50i-h6-emmc" }, + { .compatible = "allwinner,sun50i-a100-mmc" }, + { .compatible = "allwinner,sun50i-a100-emmc" }, { /* sentinel */ } }; -- 2.30.0
[PATCH v2 10/21] sunxi: add support for R_I2C on H616
This port is needed for communication with PMIC. SPL uses it to set DRAM voltage on H616 boards. Reviewed-by: Samuel Holland Signed-off-by: Jernej Skrabec --- arch/arm/include/asm/arch-sunxi/gpio.h | 1 + board/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 cdb7dbd5b8e5..de77bf638e21 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -220,6 +220,7 @@ enum sunxi_gpio_number { #define SUN8I_A23_GPL_R_TWI3 #define SUN8I_GPL_R_UART 2 #define SUN50I_GPL_R_TWI 2 +#define SUN50I_H616_GPL_R_TWI 3 #define SUN9I_GPN_R_RSB3 diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 40fdd5da0477..14d31c719ece 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -196,6 +196,10 @@ void i2c_init_board(void) clock_twi_onoff(5, 1); sunxi_gpio_set_cfgpin(SUNXI_GPL(8), SUN50I_GPL_R_TWI); sunxi_gpio_set_cfgpin(SUNXI_GPL(9), SUN50I_GPL_R_TWI); +#elif CONFIG_MACH_SUN50I_H616 + clock_twi_onoff(5, 1); + sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN50I_H616_GPL_R_TWI); + sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN50I_H616_GPL_R_TWI); #else clock_twi_onoff(5, 1); sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_H3_GPL_R_TWI); -- 2.30.0
[PATCH v2 09/21] sunxi: add support for H616 uart0
This port is used for debug terminal on all known H616 boards. Reviewed-by: Samuel Holland Signed-off-by: Jernej Skrabec --- 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 f817d328f432..cdb7dbd5b8e5 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -206,6 +206,7 @@ enum sunxi_gpio_number { #define SUN6I_GPH_UART02 #define SUN9I_GPH_UART02 #define SUN50I_H6_GPH_UART02 +#define SUN50I_H616_GPH_UART0 2 #define SUNXI_GPI_SDC3 2 #define SUN7I_GPI_TWI3 3 diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index 8ed9a87c1195..a883edd24107 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -116,6 +116,10 @@ static int gpio_init(void) sunxi_gpio_set_cfgpin(SUNXI_GPH(0), SUN50I_H6_GPH_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPH(1), SUN50I_H6_GPH_UART0); sunxi_gpio_set_pull(SUNXI_GPH(1), SUNXI_GPIO_PULL_UP); +#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN50I_H616) + sunxi_gpio_set_cfgpin(SUNXI_GPH(0), SUN50I_H616_GPH_UART0); + sunxi_gpio_set_cfgpin(SUNXI_GPH(1), SUN50I_H616_GPH_UART0); + sunxi_gpio_set_pull(SUNXI_GPH(1), SUNXI_GPIO_PULL_UP); #elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN8I_A83T) sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN8I_A83T_GPB_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPB(10), SUN8I_A83T_GPB_UART0); -- 2.30.0
[PATCH v2 08/21] sunxi: introduce support for H616 clocks
H616 has mostly the same clocks as H6 with some small differences. Just reuse H6 clocks for H616 and handle differences with macros. Reviewed-by: Samuel Holland Signed-off-by: Jernej Skrabec --- .../include/asm/arch-sunxi/clock_sun50i_h6.h | 18 +- arch/arm/mach-sunxi/clock_sun50i_h6.c | 8 ++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h index e83e84ab6cab..62abfc4ef6bd 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h @@ -230,6 +230,7 @@ struct sunxi_ccm_reg { #define CCM_PLL1_CTRL_EN BIT(31) #define CCM_PLL1_LOCK_EN BIT(29) #define CCM_PLL1_LOCK BIT(28) +#define CCM_PLL1_OUT_ENBIT(27) #define CCM_PLL1_CLOCK_TIME_2 (2 << 24) #define CCM_PLL1_CTRL_P(p) ((p) << 16) #define CCM_PLL1_CTRL_N(n) ((n) << 8) @@ -238,6 +239,7 @@ struct sunxi_ccm_reg { #define CCM_PLL5_CTRL_EN BIT(31) #define CCM_PLL5_LOCK_EN BIT(29) #define CCM_PLL5_LOCK BIT(28) +#define CCM_PLL5_OUT_ENBIT(27) #define CCM_PLL5_CTRL_N(n) ((n) << 8) #define CCM_PLL5_CTRL_DIV1(div1) ((div1) << 0) #define CCM_PLL5_CTRL_DIV2(div0) ((div0) << 1) @@ -252,7 +254,6 @@ struct sunxi_ccm_reg { #define CCM_PLL6_CTRL_DIV1_MASK(0x1 << CCM_PLL6_CTRL_DIV1_SHIFT) #define CCM_PLL6_CTRL_DIV2_SHIFT 1 #define CCM_PLL6_CTRL_DIV2_MASK(0x1 << CCM_PLL6_CTRL_DIV2_SHIFT) -#define CCM_PLL6_DEFAULT 0xa0006300 /* cpu_axi bit field*/ #define CCM_CPU_AXI_MUX_MASK (0x3 << 24) @@ -262,6 +263,9 @@ struct sunxi_ccm_reg { #define CCM_CPU_AXI_AXI_MASK 0x3 #define CCM_CPU_AXI_DEFAULT_FACTORS0x301 +#ifdef CONFIG_MACH_SUN50I_H6 +#define CCM_PLL6_DEFAULT 0xa0006300 + /* psi_ahb1_ahb2 bit field */ #define CCM_PSI_AHB1_AHB2_DEFAULT 0x03000102 @@ -270,6 +274,18 @@ struct sunxi_ccm_reg { /* apb1 bit field */ #define CCM_APB1_DEFAULT 0x03000102 +#elif CONFIG_MACH_SUN50I_H616 +#define CCM_PLL6_DEFAULT 0xa8003100 + +/* psi_ahb1_ahb2 bit field */ +#define CCM_PSI_AHB1_AHB2_DEFAULT 0x0302 + +/* ahb3 bit field */ +#define CCM_AHB3_DEFAULT 0x0302 + +/* apb1 bit field */ +#define CCM_APB1_DEFAULT 0x03000102 +#endif /* apb2 bit field */ #define APB2_CLK_SRC_OSC24M(0x0 << 24) diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c index 6bd466915c11..daca02019bab 100644 --- a/arch/arm/mach-sunxi/clock_sun50i_h6.c +++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c @@ -68,6 +68,9 @@ void clock_set_pll1(unsigned int clk) /* clk = 24*n/p, p is ignored if clock is >288MHz */ writel(CCM_PLL1_CTRL_EN | CCM_PLL1_LOCK_EN | CCM_PLL1_CLOCK_TIME_2 | +#ifdef CONFIG_MACH_SUN50I_H616 + CCM_PLL1_OUT_EN | +#endif CCM_PLL1_CTRL_N(clk / 2400), >pll1_cfg); while (!(readl(>pll1_cfg) & CCM_PLL1_LOCK)) {} @@ -83,6 +86,7 @@ unsigned int clock_get_pll6(void) { struct sunxi_ccm_reg *const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + int m = IS_ENABLED(CONFIG_MACH_SUN50I_H6) 4 : 2; uint32_t rval = readl(>pll6_cfg); int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT); @@ -90,8 +94,8 @@ unsigned int clock_get_pll6(void) CCM_PLL6_CTRL_DIV1_SHIFT) + 1; int div2 = ((rval & CCM_PLL6_CTRL_DIV2_MASK) >> CCM_PLL6_CTRL_DIV2_SHIFT) + 1; - /* The register defines PLL6-4X, not plain PLL6 */ - return 2400 / 4 * n / div1 / div2; + /* The register defines PLL6-2X or PLL6-4X, not plain PLL6 */ + return 2400 / m * n / div1 / div2; } int clock_twi_onoff(int port, int state) -- 2.30.0
[PATCH v2 07/21] sunxi: support loading with SPL > 32KB
From: Andre Przywara H616 supports and needs bigger SPL than 32 KiB, mostly due to big DRAM driver and need for PMIC configuration, which pulls several drivers which are not needed otherwise. spl_mmc_get_uboot_raw_sector() will now compare pre-configured size with that, reported in SPL header. If size in header is bigger, it will use that value instead. In the process of function rework, also add missing function argument. Signed-off-by: Andre Przywara Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/board.c | 16 ++-- common/spl/Kconfig | 3 ++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index 7a8b303f233c..8ed9a87c1195 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -277,15 +277,27 @@ uint32_t sunxi_get_boot_device(void) } #ifdef CONFIG_SPL_BUILD +static u32 sunxi_get_spl_size(void) +{ + if (!is_boot0_magic(SPL_ADDR + 4)) /* eGON.BT0 */ + return 0; + + return readl(SPL_ADDR + 0x10); +} + /* * The eGON SPL image can be located at 8KB or at 128KB into an SD card or * an eMMC device. The boot source has bit 4 set in the latter case. * By adding 120KB to the normal offset when booting from a "high" location * we can support both cases. */ -unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc) +unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc, + unsigned long raw_sect) { - unsigned long sector = CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR; + unsigned long spl_size = sunxi_get_spl_size(); + unsigned long sector; + + sector = max(raw_sect, spl_size / 512); switch (sunxi_get_boot_source()) { case SUNXI_BOOTED_FROM_MMC0_HIGH: diff --git a/common/spl/Kconfig b/common/spl/Kconfig index bed715774d81..1ef09e4ad22a 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -316,7 +316,7 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR config SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR hex "Address on the MMC to load U-Boot from" depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR - default 0x50 if ARCH_SUNXI + default 0x40 if ARCH_SUNXI default 0x75 if ARCH_DAVINCI default 0x8a if ARCH_MX6 || ARCH_MX7 default 0x100 if ARCH_UNIPHIER @@ -333,6 +333,7 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR config SYS_MMCSD_RAW_MODE_U_BOOT_DATA_PART_OFFSET hex "U-Boot main hardware partition image offset" depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR + default 0x10 if ARCH_SUNXI default 0x0 help On some platforms SPL location depends on hardware partition. The ROM -- 2.30.0
[PATCH v2 05/21] sunxi: prcm: Add memory map for H6 like SoCs
There was no need to have prcm definitions for H6 and similar SoCs till now. However, support R_I2C will be needed soon in SPL. Move old definitions to prcm_sun6i.h and add new ones in prcm_sun50i.h. One of those files will be selected in common prcm.h based on defined macros. This commit doesn't do any functional change. Signed-off-by: Jernej Skrabec --- arch/arm/include/asm/arch-sunxi/prcm.h| 249 +- arch/arm/include/asm/arch-sunxi/prcm_sun50i.h | 47 arch/arm/include/asm/arch-sunxi/prcm_sun6i.h | 247 + 3 files changed, 304 insertions(+), 239 deletions(-) create mode 100644 arch/arm/include/asm/arch-sunxi/prcm_sun50i.h create mode 100644 arch/arm/include/asm/arch-sunxi/prcm_sun6i.h diff --git a/arch/arm/include/asm/arch-sunxi/prcm.h b/arch/arm/include/asm/arch-sunxi/prcm.h index 767d1ff98d74..5106076f5e91 100644 --- a/arch/arm/include/asm/arch-sunxi/prcm.h +++ b/arch/arm/include/asm/arch-sunxi/prcm.h @@ -1,247 +1,18 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * Sunxi A31 Power Management Unit register definition. + * (C) Copyright 2020 Jernej Skrabec * - * (C) Copyright 2013 Oliver Schinagl - * http://linux-sunxi.org - * Allwinner Technology Co., Ltd. - * Berg Xing - * Tom Cubie + * Sunxi platform prcm register definition. */ #ifndef _SUNXI_PRCM_H #define _SUNXI_PRCM_H -#define __PRCM_CPUS_CFG_PRE(n) (((n) & 0x3) << 4) -#define PRCM_CPUS_CFG_PRE_MASK __PRCM_CPUS_CFG_PRE(0x3) -#define __PRCM_CPUS_CFG_PRE_DIV(n) (((n) >> 1) - 1) -#define PRCM_CPUS_CFG_PRE_DIV(n) \ - __PRCM_CPUS_CFG_PRE(__PRCM_CPUS_CFG_CLK_PRE(n)) -#define __PRCM_CPUS_CFG_POST(n) (((n) & 0x1f) << 8) -#define PRCM_CPUS_CFG_POST_MASK __PRCM_CPUS_CFG_POST(0x1f) -#define __PRCM_CPUS_CFG_POST_DIV(n) ((n) - 1) -#define PRCM_CPUS_CFG_POST_DIV(n) \ - __PRCM_CPUS_CFG_POST_DIV(__PRCM_CPUS_CFG_POST_DIV(n)) -#define __PRCM_CPUS_CFG_CLK_SRC(n) (((n) & 0x3) << 16) -#define PRCM_CPUS_CFG_CLK_SRC_MASK __PRCM_CPUS_CFG_CLK_SRC(0x3) -#define __PRCM_CPUS_CFG_CLK_SRC_LOSC 0x0 -#define __PRCM_CPUS_CFG_CLK_SRC_HOSC 0x1 -#define __PRCM_CPUS_CFG_CLK_SRC_PLL6 0x2 -#define __PRCM_CPUS_CFG_CLK_SRC_PDIV 0x3 -#define PRCM_CPUS_CFG_CLK_SRC_LOSC \ - __PRCM_CPUS_CFG_CLK_SRC(__PRCM_CPUS_CFG_CLK_SRC_LOSC) -#define PRCM_CPUS_CFG_CLK_SRC_HOSC \ - __PRCM_CPUS_CFG_CLK_SRC(__PRCM_CPUS_CFG_CLK_SRC_HOSC) -#define PRCM_CPUS_CFG_CLK_SRC_PLL6 \ - __PRCM_CPUS_CFG_CLK_SRC(__PRCM_CPUS_CFG_CLK_SRC_PLL6) -#define PRCM_CPUS_CFG_CLK_SRC_PDIV \ - __PRCM_CPUS_CFG_CLK_SRC(__PRCM_CPUS_CFG_CLK_SRC_PDIV) - -#define __PRCM_APB0_RATIO(n) (((n) & 0x3) << 0) -#define PRCM_APB0_RATIO_DIV_MASK __PRCM_APB0_RATIO_DIV(0x3) -#define __PRCM_APB0_RATIO_DIV(n) (((n) >> 1) - 1) -#define PRCM_APB0_RATIO_DIV(n) \ - __PRCM_APB0_RATIO(__PRCM_APB0_RATIO_DIV(n)) - -#define PRCM_CPU_CFG_NEON_CLK_EN (0x1 << 0) -#define PRCM_CPU_CFG_CPU_CLK_EN (0x1 << 1) - -#define PRCM_APB0_GATE_PIO (0x1 << 0) -#define PRCM_APB0_GATE_IR (0x1 << 1) -#define PRCM_APB0_GATE_TIMER01 (0x1 << 2) -#define PRCM_APB0_GATE_P2WI (0x1 << 3) /* sun6i */ -#define PRCM_APB0_GATE_RSB (0x1 << 3) /* sun8i */ -#define PRCM_APB0_GATE_UART (0x1 << 4) -#define PRCM_APB0_GATE_1WIRE (0x1 << 5) -#define PRCM_APB0_GATE_I2C (0x1 << 6) - -#define PRCM_APB0_RESET_PIO (0x1 << 0) -#define PRCM_APB0_RESET_IR (0x1 << 1) -#define PRCM_APB0_RESET_TIMER01 (0x1 << 2) -#define PRCM_APB0_RESET_P2WI (0x1 << 3) -#define PRCM_APB0_RESET_UART (0x1 << 4) -#define PRCM_APB0_RESET_1WIRE (0x1 << 5) -#define PRCM_APB0_RESET_I2C (0x1 << 6) - -#define PRCM_PLL_CTRL_PLL_BIAS (0x1 << 0) -#define PRCM_PLL_CTRL_HOSC_GAIN_ENH (0x1 << 1) -#define __PRCM_PLL_CTRL_USB_CLK_SRC(n) (((n) & 0x3) << 4) -#define PRCM_PLL_CTRL_USB_CLK_SRC_MASK \ - __PRCM_PLL_CTRL_USB_CLK_SRC(0x3) -#define __PRCM_PLL_CTRL_USB_CLK_0 0x0 -#define __PRCM_PLL_CTRL_USB_CLK_1 0x1 -#define __PRCM_PLL_CTRL_USB_CLK_2 0x2 -#define __PRCM_PLL_CTRL_USB_CLK_3 0x3 -#define PRCM_PLL_CTRL_USB_CLK_0 \ - __PRCM_PLL_CTRL_USB_CLK_SRC(__PRCM_PLL_CTRL_USB_CLK_0) -#define PRCM_PLL_CTRL_USB_CLK_1 \ - __PRCM_PLL_CTRL_USB_CLK_SRC(__PRCM_PLL_CTRL_USB_CLK_1) -#define PRCM_PLL_CTRL_USB_CLK_2 \ - __PRCM_PLL_CTRL_USB_CLK_SRC(__PRCM_PLL_CTRL_USB_CLK_2) -#define PRCM_PLL_CTRL_USB_CLK_3 \ - __PRCM_PLL_CTRL_USB_CLK_SRC(__PRCM_PLL_CTRL_USB_CLK_3) -#define __PRCM_PLL_CTRL_INT_PLL_IN_SEL(n) (((n) & 0x3) << 12) -#define PRCM_PLL_CTRL_INT_PLL_IN_SEL_MASK \ - __PRCM_PLL_CTRL_INT_PLL_IN_SEL(0x3) -#define PRCM_PLL_CTRL_INT_PLL_IN_SEL(n) \ - __PRCM_PLL_CTRL_INT_PLL_IN_SEL(n) -#define __PRCM_PLL_CTRL_HOSC_CLK_SEL(n) (((n) & 0x3) << 20) -#define PRCM_PLL_CTRL_HOSC_CLK_SEL_MASK \ - __PRCM_PLL_CTRL_HOSC_CLK_SEL(0x3) -#define __PRCM_PLL_CTRL_HOSC_CLK_0 0x0 -#define __PRCM_PLL_CTRL_HOSC_CLK
[PATCH v2 06/21] sunxi: Add support for I2C on H6 like SoCs
I2C support, especially R_I2C port, will be needed in future. Upcoming support for H616 will need R_I2C to adjust DRAM voltage. Reviewed-by: Samuel Holland Signed-off-by: Jernej Skrabec --- .../include/asm/arch-sunxi/clock_sun50i_h6.h | 1 + arch/arm/mach-sunxi/Kconfig | 2 +- arch/arm/mach-sunxi/clock_sun50i_h6.c | 29 +++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h index 426069fc69a4..e83e84ab6cab 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h @@ -297,6 +297,7 @@ struct sunxi_ccm_reg { /* Module gate/reset shift*/ #define RESET_SHIFT(16) +#define GATE_SHIFT (0) /* DRAM clock bit field */ #define DRAM_MOD_RESET BIT(30) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index bd82c0ef3ee4..b23ed695cd1c 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -730,7 +730,7 @@ config I2C3_ENABLE See I2C0_ENABLE help text. endif -if SUNXI_GEN_SUN6I +if SUNXI_GEN_SUN6I || SUN50I_GEN_H6 config R_I2C_ENABLE bool "Enable the PRCM I2C/TWI controller" # This is used for the pmic on H3 diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c index ba8a26eb0d36..6bd466915c11 100644 --- a/arch/arm/mach-sunxi/clock_sun50i_h6.c +++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c @@ -2,6 +2,7 @@ #include #include #include +#include #ifdef CONFIG_SPL_BUILD void clock_init_safe(void) @@ -92,3 +93,31 @@ unsigned int clock_get_pll6(void) /* The register defines PLL6-4X, not plain PLL6 */ return 2400 / 4 * n / div1 / div2; } + +int clock_twi_onoff(int port, int state) +{ + 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; + u32 value, *ptr; + int shift; + + value = BIT(GATE_SHIFT) | BIT (RESET_SHIFT); + + if (port == 5) { + shift = 0; + ptr = >twi_gate_reset; + } else { + shift = port; + ptr = >twi_gate_reset; + } + + /* set the apb clock gate and reset for twi */ + if (state) + setbits_le32(ptr, value << shift); + else + clrbits_le32(ptr, value << shift); + + return 0; +} -- 2.30.0
[PATCH v2 01/21] sunxi: Add support for AXP305 PMIC
This PMIC can be found on H616 boards and it's very similar to AXP805 and AXP806. Reviewed-by: Andre Przywara Reviewed-by: Jaehoon Chung Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/pmic_bus.c | 6 +++ board/sunxi/board.c| 10 ++-- drivers/power/Kconfig | 13 +- drivers/power/Makefile | 1 + drivers/power/axp305.c | 83 ++ include/axp305.h | 17 +++ include/axp_pmic.h | 3 ++ 7 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 drivers/power/axp305.c create mode 100644 include/axp305.h diff --git a/arch/arm/mach-sunxi/pmic_bus.c b/arch/arm/mach-sunxi/pmic_bus.c index dea42de833f1..0394ce856448 100644 --- a/arch/arm/mach-sunxi/pmic_bus.c +++ b/arch/arm/mach-sunxi/pmic_bus.c @@ -18,6 +18,8 @@ #define AXP209_I2C_ADDR0x34 +#define AXP305_I2C_ADDR0x36 + #define AXP221_CHIP_ADDR 0x68 #define AXP221_CTRL_ADDR 0x3e #define AXP221_INIT_DATA 0x3e @@ -64,6 +66,8 @@ int pmic_bus_read(u8 reg, u8 *data) return i2c_read(AXP152_I2C_ADDR, reg, 1, data, 1); #elif defined CONFIG_AXP209_POWER return i2c_read(AXP209_I2C_ADDR, reg, 1, data, 1); +#elif defined CONFIG_AXP305_POWER + return i2c_read(AXP305_I2C_ADDR, reg, 1, data, 1); #elif defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER # ifdef CONFIG_MACH_SUN6I return p2wi_read(reg, data); @@ -81,6 +85,8 @@ int pmic_bus_write(u8 reg, u8 data) return i2c_write(AXP152_I2C_ADDR, reg, 1, , 1); #elif defined CONFIG_AXP209_POWER return i2c_write(AXP209_I2C_ADDR, reg, 1, , 1); +#elif defined CONFIG_AXP305_POWER + return i2c_write(AXP305_I2C_ADDR, reg, 1, , 1); #elif defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER # ifdef CONFIG_MACH_SUN6I return p2wi_write(reg, data); diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 77e464718846..40fdd5da0477 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -634,16 +634,18 @@ void sunxi_board_init(void) #endif #if defined CONFIG_AXP152_POWER || defined CONFIG_AXP209_POWER || \ - defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \ - defined CONFIG_AXP818_POWER + defined CONFIG_AXP221_POWER || defined CONFIG_AXP305_POWER || \ + defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER power_failed = axp_init(); #if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \ defined CONFIG_AXP818_POWER power_failed |= axp_set_dcdc1(CONFIG_AXP_DCDC1_VOLT); #endif +#if !defined(CONFIG_AXP305_POWER) power_failed |= axp_set_dcdc2(CONFIG_AXP_DCDC2_VOLT); power_failed |= axp_set_dcdc3(CONFIG_AXP_DCDC3_VOLT); +#endif #if !defined(CONFIG_AXP209_POWER) && !defined(CONFIG_AXP818_POWER) power_failed |= axp_set_dcdc4(CONFIG_AXP_DCDC4_VOLT); #endif @@ -656,8 +658,10 @@ void sunxi_board_init(void) defined CONFIG_AXP818_POWER power_failed |= axp_set_aldo1(CONFIG_AXP_ALDO1_VOLT); #endif +#if !defined(CONFIG_AXP305_POWER) power_failed |= axp_set_aldo2(CONFIG_AXP_ALDO2_VOLT); -#if !defined(CONFIG_AXP152_POWER) +#endif +#if !defined(CONFIG_AXP152_POWER) && !defined(CONFIG_AXP305_POWER) power_failed |= axp_set_aldo3(CONFIG_AXP_ALDO3_VOLT); #endif #ifdef CONFIG_AXP209_POWER diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 02050f6f3569..d17cf2d9112a 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -48,6 +48,15 @@ config AXP221_POWER Select this to enable support for the axp221/axp223 pmic found on most A23 and A31 boards. +config AXP305_POWER + bool "axp305 pmic support" + depends on MACH_SUN50I_H616 + select AXP_PMIC_BUS + select CMD_POWEROFF + ---help--- + Select this to enable support for the axp305 pmic found on most + H616 boards. + config AXP809_POWER bool "axp809 pmic support" depends on MACH_SUN9I @@ -127,11 +136,12 @@ config AXP_DCDC3_VOLT config AXP_DCDC4_VOLT int "axp pmic dcdc4 voltage" - depends on AXP152_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER + depends on AXP152_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP305_POWER default 1250 if AXP152_POWER default 1200 if MACH_SUN6I default 0 if MACH_SUN8I default 900 if MACH_SUN9I + default 1500 if AXP305_POWER ---help--- Set the voltage (mV) to program the axp pmic dcdc4 at, set to 0 to disable dcdc4. @@ -140,6 +150,7 @@ config AXP_DCDC4_VOLT On A23 / A33 boards dcdc4 is unused and should be disabled. On A80 boards dcdc4 powers VDD-SYS, HDMI, USB OTG and should be 0.9V. On A83T boards dcdc4 is
[PATCH v2 04/21] i2c: mvtwsi: sunxi: update macro
While currently none of the newer Allwinner SoCs currently has I2C support implemented in U-Boot, this will change soon. mvtwsi driver is good as it is for them except one macro. Update it to be ready once I2C support lands for those SoCs. Reviewed-by: Heiko Schocher Reviewed-by: Samuel Holland Signed-off-by: Jernej Skrabec --- drivers/i2c/mvtwsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/mvtwsi.c b/drivers/i2c/mvtwsi.c index 14c594d648ba..36d0d1485277 100644 --- a/drivers/i2c/mvtwsi.c +++ b/drivers/i2c/mvtwsi.c @@ -121,7 +121,7 @@ enum mvtwsi_ctrl_register_fields { * on other platforms, it is a normal r/w bit, which is cleared by writing 0. */ -#ifdef CONFIG_SUNXI_GEN_SUN6I +#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) #defineMVTWSI_CONTROL_CLEAR_IFLG 0x0008 #else #defineMVTWSI_CONTROL_CLEAR_IFLG 0x -- 2.30.0
[PATCH v2 03/21] mmc: sunxi: Replace H6 ifdefs with H6 gen macro
It turns out that several SoCs share same mmc configuration as H6. In order to lower ifdef clutter replace H6 specific macro with common one. Reviewed-by: Andre Przywara Signed-off-by: Jernej Skrabec --- arch/arm/include/asm/arch-sunxi/mmc.h | 2 +- drivers/mmc/sunxi_mmc.c | 12 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/mmc.h b/arch/arm/include/asm/arch-sunxi/mmc.h index f2deafddd202..340e25b04d2a 100644 --- a/arch/arm/include/asm/arch-sunxi/mmc.h +++ b/arch/arm/include/asm/arch-sunxi/mmc.h @@ -45,7 +45,7 @@ struct sunxi_mmc { u32 chda; /* 0x90 */ u32 cbda; /* 0x94 */ u32 res2[26]; -#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_MACH_SUN50I_H6) +#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) u32 res3[17]; u32 samp_dl; u32 res4[46]; diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 0e03b07ce555..3767a39277c1 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -122,7 +122,7 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) if (IS_ENABLED(CONFIG_MACH_SUN8I_A83T) && priv->mmc_no != 2) new_mode = false; -#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H6) +#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_SUN50I_GEN_H6) calibrate = true; #endif @@ -133,7 +133,7 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) #ifdef CONFIG_MACH_SUN9I pll = CCM_MMC_CTRL_PLL_PERIPH0; pll_hz = clock_get_pll4_periph0(); -#elif defined(CONFIG_MACH_SUN50I_H6) +#elif defined(CONFIG_SUN50I_GEN_H6) pll = CCM_MMC_CTRL_PLL6X2; pll_hz = clock_get_pll6() * 2; #else @@ -249,7 +249,7 @@ static int mmc_config_clock(struct sunxi_mmc_priv *priv, struct mmc *mmc) rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK; writel(rval, >reg->clkcr); -#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H6) +#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_SUN50I_GEN_H6) /* A64 supports calibration of delays on MMC controller and we * have to set delay of zero before starting calibration. * Allwinner BSP driver sets a delay only in the case of @@ -530,7 +530,7 @@ struct mmc *sunxi_mmc_init(int sdc_no) cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; cfg->host_caps = MMC_MODE_4BIT; -#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I) || defined(CONFIG_MACH_SUN50I_H6) +#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I) || defined(CONFIG_SUN50I_GEN_H6) if (sdc_no == 2) cfg->host_caps = MMC_MODE_8BIT; #endif @@ -545,7 +545,7 @@ struct mmc *sunxi_mmc_init(int sdc_no) /* config ahb clock */ debug("init mmc %d clock and io\n", sdc_no); -#if !defined(CONFIG_MACH_SUN50I_H6) +#if !defined(CONFIG_SUN50I_GEN_H6) setbits_le32(>ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no)); #ifdef CONFIG_SUNXI_GEN_SUN6I @@ -557,7 +557,7 @@ struct mmc *sunxi_mmc_init(int sdc_no) writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET, SUNXI_MMC_COMMON_BASE + 4 * sdc_no); #endif -#else /* CONFIG_MACH_SUN50I_H6 */ +#else /* CONFIG_SUN50I_GEN_H6 */ setbits_le32(>sd_gate_reset, 1 << sdc_no); /* unassert reset */ setbits_le32(>sd_gate_reset, 1 << (RESET_SHIFT + sdc_no)); -- 2.30.0
[PATCH v2 02/21] sunxi: Introduce common symbol for H6 like SoCs
It turns out that there are at least 2 other SoCs which have basically the same memory map, similar clocks and other features as H6. It's very likely that we'll see more such SoCs in the future. In order to ease porting to new SoCs and lower ifdef clutter, introduce common symbol for them. Signed-off-by: Jernej Skrabec --- arch/arm/include/asm/arch-sunxi/boot0.h | 2 +- arch/arm/include/asm/arch-sunxi/clock.h | 2 +- arch/arm/include/asm/arch-sunxi/cpu.h | 2 +- arch/arm/include/asm/arch-sunxi/timer.h | 2 +- arch/arm/mach-sunxi/Kconfig | 19 +-- arch/arm/mach-sunxi/Makefile| 2 +- arch/arm/mach-sunxi/board.c | 4 ++-- arch/arm/mach-sunxi/rmr_switch.S| 2 +- common/spl/Kconfig | 4 ++-- include/configs/sun50i.h| 2 +- 10 files changed, 24 insertions(+), 17 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/boot0.h b/arch/arm/include/asm/arch-sunxi/boot0.h index 46d0f0666c2b..e8e8e38f0556 100644 --- a/arch/arm/include/asm/arch-sunxi/boot0.h +++ b/arch/arm/include/asm/arch-sunxi/boot0.h @@ -39,7 +39,7 @@ .word 0xf57ff06f // isb sy .word 0xe320f003 // wfi .word 0xeafd // b @wfi -#ifndef CONFIG_MACH_SUN50I_H6 +#ifndef CONFIG_SUN50I_GEN_H6 .word 0x017000a0 // writeable RVBAR mapping address #else .word 0x09010040 // writeable RVBAR mapping address diff --git a/arch/arm/include/asm/arch-sunxi/clock.h b/arch/arm/include/asm/arch-sunxi/clock.h index 5994130e6b54..cbbe5c7a1e68 100644 --- a/arch/arm/include/asm/arch-sunxi/clock.h +++ b/arch/arm/include/asm/arch-sunxi/clock.h @@ -16,7 +16,7 @@ /* clock control module regs definition */ #if defined(CONFIG_MACH_SUN8I_A83T) #include -#elif defined(CONFIG_MACH_SUN50I_H6) +#elif defined(CONFIG_SUN50I_GEN_H6) #include #elif defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN8I) || \ defined(CONFIG_MACH_SUN50I) diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h b/arch/arm/include/asm/arch-sunxi/cpu.h index 8b57d24e2f0c..b08f2023748c 100644 --- a/arch/arm/include/asm/arch-sunxi/cpu.h +++ b/arch/arm/include/asm/arch-sunxi/cpu.h @@ -8,7 +8,7 @@ #if defined(CONFIG_MACH_SUN9I) #include -#elif defined(CONFIG_MACH_SUN50I_H6) +#elif defined(CONFIG_SUN50I_GEN_H6) #include #else #include diff --git a/arch/arm/include/asm/arch-sunxi/timer.h b/arch/arm/include/asm/arch-sunxi/timer.h index 6f138d04b806..bb5626d893bb 100644 --- a/arch/arm/include/asm/arch-sunxi/timer.h +++ b/arch/arm/include/asm/arch-sunxi/timer.h @@ -76,7 +76,7 @@ struct sunxi_timer_reg { struct sunxi_tgp tgp[4]; u8 res5[8]; u32 cpu_cfg; -#elif defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_MACH_SUN50I_H6) +#elif defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) u8 res3[16]; struct sunxi_wdog wdog[5]; /* We have 5 watchdogs */ #endif diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 49ef217f08c0..bd82c0ef3ee4 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -82,7 +82,7 @@ config SUN8I_RSB config SUNXI_SRAM_ADDRESS hex default 0x1 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5 - default 0x2 if MACH_SUN50I_H6 + default 0x2 if SUN50I_GEN_H6 default 0x0 ---help--- Older Allwinner SoCs have their mask boot ROM mapped just below 4GB, @@ -108,6 +108,15 @@ config SUNXI_GEN_SUN6I separate ahb reset control registers, custom pmic bus, new style watchdog, etc. +config SUN50I_GEN_H6 + bool + select FIT + select SPL_LOAD_FIT + select SUPPORT_SPL + ---help--- + Select this for sunxi SoCs which have H6 like peripherals, clocks + and memory map. + config SUNXI_DRAM_DW bool ---help--- @@ -302,11 +311,9 @@ config MACH_SUN50I_H5 config MACH_SUN50I_H6 bool "sun50i (Allwinner H6)" select ARM64 - select SUPPORT_SPL - select FIT select PHY_SUN4I_USB - select SPL_LOAD_FIT select DRAM_SUN50I_H6 + select SUN50I_GEN_H6 endchoice @@ -756,7 +763,7 @@ config VIDEO_SUNXI depends on !MACH_SUN8I_V3S depends on !MACH_SUN9I depends on !MACH_SUN50I - depends on !MACH_SUN50I_H6 + depends on !SUN50I_GEN_H6 select VIDEO imply VIDEO_DT_SIMPLEFB default y @@ -989,7 +996,7 @@ config SPL_STACK_R_ADDR default 0x4fe0 if MACH_SUN8I default 0x2fe0 if MACH_SUN9I default 0x4fe0 if MACH_SUN50I - default 0x4fe0 if MACH_SUN50I_H6 + default 0x4fe0 if SUN50I_GEN_H6 config SPL_SPI_SUNXI bool "Support for SPI Flash on Allwinner SoCs in SPL" diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile index d129f334798b..b8aca43d6630 100644 --- a/arch/arm/mach-sunxi
[PATCH v2 00/21] sunxi: Introduce H616 support
This series introduces H616 support. Later patches add also OrangePi Zero2 support but since H616 DT is not merged into Linux yet, I don't expect them to land yet. Most patches are ready to land, except those which depends on non-upstreamed DT yet. This series is based on u-boot-sunxi repo. Please take a look. Best regards, Jernej Changes from v1: - collected tags - replaced AXP805 magic value with macro - fixed H6 build (missing symbols after refactoring) - removed premature SPI boot support - add missing peripherals to prcm map - reworked mmc sector calculation - fixed comment in clock function - used IS_ENABLED ternary instead of #if #else #endif - renamed DRAM struct field to more meaningful name - fixed missing space in Kconfig for DRAM symbol - removed unused macro from sunxi-u-boot.dtsi - removed padding definition for H616 - added FEL support for H616 - picked patches 1-2 from https://patchwork.ozlabs.org/project/uboot/list/?series=223600 - added mmc support for H616 Andre Przywara (4): sunxi: support loading with SPL > 32KB mmc: sunxi: Refactor mod clock register offset net: sun8i-emac: Always clear syscon EPHY register net: sun8i-emac: Determine pinmux based on SoC, not EMAC type Jernej Skrabec (17): sunxi: Add support for AXP305 PMIC sunxi: Introduce common symbol for H6 like SoCs mmc: sunxi: Replace H6 ifdefs with H6 gen macro i2c: mvtwsi: sunxi: update macro sunxi: prcm: Add memory map for H6 like SoCs sunxi: Add support for I2C on H6 like SoCs sunxi: introduce support for H616 clocks sunxi: add support for H616 uart0 sunxi: add support for R_I2C on H616 sunxi: Add H616 DRAM support sunxi: Add support for H616 SoC mmc: sunxi: Add H616 clock offset sunxi: Add H616 FEL support arm: sunxi: add initial H616 DTSI and headers sunxi: gpio: introduce compatible for H616 clk: sunxi: Add support for H616 clocks sunxi: Add support for OrangePi Zero2 arch/arm/cpu/armv8/fel_utils.S|5 +- arch/arm/dts/Makefile |2 + arch/arm/dts/sun50i-h616-orangepi-zero2.dts | 240 arch/arm/dts/sun50i-h616.dtsi | 716 arch/arm/dts/sunxi-u-boot.dtsi|8 + arch/arm/include/asm/arch-sunxi/boot0.h |2 +- arch/arm/include/asm/arch-sunxi/clock.h |2 +- .../include/asm/arch-sunxi/clock_sun50i_h6.h | 19 +- arch/arm/include/asm/arch-sunxi/cpu.h |2 +- .../include/asm/arch-sunxi/cpu_sun50i_h6.h|7 + arch/arm/include/asm/arch-sunxi/dram.h|2 + .../include/asm/arch-sunxi/dram_sun50i_h616.h | 159 +++ arch/arm/include/asm/arch-sunxi/gpio.h|2 + arch/arm/include/asm/arch-sunxi/mmc.h |2 +- arch/arm/include/asm/arch-sunxi/prcm.h| 249 +--- arch/arm/include/asm/arch-sunxi/prcm_sun50i.h | 47 + arch/arm/include/asm/arch-sunxi/prcm_sun6i.h | 247 arch/arm/include/asm/arch-sunxi/timer.h |2 +- arch/arm/mach-sunxi/Kconfig | 75 +- arch/arm/mach-sunxi/Makefile |4 +- arch/arm/mach-sunxi/board.c | 24 +- arch/arm/mach-sunxi/clock_sun50i_h6.c | 37 +- arch/arm/mach-sunxi/cpu_info.c|2 + arch/arm/mach-sunxi/dram_sun50i_h616.c| 1023 + arch/arm/mach-sunxi/dram_timings/Makefile |2 + .../mach-sunxi/dram_timings/h616_ddr3_1333.c | 94 ++ arch/arm/mach-sunxi/pmic_bus.c|6 + arch/arm/mach-sunxi/rmr_switch.S |2 +- board/sunxi/MAINTAINERS |5 + board/sunxi/board.c | 14 +- common/spl/Kconfig|7 +- configs/orangepi_zero2_defconfig | 15 + drivers/clk/sunxi/Kconfig |7 + drivers/clk/sunxi/Makefile|1 + drivers/clk/sunxi/clk_h616.c | 120 ++ drivers/gpio/sunxi_gpio.c |1 + drivers/i2c/mvtwsi.c |2 +- drivers/mmc/sunxi_mmc.c | 97 +- drivers/net/sun8i_emac.c | 59 +- drivers/power/Kconfig | 14 +- drivers/power/Makefile|1 + drivers/power/axp305.c| 83 ++ include/axp305.h | 17 + include/axp_pmic.h|3 + include/configs/sun50i.h |2 +- include/configs/sunxi-common.h|7 + include/dt-bindings/clock/sun50i-h616-ccu.h | 115 ++ include/dt-bindings/reset/sun50i-h616-ccu.h | 70 ++ 48 files changed, 3258 insertions(+), 364 deletions(-) create mode 100644 arch/arm/dts/sun50i-h616-orangepi-zero2.dts create mode 100644 arch/arm/dts/sun50i-h616.dtsi create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h create mode 100644 arch/arm/include/asm/arch-sunxi/prcm_sun50
[PATCH v6 3/3] arm64: dts: sun50i: Add support for Orange Pi 3
From: Andre Heider dts file is taken from Linux 5.11-rc1 tag. The Bluetooth controller of this device ships with a default address, use the new CONFIG_FIXUP_BDADDR option to fix it up. akonadi:?collection=30=INBOX Acked-by: Maxime Ripard Signed-off-by: Andre Heider [Updated OrangePi 3 DT, rebase and config update] Signed-off-by: Jernej Skrabec --- arch/arm/dts/Makefile | 1 + arch/arm/dts/sun50i-h6-orangepi-3.dts | 345 ++ board/sunxi/MAINTAINERS | 5 + configs/orangepi_3_defconfig | 12 + 4 files changed, 363 insertions(+) create mode 100644 arch/arm/dts/sun50i-h6-orangepi-3.dts create mode 100644 configs/orangepi_3_defconfig diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index e00aed1ec207..607571d04b25 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -605,6 +605,7 @@ dtb-$(CONFIG_MACH_SUN50I_H5) += \ sun50i-h5-orangepi-zero-plus2.dtb dtb-$(CONFIG_MACH_SUN50I_H6) += \ sun50i-h6-beelink-gs1.dtb \ + sun50i-h6-orangepi-3.dtb \ sun50i-h6-orangepi-lite2.dtb \ sun50i-h6-orangepi-one-plus.dtb \ sun50i-h6-pine-h64.dtb \ diff --git a/arch/arm/dts/sun50i-h6-orangepi-3.dts b/arch/arm/dts/sun50i-h6-orangepi-3.dts new file mode 100644 index ..15c9dd8c4479 --- /dev/null +++ b/arch/arm/dts/sun50i-h6-orangepi-3.dts @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +// Copyright (C) 2019 Ondřej Jirman + +/dts-v1/; + +#include "sun50i-h6.dtsi" +#include "sun50i-h6-cpu-opp.dtsi" + +#include + +/ { + model = "OrangePi 3"; + compatible = "xunlong,orangepi-3", "allwinner,sun50i-h6"; + + aliases { + serial0 = + serial1 = + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + connector { + compatible = "hdmi-connector"; + ddc-en-gpios = < 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */ + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <_out_con>; + }; + }; + }; + + ext_osc32k: ext_osc32k_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + clock-output-names = "ext_osc32k"; + }; + + leds { + compatible = "gpio-leds"; + + power { + label = "orangepi:red:power"; + gpios = <_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */ + default-state = "on"; + }; + + status { + label = "orangepi:green:status"; + gpios = <_pio 0 7 GPIO_ACTIVE_HIGH>; /* PL7 */ + }; + }; + + reg_vcc5v: vcc5v { + /* board wide 5V supply directly from the DC jack */ + compatible = "regulator-fixed"; + regulator-name = "vcc-5v"; + regulator-min-microvolt = <500>; + regulator-max-microvolt = <500>; + regulator-always-on; + }; + + reg_vcc33_wifi: vcc33-wifi { + /* Always on 3.3V regulator for WiFi and BT */ + compatible = "regulator-fixed"; + regulator-name = "vcc33-wifi"; + regulator-min-microvolt = <330>; + regulator-max-microvolt = <330>; + regulator-always-on; + vin-supply = <_vcc5v>; + }; + + reg_vcc_wifi_io: vcc-wifi-io { + /* Always on 1.8V/300mA regulator for WiFi and BT IO */ + compatible = "regulator-fixed"; + regulator-name = "vcc-wifi-io"; + regulator-min-microvolt = <180>; + regulator-max-microvolt = <180>; + regulator-always-on; + vin-supply = <_vcc33_wifi>; + }; + + wifi_pwrseq: wifi-pwrseq { + compatible = "mmc-pwrseq-simple"; + clocks = < 1>; + clock-names = "ext_clock"; + reset-gpios = <_pio 1 3 GPIO_ACTIVE_LOW>; /* PM3 */ + post-power-on-delay-ms = <200>; + }; +}; + + { + cpu-supply = <_dcdca>; +}; + + { + status = "okay"; +}; + + { + status = "okay"; +}; + + { + status = "okay"; +}; + + { + status = "okay"; +}; + + { + mali-supply = <_dcdcc>; + status = "okay"; +}; + + { + status = "okay&q
[PATCH v6 2/3] arm: sunxi: add a config option to fixup a Bluetooth address
From: Andre Heider Some Bluetooth controllers, like the BCM4345C5 of the Orange Pi 3, ship with the controller default address. Add a config option to fix it up so it can function properly. Signed-off-by: Andre Heider Tested-by: Ondrej Jirman Acked-by: Maxime Ripard [rebased] Signed-off-by: Jernej Skrabec --- arch/arm/mach-sunxi/Kconfig | 11 +++ board/sunxi/board.c | 34 ++ 2 files changed, 45 insertions(+) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 49ef217f08c0..11e644519271 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -1016,4 +1016,15 @@ config PINEPHONE_DT_SELECTION Enable this option to automatically select the device tree for the correct PinePhone hardware revision during boot. +config BLUETOOTH_DT_DEVICE_FIXUP + string "Fixup the Bluetooth controller address" + default "" + help + This option specifies the DT compatible name of the Bluetooth + controller for which to set the "local-bd-address" property. + Set this option if your device ships with the Bluetooth controller + default address. + The used address is "bdaddr" if set, and "ethaddr" with the LSB + flipped elsewise. + endif diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 4a29e351141b..ed658fced3c7 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -908,6 +908,38 @@ int misc_init_r(void) return 0; } +static void bluetooth_dt_fixup(void *blob) +{ + /* Some devices ship with a Bluetooth controller default address. +* Set a valid address through the device tree. +*/ + uchar tmp[ETH_ALEN], bdaddr[ETH_ALEN]; + unsigned int sid[4]; + int i; + + if (!CONFIG_BLUETOOTH_DT_DEVICE_FIXUP[0]) + return; + + if (eth_env_get_enetaddr("bdaddr", tmp)) { + /* Convert between the binary formats of the corresponding stacks */ + for (i = 0; i < ETH_ALEN; ++i) + bdaddr[i] = tmp[ETH_ALEN - i - 1]; + } else { + if (!get_unique_sid(sid)) + return; + + bdaddr[0] = ((sid[3] >> 0) & 0xff) ^ 1; + bdaddr[1] = (sid[3] >> 8) & 0xff; + bdaddr[2] = (sid[3] >> 16) & 0xff; + bdaddr[3] = (sid[3] >> 24) & 0xff; + bdaddr[4] = (sid[0] >> 0) & 0xff; + bdaddr[5] = 0x02; + } + + do_fixup_by_compat(blob, CONFIG_BLUETOOTH_DT_DEVICE_FIXUP, + "local-bd-address", bdaddr, ETH_ALEN, 1); +} + int ft_board_setup(void *blob, struct bd_info *bd) { int __maybe_unused r; @@ -918,6 +950,8 @@ int ft_board_setup(void *blob, struct bd_info *bd) */ setup_environment(blob); + bluetooth_dt_fixup(blob); + #ifdef CONFIG_VIDEO_DT_SIMPLEFB r = sunxi_simplefb_setup(blob); if (r) -- 2.30.0
[PATCH v6 1/3] sunxi: board: extract creating a unique sid into a helper function
From: Andre Heider Refactor setup_environment() so we can use the created sid for a Bluetooth address too. Acked-by: Maxime Ripard Reviewed-by: Andre Przywara Signed-off-by: Andre Heider [rebased] Signed-off-by: Jernej Skrabec --- board/sunxi/board.c | 121 1 file changed, 66 insertions(+), 55 deletions(-) diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 708a27ed78e9..4a29e351141b 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -789,6 +789,38 @@ static void parse_spl_header(const uint32_t spl_addr) env_set_hex("fel_scriptaddr", spl->fel_script_address); } +static bool get_unique_sid(unsigned int *sid) +{ + if (sunxi_get_sid(sid) != 0) + return false; + + if (!sid[0]) + return false; + + /* +* The single words 1 - 3 of the SID have quite a few bits +* which are the same on many models, so we take a crc32 +* of all 3 words, to get a more unique value. +* +* Note we only do this on newer SoCs as we cannot change +* the algorithm on older SoCs since those have been using +* fixed mac-addresses based on only using word 3 for a +* long time and changing a fixed mac-address with an +* u-boot update is not good. +*/ +#if !defined(CONFIG_MACH_SUN4I) && !defined(CONFIG_MACH_SUN5I) && \ +!defined(CONFIG_MACH_SUN6I) && !defined(CONFIG_MACH_SUN7I) && \ +!defined(CONFIG_MACH_SUN8I_A23) && !defined(CONFIG_MACH_SUN8I_A33) + sid[3] = crc32(0, (unsigned char *)[1], 12); +#endif + + /* Ensure the NIC specific bytes of the mac are not all 0 */ + if ((sid[3] & 0xff) == 0) + sid[3] |= 0x80; + + return true; +} + /* * Note this function gets called multiple times. * It must not make any changes to env variables which already exist. @@ -799,61 +831,40 @@ static void setup_environment(const void *fdt) unsigned int sid[4]; uint8_t mac_addr[6]; char ethaddr[16]; - int i, ret; - - ret = sunxi_get_sid(sid); - if (ret == 0 && sid[0] != 0) { - /* -* The single words 1 - 3 of the SID have quite a few bits -* which are the same on many models, so we take a crc32 -* of all 3 words, to get a more unique value. -* -* Note we only do this on newer SoCs as we cannot change -* the algorithm on older SoCs since those have been using -* fixed mac-addresses based on only using word 3 for a -* long time and changing a fixed mac-address with an -* u-boot update is not good. -*/ -#if !defined(CONFIG_MACH_SUN4I) && !defined(CONFIG_MACH_SUN5I) && \ -!defined(CONFIG_MACH_SUN6I) && !defined(CONFIG_MACH_SUN7I) && \ -!defined(CONFIG_MACH_SUN8I_A23) && !defined(CONFIG_MACH_SUN8I_A33) - sid[3] = crc32(0, (unsigned char *)[1], 12); -#endif - - /* Ensure the NIC specific bytes of the mac are not all 0 */ - if ((sid[3] & 0xff) == 0) - sid[3] |= 0x80; - - for (i = 0; i < 4; i++) { - sprintf(ethaddr, "ethernet%d", i); - if (!fdt_get_alias(fdt, ethaddr)) - continue; - - if (i == 0) - strcpy(ethaddr, "ethaddr"); - else - sprintf(ethaddr, "eth%daddr", i); - - if (env_get(ethaddr)) - continue; - - /* Non OUI / registered MAC address */ - mac_addr[0] = (i << 4) | 0x02; - mac_addr[1] = (sid[0] >> 0) & 0xff; - mac_addr[2] = (sid[3] >> 24) & 0xff; - mac_addr[3] = (sid[3] >> 16) & 0xff; - mac_addr[4] = (sid[3] >> 8) & 0xff; - mac_addr[5] = (sid[3] >> 0) & 0xff; - - eth_env_set_enetaddr(ethaddr, mac_addr); - } - - if (!env_get("serial#")) { - snprintf(serial_string, sizeof(serial_string), - "%08x%08x", sid[0], sid[3]); - - env_set("serial#", serial_string); - } + int i; + + if (!get_unique_sid(sid)) + return; + + for (i = 0; i < 4; i++) { + sprintf(ethaddr, "ethernet%d", i); + if (!fdt_get_alias(fdt, ethaddr)) + continue; + + if (i == 0) +
[PATCH v6 0/3] sunxi: Add support for OrangePi 3
This series introduces OrangePi 3 support. Previous cover letter: This is just refreshed v4 from here: https://patchwork.ozlabs.org/project/uboot/list/?series=156657=* Patches are only rebased, DT updated and defconfig regenerated, so I kept old tags. Only difference with old version is that this one does not sync H6 DT files. Becasue of that, this series should be applied on top of: https://patchwork.ozlabs.org/project/uboot/list/?series=222516 Please take a look. Best regards, Jernej Changes from v5: - Added tags - Renamed FIXUP_BDADDR -> BLUETOOTH_DT_DEVICE_FIXUP - Renamed fixup_bd_address() -> bluetooth_dt_fixup() - Removed CONFIG_PSCI_RESET from defconfig Andre Heider (3): sunxi: board: extract creating a unique sid into a helper function arm: sunxi: add a config option to fixup a Bluetooth address arm64: dts: sun50i: Add support for Orange Pi 3 arch/arm/dts/Makefile | 1 + arch/arm/dts/sun50i-h6-orangepi-3.dts | 345 ++ arch/arm/mach-sunxi/Kconfig | 11 + board/sunxi/MAINTAINERS | 5 + board/sunxi/board.c | 155 configs/orangepi_3_defconfig | 12 + 6 files changed, 474 insertions(+), 55 deletions(-) create mode 100644 arch/arm/dts/sun50i-h6-orangepi-3.dts create mode 100644 configs/orangepi_3_defconfig -- 2.30.0