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#define pr_fmt(fmt) "SCMI Notifications RESET - " fmt 9 10#include <linux/scmi_protocol.h> 11 12#include "common.h" 13#include "notify.h" 14 15enum scmi_reset_protocol_cmd { 16 RESET_DOMAIN_ATTRIBUTES = 0x3, 17 RESET = 0x4, 18 RESET_NOTIFY = 0x5, 19}; 20 21#define NUM_RESET_DOMAIN_MASK 0xffff 22#define RESET_NOTIFY_ENABLE BIT(0) 23 24struct scmi_msg_resp_reset_domain_attributes { 25 __le32 attributes; 26#define SUPPORTS_ASYNC_RESET(x) ((x) & BIT(31)) 27#define SUPPORTS_NOTIFY_RESET(x) ((x) & BIT(30)) 28 __le32 latency; 29 u8 name[SCMI_MAX_STR_SIZE]; 30}; 31 32struct scmi_msg_reset_domain_reset { 33 __le32 domain_id; 34 __le32 flags; 35#define AUTONOMOUS_RESET BIT(0) 36#define EXPLICIT_RESET_ASSERT BIT(1) 37#define ASYNCHRONOUS_RESET BIT(2) 38 __le32 reset_state; 39#define ARCH_COLD_RESET 0 40}; 41 42struct scmi_msg_reset_notify { 43 __le32 id; 44 __le32 event_control; 45#define RESET_TP_NOTIFY_ALL BIT(0) 46}; 47 48struct scmi_reset_issued_notify_payld { 49 __le32 agent_id; 50 __le32 domain_id; 51 __le32 reset_state; 52}; 53 54struct reset_dom_info { 55 bool async_reset; 56 bool reset_notify; 57 u32 latency_us; 58 char name[SCMI_MAX_STR_SIZE]; 59}; 60 61struct scmi_reset_info { 62 u32 version; 63 int num_domains; 64 struct reset_dom_info *dom_info; 65}; 66 67static int scmi_reset_attributes_get(const struct scmi_handle *handle, 68 struct scmi_reset_info *pi) 69{ 70 int ret; 71 struct scmi_xfer *t; 72 u32 attr; 73 74 ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES, 75 SCMI_PROTOCOL_RESET, 0, sizeof(attr), &t); 76 if (ret) 77 return ret; 78 79 ret = scmi_do_xfer(handle, t); 80 if (!ret) { 81 attr = get_unaligned_le32(t->rx.buf); 82 pi->num_domains = attr & NUM_RESET_DOMAIN_MASK; 83 } 84 85 scmi_xfer_put(handle, t); 86 return ret; 87} 88 89static int 90scmi_reset_domain_attributes_get(const struct scmi_handle *handle, u32 domain, 91 struct reset_dom_info *dom_info) 92{ 93 int ret; 94 struct scmi_xfer *t; 95 struct scmi_msg_resp_reset_domain_attributes *attr; 96 97 ret = scmi_xfer_get_init(handle, RESET_DOMAIN_ATTRIBUTES, 98 SCMI_PROTOCOL_RESET, sizeof(domain), 99 sizeof(*attr), &t); 100 if (ret) 101 return ret; 102 103 put_unaligned_le32(domain, t->tx.buf); 104 attr = t->rx.buf; 105 106 ret = scmi_do_xfer(handle, t); 107 if (!ret) { 108 u32 attributes = le32_to_cpu(attr->attributes); 109 110 dom_info->async_reset = SUPPORTS_ASYNC_RESET(attributes); 111 dom_info->reset_notify = SUPPORTS_NOTIFY_RESET(attributes); 112 dom_info->latency_us = le32_to_cpu(attr->latency); 113 if (dom_info->latency_us == U32_MAX) 114 dom_info->latency_us = 0; 115 strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); 116 } 117 118 scmi_xfer_put(handle, t); 119 return ret; 120} 121 122static int scmi_reset_num_domains_get(const struct scmi_handle *handle) 123{ 124 struct scmi_reset_info *pi = handle->reset_priv; 125 126 return pi->num_domains; 127} 128 129static char *scmi_reset_name_get(const struct scmi_handle *handle, u32 domain) 130{ 131 struct scmi_reset_info *pi = handle->reset_priv; 132 struct reset_dom_info *dom = pi->dom_info + domain; 133 134 return dom->name; 135} 136 137static int scmi_reset_latency_get(const struct scmi_handle *handle, u32 domain) 138{ 139 struct scmi_reset_info *pi = handle->reset_priv; 140 struct reset_dom_info *dom = pi->dom_info + domain; 141 142 return dom->latency_us; 143} 144 145static int scmi_domain_reset(const struct scmi_handle *handle, u32 domain, 146 u32 flags, u32 state) 147{ 148 int ret; 149 struct scmi_xfer *t; 150 struct scmi_msg_reset_domain_reset *dom; 151 struct scmi_reset_info *pi = handle->reset_priv; 152 struct reset_dom_info *rdom; 153 154 if (domain >= pi->num_domains) 155 return -EINVAL; 156 157 rdom = pi->dom_info + domain; 158 if (rdom->async_reset) 159 flags |= ASYNCHRONOUS_RESET; 160 161 ret = scmi_xfer_get_init(handle, RESET, SCMI_PROTOCOL_RESET, 162 sizeof(*dom), 0, &t); 163 if (ret) 164 return ret; 165 166 dom = t->tx.buf; 167 dom->domain_id = cpu_to_le32(domain); 168 dom->flags = cpu_to_le32(flags); 169 dom->reset_state = cpu_to_le32(state); 170 171 if (rdom->async_reset) 172 ret = scmi_do_xfer_with_response(handle, t); 173 else 174 ret = scmi_do_xfer(handle, t); 175 176 scmi_xfer_put(handle, t); 177 return ret; 178} 179 180static int scmi_reset_domain_reset(const struct scmi_handle *handle, u32 domain) 181{ 182 return scmi_domain_reset(handle, domain, AUTONOMOUS_RESET, 183 ARCH_COLD_RESET); 184} 185 186static int 187scmi_reset_domain_assert(const struct scmi_handle *handle, u32 domain) 188{ 189 return scmi_domain_reset(handle, domain, EXPLICIT_RESET_ASSERT, 190 ARCH_COLD_RESET); 191} 192 193static int 194scmi_reset_domain_deassert(const struct scmi_handle *handle, u32 domain) 195{ 196 return scmi_domain_reset(handle, domain, 0, ARCH_COLD_RESET); 197} 198 199static const struct scmi_reset_ops reset_ops = { 200 .num_domains_get = scmi_reset_num_domains_get, 201 .name_get = scmi_reset_name_get, 202 .latency_get = scmi_reset_latency_get, 203 .reset = scmi_reset_domain_reset, 204 .assert = scmi_reset_domain_assert, 205 .deassert = scmi_reset_domain_deassert, 206}; 207 208static int scmi_reset_notify(const struct scmi_handle *handle, u32 domain_id, 209 bool enable) 210{ 211 int ret; 212 u32 evt_cntl = enable ? RESET_TP_NOTIFY_ALL : 0; 213 struct scmi_xfer *t; 214 struct scmi_msg_reset_notify *cfg; 215 216 ret = scmi_xfer_get_init(handle, RESET_NOTIFY, 217 SCMI_PROTOCOL_RESET, sizeof(*cfg), 0, &t); 218 if (ret) 219 return ret; 220 221 cfg = t->tx.buf; 222 cfg->id = cpu_to_le32(domain_id); 223 cfg->event_control = cpu_to_le32(evt_cntl); 224 225 ret = scmi_do_xfer(handle, t); 226 227 scmi_xfer_put(handle, t); 228 return ret; 229} 230 231static int scmi_reset_set_notify_enabled(const struct scmi_handle *handle, 232 u8 evt_id, u32 src_id, bool enable) 233{ 234 int ret; 235 236 ret = scmi_reset_notify(handle, src_id, enable); 237 if (ret) 238 pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n", 239 evt_id, src_id, ret); 240 241 return ret; 242} 243 244static void *scmi_reset_fill_custom_report(const struct scmi_handle *handle, 245 u8 evt_id, ktime_t timestamp, 246 const void *payld, size_t payld_sz, 247 void *report, u32 *src_id) 248{ 249 const struct scmi_reset_issued_notify_payld *p = payld; 250 struct scmi_reset_issued_report *r = report; 251 252 if (evt_id != SCMI_EVENT_RESET_ISSUED || sizeof(*p) != payld_sz) 253 return NULL; 254 255 r->timestamp = timestamp; 256 r->agent_id = le32_to_cpu(p->agent_id); 257 r->domain_id = le32_to_cpu(p->domain_id); 258 r->reset_state = le32_to_cpu(p->reset_state); 259 *src_id = r->domain_id; 260 261 return r; 262} 263 264static const struct scmi_event reset_events[] = { 265 { 266 .id = SCMI_EVENT_RESET_ISSUED, 267 .max_payld_sz = sizeof(struct scmi_reset_issued_notify_payld), 268 .max_report_sz = sizeof(struct scmi_reset_issued_report), 269 }, 270}; 271 272static const struct scmi_event_ops reset_event_ops = { 273 .set_notify_enabled = scmi_reset_set_notify_enabled, 274 .fill_custom_report = scmi_reset_fill_custom_report, 275}; 276 277static int scmi_reset_protocol_init(struct scmi_handle *handle) 278{ 279 int domain; 280 u32 version; 281 struct scmi_reset_info *pinfo; 282 283 scmi_version_get(handle, SCMI_PROTOCOL_RESET, &version); 284 285 dev_dbg(handle->dev, "Reset Version %d.%d\n", 286 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); 287 288 pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL); 289 if (!pinfo) 290 return -ENOMEM; 291 292 scmi_reset_attributes_get(handle, pinfo); 293 294 pinfo->dom_info = devm_kcalloc(handle->dev, pinfo->num_domains, 295 sizeof(*pinfo->dom_info), GFP_KERNEL); 296 if (!pinfo->dom_info) 297 return -ENOMEM; 298 299 for (domain = 0; domain < pinfo->num_domains; domain++) { 300 struct reset_dom_info *dom = pinfo->dom_info + domain; 301 302 scmi_reset_domain_attributes_get(handle, domain, dom); 303 } 304 305 scmi_register_protocol_events(handle, 306 SCMI_PROTOCOL_RESET, SCMI_PROTO_QUEUE_SZ, 307 &reset_event_ops, reset_events, 308 ARRAY_SIZE(reset_events), 309 pinfo->num_domains); 310 311 pinfo->version = version; 312 handle->reset_ops = &reset_ops; 313 handle->reset_priv = pinfo; 314 315 return 0; 316} 317 318DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_RESET, reset) 319