rk平台支持二级休眠,即SOC大部分电都关了,只留下唤醒源需要的电.
rk3588 evb1因为蓝牙相关的部分大部分IO没有接到PMU电源域,所以调试起来需要另外配置,以方便快速验证.
下面,我们以博通AP6275p芯片为例, 分析下快速验证蓝牙休眠唤醒需要的设定(前提是蓝牙已经正常bringup能工作的情况下).
为了方便只要答案的同学, 这里直接给出配置:
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"
+&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少休眠了很多模块, 待以后进一步澄清.
为了支持休眠唤醒, IC部分,至少BT_WAKE_HOST, UART_RTS, BT_REG_ON(图中1,2,3)几个引脚所在的IC模块要有电.
BT_WAKE_HOST因为是中断源.
UART_RTS是为了保持高电平, 不让外部蓝牙模块发信号(这里存疑, 可能是错的. 因为IC没电也可能可以钳住这个电平).
BT_REG_ON是为了保持高电平让外部蓝牙模块不掉电(同上, 可能是错的).
查3588 TRM, 以上电源域都在VD_LOGIC, 所以以下配置打开:
+&vdd_log_s0 {
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <750000>;
+ };
+};
查图1 BT_WAKE_HOST, UART_RTS, BT_REG_ON外部电源域, 就是图1中的4部分, 即VCC_1V8_S0. 所以这个电源域打开.
+&vcc_1v8_s0 {
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+};
如上, VCC_3V3_S0(1)和VCC_1V8_S0(2)要有电, 所以对应节点要打开.VCC_1V8_S0已经打开, 所以还需要打开VCC_3V3_S0.
+&vcc_3v3_s0 {
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+};
这里需要说明的是, 假设蓝牙模块外部32K晶振是3588供电, 那对应的3588模块内部外部电源域都要打开, 但我们是8563供32K.
但是如下配置现在已经无法解释了, 不知道当初为啥要配置. (也许是当初看错, 也许是忘了, 这怪开始没总结. 要验证只能重新搭环境看看这个配置是否必要, 等验证了再回来更新)
+&vdd_1v8_pll_s0 {
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+};
如下, 意思是打开中断源. 当然, 即使不需要中断唤醒, "BT,wake_host_irq"节点还是需要配置.
+&wireless_bluetooth {
+ interrupt-parent = <&gpio3>;
+ interrupts = ;
+ wakeup-source;
+};
在调试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
完.