Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver updates from Arnd Bergmann: "A number of new drivers get added this time, along with many low-priority bugfixes. The most interesting changes by subsystem are: bus drivers: - Updates to the Broadcom bus interface driver to support newer SoC types - The TI OMAP sysc driver now supports updated DT bindings memory controllers: - A new driver for Tegra186 gets added - A new driver for the ti-emif sram, to allow relocating suspend/resume handlers there SoC specific: - A new driver for Qualcomm QMI, the interface to the modem on MSM SoCs - A new driver for power domains on the actions S700 SoC - A driver for the Xilinx Zynq VCU logicoreIP reset controllers: - A new driver for Amlogic Meson-AGX - various bug fixes tee subsystem: - A new user interface got added to enable asynchronous communication with the TEE supplicant. - A new method of using user space memory for communication with the TEE is added" * tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (84 commits) of: platform: fix OF node refcount leak soc: fsl: guts: Add a NULL check for devm_kasprintf() bus: ti-sysc: Fix smartreflex sysc mask psci: add CPU_IDLE dependency soc: xilinx: Fix Kconfig alignment soc: xilinx: xlnx_vcu: Use bitwise & rather than logical && on clkoutdiv soc: xilinx: xlnx_vcu: Depends on HAS_IOMEM for xlnx_vcu soc: bcm: brcmstb: Be multi-platform compatible soc: brcmstb: biuctrl: exit without warning on non brcmstb platforms Revert "soc: brcmstb: Only register SoC device on STB platforms" bus: omap: add MODULE_LICENSE tags soc: brcmstb: Only register SoC device on STB platforms tee: shm: Potential NULL dereference calling tee_shm_register() soc: xilinx: xlnx_vcu: Add Xilinx ZYNQMP VCU logicoreIP init driver dt-bindings: soc: xilinx: Add DT bindings to xlnx_vcu driver soc: xilinx: Create folder structure for soc specific drivers of: platform: populate /firmware/ node from of_platform_default_populate_init() soc: samsung: Add SPDX license identifiers soc: qcom: smp2p: Use common error handling code in qcom_smp2p_probe() tee: shm: don't put_page on null shm->pages ...
This commit is contained in:
@@ -84,6 +84,16 @@ config OMAP_GPMC_DEBUG
|
||||
bootloader or else the GPMC timings won't be identical with the
|
||||
bootloader timings.
|
||||
|
||||
config TI_EMIF_SRAM
|
||||
tristate "Texas Instruments EMIF SRAM driver"
|
||||
depends on (SOC_AM33XX || SOC_AM43XX) && SRAM
|
||||
help
|
||||
This driver is for the EMIF module available on Texas Instruments
|
||||
AM33XX and AM43XX SoCs and is required for PM. Certain parts of
|
||||
the EMIF PM code must run from on-chip SRAM late in the suspend
|
||||
sequence so this driver provides several relocatable PM functions
|
||||
for the SoC PM code to use.
|
||||
|
||||
config MVEBU_DEVBUS
|
||||
bool "Marvell EBU Device Bus Controller"
|
||||
default y
|
||||
|
@@ -23,3 +23,11 @@ obj-$(CONFIG_DA8XX_DDRCTL) += da8xx-ddrctl.o
|
||||
|
||||
obj-$(CONFIG_SAMSUNG_MC) += samsung/
|
||||
obj-$(CONFIG_TEGRA_MC) += tegra/
|
||||
obj-$(CONFIG_TI_EMIF_SRAM) += ti-emif-sram.o
|
||||
ti-emif-sram-objs := ti-emif-pm.o ti-emif-sram-pm.o
|
||||
|
||||
AFLAGS_ti-emif-sram-pm.o :=-Wa,-march=armv7-a
|
||||
|
||||
include drivers/memory/Makefile.asm-offsets
|
||||
|
||||
drivers/memory/ti-emif-sram-pm.o: include/generated/ti-emif-asm-offsets.h
|
||||
|
5
drivers/memory/Makefile.asm-offsets
Normal file
5
drivers/memory/Makefile.asm-offsets
Normal file
@@ -0,0 +1,5 @@
|
||||
drivers/memory/emif-asm-offsets.s: drivers/memory/emif-asm-offsets.c
|
||||
$(call if_changed_dep,cc_s_c)
|
||||
|
||||
include/generated/ti-emif-asm-offsets.h: drivers/memory/emif-asm-offsets.s FORCE
|
||||
$(call filechk,offsets,__TI_EMIF_ASM_OFFSETS_H__)
|
92
drivers/memory/emif-asm-offsets.c
Normal file
92
drivers/memory/emif-asm-offsets.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* TI AM33XX EMIF PM Assembly Offsets
|
||||
*
|
||||
* Copyright (C) 2016-2017 Texas Instruments Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#include <linux/ti-emif-sram.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
DEFINE(EMIF_SDCFG_VAL_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_sdcfg_val));
|
||||
DEFINE(EMIF_TIMING1_VAL_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_timing1_val));
|
||||
DEFINE(EMIF_TIMING2_VAL_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_timing2_val));
|
||||
DEFINE(EMIF_TIMING3_VAL_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_timing3_val));
|
||||
DEFINE(EMIF_REF_CTRL_VAL_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_ref_ctrl_val));
|
||||
DEFINE(EMIF_ZQCFG_VAL_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_zqcfg_val));
|
||||
DEFINE(EMIF_PMCR_VAL_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_pmcr_val));
|
||||
DEFINE(EMIF_PMCR_SHDW_VAL_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_pmcr_shdw_val));
|
||||
DEFINE(EMIF_RD_WR_LEVEL_RAMP_CTRL_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_rd_wr_level_ramp_ctrl));
|
||||
DEFINE(EMIF_RD_WR_EXEC_THRESH_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_rd_wr_exec_thresh));
|
||||
DEFINE(EMIF_COS_CONFIG_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_cos_config));
|
||||
DEFINE(EMIF_PRIORITY_TO_COS_MAPPING_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_priority_to_cos_mapping));
|
||||
DEFINE(EMIF_CONNECT_ID_SERV_1_MAP_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_connect_id_serv_1_map));
|
||||
DEFINE(EMIF_CONNECT_ID_SERV_2_MAP_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_connect_id_serv_2_map));
|
||||
DEFINE(EMIF_OCP_CONFIG_VAL_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_ocp_config_val));
|
||||
DEFINE(EMIF_LPDDR2_NVM_TIM_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_lpddr2_nvm_tim));
|
||||
DEFINE(EMIF_LPDDR2_NVM_TIM_SHDW_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_lpddr2_nvm_tim_shdw));
|
||||
DEFINE(EMIF_DLL_CALIB_CTRL_VAL_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_dll_calib_ctrl_val));
|
||||
DEFINE(EMIF_DLL_CALIB_CTRL_VAL_SHDW_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_dll_calib_ctrl_val_shdw));
|
||||
DEFINE(EMIF_DDR_PHY_CTLR_1_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_ddr_phy_ctlr_1));
|
||||
DEFINE(EMIF_EXT_PHY_CTRL_VALS_OFFSET,
|
||||
offsetof(struct emif_regs_amx3, emif_ext_phy_ctrl_vals));
|
||||
DEFINE(EMIF_REGS_AMX3_SIZE, sizeof(struct emif_regs_amx3));
|
||||
|
||||
BLANK();
|
||||
|
||||
DEFINE(EMIF_PM_BASE_ADDR_VIRT_OFFSET,
|
||||
offsetof(struct ti_emif_pm_data, ti_emif_base_addr_virt));
|
||||
DEFINE(EMIF_PM_BASE_ADDR_PHYS_OFFSET,
|
||||
offsetof(struct ti_emif_pm_data, ti_emif_base_addr_phys));
|
||||
DEFINE(EMIF_PM_CONFIG_OFFSET,
|
||||
offsetof(struct ti_emif_pm_data, ti_emif_sram_config));
|
||||
DEFINE(EMIF_PM_REGS_VIRT_OFFSET,
|
||||
offsetof(struct ti_emif_pm_data, regs_virt));
|
||||
DEFINE(EMIF_PM_REGS_PHYS_OFFSET,
|
||||
offsetof(struct ti_emif_pm_data, regs_phys));
|
||||
DEFINE(EMIF_PM_DATA_SIZE, sizeof(struct ti_emif_pm_data));
|
||||
|
||||
BLANK();
|
||||
|
||||
DEFINE(EMIF_PM_SAVE_CONTEXT_OFFSET,
|
||||
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_ENTER_SR_OFFSET,
|
||||
offsetof(struct ti_emif_pm_functions, enter_sr));
|
||||
DEFINE(EMIF_PM_EXIT_SR_OFFSET,
|
||||
offsetof(struct ti_emif_pm_functions, exit_sr));
|
||||
DEFINE(EMIF_PM_ABORT_SR_OFFSET,
|
||||
offsetof(struct ti_emif_pm_functions, abort_sr));
|
||||
DEFINE(EMIF_PM_FUNCTIONS_SIZE, sizeof(struct ti_emif_pm_functions));
|
||||
|
||||
return 0;
|
||||
}
|
@@ -555,6 +555,9 @@
|
||||
#define READ_LATENCY_SHDW_SHIFT 0
|
||||
#define READ_LATENCY_SHDW_MASK (0x1f << 0)
|
||||
|
||||
#define EMIF_SRAM_AM33_REG_LAYOUT 0x00000000
|
||||
#define EMIF_SRAM_AM43_REG_LAYOUT 0x00000001
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
/*
|
||||
* Structure containing shadow of important registers in EMIF
|
||||
@@ -585,5 +588,19 @@ struct emif_regs {
|
||||
u32 ext_phy_ctrl_3_shdw;
|
||||
u32 ext_phy_ctrl_4_shdw;
|
||||
};
|
||||
|
||||
struct ti_emif_pm_functions;
|
||||
|
||||
extern unsigned int ti_emif_sram;
|
||||
extern unsigned int ti_emif_sram_sz;
|
||||
extern struct ti_emif_pm_data ti_emif_pm_sram_data;
|
||||
extern struct emif_regs_amx3 ti_emif_regs_amx3;
|
||||
|
||||
void ti_emif_save_context(void);
|
||||
void ti_emif_restore_context(void);
|
||||
void ti_emif_enter_sr(void);
|
||||
void ti_emif_exit_sr(void);
|
||||
void ti_emif_abort_sr(void);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __EMIF_H */
|
||||
|
@@ -10,3 +10,4 @@ tegra-mc-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
|
||||
obj-$(CONFIG_TEGRA_MC) += tegra-mc.o
|
||||
|
||||
obj-$(CONFIG_TEGRA124_EMC) += tegra124-emc.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o
|
||||
|
@@ -912,11 +912,26 @@ static const struct tegra_smmu_swgroup tegra114_swgroups[] = {
|
||||
{ .name = "tsec", .swgroup = TEGRA_SWGROUP_TSEC, .reg = 0x294 },
|
||||
};
|
||||
|
||||
static const unsigned int tegra114_group_display[] = {
|
||||
TEGRA_SWGROUP_DC,
|
||||
TEGRA_SWGROUP_DCB,
|
||||
};
|
||||
|
||||
static const struct tegra_smmu_group_soc tegra114_groups[] = {
|
||||
{
|
||||
.name = "display",
|
||||
.swgroups = tegra114_group_display,
|
||||
.num_swgroups = ARRAY_SIZE(tegra114_group_display),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct tegra_smmu_soc tegra114_smmu_soc = {
|
||||
.clients = tegra114_mc_clients,
|
||||
.num_clients = ARRAY_SIZE(tegra114_mc_clients),
|
||||
.swgroups = tegra114_swgroups,
|
||||
.num_swgroups = ARRAY_SIZE(tegra114_swgroups),
|
||||
.groups = tegra114_groups,
|
||||
.num_groups = ARRAY_SIZE(tegra114_groups),
|
||||
.supports_round_robin_arbitration = false,
|
||||
.supports_request_limit = false,
|
||||
.num_tlb_lines = 32,
|
||||
|
@@ -999,12 +999,27 @@ static const struct tegra_smmu_swgroup tegra124_swgroups[] = {
|
||||
{ .name = "vi", .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280 },
|
||||
};
|
||||
|
||||
static const unsigned int tegra124_group_display[] = {
|
||||
TEGRA_SWGROUP_DC,
|
||||
TEGRA_SWGROUP_DCB,
|
||||
};
|
||||
|
||||
static const struct tegra_smmu_group_soc tegra124_groups[] = {
|
||||
{
|
||||
.name = "display",
|
||||
.swgroups = tegra124_group_display,
|
||||
.num_swgroups = ARRAY_SIZE(tegra124_group_display),
|
||||
},
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_124_SOC
|
||||
static const struct tegra_smmu_soc tegra124_smmu_soc = {
|
||||
.clients = tegra124_mc_clients,
|
||||
.num_clients = ARRAY_SIZE(tegra124_mc_clients),
|
||||
.swgroups = tegra124_swgroups,
|
||||
.num_swgroups = ARRAY_SIZE(tegra124_swgroups),
|
||||
.groups = tegra124_groups,
|
||||
.num_groups = ARRAY_SIZE(tegra124_groups),
|
||||
.supports_round_robin_arbitration = true,
|
||||
.supports_request_limit = true,
|
||||
.num_tlb_lines = 32,
|
||||
@@ -1029,6 +1044,8 @@ static const struct tegra_smmu_soc tegra132_smmu_soc = {
|
||||
.num_clients = ARRAY_SIZE(tegra124_mc_clients),
|
||||
.swgroups = tegra124_swgroups,
|
||||
.num_swgroups = ARRAY_SIZE(tegra124_swgroups),
|
||||
.groups = tegra124_groups,
|
||||
.num_groups = ARRAY_SIZE(tegra124_groups),
|
||||
.supports_round_robin_arbitration = true,
|
||||
.supports_request_limit = true,
|
||||
.num_tlb_lines = 32,
|
||||
|
600
drivers/memory/tegra/tegra186.c
Normal file
600
drivers/memory/tegra/tegra186.c
Normal file
@@ -0,0 +1,600 @@
|
||||
/*
|
||||
* Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <dt-bindings/memory/tegra186-mc.h>
|
||||
|
||||
struct tegra_mc {
|
||||
struct device *dev;
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
struct tegra_mc_client {
|
||||
const char *name;
|
||||
unsigned int sid;
|
||||
struct {
|
||||
unsigned int override;
|
||||
unsigned int security;
|
||||
} regs;
|
||||
};
|
||||
|
||||
static const struct tegra_mc_client tegra186_mc_clients[] = {
|
||||
{
|
||||
.name = "ptcr",
|
||||
.sid = TEGRA186_SID_PASSTHROUGH,
|
||||
.regs = {
|
||||
.override = 0x000,
|
||||
.security = 0x004,
|
||||
},
|
||||
}, {
|
||||
.name = "afir",
|
||||
.sid = TEGRA186_SID_AFI,
|
||||
.regs = {
|
||||
.override = 0x070,
|
||||
.security = 0x074,
|
||||
},
|
||||
}, {
|
||||
.name = "hdar",
|
||||
.sid = TEGRA186_SID_HDA,
|
||||
.regs = {
|
||||
.override = 0x0a8,
|
||||
.security = 0x0ac,
|
||||
},
|
||||
}, {
|
||||
.name = "host1xdmar",
|
||||
.sid = TEGRA186_SID_HOST1X,
|
||||
.regs = {
|
||||
.override = 0x0b0,
|
||||
.security = 0x0b4,
|
||||
},
|
||||
}, {
|
||||
.name = "nvencsrd",
|
||||
.sid = TEGRA186_SID_NVENC,
|
||||
.regs = {
|
||||
.override = 0x0e0,
|
||||
.security = 0x0e4,
|
||||
},
|
||||
}, {
|
||||
.name = "satar",
|
||||
.sid = TEGRA186_SID_SATA,
|
||||
.regs = {
|
||||
.override = 0x0f8,
|
||||
.security = 0x0fc,
|
||||
},
|
||||
}, {
|
||||
.name = "mpcorer",
|
||||
.sid = TEGRA186_SID_PASSTHROUGH,
|
||||
.regs = {
|
||||
.override = 0x138,
|
||||
.security = 0x13c,
|
||||
},
|
||||
}, {
|
||||
.name = "nvencswr",
|
||||
.sid = TEGRA186_SID_NVENC,
|
||||
.regs = {
|
||||
.override = 0x158,
|
||||
.security = 0x15c,
|
||||
},
|
||||
}, {
|
||||
.name = "afiw",
|
||||
.sid = TEGRA186_SID_AFI,
|
||||
.regs = {
|
||||
.override = 0x188,
|
||||
.security = 0x18c,
|
||||
},
|
||||
}, {
|
||||
.name = "hdaw",
|
||||
.sid = TEGRA186_SID_HDA,
|
||||
.regs = {
|
||||
.override = 0x1a8,
|
||||
.security = 0x1ac,
|
||||
},
|
||||
}, {
|
||||
.name = "mpcorew",
|
||||
.sid = TEGRA186_SID_PASSTHROUGH,
|
||||
.regs = {
|
||||
.override = 0x1c8,
|
||||
.security = 0x1cc,
|
||||
},
|
||||
}, {
|
||||
.name = "sataw",
|
||||
.sid = TEGRA186_SID_SATA,
|
||||
.regs = {
|
||||
.override = 0x1e8,
|
||||
.security = 0x1ec,
|
||||
},
|
||||
}, {
|
||||
.name = "ispra",
|
||||
.sid = TEGRA186_SID_ISP,
|
||||
.regs = {
|
||||
.override = 0x220,
|
||||
.security = 0x224,
|
||||
},
|
||||
}, {
|
||||
.name = "ispwa",
|
||||
.sid = TEGRA186_SID_ISP,
|
||||
.regs = {
|
||||
.override = 0x230,
|
||||
.security = 0x234,
|
||||
},
|
||||
}, {
|
||||
.name = "ispwb",
|
||||
.sid = TEGRA186_SID_ISP,
|
||||
.regs = {
|
||||
.override = 0x238,
|
||||
.security = 0x23c,
|
||||
},
|
||||
}, {
|
||||
.name = "xusb_hostr",
|
||||
.sid = TEGRA186_SID_XUSB_HOST,
|
||||
.regs = {
|
||||
.override = 0x250,
|
||||
.security = 0x254,
|
||||
},
|
||||
}, {
|
||||
.name = "xusb_hostw",
|
||||
.sid = TEGRA186_SID_XUSB_HOST,
|
||||
.regs = {
|
||||
.override = 0x258,
|
||||
.security = 0x25c,
|
||||
},
|
||||
}, {
|
||||
.name = "xusb_devr",
|
||||
.sid = TEGRA186_SID_XUSB_DEV,
|
||||
.regs = {
|
||||
.override = 0x260,
|
||||
.security = 0x264,
|
||||
},
|
||||
}, {
|
||||
.name = "xusb_devw",
|
||||
.sid = TEGRA186_SID_XUSB_DEV,
|
||||
.regs = {
|
||||
.override = 0x268,
|
||||
.security = 0x26c,
|
||||
},
|
||||
}, {
|
||||
.name = "tsecsrd",
|
||||
.sid = TEGRA186_SID_TSEC,
|
||||
.regs = {
|
||||
.override = 0x2a0,
|
||||
.security = 0x2a4,
|
||||
},
|
||||
}, {
|
||||
.name = "tsecswr",
|
||||
.sid = TEGRA186_SID_TSEC,
|
||||
.regs = {
|
||||
.override = 0x2a8,
|
||||
.security = 0x2ac,
|
||||
},
|
||||
}, {
|
||||
.name = "gpusrd",
|
||||
.sid = TEGRA186_SID_GPU,
|
||||
.regs = {
|
||||
.override = 0x2c0,
|
||||
.security = 0x2c4,
|
||||
},
|
||||
}, {
|
||||
.name = "gpuswr",
|
||||
.sid = TEGRA186_SID_GPU,
|
||||
.regs = {
|
||||
.override = 0x2c8,
|
||||
.security = 0x2cc,
|
||||
},
|
||||
}, {
|
||||
.name = "sdmmcra",
|
||||
.sid = TEGRA186_SID_SDMMC1,
|
||||
.regs = {
|
||||
.override = 0x300,
|
||||
.security = 0x304,
|
||||
},
|
||||
}, {
|
||||
.name = "sdmmcraa",
|
||||
.sid = TEGRA186_SID_SDMMC2,
|
||||
.regs = {
|
||||
.override = 0x308,
|
||||
.security = 0x30c,
|
||||
},
|
||||
}, {
|
||||
.name = "sdmmcr",
|
||||
.sid = TEGRA186_SID_SDMMC3,
|
||||
.regs = {
|
||||
.override = 0x310,
|
||||
.security = 0x314,
|
||||
},
|
||||
}, {
|
||||
.name = "sdmmcrab",
|
||||
.sid = TEGRA186_SID_SDMMC4,
|
||||
.regs = {
|
||||
.override = 0x318,
|
||||
.security = 0x31c,
|
||||
},
|
||||
}, {
|
||||
.name = "sdmmcwa",
|
||||
.sid = TEGRA186_SID_SDMMC1,
|
||||
.regs = {
|
||||
.override = 0x320,
|
||||
.security = 0x324,
|
||||
},
|
||||
}, {
|
||||
.name = "sdmmcwaa",
|
||||
.sid = TEGRA186_SID_SDMMC2,
|
||||
.regs = {
|
||||
.override = 0x328,
|
||||
.security = 0x32c,
|
||||
},
|
||||
}, {
|
||||
.name = "sdmmcw",
|
||||
.sid = TEGRA186_SID_SDMMC3,
|
||||
.regs = {
|
||||
.override = 0x330,
|
||||
.security = 0x334,
|
||||
},
|
||||
}, {
|
||||
.name = "sdmmcwab",
|
||||
.sid = TEGRA186_SID_SDMMC4,
|
||||
.regs = {
|
||||
.override = 0x338,
|
||||
.security = 0x33c,
|
||||
},
|
||||
}, {
|
||||
.name = "vicsrd",
|
||||
.sid = TEGRA186_SID_VIC,
|
||||
.regs = {
|
||||
.override = 0x360,
|
||||
.security = 0x364,
|
||||
},
|
||||
}, {
|
||||
.name = "vicswr",
|
||||
.sid = TEGRA186_SID_VIC,
|
||||
.regs = {
|
||||
.override = 0x368,
|
||||
.security = 0x36c,
|
||||
},
|
||||
}, {
|
||||
.name = "viw",
|
||||
.sid = TEGRA186_SID_VI,
|
||||
.regs = {
|
||||
.override = 0x390,
|
||||
.security = 0x394,
|
||||
},
|
||||
}, {
|
||||
.name = "nvdecsrd",
|
||||
.sid = TEGRA186_SID_NVDEC,
|
||||
.regs = {
|
||||
.override = 0x3c0,
|
||||
.security = 0x3c4,
|
||||
},
|
||||
}, {
|
||||
.name = "nvdecswr",
|
||||
.sid = TEGRA186_SID_NVDEC,
|
||||
.regs = {
|
||||
.override = 0x3c8,
|
||||
.security = 0x3cc,
|
||||
},
|
||||
}, {
|
||||
.name = "aper",
|
||||
.sid = TEGRA186_SID_APE,
|
||||
.regs = {
|
||||
.override = 0x3d0,
|
||||
.security = 0x3d4,
|
||||
},
|
||||
}, {
|
||||
.name = "apew",
|
||||
.sid = TEGRA186_SID_APE,
|
||||
.regs = {
|
||||
.override = 0x3d8,
|
||||
.security = 0x3dc,
|
||||
},
|
||||
}, {
|
||||
.name = "nvjpgsrd",
|
||||
.sid = TEGRA186_SID_NVJPG,
|
||||
.regs = {
|
||||
.override = 0x3f0,
|
||||
.security = 0x3f4,
|
||||
},
|
||||
}, {
|
||||
.name = "nvjpgswr",
|
||||
.sid = TEGRA186_SID_NVJPG,
|
||||
.regs = {
|
||||
.override = 0x3f8,
|
||||
.security = 0x3fc,
|
||||
},
|
||||
}, {
|
||||
.name = "sesrd",
|
||||
.sid = TEGRA186_SID_SE,
|
||||
.regs = {
|
||||
.override = 0x400,
|
||||
.security = 0x404,
|
||||
},
|
||||
}, {
|
||||
.name = "seswr",
|
||||
.sid = TEGRA186_SID_SE,
|
||||
.regs = {
|
||||
.override = 0x408,
|
||||
.security = 0x40c,
|
||||
},
|
||||
}, {
|
||||
.name = "etrr",
|
||||
.sid = TEGRA186_SID_ETR,
|
||||
.regs = {
|
||||
.override = 0x420,
|
||||
.security = 0x424,
|
||||
},
|
||||
}, {
|
||||
.name = "etrw",
|
||||
.sid = TEGRA186_SID_ETR,
|
||||
.regs = {
|
||||
.override = 0x428,
|
||||
.security = 0x42c,
|
||||
},
|
||||
}, {
|
||||
.name = "tsecsrdb",
|
||||
.sid = TEGRA186_SID_TSECB,
|
||||
.regs = {
|
||||
.override = 0x430,
|
||||
.security = 0x434,
|
||||
},
|
||||
}, {
|
||||
.name = "tsecswrb",
|
||||
.sid = TEGRA186_SID_TSECB,
|
||||
.regs = {
|
||||
.override = 0x438,
|
||||
.security = 0x43c,
|
||||
},
|
||||
}, {
|
||||
.name = "gpusrd2",
|
||||
.sid = TEGRA186_SID_GPU,
|
||||
.regs = {
|
||||
.override = 0x440,
|
||||
.security = 0x444,
|
||||
},
|
||||
}, {
|
||||
.name = "gpuswr2",
|
||||
.sid = TEGRA186_SID_GPU,
|
||||
.regs = {
|
||||
.override = 0x448,
|
||||
.security = 0x44c,
|
||||
},
|
||||
}, {
|
||||
.name = "axisr",
|
||||
.sid = TEGRA186_SID_GPCDMA_0,
|
||||
.regs = {
|
||||
.override = 0x460,
|
||||
.security = 0x464,
|
||||
},
|
||||
}, {
|
||||
.name = "axisw",
|
||||
.sid = TEGRA186_SID_GPCDMA_0,
|
||||
.regs = {
|
||||
.override = 0x468,
|
||||
.security = 0x46c,
|
||||
},
|
||||
}, {
|
||||
.name = "eqosr",
|
||||
.sid = TEGRA186_SID_EQOS,
|
||||
.regs = {
|
||||
.override = 0x470,
|
||||
.security = 0x474,
|
||||
},
|
||||
}, {
|
||||
.name = "eqosw",
|
||||
.sid = TEGRA186_SID_EQOS,
|
||||
.regs = {
|
||||
.override = 0x478,
|
||||
.security = 0x47c,
|
||||
},
|
||||
}, {
|
||||
.name = "ufshcr",
|
||||
.sid = TEGRA186_SID_UFSHC,
|
||||
.regs = {
|
||||
.override = 0x480,
|
||||
.security = 0x484,
|
||||
},
|
||||
}, {
|
||||
.name = "ufshcw",
|
||||
.sid = TEGRA186_SID_UFSHC,
|
||||
.regs = {
|
||||
.override = 0x488,
|
||||
.security = 0x48c,
|
||||
},
|
||||
}, {
|
||||
.name = "nvdisplayr",
|
||||
.sid = TEGRA186_SID_NVDISPLAY,
|
||||
.regs = {
|
||||
.override = 0x490,
|
||||
.security = 0x494,
|
||||
},
|
||||
}, {
|
||||
.name = "bpmpr",
|
||||
.sid = TEGRA186_SID_BPMP,
|
||||
.regs = {
|
||||
.override = 0x498,
|
||||
.security = 0x49c,
|
||||
},
|
||||
}, {
|
||||
.name = "bpmpw",
|
||||
.sid = TEGRA186_SID_BPMP,
|
||||
.regs = {
|
||||
.override = 0x4a0,
|
||||
.security = 0x4a4,
|
||||
},
|
||||
}, {
|
||||
.name = "bpmpdmar",
|
||||
.sid = TEGRA186_SID_BPMP,
|
||||
.regs = {
|
||||
.override = 0x4a8,
|
||||
.security = 0x4ac,
|
||||
},
|
||||
}, {
|
||||
.name = "bpmpdmaw",
|
||||
.sid = TEGRA186_SID_BPMP,
|
||||
.regs = {
|
||||
.override = 0x4b0,
|
||||
.security = 0x4b4,
|
||||
},
|
||||
}, {
|
||||
.name = "aonr",
|
||||
.sid = TEGRA186_SID_AON,
|
||||
.regs = {
|
||||
.override = 0x4b8,
|
||||
.security = 0x4bc,
|
||||
},
|
||||
}, {
|
||||
.name = "aonw",
|
||||
.sid = TEGRA186_SID_AON,
|
||||
.regs = {
|
||||
.override = 0x4c0,
|
||||
.security = 0x4c4,
|
||||
},
|
||||
}, {
|
||||
.name = "aondmar",
|
||||
.sid = TEGRA186_SID_AON,
|
||||
.regs = {
|
||||
.override = 0x4c8,
|
||||
.security = 0x4cc,
|
||||
},
|
||||
}, {
|
||||
.name = "aondmaw",
|
||||
.sid = TEGRA186_SID_AON,
|
||||
.regs = {
|
||||
.override = 0x4d0,
|
||||
.security = 0x4d4,
|
||||
},
|
||||
}, {
|
||||
.name = "scer",
|
||||
.sid = TEGRA186_SID_SCE,
|
||||
.regs = {
|
||||
.override = 0x4d8,
|
||||
.security = 0x4dc,
|
||||
},
|
||||
}, {
|
||||
.name = "scew",
|
||||
.sid = TEGRA186_SID_SCE,
|
||||
.regs = {
|
||||
.override = 0x4e0,
|
||||
.security = 0x4e4,
|
||||
},
|
||||
}, {
|
||||
.name = "scedmar",
|
||||
.sid = TEGRA186_SID_SCE,
|
||||
.regs = {
|
||||
.override = 0x4e8,
|
||||
.security = 0x4ec,
|
||||
},
|
||||
}, {
|
||||
.name = "scedmaw",
|
||||
.sid = TEGRA186_SID_SCE,
|
||||
.regs = {
|
||||
.override = 0x4f0,
|
||||
.security = 0x4f4,
|
||||
},
|
||||
}, {
|
||||
.name = "apedmar",
|
||||
.sid = TEGRA186_SID_APE,
|
||||
.regs = {
|
||||
.override = 0x4f8,
|
||||
.security = 0x4fc,
|
||||
},
|
||||
}, {
|
||||
.name = "apedmaw",
|
||||
.sid = TEGRA186_SID_APE,
|
||||
.regs = {
|
||||
.override = 0x500,
|
||||
.security = 0x504,
|
||||
},
|
||||
}, {
|
||||
.name = "nvdisplayr1",
|
||||
.sid = TEGRA186_SID_NVDISPLAY,
|
||||
.regs = {
|
||||
.override = 0x508,
|
||||
.security = 0x50c,
|
||||
},
|
||||
}, {
|
||||
.name = "vicsrd1",
|
||||
.sid = TEGRA186_SID_VIC,
|
||||
.regs = {
|
||||
.override = 0x510,
|
||||
.security = 0x514,
|
||||
},
|
||||
}, {
|
||||
.name = "nvdecsrd1",
|
||||
.sid = TEGRA186_SID_NVDEC,
|
||||
.regs = {
|
||||
.override = 0x518,
|
||||
.security = 0x51c,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static int tegra186_mc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct tegra_mc *mc;
|
||||
unsigned int i;
|
||||
int err = 0;
|
||||
|
||||
mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
|
||||
if (!mc)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
mc->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(mc->regs))
|
||||
return PTR_ERR(mc->regs);
|
||||
|
||||
mc->dev = &pdev->dev;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tegra186_mc_clients); i++) {
|
||||
const struct tegra_mc_client *client = &tegra186_mc_clients[i];
|
||||
u32 override, security;
|
||||
|
||||
override = readl(mc->regs + client->regs.override);
|
||||
security = readl(mc->regs + client->regs.security);
|
||||
|
||||
dev_dbg(&pdev->dev, "client %s: override: %x security: %x\n",
|
||||
client->name, override, security);
|
||||
|
||||
dev_dbg(&pdev->dev, "setting SID %u for %s\n", client->sid,
|
||||
client->name);
|
||||
writel(client->sid, mc->regs + client->regs.override);
|
||||
|
||||
override = readl(mc->regs + client->regs.override);
|
||||
security = readl(mc->regs + client->regs.security);
|
||||
|
||||
dev_dbg(&pdev->dev, "client %s: override: %x security: %x\n",
|
||||
client->name, override, security);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, mc);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct of_device_id tegra186_mc_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra186-mc", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra186_mc_of_match);
|
||||
|
||||
static struct platform_driver tegra186_mc_driver = {
|
||||
.driver = {
|
||||
.name = "tegra186-mc",
|
||||
.of_match_table = tegra186_mc_of_match,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.prevent_deferred_probe = true,
|
||||
.probe = tegra186_mc_probe,
|
||||
};
|
||||
module_platform_driver(tegra186_mc_driver);
|
||||
|
||||
MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
|
||||
MODULE_DESCRIPTION("NVIDIA Tegra186 Memory Controller driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@@ -1059,11 +1059,26 @@ static const struct tegra_smmu_swgroup tegra210_swgroups[] = {
|
||||
{ .name = "tsecb", .swgroup = TEGRA_SWGROUP_TSECB, .reg = 0xad4 },
|
||||
};
|
||||
|
||||
static const unsigned int tegra210_group_display[] = {
|
||||
TEGRA_SWGROUP_DC,
|
||||
TEGRA_SWGROUP_DCB,
|
||||
};
|
||||
|
||||
static const struct tegra_smmu_group_soc tegra210_groups[] = {
|
||||
{
|
||||
.name = "display",
|
||||
.swgroups = tegra210_group_display,
|
||||
.num_swgroups = ARRAY_SIZE(tegra210_group_display),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct tegra_smmu_soc tegra210_smmu_soc = {
|
||||
.clients = tegra210_mc_clients,
|
||||
.num_clients = ARRAY_SIZE(tegra210_mc_clients),
|
||||
.swgroups = tegra210_swgroups,
|
||||
.num_swgroups = ARRAY_SIZE(tegra210_swgroups),
|
||||
.groups = tegra210_groups,
|
||||
.num_groups = ARRAY_SIZE(tegra210_groups),
|
||||
.supports_round_robin_arbitration = true,
|
||||
.supports_request_limit = true,
|
||||
.num_tlb_lines = 32,
|
||||
|
@@ -934,11 +934,26 @@ static const struct tegra_smmu_swgroup tegra30_swgroups[] = {
|
||||
{ .name = "isp", .swgroup = TEGRA_SWGROUP_ISP, .reg = 0x258 },
|
||||
};
|
||||
|
||||
static const unsigned int tegra30_group_display[] = {
|
||||
TEGRA_SWGROUP_DC,
|
||||
TEGRA_SWGROUP_DCB,
|
||||
};
|
||||
|
||||
static const struct tegra_smmu_group_soc tegra30_groups[] = {
|
||||
{
|
||||
.name = "display",
|
||||
.swgroups = tegra30_group_display,
|
||||
.num_swgroups = ARRAY_SIZE(tegra30_group_display),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct tegra_smmu_soc tegra30_smmu_soc = {
|
||||
.clients = tegra30_mc_clients,
|
||||
.num_clients = ARRAY_SIZE(tegra30_mc_clients),
|
||||
.swgroups = tegra30_swgroups,
|
||||
.num_swgroups = ARRAY_SIZE(tegra30_swgroups),
|
||||
.groups = tegra30_groups,
|
||||
.num_groups = ARRAY_SIZE(tegra30_groups),
|
||||
.supports_round_robin_arbitration = false,
|
||||
.supports_request_limit = false,
|
||||
.num_tlb_lines = 16,
|
||||
|
324
drivers/memory/ti-emif-pm.c
Normal file
324
drivers/memory/ti-emif-pm.c
Normal file
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* TI AM33XX SRAM EMIF Driver
|
||||
*
|
||||
* Copyright (C) 2016-2017 Texas Instruments Inc.
|
||||
* Dave Gerlach
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sram.h>
|
||||
#include <linux/ti-emif-sram.h>
|
||||
|
||||
#include "emif.h"
|
||||
|
||||
#define TI_EMIF_SRAM_SYMBOL_OFFSET(sym) ((unsigned long)(sym) - \
|
||||
(unsigned long)&ti_emif_sram)
|
||||
|
||||
#define EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES 0x00a0
|
||||
|
||||
struct ti_emif_data {
|
||||
phys_addr_t ti_emif_sram_phys;
|
||||
phys_addr_t ti_emif_sram_data_phys;
|
||||
unsigned long ti_emif_sram_virt;
|
||||
unsigned long ti_emif_sram_data_virt;
|
||||
struct gen_pool *sram_pool_code;
|
||||
struct gen_pool *sram_pool_data;
|
||||
struct ti_emif_pm_data pm_data;
|
||||
struct ti_emif_pm_functions pm_functions;
|
||||
};
|
||||
|
||||
static struct ti_emif_data *emif_instance;
|
||||
|
||||
static u32 sram_suspend_address(struct ti_emif_data *emif_data,
|
||||
unsigned long addr)
|
||||
{
|
||||
return (emif_data->ti_emif_sram_virt +
|
||||
TI_EMIF_SRAM_SYMBOL_OFFSET(addr));
|
||||
}
|
||||
|
||||
static phys_addr_t sram_resume_address(struct ti_emif_data *emif_data,
|
||||
unsigned long addr)
|
||||
{
|
||||
return ((unsigned long)emif_data->ti_emif_sram_phys +
|
||||
TI_EMIF_SRAM_SYMBOL_OFFSET(addr));
|
||||
}
|
||||
|
||||
static void ti_emif_free_sram(struct ti_emif_data *emif_data)
|
||||
{
|
||||
gen_pool_free(emif_data->sram_pool_code, emif_data->ti_emif_sram_virt,
|
||||
ti_emif_sram_sz);
|
||||
gen_pool_free(emif_data->sram_pool_data,
|
||||
emif_data->ti_emif_sram_data_virt,
|
||||
sizeof(struct emif_regs_amx3));
|
||||
}
|
||||
|
||||
static int ti_emif_alloc_sram(struct device *dev,
|
||||
struct ti_emif_data *emif_data)
|
||||
{
|
||||
struct device_node *np = dev->of_node;
|
||||
int ret;
|
||||
|
||||
emif_data->sram_pool_code = of_gen_pool_get(np, "sram", 0);
|
||||
if (!emif_data->sram_pool_code) {
|
||||
dev_err(dev, "Unable to get sram pool for ocmcram code\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
emif_data->ti_emif_sram_virt =
|
||||
gen_pool_alloc(emif_data->sram_pool_code,
|
||||
ti_emif_sram_sz);
|
||||
if (!emif_data->ti_emif_sram_virt) {
|
||||
dev_err(dev, "Unable to allocate code memory from ocmcram\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Save physical address to calculate resume offset during pm init */
|
||||
emif_data->ti_emif_sram_phys =
|
||||
gen_pool_virt_to_phys(emif_data->sram_pool_code,
|
||||
emif_data->ti_emif_sram_virt);
|
||||
|
||||
/* Get sram pool for data section and allocate space */
|
||||
emif_data->sram_pool_data = of_gen_pool_get(np, "sram", 1);
|
||||
if (!emif_data->sram_pool_data) {
|
||||
dev_err(dev, "Unable to get sram pool for ocmcram data\n");
|
||||
ret = -ENODEV;
|
||||
goto err_free_sram_code;
|
||||
}
|
||||
|
||||
emif_data->ti_emif_sram_data_virt =
|
||||
gen_pool_alloc(emif_data->sram_pool_data,
|
||||
sizeof(struct emif_regs_amx3));
|
||||
if (!emif_data->ti_emif_sram_data_virt) {
|
||||
dev_err(dev, "Unable to allocate data memory from ocmcram\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free_sram_code;
|
||||
}
|
||||
|
||||
/* Save physical address to calculate resume offset during pm init */
|
||||
emif_data->ti_emif_sram_data_phys =
|
||||
gen_pool_virt_to_phys(emif_data->sram_pool_data,
|
||||
emif_data->ti_emif_sram_data_virt);
|
||||
/*
|
||||
* These functions are called during suspend path while MMU is
|
||||
* still on so add virtual base to offset for absolute address
|
||||
*/
|
||||
emif_data->pm_functions.save_context =
|
||||
sram_suspend_address(emif_data,
|
||||
(unsigned long)ti_emif_save_context);
|
||||
emif_data->pm_functions.enter_sr =
|
||||
sram_suspend_address(emif_data,
|
||||
(unsigned long)ti_emif_enter_sr);
|
||||
emif_data->pm_functions.abort_sr =
|
||||
sram_suspend_address(emif_data,
|
||||
(unsigned long)ti_emif_abort_sr);
|
||||
|
||||
/*
|
||||
* These are called during resume path when MMU is not enabled
|
||||
* so physical address is used instead
|
||||
*/
|
||||
emif_data->pm_functions.restore_context =
|
||||
sram_resume_address(emif_data,
|
||||
(unsigned long)ti_emif_restore_context);
|
||||
emif_data->pm_functions.exit_sr =
|
||||
sram_resume_address(emif_data,
|
||||
(unsigned long)ti_emif_exit_sr);
|
||||
|
||||
emif_data->pm_data.regs_virt =
|
||||
(struct emif_regs_amx3 *)emif_data->ti_emif_sram_data_virt;
|
||||
emif_data->pm_data.regs_phys = emif_data->ti_emif_sram_data_phys;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_sram_code:
|
||||
gen_pool_free(emif_data->sram_pool_code, emif_data->ti_emif_sram_virt,
|
||||
ti_emif_sram_sz);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ti_emif_push_sram(struct device *dev, struct ti_emif_data *emif_data)
|
||||
{
|
||||
void *copy_addr;
|
||||
u32 data_addr;
|
||||
|
||||
copy_addr = sram_exec_copy(emif_data->sram_pool_code,
|
||||
(void *)emif_data->ti_emif_sram_virt,
|
||||
&ti_emif_sram, ti_emif_sram_sz);
|
||||
if (!copy_addr) {
|
||||
dev_err(dev, "Cannot copy emif code to sram\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data_addr = sram_suspend_address(emif_data,
|
||||
(unsigned long)&ti_emif_pm_sram_data);
|
||||
copy_addr = sram_exec_copy(emif_data->sram_pool_code,
|
||||
(void *)data_addr,
|
||||
&emif_data->pm_data,
|
||||
sizeof(emif_data->pm_data));
|
||||
if (!copy_addr) {
|
||||
dev_err(dev, "Cannot copy emif data to code sram\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Due to Usage Note 3.1.2 "DDR3: JEDEC Compliance for Maximum
|
||||
* Self-Refresh Command Limit" found in AM335x Silicon Errata
|
||||
* (Document SPRZ360F Revised November 2013) we must configure
|
||||
* the self refresh delay timer to 0xA (8192 cycles) to avoid
|
||||
* generating too many refresh command from the EMIF.
|
||||
*/
|
||||
static void ti_emif_configure_sr_delay(struct ti_emif_data *emif_data)
|
||||
{
|
||||
writel(EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES,
|
||||
(emif_data->pm_data.ti_emif_base_addr_virt +
|
||||
EMIF_POWER_MANAGEMENT_CONTROL));
|
||||
|
||||
writel(EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES,
|
||||
(emif_data->pm_data.ti_emif_base_addr_virt +
|
||||
EMIF_POWER_MANAGEMENT_CTRL_SHDW));
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_emif_copy_pm_function_table - copy mapping of pm funcs in sram
|
||||
* @sram_pool: pointer to struct gen_pool where dst resides
|
||||
* @dst: void * to address that table should be copied
|
||||
*
|
||||
* Returns 0 if success other error code if table is not available
|
||||
*/
|
||||
int ti_emif_copy_pm_function_table(struct gen_pool *sram_pool, void *dst)
|
||||
{
|
||||
void *copy_addr;
|
||||
|
||||
if (!emif_instance)
|
||||
return -ENODEV;
|
||||
|
||||
copy_addr = sram_exec_copy(sram_pool, dst,
|
||||
&emif_instance->pm_functions,
|
||||
sizeof(emif_instance->pm_functions));
|
||||
if (!copy_addr)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ti_emif_copy_pm_function_table);
|
||||
|
||||
/**
|
||||
* ti_emif_get_mem_type - return type for memory type in use
|
||||
*
|
||||
* Returns memory type value read from EMIF or error code if fails
|
||||
*/
|
||||
int ti_emif_get_mem_type(void)
|
||||
{
|
||||
unsigned long temp;
|
||||
|
||||
if (!emif_instance)
|
||||
return -ENODEV;
|
||||
|
||||
temp = readl(emif_instance->pm_data.ti_emif_base_addr_virt +
|
||||
EMIF_SDRAM_CONFIG);
|
||||
|
||||
temp = (temp & SDRAM_TYPE_MASK) >> SDRAM_TYPE_SHIFT;
|
||||
return temp;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ti_emif_get_mem_type);
|
||||
|
||||
static const struct of_device_id ti_emif_of_match[] = {
|
||||
{ .compatible = "ti,emif-am3352", .data =
|
||||
(void *)EMIF_SRAM_AM33_REG_LAYOUT, },
|
||||
{ .compatible = "ti,emif-am4372", .data =
|
||||
(void *)EMIF_SRAM_AM43_REG_LAYOUT, },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ti_emif_of_match);
|
||||
|
||||
static int ti_emif_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct of_device_id *match;
|
||||
struct ti_emif_data *emif_data;
|
||||
|
||||
emif_data = devm_kzalloc(dev, sizeof(*emif_data), GFP_KERNEL);
|
||||
if (!emif_data)
|
||||
return -ENOMEM;
|
||||
|
||||
match = of_match_device(ti_emif_of_match, &pdev->dev);
|
||||
if (!match)
|
||||
return -ENODEV;
|
||||
|
||||
emif_data->pm_data.ti_emif_sram_config = (unsigned long)match->data;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
emif_data->pm_data.ti_emif_base_addr_virt = devm_ioremap_resource(dev,
|
||||
res);
|
||||
if (IS_ERR(emif_data->pm_data.ti_emif_base_addr_virt)) {
|
||||
dev_err(dev, "could not ioremap emif mem\n");
|
||||
ret = PTR_ERR(emif_data->pm_data.ti_emif_base_addr_virt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
emif_data->pm_data.ti_emif_base_addr_phys = res->start;
|
||||
|
||||
ti_emif_configure_sr_delay(emif_data);
|
||||
|
||||
ret = ti_emif_alloc_sram(dev, emif_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ti_emif_push_sram(dev, emif_data);
|
||||
if (ret)
|
||||
goto fail_free_sram;
|
||||
|
||||
emif_instance = emif_data;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_free_sram:
|
||||
ti_emif_free_sram(emif_data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ti_emif_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ti_emif_data *emif_data = emif_instance;
|
||||
|
||||
emif_instance = NULL;
|
||||
|
||||
ti_emif_free_sram(emif_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ti_emif_driver = {
|
||||
.probe = ti_emif_probe,
|
||||
.remove = ti_emif_remove,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.of_match_table = of_match_ptr(ti_emif_of_match),
|
||||
},
|
||||
};
|
||||
module_platform_driver(ti_emif_driver);
|
||||
|
||||
MODULE_AUTHOR("Dave Gerlach <d-gerlach@ti.com>");
|
||||
MODULE_DESCRIPTION("Texas Instruments SRAM EMIF driver");
|
||||
MODULE_LICENSE("GPL v2");
|
334
drivers/memory/ti-emif-sram-pm.S
Normal file
334
drivers/memory/ti-emif-sram-pm.S
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Low level PM code for TI EMIF
|
||||
*
|
||||
* Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Dave Gerlach
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <generated/ti-emif-asm-offsets.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
#include <asm/memory.h>
|
||||
|
||||
#include "emif.h"
|
||||
|
||||
#define EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES 0x00a0
|
||||
#define EMIF_POWER_MGMT_SR_TIMER_MASK 0x00f0
|
||||
#define EMIF_POWER_MGMT_SELF_REFRESH_MODE 0x0200
|
||||
#define EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK 0x0700
|
||||
|
||||
#define EMIF_SDCFG_TYPE_DDR2 0x2 << SDRAM_TYPE_SHIFT
|
||||
#define EMIF_STATUS_READY 0x4
|
||||
|
||||
#define AM43XX_EMIF_PHY_CTRL_REG_COUNT 0x120
|
||||
|
||||
#define EMIF_AM437X_REGISTERS 0x1
|
||||
|
||||
.arm
|
||||
.align 3
|
||||
|
||||
ENTRY(ti_emif_sram)
|
||||
|
||||
/*
|
||||
* void ti_emif_save_context(void)
|
||||
*
|
||||
* Used during suspend to save the context of all required EMIF registers
|
||||
* to local memory if the EMIF is going to lose context during the sleep
|
||||
* transition. Operates on the VIRTUAL address of the EMIF.
|
||||
*/
|
||||
ENTRY(ti_emif_save_context)
|
||||
stmfd sp!, {r4 - r11, lr} @ save registers on stack
|
||||
|
||||
adr r4, ti_emif_pm_sram_data
|
||||
ldr r0, [r4, #EMIF_PM_BASE_ADDR_VIRT_OFFSET]
|
||||
ldr r2, [r4, #EMIF_PM_REGS_VIRT_OFFSET]
|
||||
|
||||
/* Save EMIF configuration */
|
||||
ldr r1, [r0, #EMIF_SDRAM_CONFIG]
|
||||
str r1, [r2, #EMIF_SDCFG_VAL_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
|
||||
str r1, [r2, #EMIF_REF_CTRL_VAL_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_SDRAM_TIMING_1]
|
||||
str r1, [r2, #EMIF_TIMING1_VAL_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_SDRAM_TIMING_2]
|
||||
str r1, [r2, #EMIF_TIMING2_VAL_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_SDRAM_TIMING_3]
|
||||
str r1, [r2, #EMIF_TIMING3_VAL_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
|
||||
str r1, [r2, #EMIF_PMCR_VAL_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
|
||||
str r1, [r2, #EMIF_PMCR_SHDW_VAL_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
|
||||
str r1, [r2, #EMIF_ZQCFG_VAL_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_DDR_PHY_CTRL_1]
|
||||
str r1, [r2, #EMIF_DDR_PHY_CTLR_1_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_COS_CONFIG]
|
||||
str r1, [r2, #EMIF_COS_CONFIG_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING]
|
||||
str r1, [r2, #EMIF_PRIORITY_TO_COS_MAPPING_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING]
|
||||
str r1, [r2, #EMIF_CONNECT_ID_SERV_1_MAP_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING]
|
||||
str r1, [r2, #EMIF_CONNECT_ID_SERV_2_MAP_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_OCP_CONFIG]
|
||||
str r1, [r2, #EMIF_OCP_CONFIG_VAL_OFFSET]
|
||||
|
||||
ldr r5, [r4, #EMIF_PM_CONFIG_OFFSET]
|
||||
cmp r5, #EMIF_SRAM_AM43_REG_LAYOUT
|
||||
bne emif_skip_save_extra_regs
|
||||
|
||||
ldr r1, [r0, #EMIF_READ_WRITE_LEVELING_RAMP_CONTROL]
|
||||
str r1, [r2, #EMIF_RD_WR_LEVEL_RAMP_CTRL_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_READ_WRITE_EXECUTION_THRESHOLD]
|
||||
str r1, [r2, #EMIF_RD_WR_EXEC_THRESH_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_LPDDR2_NVM_TIMING]
|
||||
str r1, [r2, #EMIF_LPDDR2_NVM_TIM_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_LPDDR2_NVM_TIMING_SHDW]
|
||||
str r1, [r2, #EMIF_LPDDR2_NVM_TIM_SHDW_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_DLL_CALIB_CTRL]
|
||||
str r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_DLL_CALIB_CTRL_SHDW]
|
||||
str r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_SHDW_OFFSET]
|
||||
|
||||
/* Loop and save entire block of emif phy regs */
|
||||
mov r5, #0x0
|
||||
add r4, r2, #EMIF_EXT_PHY_CTRL_VALS_OFFSET
|
||||
add r3, r0, #EMIF_EXT_PHY_CTRL_1
|
||||
ddr_phy_ctrl_save:
|
||||
ldr r1, [r3, r5]
|
||||
str r1, [r4, r5]
|
||||
add r5, r5, #0x4
|
||||
cmp r5, #AM43XX_EMIF_PHY_CTRL_REG_COUNT
|
||||
bne ddr_phy_ctrl_save
|
||||
|
||||
emif_skip_save_extra_regs:
|
||||
ldmfd sp!, {r4 - r11, pc} @ restore regs and return
|
||||
ENDPROC(ti_emif_save_context)
|
||||
|
||||
/*
|
||||
* void ti_emif_restore_context(void)
|
||||
*
|
||||
* Used during resume to restore the context of all required EMIF registers
|
||||
* from local memory after the EMIF has lost context during a sleep transition.
|
||||
* Operates on the PHYSICAL address of the EMIF.
|
||||
*/
|
||||
ENTRY(ti_emif_restore_context)
|
||||
adr r4, ti_emif_pm_sram_data
|
||||
ldr r0, [r4, #EMIF_PM_BASE_ADDR_PHYS_OFFSET]
|
||||
ldr r2, [r4, #EMIF_PM_REGS_PHYS_OFFSET]
|
||||
|
||||
/* Config EMIF Timings */
|
||||
ldr r1, [r2, #EMIF_DDR_PHY_CTLR_1_OFFSET]
|
||||
str r1, [r0, #EMIF_DDR_PHY_CTRL_1]
|
||||
str r1, [r0, #EMIF_DDR_PHY_CTRL_1_SHDW]
|
||||
|
||||
ldr r1, [r2, #EMIF_TIMING1_VAL_OFFSET]
|
||||
str r1, [r0, #EMIF_SDRAM_TIMING_1]
|
||||
str r1, [r0, #EMIF_SDRAM_TIMING_1_SHDW]
|
||||
|
||||
ldr r1, [r2, #EMIF_TIMING2_VAL_OFFSET]
|
||||
str r1, [r0, #EMIF_SDRAM_TIMING_2]
|
||||
str r1, [r0, #EMIF_SDRAM_TIMING_2_SHDW]
|
||||
|
||||
ldr r1, [r2, #EMIF_TIMING3_VAL_OFFSET]
|
||||
str r1, [r0, #EMIF_SDRAM_TIMING_3]
|
||||
str r1, [r0, #EMIF_SDRAM_TIMING_3_SHDW]
|
||||
|
||||
ldr r1, [r2, #EMIF_REF_CTRL_VAL_OFFSET]
|
||||
str r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
|
||||
str r1, [r0, #EMIF_SDRAM_REFRESH_CTRL_SHDW]
|
||||
|
||||
ldr r1, [r2, #EMIF_PMCR_VAL_OFFSET]
|
||||
str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
|
||||
|
||||
ldr r1, [r2, #EMIF_PMCR_SHDW_VAL_OFFSET]
|
||||
str r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
|
||||
|
||||
ldr r1, [r2, #EMIF_COS_CONFIG_OFFSET]
|
||||
str r1, [r0, #EMIF_COS_CONFIG]
|
||||
|
||||
ldr r1, [r2, #EMIF_PRIORITY_TO_COS_MAPPING_OFFSET]
|
||||
str r1, [r0, #EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING]
|
||||
|
||||
ldr r1, [r2, #EMIF_CONNECT_ID_SERV_1_MAP_OFFSET]
|
||||
str r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING]
|
||||
|
||||
ldr r1, [r2, #EMIF_CONNECT_ID_SERV_2_MAP_OFFSET]
|
||||
str r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING]
|
||||
|
||||
ldr r1, [r2, #EMIF_OCP_CONFIG_VAL_OFFSET]
|
||||
str r1, [r0, #EMIF_OCP_CONFIG]
|
||||
|
||||
ldr r5, [r4, #EMIF_PM_CONFIG_OFFSET]
|
||||
cmp r5, #EMIF_SRAM_AM43_REG_LAYOUT
|
||||
bne emif_skip_restore_extra_regs
|
||||
|
||||
ldr r1, [r2, #EMIF_RD_WR_LEVEL_RAMP_CTRL_OFFSET]
|
||||
str r1, [r0, #EMIF_READ_WRITE_LEVELING_RAMP_CONTROL]
|
||||
|
||||
ldr r1, [r2, #EMIF_RD_WR_EXEC_THRESH_OFFSET]
|
||||
str r1, [r0, #EMIF_READ_WRITE_EXECUTION_THRESHOLD]
|
||||
|
||||
ldr r1, [r2, #EMIF_LPDDR2_NVM_TIM_OFFSET]
|
||||
str r1, [r0, #EMIF_LPDDR2_NVM_TIMING]
|
||||
|
||||
ldr r1, [r2, #EMIF_LPDDR2_NVM_TIM_SHDW_OFFSET]
|
||||
str r1, [r0, #EMIF_LPDDR2_NVM_TIMING_SHDW]
|
||||
|
||||
ldr r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_OFFSET]
|
||||
str r1, [r0, #EMIF_DLL_CALIB_CTRL]
|
||||
|
||||
ldr r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_SHDW_OFFSET]
|
||||
str r1, [r0, #EMIF_DLL_CALIB_CTRL_SHDW]
|
||||
|
||||
ldr r1, [r2, #EMIF_ZQCFG_VAL_OFFSET]
|
||||
str r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
|
||||
|
||||
/* Loop and restore entire block of emif phy regs */
|
||||
mov r5, #0x0
|
||||
/* Load ti_emif_regs_amx3 + EMIF_EXT_PHY_CTRL_VALS_OFFSET for address
|
||||
* to phy register save space
|
||||
*/
|
||||
add r3, r2, #EMIF_EXT_PHY_CTRL_VALS_OFFSET
|
||||
add r4, r0, #EMIF_EXT_PHY_CTRL_1
|
||||
ddr_phy_ctrl_restore:
|
||||
ldr r1, [r3, r5]
|
||||
str r1, [r4, r5]
|
||||
add r5, r5, #0x4
|
||||
cmp r5, #AM43XX_EMIF_PHY_CTRL_REG_COUNT
|
||||
bne ddr_phy_ctrl_restore
|
||||
|
||||
emif_skip_restore_extra_regs:
|
||||
/*
|
||||
* Output impedence calib needed only for DDR3
|
||||
* but since the initial state of this will be
|
||||
* disabled for DDR2 no harm in restoring the
|
||||
* old configuration
|
||||
*/
|
||||
ldr r1, [r2, #EMIF_ZQCFG_VAL_OFFSET]
|
||||
str r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
|
||||
|
||||
/* Write to sdcfg last for DDR2 only */
|
||||
ldr r1, [r2, #EMIF_SDCFG_VAL_OFFSET]
|
||||
and r2, r1, #SDRAM_TYPE_MASK
|
||||
cmp r2, #EMIF_SDCFG_TYPE_DDR2
|
||||
streq r1, [r0, #EMIF_SDRAM_CONFIG]
|
||||
|
||||
mov pc, lr
|
||||
ENDPROC(ti_emif_restore_context)
|
||||
|
||||
/*
|
||||
* void ti_emif_enter_sr(void)
|
||||
*
|
||||
* Programs the EMIF to tell the SDRAM to enter into self-refresh
|
||||
* mode during a sleep transition. Operates on the VIRTUAL address
|
||||
* of the EMIF.
|
||||
*/
|
||||
ENTRY(ti_emif_enter_sr)
|
||||
stmfd sp!, {r4 - r11, lr} @ save registers on stack
|
||||
|
||||
adr r4, ti_emif_pm_sram_data
|
||||
ldr r0, [r4, #EMIF_PM_BASE_ADDR_VIRT_OFFSET]
|
||||
ldr r2, [r4, #EMIF_PM_REGS_VIRT_OFFSET]
|
||||
|
||||
ldr r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
|
||||
bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
|
||||
orr r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE
|
||||
str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
|
||||
|
||||
ldmfd sp!, {r4 - r11, pc} @ restore regs and return
|
||||
ENDPROC(ti_emif_enter_sr)
|
||||
|
||||
/*
|
||||
* void ti_emif_exit_sr(void)
|
||||
*
|
||||
* Programs the EMIF to tell the SDRAM to exit self-refresh mode
|
||||
* after a sleep transition. Operates on the PHYSICAL address of
|
||||
* the EMIF.
|
||||
*/
|
||||
ENTRY(ti_emif_exit_sr)
|
||||
adr r4, ti_emif_pm_sram_data
|
||||
ldr r0, [r4, #EMIF_PM_BASE_ADDR_PHYS_OFFSET]
|
||||
ldr r2, [r4, #EMIF_PM_REGS_PHYS_OFFSET]
|
||||
|
||||
/*
|
||||
* Toggle EMIF to exit refresh mode:
|
||||
* if EMIF lost context, PWR_MGT_CTRL is currently 0, writing disable
|
||||
* (0x0), wont do diddly squat! so do a toggle from SR(0x2) to disable
|
||||
* (0x0) here.
|
||||
* *If* EMIF did not lose context, nothing broken as we write the same
|
||||
* value(0x2) to reg before we write a disable (0x0).
|
||||
*/
|
||||
ldr r1, [r2, #EMIF_PMCR_VAL_OFFSET]
|
||||
bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
|
||||
orr r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE
|
||||
str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
|
||||
bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
|
||||
str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
|
||||
|
||||
/* Wait for EMIF to become ready */
|
||||
1: ldr r1, [r0, #EMIF_STATUS]
|
||||
tst r1, #EMIF_STATUS_READY
|
||||
beq 1b
|
||||
|
||||
mov pc, lr
|
||||
ENDPROC(ti_emif_exit_sr)
|
||||
|
||||
/*
|
||||
* void ti_emif_abort_sr(void)
|
||||
*
|
||||
* Disables self-refresh after a failed transition to a low-power
|
||||
* state so the kernel can jump back to DDR and follow abort path.
|
||||
* Operates on the VIRTUAL address of the EMIF.
|
||||
*/
|
||||
ENTRY(ti_emif_abort_sr)
|
||||
stmfd sp!, {r4 - r11, lr} @ save registers on stack
|
||||
|
||||
adr r4, ti_emif_pm_sram_data
|
||||
ldr r0, [r4, #EMIF_PM_BASE_ADDR_VIRT_OFFSET]
|
||||
ldr r2, [r4, #EMIF_PM_REGS_VIRT_OFFSET]
|
||||
|
||||
ldr r1, [r2, #EMIF_PMCR_VAL_OFFSET]
|
||||
bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
|
||||
str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
|
||||
|
||||
/* Wait for EMIF to become ready */
|
||||
1: ldr r1, [r0, #EMIF_STATUS]
|
||||
tst r1, #EMIF_STATUS_READY
|
||||
beq 1b
|
||||
|
||||
ldmfd sp!, {r4 - r11, pc} @ restore regs and return
|
||||
ENDPROC(ti_emif_abort_sr)
|
||||
|
||||
.align 3
|
||||
ENTRY(ti_emif_pm_sram_data)
|
||||
.space EMIF_PM_DATA_SIZE
|
||||
ENTRY(ti_emif_sram_sz)
|
||||
.word . - ti_emif_save_context
|
Reference in New Issue
Block a user