xref: /openbmc/linux/drivers/reset/reset-socfpga.c (revision 3ad60b4b)
1b3ca9888SDinh Nguyen // SPDX-License-Identifier: GPL-2.0
2b3ca9888SDinh Nguyen /*
3b3ca9888SDinh Nguyen  * Copyright (C) 2018, Intel Corporation
4b3ca9888SDinh Nguyen  * Copied from reset-sunxi.c
5b3ca9888SDinh Nguyen  */
6b3ca9888SDinh Nguyen 
7b3ca9888SDinh Nguyen #include <linux/err.h>
8b3ca9888SDinh Nguyen #include <linux/io.h>
9b3ca9888SDinh Nguyen #include <linux/init.h>
10b3ca9888SDinh Nguyen #include <linux/of.h>
11b3ca9888SDinh Nguyen #include <linux/of_address.h>
12b3ca9888SDinh Nguyen #include <linux/platform_device.h>
13b3ca9888SDinh Nguyen #include <linux/reset-controller.h>
149357b046SMaxime Ripard #include <linux/reset/reset-simple.h>
15cdbeb315SPhilipp Zabel #include <linux/reset/socfpga.h>
16b3ca9888SDinh Nguyen #include <linux/slab.h>
17b3ca9888SDinh Nguyen #include <linux/spinlock.h>
18b3ca9888SDinh Nguyen #include <linux/types.h>
19b3ca9888SDinh Nguyen 
20b3ca9888SDinh Nguyen #define SOCFPGA_NR_BANKS	8
21b3ca9888SDinh Nguyen 
a10_reset_init(struct device_node * np)22b3ca9888SDinh Nguyen static int a10_reset_init(struct device_node *np)
23b3ca9888SDinh Nguyen {
24b3ca9888SDinh Nguyen 	struct reset_simple_data *data;
25b3ca9888SDinh Nguyen 	struct resource res;
26b3ca9888SDinh Nguyen 	resource_size_t size;
27b3ca9888SDinh Nguyen 	int ret;
28b3ca9888SDinh Nguyen 	u32 reg_offset = 0x10;
29b3ca9888SDinh Nguyen 
30b3ca9888SDinh Nguyen 	data = kzalloc(sizeof(*data), GFP_KERNEL);
31b3ca9888SDinh Nguyen 	if (!data)
32b3ca9888SDinh Nguyen 		return -ENOMEM;
33b3ca9888SDinh Nguyen 
34b3ca9888SDinh Nguyen 	ret = of_address_to_resource(np, 0, &res);
35b3ca9888SDinh Nguyen 	if (ret)
36b3ca9888SDinh Nguyen 		goto err_alloc;
37b3ca9888SDinh Nguyen 
38b3ca9888SDinh Nguyen 	size = resource_size(&res);
39b3ca9888SDinh Nguyen 	if (!request_mem_region(res.start, size, np->name)) {
40b3ca9888SDinh Nguyen 		ret = -EBUSY;
41b3ca9888SDinh Nguyen 		goto err_alloc;
42b3ca9888SDinh Nguyen 	}
43b3ca9888SDinh Nguyen 
44b3ca9888SDinh Nguyen 	data->membase = ioremap(res.start, size);
45b3ca9888SDinh Nguyen 	if (!data->membase) {
46b3ca9888SDinh Nguyen 		ret = -ENOMEM;
470d625a16SDinh Nguyen 		goto release_region;
48b3ca9888SDinh Nguyen 	}
49b3ca9888SDinh Nguyen 
50b3ca9888SDinh Nguyen 	if (of_property_read_u32(np, "altr,modrst-offset", &reg_offset))
51b3ca9888SDinh Nguyen 		pr_warn("missing altr,modrst-offset property, assuming 0x10\n");
52b3ca9888SDinh Nguyen 	data->membase += reg_offset;
53b3ca9888SDinh Nguyen 
54b3ca9888SDinh Nguyen 	spin_lock_init(&data->lock);
55b3ca9888SDinh Nguyen 
56b3ca9888SDinh Nguyen 	data->rcdev.owner = THIS_MODULE;
57b3ca9888SDinh Nguyen 	data->rcdev.nr_resets = SOCFPGA_NR_BANKS * 32;
58b3ca9888SDinh Nguyen 	data->rcdev.ops = &reset_simple_ops;
59b3ca9888SDinh Nguyen 	data->rcdev.of_node = np;
60b3ca9888SDinh Nguyen 	data->status_active_low = true;
61b3ca9888SDinh Nguyen 
620d625a16SDinh Nguyen 	ret = reset_controller_register(&data->rcdev);
630d625a16SDinh Nguyen 	if (ret)
640d625a16SDinh Nguyen 		pr_err("unable to register device\n");
650d625a16SDinh Nguyen 
660d625a16SDinh Nguyen 	return ret;
670d625a16SDinh Nguyen 
680d625a16SDinh Nguyen release_region:
690d625a16SDinh Nguyen 	release_mem_region(res.start, size);
70b3ca9888SDinh Nguyen 
71b3ca9888SDinh Nguyen err_alloc:
72b3ca9888SDinh Nguyen 	kfree(data);
73b3ca9888SDinh Nguyen 	return ret;
74b3ca9888SDinh Nguyen };
75b3ca9888SDinh Nguyen 
76b3ca9888SDinh Nguyen /*
77b3ca9888SDinh Nguyen  * These are the reset controller we need to initialize early on in
78b3ca9888SDinh Nguyen  * our system, before we can even think of using a regular device
79b3ca9888SDinh Nguyen  * driver for it.
80b3ca9888SDinh Nguyen  * The controllers that we can register through the regular device
81b3ca9888SDinh Nguyen  * model are handled by the simple reset driver directly.
82b3ca9888SDinh Nguyen  */
83b3ca9888SDinh Nguyen static const struct of_device_id socfpga_early_reset_dt_ids[] __initconst = {
84b3ca9888SDinh Nguyen 	{ .compatible = "altr,rst-mgr", },
85b3ca9888SDinh Nguyen 	{ /* sentinel */ },
86b3ca9888SDinh Nguyen };
87b3ca9888SDinh Nguyen 
socfpga_reset_init(void)88b3ca9888SDinh Nguyen void __init socfpga_reset_init(void)
89b3ca9888SDinh Nguyen {
90b3ca9888SDinh Nguyen 	struct device_node *np;
91b3ca9888SDinh Nguyen 
92b3ca9888SDinh Nguyen 	for_each_matching_node(np, socfpga_early_reset_dt_ids)
93b3ca9888SDinh Nguyen 		a10_reset_init(np);
94b3ca9888SDinh Nguyen }
95*3ad60b4bSPaweł Anikiel 
96*3ad60b4bSPaweł Anikiel /*
97*3ad60b4bSPaweł Anikiel  * The early driver is problematic, because it doesn't register
98*3ad60b4bSPaweł Anikiel  * itself as a driver. This causes certain device links to prevent
99*3ad60b4bSPaweł Anikiel  * consumer devices from probing. The hacky solution is to register
100*3ad60b4bSPaweł Anikiel  * an empty driver, whose only job is to attach itself to the reset
101*3ad60b4bSPaweł Anikiel  * manager and call probe.
102*3ad60b4bSPaweł Anikiel  */
103*3ad60b4bSPaweł Anikiel static const struct of_device_id socfpga_reset_dt_ids[] = {
104*3ad60b4bSPaweł Anikiel 	{ .compatible = "altr,rst-mgr", },
105*3ad60b4bSPaweł Anikiel 	{ /* sentinel */ },
106*3ad60b4bSPaweł Anikiel };
107*3ad60b4bSPaweł Anikiel 
reset_simple_probe(struct platform_device * pdev)108*3ad60b4bSPaweł Anikiel static int reset_simple_probe(struct platform_device *pdev)
109*3ad60b4bSPaweł Anikiel {
110*3ad60b4bSPaweł Anikiel 	return 0;
111*3ad60b4bSPaweł Anikiel }
112*3ad60b4bSPaweł Anikiel 
113*3ad60b4bSPaweł Anikiel static struct platform_driver reset_socfpga_driver = {
114*3ad60b4bSPaweł Anikiel 	.probe	= reset_simple_probe,
115*3ad60b4bSPaweł Anikiel 	.driver = {
116*3ad60b4bSPaweł Anikiel 		.name		= "socfpga-reset",
117*3ad60b4bSPaweł Anikiel 		.of_match_table	= socfpga_reset_dt_ids,
118*3ad60b4bSPaweł Anikiel 	},
119*3ad60b4bSPaweł Anikiel };
120*3ad60b4bSPaweł Anikiel builtin_platform_driver(reset_socfpga_driver);
121