blob: 1849db4da9b076bf839e8a46dee8d4315def7cf8 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Dinh Nguyen2ac71882018-04-04 17:18:20 -05002/*
3 * Socfpga Reset Controller Driver
4 *
5 * Copyright 2014 Steffen Trumtrar <s.trumtrar@pengutronix.de>
6 *
7 * based on
8 * Allwinner SoCs Reset Controller driver
9 *
10 * Copyright 2013 Maxime Ripard
11 *
12 * Maxime Ripard <maxime.ripard@free-electrons.com>
Dinh Nguyen2ac71882018-04-04 17:18:20 -050013 */
14
15#include <common.h>
16#include <dm.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060017#include <log.h>
Simon Glass336d4612020-02-03 07:36:16 -070018#include <malloc.h>
Simon Goldschmidtef72ba02019-07-15 21:47:55 +020019#include <dm/lists.h>
Dinh Nguyen2ac71882018-04-04 17:18:20 -050020#include <dm/of_access.h>
Simon Glass7b51b572019-08-01 09:46:52 -060021#include <env.h>
Dinh Nguyen2ac71882018-04-04 17:18:20 -050022#include <reset-uclass.h>
Ley Foon Tan9e608212020-01-10 13:48:37 +080023#include <wait_bit.h>
Dinh Nguyen2ac71882018-04-04 17:18:20 -050024#include <linux/bitops.h>
25#include <linux/io.h>
26#include <linux/sizes.h>
27
28#define BANK_INCREMENT 4
29#define NR_BANKS 8
30
31struct socfpga_reset_data {
Simon Goldschmidt1ea97502019-03-01 20:12:30 +010032 void __iomem *modrst_base;
Dinh Nguyen2ac71882018-04-04 17:18:20 -050033};
34
Simon Goldschmidtede6e7b2019-03-01 20:12:32 +010035/*
36 * For compatibility with Kernels that don't support peripheral reset, this
37 * driver can keep the old behaviour of not asserting peripheral reset before
38 * starting the OS and deasserting all peripheral resets (enabling all
39 * peripherals).
40 *
41 * For that, the reset driver checks the environment variable
42 * "socfpga_legacy_reset_compat". If this variable is '1', perihperals are not
43 * reset again once taken out of reset and all peripherals in 'permodrst' are
44 * taken out of reset before booting into the OS.
45 * Note that this should be required for gen5 systems only that are running
46 * Linux kernels without proper peripheral reset support for all drivers used.
47 */
48static bool socfpga_reset_keep_enabled(void)
49{
50#if !defined(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(ENV_SUPPORT)
51 const char *env_str;
52 long val;
53
54 env_str = env_get("socfpga_legacy_reset_compat");
55 if (env_str) {
56 val = simple_strtol(env_str, NULL, 0);
57 if (val == 1)
58 return true;
59 }
60#endif
61
62 return false;
63}
64
Dinh Nguyen2ac71882018-04-04 17:18:20 -050065static int socfpga_reset_assert(struct reset_ctl *reset_ctl)
66{
67 struct socfpga_reset_data *data = dev_get_priv(reset_ctl->dev);
68 int id = reset_ctl->id;
69 int reg_width = sizeof(u32);
70 int bank = id / (reg_width * BITS_PER_BYTE);
71 int offset = id % (reg_width * BITS_PER_BYTE);
72
Simon Goldschmidt1ea97502019-03-01 20:12:30 +010073 setbits_le32(data->modrst_base + (bank * BANK_INCREMENT), BIT(offset));
Dinh Nguyen2ac71882018-04-04 17:18:20 -050074 return 0;
75}
76
77static int socfpga_reset_deassert(struct reset_ctl *reset_ctl)
78{
79 struct socfpga_reset_data *data = dev_get_priv(reset_ctl->dev);
80 int id = reset_ctl->id;
81 int reg_width = sizeof(u32);
82 int bank = id / (reg_width * BITS_PER_BYTE);
83 int offset = id % (reg_width * BITS_PER_BYTE);
84
Simon Goldschmidt1ea97502019-03-01 20:12:30 +010085 clrbits_le32(data->modrst_base + (bank * BANK_INCREMENT), BIT(offset));
Ley Foon Tan9e608212020-01-10 13:48:37 +080086
87 return wait_for_bit_le32(data->modrst_base + (bank * BANK_INCREMENT),
88 BIT(offset),
89 false, 500, false);
Dinh Nguyen2ac71882018-04-04 17:18:20 -050090}
91
92static int socfpga_reset_request(struct reset_ctl *reset_ctl)
93{
94 debug("%s(reset_ctl=%p) (dev=%p, id=%lu)\n", __func__,
95 reset_ctl, reset_ctl->dev, reset_ctl->id);
96
97 return 0;
98}
99
100static int socfpga_reset_free(struct reset_ctl *reset_ctl)
101{
102 debug("%s(reset_ctl=%p) (dev=%p, id=%lu)\n", __func__, reset_ctl,
103 reset_ctl->dev, reset_ctl->id);
104
105 return 0;
106}
107
108static const struct reset_ops socfpga_reset_ops = {
109 .request = socfpga_reset_request,
Simon Glass94474b22020-02-03 07:35:52 -0700110 .rfree = socfpga_reset_free,
Dinh Nguyen2ac71882018-04-04 17:18:20 -0500111 .rst_assert = socfpga_reset_assert,
112 .rst_deassert = socfpga_reset_deassert,
113};
114
115static int socfpga_reset_probe(struct udevice *dev)
116{
117 struct socfpga_reset_data *data = dev_get_priv(dev);
Dinh Nguyen2ac71882018-04-04 17:18:20 -0500118 u32 modrst_offset;
Simon Goldschmidt1ea97502019-03-01 20:12:30 +0100119 void __iomem *membase;
Dinh Nguyen2ac71882018-04-04 17:18:20 -0500120
Masahiro Yamada702e57e2020-08-04 14:14:43 +0900121 membase = dev_read_addr_ptr(dev);
Dinh Nguyen2ac71882018-04-04 17:18:20 -0500122
Simon Goldschmidt6cdd0a42019-05-09 22:11:59 +0200123 modrst_offset = dev_read_u32_default(dev, "altr,modrst-offset", 0x10);
Simon Goldschmidt1ea97502019-03-01 20:12:30 +0100124 data->modrst_base = membase + modrst_offset;
Dinh Nguyen2ac71882018-04-04 17:18:20 -0500125
126 return 0;
127}
128
Simon Goldschmidtede6e7b2019-03-01 20:12:32 +0100129static int socfpga_reset_remove(struct udevice *dev)
130{
131 struct socfpga_reset_data *data = dev_get_priv(dev);
132
133 if (socfpga_reset_keep_enabled()) {
134 puts("Deasserting all peripheral resets\n");
135 writel(0, data->modrst_base + 4);
136 }
137
138 return 0;
139}
140
Simon Goldschmidtef72ba02019-07-15 21:47:55 +0200141static int socfpga_reset_bind(struct udevice *dev)
142{
143 int ret;
144 struct udevice *sys_child;
145
146 /*
147 * The sysreset driver does not have a device node, so bind it here.
148 * Bind it to the node, too, so that it can get its base address.
149 */
150 ret = device_bind_driver_to_node(dev, "socfpga_sysreset", "sysreset",
151 dev->node, &sys_child);
152 if (ret)
153 debug("Warning: No sysreset driver: ret=%d\n", ret);
154
155 return 0;
156}
157
Dinh Nguyen2ac71882018-04-04 17:18:20 -0500158static const struct udevice_id socfpga_reset_match[] = {
159 { .compatible = "altr,rst-mgr" },
160 { /* sentinel */ },
161};
162
163U_BOOT_DRIVER(socfpga_reset) = {
164 .name = "socfpga-reset",
165 .id = UCLASS_RESET,
166 .of_match = socfpga_reset_match,
Simon Goldschmidtef72ba02019-07-15 21:47:55 +0200167 .bind = socfpga_reset_bind,
Dinh Nguyen2ac71882018-04-04 17:18:20 -0500168 .probe = socfpga_reset_probe,
169 .priv_auto_alloc_size = sizeof(struct socfpga_reset_data),
170 .ops = &socfpga_reset_ops,
Simon Goldschmidtede6e7b2019-03-01 20:12:32 +0100171 .remove = socfpga_reset_remove,
172 .flags = DM_FLAG_OS_PREPARE,
Dinh Nguyen2ac71882018-04-04 17:18:20 -0500173};