Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 19 Nov 2012 11:45:39 +0000 (UTC)
From:      Aleksandr Rybalko <ray@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r243273 - projects/efika_mx/sys/arm/freescale/imx
Message-ID:  <201211191145.qAJBjd3G045759@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ray
Date: Mon Nov 19 11:45:39 2012
New Revision: 243273
URL: http://svnweb.freebsd.org/changeset/base/243273

Log:
  Switch event timer to ET_FLAGS_ONESHOT mode.
  
  Sponsored by:	FreeBSD Foundation

Modified:
  projects/efika_mx/sys/arm/freescale/imx/imx_gpt.c

Modified: projects/efika_mx/sys/arm/freescale/imx/imx_gpt.c
==============================================================================
--- projects/efika_mx/sys/arm/freescale/imx/imx_gpt.c	Mon Nov 19 11:35:56 2012	(r243272)
+++ projects/efika_mx/sys/arm/freescale/imx/imx_gpt.c	Mon Nov 19 11:45:39 2012	(r243273)
@@ -81,10 +81,9 @@ static struct timecounter imx_gpt_timeco
 	.tc_get_timecount  = imx_gpt_get_timecount,
 	.tc_counter_mask   = ~0u,
 	.tc_frequency      = 0,
-	.tc_quality        = 1000,
+	.tc_quality        = 500,
 };
 
-static volatile uint32_t imx_gpt_base;
 struct imx_gpt_softc *imx_gpt_sc = NULL;
 static volatile int imx_gpt_delay_count = 300;
 
@@ -140,7 +139,6 @@ imx_gpt_attach(device_t dev)
 	default:
 		sc->clkfreq = imx51_get_clock(IMX51CLK_IPG_CLK_ROOT);
 	}
-
 	device_printf(dev, "Run on %dKHz clock.\n", sc->clkfreq / 1000);
 
 	/* Reset */
@@ -156,10 +154,13 @@ imx_gpt_attach(device_t dev)
 	/* Disable interrupts */
 	WRITE4(sc, IMX_GPT_IR, 0);
 
-	/* Tick every 1us */
-	WRITE4(sc, IMX_GPT_PR, 1);
+	/* Tick every 10us */
+	/* XXX: must be calculated from clock source frequency */
+	WRITE4(sc, IMX_GPT_PR, 665);
+	/* Use 100 KHz */
+	sc->clkfreq = 100000;
 
-	/* Setup and enable the timer */
+	/* Setup and enable the timer interrupt */
 	err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_CLK, imx_gpt_intr,
 	    NULL, sc, &sc->sc_ih);
 	if (err != 0) {
@@ -170,30 +171,28 @@ imx_gpt_attach(device_t dev)
 	}
 
 	sc->et.et_name = "i.MXxxx GPT Eventtimer";
-	sc->et.et_flags = ET_FLAGS_PERIODIC;
+	sc->et.et_flags = ET_FLAGS_ONESHOT;
 	sc->et.et_quality = 1000;
 	sc->et.et_frequency = sc->clkfreq;
 	sc->et.et_min_period.sec = 0;
 	sc->et.et_min_period.frac =
-            ((0x00000002LLU << 32) / sc->et.et_frequency) << 32;
+	    ((0x00000002LLU << 32) / sc->et.et_frequency) << 32;
 	sc->et.et_max_period.sec = 0xfffffff0U / sc->et.et_frequency;
 	sc->et.et_max_period.frac =
-            ((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32;
+	    ((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32;
 	sc->et.et_start = imx_gpt_timer_start;
 	sc->et.et_stop = imx_gpt_timer_stop;
 	sc->et.et_priv = sc;
 	et_register(&sc->et);
 
-	WRITE4(sc, IMX_GPT_OCR1, sc->sc_reload_value);
-
-	WRITE4(sc, IMX_GPT_SR, (GPT_IR_ROV << 1) - 1);
+	/* Disable interrupts */
 	WRITE4(sc, IMX_GPT_IR, 0);
+	/* ACK any panding interrupts */
+	WRITE4(sc, IMX_GPT_SR, (GPT_IR_ROV << 1) - 1);
 
-	/* i.MX515 has only one unit, but keep it to be safe */
 	if (device_get_unit(dev) == 0)
 	    imx_gpt_sc = sc;
 
-	sc->sc_reload_value = sc->clkfreq / hz - 1;
 	imx_gpt_timecounter.tc_frequency = sc->clkfreq;
 	tc_init(&imx_gpt_timecounter);
 
@@ -203,6 +202,8 @@ imx_gpt_attach(device_t dev)
 
 	imx_gpt_delay_count = imx51_get_clock(IMX51CLK_ARM_ROOT) / 4000000;
 
+	SET4(sc, IMX_GPT_CR, GPT_CR_EN);
+
 	return (0);
 }
 
@@ -210,8 +211,34 @@ static int
 imx_gpt_timer_start(struct eventtimer *et, struct bintime *first,
     struct bintime *period)
 {
+	struct imx_gpt_softc *sc;
+	uint32_t ticks;
 
-	return (0);
+	sc = (struct imx_gpt_softc *)et->et_priv;
+	if (first != NULL) {
+
+		ticks = (et->et_frequency * (first->frac >> 32)) >> 32;
+		if (first->sec != 0)
+			ticks += et->et_frequency * first->sec;
+
+		/*
+		 * TODO: setupt second compare reg with time which will save
+		 * us in case correct one lost, f.e. if period to short and
+		 * setup done later than counter reach target value.
+		 */
+		/* Do not disturb, otherwise event will be lost */
+		spinlock_enter();
+		/* Set expected value */
+		WRITE4(sc, IMX_GPT_OCR1, READ4(sc, IMX_GPT_CNT) + ticks);
+		/* Enable compare register 1 Interrupt */
+		SET4(sc, IMX_GPT_IR, GPT_IR_OF1);
+		/* Now everybody can relax */
+		spinlock_exit();
+
+		return (0);
+	}
+
+	return (EINVAL);
 }
 
 static int
@@ -221,7 +248,9 @@ imx_gpt_timer_stop(struct eventtimer *et
 
 	sc = (struct imx_gpt_softc *)et->et_priv;
 
-	CLEAR4(sc, IMX_GPT_CR, GPT_CR_EN);
+	/* Disable OF1 Interrupt */
+	CLEAR4(sc, IMX_GPT_IR, GPT_IR_OF1);
+	WRITE4(sc, IMX_GPT_SR, GPT_IR_OF1);
 
 	return (0);
 }
@@ -243,35 +272,32 @@ cpu_initclocks(void)
 
 	cpu_initclocks_bsp();
 
-	WRITE4(imx_gpt_sc, IMX_GPT_IR, GPT_IR_ALL);
-	SET4(imx_gpt_sc, IMX_GPT_CR, GPT_CR_EN);
-	/* Do DELAY using counter */
+	/* Switch to DELAY using counter */
 	imx_gpt_delay_count = 0;
-	device_printf(imx_gpt_sc->sc_dev, "switch DELAY to use H/W counter\n");
-
+	device_printf(imx_gpt_sc->sc_dev,
+	    "switch DELAY to use H/W counter\n");
 }
 
 static int
 imx_gpt_intr(void *arg)
 {
-	uint64_t ccount;
+	struct imx_gpt_softc *sc;
 	uint32_t status;
 
-	status = READ4(imx_gpt_sc, IMX_GPT_SR);
-	WRITE4(imx_gpt_sc, IMX_GPT_SR, GPT_IR_OF1);
+	sc = (struct imx_gpt_softc *)arg;
+
+	/* Sometime we not get staus bit when interrupt arrive.  Cache? */
+	while (!(status = READ4(sc, IMX_GPT_SR)))
+		;
 
 	if (status & GPT_IR_OF1) {
-		/* Realod compare register */
-		ccount = READ4(imx_gpt_sc, IMX_GPT_CNT);
-		ccount += imx_gpt_sc->sc_reload_value;
-		ccount &= 0xffffffff;
-		WRITE4(imx_gpt_sc, IMX_GPT_OCR1, ccount);
-
-		if (imx_gpt_sc->et.et_active)
-			imx_gpt_sc->et.et_event_cb(&imx_gpt_sc->et,
-			    imx_gpt_sc->et.et_arg);
+		if (sc->et.et_active) {
+			sc->et.et_event_cb(&sc->et, sc->et.et_arg);
+		}
 	}
-	/* TODO: other ints */
+
+	/* ACK */
+	WRITE4(sc, IMX_GPT_SR, status);
 
 	return (FILTER_HANDLED);
 }
@@ -279,14 +305,11 @@ imx_gpt_intr(void *arg)
 u_int
 imx_gpt_get_timecount(struct timecounter *tc)
 {
-	uint32_t counter;
 
 	if (imx_gpt_sc == NULL)
 		return (0);
 
-	counter = READ4(imx_gpt_sc, IMX_GPT_CNT);
-
-	return (imx_gpt_base + counter);
+	return (READ4(imx_gpt_sc, IMX_GPT_CNT));
 }
 
 static device_method_t imx_gpt_methods[] = {
@@ -310,25 +333,28 @@ void
 DELAY(int usec)
 {
 	int32_t counts;
-	uint64_t counts_per_usec, last;
+	uint32_t last;
 
-	/* Check the timers are setup, if not just use a for loop for the meantime */
+	/*
+	 * Check the timers are setup, if not just use a for loop for the
+	 * meantime.
+	 */
 	if (imx_gpt_delay_count) {
 		for (; usec > 0; usec--)
-			for (counts = imx_gpt_delay_count; counts > 0; counts--)
-				cpufunc_nullop();	/* Prevent gcc from optimizing
-							 * out the loop
-							 */
+			for (counts = imx_gpt_delay_count; counts > 0;
+			    counts--)
+				/* Prevent optimizing out the loop */
+				cpufunc_nullop();
 		return;
 	}
 
-	/* Get the number of times to count */
-	counts_per_usec = ((imx_gpt_timecounter.tc_frequency / 1000000) + 1);
-
-	last = imx_gpt_get_timecount(NULL) + usec * counts_per_usec;
+	/* At least 1 count */
+	usec = MAX(1, usec / 100);
 
-	while (imx_gpt_get_timecount(NULL) < last) {
-		cpufunc_nullop();	/* Prevent optimizing out the loop */
+	last = READ4(imx_gpt_sc, IMX_GPT_CNT) + usec;
+	while (READ4(imx_gpt_sc, IMX_GPT_CNT) < last) {
+		/* Prevent optimizing out the loop */
+		cpufunc_nullop();
 	}
 	/* TODO: use interrupt on OCR2 */
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201211191145.qAJBjd3G045759>