blob: a3e3e77c089f9475ac0e72a4f16589630aae10ed [file] [log] [blame]
/*
* drivers/amlogic/reboot/reboot_m8b.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* 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.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/reboot.h>
#include <asm/system_misc.h>
#include <linux/amlogic/iomap.h>
#include <linux/amlogic/cpu_version.h>
#include <asm/compiler.h>
#include <linux/kdebug.h>
#include <linux/amlogic/iomap.h>
#include <linux/cpuidle.h>
#include <asm/cpuidle.h>
#include <linux/amlogic/reboot_m8b.h>
#define WATCHDOG_ENABLE_BIT (1<<19)
#define DUAL_CORE_RESET (3<<24)
#define AO_RTI_STATUS_REG1 ((0x00 << 10) | (0x01 << 2))
#define VENC_VDAC_SETTING 0x1b7e
#define WATCHDOG_RESET 0x2641
#define WATCHDOG_TC 0x2640
#ifdef AMLOGIC_M8B_REBOOT_UBOOT_SUSPEND
static int reboot_flag;
static int __init do_parse_args(char *line)
{
if (strcmp(line, "uboot_suspend") == 0)
reboot_flag = 1;
pr_info("reboot_flag=%x\n", reboot_flag);
return 1;
}
__setup("reboot_args=", do_parse_args);
#endif
static inline void arch_reset(char mode, const char *cmd)
{
aml_write_cbus(VENC_VDAC_SETTING, 0xf);
aml_write_cbus(WATCHDOG_RESET, 0);
aml_write_cbus(WATCHDOG_TC,
DUAL_CORE_RESET | WATCHDOG_ENABLE_BIT | 100);
while (1)
cpu_do_idle();
}
void meson_common_restart(char mode, const char *cmd)
{
u32 reboot_reason = MESON_NORMAL_BOOT;
if (cmd) {
if (strcmp(cmd, "charging_reboot") == 0)
reboot_reason = MESON_CHARGING_REBOOT;
else if (strcmp(cmd, "recovery") == 0 ||
strcmp(cmd, "factory_reset") == 0)
reboot_reason = MESON_FACTORY_RESET_REBOOT;
else if (strcmp(cmd, "update") == 0)
reboot_reason = MESON_UPDATE_REBOOT;
else if (strcmp(cmd, "report_crash") == 0)
reboot_reason = MESON_CRASH_REBOOT;
else if (strcmp(cmd, "factory_testl_reboot") == 0)
reboot_reason = MESON_FACTORY_TEST_REBOOT;
else if (strcmp(cmd, "switch_system") == 0)
reboot_reason = MESON_SYSTEM_SWITCH_REBOOT;
else if (strcmp(cmd, "safe_mode") == 0)
reboot_reason = MESON_SAFE_REBOOT;
else if (strcmp(cmd, "lock_system") == 0)
reboot_reason = MESON_LOCK_REBOOT;
else if (strcmp(cmd, "usb_burner_reboot") == 0)
reboot_reason = MESON_USB_BURNER_REBOOT;
else if (strcmp(cmd, "uboot_suspend") == 0)
reboot_reason = MESON_UBOOT_SUSPEND;
}
aml_write_aobus(AO_RTI_STATUS_REG1, reboot_reason);
pr_info("reboot_reason(0x%x) = 0x%x\n", AO_RTI_STATUS_REG1,
aml_read_aobus(AO_RTI_STATUS_REG1));
arch_reset(mode, cmd);
}
static void do_aml_restart(enum reboot_mode reboot_mode, const char *cmd)
{
pr_info("meson power off\n");
#ifdef AMLOGIC_M8B_REBOOT_UBOOT_SUSPEND
if (reboot_flag)
meson_common_restart('h', "uboot_suspend");
else
#endif
meson_common_restart('h', "charging_reboot");
}
static int aml_restart_probe(struct platform_device *pdev)
{
arm_pm_restart = do_aml_restart;
return 0;
}
static const struct of_device_id of_aml_restart_match[] = {
{ .compatible = "aml, reboot_m8b", },
{},
};
MODULE_DEVICE_TABLE(of, of_aml_restart_match);
static struct platform_driver aml_restart_driver = {
.probe = aml_restart_probe,
.driver = {
.name = "aml-restart",
.of_match_table = of_match_ptr(of_aml_restart_match),
},
};
static int __init aml_restart_init(void)
{
return platform_driver_register(&aml_restart_driver);
}
device_initcall(aml_restart_init);