1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Amlogic Meson Reset Controller driver
4  *
5  * Copyright (c) 2018 BayLibre, SAS.
6  * Author: Neil Armstrong <narmstrong@baylibre.com>
7  */
8 
9 #include <common.h>
10 #include <dm.h>
11 #include <log.h>
12 #include <malloc.h>
13 #include <reset-uclass.h>
14 #include <regmap.h>
15 #include <linux/bitops.h>
16 
17 #define REG_COUNT	8
18 #define BITS_PER_REG	32
19 #define LEVEL_OFFSET	0x7c
20 
21 struct meson_reset_priv {
22 	struct regmap *regmap;
23 };
24 
meson_reset_request(struct reset_ctl * reset_ctl)25 static int meson_reset_request(struct reset_ctl *reset_ctl)
26 {
27 	if (reset_ctl->id > (REG_COUNT * BITS_PER_REG))
28 		return -EINVAL;
29 
30 	return 0;
31 }
32 
meson_reset_free(struct reset_ctl * reset_ctl)33 static int meson_reset_free(struct reset_ctl *reset_ctl)
34 {
35 	return 0;
36 }
37 
meson_reset_level(struct reset_ctl * reset_ctl,bool assert)38 static int meson_reset_level(struct reset_ctl *reset_ctl, bool assert)
39 {
40 	struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev);
41 	uint bank = reset_ctl->id / BITS_PER_REG;
42 	uint offset = reset_ctl->id % BITS_PER_REG;
43 	uint reg_offset = LEVEL_OFFSET + (bank << 2);
44 	uint val;
45 
46 	regmap_read(priv->regmap, reg_offset, &val);
47 	if (assert)
48 		val &= ~BIT(offset);
49 	else
50 		val |= BIT(offset);
51 	regmap_write(priv->regmap, reg_offset, val);
52 
53 	return 0;
54 }
55 
meson_reset_assert(struct reset_ctl * reset_ctl)56 static int meson_reset_assert(struct reset_ctl *reset_ctl)
57 {
58 	return meson_reset_level(reset_ctl, true);
59 }
60 
meson_reset_deassert(struct reset_ctl * reset_ctl)61 static int meson_reset_deassert(struct reset_ctl *reset_ctl)
62 {
63 	return meson_reset_level(reset_ctl, false);
64 }
65 
66 struct reset_ops meson_reset_ops = {
67 	.request = meson_reset_request,
68 	.rfree = meson_reset_free,
69 	.rst_assert = meson_reset_assert,
70 	.rst_deassert = meson_reset_deassert,
71 };
72 
73 static const struct udevice_id meson_reset_ids[] = {
74 	{ .compatible = "amlogic,meson-gxbb-reset" },
75 	{ .compatible = "amlogic,meson-axg-reset" },
76 	{ }
77 };
78 
meson_reset_probe(struct udevice * dev)79 static int meson_reset_probe(struct udevice *dev)
80 {
81 	struct meson_reset_priv *priv = dev_get_priv(dev);
82 
83 	return regmap_init_mem(dev_ofnode(dev), &priv->regmap);
84 }
85 
86 U_BOOT_DRIVER(meson_reset) = {
87 	.name = "meson_reset",
88 	.id = UCLASS_RESET,
89 	.of_match = meson_reset_ids,
90 	.probe = meson_reset_probe,
91 	.ops = &meson_reset_ops,
92 	.priv_auto	= sizeof(struct meson_reset_priv),
93 };
94