161 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2014 Linaro Ltd.4 *5 * Author: Linus Walleij <linus.walleij@linaro.org>6 */7#include <linux/init.h>8#include <linux/mfd/syscon.h>9#include <linux/reboot.h>10#include <linux/regmap.h>11#include <linux/of.h>12 13#define INTEGRATOR_HDR_CTRL_OFFSET 0x0C14#define INTEGRATOR_HDR_LOCK_OFFSET 0x1415#define INTEGRATOR_CM_CTRL_RESET (1 << 3)16 17#define VERSATILE_SYS_LOCK_OFFSET 0x2018#define VERSATILE_SYS_RESETCTL_OFFSET 0x4019 20/* Magic unlocking token used on all Versatile boards */21#define VERSATILE_LOCK_VAL 0xA05F22 23/*24 * We detect the different syscon types from the compatible strings.25 */26enum versatile_reboot {27 INTEGRATOR_REBOOT_CM,28 VERSATILE_REBOOT_CM,29 REALVIEW_REBOOT_EB,30 REALVIEW_REBOOT_PB1176,31 REALVIEW_REBOOT_PB11MP,32 REALVIEW_REBOOT_PBA8,33 REALVIEW_REBOOT_PBX,34};35 36/* Pointer to the system controller */37static struct regmap *syscon_regmap;38static enum versatile_reboot versatile_reboot_type;39 40static const struct of_device_id versatile_reboot_of_match[] = {41 {42 .compatible = "arm,core-module-integrator",43 .data = (void *)INTEGRATOR_REBOOT_CM44 },45 {46 .compatible = "arm,core-module-versatile",47 .data = (void *)VERSATILE_REBOOT_CM,48 },49 {50 .compatible = "arm,realview-eb-syscon",51 .data = (void *)REALVIEW_REBOOT_EB,52 },53 {54 .compatible = "arm,realview-pb1176-syscon",55 .data = (void *)REALVIEW_REBOOT_PB1176,56 },57 {58 .compatible = "arm,realview-pb11mp-syscon",59 .data = (void *)REALVIEW_REBOOT_PB11MP,60 },61 {62 .compatible = "arm,realview-pba8-syscon",63 .data = (void *)REALVIEW_REBOOT_PBA8,64 },65 {66 .compatible = "arm,realview-pbx-syscon",67 .data = (void *)REALVIEW_REBOOT_PBX,68 },69 {},70};71 72static int versatile_reboot(struct notifier_block *this, unsigned long mode,73 void *cmd)74{75 /* Unlock the reset register */76 /* Then hit reset on the different machines */77 switch (versatile_reboot_type) {78 case INTEGRATOR_REBOOT_CM:79 regmap_write(syscon_regmap, INTEGRATOR_HDR_LOCK_OFFSET,80 VERSATILE_LOCK_VAL);81 regmap_update_bits(syscon_regmap,82 INTEGRATOR_HDR_CTRL_OFFSET,83 INTEGRATOR_CM_CTRL_RESET,84 INTEGRATOR_CM_CTRL_RESET);85 break;86 case VERSATILE_REBOOT_CM:87 regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,88 VERSATILE_LOCK_VAL);89 regmap_update_bits(syscon_regmap,90 VERSATILE_SYS_RESETCTL_OFFSET,91 0x0107,92 0x0105);93 regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,94 0);95 break;96 case REALVIEW_REBOOT_EB:97 regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,98 VERSATILE_LOCK_VAL);99 regmap_write(syscon_regmap,100 VERSATILE_SYS_RESETCTL_OFFSET, 0x0008);101 break;102 case REALVIEW_REBOOT_PB1176:103 regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,104 VERSATILE_LOCK_VAL);105 regmap_write(syscon_regmap,106 VERSATILE_SYS_RESETCTL_OFFSET, 0x0100);107 break;108 case REALVIEW_REBOOT_PB11MP:109 case REALVIEW_REBOOT_PBA8:110 regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,111 VERSATILE_LOCK_VAL);112 regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,113 0x0000);114 regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,115 0x0004);116 break;117 case REALVIEW_REBOOT_PBX:118 regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,119 VERSATILE_LOCK_VAL);120 regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,121 0x00f0);122 regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,123 0x00f4);124 break;125 }126 dsb();127 128 return NOTIFY_DONE;129}130 131static struct notifier_block versatile_reboot_nb = {132 .notifier_call = versatile_reboot,133 .priority = 192,134};135 136static int __init versatile_reboot_probe(void)137{138 const struct of_device_id *reboot_id;139 struct device_node *np;140 int err;141 142 np = of_find_matching_node_and_match(NULL, versatile_reboot_of_match,143 &reboot_id);144 if (!np)145 return -ENODEV;146 versatile_reboot_type = (enum versatile_reboot)reboot_id->data;147 148 syscon_regmap = syscon_node_to_regmap(np);149 of_node_put(np);150 if (IS_ERR(syscon_regmap))151 return PTR_ERR(syscon_regmap);152 153 err = register_restart_handler(&versatile_reboot_nb);154 if (err)155 return err;156 157 pr_info("versatile reboot driver registered\n");158 return 0;159}160device_initcall(versatile_reboot_probe);161