[PATCH v2 07/10] sunxi: Parameterize bit delay code in H616 DRAM driver

2023-04-10 Thread Jernej Skrabec
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

2023-04-10 Thread Jernej Skrabec
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

2023-04-10 Thread Jernej Skrabec
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

2023-04-10 Thread Jernej Skrabec
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

2023-04-10 Thread Jernej Skrabec
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

2023-04-10 Thread Jernej Skrabec
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

2023-04-10 Thread Jernej Skrabec
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

2023-04-10 Thread Jernej Skrabec
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

2023-04-10 Thread Jernej Skrabec
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

2023-04-10 Thread Jernej Skrabec
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

2023-04-10 Thread Jernej Skrabec
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

2022-12-11 Thread Jernej Skrabec
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

2022-12-11 Thread Jernej Skrabec
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

2022-12-11 Thread Jernej Skrabec
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

2022-12-11 Thread Jernej Skrabec
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

2022-12-11 Thread Jernej Skrabec
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

2022-12-11 Thread Jernej Skrabec
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

2022-12-11 Thread Jernej Skrabec
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

2022-12-11 Thread Jernej Skrabec
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

2022-12-11 Thread Jernej Skrabec
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

2022-01-30 Thread Jernej Skrabec
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

2022-01-30 Thread Jernej Skrabec
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

2022-01-30 Thread Jernej Skrabec
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

2022-01-30 Thread Jernej Skrabec
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

2022-01-29 Thread Jernej Skrabec
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

2022-01-29 Thread Jernej Skrabec
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

2022-01-29 Thread Jernej Skrabec
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

2021-09-11 Thread Jernej Skrabec
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

2021-08-21 Thread 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

2021-06-07 Thread Jernej Skrabec
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

2021-03-23 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-03-06 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-23 Thread Jernej Skrabec
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

2021-02-21 Thread Jernej Skrabec
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

2021-02-01 Thread Jernej Skrabec
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

2021-01-31 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-11 Thread Jernej Skrabec
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

2021-01-10 Thread Jernej Skrabec
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

2021-01-10 Thread Jernej Skrabec
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

2021-01-10 Thread Jernej Skrabec
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

2021-01-10 Thread Jernej Skrabec
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



  1   2   >