[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20260206-memory-refactor-v1-1-4385d439558a@nvidia.com>
Date: Fri, 06 Feb 2026 11:54:18 +0900
From: Mikko Perttunen <mperttunen@...dia.com>
To: Krzysztof Kozlowski <krzk@...nel.org>,
Thierry Reding <thierry.reding@...il.com>,
Jonathan Hunter <jonathanh@...dia.com>
Cc: Svyatoslav Ryhel <clamor95@...il.com>, linux-kernel@...r.kernel.org,
linux-tegra@...r.kernel.org, Mikko Perttunen <mperttunen@...dia.com>
Subject: [PATCH] memory: tegra: Deduplicate rate request management code
As is, the EMC drivers for each 32-bit platform contain almost
identical duplicated code for aggregating rate requests. Move this
code out to a shared tegra-emc-common file to reduce duplication.
Signed-off-by: Mikko Perttunen <mperttunen@...dia.com>
---
This patch is on top of 'memory: tegra: Add Tegra114 EMC driver'
---
drivers/memory/tegra/Kconfig | 7 ++
drivers/memory/tegra/Makefile | 1 +
drivers/memory/tegra/tegra-emc-common.c | 96 ++++++++++++++++++++++++++++
drivers/memory/tegra/tegra-emc-common.h | 38 +++++++++++
drivers/memory/tegra/tegra114-emc.c | 107 ++-----------------------------
drivers/memory/tegra/tegra124-emc.c | 107 ++-----------------------------
drivers/memory/tegra/tegra20-emc.c | 110 ++------------------------------
drivers/memory/tegra/tegra30-emc.c | 107 ++-----------------------------
8 files changed, 167 insertions(+), 406 deletions(-)
diff --git a/drivers/memory/tegra/Kconfig b/drivers/memory/tegra/Kconfig
index 11e7cc357d39..aeda7f104d34 100644
--- a/drivers/memory/tegra/Kconfig
+++ b/drivers/memory/tegra/Kconfig
@@ -17,6 +17,7 @@ config TEGRA20_EMC
select DEVFREQ_GOV_SIMPLE_ONDEMAND
select PM_DEVFREQ
select DDR
+ select TEGRA_EMC_COMMON
help
This driver is for the External Memory Controller (EMC) found on
Tegra20 chips. The EMC controls the external DRAM on the board.
@@ -29,6 +30,7 @@ config TEGRA30_EMC
depends on ARCH_TEGRA_3x_SOC || COMPILE_TEST
select PM_OPP
select DDR
+ select TEGRA_EMC_COMMON
help
This driver is for the External Memory Controller (EMC) found on
Tegra30 chips. The EMC controls the external DRAM on the board.
@@ -41,6 +43,7 @@ config TEGRA114_EMC
depends on ARCH_TEGRA_114_SOC || COMPILE_TEST
select TEGRA124_CLK_EMC if ARCH_TEGRA
select PM_OPP
+ select TEGRA_EMC_COMMON
help
This driver is for the External Memory Controller (EMC) found on
Tegra114 chips. The EMC controls the external DRAM on the board.
@@ -53,6 +56,7 @@ config TEGRA124_EMC
depends on ARCH_TEGRA_124_SOC || COMPILE_TEST
select TEGRA124_CLK_EMC if ARCH_TEGRA
select PM_OPP
+ select TEGRA_EMC_COMMON
help
This driver is for the External Memory Controller (EMC) found on
Tegra124 chips. The EMC controls the external DRAM on the board.
@@ -73,4 +77,7 @@ config TEGRA210_EMC
This driver is required to change memory timings / clock rate for
external memory.
+config TEGRA_EMC_COMMON
+ tristate
+
endif
diff --git a/drivers/memory/tegra/Makefile b/drivers/memory/tegra/Makefile
index 6b9156de4b66..28f22c957a34 100644
--- a/drivers/memory/tegra/Makefile
+++ b/drivers/memory/tegra/Makefile
@@ -14,6 +14,7 @@ tegra-mc-$(CONFIG_ARCH_TEGRA_264_SOC) += tegra186.o tegra264.o
obj-$(CONFIG_TEGRA_MC) += tegra-mc.o
+obj-$(CONFIG_TEGRA_EMC_COMMON) += tegra-emc-common.o
obj-$(CONFIG_TEGRA20_EMC) += tegra20-emc.o
obj-$(CONFIG_TEGRA30_EMC) += tegra30-emc.o
obj-$(CONFIG_TEGRA114_EMC) += tegra114-emc.o
diff --git a/drivers/memory/tegra/tegra-emc-common.c b/drivers/memory/tegra/tegra-emc-common.c
new file mode 100644
index 000000000000..9292472a5890
--- /dev/null
+++ b/drivers/memory/tegra/tegra-emc-common.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/pm_opp.h>
+
+#include "tegra-emc-common.h"
+
+void tegra_emc_rate_requests_init(struct tegra_emc_rate_requests *reqs,
+ struct device *dev)
+{
+ unsigned int i;
+
+ mutex_init(&reqs->rate_lock);
+ reqs->dev = dev;
+
+ for (i = 0; i < TEGRA_EMC_RATE_TYPE_MAX; i++) {
+ reqs->requested_rate[i].min_rate = 0;
+ reqs->requested_rate[i].max_rate = ULONG_MAX;
+ }
+}
+EXPORT_SYMBOL_GPL(tegra_emc_rate_requests_init);
+
+static int tegra_emc_request_rate(struct tegra_emc_rate_requests *reqs,
+ unsigned long new_min_rate,
+ unsigned long new_max_rate,
+ enum tegra_emc_rate_request_type type)
+{
+ struct tegra_emc_rate_request *req = reqs->requested_rate;
+ unsigned long min_rate = 0, max_rate = ULONG_MAX;
+ unsigned int i;
+ int err;
+
+ /* select minimum and maximum rates among the requested rates */
+ for (i = 0; i < TEGRA_EMC_RATE_TYPE_MAX; i++, req++) {
+ if (i == type) {
+ min_rate = max(new_min_rate, min_rate);
+ max_rate = min(new_max_rate, max_rate);
+ } else {
+ min_rate = max(req->min_rate, min_rate);
+ max_rate = min(req->max_rate, max_rate);
+ }
+ }
+
+ if (min_rate > max_rate) {
+ dev_err_ratelimited(reqs->dev, "%s: type %u: out of range: %lu %lu\n",
+ __func__, type, min_rate, max_rate);
+ return -ERANGE;
+ }
+
+ /*
+ * EMC rate-changes should go via OPP API because it manages voltage
+ * changes.
+ */
+ err = dev_pm_opp_set_rate(reqs->dev, min_rate);
+ if (err)
+ return err;
+
+ reqs->requested_rate[type].min_rate = new_min_rate;
+ reqs->requested_rate[type].max_rate = new_max_rate;
+
+ return 0;
+}
+
+int tegra_emc_set_min_rate(struct tegra_emc_rate_requests *reqs,
+ unsigned long rate,
+ enum tegra_emc_rate_request_type type)
+{
+ struct tegra_emc_rate_request *req = &reqs->requested_rate[type];
+ int ret;
+
+ mutex_lock(&reqs->rate_lock);
+ ret = tegra_emc_request_rate(reqs, rate, req->max_rate, type);
+ mutex_unlock(&reqs->rate_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tegra_emc_set_min_rate);
+
+int tegra_emc_set_max_rate(struct tegra_emc_rate_requests *reqs,
+ unsigned long rate,
+ enum tegra_emc_rate_request_type type)
+{
+ struct tegra_emc_rate_request *req = &reqs->requested_rate[type];
+ int ret;
+
+ mutex_lock(&reqs->rate_lock);
+ ret = tegra_emc_request_rate(reqs, req->min_rate, rate, type);
+ mutex_unlock(&reqs->rate_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tegra_emc_set_max_rate);
+
+MODULE_DESCRIPTION("NVIDIA Tegra EMC common code");
+MODULE_LICENSE("GPL");
diff --git a/drivers/memory/tegra/tegra-emc-common.h b/drivers/memory/tegra/tegra-emc-common.h
new file mode 100644
index 000000000000..420ff574045c
--- /dev/null
+++ b/drivers/memory/tegra/tegra-emc-common.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef TEGRA_EMC_COMMON_H
+#define TEGRA_EMC_COMMON_H
+
+#include <linux/device.h>
+#include <linux/mutex.h>
+
+enum tegra_emc_rate_request_type {
+ TEGRA_EMC_RATE_DEVFREQ,
+ TEGRA_EMC_RATE_DEBUG,
+ TEGRA_EMC_RATE_ICC,
+ TEGRA_EMC_RATE_TYPE_MAX,
+};
+
+struct tegra_emc_rate_request {
+ unsigned long min_rate;
+ unsigned long max_rate;
+};
+
+struct tegra_emc_rate_requests {
+ struct tegra_emc_rate_request requested_rate[TEGRA_EMC_RATE_TYPE_MAX];
+ struct mutex rate_lock;
+ struct device *dev;
+};
+
+void tegra_emc_rate_requests_init(struct tegra_emc_rate_requests *reqs,
+ struct device *dev);
+
+int tegra_emc_set_min_rate(struct tegra_emc_rate_requests *reqs,
+ unsigned long rate,
+ enum tegra_emc_rate_request_type type);
+
+int tegra_emc_set_max_rate(struct tegra_emc_rate_requests *reqs,
+ unsigned long rate,
+ enum tegra_emc_rate_request_type type);
+
+#endif /* TEGRA_EMC_COMMON_H */
diff --git a/drivers/memory/tegra/tegra114-emc.c b/drivers/memory/tegra/tegra114-emc.c
index 789b8e959a68..4fdc30e29488 100644
--- a/drivers/memory/tegra/tegra114-emc.c
+++ b/drivers/memory/tegra/tegra114-emc.c
@@ -32,6 +32,7 @@
#include <soc/tegra/mc.h>
#include "mc.h"
+#include "tegra-emc-common.h"
#define EMC_INTSTATUS 0x0
#define EMC_INTSTATUS_REFRESH_OVERFLOW BIT(3)
@@ -392,17 +393,6 @@ struct emc_timing {
u32 emc_zcal_interval;
};
-enum emc_rate_request_type {
- EMC_RATE_DEBUG,
- EMC_RATE_ICC,
- EMC_RATE_TYPE_MAX,
-};
-
-struct emc_rate_request {
- unsigned long min_rate;
- unsigned long max_rate;
-};
-
struct tegra_emc {
struct device *dev;
struct tegra_mc *mc;
@@ -425,14 +415,7 @@ struct tegra_emc {
struct icc_provider provider;
- /*
- * There are multiple sources in the EMC driver which could request
- * a min/max clock rate, these rates are contained in this array.
- */
- struct emc_rate_request requested_rate[EMC_RATE_TYPE_MAX];
-
- /* protect shared rate-change code path */
- struct mutex rate_lock;
+ struct tegra_emc_rate_requests reqs;
};
static irqreturn_t tegra_emc_isr(int irq, void *data)
@@ -995,83 +978,6 @@ tegra_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code)
return NULL;
}
-static void tegra_emc_rate_requests_init(struct tegra_emc *emc)
-{
- unsigned int i;
-
- for (i = 0; i < EMC_RATE_TYPE_MAX; i++) {
- emc->requested_rate[i].min_rate = 0;
- emc->requested_rate[i].max_rate = ULONG_MAX;
- }
-}
-
-static int emc_request_rate(struct tegra_emc *emc,
- unsigned long new_min_rate,
- unsigned long new_max_rate,
- enum emc_rate_request_type type)
-{
- struct emc_rate_request *req = emc->requested_rate;
- unsigned long min_rate = 0, max_rate = ULONG_MAX;
- unsigned int i;
- int err;
-
- /* select minimum and maximum rates among the requested rates */
- for (i = 0; i < EMC_RATE_TYPE_MAX; i++, req++) {
- if (i == type) {
- min_rate = max(new_min_rate, min_rate);
- max_rate = min(new_max_rate, max_rate);
- } else {
- min_rate = max(req->min_rate, min_rate);
- max_rate = min(req->max_rate, max_rate);
- }
- }
-
- if (min_rate > max_rate) {
- dev_err_ratelimited(emc->dev, "%s: type %u: out of range: %lu %lu\n",
- __func__, type, min_rate, max_rate);
- return -ERANGE;
- }
-
- /*
- * EMC rate-changes should go via OPP API because it manages voltage
- * changes.
- */
- err = dev_pm_opp_set_rate(emc->dev, min_rate);
- if (err)
- return err;
-
- emc->requested_rate[type].min_rate = new_min_rate;
- emc->requested_rate[type].max_rate = new_max_rate;
-
- return 0;
-}
-
-static int emc_set_min_rate(struct tegra_emc *emc, unsigned long rate,
- enum emc_rate_request_type type)
-{
- struct emc_rate_request *req = &emc->requested_rate[type];
- int ret;
-
- mutex_lock(&emc->rate_lock);
- ret = emc_request_rate(emc, rate, req->max_rate, type);
- mutex_unlock(&emc->rate_lock);
-
- return ret;
-}
-
-static int emc_set_max_rate(struct tegra_emc *emc, unsigned long rate,
- enum emc_rate_request_type type)
-{
- struct emc_rate_request *req = &emc->requested_rate[type];
- int ret;
-
- mutex_lock(&emc->rate_lock);
- ret = emc_request_rate(emc, req->min_rate, rate, type);
- mutex_unlock(&emc->rate_lock);
-
- return ret;
-}
-
/*
* debugfs interface
*
@@ -1144,7 +1050,7 @@ static int tegra_emc_debug_min_rate_set(void *data, u64 rate)
if (!tegra_emc_validate_rate(emc, rate))
return -EINVAL;
- err = emc_set_min_rate(emc, rate, EMC_RATE_DEBUG);
+ err = tegra_emc_set_min_rate(&emc->reqs, rate, TEGRA_EMC_RATE_DEBUG);
if (err < 0)
return err;
@@ -1174,7 +1080,7 @@ static int tegra_emc_debug_max_rate_set(void *data, u64 rate)
if (!tegra_emc_validate_rate(emc, rate))
return -EINVAL;
- err = emc_set_max_rate(emc, rate, EMC_RATE_DEBUG);
+ err = tegra_emc_set_max_rate(&emc->reqs, rate, TEGRA_EMC_RATE_DEBUG);
if (err < 0)
return err;
@@ -1280,7 +1186,7 @@ static int emc_icc_set(struct icc_node *src, struct icc_node *dst)
do_div(rate, ddr * dram_data_bus_width_bytes);
rate = min_t(u64, rate, U32_MAX);
- err = emc_set_min_rate(emc, rate, EMC_RATE_ICC);
+ err = tegra_emc_set_min_rate(&emc->reqs, rate, TEGRA_EMC_RATE_ICC);
if (err)
return err;
@@ -1357,7 +1263,6 @@ static int tegra_emc_probe(struct platform_device *pdev)
if (!emc)
return -ENOMEM;
- mutex_init(&emc->rate_lock);
emc->dev = &pdev->dev;
emc->regs = devm_platform_ioremap_resource(pdev, 0);
@@ -1424,7 +1329,7 @@ static int tegra_emc_probe(struct platform_device *pdev)
if (err)
return err;
- tegra_emc_rate_requests_init(emc);
+ tegra_emc_rate_requests_init(&emc->reqs, &pdev->dev);
if (IS_ENABLED(CONFIG_DEBUG_FS))
emc_debugfs_init(&pdev->dev, emc);
diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c
index 9978ff911c47..04ca1f606d29 100644
--- a/drivers/memory/tegra/tegra124-emc.c
+++ b/drivers/memory/tegra/tegra124-emc.c
@@ -27,6 +27,7 @@
#include <soc/tegra/mc.h>
#include "mc.h"
+#include "tegra-emc-common.h"
#define EMC_FBIO_CFG5 0x104
#define EMC_FBIO_CFG5_DRAM_TYPE_MASK 0x3
@@ -467,17 +468,6 @@ struct emc_timing {
u32 emc_zcal_interval;
};
-enum emc_rate_request_type {
- EMC_RATE_DEBUG,
- EMC_RATE_ICC,
- EMC_RATE_TYPE_MAX,
-};
-
-struct emc_rate_request {
- unsigned long min_rate;
- unsigned long max_rate;
-};
-
struct tegra_emc {
struct device *dev;
@@ -503,14 +493,7 @@ struct tegra_emc {
struct icc_provider provider;
- /*
- * There are multiple sources in the EMC driver which could request
- * a min/max clock rate, these rates are contained in this array.
- */
- struct emc_rate_request requested_rate[EMC_RATE_TYPE_MAX];
-
- /* protect shared rate-change code path */
- struct mutex rate_lock;
+ struct tegra_emc_rate_requests reqs;
};
/* Timing change sequence functions */
@@ -1041,83 +1024,6 @@ tegra124_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code)
return NULL;
}
-static void tegra124_emc_rate_requests_init(struct tegra_emc *emc)
-{
- unsigned int i;
-
- for (i = 0; i < EMC_RATE_TYPE_MAX; i++) {
- emc->requested_rate[i].min_rate = 0;
- emc->requested_rate[i].max_rate = ULONG_MAX;
- }
-}
-
-static int emc_request_rate(struct tegra_emc *emc,
- unsigned long new_min_rate,
- unsigned long new_max_rate,
- enum emc_rate_request_type type)
-{
- struct emc_rate_request *req = emc->requested_rate;
- unsigned long min_rate = 0, max_rate = ULONG_MAX;
- unsigned int i;
- int err;
-
- /* select minimum and maximum rates among the requested rates */
- for (i = 0; i < EMC_RATE_TYPE_MAX; i++, req++) {
- if (i == type) {
- min_rate = max(new_min_rate, min_rate);
- max_rate = min(new_max_rate, max_rate);
- } else {
- min_rate = max(req->min_rate, min_rate);
- max_rate = min(req->max_rate, max_rate);
- }
- }
-
- if (min_rate > max_rate) {
- dev_err_ratelimited(emc->dev, "%s: type %u: out of range: %lu %lu\n",
- __func__, type, min_rate, max_rate);
- return -ERANGE;
- }
-
- /*
- * EMC rate-changes should go via OPP API because it manages voltage
- * changes.
- */
- err = dev_pm_opp_set_rate(emc->dev, min_rate);
- if (err)
- return err;
-
- emc->requested_rate[type].min_rate = new_min_rate;
- emc->requested_rate[type].max_rate = new_max_rate;
-
- return 0;
-}
-
-static int emc_set_min_rate(struct tegra_emc *emc, unsigned long rate,
- enum emc_rate_request_type type)
-{
- struct emc_rate_request *req = &emc->requested_rate[type];
- int ret;
-
- mutex_lock(&emc->rate_lock);
- ret = emc_request_rate(emc, rate, req->max_rate, type);
- mutex_unlock(&emc->rate_lock);
-
- return ret;
-}
-
-static int emc_set_max_rate(struct tegra_emc *emc, unsigned long rate,
- enum emc_rate_request_type type)
-{
- struct emc_rate_request *req = &emc->requested_rate[type];
- int ret;
-
- mutex_lock(&emc->rate_lock);
- ret = emc_request_rate(emc, req->min_rate, rate, type);
- mutex_unlock(&emc->rate_lock);
-
- return ret;
-}
-
/*
* debugfs interface
*
@@ -1190,7 +1096,7 @@ static int tegra124_emc_debug_min_rate_set(void *data, u64 rate)
if (!tegra124_emc_validate_rate(emc, rate))
return -EINVAL;
- err = emc_set_min_rate(emc, rate, EMC_RATE_DEBUG);
+ err = tegra_emc_set_min_rate(&emc->reqs, rate, TEGRA_EMC_RATE_DEBUG);
if (err < 0)
return err;
@@ -1220,7 +1126,7 @@ static int tegra124_emc_debug_max_rate_set(void *data, u64 rate)
if (!tegra124_emc_validate_rate(emc, rate))
return -EINVAL;
- err = emc_set_max_rate(emc, rate, EMC_RATE_DEBUG);
+ err = tegra_emc_set_max_rate(&emc->reqs, rate, TEGRA_EMC_RATE_DEBUG);
if (err < 0)
return err;
@@ -1327,7 +1233,7 @@ static int emc_icc_set(struct icc_node *src, struct icc_node *dst)
do_div(rate, ddr * dram_data_bus_width_bytes);
rate = min_t(u64, rate, U32_MAX);
- err = emc_set_min_rate(emc, rate, EMC_RATE_ICC);
+ err = tegra_emc_set_min_rate(&emc->reqs, rate, TEGRA_EMC_RATE_ICC);
if (err)
return err;
@@ -1441,7 +1347,6 @@ static int tegra124_emc_probe(struct platform_device *pdev)
if (!emc)
return -ENOMEM;
- mutex_init(&emc->rate_lock);
emc->dev = &pdev->dev;
emc->regs = devm_platform_ioremap_resource(pdev, 0);
@@ -1487,7 +1392,7 @@ static int tegra124_emc_probe(struct platform_device *pdev)
if (err)
return err;
- tegra124_emc_rate_requests_init(emc);
+ tegra_emc_rate_requests_init(&emc->reqs, &pdev->dev);
if (IS_ENABLED(CONFIG_DEBUG_FS))
emc_debugfs_init(&pdev->dev, emc);
diff --git a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegra20-emc.c
index 398cb8ae2e38..1fd59f49242b 100644
--- a/drivers/memory/tegra/tegra20-emc.c
+++ b/drivers/memory/tegra/tegra20-emc.c
@@ -32,6 +32,7 @@
#include "../of_memory.h"
#include "mc.h"
+#include "tegra-emc-common.h"
#define EMC_INTSTATUS 0x000
#define EMC_INTMASK 0x004
@@ -182,18 +183,6 @@ struct emc_timing {
u32 data[ARRAY_SIZE(emc_timing_registers)];
};
-enum emc_rate_request_type {
- EMC_RATE_DEVFREQ,
- EMC_RATE_DEBUG,
- EMC_RATE_ICC,
- EMC_RATE_TYPE_MAX,
-};
-
-struct emc_rate_request {
- unsigned long min_rate;
- unsigned long max_rate;
-};
-
struct tegra_emc {
struct device *dev;
struct tegra_mc *mc;
@@ -212,14 +201,7 @@ struct tegra_emc {
unsigned long max_rate;
} debugfs;
- /*
- * There are multiple sources in the EMC driver which could request
- * a min/max clock rate, these rates are contained in this array.
- */
- struct emc_rate_request requested_rate[EMC_RATE_TYPE_MAX];
-
- /* protect shared rate-change code path */
- struct mutex rate_lock;
+ struct tegra_emc_rate_requests reqs;
struct devfreq_simple_ondemand_data ondemand_data;
@@ -710,83 +692,6 @@ static long emc_round_rate(unsigned long rate,
return timing->rate;
}
-static void tegra20_emc_rate_requests_init(struct tegra_emc *emc)
-{
- unsigned int i;
-
- for (i = 0; i < EMC_RATE_TYPE_MAX; i++) {
- emc->requested_rate[i].min_rate = 0;
- emc->requested_rate[i].max_rate = ULONG_MAX;
- }
-}
-
-static int emc_request_rate(struct tegra_emc *emc,
- unsigned long new_min_rate,
- unsigned long new_max_rate,
- enum emc_rate_request_type type)
-{
- struct emc_rate_request *req = emc->requested_rate;
- unsigned long min_rate = 0, max_rate = ULONG_MAX;
- unsigned int i;
- int err;
-
- /* select minimum and maximum rates among the requested rates */
- for (i = 0; i < EMC_RATE_TYPE_MAX; i++, req++) {
- if (i == type) {
- min_rate = max(new_min_rate, min_rate);
- max_rate = min(new_max_rate, max_rate);
- } else {
- min_rate = max(req->min_rate, min_rate);
- max_rate = min(req->max_rate, max_rate);
- }
- }
-
- if (min_rate > max_rate) {
- dev_err_ratelimited(emc->dev, "%s: type %u: out of range: %lu %lu\n",
- __func__, type, min_rate, max_rate);
- return -ERANGE;
- }
-
- /*
- * EMC rate-changes should go via OPP API because it manages voltage
- * changes.
- */
- err = dev_pm_opp_set_rate(emc->dev, min_rate);
- if (err)
- return err;
-
- emc->requested_rate[type].min_rate = new_min_rate;
- emc->requested_rate[type].max_rate = new_max_rate;
-
- return 0;
-}
-
-static int emc_set_min_rate(struct tegra_emc *emc, unsigned long rate,
- enum emc_rate_request_type type)
-{
- struct emc_rate_request *req = &emc->requested_rate[type];
- int ret;
-
- mutex_lock(&emc->rate_lock);
- ret = emc_request_rate(emc, rate, req->max_rate, type);
- mutex_unlock(&emc->rate_lock);
-
- return ret;
-}
-
-static int emc_set_max_rate(struct tegra_emc *emc, unsigned long rate,
- enum emc_rate_request_type type)
-{
- struct emc_rate_request *req = &emc->requested_rate[type];
- int ret;
-
- mutex_lock(&emc->rate_lock);
- ret = emc_request_rate(emc, req->min_rate, rate, type);
- mutex_unlock(&emc->rate_lock);
-
- return ret;
-}
-
/*
* debugfs interface
*
@@ -857,7 +762,7 @@ static int tegra20_emc_debug_min_rate_set(void *data, u64 rate)
if (!tegra20_emc_validate_rate(emc, rate))
return -EINVAL;
- err = emc_set_min_rate(emc, rate, EMC_RATE_DEBUG);
+ err = tegra_emc_set_min_rate(&emc->reqs, rate, TEGRA_EMC_RATE_DEBUG);
if (err < 0)
return err;
@@ -887,7 +792,7 @@ static int tegra20_emc_debug_max_rate_set(void *data, u64 rate)
if (!tegra20_emc_validate_rate(emc, rate))
return -EINVAL;
- err = emc_set_max_rate(emc, rate, EMC_RATE_DEBUG);
+ err = tegra_emc_set_max_rate(&emc->reqs, rate, TEGRA_EMC_RATE_DEBUG);
if (err < 0)
return err;
@@ -993,7 +898,7 @@ static int emc_icc_set(struct icc_node *src, struct icc_node *dst)
do_div(rate, dram_data_bus_width_bytes);
rate = min_t(u64, rate, U32_MAX);
- err = emc_set_min_rate(emc, rate, EMC_RATE_ICC);
+ err = tegra_emc_set_min_rate(&emc->reqs, rate, TEGRA_EMC_RATE_ICC);
if (err)
return err;
@@ -1111,7 +1016,7 @@ static int tegra20_emc_devfreq_target(struct device *dev, unsigned long *freq,
rate = dev_pm_opp_get_freq(opp);
dev_pm_opp_put(opp);
- return emc_set_min_rate(emc, rate, EMC_RATE_DEVFREQ);
+ return tegra_emc_set_min_rate(&emc->reqs, rate, TEGRA_EMC_RATE_DEVFREQ);
}
static int tegra20_emc_devfreq_get_dev_status(struct device *dev,
@@ -1190,7 +1095,6 @@ static int tegra20_emc_probe(struct platform_device *pdev)
if (!emc)
return -ENOMEM;
- mutex_init(&emc->rate_lock);
emc->clk_nb.notifier_call = tegra20_emc_clk_change_notify;
emc->dev = &pdev->dev;
@@ -1228,7 +1132,7 @@ static int tegra20_emc_probe(struct platform_device *pdev)
return err;
platform_set_drvdata(pdev, emc);
- tegra20_emc_rate_requests_init(emc);
+ tegra_emc_rate_requests_init(&emc->reqs, &pdev->dev);
tegra20_emc_debugfs_init(emc);
tegra20_emc_interconnect_init(emc);
tegra20_emc_devfreq_init(emc);
diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c
index 914116d8ec16..93aeef65b9d4 100644
--- a/drivers/memory/tegra/tegra30-emc.c
+++ b/drivers/memory/tegra/tegra30-emc.c
@@ -36,6 +36,7 @@
#include "../of_memory.h"
#include "mc.h"
+#include "tegra-emc-common.h"
#define EMC_INTSTATUS 0x000
#define EMC_INTMASK 0x004
@@ -341,17 +342,6 @@ struct emc_timing {
bool emc_cfg_dyn_self_ref;
};
-enum emc_rate_request_type {
- EMC_RATE_DEBUG,
- EMC_RATE_ICC,
- EMC_RATE_TYPE_MAX,
-};
-
-struct emc_rate_request {
- unsigned long min_rate;
- unsigned long max_rate;
-};
-
struct tegra_emc {
struct device *dev;
struct tegra_mc *mc;
@@ -383,14 +373,7 @@ struct tegra_emc {
unsigned long max_rate;
} debugfs;
- /*
- * There are multiple sources in the EMC driver which could request
- * a min/max clock rate, these rates are contained in this array.
- */
- struct emc_rate_request requested_rate[EMC_RATE_TYPE_MAX];
-
- /* protect shared rate-change code path */
- struct mutex rate_lock;
+ struct tegra_emc_rate_requests reqs;
bool mrr_error;
};
@@ -1228,83 +1211,6 @@ static long emc_round_rate(unsigned long rate,
return timing->rate;
}
-static void tegra30_emc_rate_requests_init(struct tegra_emc *emc)
-{
- unsigned int i;
-
- for (i = 0; i < EMC_RATE_TYPE_MAX; i++) {
- emc->requested_rate[i].min_rate = 0;
- emc->requested_rate[i].max_rate = ULONG_MAX;
- }
-}
-
-static int emc_request_rate(struct tegra_emc *emc,
- unsigned long new_min_rate,
- unsigned long new_max_rate,
- enum emc_rate_request_type type)
-{
- struct emc_rate_request *req = emc->requested_rate;
- unsigned long min_rate = 0, max_rate = ULONG_MAX;
- unsigned int i;
- int err;
-
- /* select minimum and maximum rates among the requested rates */
- for (i = 0; i < EMC_RATE_TYPE_MAX; i++, req++) {
- if (i == type) {
- min_rate = max(new_min_rate, min_rate);
- max_rate = min(new_max_rate, max_rate);
- } else {
- min_rate = max(req->min_rate, min_rate);
- max_rate = min(req->max_rate, max_rate);
- }
- }
-
- if (min_rate > max_rate) {
- dev_err_ratelimited(emc->dev, "%s: type %u: out of range: %lu %lu\n",
- __func__, type, min_rate, max_rate);
- return -ERANGE;
- }
-
- /*
- * EMC rate-changes should go via OPP API because it manages voltage
- * changes.
- */
- err = dev_pm_opp_set_rate(emc->dev, min_rate);
- if (err)
- return err;
-
- emc->requested_rate[type].min_rate = new_min_rate;
- emc->requested_rate[type].max_rate = new_max_rate;
-
- return 0;
-}
-
-static int emc_set_min_rate(struct tegra_emc *emc, unsigned long rate,
- enum emc_rate_request_type type)
-{
- struct emc_rate_request *req = &emc->requested_rate[type];
- int ret;
-
- mutex_lock(&emc->rate_lock);
- ret = emc_request_rate(emc, rate, req->max_rate, type);
- mutex_unlock(&emc->rate_lock);
-
- return ret;
-}
-
-static int emc_set_max_rate(struct tegra_emc *emc, unsigned long rate,
- enum emc_rate_request_type type)
-{
- struct emc_rate_request *req = &emc->requested_rate[type];
- int ret;
-
- mutex_lock(&emc->rate_lock);
- ret = emc_request_rate(emc, req->min_rate, rate, type);
- mutex_unlock(&emc->rate_lock);
-
- return ret;
-}
-
/*
* debugfs interface
*
@@ -1375,7 +1281,7 @@ static int tegra30_emc_debug_min_rate_set(void *data, u64 rate)
if (!tegra30_emc_validate_rate(emc, rate))
return -EINVAL;
- err = emc_set_min_rate(emc, rate, EMC_RATE_DEBUG);
+ err = tegra_emc_set_min_rate(&emc->reqs, rate, TEGRA_EMC_RATE_DEBUG);
if (err < 0)
return err;
@@ -1405,7 +1311,7 @@ static int tegra30_emc_debug_max_rate_set(void *data, u64 rate)
if (!tegra30_emc_validate_rate(emc, rate))
return -EINVAL;
- err = emc_set_max_rate(emc, rate, EMC_RATE_DEBUG);
+ err = tegra_emc_set_max_rate(&emc->reqs, rate, TEGRA_EMC_RATE_DEBUG);
if (err < 0)
return err;
@@ -1511,7 +1417,7 @@ static int emc_icc_set(struct icc_node *src, struct icc_node *dst)
do_div(rate, ddr * dram_data_bus_width_bytes);
rate = min_t(u64, rate, U32_MAX);
- err = emc_set_min_rate(emc, rate, EMC_RATE_ICC);
+ err = tegra_emc_set_min_rate(&emc->reqs, rate, TEGRA_EMC_RATE_ICC);
if (err)
return err;
@@ -1622,7 +1528,6 @@ static int tegra30_emc_probe(struct platform_device *pdev)
if (IS_ERR(emc->mc))
return PTR_ERR(emc->mc);
- mutex_init(&emc->rate_lock);
emc->clk_nb.notifier_call = emc_clk_change_notify;
emc->dev = &pdev->dev;
@@ -1664,7 +1569,7 @@ static int tegra30_emc_probe(struct platform_device *pdev)
return err;
platform_set_drvdata(pdev, emc);
- tegra30_emc_rate_requests_init(emc);
+ tegra_emc_rate_requests_init(&emc->reqs, &pdev->dev);
tegra30_emc_debugfs_init(emc);
tegra30_emc_interconnect_init(emc);
---
base-commit: ed4cdcc0b03e72cfdffbff9f0ea24338517bc893
change-id: 20260203-memory-refactor-54a6089a8dcf
prerequisite-message-id: <20260126190755.78475-1-clamor95@...il.com>
prerequisite-patch-id: d0cc6cf04447264ce099226c9157f1def25df716
prerequisite-patch-id: c57efa588876ea5cf00ea0f28f814ec818bbea58
prerequisite-patch-id: cddf792516ed7582a3cc20eb00ae7745969ff984
prerequisite-patch-id: 9e7e9d889caed5b5deeb60e03b233ffcb0f25724
prerequisite-patch-id: 90ba18fe5154b59da1c7b2db058e93c9f007854e
Powered by blists - more mailing lists