diff mbox

[v3,3/5] soc: rockchip: add reboot notifier driver

Message ID 1447840582-19850-1-git-send-email-andy.yan@rock-chips.com (mailing list archive)
State New, archived
Headers show

Commit Message

Andy Yan Nov. 18, 2015, 9:56 a.m. UTC
rockchip platform have a protocol to pass the kernel reboot
mode to bootloader by some special registers when system reboot.
By this way the bootloader can take different action according
to the different kernel reboot mode, for example, command
"reboot loader" will reboot the board to rockusb mode, this is
a very convenient way to get the board enter download mode.

Signed-off-by: Andy Yan <andy.yan@rock-chips.com>

---

Changes in v3:
 - move from mach-rockchip to drivers/soc/rockchip, as the tegra does
 - use dts pass the related register

Changes in v2:
  - check cpu dt node
  - remove a unnecessary of_put_node in function rockchip_get_pmu_regmap
  - fix a align issue
  - use reboot_notifier instead of restart_handler

 drivers/soc/rockchip/Kconfig  |  7 ++++
 drivers/soc/rockchip/Makefile |  1 +
 drivers/soc/rockchip/loader.h | 22 ++++++++++
 drivers/soc/rockchip/reboot.c | 98 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 128 insertions(+)
 create mode 100644 drivers/soc/rockchip/loader.h
 create mode 100644 drivers/soc/rockchip/reboot.c

Comments

kernel test robot Nov. 19, 2015, 12:39 a.m. UTC | #1
Hi Andy,

[auto build test WARNING on rockchip/for-next]
[also build test WARNING on v4.4-rc1 next-20151118]

url:    https://github.com/0day-ci/linux/commits/Andy-Yan/Add-reboot-notifier-driver-for-rockchip-platform/20151118-181000
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
config: arm64-allmodconfig (attached as .config)
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm64 

All warnings (new ones prefixed by >>):

>> WARNING: drivers/soc/built-in.o(.data+0x718): Section mismatch in reference from the variable rockchip_reboot_driver to the function .init.text:rockchip_reboot_probe()
   The variable rockchip_reboot_driver references
   the function __init rockchip_reboot_probe()
   If the reference is valid then annotate the
   variable with or __refdata (see linux/init.h) or name the variable:
   

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Arnd Bergmann Dec. 14, 2015, 11:39 a.m. UTC | #2
On Wednesday 18 November 2015 17:56:22 Andy Yan wrote:
> rockchip platform have a protocol to pass the kernel reboot
> mode to bootloader by some special registers when system reboot.
> By this way the bootloader can take different action according
> to the different kernel reboot mode, for example, command
> "reboot loader" will reboot the board to rockusb mode, this is
> a very convenient way to get the board enter download mode.
> 
> Signed-off-by: Andy Yan <andy.yan@rock-chips.com>

Adding John Stultz to Cc

I just saw this thread pop up again, and had to think of John's recent
patch to unify this across platforms.

John, can you have a look at this driver too, and see how it fits in?
I think this is yet another variant, using an MMIO register rather than
RAM (as HTC / NVIDIA does) or SRAM (as Qualcomm does), but otherwise
it conceptually fits in with what you had.

The driver goes through an existing syscon regmap as far as I can
tell, rather than a memory area or its own device.

	Arnd

> ---
> 
> Changes in v3:
>  - move from mach-rockchip to drivers/soc/rockchip, as the tegra does
>  - use dts pass the related register
> 
> Changes in v2:
>   - check cpu dt node
>   - remove a unnecessary of_put_node in function rockchip_get_pmu_regmap
>   - fix a align issue
>   - use reboot_notifier instead of restart_handler
> 
>  drivers/soc/rockchip/Kconfig  |  7 ++++
>  drivers/soc/rockchip/Makefile |  1 +
>  drivers/soc/rockchip/loader.h | 22 ++++++++++
>  drivers/soc/rockchip/reboot.c | 98 +++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 128 insertions(+)
>  create mode 100644 drivers/soc/rockchip/loader.h
>  create mode 100644 drivers/soc/rockchip/reboot.c
> 
> diff --git a/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig
> index 7140ff8..4edbc44 100644
> --- a/drivers/soc/rockchip/Kconfig
> +++ b/drivers/soc/rockchip/Kconfig
> @@ -15,4 +15,11 @@ config ROCKCHIP_PM_DOMAINS
>  
>            If unsure, say N.
>  
> +config ROCKCHIP_REBOOT
> +	bool "Rockchip reboot notifier driver"
> +	help
> +	  Say y here will enable reboot notifier support.
> +	  This will get reboot mode arguments from userspace and
> +	  store it in special register.
> +
>  endif
> diff --git a/drivers/soc/rockchip/Makefile b/drivers/soc/rockchip/Makefile
> index 3d73d06..9817496 100644
> --- a/drivers/soc/rockchip/Makefile
> +++ b/drivers/soc/rockchip/Makefile
> @@ -2,3 +2,4 @@
>  # Rockchip Soc drivers
>  #
>  obj-$(CONFIG_ROCKCHIP_PM_DOMAINS) += pm_domains.o
> +obj-$(CONFIG_ROCKCHIP_REBOOT) += reboot.o
> diff --git a/drivers/soc/rockchip/loader.h b/drivers/soc/rockchip/loader.h
> new file mode 100644
> index 0000000..bf51baa
> --- /dev/null
> +++ b/drivers/soc/rockchip/loader.h
> @@ -0,0 +1,22 @@
> +#ifndef __MACH_ROCKCHIP_LOADER_H
> +#define __MACH_ROCKCHIP_LOADER_H
> +
> +/*high 24 bits is tag, low 8 bits is type*/
> +#define SYS_LOADER_REBOOT_FLAG   0x5242C300
> +
> +enum {
> +	BOOT_NORMAL = 0, /* normal boot */
> +	BOOT_LOADER,     /* enter loader rockusb mode */
> +	BOOT_MASKROM,    /* enter maskrom rockusb mode (not support now) */
> +	BOOT_RECOVER,    /* enter recover */
> +	BOOT_NORECOVER,  /* do not enter recover */
> +	BOOT_SECONDOS,   /* boot second OS (not support now)*/
> +	BOOT_WIPEDATA,   /* enter recover and wipe data. */
> +	BOOT_WIPEALL,    /* enter recover and wipe all data. */
> +	BOOT_CHECKIMG,   /* check firmware img with backup part*/
> +	BOOT_FASTBOOT,   /* enter fast boot mode */
> +	BOOT_SECUREBOOT_DISABLE,
> +	BOOT_CHARGING,   /* enter charge mode */
> +	BOOT_MAX         /* MAX VALID BOOT TYPE.*/
> +};
> +#endif
> diff --git a/drivers/soc/rockchip/reboot.c b/drivers/soc/rockchip/reboot.c
> new file mode 100644
> index 0000000..048aeb0b
> --- /dev/null
> +++ b/drivers/soc/rockchip/reboot.c
> @@ -0,0 +1,98 @@
> +/*
> + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/reboot.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
> +#include "loader.h"
> +
> +struct rockchip_reboot {
> +	struct device *dev;
> +	struct regmap *map;
> +	u32 offset;
> +	struct notifier_block reboot_notifier;
> +};
> +
> +static void rockchip_get_reboot_flag(const char *cmd, u32 *flag)
> +{
> +	*flag = SYS_LOADER_REBOOT_FLAG + BOOT_NORMAL;
> +
> +	if (cmd) {
> +		if (!strcmp(cmd, "loader") || !strcmp(cmd, "bootloader"))
> +			*flag = SYS_LOADER_REBOOT_FLAG + BOOT_LOADER;
> +		else if (!strcmp(cmd, "recovery"))
> +			*flag = SYS_LOADER_REBOOT_FLAG + BOOT_RECOVER;
> +		else if (!strcmp(cmd, "charge"))
> +			*flag = SYS_LOADER_REBOOT_FLAG + BOOT_CHARGING;
> +		else if (!strcmp(cmd, "fastboot"))
> +			*flag = SYS_LOADER_REBOOT_FLAG + BOOT_FASTBOOT;
> +	}
> +}
> +
> +static int rockchip_reboot_notify(struct notifier_block *this,
> +				  unsigned long mode, void *cmd)
> +{
> +	struct rockchip_reboot *reboot;
> +	u32 flag;
> +
> +	reboot = container_of(this, struct rockchip_reboot, reboot_notifier);
> +	rockchip_get_reboot_flag(cmd, &flag);
> +	regmap_write(reboot->map, reboot->offset, flag);
> +
> +	return NOTIFY_DONE;
> +}
> +
> +static int __init rockchip_reboot_probe(struct platform_device *pdev)
> +{
> +	struct rockchip_reboot *reboot;
> +	int ret;
> +
> +	reboot = devm_kzalloc(&pdev->dev, sizeof(*reboot), GFP_KERNEL);
> +	if (!reboot)
> +		return -ENOMEM;
> +
> +	reboot->dev = &pdev->dev;
> +	reboot->map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
> +						      "rockchip,regmap");
> +	if (IS_ERR(reboot->map))
> +		return PTR_ERR(reboot->map);
> +
> +	if (of_property_read_u32(pdev->dev.of_node, "offset", &reboot->offset))
> +		return -EINVAL;
> +
> +	reboot->reboot_notifier.notifier_call = rockchip_reboot_notify;
> +	ret = register_reboot_notifier(&reboot->reboot_notifier);
> +	if (ret)
> +		dev_err(reboot->dev, "can't register reboot notifier\n");
> +
> +	return ret;
> +}
> +
> +static const struct of_device_id rockchip_reboot_of_match[] = {
> +	{ .compatible = "rockchip,reboot" },
> +	{}
> +};
> +
> +static struct platform_driver rockchip_reboot_driver = {
> +	.probe = rockchip_reboot_probe,
> +	.driver = {
> +		.name = "rockchip-reboot",
> +		.of_match_table = rockchip_reboot_of_match,
> +	},
> +};
> +module_platform_driver(rockchip_reboot_driver);
> +
> +MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com");
> +MODULE_DESCRIPTION("Rockchip platform reboot notifier driver");
> +MODULE_LICENSE("GPL");
>
Thierry Reding Dec. 15, 2015, 4:31 p.m. UTC | #3
On Mon, Dec 14, 2015 at 12:39:44PM +0100, Arnd Bergmann wrote:
> On Wednesday 18 November 2015 17:56:22 Andy Yan wrote:
> > rockchip platform have a protocol to pass the kernel reboot
> > mode to bootloader by some special registers when system reboot.
> > By this way the bootloader can take different action according
> > to the different kernel reboot mode, for example, command
> > "reboot loader" will reboot the board to rockusb mode, this is
> > a very convenient way to get the board enter download mode.
> > 
> > Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
> 
> Adding John Stultz to Cc
> 
> I just saw this thread pop up again, and had to think of John's recent
> patch to unify this across platforms.
> 
> John, can you have a look at this driver too, and see how it fits in?
> I think this is yet another variant, using an MMIO register rather than
> RAM (as HTC / NVIDIA does) or SRAM (as Qualcomm does), but otherwise
> it conceptually fits in with what you had.

FWIW, Tegra typically does use an MMIO register as well. See
drivers/soc/tegra/pmc.c:tegra_pmc_restart_notify(). I don't know what
HTC does, but if it's writing somewhere in RAM it isn't using the
standard way of resetting the SoC. There's early boot ROM code which I
think evaluates the PMC_SCRATCH0 register on Tegra to determine which
mode to boot into. That's before even any firmware gets the chance of
doing anything.

Thierry
Arnd Bergmann Dec. 15, 2015, 4:34 p.m. UTC | #4
On Tuesday 15 December 2015 17:31:22 Thierry Reding wrote:
> On Mon, Dec 14, 2015 at 12:39:44PM +0100, Arnd Bergmann wrote:
> > On Wednesday 18 November 2015 17:56:22 Andy Yan wrote:
> > > rockchip platform have a protocol to pass the kernel reboot
> > > mode to bootloader by some special registers when system reboot.
> > > By this way the bootloader can take different action according
> > > to the different kernel reboot mode, for example, command
> > > "reboot loader" will reboot the board to rockusb mode, this is
> > > a very convenient way to get the board enter download mode.
> > > 
> > > Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
> > 
> > Adding John Stultz to Cc
> > 
> > I just saw this thread pop up again, and had to think of John's recent
> > patch to unify this across platforms.
> > 
> > John, can you have a look at this driver too, and see how it fits in?
> > I think this is yet another variant, using an MMIO register rather than
> > RAM (as HTC / NVIDIA does) or SRAM (as Qualcomm does), but otherwise
> > it conceptually fits in with what you had.
> 
> FWIW, Tegra typically does use an MMIO register as well. See
> drivers/soc/tegra/pmc.c:tegra_pmc_restart_notify(). I don't know what
> HTC does, but if it's writing somewhere in RAM it isn't using the
> standard way of resetting the SoC. There's early boot ROM code which I
> think evaluates the PMC_SCRATCH0 register on Tegra to determine which
> mode to boot into. That's before even any firmware gets the chance of
> doing anything.

HTC apparently uses a separate RAM area to pass the reboot reason,
and they have a driver to store that, which is separate from the
driver that they use for actually rebooting the machine.

	Arnd
Heiko Stuebner Dec. 15, 2015, 5:27 p.m. UTC | #5
Am Dienstag, 15. Dezember 2015, 17:34:00 schrieb Arnd Bergmann:
> On Tuesday 15 December 2015 17:31:22 Thierry Reding wrote:
> > On Mon, Dec 14, 2015 at 12:39:44PM +0100, Arnd Bergmann wrote:
> > > On Wednesday 18 November 2015 17:56:22 Andy Yan wrote:
> > > > rockchip platform have a protocol to pass the kernel reboot
> > > > mode to bootloader by some special registers when system reboot.
> > > > By this way the bootloader can take different action according
> > > > to the different kernel reboot mode, for example, command
> > > > "reboot loader" will reboot the board to rockusb mode, this is
> > > > a very convenient way to get the board enter download mode.
> > > > 
> > > > Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
> > > 
> > > Adding John Stultz to Cc
> > > 
> > > I just saw this thread pop up again, and had to think of John's recent
> > > patch to unify this across platforms.
> > > 
> > > John, can you have a look at this driver too, and see how it fits in?
> > > I think this is yet another variant, using an MMIO register rather than
> > > RAM (as HTC / NVIDIA does) or SRAM (as Qualcomm does), but otherwise
> > > it conceptually fits in with what you had.
> > 
> > FWIW, Tegra typically does use an MMIO register as well. See
> > drivers/soc/tegra/pmc.c:tegra_pmc_restart_notify(). I don't know what
> > HTC does, but if it's writing somewhere in RAM it isn't using the
> > standard way of resetting the SoC. There's early boot ROM code which I
> > think evaluates the PMC_SCRATCH0 register on Tegra to determine which
> > mode to boot into. That's before even any firmware gets the chance of
> > doing anything.
> 
> HTC apparently uses a separate RAM area to pass the reboot reason,
> and they have a driver to store that, which is separate from the
> driver that they use for actually rebooting the machine.

same on Rockchip. The general restart handling doesn't care about any reason, 
it is merely an agreement between kernel and bootloader to store a reason 
value in some reboot-safe register of the soc.


Heiko
Thierry Reding Dec. 15, 2015, 5:42 p.m. UTC | #6
On Tue, Dec 15, 2015 at 05:34:00PM +0100, Arnd Bergmann wrote:
> On Tuesday 15 December 2015 17:31:22 Thierry Reding wrote:
> > On Mon, Dec 14, 2015 at 12:39:44PM +0100, Arnd Bergmann wrote:
> > > On Wednesday 18 November 2015 17:56:22 Andy Yan wrote:
> > > > rockchip platform have a protocol to pass the kernel reboot
> > > > mode to bootloader by some special registers when system reboot.
> > > > By this way the bootloader can take different action according
> > > > to the different kernel reboot mode, for example, command
> > > > "reboot loader" will reboot the board to rockusb mode, this is
> > > > a very convenient way to get the board enter download mode.
> > > > 
> > > > Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
> > > 
> > > Adding John Stultz to Cc
> > > 
> > > I just saw this thread pop up again, and had to think of John's recent
> > > patch to unify this across platforms.
> > > 
> > > John, can you have a look at this driver too, and see how it fits in?
> > > I think this is yet another variant, using an MMIO register rather than
> > > RAM (as HTC / NVIDIA does) or SRAM (as Qualcomm does), but otherwise
> > > it conceptually fits in with what you had.
> > 
> > FWIW, Tegra typically does use an MMIO register as well. See
> > drivers/soc/tegra/pmc.c:tegra_pmc_restart_notify(). I don't know what
> > HTC does, but if it's writing somewhere in RAM it isn't using the
> > standard way of resetting the SoC. There's early boot ROM code which I
> > think evaluates the PMC_SCRATCH0 register on Tegra to determine which
> > mode to boot into. That's before even any firmware gets the chance of
> > doing anything.
> 
> HTC apparently uses a separate RAM area to pass the reboot reason,
> and they have a driver to store that, which is separate from the
> driver that they use for actually rebooting the machine.

I wasn't very clear, but the PMC_SCRATCH0 register is used to store the
reset reason. It supports the recovery mode, which I think is really an
Android thing, "bootloader" will typically cause the bootloader not to
boot anything, and "forced-recovery" will go into a recovery mode that
is used to bootstrap the device (usually by uploading a "miniloader"
that initializes RAM, downloads a bootloader for booting or flashing an
operating system, ...).

The write that resets the SoC is to a different register.

Thierry
Arnd Bergmann Dec. 15, 2015, 8:38 p.m. UTC | #7
On Tuesday 15 December 2015 18:42:36 Thierry Reding wrote:
> On Tue, Dec 15, 2015 at 05:34:00PM +0100, Arnd Bergmann wrote:
> > On Tuesday 15 December 2015 17:31:22 Thierry Reding wrote:
> > > On Mon, Dec 14, 2015 at 12:39:44PM +0100, Arnd Bergmann wrote:
> > > > On Wednesday 18 November 2015 17:56:22 Andy Yan wrote:
> > > > > rockchip platform have a protocol to pass the kernel reboot
> > > > > mode to bootloader by some special registers when system reboot.
> > > > > By this way the bootloader can take different action according
> > > > > to the different kernel reboot mode, for example, command
> > > > > "reboot loader" will reboot the board to rockusb mode, this is
> > > > > a very convenient way to get the board enter download mode.
> > > > > 
> > > > > Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
> > > > 
> > > > Adding John Stultz to Cc
> > > > 
> > > > I just saw this thread pop up again, and had to think of John's recent
> > > > patch to unify this across platforms.
> > > > 
> > > > John, can you have a look at this driver too, and see how it fits in?
> > > > I think this is yet another variant, using an MMIO register rather than
> > > > RAM (as HTC / NVIDIA does) or SRAM (as Qualcomm does), but otherwise
> > > > it conceptually fits in with what you had.
> > > 
> > > FWIW, Tegra typically does use an MMIO register as well. See
> > > drivers/soc/tegra/pmc.c:tegra_pmc_restart_notify(). I don't know what
> > > HTC does, but if it's writing somewhere in RAM it isn't using the
> > > standard way of resetting the SoC. There's early boot ROM code which I
> > > think evaluates the PMC_SCRATCH0 register on Tegra to determine which
> > > mode to boot into. That's before even any firmware gets the chance of
> > > doing anything.


I just checked the android lollipop tree, and I could not find a pmc_restart_notify
function, only this file

https://android.googlesource.com/kernel/tegra/+/android-tegra-flounder-3.10-lollipop-release/drivers/htc_debug/stability/reboot_params.c

with the device that stores into RAM. It looks like HTC ported over
a driver that they were already using on some Qualcomm MSM8960 device,
as in 

https://gitlab.com/MaC/android_kernel_htc_msm8960/blob/859977fc723f59a6b707df1d70e80826ee1dccc4/arch/arm/mach-msm/htc/htc_restart_handler.c

On Android marshmallow (Flounder), that file again does not exist, and
I don't see how it's done.

> > HTC apparently uses a separate RAM area to pass the reboot reason,
> > and they have a driver to store that, which is separate from the
> > driver that they use for actually rebooting the machine.
> 
> I wasn't very clear, but the PMC_SCRATCH0 register is used to store the
> reset reason. It supports the recovery mode, which I think is really an
> Android thing, "bootloader" will typically cause the bootloader not to
> boot anything, and "forced-recovery" will go into a recovery mode that
> is used to bootstrap the device (usually by uploading a "miniloader"
> that initializes RAM, downloads a bootloader for booting or flashing an
> operating system, ...).
> 
> The write that resets the SoC is to a different register.

So is this scratch register interpreted by some maskrom code, or by code that
can be provided by the OEM?

	Arnd
Thierry Reding Dec. 28, 2015, 9:20 a.m. UTC | #8
On Tue, Dec 15, 2015 at 09:38:41PM +0100, Arnd Bergmann wrote:
> On Tuesday 15 December 2015 18:42:36 Thierry Reding wrote:
> > On Tue, Dec 15, 2015 at 05:34:00PM +0100, Arnd Bergmann wrote:
> > > On Tuesday 15 December 2015 17:31:22 Thierry Reding wrote:
> > > > On Mon, Dec 14, 2015 at 12:39:44PM +0100, Arnd Bergmann wrote:
> > > > > On Wednesday 18 November 2015 17:56:22 Andy Yan wrote:
> > > > > > rockchip platform have a protocol to pass the kernel reboot
> > > > > > mode to bootloader by some special registers when system reboot.
> > > > > > By this way the bootloader can take different action according
> > > > > > to the different kernel reboot mode, for example, command
> > > > > > "reboot loader" will reboot the board to rockusb mode, this is
> > > > > > a very convenient way to get the board enter download mode.
> > > > > > 
> > > > > > Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
> > > > > 
> > > > > Adding John Stultz to Cc
> > > > > 
> > > > > I just saw this thread pop up again, and had to think of John's recent
> > > > > patch to unify this across platforms.
> > > > > 
> > > > > John, can you have a look at this driver too, and see how it fits in?
> > > > > I think this is yet another variant, using an MMIO register rather than
> > > > > RAM (as HTC / NVIDIA does) or SRAM (as Qualcomm does), but otherwise
> > > > > it conceptually fits in with what you had.
> > > > 
> > > > FWIW, Tegra typically does use an MMIO register as well. See
> > > > drivers/soc/tegra/pmc.c:tegra_pmc_restart_notify(). I don't know what
> > > > HTC does, but if it's writing somewhere in RAM it isn't using the
> > > > standard way of resetting the SoC. There's early boot ROM code which I
> > > > think evaluates the PMC_SCRATCH0 register on Tegra to determine which
> > > > mode to boot into. That's before even any firmware gets the chance of
> > > > doing anything.
> 
> 
> I just checked the android lollipop tree, and I could not find a pmc_restart_notify
> function, only this file
> 
> https://android.googlesource.com/kernel/tegra/+/android-tegra-flounder-3.10-lollipop-release/drivers/htc_debug/stability/reboot_params.c
> 
> with the device that stores into RAM. It looks like HTC ported over
> a driver that they were already using on some Qualcomm MSM8960 device,
> as in 
> 
> https://gitlab.com/MaC/android_kernel_htc_msm8960/blob/859977fc723f59a6b707df1d70e80826ee1dccc4/arch/arm/mach-msm/htc/htc_restart_handler.c
> 
> On Android marshmallow (Flounder), that file again does not exist, and
> I don't see how it's done.
> 
> > > HTC apparently uses a separate RAM area to pass the reboot reason,
> > > and they have a driver to store that, which is separate from the
> > > driver that they use for actually rebooting the machine.
> > 
> > I wasn't very clear, but the PMC_SCRATCH0 register is used to store the
> > reset reason. It supports the recovery mode, which I think is really an
> > Android thing, "bootloader" will typically cause the bootloader not to
> > boot anything, and "forced-recovery" will go into a recovery mode that
> > is used to bootstrap the device (usually by uploading a "miniloader"
> > that initializes RAM, downloads a bootloader for booting or flashing an
> > operating system, ...).
> > 
> > The write that resets the SoC is to a different register.
> 
> So is this scratch register interpreted by some maskrom code, or by code that
> can be provided by the OEM?

My understanding is that its interpreted both by what's called BootROM
on Tegra (I guess that's what you call "maskrom code") and the system's
bootloader. The BootROM cannot typically be replaced by the OEM, but it
is quite typical for the bootloader to differ between devices.

The BootROM will interpret a subset of the bits in that register. Most
notable the "force recovery" bit. That will cause the BootROM to go into
a mode which can be used to bootstrap the device. It implements a simple
protocol (RCM) which can be used to upload a loader (usually referred to
as mini-loader) to the device's IRAM which in turn will initialize the
memory and which can download a proper bootloader (such as U-Boot) to
memory using a slightly more complex protocol (the standard protocol is
called nv3p, but the particular choice of protocol no longer matters at
this point).

The bootloader can also access this register and will interpret the
"bootloader" and "recovery" bits. On the, argueably small, sample of
Android devices I've worked with, the "bootloader" bit will make the
bootloader go into fastboot mode, whereas the "recovery" bit will make
it initiate the RCK mode, which is used to update through OTA.

There are a couple of other bits in this register, but they are badly
documented and don't seem to relate to reboot.

Thierry
Arnd Bergmann Dec. 28, 2015, 3:35 p.m. UTC | #9
On Monday 28 December 2015 10:20:56 Thierry Reding wrote:
> > > > HTC apparently uses a separate RAM area to pass the reboot reason,
> > > > and they have a driver to store that, which is separate from the
> > > > driver that they use for actually rebooting the machine.
> > > 
> > > I wasn't very clear, but the PMC_SCRATCH0 register is used to store the
> > > reset reason. It supports the recovery mode, which I think is really an
> > > Android thing, "bootloader" will typically cause the bootloader not to
> > > boot anything, and "forced-recovery" will go into a recovery mode that
> > > is used to bootstrap the device (usually by uploading a "miniloader"
> > > that initializes RAM, downloads a bootloader for booting or flashing an
> > > operating system, ...).
> > > 
> > > The write that resets the SoC is to a different register.
> > 
> > So is this scratch register interpreted by some maskrom code, or by code that
> > can be provided by the OEM?
> 
> My understanding is that its interpreted both by what's called BootROM
> on Tegra (I guess that's what you call "maskrom code") and the system's
> bootloader. The BootROM cannot typically be replaced by the OEM, but it
> is quite typical for the bootloader to differ between devices.

Ok, so not maskrom (which would not be OEM specific, but hardcoded for
the chip) but rather some form of PROM. This means we can only guess
that all OEMs use the same protocol but in theory someone could have
implemented an incompatible BootROM, but it's also possible that HTC
just ignore the register entirely and implement the same thing separately.

> The BootROM will interpret a subset of the bits in that register. Most
> notable the "force recovery" bit. That will cause the BootROM to go into
> a mode which can be used to bootstrap the device. It implements a simple
> protocol (RCM) which can be used to upload a loader (usually referred to
> as mini-loader) to the device's IRAM which in turn will initialize the
> memory and which can download a proper bootloader (such as U-Boot) to
> memory using a slightly more complex protocol (the standard protocol is
> called nv3p, but the particular choice of protocol no longer matters at
> this point).
> 
> The bootloader can also access this register and will interpret the
> "bootloader" and "recovery" bits. On the, argueably small, sample of
> Android devices I've worked with, the "bootloader" bit will make the
> bootloader go into fastboot mode, whereas the "recovery" bit will make
> it initiate the RCK mode, which is used to update through OTA.
> 
> There are a couple of other bits in this register, but they are badly
> documented and don't seem to relate to reboot.

Ok.

	Arnd
Thierry Reding Jan. 21, 2016, 4:20 p.m. UTC | #10
On Mon, Dec 28, 2015 at 04:35:46PM +0100, Arnd Bergmann wrote:
> On Monday 28 December 2015 10:20:56 Thierry Reding wrote:
> > > > > HTC apparently uses a separate RAM area to pass the reboot reason,
> > > > > and they have a driver to store that, which is separate from the
> > > > > driver that they use for actually rebooting the machine.
> > > > 
> > > > I wasn't very clear, but the PMC_SCRATCH0 register is used to store the
> > > > reset reason. It supports the recovery mode, which I think is really an
> > > > Android thing, "bootloader" will typically cause the bootloader not to
> > > > boot anything, and "forced-recovery" will go into a recovery mode that
> > > > is used to bootstrap the device (usually by uploading a "miniloader"
> > > > that initializes RAM, downloads a bootloader for booting or flashing an
> > > > operating system, ...).
> > > > 
> > > > The write that resets the SoC is to a different register.
> > > 
> > > So is this scratch register interpreted by some maskrom code, or by code that
> > > can be provided by the OEM?
> > 
> > My understanding is that its interpreted both by what's called BootROM
> > on Tegra (I guess that's what you call "maskrom code") and the system's
> > bootloader. The BootROM cannot typically be replaced by the OEM, but it
> > is quite typical for the bootloader to differ between devices.
> 
> Ok, so not maskrom (which would not be OEM specific, but hardcoded for
> the chip) but rather some form of PROM. This means we can only guess
> that all OEMs use the same protocol but in theory someone could have
> implemented an incompatible BootROM, but it's also possible that HTC
> just ignore the register entirely and implement the same thing separately.

I wasn't being clear, the BootROM is hardcoded for the chip, I'm not
aware of a way to replace it once the chip's taped out.

Thierry
diff mbox

Patch

diff --git a/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig
index 7140ff8..4edbc44 100644
--- a/drivers/soc/rockchip/Kconfig
+++ b/drivers/soc/rockchip/Kconfig
@@ -15,4 +15,11 @@  config ROCKCHIP_PM_DOMAINS
 
           If unsure, say N.
 
+config ROCKCHIP_REBOOT
+	bool "Rockchip reboot notifier driver"
+	help
+	  Say y here will enable reboot notifier support.
+	  This will get reboot mode arguments from userspace and
+	  store it in special register.
+
 endif
diff --git a/drivers/soc/rockchip/Makefile b/drivers/soc/rockchip/Makefile
index 3d73d06..9817496 100644
--- a/drivers/soc/rockchip/Makefile
+++ b/drivers/soc/rockchip/Makefile
@@ -2,3 +2,4 @@ 
 # Rockchip Soc drivers
 #
 obj-$(CONFIG_ROCKCHIP_PM_DOMAINS) += pm_domains.o
+obj-$(CONFIG_ROCKCHIP_REBOOT) += reboot.o
diff --git a/drivers/soc/rockchip/loader.h b/drivers/soc/rockchip/loader.h
new file mode 100644
index 0000000..bf51baa
--- /dev/null
+++ b/drivers/soc/rockchip/loader.h
@@ -0,0 +1,22 @@ 
+#ifndef __MACH_ROCKCHIP_LOADER_H
+#define __MACH_ROCKCHIP_LOADER_H
+
+/*high 24 bits is tag, low 8 bits is type*/
+#define SYS_LOADER_REBOOT_FLAG   0x5242C300
+
+enum {
+	BOOT_NORMAL = 0, /* normal boot */
+	BOOT_LOADER,     /* enter loader rockusb mode */
+	BOOT_MASKROM,    /* enter maskrom rockusb mode (not support now) */
+	BOOT_RECOVER,    /* enter recover */
+	BOOT_NORECOVER,  /* do not enter recover */
+	BOOT_SECONDOS,   /* boot second OS (not support now)*/
+	BOOT_WIPEDATA,   /* enter recover and wipe data. */
+	BOOT_WIPEALL,    /* enter recover and wipe all data. */
+	BOOT_CHECKIMG,   /* check firmware img with backup part*/
+	BOOT_FASTBOOT,   /* enter fast boot mode */
+	BOOT_SECUREBOOT_DISABLE,
+	BOOT_CHARGING,   /* enter charge mode */
+	BOOT_MAX         /* MAX VALID BOOT TYPE.*/
+};
+#endif
diff --git a/drivers/soc/rockchip/reboot.c b/drivers/soc/rockchip/reboot.c
new file mode 100644
index 0000000..048aeb0b
--- /dev/null
+++ b/drivers/soc/rockchip/reboot.c
@@ -0,0 +1,98 @@ 
+/*
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include "loader.h"
+
+struct rockchip_reboot {
+	struct device *dev;
+	struct regmap *map;
+	u32 offset;
+	struct notifier_block reboot_notifier;
+};
+
+static void rockchip_get_reboot_flag(const char *cmd, u32 *flag)
+{
+	*flag = SYS_LOADER_REBOOT_FLAG + BOOT_NORMAL;
+
+	if (cmd) {
+		if (!strcmp(cmd, "loader") || !strcmp(cmd, "bootloader"))
+			*flag = SYS_LOADER_REBOOT_FLAG + BOOT_LOADER;
+		else if (!strcmp(cmd, "recovery"))
+			*flag = SYS_LOADER_REBOOT_FLAG + BOOT_RECOVER;
+		else if (!strcmp(cmd, "charge"))
+			*flag = SYS_LOADER_REBOOT_FLAG + BOOT_CHARGING;
+		else if (!strcmp(cmd, "fastboot"))
+			*flag = SYS_LOADER_REBOOT_FLAG + BOOT_FASTBOOT;
+	}
+}
+
+static int rockchip_reboot_notify(struct notifier_block *this,
+				  unsigned long mode, void *cmd)
+{
+	struct rockchip_reboot *reboot;
+	u32 flag;
+
+	reboot = container_of(this, struct rockchip_reboot, reboot_notifier);
+	rockchip_get_reboot_flag(cmd, &flag);
+	regmap_write(reboot->map, reboot->offset, flag);
+
+	return NOTIFY_DONE;
+}
+
+static int __init rockchip_reboot_probe(struct platform_device *pdev)
+{
+	struct rockchip_reboot *reboot;
+	int ret;
+
+	reboot = devm_kzalloc(&pdev->dev, sizeof(*reboot), GFP_KERNEL);
+	if (!reboot)
+		return -ENOMEM;
+
+	reboot->dev = &pdev->dev;
+	reboot->map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+						      "rockchip,regmap");
+	if (IS_ERR(reboot->map))
+		return PTR_ERR(reboot->map);
+
+	if (of_property_read_u32(pdev->dev.of_node, "offset", &reboot->offset))
+		return -EINVAL;
+
+	reboot->reboot_notifier.notifier_call = rockchip_reboot_notify;
+	ret = register_reboot_notifier(&reboot->reboot_notifier);
+	if (ret)
+		dev_err(reboot->dev, "can't register reboot notifier\n");
+
+	return ret;
+}
+
+static const struct of_device_id rockchip_reboot_of_match[] = {
+	{ .compatible = "rockchip,reboot" },
+	{}
+};
+
+static struct platform_driver rockchip_reboot_driver = {
+	.probe = rockchip_reboot_probe,
+	.driver = {
+		.name = "rockchip-reboot",
+		.of_match_table = rockchip_reboot_of_match,
+	},
+};
+module_platform_driver(rockchip_reboot_driver);
+
+MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com");
+MODULE_DESCRIPTION("Rockchip platform reboot notifier driver");
+MODULE_LICENSE("GPL");