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