19756bcc4SClement Faure // SPDX-License-Identifier: BSD-2-Clause
29756bcc4SClement Faure /*
3*35e561d8SSahil Malhotra * Copyright 2022-2023, 2025 NXP
49756bcc4SClement Faure */
59756bcc4SClement Faure #include <assert.h>
69756bcc4SClement Faure #include <drivers/imx_mu.h>
7*35e561d8SSahil Malhotra #include <imx-regs.h>
89756bcc4SClement Faure #include <kernel/delay.h>
99756bcc4SClement Faure #include <kernel/spinlock.h>
109756bcc4SClement Faure #include <string.h>
119756bcc4SClement Faure #include <trace.h>
129756bcc4SClement Faure
139756bcc4SClement Faure #include "imx_mu_platform.h"
149756bcc4SClement Faure
159756bcc4SClement Faure #define RX_TIMEOUT (100 * 1000)
169756bcc4SClement Faure
17*35e561d8SSahil Malhotra #if defined(CFG_MX93) || defined(CFG_MX91)
18*35e561d8SSahil Malhotra #define IS_MU_TRUST (MU_BASE == MU_TRUST_BASE)
19*35e561d8SSahil Malhotra #else
20*35e561d8SSahil Malhotra #define IS_MU_TRUST false
21*35e561d8SSahil Malhotra #endif
22*35e561d8SSahil Malhotra
239756bcc4SClement Faure static unsigned int mu_spinlock = SPINLOCK_UNLOCK;
249756bcc4SClement Faure
imx_mu_plat_init(vaddr_t base __unused)259756bcc4SClement Faure __weak void imx_mu_plat_init(vaddr_t base __unused)
269756bcc4SClement Faure {
279756bcc4SClement Faure }
289756bcc4SClement Faure
imx_mu_plat_send(vaddr_t base __unused,unsigned int index __unused,uint32_t msg __unused)299756bcc4SClement Faure __weak TEE_Result imx_mu_plat_send(vaddr_t base __unused,
309756bcc4SClement Faure unsigned int index __unused,
319756bcc4SClement Faure uint32_t msg __unused)
329756bcc4SClement Faure {
339756bcc4SClement Faure return TEE_ERROR_NOT_IMPLEMENTED;
349756bcc4SClement Faure }
359756bcc4SClement Faure
imx_mu_plat_receive(vaddr_t base __unused,unsigned int index __unused,uint32_t * msg __unused)369756bcc4SClement Faure __weak TEE_Result imx_mu_plat_receive(vaddr_t base __unused,
379756bcc4SClement Faure unsigned int index __unused,
389756bcc4SClement Faure uint32_t *msg __unused)
399756bcc4SClement Faure {
409756bcc4SClement Faure return TEE_ERROR_NOT_IMPLEMENTED;
419756bcc4SClement Faure }
429756bcc4SClement Faure
439756bcc4SClement Faure /*
449756bcc4SClement Faure * Receive a message via the MU
459756bcc4SClement Faure *
469756bcc4SClement Faure * @base: virtual base address of the MU controller
479756bcc4SClement Faure * @[out]msg: message received
489756bcc4SClement Faure */
imx_mu_receive_msg(vaddr_t base,struct imx_mu_msg * msg)499756bcc4SClement Faure static TEE_Result imx_mu_receive_msg(vaddr_t base, struct imx_mu_msg *msg)
509756bcc4SClement Faure {
519756bcc4SClement Faure TEE_Result res = TEE_ERROR_GENERIC;
529756bcc4SClement Faure unsigned int count = 0;
539756bcc4SClement Faure uint32_t response = 0;
549756bcc4SClement Faure unsigned int nb_channel = 0;
559756bcc4SClement Faure uint64_t tout_rx = timeout_init_us(RX_TIMEOUT);
569756bcc4SClement Faure
579756bcc4SClement Faure assert(base && msg);
589756bcc4SClement Faure
599756bcc4SClement Faure do {
609756bcc4SClement Faure res = imx_mu_plat_receive(base, 0, &response);
619756bcc4SClement Faure if (timeout_elapsed(tout_rx))
629756bcc4SClement Faure break;
639756bcc4SClement Faure } while (res == TEE_ERROR_NO_DATA);
649756bcc4SClement Faure
659756bcc4SClement Faure if (res)
669756bcc4SClement Faure return res;
679756bcc4SClement Faure
689756bcc4SClement Faure memcpy(&msg->header, &response, sizeof(response));
699756bcc4SClement Faure
709756bcc4SClement Faure /* Check the size of the message to receive */
719756bcc4SClement Faure if (msg->header.size > IMX_MU_MSG_SIZE) {
729756bcc4SClement Faure EMSG("Size of the message is > than IMX_MU_MSG_SIZE");
739756bcc4SClement Faure return TEE_ERROR_BAD_FORMAT;
749756bcc4SClement Faure }
759756bcc4SClement Faure
76c4023a0fSSahil Malhotra nb_channel = imx_mu_plat_get_rx_channel(base);
779756bcc4SClement Faure
789756bcc4SClement Faure for (count = 1; count < msg->header.size; count++) {
799756bcc4SClement Faure res = imx_mu_plat_receive(base, count % nb_channel,
809756bcc4SClement Faure &msg->data.u32[count - 1]);
819756bcc4SClement Faure if (res)
829756bcc4SClement Faure return res;
839756bcc4SClement Faure }
849756bcc4SClement Faure
859756bcc4SClement Faure return TEE_SUCCESS;
869756bcc4SClement Faure }
879756bcc4SClement Faure
889756bcc4SClement Faure /*
899756bcc4SClement Faure * Send a message via the MU
909756bcc4SClement Faure *
919756bcc4SClement Faure * @base: virtual base address of the MU controller
929756bcc4SClement Faure * @[in]msg: message to send
939756bcc4SClement Faure */
imx_mu_send_msg(vaddr_t base,struct imx_mu_msg * msg)949756bcc4SClement Faure static TEE_Result imx_mu_send_msg(vaddr_t base, struct imx_mu_msg *msg)
959756bcc4SClement Faure {
969756bcc4SClement Faure TEE_Result res = TEE_ERROR_GENERIC;
979756bcc4SClement Faure unsigned int count = 0;
989756bcc4SClement Faure unsigned int nb_channel = 0;
99*35e561d8SSahil Malhotra unsigned int start_index = 0;
100*35e561d8SSahil Malhotra unsigned int end_index = 0;
1019756bcc4SClement Faure uint32_t word = 0;
1029756bcc4SClement Faure
1039756bcc4SClement Faure assert(base && msg);
1049756bcc4SClement Faure
1059756bcc4SClement Faure if (msg->header.size > IMX_MU_MSG_SIZE) {
1069756bcc4SClement Faure EMSG("msg->size is > than IMX_MU_MSG_SIZE");
1079756bcc4SClement Faure return TEE_ERROR_BAD_FORMAT;
1089756bcc4SClement Faure }
1099756bcc4SClement Faure
110*35e561d8SSahil Malhotra if (IS_MU_TRUST) {
111*35e561d8SSahil Malhotra /*
112*35e561d8SSahil Malhotra * make sure command (bit[31:26]) is higher than SCM_CR2_CMD_VAL
113*35e561d8SSahil Malhotra * SCM_CR2_CMD_VAL is set to 0 by ELE FW. but let’s use
114*35e561d8SSahil Malhotra * max value.
115*35e561d8SSahil Malhotra */
116*35e561d8SSahil Malhotra word |= GENMASK_32(31, 26);
117*35e561d8SSahil Malhotra
118*35e561d8SSahil Malhotra /* size (including dummy header) -> bit[19:16]*/
119*35e561d8SSahil Malhotra word |= SHIFT_U32(((msg->header.size + 1) & GENMASK_32(3, 0)),
120*35e561d8SSahil Malhotra 16);
121*35e561d8SSahil Malhotra
122*35e561d8SSahil Malhotra res = imx_mu_plat_send(base, start_index, word);
1239756bcc4SClement Faure if (res)
1249756bcc4SClement Faure return res;
1259756bcc4SClement Faure
126*35e561d8SSahil Malhotra start_index++;
127*35e561d8SSahil Malhotra memcpy(&word, &msg->header, sizeof(uint32_t));
128*35e561d8SSahil Malhotra res = imx_mu_plat_send(base, start_index, word);
129*35e561d8SSahil Malhotra if (res)
130*35e561d8SSahil Malhotra return res;
1319756bcc4SClement Faure
132*35e561d8SSahil Malhotra start_index++;
133*35e561d8SSahil Malhotra /*
134*35e561d8SSahil Malhotra * TR15 is reserved for special USM commands
135*35e561d8SSahil Malhotra */
136*35e561d8SSahil Malhotra nb_channel = imx_mu_plat_get_tx_channel(base) - 1;
137*35e561d8SSahil Malhotra end_index = msg->header.size + 1;
138*35e561d8SSahil Malhotra assert(end_index < nb_channel);
139*35e561d8SSahil Malhotra } else {
140*35e561d8SSahil Malhotra memcpy(&word, &msg->header, sizeof(uint32_t));
141*35e561d8SSahil Malhotra res = imx_mu_plat_send(base, start_index, word);
142*35e561d8SSahil Malhotra if (res)
143*35e561d8SSahil Malhotra return res;
144*35e561d8SSahil Malhotra
145*35e561d8SSahil Malhotra start_index++;
146*35e561d8SSahil Malhotra nb_channel = imx_mu_plat_get_tx_channel(base);
147*35e561d8SSahil Malhotra end_index = msg->header.size;
148*35e561d8SSahil Malhotra }
149*35e561d8SSahil Malhotra
150*35e561d8SSahil Malhotra for (count = start_index; count < end_index; count++) {
1519756bcc4SClement Faure res = imx_mu_plat_send(base, count % nb_channel,
152*35e561d8SSahil Malhotra msg->data.u32[count - start_index]);
1539756bcc4SClement Faure if (res)
1549756bcc4SClement Faure return res;
1559756bcc4SClement Faure }
1569756bcc4SClement Faure
1579756bcc4SClement Faure return TEE_SUCCESS;
1589756bcc4SClement Faure }
1599756bcc4SClement Faure
imx_mu_init(vaddr_t base)1609756bcc4SClement Faure void imx_mu_init(vaddr_t base)
1619756bcc4SClement Faure {
1629756bcc4SClement Faure uint32_t exceptions = 0;
1639756bcc4SClement Faure
1649756bcc4SClement Faure if (!base) {
1659756bcc4SClement Faure EMSG("Bad MU base address");
1669756bcc4SClement Faure return;
1679756bcc4SClement Faure }
1689756bcc4SClement Faure
1699756bcc4SClement Faure exceptions = cpu_spin_lock_xsave(&mu_spinlock);
1709756bcc4SClement Faure
1719756bcc4SClement Faure imx_mu_plat_init(base);
1729756bcc4SClement Faure
1739756bcc4SClement Faure cpu_spin_unlock_xrestore(&mu_spinlock, exceptions);
1749756bcc4SClement Faure }
1759756bcc4SClement Faure
imx_mu_call(vaddr_t base,struct imx_mu_msg * msg,bool wait_for_answer)1769756bcc4SClement Faure TEE_Result imx_mu_call(vaddr_t base, struct imx_mu_msg *msg,
1779756bcc4SClement Faure bool wait_for_answer)
1789756bcc4SClement Faure {
1799756bcc4SClement Faure TEE_Result res = TEE_ERROR_GENERIC;
1809756bcc4SClement Faure uint32_t exceptions = 0;
1819756bcc4SClement Faure
1829756bcc4SClement Faure if (!base || !msg)
1839756bcc4SClement Faure return TEE_ERROR_BAD_PARAMETERS;
1849756bcc4SClement Faure
1859756bcc4SClement Faure exceptions = cpu_spin_lock_xsave(&mu_spinlock);
1869756bcc4SClement Faure
1879756bcc4SClement Faure res = imx_mu_send_msg(base, msg);
1889756bcc4SClement Faure if (res == TEE_SUCCESS && wait_for_answer)
1899756bcc4SClement Faure res = imx_mu_receive_msg(base, msg);
1909756bcc4SClement Faure
1919756bcc4SClement Faure cpu_spin_unlock_xrestore(&mu_spinlock, exceptions);
1929756bcc4SClement Faure
1939756bcc4SClement Faure return res;
1949756bcc4SClement Faure }
195