summaryrefslogtreecommitdiff
path: root/components/drivers/reset/reset-scmi.c
blob: d10d296d86fed077aeccf2bddfc100f6987f9c9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * Copyright (c) 2006-2022, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-11-26     GuEe-GUI     first version
 */

#include <rtthread.h>
#include <rtdevice.h>

#define DBG_TAG "reset.scmi"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

struct scmi_reset
{
    struct rt_reset_controller parent;

    struct rt_scmi_device *sdev;
};

#define raw_to_scmi_reset(raw) rt_container_of(raw, struct scmi_reset, parent)

static rt_err_t scmi_reset_do(struct scmi_reset *srst, int domain,
        rt_uint32_t flags, rt_uint32_t state)
{
    struct scmi_reset_in in =
    {
        .domain_id = rt_cpu_to_le32(domain),
        .flags = rt_cpu_to_le32(flags),
        .reset_state = rt_cpu_to_le32(state),
    };
    struct scmi_reset_out out;
    struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_RESET_RESET, &in, &out);

    return rt_scmi_process_msg(srst->sdev, &msg);
}

static rt_err_t scmi_reset_reset(struct rt_reset_control *rstc)
{
    struct scmi_reset *srst = raw_to_scmi_reset(rstc);

    return scmi_reset_do(srst, rstc->id, SCMI_RESET_FLAG_RESET, SCMI_ARCH_COLD_RESET);
}

static rt_err_t scmi_reset_assert(struct rt_reset_control *rstc)
{
    struct scmi_reset *srst = raw_to_scmi_reset(rstc);

    return scmi_reset_do(srst, rstc->id, SCMI_RESET_FLAG_ASSERT, SCMI_ARCH_COLD_RESET);
}

static rt_err_t scmi_reset_deassert(struct rt_reset_control *rstc)
{
    struct scmi_reset *srst = raw_to_scmi_reset(rstc);

    return scmi_reset_do(srst, rstc->id, 0, SCMI_ARCH_COLD_RESET);
}

static rt_err_t scmi_reset_ofw_parse(struct rt_reset_control *rstc,
        struct rt_ofw_cell_args *args)
{
    rt_err_t err;
    struct scmi_reset *srst = raw_to_scmi_reset(rstc);
    struct scmi_reset_attr_in in =
    {
        .domain_id = rt_cpu_to_le32(rstc->id),
    };
    struct scmi_reset_attr_out out;
    struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_RESET_DOMAIN_ATTRIBUTES, &in, &out);

    if ((err = rt_scmi_process_msg(srst->sdev, &msg)))
    {
        return err;
    }

    return rt_le32_to_cpu(out.status) == 0 ? RT_EOK : -RT_ERROR;
}

static const struct rt_reset_control_ops scmi_reset_ops =
{
    .ofw_parse = scmi_reset_ofw_parse,
    .reset = scmi_reset_reset,
    .assert = scmi_reset_assert,
    .deassert = scmi_reset_deassert,
};

static rt_err_t scmi_reset_probe(struct rt_scmi_device *sdev)
{
    rt_err_t err;
    struct rt_reset_controller *rstcer;
    struct scmi_reset *srst = rt_calloc(1, sizeof(*srst));

    if (!srst)
    {
        return -RT_ENOMEM;
    }

    rstcer = &srst->parent;

    rstcer->priv = srst;
    rstcer->ofw_node = sdev->parent.ofw_node;
    rstcer->ops = &scmi_reset_ops;

    if ((err = rt_reset_controller_register(&srst->parent)))
    {
        rt_free(srst);
    }

    return err;
}

static const struct rt_scmi_device_id scmi_reset_ids[] =
{
    { SCMI_PROTOCOL_ID_RESET, "reset" },
    { /* sentinel */ },
};

static struct rt_scmi_driver scmi_reset_driver =
{
    .name = "reset-scmi",
    .ids = scmi_reset_ids,

    .probe = scmi_reset_probe,
};
RT_SCMI_DRIVER_EXPORT(scmi_reset_driver);