Exemplo n.º 1
0
/**
 * 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);
}
Exemplo n.º 2
0
/**
 * 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);
}
Exemplo n.º 3
0
/**
 * Initialize the QLM layer
 */
void cvmx_qlm_init(void)
{
    int qlm;
    int qlm_jtag_length;
    char *qlm_jtag_name = "cvmx_qlm_jtag";
    int qlm_jtag_size = CVMX_QLM_JTAG_UINT32 * 8 * 4;
    static uint64_t qlm_base = 0;
    const cvmx_bootmem_named_block_desc_t *desc;
    
#ifndef CVMX_BUILD_FOR_LINUX_HOST
    /* Skip actual JTAG accesses on simulator */
    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
        return;
#endif

    qlm_jtag_length = cvmx_qlm_jtag_get_length();

    if (4 * qlm_jtag_length > (int)sizeof(__cvmx_qlm_jtag_xor_ref[0]) * 8)
    {
        cvmx_dprintf("ERROR: cvmx_qlm_init: JTAG chain larger than XOR ref size\n");
        return;
    }

    /* No need to initialize the initial JTAG state if cvmx_qlm_jtag
       named block is already created. */
    if ((desc = cvmx_bootmem_find_named_block(qlm_jtag_name)) != NULL)
    {
#ifdef CVMX_BUILD_FOR_LINUX_HOST
        char buffer[qlm_jtag_size];

        octeon_remote_read_mem(buffer, desc->base_addr, qlm_jtag_size);
        memcpy(__cvmx_qlm_jtag_xor_ref, buffer, qlm_jtag_size);
#else
        __cvmx_qlm_jtag_xor_ref = cvmx_phys_to_ptr(desc->base_addr);
#endif
        /* Initialize the internal JTAG */
        cvmx_helper_qlm_jtag_init();
        return;
    }

    /* Create named block to store the initial JTAG state. */
    qlm_base = cvmx_bootmem_phy_named_block_alloc(qlm_jtag_size, 0, 0, 128, qlm_jtag_name, CVMX_BOOTMEM_FLAG_END_ALLOC);

    if (qlm_base == -1ull)
    {
        cvmx_dprintf("ERROR: cvmx_qlm_init: Error in creating %s named block\n", qlm_jtag_name);
        return;
    }

#ifndef CVMX_BUILD_FOR_LINUX_HOST
    __cvmx_qlm_jtag_xor_ref = cvmx_phys_to_ptr(qlm_base);
#endif
    memset(__cvmx_qlm_jtag_xor_ref, 0, qlm_jtag_size);

    /* Initialize the internal JTAG */
    cvmx_helper_qlm_jtag_init();

    /* Read the XOR defaults for the JTAG chain */
    for (qlm=0; qlm<cvmx_qlm_get_num(); qlm++)
    {
        int i;
        /* Capture the reset defaults */
        cvmx_helper_qlm_jtag_capture(qlm);
        /* Save the reset defaults. This will shift out too much data, but
           the extra zeros don't hurt anything */
        for (i=0; i<CVMX_QLM_JTAG_UINT32; i++)
            __cvmx_qlm_jtag_xor_ref[qlm][i] = cvmx_helper_qlm_jtag_shift(qlm, 32, 0);
    }

#ifdef CVMX_BUILD_FOR_LINUX_HOST
    /* Update the initial state for oct-remote utils. */
    {
        char buffer[qlm_jtag_size];

        memcpy(buffer, &__cvmx_qlm_jtag_xor_ref, qlm_jtag_size);
        octeon_remote_write_mem(qlm_base, buffer, qlm_jtag_size);
    }
#endif

    /* Apply speed tweak as a workaround for errata G-16094. */
    __cvmx_qlm_speed_tweak();
    __cvmx_qlm_pcie_idle_dac_tweak();
}