From: Stefan Eichenberger <eichest@gmail.com>
To: sbabic@denx.de, festevam@gmail.com, uboot-imx@nxp.com,
trini@konsulko.com, francesco.dolcini@toradex.com,
stefan.eichenberger@toradex.com, peng.fan@nxp.com,
emanuele.ghidoli@toradex.com, joao.goncalves@toradex.com,
vitor.soares@toradex.com, igor.opaniuk@foundries.io
Cc: u-boot@lists.denx.de
Subject: [PATCH v1 5/5] imx: mach: imx8: fdt: set correct frequencies for the industrial SoC
Date: Wed, 11 Dec 2024 13:18:55 +0100 [thread overview]
Message-ID: <20241211122036.103383-6-eichest@gmail.com> (raw)
In-Reply-To: <20241211122036.103383-1-eichest@gmail.com>
From: Stefan Eichenberger <stefan.eichenberger@toradex.com>
Set correct CPU and GPU frequencies for the industrial i.MX8 SoC
variant.
Ensure that the CPU and GPU frequencies are properly configured for the
industrial variant of the SoC. According to the "i.MX 8QuadMax
Industrial Applications Processors" datasheet, the frequency limits for
this variant are as follows:
- Cortex-A72: 1.296 GHz
- Cortex-A53: 1.104 GHz
- GPU core: 625 MHz
- GPU shader: 625 MHz
The CPU clock is enforced by the System Controller Firmware (SCFW), but
the cpufreq driver is unaware of this enforcement. By removing
unsupported frequencies from the operating points, we ensure that the
cpufreq driver aligns correctly with the SCFW's settings.
The GPU frequency, on the other hand, is not enforced by the SCFW. As a
result, the GPU could potentially be overclocked. To prevent this, we
set the correct clock frequency and update the operating points
accordingly, ensuring compliance with the datasheet specifications.
Signed-off-by: Stefan Eichenberger <stefan.eichenberger@toradex.com>
---
arch/arm/mach-imx/imx8/fdt.c | 132 +++++++++++++++++++++++++++++++++++
1 file changed, 132 insertions(+)
diff --git a/arch/arm/mach-imx/imx8/fdt.c b/arch/arm/mach-imx/imx8/fdt.c
index 6d0585f5cc6..ce78c8ce919 100644
--- a/arch/arm/mach-imx/imx8/fdt.c
+++ b/arch/arm/mach-imx/imx8/fdt.c
@@ -11,6 +11,8 @@
#include <fdt_support.h>
#include <linux/libfdt.h>
#include <linux/printk.h>
+#include <cpu.h>
+#include <dm.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -279,6 +281,134 @@ static int ft_add_optee_node(void *fdt, struct bd_info *bd)
return 0;
}
+static int delete_node(void *blob, const char *node)
+{
+ int nodeoffset;
+ int err;
+
+ nodeoffset = fdt_path_offset(blob, node);
+ if (nodeoffset < 0)
+ return -ENXIO;
+
+ err = fdt_del_node(blob, nodeoffset);
+ if (err)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int change_property(void *blob, const char *node, const char *property,
+ const void *value, int len)
+{
+ int nodeoffset;
+ int err;
+
+ nodeoffset = fdt_path_offset(blob, node);
+ if (nodeoffset < 0)
+ return -ENXIO;
+
+ err = fdt_setprop(blob, nodeoffset, property, value, len);
+ if (err)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void update_fdt_gpu_industrial_frequencies(void *blob)
+{
+ u32 gpu_opp_table[6];
+ u32 gpu_assigned_clocks[2];
+ int err;
+
+ gpu_opp_table[0] = cpu_to_fdt32(625000); /* Normal Core Clock */
+ gpu_opp_table[1] = cpu_to_fdt32(0);
+ gpu_opp_table[2] = cpu_to_fdt32(625000); /* Normal Shader Clock */
+ gpu_opp_table[3] = cpu_to_fdt32(0);
+ gpu_opp_table[4] = cpu_to_fdt32(400000); /* Low Shader and Core Clock */
+ gpu_opp_table[5] = cpu_to_fdt32(0);
+
+ gpu_assigned_clocks[0] = cpu_to_fdt32(625000000); /* Core Clock */
+ gpu_assigned_clocks[1] = cpu_to_fdt32(625000000); /* Shader Clock */
+
+ err = change_property(blob, "/bus@53100000/gpu@53100000",
+ "assigned-clock-rates", gpu_assigned_clocks,
+ sizeof(gpu_assigned_clocks));
+ if (err && err != ENXIO)
+ printf("Failed to set assigned-clock-rates for GPU0: %s\n",
+ fdt_strerror(err));
+
+ err = change_property(blob, "/bus@54100000/gpu@54100000",
+ "assigned-clock-rates", gpu_assigned_clocks,
+ sizeof(gpu_assigned_clocks));
+ if (err && err != ENXIO)
+ printf("Failed to set assigned-clock-rates for GPU1: %s\n",
+ fdt_strerror(err));
+
+ err = change_property(blob, "/bus@54100000/imx8_gpu1_ss@80000000",
+ "operating-points", &gpu_opp_table,
+ sizeof(gpu_opp_table));
+ if (err && err != ENXIO)
+ printf("Failed to set operating-points for GPU: %s\n",
+ fdt_strerror(err));
+}
+
+static void update_fdt_cpu_industrial_frequencies(void *blob)
+{
+ int err;
+
+ err = delete_node(blob, "/opp-table-0/opp-1200000000");
+ if (err && err != -ENXIO)
+ printf("Failed to delete 1.2 GHz node on A53: %s\n",
+ fdt_strerror(err));
+
+ err = delete_node(blob, "/opp-table-1/opp-1596000000");
+ if (err && err != -ENXIO)
+ printf("Failed to delete 1.596 GHz node on A72: %s\n",
+ fdt_strerror(err));
+}
+
+static void update_fdt_frequencies(void *blob)
+{
+ struct cpu_info cpu;
+ struct udevice *dev;
+ int err;
+
+ uclass_first_device(UCLASS_CPU, &dev);
+
+ err = cpu_get_info(dev, &cpu);
+ if (err) {
+ printf("Failed to get CPU info\n");
+ return;
+ }
+
+ /*
+ * Differentiate between the automotive and industrial variants of the
+ * i.MX8. The difference of these two CPUs is the maximum frequencies
+ * for the CPU and GPU.
+ * Core Automotive [max. MHz] Industrial [max. MHz]
+ * A53 1200 1104
+ * A72 1596 1296
+ * GPU Core 800 625
+ * GPU Shader 1000 625
+ *
+ * While the SCFW enforces these limits for the CPU, the OS cpufreq
+ * driver remains unaware, causing a mismatch between reported and
+ * actual frequencies. This is resolved by removing the unsupprted
+ * frequencies from the device tree.
+ *
+ * The GPU frequencies are not enforced by the SCFW, therefore without
+ * updating the device tree we overclock the GPU.
+ *
+ * Using the cpu_freq variable is the only know way to differentiate
+ * between the automotive and industrial variants of the i.MX8.
+ */
+ if (cpu.cpu_freq != 1104000000)
+ return;
+
+ update_fdt_cpu_industrial_frequencies(blob);
+ update_fdt_gpu_industrial_frequencies(blob);
+}
+
int ft_system_setup(void *blob, struct bd_info *bd)
{
int ret;
@@ -294,6 +424,8 @@ int ft_system_setup(void *blob, struct bd_info *bd)
update_fdt_with_owned_resources(blob);
+ update_fdt_frequencies(blob);
+
if (is_imx8qm()) {
ret = config_smmu_fdt(blob);
if (ret)
--
2.45.2
next prev parent reply other threads:[~2024-12-11 12:51 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-12-11 12:18 [PATCH v1 0/5] add support for Apalis iMX8 1300MHz version Stefan Eichenberger
2024-12-11 12:18 ` [PATCH v1 1/5] toradex: tdx-cfg-block: set apalis imx8dxp to always disabled Stefan Eichenberger
2024-12-11 12:18 ` [PATCH v1 2/5] toradex: tdx-cfg-block: increase indentation for longer defines Stefan Eichenberger
2024-12-11 12:18 ` [PATCH v1 3/5] toradex: tdx-cfg-block: add new apalis imx8 pids Stefan Eichenberger
2024-12-11 12:18 ` [PATCH v1 4/5] toradex: apalis-imx8: simplify module version handling Stefan Eichenberger
2024-12-11 12:18 ` Stefan Eichenberger [this message]
2024-12-11 17:39 ` [PATCH v1 0/5] add support for Apalis iMX8 1300MHz version Francesco Dolcini
2024-12-17 10:55 ` Fabio Estevam
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241211122036.103383-6-eichest@gmail.com \
--to=eichest@gmail.com \
--cc=emanuele.ghidoli@toradex.com \
--cc=festevam@gmail.com \
--cc=francesco.dolcini@toradex.com \
--cc=igor.opaniuk@foundries.io \
--cc=joao.goncalves@toradex.com \
--cc=peng.fan@nxp.com \
--cc=sbabic@denx.de \
--cc=stefan.eichenberger@toradex.com \
--cc=trini@konsulko.com \
--cc=u-boot@lists.denx.de \
--cc=uboot-imx@nxp.com \
--cc=vitor.soares@toradex.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.