]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/contrib/octeon-sdk/cvmx-llm.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / contrib / octeon-sdk / cvmx-llm.c
1 /***********************license start***************
2  * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3  * reserved.
4  *
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *   * Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  *
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17
18  *   * Neither the name of Cavium Inc. nor the names of
19  *     its contributors may be used to endorse or promote products
20  *     derived from this software without specific prior written
21  *     permission.
22
23  * This Software, including technical data, may be subject to U.S. export  control
24  * laws, including the U.S. Export Administration Act and its  associated
25  * regulations, and may be subject to export or import  regulations in other
26  * countries.
27
28  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29  * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30  * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31  * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32  * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33  * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34  * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35  * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36  * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37  * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38  ***********************license end**************************************/
39
40
41
42
43
44
45
46 /**
47  * @file
48  *
49  * Configuration functions for low latency memory.
50  *
51  * <hr>$Revision: 70030 $<hr>
52  */
53 #include "cvmx-config.h"
54 #include "cvmx.h"
55 #include "cvmx-llm.h"
56 #include "cvmx-sysinfo.h"
57 #include "cvmx-csr-db.h"
58
59 #define MIN(a,b) (((a)<(b))?(a):(b))
60
61 typedef struct
62 {
63     uint32_t dfa_memcfg0_base;
64     uint32_t dfa_memcfg1_base;
65     uint32_t mrs_dat_p0bunk0;
66     uint32_t mrs_dat_p0bunk1;
67     uint32_t mrs_dat_p1bunk0;
68     uint32_t mrs_dat_p1bunk1;
69     uint8_t  p0_ena;
70     uint8_t  p1_ena;
71     uint8_t  bunkport;
72 } rldram_csr_config_t;
73
74
75
76
77
78 int rld_csr_config_generate(llm_descriptor_t *llm_desc_ptr, rldram_csr_config_t *cfg_ptr);
79
80
81 void print_rld_cfg(rldram_csr_config_t *cfg_ptr);
82 void write_rld_cfg(rldram_csr_config_t *cfg_ptr);
83 static void cn31xx_dfa_memory_init(void);
84
85 static uint32_t process_address_map_str(uint32_t mrs_dat, char *addr_str);
86
87
88
89 #ifndef CVMX_LLM_NUM_PORTS
90 #warning WARNING: default CVMX_LLM_NUM_PORTS used.  Defaults deprecated, please set in executive-config.h
91 #define CVMX_LLM_NUM_PORTS 1
92 #endif
93
94
95 #if (CVMX_LLM_NUM_PORTS != 1) && (CVMX_LLM_NUM_PORTS != 2)
96 #error "Invalid CVMX_LLM_NUM_PORTS value: must be 1 or 2\n"
97 #endif
98
99 int cvmx_llm_initialize()
100 {
101     if (cvmx_llm_initialize_desc(NULL) < 0)
102         return -1;
103
104     return 0;
105 }
106
107
108 int cvmx_llm_get_default_descriptor(llm_descriptor_t *llm_desc_ptr)
109 {
110     cvmx_sysinfo_t *sys_ptr;
111     sys_ptr = cvmx_sysinfo_get();
112
113     if (!llm_desc_ptr)
114         return -1;
115
116     memset(llm_desc_ptr, 0, sizeof(llm_descriptor_t));
117
118     llm_desc_ptr->cpu_hz = cvmx_clock_get_rate(CVMX_CLOCK_CORE);
119
120     if (sys_ptr->board_type == CVMX_BOARD_TYPE_EBT3000)
121     { // N3K->RLD0 Address Swizzle
122         strcpy(llm_desc_ptr->addr_rld0_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
123         strcpy(llm_desc_ptr->addr_rld0_bb_str, "22 21 19 20 08 07 06 05 04 03 02 01 00 09 18 17 16 15 14 13 12 11 10");
124         // N3K->RLD1 Address Swizzle
125         strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
126         strcpy(llm_desc_ptr->addr_rld1_bb_str, "22 21 20 00 08 07 06 05 04 13 02 01 03 09 18 17 16 15 14 10 12 11 19");
127         /* NOTE: The ebt3000 has a strange RLDRAM configuration for validation purposes.  It is not recommended to have
128         ** different amounts of memory on different ports as that renders some memory unusable */
129         llm_desc_ptr->rld0_bunks = 2;
130         llm_desc_ptr->rld1_bunks = 2;
131         llm_desc_ptr->rld0_mbytes = 128;          // RLD0: 4x 32Mx9
132         llm_desc_ptr->rld1_mbytes = 64;           // RLD1: 2x 16Mx18
133     }
134     else if (sys_ptr->board_type == CVMX_BOARD_TYPE_EBT5800)
135     {
136         strcpy(llm_desc_ptr->addr_rld0_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
137         strcpy(llm_desc_ptr->addr_rld0_bb_str, "22 21 20 00 08 07 06 05 04 13 02 01 03 09 18 17 16 15 14 10 12 11 19");
138         strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
139         strcpy(llm_desc_ptr->addr_rld1_bb_str, "22 21 20 00 08 07 06 05 04 13 02 01 03 09 18 17 16 15 14 10 12 11 19");
140         llm_desc_ptr->rld0_bunks = 2;
141         llm_desc_ptr->rld1_bunks = 2;
142         llm_desc_ptr->rld0_mbytes = 128;
143         llm_desc_ptr->rld1_mbytes = 128;
144         llm_desc_ptr->max_rld_clock_mhz = 400;  /* CN58XX needs a max clock speed for selecting optimal divisor */
145     }
146     else if (sys_ptr->board_type == CVMX_BOARD_TYPE_EBH3000)
147     {
148         strcpy(llm_desc_ptr->addr_rld0_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
149         strcpy(llm_desc_ptr->addr_rld0_bb_str, "22 21 19 20 08 07 06 05 04 03 02 01 00 09 18 17 16 15 14 13 12 11 10");
150         strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
151         strcpy(llm_desc_ptr->addr_rld1_bb_str, "22 21 19 20 08 07 06 05 04 03 02 01 00 09 18 17 16 15 14 13 12 11 10");
152         llm_desc_ptr->rld0_bunks = 2;
153         llm_desc_ptr->rld1_bunks = 2;
154         llm_desc_ptr->rld0_mbytes = 128;
155         llm_desc_ptr->rld1_mbytes = 128;
156     }
157     else if (sys_ptr->board_type == CVMX_BOARD_TYPE_THUNDER)
158     {
159
160         if (sys_ptr->board_rev_major >= 4)
161         {
162             strcpy(llm_desc_ptr->addr_rld0_fb_str, "22 21 13 11 01 02 07 19 03 18 10 12 20 06 04 08 17 05 14 16 00 09 15");
163             strcpy(llm_desc_ptr->addr_rld0_bb_str, "22 21 11 13 04 08 17 05 14 16 00 09 15 06 01 02 07 19 03 18 10 12 20");
164             strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 02 19 18 17 16 09 14 13 20 11 10 01 08 03 06 15 04 07 05 12 00");
165             strcpy(llm_desc_ptr->addr_rld1_bb_str, "22 21 19 02 08 03 06 15 04 07 05 12 00 01 18 17 16 09 14 13 20 11 10");
166         }
167         else
168         {
169             strcpy(llm_desc_ptr->addr_rld0_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
170             strcpy(llm_desc_ptr->addr_rld0_bb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
171             strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
172             strcpy(llm_desc_ptr->addr_rld1_bb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
173         }
174
175         llm_desc_ptr->rld0_bunks = 2;
176         llm_desc_ptr->rld1_bunks = 2;
177         llm_desc_ptr->rld0_mbytes = 128;
178         llm_desc_ptr->rld1_mbytes = 128;
179     }
180     else if (sys_ptr->board_type == CVMX_BOARD_TYPE_NICPRO2)
181     {
182         strcpy(llm_desc_ptr->addr_rld0_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
183         strcpy(llm_desc_ptr->addr_rld0_bb_str, "22 21 19 20 08 07 06 05 04 03 02 01 00 09 18 17 16 15 14 13 12 11 10");
184         strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
185         strcpy(llm_desc_ptr->addr_rld1_bb_str, "22 21 19 20 08 07 06 05 04 03 02 01 00 09 18 17 16 15 14 13 12 11 10");
186         llm_desc_ptr->rld0_bunks = 2;
187         llm_desc_ptr->rld1_bunks = 2;
188         llm_desc_ptr->rld0_mbytes = 256;
189         llm_desc_ptr->rld1_mbytes = 256;
190         llm_desc_ptr->max_rld_clock_mhz = 400;  /* CN58XX needs a max clock speed for selecting optimal divisor */
191     }
192     else if (sys_ptr->board_type == CVMX_BOARD_TYPE_EBH3100)
193     {
194         /* CN31xx DFA memory is DDR based, so it is completely different from the CN38XX DFA memory */
195         llm_desc_ptr->rld0_bunks = 1;
196         llm_desc_ptr->rld0_mbytes = 256;
197     }
198     else if (sys_ptr->board_type == CVMX_BOARD_TYPE_KBP)
199     {
200         strcpy(llm_desc_ptr->addr_rld0_fb_str, "");
201         strcpy(llm_desc_ptr->addr_rld0_bb_str, "");
202         llm_desc_ptr->rld0_bunks = 0;
203         llm_desc_ptr->rld0_mbytes = 0;
204         strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
205         strcpy(llm_desc_ptr->addr_rld1_bb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
206         llm_desc_ptr->rld1_bunks = 2;
207         llm_desc_ptr->rld1_mbytes = 64;
208     }
209     else
210     {
211         cvmx_dprintf("No default LLM configuration available for board %s (%d)\n", cvmx_board_type_to_string(sys_ptr->board_type),  sys_ptr->board_type);
212         return -1;
213     }
214
215     return(0);
216 }
217
218 int cvmx_llm_initialize_desc(llm_descriptor_t *llm_desc_ptr)
219 {
220     cvmx_sysinfo_t *sys_ptr;
221     sys_ptr = cvmx_sysinfo_get();
222     llm_descriptor_t default_llm_desc;
223
224     memset(&default_llm_desc, 0, sizeof(default_llm_desc));
225     if (sys_ptr->board_type == CVMX_BOARD_TYPE_SIM)
226     {
227         cvmx_dprintf("Skipping llm configuration for simulator.\n");
228         return 0;
229     }
230
231     if (sys_ptr->board_type == CVMX_BOARD_TYPE_EBH3100)
232     {
233         /* CN31xx DFA memory is DDR based, so it is completely different from the CN38XX DFA memory
234         ** config descriptors are not supported yet.*/
235         cvmx_dprintf("Warning: preliminary DFA memory configuration\n");
236         cn31xx_dfa_memory_init();
237         return(256*1024*1024);
238     }
239
240     /* If no descriptor passed, generate default descriptor based on board type.
241     ** Fail if no default available for given board type
242     */
243     if (!llm_desc_ptr)
244     {
245         /* Get default descriptor */
246         if (0 > cvmx_llm_get_default_descriptor(&default_llm_desc))
247             return -1;
248
249         /* Disable second port depending on CVMX config */
250         if (CVMX_LLM_NUM_PORTS == 1)
251           default_llm_desc.rld0_bunks = 0;        // For single port: Force RLD0(P1) to appear EMPTY
252
253         cvmx_dprintf("Using default LLM configuration for board %s (%d)\n", cvmx_board_type_to_string(sys_ptr->board_type),  sys_ptr->board_type);
254
255         llm_desc_ptr = &default_llm_desc;
256     }
257
258
259
260     rldram_csr_config_t ebt3000_rld_cfg;
261     if (!rld_csr_config_generate(llm_desc_ptr, &ebt3000_rld_cfg))
262     {
263         cvmx_dprintf("Configuring %d llm port(s).\n", !!llm_desc_ptr->rld0_bunks + !!llm_desc_ptr->rld1_bunks);
264         write_rld_cfg(&ebt3000_rld_cfg);
265     }
266     else
267     {
268         cvmx_dprintf("Error creating rldram configuration\n");
269         return(-1);
270     }
271
272     /* Compute how much memory is configured
273     ** Memory is interleaved, so if one port has more than the other some memory is not usable */
274
275     /* If both ports are enabled, handle the case where one port has more than the other.
276     ** This is an unusual and not recommended configuration that exists on the ebt3000 board */
277     if (!!llm_desc_ptr->rld0_bunks && !!llm_desc_ptr->rld1_bunks)
278         llm_desc_ptr->rld0_mbytes = llm_desc_ptr->rld1_mbytes = MIN(llm_desc_ptr->rld0_mbytes, llm_desc_ptr->rld1_mbytes);
279
280     return(((!!llm_desc_ptr->rld0_bunks) * llm_desc_ptr->rld0_mbytes
281           + (!!llm_desc_ptr->rld1_bunks) * llm_desc_ptr->rld1_mbytes) * 1024*1024);
282 }
283
284 //======================
285 // SUPPORT FUNCTIONS:
286 //======================
287 //======================================================================
288 // Extracts srcvec[srcbitpos] and places it in return int (bit[0])
289 int bit_extract ( int srcvec,         // source word (to extract)
290                   int srcbitpos       // source bit position
291                 )
292 {
293     return(((1 << srcbitpos) & srcvec) >> srcbitpos);
294 }
295 //======================================================================
296 // Inserts srcvec[0] into dstvec[dstbitpos] (without affecting other bits)
297 int bit_insert ( int srcvec,           // srcvec[0] = bit to be inserted
298                  int dstbitpos,        // Bit position to insert into returned int
299                  int dstvec            // dstvec (destination vector)
300                )
301 {
302     return((srcvec << dstbitpos) | dstvec);      // Shift bit to insert into bit position/OR with accumulated number
303 }
304 //======================================================================
305
306 int rld_csr_config_generate(llm_descriptor_t *llm_desc_ptr, rldram_csr_config_t *cfg_ptr)
307 {
308     char *addr_rld0_fb_str;
309     char *addr_rld0_bb_str;
310     char *addr_rld1_fb_str;
311     char *addr_rld1_bb_str;
312     int eclk_ps;
313     int mtype = 0;                           // MTYPE (0: RLDRAM/1: FCRAM
314     int trcmin = 20;                         // tRC(min) - from RLDRAM data sheet
315     int trc_cyc;                             // TRC(cyc)
316     int trc_mod;
317     int trl_cyc;                             // TRL(cyc)
318     int twl_cyc;                             // TWL(cyc)
319     int tmrsc_cyc = 6;                       // tMRSC(cyc)  [2-7]
320     int mclk_ps;                             // DFA Memory Clock(in ps) = 2x eclk
321     int rldcfg = 99;                         // RLDRAM-II CFG (1,2,3)
322     int mrs_odt = 0;                         // RLDRAM MRS A[9]=ODT (default)
323     int mrs_impmatch = 0;                    // RLDRAM MRS A[8]=Impedance Matching (default)
324     int mrs_dllrst = 1;                      // RLDRAM MRS A[7]=DLL Reset (default)
325     uint32_t mrs_dat;
326     int mrs_dat_p0bunk0 = 0;                 // MRS Register Data After Address Map (for Port0 Bunk0)
327     int mrs_dat_p0bunk1 = 0;                 // MRS Register Data After Address Map (for Port0 Bunk1)
328     int mrs_dat_p1bunk0 = 0;                 // MRS Register Data After Address Map (for Port1 Bunk0)
329     int mrs_dat_p1bunk1 = 0;                 // MRS Register Data After Address Map (for Port1 Bunk1)
330     int p0_ena = 0;                          // DFA Port#0 Enabled
331     int p1_ena = 0;                          // DFA Port#1 Enabled
332     int memport = 0;                       // Memory(MB) per Port [MAX=512]
333     int membunk;                             // Memory(MB) per Bunk
334     int bunkport = 0;                        // Bunks/Port [1/2]
335     int pbunk = 0;                               // Physical Bunk(or Rank) encoding for address bit
336     int tref_ms = 32;                        // tREF(ms) (RLDRAM-II overall device refresh interval
337     int trefi_ns;                            // tREFI(ns) = tREF(ns)/#rows/bank
338     int rows = 8;                            // #rows/bank (K) typically 8K
339     int ref512int;
340     int ref512mod;
341     int tskw_cyc = 0;
342     int fprch = 1;
343     int bprch = 0;
344     int dfa_memcfg0_base = 0;
345     int dfa_memcfg1_base = 0;
346     int tbl = 1;                             // tBL (1: 2-burst /2: 4-burst)
347     int rw_dly;
348     int wr_dly;
349     int r2r = 1;
350     int sil_lat = 1;
351     int clkdiv = 2;  /* CN38XX is fixed at 2, CN58XX supports 2,3,4 */
352     int clkdiv_enc = 0x0;  /* Encoded clock divisor, only used for CN58XX */
353
354     if (!llm_desc_ptr)
355         return -1;
356
357     /* Setup variables from descriptor */
358
359     addr_rld0_fb_str = llm_desc_ptr->addr_rld0_fb_str;
360     addr_rld0_bb_str = llm_desc_ptr->addr_rld0_bb_str;
361     addr_rld1_fb_str = llm_desc_ptr->addr_rld1_fb_str;
362     addr_rld1_bb_str = llm_desc_ptr->addr_rld1_bb_str;
363
364     p0_ena = !!llm_desc_ptr->rld1_bunks;        // NOTE: P0 == RLD1
365     p1_ena = !!llm_desc_ptr->rld0_bunks;        // NOTE: P1 == RLD0
366
367     // Massage the code, so that if the user had imbalanced memory per-port (or imbalanced bunks/port), we
368     // at least try to configure 'workable' memory.
369     if (p0_ena && p1_ena)  // IF BOTH PORTS Enabled (imbalanced memory), select smaller of BOTH
370     {
371         memport = MIN(llm_desc_ptr->rld0_mbytes, llm_desc_ptr->rld1_mbytes);
372         bunkport = MIN(llm_desc_ptr->rld0_bunks, llm_desc_ptr->rld1_bunks);
373     }
374     else if (p0_ena) // P0=RLD1 Enabled
375     {
376         memport = llm_desc_ptr->rld1_mbytes;
377         bunkport = llm_desc_ptr->rld1_bunks;
378     }
379     else if (p1_ena) // P1=RLD0 Enabled
380     {
381         memport = llm_desc_ptr->rld0_mbytes;
382         bunkport = llm_desc_ptr->rld0_bunks;
383     }
384     else
385         return -1;
386
387     uint32_t eclk_mhz = llm_desc_ptr->cpu_hz/1000000;
388
389
390
391     /* Tweak skew based on cpu clock */
392     if (eclk_mhz <= 367)
393     {
394         tskw_cyc = 0;
395     }
396     else
397     {
398         tskw_cyc = 1;
399     }
400
401     /* Determine clock divider ratio (only required for CN58XX) */
402     if (OCTEON_IS_MODEL(OCTEON_CN58XX))
403     {
404         uint32_t max_llm_clock_mhz = llm_desc_ptr->max_rld_clock_mhz;
405         if (!max_llm_clock_mhz)
406         {
407             max_llm_clock_mhz = 400;  /* Default to 400 MHz */
408             cvmx_dprintf("Warning, using default max_rld_clock_mhz of: %lu MHz\n", (unsigned long)max_llm_clock_mhz);
409         }
410
411         /* Compute the divisor, and round up */
412         clkdiv = eclk_mhz/max_llm_clock_mhz;
413         if (clkdiv * max_llm_clock_mhz < eclk_mhz)
414             clkdiv++;
415
416         if (clkdiv > 4)
417         {
418             cvmx_dprintf("ERROR: CN58XX LLM clock divisor out of range\n");
419             goto TERMINATE;
420         }
421         if (clkdiv < 2)
422             clkdiv = 2;
423
424         cvmx_dprintf("Using llm clock divisor: %d, llm clock is: %lu MHz\n", clkdiv, (unsigned long)eclk_mhz/clkdiv);
425         /* Translate divisor into bit encoding for register */
426         /* 0 -> div 2
427         ** 1 -> reserved
428         ** 2 -> div 3
429         ** 3 -> div 4
430         */
431         if (clkdiv == 2)
432             clkdiv_enc = 0;
433         else
434             clkdiv_enc = clkdiv - 1;
435
436     /* Odd divisor needs sil_lat to be 2 */
437         if (clkdiv == 0x3)
438             sil_lat = 2;
439
440         /* Increment tskw for high clock speeds */
441         if ((unsigned long)eclk_mhz/clkdiv >= 375)
442             tskw_cyc += 1;
443     }
444
445     eclk_ps = (1000000+(eclk_mhz-1)) / eclk_mhz;  // round up if nonzero remainder
446     //=======================================================================
447
448     //=======================================================================
449     // Now, Query User for DFA Memory Type
450     if (mtype != 0)
451     {
452         goto TERMINATE;         // Complete this code for FCRAM usage on N3K-P2
453     }
454     //=======================================================================
455     // Query what the tRC(min) value is from the data sheets
456     //=======================================================================
457     // Now determine the Best CFG based on Memory clock(ps) and tRCmin(ns)
458     mclk_ps = eclk_ps * clkdiv;
459     trc_cyc = ((trcmin * 1000)/mclk_ps);
460     trc_mod = ((trcmin * 1000) % mclk_ps);
461     // If remainder exists, bump up to the next integer multiple
462     if (trc_mod != 0)
463     {
464         trc_cyc = trc_cyc + 1;
465     }
466     // If tRC is now ODD, then bump it to the next EVEN integer (RLDRAM-II does not support odd tRC values at this time).
467     if (trc_cyc & 1)
468     {
469         trc_cyc = trc_cyc + 1;           // Bump it to an even #
470     }
471     // RLDRAM CFG Range Check: If the computed trc_cyc is less than 4, then set it to min CFG1 [tRC=4]
472     if (trc_cyc < 4)
473     {
474         trc_cyc = 4;             // If computed trc_cyc < 4 then clamp to 4
475     }
476     else if (trc_cyc > 8)
477     {    // If the computed trc_cyc > 8, then report an error (because RLDRAM cannot support a tRC>8
478         goto TERMINATE;
479     }
480     // Assuming all is ok(up to here)
481     // At this point the tRC_cyc has been clamped  between 4 and 8 (and is even), So it can only be 4,6,8 which are
482     // the RLDRAM valid CFG range values.
483     trl_cyc = trc_cyc;                 // tRL = tRC (for RLDRAM=II)
484     twl_cyc = trl_cyc + 1;             // tWL = tRL + 1 (for RLDRAM-II)
485     // NOTE: RLDRAM-II (as of 4/25/05) only have 3 supported CFG encodings:
486     if (trc_cyc == 4)
487     {
488         rldcfg = 1;           // CFG #1 (tRL=4/tRC=4/tWL=5)
489     }
490     else if (trc_cyc == 6)
491     {
492         rldcfg = 2;           // CFG #2 (tRL=6/tRC=6/tWL=7)
493     }
494     else if (trc_cyc == 8)
495     {
496         rldcfg = 3;           // CFG #3 (tRL=8/tRC=8/tWL=9)
497     }
498     else
499     {
500         goto TERMINATE;
501     }
502     //=======================================================================
503     mrs_dat = ( (mrs_odt << 9) | (mrs_impmatch << 8) | (mrs_dllrst << 7) | rldcfg );
504     //=======================================================================
505     // If there is only a single bunk, then skip over address mapping queries (which are not required)
506     if (bunkport == 1)
507     {
508         goto CALC_PBUNK;
509     }
510
511     /* Process the address mappings */
512     /* Note that that RLD0 pins corresponds to Port#1, and
513     **                RLD1 pins corresponds to Port#0.
514     */
515     mrs_dat_p1bunk0 = process_address_map_str(mrs_dat, addr_rld0_fb_str);
516     mrs_dat_p1bunk1 = process_address_map_str(mrs_dat, addr_rld0_bb_str);
517     mrs_dat_p0bunk0 = process_address_map_str(mrs_dat, addr_rld1_fb_str);
518     mrs_dat_p0bunk1 = process_address_map_str(mrs_dat, addr_rld1_bb_str);
519
520
521     //=======================================================================
522     CALC_PBUNK:
523     // Determine the PBUNK field (based on Memory/Bunk)
524     // This determines the addr bit used to distinguish when crossing a bunk.
525     // NOTE: For RLDRAM, the bunk bit is extracted from 'a' programmably selected high
526     // order addr bit. [linear address per-bunk]
527     if (bunkport == 2)
528     {
529         membunk = (memport / 2);
530     }
531     else
532     {
533         membunk = memport;
534     }
535     if (membunk == 16)
536     {       // 16MB/bunk MA[19]
537         pbunk = 0;
538     }
539     else if (membunk == 32)
540     {  // 32MB/bunk MA[20]
541         pbunk = 1;
542     }
543     else if (membunk == 64)
544     {  // 64MB/bunk MA[21]
545         pbunk = 2;
546     }
547     else if (membunk == 128)
548     { // 128MB/bunk MA[22]
549         pbunk = 3;
550     }
551     else if (membunk == 256)
552     { // 256MB/bunk MA[23]
553         pbunk = 4;
554     }
555     else if (membunk == 512)
556     { // 512MB/bunk
557     }
558     //=======================================================================
559     //=======================================================================
560     //=======================================================================
561     // Now determine N3K REFINT
562     trefi_ns = (tref_ms * 1000 * 1000) / (rows * 1024);
563     ref512int = ((trefi_ns * 1000) / (eclk_ps * 512));
564     ref512mod = ((trefi_ns * 1000) % (eclk_ps * 512));
565     //=======================================================================
566     // Ask about tSKW
567 #if 0
568     if (tskw_ps ==  0)
569     {
570         tskw_cyc = 0;
571     }
572     else
573     { // CEILING function
574         tskw_cyc = (tskw_ps / eclk_ps);
575         tskw_mod = (tskw_ps % eclk_ps);
576         if (tskw_mod != 0)
577         {  // If there's a remainder - then bump to next (+1)
578             tskw_cyc = tskw_cyc + 1;
579         }
580     }
581 #endif
582     if (tskw_cyc > 3)
583     {
584         goto TERMINATE;
585     }
586
587     tbl = 1;        // BLEN=2 (ALWAYs for RLDRAM)
588     //=======================================================================
589     // RW_DLY = (ROUND_UP{[[(TRL+TBL)*2 + tSKW + BPRCH] + 1] / 2}) - tWL
590     rw_dly = ((((trl_cyc + tbl) * 2 + tskw_cyc + bprch) + 1) / 2);
591     if (rw_dly & 1)
592     { // If it's ODD then round up
593         rw_dly = rw_dly + 1;
594     }
595     rw_dly = rw_dly - twl_cyc +1 ;
596     if (rw_dly < 0)
597     { // range check - is it positive
598         goto TERMINATE;
599     }
600     //=======================================================================
601     // WR_DLY = (ROUND_UP[[(tWL + tBL)*2 - tSKW + FPRCH] / 2]) - tRL
602     wr_dly = (((twl_cyc + tbl) * 2 - tskw_cyc + fprch) / 2);
603     if (wr_dly & 1)
604     { // If it's ODD then round up
605         wr_dly = wr_dly + 1;
606     }
607     wr_dly = wr_dly - trl_cyc + 1;
608     if (wr_dly < 0)
609     { // range check - is it positive
610         goto TERMINATE;
611     }
612
613
614     dfa_memcfg0_base = 0;
615     dfa_memcfg0_base = ( p0_ena |
616                          (p1_ena << 1) |
617                          (mtype << 3) |
618                          (sil_lat << 4) |
619                          (rw_dly << 6) |
620                          (wr_dly << 10) |
621                          (fprch << 14) |
622                          (bprch << 16) |
623                          (0 << 18) |         // BLEN=0(2-burst for RLDRAM)
624                          (pbunk << 19) |
625                          (r2r << 22) |       // R2R=1
626                          (clkdiv_enc << 28 )
627                        );
628
629
630     dfa_memcfg1_base = 0;
631     dfa_memcfg1_base = ( ref512int |
632                          (tskw_cyc << 4) |
633                          (trl_cyc << 8) |
634                          (twl_cyc << 12) |
635                          (trc_cyc << 16) |
636                          (tmrsc_cyc << 20)
637                        );
638
639
640
641
642     cfg_ptr->dfa_memcfg0_base = dfa_memcfg0_base;
643     cfg_ptr->dfa_memcfg1_base = dfa_memcfg1_base;
644     cfg_ptr->mrs_dat_p0bunk0 =  mrs_dat_p0bunk0;
645     cfg_ptr->mrs_dat_p1bunk0 =  mrs_dat_p1bunk0;
646     cfg_ptr->mrs_dat_p0bunk1 =  mrs_dat_p0bunk1;
647     cfg_ptr->mrs_dat_p1bunk1 =  mrs_dat_p1bunk1;
648     cfg_ptr->p0_ena =           p0_ena;
649     cfg_ptr->p1_ena =           p1_ena;
650     cfg_ptr->bunkport =         bunkport;
651     //=======================================================================
652
653     return(0);
654     TERMINATE:
655     return(-1);
656
657 }
658
659
660
661 static uint32_t process_address_map_str(uint32_t mrs_dat, char *addr_str)
662 {
663     int count = 0;
664     int amap [23];
665     uint32_t new_mrs_dat = 0;
666
667 //    cvmx_dprintf("mrs_dat: 0x%x, str: %x\n", mrs_dat, addr_str);
668     char *charptr = strtok(addr_str," ");
669     while ((charptr != NULL) & (count <= 22))
670     {
671         amap[22-count] = atoi(charptr);         // Assign the AMAP Array
672         charptr = strtok(NULL," ");             // Get Next char string (which represents next addr bit mapping)
673         count++;
674     }
675     // Now do the bit swap of MRSDAT (based on address mapping)
676     uint32_t mrsdat_bit;
677     for (count=0;count<=22;count++)
678     {
679         mrsdat_bit = bit_extract(mrs_dat, count);
680         new_mrs_dat = bit_insert(mrsdat_bit, amap[count], new_mrs_dat);
681     }
682
683     return new_mrs_dat;
684 }
685
686
687 //#define PRINT_LLM_CONFIG
688 #ifdef PRINT_LLM_CONFIG
689 #define ll_printf printf
690 #else
691 #define ll_printf(...)
692 #define cvmx_csr_db_decode(...)
693 #endif
694
695 static void cn31xx_dfa_memory_init(void)
696 {
697     if (OCTEON_IS_MODEL(OCTEON_CN31XX))
698     {
699         cvmx_dfa_ddr2_cfg_t  dfaCfg;
700         cvmx_dfa_eclkcfg_t   dfaEcklCfg;
701         cvmx_dfa_ddr2_addr_t dfaAddr;
702         cvmx_dfa_ddr2_tmg_t  dfaTmg;
703         cvmx_dfa_ddr2_pll_t  dfaPll;
704         int mem_freq_hz = 533*1000000;
705         int ref_freq_hz = cvmx_sysinfo_get()->dfa_ref_clock_hz;
706         if (!ref_freq_hz)
707             ref_freq_hz = 33*1000000;
708
709         cvmx_dprintf ("Configuring DFA memory for %d MHz operation.\n",mem_freq_hz/1000000);
710
711           /* Turn on the DFA memory port. */
712         dfaCfg.u64 = cvmx_read_csr (CVMX_DFA_DDR2_CFG);
713         dfaCfg.s.prtena = 1;
714         cvmx_write_csr (CVMX_DFA_DDR2_CFG, dfaCfg.u64);
715
716           /* Start the PLL alignment sequence */
717         dfaPll.u64 = 0;
718         dfaPll.s.pll_ratio  = mem_freq_hz/ref_freq_hz         /*400Mhz / 33MHz*/;
719         dfaPll.s.pll_div2   = 1              /*400 - 1 */;
720         dfaPll.s.pll_bypass = 0;
721         cvmx_write_csr (CVMX_DFA_DDR2_PLL, dfaPll.u64);
722
723         dfaPll.s.pll_init = 1;
724         cvmx_write_csr (CVMX_DFA_DDR2_PLL, dfaPll.u64);
725
726         cvmx_wait (RLD_INIT_DELAY); //want 150uS
727         dfaPll.s.qdll_ena = 1;
728         cvmx_write_csr (CVMX_DFA_DDR2_PLL, dfaPll.u64);
729
730         cvmx_wait (RLD_INIT_DELAY); //want 10us
731         dfaEcklCfg.u64 = 0;
732         dfaEcklCfg.s.dfa_frstn = 1;
733         cvmx_write_csr (CVMX_DFA_ECLKCFG, dfaEcklCfg.u64);
734
735           /* Configure the DFA Memory */
736         dfaCfg.s.silo_hc = 1 /*400 - 1 */;
737         dfaCfg.s.silo_qc = 0 /*400 - 0 */;
738         dfaCfg.s.tskw    = 1 /*400 - 1 */;
739         dfaCfg.s.ref_int = 0x820 /*533 - 0x820  400 - 0x618*/;
740         dfaCfg.s.trfc    = 0x1A  /*533 - 0x23   400 - 0x1A*/;
741         dfaCfg.s.fprch   = 0; /* 1 more conservative*/
742         dfaCfg.s.bprch   = 0; /* 1 */
743         cvmx_write_csr (CVMX_DFA_DDR2_CFG, dfaCfg.u64);
744
745         dfaEcklCfg.u64 = cvmx_read_csr (CVMX_DFA_ECLKCFG);
746         dfaEcklCfg.s.maxbnk = 1;
747         cvmx_write_csr (CVMX_DFA_ECLKCFG, dfaEcklCfg.u64);
748
749         dfaAddr.u64 = cvmx_read_csr (CVMX_DFA_DDR2_ADDR);
750         dfaAddr.s.num_cols    = 0x1;
751         dfaAddr.s.num_colrows = 0x2;
752         dfaAddr.s.num_rnks    = 0x1;
753         cvmx_write_csr (CVMX_DFA_DDR2_ADDR, dfaAddr.u64);
754
755         dfaTmg.u64 =  cvmx_read_csr (CVMX_DFA_DDR2_TMG);
756         dfaTmg.s.ddr2t    = 0;
757         dfaTmg.s.tmrd     = 0x2;
758         dfaTmg.s.caslat   = 0x4 /*400 - 0x3, 500 - 0x4*/;
759         dfaTmg.s.pocas    = 0;
760         dfaTmg.s.addlat   = 0;
761         dfaTmg.s.trcd     = 4   /*400 - 3, 500 - 4*/;
762         dfaTmg.s.trrd     = 2;
763         dfaTmg.s.tras     = 0xB /*400 - 8, 500 - 0xB*/;
764         dfaTmg.s.trp      = 4   /*400 - 3, 500 - 4*/;
765         dfaTmg.s.twr      = 4   /*400 - 3, 500 - 4*/;
766         dfaTmg.s.twtr     = 2   /*400 - 2 */;
767         dfaTmg.s.tfaw     = 0xE /*400 - 0xA, 500 - 0xE*/;
768         dfaTmg.s.r2r_slot = 0;
769         dfaTmg.s.dic      = 0;  /*400 - 0 */
770         dfaTmg.s.dqsn_ena = 0;
771         dfaTmg.s.odt_rtt  = 0;
772         cvmx_write_csr (CVMX_DFA_DDR2_TMG, dfaTmg.u64);
773
774           /* Turn on the DDR2 interface and wait a bit for the hardware to setup. */
775         dfaCfg.s.init = 1;
776         cvmx_write_csr (CVMX_DFA_DDR2_CFG, dfaCfg.u64);
777         cvmx_wait(RLD_INIT_DELAY); // want at least 64K cycles
778     }
779 }
780
781 void write_rld_cfg(rldram_csr_config_t *cfg_ptr)
782 {
783     cvmx_dfa_memcfg0_t    memcfg0;
784     cvmx_dfa_memcfg2_t    memcfg2;
785
786     memcfg0.u64 = cfg_ptr->dfa_memcfg0_base;
787
788     if ((OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)))
789     {
790         uint32_t dfa_memcfg0;
791
792         if (OCTEON_IS_MODEL (OCTEON_CN58XX)) {
793               // Set RLDQK90_RST and RDLCK_RST to reset all three DLLs.
794             memcfg0.s.rldck_rst    = 1;
795             memcfg0.s.rldqck90_rst = 1;
796             cvmx_write_csr(CVMX_DFA_MEMCFG0, memcfg0.u64);
797             ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  clk/qk90 reset\n", (uint32_t) memcfg0.u64);
798             cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), memcfg0.u64);
799
800               // Clear RDLCK_RST while asserting RLDQK90_RST to bring RLDCK DLL out of reset.
801             memcfg0.s.rldck_rst    = 0;
802             memcfg0.s.rldqck90_rst = 1;
803             cvmx_write_csr(CVMX_DFA_MEMCFG0, memcfg0.u64);
804             cvmx_wait(4000000);  /* Wait  */
805             ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  qk90 reset\n", (uint32_t) memcfg0.u64);
806             cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), memcfg0.u64);
807
808               // Clear both RDLCK90_RST and RLDQK90_RST to bring the RLDQK90 DLL out of reset.
809             memcfg0.s.rldck_rst    = 0;
810             memcfg0.s.rldqck90_rst = 0;
811             cvmx_write_csr(CVMX_DFA_MEMCFG0, memcfg0.u64);
812             cvmx_wait(4000000);  /* Wait  */
813             ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  DLL out of reset\n", (uint32_t) memcfg0.u64);
814             cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), memcfg0.u64);
815         }
816
817         //=======================================================================
818         // Now print out the sequence of events:
819         cvmx_write_csr(CVMX_DFA_MEMCFG0, cfg_ptr->dfa_memcfg0_base);
820         ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  port enables\n", cfg_ptr->dfa_memcfg0_base);
821         cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), cfg_ptr->dfa_memcfg0_base);
822         cvmx_wait(4000000);  /* Wait  */
823
824         cvmx_write_csr(CVMX_DFA_MEMCFG1, cfg_ptr->dfa_memcfg1_base);
825         ll_printf("CVMX_DFA_MEMCFG1: 0x%08x\n", cfg_ptr->dfa_memcfg1_base);
826         cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG1 & ~(1ull<<63), cfg_ptr->dfa_memcfg1_base);
827
828         if (cfg_ptr->p0_ena ==1)
829         {
830             cvmx_write_csr(CVMX_DFA_MEMRLD,  cfg_ptr->mrs_dat_p0bunk0);
831             ll_printf("CVMX_DFA_MEMRLD : 0x%08x  p0_ena memrld\n", cfg_ptr->mrs_dat_p0bunk0);
832             cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMRLD & ~(1ull<<63), cfg_ptr->mrs_dat_p0bunk0);
833
834             dfa_memcfg0 = ( cfg_ptr->dfa_memcfg0_base |
835                             (1 << 23) |   // P0_INIT
836                             (1 << 25)     // BUNK_INIT[1:0]=Bunk#0
837                           );
838
839             cvmx_write_csr(CVMX_DFA_MEMCFG0, dfa_memcfg0);
840             ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  p0_init/bunk_init\n", dfa_memcfg0);
841             cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), dfa_memcfg0);
842             cvmx_wait(RLD_INIT_DELAY);
843             ll_printf("Delay.....\n");
844             cvmx_write_csr(CVMX_DFA_MEMCFG0, cfg_ptr->dfa_memcfg0_base);
845             ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  back to base\n", cfg_ptr->dfa_memcfg0_base);
846             cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), cfg_ptr->dfa_memcfg0_base);
847         }
848
849         if (cfg_ptr->p1_ena ==1)
850         {
851             cvmx_write_csr(CVMX_DFA_MEMRLD,  cfg_ptr->mrs_dat_p1bunk0);
852             ll_printf("CVMX_DFA_MEMRLD : 0x%08x  p1_ena memrld\n", cfg_ptr->mrs_dat_p1bunk0);
853             cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMRLD & ~(1ull<<63), cfg_ptr->mrs_dat_p1bunk0);
854
855             dfa_memcfg0 = ( cfg_ptr->dfa_memcfg0_base |
856                             (1 << 24) |   // P1_INIT
857                             (1 << 25)     // BUNK_INIT[1:0]=Bunk#0
858                           );
859             cvmx_write_csr(CVMX_DFA_MEMCFG0, dfa_memcfg0);
860             ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  p1_init/bunk_init\n", dfa_memcfg0);
861             cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), dfa_memcfg0);
862             cvmx_wait(RLD_INIT_DELAY);
863             ll_printf("Delay.....\n");
864             cvmx_write_csr(CVMX_DFA_MEMCFG0, cfg_ptr->dfa_memcfg0_base);
865             ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  back to base\n", cfg_ptr->dfa_memcfg0_base);
866             cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), cfg_ptr->dfa_memcfg0_base);
867         }
868
869         // P0 Bunk#1
870         if ((cfg_ptr->p0_ena ==1) && (cfg_ptr->bunkport == 2))
871         {
872             cvmx_write_csr(CVMX_DFA_MEMRLD,  cfg_ptr->mrs_dat_p0bunk1);
873             ll_printf("CVMX_DFA_MEMRLD : 0x%08x  p0_ena memrld\n", cfg_ptr->mrs_dat_p0bunk1);
874             cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMRLD & ~(1ull<<63), cfg_ptr->mrs_dat_p0bunk1);
875
876             dfa_memcfg0 = ( cfg_ptr->dfa_memcfg0_base |
877                             (1 << 23) |   // P0_INIT
878                             (2 << 25)     // BUNK_INIT[1:0]=Bunk#1
879                           );
880             cvmx_write_csr(CVMX_DFA_MEMCFG0, dfa_memcfg0);
881             ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  p0_init/bunk_init\n", dfa_memcfg0);
882             cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), dfa_memcfg0);
883             cvmx_wait(RLD_INIT_DELAY);
884             ll_printf("Delay.....\n");
885
886             if (cfg_ptr->p1_ena == 1)
887             { // Re-arm Px_INIT if P1-B1 init is required
888                 cvmx_write_csr(CVMX_DFA_MEMCFG0, cfg_ptr->dfa_memcfg0_base);
889                 ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  px_init rearm\n", cfg_ptr->dfa_memcfg0_base);
890                 cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), cfg_ptr->dfa_memcfg0_base);
891             }
892         }
893
894         if ((cfg_ptr->p1_ena == 1) && (cfg_ptr->bunkport == 2))
895         {
896             cvmx_write_csr(CVMX_DFA_MEMRLD,  cfg_ptr->mrs_dat_p1bunk1);
897             ll_printf("CVMX_DFA_MEMRLD : 0x%08x  p1_ena memrld\n", cfg_ptr->mrs_dat_p1bunk1);
898             cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMRLD & ~(1ull<<63), cfg_ptr->mrs_dat_p1bunk1);
899
900             dfa_memcfg0 = ( cfg_ptr->dfa_memcfg0_base |
901                             (1 << 24) |   // P1_INIT
902                             (2 << 25)     // BUNK_INIT[1:0]=10
903                           );
904             cvmx_write_csr(CVMX_DFA_MEMCFG0, dfa_memcfg0);
905             ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  p1_init/bunk_init\n", dfa_memcfg0);
906             cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), dfa_memcfg0);
907         }
908         cvmx_wait(4000000);  // 1/100S, 0.01S, 10mS
909         ll_printf("Delay.....\n");
910
911           /* Enable bunks */
912         dfa_memcfg0 = cfg_ptr->dfa_memcfg0_base |((cfg_ptr->bunkport >= 1) << 25) | ((cfg_ptr->bunkport == 2) << 26);
913         cvmx_write_csr(CVMX_DFA_MEMCFG0, dfa_memcfg0);
914         ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  enable bunks\n", dfa_memcfg0);
915         cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), dfa_memcfg0);
916         cvmx_wait(RLD_INIT_DELAY);
917         ll_printf("Delay.....\n");
918
919           /* Issue a Silo reset by toggling SILRST in memcfg2. */
920         memcfg2.u64 = cvmx_read_csr (CVMX_DFA_MEMCFG2);
921         memcfg2.s.silrst = 1;
922         cvmx_write_csr (CVMX_DFA_MEMCFG2, memcfg2.u64);
923         ll_printf("CVMX_DFA_MEMCFG2: 0x%08x  silo reset start\n", (uint32_t) memcfg2.u64);
924         memcfg2.s.silrst = 0;
925         cvmx_write_csr (CVMX_DFA_MEMCFG2, memcfg2.u64);
926         ll_printf("CVMX_DFA_MEMCFG2: 0x%08x  silo reset done\n", (uint32_t) memcfg2.u64);
927     }
928 }
929