mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 11:41:38 -04:00
ARM: SoC driver updates
- New SoC specific drivers
- NVIDIA Tegra PM Domain support for newer SoCs (Tegra186 and later)
based on the "BPMP" firmware
- Clocksource and system controller drivers for the newly added
Action Semi platforms (both arm and arm64).
- Reset subsystem, merged through arm-soc by tradition:
- New drivers for Altera Stratix10, TI Keystone and Cortina Gemini SoCs
- Various subsystem-wide cleanups
- Updates for existing SoC-specific drivers
- TI GPMC (General Purpose Memory Controller)
- Mediatek "scpsys" system controller support for MT6797
- Broadcom "brcmstb_gisb" bus arbitrer
- ARM SCPI firmware
- Renesas "SYSC" system controller
One more driver update was submitted for the Freescale/NXP DPAA
data path acceleration that has previously been used on PowerPC
chips. I ended up postponing the merge until some API questions
for its unusual MMIO access are resolved.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQIVAwUAWVpDFmCrR//JCVInAQKoihAAosgC3+3IHppOhHid+HepkOcp2teyKknw
42fSXVpTdfWa8Oe7q80Kzmz2CPNfFq2SzHz6oXb9WCcDFqSGr0b9aSE7NnksRjTf
2euHVJ4MnJpkRewvorRmcpK8dPXDcHwEw/8hU3yZtJUGI0IKtlrqXis+evgkz9cn
YDynuVdAZgZiEfiNeSeadyNLcxaQCc3x9ovvsBXxBa1/x1pfeRnTbp+6hiHilCJu
Szts/yAzZzZE9Jkf9dLKfNlsT6m2SgtjukqqOR+zHAhi7/BdTFSVUP6L8u7QjrR+
+ijTICg8FMJGiWLAOe6ED2qZVByN92EJ2AGwriYlSles9ouoGfRkJ2rwxyjbete7
avy0HP+PSBFXWdwbOcq8HX8CrbuBltagl5fkMokct6biWLLMshNZ33WWdQ6/DsM2
b9mAAZuhbs0g1qWUBD3+q6qBytSuGme6Px6fMoVEc4GQ2YVFUQOoEfZOGKRv1U1o
aMWGt/6qeF8SG288rYAnQ/TuYWpOLtksV6yhotA00HUHhkTCy0xVCdyWGZtNyKhG
o/x4YnhWFzHsXmqKcR1sM7LzfZY/WNmbrOLvK6i83Z0P7QptqrdaLAylL3iSPEyX
ZDUgExf6PYXkWIewc3KwC5sJjuD05z3ZCgIR+mCezwbuD+3Z2fOdjodY/VBZ74hq
URcM/BqtuWE=
=5L6n
-----END PGP SIGNATURE-----
Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver updates from Arnd Bergmann:
"New SoC specific drivers:
- NVIDIA Tegra PM Domain support for newer SoCs (Tegra186 and later)
based on the "BPMP" firmware
- Clocksource and system controller drivers for the newly added
Action Semi platforms (both arm and arm64).
Reset subsystem, merged through arm-soc by tradition:
- New drivers for Altera Stratix10, TI Keystone and Cortina Gemini
SoCs
- Various subsystem-wide cleanups
Updates for existing SoC-specific drivers
- TI GPMC (General Purpose Memory Controller)
- Mediatek "scpsys" system controller support for MT6797
- Broadcom "brcmstb_gisb" bus arbitrer
- ARM SCPI firmware
- Renesas "SYSC" system controller
One more driver update was submitted for the Freescale/NXP DPAA data
path acceleration that has previously been used on PowerPC chips. I
ended up postponing the merge until some API questions for its unusual
MMIO access are resolved"
* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (35 commits)
clocksource: owl: Add S900 support
clocksource: Add Owl timer
soc: renesas: rcar-sysc: Use GENPD_FLAG_ALWAYS_ON
firmware: tegra: Fix locking bugs in BPMP
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
soc: brcmstb: enable drivers for ARM64 and BMIPS
soc: renesas: Rework Kconfig and Makefile logic
reset: Add the TI SCI reset driver
dt-bindings: reset: Add TI SCI reset binding
reset: use kref for reference counting
soc: qcom: smsm: Improve error handling, quiesce probe deferral
cpufreq: scpi: use new scpi_ops functions to remove duplicate code
firmware: arm_scpi: add support to populate OPPs and get transition latency
dt-bindings: reset: Add reset manager offsets for Stratix10
memory: omap-gpmc: add error message if bank-width property is absent
memory: omap-gpmc: make dts snippet include semicolon
reset: Add a Gemini reset controller
...
This commit is contained in:
commit
e854711291
42 changed files with 2059 additions and 198 deletions
|
|
@ -7,6 +7,7 @@ source "drivers/soc/fsl/Kconfig"
|
|||
source "drivers/soc/imx/Kconfig"
|
||||
source "drivers/soc/mediatek/Kconfig"
|
||||
source "drivers/soc/qcom/Kconfig"
|
||||
source "drivers/soc/renesas/Kconfig"
|
||||
source "drivers/soc/rockchip/Kconfig"
|
||||
source "drivers/soc/samsung/Kconfig"
|
||||
source "drivers/soc/sunxi/Kconfig"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ obj-y += fsl/
|
|||
obj-$(CONFIG_ARCH_MXC) += imx/
|
||||
obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
|
||||
obj-$(CONFIG_ARCH_QCOM) += qcom/
|
||||
obj-$(CONFIG_ARCH_RENESAS) += renesas/
|
||||
obj-y += renesas/
|
||||
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
|
||||
obj-$(CONFIG_SOC_SAMSUNG) += samsung/
|
||||
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ config RASPBERRYPI_POWER
|
|||
|
||||
config SOC_BRCMSTB
|
||||
bool "Broadcom STB SoC drivers"
|
||||
depends on ARM
|
||||
depends on ARM || ARM64 || BMIPS_GENERIC || COMPILE_TEST
|
||||
select SOC_BUS
|
||||
help
|
||||
Enables drivers for the Broadcom Set-Top Box (STB) series of chips.
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
obj-y += gpc.o
|
||||
obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
|
||||
obj-$(CONFIG_IMX7_PM_DOMAINS) += gpcv2.o
|
||||
|
|
|
|||
|
|
@ -1117,6 +1117,11 @@ static int pwrap_probe(struct platform_device *pdev)
|
|||
const struct of_device_id *of_slave_id = NULL;
|
||||
struct resource *res;
|
||||
|
||||
if (!of_id) {
|
||||
dev_err(&pdev->dev, "Error: No device match found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (pdev->dev.of_node->child)
|
||||
of_slave_id = of_match_node(of_slave_match_tbl,
|
||||
pdev->dev.of_node->child);
|
||||
|
|
@ -1200,7 +1205,8 @@ static int pwrap_probe(struct platform_device *pdev)
|
|||
|
||||
if (!(pwrap_readl(wrp, PWRAP_WACS2_RDATA) & PWRAP_STATE_INIT_DONE0)) {
|
||||
dev_dbg(wrp->dev, "initialization isn't finished\n");
|
||||
return -ENODEV;
|
||||
ret = -ENODEV;
|
||||
goto err_out2;
|
||||
}
|
||||
|
||||
/* Initialize watchdog, may not be done by the bootloader */
|
||||
|
|
@ -1220,8 +1226,10 @@ static int pwrap_probe(struct platform_device *pdev)
|
|||
goto err_out2;
|
||||
|
||||
wrp->regmap = devm_regmap_init(wrp->dev, NULL, wrp, &pwrap_regmap_config);
|
||||
if (IS_ERR(wrp->regmap))
|
||||
return PTR_ERR(wrp->regmap);
|
||||
if (IS_ERR(wrp->regmap)) {
|
||||
ret = PTR_ERR(wrp->regmap);
|
||||
goto err_out2;
|
||||
}
|
||||
|
||||
ret = of_platform_populate(np, NULL, NULL, wrp->dev);
|
||||
if (ret) {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/soc/mediatek/infracfg.h>
|
||||
|
||||
#include <dt-bindings/power/mt2701-power.h>
|
||||
#include <dt-bindings/power/mt6797-power.h>
|
||||
#include <dt-bindings/power/mt8173-power.h>
|
||||
|
||||
#define SPM_VDE_PWR_CON 0x0210
|
||||
|
|
@ -71,6 +72,7 @@ enum clk_id {
|
|||
CLK_VENC,
|
||||
CLK_VENC_LT,
|
||||
CLK_ETHIF,
|
||||
CLK_VDEC,
|
||||
CLK_MAX,
|
||||
};
|
||||
|
||||
|
|
@ -81,6 +83,7 @@ static const char * const clk_names[] = {
|
|||
"venc",
|
||||
"venc_lt",
|
||||
"ethif",
|
||||
"vdec",
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
@ -107,21 +110,28 @@ struct scp_domain {
|
|||
struct regulator *supply;
|
||||
};
|
||||
|
||||
struct scp_ctrl_reg {
|
||||
int pwr_sta_offs;
|
||||
int pwr_sta2nd_offs;
|
||||
};
|
||||
|
||||
struct scp {
|
||||
struct scp_domain *domains;
|
||||
struct genpd_onecell_data pd_data;
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct regmap *infracfg;
|
||||
struct scp_ctrl_reg ctrl_reg;
|
||||
};
|
||||
|
||||
static int scpsys_domain_is_on(struct scp_domain *scpd)
|
||||
{
|
||||
struct scp *scp = scpd->scp;
|
||||
|
||||
u32 status = readl(scp->base + SPM_PWR_STATUS) & scpd->data->sta_mask;
|
||||
u32 status2 = readl(scp->base + SPM_PWR_STATUS_2ND) &
|
||||
scpd->data->sta_mask;
|
||||
u32 status = readl(scp->base + scp->ctrl_reg.pwr_sta_offs) &
|
||||
scpd->data->sta_mask;
|
||||
u32 status2 = readl(scp->base + scp->ctrl_reg.pwr_sta2nd_offs) &
|
||||
scpd->data->sta_mask;
|
||||
|
||||
/*
|
||||
* A domain is on when both status bits are set. If only one is set
|
||||
|
|
@ -346,7 +356,8 @@ static void init_clks(struct platform_device *pdev, struct clk **clk)
|
|||
}
|
||||
|
||||
static struct scp *init_scp(struct platform_device *pdev,
|
||||
const struct scp_domain_data *scp_domain_data, int num)
|
||||
const struct scp_domain_data *scp_domain_data, int num,
|
||||
struct scp_ctrl_reg *scp_ctrl_reg)
|
||||
{
|
||||
struct genpd_onecell_data *pd_data;
|
||||
struct resource *res;
|
||||
|
|
@ -358,6 +369,9 @@ static struct scp *init_scp(struct platform_device *pdev,
|
|||
if (!scp)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
scp->ctrl_reg.pwr_sta_offs = scp_ctrl_reg->pwr_sta_offs;
|
||||
scp->ctrl_reg.pwr_sta2nd_offs = scp_ctrl_reg->pwr_sta2nd_offs;
|
||||
|
||||
scp->dev = &pdev->dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
|
@ -556,8 +570,13 @@ static const struct scp_domain_data scp_domain_data_mt2701[] = {
|
|||
static int __init scpsys_probe_mt2701(struct platform_device *pdev)
|
||||
{
|
||||
struct scp *scp;
|
||||
struct scp_ctrl_reg scp_reg;
|
||||
|
||||
scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701);
|
||||
scp_reg.pwr_sta_offs = SPM_PWR_STATUS;
|
||||
scp_reg.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND;
|
||||
|
||||
scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701,
|
||||
&scp_reg);
|
||||
if (IS_ERR(scp))
|
||||
return PTR_ERR(scp);
|
||||
|
||||
|
|
@ -566,6 +585,116 @@ static int __init scpsys_probe_mt2701(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* MT6797 power domain support
|
||||
*/
|
||||
|
||||
static const struct scp_domain_data scp_domain_data_mt6797[] = {
|
||||
[MT6797_POWER_DOMAIN_VDEC] = {
|
||||
.name = "vdec",
|
||||
.sta_mask = BIT(7),
|
||||
.ctl_offs = 0x300,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.clk_id = {CLK_VDEC},
|
||||
},
|
||||
[MT6797_POWER_DOMAIN_VENC] = {
|
||||
.name = "venc",
|
||||
.sta_mask = BIT(21),
|
||||
.ctl_offs = 0x304,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(15, 12),
|
||||
.clk_id = {CLK_NONE},
|
||||
},
|
||||
[MT6797_POWER_DOMAIN_ISP] = {
|
||||
.name = "isp",
|
||||
.sta_mask = BIT(5),
|
||||
.ctl_offs = 0x308,
|
||||
.sram_pdn_bits = GENMASK(9, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(13, 12),
|
||||
.clk_id = {CLK_NONE},
|
||||
},
|
||||
[MT6797_POWER_DOMAIN_MM] = {
|
||||
.name = "mm",
|
||||
.sta_mask = BIT(3),
|
||||
.ctl_offs = 0x30C,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.clk_id = {CLK_MM},
|
||||
.bus_prot_mask = (BIT(1) | BIT(2)),
|
||||
},
|
||||
[MT6797_POWER_DOMAIN_AUDIO] = {
|
||||
.name = "audio",
|
||||
.sta_mask = BIT(24),
|
||||
.ctl_offs = 0x314,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(15, 12),
|
||||
.clk_id = {CLK_NONE},
|
||||
},
|
||||
[MT6797_POWER_DOMAIN_MFG_ASYNC] = {
|
||||
.name = "mfg_async",
|
||||
.sta_mask = BIT(13),
|
||||
.ctl_offs = 0x334,
|
||||
.sram_pdn_bits = 0,
|
||||
.sram_pdn_ack_bits = 0,
|
||||
.clk_id = {CLK_MFG},
|
||||
},
|
||||
[MT6797_POWER_DOMAIN_MJC] = {
|
||||
.name = "mjc",
|
||||
.sta_mask = BIT(20),
|
||||
.ctl_offs = 0x310,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.clk_id = {CLK_NONE},
|
||||
},
|
||||
};
|
||||
|
||||
#define NUM_DOMAINS_MT6797 ARRAY_SIZE(scp_domain_data_mt6797)
|
||||
#define SPM_PWR_STATUS_MT6797 0x0180
|
||||
#define SPM_PWR_STATUS_2ND_MT6797 0x0184
|
||||
|
||||
static int __init scpsys_probe_mt6797(struct platform_device *pdev)
|
||||
{
|
||||
struct scp *scp;
|
||||
struct genpd_onecell_data *pd_data;
|
||||
int ret;
|
||||
struct scp_ctrl_reg scp_reg;
|
||||
|
||||
scp_reg.pwr_sta_offs = SPM_PWR_STATUS_MT6797;
|
||||
scp_reg.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND_MT6797;
|
||||
|
||||
scp = init_scp(pdev, scp_domain_data_mt6797, NUM_DOMAINS_MT6797,
|
||||
&scp_reg);
|
||||
if (IS_ERR(scp))
|
||||
return PTR_ERR(scp);
|
||||
|
||||
mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT6797);
|
||||
|
||||
pd_data = &scp->pd_data;
|
||||
|
||||
ret = pm_genpd_add_subdomain(pd_data->domains[MT6797_POWER_DOMAIN_MM],
|
||||
pd_data->domains[MT6797_POWER_DOMAIN_VDEC]);
|
||||
if (ret && IS_ENABLED(CONFIG_PM))
|
||||
dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
|
||||
|
||||
ret = pm_genpd_add_subdomain(pd_data->domains[MT6797_POWER_DOMAIN_MM],
|
||||
pd_data->domains[MT6797_POWER_DOMAIN_ISP]);
|
||||
if (ret && IS_ENABLED(CONFIG_PM))
|
||||
dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
|
||||
|
||||
ret = pm_genpd_add_subdomain(pd_data->domains[MT6797_POWER_DOMAIN_MM],
|
||||
pd_data->domains[MT6797_POWER_DOMAIN_VENC]);
|
||||
if (ret && IS_ENABLED(CONFIG_PM))
|
||||
dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
|
||||
|
||||
ret = pm_genpd_add_subdomain(pd_data->domains[MT6797_POWER_DOMAIN_MM],
|
||||
pd_data->domains[MT6797_POWER_DOMAIN_MJC]);
|
||||
if (ret && IS_ENABLED(CONFIG_PM))
|
||||
dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* MT8173 power domain support
|
||||
*/
|
||||
|
|
@ -667,8 +796,13 @@ static int __init scpsys_probe_mt8173(struct platform_device *pdev)
|
|||
struct scp *scp;
|
||||
struct genpd_onecell_data *pd_data;
|
||||
int ret;
|
||||
struct scp_ctrl_reg scp_reg;
|
||||
|
||||
scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173);
|
||||
scp_reg.pwr_sta_offs = SPM_PWR_STATUS;
|
||||
scp_reg.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND;
|
||||
|
||||
scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173,
|
||||
&scp_reg);
|
||||
if (IS_ERR(scp))
|
||||
return PTR_ERR(scp);
|
||||
|
||||
|
|
@ -697,6 +831,9 @@ static const struct of_device_id of_scpsys_match_tbl[] = {
|
|||
{
|
||||
.compatible = "mediatek,mt2701-scpsys",
|
||||
.data = scpsys_probe_mt2701,
|
||||
}, {
|
||||
.compatible = "mediatek,mt6797-scpsys",
|
||||
.data = scpsys_probe_mt6797,
|
||||
}, {
|
||||
.compatible = "mediatek,mt8173-scpsys",
|
||||
.data = scpsys_probe_mt8173,
|
||||
|
|
|
|||
|
|
@ -439,14 +439,15 @@ static int smsm_get_size_info(struct qcom_smsm *smsm)
|
|||
} *info;
|
||||
|
||||
info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_SMSM_SIZE_INFO, &size);
|
||||
if (PTR_ERR(info) == -ENOENT || size != sizeof(*info)) {
|
||||
if (IS_ERR(info) && PTR_ERR(info) != -ENOENT) {
|
||||
if (PTR_ERR(info) != -EPROBE_DEFER)
|
||||
dev_err(smsm->dev, "unable to retrieve smsm size info\n");
|
||||
return PTR_ERR(info);
|
||||
} else if (IS_ERR(info) || size != sizeof(*info)) {
|
||||
dev_warn(smsm->dev, "no smsm size info, using defaults\n");
|
||||
smsm->num_entries = SMSM_DEFAULT_NUM_ENTRIES;
|
||||
smsm->num_hosts = SMSM_DEFAULT_NUM_HOSTS;
|
||||
return 0;
|
||||
} else if (IS_ERR(info)) {
|
||||
dev_err(smsm->dev, "unable to retrieve smsm size info\n");
|
||||
return PTR_ERR(info);
|
||||
}
|
||||
|
||||
smsm->num_entries = info->num_entries;
|
||||
|
|
|
|||
63
drivers/soc/renesas/Kconfig
Normal file
63
drivers/soc/renesas/Kconfig
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
config SOC_RENESAS
|
||||
bool "Renesas SoC driver support" if COMPILE_TEST && !ARCH_RENESAS
|
||||
default y if ARCH_RENESAS
|
||||
select SOC_BUS
|
||||
select RST_RCAR if ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || \
|
||||
ARCH_R8A7795 || ARCH_R8A7796
|
||||
select SYSC_R8A7743 if ARCH_R8A7743
|
||||
select SYSC_R8A7745 if ARCH_R8A7745
|
||||
select SYSC_R8A7779 if ARCH_R8A7779
|
||||
select SYSC_R8A7790 if ARCH_R8A7790
|
||||
select SYSC_R8A7791 if ARCH_R8A7791 || ARCH_R8A7793
|
||||
select SYSC_R8A7792 if ARCH_R8A7792
|
||||
select SYSC_R8A7794 if ARCH_R8A7794
|
||||
select SYSC_R8A7795 if ARCH_R8A7795
|
||||
select SYSC_R8A7796 if ARCH_R8A7796
|
||||
|
||||
if SOC_RENESAS
|
||||
|
||||
# SoC
|
||||
config SYSC_R8A7743
|
||||
bool "RZ/G1M System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7745
|
||||
bool "RZ/G1E System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7779
|
||||
bool "R-Car H1 System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7790
|
||||
bool "R-Car H2 System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7791
|
||||
bool "R-Car M2-W/N System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7792
|
||||
bool "R-Car V2H System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7794
|
||||
bool "R-Car E2 System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7795
|
||||
bool "R-Car H3 System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7796
|
||||
bool "R-Car M3-W System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
# Family
|
||||
config RST_RCAR
|
||||
bool "R-Car Reset Controller support" if COMPILE_TEST
|
||||
|
||||
config SYSC_RCAR
|
||||
bool "R-Car System Controller support" if COMPILE_TEST
|
||||
|
||||
endif # SOC_RENESAS
|
||||
|
|
@ -1,18 +1,17 @@
|
|||
obj-$(CONFIG_SOC_BUS) += renesas-soc.o
|
||||
# Generic, must be first because of soc_device_register()
|
||||
obj-$(CONFIG_SOC_RENESAS) += renesas-soc.o
|
||||
|
||||
obj-$(CONFIG_ARCH_RCAR_GEN1) += rcar-rst.o
|
||||
obj-$(CONFIG_ARCH_RCAR_GEN2) += rcar-rst.o
|
||||
obj-$(CONFIG_ARCH_R8A7795) += rcar-rst.o
|
||||
obj-$(CONFIG_ARCH_R8A7796) += rcar-rst.o
|
||||
# SoC
|
||||
obj-$(CONFIG_SYSC_R8A7743) += r8a7743-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A7745) += r8a7745-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A7779) += r8a7779-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A7790) += r8a7790-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A7791) += r8a7791-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A7792) += r8a7792-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A7794) += r8a7794-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A7795) += r8a7795-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A7796) += r8a7796-sysc.o
|
||||
|
||||
obj-$(CONFIG_ARCH_R8A7743) += rcar-sysc.o r8a7743-sysc.o
|
||||
obj-$(CONFIG_ARCH_R8A7745) += rcar-sysc.o r8a7745-sysc.o
|
||||
obj-$(CONFIG_ARCH_R8A7779) += rcar-sysc.o r8a7779-sysc.o
|
||||
obj-$(CONFIG_ARCH_R8A7790) += rcar-sysc.o r8a7790-sysc.o
|
||||
obj-$(CONFIG_ARCH_R8A7791) += rcar-sysc.o r8a7791-sysc.o
|
||||
obj-$(CONFIG_ARCH_R8A7792) += rcar-sysc.o r8a7792-sysc.o
|
||||
# R-Car M2-N is identical to R-Car M2-W w.r.t. power domains.
|
||||
obj-$(CONFIG_ARCH_R8A7793) += rcar-sysc.o r8a7791-sysc.o
|
||||
obj-$(CONFIG_ARCH_R8A7794) += rcar-sysc.o r8a7794-sysc.o
|
||||
obj-$(CONFIG_ARCH_R8A7795) += rcar-sysc.o r8a7795-sysc.o
|
||||
obj-$(CONFIG_ARCH_R8A7796) += rcar-sysc.o r8a7796-sysc.o
|
||||
# Family
|
||||
obj-$(CONFIG_RST_RCAR) += rcar-rst.o
|
||||
obj-$(CONFIG_SYSC_RCAR) += rcar-sysc.o
|
||||
|
|
|
|||
|
|
@ -181,17 +181,6 @@ static int rcar_sysc_pd_power_off(struct generic_pm_domain *genpd)
|
|||
struct rcar_sysc_pd *pd = to_rcar_pd(genpd);
|
||||
|
||||
pr_debug("%s: %s\n", __func__, genpd->name);
|
||||
|
||||
if (pd->flags & PD_NO_CR) {
|
||||
pr_debug("%s: Cannot control %s\n", __func__, genpd->name);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (pd->flags & PD_BUSY) {
|
||||
pr_debug("%s: %s busy\n", __func__, genpd->name);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return rcar_sysc_power_down(&pd->ch);
|
||||
}
|
||||
|
||||
|
|
@ -200,12 +189,6 @@ static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd)
|
|||
struct rcar_sysc_pd *pd = to_rcar_pd(genpd);
|
||||
|
||||
pr_debug("%s: %s\n", __func__, genpd->name);
|
||||
|
||||
if (pd->flags & PD_NO_CR) {
|
||||
pr_debug("%s: Cannot control %s\n", __func__, genpd->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return rcar_sysc_power_up(&pd->ch);
|
||||
}
|
||||
|
||||
|
|
@ -223,8 +206,7 @@ static void __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd)
|
|||
* only be turned off if the CPU is not in use.
|
||||
*/
|
||||
pr_debug("PM domain %s contains %s\n", name, "CPU");
|
||||
pd->flags |= PD_BUSY;
|
||||
gov = &pm_domain_always_on_gov;
|
||||
genpd->flags |= GENPD_FLAG_ALWAYS_ON;
|
||||
} else if (pd->flags & PD_SCU) {
|
||||
/*
|
||||
* This domain contains an SCU and cache-controller, and
|
||||
|
|
@ -232,19 +214,17 @@ static void __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd)
|
|||
* not in use.
|
||||
*/
|
||||
pr_debug("PM domain %s contains %s\n", name, "SCU");
|
||||
pd->flags |= PD_BUSY;
|
||||
gov = &pm_domain_always_on_gov;
|
||||
genpd->flags |= GENPD_FLAG_ALWAYS_ON;
|
||||
} else if (pd->flags & PD_NO_CR) {
|
||||
/*
|
||||
* This domain cannot be turned off.
|
||||
*/
|
||||
pd->flags |= PD_BUSY;
|
||||
gov = &pm_domain_always_on_gov;
|
||||
genpd->flags |= GENPD_FLAG_ALWAYS_ON;
|
||||
}
|
||||
|
||||
if (!(pd->flags & (PD_CPU | PD_SCU))) {
|
||||
/* Enable Clock Domain for I/O devices */
|
||||
genpd->flags = GENPD_FLAG_PM_CLK;
|
||||
genpd->flags |= GENPD_FLAG_PM_CLK;
|
||||
if (has_cpg_mstp) {
|
||||
genpd->attach_dev = cpg_mstp_attach_dev;
|
||||
genpd->detach_dev = cpg_mstp_detach_dev;
|
||||
|
|
@ -275,35 +255,33 @@ finalize:
|
|||
}
|
||||
|
||||
static const struct of_device_id rcar_sysc_matches[] = {
|
||||
#ifdef CONFIG_ARCH_R8A7743
|
||||
#ifdef CONFIG_SYSC_R8A7743
|
||||
{ .compatible = "renesas,r8a7743-sysc", .data = &r8a7743_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_R8A7745
|
||||
#ifdef CONFIG_SYSC_R8A7745
|
||||
{ .compatible = "renesas,r8a7745-sysc", .data = &r8a7745_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_R8A7779
|
||||
#ifdef CONFIG_SYSC_R8A7779
|
||||
{ .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_R8A7790
|
||||
#ifdef CONFIG_SYSC_R8A7790
|
||||
{ .compatible = "renesas,r8a7790-sysc", .data = &r8a7790_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_R8A7791
|
||||
#ifdef CONFIG_SYSC_R8A7791
|
||||
{ .compatible = "renesas,r8a7791-sysc", .data = &r8a7791_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_R8A7792
|
||||
{ .compatible = "renesas,r8a7792-sysc", .data = &r8a7792_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_R8A7793
|
||||
/* R-Car M2-N is identical to R-Car M2-W w.r.t. power domains. */
|
||||
{ .compatible = "renesas,r8a7793-sysc", .data = &r8a7791_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_R8A7794
|
||||
#ifdef CONFIG_SYSC_R8A7792
|
||||
{ .compatible = "renesas,r8a7792-sysc", .data = &r8a7792_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_SYSC_R8A7794
|
||||
{ .compatible = "renesas,r8a7794-sysc", .data = &r8a7794_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_R8A7795
|
||||
#ifdef CONFIG_SYSC_R8A7795
|
||||
{ .compatible = "renesas,r8a7795-sysc", .data = &r8a7795_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_R8A7796
|
||||
#ifdef CONFIG_SYSC_R8A7796
|
||||
{ .compatible = "renesas,r8a7796-sysc", .data = &r8a7796_sysc_info },
|
||||
#endif
|
||||
{ /* sentinel */ }
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
#define PD_SCU BIT(1) /* Area contains SCU and L2 cache */
|
||||
#define PD_NO_CR BIT(2) /* Area lacks PWR{ON,OFF}CR registers */
|
||||
|
||||
#define PD_BUSY BIT(3) /* Busy, for internal use only */
|
||||
|
||||
#define PD_CPU_CR PD_CPU /* CPU area has CR (R-Car H1) */
|
||||
#define PD_CPU_NOCR PD_CPU | PD_NO_CR /* CPU area lacks CR (R-Car Gen2/3) */
|
||||
#define PD_ALWAYS_ON PD_NO_CR /* Always-on area */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in a new issue