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>