]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: Intel |
0a391b1c BM |
2 | /* |
3 | * Copyright (C) 2013, Intel Corporation | |
4 | * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> | |
5 | * | |
6 | * Ported from Intel released Quark UEFI BIOS | |
7 | * QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei | |
0a391b1c BM |
8 | */ |
9 | ||
10 | /* | |
11 | * This is the main Quark Memory Reference Code (MRC) | |
12 | * | |
13 | * These functions are generic and should work for any Quark-based board. | |
14 | * | |
15 | * MRC requires two data structures to be passed in which are initialized by | |
16 | * mrc_adjust_params(). | |
17 | * | |
18 | * The basic flow is as follows: | |
19 | * 01) Check for supported DDR speed configuration | |
20 | * 02) Set up Memory Manager buffer as pass-through (POR) | |
21 | * 03) Set Channel Interleaving Mode and Channel Stride to the most aggressive | |
22 | * setting possible | |
23 | * 04) Set up the Memory Controller logic | |
24 | * 05) Set up the DDR_PHY logic | |
25 | * 06) Initialise the DRAMs (JEDEC) | |
26 | * 07) Perform the Receive Enable Calibration algorithm | |
27 | * 08) Perform the Write Leveling algorithm | |
28 | * 09) Perform the Read Training algorithm (includes internal Vref) | |
29 | * 10) Perform the Write Training algorithm | |
30 | * 11) Set Channel Interleaving Mode and Channel Stride to the desired settings | |
31 | * | |
32 | * DRAM unit configuration based on Valleyview MRC. | |
33 | */ | |
34 | ||
d678a59d | 35 | #include <common.h> |
0a391b1c BM |
36 | #include <asm/arch/mrc.h> |
37 | #include <asm/arch/msg_port.h> | |
38 | #include "mrc_util.h" | |
39 | #include "smc.h" | |
40 | ||
41 | static const struct mem_init init[] = { | |
42 | { 0x0101, BM_COLD | BM_FAST | BM_WARM | BM_S3, clear_self_refresh }, | |
43 | { 0x0200, BM_COLD | BM_FAST | BM_WARM | BM_S3, prog_ddr_timing_control }, | |
44 | { 0x0103, BM_COLD | BM_FAST , prog_decode_before_jedec }, | |
45 | { 0x0104, BM_COLD | BM_FAST , perform_ddr_reset }, | |
46 | { 0x0300, BM_COLD | BM_FAST | BM_S3, ddrphy_init }, | |
47 | { 0x0400, BM_COLD | BM_FAST , perform_jedec_init }, | |
48 | { 0x0105, BM_COLD | BM_FAST , set_ddr_init_complete }, | |
49 | { 0x0106, BM_FAST | BM_WARM | BM_S3, restore_timings }, | |
50 | { 0x0106, BM_COLD , default_timings }, | |
51 | { 0x0500, BM_COLD , rcvn_cal }, | |
52 | { 0x0600, BM_COLD , wr_level }, | |
53 | { 0x0120, BM_COLD , prog_page_ctrl }, | |
54 | { 0x0700, BM_COLD , rd_train }, | |
55 | { 0x0800, BM_COLD , wr_train }, | |
56 | { 0x010b, BM_COLD , store_timings }, | |
57 | { 0x010c, BM_COLD | BM_FAST | BM_WARM | BM_S3, enable_scrambling }, | |
58 | { 0x010d, BM_COLD | BM_FAST | BM_WARM | BM_S3, prog_ddr_control }, | |
59 | { 0x010e, BM_COLD | BM_FAST | BM_WARM | BM_S3, prog_dra_drb }, | |
60 | { 0x010f, BM_WARM | BM_S3, perform_wake }, | |
61 | { 0x0110, BM_COLD | BM_FAST | BM_WARM | BM_S3, change_refresh_period }, | |
62 | { 0x0111, BM_COLD | BM_FAST | BM_WARM | BM_S3, set_auto_refresh }, | |
63 | { 0x0112, BM_COLD | BM_FAST | BM_WARM | BM_S3, ecc_enable }, | |
64 | { 0x0113, BM_COLD | BM_FAST , memory_test }, | |
65 | { 0x0114, BM_COLD | BM_FAST | BM_WARM | BM_S3, lock_registers } | |
66 | }; | |
67 | ||
68 | /* Adjust configuration parameters before initialization sequence */ | |
69 | static void mrc_adjust_params(struct mrc_params *mrc_params) | |
70 | { | |
71 | const struct dram_params *dram_params; | |
72 | uint8_t dram_width; | |
73 | uint32_t rank_enables; | |
74 | uint32_t channel_width; | |
75 | ||
76 | ENTERFN(); | |
77 | ||
78 | /* initially expect success */ | |
79 | mrc_params->status = MRC_SUCCESS; | |
80 | ||
81 | dram_width = mrc_params->dram_width; | |
82 | rank_enables = mrc_params->rank_enables; | |
83 | channel_width = mrc_params->channel_width; | |
84 | ||
85 | /* | |
86 | * Setup board layout (must be reviewed as is selecting static timings) | |
87 | * 0 == R0 (DDR3 x16), 1 == R1 (DDR3 x16), | |
88 | * 2 == DV (DDR3 x8), 3 == SV (DDR3 x8). | |
89 | */ | |
90 | if (dram_width == X8) | |
91 | mrc_params->board_id = 2; /* select x8 layout */ | |
92 | else | |
93 | mrc_params->board_id = 0; /* select x16 layout */ | |
94 | ||
95 | /* initially no memory */ | |
96 | mrc_params->mem_size = 0; | |
97 | ||
98 | /* begin of channel settings */ | |
99 | dram_params = &mrc_params->params; | |
100 | ||
101 | /* | |
102 | * Determine column bits: | |
103 | * | |
104 | * Column: 11 for 8Gbx8, else 10 | |
105 | */ | |
106 | mrc_params->column_bits[0] = | |
312cc39e BM |
107 | (dram_params[0].density == 4) && |
108 | (dram_width == X8) ? 11 : 10; | |
0a391b1c BM |
109 | |
110 | /* | |
111 | * Determine row bits: | |
112 | * | |
113 | * 512Mbx16=12 512Mbx8=13 | |
114 | * 1Gbx16=13 1Gbx8=14 | |
115 | * 2Gbx16=14 2Gbx8=15 | |
116 | * 4Gbx16=15 4Gbx8=16 | |
117 | * 8Gbx16=16 8Gbx8=16 | |
118 | */ | |
312cc39e BM |
119 | mrc_params->row_bits[0] = 12 + dram_params[0].density + |
120 | (dram_params[0].density < 4) && | |
121 | (dram_width == X8) ? 1 : 0; | |
0a391b1c BM |
122 | |
123 | /* | |
124 | * Determine per-channel memory size: | |
125 | * | |
126 | * (For 2 RANKs, multiply by 2) | |
127 | * (For 16 bit data bus, divide by 2) | |
128 | * | |
129 | * DENSITY WIDTH MEM_AVAILABLE | |
130 | * 512Mb x16 0x008000000 ( 128MB) | |
131 | * 512Mb x8 0x010000000 ( 256MB) | |
132 | * 1Gb x16 0x010000000 ( 256MB) | |
133 | * 1Gb x8 0x020000000 ( 512MB) | |
134 | * 2Gb x16 0x020000000 ( 512MB) | |
135 | * 2Gb x8 0x040000000 (1024MB) | |
136 | * 4Gb x16 0x040000000 (1024MB) | |
137 | * 4Gb x8 0x080000000 (2048MB) | |
138 | */ | |
312cc39e | 139 | mrc_params->channel_size[0] = 1 << dram_params[0].density; |
0a391b1c BM |
140 | mrc_params->channel_size[0] *= (dram_width == X8) ? 2 : 1; |
141 | mrc_params->channel_size[0] *= (rank_enables == 0x3) ? 2 : 1; | |
142 | mrc_params->channel_size[0] *= (channel_width == X16) ? 1 : 2; | |
143 | ||
144 | /* Determine memory size (convert number of 64MB/512Mb units) */ | |
145 | mrc_params->mem_size += mrc_params->channel_size[0] << 26; | |
146 | ||
147 | LEAVEFN(); | |
148 | } | |
149 | ||
150 | static void mrc_mem_init(struct mrc_params *mrc_params) | |
151 | { | |
152 | int i; | |
153 | ||
154 | ENTERFN(); | |
155 | ||
156 | /* MRC started */ | |
157 | mrc_post_code(0x01, 0x00); | |
158 | ||
159 | if (mrc_params->boot_mode != BM_COLD) { | |
160 | if (mrc_params->ddr_speed != mrc_params->timings.ddr_speed) { | |
161 | /* full training required as frequency changed */ | |
162 | mrc_params->boot_mode = BM_COLD; | |
163 | } | |
164 | } | |
165 | ||
166 | for (i = 0; i < ARRAY_SIZE(init); i++) { | |
167 | uint64_t my_tsc; | |
168 | ||
169 | if (mrc_params->boot_mode & init[i].boot_path) { | |
170 | uint8_t major = init[i].post_code >> 8 & 0xff; | |
171 | uint8_t minor = init[i].post_code >> 0 & 0xff; | |
172 | mrc_post_code(major, minor); | |
173 | ||
174 | my_tsc = rdtsc(); | |
175 | init[i].init_fn(mrc_params); | |
176 | DPF(D_TIME, "Execution time %llx", rdtsc() - my_tsc); | |
177 | } | |
178 | } | |
179 | ||
180 | /* display the timings */ | |
181 | print_timings(mrc_params); | |
182 | ||
183 | /* MRC complete */ | |
184 | mrc_post_code(0x01, 0xff); | |
185 | ||
186 | LEAVEFN(); | |
187 | } | |
188 | ||
189 | void mrc_init(struct mrc_params *mrc_params) | |
190 | { | |
191 | ENTERFN(); | |
192 | ||
fd004950 | 193 | DPF(D_INFO, "MRC Version %04x\n", MRC_VERSION); |
0a391b1c BM |
194 | |
195 | /* Set up the data structures used by mrc_mem_init() */ | |
196 | mrc_adjust_params(mrc_params); | |
197 | ||
198 | /* Initialize system memory */ | |
199 | mrc_mem_init(mrc_params); | |
200 | ||
201 | LEAVEFN(); | |
202 | } |