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 <tswathi@qualcomm.corp-partner.google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/90467
Reviewed-by: Kapil Porwal <kapilporwal@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Swathi Tamilselvan 2025-12-10 22:40:07 +05:30 committed by Matt DeVillier
commit 02e6f2a214
5 changed files with 291 additions and 0 deletions

View file

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

View file

@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <device/device.h>
#include <console/console.h>
#include <timer.h>
#include <soc/addressmap.h>
#include <soc/cmd_db.h>
#include <soc/rpmh.h>
#include <soc/rpmh_bcm.h>
#include <soc/rpmh_config.h>
#include <soc/rpmh_regulator.h>
/**
* 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;
}

View file

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

View file

@ -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 <types.h>
/*
* 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_ */

View file

@ -0,0 +1,165 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <device/device.h>
#include <console/console.h>
#include <device/device.h>
#include <device/mmio.h>
#include <string.h>
#include <soc/addressmap.h>
#include <soc/rpmh_config.h>
#include <soc/rpmh_internal.h>
#include <soc/rpmh_rsc.h>
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;
}