arm-trusted-firmware/plat/nvidia/tegra/drivers/bpmp_ipc/intf.c

346 lines
7.7 KiB
C
Raw Normal View History

Tegra: bpmp_ipc: IPC driver to communicate with BPMP firmware This patch adds the driver to communicate with the BPMP firmware on Tegra SoCs, starting Tegra186. BPMP firmware is responsible for clock enable/ disable requests, module resets among other things. MRQ is short for Message ReQuest. This is the general purpose, multi channel messaging protocol that is widely used to communicate with BPMP. This is further divided into a common high level protocol and a peer-specific low level protocol. The higher level protocol specifies the peer identification, channel definition and allocation, message structure, message semantics and message dispatch process whereas the lower level protocol defines actual message transfer implementation details. Currently, BPMP supports two lower level protocols - Token Mail Operations (TMO), IVC Mail Operations (IMO). This driver implements the IMO protocol. IMO is implemented using the IVC (Inter-VM Communication) protocol which is a lockless, shared memory messaging queue management protocol. The IVC peer is expected to perform the following as part of establishing a connection with BPMP. 1. Initialize the channels with tegra_ivc_init() or its equivalent. 2. Reset the channel with tegra_ivc_channel_reset. The peer should also ensure that BPMP is notified via the doorbell. 3. Poll until the channel connection is established [tegra_ivc_channel_notified() return 0]. Interrupt BPMP with doorbell each time after tegra_ivc_channel_notified() return non zero. The IPC driver currently supports reseting the GPCDMAand XUSB_PADCTL hardware blocks. In future, more hardware blocks would be supported. Change-Id: I52a4bd3a853de6c4fa410904b6614ff1c63df364 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
2017-09-25 21:27:45 +01:00
/*
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
Tegra: bpmp_ipc: IPC driver to communicate with BPMP firmware This patch adds the driver to communicate with the BPMP firmware on Tegra SoCs, starting Tegra186. BPMP firmware is responsible for clock enable/ disable requests, module resets among other things. MRQ is short for Message ReQuest. This is the general purpose, multi channel messaging protocol that is widely used to communicate with BPMP. This is further divided into a common high level protocol and a peer-specific low level protocol. The higher level protocol specifies the peer identification, channel definition and allocation, message structure, message semantics and message dispatch process whereas the lower level protocol defines actual message transfer implementation details. Currently, BPMP supports two lower level protocols - Token Mail Operations (TMO), IVC Mail Operations (IMO). This driver implements the IMO protocol. IMO is implemented using the IVC (Inter-VM Communication) protocol which is a lockless, shared memory messaging queue management protocol. The IVC peer is expected to perform the following as part of establishing a connection with BPMP. 1. Initialize the channels with tegra_ivc_init() or its equivalent. 2. Reset the channel with tegra_ivc_channel_reset. The peer should also ensure that BPMP is notified via the doorbell. 3. Poll until the channel connection is established [tegra_ivc_channel_notified() return 0]. Interrupt BPMP with doorbell each time after tegra_ivc_channel_notified() return non zero. The IPC driver currently supports reseting the GPCDMAand XUSB_PADCTL hardware blocks. In future, more hardware blocks would be supported. Change-Id: I52a4bd3a853de6c4fa410904b6614ff1c63df364 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
2017-09-25 21:27:45 +01:00
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <bpmp_ipc.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
Tegra: bpmp_ipc: IPC driver to communicate with BPMP firmware This patch adds the driver to communicate with the BPMP firmware on Tegra SoCs, starting Tegra186. BPMP firmware is responsible for clock enable/ disable requests, module resets among other things. MRQ is short for Message ReQuest. This is the general purpose, multi channel messaging protocol that is widely used to communicate with BPMP. This is further divided into a common high level protocol and a peer-specific low level protocol. The higher level protocol specifies the peer identification, channel definition and allocation, message structure, message semantics and message dispatch process whereas the lower level protocol defines actual message transfer implementation details. Currently, BPMP supports two lower level protocols - Token Mail Operations (TMO), IVC Mail Operations (IMO). This driver implements the IMO protocol. IMO is implemented using the IVC (Inter-VM Communication) protocol which is a lockless, shared memory messaging queue management protocol. The IVC peer is expected to perform the following as part of establishing a connection with BPMP. 1. Initialize the channels with tegra_ivc_init() or its equivalent. 2. Reset the channel with tegra_ivc_channel_reset. The peer should also ensure that BPMP is notified via the doorbell. 3. Poll until the channel connection is established [tegra_ivc_channel_notified() return 0]. Interrupt BPMP with doorbell each time after tegra_ivc_channel_notified() return non zero. The IPC driver currently supports reseting the GPCDMAand XUSB_PADCTL hardware blocks. In future, more hardware blocks would be supported. Change-Id: I52a4bd3a853de6c4fa410904b6614ff1c63df364 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
2017-09-25 21:27:45 +01:00
#include <errno.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
Tegra: bpmp_ipc: IPC driver to communicate with BPMP firmware This patch adds the driver to communicate with the BPMP firmware on Tegra SoCs, starting Tegra186. BPMP firmware is responsible for clock enable/ disable requests, module resets among other things. MRQ is short for Message ReQuest. This is the general purpose, multi channel messaging protocol that is widely used to communicate with BPMP. This is further divided into a common high level protocol and a peer-specific low level protocol. The higher level protocol specifies the peer identification, channel definition and allocation, message structure, message semantics and message dispatch process whereas the lower level protocol defines actual message transfer implementation details. Currently, BPMP supports two lower level protocols - Token Mail Operations (TMO), IVC Mail Operations (IMO). This driver implements the IMO protocol. IMO is implemented using the IVC (Inter-VM Communication) protocol which is a lockless, shared memory messaging queue management protocol. The IVC peer is expected to perform the following as part of establishing a connection with BPMP. 1. Initialize the channels with tegra_ivc_init() or its equivalent. 2. Reset the channel with tegra_ivc_channel_reset. The peer should also ensure that BPMP is notified via the doorbell. 3. Poll until the channel connection is established [tegra_ivc_channel_notified() return 0]. Interrupt BPMP with doorbell each time after tegra_ivc_channel_notified() return non zero. The IPC driver currently supports reseting the GPCDMAand XUSB_PADCTL hardware blocks. In future, more hardware blocks would be supported. Change-Id: I52a4bd3a853de6c4fa410904b6614ff1c63df364 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
2017-09-25 21:27:45 +01:00
#include <stdbool.h>
#include <string.h>
#include <tegra_def.h>
#include "intf.h"
#include "ivc.h"
/**
* Holds IVC channel data
*/
struct ccplex_bpmp_channel_data {
/* Buffer for incoming data */
struct frame_data *ib;
/* Buffer for outgoing data */
struct frame_data *ob;
};
static struct ccplex_bpmp_channel_data s_channel;
static struct ivc ivc_ccplex_bpmp_channel;
/*
* Helper functions to access the HSP doorbell registers
*/
static inline uint32_t hsp_db_read(uint32_t reg)
{
return mmio_read_32((uint32_t)(TEGRA_HSP_DBELL_BASE + reg));
}
static inline void hsp_db_write(uint32_t reg, uint32_t val)
{
mmio_write_32((uint32_t)(TEGRA_HSP_DBELL_BASE + reg), val);
}
/*******************************************************************************
* IVC wrappers for CCPLEX <-> BPMP communication.
******************************************************************************/
static void tegra_bpmp_ring_bpmp_doorbell(void);
/*
* Get the next frame where data can be written.
*/
static struct frame_data *tegra_bpmp_get_next_out_frame(void)
{
struct frame_data *frame;
const struct ivc *ch = &ivc_ccplex_bpmp_channel;
frame = (struct frame_data *)tegra_ivc_write_get_next_frame(ch);
if (frame == NULL) {
ERROR("%s: Error in getting next frame, exiting\n", __func__);
} else {
s_channel.ob = frame;
}
return frame;
}
static void tegra_bpmp_signal_slave(void)
{
(void)tegra_ivc_write_advance(&ivc_ccplex_bpmp_channel);
tegra_bpmp_ring_bpmp_doorbell();
}
static int32_t tegra_bpmp_free_master(void)
{
return tegra_ivc_read_advance(&ivc_ccplex_bpmp_channel);
}
static bool tegra_bpmp_slave_acked(void)
{
struct frame_data *frame;
bool ret = true;
frame = (struct frame_data *)tegra_ivc_read_get_next_frame(&ivc_ccplex_bpmp_channel);
if (frame == NULL) {
ret = false;
} else {
s_channel.ib = frame;
}
return ret;
}
static struct frame_data *tegra_bpmp_get_cur_in_frame(void)
{
return s_channel.ib;
}
/*
* Enables BPMP to ring CCPlex doorbell
*/
static void tegra_bpmp_enable_ccplex_doorbell(void)
{
uint32_t reg;
reg = hsp_db_read(HSP_DBELL_1_ENABLE);
reg |= HSP_MASTER_BPMP_BIT;
hsp_db_write(HSP_DBELL_1_ENABLE, reg);
}
/*
* CCPlex rings the BPMP doorbell
*/
static void tegra_bpmp_ring_bpmp_doorbell(void)
{
/*
* Any writes to this register has the same effect,
* uses master ID of the write transaction and set
* corresponding flag.
*/
hsp_db_write(HSP_DBELL_3_TRIGGER, HSP_MASTER_CCPLEX_BIT);
}
/*
* Returns true if CCPLex can ring BPMP doorbell, otherwise false.
* This also signals that BPMP is up and ready.
*/
static bool tegra_bpmp_can_ccplex_ring_doorbell(void)
{
uint32_t reg;
/* check if ccplex can communicate with bpmp */
reg = hsp_db_read(HSP_DBELL_3_ENABLE);
return ((reg & HSP_MASTER_CCPLEX_BIT) != 0U);
}
static int32_t tegra_bpmp_wait_for_slave_ack(void)
{
uint32_t timeout = TIMEOUT_RESPONSE_FROM_BPMP_US;
while (!tegra_bpmp_slave_acked() && (timeout != 0U)) {
udelay(1);
timeout--;
};
return ((timeout == 0U) ? -ETIMEDOUT : 0);
}
/*
* Notification from the ivc layer
*/
static void tegra_bpmp_ivc_notify(const struct ivc *ivc)
{
(void)(ivc);
tegra_bpmp_ring_bpmp_doorbell();
}
/*
* Atomic send/receive API, which means it waits until slave acks
*/
static int32_t tegra_bpmp_ipc_send_req_atomic(uint32_t mrq, void *p_out,
uint32_t size_out, void *p_in, uint32_t size_in)
{
struct frame_data *frame = tegra_bpmp_get_next_out_frame();
const struct frame_data *f_in = NULL;
int32_t ret = 0;
void *p_fdata;
if ((p_out == NULL) || (size_out > IVC_DATA_SZ_BYTES) ||
(frame == NULL)) {
ERROR("%s: invalid parameters, exiting\n", __func__);
return -EINVAL;
Tegra: bpmp_ipc: IPC driver to communicate with BPMP firmware This patch adds the driver to communicate with the BPMP firmware on Tegra SoCs, starting Tegra186. BPMP firmware is responsible for clock enable/ disable requests, module resets among other things. MRQ is short for Message ReQuest. This is the general purpose, multi channel messaging protocol that is widely used to communicate with BPMP. This is further divided into a common high level protocol and a peer-specific low level protocol. The higher level protocol specifies the peer identification, channel definition and allocation, message structure, message semantics and message dispatch process whereas the lower level protocol defines actual message transfer implementation details. Currently, BPMP supports two lower level protocols - Token Mail Operations (TMO), IVC Mail Operations (IMO). This driver implements the IMO protocol. IMO is implemented using the IVC (Inter-VM Communication) protocol which is a lockless, shared memory messaging queue management protocol. The IVC peer is expected to perform the following as part of establishing a connection with BPMP. 1. Initialize the channels with tegra_ivc_init() or its equivalent. 2. Reset the channel with tegra_ivc_channel_reset. The peer should also ensure that BPMP is notified via the doorbell. 3. Poll until the channel connection is established [tegra_ivc_channel_notified() return 0]. Interrupt BPMP with doorbell each time after tegra_ivc_channel_notified() return non zero. The IPC driver currently supports reseting the GPCDMAand XUSB_PADCTL hardware blocks. In future, more hardware blocks would be supported. Change-Id: I52a4bd3a853de6c4fa410904b6614ff1c63df364 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
2017-09-25 21:27:45 +01:00
}
/* prepare the command frame */
frame->mrq = mrq;
frame->flags = FLAG_DO_ACK;
p_fdata = frame->data;
(void)memcpy(p_fdata, p_out, (size_t)size_out);
Tegra: bpmp_ipc: IPC driver to communicate with BPMP firmware This patch adds the driver to communicate with the BPMP firmware on Tegra SoCs, starting Tegra186. BPMP firmware is responsible for clock enable/ disable requests, module resets among other things. MRQ is short for Message ReQuest. This is the general purpose, multi channel messaging protocol that is widely used to communicate with BPMP. This is further divided into a common high level protocol and a peer-specific low level protocol. The higher level protocol specifies the peer identification, channel definition and allocation, message structure, message semantics and message dispatch process whereas the lower level protocol defines actual message transfer implementation details. Currently, BPMP supports two lower level protocols - Token Mail Operations (TMO), IVC Mail Operations (IMO). This driver implements the IMO protocol. IMO is implemented using the IVC (Inter-VM Communication) protocol which is a lockless, shared memory messaging queue management protocol. The IVC peer is expected to perform the following as part of establishing a connection with BPMP. 1. Initialize the channels with tegra_ivc_init() or its equivalent. 2. Reset the channel with tegra_ivc_channel_reset. The peer should also ensure that BPMP is notified via the doorbell. 3. Poll until the channel connection is established [tegra_ivc_channel_notified() return 0]. Interrupt BPMP with doorbell each time after tegra_ivc_channel_notified() return non zero. The IPC driver currently supports reseting the GPCDMAand XUSB_PADCTL hardware blocks. In future, more hardware blocks would be supported. Change-Id: I52a4bd3a853de6c4fa410904b6614ff1c63df364 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
2017-09-25 21:27:45 +01:00
/* signal the slave */
tegra_bpmp_signal_slave();
Tegra: bpmp_ipc: IPC driver to communicate with BPMP firmware This patch adds the driver to communicate with the BPMP firmware on Tegra SoCs, starting Tegra186. BPMP firmware is responsible for clock enable/ disable requests, module resets among other things. MRQ is short for Message ReQuest. This is the general purpose, multi channel messaging protocol that is widely used to communicate with BPMP. This is further divided into a common high level protocol and a peer-specific low level protocol. The higher level protocol specifies the peer identification, channel definition and allocation, message structure, message semantics and message dispatch process whereas the lower level protocol defines actual message transfer implementation details. Currently, BPMP supports two lower level protocols - Token Mail Operations (TMO), IVC Mail Operations (IMO). This driver implements the IMO protocol. IMO is implemented using the IVC (Inter-VM Communication) protocol which is a lockless, shared memory messaging queue management protocol. The IVC peer is expected to perform the following as part of establishing a connection with BPMP. 1. Initialize the channels with tegra_ivc_init() or its equivalent. 2. Reset the channel with tegra_ivc_channel_reset. The peer should also ensure that BPMP is notified via the doorbell. 3. Poll until the channel connection is established [tegra_ivc_channel_notified() return 0]. Interrupt BPMP with doorbell each time after tegra_ivc_channel_notified() return non zero. The IPC driver currently supports reseting the GPCDMAand XUSB_PADCTL hardware blocks. In future, more hardware blocks would be supported. Change-Id: I52a4bd3a853de6c4fa410904b6614ff1c63df364 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
2017-09-25 21:27:45 +01:00
/* wait for slave to ack */
ret = tegra_bpmp_wait_for_slave_ack();
if (ret < 0) {
ERROR("%s: wait for slave failed (%d)\n", __func__, ret);
return ret;
}
Tegra: bpmp_ipc: IPC driver to communicate with BPMP firmware This patch adds the driver to communicate with the BPMP firmware on Tegra SoCs, starting Tegra186. BPMP firmware is responsible for clock enable/ disable requests, module resets among other things. MRQ is short for Message ReQuest. This is the general purpose, multi channel messaging protocol that is widely used to communicate with BPMP. This is further divided into a common high level protocol and a peer-specific low level protocol. The higher level protocol specifies the peer identification, channel definition and allocation, message structure, message semantics and message dispatch process whereas the lower level protocol defines actual message transfer implementation details. Currently, BPMP supports two lower level protocols - Token Mail Operations (TMO), IVC Mail Operations (IMO). This driver implements the IMO protocol. IMO is implemented using the IVC (Inter-VM Communication) protocol which is a lockless, shared memory messaging queue management protocol. The IVC peer is expected to perform the following as part of establishing a connection with BPMP. 1. Initialize the channels with tegra_ivc_init() or its equivalent. 2. Reset the channel with tegra_ivc_channel_reset. The peer should also ensure that BPMP is notified via the doorbell. 3. Poll until the channel connection is established [tegra_ivc_channel_notified() return 0]. Interrupt BPMP with doorbell each time after tegra_ivc_channel_notified() return non zero. The IPC driver currently supports reseting the GPCDMAand XUSB_PADCTL hardware blocks. In future, more hardware blocks would be supported. Change-Id: I52a4bd3a853de6c4fa410904b6614ff1c63df364 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
2017-09-25 21:27:45 +01:00
/* retrieve the response frame */
if ((size_in <= IVC_DATA_SZ_BYTES) && (p_in != NULL)) {
Tegra: bpmp_ipc: IPC driver to communicate with BPMP firmware This patch adds the driver to communicate with the BPMP firmware on Tegra SoCs, starting Tegra186. BPMP firmware is responsible for clock enable/ disable requests, module resets among other things. MRQ is short for Message ReQuest. This is the general purpose, multi channel messaging protocol that is widely used to communicate with BPMP. This is further divided into a common high level protocol and a peer-specific low level protocol. The higher level protocol specifies the peer identification, channel definition and allocation, message structure, message semantics and message dispatch process whereas the lower level protocol defines actual message transfer implementation details. Currently, BPMP supports two lower level protocols - Token Mail Operations (TMO), IVC Mail Operations (IMO). This driver implements the IMO protocol. IMO is implemented using the IVC (Inter-VM Communication) protocol which is a lockless, shared memory messaging queue management protocol. The IVC peer is expected to perform the following as part of establishing a connection with BPMP. 1. Initialize the channels with tegra_ivc_init() or its equivalent. 2. Reset the channel with tegra_ivc_channel_reset. The peer should also ensure that BPMP is notified via the doorbell. 3. Poll until the channel connection is established [tegra_ivc_channel_notified() return 0]. Interrupt BPMP with doorbell each time after tegra_ivc_channel_notified() return non zero. The IPC driver currently supports reseting the GPCDMAand XUSB_PADCTL hardware blocks. In future, more hardware blocks would be supported. Change-Id: I52a4bd3a853de6c4fa410904b6614ff1c63df364 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
2017-09-25 21:27:45 +01:00
f_in = tegra_bpmp_get_cur_in_frame();
if (f_in != NULL) {
ERROR("Failed to get next input frame!\n");
} else {
(void)memcpy(p_in, p_fdata, (size_t)size_in);
Tegra: bpmp_ipc: IPC driver to communicate with BPMP firmware This patch adds the driver to communicate with the BPMP firmware on Tegra SoCs, starting Tegra186. BPMP firmware is responsible for clock enable/ disable requests, module resets among other things. MRQ is short for Message ReQuest. This is the general purpose, multi channel messaging protocol that is widely used to communicate with BPMP. This is further divided into a common high level protocol and a peer-specific low level protocol. The higher level protocol specifies the peer identification, channel definition and allocation, message structure, message semantics and message dispatch process whereas the lower level protocol defines actual message transfer implementation details. Currently, BPMP supports two lower level protocols - Token Mail Operations (TMO), IVC Mail Operations (IMO). This driver implements the IMO protocol. IMO is implemented using the IVC (Inter-VM Communication) protocol which is a lockless, shared memory messaging queue management protocol. The IVC peer is expected to perform the following as part of establishing a connection with BPMP. 1. Initialize the channels with tegra_ivc_init() or its equivalent. 2. Reset the channel with tegra_ivc_channel_reset. The peer should also ensure that BPMP is notified via the doorbell. 3. Poll until the channel connection is established [tegra_ivc_channel_notified() return 0]. Interrupt BPMP with doorbell each time after tegra_ivc_channel_notified() return non zero. The IPC driver currently supports reseting the GPCDMAand XUSB_PADCTL hardware blocks. In future, more hardware blocks would be supported. Change-Id: I52a4bd3a853de6c4fa410904b6614ff1c63df364 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
2017-09-25 21:27:45 +01:00
}
}
Tegra: bpmp_ipc: IPC driver to communicate with BPMP firmware This patch adds the driver to communicate with the BPMP firmware on Tegra SoCs, starting Tegra186. BPMP firmware is responsible for clock enable/ disable requests, module resets among other things. MRQ is short for Message ReQuest. This is the general purpose, multi channel messaging protocol that is widely used to communicate with BPMP. This is further divided into a common high level protocol and a peer-specific low level protocol. The higher level protocol specifies the peer identification, channel definition and allocation, message structure, message semantics and message dispatch process whereas the lower level protocol defines actual message transfer implementation details. Currently, BPMP supports two lower level protocols - Token Mail Operations (TMO), IVC Mail Operations (IMO). This driver implements the IMO protocol. IMO is implemented using the IVC (Inter-VM Communication) protocol which is a lockless, shared memory messaging queue management protocol. The IVC peer is expected to perform the following as part of establishing a connection with BPMP. 1. Initialize the channels with tegra_ivc_init() or its equivalent. 2. Reset the channel with tegra_ivc_channel_reset. The peer should also ensure that BPMP is notified via the doorbell. 3. Poll until the channel connection is established [tegra_ivc_channel_notified() return 0]. Interrupt BPMP with doorbell each time after tegra_ivc_channel_notified() return non zero. The IPC driver currently supports reseting the GPCDMAand XUSB_PADCTL hardware blocks. In future, more hardware blocks would be supported. Change-Id: I52a4bd3a853de6c4fa410904b6614ff1c63df364 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
2017-09-25 21:27:45 +01:00
ret = tegra_bpmp_free_master();
if (ret < 0) {
ERROR("%s: free master failed (%d)\n", __func__, ret);
Tegra: bpmp_ipc: IPC driver to communicate with BPMP firmware This patch adds the driver to communicate with the BPMP firmware on Tegra SoCs, starting Tegra186. BPMP firmware is responsible for clock enable/ disable requests, module resets among other things. MRQ is short for Message ReQuest. This is the general purpose, multi channel messaging protocol that is widely used to communicate with BPMP. This is further divided into a common high level protocol and a peer-specific low level protocol. The higher level protocol specifies the peer identification, channel definition and allocation, message structure, message semantics and message dispatch process whereas the lower level protocol defines actual message transfer implementation details. Currently, BPMP supports two lower level protocols - Token Mail Operations (TMO), IVC Mail Operations (IMO). This driver implements the IMO protocol. IMO is implemented using the IVC (Inter-VM Communication) protocol which is a lockless, shared memory messaging queue management protocol. The IVC peer is expected to perform the following as part of establishing a connection with BPMP. 1. Initialize the channels with tegra_ivc_init() or its equivalent. 2. Reset the channel with tegra_ivc_channel_reset. The peer should also ensure that BPMP is notified via the doorbell. 3. Poll until the channel connection is established [tegra_ivc_channel_notified() return 0]. Interrupt BPMP with doorbell each time after tegra_ivc_channel_notified() return non zero. The IPC driver currently supports reseting the GPCDMAand XUSB_PADCTL hardware blocks. In future, more hardware blocks would be supported. Change-Id: I52a4bd3a853de6c4fa410904b6614ff1c63df364 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
2017-09-25 21:27:45 +01:00
}
return ret;
}
/*
* Initializes the BPMP<--->CCPlex communication path.
*/
int32_t tegra_bpmp_ipc_init(void)
{
size_t msg_size;
uint32_t frame_size, timeout;
int32_t error = 0;
/* allow bpmp to ring CCPLEX's doorbell */
tegra_bpmp_enable_ccplex_doorbell();
/* wait for BPMP to actually ring the doorbell */
timeout = TIMEOUT_RESPONSE_FROM_BPMP_US;
while ((timeout != 0U) && !tegra_bpmp_can_ccplex_ring_doorbell()) {
udelay(1); /* bpmp turn-around time */
timeout--;
}
if (timeout == 0U) {
ERROR("%s: BPMP firmware is not ready\n", __func__);
return -ENOTSUP;
}
INFO("%s: BPMP handshake completed\n", __func__);
msg_size = tegra_ivc_align(IVC_CMD_SZ_BYTES);
frame_size = (uint32_t)tegra_ivc_total_queue_size(msg_size);
if (frame_size > TEGRA_BPMP_IPC_CH_MAP_SIZE) {
ERROR("%s: carveout size is not sufficient\n", __func__);
return -EINVAL;
}
error = tegra_ivc_init(&ivc_ccplex_bpmp_channel,
(uint32_t)TEGRA_BPMP_IPC_RX_PHYS_BASE,
(uint32_t)TEGRA_BPMP_IPC_TX_PHYS_BASE,
1U, frame_size, tegra_bpmp_ivc_notify);
if (error != 0) {
ERROR("%s: IVC init failed (%d)\n", __func__, error);
} else {
/* reset channel */
tegra_ivc_channel_reset(&ivc_ccplex_bpmp_channel);
/* wait for notification from BPMP */
while (tegra_ivc_channel_notified(&ivc_ccplex_bpmp_channel) != 0) {
/*
* Interrupt BPMP with doorbell each time after
* tegra_ivc_channel_notified() returns non zero
* value.
*/
tegra_bpmp_ring_bpmp_doorbell();
}
INFO("%s: All communication channels initialized\n", __func__);
}
return error;
}
/* Handler to reset a hardware module */
int32_t tegra_bpmp_ipc_reset_module(uint32_t rst_id)
{
int32_t ret;
struct mrq_reset_request req = {
.cmd = (uint32_t)CMD_RESET_MODULE,
.reset_id = rst_id
};
/* only GPCDMA/XUSB_PADCTL resets are supported */
assert((rst_id == TEGRA_RESET_ID_XUSB_PADCTL) ||
(rst_id == TEGRA_RESET_ID_GPCDMA));
ret = tegra_bpmp_ipc_send_req_atomic(MRQ_RESET, &req,
(uint32_t)sizeof(req), NULL, 0);
if (ret != 0) {
ERROR("%s: failed for module %d with error %d\n", __func__,
rst_id, ret);
}
return ret;
}
int tegra_bpmp_ipc_enable_clock(uint32_t clk_id)
{
int ret;
struct mrq_clk_request req;
/* only SE clocks are supported */
if (clk_id != TEGRA_CLK_SE) {
return -ENOTSUP;
}
/* prepare the MRQ_CLK command */
req.cmd_and_id = make_mrq_clk_cmd(CMD_CLK_ENABLE, clk_id);
ret = tegra_bpmp_ipc_send_req_atomic(MRQ_CLK, &req, (uint32_t)sizeof(req),
NULL, 0);
if (ret != 0) {
ERROR("%s: failed for module %d with error %d\n", __func__,
clk_id, ret);
}
return ret;
}
int tegra_bpmp_ipc_disable_clock(uint32_t clk_id)
{
int ret;
struct mrq_clk_request req;
/* only SE clocks are supported */
if (clk_id != TEGRA_CLK_SE) {
return -ENOTSUP;
}
/* prepare the MRQ_CLK command */
req.cmd_and_id = make_mrq_clk_cmd(CMD_CLK_DISABLE, clk_id);
ret = tegra_bpmp_ipc_send_req_atomic(MRQ_CLK, &req, (uint32_t)sizeof(req),
NULL, 0);
if (ret != 0) {
ERROR("%s: failed for module %d with error %d\n", __func__,
clk_id, ret);
}
return ret;
}