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.

DM388: Fast Linux bootup with 4.4 kernel

Part Number: DM388
Other Parts Discussed in Thread: DM385

Team,

Our customer is actively designing with DM388 and wants to optimize the Linux wakeup time to as fast as possible (<1 sec system boot up if possible).

First off, we have together listed the actions needed for the deepsleep mode function:

1. implement DVFS, need to update the new SDK base on 4.4 kernel

2. enabling DVFS/CPUFreq in Linux PSP

3. change the setting of register DEEPSLEEP_CTRL to enter or wakeup from deepsleepmode.

Since the wakeup time of 500msec is only for the DM388, the whole system wakeup is of focus now.

Because the customer had implemented the deepsleep mode function before, they can successfully go into deepsleep mode with 1.1W power consumption in their system, but they then need to kill all applications before going to deepsleep mode, and then reload all applications (like re-building the video stream, running the OSD, etc.) after wake up, the total time is 6 seconds to finish.

Since the 500msec is the wake up time for the DM388 chip only, not the whole system, the customer needs the whole system ready in 1 second or even less after wake-up, is it possible in our new 4.4 Linux SDK?

What experience do any have in fast booting of the newest 4.4 kernel?

We realize there are a variety of Linux distributions optimized specifically for fast wakeup times, and even 3rd party companies that have developed custom SDKs for this purpose, but since the customer will be using our TI DM3x Linux SDK, we'd prefer to use that as the framework for the fast boot.

Comments welcomed!

TY,
CY

  • Hi,

    I will inform my team to look into this issue.

    Regards,

    Anuj

  • Hi,

    AFAIK, bullet-1 and 2 in above questions are already addressed in 4.4 kernel and it can work just with enabling certain kernel configs.
    However, DVFS might need customization based on the devices and peripherals used by the targeted device.

    Cold boot time of 4.4 kernel is approx 20-30 seconds. But this is without much optimization and hence there is huge scope for improving the boot time. Though many other linux distributions supports fast boot, those distributions may not (mostly not) include support for the platform which you are looking for. So, this might require your customer t port the latest kernel on the specific distro, with necessary changes.

    Alternately, he can also choose to optimize the linux boot time with standard techniques such as hibernation, snapshot boot etc with necessary optimization. However, this is not supported in the kernel 4.4 at present !
  • Hi,

    We at PathPartner have implemented hibernate and resume. We have achieved boot time of 3.5 secs with a more complex OS like Android. Also we have implemented the pipelining of the DM38x Video in memory and which could save us a lot of time. But, this requires a considerable amount of time to implement. To expedite it you can contact us at sales@pathpartnertech.com. We are one of the Partners of TI and also maintainers TI's DM series
  • Hi,

    I can boot up our DM388 board to see the shell layer with kernel 4.4(IPNC_RDK_3.9.0) now.

    I test the deep sleep function (echo -n "mem" > /sys/power/state).

    It can sleep but can't wake up from OSC_WAKE pin. (It's OK on IPNC_RDK_3.8.)

    ---------------------------------------------------------------------------------------------------------------------------------------------

    Arago 2016.05 DM388_CSK ttyS0

    DM388_CSK login: root
    root@DM388_CSK:~# echo -n "m[ 47.740930] autorun-usecase.sh[110]: TimeOut occure in boot_proc.
    [ 47.741699] autorun-usecase.sh[110]: Program exit.
    em" > [ 51.758718] autorun-usecase.sh[110]: TimeOut occure in boot_proc.
    [ 51.759473] autorun-usecase.sh[110]: Program exit.
    /sys/power/state
    [ 59.757011] PM: Syncing filesystems ... done.
    [ 59.772217] Freezing user space processes ... (elapsed 0.001 seconds) done.
    [ 59.780593] Freezing remaining freezable tasks ... (elapsed 0.001 seconds) done.
    [ 59.789221] Suspending console(s) (use no_console_suspend to debug)

    ---------------------------------------------------------------------------------------------------------------------------------------------

    Do you have any suggestions?

    Thanks.

    Yours Sincerely,

    S.K.

  • Hi Huang,

    looks like pinmux is not done.

    Can you dump
    # devmem2 0x48140818

    If possible set it with 0x01 and check.
  • Hi,

    I can confirm the U28 pin is the DEVOSC_WAKE mode(0x01).
    -----------------------------------------------------------------------------
    root@DM388_CSK:~# devmem2 0x48140818
    /dev/mem opened.
    Memory mapped at address 0xb6f24000.
    Read at address 0x48140818 (0xb6f24818): 0x000E0001
    -----------------------------------------------------------------------------

    When I press the button, I can see the correct action from Logic 1(3.24v) to Logic 0(0v).

    It still doesn't wake up.
  • Hi Huang,

    Now I am suspecting if deep sleep is enabled in IPNC 3.9. Can you check if deepsleep is enabled and proper polarity is set 0x481C5324? Also do you enable deep sleep explicitly through debugfs entry in IPNC 3.8(If not can you check the value of 0x481C5324 and /sys/kernel/debug/enable_deep_sleep in IPNC 3.8) ?
  • Hi,

    1.
    root@DM388_CSK:/sys/kernel/debug# devmem2 0x481C5324
    /dev/mem opened.
    Memory mapped at address 0xb6f2a000.
    Read at address 0x481C5324 (0xb6f2a324): 0x00016A75
    [host]388_CSK:/sys/kernel/debug#

    (PS: I try to use devmem2 to change the value, but it can't work. I read it again -> 0x00016A75)


    2. The Source of Timer Wake-up can be successful for IPNC_RDK_3.9.
    a. mount -t debugfs debugfs /sys/kernel/debug
    b. echo 5 > /sys/kernel/debug/pm_debug/wakeup_timer_seconds
    c. echo -n "mem" > /sys/power/state
    --------------------------------------------------------
    root@DM388_CSK:/sys/kernel/debug# echo -n "mem" > /sys/power/state
    [ 1579.896746] PM: Syncing filesystems ... done.
    [ 1579.902703] Freezing user space processes ... (elapsed 0.001 seconds) done.
    [ 1579.911125] Freezing remaining freezable tasks ... (elapsed 0.001 seconds) done.
    [ 1579.919793] Suspending console(s) (use no_console_suspend to debug)
    [ 1579.931636] PM: suspend of devices complete after 4.306 msecs
    [ 1579.933527] PM: late suspend of devices complete after 1.873 msecs
    [ 1579.935265] omap_rtc 480c0000.rtc: omap_device: omap_device_idle() called from invalid state 2
    [ 1579.935321] PM: noirq suspend of devices complete after 1.781 msecs
    [ 1579.935325] PM: Resume timer in 5.000 secs (100000000 ticks at 20000000 ticks/sec.)
    [ 1579.939032] omap_hwmod: rtc: _wait_target_ready failed: -16
    [ 1579.954311] PM: noirq resume of devices complete after 18.811 msecs
    [ 1579.955842] PM: early resume of devices complete after 1.395 msecs
    [ 1579.956268] net eth0: initializing cpsw version 1.10 (0)
    [ 1579.956279] net eth0: initialized cpsw ale version 1.3
    [ 1579.958174] net eth0: phy "/ocp/ethernet@4a100000/mdio@4a100800/ethernet-phy@25" not found on slave 0
    [ 1579.958188] libphy: PHY not found
    [ 1579.958196] net eth0: phy "" not found on slave 1, err -19
    [ 1580.020092] PM: resume of devices complete after 64.222 msecs
    [ 1580.108854] Restarting tasks ... done.
    root@DM388_CSK:/sys/kernel/debug#
    --------------------------------------------------------

    3. In IPNC_RDK_3.8, I DO NOT need to run "mount -t debugfs debugfs /sys/kernel/debug".
    I just run "echo -n "mem" > /sys/power/state" and press the button of OSC_WAKE PIN. The device wakes up.
    (I will back to 3.8 to read the value of 0x481C5324.)

    Thanks.
  • Hi ,

    I am still debuging the issue of  OSC_WAKE pin.

    A.) I need confirm one thing. Do I absolutely have to use the circuit of AUX OSC for the deep sleep mode in IPNC_RDK_3.9?  

    B.) Can I also ask a extended question about the power consumption of the deep sleep mode.

    I remove all peripheral devices and use the power supply to measure the current.

    (You can image the board is very clean. There are only DM388 chip, DDR3 DRAM ,  NAND FLASH and SD card.)

    After I run "echo -n "mem"  > /sys/power/state", the current is 387mA@4.2V.   (590mA -> 387mA)

    (From the file of DM385 PowerSpreadSheet Ver1 00 Release.zip, the deep sleep is 107mW.)

    Is my current reasonable? Do you know how to do that 107mW?

    Thanks.

    S.K.

  • Hi SK,

    A.) I need confirm one thing. Do I absolutely have to use the circuit of AUX OSC for the deep sleep mode in IPNC_RDK_3.9?
    Ans: It is optional. It is used if for e.g. precise audio frequency is required, which cannot be derived from DEV OSC. If it is not being used, it need not be controlled for deep sleep.

    B.) Can I also ask a extended question about the power consumption of the deep sleep mode.
    Ans: We need to make sure if the DM38x is actually in deepsleep. We need to confirm this, since I have my doubts as mentioned in previous posts.
  • Hi Dwarakesh,

    I can solve this issue for the OSC_WAKE PIN.

    I use the old file of "sleep81xx.S" to check the flow.

    It can wake up and the current of deep sleep is 125mA@3.8V.( I think I still have the PLL issue.)

    Thanks.
    S.K.
  • Hi S.K,

    Good to know you solved it. Was sleep81xx.S missing in IPNC RDK 3.9 or it was not proper ?
  • Hi Dwarakesh,

    The new sleep81xx.S has some different flow  at the function of  "ENTRY(ti814x_cpu_suspend)"  in IPNC_RDK 3.9.

    I try to use the old flow because it works fine for our board.

    Finally, the old flow is also OK for 3.9.

    Thanks again.

    S.K.

  • Hi SK Huang,

    It is good to know that you identified the fix your self.

    Sleepti81xx.S in 3.9 RDK is changed with a reason like

    1. Kernel 4.4 Compatibility 
    2. WFI 
    3. clock

    I would recommend using new sleep file and adding new functionality to it such as OSC wakeup.  

    If you feel that is not what you want to do, then please make sure that with the old sleep file you are not hitting random issues such as hang or crash in long run. 

    Thanks

  • Hi Ravikiran,

    If I add ARM WFI instruction(one of new flow in sleep81xx.c), It can't wake up with OSC_WAKE PIN.

    Is it a interrupt pin for ARM?   

    Thanks.

    S.K.

  • Hi,

    Have you checked this spruhg1b.pdf - page 279 for OSC WAKE functionality already?
    Please note that OSC Wake is not validated in 3.9 RDK release :)

    Yes it is an event to ARM and type of the event to be configured before device entering deep sleep.

  • Hi Huang,

    For deep sleep flow, it is not expected WFI instruction to be executed.

    If DeepSleep is enabled - enter Deepsleep
    Else WFI (ARM/A8 cpu waits for Interrupt)

    Refer: processors.wiki.ti.com/.../TI81XX_PSP_PM_SUSPEND_RESUME_User_Guide

    OSC_WAKE is not generic interrupt mechanism, which comes through interrupt controller. It is specific to waking up osc. And it looks like it is not a wake up source for WFI

    Can you try the 3.9 code, with just WFI disabled ? Trying this is a safe bet than using 3.8 sleepti81xx.S
  • Hi Ravikiran,

    After I try that, It's not workable for the deep sleep mode in IPNC_RDK_3.9.

    If I remove "WFI", the flow will wake up immediately. It doesn't do the deep sleep action.

    Thanks.

    S.K.

  • Hi Huang,

    We will try this internally and get back to you. Can you provide what all changes you have done ? Have you replaced the sleepti8xx.S file from 3.8 to 3.9. That's the only change you have done, for it to work successfully ?

    You mentioned "If I add ARM WFI instruction(one of new flow in sleep81xx.c), It can't wake up with OSC_WAKE PIN." Can you point to this change in code ?

    Now you say "If I remove "WFI", the flow will wake up immediately. It doesn't do the deep sleep action." What is the difference between this statement and the previous one "If I add ARM WFI instruction(one of new flow in sleep81xx.c), It can't wake up with OSC_WAKE PIN." in terms of changes tried in code ?
  • Hi Dwarakesh,

    1. About this function "ENTRY(ti814x_cpu_suspend)"  of  sleep81xx.S in IPNC_RDK_3.9:

        Please replace  the function with  sleep81xx.S in IPNC_RDK_3.8.

    2. If I add WFI at this file, it can't wake up via OSC_WAKE PIN. Because it is not a interrupt pin, It always blocks here.

        I can know the deep sleep mode doesn't use the WFI.

    3. If I remove WFI from the original  sleep81xx.S in IPNC_RDK_3.9, it doesn't enter the sleep mode.

        This original file(sleep81xx.S) in IPNC_RDK_3.9  is not  workable for the deep sleep mode. 

    Thanks.

    S.K.

  • Hi Huang,

    Please find attached pm-debug.c  It enables debfugfs entry for deep sleep. We tested here with DM38x CSK and IPNC RDK 3.9 package. We are able to wake up using OSC_WAKEUP from deep sleep with sleep81xx.S from the IPNC 3.9 package without any change. Revert back all your changes. Add pm-debug.c in arch/arm/mach-omap2/

    # mount -t debugfs debugfs /sys/kernel/debug

    # echo "1" > /sys/kernel/debug/pm_debug/enable_deep_sleep

    # echo -n "mem" > /sys/power/state

    Thanks @vishwanath patil for helping out

    3666.pm-debug.c
    /*
     * OMAP Power Management debug routines
     *
     * Copyright (C) 2005 Texas Instruments, Inc.
     * Copyright (C) 2006-2008 Nokia Corporation
     *
     * Written by:
     * Richard Woodruff <r-woodruff2@ti.com>
     * Tony Lindgren
     * Juha Yrjola
     * Amit Kucheria <amit.kucheria@nokia.com>
     * Igor Stoppa <igor.stoppa@nokia.com>
     * Jouni Hogander
     *
     * Based on pm.c for omap2
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License version 2 as
     * published by the Free Software Foundation.
     */
    
    #include <linux/kernel.h>
    #include <linux/sched.h>
    #include <linux/clk.h>
    #include <linux/err.h>
    #include <linux/io.h>
    #include <linux/module.h>
    #include <linux/slab.h>
    #include <plat/dmtimer.h>
    
    #include "clock.h"
    #include "powerdomain.h"
    #include "clockdomain.h"
    #include "omap-pm.h"
    
    #include "soc.h"
    #include "cm2xxx_3xxx.h"
    #include "prm2xxx_3xxx.h"
    #include "pm.h"
    
    u32 enable_deep_sleep;
    u32 osc_wake_polarity;
    
    u32 enable_off_mode;
    u32 wakeup_timer_seconds;
    u32 wakeup_timer_milliseconds;
    #if defined(CONFIG_SOC_TI81XX)
    static u32 turnoff_idle_powerdomains;
    #endif
    
    #ifdef CONFIG_DEBUG_FS
    #include <linux/debugfs.h>
    #include <linux/seq_file.h>
    
    static int pm_dbg_init_done;
    
    static int pm_dbg_init(void);
    
    enum {
    	DEBUG_FILE_COUNTERS = 0,
    	DEBUG_FILE_TIMERS,
    };
    
    static const char pwrdm_state_names[][PWRDM_MAX_PWRSTS] = {
    	"OFF",
    	"RET",
    	"INA",
    	"ON"
    };
    
    void pm_dbg_update_time(struct powerdomain *pwrdm, int prev)
    {
    	s64 t;
    
    	if (!pm_dbg_init_done)
    		return ;
    
    	/* Update timer for previous state */
    	t = sched_clock();
    
    	pwrdm->state_timer[prev] += t - pwrdm->timer;
    
    	pwrdm->timer = t;
    }
    
    static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user)
    {
    	struct seq_file *s = (struct seq_file *)user;
    
    	if (strcmp(clkdm->name, "emu_clkdm") == 0 ||
    		strcmp(clkdm->name, "wkup_clkdm") == 0 ||
    		strncmp(clkdm->name, "dpll", 4) == 0)
    		return 0;
    
    	seq_printf(s, "%s->%s (%d)\n", clkdm->name, clkdm->pwrdm.ptr->name,
    		   clkdm->usecount);
    
    	return 0;
    }
    
    static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user)
    {
    	struct seq_file *s = (struct seq_file *)user;
    	int i;
    
    	if (strcmp(pwrdm->name, "emu_pwrdm") == 0 ||
    		strcmp(pwrdm->name, "wkup_pwrdm") == 0 ||
    		strncmp(pwrdm->name, "dpll", 4) == 0)
    		return 0;
    
    	if (pwrdm->state != pwrdm_read_pwrst(pwrdm))
    		printk(KERN_ERR "pwrdm state mismatch(%s) %d != %d\n",
    			pwrdm->name, pwrdm->state, pwrdm_read_pwrst(pwrdm));
    
    	seq_printf(s, "%s (%s)", pwrdm->name,
    			pwrdm_state_names[pwrdm->state]);
    	for (i = 0; i < PWRDM_MAX_PWRSTS; i++)
    		seq_printf(s, ",%s:%d", pwrdm_state_names[i],
    			pwrdm->state_counter[i]);
    
    	seq_printf(s, ",RET-LOGIC-OFF:%d", pwrdm->ret_logic_off_counter);
    	for (i = 0; i < pwrdm->banks; i++)
    		seq_printf(s, ",RET-MEMBANK%d-OFF:%d", i + 1,
    				pwrdm->ret_mem_off_counter[i]);
    
    	seq_printf(s, "\n");
    
    	return 0;
    }
    
    static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user)
    {
    	struct seq_file *s = (struct seq_file *)user;
    	int i;
    
    	if (strcmp(pwrdm->name, "emu_pwrdm") == 0 ||
    		strcmp(pwrdm->name, "wkup_pwrdm") == 0 ||
    		strncmp(pwrdm->name, "dpll", 4) == 0)
    		return 0;
    
    	pwrdm_state_switch(pwrdm);
    
    	seq_printf(s, "%s (%s)", pwrdm->name,
    		pwrdm_state_names[pwrdm->state]);
    
    	for (i = 0; i < 4; i++)
    		seq_printf(s, ",%s:%lld", pwrdm_state_names[i],
    			pwrdm->state_timer[i]);
    
    	seq_printf(s, "\n");
    	return 0;
    }
    
    static int pm_dbg_show_counters(struct seq_file *s, void *unused)
    {
    	pwrdm_for_each(pwrdm_dbg_show_counter, s);
    	clkdm_for_each(clkdm_dbg_show_counter, s);
    
    	return 0;
    }
    
    static int pm_dbg_show_timers(struct seq_file *s, void *unused)
    {
    	pwrdm_for_each(pwrdm_dbg_show_timer, s);
    	return 0;
    }
    
    static int pm_dbg_open(struct inode *inode, struct file *file)
    {
    	switch ((int)inode->i_private) {
    	case DEBUG_FILE_COUNTERS:
    		return single_open(file, pm_dbg_show_counters,
    			&inode->i_private);
    	case DEBUG_FILE_TIMERS:
    	default:
    		return single_open(file, pm_dbg_show_timers,
    			&inode->i_private);
    	}
    }
    
    static const struct file_operations debug_fops = {
    	.open           = pm_dbg_open,
    	.read           = seq_read,
    	.llseek         = seq_lseek,
    	.release        = single_release,
    };
    
    static int pwrdm_suspend_get(void *data, u64 *val)
    {
    	int ret = -EINVAL;
    
    	if (cpu_is_omap34xx())
    		ret = omap3_pm_get_suspend_state((struct powerdomain *)data);
    	*val = ret;
    
    	if (ret >= 0)
    		return 0;
    	return *val;
    }
    
    static int pwrdm_suspend_set(void *data, u64 val)
    {
    	if (cpu_is_omap34xx())
    		return omap3_pm_set_suspend_state(
    			(struct powerdomain *)data, (int)val);
    	return -EINVAL;
    }
    
    DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get,
    			pwrdm_suspend_set, "%llu\n");
    
    static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir)
    {
    	int i;
    	s64 t;
    	struct dentry *d;
    
    	t = sched_clock();
    
    	for (i = 0; i < 4; i++)
    		pwrdm->state_timer[i] = 0;
    
    	pwrdm->timer = t;
    
    	if (strncmp(pwrdm->name, "dpll", 4) == 0)
    		return 0;
    
    	d = debugfs_create_dir(pwrdm->name, (struct dentry *)dir);
    	if (d)
    		(void) debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d,
    			(void *)pwrdm, &pwrdm_suspend_fops);
    
    	return 0;
    }
    
    static int option_get(void *data, u64 *val)
    {
    	u32 *option = data;
    
    	*val = *option;
    
    	return 0;
    }
    
    static int option_set(void *data, u64 val)
    {
    	u32 *option = data;
    
    	*option = val;
    
    	if (option == &enable_off_mode) {
    		if (val)
    			omap_pm_enable_off_mode();
    		else
    			omap_pm_disable_off_mode();
    		if (cpu_is_omap34xx())
    			omap3_pm_off_mode_enable(val);
    	}
    
    #if defined(CONFIG_SOC_TI81XX)
    	if (option == &turnoff_idle_powerdomains) {
    		ti81xx_powerdown_idle_pwrdms(val);
    	}
    #endif
     if (option == &enable_deep_sleep) {
    		printk(KERN_EMERG"deep sleep vishwa\n");
                    ti81xx_enable_deep_sleep(val);
            } else if (option == &osc_wake_polarity) {
                    ti81xx_config_deepsleep_wake_polarity(val);
            }
    
    	return 0;
    }
    
    DEFINE_SIMPLE_ATTRIBUTE(pm_dbg_option_fops, option_get, option_set, "%llu\n");
    
    static int __init pm_dbg_init(void)
    {
    	struct dentry *d;
    
    	if (pm_dbg_init_done)
    		return 0;
    
    	d = debugfs_create_dir("pm_debug", NULL);
    	if (!d)
    		return -EINVAL;
    
    	(void) debugfs_create_file("count", S_IRUGO,
    		d, (void *)DEBUG_FILE_COUNTERS, &debug_fops);
    	(void) debugfs_create_file("time", S_IRUGO,
    		d, (void *)DEBUG_FILE_TIMERS, &debug_fops);
    
    	pwrdm_for_each(pwrdms_setup, (void *)d);
    
    	(void) debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUSR, d,
    				   &enable_off_mode, &pm_dbg_option_fops);
    	(void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUGO, d,
    				   &wakeup_timer_seconds, &pm_dbg_option_fops);
    	(void) debugfs_create_file("wakeup_timer_milliseconds",
    				   S_IRUGO | S_IWUGO, d, &wakeup_timer_milliseconds,
    				   &pm_dbg_option_fops);
    #if defined(CONFIG_SOC_TI81XX)
    	if (soc_is_ti81xx() || (omap_rev() > TI8148_REV_ES1_0)) {
    		(void) debugfs_create_file("turnoff_idle_powerdomains",
    						S_IRUGO | S_IWUGO, d,
    						&turnoff_idle_powerdomains,
    						&pm_dbg_option_fops);
    	}
    #endif
    	 (void) debugfs_create_file("enable_deep_sleep", 
                                                    S_IRUGO | S_IWUGO, d, 
                                                    &enable_deep_sleep, 
                                                    &pm_dbg_option_fops); 
                    (void) debugfs_create_file("deepsleep_polarity", 
                                                    S_IRUGO | S_IWUGO, d, 
                                                    &osc_wake_polarity, 
                                                    &pm_dbg_option_fops); 
    
    	pm_dbg_init_done = 1;
    
    	return 0;
    }
    omap_arch_initcall(pm_dbg_init);
    
    #endif