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
This commit is contained in:
Tom Rini 2024-12-04 14:30:25 -06:00
commit fe76d868f7
6 changed files with 143 additions and 6 deletions

View file

@ -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>;

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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;
@ -192,6 +197,33 @@ static int match_opp(struct vd_data *vd, u32 freq)
return -EINVAL;
}
/**
* 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
@ -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,

View file

@ -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