RK3588 EVB1蓝牙休眠唤醒调试

RK3588 EVB1蓝牙休眠唤醒调试

rk平台支持二级休眠,即SOC大部分电都关了,只留下唤醒源需要的电.

rk3588 evb1因为蓝牙相关的部分大部分IO没有接到PMU电源域,所以调试起来需要另外配置,以方便快速验证.

下面,我们以博通AP6275p芯片为例, 分析下快速验证蓝牙休眠唤醒需要的设定(前提是蓝牙已经正常bringup能工作的情况下).

一. DTS全部配置

为了方便只要答案的同学, 这里直接给出配置:

Subject: [PATCH] dts:arm64:rk3588:config for bt wake up from deep sleep

Change-Id: Ia382dbf9860a76d2558f6f6f5f330cd46f58689d
---
 .../boot/dts/rockchip/rk3588-evb1-bt-wakeup.dtsi   | 52 ++++++++++++++++++++++
 .../boot/dts/rockchip/rk3588-evb1-lp4-v10.dts      |  1 +
 2 files changed, 53 insertions(+)
 create mode 100755 arch/arm64/boot/dts/rockchip/rk3588-evb1-bt-wakeup.dtsi

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-bt-wakeup.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-evb1-bt-wakeup.dtsi
new file mode 100755
index 0000000..75f79b8
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-bt-wakeup.dtsi
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2022 Rockchip Electronics Co., Ltd.
+ *
+ */
+
+&rockchip_suspend {
+	rockchip,sleep-mode-config = <
+		(0
+		| RKPM_SLP_ARMOFF_DDRPD
+		)
+	>;
+	rockchip,wakeup-config = <
+		(0
+		| RKPM_CPU0_WKUP_EN
+		| RKPM_GPIO_WKUP_EN
+		)
+	>;
+
+	status = "okay";
+};
+
+&vdd_log_s0 {
+	regulator-state-mem {
+	regulator-on-in-suspend;
+	regulator-suspend-microvolt = <750000>;
+	};
+};
+
+&vcc_3v3_s0 {
+	regulator-state-mem {
+		regulator-on-in-suspend;
+	};
+};
+
+&vcc_1v8_s0 {
+	regulator-state-mem {
+		regulator-on-in-suspend;
+	};
+};
+
+&vdd_1v8_pll_s0 {
+	regulator-state-mem {
+		regulator-on-in-suspend;
+	};
+};
+
+&wireless_bluetooth {
+	interrupt-parent = <&gpio3>;
+	interrupts = ;
+	wakeup-source;
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4-v10.dts
index d1a264f..ecfbad8 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4-v10.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4-v10.dts
@@ -8,6 +8,7 @@
 
 #include "rk3588-evb1-lp4.dtsi"
 #include "rk3588-evb1-imx415.dtsi"
+#include "rk3588-evb1-bt-wakeup.dtsi"
 #include "rk3588-android.dtsi"

二 分析.

2.1 rockchip_suspend节点

+&rockchip_suspend {
+	rockchip,sleep-mode-config = <
+		(0
+		| RKPM_SLP_ARMOFF_DDRPD
+		)
+	>;
+	rockchip,wakeup-config = <
+		(0
+		| RKPM_CPU0_WKUP_EN
+		| RKPM_GPIO_WKUP_EN
+		)
+	>;
+
+	status = "okay";
+};

这里解释下RKPM_GPIO_WKUP_EN节点, 这里是因为唤醒源是BT_WAKE_HOST_H,即GPIO3_A0. 所以RKPM_GPIO_WKUP_EN唤醒源需要开启.

其他修改部分不是很清晰, 比如sleep-mode-config少休眠了很多模块, 待以后进一步澄清.

2.2 电源域

2.2.1 芯片内部电源域

为了支持休眠唤醒, IC部分,至少BT_WAKE_HOST, UART_RTS, BT_REG_ON(图中1,2,3)几个引脚所在的IC模块要有电.

BT_WAKE_HOST因为是中断源.

UART_RTS是为了保持高电平, 不让外部蓝牙模块发信号(这里存疑, 可能是错的. 因为IC没电也可能可以钳住这个电平).

BT_REG_ON是为了保持高电平让外部蓝牙模块不掉电(同上, 可能是错的).

RK3588 EVB1蓝牙休眠唤醒调试_第1张图片

图1

查3588 TRM, 以上电源域都在VD_LOGIC, 所以以下配置打开:

+&vdd_log_s0 {
+	regulator-state-mem {
+	regulator-on-in-suspend;
+	regulator-suspend-microvolt = <750000>;
+	};
+};

RK3588 EVB1蓝牙休眠唤醒调试_第2张图片

图2
2.2.1 芯片外部电源域.

查图1 BT_WAKE_HOST, UART_RTS, BT_REG_ON外部电源域, 就是图1中的4部分, 即VCC_1V8_S0. 所以这个电源域打开.

+&vcc_1v8_s0 {
+	regulator-state-mem {
+		regulator-on-in-suspend;
+	};
+};
2.2.3 蓝牙模块电源域

RK3588 EVB1蓝牙休眠唤醒调试_第3张图片

如上, VCC_3V3_S0(1)和VCC_1V8_S0(2)要有电, 所以对应节点要打开.VCC_1V8_S0已经打开, 所以还需要打开VCC_3V3_S0.

+&vcc_3v3_s0 {
+	regulator-state-mem {
+		regulator-on-in-suspend;
+	};
+};
2.2.4 32K电源域

RK3588 EVB1蓝牙休眠唤醒调试_第4张图片

这里需要说明的是, 假设蓝牙模块外部32K晶振是3588供电, 那对应的3588模块内部外部电源域都要打开, 但我们是8563供32K.

但是如下配置现在已经无法解释了, 不知道当初为啥要配置. (也许是当初看错, 也许是忘了, 这怪开始没总结. 要验证只能重新搭环境看看这个配置是否必要, 等验证了再回来更新)

+&vdd_1v8_pll_s0 {
+	regulator-state-mem {
+		regulator-on-in-suspend;
+	};
+};
2.4.5 中断源配置

如下, 意思是打开中断源. 当然, 即使不需要中断唤醒, "BT,wake_host_irq"节点还是需要配置.

+&wireless_bluetooth {
+	interrupt-parent = <&gpio3>;
+	interrupts = ;
+	wakeup-source;
+};

3 4 rtk蓝牙特殊处理

在调试rtk 8852be芯片蓝牙唤醒过程中,发现Host系统唤醒后,收不到正确的按键值,从而导致系统重新进休眠.
其原因是芯片驱动不完善,醒来后没法通过蓝牙H5协议和Host蓝牙协议栈握手(博通芯片使用H4协议,并用RTS引脚控制蓝牙芯片的数据发送,所以无此问题).

目前解决办法是,在蓝牙唤醒过程中, rfkill-bt.c的驱动中,发送power up按键,这样,系统就能亮屏.不过, 这里有一个side-effect: 唤醒后因为无法握手会重启蓝牙协议栈,导致蓝牙遥控器连上时间会延迟.

diff --git a/net/rfkill/rfkill-bt.c b/net/rfkill/rfkill-bt.c
index 719a23d..e5209e98 100644
--- a/net/rfkill/rfkill-bt.c
+++ b/net/rfkill/rfkill-bt.c
@@ -39,7 +39,7 @@
 #include 
 #include 
 #endif
-
+#include 
 #if 0
 #define DBG(x...) pr_info("[BT_RFKILL]: " x)
 #else
@@ -72,6 +72,7 @@ struct rfkill_rk_data {
 };

 static struct rfkill_rk_data *g_rfkill = NULL;
+static struct input_dev *power_key_dev;

 static const char bt_name[] =
 #if defined(CONFIG_BCM4330)
@@ -721,6 +722,26 @@ static int rfkill_rk_probe(struct platform_device *pdev)

        LOG("%s device registered.\n", pdata->name);

+       /* register input device */
+       power_key_dev = input_allocate_device();
+       if (!power_key_dev) {
+               LOG("ir_dev: not enough memory for input device\n");
+               return -ENOMEM;
+       }
+
+       power_key_dev->name = "bt-powerkey";
+       power_key_dev->id.bustype = BUS_HOST;
+
+       power_key_dev->evbit[0] = BIT_MASK(EV_KEY);
+       set_bit(KEY_POWER, power_key_dev->keybit);
+
+       ret = input_register_device(power_key_dev);
+       if (ret) {
+               input_free_device(power_key_dev);
+               LOG("ir_rx_init: register input device exception, exit\n");
+               return -EBUSY;
+       }
+
        return 0;

 fail_rfkill:
@@ -776,9 +797,32 @@ static int rfkill_rk_remove(struct platform_device *pdev)
        return 0;
 }

+static int rfkill_rk_pm_resume(struct device *pdev)
+{
+       LOG("%s, wake up now send power key.....", __func__);
+
+       input_report_key(power_key_dev, KEY_POWER, 1);
+       input_sync(power_key_dev);
+       msleep(1);
+       input_report_key(power_key_dev, KEY_POWER, 0);
+       input_sync(power_key_dev);
+
+       return 0;
+}
+
+static int rfkill_rk_pm_suspend(struct device *pdev)
+{
+       LOG("%s", __func__);
+
+       return 0;
+}
+
+
 static const struct dev_pm_ops rfkill_rk_pm_ops = {
        .prepare = rfkill_rk_pm_prepare,
        .complete = rfkill_rk_pm_complete,
+       .suspend = rfkill_rk_pm_suspend,
+       .resume = rfkill_rk_pm_resume,
 };

 #ifdef CONFIG_OF

4 结束

完.

你可能感兴趣的:(蓝牙,蓝牙)