mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-29 17:23:36 +00:00
ARM: SoC-related driver updates
Various driver updates for platforms and a couple of the small driver subsystems we merge through our tree: Among the larger pieces: - Power management improvements for TI am335x and am437x (RTC suspend/wake) - Misc new additions for Amlogic (socinfo updates) - ZynqMP FPGA manager - Nvidia improvements for reset/powergate handling - PMIC wrapper for Mediatek MT8516 - Misc fixes/improvements for ARM SCMI, TEE, NXP i.MX SCU drivers -----BEGIN PGP SIGNATURE----- iQJDBAABCAAtFiEElf+HevZ4QCAJmMQ+jBrnPN6EHHcFAlzc+9QPHG9sb2ZAbGl4 b20ubmV0AAoJEIwa5zzehBx3o3sQAIJ2SZnITy/ycvkbhKe+V/806P+aoqMpbZDw 7ldBQFoIMQqVIoeSSeml+9B86ZGyK4CGTgnvsfAI/Zt2fZSHczjqLP5InbEnvB5M 4naf0nSjSlkb5F4p24wXQ7WTI8IO45SwqG4hCi/WW6MakxN21cwdMWHBn+TRZWQu +AlJdwyDFJoMRXcq8xvLHOBNVAqD3LyvlECbLKqn3+UPwwYw0Ti1dsLwaMLOYDbc o/1dC2O8111kg2DgO0OM4Tl7jdbpmGA5MeixbVnmu3t4b2s26trG33eXqK2yWqaV XigD85R74GAq/wmgnzjdiNaIgZjlPPitVYaTE4L6Od39zMgXemnsqMlh/byPeO2y JvRRLEIciNay9q9uq+8H2zRWwa2wLqAewjssTTMM0RJNQWUtonVCkD8DAx4GLDof 6Ej42XGbtxnqpf0g854mBJ4zaPfZLN4xK//1Llx9HkM8mhLZLJ7BQvgvW1JzniSa XKnmjqK7SySiJ4bbjn+aFk5EkX7Oh5aXno18tVNKXdxc8nWoEw4PHMUmCCHOFPye /1oxc95Ux8P/lV+B0ZjiI0yTAX/IpDkEszAYmgdy6pWh1hXnYUr/Rpm7cGUG8kzk SbtyB8JOI/DFQ7QMDfPp6e6bcB8zTbUuF9H2MXwPN5TqGzP/mya88DC5Iv1jY4jc 0oWv/uhj =YSfu -----END PGP SIGNATURE----- Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc Pull ARM SoC-related driver updates from Olof Johansson: "Various driver updates for platforms and a couple of the small driver subsystems we merge through our tree: Among the larger pieces: - Power management improvements for TI am335x and am437x (RTC suspend/wake) - Misc new additions for Amlogic (socinfo updates) - ZynqMP FPGA manager - Nvidia improvements for reset/powergate handling - PMIC wrapper for Mediatek MT8516 - Misc fixes/improvements for ARM SCMI, TEE, NXP i.MX SCU drivers" * tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (57 commits) soc: aspeed: fix Kconfig soc: add aspeed folder and misc drivers spi: zynqmp: Fix build break soc: imx: Add generic i.MX8 SoC driver MAINTAINERS: Update email for Qualcomm SoC maintainer memory: tegra: Fix a typos for "fdcdwr2" mc client Revert "ARM: tegra: Restore memory arbitration on resume from LP1 on Tegra30+" memory: tegra: Replace readl-writel with mc_readl-mc_writel memory: tegra: Fix integer overflow on tick value calculation memory: tegra: Fix missed registers values latching ARM: tegra: cpuidle: Handle tick broadcasting within cpuidle core on Tegra20/30 optee: allow to work without static shared memory soc/tegra: pmc: Move powergate initialisation to probe soc/tegra: pmc: Remove reset sysfs entries on error soc/tegra: pmc: Fix reset sources and levels soc: amlogic: meson-gx-pwrc-vpu: Add support for G12A soc: amlogic: meson-gx-pwrc-vpu: Fix power on/off register bitmask fpga manager: Adding FPGA Manager support for Xilinx zynqmp dt-bindings: fpga: Add bindings for ZynqMP fpga driver firmware: xilinx: Add fpga API's ...
This commit is contained in:
commit
dc413a90ed
@ -0,0 +1,25 @@
|
||||
Devicetree bindings for Zynq Ultrascale MPSoC FPGA Manager.
|
||||
The ZynqMP SoC uses the PCAP (Processor configuration Port) to configure the
|
||||
Programmable Logic (PL). The configuration uses the firmware interface.
|
||||
|
||||
Required properties:
|
||||
- compatible: should contain "xlnx,zynqmp-pcap-fpga"
|
||||
|
||||
Example for full FPGA configuration:
|
||||
|
||||
fpga-region0 {
|
||||
compatible = "fpga-region";
|
||||
fpga-mgr = <&zynqmp_pcap>;
|
||||
#address-cells = <0x1>;
|
||||
#size-cells = <0x1>;
|
||||
};
|
||||
|
||||
firmware {
|
||||
zynqmp_firmware: zynqmp-firmware {
|
||||
compatible = "xlnx,zynqmp-firmware";
|
||||
method = "smc";
|
||||
zynqmp_pcap: pcap {
|
||||
compatible = "xlnx,zynqmp-pcap-fpga";
|
||||
};
|
||||
};
|
||||
};
|
@ -25,6 +25,7 @@ Required properties in pwrap device node.
|
||||
"mediatek,mt8135-pwrap" for MT8135 SoCs
|
||||
"mediatek,mt8173-pwrap" for MT8173 SoCs
|
||||
"mediatek,mt8183-pwrap" for MT8183 SoCs
|
||||
"mediatek,mt8516-pwrap" for MT8516 SoCs
|
||||
- interrupts: IRQ for pwrap in SOC
|
||||
- reg-names: Must include the following entries:
|
||||
"pwrap": Main registers base
|
||||
|
@ -41,8 +41,8 @@ Example of EEMI ops usage:
|
||||
int ret;
|
||||
|
||||
eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
if (!eemi_ops)
|
||||
return -ENXIO;
|
||||
if (IS_ERR(eemi_ops))
|
||||
return PTR_ERR(eemi_ops);
|
||||
|
||||
ret = eemi_ops->query_data(qdata, ret_payload);
|
||||
|
||||
|
@ -2043,7 +2043,7 @@ W: http://www.armlinux.org.uk/
|
||||
S: Maintained
|
||||
|
||||
ARM/QUALCOMM SUPPORT
|
||||
M: Andy Gross <andy.gross@linaro.org>
|
||||
M: Andy Gross <agross@kernel.org>
|
||||
M: David Brown <david.brown@linaro.org>
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
S: Maintained
|
||||
|
@ -10,6 +10,12 @@
|
||||
#include <asm/suspend.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/platform_data/pm33xx.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_data/gpio-omap.h>
|
||||
#include <linux/pinctrl/pinmux.h>
|
||||
#include <linux/wkup_m3_ipc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#include "cm33xx.h"
|
||||
#include "common.h"
|
||||
@ -38,6 +44,29 @@ static int am43xx_map_scu(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int am33xx_check_off_mode_enable(void)
|
||||
{
|
||||
if (enable_off_mode)
|
||||
pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n");
|
||||
|
||||
/* off mode not supported on am335x so return 0 always */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int am43xx_check_off_mode_enable(void)
|
||||
{
|
||||
/*
|
||||
* Check for am437x-gp-evm which has the right Hardware design to
|
||||
* support this mode reliably.
|
||||
*/
|
||||
if (of_machine_is_compatible("ti,am437x-gp-evm") && enable_off_mode)
|
||||
return enable_off_mode;
|
||||
else if (enable_off_mode)
|
||||
pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amx3_common_init(void)
|
||||
{
|
||||
gfx_pwrdm = pwrdm_lookup("gfx_pwrdm");
|
||||
@ -141,7 +170,9 @@ static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long),
|
||||
scu_power_mode(scu_base, SCU_PM_POWEROFF);
|
||||
ret = cpu_suspend(args, fn);
|
||||
scu_power_mode(scu_base, SCU_PM_NORMAL);
|
||||
amx3_post_suspend_common();
|
||||
|
||||
if (!am43xx_check_off_mode_enable())
|
||||
amx3_post_suspend_common();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -163,10 +194,48 @@ void __iomem *am43xx_get_rtc_base_addr(void)
|
||||
return omap_hwmod_get_mpu_rt_va(rtc_oh);
|
||||
}
|
||||
|
||||
static void am43xx_save_context(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void am33xx_save_context(void)
|
||||
{
|
||||
omap_intc_save_context();
|
||||
}
|
||||
|
||||
static void am33xx_restore_context(void)
|
||||
{
|
||||
omap_intc_restore_context();
|
||||
}
|
||||
|
||||
static void am43xx_restore_context(void)
|
||||
{
|
||||
/*
|
||||
* HACK: restore dpll_per_clkdcoldo register contents, to avoid
|
||||
* breaking suspend-resume
|
||||
*/
|
||||
writel_relaxed(0x0, AM33XX_L4_WK_IO_ADDRESS(0x44df2e14));
|
||||
}
|
||||
|
||||
static void am43xx_prepare_rtc_suspend(void)
|
||||
{
|
||||
omap_hwmod_enable(rtc_oh);
|
||||
}
|
||||
|
||||
static void am43xx_prepare_rtc_resume(void)
|
||||
{
|
||||
omap_hwmod_idle(rtc_oh);
|
||||
}
|
||||
|
||||
static struct am33xx_pm_platform_data am33xx_ops = {
|
||||
.init = am33xx_suspend_init,
|
||||
.soc_suspend = am33xx_suspend,
|
||||
.get_sram_addrs = amx3_get_sram_addrs,
|
||||
.save_context = am33xx_save_context,
|
||||
.restore_context = am33xx_restore_context,
|
||||
.prepare_rtc_suspend = am43xx_prepare_rtc_suspend,
|
||||
.prepare_rtc_resume = am43xx_prepare_rtc_resume,
|
||||
.check_off_mode_enable = am33xx_check_off_mode_enable,
|
||||
.get_rtc_base_addr = am43xx_get_rtc_base_addr,
|
||||
};
|
||||
|
||||
@ -174,6 +243,11 @@ static struct am33xx_pm_platform_data am43xx_ops = {
|
||||
.init = am43xx_suspend_init,
|
||||
.soc_suspend = am43xx_suspend,
|
||||
.get_sram_addrs = amx3_get_sram_addrs,
|
||||
.save_context = am43xx_save_context,
|
||||
.restore_context = am43xx_restore_context,
|
||||
.prepare_rtc_suspend = am43xx_prepare_rtc_suspend,
|
||||
.prepare_rtc_resume = am43xx_prepare_rtc_resume,
|
||||
.check_off_mode_enable = am43xx_check_off_mode_enable,
|
||||
.get_rtc_base_addr = am43xx_get_rtc_base_addr,
|
||||
};
|
||||
|
||||
|
@ -368,6 +368,9 @@ wait_emif_enable1:
|
||||
mov r1, #AM43XX_EMIF_POWEROFF_DISABLE
|
||||
str r1, [r2, #0x0]
|
||||
|
||||
ldr r1, [r9, #EMIF_PM_RUN_HW_LEVELING]
|
||||
blx r1
|
||||
|
||||
#ifdef CONFIG_CACHE_L2X0
|
||||
ldr r2, l2_cache_base
|
||||
ldr r0, [r2, #L2X0_CTRL]
|
||||
|
@ -10,6 +10,7 @@ menuconfig ARCH_TEGRA
|
||||
select HAVE_ARM_SCU if SMP
|
||||
select HAVE_ARM_TWD if SMP
|
||||
select PINCTRL
|
||||
select PM
|
||||
select PM_OPP
|
||||
select RESET_CONTROLLER
|
||||
select SOC_BUS
|
||||
|
@ -61,7 +61,8 @@ static struct cpuidle_driver tegra_idle_driver = {
|
||||
.exit_latency = 5000,
|
||||
.target_residency = 10000,
|
||||
.power_usage = 0,
|
||||
.flags = CPUIDLE_FLAG_COUPLED,
|
||||
.flags = CPUIDLE_FLAG_COUPLED |
|
||||
CPUIDLE_FLAG_TIMER_STOP,
|
||||
.name = "powered-down",
|
||||
.desc = "CPU power gated",
|
||||
},
|
||||
@ -136,12 +137,8 @@ static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev,
|
||||
if (tegra20_reset_cpu_1() || !tegra_cpu_rail_off_ready())
|
||||
return false;
|
||||
|
||||
tick_broadcast_enter();
|
||||
|
||||
tegra_idle_lp2_last();
|
||||
|
||||
tick_broadcast_exit();
|
||||
|
||||
if (cpu_online(1))
|
||||
tegra20_wake_cpu1_from_reset();
|
||||
|
||||
@ -153,14 +150,10 @@ static bool tegra20_idle_enter_lp2_cpu_1(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv,
|
||||
int index)
|
||||
{
|
||||
tick_broadcast_enter();
|
||||
|
||||
cpu_suspend(0, tegra20_sleep_cpu_secondary_finish);
|
||||
|
||||
tegra20_cpu_clear_resettable();
|
||||
|
||||
tick_broadcast_exit();
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
|
@ -56,6 +56,7 @@ static struct cpuidle_driver tegra_idle_driver = {
|
||||
.exit_latency = 2000,
|
||||
.target_residency = 2200,
|
||||
.power_usage = 0,
|
||||
.flags = CPUIDLE_FLAG_TIMER_STOP,
|
||||
.name = "powered-down",
|
||||
.desc = "CPU power gated",
|
||||
},
|
||||
@ -76,12 +77,8 @@ static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
|
||||
return false;
|
||||
}
|
||||
|
||||
tick_broadcast_enter();
|
||||
|
||||
tegra_idle_lp2_last();
|
||||
|
||||
tick_broadcast_exit();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -90,14 +87,10 @@ static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv,
|
||||
int index)
|
||||
{
|
||||
tick_broadcast_enter();
|
||||
|
||||
smp_wmb();
|
||||
|
||||
cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
|
||||
|
||||
tick_broadcast_exit();
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
|
@ -79,24 +79,15 @@
|
||||
#define TEGRA_PMC_BASE 0x7000E400
|
||||
#define TEGRA_PMC_SIZE SZ_256
|
||||
|
||||
#define TEGRA_MC_BASE 0x7000F000
|
||||
#define TEGRA_MC_SIZE SZ_1K
|
||||
|
||||
#define TEGRA_EMC_BASE 0x7000F400
|
||||
#define TEGRA_EMC_SIZE SZ_1K
|
||||
|
||||
#define TEGRA114_MC_BASE 0x70019000
|
||||
#define TEGRA114_MC_SIZE SZ_4K
|
||||
|
||||
#define TEGRA_EMC0_BASE 0x7001A000
|
||||
#define TEGRA_EMC0_SIZE SZ_2K
|
||||
|
||||
#define TEGRA_EMC1_BASE 0x7001A800
|
||||
#define TEGRA_EMC1_SIZE SZ_2K
|
||||
|
||||
#define TEGRA124_MC_BASE 0x70019000
|
||||
#define TEGRA124_MC_SIZE SZ_4K
|
||||
|
||||
#define TEGRA124_EMC_BASE 0x7001B000
|
||||
#define TEGRA124_EMC_SIZE SZ_2K
|
||||
|
||||
|
@ -44,8 +44,6 @@
|
||||
#define EMC_XM2VTTGENPADCTRL 0x310
|
||||
#define EMC_XM2VTTGENPADCTRL2 0x314
|
||||
|
||||
#define MC_EMEM_ARB_CFG 0x90
|
||||
|
||||
#define PMC_CTRL 0x0
|
||||
#define PMC_CTRL_SIDE_EFFECT_LP0 (1 << 14) /* enter LP0 when CPU pwr gated */
|
||||
|
||||
@ -420,22 +418,6 @@ _pll_m_c_x_done:
|
||||
movweq r0, #:lower16:TEGRA124_EMC_BASE
|
||||
movteq r0, #:upper16:TEGRA124_EMC_BASE
|
||||
|
||||
cmp r10, #TEGRA30
|
||||
moveq r2, #0x20
|
||||
movweq r4, #:lower16:TEGRA_MC_BASE
|
||||
movteq r4, #:upper16:TEGRA_MC_BASE
|
||||
cmp r10, #TEGRA114
|
||||
moveq r2, #0x34
|
||||
movweq r4, #:lower16:TEGRA114_MC_BASE
|
||||
movteq r4, #:upper16:TEGRA114_MC_BASE
|
||||
cmp r10, #TEGRA124
|
||||
moveq r2, #0x20
|
||||
movweq r4, #:lower16:TEGRA124_MC_BASE
|
||||
movteq r4, #:upper16:TEGRA124_MC_BASE
|
||||
|
||||
ldr r1, [r5, r2] @ restore MC_EMEM_ARB_CFG
|
||||
str r1, [r4, #MC_EMEM_ARB_CFG]
|
||||
|
||||
exit_self_refresh:
|
||||
ldr r1, [r5, #0xC] @ restore EMC_XM2VTTGENPADCTRL
|
||||
str r1, [r0, #EMC_XM2VTTGENPADCTRL]
|
||||
@ -564,7 +546,6 @@ tegra30_sdram_pad_address:
|
||||
.word TEGRA_PMC_BASE + PMC_IO_DPD_STATUS @0x14
|
||||
.word TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT @0x18
|
||||
.word TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST @0x1c
|
||||
.word TEGRA_MC_BASE + MC_EMEM_ARB_CFG @0x20
|
||||
tegra30_sdram_pad_address_end:
|
||||
|
||||
tegra114_sdram_pad_address:
|
||||
@ -581,7 +562,6 @@ tegra114_sdram_pad_address:
|
||||
.word TEGRA_EMC1_BASE + EMC_AUTO_CAL_INTERVAL @0x28
|
||||
.word TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL @0x2c
|
||||
.word TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL2 @0x30
|
||||
.word TEGRA114_MC_BASE + MC_EMEM_ARB_CFG @0x34
|
||||
tegra114_sdram_pad_adress_end:
|
||||
|
||||
tegra124_sdram_pad_address:
|
||||
@ -593,7 +573,6 @@ tegra124_sdram_pad_address:
|
||||
.word TEGRA_PMC_BASE + PMC_IO_DPD_STATUS @0x14
|
||||
.word TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT @0x18
|
||||
.word TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST @0x1c
|
||||
.word TEGRA124_MC_BASE + MC_EMEM_ARB_CFG @0x20
|
||||
tegra124_sdram_pad_address_end:
|
||||
|
||||
tegra30_sdram_pad_size:
|
||||
|
@ -12,28 +12,38 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_clock.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
struct tegra_aconnect {
|
||||
struct clk *ape_clk;
|
||||
struct clk *apb2ape_clk;
|
||||
};
|
||||
|
||||
static int tegra_aconnect_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct tegra_aconnect *aconnect;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
return -EINVAL;
|
||||
|
||||
ret = pm_clk_create(&pdev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
aconnect = devm_kzalloc(&pdev->dev, sizeof(struct tegra_aconnect),
|
||||
GFP_KERNEL);
|
||||
if (!aconnect)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_pm_clk_add_clk(&pdev->dev, "ape");
|
||||
if (ret)
|
||||
goto clk_destroy;
|
||||
aconnect->ape_clk = devm_clk_get(&pdev->dev, "ape");
|
||||
if (IS_ERR(aconnect->ape_clk)) {
|
||||
dev_err(&pdev->dev, "Can't retrieve ape clock\n");
|
||||
return PTR_ERR(aconnect->ape_clk);
|
||||
}
|
||||
|
||||
ret = of_pm_clk_add_clk(&pdev->dev, "apb2ape");
|
||||
if (ret)
|
||||
goto clk_destroy;
|
||||
aconnect->apb2ape_clk = devm_clk_get(&pdev->dev, "apb2ape");
|
||||
if (IS_ERR(aconnect->apb2ape_clk)) {
|
||||
dev_err(&pdev->dev, "Can't retrieve apb2ape clock\n");
|
||||
return PTR_ERR(aconnect->apb2ape_clk);
|
||||
}
|
||||
|
||||
dev_set_drvdata(&pdev->dev, aconnect);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
|
||||
@ -41,35 +51,51 @@ static int tegra_aconnect_probe(struct platform_device *pdev)
|
||||
dev_info(&pdev->dev, "Tegra ACONNECT bus registered\n");
|
||||
|
||||
return 0;
|
||||
|
||||
clk_destroy:
|
||||
pm_clk_destroy(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_aconnect_remove(struct platform_device *pdev)
|
||||
{
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
pm_clk_destroy(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_aconnect_runtime_resume(struct device *dev)
|
||||
{
|
||||
return pm_clk_resume(dev);
|
||||
struct tegra_aconnect *aconnect = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(aconnect->ape_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "ape clk_enable failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(aconnect->apb2ape_clk);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(aconnect->ape_clk);
|
||||
dev_err(dev, "apb2ape clk_enable failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_aconnect_runtime_suspend(struct device *dev)
|
||||
{
|
||||
return pm_clk_suspend(dev);
|
||||
struct tegra_aconnect *aconnect = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(aconnect->ape_clk);
|
||||
clk_disable_unprepare(aconnect->apb2ape_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops tegra_aconnect_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(tegra_aconnect_runtime_suspend,
|
||||
tegra_aconnect_runtime_resume, NULL)
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra_aconnect_of_match[] = {
|
||||
|
@ -739,8 +739,8 @@ static int zynqmp_clock_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
if (!eemi_ops)
|
||||
return -ENXIO;
|
||||
if (IS_ERR(eemi_ops))
|
||||
return PTR_ERR(eemi_ops);
|
||||
|
||||
ret = zynqmp_clk_setup(dev->of_node);
|
||||
|
||||
|
@ -654,9 +654,7 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo)
|
||||
|
||||
static int scmi_mailbox_check(struct device_node *np)
|
||||
{
|
||||
struct of_phandle_args arg;
|
||||
|
||||
return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, &arg);
|
||||
return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, NULL);
|
||||
}
|
||||
|
||||
static int scmi_mbox_free_channel(int id, void *p, void *data)
|
||||
@ -798,7 +796,9 @@ static int scmi_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
desc = of_match_device(scmi_of_match, dev)->data;
|
||||
desc = of_device_get_match_data(dev);
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
|
@ -1,3 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o
|
||||
obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o
|
||||
obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o
|
||||
|
168
drivers/firmware/imx/imx-scu-irq.c
Normal file
168
drivers/firmware/imx/imx-scu-irq.c
Normal file
@ -0,0 +1,168 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2019 NXP
|
||||
*
|
||||
* Implementation of the SCU IRQ functions using MU.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <dt-bindings/firmware/imx/rsrc.h>
|
||||
#include <linux/firmware/imx/ipc.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
|
||||
#define IMX_SC_IRQ_FUNC_ENABLE 1
|
||||
#define IMX_SC_IRQ_FUNC_STATUS 2
|
||||
#define IMX_SC_IRQ_NUM_GROUP 4
|
||||
|
||||
static u32 mu_resource_id;
|
||||
|
||||
struct imx_sc_msg_irq_get_status {
|
||||
struct imx_sc_rpc_msg hdr;
|
||||
union {
|
||||
struct {
|
||||
u16 resource;
|
||||
u8 group;
|
||||
u8 reserved;
|
||||
} __packed req;
|
||||
struct {
|
||||
u32 status;
|
||||
} resp;
|
||||
} data;
|
||||
};
|
||||
|
||||
struct imx_sc_msg_irq_enable {
|
||||
struct imx_sc_rpc_msg hdr;
|
||||
u32 mask;
|
||||
u16 resource;
|
||||
u8 group;
|
||||
u8 enable;
|
||||
} __packed;
|
||||
|
||||
static struct imx_sc_ipc *imx_sc_irq_ipc_handle;
|
||||
static struct work_struct imx_sc_irq_work;
|
||||
static ATOMIC_NOTIFIER_HEAD(imx_scu_irq_notifier_chain);
|
||||
|
||||
int imx_scu_irq_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_register(
|
||||
&imx_scu_irq_notifier_chain, nb);
|
||||
}
|
||||
EXPORT_SYMBOL(imx_scu_irq_register_notifier);
|
||||
|
||||
int imx_scu_irq_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_unregister(
|
||||
&imx_scu_irq_notifier_chain, nb);
|
||||
}
|
||||
EXPORT_SYMBOL(imx_scu_irq_unregister_notifier);
|
||||
|
||||
static int imx_scu_irq_notifier_call_chain(unsigned long status, u8 *group)
|
||||
{
|
||||
return atomic_notifier_call_chain(&imx_scu_irq_notifier_chain,
|
||||
status, (void *)group);
|
||||
}
|
||||
|
||||
static void imx_scu_irq_work_handler(struct work_struct *work)
|
||||
{
|
||||
struct imx_sc_msg_irq_get_status msg;
|
||||
struct imx_sc_rpc_msg *hdr = &msg.hdr;
|
||||
u32 irq_status;
|
||||
int ret;
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < IMX_SC_IRQ_NUM_GROUP; i++) {
|
||||
hdr->ver = IMX_SC_RPC_VERSION;
|
||||
hdr->svc = IMX_SC_RPC_SVC_IRQ;
|
||||
hdr->func = IMX_SC_IRQ_FUNC_STATUS;
|
||||
hdr->size = 2;
|
||||
|
||||
msg.data.req.resource = mu_resource_id;
|
||||
msg.data.req.group = i;
|
||||
|
||||
ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true);
|
||||
if (ret) {
|
||||
pr_err("get irq group %d status failed, ret %d\n",
|
||||
i, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
irq_status = msg.data.resp.status;
|
||||
if (!irq_status)
|
||||
continue;
|
||||
|
||||
imx_scu_irq_notifier_call_chain(irq_status, &i);
|
||||
}
|
||||
}
|
||||
|
||||
int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable)
|
||||
{
|
||||
struct imx_sc_msg_irq_enable msg;
|
||||
struct imx_sc_rpc_msg *hdr = &msg.hdr;
|
||||
int ret;
|
||||
|
||||
hdr->ver = IMX_SC_RPC_VERSION;
|
||||
hdr->svc = IMX_SC_RPC_SVC_IRQ;
|
||||
hdr->func = IMX_SC_IRQ_FUNC_ENABLE;
|
||||
hdr->size = 3;
|
||||
|
||||
msg.resource = mu_resource_id;
|
||||
msg.group = group;
|
||||
msg.mask = mask;
|
||||
msg.enable = enable;
|
||||
|
||||
ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true);
|
||||
if (ret)
|
||||
pr_err("enable irq failed, group %d, mask %d, ret %d\n",
|
||||
group, mask, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(imx_scu_irq_group_enable);
|
||||
|
||||
static void imx_scu_irq_callback(struct mbox_client *c, void *msg)
|
||||
{
|
||||
schedule_work(&imx_sc_irq_work);
|
||||
}
|
||||
|
||||
int imx_scu_enable_general_irq_channel(struct device *dev)
|
||||
{
|
||||
struct of_phandle_args spec;
|
||||
struct mbox_client *cl;
|
||||
struct mbox_chan *ch;
|
||||
int ret = 0, i = 0;
|
||||
|
||||
ret = imx_scu_get_handle(&imx_sc_irq_ipc_handle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cl = devm_kzalloc(dev, sizeof(*cl), GFP_KERNEL);
|
||||
if (!cl)
|
||||
return -ENOMEM;
|
||||
|
||||
cl->dev = dev;
|
||||
cl->rx_callback = imx_scu_irq_callback;
|
||||
|
||||
/* SCU general IRQ uses general interrupt channel 3 */
|
||||
ch = mbox_request_channel_byname(cl, "gip3");
|
||||
if (IS_ERR(ch)) {
|
||||
ret = PTR_ERR(ch);
|
||||
dev_err(dev, "failed to request mbox chan gip3, ret %d\n", ret);
|
||||
devm_kfree(dev, cl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
INIT_WORK(&imx_sc_irq_work, imx_scu_irq_work_handler);
|
||||
|
||||
if (!of_parse_phandle_with_args(dev->of_node, "mboxes",
|
||||
"#mbox-cells", 0, &spec))
|
||||
i = of_alias_get_id(spec.np, "mu");
|
||||
|
||||
/* use mu1 as general mu irq channel if failed */
|
||||
if (i < 0)
|
||||
i = 1;
|
||||
|
||||
mu_resource_id = IMX_SC_R_MU_0A + i;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(imx_scu_enable_general_irq_channel);
|
@ -10,6 +10,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/firmware/imx/types.h>
|
||||
#include <linux/firmware/imx/ipc.h>
|
||||
#include <linux/firmware/imx/sci.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -246,6 +247,11 @@ static int imx_scu_probe(struct platform_device *pdev)
|
||||
|
||||
imx_sc_ipc_handle = sc_ipc;
|
||||
|
||||
ret = imx_scu_enable_general_irq_channel(dev);
|
||||
if (ret)
|
||||
dev_warn(dev,
|
||||
"failed to enable general irq channel: %d\n", ret);
|
||||
|
||||
dev_info(dev, "NXP i.MX SCU Initialized\n");
|
||||
|
||||
return devm_of_platform_populate(dev);
|
||||
|
@ -74,7 +74,10 @@ struct imx_sc_pd_range {
|
||||
char *name;
|
||||
u32 rsrc;
|
||||
u8 num;
|
||||
|
||||
/* add domain index */
|
||||
bool postfix;
|
||||
u8 start_from;
|
||||
};
|
||||
|
||||
struct imx_sc_pd_soc {
|
||||
@ -84,71 +87,75 @@ struct imx_sc_pd_soc {
|
||||
|
||||
static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
|
||||
/* LSIO SS */
|
||||
{ "lsio-pwm", IMX_SC_R_PWM_0, 8, 1 },
|
||||
{ "lsio-gpio", IMX_SC_R_GPIO_0, 8, 1 },
|
||||
{ "lsio-gpt", IMX_SC_R_GPT_0, 5, 1 },
|
||||
{ "lsio-kpp", IMX_SC_R_KPP, 1, 0 },
|
||||
{ "lsio-fspi", IMX_SC_R_FSPI_0, 2, 1 },
|
||||
{ "lsio-mu", IMX_SC_R_MU_0A, 14, 1 },
|
||||
{ "pwm", IMX_SC_R_PWM_0, 8, true, 0 },
|
||||
{ "gpio", IMX_SC_R_GPIO_0, 8, true, 0 },
|
||||
{ "gpt", IMX_SC_R_GPT_0, 5, true, 0 },
|
||||
{ "kpp", IMX_SC_R_KPP, 1, false, 0 },
|
||||
{ "fspi", IMX_SC_R_FSPI_0, 2, true, 0 },
|
||||
{ "mu", IMX_SC_R_MU_0A, 14, true, 0 },
|
||||
|
||||
/* CONN SS */
|
||||
{ "con-usb", IMX_SC_R_USB_0, 2, 1 },
|
||||
{ "con-usb0phy", IMX_SC_R_USB_0_PHY, 1, 0 },
|
||||
{ "con-usb2", IMX_SC_R_USB_2, 1, 0 },
|
||||
{ "con-usb2phy", IMX_SC_R_USB_2_PHY, 1, 0 },
|
||||
{ "con-sdhc", IMX_SC_R_SDHC_0, 3, 1 },
|
||||
{ "con-enet", IMX_SC_R_ENET_0, 2, 1 },
|
||||
{ "con-nand", IMX_SC_R_NAND, 1, 0 },
|
||||
{ "con-mlb", IMX_SC_R_MLB_0, 1, 1 },
|
||||
{ "usb", IMX_SC_R_USB_0, 2, true, 0 },
|
||||
{ "usb0phy", IMX_SC_R_USB_0_PHY, 1, false, 0 },
|
||||
{ "usb2", IMX_SC_R_USB_2, 1, false, 0 },
|
||||
{ "usb2phy", IMX_SC_R_USB_2_PHY, 1, false, 0 },
|
||||
{ "sdhc", IMX_SC_R_SDHC_0, 3, true, 0 },
|
||||
{ "enet", IMX_SC_R_ENET_0, 2, true, 0 },
|
||||
{ "nand", IMX_SC_R_NAND, 1, false, 0 },
|
||||
{ "mlb", IMX_SC_R_MLB_0, 1, true, 0 },
|
||||
|
||||
/* Audio DMA SS */
|
||||
{ "adma-audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, 0 },
|
||||
{ "adma-audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, 0 },
|
||||
{ "adma-audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, 0 },
|
||||
{ "adma-dma0-ch", IMX_SC_R_DMA_0_CH0, 16, 1 },
|
||||
{ "adma-dma1-ch", IMX_SC_R_DMA_1_CH0, 16, 1 },
|
||||
{ "adma-dma2-ch", IMX_SC_R_DMA_2_CH0, 5, 1 },
|
||||
{ "adma-asrc0", IMX_SC_R_ASRC_0, 1, 0 },
|
||||
{ "adma-asrc1", IMX_SC_R_ASRC_1, 1, 0 },
|
||||
{ "adma-esai0", IMX_SC_R_ESAI_0, 1, 0 },
|
||||
{ "adma-spdif0", IMX_SC_R_SPDIF_0, 1, 0 },
|
||||
{ "adma-sai", IMX_SC_R_SAI_0, 3, 1 },
|
||||
{ "adma-amix", IMX_SC_R_AMIX, 1, 0 },
|
||||
{ "adma-mqs0", IMX_SC_R_MQS_0, 1, 0 },
|
||||
{ "adma-dsp", IMX_SC_R_DSP, 1, 0 },
|
||||
{ "adma-dsp-ram", IMX_SC_R_DSP_RAM, 1, 0 },
|
||||
{ "adma-can", IMX_SC_R_CAN_0, 3, 1 },
|
||||
{ "adma-ftm", IMX_SC_R_FTM_0, 2, 1 },
|
||||
{ "adma-lpi2c", IMX_SC_R_I2C_0, 4, 1 },
|
||||
{ "adma-adc", IMX_SC_R_ADC_0, 1, 1 },
|
||||
{ "adma-lcd", IMX_SC_R_LCD_0, 1, 1 },
|
||||
{ "adma-lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, 1 },
|
||||
{ "adma-lpuart", IMX_SC_R_UART_0, 4, 1 },
|
||||
{ "adma-lpspi", IMX_SC_R_SPI_0, 4, 1 },
|
||||
/* AUDIO SS */
|
||||
{ "audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false, 0 },
|
||||
{ "audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false, 0 },
|
||||
{ "audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false, 0 },
|
||||
{ "dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true, 0 },
|
||||
{ "dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true, 0 },
|
||||
{ "dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true, 0 },
|
||||
{ "asrc0", IMX_SC_R_ASRC_0, 1, false, 0 },
|
||||
{ "asrc1", IMX_SC_R_ASRC_1, 1, false, 0 },
|
||||
{ "esai0", IMX_SC_R_ESAI_0, 1, false, 0 },
|
||||
{ "spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 },
|
||||
{ "sai", IMX_SC_R_SAI_0, 3, true, 0 },
|
||||
{ "amix", IMX_SC_R_AMIX, 1, false, 0 },
|
||||
{ "mqs0", IMX_SC_R_MQS_0, 1, false, 0 },
|
||||
{ "dsp", IMX_SC_R_DSP, 1, false, 0 },
|
||||
{ "dsp-ram", IMX_SC_R_DSP_RAM, 1, false, 0 },
|
||||
|
||||
/* VPU SS */
|
||||
{ "vpu", IMX_SC_R_VPU, 1, 0 },
|
||||
{ "vpu-pid", IMX_SC_R_VPU_PID0, 8, 1 },
|
||||
{ "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, 0 },
|
||||
{ "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, 0 },
|
||||
/* DMA SS */
|
||||
{ "can", IMX_SC_R_CAN_0, 3, true, 0 },
|
||||
{ "ftm", IMX_SC_R_FTM_0, 2, true, 0 },
|
||||
{ "lpi2c", IMX_SC_R_I2C_0, 4, true, 0 },
|
||||
{ "adc", IMX_SC_R_ADC_0, 1, true, 0 },
|
||||
{ "lcd", IMX_SC_R_LCD_0, 1, true, 0 },
|
||||
{ "lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true, 0 },
|
||||
{ "lpuart", IMX_SC_R_UART_0, 4, true, 0 },
|
||||
{ "lpspi", IMX_SC_R_SPI_0, 4, true, 0 },
|
||||
|
||||
/* VPU SS */
|
||||
{ "vpu", IMX_SC_R_VPU, 1, false, 0 },
|
||||
{ "vpu-pid", IMX_SC_R_VPU_PID0, 8, true, 0 },
|
||||
{ "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, false, 0 },
|
||||
{ "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, false, 0 },
|
||||
|
||||
/* GPU SS */
|
||||
{ "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, 1 },
|
||||
{ "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, true, 0 },
|
||||
|
||||
/* HSIO SS */
|
||||
{ "hsio-pcie-b", IMX_SC_R_PCIE_B, 1, 0 },
|
||||
{ "hsio-serdes-1", IMX_SC_R_SERDES_1, 1, 0 },
|
||||
{ "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, 0 },
|
||||
{ "pcie-b", IMX_SC_R_PCIE_B, 1, false, 0 },
|
||||
{ "serdes-1", IMX_SC_R_SERDES_1, 1, false, 0 },
|
||||
{ "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, false, 0 },
|
||||
|
||||
/* MIPI/LVDS SS */
|
||||
{ "mipi0", IMX_SC_R_MIPI_0, 1, 0 },
|
||||
{ "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, 0 },
|
||||
{ "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, 1 },
|
||||
{ "lvds0", IMX_SC_R_LVDS_0, 1, 0 },
|
||||
/* MIPI SS */
|
||||
{ "mipi0", IMX_SC_R_MIPI_0, 1, false, 0 },
|
||||
{ "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, false, 0 },
|
||||
{ "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, true, 0 },
|
||||
|
||||
/* LVDS SS */
|
||||
{ "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 },
|
||||
|
||||
/* DC SS */
|
||||
{ "dc0", IMX_SC_R_DC_0, 1, 0 },
|
||||
{ "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, 1 },
|
||||
{ "dc0", IMX_SC_R_DC_0, 1, false, 0 },
|
||||
{ "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 },
|
||||
};
|
||||
|
||||
static const struct imx_sc_pd_soc imx8qxp_scu_pd = {
|
||||
@ -236,7 +243,7 @@ imx_scu_add_pm_domain(struct device *dev, int idx,
|
||||
|
||||
if (pd_ranges->postfix)
|
||||
snprintf(sc_pd->name, sizeof(sc_pd->name),
|
||||
"%s%i", pd_ranges->name, idx);
|
||||
"%s%i", pd_ranges->name, pd_ranges->start_from + idx);
|
||||
else
|
||||
snprintf(sc_pd->name, sizeof(sc_pd->name),
|
||||
"%s", pd_ranges->name);
|
||||
|
@ -90,9 +90,6 @@ static int process_api_request(u32 pm_id, u64 *pm_api_arg, u32 *pm_api_ret)
|
||||
int ret;
|
||||
struct zynqmp_pm_query_data qdata = {0};
|
||||
|
||||
if (!eemi_ops)
|
||||
return -ENXIO;
|
||||
|
||||
switch (pm_id) {
|
||||
case PM_GET_API_VERSION:
|
||||
ret = eemi_ops->get_api_version(&pm_api_version);
|
||||
@ -163,21 +160,14 @@ static ssize_t zynqmp_pm_debugfs_api_write(struct file *file,
|
||||
|
||||
strcpy(debugfs_buf, "");
|
||||
|
||||
if (*off != 0 || len == 0)
|
||||
if (*off != 0 || len <= 1 || len > PAGE_SIZE - 1)
|
||||
return -EINVAL;
|
||||
|
||||
kern_buff = kzalloc(len, GFP_KERNEL);
|
||||
if (!kern_buff)
|
||||
return -ENOMEM;
|
||||
|
||||
kern_buff = memdup_user_nul(ptr, len);
|
||||
if (IS_ERR(kern_buff))
|
||||
return PTR_ERR(kern_buff);
|
||||
tmp_buff = kern_buff;
|
||||
|
||||
ret = strncpy_from_user(kern_buff, ptr, len);
|
||||
if (ret < 0) {
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Read the API name from a user request */
|
||||
pm_api_req = strsep(&kern_buff, " ");
|
||||
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include <linux/firmware/xlnx-zynqmp.h>
|
||||
#include "zynqmp-debug.h"
|
||||
|
||||
static const struct zynqmp_eemi_ops *eemi_ops_tbl;
|
||||
|
||||
static const struct mfd_cell firmware_devs[] = {
|
||||
{
|
||||
.name = "zynqmp_power_controller",
|
||||
@ -537,6 +539,49 @@ static int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_fpga_load - Perform the fpga load
|
||||
* @address: Address to write to
|
||||
* @size: pl bitstream size
|
||||
* @flags: Bitstream type
|
||||
* -XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration
|
||||
* -XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration
|
||||
*
|
||||
* This function provides access to pmufw. To transfer
|
||||
* the required bitstream into PL.
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
static int zynqmp_pm_fpga_load(const u64 address, const u32 size,
|
||||
const u32 flags)
|
||||
{
|
||||
return zynqmp_pm_invoke_fn(PM_FPGA_LOAD, lower_32_bits(address),
|
||||
upper_32_bits(address), size, flags, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_fpga_get_status - Read value from PCAP status register
|
||||
* @value: Value to read
|
||||
*
|
||||
* This function provides access to the pmufw to get the PCAP
|
||||
* status
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
static int zynqmp_pm_fpga_get_status(u32 *value)
|
||||
{
|
||||
u32 ret_payload[PAYLOAD_ARG_CNT];
|
||||
int ret;
|
||||
|
||||
if (!value)
|
||||
return -EINVAL;
|
||||
|
||||
ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload);
|
||||
*value = ret_payload[1];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_init_finalize() - PM call to inform firmware that the caller
|
||||
* master has initialized its own power management
|
||||
@ -640,6 +685,8 @@ static const struct zynqmp_eemi_ops eemi_ops = {
|
||||
.request_node = zynqmp_pm_request_node,
|
||||
.release_node = zynqmp_pm_release_node,
|
||||
.set_requirement = zynqmp_pm_set_requirement,
|
||||
.fpga_load = zynqmp_pm_fpga_load,
|
||||
.fpga_get_status = zynqmp_pm_fpga_get_status,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -649,7 +696,11 @@ static const struct zynqmp_eemi_ops eemi_ops = {
|
||||
*/
|
||||
const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
|
||||
{
|
||||
return &eemi_ops;
|
||||
if (eemi_ops_tbl)
|
||||
return eemi_ops_tbl;
|
||||
else
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops);
|
||||
|
||||
@ -694,6 +745,9 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
|
||||
pr_info("%s Trustzone version v%d.%d\n", __func__,
|
||||
pm_tz_version >> 16, pm_tz_version & 0xFFFF);
|
||||
|
||||
/* Assign eemi_ops_table */
|
||||
eemi_ops_tbl = &eemi_ops;
|
||||
|
||||
zynqmp_pm_api_debugfs_init();
|
||||
|
||||
ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, firmware_devs,
|
||||
|
@ -204,4 +204,13 @@ config FPGA_DFL_PCI
|
||||
|
||||
To compile this as a module, choose M here.
|
||||
|
||||
config FPGA_MGR_ZYNQMP_FPGA
|
||||
tristate "Xilinx ZynqMP FPGA"
|
||||
depends on ARCH_ZYNQMP || COMPILE_TEST
|
||||
help
|
||||
FPGA manager driver support for Xilinx ZynqMP FPGAs.
|
||||
This driver uses the processor configuration port(PCAP)
|
||||
to configure the programmable logic(PL) through PS
|
||||
on ZynqMP SoC.
|
||||
|
||||
endif # FPGA
|
||||
|
@ -17,6 +17,7 @@ obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC) += stratix10-soc.o
|
||||
obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o
|
||||
obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o
|
||||
obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o
|
||||
obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA) += zynqmp-fpga.o
|
||||
obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o
|
||||
obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o
|
||||
|
||||
|
159
drivers/fpga/zynqmp-fpga.c
Normal file
159
drivers/fpga/zynqmp-fpga.c
Normal file
@ -0,0 +1,159 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2019 Xilinx, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/fpga/fpga-mgr.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/firmware/xlnx-zynqmp.h>
|
||||
|
||||
/* Constant Definitions */
|
||||
#define IXR_FPGA_DONE_MASK BIT(3)
|
||||
|
||||
/**
|
||||
* struct zynqmp_fpga_priv - Private data structure
|
||||
* @dev: Device data structure
|
||||
* @flags: flags which is used to identify the bitfile type
|
||||
*/
|
||||
struct zynqmp_fpga_priv {
|
||||
struct device *dev;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
static int zynqmp_fpga_ops_write_init(struct fpga_manager *mgr,
|
||||
struct fpga_image_info *info,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct zynqmp_fpga_priv *priv;
|
||||
|
||||
priv = mgr->priv;
|
||||
priv->flags = info->flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
struct zynqmp_fpga_priv *priv;
|
||||
dma_addr_t dma_addr;
|
||||
u32 eemi_flags = 0;
|
||||
char *kbuf;
|
||||
int ret;
|
||||
|
||||
if (!eemi_ops || !eemi_ops->fpga_load)
|
||||
return -ENXIO;
|
||||
|
||||
priv = mgr->priv;
|
||||
|
||||
kbuf = dma_alloc_coherent(priv->dev, size, &dma_addr, GFP_KERNEL);
|
||||
if (!kbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(kbuf, buf, size);
|
||||
|
||||
wmb(); /* ensure all writes are done before initiate FW call */
|
||||
|
||||
if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG)
|
||||
eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL;
|
||||
|
||||
ret = eemi_ops->fpga_load(dma_addr, size, eemi_flags);
|
||||
|
||||
dma_free_coherent(priv->dev, size, kbuf, dma_addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int zynqmp_fpga_ops_write_complete(struct fpga_manager *mgr,
|
||||
struct fpga_image_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr)
|
||||
{
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
u32 status;
|
||||
|
||||
if (!eemi_ops || !eemi_ops->fpga_get_status)
|
||||
return FPGA_MGR_STATE_UNKNOWN;
|
||||
|
||||
eemi_ops->fpga_get_status(&status);
|
||||
if (status & IXR_FPGA_DONE_MASK)
|
||||
return FPGA_MGR_STATE_OPERATING;
|
||||
|
||||
return FPGA_MGR_STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
static const struct fpga_manager_ops zynqmp_fpga_ops = {
|
||||
.state = zynqmp_fpga_ops_state,
|
||||
.write_init = zynqmp_fpga_ops_write_init,
|
||||
.write = zynqmp_fpga_ops_write,
|
||||
.write_complete = zynqmp_fpga_ops_write_complete,
|
||||
};
|
||||
|
||||
static int zynqmp_fpga_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct zynqmp_fpga_priv *priv;
|
||||
struct fpga_manager *mgr;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->dev = dev;
|
||||
|
||||
mgr = devm_fpga_mgr_create(dev, "Xilinx ZynqMP FPGA Manager",
|
||||
&zynqmp_fpga_ops, priv);
|
||||
if (!mgr)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, mgr);
|
||||
|
||||
ret = fpga_mgr_register(mgr);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to register FPGA manager");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zynqmp_fpga_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct fpga_manager *mgr = platform_get_drvdata(pdev);
|
||||
|
||||
fpga_mgr_unregister(mgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id zynqmp_fpga_of_match[] = {
|
||||
{ .compatible = "xlnx,zynqmp-pcap-fpga", },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match);
|
||||
|
||||
static struct platform_driver zynqmp_fpga_driver = {
|
||||
.probe = zynqmp_fpga_probe,
|
||||
.remove = zynqmp_fpga_remove,
|
||||
.driver = {
|
||||
.name = "zynqmp_fpga_manager",
|
||||
.of_match_table = of_match_ptr(zynqmp_fpga_of_match),
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(zynqmp_fpga_driver);
|
||||
|
||||
MODULE_AUTHOR("Nava kishore Manne <navam@xilinx.com>");
|
||||
MODULE_DESCRIPTION("Xilinx ZynqMp FPGA Manager");
|
||||
MODULE_LICENSE("GPL");
|
@ -537,6 +537,9 @@
|
||||
#define MCONNID_SHIFT 0
|
||||
#define MCONNID_MASK (0xff << 0)
|
||||
|
||||
/* READ_WRITE_LEVELING_CONTROL */
|
||||
#define RDWRLVLFULL_START 0x80000000
|
||||
|
||||
/* DDR_PHY_CTRL_1 - EMIF4D */
|
||||
#define DLL_SLAVE_DLY_CTRL_SHIFT_4D 4
|
||||
#define DLL_SLAVE_DLY_CTRL_MASK_4D (0xFF << 4)
|
||||
@ -598,6 +601,7 @@ extern struct emif_regs_amx3 ti_emif_regs_amx3;
|
||||
|
||||
void ti_emif_save_context(void);
|
||||
void ti_emif_restore_context(void);
|
||||
void ti_emif_run_hw_leveling(void);
|
||||
void ti_emif_enter_sr(void);
|
||||
void ti_emif_exit_sr(void);
|
||||
void ti_emif_abort_sr(void);
|
||||
|
@ -51,6 +51,9 @@
|
||||
#define MC_EMEM_ADR_CFG 0x54
|
||||
#define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0)
|
||||
|
||||
#define MC_TIMING_CONTROL 0xfc
|
||||
#define MC_TIMING_UPDATE BIT(0)
|
||||
|
||||
static const struct of_device_id tegra_mc_of_match[] = {
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
{ .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc },
|
||||
@ -74,7 +77,7 @@ static const struct of_device_id tegra_mc_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_mc_of_match);
|
||||
|
||||
static int terga_mc_block_dma_common(struct tegra_mc *mc,
|
||||
static int tegra_mc_block_dma_common(struct tegra_mc *mc,
|
||||
const struct tegra_mc_reset *rst)
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -90,13 +93,13 @@ static int terga_mc_block_dma_common(struct tegra_mc *mc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool terga_mc_dma_idling_common(struct tegra_mc *mc,
|
||||
static bool tegra_mc_dma_idling_common(struct tegra_mc *mc,
|
||||
const struct tegra_mc_reset *rst)
|
||||
{
|
||||
return (mc_readl(mc, rst->status) & BIT(rst->bit)) != 0;
|
||||
}
|
||||
|
||||
static int terga_mc_unblock_dma_common(struct tegra_mc *mc,
|
||||
static int tegra_mc_unblock_dma_common(struct tegra_mc *mc,
|
||||
const struct tegra_mc_reset *rst)
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -112,17 +115,17 @@ static int terga_mc_unblock_dma_common(struct tegra_mc *mc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int terga_mc_reset_status_common(struct tegra_mc *mc,
|
||||
static int tegra_mc_reset_status_common(struct tegra_mc *mc,
|
||||
const struct tegra_mc_reset *rst)
|
||||
{
|
||||
return (mc_readl(mc, rst->control) & BIT(rst->bit)) != 0;
|
||||
}
|
||||
|
||||
const struct tegra_mc_reset_ops terga_mc_reset_ops_common = {
|
||||
.block_dma = terga_mc_block_dma_common,
|
||||
.dma_idling = terga_mc_dma_idling_common,
|
||||
.unblock_dma = terga_mc_unblock_dma_common,
|
||||
.reset_status = terga_mc_reset_status_common,
|
||||
const struct tegra_mc_reset_ops tegra_mc_reset_ops_common = {
|
||||
.block_dma = tegra_mc_block_dma_common,
|
||||
.dma_idling = tegra_mc_dma_idling_common,
|
||||
.unblock_dma = tegra_mc_unblock_dma_common,
|
||||
.reset_status = tegra_mc_reset_status_common,
|
||||
};
|
||||
|
||||
static inline struct tegra_mc *reset_to_mc(struct reset_controller_dev *rcdev)
|
||||
@ -282,25 +285,28 @@ static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
|
||||
u32 value;
|
||||
|
||||
/* compute the number of MC clock cycles per tick */
|
||||
tick = mc->tick * clk_get_rate(mc->clk);
|
||||
tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk);
|
||||
do_div(tick, NSEC_PER_SEC);
|
||||
|
||||
value = readl(mc->regs + MC_EMEM_ARB_CFG);
|
||||
value = mc_readl(mc, MC_EMEM_ARB_CFG);
|
||||
value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK;
|
||||
value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick);
|
||||
writel(value, mc->regs + MC_EMEM_ARB_CFG);
|
||||
mc_writel(mc, value, MC_EMEM_ARB_CFG);
|
||||
|
||||
/* write latency allowance defaults */
|
||||
for (i = 0; i < mc->soc->num_clients; i++) {
|
||||
const struct tegra_mc_la *la = &mc->soc->clients[i].la;
|
||||
u32 value;
|
||||
|
||||
value = readl(mc->regs + la->reg);
|
||||
value = mc_readl(mc, la->reg);
|
||||
value &= ~(la->mask << la->shift);
|
||||
value |= (la->def & la->mask) << la->shift;
|
||||
writel(value, mc->regs + la->reg);
|
||||
mc_writel(mc, value, la->reg);
|
||||
}
|
||||
|
||||
/* latch new values */
|
||||
mc_writel(mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ static inline void mc_writel(struct tegra_mc *mc, u32 value,
|
||||
writel_relaxed(value, mc->regs + offset);
|
||||
}
|
||||
|
||||
extern const struct tegra_mc_reset_ops terga_mc_reset_ops_common;
|
||||
extern const struct tegra_mc_reset_ops tegra_mc_reset_ops_common;
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
extern const struct tegra_mc_soc tegra20_mc_soc;
|
||||
|
@ -572,7 +572,7 @@ static const struct tegra_mc_client tegra114_mc_clients[] = {
|
||||
},
|
||||
}, {
|
||||
.id = 0x34,
|
||||
.name = "fdcwr2",
|
||||
.name = "fdcdwr2",
|
||||
.swgroup = TEGRA_SWGROUP_NV,
|
||||
.smmu = {
|
||||
.reg = 0x22c,
|
||||
@ -975,7 +975,7 @@ const struct tegra_mc_soc tegra114_mc_soc = {
|
||||
.smmu = &tegra114_smmu_soc,
|
||||
.intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
|
||||
MC_INT_DECERR_EMEM,
|
||||
.reset_ops = &terga_mc_reset_ops_common,
|
||||
.reset_ops = &tegra_mc_reset_ops_common,
|
||||
.resets = tegra114_mc_resets,
|
||||
.num_resets = ARRAY_SIZE(tegra114_mc_resets),
|
||||
};
|
||||
|
@ -1074,7 +1074,7 @@ const struct tegra_mc_soc tegra124_mc_soc = {
|
||||
.intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
|
||||
MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
|
||||
MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
|
||||
.reset_ops = &terga_mc_reset_ops_common,
|
||||
.reset_ops = &tegra_mc_reset_ops_common,
|
||||
.resets = tegra124_mc_resets,
|
||||
.num_resets = ARRAY_SIZE(tegra124_mc_resets),
|
||||
};
|
||||
@ -1104,7 +1104,7 @@ const struct tegra_mc_soc tegra132_mc_soc = {
|
||||
.intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
|
||||
MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
|
||||
MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
|
||||
.reset_ops = &terga_mc_reset_ops_common,
|
||||
.reset_ops = &tegra_mc_reset_ops_common,
|
||||
.resets = tegra124_mc_resets,
|
||||
.num_resets = ARRAY_SIZE(tegra124_mc_resets),
|
||||
};
|
||||
|
@ -198,7 +198,7 @@ static const struct tegra_mc_reset tegra20_mc_resets[] = {
|
||||
TEGRA20_MC_RESET(VI, 0x100, 0x178, 0x104, 14),
|
||||
};
|
||||
|
||||
static int terga20_mc_hotreset_assert(struct tegra_mc *mc,
|
||||
static int tegra20_mc_hotreset_assert(struct tegra_mc *mc,
|
||||
const struct tegra_mc_reset *rst)
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -214,7 +214,7 @@ static int terga20_mc_hotreset_assert(struct tegra_mc *mc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int terga20_mc_hotreset_deassert(struct tegra_mc *mc,
|
||||
static int tegra20_mc_hotreset_deassert(struct tegra_mc *mc,
|
||||
const struct tegra_mc_reset *rst)
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -230,7 +230,7 @@ static int terga20_mc_hotreset_deassert(struct tegra_mc *mc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int terga20_mc_block_dma(struct tegra_mc *mc,
|
||||
static int tegra20_mc_block_dma(struct tegra_mc *mc,
|
||||
const struct tegra_mc_reset *rst)
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -246,19 +246,19 @@ static int terga20_mc_block_dma(struct tegra_mc *mc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool terga20_mc_dma_idling(struct tegra_mc *mc,
|
||||
static bool tegra20_mc_dma_idling(struct tegra_mc *mc,
|
||||
const struct tegra_mc_reset *rst)
|
||||
{
|
||||
return mc_readl(mc, rst->status) == 0;
|
||||
}
|
||||
|
||||
static int terga20_mc_reset_status(struct tegra_mc *mc,
|
||||
static int tegra20_mc_reset_status(struct tegra_mc *mc,
|
||||
const struct tegra_mc_reset *rst)
|
||||
{
|
||||
return (mc_readl(mc, rst->reset) & BIT(rst->bit)) == 0;
|
||||
}
|
||||
|
||||
static int terga20_mc_unblock_dma(struct tegra_mc *mc,
|
||||
static int tegra20_mc_unblock_dma(struct tegra_mc *mc,
|
||||
const struct tegra_mc_reset *rst)
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -274,13 +274,13 @@ static int terga20_mc_unblock_dma(struct tegra_mc *mc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct tegra_mc_reset_ops terga20_mc_reset_ops = {
|
||||
.hotreset_assert = terga20_mc_hotreset_assert,
|
||||
.hotreset_deassert = terga20_mc_hotreset_deassert,
|
||||
.block_dma = terga20_mc_block_dma,
|
||||
.dma_idling = terga20_mc_dma_idling,
|
||||
.unblock_dma = terga20_mc_unblock_dma,
|
||||
.reset_status = terga20_mc_reset_status,
|
||||
static const struct tegra_mc_reset_ops tegra20_mc_reset_ops = {
|
||||
.hotreset_assert = tegra20_mc_hotreset_assert,
|
||||
.hotreset_deassert = tegra20_mc_hotreset_deassert,
|
||||
.block_dma = tegra20_mc_block_dma,
|
||||
.dma_idling = tegra20_mc_dma_idling,
|
||||
.unblock_dma = tegra20_mc_unblock_dma,
|
||||
.reset_status = tegra20_mc_reset_status,
|
||||
};
|
||||
|
||||
const struct tegra_mc_soc tegra20_mc_soc = {
|
||||
@ -290,7 +290,7 @@ const struct tegra_mc_soc tegra20_mc_soc = {
|
||||
.client_id_mask = 0x3f,
|
||||
.intmask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE |
|
||||
MC_INT_DECERR_EMEM,
|
||||
.reset_ops = &terga20_mc_reset_ops,
|
||||
.reset_ops = &tegra20_mc_reset_ops,
|
||||
.resets = tegra20_mc_resets,
|
||||
.num_resets = ARRAY_SIZE(tegra20_mc_resets),
|
||||
};
|
||||
|
@ -1132,7 +1132,7 @@ const struct tegra_mc_soc tegra210_mc_soc = {
|
||||
.intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
|
||||
MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
|
||||
MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
|
||||
.reset_ops = &terga_mc_reset_ops_common,
|
||||
.reset_ops = &tegra_mc_reset_ops_common,
|
||||
.resets = tegra210_mc_resets,
|
||||
.num_resets = ARRAY_SIZE(tegra210_mc_resets),
|
||||
};
|
||||
|
@ -726,7 +726,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
},
|
||||
}, {
|
||||
.id = 0x34,
|
||||
.name = "fdcwr2",
|
||||
.name = "fdcdwr2",
|
||||
.swgroup = TEGRA_SWGROUP_NV2,
|
||||
.smmu = {
|
||||
.reg = 0x22c,
|
||||
@ -999,7 +999,7 @@ const struct tegra_mc_soc tegra30_mc_soc = {
|
||||
.smmu = &tegra30_smmu_soc,
|
||||
.intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
|
||||
MC_INT_DECERR_EMEM,
|
||||
.reset_ops = &terga_mc_reset_ops_common,
|
||||
.reset_ops = &tegra_mc_reset_ops_common,
|
||||
.resets = tegra30_mc_resets,
|
||||
.num_resets = ARRAY_SIZE(tegra30_mc_resets),
|
||||
};
|
||||
|
@ -138,6 +138,9 @@ static int ti_emif_alloc_sram(struct device *dev,
|
||||
emif_data->pm_functions.exit_sr =
|
||||
sram_resume_address(emif_data,
|
||||
(unsigned long)ti_emif_exit_sr);
|
||||
emif_data->pm_functions.run_hw_leveling =
|
||||
sram_resume_address(emif_data,
|
||||
(unsigned long)ti_emif_run_hw_leveling);
|
||||
|
||||
emif_data->pm_data.regs_virt =
|
||||
(struct emif_regs_amx3 *)emif_data->ti_emif_sram_data_virt;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#define EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK 0x0700
|
||||
|
||||
#define EMIF_SDCFG_TYPE_DDR2 0x2 << SDRAM_TYPE_SHIFT
|
||||
#define EMIF_SDCFG_TYPE_DDR3 0x3 << SDRAM_TYPE_SHIFT
|
||||
#define EMIF_STATUS_READY 0x4
|
||||
|
||||
#define AM43XX_EMIF_PHY_CTRL_REG_COUNT 0x120
|
||||
@ -244,6 +245,46 @@ emif_skip_restore_extra_regs:
|
||||
mov pc, lr
|
||||
ENDPROC(ti_emif_restore_context)
|
||||
|
||||
/*
|
||||
* void ti_emif_run_hw_leveling(void)
|
||||
*
|
||||
* Used during resume to run hardware leveling again and restore the
|
||||
* configuration of the EMIF PHY, only for DDR3.
|
||||
*/
|
||||
ENTRY(ti_emif_run_hw_leveling)
|
||||
adr r4, ti_emif_pm_sram_data
|
||||
ldr r0, [r4, #EMIF_PM_BASE_ADDR_PHYS_OFFSET]
|
||||
|
||||
ldr r3, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL]
|
||||
orr r3, r3, #RDWRLVLFULL_START
|
||||
ldr r2, [r0, #EMIF_SDRAM_CONFIG]
|
||||
and r2, r2, #SDRAM_TYPE_MASK
|
||||
cmp r2, #EMIF_SDCFG_TYPE_DDR3
|
||||
bne skip_hwlvl
|
||||
|
||||
str r3, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL]
|
||||
|
||||
/*
|
||||
* If EMIF registers are touched during initial stage of HW
|
||||
* leveling sequence there will be an L3 NOC timeout error issued
|
||||
* as the EMIF will not respond, which is not fatal, but it is
|
||||
* avoidable. This small wait loop is enough time for this condition
|
||||
* to clear, even at worst case of CPU running at max speed of 1Ghz.
|
||||
*/
|
||||
mov r2, #0x2000
|
||||
1:
|
||||
subs r2, r2, #0x1
|
||||
bne 1b
|
||||
|
||||
/* Bit clears when operation is complete */
|
||||
2: ldr r1, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL]
|
||||
tst r1, #RDWRLVLFULL_START
|
||||
bne 2b
|
||||
|
||||
skip_hwlvl:
|
||||
mov pc, lr
|
||||
ENDPROC(ti_emif_run_hw_leveling)
|
||||
|
||||
/*
|
||||
* void ti_emif_enter_sr(void)
|
||||
*
|
||||
|
@ -496,30 +496,6 @@ config VEXPRESS_SYSCFG
|
||||
bus. System Configuration interface is one of the possible means
|
||||
of generating transactions on this bus.
|
||||
|
||||
config ASPEED_P2A_CTRL
|
||||
depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON
|
||||
tristate "Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC bridge control"
|
||||
help
|
||||
Control Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC mappings through
|
||||
ioctl()s, the driver also provides an interface for userspace mappings to
|
||||
a pre-defined region.
|
||||
|
||||
config ASPEED_LPC_CTRL
|
||||
depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON
|
||||
tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control"
|
||||
---help---
|
||||
Control Aspeed ast2400/2500 HOST LPC to BMC mappings through
|
||||
ioctl()s, the driver also provides a read/write interface to a BMC ram
|
||||
region where the host LPC read/write region can be buffered.
|
||||
|
||||
config ASPEED_LPC_SNOOP
|
||||
tristate "Aspeed ast2500 HOST LPC snoop support"
|
||||
depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON
|
||||
help
|
||||
Provides a driver to control the LPC snoop interface which
|
||||
allows the BMC to listen on and save the data written by
|
||||
the host to an arbitrary LPC I/O port.
|
||||
|
||||
config PCI_ENDPOINT_TEST
|
||||
depends on PCI
|
||||
select CRC32
|
||||
|
@ -54,9 +54,6 @@ obj-$(CONFIG_GENWQE) += genwqe/
|
||||
obj-$(CONFIG_ECHO) += echo/
|
||||
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
|
||||
obj-$(CONFIG_CXL_BASE) += cxl/
|
||||
obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
|
||||
obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
|
||||
obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o
|
||||
obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
|
||||
obj-$(CONFIG_OCXL) += ocxl/
|
||||
obj-y += cardreader/
|
||||
|
@ -16,6 +16,8 @@ struct zynqmp_nvmem_data {
|
||||
struct nvmem_device *nvmem;
|
||||
};
|
||||
|
||||
static const struct zynqmp_eemi_ops *eemi_ops;
|
||||
|
||||
static int zynqmp_nvmem_read(void *context, unsigned int offset,
|
||||
void *val, size_t bytes)
|
||||
{
|
||||
@ -23,9 +25,7 @@ static int zynqmp_nvmem_read(void *context, unsigned int offset,
|
||||
int idcode, version;
|
||||
struct zynqmp_nvmem_data *priv = context;
|
||||
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->get_chipid)
|
||||
if (!eemi_ops->get_chipid)
|
||||
return -ENXIO;
|
||||
|
||||
ret = eemi_ops->get_chipid(&idcode, &version);
|
||||
@ -61,6 +61,10 @@ static int zynqmp_nvmem_probe(struct platform_device *pdev)
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
if (IS_ERR(eemi_ops))
|
||||
return PTR_ERR(eemi_ops);
|
||||
|
||||
priv->dev = dev;
|
||||
econfig.dev = dev;
|
||||
econfig.reg_read = zynqmp_nvmem_read;
|
||||
|
@ -79,11 +79,11 @@ static int zynqmp_reset_probe(struct platform_device *pdev)
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
priv->eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
if (!priv->eemi_ops)
|
||||
return -ENXIO;
|
||||
if (IS_ERR(priv->eemi_ops))
|
||||
return PTR_ERR(priv->eemi_ops);
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
priv->rcdev.ops = &zynqmp_reset_ops;
|
||||
priv->rcdev.owner = THIS_MODULE;
|
||||
|
@ -403,15 +403,12 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
|
||||
static struct omap_rtc *omap_rtc_power_off_rtc;
|
||||
|
||||
/*
|
||||
* omap_rtc_poweroff: RTC-controlled power off
|
||||
*
|
||||
* The RTC can be used to control an external PMIC via the pmic_power_en pin,
|
||||
* which can be configured to transition to OFF on ALARM2 events.
|
||||
*
|
||||
* Called with local interrupts disabled.
|
||||
/**
|
||||
* omap_rtc_power_off_program: Set the pmic power off sequence. The RTC
|
||||
* generates pmic_pwr_enable control, which can be used to control an external
|
||||
* PMIC.
|
||||
*/
|
||||
static void omap_rtc_power_off(void)
|
||||
int omap_rtc_power_off_program(struct device *dev)
|
||||
{
|
||||
struct omap_rtc *rtc = omap_rtc_power_off_rtc;
|
||||
struct rtc_time tm;
|
||||
@ -425,6 +422,9 @@ static void omap_rtc_power_off(void)
|
||||
rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN);
|
||||
|
||||
again:
|
||||
/* Clear any existing ALARM2 event */
|
||||
rtc_writel(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM2);
|
||||
|
||||
/* set alarm one second from now */
|
||||
omap_rtc_read_time_raw(rtc, &tm);
|
||||
seconds = tm.tm_sec;
|
||||
@ -461,6 +461,39 @@ static void omap_rtc_power_off(void)
|
||||
|
||||
rtc->type->lock(rtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_rtc_power_off_program);
|
||||
|
||||
/*
|
||||
* omap_rtc_poweroff: RTC-controlled power off
|
||||
*
|
||||
* The RTC can be used to control an external PMIC via the pmic_power_en pin,
|
||||
* which can be configured to transition to OFF on ALARM2 events.
|
||||
*
|
||||
* Notes:
|
||||
* The one-second alarm offset is the shortest offset possible as the alarm
|
||||
* registers must be set before the next timer update and the offset
|
||||
* calculation is too heavy for everything to be done within a single access
|
||||
* period (~15 us).
|
||||
*
|
||||
* Called with local interrupts disabled.
|
||||
*/
|
||||
static void omap_rtc_power_off(void)
|
||||
{
|
||||
struct rtc_device *rtc = omap_rtc_power_off_rtc->rtc;
|
||||
u32 val;
|
||||
|
||||
omap_rtc_power_off_program(rtc->dev.parent);
|
||||
|
||||
/* Set PMIC power enable and EXT_WAKEUP in case PB power on is used */
|
||||
omap_rtc_power_off_rtc->type->unlock(omap_rtc_power_off_rtc);
|
||||
val = rtc_readl(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG);
|
||||
val |= OMAP_RTC_PMIC_POWER_EN_EN | OMAP_RTC_PMIC_EXT_WKUP_POL(0) |
|
||||
OMAP_RTC_PMIC_EXT_WKUP_EN(0);
|
||||
rtc_writel(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG, val);
|
||||
omap_rtc_power_off_rtc->type->lock(omap_rtc_power_off_rtc);
|
||||
|
||||
/*
|
||||
* Wait for alarm to trigger (within one second) and external PMIC to
|
||||
* power off the system. Add a 500 ms margin for external latencies
|
||||
|
@ -2,6 +2,7 @@ menu "SOC (System On Chip) specific Drivers"
|
||||
|
||||
source "drivers/soc/actions/Kconfig"
|
||||
source "drivers/soc/amlogic/Kconfig"
|
||||
source "drivers/soc/aspeed/Kconfig"
|
||||
source "drivers/soc/atmel/Kconfig"
|
||||
source "drivers/soc/bcm/Kconfig"
|
||||
source "drivers/soc/fsl/Kconfig"
|
||||
|
@ -4,6 +4,7 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_ARCH_ACTIONS) += actions/
|
||||
obj-$(CONFIG_SOC_ASPEED) += aspeed/
|
||||
obj-$(CONFIG_ARCH_AT91) += atmel/
|
||||
obj-y += bcm/
|
||||
obj-$(CONFIG_ARCH_DOVE) += dove/
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
@ -26,6 +27,7 @@
|
||||
#define HHI_MEM_PD_REG0 (0x40 << 2)
|
||||
#define HHI_VPU_MEM_PD_REG0 (0x41 << 2)
|
||||
#define HHI_VPU_MEM_PD_REG1 (0x42 << 2)
|
||||
#define HHI_VPU_MEM_PD_REG2 (0x4d << 2)
|
||||
|
||||
struct meson_gx_pwrc_vpu {
|
||||
struct generic_pm_domain genpd;
|
||||
@ -54,12 +56,55 @@ static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
|
||||
/* Power Down Memories */
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
|
||||
0x2 << i, 0x3 << i);
|
||||
0x3 << i, 0x3 << i);
|
||||
udelay(5);
|
||||
}
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
|
||||
0x2 << i, 0x3 << i);
|
||||
0x3 << i, 0x3 << i);
|
||||
udelay(5);
|
||||
}
|
||||
for (i = 8; i < 16; i++) {
|
||||
regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
|
||||
BIT(i), BIT(i));
|
||||
udelay(5);
|
||||
}
|
||||
udelay(20);
|
||||
|
||||
regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
|
||||
GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
|
||||
|
||||
msleep(20);
|
||||
|
||||
clk_disable_unprepare(pd->vpu_clk);
|
||||
clk_disable_unprepare(pd->vapb_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_g12a_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
|
||||
int i;
|
||||
|
||||
regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
|
||||
GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
|
||||
udelay(20);
|
||||
|
||||
/* Power Down Memories */
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
|
||||
0x3 << i, 0x3 << i);
|
||||
udelay(5);
|
||||
}
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
|
||||
0x3 << i, 0x3 << i);
|
||||
udelay(5);
|
||||
}
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2,
|
||||
0x3 << i, 0x3 << i);
|
||||
udelay(5);
|
||||
}
|
||||
for (i = 8; i < 16; i++) {
|
||||
@ -108,13 +153,67 @@ static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
|
||||
/* Power Up Memories */
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
|
||||
0x2 << i, 0);
|
||||
0x3 << i, 0);
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
|
||||
0x2 << i, 0);
|
||||
0x3 << i, 0);
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
for (i = 8; i < 16; i++) {
|
||||
regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
|
||||
BIT(i), 0);
|
||||
udelay(5);
|
||||
}
|
||||
udelay(20);
|
||||
|
||||
ret = reset_control_assert(pd->rstc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
|
||||
GEN_PWR_VPU_HDMI_ISO, 0);
|
||||
|
||||
ret = reset_control_deassert(pd->rstc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = meson_gx_pwrc_vpu_setup_clk(pd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_g12a_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
|
||||
GEN_PWR_VPU_HDMI, 0);
|
||||
udelay(20);
|
||||
|
||||
/* Power Up Memories */
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
|
||||
0x3 << i, 0);
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
|
||||
0x3 << i, 0);
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2,
|
||||
0x3 << i, 0);
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
@ -160,15 +259,37 @@ static struct meson_gx_pwrc_vpu vpu_hdmi_pd = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct meson_gx_pwrc_vpu vpu_hdmi_pd_g12a = {
|
||||
.genpd = {
|
||||
.name = "vpu_hdmi",
|
||||
.power_off = meson_g12a_pwrc_vpu_power_off,
|
||||
.power_on = meson_g12a_pwrc_vpu_power_on,
|
||||
},
|
||||
};
|
||||
|
||||
static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct meson_gx_pwrc_vpu *vpu_pd_match;
|
||||
struct regmap *regmap_ao, *regmap_hhi;
|
||||
struct meson_gx_pwrc_vpu *vpu_pd;
|
||||
struct reset_control *rstc;
|
||||
struct clk *vpu_clk;
|
||||
struct clk *vapb_clk;
|
||||
bool powered_off;
|
||||
int ret;
|
||||
|
||||
vpu_pd_match = of_device_get_match_data(&pdev->dev);
|
||||
if (!vpu_pd_match) {
|
||||
dev_err(&pdev->dev, "failed to get match data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
vpu_pd = devm_kzalloc(&pdev->dev, sizeof(*vpu_pd), GFP_KERNEL);
|
||||
if (!vpu_pd)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(vpu_pd, vpu_pd_match, sizeof(*vpu_pd));
|
||||
|
||||
regmap_ao = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node));
|
||||
if (IS_ERR(regmap_ao)) {
|
||||
dev_err(&pdev->dev, "failed to get regmap\n");
|
||||
@ -201,39 +322,46 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(vapb_clk);
|
||||
}
|
||||
|
||||
vpu_hdmi_pd.regmap_ao = regmap_ao;
|
||||
vpu_hdmi_pd.regmap_hhi = regmap_hhi;
|
||||
vpu_hdmi_pd.rstc = rstc;
|
||||
vpu_hdmi_pd.vpu_clk = vpu_clk;
|
||||
vpu_hdmi_pd.vapb_clk = vapb_clk;
|
||||
vpu_pd->regmap_ao = regmap_ao;
|
||||
vpu_pd->regmap_hhi = regmap_hhi;
|
||||
vpu_pd->rstc = rstc;
|
||||
vpu_pd->vpu_clk = vpu_clk;
|
||||
vpu_pd->vapb_clk = vapb_clk;
|
||||
|
||||
powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd);
|
||||
platform_set_drvdata(pdev, vpu_pd);
|
||||
|
||||
powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd);
|
||||
|
||||
/* If already powered, sync the clock states */
|
||||
if (!powered_off) {
|
||||
ret = meson_gx_pwrc_vpu_setup_clk(&vpu_hdmi_pd);
|
||||
ret = meson_gx_pwrc_vpu_setup_clk(vpu_pd);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_genpd_init(&vpu_hdmi_pd.genpd, &pm_domain_always_on_gov,
|
||||
pm_genpd_init(&vpu_pd->genpd, &pm_domain_always_on_gov,
|
||||
powered_off);
|
||||
|
||||
return of_genpd_add_provider_simple(pdev->dev.of_node,
|
||||
&vpu_hdmi_pd.genpd);
|
||||
&vpu_pd->genpd);
|
||||
}
|
||||
|
||||
static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct meson_gx_pwrc_vpu *vpu_pd = platform_get_drvdata(pdev);
|
||||
bool powered_off;
|
||||
|
||||
powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd);
|
||||
powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd);
|
||||
if (!powered_off)
|
||||
meson_gx_pwrc_vpu_power_off(&vpu_hdmi_pd.genpd);
|
||||
vpu_pd->genpd.power_off(&vpu_pd->genpd);
|
||||
}
|
||||
|
||||
static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = {
|
||||
{ .compatible = "amlogic,meson-gx-pwrc-vpu" },
|
||||
{ .compatible = "amlogic,meson-gx-pwrc-vpu", .data = &vpu_hdmi_pd },
|
||||
{
|
||||
.compatible = "amlogic,meson-g12a-pwrc-vpu",
|
||||
.data = &vpu_hdmi_pd_g12a
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
|
@ -37,26 +37,34 @@ static const struct meson_gx_soc_id {
|
||||
{ "AXG", 0x25 },
|
||||
{ "GXLX", 0x26 },
|
||||
{ "TXHD", 0x27 },
|
||||
{ "G12A", 0x28 },
|
||||
{ "G12B", 0x29 },
|
||||
};
|
||||
|
||||
static const struct meson_gx_package_id {
|
||||
const char *name;
|
||||
unsigned int major_id;
|
||||
unsigned int pack_id;
|
||||
unsigned int pack_mask;
|
||||
} soc_packages[] = {
|
||||
{ "S905", 0x1f, 0 },
|
||||
{ "S905H", 0x1f, 0x13 },
|
||||
{ "S905M", 0x1f, 0x20 },
|
||||
{ "S905D", 0x21, 0 },
|
||||
{ "S905X", 0x21, 0x80 },
|
||||
{ "S905W", 0x21, 0xa0 },
|
||||
{ "S905L", 0x21, 0xc0 },
|
||||
{ "S905M2", 0x21, 0xe0 },
|
||||
{ "S912", 0x22, 0 },
|
||||
{ "962X", 0x24, 0x10 },
|
||||
{ "962E", 0x24, 0x20 },
|
||||
{ "A113X", 0x25, 0x37 },
|
||||
{ "A113D", 0x25, 0x22 },
|
||||
{ "S905", 0x1f, 0, 0x20 }, /* pack_id != 0x20 */
|
||||
{ "S905H", 0x1f, 0x3, 0xf }, /* pack_id & 0xf == 0x3 */
|
||||
{ "S905M", 0x1f, 0x20, 0xf0 }, /* pack_id == 0x20 */
|
||||
{ "S905D", 0x21, 0, 0xf0 },
|
||||
{ "S905X", 0x21, 0x80, 0xf0 },
|
||||
{ "S905W", 0x21, 0xa0, 0xf0 },
|
||||
{ "S905L", 0x21, 0xc0, 0xf0 },
|
||||
{ "S905M2", 0x21, 0xe0, 0xf0 },
|
||||
{ "S805X", 0x21, 0x30, 0xf0 },
|
||||
{ "S805Y", 0x21, 0xb0, 0xf0 },
|
||||
{ "S912", 0x22, 0, 0x0 }, /* Only S912 is known for GXM */
|
||||
{ "962X", 0x24, 0x10, 0xf0 },
|
||||
{ "962E", 0x24, 0x20, 0xf0 },
|
||||
{ "A113X", 0x25, 0x37, 0xff },
|
||||
{ "A113D", 0x25, 0x22, 0xff },
|
||||
{ "S905D2", 0x28, 0x10, 0xf0 },
|
||||
{ "S905X2", 0x28, 0x40, 0xf0 },
|
||||
{ "S922X", 0x29, 0x40, 0xf0 },
|
||||
};
|
||||
|
||||
static inline unsigned int socinfo_to_major(u32 socinfo)
|
||||
@ -81,13 +89,14 @@ static inline unsigned int socinfo_to_misc(u32 socinfo)
|
||||
|
||||
static const char *socinfo_to_package_id(u32 socinfo)
|
||||
{
|
||||
unsigned int pack = socinfo_to_pack(socinfo) & 0xf0;
|
||||
unsigned int pack = socinfo_to_pack(socinfo);
|
||||
unsigned int major = socinfo_to_major(socinfo);
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(soc_packages) ; ++i) {
|
||||
if (soc_packages[i].major_id == major &&
|
||||
soc_packages[i].pack_id == pack)
|
||||
soc_packages[i].pack_id ==
|
||||
(pack & soc_packages[i].pack_mask))
|
||||
return soc_packages[i].name;
|
||||
}
|
||||
|
||||
@ -123,8 +132,10 @@ static int __init meson_gx_socinfo_init(void)
|
||||
return -ENODEV;
|
||||
|
||||
/* check if interface is enabled */
|
||||
if (!of_device_is_available(np))
|
||||
if (!of_device_is_available(np)) {
|
||||
of_node_put(np);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* check if chip-id is available */
|
||||
if (!of_property_read_bool(np, "amlogic,has-chip-id"))
|
||||
|
31
drivers/soc/aspeed/Kconfig
Normal file
31
drivers/soc/aspeed/Kconfig
Normal file
@ -0,0 +1,31 @@
|
||||
menu "Aspeed SoC drivers"
|
||||
|
||||
config SOC_ASPEED
|
||||
def_bool y
|
||||
depends on ARCH_ASPEED || COMPILE_TEST
|
||||
|
||||
config ASPEED_LPC_CTRL
|
||||
depends on SOC_ASPEED && REGMAP && MFD_SYSCON
|
||||
tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control"
|
||||
---help---
|
||||
Control Aspeed ast2400/2500 HOST LPC to BMC mappings through
|
||||
ioctl()s, the driver also provides a read/write interface to a BMC ram
|
||||
region where the host LPC read/write region can be buffered.
|
||||
|
||||
config ASPEED_LPC_SNOOP
|
||||
tristate "Aspeed ast2500 HOST LPC snoop support"
|
||||
depends on SOC_ASPEED && REGMAP && MFD_SYSCON
|
||||
help
|
||||
Provides a driver to control the LPC snoop interface which
|
||||
allows the BMC to listen on and save the data written by
|
||||
the host to an arbitrary LPC I/O port.
|
||||
|
||||
config ASPEED_P2A_CTRL
|
||||
depends on SOC_ASPEED && REGMAP && MFD_SYSCON
|
||||
tristate "Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC bridge control"
|
||||
help
|
||||
Control Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC mappings through
|
||||
ioctl()s, the driver also provides an interface for userspace mappings to
|
||||
a pre-defined region.
|
||||
|
||||
endmenu
|
3
drivers/soc/aspeed/Makefile
Normal file
3
drivers/soc/aspeed/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
|
||||
obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
|
||||
obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o
|
@ -1,2 +1,3 @@
|
||||
obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
|
||||
obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
|
||||
obj-$(CONFIG_ARCH_MXC) += soc-imx8.o
|
||||
|
@ -406,7 +406,6 @@ static int imx_gpc_probe(struct platform_device *pdev)
|
||||
const struct imx_gpc_dt_data *of_id_data = of_id->data;
|
||||
struct device_node *pgc_node;
|
||||
struct regmap *regmap;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
@ -417,8 +416,7 @@ static int imx_gpc_probe(struct platform_device *pdev)
|
||||
!pgc_node)
|
||||
return 0;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
@ -136,8 +136,8 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
|
||||
GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ;
|
||||
const bool enable_power_control = !on;
|
||||
const bool has_regulator = !IS_ERR(domain->regulator);
|
||||
unsigned long deadline;
|
||||
int i, ret = 0;
|
||||
u32 pxx_req;
|
||||
|
||||
regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
|
||||
domain->bits.map, domain->bits.map);
|
||||
@ -169,30 +169,19 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
|
||||
* As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
|
||||
* for PUP_REQ/PDN_REQ bit to be cleared
|
||||
*/
|
||||
deadline = jiffies + msecs_to_jiffies(1);
|
||||
while (true) {
|
||||
u32 pxx_req;
|
||||
|
||||
regmap_read(domain->regmap, offset, &pxx_req);
|
||||
|
||||
if (!(pxx_req & domain->bits.pxx))
|
||||
break;
|
||||
|
||||
if (time_after(jiffies, deadline)) {
|
||||
dev_err(domain->dev, "falied to command PGC\n");
|
||||
ret = -ETIMEDOUT;
|
||||
/*
|
||||
* If we were in a process of enabling a
|
||||
* domain and failed we might as well disable
|
||||
* the regulator we just enabled. And if it
|
||||
* was the opposite situation and we failed to
|
||||
* power down -- keep the regulator on
|
||||
*/
|
||||
on = !on;
|
||||
break;
|
||||
}
|
||||
|
||||
cpu_relax();
|
||||
ret = regmap_read_poll_timeout(domain->regmap, offset, pxx_req,
|
||||
!(pxx_req & domain->bits.pxx),
|
||||
0, USEC_PER_MSEC);
|
||||
if (ret) {
|
||||
dev_err(domain->dev, "failed to command PGC\n");
|
||||
/*
|
||||
* If we were in a process of enabling a
|
||||
* domain and failed we might as well disable
|
||||
* the regulator we just enabled. And if it
|
||||
* was the opposite situation and we failed to
|
||||
* power down -- keep the regulator on
|
||||
*/
|
||||
on = !on;
|
||||
}
|
||||
|
||||
if (enable_power_control)
|
||||
@ -574,7 +563,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *pgc_np, *np;
|
||||
struct regmap *regmap;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
@ -584,8 +572,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(dev, res);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
115
drivers/soc/imx/soc-imx8.c
Normal file
115
drivers/soc/imx/soc-imx8.c
Normal file
@ -0,0 +1,115 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright 2019 NXP.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define REV_B1 0x21
|
||||
|
||||
#define IMX8MQ_SW_INFO_B1 0x40
|
||||
#define IMX8MQ_SW_MAGIC_B1 0xff0055aa
|
||||
|
||||
struct imx8_soc_data {
|
||||
char *name;
|
||||
u32 (*soc_revision)(void);
|
||||
};
|
||||
|
||||
static u32 __init imx8mq_soc_revision(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
void __iomem *ocotp_base;
|
||||
u32 magic;
|
||||
u32 rev = 0;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp");
|
||||
if (!np)
|
||||
goto out;
|
||||
|
||||
ocotp_base = of_iomap(np, 0);
|
||||
WARN_ON(!ocotp_base);
|
||||
|
||||
magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1);
|
||||
if (magic == IMX8MQ_SW_MAGIC_B1)
|
||||
rev = REV_B1;
|
||||
|
||||
iounmap(ocotp_base);
|
||||
|
||||
out:
|
||||
of_node_put(np);
|
||||
return rev;
|
||||
}
|
||||
|
||||
static const struct imx8_soc_data imx8mq_soc_data = {
|
||||
.name = "i.MX8MQ",
|
||||
.soc_revision = imx8mq_soc_revision,
|
||||
};
|
||||
|
||||
static const struct of_device_id imx8_soc_match[] = {
|
||||
{ .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, },
|
||||
{ }
|
||||
};
|
||||
|
||||
#define imx8_revision(soc_rev) \
|
||||
soc_rev ? \
|
||||
kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf, soc_rev & 0xf) : \
|
||||
"unknown"
|
||||
|
||||
static int __init imx8_soc_init(void)
|
||||
{
|
||||
struct soc_device_attribute *soc_dev_attr;
|
||||
struct soc_device *soc_dev;
|
||||
struct device_node *root;
|
||||
const struct of_device_id *id;
|
||||
u32 soc_rev = 0;
|
||||
const struct imx8_soc_data *data;
|
||||
int ret;
|
||||
|
||||
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
|
||||
if (!soc_dev_attr)
|
||||
return -ENODEV;
|
||||
|
||||
soc_dev_attr->family = "Freescale i.MX";
|
||||
|
||||
root = of_find_node_by_path("/");
|
||||
ret = of_property_read_string(root, "model", &soc_dev_attr->machine);
|
||||
if (ret)
|
||||
goto free_soc;
|
||||
|
||||
id = of_match_node(imx8_soc_match, root);
|
||||
if (!id)
|
||||
goto free_soc;
|
||||
|
||||
of_node_put(root);
|
||||
|
||||
data = id->data;
|
||||
if (data) {
|
||||
soc_dev_attr->soc_id = data->name;
|
||||
if (data->soc_revision)
|
||||
soc_rev = data->soc_revision();
|
||||
}
|
||||
|
||||
soc_dev_attr->revision = imx8_revision(soc_rev);
|
||||
if (!soc_dev_attr->revision)
|
||||
goto free_soc;
|
||||
|
||||
soc_dev = soc_device_register(soc_dev_attr);
|
||||
if (IS_ERR(soc_dev))
|
||||
goto free_rev;
|
||||
|
||||
return 0;
|
||||
|
||||
free_rev:
|
||||
kfree(soc_dev_attr->revision);
|
||||
free_soc:
|
||||
kfree(soc_dev_attr);
|
||||
of_node_put(root);
|
||||
return -ENODEV;
|
||||
}
|
||||
device_initcall(imx8_soc_init);
|
@ -381,6 +381,10 @@ enum pwrap_regs {
|
||||
PWRAP_EXT_GPS_AUXADC_RDATA_ADDR,
|
||||
PWRAP_GPSINF_0_STA,
|
||||
PWRAP_GPSINF_1_STA,
|
||||
|
||||
/* MT8516 only regs */
|
||||
PWRAP_OP_TYPE,
|
||||
PWRAP_MSB_FIRST,
|
||||
};
|
||||
|
||||
static int mt2701_regs[] = {
|
||||
@ -852,6 +856,91 @@ static int mt8183_regs[] = {
|
||||
[PWRAP_WACS2_VLDCLR] = 0xC28,
|
||||
};
|
||||
|
||||
static int mt8516_regs[] = {
|
||||
[PWRAP_MUX_SEL] = 0x0,
|
||||
[PWRAP_WRAP_EN] = 0x4,
|
||||
[PWRAP_DIO_EN] = 0x8,
|
||||
[PWRAP_SIDLY] = 0xc,
|
||||
[PWRAP_RDDMY] = 0x10,
|
||||
[PWRAP_SI_CK_CON] = 0x14,
|
||||
[PWRAP_CSHEXT_WRITE] = 0x18,
|
||||
[PWRAP_CSHEXT_READ] = 0x1c,
|
||||
[PWRAP_CSLEXT_START] = 0x20,
|
||||
[PWRAP_CSLEXT_END] = 0x24,
|
||||
[PWRAP_STAUPD_PRD] = 0x28,
|
||||
[PWRAP_STAUPD_GRPEN] = 0x2c,
|
||||
[PWRAP_STAUPD_MAN_TRIG] = 0x40,
|
||||
[PWRAP_STAUPD_STA] = 0x44,
|
||||
[PWRAP_WRAP_STA] = 0x48,
|
||||
[PWRAP_HARB_INIT] = 0x4c,
|
||||
[PWRAP_HARB_HPRIO] = 0x50,
|
||||
[PWRAP_HIPRIO_ARB_EN] = 0x54,
|
||||
[PWRAP_HARB_STA0] = 0x58,
|
||||
[PWRAP_HARB_STA1] = 0x5c,
|
||||
[PWRAP_MAN_EN] = 0x60,
|
||||
[PWRAP_MAN_CMD] = 0x64,
|
||||
[PWRAP_MAN_RDATA] = 0x68,
|
||||
[PWRAP_MAN_VLDCLR] = 0x6c,
|
||||
[PWRAP_WACS0_EN] = 0x70,
|
||||
[PWRAP_INIT_DONE0] = 0x74,
|
||||
[PWRAP_WACS0_CMD] = 0x78,
|
||||
[PWRAP_WACS0_RDATA] = 0x7c,
|
||||
[PWRAP_WACS0_VLDCLR] = 0x80,
|
||||
[PWRAP_WACS1_EN] = 0x84,
|
||||
[PWRAP_INIT_DONE1] = 0x88,
|
||||
[PWRAP_WACS1_CMD] = 0x8c,
|
||||
[PWRAP_WACS1_RDATA] = 0x90,
|
||||
[PWRAP_WACS1_VLDCLR] = 0x94,
|
||||
[PWRAP_WACS2_EN] = 0x98,
|
||||
[PWRAP_INIT_DONE2] = 0x9c,
|
||||
[PWRAP_WACS2_CMD] = 0xa0,
|
||||
[PWRAP_WACS2_RDATA] = 0xa4,
|
||||
[PWRAP_WACS2_VLDCLR] = 0xa8,
|
||||
[PWRAP_INT_EN] = 0xac,
|
||||
[PWRAP_INT_FLG_RAW] = 0xb0,
|
||||
[PWRAP_INT_FLG] = 0xb4,
|
||||
[PWRAP_INT_CLR] = 0xb8,
|
||||
[PWRAP_SIG_ADR] = 0xbc,
|
||||
[PWRAP_SIG_MODE] = 0xc0,
|
||||
[PWRAP_SIG_VALUE] = 0xc4,
|
||||
[PWRAP_SIG_ERRVAL] = 0xc8,
|
||||
[PWRAP_CRC_EN] = 0xcc,
|
||||
[PWRAP_TIMER_EN] = 0xd0,
|
||||
[PWRAP_TIMER_STA] = 0xd4,
|
||||
[PWRAP_WDT_UNIT] = 0xd8,
|
||||
[PWRAP_WDT_SRC_EN] = 0xdc,
|
||||
[PWRAP_WDT_FLG] = 0xe0,
|
||||
[PWRAP_DEBUG_INT_SEL] = 0xe4,
|
||||
[PWRAP_DVFS_ADR0] = 0xe8,
|
||||
[PWRAP_DVFS_WDATA0] = 0xec,
|
||||
[PWRAP_DVFS_ADR1] = 0xf0,
|
||||
[PWRAP_DVFS_WDATA1] = 0xf4,
|
||||
[PWRAP_DVFS_ADR2] = 0xf8,
|
||||
[PWRAP_DVFS_WDATA2] = 0xfc,
|
||||
[PWRAP_DVFS_ADR3] = 0x100,
|
||||
[PWRAP_DVFS_WDATA3] = 0x104,
|
||||
[PWRAP_DVFS_ADR4] = 0x108,
|
||||
[PWRAP_DVFS_WDATA4] = 0x10c,
|
||||
[PWRAP_DVFS_ADR5] = 0x110,
|
||||
[PWRAP_DVFS_WDATA5] = 0x114,
|
||||
[PWRAP_DVFS_ADR6] = 0x118,
|
||||
[PWRAP_DVFS_WDATA6] = 0x11c,
|
||||
[PWRAP_DVFS_ADR7] = 0x120,
|
||||
[PWRAP_DVFS_WDATA7] = 0x124,
|
||||
[PWRAP_SPMINF_STA] = 0x128,
|
||||
[PWRAP_CIPHER_KEY_SEL] = 0x12c,
|
||||
[PWRAP_CIPHER_IV_SEL] = 0x130,
|
||||
[PWRAP_CIPHER_EN] = 0x134,
|
||||
[PWRAP_CIPHER_RDY] = 0x138,
|
||||
[PWRAP_CIPHER_MODE] = 0x13c,
|
||||
[PWRAP_CIPHER_SWRST] = 0x140,
|
||||
[PWRAP_DCM_EN] = 0x144,
|
||||
[PWRAP_DCM_DBC_PRD] = 0x148,
|
||||
[PWRAP_SW_RST] = 0x168,
|
||||
[PWRAP_OP_TYPE] = 0x16c,
|
||||
[PWRAP_MSB_FIRST] = 0x170,
|
||||
};
|
||||
|
||||
enum pmic_type {
|
||||
PMIC_MT6323,
|
||||
PMIC_MT6351,
|
||||
@ -869,6 +958,7 @@ enum pwrap_type {
|
||||
PWRAP_MT8135,
|
||||
PWRAP_MT8173,
|
||||
PWRAP_MT8183,
|
||||
PWRAP_MT8516,
|
||||
};
|
||||
|
||||
struct pmic_wrapper;
|
||||
@ -1281,7 +1371,7 @@ static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp)
|
||||
static int pwrap_init_cipher(struct pmic_wrapper *wrp)
|
||||
{
|
||||
int ret;
|
||||
u32 rdata;
|
||||
u32 rdata = 0;
|
||||
|
||||
pwrap_writel(wrp, 0x1, PWRAP_CIPHER_SWRST);
|
||||
pwrap_writel(wrp, 0x0, PWRAP_CIPHER_SWRST);
|
||||
@ -1297,6 +1387,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
|
||||
case PWRAP_MT6765:
|
||||
case PWRAP_MT6797:
|
||||
case PWRAP_MT8173:
|
||||
case PWRAP_MT8516:
|
||||
pwrap_writel(wrp, 1, PWRAP_CIPHER_EN);
|
||||
break;
|
||||
case PWRAP_MT7622:
|
||||
@ -1478,7 +1569,8 @@ static int pwrap_init(struct pmic_wrapper *wrp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
reset_control_reset(wrp->rstc);
|
||||
if (wrp->rstc)
|
||||
reset_control_reset(wrp->rstc);
|
||||
if (wrp->rstc_bridge)
|
||||
reset_control_reset(wrp->rstc_bridge);
|
||||
|
||||
@ -1764,6 +1856,18 @@ static const struct pmic_wrapper_type pwrap_mt8183 = {
|
||||
.init_soc_specific = pwrap_mt8183_init_soc_specific,
|
||||
};
|
||||
|
||||
static struct pmic_wrapper_type pwrap_mt8516 = {
|
||||
.regs = mt8516_regs,
|
||||
.type = PWRAP_MT8516,
|
||||
.arb_en_all = 0xff,
|
||||
.int_en_all = ~(u32)(BIT(31) | BIT(2)),
|
||||
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
|
||||
.wdt_src = PWRAP_WDT_SRC_MASK_ALL,
|
||||
.caps = PWRAP_CAP_DCM,
|
||||
.init_reg_clock = pwrap_mt2701_init_reg_clock,
|
||||
.init_soc_specific = NULL,
|
||||
};
|
||||
|
||||
static const struct of_device_id of_pwrap_match_tbl[] = {
|
||||
{
|
||||
.compatible = "mediatek,mt2701-pwrap",
|
||||
@ -1786,6 +1890,9 @@ static const struct of_device_id of_pwrap_match_tbl[] = {
|
||||
}, {
|
||||
.compatible = "mediatek,mt8183-pwrap",
|
||||
.data = &pwrap_mt8183,
|
||||
}, {
|
||||
.compatible = "mediatek,mt8516-pwrap",
|
||||
.data = &pwrap_mt8516,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
|
@ -248,8 +248,8 @@ static int cmd_db_dev_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WB);
|
||||
if (IS_ERR_OR_NULL(cmd_db_header)) {
|
||||
ret = PTR_ERR(cmd_db_header);
|
||||
if (!cmd_db_header) {
|
||||
ret = -ENOMEM;
|
||||
cmd_db_header = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
@ -345,8 +345,7 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout)
|
||||
struct qmi_handle *qmi = txn->qmi;
|
||||
int ret;
|
||||
|
||||
ret = wait_for_completion_interruptible_timeout(&txn->completion,
|
||||
timeout);
|
||||
ret = wait_for_completion_timeout(&txn->completion, timeout);
|
||||
|
||||
mutex_lock(&qmi->txn_lock);
|
||||
mutex_lock(&txn->lock);
|
||||
@ -354,9 +353,7 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout)
|
||||
mutex_unlock(&txn->lock);
|
||||
mutex_unlock(&qmi->txn_lock);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret == 0)
|
||||
if (ret == 0)
|
||||
return -ETIMEDOUT;
|
||||
else
|
||||
return txn->result;
|
||||
|
@ -137,6 +137,26 @@ static struct class rmtfs_class = {
|
||||
.name = "rmtfs",
|
||||
};
|
||||
|
||||
static int qcom_rmtfs_mem_mmap(struct file *filep, struct vm_area_struct *vma)
|
||||
{
|
||||
struct qcom_rmtfs_mem *rmtfs_mem = filep->private_data;
|
||||
|
||||
if (vma->vm_end - vma->vm_start > rmtfs_mem->size) {
|
||||
dev_dbg(&rmtfs_mem->dev,
|
||||
"vm_end[%lu] - vm_start[%lu] [%lu] > mem->size[%pa]\n",
|
||||
vma->vm_end, vma->vm_start,
|
||||
(vma->vm_end - vma->vm_start), &rmtfs_mem->size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
|
||||
return remap_pfn_range(vma,
|
||||
vma->vm_start,
|
||||
rmtfs_mem->addr >> PAGE_SHIFT,
|
||||
vma->vm_end - vma->vm_start,
|
||||
vma->vm_page_prot);
|
||||
}
|
||||
|
||||
static const struct file_operations qcom_rmtfs_mem_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = qcom_rmtfs_mem_open,
|
||||
@ -144,6 +164,7 @@ static const struct file_operations qcom_rmtfs_mem_fops = {
|
||||
.write = qcom_rmtfs_mem_write,
|
||||
.release = qcom_rmtfs_mem_release,
|
||||
.llseek = default_llseek,
|
||||
.mmap = qcom_rmtfs_mem_mmap,
|
||||
};
|
||||
|
||||
static void qcom_rmtfs_mem_release_device(struct device *dev)
|
||||
|
@ -459,7 +459,7 @@ static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg,
|
||||
do {
|
||||
slot = bitmap_find_next_zero_area(tcs->slots, MAX_TCS_SLOTS,
|
||||
i, msg->num_cmds, 0);
|
||||
if (slot == tcs->num_tcs * tcs->ncpt)
|
||||
if (slot >= tcs->num_tcs * tcs->ncpt)
|
||||
return -ENOMEM;
|
||||
i += tcs->ncpt;
|
||||
} while (slot + msg->num_cmds - 1 >= i);
|
||||
|
@ -335,6 +335,9 @@ static int __init renesas_soc_init(void)
|
||||
/* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */
|
||||
if ((product & 0x7fff) == 0x5210)
|
||||
product ^= 0x11;
|
||||
/* R-Car M3-W ES1.3 incorrectly identifies as ES2.1 */
|
||||
if ((product & 0x7fff) == 0x5211)
|
||||
product ^= 0x12;
|
||||
if (soc->id && ((product >> 8) & 0xff) != soc->id) {
|
||||
pr_warn("SoC mismatch (product = 0x%x)\n", product);
|
||||
return -ENODEV;
|
||||
|
@ -66,9 +66,11 @@ static const struct rockchip_grf_info rk3228_grf __initconst = {
|
||||
};
|
||||
|
||||
#define RK3288_GRF_SOC_CON0 0x244
|
||||
#define RK3288_GRF_SOC_CON2 0x24c
|
||||
|
||||
static const struct rockchip_grf_value rk3288_defaults[] __initconst = {
|
||||
{ "jtag switching", RK3288_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 12) },
|
||||
{ "pwm select", RK3288_GRF_SOC_CON2, HIWORD_UPDATE(1, 1, 0) },
|
||||
};
|
||||
|
||||
static const struct rockchip_grf_info rk3288_grf __initconst = {
|
||||
|
@ -268,6 +268,14 @@ static const char * const tegra186_reset_levels[] = {
|
||||
};
|
||||
|
||||
static const char * const tegra30_reset_sources[] = {
|
||||
"POWER_ON_RESET",
|
||||
"WATCHDOG",
|
||||
"SENSOR",
|
||||
"SW_MAIN",
|
||||
"LP0"
|
||||
};
|
||||
|
||||
static const char * const tegra210_reset_sources[] = {
|
||||
"POWER_ON_RESET",
|
||||
"WATCHDOG",
|
||||
"SENSOR",
|
||||
@ -656,10 +664,15 @@ static int tegra_genpd_power_on(struct generic_pm_domain *domain)
|
||||
int err;
|
||||
|
||||
err = tegra_powergate_power_up(pg, true);
|
||||
if (err)
|
||||
if (err) {
|
||||
dev_err(dev, "failed to turn on PM domain %s: %d\n",
|
||||
pg->genpd.name, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
reset_control_release(pg->reset);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -669,10 +682,18 @@ static int tegra_genpd_power_off(struct generic_pm_domain *domain)
|
||||
struct device *dev = pg->pmc->dev;
|
||||
int err;
|
||||
|
||||
err = reset_control_acquire(pg->reset);
|
||||
if (err < 0) {
|
||||
pr_err("failed to acquire resets: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = tegra_powergate_power_down(pg);
|
||||
if (err)
|
||||
if (err) {
|
||||
dev_err(dev, "failed to turn off PM domain %s: %d\n",
|
||||
pg->genpd.name, err);
|
||||
reset_control_release(pg->reset);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -937,38 +958,53 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
|
||||
struct device *dev = pg->pmc->dev;
|
||||
int err;
|
||||
|
||||
pg->reset = of_reset_control_array_get_exclusive(np);
|
||||
pg->reset = of_reset_control_array_get_exclusive_released(np);
|
||||
if (IS_ERR(pg->reset)) {
|
||||
err = PTR_ERR(pg->reset);
|
||||
dev_err(dev, "failed to get device resets: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (off)
|
||||
err = reset_control_assert(pg->reset);
|
||||
else
|
||||
err = reset_control_deassert(pg->reset);
|
||||
err = reset_control_acquire(pg->reset);
|
||||
if (err < 0) {
|
||||
pr_err("failed to acquire resets: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (err)
|
||||
if (off) {
|
||||
err = reset_control_assert(pg->reset);
|
||||
} else {
|
||||
err = reset_control_deassert(pg->reset);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
reset_control_release(pg->reset);
|
||||
}
|
||||
|
||||
out:
|
||||
if (err) {
|
||||
reset_control_release(pg->reset);
|
||||
reset_control_put(pg->reset);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
|
||||
static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
|
||||
{
|
||||
struct device *dev = pmc->dev;
|
||||
struct tegra_powergate *pg;
|
||||
int id, err;
|
||||
int id, err = 0;
|
||||
bool off;
|
||||
|
||||
pg = kzalloc(sizeof(*pg), GFP_KERNEL);
|
||||
if (!pg)
|
||||
return;
|
||||
return -ENOMEM;
|
||||
|
||||
id = tegra_powergate_lookup(pmc, np->name);
|
||||
if (id < 0) {
|
||||
dev_err(dev, "powergate lookup failed for %pOFn: %d\n", np, id);
|
||||
err = -ENODEV;
|
||||
goto free_mem;
|
||||
}
|
||||
|
||||
@ -1021,7 +1057,7 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
|
||||
|
||||
dev_dbg(dev, "added PM domain %s\n", pg->genpd.name);
|
||||
|
||||
return;
|
||||
return 0;
|
||||
|
||||
remove_genpd:
|
||||
pm_genpd_remove(&pg->genpd);
|
||||
@ -1040,25 +1076,67 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
|
||||
|
||||
free_mem:
|
||||
kfree(pg);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void tegra_powergate_init(struct tegra_pmc *pmc,
|
||||
struct device_node *parent)
|
||||
static int tegra_powergate_init(struct tegra_pmc *pmc,
|
||||
struct device_node *parent)
|
||||
{
|
||||
struct device_node *np, *child;
|
||||
unsigned int i;
|
||||
int err = 0;
|
||||
|
||||
/* Create a bitmap of the available and valid partitions */
|
||||
for (i = 0; i < pmc->soc->num_powergates; i++)
|
||||
if (pmc->soc->powergates[i])
|
||||
set_bit(i, pmc->powergates_available);
|
||||
np = of_get_child_by_name(parent, "powergates");
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
for_each_child_of_node(np, child) {
|
||||
err = tegra_powergate_add(pmc, child);
|
||||
if (err < 0) {
|
||||
of_node_put(child);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
of_node_put(np);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void tegra_powergate_remove(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct tegra_powergate *pg = to_powergate(genpd);
|
||||
|
||||
reset_control_put(pg->reset);
|
||||
|
||||
while (pg->num_clks--)
|
||||
clk_put(pg->clks[pg->num_clks]);
|
||||
|
||||
kfree(pg->clks);
|
||||
|
||||
set_bit(pg->id, pmc->powergates_available);
|
||||
|
||||
kfree(pg);
|
||||
}
|
||||
|
||||
static void tegra_powergate_remove_all(struct device_node *parent)
|
||||
{
|
||||
struct generic_pm_domain *genpd;
|
||||
struct device_node *np, *child;
|
||||
|
||||
np = of_get_child_by_name(parent, "powergates");
|
||||
if (!np)
|
||||
return;
|
||||
|
||||
for_each_child_of_node(np, child)
|
||||
tegra_powergate_add(pmc, child);
|
||||
for_each_child_of_node(np, child) {
|
||||
of_genpd_del_provider(child);
|
||||
|
||||
genpd = of_genpd_remove_last(child);
|
||||
if (IS_ERR(genpd))
|
||||
continue;
|
||||
|
||||
tegra_powergate_remove(genpd);
|
||||
}
|
||||
|
||||
of_node_put(np);
|
||||
}
|
||||
@ -1709,13 +1787,16 @@ static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc)
|
||||
static ssize_t reset_reason_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
u32 value, rst_src;
|
||||
u32 value;
|
||||
|
||||
value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status);
|
||||
rst_src = (value & pmc->soc->regs->rst_source_mask) >>
|
||||
pmc->soc->regs->rst_source_shift;
|
||||
value &= pmc->soc->regs->rst_source_mask;
|
||||
value >>= pmc->soc->regs->rst_source_shift;
|
||||
|
||||
return sprintf(buf, "%s\n", pmc->soc->reset_sources[rst_src]);
|
||||
if (WARN_ON(value >= pmc->soc->num_reset_sources))
|
||||
return sprintf(buf, "%s\n", "UNKNOWN");
|
||||
|
||||
return sprintf(buf, "%s\n", pmc->soc->reset_sources[value]);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(reset_reason);
|
||||
@ -1723,13 +1804,16 @@ static DEVICE_ATTR_RO(reset_reason);
|
||||
static ssize_t reset_level_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
u32 value, rst_lvl;
|
||||
u32 value;
|
||||
|
||||
value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status);
|
||||
rst_lvl = (value & pmc->soc->regs->rst_level_mask) >>
|
||||
pmc->soc->regs->rst_level_shift;
|
||||
value &= pmc->soc->regs->rst_level_mask;
|
||||
value >>= pmc->soc->regs->rst_level_shift;
|
||||
|
||||
return sprintf(buf, "%s\n", pmc->soc->reset_levels[rst_lvl]);
|
||||
if (WARN_ON(value >= pmc->soc->num_reset_levels))
|
||||
return sprintf(buf, "%s\n", "UNKNOWN");
|
||||
|
||||
return sprintf(buf, "%s\n", pmc->soc->reset_levels[value]);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(reset_level);
|
||||
@ -1999,7 +2083,7 @@ static int tegra_pmc_probe(struct platform_device *pdev)
|
||||
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
|
||||
err = tegra_powergate_debugfs_init();
|
||||
if (err < 0)
|
||||
return err;
|
||||
goto cleanup_sysfs;
|
||||
}
|
||||
|
||||
err = register_restart_handler(&tegra_pmc_restart_handler);
|
||||
@ -2013,9 +2097,13 @@ static int tegra_pmc_probe(struct platform_device *pdev)
|
||||
if (err)
|
||||
goto cleanup_restart_handler;
|
||||
|
||||
err = tegra_powergate_init(pmc, pdev->dev.of_node);
|
||||
if (err < 0)
|
||||
goto cleanup_powergates;
|
||||
|
||||
err = tegra_pmc_irq_init(pmc);
|
||||
if (err < 0)
|
||||
goto cleanup_restart_handler;
|
||||
goto cleanup_powergates;
|
||||
|
||||
mutex_lock(&pmc->powergates_lock);
|
||||
iounmap(pmc->base);
|
||||
@ -2026,10 +2114,15 @@ static int tegra_pmc_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_powergates:
|
||||
tegra_powergate_remove_all(pdev->dev.of_node);
|
||||
cleanup_restart_handler:
|
||||
unregister_restart_handler(&tegra_pmc_restart_handler);
|
||||
cleanup_debugfs:
|
||||
debugfs_remove(pmc->debugfs);
|
||||
cleanup_sysfs:
|
||||
device_remove_file(&pdev->dev, &dev_attr_reset_reason);
|
||||
device_remove_file(&pdev->dev, &dev_attr_reset_level);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -2185,7 +2278,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
|
||||
.init = tegra20_pmc_init,
|
||||
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
|
||||
.reset_sources = tegra30_reset_sources,
|
||||
.num_reset_sources = 5,
|
||||
.num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
|
||||
.reset_levels = NULL,
|
||||
.num_reset_levels = 0,
|
||||
};
|
||||
@ -2236,7 +2329,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
|
||||
.init = tegra20_pmc_init,
|
||||
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
|
||||
.reset_sources = tegra30_reset_sources,
|
||||
.num_reset_sources = 5,
|
||||
.num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
|
||||
.reset_levels = NULL,
|
||||
.num_reset_levels = 0,
|
||||
};
|
||||
@ -2347,7 +2440,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
|
||||
.init = tegra20_pmc_init,
|
||||
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
|
||||
.reset_sources = tegra30_reset_sources,
|
||||
.num_reset_sources = 5,
|
||||
.num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
|
||||
.reset_levels = NULL,
|
||||
.num_reset_levels = 0,
|
||||
};
|
||||
@ -2452,8 +2545,8 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
|
||||
.regs = &tegra20_pmc_regs,
|
||||
.init = tegra20_pmc_init,
|
||||
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
|
||||
.reset_sources = tegra30_reset_sources,
|
||||
.num_reset_sources = 5,
|
||||
.reset_sources = tegra210_reset_sources,
|
||||
.num_reset_sources = ARRAY_SIZE(tegra210_reset_sources),
|
||||
.reset_levels = NULL,
|
||||
.num_reset_levels = 0,
|
||||
};
|
||||
@ -2578,9 +2671,9 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
|
||||
.init = NULL,
|
||||
.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
|
||||
.reset_sources = tegra186_reset_sources,
|
||||
.num_reset_sources = 14,
|
||||
.num_reset_sources = ARRAY_SIZE(tegra186_reset_sources),
|
||||
.reset_levels = tegra186_reset_levels,
|
||||
.num_reset_levels = 3,
|
||||
.num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
|
||||
.num_wake_events = ARRAY_SIZE(tegra186_wake_events),
|
||||
.wake_events = tegra186_wake_events,
|
||||
};
|
||||
@ -2719,6 +2812,7 @@ static int __init tegra_pmc_early_init(void)
|
||||
const struct of_device_id *match;
|
||||
struct device_node *np;
|
||||
struct resource regs;
|
||||
unsigned int i;
|
||||
bool invert;
|
||||
|
||||
mutex_init(&pmc->powergates_lock);
|
||||
@ -2775,7 +2869,10 @@ static int __init tegra_pmc_early_init(void)
|
||||
if (pmc->soc->maybe_tz_only)
|
||||
pmc->tz_only = tegra_pmc_detect_tz_only(pmc);
|
||||
|
||||
tegra_powergate_init(pmc, np);
|
||||
/* Create a bitmap of the available and valid partitions */
|
||||
for (i = 0; i < pmc->soc->num_powergates; i++)
|
||||
if (pmc->soc->powergates[i])
|
||||
set_bit(i, pmc->powergates_available);
|
||||
|
||||
/*
|
||||
* Invert the interrupt polarity if a PMC device tree node
|
||||
|
@ -45,11 +45,12 @@ config KEYSTONE_NAVIGATOR_DMA
|
||||
config AMX3_PM
|
||||
tristate "AMx3 Power Management"
|
||||
depends on SOC_AM33XX || SOC_AM43XX
|
||||
depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM
|
||||
depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM && RTC_DRV_OMAP
|
||||
help
|
||||
Enable power management on AM335x and AM437x. Required for suspend to mem
|
||||
and standby states on both AM335x and AM437x platforms and for deeper cpuidle
|
||||
c-states on AM335x.
|
||||
c-states on AM335x. Also required for rtc and ddr in self-refresh low
|
||||
power mode on AM437x platforms.
|
||||
|
||||
config WKUP_M3_IPC
|
||||
tristate "TI AMx3 Wkup-M3 IPC Driver"
|
||||
|
@ -6,6 +6,7 @@
|
||||
* Vaibhav Bedia, Dave Gerlach
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/genalloc.h>
|
||||
@ -13,9 +14,12 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nvmem-consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/pm33xx.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/rtc/rtc-omap.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/sram.h>
|
||||
#include <linux/suspend.h>
|
||||
@ -29,33 +33,162 @@
|
||||
#define AMX3_PM_SRAM_SYMBOL_OFFSET(sym) ((unsigned long)(sym) - \
|
||||
(unsigned long)pm_sram->do_wfi)
|
||||
|
||||
#define RTC_SCRATCH_RESUME_REG 0
|
||||
#define RTC_SCRATCH_MAGIC_REG 1
|
||||
#define RTC_REG_BOOT_MAGIC 0x8cd0 /* RTC */
|
||||
#define GIC_INT_SET_PENDING_BASE 0x200
|
||||
#define AM43XX_GIC_DIST_BASE 0x48241000
|
||||
|
||||
static u32 rtc_magic_val;
|
||||
|
||||
static int (*am33xx_do_wfi_sram)(unsigned long unused);
|
||||
static phys_addr_t am33xx_do_wfi_sram_phys;
|
||||
|
||||
static struct gen_pool *sram_pool, *sram_pool_data;
|
||||
static unsigned long ocmcram_location, ocmcram_location_data;
|
||||
|
||||
static struct rtc_device *omap_rtc;
|
||||
static void __iomem *gic_dist_base;
|
||||
|
||||
static struct am33xx_pm_platform_data *pm_ops;
|
||||
static struct am33xx_pm_sram_addr *pm_sram;
|
||||
|
||||
static struct device *pm33xx_dev;
|
||||
static struct wkup_m3_ipc *m3_ipc;
|
||||
|
||||
#ifdef CONFIG_SUSPEND
|
||||
static int rtc_only_idle;
|
||||
static int retrigger_irq;
|
||||
static unsigned long suspend_wfi_flags;
|
||||
|
||||
static struct wkup_m3_wakeup_src wakeup_src = {.irq_nr = 0,
|
||||
.src = "Unknown",
|
||||
};
|
||||
|
||||
static struct wkup_m3_wakeup_src rtc_alarm_wakeup = {
|
||||
.irq_nr = 108, .src = "RTC Alarm",
|
||||
};
|
||||
|
||||
static struct wkup_m3_wakeup_src rtc_ext_wakeup = {
|
||||
.irq_nr = 0, .src = "Ext wakeup",
|
||||
};
|
||||
#endif
|
||||
|
||||
static u32 sram_suspend_address(unsigned long addr)
|
||||
{
|
||||
return ((unsigned long)am33xx_do_wfi_sram +
|
||||
AMX3_PM_SRAM_SYMBOL_OFFSET(addr));
|
||||
}
|
||||
|
||||
static int am33xx_push_sram_idle(void)
|
||||
{
|
||||
struct am33xx_pm_ro_sram_data ro_sram_data;
|
||||
int ret;
|
||||
u32 table_addr, ro_data_addr;
|
||||
void *copy_addr;
|
||||
|
||||
ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data;
|
||||
ro_sram_data.amx3_pm_sram_data_phys =
|
||||
gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data);
|
||||
ro_sram_data.rtc_base_virt = pm_ops->get_rtc_base_addr();
|
||||
|
||||
/* Save physical address to calculate resume offset during pm init */
|
||||
am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool,
|
||||
ocmcram_location);
|
||||
|
||||
am33xx_do_wfi_sram = sram_exec_copy(sram_pool, (void *)ocmcram_location,
|
||||
pm_sram->do_wfi,
|
||||
*pm_sram->do_wfi_sz);
|
||||
if (!am33xx_do_wfi_sram) {
|
||||
dev_err(pm33xx_dev,
|
||||
"PM: %s: am33xx_do_wfi copy to sram failed\n",
|
||||
__func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
table_addr =
|
||||
sram_suspend_address((unsigned long)pm_sram->emif_sram_table);
|
||||
ret = ti_emif_copy_pm_function_table(sram_pool, (void *)table_addr);
|
||||
if (ret) {
|
||||
dev_dbg(pm33xx_dev,
|
||||
"PM: %s: EMIF function copy failed\n", __func__);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ro_data_addr =
|
||||
sram_suspend_address((unsigned long)pm_sram->ro_sram_data);
|
||||
copy_addr = sram_exec_copy(sram_pool, (void *)ro_data_addr,
|
||||
&ro_sram_data,
|
||||
sizeof(ro_sram_data));
|
||||
if (!copy_addr) {
|
||||
dev_err(pm33xx_dev,
|
||||
"PM: %s: ro_sram_data copy to sram failed\n",
|
||||
__func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init am43xx_map_gic(void)
|
||||
{
|
||||
gic_dist_base = ioremap(AM43XX_GIC_DIST_BASE, SZ_4K);
|
||||
|
||||
if (!gic_dist_base)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SUSPEND
|
||||
struct wkup_m3_wakeup_src rtc_wake_src(void)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
i = __raw_readl(pm_ops->get_rtc_base_addr() + 0x44) & 0x40;
|
||||
|
||||
if (i) {
|
||||
retrigger_irq = rtc_alarm_wakeup.irq_nr;
|
||||
return rtc_alarm_wakeup;
|
||||
}
|
||||
|
||||
retrigger_irq = rtc_ext_wakeup.irq_nr;
|
||||
|
||||
return rtc_ext_wakeup;
|
||||
}
|
||||
|
||||
int am33xx_rtc_only_idle(unsigned long wfi_flags)
|
||||
{
|
||||
omap_rtc_power_off_program(&omap_rtc->dev);
|
||||
am33xx_do_wfi_sram(wfi_flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int am33xx_pm_suspend(suspend_state_t suspend_state)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
ret = pm_ops->soc_suspend((unsigned long)suspend_state,
|
||||
am33xx_do_wfi_sram, suspend_wfi_flags);
|
||||
if (suspend_state == PM_SUSPEND_MEM &&
|
||||
pm_ops->check_off_mode_enable()) {
|
||||
pm_ops->prepare_rtc_suspend();
|
||||
pm_ops->save_context();
|
||||
suspend_wfi_flags |= WFI_FLAG_RTC_ONLY;
|
||||
clk_save_context();
|
||||
ret = pm_ops->soc_suspend(suspend_state, am33xx_rtc_only_idle,
|
||||
suspend_wfi_flags);
|
||||
|
||||
suspend_wfi_flags &= ~WFI_FLAG_RTC_ONLY;
|
||||
|
||||
if (!ret) {
|
||||
clk_restore_context();
|
||||
pm_ops->restore_context();
|
||||
m3_ipc->ops->set_rtc_only(m3_ipc);
|
||||
am33xx_push_sram_idle();
|
||||
}
|
||||
} else {
|
||||
ret = pm_ops->soc_suspend(suspend_state, am33xx_do_wfi_sram,
|
||||
suspend_wfi_flags);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
dev_err(pm33xx_dev, "PM: Kernel suspend failure\n");
|
||||
@ -77,8 +210,20 @@ static int am33xx_pm_suspend(suspend_state_t suspend_state)
|
||||
"PM: CM3 returned unknown result = %d\n", i);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
/* print the wakeup reason */
|
||||
if (rtc_only_idle) {
|
||||
wakeup_src = rtc_wake_src();
|
||||
pr_info("PM: Wakeup source %s\n", wakeup_src.src);
|
||||
} else {
|
||||
pr_info("PM: Wakeup source %s\n",
|
||||
m3_ipc->ops->request_wake_src(m3_ipc));
|
||||
}
|
||||
}
|
||||
|
||||
if (suspend_state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable())
|
||||
pm_ops->prepare_rtc_resume();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -101,6 +246,18 @@ static int am33xx_pm_enter(suspend_state_t suspend_state)
|
||||
static int am33xx_pm_begin(suspend_state_t state)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct nvmem_device *nvmem;
|
||||
|
||||
if (state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) {
|
||||
nvmem = devm_nvmem_device_get(&omap_rtc->dev,
|
||||
"omap_rtc_scratch0");
|
||||
if (nvmem)
|
||||
nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4,
|
||||
(void *)&rtc_magic_val);
|
||||
rtc_only_idle = 1;
|
||||
} else {
|
||||
rtc_only_idle = 0;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case PM_SUSPEND_MEM:
|
||||
@ -116,7 +273,28 @@ static int am33xx_pm_begin(suspend_state_t state)
|
||||
|
||||
static void am33xx_pm_end(void)
|
||||
{
|
||||
u32 val = 0;
|
||||
struct nvmem_device *nvmem;
|
||||
|
||||
nvmem = devm_nvmem_device_get(&omap_rtc->dev, "omap_rtc_scratch0");
|
||||
m3_ipc->ops->finish_low_power(m3_ipc);
|
||||
if (rtc_only_idle) {
|
||||
if (retrigger_irq)
|
||||
/*
|
||||
* 32 bits of Interrupt Set-Pending correspond to 32
|
||||
* 32 interrupts. Compute the bit offset of the
|
||||
* Interrupt and set that particular bit
|
||||
* Compute the register offset by dividing interrupt
|
||||
* number by 32 and mutiplying by 4
|
||||
*/
|
||||
writel_relaxed(1 << (retrigger_irq & 31),
|
||||
gic_dist_base + GIC_INT_SET_PENDING_BASE
|
||||
+ retrigger_irq / 32 * 4);
|
||||
nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4,
|
||||
(void *)&val);
|
||||
}
|
||||
|
||||
rtc_only_idle = 0;
|
||||
}
|
||||
|
||||
static int am33xx_pm_valid(suspend_state_t state)
|
||||
@ -219,51 +397,37 @@ static int am33xx_pm_alloc_sram(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int am33xx_push_sram_idle(void)
|
||||
static int am33xx_pm_rtc_setup(void)
|
||||
{
|
||||
struct am33xx_pm_ro_sram_data ro_sram_data;
|
||||
int ret;
|
||||
u32 table_addr, ro_data_addr;
|
||||
void *copy_addr;
|
||||
struct device_node *np;
|
||||
unsigned long val = 0;
|
||||
struct nvmem_device *nvmem;
|
||||
|
||||
ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data;
|
||||
ro_sram_data.amx3_pm_sram_data_phys =
|
||||
gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data);
|
||||
ro_sram_data.rtc_base_virt = pm_ops->get_rtc_base_addr();
|
||||
np = of_find_node_by_name(NULL, "rtc");
|
||||
|
||||
/* Save physical address to calculate resume offset during pm init */
|
||||
am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool,
|
||||
ocmcram_location);
|
||||
if (of_device_is_available(np)) {
|
||||
omap_rtc = rtc_class_open("rtc0");
|
||||
if (!omap_rtc) {
|
||||
pr_warn("PM: rtc0 not available");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
am33xx_do_wfi_sram = sram_exec_copy(sram_pool, (void *)ocmcram_location,
|
||||
pm_sram->do_wfi,
|
||||
*pm_sram->do_wfi_sz);
|
||||
if (!am33xx_do_wfi_sram) {
|
||||
dev_err(pm33xx_dev,
|
||||
"PM: %s: am33xx_do_wfi copy to sram failed\n",
|
||||
__func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
nvmem = devm_nvmem_device_get(&omap_rtc->dev,
|
||||
"omap_rtc_scratch0");
|
||||
if (nvmem) {
|
||||
nvmem_device_read(nvmem, RTC_SCRATCH_MAGIC_REG * 4,
|
||||
4, (void *)&rtc_magic_val);
|
||||
if ((rtc_magic_val & 0xffff) != RTC_REG_BOOT_MAGIC)
|
||||
pr_warn("PM: bootloader does not support rtc-only!\n");
|
||||
|
||||
table_addr =
|
||||
sram_suspend_address((unsigned long)pm_sram->emif_sram_table);
|
||||
ret = ti_emif_copy_pm_function_table(sram_pool, (void *)table_addr);
|
||||
if (ret) {
|
||||
dev_dbg(pm33xx_dev,
|
||||
"PM: %s: EMIF function copy failed\n", __func__);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ro_data_addr =
|
||||
sram_suspend_address((unsigned long)pm_sram->ro_sram_data);
|
||||
copy_addr = sram_exec_copy(sram_pool, (void *)ro_data_addr,
|
||||
&ro_sram_data,
|
||||
sizeof(ro_sram_data));
|
||||
if (!copy_addr) {
|
||||
dev_err(pm33xx_dev,
|
||||
"PM: %s: ro_sram_data copy to sram failed\n",
|
||||
__func__);
|
||||
return -ENODEV;
|
||||
nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4,
|
||||
4, (void *)&val);
|
||||
val = pm_sram->resume_address;
|
||||
nvmem_device_write(nvmem, RTC_SCRATCH_RESUME_REG * 4,
|
||||
4, (void *)&val);
|
||||
}
|
||||
} else {
|
||||
pr_warn("PM: no-rtc available, rtc-only mode disabled.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -284,34 +448,42 @@ static int am33xx_pm_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = am43xx_map_gic();
|
||||
if (ret) {
|
||||
pr_err("PM: Could not ioremap GIC base\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_sram = pm_ops->get_sram_addrs();
|
||||
if (!pm_sram) {
|
||||
dev_err(dev, "PM: Cannot get PM asm function addresses!!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
m3_ipc = wkup_m3_ipc_get();
|
||||
if (!m3_ipc) {
|
||||
pr_err("PM: Cannot get wkup_m3_ipc handle\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
pm33xx_dev = dev;
|
||||
|
||||
ret = am33xx_pm_alloc_sram();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = am33xx_push_sram_idle();
|
||||
ret = am33xx_pm_rtc_setup();
|
||||
if (ret)
|
||||
goto err_free_sram;
|
||||
|
||||
m3_ipc = wkup_m3_ipc_get();
|
||||
if (!m3_ipc) {
|
||||
dev_dbg(dev, "PM: Cannot get wkup_m3_ipc handle\n");
|
||||
ret = -EPROBE_DEFER;
|
||||
ret = am33xx_push_sram_idle();
|
||||
if (ret)
|
||||
goto err_free_sram;
|
||||
}
|
||||
|
||||
am33xx_pm_set_ipc_ops();
|
||||
|
||||
#ifdef CONFIG_SUSPEND
|
||||
suspend_set_ops(&am33xx_pm_ops);
|
||||
#endif /* CONFIG_SUSPEND */
|
||||
|
||||
/*
|
||||
* For a system suspend we must flush the caches, we want
|
||||
@ -323,6 +495,7 @@ static int am33xx_pm_probe(struct platform_device *pdev)
|
||||
suspend_wfi_flags |= WFI_FLAG_SELF_REFRESH;
|
||||
suspend_wfi_flags |= WFI_FLAG_SAVE_EMIF;
|
||||
suspend_wfi_flags |= WFI_FLAG_WAKE_M3;
|
||||
#endif /* CONFIG_SUSPEND */
|
||||
|
||||
ret = pm_ops->init();
|
||||
if (ret) {
|
||||
|
@ -23,6 +23,8 @@
|
||||
/* Flag stating if PM nodes mapped to the PM domain has been requested */
|
||||
#define ZYNQMP_PM_DOMAIN_REQUESTED BIT(0)
|
||||
|
||||
static const struct zynqmp_eemi_ops *eemi_ops;
|
||||
|
||||
/**
|
||||
* struct zynqmp_pm_domain - Wrapper around struct generic_pm_domain
|
||||
* @gpd: Generic power domain
|
||||
@ -71,9 +73,8 @@ static int zynqmp_gpd_power_on(struct generic_pm_domain *domain)
|
||||
{
|
||||
int ret;
|
||||
struct zynqmp_pm_domain *pd;
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->set_requirement)
|
||||
if (!eemi_ops->set_requirement)
|
||||
return -ENXIO;
|
||||
|
||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
||||
@ -107,9 +108,8 @@ static int zynqmp_gpd_power_off(struct generic_pm_domain *domain)
|
||||
struct zynqmp_pm_domain *pd;
|
||||
u32 capabilities = 0;
|
||||
bool may_wakeup;
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->set_requirement)
|
||||
if (!eemi_ops->set_requirement)
|
||||
return -ENXIO;
|
||||
|
||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
||||
@ -160,9 +160,8 @@ static int zynqmp_gpd_attach_dev(struct generic_pm_domain *domain,
|
||||
{
|
||||
int ret;
|
||||
struct zynqmp_pm_domain *pd;
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->request_node)
|
||||
if (!eemi_ops->request_node)
|
||||
return -ENXIO;
|
||||
|
||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
||||
@ -197,9 +196,8 @@ static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain,
|
||||
{
|
||||
int ret;
|
||||
struct zynqmp_pm_domain *pd;
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->release_node)
|
||||
if (!eemi_ops->release_node)
|
||||
return;
|
||||
|
||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
||||
@ -266,6 +264,10 @@ static int zynqmp_gpd_probe(struct platform_device *pdev)
|
||||
struct zynqmp_pm_domain *pd;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
if (IS_ERR(eemi_ops))
|
||||
return PTR_ERR(eemi_ops);
|
||||
|
||||
pd = devm_kcalloc(dev, ZYNQMP_NUM_DOMAINS, sizeof(*pd), GFP_KERNEL);
|
||||
if (!pd)
|
||||
return -ENOMEM;
|
||||
|
@ -31,6 +31,7 @@ static const char *const suspend_modes[] = {
|
||||
};
|
||||
|
||||
static enum pm_suspend_mode suspend_mode = PM_SUSPEND_MODE_STD;
|
||||
static const struct zynqmp_eemi_ops *eemi_ops;
|
||||
|
||||
enum pm_api_cb_id {
|
||||
PM_INIT_SUSPEND_CB = 30,
|
||||
@ -92,9 +93,8 @@ static ssize_t suspend_mode_store(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int md, ret = -EINVAL;
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->set_suspend_mode)
|
||||
if (!eemi_ops->set_suspend_mode)
|
||||
return ret;
|
||||
|
||||
for (md = PM_SUSPEND_MODE_FIRST; md < ARRAY_SIZE(suspend_modes); md++)
|
||||
@ -120,9 +120,11 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
|
||||
int ret, irq;
|
||||
u32 pm_api_version;
|
||||
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
if (IS_ERR(eemi_ops))
|
||||
return PTR_ERR(eemi_ops);
|
||||
|
||||
if (!eemi_ops || !eemi_ops->get_api_version || !eemi_ops->init_finalize)
|
||||
if (!eemi_ops->get_api_version || !eemi_ops->init_finalize)
|
||||
return -ENXIO;
|
||||
|
||||
eemi_ops->init_finalize();
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/firmware/xlnx-zynqmp.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
@ -138,6 +139,7 @@
|
||||
|
||||
#define SPI_AUTOSUSPEND_TIMEOUT 3000
|
||||
enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA};
|
||||
static const struct zynqmp_eemi_ops *eemi_ops;
|
||||
|
||||
/**
|
||||
* struct zynqmp_qspi - Defines qspi driver instance
|
||||
@ -1021,6 +1023,10 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
if (IS_ERR(eemi_ops))
|
||||
return PTR_ERR(eemi_ops);
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*xqspi));
|
||||
if (!master)
|
||||
return -ENOMEM;
|
||||
|
@ -419,9 +419,35 @@ static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn,
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct tee_shm_pool *optee_config_dyn_shm(void)
|
||||
{
|
||||
struct tee_shm_pool_mgr *priv_mgr;
|
||||
struct tee_shm_pool_mgr *dmabuf_mgr;
|
||||
void *rc;
|
||||
|
||||
rc = optee_shm_pool_alloc_pages();
|
||||
if (IS_ERR(rc))
|
||||
return rc;
|
||||
priv_mgr = rc;
|
||||
|
||||
rc = optee_shm_pool_alloc_pages();
|
||||
if (IS_ERR(rc)) {
|
||||
tee_shm_pool_mgr_destroy(priv_mgr);
|
||||
return rc;
|
||||
}
|
||||
dmabuf_mgr = rc;
|
||||
|
||||
rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
|
||||
if (IS_ERR(rc)) {
|
||||
tee_shm_pool_mgr_destroy(priv_mgr);
|
||||
tee_shm_pool_mgr_destroy(dmabuf_mgr);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct tee_shm_pool *
|
||||
optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm,
|
||||
u32 sec_caps)
|
||||
optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm)
|
||||
{
|
||||
union {
|
||||
struct arm_smccc_res smccc;
|
||||
@ -436,10 +462,11 @@ optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm,
|
||||
struct tee_shm_pool_mgr *priv_mgr;
|
||||
struct tee_shm_pool_mgr *dmabuf_mgr;
|
||||
void *rc;
|
||||
const int sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
|
||||
|
||||
invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
|
||||
if (res.result.status != OPTEE_SMC_RETURN_OK) {
|
||||
pr_info("shm service not available\n");
|
||||
pr_err("static shm service not available\n");
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
@ -465,28 +492,15 @@ optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm,
|
||||
}
|
||||
vaddr = (unsigned long)va;
|
||||
|
||||
/*
|
||||
* If OP-TEE can work with unregistered SHM, we will use own pool
|
||||
* for private shm
|
||||
*/
|
||||
if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) {
|
||||
rc = optee_shm_pool_alloc_pages();
|
||||
if (IS_ERR(rc))
|
||||
goto err_memunmap;
|
||||
priv_mgr = rc;
|
||||
} else {
|
||||
const size_t sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
|
||||
rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz,
|
||||
3 /* 8 bytes aligned */);
|
||||
if (IS_ERR(rc))
|
||||
goto err_memunmap;
|
||||
priv_mgr = rc;
|
||||
|
||||
rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz,
|
||||
3 /* 8 bytes aligned */);
|
||||
if (IS_ERR(rc))
|
||||
goto err_memunmap;
|
||||
priv_mgr = rc;
|
||||
|
||||
vaddr += sz;
|
||||
paddr += sz;
|
||||
size -= sz;
|
||||
}
|
||||
vaddr += sz;
|
||||
paddr += sz;
|
||||
size -= sz;
|
||||
|
||||
rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, size, PAGE_SHIFT);
|
||||
if (IS_ERR(rc))
|
||||
@ -552,7 +566,7 @@ static optee_invoke_fn *get_invoke_func(struct device_node *np)
|
||||
static struct optee *optee_probe(struct device_node *np)
|
||||
{
|
||||
optee_invoke_fn *invoke_fn;
|
||||
struct tee_shm_pool *pool;
|
||||
struct tee_shm_pool *pool = ERR_PTR(-EINVAL);
|
||||
struct optee *optee = NULL;
|
||||
void *memremaped_shm = NULL;
|
||||
struct tee_device *teedev;
|
||||
@ -581,13 +595,17 @@ static struct optee *optee_probe(struct device_node *np)
|
||||
}
|
||||
|
||||
/*
|
||||
* We have no other option for shared memory, if secure world
|
||||
* doesn't have any reserved memory we can use we can't continue.
|
||||
* Try to use dynamic shared memory if possible
|
||||
*/
|
||||
if (!(sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM))
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
|
||||
pool = optee_config_dyn_shm();
|
||||
|
||||
/*
|
||||
* If dynamic shared memory is not available or failed - try static one
|
||||
*/
|
||||
if (IS_ERR(pool) && (sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM))
|
||||
pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm);
|
||||
|
||||
pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm, sec_caps);
|
||||
if (IS_ERR(pool))
|
||||
return (void *)pool;
|
||||
|
||||
|
@ -15,4 +15,9 @@
|
||||
|
||||
#include <linux/firmware/imx/svc/misc.h>
|
||||
#include <linux/firmware/imx/svc/pm.h>
|
||||
|
||||
int imx_scu_enable_general_irq_channel(struct device *dev);
|
||||
int imx_scu_irq_register_notifier(struct notifier_block *nb);
|
||||
int imx_scu_irq_unregister_notifier(struct notifier_block *nb);
|
||||
int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable);
|
||||
#endif /* _SC_SCI_H */
|
||||
|
@ -48,6 +48,14 @@
|
||||
#define ZYNQMP_PM_CAPABILITY_WAKEUP 0x4U
|
||||
#define ZYNQMP_PM_CAPABILITY_POWER 0x8U
|
||||
|
||||
/*
|
||||
* Firmware FPGA Manager flags
|
||||
* XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration
|
||||
* XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration
|
||||
*/
|
||||
#define XILINX_ZYNQMP_PM_FPGA_FULL 0x0U
|
||||
#define XILINX_ZYNQMP_PM_FPGA_PARTIAL BIT(0)
|
||||
|
||||
enum pm_api_id {
|
||||
PM_GET_API_VERSION = 1,
|
||||
PM_REQUEST_NODE = 13,
|
||||
@ -56,6 +64,8 @@ enum pm_api_id {
|
||||
PM_RESET_ASSERT = 17,
|
||||
PM_RESET_GET_STATUS,
|
||||
PM_PM_INIT_FINALIZE = 21,
|
||||
PM_FPGA_LOAD,
|
||||
PM_FPGA_GET_STATUS,
|
||||
PM_GET_CHIPID = 24,
|
||||
PM_IOCTL = 34,
|
||||
PM_QUERY_DATA,
|
||||
@ -258,6 +268,8 @@ struct zynqmp_pm_query_data {
|
||||
struct zynqmp_eemi_ops {
|
||||
int (*get_api_version)(u32 *version);
|
||||
int (*get_chipid)(u32 *idcode, u32 *version);
|
||||
int (*fpga_load)(const u64 address, const u32 size, const u32 flags);
|
||||
int (*fpga_get_status)(u32 *value);
|
||||
int (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out);
|
||||
int (*clock_enable)(u32 clock_id);
|
||||
int (*clock_disable)(u32 clock_id);
|
||||
@ -293,7 +305,7 @@ const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void);
|
||||
#else
|
||||
static inline struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
|
||||
{
|
||||
return NULL;
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -51,6 +51,11 @@ struct am33xx_pm_platform_data {
|
||||
unsigned long args);
|
||||
struct am33xx_pm_sram_addr *(*get_sram_addrs)(void);
|
||||
void __iomem *(*get_rtc_base_addr)(void);
|
||||
void (*save_context)(void);
|
||||
void (*restore_context)(void);
|
||||
void (*prepare_rtc_suspend)(void);
|
||||
void (*prepare_rtc_resume)(void);
|
||||
int (*check_off_mode_enable)(void);
|
||||
};
|
||||
|
||||
struct am33xx_pm_sram_data {
|
||||
|
@ -2,6 +2,8 @@
|
||||
#ifndef _LINUX_RESET_H_
|
||||
#define _LINUX_RESET_H_
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct device;
|
||||
|
7
include/linux/rtc/rtc-omap.h
Normal file
7
include/linux/rtc/rtc-omap.h
Normal file
@ -0,0 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef _LINUX_RTCOMAP_H_
|
||||
#define _LINUX_RTCOMAP_H_
|
||||
|
||||
int omap_rtc_power_off_program(struct device *dev);
|
||||
#endif /* _LINUX_RTCOMAP_H_ */
|
@ -55,6 +55,7 @@ struct ti_emif_pm_data {
|
||||
struct ti_emif_pm_functions {
|
||||
u32 save_context;
|
||||
u32 restore_context;
|
||||
u32 run_hw_leveling;
|
||||
u32 enter_sr;
|
||||
u32 exit_sr;
|
||||
u32 abort_sr;
|
||||
@ -126,6 +127,8 @@ static inline void ti_emif_asm_offsets(void)
|
||||
offsetof(struct ti_emif_pm_functions, save_context));
|
||||
DEFINE(EMIF_PM_RESTORE_CONTEXT_OFFSET,
|
||||
offsetof(struct ti_emif_pm_functions, restore_context));
|
||||
DEFINE(EMIF_PM_RUN_HW_LEVELING,
|
||||
offsetof(struct ti_emif_pm_functions, run_hw_leveling));
|
||||
DEFINE(EMIF_PM_ENTER_SR_OFFSET,
|
||||
offsetof(struct ti_emif_pm_functions, enter_sr));
|
||||
DEFINE(EMIF_PM_EXIT_SR_OFFSET,
|
||||
|
Loading…
Reference in New Issue
Block a user