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
