1 /*
2 * Copyright (c) 2021 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "hpm_common.h"
9 #include "hpm_dram_drv.h"
10
11 #ifndef HPM_DRAM_DRV_DEFAULT_PRESCALER
12 #define HPM_DRAM_DRV_DEFAULT_PRESCALER (0x3UL)
13 #endif
14
15 #ifndef HPM_DRAM_DRV_RETRY_COUNT
16 #define HPM_DRAM_DRV_RETRY_COUNT (5000U)
17 #endif
18
19 #define DRAM_PRESCALER_MAX (256UL)
20
dram_config_delay_cell(DRAM_Type * ptr,uint32_t delay_cell_value)21 static void dram_config_delay_cell(DRAM_Type *ptr, uint32_t delay_cell_value)
22 {
23 ptr->DLYCFG &= ~DRAM_DLYCFG_OE_MASK;
24 ptr->DLYCFG = DRAM_DLYCFG_DLYSEL_SET(delay_cell_value) | DRAM_DLYCFG_DLYEN_MASK;
25 ptr->DLYCFG |= DRAM_DLYCFG_OE_MASK;
26 }
27
dram_ip_cmd_done(DRAM_Type * ptr)28 static hpm_stat_t dram_ip_cmd_done(DRAM_Type *ptr)
29 {
30 uint32_t intr_status = 0;
31 uint32_t retry = 0;
32 do {
33 if (retry > HPM_DRAM_DRV_RETRY_COUNT) {
34 break;
35 }
36 retry++;
37 intr_status = ptr->INTR
38 & (uint32_t)(DRAM_INTR_IPCMDDONE_MASK | DRAM_INTR_IPCMDERR_MASK);
39 } while (intr_status == 0);
40
41 if (retry > HPM_DRAM_DRV_RETRY_COUNT) {
42 return status_timeout;
43 }
44
45 ptr->INTR |= DRAM_INTR_IPCMDDONE_MASK | DRAM_INTR_IPCMDERR_MASK;
46 if (intr_status & DRAM_INTR_IPCMDERR_MASK) {
47 return status_dram_cmd_err;
48 }
49 return status_success;
50 }
51
dram_make_cmd(uint32_t opcode)52 static uint32_t dram_make_cmd(uint32_t opcode)
53 {
54 return (opcode & ~DRAM_CMD_WRITE_FLAG) | DRAM_CMD_KEY;
55 }
56
dram_is_write_cmd(uint32_t opcode)57 static bool dram_is_write_cmd(uint32_t opcode)
58 {
59 return ((opcode & DRAM_CMD_WRITE_FLAG) == DRAM_CMD_WRITE_FLAG);
60 }
61
dram_issue_ip_cmd(DRAM_Type * ptr,uint32_t base_address,dram_cmd_t * cmd)62 uint32_t dram_issue_ip_cmd(DRAM_Type *ptr, uint32_t base_address, dram_cmd_t *cmd)
63 {
64 bool read_data = !dram_is_write_cmd(cmd->opcode);
65 ptr->SADDR = base_address;
66 if (!read_data) {
67 ptr->IPTX = cmd->data;
68 }
69 ptr->IPCMD = dram_make_cmd(cmd->opcode);
70
71 if (dram_ip_cmd_done(ptr) < 0) {
72 return status_dram_cmd_err;
73 }
74
75 if (read_data) {
76 cmd->data = ptr->IPRX;
77 }
78 return status_success;
79 }
80
dram_default_config(DRAM_Type * ptr,dram_config_t * config)81 void dram_default_config(DRAM_Type *ptr, dram_config_t *config)
82 {
83 dram_axi_q_weight_t *q;
84 config->dqs = DRAM_DQS_FROM_PAD;
85 config->cmd_timeout = 0;
86 config->bus_timeout = 0x10;
87 q = &config->axi_q_weight[DRAM_AXI_Q_A];
88 q->enable = true;
89 q->qos = 4;
90 q->age = 2;
91 q->slave_hit = 0x5;
92 q->slave_hit_wo_rw = 0x3;
93
94 q = &config->axi_q_weight[DRAM_AXI_Q_B];
95 q->enable = true;
96 q->qos = 4;
97 q->age = 2;
98 q->page_hit = 0x5;
99 q->slave_hit_wo_rw = 0x3;
100 q->bank_rotation = 0x6;
101 }
102
dram_get_typical_sdram_config(DRAM_Type * ptr,dram_sdram_config_t * config)103 void dram_get_typical_sdram_config(DRAM_Type *ptr, dram_sdram_config_t *config)
104 {
105 config->col_addr_bits = DRAM_SDRAM_COLUMN_ADDR_9_BITS;
106 config->cas_latency = DRAM_SDRAM_CAS_LATENCY_3;
107 config->bank_num = DRAM_SDRAM_BANK_NUM_4;
108 config->prescaler = HPM_DRAM_DRV_DEFAULT_PRESCALER;
109 config->burst_len_in_byte = 8;
110 config->auto_refresh_count_in_one_burst = 1;
111 config->precharge_to_act_in_ns = 20;
112 config->act_to_rw_in_ns = 20;
113 config->refresh_recover_in_ns = 70;
114 config->write_recover_in_ns = 12;
115 config->cke_off_in_ns = 42;
116 config->act_to_precharge_in_ns = 42;
117
118 config->self_refresh_recover_in_ns = 70;
119 config->refresh_to_refresh_in_ns = 60;
120 config->act_to_act_in_ns = 12;
121 config->idle_timeout_in_ns = 6;
122 config->cs_mux_pin = DRAM_IO_MUX_NOT_USED;
123 }
124
dram_init(DRAM_Type * ptr,dram_config_t * config)125 void dram_init(DRAM_Type *ptr, dram_config_t *config)
126 {
127 uint32_t i;
128 dram_axi_q_weight_t *q;
129 for (i = 0; i < DRAM_BR_COUNT; i++) {
130 ptr->BR[i] = 0;
131 }
132
133 dram_sw_reset(ptr);
134 dram_disable(ptr);
135 ptr->CTRL |= DRAM_CTRL_BTO_SET(config->bus_timeout)
136 | DRAM_CTRL_CTO_SET(config->cmd_timeout)
137 | DRAM_CTRL_DQS_SET(config->dqs);
138
139 q = &config->axi_q_weight[DRAM_AXI_Q_A];
140 if (q->enable) {
141 ptr->BMW0 = DRAM_BMW0_QOS_SET(q->qos)
142 | DRAM_BMW0_AGE_SET(q->age)
143 | DRAM_BMW0_SH_SET(q->slave_hit)
144 | DRAM_BMW0_RWS_SET(q->slave_hit_wo_rw);
145 } else {
146 ptr->BMW0 = 0;
147 }
148
149 q = &config->axi_q_weight[DRAM_AXI_Q_B];
150 if (q->enable) {
151 ptr->BMW1 = DRAM_BMW1_QOS_SET(q->qos)
152 | DRAM_BMW1_AGE_SET(q->age)
153 | DRAM_BMW1_PH_SET(q->page_hit)
154 | DRAM_BMW1_BR_SET(q->bank_rotation)
155 | DRAM_BMW1_RWS_SET(q->slave_hit_wo_rw);
156 } else {
157 ptr->BMW1 = 0;
158 }
159
160 dram_enable(ptr);
161 }
162
dram_convert_actual_size_to_memory_size(uint32_t size_in_kb)163 static uint8_t dram_convert_actual_size_to_memory_size(uint32_t size_in_kb)
164 {
165 uint8_t size = 0;
166 if (size_in_kb == 4) {
167 return 0;
168 }
169
170 if (size_in_kb > 2 * 1 << 20) {
171 return 0x1F;
172 }
173
174 size = 1;
175 size_in_kb >>= 3;
176 while (size_in_kb > 1) {
177 size_in_kb >>= 1;
178 size++;
179 }
180 return size;
181 }
182
dram_convert_burst_len(uint8_t burst_len_in_byte)183 static uint8_t dram_convert_burst_len(uint8_t burst_len_in_byte)
184 {
185 if ((burst_len_in_byte == 0)
186 || (burst_len_in_byte > DRAM_SDRAM_MAX_BURST_LENGTH_IN_BYTE)) {
187 return DRAM_SDRAM_MAX_BURST_LENGTH_IN_BYTE + 1;
188 }
189
190 switch (burst_len_in_byte) {
191 case 1:
192 case 2:
193 case 4:
194 return burst_len_in_byte >> 1;
195 case 8:
196 return (burst_len_in_byte - 1) >> 1;
197 default:
198 return DRAM_SDRAM_MAX_BURST_LENGTH_IN_BYTE + 1;
199 }
200 }
201
ns2cycle(uint32_t freq_in_hz,uint32_t ns)202 static uint32_t ns2cycle(uint32_t freq_in_hz, uint32_t ns)
203 {
204 uint32_t ns_per_cycle;
205 ns_per_cycle = 1000000000 / freq_in_hz;
206 if (ns < ns_per_cycle) {
207 return 1;
208 }
209 return ns / ns_per_cycle;
210 }
211
dram_config_sdram(DRAM_Type * ptr,uint32_t clk_in_hz,dram_sdram_config_t * config)212 hpm_stat_t dram_config_sdram(DRAM_Type *ptr, uint32_t clk_in_hz, dram_sdram_config_t *config)
213 {
214 hpm_stat_t err;
215 uint32_t prescaler;
216 uint32_t refresh_cycle;
217 uint32_t clk_in_khz = clk_in_hz / 1000;
218 dram_cmd_t cmd = {0};
219 uint8_t size = dram_convert_actual_size_to_memory_size(config->size_in_byte >> 10);
220 uint8_t burst_len = dram_convert_burst_len(config->burst_len_in_byte);
221
222 prescaler = ((config->prescaler == 0) ? DRAM_PRESCALER_MAX : config->prescaler);
223 refresh_cycle = clk_in_khz * config->refresh_in_ms / config->refresh_count / (prescaler << 4);
224
225 if ((prescaler == 0) || (prescaler > DRAM_PRESCALER_MAX)
226 || (refresh_cycle == 0) || (refresh_cycle > DRAM_PRESCALER_MAX)) {
227 return status_invalid_argument;
228 }
229
230 if (prescaler == DRAM_PRESCALER_MAX) {
231 prescaler = 0;
232 }
233
234 if (refresh_cycle == DRAM_PRESCALER_MAX) {
235 refresh_cycle = 0;
236 }
237
238 ptr->BR[config->cs] = DRAM_BR_BASE_SET(config->base_address >> DRAM_BR_BASE_SHIFT)
239 | DRAM_BR_SIZE_SET(size) | DRAM_BR_VLD_MASK;
240
241 ptr->SDRCTRL0 = DRAM_SDRCTRL0_PORTSZ_SET(config->port_size)
242 | DRAM_SDRCTRL0_BURSTLEN_SET(burst_len)
243 | DRAM_SDRCTRL0_COL_SET(config->col_addr_bits)
244 | DRAM_SDRCTRL0_COL8_SET(config->col_addr_bits == DRAM_SDRAM_COLUMN_ADDR_8_BITS)
245 | DRAM_SDRCTRL0_CAS_SET(config->cas_latency)
246 | DRAM_SDRCTRL0_BANK2_SET(config->bank_num);
247
248 ptr->SDRCTRL1 = DRAM_SDRCTRL1_PRE2ACT_SET(ns2cycle(clk_in_hz, config->precharge_to_act_in_ns))
249 | DRAM_SDRCTRL1_ACT2RW_SET(ns2cycle(clk_in_hz, config->act_to_rw_in_ns))
250 | DRAM_SDRCTRL1_RFRC_SET(ns2cycle(clk_in_hz, config->refresh_recover_in_ns))
251 | DRAM_SDRCTRL1_WRC_SET(ns2cycle(clk_in_hz, config->write_recover_in_ns))
252 | DRAM_SDRCTRL1_CKEOFF_SET(ns2cycle(clk_in_hz, config->cke_off_in_ns))
253 | DRAM_SDRCTRL1_ACT2PRE_SET(ns2cycle(clk_in_hz, config->act_to_precharge_in_ns));
254
255 ptr->SDRCTRL2 = DRAM_SDRCTRL2_SRRC_SET(ns2cycle(clk_in_hz, config->self_refresh_recover_in_ns))
256 | DRAM_SDRCTRL2_REF2REF_SET(ns2cycle(clk_in_hz, config->refresh_to_refresh_in_ns))
257 | DRAM_SDRCTRL2_ACT2ACT_SET(ns2cycle(clk_in_hz, config->act_to_act_in_ns))
258 | DRAM_SDRCTRL2_ITO_SET(ns2cycle(clk_in_hz, config->idle_timeout_in_ns));
259
260 ptr->SDRCTRL3 = DRAM_SDRCTRL3_PRESCALE_SET(prescaler)
261 | DRAM_SDRCTRL3_RT_SET(refresh_cycle)
262 | DRAM_SDRCTRL3_UT_SET(refresh_cycle)
263 | DRAM_SDRCTRL3_REBL_SET(config->auto_refresh_count_in_one_burst - 1);
264 /*
265 *
266 * DATSZ[2:0]: Data size in byte
267 * 0b - 4
268 * 1b - 1
269 * 2b - 2
270 * 3b - 3
271 * > 3b - 4
272 */
273 ptr->DATSZ = DRAM_DATSZ_DATSZ_SET((config->data_width_in_byte & (0x3UL)));
274 ptr->BYTEMSK = 0;
275
276 cmd.opcode = DRAM_CMD_SDRAM_PRECHARGE_ALL;
277 cmd.data = 0;
278 err = dram_issue_ip_cmd(ptr, config->base_address, &cmd);
279 if (status_success != err) {
280 return err;
281 }
282
283 cmd.opcode = DRAM_CMD_SDRAM_AUTO_REFRESH;
284 err = dram_issue_ip_cmd(ptr, config->base_address, &cmd);
285 if (status_success != err) {
286 return err;
287 }
288 err = dram_issue_ip_cmd(ptr, config->base_address, &cmd);
289 if (status_success != err) {
290 return err;
291 }
292
293 /*
294 *
295 * DATSZ[2:0]: Data size in byte
296 * 0b - 4
297 * 1b - 1
298 * 2b - 2
299 * 3b - 3
300 * > 3b - 4
301 */
302 ptr->DATSZ = DRAM_DATSZ_DATSZ_SET((config->data_width_in_byte & (0x3UL)));
303 ptr->BYTEMSK = 0;
304
305 /*
306 * config delay cell
307 */
308 dram_config_delay_cell(ptr, config->delay_cell_value);
309
310 cmd.opcode = DRAM_CMD_SDRAM_PRECHARGE_ALL;
311 cmd.data = 0;
312 err = dram_issue_ip_cmd(ptr, config->base_address, &cmd);
313 if (status_success != err) {
314 return err;
315 }
316
317 cmd.opcode = DRAM_CMD_SDRAM_AUTO_REFRESH;
318 err = dram_issue_ip_cmd(ptr, config->base_address, &cmd);
319 if (status_success != err) {
320 return err;
321 }
322 err = dram_issue_ip_cmd(ptr, config->base_address, &cmd);
323 if (status_success != err) {
324 return err;
325 }
326
327 cmd.opcode = DRAM_CMD_SDRAM_MODE_SET;
328 /* FIXME: the mode register layout definition better to be passed in? */
329 cmd.data = (uint32_t)(burst_len | config->cas_latency << 4);
330 err = dram_issue_ip_cmd(ptr, config->base_address, &cmd);
331 if (status_success != err) {
332 return err;
333 }
334 ptr->SDRCTRL3 |= DRAM_SDRCTRL3_REN_MASK;
335
336 return status_success;
337 }
338
339