From 5b233442afacde1aca2556c543b1cd8e22946690 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 28 Mar 2025 09:53:24 +0100 Subject: [PATCH] spmi: msm: correctly handle multiple mapping entries On v5 & v7 controllers, multiple mapping for different Execution Environment exists, if the mapping owner is for a different Execution Environment we can only read and not write any data. To allow us to find a Write mapping for our Execution Environment, we can overwritte a mapping if we encounter a new one which we own. Implement this logic, the result is the same mapping table as in Linux. Signed-off-by: Neil Armstrong Tested-by: caleb.connolly@linaro.org # sdm845 Link: https://lore.kernel.org/r/20250328-topic-sm8x50-spmi-fix-v1-4-a7548d3aef0d@linaro.org Signed-off-by: Caleb Connolly --- drivers/spmi/spmi-msm.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/spmi/spmi-msm.c b/drivers/spmi/spmi-msm.c index ee3feaf8b50..faae54e9fef 100644 --- a/drivers/spmi/spmi-msm.c +++ b/drivers/spmi/spmi-msm.c @@ -254,16 +254,30 @@ static struct dm_spmi_ops msm_spmi_ops = { .write = msm_spmi_write, }; +/* + * In order to allow multiple EEs to write to a single PPID in arbiter + * version 5 and 7, there is more than one APID mapped to each PPID. + * The owner field for each of these mappings specifies the EE which is + * allowed to write to the APID. + */ static void msm_spmi_channel_map_v5(struct msm_spmi_priv *priv, unsigned int i, uint8_t slave_id, uint8_t pid) { /* Mark channels read-only when from different owner */ uint32_t cnfg = readl(priv->spmi_cnfg + ARB_CHANNEL_OFFSET(i)); uint8_t owner = SPMI_OWNERSHIP_PERIPH2OWNER(cnfg); - - priv->channel_map[slave_id][pid] = i | SPMI_CHANNEL_VALID; - if (owner != priv->owner) - priv->channel_map[slave_id][pid] |= SPMI_CHANNEL_READ_ONLY; + bool prev_valid = priv->channel_map[slave_id][pid] & SPMI_CHANNEL_VALID; + uint32_t prev_read_only = priv->channel_map[slave_id][pid] & SPMI_CHANNEL_READ_ONLY; + + if (!prev_valid) { + /* First PPID mapping */ + priv->channel_map[slave_id][pid] = i | SPMI_CHANNEL_VALID; + if (owner != priv->owner) + priv->channel_map[slave_id][pid] |= SPMI_CHANNEL_READ_ONLY; + } else if ((owner == priv->owner) && prev_read_only) { + /* Read only and we found one we own, switch */ + priv->channel_map[slave_id][pid] = i | SPMI_CHANNEL_VALID; + } } static int msm_spmi_probe(struct udevice *dev) -- 2.39.5