Dear Xenomai experts,

So far there is:

- xenomai-2.4.9.1
- linux-2.6.29
- ARM architecture based on (unknown for Xenomai core)
- It supports CONFIG_GENERIC_TIME and CONFIG_GENERIC_CLOCKEVENTS
- there is no cascaded interrupts

1) I'm following the steps described in README.INSTALL and HOWTO -
http://www.xenomai.org/index.php/I-pipe:ArmPorting
And since I'm very new in Linux as well is in Xenomai (thank God for this
project) all my problems are from that I'm not quite sure whether I'm doing
all steps correct or not.

For now on I have done with:

- prepare kernel with adeos patch
- configure kernel with its original defconfig file (the original
configuration is verified and working fine on target board)
- building kernel (and here we are!)

2) I did add implementation for (even though the  I did not find any link to
it in HOWTO, so I referred to PXA's implementation):
__ipipe_check_tickdev (called from kernel\core.c)

And for:
mv88f6290_osmr0_set_mode
mv88f6290_osmr0_set_next_event
ckevt_mv88f6290_osmr0
Even though all of them are required by __ipipe_mach_release_timer() I did
not find in HOWTO how these functions should be implemented for MYCORE, so I
referred to PXA's implementation again.

3) Then I did define all next things:

#define IRQ_OST0    IRQ_MV88F6290_TIMER0    /* OS Timer IRQ number match */
#define OSCR        __REG(TIMER0_VAL)        /* (TIMER_VIRT_BASE + 0x0014) -
OS timer 0 Register*/
#define OSMR0        __REG(TIMER_CTRL)        /* (TIMER_VIRT_BASE + 0x0000)
- OS timers Control Register*/
#define OIER_E0        (1 << 0)                    /* Interrupt enable
channel 0 */

Since, according to documentation, there is no PENDING (Status) register for
the timer I did comment all the lines required these definitions.
*QUESTION: Please tell me am I right or not and what to do if it is still
required?*

//#define OSSR        __REG(TIMER0_RELOAD)     /* OS Timer Status Register
*/
//#define OSSR_M0        (1 << 0)                    /* Match status channel
0 */

4) Now I have a problem to define OIER value /* OS Timer Interrupt Enable
Register */
According to Documentation, timer has 3 registers: Control, Reload and Timer
Register.
*QUESTION: What to do with OIER, have no idea, need some one kick me in
right direction!*

I'm attaching the code which has been added according to HOWTO for the
reference.

5) Any additional information (schematic or step-by-step explanation) about
*How what I'm doing now is working* is very welcome to share.

========= CODE BEGIN ==========

#ifdef CONFIG_IPIPE
#ifdef CONFIG_NO_IDLE_HZ
#error "dynamic tick timer not yet supported with IPIPE"
#endif /* CONFIG_NO_IDLE_HZ */

#define __REG(x) (*(volatile unsigned long *)x) /* === I'm not sure whether
this implementation should be or another ===*/

//# define __PREG(x)    io_v2p(x)

//#define OSSR        __REG(TIMER0_RELOAD)     /* OS Timer Status Register
*/
#define IRQ_OST0    IRQ_MV88F6290_TIMER0    /* OS Timer IRQ number match */

//#define OSSR_M0        (1 << 0)                    /* Match status channel
0 */
#define OSCR        __REG(TIMER0_VAL)        /* (TIMER_VIRT_BASE + 0x0014) -
OS timer 0 Register*/
#define OSMR0        __REG(TIMER_CTRL)        /* (TIMER_VIRT_BASE + 0x0000)
- OS timers Control Register*/

#define OIER_E0        (1 << 0)                    /* Interrupt enable
channel 0 */

 /* OS Timer Interrupt Enable Register */

/*Hardware timer IRQ number */
int __ipipe_mach_timerint = IRQ_MV88F6290_TIMER0; /* === ??? ===*/
EXPORT_SYMBOL(__ipipe_mach_timerint);

/*Initialized to 0, it became non zero when the hardware timer is handled by
Xenomai. */
int __ipipe_mach_timerstolen = 0;
EXPORT_SYMBOL(__ipipe_mach_timerstolen);

/*Count of hardware timer ticks between two timer interrupts, same thing as
the LATCH constant. */
unsigned int __ipipe_mach_ticks_per_jiffy = LATCH;  /* === ??? ===*/
EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);

static int mv88f6290_timer_initialized;

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];

/* (...) */
#else /* !CONFIG_SMP */
static union tsc_reg *tsc;

/* (...) */
#endif
#endif

int mv88f6290_tclk;

int __init mv88f6290_find_tclk(void)
{
    u32 dev, rev;

    mv88f6290_pcie_id(&dev, &rev);

    return 166666667;
}

static void mv88f6290_timer_init(void)
{
    mv88f6290_tclk = mv88f6290_find_tclk();
    orion_time_init(IRQ_MV88F6290_BRIDGE, mv88f6290_tclk);

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

        mv88f6290_timer_initialized = 1;
#endif /* CONFIG_IPIPE */

}

struct sys_timer mv88f6290_timer = {
    .init = mv88f6290_timer_init,
};

/* Acknowledge the hardware timer interrupt at hardware timer level.  */
void __ipipe_mach_acktimer(void)
{
    //OSSR = OSSR_M0;  /* Clear match on timer 0 */
}

/* High resolution counter, or its emulation using the hardware decrementer
or free-running counter. */
notrace unsigned long long __ipipe_mach_get_tsc(void)
{
    if (likely(mv88f6290_timer_initialized)) {
        union tsc_reg *local_tsc, result;
        unsigned long stamp;

        local_tsc = &tsc[ipipe_processor_id()];

        __asm__ ("ldmia %1, %M0\n"
             : "=r"(result.full): "r"(local_tsc), "m"(*local_tsc));
        barrier();
        stamp = OSCR;
        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);

#ifdef CONFIG_IPIPE

/* Fills a structure which will be used in user-space to emulate the tsc. */
#ifdef CONFIG_SMP

/* (...) */
void __ipipe_mach_get_tscinfo(struct __ipipe_tscinfo *info)
{
    info->type = IPIPE_TSC_TYPE_NONE;
}
#else
/* (...) */
void __ipipe_mach_get_tscinfo(struct __ipipe_tscinfo *info)
{
    info->type = IPIPE_TSC_TYPE_FREERUNNING;
    info->u.fr.counter = (unsigned *) TIMER0_VAL; /* === ??? ===*/
    info->u.fr.mask = 0xffffffff;
    info->u.fr.tsc = &tsc->full;
}

/*
info->type indicates that the tsc is based on a free-running counter,
info->u.fr.counter is set to the PHYSICAL address of the free-running
counter,
info->u.fr.mask is a mask indicating which bits in the free-running counter
are valid.
info->u.fr.tsc is a pointer to the shared tsc area
*/

#endif /* !CONFIG_SMP */

/* Program the hardware timer to trig an interrupt in 'delay' hardware timer
ticks  */
void __ipipe_mach_set_dec(unsigned long delay)
{
        if (delay > 8)    {

                unsigned long flags;

                local_irq_save_hw(flags);
                OSMR0 = delay + OSCR;
                local_irq_restore_hw(flags);
        }
    else
;                 ipipe_trigger_irq(IRQ_OST0);

}
//EXPORT_SYMBOL(__ipipe_mach_set_dec);

/* Returns the count of hardware timer ticks remaining before the next timer
interrupt. */
unsigned long __ipipe_mach_get_dec(void)
{
    return OSMR0 - OSCR;
}
//EXPORT_SYMBOL(__ipipe_mach_get_dec);

static int
mv88f6290_osmr0_set_next_event(unsigned long delta, struct
clock_event_device *dev)
{
    unsigned long flags, next, oscr;

    raw_local_irq_save(flags);
    next = OSCR + delta;
    OIER |= OIER_E0;
    OSMR0 = next;
    oscr = OSCR;
    raw_local_irq_restore(flags);

    return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
    return 0;
}

static void
mv88f6290_osmr0_set_mode(enum clock_event_mode mode, struct
clock_event_device *dev)
{
    unsigned long irqflags;

    switch (mode) {
    case CLOCK_EVT_MODE_ONESHOT:
        raw_local_irq_save(irqflags);
        OIER &= ~OIER_E0;
        //OSSR = OSSR_M0;
        raw_local_irq_restore(irqflags);
        break;

    case CLOCK_EVT_MODE_UNUSED:
    case CLOCK_EVT_MODE_SHUTDOWN:
        /* initializing, released, or preparing for suspend */
        raw_local_irq_save(irqflags);
        OIER &= ~OIER_E0;
        //OSSR = OSSR_M0;
        raw_local_irq_restore(irqflags);
        break;

    case CLOCK_EVT_MODE_RESUME:
    case CLOCK_EVT_MODE_PERIODIC:
        break;
    }
}

static struct clock_event_device ckevt_mv88f6290_osmr0 = {
    .name        = "mv88f6290",
    .features        = CLOCK_EVT_FEAT_ONESHOT,
    .shift        = 32,
    .rating        = 200,
    .set_next_event    = mv88f6290_osmr0_set_next_event,
    .set_mode        = mv88f6290_osmr0_set_mode,
};


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


/* Reprograms the timer when Xenomai stops intercepting the timer,
generally,
  * the implementation should simply call
__ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy);
  * but see Adapting to boards using CONFIG_GENERIC_TIME and
CONFIG_GENERIC_CLOCKEVENTS
  * in case the board supports CONFIG_GENERIC_TIME and
CONFIG_GENERIC_CLOCKEVENTS.
  */

void __ipipe_mach_release_timer(void)
{
        mv88f6290_osmr0_set_mode(ckevt_mv88f6290_osmr0.mode,
&ckevt_mv88f6290_osmr0);

        if (ckevt_mv88f6290_osmr0.mode == CLOCK_EVT_MODE_ONESHOT)
                mv88f6290_osmr0_set_next_event(LATCH,
&ckevt_mv88f6290_osmr0);
}
//EXPORT_SYMBOL(__ipipe_mach_release_timer);

#endif /* CONFIG_IPIPE */

========= CODE END    ==========

Sergey
_______________________________________________
Xenomai-help mailing list
[email protected]
https://mail.gna.org/listinfo/xenomai-help

Reply via email to