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