summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/cpu/armv8/cache_v8.c30
-rw-r--r--arch/arm/dts/Makefile1
-rw-r--r--arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h2
-rw-r--r--arch/arm/include/asm/arch-sunxi/mmc.h139
-rw-r--r--arch/arm/include/asm/armv8/mmu.h20
-rw-r--r--arch/arm/include/asm/global_data.h2
-rw-r--r--arch/arm/mach-imx/spl_imx_romapi.c6
-rw-r--r--arch/arm/mach-sunxi/Kconfig17
-rw-r--r--arch/arm/mach-sunxi/dram_sun50i_h616.c294
-rw-r--r--arch/arm/mach-sunxi/dram_timings/Makefile1
-rw-r--r--arch/arm/mach-sunxi/dram_timings/h616_lpddr4_2133.c95
-rw-r--r--arch/arm/mach-sunxi/pmic_bus.c3
12 files changed, 339 insertions, 271 deletions
diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c
index cb1131a0480..697334086fd 100644
--- a/arch/arm/cpu/armv8/cache_v8.c
+++ b/arch/arm/cpu/armv8/cache_v8.c
@@ -93,16 +93,10 @@ u64 get_tcr(u64 *pips, u64 *pva_bits)
if (el == 1) {
tcr = TCR_EL1_RSVD | (ips << 32) | TCR_EPD1_DISABLE;
- if (gd->arch.has_hafdbs)
- tcr |= TCR_EL1_HA | TCR_EL1_HD;
} else if (el == 2) {
tcr = TCR_EL2_RSVD | (ips << 16);
- if (gd->arch.has_hafdbs)
- tcr |= TCR_EL2_HA | TCR_EL2_HD;
} else {
tcr = TCR_EL3_RSVD | (ips << 16);
- if (gd->arch.has_hafdbs)
- tcr |= TCR_EL3_HA | TCR_EL3_HD;
}
/* PTWs cacheable, inner/outer WBWA and inner shareable */
@@ -206,9 +200,6 @@ static void __cmo_on_leaves(void (*cmo_fn)(unsigned long, unsigned long),
attrs != PTE_BLOCK_MEMTYPE(MT_NORMAL_NC))
continue;
- if (gd->arch.has_hafdbs && (pte & (PTE_RDONLY | PTE_DBM)) != PTE_DBM)
- continue;
-
end = va + BIT(level2shift(level)) - 1;
/* No intersection with RAM? */
@@ -318,7 +309,7 @@ static void map_range(u64 virt, u64 phys, u64 size, int level,
for (i = idx; size; i++) {
u64 next_size, *next_table;
- if (level >= gd->arch.first_block_level &&
+ if (level >= 1 &&
size >= map_size && !(virt & (map_size - 1))) {
if (level == 3)
table[i] = phys | attrs | PTE_TYPE_PAGE;
@@ -357,12 +348,6 @@ static void add_map(struct mm_region *map)
if (va_bits < 39)
level = 1;
- if (!gd->arch.first_block_level)
- gd->arch.first_block_level = 1;
-
- if (gd->arch.has_hafdbs)
- attrs |= PTE_DBM | PTE_RDONLY;
-
map_range(map->virt, map->phys, map->size, level,
(u64 *)gd->arch.tlb_addr, attrs);
}
@@ -376,7 +361,7 @@ static void count_range(u64 virt, u64 size, int level, int *cntp)
for (i = idx; size; i++) {
u64 next_size;
- if (level >= gd->arch.first_block_level &&
+ if (level >= 1 &&
size >= map_size && !(virt & (map_size - 1))) {
virt += map_size;
size -= map_size;
@@ -414,16 +399,7 @@ static int count_ranges(void)
__weak u64 get_page_table_size(void)
{
u64 one_pt = MAX_PTE_ENTRIES * sizeof(u64);
- u64 size, mmfr1;
-
- asm volatile("mrs %0, id_aa64mmfr1_el1" : "=r" (mmfr1));
- if ((mmfr1 & 0xf) == 2) {
- gd->arch.has_hafdbs = true;
- gd->arch.first_block_level = 2;
- } else {
- gd->arch.has_hafdbs = false;
- gd->arch.first_block_level = 1;
- }
+ u64 size;
/* Account for all page tables we would need to cover our memory map */
size = one_pt * count_ranges();
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 3200a5f01eb..1be08c5fdc2 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -721,6 +721,7 @@ dtb-$(CONFIG_MACH_SUN7I) += \
sun7i-a20-haoyu-marsboard.dtb \
sun7i-a20-hummingbird.dtb \
sun7i-a20-i12-tvbox.dtb \
+ sun7i-a20-icnova-a20-adb4006.dtb \
sun7i-a20-icnova-swac.dtb \
sun7i-a20-itead-ibox.dtb \
sun7i-a20-lamobo-r1.dtb \
diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h
index 11774deded0..a8fdda124a0 100644
--- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h
+++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h
@@ -130,6 +130,7 @@ check_member(sunxi_mctl_ctl_reg, unk_0x4240, 0x4240);
#define MSTR_DEVICETYPE_LPDDR2 BIT(2)
#define MSTR_DEVICETYPE_LPDDR3 BIT(3)
#define MSTR_DEVICETYPE_DDR4 BIT(4)
+#define MSTR_DEVICETYPE_LPDDR4 BIT(5)
#define MSTR_DEVICETYPE_MASK GENMASK(5, 0)
#define MSTR_2TMODE BIT(10)
#define MSTR_BUSWIDTH_FULL (0 << 12)
@@ -154,6 +155,7 @@ struct dram_para {
u32 odt_en;
u32 tpr0;
u32 tpr2;
+ u32 tpr6;
u32 tpr10;
u32 tpr11;
u32 tpr12;
diff --git a/arch/arm/include/asm/arch-sunxi/mmc.h b/arch/arm/include/asm/arch-sunxi/mmc.h
index 8ed3e0459c9..b8d91b5c64b 100644
--- a/arch/arm/include/asm/arch-sunxi/mmc.h
+++ b/arch/arm/include/asm/arch-sunxi/mmc.h
@@ -1,139 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * (C) Copyright 2007-2011
- * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
- * Aaron <leafy.myeh@allwinnertech.com>
- *
- * MMC register definition for allwinner sunxi platform.
- */
-#ifndef _SUNXI_MMC_H
-#define _SUNXI_MMC_H
-
-#include <linux/types.h>
-
-struct sunxi_mmc {
- u32 gctrl; /* 0x00 global control */
- u32 clkcr; /* 0x04 clock control */
- u32 timeout; /* 0x08 time out */
- u32 width; /* 0x0c bus width */
- u32 blksz; /* 0x10 block size */
- u32 bytecnt; /* 0x14 byte count */
- u32 cmd; /* 0x18 command */
- u32 arg; /* 0x1c argument */
- u32 resp0; /* 0x20 response 0 */
- u32 resp1; /* 0x24 response 1 */
- u32 resp2; /* 0x28 response 2 */
- u32 resp3; /* 0x2c response 3 */
- u32 imask; /* 0x30 interrupt mask */
- u32 mint; /* 0x34 masked interrupt status */
- u32 rint; /* 0x38 raw interrupt status */
- u32 status; /* 0x3c status */
- u32 ftrglevel; /* 0x40 FIFO threshold watermark*/
- u32 funcsel; /* 0x44 function select */
- u32 cbcr; /* 0x48 CIU byte count */
- u32 bbcr; /* 0x4c BIU byte count */
- u32 dbgc; /* 0x50 debug enable */
- u32 res0; /* 0x54 reserved */
- u32 a12a; /* 0x58 Auto command 12 argument */
- u32 ntsr; /* 0x5c New timing set register */
- u32 res1[8];
- u32 dmac; /* 0x80 internal DMA control */
- u32 dlba; /* 0x84 internal DMA descr list base address */
- u32 idst; /* 0x88 internal DMA status */
- u32 idie; /* 0x8c internal DMA interrupt enable */
- u32 chda; /* 0x90 */
- u32 cbda; /* 0x94 */
- u32 res2[26];
-#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2)
- u32 res3[17];
- u32 samp_dl;
- u32 res4[46];
-#endif
- u32 fifo; /* 0x100 / 0x200 FIFO access address */
-};
-
-#define SUNXI_MMC_CLK_POWERSAVE (0x1 << 17)
-#define SUNXI_MMC_CLK_ENABLE (0x1 << 16)
-#define SUNXI_MMC_CLK_DIVIDER_MASK (0xff)
-
-#define SUNXI_MMC_GCTRL_SOFT_RESET (0x1 << 0)
-#define SUNXI_MMC_GCTRL_FIFO_RESET (0x1 << 1)
-#define SUNXI_MMC_GCTRL_DMA_RESET (0x1 << 2)
-#define SUNXI_MMC_GCTRL_RESET (SUNXI_MMC_GCTRL_SOFT_RESET|\
- SUNXI_MMC_GCTRL_FIFO_RESET|\
- SUNXI_MMC_GCTRL_DMA_RESET)
-#define SUNXI_MMC_GCTRL_DMA_ENABLE (0x1 << 5)
-#define SUNXI_MMC_GCTRL_ACCESS_BY_AHB (0x1 << 31)
-
-#define SUNXI_MMC_CMD_RESP_EXPIRE (0x1 << 6)
-#define SUNXI_MMC_CMD_LONG_RESPONSE (0x1 << 7)
-#define SUNXI_MMC_CMD_CHK_RESPONSE_CRC (0x1 << 8)
-#define SUNXI_MMC_CMD_DATA_EXPIRE (0x1 << 9)
-#define SUNXI_MMC_CMD_WRITE (0x1 << 10)
-#define SUNXI_MMC_CMD_AUTO_STOP (0x1 << 12)
-#define SUNXI_MMC_CMD_WAIT_PRE_OVER (0x1 << 13)
-#define SUNXI_MMC_CMD_SEND_INIT_SEQ (0x1 << 15)
-#define SUNXI_MMC_CMD_UPCLK_ONLY (0x1 << 21)
-#define SUNXI_MMC_CMD_START (0x1 << 31)
-
-#define SUNXI_MMC_RINT_RESP_ERROR (0x1 << 1)
-#define SUNXI_MMC_RINT_COMMAND_DONE (0x1 << 2)
-#define SUNXI_MMC_RINT_DATA_OVER (0x1 << 3)
-#define SUNXI_MMC_RINT_TX_DATA_REQUEST (0x1 << 4)
-#define SUNXI_MMC_RINT_RX_DATA_REQUEST (0x1 << 5)
-#define SUNXI_MMC_RINT_RESP_CRC_ERROR (0x1 << 6)
-#define SUNXI_MMC_RINT_DATA_CRC_ERROR (0x1 << 7)
-#define SUNXI_MMC_RINT_RESP_TIMEOUT (0x1 << 8)
-#define SUNXI_MMC_RINT_DATA_TIMEOUT (0x1 << 9)
-#define SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE (0x1 << 10)
-#define SUNXI_MMC_RINT_FIFO_RUN_ERROR (0x1 << 11)
-#define SUNXI_MMC_RINT_HARD_WARE_LOCKED (0x1 << 12)
-#define SUNXI_MMC_RINT_START_BIT_ERROR (0x1 << 13)
-#define SUNXI_MMC_RINT_AUTO_COMMAND_DONE (0x1 << 14)
-#define SUNXI_MMC_RINT_END_BIT_ERROR (0x1 << 15)
-#define SUNXI_MMC_RINT_SDIO_INTERRUPT (0x1 << 16)
-#define SUNXI_MMC_RINT_CARD_INSERT (0x1 << 30)
-#define SUNXI_MMC_RINT_CARD_REMOVE (0x1 << 31)
-#define SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT \
- (SUNXI_MMC_RINT_RESP_ERROR | \
- SUNXI_MMC_RINT_RESP_CRC_ERROR | \
- SUNXI_MMC_RINT_DATA_CRC_ERROR | \
- SUNXI_MMC_RINT_RESP_TIMEOUT | \
- SUNXI_MMC_RINT_DATA_TIMEOUT | \
- SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE | \
- SUNXI_MMC_RINT_FIFO_RUN_ERROR | \
- SUNXI_MMC_RINT_HARD_WARE_LOCKED | \
- SUNXI_MMC_RINT_START_BIT_ERROR | \
- SUNXI_MMC_RINT_END_BIT_ERROR) /* 0xbfc2 */
-#define SUNXI_MMC_RINT_INTERRUPT_DONE_BIT \
- (SUNXI_MMC_RINT_AUTO_COMMAND_DONE | \
- SUNXI_MMC_RINT_DATA_OVER | \
- SUNXI_MMC_RINT_COMMAND_DONE | \
- SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE)
-
-#define SUNXI_MMC_STATUS_RXWL_FLAG (0x1 << 0)
-#define SUNXI_MMC_STATUS_TXWL_FLAG (0x1 << 1)
-#define SUNXI_MMC_STATUS_FIFO_EMPTY (0x1 << 2)
-#define SUNXI_MMC_STATUS_FIFO_FULL (0x1 << 3)
-#define SUNXI_MMC_STATUS_CARD_PRESENT (0x1 << 8)
-#define SUNXI_MMC_STATUS_CARD_DATA_BUSY (0x1 << 9)
-#define SUNXI_MMC_STATUS_DATA_FSM_BUSY (0x1 << 10)
-#define SUNXI_MMC_STATUS_FIFO_LEVEL(reg) (((reg) >> 17) & 0x3fff)
-
-#define SUNXI_MMC_NTSR_MODE_SEL_NEW (0x1 << 31)
-
-#define SUNXI_MMC_IDMAC_RESET (0x1 << 0)
-#define SUNXI_MMC_IDMAC_FIXBURST (0x1 << 1)
-#define SUNXI_MMC_IDMAC_ENABLE (0x1 << 7)
-
-#define SUNXI_MMC_IDIE_TXIRQ (0x1 << 0)
-#define SUNXI_MMC_IDIE_RXIRQ (0x1 << 1)
-
-#define SUNXI_MMC_COMMON_CLK_GATE (1 << 16)
-#define SUNXI_MMC_COMMON_RESET (1 << 18)
-
-#define SUNXI_MMC_CAL_DL_SW_EN (0x1 << 7)
+#ifndef _ASM_ARCH_MMC_H_
+#define _ASM_ARCH_MMC_H_
struct mmc *sunxi_mmc_init(int sdc_no);
-#endif /* _SUNXI_MMC_H */
+
+#endif /* _ASM_ARCH_MMC_H_ */
diff --git a/arch/arm/include/asm/armv8/mmu.h b/arch/arm/include/asm/armv8/mmu.h
index 4f0adb07325..ce655ce7a95 100644
--- a/arch/arm/include/asm/armv8/mmu.h
+++ b/arch/arm/include/asm/armv8/mmu.h
@@ -49,13 +49,10 @@
#define PTE_TYPE_BLOCK (1 << 0)
#define PTE_TYPE_VALID (1 << 0)
-#define PTE_RDONLY BIT(7)
-#define PTE_DBM BIT(51)
-
-#define PTE_TABLE_PXN BIT(59)
-#define PTE_TABLE_XN BIT(60)
-#define PTE_TABLE_AP BIT(61)
-#define PTE_TABLE_NS BIT(63)
+#define PTE_TABLE_PXN (1UL << 59)
+#define PTE_TABLE_XN (1UL << 60)
+#define PTE_TABLE_AP (1UL << 61)
+#define PTE_TABLE_NS (1UL << 63)
/*
* Block
@@ -102,15 +99,6 @@
#define TCR_TG0_16K (2 << 14)
#define TCR_EPD1_DISABLE (1 << 23)
-#define TCR_EL1_HA BIT(39)
-#define TCR_EL1_HD BIT(40)
-
-#define TCR_EL2_HA BIT(21)
-#define TCR_EL2_HD BIT(22)
-
-#define TCR_EL3_HA BIT(21)
-#define TCR_EL3_HD BIT(22)
-
#define TCR_EL1_RSVD (1U << 31)
#define TCR_EL2_RSVD (1U << 31 | 1 << 23)
#define TCR_EL3_RSVD (1U << 31 | 1 << 23)
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index b385bae0266..75bd9d56f89 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -52,8 +52,6 @@ struct arch_global_data {
#if defined(CONFIG_ARM64)
unsigned long tlb_fillptr;
unsigned long tlb_emerg;
- unsigned int first_block_level;
- bool has_hafdbs;
#endif
#endif
#ifdef CFG_SYS_MEM_RESERVE_SECURE
diff --git a/arch/arm/mach-imx/spl_imx_romapi.c b/arch/arm/mach-imx/spl_imx_romapi.c
index 93d48e56aca..5eb5a3d3c4a 100644
--- a/arch/arm/mach-imx/spl_imx_romapi.c
+++ b/arch/arm/mach-imx/spl_imx_romapi.c
@@ -162,7 +162,7 @@ static ulong spl_romapi_read_stream(struct spl_load_info *load, ulong sector,
return 0;
}
- ss->end = end;
+ ss->end += bytes;
}
memcpy(buf, (void *)(sector), count);
@@ -285,7 +285,7 @@ static int spl_romapi_load_image_stream(struct spl_image_info *spl_image,
ret = rom_api_download_image(p, 0, pg);
if (ret != ROM_API_OKAY) {
- puts("Steam(USB) download failure\n");
+ puts("Stream(USB) download failure\n");
return -1;
}
@@ -305,7 +305,7 @@ static int spl_romapi_load_image_stream(struct spl_image_info *spl_image,
ret = rom_api_download_image(p, 0, pg);
if (ret != ROM_API_OKAY) {
- puts("Steam(USB) download failure\n");
+ puts("Stream(USB) download failure\n");
return -1;
}
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index a10e4c06b6a..a4a8d8e9445 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -85,6 +85,12 @@ config DRAM_SUN50I_H616_TPR2
help
TPR2 value from vendor DRAM settings.
+config DRAM_SUN50I_H616_TPR6
+ hex "H616 DRAM TPR6 parameter"
+ default 0x3300c080
+ help
+ TPR6 value from vendor DRAM settings.
+
config DRAM_SUN50I_H616_TPR10
hex "H616 DRAM TPR10 parameter"
help
@@ -462,6 +468,9 @@ config SUNXI_DRAM_DDR2
config SUNXI_DRAM_LPDDR3
bool
+config SUNXI_DRAM_LPDDR4
+ bool
+
choice
prompt "DRAM Type and Timing"
default SUNXI_DRAM_DDR3_1333 if !MACH_SUN8I_V3S
@@ -505,6 +514,14 @@ config SUNXI_DRAM_H616_LPDDR3
This option is the LPDDR3 timing used by the stock boot0 by
Allwinner.
+config SUNXI_DRAM_H616_LPDDR4
+ bool "LPDDR4 DRAM chips on the H616 DRAM controller"
+ select SUNXI_DRAM_LPDDR4
+ depends on DRAM_SUN50I_H616
+ help
+ This option is the LPDDR4 timing used by the stock boot0 by
+ Allwinner.
+
config SUNXI_DRAM_H616_DDR3_1333
bool "DDR3-1333 boot0 timings on the H616 DRAM controller"
select SUNXI_DRAM_DDR3
diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c
index 7e580b62dca..c5c1331a4c3 100644
--- a/arch/arm/mach-sunxi/dram_sun50i_h616.c
+++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c
@@ -6,8 +6,8 @@
* unknown. That's why this driver has plenty of magic numbers. Some
* meaning was nevertheless deduced from strings found in boot0 and
* known meaning of some dram parameters.
- * This driver only supports DDR3 memory and omits logic for all
- * other supported types supported by hardware.
+ * This driver supports DDR3, LPDDR3 and LPDDR4 memory. There is no
+ * DDR4 support yet.
*
* (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
*
@@ -238,64 +238,59 @@ static const u8 phy_init[] = {
0x08, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x07,
0x17, 0x19, 0x1a
+#elif defined(CONFIG_SUNXI_DRAM_H616_LPDDR4)
+ 0x02, 0x00, 0x17, 0x05, 0x04, 0x19, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x01,
+ 0x18, 0x03, 0x1a
#endif
};
+#define MASK_BYTE(reg, nr) (((reg) >> ((nr) * 8)) & 0x1f)
static void mctl_phy_configure_odt(const struct dram_para *para)
{
- unsigned int val;
+ uint32_t val_lo, val_hi;
- val = para->dx_dri & 0x1f;
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x388);
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x38c);
-
- val = (para->dx_dri >> 8) & 0x1f;
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x3c8);
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x3cc);
-
- val = (para->dx_dri >> 16) & 0x1f;
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x408);
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x40c);
-
- val = (para->dx_dri >> 24) & 0x1f;
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x448);
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x44c);
-
- val = para->ca_dri & 0x1f;
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x340);
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x344);
-
- val = (para->ca_dri >> 8) & 0x1f;
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x348);
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x34c);
-
- val = para->dx_odt & 0x1f;
- if (para->type == SUNXI_DRAM_TYPE_LPDDR3)
- writel_relaxed(0, SUNXI_DRAM_PHY0_BASE + 0x380);
- else
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x380);
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x384);
-
- val = (para->dx_odt >> 8) & 0x1f;
- if (para->type == SUNXI_DRAM_TYPE_LPDDR3)
- writel_relaxed(0, SUNXI_DRAM_PHY0_BASE + 0x3c0);
- else
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x3c0);
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x3c4);
-
- val = (para->dx_odt >> 16) & 0x1f;
- if (para->type == SUNXI_DRAM_TYPE_LPDDR3)
- writel_relaxed(0, SUNXI_DRAM_PHY0_BASE + 0x400);
- else
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x400);
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x404);
+ /*
+ * This part should be applicable to all memory types, but is
+ * usually found in LPDDR4 bootloaders. Therefore, we will leave
+ * only for this type of memory.
+ */
+ if (para->type == SUNXI_DRAM_TYPE_LPDDR4) {
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x390, BIT(5), BIT(4));
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x3d0, BIT(5), BIT(4));
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x410, BIT(5), BIT(4));
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x450, BIT(5), BIT(4));
+ }
- val = (para->dx_odt >> 24) & 0x1f;
- if (para->type == SUNXI_DRAM_TYPE_LPDDR3)
- writel_relaxed(0, SUNXI_DRAM_PHY0_BASE + 0x440);
- else
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x440);
- writel_relaxed(val, SUNXI_DRAM_PHY0_BASE + 0x444);
+ val_lo = para->dx_dri;
+ val_hi = (para->type == SUNXI_DRAM_TYPE_LPDDR4) ? 0x04040404 : para->dx_dri;
+ writel_relaxed(MASK_BYTE(val_lo, 0), SUNXI_DRAM_PHY0_BASE + 0x388);
+ writel_relaxed(MASK_BYTE(val_hi, 0), SUNXI_DRAM_PHY0_BASE + 0x38c);
+ writel_relaxed(MASK_BYTE(val_lo, 1), SUNXI_DRAM_PHY0_BASE + 0x3c8);
+ writel_relaxed(MASK_BYTE(val_hi, 1), SUNXI_DRAM_PHY0_BASE + 0x3cc);
+ writel_relaxed(MASK_BYTE(val_lo, 2), SUNXI_DRAM_PHY0_BASE + 0x408);
+ writel_relaxed(MASK_BYTE(val_hi, 2), SUNXI_DRAM_PHY0_BASE + 0x40c);
+ writel_relaxed(MASK_BYTE(val_lo, 3), SUNXI_DRAM_PHY0_BASE + 0x448);
+ writel_relaxed(MASK_BYTE(val_hi, 3), SUNXI_DRAM_PHY0_BASE + 0x44c);
+
+ val_lo = para->ca_dri;
+ val_hi = para->ca_dri;
+ writel_relaxed(MASK_BYTE(val_lo, 0), SUNXI_DRAM_PHY0_BASE + 0x340);
+ writel_relaxed(MASK_BYTE(val_hi, 0), SUNXI_DRAM_PHY0_BASE + 0x344);
+ writel_relaxed(MASK_BYTE(val_lo, 1), SUNXI_DRAM_PHY0_BASE + 0x348);
+ writel_relaxed(MASK_BYTE(val_hi, 1), SUNXI_DRAM_PHY0_BASE + 0x34c);
+
+ val_lo = (para->type == SUNXI_DRAM_TYPE_LPDDR3) ? 0 : para->dx_odt;
+ val_hi = (para->type == SUNXI_DRAM_TYPE_LPDDR4) ? 0 : para->dx_odt;
+ writel_relaxed(MASK_BYTE(val_lo, 0), SUNXI_DRAM_PHY0_BASE + 0x380);
+ writel_relaxed(MASK_BYTE(val_hi, 0), SUNXI_DRAM_PHY0_BASE + 0x384);
+ writel_relaxed(MASK_BYTE(val_lo, 1), SUNXI_DRAM_PHY0_BASE + 0x3c0);
+ writel_relaxed(MASK_BYTE(val_hi, 1), SUNXI_DRAM_PHY0_BASE + 0x3c4);
+ writel_relaxed(MASK_BYTE(val_lo, 2), SUNXI_DRAM_PHY0_BASE + 0x400);
+ writel_relaxed(MASK_BYTE(val_hi, 2), SUNXI_DRAM_PHY0_BASE + 0x404);
+ writel_relaxed(MASK_BYTE(val_lo, 3), SUNXI_DRAM_PHY0_BASE + 0x440);
+ writel_relaxed(MASK_BYTE(val_hi, 3), SUNXI_DRAM_PHY0_BASE + 0x444);
dmb();
}
@@ -414,12 +409,18 @@ static bool mctl_phy_read_calibration(const struct dram_config *config)
return result;
}
-static bool mctl_phy_read_training(const struct dram_config *config)
+static bool mctl_phy_read_training(const struct dram_para *para,
+ const struct dram_config *config)
{
u32 val1, val2, *ptr1, *ptr2;
bool result = true;
int i;
+ if (para->type == SUNXI_DRAM_TYPE_LPDDR4) {
+ writel(0, SUNXI_DRAM_PHY0_BASE + 0x800);
+ writel(0, SUNXI_DRAM_PHY0_BASE + 0x81c);
+ }
+
clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 3, 2);
clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x804, 0x3f, 0xf);
clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x808, 0x3f, 0xf);
@@ -600,6 +601,8 @@ static void mctl_phy_bit_delay_compensation(const struct dram_para *para)
clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x60, 1);
setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 8);
clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10);
+ if (para->type == SUNXI_DRAM_TYPE_LPDDR4)
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x4, 0x80);
if (para->tpr10 & BIT(30))
val = para->tpr11 & 0x3f;
@@ -813,8 +816,9 @@ static void mctl_phy_ca_bit_delay_compensation(const struct dram_para *para,
writel(val, SUNXI_DRAM_PHY0_BASE + 0x7e0);
writel(val, SUNXI_DRAM_PHY0_BASE + 0x7f4);
- if (para->type == SUNXI_DRAM_TYPE_DDR3) {
- val = (para->tpr10 >> 7) & 0x1e;
+ val = (para->tpr10 >> 7) & 0x1e;
+ switch (para->type) {
+ case SUNXI_DRAM_TYPE_DDR3:
if (para->tpr2 & 1) {
writel(val, SUNXI_DRAM_PHY0_BASE + 0x794);
if (config->ranks == 2) {
@@ -840,8 +844,8 @@ static void mctl_phy_ca_bit_delay_compensation(const struct dram_para *para,
writel(val, SUNXI_DRAM_PHY0_BASE + 0x7b8);
}
}
- } else if (para->type == SUNXI_DRAM_TYPE_LPDDR3) {
- val = (para->tpr10 >> 7) & 0x1e;
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR3:
if (para->tpr2 & 1) {
writel(val, SUNXI_DRAM_PHY0_BASE + 0x7a0);
if (config->ranks == 2) {
@@ -855,7 +859,18 @@ static void mctl_phy_ca_bit_delay_compensation(const struct dram_para *para,
writel(val, SUNXI_DRAM_PHY0_BASE + 0x7f8);
}
}
- }
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR4:
+ if (para->tpr2 & 1) {
+ writel(val, SUNXI_DRAM_PHY0_BASE + 0x788);
+ } else {
+ writel(val, SUNXI_DRAM_PHY0_BASE + 0x794);
+ };
+ break;
+ case SUNXI_DRAM_TYPE_DDR4:
+ default:
+ panic("This DRAM setup is currently not supported.\n");
+ };
}
static bool mctl_phy_init(const struct dram_para *para,
@@ -868,30 +883,42 @@ static bool mctl_phy_init(const struct dram_para *para,
u32 val, val2, *ptr, mr0, mr2;
int i;
+ if (para->type == SUNXI_DRAM_TYPE_LPDDR4)
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x4,0x80);
+
if (config->bus_full_width)
val = 0xf;
else
val = 3;
clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x3c, 0xf, val);
- if (para->tpr2 & 0x100) {
- if (para->type == SUNXI_DRAM_TYPE_DDR3) {
+ switch (para->type) {
+ case SUNXI_DRAM_TYPE_DDR3:
+ if (para->tpr2 & 0x100) {
val = 9;
val2 = 7;
- } else if (para->type == SUNXI_DRAM_TYPE_LPDDR3) {
- // untested setup: use some values for now
- val = 14;
- val2 = 8;
- }
- } else {
- if (para->type == SUNXI_DRAM_TYPE_DDR3) {
+ } else {
val = 13;
val2 = 9;
- } else if (para->type == SUNXI_DRAM_TYPE_LPDDR3) {
+ }
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR3:
+ if (para->tpr2 & 0x100) {
+ val = 12;
+ val2 = 6;
+ } else {
val = 14;
val2 = 8;
}
- }
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR4:
+ val = 20;
+ val2 = 10;
+ break;
+ case SUNXI_DRAM_TYPE_DDR4:
+ default:
+ panic("This DRAM setup is currently not supported.\n");
+ };
writel(val, SUNXI_DRAM_PHY0_BASE + 0x14);
writel(val, SUNXI_DRAM_PHY0_BASE + 0x35c);
@@ -915,19 +942,40 @@ static bool mctl_phy_init(const struct dram_para *para,
if (para->tpr10 & TPR10_CA_BIT_DELAY)
mctl_phy_ca_bit_delay_compensation(para, config);
- if (para->type == SUNXI_DRAM_TYPE_DDR3)
- val = 0x80;
- else if (para->type == SUNXI_DRAM_TYPE_LPDDR3)
- val = 0xc0;
+ switch (para->type) {
+ case SUNXI_DRAM_TYPE_DDR3:
+ val = para->tpr6 & 0xff;
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR3:
+ val = para->tpr6 >> 8 & 0xff;
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR4:
+ val = para->tpr6 >> 24 & 0xff;
+ break;
+ case SUNXI_DRAM_TYPE_DDR4:
+ default:
+ panic("This DRAM setup is currently not supported.\n");
+ };
+
writel(val, SUNXI_DRAM_PHY0_BASE + 0x3dc);
writel(val, SUNXI_DRAM_PHY0_BASE + 0x45c);
mctl_phy_configure_odt(para);
- if (para->type == SUNXI_DRAM_TYPE_DDR3)
+ switch (para->type) {
+ case SUNXI_DRAM_TYPE_DDR3:
val = 0x0a;
- else if (para->type == SUNXI_DRAM_TYPE_LPDDR3)
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR3:
val = 0x0b;
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR4:
+ val = 0x0d;
+ break;
+ case SUNXI_DRAM_TYPE_DDR4:
+ default:
+ panic("This DRAM setup is currently not supported.\n");
+ };
clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 0x7, val);
if (para->clk <= 672)
@@ -977,8 +1025,8 @@ static bool mctl_phy_init(const struct dram_para *para,
mr0 = 0x1f14;
mr2 = 0x20;
}
-
- if (para->type == SUNXI_DRAM_TYPE_DDR3) {
+ switch (para->type) {
+ case SUNXI_DRAM_TYPE_DDR3:
writel(mr0, &mctl_ctl->mrctrl1);
writel(0x80000030, &mctl_ctl->mrctrl0);
mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
@@ -994,7 +1042,8 @@ static bool mctl_phy_init(const struct dram_para *para,
writel(0, &mctl_ctl->mrctrl1);
writel(0x80003030, &mctl_ctl->mrctrl0);
mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
- } else if (para->type == SUNXI_DRAM_TYPE_LPDDR3) {
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR3:
writel(mr0, &mctl_ctl->mrctrl1);
writel(0x800000f0, &mctl_ctl->mrctrl0);
mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
@@ -1010,7 +1059,48 @@ static bool mctl_phy_init(const struct dram_para *para,
writel(0x301, &mctl_ctl->mrctrl1);
writel(0x800000f0, &mctl_ctl->mrctrl0);
mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
- }
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR4:
+ writel(0x0, &mctl_ctl->mrctrl1);
+ writel(0x80000030, &mctl_ctl->mrctrl0);
+ mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
+
+ writel(0x134, &mctl_ctl->mrctrl1);
+ writel(0x80000030, &mctl_ctl->mrctrl0);
+ mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
+
+ writel(0x21b, &mctl_ctl->mrctrl1);
+ writel(0x80000030, &mctl_ctl->mrctrl0);
+ mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
+
+ writel(0x333, &mctl_ctl->mrctrl1);
+ writel(0x80000030, &mctl_ctl->mrctrl0);
+ mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
+
+ writel(0x403, &mctl_ctl->mrctrl1);
+ writel(0x80000030, &mctl_ctl->mrctrl0);
+ mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
+
+ writel(0xb04, &mctl_ctl->mrctrl1);
+ writel(0x80000030, &mctl_ctl->mrctrl0);
+ mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
+
+ writel(0xc72, &mctl_ctl->mrctrl1);
+ writel(0x80000030, &mctl_ctl->mrctrl0);
+ mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
+
+ writel(0xe09, &mctl_ctl->mrctrl1);
+ writel(0x80000030, &mctl_ctl->mrctrl0);
+ mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
+
+ writel(0x1624, &mctl_ctl->mrctrl1);
+ writel(0x80000030, &mctl_ctl->mrctrl0);
+ mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
+ break;
+ case SUNXI_DRAM_TYPE_DDR4:
+ default:
+ panic("This DRAM setup is currently not supported.\n");
+ };
writel(0, SUNXI_DRAM_PHY0_BASE + 0x54);
@@ -1040,7 +1130,7 @@ static bool mctl_phy_init(const struct dram_para *para,
if (para->tpr10 & TPR10_READ_TRAINING) {
for (i = 0; i < 5; i++)
- if (mctl_phy_read_training(config))
+ if (mctl_phy_read_training(para, config))
break;
if (i == 5) {
debug("read training failed!\n");
@@ -1079,17 +1169,29 @@ static bool mctl_ctrl_init(const struct dram_para *para,
setbits_le32(&mctl_com->unk_0x008, 0xff00);
+ if (para->type == SUNXI_DRAM_TYPE_LPDDR4)
+ writel(1, SUNXI_DRAM_COM_BASE + 0x50);
clrsetbits_le32(&mctl_ctl->sched[0], 0xff00, 0x3000);
writel(0, &mctl_ctl->hwlpctl);
setbits_le32(&mctl_com->unk_0x008, 0xff00);
- reg_val = MSTR_BURST_LENGTH(8) | MSTR_ACTIVE_RANKS(config->ranks);
- if (para->type == SUNXI_DRAM_TYPE_DDR3)
- reg_val |= MSTR_DEVICETYPE_DDR3 | MSTR_2TMODE;
- else if (para->type == SUNXI_DRAM_TYPE_LPDDR3)
- reg_val |= MSTR_DEVICETYPE_LPDDR3;
+ reg_val = MSTR_ACTIVE_RANKS(config->ranks);
+ switch (para->type) {
+ case SUNXI_DRAM_TYPE_DDR3:
+ reg_val |= MSTR_BURST_LENGTH(8) | MSTR_DEVICETYPE_DDR3 | MSTR_2TMODE;
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR3:
+ reg_val |= MSTR_BURST_LENGTH(8) | MSTR_DEVICETYPE_LPDDR3;
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR4:
+ reg_val |= MSTR_BURST_LENGTH(16) | MSTR_DEVICETYPE_LPDDR4;
+ break;
+ case SUNXI_DRAM_TYPE_DDR4:
+ default:
+ panic("This DRAM setup is currently not supported.\n");
+ };
if (config->bus_full_width)
reg_val |= MSTR_BUSWIDTH_FULL;
else
@@ -1101,10 +1203,20 @@ static bool mctl_ctrl_init(const struct dram_para *para,
else
writel(0x0201, &mctl_ctl->odtmap);
- if (para->type == SUNXI_DRAM_TYPE_DDR3)
+ switch (para->type) {
+ case SUNXI_DRAM_TYPE_DDR3:
reg_val = 0x06000400;
- else if (para->type == SUNXI_DRAM_TYPE_LPDDR3)
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR3:
reg_val = 0x09020400;
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR4:
+ reg_val = 0x04000400;
+ break;
+ case SUNXI_DRAM_TYPE_DDR4:
+ default:
+ panic("This DRAM setup is currently not supported.\n");
+ };
writel(reg_val, &mctl_ctl->odtcfg);
writel(reg_val, &mctl_ctl->unk_0x2240);
writel(reg_val, &mctl_ctl->unk_0x3240);
@@ -1124,6 +1236,9 @@ static bool mctl_ctrl_init(const struct dram_para *para,
setbits_le32(&mctl_ctl->unk_0x3180, BIT(31) | BIT(30));
setbits_le32(&mctl_ctl->unk_0x4180, BIT(31) | BIT(30));
+ if (para->type == SUNXI_DRAM_TYPE_LPDDR4)
+ setbits_le32(&mctl_ctl->dbictl, 0x1);
+
setbits_le32(&mctl_ctl->rfshctl3, BIT(0));
clrbits_le32(&mctl_ctl->dfimisc, BIT(0));
@@ -1246,6 +1361,8 @@ static const struct dram_para para = {
.type = SUNXI_DRAM_TYPE_DDR3,
#elif defined(CONFIG_SUNXI_DRAM_H616_LPDDR3)
.type = SUNXI_DRAM_TYPE_LPDDR3,
+#elif defined(CONFIG_SUNXI_DRAM_H616_LPDDR4)
+ .type = SUNXI_DRAM_TYPE_LPDDR4,
#endif
.dx_odt = CONFIG_DRAM_SUN50I_H616_DX_ODT,
.dx_dri = CONFIG_DRAM_SUN50I_H616_DX_DRI,
@@ -1253,6 +1370,7 @@ static const struct dram_para para = {
.odt_en = CONFIG_DRAM_SUN50I_H616_ODT_EN,
.tpr0 = CONFIG_DRAM_SUN50I_H616_TPR0,
.tpr2 = CONFIG_DRAM_SUN50I_H616_TPR2,
+ .tpr6 = CONFIG_DRAM_SUN50I_H616_TPR6,
.tpr10 = CONFIG_DRAM_SUN50I_H616_TPR10,
.tpr11 = CONFIG_DRAM_SUN50I_H616_TPR11,
.tpr12 = CONFIG_DRAM_SUN50I_H616_TPR12,
diff --git a/arch/arm/mach-sunxi/dram_timings/Makefile b/arch/arm/mach-sunxi/dram_timings/Makefile
index 8bfd99448a8..5f203419240 100644
--- a/arch/arm/mach-sunxi/dram_timings/Makefile
+++ b/arch/arm/mach-sunxi/dram_timings/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_SUNXI_DRAM_H6_LPDDR3) += h6_lpddr3.o
obj-$(CONFIG_SUNXI_DRAM_H6_DDR3_1333) += h6_ddr3_1333.o
obj-$(CONFIG_SUNXI_DRAM_H616_DDR3_1333) += h616_ddr3_1333.o
obj-$(CONFIG_SUNXI_DRAM_H616_LPDDR3) += h616_lpddr3.o
+obj-$(CONFIG_SUNXI_DRAM_H616_LPDDR4) += h616_lpddr4_2133.o
diff --git a/arch/arm/mach-sunxi/dram_timings/h616_lpddr4_2133.c b/arch/arm/mach-sunxi/dram_timings/h616_lpddr4_2133.c
new file mode 100644
index 00000000000..c11cb8678f6
--- /dev/null
+++ b/arch/arm/mach-sunxi/dram_timings/h616_lpddr4_2133.c
@@ -0,0 +1,95 @@
+/*
+ * sun50i H616 LPDDR4-2133 timings, as programmed by Allwinner's boot0
+ * for orangepi zero3 with the H618 and LPDDR4 memory.
+ *
+ * (C) Copyright 2023 Mikhail Kalashnikov <iuncuim@gmail.com>
+ * Based on H6 DDR3 timings:
+ * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/dram.h>
+#include <asm/arch/cpu.h>
+
+void mctl_set_timing_params(const struct dram_para *para)
+{
+ struct sunxi_mctl_ctl_reg * const mctl_ctl =
+ (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+
+ u8 tccd = 4;
+ u8 tfaw = ns_to_t(40);
+ u8 trrd = max(ns_to_t(10), 2);
+ u8 trcd = max(ns_to_t(18), 2);
+ u8 trc = ns_to_t(65);
+ u8 txp = max(ns_to_t(8), 2);
+ u8 trtp = max(ns_to_t(8), 4);
+ u8 trp = ns_to_t(21);
+ u8 tras = ns_to_t(42);
+ u16 trefi = ns_to_t(3904) / 32;
+ u16 trfc = ns_to_t(280);
+ u16 txsr = ns_to_t(190);
+
+ u8 tmrw = max(ns_to_t(14), 5);
+ u8 tmrd = tmrw;
+ u8 tmod = 12;
+ u8 tcke = max(ns_to_t(15), 2);
+ u8 tcksrx = max(ns_to_t(2), 2);
+ u8 tcksre = max(ns_to_t(5), 2);
+ u8 tckesr = tcke;
+ u8 trasmax = (trefi * 9) / 32;
+ u8 txs = 4;
+ u8 txsdll = 16;
+ u8 txsabort = 4;
+ u8 txsfast = 4;
+ u8 tcl = 10;
+ u8 tcwl = 5;
+ u8 t_rdata_en = 17;
+ u8 tphy_wrlat = 5;
+
+ u8 twtp = 24;
+ u8 twr2rd = max(trrd, (u8)4) + 14;
+ u8 trd2wr = (ns_to_t(4) + 17) - ns_to_t(1);
+
+ /* set DRAM timing */
+ writel((twtp << 24) | (tfaw << 16) | (trasmax << 8) | tras,
+ &mctl_ctl->dramtmg[0]);
+ writel((txp << 16) | (trtp << 8) | trc, &mctl_ctl->dramtmg[1]);
+ writel((tcwl << 24) | (tcl << 16) | (trd2wr << 8) | twr2rd,
+ &mctl_ctl->dramtmg[2]);
+ writel((tmrw << 20) | (tmrd << 12) | tmod, &mctl_ctl->dramtmg[3]);
+ writel((trcd << 24) | (tccd << 16) | (trrd << 8) | trp,
+ &mctl_ctl->dramtmg[4]);
+ writel((tcksrx << 24) | (tcksre << 16) | (tckesr << 8) | tcke,
+ &mctl_ctl->dramtmg[5]);
+ /* Value suggested by ZynqMP manual and used by libdram */
+ writel((txp + 2) | 0x02020000, &mctl_ctl->dramtmg[6]);
+ writel((txsfast << 24) | (txsabort << 16) | (txsdll << 8) | txs,
+ &mctl_ctl->dramtmg[8]);
+ writel(0x00020208, &mctl_ctl->dramtmg[9]);
+ writel(0xE0C05, &mctl_ctl->dramtmg[10]);
+ writel(0x440C021C, &mctl_ctl->dramtmg[11]);
+ writel(8, &mctl_ctl->dramtmg[12]);
+ writel(0xA100002, &mctl_ctl->dramtmg[13]);
+ writel(txsr, &mctl_ctl->dramtmg[14]);
+
+ clrsetbits_le32(&mctl_ctl->init[0], 0xC0000FFF, 0x3f0);
+ writel(0x01f20000, &mctl_ctl->init[1]);
+ writel(0x00000d05, &mctl_ctl->init[2]);
+ writel(0, &mctl_ctl->dfimisc);
+ writel(0x0034001b, &mctl_ctl->init[3]);
+ writel(0x00330000, &mctl_ctl->init[4]);
+ writel(0x00040072, &mctl_ctl->init[6]);
+ writel(0x00240009, &mctl_ctl->init[7]);
+
+ clrsetbits_le32(&mctl_ctl->rankctl, 0xff0, 0x660);
+
+ /* Configure DFI timing */
+ writel(tphy_wrlat | 0x2000000 | (t_rdata_en << 16) | 0x808000,
+ &mctl_ctl->dfitmg0);
+ writel(0x100202, &mctl_ctl->dfitmg1);
+
+ /* set refresh timing */
+ writel((trefi << 16) | trfc, &mctl_ctl->rfshtmg);
+}
diff --git a/arch/arm/mach-sunxi/pmic_bus.c b/arch/arm/mach-sunxi/pmic_bus.c
index c0908406370..8e7625fe057 100644
--- a/arch/arm/mach-sunxi/pmic_bus.c
+++ b/arch/arm/mach-sunxi/pmic_bus.c
@@ -22,6 +22,7 @@
#define AXP209_I2C_ADDR 0x34
#define AXP305_I2C_ADDR 0x36
+#define AXP313_I2C_ADDR 0x36
#define AXP221_CHIP_ADDR 0x68
@@ -34,6 +35,8 @@ static int pmic_i2c_address(void)
return AXP152_I2C_ADDR;
if (IS_ENABLED(CONFIG_AXP305_POWER))
return AXP305_I2C_ADDR;
+ if (IS_ENABLED(CONFIG_AXP313_POWER))
+ return AXP313_I2C_ADDR;
/* Other AXP2xx and AXP8xx variants */
return AXP209_I2C_ADDR;