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