Ejemplo n.º 1
0
void
cpu_initclocks(void)
{
	struct cpu_info * const ci = curcpu();
	uint32_t cnt;

	static struct timecounter tc =  {
		ingenic_count_read,		/* get_timecount */
		0,				/* no poll_pps */
		~0u,				/* counter_mask */
		12000000,			/* frequency */
		"Ingenic OS timer",		/* name */
		100,				/* quality */
	};

	curcpu()->ci_cctr_freq = tc.tc_frequency;

	tc_init(&tc);

	printf("starting timer interrupt...\n");
	/* start the timer interrupt */
	cnt = readreg(JZ_OST_CNT_LO);
	ci->ci_next_cp0_clk_intr = cnt + ci->ci_cycles_per_hz;
	writereg(JZ_TC_TFCR, TFR_OSTFLAG);
	writereg(JZ_OST_DATA, ci->ci_next_cp0_clk_intr);
	/*
	 * XXX
	 * We can use OST or one of the regular timers to generate the 100hz
	 * interrupt. OST interrupts need to be rescheduled every time and by
	 * only one core, the regular timer can be programmed to fire every
	 * 10ms without rescheduling and we'd still use the OST as time base.
	 * OST is supposed to fire on INT2 although I haven't been able to get
	 * that to work yet ( all I get is INT0 which is for hardware interrupts
	 * in general )
	 * So if we can get OST to fire on INT2 we can just block INT0 on core1
	 * and have a timer interrupt on both cores, if not the regular timer 
	 * would be more convenient but we'd have to shoot an IPI to core1 on
	 * every tick.
	 * For now, use OST and hope we'll figure out how to make it fire on
	 * INT2.
	 */
#ifdef USE_OST
	writereg(JZ_TC_TMCR, TFR_OSTFLAG);
#else
	writereg(JZ_TC_TECR, TESR_TCST5);	/* disable timer 5 */
	writereg(JZ_TC_TCNT(5), 0);
	writereg(JZ_TC_TDFR(5), 30000);	/* 10ms at 48MHz / 16 */
	writereg(JZ_TC_TDHR(5), 60000);	/* not reached */
	writereg(JZ_TC_TCSR(5), TCSR_EXT_EN| TCSR_DIV_16);
	writereg(JZ_TC_TMCR, TFR_FFLAG5);
	writereg(JZ_TC_TFCR, TFR_FFLAG5);
	writereg(JZ_TC_TESR, TESR_TCST5);	/* enable timer 5 */
#endif

#ifdef INGENIC_CLOCK_DEBUG
	printf("INTC %08x %08x\n", readreg(JZ_ICSR0), readreg(JZ_ICSR1));
	printf("ICMR0 %08x\n", readreg(JZ_ICMR0));
#endif
	writereg(JZ_ICMCR0, 0x0c000000); /* TCU2, OST */
	spl0();
#ifdef INGENIC_CLOCK_DEBUG
	printf("TFR: %08x\n", readreg(JZ_TC_TFR));
	printf("TMR: %08x\n", readreg(JZ_TC_TMR));
	printf("cnt5: %08x\n", readreg(JZ_TC_TCNT(5)));
	printf("CR: %08x\n", MFC0(MIPS_COP_0_CAUSE, 0));
	printf("SR: %08x\n", MFC0(MIPS_COP_0_STATUS, 0));
	delay(100000);
	printf("TFR: %08x\n", readreg(JZ_TC_TFR));
	printf("TMR: %08x\n", readreg(JZ_TC_TMR));
	printf("cnt5: %08x\n", readreg(JZ_TC_TCNT(5)));
	printf("CR: %08x\n", MFC0(MIPS_COP_0_CAUSE, 0));
	printf("SR: %08x\n", MFC0(MIPS_COP_0_STATUS, 0));
	printf("TFR: %08x\n", readreg(JZ_TC_TFR));
	printf("TMR: %08x\n", readreg(JZ_TC_TMR));
	printf("cnt5: %08x\n", readreg(JZ_TC_TCNT(5)));
	printf("CR: %08x\n", MFC0(MIPS_COP_0_CAUSE, 0));
	printf("SR: %08x\n", MFC0(MIPS_COP_0_STATUS, 0));
	
	printf("INTC %08x %08x\n", readreg(JZ_ICSR0), readreg(JZ_ICSR1));
	delay(3000000);
	printf("%s %d\n", __func__, MFC0(12, 3));
	printf("%s %08x\n", __func__, MFC0(12, 4));
#endif
}
Ejemplo n.º 2
0
static int
jz4780_timer_attach(device_t dev)
{
	struct jz4780_timer_softc *sc = device_get_softc(dev);
	pcell_t counter_freq;
	clk_t clk;

	/* There should be exactly one instance. */
	if (jz4780_timer_sc != NULL)
		return (ENXIO);

	sc->dev = dev;

	if (bus_alloc_resources(dev, jz4780_timer_spec, sc->res)) {
		device_printf(dev, "can not allocate resources for device\n");
		return (ENXIO);
	}

	counter_freq = 0;
	if (clk_get_by_name(dev, "ext", &clk) == 0) {
		uint64_t clk_freq;

		if (clk_get_freq(clk, &clk_freq) == 0)
			counter_freq = (uint32_t)clk_freq / 16;
		clk_release(clk);
	}
	if (counter_freq == 0) {
		device_printf(dev, "unable to determine ext clock frequency\n");
		/* Hardcode value we 'know' is correct */
		counter_freq = 48000000 / 16;
	}

	/*
	 * Disable the timers, select the input for each timer,
	 * clear and then start OST.
	 */

	/* Stop OST, if it happens to be running */
	CSR_WRITE_4(sc, JZ_TC_TECR, TESR_OST);
	/* Stop all other channels as well */
	CSR_WRITE_4(sc, JZ_TC_TECR, TESR_TCST0 | TESR_TCST1 | TESR_TCST2 |
	    TESR_TCST3 | TESR_TCST4 | TESR_TCST5 | TESR_TCST6 | TESR_TCST3);
	/* Clear detect mask flags */
	CSR_WRITE_4(sc, JZ_TC_TFCR, 0xFFFFFFFF);
	/* Mask all interrupts */
	CSR_WRITE_4(sc, JZ_TC_TMSR, 0xFFFFFFFF);

	/* Init counter with known data */
	CSR_WRITE_4(sc, JZ_OST_CTRL, 0);
	CSR_WRITE_4(sc, JZ_OST_CNT_LO, 0);
	CSR_WRITE_4(sc, JZ_OST_CNT_HI, 0);
	CSR_WRITE_4(sc, JZ_OST_DATA, 0xffffffff);

	/* Configure counter for external clock */
	CSR_WRITE_4(sc, JZ_OST_CTRL, OSTC_EXT_EN | OSTC_MODE | OSTC_DIV_16);

	/* Start the counter again */
	CSR_WRITE_4(sc, JZ_TC_TESR, TESR_OST);

	/* Configure TCU channel 5 similarly to OST and leave it disabled */
	CSR_WRITE_4(sc, JZ_TC_TCSR(5), TCSR_EXT_EN | TCSR_DIV_16);
	CSR_WRITE_4(sc, JZ_TC_TMCR, TMR_FMASK(5));

	if (bus_setup_intr(dev, sc->res[2], INTR_TYPE_CLK,
	    jz4780_hardclock, NULL, sc, &sc->ih_cookie)) {
		device_printf(dev, "could not setup interrupt handler\n");
		bus_release_resources(dev, jz4780_timer_spec, sc->res);
		return (ENXIO);
	}

	sc->et.et_name = "JZ4780 TCU5";
	sc->et.et_flags = ET_FLAGS_ONESHOT;
	sc->et.et_frequency = counter_freq;
	sc->et.et_quality = 1000;
	sc->et.et_min_period = (0x00000002LLU * SBT_1S) / sc->et.et_frequency;
	sc->et.et_max_period = (0x0000fffeLLU * SBT_1S) / sc->et.et_frequency;
	sc->et.et_start = jz4780_timer_start;
	sc->et.et_stop = jz4780_timer_stop;
	sc->et.et_priv = sc;

	et_register(&sc->et);

	sc->tc.tc_get_timecount = jz4780_get_timecount;
	sc->tc.tc_name = "JZ4780 OST";
	sc->tc.tc_frequency = counter_freq;
	sc->tc.tc_counter_mask = ~0u;
	sc->tc.tc_quality = 1000;
	sc->tc.tc_priv = sc;

	tc_init(&sc->tc);

	/* Now when tc is initialized, allow DELAY to find it */
	jz4780_timer_sc = sc;

	return (0);
}