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