/*
 * AXCCommFreeRTOS.cpp
 */
#include "AXCCommFreeRTOS.hpp"
#include "FreeRTOS.h"
#include "event_groups.h"

//#incldue "regs/across.h"
#define ACR_BASE      (0x30000000)	// baba 以前のデータシート取得後検討

//#include "regs/dsp.h"
#define ADSP_BASE	(ACR_BASE + 0x1500000)	// baba 以前のデータシート取得後検討

enum DSP_REGS {	// baba 以前のデータシート取得後検討
  r_DSP_CTL		= 0x00,
  r_DSP_ACT		= 0x04,
  r_DSP_PSTATUS		= 0x08,
  r_DSP_STAT_VECTOR_SEL	= 0x0c,
  r_DSP_SYSROM_ADDR	= 0x10,
  r_DSP_SYSRAM_ADDR	= 0x14,
  r_HOST_INT_MASK	= 0x18,
  r_HOST_INT_STATUS	= 0x1c,
  r_HOST_INT_UNMASK	= 0x20,
  r_HOST_INT_RAW	= 0x24,
  r_HOST_RES_ID_REQ	= 0x28,
  r_HOST_RES_ARG00	= 0x2c,
  r_HOST_RES_ARG01	= 0x30,
  r_HOST_RES_ARG02	= 0x34,
  r_HOST_RES_ARG03	= 0x38,
  r_DSP_INT_MASK	= 0x3c,
  r_DSP_INT_STATUS	= 0x40,
  r_DSP_INT_UNMASK	= 0x44,
  r_DSP_INT_RAW		= 0x48,
  r_DSP_COM_ID_REQ	= 0x4c,
  r_DSP_COM_ARG00	= 0x50,
  r_DSP_COM_ARG01	= 0x54,
  r_DSP_COM_ARG02	= 0x58,
  r_DSP_COM_ARG03	= 0x5c,
};

enum AUDIO_DSP_INT {	// baba 以前のデータシート取得後検討
  AUDIO_DSP_INT_SIO2		= (1 << 15),
  AUDIO_DSP_INT_SIO1		= (1 << 14),
  AUDIO_DSP_INT_SIO0		= (1 << 13),
  AUDIO_DSP_INT_I2C1		= (1 << 12),
  AUDIO_DSP_INT_I2C0		= (1 << 11),
  AUDIO_DSP_INT_APKT		= (1 << 10),
  AUDIO_DSP_INT_ISP_DMAR	= (1 << 9),
  AUDIO_DSP_INT_ISP_DMAW	= (1 << 8),
  AUDIO_DSP_INT_ISP_SCL		= (1 << 7),
  AUDIO_DSP_INT_ISP_RPU		= (1 << 6),
  AUDIO_DSP_INT_IMAGEIF_DMAR	= (1 << 5),
  AUDIO_DSP_INT_IMAGEIF_DMAW	= (1 << 4),
  AUDIO_DSP_INT_IMAGEIF_MIX	= (1 << 3),
  AUDIO_DSP_INT_IMAGEIF_SPU	= (1 << 2),
  AUDIO_DSP_INT_IMAGEIF_ISI	= (1 << 1),
  AUDIO_DSP_INT_HOST		= (1 << 0),
  AUDIO_DSP_INT_ALL		= (0xffff)
};

#include <string.h>

//#include "cpuCommInt.h"			// baba 以前のファイルが存在するか確認後検討

AXCCommFreeRTOS::AXCCommFreeRTOS()
    : m_isInited(false),
      m_fromXtensa(0),		// def:m_fromXtensa(COM_MEM_FROM_XTENSA),	// baba 以前のデータシート取得後検討
			m_fromArm(0),				// def:m_fromArm(COM_MEM_FROM_ARM),				// baba 以前のデータシート取得後検討
      m_dspRegBase(ADSP_BASE)
 {
}

AXCCommFreeRTOS::~AXCCommFreeRTOS() {
  if (m_isInited) {
    ;
  }
}

AXCCommFreeRTOS::commStatus AXCCommFreeRTOS::init(AXComm_t type) {
  commStatus stat = COMM_ERROR;

  if (true == m_isInited) {
    goto err;
  }

  switch (type & AXCOMM_TYPE_MASK) {
    case AXCOMM_TYPE_CPU:
    break;

    case AXCOMM_TYPE_PROCESS:
    /* FreeRTOS版ではプロセス間通信は非対応 */
    default:
    goto err;
  }

  m_isInited = true;
  stat = COMM_SUCCESS;

  err:

  return stat;
}

int AXCCommFreeRTOS::readSync(char *buf, int size) {
  int stat = -1;

  if (false == m_isInited) {
    goto err;
  }
	
  if (size < 0 || size > COM_MEM_FROM_ARM_SIZE) {	// baba 以前のデータシート取得後検討
    goto err;
  }

  while (getCommMemStat(m_fromArm) != COMM_MEM_STAT_DATA) {
		EventBits_t flgptn;	
#ifdef BB_TMP_PASS	// axc_comm_flg_rはレジスタ？か不明のためコンパイル用に仮実装しておく
		flgptn = xEventGroupWaitBits((EventGroupHandle_t)axc_comm_flg_r, 1, pdTRUE, pdFALSE, portMAX_DELAY);	// baba 以前のデータシート取得後検討
#else
		flgptn = xEventGroupWaitBits(axc_comm_flg_r, 1, pdTRUE, pdFALSE, portMAX_DELAY);	// baba 以前のデータシート取得後検討
#endif
		if ((flgptn & 1) != 1) goto err;
  }

  memcpy(buf, (void *)m_fromArm, size);
#ifndef BB_TMP_PASS		// レジスタ操作関数と考えられるが不明のためコンパイル用に除去
  drvXInt_unsetMask(AUDIO_DSP_INT_HOST);	// baba 以前のデータシート取得後検討
#endif
  setCommMemStat(m_fromArm, COMM_MEM_STAT_ACK);
#ifndef BB_TMP_PASS		// レジスタ操作関数と考えられるが不明のためコンパイル用に除去
  drvXInt_setMask(AUDIO_DSP_INT_HOST);		// baba 以前のデータシート取得後検討
#endif

	// 今回HOSTとの通信は無く不要
  //raiseIntr();
  stat = size;

  err:

  return stat;
}

int AXCCommFreeRTOS::writeSync(char *buf, int size) {
  int stat = -1;
  UINT32_t sz = 0;

  if (false == m_isInited) {
    goto err;
  }
	
  if (size < 0 || size > COM_MEM_FROM_XTENSA_SIZE) goto err;	// baba 以前のデータシート取得後検討

  while (getCommMemStat(m_fromXtensa) != COMM_MEM_STAT_EMPTY) {
		EventBits_t flgptn;	
#ifdef BB_TMP_PASS	// axc_comm_flg_wはレジスタ？か不明のためコンパイル用に仮実装しておく
		flgptn = xEventGroupWaitBits((EventGroupHandle_t)axc_comm_flg_w, 1, pdTRUE, pdFALSE, portMAX_DELAY);	// baba 以前のデータシート取得後検討
#else
		flgptn = xEventGroupWaitBits(axc_comm_flg_w, 1, pdTRUE, pdFALSE, portMAX_DELAY);	// baba 以前のデータシート取得後検討
#endif
		if ((flgptn & 1) != 1) goto err;
  }

  memcpy((void *)(m_fromXtensa + sizeof(sz)), buf + sizeof(sz), size - sizeof(sz));
  memcpy(&sz, buf, sizeof(sz));
#ifndef BB_TMP_PASS		// レジスタ操作関数と考えられるが不明のためコンパイル用に除去
  drvXInt_unsetMask(AUDIO_DSP_INT_HOST);	// baba 以前のデータシート取得後検討
#endif
  setCommMemStat(m_fromXtensa, (commMemStat)sz);
#ifndef BB_TMP_PASS		// レジスタ操作関数と考えられるが不明のためコンパイル用に除去
  drvXInt_setMask(AUDIO_DSP_INT_HOST);		// baba 以前のデータシート取得後検討
#endif

	// 今回はHOSTとの通信は無く不要
  //raiseIntr();
  stat = size;

  err:

  return stat;
}

void AXCCommFreeRTOS::setBaseAddr(UINT32_t fromXtensa, UINT32_t fromArm, UINT32_t dspRegBase)
{
  m_fromXtensa = fromXtensa;
  m_fromArm = fromArm;
  m_dspRegBase = dspRegBase;
}


void AXCCommFreeRTOS::raiseIntr()
{
  while (readReg(r_HOST_RES_ID_REQ) & 1) {
      /* busy wait */
  }
  writeReg(r_HOST_RES_ID_REQ, 1);
}

UINT32_t AXCCommFreeRTOS::readReg(int offset)
{
#ifdef XTENSA_CACHE_FLUSH
  xtensa_cache_flush(m_dspRegBase + offset);		// baba 以前のデータシート取得後検討
#endif
  return *(volatile UINT32_t *)(m_dspRegBase + offset);
}

void AXCCommFreeRTOS::writeReg(int offset, UINT32_t v)
{
  *(volatile UINT32_t *)(m_dspRegBase + offset) = v;

}

AXCCommFreeRTOS::commMemStat AXCCommFreeRTOS::getCommMemStat(UINT32_t phyAddr)
{
#ifdef XTENSA_CACHE_FLUSH
  xtensa_cache_flush(phyAddr);		// baba 以前のデータシート取得後検討
#endif
  UINT32_t stat = *(volatile UINT32_t *)phyAddr;
  switch ((commMemStat)stat) {
  case COMM_MEM_STAT_EMPTY:
    return COMM_MEM_STAT_EMPTY;
  case COMM_MEM_STAT_ACK:
    return COMM_MEM_STAT_ACK;
  default:
    break;
  }
  return AXCCommFreeRTOS::COMM_MEM_STAT_DATA;
}

void AXCCommFreeRTOS::setCommMemStat(UINT32_t phyAddr, commMemStat stat)
{
  *(volatile UINT32_t *)phyAddr = stat;
}
