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