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", ®_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