^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/pm_domain.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/version.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <soc/tegra/bpmp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <soc/tegra/bpmp-abi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) struct tegra_powergate_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) unsigned int id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct tegra_powergate {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct generic_pm_domain genpd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct tegra_bpmp *bpmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) unsigned int id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static inline struct tegra_powergate *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) to_tegra_powergate(struct generic_pm_domain *genpd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) return container_of(genpd, struct tegra_powergate, genpd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static int tegra_bpmp_powergate_set_state(struct tegra_bpmp *bpmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) unsigned int id, u32 state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct mrq_pg_request request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct tegra_bpmp_message msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) memset(&request, 0, sizeof(request));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) request.cmd = CMD_PG_SET_STATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) request.id = id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) request.set_state.state = state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) memset(&msg, 0, sizeof(msg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) msg.mrq = MRQ_PG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) msg.tx.data = &request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) msg.tx.size = sizeof(request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) err = tegra_bpmp_transfer(bpmp, &msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) else if (msg.rx.ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static int tegra_bpmp_powergate_get_state(struct tegra_bpmp *bpmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) unsigned int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct mrq_pg_response response;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct mrq_pg_request request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct tegra_bpmp_message msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) memset(&request, 0, sizeof(request));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) request.cmd = CMD_PG_GET_STATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) request.id = id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) memset(&response, 0, sizeof(response));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) memset(&msg, 0, sizeof(msg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) msg.mrq = MRQ_PG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) msg.tx.data = &request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) msg.tx.size = sizeof(request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) msg.rx.data = &response;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) msg.rx.size = sizeof(response);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) err = tegra_bpmp_transfer(bpmp, &msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return PG_STATE_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) else if (msg.rx.ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return response.get_state.state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static int tegra_bpmp_powergate_get_max_id(struct tegra_bpmp *bpmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct mrq_pg_response response;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct mrq_pg_request request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct tegra_bpmp_message msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) memset(&request, 0, sizeof(request));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) request.cmd = CMD_PG_GET_MAX_ID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) memset(&response, 0, sizeof(response));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) memset(&msg, 0, sizeof(msg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) msg.mrq = MRQ_PG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) msg.tx.data = &request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) msg.tx.size = sizeof(request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) msg.rx.data = &response;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) msg.rx.size = sizeof(response);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) err = tegra_bpmp_transfer(bpmp, &msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) else if (msg.rx.ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return response.get_max_id.max_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) static char *tegra_bpmp_powergate_get_name(struct tegra_bpmp *bpmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) unsigned int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct mrq_pg_response response;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) struct mrq_pg_request request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) struct tegra_bpmp_message msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) memset(&request, 0, sizeof(request));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) request.cmd = CMD_PG_GET_NAME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) request.id = id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) memset(&response, 0, sizeof(response));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) memset(&msg, 0, sizeof(msg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) msg.mrq = MRQ_PG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) msg.tx.data = &request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) msg.tx.size = sizeof(request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) msg.rx.data = &response;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) msg.rx.size = sizeof(response);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) err = tegra_bpmp_transfer(bpmp, &msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (err < 0 || msg.rx.ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return kstrdup(response.get_name.name, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static inline bool tegra_bpmp_powergate_is_powered(struct tegra_bpmp *bpmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) unsigned int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return tegra_bpmp_powergate_get_state(bpmp, id) != PG_STATE_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static int tegra_powergate_power_on(struct generic_pm_domain *domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) struct tegra_powergate *powergate = to_tegra_powergate(domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) struct tegra_bpmp *bpmp = powergate->bpmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) PG_STATE_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static int tegra_powergate_power_off(struct generic_pm_domain *domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) struct tegra_powergate *powergate = to_tegra_powergate(domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) struct tegra_bpmp *bpmp = powergate->bpmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) PG_STATE_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) static struct tegra_powergate *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) tegra_powergate_add(struct tegra_bpmp *bpmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) const struct tegra_powergate_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) struct tegra_powergate *powergate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) bool off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) off = !tegra_bpmp_powergate_is_powered(bpmp, info->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) powergate = devm_kzalloc(bpmp->dev, sizeof(*powergate), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) if (!powergate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) powergate->id = info->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) powergate->bpmp = bpmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) powergate->genpd.name = kstrdup(info->name, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) powergate->genpd.power_on = tegra_powergate_power_on;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) powergate->genpd.power_off = tegra_powergate_power_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) err = pm_genpd_init(&powergate->genpd, NULL, off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) kfree(powergate->genpd.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return ERR_PTR(err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return powergate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static void tegra_powergate_remove(struct tegra_powergate *powergate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) struct generic_pm_domain *genpd = &powergate->genpd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) struct tegra_bpmp *bpmp = powergate->bpmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) err = pm_genpd_remove(genpd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) dev_err(bpmp->dev, "failed to remove power domain %s: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) genpd->name, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) kfree(genpd->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) tegra_bpmp_probe_powergates(struct tegra_bpmp *bpmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) struct tegra_powergate_info **powergatesp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) struct tegra_powergate_info *powergates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) unsigned int max_id, id, count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) unsigned int num_holes = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) err = tegra_bpmp_powergate_get_max_id(bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) max_id = err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) dev_dbg(bpmp->dev, "maximum powergate ID: %u\n", max_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) powergates = kcalloc(max_id + 1, sizeof(*powergates), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (!powergates)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) for (id = 0; id <= max_id; id++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) struct tegra_powergate_info *info = &powergates[count];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) info->name = tegra_bpmp_powergate_get_name(bpmp, id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (!info->name || info->name[0] == '\0') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) num_holes++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) info->id = id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) dev_dbg(bpmp->dev, "holes: %u\n", num_holes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) *powergatesp = powergates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) static int tegra_bpmp_add_powergates(struct tegra_bpmp *bpmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) struct tegra_powergate_info *powergates,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) unsigned int count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) struct genpd_onecell_data *genpd = &bpmp->genpd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) struct generic_pm_domain **domains;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) struct tegra_powergate *powergate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) domains = kcalloc(count, sizeof(*domains), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) if (!domains)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) for (i = 0; i < count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) powergate = tegra_powergate_add(bpmp, &powergates[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) if (IS_ERR(powergate)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) err = PTR_ERR(powergate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) goto remove;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) dev_dbg(bpmp->dev, "added power domain %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) powergate->genpd.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) domains[i] = &powergate->genpd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) genpd->num_domains = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) genpd->domains = domains;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) remove:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) while (i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) powergate = to_tegra_powergate(domains[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) tegra_powergate_remove(powergate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) kfree(genpd->domains);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) struct genpd_onecell_data *genpd = &bpmp->genpd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) unsigned int i = genpd->num_domains;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) struct tegra_powergate *powergate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) while (i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) dev_dbg(bpmp->dev, "removing power domain %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) genpd->domains[i]->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) powergate = to_tegra_powergate(genpd->domains[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) tegra_powergate_remove(powergate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) static struct generic_pm_domain *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) tegra_powergate_xlate(struct of_phandle_args *spec, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) struct genpd_onecell_data *genpd = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) for (i = 0; i < genpd->num_domains; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) struct tegra_powergate *powergate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) powergate = to_tegra_powergate(genpd->domains[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (powergate->id == spec->args[0]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) domain = &powergate->genpd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) return domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) int tegra_bpmp_init_powergates(struct tegra_bpmp *bpmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) struct device_node *np = bpmp->dev->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) struct tegra_powergate_info *powergates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) struct device *dev = bpmp->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) unsigned int count, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) err = tegra_bpmp_probe_powergates(bpmp, &powergates);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) count = err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) dev_dbg(dev, "%u power domains probed\n", count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) err = tegra_bpmp_add_powergates(bpmp, powergates, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) goto free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) bpmp->genpd.xlate = tegra_powergate_xlate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) err = of_genpd_add_provider_onecell(np, &bpmp->genpd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) dev_err(dev, "failed to add power domain provider: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) tegra_bpmp_remove_powergates(bpmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) for (i = 0; i < count; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) kfree(powergates[i].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) kfree(powergates);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }