1 // SPDX-License-Identifier: (GPL-2.0+ OR MIT) 2 /* 3 * Copyright (C) 2018 Amarula Solutions. 4 * Author: Jagan Teki <jagan@amarulasolutions.com> 5 */ 6 7 #include <common.h> 8 #include <dm.h> 9 #include <errno.h> 10 #include <reset-uclass.h> 11 #include <asm/io.h> 12 #include <dm/lists.h> 13 #include <linux/log2.h> 14 #include <asm/arch/ccu.h> 15 16 struct sunxi_reset_priv { 17 void *base; 18 ulong count; 19 const struct ccu_desc *desc; 20 }; 21 22 static const struct ccu_reset *priv_to_reset(struct sunxi_reset_priv *priv, 23 unsigned long id) 24 { 25 return &priv->desc->resets[id]; 26 } 27 28 static int sunxi_reset_request(struct reset_ctl *reset_ctl) 29 { 30 struct sunxi_reset_priv *priv = dev_get_priv(reset_ctl->dev); 31 32 debug("%s: (RST#%ld)\n", __func__, reset_ctl->id); 33 34 if (reset_ctl->id >= priv->count) 35 return -EINVAL; 36 37 return 0; 38 } 39 40 static int sunxi_reset_free(struct reset_ctl *reset_ctl) 41 { 42 debug("%s: (RST#%ld)\n", __func__, reset_ctl->id); 43 44 return 0; 45 } 46 47 static int sunxi_set_reset(struct reset_ctl *reset_ctl, bool on) 48 { 49 struct sunxi_reset_priv *priv = dev_get_priv(reset_ctl->dev); 50 const struct ccu_reset *reset = priv_to_reset(priv, reset_ctl->id); 51 u32 reg; 52 53 if (!(reset->flags & CCU_RST_F_IS_VALID)) { 54 printf("%s: (RST#%ld) unhandled\n", __func__, reset_ctl->id); 55 return 0; 56 } 57 58 debug("%s: (RST#%ld) off#0x%x, BIT(%d)\n", __func__, 59 reset_ctl->id, reset->off, ilog2(reset->bit)); 60 61 reg = readl(priv->base + reset->off); 62 if (on) 63 reg |= reset->bit; 64 else 65 reg &= ~reset->bit; 66 67 writel(reg, priv->base + reset->off); 68 69 return 0; 70 } 71 72 static int sunxi_reset_assert(struct reset_ctl *reset_ctl) 73 { 74 return sunxi_set_reset(reset_ctl, false); 75 } 76 77 static int sunxi_reset_deassert(struct reset_ctl *reset_ctl) 78 { 79 return sunxi_set_reset(reset_ctl, true); 80 } 81 82 struct reset_ops sunxi_reset_ops = { 83 .request = sunxi_reset_request, 84 .free = sunxi_reset_free, 85 .rst_assert = sunxi_reset_assert, 86 .rst_deassert = sunxi_reset_deassert, 87 }; 88 89 static int sunxi_reset_probe(struct udevice *dev) 90 { 91 struct sunxi_reset_priv *priv = dev_get_priv(dev); 92 93 priv->base = dev_read_addr_ptr(dev); 94 95 return 0; 96 } 97 98 int sunxi_reset_bind(struct udevice *dev, ulong count) 99 { 100 struct udevice *rst_dev; 101 struct sunxi_reset_priv *priv; 102 int ret; 103 104 ret = device_bind_driver_to_node(dev, "sunxi_reset", "reset", 105 dev_ofnode(dev), &rst_dev); 106 if (ret) { 107 debug("failed to bind sunxi_reset driver (ret=%d)\n", ret); 108 return ret; 109 } 110 priv = malloc(sizeof(struct sunxi_reset_priv)); 111 priv->count = count; 112 priv->desc = (const struct ccu_desc *)dev_get_driver_data(dev); 113 rst_dev->priv = priv; 114 115 return 0; 116 } 117 118 U_BOOT_DRIVER(sunxi_reset) = { 119 .name = "sunxi_reset", 120 .id = UCLASS_RESET, 121 .ops = &sunxi_reset_ops, 122 .probe = sunxi_reset_probe, 123 .priv_auto_alloc_size = sizeof(struct sunxi_reset_priv), 124 }; 125