1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * System Control and Management Interface (SCMI) Reset Protocol 4 * 5 * Copyright (C) 2019 ARM Ltd. 6 */ 7 8 #include "common.h" 9 10 enum scmi_reset_protocol_cmd { 11 RESET_DOMAIN_ATTRIBUTES = 0x3, 12 RESET = 0x4, 13 RESET_NOTIFY = 0x5, 14 }; 15 16 enum scmi_reset_protocol_notify { 17 RESET_ISSUED = 0x0, 18 }; 19 20 #define NUM_RESET_DOMAIN_MASK 0xffff 21 #define RESET_NOTIFY_ENABLE BIT(0) 22 23 struct scmi_msg_resp_reset_domain_attributes { 24 __le32 attributes; 25 #define SUPPORTS_ASYNC_RESET(x) ((x) & BIT(31)) 26 #define SUPPORTS_NOTIFY_RESET(x) ((x) & BIT(30)) 27 __le32 latency; 28 u8 name[SCMI_MAX_STR_SIZE]; 29 }; 30 31 struct scmi_msg_reset_domain_reset { 32 __le32 domain_id; 33 __le32 flags; 34 #define AUTONOMOUS_RESET BIT(0) 35 #define EXPLICIT_RESET_ASSERT BIT(1) 36 #define ASYNCHRONOUS_RESET BIT(2) 37 __le32 reset_state; 38 #define ARCH_RESET_TYPE BIT(31) 39 #define COLD_RESET_STATE BIT(0) 40 #define ARCH_COLD_RESET (ARCH_RESET_TYPE | COLD_RESET_STATE) 41 }; 42 43 struct reset_dom_info { 44 bool async_reset; 45 bool reset_notify; 46 u32 latency_us; 47 char name[SCMI_MAX_STR_SIZE]; 48 }; 49 50 struct scmi_reset_info { 51 int num_domains; 52 struct reset_dom_info *dom_info; 53 }; 54 55 static int scmi_reset_attributes_get(const struct scmi_handle *handle, 56 struct scmi_reset_info *pi) 57 { 58 int ret; 59 struct scmi_xfer *t; 60 u32 attr; 61 62 ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES, 63 SCMI_PROTOCOL_RESET, 0, sizeof(attr), &t); 64 if (ret) 65 return ret; 66 67 ret = scmi_do_xfer(handle, t); 68 if (!ret) { 69 attr = get_unaligned_le32(t->rx.buf); 70 pi->num_domains = attr & NUM_RESET_DOMAIN_MASK; 71 } 72 73 scmi_xfer_put(handle, t); 74 return ret; 75 } 76 77 static int 78 scmi_reset_domain_attributes_get(const struct scmi_handle *handle, u32 domain, 79 struct reset_dom_info *dom_info) 80 { 81 int ret; 82 struct scmi_xfer *t; 83 struct scmi_msg_resp_reset_domain_attributes *attr; 84 85 ret = scmi_xfer_get_init(handle, RESET_DOMAIN_ATTRIBUTES, 86 SCMI_PROTOCOL_RESET, sizeof(domain), 87 sizeof(*attr), &t); 88 if (ret) 89 return ret; 90 91 put_unaligned_le32(domain, t->tx.buf); 92 attr = t->rx.buf; 93 94 ret = scmi_do_xfer(handle, t); 95 if (!ret) { 96 u32 attributes = le32_to_cpu(attr->attributes); 97 98 dom_info->async_reset = SUPPORTS_ASYNC_RESET(attributes); 99 dom_info->reset_notify = SUPPORTS_NOTIFY_RESET(attributes); 100 dom_info->latency_us = le32_to_cpu(attr->latency); 101 if (dom_info->latency_us == U32_MAX) 102 dom_info->latency_us = 0; 103 strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); 104 } 105 106 scmi_xfer_put(handle, t); 107 return ret; 108 } 109 110 static int scmi_reset_num_domains_get(const struct scmi_handle *handle) 111 { 112 struct scmi_reset_info *pi = handle->reset_priv; 113 114 return pi->num_domains; 115 } 116 117 static char *scmi_reset_name_get(const struct scmi_handle *handle, u32 domain) 118 { 119 struct scmi_reset_info *pi = handle->reset_priv; 120 struct reset_dom_info *dom = pi->dom_info + domain; 121 122 return dom->name; 123 } 124 125 static int scmi_reset_latency_get(const struct scmi_handle *handle, u32 domain) 126 { 127 struct scmi_reset_info *pi = handle->reset_priv; 128 struct reset_dom_info *dom = pi->dom_info + domain; 129 130 return dom->latency_us; 131 } 132 133 static int scmi_domain_reset(const struct scmi_handle *handle, u32 domain, 134 u32 flags, u32 state) 135 { 136 int ret; 137 struct scmi_xfer *t; 138 struct scmi_msg_reset_domain_reset *dom; 139 struct scmi_reset_info *pi = handle->reset_priv; 140 struct reset_dom_info *rdom = pi->dom_info + domain; 141 142 if (rdom->async_reset) 143 flags |= ASYNCHRONOUS_RESET; 144 145 ret = scmi_xfer_get_init(handle, RESET, SCMI_PROTOCOL_RESET, 146 sizeof(*dom), 0, &t); 147 if (ret) 148 return ret; 149 150 dom = t->tx.buf; 151 dom->domain_id = cpu_to_le32(domain); 152 dom->flags = cpu_to_le32(flags); 153 dom->reset_state = cpu_to_le32(state); 154 155 if (rdom->async_reset) 156 ret = scmi_do_xfer_with_response(handle, t); 157 else 158 ret = scmi_do_xfer(handle, t); 159 160 scmi_xfer_put(handle, t); 161 return ret; 162 } 163 164 static int scmi_reset_domain_reset(const struct scmi_handle *handle, u32 domain) 165 { 166 return scmi_domain_reset(handle, domain, AUTONOMOUS_RESET, 167 ARCH_COLD_RESET); 168 } 169 170 static int 171 scmi_reset_domain_assert(const struct scmi_handle *handle, u32 domain) 172 { 173 return scmi_domain_reset(handle, domain, EXPLICIT_RESET_ASSERT, 174 ARCH_COLD_RESET); 175 } 176 177 static int 178 scmi_reset_domain_deassert(const struct scmi_handle *handle, u32 domain) 179 { 180 return scmi_domain_reset(handle, domain, 0, ARCH_COLD_RESET); 181 } 182 183 static struct scmi_reset_ops reset_ops = { 184 .num_domains_get = scmi_reset_num_domains_get, 185 .name_get = scmi_reset_name_get, 186 .latency_get = scmi_reset_latency_get, 187 .reset = scmi_reset_domain_reset, 188 .assert = scmi_reset_domain_assert, 189 .deassert = scmi_reset_domain_deassert, 190 }; 191 192 static int scmi_reset_protocol_init(struct scmi_handle *handle) 193 { 194 int domain; 195 u32 version; 196 struct scmi_reset_info *pinfo; 197 198 scmi_version_get(handle, SCMI_PROTOCOL_RESET, &version); 199 200 dev_dbg(handle->dev, "Reset Version %d.%d\n", 201 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); 202 203 pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL); 204 if (!pinfo) 205 return -ENOMEM; 206 207 scmi_reset_attributes_get(handle, pinfo); 208 209 pinfo->dom_info = devm_kcalloc(handle->dev, pinfo->num_domains, 210 sizeof(*pinfo->dom_info), GFP_KERNEL); 211 if (!pinfo->dom_info) 212 return -ENOMEM; 213 214 for (domain = 0; domain < pinfo->num_domains; domain++) { 215 struct reset_dom_info *dom = pinfo->dom_info + domain; 216 217 scmi_reset_domain_attributes_get(handle, domain, dom); 218 } 219 220 handle->reset_ops = &reset_ops; 221 handle->reset_priv = pinfo; 222 223 return 0; 224 } 225 226 static int __init scmi_reset_init(void) 227 { 228 return scmi_protocol_register(SCMI_PROTOCOL_RESET, 229 &scmi_reset_protocol_init); 230 } 231 subsys_initcall(scmi_reset_init); 232