Exemplo n.º 1
0
void
au_cal_timers(bus_space_tag_t st, bus_space_handle_t sh)
{
	uint32_t ctrdiff[4], startctr, endctr;
	uint32_t ctl, ctr, octr;
	int i;

	/* Enable the programmable counter 1. */
	ctl = bus_space_read_4(st, sh, PC_COUNTER_CONTROL);
	if ((ctl & (CC_EO | CC_EN1)) != (CC_EO | CC_EN1));
		SET_PC_REG(PC_COUNTER_CONTROL, 0, ctl | CC_EO | CC_EN1);

	/* Initialize for 16Hz. */
	SET_PC_REG(PC_TRIM1, CC_T1S, PC_RATE / 16 - 1);

	/* Run the loop an extra time to prime the cache. */
	for (i = 0; i < 4; i++) {
		/* Reset the counter. */
		SET_PC_REG(PC_COUNTER_WRITE1, CC_C1S, 0);

		/* Wait for 1/16th of a second. */
		//startctr = mips3_cp0_count_read();

		/* Wait for the PC to tick over. */
		ctr = bus_space_read_4(st, sh, PC_COUNTER_READ_1);
		do {
			octr = bus_space_read_4(st, sh, PC_COUNTER_READ_1);
		} while (ctr == octr);

		startctr = mips3_cp0_count_read();
		do {
			ctr = bus_space_read_4(st, sh, PC_COUNTER_READ_1);
		} while (ctr == octr);	// while (ctr <= octr + 1);
		endctr = mips3_cp0_count_read();
		ctrdiff[i] = endctr - startctr;
	}

	/* Disable the counter (if it wasn't enabled already). */
	if ((ctl & (CC_EO | CC_EN1)) != (CC_EO | CC_EN1));
		SET_PC_REG(PC_COUNTER_CONTROL, 0, ctl);

	/* Compute the number of cycles per second. */
	curcpu()->ci_cpu_freq = ((ctrdiff[2] + ctrdiff[3]) / 2) * 16;

	/* Compute the number of ticks for hz. */
	curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz;

	/* Compute the delay divisor. */
	curcpu()->ci_divisor_delay =
	    ((curcpu()->ci_cpu_freq + 500000) / 1000000);

	/*
	 * To implement a more accurate microtime using the CP0 COUNT
	 * register we need to divide that register by the number of
	 * cycles per MHz.  But...
	 *
	 * DIV and DIVU are expensive on MIPS (eg 75 clocks on the
	 * R4000).  MULT and MULTU are only 12 clocks on the same CPU.
	 * On the SB1 these appear to be 40-72 clocks for DIV/DIVU and 3
	 * clocks for MUL/MULTU.
	 *
	 * The strategy we use to to calculate the reciprical of cycles
	 * per MHz, scaled by 1<<32.  Then we can simply issue a MULTU
	 * and pluck of the HI register and have the results of the
	 * division.
	 */
	curcpu()->ci_divisor_recip =
	    0x100000000ULL / curcpu()->ci_divisor_delay;

	/*
	 * Get correct cpu frequency if the CPU runs at twice the
	 * external/cp0-count frequency.
	 */
	if (mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT)
		curcpu()->ci_cpu_freq *= 2;

#ifdef DEBUG
	printf("Timer calibration: %lu cycles/sec [(%u, %u) * 16]\n",
	    curcpu()->ci_cpu_freq, ctrdiff[2], ctrdiff[3]);
#endif
}
Exemplo n.º 2
0
void
au_cal_timers(bus_space_tag_t st, bus_space_handle_t sh)
{
	struct cpu_info * const ci = curcpu();
	uint32_t ctrdiff[4], startctr, endctr;
	uint32_t ctl, ctr, octr;
	int i;

	/* Enable the programmable counter 1. */
	ctl = bus_space_read_4(st, sh, PC_COUNTER_CONTROL);
	if ((ctl & (CC_EO | CC_EN1)) != (CC_EO | CC_EN1))
		SET_PC_REG(PC_COUNTER_CONTROL, 0, ctl | CC_EO | CC_EN1);

	/* Initialize for 16Hz. */
	SET_PC_REG(PC_TRIM1, CC_T1S, PC_RATE / 16 - 1);

	/* Run the loop an extra time to prime the cache. */
	for (i = 0; i < 4; i++) {
		/* Reset the counter. */
		SET_PC_REG(PC_COUNTER_WRITE1, CC_C1S, 0);

		/* Wait for 1/16th of a second. */
		//startctr = mips3_cp0_count_read();

		/* Wait for the PC to tick over. */
		ctr = bus_space_read_4(st, sh, PC_COUNTER_READ_1);
		do {
			octr = bus_space_read_4(st, sh, PC_COUNTER_READ_1);
		} while (ctr == octr);

		startctr = mips3_cp0_count_read();
		do {
			ctr = bus_space_read_4(st, sh, PC_COUNTER_READ_1);
		} while (ctr == octr);	// while (ctr <= octr + 1);
		endctr = mips3_cp0_count_read();
		ctrdiff[i] = endctr - startctr;
	}

	/* Disable the counter (if it wasn't enabled already). */
	if ((ctl & (CC_EO | CC_EN1)) != (CC_EO | CC_EN1))
		SET_PC_REG(PC_COUNTER_CONTROL, 0, ctl);

	/* Compute the number of cycles per second. */
	ci->ci_cpu_freq = ((ctrdiff[2] + ctrdiff[3]) / 2) * 16;
	ci->ci_cctr_freq = ci->ci_cpu_freq;

	/* Compute the number of ticks for hz. */
	ci->ci_cycles_per_hz = (ci->ci_cpu_freq + hz / 2) / hz;

	/* Compute the delay divisor. */
	ci->ci_divisor_delay = (ci->ci_cpu_freq + 500000) / 1000000;

	/*
	 * Get correct cpu frequency if the CPU runs at twice the
	 * external/cp0-count frequency.
	 */
	if (mips_options.mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT)
		ci->ci_cpu_freq *= 2;

#ifdef DEBUG
	printf("Timer calibration: %lu cycles/sec [(%u, %u) * 16]\n",
	    ci->ci_cpu_freq, ctrdiff[2], ctrdiff[3]);
#endif
}