build/patch/kernel/archive/sunxi-5.15/patches.megous/misc-modem-power-Simpler-boot-mode-selection-API-add-more-boot-.patch

312 lines
9.7 KiB
Diff
Raw Normal View History

From 3f746fec93dd054eb7d8378f075c2f5a67c19d43 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Thu, 3 Dec 2020 20:00:06 +0100
Subject: [PATCH 277/478] misc: modem-power: Simpler boot mode selection API,
add more boot modes
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/misc/modem-power.c | 129 ++++++++++++++-----------------------
1 file changed, 47 insertions(+), 82 deletions(-)
diff --git a/drivers/misc/modem-power.c b/drivers/misc/modem-power.c
index c33e56f0dc2c..91d2bfdd163e 100644
--- a/drivers/misc/modem-power.c
+++ b/drivers/misc/modem-power.c
@@ -66,6 +66,14 @@ enum {
MPWR_REQ_PWUP,
};
+enum {
+ MPWR_MODE_NORMAL = 1,
+ MPWR_MODE_DUMB,
+ MPWR_MODE_FASTBOOT,
+ MPWR_MODE_ALT1,
+ MPWR_MODE_ALT2,
+};
+
struct mpwr_dev;
struct mpwr_gpio {
@@ -157,6 +165,7 @@ struct mpwr_dev {
// change
spinlock_t lock; /* protects last_request */
int last_request;
+ int powerup_mode;
ktime_t last_wakeup;
struct timer_list wd_timer;
@@ -177,8 +186,6 @@ enum {
/* eg25 */
MPWR_F_GOT_PDN,
/* config options */
- MPWR_F_DUMB_POWERUP,
- MPWR_F_FASTBOOT_POWERUP,
MPWR_F_BLOCKED,
/* file */
MPWR_F_OPEN,
@@ -318,7 +325,7 @@ static const struct mpwr_eg25_qcfg mpwr_eg25_qcfgs[] = {
{ "airplanecontrol", "1", mpwr_eg25_qcfg_airplanecontrol_is_ok },
// available since firmware R07A08_01.002.01.002
- { "fast/poweroff", "1" },
+ { "fast/poweroff", "1" },
};
static char* mpwr_serdev_get_response_value(struct mpwr_dev *mpwr,
@@ -388,12 +395,11 @@ static int mpwr_eg25_power_up(struct mpwr_dev* mpwr)
{
struct gpio_desc *pwrkey_gpio = mpwr_eg25_get_pwrkey_gpio(mpwr);
bool wakeup_ok, status_ok;
- bool needs_restart = false, fastboot;
+ bool needs_restart = false;
u32 speed = 115200;
int ret, i, off;
ktime_t start;
-
- fastboot = test_and_clear_bit(MPWR_F_FASTBOOT_POWERUP, mpwr->flags);
+ int mode = mpwr->powerup_mode;
if (regulator_is_enabled(mpwr->regulator))
dev_warn(mpwr->dev,
@@ -408,7 +414,8 @@ static int mpwr_eg25_power_up(struct mpwr_dev* mpwr)
}
/* Drive default gpio signals during powerup */
- gpiod_direction_output(mpwr->host_ready_gpio, 1);
+ /* host_ready_gpio should be 1 during normal powerup */
+ gpiod_direction_output(mpwr->host_ready_gpio, mode != MPWR_MODE_ALT2);
/* #W_DISABLE must be left pulled up during modem power up
* early on, because opensource bootloader uses this signal to enter
* fastboot mode when it's pulled down.
@@ -416,11 +423,12 @@ static int mpwr_eg25_power_up(struct mpwr_dev* mpwr)
* This should be 1 for normal powerup and 0 for fastboot mode with
* special Biktor's firmware.
*/
- gpiod_direction_output(mpwr->enable_gpio, !fastboot);
+ gpiod_direction_output(mpwr->enable_gpio, mode != MPWR_MODE_FASTBOOT);
gpiod_direction_output(mpwr->sleep_gpio, 0);
gpiod_direction_output(mpwr->reset_gpio, 0);
gpiod_direction_output(pwrkey_gpio, 0);
- gpiod_direction_output(mpwr->dtr_gpio, 0);
+ /* dtr_gpio should be 0 during normal powerup */
+ gpiod_direction_output(mpwr->dtr_gpio, mode == MPWR_MODE_ALT1);
/* Wait for powerup. (30ms min. according to datasheet) */
msleep(50);
@@ -431,7 +439,7 @@ static int mpwr_eg25_power_up(struct mpwr_dev* mpwr)
gpiod_set_value(pwrkey_gpio, 0);
/* skip modem killswitch status checks in fastboot bootloader entry mode */
- if (fastboot)
+ if (mode != MPWR_MODE_NORMAL)
goto open_serdev;
/* Switch status key to input, in case it's multiplexed with pwrkey. */
@@ -496,7 +504,7 @@ static int mpwr_eg25_power_up(struct mpwr_dev* mpwr)
goto err_shutdown;
}
- if (test_bit(MPWR_F_DUMB_POWERUP, mpwr->flags) || fastboot)
+ if (mode != MPWR_MODE_NORMAL)
goto powered_up;
ret = mpwr_serdev_at_cmd_with_retry_ignore_timeout(mpwr, "AT&FE0", 1000, 30);
@@ -556,7 +564,7 @@ static int mpwr_eg25_power_up(struct mpwr_dev* mpwr)
/* reset the modem, to apply QDAI config if necessary */
if (needs_restart) {
dev_info(mpwr->dev, "Restarting modem\n");
-
+
/* reboot is broken with fastboot enabled */
mpwr_serdev_at_cmd(mpwr, "AT+QCFG=\"fast/poweroff\",0", 5000);
@@ -624,6 +632,11 @@ static int mpwr_eg25_power_up(struct mpwr_dev* mpwr)
dev_err(mpwr->dev, "Modem will probably not sleep!\n");
powered_up:
+ // if we're signaling some alternate boot mode via GPIO, we need to
+ // sleep here so that modem's boot script notices the gpio
+ if (mode == MPWR_MODE_ALT1 || mode == MPWR_MODE_FASTBOOT || mode == MPWR_MODE_ALT2)
+ msleep(12000);
+
gpiod_direction_output(mpwr->dtr_gpio, 1);
return 0;
@@ -738,7 +751,7 @@ static int mpwr_eg25_power_down_finish(struct mpwr_dev* mpwr)
static int mpwr_eg25_power_down(struct mpwr_dev* mpwr)
{
struct gpio_desc *pwrkey_gpio = mpwr_eg25_get_pwrkey_gpio(mpwr);
- int ret;
+ //int ret;
/* Send 800ms pwrkey pulse to initiate powerdown. */
gpiod_direction_output(pwrkey_gpio, 1);
@@ -1112,7 +1125,7 @@ static void mpwr_work_handler(struct work_struct *work)
pm_relax(mpwr->dev);
}
-static void mpwr_request_power_change(struct mpwr_dev* mpwr, int request)
+static void mpwr_request_power_change(struct mpwr_dev* mpwr, int request, int mode)
{
unsigned long flags;
@@ -1121,6 +1134,8 @@ static void mpwr_request_power_change(struct mpwr_dev* mpwr, int request)
spin_lock_irqsave(&mpwr->lock, flags);
mpwr->last_request = request;
+ if (mode >= 0)
+ mpwr->powerup_mode = mode;
spin_unlock_irqrestore(&mpwr->lock, flags);
queue_work(mpwr->wq, &mpwr->power_work);
@@ -1189,17 +1204,17 @@ static ssize_t powered_store(struct device *dev,
const char *buf, size_t len)
{
struct mpwr_dev *mpwr = platform_get_drvdata(to_platform_device(dev));
- bool status;
+ unsigned status;
int ret;
if (test_bit(MPWR_F_BLOCKED, mpwr->flags))
return -EPERM;
- ret = kstrtobool(buf, &status);
+ ret = kstrtouint(buf, 10, &status);
if (ret)
return ret;
- mpwr_request_power_change(mpwr, status ? MPWR_REQ_PWUP : MPWR_REQ_PWDN);
+ mpwr_request_power_change(mpwr, status ? MPWR_REQ_PWUP : MPWR_REQ_PWDN, status);
return len;
}
@@ -1209,17 +1224,17 @@ static ssize_t powered_blocking_store(struct device *dev,
const char *buf, size_t len)
{
struct mpwr_dev *mpwr = platform_get_drvdata(to_platform_device(dev));
- bool status;
+ unsigned status;
int ret;
if (test_bit(MPWR_F_BLOCKED, mpwr->flags))
return -EPERM;
- ret = kstrtobool(buf, &status);
+ ret = kstrtouint(buf, 10, &status);
if (ret)
return ret;
- mpwr_request_power_change(mpwr, status ? MPWR_REQ_PWUP : MPWR_REQ_PWDN);
+ mpwr_request_power_change(mpwr, status ? MPWR_REQ_PWUP : MPWR_REQ_PWDN, status);
ret = wait_event_interruptible_timeout(mpwr->wait,
!test_bit(MPWR_F_POWER_CHANGE_INPROGRESS, mpwr->flags),
@@ -1235,64 +1250,16 @@ static ssize_t powered_blocking_store(struct device *dev,
return len;
}
-static ssize_t dumb_powerup_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mpwr_dev *mpwr = platform_get_drvdata(to_platform_device(dev));
-
- return scnprintf(buf, PAGE_SIZE, "%u\n",
- !!test_bit(MPWR_F_DUMB_POWERUP, mpwr->flags));
-}
-
-static ssize_t dumb_powerup_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static ssize_t help_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct mpwr_dev *mpwr = platform_get_drvdata(to_platform_device(dev));
- bool val;
- int ret;
-
- ret = kstrtobool(buf, &val);
- if (ret)
- return ret;
-
- if (val) {
- dev_err(mpwr->dev, "Don't use dumb_powerup, it's just a debug function!\n");
- set_bit(MPWR_F_DUMB_POWERUP, mpwr->flags);
- } else
- clear_bit(MPWR_F_DUMB_POWERUP, mpwr->flags);
-
- return len;
-}
-
-static ssize_t fastboot_powerup_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mpwr_dev *mpwr = platform_get_drvdata(to_platform_device(dev));
-
- return scnprintf(buf, PAGE_SIZE, "%u\n",
- !!test_bit(MPWR_F_FASTBOOT_POWERUP, mpwr->flags));
-}
-
-static ssize_t fastboot_powerup_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- struct mpwr_dev *mpwr = platform_get_drvdata(to_platform_device(dev));
- bool val;
- int ret;
-
- ret = kstrtobool(buf, &val);
- if (ret)
- return ret;
-
- if (val) {
- dev_warn(mpwr->dev, "Fastboot powerup needs a special bootloader!\n");
- set_bit(MPWR_F_FASTBOOT_POWERUP, mpwr->flags);
- } else
- clear_bit(MPWR_F_FASTBOOT_POWERUP, mpwr->flags);
-
- return len;
+ return scnprintf(buf, PAGE_SIZE,
+ "echo N > powered, where N can be:\n"
+ "0: power off\n"
+ "1: normal powerup\n"
+ "2: dumb powerup (no AT commands and little error checking during powerup)\n"
+ "3: fastboot powerup (with biktor's patched aboot - #W_DISABLE held low during powerup)\n"
+ "4: alternate powerup (megi's userspace - DTR held high during powerup)\n\n"
+ "echo N > powered_blocking can be used for the write to block until power status transition completes\n");
}
static ssize_t killswitched_show(struct device *dev,
@@ -1328,26 +1295,24 @@ static ssize_t hard_reset_store(struct device *dev,
if (ret)
return ret;
if (val)
- mpwr_request_power_change(mpwr, MPWR_REQ_RESET);
+ mpwr_request_power_change(mpwr, MPWR_REQ_RESET, -1);
return len;
}
static DEVICE_ATTR_RW(powered);
static DEVICE_ATTR_WO(powered_blocking);
-static DEVICE_ATTR_RW(dumb_powerup);
-static DEVICE_ATTR_RW(fastboot_powerup);
static DEVICE_ATTR_RO(killswitched);
static DEVICE_ATTR_RO(is_busy);
+static DEVICE_ATTR_RO(help);
static DEVICE_ATTR_WO(hard_reset);
static struct attribute *mpwr_attrs[] = {
&dev_attr_powered.attr,
&dev_attr_powered_blocking.attr,
- &dev_attr_dumb_powerup.attr,
- &dev_attr_fastboot_powerup.attr,
&dev_attr_killswitched.attr,
&dev_attr_is_busy.attr,
+ &dev_attr_help.attr,
&dev_attr_hard_reset.attr,
NULL,
};
--
2.35.3