soc/tegra: Changes for v4.13-rc1
This contains an implementation of generic PM domains for Tegra186, based on the BPMP powergate request. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEiOrDCAFJzPfAjcif3SOs138+s6EFAllDj1wTHHRyZWRpbmdA bnZpZGlhLmNvbQAKCRDdI6zXfz6zofYAD/wKf+1uvTiFCXTHe+ebKBrsxpiF9na+ PDARXtOzjv5dWZOe4IY1NaejyOFL5TAjjB0WSjaj1y/dqd6UmqaJynaUkc7lcGhp wol8NNecQQosex8Bcswy+96HsnN9kTI7LvZqHAL5boGkzDygj6bNvDpB6rdkONlD gkOORyeuQnP3IIEstk1v1r8s+7NlcNYqGoFqXP9qIfD4LVqVA/IXK86riKiP8Bou s9E4cbXvwhZhZ76m5hLNrGU880CpyLf6JCExgqaLUNmqhZ49ZLXY8L4ReewWB3tI WRAzt6kOsj4EzPb0h8wksMWbxHsQ79ms3rA1YtjUb2zJzk6gbv9DNhEwarj/qyz7 16K158Uxhi2iELfnLFICq24U9wtqe5bGw/FLJASSD2Quv8aRih6p/oLdfatZ5kAh unR1HYTSw7z1XFjhGUEwb7x1MRNuS5dpMWar5L8nn4b5bACGvsNUHm+sID5TJlgR CowaYqO1QGxB4EpxMaGMzzEOieWofvy8Bu0WX3tTzuwPALq9LOOfQstmU69I4/Og tkrirL+TkBJEi8bMmn64iGMj0aOq33czpbFBdzaL7BDYHbOaB34bAErrJwQIYHNK gLMyQXD1TaBGliJtEeN+FsFFpHsVdB9wy0wGCkwu9nPCigoYOt52fQAnjrP7w26P ZKLNmUpszxrIVQ== =uyV7 -----END PGP SIGNATURE----- Merge tag 'tegra-for-4.13-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into next/drivers soc/tegra: Changes for v4.13-rc1 This contains an implementation of generic PM domains for Tegra186, based on the BPMP powergate request. * tag 'tegra-for-4.13-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux: soc/tegra: flowctrl: Fix error handling soc/tegra: bpmp: Implement generic PM domains soc/tegra: bpmp: Update ABI header PM / Domains: Allow overriding the ->xlate() callback Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
f39b24e0b4
@ -1584,9 +1584,6 @@ EXPORT_SYMBOL_GPL(pm_genpd_remove);
|
||||
|
||||
#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
|
||||
|
||||
typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args,
|
||||
void *data);
|
||||
|
||||
/*
|
||||
* Device Tree based PM domain providers.
|
||||
*
|
||||
@ -1742,6 +1739,9 @@ int of_genpd_add_provider_onecell(struct device_node *np,
|
||||
|
||||
mutex_lock(&gpd_list_lock);
|
||||
|
||||
if (!data->xlate)
|
||||
data->xlate = genpd_xlate_onecell;
|
||||
|
||||
for (i = 0; i < data->num_domains; i++) {
|
||||
if (!data->domains[i])
|
||||
continue;
|
||||
@ -1752,7 +1752,7 @@ int of_genpd_add_provider_onecell(struct device_node *np,
|
||||
data->domains[i]->has_provider = true;
|
||||
}
|
||||
|
||||
ret = genpd_add_provider(np, genpd_xlate_onecell, data);
|
||||
ret = genpd_add_provider(np, data->xlate, data);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
|
@ -810,6 +810,10 @@ static int tegra_bpmp_probe(struct platform_device *pdev)
|
||||
if (err < 0)
|
||||
goto free_mrq;
|
||||
|
||||
err = tegra_bpmp_init_powergates(bpmp);
|
||||
if (err < 0)
|
||||
goto free_mrq;
|
||||
|
||||
platform_set_drvdata(pdev, bpmp);
|
||||
|
||||
return 0;
|
||||
|
@ -115,3 +115,8 @@ config SOC_TEGRA_PMC
|
||||
|
||||
config SOC_TEGRA_PMC_TEGRA186
|
||||
bool
|
||||
|
||||
config SOC_TEGRA_POWERGATE_BPMP
|
||||
def_bool y
|
||||
depends on PM_GENERIC_DOMAINS
|
||||
depends on TEGRA_BPMP
|
||||
|
@ -4,3 +4,4 @@ obj-y += common.o
|
||||
obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o
|
||||
obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o
|
||||
obj-$(CONFIG_SOC_TEGRA_PMC_TEGRA186) += pmc-tegra186.o
|
||||
obj-$(CONFIG_SOC_TEGRA_POWERGATE_BPMP) += powergate-bpmp.o
|
||||
|
@ -157,7 +157,7 @@ static int tegra_flowctrl_probe(struct platform_device *pdev)
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
tegra_flowctrl_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(tegra_flowctrl_base))
|
||||
return PTR_ERR(base);
|
||||
return PTR_ERR(tegra_flowctrl_base);
|
||||
|
||||
iounmap(base);
|
||||
|
||||
|
359
drivers/soc/tegra/powergate-bpmp.c
Normal file
359
drivers/soc/tegra/powergate-bpmp.c
Normal file
@ -0,0 +1,359 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include <soc/tegra/bpmp.h>
|
||||
#include <soc/tegra/bpmp-abi.h>
|
||||
|
||||
struct tegra_powergate_info {
|
||||
unsigned int id;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct tegra_powergate {
|
||||
struct generic_pm_domain genpd;
|
||||
struct tegra_bpmp *bpmp;
|
||||
unsigned int id;
|
||||
};
|
||||
|
||||
static inline struct tegra_powergate *
|
||||
to_tegra_powergate(struct generic_pm_domain *genpd)
|
||||
{
|
||||
return container_of(genpd, struct tegra_powergate, genpd);
|
||||
}
|
||||
|
||||
static int tegra_bpmp_powergate_set_state(struct tegra_bpmp *bpmp,
|
||||
unsigned int id, u32 state)
|
||||
{
|
||||
struct mrq_pg_request request;
|
||||
struct tegra_bpmp_message msg;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.cmd = CMD_PG_SET_STATE;
|
||||
request.id = id;
|
||||
request.set_state.state = state;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.mrq = MRQ_PG;
|
||||
msg.tx.data = &request;
|
||||
msg.tx.size = sizeof(request);
|
||||
|
||||
return tegra_bpmp_transfer(bpmp, &msg);
|
||||
}
|
||||
|
||||
static int tegra_bpmp_powergate_get_state(struct tegra_bpmp *bpmp,
|
||||
unsigned int id)
|
||||
{
|
||||
struct mrq_pg_response response;
|
||||
struct mrq_pg_request request;
|
||||
struct tegra_bpmp_message msg;
|
||||
int err;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.cmd = CMD_PG_GET_STATE;
|
||||
request.id = id;
|
||||
|
||||
memset(&response, 0, sizeof(response));
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.mrq = MRQ_PG;
|
||||
msg.tx.data = &request;
|
||||
msg.tx.size = sizeof(request);
|
||||
msg.rx.data = &response;
|
||||
msg.rx.size = sizeof(response);
|
||||
|
||||
err = tegra_bpmp_transfer(bpmp, &msg);
|
||||
if (err < 0)
|
||||
return PG_STATE_OFF;
|
||||
|
||||
return response.get_state.state;
|
||||
}
|
||||
|
||||
static int tegra_bpmp_powergate_get_max_id(struct tegra_bpmp *bpmp)
|
||||
{
|
||||
struct mrq_pg_response response;
|
||||
struct mrq_pg_request request;
|
||||
struct tegra_bpmp_message msg;
|
||||
int err;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.cmd = CMD_PG_GET_MAX_ID;
|
||||
|
||||
memset(&response, 0, sizeof(response));
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.mrq = MRQ_PG;
|
||||
msg.tx.data = &request;
|
||||
msg.tx.size = sizeof(request);
|
||||
msg.rx.data = &response;
|
||||
msg.rx.size = sizeof(response);
|
||||
|
||||
err = tegra_bpmp_transfer(bpmp, &msg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return response.get_max_id.max_id;
|
||||
}
|
||||
|
||||
static char *tegra_bpmp_powergate_get_name(struct tegra_bpmp *bpmp,
|
||||
unsigned int id)
|
||||
{
|
||||
struct mrq_pg_response response;
|
||||
struct mrq_pg_request request;
|
||||
struct tegra_bpmp_message msg;
|
||||
int err;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.cmd = CMD_PG_GET_NAME;
|
||||
request.id = id;
|
||||
|
||||
memset(&response, 0, sizeof(response));
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.mrq = MRQ_PG;
|
||||
msg.tx.data = &request;
|
||||
msg.tx.size = sizeof(request);
|
||||
msg.rx.data = &response;
|
||||
msg.rx.size = sizeof(response);
|
||||
|
||||
err = tegra_bpmp_transfer(bpmp, &msg);
|
||||
if (err < 0)
|
||||
return NULL;
|
||||
|
||||
return kstrdup(response.get_name.name, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static inline bool tegra_bpmp_powergate_is_powered(struct tegra_bpmp *bpmp,
|
||||
unsigned int id)
|
||||
{
|
||||
return tegra_bpmp_powergate_get_state(bpmp, id) != PG_STATE_OFF;
|
||||
}
|
||||
|
||||
static int tegra_powergate_power_on(struct generic_pm_domain *domain)
|
||||
{
|
||||
struct tegra_powergate *powergate = to_tegra_powergate(domain);
|
||||
struct tegra_bpmp *bpmp = powergate->bpmp;
|
||||
|
||||
return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
|
||||
PG_STATE_ON);
|
||||
}
|
||||
|
||||
static int tegra_powergate_power_off(struct generic_pm_domain *domain)
|
||||
{
|
||||
struct tegra_powergate *powergate = to_tegra_powergate(domain);
|
||||
struct tegra_bpmp *bpmp = powergate->bpmp;
|
||||
|
||||
return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
|
||||
PG_STATE_OFF);
|
||||
}
|
||||
|
||||
static struct tegra_powergate *
|
||||
tegra_powergate_add(struct tegra_bpmp *bpmp,
|
||||
const struct tegra_powergate_info *info)
|
||||
{
|
||||
struct tegra_powergate *powergate;
|
||||
bool off;
|
||||
int err;
|
||||
|
||||
off = !tegra_bpmp_powergate_is_powered(bpmp, info->id);
|
||||
|
||||
powergate = devm_kzalloc(bpmp->dev, sizeof(*powergate), GFP_KERNEL);
|
||||
if (!powergate)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
powergate->id = info->id;
|
||||
powergate->bpmp = bpmp;
|
||||
|
||||
powergate->genpd.name = kstrdup(info->name, GFP_KERNEL);
|
||||
powergate->genpd.power_on = tegra_powergate_power_on;
|
||||
powergate->genpd.power_off = tegra_powergate_power_off;
|
||||
|
||||
err = pm_genpd_init(&powergate->genpd, NULL, off);
|
||||
if (err < 0) {
|
||||
kfree(powergate->genpd.name);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
return powergate;
|
||||
}
|
||||
|
||||
static void tegra_powergate_remove(struct tegra_powergate *powergate)
|
||||
{
|
||||
struct generic_pm_domain *genpd = &powergate->genpd;
|
||||
struct tegra_bpmp *bpmp = powergate->bpmp;
|
||||
int err;
|
||||
|
||||
err = pm_genpd_remove(genpd);
|
||||
if (err < 0)
|
||||
dev_err(bpmp->dev, "failed to remove power domain %s: %d\n",
|
||||
genpd->name, err);
|
||||
|
||||
kfree(genpd->name);
|
||||
}
|
||||
|
||||
static int
|
||||
tegra_bpmp_probe_powergates(struct tegra_bpmp *bpmp,
|
||||
struct tegra_powergate_info **powergatesp)
|
||||
{
|
||||
struct tegra_powergate_info *powergates;
|
||||
unsigned int max_id, id, count = 0;
|
||||
unsigned int num_holes = 0;
|
||||
int err;
|
||||
|
||||
err = tegra_bpmp_powergate_get_max_id(bpmp);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
max_id = err;
|
||||
|
||||
dev_dbg(bpmp->dev, "maximum powergate ID: %u\n", max_id);
|
||||
|
||||
powergates = kcalloc(max_id + 1, sizeof(*powergates), GFP_KERNEL);
|
||||
if (!powergates)
|
||||
return -ENOMEM;
|
||||
|
||||
for (id = 0; id <= max_id; id++) {
|
||||
struct tegra_powergate_info *info = &powergates[count];
|
||||
|
||||
info->name = tegra_bpmp_powergate_get_name(bpmp, id);
|
||||
if (!info->name || info->name[0] == '\0') {
|
||||
num_holes++;
|
||||
continue;
|
||||
}
|
||||
|
||||
info->id = id;
|
||||
count++;
|
||||
}
|
||||
|
||||
dev_dbg(bpmp->dev, "holes: %u\n", num_holes);
|
||||
|
||||
*powergatesp = powergates;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int tegra_bpmp_add_powergates(struct tegra_bpmp *bpmp,
|
||||
struct tegra_powergate_info *powergates,
|
||||
unsigned int count)
|
||||
{
|
||||
struct genpd_onecell_data *genpd = &bpmp->genpd;
|
||||
struct generic_pm_domain **domains;
|
||||
struct tegra_powergate *powergate;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
domains = kcalloc(count, sizeof(*domains), GFP_KERNEL);
|
||||
if (!domains)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
powergate = tegra_powergate_add(bpmp, &powergates[i]);
|
||||
if (IS_ERR(powergate)) {
|
||||
err = PTR_ERR(powergate);
|
||||
goto remove;
|
||||
}
|
||||
|
||||
dev_dbg(bpmp->dev, "added power domain %s\n",
|
||||
powergate->genpd.name);
|
||||
domains[i] = &powergate->genpd;
|
||||
}
|
||||
|
||||
genpd->num_domains = count;
|
||||
genpd->domains = domains;
|
||||
|
||||
return 0;
|
||||
|
||||
remove:
|
||||
while (i--) {
|
||||
powergate = to_tegra_powergate(domains[i]);
|
||||
tegra_powergate_remove(powergate);
|
||||
}
|
||||
|
||||
kfree(genpd->domains);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp)
|
||||
{
|
||||
struct genpd_onecell_data *genpd = &bpmp->genpd;
|
||||
unsigned int i = genpd->num_domains;
|
||||
struct tegra_powergate *powergate;
|
||||
|
||||
while (i--) {
|
||||
dev_dbg(bpmp->dev, "removing power domain %s\n",
|
||||
genpd->domains[i]->name);
|
||||
powergate = to_tegra_powergate(genpd->domains[i]);
|
||||
tegra_powergate_remove(powergate);
|
||||
}
|
||||
}
|
||||
|
||||
static struct generic_pm_domain *
|
||||
tegra_powergate_xlate(struct of_phandle_args *spec, void *data)
|
||||
{
|
||||
struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
|
||||
struct genpd_onecell_data *genpd = data;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < genpd->num_domains; i++) {
|
||||
struct tegra_powergate *powergate;
|
||||
|
||||
powergate = to_tegra_powergate(genpd->domains[i]);
|
||||
if (powergate->id == spec->args[0]) {
|
||||
domain = &powergate->genpd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
int tegra_bpmp_init_powergates(struct tegra_bpmp *bpmp)
|
||||
{
|
||||
struct device_node *np = bpmp->dev->of_node;
|
||||
struct tegra_powergate_info *powergates;
|
||||
struct device *dev = bpmp->dev;
|
||||
unsigned int count, i;
|
||||
int err;
|
||||
|
||||
err = tegra_bpmp_probe_powergates(bpmp, &powergates);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
count = err;
|
||||
|
||||
dev_dbg(dev, "%u power domains probed\n", count);
|
||||
|
||||
err = tegra_bpmp_add_powergates(bpmp, powergates, count);
|
||||
if (err < 0)
|
||||
goto free;
|
||||
|
||||
bpmp->genpd.xlate = tegra_powergate_xlate;
|
||||
|
||||
err = of_genpd_add_provider_onecell(np, &bpmp->genpd);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "failed to add power domain provider: %d\n", err);
|
||||
tegra_bpmp_remove_powergates(bpmp);
|
||||
}
|
||||
|
||||
free:
|
||||
for (i = 0; i < count; i++)
|
||||
kfree(powergates[i].name);
|
||||
|
||||
kfree(powergates);
|
||||
return err;
|
||||
}
|
@ -206,9 +206,13 @@ static inline void pm_genpd_syscore_poweron(struct device *dev) {}
|
||||
/* OF PM domain providers */
|
||||
struct of_device_id;
|
||||
|
||||
typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args,
|
||||
void *data);
|
||||
|
||||
struct genpd_onecell_data {
|
||||
struct generic_pm_domain **domains;
|
||||
unsigned int num_domains;
|
||||
genpd_xlate_t xlate;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
|
||||
|
@ -81,13 +81,18 @@
|
||||
* Provides the MRQ number for the MRQ message: #mrq. The remainder of
|
||||
* the MRQ message is a payload (immediately following the
|
||||
* mrq_request) whose format depends on mrq.
|
||||
*
|
||||
* @todo document the flags
|
||||
*/
|
||||
struct mrq_request {
|
||||
/** @brief MRQ number of the request */
|
||||
uint32_t mrq;
|
||||
/** @brief flags for the request */
|
||||
/**
|
||||
* @brief flags providing follow up directions to the receiver
|
||||
*
|
||||
* | Bit | Description |
|
||||
* |-----|--------------------------------------------|
|
||||
* | 1 | ring the sender's doorbell when responding |
|
||||
* | 0 | should be 1 |
|
||||
*/
|
||||
uint32_t flags;
|
||||
} __ABI_PACKED;
|
||||
|
||||
@ -99,13 +104,11 @@ struct mrq_request {
|
||||
* remainder of the MRQ response is a payload (immediately following
|
||||
* the mrq_response) whose format depends on the associated
|
||||
* mrq_request::mrq
|
||||
*
|
||||
* @todo document the flags
|
||||
*/
|
||||
struct mrq_response {
|
||||
/** @brief error code for the MRQ request itself */
|
||||
int32_t err;
|
||||
/** @brief flags for the response */
|
||||
/** @brief reserved for future use */
|
||||
uint32_t flags;
|
||||
} __ABI_PACKED;
|
||||
|
||||
@ -147,6 +150,8 @@ struct mrq_response {
|
||||
#define MRQ_ABI_RATCHET 29
|
||||
#define MRQ_EMC_DVFS_LATENCY 31
|
||||
#define MRQ_TRACE_ITER 64
|
||||
#define MRQ_RINGBUF_CONSOLE 65
|
||||
#define MRQ_PG 66
|
||||
|
||||
/** @} */
|
||||
|
||||
@ -155,7 +160,7 @@ struct mrq_response {
|
||||
* @brief Maximum MRQ code to be sent by CPU software to
|
||||
* BPMP. Subject to change in future
|
||||
*/
|
||||
#define MAX_CPU_MRQ_ID 64
|
||||
#define MAX_CPU_MRQ_ID 66
|
||||
|
||||
/**
|
||||
* @addtogroup MRQ_Payloads Message Payloads
|
||||
@ -175,6 +180,7 @@ struct mrq_response {
|
||||
* @defgroup Vhint CPU Voltage hint
|
||||
* @defgroup MRQ_Deprecated Deprecated MRQ messages
|
||||
* @defgroup EMC
|
||||
* @defgroup RingbufConsole
|
||||
* @}
|
||||
*/
|
||||
|
||||
@ -637,7 +643,7 @@ struct mrq_debugfs_response {
|
||||
* * Initiators: Any
|
||||
* * Targets: BPMP
|
||||
* * Request Payload: @ref mrq_reset_request
|
||||
* * Response Payload: N/A
|
||||
* * Response Payload: @ref mrq_reset_response
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -647,6 +653,7 @@ enum mrq_reset_commands {
|
||||
CMD_RESET_ASSERT = 1,
|
||||
CMD_RESET_DEASSERT = 2,
|
||||
CMD_RESET_MODULE = 3,
|
||||
CMD_RESET_GET_MAX_ID = 4,
|
||||
CMD_RESET_MAX, /* not part of ABI and subject to change */
|
||||
};
|
||||
|
||||
@ -664,6 +671,38 @@ struct mrq_reset_request {
|
||||
uint32_t reset_id;
|
||||
} __ABI_PACKED;
|
||||
|
||||
/**
|
||||
* @ingroup Reset
|
||||
* @brief Response for MRQ_RESET sub-command CMD_RESET_GET_MAX_ID. When
|
||||
* this sub-command is not supported, firmware will return -BPMP_EBADCMD
|
||||
* in mrq_response::err.
|
||||
*/
|
||||
struct cmd_reset_get_max_id_response {
|
||||
/** @brief max reset id */
|
||||
uint32_t max_id;
|
||||
} __ABI_PACKED;
|
||||
|
||||
/**
|
||||
* @ingroup Reset
|
||||
* @brief Response with MRQ_RESET
|
||||
*
|
||||
* Each sub-command supported by @ref mrq_reset_request may return
|
||||
* sub-command-specific data. Some do and some do not as indicated
|
||||
* in the following table
|
||||
*
|
||||
* | sub-command | payload |
|
||||
* |----------------------|------------------|
|
||||
* | CMD_RESET_ASSERT | - |
|
||||
* | CMD_RESET_DEASSERT | - |
|
||||
* | CMD_RESET_MODULE | - |
|
||||
* | CMD_RESET_GET_MAX_ID | reset_get_max_id |
|
||||
*/
|
||||
struct mrq_reset_response {
|
||||
union {
|
||||
struct cmd_reset_get_max_id_response reset_get_max_id;
|
||||
} __UNION_ANON;
|
||||
} __ABI_PACKED;
|
||||
|
||||
/**
|
||||
* @ingroup MRQ_Codes
|
||||
* @def MRQ_I2C
|
||||
@ -812,6 +851,17 @@ enum {
|
||||
};
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name MRQ_CLK properties
|
||||
* Flag bits for cmd_clk_properties_response::flags and
|
||||
* cmd_clk_get_all_info_response::flags
|
||||
* @{
|
||||
*/
|
||||
#define BPMP_CLK_HAS_MUX (1 << 0)
|
||||
#define BPMP_CLK_HAS_SET_RATE (1 << 1)
|
||||
#define BPMP_CLK_IS_ROOT (1 << 2)
|
||||
/** @} */
|
||||
|
||||
#define MRQ_CLK_NAME_MAXLEN 40
|
||||
#define MRQ_CLK_MAX_PARENTS 16
|
||||
|
||||
@ -1010,7 +1060,7 @@ struct mrq_clk_response {
|
||||
*
|
||||
* * Platforms: All
|
||||
* * Initiators: Any
|
||||
* * Targets: Any
|
||||
* * Targets: Any except DMCE
|
||||
* * Request Payload: @ref mrq_query_abi_request
|
||||
* * Response Payload: @ref mrq_query_abi_response
|
||||
*/
|
||||
@ -1030,6 +1080,9 @@ struct mrq_query_abi_request {
|
||||
/**
|
||||
* @ingroup ABI_info
|
||||
* @brief response to MRQ_QUERY_ABI
|
||||
*
|
||||
* @note mrq_response::err of 0 indicates that the query was
|
||||
* successful, not that the MRQ itself is supported!
|
||||
*/
|
||||
struct mrq_query_abi_response {
|
||||
/** @brief 0 if queried MRQ is supported. Else, -#BPMP_ENODEV */
|
||||
@ -1080,7 +1133,9 @@ struct mrq_pg_read_state_response {
|
||||
/**
|
||||
* @ingroup MRQ_Codes
|
||||
* @def MRQ_PG_UPDATE_STATE
|
||||
* @brief modify the power-gating state of a partition
|
||||
* @brief modify the power-gating state of a partition. In contrast to
|
||||
* MRQ_PG calls, the operations that change state (on/off) of power
|
||||
* partition are reference counted.
|
||||
*
|
||||
* * Platforms: T186
|
||||
* * Initiators: Any
|
||||
@ -1124,6 +1179,171 @@ struct mrq_pg_update_state_request {
|
||||
} __ABI_PACKED;
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @ingroup MRQ_Codes
|
||||
* @def MRQ_PG
|
||||
* @brief Control power-gating state of a partition. In contrast to
|
||||
* MRQ_PG_UPDATE_STATE, operations that change the power partition
|
||||
* state are NOT reference counted
|
||||
*
|
||||
* * Platforms: T186
|
||||
* * Initiators: Any
|
||||
* * Targets: BPMP
|
||||
* * Request Payload: @ref mrq_pg_request
|
||||
* * Response Payload: @ref mrq_pg_response
|
||||
* @addtogroup Powergating
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name MRQ_PG sub-commands
|
||||
* @{
|
||||
*/
|
||||
enum mrq_pg_cmd {
|
||||
/**
|
||||
* @brief Check whether the BPMP driver supports the specified
|
||||
* request type
|
||||
*
|
||||
* mrq_response::err is 0 if the specified request is
|
||||
* supported and -#BPMP_ENODEV otherwise.
|
||||
*/
|
||||
CMD_PG_QUERY_ABI = 0,
|
||||
|
||||
/**
|
||||
* @brief Set the current state of specified power domain. The
|
||||
* possible values for power domains are defined in enum
|
||||
* pg_states
|
||||
*
|
||||
* mrq_response:err is
|
||||
* 0: Success
|
||||
* -#BPMP_EINVAL: Invalid request parameters
|
||||
*/
|
||||
CMD_PG_SET_STATE = 1,
|
||||
|
||||
/**
|
||||
* @brief Get the current state of specified power domain. The
|
||||
* possible values for power domains are defined in enum
|
||||
* pg_states
|
||||
*
|
||||
* mrq_response:err is
|
||||
* 0: Success
|
||||
* -#BPMP_EINVAL: Invalid request parameters
|
||||
*/
|
||||
CMD_PG_GET_STATE = 2,
|
||||
|
||||
/**
|
||||
* @brief get the name string of specified power domain id.
|
||||
*
|
||||
* mrq_response:err is
|
||||
* 0: Success
|
||||
* -#BPMP_EINVAL: Invalid request parameters
|
||||
*/
|
||||
CMD_PG_GET_NAME = 3,
|
||||
|
||||
|
||||
/**
|
||||
* @brief get the highest power domain id in the system. Not
|
||||
* all IDs between 0 and max_id are valid IDs.
|
||||
*
|
||||
* mrq_response:err is
|
||||
* 0: Success
|
||||
* -#BPMP_EINVAL: Invalid request parameters
|
||||
*/
|
||||
CMD_PG_GET_MAX_ID = 4,
|
||||
};
|
||||
/** @} */
|
||||
|
||||
#define MRQ_PG_NAME_MAXLEN 40
|
||||
|
||||
/**
|
||||
* @brief possible power domain states in
|
||||
* cmd_pg_set_state_request:state and cmd_pg_get_state_response:state.
|
||||
* PG_STATE_OFF: power domain is OFF
|
||||
* PG_STATE_ON: power domain is ON
|
||||
* PG_STATE_RUNNING: power domain is ON and made into directly usable
|
||||
* state by turning on the clocks associated with
|
||||
* the domain
|
||||
*/
|
||||
enum pg_states {
|
||||
PG_STATE_OFF = 0,
|
||||
PG_STATE_ON = 1,
|
||||
PG_STATE_RUNNING = 2,
|
||||
};
|
||||
|
||||
struct cmd_pg_query_abi_request {
|
||||
uint32_t type; /* enum mrq_pg_cmd */
|
||||
} __ABI_PACKED;
|
||||
|
||||
struct cmd_pg_set_state_request {
|
||||
uint32_t state; /* enum pg_states */
|
||||
} __ABI_PACKED;
|
||||
|
||||
struct cmd_pg_get_state_response {
|
||||
uint32_t state; /* enum pg_states */
|
||||
} __ABI_PACKED;
|
||||
|
||||
struct cmd_pg_get_name_response {
|
||||
uint8_t name[MRQ_PG_NAME_MAXLEN];
|
||||
} __ABI_PACKED;
|
||||
|
||||
struct cmd_pg_get_max_id_response {
|
||||
uint32_t max_id;
|
||||
} __ABI_PACKED;
|
||||
|
||||
/**
|
||||
* @ingroup Powergating
|
||||
* @brief request with #MRQ_PG
|
||||
*
|
||||
* Used by the sender of an #MRQ_PG message to control power
|
||||
* partitions. The pg_request is split into several sub-commands. Some
|
||||
* sub-commands require no additional data. Others have a sub-command
|
||||
* specific payload
|
||||
*
|
||||
* |sub-command |payload |
|
||||
* |----------------------------|-----------------------|
|
||||
* |CMD_PG_QUERY_ABI | query_abi |
|
||||
* |CMD_PG_SET_STATE | set_state |
|
||||
* |CMD_PG_GET_STATE | - |
|
||||
* |CMD_PG_GET_NAME | - |
|
||||
* |CMD_PG_GET_MAX_ID | - |
|
||||
*
|
||||
*/
|
||||
|
||||
struct mrq_pg_request {
|
||||
uint32_t cmd;
|
||||
uint32_t id;
|
||||
union {
|
||||
struct cmd_pg_query_abi_request query_abi;
|
||||
struct cmd_pg_set_state_request set_state;
|
||||
} __UNION_ANON;
|
||||
} __ABI_PACKED;
|
||||
|
||||
/**
|
||||
* @ingroup Powergating
|
||||
* @brief response to MRQ_PG
|
||||
*
|
||||
* Each sub-command supported by @ref mrq_pg_request may return
|
||||
* sub-command-specific data. Some do and some do not as indicated in
|
||||
* the following table
|
||||
*
|
||||
* |sub-command |payload |
|
||||
* |----------------------------|-----------------------|
|
||||
* |CMD_PG_QUERY_ABI | - |
|
||||
* |CMD_PG_SET_STATE | - |
|
||||
* |CMD_PG_GET_STATE | get_state |
|
||||
* |CMD_PG_GET_NAME | get_name |
|
||||
* |CMD_PG_GET_MAX_ID | get_max_id |
|
||||
*
|
||||
*/
|
||||
|
||||
struct mrq_pg_response {
|
||||
union {
|
||||
struct cmd_pg_get_state_response get_state;
|
||||
struct cmd_pg_get_name_response get_name;
|
||||
struct cmd_pg_get_max_id_response get_max_id;
|
||||
} __UNION_ANON;
|
||||
} __ABI_PACKED;
|
||||
|
||||
/**
|
||||
* @ingroup MRQ_Codes
|
||||
* @def MRQ_THERMAL
|
||||
@ -1529,6 +1749,184 @@ struct mrq_trace_iter_request {
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @ingroup MRQ_Codes
|
||||
* @def MRQ_RINGBUF_CONSOLE
|
||||
* @brief A ring buffer debug console for BPMP
|
||||
* @addtogroup RingbufConsole
|
||||
*
|
||||
* The ring buffer debug console aims to be a substitute for the UART debug
|
||||
* console. The debug console is implemented with two ring buffers in the
|
||||
* BPMP-FW, the RX (receive) and TX (transmit) buffers. Characters can be read
|
||||
* and written to the buffers by the host via the MRQ interface.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Maximum number of bytes transferred in a single write command to the
|
||||
* BPMP
|
||||
*
|
||||
* This is determined by the number of free bytes in the message struct,
|
||||
* rounded down to a multiple of four.
|
||||
*/
|
||||
#define MRQ_RINGBUF_CONSOLE_MAX_WRITE_LEN 112
|
||||
|
||||
/**
|
||||
* @brief Maximum number of bytes transferred in a single read command to the
|
||||
* BPMP
|
||||
*
|
||||
* This is determined by the number of free bytes in the message struct,
|
||||
* rounded down to a multiple of four.
|
||||
*/
|
||||
#define MRQ_RINGBUF_CONSOLE_MAX_READ_LEN 116
|
||||
|
||||
enum mrq_ringbuf_console_host_to_bpmp_cmd {
|
||||
/**
|
||||
* @brief Check whether the BPMP driver supports the specified request
|
||||
* type
|
||||
*
|
||||
* mrq_response::err is 0 if the specified request is supported and
|
||||
* -#BPMP_ENODEV otherwise
|
||||
*/
|
||||
CMD_RINGBUF_CONSOLE_QUERY_ABI = 0,
|
||||
/**
|
||||
* @brief Perform a read operation on the BPMP TX buffer
|
||||
*
|
||||
* mrq_response::err is 0
|
||||
*/
|
||||
CMD_RINGBUF_CONSOLE_READ = 1,
|
||||
/**
|
||||
* @brief Perform a write operation on the BPMP RX buffer
|
||||
*
|
||||
* mrq_response::err is 0 if the operation was successful and
|
||||
* -#BPMP_ENODEV otherwise
|
||||
*/
|
||||
CMD_RINGBUF_CONSOLE_WRITE = 2,
|
||||
/**
|
||||
* @brief Get the length of the buffer and the physical addresses of
|
||||
* the buffer data and the head and tail counters
|
||||
*
|
||||
* mrq_response::err is 0 if the operation was successful and
|
||||
* -#BPMP_ENODEV otherwise
|
||||
*/
|
||||
CMD_RINGBUF_CONSOLE_GET_FIFO = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup RingbufConsole
|
||||
* @brief Host->BPMP request data for request type
|
||||
* #CMD_RINGBUF_CONSOLE_QUERY_ABI
|
||||
*/
|
||||
struct cmd_ringbuf_console_query_abi_req {
|
||||
/** @brief Command identifier to be queried */
|
||||
uint32_t cmd;
|
||||
} __ABI_PACKED;
|
||||
|
||||
/** @private */
|
||||
struct cmd_ringbuf_console_query_abi_resp {
|
||||
EMPTY
|
||||
} __ABI_PACKED;
|
||||
|
||||
/**
|
||||
* @ingroup RingbufConsole
|
||||
* @brief Host->BPMP request data for request type #CMD_RINGBUF_CONSOLE_READ
|
||||
*/
|
||||
struct cmd_ringbuf_console_read_req {
|
||||
/**
|
||||
* @brief Number of bytes requested to be read from the BPMP TX buffer
|
||||
*/
|
||||
uint8_t len;
|
||||
} __ABI_PACKED;
|
||||
|
||||
/**
|
||||
* @ingroup RingbufConsole
|
||||
* @brief BPMP->Host response data for request type #CMD_RINGBUF_CONSOLE_READ
|
||||
*/
|
||||
struct cmd_ringbuf_console_read_resp {
|
||||
/** @brief The actual data read from the BPMP TX buffer */
|
||||
uint8_t data[MRQ_RINGBUF_CONSOLE_MAX_READ_LEN];
|
||||
/** @brief Number of bytes in cmd_ringbuf_console_read_resp::data */
|
||||
uint8_t len;
|
||||
} __ABI_PACKED;
|
||||
|
||||
/**
|
||||
* @ingroup RingbufConsole
|
||||
* @brief Host->BPMP request data for request type #CMD_RINGBUF_CONSOLE_WRITE
|
||||
*/
|
||||
struct cmd_ringbuf_console_write_req {
|
||||
/** @brief The actual data to be written to the BPMP RX buffer */
|
||||
uint8_t data[MRQ_RINGBUF_CONSOLE_MAX_WRITE_LEN];
|
||||
/** @brief Number of bytes in cmd_ringbuf_console_write_req::data */
|
||||
uint8_t len;
|
||||
} __ABI_PACKED;
|
||||
|
||||
/**
|
||||
* @ingroup RingbufConsole
|
||||
* @brief BPMP->Host response data for request type #CMD_RINGBUF_CONSOLE_WRITE
|
||||
*/
|
||||
struct cmd_ringbuf_console_write_resp {
|
||||
/** @brief Number of bytes of available space in the BPMP RX buffer */
|
||||
uint32_t space_avail;
|
||||
/** @brief Number of bytes that were written to the BPMP RX buffer */
|
||||
uint8_t len;
|
||||
} __ABI_PACKED;
|
||||
|
||||
/** @private */
|
||||
struct cmd_ringbuf_console_get_fifo_req {
|
||||
EMPTY
|
||||
} __ABI_PACKED;
|
||||
|
||||
/**
|
||||
* @ingroup RingbufConsole
|
||||
* @brief BPMP->Host reply data for request type #CMD_RINGBUF_CONSOLE_GET_FIFO
|
||||
*/
|
||||
struct cmd_ringbuf_console_get_fifo_resp {
|
||||
/** @brief Physical address of the BPMP TX buffer */
|
||||
uint64_t bpmp_tx_buf_addr;
|
||||
/** @brief Physical address of the BPMP TX buffer head counter */
|
||||
uint64_t bpmp_tx_head_addr;
|
||||
/** @brief Physical address of the BPMP TX buffer tail counter */
|
||||
uint64_t bpmp_tx_tail_addr;
|
||||
/** @brief Length of the BPMP TX buffer */
|
||||
uint32_t bpmp_tx_buf_len;
|
||||
} __ABI_PACKED;
|
||||
|
||||
/**
|
||||
* @ingroup RingbufConsole
|
||||
* @brief Host->BPMP request data.
|
||||
*
|
||||
* Reply type is union #mrq_ringbuf_console_bpmp_to_host_response .
|
||||
*/
|
||||
struct mrq_ringbuf_console_host_to_bpmp_request {
|
||||
/**
|
||||
* @brief type of request. Values listed in enum
|
||||
* #mrq_ringbuf_console_host_to_bpmp_cmd.
|
||||
*/
|
||||
uint32_t type;
|
||||
/** @brief request type specific parameters. */
|
||||
union {
|
||||
struct cmd_ringbuf_console_query_abi_req query_abi;
|
||||
struct cmd_ringbuf_console_read_req read;
|
||||
struct cmd_ringbuf_console_write_req write;
|
||||
struct cmd_ringbuf_console_get_fifo_req get_fifo;
|
||||
} __UNION_ANON;
|
||||
} __ABI_PACKED;
|
||||
|
||||
/**
|
||||
* @ingroup RingbufConsole
|
||||
* @brief Host->BPMP reply data
|
||||
*
|
||||
* In response to struct #mrq_ringbuf_console_host_to_bpmp_request.
|
||||
*/
|
||||
union mrq_ringbuf_console_bpmp_to_host_response {
|
||||
struct cmd_ringbuf_console_query_abi_resp query_abi;
|
||||
struct cmd_ringbuf_console_read_resp read;
|
||||
struct cmd_ringbuf_console_write_resp write;
|
||||
struct cmd_ringbuf_console_get_fifo_resp get_fifo;
|
||||
} __ABI_PACKED;
|
||||
/** @} */
|
||||
|
||||
/*
|
||||
* 4. Enumerations
|
||||
*/
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define __SOC_TEGRA_BPMP_H
|
||||
|
||||
#include <linux/mailbox_client.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/types.h>
|
||||
@ -91,6 +92,8 @@ struct tegra_bpmp {
|
||||
unsigned int num_clocks;
|
||||
|
||||
struct reset_controller_dev rstc;
|
||||
|
||||
struct genpd_onecell_data genpd;
|
||||
};
|
||||
|
||||
struct tegra_bpmp *tegra_bpmp_get(struct device *dev);
|
||||
@ -138,4 +141,13 @@ static inline int tegra_bpmp_init_resets(struct tegra_bpmp *bpmp)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_SOC_TEGRA_POWERGATE_BPMP)
|
||||
int tegra_bpmp_init_powergates(struct tegra_bpmp *bpmp);
|
||||
#else
|
||||
static inline int tegra_bpmp_init_powergates(struct tegra_bpmp *bpmp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SOC_TEGRA_BPMP_H */
|
||||
|
Loading…
Reference in New Issue
Block a user