1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2022 StarFive Technology Co., Ltd. 4 * Author: Yanhong Wang <yanhong.wang@starfivetech.com> 5 * 6 */ 7 8#include <dm.h> 9#include <dm/ofnode.h> 10#include <dt-bindings/reset/starfive,jh7110-crg.h> 11#include <errno.h> 12#include <linux/iopoll.h> 13#include <reset-uclass.h> 14 15struct jh7110_reset_priv { 16 void __iomem *reg; 17 u32 assert; 18 u32 status; 19 u32 resets; 20}; 21 22struct reset_info { 23 const char *compat; 24 const u32 nr_resets; 25 const u32 assert_offset; 26 const u32 status_offset; 27}; 28 29static const struct reset_info jh7110_rst_info[] = { 30 { 31 .compat = "starfive,jh7110-syscrg", 32 .nr_resets = JH7110_SYSRST_END, 33 .assert_offset = 0x2F8, 34 .status_offset = 0x308, 35 }, 36 { 37 .compat = "starfive,jh7110-aoncrg", 38 .nr_resets = JH7110_AONRST_END, 39 .assert_offset = 0x38, 40 .status_offset = 0x3C, 41 }, 42 { 43 .compat = "starfive,jh7110-stgcrg", 44 .nr_resets = JH7110_STGRST_END, 45 .assert_offset = 0x74, 46 .status_offset = 0x78, 47 } 48}; 49 50static const struct reset_info *jh7110_reset_get_cfg(const char *compat) 51{ 52 int i; 53 54 for (i = 0; i < ARRAY_SIZE(jh7110_rst_info); i++) 55 if (!strcmp(compat, jh7110_rst_info[i].compat)) 56 return &jh7110_rst_info[i]; 57 58 return NULL; 59} 60 61static int jh7110_reset_trigger(struct jh7110_reset_priv *priv, 62 unsigned long id, bool assert) 63{ 64 ulong group; 65 u32 mask, value, done = 0; 66 ulong addr; 67 68 group = id / 32; 69 mask = BIT(id % 32); 70 71 if (!assert) 72 done ^= mask; 73 74 addr = (ulong)priv->reg + priv->assert + group * sizeof(u32); 75 value = readl((ulong *)addr); 76 77 if (assert) 78 value |= mask; 79 else 80 value &= ~mask; 81 82 writel(value, (ulong *)addr); 83 addr = (ulong)priv->reg + priv->status + group * sizeof(u32); 84 85 return readl_poll_timeout((ulong *)addr, value, 86 (value & mask) == done, 1000); 87} 88 89static int jh7110_reset_assert(struct reset_ctl *rst) 90{ 91 struct jh7110_reset_priv *priv = dev_get_priv(rst->dev); 92 93 jh7110_reset_trigger(priv, rst->id, true); 94 95 return 0; 96} 97 98static int jh7110_reset_deassert(struct reset_ctl *rst) 99{ 100 struct jh7110_reset_priv *priv = dev_get_priv(rst->dev); 101 102 jh7110_reset_trigger(priv, rst->id, false); 103 104 return 0; 105} 106 107static int jh7110_reset_free(struct reset_ctl *rst) 108{ 109 return 0; 110} 111 112static int jh7110_reset_request(struct reset_ctl *rst) 113{ 114 struct jh7110_reset_priv *priv = dev_get_priv(rst->dev); 115 116 if (rst->id >= priv->resets) 117 return -EINVAL; 118 119 return 0; 120} 121 122static int jh7110_reset_probe(struct udevice *dev) 123{ 124 struct jh7110_reset_priv *priv = dev_get_priv(dev); 125 const struct reset_info *cfg; 126 const char *compat; 127 128 compat = ofnode_get_property(dev_ofnode(dev), "compatible", NULL); 129 if (!compat) 130 return -EINVAL; 131 132 cfg = jh7110_reset_get_cfg(compat); 133 if (!cfg) 134 return -EINVAL; 135 136 priv->assert = cfg->assert_offset; 137 priv->status = cfg->status_offset; 138 priv->resets = cfg->nr_resets; 139 priv->reg = (void __iomem *)dev_read_addr_index(dev, 0); 140 141 return 0; 142} 143 144const struct reset_ops jh7110_reset_reset_ops = { 145 .rfree = jh7110_reset_free, 146 .request = jh7110_reset_request, 147 .rst_assert = jh7110_reset_assert, 148 .rst_deassert = jh7110_reset_deassert, 149}; 150 151U_BOOT_DRIVER(jh7110_reset) = { 152 .name = "jh7110_reset", 153 .id = UCLASS_RESET, 154 .ops = &jh7110_reset_reset_ops, 155 .probe = jh7110_reset_probe, 156 .priv_auto = sizeof(struct jh7110_reset_priv), 157}; 158