#include "ddrphy-regs.h"
#include "umc-regs.h"
+#define DRAM_CH_NR 2
+
enum dram_size {
DRAM_SZ_128M,
DRAM_SZ_256M,
}
static int umc_dramcont_init(void __iomem *dramcont, void __iomem *ca_base,
- int size, int width)
+ int freq, unsigned long size, bool ddr3plus)
{
enum dram_size dram_size;
- switch (size / (width / 16)) {
+ if (freq != 1600) {
+ pr_err("Unsupported DDR frequency %d MHz\n", freq);
+ return -EINVAL;
+ }
+
+ if (ddr3plus) {
+ pr_err("DDR3+ is not supported\n");
+ return -EINVAL;
+ }
+
+ switch (size) {
case SZ_128M:
dram_size = DRAM_SZ_128M;
break;
dram_size = DRAM_SZ_512M;
break;
default:
- pr_err("unsupported DRAM size\n");
+ pr_err("unsupported DRAM size 0x%08lx (per 16bit)\n", size);
return -EINVAL;
}
return 0;
}
-int ph1_pro4_umc_init(const struct uniphier_board_data *bd)
+static int umc_ch_init(void __iomem *dc_base, void __iomem *ca_base,
+ int freq, unsigned long size, unsigned int width,
+ bool ddr3plus)
{
- void __iomem *ssif_base = (void __iomem *)UMC_SSIF_BASE;
- void __iomem *ca_base0 = (void __iomem *)UMC_CA_BASE(0);
- void __iomem *ca_base1 = (void __iomem *)UMC_CA_BASE(1);
- void __iomem *dramcont0 = (void __iomem *)UMC_DRAMCONT_BASE(0);
- void __iomem *dramcont1 = (void __iomem *)UMC_DRAMCONT_BASE(1);
- void __iomem *phy0_0 = (void __iomem *)DDRPHY_BASE(0, 0);
- void __iomem *phy0_1 = (void __iomem *)DDRPHY_BASE(0, 1);
- void __iomem *phy1_0 = (void __iomem *)DDRPHY_BASE(1, 0);
- void __iomem *phy1_1 = (void __iomem *)DDRPHY_BASE(1, 1);
- int ret;
-
- if (bd->dram_freq != 1600) {
- pr_err("Unsupported DDR configuration\n");
- return -EINVAL;
- }
-
- umc_dram_init_start(dramcont0);
- umc_dram_init_start(dramcont1);
- umc_dram_init_poll(dramcont0);
- umc_dram_init_poll(dramcont1);
-
- writel(0x00000101, dramcont0 + UMC_DIOCTLA);
+ void __iomem *phy_base = dc_base + 0x00001000;
+ int nr_phy = width / 16;
+ int phy, ret;
- ph1_ld4_ddrphy_init(phy0_0, bd->dram_freq, bd->dram_ddr3plus);
+ umc_dram_init_start(dc_base);
+ umc_dram_init_poll(dc_base);
- ddrphy_prepare_training(phy0_0, 0);
- ddrphy_training(phy0_0);
+ for (phy = 0; phy < nr_phy; phy++) {
+ writel(0x00000100 | ((1 << (phy + 1)) - 1),
+ dc_base + UMC_DIOCTLA);
- writel(0x00000103, dramcont0 + UMC_DIOCTLA);
+ ret = ph1_ld4_ddrphy_init(phy_base, freq, ddr3plus);
+ if (ret)
+ return ret;
- ph1_ld4_ddrphy_init(phy0_1, bd->dram_freq, bd->dram_ddr3plus);
+ ddrphy_prepare_training(phy_base, phy);
+ ret = ddrphy_training(phy_base);
+ if (ret)
+ return ret;
- ddrphy_prepare_training(phy0_1, 1);
- ddrphy_training(phy0_1);
-
- writel(0x00000101, dramcont1 + UMC_DIOCTLA);
-
- ph1_ld4_ddrphy_init(phy1_0, bd->dram_freq, bd->dram_ddr3plus);
-
- ddrphy_prepare_training(phy1_0, 0);
- ddrphy_training(phy1_0);
-
- writel(0x00000103, dramcont1 + UMC_DIOCTLA);
-
- ph1_ld4_ddrphy_init(phy1_1, bd->dram_freq, bd->dram_ddr3plus);
-
- ddrphy_prepare_training(phy1_1, 1);
- ddrphy_training(phy1_1);
+ phy_base += 0x00001000;
+ }
- ret = umc_dramcont_init(dramcont0, ca_base0, bd->dram_ch[0].size,
- bd->dram_ch[0].width);
- if (ret)
- return ret;
+ return umc_dramcont_init(dc_base, ca_base, freq, size / (width / 16),
+ ddr3plus);
+}
- ret = umc_dramcont_init(dramcont1, ca_base1, bd->dram_ch[1].size,
- bd->dram_ch[1].width);
- if (ret)
- return ret;
+int ph1_pro4_umc_init(const struct uniphier_board_data *bd)
+{
+ void __iomem *umc_base = (void __iomem *)0x5b800000;
+ void __iomem *ca_base = umc_base + 0x00001000;
+ void __iomem *dc_base = umc_base + 0x00400000;
+ void __iomem *ssif_base = umc_base;
+ int ch, ret;
+
+ for (ch = 0; ch < DRAM_CH_NR; ch++) {
+ ret = umc_ch_init(dc_base, ca_base, bd->dram_freq,
+ bd->dram_ch[ch].size,
+ bd->dram_ch[ch].width,
+ bd->dram_ddr3plus);
+ if (ret) {
+ pr_err("failed to initialize UMC ch%d\n", ch);
+ return ret;
+ }
+
+ ca_base += 0x00001000;
+ dc_base += 0x00200000;
+ }
umc_start_ssif(ssif_base);