This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Timer Interrupt implement in ubbot in SDK6.0

Hi team,

My customer needs to implement timer interrupt in uboot which is used to driver a LED periodically to monitor the progress of FTP downloading.  We ported the codes from starterware, please see attachment. Current issue is that it can go to ISR periodically as designed but the progress can't run back to main progress.

And whether we already have the patch for such kind of user case?

Could someone help look at this issue?

1541.start.S

/*
 * (C) Copyright 2003
 * Texas Instruments <www.ti.com>
 *
 * (C) Copyright 2002
 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
 * Marius Groeger <mgroeger@sysgo.de>
 *
 * (C) Copyright 2002
 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
 * Alex Zuepke <azu@sysgo.de>
 *
 * (C) Copyright 2002-2004
 * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
 *
 * (C) Copyright 2004
 * Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * 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., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <common.h>
#include <asm/proc-armv/ptrace.h>
#include <hw_intc.h>
#include <soc_AM335x.h>
#include <hw_types.h>
#include <hw_dmtimer.h>
#include <dmtimer.h>


/******************************************************************************
**                INTERNAL MACRO DEFINITIONS
******************************************************************************/
#define REG_IDX_SHIFT                  (0x05)
#define REG_BIT_MASK                   (0x1F)
#define NUM_INTERRUPTS                 (128u)

/******************************************************************************
**                      INTERNAL MACRO DEFINITIONS
*******************************************************************************/
#define TIMER_INITIAL_COUNT             (0xFF000000u)
#define TIMER_RLD_COUNT                 (0xFF000000u)
//#define TIMER_RLD_COUNT                 (0xFFFF0000u)



/**************** *************************************************************
**                 STATIC VARIABLE DEFINITIONS
******************************************************************************/
void (*fnRAMVectors[NUM_INTERRUPTS])(void);

static void IntDefaultHandler(void)
{
    /* Go Back. Nothing to be done */
    ;
}


DECLARE_GLOBAL_DATA_PTR;

#ifdef CONFIG_USE_IRQ
int interrupt_init (void)
{
	/*
	 * setup up stacks if necessary
	 */
#if 1	 
	IRQ_STACK_START = gd->irq_sp - 4;
	IRQ_STACK_START_IN = gd->irq_sp + 8;
	FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
#else
     IRQ_STACK_START = 0x80f00000 - 4;
	IRQ_STACK_START_IN = 0x80f00000 + 8;
	FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
   
#endif

	return arch_interrupt_init();
}

int	arch_interrupt_init	(void)
{
#if 1
    printf("IRQ__STACK_START:0x%x\n",IRQ_STACK_START);
    DMTimer2ModuleClkConfig();
    /* Enable IRQ in CPSR */
    IntMasterIRQEnable();

    /* Register DMTimer2 interrupts on to AINTC */
    DMTimerAintcConfigure();

    /* Perform the necessary configurations for DMTimer */
    DMTimerSetUp();

    /* Enable the DMTimer interrupts */
    DMTimerIntEnable(SOC_DMTIMER_2_REGS, DMTIMER_INT_OVF_EN_FLAG);

    /* Start the DMTimer */
    DMTimerEnable(SOC_DMTIMER_2_REGS); 
    //disable_interrupts();


   // DMTimerIntDisable(SOC_DMTIMER_2_REGS, DMTIMER_INT_OVF_EN_FLAG);


    while(0)
    {
        printf("arch_interrupt_init....\n");
    }
    reset_timer_masked();

      // DMTimerIntDisable(SOC_DMTIMER_2_REGS, DMTIMER_INT_OVF_EN_FLAG);

    /* Stop the DMTimer */
    //DMTimerDisable(SOC_DMTIMER_2_REGS);

        while(0)
    {   
        printfcctr();
    }
  #endif  
  
 return 0;
}

/* enable IRQ interrupts */
void enable_interrupts (void)
{
	unsigned long temp;
	__asm__ __volatile__("mrs %0, cpsr\n"
			     "bic %0, %0, #0x80\n"
			     "msr cpsr_c, %0"
			     : "=r" (temp)
			     :
			     : "memory");
}


/*
 * disable IRQ/FIQ interrupts
 * returns true if interrupts had been enabled before we disabled them
 */
int disable_interrupts (void)
{
	unsigned long old,temp;
	__asm__ __volatile__("mrs %0, cpsr\n"
			     "orr %1, %0, #0xc0\n"
			     "msr cpsr_c, %1"
			     : "=r" (old), "=r" (temp)
			     :
			     : "memory");
	return (old & 0x80) == 0;
}
#else
int interrupt_init (void)
{
	/*
	 * setup up stacks if necessary
	 */
	IRQ_STACK_START_IN = gd->irq_sp + 8;

	return 0;
}

void enable_interrupts (void)
{
	return;
}
int disable_interrupts (void)
{
	return 0;
}
#endif



void CPUirqe(void)
{
    /* Enable IRQ in CPSR */
    #if 1
    asm("    mrs     r0, CPSR\n\t"
        "    bic     r0, r0, #0x80\n\t"
        "    msr     CPSR_c, r0");
        #else

        	unsigned long temp;
	__asm__ __volatile__("mrs %0, cpsr\n"
			     "bic %0, %0, #0x80\n"
			     "msr cpsr_c, %0"
			     : "=r" (temp)
			     :
			     : "memory");

        #endif
}

void IntAINTCInit(void)
{
    unsigned int intrNum;

    /* Reset the ARM interrupt controller */
    HWREG(SOC_AINTC_REGS + INTC_SYSCONFIG) = INTC_SYSCONFIG_SOFTRESET;
 
    /* Wait for the reset to complete */
    while((HWREG(SOC_AINTC_REGS + INTC_SYSSTATUS) 
          & INTC_SYSSTATUS_RESETDONE) != INTC_SYSSTATUS_RESETDONE);    
  
    /* Enable any interrupt generation by setting priority threshold */ 
    HWREG(SOC_AINTC_REGS + INTC_THRESHOLD) = 
                                       INTC_THRESHOLD_PRIORITYTHRESHOLD;

    /* Register the default handler for all interrupts */
    for(intrNum = 0; intrNum < NUM_INTERRUPTS; intrNum++)
    {
        fnRAMVectors[intrNum] = IntDefaultHandler;
    }
}

void IntPrioritySet(unsigned int intrNum, unsigned int priority,
                    unsigned int hostIntRoute)
{
    HWREG(SOC_AINTC_REGS + INTC_ILR(intrNum)) =
                                 ((priority << INTC_ILR_PRIORITY_SHIFT)
                                   & INTC_ILR_PRIORITY)
                                 | hostIntRoute ;
}


void IntSystemEnable(unsigned int intrNum)
{
    //asm(" dsb");
    
    /* Disable the system interrupt in the corresponding MIR_CLEAR register */
    HWREG(SOC_AINTC_REGS + INTC_MIR_CLEAR(intrNum >> REG_IDX_SHIFT))
                                   = (0x01 << (intrNum & REG_BIT_MASK));
}

void IntSystemDisable(unsigned int intrNum)
{

    //__asm(" dsb");
    
    /* Enable the system interrupt in the corresponding MIR_SET register */
    HWREG(SOC_AINTC_REGS + INTC_MIR_SET(intrNum >> REG_IDX_SHIFT)) 
                                   = (0x01 << (intrNum & REG_BIT_MASK));
}

void IntControlDisable()
{

    //__asm(" dsb");
    
    /* Enable the system interrupt in the corresponding MIR_SET register */
    HWREG(SOC_AINTC_REGS + INTC_CONTROL)  = 0x01 ;
}

/**
 * \brief    Registers an interrupt Handler in the interrupt vector table for
 *           system interrupts. 
 * 
 * \param    intrNum - Interrupt Number
 * \param    fnHandler - Function pointer to the ISR
 * 
 * Note: When the interrupt occurs for the sytem interrupt number indicated,
 * the control goes to the ISR given as the parameter.
 * 
 * \return      None.
 **/
void IntRegister(unsigned int intrNum, void (*fnHandler)(void))
{
    /* Assign ISR */
    fnRAMVectors[intrNum] = fnHandler;
}

/**
 * \brief   This API will stop the timer. 
 *
 * \param   baseAdd      Base Address of the DMTimer Module Register.
 *
 * \return  None.
 *
 **/


 
/*
** Setup the timer for one-shot and compare mode.
*/
void DMTimerSetUp(void)
{
    /* Load the counter with the initial count value */
    DMTimerCounterSet(SOC_DMTIMER_2_REGS, TIMER_INITIAL_COUNT);

    /* Load the load register with the reload count value */
    DMTimerReloadSet(SOC_DMTIMER_2_REGS, TIMER_RLD_COUNT);

    /* Configure the DMTimer for Auto-reload and compare mode */
    DMTimerModeConfigure(SOC_DMTIMER_2_REGS, DMTIMER_AUTORLD_NOCMP_ENABLE);
}

void bad_mode (void)
{
	panic ("Resetting CPU ...\n");
	reset_cpu (0);
}

void show_regs (struct pt_regs *regs)
{
	unsigned long flags;
	const char *processor_modes[] = {
	"USER_26",	"FIQ_26",	"IRQ_26",	"SVC_26",
	"UK4_26",	"UK5_26",	"UK6_26",	"UK7_26",
	"UK8_26",	"UK9_26",	"UK10_26",	"UK11_26",
	"UK12_26",	"UK13_26",	"UK14_26",	"UK15_26",
	"USER_32",	"FIQ_32",	"IRQ_32",	"SVC_32",
	"UK4_32",	"UK5_32",	"UK6_32",	"ABT_32",
	"UK8_32",	"UK9_32",	"UK10_32",	"UND_32",
	"UK12_32",	"UK13_32",	"UK14_32",	"SYS_32",
	};

	flags = condition_codes (regs);

	printf ("pc : [<%08lx>]	   lr : [<%08lx>]\n"
		"sp : %08lx  ip : %08lx	 fp : %08lx\n",
		instruction_pointer (regs),
		regs->ARM_lr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
	printf ("r10: %08lx  r9 : %08lx	 r8 : %08lx\n",
		regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
	printf ("r7 : %08lx  r6 : %08lx	 r5 : %08lx  r4 : %08lx\n",
		regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
	printf ("r3 : %08lx  r2 : %08lx	 r1 : %08lx  r0 : %08lx\n",
		regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
	printf ("Flags: %c%c%c%c",
		flags & CC_N_BIT ? 'N' : 'n',
		flags & CC_Z_BIT ? 'Z' : 'z',
		flags & CC_C_BIT ? 'C' : 'c', flags & CC_V_BIT ? 'V' : 'v');
	printf ("  IRQs %s  FIQs %s  Mode %s%s\n",
		interrupts_enabled (regs) ? "on" : "off",
		fast_interrupts_enabled (regs) ? "on" : "off",
		processor_modes[processor_mode (regs)],
		thumb_mode (regs) ? " (T)" : "");
}

void do_undefined_instruction (struct pt_regs *pt_regs)
{
	printf ("undefined instruction\n");
	show_regs (pt_regs);
	bad_mode ();
}

void do_software_interrupt (struct pt_regs *pt_regs)
{
	printf ("software interrupt\n");
	show_regs (pt_regs);
	bad_mode ();
}

void do_prefetch_abort (struct pt_regs *pt_regs)
{
	printf ("prefetch abort\n");
	show_regs (pt_regs);
	bad_mode ();
}

void do_data_abort (struct pt_regs *pt_regs)
{
	printf ("data abort\n");
	show_regs (pt_regs);
	bad_mode ();
}

void do_not_used (struct pt_regs *pt_regs)
{
	printf ("not used\n");
	show_regs (pt_regs);
	bad_mode ();
}

void do_fiq (struct pt_regs *pt_regs)
{
	printf ("fast interrupt request\n");
	show_regs (pt_regs);
	bad_mode ();
}

//#ifndef CONFIG_USE_IRQ
#if 0
ulong timestamp = 0;
extern struct gptimer *timer_base;
void kw_timer_interrupt(void)
{

      unsigned int temp = 0;
      int ret = 0;
    //MV_REG_WRITE(0x20304, ~(0x00000100));
    //ret =  disable_interrupts();

    DMTimerIntDisable(SOC_DMTIMER_2_REGS, DMTIMER_INT_OVF_EN_FLAG);

    /* Clear the status of the interrupt flags */
    DMTimerIntStatusClear(SOC_DMTIMER_2_REGS, DMTIMER_INT_OVF_IT_FLAG);

     /* Stop the DMTimer */
    DMTimerDisable(SOC_DMTIMER_2_REGS); 

    printf("kw_timer_interrupt#####....:0x%x\n",readl(&timer_base->tcrr));
        
  	timestamp++;
   	timer_server(timestamp);

	return ;
}
#endif
void do_irq (struct pt_regs *pt_regs)
{
   
	//puts ("interrupt request.....\n");
	//show_regs (pt_regs);
	//bad_mode ();
	//disable_interrupts();
	// DMTimerIntStatusClear(SOC_DMTIMER_2_REGS, DMTIMER_INT_OVF_IT_FLAG);
	#if 0
	int temp = 0;
	    	__asm__ __volatile__("mov %0, sp\n"
			     : "=r" (temp)
			     :
			     : "memory");


	printf("\nInterrupt sp = 0x%x\n",temp);
	#endif
	kw_timer_interrupt();
	//printf("do_irq end ..\n");
}
//#endif

/*
 * (C) Copyright 2008
 * Texas Instruments
 *
 * Richard Woodruff <r-woodruff2@ti.com>
 * Syed Moahmmed Khasim <khasim@ti.com>
 *
 * (C) Copyright 2002
 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
 * Marius Groeger <mgroeger@sysgo.de>
 * Alex Zuepke <azu@sysgo.de>
 *
 * (C) Copyright 2002
 * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * 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., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <common.h>
#include <asm/io.h>
#include <soc_AM335x.h>
#include <hw_types.h>
#include <hw_cm_per.h>
#include <interrupt.h>
#include <dmtimer.h>

DECLARE_GLOBAL_DATA_PTR;

static volatile unsigned int flagIsr = 0;

struct gptimer *timer_base = (struct gptimer *)CONFIG_SYS_TIMERBASE;

/*
 * Nothing really to do with interrupts, just starts up a counter.
 */

#define TIMER_CLOCK		(V_SCLK / (2 << CONFIG_SYS_PTV))
#define TIMER_OVERFLOW_VAL	0xffffffff
#define TIMER_LOAD_VAL		0

ulong timestamp = 0;
extern struct gptimer *timer_base;
extern int mainCnt;
void kw_timer_interrupt(void)
{
      unsigned int temp = 0;
      int ret = 0;
    //MV_REG_WRITE(0x20304, ~(0x00000100));
    //ret =  disable_interrupts();
    DMTimerIntDisable(SOC_DMTIMER_2_REGS, DMTIMER_INT_OVF_EN_FLAG);
    DMTimerIntStatusClear(SOC_DMTIMER_2_REGS, DMTIMER_INT_OVF_IT_FLAG);
    IntControlDisable();
#if 1

    	__asm__ __volatile__("mov %0, sp\n"
			     : "=r" (temp)
			     :
			     : "memory");


	printf("Interrupt sp = 0x%x,timestamp:%d\n",temp,timestamp++);
#endif	
     DMTimerIntEnable(SOC_DMTIMER_2_REGS, DMTIMER_INT_OVF_EN_FLAG);
     
   //   printf("\nmianCnt = %d\n",mainCnt);

    
    /* Clear the status of the interrupt flags */
 //   DMTimerIntStatusClear(SOC_DMTIMER_2_REGS, DMTIMER_INT_OVF_IT_FLAG);
#if 1
     /* Stop the DMTimer */
   // IntSystemDisable(SYS_INT_TINT2);
     //IntControlDisable();
   
    // printf("IntStatusClear:0x%x\n",readl(&timer_base->tistat));
   // DMTimerDisable(SOC_DMTIMER_2_REGS); 
        
  
#endif

#if 0
   // printf("---:0x%x\n",readl(&timer_base->tcrr));

   if( timestamp%2 == 0)
   {
    lightRunAlmLed();
   }
   else
   {
    turnoffRunAlmLed();
   }

    timestamp++;
   	timer_server(timestamp);
#endif

   //flush_dcache_all();
   //invalidate_dcache_all();
  //IntControlDisable();

     /* Perform the necessary configurations for DMTimer */
    //DMTimerSetUp();

    /* Enable the DMTimer interrupts */
   // DMTimerIntEnable(SOC_DMTIMER_2_REGS, DMTIMER_INT_OVF_EN_FLAG);

    /* Start the DMTimer */
    //DMTimerEnable(SOC_DMTIMER_2_REGS); 
    //disable_interrupts();

   //DMTimerEnable(SOC_DMTIMER_2_REGS);

   	//printf("kw_timer_interrupt++++++++++++++++++++++++++++:0x%x\n",readl(&timer_base->tcrr));

	return ;
}


void printfcctr()
{
  // char szArryay[2048] ={0};
  int temp = 0;
   ulong ret = readl(&timer_base->tcrr);

       	__asm__ __volatile__("mov %0, sp\n"
			     : "=r" (temp)
			     :
			     : "memory");



  //  if (ret >0xff000000 && ret < 0xff000100 && doneirq !=1)
   	printf("\n777While######sp:0x%x\n",temp);
   //	else if(ret > 0xffffff00 && ret < 0xffffffff)
   	//  printf("CCTR*******....:0x%x\n",readl(&timer_base->tcrr));
}

void printfcctr1()
{
  // char szArryay[2048] ={0};
  int temp = 0;
   ulong ret = readl(&timer_base->tcrr);

       	__asm__ __volatile__("mov %0, sp\n"
			     : "=r" (temp)
			     :
			     : "memory");



  //  if (ret >0xff000000 && ret < 0xff000100 && doneirq !=1)
   	printf("\nWhile######sp:0x%x\n",temp);
   //	else if(ret > 0xffffff00 && ret < 0xffffffff)
   	//  printf("CCTR*******....:0x%x\n",readl(&timer_base->tcrr));
}
int timer_init(void)
{


#if 1
    /* start the counter ticking up, reload value on overflow */
	writel(TIMER_LOAD_VAL, &timer_base->tldr);
	/* enable timer */
	writel((CONFIG_SYS_PTV << 2) | TCLR_PRE | TCLR_AR | TCLR_ST,
		&timer_base->tclr);

	/* reset time, capture current incrementer value time */
	gd->lastinc = readl(&timer_base->tcrr) / (TIMER_CLOCK / CONFIG_SYS_HZ);
	gd->tbl = 0;		/* start "advancing" time stamp from 0 */
#else
    //printf("timer_inittimer_init:0x%x\n",IRQ_STACK_START);
     DMTimer2ModuleClkConfig();
    /* Enable IRQ in CPSR */
    IntMasterIRQEnable();

    /* Register DMTimer2 interrupts on to AINTC */
    DMTimerAintcConfigure();

    /* Perform the necessary configurations for DMTimer */
    DMTimerSetUp();

    /* Enable the DMTimer interrupts */
   DMTimerIntEnable(SOC_DMTIMER_2_REGS, DMTIMER_INT_OVF_EN_FLAG);

    /* Start the DMTimer */
   DMTimerEnable(SOC_DMTIMER_2_REGS);  

     while(0)
    {
    printf("timer_init.....****..\n");
    }
    reset_timer_masked();

 #endif   

	return 0;
}


void EnableTimer2Interrupt(void)
{
    writel(0x7, &timer_base->tisr);
    writel(0x7, &timer_base->twer);
}
#if 1

void DMTimer2ModuleClkConfig(void)
{
    HWREG(SOC_CM_PER_REGS + CM_PER_L3S_CLKSTCTRL) =
                             CM_PER_L3S_CLKSTCTRL_CLKTRCTRL_SW_WKUP;

    while((HWREG(SOC_CM_PER_REGS + CM_PER_L3S_CLKSTCTRL) &
     CM_PER_L3S_CLKSTCTRL_CLKTRCTRL) != CM_PER_L3S_CLKSTCTRL_CLKTRCTRL_SW_WKUP);

    HWREG(SOC_CM_PER_REGS + CM_PER_L3_CLKSTCTRL) =
                             CM_PER_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP;

    while((HWREG(SOC_CM_PER_REGS + CM_PER_L3_CLKSTCTRL) &
     CM_PER_L3_CLKSTCTRL_CLKTRCTRL) != CM_PER_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP);

    HWREG(SOC_CM_PER_REGS + CM_PER_L3_INSTR_CLKCTRL) =
                             CM_PER_L3_INSTR_CLKCTRL_MODULEMODE_ENABLE;

    while((HWREG(SOC_CM_PER_REGS + CM_PER_L3_INSTR_CLKCTRL) &
                               CM_PER_L3_INSTR_CLKCTRL_MODULEMODE) !=
                                   CM_PER_L3_INSTR_CLKCTRL_MODULEMODE_ENABLE);

    HWREG(SOC_CM_PER_REGS + CM_PER_L3_CLKCTRL) =
                             CM_PER_L3_CLKCTRL_MODULEMODE_ENABLE;

    while((HWREG(SOC_CM_PER_REGS + CM_PER_L3_CLKCTRL) &
        CM_PER_L3_CLKCTRL_MODULEMODE) != CM_PER_L3_CLKCTRL_MODULEMODE_ENABLE);

    HWREG(SOC_CM_PER_REGS + CM_PER_OCPWP_L3_CLKSTCTRL) =
                             CM_PER_OCPWP_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP;

    while((HWREG(SOC_CM_PER_REGS + CM_PER_OCPWP_L3_CLKSTCTRL) &
                              CM_PER_OCPWP_L3_CLKSTCTRL_CLKTRCTRL) !=
                                CM_PER_OCPWP_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP);

    HWREG(SOC_CM_PER_REGS + CM_PER_L4LS_CLKSTCTRL) =
                             CM_PER_L4LS_CLKSTCTRL_CLKTRCTRL_SW_WKUP;

    while((HWREG(SOC_CM_PER_REGS + CM_PER_L4LS_CLKSTCTRL) &
                             CM_PER_L4LS_CLKSTCTRL_CLKTRCTRL) !=
                               CM_PER_L4LS_CLKSTCTRL_CLKTRCTRL_SW_WKUP);

    HWREG(SOC_CM_PER_REGS + CM_PER_L4LS_CLKCTRL) =
                             CM_PER_L4LS_CLKCTRL_MODULEMODE_ENABLE;

    while((HWREG(SOC_CM_PER_REGS + CM_PER_L4LS_CLKCTRL) &
      CM_PER_L4LS_CLKCTRL_MODULEMODE) != CM_PER_L4LS_CLKCTRL_MODULEMODE_ENABLE);

    /* Select the clock source for the Timer2 instance. */
    HWREG(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_TIMER2_CLK) &=
          ~(CM_DPLL_CLKSEL_TIMER2_CLK_CLKSEL);

    HWREG(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_TIMER2_CLK) |=
          CM_DPLL_CLKSEL_TIMER2_CLK_CLKSEL_CLK_M_OSC;

    while((HWREG(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_TIMER2_CLK) &
           CM_DPLL_CLKSEL_TIMER2_CLK_CLKSEL) !=
           CM_DPLL_CLKSEL_TIMER2_CLK_CLKSEL_CLK_M_OSC);

    HWREG(SOC_CM_PER_REGS + CM_PER_TIMER2_CLKCTRL) |=
                             CM_PER_TIMER2_CLKCTRL_MODULEMODE_ENABLE;

    while((HWREG(SOC_CM_PER_REGS + CM_PER_TIMER2_CLKCTRL) &
    CM_PER_TIMER2_CLKCTRL_MODULEMODE) != CM_PER_TIMER2_CLKCTRL_MODULEMODE_ENABLE);

    while((HWREG(SOC_CM_PER_REGS + CM_PER_TIMER2_CLKCTRL) & 
       CM_PER_TIMER2_CLKCTRL_IDLEST) != CM_PER_TIMER2_CLKCTRL_IDLEST_FUNC);

    while(!(HWREG(SOC_CM_PER_REGS + CM_PER_L3S_CLKSTCTRL) &
            CM_PER_L3S_CLKSTCTRL_CLKACTIVITY_L3S_GCLK));

    while(!(HWREG(SOC_CM_PER_REGS + CM_PER_L3_CLKSTCTRL) &
            CM_PER_L3_CLKSTCTRL_CLKACTIVITY_L3_GCLK));

    while(!(HWREG(SOC_CM_PER_REGS + CM_PER_OCPWP_L3_CLKSTCTRL) &
           (CM_PER_OCPWP_L3_CLKSTCTRL_CLKACTIVITY_OCPWP_L3_GCLK |
            CM_PER_OCPWP_L3_CLKSTCTRL_CLKACTIVITY_OCPWP_L4_GCLK)));

    while(!(HWREG(SOC_CM_PER_REGS + CM_PER_L4LS_CLKSTCTRL) &
           (CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_L4LS_GCLK |
            CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_TIMER2_GCLK)));

}

void IntMasterIRQEnable(void)
{
    /* Enable IRQ in CPSR.*/
    CPUirqe();

}



/*
** DMTimer interrupt service routine. This will send a character to serial 
** console.
*/    
void DMTimerIsr(void)
{
    /* Disable the DMTimer interrupts */
    DMTimerIntDisable(SOC_DMTIMER_2_REGS, DMTIMER_INT_OVF_EN_FLAG);

    /* Clear the status of the interrupt flags */
    DMTimerIntStatusClear(SOC_DMTIMER_2_REGS, DMTIMER_INT_OVF_IT_FLAG);

    flagIsr = 1;


    /* Enable the DMTimer interrupts */
    DMTimerIntEnable(SOC_DMTIMER_2_REGS, DMTIMER_INT_OVF_EN_FLAG);
}

/** Do the necessary DMTimer configurations on to AINTC.
*/
void DMTimerAintcConfigure(void)
{
    /* Initialize the ARM interrupt control */
    IntAINTCInit();

    /* Registering DMTimerIsr */
    //IntRegister(SYS_INT_TINT2, DMTimerIsr);



    /* Set the priority */
    IntPrioritySet(SYS_INT_TINT2, 0, AINTC_HOSTINT_ROUTE_IRQ);

    /* Enable the system interrupt */
    IntSystemEnable(SYS_INT_TINT2);
}


#endif
/*
 * timer without interrupts
 */
ulong get_timer(ulong base)
{
	return get_timer_masked() - base;
}

/* delay x useconds */
void __udelay(unsigned long usec)
{
	long tmo = usec * (TIMER_CLOCK / 1000) / 1000;
	unsigned long now, last = readl(&timer_base->tcrr);

	while (tmo > 0) {
		now = readl(&timer_base->tcrr);
		if (last > now) /* count up timer overflow */
			tmo -= TIMER_OVERFLOW_VAL - last + now + 1;
		else
			tmo -= now - last;
		last = now;
	}
}
extern ulong timestamp;
void reset_timer_masked (void)
{
	/* reset time */
	//printf("tcrr:0x%x\n",readl(&timer_base->tcrr));
	gd->lastinc = readl(&timer_base->tcrr) / (TIMER_CLOCK / CONFIG_SYS_HZ);  /* capure current decrementer value time */
	gd->tbl = 0;
}


ulong get_timer_masked(void)
{
	/* current tick value */

	ulong now = readl(&timer_base->tcrr) / (TIMER_CLOCK / CONFIG_SYS_HZ);
	//printf("tcrr###### :0x%x\n",readl(&timer_base->tcrr));
  // printf("#######mask time = 0x%x,gd->lastinc= 0x%x\n",now,gd->lastinc);


	if (now >= gd->lastinc)	/* normal mode (non roll) */
		/* move stamp fordward with absoulte diff ticks */
		{
		   // printf("++++++\n");
		gd->tbl += (now - gd->lastinc);
		}
	else	/* we have rollover of incrementer */
	{
	   // printf("-----------\n");
		gd->tbl += ((TIMER_LOAD_VAL / (TIMER_CLOCK / CONFIG_SYS_HZ))
			     - gd->lastinc) + now;
			     }
	gd->lastinc = now;
	//printf("gd->tbl:%d\n",gd->tbl);
	return gd->tbl;
}
/*
 * This function is derived from PowerPC code (read timebase as long long).
 * On ARM it just returns the timer value.
 */
unsigned long long get_ticks(void)
{
	return get_timer(0);
}

/*
 * This function is derived from PowerPC code (timebase clock frequency).
 * On ARM it returns the number of timer ticks per second.
 */
ulong get_tbclk(void)
{
	return CONFIG_SYS_HZ;
}

  • Hi Gino,

    I will forward this to the SW experts.

  • Hello Gino,

    #Q: Current issue is that it can go to ISR periodically as designed but the progress can't run back to main progress.

    - I guess the timer is frozen when it stopped, TCRR is frozen. The timer can be restarted from the frozen value unless TCRR has been reloaded with a new value.
    Try to reload a new value in TCRR register.

    My second suggestions is related with CPSR register. It seems that it can be freeze when you use void IntMasterIRQEnable(void)
    {
        /* Enable IRQ in CPSR.*/
        CPUirqe();

    }

    See CPUirqe function:

    oid CPUirqe(void)
    {
        /* Enable IRQ in CPSR */
        #if 1
        asm("    mrs     r0, CPSR\n\t"
            "    bic     r0, r0, #0x80\n\t"
            "    msr     CPSR_c, r0");
            #else

                unsigned long temp;
        __asm__ __volatile__("mrs %0, cpsr\n"
                     "bic %0, %0, #0x80\n"
                     "msr cpsr_c, %0"
                     : "=r" (temp)
                     :
                     : "memory");

            #endif
    }

    ; Step 7 : Read-modify-write the CPSR to enable IRQs/FIQs at ARM side
    MRS R0, CPSR ; Read the status register
    BIC R0, R0, #0x80/0x40 ; Clear the I/F bit
    MSR CPSR, R0 ; Write it back to enable IRQs


    ; Step 8 : Jump to relevant subroutine handler

    Best regards,

    Yanko

  • Hello Yanko,

    Thank you for your reply.

    Your first suggestion, " I guess the timer is frozen when it stopped, TCRR is frozen"

    I think it may not be the root cause. Actually, I can see the interrupt occurred constantly. If it is frozen, the interrupt will be triggered once. And also, if I decrease the value, I can see the period between two interrupts can be increased accordingly.So is my understanding right?

    Your second suggestion

    I am not very clear about that. You mean I should also clear fiq bit (0x40) in "bic %0, %0, #0x80", right? Meanwhile I see you mentioned step7&8, so where is the step 1 - 6?

  • Hi Gino,

    About your questions:


    I am not very clear about that. You mean I should also clear fiq bit (0x40) in "bic %0, %0, #0x80", right?

    Meanwhile I see you mentioned step7&8, so where is the step 1 - 6?

    I suggest you to see section 6.2.3 INTC Preemptive Processing Sequence in AM335x TRM.

    1. Save the ARM critical context registers.
    2. Save the INTC_THRESHOLD PRIORITYTHRESHOLD field before modifying it.
    3. Read the active interrupt priority in the INTC_IRQ_PRIORITY IRQPRIORITY/INTC_FIQ_PRIORITY FIQPRIORITY field and write it to the PRIORITYTHRESHOLD(1) field.
    4. Read the active interrupt number in the INTC_SIR_IRQ[6:0] ACTIVEIRQ/INTC_SIR_FIQ[6:0] ACTIVEFIQ field to identify the interrupt source.
    5. Write 1 to the appropriate INTC_CONTROL NEWIRQAGR and (2) NEWFIQAGR bit while an interrupt is still processing to allow only higher priority interrupts to preempt.
    6. Because the writes are posted on an Interconnect bus, to be sure that the preceding writes are done before enabling IRQs/FIQs, a Data Synchronization Barrier is used. This operation ensure that the IRQ line is de-asserted before IRQ/FIQ enabling.
    7. Enable IRQ/FIQ at ARM side.
    8. Jump to the relevant subroutine handler.

    #Q:  I think it may not be the root cause. Actually, I can see the interrupt occurred constantly. If it is frozen, the interrupt will be triggered once. And also, if I decrease the value, I can see the period between two interrupts can be increased accordingly.So is my understanding right?

    OK, however your previous post was: Current issue is that it can go to ISR periodically as designed but the progress can't run back to main progress.

    Could you explain what do you have in mind can't run back to main progress?

    - My understanding is that you must reset GPIOs which controls the LED.

    Best regards,

    Yanko

  • u-boot is usually used in a non-interrupt mode. If you look in the include/configs/am335x_evm.h file you will see

    /* Unsupported features */
    #undef CONFIG_USE_IRQ

    And in timer.c, the polled routines are used by various drivers. I think you said the customer just wants to see status while tftp download, can you just modify one of the network drivers to toggle the LED? I have not tested this so I do not know if the LED would flicker or not show much. I will look around the code. I was thinking maybe toggle the LED on at the top of TftpSend and then toggle it off at the end of TftpSend.

    Steve K.

  • Hello Steve,

    Customer insists on timer interrupt in uboot. They hope we can directly provide the patch for this timer interrupt based on SDK6.0 on AM335x, so could you help it?