root/drivers/power/reset/arm-versatile-reboot.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. versatile_reboot
  2. versatile_reboot_probe

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   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      0x0C
  14 #define INTEGRATOR_HDR_LOCK_OFFSET      0x14
  15 #define INTEGRATOR_CM_CTRL_RESET        (1 << 3)
  16 
  17 #define VERSATILE_SYS_LOCK_OFFSET       0x20
  18 #define VERSATILE_SYS_RESETCTL_OFFSET   0x40
  19 
  20 /* Magic unlocking token used on all Versatile boards */
  21 #define VERSATILE_LOCK_VAL              0xA05F
  22 
  23 /*
  24  * We detect the different syscon types from the compatible strings.
  25  */
  26 enum 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 */
  37 static struct regmap *syscon_regmap;
  38 static enum versatile_reboot versatile_reboot_type;
  39 
  40 static const struct of_device_id versatile_reboot_of_match[] = {
  41         {
  42                 .compatible = "arm,core-module-integrator",
  43                 .data = (void *)INTEGRATOR_REBOOT_CM
  44         },
  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 
  72 static 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 
 131 static struct notifier_block versatile_reboot_nb = {
 132         .notifier_call = versatile_reboot,
 133         .priority = 192,
 134 };
 135 
 136 static 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         if (IS_ERR(syscon_regmap))
 150                 return PTR_ERR(syscon_regmap);
 151 
 152         err = register_restart_handler(&versatile_reboot_nb);
 153         if (err)
 154                 return err;
 155 
 156         pr_info("versatile reboot driver registered\n");
 157         return 0;
 158 }
 159 device_initcall(versatile_reboot_probe);

/* [<][>][^][v][top][bottom][index][help] */