175 lines
4.8 KiB
C
175 lines
4.8 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Portions Copyright (C) 2015, Amlogic, Inc. All rights reserved.
|
|
* Copyright (C) 2023-2025, Ferass El Hafidi <funderscore@postmarketos.org>
|
|
*/
|
|
#include <init.h>
|
|
#include <asm/unaligned.h>
|
|
#include <linux/libfdt.h>
|
|
#include <config.h>
|
|
#include <errno.h>
|
|
#include <asm/io.h>
|
|
#include <asm/arch/dram-gx.h>
|
|
#include <asm/arch/gx.h>
|
|
#include <asm/arch/clock-gx.h>
|
|
#include <asm/arch/dram-settings-gx.h>
|
|
#include <linux/delay.h>
|
|
|
|
/* Meson GXBB specific DRAM init */
|
|
|
|
void meson_dram_prepare_pctl(void)
|
|
{
|
|
writel(PCTL0_1US_PCK, PCTL_TOGCNT1U);
|
|
writel(PCTL0_100NS_PCK, PCTL_TOGCNT100N);
|
|
writel(PCTL0_INIT_US, PCTL_TINIT);
|
|
writel(PCTL0_RSTH_US, PCTL_TRSTH);
|
|
|
|
writel(PCTL0_MCFG | (CONFIG_DRAM_2T_MODE ? 8 : 0),
|
|
PCTL_MCFG);
|
|
writel(PCTL0_MCFG1, PCTL_MCFG1);
|
|
udelay(500);
|
|
|
|
WAIT_FOR(PCTL_DFISTSTAT0);
|
|
|
|
/* Ask the DRAM to kindly power on and wait until it is ready */
|
|
writel(PCTL_POWCTL_POWERON, PCTL_POWCTL);
|
|
WAIT_FOR(PCTL_POWSTAT);
|
|
}
|
|
|
|
void meson_dram_phy_init(void)
|
|
{
|
|
/* Some unknown magic done by bl2 */
|
|
writel(0x49494949, DDR0_PUB_IOVCR0);
|
|
writel(0x49494949, DDR0_PUB_IOVCR1);
|
|
|
|
writel(PUB_ODTCR, DDR0_PUB_ODTCR);
|
|
|
|
writel(PUB_MR0, DDR0_PUB_MR0);
|
|
writel(PUB_MR1, DDR0_PUB_MR1);
|
|
writel(PUB_MR2, DDR0_PUB_MR2);
|
|
writel(PUB_MR3, DDR0_PUB_MR3);
|
|
|
|
/* Configure DRAM timing parameters (DTPR) */
|
|
writel(PUB_DTPR0, DDR0_PUB_DTPR0);
|
|
writel(PUB_DTPR1, DDR0_PUB_DTPR1);
|
|
writel(PUB_PGCR1, DDR0_PUB_PGCR1);
|
|
writel(PUB_DTPR2, DDR0_PUB_DTPR2);
|
|
writel(PUB_DTPR3, DDR0_PUB_DTPR3);
|
|
|
|
if (IS_ENABLED(CONFIG_DRAM_TWO_IDENTICAL_RANKS))
|
|
writel(PUB_PGCR2 | (1 << 28), DDR0_PUB_PGCR2);
|
|
else
|
|
writel(PUB_PGCR2, DDR0_PUB_PGCR2);
|
|
|
|
writel(PUB_PGCR3, DDR0_PUB_PGCR3);
|
|
writel(PUB_DXCCR, DDR0_PUB_DXCCR);
|
|
|
|
writel(PUB_DTCR, DDR0_PUB_DTCR);
|
|
/* Wait for DLL lock */
|
|
WAIT_FOR(DDR0_PUB_PGSR0);
|
|
|
|
writel(0, DDR0_PUB_ACIOCR1);
|
|
writel(0, DDR0_PUB_ACIOCR2);
|
|
writel(0, DDR0_PUB_ACIOCR3);
|
|
writel(0, DDR0_PUB_ACIOCR4);
|
|
writel(0, DDR0_PUB_ACIOCR5);
|
|
|
|
writel(0, DDR0_PUB_DX0GCR1);
|
|
writel(0, DDR0_PUB_DX0GCR2);
|
|
writel((1 << 10) | (2 << 12), DDR0_PUB_DX0GCR3);
|
|
writel(0, DDR0_PUB_DX1GCR1);
|
|
writel(0, DDR0_PUB_DX1GCR2);
|
|
writel((1 << 10) | (2 << 12), DDR0_PUB_DX1GCR3);
|
|
writel(0, DDR0_PUB_DX2GCR1);
|
|
writel(0, DDR0_PUB_DX2GCR2);
|
|
writel((1 << 10) | (2 << 12), DDR0_PUB_DX2GCR3);
|
|
writel(0, DDR0_PUB_DX3GCR1);
|
|
writel(0, DDR0_PUB_DX3GCR2);
|
|
writel((1 << 10) | (2 << 12), DDR0_PUB_DX3GCR3);
|
|
|
|
writel(PUB_DCR, DDR0_PUB_DCR);
|
|
|
|
writel(PUB_DTAR, DDR0_PUB_DTAR0);
|
|
writel(PUB_DTAR | 0x8, DDR0_PUB_DTAR1);
|
|
writel(PUB_DTAR | 0x10, DDR0_PUB_DTAR2);
|
|
writel(PUB_DTAR | 0x18, DDR0_PUB_DTAR3);
|
|
|
|
writel(PUB_DSGCR, DDR0_PUB_DSGCR);
|
|
|
|
/* Wait for the SDRAM to initialise */
|
|
WAIT_FOR(DDR0_PUB_PGSR0);
|
|
}
|
|
|
|
void meson_dram_phy_setup_ranks(void)
|
|
{
|
|
if (IS_ENABLED(CONFIG_DRAM_ONE_RANK) || IS_ENABLED(CONFIG_DRAM_TWO_DIFF_RANKS)) {
|
|
uint i = 0, j = 0;
|
|
|
|
writel((readl(DDR0_PUB_DX0LCDLR0) >> 8) |
|
|
(readl(DDR0_PUB_DX0LCDLR0) & 0xffffff00),
|
|
DDR0_PUB_DX0LCDLR0);
|
|
|
|
i = ((readl(DDR0_PUB_DX2GTR) >> 3) & (7 << 0));
|
|
j = ((readl(DDR0_PUB_DX2GTR) >> 14) & (3 << 0));
|
|
writel(i | (i << 3) | (j << 12) | (j << 14), DDR0_PUB_DX2GTR);
|
|
|
|
writel((readl(DDR0_PUB_DX2LCDLR2) >> 8) |
|
|
(readl(DDR0_PUB_DX2LCDLR2) & 0xffffff00),
|
|
DDR0_PUB_DX2LCDLR2);
|
|
|
|
writel((readl(DDR0_PUB_DX3LCDLR0) >> 8) |
|
|
(readl(DDR0_PUB_DX3LCDLR0) & 0xffffff00),
|
|
DDR0_PUB_DX3LCDLR0);
|
|
|
|
i = (readl(DDR0_PUB_DX3GTR) >> 3) & (7 << 0);
|
|
j = (readl(DDR0_PUB_DX3GTR) >> 14) & (3 << 0);
|
|
writel(i | (i << 3) | (j << 12) | (j << 14), DDR0_PUB_DX3GTR);
|
|
|
|
writel((readl(DDR0_PUB_DX3LCDLR2) >> 8) |
|
|
(readl(DDR0_PUB_DX3LCDLR2) & 0xffffff00),
|
|
DDR0_PUB_DX3LCDLR2);
|
|
|
|
writel((readl(DDR0_PUB_DX0LCDLR0) << 8) |
|
|
(readl(DDR0_PUB_DX0LCDLR0) & 0xffff00ff),
|
|
DDR0_PUB_DX0LCDLR0);
|
|
|
|
i = (readl(DDR0_PUB_DX0GTR) << 0) & (7 << 0);
|
|
j = (readl(DDR0_PUB_DX0GTR) >> 12) & (3 << 0);
|
|
writel(i | (i << 3) | (j << 12) | (j << 14), DDR0_PUB_DX0GTR);
|
|
|
|
writel((readl(DDR0_PUB_DX0LCDLR2) << 8) |
|
|
(readl(DDR0_PUB_DX0LCDLR2) & 0xffff00ff),
|
|
DDR0_PUB_DX0LCDLR2);
|
|
|
|
writel((readl(DDR0_PUB_DX1LCDLR0) << 8) |
|
|
(readl(DDR0_PUB_DX1LCDLR0) & 0xffff00ff),
|
|
DDR0_PUB_DX1LCDLR0);
|
|
|
|
i = (readl(DDR0_PUB_DX1GTR) << 0) & (7 << 0);
|
|
j = (readl(DDR0_PUB_DX1GTR) >> 12) & (3 << 0);
|
|
writel(i | (i << 3) | (j << 12) | (j << 14), DDR0_PUB_DX0GTR);
|
|
|
|
writel((readl(DDR0_PUB_DX1LCDLR2) >> 8) |
|
|
(readl(DDR0_PUB_DX1LCDLR2) & 0xffffff00),
|
|
DDR0_PUB_DX1LCDLR2);
|
|
}
|
|
|
|
writel((~(1 << 28)) & PUB_PGCR2, DDR0_PUB_PGCR2);
|
|
|
|
if (IS_ENABLED(CONFIG_DRAM_2T_MODE) && (PUB_DCR & 7) == 3)
|
|
writel(0x1f, DDR0_PUB_ACLCDLR);
|
|
}
|
|
|
|
void meson_dram_finalise_init(void)
|
|
{
|
|
WAIT_FOR(PCTL_CMDTSTAT);
|
|
writel(PCTL_SCTL_GO_STATE, PCTL_SCTL);
|
|
|
|
while (readl(PCTL_STAT) != PCTL_STAT_ACCESS)
|
|
;
|
|
writel(0x880019d, DMC_REFR_CTRL1);
|
|
writel(0x20100000 | (CONFIG_DRAM_CLK / 20) |
|
|
(timings.refi << 8), DMC_REFR_CTRL2);
|
|
clrbits_32(DDR0_PUB_ZQCR, 4);
|
|
}
|