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:
Коммит
11077e9bf7
|
@ -23,6 +23,13 @@ Required properties:
|
||||||
the value shall be "emif<n>" where <n> is the number of the EMIF
|
the value shall be "emif<n>" where <n> is the number of the EMIF
|
||||||
instance with base 1.
|
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:
|
Optional properties:
|
||||||
- cs1-used : Have this property if CS1 of this EMIF
|
- cs1-used : Have this property if CS1 of this EMIF
|
||||||
instance has a memory part attached to it. If there is a memory
|
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
|
- hw-caps-temp-alert : Have this property if the controller
|
||||||
has capability for generating SDRAM temperature alerts
|
has capability for generating SDRAM temperature alerts
|
||||||
|
|
||||||
Example:
|
-Examples:
|
||||||
|
|
||||||
emif1: emif@4c000000 {
|
emif1: emif@4c000000 {
|
||||||
compatible = "ti,emif-4d";
|
compatible = "ti,emif-4d";
|
||||||
|
@ -56,3 +63,11 @@ emif1: emif@4c000000 {
|
||||||
hw-caps-ll-interface;
|
hw-caps-ll-interface;
|
||||||
hw-caps-temp-alert;
|
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? */
|
/* Is the message of valid length? */
|
||||||
if (mbox_msg->len > info->desc->max_msg_size) {
|
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);
|
mbox_msg->len, info->desc->max_msg_size);
|
||||||
ti_sci_dump_header_dbg(dev, hdr);
|
ti_sci_dump_header_dbg(dev, hdr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mbox_msg->len < xfer->rx_len) {
|
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);
|
mbox_msg->len, xfer->rx_len);
|
||||||
ti_sci_dump_header_dbg(dev, hdr);
|
ti_sci_dump_header_dbg(dev, hdr);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -84,6 +84,16 @@ config OMAP_GPMC_DEBUG
|
||||||
bootloader or else the GPMC timings won't be identical with the
|
bootloader or else the GPMC timings won't be identical with the
|
||||||
bootloader timings.
|
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
|
config MVEBU_DEVBUS
|
||||||
bool "Marvell EBU Device Bus Controller"
|
bool "Marvell EBU Device Bus Controller"
|
||||||
default y
|
default y
|
||||||
|
|
|
@ -23,3 +23,11 @@ obj-$(CONFIG_DA8XX_DDRCTL) += da8xx-ddrctl.o
|
||||||
|
|
||||||
obj-$(CONFIG_SAMSUNG_MC) += samsung/
|
obj-$(CONFIG_SAMSUNG_MC) += samsung/
|
||||||
obj-$(CONFIG_TEGRA_MC) += tegra/
|
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
|
||||||
|
|
|
@ -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__)
|
|
@ -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_SHIFT 0
|
||||||
#define READ_LATENCY_SHDW_MASK (0x1f << 0)
|
#define READ_LATENCY_SHDW_MASK (0x1f << 0)
|
||||||
|
|
||||||
|
#define EMIF_SRAM_AM33_REG_LAYOUT 0x00000000
|
||||||
|
#define EMIF_SRAM_AM43_REG_LAYOUT 0x00000001
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
/*
|
/*
|
||||||
* Structure containing shadow of important registers in EMIF
|
* 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_3_shdw;
|
||||||
u32 ext_phy_ctrl_4_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 /* __ASSEMBLY__ */
|
||||||
#endif /* __EMIF_H */
|
#endif /* __EMIF_H */
|
||||||
|
|
|
@ -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");
|
|
@ -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)) {
|
if (!knav_queue_is_busy(inst)) {
|
||||||
struct knav_range_info *range = inst->range;
|
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)
|
if (range->ops && range->ops->open_queue)
|
||||||
ret = range->ops->open_queue(range, inst, flags);
|
ret = range->ops->open_queue(range, inst, flags);
|
||||||
|
|
||||||
|
@ -779,7 +779,7 @@ void *knav_pool_create(const char *name,
|
||||||
goto err;
|
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->kdev = kdev;
|
||||||
pool->dev = kdev->dev;
|
pool->dev = kdev->dev;
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
Загрузка…
Ссылка в новой задаче