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