1// 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}; 161