linux/drivers/firmware/arm_scmi/reset.c
<<
>>
Prefs
   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
  10enum scmi_reset_protocol_cmd {
  11        RESET_DOMAIN_ATTRIBUTES = 0x3,
  12        RESET = 0x4,
  13        RESET_NOTIFY = 0x5,
  14};
  15
  16enum 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
  23struct 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
  31struct 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
  43struct reset_dom_info {
  44        bool async_reset;
  45        bool reset_notify;
  46        u32 latency_us;
  47        char name[SCMI_MAX_STR_SIZE];
  48};
  49
  50struct scmi_reset_info {
  51        int num_domains;
  52        struct reset_dom_info *dom_info;
  53};
  54
  55static 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
  77static int
  78scmi_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
 110static 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
 117static 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
 125static 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
 133static 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
 164static 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
 170static int
 171scmi_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
 177static int
 178scmi_reset_domain_deassert(const struct scmi_handle *handle, u32 domain)
 179{
 180        return scmi_domain_reset(handle, domain, 0, ARCH_COLD_RESET);
 181}
 182
 183static 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
 192static 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
 226static int __init scmi_reset_init(void)
 227{
 228        return scmi_protocol_register(SCMI_PROTOCOL_RESET,
 229                                      &scmi_reset_protocol_init);
 230}
 231subsys_initcall(scmi_reset_init);
 232