zoukankan      html  css  js  c++  java
  • RK30SDK系统重启源码分析

    Linux系统重启的最底层函数是arch_reset,这是一个全局的函数指针变量,定义在 arch/arm/mach-rk30/include/mach/system.h中:

    extern void (*arch_reset)(char, const char *);

    注意,这是一个变量声明,类型为函数指针。并不是函数的声明!它的实现在mach-rk30/reset.c中:


    static void rk30_arch_reset(char mode, const char *cmd)
    {
        u32 boot_flag = 0;
        u32 boot_mode = BOOT_MODE_REBOOT;

        if (cmd) {
            if (!strcmp(cmd, "loader") || !strcmp(cmd, "bootloader"))
                boot_flag = SYS_LOADER_REBOOT_FLAG + BOOT_LOADER;
            else if(!strcmp(cmd, "recovery"))
                boot_flag = SYS_LOADER_REBOOT_FLAG + BOOT_RECOVER;
            else if (!strcmp(cmd, "charge"))
                boot_mode = BOOT_MODE_CHARGE;
        } else {
            if (system_state != SYSTEM_RESTART)
                boot_mode = BOOT_MODE_PANIC;
        }
        writel_relaxed(boot_flag, RK30_PMU_BASE + PMU_SYS_REG0);    // for loader
        writel_relaxed(boot_mode, RK30_PMU_BASE + PMU_SYS_REG1);    // for linux
        dsb();
        /* disable remap */
        writel_relaxed(1 << (12 + 16), RK30_GRF_BASE + GRF_SOC_CON0);
        /* pll enter slow mode */
        writel_relaxed(PLL_MODE_SLOW(APLL_ID) | PLL_MODE_SLOW(CPLL_ID) | PLL_MODE_SLOW(GPLL_ID), RK30_CRU_BASE + CRU_MODE_CON);
        dsb();
        writel_relaxed(0xeca8, RK30_CRU_BASE + CRU_GLB_SRST_SND);
        dsb();
    }

    void (*arch_reset)(char, const char *) = rk30_arch_reset;


    注意,平台的真正实现在rk30_arch_reset中,然后赋值给指针变量arch_reset。 这样,你在其它地方就能把arch_reset当成函数一样任意调用了。为什么要这样?为了封装呀,不同的CPU上可能有不同的实现,但最后暴露给上层的接口始终是arch_reset。

    rk30_arch_reset的内部实现很有意思,第一个参数mode没有用到,参数cmd是一个字符串,"loader" "bootloader"应该是通常的重新启动进入系统;"recovery"应该是重启进入recovery模式, “charge”应该是重启进入充电界面(相当于关机?)

    下面来做个简单测试,随便找个驱动程序,在其probe函数里面加入下面的代码(记得要包含头文件哦),强行重启到recovery模式:

    printk("++++++++reboot to recovery begin ");
    printk("++++++++reboot to recovery begin ");
    arch_reset(0, "recovery");
    printk("++++++++reboot to recovery end ");
    printk("++++++++reboot to recovery end ");

    上电测试,串口中能打印出下面的信息,可以看出在arch_reset之后,系统确实重启了:

    [    1.491413] ++++++++reboot to recovery begin
    [    1.495691] ++++++++reboot to recovery begin
    DDR Version 1.00 20120529
    In
    DDR3
    freq
    300MHz
    config state
    pctl
    phy
    mem

    分析了这么多,那就顺便再看一下S3C2410里面的实现吧, arch_reset的定义在mach-s3c2410/system-reset.h中:

    extern void (*s3c24xx_reset_hook)(void);

    static void
    arch_reset(char mode, const char *cmd)
    {
        if (mode == 's') {
            cpu_reset(0);
        }

        if (s3c24xx_reset_hook)
            s3c24xx_reset_hook();

        arch_wdt_reset();

        /* we'll take a jump through zero as a poor second */
        cpu_reset(0);
    }

    这里又不同于RK30SDK,arch_reset被定义成了一个函数,它在内部又调用了s3c24xx_reset_hook,而s3c24xx_reset_hook却被定义成了一个函数指针变量,估计不同的CPU有不同的代码,让我们继续寻找s3c24xx_reset_hook:


    ./mach-s3c2416/s3c2416.c:87:    s3c24xx_reset_hook = s3c2416_hard_reset;
    ./mach-s3c2412/s3c2412.c:169:    s3c24xx_reset_hook = s3c2412_hard_reset;
    ./mach-s3c2443/s3c2443.c:68:    s3c24xx_reset_hook = s3c2443_hard_reset;

    看到了吧,这3种CPU里面分别对应不同的hook函数,先看看s3c2416_hard_reset的实现:

    static void s3c2416_hard_reset(void)
    {
        __raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST);
    }

    再看看s3c2412_hard_reset的实现:

    static void s3c2412_hard_reset(void)
    {
        /* errata "Watch-dog/Software Reset Problem" specifies that
         * this reset must be done with the SYSCLK sourced from
         * EXTCLK instead of FOUT to avoid a glitch in the reset
         * mechanism.
         *
         * See the watchdog section of the S3C2412 manual for more
         * information on this fix.
         */

        __raw_writel(0x00, S3C2412_CLKSRC);
        __raw_writel(S3C2412_SWRST_RESET, S3C2412_SWRST);

        mdelay(1);
    }

    还有s3c2443_hard_reset的实现:

    static void s3c2443_hard_reset(void)
    {
        __raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST);
    }

    仔细观察,其实都大同小异,应该是2410系列中不同型号的CPU在寄存器上有些细微的差别,或者不同的实现方式。

    不过这里arch_reset的参数的用法不同于RK30SDK,这里用了第一个参数mode, 第二个参数cmd却没有使用,这里先留个问题吧,后续再去深究这2个参数的用法。

  • 相关阅读:
    php RabbitMQ使用
    phalcon: 开启模板缓存和缓存路径
    phalcon:整合官方多模块功能,方便多表查询
    mysql: 模糊查询 feild like keyword or feild like keyword , concat(feild1,feild2,feild3) like keyword
    php的http数据传输get/post...
    java大数字操作:BigInteger,BigDecimal(浮点型)
    DecimalFormat数据格式函数
    MySQL比like语句更高效的写法locate position instr find_in_set
    mysql中使用instr替换like
    mysql中的多行查询结果合并成一个
  • 原文地址:https://www.cnblogs.com/swnuwangyun/p/3245563.html
Copyright © 2011-2022 走看看