迅为iTOP4412开发板上如何移植SDIO接口WIFI

2019-07-12 20:35发布

近期需要把WiFi无线网络功能移植到在iTOP4412 开发平台,查阅了相关资料,经过一段时间的研究、调试,终于成功,将WiFi功能移植到了开发板上面,这里笔者记录移植过程及注意事项,方便以后工作需要。
    iTOP4412开发板的WiFi模块与板卡之间的连接采用SDIO接口,WiFi硬件模块使用的是MTK的MT6620芯片,MTK提供了Android4.0及Android4.4的driver, Porting Guid,有了这些就为我们的移植工作做了总体性的指导。

但是仅仅有MTK提供的文档还是远远不够的,毕竟硬件接口定义不同,kernel版本也不同,Android层与MTK提供的代码也有差异,这就需要我们在MTK文档的指导下, Step  by Step 进行 Porting 工作.


移植环境:
    1  iTOP4412 精英版 +  MT6620 WiFi模块
    2  kernel  3.0.15  version
    3  Android4.4.4  
4  Ubuntu12.04  64BIt 开发环境


1.2  硬件相关部分
 下图为WiFi模块与开发板连接的引脚定义,通过该接口可以看出WiFi模块与CPU的交互接口.



    查看WiFi模块的原理图可知,WiFi模块与CPU之间采用SDIO接口进行数据和命令的交互工作,Pin1,2,3,5,6,7 为SDIO接口,另外还需要Pin8,Pin10 UART 串口, 另外Pin18,Pin17用于串口流控,实际是可以不使用流控功能。 MT6620芯片是复合芯片,除了具备WiFi功能以后,还支持蓝牙,FM,GPS功能,他们与CPU之间的通信需要串口,另外MT6620固件补丁的下载也是通过串口进行的,所以说串口是必不可少的硬件接口,即使您只使用该芯片的WiFi功能。

   除了SDIO接口,UART口以外,还需要与CPU进行交互的接口包括Pin16  PMU_EN ,使能引脚,默认低电平状态,高电平有效。
  Pin15  WiFI_RESET引脚,默认低电平状态,高电平有效,用于复位WiFi芯片; 
  Pin 13  WiFi INT  WiFI的中断引脚,用于告知CPU有数据来了;


   以上这些引脚需要在BSP中配置,WiFI的驱动会通过这些引脚与MT6620芯片进行通信;
另外需要强调的是WiFi模块占用CPU的MMC3端口, 也可以说就是SDIO总线,关于MMC,SD,SDIO总线的来历这里不再描述,下图为核心板WiFi相关部分:



    在iTOP4412 精英版中 mmc0,mmc1总线用于eMMC,mmc2用于TF卡,mmc3用于SDIO WiFi,关于wifi的其他硬件连接比如串口,使能(GPIO),复位(GPIO),中断(GPIO)这里不再贴出,具体的请查看开发板的原理图。

    这里重点强调一下 HUB_CONNECT,也就是上图中的L5 引脚,该引脚复用为mmc总线的CD引脚,也就是Card Detect引脚,用于告知MMC3控制器有设备插入,属于中断引脚,我们需要把引脚与CPU的 某GPIO引脚连接:



    以上为iTOP4412 底板原理图WiFi接口部分,请注意HUB_CONNECT引脚通过0欧电阻与6060_GPIO2进行了连接,6060_GPIO2为核心板GPIO引脚。

    这样连接的目的是通过软件输出6060_GPIO2低电平,从而HUB_CONNECT引脚为低电平输入状态,MMC3控制认为有设备插入到了MMC3总线上面,原理同TF卡,SD卡的检测。

   以上为进行Porting前的准备工作,当然需要万用表,示波器工具进行辅助的检测,查看WiFi模块的工作电压是否正常,GPIO的当前状态,MMC总线上面的时钟及是否有数据从MMC3控制器输出等等.

1.3  Kernel
1.3.1 概述
    iTOP4412开发板采用的是Linux 3.0.15 版本,MTK官方给的移植Porting没有说明针对具体的 kernel版本,由于是Android4.4,所以kernel应该是3.0以后的版本或者更高支持;

   首先按照PoringGuid的指导说明,把New和Modify文件夹下面关于kernel部分的修改放到我们的kernel代码里面,MT6620的驱动分两个部分, 一部分放在driver/misc/目录下面,文件夹名称 mediatek,里面存放的是WMT,既wireless manage tools, 里面提供了与MT6620  download  firmware patch ,enable /disable WIFi芯片,power on, power off操作的相关驱动部分, 及SDIO总线设备接口驱动Host Interface drivers,这些驱动工作正常后才开始加载WiFi 网络相关驱动。

   我们以驱动库 .ko 的形式编译驱动模块,driver/misc/mediatek/ 库文件与WiFi网络库文件 列表如下::

mtk_hif_sdio.ko ----mmc总线相关接口,mmc总线发现SDIO设备,分配总线地址后,会与该驱动进行适配.适配成功后该驱动会调用WiFi网络驱动;
mtk_stp_uart.ko-----串口相关驱动,通过串口下载固件补丁,设置芯片参数;
mtk_stp_wmt.ko-----core 部分,提供WiFi上电,断电等等相关操作;
mtk_wmt_wifi.ko ----字符设备驱动,创建设备节点用于与用户空间交互; 
wlan_mt6620.ko -- -- WiFi网络相关驱动,不需要我们进行修改;


另外这里附一张MMC驱动框架图:

   因为我们的MT6620模块挂载到了MMC总线上面,属于MMC子系统的工作实例,我们非常有必要熟悉一下mmc驱动架构,是我们移植工作的非常重要的一部分,关于MMC子系统的详细介绍这里不再说明.




1.3.2 代码修改

1  根据硬件连接情况配置必要的平台资源

 修改文件:  kernel/iTop4412_Kernel_3.0/arch/arm/mach-exynos/mach-itop4412.c

 关键函数1: 该函数配置WiFi相关的GPIO引脚为初始化输出状态,或者配置为中断状态
            WIFI驱动会改变这些引脚的状态,这里仅仅是初始化.


   static void __init mtk_combo_init(void)
    {

        //MT66XX PMUEN
        if(gpio_request(EXYNOS4_GPC1(0), "GPC1_0"))
        {
                printk(KERN_ERR "failed to request GPC1_0 for MT6620  PMUEN control ");
        }
        //MT66XX SYSRST
        if(gpio_request(EXYNOS4_GPC1(1), "GPC1_1"))
        {
       printk(KERN_ERR "failed to request GPC1_1 for MT6620  SYSRST control ");

        }
        s3c_gpio_cfgpin(EXYNOS4_GPC1(0), S3C_GPIO_OUTPUT);
        s3c_gpio_cfgpin(EXYNOS4_GPC1(1), S3C_GPIO_OUTPUT);

        gpio_direction_output(EXYNOS4_GPC1(0), 0);
        gpio_direction_output(EXYNOS4_GPC1(1), 0);


        gpio_free(EXYNOS4_GPC1(0));
        gpio_free(EXYNOS4_GPC1(1));

        mdelay(5);

        //need config eint models for Wifi & BGA Interupt
        if (gpio_request(EXYNOS4_GPX2(5), "WiFi INT"))
                printk(KERN_WARNING "MT6620 WiFi INT(GPX2.5) Port request error!!! ");
        else    {
                s3c_gpio_setpull(EXYNOS4_GPX2(5), S3C_GPIO_PULL_NONE);
                s3c_gpio_cfgpin(EXYNOS4_GPX2(5), S3C_GPIO_SFN(0xF));
                gpio_free(EXYNOS4_GPX2(5));
        }

        if (gpio_request(EXYNOS4_GPX2(4), "BGF INT"))
                printk(KERN_WARNING "MT6620 BGA INT(GPX2.4) Port request error!!! ");
        else    {
                s3c_gpio_setpull(EXYNOS4_GPX2(4), S3C_GPIO_PULL_NONE);
                s3c_gpio_cfgpin(EXYNOS4_GPX2(4), S3C_GPIO_SFN(0xF));
                gpio_free(EXYNOS4_GPX2(4));
        }

        //normal it is high level
        if (gpio_request(EXYNOS4_GPX3(2),  "6260_GPIO2")!=0) {
             printk("[mt6620] ERROR:Cannot request 6260_GPIO2 ");
         } else {
             gpio_direction_output(EXYNOS4_GPX3(2), 1);/* WLAN_CHIP_PWD */
             gpio_set_value(EXYNOS4_GPX3(2), 1);
             mdelay(100);
             gpio_free(EXYNOS4_GPX3(2));
}
 
    return; }



关键函数2: setup_mt6620_wlan_power_for_onoff

    该函数为导出函数,WIFi驱动会调用该函数,该函数关键地方是让MMC控制器驱动扫描MMC总线上面的设备,MMC扫描到了WiFI模块才会加载相应的WiFi驱动,这里是主动让MMC扫描,我们的SD卡是采用中断触发的方式扫描,他们本质上都是扫描MMC总线上面的新设备,然后加载对应的设备驱动,具体的可以看一下MMC子系统相关内容.

函数所属文件: kernel/iTop4412_Kernel_3.0/arch/arm/mach-exynos/mach-itop4412.c

void setup_mt6620_wlan_power_for_onoff(int on)
{
    int chip_pwd_low_val;
    int outValue;

    printk("[mt6620] +++ %s : wlan power %s ",__func__, on?"on":"off");

#if 1
    if (on) {
         outValue = 0;
    } else {
        outValue = 1;
    }

   if (gpio_request(EXYNOS4_GPX3(2),  "6260_GPIO2")!=0) {
        printk("[mt6620] ERROR:Cannot request 6260_GPIO2 ");
    } else {
        gpio_direction_output(EXYNOS4_GPX3(2), 1);/* WLAN_CHIP_PWD */
        gpio_set_value(EXYNOS4_GPX3(2), outValue);
        mdelay(100);
        gpio_free(EXYNOS4_GPX3(2));
   }

    if(on)
    {
     //need reset on mt6620 ? need test......
    }
#endif

    extern void sdhci_s3c_sdio_card_detect(struct platform_device *pdev);

   // mdelay(200);

   //need sdhc controler check wifi catd states......
   sdhci_s3c_sdio_card_detect(&s3c_device_hsmmc3);

   printk("[mt6620] --- %s ",__func__);

}
EXPORT_SYMBOL(setup_mt6620_wlan_power_for_onoff);


关键结构体: 该结构体告诉WiFi驱动相关部分使用了平台的哪些GPIO资源.
结构体所属文件: kernel/iTop4412_Kernel_3.0/arch/arm/mach-exynos/mach-itop4412.c

  static struct mtk_wmt_platform_data mtk_wmt_pdata = {
        .pmu =EXYNOS4_GPC1(0), //RK30SDK_WIFI_GPIO_POWER_N,//RK30_PIN0_PB5, //MUST set to pin num in target system
        .rst = EXYNOS4_GPC1(1),//RK30SDK_WIFI_GPIO_RESET_N,//RK30_PIN3_PD0, //MUST set to pin num in target system
        .bgf_int=EXYNOS4_GPX2(4), //IRQ_EINT(20),//RK30SDK_WIFI_GPIO_BGF_INT_B,//RK30_PIN0_PA5,//MUST set to pin num in target system if use UART interface.
        .urt_cts = -EINVAL, // set it to the correct GPIO num if use common SDIO, otherwise set it to -EINVAL.
        .rtc = -EINVAL, //Optipnal. refer to HW design.
        .gps_sync = -EINVAL, //Optional. refer to HW design.
        .gps_lna = -EINVAL, //Optional. refer to HW design.
    };
    static struct mtk_sdio_eint_platform_data mtk_sdio_eint_pdata = {
        .sdio_eint = EXYNOS4_GPX2(5),//IRQ_EINT(21) ,//RK30SDK_WIFI_GPIO_WIFI_INT_B,//53, //MUST set pin num in target system.
    };
    static struct platform_device mtk_wmt_dev = {
        .name = "mtk_wmt",
        .id = 1,
        .dev = {
        .platform_data = &mtk_wmt_pdata,
        },
    };
    static struct platform_device mtk_sdio_eint_dev = {
        .name = "mtk_sdio_eint",
        .id = 1,
        .dev = {
        .platform_data = &mtk_sdio_eint_pdata,
        },
    };
2  WIFI驱动导出函数.

文件:
kernel/iTop4412_Kernel_3.0/drivers/misc/mediatek/combo_mt66xx/wmt/platform/vendor/wmt_plat.c

修改函数:  wmt_plat_sdio_ctrl 
函数说明: 该函数会调用我们上面导出的接口,让MMC总线控制器扫描新设备

INT32 wmt_plat_sdio_ctrl (WMT_SDIO_SLOT_NUM sdioPortType, ENUM_FUNC_STATE on)
{
int ret = 0;

       extern void setup_mt6620_wlan_power_for_onoff(int on);

    if (FUNC_OFF == on)  {
        /* add control logic here to generate SDIO CARD REMOVAL event to mmc/sd
         * controller. SDIO card removal operation and remove success messages
         * are expected.
         */

        //add by dg 2015-04-14
        setup_mt6620_wlan_power_for_onoff(0);
    }
    else {
        /* add control logic here to generate SDIO CARD INSERTION event to mmc/sd
         * controller. SDIO card detection operation and detect success messages
         * are expected.
         */

        //add by dg 2015-04-14
        setup_mt6620_wlan_power_for_onoff(1);

    }
        //extern int omap_mmc_update_mtk_card_status(int state);
        //ret = omap_mmc_update_mtk_card_status((FUNC_OFF == on)? 0: 1);

     WMT_INFO_FUNC(KERN_INFO "%s, on=%d, ret=%d ", __FUNCTION__, on, ret);
return ret;
}

     以上两个文件的修改最为关键,当然您还需要配置MMC3的相关引脚为MMC工作状态,默认情况下面MMC3相关引脚为复用引脚中的GPIO状态,我们需要配置为MMC总线状态,笔者在调试过程中总是发现MMC总线上面没有命令或者数据输出,后发现默认情况下MMC3相关引脚并没有配置成MMC工作模式,查看Exynos4412   Datasheet后才发现这一问题.修改工作模式后,此问题得到解决.

MTK 官方给的移植文档中会告诉你需要在原始内核代码里面增加哪些文件,如何在make menuconfig中配置相关部分,这里就不再详细描述.