Browse Source

soc: nxp: s32: convert power mng to native drivers

Convert power management to native drivers retaining existing
functionalities. Presently only SoC reset support and power control
initialization is supported, but these drivers will be extended to
support power management as well.

MC_ME and MC_RGM peripherals are common enough to be reused by other NXP
S32 devices, whereas PMC has specific implementations for each SoC
series.

Signed-off-by: Manuel Argüelles <manuel.arguelles@nxp.com>
pull/76664/head
Manuel Argüelles 12 months ago committed by David Leach
parent
commit
7704d4eba4
  1. 4
      boards/nxp/mr_canhubk3/mr_canhubk3.dts
  2. 17
      dts/arm/nxp/nxp_s32k344_m7.dtsi
  3. 12
      dts/bindings/power/nxp,s32-mc-me.yaml
  4. 37
      dts/bindings/power/nxp,s32-mc-rgm.yaml
  5. 36
      dts/bindings/power/nxp,s32k3-pmc.yaml
  6. 23
      soc/nxp/s32/Kconfig
  7. 3
      soc/nxp/s32/common/CMakeLists.txt
  8. 158
      soc/nxp/s32/common/mc_me.c
  9. 122
      soc/nxp/s32/common/mc_rgm.c
  10. 96
      soc/nxp/s32/common/power_soc.c
  11. 2
      soc/nxp/s32/s32k3/CMakeLists.txt
  12. 19
      soc/nxp/s32/s32k3/Kconfig
  13. 136
      soc/nxp/s32/s32k3/pmc.c
  14. 2
      west.yml

4
boards/nxp/mr_canhubk3/mr_canhubk3.dts

@ -201,6 +201,10 @@ @@ -201,6 +201,10 @@
};
};
&pmc {
lm-reg;
};
&flash0 {
partitions {
compatible = "fixed-partitions";

17
dts/arm/nxp/nxp_s32k344_m7.dtsi

@ -857,6 +857,23 @@ @@ -857,6 +857,23 @@
reg = <0x40080000 0x4000>;
status = "disabled";
};
pmc: pmc@402e8000 {
compatible = "nxp,s32k3-pmc";
reg = <0x402e8000 0x4000>;
};
mc_me: mc_me@402dc000 {
compatible = "nxp,s32-mc-me";
reg = <0x402dc000 0x4000>;
};
mc_rgm: mc_rgm@4028c000 {
compatible = "nxp,s32-mc-rgm";
reg = <0x4028c000 0x4000>;
func-reset-threshold = <0>;
dest-reset-threshold = <0>;
};
};
};

12
dts/bindings/power/nxp,s32-mc-me.yaml

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
# Copyright 2024 NXP
# SPDX-License-Identifier: Apache-2.0
description: NXP S32 Module Entry (MC_ME)
compatible: "nxp,s32-mc-me"
include: base.yaml
properties:
reg:
required: true

37
dts/bindings/power/nxp,s32-mc-rgm.yaml

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
# Copyright 2024 NXP
# SPDX-License-Identifier: Apache-2.0
description: NXP S32 Module Reset Generation (MC_RGM)
compatible: "nxp,s32-mc-rgm"
include: base.yaml
properties:
reg:
required: true
func-reset-threshold:
type: int
enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
default: 15
description: |
Functional Reset Escalation threshold.
If the value of this property is 0, the Functional reset escalation
function is disabled. Any other value is the number of Functional
resets that causes a Destructive reset, if the FRET register isn't
written to beforehand.
Default to maximum threshold (hardware reset value).
dest-reset-threshold:
type: int
enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
default: 0
description: |
Destructive Reset Escalation threshold.
If the value of this property is 0, the Destructive reset escalation
function is disabled. Any other value is the number of Destructive
resets which keeps the chip in the reset state until the next power-on
reset triggers a new reset sequence, if the DRET register isn't
written to beforehand.
Default to disabled (hardware reset value).

36
dts/bindings/power/nxp,s32k3-pmc.yaml

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
# Copyright 2024 NXP
# SPDX-License-Identifier: Apache-2.0
description: NXP S32K3xx Power Management Controller (PMC)
compatible: "nxp,s32k3-pmc"
include: base.yaml
properties:
reg:
required: true
lm-reg:
type: boolean
description: |
Enables the Last Mile regulator, which regulates an external 1.5V
voltage on V15 down to the core and logic supply (V11 power domain),
which is typically 1.1V.
When enabling PLL as system clock, the PMC Last Mile regulator should
be enabled.
lm-reg-auto:
type: boolean
description: |
Enables to turn over automatically from Boot Regulator Mode to Last Mile
regulator mode and vice versa, depending on the V15 voltage status.
When configuring system clocks higher than FIRC clock frequency,
lm-reg should be also enabled.
lm-reg-base-control:
type: boolean
description: |
Enable this if an external BJT between VDD_HV_A and V15 is used on the
PCB. The base of this BJT must be connected to the VRC_CTRL pin and is
controlled by the PMC to regulate a voltage of 1.5V on V15 pin.

23
soc/nxp/s32/Kconfig

@ -3,29 +3,6 @@ @@ -3,29 +3,6 @@
if SOC_FAMILY_NXP_S32
config NXP_S32_FUNC_RESET_THRESHOLD
int "Functional Reset Escalation threshold"
default 15
range 0 15
help
If the value of this option is 0, the Functional reset escalation
function is disabled. Any other value is the number of Functional
resets that causes a Destructive reset, if the FRET register isn't
written to beforehand.
Default to maximum threshold (hardware reset value).
config NXP_S32_DEST_RESET_THRESHOLD
int "Destructive Reset Escalation threshold"
default 0
range 0 15
help
If the value of this field is 0, the Destructive reset escalation
function is disabled. Any other value is the number of Destructive
resets which keeps the chip in the reset state until the next power-on
reset triggers a new reset sequence, if the DRET register isn't
written to beforehand.
Default to disabled (hardware reset value).
rsource "*/Kconfig"
endif # SOC_FAMILY_NXP_S32

3
soc/nxp/s32/common/CMakeLists.txt

@ -3,4 +3,5 @@ @@ -3,4 +3,5 @@
zephyr_include_directories(.)
zephyr_sources(osif.c)
zephyr_sources_ifdef(CONFIG_SOC_SERIES_S32K3 power_soc.c)
zephyr_library_sources_ifdef(CONFIG_DT_HAS_NXP_S32_MC_RGM_ENABLED mc_rgm.c)
zephyr_library_sources_ifdef(CONFIG_DT_HAS_NXP_S32_MC_ME_ENABLED mc_me.c)

158
soc/nxp/s32/common/mc_me.c

@ -0,0 +1,158 @@ @@ -0,0 +1,158 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT nxp_s32_mc_me
#include <zephyr/kernel.h>
#if defined(CONFIG_REBOOT)
#include <zephyr/sys/reboot.h>
#endif /* CONFIG_REBOOT */
/* Control Key Register */
#define MC_ME_CTL_KEY 0x0
#define MC_ME_CTL_KEY_KEY_MASK GENMASK(15, 0)
#define MC_ME_CTL_KEY_KEY(v) FIELD_PREP(MC_ME_CTL_KEY_KEY_MASK, (v))
/* Mode Configuration Register */
#define MC_ME_MODE_CONF 0x4
#define MC_ME_MODE_CONF_DEST_RST_MASK BIT(0)
#define MC_ME_MODE_CONF_DEST_RST(v) FIELD_PREP(MC_ME_MODE_CONF_DEST_RST_MASK, (v))
#define MC_ME_MODE_CONF_FUNC_RST_MASK BIT(1)
#define MC_ME_MODE_CONF_FUNC_RST(v) FIELD_PREP(MC_ME_MODE_CONF_FUNC_RST_MASK, (v))
#define MC_ME_MODE_CONF_STANDBY_MASK BIT(15)
#define MC_ME_MODE_CONF_STANDBY(v) FIELD_PREP(MC_ME_MODE_CONF_STANDBY_MASK, (v))
/* Mode Update Register */
#define MC_ME_MODE_UPD 0x8
#define MC_ME_MODE_UPD_MODE_UPD_MASK BIT(0)
#define MC_ME_MODE_UPD_MODE_UPD(v) FIELD_PREP(MC_ME_MODE_UPD_MODE_UPD_MASK, (v))
/* Mode Status Register */
#define MC_ME_MODE_STAT 0xc
#define MC_ME_MODE_STAT_PREV_MODE_MASK BIT(0)
#define MC_ME_MODE_STAT_PREV_MODE(v) FIELD_PREP(MC_ME_MODE_STAT_PREV_MODE_MASK, (v))
/* Main Core ID Register */
#define MC_ME_MAIN_COREID 0x10
#define MC_ME_MAIN_COREID_CIDX_MASK GENMASK(2, 0)
#define MC_ME_MAIN_COREID_CIDX(v) FIELD_PREP(MC_ME_MAIN_COREID_CIDX_MASK, (v))
#define MC_ME_MAIN_COREID_PIDX_MASK GENMASK(12, 8)
#define MC_ME_MAIN_COREID_PIDX(v) FIELD_PREP(MC_ME_MAIN_COREID_PIDX_MASK, (v))
/* Partition p Process Configuration Register */
#define MC_ME_PRTN_PCONF(p) (0x100 + 0x200 * (p))
#define MC_ME_PRTN_PCONF_PCE_MASK BIT(0)
#define MC_ME_PRTN_PCONF_PCE(v) FIELD_PREP(MC_ME_PRTN_PCONF_PCE_MASK, (v))
/* Partition p Process Update Register */
#define MC_ME_PRTN_PUPD(p) (0x104 + 0x200 * (p))
#define MC_ME_PRTN_PUPD_PCUD_MASK BIT(0)
#define MC_ME_PRTN_PUPD_PCUD(v) FIELD_PREP(MC_ME_PRTN_PUPD_PCUD_MASK, (v))
/* Partition p Status Register */
#define MC_ME_PRTN_STAT(p) (0x108 + 0x200 * (p))
#define MC_ME_PRTN_STAT_PCS_MASK BIT(0)
#define MC_ME_PRTN_STAT_PCS(v) FIELD_PREP(MC_ME_PRTN_STAT_PCS_MASK, (v))
/* Partition p COFB c Clock Status Register */
#define MC_ME_PRTN_COFB_STAT(p, c) (0x110 + 0x200 * (p) + 0x4 * (c))
/* Partition p COFB c Clock Enable Register */
#define MC_ME_PRTN_COFB_CLKEN(p, c) (0x130 + 0x200 * (p) + 0x4 * (c))
/* Partition p Core c Process Configuration Register */
#define MC_ME_PRTN_CORE_PCONF(p, c) (0x140 + 0x200 * (p) + 0x20 * (c))
#define MC_ME_PRTN_CORE_PCONF_CCE_MASK BIT(0)
#define MC_ME_PRTN_CORE_PCONF_CCE(v) FIELD_PREP(MC_ME_PRTN_CORE_PCONF_CCE_MASK, (v))
/* Partition n Core c Process Update Register */
#define MC_ME_PRTN_CORE_PUPD(p, c) (0x144 + 0x200 * (p) + 0x20 * (c))
#define MC_ME_PRTN_CORE_PUPD_CCUPD_MASK BIT(0)
#define MC_ME_PRTN_CORE_PUPD_CCUPD(v) FIELD_PREP(MC_ME_PRTN_CORE_PUPD_CCUPD_MASK, (v))
/* Partition n Core c Status Register */
#define MC_ME_PRTN_CORE_STAT(p, c) (0x148 + 0x200 * (p) + 0x20 * (c))
#define MC_ME_PRTN_CORE_STAT_CCS_MASK BIT(0)
#define MC_ME_PRTN_CORE_STAT_CCS(v) FIELD_PREP(MC_ME_PRTN_CORE_STAT_CCS_MASK, (v))
#define MC_ME_PRTN_CORE_STAT_WFI_MASK BIT(31)
#define MC_ME_PRTN_CORE_STAT_WFI(v) FIELD_PREP(MC_ME_PRTN_CORE_STAT_WFI_MASK, (v))
/* Partition n Core c Address Register */
#define MC_ME_PRTN_CORE_ADDR(p, c) (0x14c + 0x200 * (p) + 0x20 * (c))
#define MC_ME_PRTN_CORE_ADDR_ADDR_MASK GENMASK(31, 2)
#define MC_ME_PRTN_CORE_ADDR_ADDR(v) FIELD_PREP(MC_ME_PRTN_CORE_ADDR_ADDR_MASK, (v))
#define MC_ME_CTL_KEY_DIRECT_KEY 0x00005af0U
#define MC_ME_CTL_KEY_INVERTED_KEY 0x0000a50fU
/* Handy accessors */
#define REG_READ(r) sys_read32((mem_addr_t)(DT_INST_REG_ADDR(0) + (r)))
#define REG_WRITE(r, v) sys_write32((v), (mem_addr_t)(DT_INST_REG_ADDR(0) + (r)))
/** MC_ME power mode */
enum mc_me_power_mode {
/** Destructive Reset Mode */
MC_ME_DEST_RESET_MODE,
/** Functional Reset Mode */
MC_ME_FUNC_RESET_MODE,
};
#if defined(CONFIG_REBOOT)
static inline void mc_me_write_ctl_key(void)
{
REG_WRITE(MC_ME_CTL_KEY, MC_ME_CTL_KEY_KEY(MC_ME_CTL_KEY_DIRECT_KEY));
REG_WRITE(MC_ME_CTL_KEY, MC_ME_CTL_KEY_KEY(MC_ME_CTL_KEY_INVERTED_KEY));
}
static inline void mc_me_trigger_mode_update(void)
{
REG_WRITE(MC_ME_MODE_UPD, MC_ME_MODE_UPD_MODE_UPD(1U));
mc_me_write_ctl_key();
}
static int mc_me_set_mode(enum mc_me_power_mode mode)
{
int err = 0;
switch (mode) {
case MC_ME_DEST_RESET_MODE:
REG_WRITE(MC_ME_MODE_CONF, MC_ME_MODE_CONF_DEST_RST(1U));
mc_me_trigger_mode_update();
break;
case MC_ME_FUNC_RESET_MODE:
REG_WRITE(MC_ME_MODE_CONF, MC_ME_MODE_CONF_FUNC_RST(1U));
mc_me_trigger_mode_update();
break;
default:
err = -ENOTSUP;
break;
}
return err;
}
/*
* Overrides default weak implementation of system reboot.
*
* SYS_REBOOT_COLD (Destructive Reset):
* - Leads most parts of the chip, except a few modules, to reset. SRAM content
* is lost after this reset event.
* - Flash is always reset, so an updated value of the option bits is reloaded
* in volatile registers outside of the Flash array.
* - Trimming is lost.
* - STCU is reset and configured BISTs are executed.
*
* SYS_REBOOT_WARM (Functional Reset):
* - Leads all the communication peripherals and cores to reset. The communication
* protocols' sanity is not guaranteed and they are assumed to be reinitialized
* after reset. The SRAM content, and the functionality of certain modules, is
* preserved across functional reset.
* - The volatile registers are not reset; in case of a reset event, the
* trimming is maintained.
* - No BISTs are executed after functional reset.
*/
void sys_arch_reboot(int type)
{
switch (type) {
case SYS_REBOOT_COLD:
mc_me_set_mode(MC_ME_DEST_RESET_MODE);
break;
case SYS_REBOOT_WARM:
mc_me_set_mode(MC_ME_FUNC_RESET_MODE);
break;
default:
/* Do nothing */
break;
}
}
#endif /* CONFIG_REBOOT */

122
soc/nxp/s32/common/mc_rgm.c

@ -0,0 +1,122 @@ @@ -0,0 +1,122 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT nxp_s32_mc_rgm
#include <zephyr/kernel.h>
#include <zephyr/init.h>
/* Destructive Event Status Register */
#define MC_RGM_DES 0x0
#define MC_RGM_DES_F_POR_MASK BIT(0)
#define MC_RGM_DES_F_POR(v) FIELD_PREP(MC_RGM_DES_F_POR_MASK, (v))
/* Functional / External Reset Status Register */
#define MC_RGM_FES 0x8
#define MC_RGM_FES_F_EXR_MASK BIT(0)
#define MC_RGM_FES_F_EXR(v) FIELD_PREP(MC_RGM_FES_F_EXR_MASK, (v))
/* Functional Event Reset Disable Register */
#define MC_RGM_FERD 0xc
/* Functional Bidirectional Reset Enable Register */
#define MC_RGM_FBRE 0x10
/* Functional Reset Escalation Counter Register */
#define MC_RGM_FREC 0x14
#define MC_RGM_FREC_FREC_MASK GENMASK(3, 0)
#define MC_RGM_FREC_FREC(v) FIELD_PREP(MC_RGM_FREC_FREC_MASK, (v))
/* Functional Reset Escalation Threshold Register */
#define MC_RGM_FRET 0x18
#define MC_RGM_FRET_FRET_MASK GENMASK(3, 0)
#define MC_RGM_FRET_FRET(v) FIELD_PREP(MC_RGM_FRET_FRET_MASK, (v))
/* Destructive Reset Escalation Threshold Register */
#define MC_RGM_DRET 0x1c
#define MC_RGM_DRET_DRET_MASK GENMASK(3, 0)
#define MC_RGM_DRET_DRET(v) FIELD_PREP(MC_RGM_DRET_DRET_MASK, (v))
/* External Reset Control Register */
#define MC_RGM_ERCTRL 0x20
#define MC_RGM_ERCTRL_ERASSERT_MASK BIT(0)
#define MC_RGM_ERCTRL_ERASSERT(v) FIELD_PREP(MC_RGM_ERCTRL_ERASSERT_MASK, (v))
/* Reset During Standby Status Register */
#define MC_RGM_RDSS 0x24
#define MC_RGM_RDSS_DES_RES_MASK BIT(0)
#define MC_RGM_RDSS_DES_RES(v) FIELD_PREP(MC_RGM_RDSS_DES_RES_MASK, (v))
#define MC_RGM_RDSS_FES_RES_MASK BIT(1)
#define MC_RGM_RDSS_FES_RES(v) FIELD_PREP(MC_RGM_RDSS_FES_RES_MASK, (v))
/* Functional Reset Entry Timeout Control Register */
#define MC_RGM_FRENTC 0x28
#define MC_RGM_FRENTC_FRET_EN_MASK BIT(0)
#define MC_RGM_FRENTC_FRET_EN(v) FIELD_PREP(MC_RGM_FRENTC_FRET_EN_MASK, (v))
#define MC_RGM_FRENTC_FRET_TIMEOUT_MASK GENMASK(31, 1)
#define MC_RGM_FRENTC_FRET_TIMEOUT(v) FIELD_PREP(MC_RGM_FRENTC_FRET_TIMEOUT_MASK, (v))
/* Low Power Debug Control Register */
#define MC_RGM_LPDEBUG 0x2c
#define MC_RGM_LPDEBUG_LP_DBG_EN_MASK BIT(0)
#define MC_RGM_LPDEBUG_LP_DBG_EN(v) FIELD_PREP(MC_RGM_LPDEBUG_LP_DBG_EN_MASK, (v))
#define MC_RGM_TIMEOUT_US 50000U
/* Handy accessors */
#define REG_READ(r) sys_read32((mem_addr_t)(DT_INST_REG_ADDR(0) + (r)))
#define REG_WRITE(r, v) sys_write32((v), (mem_addr_t)(DT_INST_REG_ADDR(0) + (r)))
static int mc_rgm_clear_reset_status(uint32_t reg)
{
bool timeout;
/*
* Register bits are cleared on write 1 if the triggering event has already
* been cleared at the source
*/
timeout = !WAIT_FOR(REG_READ(reg) == 0U, MC_RGM_TIMEOUT_US, REG_WRITE(reg, 0xffffffff));
return timeout ? -ETIMEDOUT : 0U;
}
static int mc_rgm_init(const struct device *dev)
{
int err = 0;
uint32_t rst_status;
ARG_UNUSED(dev);
/*
* MC_RGM_FES must be cleared before writing 1 to any of the fields in MC_RGM_FERD,
* otherwise an interrupt request may occur
*/
rst_status = REG_READ(MC_RGM_FES);
if (rst_status != 0U) {
err = mc_rgm_clear_reset_status(MC_RGM_FES);
if (err) {
return err;
}
}
/* All functional reset sources generate a reset event */
REG_WRITE(MC_RGM_FERD, 0U);
rst_status = REG_READ(MC_RGM_DES);
if ((DT_INST_PROP(0, func_reset_threshold) != 0U) && (rst_status != 0U)) {
/* MC_RGM_FRET value is reset on power-on and any destructive reset */
REG_WRITE(MC_RGM_FRET, MC_RGM_FRET_FRET(DT_INST_PROP(0, func_reset_threshold)));
} else {
REG_WRITE(MC_RGM_FRET, MC_RGM_FRET_FRET(0U));
}
if ((DT_INST_PROP(0, dest_reset_threshold) != 0U) &&
(FIELD_GET(MC_RGM_DES_F_POR_MASK, rst_status) != 0U)) {
/* MC_RGM_DRET value is reset only on power-on reset */
REG_WRITE(MC_RGM_DRET, MC_RGM_DRET_DRET(DT_INST_PROP(0, dest_reset_threshold)));
} else {
REG_WRITE(MC_RGM_DRET, MC_RGM_DRET_DRET(0U));
}
/* Clear destructive reset status to avoid persisting it across resets */
err = mc_rgm_clear_reset_status(MC_RGM_DES);
if (err) {
return err;
}
return err;
}
DEVICE_DT_INST_DEFINE(0, mc_rgm_init, NULL, NULL, 0, PRE_KERNEL_1, 1, NULL);

96
soc/nxp/s32/common/power_soc.c

@ -1,96 +0,0 @@ @@ -1,96 +0,0 @@
/*
* Copyright 2023 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/init.h>
#ifdef CONFIG_REBOOT
#include <zephyr/sys/reboot.h>
#endif
#include <Power_Ip.h>
#ifdef CONFIG_REBOOT
BUILD_ASSERT(POWER_IP_PERFORM_RESET_API == STD_ON, "Power Reset API must be enabled");
/*
* Overrides default weak implementation of system reboot.
*
* SYS_REBOOT_COLD (Destructive Reset):
* - Leads most parts of the chip, except a few modules, to reset. SRAM content
* is lost after this reset event.
* - Flash is always reset, so an updated value of the option bits is reloaded
* in volatile registers outside of the Flash array.
* - Trimming is lost.
* - STCU is reset and configured BISTs are executed.
*
* SYS_REBOOT_WARM (Functional Reset):
* - Leads all the communication peripherals and cores to reset. The communication
* protocols' sanity is not guaranteed and they are assumed to be reinitialized
* after reset. The SRAM content, and the functionality of certain modules, is
* preserved across functional reset.
* - The volatile registers are not reset; in case of a reset event, the
* trimming is maintained.
* - No BISTs are executed after functional reset.
*/
void sys_arch_reboot(int type)
{
Power_Ip_MC_RGM_ConfigType mc_rgm_cfg = { 0 };
const Power_Ip_HwIPsConfigType power_cfg = {
.McRgmConfigPtr = (const Power_Ip_MC_RGM_ConfigType *)&mc_rgm_cfg,
.PMCConfigPtr = NULL
};
switch (type) {
case SYS_REBOOT_COLD:
/* Destructive reset */
mc_rgm_cfg.ResetType = MCU_DEST_RESET;
Power_Ip_PerformReset(&power_cfg);
break;
case SYS_REBOOT_WARM:
/* Functional reset */
mc_rgm_cfg.ResetType = MCU_FUNC_RESET;
Power_Ip_PerformReset(&power_cfg);
break;
default:
/* Do nothing */
break;
}
}
#endif /* CONFIG_REBOOT */
static int nxp_s32_power_init(void)
{
const Power_Ip_MC_RGM_ConfigType mc_rgm_cfg = {
.FuncResetOpt = 0U, /* All functional reset sources enabled */
.FesThresholdReset = MC_RGM_FRET_FRET(CONFIG_NXP_S32_FUNC_RESET_THRESHOLD),
.DesThresholdReset = MC_RGM_DRET_DRET(CONFIG_NXP_S32_DEST_RESET_THRESHOLD)
};
const Power_Ip_PMC_ConfigType pmc_cfg = {
#ifdef CONFIG_SOC_SERIES_S32K3
/* PMC Configuration Register (CONFIG) */
.ConfigRegister = PMC_CONFIG_LMEN(IS_ENABLED(CONFIG_NXP_S32_PMC_LMEN))
| PMC_CONFIG_LMBCTLEN(IS_ENABLED(CONFIG_NXP_S32_PMC_LMBCTLEN)),
#else
#error "SoC not supported"
#endif
};
const Power_Ip_HwIPsConfigType power_cfg = {
.McRgmConfigPtr = &mc_rgm_cfg,
.PMCConfigPtr = &pmc_cfg
};
Power_Ip_Init(&power_cfg);
/* Read and clear the reset reason to avoid persisting it across resets */
(void)Power_Ip_GetResetReason();
return 0;
}
SYS_INIT(nxp_s32_power_init, PRE_KERNEL_1, 1);

2
soc/nxp/s32/s32k3/CMakeLists.txt

@ -6,6 +6,8 @@ zephyr_library() @@ -6,6 +6,8 @@ zephyr_library()
zephyr_include_directories(.)
zephyr_library_sources(soc.c)
zephyr_library_sources_ifdef(CONFIG_DT_HAS_NXP_S32K3_PMC_ENABLED pmc.c)
zephyr_library_sources_ifdef(CONFIG_CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS mpu_regions.c)
zephyr_linker_sources(SECTIONS sections.ld)
zephyr_library_sources_ifdef(CONFIG_PLATFORM_SPECIFIC_INIT s32k3xx_startup.S)

19
soc/nxp/s32/s32k3/Kconfig

@ -38,23 +38,4 @@ config IVT_HEADER_SIZE @@ -38,23 +38,4 @@ config IVT_HEADER_SIZE
help
Size of ivt header region
config NXP_S32_PMC_LMEN
bool "Last Mile regulator"
default y if CLOCK_CONTROL
help
Enables the Last Mile regulator, which regulates an external 1.5V
voltage on V15 down to the core and logic supply (V11 power domain),
which is typically 1.1V.
When enabling PLL as system clock, the PMC last mile regulator should
be enabled.
config NXP_S32_PMC_LMBCTLEN
bool "External BCTL regulator for V15"
depends on NXP_S32_PMC_LMEN
help
This option must be selected if an external BJT between VDD_HV_A and
V15 is used on the PCB. The base of this BJT must be connected to the
VRC_CTRL pin and is controlled by the PMC to regulate a voltage of
1.5V on V15 pin.
endif # SOC_SERIES_S32K3

136
soc/nxp/s32/s32k3/pmc.c

@ -0,0 +1,136 @@ @@ -0,0 +1,136 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT nxp_s32k3_pmc
#include <zephyr/kernel.h>
#include <zephyr/init.h>
/* Low Voltage Status and Control Register */
#define PMC_LVSC 0x0
#define PMC_LVSC_HVDAF_MASK BIT(0)
#define PMC_LVSC_HVDAF(v) FIELD_PREP(PMC_LVSC_HVDAF_MASK, (v))
#define PMC_LVSC_HVDBF_MASK BIT(1)
#define PMC_LVSC_HVDBF(v) FIELD_PREP(PMC_LVSC_HVDBF_MASK, (v))
#define PMC_LVSC_HVD25F_MASK BIT(2)
#define PMC_LVSC_HVD25F(v) FIELD_PREP(PMC_LVSC_HVD25F_MASK, (v))
#define PMC_LVSC_HVD11F_MASK BIT(3)
#define PMC_LVSC_HVD11F(v) FIELD_PREP(PMC_LVSC_HVD11F_MASK, (v))
#define PMC_LVSC_LVD5AF_MASK BIT(4)
#define PMC_LVSC_LVD5AF(v) FIELD_PREP(PMC_LVSC_LVD5AF_MASK, (v))
#define PMC_LVSC_LVD15F_MASK BIT(5)
#define PMC_LVSC_LVD15F(v) FIELD_PREP(PMC_LVSC_LVD15F_MASK, (v))
#define PMC_LVSC_HVDAS_MASK BIT(8)
#define PMC_LVSC_HVDAS(v) FIELD_PREP(PMC_LVSC_HVDAS_MASK, (v))
#define PMC_LVSC_HVDBS_MASK BIT(9)
#define PMC_LVSC_HVDBS(v) FIELD_PREP(PMC_LVSC_HVDBS_MASK, (v))
#define PMC_LVSC_HVD25S_MASK BIT(10)
#define PMC_LVSC_HVD25S(v) FIELD_PREP(PMC_LVSC_HVD25S_MASK, (v))
#define PMC_LVSC_HVD11S_MASK BIT(11)
#define PMC_LVSC_HVD11S(v) FIELD_PREP(PMC_LVSC_HVD11S_MASK, (v))
#define PMC_LVSC_LVD5AS_MASK BIT(12)
#define PMC_LVSC_LVD5AS(v) FIELD_PREP(PMC_LVSC_LVD5AS_MASK, (v))
#define PMC_LVSC_LVD15S_MASK BIT(13)
#define PMC_LVSC_LVD15S(v) FIELD_PREP(PMC_LVSC_LVD15S_MASK, (v))
#define PMC_LVSC_LVRAF_MASK BIT(16)
#define PMC_LVSC_LVRAF(v) FIELD_PREP(PMC_LVSC_LVRAF_MASK, (v))
#define PMC_LVSC_LVRALPF_MASK BIT(17)
#define PMC_LVSC_LVRALPF(v) FIELD_PREP(PMC_LVSC_LVRALPF_MASK, (v))
#define PMC_LVSC_LVRBF_MASK BIT(18)
#define PMC_LVSC_LVRBF(v) FIELD_PREP(PMC_LVSC_LVRBF_MASK, (v))
#define PMC_LVSC_LVRBLPF_MASK BIT(19)
#define PMC_LVSC_LVRBLPF(v) FIELD_PREP(PMC_LVSC_LVRBLPF_MASK, (v))
#define PMC_LVSC_LVR25F_MASK BIT(20)
#define PMC_LVSC_LVR25F(v) FIELD_PREP(PMC_LVSC_LVR25F_MASK, (v))
#define PMC_LVSC_LVR25LPF_MASK BIT(21)
#define PMC_LVSC_LVR25LPF(v) FIELD_PREP(PMC_LVSC_LVR25LPF_MASK, (v))
#define PMC_LVSC_LVR11F_MASK BIT(22)
#define PMC_LVSC_LVR11F(v) FIELD_PREP(PMC_LVSC_LVR11F_MASK, (v))
#define PMC_LVSC_LVR11LPF_MASK BIT(23)
#define PMC_LVSC_LVR11LPF(v) FIELD_PREP(PMC_LVSC_LVR11LPF_MASK, (v))
#define PMC_LVSC_GNG25OSCF_MASK BIT(24)
#define PMC_LVSC_GNG25OSCF(v) FIELD_PREP(PMC_LVSC_GNG25OSCF_MASK, (v))
#define PMC_LVSC_GNG11OSCF_MASK BIT(25)
#define PMC_LVSC_GNG11OSCF(v) FIELD_PREP(PMC_LVSC_GNG11OSCF_MASK, (v))
#define PMC_LVSC_PORF_MASK BIT(31)
#define PMC_LVSC_PORF(v) FIELD_PREP(PMC_LVSC_PORF_MASK, (v))
/* PMC Configuration Register */
#define PMC_CONFIG 0x4
#define PMC_CONFIG_LMEN_MASK BIT(0)
#define PMC_CONFIG_LMEN(v) FIELD_PREP(PMC_CONFIG_LMEN_MASK, (v))
#define PMC_CONFIG_LMBCTLEN_MASK BIT(1)
#define PMC_CONFIG_LMBCTLEN(v) FIELD_PREP(PMC_CONFIG_LMBCTLEN_MASK, (v))
#define PMC_CONFIG_FASTREC_MASK BIT(2)
#define PMC_CONFIG_FASTREC(v) FIELD_PREP(PMC_CONFIG_FASTREC_MASK, (v))
#define PMC_CONFIG_LPM25EN_MASK BIT(3)
#define PMC_CONFIG_LPM25EN(v) FIELD_PREP(PMC_CONFIG_LPM25EN_MASK, (v))
#define PMC_CONFIG_LVRBLPEN_MASK BIT(4)
#define PMC_CONFIG_LVRBLPEN(v) FIELD_PREP(PMC_CONFIG_LVRBLPEN_MASK, (v))
#define PMC_CONFIG_HVDIE_MASK BIT(8)
#define PMC_CONFIG_HVDIE(v) FIELD_PREP(PMC_CONFIG_HVDIE_MASK, (v))
#define PMC_CONFIG_LVDIE_MASK BIT(9)
#define PMC_CONFIG_LVDIE(v) FIELD_PREP(PMC_CONFIG_LVDIE_MASK, (v))
#define PMC_CONFIG_LMAUTOEN_MASK BIT(16)
#define PMC_CONFIG_LMAUTOEN(v) FIELD_PREP(PMC_CONFIG_LMAUTOEN_MASK, (v))
#define PMC_CONFIG_LMSTAT_MASK BIT(17)
#define PMC_CONFIG_LMSTAT(v) FIELD_PREP(PMC_CONFIG_LMSTAT_MASK, (v))
/* Version ID register */
#define PMC_VERID 0xc
#define PMC_VERID_LMFEAT_MASK BIT(0)
#define PMC_VERID_LMFEAT(v) FIELD_PREP(PMC_VERID_LMFEAT_MASK, (v))
#define PMC_VERID_MINOR_MASK GENMASK(23, 16)
#define PMC_VERID_MINOR(v) FIELD_PREP(PMC_VERID_MINOR_MASK, (v))
#define PMC_VERID_MAJOR_MASK GENMASK(31, 24)
#define PMC_VERID_MAJOR(v) FIELD_PREP(PMC_VERID_MAJOR_MASK, (v))
/* Handy accessors */
#define REG_READ(r) sys_read32((mem_addr_t)(DT_INST_REG_ADDR(0) + (r)))
#define REG_WRITE(r, v) sys_write32((v), (mem_addr_t)(DT_INST_REG_ADDR(0) + (r)))
#define PMC_TIMEOUT_US 10000U
static int pmc_init(const struct device *dev)
{
uint32_t reg_val;
ARG_UNUSED(dev);
/* Clear Low Voltage Status flags after initial power ramp-up */
REG_WRITE(PMC_LVSC, 0xffffffffU);
/* Last Mile regulator initialization */
reg_val = PMC_CONFIG_LMEN(DT_INST_PROP(0, lm_reg)) |
PMC_CONFIG_LMAUTOEN(DT_INST_PROP(0, lm_reg_auto)) |
PMC_CONFIG_LMBCTLEN(DT_INST_PROP(0, lm_reg_base_control));
if (DT_INST_PROP(0, lm_reg)) {
REG_WRITE(PMC_CONFIG, reg_val & ~PMC_CONFIG_LMEN_MASK);
/*
* If external BJT is using on the PCB board, wait for the LVD15 to go above
* low-voltage detect threshold before enabling LMEN
*/
if (DT_INST_PROP(0, lm_reg_base_control)) {
if (!WAIT_FOR(FIELD_GET(PMC_LVSC_LVD15S_MASK, REG_READ(PMC_LVSC)) == 0U,
PMC_TIMEOUT_US, k_busy_wait(10U))) {
return -ETIMEDOUT;
}
}
REG_WRITE(PMC_CONFIG, REG_READ(PMC_CONFIG) | PMC_CONFIG_LMEN(1U));
} else {
REG_WRITE(PMC_CONFIG, reg_val);
if (DT_INST_PROP(0, lm_reg_auto)) {
/* Wait for Last Mile regulator to be turned on */
if (!WAIT_FOR(FIELD_GET(PMC_CONFIG_LMSTAT_MASK, REG_READ(PMC_CONFIG)) == 1U,
PMC_TIMEOUT_US, k_busy_wait(10U))) {
return -ETIMEDOUT;
}
}
}
return 0;
}
DEVICE_DT_INST_DEFINE(0, pmc_init, NULL, NULL, 0, PRE_KERNEL_1, 1, NULL);

2
west.yml

@ -198,7 +198,7 @@ manifest: @@ -198,7 +198,7 @@ manifest:
groups:
- hal
- name: hal_nxp
revision: 220a4b285d226483a846e41d95abf8ab415b83e3
revision: 4f9ef3bc4e9ff1a2a57c8add2ab2a02b2162989b
path: modules/hal/nxp
groups:
- hal

Loading…
Cancel
Save