sun6i: s/SUNXI_GPL0_R_P2WI/SUN6I_GPL0_R_P2WI/
Subsystems (3)
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
@@ -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
@@ -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
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
@@ -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
@@ -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
@@ -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
@@ -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
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
Signed-off-by Hans de Goede <[email protected]>--- 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.harch/arm/cpu/armv7/sunxi/Makefile +1
-0@@ -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.oarch/arm/cpu/armv7/sunxi/rsb.c new file +45
-0@@ -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
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 0x3f500000arch/arm/include/asm/arch-sunxi/gpio.h +2
-0@@ -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 2arch/arm/include/asm/arch-sunxi/prcm.h +2
-1@@ -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@@ -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
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
Signed-off-by Hans de Goede <[email protected]>--- 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.ccreate mode 100644arch/arm/include/asm/arch-sunxi/rsb.harch/arm/cpu/armv7/sunxi/Makefile +1
-0@@ -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.oarch/arm/cpu/armv7/sunxi/rsb.c new file +49
-0@@ -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
-0arch/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 0x3f500000arch/arm/include/asm/arch-sunxi/gpio.h +2
-0@@ -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 2arch/arm/include/asm/arch-sunxi/prcm.h +2
-1@@ -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@@ -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
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.
PATCH 2/14 sunxi: Add support for the rsb (Reduced Serial Bus)
In reply to Hans de GoedeQuoted 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.
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
PATCH 3/14 sunxi: axp221: Add axp223 support
In reply to Hans de GoedeThe 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
@@ -76,7 +76,7 @@ int print_cpuinfo(void)int sunxi_get_sid (unsigned int *sid) { -#ifdef CONFIG_MACH_SUN6I +#if definedCONFIG_MACH_SUN6I || definedCONFIG_MACH_SUN8I #ifdef CONFIG_AXP221_POWER return axp221_get_sid (sid);#else
drivers/power/Kconfig +4 -4
@@ -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
@@ -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
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.
Signed-off-by Hans de Goede <[email protected]>--- 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@@ -76,7 +76,7 @@ int print_cpuinfo(void)int sunxi_get_sid (unsigned int *sid) { -#ifdef CONFIG_MACH_SUN6I +#if definedCONFIG_MACH_SUN6I || definedCONFIG_MACH_SUN8I #ifdef CONFIG_AXP221_POWER return axp221_get_sid (sid);#else drivers/power/Kconfig +4
-4@@ -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@@ -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@@ -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
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.
Signed-off-by Hans de Goede <[email protected]>--- 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@@ -76,7 +76,7 @@ int print_cpuinfo(void)int sunxi_get_sid (unsigned int *sid) { -#ifdef CONFIG_MACH_SUN6I +#if definedCONFIG_MACH_SUN6I || definedCONFIG_MACH_SUN8I #ifdef CONFIG_AXP221_POWER return axp221_get_sid (sid);#else drivers/power/Kconfig +4
-4@@ -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@@ -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@@ -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
PATCH 3/14 sunxi: axp221: Add axp223 support
In reply to Hans de GoedeQuoted 5 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.
Signed-off-by Hans de Goede <[email protected]>
With the whitespace fixed:
PATCH 4/14 sunxi: axp221: Add Kconfig help and sane defaults for typical ldo usage
In reply to Hans de GoedeSome 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH 4/14 sunxi: axp221: Add Kconfig help and sane defaults for typical ldo usage
Quoted 5 lines · Hans de Goede
Some of the ldo-s of the axp221 are used in the same way on most boards, add comments to the
Kconfighelp text to reflect this, and give them defaults matching their typical usage.Signed-off-by Hans de Goede <[email protected]>
PATCH 5/14 sunxi: axp221: Make dcdc1 voltage configurable
In reply to Hans de GoedeThe 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
@@ -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
@@ -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
@@ -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
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.
Signed-off-by Hans de Goede <[email protected]>
PATCH 6/14 sunxi: axp221: Explicitly turn off unused voltages
In reply to Hans de GoedeExplicitly 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
@@ -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
@@ -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
@@ -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
PATCH 6/14 sunxi: axp221: Explicitly turn off unused voltages
Quoted 5 lines · 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.
Signed-off-by Hans de Goede <[email protected]>
PATCH 7/14 sunxi: axp221: Disable dcdc4 on sun8i (A23)
In reply to Hans de Goededcdc4 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
@@ -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
PATCH 7/14 sunxi: axp221: Disable dcdc4 on sun8i (A23)
Quoted 6 lines · 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.
Signed-off-by Hans de Goede <[email protected]>
(although I'm wondering if it might have been better to make this Kconfigurable...)
PATCH 8/14 sun6i: Add a sigma_delta_enable paramter to clock_set_pll5()
In reply to Hans de GoedeThe 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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH 8/14 sun6i: Add a sigma_delta_enable paramter to clock_set_pll5()
Quoted 4 lines · Hans de Goede
The sun8i dram code sometimes wants to enable sigma delta mode, add a parameter to allow this.
Signed-off-by Hans de Goede <[email protected]>
PATCH 8/14 sun6i: Add a sigma_delta_enable paramter to clock_set_pll5()
In reply to Hans de GoedeQuoted 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.
Signed-off-by Hans de Goede <[email protected]>--- 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@@ -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
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
-0clrsetbits_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@@ -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@@ -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
PATCH 9/14 sun6i: Add k and m parameters to clock_set_pll5()
In reply to Hans de GoedeThe 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
@@ -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
@@ -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
@@ -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
PATCH 9/14 sun6i: Add k and m parameters to clock_set_pll5()
Quoted 4 lines · Hans de Goede
The A23 (sun8i) requires different values for these then sun6i, so make them function parameters.
Signed-off-by Hans de Goede <[email protected]>
PATCH 9/14 sun6i: Add k and m parameters to clock_set_pll5()
In reply to Hans de GoedeQuoted 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.
Signed-off-by Hans de Goede <[email protected]>
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@@ -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@@ -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@@ -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
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.
Signed-off-by Hans de Goede <[email protected]>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@@ -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@@ -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@@ -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 */
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.
Signed-off-by Hans de Goede <[email protected]>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 todram_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@@ -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@@ -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@@ -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 */
PATCH 10/14 sunxi: Move await_completion dram helper to dram.h
In reply to Hans de GoedeThe 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
@@ -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
@@ -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
@@ -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
PATCH 10/14 sunxi: Move await_completion dram helper to dram.h
Quoted 5 lines · Hans de Goede
The
await_completionhelper 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 indram.h, rather then adding yet another copy.Signed-off-by Hans de Goede <[email protected]>
PATCH 10/14 sunxi: Move await_completion dram helper to dram.h
In reply to Hans de GoedeQuoted 5 lines · On Tue, 16 Dec 2014 21:31:35 +0100 Hans de Goede <[email protected]> wrote:
The
await_completionhelper 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 indram.h, rather then adding yet another copy.Signed-off-by Hans de Goede <[email protected]>
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@@ -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@@ -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
-8writel (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@@ -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
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_completionhelper 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 indram.h, rather then adding yet another copy.Signed-off-by Hans de Goede <[email protected]>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
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_completionhelper 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 indram.h, rather then adding yet another copy.Signed-off-by Hans de Goede <[email protected]>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
PATCH 11/14 sunxi: Fill memory before comparing it when doing dram init on sun6i
In reply to Hans de GoedeThe 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
@@ -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
@@ -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
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_fillfunction this introduces is added as an inline helper indram.h, so that it can be shared with the sun8i dram code.While at it move
mctl_mem_matchestodram.hfor re-use in sun8i too.Signed-off-by Hans de Goede <[email protected]>--- 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@@ -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@@ -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 */
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_fillfunction this introduces is added as an inline helper indram.h, so that it can be shared with the sun8i dram code.While at it move
mctl_mem_matchestodram.hfor re-use in sun8i too.Signed-off-by Hans de Goede <[email protected]>--- 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@@ -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@@ -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
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
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
PATCH 11/14 sunxi: Fill memory before comparing it when doing dram init on sun6i
In reply to Ian CampbellHi,
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_fillfunction this introduces is added as an inline helper indram.h, so that it can be shared with the sun8i dram code.While at it move
mctl_mem_matchestodram.hfor re-use in sun8i too.Signed-off-by Hans de Goede <[email protected]>--- 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@@ -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@@ -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 */
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.
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
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.
PATCH 11/14 sunxi: Fill memory before comparing it when doing dram init on sun6i
In reply to Ian CampbellHi,
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
PATCH 12/14 sunxi: Use memcmp for mctl_mem_matches
In reply to Hans de GoedeUse 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
@@ -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
PATCH 12/14 sunxi: Use memcmp for mctl_mem_matches
Quoted 3 lines · Hans de Goede
Use memcmp for
mctl_mem_matchesinstead of DIY.Signed-off-by Hans de Goede <[email protected]>
Ian.
PATCH 13/14 sun8i: Add dram initialization support
In reply to Hans de GoedeBased 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
@@ -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
@@ -114,7 +114,8 @@ void reset_cpu(ulong addr)/* do some early init */ void s_init (void ) { -#if definedCONFIG_SPL_BUILD && definedCONFIG_MACH_SUN6I +#if definedCONFIG_SPL_BUILD && \ + (definedCONFIG_MACH_SUN6I || definedCONFIG_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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -12,6 +12,8 @@/* * A23 specific configuration */ +#define CONFIG_CLK_FULL_SPEED 1008000000 +#define CONFIG_SYS_PROMPT "sun8i# "/*
Signature · 1 line
2.1.0
PATCH 13/14 sun8i: Add dram initialization support
Quoted 747 lines · Hans de Goede
Based on the register /
dram_paraheaders from the Allwinner u-boot / linux sources + the init sequences from boot0.Signed-off-by Hans de Goede <[email protected]>--- 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.harch/arm/cpu/armv7/sunxi/Makefile +1
-0@@ -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 endifarch/arm/cpu/armv7/sunxi/board.c +2
-1@@ -114,7 +114,8 @@ void reset_cpu(ulong addr)/* do some early init */ void s_init (void ) { -#if definedCONFIG_SPL_BUILD && definedCONFIG_MACH_SUN6I +#if definedCONFIG_SPL_BUILD && \ + (definedCONFIG_MACH_SUN6I || definedCONFIG_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@@ -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@@ -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 0xd1303333arch/arm/include/asm/arch-sunxi/dram.h +2
-0@@ -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@@ -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@@ -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@@ -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=3000include/configs/sun8i.h +2
-1@@ -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
PATCH 13/14 sun8i: Add dram initialization support
In reply to Hans de GoedeQuoted 10 lines · Hans de Goede
Based on the register /
dram_paraheaders from the Allwinner u-boot / linux sources + the init sequences from boot0.Signed-off-by Hans de Goede <[email protected]>+/*
+ * 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@@ -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.
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_paraheaders from the Allwinner u-boot / linux sources + the init sequences from boot0.Signed-off-by Hans de Goede <[email protected]>+/*
+ * 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@@ -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=yNot replaced with a S: variant? I know you want
CONFIG_TARGETto 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_TREEtoCONFIG_FDTFILEconversion 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
PATCH 13/14 sun8i: Add dram initialization support
In reply to Hans de GoedeQuoted 2 lines · On Tue, 16 Dec 2014 21:31:38 +0100 Hans de Goede <[email protected]> wrote:
Based on the register /
dram_paraheaders 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
Signed-off-by Hans de Goede <[email protected]>--- 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.harch/arm/cpu/armv7/sunxi/Makefile +1
-0@@ -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 endifarch/arm/cpu/armv7/sunxi/board.c +2
-1@@ -114,7 +114,8 @@ void reset_cpu(ulong addr)/* do some early init */ void s_init (void ) { -#if definedCONFIG_SPL_BUILD && definedCONFIG_MACH_SUN6I +#if definedCONFIG_SPL_BUILD && \ + (definedCONFIG_MACH_SUN6I || definedCONFIG_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
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@@ -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 0xd1303333arch/arm/include/asm/arch-sunxi/dram.h +2
-0@@ -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@@ -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@@ -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@@ -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=3000include/configs/sun8i.h +2
-0@@ -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
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_paraheaders 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
Signed-off-by Hans de Goede <[email protected]>--- 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.ccreate mode 100644arch/arm/include/asm/arch-sunxi/dram_sun8i.harch/arm/cpu/armv7/sunxi/Makefile +1
-0@@ -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 endifarch/arm/cpu/armv7/sunxi/board.c +2
-1@@ -114,7 +114,8 @@ void reset_cpu(ulong addr)/* do some early init */ void s_init (void ) { -#if definedCONFIG_SPL_BUILD && definedCONFIG_MACH_SUN6I +#if definedCONFIG_SPL_BUILD && \ + (definedCONFIG_MACH_SUN6I || definedCONFIG_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
-0arch/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
0x40bis 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
0x7Barch/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 - ZCALarch/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@@ -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 0xd1303333arch/arm/include/asm/arch-sunxi/dram.h +2
-0@@ -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@@ -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@@ -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@@ -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=3000include/configs/sun8i.h +2
-0@@ -12,6 +12,8 @@/* * A23 specific configuration */ +#define CONFIG_CLK_FULL_SPEED 1008000000 +#define CONFIG_SYS_PROMPT "sun8i# "/*
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_paraheaders 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.carch/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
PATCH 14/14 sun8i: Add defconfig for Ippo_q8h v1.2
In reply to Hans de GoedeWe 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
@@ -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
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.
Signed-off-by Hans de Goede <[email protected]>
(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
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.
PATCH 1/14 sun6i: s/SUNXI_GPL0_R_P2WI/SUN6I_GPL0_R_P2WI/
In reply to Hans de GoedeQuoted 4 lines · Hans de Goede
The p2wi interface is only available on sun6i, adjust the gpio pinmux defines for it to reflect this.
Signed-off-by Hans de Goede <[email protected]>