text: /*
   * Copyright 2017 NXP
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   * Redistributions of source code must retain the above copyright notice, this
   * list of conditions and the following disclaimer.
   *
   * Redistributions in binary form must reproduce the above copyright notice,
   * this list of conditions and the following disclaimer in the documentation
   * and/or other materials provided with the distribution.
   *
   * Neither the name of NXP nor the names of its contributors may be used
   * to endorse or promote products derived from this software without specific
   * prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGE.
   */
  
  #include <sci/scfw.h>
  #include <sci/ipc.h>
  #include <sci/rpc.h>
  #include <stdlib.h>
  
  #include "mx8_mu.h"
  
  #include <bakery_lock.h>
  DEFINE_BAKERY_LOCK(sc_ipc_bakery_lock);
  #define sc_ipc_lock_init()	bakery_lock_init(&sc_ipc_bakery_lock)
  #define sc_ipc_lock()		bakery_lock_get(&sc_ipc_bakery_lock)
  #define sc_ipc_unlock()		bakery_lock_release(&sc_ipc_bakery_lock)
  
  void sc_call_rpc(sc_ipc_t ipc, sc_rpc_msg_t *msg, bool no_resp)
  {
  	sc_ipc_lock();
  
  	sc_ipc_write(ipc, msg);
  	if (!no_resp)
  		sc_ipc_read(ipc, msg);
  
  	sc_ipc_unlock();
  }
  
  sc_err_t sc_ipc_open(sc_ipc_t *ipc, sc_ipc_id_t id)
  {
  	uint32_t base = id;
  	uint32_t i;
  	
  	/* Get MU base associated with IPC channel */
  	if ((ipc == NULL) || (base == 0))
  		return SC_ERR_IPC;
  
  	sc_ipc_lock_init();
  
  	/* Init MU */
  	MU_Init(base);
  
  	/* Enable all RX interrupts */
  	for (i = 0; i < MU_RR_COUNT; i++) {
  		MU_EnableRxFullInt(base, i);
  	}
  
  	/* Return MU address as handle */
  	*ipc = (sc_ipc_t) id;
  
  	return SC_ERR_NONE;
  }
  
  void sc_ipc_close(sc_ipc_t ipc)
  {
  	uint32_t base = ipc;
  
  	if (base != 0)
  		MU_Init(base);
  }
  
  void sc_ipc_read(sc_ipc_t ipc, void *data)
  {
  	uint32_t base = ipc;
  	sc_rpc_msg_t *msg = (sc_rpc_msg_t*) data;
  	uint8_t count = 0;
  
  	/* Check parms */
  	if ((base == 0) || (msg == NULL))
  		return;
  
  	/* Read first word */
  	MU_ReceiveMsg(base, 0, (uint32_t*) msg);   
  	count++;
  
  	/* Check size */
  	if (msg->size > SC_RPC_MAX_MSG) {
  		*((uint32_t*) msg) = 0;
  		return;
  	}
  	
  	/* Read remaining words */
  	while (count < msg->size) {
  		MU_ReceiveMsg(base, count % MU_RR_COUNT,
  			&(msg->DATA.u32[count - 1]));   
  		count++;
  	}
  }
  
  void sc_ipc_write(sc_ipc_t ipc, void *data)
  {
  	sc_rpc_msg_t *msg = (sc_rpc_msg_t*) data;
  	uint32_t base = ipc;
  	uint8_t count = 0;
  
  	/* Check parms */
  	if ((base == 0) || (msg == NULL))
  		return;
  
  	/* Check size */
  	if (msg->size > SC_RPC_MAX_MSG)
  		return;
  
  	/* Write first word */
  	MU_SendMessage(base, 0, *((uint32_t*) msg));   
  	count++;
  	
  	/* Write remaining words */
  	while (count < msg->size) {
  		MU_SendMessage(base, count % MU_TR_COUNT,
  			msg->DATA.u32[count - 1]);   
  		count++;
  	}
  }
  
  