1/***********************license start***************
2 * Copyright (c) 2011  Cavium Inc. (support@cavium.com). All rights
3 * reserved.
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *   * Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 *
13 *   * Redistributions in binary form must reproduce the above
14 *     copyright notice, this list of conditions and the following
15 *     disclaimer in the documentation and/or other materials provided
16 *     with the distribution.
17
18 *   * Neither the name of Cavium Inc. nor the names of
19 *     its contributors may be used to endorse or promote products
20 *     derived from this software without specific prior written
21 *     permission.
22
23 * This Software, including technical data, may be subject to U.S. export  control
24 * laws, including the U.S. Export Administration Act and its  associated
25 * regulations, and may be subject to export or import  regulations in other
26 * countries.
27
28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
39
40
41/**
42 * @file
43 *
44 * Helper utilities for qlm.
45 *
46 * <hr>$Revision: 70129 $<hr>
47 */
48#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
49#include <asm/octeon/cvmx.h>
50#include <asm/octeon/cvmx-bootmem.h>
51#include <asm/octeon/cvmx-helper-jtag.h>
52#include <asm/octeon/cvmx-qlm.h>
53#include <asm/octeon/cvmx-gmxx-defs.h>
54#include <asm/octeon/cvmx-sriox-defs.h>
55#include <asm/octeon/cvmx-sriomaintx-defs.h>
56#include <asm/octeon/cvmx-pciercx-defs.h>
57#else
58#if !defined(__FreeBSD__) || !defined(_KERNEL)
59#include "executive-config.h"
60#include "cvmx-config.h"
61#include "cvmx.h"
62#include "cvmx-bootmem.h"
63#include "cvmx-helper-jtag.h"
64#include "cvmx-qlm.h"
65#else
66#include "cvmx.h"
67#include "cvmx-bootmem.h"
68#include "cvmx-helper-jtag.h"
69#include "cvmx-qlm.h"
70#endif
71
72#endif
73
74/**
75 * The JTAG chain for CN52XX and CN56XX is 4 * 268 bits long, or 1072.
76 * CN5XXX full chain shift is:
77 *     new data => lane 3 => lane 2 => lane 1 => lane 0 => data out
78 * The JTAG chain for CN63XX is 4 * 300 bits long, or 1200.
79 * The JTAG chain for CN68XX is 4 * 304 bits long, or 1216.
80 * The JTAG chain for CN66XX/CN61XX/CNF71XX is 4 * 304 bits long, or 1216.
81 * CN6XXX full chain shift is:
82 *     new data => lane 0 => lane 1 => lane 2 => lane 3 => data out
83 * Shift LSB first, get LSB out
84 */
85extern const __cvmx_qlm_jtag_field_t __cvmx_qlm_jtag_field_cn52xx[];
86extern const __cvmx_qlm_jtag_field_t __cvmx_qlm_jtag_field_cn56xx[];
87extern const __cvmx_qlm_jtag_field_t __cvmx_qlm_jtag_field_cn63xx[];
88extern const __cvmx_qlm_jtag_field_t __cvmx_qlm_jtag_field_cn66xx[];
89extern const __cvmx_qlm_jtag_field_t __cvmx_qlm_jtag_field_cn68xx[];
90
91#define CVMX_QLM_JTAG_UINT32 40
92#ifdef CVMX_BUILD_FOR_LINUX_HOST
93extern void octeon_remote_read_mem(void *buffer, uint64_t physical_address, int length);
94extern void octeon_remote_write_mem(uint64_t physical_address, const void *buffer, int length);
95uint32_t __cvmx_qlm_jtag_xor_ref[5][CVMX_QLM_JTAG_UINT32];
96#else
97typedef uint32_t qlm_jtag_uint32_t[CVMX_QLM_JTAG_UINT32];
98CVMX_SHARED qlm_jtag_uint32_t *__cvmx_qlm_jtag_xor_ref;
99#endif
100
101
102/**
103 * Return the number of QLMs supported by the chip
104 *
105 * @return  Number of QLMs
106 */
107int cvmx_qlm_get_num(void)
108{
109    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
110        return 5;
111    else if (OCTEON_IS_MODEL(OCTEON_CN66XX))
112        return 3;
113    else if (OCTEON_IS_MODEL(OCTEON_CN63XX))
114        return 3;
115    else if (OCTEON_IS_MODEL(OCTEON_CN61XX))
116        return 3;
117    else if (OCTEON_IS_MODEL(OCTEON_CN56XX))
118        return 4;
119    else if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CNF71XX))
120        return 2;
121
122    //cvmx_dprintf("Warning: cvmx_qlm_get_num: This chip does not have QLMs\n");
123    return 0;
124}
125
126/**
127 * Return the qlm number based on the interface
128 *
129 * @param interface  Interface to look up
130 */
131int cvmx_qlm_interface(int interface)
132{
133	if (OCTEON_IS_MODEL(OCTEON_CN61XX)) {
134		return (interface == 0) ? 2 : 0;
135	} else if (OCTEON_IS_MODEL(OCTEON_CN63XX) || OCTEON_IS_MODEL(OCTEON_CN66XX)) {
136		return 2 - interface;
137	} else {
138		/* Must be cn68XX */
139		switch(interface) {
140		case 1:
141			return 0;
142		default:
143			return interface;
144		}
145	}
146}
147
148/**
149 * Return number of lanes for a given qlm
150 *
151 * @return  Number of lanes
152 */
153int cvmx_qlm_get_lanes(int qlm)
154{
155    if (OCTEON_IS_MODEL(OCTEON_CN61XX) && qlm == 1)
156        return 2;
157    else if (OCTEON_IS_MODEL(OCTEON_CNF71XX))
158        return 2;
159
160    return 4;
161}
162
163/**
164 * Get the QLM JTAG fields based on Octeon model on the supported chips.
165 *
166 * @return  qlm_jtag_field_t structure
167 */
168const __cvmx_qlm_jtag_field_t *cvmx_qlm_jtag_get_field(void)
169{
170    /* Figure out which JTAG chain description we're using */
171    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
172        return __cvmx_qlm_jtag_field_cn68xx;
173    else if (OCTEON_IS_MODEL(OCTEON_CN66XX)
174             || OCTEON_IS_MODEL(OCTEON_CN61XX)
175             || OCTEON_IS_MODEL(OCTEON_CNF71XX))
176        return __cvmx_qlm_jtag_field_cn66xx;
177    else if (OCTEON_IS_MODEL(OCTEON_CN63XX))
178        return __cvmx_qlm_jtag_field_cn63xx;
179    else if (OCTEON_IS_MODEL(OCTEON_CN56XX))
180        return __cvmx_qlm_jtag_field_cn56xx;
181    else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
182        return __cvmx_qlm_jtag_field_cn52xx;
183    else
184    {
185        //cvmx_dprintf("cvmx_qlm_jtag_get_field: Needs update for this chip\n");
186        return NULL;
187    }
188}
189
190/**
191 * Get the QLM JTAG length by going through qlm_jtag_field for each
192 * Octeon model that is supported
193 *
194 * @return return the length.
195 */
196int cvmx_qlm_jtag_get_length(void)
197{
198    const __cvmx_qlm_jtag_field_t *qlm_ptr = cvmx_qlm_jtag_get_field();
199    int length = 0;
200
201    /* Figure out how many bits are in the JTAG chain */
202    while (qlm_ptr != NULL && qlm_ptr->name)
203    {
204        if (qlm_ptr->stop_bit > length)
205            length = qlm_ptr->stop_bit + 1;
206        qlm_ptr++;
207    }
208    return length;
209}
210
211/**
212 * Initialize the QLM layer
213 */
214void cvmx_qlm_init(void)
215{
216    int qlm;
217    int qlm_jtag_length;
218    char *qlm_jtag_name = "cvmx_qlm_jtag";
219    int qlm_jtag_size = CVMX_QLM_JTAG_UINT32 * 8 * 4;
220    static uint64_t qlm_base = 0;
221    const cvmx_bootmem_named_block_desc_t *desc;
222
223#ifndef CVMX_BUILD_FOR_LINUX_HOST
224    /* Skip actual JTAG accesses on simulator */
225    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
226        return;
227#endif
228
229    qlm_jtag_length = cvmx_qlm_jtag_get_length();
230
231    if (4 * qlm_jtag_length > (int)sizeof(__cvmx_qlm_jtag_xor_ref[0]) * 8)
232    {
233        cvmx_dprintf("ERROR: cvmx_qlm_init: JTAG chain larger than XOR ref size\n");
234        return;
235    }
236
237    /* No need to initialize the initial JTAG state if cvmx_qlm_jtag
238       named block is already created. */
239    if ((desc = cvmx_bootmem_find_named_block(qlm_jtag_name)) != NULL)
240    {
241#ifdef CVMX_BUILD_FOR_LINUX_HOST
242        char buffer[qlm_jtag_size];
243
244        octeon_remote_read_mem(buffer, desc->base_addr, qlm_jtag_size);
245        memcpy(__cvmx_qlm_jtag_xor_ref, buffer, qlm_jtag_size);
246#else
247        __cvmx_qlm_jtag_xor_ref = cvmx_phys_to_ptr(desc->base_addr);
248#endif
249        /* Initialize the internal JTAG */
250        cvmx_helper_qlm_jtag_init();
251        return;
252    }
253
254    /* Create named block to store the initial JTAG state. */
255    qlm_base = cvmx_bootmem_phy_named_block_alloc(qlm_jtag_size, 0, 0, 128, qlm_jtag_name, CVMX_BOOTMEM_FLAG_END_ALLOC);
256
257    if (qlm_base == -1ull)
258    {
259        cvmx_dprintf("ERROR: cvmx_qlm_init: Error in creating %s named block\n", qlm_jtag_name);
260        return;
261    }
262
263#ifndef CVMX_BUILD_FOR_LINUX_HOST
264    __cvmx_qlm_jtag_xor_ref = cvmx_phys_to_ptr(qlm_base);
265#endif
266    memset(__cvmx_qlm_jtag_xor_ref, 0, qlm_jtag_size);
267
268    /* Initialize the internal JTAG */
269    cvmx_helper_qlm_jtag_init();
270
271    /* Read the XOR defaults for the JTAG chain */
272    for (qlm=0; qlm<cvmx_qlm_get_num(); qlm++)
273    {
274        int i;
275        /* Capture the reset defaults */
276        cvmx_helper_qlm_jtag_capture(qlm);
277        /* Save the reset defaults. This will shift out too much data, but
278           the extra zeros don't hurt anything */
279        for (i=0; i<CVMX_QLM_JTAG_UINT32; i++)
280            __cvmx_qlm_jtag_xor_ref[qlm][i] = cvmx_helper_qlm_jtag_shift(qlm, 32, 0);
281    }
282
283#ifdef CVMX_BUILD_FOR_LINUX_HOST
284    /* Update the initial state for oct-remote utils. */
285    {
286        char buffer[qlm_jtag_size];
287
288        memcpy(buffer, &__cvmx_qlm_jtag_xor_ref, qlm_jtag_size);
289        octeon_remote_write_mem(qlm_base, buffer, qlm_jtag_size);
290    }
291#endif
292
293    /* Apply speed tweak as a workaround for errata G-16094. */
294    __cvmx_qlm_speed_tweak();
295    __cvmx_qlm_pcie_idle_dac_tweak();
296}
297
298/**
299 * Lookup the bit information for a JTAG field name
300 *
301 * @param name   Name to lookup
302 *
303 * @return Field info, or NULL on failure
304 */
305static const __cvmx_qlm_jtag_field_t *__cvmx_qlm_lookup_field(const char *name)
306{
307    const __cvmx_qlm_jtag_field_t *ptr = cvmx_qlm_jtag_get_field();
308    while (ptr->name)
309    {
310        if (strcmp(name, ptr->name) == 0)
311            return ptr;
312        ptr++;
313    }
314    cvmx_dprintf("__cvmx_qlm_lookup_field: Illegal field name %s\n", name);
315    return NULL;
316}
317
318/**
319 * Get a field in a QLM JTAG chain
320 *
321 * @param qlm    QLM to get
322 * @param lane   Lane in QLM to get
323 * @param name   String name of field
324 *
325 * @return JTAG field value
326 */
327uint64_t cvmx_qlm_jtag_get(int qlm, int lane, const char *name)
328{
329    const __cvmx_qlm_jtag_field_t *field = __cvmx_qlm_lookup_field(name);
330    int qlm_jtag_length = cvmx_qlm_jtag_get_length();
331    int num_lanes = cvmx_qlm_get_lanes(qlm);
332
333    if (!field)
334        return 0;
335
336    /* Capture the current settings */
337    cvmx_helper_qlm_jtag_capture(qlm);
338    /* Shift past lanes we don't care about. CN6XXX shifts lane 3 first */
339    cvmx_helper_qlm_jtag_shift_zeros(qlm, qlm_jtag_length * (num_lanes-1-lane));    /* Shift to the start of the field */
340    cvmx_helper_qlm_jtag_shift_zeros(qlm, field->start_bit);
341    /* Shift out the value and return it */
342    return cvmx_helper_qlm_jtag_shift(qlm, field->stop_bit - field->start_bit + 1, 0);
343}
344
345/**
346 * Set a field in a QLM JTAG chain
347 *
348 * @param qlm    QLM to set
349 * @param lane   Lane in QLM to set, or -1 for all lanes
350 * @param name   String name of field
351 * @param value  Value of the field
352 */
353void cvmx_qlm_jtag_set(int qlm, int lane, const char *name, uint64_t value)
354{
355    int i, l;
356    uint32_t shift_values[CVMX_QLM_JTAG_UINT32];
357    int num_lanes = cvmx_qlm_get_lanes(qlm);
358    const __cvmx_qlm_jtag_field_t *field = __cvmx_qlm_lookup_field(name);
359    int qlm_jtag_length = cvmx_qlm_jtag_get_length();
360    int total_length = qlm_jtag_length * num_lanes;
361    int bits = 0;
362
363    if (!field)
364        return;
365
366    /* Get the current state */
367    cvmx_helper_qlm_jtag_capture(qlm);
368    for (i=0; i<CVMX_QLM_JTAG_UINT32; i++)
369        shift_values[i] = cvmx_helper_qlm_jtag_shift(qlm, 32, 0);
370
371    /* Put new data in our local array */
372    for (l=0; l<num_lanes; l++)
373    {
374        uint64_t new_value = value;
375        int bits;
376        if ((l != lane) && (lane != -1))
377            continue;
378        for (bits = field->start_bit + (num_lanes-1-l)*qlm_jtag_length;
379             bits <= field->stop_bit + (num_lanes-1-l)*qlm_jtag_length;
380             bits++)
381        {
382            if (new_value & 1)
383                shift_values[bits/32] |= 1<<(bits&31);
384            else
385                shift_values[bits/32] &= ~(1<<(bits&31));
386            new_value>>=1;
387        }
388    }
389
390    /* Shift out data and xor with reference */
391    while (bits < total_length)
392    {
393        uint32_t shift = shift_values[bits/32] ^ __cvmx_qlm_jtag_xor_ref[qlm][bits/32];
394        int width = total_length - bits;
395        if (width > 32)
396            width = 32;
397        cvmx_helper_qlm_jtag_shift(qlm, width, shift);
398        bits += 32;
399    }
400
401    /* Update the new data */
402    cvmx_helper_qlm_jtag_update(qlm);
403    /* Always give the QLM 1ms to settle after every update. This may not
404       always be needed, but some of the options make significant
405       electrical changes */
406    cvmx_wait_usec(1000);
407}
408
409/**
410 * Errata G-16094: QLM Gen2 Equalizer Default Setting Change.
411 * CN68XX pass 1.x and CN66XX pass 1.x QLM tweak. This function tweaks the
412 * JTAG setting for a QLMs to run better at 5 and 6.25Ghz.
413 */
414void __cvmx_qlm_speed_tweak(void)
415{
416    cvmx_mio_qlmx_cfg_t qlm_cfg;
417    int num_qlms = 0;
418    int qlm;
419
420    if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_X))
421        num_qlms = 5;
422    else if (OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_X))
423        num_qlms = 3;
424    else
425        return;
426
427    /* Loop through the QLMs */
428    for (qlm = 0; qlm < num_qlms; qlm++)
429    {
430        /* Read the QLM speed */
431	qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm));
432
433        /* If the QLM is at 6.25Ghz or 5Ghz then program JTAG */
434        if ((qlm_cfg.s.qlm_spd == 5) || (qlm_cfg.s.qlm_spd == 12) ||
435            (qlm_cfg.s.qlm_spd == 0) || (qlm_cfg.s.qlm_spd == 6) ||
436            (qlm_cfg.s.qlm_spd == 11))
437        {
438            cvmx_qlm_jtag_set(qlm, -1, "rx_cap_gen2", 0x1);
439            cvmx_qlm_jtag_set(qlm, -1, "rx_eq_gen2", 0x8);
440        }
441    }
442}
443
444/**
445 * Errata G-16174: QLM Gen2 PCIe IDLE DAC change.
446 * CN68XX pass 1.x, CN66XX pass 1.x and CN63XX pass 1.0-2.2 QLM tweak.
447 * This function tweaks the JTAG setting for a QLMs for PCIe to run better.
448 */
449void __cvmx_qlm_pcie_idle_dac_tweak(void)
450{
451    int num_qlms = 0;
452    int qlm;
453
454    if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_X))
455        num_qlms = 5;
456    else if (OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_X))
457        num_qlms = 3;
458    else if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) ||
459             OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_X))
460        num_qlms = 3;
461    else
462        return;
463
464    /* Loop through the QLMs */
465    for (qlm = 0; qlm < num_qlms; qlm++)
466        cvmx_qlm_jtag_set(qlm, -1, "idle_dac", 0x2);
467}
468
469#ifndef CVMX_BUILD_FOR_LINUX_HOST
470/**
471 * Get the speed (Gbaud) of the QLM in Mhz.
472 *
473 * @param qlm    QLM to examine
474 *
475 * @return Speed in Mhz
476 */
477int cvmx_qlm_get_gbaud_mhz(int qlm)
478{
479    if (OCTEON_IS_MODEL(OCTEON_CN63XX))
480    {
481        if (qlm == 2)
482        {
483            cvmx_gmxx_inf_mode_t inf_mode;
484            inf_mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(0));
485            switch (inf_mode.s.speed)
486            {
487                case 0: return 5000;    /* 5     Gbaud */
488                case 1: return 2500;    /* 2.5   Gbaud */
489                case 2: return 2500;    /* 2.5   Gbaud */
490                case 3: return 1250;    /* 1.25  Gbaud */
491                case 4: return 1250;    /* 1.25  Gbaud */
492                case 5: return 6250;    /* 6.25  Gbaud */
493                case 6: return 5000;    /* 5     Gbaud */
494                case 7: return 2500;    /* 2.5   Gbaud */
495                case 8: return 3125;    /* 3.125 Gbaud */
496                case 9: return 2500;    /* 2.5   Gbaud */
497                case 10: return 1250;   /* 1.25  Gbaud */
498                case 11: return 5000;   /* 5     Gbaud */
499                case 12: return 6250;   /* 6.25  Gbaud */
500                case 13: return 3750;   /* 3.75  Gbaud */
501                case 14: return 3125;   /* 3.125 Gbaud */
502                default: return 0;      /* Disabled */
503            }
504        }
505        else
506        {
507            cvmx_sriox_status_reg_t status_reg;
508            status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(qlm));
509            if (status_reg.s.srio)
510            {
511                cvmx_sriomaintx_port_0_ctl2_t sriomaintx_port_0_ctl2;
512                sriomaintx_port_0_ctl2.u32 = cvmx_read_csr(CVMX_SRIOMAINTX_PORT_0_CTL2(qlm));
513                switch (sriomaintx_port_0_ctl2.s.sel_baud)
514                {
515                    case 1: return 1250;    /* 1.25  Gbaud */
516                    case 2: return 2500;    /* 2.5   Gbaud */
517                    case 3: return 3125;    /* 3.125 Gbaud */
518                    case 4: return 5000;    /* 5     Gbaud */
519                    case 5: return 6250;    /* 6.250 Gbaud */
520                    default: return 0;      /* Disabled */
521                }
522            }
523            else
524            {
525                cvmx_pciercx_cfg032_t pciercx_cfg032;
526                pciercx_cfg032.u32 = cvmx_read_csr(CVMX_PCIERCX_CFG032(qlm));
527                switch (pciercx_cfg032.s.ls)
528                {
529                    case 1:
530                        return 2500;
531                    case 2:
532                        return 5000;
533                    case 4:
534                        return 8000;
535                    default:
536                    {
537                        cvmx_mio_rst_boot_t mio_rst_boot;
538                        mio_rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT);
539                        if ((qlm == 0) && mio_rst_boot.s.qlm0_spd == 0xf)
540                            return 0;
541                        if ((qlm == 1) && mio_rst_boot.s.qlm1_spd == 0xf)
542                            return 0;
543                        return 5000; /* Best guess I can make */
544                    }
545                }
546            }
547        }
548    }
549    else if (OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF71XX))
550    {
551        cvmx_mio_qlmx_cfg_t qlm_cfg;
552
553        qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm));
554        switch (qlm_cfg.s.qlm_spd)
555        {
556            case 0: return 5000;    /* 5     Gbaud */
557            case 1: return 2500;    /* 2.5   Gbaud */
558            case 2: return 2500;    /* 2.5   Gbaud */
559            case 3: return 1250;    /* 1.25  Gbaud */
560            case 4: return 1250;    /* 1.25  Gbaud */
561            case 5: return 6250;    /* 6.25  Gbaud */
562            case 6: return 5000;    /* 5     Gbaud */
563            case 7: return 2500;    /* 2.5   Gbaud */
564            case 8: return 3125;    /* 3.125 Gbaud */
565            case 9: return 2500;    /* 2.5   Gbaud */
566            case 10: return 1250;   /* 1.25  Gbaud */
567            case 11: return 5000;   /* 5     Gbaud */
568            case 12: return 6250;   /* 6.25  Gbaud */
569            case 13: return 3750;   /* 3.75  Gbaud */
570            case 14: return 3125;   /* 3.125 Gbaud */
571            default: return 0;      /* Disabled */
572        }
573    }
574    return 0;
575}
576#endif
577
578/*
579 * Read QLM and return status based on CN66XX.
580 * @return  Return 1 if QLM is SGMII
581 *                 2 if QLM is XAUI
582 *                 3 if QLM is PCIe gen2 / gen1
583 *                 4 if QLM is SRIO 1x4 short / long
584 *                 5 if QLM is SRIO 2x2 short / long
585 *                 6 if QLM is SRIO 4x1 short / long
586 *                 7 if QLM is PCIe 1x2 gen2 / gen1
587 *                 8 if QLM is PCIe 2x1 gen2 / gen1
588 *                 9 if QLM is ILK
589 *                 10 if QLM is RXAUI
590 *                 -1 otherwise
591 */
592int cvmx_qlm_get_status(int qlm)
593{
594    cvmx_mio_qlmx_cfg_t qlmx_cfg;
595
596    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
597    {
598        qlmx_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm));
599        /* QLM is disabled when QLM SPD is 15. */
600        if (qlmx_cfg.s.qlm_spd == 15)
601            return  -1;
602
603        switch (qlmx_cfg.s.qlm_cfg)
604        {
605            case 0: /* PCIE */
606                return 3;
607            case 1: /* ILK */
608                return 9;
609            case 2: /* SGMII */
610                return 1;
611            case 3: /* XAUI */
612                return 2;
613            case 7: /* RXAUI */
614                return 10;
615            default: return -1;
616        }
617    }
618    else if (OCTEON_IS_MODEL(OCTEON_CN66XX))
619    {
620        qlmx_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm));
621        /* QLM is disabled when QLM SPD is 15. */
622        if (qlmx_cfg.s.qlm_spd == 15)
623            return  -1;
624
625        switch (qlmx_cfg.s.qlm_cfg)
626        {
627            case 0x9: /* SGMII */
628                return 1;
629            case 0xb: /* XAUI */
630                return 2;
631            case 0x0: /* PCIE gen2 */
632            case 0x8: /* PCIE gen2 (alias) */
633            case 0x2: /* PCIE gen1 */
634            case 0xa: /* PCIE gen1 (alias) */
635                return 3;
636            case 0x1: /* SRIO 1x4 short */
637            case 0x3: /* SRIO 1x4 long */
638                return 4;
639            case 0x4: /* SRIO 2x2 short */
640            case 0x6: /* SRIO 2x2 long */
641                return 5;
642            case 0x5: /* SRIO 4x1 short */
643            case 0x7: /* SRIO 4x1 long */
644                if (!OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_0))
645                    return 6;
646            default:
647                return -1;
648        }
649    }
650    else if (OCTEON_IS_MODEL(OCTEON_CN63XX))
651    {
652        cvmx_sriox_status_reg_t status_reg;
653        /* For now skip qlm2 */
654        if (qlm == 2)
655        {
656            cvmx_gmxx_inf_mode_t inf_mode;
657            inf_mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(0));
658            if (inf_mode.s.speed == 15)
659                return -1;
660            else if(inf_mode.s.mode == 0)
661                return 1;
662            else
663                return 2;
664        }
665        status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(qlm));
666        if (status_reg.s.srio)
667            return 4;
668        else
669            return 3;
670    }
671    else if (OCTEON_IS_MODEL(OCTEON_CN61XX))
672    {
673        qlmx_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm));
674        /* QLM is disabled when QLM SPD is 15. */
675        if (qlmx_cfg.s.qlm_spd == 15)
676            return  -1;
677
678        switch(qlm)
679        {
680            case 0:
681                switch (qlmx_cfg.s.qlm_cfg)
682                {
683                    case 0: /* PCIe 1x4 gen2 / gen1 */
684                        return 3;
685                    case 2: /* SGMII */
686                        return 1;
687                    case 3: /* XAUI */
688                        return 2;
689                    default: return -1;
690                }
691                break;
692            case 1:
693                switch (qlmx_cfg.s.qlm_cfg)
694                {
695                    case 0: /* PCIe 1x2 gen2 / gen1 */
696                        return 7;
697                    case 1: /* PCIe 2x1 gen2 / gen1 */
698                        return 8;
699                    default: return -1;
700                }
701                break;
702            case 2:
703                switch (qlmx_cfg.s.qlm_cfg)
704                {
705                    case 2: /* SGMII */
706                        return 1;
707                    case 3: /* XAUI */
708                        return 2;
709                    default: return -1;
710                }
711                break;
712        }
713    }
714    else if (OCTEON_IS_MODEL(OCTEON_CNF71XX))
715    {
716        qlmx_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm));
717        /* QLM is disabled when QLM SPD is 15. */
718        if (qlmx_cfg.s.qlm_spd == 15)
719            return  -1;
720
721        switch(qlm)
722        {
723            case 0:
724                if (qlmx_cfg.s.qlm_cfg == 2) /* SGMII */
725                    return 1;
726                break;
727            case 1:
728                switch (qlmx_cfg.s.qlm_cfg)
729                {
730                    case 0: /* PCIe 1x2 gen2 / gen1 */
731                        return 7;
732                    case 1: /* PCIe 2x1 gen2 / gen1 */
733                        return 8;
734                    default: return -1;
735                }
736                break;
737        }
738    }
739    return -1;
740}
741