fix(smmu): set root port CR0 GPCEN before ACCESSEN

In the SMMU root port programming model, changing both
SMMU_ROOT_CR0.GPCEN and ACCESSEN bits in the same MMIO write operation
is permitted by the architecture but left to the SMMU IP implementation
to determine the order of completing one or the other operation.

Enforce more determinism by setting CR0.GPCEN, wait for CR0ACK.GPCEN
completion, then setting CR0.ACCESSEN and wait for CR0ACK.ACCESSEN
completion.

Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
Change-Id: I36ba5fbc13d06c6243226008d18a2d57477b0d28
This commit is contained in:
Olivier Deprez 2025-01-07 17:27:05 +01:00
parent 9244331f35
commit 8cc972421f

View file

@ -124,22 +124,35 @@ int __init smmuv3_init(uintptr_t smmu_base)
gptbr_el3 << 12);
/*
* ACCESSEN=1: SMMU- and client-originated accesses are
* not terminated by this mechanism.
* GPCEN=1: All clients and SMMU-originated accesses,
* except GPT-walks, are subject to GPC.
*
* It is recommended to set GPCEN and wait for completion
* prior to setting ACCESSEN.
*/
mmio_setbits_32(smmu_base + SMMU_ROOT_CR0,
SMMU_ROOT_CR0_GPCEN);
/* Poll for GPCEN ack bit. */
if (smmuv3_poll(smmu_base + SMMU_ROOT_CR0ACK,
SMMU_ROOT_CR0_GPCEN,
SMMU_ROOT_CR0_GPCEN) != 0) {
WARN("Failed enabling SMMU GPC.\n");
}
/*
* ACCESSEN=1: SMMU- and client-originated accesses are
* not terminated by this mechanism.
*/
mmio_setbits_32(smmu_base + SMMU_ROOT_CR0,
SMMU_ROOT_CR0_GPCEN |
SMMU_ROOT_CR0_ACCESSEN);
/* Poll for ACCESSEN and GPCEN ack bits. */
/* Poll for ACCESSEN ack bit. */
if (smmuv3_poll(smmu_base + SMMU_ROOT_CR0ACK,
SMMU_ROOT_CR0_GPCEN |
SMMU_ROOT_CR0_ACCESSEN,
SMMU_ROOT_CR0_GPCEN |
SMMU_ROOT_CR0_ACCESSEN) != 0) {
WARN("Failed enabling SMMU GPC.\n");
WARN("Failed enabling SMMU ACCESS.\n");
/*
* Do not return in error, but fall back to