lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Sun, 22 Apr 2007 18:00:11 +0200
From:	"Remy Bohmer" <l.pinguin@...il.com>
To:	"David Brownell" <david-b@...bell.net>
Cc:	"Ingo Molnar" <mingo@...e.hu>,
	"Thomas Gleixner" <tglx@...utronix.de>,
	linux-kernel@...r.kernel.org
Subject: Re: gtod/clocksource/clockevents documentation

Hello David,

Thanks for this patch you sent me. This patch will also increase the
clock resolution which is good in RT context.

But, unfortunately, I have some problems with compiling the kernel, as
this patch does not enable CONFIG_GENERIC_TIME, while the patch you
published earlier did.

Is there a special reason why you removed that?

I now get the following linker errors while using the RT-kernel. They
do not appear while using a non-RT kernel. (Those unresolved externals
rely on CONFIG_GENERIC_TIME)

====================================================================
kernel/built-in.o: In function
`do_sys_settimeofday':tsacct.c:(.text+0xad60): undefined reference to
`warp_check_clock_was_changed'
kernel/built-in.o: In function `do_sysinfo':tsacct.c:(.text+0x101d4):
undefined reference to `__get_nsec_offset'
kernel/built-in.o: In function
`timekeeping_resume':tsacct.c:(.text+0x10acc): undefined reference to
`warp_check_clock_was_changed'
kernel/built-in.o: In function
`ktime_get_ts':tsacct.c:(.text+0x1e498): undefined reference to
`__get_nsec_offset'
kernel/built-in.o: In function
`second_overflow':tsacct.c:(.text+0x1fd3c): undefined reference to
`warp_check_clock_was_changed'
====================================================================

Kind Regards,

Remy Böhmer


2007/4/22, David Brownell <david-b@...bell.net>:
> On Saturday 21 April 2007, Remy Bohmer wrote:
> > Hello All,
> >
> > I need to implement a gtod/clocksource/clockevents implementation for
> > the Atmel ARM AT91SAM9261 CPU, and I am looking for some kernel
> > (interface) documentation about these mechanisms.
> >
> > I already investigated the 'examples'/implementations of other
> > architectures in the kernel, but that did not really help me... I also
> > looked at the patch for the AT91RM9200 CPU posted by David Brownell...
>
> You know, I started that partly because I couldn't find enough
> info to satisfy my curiousity about how the "new dyntick" was
> expected to work ... ;)
>
>
> > I hacked something which now makes the RT kernel to boot, but the
> > time-of-day warps several minutes per second, back and forward in
> > time... ;-)
>
> Maybe you've got the scaling wrong on the clocksources?  The
> concerns with the shift/mult stuff were particularly opaque;
> some sanity checks might be worth adding, it's easy enough
> to provide wrong values with exactly those failures mode, and
> it's not immediately obvious what "good" values may be.
>
>
> > So, Can anybody please give me pointer to some useful documentation
> > and/or examples?
>
> The best I found was www.kernel.org, current GIT trees.  There
> were some old OLS papers too.
>
> One thing I found lacking was the simple statement up front that
> clocksources are just fixed-rate free running counters; and that
> clockevents are just dual-mode (PIT or oneshot) timers.
>
>
> > The reason behind this initiative is to make the RT-preempt patch
> > compile and work on this architecture. Currently the GENERIC_TIME is
> > not set, which results in several unresolved externals at compile
> > time, and I believe the best way to fix this is to implement proper
> > gtod/clocksource/clockevents to allow the enabling of GENERIC_TIME
>
> Try the appended patch ... the clocksource should work for you,
> giving GENERIC_TIME with maybe a bit of tweaking.
>
> - Dave
>
> =====================   CUT HERE
> This defines a simple library to allocate at91 timer/counter blocks,
> insulating drivers from CPU differences.  Making that work also implies
> defining TC clocks for each processor, and handing a table of TC block
> descriptors to that library.
>
> It also defines a simple TC based clocksource.  Any available TC block
> can be used as a higher precision clocksource than one based on the 32KHz
> slow clock.  Its timebase is MCLK/8, usually 5-10 MHz.  The way it works
> is to combine two 16-bit counters to get a 32-bit clocksource.
>
> INCOMPLETE:
>     (a) The clocksource is currently not efficient for suspend/resume;
>         it doesn't have suspend or resume methods to shut down the TC
>         clocks it uses.
>
>     (b) AVR32 uses this same timer/counter block, albeit with different
>         input clocks and prescalers ... the library to should work for
>         those platforms too, but <linux/atmel_tc.h> has AT91-isms.
>
>     (c) Recent versions of AVR32 code stopped using the architectural
>         counter for the clocksource, and switched over to the TC block.
>         Similar code should become fully sharable with at least the
>         AT91sam926 chips.
>
> Note that AT91rm9200 chips don't really have a need for this other than
> the additional precision; their "system timer" module is more powerful
> than the corresponding AT91sam926 logic, and can fully support the new
> style dynamic tick framework.  (Although the timer IRQ path becomes so
> long that DBGU consistently drops multiple character for things like
> uparrow keys at 38400 baud...)
>
> Signed-off-by: David Brownell <dbrownell@...rs.sourceforge.net>
> ---
>  arch/arm/mach-at91/Kconfig       |   16 ++
>  arch/arm/mach-at91/Makefile      |    1
>  arch/arm/mach-at91/at91rm9200.c  |   36 ++++++
>  arch/arm/mach-at91/at91sam9260.c |   36 ++++++
>  arch/arm/mach-at91/at91sam9261.c |   27 ++++
>  arch/arm/mach-at91/at91sam9263.c |   27 ++++
>  arch/arm/mach-at91/generic.h     |    4
>  arch/arm/mach-at91/tclib.c       |  220 +++++++++++++++++++++++++++++++++++++++
>  include/linux/atmel_tc.h         |  187 +++++++++++++++++++++++++++++++++
>  9 files changed, 554 insertions(+)
>
> --- at91.orig/arch/arm/mach-at91/Kconfig        2007-03-08 20:17:01.000000000 -0800
> +++ at91/arch/arm/mach-at91/Kconfig     2007-03-11 21:58:10.000000000 -0700
> @@ -171,6 +171,22 @@ config AT91_PROGRAMMABLE_CLOCKS
>           Select this if you need to program one or more of the PCK0..PCK3
>           programmable clock outputs.
>
> +config ATMEL_TCLIB
> +       bool "Timer/Counter Library"
> +       help
> +         Select this if you want a library to allocate the Timer/Counter
> +         blocks found on many Atmel processors.  This facilitates using
> +         these modules despite processor differences.
> +
> +config AT91_TC_CLOCKSOURCE
> +       bool "Timer/Counter Clocksource"
> +       depends on ATMEL_TCLIB && ARCH_AT91
> +       help
> +         Select this to get a higher precision clocksource, with a
> +         multi-MHz PLL as the base rather than a 32 Khz oscillator.
> +         This prevents other drivers from using that TC block (which
> +         is currently rare), and draws power for two of its channels.
> +
>  endmenu
>
>  endif
> --- at91.orig/arch/arm/mach-at91/Makefile       2007-03-08 19:50:34.000000000 -0800
> +++ at91/arch/arm/mach-at91/Makefile    2007-03-08 20:17:01.000000000 -0800
> @@ -8,6 +8,7 @@ obj-n           :=
>  obj-           :=
>
>  obj-$(CONFIG_PM)               += pm.o
> +obj-$(CONFIG_ATMEL_TCLIB)      += tclib.o
>
>  # CPU-specific support
>  obj-$(CONFIG_ARCH_AT91RM9200)  += at91rm9200.o at91rm9200_time.o at91rm9200_devices.o
> --- at91.orig/arch/arm/mach-at91/generic.h      2007-03-08 19:50:34.000000000 -0800
> +++ at91/arch/arm/mach-at91/generic.h   2007-03-11 21:58:09.000000000 -0700
> @@ -26,6 +26,10 @@ struct sys_timer;
>  extern struct sys_timer at91rm9200_timer;
>  extern struct sys_timer at91sam926x_timer;
>
> +/* Timer/Counter library */
> +struct tc_block;
> +extern void __init atmel_tc_init(struct tc_block *, unsigned n);
> +
>   /* Clocks */
>  extern int __init at91_clock_init(unsigned long main_clock);
>  struct device;
> --- /dev/null   1970-01-01 00:00:00.000000000 +0000
> +++ at91/arch/arm/mach-at91/tclib.c     2007-03-10 09:26:11.000000000 -0800
> @@ -0,0 +1,220 @@
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/mutex.h>
> +#include <linux/string.h>
> +#include <linux/clk.h>
> +#include <linux/ioport.h>
> +#include <linux/atmel_tc.h>
> +
> +#include <asm/errno.h>
> +#include <asm/hardware.h>
> +#include <asm/io.h>
> +
> +#include "generic.h"
> +
> +
> +/*
> + * This is a thin library to solve the problem of how to portably allocate
> + * one of the TC modules.  For simplicitly, it doesn't currently expect to
> + * share individual timers between different drivers.
> + *
> + * And at the end of this file there's an optional clocksource.  That may be
> + * of interest in cases where more precision is needed, or with sam92xx chips
> + * where no better timer is available.
> + */
> +
> +static struct tc_block *blocks;
> +static unsigned nblocks;
> +
> +static DEFINE_MUTEX(alloc_lock);
> +
> +struct tc_block *tc_allocate(int blk, const char *name)
> +{
> +       struct tc_block *tc;
> +
> +       mutex_lock(&alloc_lock);
> +       if (blk >= 0) {
> +               if (blocks[blk].ioaddr)
> +                       goto full;
> +       } else {
> +               for (blk = 0; blk < nblocks; blk++) {
> +                       if (blocks[blk].ioaddr)
> +                               continue;
> +                       break;
> +               }
> +               if (blk == nblocks)
> +                       goto full;
> +       }
> +       tc = &blocks[blk];
> +
> +       if (!request_mem_region(tc->physaddr, 256, name))
> +               goto full;
> +
> +       tc->ioaddr = ioremap(tc->physaddr, 256);
> +       if (!tc->ioaddr)
> +               goto requested;
> +
> +       pr_debug("%s: tc%d\n", __FUNCTION__, blk);
> +       mutex_unlock(&alloc_lock);
> +       return tc;
> +
> +requested:
> +       release_mem_region(tc->physaddr, 256);
> +full:
> +       pr_debug("%s: alloc FAIL\n", __FUNCTION__);
> +       mutex_unlock(&alloc_lock);
> +       return NULL;
> +}
> +
> +void tc_free(struct tc_block *tc)
> +{
> +       int blk;
> +
> +       for (blk = 0; blk < nblocks; blk++) {
> +               if (tc->ioaddr == blocks[blk].ioaddr)
> +                       break;
> +       }
> +       if (blk == nblocks)
> +               return;
> +
> +       mutex_lock(&alloc_lock);
> +       pr_debug("%s: tc%d\n", __FUNCTION__, blk);
> +       iounmap(tc->ioaddr);
> +       tc->ioaddr = NULL;
> +       release_mem_region(tc->physaddr, 256);
> +       mutex_unlock(&alloc_lock);
> +}
> +
> +void __init atmel_tc_init(struct tc_block *tcblocks, unsigned n)
> +{
> +       blocks = tcblocks;
> +       nblocks = n;
> +}
> +
> +
> +/*--------------------------------------------------------------------------*/
> +
> +#ifdef CONFIG_AT91_TC_CLOCKSOURCE
> +
> +#include <linux/clocksource.h>
> +
> +/* Build a free-running 32 bit timer with a decent base rate of MCK/8
> + * (at around 5-10 MHz) by chaining two 16 bit TC timers.  This rolls
> + * over in around ten minutes.  (There seems to be little point in using
> + * CLOCK1, at MCK/2, given how long it takes to read the cycle count.
> + * This way, the reported precision reasonably matches its accuracy.)
> + *
> + * Example: rm9200 board MCK 46 Mhz, TC clk at 5.76 MHz or ~174 ns/tick.
> + * The first timer rolls over every 11.4 msec, incrementing the second
> + * counter at ~87 Hz.
> + *
> + * NOTE that the third timer does NOT make a very good clockevent source;
> + * sixteen bit counters are wasted silicon in this context.  In periodic
> + * mode, slightly higher MCK would prevent HZ=100 from working.  (The PIT
> + * timer in any AT91 chip is a better answer.)  For oneshot mode, it can't
> + * handle intervals long enough (up to a few seconds) for good "tickless"
> + * operation.  Using CLOCK4 or SLCK barely helps.
> + */
> +
> +static struct tc_block *tc;
> +
> +static cycle_t tc_get_cycles(void)
> +{
> +       union {
> +               u32     word;
> +               u16     half[2];
> +       }               u;
> +       unsigned long   flags;
> +       void __iomem    *tcaddr = tc->ioaddr;
> +
> +       local_irq_save(flags);
> +retry:
> +       u.half[1] = __raw_readl(tcaddr + TC_CHAN(1, CV));
> +       u.half[0] = __raw_readl(tcaddr + TC_CHAN(0, CV));
> +       if (u.half[1] != __raw_readl(tcaddr + TC_CHAN(1, CV)))
> +               goto retry;
> +       local_irq_restore(flags);
> +       return u.word;
> +}
> +
> +static struct clocksource tc_clksrc = {
> +       .name           = "tc_clksrc",
> +       .rating         = 250,
> +       .read           = tc_get_cycles,
> +       .mask           = CLOCKSOURCE_MASK(32),
> +       .shift          = 18,
> +       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
> +};
> +
> +
> +/* REVISIT behavior during system suspend states... we should disable all
> + * clocks and save the power, especially when the main oscillator will be
> + * disabled!  This implies defining and using a driver model device node.
> + */
> +
> +
> +/* Init this late, so board-specific code has a chance to grab hardware.
> + * All we really care about is having two timers to chain; but sometimes
> + * TC modules will be used by drivers hooked up to external hardware.
> + */
> +static int __init tc_clksrc_init(void)
> +{
> +       static char bootinfo[] __initdata
> +               = KERN_INFO "%s: tc%d at %d.%03d MHz\n";
> +
> +       int value;
> +       void __iomem *addr;
> +
> +       tc = tc_allocate(-1, tc_clksrc.name);
> +       if (tc == NULL) {
> +               pr_debug("can't alloc TC for clocksource\n");
> +               return -ENODEV;
> +       }
> +
> +       /* how fast will we be counting? */
> +       value = (int) clk_get_rate(tc->tc0_clk) / 8;
> +       tc_clksrc.mult = clocksource_hz2mult(value, tc_clksrc.shift);
> +
> +       printk(bootinfo, tc_clksrc.name, tc - blocks,
> +                       value/1000000, (value % 1000000) / 1000);
> +
> +       /* channel 0:  waveform mode, input mclk/8, clock TIOA0 on overflow */
> +       addr = tc->ioaddr;
> +       clk_enable(tc->tc0_clk);
> +       __raw_writel(AT91_TC_TIMER_CLOCK2               /* input: mclk/8 */
> +                       | AT91_TC_WAVE
> +                       | AT91_TC_WAVESEL_UP            /* free-run */
> +                       | AT91_TC_ACPA_SET              /* TIOA0 rises at 0 */
> +                       | AT91_TC_ACPC_CLEAR,           /* (duty cycle 50%) */
> +                       addr + TC_CHAN(0, CMR));
> +       __raw_writel(0x0000, addr + TC_CHAN(0, RA));
> +       __raw_writel(0x8000, addr + TC_CHAN(0, RC));
> +       __raw_writel(0xff, addr + TC_CHAN(0, IDR));     /* no irqs */
> +       __raw_writel(AT91_TC_CLKEN, addr + TC_CHAN(0, CCR));
> +
> +       /* channel 1:  waveform mode, input TIOA0 */
> +       clk_enable(tc->tc1_clk);        /* REVISIT: is this clock needed?? */
> +       __raw_writel(AT91_TC_XC1                        /* input: TIOA0 */
> +                       | AT91_TC_WAVE
> +                       | AT91_TC_WAVESEL_UP,           /* free-run */
> +                       addr + TC_CHAN(1, CMR));
> +       __raw_writel(0xff, addr + TC_CHAN(1, IDR));     /* no irqs */
> +       __raw_writel(AT91_TC_CLKEN, addr + TC_CHAN(1, CCR));
> +
> +       /* channel 2: UNUSED */
> +
> +       /* chain channel 0 to channel 1, then reset all the timers */
> +       __raw_writel(AT91_TC_TC0XC0S_NONE
> +                       | AT91_TC_TC1XC1S_TIOA0
> +                       | AT91_TC_TC2XC2S_NONE,
> +                       tc->ioaddr + AT91_TC_BMR);
> +       __raw_writel(AT91_TC_SYNC, tc->ioaddr + AT91_TC_BCR);
> +
> +       /* and away we go! */
> +       clocksource_register(&tc_clksrc);
> +
> +       return 0;
> +}
> +late_initcall(tc_clksrc_init);
> +
> +#endif /* CONFIG_AT91_TC_CLOCKSOURCE */
> --- at91.orig/arch/arm/mach-at91/at91rm9200.c   2007-03-08 19:50:34.000000000 -0800
> +++ at91/arch/arm/mach-at91/at91rm9200.c        2007-03-10 09:16:49.000000000 -0800
> @@ -248,6 +248,39 @@ static void at91rm9200_reset(void)
>         at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
>  }
>
> +/* --------------------------------------------------------------------
> + *  Timer/Counter library initialization
> + * -------------------------------------------------------------------- */
> +#ifdef CONFIG_ATMEL_TCLIB
> +#include <linux/atmel_tc.h>
> +
> +static struct tc_block tcblocks[] = {
> +       [0] = {
> +               .physaddr = AT91RM9200_BASE_TCB0,
> +               .tc0_clk = &tc0_clk,
> +               .tc0_irq = AT91RM9200_ID_TC0,
> +               .tc1_clk = &tc1_clk,
> +               .tc1_irq = AT91RM9200_ID_TC1,
> +               .tc2_clk = &tc2_clk,
> +               .tc2_irq = AT91RM9200_ID_TC2,
> +       },
> +       [1] = {
> +               .physaddr = AT91RM9200_BASE_TCB1,
> +               .tc0_clk = &tc3_clk,
> +               .tc0_irq = AT91RM9200_ID_TC3,
> +               .tc1_clk = &tc4_clk,
> +               .tc1_irq = AT91RM9200_ID_TC4,
> +               .tc2_clk = &tc5_clk,
> +               .tc2_irq = AT91RM9200_ID_TC5,
> +       },
> +};
> +
> +#define at91rm9200_tc_init()   atmel_tc_init(tcblocks, ARRAY_SIZE(tcblocks))
> +
> +#else
> +#define at91rm9200_tc_init()   do{}while(0)
> +#endif
> +
>
>  /* --------------------------------------------------------------------
>   *  AT91RM9200 processor initialization
> @@ -271,6 +304,9 @@ void __init at91rm9200_initialize(unsign
>
>         /* Initialize GPIO subsystem */
>         at91_gpio_init(at91rm9200_gpio, banks);
> +
> +       /* Initialize TC blocks */
> +       at91rm9200_tc_init();
>  }
>
>
> --- at91.orig/arch/arm/mach-at91/at91sam9260.c  2007-03-08 19:50:34.000000000 -0800
> +++ at91/arch/arm/mach-at91/at91sam9260.c       2007-03-10 09:16:56.000000000 -0800
> @@ -262,6 +262,39 @@ static void at91sam9260_reset(void)
>         at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
>  }
>
> +/* --------------------------------------------------------------------
> + *  Timer/Counter library initialization
> + * -------------------------------------------------------------------- */
> +#ifdef CONFIG_ATMEL_TCLIB
> +#include <linux/atmel_tc.h>
> +
> +static struct tc_block tcblocks[] = {
> +       [0] = {
> +               .physaddr = AT91SAM9260_BASE_TCB0,
> +               .tc0_clk = &tc0_clk,
> +               .tc0_irq = AT91SAM9260_ID_TC0,
> +               .tc1_clk = &tc1_clk,
> +               .tc1_irq = AT91SAM9260_ID_TC1,
> +               .tc2_clk = &tc2_clk,
> +               .tc2_irq = AT91SAM9260_ID_TC2,
> +       },
> +       [1] = {
> +               .physaddr = AT91SAM9260_BASE_TCB1,
> +               .tc0_clk = &tc3_clk,
> +               .tc0_irq = AT91SAM9260_ID_TC3,
> +               .tc1_clk = &tc4_clk,
> +               .tc1_irq = AT91SAM9260_ID_TC4,
> +               .tc2_clk = &tc5_clk,
> +               .tc2_irq = AT91SAM9260_ID_TC5,
> +       },
> +};
> +
> +#define at91sam9260_tc_init()  atmel_tc_init(tcblocks, ARRAY_SIZE(tcblocks))
> +
> +#else
> +#define at91sam9260_tc_init()  do{}while(0)
> +#endif
> +
>
>  /* --------------------------------------------------------------------
>   *  AT91SAM9260 processor initialization
> @@ -310,6 +343,9 @@ void __init at91sam9260_initialize(unsig
>
>         /* Register GPIO subsystem */
>         at91_gpio_init(at91sam9260_gpio, 3);
> +
> +       /* Initialize TC blocks */
> +       at91sam9260_tc_init();
>  }
>
>  /* --------------------------------------------------------------------
> --- at91.orig/arch/arm/mach-at91/at91sam9261.c  2007-03-08 19:50:34.000000000 -0800
> +++ at91/arch/arm/mach-at91/at91sam9261.c       2007-03-10 09:16:58.000000000 -0800
> @@ -230,6 +230,30 @@ static void at91sam9261_reset(void)
>
>
>  /* --------------------------------------------------------------------
> + *  Timer/Counter library initialization
> + * -------------------------------------------------------------------- */
> +#ifdef CONFIG_ATMEL_TCLIB
> +#include <linux/atmel_tc.h>
> +
> +static struct tc_block tcblocks[] = {
> +       [0] = {
> +               .physaddr = AT91SAM9261_BASE_TCB0,
> +               .tc0_clk = &tc0_clk,
> +               .tc0_irq = AT91SAM9261_ID_TC0,
> +               .tc1_clk = &tc1_clk,
> +               .tc1_irq = AT91SAM9261_ID_TC1,
> +               .tc2_clk = &tc2_clk,
> +               .tc2_irq = AT91SAM9261_ID_TC2,
> +       },
> +};
> +
> +#define at91sam9261_tc_init()  atmel_tc_init(tcblocks, ARRAY_SIZE(tcblocks))
> +
> +#else
> +#define at91sam9261_tc_init()  do{}while(0)
> +#endif
> +
> +/* --------------------------------------------------------------------
>   *  AT91SAM9261 processor initialization
>   * -------------------------------------------------------------------- */
>
> @@ -250,6 +274,9 @@ void __init at91sam9261_initialize(unsig
>
>         /* Register GPIO subsystem */
>         at91_gpio_init(at91sam9261_gpio, 3);
> +
> +       /* Initialize TC blocks */
> +       at91sam9261_tc_init();
>  }
>
>  /* --------------------------------------------------------------------
> --- at91.orig/arch/arm/mach-at91/at91sam9263.c  2007-03-08 19:50:34.000000000 -0800
> +++ at91/arch/arm/mach-at91/at91sam9263.c       2007-03-10 09:17:02.000000000 -0800
> @@ -237,6 +237,30 @@ static void at91sam9263_reset(void)
>
>
>  /* --------------------------------------------------------------------
> + *  Timer/Counter library initialization
> + * -------------------------------------------------------------------- */
> +#ifdef CONFIG_ATMEL_TCLIB
> +#include <linux/atmel_tc.h>
> +
> +static struct tc_block tcblocks[] = {
> +       [0] = {
> +               .physaddr = AT91SAM9263_BASE_TCB0,
> +               .tc0_clk = &tcb_clk,
> +               .tc0_irq = AT91SAM9261_ID_TCB,
> +               .tc1_clk = &tcb_clk,
> +               .tc1_irq = AT91SAM9261_ID_TCB,
> +               .tc2_clk = &tcb_clk,
> +               .tc2_irq = AT91SAM9261_ID_TCB,
> +       },
> +};
> +
> +#define at91sam9263_tc_init()  atmel_tc_init(tcblocks, ARRAY_SIZE(tcblocks))
> +
> +#else
> +#define at91sam9263_tc_init()  do{}while(0)
> +#endif
> +
> +/* --------------------------------------------------------------------
>   *  AT91SAM9263 processor initialization
>   * -------------------------------------------------------------------- */
>
> @@ -256,6 +280,9 @@ void __init at91sam9263_initialize(unsig
>
>         /* Register GPIO subsystem */
>         at91_gpio_init(at91sam9263_gpio, 5);
> +
> +       /* Initialize TC blocks */
> +       at91sam9263_tc_init();
>  }
>
>  /* --------------------------------------------------------------------
> --- /dev/null   1970-01-01 00:00:00.000000000 +0000
> +++ at91/include/linux/atmel_tc.h       2007-03-08 20:17:01.000000000 -0800
> @@ -0,0 +1,187 @@
> +/*
> + * <linux/atmel_tc.h>
> + *
> + * Copyright (C) SAN People
> + *
> + * Timer/Counter Unit (TC) registers.
> + * Based on AT91RM9200 datasheet revision E.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#ifndef ATMEL_TC_H
> +#define ATMEL_TC_H
> +
> +/*
> + * This is a simple library to allocate the 16-bit Timer/Counter blocks..
> + * It allocates either specific blocks (interfacing to external hardware),
> + * or any unused block..  At least initially, this doesn't expect to share
> + * timers in one block between drivers.
> + *
> + * Note that some chips have multiple TC blocks, while others don't.
> + * Also, some chips have one clock (and irq) for each timer, but others
> + * share one for the whole block.
> + */
> +
> +/* REVISIT AVR32 uses interprets CLOCK1/CLOCK2/.../CLOCK5 differently
> + * than AT91.  Like the rm9200 and sam9260, the ap7000 has two TC modules.
> + *
> + * FIXME remove AT91 prefixes
> + */
> +
> +#define TC_CHAN(idx, reg)      ((idx)*0x40 + AT91_TC_ ## reg)
> +
> +struct tc_block {
> +       void __iomem    *ioaddr;
> +       u32             physaddr;
> +
> +       struct clk      *tc0_clk;
> +       int             tc0_irq;
> +
> +       struct clk      *tc1_clk;
> +       int             tc1_irq;
> +
> +       struct clk      *tc2_clk;
> +       int             tc2_irq;
> +};
> +
> +/*
> + * Returned TC block is "on loan" to caller.
> + * Caller enables/disables TC clocks as needed (e.g. during suspend).
> + * BLOCK = 0, 1, etc; or negative to mean "any block"
> + */
> +extern struct tc_block *tc_allocate(int block, const char *name);
> +extern void tc_free(struct tc_block *tc);
> +
> +#define AT91_TC_BCR            0xc0            /* TC Block Control Register */
> +#define                AT91_TC_SYNC            (1 << 0)        /* Synchro Command */
> +
> +#define AT91_TC_BMR            0xc4            /* TC Block Mode Register */
> +#define                AT91_TC_TC0XC0S         (3 << 0)        /* External Clock Signal 0 Selection */
> +#define                        AT91_TC_TC0XC0S_TCLK0           (0 << 0)
> +#define                        AT91_TC_TC0XC0S_NONE            (1 << 0)
> +#define                        AT91_TC_TC0XC0S_TIOA1           (2 << 0)
> +#define                        AT91_TC_TC0XC0S_TIOA2           (3 << 0)
> +#define                AT91_TC_TC1XC1S         (3 << 2)        /* External Clock Signal 1 Selection */
> +#define                        AT91_TC_TC1XC1S_TCLK1           (0 << 2)
> +#define                        AT91_TC_TC1XC1S_NONE            (1 << 2)
> +#define                        AT91_TC_TC1XC1S_TIOA0           (2 << 2)
> +#define                        AT91_TC_TC1XC1S_TIOA2           (3 << 2)
> +#define                AT91_TC_TC2XC2S         (3 << 4)        /* External Clock Signal 2 Selection */
> +#define                        AT91_TC_TC2XC2S_TCLK2           (0 << 4)
> +#define                        AT91_TC_TC2XC2S_NONE            (1 << 4)
> +#define                        AT91_TC_TC2XC2S_TIOA0           (2 << 4)
> +#define                        AT91_TC_TC2XC2S_TIOA1           (3 << 4)
> +
> +
> +#define AT91_TC_CCR            0x00            /* Channel Control Register */
> +#define                AT91_TC_CLKEN           (1 << 0)        /* Counter Clock Enable Command */
> +#define                AT91_TC_CLKDIS          (1 << 1)        /* Counter CLock Disable Command */
> +#define                AT91_TC_SWTRG           (1 << 2)        /* Software Trigger Command */
> +
> +#define AT91_TC_CMR            0x04            /* Channel Mode Register */
> +#define                AT91_TC_TCCLKS          (7 << 0)        /* Capture/Waveform Mode: Clock Selection */
> +#define                        AT91_TC_TIMER_CLOCK1            (0 << 0)
> +#define                        AT91_TC_TIMER_CLOCK2            (1 << 0)
> +#define                        AT91_TC_TIMER_CLOCK3            (2 << 0)
> +#define                        AT91_TC_TIMER_CLOCK4            (3 << 0)
> +#define                        AT91_TC_TIMER_CLOCK5            (4 << 0)
> +#define                        AT91_TC_XC0                     (5 << 0)
> +#define                        AT91_TC_XC1                     (6 << 0)
> +#define                        AT91_TC_XC2                     (7 << 0)
> +#define                AT91_TC_CLKI            (1 << 3)        /* Capture/Waveform Mode: Clock Invert */
> +#define                AT91_TC_BURST           (3 << 4)        /* Capture/Waveform Mode: Burst Signal Selection */
> +#define                AT91_TC_LDBSTOP         (1 << 6)        /* Capture Mode: Counter Clock Stopped with TB Loading */
> +#define                AT91_TC_LDBDIS          (1 << 7)        /* Capture Mode: Counter Clock Disable with RB Loading */
> +#define                AT91_TC_ETRGEDG         (3 << 8)        /* Capture Mode: External Trigger Edge Selection */
> +#define                AT91_TC_ABETRG          (1 << 10)       /* Capture Mode: TIOA or TIOB External Trigger Selection */
> +#define                AT91_TC_CPCTRG          (1 << 14)       /* Capture Mode: RC Compare Trigger Enable */
> +#define                AT91_TC_WAVE            (1 << 15)       /* Capture/Waveform mode */
> +#define                AT91_TC_LDRA            (3 << 16)       /* Capture Mode: RA Loading Selection */
> +#define                AT91_TC_LDRB            (3 << 18)       /* Capture Mode: RB Loading Selection */
> +
> +#define                AT91_TC_CPCSTOP         (1 <<  6)       /* Waveform Mode: Counter Clock Stopped with RC Compare */
> +#define                AT91_TC_CPCDIS          (1 <<  7)       /* Waveform Mode: Counter Clock Disable with RC Compare */
> +#define                AT91_TC_EEVTEDG         (3 <<  8)       /* Waveform Mode: External Event Edge Selection */
> +#define                        AT91_TC_EEVTEDG_NONE            (0 << 8)
> +#define                        AT91_TC_EEVTEDG_RISING          (1 << 8)
> +#define                        AT91_TC_EEVTEDG_FALLING         (2 << 8)
> +#define                        AT91_TC_EEVTEDG_BOTH            (3 << 8)
> +#define                AT91_TC_EEVT            (3 << 10)       /* Waveform Mode: External Event Selection */
> +#define                        AT91_TC_EEVT_TIOB               (0 << 10)
> +#define                        AT91_TC_EEVT_XC0                (1 << 10)
> +#define                        AT91_TC_EEVT_XC1                (2 << 10)
> +#define                        AT91_TC_EEVT_XC2                (3 << 10)
> +#define                AT91_TC_ENETRG          (1 << 12)       /* Waveform Mode: External Event Trigger Enable */
> +#define                AT91_TC_WAVESEL         (3 << 13)       /* Waveform Mode: Waveform Selection */
> +#define                        AT91_TC_WAVESEL_UP              (0 << 13)
> +#define                        AT91_TC_WAVESEL_UP_AUTO         (2 << 13)
> +#define                        AT91_TC_WAVESEL_UPDOWN          (1 << 13)
> +#define                        AT91_TC_WAVESEL_UPDOWN_AUTO     (3 << 13)
> +#define                AT91_TC_ACPA            (3 << 16)       /* Waveform Mode: RA Compare Effect on TIOA */
> +#define                        AT91_TC_ACPA_NONE               (0 << 16)
> +#define                        AT91_TC_ACPA_SET                (1 << 16)
> +#define                        AT91_TC_ACPA_CLEAR              (2 << 16)
> +#define                        AT91_TC_ACPA_TOGGLE             (3 << 16)
> +#define                AT91_TC_ACPC            (3 << 18)       /* Waveform Mode: RC Compre Effect on TIOA */
> +#define                        AT91_TC_ACPC_NONE               (0 << 18)
> +#define                        AT91_TC_ACPC_SET                (1 << 18)
> +#define                        AT91_TC_ACPC_CLEAR              (2 << 18)
> +#define                        AT91_TC_ACPC_TOGGLE             (3 << 18)
> +#define                AT91_TC_AEEVT           (3 << 20)       /* Waveform Mode: External Event Effect on TIOA */
> +#define                        AT91_TC_AEEVT_NONE              (0 << 20)
> +#define                        AT91_TC_AEEVT_SET               (1 << 20)
> +#define                        AT91_TC_AEEVT_CLEAR             (2 << 20)
> +#define                        AT91_TC_AEEVT_TOGGLE            (3 << 20)
> +#define                AT91_TC_ASWTRG          (3 << 22)       /* Waveform Mode: Software Trigger Effect on TIOA */
> +#define                        AT91_TC_ASWTRG_NONE             (0 << 22)
> +#define                        AT91_TC_ASWTRG_SET              (1 << 22)
> +#define                        AT91_TC_ASWTRG_CLEAR            (2 << 22)
> +#define                        AT91_TC_ASWTRG_TOGGLE           (3 << 22)
> +#define                AT91_TC_BCPB            (3 << 24)       /* Waveform Mode: RB Compare Effect on TIOB */
> +#define                        AT91_TC_BCPB_NONE               (0 << 24)
> +#define                        AT91_TC_BCPB_SET                (1 << 24)
> +#define                        AT91_TC_BCPB_CLEAR              (2 << 24)
> +#define                        AT91_TC_BCPB_TOGGLE             (3 << 24)
> +#define                AT91_TC_BCPC            (3 << 26)       /* Waveform Mode: RC Compare Effect on TIOB */
> +#define                        AT91_TC_BCPC_NONE               (0 << 26)
> +#define                        AT91_TC_BCPC_SET                (1 << 26)
> +#define                        AT91_TC_BCPC_CLEAR              (2 << 26)
> +#define                        AT91_TC_BCPC_TOGGLE             (3 << 26)
> +#define                AT91_TC_BEEVT           (3 << 28)       /* Waveform Mode: External Event Effect on TIOB */
> +#define                        AT91_TC_BEEVT_NONE              (0 << 28)
> +#define                        AT91_TC_BEEVT_SET               (1 << 28)
> +#define                        AT91_TC_BEEVT_CLEAR             (2 << 28)
> +#define                        AT91_TC_BEEVT_TOGGLE            (3 << 28)
> +#define                AT91_TC_BSWTRG          (3 << 30)       /* Waveform Mode: Software Trigger Effect on TIOB */
> +#define                        AT91_TC_BSWTRG_NONE             (0 << 30)
> +#define                        AT91_TC_BSWTRG_SET              (1 << 30)
> +#define                        AT91_TC_BSWTRG_CLEAR            (2 << 30)
> +#define                        AT91_TC_BSWTRG_TOGGLE           (3 << 30)
> +
> +#define AT91_TC_CV             0x10            /* Counter Value */
> +#define AT91_TC_RA             0x14            /* Register A */
> +#define AT91_TC_RB             0x18            /* Register B */
> +#define AT91_TC_RC             0x1c            /* Register C */
> +
> +#define AT91_TC_SR             0x20            /* Status Register */
> +#define                AT91_TC_COVFS           (1 <<  0)       /* Counter Overflow Status */
> +#define                AT91_TC_LOVRS           (1 <<  1)       /* Load Overrun Status */
> +#define                AT91_TC_CPAS            (1 <<  2)       /* RA Compare Status */
> +#define                AT91_TC_CPBS            (1 <<  3)       /* RB Compare Status */
> +#define                AT91_TC_CPCS            (1 <<  4)       /* RC Compare Status */
> +#define                AT91_TC_LDRAS           (1 <<  5)       /* RA Loading Status */
> +#define                AT91_TC_LDRBS           (1 <<  6)       /* RB Loading Status */
> +#define                AT91_TC_ETRGS           (1 <<  7)       /* External Trigger Status */
> +#define                AT91_TC_CLKSTA          (1 << 16)       /* Clock Enabling Status */
> +#define                AT91_TC_MTIOA           (1 << 17)       /* TIOA Mirror */
> +#define                AT91_TC_MTIOB           (1 << 18)       /* TIOB Mirror */
> +
> +#define AT91_TC_IER            0x24            /* Interrupt Enable Register */
> +#define AT91_TC_IDR            0x28            /* Interrupt Disable Register */
> +#define AT91_TC_IMR            0x2c            /* Interrupt Mask Register */
> +
> +#endif /* ATMEL_TC_H */
>
>
>
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ