diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-01 16:35:31 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-01 16:35:31 -0800 |
commit | fe53d1443a146326b49d57fe6336b5c2a725223f (patch) | |
tree | 0bb6de8614bec52f025a0608910e80d6e9315245 /drivers/memory | |
parent | adbc128fa8b4e9ecfdd11d5dd0a7d9845c6ea510 (diff) | |
parent | 796543a64ebffdb638a22f428c4dadd037e34866 (diff) | |
download | linux-fe53d1443a146326b49d57fe6336b5c2a725223f.tar.gz linux-fe53d1443a146326b49d57fe6336b5c2a725223f.tar.bz2 linux-fe53d1443a146326b49d57fe6336b5c2a725223f.zip |
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
...
Diffstat (limited to 'drivers/memory')
-rw-r--r-- | drivers/memory/Kconfig | 10 | ||||
-rw-r--r-- | drivers/memory/Makefile | 8 | ||||
-rw-r--r-- | drivers/memory/Makefile.asm-offsets | 5 | ||||
-rw-r--r-- | drivers/memory/emif-asm-offsets.c | 92 | ||||
-rw-r--r-- | drivers/memory/emif.h | 17 | ||||
-rw-r--r-- | drivers/memory/tegra/Makefile | 1 | ||||
-rw-r--r-- | drivers/memory/tegra/tegra114.c | 15 | ||||
-rw-r--r-- | drivers/memory/tegra/tegra124.c | 17 | ||||
-rw-r--r-- | drivers/memory/tegra/tegra186.c | 600 | ||||
-rw-r--r-- | drivers/memory/tegra/tegra210.c | 15 | ||||
-rw-r--r-- | drivers/memory/tegra/tegra30.c | 15 | ||||
-rw-r--r-- | drivers/memory/ti-emif-pm.c | 324 | ||||
-rw-r--r-- | drivers/memory/ti-emif-sram-pm.S | 334 |
13 files changed, 1453 insertions, 0 deletions
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index ffc350258041..19a0e83f260d 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -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 diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index 929a601d4cd1..66f55240830e 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -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 diff --git a/drivers/memory/Makefile.asm-offsets b/drivers/memory/Makefile.asm-offsets new file mode 100644 index 000000000000..843ff60ccb5a --- /dev/null +++ b/drivers/memory/Makefile.asm-offsets @@ -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__) diff --git a/drivers/memory/emif-asm-offsets.c b/drivers/memory/emif-asm-offsets.c new file mode 100644 index 000000000000..71a89d5d3efd --- /dev/null +++ b/drivers/memory/emif-asm-offsets.c @@ -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; +} diff --git a/drivers/memory/emif.h b/drivers/memory/emif.h index bfe08bae961a..9e9f8037955d 100644 --- a/drivers/memory/emif.h +++ b/drivers/memory/emif.h @@ -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 */ diff --git a/drivers/memory/tegra/Makefile b/drivers/memory/tegra/Makefile index b44e8627a5e0..ce87a9470034 100644 --- a/drivers/memory/tegra/Makefile +++ b/drivers/memory/tegra/Makefile @@ -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 diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c index ba8fff3d66a6..b20e6e3e208e 100644 --- a/drivers/memory/tegra/tegra114.c +++ b/drivers/memory/tegra/tegra114.c @@ -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, diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c index 5a58e440f4a7..8b6360eabb8a 100644 --- a/drivers/memory/tegra/tegra124.c +++ b/drivers/memory/tegra/tegra124.c @@ -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, diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c new file mode 100644 index 000000000000..7254fb596979 --- /dev/null +++ b/drivers/memory/tegra/tegra186.c @@ -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"); diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c index 5e144abe4c18..d398bcd3fc57 100644 --- a/drivers/memory/tegra/tegra210.c +++ b/drivers/memory/tegra/tegra210.c @@ -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, diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c index b44737840e70..d756c837f23e 100644 --- a/drivers/memory/tegra/tegra30.c +++ b/drivers/memory/tegra/tegra30.c @@ -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, diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c new file mode 100644 index 000000000000..62a86c4bcd0b --- /dev/null +++ b/drivers/memory/ti-emif-pm.c @@ -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"); diff --git a/drivers/memory/ti-emif-sram-pm.S b/drivers/memory/ti-emif-sram-pm.S new file mode 100644 index 000000000000..a5369181e5c2 --- /dev/null +++ b/drivers/memory/ti-emif-sram-pm.S @@ -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 |