summaryrefslogtreecommitdiff
path: root/drivers/memory
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/memory')
-rw-r--r--drivers/memory/Kconfig2
-rw-r--r--drivers/memory/atmel-ebi.c35
-rw-r--r--drivers/memory/brcmstb_dpfe.c2
-rw-r--r--drivers/memory/brcmstb_memc.c3
-rw-r--r--drivers/memory/emif.c96
-rw-r--r--drivers/memory/fsl-corenet-cf.c2
-rw-r--r--drivers/memory/fsl_ifc.c2
-rw-r--r--drivers/memory/jz4780-nemc.c2
-rw-r--r--drivers/memory/mtk-smi.c12
-rw-r--r--drivers/memory/omap-gpmc.c79
-rw-r--r--drivers/memory/pl172.c58
-rw-r--r--drivers/memory/pl353-smc.c58
-rw-r--r--drivers/memory/renesas-rpc-if.c4
-rw-r--r--drivers/memory/samsung/exynos5422-dmc.c92
-rw-r--r--drivers/memory/stm32-fmc2-ebi.c750
-rw-r--r--drivers/memory/tegra/mc.c13
-rw-r--r--drivers/memory/tegra/tegra124-emc.c9
-rw-r--r--drivers/memory/tegra/tegra124.c2
-rw-r--r--drivers/memory/tegra/tegra186-emc.c9
-rw-r--r--drivers/memory/tegra/tegra20-emc.c17
-rw-r--r--drivers/memory/tegra/tegra20.c2
-rw-r--r--drivers/memory/tegra/tegra210-emc-cc-r21021.c429
-rw-r--r--drivers/memory/tegra/tegra210-emc-core.c2
-rw-r--r--drivers/memory/tegra/tegra234.c48
-rw-r--r--drivers/memory/tegra/tegra30-emc.c9
-rw-r--r--drivers/memory/tegra/tegra30.c2
-rw-r--r--drivers/memory/ti-aemif.c266
-rw-r--r--drivers/memory/ti-emif-pm.c2
28 files changed, 1119 insertions, 888 deletions
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 8efdd1f97139..c82d8d8a16ea 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -167,7 +167,7 @@ config FSL_CORENET_CF
represents a coherency violation.
config FSL_IFC
- bool "Freescale IFC driver" if COMPILE_TEST
+ bool "Freescale IFC driver"
depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A || COMPILE_TEST
depends on HAS_IOMEM
diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c
index e8bb5f37f5cb..8db970da9af9 100644
--- a/drivers/memory/atmel-ebi.c
+++ b/drivers/memory/atmel-ebi.c
@@ -6,6 +6,7 @@
* Copyright (C) 2013 Jean-Jacques Hiblot <jjhiblot@traphandler.com>
*/
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
@@ -517,7 +518,7 @@ static int atmel_ebi_dev_disable(struct atmel_ebi *ebi, struct device_node *np)
static int atmel_ebi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *child, *np = dev->of_node, *smc_np;
+ struct device_node *np = dev->of_node;
struct atmel_ebi *ebi;
int ret, reg_cells;
struct clk *clk;
@@ -541,30 +542,24 @@ static int atmel_ebi_probe(struct platform_device *pdev)
ebi->clk = clk;
- smc_np = of_parse_phandle(dev->of_node, "atmel,smc", 0);
+ struct device_node *smc_np __free(device_node) =
+ of_parse_phandle(dev->of_node, "atmel,smc", 0);
ebi->smc.regmap = syscon_node_to_regmap(smc_np);
- if (IS_ERR(ebi->smc.regmap)) {
- ret = PTR_ERR(ebi->smc.regmap);
- goto put_node;
- }
+ if (IS_ERR(ebi->smc.regmap))
+ return PTR_ERR(ebi->smc.regmap);
ebi->smc.layout = atmel_hsmc_get_reg_layout(smc_np);
- if (IS_ERR(ebi->smc.layout)) {
- ret = PTR_ERR(ebi->smc.layout);
- goto put_node;
- }
+ if (IS_ERR(ebi->smc.layout))
+ return PTR_ERR(ebi->smc.layout);
ebi->smc.clk = of_clk_get(smc_np, 0);
if (IS_ERR(ebi->smc.clk)) {
- if (PTR_ERR(ebi->smc.clk) != -ENOENT) {
- ret = PTR_ERR(ebi->smc.clk);
- goto put_node;
- }
+ if (PTR_ERR(ebi->smc.clk) != -ENOENT)
+ return PTR_ERR(ebi->smc.clk);
ebi->smc.clk = NULL;
}
- of_node_put(smc_np);
ret = clk_prepare_enable(ebi->smc.clk);
if (ret)
return ret;
@@ -597,7 +592,7 @@ static int atmel_ebi_probe(struct platform_device *pdev)
reg_cells += val;
- for_each_available_child_of_node(np, child) {
+ for_each_available_child_of_node_scoped(np, child) {
if (!of_property_present(child, "reg"))
continue;
@@ -607,18 +602,12 @@ static int atmel_ebi_probe(struct platform_device *pdev)
child);
ret = atmel_ebi_dev_disable(ebi, child);
- if (ret) {
- of_node_put(child);
+ if (ret)
return ret;
- }
}
}
return of_platform_populate(np, NULL, NULL, dev);
-
-put_node:
- of_node_put(smc_np);
- return ret;
}
static __maybe_unused int atmel_ebi_resume(struct device *dev)
diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c
index 5028467b2dc9..08d9e05b1b33 100644
--- a/drivers/memory/brcmstb_dpfe.c
+++ b/drivers/memory/brcmstb_dpfe.c
@@ -934,7 +934,7 @@ static struct platform_driver brcmstb_dpfe_driver = {
.of_match_table = brcmstb_dpfe_of_match,
},
.probe = brcmstb_dpfe_probe,
- .remove_new = brcmstb_dpfe_remove,
+ .remove = brcmstb_dpfe_remove,
.resume = brcmstb_dpfe_resume,
};
diff --git a/drivers/memory/brcmstb_memc.c b/drivers/memory/brcmstb_memc.c
index ea9213f7152e..c87b37e2c1f0 100644
--- a/drivers/memory/brcmstb_memc.c
+++ b/drivers/memory/brcmstb_memc.c
@@ -243,6 +243,7 @@ static const struct of_device_id brcmstb_memc_of_match[] = {
},
{}
};
+MODULE_DEVICE_TABLE(of, brcmstb_memc_of_match);
static int brcmstb_memc_suspend(struct device *dev)
{
@@ -282,7 +283,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(brcmstb_memc_pm_ops, brcmstb_memc_suspend,
static struct platform_driver brcmstb_memc_driver = {
.probe = brcmstb_memc_probe,
- .remove_new = brcmstb_memc_remove,
+ .remove = brcmstb_memc_remove,
.driver = {
.name = "brcmstb_memc",
.of_match_table = brcmstb_memc_of_match,
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
index 434982545be6..2e1ecae9e959 100644
--- a/drivers/memory/emif.c
+++ b/drivers/memory/emif.c
@@ -7,6 +7,7 @@
* Aneesh V <aneesh@ti.com>
* Santosh Shilimkar <santosh.shilimkar@ti.com>
*/
+#include <linux/cleanup.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/reboot.h>
@@ -57,7 +58,6 @@ struct emif_data {
u8 temperature_level;
u8 lpmode;
struct list_head node;
- unsigned long irq_state;
void __iomem *base;
struct device *dev;
struct emif_regs *regs_cache[EMIF_MAX_NUM_FREQUENCIES];
@@ -69,10 +69,8 @@ struct emif_data {
static struct emif_data *emif1;
static DEFINE_SPINLOCK(emif_lock);
-static unsigned long irq_state;
static LIST_HEAD(device_list);
-#ifdef CONFIG_DEBUG_FS
static void do_emif_regdump_show(struct seq_file *s, struct emif_data *emif,
struct emif_regs *regs)
{
@@ -140,31 +138,24 @@ static int emif_mr4_show(struct seq_file *s, void *unused)
DEFINE_SHOW_ATTRIBUTE(emif_mr4);
-static int __init_or_module emif_debugfs_init(struct emif_data *emif)
+static void emif_debugfs_init(struct emif_data *emif)
{
- emif->debugfs_root = debugfs_create_dir(dev_name(emif->dev), NULL);
- debugfs_create_file("regcache_dump", S_IRUGO, emif->debugfs_root, emif,
- &emif_regdump_fops);
- debugfs_create_file("mr4", S_IRUGO, emif->debugfs_root, emif,
- &emif_mr4_fops);
- return 0;
-}
-
-static void __exit emif_debugfs_exit(struct emif_data *emif)
-{
- debugfs_remove_recursive(emif->debugfs_root);
- emif->debugfs_root = NULL;
-}
-#else
-static inline int __init_or_module emif_debugfs_init(struct emif_data *emif)
-{
- return 0;
+ if (IS_ENABLED(CONFIG_DEBUG_FS)) {
+ emif->debugfs_root = debugfs_create_dir(dev_name(emif->dev), NULL);
+ debugfs_create_file("regcache_dump", S_IRUGO, emif->debugfs_root, emif,
+ &emif_regdump_fops);
+ debugfs_create_file("mr4", S_IRUGO, emif->debugfs_root, emif,
+ &emif_mr4_fops);
+ }
}
-static inline void __exit emif_debugfs_exit(struct emif_data *emif)
+static void emif_debugfs_exit(struct emif_data *emif)
{
+ if (IS_ENABLED(CONFIG_DEBUG_FS)) {
+ debugfs_remove_recursive(emif->debugfs_root);
+ emif->debugfs_root = NULL;
+ }
}
-#endif
/*
* Get bus width used by EMIF. Note that this may be different from the
@@ -531,18 +522,18 @@ out:
static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
{
u32 old_temp_level;
- irqreturn_t ret = IRQ_HANDLED;
+ irqreturn_t ret;
struct emif_custom_configs *custom_configs;
- spin_lock_irqsave(&emif_lock, irq_state);
+ guard(spinlock_irqsave)(&emif_lock);
old_temp_level = emif->temperature_level;
get_temperature_level(emif);
if (unlikely(emif->temperature_level == old_temp_level)) {
- goto out;
+ return IRQ_HANDLED;
} else if (!emif->curr_regs) {
dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n");
- goto out;
+ return IRQ_HANDLED;
}
custom_configs = emif->plat_data->custom_configs;
@@ -562,8 +553,7 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
* from thread context
*/
emif->temperature_level = SDRAM_TEMP_VERY_HIGH_SHUTDOWN;
- ret = IRQ_WAKE_THREAD;
- goto out;
+ return IRQ_WAKE_THREAD;
}
}
@@ -579,10 +569,9 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
/* Temperature is going up - handle immediately */
setup_temperature_sensitive_regs(emif, emif->curr_regs);
do_freq_update();
+ ret = IRQ_HANDLED;
}
-out:
- spin_unlock_irqrestore(&emif_lock, irq_state);
return ret;
}
@@ -625,6 +614,7 @@ static irqreturn_t emif_interrupt_handler(int irq, void *dev_id)
static irqreturn_t emif_threaded_isr(int irq, void *dev_id)
{
struct emif_data *emif = dev_id;
+ unsigned long irq_state;
if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) {
dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n");
@@ -679,7 +669,7 @@ static void disable_and_clear_all_interrupts(struct emif_data *emif)
clear_all_interrupts(emif);
}
-static int __init_or_module setup_interrupts(struct emif_data *emif, u32 irq)
+static int setup_interrupts(struct emif_data *emif, u32 irq)
{
u32 interrupts, type;
void __iomem *base = emif->base;
@@ -710,7 +700,7 @@ static int __init_or_module setup_interrupts(struct emif_data *emif, u32 irq)
}
-static void __init_or_module emif_onetime_settings(struct emif_data *emif)
+static void emif_onetime_settings(struct emif_data *emif)
{
u32 pwr_mgmt_ctrl, zq, temp_alert_cfg;
void __iomem *base = emif->base;
@@ -834,8 +824,7 @@ static int is_custom_config_valid(struct emif_custom_configs *cust_cfgs,
return valid;
}
-#if defined(CONFIG_OF)
-static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
+static void of_get_custom_configs(struct device_node *np_emif,
struct emif_data *emif)
{
struct emif_custom_configs *cust_cfgs = NULL;
@@ -873,7 +862,7 @@ static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
be32_to_cpup(poll_intvl);
}
- if (of_find_property(np_emif, "extended-temp-part", &len))
+ if (of_property_read_bool(np_emif, "extended-temp-part"))
cust_cfgs->mask |= EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART;
if (!is_custom_config_valid(cust_cfgs, emif->dev)) {
@@ -884,18 +873,14 @@ static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
emif->plat_data->custom_configs = cust_cfgs;
}
-static void __init_or_module of_get_ddr_info(struct device_node *np_emif,
+static void of_get_ddr_info(struct device_node *np_emif,
struct device_node *np_ddr,
struct ddr_device_info *dev_info)
{
u32 density = 0, io_width = 0;
- int len;
- if (of_find_property(np_emif, "cs1-used", &len))
- dev_info->cs1_used = true;
-
- if (of_find_property(np_emif, "cal-resistor-per-cs", &len))
- dev_info->cal_resistors_per_cs = true;
+ dev_info->cs1_used = of_property_read_bool(np_emif, "cs1-used");
+ dev_info->cal_resistors_per_cs = of_property_read_bool(np_emif, "cal-resistor-per-cs");
if (of_device_is_compatible(np_ddr, "jedec,lpddr2-s4"))
dev_info->type = DDR_TYPE_LPDDR2_S4;
@@ -918,14 +903,13 @@ static void __init_or_module of_get_ddr_info(struct device_node *np_emif,
dev_info->io_width = __fls(io_width) - 1;
}
-static struct emif_data * __init_or_module of_get_memory_device_details(
+static struct emif_data *of_get_memory_device_details(
struct device_node *np_emif, struct device *dev)
{
struct emif_data *emif = NULL;
struct ddr_device_info *dev_info = NULL;
struct emif_platform_data *pd = NULL;
struct device_node *np_ddr;
- int len;
np_ddr = of_parse_phandle(np_emif, "device-handle", 0);
if (!np_ddr)
@@ -953,7 +937,7 @@ static struct emif_data * __init_or_module of_get_memory_device_details(
of_property_read_u32(np_emif, "phy-type", &pd->phy_type);
- if (of_find_property(np_emif, "hw-caps-ll-interface", &len))
+ if (of_property_read_bool(np_emif, "hw-caps-ll-interface"))
pd->hw_caps |= EMIF_HW_CAPS_LL_INTERFACE;
of_get_ddr_info(np_emif, np_ddr, dev_info);
@@ -991,16 +975,7 @@ out:
return emif;
}
-#else
-
-static struct emif_data * __init_or_module of_get_memory_device_details(
- struct device_node *np_emif, struct device *dev)
-{
- return NULL;
-}
-#endif
-
-static struct emif_data *__init_or_module get_device_details(
+static struct emif_data *get_device_details(
struct platform_device *pdev)
{
u32 size;
@@ -1104,7 +1079,7 @@ error:
return NULL;
}
-static int __init_or_module emif_probe(struct platform_device *pdev)
+static int emif_probe(struct platform_device *pdev)
{
struct emif_data *emif;
int irq, ret;
@@ -1159,7 +1134,7 @@ error:
return -ENODEV;
}
-static void __exit emif_remove(struct platform_device *pdev)
+static void emif_remove(struct platform_device *pdev)
{
struct emif_data *emif = platform_get_drvdata(pdev);
@@ -1183,7 +1158,8 @@ MODULE_DEVICE_TABLE(of, emif_of_match);
#endif
static struct platform_driver emif_driver = {
- .remove_new = __exit_p(emif_remove),
+ .probe = emif_probe,
+ .remove = emif_remove,
.shutdown = emif_shutdown,
.driver = {
.name = "emif",
@@ -1191,7 +1167,7 @@ static struct platform_driver emif_driver = {
},
};
-module_platform_driver_probe(emif_driver, emif_probe);
+module_platform_driver(emif_driver);
MODULE_DESCRIPTION("TI EMIF SDRAM Controller Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/memory/fsl-corenet-cf.c b/drivers/memory/fsl-corenet-cf.c
index f47d05f7c5c5..ecd6c1955153 100644
--- a/drivers/memory/fsl-corenet-cf.c
+++ b/drivers/memory/fsl-corenet-cf.c
@@ -249,7 +249,7 @@ static struct platform_driver ccf_driver = {
.of_match_table = ccf_matches,
},
.probe = ccf_probe,
- .remove_new = ccf_remove,
+ .remove = ccf_remove,
};
module_platform_driver(ccf_driver);
diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c
index 15e919c24f81..e89e0c6cc4bc 100644
--- a/drivers/memory/fsl_ifc.c
+++ b/drivers/memory/fsl_ifc.c
@@ -316,7 +316,7 @@ static struct platform_driver fsl_ifc_ctrl_driver = {
.of_match_table = fsl_ifc_match,
},
.probe = fsl_ifc_ctrl_probe,
- .remove_new = fsl_ifc_ctrl_remove,
+ .remove = fsl_ifc_ctrl_remove,
};
static int __init fsl_ifc_init(void)
diff --git a/drivers/memory/jz4780-nemc.c b/drivers/memory/jz4780-nemc.c
index fb6db2ffe71b..1a8161514d03 100644
--- a/drivers/memory/jz4780-nemc.c
+++ b/drivers/memory/jz4780-nemc.c
@@ -407,7 +407,7 @@ static const struct of_device_id jz4780_nemc_dt_match[] = {
static struct platform_driver jz4780_nemc_driver = {
.probe = jz4780_nemc_probe,
- .remove_new = jz4780_nemc_remove,
+ .remove = jz4780_nemc_remove,
.driver = {
.name = "jz4780-nemc",
.of_match_table = of_match_ptr(jz4780_nemc_dt_match),
diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c
index 572c7fbdcfd3..5710348f72f6 100644
--- a/drivers/memory/mtk-smi.c
+++ b/drivers/memory/mtk-smi.c
@@ -450,6 +450,7 @@ static const struct of_device_id mtk_smi_larb_of_ids[] = {
{.compatible = "mediatek,mt8195-smi-larb", .data = &mtk_smi_larb_mt8195},
{}
};
+MODULE_DEVICE_TABLE(of, mtk_smi_larb_of_ids);
static int mtk_smi_larb_sleep_ctrl_enable(struct mtk_smi_larb *larb)
{
@@ -615,7 +616,7 @@ static const struct dev_pm_ops smi_larb_pm_ops = {
static struct platform_driver mtk_smi_larb_driver = {
.probe = mtk_smi_larb_probe,
- .remove_new = mtk_smi_larb_remove,
+ .remove = mtk_smi_larb_remove,
.driver = {
.name = "mtk-smi-larb",
.of_match_table = mtk_smi_larb_of_ids,
@@ -735,6 +736,7 @@ static const struct of_device_id mtk_smi_common_of_ids[] = {
{.compatible = "mediatek,mt8365-smi-common", .data = &mtk_smi_common_mt8365},
{}
};
+MODULE_DEVICE_TABLE(of, mtk_smi_common_of_ids);
static int mtk_smi_common_probe(struct platform_device *pdev)
{
@@ -769,13 +771,9 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
if (IS_ERR(common->smi_ao_base))
return PTR_ERR(common->smi_ao_base);
- common->clk_async = devm_clk_get(dev, "async");
+ common->clk_async = devm_clk_get_enabled(dev, "async");
if (IS_ERR(common->clk_async))
return PTR_ERR(common->clk_async);
-
- ret = clk_prepare_enable(common->clk_async);
- if (ret)
- return ret;
} else {
common->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(common->base))
@@ -840,7 +838,7 @@ static const struct dev_pm_ops smi_common_pm_ops = {
static struct platform_driver mtk_smi_common_driver = {
.probe = mtk_smi_common_probe,
- .remove_new = mtk_smi_common_remove,
+ .remove = mtk_smi_common_remove,
.driver = {
.name = "mtk-smi-common",
.of_match_table = mtk_smi_common_of_ids,
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 80d038884207..53f1888cc84f 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -9,6 +9,7 @@
* Copyright (C) 2009 Texas Instruments
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
*/
+#include <linux/cleanup.h>
#include <linux/cpu_pm.h>
#include <linux/irq.h>
#include <linux/kernel.h>
@@ -357,17 +358,6 @@ static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
return (time_ps + tick_ps - 1) / tick_ps;
}
-static unsigned int gpmc_clk_ticks_to_ns(unsigned int ticks, int cs,
- enum gpmc_clk_domain cd)
-{
- return ticks * gpmc_get_clk_period(cs, cd) / 1000;
-}
-
-unsigned int gpmc_ticks_to_ns(unsigned int ticks)
-{
- return gpmc_clk_ticks_to_ns(ticks, /* any CS */ 0, GPMC_CD_FCLK);
-}
-
static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
{
return ticks * gpmc_get_fclk_period();
@@ -414,6 +404,13 @@ static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p)
}
#ifdef CONFIG_OMAP_GPMC_DEBUG
+
+static unsigned int gpmc_clk_ticks_to_ns(unsigned int ticks, int cs,
+ enum gpmc_clk_domain cd)
+{
+ return ticks * gpmc_get_clk_period(cs, cd) / 1000;
+}
+
/**
* get_gpmc_timing_reg - read a timing parameter and print DTS settings for it.
* @cs: Chip Select Region
@@ -989,18 +986,18 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
if (size > (1 << GPMC_SECTION_SHIFT))
return -ENOMEM;
- spin_lock(&gpmc_mem_lock);
- if (gpmc_cs_reserved(cs)) {
- r = -EBUSY;
- goto out;
- }
+ guard(spinlock)(&gpmc_mem_lock);
+
+ if (gpmc_cs_reserved(cs))
+ return -EBUSY;
+
if (gpmc_cs_mem_enabled(cs))
r = adjust_resource(res, res->start & ~(size - 1), size);
if (r < 0)
r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0,
size, NULL, NULL);
if (r < 0)
- goto out;
+ return r;
/* Disable CS while changing base address and size mask */
gpmc_cs_disable_mem(cs);
@@ -1008,16 +1005,15 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
r = gpmc_cs_set_memconf(cs, res->start, resource_size(res));
if (r < 0) {
release_resource(res);
- goto out;
+ return r;
}
/* Enable CS */
gpmc_cs_enable_mem(cs);
*base = res->start;
gpmc_cs_set_reserved(cs, 1);
-out:
- spin_unlock(&gpmc_mem_lock);
- return r;
+
+ return 0;
}
EXPORT_SYMBOL(gpmc_cs_request);
@@ -1026,10 +1022,9 @@ void gpmc_cs_free(int cs)
struct gpmc_cs_data *gpmc;
struct resource *res;
- spin_lock(&gpmc_mem_lock);
+ guard(spinlock)(&gpmc_mem_lock);
if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
WARN(1, "Trying to free non-reserved GPMC CS%d\n", cs);
- spin_unlock(&gpmc_mem_lock);
return;
}
gpmc = &gpmc_cs[cs];
@@ -1039,7 +1034,6 @@ void gpmc_cs_free(int cs)
if (res->flags)
release_resource(res);
gpmc_cs_set_reserved(cs, 0);
- spin_unlock(&gpmc_mem_lock);
}
EXPORT_SYMBOL(gpmc_cs_free);
@@ -1297,21 +1291,6 @@ int gpmc_omap_onenand_set_timings(struct device *dev, int cs, int freq,
}
EXPORT_SYMBOL_GPL(gpmc_omap_onenand_set_timings);
-int gpmc_get_client_irq(unsigned int irq_config)
-{
- if (!gpmc_irq_domain) {
- pr_warn("%s called before GPMC IRQ domain available\n",
- __func__);
- return 0;
- }
-
- /* we restrict this to NAND IRQs only */
- if (irq_config >= GPMC_NR_NAND_IRQS)
- return 0;
-
- return irq_create_mapping(gpmc_irq_domain, irq_config);
-}
-
static int gpmc_irq_endis(unsigned long hwirq, bool endis)
{
u32 regval;
@@ -2247,26 +2226,6 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
goto err;
}
- if (of_node_name_eq(child, "nand")) {
- /* Warn about older DT blobs with no compatible property */
- if (!of_property_read_bool(child, "compatible")) {
- dev_warn(&pdev->dev,
- "Incompatible NAND node: missing compatible");
- ret = -EINVAL;
- goto err;
- }
- }
-
- if (of_node_name_eq(child, "onenand")) {
- /* Warn about older DT blobs with no compatible property */
- if (!of_property_read_bool(child, "compatible")) {
- dev_warn(&pdev->dev,
- "Incompatible OneNAND node: missing compatible");
- ret = -EINVAL;
- goto err;
- }
- }
-
if (of_match_node(omap_nand_ids, child)) {
/* NAND specific setup */
val = 8;
@@ -2745,7 +2704,7 @@ MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
static struct platform_driver gpmc_driver = {
.probe = gpmc_probe,
- .remove_new = gpmc_remove,
+ .remove = gpmc_remove,
.driver = {
.name = DEVICE_NAME,
.of_match_table = of_match_ptr(gpmc_dt_ids),
diff --git a/drivers/memory/pl172.c b/drivers/memory/pl172.c
index 9eb8cc7de494..be7ba599cccf 100644
--- a/drivers/memory/pl172.c
+++ b/drivers/memory/pl172.c
@@ -187,6 +187,13 @@ static int pl172_parse_cs_config(struct amba_device *adev,
return -EINVAL;
}
+static void pl172_amba_release_regions(void *data)
+{
+ struct amba_device *adev = data;
+
+ amba_release_regions(adev);
+}
+
static const char * const pl172_revisions[] = {"r1", "r2", "r2p3", "r2p4"};
static const char * const pl175_revisions[] = {"r1"};
static const char * const pl176_revisions[] = {"r0"};
@@ -216,38 +223,30 @@ static int pl172_probe(struct amba_device *adev, const struct amba_id *id)
if (!pl172)
return -ENOMEM;
- pl172->clk = devm_clk_get(dev, "mpmcclk");
- if (IS_ERR(pl172->clk)) {
- dev_err(dev, "no mpmcclk provided clock\n");
- return PTR_ERR(pl172->clk);
- }
-
- ret = clk_prepare_enable(pl172->clk);
- if (ret) {
- dev_err(dev, "unable to mpmcclk enable clock\n");
- return ret;
- }
+ pl172->clk = devm_clk_get_enabled(dev, "mpmcclk");
+ if (IS_ERR(pl172->clk))
+ return dev_err_probe(dev, PTR_ERR(pl172->clk),
+ "no mpmcclk provided clock\n");
pl172->rate = clk_get_rate(pl172->clk) / MSEC_PER_SEC;
- if (!pl172->rate) {
- dev_err(dev, "unable to get mpmcclk clock rate\n");
- ret = -EINVAL;
- goto err_clk_enable;
- }
+ if (!pl172->rate)
+ return dev_err_probe(dev, -EINVAL,
+ "unable to get mpmcclk clock rate\n");
ret = amba_request_regions(adev, NULL);
if (ret) {
dev_err(dev, "unable to request AMBA regions\n");
- goto err_clk_enable;
+ return ret;
}
+ ret = devm_add_action_or_reset(dev, pl172_amba_release_regions, adev);
+ if (ret)
+ return ret;
+
pl172->base = devm_ioremap(dev, adev->res.start,
resource_size(&adev->res));
- if (!pl172->base) {
- dev_err(dev, "ioremap failed\n");
- ret = -ENOMEM;
- goto err_no_ioremap;
- }
+ if (!pl172->base)
+ return dev_err_probe(dev, -ENOMEM, "ioremap failed\n");
amba_set_drvdata(adev, pl172);
@@ -265,20 +264,6 @@ static int pl172_probe(struct amba_device *adev, const struct amba_id *id)
}
return 0;
-
-err_no_ioremap:
- amba_release_regions(adev);
-err_clk_enable:
- clk_disable_unprepare(pl172->clk);
- return ret;
-}
-
-static void pl172_remove(struct amba_device *adev)
-{
- struct pl172_data *pl172 = amba_get_drvdata(adev);
-
- clk_disable_unprepare(pl172->clk);
- amba_release_regions(adev);
}
static const struct amba_id pl172_ids[] = {
@@ -306,7 +291,6 @@ static struct amba_driver pl172_driver = {
.name = "memory-pl172",
},
.probe = pl172_probe,
- .remove = pl172_remove,
.id_table = pl172_ids,
};
module_amba_driver(pl172_driver);
diff --git a/drivers/memory/pl353-smc.c b/drivers/memory/pl353-smc.c
index 48540817e046..28a8cc56003c 100644
--- a/drivers/memory/pl353-smc.c
+++ b/drivers/memory/pl353-smc.c
@@ -74,73 +74,39 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id)
struct device_node *of_node = adev->dev.of_node;
const struct of_device_id *match = NULL;
struct pl353_smc_data *pl353_smc;
- struct device_node *child;
- int err;
pl353_smc = devm_kzalloc(&adev->dev, sizeof(*pl353_smc), GFP_KERNEL);
if (!pl353_smc)
return -ENOMEM;
- pl353_smc->aclk = devm_clk_get(&adev->dev, "apb_pclk");
- if (IS_ERR(pl353_smc->aclk)) {
- dev_err(&adev->dev, "aclk clock not found.\n");
- return PTR_ERR(pl353_smc->aclk);
- }
-
- pl353_smc->memclk = devm_clk_get(&adev->dev, "memclk");
- if (IS_ERR(pl353_smc->memclk)) {
- dev_err(&adev->dev, "memclk clock not found.\n");
- return PTR_ERR(pl353_smc->memclk);
- }
+ pl353_smc->aclk = devm_clk_get_enabled(&adev->dev, "apb_pclk");
+ if (IS_ERR(pl353_smc->aclk))
+ return dev_err_probe(&adev->dev, PTR_ERR(pl353_smc->aclk),
+ "aclk clock not found.\n");
- err = clk_prepare_enable(pl353_smc->aclk);
- if (err) {
- dev_err(&adev->dev, "Unable to enable AXI clock.\n");
- return err;
- }
-
- err = clk_prepare_enable(pl353_smc->memclk);
- if (err) {
- dev_err(&adev->dev, "Unable to enable memory clock.\n");
- goto disable_axi_clk;
- }
+ pl353_smc->memclk = devm_clk_get_enabled(&adev->dev, "memclk");
+ if (IS_ERR(pl353_smc->memclk))
+ return dev_err_probe(&adev->dev, PTR_ERR(pl353_smc->memclk),
+ "memclk clock not found.\n");
amba_set_drvdata(adev, pl353_smc);
/* Find compatible children. Only a single child is supported */
- for_each_available_child_of_node(of_node, child) {
+ for_each_available_child_of_node_scoped(of_node, child) {
match = of_match_node(pl353_smc_supported_children, child);
if (!match) {
dev_warn(&adev->dev, "unsupported child node\n");
continue;
}
+ of_platform_device_create(child, NULL, &adev->dev);
break;
}
if (!match) {
- err = -ENODEV;
dev_err(&adev->dev, "no matching children\n");
- goto disable_mem_clk;
+ return -ENODEV;
}
- of_platform_device_create(child, NULL, &adev->dev);
- of_node_put(child);
-
return 0;
-
-disable_mem_clk:
- clk_disable_unprepare(pl353_smc->memclk);
-disable_axi_clk:
- clk_disable_unprepare(pl353_smc->aclk);
-
- return err;
-}
-
-static void pl353_smc_remove(struct amba_device *adev)
-{
- struct pl353_smc_data *pl353_smc = amba_get_drvdata(adev);
-
- clk_disable_unprepare(pl353_smc->memclk);
- clk_disable_unprepare(pl353_smc->aclk);
}
static const struct amba_id pl353_ids[] = {
@@ -154,13 +120,11 @@ MODULE_DEVICE_TABLE(amba, pl353_ids);
static struct amba_driver pl353_smc_driver = {
.drv = {
- .owner = THIS_MODULE,
.name = "pl353-smc",
.pm = &pl353_smc_dev_pm_ops,
},
.id_table = pl353_ids,
.probe = pl353_smc_probe,
- .remove = pl353_smc_remove,
};
module_amba_driver(pl353_smc_driver);
diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c
index 3167826b236a..15b4706aafee 100644
--- a/drivers/memory/renesas-rpc-if.c
+++ b/drivers/memory/renesas-rpc-if.c
@@ -367,7 +367,7 @@ int rpcif_hw_init(struct device *dev, bool hyperflash)
regmap_update_bits(rpc->regmap, RPCIF_CMNCR,
RPCIF_CMNCR_MOIIO(3) | RPCIF_CMNCR_IOFV(3) |
RPCIF_CMNCR_BSZ(3),
- RPCIF_CMNCR_MOIIO(1) | RPCIF_CMNCR_IOFV(2) |
+ RPCIF_CMNCR_MOIIO(1) | RPCIF_CMNCR_IOFV(3) |
RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0));
else
regmap_update_bits(rpc->regmap, RPCIF_CMNCR,
@@ -795,7 +795,7 @@ MODULE_DEVICE_TABLE(of, rpcif_of_match);
static struct platform_driver rpcif_driver = {
.probe = rpcif_probe,
- .remove_new = rpcif_remove,
+ .remove = rpcif_remove,
.driver = {
.name = "rpc-if",
.of_match_table = rpcif_of_match,
diff --git a/drivers/memory/samsung/exynos5422-dmc.c b/drivers/memory/samsung/exynos5422-dmc.c
index da7ecd921c72..788d49c688b1 100644
--- a/drivers/memory/samsung/exynos5422-dmc.c
+++ b/drivers/memory/samsung/exynos5422-dmc.c
@@ -4,6 +4,7 @@
* Author: Lukasz Luba <l.luba@partner.samsung.com>
*/
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/devfreq.h>
#include <linux/devfreq-event.h>
@@ -339,19 +340,20 @@ static int exynos5_switch_timing_regs(struct exynos5_dmc *dmc, bool set)
static int exynos5_init_freq_table(struct exynos5_dmc *dmc,
struct devfreq_dev_profile *profile)
{
+ struct device *dev = dmc->dev;
int i, ret;
int idx;
unsigned long freq;
- ret = devm_pm_opp_of_add_table(dmc->dev);
+ ret = devm_pm_opp_of_add_table(dev);
if (ret < 0) {
- dev_err(dmc->dev, "Failed to get OPP table\n");
+ dev_err(dev, "Failed to get OPP table\n");
return ret;
}
- dmc->opp_count = dev_pm_opp_get_opp_count(dmc->dev);
+ dmc->opp_count = dev_pm_opp_get_opp_count(dev);
- dmc->opp = devm_kmalloc_array(dmc->dev, dmc->opp_count,
+ dmc->opp = devm_kmalloc_array(dev, dmc->opp_count,
sizeof(struct dmc_opp_table), GFP_KERNEL);
if (!dmc->opp)
return -ENOMEM;
@@ -360,7 +362,7 @@ static int exynos5_init_freq_table(struct exynos5_dmc *dmc,
for (i = 0, freq = ULONG_MAX; i < dmc->opp_count; i++, freq--) {
struct dev_pm_opp *opp;
- opp = dev_pm_opp_find_freq_floor(dmc->dev, &freq);
+ opp = dev_pm_opp_find_freq_floor(dev, &freq);
if (IS_ERR(opp))
return PTR_ERR(opp);
@@ -1175,51 +1177,44 @@ static int create_timings_aligned(struct exynos5_dmc *dmc, u32 *reg_timing_row,
static int of_get_dram_timings(struct exynos5_dmc *dmc)
{
int ret = 0;
+ struct device *dev = dmc->dev;
int idx;
- struct device_node *np_ddr;
u32 freq_mhz, clk_period_ps;
- np_ddr = of_parse_phandle(dmc->dev->of_node, "device-handle", 0);
+ struct device_node *np_ddr __free(device_node) =
+ of_parse_phandle(dev->of_node, "device-handle", 0);
if (!np_ddr) {
- dev_warn(dmc->dev, "could not find 'device-handle' in DT\n");
+ dev_warn(dev, "could not find 'device-handle' in DT\n");
return -EINVAL;
}
- dmc->timing_row = devm_kmalloc_array(dmc->dev, TIMING_COUNT,
+ dmc->timing_row = devm_kmalloc_array(dev, TIMING_COUNT,
sizeof(u32), GFP_KERNEL);
- if (!dmc->timing_row) {
- ret = -ENOMEM;
- goto put_node;
- }
+ if (!dmc->timing_row)
+ return -ENOMEM;
- dmc->timing_data = devm_kmalloc_array(dmc->dev, TIMING_COUNT,
+ dmc->timing_data = devm_kmalloc_array(dev, TIMING_COUNT,
sizeof(u32), GFP_KERNEL);
- if (!dmc->timing_data) {
- ret = -ENOMEM;
- goto put_node;
- }
+ if (!dmc->timing_data)
+ return -ENOMEM;
- dmc->timing_power = devm_kmalloc_array(dmc->dev, TIMING_COUNT,
+ dmc->timing_power = devm_kmalloc_array(dev, TIMING_COUNT,
sizeof(u32), GFP_KERNEL);
- if (!dmc->timing_power) {
- ret = -ENOMEM;
- goto put_node;
- }
+ if (!dmc->timing_power)
+ return -ENOMEM;
- dmc->timings = of_lpddr3_get_ddr_timings(np_ddr, dmc->dev,
+ dmc->timings = of_lpddr3_get_ddr_timings(np_ddr, dev,
DDR_TYPE_LPDDR3,
&dmc->timings_arr_size);
if (!dmc->timings) {
- dev_warn(dmc->dev, "could not get timings from DT\n");
- ret = -EINVAL;
- goto put_node;
+ dev_warn(dev, "could not get timings from DT\n");
+ return -EINVAL;
}
- dmc->min_tck = of_lpddr3_get_min_tck(np_ddr, dmc->dev);
+ dmc->min_tck = of_lpddr3_get_min_tck(np_ddr, dev);
if (!dmc->min_tck) {
- dev_warn(dmc->dev, "could not get tck from DT\n");
- ret = -EINVAL;
- goto put_node;
+ dev_warn(dev, "could not get tck from DT\n");
+ return -EINVAL;
}
/* Sorted array of OPPs with frequency ascending */
@@ -1239,8 +1234,6 @@ static int of_get_dram_timings(struct exynos5_dmc *dmc)
dmc->bypass_timing_data = dmc->timing_data[idx - 1];
dmc->bypass_timing_power = dmc->timing_power[idx - 1];
-put_node:
- of_node_put(np_ddr);
return ret;
}
@@ -1254,34 +1247,34 @@ put_node:
static int exynos5_dmc_init_clks(struct exynos5_dmc *dmc)
{
int ret;
+ struct device *dev = dmc->dev;
unsigned long target_volt = 0;
unsigned long target_rate = 0;
unsigned int tmp;
- dmc->fout_spll = devm_clk_get(dmc->dev, "fout_spll");
+ dmc->fout_spll = devm_clk_get(dev, "fout_spll");
if (IS_ERR(dmc->fout_spll))
return PTR_ERR(dmc->fout_spll);
- dmc->fout_bpll = devm_clk_get(dmc->dev, "fout_bpll");
+ dmc->fout_bpll = devm_clk_get(dev, "fout_bpll");
if (IS_ERR(dmc->fout_bpll))
return PTR_ERR(dmc->fout_bpll);
- dmc->mout_mclk_cdrex = devm_clk_get(dmc->dev, "mout_mclk_cdrex");
+ dmc->mout_mclk_cdrex = devm_clk_get(dev, "mout_mclk_cdrex");
if (IS_ERR(dmc->mout_mclk_cdrex))
return PTR_ERR(dmc->mout_mclk_cdrex);
- dmc->mout_bpll = devm_clk_get(dmc->dev, "mout_bpll");
+ dmc->mout_bpll = devm_clk_get(dev, "mout_bpll");
if (IS_ERR(dmc->mout_bpll))
return PTR_ERR(dmc->mout_bpll);
- dmc->mout_mx_mspll_ccore = devm_clk_get(dmc->dev,
- "mout_mx_mspll_ccore");
+ dmc->mout_mx_mspll_ccore = devm_clk_get(dev, "mout_mx_mspll_ccore");
if (IS_ERR(dmc->mout_mx_mspll_ccore))
return PTR_ERR(dmc->mout_mx_mspll_ccore);
- dmc->mout_spll = devm_clk_get(dmc->dev, "ff_dout_spll2");
+ dmc->mout_spll = devm_clk_get(dev, "ff_dout_spll2");
if (IS_ERR(dmc->mout_spll)) {
- dmc->mout_spll = devm_clk_get(dmc->dev, "mout_sclk_spll");
+ dmc->mout_spll = devm_clk_get(dev, "mout_sclk_spll");
if (IS_ERR(dmc->mout_spll))
return PTR_ERR(dmc->mout_spll);
}
@@ -1329,38 +1322,37 @@ static int exynos5_dmc_init_clks(struct exynos5_dmc *dmc)
*/
static int exynos5_performance_counters_init(struct exynos5_dmc *dmc)
{
+ struct device *dev = dmc->dev;
int ret, i;
- dmc->num_counters = devfreq_event_get_edev_count(dmc->dev,
- "devfreq-events");
+ dmc->num_counters = devfreq_event_get_edev_count(dev, "devfreq-events");
if (dmc->num_counters < 0) {
- dev_err(dmc->dev, "could not get devfreq-event counters\n");
+ dev_err(dev, "could not get devfreq-event counters\n");
return dmc->num_counters;
}
- dmc->counter = devm_kcalloc(dmc->dev, dmc->num_counters,
+ dmc->counter = devm_kcalloc(dev, dmc->num_counters,
sizeof(*dmc->counter), GFP_KERNEL);
if (!dmc->counter)
return -ENOMEM;
for (i = 0; i < dmc->num_counters; i++) {
dmc->counter[i] =
- devfreq_event_get_edev_by_phandle(dmc->dev,
- "devfreq-events", i);
+ devfreq_event_get_edev_by_phandle(dev, "devfreq-events", i);
if (IS_ERR_OR_NULL(dmc->counter[i]))
return -EPROBE_DEFER;
}
ret = exynos5_counters_enable_edev(dmc);
if (ret < 0) {
- dev_err(dmc->dev, "could not enable event counter\n");
+ dev_err(dev, "could not enable event counter\n");
return ret;
}
ret = exynos5_counters_set_event(dmc);
if (ret < 0) {
exynos5_counters_disable_edev(dmc);
- dev_err(dmc->dev, "could not set event counter\n");
+ dev_err(dev, "could not set event counter\n");
return ret;
}
@@ -1579,7 +1571,7 @@ MODULE_DEVICE_TABLE(of, exynos5_dmc_of_match);
static struct platform_driver exynos5_dmc_platdrv = {
.probe = exynos5_dmc_probe,
- .remove_new = exynos5_dmc_remove,
+ .remove = exynos5_dmc_remove,
.driver = {
.name = "exynos5-dmc",
.of_match_table = exynos5_dmc_of_match,
diff --git a/drivers/memory/stm32-fmc2-ebi.c b/drivers/memory/stm32-fmc2-ebi.c
index 47d0ea5f1616..6e386ab54091 100644
--- a/drivers/memory/stm32-fmc2-ebi.c
+++ b/drivers/memory/stm32-fmc2-ebi.c
@@ -11,6 +11,7 @@
#include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>
@@ -20,8 +21,15 @@
#define FMC2_BCR(x) ((x) * 0x8 + FMC2_BCR1)
#define FMC2_BTR(x) ((x) * 0x8 + FMC2_BTR1)
#define FMC2_PCSCNTR 0x20
+#define FMC2_CFGR 0x20
+#define FMC2_SR 0x84
#define FMC2_BWTR1 0x104
#define FMC2_BWTR(x) ((x) * 0x8 + FMC2_BWTR1)
+#define FMC2_SECCFGR 0x300
+#define FMC2_CIDCFGR0 0x30c
+#define FMC2_CIDCFGR(x) ((x) * 0x8 + FMC2_CIDCFGR0)
+#define FMC2_SEMCR0 0x310
+#define FMC2_SEMCR(x) ((x) * 0x8 + FMC2_SEMCR0)
/* Register: FMC2_BCR1 */
#define FMC2_BCR1_CCLKEN BIT(20)
@@ -42,6 +50,7 @@
#define FMC2_BCR_ASYNCWAIT BIT(15)
#define FMC2_BCR_CPSIZE GENMASK(18, 16)
#define FMC2_BCR_CBURSTRW BIT(19)
+#define FMC2_BCR_CSCOUNT GENMASK(21, 20)
#define FMC2_BCR_NBLSET GENMASK(23, 22)
/* Register: FMC2_BTRx/FMC2_BWTRx */
@@ -58,8 +67,28 @@
#define FMC2_PCSCNTR_CSCOUNT GENMASK(15, 0)
#define FMC2_PCSCNTR_CNTBEN(x) BIT((x) + 16)
+/* Register: FMC2_CFGR */
+#define FMC2_CFGR_CLKDIV GENMASK(19, 16)
+#define FMC2_CFGR_CCLKEN BIT(20)
+#define FMC2_CFGR_FMC2EN BIT(31)
+
+/* Register: FMC2_SR */
+#define FMC2_SR_ISOST GENMASK(1, 0)
+
+/* Register: FMC2_CIDCFGR */
+#define FMC2_CIDCFGR_CFEN BIT(0)
+#define FMC2_CIDCFGR_SEMEN BIT(1)
+#define FMC2_CIDCFGR_SCID GENMASK(6, 4)
+#define FMC2_CIDCFGR_SEMWLC1 BIT(17)
+
+/* Register: FMC2_SEMCR */
+#define FMC2_SEMCR_SEM_MUTEX BIT(0)
+#define FMC2_SEMCR_SEMCID GENMASK(6, 4)
+
#define FMC2_MAX_EBI_CE 4
#define FMC2_MAX_BANKS 5
+#define FMC2_MAX_RESOURCES 6
+#define FMC2_CID1 1
#define FMC2_BCR_CPSIZE_0 0x0
#define FMC2_BCR_CPSIZE_128 0x1
@@ -74,6 +103,11 @@
#define FMC2_BCR_MTYP_PSRAM 0x1
#define FMC2_BCR_MTYP_NOR 0x2
+#define FMC2_BCR_CSCOUNT_0 0x0
+#define FMC2_BCR_CSCOUNT_1 0x1
+#define FMC2_BCR_CSCOUNT_64 0x2
+#define FMC2_BCR_CSCOUNT_256 0x3
+
#define FMC2_BXTR_EXTMOD_A 0x0
#define FMC2_BXTR_EXTMOD_B 0x1
#define FMC2_BXTR_EXTMOD_C 0x2
@@ -88,6 +122,7 @@
#define FMC2_BTR_CLKDIV_MAX 0xf
#define FMC2_BTR_DATLAT_MAX 0xf
#define FMC2_PCSCNTR_CSCOUNT_MAX 0xff
+#define FMC2_CFGR_CLKDIV_MAX 0xf
enum stm32_fmc2_ebi_bank {
FMC2_EBI1 = 0,
@@ -101,7 +136,8 @@ enum stm32_fmc2_ebi_register_type {
FMC2_REG_BCR = 1,
FMC2_REG_BTR,
FMC2_REG_BWTR,
- FMC2_REG_PCSCNTR
+ FMC2_REG_PCSCNTR,
+ FMC2_REG_CFGR
};
enum stm32_fmc2_ebi_transaction_type {
@@ -132,16 +168,42 @@ enum stm32_fmc2_ebi_cpsize {
FMC2_CPSIZE_1024 = 1024
};
+enum stm32_fmc2_ebi_cscount {
+ FMC2_CSCOUNT_0 = 0,
+ FMC2_CSCOUNT_1 = 1,
+ FMC2_CSCOUNT_64 = 64,
+ FMC2_CSCOUNT_256 = 256
+};
+
+struct stm32_fmc2_ebi;
+
+struct stm32_fmc2_ebi_data {
+ const struct stm32_fmc2_prop *child_props;
+ unsigned int nb_child_props;
+ u32 fmc2_enable_reg;
+ u32 fmc2_enable_bit;
+ int (*nwait_used_by_ctrls)(struct stm32_fmc2_ebi *ebi);
+ void (*set_setup)(struct stm32_fmc2_ebi *ebi);
+ int (*save_setup)(struct stm32_fmc2_ebi *ebi);
+ int (*check_rif)(struct stm32_fmc2_ebi *ebi, u32 resource);
+ void (*put_sems)(struct stm32_fmc2_ebi *ebi);
+ void (*get_sems)(struct stm32_fmc2_ebi *ebi);
+};
+
struct stm32_fmc2_ebi {
struct device *dev;
struct clk *clk;
struct regmap *regmap;
+ const struct stm32_fmc2_ebi_data *data;
u8 bank_assigned;
+ u8 sem_taken;
+ bool access_granted;
u32 bcr[FMC2_MAX_EBI_CE];
u32 btr[FMC2_MAX_EBI_CE];
u32 bwtr[FMC2_MAX_EBI_CE];
u32 pcscntr;
+ u32 cfgr;
};
/*
@@ -181,8 +243,11 @@ static int stm32_fmc2_ebi_check_mux(struct stm32_fmc2_ebi *ebi,
int cs)
{
u32 bcr;
+ int ret;
- regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ if (ret)
+ return ret;
if (bcr & FMC2_BCR_MTYP)
return 0;
@@ -195,8 +260,11 @@ static int stm32_fmc2_ebi_check_waitcfg(struct stm32_fmc2_ebi *ebi,
int cs)
{
u32 bcr, val = FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR);
+ int ret;
- regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ if (ret)
+ return ret;
if ((bcr & FMC2_BCR_MTYP) == val && bcr & FMC2_BCR_BURSTEN)
return 0;
@@ -209,8 +277,11 @@ static int stm32_fmc2_ebi_check_sync_trans(struct stm32_fmc2_ebi *ebi,
int cs)
{
u32 bcr;
+ int ret;
- regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ if (ret)
+ return ret;
if (bcr & FMC2_BCR_BURSTEN)
return 0;
@@ -218,13 +289,43 @@ static int stm32_fmc2_ebi_check_sync_trans(struct stm32_fmc2_ebi *ebi,
return -EINVAL;
}
+static int stm32_fmc2_ebi_mp25_check_cclk(struct stm32_fmc2_ebi *ebi,
+ const struct stm32_fmc2_prop *prop,
+ int cs)
+{
+ if (!ebi->access_granted)
+ return -EACCES;
+
+ return stm32_fmc2_ebi_check_sync_trans(ebi, prop, cs);
+}
+
+static int stm32_fmc2_ebi_mp25_check_clk_period(struct stm32_fmc2_ebi *ebi,
+ const struct stm32_fmc2_prop *prop,
+ int cs)
+{
+ u32 cfgr;
+ int ret;
+
+ ret = regmap_read(ebi->regmap, FMC2_CFGR, &cfgr);
+ if (ret)
+ return ret;
+
+ if (cfgr & FMC2_CFGR_CCLKEN && !ebi->access_granted)
+ return -EACCES;
+
+ return stm32_fmc2_ebi_check_sync_trans(ebi, prop, cs);
+}
+
static int stm32_fmc2_ebi_check_async_trans(struct stm32_fmc2_ebi *ebi,
const struct stm32_fmc2_prop *prop,
int cs)
{
u32 bcr;
+ int ret;
- regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ if (ret)
+ return ret;
if (!(bcr & FMC2_BCR_BURSTEN) || !(bcr & FMC2_BCR_CBURSTRW))
return 0;
@@ -237,8 +338,11 @@ static int stm32_fmc2_ebi_check_cpsize(struct stm32_fmc2_ebi *ebi,
int cs)
{
u32 bcr, val = FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_PSRAM);
+ int ret;
- regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ if (ret)
+ return ret;
if ((bcr & FMC2_BCR_MTYP) == val && bcr & FMC2_BCR_BURSTEN)
return 0;
@@ -251,12 +355,18 @@ static int stm32_fmc2_ebi_check_address_hold(struct stm32_fmc2_ebi *ebi,
int cs)
{
u32 bcr, bxtr, val = FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_D);
+ int ret;
+
+ ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ if (ret)
+ return ret;
- regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
if (prop->reg_type == FMC2_REG_BWTR)
- regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr);
+ ret = regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr);
else
- regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr);
+ ret = regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr);
+ if (ret)
+ return ret;
if ((!(bcr & FMC2_BCR_BURSTEN) || !(bcr & FMC2_BCR_CBURSTRW)) &&
((bxtr & FMC2_BXTR_ACCMOD) == val || bcr & FMC2_BCR_MUXEN))
@@ -270,12 +380,19 @@ static int stm32_fmc2_ebi_check_clk_period(struct stm32_fmc2_ebi *ebi,
int cs)
{
u32 bcr, bcr1;
+ int ret;
- regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
- if (cs)
- regmap_read(ebi->regmap, FMC2_BCR1, &bcr1);
- else
+ ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ if (ret)
+ return ret;
+
+ if (cs) {
+ ret = regmap_read(ebi->regmap, FMC2_BCR1, &bcr1);
+ if (ret)
+ return ret;
+ } else {
bcr1 = bcr;
+ }
if (bcr & FMC2_BCR_BURSTEN && (!cs || !(bcr1 & FMC2_BCR1_CCLKEN)))
return 0;
@@ -307,18 +424,48 @@ static u32 stm32_fmc2_ebi_ns_to_clk_period(struct stm32_fmc2_ebi *ebi,
{
u32 nb_clk_cycles = stm32_fmc2_ebi_ns_to_clock_cycles(ebi, cs, setup);
u32 bcr, btr, clk_period;
+ int ret;
+
+ ret = regmap_read(ebi->regmap, FMC2_BCR1, &bcr);
+ if (ret)
+ return ret;
- regmap_read(ebi->regmap, FMC2_BCR1, &bcr);
if (bcr & FMC2_BCR1_CCLKEN || !cs)
- regmap_read(ebi->regmap, FMC2_BTR1, &btr);
+ ret = regmap_read(ebi->regmap, FMC2_BTR1, &btr);
else
- regmap_read(ebi->regmap, FMC2_BTR(cs), &btr);
+ ret = regmap_read(ebi->regmap, FMC2_BTR(cs), &btr);
+ if (ret)
+ return ret;
clk_period = FIELD_GET(FMC2_BTR_CLKDIV, btr) + 1;
return DIV_ROUND_UP(nb_clk_cycles, clk_period);
}
+static u32 stm32_fmc2_ebi_mp25_ns_to_clk_period(struct stm32_fmc2_ebi *ebi,
+ int cs, u32 setup)
+{
+ u32 nb_clk_cycles = stm32_fmc2_ebi_ns_to_clock_cycles(ebi, cs, setup);
+ u32 cfgr, btr, clk_period;
+ int ret;
+
+ ret = regmap_read(ebi->regmap, FMC2_CFGR, &cfgr);
+ if (ret)
+ return ret;
+
+ if (cfgr & FMC2_CFGR_CCLKEN) {
+ clk_period = FIELD_GET(FMC2_CFGR_CLKDIV, cfgr) + 1;
+ } else {
+ ret = regmap_read(ebi->regmap, FMC2_BTR(cs), &btr);
+ if (ret)
+ return ret;
+
+ clk_period = FIELD_GET(FMC2_BTR_CLKDIV, btr) + 1;
+ }
+
+ return DIV_ROUND_UP(nb_clk_cycles, clk_period);
+}
+
static int stm32_fmc2_ebi_get_reg(int reg_type, int cs, u32 *reg)
{
switch (reg_type) {
@@ -334,6 +481,9 @@ static int stm32_fmc2_ebi_get_reg(int reg_type, int cs, u32 *reg)
case FMC2_REG_PCSCNTR:
*reg = FMC2_PCSCNTR;
break;
+ case FMC2_REG_CFGR:
+ *reg = FMC2_CFGR;
+ break;
default:
return -EINVAL;
}
@@ -571,11 +721,16 @@ static int stm32_fmc2_ebi_set_address_setup(struct stm32_fmc2_ebi *ebi,
if (ret)
return ret;
- regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ if (ret)
+ return ret;
+
if (prop->reg_type == FMC2_REG_BWTR)
- regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr);
+ ret = regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr);
else
- regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr);
+ ret = regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr);
+ if (ret)
+ return ret;
if ((bxtr & FMC2_BXTR_ACCMOD) == val || bcr & FMC2_BCR_MUXEN)
val = clamp_val(setup, 1, FMC2_BXTR_ADDSET_MAX);
@@ -675,6 +830,30 @@ static int stm32_fmc2_ebi_set_clk_period(struct stm32_fmc2_ebi *ebi,
return 0;
}
+static int stm32_fmc2_ebi_mp25_set_clk_period(struct stm32_fmc2_ebi *ebi,
+ const struct stm32_fmc2_prop *prop,
+ int cs, u32 setup)
+{
+ u32 val, cfgr;
+ int ret;
+
+ ret = regmap_read(ebi->regmap, FMC2_CFGR, &cfgr);
+ if (ret)
+ return ret;
+
+ if (cfgr & FMC2_CFGR_CCLKEN) {
+ val = setup ? clamp_val(setup - 1, 1, FMC2_CFGR_CLKDIV_MAX) : 1;
+ val = FIELD_PREP(FMC2_CFGR_CLKDIV, val);
+ regmap_update_bits(ebi->regmap, FMC2_CFGR, FMC2_CFGR_CLKDIV, val);
+ } else {
+ val = setup ? clamp_val(setup - 1, 1, FMC2_BTR_CLKDIV_MAX) : 1;
+ val = FIELD_PREP(FMC2_BTR_CLKDIV, val);
+ regmap_update_bits(ebi->regmap, FMC2_BTR(cs), FMC2_BTR_CLKDIV, val);
+ }
+
+ return 0;
+}
+
static int stm32_fmc2_ebi_set_data_latency(struct stm32_fmc2_ebi *ebi,
const struct stm32_fmc2_prop *prop,
int cs, u32 setup)
@@ -693,11 +872,14 @@ static int stm32_fmc2_ebi_set_max_low_pulse(struct stm32_fmc2_ebi *ebi,
int cs, u32 setup)
{
u32 old_val, new_val, pcscntr;
+ int ret;
if (setup < 1)
return 0;
- regmap_read(ebi->regmap, FMC2_PCSCNTR, &pcscntr);
+ ret = regmap_read(ebi->regmap, FMC2_PCSCNTR, &pcscntr);
+ if (ret)
+ return ret;
/* Enable counter for the bank */
regmap_update_bits(ebi->regmap, FMC2_PCSCNTR,
@@ -717,6 +899,27 @@ static int stm32_fmc2_ebi_set_max_low_pulse(struct stm32_fmc2_ebi *ebi,
return 0;
}
+static int stm32_fmc2_ebi_mp25_set_max_low_pulse(struct stm32_fmc2_ebi *ebi,
+ const struct stm32_fmc2_prop *prop,
+ int cs, u32 setup)
+{
+ u32 val;
+
+ if (setup == FMC2_CSCOUNT_0)
+ val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_0);
+ else if (setup == FMC2_CSCOUNT_1)
+ val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_1);
+ else if (setup <= FMC2_CSCOUNT_64)
+ val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_64);
+ else
+ val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_256);
+
+ regmap_update_bits(ebi->regmap, FMC2_BCR(cs),
+ FMC2_BCR_CSCOUNT, val);
+
+ return 0;
+}
+
static const struct stm32_fmc2_prop stm32_fmc2_child_props[] = {
/* st,fmc2-ebi-cs-trans-type must be the first property */
{
@@ -882,6 +1085,275 @@ static const struct stm32_fmc2_prop stm32_fmc2_child_props[] = {
},
};
+static const struct stm32_fmc2_prop stm32_fmc2_mp25_child_props[] = {
+ /* st,fmc2-ebi-cs-trans-type must be the first property */
+ {
+ .name = "st,fmc2-ebi-cs-transaction-type",
+ .mprop = true,
+ .set = stm32_fmc2_ebi_set_trans_type,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-cclk-enable",
+ .bprop = true,
+ .reg_type = FMC2_REG_CFGR,
+ .reg_mask = FMC2_CFGR_CCLKEN,
+ .check = stm32_fmc2_ebi_mp25_check_cclk,
+ .set = stm32_fmc2_ebi_set_bit_field,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-mux-enable",
+ .bprop = true,
+ .reg_type = FMC2_REG_BCR,
+ .reg_mask = FMC2_BCR_MUXEN,
+ .check = stm32_fmc2_ebi_check_mux,
+ .set = stm32_fmc2_ebi_set_bit_field,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-buswidth",
+ .reset_val = FMC2_BUSWIDTH_16,
+ .set = stm32_fmc2_ebi_set_buswidth,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-waitpol-high",
+ .bprop = true,
+ .reg_type = FMC2_REG_BCR,
+ .reg_mask = FMC2_BCR_WAITPOL,
+ .set = stm32_fmc2_ebi_set_bit_field,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-waitcfg-enable",
+ .bprop = true,
+ .reg_type = FMC2_REG_BCR,
+ .reg_mask = FMC2_BCR_WAITCFG,
+ .check = stm32_fmc2_ebi_check_waitcfg,
+ .set = stm32_fmc2_ebi_set_bit_field,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-wait-enable",
+ .bprop = true,
+ .reg_type = FMC2_REG_BCR,
+ .reg_mask = FMC2_BCR_WAITEN,
+ .check = stm32_fmc2_ebi_check_sync_trans,
+ .set = stm32_fmc2_ebi_set_bit_field,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-asyncwait-enable",
+ .bprop = true,
+ .reg_type = FMC2_REG_BCR,
+ .reg_mask = FMC2_BCR_ASYNCWAIT,
+ .check = stm32_fmc2_ebi_check_async_trans,
+ .set = stm32_fmc2_ebi_set_bit_field,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-cpsize",
+ .check = stm32_fmc2_ebi_check_cpsize,
+ .set = stm32_fmc2_ebi_set_cpsize,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-byte-lane-setup-ns",
+ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+ .set = stm32_fmc2_ebi_set_bl_setup,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-address-setup-ns",
+ .reg_type = FMC2_REG_BTR,
+ .reset_val = FMC2_BXTR_ADDSET_MAX,
+ .check = stm32_fmc2_ebi_check_async_trans,
+ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+ .set = stm32_fmc2_ebi_set_address_setup,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-address-hold-ns",
+ .reg_type = FMC2_REG_BTR,
+ .reset_val = FMC2_BXTR_ADDHLD_MAX,
+ .check = stm32_fmc2_ebi_check_address_hold,
+ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+ .set = stm32_fmc2_ebi_set_address_hold,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-data-setup-ns",
+ .reg_type = FMC2_REG_BTR,
+ .reset_val = FMC2_BXTR_DATAST_MAX,
+ .check = stm32_fmc2_ebi_check_async_trans,
+ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+ .set = stm32_fmc2_ebi_set_data_setup,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-bus-turnaround-ns",
+ .reg_type = FMC2_REG_BTR,
+ .reset_val = FMC2_BXTR_BUSTURN_MAX + 1,
+ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+ .set = stm32_fmc2_ebi_set_bus_turnaround,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-data-hold-ns",
+ .reg_type = FMC2_REG_BTR,
+ .check = stm32_fmc2_ebi_check_async_trans,
+ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+ .set = stm32_fmc2_ebi_set_data_hold,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-clk-period-ns",
+ .reset_val = FMC2_CFGR_CLKDIV_MAX + 1,
+ .check = stm32_fmc2_ebi_mp25_check_clk_period,
+ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+ .set = stm32_fmc2_ebi_mp25_set_clk_period,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-data-latency-ns",
+ .check = stm32_fmc2_ebi_check_sync_trans,
+ .calculate = stm32_fmc2_ebi_mp25_ns_to_clk_period,
+ .set = stm32_fmc2_ebi_set_data_latency,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-write-address-setup-ns",
+ .reg_type = FMC2_REG_BWTR,
+ .reset_val = FMC2_BXTR_ADDSET_MAX,
+ .check = stm32_fmc2_ebi_check_async_trans,
+ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+ .set = stm32_fmc2_ebi_set_address_setup,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-write-address-hold-ns",
+ .reg_type = FMC2_REG_BWTR,
+ .reset_val = FMC2_BXTR_ADDHLD_MAX,
+ .check = stm32_fmc2_ebi_check_address_hold,
+ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+ .set = stm32_fmc2_ebi_set_address_hold,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-write-data-setup-ns",
+ .reg_type = FMC2_REG_BWTR,
+ .reset_val = FMC2_BXTR_DATAST_MAX,
+ .check = stm32_fmc2_ebi_check_async_trans,
+ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+ .set = stm32_fmc2_ebi_set_data_setup,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-write-bus-turnaround-ns",
+ .reg_type = FMC2_REG_BWTR,
+ .reset_val = FMC2_BXTR_BUSTURN_MAX + 1,
+ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+ .set = stm32_fmc2_ebi_set_bus_turnaround,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-write-data-hold-ns",
+ .reg_type = FMC2_REG_BWTR,
+ .check = stm32_fmc2_ebi_check_async_trans,
+ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+ .set = stm32_fmc2_ebi_set_data_hold,
+ },
+ {
+ .name = "st,fmc2-ebi-cs-max-low-pulse-ns",
+ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+ .set = stm32_fmc2_ebi_mp25_set_max_low_pulse,
+ },
+};
+
+static int stm32_fmc2_ebi_mp25_check_rif(struct stm32_fmc2_ebi *ebi, u32 resource)
+{
+ u32 seccfgr, cidcfgr, semcr;
+ int cid, ret;
+
+ if (resource >= FMC2_MAX_RESOURCES)
+ return -EINVAL;
+
+ ret = regmap_read(ebi->regmap, FMC2_SECCFGR, &seccfgr);
+ if (ret)
+ return ret;
+
+ if (seccfgr & BIT(resource)) {
+ if (resource)
+ dev_err(ebi->dev, "resource %d is configured as secure\n",
+ resource);
+
+ return -EACCES;
+ }
+
+ ret = regmap_read(ebi->regmap, FMC2_CIDCFGR(resource), &cidcfgr);
+ if (ret)
+ return ret;
+
+ if (!(cidcfgr & FMC2_CIDCFGR_CFEN))
+ /* CID filtering is turned off: access granted */
+ return 0;
+
+ if (!(cidcfgr & FMC2_CIDCFGR_SEMEN)) {
+ /* Static CID mode */
+ cid = FIELD_GET(FMC2_CIDCFGR_SCID, cidcfgr);
+ if (cid != FMC2_CID1) {
+ if (resource)
+ dev_err(ebi->dev, "static CID%d set for resource %d\n",
+ cid, resource);
+
+ return -EACCES;
+ }
+
+ return 0;
+ }
+
+ /* Pass-list with semaphore mode */
+ if (!(cidcfgr & FMC2_CIDCFGR_SEMWLC1)) {
+ if (resource)
+ dev_err(ebi->dev, "CID1 is block-listed for resource %d\n",
+ resource);
+
+ return -EACCES;
+ }
+
+ ret = regmap_read(ebi->regmap, FMC2_SEMCR(resource), &semcr);
+ if (ret)
+ return ret;
+
+ if (!(semcr & FMC2_SEMCR_SEM_MUTEX)) {
+ regmap_update_bits(ebi->regmap, FMC2_SEMCR(resource),
+ FMC2_SEMCR_SEM_MUTEX, FMC2_SEMCR_SEM_MUTEX);
+
+ ret = regmap_read(ebi->regmap, FMC2_SEMCR(resource), &semcr);
+ if (ret)
+ return ret;
+ }
+
+ cid = FIELD_GET(FMC2_SEMCR_SEMCID, semcr);
+ if (cid != FMC2_CID1) {
+ if (resource)
+ dev_err(ebi->dev, "resource %d is already used by CID%d\n",
+ resource, cid);
+
+ return -EACCES;
+ }
+
+ ebi->sem_taken |= BIT(resource);
+
+ return 0;
+}
+
+static void stm32_fmc2_ebi_mp25_put_sems(struct stm32_fmc2_ebi *ebi)
+{
+ unsigned int resource;
+
+ for (resource = 0; resource < FMC2_MAX_RESOURCES; resource++) {
+ if (!(ebi->sem_taken & BIT(resource)))
+ continue;
+
+ regmap_update_bits(ebi->regmap, FMC2_SEMCR(resource),
+ FMC2_SEMCR_SEM_MUTEX, 0);
+ }
+}
+
+static void stm32_fmc2_ebi_mp25_get_sems(struct stm32_fmc2_ebi *ebi)
+{
+ unsigned int resource;
+
+ for (resource = 0; resource < FMC2_MAX_RESOURCES; resource++) {
+ if (!(ebi->sem_taken & BIT(resource)))
+ continue;
+
+ regmap_update_bits(ebi->regmap, FMC2_SEMCR(resource),
+ FMC2_SEMCR_SEM_MUTEX, FMC2_SEMCR_SEM_MUTEX);
+ }
+}
+
static int stm32_fmc2_ebi_parse_prop(struct stm32_fmc2_ebi *ebi,
struct device_node *dev_node,
const struct stm32_fmc2_prop *prop,
@@ -944,17 +1416,48 @@ static void stm32_fmc2_ebi_disable_bank(struct stm32_fmc2_ebi *ebi, int cs)
regmap_update_bits(ebi->regmap, FMC2_BCR(cs), FMC2_BCR_MBKEN, 0);
}
-static void stm32_fmc2_ebi_save_setup(struct stm32_fmc2_ebi *ebi)
+static int stm32_fmc2_ebi_save_setup(struct stm32_fmc2_ebi *ebi)
{
unsigned int cs;
+ int ret;
for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) {
- regmap_read(ebi->regmap, FMC2_BCR(cs), &ebi->bcr[cs]);
- regmap_read(ebi->regmap, FMC2_BTR(cs), &ebi->btr[cs]);
- regmap_read(ebi->regmap, FMC2_BWTR(cs), &ebi->bwtr[cs]);
+ if (!(ebi->bank_assigned & BIT(cs)))
+ continue;
+
+ ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &ebi->bcr[cs]);
+ ret |= regmap_read(ebi->regmap, FMC2_BTR(cs), &ebi->btr[cs]);
+ ret |= regmap_read(ebi->regmap, FMC2_BWTR(cs), &ebi->bwtr[cs]);
+ if (ret)
+ return ret;
}
- regmap_read(ebi->regmap, FMC2_PCSCNTR, &ebi->pcscntr);
+ return 0;
+}
+
+static int stm32_fmc2_ebi_mp1_save_setup(struct stm32_fmc2_ebi *ebi)
+{
+ int ret;
+
+ ret = stm32_fmc2_ebi_save_setup(ebi);
+ if (ret)
+ return ret;
+
+ return regmap_read(ebi->regmap, FMC2_PCSCNTR, &ebi->pcscntr);
+}
+
+static int stm32_fmc2_ebi_mp25_save_setup(struct stm32_fmc2_ebi *ebi)
+{
+ int ret;
+
+ ret = stm32_fmc2_ebi_save_setup(ebi);
+ if (ret)
+ return ret;
+
+ if (ebi->access_granted)
+ ret = regmap_read(ebi->regmap, FMC2_CFGR, &ebi->cfgr);
+
+ return ret;
}
static void stm32_fmc2_ebi_set_setup(struct stm32_fmc2_ebi *ebi)
@@ -962,14 +1465,29 @@ static void stm32_fmc2_ebi_set_setup(struct stm32_fmc2_ebi *ebi)
unsigned int cs;
for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) {
+ if (!(ebi->bank_assigned & BIT(cs)))
+ continue;
+
regmap_write(ebi->regmap, FMC2_BCR(cs), ebi->bcr[cs]);
regmap_write(ebi->regmap, FMC2_BTR(cs), ebi->btr[cs]);
regmap_write(ebi->regmap, FMC2_BWTR(cs), ebi->bwtr[cs]);
}
+}
+static void stm32_fmc2_ebi_mp1_set_setup(struct stm32_fmc2_ebi *ebi)
+{
+ stm32_fmc2_ebi_set_setup(ebi);
regmap_write(ebi->regmap, FMC2_PCSCNTR, ebi->pcscntr);
}
+static void stm32_fmc2_ebi_mp25_set_setup(struct stm32_fmc2_ebi *ebi)
+{
+ stm32_fmc2_ebi_set_setup(ebi);
+
+ if (ebi->access_granted)
+ regmap_write(ebi->regmap, FMC2_CFGR, ebi->cfgr);
+}
+
static void stm32_fmc2_ebi_disable_banks(struct stm32_fmc2_ebi *ebi)
{
unsigned int cs;
@@ -983,33 +1501,48 @@ static void stm32_fmc2_ebi_disable_banks(struct stm32_fmc2_ebi *ebi)
}
/* NWAIT signal can not be connected to EBI controller and NAND controller */
-static bool stm32_fmc2_ebi_nwait_used_by_ctrls(struct stm32_fmc2_ebi *ebi)
+static int stm32_fmc2_ebi_nwait_used_by_ctrls(struct stm32_fmc2_ebi *ebi)
{
+ struct device *dev = ebi->dev;
unsigned int cs;
u32 bcr;
+ int ret;
for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) {
if (!(ebi->bank_assigned & BIT(cs)))
continue;
- regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+ if (ret)
+ return ret;
+
if ((bcr & FMC2_BCR_WAITEN || bcr & FMC2_BCR_ASYNCWAIT) &&
- ebi->bank_assigned & BIT(FMC2_NAND))
- return true;
+ ebi->bank_assigned & BIT(FMC2_NAND)) {
+ dev_err(dev, "NWAIT signal connected to EBI and NAND controllers\n");
+ return -EINVAL;
+ }
}
- return false;
+ return 0;
}
static void stm32_fmc2_ebi_enable(struct stm32_fmc2_ebi *ebi)
{
- regmap_update_bits(ebi->regmap, FMC2_BCR1,
- FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN);
+ if (!ebi->access_granted)
+ return;
+
+ regmap_update_bits(ebi->regmap, ebi->data->fmc2_enable_reg,
+ ebi->data->fmc2_enable_bit,
+ ebi->data->fmc2_enable_bit);
}
static void stm32_fmc2_ebi_disable(struct stm32_fmc2_ebi *ebi)
{
- regmap_update_bits(ebi->regmap, FMC2_BCR1, FMC2_BCR1_FMC2EN, 0);
+ if (!ebi->access_granted)
+ return;
+
+ regmap_update_bits(ebi->regmap, ebi->data->fmc2_enable_reg,
+ ebi->data->fmc2_enable_bit, 0);
}
static int stm32_fmc2_ebi_setup_cs(struct stm32_fmc2_ebi *ebi,
@@ -1021,8 +1554,8 @@ static int stm32_fmc2_ebi_setup_cs(struct stm32_fmc2_ebi *ebi,
stm32_fmc2_ebi_disable_bank(ebi, cs);
- for (i = 0; i < ARRAY_SIZE(stm32_fmc2_child_props); i++) {
- const struct stm32_fmc2_prop *p = &stm32_fmc2_child_props[i];
+ for (i = 0; i < ebi->data->nb_child_props; i++) {
+ const struct stm32_fmc2_prop *p = &ebi->data->child_props[i];
ret = stm32_fmc2_ebi_parse_prop(ebi, dev_node, p, cs);
if (ret) {
@@ -1040,42 +1573,40 @@ static int stm32_fmc2_ebi_setup_cs(struct stm32_fmc2_ebi *ebi,
static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi)
{
struct device *dev = ebi->dev;
- struct device_node *child;
bool child_found = false;
u32 bank;
int ret;
- for_each_available_child_of_node(dev->of_node, child) {
+ for_each_available_child_of_node_scoped(dev->of_node, child) {
ret = of_property_read_u32(child, "reg", &bank);
- if (ret) {
- dev_err(dev, "could not retrieve reg property: %d\n",
- ret);
- of_node_put(child);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "could not retrieve reg property\n");
if (bank >= FMC2_MAX_BANKS) {
dev_err(dev, "invalid reg value: %d\n", bank);
- of_node_put(child);
return -EINVAL;
}
if (ebi->bank_assigned & BIT(bank)) {
dev_err(dev, "bank already assigned: %d\n", bank);
- of_node_put(child);
return -EINVAL;
}
- if (bank < FMC2_MAX_EBI_CE) {
- ret = stm32_fmc2_ebi_setup_cs(ebi, child, bank);
+ if (ebi->data->check_rif) {
+ ret = ebi->data->check_rif(ebi, bank + 1);
if (ret) {
- dev_err(dev, "setup chip select %d failed: %d\n",
- bank, ret);
- of_node_put(child);
+ dev_err(dev, "bank access failed: %d\n", bank);
return ret;
}
}
+ if (bank < FMC2_MAX_EBI_CE) {
+ ret = stm32_fmc2_ebi_setup_cs(ebi, child, bank);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "setup chip select %d failed\n", bank);
+ }
+
ebi->bank_assigned |= BIT(bank);
child_found = true;
}
@@ -1085,9 +1616,10 @@ static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi)
return -ENODEV;
}
- if (stm32_fmc2_ebi_nwait_used_by_ctrls(ebi)) {
- dev_err(dev, "NWAIT signal connected to EBI and NAND controllers\n");
- return -EINVAL;
+ if (ebi->data->nwait_used_by_ctrls) {
+ ret = ebi->data->nwait_used_by_ctrls(ebi);
+ if (ret)
+ return ret;
}
stm32_fmc2_ebi_enable(ebi);
@@ -1107,6 +1639,11 @@ static int stm32_fmc2_ebi_probe(struct platform_device *pdev)
return -ENOMEM;
ebi->dev = dev;
+ platform_set_drvdata(pdev, ebi);
+
+ ebi->data = of_device_get_match_data(dev);
+ if (!ebi->data)
+ return -EINVAL;
ebi->regmap = device_node_to_regmap(dev->of_node);
if (IS_ERR(ebi->regmap))
@@ -1120,28 +1657,57 @@ static int stm32_fmc2_ebi_probe(struct platform_device *pdev)
if (PTR_ERR(rstc) == -EPROBE_DEFER)
return -EPROBE_DEFER;
- ret = clk_prepare_enable(ebi->clk);
+ ret = devm_pm_runtime_enable(dev);
if (ret)
return ret;
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
if (!IS_ERR(rstc)) {
reset_control_assert(rstc);
reset_control_deassert(rstc);
}
+ /* Check if CFGR register can be modified */
+ ebi->access_granted = true;
+ if (ebi->data->check_rif) {
+ ret = ebi->data->check_rif(ebi, 0);
+ if (ret) {
+ u32 sr;
+
+ ebi->access_granted = false;
+
+ ret = regmap_read(ebi->regmap, FMC2_SR, &sr);
+ if (ret)
+ goto err_release;
+
+ /* In case of CFGR is secure, just check that the FMC2 is enabled */
+ if (sr & FMC2_SR_ISOST) {
+ dev_err(dev, "FMC2 is not ready to be used.\n");
+ ret = -EACCES;
+ goto err_release;
+ }
+ }
+ }
+
ret = stm32_fmc2_ebi_parse_dt(ebi);
if (ret)
goto err_release;
- stm32_fmc2_ebi_save_setup(ebi);
- platform_set_drvdata(pdev, ebi);
+ ret = ebi->data->save_setup(ebi);
+ if (ret)
+ goto err_release;
return 0;
err_release:
stm32_fmc2_ebi_disable_banks(ebi);
stm32_fmc2_ebi_disable(ebi);
- clk_disable_unprepare(ebi->clk);
+ if (ebi->data->put_sems)
+ ebi->data->put_sems(ebi);
+ pm_runtime_put_sync_suspend(dev);
return ret;
}
@@ -1153,7 +1719,25 @@ static void stm32_fmc2_ebi_remove(struct platform_device *pdev)
of_platform_depopulate(&pdev->dev);
stm32_fmc2_ebi_disable_banks(ebi);
stm32_fmc2_ebi_disable(ebi);
+ if (ebi->data->put_sems)
+ ebi->data->put_sems(ebi);
+ pm_runtime_put_sync_suspend(&pdev->dev);
+}
+
+static int __maybe_unused stm32_fmc2_ebi_runtime_suspend(struct device *dev)
+{
+ struct stm32_fmc2_ebi *ebi = dev_get_drvdata(dev);
+
clk_disable_unprepare(ebi->clk);
+
+ return 0;
+}
+
+static int __maybe_unused stm32_fmc2_ebi_runtime_resume(struct device *dev)
+{
+ struct stm32_fmc2_ebi *ebi = dev_get_drvdata(dev);
+
+ return clk_prepare_enable(ebi->clk);
}
static int __maybe_unused stm32_fmc2_ebi_suspend(struct device *dev)
@@ -1161,7 +1745,9 @@ static int __maybe_unused stm32_fmc2_ebi_suspend(struct device *dev)
struct stm32_fmc2_ebi *ebi = dev_get_drvdata(dev);
stm32_fmc2_ebi_disable(ebi);
- clk_disable_unprepare(ebi->clk);
+ if (ebi->data->put_sems)
+ ebi->data->put_sems(ebi);
+ pm_runtime_put_sync_suspend(dev);
pinctrl_pm_select_sleep_state(dev);
return 0;
@@ -1174,28 +1760,62 @@ static int __maybe_unused stm32_fmc2_ebi_resume(struct device *dev)
pinctrl_pm_select_default_state(dev);
- ret = clk_prepare_enable(ebi->clk);
- if (ret)
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
return ret;
- stm32_fmc2_ebi_set_setup(ebi);
+ if (ebi->data->get_sems)
+ ebi->data->get_sems(ebi);
+ ebi->data->set_setup(ebi);
stm32_fmc2_ebi_enable(ebi);
return 0;
}
-static SIMPLE_DEV_PM_OPS(stm32_fmc2_ebi_pm_ops, stm32_fmc2_ebi_suspend,
- stm32_fmc2_ebi_resume);
+static const struct dev_pm_ops stm32_fmc2_ebi_pm_ops = {
+ SET_RUNTIME_PM_OPS(stm32_fmc2_ebi_runtime_suspend,
+ stm32_fmc2_ebi_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(stm32_fmc2_ebi_suspend, stm32_fmc2_ebi_resume)
+};
+
+static const struct stm32_fmc2_ebi_data stm32_fmc2_ebi_mp1_data = {
+ .child_props = stm32_fmc2_child_props,
+ .nb_child_props = ARRAY_SIZE(stm32_fmc2_child_props),
+ .fmc2_enable_reg = FMC2_BCR1,
+ .fmc2_enable_bit = FMC2_BCR1_FMC2EN,
+ .nwait_used_by_ctrls = stm32_fmc2_ebi_nwait_used_by_ctrls,
+ .set_setup = stm32_fmc2_ebi_mp1_set_setup,
+ .save_setup = stm32_fmc2_ebi_mp1_save_setup,
+};
+
+static const struct stm32_fmc2_ebi_data stm32_fmc2_ebi_mp25_data = {
+ .child_props = stm32_fmc2_mp25_child_props,
+ .nb_child_props = ARRAY_SIZE(stm32_fmc2_mp25_child_props),
+ .fmc2_enable_reg = FMC2_CFGR,
+ .fmc2_enable_bit = FMC2_CFGR_FMC2EN,
+ .set_setup = stm32_fmc2_ebi_mp25_set_setup,
+ .save_setup = stm32_fmc2_ebi_mp25_save_setup,
+ .check_rif = stm32_fmc2_ebi_mp25_check_rif,
+ .put_sems = stm32_fmc2_ebi_mp25_put_sems,
+ .get_sems = stm32_fmc2_ebi_mp25_get_sems,
+};
static const struct of_device_id stm32_fmc2_ebi_match[] = {
- {.compatible = "st,stm32mp1-fmc2-ebi"},
+ {
+ .compatible = "st,stm32mp1-fmc2-ebi",
+ .data = &stm32_fmc2_ebi_mp1_data,
+ },
+ {
+ .compatible = "st,stm32mp25-fmc2-ebi",
+ .data = &stm32_fmc2_ebi_mp25_data,
+ },
{}
};
MODULE_DEVICE_TABLE(of, stm32_fmc2_ebi_match);
static struct platform_driver stm32_fmc2_ebi_driver = {
.probe = stm32_fmc2_ebi_probe,
- .remove_new = stm32_fmc2_ebi_remove,
+ .remove = stm32_fmc2_ebi_remove,
.driver = {
.name = "stm32_fmc2_ebi",
.of_match_table = stm32_fmc2_ebi_match,
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
index a083921a8968..bd5b58f1fd42 100644
--- a/drivers/memory/tegra/mc.c
+++ b/drivers/memory/tegra/mc.c
@@ -450,7 +450,6 @@ static int load_one_timing(struct tegra_mc *mc,
static int load_timings(struct tegra_mc *mc, struct device_node *node)
{
- struct device_node *child;
struct tegra_mc_timing *timing;
int child_count = of_get_child_count(node);
int i = 0, err;
@@ -462,14 +461,12 @@ static int load_timings(struct tegra_mc *mc, struct device_node *node)
mc->num_timings = child_count;
- for_each_child_of_node(node, child) {
+ for_each_child_of_node_scoped(node, child) {
timing = &mc->timings[i++];
err = load_one_timing(mc, timing, child);
- if (err) {
- of_node_put(child);
+ if (err)
return err;
- }
}
return 0;
@@ -477,7 +474,6 @@ static int load_timings(struct tegra_mc *mc, struct device_node *node)
static int tegra_mc_setup_timings(struct tegra_mc *mc)
{
- struct device_node *node;
u32 ram_code, node_ram_code;
int err;
@@ -485,14 +481,13 @@ static int tegra_mc_setup_timings(struct tegra_mc *mc)
mc->num_timings = 0;
- for_each_child_of_node(mc->dev->of_node, node) {
+ for_each_child_of_node_scoped(mc->dev->of_node, node) {
err = of_property_read_u32(node, "nvidia,ram-code",
&node_ram_code);
if (err || (node_ram_code != ram_code))
continue;
err = load_timings(mc, node);
- of_node_put(node);
if (err)
return err;
break;
@@ -755,7 +750,7 @@ const char *const tegra_mc_error_names[8] = {
[6] = "SMMU translation error",
};
-struct icc_node *tegra_mc_icc_xlate(struct of_phandle_args *spec, void *data)
+struct icc_node *tegra_mc_icc_xlate(const struct of_phandle_args *spec, void *data)
{
struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
struct icc_node *node;
diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c
index 00ed2b6a0d1b..03f1daa2d132 100644
--- a/drivers/memory/tegra/tegra124-emc.c
+++ b/drivers/memory/tegra/tegra124-emc.c
@@ -992,7 +992,6 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,
struct device_node *node)
{
int child_count = of_get_child_count(node);
- struct device_node *child;
struct emc_timing *timing;
unsigned int i = 0;
int err;
@@ -1004,14 +1003,12 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,
emc->num_timings = child_count;
- for_each_child_of_node(node, child) {
+ for_each_child_of_node_scoped(node, child) {
timing = &emc->timings[i++];
err = load_one_timing_from_dt(emc, timing, child);
- if (err) {
- of_node_put(child);
+ if (err)
return err;
- }
}
sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings,
@@ -1285,7 +1282,7 @@ to_tegra_emc_provider(struct icc_provider *provider)
}
static struct icc_node_data *
-emc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+emc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
{
struct icc_provider *provider = data;
struct icc_node_data *ndata;
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
index 470b7dbab2c2..9d7393e19f12 100644
--- a/drivers/memory/tegra/tegra124.c
+++ b/drivers/memory/tegra/tegra124.c
@@ -1170,7 +1170,7 @@ static int tegra124_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw,
}
static struct icc_node_data *
-tegra124_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+tegra124_mc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
{
struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
const struct tegra_mc_client *client;
diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c
index fcd4aea48bda..bc807d7fcd4e 100644
--- a/drivers/memory/tegra/tegra186-emc.c
+++ b/drivers/memory/tegra/tegra186-emc.c
@@ -35,11 +35,6 @@ struct tegra186_emc {
struct icc_provider provider;
};
-static inline struct tegra186_emc *to_tegra186_emc(struct icc_provider *provider)
-{
- return container_of(provider, struct tegra186_emc, provider);
-}
-
/*
* debugfs interface
*
@@ -236,7 +231,7 @@ static int tegra_emc_icc_set_bw(struct icc_node *src, struct icc_node *dst)
}
static struct icc_node *
-tegra_emc_of_icc_xlate(struct of_phandle_args *spec, void *data)
+tegra_emc_of_icc_xlate(const struct of_phandle_args *spec, void *data)
{
struct icc_provider *provider = data;
struct icc_node *node;
@@ -411,7 +406,7 @@ static struct platform_driver tegra186_emc_driver = {
.sync_state = icc_sync_state,
},
.probe = tegra186_emc_probe,
- .remove_new = tegra186_emc_remove,
+ .remove = tegra186_emc_remove,
};
module_platform_driver(tegra186_emc_driver);
diff --git a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegra20-emc.c
index fd595c851a27..9b7d30a21a5b 100644
--- a/drivers/memory/tegra/tegra20-emc.c
+++ b/drivers/memory/tegra/tegra20-emc.c
@@ -410,7 +410,6 @@ static int cmp_timings(const void *_a, const void *_b)
static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,
struct device_node *node)
{
- struct device_node *child;
struct emc_timing *timing;
int child_count;
int err;
@@ -428,15 +427,13 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,
timing = emc->timings;
- for_each_child_of_node(node, child) {
+ for_each_child_of_node_scoped(node, child) {
if (of_node_name_eq(child, "lpddr2"))
continue;
err = load_one_timing_from_dt(emc, timing++, child);
- if (err) {
- of_node_put(child);
+ if (err)
return err;
- }
emc->num_timings++;
}
@@ -477,14 +474,15 @@ tegra_emc_find_node_by_ram_code(struct tegra_emc *emc)
ram_code = tegra_read_ram_code();
- for (np = of_find_node_by_name(dev->of_node, "emc-tables"); np;
- np = of_find_node_by_name(np, "emc-tables")) {
+ for_each_child_of_node(dev->of_node, np) {
+ if (!of_node_name_eq(np, "emc-tables"))
+ continue;
err = of_property_read_u32(np, "nvidia,ram-code", &value);
if (err || value != ram_code) {
struct device_node *lpddr2_np;
bool cfg_mismatches = false;
- lpddr2_np = of_find_node_by_name(np, "lpddr2");
+ lpddr2_np = of_get_child_by_name(np, "lpddr2");
if (lpddr2_np) {
const struct lpddr2_info *info;
@@ -521,7 +519,6 @@ tegra_emc_find_node_by_ram_code(struct tegra_emc *emc)
}
if (cfg_mismatches) {
- of_node_put(np);
continue;
}
}
@@ -950,7 +947,7 @@ to_tegra_emc_provider(struct icc_provider *provider)
}
static struct icc_node_data *
-emc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+emc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
{
struct icc_provider *provider = data;
struct icc_node_data *ndata;
diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c
index aa4b97d5e732..a3022e715dee 100644
--- a/drivers/memory/tegra/tegra20.c
+++ b/drivers/memory/tegra/tegra20.c
@@ -390,7 +390,7 @@ static int tegra20_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw,
}
static struct icc_node_data *
-tegra20_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+tegra20_mc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
{
struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
unsigned int i, idx = spec->args[0];
diff --git a/drivers/memory/tegra/tegra210-emc-cc-r21021.c b/drivers/memory/tegra/tegra210-emc-cc-r21021.c
index 4cb608c71ead..a30a646ec468 100644
--- a/drivers/memory/tegra/tegra210-emc-cc-r21021.c
+++ b/drivers/memory/tegra/tegra210-emc-cc-r21021.c
@@ -75,29 +75,29 @@ enum {
* The division portion of the average operation.
*/
#define __AVERAGE_PTFV(dev) \
- ({ next->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] = \
- next->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] / \
+ ({ next->ptfv_list[(dev)] = \
+ next->ptfv_list[(dev)] / \
next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; })
/*
* Convert val to fixed point and add it to the temporary average.
*/
#define __INCREMENT_PTFV(dev, val) \
- ({ next->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] += \
+ ({ next->ptfv_list[(dev)] += \
((val) * MOVAVG_PRECISION_FACTOR); })
/*
* Convert a moving average back to integral form and return the value.
*/
#define __MOVAVG_AC(timing, dev) \
- ((timing)->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] / \
+ ((timing)->ptfv_list[(dev)] / \
MOVAVG_PRECISION_FACTOR)
/* Weighted update. */
#define __WEIGHTED_UPDATE_PTFV(dev, nval) \
do { \
int w = PTFV_MOVAVG_WEIGHT_INDEX; \
- int dqs = PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX; \
+ int dqs = (dev); \
\
next->ptfv_list[dqs] = \
((nval * MOVAVG_PRECISION_FACTOR) + \
@@ -105,315 +105,91 @@ enum {
next->ptfv_list[w])) / \
(next->ptfv_list[w] + 1); \
\
- emc_dbg(emc, EMA_UPDATES, "%s: (s=%lu) EMA: %u\n", \
+ emc_dbg(emc, EMA_UPDATES, "%s: (s=%u) EMA: %u\n", \
__stringify(dev), nval, next->ptfv_list[dqs]); \
} while (0)
/* Access a particular average. */
#define __MOVAVG(timing, dev) \
- ((timing)->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX])
+ ((timing)->ptfv_list[(dev)])
-static u32 update_clock_tree_delay(struct tegra210_emc *emc, int type)
+static bool tegra210_emc_compare_update_delay(struct tegra210_emc_timing *timing,
+ u32 measured, u32 idx)
{
- bool periodic_training_update = type == PERIODIC_TRAINING_UPDATE;
- struct tegra210_emc_timing *last = emc->last;
- struct tegra210_emc_timing *next = emc->next;
- u32 last_timing_rate_mhz = last->rate / 1000;
- u32 next_timing_rate_mhz = next->rate / 1000;
- bool dvfs_update = type == DVFS_UPDATE;
- s32 tdel = 0, tmdel = 0, adel = 0;
- bool dvfs_pt1 = type == DVFS_PT1;
- unsigned long cval = 0;
- u32 temp[2][2], value;
- unsigned int i;
-
- /*
- * Dev0 MSB.
- */
- if (dvfs_pt1 || periodic_training_update) {
- value = tegra210_emc_mrr_read(emc, 2, 19);
-
- for (i = 0; i < emc->num_channels; i++) {
- temp[i][0] = (value & 0x00ff) << 8;
- temp[i][1] = (value & 0xff00) << 0;
- value >>= 16;
- }
-
- /*
- * Dev0 LSB.
- */
- value = tegra210_emc_mrr_read(emc, 2, 18);
-
- for (i = 0; i < emc->num_channels; i++) {
- temp[i][0] |= (value & 0x00ff) >> 0;
- temp[i][1] |= (value & 0xff00) >> 8;
- value >>= 16;
- }
- }
-
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[0][0];
- }
+ u32 *curr = &timing->current_dram_clktree[idx];
+ u32 rate_mhz = timing->rate / 1000;
+ u32 tmdel;
- if (dvfs_pt1)
- __INCREMENT_PTFV(C0D0U0, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C0D0U0);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C0D0U0, cval);
-
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C0D0U0] -
- __MOVAVG_AC(next, C0D0U0);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
- adel = tmdel;
-
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C0D0U0] =
- __MOVAVG_AC(next, C0D0U0);
- }
+ tmdel = abs(*curr - measured);
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[0][1];
+ if (tmdel * 128 * rate_mhz / 1000000 > timing->tree_margin) {
+ *curr = measured;
+ return true;
}
- if (dvfs_pt1)
- __INCREMENT_PTFV(C0D0U1, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C0D0U1);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C0D0U1, cval);
-
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C0D0U1] -
- __MOVAVG_AC(next, C0D0U1);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
-
- if (tmdel > adel)
- adel = tmdel;
-
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C0D0U1] =
- __MOVAVG_AC(next, C0D0U1);
- }
-
- if (emc->num_channels > 1) {
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[1][0];
- }
-
- if (dvfs_pt1)
- __INCREMENT_PTFV(C1D0U0, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C1D0U0);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C1D0U0, cval);
-
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C1D0U0] -
- __MOVAVG_AC(next, C1D0U0);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
-
- if (tmdel > adel)
- adel = tmdel;
-
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C1D0U0] =
- __MOVAVG_AC(next, C1D0U0);
- }
-
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[1][1];
- }
-
- if (dvfs_pt1)
- __INCREMENT_PTFV(C1D0U1, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C1D0U1);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C1D0U1, cval);
-
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C1D0U1] -
- __MOVAVG_AC(next, C1D0U1);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
-
- if (tmdel > adel)
- adel = tmdel;
-
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C1D0U1] =
- __MOVAVG_AC(next, C1D0U1);
- }
- }
-
- if (emc->num_devices < 2)
- goto done;
-
- /*
- * Dev1 MSB.
- */
- if (dvfs_pt1 || periodic_training_update) {
- value = tegra210_emc_mrr_read(emc, 1, 19);
+ return false;
+}
- for (i = 0; i < emc->num_channels; i++) {
- temp[i][0] = (value & 0x00ff) << 8;
- temp[i][1] = (value & 0xff00) << 0;
- value >>= 16;
- }
+static void tegra210_emc_get_clktree_delay(struct tegra210_emc *emc,
+ u32 delay[DRAM_CLKTREE_NUM])
+{
+ struct tegra210_emc_timing *curr = emc->last;
+ u32 rate_mhz = curr->rate / 1000;
+ u32 msb, lsb, dqsosc, delay_us;
+ unsigned int c, d, idx;
+ unsigned long clocks;
- /*
- * Dev1 LSB.
- */
- value = tegra210_emc_mrr_read(emc, 1, 18);
+ clocks = tegra210_emc_actual_osc_clocks(curr->run_clocks);
+ delay_us = 2 + (clocks / rate_mhz);
- for (i = 0; i < emc->num_channels; i++) {
- temp[i][0] |= (value & 0x00ff) >> 0;
- temp[i][1] |= (value & 0xff00) >> 8;
- value >>= 16;
- }
- }
+ tegra210_emc_start_periodic_compensation(emc);
+ udelay(delay_us);
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[0][0];
- }
+ for (d = 0; d < emc->num_devices; d++) {
+ /* Read DQSOSC from MRR18/19 */
+ msb = tegra210_emc_mrr_read(emc, 2 - d, 19);
+ lsb = tegra210_emc_mrr_read(emc, 2 - d, 18);
- if (dvfs_pt1)
- __INCREMENT_PTFV(C0D1U0, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C0D1U0);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C0D1U0, cval);
-
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C0D1U0] -
- __MOVAVG_AC(next, C0D1U0);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
-
- if (tmdel > adel)
- adel = tmdel;
-
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C0D1U0] =
- __MOVAVG_AC(next, C0D1U0);
- }
+ for (c = 0; c < emc->num_channels; c++) {
+ /* C[c]D[d]U[0] */
+ idx = c * 4 + d * 2;
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[0][1];
- }
+ dqsosc = (msb & 0x00ff) << 8;
+ dqsosc |= (lsb & 0x00ff) >> 0;
- if (dvfs_pt1)
- __INCREMENT_PTFV(C0D1U1, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C0D1U1);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C0D1U1, cval);
-
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C0D1U1] -
- __MOVAVG_AC(next, C0D1U1);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
-
- if (tmdel > adel)
- adel = tmdel;
-
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C0D1U1] =
- __MOVAVG_AC(next, C0D1U1);
- }
+ /* Check for unpopulated channels */
+ if (dqsosc)
+ delay[idx] = (clocks * 1000000) /
+ (rate_mhz * 2 * dqsosc);
- if (emc->num_channels > 1) {
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[1][0];
- }
+ /* C[c]D[d]U[1] */
+ idx++;
- if (dvfs_pt1)
- __INCREMENT_PTFV(C1D1U0, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C1D1U0);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C1D1U0, cval);
-
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C1D1U0] -
- __MOVAVG_AC(next, C1D1U0);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
-
- if (tmdel > adel)
- adel = tmdel;
-
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C1D1U0] =
- __MOVAVG_AC(next, C1D1U0);
- }
+ dqsosc = (msb & 0xff00) << 0;
+ dqsosc |= (lsb & 0xff00) >> 8;
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[1][1];
- }
+ /* Check for unpopulated channels */
+ if (dqsosc)
+ delay[idx] = (clocks * 1000000) /
+ (rate_mhz * 2 * dqsosc);
- if (dvfs_pt1)
- __INCREMENT_PTFV(C1D1U1, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C1D1U1);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C1D1U1, cval);
-
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C1D1U1] -
- __MOVAVG_AC(next, C1D1U1);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
-
- if (tmdel > adel)
- adel = tmdel;
-
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C1D1U1] =
- __MOVAVG_AC(next, C1D1U1);
+ msb >>= 16;
+ lsb >>= 16;
}
}
-
-done:
- return adel;
}
-static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type,
- struct tegra210_emc_timing *last,
- struct tegra210_emc_timing *next)
+static bool periodic_compensation_handler(struct tegra210_emc *emc, u32 type,
+ struct tegra210_emc_timing *last,
+ struct tegra210_emc_timing *next)
{
#define __COPY_EMA(nt, lt, dev) \
({ __MOVAVG(nt, dev) = __MOVAVG(lt, dev) * \
(nt)->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; })
- u32 i, adel = 0, samples = next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX];
- u32 delay;
-
- delay = tegra210_emc_actual_osc_clocks(last->run_clocks);
- delay *= 1000;
- delay = 2 + (delay / last->rate);
+ u32 i, samples = next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX];
+ u32 delay[DRAM_CLKTREE_NUM], idx;
+ bool over = false;
if (!next->periodic_training)
return 0;
@@ -427,57 +203,46 @@ static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type,
* calibration then we can reuse the previous
* frequencies EMA data.
*/
- __COPY_EMA(next, last, C0D0U0);
- __COPY_EMA(next, last, C0D0U1);
- __COPY_EMA(next, last, C1D0U0);
- __COPY_EMA(next, last, C1D0U1);
- __COPY_EMA(next, last, C0D1U0);
- __COPY_EMA(next, last, C0D1U1);
- __COPY_EMA(next, last, C1D1U0);
- __COPY_EMA(next, last, C1D1U1);
+ for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++)
+ __COPY_EMA(next, last, idx);
} else {
/* Reset the EMA.*/
- __MOVAVG(next, C0D0U0) = 0;
- __MOVAVG(next, C0D0U1) = 0;
- __MOVAVG(next, C1D0U0) = 0;
- __MOVAVG(next, C1D0U1) = 0;
- __MOVAVG(next, C0D1U0) = 0;
- __MOVAVG(next, C0D1U1) = 0;
- __MOVAVG(next, C1D1U0) = 0;
- __MOVAVG(next, C1D1U1) = 0;
+ for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++)
+ __MOVAVG(next, idx) = 0;
for (i = 0; i < samples; i++) {
- tegra210_emc_start_periodic_compensation(emc);
- udelay(delay);
+ /* Generate next sample of data. */
+ tegra210_emc_get_clktree_delay(emc, delay);
- /*
- * Generate next sample of data.
- */
- adel = update_clock_tree_delay(emc, DVFS_PT1);
+ for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++)
+ __INCREMENT_PTFV(idx, delay[idx]);
}
}
- /*
- * Seems like it should be part of the
- * 'if (last_timing->periodic_training)' conditional
- * since is already done for the else clause.
- */
- adel = update_clock_tree_delay(emc, DVFS_UPDATE);
+ for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++) {
+ /* Do the division part of the moving average */
+ __AVERAGE_PTFV(idx);
+ over |= tegra210_emc_compare_update_delay(next,
+ __MOVAVG_AC(next, idx), idx);
+ }
}
if (type == PERIODIC_TRAINING_SEQUENCE) {
- tegra210_emc_start_periodic_compensation(emc);
- udelay(delay);
+ tegra210_emc_get_clktree_delay(emc, delay);
- adel = update_clock_tree_delay(emc, PERIODIC_TRAINING_UPDATE);
+ for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++) {
+ __WEIGHTED_UPDATE_PTFV(idx, delay[idx]);
+ over |= tegra210_emc_compare_update_delay(next,
+ __MOVAVG_AC(next, idx), idx);
+ }
}
- return adel;
+ return over;
}
static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc)
{
- u32 emc_cfg, emc_cfg_o, emc_cfg_update, del, value;
+ u32 emc_cfg, emc_cfg_o, emc_cfg_update, value;
static const u32 list[] = {
EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0,
EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1,
@@ -492,7 +257,6 @@ static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc)
};
struct tegra210_emc_timing *last = emc->last;
unsigned int items = ARRAY_SIZE(list), i;
- unsigned long delay;
if (last->periodic_training) {
emc_dbg(emc, PER_TRAIN, "Periodic training starting\n");
@@ -530,30 +294,18 @@ static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc)
/*
* 2. osc kick off - this assumes training and dvfs have set
* correct MR23.
- */
- tegra210_emc_start_periodic_compensation(emc);
-
- /*
+ *
* 3. Let dram capture its clock tree delays.
- */
- delay = tegra210_emc_actual_osc_clocks(last->run_clocks);
- delay *= 1000;
- delay /= last->rate + 1;
- udelay(delay);
-
- /*
+ *
* 4. Check delta wrt previous values (save value if margin
* exceeds what is set in table).
*/
- del = periodic_compensation_handler(emc,
- PERIODIC_TRAINING_SEQUENCE,
- last, last);
-
+ if (periodic_compensation_handler(emc, PERIODIC_TRAINING_SEQUENCE,
+ last, last)) {
/*
* 5. Apply compensation w.r.t. trained values (if clock tree
* has drifted more than the set margin).
*/
- if (last->tree_margin < ((del * 128 * (last->rate / 1000)) / 1000000)) {
for (i = 0; i < items; i++) {
value = tegra210_emc_compensate(last, list[i]);
emc_dbg(emc, EMA_WRITES, "0x%08x <= 0x%08x\n",
@@ -734,16 +486,7 @@ static void tegra210_emc_r21021_set_clock(struct tegra210_emc *emc, u32 clksrc)
EMC_EMC_STATUS_DRAM_IN_SELF_REFRESH_MASK,
0);
- tegra210_emc_start_periodic_compensation(emc);
-
- delay = 1000 * tegra210_emc_actual_osc_clocks(last->run_clocks);
- udelay((delay / last->rate) + 2);
-
- value = periodic_compensation_handler(emc, DVFS_SEQUENCE, fake,
- next);
- value = (value * 128 * next->rate / 1000) / 1000000;
-
- if (next->periodic_training && value > next->tree_margin)
+ if (periodic_compensation_handler(emc, DVFS_SEQUENCE, fake, next))
compensate_trimmer_applicable = true;
}
diff --git a/drivers/memory/tegra/tegra210-emc-core.c b/drivers/memory/tegra/tegra210-emc-core.c
index 78ca1d6c0977..2d5d8245a1d3 100644
--- a/drivers/memory/tegra/tegra210-emc-core.c
+++ b/drivers/memory/tegra/tegra210-emc-core.c
@@ -2051,7 +2051,7 @@ static struct platform_driver tegra210_emc_driver = {
.pm = &tegra210_emc_pm_ops,
},
.probe = tegra210_emc_probe,
- .remove_new = tegra210_emc_remove,
+ .remove = tegra210_emc_remove,
};
module_platform_driver(tegra210_emc_driver);
diff --git a/drivers/memory/tegra/tegra234.c b/drivers/memory/tegra/tegra234.c
index abff87f917cb..5f57cea48b62 100644
--- a/drivers/memory/tegra/tegra234.c
+++ b/drivers/memory/tegra/tegra234.c
@@ -92,6 +92,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0RDB,
.name = "dla0rdb",
+ .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+ .type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@@ -102,6 +104,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0RDB1,
.name = "dla0rdb1",
+ .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+ .type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@@ -112,6 +116,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0WRB,
.name = "dla0wrb",
+ .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+ .type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@@ -121,7 +127,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1RDB,
- .name = "dla0rdb",
+ .name = "dla1rdb",
+ .bpmp_id = TEGRA_ICC_BPMP_DLA_1,
+ .type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
@@ -407,7 +415,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1RDB1,
- .name = "dla0rdb1",
+ .name = "dla1rdb1",
+ .bpmp_id = TEGRA_ICC_BPMP_DLA_1,
+ .type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
@@ -417,7 +427,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1WRB,
- .name = "dla0wrb",
+ .name = "dla1wrb",
+ .bpmp_id = TEGRA_ICC_BPMP_DLA_1,
+ .type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
@@ -539,7 +551,7 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
.bpmp_id = TEGRA_ICC_BPMP_NVJPG_0,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVJPG,
- .regs = {
+ .regs = {
.sid = {
.override = 0x3f8,
.security = 0x3fc,
@@ -660,6 +672,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0RDA,
.name = "dla0rda",
+ .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+ .type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@@ -670,6 +684,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0FALRDB,
.name = "dla0falrdb",
+ .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+ .type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@@ -680,6 +696,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0WRA,
.name = "dla0wra",
+ .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+ .type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@@ -690,6 +708,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0FALWRB,
.name = "dla0falwrb",
+ .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+ .type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@@ -699,7 +719,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1RDA,
- .name = "dla0rda",
+ .name = "dla1rda",
+ .bpmp_id = TEGRA_ICC_BPMP_DLA_1,
+ .type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
@@ -709,7 +731,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1FALRDB,
- .name = "dla0falrdb",
+ .name = "dla1falrdb",
+ .bpmp_id = TEGRA_ICC_BPMP_DLA_1,
+ .type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
@@ -719,7 +743,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1WRA,
- .name = "dla0wra",
+ .name = "dla1wra",
+ .bpmp_id = TEGRA_ICC_BPMP_DLA_1,
+ .type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
@@ -729,7 +755,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1FALWRB,
- .name = "dla0falwrb",
+ .name = "dla1falwrb",
+ .bpmp_id = TEGRA_ICC_BPMP_DLA_1,
+ .type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
@@ -908,6 +936,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0RDA1,
.name = "dla0rda1",
+ .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+ .type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@@ -917,7 +947,7 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1RDA1,
- .name = "dla0rda1",
+ .name = "dla1rda1",
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c
index 9eae25c57ec6..921dce1b8bc6 100644
--- a/drivers/memory/tegra/tegra30-emc.c
+++ b/drivers/memory/tegra/tegra30-emc.c
@@ -979,7 +979,6 @@ static int emc_check_mc_timings(struct tegra_emc *emc)
static int emc_load_timings_from_dt(struct tegra_emc *emc,
struct device_node *node)
{
- struct device_node *child;
struct emc_timing *timing;
int child_count;
int err;
@@ -998,12 +997,10 @@ static int emc_load_timings_from_dt(struct tegra_emc *emc,
emc->num_timings = child_count;
timing = emc->timings;
- for_each_child_of_node(node, child) {
+ for_each_child_of_node_scoped(node, child) {
err = load_one_timing_from_dt(emc, timing++, child);
- if (err) {
- of_node_put(child);
+ if (err)
return err;
- }
}
sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings,
@@ -1468,7 +1465,7 @@ to_tegra_emc_provider(struct icc_provider *provider)
}
static struct icc_node_data *
-emc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+emc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
{
struct icc_provider *provider = data;
struct icc_node_data *ndata;
diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
index 06f8b35e0a14..d3e685c8431f 100644
--- a/drivers/memory/tegra/tegra30.c
+++ b/drivers/memory/tegra/tegra30.c
@@ -1332,7 +1332,7 @@ static int tegra30_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw,
}
static struct icc_node_data *
-tegra30_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+tegra30_mc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
{
struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
const struct tegra_mc_client *client;
diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c
index e192db9e0e4b..c8b83c9edbd5 100644
--- a/drivers/memory/ti-aemif.c
+++ b/drivers/memory/ti-aemif.c
@@ -13,11 +13,12 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/memory/ti-aemif.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
-#include <linux/platform_data/ti-aemif.h>
#define TA_SHIFT 2
#define RHOLD_SHIFT 4
@@ -70,39 +71,27 @@
#define ACR_SSTROBE_MASK BIT(31)
#define ASIZE_16BIT 1
-#define CONFIG_MASK (TA(TA_MAX) | \
- RHOLD(RHOLD_MAX) | \
- RSTROBE(RSTROBE_MAX) | \
- RSETUP(RSETUP_MAX) | \
- WHOLD(WHOLD_MAX) | \
- WSTROBE(WSTROBE_MAX) | \
- WSETUP(WSETUP_MAX) | \
- EW(EW_MAX) | SSTROBE(SSTROBE_MAX) | \
- ASIZE_MAX)
+#define TIMINGS_MASK (TA(TA_MAX) | \
+ RHOLD(RHOLD_MAX) | \
+ RSTROBE(RSTROBE_MAX) | \
+ RSETUP(RSETUP_MAX) | \
+ WHOLD(WHOLD_MAX) | \
+ WSTROBE(WSTROBE_MAX) | \
+ WSETUP(WSETUP_MAX))
+
+#define CONFIG_MASK (EW(EW_MAX) | SSTROBE(SSTROBE_MAX) | ASIZE_MAX)
/**
- * struct aemif_cs_data: structure to hold cs parameters
+ * struct aemif_cs_data: structure to hold CS parameters
+ * @timings: timings configuration
* @cs: chip-select number
- * @wstrobe: write strobe width, ns
- * @rstrobe: read strobe width, ns
- * @wsetup: write setup width, ns
- * @whold: write hold width, ns
- * @rsetup: read setup width, ns
- * @rhold: read hold width, ns
- * @ta: minimum turn around time, ns
* @enable_ss: enable/disable select strobe mode
* @enable_ew: enable/disable extended wait mode
* @asize: width of the asynchronous device's data bus
*/
struct aemif_cs_data {
+ struct aemif_cs_timings timings;
u8 cs;
- u16 wstrobe;
- u16 rstrobe;
- u8 wsetup;
- u8 whold;
- u8 rsetup;
- u8 rhold;
- u8 ta;
u8 enable_ss;
u8 enable_ew;
u8 asize;
@@ -116,6 +105,7 @@ struct aemif_cs_data {
* @num_cs: number of assigned chip-selects
* @cs_offset: start number of cs nodes
* @cs_data: array of chip-select settings
+ * @config_cs_lock: lock used to access CS configuration
*/
struct aemif_device {
void __iomem *base;
@@ -124,20 +114,94 @@ struct aemif_device {
u8 num_cs;
int cs_offset;
struct aemif_cs_data cs_data[NUM_CS];
+ struct mutex config_cs_lock;
};
/**
+ * aemif_check_cs_timings() - Check the validity of a CS timing configuration.
+ * @timings: timings configuration
+ *
+ * @return: 0 if the timing configuration is valid, negative error number otherwise.
+ */
+int aemif_check_cs_timings(struct aemif_cs_timings *timings)
+{
+ if (timings->ta > TA_MAX)
+ return -EINVAL;
+
+ if (timings->rhold > RHOLD_MAX)
+ return -EINVAL;
+
+ if (timings->rstrobe > RSTROBE_MAX)
+ return -EINVAL;
+
+ if (timings->rsetup > RSETUP_MAX)
+ return -EINVAL;
+
+ if (timings->whold > WHOLD_MAX)
+ return -EINVAL;
+
+ if (timings->wstrobe > WSTROBE_MAX)
+ return -EINVAL;
+
+ if (timings->wsetup > WSETUP_MAX)
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aemif_check_cs_timings);
+
+/**
+ * aemif_set_cs_timings() - Set the timing configuration of a given chip select.
+ * @aemif: aemif device to configure
+ * @cs: index of the chip select to configure
+ * @timings: timings configuration to set
+ *
+ * @return: 0 on success, else negative errno.
+ */
+int aemif_set_cs_timings(struct aemif_device *aemif, u8 cs,
+ struct aemif_cs_timings *timings)
+{
+ unsigned int offset;
+ u32 val, set;
+ int ret;
+
+ if (!timings || !aemif)
+ return -EINVAL;
+
+ if (cs > aemif->num_cs)
+ return -EINVAL;
+
+ ret = aemif_check_cs_timings(timings);
+ if (ret)
+ return ret;
+
+ set = TA(timings->ta) | RHOLD(timings->rhold) | RSTROBE(timings->rstrobe) |
+ RSETUP(timings->rsetup) | WHOLD(timings->whold) |
+ WSTROBE(timings->wstrobe) | WSETUP(timings->wsetup);
+
+ offset = A1CR_OFFSET + cs * 4;
+
+ mutex_lock(&aemif->config_cs_lock);
+ val = readl(aemif->base + offset);
+ val &= ~TIMINGS_MASK;
+ val |= set;
+ writel(val, aemif->base + offset);
+ mutex_unlock(&aemif->config_cs_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aemif_set_cs_timings);
+
+/**
* aemif_calc_rate - calculate timing data.
* @pdev: platform device to calculate for
* @wanted: The cycle time needed in nanoseconds.
* @clk: The input clock rate in kHz.
- * @max: The maximum divider value that can be programmed.
*
- * On success, returns the calculated timing value minus 1 for easy
- * programming into AEMIF timing registers, else negative errno.
+ * @return: the calculated timing value minus 1 for easy
+ * programming into AEMIF timing registers.
*/
-static int aemif_calc_rate(struct platform_device *pdev, int wanted,
- unsigned long clk, int max)
+static u32 aemif_calc_rate(struct platform_device *pdev, int wanted, unsigned long clk)
{
int result;
@@ -150,10 +214,6 @@ static int aemif_calc_rate(struct platform_device *pdev, int wanted,
if (result < 0)
result = 0;
- /* ... But configuring tighter timings is not an option. */
- else if (result > max)
- result = -EINVAL;
-
return result;
}
@@ -175,48 +235,25 @@ static int aemif_config_abus(struct platform_device *pdev, int csnum)
{
struct aemif_device *aemif = platform_get_drvdata(pdev);
struct aemif_cs_data *data = &aemif->cs_data[csnum];
- int ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
- unsigned long clk_rate = aemif->clk_rate;
unsigned offset;
u32 set, val;
offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
- ta = aemif_calc_rate(pdev, data->ta, clk_rate, TA_MAX);
- rhold = aemif_calc_rate(pdev, data->rhold, clk_rate, RHOLD_MAX);
- rstrobe = aemif_calc_rate(pdev, data->rstrobe, clk_rate, RSTROBE_MAX);
- rsetup = aemif_calc_rate(pdev, data->rsetup, clk_rate, RSETUP_MAX);
- whold = aemif_calc_rate(pdev, data->whold, clk_rate, WHOLD_MAX);
- wstrobe = aemif_calc_rate(pdev, data->wstrobe, clk_rate, WSTROBE_MAX);
- wsetup = aemif_calc_rate(pdev, data->wsetup, clk_rate, WSETUP_MAX);
-
- if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
- whold < 0 || wstrobe < 0 || wsetup < 0) {
- dev_err(&pdev->dev, "%s: cannot get suitable timings\n",
- __func__);
- return -EINVAL;
- }
-
- set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
- WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
-
- set |= (data->asize & ACR_ASIZE_MASK);
+ set = (data->asize & ACR_ASIZE_MASK);
if (data->enable_ew)
set |= ACR_EW_MASK;
if (data->enable_ss)
set |= ACR_SSTROBE_MASK;
+ mutex_lock(&aemif->config_cs_lock);
val = readl(aemif->base + offset);
val &= ~CONFIG_MASK;
val |= set;
writel(val, aemif->base + offset);
+ mutex_unlock(&aemif->config_cs_lock);
- return 0;
-}
-
-static inline int aemif_cycles_to_nsec(int val, unsigned long clk_rate)
-{
- return ((val + 1) * NSEC_PER_MSEC) / clk_rate;
+ return aemif_set_cs_timings(aemif, data->cs - aemif->cs_offset, &data->timings);
}
/**
@@ -232,19 +269,18 @@ static void aemif_get_hw_params(struct platform_device *pdev, int csnum)
{
struct aemif_device *aemif = platform_get_drvdata(pdev);
struct aemif_cs_data *data = &aemif->cs_data[csnum];
- unsigned long clk_rate = aemif->clk_rate;
u32 val, offset;
offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
val = readl(aemif->base + offset);
- data->ta = aemif_cycles_to_nsec(TA_VAL(val), clk_rate);
- data->rhold = aemif_cycles_to_nsec(RHOLD_VAL(val), clk_rate);
- data->rstrobe = aemif_cycles_to_nsec(RSTROBE_VAL(val), clk_rate);
- data->rsetup = aemif_cycles_to_nsec(RSETUP_VAL(val), clk_rate);
- data->whold = aemif_cycles_to_nsec(WHOLD_VAL(val), clk_rate);
- data->wstrobe = aemif_cycles_to_nsec(WSTROBE_VAL(val), clk_rate);
- data->wsetup = aemif_cycles_to_nsec(WSETUP_VAL(val), clk_rate);
+ data->timings.ta = TA_VAL(val);
+ data->timings.rhold = RHOLD_VAL(val);
+ data->timings.rstrobe = RSTROBE_VAL(val);
+ data->timings.rsetup = RSETUP_VAL(val);
+ data->timings.whold = WHOLD_VAL(val);
+ data->timings.wstrobe = WSTROBE_VAL(val);
+ data->timings.wsetup = WSETUP_VAL(val);
data->enable_ew = EW_VAL(val);
data->enable_ss = SSTROBE_VAL(val);
data->asize = val & ASIZE_MAX;
@@ -262,6 +298,7 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
struct device_node *np)
{
struct aemif_device *aemif = platform_get_drvdata(pdev);
+ unsigned long clk_rate = aemif->clk_rate;
struct aemif_cs_data *data;
u32 cs;
u32 val;
@@ -289,32 +326,33 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
/* override the values from device node */
if (!of_property_read_u32(np, "ti,cs-min-turnaround-ns", &val))
- data->ta = val;
+ data->timings.ta = aemif_calc_rate(pdev, val, clk_rate);
if (!of_property_read_u32(np, "ti,cs-read-hold-ns", &val))
- data->rhold = val;
+ data->timings.rhold = aemif_calc_rate(pdev, val, clk_rate);
if (!of_property_read_u32(np, "ti,cs-read-strobe-ns", &val))
- data->rstrobe = val;
+ data->timings.rstrobe = aemif_calc_rate(pdev, val, clk_rate);
if (!of_property_read_u32(np, "ti,cs-read-setup-ns", &val))
- data->rsetup = val;
+ data->timings.rsetup = aemif_calc_rate(pdev, val, clk_rate);
if (!of_property_read_u32(np, "ti,cs-write-hold-ns", &val))
- data->whold = val;
+ data->timings.whold = aemif_calc_rate(pdev, val, clk_rate);
if (!of_property_read_u32(np, "ti,cs-write-strobe-ns", &val))
- data->wstrobe = val;
+ data->timings.wstrobe = aemif_calc_rate(pdev, val, clk_rate);
if (!of_property_read_u32(np, "ti,cs-write-setup-ns", &val))
- data->wsetup = val;
+ data->timings.wsetup = aemif_calc_rate(pdev, val, clk_rate);
if (!of_property_read_u32(np, "ti,cs-bus-width", &val))
if (val == 16)
data->asize = 1;
data->enable_ew = of_property_read_bool(np, "ti,cs-extended-wait-mode");
data->enable_ss = of_property_read_bool(np, "ti,cs-select-strobe-mode");
- return 0;
+
+ return aemif_check_cs_timings(&data->timings);
}
static const struct of_device_id aemif_of_match[] = {
@@ -330,43 +368,29 @@ static int aemif_probe(struct platform_device *pdev)
int ret = -ENODEV;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
- struct device_node *child_np;
struct aemif_device *aemif;
- struct aemif_platform_data *pdata;
- struct of_dev_auxdata *dev_lookup;
aemif = devm_kzalloc(dev, sizeof(*aemif), GFP_KERNEL);
if (!aemif)
return -ENOMEM;
- pdata = dev_get_platdata(&pdev->dev);
- dev_lookup = pdata ? pdata->dev_lookup : NULL;
-
platform_set_drvdata(pdev, aemif);
- aemif->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(aemif->clk)) {
- dev_err(dev, "cannot get clock 'aemif'\n");
- return PTR_ERR(aemif->clk);
- }
-
- ret = clk_prepare_enable(aemif->clk);
- if (ret)
- return ret;
+ aemif->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(aemif->clk))
+ return dev_err_probe(dev, PTR_ERR(aemif->clk),
+ "cannot get clock 'aemif'\n");
aemif->clk_rate = clk_get_rate(aemif->clk) / MSEC_PER_SEC;
if (np && of_device_is_compatible(np, "ti,da850-aemif"))
aemif->cs_offset = 2;
- else if (pdata)
- aemif->cs_offset = pdata->cs_offset;
aemif->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(aemif->base)) {
- ret = PTR_ERR(aemif->base);
- goto error;
- }
+ if (IS_ERR(aemif->base))
+ return PTR_ERR(aemif->base);
+ mutex_init(&aemif->config_cs_lock);
if (np) {
/*
* For every controller device node, there is a cs device node
@@ -374,17 +398,10 @@ static int aemif_probe(struct platform_device *pdev)
* functions iterate over these nodes and update the cs data
* array.
*/
- for_each_available_child_of_node(np, child_np) {
+ for_each_available_child_of_node_scoped(np, child_np) {
ret = of_aemif_parse_abus_config(pdev, child_np);
- if (ret < 0) {
- of_node_put(child_np);
- goto error;
- }
- }
- } else if (pdata && pdata->num_abus_data > 0) {
- for (i = 0; i < pdata->num_abus_data; i++, aemif->num_cs++) {
- aemif->cs_data[i].cs = pdata->abus_data[i].cs;
- aemif_get_hw_params(pdev, i);
+ if (ret < 0)
+ return ret;
}
}
@@ -393,7 +410,7 @@ static int aemif_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(dev, "Error configuring chip select %d\n",
aemif->cs_data[i].cs);
- goto error;
+ return ret;
}
}
@@ -402,41 +419,18 @@ static int aemif_probe(struct platform_device *pdev)
* child will be probed after the AEMIF timing parameters are set.
*/
if (np) {
- for_each_available_child_of_node(np, child_np) {
- ret = of_platform_populate(child_np, NULL,
- dev_lookup, dev);
- if (ret < 0) {
- of_node_put(child_np);
- goto error;
- }
- }
- } else if (pdata) {
- for (i = 0; i < pdata->num_sub_devices; i++) {
- pdata->sub_devices[i].dev.parent = dev;
- ret = platform_device_register(&pdata->sub_devices[i]);
- if (ret) {
- dev_warn(dev, "Error register sub device %s\n",
- pdata->sub_devices[i].name);
- }
+ for_each_available_child_of_node_scoped(np, child_np) {
+ ret = of_platform_populate(child_np, NULL, NULL, dev);
+ if (ret < 0)
+ return ret;
}
}
return 0;
-error:
- clk_disable_unprepare(aemif->clk);
- return ret;
-}
-
-static void aemif_remove(struct platform_device *pdev)
-{
- struct aemif_device *aemif = platform_get_drvdata(pdev);
-
- clk_disable_unprepare(aemif->clk);
}
static struct platform_driver aemif_driver = {
.probe = aemif_probe,
- .remove_new = aemif_remove,
.driver = {
.name = "ti-aemif",
.of_match_table = of_match_ptr(aemif_of_match),
diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c
index 592f70e9c8e5..df362ecc59e9 100644
--- a/drivers/memory/ti-emif-pm.c
+++ b/drivers/memory/ti-emif-pm.c
@@ -330,7 +330,7 @@ static const struct dev_pm_ops ti_emif_pm_ops = {
static struct platform_driver ti_emif_driver = {
.probe = ti_emif_probe,
- .remove_new = ti_emif_remove,
+ .remove = ti_emif_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = ti_emif_of_match,