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
130
131
132
133
134
|
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-11-21 GuEe-GUI first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#define DBG_TAG "pm-domain.scmi"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
struct scmi_pm_domain_proxy;
struct scmi_pm_domain
{
struct rt_dm_power_domain parent;
rt_uint32_t domain;
struct scmi_pm_domain_proxy *proxy;
};
#define raw_to_scmi_pm_domain(raw) rt_container_of(raw, struct scmi_pm_domain, parent)
struct scmi_pm_domain_proxy
{
struct rt_dm_power_domain_proxy parent;
struct rt_scmi_device *sdev;
rt_uint32_t num_domains;
struct scmi_pm_domain domains[];
};
#define raw_to_scmi_pm_domain_proxy(raw) rt_container_of(raw, struct scmi_pm_domain_proxy, parent)
static rt_err_t scmi_pm_domain_power(struct scmi_pm_domain *scmi_pd, rt_bool_t power_on)
{
struct scmi_power_state_set_in in =
{
.flags = rt_cpu_to_le32(0),
.domain = rt_cpu_to_le32(scmi_pd->domain),
.state = rt_cpu_to_le32(power_on ? SCMI_POWER_STATE_GENERIC_ON : SCMI_POWER_STATE_GENERIC_OFF),
};
struct scmi_power_state_set_out out;
struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_POWER_STATE_SET, &in, &out);
return rt_scmi_process_msg(scmi_pd->proxy->sdev, &msg);
}
static rt_err_t scmi_pd_power_on(struct rt_dm_power_domain *domain)
{
return scmi_pm_domain_power(raw_to_scmi_pm_domain(domain), RT_TRUE);
}
static rt_err_t scmi_pd_power_off(struct rt_dm_power_domain *domain)
{
return scmi_pm_domain_power(raw_to_scmi_pm_domain(domain), RT_FALSE);
}
static struct rt_dm_power_domain *scmi_pm_domain_proxy_ofw_parse(
struct rt_dm_power_domain_proxy *proxy, struct rt_ofw_cell_args *args)
{
struct scmi_pm_domain_proxy *scmi_proxy = raw_to_scmi_pm_domain_proxy(proxy);
return &scmi_proxy->domains[args->args[0]].parent;
}
static rt_err_t scmi_pm_domain_probe(struct rt_scmi_device *sdev)
{
rt_err_t err;
rt_uint32_t num_domains;
struct scmi_pm_domain *scmi_pds;
struct scmi_pm_domain_proxy *scmi_proxy;
struct scmi_power_attributes attr = {};
struct rt_scmi_msg msg = RT_SCMI_MSG_OUT(SCMI_COM_MSG_ATTRIBUTES, &attr);
if ((err = rt_scmi_process_msg(sdev, &msg)))
{
return err;
}
num_domains = rt_le16_to_cpu(attr.num_domains);
scmi_proxy = rt_calloc(1, sizeof(*scmi_proxy) + sizeof(*scmi_pds) * num_domains);
if (!scmi_proxy)
{
return -RT_ENOMEM;
}
scmi_proxy->sdev = sdev;
scmi_proxy->num_domains = num_domains;
scmi_pds = scmi_proxy->domains;
for (int i = 0; i < num_domains; ++i, ++scmi_pds)
{
struct rt_dm_power_domain *domain = &scmi_pds->parent;
domain->power_off = scmi_pd_power_off;
domain->power_on = scmi_pd_power_on;
scmi_pds->domain = i;
scmi_pds->proxy = scmi_proxy;
rt_dm_power_domain_register(domain);
}
scmi_proxy->parent.ofw_parse = scmi_pm_domain_proxy_ofw_parse;
rt_dm_power_domain_proxy_ofw_bind(&scmi_proxy->parent, sdev->parent.ofw_node);
return RT_EOK;
}
static const struct rt_scmi_device_id scmi_pm_domain_ids[] =
{
{ SCMI_PROTOCOL_ID_POWER, "genpd" },
{ /* sentinel */ },
};
static struct rt_scmi_driver scmi_pm_domain_driver =
{
.name = "pm-domain-scmi",
.ids = scmi_pm_domain_ids,
.probe = scmi_pm_domain_probe,
};
RT_SCMI_DRIVER_EXPORT(scmi_pm_domain_driver);
|