Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 8 Nov 2012 12:50:11 +0000 (UTC)
From:      Aleksandr Rybalko <ray@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r242761 - projects/efika_mx/sys/arm/freescale/imx
Message-ID:  <201211081250.qA8CoBWh073641@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ray
Date: Thu Nov  8 12:50:11 2012
New Revision: 242761
URL: http://svnweb.freebsd.org/changeset/base/242761

Log:
  General Purpose Timer (GPT) driver.

Added:
  projects/efika_mx/sys/arm/freescale/imx/imx_gpt.c
  projects/efika_mx/sys/arm/freescale/imx/imx_gptreg.h
  projects/efika_mx/sys/arm/freescale/imx/imx_gptvar.h

Added: projects/efika_mx/sys/arm/freescale/imx/imx_gpt.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/efika_mx/sys/arm/freescale/imx/imx_gpt.c	Thu Nov  8 12:50:11 2012	(r242761)
@@ -0,0 +1,333 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Oleksandr Rybalko under sponsorship
+ * from the FreeBSD Foundation.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.	Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2.	Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/timeet.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <arm/freescale/imx/imx_gptvar.h>
+#include <arm/freescale/imx/imx_gptreg.h>
+
+#include <sys/kdb.h>
+#include <arm/freescale/imx/imx51_ccmvar.h>
+
+#define	WRITE4(_sc, _r, _v)						\
+	    bus_space_write_4((_sc)->sc_iot, (_sc)->sc_ioh, (_r), (_v))
+#define	READ4(_sc, _r)							\
+	    bus_space_read_4((_sc)->sc_iot, (_sc)->sc_ioh, (_r))
+#define	SET4(_sc, _r, _m)						\
+	    WRITE4((_sc), (_r), READ4((_sc), (_r)) | (_m))
+#define	CLEAR4(_sc, _r, _m)						\
+	    WRITE4((_sc), (_r), READ4((_sc), (_r)) & ~(_m))
+
+static u_int	imx_gpt_get_timecount(struct timecounter *);
+static int	imx_gpt_timer_start(struct eventtimer *,
+    struct bintime *, struct bintime *);
+static int	imx_gpt_timer_stop(struct eventtimer *);
+
+static int imx_gpt_intr(void *);
+static int imx_gpt_probe(device_t);
+static int imx_gpt_attach(device_t);
+
+static struct timecounter imx_gpt_timecounter = {
+	.tc_name           = "i.MX GPT Timecouter",
+	.tc_get_timecount  = imx_gpt_get_timecount,
+	.tc_counter_mask   = ~0u,
+	.tc_frequency      = 0,
+	.tc_quality        = 1000,
+};
+
+static volatile uint32_t imx_gpt_base;
+struct imx_gpt_softc *imx_gpt_sc = NULL;
+static volatile int imx_gpt_delay_count = 300;
+
+static struct resource_spec imx_gpt_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+static int
+imx_gpt_probe(device_t dev)
+{
+
+	if (!ofw_bus_is_compatible(dev, "fsl,imx51-gpt"))
+		return (ENXIO);
+
+	device_set_desc(dev, "Freescale i.MXxxx GPT timer");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+imx_gpt_attach(device_t dev)
+{
+	struct imx_gpt_softc *sc;
+	int err;
+
+	sc = device_get_softc(dev);
+
+	if (bus_alloc_resources(dev, imx_gpt_spec, sc->res)) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	sc->sc_dev = dev;
+	sc->sc_clksrc = GPT_CR_CLKSRC_IPG;
+	sc->sc_iot = rman_get_bustag(sc->res[0]);
+	sc->sc_ioh = rman_get_bushandle(sc->res[0]);
+
+	switch (sc->sc_clksrc) {
+	case GPT_CR_CLKSRC_NONE:
+		device_printf(dev, "can't run timer without clock source\n");
+		return (EINVAL);
+	case GPT_CR_CLKSRC_EXT:
+		device_printf(dev, "Not implemented. Geve me the way to get "
+		    "external clock source frequency\n");
+		return (EINVAL);
+	case GPT_CR_CLKSRC_32K:
+		sc->clkfreq = 32768;
+		break;
+	case GPT_CR_CLKSRC_IPG_HIGH:
+		sc->clkfreq = imx51_get_clock(IMX51CLK_IPG_CLK_ROOT) * 2;
+		break;
+	default:
+		sc->clkfreq = imx51_get_clock(IMX51CLK_IPG_CLK_ROOT);
+	}
+
+	device_printf(dev, "Run on %dKHz clock.\n", sc->clkfreq / 1000);
+
+	/* Reset */
+	WRITE4(sc, IMX_GPT_CR, GPT_CR_SWR);
+	/* Enable and setup counters */
+	WRITE4(sc, IMX_GPT_CR,
+	    GPT_CR_CLKSRC_IPG |	/* Use IPG clock */
+	    GPT_CR_FRR |	/* Just count (FreeRunner mode) */
+	    GPT_CR_STOPEN |	/* Run in STOP mode */
+	    GPT_CR_WAITEN |	/* Run in WAIT mode */
+	    GPT_CR_DBGEN);	/* Run in DEBUG mode */
+
+	/* Disable interrupts */
+	WRITE4(sc, IMX_GPT_IR, 0);
+
+	/* Tick every 1us */
+	WRITE4(sc, IMX_GPT_PR, 1);
+
+	/* Setup and enable the timer */
+	err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_CLK, imx_gpt_intr,
+	    NULL, sc, &sc->sc_ih);
+	if (err != 0) {
+		bus_release_resources(dev, imx_gpt_spec, sc->res);
+		device_printf(dev, "Unable to setup the clock irq handler, "
+		    "err = %d\n", err);
+		return (ENXIO);
+	}
+
+	sc->et.et_name = "i.MXxxx GPT Eventtimer";
+	sc->et.et_flags = ET_FLAGS_PERIODIC;
+	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;
+	sc->et.et_max_period.sec = 0xfffffff0U / sc->et.et_frequency;
+	sc->et.et_max_period.frac =
+            ((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);
+	WRITE4(sc, IMX_GPT_IR, 0);
+
+	/* 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);
+
+	printf("clock: hz=%d stathz = %d\n", hz, stathz);
+
+	device_printf(sc->sc_dev, "timer clock frequency %d\n", sc->clkfreq);
+
+	imx_gpt_delay_count = imx51_get_clock(IMX51CLK_ARM_ROOT) / 4000000;
+
+	return (0);
+}
+
+static int
+imx_gpt_timer_start(struct eventtimer *et, struct bintime *first,
+    struct bintime *period)
+{
+
+	return (0);
+}
+
+static int
+imx_gpt_timer_stop(struct eventtimer *et)
+{
+	struct imx_gpt_softc *sc;
+
+	sc = (struct imx_gpt_softc *)et->et_priv;
+
+	CLEAR4(sc, IMX_GPT_CR, GPT_CR_EN);
+
+	return (0);
+}
+
+int
+imx_gpt_get_timerfreq(struct imx_gpt_softc *sc)
+{
+
+	return (sc->clkfreq);
+}
+
+void
+cpu_initclocks(void)
+{
+
+	if (!imx_gpt_sc) {
+		panic("%s: driver has not been initialized!", __func__);
+	}
+
+	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 */
+	imx_gpt_delay_count = 0;
+	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;
+	uint32_t status;
+
+	status = READ4(imx_gpt_sc, IMX_GPT_SR);
+	WRITE4(imx_gpt_sc, IMX_GPT_SR, GPT_IR_OF1);
+
+	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);
+	}
+	/* TODO: other ints */
+
+	return (FILTER_HANDLED);
+}
+
+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);
+}
+
+static device_method_t imx_gpt_methods[] = {
+	DEVMETHOD(device_probe,		imx_gpt_probe),
+	DEVMETHOD(device_attach,	imx_gpt_attach),
+
+	DEVMETHOD_END
+};
+
+static driver_t imx_gpt_driver = {
+	"imx_gpt",
+	imx_gpt_methods,
+	sizeof(struct imx_gpt_softc),
+};
+
+static devclass_t imx_gpt_devclass;
+
+DRIVER_MODULE(imx_gpt, simplebus, imx_gpt_driver, imx_gpt_devclass, 0, 0);
+
+void
+DELAY(int usec)
+{
+	int32_t counts;
+	uint64_t counts_per_usec, last;
+
+	/* 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
+							 */
+		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;
+
+	while (imx_gpt_get_timecount(NULL) < last) {
+		cpufunc_nullop();	/* Prevent optimizing out the loop */
+	}
+	/* TODO: use interrupt on OCR2 */
+}

Added: projects/efika_mx/sys/arm/freescale/imx/imx_gptreg.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/efika_mx/sys/arm/freescale/imx/imx_gptreg.h	Thu Nov  8 12:50:11 2012	(r242761)
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Oleksandr Rybalko under sponsorship
+ * from the FreeBSD Foundation.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.	Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2.	Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/* Registers definition for Freescale i.MX515 Generic Periodic Timer */
+
+#define	IMX_GPT_CR	0x0000 /* Control Register          R/W */
+#define		GPT_CR_FO3		(1 << 31)
+#define		GPT_CR_FO2		(1 << 30)
+#define		GPT_CR_FO1		(1 << 29)
+#define		GPT_CR_OM3_SHIFT	26
+#define		GPT_CR_OM3_MASK		0x1c000000
+#define		GPT_CR_OM2_SHIFT	23
+#define		GPT_CR_OM2_MASK		0x03800000
+#define		GPT_CR_OM1_SHIFT	20
+#define		GPT_CR_OM1_MASK		0x00700000
+#define		GPT_CR_OMX_NONE		0
+#define		GPT_CR_OMX_TOGGLE	1
+#define		GPT_CR_OMX_CLEAR	2
+#define		GPT_CR_OMX_SET		3
+#define		GPT_CR_OMX_PULSE	4 /* Run CLKSRC on output pin */
+#define		GPT_CR_IM2_SHIFT	18
+#define		GPT_CR_IM2_MASK		0x000c0000
+#define		GPT_CR_IM1_SHIFT	16
+#define		GPT_CR_IM1_MASK		0x00030000
+#define		GPT_CR_IMX_NONE		0
+#define		GPT_CR_IMX_REDGE	1
+#define		GPT_CR_IMX_FEDGE	2
+#define		GPT_CR_IMX_BOTH		3
+#define		GPT_CR_SWR		(1 << 15)
+#define		GPT_CR_FRR		(1 << 9)
+#define		GPT_CR_CLKSRC_NONE	0x00000000
+#define		GPT_CR_CLKSRC_IPG	0x00000040
+#define		GPT_CR_CLKSRC_IPG_HIGH	0x00000080
+#define		GPT_CR_CLKSRC_EXT	0x000000c0
+#define		GPT_CR_CLKSRC_32K	0x00000100
+#define		GPT_CR_STOPEN		(1 << 5)
+#define		GPT_CR_WAITEN		(1 << 3)
+#define		GPT_CR_DBGEN		(1 << 2)
+#define		GPT_CR_ENMOD		(1 << 1)
+#define		GPT_CR_EN		(1 << 0)
+
+#define	IMX_GPT_PR	0x0004 /* Prescaler Register        R/W */
+#define		GPT_PR_VALUE_SHIFT	0
+#define		GPT_PR_VALUE_MASK	0x00000fff
+
+/* Same map for SR and IR */
+#define	IMX_GPT_SR	0x0008 /* Status Register           R/W */
+#define	IMX_GPT_IR	0x000c /* Interrupt Register        R/W */
+#define		GPT_IR_ROV		(1 << 5)
+#define		GPT_IR_IF2		(1 << 4)
+#define		GPT_IR_IF1		(1 << 3)
+#define		GPT_IR_OF3		(1 << 2)
+#define		GPT_IR_OF2		(1 << 1)
+#define		GPT_IR_OF1		(1 << 0)
+#define		GPT_IR_ALL		\
+			(GPT_IR_ROV |	\
+			GPT_IR_IF2 |	\
+			GPT_IR_IF1 |	\
+			GPT_IR_OF3 |	\
+			GPT_IR_OF2 |	\
+			GPT_IR_OF1)
+
+#define	IMX_GPT_OCR1	0x0010 /* Output Compare Register 1 R/W */
+#define	IMX_GPT_OCR2	0x0014 /* Output Compare Register 2 R/W */
+#define	IMX_GPT_OCR3	0x0018 /* Output Compare Register 3 R/W */
+#define	IMX_GPT_ICR1	0x001c /* Input capture Register 1  RO */
+#define	IMX_GPT_ICR2	0x0020 /* Input capture Register 2  RO */
+#define	IMX_GPT_CNT	0x0024 /* Counter Register          RO */

Added: projects/efika_mx/sys/arm/freescale/imx/imx_gptvar.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/efika_mx/sys/arm/freescale/imx/imx_gptvar.h	Thu Nov  8 12:50:11 2012	(r242761)
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Oleksandr Rybalko under sponsorship
+ * from the FreeBSD Foundation.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.	Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2.	Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IMXGPTVAR_H
+#define	_IMXGPTVAR_H
+
+struct imx_gpt_softc {
+	device_t 	sc_dev;
+	struct resource *res[3];
+	bus_space_tag_t sc_iot;
+	bus_space_handle_t sc_ioh;
+	int 		sc_intr;
+	void 		*sc_ih;			/* interrupt handler */
+
+	int 		sc_reload_value;
+
+	uint32_t 	sc_clksrc;
+	uint32_t 	clkfreq;
+
+	struct eventtimer et;
+	int		period;
+	int		oneshot;
+};
+
+extern struct imx_gpt_softc *imx_gpt_sc;
+
+int imx_gpt_get_timerfreq(struct imx_gpt_softc *);
+#endif	/* _IMXGPTVAR_H */



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