Hi Gilles,

here is my time.c



Il 10/04/2012 11:11, Gilles Chanteperdrix ha scritto:
On 04/10/2012 11:06 AM, Gilles Chanteperdrix wrote:
On 04/10/2012 10:58 AM, Roberto Bielli wrote:
Hi Gilles,

i look at the processor errata but for the imx25 there are no errata
elements on timer.
It is strange that you use linux 2.6.31 on imx25: linux 2.6.31 does not
support imx25.

The I-pipe support has not been written for imx25, so, it is entirely
possible that you have to adapt it. See:
http://www.xenomai.org/index.php/I-pipe:ArmPorting

Latest kernels support imx25, and imx25 works like an mx3, not an mx2,
can you show me arch/arm/plat-mxc/time.c for your (undoubtedly) patched
kernel?



--
+------------------------------------------------------------------------------------------------+
                                                        
Roberto Bielli
Sviluppo Software                                       
Axel S.r.l.                                     
                                                        
Via Del Cannino, 3                              
21020 Crosio Della Valle                        
Varese - Italy                                  
                                                        
Telefono: +39 0332 949600                       
Fax:      +39 0332 969315                       
                                                        
E-mail:   roberto.bie...@axelsw.it      
Web Site: www.axelsw.it

+------------------------------------------------------------------------------------------------+

Si precisa che le informazioni contenute in questo messaggio sono riservate e 
ad uso esclusivo del destinatario.
Qualora il messaggio in parola Le fosse pervenuto per errore, La preghiamo di 
eliminarlo senza copiarlo e di non inoltrarlo a terzi,
dandocene gentilmente comunicazione. Grazie.
Informativa sul trattamento dei dati personali (D. Lgs. 196/2003).
I dati utilizzati per la spedizione del presente messaggio sono utilizzati da 
Axel S.r.l., titolare del trattamento,
per l'invio delle comunicazioni dei diversi settori aziendali, non essendo 
autorizzata la divulgazione a terzi.
Potrete rivolgere alla seguente mail richieste di verifica, rettifica o 
cancellazione dei Vostri dati: i...@axelsw.it

This e-mail and any attachments is confidential and may contain privileged 
information
intended for the addressee(s) only. Dissemination, copying, printing or use by 
anybody
else is unauthorised. If you are not the intended recipient,
please delete this message and any attachments and advise the sender
by return e-mail.Thank you.                     
                                                        
+------------------------------------------------------------------------------------------------+

/*
 *  linux/arch/arm/plat-mxc/time.c
 *
 *  Copyright (C) 2000-2001 Deep Blue Solutions
 *  Copyright (C) 2002 Shane Nay (sh...@minirl.com)
 *  Copyright (C) 2006-2007 Pavel Pisa (pp...@pikron.com)
 *  Copyright (C) 2008 Juergen Beisert (ker...@pengutronix.de)
 *
 * 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.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */

#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/clockchips.h>
#include <linux/clk.h>

#include <mach/hardware.h>
#include <asm/mach/time.h>
#include <mach/common.h>

/* defines common for all i.MX */
#define MXC_TCTL                0x00
#define MXC_TCTL_TEN            (1 << 0)
#define MXC_TPRER               0x04

/* MX1, MX21, MX27 */
#define MX1_2_TCTL_CLK_PCLK1    (1 << 1)
#define MX1_2_TCTL_IRQEN        (1 << 4)
#define MX1_2_TCTL_FRR          (1 << 8)
#define MX1_2_TCMP              0x08
#define MX1_2_TCN               0x10
#define MX1_2_TSTAT             0x14

/* MX21, MX27 */
#define MX2_TSTAT_CAPT          (1 << 1)
#define MX2_TSTAT_COMP          (1 << 0)

/* MX31, MX35, MX25 */
#define MX3_TCTL_WAITEN         (1 << 3)
#define MX3_TCTL_CLK_IPG        (1 << 6)
#define MX3_TCTL_CLK_PER        (2 << 6)
#define MX3_TCTL_FRR            (1 << 9)
#define MX3_IR                  0x0c
#define MX3_TSTAT               0x08
#define MX3_TSTAT_OF1           (1 << 0)
#define MX3_TCN                 0x24
#define MX3_TCMP                0x10

#ifdef CONFIG_IPIPE
#ifdef CONFIG_NO_IDLE_HZ
#error "dynamic tick timer not yet supported with IPIPE"
#endif /* CONFIG_NO_IDLE_HZ */
int __ipipe_mach_timerint;
EXPORT_SYMBOL(__ipipe_mach_timerint);

int __ipipe_mach_timerstolen = 0;
EXPORT_SYMBOL(__ipipe_mach_timerstolen);

unsigned int __ipipe_mach_ticks_per_jiffy = LATCH;
EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);

static int mxc_timer_initialized;
static unsigned mxc_min_delay;

union tsc_reg {
#ifdef __BIG_ENDIAN
        struct {
                unsigned long high;
                unsigned long low;
        };
#else /* __LITTLE_ENDIAN */
        struct {
                unsigned long low;
                unsigned long high;
        };
#endif /* __LITTLE_ENDIAN */
        unsigned long long full;
};

#ifdef CONFIG_SMP
static union tsc_reg tsc[NR_CPUS];

void __ipipe_mach_get_tscinfo(struct __ipipe_tscinfo *info)
{
        info->type = IPIPE_TSC_TYPE_NONE;
}

#else /* !CONFIG_SMP */
static union tsc_reg *tsc;

void __ipipe_mach_get_tscinfo(struct __ipipe_tscinfo *info)
{
        info->type = IPIPE_TSC_TYPE_FREERUNNING;
        if (cpu_is_mx1()) {
#ifdef CONFIG_ARCH_MX1
                info->u.fr.counter = (unsigned *) (TIM1_BASE_ADDR + MX1_2_TCN);
#endif
        } else if (cpu_is_mx2()) {
#ifdef CONFIG_ARCH_MX2
                info->u.fr.counter = (unsigned *) (GPT1_BASE_ADDR + MX1_2_TCN);
#endif
        } else if (cpu_is_mx3() || cpu_is_mx25() ) {
#if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX25
                info->u.fr.counter = (unsigned *) (GPT1_BASE_ADDR + MX3_TCN);
#endif
        }
        info->u.fr.mask = 0xffffffff;
        info->u.fr.tsc = &tsc->full;
}
#endif /* !CONFIG_SMP */

static void ipipe_mach_update_tsc(void);
#endif /* CONFIG_IPIPE */

#define timer_is_v2()   (cpu_is_mx3() || cpu_is_mx25() || cpu_is_mx5())

static struct clock_event_device clockevent_mxc;
static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;

static void __iomem *timer_base;

static inline void gpt_irq_disable(void)
{
        unsigned int tmp;

        if (timer_is_v2())
                __raw_writel(0, timer_base + MX3_IR);
        else {
                tmp = __raw_readl(timer_base + MXC_TCTL);
                __raw_writel(tmp & ~MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL);
        }
}

static inline void gpt_irq_enable(void)
{
        if (timer_is_v2())
                __raw_writel(1<<0, timer_base + MX3_IR);
        else {
                __raw_writel(__raw_readl(timer_base + MXC_TCTL) | 
MX1_2_TCTL_IRQEN,
                        timer_base + MXC_TCTL);
        }
}

static void gpt_irq_acknowledge(void)
{
        if (cpu_is_mx1())
                __raw_writel(0, timer_base + MX1_2_TSTAT);
        if (cpu_is_mx2())
                __raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP, timer_base + 
MX1_2_TSTAT);
        if (timer_is_v2())
                __raw_writel(MX3_TSTAT_OF1, timer_base + MX3_TSTAT);
}

static cycle_t timer_v1_get_cycles(struct clocksource *cs)
{
        return __raw_readl(timer_base + MX1_2_TCN);
}

static cycle_t timer_v2_get_cycles(struct clocksource *cs)
{
        return __raw_readl(timer_base + MX3_TCN);
}

static struct clocksource clocksource_mxc = {
        .name           = "mxc_timer1",
        .rating         = 200,
        .read           = timer_v1_get_cycles,
        .mask           = CLOCKSOURCE_MASK(32),
        .shift          = 20,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
};

static int __init mxc_clocksource_init(struct clk *timer_clk)
{
        unsigned int c = clk_get_rate(timer_clk);

        if (timer_is_v2())
                clocksource_mxc.read = timer_v2_get_cycles;

#ifdef CONFIG_IPIPE
        __ipipe_mach_ticks_per_jiffy = (c + HZ/2) / HZ;
#endif /* CONFIG_IPIPE */
        clocksource_mxc.mult = clocksource_hz2mult(c,
                                        clocksource_mxc.shift);
        clocksource_register(&clocksource_mxc);

        return 0;
}

/* clock event */

static int timer_v1_set_next_event(unsigned long evt,
                              struct clock_event_device *unused)
{
        unsigned long tcmp;

        tcmp = __raw_readl(timer_base + MX1_2_TCN) + evt;

        __raw_writel(tcmp, timer_base + MX1_2_TCMP);

        return (int)(tcmp - __raw_readl(timer_base + MX1_2_TCN)) < 0 ?
                                -ETIME : 0;
}

static int timer_v2_set_next_event(unsigned long evt,
                              struct clock_event_device *unused)
{
        unsigned long tcmp;

        tcmp = __raw_readl(timer_base + MX3_TCN) + evt;

        __raw_writel(tcmp, timer_base + MX3_TCMP);

        return (int)(tcmp - __raw_readl(timer_base + MX3_TCN)) < 0 ? -ETIME : 0;
}

#ifdef DEBUG
static inline const char *clock_event_mode_label(enum clock_event_mode mode)
{
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
                return "CLOCK_EVT_MODE_PERIODIC";
        case CLOCK_EVT_MODE_ONESHOT:
                return "CLOCK_EVT_MODE_ONESHOT";
        case CLOCK_EVT_MODE_SHUTDOWN:
                return "CLOCK_EVT_MODE_SHUTDOWN";
        case CLOCK_EVT_MODE_UNUSED:
                return "CLOCK_EVT_MODE_UNUSED";
        case CLOCK_EVT_MODE_RESUME:
                return "CLOCK_EVT_MODE_RESUME";
        }
        return "UNKNOWN";
};
#endif /* DEBUG */

static void mxc_set_mode(enum clock_event_mode mode,
                                struct clock_event_device *evt)
{
        unsigned long flags;

        /*
         * The timer interrupt generation is disabled at least
         * for enough time to call mxc_set_next_event()
         */
        local_irq_save(flags);

        /* Disable interrupt in GPT module */
        gpt_irq_disable();

        if (mode != clockevent_mode) {
                /* Set event time into far-far future */
                if (timer_is_v2())
                        __raw_writel(__raw_readl(timer_base + MX3_TCN) - 3,
                                        timer_base + MX3_TCMP);
                else
                        __raw_writel(__raw_readl(timer_base + MX1_2_TCN) - 3,
                                        timer_base + MX1_2_TCMP);

                /* Clear pending interrupt */
                gpt_irq_acknowledge();
        }

#ifdef DEBUG
        printk(KERN_INFO "mxc_set_mode: changing mode from %s[%d] to %s[%d]\n",
                clock_event_mode_label(clockevent_mode), clockevent_mode,
                clock_event_mode_label(mode), mode);
#endif /* DEBUG */

        /* Remember timer mode */
        clockevent_mode = mode;
        local_irq_restore(flags);
        switch (mode)
        {
        case CLOCK_EVT_MODE_PERIODIC:
                printk(KERN_ERR "mxc_set_mode: Periodic mode is not supported 
for i.MX\n");
                break;
        case CLOCK_EVT_MODE_ONESHOT:
        /*
         * Do not put overhead of interrupt enable/disable into
         * mxc_set_next_event(), the core has about 4 minutes
         * to call mxc_set_next_event() or shutdown clock after
         * mode switching
         */
                local_irq_save(flags);
                gpt_irq_enable();
                local_irq_restore(flags);
                break;
        case CLOCK_EVT_MODE_SHUTDOWN:
        case CLOCK_EVT_MODE_UNUSED:
        case CLOCK_EVT_MODE_RESUME:
                /* Left event sources disabled, no more interrupts appear */
                break;
        }
}

/*
 * IRQ handler for the timer
 */
static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
{
        struct clock_event_device *evt = &clockevent_mxc;
        uint32_t tstat;
        unsigned long reg;

        if (timer_is_v2())
                tstat = __raw_readl(timer_base + MX3_TSTAT);
        else
                tstat = __raw_readl(timer_base + MX1_2_TSTAT);

#ifndef CONFIG_IPIPE
        gpt_irq_acknowledge();
#else /* !CONFIG_IPIPE */

        ipipe_mach_update_tsc();

#endif /* !CONFIG_IPIPE */

        evt->event_handler(evt);

        return IRQ_HANDLED;
}

static struct irqaction mxc_timer_irq = {
        .name           = "i.MX Timer Tick",
        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
        .handler        = mxc_timer_interrupt,
};

static struct clock_event_device clockevent_mxc = {
        .name           = "mxc_timer1",
        .features       = CLOCK_EVT_FEAT_ONESHOT,
        .shift          = 32,
        .set_mode       = mxc_set_mode,
        .set_next_event = timer_v1_set_next_event,
        .rating         = 200,
};

static int __init mxc_clockevent_init(struct clk *timer_clk)
{
        unsigned long c = clk_get_rate(timer_clk);

        printk(KERN_DEBUG "%s: timer clk rate is %lu.%03luMHz\n", __FUNCTION__,
                c / 1000000, c / 1000 % 1000);

        if (timer_is_v2())
                clockevent_mxc.set_next_event = timer_v2_set_next_event;

        clockevent_mxc.mult = div_sc(c, NSEC_PER_SEC,
                                        clockevent_mxc.shift);
        clockevent_mxc.max_delta_ns =
                        clockevent_delta2ns(0xfffffffe, &clockevent_mxc);
        clockevent_mxc.min_delta_ns =
                        clockevent_delta2ns(0xff, &clockevent_mxc);

        clockevent_mxc.cpumask = cpumask_of(0);

        clockevents_register_device(&clockevent_mxc);

        return 0;
}

void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
{
        uint32_t tctl_val;

        clk_enable(timer_clk);

        timer_base = base;

        /*
         * Initialise to a known state (all timers off, and timing reset)
         */

        __raw_writel(0, timer_base + MXC_TCTL);
        __raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */

        if (timer_is_v2())
                tctl_val = MX3_TCTL_CLK_IPG | MX3_TCTL_FRR | MX3_TCTL_WAITEN | 
MXC_TCTL_TEN;
        else
                tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;

        __raw_writel(tctl_val, timer_base + MXC_TCTL);

        /* init and register the timer to the framework */
        mxc_clocksource_init(timer_clk);
        mxc_clockevent_init(timer_clk);

        /* Make irqs happen */
        setup_irq(irq, &mxc_timer_irq);

#ifdef CONFIG_IPIPE
        __ipipe_mach_timerint = irq;
#ifndef CONFIG_SMP
        tsc = (union tsc_reg *) __ipipe_tsc_area;
        barrier();
#endif /* CONFIG_SMP */

//      mxc_min_delay = ((ipipe_cpu_freq() + 500000) / 1000000) ?: 1;
        mxc_min_delay = (ipipe_cpu_freq() + 500000) / 1000000;
        if (mxc_min_delay == 0)
        {
                mxc_min_delay = 1;
        }

        printk(  KERN_INFO "mxc_min_delay = %d\n", mxc_min_delay );
        mxc_timer_initialized = 1;
#endif /* CONFIG_IPIPE */
}

#ifdef CONFIG_IPIPE
int __ipipe_check_tickdev(const char *devname)
{
        return !strcmp(devname, clockevent_mxc.name);
}

void __ipipe_mach_acktimer(void)
{
        uint32_t tstat;

    if (timer_is_v2())
                tstat = __raw_readl(timer_base + MX3_TSTAT);
        else
                tstat = __raw_readl(timer_base + MX1_2_TSTAT);
                
                                 
        gpt_irq_acknowledge();
}

static void ipipe_mach_update_tsc(void)
{
        union tsc_reg *local_tsc;
        unsigned long stamp, flags;

        //local_irq_save_hw(flags);
        local_tsc = &tsc[ipipe_processor_id()];
        if (!cpu_is_mx3() && !cpu_is_mx25() )
                stamp = __raw_readl(timer_base + MX1_2_TCN);
        else
                stamp = __raw_readl(timer_base + MX3_TCN);
        if (unlikely(stamp < local_tsc->low))
                /* 32 bit counter wrapped, increment high word. */
                local_tsc->high++;
        local_tsc->low = stamp;
        //local_irq_restore_hw(flags);
}

notrace unsigned long long __ipipe_mach_get_tsc(void)
{
        if (likely(mxc_timer_initialized)) {
                union tsc_reg *local_tsc, result;
                unsigned long stamp;

                local_tsc = &tsc[ipipe_processor_id()];

                if (!cpu_is_mx3() && !cpu_is_mx25() )  {
                        __asm__ ("ldmia %1, %M0\n"
                                 : "=r"(result.full), "+&r"(local_tsc)
                                 : "m"(*local_tsc));
                        barrier();
                        stamp = __raw_readl(timer_base + MX1_2_TCN);
                } else {
                        __asm__ ("ldmia %1, %M0\n"
                                 : "=r"(result.full), "+&r"(local_tsc)
                                 : "m"(*local_tsc));
                        barrier();
                        stamp = __raw_readl(timer_base + MX3_TCN);
                }
                if (unlikely(stamp < result.low))
                        /* 32 bit counter wrapped, increment high word. */
                        result.high++;
                result.low = stamp;

                return result.full;
        }

        return 0;
}
EXPORT_SYMBOL(__ipipe_mach_get_tsc);

/*
 * Reprogram the timer
 */

void __ipipe_mach_set_dec(unsigned long delay)
{
        /*if (delay > mxc_min_delay) {
                unsigned long flags;

                local_irq_save_hw(flags);
                if (!cpu_is_mx3() && !cpu_is_mx25() )
                        timer_v1_set_next_event(delay, NULL);
                else
                        timer_v2_set_next_event(delay, NULL);
                local_irq_restore_hw(flags);
        } else
                ipipe_trigger_irq(__ipipe_mach_timerint);*/
                
                
        if (delay > mxc_min_delay) {
                 unsigned long tcmp;

                 if (!timer_is_v2()) {
                                 tcmp = __raw_readl(timer_base + MX1_2_TCN) + 
delay;
                                 __raw_writel(tcmp, timer_base + MX1_2_TCMP);
                                 __raw_readl(timer_base + MX1_2_TCN);
                 } else {
                                 tcmp = __raw_readl(timer_base + MX3_TCN) + 
delay;
                                 __raw_writel(tcmp, timer_base + MX3_TCMP);
                                 __raw_readl(timer_base + MX3_TCN);
                 }
    } else
                 ipipe_trigger_irq(__ipipe_mach_timerint);
}
EXPORT_SYMBOL(__ipipe_mach_set_dec);

void __ipipe_mach_release_timer(void)
{
        mxc_set_mode(clockevent_mxc.mode, &clockevent_mxc);
        if (clockevent_mxc.mode == CLOCK_EVT_MODE_ONESHOT)
                clockevent_mxc.set_next_event(LATCH, &clockevent_mxc);
}
EXPORT_SYMBOL(__ipipe_mach_release_timer);

unsigned long __ipipe_mach_get_dec(void)
{
        if (!cpu_is_mx3() && !cpu_is_mx25() )
                return __raw_readl(timer_base + MX1_2_TCMP)
                        - __raw_readl(timer_base + MX1_2_TCN);
        else
                return __raw_readl(timer_base + MX3_TCMP)
                        - __raw_readl(timer_base + MX3_TCN);
}
#endif /* CONFIG_IPIPE */
_______________________________________________
Xenomai-core mailing list
Xenomai-core@gna.org
https://mail.gna.org/listinfo/xenomai-core

Reply via email to