]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
5894ca00 | 2 | /* |
a74c28a0 MY |
3 | * Copyright (C) 2011-2014 Panasonic Corporation |
4 | * Copyright (C) 2015-2016 Socionext Inc. | |
5 | * Author: Masahiro Yamada <yamada.masahiro@socionext.com> | |
5894ca00 MY |
6 | */ |
7 | ||
0f4ec05b | 8 | #include <linux/errno.h> |
f6e7f07c | 9 | #include <linux/io.h> |
1e94b46f | 10 | #include <linux/printk.h> |
323d1f9d | 11 | #include <linux/sizes.h> |
a191e0de | 12 | #include <asm/processor.h> |
107b3fb4 MY |
13 | |
14 | #include "../init.h" | |
6dd34ae4 | 15 | #include "ddrphy-init.h" |
107b3fb4 | 16 | #include "umc-regs.h" |
5894ca00 | 17 | |
c5985b4b MY |
18 | #define DRAM_CH_NR 2 |
19 | ||
380a8caf MY |
20 | enum dram_freq { |
21 | DRAM_FREQ_1333M, | |
22 | DRAM_FREQ_1600M, | |
23 | DRAM_FREQ_NR, | |
24 | }; | |
25 | ||
82e59508 MY |
26 | enum dram_size { |
27 | DRAM_SZ_128M, | |
28 | DRAM_SZ_256M, | |
380a8caf | 29 | DRAM_SZ_512M, |
82e59508 MY |
30 | DRAM_SZ_NR, |
31 | }; | |
32 | ||
380a8caf MY |
33 | static u32 umc_cmdctla[DRAM_FREQ_NR] = {0x55990b11, 0x66bb0f17}; |
34 | static u32 umc_cmdctla_plus[DRAM_FREQ_NR] = {0x45990b11, 0x46bb0f17}; | |
35 | static u32 umc_cmdctlb[DRAM_FREQ_NR] = {0x16958944, 0x18c6ab44}; | |
36 | static u32 umc_cmdctlb_plus[DRAM_FREQ_NR] = {0x16958924, 0x18c6ab24}; | |
37 | static u32 umc_spcctla[DRAM_FREQ_NR][DRAM_SZ_NR] = { | |
38 | {0x00240512, 0x00350512, 0x00000000}, /* no data for 1333MHz,128MB */ | |
39 | {0x002b0617, 0x003f0617, 0x00670617}, | |
40 | }; | |
41 | static u32 umc_spcctlb[DRAM_FREQ_NR] = {0x00ff0006, 0x00ff0008}; | |
42 | static u32 umc_rdatactl[DRAM_FREQ_NR] = {0x000a00ac, 0x000c00ac}; | |
82e59508 | 43 | |
c5985b4b MY |
44 | static int umc_get_rank(int ch) |
45 | { | |
46 | return ch; /* ch0: rank0, ch1: rank1 for this SoC */ | |
47 | } | |
48 | ||
ee94ee34 | 49 | static void umc_start_ssif(void __iomem *ssif_base) |
5894ca00 MY |
50 | { |
51 | writel(0x00000000, ssif_base + 0x0000b004); | |
52 | writel(0xffffffff, ssif_base + 0x0000c004); | |
53 | writel(0x000fffcf, ssif_base + 0x0000c008); | |
54 | writel(0x00000001, ssif_base + 0x0000b000); | |
55 | writel(0x00000001, ssif_base + 0x0000c000); | |
56 | writel(0x03010101, ssif_base + UMC_MDMCHSEL); | |
57 | writel(0x03010100, ssif_base + UMC_DMDCHSEL); | |
58 | ||
59 | writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_FETCH); | |
60 | writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMQUE0); | |
61 | writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMWC0); | |
62 | writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMRC0); | |
63 | writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMQUE1); | |
64 | writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMWC1); | |
65 | writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMRC1); | |
66 | writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_WC); | |
67 | writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_RC); | |
68 | writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_DST); | |
69 | ||
70 | writel(0x00000001, ssif_base + UMC_CPURST); | |
71 | writel(0x00000001, ssif_base + UMC_IDSRST); | |
72 | writel(0x00000001, ssif_base + UMC_IXMRST); | |
73 | writel(0x00000001, ssif_base + UMC_MDMRST); | |
74 | writel(0x00000001, ssif_base + UMC_MDDRST); | |
75 | writel(0x00000001, ssif_base + UMC_SIORST); | |
76 | writel(0x00000001, ssif_base + UMC_VIORST); | |
77 | writel(0x00000001, ssif_base + UMC_FRCRST); | |
78 | writel(0x00000001, ssif_base + UMC_RGLRST); | |
79 | writel(0x00000001, ssif_base + UMC_AIORST); | |
80 | writel(0x00000001, ssif_base + UMC_DMDRST); | |
81 | } | |
82 | ||
4e651003 | 83 | static int umc_dramcont_init(void __iomem *dc_base, void __iomem *ca_base, |
fd14397e | 84 | int freq, unsigned long size, bool ddr3plus) |
5894ca00 | 85 | { |
380a8caf | 86 | enum dram_freq freq_e; |
82e59508 | 87 | enum dram_size size_e; |
5894ca00 | 88 | |
380a8caf MY |
89 | switch (freq) { |
90 | case 1333: | |
91 | freq_e = DRAM_FREQ_1333M; | |
92 | break; | |
93 | case 1600: | |
94 | freq_e = DRAM_FREQ_1600M; | |
95 | break; | |
96 | default: | |
97 | pr_err("unsupported DRAM frequency %d MHz\n", freq); | |
98 | return -EINVAL; | |
99 | } | |
100 | ||
82e59508 MY |
101 | switch (size) { |
102 | case 0: | |
103 | return 0; | |
fd14397e | 104 | case SZ_128M: |
82e59508 MY |
105 | size_e = DRAM_SZ_128M; |
106 | break; | |
fd14397e | 107 | case SZ_256M: |
82e59508 MY |
108 | size_e = DRAM_SZ_256M; |
109 | break; | |
fd14397e | 110 | case SZ_512M: |
380a8caf MY |
111 | size_e = DRAM_SZ_512M; |
112 | break; | |
82e59508 | 113 | default: |
fd14397e | 114 | pr_err("unsupported DRAM size 0x%08lx\n", size); |
82e59508 MY |
115 | return -EINVAL; |
116 | } | |
5894ca00 | 117 | |
380a8caf | 118 | writel((ddr3plus ? umc_cmdctla_plus : umc_cmdctla)[freq_e], |
4e651003 | 119 | dc_base + UMC_CMDCTLA); |
380a8caf | 120 | writel((ddr3plus ? umc_cmdctlb_plus : umc_cmdctlb)[freq_e], |
4e651003 MY |
121 | dc_base + UMC_CMDCTLB); |
122 | writel(umc_spcctla[freq_e][size_e], dc_base + UMC_SPCCTLA); | |
123 | writel(umc_spcctlb[freq_e], dc_base + UMC_SPCCTLB); | |
124 | writel(umc_rdatactl[freq_e], dc_base + UMC_RDATACTL_D0); | |
125 | writel(0x04060806, dc_base + UMC_WDATACTL_D0); | |
126 | writel(0x04a02000, dc_base + UMC_DATASET); | |
5894ca00 | 127 | writel(0x00000000, ca_base + 0x2300); |
4e651003 MY |
128 | writel(0x00400020, dc_base + UMC_DCCGCTL); |
129 | writel(0x00000003, dc_base + 0x7000); | |
130 | writel(0x0000004f, dc_base + 0x8000); | |
131 | writel(0x000000c3, dc_base + 0x8004); | |
132 | writel(0x00000077, dc_base + 0x8008); | |
133 | writel(0x0000003b, dc_base + UMC_DICGCTLA); | |
134 | writel(0x020a0808, dc_base + UMC_DICGCTLB); | |
135 | writel(0x00000004, dc_base + UMC_FLOWCTLG); | |
5894ca00 | 136 | writel(0x80000201, ca_base + 0xc20); |
4e651003 MY |
137 | writel(0x0801e01e, dc_base + UMC_FLOWCTLA); |
138 | writel(0x00200000, dc_base + UMC_FLOWCTLB); | |
139 | writel(0x00004444, dc_base + UMC_FLOWCTLC); | |
140 | writel(0x200a0a00, dc_base + UMC_SPCSETB); | |
141 | writel(0x00000000, dc_base + UMC_SPCSETD); | |
142 | writel(0x00000520, dc_base + UMC_DFICUPDCTLA); | |
82e59508 MY |
143 | |
144 | return 0; | |
5894ca00 MY |
145 | } |
146 | ||
c5985b4b | 147 | static int umc_ch_init(void __iomem *dc_base, void __iomem *ca_base, |
fd14397e | 148 | int freq, unsigned long size, bool ddr3plus, int ch) |
5894ca00 | 149 | { |
c5985b4b MY |
150 | void __iomem *phy_base = dc_base + 0x00001000; |
151 | int ret; | |
b614e16c | 152 | |
a191e0de | 153 | writel(UMC_INITSET_INIT1EN, dc_base + UMC_INITSET); |
a8b66ac8 | 154 | while (readl(dc_base + UMC_INITSTAT) & UMC_INITSTAT_INIT1ST) |
a191e0de | 155 | cpu_relax(); |
5894ca00 | 156 | |
c5985b4b | 157 | writel(0x00000101, dc_base + UMC_DIOCTLA); |
b614e16c | 158 | |
5b660066 | 159 | ret = uniphier_ld4_ddrphy_init(phy_base, freq, ddr3plus); |
c5985b4b MY |
160 | if (ret) |
161 | return ret; | |
b614e16c | 162 | |
c5985b4b MY |
163 | ddrphy_prepare_training(phy_base, umc_get_rank(ch)); |
164 | ret = ddrphy_training(phy_base); | |
165 | if (ret) | |
166 | return ret; | |
5894ca00 | 167 | |
fd14397e | 168 | return umc_dramcont_init(dc_base, ca_base, freq, size, ddr3plus); |
5894ca00 MY |
169 | } |
170 | ||
5b660066 | 171 | int uniphier_sld8_umc_init(const struct uniphier_board_data *bd) |
5894ca00 | 172 | { |
c5985b4b MY |
173 | void __iomem *umc_base = (void __iomem *)0x5b800000; |
174 | void __iomem *ca_base = umc_base + 0x00001000; | |
175 | void __iomem *dc_base = umc_base + 0x00400000; | |
176 | void __iomem *ssif_base = umc_base; | |
177 | int ch, ret; | |
178 | ||
179 | for (ch = 0; ch < DRAM_CH_NR; ch++) { | |
180 | ret = umc_ch_init(dc_base, ca_base, bd->dram_freq, | |
fd14397e | 181 | bd->dram_ch[ch].size, |
a74c28a0 | 182 | !!(bd->flags & UNIPHIER_BD_DDR3PLUS), ch); |
c5985b4b MY |
183 | if (ret) { |
184 | pr_err("failed to initialize UMC ch%d\n", ch); | |
185 | return ret; | |
186 | } | |
187 | ||
188 | ca_base += 0x00001000; | |
189 | dc_base += 0x00200000; | |
323d1f9d | 190 | } |
c5985b4b MY |
191 | |
192 | umc_start_ssif(ssif_base); | |
193 | ||
194 | return 0; | |
5894ca00 | 195 | } |