diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index a564237278ff..13279dd4f01a 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -94,7 +94,7 @@ config POWER_RESET_GPIO_RESTART create a binding in your devicetree. config POWER_RESET_HISI - bool "Hisilicon power-off driver" + tristate "Hisilicon power-off driver" depends on ARCH_HISI help Reboot support for Hisilicon boards. diff --git a/drivers/power/reset/hisi-reboot.c b/drivers/power/reset/hisi-reboot.c index 0ba5fdce186f..283afb538ad3 100644 --- a/drivers/power/reset/hisi-reboot.c +++ b/drivers/power/reset/hisi-reboot.c @@ -8,26 +8,64 @@ * Author: Haojian Zhuang */ +#include #include #include #include +#include #include #include #include #include +#include +#include #include static void __iomem *base; static u32 reboot_offset; +static struct regmap *pmu_regmap; +static struct regmap *sctrl_regmap; + +#define REBOOT_REASON_BOOTLOADER (0x01) +#define REBOOT_REASON_COLDBOOT (0x00) +#define DDR_BYPASS BIT(31) + +#define RST_FLAG_MASK GENMASK(7, 0) + +#define PMU_HRST_OFFSET ((0x101) << 2) +#define SCPEREN1_OFFSET (0x170) static int hisi_restart_handler(struct notifier_block *this, unsigned long mode, void *cmd) { - writel_relaxed(0xdeadbeef, base + reboot_offset); + int ret; + char reboot_reason; + + if (!cmd || !strcmp(cmd, "bootloader")) + reboot_reason = REBOOT_REASON_BOOTLOADER; + else + reboot_reason = REBOOT_REASON_COLDBOOT; + + if (base) { + writel_relaxed(0xdeadbeef, base + reboot_offset); + } else { + ret = regmap_update_bits(pmu_regmap, PMU_HRST_OFFSET, + RST_FLAG_MASK, reboot_reason); + if (ret) + return ret; + + ret = regmap_write(sctrl_regmap, SCPEREN1_OFFSET, DDR_BYPASS); + if (ret) + return ret; + + ret = regmap_write(sctrl_regmap, reboot_offset, 0xdeadbeef); + if (ret) + return ret; + } while (1) - cpu_do_idle(); + mdelay(1); return NOTIFY_DONE; } @@ -44,8 +82,17 @@ static int hisi_reboot_probe(struct platform_device *pdev) base = of_iomap(np, 0); if (!base) { - WARN(1, "failed to map base address"); - return -ENODEV; + pmu_regmap = syscon_regmap_lookup_by_phandle(np, "pmu-regmap"); + if (!pmu_regmap) { + WARN(1, "failed to regmap pmu address"); + return -ENODEV; + } + + sctrl_regmap = syscon_regmap_lookup_by_phandle(np, "sctrl-regmap"); + if (!sctrl_regmap) { + WARN(1, "failed to regmap sctrl address"); + return -ENODEV; + } } if (of_property_read_u32(np, "reboot-offset", &reboot_offset) < 0) { @@ -66,6 +113,7 @@ static int hisi_reboot_probe(struct platform_device *pdev) static const struct of_device_id hisi_reboot_of_match[] = { { .compatible = "hisilicon,sysctrl" }, + { .compatible = "hisilicon,hi3660-reboot" }, {} }; @@ -77,3 +125,6 @@ static struct platform_driver hisi_reboot_driver = { }, }; module_platform_driver(hisi_reboot_driver); + +MODULE_DESCRIPTION("Reset driver for HiSi SoCs"); +MODULE_LICENSE("GPL v2");