Exemple #1
0
/**
 * Due to errata G-720, the 2nd order CDR circuit on CN52XX pass
 * 1 doesn't work properly. The following code disables 2nd order
 * CDR for the specified QLM.
 *
 * @param qlm    QLM to disable 2nd order CDR for.
 */
void __cvmx_helper_errata_qlm_disable_2nd_order_cdr(int qlm)
{
	int lane;
	/* Apply the workaround only once. */
	cvmx_ciu_qlm_jtgd_t qlm_jtgd;
	qlm_jtgd.u64 = cvmx_read_csr(CVMX_CIU_QLM_JTGD);
	if (qlm_jtgd.s.select != 0)
		return;

	cvmx_helper_qlm_jtag_init();
	/* We need to load all four lanes of the QLM, a total of 1072 bits */
	for (lane = 0; lane < 4; lane++) {
		/*
		 * Each lane has 268 bits. We need to set
		 * cfg_cdr_incx<67:64> = 3 and
		 * cfg_cdr_secord<77> = 1.
		 * All other bits are zero. Bits go in LSB first,
		 * so start off with the zeros for bits <63:0>.
		 */
		cvmx_helper_qlm_jtag_shift_zeros(qlm, 63 - 0 + 1);
		/* cfg_cdr_incx<67:64>=3 */
		cvmx_helper_qlm_jtag_shift(qlm, 67 - 64 + 1, 3);
		/* Zeros for bits <76:68> */
		cvmx_helper_qlm_jtag_shift_zeros(qlm, 76 - 68 + 1);
		/* cfg_cdr_secord<77>=1 */
		cvmx_helper_qlm_jtag_shift(qlm, 77 - 77 + 1, 1);
		/* Zeros for bits <267:78> */
		cvmx_helper_qlm_jtag_shift_zeros(qlm, 267 - 78 + 1);
	}
	cvmx_helper_qlm_jtag_update(qlm);
}
Exemple #2
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);
}
void __cvmx_helper_errata_qlm_disable_2nd_order_cdr(int qlm)
{
	int lane;
	cvmx_helper_qlm_jtag_init();
	
	for (lane = 0; lane < 4; lane++) {
		cvmx_helper_qlm_jtag_shift_zeros(qlm, 63 - 0 + 1);
		
		cvmx_helper_qlm_jtag_shift(qlm, 67 - 64 + 1, 3);
		
		cvmx_helper_qlm_jtag_shift_zeros(qlm, 76 - 68 + 1);
		
		cvmx_helper_qlm_jtag_shift(qlm, 77 - 77 + 1, 1);
		
		cvmx_helper_qlm_jtag_shift_zeros(qlm, 267 - 78 + 1);
	}
	cvmx_helper_qlm_jtag_update(qlm);
}
/**
 * Due to errata G-720, the 2nd order CDR circuit on CN52XX pass
 * 1 doesn't work properly. The following code disables 2nd order
 * CDR for the specified QLM.
 *
 * @qlm:    QLM to disable 2nd order CDR for.
 */
void __cvmx_helper_errata_qlm_disable_2nd_order_cdr(int qlm)
{
	int lane;
	cvmx_helper_qlm_jtag_init();
	/* We need to load all four lanes of the QLM, a total of 1072 bits */
	for (lane = 0; lane < 4; lane++) {
		/*
		 * Each lane has 268 bits. We need to set
		 * cfg_cdr_incx<67:64> = 3 and cfg_cdr_secord<77> =
		 * 1. All other bits are zero. Bits go in LSB first,
		 * so start off with the zeros for bits <63:0>.
		 */
		cvmx_helper_qlm_jtag_shift_zeros(qlm, 63 - 0 + 1);
		/* cfg_cdr_incx<67:64>=3 */
		cvmx_helper_qlm_jtag_shift(qlm, 67 - 64 + 1, 3);
		/* Zeros for bits <76:68> */
		cvmx_helper_qlm_jtag_shift_zeros(qlm, 76 - 68 + 1);
		/* cfg_cdr_secord<77>=1 */
		cvmx_helper_qlm_jtag_shift(qlm, 77 - 77 + 1, 1);
		/* Zeros for bits <267:78> */
		cvmx_helper_qlm_jtag_shift_zeros(qlm, 267 - 78 + 1);
	}
	cvmx_helper_qlm_jtag_update(qlm);
}
Exemple #5
0
int checkboard(void)
{
    int core_mVolts, dram_mVolts;

    debug("In %s\n", __func__);

    if (octeon_show_info()) {

        int mcu_rev_maj = 0;
        int mcu_rev_min = 0;

        if (twsii_mcu_read(0x00) == 0xa5
                && twsii_mcu_read(0x01) == 0x5a) {
            gd->arch.mcu_rev_maj = mcu_rev_maj = twsii_mcu_read(2);
            gd->arch.mcu_rev_min = mcu_rev_min = twsii_mcu_read(3);
        }

        core_mVolts = read_ispPAC_mvolts_avg(10, BOARD_ISP_TWSI_ADDR, 8);
        dram_mVolts = read_ispPAC_mvolts_avg(10, BOARD_ISP_TWSI_ADDR, 7);

        char mcu_ip_msg[64] = { 0 };

        if (twsii_mcu_read(0x14) == 1)
            sprintf(mcu_ip_msg, "MCU IPaddr: %d.%d.%d.%d, ",
                    twsii_mcu_read(0x10),
                    twsii_mcu_read(0x11),
                    twsii_mcu_read(0x12), twsii_mcu_read(0x13));
        printf("MCU rev: %d.%02d, %sCPU voltage: %d.%03d DDR voltage: %d.%03d\n",
               gd->arch.mcu_rev_maj, gd->arch.mcu_rev_min, mcu_ip_msg,
               core_mVolts / 1000, core_mVolts % 1000,
               dram_mVolts / 1000, dram_mVolts % 1000);

#define LED_CHARACTERS 8
        char tmp[10];
        int characters, idx = 0, value = core_mVolts;

        idx = sprintf(tmp, "%lu ", gd->cpu_clk);
        characters = LED_CHARACTERS - idx;

        if (value / 1000) {
            idx += sprintf(tmp + idx, "%d", value / 1000);
            characters = LED_CHARACTERS - idx;
        }

        characters -= 1;	/* Account for decimal point */

        value %= 1000;
        value = DIV_ROUND_UP(value, ipow(10, max(3 - characters, 0)));

        idx += sprintf(tmp + idx, ".%0*d", min(3, characters), value);

        /* Display CPU speed and voltage on display */
        octeon_led_str_write(tmp);
    } else {
        octeon_led_str_write("Boot    ");
    }

#if 0				/* DEBUG use only */
    {

        char *eptr = getenv("jtag_ic50");
        if (eptr) {
            /* Do experimental JTAG changes for pass 1.1 */
            int qlm_num;

            int ic50_val = simple_strtol(eptr, NULL, 10);
            int ir50_val = ic50_val;
            eptr = getenv("jtag_ir50");

            if (eptr)
                ir50_val = simple_strtol(eptr, NULL, 10);
            else
                puts("Warning: jtag_ir50 val not set, using ic50 value\n");

            printf("Setting QLM DAC ir50=0x%x, ic50=0x%x via JTAG chain\n",
                   ir50_val, ic50_val);

            /* New ss are xored with default values, which are 0x11 */
            ic50_val ^= 0x11;
            ir50_val ^= 0x11;

            cvmx_helper_qlm_jtag_init();
            for (qlm_num = 0; qlm_num < 3; qlm_num++) {
                cvmx_helper_qlm_jtag_shift_zeros(qlm_num, 34);
                cvmx_helper_qlm_jtag_shift(qlm_num, 5, ir50_val);	/* ir50dac */
                cvmx_helper_qlm_jtag_shift(qlm_num, 5, ic50_val);	/* ic50dac */
                cvmx_helper_qlm_jtag_shift_zeros(qlm_num,
                                                 300 - 44);
                cvmx_helper_qlm_jtag_shift_zeros(qlm_num, 34);
                cvmx_helper_qlm_jtag_shift(qlm_num, 5, ir50_val);	/* ir50dac */
                cvmx_helper_qlm_jtag_shift(qlm_num, 5, ic50_val);	/* ic50dac */
                cvmx_helper_qlm_jtag_shift_zeros(qlm_num,
                                                 300 - 44);
                cvmx_helper_qlm_jtag_shift_zeros(qlm_num, 34);
                cvmx_helper_qlm_jtag_shift(qlm_num, 5, ir50_val);	/* ir50dac */
                cvmx_helper_qlm_jtag_shift(qlm_num, 5, ic50_val);	/* ic50dac */
                cvmx_helper_qlm_jtag_shift_zeros(qlm_num,
                                                 300 - 44);
                cvmx_helper_qlm_jtag_shift_zeros(qlm_num, 34);
                cvmx_helper_qlm_jtag_shift(qlm_num, 5, ir50_val);	/* ir50dac */
                cvmx_helper_qlm_jtag_shift(qlm_num, 5, ic50_val);	/* ic50dac */
                cvmx_helper_qlm_jtag_shift_zeros(qlm_num,
                                                 300 - 44);
                cvmx_helper_qlm_jtag_update(qlm_num);
            }
        }
    }
#endif
    return 0;
}
Exemple #6
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 * sizeof(uint32_t);
	static uint64_t qlm_base = 0;
	const cvmx_bootmem_named_block_desc_t *desc;

	if (OCTEON_IS_OCTEON3())
		return;

#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 (sizeof(uint32_t) * 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;
		int num_lanes = cvmx_qlm_get_lanes(qlm);
		/* Shift all zeros in the chain to make sure all fields are at
		   reset defaults */
		cvmx_helper_qlm_jtag_shift_zeros(qlm, qlm_jtag_length * num_lanes);
		cvmx_helper_qlm_jtag_update(qlm);

		/* 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 all QLM errata workarounds. */
	__cvmx_qlm_speed_tweak();
	__cvmx_qlm_pcie_idle_dac_tweak();
}