summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorNeil Armstrong <neil.armstrong@linaro.org>2025-03-28 09:53:24 +0100
committerCaleb Connolly <caleb.connolly@linaro.org>2025-04-10 15:43:10 +0200
commit5b233442afacde1aca2556c543b1cd8e22946690 (patch)
treef6bdb88c5ee89ee7d819a725800137f688832877 /drivers
parent69400a696cb823075990048eac5c4ed857229daf (diff)
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 <neil.armstrong@linaro.org> 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 <caleb.connolly@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/spmi/spmi-msm.c22
1 files 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)