blob: 93cef28e0a4c010babe7888b1fce48fb8cbbc003 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <config.h>
#include <common.h>
#include <asm/arch/io.h>
#include <command.h>
#include <malloc.h>
#include <asm/arch/mailbox.h>
#include <asm/arch/secure_apb.h>
#define aml_writel32(value, reg) writel(value, reg)
#define aml_readl32(reg) readl(reg)
static inline void mbwrite(uint32_t to, void *from, long count)
{
int i = 0;
int len = count / 4 + (count % 4);
uint32_t *p = from;
while (len > 0) {
aml_writel32(p[i], to + (4 * i));
len--;
i++;
}
}
static inline void mbclean(uint32_t to, long count)
{
int i = 0;
int len = count / 4 + (count % 4);
while (len > 0) {
aml_writel32(0, to + (4 * i));
len--;
i++;
}
}
int mhu_get_addr(uint32_t chan, uint32_t *mboxset, uint32_t *mboxsts,
uintptr_t *mboxpl, uint32_t *mboxwr, uint32_t *mboxrd,
uint32_t *mboxirqclr, uint32_t *mboxid)
{
int ret = 0;
switch (chan) {
case AOCPU_REE_CHANNEL:
*mboxset = REE2AO_SET_ADDR;
*mboxsts = REE2AO_STS_ADDR;
*mboxwr = REE2AO_WR_ADDR;
*mboxrd = REE2AO_RD_ADDR;
*mboxirqclr = REE2AO_IRQCLR_ADDR;
*mboxid = REE2AO_MBOX_ID;
break;
default:
printf("[BL33]: no support chan 0x%x\n", chan);
ret = -1;
break;
};
return ret;
}
void mhu_message_start(uint32_t mboxsts)
{
/* Make sure any previous command has finished */
while (aml_readl32(mboxsts) != 0);
}
void mhu_build_payload(uintptr_t mboxpl, uint32_t mboxwr, void *message, uint32_t size)
{
if (size > (MHU_PAYLOAD_SIZE - MHU_DATA_OFFSET)) {
printf("bl33: scpi send input size error\n");
return;
}
if (size == 0)
return;
mbwrite(mboxwr + MHU_DATA_OFFSET, message, size);
}
void mhu_get_payload(uintptr_t mboxpl, uint32_t mboxwr, void *message, uint32_t size)
{
if (size > (MHU_PAYLOAD_SIZE - MHU_DATA_OFFSET)) {
printf("bl33: scpi send input size error\n");
return;
}
if (size == 0)
return;
printf("bl33: scpi no support get revmessage\n");
}
void mhu_message_send(uint32_t mboxset, uint32_t command, uint32_t size)
{
uint32_t mbox_cmd;
mbox_cmd = MHU_CMD_BUILD(command, size + MHU_DATA_OFFSET);
aml_writel32(mbox_cmd, mboxset);
}
uint32_t mhu_message_wait(uint32_t mboxsts)
{
/* Wait for response from HIFI */
uint32_t response;
while ((response = aml_readl32(mboxsts)));
return response;
}
void mhu_message_end(uintptr_t mboxpl, uint32_t mboxwr, uint32_t mboxirqclr, uint32_t mboxid)
{
mbclean(mboxwr, MHU_PAYLOAD_SIZE);
/* Clear any response we got by writing all ones to the CLEAR register */
aml_writel32(MHU_ACK_MASK(mboxid), mboxirqclr);
}
void mhu_init(void)
{
aml_writel32(0xffffffffu, REE2AO_CLR_ADDR);
printf("[BL33] mhu init done -v2\n");
}
int scpi_send_data(uint32_t chan, uint32_t command,
void *sendmessage, uint32_t sendsize,
void *revmessage, uint32_t revsize)
{
uint32_t mboxset = 0;
uint32_t mboxsts = 0;
uintptr_t mboxpl = 0;
uint32_t mboxwr = 0;
uint32_t mboxrd = 0;
uint32_t mboxirq = 0;
uint32_t mboxid = 0;
int ret = 0;
ret = mhu_get_addr(chan, &mboxset, &mboxsts,
&mboxpl, &mboxwr, &mboxrd,
&mboxirq, &mboxid);
if (ret) {
printf("bl33: mhu get addr fail\n");
return ret;
}
mhu_message_start(mboxsts);
if (sendmessage != NULL && sendsize != 0)
mhu_build_payload(mboxpl, mboxwr, sendmessage, sendsize);
mhu_message_send(mboxset, command, sendsize);
mhu_message_wait(mboxsts);
if (revmessage != NULL && revsize != 0)
mhu_get_payload(mboxpl, mboxrd, revmessage, revsize);
mhu_message_end(mboxpl, mboxwr, mboxirq, mboxid);
return ret;
}