1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * System Control and Management Interface (SCMI) Reset Protocol 4 * 5 * Copyright (C) 2019-2022 ARM Ltd. 6 */ 7 8 #define pr_fmt(fmt) "SCMI Notifications RESET - " fmt 9 10 #include <linux/module.h> 11 #include <linux/scmi_protocol.h> 12 13 #include "protocols.h" 14 #include "notify.h" 15 16 /* Updated only after ALL the mandatory features for that version are merged */ 17 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 18 19 enum scmi_reset_protocol_cmd { 20 RESET_DOMAIN_ATTRIBUTES = 0x3, 21 RESET = 0x4, 22 RESET_NOTIFY = 0x5, 23 RESET_DOMAIN_NAME_GET = 0x6, 24 }; 25 26 #define NUM_RESET_DOMAIN_MASK 0xffff 27 #define RESET_NOTIFY_ENABLE BIT(0) 28 29 struct scmi_msg_resp_reset_domain_attributes { 30 __le32 attributes; 31 #define SUPPORTS_ASYNC_RESET(x) ((x) & BIT(31)) 32 #define SUPPORTS_NOTIFY_RESET(x) ((x) & BIT(30)) 33 #define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(29)) 34 __le32 latency; 35 u8 name[SCMI_SHORT_NAME_MAX_SIZE]; 36 }; 37 38 struct scmi_msg_reset_domain_reset { 39 __le32 domain_id; 40 __le32 flags; 41 #define AUTONOMOUS_RESET BIT(0) 42 #define EXPLICIT_RESET_ASSERT BIT(1) 43 #define ASYNCHRONOUS_RESET BIT(2) 44 __le32 reset_state; 45 #define ARCH_COLD_RESET 0 46 }; 47 48 struct scmi_msg_reset_notify { 49 __le32 id; 50 __le32 event_control; 51 #define RESET_TP_NOTIFY_ALL BIT(0) 52 }; 53 54 struct scmi_reset_issued_notify_payld { 55 __le32 agent_id; 56 __le32 domain_id; 57 __le32 reset_state; 58 }; 59 60 struct reset_dom_info { 61 bool async_reset; 62 bool reset_notify; 63 u32 latency_us; 64 char name[SCMI_MAX_STR_SIZE]; 65 }; 66 67 struct scmi_reset_info { 68 u32 version; 69 int num_domains; 70 struct reset_dom_info *dom_info; 71 }; 72 73 static int scmi_reset_attributes_get(const struct scmi_protocol_handle *ph, 74 struct scmi_reset_info *pi) 75 { 76 int ret; 77 struct scmi_xfer *t; 78 u32 attr; 79 80 ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 81 0, sizeof(attr), &t); 82 if (ret) 83 return ret; 84 85 ret = ph->xops->do_xfer(ph, t); 86 if (!ret) { 87 attr = get_unaligned_le32(t->rx.buf); 88 pi->num_domains = attr & NUM_RESET_DOMAIN_MASK; 89 } 90 91 ph->xops->xfer_put(ph, t); 92 return ret; 93 } 94 95 static int 96 scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph, 97 u32 domain, struct reset_dom_info *dom_info, 98 u32 version) 99 { 100 int ret; 101 u32 attributes; 102 struct scmi_xfer *t; 103 struct scmi_msg_resp_reset_domain_attributes *attr; 104 105 ret = ph->xops->xfer_get_init(ph, RESET_DOMAIN_ATTRIBUTES, 106 sizeof(domain), sizeof(*attr), &t); 107 if (ret) 108 return ret; 109 110 put_unaligned_le32(domain, t->tx.buf); 111 attr = t->rx.buf; 112 113 ret = ph->xops->do_xfer(ph, t); 114 if (!ret) { 115 attributes = le32_to_cpu(attr->attributes); 116 117 dom_info->async_reset = SUPPORTS_ASYNC_RESET(attributes); 118 dom_info->reset_notify = SUPPORTS_NOTIFY_RESET(attributes); 119 dom_info->latency_us = le32_to_cpu(attr->latency); 120 if (dom_info->latency_us == U32_MAX) 121 dom_info->latency_us = 0; 122 strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE); 123 } 124 125 ph->xops->xfer_put(ph, t); 126 127 /* 128 * If supported overwrite short name with the extended one; 129 * on error just carry on and use already provided short name. 130 */ 131 if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 && 132 SUPPORTS_EXTENDED_NAMES(attributes)) 133 ph->hops->extended_name_get(ph, RESET_DOMAIN_NAME_GET, domain, 134 NULL, dom_info->name, 135 SCMI_MAX_STR_SIZE); 136 137 return ret; 138 } 139 140 static int scmi_reset_num_domains_get(const struct scmi_protocol_handle *ph) 141 { 142 struct scmi_reset_info *pi = ph->get_priv(ph); 143 144 return pi->num_domains; 145 } 146 147 static const char * 148 scmi_reset_name_get(const struct scmi_protocol_handle *ph, u32 domain) 149 { 150 struct scmi_reset_info *pi = ph->get_priv(ph); 151 152 struct reset_dom_info *dom = pi->dom_info + domain; 153 154 return dom->name; 155 } 156 157 static int scmi_reset_latency_get(const struct scmi_protocol_handle *ph, 158 u32 domain) 159 { 160 struct scmi_reset_info *pi = ph->get_priv(ph); 161 struct reset_dom_info *dom = pi->dom_info + domain; 162 163 return dom->latency_us; 164 } 165 166 static int scmi_domain_reset(const struct scmi_protocol_handle *ph, u32 domain, 167 u32 flags, u32 state) 168 { 169 int ret; 170 struct scmi_xfer *t; 171 struct scmi_msg_reset_domain_reset *dom; 172 struct scmi_reset_info *pi = ph->get_priv(ph); 173 struct reset_dom_info *rdom; 174 175 if (domain >= pi->num_domains) 176 return -EINVAL; 177 178 rdom = pi->dom_info + domain; 179 if (rdom->async_reset && flags & AUTONOMOUS_RESET) 180 flags |= ASYNCHRONOUS_RESET; 181 182 ret = ph->xops->xfer_get_init(ph, RESET, sizeof(*dom), 0, &t); 183 if (ret) 184 return ret; 185 186 dom = t->tx.buf; 187 dom->domain_id = cpu_to_le32(domain); 188 dom->flags = cpu_to_le32(flags); 189 dom->reset_state = cpu_to_le32(state); 190 191 if (flags & ASYNCHRONOUS_RESET) 192 ret = ph->xops->do_xfer_with_response(ph, t); 193 else 194 ret = ph->xops->do_xfer(ph, t); 195 196 ph->xops->xfer_put(ph, t); 197 return ret; 198 } 199 200 static int scmi_reset_domain_reset(const struct scmi_protocol_handle *ph, 201 u32 domain) 202 { 203 return scmi_domain_reset(ph, domain, AUTONOMOUS_RESET, 204 ARCH_COLD_RESET); 205 } 206 207 static int 208 scmi_reset_domain_assert(const struct scmi_protocol_handle *ph, u32 domain) 209 { 210 return scmi_domain_reset(ph, domain, EXPLICIT_RESET_ASSERT, 211 ARCH_COLD_RESET); 212 } 213 214 static int 215 scmi_reset_domain_deassert(const struct scmi_protocol_handle *ph, u32 domain) 216 { 217 return scmi_domain_reset(ph, domain, 0, ARCH_COLD_RESET); 218 } 219 220 static const struct scmi_reset_proto_ops reset_proto_ops = { 221 .num_domains_get = scmi_reset_num_domains_get, 222 .name_get = scmi_reset_name_get, 223 .latency_get = scmi_reset_latency_get, 224 .reset = scmi_reset_domain_reset, 225 .assert = scmi_reset_domain_assert, 226 .deassert = scmi_reset_domain_deassert, 227 }; 228 229 static int scmi_reset_notify(const struct scmi_protocol_handle *ph, 230 u32 domain_id, bool enable) 231 { 232 int ret; 233 u32 evt_cntl = enable ? RESET_TP_NOTIFY_ALL : 0; 234 struct scmi_xfer *t; 235 struct scmi_msg_reset_notify *cfg; 236 237 ret = ph->xops->xfer_get_init(ph, RESET_NOTIFY, sizeof(*cfg), 0, &t); 238 if (ret) 239 return ret; 240 241 cfg = t->tx.buf; 242 cfg->id = cpu_to_le32(domain_id); 243 cfg->event_control = cpu_to_le32(evt_cntl); 244 245 ret = ph->xops->do_xfer(ph, t); 246 247 ph->xops->xfer_put(ph, t); 248 return ret; 249 } 250 251 static int scmi_reset_set_notify_enabled(const struct scmi_protocol_handle *ph, 252 u8 evt_id, u32 src_id, bool enable) 253 { 254 int ret; 255 256 ret = scmi_reset_notify(ph, src_id, enable); 257 if (ret) 258 pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n", 259 evt_id, src_id, ret); 260 261 return ret; 262 } 263 264 static void * 265 scmi_reset_fill_custom_report(const struct scmi_protocol_handle *ph, 266 u8 evt_id, ktime_t timestamp, 267 const void *payld, size_t payld_sz, 268 void *report, u32 *src_id) 269 { 270 const struct scmi_reset_issued_notify_payld *p = payld; 271 struct scmi_reset_issued_report *r = report; 272 273 if (evt_id != SCMI_EVENT_RESET_ISSUED || sizeof(*p) != payld_sz) 274 return NULL; 275 276 r->timestamp = timestamp; 277 r->agent_id = le32_to_cpu(p->agent_id); 278 r->domain_id = le32_to_cpu(p->domain_id); 279 r->reset_state = le32_to_cpu(p->reset_state); 280 *src_id = r->domain_id; 281 282 return r; 283 } 284 285 static int scmi_reset_get_num_sources(const struct scmi_protocol_handle *ph) 286 { 287 struct scmi_reset_info *pinfo = ph->get_priv(ph); 288 289 if (!pinfo) 290 return -EINVAL; 291 292 return pinfo->num_domains; 293 } 294 295 static const struct scmi_event reset_events[] = { 296 { 297 .id = SCMI_EVENT_RESET_ISSUED, 298 .max_payld_sz = sizeof(struct scmi_reset_issued_notify_payld), 299 .max_report_sz = sizeof(struct scmi_reset_issued_report), 300 }, 301 }; 302 303 static const struct scmi_event_ops reset_event_ops = { 304 .get_num_sources = scmi_reset_get_num_sources, 305 .set_notify_enabled = scmi_reset_set_notify_enabled, 306 .fill_custom_report = scmi_reset_fill_custom_report, 307 }; 308 309 static const struct scmi_protocol_events reset_protocol_events = { 310 .queue_sz = SCMI_PROTO_QUEUE_SZ, 311 .ops = &reset_event_ops, 312 .evts = reset_events, 313 .num_events = ARRAY_SIZE(reset_events), 314 }; 315 316 static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph) 317 { 318 int domain, ret; 319 u32 version; 320 struct scmi_reset_info *pinfo; 321 322 ret = ph->xops->version_get(ph, &version); 323 if (ret) 324 return ret; 325 326 dev_dbg(ph->dev, "Reset Version %d.%d\n", 327 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); 328 329 pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL); 330 if (!pinfo) 331 return -ENOMEM; 332 333 ret = scmi_reset_attributes_get(ph, pinfo); 334 if (ret) 335 return ret; 336 337 pinfo->dom_info = devm_kcalloc(ph->dev, pinfo->num_domains, 338 sizeof(*pinfo->dom_info), GFP_KERNEL); 339 if (!pinfo->dom_info) 340 return -ENOMEM; 341 342 for (domain = 0; domain < pinfo->num_domains; domain++) { 343 struct reset_dom_info *dom = pinfo->dom_info + domain; 344 345 scmi_reset_domain_attributes_get(ph, domain, dom, version); 346 } 347 348 pinfo->version = version; 349 return ph->set_priv(ph, pinfo, version); 350 } 351 352 static const struct scmi_protocol scmi_reset = { 353 .id = SCMI_PROTOCOL_RESET, 354 .owner = THIS_MODULE, 355 .instance_init = &scmi_reset_protocol_init, 356 .ops = &reset_proto_ops, 357 .events = &reset_protocol_events, 358 .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, 359 }; 360 361 DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(reset, scmi_reset) 362