1. 程式人生 > >購買開發板後在iTOP4412開發板上移植SDIO介面WIFI方法

購買開發板後在iTOP4412開發板上移植SDIO介面WIFI方法

       近期需要把WiFi無線網路功能移植到在iTOP4412 開發平臺,查閱了相關資料,經過一段時間的研究、除錯,終於成功,將WiFi功能移植到了開發板上面,這裡筆者記錄移植過程及注意事項,方便以後工作需要。

    iTOP4412開發板的WiFi模組與板卡之間的連線採用SDIO介面,WiFi硬體模組使用的是MTKMT6620晶片,MTK提供了Android4.0Android4.4driver, 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介面,另外還需要Pin8Pin10 UART 串列埠另外Pin18,Pin17用於串列埠流控,實際是可以不使用流控功能。 MT6620晶片是複合晶片,除了具備WiFi功能以後,還支援藍芽,FMGPS功能,他們與CPU之間的通訊需要串列埠,另外MT6620韌體補丁的下載也是通過串列埠進行的,所以說串列埠是必不可少的硬體介面,即使您只使用該晶片的WiFi功能。

   除了SDIO介面,UART口以外,還需要與CPU進行互動的介面包括Pin16  PMU_EN ,使能引腳,預設低電平狀態,高電平有效。

  Pin15  WiFI_RESET引腳,預設低電平狀態,高電平有效

,用於復位WiFi晶片; 

  Pin 13  WiFi INT  WiFI的中斷引腳,用於告知CPU有資料來了;

   以上這些引腳需要在BSP中配置,WiFI的驅動會通過這些引腳與MT6620晶片進行通訊;

另外需要強調的是WiFi模組佔用CPUMMC3也可以說就是SDIO匯流排,關於MMCSDSDIO匯流排的來歷這裡不再描述,下圖為核心板WiFi相關部分:


    在iTOP4412 精英版中 mmc0,mmc1匯流排用於eMMCmmc2用於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的指導說明,把NewModify資料夾下面關於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\n");

        }

        //MT66XX SYSRST

        if(gpio_request(EXYNOS4_GPC1(1), "GPC1_1"))

        {

       printk(KERN_ERR "failed to request GPC1_1 for MT6620  SYSRST control\n");

        }

        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!!!\n");

        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!!!\n");

        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\n");

         } 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\n",__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\n");

    } 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\n",__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\n", __FUNCTION__, on, ret);

return ret;

}

     以上兩個檔案的修改最為關鍵,當然您還需要配置MMC3的相關引腳為MMC工作狀態,預設情況下面MMC3相關引腳為複用引腳中的GPIO狀態,我們需要配置為MMC匯流排狀態,筆者在除錯過程中總是發現MMC總線上面沒有命令或者資料輸出,後發現預設情況下MMC3相關引腳並沒有配置成MMC工作模式,檢視Exynos4412   Datasheet後才發現這一問題.修改工作模式後,此問題得到解決.

MTK 官方給的移植文件中會告訴你需要在原始核心程式碼裡面增加哪些檔案,如何在make menuconfig中配置相關部分,這裡就不再詳細描述.

1.4  使用者態空間

下面我們描述一下采用Linux系統和Android系統的使用者都需要注意的地方:

   驅動層移植完成後, MTKPorting Guid會告訴你需要在使用者態執行wmt_launcher工具,作為後臺的一個服務程式執行,該服務會配置串列埠的工作引數,下載韌體補丁到MT6620中,他的原始碼相對比較簡單,只有一個.c檔案:

原始檔案位於MTK釋出包:

APEX_Android_4.4_MP_SW_package_V2.0/APEX_Android_4.4_MP_001_panda_combo_mt66xx_Package_Common/New/hardware/mediatek/wmt/ stp_uart_launcher.c

修改後的檔案位於iTOP4412 Android4.4釋出包:

 iTop4412_KK4.4/hardware/mediatek/wmt/stp_uart_launcher.c

修改點主要在串列埠引數配置上,由於核心版本不同,串列埠設定引數也略有不同.

具體修改可以使用程式碼比對工具進行比較。

    另外需要說明的是執行wmt_launcher的執行引數 跟MTK給的移植文件有點不同,Porting Guid 裡面推薦串列埠波特率使用921600, 而在iTOP4412的板子上面採用該值會工作不正常,導致韌體補丁無法下載,開始懷疑板卡不支援該波特率,後使用串列埠測試工具專門針對這個串列埠進行921600測試,也沒發現問題,後沒有繼續查詢,而是執行wmt_launcher時採用115200波特率:

wmt_launcher  -b 115200  -d  /dev/ttySAC0  -p  /system/etc/firmware &

注意:  如果您的作業系統使用的是Linux而不是Android,需要修改stp_uart_launcher.c

原始程式碼裡面有Android特有的屬性相關部分,Linux系統不具有這個特性,我們提供了修改好的檔案:stp_uart_launcher-linux-ok.c ,使用者可以作為參考,該檔案與原始檔案stp_uart_launcher-ori.c,及正常工作的檔案 stp_uart_launcher.c 位於相同目錄下面.

    執行  wmt_launcher 服務後,然後執行 "echo  1  > /dev/wmtWifi"命令,如果工作正常,會產生wlan0網路節點,如果沒有產生裝置節點中間會提示出錯資訊,需要根據資訊查詢相關問題,預設情況下WiFi驅動的除錯級別為DEBUG級別,可以提升除錯級別為更高,當然不要忘記把Kernel控制檯輸出級別也設定的高一些,驅動的輸出資訊依賴於驅動程式碼設定的除錯級別及Kernel的控制檯級別兩部分

    除錯資訊多一些,方便定位與分析問題,驅動工作正常後需要把除錯級別恢復為正常狀態,過多的除錯資訊輸出會影響驅動的工作效率和工作的結果,筆者在除錯MMC部分由於把MMC匯流排的除錯資訊全部放開,導致MMC工作效率降低,WiFi相關驅動總是適配不到SDIO裝置,因為WiFI驅動會按一定的迴圈次數查詢SDIO裝置,由於SDIO相關驅動工作效率很低(大量的除錯資訊輸出引起),導致WiFi驅動輪訓次數結束了都沒有匹配到裝置。

   如果產生了wlan0裝置節點,那麼下一步就是移植wpa_supplicantwpa_cli程式了,Android4.4採用的wpa_supplicanat_8 版本,而不是以前Android4.0採用的wpa_supplicant版本,他們之間的差異還是比較大的,顯著的一個區別是Android4.4裡面 wpa_supplicant_8使用的是 NL80211驅動庫。而Android4.0中的wpa_supplicant採用的是WEXT 驅動庫,如果您使用的是Android4.4的核心版本,執行的是Linux系統,那麼需要您移植wpa_supplicanat_8Linux檔案系統中。

Android4.4系統包含wpa_supplicant_8程式碼,編譯Android4.4時會編譯生產wpa_supplicant_8.

wpa_cliwpa_supplicant的客戶端程式,可以使用該程式掃描無線網路,設定網路的ESSID和密碼,連線到無線網路,Linux使用者需要使用wpa_cli進行網路連線。Android使用者也可以在命令列中使用該工具驗證WiFi驅動及wpa_supplicant_8是否工作正常.

這些都沒有問題後我們需要移植HAL層相關程式碼。

1.5  HAL層移植

 HAL層移植相對簡單,MT6620 採用的是AndroidWiFi架構,沒有經過修改,按照MTK的指導文件移植即可,這裡需要注意的是wifi.c檔案和init.connectivity.rc檔案.

1.5.1 wifi.c檔案

 wifi.c檔案的路徑

iTop4412_KK4.4/hardware/libhardware_legacy/wifi.c

該檔案會與wpa_supplicnat服務進行通訊,是Android進行WIFi控制的HAL層的實現,根據logcat 輸出資訊判斷WiFi 工作流程哪裡出了問題,筆者修改了wifi.c檔案的巨集定義:

static char primary_iface[PROPERTY_VALUE_MAX];

// TODO: use new ANDROID_SOCKET mechanism, once support for multiple

// sockets is in

//dg cancel for mt6620

//#define WIFI_DRIVER_MODULE_NAME1"rtl8188eu"

//#define WIFI_DRIVER_MODULE_PATH1        "/system/lib/modules/rtl8188eu.ko"

//#define WIFI_DRIVER_MODULE_NAME2"rtl8192cu"

//#define WIFI_DRIVER_MODULE_PATH2        "/system/lib/modules/rtl8192cu.ko"

//#define WIFI_DRIVER_MODULE_NAME3"rt5370sta"

//#define WIFI_DRIVER_MODULE_PATH3        "/system/lib/modules/rt5370sta.ko"

    由於我們在 init.connectivity.rc  裡面載入了  WiFi驅動庫及執行 wmt_launcher服務,所以不再需要wif.c載入驅動了,直接註釋掉相關巨集即可.

wifi.c的 int wifi_load_driver() 函式會設定wifi的相關屬性:

static const char DRIVER_PROP_NAME[]    = "wlan.driver.status";

property_set(DRIVER_PROP_NAME, "ok");

設定屬性後會觸發WiFi上電操作,因為我們在init.connectivity.rc設定了屬性觸發:

# monitor property and power on/off wlan 

on property:wlan.driver.status=ok

write /dev/wmtWifi "1"

on property:wlan.driver.status=unloaded

write /dev/wmtWifi "0"

wifi.c 會啟動wpa_suplicant服務:

int wifi_start_supplicant(int p2p_supported)

該函式會查詢wpa_supplicant服務是否已經執行,如沒有執行會啟動該服務.

1.5.2  init.connectivity.rc 檔案

init.connectivity.rc 原始檔案有MTK提供:

iTop4412_KK4.4/hardware/mediatek/config/combo_mt66xx/ init.combo_mt66xx.rc

原始檔名稱為 init.combo_mt66xx.rc,拷貝到ramdiskroot目錄下面名稱變更為init.connectivity.rc檔案 。

我們在該檔案增加了載入驅動模組庫操作,執行wmt_lanucher服務操作,另外需要注意檔案原有的建立wifi相關目錄操作,及修改許可權,變更擁有者,這些command非常的重要,比如:

    mkdir /data/misc/wifi 0770 wifi wifi

    mkdir /data/misc/wifi/sockets 0770 wifi wifi

    mkdir /data/misc/wpa_supplicant 0770 wifi wifi

    mkdir /data/misc/p2p_supplicant 0770 wifi wifi

    chown wifi wifi /data/misc/wifi/wpa_supplicant.conf

    chown wifi wifi /data/misc/wifi/p2p_supplicant.conf

    chmod 0660 /data/misc/wifi/wpa_supplicant.conf

    chmod 0660 /data/misc/wifi/p2p_supplicant.conf

  wpa_supplicant會在/data/misc/wifi/sockets目錄下面建立wlan0檔案節點用於與外部程式wpa_cli或者Android層服務進行通訊.

  這樣在Android4.4Setting裡面開啟WiFi,就可以掃描到熱點,連線網際網路了,啟動WiFi之前注意關閉有線連線,否則會存在網路訪問衝突.

   注意: Android系統第一次執行是沒有開啟WiFi功能的,如果您的開發板上面有WiFi模組,且手動開啟了Android  Setting介面的 WiFi功能 ,那麼請不要把WiFi模組從底板上面拆除,否則Android啟動過程中因為找不到WiFi模組 ,會頻繁 打印出除錯資訊,導致Android啟動失敗 ,如果確實產生了這個問題,請重新燒寫Android系統此問題即可解決.

1.5 總結

    以上作為 iTOP4412開發平臺移植 WiFi功能的過程總結,即將釋出的Android4.4KernelAndroid層程式碼均包含Porting 後的程式碼,也就是Wifi正常工作的程式碼,方便大家學習和產品研發.

   如果您在實際的專案中需要WiFi功能,請參考我們的原理圖設計硬體,盡力使用相同的WiFi資源,比如WiFi使能配置引腳,WiFi中斷配置引腳,WiFi 復位引腳,串列埠配置引腳等等,這樣您只需要關注硬體部分,驅動使用我們移植好的即可,否則需要您修改WiFi引腳配置,進行必要的除錯工作,增加自己的工作量。