cd355cc8409ba04b526f0100ca514c9953f44a42
[oweals/u-boot.git] / arch / mips / mach-mtmips / ddr_init.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2020 MediaTek Inc.
4  *
5  * Author:  Weijie Gao <weijie.gao@mediatek.com>
6  */
7
8 #include <common.h>
9 #include <linux/bitops.h>
10 #include <linux/io.h>
11 #include <linux/sizes.h>
12 #include <mach/ddr.h>
13 #include <mach/mc.h>
14
15 #define DDR_BW_TEST_PAT                 0xaa5555aa
16
17 static const u32 dram_size[] = {
18         [DRAM_8MB] = SZ_8M,
19         [DRAM_16MB] = SZ_16M,
20         [DRAM_32MB] = SZ_32M,
21         [DRAM_64MB] = SZ_64M,
22         [DRAM_128MB] = SZ_128M,
23         [DRAM_256MB] = SZ_256M,
24 };
25
26 static void dram_test_write(u32 addr, u32 val)
27 {
28         volatile ulong *target = (volatile ulong *)(KSEG1 + addr);
29
30         sync();
31         *target = val;
32         sync();
33 }
34
35 static u32 dram_test_read(u32 addr)
36 {
37         volatile ulong *target = (volatile ulong *)(KSEG1 + addr);
38         u32 val;
39
40         sync();
41         val = *target;
42         sync();
43
44         return val;
45 }
46
47 static int dram_addr_test_bit(u32 bit)
48 {
49         u32 val;
50
51         dram_test_write(0, 0);
52         dram_test_write(BIT(bit), DDR_BW_TEST_PAT);
53         val = dram_test_read(0);
54
55         if (val == DDR_BW_TEST_PAT)
56                 return 1;
57
58         return 0;
59 }
60
61 static void mc_ddr_init(void __iomem *memc, const struct mc_ddr_cfg *cfg,
62                         u32 dq_dly, u32 dqs_dly, mc_reset_t mc_reset, u32 bw)
63 {
64         u32 val;
65
66         mc_reset(1);
67         __udelay(200);
68         mc_reset(0);
69
70         clrbits_32(memc + MEMCTL_SDRAM_CFG1_REG, RBC_MAPPING);
71
72         writel(cfg->cfg2, memc + MEMCTL_DDR_CFG2_REG);
73         writel(cfg->cfg3, memc + MEMCTL_DDR_CFG3_REG);
74         writel(cfg->cfg4, memc + MEMCTL_DDR_CFG4_REG);
75         writel(dq_dly, memc + MEMCTL_DDR_DQ_DLY_REG);
76         writel(dqs_dly, memc + MEMCTL_DDR_DQS_DLY_REG);
77
78         writel(cfg->cfg0, memc + MEMCTL_DDR_CFG0_REG);
79
80         val = cfg->cfg1;
81         if (bw) {
82                 val &= ~IND_SDRAM_WIDTH_M;
83                 val |= (bw << IND_SDRAM_WIDTH_S) & IND_SDRAM_WIDTH_M;
84         }
85
86         writel(val, memc + MEMCTL_DDR_CFG1_REG);
87
88         clrsetbits_32(memc + MEMCTL_PWR_SAVE_CNT_REG, SR_TAR_CNT_M,
89                       1 << SR_TAR_CNT_S);
90
91         setbits_32(memc + MEMCTL_DDR_SELF_REFRESH_REG, SR_AUTO_EN);
92 }
93
94 void ddr1_init(struct mc_ddr_init_param *param)
95 {
96         enum mc_dram_size sz;
97         u32 bw = 0;
98
99         /* First initialization, determine bus width */
100         mc_ddr_init(param->memc, &param->cfgs[DRAM_8MB], param->dq_dly,
101                     param->dqs_dly, param->mc_reset, IND_SDRAM_WIDTH_16BIT);
102
103         /* Test bus width */
104         dram_test_write(0, DDR_BW_TEST_PAT);
105         if (dram_test_read(0) == DDR_BW_TEST_PAT)
106                 bw = IND_SDRAM_WIDTH_16BIT;
107         else
108                 bw = IND_SDRAM_WIDTH_8BIT;
109
110         /* Second initialization, determine DDR capacity */
111         mc_ddr_init(param->memc, &param->cfgs[DRAM_128MB], param->dq_dly,
112                     param->dqs_dly, param->mc_reset, bw);
113
114         if (dram_addr_test_bit(9)) {
115                 sz = DRAM_8MB;
116         } else {
117                 if (dram_addr_test_bit(10)) {
118                         if (dram_addr_test_bit(23))
119                                 sz = DRAM_16MB;
120                         else
121                                 sz = DRAM_32MB;
122                 } else {
123                         if (dram_addr_test_bit(24))
124                                 sz = DRAM_64MB;
125                         else
126                                 sz = DRAM_128MB;
127                 }
128         }
129
130         /* Final initialization, with DDR calibration */
131         mc_ddr_init(param->memc, &param->cfgs[sz], param->dq_dly,
132                     param->dqs_dly, param->mc_reset, bw);
133
134         /* Return actual DDR configuration */
135         param->memsize = dram_size[sz];
136         param->bus_width = bw;
137 }
138
139 void ddr2_init(struct mc_ddr_init_param *param)
140 {
141         enum mc_dram_size sz;
142         u32 bw = 0;
143
144         /* First initialization, determine bus width */
145         mc_ddr_init(param->memc, &param->cfgs[DRAM_32MB], param->dq_dly,
146                     param->dqs_dly, param->mc_reset, IND_SDRAM_WIDTH_16BIT);
147
148         /* Test bus width */
149         dram_test_write(0, DDR_BW_TEST_PAT);
150         if (dram_test_read(0) == DDR_BW_TEST_PAT)
151                 bw = IND_SDRAM_WIDTH_16BIT;
152         else
153                 bw = IND_SDRAM_WIDTH_8BIT;
154
155         /* Second initialization, determine DDR capacity */
156         mc_ddr_init(param->memc, &param->cfgs[DRAM_256MB], param->dq_dly,
157                     param->dqs_dly, param->mc_reset, bw);
158
159         if (bw == IND_SDRAM_WIDTH_16BIT) {
160                 if (dram_addr_test_bit(10)) {
161                         sz = DRAM_32MB;
162                 } else {
163                         if (dram_addr_test_bit(24)) {
164                                 if (dram_addr_test_bit(27))
165                                         sz = DRAM_64MB;
166                                 else
167                                         sz = DRAM_128MB;
168                         } else {
169                                 sz = DRAM_256MB;
170                         }
171                 }
172         } else {
173                 if (dram_addr_test_bit(23)) {
174                         sz = DRAM_32MB;
175                 } else {
176                         if (dram_addr_test_bit(24)) {
177                                 if (dram_addr_test_bit(27))
178                                         sz = DRAM_64MB;
179                                 else
180                                         sz = DRAM_128MB;
181                         } else {
182                                 sz = DRAM_256MB;
183                         }
184                 }
185         }
186
187         /* Final initialization, with DDR calibration */
188         mc_ddr_init(param->memc, &param->cfgs[sz], param->dq_dly,
189                     param->dqs_dly, param->mc_reset, bw);
190
191         /* Return actual DDR configuration */
192         param->memsize = dram_size[sz];
193         param->bus_width = bw;
194 }