189c1e2daSStephen Warren /*
289c1e2daSStephen Warren * Copyright (c) 2016, NVIDIA CORPORATION.
389c1e2daSStephen Warren *
489c1e2daSStephen Warren * SPDX-License-Identifier: GPL-2.0
589c1e2daSStephen Warren */
689c1e2daSStephen Warren
789c1e2daSStephen Warren #include <common.h>
889c1e2daSStephen Warren #include <dm.h>
989c1e2daSStephen Warren #include <fdtdec.h>
1089c1e2daSStephen Warren #include <reset.h>
1189c1e2daSStephen Warren #include <reset-uclass.h>
1289c1e2daSStephen Warren
1389c1e2daSStephen Warren DECLARE_GLOBAL_DATA_PTR;
1489c1e2daSStephen Warren
reset_dev_ops(struct udevice * dev)1589c1e2daSStephen Warren static inline struct reset_ops *reset_dev_ops(struct udevice *dev)
1689c1e2daSStephen Warren {
1789c1e2daSStephen Warren return (struct reset_ops *)dev->driver->ops;
1889c1e2daSStephen Warren }
1989c1e2daSStephen Warren
reset_of_xlate_default(struct reset_ctl * reset_ctl,struct ofnode_phandle_args * args)2089c1e2daSStephen Warren static int reset_of_xlate_default(struct reset_ctl *reset_ctl,
2140a475e8SSimon Glass struct ofnode_phandle_args *args)
2289c1e2daSStephen Warren {
2389c1e2daSStephen Warren debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
2489c1e2daSStephen Warren
2589c1e2daSStephen Warren if (args->args_count != 1) {
2689c1e2daSStephen Warren debug("Invaild args_count: %d\n", args->args_count);
2789c1e2daSStephen Warren return -EINVAL;
2889c1e2daSStephen Warren }
2989c1e2daSStephen Warren
3089c1e2daSStephen Warren reset_ctl->id = args->args[0];
3189c1e2daSStephen Warren
3289c1e2daSStephen Warren return 0;
3389c1e2daSStephen Warren }
3489c1e2daSStephen Warren
reset_get_by_index(struct udevice * dev,int index,struct reset_ctl * reset_ctl)3589c1e2daSStephen Warren int reset_get_by_index(struct udevice *dev, int index,
3689c1e2daSStephen Warren struct reset_ctl *reset_ctl)
3789c1e2daSStephen Warren {
3840a475e8SSimon Glass struct ofnode_phandle_args args;
3989c1e2daSStephen Warren int ret;
4089c1e2daSStephen Warren struct udevice *dev_reset;
4189c1e2daSStephen Warren struct reset_ops *ops;
4289c1e2daSStephen Warren
4389c1e2daSStephen Warren debug("%s(dev=%p, index=%d, reset_ctl=%p)\n", __func__, dev, index,
4489c1e2daSStephen Warren reset_ctl);
453b9d1bddSPatrice Chotard reset_ctl->dev = NULL;
4689c1e2daSStephen Warren
4740a475e8SSimon Glass ret = dev_read_phandle_with_args(dev, "resets", "#reset-cells", 0,
4889c1e2daSStephen Warren index, &args);
4989c1e2daSStephen Warren if (ret) {
5040a475e8SSimon Glass debug("%s: fdtdec_parse_phandle_with_args() failed: %d\n",
5189c1e2daSStephen Warren __func__, ret);
5289c1e2daSStephen Warren return ret;
5389c1e2daSStephen Warren }
5489c1e2daSStephen Warren
5540a475e8SSimon Glass ret = uclass_get_device_by_ofnode(UCLASS_RESET, args.node,
5689c1e2daSStephen Warren &dev_reset);
5789c1e2daSStephen Warren if (ret) {
5840a475e8SSimon Glass debug("%s: uclass_get_device_by_ofnode() failed: %d\n",
5989c1e2daSStephen Warren __func__, ret);
6040a475e8SSimon Glass debug("%s %d\n", ofnode_get_name(args.node), args.args[0]);
6189c1e2daSStephen Warren return ret;
6289c1e2daSStephen Warren }
6389c1e2daSStephen Warren ops = reset_dev_ops(dev_reset);
6489c1e2daSStephen Warren
6589c1e2daSStephen Warren reset_ctl->dev = dev_reset;
6689c1e2daSStephen Warren if (ops->of_xlate)
6789c1e2daSStephen Warren ret = ops->of_xlate(reset_ctl, &args);
6889c1e2daSStephen Warren else
6989c1e2daSStephen Warren ret = reset_of_xlate_default(reset_ctl, &args);
7089c1e2daSStephen Warren if (ret) {
7189c1e2daSStephen Warren debug("of_xlate() failed: %d\n", ret);
7289c1e2daSStephen Warren return ret;
7389c1e2daSStephen Warren }
7489c1e2daSStephen Warren
7589c1e2daSStephen Warren ret = ops->request(reset_ctl);
7689c1e2daSStephen Warren if (ret) {
7789c1e2daSStephen Warren debug("ops->request() failed: %d\n", ret);
7889c1e2daSStephen Warren return ret;
7989c1e2daSStephen Warren }
8089c1e2daSStephen Warren
8189c1e2daSStephen Warren return 0;
8289c1e2daSStephen Warren }
8389c1e2daSStephen Warren
reset_get_bulk(struct udevice * dev,struct reset_ctl_bulk * bulk)84d7940296SNeil Armstrong int reset_get_bulk(struct udevice *dev, struct reset_ctl_bulk *bulk)
85d7940296SNeil Armstrong {
86d7940296SNeil Armstrong int i, ret, err, count;
87d7940296SNeil Armstrong
88d7940296SNeil Armstrong bulk->count = 0;
89d7940296SNeil Armstrong
90d7940296SNeil Armstrong count = dev_count_phandle_with_args(dev, "resets", "#reset-cells");
91*989a41fcSNeil Armstrong if (count < 1)
92*989a41fcSNeil Armstrong return count;
93d7940296SNeil Armstrong
94d7940296SNeil Armstrong bulk->resets = devm_kcalloc(dev, count, sizeof(struct reset_ctl),
95d7940296SNeil Armstrong GFP_KERNEL);
96d7940296SNeil Armstrong if (!bulk->resets)
97d7940296SNeil Armstrong return -ENOMEM;
98d7940296SNeil Armstrong
99d7940296SNeil Armstrong for (i = 0; i < count; i++) {
100d7940296SNeil Armstrong ret = reset_get_by_index(dev, i, &bulk->resets[i]);
101d7940296SNeil Armstrong if (ret < 0)
102d7940296SNeil Armstrong goto bulk_get_err;
103d7940296SNeil Armstrong
104d7940296SNeil Armstrong ++bulk->count;
105d7940296SNeil Armstrong }
106d7940296SNeil Armstrong
107d7940296SNeil Armstrong return 0;
108d7940296SNeil Armstrong
109d7940296SNeil Armstrong bulk_get_err:
110d7940296SNeil Armstrong err = reset_release_all(bulk->resets, bulk->count);
111d7940296SNeil Armstrong if (err)
112d7940296SNeil Armstrong debug("%s: could release all resets for %p\n",
113d7940296SNeil Armstrong __func__, dev);
114d7940296SNeil Armstrong
115d7940296SNeil Armstrong return ret;
116d7940296SNeil Armstrong }
117d7940296SNeil Armstrong
reset_get_by_name(struct udevice * dev,const char * name,struct reset_ctl * reset_ctl)11889c1e2daSStephen Warren int reset_get_by_name(struct udevice *dev, const char *name,
11989c1e2daSStephen Warren struct reset_ctl *reset_ctl)
12089c1e2daSStephen Warren {
12189c1e2daSStephen Warren int index;
12289c1e2daSStephen Warren
12389c1e2daSStephen Warren debug("%s(dev=%p, name=%s, reset_ctl=%p)\n", __func__, dev, name,
12489c1e2daSStephen Warren reset_ctl);
1253b9d1bddSPatrice Chotard reset_ctl->dev = NULL;
12689c1e2daSStephen Warren
12740a475e8SSimon Glass index = dev_read_stringlist_search(dev, "reset-names", name);
12889c1e2daSStephen Warren if (index < 0) {
129b02e4044SSimon Glass debug("fdt_stringlist_search() failed: %d\n", index);
13089c1e2daSStephen Warren return index;
13189c1e2daSStephen Warren }
13289c1e2daSStephen Warren
13389c1e2daSStephen Warren return reset_get_by_index(dev, index, reset_ctl);
13489c1e2daSStephen Warren }
13589c1e2daSStephen Warren
reset_request(struct reset_ctl * reset_ctl)1369bd5cdf6SPatrice Chotard int reset_request(struct reset_ctl *reset_ctl)
1379bd5cdf6SPatrice Chotard {
1389bd5cdf6SPatrice Chotard struct reset_ops *ops = reset_dev_ops(reset_ctl->dev);
1399bd5cdf6SPatrice Chotard
1409bd5cdf6SPatrice Chotard debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
1419bd5cdf6SPatrice Chotard
1429bd5cdf6SPatrice Chotard return ops->request(reset_ctl);
1439bd5cdf6SPatrice Chotard }
1449bd5cdf6SPatrice Chotard
reset_free(struct reset_ctl * reset_ctl)14589c1e2daSStephen Warren int reset_free(struct reset_ctl *reset_ctl)
14689c1e2daSStephen Warren {
14789c1e2daSStephen Warren struct reset_ops *ops = reset_dev_ops(reset_ctl->dev);
14889c1e2daSStephen Warren
14989c1e2daSStephen Warren debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
15089c1e2daSStephen Warren
15189c1e2daSStephen Warren return ops->free(reset_ctl);
15289c1e2daSStephen Warren }
15389c1e2daSStephen Warren
reset_assert(struct reset_ctl * reset_ctl)15489c1e2daSStephen Warren int reset_assert(struct reset_ctl *reset_ctl)
15589c1e2daSStephen Warren {
15689c1e2daSStephen Warren struct reset_ops *ops = reset_dev_ops(reset_ctl->dev);
15789c1e2daSStephen Warren
15889c1e2daSStephen Warren debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
15989c1e2daSStephen Warren
16089c1e2daSStephen Warren return ops->rst_assert(reset_ctl);
16189c1e2daSStephen Warren }
16289c1e2daSStephen Warren
reset_assert_bulk(struct reset_ctl_bulk * bulk)163d7940296SNeil Armstrong int reset_assert_bulk(struct reset_ctl_bulk *bulk)
164d7940296SNeil Armstrong {
165d7940296SNeil Armstrong int i, ret;
166d7940296SNeil Armstrong
167d7940296SNeil Armstrong for (i = 0; i < bulk->count; i++) {
168d7940296SNeil Armstrong ret = reset_assert(&bulk->resets[i]);
169d7940296SNeil Armstrong if (ret < 0)
170d7940296SNeil Armstrong return ret;
171d7940296SNeil Armstrong }
172d7940296SNeil Armstrong
173d7940296SNeil Armstrong return 0;
174d7940296SNeil Armstrong }
175d7940296SNeil Armstrong
reset_deassert(struct reset_ctl * reset_ctl)17689c1e2daSStephen Warren int reset_deassert(struct reset_ctl *reset_ctl)
17789c1e2daSStephen Warren {
17889c1e2daSStephen Warren struct reset_ops *ops = reset_dev_ops(reset_ctl->dev);
17989c1e2daSStephen Warren
18089c1e2daSStephen Warren debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
18189c1e2daSStephen Warren
18289c1e2daSStephen Warren return ops->rst_deassert(reset_ctl);
18389c1e2daSStephen Warren }
18489c1e2daSStephen Warren
reset_deassert_bulk(struct reset_ctl_bulk * bulk)185d7940296SNeil Armstrong int reset_deassert_bulk(struct reset_ctl_bulk *bulk)
186d7940296SNeil Armstrong {
187d7940296SNeil Armstrong int i, ret;
188d7940296SNeil Armstrong
189d7940296SNeil Armstrong for (i = 0; i < bulk->count; i++) {
190d7940296SNeil Armstrong ret = reset_deassert(&bulk->resets[i]);
191d7940296SNeil Armstrong if (ret < 0)
192d7940296SNeil Armstrong return ret;
193d7940296SNeil Armstrong }
194d7940296SNeil Armstrong
195d7940296SNeil Armstrong return 0;
196d7940296SNeil Armstrong }
197d7940296SNeil Armstrong
reset_release_all(struct reset_ctl * reset_ctl,int count)1983b9d1bddSPatrice Chotard int reset_release_all(struct reset_ctl *reset_ctl, int count)
1993b9d1bddSPatrice Chotard {
2003b9d1bddSPatrice Chotard int i, ret;
2013b9d1bddSPatrice Chotard
2023b9d1bddSPatrice Chotard for (i = 0; i < count; i++) {
2033b9d1bddSPatrice Chotard debug("%s(reset_ctl[%d]=%p)\n", __func__, i, &reset_ctl[i]);
2043b9d1bddSPatrice Chotard
2053b9d1bddSPatrice Chotard /* check if reset has been previously requested */
2063b9d1bddSPatrice Chotard if (!reset_ctl[i].dev)
2073b9d1bddSPatrice Chotard continue;
2083b9d1bddSPatrice Chotard
2093b9d1bddSPatrice Chotard ret = reset_assert(&reset_ctl[i]);
2103b9d1bddSPatrice Chotard if (ret)
2113b9d1bddSPatrice Chotard return ret;
2123b9d1bddSPatrice Chotard
2133b9d1bddSPatrice Chotard ret = reset_free(&reset_ctl[i]);
2143b9d1bddSPatrice Chotard if (ret)
2153b9d1bddSPatrice Chotard return ret;
2163b9d1bddSPatrice Chotard }
2173b9d1bddSPatrice Chotard
2183b9d1bddSPatrice Chotard return 0;
2193b9d1bddSPatrice Chotard }
2203b9d1bddSPatrice Chotard
22189c1e2daSStephen Warren UCLASS_DRIVER(reset) = {
22289c1e2daSStephen Warren .id = UCLASS_RESET,
22389c1e2daSStephen Warren .name = "reset",
22489c1e2daSStephen Warren };
225