1 /* 2 * Copyright (C) 2014 Linaro Ltd. 3 * 4 * Author: Linus Walleij <linus.walleij@linaro.org> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2, as 8 * published by the Free Software Foundation. 9 * 10 */ 11 #include <linux/init.h> 12 #include <linux/mfd/syscon.h> 13 #include <linux/reboot.h> 14 #include <linux/regmap.h> 15 #include <linux/of.h> 16 #include <asm/system_misc.h> 17 18 #define REALVIEW_SYS_LOCK_OFFSET 0x20 19 #define REALVIEW_SYS_LOCK_VAL 0xA05F 20 #define REALVIEW_SYS_RESETCTL_OFFSET 0x40 21 22 /* 23 * We detect the different syscon types from the compatible strings. 24 */ 25 enum versatile_reboot { 26 REALVIEW_REBOOT_EB, 27 REALVIEW_REBOOT_PB1176, 28 REALVIEW_REBOOT_PB11MP, 29 REALVIEW_REBOOT_PBA8, 30 REALVIEW_REBOOT_PBX, 31 }; 32 33 /* Pointer to the system controller */ 34 static struct regmap *syscon_regmap; 35 static enum versatile_reboot versatile_reboot_type; 36 37 static const struct of_device_id versatile_reboot_of_match[] = { 38 { 39 .compatible = "arm,realview-eb-syscon", 40 .data = (void *)REALVIEW_REBOOT_EB, 41 }, 42 { 43 .compatible = "arm,realview-pb1176-syscon", 44 .data = (void *)REALVIEW_REBOOT_PB1176, 45 }, 46 { 47 .compatible = "arm,realview-pb11mp-syscon", 48 .data = (void *)REALVIEW_REBOOT_PB11MP, 49 }, 50 { 51 .compatible = "arm,realview-pba8-syscon", 52 .data = (void *)REALVIEW_REBOOT_PBA8, 53 }, 54 { 55 .compatible = "arm,realview-pbx-syscon", 56 .data = (void *)REALVIEW_REBOOT_PBX, 57 }, 58 }; 59 60 static void versatile_reboot(enum reboot_mode mode, const char *cmd) 61 { 62 /* Unlock the reset register */ 63 regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET, 64 REALVIEW_SYS_LOCK_VAL); 65 /* Then hit reset on the different machines */ 66 switch (versatile_reboot_type) { 67 case REALVIEW_REBOOT_EB: 68 regmap_write(syscon_regmap, 69 REALVIEW_SYS_RESETCTL_OFFSET, 0x0008); 70 break; 71 case REALVIEW_REBOOT_PB1176: 72 regmap_write(syscon_regmap, 73 REALVIEW_SYS_RESETCTL_OFFSET, 0x0100); 74 break; 75 case REALVIEW_REBOOT_PB11MP: 76 case REALVIEW_REBOOT_PBA8: 77 regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET, 78 0x0000); 79 regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET, 80 0x0004); 81 break; 82 case REALVIEW_REBOOT_PBX: 83 regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET, 84 0x00f0); 85 regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET, 86 0x00f4); 87 break; 88 } 89 dsb(); 90 } 91 92 static int __init versatile_reboot_probe(void) 93 { 94 const struct of_device_id *reboot_id; 95 struct device_node *np; 96 97 np = of_find_matching_node_and_match(NULL, versatile_reboot_of_match, 98 &reboot_id); 99 if (!np) 100 return -ENODEV; 101 versatile_reboot_type = (enum versatile_reboot)reboot_id->data; 102 103 syscon_regmap = syscon_node_to_regmap(np); 104 if (IS_ERR(syscon_regmap)) 105 return PTR_ERR(syscon_regmap); 106 107 arm_pm_restart = versatile_reboot; 108 pr_info("versatile reboot driver registered\n"); 109 return 0; 110 } 111 device_initcall(versatile_reboot_probe); 112