1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * TI keystone reboot driver 4 * 5 * Copyright (C) 2014 Texas Instruments Incorporated. https://www.ti.com/ 6 * 7 * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com> 8 */ 9 10 #include <linux/io.h> 11 #include <linux/module.h> 12 #include <linux/notifier.h> 13 #include <linux/platform_device.h> 14 #include <linux/reboot.h> 15 #include <linux/regmap.h> 16 #include <linux/mfd/syscon.h> 17 #include <linux/of.h> 18 19 #define RSCTRL_RG 0x4 20 #define RSCFG_RG 0x8 21 #define RSISO_RG 0xc 22 23 #define RSCTRL_KEY_MASK 0x0000ffff 24 #define RSCTRL_RESET_MASK BIT(16) 25 #define RSCTRL_KEY 0x5a69 26 27 #define RSMUX_OMODE_MASK 0xe 28 #define RSMUX_OMODE_RESET_ON 0xa 29 #define RSMUX_OMODE_RESET_OFF 0x0 30 #define RSMUX_LOCK_SET 0x1 31 32 #define RSCFG_RSTYPE_SOFT 0x300f 33 #define RSCFG_RSTYPE_HARD 0x0 34 35 #define WDT_MUX_NUMBER 0x4 36 37 static int rspll_offset; 38 static struct regmap *pllctrl_regs; 39 40 /** 41 * rsctrl_enable_rspll_write - enable access to RSCTRL, RSCFG 42 * To be able to access to RSCTRL, RSCFG registers 43 * we have to write a key before 44 */ 45 static inline int rsctrl_enable_rspll_write(void) 46 { 47 return regmap_update_bits(pllctrl_regs, rspll_offset + RSCTRL_RG, 48 RSCTRL_KEY_MASK, RSCTRL_KEY); 49 } 50 51 static int rsctrl_restart_handler(struct notifier_block *this, 52 unsigned long mode, void *cmd) 53 { 54 /* enable write access to RSTCTRL */ 55 rsctrl_enable_rspll_write(); 56 57 /* reset the SOC */ 58 regmap_update_bits(pllctrl_regs, rspll_offset + RSCTRL_RG, 59 RSCTRL_RESET_MASK, 0); 60 61 return NOTIFY_DONE; 62 } 63 64 static struct notifier_block rsctrl_restart_nb = { 65 .notifier_call = rsctrl_restart_handler, 66 .priority = 128, 67 }; 68 69 static const struct of_device_id rsctrl_of_match[] = { 70 {.compatible = "ti,keystone-reset", }, 71 {}, 72 }; 73 MODULE_DEVICE_TABLE(of, rsctrl_of_match); 74 75 static int rsctrl_probe(struct platform_device *pdev) 76 { 77 int i; 78 int ret; 79 u32 val; 80 unsigned int rg; 81 u32 rsmux_offset; 82 struct regmap *devctrl_regs; 83 struct device *dev = &pdev->dev; 84 struct device_node *np = dev->of_node; 85 86 if (!np) 87 return -ENODEV; 88 89 /* get regmaps */ 90 pllctrl_regs = syscon_regmap_lookup_by_phandle_args(np, "ti,syscon-pll", 91 1, &rspll_offset); 92 if (IS_ERR(pllctrl_regs)) 93 return PTR_ERR(pllctrl_regs); 94 95 devctrl_regs = syscon_regmap_lookup_by_phandle_args(np, "ti,syscon-dev", 96 1, &rsmux_offset); 97 if (IS_ERR(devctrl_regs)) 98 return PTR_ERR(devctrl_regs); 99 100 /* set soft/hard reset */ 101 val = of_property_read_bool(np, "ti,soft-reset"); 102 val = val ? RSCFG_RSTYPE_SOFT : RSCFG_RSTYPE_HARD; 103 104 ret = rsctrl_enable_rspll_write(); 105 if (ret) 106 return ret; 107 108 ret = regmap_write(pllctrl_regs, rspll_offset + RSCFG_RG, val); 109 if (ret) 110 return ret; 111 112 /* disable a reset isolation for all module clocks */ 113 ret = regmap_write(pllctrl_regs, rspll_offset + RSISO_RG, 0); 114 if (ret) 115 return ret; 116 117 /* enable a reset for watchdogs from wdt-list */ 118 for (i = 0; i < WDT_MUX_NUMBER; i++) { 119 ret = of_property_read_u32_index(np, "ti,wdt-list", i, &val); 120 if (ret == -EOVERFLOW && !i) { 121 dev_err(dev, "ti,wdt-list property has to contain at" 122 "least one entry\n"); 123 return -EINVAL; 124 } else if (ret) { 125 break; 126 } 127 128 if (val >= WDT_MUX_NUMBER) { 129 dev_err(dev, "ti,wdt-list property can contain " 130 "only numbers < 4\n"); 131 return -EINVAL; 132 } 133 134 rg = rsmux_offset + val * 4; 135 136 ret = regmap_update_bits(devctrl_regs, rg, RSMUX_OMODE_MASK, 137 RSMUX_OMODE_RESET_ON | 138 RSMUX_LOCK_SET); 139 if (ret) 140 return ret; 141 } 142 143 ret = register_restart_handler(&rsctrl_restart_nb); 144 if (ret) 145 dev_err(dev, "cannot register restart handler (err=%d)\n", ret); 146 147 return ret; 148 } 149 150 static struct platform_driver rsctrl_driver = { 151 .probe = rsctrl_probe, 152 .driver = { 153 .name = KBUILD_MODNAME, 154 .of_match_table = rsctrl_of_match, 155 }, 156 }; 157 module_platform_driver(rsctrl_driver); 158 159 MODULE_AUTHOR("Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>"); 160 MODULE_DESCRIPTION("Texas Instruments keystone reset driver"); 161 MODULE_ALIAS("platform:" KBUILD_MODNAME); 162