[RK3399][Android7.1] WiFi中的SDIO和电源框架

2019-07-13 22:48发布

Platform: RK3399
OS: Android 7.1
Kernel: v4.4.83

框架:

引用网友一张框图,画得很不错
这里写图片描述 从硬件角度来看:
CPU -> SDIO -> AP6356S 从软件角度来看分:
电源/IO管理
SDIO通道(Host和Client)
WiFi驱动

电源/GPIO管理模块:

主要完成对电源、GPIO的初始化和控制等。 配置是在DTS中
rk3399-mid-818-android.dts: wireless-wlan { compatible = "wlan-platdata"; rockchip,grf = <&grf>; //AP6354和AP6356S兼容 wifi_chip_type = "ap6354"; sdio_vref = <1800>; //WiFi中断脚,有些模组没有这个脚可以不配置 WIFI,host_wake_irq = <&gpio0 3 GPIO_ACTIVE_HIGH>; /* GPIO0_a3 */ status = "okay"; }; sdio_pwrseq: sdio-pwrseq { compatible = "mmc-pwrseq-simple"; clocks = <&rk818 1>; clock-names = "ext_clock"; pinctrl-names = "default"; pinctrl-0 = <&wifi_enable_h>; /* * On the module itself this is one of these (depending * on the actual card populated): * - SDIO_RESET_L_WL_REG_ON * - PDN (power down when low) */ //到rk3399上面,WL_REG_ON即对WiFi电源的控制是放在sdio模块中了。 reset-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; /* GPIO0_B2 */ }; &sdio0 { cap-sdio-irq; mmc-pwrseq = <&sdio_pwrseq>; }; 解析配置的驱动在rfkill-wlan.c static struct of_device_id wlan_platdata_of_match[] = { { .compatible = "wlan-platdata" }, { } }; static int wlan_platdata_parse_dt(struct device *dev, struct rksdmmc_gpio_wifi_moudle *data) { syscon_regmap_lookup_by_phandle(node, "rockchip,grf"); of_property_read_string(node, "wifi_chip_type", &strings); of_find_property(node, "keep_wifi_power_on", NULL) of_find_property(node, "power_ctrl_by_pmu", NULL) of_get_named_gpio_flags(node, "WIFI,poweren_gpio", 0, &flags); of_get_named_gpio_flags(node, "WIFI,reset_gpio", 0, &flags); of_get_named_gpio_flags(node, "WIFI,host_wake_irq", 0, &flags); }

SDIO Host:

对应的是对CPU上的SDIO Host Controller的控制实现,不管是哪个平台,最终都是通过mmc_add_host()添加mmc框架的core层中去。
host驱动位于kernel/drivers/mmc/host目录,使用的是Synopsys DW(DesignWare)的ip核。 kris@eco:~/rk3399/kernel/drivers/mmc/host$ ls *.o built-in.o dw_mmc-pltfm.o rk_sdmmc_ops.o sdhci-of-arasan.o dw_mmc.o dw_mmc-rockchip.o sdhci.o sdhci-pltfm.o dw_mmc.c: static const struct mmc_host_ops dw_mci_ops = { .request = dw_mci_request, .pre_req = dw_mci_pre_req, .post_req = dw_mci_post_req, .set_ios = dw_mci_set_ios, .set_sdio_status = dw_mci_set_sdio_status, .get_ro = dw_mci_get_ro, .get_cd = dw_mci_get_cd, .enable_sdio_irq = dw_mci_enable_sdio_irq, .execute_tuning = dw_mci_execute_tuning, .card_busy = dw_mci_card_busy, .start_signal_voltage_switch = dw_mci_switch_voltage, .init_card = dw_mci_init_card, .prepare_hs400_tuning = dw_mci_prepare_hs400_tuning, }; static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) { mmc->ops = &dw_mci_ops; dw_mci_slot_of_parse(slot); mmc_of_parse(mmc); mmc_add_host(mmc); } 解析的配置位于sdio0节点中
rk3399-mid-818-android.dts
//板级配置 &sdio0 { clock-frequency = <150000000>; clock-freq-min-max = <200000 150000000>; supports-sdio; bus-width = <4>; disable-wp; cap-sd-highspeed; cap-sdio-irq; keep-power-in-suspend; mmc-pwrseq = <&sdio_pwrseq>; non-removable; num-slots = <1>; pinctrl-names = "default"; pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>; sd-uhs-sdr104; status = "okay"; }; 还有一部分配置在rk3399.dtsi中
//平台配置 sdio0: dwmmc@fe310000 { compatible = "rockchip,rk3399-dw-mshc", "rockchip,rk3288-dw-mshc"; reg = <0x0 0xfe310000 0x0 0x4000>; interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH 0>; clock-freq-min-max = <400000 150000000>; clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>, <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>; clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; power-domains = <&power RK3399_PD_SDIOAUDIO>; status = "disabled"; };

SDIO Client:

对应的是对WiFi模组内部的SDIO控制器的控制实现,因此此模块代码也是集成于WiFi驱动中。
AP6356S用的是broadcom模组,驱动位于kernel/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd目录下
SDIO注册调用流程如下: rockchip_wifi_init_module_rkwifi -> dhd_linux.c wifi_init_thread -> dhd_module_init -> dhd_wifi_platform_register_drv -> dhd_wifi_platform_load -> dhd_wifi_platform_load_sdio -> dhd_bus_register -> bcmsdh_register -> bcmsdh_register_client_driver -> sdio_register_driver 对应sdio_driver: static struct sdio_driver bcmsdh_sdmmc_driver = { .probe = bcmsdh_sdmmc_probe, .remove = bcmsdh_sdmmc_remove, .name = "bcmsdh_sdmmc", .id_table = bcmsdh_sdmmc_ids, }; SDIO Client通过SDIO Host去控制WiFi模块。 WiFi驱动因为内容过多,后面再分析了。

参考:

WiFi驱动(1)框架解析