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.

Commanded times are (i.e. sleep) are exactly 1.5x longer than requested

Other Parts Discussed in Thread: OMAPL138, DA8XX

I'm have switched the kernel to use timer 2 as its base timer (im on OMAPL138 and DSP is using timer 0 and timer 1). However, since i have done that, when i use the command sleep, it comes out longer than expected. Example sleep(10) lasts exactly 15 seconds.

I imagine the timer configuration is wrong, but I don't know where to fix this in the kernel source. 

  • Hi Daniel,
    What are the changed have you been made ?


    ------------
  • We have only made changes so that the arm uses timer2, we have not changed anything else.

    In arch/arm/mach-davinci/da850.c added the following;

    Line 51: Added timer 2 define

    /* jnz: added to setup clk for time 2 and 3 */
    #define SUSPSRC_TIMER2_SRC	BIT(29)
    
    

    Line 203: Added timer 2 clk struct

    /* jnz: added for kernel to use timer2 as system clock */
    static struct clk timerp64_2_clk = {
    	.name		= "timer2",
    	.parent		= &pll0_sysclk2,
    };
    

    Line 799: Ifdef'd out timer 0 and use timer 2

    /* jnz use timer 2 for ARM */
    #ifdef CONFIG_NGCC_TIMER_O
    /*
     * T0_BOT: Timer 0, bottom		: Used for clock_event
     * T0_TOP: Timer 0, top			: Used for clocksource
     * T1_BOT, T1_TOP: Timer 1, bottom & top: Used for watchdog timer
     */
    static struct davinci_timer_info da850_timer_info = {
    	.timers		= da850_timer_instance,
    	.clockevent_id	= T0_BOT,
    	.clocksource_id	= T0_TOP,
    };
    
    #elif defined(CONFIG_NGCC_TIMER_2)
    /*
     * T0_BOT: Timer 0, bottom		: Used for clock_event
     * T0_TOP: Timer 0, top			: Used for clocksource
     * T1_BOT, T1_TOP: Timer 1, bottom & top: Used for watchdog timer
     * jnz use timer2 for system clock
     * T0_BOT: Timer 2, bottom		: Used for clock_event
     * T0_TOP: Timer 2, top			: Used for clocksource
     */
    static struct davinci_timer_info da850_timer_info = {
    	.timers		= da850_timer_instance,
    	.clockevent_id	= T2_BOT,
    	.clocksource_id	= T2_TOP,
    };
    #endif


    Line 1180: da850 Init: setup timer 2
    void __init da850_init(void)
    {
    	unsigned int v;
    
    	davinci_common_init(&davinci_soc_info_da850);
    
    	da8xx_syscfg0_base = ioremap(DA8XX_SYSCFG0_BASE, SZ_4K);
    	if (WARN(!da8xx_syscfg0_base, "Unable to map syscfg0 module"))
    		return;
    
    	da8xx_syscfg1_base = ioremap(DA8XX_SYSCFG1_BASE, SZ_4K);
    	if (WARN(!da8xx_syscfg1_base, "Unable to map syscfg1 module"))
    		return;
    
    	/*
    	 * Move the clock source of Async3 domain to PLL1 SYSCLK2.
    	 * This helps keeping the peripherals on this domain insulated
    	 * from CPU frequency changes caused by DVFS. The firmware sets
    	 * both PLL0 and PLL1 to the same frequency so, there should not
    	 * be any noticible change even in non-DVFS use cases.
    	 */
    	da850_set_async3_src(1);
    
    	/* Unlock writing to PLL0 registers */
    	v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP0_REG));
    	v &= ~CFGCHIP0_PLL_MASTER_LOCK;
    	__raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP0_REG));
    
    	/* Unlock writing to PLL1 registers */
    	v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG));
    	v &= ~CFGCHIP3_PLL1_MASTER_LOCK;
    	__raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG));
    
    #ifdef CONFIG_NGCC_TIMER_2
        	/* jnz: added to setup clk for timer2 */
    	/* Set timer2 src to ARM */
    	v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_SUSPSRC_REG));
    	v &= ~SUSPSRC_TIMER2_SRC;
    	__raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_SUSPSRC_REG));
    #endif
    
    	da850_timer64p2_base = ioremap(DA850_TIMER64P2_BASE, SZ_4K);
    	if (WARN(!da850_timer64p2_base, "Unable to map timer2 module"))
    		return;
    
    	da850_timer_instance[2].base = DA850_TIMER64P2_VIRT;
    
    }
    

    In arch/arm/mach-davinci/include/mach/da8xx.h added the following;

    Line 56:

    /* jnz: added to setup clk for the timer2 and 3 */
    #define DA8XX_SUSPSRC_REG	0x170
    

    In arch/arm/mach-davinci/time.c added the following;

    Line 110:

    /* jnz: added timer2/3 for linux to use */
    static char *id_to_name[] = {
    	[T0_BOT]	= "timer0_0",
    	[T0_TOP]	= "timer0_1",
    	[T1_BOT]	= "timer1_0",
    	[T1_TOP]	= "timer1_1",
    	[T2_BOT]	= "timer2_0",
    	[T2_TOP]	= "timer2_1",
    	[T3_BOT]	= "timer3_0",
    	[T3_TOP]	= "timer3_1",
    };
    

    Line 220: timer_init: Changed the for loop to only init timer 2

    static void __init timer_init(void)
    {
    	struct davinci_soc_info *soc_info = &davinci_soc_info;
    	struct davinci_timer_instance *dtip = soc_info->timer_info->timers;
    	int i;
    
    	/* Global init of each 64-bit timer as a whole */ /* jnz: only do time 2 */
            /* jnz: dsp use time0 and also use timer1 for watchdog, so we use time2 */
    	for(i=2; i<3; i++) {
    		u32 tgcr;
    //		void __iomem *base = ioremap(dtip[i].base, SZ_4K);
    		void __iomem *base = dtip[i].base;
    

    Line 485: Change to timer 2

    	/* jnz - change to timer 2 */
    #ifdef CONFIG_NGCC_TIMER_O
    	timer_clk = clk_get(NULL, "timer0");
    //	printk(KERN_WARNING "using timer 0\n");
    #elif defined(CONFIG_NGCC_TIMER_2)
    	timer_clk = clk_get(NULL, "timer2");
    //	printk(KERN_WARNING "using timer 2\n");
    #endif
    

    In arch/arm/mach-davinci/include/mach/time.h added the following;

    /* jnz added timer 2/3 */
    enum {
    	T0_BOT,
    	T0_TOP,
    	T1_BOT,
    	T1_TOP,
    	T2_BOT,
    	T2_TOP,
    	T3_BOT,
    	T3_TOP,
    	NUM_TIMERS
    };
    
    /* jnz: added and modified to support timer2 and 3 */
    #define IS_TIMER3(id)		(id & 0x6)
    #define IS_TIMER2(id)		(id & 0x4)
    #define IS_TIMER1(id)		(id & 0x2)
    #define IS_TIMER0(id)		(!(id & 0xe))
    #define IS_TIMER_TOP(id)	((id & 0x1))
    #define IS_TIMER_BOT(id)	(!IS_TIMER_TOP(id))
    
    /* jnz */
    //#define ID_TO_TIMER(id)		( IS_TIMER1(id) != 0)
    #define ID_TO_TIMER(id)		( id >> 1)
    
    extern struct davinci_timer_instance davinci_timer_instance[];
    
    #endif /* __ARCH_ARM_MACH_DAVINCI_TIME_H */
    

  • I think i have found the problem, now i  just need to figure out how to solve it. We have the higher speed 450 Mhz device, not the standard 300Mhz, so i  have to setup the code to handle this.

    See the comment in da8xx.h:

    /*
     * If the DA850/OMAP-L138/AM18x SoC on board is of a higher speed grade
     * (than the regular 300Mhz variant), the board code should set this up
     * with the supported speed before calling da850_register_cpufreq().
     */
    

    I will look for where to fix this, but please tell me if you already know.

    UPDATE:

    I've added this code (originally from baord-da850-evem.c) and a call to it to my board file.

    #ifdef CONFIG_CPU_FREQ
    static __init int da850_evm_init_cpufreq(void)
    {
    	switch (system_rev & 0xF) {
    	case 3:
    		da850_max_speed = 456000;
    		break;
    	case 2:
    		da850_max_speed = 408000;
    		break;
    	case 1:
    		da850_max_speed = 372000;
    		break;
    	}
    
    	return da850_register_cpufreq("pll0_sysclk3");
    }
    #else
    static __init int da850_evm_init_cpufreq(void) { return 0; }
    #endif
    

    I've also enabled the option CONFIG_CPU_FREQ in the menuconfig. However, doing this gives the following compile errors; 

    arch/arm/mach-davinci/built-in.o: In function `davinci_cpu_exit':
    cpufreq.c:(.text+0x2e44): undefined reference to `cpufreq_frequency_table_put_attr'
    arch/arm/mach-davinci/built-in.o: In function `davinci_target':
    cpufreq.c:(.text+0x2ee0): undefined reference to `cpufreq_frequency_table_target'
    arch/arm/mach-davinci/built-in.o: In function `davinci_verify_speed':
    cpufreq.c:(.text+0x2fc4): undefined reference to `cpufreq_frequency_table_verify'
    arch/arm/mach-davinci/built-in.o: In function `davinci_cpu_init':
    cpufreq.c:(.text+0x3118): undefined reference to `cpufreq_frequency_table_cpuinfo'
    cpufreq.c:(.text+0x312c): undefined reference to `cpufreq_frequency_table_get_attr'
    arch/arm/mach-davinci/built-in.o:(.data+0x3d88): undefined reference to `cpufreq_freq_attr_scaling_available_freqs'
    make: *** [.tmp_vmlinux1] Error 1

    After some searching I found we need to enable the option CONFIG_CPU_FREQ_TABLE, however this is incomplete in the kconfig

    (/drivers/cpufreq/kconfig)

    config CPU_FREQ_TABLE
    tristate

    I've changed it to:

    config CPU_FREQ_TABLE
    bool "CPU_FREQ_TABLE"
    help
    This used to just be tristate, but needed to enable so changed
    to bool type. -DRW

    Then enabled it in the menuconfig, this allowed me build the kernel... however once the da850_evm_init_cpufreq() function is called, the serial communication of my device gets put to some other baud rate and becomes unreadable (see below). Meanwhile my LED that toggles after a 10 second sleep is still toggling at 15 second rate instead of 10.

    U-Boot 2012.04.01 (Jun 30 2015 - 10:12:28)
    
    DRAM:  64 MiB
    WARNING: Caches not enabled
    Using default environment
    
    In:    serial
    Out:   serial
    Err:   serial
    Net:   DaVinci-EMAC
    Hit any key to stop autoboot:  0
    ## Booting kernel from Legacy Image at c3000000 ...
       Image Name:   Linux-2.6.38+
       Image Type:   ARM Linux Kernel Image (uncompressed)
       Data Size:    1550476 Bytes = 1.5 MiB
       Load Address: c1008000
       Entry Point:  c1008000
       Verifying Checksum ... OK
       Loading Kernel Image ... OK
    OK
    
    Starting kernel ...
    
    Uncompressing Linux... done, booting the kernel.
    evice_add
    Serial: 8250/16550 driver, 3 ports, IRQ sharing disabled
    serial8250.0: ttyS0 at MMIO 0x1c42000 (irq = 25) is a 16550A
    console [ttyS0] enabled
    serial8250.0: ttyS1 at MMIO 0x1d0c000 (irq = 53) is a 16550A
    serial8250.0: ttyS2 at MMIO 0x1d0d000 (irq = 61) is a 16550A
    brd: module loaded
    spi_davinci spi_davinci.1: DMA: supported
    spi_davinci spi_davinci.1: DMA: RX channel: 18, TX channel: 19, event queue: 0
    m25p80 spi1.0: n25q256a (32768 Kbytes)
    Creating 15 MTD partitions on "m25p80":
    0x000000000000-0x000000040000 : "Stage1"
    0x000000040000-0x000000140000 : "Stage2"
    0x000000140000-0x000000180000 : "NVRAM"
    Read MAC address from NVRAM: 08:08:ea:00:00:03
    0x000000180000-0x0000001c0000 : "Mfg Dflts"
    0x0000001c0000-0x000000200000 : "Params"
    0x000000200000-0x000000300000 : "Stage3"
    0x000000300000-0x000000500000 : "FPGA"
    0x000000500000-0x000000900000 : "TestAppDSP"
    0x000000900000-0x000000d00000 : "AppDSP"
    0x000000d00000-0x000000d40000 : "TestAppParams"
    0x000000d40000-0x000000d80000 : "UBL"
    0x000000d80000-0x000000e80000 : "U-boot"
    0x000000e80000-0x000001280000 : "UImage"
    0x000001280000-0x000001880000 : "LinuxInitFS"
    0x000001880000-0x000001c80000 : "LinuxUserFS"
    spi_davinci spi_davinci.1: Controller at 0xfef0e000
    davinci_mdio davinci_mdio.0: davinci mdio revision 1.5
    davinci_mdio davinci_mdio.0: detected phy mask fffffffe
    davinci_mdio.0: probed
    davinci_mdio davinci_mdio.0: phy[0]: device 0:00, driver SMSC LAN8710/LAN8720
    ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
    Initializing USB Mass Storage driver...
    usbcore: registered new interface driver usb-storage
    USB Mass Storage support registered.
    omap_rtc omap_rtc: rtc core: registered omap_rtc as rtc0
    omap_rtc: RTC power up reset detected
    omap_rtc: already running
    TCP cubic registered
    NET: Registered protocol family 17
    oàò|sìnîó|sc
                ?ooìsnìonpo
                           o
    
    
    
                            lbllcl
    
    
    
    
    
    
    
    
                                  l`
                                    c|
    
    
                                      lcl
                                         l
                                          slìclnîó

    Thanks,

    Dan

  • Dear Daniel,
    Better to configure the frequency in u-boot itself.
    Also you can configure the frequency at run time via CPU frequency scaling with user space governor.

    processors.wiki.ti.com/.../OMAP-L1_Linux_Drivers_Usage
    processors.wiki.ti.com/.../OMAPL1:_Changing_the_Operating_Point