Skip to contentSkip to conversation

sun6i: s/SUNXI_GPL0_R_P2WI/SUN6I_GPL0_R_P2WI/

PATCH New Hans de Goede 4 participants 54 messages Dec 16, 2014 – Dec 22, 2014

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/14 sun6i: s/SUNXI_GPL0_R_P2WI/SUN6I_GPL0_R_P2WI/

The p2wi interface is only available on sun6i, adjust the gpio pinmux defines for it to reflect this.

---
 arch/arm/cpu/armv7/sunxi/p2wi.c        | 4 ++--
 arch/arm/include/asm/arch-sunxi/gpio.h | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)
arch/arm/cpu/armv7/sunxi/p2wi.c +2 -2
index 48613bd..52c2c53 100644
@@ -31,8 +31,8 @@ void p2wi_init(void)
 	/* Enable p2wi and PIO clk, and de-assert their resets */
 	prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_P2WI);
 
-	sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUNXI_GPL0_R_P2WI_SCK);
-	sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUNXI_GPL1_R_P2WI_SDA);
+	sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN6I_GPL0_R_P2WI_SCK);
+	sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN6I_GPL1_R_P2WI_SDA);
 
 	/* Reset p2wi controller and set clock to CLKIN(12)/8 = 1.5 MHz */
 	writel(P2WI_CTRL_RESET, &p2wi->ctrl);
arch/arm/include/asm/arch-sunxi/gpio.h +2 -2
index 366c0dc..9f972ce 100644
@@ -173,8 +173,8 @@ enum sunxi_gpio_number {
 
 #define SUN4I_GPI4_SDC3		2
 
-#define SUNXI_GPL0_R_P2WI_SCK	3
-#define SUNXI_GPL1_R_P2WI_SDA	3
+#define SUN6I_GPL0_R_P2WI_SCK	3
+#define SUN6I_GPL1_R_P2WI_SDA	3
 
 #define SUN8I_GPL2_R_UART_TX	2
 #define SUN8I_GPL3_R_UART_RX	2
Signature · 1 line
2.1.0
#1 lore raw

PATCH 2/14 sunxi: Add support for the rsb (Reduced Serial Bus)

sun8i (A23) introduces a new bus for communicating with the pmic, the rsb, the rsb is also used to communicate with the pmic on the A80, and is documented in the A80 user manual.

This commit adds support for this based on the rsb driver from the allwinner u-boot sources.

Note: Not yet ready for upstream, code needs some significant cleanups.

---
 arch/arm/cpu/armv7/sunxi/Makefile      |   1 +
 arch/arm/cpu/armv7/sunxi/rsb.c         | 158 +++++++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-sunxi/cpu.h  |   3 +-
 arch/arm/include/asm/arch-sunxi/gpio.h |   2 +
 arch/arm/include/asm/arch-sunxi/prcm.h |   3 +-
 arch/arm/include/asm/arch-sunxi/rsb.h  |  55 ++++++++++++
 6 files changed, 220 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/sunxi/rsb.c
 create mode 100644 arch/arm/include/asm/arch-sunxi/rsb.h
arch/arm/cpu/armv7/sunxi/Makefile +1 -0
index 1337b60..3e8975a 100644
@@ -15,6 +15,7 @@ obj-y	+= pinmux.o
 obj-$(CONFIG_MACH_SUN6I)	+= prcm.o
 obj-$(CONFIG_MACH_SUN8I)	+= prcm.o
 obj-$(CONFIG_MACH_SUN6I)	+= p2wi.o
+obj-$(CONFIG_MACH_SUN8I)	+= rsb.o
 obj-$(CONFIG_MACH_SUN4I)	+= clock_sun4i.o
 obj-$(CONFIG_MACH_SUN5I)	+= clock_sun4i.o
 obj-$(CONFIG_MACH_SUN6I)	+= clock_sun6i.o
arch/arm/cpu/armv7/sunxi/rsb.c new file +158 -0

158 lines not on this page · raw message

arch/arm/include/asm/arch-sunxi/cpu.h +2 -1
index 9500262..49c1614 100644
@@ -128,7 +128,8 @@
 #define SUN6I_CPUCFG_BASE		0x01f01c00
 #define SUNXI_R_UART_BASE		0x01f02800
 #define SUNXI_R_PIO_BASE		0x01f02c00
-#define SUNXI_P2WI_BASE			0x01f03400
+#define SUNXI_P2WI_BASE			0x01f03400	/* on sun6i */
+#define SUNXI_RSB_BASE			0x01f03400	/* on sun8i */
 
 /* CoreSight Debug Module */
 #define SUNXI_CSDM_BASE			0x3f500000
arch/arm/include/asm/arch-sunxi/gpio.h +2 -0
index 9f972ce..6623f15 100644
@@ -176,6 +176,8 @@ enum sunxi_gpio_number {
 #define SUN6I_GPL0_R_P2WI_SCK	3
 #define SUN6I_GPL1_R_P2WI_SDA	3
 
+#define SUN8I_GPL0_R_RSB_SCK	2
+#define SUN8I_GPL1_R_RSB_SDA	2
 #define SUN8I_GPL2_R_UART_TX	2
 #define SUN8I_GPL3_R_UART_RX	2
 
arch/arm/include/asm/arch-sunxi/prcm.h +2 -1
index 88de1ff..82ed541 100644
@@ -50,7 +50,8 @@
 #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)
+#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)
arch/arm/include/asm/arch-sunxi/rsb.h new file +55 -0

55 lines not on this page · raw message

Signature · 1 line
2.1.0
#2 lore raw

PATCH 2/14 sunxi: Add support for the rsb (Reduced Serial Bus)

Hi,

Quoted 8 lines · Hans de Goede

sun8i (A23) introduces a new bus for communicating with the pmic, the rsb, the rsb is also used to communicate with the pmic on the A80, and is documented in the A80 user manual.

This commit adds support for this based on the rsb driver from the allwinner u-boot sources.

Note: Not yet ready for upstream, code needs some significant cleanups.

Confusing note.

Quoted 76 lines
---
 arch/arm/cpu/armv7/sunxi/Makefile      |   1 +
 arch/arm/cpu/armv7/sunxi/rsb.c         | 158 +++++++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-sunxi/cpu.h  |   3 +-
 arch/arm/include/asm/arch-sunxi/gpio.h |   2 +
 arch/arm/include/asm/arch-sunxi/prcm.h |   3 +-
 arch/arm/include/asm/arch-sunxi/rsb.h  |  55 ++++++++++++
 6 files changed, 220 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/sunxi/rsb.c
 create mode 100644 arch/arm/include/asm/arch-sunxi/rsb.h
arch/arm/cpu/armv7/sunxi/Makefile +1 -0
index 1337b60..3e8975a 100644
@@ -15,6 +15,7 @@ obj-y += pinmux.o
 obj-$(CONFIG_MACH_SUN6I)       += prcm.o
 obj-$(CONFIG_MACH_SUN8I)       += prcm.o
 obj-$(CONFIG_MACH_SUN6I)       += p2wi.o
+obj-$(CONFIG_MACH_SUN8I)       += rsb.o
 obj-$(CONFIG_MACH_SUN4I)       += clock_sun4i.o
 obj-$(CONFIG_MACH_SUN5I)       += clock_sun4i.o
 obj-$(CONFIG_MACH_SUN6I)       += clock_sun6i.o
arch/arm/cpu/armv7/sunxi/rsb.c new file +45 -0
new file mode 100644
index 0000000..b72bb9d
@@ -0,0 +1,158 @@
+/*
+ * (C) Copyright 2014 Hans de Goede <[email protected]>
+ *
+ * Based on allwinner u-boot sources rsb code which is:
+ * (C) Copyright 2007-2013
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * lixiang <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/prcm.h>
+#include <asm/arch/rsb.h>
+
+static void rsb_cfg_io(void)
+{
+       sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_GPL0_R_RSB_SCK);
+       sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN8I_GPL1_R_RSB_SDA);
+       sunxi_gpio_set_pull(SUNXI_GPL(0), 1);
+       sunxi_gpio_set_pull(SUNXI_GPL(1), 1);
+       sunxi_gpio_set_drv(SUNXI_GPL(0), 2);
+       sunxi_gpio_set_drv(SUNXI_GPL(1), 2);
+}
+
+static void rsb_set_clk(void)
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+       u32 div = 0;
+       u32 cd_odly = 0;
+
+       /* Source is Hosc24M, set RSB clk to 3Mhz */
+       div = 24000000 / 3000000 / 2 - 1;
+       cd_odly = div >> 1;
+       if (!cd_odly)
+               cd_odly = 1;
+
+       writel((cd_odly << 8) | div, &rsb->ccr);
+}
+
+void rsb_init(void)

arch/arm/cpu/armv7/sunxi/rsb.c line 55

Quoted 10 lines
arch/arm/cpu/armv7/sunxi/rsb.c new file +10 -0
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+
+       rsb_cfg_io();
+
+       /* Enable RSB and PIO clk, and de-assert their resets */
+       prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_RSB);
+
+       writel(RSB_CTRL_SOFT_RST, &rsb->ctrl);

Do we need a small delay here for the device to finish reset?

Quoted 108 lines
arch/arm/cpu/armv7/sunxi/rsb.c new file +103 -0
+       rsb_set_clk();
+}
+
+static int rsb_await_trans(void)
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+       unsigned long tmo = timer_get_us() + 1000000;
+       u32 stat;
+       int ret;
+
+       while (1) {
+               stat = readl(&rsb->stat);
+               if (stat & RSB_STAT_LBSY_INT) {
+                       ret = -EBUSY;
+                       break;
+               }
+               if (stat & RSB_STAT_TERR_INT) {
+                       ret = -EIO;
+                       break;
+               }
+               if (stat & RSB_STAT_TOVER_INT) {
+                       ret = 0;
+                       break;
+               }
+               if (timer_get_us() > tmo) {
+                       ret = -ETIME;
+                       break;
+               }
+       }
+       writel(stat, &rsb->stat); /* Clear status bits */
+
+       return ret;
+}
+
+int rsb_set_device_mode(u32 device_mode_data)
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+       unsigned long tmo = timer_get_us() + 1000000;
+
+       writel(RSB_DMCR_DEVICE_MODE_START | device_mode_data, &rsb->dmcr);
+
+       while (readl(&rsb->dmcr) & RSB_DMCR_DEVICE_MODE_START) {
+               if (timer_get_us() > tmo)
+                       return -ETIME;
+       }
+
+       return rsb_await_trans();
+}
+
+static int rsb_do_trans(void)
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+
+       setbits_le32(&rsb->ctrl, RSB_CTRL_START_TRANS);
+       return rsb_await_trans();
+}
+
+int rsb_set_device_address(u16 device_addr, u16 runtime_addr)
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+
+       writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_addr) |
+              RSB_DEVADDR_DEVICE_ADDR(device_addr), &rsb->devaddr);
+       writel(RSB_CMD_SET_RTSADDR, &rsb->cmd);
+
+       return rsb_do_trans();
+}
+
+int rsb_write(const u16 runtime_device_addr, const u8 reg_addr, u8 data)
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+
+       writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_device_addr), &rsb->devaddr);
+       writel(reg_addr, &rsb->addr);
+       writel(data, &rsb->data);
+       writel(RSB_CMD_BYTE_WRITE, &rsb->cmd);
+
+       return rsb_do_trans();
+}
+
+int rsb_read(const u16 runtime_device_addr, const u8 reg_addr, u8 *data)
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+       int ret;
+
+       writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_device_addr), &rsb->devaddr);
+       writel(reg_addr, &rsb->addr);
+       writel(RSB_CMD_BYTE_READ, &rsb->cmd);
+
+       ret = rsb_do_trans();
+       if (ret)
+               return ret;
+
+       *data = readl(&rsb->data) & 0xff;
+
+       return 0;
+}
arch/arm/include/asm/arch-sunxi/cpu.h +0 -0
index 9500262..49c1614 100644

arch/arm/include/asm/arch-sunxi/cpu.h line 132

Quoted 6 lines
arch/arm/include/asm/arch-sunxi/cpu.h +2 -1
@@ -128,7 +128,8 @@
 #define SUN6I_CPUCFG_BASE              0x01f01c00
 #define SUNXI_R_UART_BASE              0x01f02800
 #define SUNXI_R_PIO_BASE               0x01f02c00
-#define SUNXI_P2WI_BASE                        0x01f03400
+#define SUNXI_P2WI_BASE                        0x01f03400      /* on sun6i */
+#define SUNXI_RSB_BASE                 0x01f03400      /* on sun8i */

Maybe we just use SUN6I_ SUN8I_ prefixes?
The base address will be different on sun9i.

Quoted 92 lines
arch/arm/include/asm/arch-sunxi/cpu.h +0 -0
 /* CoreSight Debug Module */
 #define SUNXI_CSDM_BASE                        0x3f500000
arch/arm/include/asm/arch-sunxi/gpio.h +2 -0
index 9f972ce..6623f15 100644
@@ -176,6 +176,8 @@ enum sunxi_gpio_number {
 #define SUN6I_GPL0_R_P2WI_SCK  3
 #define SUN6I_GPL1_R_P2WI_SDA  3
 
+#define SUN8I_GPL0_R_RSB_SCK   2
+#define SUN8I_GPL1_R_RSB_SDA   2
 #define SUN8I_GPL2_R_UART_TX   2
 #define SUN8I_GPL3_R_UART_RX   2
 
arch/arm/include/asm/arch-sunxi/prcm.h +2 -1
index 88de1ff..82ed541 100644
@@ -50,7 +50,8 @@
 #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)
+#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)
arch/arm/include/asm/arch-sunxi/rsb.h new file +55 -1
new file mode 100644
index 0000000..95a595a
@@ -0,0 +1,55 @@
+/*
+ * (C) Copyright 2014 Hans de Goede <[email protected]>
+ *
+ * Based on allwinner u-boot sources rsb code which is:
+ * (C) Copyright 2007-2013
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * lixiang <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __SUNXI_RSB_H
+#define __SUNXI_RSB_H
+
+#include <common.h>
+#include <asm/io.h>
+
+struct sunxi_rsb_reg {
+       u32 ctrl;       /* 0x00 */
+       u32 ccr;        /* 0x04 */
+       u32 inte;       /* 0x08 */
+       u32 stat;       /* 0x0c */
+       u32 addr;       /* 0x10 */
+       u8 res0[8];     /* 0x14 */
+       u32 data;       /* 0x1c */
+       u8 res1[4];     /* 0x20 */
+       u32 lcr;        /* 0x24 */
+       u32 dmcr;       /* 0x28 */
+       u32 cmd;        /* 0x2c */
+       u32 devaddr;    /* 0x30 */
+};
+
+#define RSB_CTRL_SOFT_RST              (1 << 0)
+#define RSB_CTRL_START_TRANS           (1 << 7)
+
+#define RSB_STAT_TOVER_INT             (1 << 0)
+#define RSB_STAT_TERR_INT              (1 << 1)
+#define RSB_STAT_LBSY_INT              (1 << 2)
+
+#define RSB_DMCR_DEVICE_MODE_START     (1 << 31)
+
+#define RSB_CMD_BYTE_WRITE             0x4e
+#define RSB_CMD_BYTE_READ              0x8b
+#define RSB_CMD_SET_RTSADDR            0xe8
+
+#define RSB_DEVADDR_RUNTIME_ADDR(x)    ((x) << 16)
+#define RSB_DEVADDR_DEVICE_ADDR(x)     ((x) << 0)
+
+void rsb_init(void);
+int rsb_set_device_mode(u32 device_mode_data);
+int rsb_set_device_address(u16 device_addr, u16 runtime_addr);
+int rsb_write(const u16 runtime_device_addr, const u8 reg_addr, u8 data);
+int rsb_read(const u16 runtime_device_addr, const u8 reg_addr, u8 *data);
+
+#endif
--
Quoted 1 line

2.1.0

The rest looks good. Thanks!

ChenYu

#3 lore raw

PATCH 2/14 sunxi: Add support for the rsb (Reduced Serial Bus)

Hi,

Quoted 7 lines · Chen-Yu Tsai

Hi,

Quoted 4 lines · Hans de Goede

sun8i (A23) introduces a new bus for communicating with the pmic, the rsb, the rsb is also used to communicate with the pmic on the A80, and is documented in the A80 user manual.

Quoted 6 lines
Quoted 4 lines

This commit adds support for this based on the rsb driver from the allwinner u-boot sources.

Note: Not yet ready for upstream, code needs some significant cleanups.

Confusing note.

Ugh, I forgot to remove that note after doing the cleanups, I'll remove it from the version of the patch my personal tree :)

Quoted 81 lines
Quoted 81 lines
---
  arch/arm/cpu/armv7/sunxi/Makefile      |   1 +
  arch/arm/cpu/armv7/sunxi/rsb.c         | 158 +++++++++++++++++++++++++++++++++
  arch/arm/include/asm/arch-sunxi/cpu.h  |   3 +-
  arch/arm/include/asm/arch-sunxi/gpio.h |   2 +
  arch/arm/include/asm/arch-sunxi/prcm.h |   3 +-
  arch/arm/include/asm/arch-sunxi/rsb.h  |  55 ++++++++++++
  6 files changed, 220 insertions(+), 2 deletions(-)

create mode 100644 arch/arm/cpu/armv7/sunxi/rsb.c create mode 100644 arch/arm/include/asm/arch-sunxi/rsb.h

arch/arm/cpu/armv7/sunxi/Makefile +1 -0
index 1337b60..3e8975a 100644
@@ -15,6 +15,7 @@ obj-y += pinmux.o
  obj-$(CONFIG_MACH_SUN6I)       += prcm.o
  obj-$(CONFIG_MACH_SUN8I)       += prcm.o
  obj-$(CONFIG_MACH_SUN6I)       += p2wi.o
+obj-$(CONFIG_MACH_SUN8I)       += rsb.o
  obj-$(CONFIG_MACH_SUN4I)       += clock_sun4i.o
  obj-$(CONFIG_MACH_SUN5I)       += clock_sun4i.o
  obj-$(CONFIG_MACH_SUN6I)       += clock_sun6i.o
arch/arm/cpu/armv7/sunxi/rsb.c new file +49 -0
new file mode 100644
index 0000000..b72bb9d
@@ -0,0 +1,158 @@
+/*
+ * (C) Copyright 2014 Hans de Goede <[email protected]>
+ *
+ * Based on allwinner u-boot sources rsb code which is:
+ * (C) Copyright 2007-2013
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * lixiang <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/prcm.h>
+#include <asm/arch/rsb.h>
+
+static void rsb_cfg_io(void)
+{
+       sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_GPL0_R_RSB_SCK);
+       sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN8I_GPL1_R_RSB_SDA);
+       sunxi_gpio_set_pull(SUNXI_GPL(0), 1);
+       sunxi_gpio_set_pull(SUNXI_GPL(1), 1);
+       sunxi_gpio_set_drv(SUNXI_GPL(0), 2);
+       sunxi_gpio_set_drv(SUNXI_GPL(1), 2);
+}
+
+static void rsb_set_clk(void)
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+       u32 div = 0;
+       u32 cd_odly = 0;
+
+       /* Source is Hosc24M, set RSB clk to 3Mhz */
+       div = 24000000 / 3000000 / 2 - 1;
+       cd_odly = div >> 1;
+       if (!cd_odly)
+               cd_odly = 1;
+
+       writel((cd_odly << 8) | div, &rsb->ccr);
+}
+
+void rsb_init(void)
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+
Quoted 8 lines

arch/arm/cpu/armv7/sunxi/rsb.c line 55

Quoted 6 lines
arch/arm/cpu/armv7/sunxi/rsb.c new file +6 -0
+       rsb_cfg_io();
+
+       /* Enable RSB and PIO clk, and de-assert their resets */
+       prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_RSB);
+
+       writel(RSB_CTRL_SOFT_RST, &rsb->ctrl);

Do we need a small delay here for the device to finish reset?

Maybe, this (no delay) is what the allwinner code was doing, and it seems to work fine ...

Quoted 206 lines
Quoted 109 lines
arch/arm/cpu/armv7/sunxi/rsb.c new file +103 -0
+       rsb_set_clk();
+}
+
+static int rsb_await_trans(void)
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+       unsigned long tmo = timer_get_us() + 1000000;
+       u32 stat;
+       int ret;
+
+       while (1) {
+               stat = readl(&rsb->stat);
+               if (stat & RSB_STAT_LBSY_INT) {
+                       ret = -EBUSY;
+                       break;
+               }
+               if (stat & RSB_STAT_TERR_INT) {
+                       ret = -EIO;
+                       break;
+               }
+               if (stat & RSB_STAT_TOVER_INT) {
+                       ret = 0;
+                       break;
+               }
+               if (timer_get_us() > tmo) {
+                       ret = -ETIME;
+                       break;
+               }
+       }
+       writel(stat, &rsb->stat); /* Clear status bits */
+
+       return ret;
+}
+
+int rsb_set_device_mode(u32 device_mode_data)
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+       unsigned long tmo = timer_get_us() + 1000000;
+
+       writel(RSB_DMCR_DEVICE_MODE_START | device_mode_data, &rsb->dmcr);
+
+       while (readl(&rsb->dmcr) & RSB_DMCR_DEVICE_MODE_START) {
+               if (timer_get_us() > tmo)
+                       return -ETIME;
+       }
+
+       return rsb_await_trans();
+}
+
+static int rsb_do_trans(void)
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+
+       setbits_le32(&rsb->ctrl, RSB_CTRL_START_TRANS);
+       return rsb_await_trans();
+}
+
+int rsb_set_device_address(u16 device_addr, u16 runtime_addr)
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+
+       writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_addr) |
+              RSB_DEVADDR_DEVICE_ADDR(device_addr), &rsb->devaddr);
+       writel(RSB_CMD_SET_RTSADDR, &rsb->cmd);
+
+       return rsb_do_trans();
+}
+
+int rsb_write(const u16 runtime_device_addr, const u8 reg_addr, u8 data)
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+
+       writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_device_addr), &rsb->devaddr);
+       writel(reg_addr, &rsb->addr);
+       writel(data, &rsb->data);
+       writel(RSB_CMD_BYTE_WRITE, &rsb->cmd);
+
+       return rsb_do_trans();
+}
+
+int rsb_read(const u16 runtime_device_addr, const u8 reg_addr, u8 *data)
+{
+       struct sunxi_rsb_reg * const rsb =
+               (struct sunxi_rsb_reg *)SUNXI_RSB_BASE;
+       int ret;
+
+       writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_device_addr), &rsb->devaddr);
+       writel(reg_addr, &rsb->addr);
+       writel(RSB_CMD_BYTE_READ, &rsb->cmd);
+
+       ret = rsb_do_trans();
+       if (ret)
+               return ret;
+
+       *data = readl(&rsb->data) & 0xff;
+
+       return 0;
+}
arch/arm/include/asm/arch-sunxi/cpu.h +0 -0
index 9500262..49c1614 100644

arch/arm/include/asm/arch-sunxi/cpu.h line 132

Quoted 6 lines
arch/arm/include/asm/arch-sunxi/cpu.h +2 -1
@@ -128,7 +128,8 @@
  #define SUN6I_CPUCFG_BASE              0x01f01c00
  #define SUNXI_R_UART_BASE              0x01f02800
  #define SUNXI_R_PIO_BASE               0x01f02c00
-#define SUNXI_P2WI_BASE                        0x01f03400
+#define SUNXI_P2WI_BASE                        0x01f03400      /* on sun6i */
+#define SUNXI_RSB_BASE                 0x01f03400      /* on sun8i */

Maybe we just use SUN6I_ SUN8I_ prefixes?
The base address will be different on sun9i.

Quoted 87 lines
arch/arm/include/asm/arch-sunxi/cpu.h +0 -0
  /* CoreSight Debug Module */
  #define SUNXI_CSDM_BASE                        0x3f500000
arch/arm/include/asm/arch-sunxi/gpio.h +2 -0
index 9f972ce..6623f15 100644
@@ -176,6 +176,8 @@ enum sunxi_gpio_number {
  #define SUN6I_GPL0_R_P2WI_SCK  3
  #define SUN6I_GPL1_R_P2WI_SDA  3
 
+#define SUN8I_GPL0_R_RSB_SCK   2
+#define SUN8I_GPL1_R_RSB_SDA   2
  #define SUN8I_GPL2_R_UART_TX   2
  #define SUN8I_GPL3_R_UART_RX   2
 
arch/arm/include/asm/arch-sunxi/prcm.h +2 -1
index 88de1ff..82ed541 100644
@@ -50,7 +50,8 @@
  #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)
+#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)
arch/arm/include/asm/arch-sunxi/rsb.h new file +51 -0
new file mode 100644
index 0000000..95a595a
@@ -0,0 +1,55 @@
+/*
+ * (C) Copyright 2014 Hans de Goede <[email protected]>
+ *
+ * Based on allwinner u-boot sources rsb code which is:
+ * (C) Copyright 2007-2013
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * lixiang <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __SUNXI_RSB_H
+#define __SUNXI_RSB_H
+
+#include <common.h>
+#include <asm/io.h>
+
+struct sunxi_rsb_reg {
+       u32 ctrl;       /* 0x00 */
+       u32 ccr;        /* 0x04 */
+       u32 inte;       /* 0x08 */
+       u32 stat;       /* 0x0c */
+       u32 addr;       /* 0x10 */
+       u8 res0[8];     /* 0x14 */
+       u32 data;       /* 0x1c */
+       u8 res1[4];     /* 0x20 */
+       u32 lcr;        /* 0x24 */
+       u32 dmcr;       /* 0x28 */
+       u32 cmd;        /* 0x2c */
+       u32 devaddr;    /* 0x30 */
+};
+
+#define RSB_CTRL_SOFT_RST              (1 << 0)
+#define RSB_CTRL_START_TRANS           (1 << 7)
+
+#define RSB_STAT_TOVER_INT             (1 << 0)
+#define RSB_STAT_TERR_INT              (1 << 1)
+#define RSB_STAT_LBSY_INT              (1 << 2)
+
+#define RSB_DMCR_DEVICE_MODE_START     (1 << 31)
+
+#define RSB_CMD_BYTE_WRITE             0x4e
+#define RSB_CMD_BYTE_READ              0x8b
+#define RSB_CMD_SET_RTSADDR            0xe8
+
+#define RSB_DEVADDR_RUNTIME_ADDR(x)    ((x) << 16)
+#define RSB_DEVADDR_DEVICE_ADDR(x)     ((x) << 0)
+
+void rsb_init(void);
+int rsb_set_device_mode(u32 device_mode_data);
+int rsb_set_device_address(u16 device_addr, u16 runtime_addr);
Quoted 8 lines
Quoted 6 lines
arch/arm/include/asm/arch-sunxi/rsb.h new file +4 -1
+int rsb_write(const u16 runtime_device_addr, const u8 reg_addr, u8 data);
+int rsb_read(const u16 runtime_device_addr, const u8 reg_addr, u8 *data);
+
+#endif
--

2.1.0

The rest looks good. Thanks!

Regards,

Hans

#4 lore raw

PATCH 2/14 sunxi: Add support for the rsb (Reduced Serial Bus)

Quoted 13 lines · Hans de Goede

Hi,

Quoted 10 lines · Chen-Yu Tsai

Hi,

Quoted 7 lines · Hans de Goede

sun8i (A23) introduces a new bus for communicating with the pmic, the rsb, the rsb is also used to communicate with the pmic on the A80, and is documented in the A80 user manual.

This commit adds support for this based on the rsb driver from the allwinner u-boot sources.

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

Note: Not yet ready for upstream, code needs some significant cleanups.

Confusing note.

Ugh, I forgot to remove that note after doing the cleanups, I'll remove it from the version of the patch my personal tree :)

I'll stop ignoring this patch then ;-)

Ian.

#5 lore raw

PATCH 2/14 sunxi: Add support for the rsb (Reduced Serial Bus)

In reply to Hans de Goede
Quoted 10 lines · Hans de Goede
Quoted 10 lines

arch/arm/include/asm/arch-sunxi/cpu.h line 132

Quoted 7 lines
arch/arm/include/asm/arch-sunxi/cpu.h +2 -1
@@ -128,7 +128,8 @@
  #define SUN6I_CPUCFG_BASE              0x01f01c00
  #define SUNXI_R_UART_BASE              0x01f02800
  #define SUNXI_R_PIO_BASE               0x01f02c00
-#define SUNXI_P2WI_BASE                        0x01f03400
+#define SUNXI_P2WI_BASE                        0x01f03400      /* on sun6i */
+#define SUNXI_RSB_BASE                 0x01f03400      /* on sun8i */

Maybe we just use SUN6I_ SUN8I_ prefixes?
The base address will be different on sun9i.

Did you miss this suggestions from Chen-Yu? Seems like a good one.

I don't have any other comments.

Ian.

#6 lore raw

PATCH 2/14 sunxi: Add support for the rsb (Reduced Serial Bus)

Hi,

Quoted 12 lines · Ian Campbell
Quoted 10 lines · Hans de Goede
Quoted 10 lines

arch/arm/include/asm/arch-sunxi/cpu.h line 132

Quoted 7 lines
arch/arm/include/asm/arch-sunxi/cpu.h +2 -1
@@ -128,7 +128,8 @@
   #define SUN6I_CPUCFG_BASE              0x01f01c00
   #define SUNXI_R_UART_BASE              0x01f02800
   #define SUNXI_R_PIO_BASE               0x01f02c00
-#define SUNXI_P2WI_BASE                        0x01f03400
+#define SUNXI_P2WI_BASE                        0x01f03400      /* on sun6i */
+#define SUNXI_RSB_BASE                 0x01f03400      /* on sun8i */

Maybe we just use SUN6I_ SUN8I_ prefixes?
The base address will be different on sun9i.

Quoted 1 line

Did you miss this suggestions from Chen-Yu? Seems like a good one.

Yes I missed that (must have read over it). That will work for P2Wi, but not for RSB, as RSB is used on the A80 too AFAIK, but I guess having P2WI as SUN6I and RSB as SUNXI makes it clear what is used where, so I'll update the patch with that change.

Regards,

Hans

#7 lore raw

PATCH 3/14 sunxi: axp221: Add axp223 support

In reply to Hans de Goede

The axp223 appears to be the same as the axp221, except that it uses the rsb to communicate rather then the p2wi. At least all the registers we use are 100% the same.

---
 arch/arm/cpu/armv7/sunxi/cpu_info.c |  2 +-
 drivers/power/Kconfig               |  8 ++--
 drivers/power/axp221.c              | 88 ++++++++++++++++++++++++++++---------
 include/axp221.h                    |  4 ++
 4 files changed, 76 insertions(+), 26 deletions(-)
arch/arm/cpu/armv7/sunxi/cpu_info.c +1 -1
index 7a3a4ca..b6cb9de 100644
@@ -76,7 +76,7 @@ int print_cpuinfo(void)
 
 int sunxi_get_sid(unsigned int *sid)
 {
-#ifdef CONFIG_MACH_SUN6I
+#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
 #ifdef CONFIG_AXP221_POWER
 	return axp221_get_sid(sid);
 #else
drivers/power/Kconfig +4 -4
index 1ec7c0e..7373a79 100644
@@ -1,10 +1,10 @@
 config AXP221_POWER
-	boolean "axp221 pmic support"
-	depends on MACH_SUN6I
+	boolean "axp221 / axp223 pmic support"
+	depends on MACH_SUN6I || MACH_SUN8I
 	default y
 	---help---
-	Say y here to enable support for the axp221 pmic found on most sun6i
-	(A31) boards.
+	Say y here to enable support for the axp221 / axp223 pmic found on most
+	sun6i (A31) / sun8i (A23) boards.
 
 config AXP221_DLDO1_VOLT
 	int "axp221 dldo1 voltage"
drivers/power/axp221.c +67 -21

205 lines not on this page · raw message

include/axp221.h +4 -0
index db219c6..10d35e1 100644
@@ -10,6 +10,10 @@
 #define AXP221_CTRL_ADDR 0x3e
 #define AXP221_INIT_DATA 0x3e
 
+#define AXP223_DEVICE_ADDR 0x3a3
+#define AXP223_RUNTIME_ADDR 0x2d
+#define AXP223_DEVICE_MODE_DATA 0x7c3e00
+
 /* Page 0 addresses */
 #define AXP221_CHIP_ID		0x03
 #define AXP221_OUTPUT_CTRL1	0x10
Signature · 1 line
2.1.0
#8 lore raw

PATCH 3/14 sunxi: axp221: Add axp223 support

Quoted 283 lines · Hans de Goede

The axp223 appears to be the same as the axp221, except that it uses the rsb to communicate rather then the p2wi. At least all the registers we use are 100% the same.

---
 arch/arm/cpu/armv7/sunxi/cpu_info.c |  2 +-
 drivers/power/Kconfig               |  8 ++--
 drivers/power/axp221.c              | 88 ++++++++++++++++++++++++++++---------
 include/axp221.h                    |  4 ++
 4 files changed, 76 insertions(+), 26 deletions(-)
arch/arm/cpu/armv7/sunxi/cpu_info.c +1 -1
index 7a3a4ca..b6cb9de 100644
@@ -76,7 +76,7 @@ int print_cpuinfo(void)
 
 int sunxi_get_sid(unsigned int *sid)
 {
-#ifdef CONFIG_MACH_SUN6I
+#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
 #ifdef CONFIG_AXP221_POWER
        return axp221_get_sid(sid);
 #else
drivers/power/Kconfig +4 -4
index 1ec7c0e..7373a79 100644
@@ -1,10 +1,10 @@
 config AXP221_POWER
-       boolean "axp221 pmic support"
-       depends on MACH_SUN6I
+       boolean "axp221 / axp223 pmic support"
+       depends on MACH_SUN6I || MACH_SUN8I
        default y
        ---help---
-       Say y here to enable support for the axp221 pmic found on most sun6i
-       (A31) boards.
+       Say y here to enable support for the axp221 / axp223 pmic found on most
+       sun6i (A31) / sun8i (A23) boards.
 
 config AXP221_DLDO1_VOLT
        int "axp221 dldo1 voltage"
drivers/power/axp221.c +67 -21
index 826567a..717adad 100644
@@ -1,4 +1,10 @@
 /*
+ * AXP221 and AXP223 driver
+ *
+ * IMPORTANT when making changes to this file check that the registers
+ * used are the same for the axp221 and axp223.
+ *
+ * (C) Copyright 2014 Hans de Goede <[email protected]>
  * (C) Copyright 2013 Oliver Schinagl <[email protected]>
  *
  * SPDX-License-Identifier:    GPL-2.0+
@@ -7,8 +13,50 @@
 #include <common.h>
 #include <errno.h>
 #include <asm/arch/p2wi.h>
+#include <asm/arch/rsb.h>
 #include <axp221.h>
 
+/*
+ * The axp221 uses the p2wi bus, the axp223 is identical (for all registers
+ * used sofar) but uses the rsb bus. These functions abstract this.
+ */
+static int pmic_bus_init(void)
+{
+#ifdef CONFIG_MACH_SUN6I
+       p2wi_init();
+       return p2wi_change_to_p2wi_mode(AXP221_CHIP_ADDR, AXP221_CTRL_ADDR,
+                                       AXP221_INIT_DATA);
+#else
+       int ret;
+
+       rsb_init();
+
+       ret = rsb_set_device_mode(AXP223_DEVICE_MODE_DATA);
+       if (ret)
+               return ret;
+
+       return rsb_set_device_address(AXP223_DEVICE_ADDR, AXP223_RUNTIME_ADDR);
+#endif
+}
+
+static int pmic_bus_read(const u8 addr, u8 *data)
+{
+#ifdef CONFIG_MACH_SUN6I
+       return p2wi_read(addr, data);
+#else
+       return rsb_read(AXP223_RUNTIME_ADDR, addr, data);
+#endif
+}
+
+static int pmic_bus_write(const u8 addr, u8 data)
+{
+#ifdef CONFIG_MACH_SUN6I
+       return p2wi_write(addr, data);
+#else
+       return rsb_write(AXP223_RUNTIME_ADDR, addr, data);
+#endif
+}
+
 static u8 axp221_mvolt_to_cfg(int mvolt, int min, int max, int div)
 {
        if (mvolt < min)
@@ -24,12 +72,12 @@ static int axp221_setbits(u8 reg, u8 bits)
        int ret;
        u8 val;
 
-       ret = p2wi_read(reg, &val);
+       ret = pmic_bus_read(reg, &val);
        if (ret)
                return ret;
 
        val |= bits;
-       return p2wi_write(reg, val);
+       return pmic_bus_write(reg, val);
 }
 
 int axp221_set_dcdc1(unsigned int mvolt)
@@ -37,7 +85,7 @@ int axp221_set_dcdc1(unsigned int mvolt)
        int ret;
        u8 cfg = axp221_mvolt_to_cfg(mvolt, 1600, 3400, 100);
 
-       ret = p2wi_write(AXP221_DCDC1_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_DCDC1_CTRL, cfg);
        if (ret)
                return ret;
 
@@ -49,28 +97,28 @@ int axp221_set_dcdc2(unsigned int mvolt)
 {
        u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
 
-       return p2wi_write(AXP221_DCDC2_CTRL, cfg);
+       return pmic_bus_write(AXP221_DCDC2_CTRL, cfg);
 }
 
 int axp221_set_dcdc3(unsigned int mvolt)
 {
        u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1860, 20);
 
-       return p2wi_write(AXP221_DCDC3_CTRL, cfg);
+       return pmic_bus_write(AXP221_DCDC3_CTRL, cfg);
 }
 
 int axp221_set_dcdc4(unsigned int mvolt)
 {
        u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
 
-       return p2wi_write(AXP221_DCDC4_CTRL, cfg);
+       return pmic_bus_write(AXP221_DCDC4_CTRL, cfg);
 }
 
 int axp221_set_dcdc5(unsigned int mvolt)
 {
        u8 cfg = axp221_mvolt_to_cfg(mvolt, 1000, 2550, 50);
 
-       return p2wi_write(AXP221_DCDC5_CTRL, cfg);
+       return pmic_bus_write(AXP221_DCDC5_CTRL, cfg);
 }
 
 int axp221_set_dldo1(unsigned int mvolt)
@@ -78,7 +126,7 @@ int axp221_set_dldo1(unsigned int mvolt)
        int ret;
        u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 
-       ret = p2wi_write(AXP221_DLDO1_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_DLDO1_CTRL, cfg);
        if (ret)
                return ret;
 
@@ -91,7 +139,7 @@ int axp221_set_dldo2(unsigned int mvolt)
        int ret;
        u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 
-       ret = p2wi_write(AXP221_DLDO2_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_DLDO2_CTRL, cfg);
        if (ret)
                return ret;
 
@@ -104,7 +152,7 @@ int axp221_set_dldo3(unsigned int mvolt)
        int ret;
        u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 
-       ret = p2wi_write(AXP221_DLDO3_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_DLDO3_CTRL, cfg);
        if (ret)
                return ret;
 
@@ -117,7 +165,7 @@ int axp221_set_dldo4(unsigned int mvolt)
        int ret;
        u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 
-       ret = p2wi_write(AXP221_DLDO4_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_DLDO4_CTRL, cfg);
        if (ret)
                return ret;
 
@@ -130,7 +178,7 @@ int axp221_set_aldo1(unsigned int mvolt)
        int ret;
        u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 
-       ret = p2wi_write(AXP221_ALDO1_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_ALDO1_CTRL, cfg);
        if (ret)
                return ret;
 
@@ -143,7 +191,7 @@ int axp221_set_aldo2(unsigned int mvolt)
        int ret;
        u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 
-       ret = p2wi_write(AXP221_ALDO2_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_ALDO2_CTRL, cfg);
        if (ret)
                return ret;
 
@@ -156,7 +204,7 @@ int axp221_set_aldo3(unsigned int mvolt)
        int ret;
        u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 
-       ret = p2wi_write(AXP221_ALDO3_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_ALDO3_CTRL, cfg);
        if (ret)
                return ret;
 
@@ -169,13 +217,11 @@ int axp221_init(void)
        u8 axp_chip_id;
        int ret;
 
-       p2wi_init();
-       ret = p2wi_change_to_p2wi_mode(AXP221_CHIP_ADDR, AXP221_CTRL_ADDR,
-                                      AXP221_INIT_DATA);
+       ret = pmic_bus_init();
        if (ret)
                return ret;
 
-       ret = p2wi_read(AXP221_CHIP_ID, &axp_chip_id);
+       ret = pmic_bus_read(AXP221_CHIP_ID, &axp_chip_id);
        if (ret)
                return ret;
 
@@ -194,17 +240,17 @@ int axp221_get_sid(unsigned int *sid)
        if (ret)
                return ret;
 
-       ret = p2wi_write(AXP221_PAGE, 1);
+       ret = pmic_bus_write(AXP221_PAGE, 1);
        if (ret)
                return ret;
 
        for (i = 0; i < 16; i++) {
-               ret = p2wi_read(AXP221_SID + i, &dest[i]);
+               ret = pmic_bus_read(AXP221_SID + i, &dest[i]);
                if (ret)
                        return ret;
        }
 
-       p2wi_write(AXP221_PAGE, 0);
+       pmic_bus_write(AXP221_PAGE, 0);
 
        for (i = 0; i < 4; i++)
                sid[i] = be32_to_cpu(sid[i]);
include/axp221.h +4 -1
index db219c6..10d35e1 100644
@@ -10,6 +10,10 @@
 #define AXP221_CTRL_ADDR 0x3e
 #define AXP221_INIT_DATA 0x3e
 
+#define AXP223_DEVICE_ADDR 0x3a3
+#define AXP223_RUNTIME_ADDR 0x2d
+#define AXP223_DEVICE_MODE_DATA 0x7c3e00
+
 /* Page 0 addresses */
 #define AXP221_CHIP_ID         0x03
 #define AXP221_OUTPUT_CTRL1    0x10
--
Quoted 2 lines

2.1.0

git am reports:

Applying patch #422068 using 'git am'
Description: [U-Boot,03/14] sunxi: axp221: Add axp223 support
Applying: sunxi: axp221: Add axp223 support /home/wens/sunxi/u-boot/.git/rebase-apply/patch:50: trailing whitespace.
*
/home/wens/sunxi/u-boot/.git/rebase-apply/patch:76: trailing whitespace.

warning: 2 lines add whitespace errors.

ChenYu

#9 lore raw

PATCH 3/14 sunxi: axp221: Add axp223 support

Hi,

Quoted 289 lines · Chen-Yu Tsai
Quoted 283 lines · Hans de Goede

The axp223 appears to be the same as the axp221, except that it uses the rsb to communicate rather then the p2wi. At least all the registers we use are 100% the same.

---
  arch/arm/cpu/armv7/sunxi/cpu_info.c |  2 +-
  drivers/power/Kconfig               |  8 ++--
  drivers/power/axp221.c              | 88 ++++++++++++++++++++++++++++---------
  include/axp221.h                    |  4 ++
  4 files changed, 76 insertions(+), 26 deletions(-)
arch/arm/cpu/armv7/sunxi/cpu_info.c +1 -1
index 7a3a4ca..b6cb9de 100644
@@ -76,7 +76,7 @@ int print_cpuinfo(void)
 
  int sunxi_get_sid(unsigned int *sid)
  {
-#ifdef CONFIG_MACH_SUN6I
+#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
  #ifdef CONFIG_AXP221_POWER
         return axp221_get_sid(sid);
  #else
drivers/power/Kconfig +4 -4
index 1ec7c0e..7373a79 100644
@@ -1,10 +1,10 @@
  config AXP221_POWER
-       boolean "axp221 pmic support"
-       depends on MACH_SUN6I
+       boolean "axp221 / axp223 pmic support"
+       depends on MACH_SUN6I || MACH_SUN8I
         default y
         ---help---
-       Say y here to enable support for the axp221 pmic found on most sun6i
-       (A31) boards.
+       Say y here to enable support for the axp221 / axp223 pmic found on most
+       sun6i (A31) / sun8i (A23) boards.
 
  config AXP221_DLDO1_VOLT
         int "axp221 dldo1 voltage"
drivers/power/axp221.c +67 -21
index 826567a..717adad 100644
@@ -1,4 +1,10 @@
  /*
+ * AXP221 and AXP223 driver
+ *
+ * IMPORTANT when making changes to this file check that the registers
+ * used are the same for the axp221 and axp223.
+ *
+ * (C) Copyright 2014 Hans de Goede <[email protected]>
   * (C) Copyright 2013 Oliver Schinagl <[email protected]>
   *
   * SPDX-License-Identifier:    GPL-2.0+
@@ -7,8 +13,50 @@
  #include <common.h>
  #include <errno.h>
  #include <asm/arch/p2wi.h>
+#include <asm/arch/rsb.h>
  #include <axp221.h>
 
+/*
+ * The axp221 uses the p2wi bus, the axp223 is identical (for all registers
+ * used sofar) but uses the rsb bus. These functions abstract this.
+ */
+static int pmic_bus_init(void)
+{
+#ifdef CONFIG_MACH_SUN6I
+       p2wi_init();
+       return p2wi_change_to_p2wi_mode(AXP221_CHIP_ADDR, AXP221_CTRL_ADDR,
+                                       AXP221_INIT_DATA);
+#else
+       int ret;
+
+       rsb_init();
+
+       ret = rsb_set_device_mode(AXP223_DEVICE_MODE_DATA);
+       if (ret)
+               return ret;
+
+       return rsb_set_device_address(AXP223_DEVICE_ADDR, AXP223_RUNTIME_ADDR);
+#endif
+}
+
+static int pmic_bus_read(const u8 addr, u8 *data)
+{
+#ifdef CONFIG_MACH_SUN6I
+       return p2wi_read(addr, data);
+#else
+       return rsb_read(AXP223_RUNTIME_ADDR, addr, data);
+#endif
+}
+
+static int pmic_bus_write(const u8 addr, u8 data)
+{
+#ifdef CONFIG_MACH_SUN6I
+       return p2wi_write(addr, data);
+#else
+       return rsb_write(AXP223_RUNTIME_ADDR, addr, data);
+#endif
+}
+
  static u8 axp221_mvolt_to_cfg(int mvolt, int min, int max, int div)
  {
         if (mvolt < min)
@@ -24,12 +72,12 @@ static int axp221_setbits(u8 reg, u8 bits)
         int ret;
         u8 val;
 
-       ret = p2wi_read(reg, &val);
+       ret = pmic_bus_read(reg, &val);
         if (ret)
                 return ret;
 
         val |= bits;
-       return p2wi_write(reg, val);
+       return pmic_bus_write(reg, val);
  }
 
  int axp221_set_dcdc1(unsigned int mvolt)
@@ -37,7 +85,7 @@ int axp221_set_dcdc1(unsigned int mvolt)
         int ret;
         u8 cfg = axp221_mvolt_to_cfg(mvolt, 1600, 3400, 100);
 
-       ret = p2wi_write(AXP221_DCDC1_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_DCDC1_CTRL, cfg);
         if (ret)
                 return ret;
 
@@ -49,28 +97,28 @@ int axp221_set_dcdc2(unsigned int mvolt)
  {
         u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
 
-       return p2wi_write(AXP221_DCDC2_CTRL, cfg);
+       return pmic_bus_write(AXP221_DCDC2_CTRL, cfg);
  }
 
  int axp221_set_dcdc3(unsigned int mvolt)
  {
         u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1860, 20);
 
-       return p2wi_write(AXP221_DCDC3_CTRL, cfg);
+       return pmic_bus_write(AXP221_DCDC3_CTRL, cfg);
  }
 
  int axp221_set_dcdc4(unsigned int mvolt)
  {
         u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
 
-       return p2wi_write(AXP221_DCDC4_CTRL, cfg);
+       return pmic_bus_write(AXP221_DCDC4_CTRL, cfg);
  }
 
  int axp221_set_dcdc5(unsigned int mvolt)
  {
         u8 cfg = axp221_mvolt_to_cfg(mvolt, 1000, 2550, 50);
 
-       return p2wi_write(AXP221_DCDC5_CTRL, cfg);
+       return pmic_bus_write(AXP221_DCDC5_CTRL, cfg);
  }
 
  int axp221_set_dldo1(unsigned int mvolt)
@@ -78,7 +126,7 @@ int axp221_set_dldo1(unsigned int mvolt)
         int ret;
         u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 
-       ret = p2wi_write(AXP221_DLDO1_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_DLDO1_CTRL, cfg);
         if (ret)
                 return ret;
 
@@ -91,7 +139,7 @@ int axp221_set_dldo2(unsigned int mvolt)
         int ret;
         u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 
-       ret = p2wi_write(AXP221_DLDO2_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_DLDO2_CTRL, cfg);
         if (ret)
                 return ret;
 
@@ -104,7 +152,7 @@ int axp221_set_dldo3(unsigned int mvolt)
         int ret;
         u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 
-       ret = p2wi_write(AXP221_DLDO3_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_DLDO3_CTRL, cfg);
         if (ret)
                 return ret;
 
@@ -117,7 +165,7 @@ int axp221_set_dldo4(unsigned int mvolt)
         int ret;
         u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 
-       ret = p2wi_write(AXP221_DLDO4_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_DLDO4_CTRL, cfg);
         if (ret)
                 return ret;
 
@@ -130,7 +178,7 @@ int axp221_set_aldo1(unsigned int mvolt)
         int ret;
         u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 
-       ret = p2wi_write(AXP221_ALDO1_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_ALDO1_CTRL, cfg);
         if (ret)
                 return ret;
 
@@ -143,7 +191,7 @@ int axp221_set_aldo2(unsigned int mvolt)
         int ret;
         u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 
-       ret = p2wi_write(AXP221_ALDO2_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_ALDO2_CTRL, cfg);
         if (ret)
                 return ret;
 
@@ -156,7 +204,7 @@ int axp221_set_aldo3(unsigned int mvolt)
         int ret;
         u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 
-       ret = p2wi_write(AXP221_ALDO3_CTRL, cfg);
+       ret = pmic_bus_write(AXP221_ALDO3_CTRL, cfg);
         if (ret)
                 return ret;
 
@@ -169,13 +217,11 @@ int axp221_init(void)
         u8 axp_chip_id;
         int ret;
 
-       p2wi_init();
-       ret = p2wi_change_to_p2wi_mode(AXP221_CHIP_ADDR, AXP221_CTRL_ADDR,
-                                      AXP221_INIT_DATA);
+       ret = pmic_bus_init();
         if (ret)
                 return ret;
 
-       ret = p2wi_read(AXP221_CHIP_ID, &axp_chip_id);
+       ret = pmic_bus_read(AXP221_CHIP_ID, &axp_chip_id);
         if (ret)
                 return ret;
 
@@ -194,17 +240,17 @@ int axp221_get_sid(unsigned int *sid)
         if (ret)
                 return ret;
 
-       ret = p2wi_write(AXP221_PAGE, 1);
+       ret = pmic_bus_write(AXP221_PAGE, 1);
         if (ret)
                 return ret;
 
         for (i = 0; i < 16; i++) {
-               ret = p2wi_read(AXP221_SID + i, &dest[i]);
+               ret = pmic_bus_read(AXP221_SID + i, &dest[i]);
                 if (ret)
                         return ret;
         }
 
-       p2wi_write(AXP221_PAGE, 0);
+       pmic_bus_write(AXP221_PAGE, 0);
 
         for (i = 0; i < 4; i++)
                 sid[i] = be32_to_cpu(sid[i]);
include/axp221.h +4 -1
index db219c6..10d35e1 100644
@@ -10,6 +10,10 @@
  #define AXP221_CTRL_ADDR 0x3e
  #define AXP221_INIT_DATA 0x3e
 
+#define AXP223_DEVICE_ADDR 0x3a3
+#define AXP223_RUNTIME_ADDR 0x2d
+#define AXP223_DEVICE_MODE_DATA 0x7c3e00
+
  /* Page 0 addresses */
  #define AXP221_CHIP_ID         0x03
  #define AXP221_OUTPUT_CTRL1    0x10
--
Quoted 2 lines

2.1.0

git am reports:

Quoted 8 lines

Applying patch #422068 using 'git am'
Description: [U-Boot,03/14] sunxi: axp221: Add axp223 support
Applying: sunxi: axp221: Add axp223 support /home/wens/sunxi/u-boot/.git/rebase-apply/patch:50: trailing whitespace.
*
/home/wens/sunxi/u-boot/.git/rebase-apply/patch:76: trailing whitespace.

warning: 2 lines add whitespace errors.

Fixed in my personal tree.

Regards,

Hans

#11 lore raw

PATCH 4/14 sunxi: axp221: Add Kconfig help and sane defaults for typical ldo usage

In reply to Hans de Goede

Some of the ldo-s of the axp221 are used in the same way on most boards, add comments to the Kconfig help text to reflect this, and give them defaults matching their typical usage.

---
 configs/CSQ_CS908_defconfig       |  3 ---
 configs/Colombus_defconfig        |  3 ---
 configs/Hummingbird_A31_defconfig |  4 ----
 configs/Mele_M9_defconfig         |  3 ---
 drivers/power/Kconfig             | 20 ++++++++++++++------
 5 files changed, 14 insertions(+), 19 deletions(-)
configs/CSQ_CS908_defconfig +0 -3
index 4c9cff6..1b6cdbf 100644
@@ -11,9 +11,6 @@ CONFIG_FDTFILE="sun6i-a31s-cs908.dtb"
 +S:CONFIG_AXP221_DLDO1_VOLT=3300
 # Wifi power
 +S:CONFIG_AXP221_ALDO1_VOLT=3300
-# HDMI power ?
-+S:CONFIG_AXP221_ALDO2_VOLT=1800
-+S:CONFIG_AXP221_ALDO3_VOLT=3000
 # No Vbus gpio for either usb
 +S:CONFIG_USB1_VBUS_PIN=""
 +S:CONFIG_USB2_VBUS_PIN=""
configs/Colombus_defconfig +0 -3
index b8c5400..f42ae52 100644
@@ -9,8 +9,5 @@ CONFIG_FDTFILE="sun6i-a31-colombus.dtb"
 +S:CONFIG_DRAM_ZQ=251
 # Wifi power
 +S:CONFIG_AXP221_ALDO1_VOLT=3300
-# HDMI power ?
-+S:CONFIG_AXP221_ALDO2_VOLT=1800
-+S:CONFIG_AXP221_ALDO3_VOLT=3000
 # No Vbus gpio for usb1
 +S:CONFIG_USB1_VBUS_PIN=""
configs/Hummingbird_A31_defconfig +0 -4
index 73855c5..7f59a0d 100644
@@ -9,10 +9,6 @@ CONFIG_FDTFILE="sun6i-a31-hummingbird.dtb"
 +S:CONFIG_DRAM_ZQ=251
 # Wifi power
 +S:CONFIG_AXP221_ALDO1_VOLT=3300
-# PM-CPUS GPIO power
-+S:CONFIG_AXP221_ALDO2_VOLT=1800
-# SoC IR, PLL and Analog power (must be 3.0V)
-+S:CONFIG_AXP221_ALDO3_VOLT=3000
 # Vbus gpio for usb1
 +S:CONFIG_USB1_VBUS_PIN="PH24"
 # No Vbus gpio for usb2
configs/Mele_M9_defconfig +0 -3
index a598254..445cc57 100644
@@ -13,9 +13,6 @@ CONFIG_FDTFILE="sun6i-a31-m9.dtb"
 +S:CONFIG_AXP221_DLDO4_VOLT=3300
 # Wifi power
 +S:CONFIG_AXP221_ALDO1_VOLT=3300
-# HDMI power ?
-+S:CONFIG_AXP221_ALDO2_VOLT=1800
-+S:CONFIG_AXP221_ALDO3_VOLT=3000
 # Vbus gpio for usb1
 +S:CONFIG_USB1_VBUS_PIN="PC27"
 # No Vbus gpio for usb2
drivers/power/Kconfig +14 -6
index 7373a79..af66887 100644
@@ -12,7 +12,9 @@ config AXP221_DLDO1_VOLT
 	default -1
 	---help---
 	Set the voltage (mV) to program the axp221 dldo1 at, set to -1 to
-	disable dldo1.
+	disable dldo1. On sun6i (A31) boards with ethernet this is often used
+	to power the ethernet phy. On sun8i (A23) boards this is often used to
+	power the wifi.
 
 config AXP221_DLDO4_VOLT
 	int "axp221 dldo4 voltage"
@@ -28,20 +30,26 @@ config AXP221_ALDO1_VOLT
 	default -1
 	---help---
 	Set the voltage (mV) to program the axp221 aldo1 at, set to -1 to
-	disable aldo1.
+	disable aldo1. On sun6i (A31) boards which have a wifi module this is
+	often used to power the wifi module.
 
 config AXP221_ALDO2_VOLT
 	int "axp221 aldo2 voltage"
 	depends on AXP221_POWER
-	default -1
+	default 1800 if MACH_SUN6I
+	default 2500 if MACH_SUN8I
 	---help---
 	Set the voltage (mV) to program the axp221 aldo2 at, set to -1 to
-	disable aldo2.
+	disable aldo2. On sun6i (A31) boards this is typically connected to
+	VCC-PM, which powers the port M gpios, and should be set to 1.8V.
+	On sun8i (A23) this is typically connected to VDD-DLL and must be
+	set to 2.5V.
 
 config AXP221_ALDO3_VOLT
 	int "axp221 aldo3 voltage"
 	depends on AXP221_POWER
-	default -1
+	default 3000
 	---help---
 	Set the voltage (mV) to program the axp221 aldo3 at, set to -1 to
-	disable aldo3.
+	disable aldo3. This is typically connected to VCC-PLL and AVCC and
+	must be set to 3V.
Signature · 1 line
2.1.0
#13 lore raw

PATCH 5/14 sunxi: axp221: Make dcdc1 voltage configurable

In reply to Hans de Goede

The dcdc1 voltage is typically used as generic 3.3V IO voltage for things like GPIO-s, sdcard interfaces, etc. On most boards this is undervolted to 3.0V to safe battery, but not on all, make it configurable so that we can use the same settings as the original firmware on all boards.

---
 board/sunxi/board.c       |  2 +-
 configs/Mele_M9_defconfig |  2 ++
 drivers/power/Kconfig     | 10 ++++++++++
 3 files changed, 13 insertions(+), 1 deletion(-)
board/sunxi/board.c +1 -1
index b5dfe95..e2ebf83 100644
@@ -175,7 +175,7 @@ void sunxi_board_init(void)
 #endif
 #ifdef CONFIG_AXP221_POWER
 	power_failed = axp221_init();
-	power_failed |= axp221_set_dcdc1(3000);
+	power_failed |= axp221_set_dcdc1(CONFIG_AXP221_DCDC1_VOLT);
 	power_failed |= axp221_set_dcdc2(1200);
 	power_failed |= axp221_set_dcdc3(1200);
 	power_failed |= axp221_set_dcdc4(1200);
configs/Mele_M9_defconfig +2 -0
index 445cc57..e5ab0ec 100644
@@ -7,6 +7,8 @@ CONFIG_FDTFILE="sun6i-a31-m9.dtb"
 +S:CONFIG_TARGET_MELE_M9=y
 +S:CONFIG_DRAM_CLK=312
 +S:CONFIG_DRAM_ZQ=120
+# The Mele M9 uses 3.3V for general IO
++S:CONFIG_AXP221_DCDC1_VOLT=3300
 # Ethernet phy power
 +S:CONFIG_AXP221_DLDO1_VOLT=3300
 # USB hub power
drivers/power/Kconfig +10 -0
index af66887..e132759 100644
@@ -6,6 +6,16 @@ config AXP221_POWER
 	Say y here to enable support for the axp221 / axp223 pmic found on most
 	sun6i (A31) / sun8i (A23) boards.
 
+config AXP221_DCDC1_VOLT
+	int "axp221 dcdc1 voltage"
+	depends on AXP221_POWER
+	default 3000
+	---help---
+	Set the voltage (mV) to program the axp221 dcdc1 at, set to 0 to
+	disable dcdc1. This is typically used as generic 3.3V IO voltage for
+	things like GPIO-s, sdcard interfaces, etc. On most boards this is
+	undervolted to 3.0V to safe battery.
+
 config AXP221_DLDO1_VOLT
 	int "axp221 dldo1 voltage"
 	depends on AXP221_POWER
Signature · 1 line
2.1.0
#14 lore raw

PATCH 5/14 sunxi: axp221: Make dcdc1 voltage configurable

Quoted 6 lines · Hans de Goede

The dcdc1 voltage is typically used as generic 3.3V IO voltage for things like GPIO-s, sdcard interfaces, etc. On most boards this is undervolted to 3.0V to safe battery, but not on all, make it configurable so that we can use the same settings as the original firmware on all boards.

#15 lore raw

PATCH 6/14 sunxi: axp221: Explicitly turn off unused voltages

In reply to Hans de Goede

Explicitly turn off unused voltages, rather then leaving them as is. Likewise explictly enabled the dcdc convertors, rather then assuming they are already enabled at boot.

---
 board/sunxi/board.c    |  10 -----
 drivers/power/Kconfig  |  16 ++++----
 drivers/power/axp221.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++---
 include/axp221.h       |   8 +++-
 4 files changed, 111 insertions(+), 25 deletions(-)
board/sunxi/board.c +0 -10
index e2ebf83..5bf19b7 100644
@@ -180,22 +180,12 @@ void sunxi_board_init(void)
 	power_failed |= axp221_set_dcdc3(1200);
 	power_failed |= axp221_set_dcdc4(1200);
 	power_failed |= axp221_set_dcdc5(1500);
-#if CONFIG_AXP221_DLDO1_VOLT != -1
 	power_failed |= axp221_set_dldo1(CONFIG_AXP221_DLDO1_VOLT);
-#endif
-#if CONFIG_AXP221_DLDO4_VOLT != -1
 	power_failed |= axp221_set_dldo4(CONFIG_AXP221_DLDO4_VOLT);
-#endif
-#if CONFIG_AXP221_ALDO1_VOLT != -1
 	power_failed |= axp221_set_aldo1(CONFIG_AXP221_ALDO1_VOLT);
-#endif
-#if CONFIG_AXP221_ALDO2_VOLT != -1
 	power_failed |= axp221_set_aldo2(CONFIG_AXP221_ALDO2_VOLT);
-#endif
-#if CONFIG_AXP221_ALDO3_VOLT != -1
 	power_failed |= axp221_set_aldo3(CONFIG_AXP221_ALDO3_VOLT);
 #endif
-#endif
 
 	printf("DRAM:");
 	ramsize = sunxi_dram_init();
drivers/power/Kconfig +8 -8
index e132759..ef0c093 100644
@@ -19,9 +19,9 @@ config AXP221_DCDC1_VOLT
 config AXP221_DLDO1_VOLT
 	int "axp221 dldo1 voltage"
 	depends on AXP221_POWER
-	default -1
+	default 0
 	---help---
-	Set the voltage (mV) to program the axp221 dldo1 at, set to -1 to
+	Set the voltage (mV) to program the axp221 dldo1 at, set to 0 to
 	disable dldo1. On sun6i (A31) boards with ethernet this is often used
 	to power the ethernet phy. On sun8i (A23) boards this is often used to
 	power the wifi.
@@ -29,17 +29,17 @@ config AXP221_DLDO1_VOLT
 config AXP221_DLDO4_VOLT
 	int "axp221 dldo4 voltage"
 	depends on AXP221_POWER
-	default -1
+	default 0
 	---help---
-	Set the voltage (mV) to program the axp221 dldo4 at, set to -1 to
+	Set the voltage (mV) to program the axp221 dldo4 at, set to 0 to
 	disable dldo4.
 
 config AXP221_ALDO1_VOLT
 	int "axp221 aldo1 voltage"
 	depends on AXP221_POWER
-	default -1
+	default 0
 	---help---
-	Set the voltage (mV) to program the axp221 aldo1 at, set to -1 to
+	Set the voltage (mV) to program the axp221 aldo1 at, set to 0 to
 	disable aldo1. On sun6i (A31) boards which have a wifi module this is
 	often used to power the wifi module.
 
@@ -49,7 +49,7 @@ config AXP221_ALDO2_VOLT
 	default 1800 if MACH_SUN6I
 	default 2500 if MACH_SUN8I
 	---help---
-	Set the voltage (mV) to program the axp221 aldo2 at, set to -1 to
+	Set the voltage (mV) to program the axp221 aldo2 at, set to 0 to
 	disable aldo2. On sun6i (A31) boards this is typically connected to
 	VCC-PM, which powers the port M gpios, and should be set to 1.8V.
 	On sun8i (A23) this is typically connected to VDD-DLL and must be
@@ -60,6 +60,6 @@ config AXP221_ALDO3_VOLT
 	depends on AXP221_POWER
 	default 3000
 	---help---
-	Set the voltage (mV) to program the axp221 aldo3 at, set to -1 to
+	Set the voltage (mV) to program the axp221 aldo3 at, set to 0 to
 	disable aldo3. This is typically connected to VCC-PLL and AVCC and
 	must be set to 3V.
drivers/power/axp221.c +96 -6

183 lines not on this page · raw message

include/axp221.h +7 -1
index 10d35e1..a6e52e3 100644
@@ -17,6 +17,12 @@
 /* Page 0 addresses */
 #define AXP221_CHIP_ID		0x03
 #define AXP221_OUTPUT_CTRL1	0x10
+#define AXP221_OUTPUT_CTRL1_DCDC0_EN	(1 << 0)
+#define AXP221_OUTPUT_CTRL1_DCDC1_EN	(1 << 1)
+#define AXP221_OUTPUT_CTRL1_DCDC2_EN	(1 << 2)
+#define AXP221_OUTPUT_CTRL1_DCDC3_EN	(1 << 3)
+#define AXP221_OUTPUT_CTRL1_DCDC4_EN	(1 << 4)
+#define AXP221_OUTPUT_CTRL1_DCDC5_EN	(1 << 5)
 #define AXP221_OUTPUT_CTRL1_ALDO1_EN	(1 << 6)
 #define AXP221_OUTPUT_CTRL1_ALDO2_EN	(1 << 7)
 #define AXP221_OUTPUT_CTRL2	0x12
@@ -24,7 +30,7 @@
 #define AXP221_OUTPUT_CTRL2_DLDO2_EN	(1 << 4)
 #define AXP221_OUTPUT_CTRL2_DLDO3_EN	(1 << 5)
 #define AXP221_OUTPUT_CTRL2_DLDO4_EN	(1 << 6)
-#define AXP221_OUTPUT_CTRL2_DCDC1_EN	(1 << 7)
+#define AXP221_OUTPUT_CTRL2_DCDC1SW_EN	(1 << 7)
 #define AXP221_OUTPUT_CTRL3	0x13
 #define AXP221_OUTPUT_CTRL3_ALDO3_EN	(1 << 7)
 #define AXP221_DLDO1_CTRL	0x15
Signature · 1 line
2.1.0
#17 lore raw

PATCH 7/14 sunxi: axp221: Disable dcdc4 on sun8i (A23)

In reply to Hans de Goede

dcdc4 is not used on sun8i, disable it.

While at it also add comments to the other fixed voltages to document what they are used for.

---
 board/sunxi/board.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
board/sunxi/board.c +8 -4
index 5bf19b7..7d6d075 100644
@@ -176,10 +176,14 @@ void sunxi_board_init(void)
 #ifdef CONFIG_AXP221_POWER
 	power_failed = axp221_init();
 	power_failed |= axp221_set_dcdc1(CONFIG_AXP221_DCDC1_VOLT);
-	power_failed |= axp221_set_dcdc2(1200);
-	power_failed |= axp221_set_dcdc3(1200);
-	power_failed |= axp221_set_dcdc4(1200);
-	power_failed |= axp221_set_dcdc5(1500);
+	power_failed |= axp221_set_dcdc2(1200); /* A31:VDD-GPU, A23:VDD-SYS */
+	power_failed |= axp221_set_dcdc3(1200); /* VDD-CPU */
+#ifdef CONFIG_MACH_SUN6I
+	power_failed |= axp221_set_dcdc4(1200); /* A31:VDD-SYS */
+#else
+	power_failed |= axp221_set_dcdc4(0);    /* A23:unused */
+#endif
+	power_failed |= axp221_set_dcdc5(1500); /* VCC-DRAM */
 	power_failed |= axp221_set_dldo1(CONFIG_AXP221_DLDO1_VOLT);
 	power_failed |= axp221_set_dldo4(CONFIG_AXP221_DLDO4_VOLT);
 	power_failed |= axp221_set_aldo1(CONFIG_AXP221_ALDO1_VOLT);
Signature · 1 line
2.1.0
#19 lore raw

PATCH 8/14 sun6i: Add a sigma_delta_enable paramter to clock_set_pll5()

In reply to Hans de Goede

The sun8i dram code sometimes wants to enable sigma delta mode, add a parameter to allow this.

---
 arch/arm/cpu/armv7/sunxi/clock_sun6i.c        | 9 +++++++--
 arch/arm/cpu/armv7/sunxi/dram_sun6i.c         | 2 +-
 arch/arm/include/asm/arch-sunxi/clock.h       | 1 -
 arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 5 +++++
 4 files changed, 13 insertions(+), 4 deletions(-)
arch/arm/cpu/armv7/sunxi/clock_sun6i.c +7 -2
index 8e949c6..193e314 100644
@@ -144,15 +144,20 @@ void clock_set_pll3(unsigned int clk)
 	       &ccm->pll3_cfg);
 }
 
-void clock_set_pll5(unsigned int clk)
+void clock_set_pll5(unsigned int clk, bool sigma_delta_enable)
 {
 	struct sunxi_ccm_reg * const ccm =
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 	const int k = 2;
 	const int m = 1;
 
+	if (sigma_delta_enable)
+		writel(CCM_PLL5_PATTERN, &ccm->pll5_pattern_cfg);
+
 	/* PLL5 rate = 24000000 * n * k / m */
-	writel(CCM_PLL5_CTRL_EN | CCM_PLL5_CTRL_UPD |
+	writel(CCM_PLL5_CTRL_EN |
+	       (sigma_delta_enable ? CCM_PLL5_CTRL_SIGMA_DELTA_EN : 0) |
+	       CCM_PLL5_CTRL_UPD |
 	       CCM_PLL5_CTRL_N(clk / (24000000 * k / m)) |
 	       CCM_PLL5_CTRL_K(k) | CCM_PLL5_CTRL_M(m), &ccm->pll5_cfg);
 
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +1 -1
index 61bb8d4..bc6428a 100644
@@ -46,7 +46,7 @@ static void mctl_sys_init(void)
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 	const int dram_clk_div = 2;
 
-	clock_set_pll5(DRAM_CLK * dram_clk_div);
+	clock_set_pll5(DRAM_CLK * dram_clk_div, false);
 
 	clrsetbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_DIV0_MASK,
 		CCM_DRAMCLK_CFG_DIV0(dram_clk_div) | CCM_DRAMCLK_CFG_RST |
arch/arm/include/asm/arch-sunxi/clock.h +0 -1
index 64acff3..505c363 100644
@@ -26,7 +26,6 @@ int clock_init(void);
 int clock_twi_onoff(int port, int state);
 void clock_set_pll1(unsigned int hz);
 void clock_set_pll3(unsigned int hz);
-void clock_set_pll5(unsigned int hz);
 unsigned int clock_get_pll5p(void);
 unsigned int clock_get_pll6(void);
 void clock_set_de_mod_clock(u32 *clk_cfg, unsigned int hz);
arch/arm/include/asm/arch-sunxi/clock_sun6i.h +5 -0
index 3d4fcd1..f807af3 100644
@@ -185,6 +185,7 @@ struct sunxi_ccm_reg {
 #define CCM_PLL5_CTRL_K(n)		((((n) - 1) & 0x3) << 4)
 #define CCM_PLL5_CTRL_N(n)		((((n) - 1) & 0x1f) << 8)
 #define CCM_PLL5_CTRL_UPD		(0x1 << 20)
+#define CCM_PLL5_CTRL_SIGMA_DELTA_EN	(0x1 << 24)
 #define CCM_PLL5_CTRL_EN		(0x1 << 31)
 
 #define PLL6_CFG_DEFAULT		0x90041811 /* 600 MHz */
@@ -274,6 +275,8 @@ struct sunxi_ccm_reg {
 
 #define MBUS_CLK_DEFAULT		0x81000001 /* PLL6 / 2 */
 
+#define CCM_PLL5_PATTERN		0xd1303333
+
 /* ahb_reset0 offsets */
 #define AHB_RESET_OFFSET_GMAC		17
 #define AHB_RESET_OFFSET_MCTL		14
@@ -308,4 +311,6 @@ struct sunxi_ccm_reg {
 #define CCM_DE_CTRL_PLL10		(5 << 24)
 #define CCM_DE_CTRL_GATE		(1 << 31)
 
+void clock_set_pll5(unsigned int clk, bool sigma_delta_enable);
+
 #endif /* _SUNXI_CLOCK_SUN6I_H */
Signature · 1 line
2.1.0
#21 lore raw

PATCH 8/14 sun6i: Add a sigma_delta_enable paramter to clock_set_pll5()

In reply to Hans de Goede
Quoted 43 lines · On Tue, 16 Dec 2014 21:31:33 +0100 Hans de Goede <[email protected]> wrote:

The sun8i dram code sometimes wants to enable sigma delta mode, add a parameter to allow this.

---
 arch/arm/cpu/armv7/sunxi/clock_sun6i.c        | 9 +++++++--
 arch/arm/cpu/armv7/sunxi/dram_sun6i.c         | 2 +-
 arch/arm/include/asm/arch-sunxi/clock.h       | 1 -
 arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 5 +++++
 4 files changed, 13 insertions(+), 4 deletions(-)
arch/arm/cpu/armv7/sunxi/clock_sun6i.c +7 -2
index 8e949c6..193e314 100644
@@ -144,15 +144,20 @@ void clock_set_pll3(unsigned int clk)
 	       &ccm->pll3_cfg);
 }
 
-void clock_set_pll5(unsigned int clk)
+void clock_set_pll5(unsigned int clk, bool sigma_delta_enable)
 {
 	struct sunxi_ccm_reg * const ccm =
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 	const int k = 2;
 	const int m = 1;
 
+	if (sigma_delta_enable)
+		writel(CCM_PLL5_PATTERN, &ccm->pll5_pattern_cfg);
+
 	/* PLL5 rate = 24000000 * n * k / m */
-	writel(CCM_PLL5_CTRL_EN | CCM_PLL5_CTRL_UPD |
+	writel(CCM_PLL5_CTRL_EN |
+	       (sigma_delta_enable ? CCM_PLL5_CTRL_SIGMA_DELTA_EN : 0) |
+	       CCM_PLL5_CTRL_UPD |
 	       CCM_PLL5_CTRL_N(clk / (24000000 * k / m)) |
 	       CCM_PLL5_CTRL_K(k) | CCM_PLL5_CTRL_M(m), &ccm->pll5_cfg);
 
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +0 -0
index 61bb8d4..bc6428a 100644

arch/arm/cpu/armv7/sunxi/dram_sun6i.c static void mctl_sys_init(void) · line 49

Quoted 5 lines
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +1 -1
@@ -46,7 +46,7 @@ static void mctl_sys_init(void)
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 	const int dram_clk_div = 2;
 
-	clock_set_pll5(DRAM_CLK * dram_clk_div);
+	clock_set_pll5(DRAM_CLK * dram_clk_div, false);

Would it make the code a bit more readable to have a named constant here (with SIGMA_DELTA as part of its name) instead of just true/false?

The "foobar(true, true, false, true)" style is not exactly informative.

I'm not insisting on this though.

Quoted 42 lines
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +0 -0
 	clrsetbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_DIV0_MASK,
 		CCM_DRAMCLK_CFG_DIV0(dram_clk_div) | CCM_DRAMCLK_CFG_RST |
arch/arm/include/asm/arch-sunxi/clock.h +0 -1
index 64acff3..505c363 100644
@@ -26,7 +26,6 @@ int clock_init(void);
 int clock_twi_onoff(int port, int state);
 void clock_set_pll1(unsigned int hz);
 void clock_set_pll3(unsigned int hz);
-void clock_set_pll5(unsigned int hz);
 unsigned int clock_get_pll5p(void);
 unsigned int clock_get_pll6(void);
 void clock_set_de_mod_clock(u32 *clk_cfg, unsigned int hz);
arch/arm/include/asm/arch-sunxi/clock_sun6i.h +5 -0
index 3d4fcd1..f807af3 100644
@@ -185,6 +185,7 @@ struct sunxi_ccm_reg {
 #define CCM_PLL5_CTRL_K(n)		((((n) - 1) & 0x3) << 4)
 #define CCM_PLL5_CTRL_N(n)		((((n) - 1) & 0x1f) << 8)
 #define CCM_PLL5_CTRL_UPD		(0x1 << 20)
+#define CCM_PLL5_CTRL_SIGMA_DELTA_EN	(0x1 << 24)
 #define CCM_PLL5_CTRL_EN		(0x1 << 31)
 
 #define PLL6_CFG_DEFAULT		0x90041811 /* 600 MHz */
@@ -274,6 +275,8 @@ struct sunxi_ccm_reg {
 
 #define MBUS_CLK_DEFAULT		0x81000001 /* PLL6 / 2 */
 
+#define CCM_PLL5_PATTERN		0xd1303333
+
 /* ahb_reset0 offsets */
 #define AHB_RESET_OFFSET_GMAC		17
 #define AHB_RESET_OFFSET_MCTL		14
@@ -308,4 +311,6 @@ struct sunxi_ccm_reg {
 #define CCM_DE_CTRL_PLL10		(5 << 24)
 #define CCM_DE_CTRL_GATE		(1 << 31)
 
+void clock_set_pll5(unsigned int clk, bool sigma_delta_enable);
+
 #endif /* _SUNXI_CLOCK_SUN6I_H */
Signature · 2 lines
Best regards,
Siarhei Siamashka
#22 lore raw

PATCH 9/14 sun6i: Add k and m parameters to clock_set_pll5()

In reply to Hans de Goede

The A23 (sun8i) requires different values for these then sun6i, so make them function parameters.

---
 arch/arm/cpu/armv7/sunxi/clock_sun6i.c        | 4 +---
 arch/arm/cpu/armv7/sunxi/dram_sun6i.c         | 2 +-
 arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 2 +-
 3 files changed, 3 insertions(+), 5 deletions(-)
arch/arm/cpu/armv7/sunxi/clock_sun6i.c +1 -3
index 193e314..8ef19df 100644
@@ -144,12 +144,10 @@ void clock_set_pll3(unsigned int clk)
 	       &ccm->pll3_cfg);
 }
 
-void clock_set_pll5(unsigned int clk, bool sigma_delta_enable)
+void clock_set_pll5(unsigned int clk, int k, int m, bool sigma_delta_enable)
 {
 	struct sunxi_ccm_reg * const ccm =
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
-	const int k = 2;
-	const int m = 1;
 
 	if (sigma_delta_enable)
 		writel(CCM_PLL5_PATTERN, &ccm->pll5_pattern_cfg);
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +1 -1
index bc6428a..a8bbdfd 100644
@@ -46,7 +46,7 @@ static void mctl_sys_init(void)
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 	const int dram_clk_div = 2;
 
-	clock_set_pll5(DRAM_CLK * dram_clk_div, false);
+	clock_set_pll5(DRAM_CLK * dram_clk_div, 2, 1, false);
 
 	clrsetbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_DIV0_MASK,
 		CCM_DRAMCLK_CFG_DIV0(dram_clk_div) | CCM_DRAMCLK_CFG_RST |
arch/arm/include/asm/arch-sunxi/clock_sun6i.h +1 -1
index f807af3..7d61216 100644
@@ -311,6 +311,6 @@ struct sunxi_ccm_reg {
 #define CCM_DE_CTRL_PLL10		(5 << 24)
 #define CCM_DE_CTRL_GATE		(1 << 31)
 
-void clock_set_pll5(unsigned int clk, bool sigma_delta_enable);
+void clock_set_pll5(unsigned int clk, int k, int m, bool sigma_delta_enable);
 
 #endif /* _SUNXI_CLOCK_SUN6I_H */
Signature · 1 line
2.1.0
#24 lore raw

PATCH 9/14 sun6i: Add k and m parameters to clock_set_pll5()

In reply to Hans de Goede
Quoted 4 lines · On Tue, 16 Dec 2014 21:31:34 +0100 Hans de Goede <[email protected]> wrote:

The A23 (sun8i) requires different values for these then sun6i, so make them function parameters.

What happens if A23 does not get these special k and m parameters, but the 'clock_set_pll5' function picks some other values for them (with the same resulting target clock speed)?

And if they are really required for A23, then why exposing them as the function arguments instead of hiding this implementation detail inside of the 'clock_set_pll5' function?

Quoted 49 lines
---
 arch/arm/cpu/armv7/sunxi/clock_sun6i.c        | 4 +---
 arch/arm/cpu/armv7/sunxi/dram_sun6i.c         | 2 +-
 arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 2 +-
 3 files changed, 3 insertions(+), 5 deletions(-)
arch/arm/cpu/armv7/sunxi/clock_sun6i.c +1 -3
index 193e314..8ef19df 100644
@@ -144,12 +144,10 @@ void clock_set_pll3(unsigned int clk)
 	       &ccm->pll3_cfg);
 }
 
-void clock_set_pll5(unsigned int clk, bool sigma_delta_enable)
+void clock_set_pll5(unsigned int clk, int k, int m, bool sigma_delta_enable)
 {
 	struct sunxi_ccm_reg * const ccm =
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
-	const int k = 2;
-	const int m = 1;
 
 	if (sigma_delta_enable)
 		writel(CCM_PLL5_PATTERN, &ccm->pll5_pattern_cfg);
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +1 -1
index bc6428a..a8bbdfd 100644
@@ -46,7 +46,7 @@ static void mctl_sys_init(void)
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 	const int dram_clk_div = 2;
 
-	clock_set_pll5(DRAM_CLK * dram_clk_div, false);
+	clock_set_pll5(DRAM_CLK * dram_clk_div, 2, 1, false);
 
 	clrsetbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_DIV0_MASK,
 		CCM_DRAMCLK_CFG_DIV0(dram_clk_div) | CCM_DRAMCLK_CFG_RST |
arch/arm/include/asm/arch-sunxi/clock_sun6i.h +1 -1
index f807af3..7d61216 100644
@@ -311,6 +311,6 @@ struct sunxi_ccm_reg {
 #define CCM_DE_CTRL_PLL10		(5 << 24)
 #define CCM_DE_CTRL_GATE		(1 << 31)
 
-void clock_set_pll5(unsigned int clk, bool sigma_delta_enable);
+void clock_set_pll5(unsigned int clk, int k, int m, bool sigma_delta_enable);
 
 #endif /* _SUNXI_CLOCK_SUN6I_H */
Signature · 2 lines
Best regards,
Siarhei Siamashka
#25 lore raw

PATCH 9/14 sun6i: Add k and m parameters to clock_set_pll5()

Hi,

Quoted 11 lines · Siarhei Siamashka
Quoted 4 lines · On Tue, 16 Dec 2014 21:31:34 +0100 Hans de Goede <[email protected]> wrote:

The A23 (sun8i) requires different values for these then sun6i, so make them function parameters.

What happens if A23 does not get these special k and m parameters, but the 'clock_set_pll5' function picks some other values for them (with the same resulting target clock speed)?

The major difference is that on the A23 pll5 must be set to dram_clk / 2, where as on A31 it needs to be set to dram_clk * 2. By codifying k and m so that they do the * 2 on A31 and / 2 on A23 we can make any multiple of 24 MHz as DRAM clk without needing any other code to figure out the optimal k and m. AFAIK using other k and m factors with the same end-result should work fine. But doing things this way follows the KISS principle and I'm a great fan of KISS.

Regards,

Hans

Quoted 57 lines

And if they are really required for A23, then why exposing them as the function arguments instead of hiding this implementation detail inside of the 'clock_set_pll5' function?

Quoted 49 lines
---
  arch/arm/cpu/armv7/sunxi/clock_sun6i.c        | 4 +---
  arch/arm/cpu/armv7/sunxi/dram_sun6i.c         | 2 +-
  arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 2 +-
  3 files changed, 3 insertions(+), 5 deletions(-)
arch/arm/cpu/armv7/sunxi/clock_sun6i.c +1 -3
index 193e314..8ef19df 100644
@@ -144,12 +144,10 @@ void clock_set_pll3(unsigned int clk)
  	       &ccm->pll3_cfg);
  }
 
-void clock_set_pll5(unsigned int clk, bool sigma_delta_enable)
+void clock_set_pll5(unsigned int clk, int k, int m, bool sigma_delta_enable)
  {
  	struct sunxi_ccm_reg * const ccm =
  		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
-	const int k = 2;
-	const int m = 1;
 
  	if (sigma_delta_enable)
  		writel(CCM_PLL5_PATTERN, &ccm->pll5_pattern_cfg);
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +1 -1
index bc6428a..a8bbdfd 100644
@@ -46,7 +46,7 @@ static void mctl_sys_init(void)
  		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  	const int dram_clk_div = 2;
 
-	clock_set_pll5(DRAM_CLK * dram_clk_div, false);
+	clock_set_pll5(DRAM_CLK * dram_clk_div, 2, 1, false);
 
  	clrsetbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_DIV0_MASK,
  		CCM_DRAMCLK_CFG_DIV0(dram_clk_div) | CCM_DRAMCLK_CFG_RST |
arch/arm/include/asm/arch-sunxi/clock_sun6i.h +1 -1
index f807af3..7d61216 100644
@@ -311,6 +311,6 @@ struct sunxi_ccm_reg {
  #define CCM_DE_CTRL_PLL10		(5 << 24)
  #define CCM_DE_CTRL_GATE		(1 << 31)
 
-void clock_set_pll5(unsigned int clk, bool sigma_delta_enable);
+void clock_set_pll5(unsigned int clk, int k, int m, bool sigma_delta_enable);
 
  #endif /* _SUNXI_CLOCK_SUN6I_H */
#26 lore raw

PATCH 9/14 sun6i: Add k and m parameters to clock_set_pll5()

Quoted 15 lines · On Fri, 19 Dec 2014 17:40:27 +0100 Hans de Goede <[email protected]> wrote:

Hi,

Quoted 11 lines · Siarhei Siamashka
Quoted 4 lines · On Tue, 16 Dec 2014 21:31:34 +0100 Hans de Goede <[email protected]> wrote:

The A23 (sun8i) requires different values for these then sun6i, so make them function parameters.

What happens if A23 does not get these special k and m parameters, but the 'clock_set_pll5' function picks some other values for them (with the same resulting target clock speed)?

Quoted 5 lines

The major difference is that on the A23 pll5 must be set to dram_clk / 2, where as on A31 it needs to be set to dram_clk * 2. By codifying k and m so that they do the * 2 on A31 and / 2 on A23 we can make any multiple of 24 MHz as DRAM clk without needing any other code to figure out the optimal k and m.

Wouldn't such other code in 'clock_set_pll5' just look like this (adds only a few extra instructions with an optimizing compiler):

    const int max_n = 32;
    int k = 1, m = 2;
    if (clk > 24000000 * k * max_n / m) {
        m = 1;
        if (clk > 24000000 * k * max_n / m)
            k = 2;
    }

As an additional bonus, you get 12 MHz clock frequency selection granularity on A31 for the DRAM clock speeds up to 384 MHz. And keep the current 24 MHz granularity for anything larger than that.

Quoted 2 lines

AFAIK using other k and m factors with the same end-result should work fine.

This statement seems to somewhat contradict with your original commit message. Should the commit message be updated?

Quoted 2 lines

But doing things this way follows the KISS principle and I'm a great fan of KISS.

By instead spreading the complexity all across the sources? So that each caller code needs to make assumptions about the valid clock frequency range and statically pick the right multiplier/divisor parameters as an additional burden?

In what way is it simple?

Quoted 64 lines

Regards,

Hans

Quoted 57 lines

And if they are really required for A23, then why exposing them as the function arguments instead of hiding this implementation detail inside of the 'clock_set_pll5' function?

Quoted 49 lines
---
  arch/arm/cpu/armv7/sunxi/clock_sun6i.c        | 4 +---
  arch/arm/cpu/armv7/sunxi/dram_sun6i.c         | 2 +-
  arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 2 +-
  3 files changed, 3 insertions(+), 5 deletions(-)
arch/arm/cpu/armv7/sunxi/clock_sun6i.c +1 -3
index 193e314..8ef19df 100644
@@ -144,12 +144,10 @@ void clock_set_pll3(unsigned int clk)
  	       &ccm->pll3_cfg);
  }
 
-void clock_set_pll5(unsigned int clk, bool sigma_delta_enable)
+void clock_set_pll5(unsigned int clk, int k, int m, bool sigma_delta_enable)
  {
  	struct sunxi_ccm_reg * const ccm =
  		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
-	const int k = 2;
-	const int m = 1;
 
  	if (sigma_delta_enable)
  		writel(CCM_PLL5_PATTERN, &ccm->pll5_pattern_cfg);
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +1 -1
index bc6428a..a8bbdfd 100644
@@ -46,7 +46,7 @@ static void mctl_sys_init(void)
  		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  	const int dram_clk_div = 2;
 
-	clock_set_pll5(DRAM_CLK * dram_clk_div, false);
+	clock_set_pll5(DRAM_CLK * dram_clk_div, 2, 1, false);
 
  	clrsetbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_DIV0_MASK,
  		CCM_DRAMCLK_CFG_DIV0(dram_clk_div) | CCM_DRAMCLK_CFG_RST |
arch/arm/include/asm/arch-sunxi/clock_sun6i.h +1 -1
index f807af3..7d61216 100644
@@ -311,6 +311,6 @@ struct sunxi_ccm_reg {
  #define CCM_DE_CTRL_PLL10		(5 << 24)
  #define CCM_DE_CTRL_GATE		(1 << 31)
 
-void clock_set_pll5(unsigned int clk, bool sigma_delta_enable);
+void clock_set_pll5(unsigned int clk, int k, int m, bool sigma_delta_enable);
 
  #endif /* _SUNXI_CLOCK_SUN6I_H */
#27 lore raw

PATCH 10/14 sunxi: Move await_completion dram helper to dram.h

In reply to Hans de Goede

The await_completion helper is already copy pasted between the sun4i and sun6i dram code, and we need it for sun8i too, so lets make it an inline helper in dram.h, rather then adding yet another copy.

---
 arch/arm/cpu/armv7/sunxi/dram_sun4i.c  | 17 ++---------------
 arch/arm/cpu/armv7/sunxi/dram_sun6i.c  | 31 +++++++++----------------------
 arch/arm/include/asm/arch-sunxi/dram.h | 14 ++++++++++++++
 3 files changed, 25 insertions(+), 37 deletions(-)
arch/arm/cpu/armv7/sunxi/dram_sun4i.c +2 -15
index ec8aaa7..c736fa3 100644
@@ -36,24 +36,11 @@
 #define CPU_CFG_CHIP_REV_B 0x3
 
 /*
- * Wait up to 1s for value to be set in given part of reg.
- */
-static void await_completion(u32 *reg, u32 mask, u32 val)
-{
-	unsigned long tmo = timer_get_us() + 1000000;
-
-	while ((readl(reg) & mask) != val) {
-		if (timer_get_us() > tmo)
-			panic("Timeout initialising DRAM\n");
-	}
-}
-
-/*
  * Wait up to 1s for mask to be clear in given reg.
  */
 static inline void await_bits_clear(u32 *reg, u32 mask)
 {
-	await_completion(reg, mask, 0);
+	mctl_await_completion(reg, mask, 0);
 }
 
 /*
@@ -61,7 +48,7 @@ static inline void await_bits_clear(u32 *reg, u32 mask)
  */
 static inline void await_bits_set(u32 *reg, u32 mask)
 {
-	await_completion(reg, mask, mask);
+	mctl_await_completion(reg, mask, mask);
 }
 
 /*
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +9 -22
index a8bbdfd..e1670e5 100644
@@ -27,19 +27,6 @@ struct dram_sun6i_para {
 	u16 page_size;
 };
 
-/*
- * Wait up to 1s for value to be set in given part of reg.
- */
-static void await_completion(u32 *reg, u32 mask, u32 val)
-{
-	unsigned long tmo = timer_get_us() + 1000000;
-
-	while ((readl(reg) & mask) != val) {
-		if (timer_get_us() > tmo)
-			panic("Timeout initialising DRAM\n");
-	}
-}
-
 static void mctl_sys_init(void)
 {
 	struct sunxi_ccm_reg * const ccm =
@@ -51,7 +38,7 @@ static void mctl_sys_init(void)
 	clrsetbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_DIV0_MASK,
 		CCM_DRAMCLK_CFG_DIV0(dram_clk_div) | CCM_DRAMCLK_CFG_RST |
 		CCM_DRAMCLK_CFG_UPD);
-	await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);
+	mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);
 
 	writel(MDFS_CLK_DEFAULT, &ccm->mdfs_clk_cfg);
 
@@ -107,8 +94,8 @@ static bool mctl_rank_detect(u32 *gsr0, int rank)
 	const u32 done = MCTL_DX_GSR0_RANK0_TRAIN_DONE << rank;
 	const u32 err = MCTL_DX_GSR0_RANK0_TRAIN_ERR << rank;
 
-	await_completion(gsr0, done, done);
-	await_completion(gsr0 + 0x10, done, done);
+	mctl_await_completion(gsr0, done, done);
+	mctl_await_completion(gsr0 + 0x10, done, done);
 
 	return !(readl(gsr0) & err) && !(readl(gsr0 + 0x10) & err);
 }
@@ -129,7 +116,7 @@ static void mctl_channel_init(int ch_index, struct dram_sun6i_para *para)
 	}
 
 	writel(MCTL_MCMD_NOP, &mctl_ctl->mcmd);
-	await_completion(&mctl_ctl->mcmd, MCTL_MCMD_BUSY, 0);
+	mctl_await_completion(&mctl_ctl->mcmd, MCTL_MCMD_BUSY, 0);
 
 	/* PHY initialization */
 	writel(MCTL_PGCR, &mctl_phy->pgcr);
@@ -166,14 +153,14 @@ static void mctl_channel_init(int ch_index, struct dram_sun6i_para *para)
 	writel(MCTL_DX_GCR | MCTL_DX_GCR_EN, &mctl_phy->dx2gcr);
 	writel(MCTL_DX_GCR | MCTL_DX_GCR_EN, &mctl_phy->dx3gcr);
 
-	await_completion(&mctl_phy->pgsr, 0x03, 0x03);
+	mctl_await_completion(&mctl_phy->pgsr, 0x03, 0x03);
 
 	writel(CONFIG_DRAM_ZQ, &mctl_phy->zq0cr1);
 
 	setbits_le32(&mctl_phy->pir, MCTL_PIR_CLEAR_STATUS);
 	writel(MCTL_PIR_STEP1, &mctl_phy->pir);
 	udelay(10);
-	await_completion(&mctl_phy->pgsr, 0x1f, 0x1f);
+	mctl_await_completion(&mctl_phy->pgsr, 0x1f, 0x1f);
 
 	/* rank detect */
 	if (!mctl_rank_detect(&mctl_phy->dx0gsr0, 1)) {
@@ -204,14 +191,14 @@ static void mctl_channel_init(int ch_index, struct dram_sun6i_para *para)
 	setbits_le32(&mctl_phy->pir, MCTL_PIR_CLEAR_STATUS);
 	writel(MCTL_PIR_STEP2, &mctl_phy->pir);
 	udelay(10);
-	await_completion(&mctl_phy->pgsr, 0x11, 0x11);
+	mctl_await_completion(&mctl_phy->pgsr, 0x11, 0x11);
 
 	if (readl(&mctl_phy->pgsr) & MCTL_PGSR_TRAIN_ERR_MASK)
 		panic("Training error initialising DRAM\n");
 
 	/* Move to configure state */
 	writel(MCTL_SCTL_CONFIG, &mctl_ctl->sctl);
-	await_completion(&mctl_ctl->sstat, 0x07, 0x01);
+	mctl_await_completion(&mctl_ctl->sstat, 0x07, 0x01);
 
 	/* Set number of clks per micro-second */
 	writel(DRAM_CLK / 1000000, &mctl_ctl->togcnt1u);
@@ -270,7 +257,7 @@ static void mctl_channel_init(int ch_index, struct dram_sun6i_para *para)
 
 	/* Move to access state */
 	writel(MCTL_SCTL_ACCESS, &mctl_ctl->sctl);
-	await_completion(&mctl_ctl->sstat, 0x07, 0x03);
+	mctl_await_completion(&mctl_ctl->sstat, 0x07, 0x03);
 }
 
 static void mctl_com_init(struct dram_sun6i_para *para)
arch/arm/include/asm/arch-sunxi/dram.h +14 -0
index 9072e68..18924f5 100644
@@ -12,6 +12,7 @@
 #ifndef _SUNXI_DRAM_H
 #define _SUNXI_DRAM_H
 
+#include <asm/io.h>
 #include <linux/types.h>
 
 /* dram regs definition */
@@ -23,4 +24,17 @@
 
 unsigned long sunxi_dram_init(void);
 
+/*
+ * Wait up to 1s for value to be set in given part of reg.
+ */
+static inline void mctl_await_completion(u32 *reg, u32 mask, u32 val)
+{
+	unsigned long tmo = timer_get_us() + 1000000;
+
+	while ((readl(reg) & mask) != val) {
+		if (timer_get_us() > tmo)
+			panic("Timeout initialising DRAM\n");
+	}
+}
+
 #endif /* _SUNXI_DRAM_H */
Signature · 1 line
2.1.0
#29 lore raw

PATCH 10/14 sunxi: Move await_completion dram helper to dram.h

In reply to Hans de Goede
Quoted 5 lines · On Tue, 16 Dec 2014 21:31:35 +0100 Hans de Goede <[email protected]> wrote:

The await_completion helper is already copy pasted between the sun4i and sun6i dram code, and we need it for sun8i too, so lets make it an inline helper in dram.h, rather then adding yet another copy.

Making this function "static inline" and placing it into a header file encourages the compiler to actually inline it. Which is not great for code size:

== Before the patch and using gcc version 4.8.3 ==

$ arm-none-linux-gnieabi-size spl/arch/arm/cpu/armv7/sunxi/dram_sun4i.o
 text    data     bss     dec     hex filename
 1731       0       0    1731     6c3
$ arm-none-linux-gnieabi-size spl/arch/arm/cpu/armv7/sunxi/dram_sun6i.o
 text    data     bss     dec     hex filename
 1841       0       0    1841     731

== After the patch and using gcc version 4.8.3 ==

$ arm-none-linux-gnieabi-size spl/arch/arm/cpu/armv7/sunxi/dram_sun4i.o
 text    data     bss     dec     hex filename
 1763       0       0    1763     6e3
$ arm-none-linux-gnieabi-size spl/arch/arm/cpu/armv7/sunxi/dram_sun6i.o
 text    data     bss     dec     hex filename
 1983       0       0    1983     7bf

Could we perhaps just introduce something like a new source file "dram_common.c" or even "dram.c"?

Quoted 70 lines
---
 arch/arm/cpu/armv7/sunxi/dram_sun4i.c  | 17 ++---------------
 arch/arm/cpu/armv7/sunxi/dram_sun6i.c  | 31 +++++++++----------------------
 arch/arm/include/asm/arch-sunxi/dram.h | 14 ++++++++++++++
 3 files changed, 25 insertions(+), 37 deletions(-)
arch/arm/cpu/armv7/sunxi/dram_sun4i.c +2 -15
index ec8aaa7..c736fa3 100644
@@ -36,24 +36,11 @@
 #define CPU_CFG_CHIP_REV_B 0x3
 
 /*
- * Wait up to 1s for value to be set in given part of reg.
- */
-static void await_completion(u32 *reg, u32 mask, u32 val)
-{
-	unsigned long tmo = timer_get_us() + 1000000;
-
-	while ((readl(reg) & mask) != val) {
-		if (timer_get_us() > tmo)
-			panic("Timeout initialising DRAM\n");
-	}
-}
-
-/*
  * Wait up to 1s for mask to be clear in given reg.
  */
 static inline void await_bits_clear(u32 *reg, u32 mask)
 {
-	await_completion(reg, mask, 0);
+	mctl_await_completion(reg, mask, 0);
 }
 
 /*
@@ -61,7 +48,7 @@ static inline void await_bits_clear(u32 *reg, u32 mask)
  */
 static inline void await_bits_set(u32 *reg, u32 mask)
 {
-	await_completion(reg, mask, mask);
+	mctl_await_completion(reg, mask, mask);
 }
 
 /*
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +0 -13
index a8bbdfd..e1670e5 100644
@@ -27,19 +27,6 @@ struct dram_sun6i_para {
 	u16 page_size;
 };
 
-/*
- * Wait up to 1s for value to be set in given part of reg.
- */
-static void await_completion(u32 *reg, u32 mask, u32 val)
-{
-	unsigned long tmo = timer_get_us() + 1000000;
-
-	while ((readl(reg) & mask) != val) {
-		if (timer_get_us() > tmo)
-			panic("Timeout initialising DRAM\n");
-	}
-}
-
 static void mctl_sys_init(void)
 {
 	struct sunxi_ccm_reg * const ccm =

arch/arm/cpu/armv7/sunxi/dram_sun6i.c static void mctl_sys_init(void) · line 41

Quoted 5 lines
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +1 -1
@@ -51,7 +38,7 @@ static void mctl_sys_init(void)
 	clrsetbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_DIV0_MASK,
 		CCM_DRAMCLK_CFG_DIV0(dram_clk_div) | CCM_DRAMCLK_CFG_RST |
 		CCM_DRAMCLK_CFG_UPD);
-	await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);
+	mctl_await_completion(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_UPD, 0);

As an additional observation, moving await_bits_clear/await_bits_set functions into a common header file and using them in the sun6i dram code might improve readability.

Quoted 95 lines
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +8 -8
 	writel(MDFS_CLK_DEFAULT, &ccm->mdfs_clk_cfg);
 
@@ -107,8 +94,8 @@ static bool mctl_rank_detect(u32 *gsr0, int rank)
 	const u32 done = MCTL_DX_GSR0_RANK0_TRAIN_DONE << rank;
 	const u32 err = MCTL_DX_GSR0_RANK0_TRAIN_ERR << rank;
 
-	await_completion(gsr0, done, done);
-	await_completion(gsr0 + 0x10, done, done);
+	mctl_await_completion(gsr0, done, done);
+	mctl_await_completion(gsr0 + 0x10, done, done);
 
 	return !(readl(gsr0) & err) && !(readl(gsr0 + 0x10) & err);
 }
@@ -129,7 +116,7 @@ static void mctl_channel_init(int ch_index, struct dram_sun6i_para *para)
 	}
 
 	writel(MCTL_MCMD_NOP, &mctl_ctl->mcmd);
-	await_completion(&mctl_ctl->mcmd, MCTL_MCMD_BUSY, 0);
+	mctl_await_completion(&mctl_ctl->mcmd, MCTL_MCMD_BUSY, 0);
 
 	/* PHY initialization */
 	writel(MCTL_PGCR, &mctl_phy->pgcr);
@@ -166,14 +153,14 @@ static void mctl_channel_init(int ch_index, struct dram_sun6i_para *para)
 	writel(MCTL_DX_GCR | MCTL_DX_GCR_EN, &mctl_phy->dx2gcr);
 	writel(MCTL_DX_GCR | MCTL_DX_GCR_EN, &mctl_phy->dx3gcr);
 
-	await_completion(&mctl_phy->pgsr, 0x03, 0x03);
+	mctl_await_completion(&mctl_phy->pgsr, 0x03, 0x03);
 
 	writel(CONFIG_DRAM_ZQ, &mctl_phy->zq0cr1);
 
 	setbits_le32(&mctl_phy->pir, MCTL_PIR_CLEAR_STATUS);
 	writel(MCTL_PIR_STEP1, &mctl_phy->pir);
 	udelay(10);
-	await_completion(&mctl_phy->pgsr, 0x1f, 0x1f);
+	mctl_await_completion(&mctl_phy->pgsr, 0x1f, 0x1f);
 
 	/* rank detect */
 	if (!mctl_rank_detect(&mctl_phy->dx0gsr0, 1)) {
@@ -204,14 +191,14 @@ static void mctl_channel_init(int ch_index, struct dram_sun6i_para *para)
 	setbits_le32(&mctl_phy->pir, MCTL_PIR_CLEAR_STATUS);
 	writel(MCTL_PIR_STEP2, &mctl_phy->pir);
 	udelay(10);
-	await_completion(&mctl_phy->pgsr, 0x11, 0x11);
+	mctl_await_completion(&mctl_phy->pgsr, 0x11, 0x11);
 
 	if (readl(&mctl_phy->pgsr) & MCTL_PGSR_TRAIN_ERR_MASK)
 		panic("Training error initialising DRAM\n");
 
 	/* Move to configure state */
 	writel(MCTL_SCTL_CONFIG, &mctl_ctl->sctl);
-	await_completion(&mctl_ctl->sstat, 0x07, 0x01);
+	mctl_await_completion(&mctl_ctl->sstat, 0x07, 0x01);
 
 	/* Set number of clks per micro-second */
 	writel(DRAM_CLK / 1000000, &mctl_ctl->togcnt1u);
@@ -270,7 +257,7 @@ static void mctl_channel_init(int ch_index, struct dram_sun6i_para *para)
 
 	/* Move to access state */
 	writel(MCTL_SCTL_ACCESS, &mctl_ctl->sctl);
-	await_completion(&mctl_ctl->sstat, 0x07, 0x03);
+	mctl_await_completion(&mctl_ctl->sstat, 0x07, 0x03);
 }
 
 static void mctl_com_init(struct dram_sun6i_para *para)
arch/arm/include/asm/arch-sunxi/dram.h +14 -0
index 9072e68..18924f5 100644
@@ -12,6 +12,7 @@
 #ifndef _SUNXI_DRAM_H
 #define _SUNXI_DRAM_H
 
+#include <asm/io.h>
 #include <linux/types.h>
 
 /* dram regs definition */
@@ -23,4 +24,17 @@
 
 unsigned long sunxi_dram_init(void);
 
+/*
+ * Wait up to 1s for value to be set in given part of reg.
+ */
+static inline void mctl_await_completion(u32 *reg, u32 mask, u32 val)
+{
+	unsigned long tmo = timer_get_us() + 1000000;
+
+	while ((readl(reg) & mask) != val) {
+		if (timer_get_us() > tmo)
+			panic("Timeout initialising DRAM\n");
+	}
+}
+
 #endif /* _SUNXI_DRAM_H */
Signature · 2 lines
Best regards,
Siarhei Siamashka
#30 lore raw

PATCH 10/14 sunxi: Move await_completion dram helper to dram.h

Hi,

Quoted 26 lines · Siarhei Siamashka
Quoted 5 lines · On Tue, 16 Dec 2014 21:31:35 +0100 Hans de Goede <[email protected]> wrote:

The await_completion helper is already copy pasted between the sun4i and sun6i dram code, and we need it for sun8i too, so lets make it an inline helper in dram.h, rather then adding yet another copy.

Making this function "static inline" and placing it into a header file encourages the compiler to actually inline it. Which is not great for code size:

== Before the patch and using gcc version 4.8.3 ==

$ arm-none-linux-gnieabi-size spl/arch/arm/cpu/armv7/sunxi/dram_sun4i.o
  text    data     bss     dec     hex filename
  1731       0       0    1731     6c3
$ arm-none-linux-gnieabi-size spl/arch/arm/cpu/armv7/sunxi/dram_sun6i.o
  text    data     bss     dec     hex filename
  1841       0       0    1841     731

== After the patch and using gcc version 4.8.3 ==

Quoted 7 lines
$ arm-none-linux-gnieabi-size spl/arch/arm/cpu/armv7/sunxi/dram_sun4i.o
  text    data     bss     dec     hex filename
  1763       0       0    1763     6e3
$ arm-none-linux-gnieabi-size spl/arch/arm/cpu/armv7/sunxi/dram_sun6i.o
  text    data     bss     dec     hex filename
  1983       0       0    1983     7bf

Ah, thanks for catching that, the size increase does not seem to be a problem right now, but it certainly is something to keep in mind.

Quoted 2 lines

Could we perhaps just introduce something like a new source file "dram_common.c" or even "dram.c"?

Sounds like a good idea, patches welcome.

Quoted 3 lines

As an additional observation, moving await_bits_clear/await_bits_set functions into a common header file and using them in the sun6i dram code might improve readability.

Sounds like another good idea, patches welcome.

Regards,

Hans

#31 lore raw

PATCH 10/14 sunxi: Move await_completion dram helper to dram.h

Quoted 37 lines · On Fri, 19 Dec 2014 17:42:58 +0100 Hans de Goede <[email protected]> wrote:

Hi,

Quoted 26 lines · Siarhei Siamashka
Quoted 5 lines · On Tue, 16 Dec 2014 21:31:35 +0100 Hans de Goede <[email protected]> wrote:

The await_completion helper is already copy pasted between the sun4i and sun6i dram code, and we need it for sun8i too, so lets make it an inline helper in dram.h, rather then adding yet another copy.

Making this function "static inline" and placing it into a header file encourages the compiler to actually inline it. Which is not great for code size:

== Before the patch and using gcc version 4.8.3 ==

$ arm-none-linux-gnieabi-size spl/arch/arm/cpu/armv7/sunxi/dram_sun4i.o
  text    data     bss     dec     hex filename
  1731       0       0    1731     6c3
$ arm-none-linux-gnieabi-size spl/arch/arm/cpu/armv7/sunxi/dram_sun6i.o
  text    data     bss     dec     hex filename
  1841       0       0    1841     731

== After the patch and using gcc version 4.8.3 ==

Quoted 7 lines
$ arm-none-linux-gnieabi-size spl/arch/arm/cpu/armv7/sunxi/dram_sun4i.o
  text    data     bss     dec     hex filename
  1763       0       0    1763     6e3
$ arm-none-linux-gnieabi-size spl/arch/arm/cpu/armv7/sunxi/dram_sun6i.o
  text    data     bss     dec     hex filename
  1983       0       0    1983     7bf
Quoted 7 lines

Ah, thanks for catching that, the size increase does not seem to be a problem right now, but it certainly is something to keep in mind.

Quoted 2 lines

Could we perhaps just introduce something like a new source file "dram_common.c" or even "dram.c"?

Sounds like a good idea, patches welcome.

I would definitely appreciate if we could have avoided having this unnecessary code size increase in the first place.

But if we run out of the code size space, then the oversized static inline functions in the headers are always relatively easy to identify and eliminate in one go. That's only a minor annoyance and I'm not going to waste time on pointless debates.

Quoted 5 lines
Quoted 3 lines

As an additional observation, moving await_bits_clear/await_bits_set functions into a common header file and using them in the sun6i dram code might improve readability.

Sounds like another good idea, patches welcome.

Signature · 2 lines
Best regards,
Siarhei Siamashka
#32 lore raw

PATCH 11/14 sunxi: Fill memory before comparing it when doing dram init on sun6i

In reply to Hans de Goede

The sun8i boot0 code fills the DRAM with a "random" pattern before comparing it at different offsets to do columns, etc. detection. The sun6i boot0 code does not do it, but it seems like a good idea to do this regardless.

The new mctl_mem_fill function this introduces is added as an inline helper in dram.h, so that it can be shared with the sun8i dram code.

While at it move mctl_mem_matches to dram.h for re-use in sun8i too.

---
 arch/arm/cpu/armv7/sunxi/dram_sun6i.c  | 15 +--------------
 arch/arm/include/asm/arch-sunxi/dram.h | 29 +++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 14 deletions(-)
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +1 -14
index e1670e5..4675c48 100644
@@ -326,20 +326,6 @@ static void mctl_port_cfg(void)
 	writel(0x00000307, &mctl_com->mbagcr[5]);
 }
 
-static bool mctl_mem_matches(u32 offset)
-{
-	const int match_count = 64;
-	int i, matches = 0;
-
-	for (i = 0; i < match_count; i++) {
-		if (readl(CONFIG_SYS_SDRAM_BASE + i * 4) ==
-		    readl(CONFIG_SYS_SDRAM_BASE + offset + i * 4))
-			matches++;
-	}
-
-	return matches == match_count;
-}
-
 unsigned long sunxi_dram_init(void)
 {
 	struct sunxi_mctl_com_reg * const mctl_com =
@@ -391,6 +377,7 @@ unsigned long sunxi_dram_init(void)
 		    MCTL_CR_BANK(1) | MCTL_CR_RANK(1));
 
 	/* Detect and set page size */
+	mctl_mem_fill();
 	for (columns = 7; columns < 20; columns++) {
 		if (mctl_mem_matches(1 << columns))
 			break;
arch/arm/include/asm/arch-sunxi/dram.h +29 -0
index 18924f5..0bf718c 100644
@@ -22,6 +22,8 @@
 #include <asm/arch/dram_sun4i.h>
 #endif
 
+#define MCTL_MEM_FILL_MATCH_COUNT 64
+
 unsigned long sunxi_dram_init(void);
 
 /*
@@ -37,4 +39,31 @@ static inline void mctl_await_completion(u32 *reg, u32 mask, u32 val)
 	}
 }
 
+/*
+ * Fill beginning of DRAM with "random" data for mctl_mem_matches()
+ */
+static inline void mctl_mem_fill(void)
+{
+	int i;
+
+	for (i = 0; i < MCTL_MEM_FILL_MATCH_COUNT; i++)
+		writel(0xaa55aa55 + i, CONFIG_SYS_SDRAM_BASE + i * 4);
+}
+
+/*
+ * Test if memory at offset offset matches memory@begin of DRAM
+ */
+static inline bool mctl_mem_matches(u32 offset)
+{
+	int i, matches = 0;
+
+	for (i = 0; i < MCTL_MEM_FILL_MATCH_COUNT; i++) {
+		if (readl(CONFIG_SYS_SDRAM_BASE + i * 4) ==
+		    readl(CONFIG_SYS_SDRAM_BASE + offset + i * 4))
+			matches++;
+	}
+
+	return matches == MCTL_MEM_FILL_MATCH_COUNT;
+}
+
 #endif /* _SUNXI_DRAM_H */
Signature · 1 line
2.1.0
#33 lore raw

PATCH 11/14 sunxi: Fill memory before comparing it when doing dram init on sun6i

Quoted 3 lines · Hans de Goede

The sun8i boot0 code fills the DRAM with a "random" pattern before comparing it at different offsets to do columns, etc. detection. The sun6i boot0 code does not do it, but it seems like a good idea to do this regardless.

Is this the right way round? The existing sun6i code (which you are moving here) seems to _rely_ on something having written a useful pattern, which I would have assumed to have been boot0. Or else how does it work now? Chance?

Quoted 89 lines

The new mctl_mem_fill function this introduces is added as an inline helper in dram.h, so that it can be shared with the sun8i dram code.

While at it move mctl_mem_matches to dram.h for re-use in sun8i too.

---
 arch/arm/cpu/armv7/sunxi/dram_sun6i.c  | 15 +--------------
 arch/arm/include/asm/arch-sunxi/dram.h | 29 +++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 14 deletions(-)
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +1 -14
index e1670e5..4675c48 100644
@@ -326,20 +326,6 @@ static void mctl_port_cfg(void)
 	writel(0x00000307, &mctl_com->mbagcr[5]);
 }
 
-static bool mctl_mem_matches(u32 offset)
-{
-	const int match_count = 64;
-	int i, matches = 0;
-
-	for (i = 0; i < match_count; i++) {
-		if (readl(CONFIG_SYS_SDRAM_BASE + i * 4) ==
-		    readl(CONFIG_SYS_SDRAM_BASE + offset + i * 4))
-			matches++;
-	}
-
-	return matches == match_count;
-}
-
 unsigned long sunxi_dram_init(void)
 {
 	struct sunxi_mctl_com_reg * const mctl_com =
@@ -391,6 +377,7 @@ unsigned long sunxi_dram_init(void)
 		    MCTL_CR_BANK(1) | MCTL_CR_RANK(1));
 
 	/* Detect and set page size */
+	mctl_mem_fill();
 	for (columns = 7; columns < 20; columns++) {
 		if (mctl_mem_matches(1 << columns))
 			break;
arch/arm/include/asm/arch-sunxi/dram.h +29 -0
index 18924f5..0bf718c 100644
@@ -22,6 +22,8 @@
 #include <asm/arch/dram_sun4i.h>
 #endif
 
+#define MCTL_MEM_FILL_MATCH_COUNT 64
+
 unsigned long sunxi_dram_init(void);
 
 /*
@@ -37,4 +39,31 @@ static inline void mctl_await_completion(u32 *reg, u32 mask, u32 val)
 	}
 }
 
+/*
+ * Fill beginning of DRAM with "random" data for mctl_mem_matches()
+ */
+static inline void mctl_mem_fill(void)
+{
+	int i;
+
+	for (i = 0; i < MCTL_MEM_FILL_MATCH_COUNT; i++)
+		writel(0xaa55aa55 + i, CONFIG_SYS_SDRAM_BASE + i * 4);
+}
+
+/*
+ * Test if memory at offset offset matches memory at begin of DRAM
+ */
+static inline bool mctl_mem_matches(u32 offset)
+{
+	int i, matches = 0;
+
+	for (i = 0; i < MCTL_MEM_FILL_MATCH_COUNT; i++) {
+		if (readl(CONFIG_SYS_SDRAM_BASE + i * 4) ==
+		    readl(CONFIG_SYS_SDRAM_BASE + offset + i * 4))
+			matches++;
+	}
+
+	return matches == MCTL_MEM_FILL_MATCH_COUNT;
+}
+
 #endif /* _SUNXI_DRAM_H */
#34 lore raw

PATCH 11/14 sunxi: Fill memory before comparing it when doing dram init on sun6i

Quoted 9 lines · On Thu, 18 Dec 2014 19:12:13 +0000 Ian Campbell <[email protected]> wrote:
Quoted 3 lines · Hans de Goede

The sun8i boot0 code fills the DRAM with a "random" pattern before comparing it at different offsets to do columns, etc. detection. The sun6i boot0 code does not do it, but it seems like a good idea to do this regardless.

Is this the right way round? The existing sun6i code (which you are moving here) seems to _rely_ on something having written a useful pattern, which I would have assumed to have been boot0. Or else how does it work now? Chance?

It appears that this code is just trying to find the first address line, which is not connected anywhere. If the address line is not connected, then having the corresponding bit set or clear in the memory address does not matter and we are effectively accessing the same location.

Both sun6i and sun8i code is incorrect and only works because of relying on luck.

The sun6i code is incorrect because it is just reading memory without initializing it at all. Probably relying on having some unique garbage there in a natural way.

The newer sun8i code is still incorrect because it is not safeguarding against accidentally encountering the same test pattern at an unrelated memory location. Yes, the probability is extremely low, but still not zero.

It's a good idea to have a look at the 'get_ram_size' function for the inspiration.

Quoted 89 lines
Quoted 89 lines

The new mctl_mem_fill function this introduces is added as an inline helper in dram.h, so that it can be shared with the sun8i dram code.

While at it move mctl_mem_matches to dram.h for re-use in sun8i too.

---
 arch/arm/cpu/armv7/sunxi/dram_sun6i.c  | 15 +--------------
 arch/arm/include/asm/arch-sunxi/dram.h | 29 +++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 14 deletions(-)
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +1 -14
index e1670e5..4675c48 100644
@@ -326,20 +326,6 @@ static void mctl_port_cfg(void)
 	writel(0x00000307, &mctl_com->mbagcr[5]);
 }
 
-static bool mctl_mem_matches(u32 offset)
-{
-	const int match_count = 64;
-	int i, matches = 0;
-
-	for (i = 0; i < match_count; i++) {
-		if (readl(CONFIG_SYS_SDRAM_BASE + i * 4) ==
-		    readl(CONFIG_SYS_SDRAM_BASE + offset + i * 4))
-			matches++;
-	}
-
-	return matches == match_count;
-}
-
 unsigned long sunxi_dram_init(void)
 {
 	struct sunxi_mctl_com_reg * const mctl_com =
@@ -391,6 +377,7 @@ unsigned long sunxi_dram_init(void)
 		    MCTL_CR_BANK(1) | MCTL_CR_RANK(1));
 
 	/* Detect and set page size */
+	mctl_mem_fill();
 	for (columns = 7; columns < 20; columns++) {
 		if (mctl_mem_matches(1 << columns))
 			break;
arch/arm/include/asm/arch-sunxi/dram.h +29 -0
index 18924f5..0bf718c 100644
@@ -22,6 +22,8 @@
 #include <asm/arch/dram_sun4i.h>
 #endif
 
+#define MCTL_MEM_FILL_MATCH_COUNT 64
+
 unsigned long sunxi_dram_init(void);
 
 /*
@@ -37,4 +39,31 @@ static inline void mctl_await_completion(u32 *reg, u32 mask, u32 val)
 	}
 }
 
+/*
+ * Fill beginning of DRAM with "random" data for mctl_mem_matches()
+ */
+static inline void mctl_mem_fill(void)
+{
+	int i;
+
+	for (i = 0; i < MCTL_MEM_FILL_MATCH_COUNT; i++)
+		writel(0xaa55aa55 + i, CONFIG_SYS_SDRAM_BASE + i * 4);
+}
+
+/*
+ * Test if memory at offset offset matches memory at begin of DRAM
+ */
+static inline bool mctl_mem_matches(u32 offset)
+{
+	int i, matches = 0;
+
+	for (i = 0; i < MCTL_MEM_FILL_MATCH_COUNT; i++) {
+		if (readl(CONFIG_SYS_SDRAM_BASE + i * 4) ==
+		    readl(CONFIG_SYS_SDRAM_BASE + offset + i * 4))
+			matches++;
+	}
+
+	return matches == MCTL_MEM_FILL_MATCH_COUNT;
+}
+
 #endif /* _SUNXI_DRAM_H */
Signature · 2 lines
Best regards,
Siarhei Siamashka
#35 lore raw

PATCH 11/14 sunxi: Fill memory before comparing it when doing dram init on sun6i

Hi,

Quoted 13 lines · Siarhei Siamashka
Quoted 9 lines · On Thu, 18 Dec 2014 19:12:13 +0000 Ian Campbell <[email protected]> wrote:
Quoted 3 lines · Hans de Goede

The sun8i boot0 code fills the DRAM with a "random" pattern before comparing it at different offsets to do columns, etc. detection. The sun6i boot0 code does not do it, but it seems like a good idea to do this regardless.

Is this the right way round? The existing sun6i code (which you are moving here) seems to _rely_ on something having written a useful pattern, which I would have assumed to have been boot0. Or else how does it work now? Chance?

Quoted 4 lines

It appears that this code is just trying to find the first address line, which is not connected anywhere. If the address line is not connected, then having the corresponding bit set or clear in the memory address does not matter and we are effectively accessing the same location.

Correct.

Quoted 11 lines

Both sun6i and sun8i code is incorrect and only works because of relying on luck.

The sun6i code is incorrect because it is just reading memory without initializing it at all. Probably relying on having some unique garbage there in a natural way.

The newer sun8i code is still incorrect because it is not safeguarding against accidentally encountering the same test pattern at an unrelated memory location. Yes, the probability is extremely low, but still not zero.

The probability is so low that it really does not matter, so I've no intention to fix this.

Regards,

Hans

#36 lore raw

PATCH 11/14 sunxi: Fill memory before comparing it when doing dram init on sun6i

Quoted 30 lines · On Fri, 19 Dec 2014 17:56:40 +0100 Hans de Goede <[email protected]> wrote:

Hi,

Quoted 13 lines · Siarhei Siamashka
Quoted 9 lines · On Thu, 18 Dec 2014 19:12:13 +0000 Ian Campbell <[email protected]> wrote:
Quoted 3 lines · Hans de Goede

The sun8i boot0 code fills the DRAM with a "random" pattern before comparing it at different offsets to do columns, etc. detection. The sun6i boot0 code does not do it, but it seems like a good idea to do this regardless.

Is this the right way round? The existing sun6i code (which you are moving here) seems to _rely_ on something having written a useful pattern, which I would have assumed to have been boot0. Or else how does it work now? Chance?

Quoted 4 lines

It appears that this code is just trying to find the first address line, which is not connected anywhere. If the address line is not connected, then having the corresponding bit set or clear in the memory address does not matter and we are effectively accessing the same location.

Correct.

Quoted 7 lines

Both sun6i and sun8i code is incorrect and only works because of relying on luck.

The sun6i code is incorrect because it is just reading memory without initializing it at all. Probably relying on having some unique garbage there in a natural way.

Quoted 7 lines
Quoted 4 lines

The newer sun8i code is still incorrect because it is not safeguarding against accidentally encountering the same test pattern at an unrelated memory location. Yes, the probability is extremely low, but still not zero.

The probability is so low that it really does not matter, so I've no intention to fix this.

"If anything bad can happen, it probably will" :-)

There are many real life examples, when something supposedly almost impossible has in fact happened. Like the following story:
http://ixbtlabs.com/articles2/magia-chisel/
In a nutshell, the designers of some old CD/CD-RW drives just did not bother to ensure that the written user data can be never confused with the service information (sync headers) on disk. The probability of encountering something that resembles a sync header was considered to be way too low. Well, until somebody has encountered a hardware glitch and a sync header fragment got mistakenly read from the drive as part of some file. Now this corrupted file can wreak havoc if written to a CD disk, because the false sync header in it is getting interpreted as an actual sync header. Oops.

Anyway, this is a bug in the sun6i/sun8i dram code. And the submitted patch appears to be only a partial/incomplete fix. A strong NAK from me.

Signature · 2 lines
Best regards,
Siarhei Siamashka
#37 lore raw

PATCH 11/14 sunxi: Fill memory before comparing it when doing dram init on sun6i

In reply to Ian Campbell

Hi,

Quoted 6 lines · Ian Campbell
Quoted 3 lines · Hans de Goede

The sun8i boot0 code fills the DRAM with a "random" pattern before comparing it at different offsets to do columns, etc. detection. The sun6i boot0 code does not do it, but it seems like a good idea to do this regardless.

Is this the right way round?

Yes, while working on the sun8i code I noticed that it was prefilling memory before doing wrap-around checks like the sun6i code is doing too, and then I realized that the sun6i code was relying on whatever is in DRAM being random enough for its wrap-around tests to work, without ensuring it is random enough.

Quoted 4 lines

The existing sun6i code (which you are
moving here) seems to _rely_ on something having written a useful pattern, which I would have assumed to have been boot0. Or else how does it work now? Chance?

Yep, it purely works by chance so far.

Regards,

Hans

Quoted 92 lines
Quoted 90 lines

The new mctl_mem_fill function this introduces is added as an inline helper in dram.h, so that it can be shared with the sun8i dram code.

While at it move mctl_mem_matches to dram.h for re-use in sun8i too.

---
  arch/arm/cpu/armv7/sunxi/dram_sun6i.c  | 15 +--------------
  arch/arm/include/asm/arch-sunxi/dram.h | 29 +++++++++++++++++++++++++++++
  2 files changed, 30 insertions(+), 14 deletions(-)
arch/arm/cpu/armv7/sunxi/dram_sun6i.c +1 -14
index e1670e5..4675c48 100644
@@ -326,20 +326,6 @@ static void mctl_port_cfg(void)
  	writel(0x00000307, &mctl_com->mbagcr[5]);
  }
 
-static bool mctl_mem_matches(u32 offset)
-{
-	const int match_count = 64;
-	int i, matches = 0;
-
-	for (i = 0; i < match_count; i++) {
-		if (readl(CONFIG_SYS_SDRAM_BASE + i * 4) ==
-		    readl(CONFIG_SYS_SDRAM_BASE + offset + i * 4))
-			matches++;
-	}
-
-	return matches == match_count;
-}
-
  unsigned long sunxi_dram_init(void)
  {
  	struct sunxi_mctl_com_reg * const mctl_com =
@@ -391,6 +377,7 @@ unsigned long sunxi_dram_init(void)
  		    MCTL_CR_BANK(1) | MCTL_CR_RANK(1));
 
  	/* Detect and set page size */
+	mctl_mem_fill();
  	for (columns = 7; columns < 20; columns++) {
  		if (mctl_mem_matches(1 << columns))
  			break;
arch/arm/include/asm/arch-sunxi/dram.h +29 -0
index 18924f5..0bf718c 100644
@@ -22,6 +22,8 @@
  #include <asm/arch/dram_sun4i.h>
  #endif
 
+#define MCTL_MEM_FILL_MATCH_COUNT 64
+
  unsigned long sunxi_dram_init(void);
 
  /*
@@ -37,4 +39,31 @@ static inline void mctl_await_completion(u32 *reg, u32 mask, u32 val)
  	}
  }
 
+/*
+ * Fill beginning of DRAM with "random" data for mctl_mem_matches()
+ */
+static inline void mctl_mem_fill(void)
+{
+	int i;
+
+	for (i = 0; i < MCTL_MEM_FILL_MATCH_COUNT; i++)
+		writel(0xaa55aa55 + i, CONFIG_SYS_SDRAM_BASE + i * 4);
+}
+
+/*
+ * Test if memory at offset offset matches memory at begin of DRAM
+ */
+static inline bool mctl_mem_matches(u32 offset)
+{
+	int i, matches = 0;
+
+	for (i = 0; i < MCTL_MEM_FILL_MATCH_COUNT; i++) {
+		if (readl(CONFIG_SYS_SDRAM_BASE + i * 4) ==
+		    readl(CONFIG_SYS_SDRAM_BASE + offset + i * 4))
+			matches++;
+	}
+
+	return matches == MCTL_MEM_FILL_MATCH_COUNT;
+}
+
  #endif /* _SUNXI_DRAM_H */
#38 lore raw

PATCH 11/14 sunxi: Fill memory before comparing it when doing dram init on sun6i

Quoted 16 lines · Hans de Goede

Hi,

Quoted 6 lines · Ian Campbell
Quoted 3 lines · Hans de Goede

The sun8i boot0 code fills the DRAM with a "random" pattern before comparing it at different offsets to do columns, etc. detection. The sun6i boot0 code does not do it, but it seems like a good idea to do this regardless.

Is this the right way round?

Yes, while working on the sun8i code I noticed that it was prefilling memory before doing wrap-around checks like the sun6i code is doing too, and then I realized that the sun6i code was relying on whatever is in DRAM being random enough for its wrap-around tests to work, without ensuring it is random enough.

Quoted 6 lines
Quoted 4 lines

The existing sun6i code (which you are
moving here) seems to _rely_ on something having written a useful pattern, which I would have assumed to have been boot0. Or else how does it work now? Chance?

Yep, it purely works by chance so far.

"excellent". Can you mention that in the commit message please. With
that: Acked-by: Ian Campbell <[email protected]>

Ian.

#39 lore raw

PATCH 11/14 sunxi: Fill memory before comparing it when doing dram init on sun6i

Quoted 22 lines · On Mon, 22 Dec 2014 14:19:20 +0000 Ian Campbell <[email protected]> wrote:
Quoted 21 lines · Hans de Goede

Hi,

Quoted 6 lines · Ian Campbell
Quoted 3 lines · Hans de Goede

The sun8i boot0 code fills the DRAM with a "random" pattern before comparing it at different offsets to do columns, etc. detection. The sun6i boot0 code does not do it, but it seems like a good idea to do this regardless.

Is this the right way round?

Yes, while working on the sun8i code I noticed that it was prefilling memory before doing wrap-around checks like the sun6i code is doing too, and then I realized that the sun6i code was relying on whatever is in DRAM being random enough for its wrap-around tests to work, without ensuring it is random enough.

Quoted 4 lines

The existing sun6i code (which you are
moving here) seems to _rely_ on something having written a useful pattern, which I would have assumed to have been boot0. Or else how does it work now? Chance?

Quoted 4 lines
Quoted 1 line

Yep, it purely works by chance so far.

"excellent". Can you mention that in the commit message please. With
that: Acked-by: Ian Campbell <[email protected]>

Ian, are you fine with the fact that it still works by chance even after this "fix"? Albeit with a much higher chance of not running into troubles.

Signature · 2 lines
Best regards,
Siarhei Siamashka
#40 lore raw

PATCH 11/14 sunxi: Fill memory before comparing it when doing dram init on sun6i

Quoted 25 lines · Siarhei Siamashka
Quoted 22 lines · On Mon, 22 Dec 2014 14:19:20 +0000 Ian Campbell <[email protected]> wrote:
Quoted 21 lines · Hans de Goede

Hi,

Quoted 6 lines · Ian Campbell
Quoted 3 lines · Hans de Goede

The sun8i boot0 code fills the DRAM with a "random" pattern before comparing it at different offsets to do columns, etc. detection. The sun6i boot0 code does not do it, but it seems like a good idea to do this regardless.

Is this the right way round?

Yes, while working on the sun8i code I noticed that it was prefilling memory before doing wrap-around checks like the sun6i code is doing too, and then I realized that the sun6i code was relying on whatever is in DRAM being random enough for its wrap-around tests to work, without ensuring it is random enough.

Quoted 4 lines

The existing sun6i code (which you are
moving here) seems to _rely_ on something having written a useful pattern, which I would have assumed to have been boot0. Or else how does it work now? Chance?

Quoted 8 lines
Quoted 4 lines
Quoted 1 line

Yep, it purely works by chance so far.

"excellent". Can you mention that in the commit message please. With
that: Acked-by: Ian Campbell <[email protected]>

Ian, are you fine with the fact that it still works by chance even after this "fix"? Albeit with a much higher chance of not running into troubles.

Yes, it's clearly an improvement even if it isn't perfect.

Ian.

#41 lore raw

PATCH 11/14 sunxi: Fill memory before comparing it when doing dram init on sun6i

In reply to Ian Campbell

Hi,

Quoted 17 lines · Ian Campbell
Quoted 16 lines · Hans de Goede

Hi,

Quoted 6 lines · Ian Campbell
Quoted 3 lines · Hans de Goede

The sun8i boot0 code fills the DRAM with a "random" pattern before comparing it at different offsets to do columns, etc. detection. The sun6i boot0 code does not do it, but it seems like a good idea to do this regardless.

Is this the right way round?

Yes, while working on the sun8i code I noticed that it was prefilling memory before doing wrap-around checks like the sun6i code is doing too, and then I realized that the sun6i code was relying on whatever is in DRAM being random enough for its wrap-around tests to work, without ensuring it is random enough.

Quoted 8 lines
Quoted 6 lines
Quoted 4 lines

The existing sun6i code (which you are
moving here) seems to _rely_ on something having written a useful pattern, which I would have assumed to have been boot0. Or else how does it work now? Chance?

Yep, it purely works by chance so far.

"excellent". Can you mention that in the commit message please.

Done.

Quoted 1 line

With that: Acked-by: Ian Campbell <[email protected]>

Thanks, the now fully acked sun8i support patch-set has been pushed to u-boot-sunxi/next .

Thanks for all the reviews!

Regards,

Hans

#42 lore raw

PATCH 12/14 sunxi: Use memcmp for mctl_mem_matches

In reply to Hans de Goede

Use memcmp for mctl_mem_matches instead of DIY.

---
 arch/arm/include/asm/arch-sunxi/dram.h | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)
arch/arm/include/asm/arch-sunxi/dram.h +3 -9
index 0bf718c..a8a37d5 100644
@@ -55,15 +55,9 @@ static inline void mctl_mem_fill(void)
  */
 static inline bool mctl_mem_matches(u32 offset)
 {
-	int i, matches = 0;
-
-	for (i = 0; i < MCTL_MEM_FILL_MATCH_COUNT; i++) {
-		if (readl(CONFIG_SYS_SDRAM_BASE + i * 4) ==
-		    readl(CONFIG_SYS_SDRAM_BASE + offset + i * 4))
-			matches++;
-	}
-
-	return matches == MCTL_MEM_FILL_MATCH_COUNT;
+	return memcmp((u32 *)CONFIG_SYS_SDRAM_BASE,
+		      (u32 *)(CONFIG_SYS_SDRAM_BASE + offset),
+		      MCTL_MEM_FILL_MATCH_COUNT * 4) == 0;
 }
 
 #endif /* _SUNXI_DRAM_H */
Signature · 1 line
2.1.0
#44 lore raw

PATCH 13/14 sun8i: Add dram initialization support

In reply to Hans de Goede

Based on the register / dram_para headers from the Allwinner u-boot / linux sources + the init sequences from boot0.

---
 arch/arm/cpu/armv7/sunxi/Makefile             |   1 +
 arch/arm/cpu/armv7/sunxi/board.c              |   3 +-
 arch/arm/cpu/armv7/sunxi/dram_sun8i.c         | 340 ++++++++++++++++++++++++++
 arch/arm/include/asm/arch-sunxi/clock_sun6i.h |   4 +
 arch/arm/include/asm/arch-sunxi/dram.h        |   2 +
 arch/arm/include/asm/arch-sunxi/dram_sun8i.h  | 266 ++++++++++++++++++++
 board/sunxi/Kconfig                           |   3 +-
 configs/Ippo_q8h_v5_defconfig                 |  17 +-
 include/configs/sun8i.h                       |   2 +
 9 files changed, 631 insertions(+), 7 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/sunxi/dram_sun8i.c
 create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun8i.h
arch/arm/cpu/armv7/sunxi/Makefile +1 -0
index 3e8975a..1e89937 100644
@@ -33,6 +33,7 @@ obj-$(CONFIG_MACH_SUN4I)	+= dram_sun4i.o
 obj-$(CONFIG_MACH_SUN5I)	+= dram_sun4i.o
 obj-$(CONFIG_MACH_SUN6I)	+= dram_sun6i.o
 obj-$(CONFIG_MACH_SUN7I)	+= dram_sun4i.o
+obj-$(CONFIG_MACH_SUN8I)	+= dram_sun8i.o
 ifdef CONFIG_SPL_FEL
 obj-y	+= start.o
 endif
arch/arm/cpu/armv7/sunxi/board.c +2 -1
index 9b3e80c..bc98c56 100644
@@ -114,7 +114,8 @@ void reset_cpu(ulong addr)
 /* do some early init */
 void s_init(void)
 {
-#if defined CONFIG_SPL_BUILD && defined CONFIG_MACH_SUN6I
+#if defined CONFIG_SPL_BUILD && \
+		(defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I)
 	/* Magic (undocmented) value taken from boot0, without this DRAM
 	 * access gets messed up (seems cache related) */
 	setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0x1800);
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +340 -0

340 lines not on this page · raw message

arch/arm/include/asm/arch-sunxi/clock_sun6i.h +4 -0
index 7d61216..45a199c 100644
@@ -273,7 +273,11 @@ struct sunxi_ccm_reg {
 #define CCM_HDMI_CTRL_DDC_GATE		(0x1 << 30)
 #define CCM_HDMI_CTRL_GATE		(0x1 << 31)
 
+#ifndef CONFIG_MACH_SUN8I
 #define MBUS_CLK_DEFAULT		0x81000001 /* PLL6 / 2 */
+#else
+#define MBUS_CLK_DEFAULT		0x81000003 /* PLL6 / 4 */
+#endif
 
 #define CCM_PLL5_PATTERN		0xd1303333
 
arch/arm/include/asm/arch-sunxi/dram.h +2 -0
index a8a37d5..8d78029 100644
@@ -18,6 +18,8 @@
 /* dram regs definition */
 #if defined(CONFIG_MACH_SUN6I)
 #include <asm/arch/dram_sun6i.h>
+#elif defined(CONFIG_MACH_SUN8I)
+#include <asm/arch/dram_sun8i.h>
 #else
 #include <asm/arch/dram_sun4i.h>
 #endif
arch/arm/include/asm/arch-sunxi/dram_sun8i.h new file +266 -0

266 lines not on this page · raw message

board/sunxi/Kconfig +2 -1
index 5bb2f58..5a88ba0 100644
@@ -29,10 +29,11 @@ config MACH_SUN7I
 config MACH_SUN8I
 	bool "sun8i (Allwinner A23)"
 	select CPU_V7
+	select SUPPORT_SPL
 
 endchoice
 
-if MACH_SUN6I
+if MACH_SUN6I || MACH_SUN8I
 
 config DRAM_CLK
 	int "sun6i dram clock speed"
configs/Ippo_q8h_v5_defconfig +12 -5
index 50c2f93..37aa46d 100644
@@ -1,8 +1,15 @@
+CONFIG_SPL=y
 CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
-CONFIG_ARM=y
-CONFIG_ARCH_SUNXI=y
-CONFIG_MACH_SUN8I=y
-CONFIG_TARGET_IPPO_Q8H_V5=y
-CONFIG_DEFAULT_DEVICE_TREE="sun8i-a23-ippo-q8h-v5.dtb"
+CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v5.dtb"
 CONFIG_VIDEO=n
 CONFIG_USB_KEYBOARD=n
++S:CONFIG_ARM=y
++S:CONFIG_ARCH_SUNXI=y
++S:CONFIG_MACH_SUN8I=y
++S:CONFIG_DRAM_CLK=480
+# zq = 0xf777
++S:CONFIG_DRAM_ZQ=63351
+# Wifi power
++S:CONFIG_AXP221_DLDO1_VOLT=3300
+# aldo1 is connected to VCC-IO, VCC-PD, VCC-USB and VCC-HP
++S:CONFIG_AXP221_ALDO1_VOLT=3000
include/configs/sun8i.h +2 -0
index 6f1fc48..792422d 100644
@@ -12,6 +12,8 @@
 /*
  * A23 specific configuration
  */
+#define CONFIG_CLK_FULL_SPEED	1008000000
+
 #define CONFIG_SYS_PROMPT	"sun8i# "
 
 /*
Signature · 1 line
2.1.0
#45 lore raw

PATCH 13/14 sun8i: Add dram initialization support

Quoted 747 lines · Hans de Goede

Based on the register / dram_para headers from the Allwinner u-boot / linux sources + the init sequences from boot0.

---
 arch/arm/cpu/armv7/sunxi/Makefile             |   1 +
 arch/arm/cpu/armv7/sunxi/board.c              |   3 +-
 arch/arm/cpu/armv7/sunxi/dram_sun8i.c         | 340 ++++++++++++++++++++++++++
 arch/arm/include/asm/arch-sunxi/clock_sun6i.h |   4 +
 arch/arm/include/asm/arch-sunxi/dram.h        |   2 +
 arch/arm/include/asm/arch-sunxi/dram_sun8i.h  | 266 ++++++++++++++++++++
 board/sunxi/Kconfig                           |   3 +-
 configs/Ippo_q8h_v5_defconfig                 |  17 +-
 include/configs/sun8i.h                       |   2 +
 9 files changed, 631 insertions(+), 7 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/sunxi/dram_sun8i.c
 create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun8i.h
arch/arm/cpu/armv7/sunxi/Makefile +1 -0
index 3e8975a..1e89937 100644
@@ -33,6 +33,7 @@ obj-$(CONFIG_MACH_SUN4I)      += dram_sun4i.o
 obj-$(CONFIG_MACH_SUN5I)       += dram_sun4i.o
 obj-$(CONFIG_MACH_SUN6I)       += dram_sun6i.o
 obj-$(CONFIG_MACH_SUN7I)       += dram_sun4i.o
+obj-$(CONFIG_MACH_SUN8I)       += dram_sun8i.o
 ifdef CONFIG_SPL_FEL
 obj-y  += start.o
 endif
arch/arm/cpu/armv7/sunxi/board.c +2 -1
index 9b3e80c..bc98c56 100644
@@ -114,7 +114,8 @@ void reset_cpu(ulong addr)
 /* do some early init */
 void s_init(void)
 {
-#if defined CONFIG_SPL_BUILD && defined CONFIG_MACH_SUN6I
+#if defined CONFIG_SPL_BUILD && \
+               (defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I)
        /* Magic (undocmented) value taken from boot0, without this DRAM
         * access gets messed up (seems cache related) */
        setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0x1800);
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +340 -0
new file mode 100644
index 0000000..3736fd1
@@ -0,0 +1,340 @@
+/*
+ * Sun8i platform dram controller init.
+ *
+ * (C) Copyright 2014 Hans de Goede <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/*
+ * Note this code uses a lot of magic hex values, that is because this code
+ * simply replays the init sequence as done by the Allwinner boot0 code, so
+ * we do not know what these values mean. There are no symbolic constants for
+ * these magic values, since we do not know how to name them and making up
+ * names for them is not useful.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/dram.h>
+#include <asm/arch/prcm.h>
+
+static const struct dram_para dram_para = {
+       .clock = CONFIG_DRAM_CLK,
+       .type = 3,
+       .zq = CONFIG_DRAM_ZQ,
+       .odt_en = 1,
+       .para1 = 0, /* not used (only used when tpr13 bit 31 is set */
+       .para2 = 0, /* not used (only used when tpr13 bit 31 is set */
+       .mr0 = 6736,
+       .mr1 = 4,
+       .mr2 = 16,
+       .mr3 = 0,
+       /* tpr0 - 10 contain timing constants or-ed together in u32 vals */
+       .tpr0 = 0x2ab83def,
+       .tpr1 = 0x18082356,
+       .tpr2 = 0x00034156,
+       .tpr3 = 0x448c5533,
+       .tpr4 = 0x08010d00,
+       .tpr5 = 0x0340b20f,
+       .tpr6 = 0x20d118cc,
+       .tpr7 = 0x14062485,
+       .tpr8 = 0x220d1d52,
+       .tpr9 = 0x1e078c22,
+       .tpr10 = 0x3c,
+       .tpr11 = 0, /* not used */
+       .tpr12 = 0, /* not used */
+       .tpr13 = 0x30000,
+};
+
+static void mctl_sys_init(void)
+{
+       struct sunxi_ccm_reg * const ccm =
+               (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+       /* enable pll5, note the divide by 2 is deliberate! */
+       clock_set_pll5(dram_para.clock * 1000000 / 2, 1, 2,
+                      dram_para.tpr13 & 0x40000);
+
+       /* deassert ahb mctl reset */
+       setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
+
+       /* enable ahb mctl clock */
+       setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
+}
+
+static void mctl_apply_odt_correction(u32 *reg, int correction)
+{
+       int val;
+
+       val = (readl(reg) >> 8) & 0xff;
+       val += correction;
+
+       /* clamp */
+       if (val < 0)
+               val = 0;
+       else if (val > 255)
+               val = 255;
+
+       clrsetbits_le32(reg, 0xff00, val << 8);
+}
+
+static void mctl_init(u32 *bus_width)
+{
+       struct sunxi_ccm_reg * const ccm =
+               (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+       struct sunxi_mctl_com_reg * const mctl_com =
+               (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;
+       struct sunxi_mctl_phy_reg * const mctl_phy =
+               (struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
+       int correction;
+
+       if (dram_para.tpr13 & 0x20)
+               writel(0x40b, &mctl_phy->dcr);
+       else
+               writel(0x1000040b, &mctl_phy->dcr);
+
+       if (dram_para.clock >= 480)
+               writel(0x5c000, &mctl_phy->dllgcr);
+       else
+               writel(0xdc000, &mctl_phy->dllgcr);
+
+       writel(0x0a003e3f, &mctl_phy->pgcr0);
+       writel(0x03008421, &mctl_phy->pgcr1);
+
+       writel(dram_para.mr0, &mctl_phy->mr0);
+       writel(dram_para.mr1, &mctl_phy->mr1);
+       writel(dram_para.mr2, &mctl_phy->mr2);
+       writel(dram_para.mr3, &mctl_phy->mr3);
+
+       if (!(dram_para.tpr13 & 0x10000)) {
+               clrsetbits_le32(&mctl_phy->dx0gcr, 0x3800, 0x2000);
+               clrsetbits_le32(&mctl_phy->dx1gcr, 0x3800, 0x2000);
+       }
+
+       /*
+        * All the masking and shifting below converts what I assume are DDR
+        * timing constants from Allwinner dram_para tpr format to the actual
+        * timing registers format.
+        */
+
+       writel((dram_para.tpr0 & 0x000fffff), &mctl_phy->ptr2);
+       writel((dram_para.tpr1 & 0x1fffffff), &mctl_phy->ptr3);
+       writel((dram_para.tpr0 & 0x3ff00000) >> 2 |
+              (dram_para.tpr2 & 0x0003ffff), &mctl_phy->ptr4);
+
+       writel(dram_para.tpr3, &mctl_phy->dtpr0);
+       writel(dram_para.tpr4, &mctl_phy->dtpr2);
+
+       writel(0x01000081, &mctl_phy->dtcr);
+
+       if (dram_para.clock <= 240 || !(dram_para.odt_en & 0x01)) {
+               clrbits_le32(&mctl_phy->dx0gcr, 0x600);
+               clrbits_le32(&mctl_phy->dx1gcr, 0x600);
+       }
+       if (dram_para.clock <= 240) {
+               writel(0, &mctl_phy->odtcr);
+               writel(0, &mctl_ctl->odtmap);
+       }
+
+       writel(((dram_para.tpr5 & 0x0f00) << 12) |
+              ((dram_para.tpr5 & 0x00f8) <<  9) |
+              ((dram_para.tpr5 & 0x0007) <<  8),
+              &mctl_ctl->rfshctl0);
+
+       writel(((dram_para.tpr5 & 0x0003f000) << 12) |
+              ((dram_para.tpr5 & 0x00fc0000) >>  2) |
+              ((dram_para.tpr5 & 0x3f000000) >> 16) |
+              ((dram_para.tpr6 & 0x0000003f) >>  0),
+              &mctl_ctl->dramtmg0);
+
+       writel(((dram_para.tpr6 & 0x000007c0) << 10) |
+              ((dram_para.tpr6 & 0x0000f800) >> 3) |
+              ((dram_para.tpr6 & 0x003f0000) >> 16),
+              &mctl_ctl->dramtmg1);
+
+       writel(((dram_para.tpr6 & 0x0fc00000) << 2) |
+              ((dram_para.tpr7 & 0x0000001f) << 16) |
+              ((dram_para.tpr7 & 0x000003e0) << 3) |
+              ((dram_para.tpr7 & 0x0000fc00) >> 10),
+              &mctl_ctl->dramtmg2);
+
+       writel(((dram_para.tpr7 & 0x03ff0000) >> 16) |
+              ((dram_para.tpr6 & 0xf0000000) >> 16),
+              &mctl_ctl->dramtmg3);
+
+       writel(((dram_para.tpr7 & 0x3c000000) >> 2 ) |
+              ((dram_para.tpr8 & 0x00000007) << 16) |
+              ((dram_para.tpr8 & 0x00000038) << 5) |
+              ((dram_para.tpr8 & 0x000003c0) >> 6),
+              &mctl_ctl->dramtmg4);
+
+       writel(((dram_para.tpr8 & 0x00003c00) << 14) |
+              ((dram_para.tpr8 & 0x0003c000) <<  2) |
+              ((dram_para.tpr8 & 0x00fc0000) >> 10) |
+              ((dram_para.tpr8 & 0x0f000000) >> 24),
+              &mctl_ctl->dramtmg5);
+
+       writel(0x00000008, &mctl_ctl->dramtmg8);
+
+       writel(((dram_para.tpr8 & 0xf0000000) >> 4) |
+              ((dram_para.tpr9 & 0x00007c00) << 6) |
+              ((dram_para.tpr9 & 0x000003e0) << 3) |
+              ((dram_para.tpr9 & 0x0000001f) >> 0),
+              &mctl_ctl->pitmg0);
+
+       setbits_le32(&mctl_ctl->pitmg1, 0x80000);
+
+       writel(((dram_para.tpr9 & 0x003f8000) << 9) | 0x2001,
+              &mctl_ctl->sched);
+
+       writel((dram_para.mr0 << 16) | dram_para.mr1, &mctl_ctl->init3);
+       writel((dram_para.mr2 << 16) | dram_para.mr3, &mctl_ctl->init4);
+
+       writel(0x00000000, &mctl_ctl->pimisc);
+       writel(0x80000000, &mctl_ctl->upd0);
+
+       writel(((dram_para.tpr9  & 0xffc00000) >> 22) |
+              ((dram_para.tpr10 & 0x00000fff) << 16),
+              &mctl_ctl->rfshtmg);
+
+       if (dram_para.tpr13 & 0x20)
+               writel(0x01040001, &mctl_ctl->mstr);
+       else
+               writel(0x01040401, &mctl_ctl->mstr);
+
+       if (!(dram_para.tpr13 & 0x20000)) {
+               writel(0x00000002, &mctl_ctl->pwrctl);
+               writel(0x00008001, &mctl_ctl->pwrtmg);
+       }
+
+       writel(0x00000001, &mctl_ctl->rfshctl3);
+       writel(0x00000001, &mctl_ctl->pimisc);
+
+       /* deassert dram_clk_cfg reset */
+       setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
+
+       setbits_le32(&mctl_com->ccr, 0x80000);
+
+       /* zq stuff */
+       writel((dram_para.zq >> 8) & 0xff, &mctl_phy->zqcr1);
+
+       writel(0x00000003, &mctl_phy->pir);
+       udelay(10);
+       mctl_await_completion(&mctl_phy->pgsr0, 0x09, 0x09);
+
+       writel(readl(&mctl_phy->zqsr0) | 0x10000000, &mctl_phy->zqcr2);
+       writel(dram_para.zq & 0xff, &mctl_phy->zqcr1);
+
+       /* A23-v1.0 SDK uses 0xfdf3, A23-v2.0 SDK uses 0x5f3 */
+       writel(0x000005f3, &mctl_phy->pir);
+       udelay(10);
+       mctl_await_completion(&mctl_phy->pgsr0, 0x03, 0x03);
+
+       if (readl(&mctl_phy->dx1gsr0) & 0x1000000) {
+               *bus_width = 8;
+               writel(0, &mctl_phy->dx1gcr);
+               writel(dram_para.zq & 0xff, &mctl_phy->zqcr1);
+               writel(0x5f3, &mctl_phy->pir);
+               udelay(10000);
+               setbits_le32(&mctl_ctl->mstr, 0x1000);
+       } else
+               *bus_width = 16;
+
+       correction = (dram_para.odt_en >> 8) & 0xff;
+       if (correction) {
+               if (dram_para.odt_en & 0x80000000)
+                       correction = -correction;
+
+               mctl_apply_odt_correction(&mctl_phy->dx0lcdlr1, correction);
+               mctl_apply_odt_correction(&mctl_phy->dx1lcdlr1, correction);
+       }
+
+       mctl_await_completion(&mctl_ctl->statr, 0x01, 0x01);
+
+       writel(0x08003e3f, &mctl_phy->pgcr0);
+       writel(0x00000000, &mctl_ctl->rfshctl3);
+}
+
+unsigned long sunxi_dram_init(void)
+{
+       struct sunxi_mctl_com_reg * const mctl_com =
+               (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+       const u32 columns = 13;
+       u32 bus, bus_width, offset, page_size, rows;
+
+       mctl_sys_init();
+       mctl_init(&bus_width);
+
+       if (bus_width == 16) {
+               page_size = 8;
+               bus = 1;
+       } else {
+               page_size = 7;
+               bus = 0;
+       }
+
+       if (!(dram_para.tpr13 & 0x80000000)) {
+               /* Detect and set rows */
+               writel(0x000310f4 | MCTL_CR_PAGE_SIZE(page_size),
+                      &mctl_com->cr);
+               setbits_le32(&mctl_com->swonr, 0x0003ffff);
+               mctl_mem_fill();
+               for (rows = 11; rows < 16; rows++) {
+                       offset = 1 << (rows + columns + bus);
+                       if (mctl_mem_matches(offset))
+                               break;
+               }
+               clrsetbits_le32(&mctl_com->cr, MCTL_CR_ROW_MASK,
+                               MCTL_CR_ROW(rows));
+       } else {
+               rows = (dram_para.para1 >> 16) & 0xff;
+               writel(((dram_para.para2 & 0x000000f0) << 11) |
+                      ((rows - 1) << 4) |
+                      ((dram_para.para1 & 0x0f000000) >> 22) |
+                      0x31000 | MCTL_CR_PAGE_SIZE(page_size),
+                      &mctl_com->cr);
+               setbits_le32(&mctl_com->swonr, 0x0003ffff);
+       }
+
+       /* Setup DRAM master priority? If this is left out things still work */
+       writel(0x00000008, &mctl_com->mcr0_0);
+       writel(0x0001000d, &mctl_com->mcr1_0);
+       writel(0x00000004, &mctl_com->mcr0_1);
+       writel(0x00000080, &mctl_com->mcr1_1);
+       writel(0x00000004, &mctl_com->mcr0_2);
+       writel(0x00000019, &mctl_com->mcr1_2);
+       writel(0x00000004, &mctl_com->mcr0_3);
+       writel(0x00000080, &mctl_com->mcr1_3);
+       writel(0x00000004, &mctl_com->mcr0_4);
+       writel(0x01010040, &mctl_com->mcr1_4);
+       writel(0x00000004, &mctl_com->mcr0_5);
+       writel(0x0001002f, &mctl_com->mcr1_5);
+       writel(0x00000004, &mctl_com->mcr0_6);
+       writel(0x00010020, &mctl_com->mcr1_6);
+       writel(0x00000004, &mctl_com->mcr0_7);
+       writel(0x00010020, &mctl_com->mcr1_7);
+       writel(0x00000008, &mctl_com->mcr0_8);
+       writel(0x00000001, &mctl_com->mcr1_8);
+       writel(0x00000008, &mctl_com->mcr0_9);
+       writel(0x00000005, &mctl_com->mcr1_9);
+       writel(0x00000008, &mctl_com->mcr0_10);
+       writel(0x00000003, &mctl_com->mcr1_10);
+       writel(0x00000008, &mctl_com->mcr0_11);
+       writel(0x00000005, &mctl_com->mcr1_11);
+       writel(0x00000008, &mctl_com->mcr0_12);
+       writel(0x00000003, &mctl_com->mcr1_12);
+       writel(0x00000008, &mctl_com->mcr0_13);
+       writel(0x00000004, &mctl_com->mcr1_13);
+       writel(0x00000008, &mctl_com->mcr0_14);
+       writel(0x00000002, &mctl_com->mcr1_14);
+       writel(0x00000008, &mctl_com->mcr0_15);
+       writel(0x00000003, &mctl_com->mcr1_15);
+       writel(0x00010138, &mctl_com->bwcr);
+
+       return 1 << (rows + columns + bus);
+}
arch/arm/include/asm/arch-sunxi/clock_sun6i.h +4 -0
index 7d61216..45a199c 100644
@@ -273,7 +273,11 @@ struct sunxi_ccm_reg {
 #define CCM_HDMI_CTRL_DDC_GATE         (0x1 << 30)
 #define CCM_HDMI_CTRL_GATE             (0x1 << 31)
 
+#ifndef CONFIG_MACH_SUN8I
 #define MBUS_CLK_DEFAULT               0x81000001 /* PLL6 / 2 */
+#else
+#define MBUS_CLK_DEFAULT               0x81000003 /* PLL6 / 4 */
+#endif
 
 #define CCM_PLL5_PATTERN               0xd1303333
 
arch/arm/include/asm/arch-sunxi/dram.h +2 -0
index a8a37d5..8d78029 100644
@@ -18,6 +18,8 @@
 /* dram regs definition */
 #if defined(CONFIG_MACH_SUN6I)
 #include <asm/arch/dram_sun6i.h>
+#elif defined(CONFIG_MACH_SUN8I)
+#include <asm/arch/dram_sun8i.h>
 #else
 #include <asm/arch/dram_sun4i.h>
 #endif
arch/arm/include/asm/arch-sunxi/dram_sun8i.h new file +266 -0
new file mode 100644
index 0000000..425cf37
@@ -0,0 +1,266 @@
+/*
+ * Sun8i platform dram controller register and constant defines
+ *
+ * (C) Copyright 2007-2013
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * CPL <[email protected]>
+ * Jerry Wang <[email protected]>
+ *
+ * (C) Copyright 2014 Hans de Goede <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _SUNXI_DRAM_SUN8I_H
+#define _SUNXI_DRAM_SUN8I_H
+
+struct dram_para {
+       u32 clock;
+       u32 type;
+       u32 zq;
+       u32 odt_en;
+       u32 para1;
+       u32 para2;
+       u32 mr0;
+       u32 mr1;
+       u32 mr2;
+       u32 mr3;
+       u32 tpr0;
+       u32 tpr1;
+       u32 tpr2;
+       u32 tpr3;
+       u32 tpr4;
+       u32 tpr5;
+       u32 tpr6;
+       u32 tpr7;
+       u32 tpr8;
+       u32 tpr9;
+       u32 tpr10;
+       u32 tpr11;
+       u32 tpr12;
+       u32 tpr13;
+};
+
+struct sunxi_mctl_com_reg {
+       u32 cr;                 /* 0x00 */
+       u32 ccr;                /* 0x04 controller configuration register */
+       u32 dbgcr;              /* 0x08 */
+       u8 res0[0x4];           /* 0x0c */
+       u32 mcr0_0;             /* 0x10 */
+       u32 mcr1_0;             /* 0x14 */
+       u32 mcr0_1;             /* 0x18 */
+       u32 mcr1_1;             /* 0x1c */
+       u32 mcr0_2;             /* 0x20 */
+       u32 mcr1_2;             /* 0x24 */
+       u32 mcr0_3;             /* 0x28 */
+       u32 mcr1_3;             /* 0x2c */
+       u32 mcr0_4;             /* 0x30 */
+       u32 mcr1_4;             /* 0x34 */
+       u32 mcr0_5;             /* 0x38 */
+       u32 mcr1_5;             /* 0x3c */
+       u32 mcr0_6;             /* 0x40 */
+       u32 mcr1_6;             /* 0x44 */
+       u32 mcr0_7;             /* 0x48 */
+       u32 mcr1_7;             /* 0x4c */
+       u32 mcr0_8;             /* 0x50 */
+       u32 mcr1_8;             /* 0x54 */
+       u32 mcr0_9;             /* 0x58 */
+       u32 mcr1_9;             /* 0x5c */
+       u32 mcr0_10;            /* 0x60 */
+       u32 mcr1_10;            /* 0x64 */
+       u32 mcr0_11;            /* 0x68 */
+       u32 mcr1_11;            /* 0x6c */
+       u32 mcr0_12;            /* 0x70 */
+       u32 mcr1_12;            /* 0x74 */
+       u32 mcr0_13;            /* 0x78 */
+       u32 mcr1_13;            /* 0x7c */
+       u32 mcr0_14;            /* 0x80 */
+       u32 mcr1_14;            /* 0x84 */
+       u32 mcr0_15;            /* 0x88 */
+       u32 mcr1_15;            /* 0x8c */
+       u32 bwcr;               /* 0x90 */
+       u32 maer;               /* 0x94 */
+       u8 res1[0x4];           /* 0x98 */
+       u32 mcgcr;              /* 0x9c */
+       u32 bwctr;              /* 0xa0 */
+       u8 res2[0x4];           /* 0xa4 */
+       u32 swonr;              /* 0xa8 */
+       u32 swoffr;             /* 0xac */
+};
+
+struct sunxi_mctl_ctl_reg {
+       u32 mstr;               /* 0x00 */
+       u32 statr;              /* 0x04 */
+       u8 res0[0x08];          /* 0x08 */
+       u32 mrctrl0;            /* 0x10 */
+       u32 mrctrl1;            /* 0x14 */
+       u32 mrstatr;            /* 0x18 */
+       u8 res1[0x04];          /* 0x1c */
+       u32 derateen;           /* 0x20 */
+       u32 deratenint;         /* 0x24 */
+       u8 res2[0x08];          /* 0x28 */
+       u32 pwrctl;             /* 0x30 */
+       u32 pwrtmg;             /* 0x34 */
+       u8 res3[0x18];          /* 0x38 */
+       u32 rfshctl0;           /* 0x50 */
+       u32 rfshctl1;           /* 0x54 */
+       u8 res4[0x8];           /* 0x58 */
+       u32 rfshctl3;           /* 0x60 */
+       u32 rfshtmg;            /* 0x64 */
+       u8 res6[0x68];          /* 0x68 */
+       u32 init0;              /* 0xd0 */
+       u32 init1;              /* 0xd4 */
+       u32 init2;              /* 0xd8 */
+       u32 init3;              /* 0xdc */
+       u32 init4;              /* 0xe0 */
+       u32 init5;              /* 0xe4 */
+       u8 res7[0x0c];          /* 0xe8 */
+       u32 rankctl;            /* 0xf4 */
+       u8 res8[0x08];          /* 0xf8 */
+       u32 dramtmg0;           /* 0x100 */
+       u32 dramtmg1;           /* 0x104 */
+       u32 dramtmg2;           /* 0x108 */
+       u32 dramtmg3;           /* 0x10c */
+       u32 dramtmg4;           /* 0x110 */
+       u32 dramtmg5;           /* 0x114 */
+       u32 dramtmg6;           /* 0x118 */
+       u32 dramtmg7;           /* 0x11c */
+       u32 dramtmg8;           /* 0x120 */
+       u8 res9[0x5c];          /* 0x124 */
+       u32 zqctl0;             /* 0x180 */
+       u32 zqctl1;             /* 0x184 */
+       u32 zqctl2;             /* 0x188 */
+       u32 zqstat;             /* 0x18c */
+       u32 pitmg0;             /* 0x190 */
+       u32 pitmg1;             /* 0x194 */
+       u32 plpcfg0;            /* 0x198 */
+       u8 res10[0x04];         /* 0x19c */
+       u32 upd0;               /* 0x1a0 */
+       u32 upd1;               /* 0x1a4 */
+       u32 upd2;               /* 0x1a8 */
+       u32 upd3;               /* 0x1ac */
+       u32 pimisc;             /* 0x1b0 */
+       u8 res11[0x1c];         /* 0x1b4 */
+       u32 trainctl0;          /* 0x1d0 */
+       u32 trainctl1;          /* 0x1d4 */
+       u32 trainctl2;          /* 0x1d8 */
+       u32 trainstat;          /* 0x1dc */
+       u8 res12[0x60];         /* 0x1e0 */
+       u32 odtcfg;             /* 0x240 */
+       u32 odtmap;             /* 0x244 */
+       u8 res13[0x08];         /* 0x248 */
+       u32 sched;              /* 0x250 */
+       u8 res14[0x04];         /* 0x254 */
+       u32 perfshpr0;          /* 0x258 */
+       u32 perfshpr1;          /* 0x25c */
+       u32 perflpr0;           /* 0x260 */
+       u32 perflpr1;           /* 0x264 */
+       u32 perfwr0;            /* 0x268 */
+       u32 perfwr1;            /* 0x26c */
+};
+
+struct sunxi_mctl_phy_reg {
+       u8 res0[0x04];          /* 0x00 */
+       u32 pir;                /* 0x04 */
+       u32 pgcr0;              /* 0x08 phy general configuration register */
+       u32 pgcr1;              /* 0x0c phy general configuration register */
+       u32 pgsr0;              /* 0x10 */
+       u32 pgsr1;              /* 0x14 */
+       u32 dllgcr;             /* 0x18 */
+       u32 ptr0;               /* 0x1c */
+       u32 ptr1;               /* 0x20 */
+       u32 ptr2;               /* 0x24 */
+       u32 ptr3;               /* 0x28 */
+       u32 ptr4;               /* 0x2c */
+       u32 acmdlr;             /* 0x30 */
+       u32 acbdlr;             /* 0x34 */
+       u32 aciocr;             /* 0x38 */
+       u32 dxccr;              /* 0x3c DATX8 common configuration register */
+       u32 dsgcr;              /* 0x40 dram system general config register */
+       u32 dcr;                /* 0x44 */
+       u32 dtpr0;              /* 0x48 dram timing parameters register 0 */
+       u32 dtpr1;              /* 0x4c dram timing parameters register 1 */
+       u32 dtpr2;              /* 0x50 dram timing parameters register 2 */
+       u32 mr0;                /* 0x54 mode register 0 */
+       u32 mr1;                /* 0x58 mode register 1 */
+       u32 mr2;                /* 0x5c mode register 2 */
+       u32 mr3;                /* 0x60 mode register 3 */
+       u32 odtcr;              /* 0x64 */
+       u32 dtcr;               /* 0x68 */
+       u32 dtar0;              /* 0x6c data training address register 0 */
+       u32 dtar1;              /* 0x70 data training address register 1 */
+       u32 dtar2;              /* 0x74 data training address register 2 */
+       u32 dtar3;              /* 0x78 data training address register 3 */
+       u32 dtdr0;              /* 0x7c */
+       u32 dtdr1;              /* 0x80 */
+       u32 dtedr0;             /* 0x84 */
+       u32 dtedr1;             /* 0x88 */
+       u32 pgcr2;              /* 0x8c */
+       u8 res1[0x70];          /* 0x90 */
+       u32 bistrr;             /* 0x100 */
+       u32 bistwcr;            /* 0x104 */
+       u32 bistmskr0;          /* 0x108 */
+       u32 bistmskr1;          /* 0x10c */
+       u32 bistmskr2;          /* 0x110 */
+       u32 bistlsr;            /* 0x114 */
+       u32 bistar0;            /* 0x118 */
+       u32 bistar1;            /* 0x11c */
+       u32 bistar2;            /* 0x120 */
+       u32 bistupdr;           /* 0x124 */
+       u32 bistgsr;            /* 0x128 */
+       u32 bistwer;            /* 0x12c */
+       u32 bistber0;           /* 0x130 */
+       u32 bistber1;           /* 0x134 */
+       u32 bistber2;           /* 0x138 */
+       u32 bistber3;           /* 0x13c */
+       u32 bistwcsr;           /* 0x140 */
+       u32 bistfwr0;           /* 0x144 */
+       u32 bistfwr1;           /* 0x148 */
+       u32 bistfwr2;           /* 0x14c */
+       u8 res2[0x30];          /* 0x150 */
+       u32 zqcr0;              /* 0x180 zq control register 0 */
+       u32 zqcr1;              /* 0x184 zq control register 1 */
+       u32 zqsr0;              /* 0x188 zq status register 0 */
+       u32 zqsr1;              /* 0x18c zq status register 1 */
+       u32 zqcr2;              /* 0x190 zq control register 2 */
+       u8 res3[0x2c];          /* 0x194 */
+       u32 dx0gcr;             /* 0x1c0 */
+       u32 dx0gsr0;            /* 0x1c4 */
+       u32 dx0gsr1;            /* 0x1c8 */
+       u32 dx0bdlr0;           /* 0x1cc */
+       u32 dx0bdlr1;           /* 0x1d0 */
+       u32 dx0bdlr2;           /* 0x1d4 */
+       u32 dx0bdlr3;           /* 0x1d8 */
+       u32 dx0bdlr4;           /* 0x1dc */
+       u32 dx0lcdlr0;          /* 0x1e0 */
+       u32 dx0lcdlr1;          /* 0x1e4 */
+       u32 dx0lcdlr2;          /* 0x1e8 */
+       u32 dx0mdlr;            /* 0x1ec */
+       u32 dx0gtr;             /* 0x1f0 */
+       u32 dx0gsr2;            /* 0x1f4 */
+       u8 res4[0x08];          /* 0x1f8 */
+       u32 dx1gcr;             /* 0x200 */
+       u32 dx1gsr0;            /* 0x204 */
+       u32 dx1gsr1;            /* 0x208 */
+       u32 dx1bdlr0;           /* 0x20c */
+       u32 dx1bdlr1;           /* 0x210 */
+       u32 dx1bdlr2;           /* 0x214 */
+       u32 dx1bdlr3;           /* 0x218 */
+       u32 dx1bdlr4;           /* 0x21c */
+       u32 dx1lcdlr0;          /* 0x220 */
+       u32 dx1lcdlr1;          /* 0x224 */
+       u32 dx1lcdlr2;          /* 0x228 */
+       u32 dx1mdlr;            /* 0x22c */
+       u32 dx1gtr;             /* 0x230 */
+       u32 dx1gsr2;            /* 0x234 */
+};
+
+/*
+ * DRAM common (sunxi_mctl_com_reg) register constants.
+ */
+#define MCTL_CR_ROW_MASK               (0xf << 4)
+#define MCTL_CR_ROW(x)                 (((x) - 1) << 4)
+#define MCTL_CR_PAGE_SIZE_MASK         (0xf << 8)
+#define MCTL_CR_PAGE_SIZE(x)           ((x) << 8)
+
+#endif /* _SUNXI_DRAM_SUN8I_H */
board/sunxi/Kconfig +2 -1
index 5bb2f58..5a88ba0 100644
@@ -29,10 +29,11 @@ config MACH_SUN7I
 config MACH_SUN8I
        bool "sun8i (Allwinner A23)"
        select CPU_V7
+       select SUPPORT_SPL
 
 endchoice
 
-if MACH_SUN6I
+if MACH_SUN6I || MACH_SUN8I
 
 config DRAM_CLK
        int "sun6i dram clock speed"
configs/Ippo_q8h_v5_defconfig +12 -5
index 50c2f93..37aa46d 100644
@@ -1,8 +1,15 @@
+CONFIG_SPL=y
 CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
-CONFIG_ARM=y
-CONFIG_ARCH_SUNXI=y
-CONFIG_MACH_SUN8I=y
-CONFIG_TARGET_IPPO_Q8H_V5=y
-CONFIG_DEFAULT_DEVICE_TREE="sun8i-a23-ippo-q8h-v5.dtb"
+CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v5.dtb"
 CONFIG_VIDEO=n
 CONFIG_USB_KEYBOARD=n
++S:CONFIG_ARM=y
++S:CONFIG_ARCH_SUNXI=y
++S:CONFIG_MACH_SUN8I=y
++S:CONFIG_DRAM_CLK=480
+# zq = 0xf777
++S:CONFIG_DRAM_ZQ=63351
+# Wifi power
++S:CONFIG_AXP221_DLDO1_VOLT=3300
+# aldo1 is connected to VCC-IO, VCC-PD, VCC-USB and VCC-HP
++S:CONFIG_AXP221_ALDO1_VOLT=3000
include/configs/sun8i.h +2 -1
index 6f1fc48..792422d 100644
@@ -12,6 +12,8 @@
 /*
  * A23 specific configuration
  */
+#define CONFIG_CLK_FULL_SPEED  1008000000
+
 #define CONFIG_SYS_PROMPT      "sun8i# "
 
 /*
--
Quoted 1 line

2.1.0

git am reports:

Applying patch #422080 using 'git am'
Description: [U-Boot,13/14] sun8i: Add dram initialization support
Applying: sun8i: Add dram initialization support /home/wens/sunxi/u-boot/.git/rebase-apply/patch:201: trailing whitespace.

        writel(((dram_para.tpr6 & 0x000007c0) << 10) |
/home/wens/sunxi/u-boot/.git/rebase-apply/patch:455: space before tab in indent.
        u32 tpr6;

warning: 2 lines add whitespace errors.

---

I forgot to send out this one. Anyway, I've tested the series on my A23 tablet and it's working fine. Something in linux-next broke my system though.

ChenYu

#46 lore raw

PATCH 13/14 sun8i: Add dram initialization support

In reply to Hans de Goede
Quoted 10 lines · Hans de Goede

Based on the register / dram_para headers from the Allwinner u-boot / linux sources + the init sequences from boot0.

+/*
+ * Note this code uses a lot of magic hex values, that is because this code
+ * simply replays the init sequence as done by the Allwinner boot0 code, so
+ * we do not know what these values mean. There are no symbolic constants for
+ * these magic values, since we do not know how to name them and making up
+ * names for them is not useful.

On that basis I've only really given this a quick glance. I've no problem with it.

Couple of queries about the defconfig changes:

configs/Ippo_q8h_v5_defconfig line 5

Quoted 11 lines
configs/Ippo_q8h_v5_defconfig +1 -4
index 50c2f93..37aa46d 100644
@@ -1,8 +1,15 @@
+CONFIG_SPL=y
 CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
-CONFIG_ARM=y
-CONFIG_ARCH_SUNXI=y
-CONFIG_MACH_SUN8I=y
-CONFIG_TARGET_IPPO_Q8H_V5=y

Not replaced with a S: variant? I know you want CONFIG_TARGET to go, but I don't think that was part of what you intended in this patch.

configs/Ippo_q8h_v5_defconfig line 3

Quoted 2 lines
configs/Ippo_q8h_v5_defconfig +1 -1
-CONFIG_DEFAULT_DEVICE_TREE="sun8i-a23-ippo-q8h-v5.dtb"
+CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v5.dtb"

The switch from CONFIG_DEFAULT_DEVICE_TREE to CONFIG_FDTFILE conversion seems a little out of place too.

Ian.

#47 lore raw

PATCH 13/14 sun8i: Add dram initialization support

Hi,

Quoted 17 lines · Ian Campbell
Quoted 10 lines · Hans de Goede

Based on the register / dram_para headers from the Allwinner u-boot / linux sources + the init sequences from boot0.

+/*
+ * Note this code uses a lot of magic hex values, that is because this code
+ * simply replays the init sequence as done by the Allwinner boot0 code, so
+ * we do not know what these values mean. There are no symbolic constants for
+ * these magic values, since we do not know how to name them and making up
+ * names for them is not useful.

On that basis I've only really given this a quick glance. I've no problem with it.

Couple of queries about the defconfig changes:

Quoted 14 lines

configs/Ippo_q8h_v5_defconfig line 5

Quoted 11 lines
configs/Ippo_q8h_v5_defconfig +1 -4
index 50c2f93..37aa46d 100644
@@ -1,8 +1,15 @@
+CONFIG_SPL=y
  CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
-CONFIG_ARM=y
-CONFIG_ARCH_SUNXI=y
-CONFIG_MACH_SUN8I=y
-CONFIG_TARGET_IPPO_Q8H_V5=y

Not replaced with a S: variant? I know you want CONFIG_TARGET to go, but I don't think that was part of what you intended in this patch.

Right, I'll add that back.

Quoted 6 lines

configs/Ippo_q8h_v5_defconfig line 3

Quoted 3 lines
configs/Ippo_q8h_v5_defconfig +1 -1
-CONFIG_DEFAULT_DEVICE_TREE="sun8i-a23-ippo-q8h-v5.dtb"
+CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v5.dtb"

The switch from CONFIG_DEFAULT_DEVICE_TREE to CONFIG_FDTFILE conversion seems a little out of place too.

That was deliberate, the CONFIG_DEFAULT_DEVICE_TREE is the wrong CONFIG define to use to set the dtb for the kernel. I'll split the Ippo_q8h_v5_defconfig changes out into a separate patch and mention this in the commit message.

Regards,

Hans

#48 lore raw

PATCH 13/14 sun8i: Add dram initialization support

In reply to Hans de Goede
Quoted 2 lines · On Tue, 16 Dec 2014 21:31:38 +0100 Hans de Goede <[email protected]> wrote:

Based on the register / dram_para headers from the Allwinner u-boot / linux sources + the init sequences from boot0.

Can the commit message have more detailed information about the precise location of the original Allwinner code, which was used as the reference?

Quoted 47 lines
---
 arch/arm/cpu/armv7/sunxi/Makefile             |   1 +
 arch/arm/cpu/armv7/sunxi/board.c              |   3 +-
 arch/arm/cpu/armv7/sunxi/dram_sun8i.c         | 340 ++++++++++++++++++++++++++
 arch/arm/include/asm/arch-sunxi/clock_sun6i.h |   4 +
 arch/arm/include/asm/arch-sunxi/dram.h        |   2 +
 arch/arm/include/asm/arch-sunxi/dram_sun8i.h  | 266 ++++++++++++++++++++
 board/sunxi/Kconfig                           |   3 +-
 configs/Ippo_q8h_v5_defconfig                 |  17 +-
 include/configs/sun8i.h                       |   2 +
 9 files changed, 631 insertions(+), 7 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/sunxi/dram_sun8i.c
 create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun8i.h
arch/arm/cpu/armv7/sunxi/Makefile +1 -0
index 3e8975a..1e89937 100644
@@ -33,6 +33,7 @@ obj-$(CONFIG_MACH_SUN4I)	+= dram_sun4i.o
 obj-$(CONFIG_MACH_SUN5I)	+= dram_sun4i.o
 obj-$(CONFIG_MACH_SUN6I)	+= dram_sun6i.o
 obj-$(CONFIG_MACH_SUN7I)	+= dram_sun4i.o
+obj-$(CONFIG_MACH_SUN8I)	+= dram_sun8i.o
 ifdef CONFIG_SPL_FEL
 obj-y	+= start.o
 endif
arch/arm/cpu/armv7/sunxi/board.c +2 -1
index 9b3e80c..bc98c56 100644
@@ -114,7 +114,8 @@ void reset_cpu(ulong addr)
 /* do some early init */
 void s_init(void)
 {
-#if defined CONFIG_SPL_BUILD && defined CONFIG_MACH_SUN6I
+#if defined CONFIG_SPL_BUILD && \
+		(defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I)
 	/* Magic (undocmented) value taken from boot0, without this DRAM
 	 * access gets messed up (seems cache related) */
 	setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0x1800);
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +0 -0
new file mode 100644
index 0000000..3736fd1

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 4

Quoted 4 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +4 -0
@@ -0,0 +1,340 @@
+/*
+ * Sun8i platform dram controller init.
+ *
+ * (C) Copyright 2014 Hans de Goede <[email protected]>

Is Allwinner copyright really not necessary here?

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 15

Quoted 10 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +10 -0
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * Note this code uses a lot of magic hex values, that is because this code
+ * simply replays the init sequence as done by the Allwinner boot0 code, so
+ * we do not know what these values mean. There are no symbolic constants for
+ * these magic values, since we do not know how to name them and making up
+ * names for them is not useful.
+ */

You are well aware of this documentation since a long time ago, right?
http://www.ti.com/lit/ug/spruhn7a/spruhn7a.pdf

Please open it and find "Table4-2 DDR3 PHY Registers". Then have a look at the "sunxi_mctl_phy_reg" struct from your patch. Compare the register names and their offsets. Looks like we are reasonably lucky again.

Just as an example, I have commented about a few hardware registers at different locations in the code.

Quoted 33 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +33 -0
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/dram.h>
+#include <asm/arch/prcm.h>
+
+static const struct dram_para dram_para = {
+	.clock = CONFIG_DRAM_CLK,
+	.type = 3,
+	.zq = CONFIG_DRAM_ZQ,
+	.odt_en = 1,
+	.para1 = 0, /* not used (only used when tpr13 bit 31 is set */
+	.para2 = 0, /* not used (only used when tpr13 bit 31 is set */
+	.mr0 = 6736,
+	.mr1 = 4,
+	.mr2 = 16,
+	.mr3 = 0,
+	/* tpr0 - 10 contain timing constants or-ed together in u32 vals */
+	.tpr0 = 0x2ab83def,
+	.tpr1 = 0x18082356,
+	.tpr2 = 0x00034156,
+	.tpr3 = 0x448c5533,
+	.tpr4 = 0x08010d00,
+	.tpr5 = 0x0340b20f,
+	.tpr6 = 0x20d118cc,
+	.tpr7 = 0x14062485,
+	.tpr8 = 0x220d1d52,
+	.tpr9 = 0x1e078c22,
+	.tpr10 = 0x3c,
+	.tpr11 = 0, /* not used */
+	.tpr12 = 0, /* not used */
+	.tpr13 = 0x30000,

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 59

Quoted 10 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +10 -0
+};
+
+static void mctl_sys_init(void)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	/* enable pll5, note the divide by 2 is deliberate! */
+	clock_set_pll5(dram_para.clock * 1000000 / 2, 1, 2,
+		       dram_para.tpr13 & 0x40000);

Is it really necessary to have the PLL5 setup so complicated and full of magic?

Quoted 28 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +28 -0
+
+	/* deassert ahb mctl reset */
+	setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
+
+	/* enable ahb mctl clock */
+	setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
+}
+
+static void mctl_apply_odt_correction(u32 *reg, int correction)
+{
+	int val;
+
+	val = (readl(reg) >> 8) & 0xff;
+	val += correction;
+
+	/* clamp */
+	if (val < 0)
+		val = 0;
+	else if (val > 255)
+		val = 255;
+
+	clrsetbits_le32(reg, 0xff00, val << 8);
+}
+
+static void mctl_init(u32 *bus_width)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 97

Quoted 10 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +10 -0
+	struct sunxi_mctl_com_reg * const mctl_com =
+		(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;
+	struct sunxi_mctl_phy_reg * const mctl_phy =
+		(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
+	int correction;
+
+	if (dram_para.tpr13 & 0x20)
+		writel(0x40b, &mctl_phy->dcr);

The bits 2-0 are DDRMR (DDR Mode), and the value 3 means DDR3. And 0x40b is actually the default reset value of this register according to the TI Keystone2 documentation.

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 99

Quoted 2 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +2 -0
+	else
+		writel(0x1000040b, &mctl_phy->dcr);

The bit 28 is marked as reserved and "Reads return zeros" in the TI Keystone2 documentation. It's a nice chance to test whether this write has any effect and whether it does modify the register.

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 102

Quoted 3 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +3 -0
+
+	if (dram_para.clock >= 480)
+		writel(0x5c000, &mctl_phy->dllgcr);

0x5c000 = (1 << 18) | (0xE << 13)

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 102

Quoted 2 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +2 -0
+	else
+		writel(0xdc000, &mctl_phy->dllgcr);

0xdc000 = (3 << 18) | (0xE << 13)

The 'dllgcr' has the same offset as "4.40 PLL Control Register (PLLCR)" in the TI Keystone2 documentation.

Bits 16-13 are CPPC (Charge Pump Proportional Current Control) with the default value 0xE, which matches what we see here.

Bits 19-18 are FRQSEL:
01 = PLL reference clock (ctl_clk/REF_CLK) ranges from 225MHz to 385MHz 11 = PLL reference clock (ctl_clk/REF_CLK) ranges from 166MHz to 275MHz

Quoted 74 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +74 -0
+
+	writel(0x0a003e3f, &mctl_phy->pgcr0);
+	writel(0x03008421, &mctl_phy->pgcr1);
+
+	writel(dram_para.mr0, &mctl_phy->mr0);
+	writel(dram_para.mr1, &mctl_phy->mr1);
+	writel(dram_para.mr2, &mctl_phy->mr2);
+	writel(dram_para.mr3, &mctl_phy->mr3);
+
+	if (!(dram_para.tpr13 & 0x10000)) {
+		clrsetbits_le32(&mctl_phy->dx0gcr, 0x3800, 0x2000);
+		clrsetbits_le32(&mctl_phy->dx1gcr, 0x3800, 0x2000);
+	}
+
+	/*
+	 * All the masking and shifting below converts what I assume are DDR
+	 * timing constants from Allwinner dram_para tpr format to the actual
+	 * timing registers format.
+	 */
+
+	writel((dram_para.tpr0 & 0x000fffff), &mctl_phy->ptr2);
+	writel((dram_para.tpr1 & 0x1fffffff), &mctl_phy->ptr3);
+	writel((dram_para.tpr0 & 0x3ff00000) >> 2 |
+	       (dram_para.tpr2 & 0x0003ffff), &mctl_phy->ptr4);
+
+	writel(dram_para.tpr3, &mctl_phy->dtpr0);
+	writel(dram_para.tpr4, &mctl_phy->dtpr2);
+
+	writel(0x01000081, &mctl_phy->dtcr);
+
+	if (dram_para.clock <= 240 || !(dram_para.odt_en & 0x01)) {
+		clrbits_le32(&mctl_phy->dx0gcr, 0x600);
+		clrbits_le32(&mctl_phy->dx1gcr, 0x600);
+	}
+	if (dram_para.clock <= 240) {
+		writel(0, &mctl_phy->odtcr);
+		writel(0, &mctl_ctl->odtmap);
+	}
+
+	writel(((dram_para.tpr5 & 0x0f00) << 12) |
+	       ((dram_para.tpr5 & 0x00f8) <<  9) |
+	       ((dram_para.tpr5 & 0x0007) <<  8),
+	       &mctl_ctl->rfshctl0);
+
+	writel(((dram_para.tpr5 & 0x0003f000) << 12) |
+	       ((dram_para.tpr5 & 0x00fc0000) >>  2) |
+	       ((dram_para.tpr5 & 0x3f000000) >> 16) |
+	       ((dram_para.tpr6 & 0x0000003f) >>  0),
+	       &mctl_ctl->dramtmg0);
+
+	writel(((dram_para.tpr6 & 0x000007c0) << 10) | 
+	       ((dram_para.tpr6 & 0x0000f800) >> 3) |
+	       ((dram_para.tpr6 & 0x003f0000) >> 16),
+	       &mctl_ctl->dramtmg1);
+
+	writel(((dram_para.tpr6 & 0x0fc00000) << 2) |
+	       ((dram_para.tpr7 & 0x0000001f) << 16) |
+	       ((dram_para.tpr7 & 0x000003e0) << 3) |
+	       ((dram_para.tpr7 & 0x0000fc00) >> 10),
+	       &mctl_ctl->dramtmg2);
+
+	writel(((dram_para.tpr7 & 0x03ff0000) >> 16) |
+	       ((dram_para.tpr6 & 0xf0000000) >> 16),
+	       &mctl_ctl->dramtmg3);
+
+	writel(((dram_para.tpr7 & 0x3c000000) >> 2 ) |
+	       ((dram_para.tpr8 & 0x00000007) << 16) |
+	       ((dram_para.tpr8 & 0x00000038) << 5) |
+	       ((dram_para.tpr8 & 0x000003c0) >> 6),
+	       &mctl_ctl->dramtmg4);
+
+	writel(((dram_para.tpr8 & 0x00003c00) << 14) |
+	       ((dram_para.tpr8 & 0x0003c000) <<  2) |
+	       ((dram_para.tpr8 & 0x00fc0000) >> 10) |

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 188

Quoted 10 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +10 -0
+	       ((dram_para.tpr8 & 0x0f000000) >> 24),
+	       &mctl_ctl->dramtmg5);
+
+	writel(0x00000008, &mctl_ctl->dramtmg8);
+
+	writel(((dram_para.tpr8 & 0xf0000000) >> 4) |
+	       ((dram_para.tpr9 & 0x00007c00) << 6) |
+	       ((dram_para.tpr9 & 0x000003e0) << 3) |
+	       ((dram_para.tpr9 & 0x0000001f) >> 0),
+	       &mctl_ctl->pitmg0);

Could there be any purpose for this other than obfuscation? Looks really strange.

Quoted 26 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +26 -0
+
+	setbits_le32(&mctl_ctl->pitmg1, 0x80000);
+
+	writel(((dram_para.tpr9 & 0x003f8000) << 9) | 0x2001,
+	       &mctl_ctl->sched);
+
+	writel((dram_para.mr0 << 16) | dram_para.mr1, &mctl_ctl->init3);
+	writel((dram_para.mr2 << 16) | dram_para.mr3, &mctl_ctl->init4);
+
+	writel(0x00000000, &mctl_ctl->pimisc);
+	writel(0x80000000, &mctl_ctl->upd0);
+
+	writel(((dram_para.tpr9  & 0xffc00000) >> 22) |
+	       ((dram_para.tpr10 & 0x00000fff) << 16),
+	       &mctl_ctl->rfshtmg);
+
+	if (dram_para.tpr13 & 0x20)
+		writel(0x01040001, &mctl_ctl->mstr);
+	else
+		writel(0x01040401, &mctl_ctl->mstr);
+
+	if (!(dram_para.tpr13 & 0x20000)) {
+		writel(0x00000002, &mctl_ctl->pwrctl);
+		writel(0x00008001, &mctl_ctl->pwrtmg);
+	}
+

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 224

Quoted 10 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +10 -0
+	writel(0x00000001, &mctl_ctl->rfshctl3);
+	writel(0x00000001, &mctl_ctl->pimisc);
+
+	/* deassert dram_clk_cfg reset */
+	setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
+
+	setbits_le32(&mctl_com->ccr, 0x80000);
+
+	/* zq stuff */
+	writel((dram_para.zq >> 8) & 0xff, &mctl_phy->zqcr1);

4.59 Impedance Control Register 1 (ZQnCR1)

Bits 7-0 - ZPROG (Impedance Divide Ratio), reset value 0x7B

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 226

Quoted 1 line
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +1 -0
+	writel(0x00000003, &mctl_phy->pir);

4.34 PHY Initialization Register (PIR)

Bit 0 - INIT
Bit 1 - ZCAL

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 228

Quoted 2 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +2 -0
+	udelay(10);
+	mctl_await_completion(&mctl_phy->pgsr0, 0x09, 0x09);

4.38 PHY General Status Register 0 (PGSR0)

Bit 0 - IDONE (Initialization Done)
Bit 3 - ZCDONE (Impedance Calibration Done)

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 227

Quoted 2 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +2 -0
+	writel(readl(&mctl_phy->zqsr0) | 0x10000000, &mctl_phy->zqcr2);
+	writel(dram_para.zq & 0xff, &mctl_phy->zqcr1);

Overwriting ZPROG again? Is it doing something reasonable? Or might it be an attempt to hide data from the tools like a10-meminfo (which can dump the DRAM setting via /dev/mem)?

Quoted 464 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +108 -0
+	/* A23-v1.0 SDK uses 0xfdf3, A23-v2.0 SDK uses 0x5f3 */
+	writel(0x000005f3, &mctl_phy->pir);
+	udelay(10);
+	mctl_await_completion(&mctl_phy->pgsr0, 0x03, 0x03);
+
+	if (readl(&mctl_phy->dx1gsr0) & 0x1000000) {
+		*bus_width = 8;
+		writel(0, &mctl_phy->dx1gcr);
+		writel(dram_para.zq & 0xff, &mctl_phy->zqcr1);
+		writel(0x5f3, &mctl_phy->pir);
+		udelay(10000);
+		setbits_le32(&mctl_ctl->mstr, 0x1000);
+	} else
+		*bus_width = 16;
+
+	correction = (dram_para.odt_en >> 8) & 0xff;
+	if (correction) {
+		if (dram_para.odt_en & 0x80000000)
+			correction = -correction;
+
+		mctl_apply_odt_correction(&mctl_phy->dx0lcdlr1, correction);
+		mctl_apply_odt_correction(&mctl_phy->dx1lcdlr1, correction);
+	}
+
+	mctl_await_completion(&mctl_ctl->statr, 0x01, 0x01);
+
+	writel(0x08003e3f, &mctl_phy->pgcr0);
+	writel(0x00000000, &mctl_ctl->rfshctl3);
+}
+
+unsigned long sunxi_dram_init(void)
+{
+	struct sunxi_mctl_com_reg * const mctl_com =
+		(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+	const u32 columns = 13;
+	u32 bus, bus_width, offset, page_size, rows;
+
+	mctl_sys_init();
+	mctl_init(&bus_width);
+
+	if (bus_width == 16) {
+		page_size = 8;
+		bus = 1;
+	} else {
+		page_size = 7;
+		bus = 0;
+	}
+
+	if (!(dram_para.tpr13 & 0x80000000)) {
+		/* Detect and set rows */
+		writel(0x000310f4 | MCTL_CR_PAGE_SIZE(page_size),
+		       &mctl_com->cr);
+		setbits_le32(&mctl_com->swonr, 0x0003ffff);
+		mctl_mem_fill();
+		for (rows = 11; rows < 16; rows++) {
+			offset = 1 << (rows + columns + bus);
+			if (mctl_mem_matches(offset))
+				break;
+		}
+		clrsetbits_le32(&mctl_com->cr, MCTL_CR_ROW_MASK,
+				MCTL_CR_ROW(rows));
+	} else {
+		rows = (dram_para.para1 >> 16) & 0xff;
+		writel(((dram_para.para2 & 0x000000f0) << 11) |
+		       ((rows - 1) << 4) |
+		       ((dram_para.para1 & 0x0f000000) >> 22) |
+		       0x31000 | MCTL_CR_PAGE_SIZE(page_size),
+		       &mctl_com->cr);
+		setbits_le32(&mctl_com->swonr, 0x0003ffff);
+	}
+
+	/* Setup DRAM master priority? If this is left out things still work */
+	writel(0x00000008, &mctl_com->mcr0_0);
+	writel(0x0001000d, &mctl_com->mcr1_0);
+	writel(0x00000004, &mctl_com->mcr0_1);
+	writel(0x00000080, &mctl_com->mcr1_1);
+	writel(0x00000004, &mctl_com->mcr0_2);
+	writel(0x00000019, &mctl_com->mcr1_2);
+	writel(0x00000004, &mctl_com->mcr0_3);
+	writel(0x00000080, &mctl_com->mcr1_3);
+	writel(0x00000004, &mctl_com->mcr0_4);
+	writel(0x01010040, &mctl_com->mcr1_4);
+	writel(0x00000004, &mctl_com->mcr0_5);
+	writel(0x0001002f, &mctl_com->mcr1_5);
+	writel(0x00000004, &mctl_com->mcr0_6);
+	writel(0x00010020, &mctl_com->mcr1_6);
+	writel(0x00000004, &mctl_com->mcr0_7);
+	writel(0x00010020, &mctl_com->mcr1_7);
+	writel(0x00000008, &mctl_com->mcr0_8);
+	writel(0x00000001, &mctl_com->mcr1_8);
+	writel(0x00000008, &mctl_com->mcr0_9);
+	writel(0x00000005, &mctl_com->mcr1_9);
+	writel(0x00000008, &mctl_com->mcr0_10);
+	writel(0x00000003, &mctl_com->mcr1_10);
+	writel(0x00000008, &mctl_com->mcr0_11);
+	writel(0x00000005, &mctl_com->mcr1_11);
+	writel(0x00000008, &mctl_com->mcr0_12);
+	writel(0x00000003, &mctl_com->mcr1_12);
+	writel(0x00000008, &mctl_com->mcr0_13);
+	writel(0x00000004, &mctl_com->mcr1_13);
+	writel(0x00000008, &mctl_com->mcr0_14);
+	writel(0x00000002, &mctl_com->mcr1_14);
+	writel(0x00000008, &mctl_com->mcr0_15);
+	writel(0x00000003, &mctl_com->mcr1_15);
+	writel(0x00010138, &mctl_com->bwcr);
+
+	return 1 << (rows + columns + bus);
+}
arch/arm/include/asm/arch-sunxi/clock_sun6i.h +4 -0
index 7d61216..45a199c 100644
@@ -273,7 +273,11 @@ struct sunxi_ccm_reg {
 #define CCM_HDMI_CTRL_DDC_GATE		(0x1 << 30)
 #define CCM_HDMI_CTRL_GATE		(0x1 << 31)
 
+#ifndef CONFIG_MACH_SUN8I
 #define MBUS_CLK_DEFAULT		0x81000001 /* PLL6 / 2 */
+#else
+#define MBUS_CLK_DEFAULT		0x81000003 /* PLL6 / 4 */
+#endif
 
 #define CCM_PLL5_PATTERN		0xd1303333
 
arch/arm/include/asm/arch-sunxi/dram.h +2 -0
index a8a37d5..8d78029 100644
@@ -18,6 +18,8 @@
 /* dram regs definition */
 #if defined(CONFIG_MACH_SUN6I)
 #include <asm/arch/dram_sun6i.h>
+#elif defined(CONFIG_MACH_SUN8I)
+#include <asm/arch/dram_sun8i.h>
 #else
 #include <asm/arch/dram_sun4i.h>
 #endif
arch/arm/include/asm/arch-sunxi/dram_sun8i.h new file +266 -0
new file mode 100644
index 0000000..425cf37
@@ -0,0 +1,266 @@
+/*
+ * Sun8i platform dram controller register and constant defines
+ *
+ * (C) Copyright 2007-2013
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * CPL <[email protected]>
+ * Jerry Wang <[email protected]>
+ *
+ * (C) Copyright 2014 Hans de Goede <[email protected]>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SUNXI_DRAM_SUN8I_H
+#define _SUNXI_DRAM_SUN8I_H
+
+struct dram_para {
+	u32 clock;
+	u32 type;
+	u32 zq;
+	u32 odt_en;
+	u32 para1;
+	u32 para2;
+	u32 mr0;
+	u32 mr1;
+	u32 mr2;
+	u32 mr3;
+	u32 tpr0;
+	u32 tpr1;
+	u32 tpr2;
+	u32 tpr3;
+	u32 tpr4;
+	u32 tpr5;
+   	u32 tpr6;
+	u32 tpr7;
+	u32 tpr8;
+	u32 tpr9;
+	u32 tpr10;
+	u32 tpr11;
+	u32 tpr12;
+	u32 tpr13;
+};
+
+struct sunxi_mctl_com_reg {
+	u32 cr;			/* 0x00 */
+	u32 ccr;		/* 0x04 controller configuration register */
+	u32 dbgcr;		/* 0x08 */
+	u8 res0[0x4];		/* 0x0c */
+	u32 mcr0_0;		/* 0x10 */
+	u32 mcr1_0;		/* 0x14 */
+	u32 mcr0_1;		/* 0x18 */
+	u32 mcr1_1;		/* 0x1c */
+	u32 mcr0_2;		/* 0x20 */
+	u32 mcr1_2;		/* 0x24 */
+	u32 mcr0_3;		/* 0x28 */
+	u32 mcr1_3;		/* 0x2c */
+	u32 mcr0_4;		/* 0x30 */
+	u32 mcr1_4;		/* 0x34 */
+	u32 mcr0_5;		/* 0x38 */
+	u32 mcr1_5;		/* 0x3c */
+	u32 mcr0_6;		/* 0x40 */
+	u32 mcr1_6;		/* 0x44 */
+	u32 mcr0_7;		/* 0x48 */
+	u32 mcr1_7;		/* 0x4c */
+	u32 mcr0_8;		/* 0x50 */
+	u32 mcr1_8;		/* 0x54 */
+	u32 mcr0_9;		/* 0x58 */
+	u32 mcr1_9;		/* 0x5c */
+	u32 mcr0_10;		/* 0x60 */
+	u32 mcr1_10;		/* 0x64 */
+	u32 mcr0_11;		/* 0x68 */
+	u32 mcr1_11;		/* 0x6c */
+	u32 mcr0_12;		/* 0x70 */
+	u32 mcr1_12;		/* 0x74 */
+	u32 mcr0_13;		/* 0x78 */
+	u32 mcr1_13;		/* 0x7c */
+	u32 mcr0_14;		/* 0x80 */
+	u32 mcr1_14;		/* 0x84 */
+	u32 mcr0_15;		/* 0x88 */
+	u32 mcr1_15;		/* 0x8c */
+	u32 bwcr;		/* 0x90 */
+	u32 maer;		/* 0x94 */
+	u8 res1[0x4];		/* 0x98 */
+	u32 mcgcr;		/* 0x9c */
+	u32 bwctr;		/* 0xa0 */
+	u8 res2[0x4];		/* 0xa4 */
+	u32 swonr;		/* 0xa8 */
+	u32 swoffr;		/* 0xac */
+};
+
+struct sunxi_mctl_ctl_reg {
+	u32 mstr;		/* 0x00 */
+	u32 statr;		/* 0x04 */
+	u8 res0[0x08];		/* 0x08 */
+	u32 mrctrl0;		/* 0x10 */
+	u32 mrctrl1;		/* 0x14 */
+	u32 mrstatr;		/* 0x18 */
+	u8 res1[0x04];		/* 0x1c */
+	u32 derateen;		/* 0x20 */
+	u32 deratenint;		/* 0x24 */
+	u8 res2[0x08];		/* 0x28 */
+	u32 pwrctl;		/* 0x30 */
+	u32 pwrtmg;		/* 0x34 */
+	u8 res3[0x18];		/* 0x38 */
+	u32 rfshctl0;		/* 0x50 */
+	u32 rfshctl1;		/* 0x54 */
+	u8 res4[0x8];		/* 0x58 */
+	u32 rfshctl3;		/* 0x60 */
+	u32 rfshtmg;		/* 0x64 */
+	u8 res6[0x68];		/* 0x68 */
+	u32 init0;		/* 0xd0 */
+	u32 init1;		/* 0xd4 */
+	u32 init2;		/* 0xd8 */
+	u32 init3;		/* 0xdc */
+	u32 init4;		/* 0xe0 */
+	u32 init5;		/* 0xe4 */
+	u8 res7[0x0c];		/* 0xe8 */
+	u32 rankctl;		/* 0xf4 */
+	u8 res8[0x08];		/* 0xf8 */
+	u32 dramtmg0;		/* 0x100 */
+	u32 dramtmg1;		/* 0x104 */
+	u32 dramtmg2;		/* 0x108 */
+	u32 dramtmg3;		/* 0x10c */
+	u32 dramtmg4;		/* 0x110 */
+	u32 dramtmg5;		/* 0x114 */
+	u32 dramtmg6;		/* 0x118 */
+	u32 dramtmg7;		/* 0x11c */
+	u32 dramtmg8;		/* 0x120 */
+	u8 res9[0x5c];		/* 0x124 */
+	u32 zqctl0;		/* 0x180 */
+	u32 zqctl1;		/* 0x184 */
+	u32 zqctl2;		/* 0x188 */
+	u32 zqstat;		/* 0x18c */
+	u32 pitmg0;		/* 0x190 */
+	u32 pitmg1;		/* 0x194 */
+	u32 plpcfg0;		/* 0x198 */
+	u8 res10[0x04];		/* 0x19c */
+	u32 upd0;		/* 0x1a0 */
+	u32 upd1;		/* 0x1a4 */
+	u32 upd2;		/* 0x1a8 */
+	u32 upd3;		/* 0x1ac */
+	u32 pimisc;		/* 0x1b0 */
+	u8 res11[0x1c];		/* 0x1b4 */
+	u32 trainctl0;		/* 0x1d0 */
+	u32 trainctl1;		/* 0x1d4 */
+	u32 trainctl2;		/* 0x1d8 */
+	u32 trainstat;		/* 0x1dc */
+	u8 res12[0x60];		/* 0x1e0 */
+	u32 odtcfg;		/* 0x240 */
+	u32 odtmap;		/* 0x244 */
+	u8 res13[0x08];		/* 0x248 */
+	u32 sched;		/* 0x250 */
+	u8 res14[0x04];		/* 0x254 */
+	u32 perfshpr0;		/* 0x258 */
+	u32 perfshpr1;		/* 0x25c */
+	u32 perflpr0;		/* 0x260 */
+	u32 perflpr1;		/* 0x264 */
+	u32 perfwr0;		/* 0x268 */
+	u32 perfwr1;		/* 0x26c */
+};
+
+struct sunxi_mctl_phy_reg {
+	u8 res0[0x04];		/* 0x00 */
+	u32 pir;		/* 0x04 */
+	u32 pgcr0;		/* 0x08 phy general configuration register */
+	u32 pgcr1;		/* 0x0c phy general configuration register */
+	u32 pgsr0;		/* 0x10 */
+	u32 pgsr1;		/* 0x14 */
+	u32 dllgcr;		/* 0x18 */
+	u32 ptr0;		/* 0x1c */
+	u32 ptr1;		/* 0x20 */
+	u32 ptr2;		/* 0x24 */
+	u32 ptr3;		/* 0x28 */
+	u32 ptr4;		/* 0x2c */
+	u32 acmdlr;		/* 0x30 */
+	u32 acbdlr;		/* 0x34 */
+	u32 aciocr;		/* 0x38 */
+	u32 dxccr;		/* 0x3c DATX8 common configuration register */
+	u32 dsgcr;		/* 0x40 dram system general config register */
+	u32 dcr;		/* 0x44 */
+	u32 dtpr0;		/* 0x48 dram timing parameters register 0 */
+	u32 dtpr1;		/* 0x4c dram timing parameters register 1 */
+	u32 dtpr2;		/* 0x50 dram timing parameters register 2 */
+	u32 mr0;		/* 0x54 mode register 0 */
+	u32 mr1;		/* 0x58 mode register 1 */
+	u32 mr2;		/* 0x5c mode register 2 */
+	u32 mr3;		/* 0x60 mode register 3 */
+	u32 odtcr;		/* 0x64 */
+	u32 dtcr;		/* 0x68 */
+	u32 dtar0;		/* 0x6c data training address register 0 */
+	u32 dtar1;		/* 0x70 data training address register 1 */
+	u32 dtar2;		/* 0x74 data training address register 2 */
+	u32 dtar3;		/* 0x78 data training address register 3 */
+	u32 dtdr0;		/* 0x7c */
+	u32 dtdr1;		/* 0x80 */
+	u32 dtedr0;		/* 0x84 */
+	u32 dtedr1;		/* 0x88 */
+	u32 pgcr2;		/* 0x8c */
+	u8 res1[0x70];		/* 0x90 */
+	u32 bistrr;		/* 0x100 */
+	u32 bistwcr;		/* 0x104 */
+	u32 bistmskr0;		/* 0x108 */
+	u32 bistmskr1;		/* 0x10c */
+	u32 bistmskr2;		/* 0x110 */
+	u32 bistlsr;		/* 0x114 */
+	u32 bistar0;		/* 0x118 */
+	u32 bistar1;		/* 0x11c */
+	u32 bistar2;		/* 0x120 */
+	u32 bistupdr;		/* 0x124 */
+	u32 bistgsr;		/* 0x128 */
+	u32 bistwer;		/* 0x12c */
+	u32 bistber0;		/* 0x130 */
+	u32 bistber1;		/* 0x134 */
+	u32 bistber2;		/* 0x138 */
+	u32 bistber3;		/* 0x13c */
+	u32 bistwcsr;		/* 0x140 */
+	u32 bistfwr0;		/* 0x144 */
+	u32 bistfwr1;		/* 0x148 */
+	u32 bistfwr2;		/* 0x14c */
+	u8 res2[0x30];		/* 0x150 */
+	u32 zqcr0;		/* 0x180 zq control register 0 */
+	u32 zqcr1;		/* 0x184 zq control register 1 */
+	u32 zqsr0;		/* 0x188 zq status register 0 */
+	u32 zqsr1;		/* 0x18c zq status register 1 */
+	u32 zqcr2;		/* 0x190 zq control register 2 */
+	u8 res3[0x2c];		/* 0x194 */
+	u32 dx0gcr;		/* 0x1c0 */
+	u32 dx0gsr0;		/* 0x1c4 */
+	u32 dx0gsr1;		/* 0x1c8 */
+	u32 dx0bdlr0;		/* 0x1cc */
+	u32 dx0bdlr1;		/* 0x1d0 */
+	u32 dx0bdlr2;		/* 0x1d4 */
+	u32 dx0bdlr3;		/* 0x1d8 */
+	u32 dx0bdlr4;		/* 0x1dc */
+	u32 dx0lcdlr0;		/* 0x1e0 */
+	u32 dx0lcdlr1;		/* 0x1e4 */
+	u32 dx0lcdlr2;		/* 0x1e8 */
+	u32 dx0mdlr;		/* 0x1ec */
+	u32 dx0gtr;		/* 0x1f0 */
+	u32 dx0gsr2;		/* 0x1f4 */
+	u8 res4[0x08];		/* 0x1f8 */
+	u32 dx1gcr;		/* 0x200 */
+	u32 dx1gsr0;		/* 0x204 */
+	u32 dx1gsr1;		/* 0x208 */
+	u32 dx1bdlr0;		/* 0x20c */
+	u32 dx1bdlr1;		/* 0x210 */
+	u32 dx1bdlr2;		/* 0x214 */
+	u32 dx1bdlr3;		/* 0x218 */
+	u32 dx1bdlr4;		/* 0x21c */
+	u32 dx1lcdlr0;		/* 0x220 */
+	u32 dx1lcdlr1;		/* 0x224 */
+	u32 dx1lcdlr2;		/* 0x228 */
+	u32 dx1mdlr;		/* 0x22c */
+	u32 dx1gtr;		/* 0x230 */
+	u32 dx1gsr2;		/* 0x234 */
+};
+
+/*
+ * DRAM common (sunxi_mctl_com_reg) register constants.
+ */
+#define MCTL_CR_ROW_MASK		(0xf << 4)
+#define MCTL_CR_ROW(x)			(((x) - 1) << 4)
+#define MCTL_CR_PAGE_SIZE_MASK		(0xf << 8)
+#define MCTL_CR_PAGE_SIZE(x)		((x) << 8)
+
+#endif /* _SUNXI_DRAM_SUN8I_H */
board/sunxi/Kconfig +2 -1
index 5bb2f58..5a88ba0 100644
@@ -29,10 +29,11 @@ config MACH_SUN7I
 config MACH_SUN8I
 	bool "sun8i (Allwinner A23)"
 	select CPU_V7
+	select SUPPORT_SPL
 
 endchoice
 
-if MACH_SUN6I
+if MACH_SUN6I || MACH_SUN8I
 
 config DRAM_CLK
 	int "sun6i dram clock speed"
configs/Ippo_q8h_v5_defconfig +12 -5
index 50c2f93..37aa46d 100644
@@ -1,8 +1,15 @@
+CONFIG_SPL=y
 CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
-CONFIG_ARM=y
-CONFIG_ARCH_SUNXI=y
-CONFIG_MACH_SUN8I=y
-CONFIG_TARGET_IPPO_Q8H_V5=y
-CONFIG_DEFAULT_DEVICE_TREE="sun8i-a23-ippo-q8h-v5.dtb"
+CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v5.dtb"
 CONFIG_VIDEO=n
 CONFIG_USB_KEYBOARD=n
++S:CONFIG_ARM=y
++S:CONFIG_ARCH_SUNXI=y
++S:CONFIG_MACH_SUN8I=y
++S:CONFIG_DRAM_CLK=480
+# zq = 0xf777
++S:CONFIG_DRAM_ZQ=63351
+# Wifi power
++S:CONFIG_AXP221_DLDO1_VOLT=3300
+# aldo1 is connected to VCC-IO, VCC-PD, VCC-USB and VCC-HP
++S:CONFIG_AXP221_ALDO1_VOLT=3000
include/configs/sun8i.h +2 -0
index 6f1fc48..792422d 100644
@@ -12,6 +12,8 @@
 /*
  * A23 specific configuration
  */
+#define CONFIG_CLK_FULL_SPEED	1008000000
+
 #define CONFIG_SYS_PROMPT	"sun8i# "
 
 /*
Signature · 2 lines
Best regards,
Siarhei Siamashka
#49 lore raw

PATCH 13/14 sun8i: Add dram initialization support

Hi,

Quoted 9 lines · Siarhei Siamashka
Quoted 2 lines · On Tue, 16 Dec 2014 21:31:38 +0100 Hans de Goede <[email protected]> wrote:

Based on the register / dram_para headers from the Allwinner u-boot / linux sources + the init sequences from boot0.

Can the commit message have more detailed information about the precise location of the original Allwinner code, which was used as the reference?

No, it cannot because no code was referenced, I traced the boot0 binary to figure out what was needed to get dram going on the A23.

Quoted 67 lines
Quoted 48 lines
---
  arch/arm/cpu/armv7/sunxi/Makefile             |   1 +
  arch/arm/cpu/armv7/sunxi/board.c              |   3 +-
  arch/arm/cpu/armv7/sunxi/dram_sun8i.c         | 340 ++++++++++++++++++++++++++
  arch/arm/include/asm/arch-sunxi/clock_sun6i.h |   4 +
  arch/arm/include/asm/arch-sunxi/dram.h        |   2 +
  arch/arm/include/asm/arch-sunxi/dram_sun8i.h  | 266 ++++++++++++++++++++
  board/sunxi/Kconfig                           |   3 +-
  configs/Ippo_q8h_v5_defconfig                 |  17 +-
  include/configs/sun8i.h                       |   2 +
  9 files changed, 631 insertions(+), 7 deletions(-)

create mode 100644 arch/arm/cpu/armv7/sunxi/dram_sun8i.c create mode 100644 arch/arm/include/asm/arch-sunxi/dram_sun8i.h

arch/arm/cpu/armv7/sunxi/Makefile +1 -0
index 3e8975a..1e89937 100644
@@ -33,6 +33,7 @@ obj-$(CONFIG_MACH_SUN4I)	+= dram_sun4i.o
  obj-$(CONFIG_MACH_SUN5I)	+= dram_sun4i.o
  obj-$(CONFIG_MACH_SUN6I)	+= dram_sun6i.o
  obj-$(CONFIG_MACH_SUN7I)	+= dram_sun4i.o
+obj-$(CONFIG_MACH_SUN8I)	+= dram_sun8i.o
  ifdef CONFIG_SPL_FEL
  obj-y	+= start.o
  endif
arch/arm/cpu/armv7/sunxi/board.c +2 -1
index 9b3e80c..bc98c56 100644
@@ -114,7 +114,8 @@ void reset_cpu(ulong addr)
  /* do some early init */
  void s_init(void)
  {
-#if defined CONFIG_SPL_BUILD && defined CONFIG_MACH_SUN6I
+#if defined CONFIG_SPL_BUILD && \
+		(defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I)
  	/* Magic (undocmented) value taken from boot0, without this DRAM
  	 * access gets messed up (seems cache related) */
  	setbits_le32(SUNXI_SRAMC_BASE + 0x44, 0x1800);
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +0 -0
new file mode 100644
index 0000000..3736fd1

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 4

Quoted 4 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +4 -0
@@ -0,0 +1,340 @@
+/*
+ * Sun8i platform dram controller init.
+ *
+ * (C) Copyright 2014 Hans de Goede <[email protected]>

Is Allwinner copyright really not necessary here?

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 15

Quoted 10 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +10 -0
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * Note this code uses a lot of magic hex values, that is because this code
+ * simply replays the init sequence as done by the Allwinner boot0 code, so
+ * we do not know what these values mean. There are no symbolic constants for
+ * these magic values, since we do not know how to name them and making up
+ * names for them is not useful.
+ */

You are well aware of this documentation since a long time ago, right?

Quoted 1 line
    http://www.ti.com/lit/ug/spruhn7a/spruhn7a.pdf

I'm aware you've used various sources to figure out more about the A10 dram controller, since this DRAM controller seems significantly different I assumed your sources would not apply, it is good to hear that they do.

I'll add a comment to the next version of this patch referencing that document.

Quoted 99 lines

Please open it and find "Table4-2 DDR3 PHY Registers". Then have a look at the "sunxi_mctl_phy_reg" struct from your patch. Compare the register names and their offsets. Looks like we are reasonably lucky again.

Just as an example, I have commented about a few hardware registers at different locations in the code.

Quoted 33 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +33 -0
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/dram.h>
+#include <asm/arch/prcm.h>
+
+static const struct dram_para dram_para = {
+	.clock = CONFIG_DRAM_CLK,
+	.type = 3,
+	.zq = CONFIG_DRAM_ZQ,
+	.odt_en = 1,
+	.para1 = 0, /* not used (only used when tpr13 bit 31 is set */
+	.para2 = 0, /* not used (only used when tpr13 bit 31 is set */
+	.mr0 = 6736,
+	.mr1 = 4,
+	.mr2 = 16,
+	.mr3 = 0,
+	/* tpr0 - 10 contain timing constants or-ed together in u32 vals */
+	.tpr0 = 0x2ab83def,
+	.tpr1 = 0x18082356,
+	.tpr2 = 0x00034156,
+	.tpr3 = 0x448c5533,
+	.tpr4 = 0x08010d00,
+	.tpr5 = 0x0340b20f,
+	.tpr6 = 0x20d118cc,
+	.tpr7 = 0x14062485,
+	.tpr8 = 0x220d1d52,
+	.tpr9 = 0x1e078c22,
+	.tpr10 = 0x3c,
+	.tpr11 = 0, /* not used */
+	.tpr12 = 0, /* not used */
+	.tpr13 = 0x30000,

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 59

Quoted 10 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +10 -0
+};
+
+static void mctl_sys_init(void)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+	/* enable pll5, note the divide by 2 is deliberate! */
+	clock_set_pll5(dram_para.clock * 1000000 / 2, 1, 2,
+		       dram_para.tpr13 & 0x40000);

Is it really necessary to have the PLL5 setup so complicated and full of magic?

Quoted 28 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +28 -0
+
+	/* deassert ahb mctl reset */
+	setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL);
+
+	/* enable ahb mctl clock */
+	setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL);
+}
+
+static void mctl_apply_odt_correction(u32 *reg, int correction)
+{
+	int val;
+
+	val = (readl(reg) >> 8) & 0xff;
+	val += correction;
+
+	/* clamp */
+	if (val < 0)
+		val = 0;
+	else if (val > 255)
+		val = 255;
+
+	clrsetbits_le32(reg, 0xff00, val << 8);
+}
+
+static void mctl_init(u32 *bus_width)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 97

Quoted 10 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +10 -0
+	struct sunxi_mctl_com_reg * const mctl_com =
+		(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;
+	struct sunxi_mctl_phy_reg * const mctl_phy =
+		(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
+	int correction;
+
+	if (dram_para.tpr13 & 0x20)
+		writel(0x40b, &mctl_phy->dcr);

The bits 2-0 are DDRMR (DDR Mode), and the value 3 means DDR3. And 0x40b is actually the default reset value of this register according to the TI Keystone2 documentation.

Quoted 6 lines

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 99

Quoted 2 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +2 -0
+	else
+		writel(0x1000040b, &mctl_phy->dcr);

The bit 28 is marked as reserved and "Reads return zeros" in the TI Keystone2 documentation. It's a nice chance to test whether this write has any effect and whether it does modify the register.

It modifies the register, so that means that at least that bit does not match the TI Keystone2 documentation.

Quoted 15 lines

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 102

Quoted 4 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +3 -0
+
+	if (dram_para.clock >= 480)
+		writel(0x5c000, &mctl_phy->dllgcr);

0x5c000 = (1 << 18) | (0xE << 13)

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 102

Quoted 2 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +2 -0
+	else
+		writel(0xdc000, &mctl_phy->dllgcr);

0xdc000 = (3 << 18) | (0xE << 13)

The 'dllgcr' has the same offset as "4.40 PLL Control Register (PLLCR)" in the TI Keystone2 documentation.

Quoted 6 lines

Bits 16-13 are CPPC (Charge Pump Proportional Current Control) with the default value 0xE, which matches what we see here.

Bits 19-18 are FRQSEL:
01 = PLL reference clock (ctl_clk/REF_CLK) ranges from 225MHz to 385MHz 11 = PLL reference clock (ctl_clk/REF_CLK) ranges from 166MHz to 275MHz

That seems to match nicely, as said pll5 is set to dram_clk / 2. which puts the cut over point at 240 MHz

Quoted 80 lines
Quoted 80 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +79 -0
+
+	writel(0x0a003e3f, &mctl_phy->pgcr0);
+	writel(0x03008421, &mctl_phy->pgcr1);
+
+	writel(dram_para.mr0, &mctl_phy->mr0);
+	writel(dram_para.mr1, &mctl_phy->mr1);
+	writel(dram_para.mr2, &mctl_phy->mr2);
+	writel(dram_para.mr3, &mctl_phy->mr3);
+
+	if (!(dram_para.tpr13 & 0x10000)) {
+		clrsetbits_le32(&mctl_phy->dx0gcr, 0x3800, 0x2000);
+		clrsetbits_le32(&mctl_phy->dx1gcr, 0x3800, 0x2000);
+	}
+
+	/*
+	 * All the masking and shifting below converts what I assume are DDR
+	 * timing constants from Allwinner dram_para tpr format to the actual
+	 * timing registers format.
+	 */
+
+	writel((dram_para.tpr0 & 0x000fffff), &mctl_phy->ptr2);
+	writel((dram_para.tpr1 & 0x1fffffff), &mctl_phy->ptr3);
+	writel((dram_para.tpr0 & 0x3ff00000) >> 2 |
+	       (dram_para.tpr2 & 0x0003ffff), &mctl_phy->ptr4);
+
+	writel(dram_para.tpr3, &mctl_phy->dtpr0);
+	writel(dram_para.tpr4, &mctl_phy->dtpr2);
+
+	writel(0x01000081, &mctl_phy->dtcr);
+
+	if (dram_para.clock <= 240 || !(dram_para.odt_en & 0x01)) {
+		clrbits_le32(&mctl_phy->dx0gcr, 0x600);
+		clrbits_le32(&mctl_phy->dx1gcr, 0x600);
+	}
+	if (dram_para.clock <= 240) {
+		writel(0, &mctl_phy->odtcr);
+		writel(0, &mctl_ctl->odtmap);
+	}
+
+	writel(((dram_para.tpr5 & 0x0f00) << 12) |
+	       ((dram_para.tpr5 & 0x00f8) <<  9) |
+	       ((dram_para.tpr5 & 0x0007) <<  8),
+	       &mctl_ctl->rfshctl0);
+
+	writel(((dram_para.tpr5 & 0x0003f000) << 12) |
+	       ((dram_para.tpr5 & 0x00fc0000) >>  2) |
+	       ((dram_para.tpr5 & 0x3f000000) >> 16) |
+	       ((dram_para.tpr6 & 0x0000003f) >>  0),
+	       &mctl_ctl->dramtmg0);
+
+	writel(((dram_para.tpr6 & 0x000007c0) << 10) |
+	       ((dram_para.tpr6 & 0x0000f800) >> 3) |
+	       ((dram_para.tpr6 & 0x003f0000) >> 16),
+	       &mctl_ctl->dramtmg1);
+
+	writel(((dram_para.tpr6 & 0x0fc00000) << 2) |
+	       ((dram_para.tpr7 & 0x0000001f) << 16) |
+	       ((dram_para.tpr7 & 0x000003e0) << 3) |
+	       ((dram_para.tpr7 & 0x0000fc00) >> 10),
+	       &mctl_ctl->dramtmg2);
+
+	writel(((dram_para.tpr7 & 0x03ff0000) >> 16) |
+	       ((dram_para.tpr6 & 0xf0000000) >> 16),
+	       &mctl_ctl->dramtmg3);
+
+	writel(((dram_para.tpr7 & 0x3c000000) >> 2 ) |
+	       ((dram_para.tpr8 & 0x00000007) << 16) |
+	       ((dram_para.tpr8 & 0x00000038) << 5) |
+	       ((dram_para.tpr8 & 0x000003c0) >> 6),
+	       &mctl_ctl->dramtmg4);
+
+	writel(((dram_para.tpr8 & 0x00003c00) << 14) |
+	       ((dram_para.tpr8 & 0x0003c000) <<  2) |
+	       ((dram_para.tpr8 & 0x00fc0000) >> 10) |
+	       ((dram_para.tpr8 & 0x0f000000) >> 24),
+	       &mctl_ctl->dramtmg5);
+
+	writel(0x00000008, &mctl_ctl->dramtmg8);
+
Quoted 8 lines

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 188

Quoted 5 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +5 -0
+	writel(((dram_para.tpr8 & 0xf0000000) >> 4) |
+	       ((dram_para.tpr9 & 0x00007c00) << 6) |
+	       ((dram_para.tpr9 & 0x000003e0) << 3) |
+	       ((dram_para.tpr9 & 0x0000001f) >> 0),
+	       &mctl_ctl->pitmg0);

Could there be any purpose for this other than obfuscation? Looks really strange.

I think the purpose is to keep the dram_para.tpr? values the same as with sun6i, so that they can be copy pasted between designs ...

Quoted 57 lines
Quoted 27 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +26 -0
+
+	setbits_le32(&mctl_ctl->pitmg1, 0x80000);
+
+	writel(((dram_para.tpr9 & 0x003f8000) << 9) | 0x2001,
+	       &mctl_ctl->sched);
+
+	writel((dram_para.mr0 << 16) | dram_para.mr1, &mctl_ctl->init3);
+	writel((dram_para.mr2 << 16) | dram_para.mr3, &mctl_ctl->init4);
+
+	writel(0x00000000, &mctl_ctl->pimisc);
+	writel(0x80000000, &mctl_ctl->upd0);
+
+	writel(((dram_para.tpr9  & 0xffc00000) >> 22) |
+	       ((dram_para.tpr10 & 0x00000fff) << 16),
+	       &mctl_ctl->rfshtmg);
+
+	if (dram_para.tpr13 & 0x20)
+		writel(0x01040001, &mctl_ctl->mstr);
+	else
+		writel(0x01040401, &mctl_ctl->mstr);
+
+	if (!(dram_para.tpr13 & 0x20000)) {
+		writel(0x00000002, &mctl_ctl->pwrctl);
+		writel(0x00008001, &mctl_ctl->pwrtmg);
+	}
+

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 224

Quoted 10 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +10 -0
+	writel(0x00000001, &mctl_ctl->rfshctl3);
+	writel(0x00000001, &mctl_ctl->pimisc);
+
+	/* deassert dram_clk_cfg reset */
+	setbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST);
+
+	setbits_le32(&mctl_com->ccr, 0x80000);
+
+	/* zq stuff */
+	writel((dram_para.zq >> 8) & 0xff, &mctl_phy->zqcr1);

4.59 Impedance Control Register 1 (ZQnCR1)

Bits 7-0 - ZPROG (Impedance Divide Ratio), reset value 0x7B

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 226

Quoted 1 line
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +1 -0
+	writel(0x00000003, &mctl_phy->pir);

4.34 PHY Initialization Register (PIR)

Bit 0 - INIT
Bit 1 - ZCAL

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 228

Quoted 2 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +2 -0
+	udelay(10);
+	mctl_await_completion(&mctl_phy->pgsr0, 0x09, 0x09);

4.38 PHY General Status Register 0 (PGSR0)

Bit 0 - IDONE (Initialization Done)
Bit 3 - ZCDONE (Impedance Calibration Done)

Quoted 6 lines

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 227

Quoted 2 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +2 -0
+	writel(readl(&mctl_phy->zqsr0) | 0x10000000, &mctl_phy->zqcr2);
+	writel(dram_para.zq & 0xff, &mctl_phy->zqcr1);

Overwriting ZPROG again? Is it doing something reasonable? Or might it be an attempt to hide data from the tools like a10-meminfo (which can dump the DRAM setting via /dev/mem)?

I've no clue.

Regards,

Hans

Quoted 468 lines
Quoted 465 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +108 -0
+	/* A23-v1.0 SDK uses 0xfdf3, A23-v2.0 SDK uses 0x5f3 */
+	writel(0x000005f3, &mctl_phy->pir);
+	udelay(10);
+	mctl_await_completion(&mctl_phy->pgsr0, 0x03, 0x03);
+
+	if (readl(&mctl_phy->dx1gsr0) & 0x1000000) {
+		*bus_width = 8;
+		writel(0, &mctl_phy->dx1gcr);
+		writel(dram_para.zq & 0xff, &mctl_phy->zqcr1);
+		writel(0x5f3, &mctl_phy->pir);
+		udelay(10000);
+		setbits_le32(&mctl_ctl->mstr, 0x1000);
+	} else
+		*bus_width = 16;
+
+	correction = (dram_para.odt_en >> 8) & 0xff;
+	if (correction) {
+		if (dram_para.odt_en & 0x80000000)
+			correction = -correction;
+
+		mctl_apply_odt_correction(&mctl_phy->dx0lcdlr1, correction);
+		mctl_apply_odt_correction(&mctl_phy->dx1lcdlr1, correction);
+	}
+
+	mctl_await_completion(&mctl_ctl->statr, 0x01, 0x01);
+
+	writel(0x08003e3f, &mctl_phy->pgcr0);
+	writel(0x00000000, &mctl_ctl->rfshctl3);
+}
+
+unsigned long sunxi_dram_init(void)
+{
+	struct sunxi_mctl_com_reg * const mctl_com =
+		(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+	const u32 columns = 13;
+	u32 bus, bus_width, offset, page_size, rows;
+
+	mctl_sys_init();
+	mctl_init(&bus_width);
+
+	if (bus_width == 16) {
+		page_size = 8;
+		bus = 1;
+	} else {
+		page_size = 7;
+		bus = 0;
+	}
+
+	if (!(dram_para.tpr13 & 0x80000000)) {
+		/* Detect and set rows */
+		writel(0x000310f4 | MCTL_CR_PAGE_SIZE(page_size),
+		       &mctl_com->cr);
+		setbits_le32(&mctl_com->swonr, 0x0003ffff);
+		mctl_mem_fill();
+		for (rows = 11; rows < 16; rows++) {
+			offset = 1 << (rows + columns + bus);
+			if (mctl_mem_matches(offset))
+				break;
+		}
+		clrsetbits_le32(&mctl_com->cr, MCTL_CR_ROW_MASK,
+				MCTL_CR_ROW(rows));
+	} else {
+		rows = (dram_para.para1 >> 16) & 0xff;
+		writel(((dram_para.para2 & 0x000000f0) << 11) |
+		       ((rows - 1) << 4) |
+		       ((dram_para.para1 & 0x0f000000) >> 22) |
+		       0x31000 | MCTL_CR_PAGE_SIZE(page_size),
+		       &mctl_com->cr);
+		setbits_le32(&mctl_com->swonr, 0x0003ffff);
+	}
+
+	/* Setup DRAM master priority? If this is left out things still work */
+	writel(0x00000008, &mctl_com->mcr0_0);
+	writel(0x0001000d, &mctl_com->mcr1_0);
+	writel(0x00000004, &mctl_com->mcr0_1);
+	writel(0x00000080, &mctl_com->mcr1_1);
+	writel(0x00000004, &mctl_com->mcr0_2);
+	writel(0x00000019, &mctl_com->mcr1_2);
+	writel(0x00000004, &mctl_com->mcr0_3);
+	writel(0x00000080, &mctl_com->mcr1_3);
+	writel(0x00000004, &mctl_com->mcr0_4);
+	writel(0x01010040, &mctl_com->mcr1_4);
+	writel(0x00000004, &mctl_com->mcr0_5);
+	writel(0x0001002f, &mctl_com->mcr1_5);
+	writel(0x00000004, &mctl_com->mcr0_6);
+	writel(0x00010020, &mctl_com->mcr1_6);
+	writel(0x00000004, &mctl_com->mcr0_7);
+	writel(0x00010020, &mctl_com->mcr1_7);
+	writel(0x00000008, &mctl_com->mcr0_8);
+	writel(0x00000001, &mctl_com->mcr1_8);
+	writel(0x00000008, &mctl_com->mcr0_9);
+	writel(0x00000005, &mctl_com->mcr1_9);
+	writel(0x00000008, &mctl_com->mcr0_10);
+	writel(0x00000003, &mctl_com->mcr1_10);
+	writel(0x00000008, &mctl_com->mcr0_11);
+	writel(0x00000005, &mctl_com->mcr1_11);
+	writel(0x00000008, &mctl_com->mcr0_12);
+	writel(0x00000003, &mctl_com->mcr1_12);
+	writel(0x00000008, &mctl_com->mcr0_13);
+	writel(0x00000004, &mctl_com->mcr1_13);
+	writel(0x00000008, &mctl_com->mcr0_14);
+	writel(0x00000002, &mctl_com->mcr1_14);
+	writel(0x00000008, &mctl_com->mcr0_15);
+	writel(0x00000003, &mctl_com->mcr1_15);
+	writel(0x00010138, &mctl_com->bwcr);
+
+	return 1 << (rows + columns + bus);
+}
arch/arm/include/asm/arch-sunxi/clock_sun6i.h +4 -0
index 7d61216..45a199c 100644
@@ -273,7 +273,11 @@ struct sunxi_ccm_reg {
  #define CCM_HDMI_CTRL_DDC_GATE		(0x1 << 30)
  #define CCM_HDMI_CTRL_GATE		(0x1 << 31)
 
+#ifndef CONFIG_MACH_SUN8I
  #define MBUS_CLK_DEFAULT		0x81000001 /* PLL6 / 2 */
+#else
+#define MBUS_CLK_DEFAULT		0x81000003 /* PLL6 / 4 */
+#endif
 
  #define CCM_PLL5_PATTERN		0xd1303333
 
arch/arm/include/asm/arch-sunxi/dram.h +2 -0
index a8a37d5..8d78029 100644
@@ -18,6 +18,8 @@
  /* dram regs definition */
  #if defined(CONFIG_MACH_SUN6I)
  #include <asm/arch/dram_sun6i.h>
+#elif defined(CONFIG_MACH_SUN8I)
+#include <asm/arch/dram_sun8i.h>
  #else
  #include <asm/arch/dram_sun4i.h>
  #endif
arch/arm/include/asm/arch-sunxi/dram_sun8i.h new file +266 -0
new file mode 100644
index 0000000..425cf37
@@ -0,0 +1,266 @@
+/*
+ * Sun8i platform dram controller register and constant defines
+ *
+ * (C) Copyright 2007-2013
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * CPL <[email protected]>
+ * Jerry Wang <[email protected]>
+ *
+ * (C) Copyright 2014 Hans de Goede <[email protected]>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _SUNXI_DRAM_SUN8I_H
+#define _SUNXI_DRAM_SUN8I_H
+
+struct dram_para {
+	u32 clock;
+	u32 type;
+	u32 zq;
+	u32 odt_en;
+	u32 para1;
+	u32 para2;
+	u32 mr0;
+	u32 mr1;
+	u32 mr2;
+	u32 mr3;
+	u32 tpr0;
+	u32 tpr1;
+	u32 tpr2;
+	u32 tpr3;
+	u32 tpr4;
+	u32 tpr5;
+   	u32 tpr6;
+	u32 tpr7;
+	u32 tpr8;
+	u32 tpr9;
+	u32 tpr10;
+	u32 tpr11;
+	u32 tpr12;
+	u32 tpr13;
+};
+
+struct sunxi_mctl_com_reg {
+	u32 cr;			/* 0x00 */
+	u32 ccr;		/* 0x04 controller configuration register */
+	u32 dbgcr;		/* 0x08 */
+	u8 res0[0x4];		/* 0x0c */
+	u32 mcr0_0;		/* 0x10 */
+	u32 mcr1_0;		/* 0x14 */
+	u32 mcr0_1;		/* 0x18 */
+	u32 mcr1_1;		/* 0x1c */
+	u32 mcr0_2;		/* 0x20 */
+	u32 mcr1_2;		/* 0x24 */
+	u32 mcr0_3;		/* 0x28 */
+	u32 mcr1_3;		/* 0x2c */
+	u32 mcr0_4;		/* 0x30 */
+	u32 mcr1_4;		/* 0x34 */
+	u32 mcr0_5;		/* 0x38 */
+	u32 mcr1_5;		/* 0x3c */
+	u32 mcr0_6;		/* 0x40 */
+	u32 mcr1_6;		/* 0x44 */
+	u32 mcr0_7;		/* 0x48 */
+	u32 mcr1_7;		/* 0x4c */
+	u32 mcr0_8;		/* 0x50 */
+	u32 mcr1_8;		/* 0x54 */
+	u32 mcr0_9;		/* 0x58 */
+	u32 mcr1_9;		/* 0x5c */
+	u32 mcr0_10;		/* 0x60 */
+	u32 mcr1_10;		/* 0x64 */
+	u32 mcr0_11;		/* 0x68 */
+	u32 mcr1_11;		/* 0x6c */
+	u32 mcr0_12;		/* 0x70 */
+	u32 mcr1_12;		/* 0x74 */
+	u32 mcr0_13;		/* 0x78 */
+	u32 mcr1_13;		/* 0x7c */
+	u32 mcr0_14;		/* 0x80 */
+	u32 mcr1_14;		/* 0x84 */
+	u32 mcr0_15;		/* 0x88 */
+	u32 mcr1_15;		/* 0x8c */
+	u32 bwcr;		/* 0x90 */
+	u32 maer;		/* 0x94 */
+	u8 res1[0x4];		/* 0x98 */
+	u32 mcgcr;		/* 0x9c */
+	u32 bwctr;		/* 0xa0 */
+	u8 res2[0x4];		/* 0xa4 */
+	u32 swonr;		/* 0xa8 */
+	u32 swoffr;		/* 0xac */
+};
+
+struct sunxi_mctl_ctl_reg {
+	u32 mstr;		/* 0x00 */
+	u32 statr;		/* 0x04 */
+	u8 res0[0x08];		/* 0x08 */
+	u32 mrctrl0;		/* 0x10 */
+	u32 mrctrl1;		/* 0x14 */
+	u32 mrstatr;		/* 0x18 */
+	u8 res1[0x04];		/* 0x1c */
+	u32 derateen;		/* 0x20 */
+	u32 deratenint;		/* 0x24 */
+	u8 res2[0x08];		/* 0x28 */
+	u32 pwrctl;		/* 0x30 */
+	u32 pwrtmg;		/* 0x34 */
+	u8 res3[0x18];		/* 0x38 */
+	u32 rfshctl0;		/* 0x50 */
+	u32 rfshctl1;		/* 0x54 */
+	u8 res4[0x8];		/* 0x58 */
+	u32 rfshctl3;		/* 0x60 */
+	u32 rfshtmg;		/* 0x64 */
+	u8 res6[0x68];		/* 0x68 */
+	u32 init0;		/* 0xd0 */
+	u32 init1;		/* 0xd4 */
+	u32 init2;		/* 0xd8 */
+	u32 init3;		/* 0xdc */
+	u32 init4;		/* 0xe0 */
+	u32 init5;		/* 0xe4 */
+	u8 res7[0x0c];		/* 0xe8 */
+	u32 rankctl;		/* 0xf4 */
+	u8 res8[0x08];		/* 0xf8 */
+	u32 dramtmg0;		/* 0x100 */
+	u32 dramtmg1;		/* 0x104 */
+	u32 dramtmg2;		/* 0x108 */
+	u32 dramtmg3;		/* 0x10c */
+	u32 dramtmg4;		/* 0x110 */
+	u32 dramtmg5;		/* 0x114 */
+	u32 dramtmg6;		/* 0x118 */
+	u32 dramtmg7;		/* 0x11c */
+	u32 dramtmg8;		/* 0x120 */
+	u8 res9[0x5c];		/* 0x124 */
+	u32 zqctl0;		/* 0x180 */
+	u32 zqctl1;		/* 0x184 */
+	u32 zqctl2;		/* 0x188 */
+	u32 zqstat;		/* 0x18c */
+	u32 pitmg0;		/* 0x190 */
+	u32 pitmg1;		/* 0x194 */
+	u32 plpcfg0;		/* 0x198 */
+	u8 res10[0x04];		/* 0x19c */
+	u32 upd0;		/* 0x1a0 */
+	u32 upd1;		/* 0x1a4 */
+	u32 upd2;		/* 0x1a8 */
+	u32 upd3;		/* 0x1ac */
+	u32 pimisc;		/* 0x1b0 */
+	u8 res11[0x1c];		/* 0x1b4 */
+	u32 trainctl0;		/* 0x1d0 */
+	u32 trainctl1;		/* 0x1d4 */
+	u32 trainctl2;		/* 0x1d8 */
+	u32 trainstat;		/* 0x1dc */
+	u8 res12[0x60];		/* 0x1e0 */
+	u32 odtcfg;		/* 0x240 */
+	u32 odtmap;		/* 0x244 */
+	u8 res13[0x08];		/* 0x248 */
+	u32 sched;		/* 0x250 */
+	u8 res14[0x04];		/* 0x254 */
+	u32 perfshpr0;		/* 0x258 */
+	u32 perfshpr1;		/* 0x25c */
+	u32 perflpr0;		/* 0x260 */
+	u32 perflpr1;		/* 0x264 */
+	u32 perfwr0;		/* 0x268 */
+	u32 perfwr1;		/* 0x26c */
+};
+
+struct sunxi_mctl_phy_reg {
+	u8 res0[0x04];		/* 0x00 */
+	u32 pir;		/* 0x04 */
+	u32 pgcr0;		/* 0x08 phy general configuration register */
+	u32 pgcr1;		/* 0x0c phy general configuration register */
+	u32 pgsr0;		/* 0x10 */
+	u32 pgsr1;		/* 0x14 */
+	u32 dllgcr;		/* 0x18 */
+	u32 ptr0;		/* 0x1c */
+	u32 ptr1;		/* 0x20 */
+	u32 ptr2;		/* 0x24 */
+	u32 ptr3;		/* 0x28 */
+	u32 ptr4;		/* 0x2c */
+	u32 acmdlr;		/* 0x30 */
+	u32 acbdlr;		/* 0x34 */
+	u32 aciocr;		/* 0x38 */
+	u32 dxccr;		/* 0x3c DATX8 common configuration register */
+	u32 dsgcr;		/* 0x40 dram system general config register */
+	u32 dcr;		/* 0x44 */
+	u32 dtpr0;		/* 0x48 dram timing parameters register 0 */
+	u32 dtpr1;		/* 0x4c dram timing parameters register 1 */
+	u32 dtpr2;		/* 0x50 dram timing parameters register 2 */
+	u32 mr0;		/* 0x54 mode register 0 */
+	u32 mr1;		/* 0x58 mode register 1 */
+	u32 mr2;		/* 0x5c mode register 2 */
+	u32 mr3;		/* 0x60 mode register 3 */
+	u32 odtcr;		/* 0x64 */
+	u32 dtcr;		/* 0x68 */
+	u32 dtar0;		/* 0x6c data training address register 0 */
+	u32 dtar1;		/* 0x70 data training address register 1 */
+	u32 dtar2;		/* 0x74 data training address register 2 */
+	u32 dtar3;		/* 0x78 data training address register 3 */
+	u32 dtdr0;		/* 0x7c */
+	u32 dtdr1;		/* 0x80 */
+	u32 dtedr0;		/* 0x84 */
+	u32 dtedr1;		/* 0x88 */
+	u32 pgcr2;		/* 0x8c */
+	u8 res1[0x70];		/* 0x90 */
+	u32 bistrr;		/* 0x100 */
+	u32 bistwcr;		/* 0x104 */
+	u32 bistmskr0;		/* 0x108 */
+	u32 bistmskr1;		/* 0x10c */
+	u32 bistmskr2;		/* 0x110 */
+	u32 bistlsr;		/* 0x114 */
+	u32 bistar0;		/* 0x118 */
+	u32 bistar1;		/* 0x11c */
+	u32 bistar2;		/* 0x120 */
+	u32 bistupdr;		/* 0x124 */
+	u32 bistgsr;		/* 0x128 */
+	u32 bistwer;		/* 0x12c */
+	u32 bistber0;		/* 0x130 */
+	u32 bistber1;		/* 0x134 */
+	u32 bistber2;		/* 0x138 */
+	u32 bistber3;		/* 0x13c */
+	u32 bistwcsr;		/* 0x140 */
+	u32 bistfwr0;		/* 0x144 */
+	u32 bistfwr1;		/* 0x148 */
+	u32 bistfwr2;		/* 0x14c */
+	u8 res2[0x30];		/* 0x150 */
+	u32 zqcr0;		/* 0x180 zq control register 0 */
+	u32 zqcr1;		/* 0x184 zq control register 1 */
+	u32 zqsr0;		/* 0x188 zq status register 0 */
+	u32 zqsr1;		/* 0x18c zq status register 1 */
+	u32 zqcr2;		/* 0x190 zq control register 2 */
+	u8 res3[0x2c];		/* 0x194 */
+	u32 dx0gcr;		/* 0x1c0 */
+	u32 dx0gsr0;		/* 0x1c4 */
+	u32 dx0gsr1;		/* 0x1c8 */
+	u32 dx0bdlr0;		/* 0x1cc */
+	u32 dx0bdlr1;		/* 0x1d0 */
+	u32 dx0bdlr2;		/* 0x1d4 */
+	u32 dx0bdlr3;		/* 0x1d8 */
+	u32 dx0bdlr4;		/* 0x1dc */
+	u32 dx0lcdlr0;		/* 0x1e0 */
+	u32 dx0lcdlr1;		/* 0x1e4 */
+	u32 dx0lcdlr2;		/* 0x1e8 */
+	u32 dx0mdlr;		/* 0x1ec */
+	u32 dx0gtr;		/* 0x1f0 */
+	u32 dx0gsr2;		/* 0x1f4 */
+	u8 res4[0x08];		/* 0x1f8 */
+	u32 dx1gcr;		/* 0x200 */
+	u32 dx1gsr0;		/* 0x204 */
+	u32 dx1gsr1;		/* 0x208 */
+	u32 dx1bdlr0;		/* 0x20c */
+	u32 dx1bdlr1;		/* 0x210 */
+	u32 dx1bdlr2;		/* 0x214 */
+	u32 dx1bdlr3;		/* 0x218 */
+	u32 dx1bdlr4;		/* 0x21c */
+	u32 dx1lcdlr0;		/* 0x220 */
+	u32 dx1lcdlr1;		/* 0x224 */
+	u32 dx1lcdlr2;		/* 0x228 */
+	u32 dx1mdlr;		/* 0x22c */
+	u32 dx1gtr;		/* 0x230 */
+	u32 dx1gsr2;		/* 0x234 */
+};
+
+/*
+ * DRAM common (sunxi_mctl_com_reg) register constants.
+ */
+#define MCTL_CR_ROW_MASK		(0xf << 4)
+#define MCTL_CR_ROW(x)			(((x) - 1) << 4)
+#define MCTL_CR_PAGE_SIZE_MASK		(0xf << 8)
+#define MCTL_CR_PAGE_SIZE(x)		((x) << 8)
+
+#endif /* _SUNXI_DRAM_SUN8I_H */
board/sunxi/Kconfig +2 -1
index 5bb2f58..5a88ba0 100644
@@ -29,10 +29,11 @@ config MACH_SUN7I
  config MACH_SUN8I
  	bool "sun8i (Allwinner A23)"
  	select CPU_V7
+	select SUPPORT_SPL
 
  endchoice
 
-if MACH_SUN6I
+if MACH_SUN6I || MACH_SUN8I
 
  config DRAM_CLK
  	int "sun6i dram clock speed"
configs/Ippo_q8h_v5_defconfig +12 -5
index 50c2f93..37aa46d 100644
@@ -1,8 +1,15 @@
+CONFIG_SPL=y
  CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
-CONFIG_ARM=y
-CONFIG_ARCH_SUNXI=y
-CONFIG_MACH_SUN8I=y
-CONFIG_TARGET_IPPO_Q8H_V5=y
-CONFIG_DEFAULT_DEVICE_TREE="sun8i-a23-ippo-q8h-v5.dtb"
+CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v5.dtb"
  CONFIG_VIDEO=n
  CONFIG_USB_KEYBOARD=n
++S:CONFIG_ARM=y
++S:CONFIG_ARCH_SUNXI=y
++S:CONFIG_MACH_SUN8I=y
++S:CONFIG_DRAM_CLK=480
+# zq = 0xf777
++S:CONFIG_DRAM_ZQ=63351
+# Wifi power
++S:CONFIG_AXP221_DLDO1_VOLT=3300
+# aldo1 is connected to VCC-IO, VCC-PD, VCC-USB and VCC-HP
++S:CONFIG_AXP221_ALDO1_VOLT=3000
include/configs/sun8i.h +2 -0
index 6f1fc48..792422d 100644
@@ -12,6 +12,8 @@
  /*
   * A23 specific configuration
   */
+#define CONFIG_CLK_FULL_SPEED	1008000000
+
  #define CONFIG_SYS_PROMPT	"sun8i# "
 
  /*
#50 lore raw

PATCH 13/14 sun8i: Add dram initialization support

Quoted 9 lines · On Fri, 19 Dec 2014 18:05:49 +0100 Hans de Goede <[email protected]> wrote:

Hi,

Quoted 6 lines · Siarhei Siamashka
Quoted 2 lines · On Tue, 16 Dec 2014 21:31:38 +0100 Hans de Goede <[email protected]> wrote:

Based on the register / dram_para headers from the Allwinner u-boot / linux sources + the init sequences from boot0.

Quoted 6 lines
Quoted 3 lines

Can the commit message have more detailed information about the precise location of the original Allwinner code, which was used as the reference?

No, it cannot because no code was referenced, I traced the boot0 binary to figure out what was needed to get dram going on the A23.

Thanks for explaining. And good job extracting all the information from there.

In this case, can we have a clear reference to this binary in the commit message? It might be useful to have a look at objdump logs when reviewing your patch.

[...]

Quoted 23 lines
Quoted 21 lines

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 4

Quoted 6 lines

+++ b/arch/arm/cpu/armv7/sunxi/dram_sun8i.c

arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +4 -0
@@ -0,0 +1,340 @@
+/*
+ * Sun8i platform dram controller init.
+ *
+ * (C) Copyright 2014 Hans de Goede <[email protected]>

Is Allwinner copyright really not necessary here?

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 15

Quoted 10 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +10 -0
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * Note this code uses a lot of magic hex values, that is because this code
+ * simply replays the init sequence as done by the Allwinner boot0 code, so
+ * we do not know what these values mean. There are no symbolic constants for
+ * these magic values, since we do not know how to name them and making up
+ * names for them is not useful.
+ */

You are well aware of this documentation since a long time ago, right?

Quoted 1 line
    http://www.ti.com/lit/ug/spruhn7a/spruhn7a.pdf
Quoted 3 lines

I'm aware you've used various sources to figure out more about the A10 dram controller, since this DRAM controller seems significantly different I assumed your sources would not apply, it is good to hear that they do.

I wonder how could you have ended up with this strange assumption? When I clearly told you that "It looks like the Allwinner A31 DRAM controller registers are very similar to what is used in RK3288" and provided the links to the relevant sources and documentation back in September:

    http://lists.denx.de/pipermail/u-boot/2014-September/189199.html

Then reminded yet again about this RK3288 similarity and used the mctl_phy->ptr0 register as an example:

    http://lists.denx.de/pipermail/u-boot/2014-December/198582.html

When we were discussing the A31 DRAM controller, of course you should have expected the information about A31.

Yes, A23 was not a part of the picture at that time. However comparing its registers with the information from spruhn7a.pdf and various Rockchip source code drops is a very natural thing to try.

So far the best matching pairs (almost 100% identical PHY) are:
Allwinner A10 (sun4i) - RK29xx
Allwinner A31 (sun6i) - RK3288
Allwinner A23 (sun8i) - TI Keystone2

It's all the same family of DRAM controllers, very likely just different revisions/generations from the same supplier. I don't expect A80 or other Allwinner chips to be any different.

[...]

Quoted 9 lines
Quoted 6 lines

arch/arm/cpu/armv7/sunxi/dram_sun8i.c line 99

Quoted 2 lines
arch/arm/cpu/armv7/sunxi/dram_sun8i.c new file +2 -0
+	else
+		writel(0x1000040b, &mctl_phy->dcr);

The bit 28 is marked as reserved and "Reads return zeros" in the TI Keystone2 documentation. It's a nice chance to test whether this write has any effect and whether it does modify the register.

It modifies the register, so that means that at least that bit does not match the TI Keystone2 documentation.

OK.

Signature · 2 lines
Best regards,
Siarhei Siamashka
#51 lore raw

PATCH 14/14 sun8i: Add defconfig for Ippo_q8h v1.2

In reply to Hans de Goede

We need separate defconfigs for the v5 and v1.2 versions of this board, as they use different DRAM parameters.

Note they also use different dtb files, as the wifi is different too.

---
 configs/Ippo_q8h_v1.2_defconfig | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
 create mode 100644 configs/Ippo_q8h_v1.2_defconfig
configs/Ippo_q8h_v1.2_defconfig new file +15 -0
new file mode 100644
index 0000000..fefed32
@@ -0,0 +1,15 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
+CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v1.2.dtb"
+CONFIG_VIDEO=n
+CONFIG_USB_KEYBOARD=n
++S:CONFIG_ARM=y
++S:CONFIG_ARCH_SUNXI=y
++S:CONFIG_MACH_SUN8I=y
++S:CONFIG_DRAM_CLK=432
+# zq = 0xf74a
++S:CONFIG_DRAM_ZQ=63306
+# Wifi power
++S:CONFIG_AXP221_DLDO1_VOLT=3300
+# aldo1 is connected to VCC-IO, VCC-PD, VCC-USB and VCC-HP
++S:CONFIG_AXP221_ALDO1_VOLT=3000
Signature · 1 line
2.1.0
#52 lore raw

PATCH 14/14 sun8i: Add defconfig for Ippo_q8h v1.2

Quoted 6 lines · Hans de Goede

We need separate defconfigs for the v5 and v1.2 versions of this board, as they use different DRAM parameters.

Note they also use different dtb files, as the wifi is different too.

(I think this is the patch you mentioned just now WRT having added a MAINTAINERS entry, so I won't mention it again ;-))

Quoted 6 lines
configs/Ippo_q8h_v1.2_defconfig new file +0 -0
new file mode 100644
index 0000000..fefed32

configs/Ippo_q8h_v1.2_defconfig line 8

Quoted 8 lines
configs/Ippo_q8h_v1.2_defconfig new file +8 -0
@@ -0,0 +1,15 @@
+CONFIG_SPL=y
+CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
+CONFIG_FDTFILE="sun8i-a23-ippo-q8h-v1.2.dtb"
+CONFIG_VIDEO=n
+CONFIG_USB_KEYBOARD=n
++S:CONFIG_ARM=y
++S:CONFIG_ARCH_SUNXI=y
++S:CONFIG_MACH_SUN8I=y

No CONFIG_TARGET? Do you want to send a patch to nuke them all, better than having a mixture IMHO.

Ian.