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 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 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 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 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 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 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 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 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 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 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 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 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