blob: f70f8e024239528eb627d9202f6a31516079ad91 [file] [log] [blame]
Alexey Romanovcc2592a2023-05-31 12:31:56 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2023 SberDevices, Inc.
4 * Author: Alexey Romanov <avromanov@sberdevices.ru>
5 */
6
7#include <dm.h>
8#include <asm/arch/sm.h>
9#include <power-domain.h>
10#include <power-domain-uclass.h>
11#include <dt-bindings/power/meson-a1-power.h>
12
13struct meson_secure_pwrc_domain_desc {
14 char *name;
15 size_t index;
16};
17
18struct meson_secure_pwrc_domain_data {
19 unsigned int count;
20 struct meson_secure_pwrc_domain_desc *domains;
21};
22
23struct meson_secure_pwrc_priv {
24 const struct meson_secure_pwrc_domain_data *data;
25};
26
27static int meson_secure_pwrc_on(struct power_domain *power_domain)
28{
29 struct meson_secure_pwrc_priv *priv = dev_get_priv(power_domain->dev);
30 struct meson_secure_pwrc_domain_desc *pwrc_domain;
31 int err;
32
33 pwrc_domain = &priv->data->domains[power_domain->id];
34
35 err = meson_sm_pwrdm_on(pwrc_domain->index);
36 if (err) {
37 pr_err("meson_sm_pwrdm_on() failed (%d)\n", err);
38 return err;
39 }
40
41 pr_debug("enable %s power domain\n", pwrc_domain->name);
42
43 return 0;
44}
45
46static int meson_secure_pwrc_off(struct power_domain *power_domain)
47{
48 struct meson_secure_pwrc_priv *priv = dev_get_priv(power_domain->dev);
49 struct meson_secure_pwrc_domain_desc *pwrc_domain;
50 int err;
51
52 pwrc_domain = &priv->data->domains[power_domain->id];
53
54 err = meson_sm_pwrdm_off(pwrc_domain->index);
55 if (err) {
56 pr_err("meson_sm_pwrdm_off() failed (%d)\n", err);
57 return err;
58 }
59
60 pr_debug("disable %s power domain\n", pwrc_domain->name);
61
62 return 0;
63}
64
65static int meson_secure_pwrc_of_xlate(struct power_domain *power_domain,
66 struct ofnode_phandle_args *args)
67{
68 struct meson_secure_pwrc_priv *priv = dev_get_priv(power_domain->dev);
69 struct meson_secure_pwrc_domain_desc *pwrc_domain;
70
71 if (args->args_count < 1) {
72 pr_err("invalid args count: %d\n", args->args_count);
73 return -EINVAL;
74 }
75
76 power_domain->id = args->args[0];
77
78 if (power_domain->id >= priv->data->count) {
79 pr_err("domain with ID=%lu is invalid\n", power_domain->id);
80 return -EINVAL;
81 }
82
83 pwrc_domain = &priv->data->domains[power_domain->id];
84
85 if (!pwrc_domain->name) {
86 pr_err("domain with ID=%lu is invalid\n", power_domain->id);
87 return -EINVAL;
88 }
89
90 return 0;
91}
92
93#define SEC_PD(__name) \
94[PWRC_##__name##_ID] = \
95{ \
96 .name = #__name, \
97 .index = PWRC_##__name##_ID, \
98}
99
100static struct meson_secure_pwrc_domain_desc a1_pwrc_domains[] = {
101 SEC_PD(DSPA),
102 SEC_PD(DSPB),
103 SEC_PD(UART),
104 SEC_PD(DMC),
105 SEC_PD(I2C),
106 SEC_PD(PSRAM),
107 SEC_PD(ACODEC),
108 SEC_PD(AUDIO),
109 SEC_PD(OTP),
110 SEC_PD(DMA),
111 SEC_PD(SD_EMMC),
112 SEC_PD(RAMA),
113 SEC_PD(RAMB),
114 SEC_PD(IR),
115 SEC_PD(SPICC),
116 SEC_PD(SPIFC),
117 SEC_PD(USB),
118 SEC_PD(NIC),
119 SEC_PD(PDMIN),
120 SEC_PD(RSA),
121};
122
123struct power_domain_ops meson_secure_pwrc_ops = {
124 .on = meson_secure_pwrc_on,
125 .off = meson_secure_pwrc_off,
126 .of_xlate = meson_secure_pwrc_of_xlate,
127};
128
129static struct meson_secure_pwrc_domain_data meson_secure_a1_pwrc_data = {
130 .count = ARRAY_SIZE(a1_pwrc_domains),
131 .domains = a1_pwrc_domains,
132};
133
134static const struct udevice_id meson_secure_pwrc_ids[] = {
135 {
136 .compatible = "amlogic,meson-a1-pwrc",
137 .data = (unsigned long)&meson_secure_a1_pwrc_data,
138 },
139 { }
140};
141
142static int meson_secure_pwrc_probe(struct udevice *dev)
143{
144 struct meson_secure_pwrc_priv *priv = dev_get_priv(dev);
145
146 priv->data = (void *)dev_get_driver_data(dev);
147 if (!priv->data)
148 return -EINVAL;
149
150 return 0;
151}
152
153U_BOOT_DRIVER(meson_secure_pwrc) = {
154 .name = "meson_secure_pwrc",
155 .id = UCLASS_POWER_DOMAIN,
156 .of_match = meson_secure_pwrc_ids,
157 .probe = meson_secure_pwrc_probe,
158 .ops = &meson_secure_pwrc_ops,
159 .priv_auto = sizeof(struct meson_secure_pwrc_priv),
160};