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; +}