1210284Sjmallett/***********************license start***************
2215990Sjmallett * Copyright (c) 2003-2010  Cavium Networks (support@cavium.com). All rights
3215990Sjmallett * reserved.
4210284Sjmallett *
5210284Sjmallett *
6215990Sjmallett * Redistribution and use in source and binary forms, with or without
7215990Sjmallett * modification, are permitted provided that the following conditions are
8215990Sjmallett * met:
9210284Sjmallett *
10215990Sjmallett *   * Redistributions of source code must retain the above copyright
11215990Sjmallett *     notice, this list of conditions and the following disclaimer.
12210284Sjmallett *
13215990Sjmallett *   * Redistributions in binary form must reproduce the above
14215990Sjmallett *     copyright notice, this list of conditions and the following
15215990Sjmallett *     disclaimer in the documentation and/or other materials provided
16215990Sjmallett *     with the distribution.
17215990Sjmallett
18215990Sjmallett *   * Neither the name of Cavium Networks nor the names of
19215990Sjmallett *     its contributors may be used to endorse or promote products
20215990Sjmallett *     derived from this software without specific prior written
21215990Sjmallett *     permission.
22215990Sjmallett
23215990Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24215990Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25215990Sjmallett * regulations, and may be subject to export or import  regulations in other
26215990Sjmallett * countries.
27215990Sjmallett
28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29215990Sjmallett * AND WITH ALL FAULTS AND CAVIUM  NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR
30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38210284Sjmallett ***********************license end**************************************/
39210284Sjmallett
40210284Sjmallett
41210284Sjmallett
42210284Sjmallett
43210284Sjmallett
44210284Sjmallett
45215990Sjmallett
46210284Sjmallett/**
47210284Sjmallett * @file
48210284Sjmallett *
49210284Sjmallett * Configuration functions for low latency memory.
50210284Sjmallett *
51215990Sjmallett * <hr>$Revision: 52372 $<hr>
52210284Sjmallett */
53210284Sjmallett#include "cvmx-config.h"
54210284Sjmallett#include "cvmx.h"
55210284Sjmallett#include "cvmx-llm.h"
56210284Sjmallett#include "cvmx-sysinfo.h"
57210284Sjmallett#include "cvmx-csr-db.h"
58210284Sjmallett
59210284Sjmallett#define	MIN(a,b) (((a)<(b))?(a):(b))
60210284Sjmallett
61210284Sjmalletttypedef struct
62210284Sjmallett{
63210284Sjmallett    uint32_t dfa_memcfg0_base;
64210284Sjmallett    uint32_t dfa_memcfg1_base;
65210284Sjmallett    uint32_t mrs_dat_p0bunk0;
66210284Sjmallett    uint32_t mrs_dat_p0bunk1;
67210284Sjmallett    uint32_t mrs_dat_p1bunk0;
68210284Sjmallett    uint32_t mrs_dat_p1bunk1;
69210284Sjmallett    uint8_t  p0_ena;
70210284Sjmallett    uint8_t  p1_ena;
71210284Sjmallett    uint8_t  bunkport;
72210284Sjmallett} rldram_csr_config_t;
73210284Sjmallett
74210284Sjmallett
75210284Sjmallett
76210284Sjmallett
77210284Sjmallett
78210284Sjmallettint rld_csr_config_generate(llm_descriptor_t *llm_desc_ptr, rldram_csr_config_t *cfg_ptr);
79210284Sjmallett
80210284Sjmallett
81210284Sjmallettvoid print_rld_cfg(rldram_csr_config_t *cfg_ptr);
82210284Sjmallettvoid write_rld_cfg(rldram_csr_config_t *cfg_ptr);
83210284Sjmallettstatic void cn31xx_dfa_memory_init(void);
84210284Sjmallett
85210284Sjmallettstatic uint32_t process_address_map_str(uint32_t mrs_dat, char *addr_str);
86210284Sjmallett
87210284Sjmallett
88210284Sjmallett
89210284Sjmallett#ifndef CVMX_LLM_NUM_PORTS
90210284Sjmallett#warning WARNING: default CVMX_LLM_NUM_PORTS used.  Defaults deprecated, please set in executive-config.h
91210284Sjmallett#define CVMX_LLM_NUM_PORTS 1
92210284Sjmallett#endif
93210284Sjmallett
94210284Sjmallett
95210284Sjmallett#if (CVMX_LLM_NUM_PORTS != 1) && (CVMX_LLM_NUM_PORTS != 2)
96210284Sjmallett#error "Invalid CVMX_LLM_NUM_PORTS value: must be 1 or 2\n"
97210284Sjmallett#endif
98210284Sjmallett
99210284Sjmallettint cvmx_llm_initialize()
100210284Sjmallett{
101210284Sjmallett    if (cvmx_llm_initialize_desc(NULL) < 0)
102210284Sjmallett        return -1;
103210284Sjmallett
104210284Sjmallett    return 0;
105210284Sjmallett}
106210284Sjmallett
107210284Sjmallett
108210284Sjmallettint cvmx_llm_get_default_descriptor(llm_descriptor_t *llm_desc_ptr)
109210284Sjmallett{
110210284Sjmallett    cvmx_sysinfo_t *sys_ptr;
111210284Sjmallett    sys_ptr = cvmx_sysinfo_get();
112210284Sjmallett
113210284Sjmallett    if (!llm_desc_ptr)
114210284Sjmallett        return -1;
115210284Sjmallett
116210284Sjmallett    memset(llm_desc_ptr, 0, sizeof(llm_descriptor_t));
117210284Sjmallett
118215990Sjmallett    llm_desc_ptr->cpu_hz = cvmx_clock_get_rate(CVMX_CLOCK_CORE);
119210284Sjmallett
120210284Sjmallett    if (sys_ptr->board_type == CVMX_BOARD_TYPE_EBT3000)
121210284Sjmallett    { // N3K->RLD0 Address Swizzle
122210284Sjmallett        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");
123210284Sjmallett        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");
124210284Sjmallett        // N3K->RLD1 Address Swizzle
125210284Sjmallett        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");
126210284Sjmallett        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");
127210284Sjmallett        /* NOTE: The ebt3000 has a strange RLDRAM configuration for validation purposes.  It is not recommended to have
128210284Sjmallett        ** different amounts of memory on different ports as that renders some memory unusable */
129210284Sjmallett        llm_desc_ptr->rld0_bunks = 2;
130210284Sjmallett        llm_desc_ptr->rld1_bunks = 2;
131210284Sjmallett        llm_desc_ptr->rld0_mbytes = 128;          // RLD0: 4x 32Mx9
132210284Sjmallett        llm_desc_ptr->rld1_mbytes = 64;           // RLD1: 2x 16Mx18
133210284Sjmallett    }
134210284Sjmallett    else if (sys_ptr->board_type == CVMX_BOARD_TYPE_EBT5800)
135210284Sjmallett    {
136210284Sjmallett        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");
137210284Sjmallett        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");
138210284Sjmallett        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");
139210284Sjmallett        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");
140210284Sjmallett        llm_desc_ptr->rld0_bunks = 2;
141210284Sjmallett        llm_desc_ptr->rld1_bunks = 2;
142210284Sjmallett        llm_desc_ptr->rld0_mbytes = 128;
143210284Sjmallett        llm_desc_ptr->rld1_mbytes = 128;
144210284Sjmallett        llm_desc_ptr->max_rld_clock_mhz = 400;  /* CN58XX needs a max clock speed for selecting optimal divisor */
145210284Sjmallett    }
146210284Sjmallett    else if (sys_ptr->board_type == CVMX_BOARD_TYPE_EBH3000)
147210284Sjmallett    {
148210284Sjmallett        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");
149210284Sjmallett        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");
150210284Sjmallett        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");
151210284Sjmallett        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");
152210284Sjmallett        llm_desc_ptr->rld0_bunks = 2;
153210284Sjmallett        llm_desc_ptr->rld1_bunks = 2;
154210284Sjmallett        llm_desc_ptr->rld0_mbytes = 128;
155210284Sjmallett        llm_desc_ptr->rld1_mbytes = 128;
156210284Sjmallett    }
157210284Sjmallett    else if (sys_ptr->board_type == CVMX_BOARD_TYPE_NAC38)
158210284Sjmallett    {
159210284Sjmallett        if (sys_ptr->board_rev_major == 1 && sys_ptr->board_rev_minor == 0)
160210284Sjmallett        {
161210284Sjmallett            strcpy(llm_desc_ptr->addr_rld0_fb_str, "22 21 20 00 08 07 06 05 04 13 02 01 03 09 18 17 16 15 14 10 12 11 19");
162210284Sjmallett            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");
163210284Sjmallett            strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 20 00 08 07 06 05 04 13 02 01 03 09 18 17 16 15 14 10 12 11 19");
164210284Sjmallett            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");
165210284Sjmallett            llm_desc_ptr->rld0_bunks = 2;
166210284Sjmallett            llm_desc_ptr->rld1_bunks = 2;
167210284Sjmallett            llm_desc_ptr->rld0_mbytes = 128;
168210284Sjmallett            llm_desc_ptr->rld1_mbytes = 128;
169210284Sjmallett        }
170210284Sjmallett        else
171210284Sjmallett        {   /* Asus new recommendation  */
172210284Sjmallett            strcpy(llm_desc_ptr->addr_rld0_fb_str, "22 21 09 11 04 06 05 08 15 20 16 18 12 13 00 01 07 02 19 17 10 14 03");
173210284Sjmallett            strcpy(llm_desc_ptr->addr_rld0_bb_str, "22 21 11 09 00 01 07 02 19 17 10 14 03 13 04 06 05 08 15 20 16 18 12");
174210284Sjmallett            strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 08 13 14 00 04 12 16 11 19 10 07 02 01 05 03 06 17 18 20 09 15");
175210284Sjmallett            strcpy(llm_desc_ptr->addr_rld1_bb_str, "22 21 13 08 01 05 03 06 17 18 20 09 15 02 14 00 04 12 16 11 19 10 07");
176210284Sjmallett            llm_desc_ptr->rld0_bunks = 2;
177210284Sjmallett            llm_desc_ptr->rld1_bunks = 2;
178210284Sjmallett            llm_desc_ptr->rld0_mbytes = 128;
179210284Sjmallett            llm_desc_ptr->rld1_mbytes = 128;
180210284Sjmallett        }
181210284Sjmallett    }
182210284Sjmallett    else if (sys_ptr->board_type == CVMX_BOARD_TYPE_THUNDER)
183210284Sjmallett    {
184210284Sjmallett
185210284Sjmallett        if (sys_ptr->board_rev_major >= 4)
186210284Sjmallett        {
187210284Sjmallett            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");
188210284Sjmallett            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");
189210284Sjmallett            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");
190210284Sjmallett            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");
191210284Sjmallett        }
192210284Sjmallett        else
193210284Sjmallett        {
194210284Sjmallett            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");
195210284Sjmallett            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");
196210284Sjmallett            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");
197210284Sjmallett            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");
198210284Sjmallett        }
199210284Sjmallett
200210284Sjmallett        llm_desc_ptr->rld0_bunks = 2;
201210284Sjmallett        llm_desc_ptr->rld1_bunks = 2;
202210284Sjmallett        llm_desc_ptr->rld0_mbytes = 128;
203210284Sjmallett        llm_desc_ptr->rld1_mbytes = 128;
204210284Sjmallett    }
205210284Sjmallett    else if (sys_ptr->board_type == CVMX_BOARD_TYPE_NICPRO2)
206210284Sjmallett    {
207210284Sjmallett        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");
208210284Sjmallett        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");
209210284Sjmallett        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");
210210284Sjmallett        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");
211210284Sjmallett        llm_desc_ptr->rld0_bunks = 2;
212210284Sjmallett        llm_desc_ptr->rld1_bunks = 2;
213210284Sjmallett        llm_desc_ptr->rld0_mbytes = 256;
214210284Sjmallett        llm_desc_ptr->rld1_mbytes = 256;
215210284Sjmallett        llm_desc_ptr->max_rld_clock_mhz = 400;  /* CN58XX needs a max clock speed for selecting optimal divisor */
216210284Sjmallett    }
217210284Sjmallett    else if (sys_ptr->board_type == CVMX_BOARD_TYPE_EBH3100)
218210284Sjmallett    {
219210284Sjmallett        /* CN31xx DFA memory is DDR based, so it is completely different from the CN38XX DFA memory */
220210284Sjmallett        llm_desc_ptr->rld0_bunks = 1;
221210284Sjmallett        llm_desc_ptr->rld0_mbytes = 256;
222210284Sjmallett    }
223210284Sjmallett    else if (sys_ptr->board_type == CVMX_BOARD_TYPE_KBP)
224210284Sjmallett    {
225210284Sjmallett        strcpy(llm_desc_ptr->addr_rld0_fb_str, "");
226210284Sjmallett        strcpy(llm_desc_ptr->addr_rld0_bb_str, "");
227210284Sjmallett        llm_desc_ptr->rld0_bunks = 0;
228210284Sjmallett        llm_desc_ptr->rld0_mbytes = 0;
229210284Sjmallett        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");
230210284Sjmallett        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");
231210284Sjmallett        llm_desc_ptr->rld1_bunks = 2;
232210284Sjmallett        llm_desc_ptr->rld1_mbytes = 64;
233210284Sjmallett    }
234210284Sjmallett    else
235210284Sjmallett    {
236210284Sjmallett        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);
237210284Sjmallett        return -1;
238210284Sjmallett    }
239210284Sjmallett
240210284Sjmallett    return(0);
241210284Sjmallett}
242210284Sjmallett
243210284Sjmallettint cvmx_llm_initialize_desc(llm_descriptor_t *llm_desc_ptr)
244210284Sjmallett{
245210284Sjmallett    cvmx_sysinfo_t *sys_ptr;
246210284Sjmallett    sys_ptr = cvmx_sysinfo_get();
247210284Sjmallett    llm_descriptor_t default_llm_desc;
248210284Sjmallett
249210284Sjmallett    memset(&default_llm_desc, 0, sizeof(default_llm_desc));
250210284Sjmallett    if (sys_ptr->board_type == CVMX_BOARD_TYPE_SIM)
251210284Sjmallett    {
252210284Sjmallett        cvmx_dprintf("Skipping llm configuration for simulator.\n");
253210284Sjmallett        return 0;
254210284Sjmallett    }
255210284Sjmallett
256210284Sjmallett    if (sys_ptr->board_type == CVMX_BOARD_TYPE_EBH3100)
257210284Sjmallett    {
258210284Sjmallett        /* CN31xx DFA memory is DDR based, so it is completely different from the CN38XX DFA memory
259210284Sjmallett        ** config descriptors are not supported yet.*/
260210284Sjmallett        cvmx_dprintf("Warning: preliminary DFA memory configuration\n");
261210284Sjmallett        cn31xx_dfa_memory_init();
262210284Sjmallett        return(256*1024*1024);
263210284Sjmallett    }
264210284Sjmallett
265210284Sjmallett    /* If no descriptor passed, generate default descriptor based on board type.
266210284Sjmallett    ** Fail if no default available for given board type
267210284Sjmallett    */
268210284Sjmallett    if (!llm_desc_ptr)
269210284Sjmallett    {
270210284Sjmallett        /* Get default descriptor */
271210284Sjmallett        if (0 > cvmx_llm_get_default_descriptor(&default_llm_desc))
272210284Sjmallett            return -1;
273210284Sjmallett
274210284Sjmallett        /* Disable second port depending on CVMX config */
275210284Sjmallett        if (CVMX_LLM_NUM_PORTS == 1)
276210284Sjmallett	  default_llm_desc.rld0_bunks = 0;        // For single port: Force RLD0(P1) to appear EMPTY
277210284Sjmallett
278210284Sjmallett        cvmx_dprintf("Using default LLM configuration for board %s (%d)\n", cvmx_board_type_to_string(sys_ptr->board_type),  sys_ptr->board_type);
279210284Sjmallett
280210284Sjmallett        llm_desc_ptr = &default_llm_desc;
281210284Sjmallett    }
282210284Sjmallett
283210284Sjmallett
284210284Sjmallett
285210284Sjmallett    rldram_csr_config_t ebt3000_rld_cfg;
286210284Sjmallett    if (!rld_csr_config_generate(llm_desc_ptr, &ebt3000_rld_cfg))
287210284Sjmallett    {
288210284Sjmallett        cvmx_dprintf("Configuring %d llm port(s).\n", !!llm_desc_ptr->rld0_bunks + !!llm_desc_ptr->rld1_bunks);
289210284Sjmallett        write_rld_cfg(&ebt3000_rld_cfg);
290210284Sjmallett    }
291210284Sjmallett    else
292210284Sjmallett    {
293210284Sjmallett        cvmx_dprintf("Error creating rldram configuration\n");
294210284Sjmallett        return(-1);
295210284Sjmallett    }
296210284Sjmallett
297210284Sjmallett    /* Compute how much memory is configured
298210284Sjmallett    ** Memory is interleaved, so if one port has more than the other some memory is not usable */
299210284Sjmallett
300210284Sjmallett    /* If both ports are enabled, handle the case where one port has more than the other.
301210284Sjmallett    ** This is an unusual and not recommended configuration that exists on the ebt3000 board */
302210284Sjmallett    if (!!llm_desc_ptr->rld0_bunks && !!llm_desc_ptr->rld1_bunks)
303210284Sjmallett        llm_desc_ptr->rld0_mbytes = llm_desc_ptr->rld1_mbytes = MIN(llm_desc_ptr->rld0_mbytes, llm_desc_ptr->rld1_mbytes);
304210284Sjmallett
305210284Sjmallett    return(((!!llm_desc_ptr->rld0_bunks) * llm_desc_ptr->rld0_mbytes
306210284Sjmallett          + (!!llm_desc_ptr->rld1_bunks) * llm_desc_ptr->rld1_mbytes) * 1024*1024);
307210284Sjmallett}
308210284Sjmallett
309210284Sjmallett//======================
310210284Sjmallett// SUPPORT FUNCTIONS:
311210284Sjmallett//======================
312210284Sjmallett//======================================================================
313210284Sjmallett// Extracts srcvec[srcbitpos] and places it in return int (bit[0])
314210284Sjmallettint bit_extract ( int srcvec,         // source word (to extract)
315210284Sjmallett                  int srcbitpos       // source bit position
316210284Sjmallett                )
317210284Sjmallett{
318210284Sjmallett    return(((1 << srcbitpos) & srcvec) >> srcbitpos);
319210284Sjmallett}
320210284Sjmallett//======================================================================
321210284Sjmallett// Inserts srcvec[0] into dstvec[dstbitpos] (without affecting other bits)
322210284Sjmallettint bit_insert ( int srcvec,           // srcvec[0] = bit to be inserted
323210284Sjmallett                 int dstbitpos,        // Bit position to insert into returned int
324210284Sjmallett                 int dstvec            // dstvec (destination vector)
325210284Sjmallett               )
326210284Sjmallett{
327210284Sjmallett    return((srcvec << dstbitpos) | dstvec);      // Shift bit to insert into bit position/OR with accumulated number
328210284Sjmallett}
329210284Sjmallett//======================================================================
330210284Sjmallett
331210284Sjmallettint rld_csr_config_generate(llm_descriptor_t *llm_desc_ptr, rldram_csr_config_t *cfg_ptr)
332210284Sjmallett{
333210284Sjmallett    char *addr_rld0_fb_str;
334210284Sjmallett    char *addr_rld0_bb_str;
335210284Sjmallett    char *addr_rld1_fb_str;
336210284Sjmallett    char *addr_rld1_bb_str;
337210284Sjmallett    int eclk_ps;
338210284Sjmallett    int mtype = 0;                           // MTYPE (0: RLDRAM/1: FCRAM
339210284Sjmallett    int trcmin = 20;                         // tRC(min) - from RLDRAM data sheet
340210284Sjmallett    int trc_cyc;                             // TRC(cyc)
341210284Sjmallett    int trc_mod;
342210284Sjmallett    int trl_cyc;                             // TRL(cyc)
343210284Sjmallett    int twl_cyc;                             // TWL(cyc)
344210284Sjmallett    int tmrsc_cyc = 6;                       // tMRSC(cyc)  [2-7]
345210284Sjmallett    int mclk_ps;                             // DFA Memory Clock(in ps) = 2x eclk
346210284Sjmallett    int rldcfg = 99;                         // RLDRAM-II CFG (1,2,3)
347210284Sjmallett    int mrs_odt = 0;                         // RLDRAM MRS A[9]=ODT (default)
348210284Sjmallett    int mrs_impmatch = 0;                    // RLDRAM MRS A[8]=Impedance Matching (default)
349210284Sjmallett    int mrs_dllrst = 1;                      // RLDRAM MRS A[7]=DLL Reset (default)
350210284Sjmallett    uint32_t mrs_dat;
351210284Sjmallett    int mrs_dat_p0bunk0 = 0;                 // MRS Register Data After Address Map (for Port0 Bunk0)
352210284Sjmallett    int mrs_dat_p0bunk1 = 0;                 // MRS Register Data After Address Map (for Port0 Bunk1)
353210284Sjmallett    int mrs_dat_p1bunk0 = 0;                 // MRS Register Data After Address Map (for Port1 Bunk0)
354210284Sjmallett    int mrs_dat_p1bunk1 = 0;                 // MRS Register Data After Address Map (for Port1 Bunk1)
355210284Sjmallett    int p0_ena = 0;                          // DFA Port#0 Enabled
356210284Sjmallett    int p1_ena = 0;                          // DFA Port#1 Enabled
357210284Sjmallett    int memport = 0;                       // Memory(MB) per Port [MAX=512]
358210284Sjmallett    int membunk;                             // Memory(MB) per Bunk
359210284Sjmallett    int bunkport = 0;                        // Bunks/Port [1/2]
360210284Sjmallett    int pbunk = 0;                               // Physical Bunk(or Rank) encoding for address bit
361210284Sjmallett    int tref_ms = 32;                        // tREF(ms) (RLDRAM-II overall device refresh interval
362210284Sjmallett    int trefi_ns;                            // tREFI(ns) = tREF(ns)/#rows/bank
363210284Sjmallett    int rows = 8;                            // #rows/bank (K) typically 8K
364210284Sjmallett    int ref512int;
365210284Sjmallett    int ref512mod;
366210284Sjmallett    int tskw_cyc = 0;
367210284Sjmallett    int fprch = 1;
368210284Sjmallett    int bprch = 0;
369210284Sjmallett    int dfa_memcfg0_base = 0;
370210284Sjmallett    int dfa_memcfg1_base = 0;
371210284Sjmallett    int tbl = 1;                             // tBL (1: 2-burst /2: 4-burst)
372210284Sjmallett    int rw_dly;
373210284Sjmallett    int wr_dly;
374210284Sjmallett    int r2r = 1;
375210284Sjmallett    int sil_lat = 1;
376210284Sjmallett    int clkdiv = 2;  /* CN38XX is fixed at 2, CN58XX supports 2,3,4 */
377210284Sjmallett    int clkdiv_enc = 0x0;  /* Encoded clock divisor, only used for CN58XX */
378210284Sjmallett
379210284Sjmallett    if (!llm_desc_ptr)
380210284Sjmallett        return -1;
381210284Sjmallett
382210284Sjmallett    /* Setup variables from descriptor */
383210284Sjmallett
384210284Sjmallett    addr_rld0_fb_str = llm_desc_ptr->addr_rld0_fb_str;
385210284Sjmallett    addr_rld0_bb_str = llm_desc_ptr->addr_rld0_bb_str;
386210284Sjmallett    addr_rld1_fb_str = llm_desc_ptr->addr_rld1_fb_str;
387210284Sjmallett    addr_rld1_bb_str = llm_desc_ptr->addr_rld1_bb_str;
388210284Sjmallett
389210284Sjmallett    p0_ena = !!llm_desc_ptr->rld1_bunks;        // NOTE: P0 == RLD1
390210284Sjmallett    p1_ena = !!llm_desc_ptr->rld0_bunks;        // NOTE: P1 == RLD0
391210284Sjmallett
392210284Sjmallett    // Massage the code, so that if the user had imbalanced memory per-port (or imbalanced bunks/port), we
393210284Sjmallett    // at least try to configure 'workable' memory.
394210284Sjmallett    if (p0_ena && p1_ena)  // IF BOTH PORTS Enabled (imbalanced memory), select smaller of BOTH
395210284Sjmallett    {
396210284Sjmallett        memport = MIN(llm_desc_ptr->rld0_mbytes, llm_desc_ptr->rld1_mbytes);
397210284Sjmallett        bunkport = MIN(llm_desc_ptr->rld0_bunks, llm_desc_ptr->rld1_bunks);
398210284Sjmallett    }
399210284Sjmallett    else if (p0_ena) // P0=RLD1 Enabled
400210284Sjmallett    {
401210284Sjmallett        memport = llm_desc_ptr->rld1_mbytes;
402210284Sjmallett        bunkport = llm_desc_ptr->rld1_bunks;
403210284Sjmallett    }
404210284Sjmallett    else if (p1_ena) // P1=RLD0 Enabled
405210284Sjmallett    {
406210284Sjmallett        memport = llm_desc_ptr->rld0_mbytes;
407210284Sjmallett        bunkport = llm_desc_ptr->rld0_bunks;
408210284Sjmallett    }
409210284Sjmallett    else
410210284Sjmallett        return -1;
411210284Sjmallett
412210284Sjmallett    uint32_t eclk_mhz = llm_desc_ptr->cpu_hz/1000000;
413210284Sjmallett
414210284Sjmallett
415210284Sjmallett
416210284Sjmallett    /* Tweak skew based on cpu clock */
417210284Sjmallett    if (eclk_mhz <= 367)
418210284Sjmallett    {
419210284Sjmallett        tskw_cyc = 0;
420210284Sjmallett    }
421210284Sjmallett    else
422210284Sjmallett    {
423210284Sjmallett        tskw_cyc = 1;
424210284Sjmallett    }
425210284Sjmallett
426210284Sjmallett    /* Determine clock divider ratio (only required for CN58XX) */
427210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN58XX))
428210284Sjmallett    {
429210284Sjmallett        uint32_t max_llm_clock_mhz = llm_desc_ptr->max_rld_clock_mhz;
430210284Sjmallett        if (!max_llm_clock_mhz)
431210284Sjmallett        {
432210284Sjmallett            max_llm_clock_mhz = 400;  /* Default to 400 MHz */
433210284Sjmallett            cvmx_dprintf("Warning, using default max_rld_clock_mhz of: %lu MHz\n", (unsigned long)max_llm_clock_mhz);
434210284Sjmallett        }
435210284Sjmallett
436210284Sjmallett        /* Compute the divisor, and round up */
437210284Sjmallett        clkdiv = eclk_mhz/max_llm_clock_mhz;
438210284Sjmallett        if (clkdiv * max_llm_clock_mhz < eclk_mhz)
439210284Sjmallett            clkdiv++;
440210284Sjmallett
441210284Sjmallett        if (clkdiv > 4)
442210284Sjmallett        {
443210284Sjmallett            cvmx_dprintf("ERROR: CN58XX LLM clock divisor out of range\n");
444210284Sjmallett            goto TERMINATE;
445210284Sjmallett        }
446210284Sjmallett        if (clkdiv < 2)
447210284Sjmallett            clkdiv = 2;
448210284Sjmallett
449210284Sjmallett        cvmx_dprintf("Using llm clock divisor: %d, llm clock is: %lu MHz\n", clkdiv, (unsigned long)eclk_mhz/clkdiv);
450210284Sjmallett        /* Translate divisor into bit encoding for register */
451210284Sjmallett        /* 0 -> div 2
452210284Sjmallett        ** 1 -> reserved
453210284Sjmallett        ** 2 -> div 3
454210284Sjmallett        ** 3 -> div 4
455210284Sjmallett        */
456210284Sjmallett        if (clkdiv == 2)
457210284Sjmallett            clkdiv_enc = 0;
458210284Sjmallett        else
459210284Sjmallett            clkdiv_enc = clkdiv - 1;
460210284Sjmallett
461210284Sjmallett    /* Odd divisor needs sil_lat to be 2 */
462210284Sjmallett        if (clkdiv == 0x3)
463210284Sjmallett            sil_lat = 2;
464210284Sjmallett
465210284Sjmallett        /* Increment tskw for high clock speeds */
466215990Sjmallett        if ((unsigned long)eclk_mhz/clkdiv >= 375)
467210284Sjmallett            tskw_cyc += 1;
468210284Sjmallett    }
469210284Sjmallett
470210284Sjmallett    eclk_ps = (1000000+(eclk_mhz-1)) / eclk_mhz;  // round up if nonzero remainder
471210284Sjmallett    //=======================================================================
472210284Sjmallett
473210284Sjmallett    //=======================================================================
474210284Sjmallett    // Now, Query User for DFA Memory Type
475210284Sjmallett    if (mtype != 0)
476210284Sjmallett    {
477210284Sjmallett        goto TERMINATE;         // Complete this code for FCRAM usage on N3K-P2
478210284Sjmallett    }
479210284Sjmallett    //=======================================================================
480210284Sjmallett    // Query what the tRC(min) value is from the data sheets
481210284Sjmallett    //=======================================================================
482210284Sjmallett    // Now determine the Best CFG based on Memory clock(ps) and tRCmin(ns)
483210284Sjmallett    mclk_ps = eclk_ps * clkdiv;
484210284Sjmallett    trc_cyc = ((trcmin * 1000)/mclk_ps);
485210284Sjmallett    trc_mod = ((trcmin * 1000) % mclk_ps);
486210284Sjmallett    // If remainder exists, bump up to the next integer multiple
487210284Sjmallett    if (trc_mod != 0)
488210284Sjmallett    {
489210284Sjmallett        trc_cyc = trc_cyc + 1;
490210284Sjmallett    }
491210284Sjmallett    // If tRC is now ODD, then bump it to the next EVEN integer (RLDRAM-II does not support odd tRC values at this time).
492210284Sjmallett    if (trc_cyc & 1)
493210284Sjmallett    {
494210284Sjmallett        trc_cyc = trc_cyc + 1;           // Bump it to an even #
495210284Sjmallett    }
496210284Sjmallett    // RLDRAM CFG Range Check: If the computed trc_cyc is less than 4, then set it to min CFG1 [tRC=4]
497210284Sjmallett    if (trc_cyc < 4)
498210284Sjmallett    {
499210284Sjmallett        trc_cyc = 4;             // If computed trc_cyc < 4 then clamp to 4
500210284Sjmallett    }
501210284Sjmallett    else if (trc_cyc > 8)
502210284Sjmallett    {    // If the computed trc_cyc > 8, then report an error (because RLDRAM cannot support a tRC>8
503210284Sjmallett        goto TERMINATE;
504210284Sjmallett    }
505210284Sjmallett    // Assuming all is ok(up to here)
506210284Sjmallett    // 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
507210284Sjmallett    // the RLDRAM valid CFG range values.
508210284Sjmallett    trl_cyc = trc_cyc;                 // tRL = tRC (for RLDRAM=II)
509210284Sjmallett    twl_cyc = trl_cyc + 1;             // tWL = tRL + 1 (for RLDRAM-II)
510210284Sjmallett    // NOTE: RLDRAM-II (as of 4/25/05) only have 3 supported CFG encodings:
511210284Sjmallett    if (trc_cyc == 4)
512210284Sjmallett    {
513210284Sjmallett        rldcfg = 1;           // CFG #1 (tRL=4/tRC=4/tWL=5)
514210284Sjmallett    }
515210284Sjmallett    else if (trc_cyc == 6)
516210284Sjmallett    {
517210284Sjmallett        rldcfg = 2;           // CFG #2 (tRL=6/tRC=6/tWL=7)
518210284Sjmallett    }
519210284Sjmallett    else if (trc_cyc == 8)
520210284Sjmallett    {
521210284Sjmallett        rldcfg = 3;           // CFG #3 (tRL=8/tRC=8/tWL=9)
522210284Sjmallett    }
523210284Sjmallett    else
524210284Sjmallett    {
525210284Sjmallett        goto TERMINATE;
526210284Sjmallett    }
527210284Sjmallett    //=======================================================================
528210284Sjmallett    mrs_dat = ( (mrs_odt << 9) | (mrs_impmatch << 8) | (mrs_dllrst << 7) | rldcfg );
529210284Sjmallett    //=======================================================================
530210284Sjmallett    // If there is only a single bunk, then skip over address mapping queries (which are not required)
531210284Sjmallett    if (bunkport == 1)
532210284Sjmallett    {
533210284Sjmallett        goto CALC_PBUNK;
534210284Sjmallett    }
535210284Sjmallett
536210284Sjmallett    /* Process the address mappings */
537210284Sjmallett    /* Note that that RLD0 pins corresponds to Port#1, and
538210284Sjmallett    **                RLD1 pins corresponds to Port#0.
539210284Sjmallett    */
540210284Sjmallett    mrs_dat_p1bunk0 = process_address_map_str(mrs_dat, addr_rld0_fb_str);
541210284Sjmallett    mrs_dat_p1bunk1 = process_address_map_str(mrs_dat, addr_rld0_bb_str);
542210284Sjmallett    mrs_dat_p0bunk0 = process_address_map_str(mrs_dat, addr_rld1_fb_str);
543210284Sjmallett    mrs_dat_p0bunk1 = process_address_map_str(mrs_dat, addr_rld1_bb_str);
544210284Sjmallett
545210284Sjmallett
546210284Sjmallett    //=======================================================================
547210284Sjmallett    CALC_PBUNK:
548210284Sjmallett    // Determine the PBUNK field (based on Memory/Bunk)
549210284Sjmallett    // This determines the addr bit used to distinguish when crossing a bunk.
550210284Sjmallett    // NOTE: For RLDRAM, the bunk bit is extracted from 'a' programmably selected high
551210284Sjmallett    // order addr bit. [linear address per-bunk]
552210284Sjmallett    if (bunkport == 2)
553210284Sjmallett    {
554210284Sjmallett        membunk = (memport / 2);
555210284Sjmallett    }
556210284Sjmallett    else
557210284Sjmallett    {
558210284Sjmallett        membunk = memport;
559210284Sjmallett    }
560210284Sjmallett    if (membunk == 16)
561210284Sjmallett    {       // 16MB/bunk MA[19]
562210284Sjmallett        pbunk = 0;
563210284Sjmallett    }
564210284Sjmallett    else if (membunk == 32)
565210284Sjmallett    {  // 32MB/bunk MA[20]
566210284Sjmallett        pbunk = 1;
567210284Sjmallett    }
568210284Sjmallett    else if (membunk == 64)
569210284Sjmallett    {  // 64MB/bunk MA[21]
570210284Sjmallett        pbunk = 2;
571210284Sjmallett    }
572210284Sjmallett    else if (membunk == 128)
573210284Sjmallett    { // 128MB/bunk MA[22]
574210284Sjmallett        pbunk = 3;
575210284Sjmallett    }
576210284Sjmallett    else if (membunk == 256)
577210284Sjmallett    { // 256MB/bunk MA[23]
578210284Sjmallett        pbunk = 4;
579210284Sjmallett    }
580210284Sjmallett    else if (membunk == 512)
581210284Sjmallett    { // 512MB/bunk
582210284Sjmallett    }
583210284Sjmallett    //=======================================================================
584210284Sjmallett    //=======================================================================
585210284Sjmallett    //=======================================================================
586210284Sjmallett    // Now determine N3K REFINT
587210284Sjmallett    trefi_ns = (tref_ms * 1000 * 1000) / (rows * 1024);
588210284Sjmallett    ref512int = ((trefi_ns * 1000) / (eclk_ps * 512));
589210284Sjmallett    ref512mod = ((trefi_ns * 1000) % (eclk_ps * 512));
590210284Sjmallett    //=======================================================================
591210284Sjmallett    // Ask about tSKW
592210284Sjmallett#if 0
593210284Sjmallett    if (tskw_ps ==  0)
594210284Sjmallett    {
595210284Sjmallett        tskw_cyc = 0;
596210284Sjmallett    }
597210284Sjmallett    else
598210284Sjmallett    { // CEILING function
599210284Sjmallett        tskw_cyc = (tskw_ps / eclk_ps);
600210284Sjmallett        tskw_mod = (tskw_ps % eclk_ps);
601210284Sjmallett        if (tskw_mod != 0)
602210284Sjmallett        {  // If there's a remainder - then bump to next (+1)
603210284Sjmallett            tskw_cyc = tskw_cyc + 1;
604210284Sjmallett        }
605210284Sjmallett    }
606210284Sjmallett#endif
607210284Sjmallett    if (tskw_cyc > 3)
608210284Sjmallett    {
609210284Sjmallett        goto TERMINATE;
610210284Sjmallett    }
611210284Sjmallett
612210284Sjmallett    tbl = 1;        // BLEN=2 (ALWAYs for RLDRAM)
613210284Sjmallett    //=======================================================================
614210284Sjmallett    // RW_DLY = (ROUND_UP{[[(TRL+TBL)*2 + tSKW + BPRCH] + 1] / 2}) - tWL
615210284Sjmallett    rw_dly = ((((trl_cyc + tbl) * 2 + tskw_cyc + bprch) + 1) / 2);
616210284Sjmallett    if (rw_dly & 1)
617210284Sjmallett    { // If it's ODD then round up
618210284Sjmallett        rw_dly = rw_dly + 1;
619210284Sjmallett    }
620210284Sjmallett    rw_dly = rw_dly - twl_cyc +1 ;
621210284Sjmallett    if (rw_dly < 0)
622210284Sjmallett    { // range check - is it positive
623210284Sjmallett        goto TERMINATE;
624210284Sjmallett    }
625210284Sjmallett    //=======================================================================
626210284Sjmallett    // WR_DLY = (ROUND_UP[[(tWL + tBL)*2 - tSKW + FPRCH] / 2]) - tRL
627210284Sjmallett    wr_dly = (((twl_cyc + tbl) * 2 - tskw_cyc + fprch) / 2);
628210284Sjmallett    if (wr_dly & 1)
629210284Sjmallett    { // If it's ODD then round up
630210284Sjmallett        wr_dly = wr_dly + 1;
631210284Sjmallett    }
632210284Sjmallett    wr_dly = wr_dly - trl_cyc + 1;
633210284Sjmallett    if (wr_dly < 0)
634210284Sjmallett    { // range check - is it positive
635210284Sjmallett        goto TERMINATE;
636210284Sjmallett    }
637210284Sjmallett
638210284Sjmallett
639210284Sjmallett    dfa_memcfg0_base = 0;
640210284Sjmallett    dfa_memcfg0_base = ( p0_ena |
641210284Sjmallett                         (p1_ena << 1) |
642210284Sjmallett                         (mtype << 3) |
643210284Sjmallett                         (sil_lat << 4) |
644210284Sjmallett                         (rw_dly << 6) |
645210284Sjmallett                         (wr_dly << 10) |
646210284Sjmallett                         (fprch << 14) |
647210284Sjmallett                         (bprch << 16) |
648210284Sjmallett                         (0 << 18) |         // BLEN=0(2-burst for RLDRAM)
649210284Sjmallett                         (pbunk << 19) |
650210284Sjmallett                         (r2r << 22) |       // R2R=1
651210284Sjmallett    			 (clkdiv_enc << 28 )
652210284Sjmallett                       );
653210284Sjmallett
654210284Sjmallett
655210284Sjmallett    dfa_memcfg1_base = 0;
656210284Sjmallett    dfa_memcfg1_base = ( ref512int |
657210284Sjmallett                         (tskw_cyc << 4) |
658210284Sjmallett                         (trl_cyc << 8) |
659210284Sjmallett                         (twl_cyc << 12) |
660210284Sjmallett                         (trc_cyc << 16) |
661210284Sjmallett                         (tmrsc_cyc << 20)
662210284Sjmallett                       );
663210284Sjmallett
664210284Sjmallett
665210284Sjmallett
666210284Sjmallett
667210284Sjmallett    cfg_ptr->dfa_memcfg0_base = dfa_memcfg0_base;
668210284Sjmallett    cfg_ptr->dfa_memcfg1_base = dfa_memcfg1_base;
669210284Sjmallett    cfg_ptr->mrs_dat_p0bunk0 =  mrs_dat_p0bunk0;
670210284Sjmallett    cfg_ptr->mrs_dat_p1bunk0 =  mrs_dat_p1bunk0;
671210284Sjmallett    cfg_ptr->mrs_dat_p0bunk1 =  mrs_dat_p0bunk1;
672210284Sjmallett    cfg_ptr->mrs_dat_p1bunk1 =  mrs_dat_p1bunk1;
673210284Sjmallett    cfg_ptr->p0_ena =           p0_ena;
674210284Sjmallett    cfg_ptr->p1_ena =           p1_ena;
675210284Sjmallett    cfg_ptr->bunkport =         bunkport;
676210284Sjmallett    //=======================================================================
677210284Sjmallett
678210284Sjmallett    return(0);
679210284Sjmallett    TERMINATE:
680210284Sjmallett    return(-1);
681210284Sjmallett
682210284Sjmallett}
683210284Sjmallett
684210284Sjmallett
685210284Sjmallett
686210284Sjmallettstatic uint32_t process_address_map_str(uint32_t mrs_dat, char *addr_str)
687210284Sjmallett{
688210284Sjmallett    int count = 0;
689210284Sjmallett    int amap [23];
690210284Sjmallett    uint32_t new_mrs_dat = 0;
691210284Sjmallett
692210284Sjmallett//    cvmx_dprintf("mrs_dat: 0x%x, str: %x\n", mrs_dat, addr_str);
693210284Sjmallett    char *charptr = strtok(addr_str," ");
694210284Sjmallett    while ((charptr != NULL) & (count <= 22))
695210284Sjmallett    {
696210284Sjmallett        amap[22-count] = atoi(charptr);         // Assign the AMAP Array
697210284Sjmallett        charptr = strtok(NULL," ");             // Get Next char string (which represents next addr bit mapping)
698210284Sjmallett        count++;
699210284Sjmallett    }
700210284Sjmallett    // Now do the bit swap of MRSDAT (based on address mapping)
701210284Sjmallett    uint32_t mrsdat_bit;
702210284Sjmallett    for (count=0;count<=22;count++)
703210284Sjmallett    {
704210284Sjmallett        mrsdat_bit = bit_extract(mrs_dat, count);
705210284Sjmallett        new_mrs_dat = bit_insert(mrsdat_bit, amap[count], new_mrs_dat);
706210284Sjmallett    }
707210284Sjmallett
708210284Sjmallett    return new_mrs_dat;
709210284Sjmallett}
710210284Sjmallett
711210284Sjmallett
712210284Sjmallett//#define PRINT_LLM_CONFIG
713210284Sjmallett#ifdef PRINT_LLM_CONFIG
714210284Sjmallett#define ll_printf printf
715210284Sjmallett#else
716210284Sjmallett#define ll_printf(...)
717210284Sjmallett#define cvmx_csr_db_decode(...)
718210284Sjmallett#endif
719210284Sjmallett
720210284Sjmallettstatic void cn31xx_dfa_memory_init(void)
721210284Sjmallett{
722210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN31XX))
723210284Sjmallett    {
724210284Sjmallett        cvmx_dfa_ddr2_cfg_t  dfaCfg;
725210284Sjmallett        cvmx_dfa_eclkcfg_t   dfaEcklCfg;
726210284Sjmallett        cvmx_dfa_ddr2_addr_t dfaAddr;
727210284Sjmallett        cvmx_dfa_ddr2_tmg_t  dfaTmg;
728210284Sjmallett        cvmx_dfa_ddr2_pll_t  dfaPll;
729210284Sjmallett        int mem_freq_hz = 533*1000000;
730210284Sjmallett        int ref_freq_hz = cvmx_sysinfo_get()->dfa_ref_clock_hz;
731210284Sjmallett        if (!ref_freq_hz)
732210284Sjmallett            ref_freq_hz = 33*1000000;
733210284Sjmallett
734210284Sjmallett        cvmx_dprintf ("Configuring DFA memory for %d MHz operation.\n",mem_freq_hz/1000000);
735210284Sjmallett
736210284Sjmallett          /* Turn on the DFA memory port. */
737210284Sjmallett        dfaCfg.u64 = cvmx_read_csr (CVMX_DFA_DDR2_CFG);
738210284Sjmallett        dfaCfg.s.prtena = 1;
739210284Sjmallett        cvmx_write_csr (CVMX_DFA_DDR2_CFG, dfaCfg.u64);
740210284Sjmallett
741210284Sjmallett          /* Start the PLL alignment sequence */
742210284Sjmallett        dfaPll.u64 = 0;
743210284Sjmallett        dfaPll.s.pll_ratio  = mem_freq_hz/ref_freq_hz         /*400Mhz / 33MHz*/;
744210284Sjmallett        dfaPll.s.pll_div2   = 1              /*400 - 1 */;
745210284Sjmallett        dfaPll.s.pll_bypass = 0;
746210284Sjmallett        cvmx_write_csr (CVMX_DFA_DDR2_PLL, dfaPll.u64);
747210284Sjmallett
748210284Sjmallett        dfaPll.s.pll_init = 1;
749210284Sjmallett        cvmx_write_csr (CVMX_DFA_DDR2_PLL, dfaPll.u64);
750210284Sjmallett
751210284Sjmallett        cvmx_wait (RLD_INIT_DELAY); //want 150uS
752210284Sjmallett        dfaPll.s.qdll_ena = 1;
753210284Sjmallett        cvmx_write_csr (CVMX_DFA_DDR2_PLL, dfaPll.u64);
754210284Sjmallett
755210284Sjmallett        cvmx_wait (RLD_INIT_DELAY); //want 10us
756210284Sjmallett        dfaEcklCfg.u64 = 0;
757210284Sjmallett        dfaEcklCfg.s.dfa_frstn = 1;
758210284Sjmallett        cvmx_write_csr (CVMX_DFA_ECLKCFG, dfaEcklCfg.u64);
759210284Sjmallett
760210284Sjmallett          /* Configure the DFA Memory */
761210284Sjmallett        dfaCfg.s.silo_hc = 1 /*400 - 1 */;
762210284Sjmallett        dfaCfg.s.silo_qc = 0 /*400 - 0 */;
763210284Sjmallett        dfaCfg.s.tskw    = 1 /*400 - 1 */;
764210284Sjmallett        dfaCfg.s.ref_int = 0x820 /*533 - 0x820  400 - 0x618*/;
765210284Sjmallett        dfaCfg.s.trfc    = 0x1A  /*533 - 0x23   400 - 0x1A*/;
766210284Sjmallett        dfaCfg.s.fprch   = 0; /* 1 more conservative*/
767210284Sjmallett        dfaCfg.s.bprch   = 0; /* 1 */
768210284Sjmallett        cvmx_write_csr (CVMX_DFA_DDR2_CFG, dfaCfg.u64);
769210284Sjmallett
770210284Sjmallett        dfaEcklCfg.u64 = cvmx_read_csr (CVMX_DFA_ECLKCFG);
771210284Sjmallett        dfaEcklCfg.s.maxbnk = 1;
772210284Sjmallett        cvmx_write_csr (CVMX_DFA_ECLKCFG, dfaEcklCfg.u64);
773210284Sjmallett
774210284Sjmallett        dfaAddr.u64 = cvmx_read_csr (CVMX_DFA_DDR2_ADDR);
775210284Sjmallett        dfaAddr.s.num_cols    = 0x1;
776210284Sjmallett        dfaAddr.s.num_colrows = 0x2;
777210284Sjmallett        dfaAddr.s.num_rnks    = 0x1;
778210284Sjmallett        cvmx_write_csr (CVMX_DFA_DDR2_ADDR, dfaAddr.u64);
779210284Sjmallett
780210284Sjmallett        dfaTmg.u64 =  cvmx_read_csr (CVMX_DFA_DDR2_TMG);
781210284Sjmallett        dfaTmg.s.ddr2t    = 0;
782210284Sjmallett        dfaTmg.s.tmrd     = 0x2;
783210284Sjmallett        dfaTmg.s.caslat   = 0x4 /*400 - 0x3, 500 - 0x4*/;
784210284Sjmallett        dfaTmg.s.pocas    = 0;
785210284Sjmallett        dfaTmg.s.addlat   = 0;
786210284Sjmallett        dfaTmg.s.trcd     = 4   /*400 - 3, 500 - 4*/;
787210284Sjmallett        dfaTmg.s.trrd     = 2;
788210284Sjmallett        dfaTmg.s.tras     = 0xB /*400 - 8, 500 - 0xB*/;
789210284Sjmallett        dfaTmg.s.trp      = 4   /*400 - 3, 500 - 4*/;
790210284Sjmallett        dfaTmg.s.twr      = 4   /*400 - 3, 500 - 4*/;
791210284Sjmallett        dfaTmg.s.twtr     = 2   /*400 - 2 */;
792210284Sjmallett        dfaTmg.s.tfaw     = 0xE /*400 - 0xA, 500 - 0xE*/;
793210284Sjmallett        dfaTmg.s.r2r_slot = 0;
794210284Sjmallett        dfaTmg.s.dic      = 0;  /*400 - 0 */
795210284Sjmallett        dfaTmg.s.dqsn_ena = 0;
796210284Sjmallett        dfaTmg.s.odt_rtt  = 0;
797210284Sjmallett        cvmx_write_csr (CVMX_DFA_DDR2_TMG, dfaTmg.u64);
798210284Sjmallett
799210284Sjmallett          /* Turn on the DDR2 interface and wait a bit for the hardware to setup. */
800210284Sjmallett        dfaCfg.s.init = 1;
801210284Sjmallett        cvmx_write_csr (CVMX_DFA_DDR2_CFG, dfaCfg.u64);
802210284Sjmallett        cvmx_wait(RLD_INIT_DELAY); // want at least 64K cycles
803210284Sjmallett    }
804210284Sjmallett}
805210284Sjmallett
806210284Sjmallettvoid write_rld_cfg(rldram_csr_config_t *cfg_ptr)
807210284Sjmallett{
808210284Sjmallett    cvmx_dfa_memcfg0_t    memcfg0;
809210284Sjmallett    cvmx_dfa_memcfg2_t    memcfg2;
810210284Sjmallett
811210284Sjmallett    memcfg0.u64 = cfg_ptr->dfa_memcfg0_base;
812210284Sjmallett
813210284Sjmallett    if ((OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)))
814210284Sjmallett    {
815210284Sjmallett        uint32_t dfa_memcfg0;
816210284Sjmallett
817210284Sjmallett        if (OCTEON_IS_MODEL (OCTEON_CN58XX)) {
818210284Sjmallett	      // Set RLDQK90_RST and RDLCK_RST to reset all three DLLs.
819210284Sjmallett	    memcfg0.s.rldck_rst    = 1;
820210284Sjmallett	    memcfg0.s.rldqck90_rst = 1;
821210284Sjmallett            cvmx_write_csr(CVMX_DFA_MEMCFG0, memcfg0.u64);
822210284Sjmallett            ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  clk/qk90 reset\n", (uint32_t) memcfg0.u64);
823210284Sjmallett            cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), memcfg0.u64);
824210284Sjmallett
825210284Sjmallett	      // Clear RDLCK_RST while asserting RLDQK90_RST to bring RLDCK DLL out of reset.
826210284Sjmallett	    memcfg0.s.rldck_rst    = 0;
827210284Sjmallett	    memcfg0.s.rldqck90_rst = 1;
828210284Sjmallett            cvmx_write_csr(CVMX_DFA_MEMCFG0, memcfg0.u64);
829210284Sjmallett            cvmx_wait(4000000);  /* Wait  */
830210284Sjmallett            ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  qk90 reset\n", (uint32_t) memcfg0.u64);
831210284Sjmallett            cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), memcfg0.u64);
832210284Sjmallett
833210284Sjmallett	      // Clear both RDLCK90_RST and RLDQK90_RST to bring the RLDQK90 DLL out of reset.
834210284Sjmallett	    memcfg0.s.rldck_rst    = 0;
835210284Sjmallett	    memcfg0.s.rldqck90_rst = 0;
836210284Sjmallett	    cvmx_write_csr(CVMX_DFA_MEMCFG0, memcfg0.u64);
837210284Sjmallett            cvmx_wait(4000000);  /* Wait  */
838210284Sjmallett            ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  DLL out of reset\n", (uint32_t) memcfg0.u64);
839210284Sjmallett            cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), memcfg0.u64);
840210284Sjmallett	}
841210284Sjmallett
842210284Sjmallett        //=======================================================================
843210284Sjmallett        // Now print out the sequence of events:
844210284Sjmallett        cvmx_write_csr(CVMX_DFA_MEMCFG0, cfg_ptr->dfa_memcfg0_base);
845210284Sjmallett        ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  port enables\n", cfg_ptr->dfa_memcfg0_base);
846210284Sjmallett        cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), cfg_ptr->dfa_memcfg0_base);
847210284Sjmallett        cvmx_wait(4000000);  /* Wait  */
848210284Sjmallett
849210284Sjmallett        cvmx_write_csr(CVMX_DFA_MEMCFG1, cfg_ptr->dfa_memcfg1_base);
850210284Sjmallett        ll_printf("CVMX_DFA_MEMCFG1: 0x%08x\n", cfg_ptr->dfa_memcfg1_base);
851210284Sjmallett        cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG1 & ~(1ull<<63), cfg_ptr->dfa_memcfg1_base);
852210284Sjmallett
853210284Sjmallett        if (cfg_ptr->p0_ena ==1)
854210284Sjmallett        {
855210284Sjmallett            cvmx_write_csr(CVMX_DFA_MEMRLD,  cfg_ptr->mrs_dat_p0bunk0);
856210284Sjmallett            ll_printf("CVMX_DFA_MEMRLD : 0x%08x  p0_ena memrld\n", cfg_ptr->mrs_dat_p0bunk0);
857210284Sjmallett            cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMRLD & ~(1ull<<63), cfg_ptr->mrs_dat_p0bunk0);
858210284Sjmallett
859210284Sjmallett            dfa_memcfg0 = ( cfg_ptr->dfa_memcfg0_base |
860210284Sjmallett                            (1 << 23) |   // P0_INIT
861210284Sjmallett                            (1 << 25)     // BUNK_INIT[1:0]=Bunk#0
862210284Sjmallett                          );
863210284Sjmallett
864210284Sjmallett            cvmx_write_csr(CVMX_DFA_MEMCFG0, dfa_memcfg0);
865210284Sjmallett            ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  p0_init/bunk_init\n", dfa_memcfg0);
866210284Sjmallett            cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), dfa_memcfg0);
867210284Sjmallett            cvmx_wait(RLD_INIT_DELAY);
868210284Sjmallett            ll_printf("Delay.....\n");
869210284Sjmallett            cvmx_write_csr(CVMX_DFA_MEMCFG0, cfg_ptr->dfa_memcfg0_base);
870210284Sjmallett            ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  back to base\n", cfg_ptr->dfa_memcfg0_base);
871210284Sjmallett            cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), cfg_ptr->dfa_memcfg0_base);
872210284Sjmallett        }
873210284Sjmallett
874210284Sjmallett        if (cfg_ptr->p1_ena ==1)
875210284Sjmallett        {
876210284Sjmallett            cvmx_write_csr(CVMX_DFA_MEMRLD,  cfg_ptr->mrs_dat_p1bunk0);
877210284Sjmallett            ll_printf("CVMX_DFA_MEMRLD : 0x%08x  p1_ena memrld\n", cfg_ptr->mrs_dat_p1bunk0);
878210284Sjmallett            cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMRLD & ~(1ull<<63), cfg_ptr->mrs_dat_p1bunk0);
879210284Sjmallett
880210284Sjmallett            dfa_memcfg0 = ( cfg_ptr->dfa_memcfg0_base |
881210284Sjmallett                            (1 << 24) |   // P1_INIT
882210284Sjmallett                            (1 << 25)     // BUNK_INIT[1:0]=Bunk#0
883210284Sjmallett                          );
884210284Sjmallett            cvmx_write_csr(CVMX_DFA_MEMCFG0, dfa_memcfg0);
885210284Sjmallett            ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  p1_init/bunk_init\n", dfa_memcfg0);
886210284Sjmallett            cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), dfa_memcfg0);
887210284Sjmallett            cvmx_wait(RLD_INIT_DELAY);
888210284Sjmallett            ll_printf("Delay.....\n");
889210284Sjmallett            cvmx_write_csr(CVMX_DFA_MEMCFG0, cfg_ptr->dfa_memcfg0_base);
890210284Sjmallett            ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  back to base\n", cfg_ptr->dfa_memcfg0_base);
891210284Sjmallett            cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), cfg_ptr->dfa_memcfg0_base);
892210284Sjmallett	}
893210284Sjmallett
894210284Sjmallett        // P0 Bunk#1
895210284Sjmallett        if ((cfg_ptr->p0_ena ==1) && (cfg_ptr->bunkport == 2))
896210284Sjmallett        {
897210284Sjmallett            cvmx_write_csr(CVMX_DFA_MEMRLD,  cfg_ptr->mrs_dat_p0bunk1);
898210284Sjmallett            ll_printf("CVMX_DFA_MEMRLD : 0x%08x  p0_ena memrld\n", cfg_ptr->mrs_dat_p0bunk1);
899210284Sjmallett            cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMRLD & ~(1ull<<63), cfg_ptr->mrs_dat_p0bunk1);
900210284Sjmallett
901210284Sjmallett            dfa_memcfg0 = ( cfg_ptr->dfa_memcfg0_base |
902210284Sjmallett                            (1 << 23) |   // P0_INIT
903210284Sjmallett                            (2 << 25)     // BUNK_INIT[1:0]=Bunk#1
904210284Sjmallett                          );
905210284Sjmallett            cvmx_write_csr(CVMX_DFA_MEMCFG0, dfa_memcfg0);
906210284Sjmallett            ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  p0_init/bunk_init\n", dfa_memcfg0);
907210284Sjmallett            cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), dfa_memcfg0);
908210284Sjmallett            cvmx_wait(RLD_INIT_DELAY);
909210284Sjmallett            ll_printf("Delay.....\n");
910210284Sjmallett
911210284Sjmallett            if (cfg_ptr->p1_ena == 1)
912210284Sjmallett            { // Re-arm Px_INIT if P1-B1 init is required
913210284Sjmallett                cvmx_write_csr(CVMX_DFA_MEMCFG0, cfg_ptr->dfa_memcfg0_base);
914210284Sjmallett                ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  px_init rearm\n", cfg_ptr->dfa_memcfg0_base);
915210284Sjmallett                cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), cfg_ptr->dfa_memcfg0_base);
916210284Sjmallett            }
917210284Sjmallett        }
918210284Sjmallett
919210284Sjmallett        if ((cfg_ptr->p1_ena == 1) && (cfg_ptr->bunkport == 2))
920210284Sjmallett        {
921210284Sjmallett            cvmx_write_csr(CVMX_DFA_MEMRLD,  cfg_ptr->mrs_dat_p1bunk1);
922210284Sjmallett            ll_printf("CVMX_DFA_MEMRLD : 0x%08x  p1_ena memrld\n", cfg_ptr->mrs_dat_p1bunk1);
923210284Sjmallett            cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMRLD & ~(1ull<<63), cfg_ptr->mrs_dat_p1bunk1);
924210284Sjmallett
925210284Sjmallett            dfa_memcfg0 = ( cfg_ptr->dfa_memcfg0_base |
926210284Sjmallett                            (1 << 24) |   // P1_INIT
927210284Sjmallett                            (2 << 25)     // BUNK_INIT[1:0]=10
928210284Sjmallett                          );
929210284Sjmallett            cvmx_write_csr(CVMX_DFA_MEMCFG0, dfa_memcfg0);
930210284Sjmallett            ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  p1_init/bunk_init\n", dfa_memcfg0);
931210284Sjmallett            cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), dfa_memcfg0);
932210284Sjmallett        }
933210284Sjmallett        cvmx_wait(4000000);  // 1/100S, 0.01S, 10mS
934210284Sjmallett        ll_printf("Delay.....\n");
935210284Sjmallett
936210284Sjmallett          /* Enable bunks */
937210284Sjmallett        dfa_memcfg0 = cfg_ptr->dfa_memcfg0_base |((cfg_ptr->bunkport >= 1) << 25) | ((cfg_ptr->bunkport == 2) << 26);
938210284Sjmallett        cvmx_write_csr(CVMX_DFA_MEMCFG0, dfa_memcfg0);
939210284Sjmallett        ll_printf("CVMX_DFA_MEMCFG0: 0x%08x  enable bunks\n", dfa_memcfg0);
940210284Sjmallett        cvmx_csr_db_decode(cvmx_get_proc_id(), CVMX_DFA_MEMCFG0 & ~(1ull<<63), dfa_memcfg0);
941210284Sjmallett        cvmx_wait(RLD_INIT_DELAY);
942210284Sjmallett        ll_printf("Delay.....\n");
943210284Sjmallett
944210284Sjmallett          /* Issue a Silo reset by toggling SILRST in memcfg2. */
945210284Sjmallett        memcfg2.u64 = cvmx_read_csr (CVMX_DFA_MEMCFG2);
946210284Sjmallett        memcfg2.s.silrst = 1;
947210284Sjmallett	cvmx_write_csr (CVMX_DFA_MEMCFG2, memcfg2.u64);
948210284Sjmallett        ll_printf("CVMX_DFA_MEMCFG2: 0x%08x  silo reset start\n", (uint32_t) memcfg2.u64);
949210284Sjmallett        memcfg2.s.silrst = 0;
950210284Sjmallett	cvmx_write_csr (CVMX_DFA_MEMCFG2, memcfg2.u64);
951210284Sjmallett        ll_printf("CVMX_DFA_MEMCFG2: 0x%08x  silo reset done\n", (uint32_t) memcfg2.u64);
952210284Sjmallett    }
953210284Sjmallett}
954210284Sjmallett
955