From 02e6f2a21486613b1acbc1f4a028588c4cc617a0 Mon Sep 17 00:00:00 2001 From: Swathi Tamilselvan Date: Wed, 10 Dec 2025 22:40:07 +0530 Subject: [PATCH] soc/qualcomm/x1p42100: Add API to intialize RPMh resources for display Add API to initialize RPMh resources for display. It includes CMD-DB initialization, enable the MMCX power rail and cast a vote for the MM0 Bus Clock Manager (BCM) resource to enable display clocks. Test=1. Create an image.serial.bin and ensure it boots on X1P42100. 2. Verified MMCX rail enablement and MM0 BCM vote using ARC and BCM AOP dump with API invoking changes hooked up with follow-on commits. Serial Log: [INFO ] RPMH_REG: Initialized mmcx.lvl at addr=0x30080 [INFO ] ARC regulator initialized successfully [DEBUG] RPMH_REG: Sent active request for mmcx.lvl [INFO ] ARC level was set successfully [DEBUG] BCM: Found address 0x00050024 for resource MM0 [INFO ] BCM: Successfully voted for MM0 (addr=0x00050024, val=0x60004001) [INFO ] BCM vote for MM0 sent successfully Change-Id: I1997ce7a1ced4504d6a3170e5f2ddd4f52e0763d Signed-off-by: Swathi Tamilselvan Reviewed-on: https://review.coreboot.org/c/coreboot/+/90467 Reviewed-by: Kapil Porwal Tested-by: build bot (Jenkins) --- src/soc/qualcomm/x1p42100/Makefile.mk | 2 + src/soc/qualcomm/x1p42100/display/disp.c | 76 ++++++++ .../x1p42100/include/soc/addressmap.h | 6 + .../x1p42100/include/soc/rpmh_config.h | 42 +++++ src/soc/qualcomm/x1p42100/rpmh_rsc_init.c | 165 ++++++++++++++++++ 5 files changed, 291 insertions(+) create mode 100644 src/soc/qualcomm/x1p42100/display/disp.c create mode 100644 src/soc/qualcomm/x1p42100/include/soc/rpmh_config.h create mode 100644 src/soc/qualcomm/x1p42100/rpmh_rsc_init.c diff --git a/src/soc/qualcomm/x1p42100/Makefile.mk b/src/soc/qualcomm/x1p42100/Makefile.mk index 46965a5375..4a51a20dd6 100644 --- a/src/soc/qualcomm/x1p42100/Makefile.mk +++ b/src/soc/qualcomm/x1p42100/Makefile.mk @@ -54,6 +54,8 @@ ramstage-$(CONFIG_PCI) += pcie.c ramstage-y += cpucp_load_reset.c ramstage-y += ../common/cmd_db.c ramstage-y += ../common/rpmh.c ../common/rpmh_bcm.c ../common/rpmh_regulator.c ../common/rpmh_rsc.c +ramstage-y += rpmh_rsc_init.c +ramstage-y += display/disp.c ################################################################################ diff --git a/src/soc/qualcomm/x1p42100/display/disp.c b/src/soc/qualcomm/x1p42100/display/disp.c new file mode 100644 index 0000000000..f09adab34f --- /dev/null +++ b/src/soc/qualcomm/x1p42100/display/disp.c @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * display_rpmh_init() - Initialize RPMh for display power management + * + * Initializes the RPMh (Resource Power Manager-Hardened) subsystem for display: + * - Waits for AOP boot + * - Initializes Command DB and RPMh RSC (Resource State Coordinator) + * - Configures MMCX ARC regulator for display power rail + * - Votes for MM0 BCM (Bus Clock Manager) for display bus clocks + * + * Return: CB_SUCCESS on success, CB_ERR on failure + */ +enum cb_err display_rpmh_init(void) +{ + enum cb_err ret; + struct rpmh_vreg arc_reg; + int rc; + volatile u32 *boot_cookie = (volatile u32 *)AOP_BOOT_COOKIE_ADDR; + + if (!wait_us(AOP_BOOT_TIMEOUT_US, *boot_cookie == AOP_BOOT_COOKIE)) { + printk(BIOS_ERR, "AOP not booted after %dus (cookie: 0x%x, expected: 0x%x)\n", + AOP_BOOT_TIMEOUT_US, *boot_cookie, AOP_BOOT_COOKIE); + return CB_ERR; + } + + printk(BIOS_INFO, "AOP boot detected (cookie: 0x%x)\n", *boot_cookie); + + ret = cmd_db_init(CMD_DB_BASE_ADDR, CMD_DB_SIZE); + if (ret != CB_SUCCESS) { + printk(BIOS_ERR, "Failed to initialize Command DB\n"); + return CB_ERR; + } + + rc = rpmh_rsc_init(); + if (rc) { + printk(BIOS_ERR, "Failed to initialize RPMh RSC\n"); + return CB_ERR; + } + + rc = rpmh_regulator_init(&arc_reg, "mmcx.lvl", RPMH_REGULATOR_TYPE_ARC); + if (rc) { + printk(BIOS_ERR, "Failed to initialize display power rail mmcx ARC regulator\n"); + return CB_ERR; + } + + printk(BIOS_INFO, "ARC regulator initialized successfully\n"); + + rc = rpmh_regulator_arc_set_level(&arc_reg, RPMH_REGULATOR_LEVEL_MIN_MM0, true, false); + if (rc) { + printk(BIOS_ERR, "Failed to set ARC level\n"); + return CB_ERR; + } + + printk(BIOS_INFO, "ARC level was set successfully\n"); + + rc = rpmh_bcm_vote("MM0", BCM_MM0_VOTE_VALUE); + if (rc) { + printk(BIOS_ERR, "Failed to send BCM vote for display bus clock manager MM0\n"); + return CB_ERR; + } + + printk(BIOS_INFO, "BCM vote for MM0 sent successfully\n"); + + return CB_SUCCESS; +} diff --git a/src/soc/qualcomm/x1p42100/include/soc/addressmap.h b/src/soc/qualcomm/x1p42100/include/soc/addressmap.h index 1c309a06d4..8b22662e92 100644 --- a/src/soc/qualcomm/x1p42100/include/soc/addressmap.h +++ b/src/soc/qualcomm/x1p42100/include/soc/addressmap.h @@ -18,6 +18,12 @@ #define DISP_PLL1_BASE 0xAF01000 #define DISP_CC_BASE 0xAF08000 +#define RPMH_BASE 0x17520000 +#define CMD_DB_BASE_ADDR 0x81c60000 +#define CMD_DB_SIZE 0x20000 + +#define AOP_BOOT_COOKIE_ADDR 0xC3F0040 + #define CBMEM_TOP 0xC7800000 /* X1P42100 NCC0 PLL CONFIG ADDRESSES */ #define NCC0_NCC_CMU_NCC_PLL_CFG 0x199A2010 diff --git a/src/soc/qualcomm/x1p42100/include/soc/rpmh_config.h b/src/soc/qualcomm/x1p42100/include/soc/rpmh_config.h new file mode 100644 index 0000000000..c1f9c4630c --- /dev/null +++ b/src/soc/qualcomm/x1p42100/include/soc/rpmh_config.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_QUALCOMM_X1P42100_RPMH_CONFIG_H_ +#define _SOC_QUALCOMM_X1P42100_RPMH_CONFIG_H_ + +#include + +/* + * X1P42100 RPMh RSC Configuration + */ + +#define RPMH_RSC_DRV_ID 2 + +#define RPMH_TCS_OFFSET 0xd00 +#define RPMH_TCS_DISTANCE 0x2a0 + +/* TCS Configuration */ +#define RPMH_NUM_ACTIVE_TCS 2 +#define RPMH_NUM_SLEEP_TCS 3 +#define RPMH_NUM_WAKE_TCS 3 +#define RPMH_NUM_CONTROL_TCS 0 +#define RPMH_NUM_FAST_PATH_TCS 0 + +#define RPMH_NUM_CHANNELS 1 + +#define RPMH_HW_SOLVER_SUPPORTED true +#define RPMH_HW_CHANNEL_MODE false + +#define RPMH_RSC_NAME "apps_rsc" + +#define RPMH_REGULATOR_LEVEL_MIN_MM0 1 +#define RPMH_REGULATOR_LEVEL_TURBO_MM0 6 + +#define BCM_MM0_VOTE_VALUE 0x60004001 + +#define AOP_BOOT_COOKIE 0xA0C00C1E +#define AOP_BOOT_TIMEOUT_US 200000 + +int rpmh_rsc_init(void); +enum cb_err display_rpmh_init(void); + +#endif /* _SOC_QUALCOMM_X1P42100_RPMH_CONFIG_H_ */ diff --git a/src/soc/qualcomm/x1p42100/rpmh_rsc_init.c b/src/soc/qualcomm/x1p42100/rpmh_rsc_init.c new file mode 100644 index 0000000000..7ddb3ac10d --- /dev/null +++ b/src/soc/qualcomm/x1p42100/rpmh_rsc_init.c @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct rsc_drv rsc_driver; +static struct cache_req non_batch_cache[CMD_DB_MAX_RESOURCES]; + +/** + * rpmh_rsc_init - Initialize the RPMh RSC driver + * + * Initializes the RPMh Resource State Coordinator driver with platform-specific configuration. + * Configuration is read from soc/rpmh_config.h for this chipset. + * + * Return: 0 on success, -1 on failure + */ +int rpmh_rsc_init(void) +{ + struct rsc_drv *drv = &rsc_driver; + u32 rsc_id, major_rsc_version, minor_rsc_version, config, max_tcs, ncpt; + int offset; + u32 solver_config; + + /* Check if already initialized */ + if (drv->initialized) { + printk(BIOS_INFO, "RPMH RSC: Already initialized, skipping re-initialization\n"); + return 0; + } + + memset(drv, 0, sizeof(*drv)); + + /* Set configuration from chipset-specific header */ + drv->base = (void *)RPMH_BASE; + drv->tcs_base = (void *)(RPMH_BASE + RPMH_TCS_OFFSET); + drv->tcs_distance = RPMH_TCS_DISTANCE; + drv->id = RPMH_RSC_DRV_ID; + drv->num_channels = RPMH_NUM_CHANNELS; + strncpy(drv->name, RPMH_RSC_NAME, sizeof(drv->name) - 1); + + /* Read hardware version */ + rsc_id = read32(drv->base); + major_rsc_version = (rsc_id >> 16) & 0xFF; + minor_rsc_version = (rsc_id >> 8) & 0xFF; + + /* Select register offsets based on version and HW channel mode */ + if (RPMH_HW_CHANNEL_MODE && major_rsc_version >= 3) { + drv->regs = rpmh_rsc_reg_offset_ver_3_0_hw_channel; + printk(BIOS_INFO, "RPMH RSC: Using v3.0 HW channel register offsets\n"); + } else if (major_rsc_version >= 3) { + drv->regs = rpmh_rsc_reg_offset_ver_3_0; + printk(BIOS_INFO, "RPMH RSC: Using v3.0 register offsets\n"); + } else { + drv->regs = rpmh_rsc_reg_offset_ver_2_7; + printk(BIOS_INFO, "RPMH RSC: Using v2.7 register offsets\n"); + } + + /* Read TCS configuration from hardware */ + config = read32(drv->base + drv->regs[DRV_PRNT_CHLD_CONFIG]); + max_tcs = (config >> (DRV_NUM_TCS_SHIFT * drv->id)) & DRV_NUM_TCS_MASK; + ncpt = (config >> DRV_NCPT_SHIFT) & DRV_NCPT_MASK; + + /* Configure TCS groups for Channel 0 - explicit approach */ + offset = 0; + drv->num_tcs = 0; + + if (RPMH_NUM_ACTIVE_TCS > 0) { + drv->ch[CH0].tcs[ACTIVE_TCS].drv = drv; + drv->ch[CH0].tcs[ACTIVE_TCS].type = ACTIVE_TCS; + drv->ch[CH0].tcs[ACTIVE_TCS].num_tcs = RPMH_NUM_ACTIVE_TCS; + drv->ch[CH0].tcs[ACTIVE_TCS].ncpt = ncpt; + drv->ch[CH0].tcs[ACTIVE_TCS].offset = offset; + drv->ch[CH0].tcs[ACTIVE_TCS].mask = ((1 << RPMH_NUM_ACTIVE_TCS) - 1) << offset; + offset += RPMH_NUM_ACTIVE_TCS; + drv->num_tcs += RPMH_NUM_ACTIVE_TCS; + printk(BIOS_DEBUG, "RPMH RSC: ACTIVE TCS: %d TCSes at offset %d (mask=0x%x)\n", + RPMH_NUM_ACTIVE_TCS, drv->ch[CH0].tcs[ACTIVE_TCS].offset, + drv->ch[CH0].tcs[ACTIVE_TCS].mask); + } + + if (RPMH_NUM_SLEEP_TCS > 0) { + drv->ch[CH0].tcs[SLEEP_TCS].drv = drv; + drv->ch[CH0].tcs[SLEEP_TCS].type = SLEEP_TCS; + drv->ch[CH0].tcs[SLEEP_TCS].num_tcs = RPMH_NUM_SLEEP_TCS; + drv->ch[CH0].tcs[SLEEP_TCS].ncpt = ncpt; + drv->ch[CH0].tcs[SLEEP_TCS].offset = offset; + drv->ch[CH0].tcs[SLEEP_TCS].mask = ((1 << RPMH_NUM_SLEEP_TCS) - 1) << offset; + offset += RPMH_NUM_SLEEP_TCS; + drv->num_tcs += RPMH_NUM_SLEEP_TCS; + printk(BIOS_DEBUG, "RPMH RSC: SLEEP TCS: %d TCSes at offset %d (mask=0x%x)\n", + RPMH_NUM_SLEEP_TCS, drv->ch[CH0].tcs[SLEEP_TCS].offset, + drv->ch[CH0].tcs[SLEEP_TCS].mask); + } + + if (RPMH_NUM_WAKE_TCS > 0) { + drv->ch[CH0].tcs[WAKE_TCS].drv = drv; + drv->ch[CH0].tcs[WAKE_TCS].type = WAKE_TCS; + drv->ch[CH0].tcs[WAKE_TCS].num_tcs = RPMH_NUM_WAKE_TCS; + drv->ch[CH0].tcs[WAKE_TCS].ncpt = ncpt; + drv->ch[CH0].tcs[WAKE_TCS].offset = offset; + drv->ch[CH0].tcs[WAKE_TCS].mask = ((1 << RPMH_NUM_WAKE_TCS) - 1) << offset; + offset += RPMH_NUM_WAKE_TCS; + drv->num_tcs += RPMH_NUM_WAKE_TCS; + printk(BIOS_DEBUG, "RPMH RSC: WAKE TCS: %d TCSes at offset %d (mask=0x%x)\n", + RPMH_NUM_WAKE_TCS, drv->ch[CH0].tcs[WAKE_TCS].offset, + drv->ch[CH0].tcs[WAKE_TCS].mask); + } + + /* Check if total TCS count exceeds hardware limit */ + if (drv->num_tcs > max_tcs) { + printk(BIOS_ERR, "RPMH RSC: TCS config exceeds hardware limit (configured: %d, max: %d)\n", + drv->num_tcs, max_tcs); + return -1; + } + + drv->ch[CH0].drv = drv; + drv->ch[CH0].initialized = true; + drv->client.non_batch_cache = non_batch_cache; + drv->client.non_batch_cache_idx = 0; + + for (int i = 0; i < CMD_DB_MAX_RESOURCES; i++) { + non_batch_cache[i].addr = 0; + non_batch_cache[i].sleep_val = UINT_MAX; + non_batch_cache[i].wake_val = UINT_MAX; + } + + /* Initialize TCS in-use bitmap */ + memset(drv->tcs_in_use, 0, sizeof(drv->tcs_in_use)); + + /* Detect solver mode from hardware */ + solver_config = read32(drv->base + drv->regs[DRV_SOLVER_CONFIG]); + solver_config = (solver_config >> 24) & 0x1; + + if (solver_config || RPMH_HW_SOLVER_SUPPORTED) { + drv->client.flags |= SOLVER_PRESENT; + printk(BIOS_INFO, "RPMH RSC: Hardware solver mode supported\n"); + + if (RPMH_HW_CHANNEL_MODE) { + drv->client.flags |= HW_CHANNEL_PRESENT; + drv->in_solver_mode = true; + drv->client.in_solver_mode = true; + printk(BIOS_INFO, "RPMH RSC: HW channel mode enabled\n"); + } else { + drv->in_solver_mode = false; + drv->client.in_solver_mode = false; + printk(BIOS_INFO, "RPMH RSC: Software control mode\n"); + } + } else { + printk(BIOS_INFO, "RPMH RSC: Hardware solver mode not supported\n"); + } + + drv->initialized = true; + + rpmh_set_rsc_drv(drv); + + printk(BIOS_INFO, "RPMH RSC: Initialized %s (drv-%d) at 0x%lx Version %d.%d\n", + drv->name, drv->id, (uintptr_t)drv->base, major_rsc_version, minor_rsc_version); + + return 0; +}