MDM9x25 Flashless boot&IPC over HSIC

概述

以EXYNOS加MDM9x25为例,连接示意图如下:
MDM9x25 Flashless boot&IPC over HSIC_第1张图片
Exynos5433需要这几个GPIO以及HSIC,给MDM9x25上电,下载MDM9x25的binary,efs同步以及MDM9x25出错的时候的ramdump collection等工作。
下面按如下步骤来介绍每个部分所需的代码移植,修改以及流程。
- MDM9x25启动,控制GPIO配置
- MDM9x25代码下载以及efs同步过程
- MDM9x25代码下载以及efs同步过程
- MDM9x25的错误处理流程以及ramdump collect过程
- AP与MDM9x25的IPC通信相关模块

MDM9x25的启动,控制部分代码移植修改

KERNEL代码部分:

(1) device tree添加相关的设置

    mdm_pdata {
        compatible = "qcom,ext-mdm9x25";

        pinctrl-names = "default";
        pinctrl-0 = <&ap2mdm_errfatal &ap2mdm_soft_reset &ap2mdm_hostrdy 
            &ap2mdm_status &ap2mdm_hsic_ready>;

        qcom,ramdump-delay-ms = <2000>;
        qcom,ramdump-timeout-ms = <120000>;
        qcom,sfr-query;
        qcom,sysmon-subsys-id = <20>;
        qcom,support-shutdown;

        qcom,mdm2ap-errfatal-gpio = <&gpa2 6 0xf>;
        qcom,ap2mdm-errfatal-gpio = <&gpr3 4 0x1>;
        qcom,mdm2ap-status-gpio   = <&gpa2 3 0xf>;
        qcom,ap2mdm-status-gpio   = <&gpf1 2 0x1>;
        qcom,ap2mdm-soft-reset-gpio = <&gpf5 1 0x1>;
        qcom,mdm2ap-pblrdy-gpio = <&gpa3 0 0xf>;
        qcom,ap2mdm-vddmin-gpio = <&gpf4 6 0x1>;
        qcom,mdm2ap-vddmin-gpio = <&gpa2 5 0x0>;
        qcom,ap2mdm-hsic-ready-gpio = <&gpg2 1 0x1>;
    };

    mdmpm_pdata {
                compatible = "qcom,mdm-hsic-pm";

        qcom,ap2mdm-hostrdy-gpio = <&gpf5 0 0x1>;
        qcom,mdm2ap-devicerdy-gpio = <&gpa1 2 0x0>;
        qcom,mdm2ap-hostwake-gpio = <&gpa3 1 0xf>;

        reg = <0x15510000 0x100>, /* EHCI */
              <0x15530000 0x100>, /* PHY */
              <0x105C0704 0xC>, /* PMU */
              <0x156E0204 0xC>; /* USB phy clk */
    };

    pinctrl@15690000{
        ap2mdm_errfatal: ap2mdm_errfatal {
            samsung,pins = "gpr3-4";
            samsung,pin-function = <0x1>;   /* OUT */
            samsung,pin-pud = <1>;          /* PULL DOWN */
            samsung,pin-drv = <0>;
        };
    };
    pinctrl@11090000{
        ap2mdm_soft_reset: ap2mdm_soft_reset {
            samsung,pins = "gpf5-1";
            samsung,pin-function = <0x1>;   /* OUT */
            samsung,pin-pud = <0>;          /* No PULL */
            samsung,pin-drv = <0>;
        };
        ap2mdm_hostrdy: ap2mdm_hostrdy {
            samsung,pins = "gpf5-0";
            samsung,pin-function = <0x1>;   /* OUT */
            samsung,pin-pud = <1>;          /* PULL DOWN */
            samsung,pin-drv = <0>;
        };
        ap2mdm_status: ap2mdm_status {
            samsung,pins = "gpf1-2";
            samsung,pin-function = <0x1>;   /* OUT */
            samsung,pin-pud = <0>;          /* No PULL */
            samsung,pin-drv = <0>;
        };
    };
    pinctrl@14CC0000{
        ap2mdm_hsic_ready: ap2mdm_hsic_ready {
            samsung,pins = "gpg2-1";
            samsung,pin-function = <0x1>;   /* OUT */
            samsung,pin-pud = <1>;          /* PULL DOWN */
            samsung,pin-drv = <0>;
        };
    };

(2) kernel/exynos54xx/drivers/esoc目录添加,并使能如下feature。

//以下是esoc文件夹下的Makefile文件,要使能的feature是
//CONFIG_ESOC,CONFIG_ESOC_DEV,CONFIG_ESOC_MDM_4x,CONFIG_ESOC_MDM_DRV,
//CONFIG_MDM_HSIC_PM这几个。
# generic  external soc control support
ccflags-$(CONFIG_ESOC_DEBUG)   := -DDEBUG
obj-$(CONFIG_ESOC) += esoc_bus.o
obj-$(CONFIG_ESOC_DEV) += esoc_dev.o
obj-$(CONFIG_ESOC_CLIENT)  += esoc_client.o
obj-$(CONFIG_ESOC_MDM_4x)  += esoc-mdm-4x.o
obj-$(CONFIG_ESOC_MDM_DRV) += esoc-mdm-drv.o
obj-$(CONFIG_MDM_HSIC_PM)  += mdm_hsic_pm.o

这里写图片描述

esoc-mdm-4x.c文件:
1) mdm_probe()->mdm9x25_setup_hw()初始化ap2mdm_errfatal,ap2mdm_hostrdy 等几个GPIO。这个过程比较简单不再赘述。
2) mdm9x25_setup_hw()->esoc_clink_register()创建/dev/esoc-0文件让mem_helper能够检查几个gpio状态,并初始化esoc_clink和mdm_ctrl结构。

int esoc_clink_register(){
    ...
    dev->bus = &esoc_bus_type;
    dev->parent = &esoc_bus;
    dev_set_name(dev, "esoc%d", id);
    err = device_register(dev);
    ...
}
esoc_bus为device类型,定义和注册如下,所以上面dev->parent = &esoc_bus的话,device_register(dev)之后会在/sys/devices/esoc-bus目录下生成dev的名字对应的节点。

struct device esoc_bus = {
    .init_name = "esoc-bus"
};
device_register(&esoc_bus);

看一下dev->bus = &esoc_bus_type;这句。这个其实会负责/dev/esoc-0 字符设备
然后设置相应的file_operation等的。然后还可以通过bus_find_device(),根据esoc_bus_type来找对应的dev。
struct bus_type esoc_bus_type = {
    .name = "esoc",
    .match = esoc_bus_match,
    .dev_attrs = esoc_clink_attrs,
};
bus_register(&esoc_bus_type);//注册esoc_bus_type之后,就会在/sys/bus/下生成esoc目录。
//之后在esoc_dev_init函数里边生成class,创建字符设备等,关键一步还是注册bus_register_notifier。这样以esoc_bus_type为dev->bus的设备注册的时候都会调用对应的函数。

int __init esoc_dev_init(void){
    esoc_class = class_create(THIS_MODULE, "esoc-dev");//在sys/class下生成esoc-dev
    esoc_major = register_chrdev(0, "esoc", &esoc_dev_fops);
    ret = bus_register_notifier(&esoc_bus_type, &esoc_dev_notifier);
}
static struct notifier_block esoc_dev_notifier = {
    .notifier_call = esoc_dev_notifier_call,
};
//添加设备的时候,查看bus,并调用相应的notifier函数的过程在:drivers/base/core.c文件中的
//device_add()函数中。
/* /* Notify clients of device addition. This call must come * after dpm_sysfs_add() and before kobject_uevent(). */
    if (dev->bus)
        blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                         BUS_NOTIFY_ADD_DEVICE, dev);
*/


//这样在esoc_clink_register()函数中注册dev的话,因为这个dev->bus是esoc_bus_type就会调用到下面的函数,生成/dev/esoc-0,相应的设备号创建和file_operation的定义也可以很容易看到。
//esoc_dev_notifier_call()->esoc_clink_add_device()
int esoc_clink_add_device(struct device *dev, void *dummy)
{
    struct esoc_udev *esoc_udev;
    struct esoc_clink *esoc_clink = to_esoc_clink(dev);

    esoc_udev = get_free_esoc_udev(esoc_clink);
    if (IS_ERR(esoc_udev))
        return PTR_ERR(esoc_udev);
    //下面创建/dev/esoc-0
    esoc_udev->dev = device_create(esoc_class, &esoc_clink->dev,
                    MKDEV(esoc_major, esoc_clink->id),
                    esoc_clink, "esoc-%d", esoc_clink->id);
    if (IS_ERR(esoc_udev->dev)) {
        pr_err("failed to create user device\n");
        goto dev_err;
    }
    return 0;
dev_err:
    return_esoc_udev(esoc_udev);
    return -ENODEV;
}
static const struct file_operations esoc_dev_fops = {
    .owner      = THIS_MODULE,
    .open       = esoc_dev_open,
    .unlocked_ioctl = esoc_dev_ioctl,
    .release    = esoc_dev_release,
};

esoc-mdm-drv.c文件:

int __init esoc_ssr_init(void)
{
    pr_err("[MIF] %s", __func__);
#if defined(CONFIG_MACH_TRLTE_LDU) || defined(CONFIG_MACH_TBLTE_LDU)
    pr_err("%s LDU doesn't have modem, skip esoc drv register", __func__);
    return 0;
#endif
    return esoc_drv_register(&esoc_ssr_drv);
}
//在注册driver的过程中,bus和probe需要被赋值。这样在driver_register的过程中,会调用到bus->match函数,也就是esoc_bus_match()函数来和dev进行匹配(过程是driver_register()->bus_add_driver()->driver_attach()->__driver_attach()->driver_match_device(),因为drv->bus->p->drivers_autoprobe默认是1,所以如果不改动的话,就会调用的相应bus的match函数,如果匹配成功的话,就会调用driver_probe_device()函数等,调用自己的probe函数)。

int esoc_drv_register(struct esoc_drv *driver)
{
    int ret;

    driver->driver.bus = &esoc_bus_type;
    driver->driver.probe = esoc_bus_probe; //bus->match函数匹配成功就会调用这个probe函数
    ret = driver_register(&driver->driver); //
    if (ret)
        return ret;
    return 0;
}
struct bus_type esoc_bus_type = {
    .name = "esoc",
    .match = esoc_bus_match, 
    //这个match比较compat_table里边的名字和esoc_link.name。由于esoc_link.name定义成了
    //MDM9x25_LABEL也就是MDM9x25,所以下面的drv也必须匹配才能调用probe函数
    .dev_attrs = esoc_clink_attrs,
};

static struct esoc_drv esoc_ssr_drv = {
    .owner = THIS_MODULE,
    .probe = esoc_ssr_probe,
    .compat_table = compat_table,
    .compat_entries = ARRAY_SIZE(compat_table),
    .driver = {
        .name = "mdm-4x",
    },
};

static struct esoc_compat compat_table[] = {
    {   .name = "MDM9x25",
        .data = NULL,
    },
    {
        .name = "MDM9x35",
        .data = NULL,
    },
};
struct bus_type esoc_bus_type = {
    .name = "esoc",
    .match = esoc_bus_match,
    .dev_attrs = esoc_clink_attrs,
};

struct bus_type esoc_bus_type = {
    .name = "esoc",
    .match = esoc_bus_match,
    .dev_attrs = esoc_clink_attrs,
};

上面的执行完之后,就会生成/sys/bus/esoc/drivers/mdm-4x

root@royceltectc:/sys/bus/esoc/drivers/mdm-4x # ls -l
ls -l
--w------- root root 4096 2015-01-13 16:35 bind
lrwxrwxrwx root root 2015-01-13 16:35 esoc0 -> ../../../../devices/qcom,mdm1.50/esoc0
--w------- root root 4096 2015-01-13 16:35 uevent
--w------- root root 4096 2015-01-13 16:35 unbind
int esoc_ssr_probe(struct esoc_clink *esoc_clink)
{
    int ret;
    struct mdm_drv *mdm_drv;
    struct esoc_eng *esoc_eng;

    pr_info("[MIF] %s\n", __func__);
    mdm_drv = devm_kzalloc(&esoc_clink->dev, sizeof(*mdm_drv), GFP_KERNEL);
    if (IS_ERR(mdm_drv))
        return PTR_ERR(mdm_drv);
    esoc_eng = &mdm_drv->cmd_eng;
    esoc_eng->handle_clink_evt = mdm_handle_clink_evt;
    ret = esoc_clink_register_cmd_eng(esoc_clink, esoc_eng);
    if (ret) {
        dev_err(&esoc_clink->dev, "failed to register cmd engine\n");
        return ret;
    }

    //设置subsystem restart的函数,具体看下面函数体。
    ret = mdm_register_ssr(esoc_clink);
    if (ret)
        goto ssr_err;
    mdm_drv->mdm_queue = alloc_workqueue("mdm_drv_queue", 0, 0);
    if (!mdm_drv->mdm_queue) {
        dev_err(&esoc_clink->dev, "could not create mdm_queue\n");
        goto queue_err;
    }
    //设置drv_data为mdm_drv,然后初始化mdm_drv。
    esoc_set_drv_data(esoc_clink, mdm_drv);
    init_completion(&mdm_drv->boot_done);
    init_completion(&mdm_drv->req_eng_wait);
    INIT_WORK(&mdm_drv->ssr_work, mdm_ssr_fn);
    mdm_drv->esoc_clink = esoc_clink;
    mdm_drv->mode = PWR_OFF;
    mdm_drv->boot_fail = false;
    //设置重启通知函数
    mdm_drv->esoc_restart.notifier_call = esoc_msm_restart_handler;
    ret = register_reboot_notifier(&mdm_drv->esoc_restart);
    if (ret)
        dev_err(&esoc_clink->dev, "register for reboot failed\n");

    return 0;
queue_err:
    esoc_clink_unregister_ssr(esoc_clink);
ssr_err:
    esoc_clink_unregister_cmd_eng(esoc_clink, esoc_eng);
    return ret;
}

/////////////////////////////////////////////////////
mdm_register_ssr()->esoc_clink_register_ssr()->subsys_register()
struct subsys_device *subsys_register(struct subsys_desc *desc)
{
    struct subsys_device *subsys;
    int ret;

    subsys = kzalloc(sizeof(*subsys), GFP_KERNEL);
    if (!subsys)
        return ERR_PTR(-ENOMEM);

    subsys->desc = desc;
    subsys->owner = desc->owner;
    subsys->dev.parent = desc->dev;
    subsys->dev.bus = &subsys_bus_type;
    subsys->dev.release = subsys_device_release;

    subsys->notify = subsys_notif_add_subsys(desc->name);

    snprintf(subsys->wlname, sizeof(subsys->wlname), "ssr(%s)", desc->name);
    wake_lock_init(&subsys->wake_lock, WAKE_LOCK_SUSPEND, subsys->wlname);
    INIT_WORK(&subsys->work, subsystem_restart_wq_func);
    spin_lock_init(&subsys->track.s_lock);

    subsys->id = ida_simple_get(&subsys_ida, 0, 0, GFP_KERNEL);
    if (subsys->id < 0) {
        ret = subsys->id;
        goto err_ida;
    }
    dev_set_name(&subsys->dev, "subsys%d", subsys->id);

    mutex_init(&subsys->track.lock);

    ret = subsys_debugfs_add(subsys);
    if (ret)
        goto err_debugfs;

    //生成/sys/devices/qcom,mdm1.50/esoc0/subsys0 ,link到
    //sys/bus/msm_subsys/devices/sybsys0
    ret = device_register(&subsys->dev);
    if (ret) {
        device_unregister(&subsys->dev);
        goto err_register;
    }

    //生成/dev/subsys_esoc0,并设置file_operations。
    ret = subsys_misc_device_add(subsys);
    if (ret) {
        put_device(&subsys->dev);
        goto err_register;
    }

    return subsys;

err_register:
    subsys_debugfs_remove(subsys);
err_debugfs:
    mutex_destroy(&subsys->track.lock);
    ida_simple_remove(&subsys_ida, subsys->id);
err_ida:
    wake_lock_destroy(&subsys->wake_lock);
    kfree(subsys);
    return ERR_PTR(ret);
}

(2) arch/arm/mach-xx/subsystem_restart.c文件:

前面已经讲过在esoc_clink_register_ssr()的时候,创建/dev/subsys_esoc0。
subsys_register()->subsys_misc_device_add()对应的file_operation是:
static const struct file_operations subsys_device_fops = {
        .owner = THIS_MODULE,
        .open = subsys_device_open,
        .release = subsys_device_close,
};
//subsys_device_open()这个是用来做subsystem power up的。
//subsys_device_open()->subsystem_get()->subsys_start()->subsys->desc->powerup()
//由于
static int mdm_register_ssr(struct esoc_clink *esoc_clink)
{
    esoc_clink->subsys.shutdown = mdm_subsys_shutdown;
    esoc_clink->subsys.ramdump = mdm_subsys_ramdumps;
    esoc_clink->subsys.powerup = mdm_subsys_powerup;
    esoc_clink->subsys.crash_shutdown = mdm_crash_shutdown;
    return esoc_clink_register_ssr(esoc_clink);
}
所以subsys_device_open()最用调用mdm_subsys_powerup()去给mdm上电。

(3) kernel/exynos54xx/drivers/usb/misc/ks_bridge.c文件修改,识别hsic的device id并创建/dev/ks_bridge节点,用来下载binary, 下载modem ramdump以及做efs sync操作。

ksb_init()->usb_register(&ksb_usb_driver);
//usb驱动定义
static struct usb_driver ksb_usb_driver = {
    .name =     "ks_bridge",
    .probe =    ksb_usb_probe,
    .disconnect =   ksb_usb_disconnect,
    .suspend =  ksb_usb_suspend,
    .resume =   ksb_usb_resume,
    .reset_resume = ksb_usb_resume,
    .id_table = ksb_usb_ids,
    .supports_autosuspend = 1,
};
static const struct usb_device_id ksb_usb_ids[] = {
    { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9008, 0), //0x9008 ks_hsic_bridge设备号
    .driver_info = (unsigned long)&ksb_fboot_dev, },
    { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9048, 2),
    .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
    { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x904C, 2),
    .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
    { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9075, 2),
    .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
    { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9079, 2),
    .driver_info = (unsigned long)&ksb_efs_usb_dev, },
    { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x908A, 2),
    .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
    { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x908E, 3),
    .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
    { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x909C, 2),
    .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
    { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x909D, 2),
    .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
    { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x909E, 3),
    .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
    { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x909F, 2),
    .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
    { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x90A0, 2),
    .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
    { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x90A4, 3),
    .driver_info = (unsigned long)&ksb_efs_hsic_dev, },

    {} /* terminating entry */
};

static struct ksb_dev_info ksb_fboot_dev[] = {
    {
        .name = "ks_hsic_bridge", //用来下载binary,接收modem ramdump的/dev/ks_hsic_bridge
    },
    {
        .name = "ks_usb_bridge",
    },
};

static struct ksb_dev_info ksb_efs_hsic_dev = {
    .name = "efs_hsic_bridge", // /dev/efs_hsic_bridge做efs同步的
};

Bootloader部分代码修改:

    需要在cmdline里边添加“androidboot.baseband=mdm”来选择合适的MDM。
//在esoc-mdm-4x.c文件里边查看如下部分
static struct of_device_id mdm_dt_match[] = {
    { .compatible = "qcom,ext-mdm9x25",
        .data = &mdm9x25_ops, },
    {},
};
MODULE_DEVICE_TABLE(of, mdm_dt_match);

static int __init get_baseband(char *str)
{
    if(!strncasecmp(str, "mdm2", 4)) {
        strcpy(mdm_dt_match->compatible, "qcom,ext-mdm9x35");
        mdm_dt_match->data = &mdm9x35_ops;
    } else if(!strncasecmp(str, "mdm", 3)) {
        strcpy(mdm_dt_match->compatible, "qcom,ext-mdm9x25");
        mdm_dt_match->data = &mdm9x25_ops;
    }
    pr_emerg("%s: %s\n", __func__, mdm_dt_match->compatible);

    return 0;
}
__setup("androidboot.baseband=", get_baseband);

Framework层代码:

(1) vendor/qcom/proprietary/mdm_helper目录添加
(2) vendor/qcom/proprietary/ks目录添加
(3) android/device/samsung/trelte_common/init.trelte.rc添加如下代码,启动mdm_helper和mdm_helper_proxy和设置下载目录等:

//init.xx.rc
on fs
    mkdir /data/tombstones 0771 system system
#MDM requirement
    mkdir /dev/block/modem
    symlink /dev/block/platform/15540000.dwmmc0/by-name/m9kefs1 /dev/block/modem/m9kefs1
    symlink /dev/block/platform/15540000.dwmmc0/by-name/m9kefs2 /dev/block/modem/m9kefs2
    symlink /dev/block/platform/15540000.dwmmc0/by-name/m9kefs3 /dev/block/modem/m9kefs3
    symlink /dev/block/platform/15540000.dwmmc0/by-name/ /dev/block/modem/dump_path
    chown system radio /dev/block/modem/m9kefs1
    chmod 0775 /dev/block/modem/m9kefs1
    chown system radio /dev/block/modem/m9kefs2
    chmod 0775 /dev/block/modem/m9kefs2
    chown system radio /dev/block/modem/m9kefs3
    chmod 0775 /dev/block/modem/m9kefs3
    chown system radio /dev/block/modem/dump_path
    chmod 0775 /dev/block/modem/dump_path

    mkdir /firmware 0771 system system
    mount vfat /dev/block/mmcblk0p13 /firmware ro shortname=lower fmask=0133,dmask=0022
    chown system system /tombstones
    chmod 0775 /tombstones
    mkdir /tombstones/modem 0775 system system
    mkdir /tombstones/lpass 0775 system system
    mkdir /tombstones/wcnss 0775 system system
    mkdir /tombstones/dsps 0775 system system
    rmdir /tombstones/qcks
    mkdir /tombstones/qcks 771 system system
    rmdir /tombstones/efs
    mkdir /tombstones/efs 771 system system
    rmdir /tombstones/mdm
    mkdir /tombstones/mdm 0771 system system


    chown system radio /dev/block/platform/15540000.dw_mmc0/by-name
    chmod 0775 /dev/block/platform/15540000.dw_mmc0/by-name

    write /sys/module/rmnet_usb/parameters/mux_enabled 1
    write /sys/module/rmnet_usb/parameters/no_fwd_rmnet_links 8
    write /sys/module/rmnet_usb/parameters/no_rmnet_insts_per_dev 17
    write /sys/module/rmnet_usb/parameters/rmnet_data_init 1

    # Allow QMUX daemon to assign port open wait time
    chown radio radio /sys/devices/virtual/hsicctl/hsicctl0/modem_wait

    write /sys/module/rmnet_usb/parameters/mux_enabled 1
    write /sys/module/rmnet_usb/parameters/no_fwd_rmnet_links 8
    write /sys/module/rmnet_usb/parameters/no_rmnet_insts_per_dev 17
    write /sys/module/rmnet_usb/parameters/rmnet_data_init 1

    # Allow QMUX daemon to assign port open wait time
    chown radio radio /sys/devices/virtual/hsicctl/hsicctl0/modem_wait

on early-init
    symlink /data/tombstones /tombstones

service mdm_helper /system/bin/mdm_helper
    class core
    onrestart setprop ro.service.mdm_helper_restarted "true"
# disabled

service mdm_helper_proxy /system/bin/mdm_helper_proxy
    class core
    disabled

on property:ro.mdm_helper_proxy_req=true
    start mdm_helper_proxy

MDM9x25 HSIC bringup:上电流程

(1) mdm上电:

//vendor/qcom/proprietary/mdm_helper的代码,会启动如下两个service
service mdm_helper /system/bin/mdm_helper
    class core
    onrestart setprop ro.service.mdm_helper_restarted "true"
    disabled
service mdm_helper_proxy /system/bin/mdm_helper_proxy
    class core
    disabled

/********************************** mdm_helper service和mdm_helper_proxy会用waitqueue方式做一个同步。 因为下载binary和其他的操作都是mdm_helper流程做,如果mdm_helper服务先启动,就必须等到mdm_helper_proxy实际给mdm上电之后mdm_helper服务才能进行下载binary和其他操作。 ***********************************/
1) mdm_helper_proxy是通过打开/dev/subsys_esoc0实际给mdm上电的,这个在上面的subsystem_restart.c文件中已经讲过。
modem_proxy_routine()->打开/dev/subsys_esoc0之后就每0.5秒醒来一次,继续睡眠:
static void* modem_proxy_routine(void *arg)
{
    struct mdm_device *dev = (struct mdm_device*)arg;
    char powerup_node[MAX_PATH_LEN];
    int fd;
    snprintf(powerup_node, sizeof(powerup_node),
            "/dev/subsys_%s",
            dev->esoc_node);
    fd = open(powerup_node, O_RDONLY);
    if (fd < 0) {
        ALOGE("%s: Proxy thread failed to open esoc node: %s",
                dev->mdm_name,
                powerup_node);
    }
    do {
        sleep(50000);
    } while(1);
    return NULL;
}

2) mdm_helper在哪里等待mdm上电完成并继续做接下来的事情呢?
modem_state_machine()->dev->ops.power_up()->mdm9k_powerup():
int mdm9k_powerup(struct mdm_device *dev){
        .....
        if (ioctl(dev->device_descriptor, //打开的是/dev/esoc-0
                    ESOC_WAIT_FOR_REQ, &request) < 0) {
            ALOGE("%s: REQ_ENG: ESOC_WAIT_FOR_REQ ioctl failed",
                    dev->mdm_name);
            return RET_FAILED;
        }
        .....
}
根据打开的节点和cmd,会跑到esoc_dev_ioctl里边
static long esoc_dev_ioctl(struct file *file, unsigned int cmd,
                        unsigned long arg)
{
    .....
    case ESOC_WAIT_FOR_REQ:
        if (esoc_clink->req_eng != &uhandle->eng)
            return -EACCES;
        pr_err("esoc REQ enginer waiting on request\n");
        err = wait_event_interruptible(esoc_udev->req_wait,//这里就是等待mdm上电的地方
                    !kfifo_is_empty(&esoc_udev->req_fifo));
        pr_err("esoc REQ engine released from wait\n");
        if (!err) {
            pr_err("esoc REQ engine reading from req fifo\n");
            err = kfifo_out_spinlocked(&esoc_udev->req_fifo, &req,
                                sizeof(req),
                        &esoc_udev->req_fifo_lock);
            if (err != sizeof(req)) {
                pr_err("read from clink %s req q failed\n",
                            esoc_clink->name);
                return -EIO;
            }
            pr_err("esoc REQ engine processing request\n");
            put_user(req, (unsigned long __user *)uarg);

        }
        return err;
        break;
    ....
}

mdm_helper_proxy在上电成功之后,mdm会拉高pbl管脚,因为之前已经设置了中断,会跑到中断函数mdm_pblrdy_change()。调用顺序是mdm_pblrdy_change()->esoc_clink_queue_request()->esoc_udev_handle_clink_req()->wake_up_interruptible(&esoc_udev->req_wait) 这个应该就是唤醒mdm_helper服务的地方。

<4>[    9.766662]  [4:     mdm_helper: 3137] <3>@BATAUTERR@esoc REQ enginer waiting on request
//打印完esoc REQ enginer waiting on request之后mdm_helper进入睡眠
//在mdm_helper_proxy给mdm上电,检测到pbl之
<6>[   10.186900]  [6:mdm_helper_prox: 3257] ext-mdm qcom,mdm1.50: Powering on modem for the first time
<6>[   10.186918]  [6:mdm_helper_prox: 3257] ext-mdm qcom,mdm1.50: mdm_toggle_soft_reset
<6>[   10.207415]  [0:irq/570-mdm pbl: 1767] ext-mdm qcom,mdm1.50: pbl ready 1:
//这里就是检测到pbl变高的时候中断函数打印的
<3>[   10.207438]  [0:irq/570-mdm pbl: 1767] ext-mdm qcom,mdm1.50: Signaling request engine for images
<4>[   10.207455]  [0:irq/570-mdm pbl: 1767] <3>@BATAUTERR@releasing esoc REQ enginer from wait
//后面mdm_helper等待的waitqueue被唤醒,继续执行下载代码或者接受ramdump的操作
<4>[   10.207508]  [4:     mdm_helper: 3137] <3>@BATAUTERR@esoc REQ engine released from wait
<4>[   10.207534]  [4:     mdm_helper: 3137] <3>@BATAUTERR@esoc REQ engine reading from req fifo
<4>[   10.207556]  [4:     mdm_helper: 3137] <3>@BATAUTERR@esoc REQ engine processing request
<12>[   10.207988]  [4:     mdm_helper: 3137] [ALOG] MDM9x35: Setting up HSIC boot link
<12>[   10.208157]  [4:     mdm_helper: 3137] [ALOG] MDM9x35: configure_flashless_boot_dev: Initiating HSIC unbind
<6>[   10.208539]  [4:     mdm_helper: 3137] s5p-ehci 15510000.usb: remove, state 1
<7>[   10.208571]  [4:     mdm_helper: 3137] s5p-ehci 15510000.usb: roothub graceful disconnect
<6>[   10.208605]  [4:     mdm_helper: 3137] usb usb1: USB disconnect, device number 1
<6>[   10.208626]  [4:     mdm_helper: 3137] usb 1-2: USB disconnect, device number 2
<7>[   10.208651]  [4:     mdm_helper: 3137] usb 1-2: unregistering device
<7>[   10.208672]  [4:     mdm_helper: 3137] usb 1-2: unregistering interface 1-2:1.0
<7>[   10.210592]  [1:     mdm_helper: 3137] usb 1-2: usb_disable_device nuking all URBs
<7>[   10.211908]  [3:     mdm_helper: 3137] usb usb1: unregistering device
<7>[   10.211925]  [3:     mdm_helper: 3137] usb usb1: unregistering interface 1-0:1.0
<7>[   10.212353]  [3:     mdm_helper: 3137] s5p-ehci 15510000.usb: shutdown urb ffffffc0b77ccb40 ep1in-intr
<7>[   10.213146]  [3:     mdm_helper: 3137] usb usb1: usb_disable_device nuking all URBs
<6>[   10.214606]  [0:         mc_log: 3126] MobiCore mcd: 501|SCRYPTO DRV [INFO]: FIPS ECDSA selftest passed.
<6>[   10.255958]  [6:mdm_helper_prox: 3257] ext-mdm qcom,mdm1.50: pblrdy i:0
<6>[   10.255984]  [6:mdm_helper_prox: 3257] ext-mdm qcom,mdm1.50: Set qcom,ap2mdm-hostrdy-gpio to 1 //给mdm上电之后还要拉高ap2mdm-hostrdy-gpio这个gpio。这个管脚一般也表示成AP2MDM_STATUS

MDM9x25 HSIC初始化以及binary下载或者ramdump collect

modem crash触发mdm_errfatal()中断处理函数,然后就是mdm_handle_clink_evt()->mdm_ssr_fn()->subsystem_restart_dev()然后在dev->restart_leve=RESET_SUBSYS_COUPLED的时候,就会再跑到subsystem_restart_wq_func()->mdm_subsys_ramdumps()->mdm_cmd_exe()的ESOC_EXE_DEBUG里,
mdm->debug = 1 后重启cp,等在ramdump collection弄完。
cp重启的时候,会拉高PBL端口,触发mdm_pblrdy_change中断函数,在函数里边检查mdm->debug。等于1的话,就会跑到esoc_clink_queue_request(ESOC_REQ_DEBUG, esoc)->esoc_udev_handle_clink_req()中设置req_fifo的值,并wake_up_interruptible(&esoc_udev->req_wait)。这会唤醒esoc_dev_ioctl中case ESOC_WAIT_FOR_REQ的wait_event_interruptible。并返回req_fifod的值(ESOC_REQ_DEBUG)给应用层。由于modem_state_machine()在开机后会停留在MDM_HELPER_STATE_POST_POWERUP state,每隔一段时间会跑进mdm9k_monitor()函数,用ESOC_WAIT_FOR_REQ读返回值。上面说了重启之后,就会返回ESOC_REQ_DEBUG。所以会赋值dev->required_action = MDM_REQUIRED_ACTION_RAMDUMPS,跑到modem_state_machine()函数的MDM_HELPER_STATE_RAMDUMP状态里边,开始collect_ramdumps。

if (ioctl(dev->device_descriptor,
                    ESOC_WAIT_FOR_REQ, &request) < 0) 

之后mdm9k_powerup()会跑到configure_flashless_boot_dev(),函数如下:

static int configure_flashless_boot_dev(struct mdm_device *dev, int mode)
{
    struct mdm_private_data *pdata = NULL;
    int cmd = ESOC_IMG_XFER_RETRY;
    int req = 0;
    int rcode, fd;
    int i;
    if (!dev) {
        ALOGE("Device structure passed in as NULL");
        return RET_FAILED;
    }
    pdata = (struct mdm_private_data*)dev->private_data;
    if(!pdata) {
        ALOGE("%s: %s: Private data is null",
                dev->mdm_name, __func__);
        return RET_FAILED;
    }
    if(!strncmp(dev->mdm_link, LINK_HSIC, 5)) {
        if (mode == MODE_BOOT || mode == MODE_RAMDUMP) { //boot或者modem crash需要下载ramdump的时候
            ALOGI("%s: Setting up %s boot link",
                    dev->mdm_name,
                    dev->mdm_link);
            for (i = 0; i < NUM_LINK_RETRIES; ++i) {
                if (pdata->peripheral_cmd) {
                    ALOGI("%s: %s: Initiating HSIC unbind",
                            dev->mdm_name,
                            __func__);
                    pdata->peripheral_cmd(dev,
                            PERIPHERAL_CMD_UNBIND);
                }
                if (ioctl(dev->device_descriptor, ESOC_NOTIFY,
                            &cmd) < 0) {
                    ALOGE("%s: :%s: Failed to reset mdm",
                            dev->mdm_name,
                            __func__);
                    return RET_FAILED;
                }
                if (ioctl(dev->device_descriptor,
                            ESOC_WAIT_FOR_REQ,
                            &req) < 0) {
                    ALOGE("%s: %s:wait for image xfer fail",
                            dev->mdm_name,
                            __func__);
                    return RET_FAILED;
                }
                if (req != ESOC_REQ_IMG &&
                        (mode != MODE_RAMDUMP)) {
                    ALOGE("%s: %s: Unnexpected request: %d",
                            dev->mdm_name,
                            __func__,
                            req);
                    continue;
                }
                usleep(500000);
                if (pdata->peripheral_cmd) {
                    ALOGI("%s: %s: Initiating HSIC bind",
                            dev->mdm_name,
                            __func__);
                    pdata->peripheral_cmd(dev,
                            PERIPHERAL_CMD_BIND);
                }
                rcode = WaitForCOMport(
                        pdata->flashless_boot_device,
                        5, 0);
                if (rcode == RET_SUCCESS)
                    break;
            }
            if (rcode != RET_SUCCESS) {
                ALOGE("%s: %s: Failed to setup HSIC link",
                        dev->mdm_name,
                        __func__);
                return RET_FAILED;
            }
        } else if (mode == MODE_RUNTIME) {//系统启动之后做efs sync等
            ALOGI("%s: Setting up %s link for efs_sync",
                    dev->mdm_name,
                    dev->mdm_link);
            peripheral_reset(dev);
            ALOGI("%s: Sending boot status notification to HSIC",
                    dev->mdm_name);
#if 1
            if (ioctl(dev->device_descriptor,
                        ESOC_SET_HSIC_READY) < 0) {
                ALOGE("%s: %s:hsic_ready failed", dev->mdm_name,
                        __func__);
                return RET_FAILED;
            }
#else
            for (i = 0; i < MAX_HSIC_NOTIFICATION_RETRIES; i++) {
                fd = open(HSIC_NOTIFICATION_NODE, O_WRONLY);
                if (fd < 0)
                {
                    if (i >= MAX_HSIC_NOTIFICATION_RETRIES \
                            -1) {
                        ALOGE("%s: node open fail: %s",
                                dev->mdm_name,
                                strerror(errno)
                                );
                        return RET_FAILED;
                    }
                    usleep(100000);
                } else {
                    rcode = write(fd, "1", sizeof(char));
                    close(fd);
                    if (rcode < 0) {
                        ALOGE("%s:node write err: %s",
                                dev->mdm_name,
                                strerror(errno)
                                );
                        return RET_FAILED;
                    } else {
                        ALOGI("%s: Notification sent",
                                dev->mdm_name);
                        break;
                    }
                }
            }
#endif
        }
    } else {
        ALOGE("%s: Link %s not supported by mdm-helper",
                dev->mdm_name,
                dev->mdm_link);
        return RET_FAILED;
    }
    return RET_SUCCESS;
}

configure_flashless_boot_dev()函数负责检查建立hsic通道,这个函数中如果是boot或者ramdump状态,会走如下步骤:
(1) hsic unbind:

    pdata->peripheral_cmd(dev,PERIPHERAL_CMD_UNBIND);

    //这个会跑到mdm_hsic_peripheral_cmd()里边执行如下操作:
    case PERIPHERAL_CMD_UNBIND:
        //transport_unbind_node = "/sys/bus/platform/drivers/s5p-ehci/unbind"
        //transport_unbind_command = "15510000.usb"
        fd = open(pdata->transport_unbind_node, O_WRONLY);
        if (fd < 0) {
            ALOGE("Failed to open bind node : %s", strerror(errno));
            goto error;
        }
        if(write(fd, pdata->transport_unbind_command,
                strlen(pdata->transport_unbind_command)) < 0) {
            ALOGE("Failed to write to bind node: %s",
                    strerror(errno));
            goto error;
        }
        break;

一般输出如下log

<12>[10.208157]  [4:mdm_helper: 3137] [ALOG] MDM9x35: configure_flashless_boot_dev: Initiating HSIC unbind
<6>[10.208539]  [4:mdm_helper: 3137] s5p-ehci 15510000.usb: remove, state 1
<7>[10.208571]  [4:mdm_helper: 3137] s5p-ehci 15510000.usb: roothub graceful disconnect
<6>[10.208605]  [4:mdm_helper: 3137] usb usb1: USB disconnect, device number 1
<6>[10.208626]  [4:mdm_helper: 3137] usb 1-2: USB disconnect, device number 2
<7>[10.208651]  [4:mdm_helper: 3137] usb 1-2: unregistering device
<7>[10.208672]  [4:mdm_helper: 3137] usb 1-2: unregistering interface 1-2:1.0
<7>[10.210592]  [1:mdm_helper: 3137] usb 1-2: usb_disable_device nuking all URBs
<7>[10.211908]  [3:mdm_helper: 3137] usb usb1: unregistering device
<7>[10.211925]  [3:mdm_helper: 3137] usb usb1: unregistering interface 1-0:1.0
<7>[10.212353]  [3:mdm_helper: 3137] s5p-ehci 15510000.usb: shutdown urb ffffffc0b77ccb40 ep1in-intr
<7>[10.213146]  [3:mdm_helper: 3137] usb usb1: usb_disable_device nuking all URBs

(2) ioctl(dev->device_descriptor, ESOC_NOTIFY, &cmd) 这里cmd是ESOC_IMG_XFER_RETRY,所以看mdm_notify函数中的case ESOC_IMG_XFER_RETRY,是在重启mdm。当然后面紧跟的
ioctl(dev->device_descriptor,ESOC_WAIT_FOR_REQ,&req) < 0)跟上面说的一样,在等待mdm重启完毕,modem的pbl被拉高。
跟上面重启的时候一样,也是输入如下log

<6>[10.255958]  [6:mdm_helper_prox:3257] ext-mdm qcom,mdm1.50: pblrdy i:0
<6>[10.255984]  [6:mdm_helper_prox:3257] ext-mdm qcom,mdm1.50: Set qcom,ap2mdm-hostrdy-gpio to 1
...
<7>[10.306512]  [3:mdm_helper: 3137] s5p-ehci 15510000.usb: stop
<7>[10.307539]  [3:mdm_helper: 3137] s5p-ehci 15510000.usb: reset command 0010b06  park=3 ithresh=1 period=512 Reset HALT
<7>[10.307761]  [3:mdm_helper: 3137] s5p-ehci 15510000.usb: irq normal 9 err 0 iaa 4 (lost 0)
<7>[10.307776]  [3:mdm_helper: 3137] s5p-ehci 15510000.usb: complete 9 unlink 0
<7>[10.307791]  [3mdm_helper: 3137] s5p-ehci 15510000.usb: ehci_stop completed status 1000 Halt
<6>[10.307902]  [3:mdm_helper: 3137] s5p-ehci 15510000.usb: USB bus 1 deregistered
<7>[10.307981]  [3:mdm_helper: 3137] samsung-usb2phy 15530000.usb2phy: samsung_usb2phy_shutdown: End of setting for shutdown
<6>[10.308455]  [3:mdm_helper: 3137] ext-mdm qcom,mdm1.50: mdm_toggle_soft_reset
<4>[10.317728]  [3:mdm_helper: 3137] <3>@BATAUTERR@esoc REQ enginer waiting on request
...
<4>[10.329003]  [3:mdm_helper: 3137] <3>@BATAUTERR@esoc REQ engine released from wait
<4>[10.329013]  [3:mdm_helper: 3137] <3>@BATAUTERR@esoc REQ engine reading from req fifo
<4>[10.329023]  [3:mdm_helper: 3137] <3>@BATAUTERR@esoc REQ engine processing request

(3) hsic bind操作:
和上面unbind差不多: pdata->peripheral_cmd(dev, PERIPHERAL_CMD_BIND)
unbind hsic -> mdm重启成功 -> hsic bind之后,就可以找检测到modem hsic,并根据其idVendor和idProduct初始化usb设备。像如下Log,由于modem已经准备进入下载模式或者ramdump collection模式,所以检测到的usb设备号需要和ks_bridge.c文件中的设备号一样才能创建ks_hsic_bridge节点。

static struct ksb_dev_info ksb_fboot_dev[] = {
    {
        .name = "ks_hsic_bridge",
    },
    {
        .name = "ks_usb_bridge",
    },
};

static const struct usb_device_id ksb_usb_ids[] = {
    { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9008, 0),
        .driver_info = (unsigned long)&ksb_fboot_dev, },
    ...
}

以下可以看到bind之后检测到usb设备号的过程

<12>[   10.829278]  [3:     mdm_helper: 3137] [ALOG] MDM9x35: configure_flashless_boot_dev: Initiating HSIC bind
<3>[   10.829789]  [3:     mdm_helper: 3137] s5p-ehci 15510000.usb: s5p_ehci_probe
<7>[   10.829817]  [3:     mdm_helper: 3137] of_get_named_gpio_flags: can't parse gpios property <3>[ 10.829989] [3: mdm_helper: 3137] s5p-ehci 15510000.usb: can not find l2-retention value <6>[ 10.830115] [3: mdm_helper: 3137] s5p-ehci 15510000.usb: IP clock gating is N/A <7>[ 10.831096] [3: mdm_helper: 3137] samsung-usb2phy 15530000.usb2phy: Can't configure specified phy mode
<7>[   10.831145]  [3:     mdm_helper: 3137] samsung-usb2phy 15530000.usb2phy: end of samsung_usb2phy_init
<6>[   10.831174]  [3:     mdm_helper: 3137] s5p-ehci 15510000.usb: EHCI Host Controller
<6>[   10.831255]  [3:     mdm_helper: 3137] s5p-ehci 15510000.usb: new USB bus registered, assigned bus number 1
<7>[   10.831312]  [3:     mdm_helper: 3137] s5p-ehci 15510000.usb: reset hcs_params 0x1212 dbg=0 cc=1 pcc=2 ordered ports=2
<7>[   10.831341]  [3:     mdm_helper: 3137] s5p-ehci 15510000.usb: reset hcc_params a026 thresh 2 uframes 256/512/1024 park
<7>[   10.831617]  [3:     mdm_helper: 3137] s5p-ehci 15510000.usb: park 3
<7>[   10.831659]  [3:     mdm_helper: 3137] s5p-ehci 15510000.usb: reset command 0080b02  park=3 ithresh=8 period=1024 Reset HALT
<6>[   10.831750]  [3:     mdm_helper: 3137] s5p-ehci 15510000.usb: irq 254, io mem 0x15510000
<7>[   10.831786]  [3:     mdm_helper: 3137] s5p-ehci 15510000.usb: init command 0010b05  park=3 ithresh=1 period=512 RUN
<6>[   10.845956]  [3:     mdm_helper: 3137] s5p-ehci 15510000.usb: USB 2.0 started, EHCI 1.00
<7>[   10.846591]  [3:     mdm_helper: 3137] usb usb1: default language 0x0409
<7>[   10.846774]  [3:     mdm_helper: 3137] usb usb1: udev 1, busnum 1, minor = 0
<6>[   10.846797]  [3:     mdm_helper: 3137] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
<6>[   10.846820]  [3:     mdm_helper: 3137] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
<6>[   10.846843]  [3:     mdm_helper: 3137] usb usb1: Product: EHCI Host Controller
<6>[   10.846864]  [3:     mdm_helper: 3137] usb usb1: Manufacturer: Linux 3.10.61-5726939-eng ehci_hcd
<6>[   10.846885]  [3:     mdm_helper: 3137] usb usb1: SerialNumber: 15510000.usb
<7>[   10.848957]  [3:     mdm_helper: 3137] usb usb1: usb_probe_device
<7>[   10.848992]  [3:     mdm_helper: 3137] usb usb1: configuration #1 chosen from 1 choice
<7>[   10.849108]  [3:     mdm_helper: 3137] usb usb1: adding 1-0:1.0 (config #1, interface 0)
<7>[   10.849929]  [3:     mdm_helper: 3137] hub 1-0:1.0: usb_probe_interface
<7>[   10.849965]  [3:     mdm_helper: 3137] hub 1-0:1.0: usb_probe_interface - got id
<6>[   10.850005]  [3:     mdm_helper: 3137] hub 1-0:1.0: USB hub found
<6>[   10.850102]  [3:     mdm_helper: 3137] hub 1-0:1.0: 2 ports detected
<7>[   10.850133]  [3:     mdm_helper: 3137] hub 1-0:1.0: standalone hub
<7>[   10.850155]  [3:     mdm_helper: 3137] hub 1-0:1.0: individual port power switching
<7>[   10.850176]  [3:     mdm_helper: 3137] hub 1-0:1.0: individual port over-current protection
<7>[   10.850198]  [3:     mdm_helper: 3137] hub 1-0:1.0: power on to power good time: 20ms
<7>[   10.850302]  [3:     mdm_helper: 3137] hub 1-0:1.0: local power source is good
<7>[   10.850730]  [3:     mdm_helper: 3137] hub 1-0:1.0: enabling power on all ports
<12>[   10.851554]  [3:     mdm_helper: 3137] [ALOG] Testing if port "/dev/ks_hsic_bridge" exists
<12>[   10.851813]  [3:     mdm_helper: 3137] [ALOG] Couldn't find "/dev/ks_hsic_bridge", 1 of 5 ... <7>[ 10.976052] [1: khubd: 686] hub 1-0:1.0: state 7 ports 2 chg 0004 evt 0000 <6>[ 10.976151] [1: khubd: 686] hub 1-0:1.0: port 2, status 0501, change 0000, 480 Mb/s <7>[ 11.036044] [1: khubd: 686] s5p-ehci 15510000.usb: port 2 reset complete, port enabled <7>[ 11.036083] [1: khubd: 686] s5p-ehci 15510000.usb: GetStatus port:2 status 001005 0 ACK POWER sig=se0 PE CONNECT <7>[ 11.037397] [4: main: 3171] SELinux: initialized (dev tmpfs, type tmpfs), uses transition SIDs <6>[ 11.096075] [1: khubd: 686] usb 1-2: new high-speed USB device number 2 using s5p-ehci <7>[ 11.127606] [0: khubd: 686] usb 1-2: default language 0x0409 <7>[ 11.128296] [1: khubd: 686] usb 1-2: udev 2, busnum 1, minor = 1 //以下就是到的modem的hsic设备号。 <6>[ 11.128323] [1: khubd: 686] usb 1-2: New USB device found, idVendor=05c6, idProduct=9008 <6>[ 11.128346] [1: khubd: 686] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0 <6>[ 11.128367] [1: khubd: 686] usb 1-2: Product: QHSUSB__BULK <6>[ 11.128390] [1: khubd: 686] usb 1-2: Manufacturer: Qualcomm CDMA Technologies MSM <7>[ 11.129616] [1: khubd: 686] usb 1-2: usb_probe_device <7>[ 11.129651] [1: khubd: 686] usb 1-2: configuration #1 chosen from 1 choice <7>[ 11.130061] [1: khubd: 686] usb 1-2: adding 1-2:1.0 (config #1, interface 0) <7>[ 11.130791] [1: khubd: 686] ks_bridge 1-2:1.0: usb_probe_interface <7>[ 11.130824] [1: khubd: 686] ks_bridge 1-2:1.0: usb_probe_interface - got id <6>[ 11.132053] [2: khubd: 686] usb 1-2: usb dev connected ...

(4) loadSahara()
走下载binary或者下载ramdump的流程,流程都是按照sahara协议走的。
下载binary的流程:
MDM9x25 Flashless boot&IPC over HSIC_第2张图片
MDM9x25 Flashless boot&IPC over HSIC_第3张图片

传一个binary的log,和上图的流程一样
01-01 23:45:52.880  3357  3357 I kickstart: EVENT: !@ STATE <-- SAHARA_WAIT_HELLO
01-01 23:45:52.880  3357  3357 I kickstart: EVENT: !@ RECEIVED <-- SAHARA_HELLO
01-01 23:45:52.880  3357  3357 I kickstart: EVENT: !@ SENDING --> SAHARA_HELLO_RESPONSE
01-01 23:45:52.880  3357  3357 E kickstart: Wrote to /sys/power/wake_lock
01-01 23:45:52.880  3357  3357 I kickstart: EVENT: !@ RECEIVED <-- SAHARA_READ_DATA
01-01 23:45:52.880  3357  3357 E kickstart: !@ Requested ID 25, file: "/firmware/image/tz.mbn"
01-01 23:45:52.880  3357  3357 I kickstart: EVENT: !@ RECEIVED <-- SAHARA_READ_DATA
01-01 23:45:52.880  3357  3357 I kickstart: EVENT: !@ RECEIVED <-- SAHARA_READ_DATA
01-01 23:45:52.890  3357  3357 I kickstart: EVENT: !@ RECEIVED <-- SAHARA_READ_DATA
01-01 23:45:52.900  3357  3357 I kickstart: EVENT: !@ RECEIVED <-- SAHARA_READ_DATA
01-01 23:45:52.910  3357  3357 I kickstart: EVENT: !@ RECEIVED <-- SAHARA_READ_DATA
01-01 23:45:52.910  3357  3357 I kickstart: EVENT: !@ RECEIVED <-- SAHARA_READ_DATA
01-01 23:45:52.940  3470  3470 W System.err: remove failed: ENOENT (No such file or directory) : /data/system/users/userlist.xml.bak
01-01 23:45:52.960  3357  3357 I kickstart: EVENT: !@ RECEIVED <-- SAHARA_READ_DATA
01-01 23:45:52.960  3357  3357 I kickstart: EVENT: !@ RECEIVED <-- SAHARA_READ_DATA
01-01 23:45:52.960  3357  3357 I kickstart: EVENT: !@ RECEIVED <-- SAHARA_READ_DATA
01-01 23:45:52.960  3357  3357 I kickstart: EVENT: !@ RECEIVED <-- SAHARA_READ_DATA
01-01 23:45:52.970  3357  3357 I kickstart: EVENT: !@ RECEIVED <-- SAHARA_END_IMAGE_TX
01-01 23:45:52.970  3357  3357 I kickstart: EVENT: !@ SENDING --> SAHARA_DONE
01-01 23:45:52.970  3357  3357 E kickstart: !@ 275556 bytes transferred in 0.084783 seconds
01-01 23:45:52.970  3357  3357 I kickstart: EVENT: !@ STATE <-- SAHARA_WAIT_DONE_RESP
01-01 23:45:52.970  3357  3357 E kickstart: Wrote to /sys/power/wake_unlock
01-01 23:45:52.970  3357  3357 I kickstart: EVENT: !@ STATE <-- SAHARA_WAIT_HELLO

Memory dump的流程:
MDM9x25 Flashless boot&IPC over HSIC_第4张图片

下载ramdump的时候log如下,可以看到和上图的流程一样

01-01 23:45:52.850  3357  3357 I kickstart: WARNING: function: sahara_start:602 !@ Successfully wrote to disk
01-01 23:45:52.850  3357  3357 E kickstart: !@ Received file 'LPM.BIN'
01-01 23:45:52.850  3357  3357 E kickstart: !@ 16384 bytes transferred in 0.003022 seconds
01-01 23:45:52.850  3357  3357 E kickstart: Opening file '/cpdump/MSGRAM.BIN' for writing
01-01 23:45:52.850  3357  3357 I kickstart: EVENT: !@ SENDING --> SAHARA_MEMORY_READ
01-01 23:45:52.850  3357  3357 I kickstart: EVENT: !@ Sent SAHARA_MEMORY_READ, address 0xFC428000, length 0x4000
01-01 23:45:52.860  3357  3357 I kickstart: WARNING: function: sahara_start:588 !@ Received: 16384 bytes
01-01 23:45:52.860  3357  3357 I kickstart: WARNING: function: sahara_start:593 !@ Writing to disk
01-01 23:45:52.860  3357  3357 I kickstart: WARNING: function: sahara_start:602 !@ Successfully wrote to disk
01-01 23:45:52.860  3357  3357 E kickstart: !@ Received file 'MSGRAM.BIN'
01-01 23:45:52.860  3357  3357 E kickstart: !@ 16384 bytes transferred in 0.002020 seconds
01-01 23:45:52.860  3357  3357 E kickstart: Opening file '/cpdump/DATARAM.BIN' for writing
01-01 23:45:52.860  3357  3357 I kickstart: EVENT: !@ SENDING --> SAHARA_MEMORY_READ
01-01 23:45:52.860  3357  3357 I kickstart: EVENT: !@ Sent SAHARA_MEMORY_READ, address 0xFC190000, length 0x10000
01-01 23:45:52.860  3357  3357 I kickstart: WARNING: function: sahara_start:588 !@ Received: 65536 bytes
01-01 23:45:52.860  3357  3357 I kickstart: WARNING: function: sahara_start:593 !@ Writing to disk
01-01 23:45:52.860  3357  3357 I kickstart: WARNING: function: sahara_start:602 !@ Successfully wrote to disk
01-01 23:45:52.860  3357  3357 E kickstart: !@ Received file 'DATARAM.BIN'
01-01 23:45:52.860  3357  3357 E kickstart: !@ 65536 bytes transferred in 0.002780 seconds
01-01 23:45:52.860  3357  3357 E kickstart: Opening file '/cpdump/CODERAM.BIN' for writing
01-01 23:45:52.860  3357  3357 I kickstart: EVENT: !@ SENDING --> SAHARA_MEMORY_READ
01-01 23:45:52.860  3357  3357 I kickstart: EVENT: !@ Sent SAHARA_MEMORY_READ, address 0xFC100000, length 0x20000
01-01 23:45:52.860  3357  3357 I kickstart: WARNING: function: sahara_start:588 !@ Received: 131072 bytes
01-01 23:45:52.860  3357  3357 I kickstart: WARNING: function: sahara_start:593 !@ Writing to disk
01-01 23:45:52.860  3357  3357 I kickstart: WARNING: function: sahara_start:602 !@ Successfully wrote to disk
01-01 23:45:52.860  3357  3357 E kickstart: !@ Received file 'CODERAM.BIN'
01-01 23:45:52.860  3357  3357 E kickstart: !@ 131072 bytes transferred in 0.004864 seconds
01-01 23:45:52.860  3357  3357 E kickstart: Opening file '/cpdump/OCIMEM.BIN' for writing
01-01 23:45:52.860  3357  3357 I kickstart: EVENT: !@ SENDING --> SAHARA_MEMORY_READ
01-01 23:45:52.860  3357  3357 I kickstart: EVENT: !@ Sent SAHARA_MEMORY_READ, address 0xFE800000, length 0x8800
01-01 23:45:52.870  3357  3357 I kickstart: WARNING: function: sahara_start:588 !@ Received: 34816 bytes
01-01 23:45:52.870  3357  3357 I kickstart: WARNING: function: sahara_start:593 !@ Writing to disk
01-01 23:45:52.870  3357  3357 I kickstart: WARNING: function: sahara_start:602 !@ Successfully wrote to disk
01-01 23:45:52.870  3357  3357 E kickstart: !@ Received file 'OCIMEM.BIN'
01-01 23:45:52.870  3357  3357 E kickstart: !@ 34816 bytes transferred in 0.001515 seconds
01-01 23:45:52.870  3357  3357 E kickstart: !@ Successfully downloaded files from target 
01-01 23:45:52.880  3357  3357 E kickstart: Wrote to /sys/power/wake_unlock

MDM代码下载,efs同步过程

代码添加及修改:

  • KERNEL代码: kernel/drivers/usb/misc/ks_bridge.c
  • APP层代码: android/vendor/qcom/proprietary/ks目录

用户层及内核代码,功能流程:
AP,CP通过HSIC连接的方式,一个特点是CP本身没有Flash等固态存储媒介来保存本身的Binary。
所以在每次启动的时候AP都需要通过HSIC来发送MDM的Binary过去。所以通过hsic建立usb连接,并完成下载。efs同步也需要通过hsic建立usb连接。

MDM代码模块

你可能感兴趣的:(MDM9x25 Flashless boot&IPC over HSIC)