123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- /*
- * Copyright (C) 2014 Linaro Ltd.
- *
- * Author: Linus Walleij <linus.walleij@linaro.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2, as
- * published by the Free Software Foundation.
- *
- */
- #include <linux/init.h>
- #include <linux/mfd/syscon.h>
- #include <linux/reboot.h>
- #include <linux/regmap.h>
- #include <linux/of.h>
- #define INTEGRATOR_HDR_CTRL_OFFSET 0x0C
- #define INTEGRATOR_HDR_LOCK_OFFSET 0x14
- #define INTEGRATOR_CM_CTRL_RESET (1 << 3)
- #define REALVIEW_SYS_LOCK_OFFSET 0x20
- #define REALVIEW_SYS_RESETCTL_OFFSET 0x40
- /* Magic unlocking token used on all Versatile boards */
- #define VERSATILE_LOCK_VAL 0xA05F
- /*
- * We detect the different syscon types from the compatible strings.
- */
- enum versatile_reboot {
- INTEGRATOR_REBOOT_CM,
- REALVIEW_REBOOT_EB,
- REALVIEW_REBOOT_PB1176,
- REALVIEW_REBOOT_PB11MP,
- REALVIEW_REBOOT_PBA8,
- REALVIEW_REBOOT_PBX,
- };
- /* Pointer to the system controller */
- static struct regmap *syscon_regmap;
- static enum versatile_reboot versatile_reboot_type;
- static const struct of_device_id versatile_reboot_of_match[] = {
- {
- .compatible = "arm,core-module-integrator",
- .data = (void *)INTEGRATOR_REBOOT_CM
- },
- {
- .compatible = "arm,realview-eb-syscon",
- .data = (void *)REALVIEW_REBOOT_EB,
- },
- {
- .compatible = "arm,realview-pb1176-syscon",
- .data = (void *)REALVIEW_REBOOT_PB1176,
- },
- {
- .compatible = "arm,realview-pb11mp-syscon",
- .data = (void *)REALVIEW_REBOOT_PB11MP,
- },
- {
- .compatible = "arm,realview-pba8-syscon",
- .data = (void *)REALVIEW_REBOOT_PBA8,
- },
- {
- .compatible = "arm,realview-pbx-syscon",
- .data = (void *)REALVIEW_REBOOT_PBX,
- },
- {},
- };
- static int versatile_reboot(struct notifier_block *this, unsigned long mode,
- void *cmd)
- {
- /* Unlock the reset register */
- /* Then hit reset on the different machines */
- switch (versatile_reboot_type) {
- case INTEGRATOR_REBOOT_CM:
- regmap_write(syscon_regmap, INTEGRATOR_HDR_LOCK_OFFSET,
- VERSATILE_LOCK_VAL);
- regmap_update_bits(syscon_regmap,
- INTEGRATOR_HDR_CTRL_OFFSET,
- INTEGRATOR_CM_CTRL_RESET,
- INTEGRATOR_CM_CTRL_RESET);
- break;
- case REALVIEW_REBOOT_EB:
- regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
- VERSATILE_LOCK_VAL);
- regmap_write(syscon_regmap,
- REALVIEW_SYS_RESETCTL_OFFSET, 0x0008);
- break;
- case REALVIEW_REBOOT_PB1176:
- regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
- VERSATILE_LOCK_VAL);
- regmap_write(syscon_regmap,
- REALVIEW_SYS_RESETCTL_OFFSET, 0x0100);
- break;
- case REALVIEW_REBOOT_PB11MP:
- case REALVIEW_REBOOT_PBA8:
- regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
- VERSATILE_LOCK_VAL);
- regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
- 0x0000);
- regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
- 0x0004);
- break;
- case REALVIEW_REBOOT_PBX:
- regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
- VERSATILE_LOCK_VAL);
- regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
- 0x00f0);
- regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
- 0x00f4);
- break;
- }
- dsb();
- return NOTIFY_DONE;
- }
- static struct notifier_block versatile_reboot_nb = {
- .notifier_call = versatile_reboot,
- .priority = 192,
- };
- static int __init versatile_reboot_probe(void)
- {
- const struct of_device_id *reboot_id;
- struct device_node *np;
- int err;
- np = of_find_matching_node_and_match(NULL, versatile_reboot_of_match,
- &reboot_id);
- if (!np)
- return -ENODEV;
- versatile_reboot_type = (enum versatile_reboot)reboot_id->data;
- syscon_regmap = syscon_node_to_regmap(np);
- if (IS_ERR(syscon_regmap))
- return PTR_ERR(syscon_regmap);
- err = register_restart_handler(&versatile_reboot_nb);
- if (err)
- return err;
- pr_info("versatile reboot driver registered\n");
- return 0;
- }
- device_initcall(versatile_reboot_probe);
|