blob: 6c6d0933f2eaea74a953745497cc5a9d583300f2 [file] [log] [blame]
Weijie Gao02cd4492020-04-21 09:28:34 +02001// 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>
Simon Glassc05ed002020-05-10 11:40:11 -060010#include <linux/delay.h>
Weijie Gao02cd4492020-04-21 09:28:34 +020011#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
18static 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
27static 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
36static 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
48static 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
62static 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
95void 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
140void 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}