/** * Set a field in a QLM JTAG chain * * @param qlm QLM to set * @param lane Lane in QLM to set, or -1 for all lanes * @param name String name of field * @param value Value of the field */ void cvmx_qlm_jtag_set(int qlm, int lane, const char *name, uint64_t value) { int i, l; uint32_t shift_values[CVMX_QLM_JTAG_UINT32]; int num_lanes = cvmx_qlm_get_lanes(qlm); const __cvmx_qlm_jtag_field_t *field = __cvmx_qlm_lookup_field(name); int qlm_jtag_length = cvmx_qlm_jtag_get_length(); int total_length = qlm_jtag_length * num_lanes; int bits = 0; if (!field) return; /* Get the current state */ cvmx_helper_qlm_jtag_capture(qlm); for (i = 0; i < CVMX_QLM_JTAG_UINT32; i++) shift_values[i] = cvmx_helper_qlm_jtag_shift(qlm, 32, 0); /* Put new data in our local array */ for (l = 0; l < num_lanes; l++) { uint64_t new_value = value; int bits; int adj_lanes; if ((l != lane) && (lane != -1)) continue; if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) adj_lanes = l * qlm_jtag_length; else adj_lanes = (num_lanes - 1 - l) * qlm_jtag_length; for (bits = field->start_bit + adj_lanes; bits <= field->stop_bit + adj_lanes; bits++) { if (new_value & 1) shift_values[bits / 32] |= 1 << (bits & 31); else shift_values[bits / 32] &= ~(1 << (bits & 31)); new_value >>= 1; } } /* Shift out data and xor with reference */ while (bits < total_length) { uint32_t shift = shift_values[bits / 32] ^ __cvmx_qlm_jtag_xor_ref[qlm][bits / 32]; int width = total_length - bits; if (width > 32) width = 32; cvmx_helper_qlm_jtag_shift(qlm, width, shift); bits += 32; } /* Update the new data */ cvmx_helper_qlm_jtag_update(qlm); /* Always give the QLM 1ms to settle after every update. This may not always be needed, but some of the options make significant electrical changes */ cvmx_wait_usec(1000); }
/** * Get a field in a QLM JTAG chain * * @param qlm QLM to get * @param lane Lane in QLM to get * @param name String name of field * * @return JTAG field value */ uint64_t cvmx_qlm_jtag_get(int qlm, int lane, const char *name) { const __cvmx_qlm_jtag_field_t *field = __cvmx_qlm_lookup_field(name); int qlm_jtag_length = cvmx_qlm_jtag_get_length(); int num_lanes = cvmx_qlm_get_lanes(qlm); if (!field) return 0; /* Capture the current settings */ cvmx_helper_qlm_jtag_capture(qlm); /* Shift past lanes we don't care about. CN6XXX shifts lane 3 first */ cvmx_helper_qlm_jtag_shift_zeros(qlm, qlm_jtag_length * (num_lanes-1-lane)); /* Shift to the start of the field */ cvmx_helper_qlm_jtag_shift_zeros(qlm, field->start_bit); /* Shift out the value and return it */ return cvmx_helper_qlm_jtag_shift(qlm, field->stop_bit - field->start_bit + 1, 0); }