mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-29 08:01:08 +00:00
02cd449f0b
This patch rewrites the mtmips architecture with the following changes: 1. Move MT7628 soc parts into a subfolder. 2. Lock parts of D-Cache as temporary stack. 3. Reimplement DDR initialization in C language. 4. Reimplement DDR calibration in a clear logic. 5. Add full support for auto size detection for DDR1 and DDR2. 6. Use accurate CPU clock depending on the input xtal frequency for timer and delay functions. Note: print_cpuinfo() has incompatible parts with MT7620 so it's moved into mt7628 subfolder. Reviewed-by: Stefan Roese <sr@denx.de> Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com> Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
194 lines
4.2 KiB
C
194 lines
4.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2020 MediaTek Inc.
|
|
*
|
|
* Author: Weijie Gao <weijie.gao@mediatek.com>
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <linux/bitops.h>
|
|
#include <linux/io.h>
|
|
#include <linux/sizes.h>
|
|
#include <mach/ddr.h>
|
|
#include <mach/mc.h>
|
|
|
|
#define DDR_BW_TEST_PAT 0xaa5555aa
|
|
|
|
static const u32 dram_size[] = {
|
|
[DRAM_8MB] = SZ_8M,
|
|
[DRAM_16MB] = SZ_16M,
|
|
[DRAM_32MB] = SZ_32M,
|
|
[DRAM_64MB] = SZ_64M,
|
|
[DRAM_128MB] = SZ_128M,
|
|
[DRAM_256MB] = SZ_256M,
|
|
};
|
|
|
|
static void dram_test_write(u32 addr, u32 val)
|
|
{
|
|
volatile ulong *target = (volatile ulong *)(KSEG1 + addr);
|
|
|
|
sync();
|
|
*target = val;
|
|
sync();
|
|
}
|
|
|
|
static u32 dram_test_read(u32 addr)
|
|
{
|
|
volatile ulong *target = (volatile ulong *)(KSEG1 + addr);
|
|
u32 val;
|
|
|
|
sync();
|
|
val = *target;
|
|
sync();
|
|
|
|
return val;
|
|
}
|
|
|
|
static int dram_addr_test_bit(u32 bit)
|
|
{
|
|
u32 val;
|
|
|
|
dram_test_write(0, 0);
|
|
dram_test_write(BIT(bit), DDR_BW_TEST_PAT);
|
|
val = dram_test_read(0);
|
|
|
|
if (val == DDR_BW_TEST_PAT)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void mc_ddr_init(void __iomem *memc, const struct mc_ddr_cfg *cfg,
|
|
u32 dq_dly, u32 dqs_dly, mc_reset_t mc_reset, u32 bw)
|
|
{
|
|
u32 val;
|
|
|
|
mc_reset(1);
|
|
__udelay(200);
|
|
mc_reset(0);
|
|
|
|
clrbits_32(memc + MEMCTL_SDRAM_CFG1_REG, RBC_MAPPING);
|
|
|
|
writel(cfg->cfg2, memc + MEMCTL_DDR_CFG2_REG);
|
|
writel(cfg->cfg3, memc + MEMCTL_DDR_CFG3_REG);
|
|
writel(cfg->cfg4, memc + MEMCTL_DDR_CFG4_REG);
|
|
writel(dq_dly, memc + MEMCTL_DDR_DQ_DLY_REG);
|
|
writel(dqs_dly, memc + MEMCTL_DDR_DQS_DLY_REG);
|
|
|
|
writel(cfg->cfg0, memc + MEMCTL_DDR_CFG0_REG);
|
|
|
|
val = cfg->cfg1;
|
|
if (bw) {
|
|
val &= ~IND_SDRAM_WIDTH_M;
|
|
val |= (bw << IND_SDRAM_WIDTH_S) & IND_SDRAM_WIDTH_M;
|
|
}
|
|
|
|
writel(val, memc + MEMCTL_DDR_CFG1_REG);
|
|
|
|
clrsetbits_32(memc + MEMCTL_PWR_SAVE_CNT_REG, SR_TAR_CNT_M,
|
|
1 << SR_TAR_CNT_S);
|
|
|
|
setbits_32(memc + MEMCTL_DDR_SELF_REFRESH_REG, SR_AUTO_EN);
|
|
}
|
|
|
|
void ddr1_init(struct mc_ddr_init_param *param)
|
|
{
|
|
enum mc_dram_size sz;
|
|
u32 bw = 0;
|
|
|
|
/* First initialization, determine bus width */
|
|
mc_ddr_init(param->memc, ¶m->cfgs[DRAM_8MB], param->dq_dly,
|
|
param->dqs_dly, param->mc_reset, IND_SDRAM_WIDTH_16BIT);
|
|
|
|
/* Test bus width */
|
|
dram_test_write(0, DDR_BW_TEST_PAT);
|
|
if (dram_test_read(0) == DDR_BW_TEST_PAT)
|
|
bw = IND_SDRAM_WIDTH_16BIT;
|
|
else
|
|
bw = IND_SDRAM_WIDTH_8BIT;
|
|
|
|
/* Second initialization, determine DDR capacity */
|
|
mc_ddr_init(param->memc, ¶m->cfgs[DRAM_128MB], param->dq_dly,
|
|
param->dqs_dly, param->mc_reset, bw);
|
|
|
|
if (dram_addr_test_bit(9)) {
|
|
sz = DRAM_8MB;
|
|
} else {
|
|
if (dram_addr_test_bit(10)) {
|
|
if (dram_addr_test_bit(23))
|
|
sz = DRAM_16MB;
|
|
else
|
|
sz = DRAM_32MB;
|
|
} else {
|
|
if (dram_addr_test_bit(24))
|
|
sz = DRAM_64MB;
|
|
else
|
|
sz = DRAM_128MB;
|
|
}
|
|
}
|
|
|
|
/* Final initialization, with DDR calibration */
|
|
mc_ddr_init(param->memc, ¶m->cfgs[sz], param->dq_dly,
|
|
param->dqs_dly, param->mc_reset, bw);
|
|
|
|
/* Return actual DDR configuration */
|
|
param->memsize = dram_size[sz];
|
|
param->bus_width = bw;
|
|
}
|
|
|
|
void ddr2_init(struct mc_ddr_init_param *param)
|
|
{
|
|
enum mc_dram_size sz;
|
|
u32 bw = 0;
|
|
|
|
/* First initialization, determine bus width */
|
|
mc_ddr_init(param->memc, ¶m->cfgs[DRAM_32MB], param->dq_dly,
|
|
param->dqs_dly, param->mc_reset, IND_SDRAM_WIDTH_16BIT);
|
|
|
|
/* Test bus width */
|
|
dram_test_write(0, DDR_BW_TEST_PAT);
|
|
if (dram_test_read(0) == DDR_BW_TEST_PAT)
|
|
bw = IND_SDRAM_WIDTH_16BIT;
|
|
else
|
|
bw = IND_SDRAM_WIDTH_8BIT;
|
|
|
|
/* Second initialization, determine DDR capacity */
|
|
mc_ddr_init(param->memc, ¶m->cfgs[DRAM_256MB], param->dq_dly,
|
|
param->dqs_dly, param->mc_reset, bw);
|
|
|
|
if (bw == IND_SDRAM_WIDTH_16BIT) {
|
|
if (dram_addr_test_bit(10)) {
|
|
sz = DRAM_32MB;
|
|
} else {
|
|
if (dram_addr_test_bit(24)) {
|
|
if (dram_addr_test_bit(27))
|
|
sz = DRAM_64MB;
|
|
else
|
|
sz = DRAM_128MB;
|
|
} else {
|
|
sz = DRAM_256MB;
|
|
}
|
|
}
|
|
} else {
|
|
if (dram_addr_test_bit(23)) {
|
|
sz = DRAM_32MB;
|
|
} else {
|
|
if (dram_addr_test_bit(24)) {
|
|
if (dram_addr_test_bit(27))
|
|
sz = DRAM_64MB;
|
|
else
|
|
sz = DRAM_128MB;
|
|
} else {
|
|
sz = DRAM_256MB;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Final initialization, with DDR calibration */
|
|
mc_ddr_init(param->memc, ¶m->cfgs[sz], param->dq_dly,
|
|
param->dqs_dly, param->mc_reset, bw);
|
|
|
|
/* Return actual DDR configuration */
|
|
param->memsize = dram_size[sz];
|
|
param->bus_width = bw;
|
|
}
|