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