summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2024-12-04 14:30:25 -0600
committerTom Rini <trini@konsulko.com>2024-12-04 14:30:25 -0600
commitfe76d868f72e483f71a59639c8aa8f658a313b5d (patch)
tree514a14ce5c2b15a2abee637d95eefcb5e35ab7e6
parent96bddc81481ca890a14eb3e65f5f3a4c9a4aeb0f (diff)
parentabb2544d890a5d23a8ecc40a902fbf0918eda53a (diff)
Merge patch series "Add OPP_LOW support for J7200"
Aniket Limaye <a-limaye@ti.com> says: This series adds OPP_LOW spec data in k3_avs driver and enables a config option to select the OPP_LOW performance point. J7200 SOC supports OPP_LOW and OPP_NOM as two Operating Performance Points as per (7.5 Operating Performance Points) section in the Datasheet [0]. - A72SS/MSMC at 2 GHz/1GHz operation must use OPP_NOM. - A72SS/MSMC at 1 GHz/500 MHz operation can use OPP_NOM or OPP_LOW voltage (though OPP_LOW voltage is recommended to reduce power consumption). The actual OPP voltage for the device is read from the efuse and updated in k3_avs_probe(). The default j7200 devicetree and k3_avs driver set OPP_NOM spec frequency and voltage. In the board init file, if K3_OPP_LOW config is enabled, Check if OPP_LOW AVS voltage read from efuse is valid and update frequency (A72 and MSMC) and voltage (VDD_CPU) as per the OPP_LOW spec. [0]: https://www.ti.com/lit/gpn/dra821u (J7200 Datasheet) Test logs: https://gist.github.com/aniket-l/328ad93ed60c2419ed7be9f85e6b6075 - With series applied on master and CONFIG_K3_OPP_LOW enabled in j7200_evm_r5_defconfig - Logs shown with and without efuse register programmed for OPP_0 (Errors out if OPP_0 not found, programs OPP_LOW spec if found) - Voltage update verified using 'i2c md 0x4c 0xe' in u-boot - Frequency update verified using 'k3conf clock dump' in linux Link: https://lore.kernel.org/r/20241119003617.1871183-1-a-limaye@ti.com
-rw-r--r--arch/arm/dts/k3-j7200-r5-common-proc-board.dts11
-rw-r--r--arch/arm/mach-k3/j721e/j721e_init.c92
-rw-r--r--arch/arm/mach-k3/r5/Kconfig7
-rw-r--r--configs/j7200_evm_r5_defconfig1
-rw-r--r--drivers/misc/k3_avs.c36
-rw-r--r--include/k3-avs.h2
6 files changed, 143 insertions, 6 deletions
diff --git a/arch/arm/dts/k3-j7200-r5-common-proc-board.dts b/arch/arm/dts/k3-j7200-r5-common-proc-board.dts
index f096b102793..06fffe2a11b 100644
--- a/arch/arm/dts/k3-j7200-r5-common-proc-board.dts
+++ b/arch/arm/dts/k3-j7200-r5-common-proc-board.dts
@@ -23,11 +23,12 @@
<&k3_pds 202 TI_SCI_PD_EXCLUSIVE>,
<&k3_pds 4 TI_SCI_PD_EXCLUSIVE>;
resets = <&k3_reset 202 0>;
- clocks = <&k3_clks 61 1>, <&k3_clks 202 2>;
- clock-names = "gtc", "core";
- assigned-clocks = <&k3_clks 202 2>, <&k3_clks 61 1>, <&k3_clks 323 0>;
- assigned-clock-parents= <0>, <0>, <&k3_clks 323 2>;
- assigned-clock-rates = <2000000000>, <200000000>;
+ clocks = <&k3_clks 61 1>, <&k3_clks 202 2>, <&k3_clks 4 1> ;
+ clock-names = "gtc", "core", "msmc";
+ assigned-clocks = <&k3_clks 202 2>, <&k3_clks 61 1>, <&k3_clks 4 1>,
+ <&k3_clks 323 0>;
+ assigned-clock-parents= <0>, <0>, <0>, <&k3_clks 323 2>;
+ assigned-clock-rates = <2000000000>, <200000000>, <1000000000>;
ti,sci = <&dmsc>;
ti,sci-proc-id = <32>;
ti,sci-host-id = <10>;
diff --git a/arch/arm/mach-k3/j721e/j721e_init.c b/arch/arm/mach-k3/j721e/j721e_init.c
index e9ed8cb267c..805b28af8e4 100644
--- a/arch/arm/mach-k3/j721e/j721e_init.c
+++ b/arch/arm/mach-k3/j721e/j721e_init.c
@@ -19,6 +19,7 @@
#include <fdtdec.h>
#include <mmc.h>
#include <remoteproc.h>
+#include <k3-avs.h>
#include "../sysfw-loader.h"
#include "../common.h"
@@ -39,6 +40,12 @@
#define NB_THREADMAP_BIT0 BIT(0)
#define NB_THREADMAP_BIT1 BIT(1)
+/* TISCI DEV ID for A72, MSMC Clock */
+#define DEV_A72SS0_CORE0_0_ID 202
+#define DEV_A72SS0_CORE0_0_ARM_CLK_CLK_ID 2
+#define DEV_A72SS0_CORE0_ID 4
+#define DEV_A72SS0_CORE0_MSMC_CLK_ID 1
+
#ifdef CONFIG_K3_LOAD_SYSFW
struct fwl_data cbass_hc_cfg0_fwls[] = {
#if defined(CONFIG_TARGET_J721E_R5_EVM)
@@ -147,6 +154,78 @@ static void setup_navss_nb(void)
writel(NB_THREADMAP_BIT1, (uintptr_t)NAVSS0_NBSS_NB1_CFG_NB_THREADMAP);
}
+#if defined(CONFIG_CPU_V7R) && defined(CONFIG_K3_AVS0)
+static int get_clock_index_by_dev_id(ofnode node, u32 dev_id, u32 clk_id)
+{
+ ofnode clknode;
+ int count, i;
+ struct ofnode_phandle_args phandle_args;
+
+ clknode = ofnode_by_compatible(ofnode_null(), "ti,k2g-sci-clk");
+ if (!ofnode_valid(clknode)) {
+ printf("%s: clock-controller not found\n", __func__);
+ return -ENODEV;
+ }
+
+ count = ofnode_count_phandle_with_args(node, "assigned-clocks", "#clock-cells", 0);
+ for (i = 0; i < count; i++) {
+ if (ofnode_parse_phandle_with_args(node, "assigned-clocks",
+ "#clock-cells", 0, i, &phandle_args)) {
+ printf("%s: Could not parse assigned-clocks at index %d\n", __func__, i);
+ continue;
+ }
+ if (ofnode_equal(clknode, phandle_args.node) &&
+ phandle_args.args[0] == dev_id && phandle_args.args[1] == clk_id)
+ return i;
+ }
+ return -1;
+}
+
+static int fdt_fixup_a72ss_clock_frequency(void)
+{
+ int index, size;
+ u32 *rates;
+ ofnode node;
+
+ node = ofnode_by_compatible(ofnode_null(), "ti,am654-rproc");
+ if (!ofnode_valid(node)) {
+ printf("%s: A72 not found\n", __func__);
+ return -ENODEV;
+ }
+
+ rates = fdt_getprop_w(ofnode_to_fdt(node), ofnode_to_offset(node),
+ "assigned-clock-rates", &size);
+ if (!rates) {
+ printf("%s: Wrong A72 assigned-clocks-rates configuration\n", __func__);
+ return -1;
+ }
+
+ /* Update A72 Clock Frequency to OPP_LOW spec */
+ index = get_clock_index_by_dev_id(node,
+ DEV_A72SS0_CORE0_0_ID,
+ DEV_A72SS0_CORE0_0_ARM_CLK_CLK_ID);
+ if (index < 0 || index >= (size / sizeof(u32))) {
+ printf("%s: Wrong A72 assigned-clocks configuration\n", __func__);
+ return -1;
+ }
+ rates[index] = cpu_to_fdt32(1000000000);
+ printf("Changed A72 CPU frequency to %dHz in DT\n", 1000000000);
+
+ /* Update MSMC Clock Frequency to OPP_LOW spec */
+ index = get_clock_index_by_dev_id(node,
+ DEV_A72SS0_CORE0_ID,
+ DEV_A72SS0_CORE0_MSMC_CLK_ID);
+ if (index < 0 || index >= (size / sizeof(u32))) {
+ printf("%s: Wrong A72 assigned-clocks configuration\n", __func__);
+ return -1;
+ }
+ rates[index] = cpu_to_fdt32(500000000);
+ printf("Changed MSMC frequency to %dHz in DT\n", 500000000);
+
+ return 0;
+}
+#endif
+
/*
* This uninitialized global variable would normal end up in the .bss section,
* but the .bss is cleared between writing and reading this variable, so move
@@ -301,8 +380,19 @@ void board_init_f(ulong dummy)
#if defined(CONFIG_CPU_V7R) && defined(CONFIG_K3_AVS0)
ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(k3_avs),
&dev);
- if (ret)
+ if (ret) {
printf("AVS init failed: %d\n", ret);
+ } else if (IS_ENABLED(CONFIG_K3_OPP_LOW)) {
+ ret = k3_avs_check_opp(dev, J721E_VDD_MPU, AM6_OPP_LOW);
+ if (ret) {
+ printf("OPP_LOW: k3_avs_check_opp failed: %d\n", ret);
+ } else {
+ ret = fdt_fixup_a72ss_clock_frequency();
+ if (ret)
+ printf("OPP_LOW: fdt_fixup_a72ss_clock_frequency failed: %d\n",
+ ret);
+ }
+ }
#endif
#if defined(CONFIG_K3_J721E_DDRSS)
diff --git a/arch/arm/mach-k3/r5/Kconfig b/arch/arm/mach-k3/r5/Kconfig
index 878087fbf56..12335880e10 100644
--- a/arch/arm/mach-k3/r5/Kconfig
+++ b/arch/arm/mach-k3/r5/Kconfig
@@ -1,6 +1,13 @@
config K3_LOAD_SYSFW
bool
+config K3_OPP_LOW
+ depends on ARCH_K3 && K3_AVS0
+ bool "Enable OPP_LOW on supported TI K3 SoCs"
+ help
+ Enabling this will allow Socs with the proper efuse to run at a lower
+ MPU core voltage and adjust frequency according to SoC TRM
+
config K3_QOS
bool "Enable Quality of Service (QoS) Settings for TI K3 SoCs"
default y if SOC_K3_AM62A7
diff --git a/configs/j7200_evm_r5_defconfig b/configs/j7200_evm_r5_defconfig
index f036a6fd46b..217759e5d1b 100644
--- a/configs/j7200_evm_r5_defconfig
+++ b/configs/j7200_evm_r5_defconfig
@@ -102,6 +102,7 @@ CONFIG_K3_SEC_PROXY=y
CONFIG_FS_LOADER=y
CONFIG_SPL_FS_LOADER=y
CONFIG_K3_AVS0=y
+# CONFIG_K3_OPP_LOW is not set
CONFIG_SUPPORT_EMMC_BOOT=y
CONFIG_SPL_MMC_HS400_SUPPORT=y
CONFIG_MMC_SDHCI=y
diff --git a/drivers/misc/k3_avs.c b/drivers/misc/k3_avs.c
index 99a18a109b7..0774e0a4c9e 100644
--- a/drivers/misc/k3_avs.c
+++ b/drivers/misc/k3_avs.c
@@ -121,6 +121,11 @@ static int k3_avs_program_voltage(struct k3_avs_privdata *priv,
if (!vd->supply)
return -ENODEV;
+ if (!volt) {
+ dev_err(priv->dev, "No efuse found for opp_%d\n", opp_id);
+ return -EINVAL;
+ }
+
vd->opp = opp_id;
vd->flags |= VD_FLAG_INIT_DONE;
@@ -193,6 +198,33 @@ static int match_opp(struct vd_data *vd, u32 freq)
}
/**
+ * k3_check_opp: Check for presence of opp efuse
+ * @dev: AVS device
+ * @vdd_id: voltage domain ID
+ * @opp_id: opp id to check if voltage is present
+ *
+ * Checks to see if an opp has voltage. k3_avs probe will populate
+ * voltage data if efuse is present. Returns 0 if data is valid.
+ */
+int k3_avs_check_opp(struct udevice *dev, int vdd_id, int opp_id)
+{
+ struct k3_avs_privdata *priv = dev_get_priv(dev);
+ struct vd_data *vd;
+ int volt;
+
+ vd = get_vd(priv, vdd_id);
+ if (!vd)
+ return -EINVAL;
+
+ volt = vd->opps[opp_id].volt;
+ if (volt)
+ return 0;
+
+ printf("No efuse found for opp_%d\n", opp_id);
+ return -EINVAL;
+}
+
+/**
* k3_avs_notify_freq: Notify clock rate change towards AVS subsystem
* @dev_id: Device ID for the clock to be changed
* @clk_id: Clock ID for the clock to be changed
@@ -501,6 +533,10 @@ static struct vd_data j721e_vd_data[] = {
.dev_id = 202, /* J721E_DEV_A72SS0_CORE0 */
.clk_id = 2, /* ARM clock */
.opps = {
+ [AM6_OPP_LOW] = {
+ .volt = 0, /* voltage TBD after OPP fuse reading */
+ .freq = 1000000000,
+ },
[AM6_OPP_NOM] = {
.volt = 880000, /* TBD in DM */
.freq = 2000000000,
diff --git a/include/k3-avs.h b/include/k3-avs.h
index 1014d5d114d..5a973e4ed45 100644
--- a/include/k3-avs.h
+++ b/include/k3-avs.h
@@ -20,11 +20,13 @@
#define NUM_OPPS 4
+#define AM6_OPP_LOW 0
#define AM6_OPP_NOM 1
#define AM6_OPP_OD 2
#define AM6_OPP_TURBO 3
int k3_avs_set_opp(struct udevice *dev, int vdd_id, int opp_id);
int k3_avs_notify_freq(int dev_id, int clk_id, u32 freq);
+int k3_avs_check_opp(struct udevice *dev, int vdd_id, int opp_id);
#endif