mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
SOC: Keystone Soc driver updates for 4.16
- TI EMIF-SRAM driver - TI SCI print format fix - Navigator strndup lenth fix -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJaRE65AAoJEHJsHOdBp5c/BOQP/1tvzmfQ2nllYiAJBN35e/PO 0qQE2rrFhPgoSx1e5+6gvuGhdekBvuqE68ejbswSYttfseOOOGpdh7s15M+sieQv fkZd7XJQMfBamJv+C5zZYe/qBNtfa8WFvAdSndpDYIaxSMsE5lzqbQPQga0/G2YW uYLc/iEFqh5uKVLl/KmVHGZ9sZ8kXZF8gGyLuzkgpqjuaJZZKygEi5agzq6EJhQK 09BEqQiesUWLxcYLjbao3EPmLmCWzsCyTbpEHBkRYtiRgsn7iccdLjQ8VSWfvb1n md3/FprPA7EuLdlYwuHQxsBNsm93WAPzLnubS1UKsenUEcbE36W4bJZgwbYHuaOT oHGeoAdTM1VWrjQ3Lty+Nn8hhCexrn72nVAxwnyt54CEdirxdSikrYOjq5jhf50z xP5eQp7J/GhX9b6xUHB25PnlxmRx2jIb1MAD5wHlND/Khw0kpph7mRuTUWtmnTOB w+qJfPpb+WkYep/8TkplyX86XB0eFghO9wPhOjc4lMmPdpsXlrdca78I+4YI6cv3 dvIRZwI4knwKQo6bqJ1lizCOaGHFxZLPylSLDplVatZFP6f1FuEHQ9GcxE2ErygP A5j+JRIJVedwW1ZJWMe3TPRAOnGrsWzuVUcBCYGURUYhGWrU6VMNGTc4nVducor+ Ukoyta0/V6rsBZCEBuP9 =hKyd -----END PGP SIGNATURE----- Merge tag 'keystone_driver_soc_for_4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone into next/drivers SOC: Keystone Soc driver updates for 4.16 - TI EMIF-SRAM driver - TI SCI print format fix - Navigator strndup lenth fix * tag 'keystone_driver_soc_for_4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone: soc: ti: fix max dup length for kstrndup firmware: ti_sci: Use %zu for size_t print format memory: ti-emif-sram: remove unused variable memory: ti-emif-sram: introduce relocatable suspend/resume handlers Documentation: dt: Update ti,emif bindings Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
11077e9bf7
@ -23,6 +23,13 @@ Required properties:
|
||||
the value shall be "emif<n>" where <n> is the number of the EMIF
|
||||
instance with base 1.
|
||||
|
||||
Required only for "ti,emif-am3352" and "ti,emif-am4372":
|
||||
- sram : Phandles for generic sram driver nodes,
|
||||
first should be type 'protect-exec' for the driver to use to copy
|
||||
and run PM functions, second should be regular pool to be used for
|
||||
data region for code. See Documentation/devicetree/bindings/sram/sram.txt
|
||||
for more details.
|
||||
|
||||
Optional properties:
|
||||
- cs1-used : Have this property if CS1 of this EMIF
|
||||
instance has a memory part attached to it. If there is a memory
|
||||
@ -44,7 +51,7 @@ Optional properties:
|
||||
- hw-caps-temp-alert : Have this property if the controller
|
||||
has capability for generating SDRAM temperature alerts
|
||||
|
||||
Example:
|
||||
-Examples:
|
||||
|
||||
emif1: emif@4c000000 {
|
||||
compatible = "ti,emif-4d";
|
||||
@ -56,3 +63,11 @@ emif1: emif@4c000000 {
|
||||
hw-caps-ll-interface;
|
||||
hw-caps-temp-alert;
|
||||
};
|
||||
|
||||
/* From am33xx.dtsi */
|
||||
emif: emif@4c000000 {
|
||||
compatible = "ti,emif-am3352";
|
||||
reg = <0x4C000000 0x1000>;
|
||||
sram = <&pm_sram_code
|
||||
&pm_sram_data>;
|
||||
};
|
||||
|
@ -287,13 +287,13 @@ static void ti_sci_rx_callback(struct mbox_client *cl, void *m)
|
||||
|
||||
/* Is the message of valid length? */
|
||||
if (mbox_msg->len > info->desc->max_msg_size) {
|
||||
dev_err(dev, "Unable to handle %d xfer(max %d)\n",
|
||||
dev_err(dev, "Unable to handle %zu xfer(max %d)\n",
|
||||
mbox_msg->len, info->desc->max_msg_size);
|
||||
ti_sci_dump_header_dbg(dev, hdr);
|
||||
return;
|
||||
}
|
||||
if (mbox_msg->len < xfer->rx_len) {
|
||||
dev_err(dev, "Recv xfer %d < expected %d length\n",
|
||||
dev_err(dev, "Recv xfer %zu < expected %d length\n",
|
||||
mbox_msg->len, xfer->rx_len);
|
||||
ti_sci_dump_header_dbg(dev, hdr);
|
||||
return;
|
||||
|
@ -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 */
|
||||
|
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
|
@ -225,7 +225,7 @@ static struct knav_queue *__knav_queue_open(struct knav_queue_inst *inst,
|
||||
if (!knav_queue_is_busy(inst)) {
|
||||
struct knav_range_info *range = inst->range;
|
||||
|
||||
inst->name = kstrndup(name, KNAV_NAME_SIZE, GFP_KERNEL);
|
||||
inst->name = kstrndup(name, KNAV_NAME_SIZE - 1, GFP_KERNEL);
|
||||
if (range->ops && range->ops->open_queue)
|
||||
ret = range->ops->open_queue(range, inst, flags);
|
||||
|
||||
@ -779,7 +779,7 @@ void *knav_pool_create(const char *name,
|
||||
goto err;
|
||||
}
|
||||
|
||||
pool->name = kstrndup(name, KNAV_NAME_SIZE, GFP_KERNEL);
|
||||
pool->name = kstrndup(name, KNAV_NAME_SIZE - 1, GFP_KERNEL);
|
||||
pool->kdev = kdev;
|
||||
pool->dev = kdev->dev;
|
||||
|
||||
|
69
include/linux/ti-emif-sram.h
Normal file
69
include/linux/ti-emif-sram.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* TI AM33XX EMIF Routines
|
||||
*
|
||||
* 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 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.
|
||||
*/
|
||||
#ifndef __LINUX_TI_EMIF_H
|
||||
#define __LINUX_TI_EMIF_H
|
||||
|
||||
#include <linux/kbuild.h>
|
||||
#include <linux/types.h>
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
struct emif_regs_amx3 {
|
||||
u32 emif_sdcfg_val;
|
||||
u32 emif_timing1_val;
|
||||
u32 emif_timing2_val;
|
||||
u32 emif_timing3_val;
|
||||
u32 emif_ref_ctrl_val;
|
||||
u32 emif_zqcfg_val;
|
||||
u32 emif_pmcr_val;
|
||||
u32 emif_pmcr_shdw_val;
|
||||
u32 emif_rd_wr_level_ramp_ctrl;
|
||||
u32 emif_rd_wr_exec_thresh;
|
||||
u32 emif_cos_config;
|
||||
u32 emif_priority_to_cos_mapping;
|
||||
u32 emif_connect_id_serv_1_map;
|
||||
u32 emif_connect_id_serv_2_map;
|
||||
u32 emif_ocp_config_val;
|
||||
u32 emif_lpddr2_nvm_tim;
|
||||
u32 emif_lpddr2_nvm_tim_shdw;
|
||||
u32 emif_dll_calib_ctrl_val;
|
||||
u32 emif_dll_calib_ctrl_val_shdw;
|
||||
u32 emif_ddr_phy_ctlr_1;
|
||||
u32 emif_ext_phy_ctrl_vals[120];
|
||||
};
|
||||
|
||||
struct ti_emif_pm_data {
|
||||
void __iomem *ti_emif_base_addr_virt;
|
||||
phys_addr_t ti_emif_base_addr_phys;
|
||||
unsigned long ti_emif_sram_config;
|
||||
struct emif_regs_amx3 *regs_virt;
|
||||
phys_addr_t regs_phys;
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct ti_emif_pm_functions {
|
||||
u32 save_context;
|
||||
u32 restore_context;
|
||||
u32 enter_sr;
|
||||
u32 exit_sr;
|
||||
u32 abort_sr;
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct gen_pool;
|
||||
|
||||
int ti_emif_copy_pm_function_table(struct gen_pool *sram_pool, void *dst);
|
||||
int ti_emif_get_mem_type(void);
|
||||
|
||||
#endif
|
||||
#endif /* __LINUX_TI_EMIF_H */
|
Loading…
Reference in New Issue
Block a user