cvmx-qlm.c revision 232809
1232809Sjmallett/***********************license start***************
2232809Sjmallett * Copyright (c) 2011  Cavium Inc. (support@cavium.com). All rights
3232809Sjmallett * reserved.
4232809Sjmallett *
5232809Sjmallett *
6232809Sjmallett * Redistribution and use in source and binary forms, with or without
7232809Sjmallett * modification, are permitted provided that the following conditions are
8232809Sjmallett * met:
9232809Sjmallett *
10232809Sjmallett *   * Redistributions of source code must retain the above copyright
11232809Sjmallett *     notice, this list of conditions and the following disclaimer.
12232809Sjmallett *
13232809Sjmallett *   * Redistributions in binary form must reproduce the above
14232809Sjmallett *     copyright notice, this list of conditions and the following
15232809Sjmallett *     disclaimer in the documentation and/or other materials provided
16232809Sjmallett *     with the distribution.
17232809Sjmallett
18232809Sjmallett *   * Neither the name of Cavium Inc. nor the names of
19232809Sjmallett *     its contributors may be used to endorse or promote products
20232809Sjmallett *     derived from this software without specific prior written
21232809Sjmallett *     permission.
22232809Sjmallett
23232809Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24232809Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25232809Sjmallett * regulations, and may be subject to export or import  regulations in other
26232809Sjmallett * countries.
27232809Sjmallett
28232809Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29232809Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30232809Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31232809Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32232809Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33232809Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34232809Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35232809Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36232809Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37232809Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38232809Sjmallett ***********************license end**************************************/
39232809Sjmallett
40232809Sjmallett
41232809Sjmallett/**
42232809Sjmallett * @file
43232809Sjmallett *
44232809Sjmallett * Helper utilities for qlm.
45232809Sjmallett *
46232809Sjmallett * <hr>$Revision: 70129 $<hr>
47232809Sjmallett */
48232809Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
49232809Sjmallett#include <asm/octeon/cvmx.h>
50232809Sjmallett#include <asm/octeon/cvmx-bootmem.h>
51232809Sjmallett#include <asm/octeon/cvmx-helper-jtag.h>
52232809Sjmallett#include <asm/octeon/cvmx-qlm.h>
53232809Sjmallett#include <asm/octeon/cvmx-gmxx-defs.h>
54232809Sjmallett#include <asm/octeon/cvmx-sriox-defs.h>
55232809Sjmallett#include <asm/octeon/cvmx-sriomaintx-defs.h>
56232809Sjmallett#include <asm/octeon/cvmx-pciercx-defs.h>
57232809Sjmallett#else
58232809Sjmallett#include "executive-config.h"
59232809Sjmallett#include "cvmx-config.h"
60232809Sjmallett#include "cvmx.h"
61232809Sjmallett#include "cvmx-bootmem.h"
62232809Sjmallett#include "cvmx-helper-jtag.h"
63232809Sjmallett#include "cvmx-qlm.h"
64232809Sjmallett#endif
65232809Sjmallett
66232809Sjmallett/**
67232809Sjmallett * The JTAG chain for CN52XX and CN56XX is 4 * 268 bits long, or 1072.
68232809Sjmallett * CN5XXX full chain shift is:
69232809Sjmallett *     new data => lane 3 => lane 2 => lane 1 => lane 0 => data out
70232809Sjmallett * The JTAG chain for CN63XX is 4 * 300 bits long, or 1200.
71232809Sjmallett * The JTAG chain for CN68XX is 4 * 304 bits long, or 1216.
72232809Sjmallett * The JTAG chain for CN66XX/CN61XX/CNF71XX is 4 * 304 bits long, or 1216.
73232809Sjmallett * CN6XXX full chain shift is:
74232809Sjmallett *     new data => lane 0 => lane 1 => lane 2 => lane 3 => data out
75232809Sjmallett * Shift LSB first, get LSB out
76232809Sjmallett */
77232809Sjmallettextern const __cvmx_qlm_jtag_field_t __cvmx_qlm_jtag_field_cn52xx[];
78232809Sjmallettextern const __cvmx_qlm_jtag_field_t __cvmx_qlm_jtag_field_cn56xx[];
79232809Sjmallettextern const __cvmx_qlm_jtag_field_t __cvmx_qlm_jtag_field_cn63xx[];
80232809Sjmallettextern const __cvmx_qlm_jtag_field_t __cvmx_qlm_jtag_field_cn66xx[];
81232809Sjmallettextern const __cvmx_qlm_jtag_field_t __cvmx_qlm_jtag_field_cn68xx[];
82232809Sjmallett
83232809Sjmallett#define CVMX_QLM_JTAG_UINT32 40
84232809Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_HOST
85232809Sjmallettextern void octeon_remote_read_mem(void *buffer, uint64_t physical_address, int length);
86232809Sjmallettextern void octeon_remote_write_mem(uint64_t physical_address, const void *buffer, int length);
87232809Sjmallettuint32_t __cvmx_qlm_jtag_xor_ref[5][CVMX_QLM_JTAG_UINT32];
88232809Sjmallett#else
89232809Sjmalletttypedef uint32_t qlm_jtag_uint32_t[CVMX_QLM_JTAG_UINT32];
90232809SjmallettCVMX_SHARED qlm_jtag_uint32_t *__cvmx_qlm_jtag_xor_ref;
91232809Sjmallett#endif
92232809Sjmallett
93232809Sjmallett
94232809Sjmallett/**
95232809Sjmallett * Return the number of QLMs supported by the chip
96232809Sjmallett *
97232809Sjmallett * @return  Number of QLMs
98232809Sjmallett */
99232809Sjmallettint cvmx_qlm_get_num(void)
100232809Sjmallett{
101232809Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
102232809Sjmallett        return 5;
103232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN66XX))
104232809Sjmallett        return 3;
105232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN63XX))
106232809Sjmallett        return 3;
107232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN61XX))
108232809Sjmallett        return 3;
109232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN56XX))
110232809Sjmallett        return 4;
111232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CNF71XX))
112232809Sjmallett        return 2;
113232809Sjmallett
114232809Sjmallett    //cvmx_dprintf("Warning: cvmx_qlm_get_num: This chip does not have QLMs\n");
115232809Sjmallett    return 0;
116232809Sjmallett}
117232809Sjmallett
118232809Sjmallett/**
119232809Sjmallett * Return the qlm number based on the interface
120232809Sjmallett *
121232809Sjmallett * @param interface  Interface to look up
122232809Sjmallett */
123232809Sjmallettint cvmx_qlm_interface(int interface)
124232809Sjmallett{
125232809Sjmallett	if (OCTEON_IS_MODEL(OCTEON_CN61XX)) {
126232809Sjmallett		return (interface == 0) ? 2 : 0;
127232809Sjmallett	} else if (OCTEON_IS_MODEL(OCTEON_CN63XX) || OCTEON_IS_MODEL(OCTEON_CN66XX)) {
128232809Sjmallett		return 2 - interface;
129232809Sjmallett	} else {
130232809Sjmallett		/* Must be cn68XX */
131232809Sjmallett		switch(interface) {
132232809Sjmallett		case 1:
133232809Sjmallett			return 0;
134232809Sjmallett		default:
135232809Sjmallett			return interface;
136232809Sjmallett		}
137232809Sjmallett	}
138232809Sjmallett}
139232809Sjmallett
140232809Sjmallett/**
141232809Sjmallett * Return number of lanes for a given qlm
142232809Sjmallett *
143232809Sjmallett * @return  Number of lanes
144232809Sjmallett */
145232809Sjmallettint cvmx_qlm_get_lanes(int qlm)
146232809Sjmallett{
147232809Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN61XX) && qlm == 1)
148232809Sjmallett        return 2;
149232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CNF71XX))
150232809Sjmallett        return 2;
151232809Sjmallett
152232809Sjmallett    return 4;
153232809Sjmallett}
154232809Sjmallett
155232809Sjmallett/**
156232809Sjmallett * Get the QLM JTAG fields based on Octeon model on the supported chips.
157232809Sjmallett *
158232809Sjmallett * @return  qlm_jtag_field_t structure
159232809Sjmallett */
160232809Sjmallettconst __cvmx_qlm_jtag_field_t *cvmx_qlm_jtag_get_field(void)
161232809Sjmallett{
162232809Sjmallett    /* Figure out which JTAG chain description we're using */
163232809Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
164232809Sjmallett        return __cvmx_qlm_jtag_field_cn68xx;
165232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN66XX)
166232809Sjmallett             || OCTEON_IS_MODEL(OCTEON_CN61XX)
167232809Sjmallett             || OCTEON_IS_MODEL(OCTEON_CNF71XX))
168232809Sjmallett        return __cvmx_qlm_jtag_field_cn66xx;
169232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN63XX))
170232809Sjmallett        return __cvmx_qlm_jtag_field_cn63xx;
171232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN56XX))
172232809Sjmallett        return __cvmx_qlm_jtag_field_cn56xx;
173232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
174232809Sjmallett        return __cvmx_qlm_jtag_field_cn52xx;
175232809Sjmallett    else
176232809Sjmallett    {
177232809Sjmallett        //cvmx_dprintf("cvmx_qlm_jtag_get_field: Needs update for this chip\n");
178232809Sjmallett        return NULL;
179232809Sjmallett    }
180232809Sjmallett}
181232809Sjmallett
182232809Sjmallett/**
183232809Sjmallett * Get the QLM JTAG length by going through qlm_jtag_field for each
184232809Sjmallett * Octeon model that is supported
185232809Sjmallett *
186232809Sjmallett * @return return the length.
187232809Sjmallett */
188232809Sjmallettint cvmx_qlm_jtag_get_length(void)
189232809Sjmallett{
190232809Sjmallett    const __cvmx_qlm_jtag_field_t *qlm_ptr = cvmx_qlm_jtag_get_field();
191232809Sjmallett    int length = 0;
192232809Sjmallett
193232809Sjmallett    /* Figure out how many bits are in the JTAG chain */
194232809Sjmallett    while (qlm_ptr != NULL && qlm_ptr->name)
195232809Sjmallett    {
196232809Sjmallett        if (qlm_ptr->stop_bit > length)
197232809Sjmallett            length = qlm_ptr->stop_bit + 1;
198232809Sjmallett        qlm_ptr++;
199232809Sjmallett    }
200232809Sjmallett    return length;
201232809Sjmallett}
202232809Sjmallett
203232809Sjmallett/**
204232809Sjmallett * Initialize the QLM layer
205232809Sjmallett */
206232809Sjmallettvoid cvmx_qlm_init(void)
207232809Sjmallett{
208232809Sjmallett    int qlm;
209232809Sjmallett    int qlm_jtag_length;
210232809Sjmallett    char *qlm_jtag_name = "cvmx_qlm_jtag";
211232809Sjmallett    int qlm_jtag_size = CVMX_QLM_JTAG_UINT32 * 8 * 4;
212232809Sjmallett    static uint64_t qlm_base = 0;
213232809Sjmallett    const cvmx_bootmem_named_block_desc_t *desc;
214232809Sjmallett
215232809Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_HOST
216232809Sjmallett    /* Skip actual JTAG accesses on simulator */
217232809Sjmallett    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
218232809Sjmallett        return;
219232809Sjmallett#endif
220232809Sjmallett
221232809Sjmallett    qlm_jtag_length = cvmx_qlm_jtag_get_length();
222232809Sjmallett
223232809Sjmallett    if (4 * qlm_jtag_length > (int)sizeof(__cvmx_qlm_jtag_xor_ref[0]) * 8)
224232809Sjmallett    {
225232809Sjmallett        cvmx_dprintf("ERROR: cvmx_qlm_init: JTAG chain larger than XOR ref size\n");
226232809Sjmallett        return;
227232809Sjmallett    }
228232809Sjmallett
229232809Sjmallett    /* No need to initialize the initial JTAG state if cvmx_qlm_jtag
230232809Sjmallett       named block is already created. */
231232809Sjmallett    if ((desc = cvmx_bootmem_find_named_block(qlm_jtag_name)) != NULL)
232232809Sjmallett    {
233232809Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_HOST
234232809Sjmallett        char buffer[qlm_jtag_size];
235232809Sjmallett
236232809Sjmallett        octeon_remote_read_mem(buffer, desc->base_addr, qlm_jtag_size);
237232809Sjmallett        memcpy(__cvmx_qlm_jtag_xor_ref, buffer, qlm_jtag_size);
238232809Sjmallett#else
239232809Sjmallett        __cvmx_qlm_jtag_xor_ref = cvmx_phys_to_ptr(desc->base_addr);
240232809Sjmallett#endif
241232809Sjmallett        /* Initialize the internal JTAG */
242232809Sjmallett        cvmx_helper_qlm_jtag_init();
243232809Sjmallett        return;
244232809Sjmallett    }
245232809Sjmallett
246232809Sjmallett    /* Create named block to store the initial JTAG state. */
247232809Sjmallett    qlm_base = cvmx_bootmem_phy_named_block_alloc(qlm_jtag_size, 0, 0, 128, qlm_jtag_name, CVMX_BOOTMEM_FLAG_END_ALLOC);
248232809Sjmallett
249232809Sjmallett    if (qlm_base == -1ull)
250232809Sjmallett    {
251232809Sjmallett        cvmx_dprintf("ERROR: cvmx_qlm_init: Error in creating %s named block\n", qlm_jtag_name);
252232809Sjmallett        return;
253232809Sjmallett    }
254232809Sjmallett
255232809Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_HOST
256232809Sjmallett    __cvmx_qlm_jtag_xor_ref = cvmx_phys_to_ptr(qlm_base);
257232809Sjmallett#endif
258232809Sjmallett    memset(__cvmx_qlm_jtag_xor_ref, 0, qlm_jtag_size);
259232809Sjmallett
260232809Sjmallett    /* Initialize the internal JTAG */
261232809Sjmallett    cvmx_helper_qlm_jtag_init();
262232809Sjmallett
263232809Sjmallett    /* Read the XOR defaults for the JTAG chain */
264232809Sjmallett    for (qlm=0; qlm<cvmx_qlm_get_num(); qlm++)
265232809Sjmallett    {
266232809Sjmallett        int i;
267232809Sjmallett        /* Capture the reset defaults */
268232809Sjmallett        cvmx_helper_qlm_jtag_capture(qlm);
269232809Sjmallett        /* Save the reset defaults. This will shift out too much data, but
270232809Sjmallett           the extra zeros don't hurt anything */
271232809Sjmallett        for (i=0; i<CVMX_QLM_JTAG_UINT32; i++)
272232809Sjmallett            __cvmx_qlm_jtag_xor_ref[qlm][i] = cvmx_helper_qlm_jtag_shift(qlm, 32, 0);
273232809Sjmallett    }
274232809Sjmallett
275232809Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_HOST
276232809Sjmallett    /* Update the initial state for oct-remote utils. */
277232809Sjmallett    {
278232809Sjmallett        char buffer[qlm_jtag_size];
279232809Sjmallett
280232809Sjmallett        memcpy(buffer, &__cvmx_qlm_jtag_xor_ref, qlm_jtag_size);
281232809Sjmallett        octeon_remote_write_mem(qlm_base, buffer, qlm_jtag_size);
282232809Sjmallett    }
283232809Sjmallett#endif
284232809Sjmallett
285232809Sjmallett    /* Apply speed tweak as a workaround for errata G-16094. */
286232809Sjmallett    __cvmx_qlm_speed_tweak();
287232809Sjmallett    __cvmx_qlm_pcie_idle_dac_tweak();
288232809Sjmallett}
289232809Sjmallett
290232809Sjmallett/**
291232809Sjmallett * Lookup the bit information for a JTAG field name
292232809Sjmallett *
293232809Sjmallett * @param name   Name to lookup
294232809Sjmallett *
295232809Sjmallett * @return Field info, or NULL on failure
296232809Sjmallett */
297232809Sjmallettstatic const __cvmx_qlm_jtag_field_t *__cvmx_qlm_lookup_field(const char *name)
298232809Sjmallett{
299232809Sjmallett    const __cvmx_qlm_jtag_field_t *ptr = cvmx_qlm_jtag_get_field();
300232809Sjmallett    while (ptr->name)
301232809Sjmallett    {
302232809Sjmallett        if (strcmp(name, ptr->name) == 0)
303232809Sjmallett            return ptr;
304232809Sjmallett        ptr++;
305232809Sjmallett    }
306232809Sjmallett    cvmx_dprintf("__cvmx_qlm_lookup_field: Illegal field name %s\n", name);
307232809Sjmallett    return NULL;
308232809Sjmallett}
309232809Sjmallett
310232809Sjmallett/**
311232809Sjmallett * Get a field in a QLM JTAG chain
312232809Sjmallett *
313232809Sjmallett * @param qlm    QLM to get
314232809Sjmallett * @param lane   Lane in QLM to get
315232809Sjmallett * @param name   String name of field
316232809Sjmallett *
317232809Sjmallett * @return JTAG field value
318232809Sjmallett */
319232809Sjmallettuint64_t cvmx_qlm_jtag_get(int qlm, int lane, const char *name)
320232809Sjmallett{
321232809Sjmallett    const __cvmx_qlm_jtag_field_t *field = __cvmx_qlm_lookup_field(name);
322232809Sjmallett    int qlm_jtag_length = cvmx_qlm_jtag_get_length();
323232809Sjmallett    int num_lanes = cvmx_qlm_get_lanes(qlm);
324232809Sjmallett
325232809Sjmallett    if (!field)
326232809Sjmallett        return 0;
327232809Sjmallett
328232809Sjmallett    /* Capture the current settings */
329232809Sjmallett    cvmx_helper_qlm_jtag_capture(qlm);
330232809Sjmallett    /* Shift past lanes we don't care about. CN6XXX shifts lane 3 first */
331232809Sjmallett    cvmx_helper_qlm_jtag_shift_zeros(qlm, qlm_jtag_length * (num_lanes-1-lane));    /* Shift to the start of the field */
332232809Sjmallett    cvmx_helper_qlm_jtag_shift_zeros(qlm, field->start_bit);
333232809Sjmallett    /* Shift out the value and return it */
334232809Sjmallett    return cvmx_helper_qlm_jtag_shift(qlm, field->stop_bit - field->start_bit + 1, 0);
335232809Sjmallett}
336232809Sjmallett
337232809Sjmallett/**
338232809Sjmallett * Set a field in a QLM JTAG chain
339232809Sjmallett *
340232809Sjmallett * @param qlm    QLM to set
341232809Sjmallett * @param lane   Lane in QLM to set, or -1 for all lanes
342232809Sjmallett * @param name   String name of field
343232809Sjmallett * @param value  Value of the field
344232809Sjmallett */
345232809Sjmallettvoid cvmx_qlm_jtag_set(int qlm, int lane, const char *name, uint64_t value)
346232809Sjmallett{
347232809Sjmallett    int i, l;
348232809Sjmallett    uint32_t shift_values[CVMX_QLM_JTAG_UINT32];
349232809Sjmallett    int num_lanes = cvmx_qlm_get_lanes(qlm);
350232809Sjmallett    const __cvmx_qlm_jtag_field_t *field = __cvmx_qlm_lookup_field(name);
351232809Sjmallett    int qlm_jtag_length = cvmx_qlm_jtag_get_length();
352232809Sjmallett    int total_length = qlm_jtag_length * num_lanes;
353232809Sjmallett    int bits = 0;
354232809Sjmallett
355232809Sjmallett    if (!field)
356232809Sjmallett        return;
357232809Sjmallett
358232809Sjmallett    /* Get the current state */
359232809Sjmallett    cvmx_helper_qlm_jtag_capture(qlm);
360232809Sjmallett    for (i=0; i<CVMX_QLM_JTAG_UINT32; i++)
361232809Sjmallett        shift_values[i] = cvmx_helper_qlm_jtag_shift(qlm, 32, 0);
362232809Sjmallett
363232809Sjmallett    /* Put new data in our local array */
364232809Sjmallett    for (l=0; l<num_lanes; l++)
365232809Sjmallett    {
366232809Sjmallett        uint64_t new_value = value;
367232809Sjmallett        int bits;
368232809Sjmallett        if ((l != lane) && (lane != -1))
369232809Sjmallett            continue;
370232809Sjmallett        for (bits = field->start_bit + (num_lanes-1-l)*qlm_jtag_length;
371232809Sjmallett             bits <= field->stop_bit + (num_lanes-1-l)*qlm_jtag_length;
372232809Sjmallett             bits++)
373232809Sjmallett        {
374232809Sjmallett            if (new_value & 1)
375232809Sjmallett                shift_values[bits/32] |= 1<<(bits&31);
376232809Sjmallett            else
377232809Sjmallett                shift_values[bits/32] &= ~(1<<(bits&31));
378232809Sjmallett            new_value>>=1;
379232809Sjmallett        }
380232809Sjmallett    }
381232809Sjmallett
382232809Sjmallett    /* Shift out data and xor with reference */
383232809Sjmallett    while (bits < total_length)
384232809Sjmallett    {
385232809Sjmallett        uint32_t shift = shift_values[bits/32] ^ __cvmx_qlm_jtag_xor_ref[qlm][bits/32];
386232809Sjmallett        int width = total_length - bits;
387232809Sjmallett        if (width > 32)
388232809Sjmallett            width = 32;
389232809Sjmallett        cvmx_helper_qlm_jtag_shift(qlm, width, shift);
390232809Sjmallett        bits += 32;
391232809Sjmallett    }
392232809Sjmallett
393232809Sjmallett    /* Update the new data */
394232809Sjmallett    cvmx_helper_qlm_jtag_update(qlm);
395232809Sjmallett    /* Always give the QLM 1ms to settle after every update. This may not
396232809Sjmallett       always be needed, but some of the options make significant
397232809Sjmallett       electrical changes */
398232809Sjmallett    cvmx_wait_usec(1000);
399232809Sjmallett}
400232809Sjmallett
401232809Sjmallett/**
402232809Sjmallett * Errata G-16094: QLM Gen2 Equalizer Default Setting Change.
403232809Sjmallett * CN68XX pass 1.x and CN66XX pass 1.x QLM tweak. This function tweaks the
404232809Sjmallett * JTAG setting for a QLMs to run better at 5 and 6.25Ghz.
405232809Sjmallett */
406232809Sjmallettvoid __cvmx_qlm_speed_tweak(void)
407232809Sjmallett{
408232809Sjmallett    cvmx_mio_qlmx_cfg_t qlm_cfg;
409232809Sjmallett    int num_qlms = 0;
410232809Sjmallett    int qlm;
411232809Sjmallett
412232809Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_X))
413232809Sjmallett        num_qlms = 5;
414232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_X))
415232809Sjmallett        num_qlms = 3;
416232809Sjmallett    else
417232809Sjmallett        return;
418232809Sjmallett
419232809Sjmallett    /* Loop through the QLMs */
420232809Sjmallett    for (qlm = 0; qlm < num_qlms; qlm++)
421232809Sjmallett    {
422232809Sjmallett        /* Read the QLM speed */
423232809Sjmallett	qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm));
424232809Sjmallett
425232809Sjmallett        /* If the QLM is at 6.25Ghz or 5Ghz then program JTAG */
426232809Sjmallett        if ((qlm_cfg.s.qlm_spd == 5) || (qlm_cfg.s.qlm_spd == 12) ||
427232809Sjmallett            (qlm_cfg.s.qlm_spd == 0) || (qlm_cfg.s.qlm_spd == 6) ||
428232809Sjmallett            (qlm_cfg.s.qlm_spd == 11))
429232809Sjmallett        {
430232809Sjmallett            cvmx_qlm_jtag_set(qlm, -1, "rx_cap_gen2", 0x1);
431232809Sjmallett            cvmx_qlm_jtag_set(qlm, -1, "rx_eq_gen2", 0x8);
432232809Sjmallett        }
433232809Sjmallett    }
434232809Sjmallett}
435232809Sjmallett
436232809Sjmallett/**
437232809Sjmallett * Errata G-16174: QLM Gen2 PCIe IDLE DAC change.
438232809Sjmallett * CN68XX pass 1.x, CN66XX pass 1.x and CN63XX pass 1.0-2.2 QLM tweak.
439232809Sjmallett * This function tweaks the JTAG setting for a QLMs for PCIe to run better.
440232809Sjmallett */
441232809Sjmallettvoid __cvmx_qlm_pcie_idle_dac_tweak(void)
442232809Sjmallett{
443232809Sjmallett    int num_qlms = 0;
444232809Sjmallett    int qlm;
445232809Sjmallett
446232809Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_X))
447232809Sjmallett        num_qlms = 5;
448232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_X))
449232809Sjmallett        num_qlms = 3;
450232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) ||
451232809Sjmallett             OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_X))
452232809Sjmallett        num_qlms = 3;
453232809Sjmallett    else
454232809Sjmallett        return;
455232809Sjmallett
456232809Sjmallett    /* Loop through the QLMs */
457232809Sjmallett    for (qlm = 0; qlm < num_qlms; qlm++)
458232809Sjmallett        cvmx_qlm_jtag_set(qlm, -1, "idle_dac", 0x2);
459232809Sjmallett}
460232809Sjmallett
461232809Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_HOST
462232809Sjmallett/**
463232809Sjmallett * Get the speed (Gbaud) of the QLM in Mhz.
464232809Sjmallett *
465232809Sjmallett * @param qlm    QLM to examine
466232809Sjmallett *
467232809Sjmallett * @return Speed in Mhz
468232809Sjmallett */
469232809Sjmallettint cvmx_qlm_get_gbaud_mhz(int qlm)
470232809Sjmallett{
471232809Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN63XX))
472232809Sjmallett    {
473232809Sjmallett        if (qlm == 2)
474232809Sjmallett        {
475232809Sjmallett            cvmx_gmxx_inf_mode_t inf_mode;
476232809Sjmallett            inf_mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(0));
477232809Sjmallett            switch (inf_mode.s.speed)
478232809Sjmallett            {
479232809Sjmallett                case 0: return 5000;    /* 5     Gbaud */
480232809Sjmallett                case 1: return 2500;    /* 2.5   Gbaud */
481232809Sjmallett                case 2: return 2500;    /* 2.5   Gbaud */
482232809Sjmallett                case 3: return 1250;    /* 1.25  Gbaud */
483232809Sjmallett                case 4: return 1250;    /* 1.25  Gbaud */
484232809Sjmallett                case 5: return 6250;    /* 6.25  Gbaud */
485232809Sjmallett                case 6: return 5000;    /* 5     Gbaud */
486232809Sjmallett                case 7: return 2500;    /* 2.5   Gbaud */
487232809Sjmallett                case 8: return 3125;    /* 3.125 Gbaud */
488232809Sjmallett                case 9: return 2500;    /* 2.5   Gbaud */
489232809Sjmallett                case 10: return 1250;   /* 1.25  Gbaud */
490232809Sjmallett                case 11: return 5000;   /* 5     Gbaud */
491232809Sjmallett                case 12: return 6250;   /* 6.25  Gbaud */
492232809Sjmallett                case 13: return 3750;   /* 3.75  Gbaud */
493232809Sjmallett                case 14: return 3125;   /* 3.125 Gbaud */
494232809Sjmallett                default: return 0;      /* Disabled */
495232809Sjmallett            }
496232809Sjmallett        }
497232809Sjmallett        else
498232809Sjmallett        {
499232809Sjmallett            cvmx_sriox_status_reg_t status_reg;
500232809Sjmallett            status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(qlm));
501232809Sjmallett            if (status_reg.s.srio)
502232809Sjmallett            {
503232809Sjmallett                cvmx_sriomaintx_port_0_ctl2_t sriomaintx_port_0_ctl2;
504232809Sjmallett                sriomaintx_port_0_ctl2.u32 = cvmx_read_csr(CVMX_SRIOMAINTX_PORT_0_CTL2(qlm));
505232809Sjmallett                switch (sriomaintx_port_0_ctl2.s.sel_baud)
506232809Sjmallett                {
507232809Sjmallett                    case 1: return 1250;    /* 1.25  Gbaud */
508232809Sjmallett                    case 2: return 2500;    /* 2.5   Gbaud */
509232809Sjmallett                    case 3: return 3125;    /* 3.125 Gbaud */
510232809Sjmallett                    case 4: return 5000;    /* 5     Gbaud */
511232809Sjmallett                    case 5: return 6250;    /* 6.250 Gbaud */
512232809Sjmallett                    default: return 0;      /* Disabled */
513232809Sjmallett                }
514232809Sjmallett            }
515232809Sjmallett            else
516232809Sjmallett            {
517232809Sjmallett                cvmx_pciercx_cfg032_t pciercx_cfg032;
518232809Sjmallett                pciercx_cfg032.u32 = cvmx_read_csr(CVMX_PCIERCX_CFG032(qlm));
519232809Sjmallett                switch (pciercx_cfg032.s.ls)
520232809Sjmallett                {
521232809Sjmallett                    case 1:
522232809Sjmallett                        return 2500;
523232809Sjmallett                    case 2:
524232809Sjmallett                        return 5000;
525232809Sjmallett                    case 4:
526232809Sjmallett                        return 8000;
527232809Sjmallett                    default:
528232809Sjmallett                    {
529232809Sjmallett                        cvmx_mio_rst_boot_t mio_rst_boot;
530232809Sjmallett                        mio_rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT);
531232809Sjmallett                        if ((qlm == 0) && mio_rst_boot.s.qlm0_spd == 0xf)
532232809Sjmallett                            return 0;
533232809Sjmallett                        if ((qlm == 1) && mio_rst_boot.s.qlm1_spd == 0xf)
534232809Sjmallett                            return 0;
535232809Sjmallett                        return 5000; /* Best guess I can make */
536232809Sjmallett                    }
537232809Sjmallett                }
538232809Sjmallett            }
539232809Sjmallett        }
540232809Sjmallett    }
541232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF71XX))
542232809Sjmallett    {
543232809Sjmallett        cvmx_mio_qlmx_cfg_t qlm_cfg;
544232809Sjmallett
545232809Sjmallett        qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm));
546232809Sjmallett        switch (qlm_cfg.s.qlm_spd)
547232809Sjmallett        {
548232809Sjmallett            case 0: return 5000;    /* 5     Gbaud */
549232809Sjmallett            case 1: return 2500;    /* 2.5   Gbaud */
550232809Sjmallett            case 2: return 2500;    /* 2.5   Gbaud */
551232809Sjmallett            case 3: return 1250;    /* 1.25  Gbaud */
552232809Sjmallett            case 4: return 1250;    /* 1.25  Gbaud */
553232809Sjmallett            case 5: return 6250;    /* 6.25  Gbaud */
554232809Sjmallett            case 6: return 5000;    /* 5     Gbaud */
555232809Sjmallett            case 7: return 2500;    /* 2.5   Gbaud */
556232809Sjmallett            case 8: return 3125;    /* 3.125 Gbaud */
557232809Sjmallett            case 9: return 2500;    /* 2.5   Gbaud */
558232809Sjmallett            case 10: return 1250;   /* 1.25  Gbaud */
559232809Sjmallett            case 11: return 5000;   /* 5     Gbaud */
560232809Sjmallett            case 12: return 6250;   /* 6.25  Gbaud */
561232809Sjmallett            case 13: return 3750;   /* 3.75  Gbaud */
562232809Sjmallett            case 14: return 3125;   /* 3.125 Gbaud */
563232809Sjmallett            default: return 0;      /* Disabled */
564232809Sjmallett        }
565232809Sjmallett    }
566232809Sjmallett    return 0;
567232809Sjmallett}
568232809Sjmallett#endif
569232809Sjmallett
570232809Sjmallett/*
571232809Sjmallett * Read QLM and return status based on CN66XX.
572232809Sjmallett * @return  Return 1 if QLM is SGMII
573232809Sjmallett *                 2 if QLM is XAUI
574232809Sjmallett *                 3 if QLM is PCIe gen2 / gen1
575232809Sjmallett *                 4 if QLM is SRIO 1x4 short / long
576232809Sjmallett *                 5 if QLM is SRIO 2x2 short / long
577232809Sjmallett *                 6 if QLM is SRIO 4x1 short / long
578232809Sjmallett *                 7 if QLM is PCIe 1x2 gen2 / gen1
579232809Sjmallett *                 8 if QLM is PCIe 2x1 gen2 / gen1
580232809Sjmallett *                 9 if QLM is ILK
581232809Sjmallett *                 10 if QLM is RXAUI
582232809Sjmallett *                 -1 otherwise
583232809Sjmallett */
584232809Sjmallettint cvmx_qlm_get_status(int qlm)
585232809Sjmallett{
586232809Sjmallett    cvmx_mio_qlmx_cfg_t qlmx_cfg;
587232809Sjmallett
588232809Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
589232809Sjmallett    {
590232809Sjmallett        qlmx_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm));
591232809Sjmallett        /* QLM is disabled when QLM SPD is 15. */
592232809Sjmallett        if (qlmx_cfg.s.qlm_spd == 15)
593232809Sjmallett            return  -1;
594232809Sjmallett
595232809Sjmallett        switch (qlmx_cfg.s.qlm_cfg)
596232809Sjmallett        {
597232809Sjmallett            case 0: /* PCIE */
598232809Sjmallett                return 3;
599232809Sjmallett            case 1: /* ILK */
600232809Sjmallett                return 9;
601232809Sjmallett            case 2: /* SGMII */
602232809Sjmallett                return 1;
603232809Sjmallett            case 3: /* XAUI */
604232809Sjmallett                return 2;
605232809Sjmallett            case 7: /* RXAUI */
606232809Sjmallett                return 10;
607232809Sjmallett            default: return -1;
608232809Sjmallett        }
609232809Sjmallett    }
610232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN66XX))
611232809Sjmallett    {
612232809Sjmallett        qlmx_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm));
613232809Sjmallett        /* QLM is disabled when QLM SPD is 15. */
614232809Sjmallett        if (qlmx_cfg.s.qlm_spd == 15)
615232809Sjmallett            return  -1;
616232809Sjmallett
617232809Sjmallett        switch (qlmx_cfg.s.qlm_cfg)
618232809Sjmallett        {
619232809Sjmallett            case 0x9: /* SGMII */
620232809Sjmallett                return 1;
621232809Sjmallett            case 0xb: /* XAUI */
622232809Sjmallett                return 2;
623232809Sjmallett            case 0x0: /* PCIE gen2 */
624232809Sjmallett            case 0x8: /* PCIE gen2 (alias) */
625232809Sjmallett            case 0x2: /* PCIE gen1 */
626232809Sjmallett            case 0xa: /* PCIE gen1 (alias) */
627232809Sjmallett                return 3;
628232809Sjmallett            case 0x1: /* SRIO 1x4 short */
629232809Sjmallett            case 0x3: /* SRIO 1x4 long */
630232809Sjmallett                return 4;
631232809Sjmallett            case 0x4: /* SRIO 2x2 short */
632232809Sjmallett            case 0x6: /* SRIO 2x2 long */
633232809Sjmallett                return 5;
634232809Sjmallett            case 0x5: /* SRIO 4x1 short */
635232809Sjmallett            case 0x7: /* SRIO 4x1 long */
636232809Sjmallett                if (!OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_0))
637232809Sjmallett                    return 6;
638232809Sjmallett            default:
639232809Sjmallett                return -1;
640232809Sjmallett        }
641232809Sjmallett    }
642232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN63XX))
643232809Sjmallett    {
644232809Sjmallett        cvmx_sriox_status_reg_t status_reg;
645232809Sjmallett        /* For now skip qlm2 */
646232809Sjmallett        if (qlm == 2)
647232809Sjmallett        {
648232809Sjmallett            cvmx_gmxx_inf_mode_t inf_mode;
649232809Sjmallett            inf_mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(0));
650232809Sjmallett            if (inf_mode.s.speed == 15)
651232809Sjmallett                return -1;
652232809Sjmallett            else if(inf_mode.s.mode == 0)
653232809Sjmallett                return 1;
654232809Sjmallett            else
655232809Sjmallett                return 2;
656232809Sjmallett        }
657232809Sjmallett        status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(qlm));
658232809Sjmallett        if (status_reg.s.srio)
659232809Sjmallett            return 4;
660232809Sjmallett        else
661232809Sjmallett            return 3;
662232809Sjmallett    }
663232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN61XX))
664232809Sjmallett    {
665232809Sjmallett        qlmx_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm));
666232809Sjmallett        /* QLM is disabled when QLM SPD is 15. */
667232809Sjmallett        if (qlmx_cfg.s.qlm_spd == 15)
668232809Sjmallett            return  -1;
669232809Sjmallett
670232809Sjmallett        switch(qlm)
671232809Sjmallett        {
672232809Sjmallett            case 0:
673232809Sjmallett                switch (qlmx_cfg.s.qlm_cfg)
674232809Sjmallett                {
675232809Sjmallett                    case 0: /* PCIe 1x4 gen2 / gen1 */
676232809Sjmallett                        return 3;
677232809Sjmallett                    case 2: /* SGMII */
678232809Sjmallett                        return 1;
679232809Sjmallett                    case 3: /* XAUI */
680232809Sjmallett                        return 2;
681232809Sjmallett                    default: return -1;
682232809Sjmallett                }
683232809Sjmallett                break;
684232809Sjmallett            case 1:
685232809Sjmallett                switch (qlmx_cfg.s.qlm_cfg)
686232809Sjmallett                {
687232809Sjmallett                    case 0: /* PCIe 1x2 gen2 / gen1 */
688232809Sjmallett                        return 7;
689232809Sjmallett                    case 1: /* PCIe 2x1 gen2 / gen1 */
690232809Sjmallett                        return 8;
691232809Sjmallett                    default: return -1;
692232809Sjmallett                }
693232809Sjmallett                break;
694232809Sjmallett            case 2:
695232809Sjmallett                switch (qlmx_cfg.s.qlm_cfg)
696232809Sjmallett                {
697232809Sjmallett                    case 2: /* SGMII */
698232809Sjmallett                        return 1;
699232809Sjmallett                    case 3: /* XAUI */
700232809Sjmallett                        return 2;
701232809Sjmallett                    default: return -1;
702232809Sjmallett                }
703232809Sjmallett                break;
704232809Sjmallett        }
705232809Sjmallett    }
706232809Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CNF71XX))
707232809Sjmallett    {
708232809Sjmallett        qlmx_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm));
709232809Sjmallett        /* QLM is disabled when QLM SPD is 15. */
710232809Sjmallett        if (qlmx_cfg.s.qlm_spd == 15)
711232809Sjmallett            return  -1;
712232809Sjmallett
713232809Sjmallett        switch(qlm)
714232809Sjmallett        {
715232809Sjmallett            case 0:
716232809Sjmallett                if (qlmx_cfg.s.qlm_cfg == 2) /* SGMII */
717232809Sjmallett                    return 1;
718232809Sjmallett                break;
719232809Sjmallett            case 1:
720232809Sjmallett                switch (qlmx_cfg.s.qlm_cfg)
721232809Sjmallett                {
722232809Sjmallett                    case 0: /* PCIe 1x2 gen2 / gen1 */
723232809Sjmallett                        return 7;
724232809Sjmallett                    case 1: /* PCIe 2x1 gen2 / gen1 */
725232809Sjmallett                        return 8;
726232809Sjmallett                    default: return -1;
727232809Sjmallett                }
728232809Sjmallett                break;
729232809Sjmallett        }
730232809Sjmallett    }
731232809Sjmallett    return -1;
732232809Sjmallett}
733