📄 tid_8xx_timer.c
字号:
/*********************************************************************** * * (C) Copyright 2000 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * Jean-Jacques Germond, Fr閐閞ic Soulier, Christian Batt; Alcatel * C/O jjg@sxb.bsf.alcatel.fr * * All rights reserved. * * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU *Library* General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This code 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 * *Library* General Public License for more details. * * You should have received a copy of the GNU *Library* General Public * License along with this program (see file COPYING.LIB); if not, * write to the Free Software Foundation, Inc., 675 Mass Ave, * Cambridge, MA 02139, USA. * ***********************************************************************//* See AR pg:21 */#define __NO_VERSION__#include "tid_def.h" /* for generic timer definitions*/#include <asm/init.h> /* for __initfunc */#include <asm/8xx_immap.h> /* for IMMR definitions */#include <asm/mpc8xx.h> /* for MPC8xx definitions */#include "commproc.h" /* for CPM Int. Vector defs */#include "tid_8xx_def.h" /* for MPX8xx CPM timer defs *//* * which CPM timer to use - index starts at 0 (= timer 1) */#define TID_TIMER_ID 0 /* use CPM timer 1 *//* The portability layer to the virtual timer */static tid_8xx_cpmtimer_t hw; /* Hardware specific data *//* * WARNING: This code removed from the init_module() function * to demonstrate separation of generic and HW dependant stuff. * This creates the RISK of forgetting to call this function, * which will cause nasty problems because critical initialization * is done here */voidtid_init_timer (Tid_Dev* dev, unsigned long period){ unsigned long immr; /* Internal Memory Map Register */ cpmtimer8xx_t *cpmtimerp; /* Pointer to the CPM Timer structure */ tid_8xx_cpmtimer_t *hwp = &hw;/* Pointer to private HW data */ /* * register hardware data in generic stucture */ dev->hw = (void *)hwp; /* * Get Pointer to Internal Memory Map * XXX - could be global symbol for all kernel files */ asm( "mfspr %0,638": "=r"(immr) : ); immr &= 0xFFFF0000; /* Pointer to CPM Timer structure */ cpmtimerp = &((immap_t *)immr)->im_cpmtimer; debugk ("TID: IMMR=0x%lx, TIMERS=0x%x\n", immr, (unsigned)cpmtimerp); /* Initialize pointers depending on which timer we use */ switch (TID_TIMER_ID) { case 0: hwp->tmrp = &(cpmtimerp->cpmt_tmr1); hwp->trrp = &(cpmtimerp->cpmt_trr1); hwp->tcrp = &(cpmtimerp->cpmt_tcr1); hwp->tcnp = &(cpmtimerp->cpmt_tcn1); hwp->terp = &(cpmtimerp->cpmt_ter1); hwp->cpm_vec = CPMVEC_TIMER1; break; case 1: hwp->tmrp = &(cpmtimerp->cpmt_tmr2); hwp->trrp = &(cpmtimerp->cpmt_trr2); hwp->tcrp = &(cpmtimerp->cpmt_tcr2); hwp->tcnp = &(cpmtimerp->cpmt_tcn2); hwp->terp = &(cpmtimerp->cpmt_ter2); hwp->cpm_vec = CPMVEC_TIMER2; break; case 2: hwp->tmrp = &(cpmtimerp->cpmt_tmr3); hwp->trrp = &(cpmtimerp->cpmt_trr3); hwp->tcrp = &(cpmtimerp->cpmt_tcr3); hwp->tcnp = &(cpmtimerp->cpmt_tcn3); hwp->terp = &(cpmtimerp->cpmt_ter3); hwp->cpm_vec = CPMVEC_TIMER3; break; case 3: hwp->tmrp = &(cpmtimerp->cpmt_tmr4); hwp->trrp = &(cpmtimerp->cpmt_trr4); hwp->tcrp = &(cpmtimerp->cpmt_tcr4); hwp->tcnp = &(cpmtimerp->cpmt_tcn4); hwp->terp = &(cpmtimerp->cpmt_ter4); hwp->cpm_vec = CPMVEC_TIMER4; break; } hwp->tgcrp = &cpmtimerp->cpmt_tgcr; debugk ("TID: using timer %d\n" "TID: tgcr @ 0x%x, tmr @ 0x%x, trr @ 0x%x, tcr @ 0x%x, tcn @ 0x%x, ter @ 0x%x\n", TID_TIMER_ID+1, (unsigned)hwp->tgcrp, (unsigned)hwp->tmrp, (unsigned)hwp->trrp, (unsigned)hwp->tcrp, (unsigned)hwp->tcnp, (unsigned)hwp->terp ); /* reset timer */ *hwp->tgcrp &= ~(CPMT_GCR_MASK << TID_TIMER_ID); tid_setPeriod(dev, period); /* Set period to 1s and start ticking */ /* clear all events */ *hwp->terp = ( CPMT_EVENT_CAP | CPMT_EVENT_REF ); /* Install interrupt handler (enable timer in CIMR) */ cpm_install_handler(hwp->cpm_vec, tid_it_handler, dev); debugk ("TID: enabling timer\n"); /* enable timer */ *hwp->tgcrp |= (CPMT_GCR_RST << TID_TIMER_ID); debugk ("TID: tgcr=0x%x, tmr=0x%x, trr=0x%x, tcr=0x%x, tcn=0x%x, ter=0x%x\n", *hwp->tgcrp, *hwp->tmrp, *hwp->trrp, *hwp->tcrp, *hwp->tcnp, *hwp->terp );}voidtid_cancel_timer (Tid_Dev* dev){ tid_8xx_cpmtimer_t *hwp = (tid_8xx_cpmtimer_t *)dev->hw; debugk ("TID: stopping timer\n"); *hwp->tgcrp &= ~(CPMT_GCR_MASK << TID_TIMER_ID); /* Uninstall interrupt handler */ cpm_free_handler (hwp->cpm_vec);}inttid_useSimulatedTimer(void){ return 0; /* we are dealing with real hardware here */}voidtid_ackTimerInterrupt(void *dev_id){ Tid_Dev* dev = (Tid_Dev *)dev_id; tid_8xx_cpmtimer_t *hwp = (tid_8xx_cpmtimer_t *)dev->hw; /* just for demonstration */#if 0 printk (".");#endif /* clear all possible events: Ref. and Cap. */ *hwp->terp = ( CPMT_EVENT_CAP | CPMT_EVENT_REF );}/* Set period in microseconds and start. * Stop if arg is zero. * Truncate to maximum period if more than this is requested - but warn about it. */void tid_setPeriod (Tid_Dev* dev, ulong interval){ unsigned short prescaler; unsigned long ticks; tid_8xx_cpmtimer_t *hwp = (tid_8xx_cpmtimer_t *)dev->hw; debugk ("TID: set interval %ld us\n", interval); if (interval == 0) { /* STOP timer */ tid_cancel_timer (dev); return; } /* Warn if requesting longer period than possible */ if (interval > CPMT_MAX_INTERVAL) { printk ("TID: Truncate interval %ld to maximum (%d)\n", interval, CPMT_MAX_INTERVAL); interval = CPMT_MAX_INTERVAL; } /* * Check if we want to use clock divider: * Since the reference counter can be incremented only in integer steps, * we try to keep it as big as possible to allow the resulting period to be * as precise as possible. */ /* prescaler, enable interrupt, restart after ref count is reached */ prescaler = (ushort)((CPMT_PRESCALER-1) << 8) | CPMT_MR_ORI | CPMT_MR_FRR; ticks = ((ulong)TQM_CLOCKRATE * interval); if (ticks > CPMT_MAX_TICKS) { ticks /= CPMT_CLOCK_DIV; prescaler |= CPMT_MR_ICLK_CLKDIV; /* use system clock divided by 16 */ } else { prescaler |= CPMT_MR_ICLK_CLK; /* use system clock without divider */ } debugk ("TID: clock/%d, prescale factor %d, reference %ld, ticks %ld\n", (ticks > CPMT_MAX_TICKS) ? CPMT_CLOCK_DIV : 1, CPMT_PRESCALER, (ticks / CPMT_PRESCALER), ticks ); /* set prescaler register */ *hwp->tmrp = prescaler; /* clear timer counter */ *hwp->tcnp = 0; /* set reference register */ *hwp->trrp = (unsigned short)(ticks / CPMT_PRESCALER);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -