1 2/***********************license start*************** 3 * Author: Cavium Networks 4 * 5 * Contact: support@caviumnetworks.com 6 * This file is part of the OCTEON SDK 7 * 8 * Copyright (c) 2003-2008 Cavium Networks 9 * 10 * This file is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License, Version 2, as 12 * published by the Free Software Foundation. 13 * 14 * This file is distributed in the hope that it will be useful, but 15 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty 16 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or 17 * NONINFRINGEMENT. See the GNU General Public License for more 18 * details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this file; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 * or visit http://www.gnu.org/licenses/. 24 * 25 * This file may also be available under a different license from Cavium. 26 * Contact Cavium Networks for more information 27 ***********************license end**************************************/ 28 29/** 30 * 31 * Helper utilities for qlm_jtag. 32 * 33 */ 34 35#include <asm/octeon/octeon.h> 36#include <asm/octeon/cvmx-helper-jtag.h> 37 38 39/** 40 * Initialize the internal QLM JTAG logic to allow programming 41 * of the JTAG chain by the cvmx_helper_qlm_jtag_*() functions. 42 * These functions should only be used at the direction of Cavium 43 * Networks. Programming incorrect values into the JTAG chain 44 * can cause chip damage. 45 */ 46void cvmx_helper_qlm_jtag_init(void) 47{ 48 union cvmx_ciu_qlm_jtgc jtgc; 49 uint32_t clock_div = 0; 50 uint32_t divisor = cvmx_sysinfo_get()->cpu_clock_hz / (25 * 1000000); 51 divisor = (divisor - 1) >> 2; 52 /* Convert the divisor into a power of 2 shift */ 53 while (divisor) { 54 clock_div++; 55 divisor = divisor >> 1; 56 } 57 58 /* 59 * Clock divider for QLM JTAG operations. eclk is divided by 60 * 2^(CLK_DIV + 2) 61 */ 62 jtgc.u64 = 0; 63 jtgc.s.clk_div = clock_div; 64 jtgc.s.mux_sel = 0; 65 if (OCTEON_IS_MODEL(OCTEON_CN52XX)) 66 jtgc.s.bypass = 0x3; 67 else 68 jtgc.s.bypass = 0xf; 69 cvmx_write_csr(CVMX_CIU_QLM_JTGC, jtgc.u64); 70 cvmx_read_csr(CVMX_CIU_QLM_JTGC); 71} 72 73/** 74 * Write up to 32bits into the QLM jtag chain. Bits are shifted 75 * into the MSB and out the LSB, so you should shift in the low 76 * order bits followed by the high order bits. The JTAG chain is 77 * 4 * 268 bits long, or 1072. 78 * 79 * @qlm: QLM to shift value into 80 * @bits: Number of bits to shift in (1-32). 81 * @data: Data to shift in. Bit 0 enters the chain first, followed by 82 * bit 1, etc. 83 * 84 * Returns The low order bits of the JTAG chain that shifted out of the 85 * circle. 86 */ 87uint32_t cvmx_helper_qlm_jtag_shift(int qlm, int bits, uint32_t data) 88{ 89 union cvmx_ciu_qlm_jtgd jtgd; 90 jtgd.u64 = 0; 91 jtgd.s.shift = 1; 92 jtgd.s.shft_cnt = bits - 1; 93 jtgd.s.shft_reg = data; 94 if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)) 95 jtgd.s.select = 1 << qlm; 96 cvmx_write_csr(CVMX_CIU_QLM_JTGD, jtgd.u64); 97 do { 98 jtgd.u64 = cvmx_read_csr(CVMX_CIU_QLM_JTGD); 99 } while (jtgd.s.shift); 100 return jtgd.s.shft_reg >> (32 - bits); 101} 102 103/** 104 * Shift long sequences of zeros into the QLM JTAG chain. It is 105 * common to need to shift more than 32 bits of zeros into the 106 * chain. This function is a convience wrapper around 107 * cvmx_helper_qlm_jtag_shift() to shift more than 32 bits of 108 * zeros at a time. 109 * 110 * @qlm: QLM to shift zeros into 111 * @bits: 112 */ 113void cvmx_helper_qlm_jtag_shift_zeros(int qlm, int bits) 114{ 115 while (bits > 0) { 116 int n = bits; 117 if (n > 32) 118 n = 32; 119 cvmx_helper_qlm_jtag_shift(qlm, n, 0); 120 bits -= n; 121 } 122} 123 124/** 125 * Program the QLM JTAG chain into all lanes of the QLM. You must 126 * have already shifted in 268*4, or 1072 bits into the JTAG 127 * chain. Updating invalid values can possibly cause chip damage. 128 * 129 * @qlm: QLM to program 130 */ 131void cvmx_helper_qlm_jtag_update(int qlm) 132{ 133 union cvmx_ciu_qlm_jtgd jtgd; 134 135 /* Update the new data */ 136 jtgd.u64 = 0; 137 jtgd.s.update = 1; 138 if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)) 139 jtgd.s.select = 1 << qlm; 140 cvmx_write_csr(CVMX_CIU_QLM_JTGD, jtgd.u64); 141 do { 142 jtgd.u64 = cvmx_read_csr(CVMX_CIU_QLM_JTGD); 143 } while (jtgd.s.update); 144} 145