xref: /rk3399_rockchip-uboot/drivers/reset/reset-uclass.c (revision 1a4f6af8bfd44c8ae6e87a81ff125eed47042cc5)
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