/****************************************************************************
 *  License : All rights reserved for TES Electronic Solutions GmbH
 *            See included /docs/license.txt for details
 *  Project : D/AVE HD
 *  Purpose : Memory transfer and cache control
 *  Platform: null (dummy implementation)
 ****************************************************************************
 * Version Control Information :
 *  $Revision: 13108 $
 *  $Date: 2017-03-21 11:26:25 +0100 (Di, 21. Mrz 2017) $
 *  $LastChangedBy: florian.zimmermann $
 ****************************************************************************
 * Change History (autogenerated):
 ****************************************************************************/

#include "davehd_kernel_driver.h"
#include "davehd_kernel_client.h"
#include "davehd_kernel_memory.h"
#include "davehd_kernel_tlist.h"
#include "davehd_kernel_os.h"
#include "davehd_os.h"
#include "davehd_guards.h"

#include "r_typedefs.h"
#include "r_cdi_api.h"
#include "r_xbus_api.h"
#include "r_dev_api.h"

#ifndef DHD_MAP_OFFSET
#define DHD_MAP_OFFSET 0x0
#endif

/*----------------------------------------------------------------------------------------------------------*/
/**/
dhd_enum_t dhd_gpu_internal_can_map_mem(dhd_gpu_device_data_t *a_device,  dhd_vidmem_t *a_memory, dhd_enum_t a_access) {

  /* all video memory is mapable*/
  return E_DHD_OK;
}

/*----------------------------------------------------------------------------------------------------------*/
/**/
dhd_enum_t dhd_gpu_internal_map_mem(dhd_gpu_device_data_t *a_device, dhd_vidmem_t *a_memory, dhd_enum_t a_access) {
  dhd_uint8_t *address =  (dhd_uint8_t *) a_memory->m_gpu_address;
    
  a_memory->m_cpu_address = address - DHD_MAP_OFFSET;

  return E_DHD_OK;
}

/*----------------------------------------------------------------------------------------------------------*/
/**/
dhd_enum_t dhd_gpu_internal_unmap_mem(dhd_gpu_device_data_t *a_device, dhd_vidmem_t *a_memory, dhd_enum_t a_access) {

  dhd_gpu_internal_cflush(a_device, a_memory->m_cpu_address, a_memory->m_size);
  a_memory->m_cpu_address = 0;

  return E_DHD_OK;
}

/*----------------------------------------------------------------------------------------------------------*/
/**/
dhd_enum_t dhd_gpu_internal_upload(dhd_gpu_device_data_t *a_device, const dhd_uint8_t *a_src, dhd_gpu_ptr_t a_dest, dhd_uint32_t a_size) {
  dhd_uint8_t *dst = (dhd_uint8_t *) a_dest - DHD_MAP_OFFSET;
  volatile dhd_uint8_t flush_mem_pipeline;
  dhd_uint32_t size = a_size;

#if defined(DHD_KERNEL_TLIST_SUPPORT) && defined(DHD_KERNEL_DUMP_KERNEL_TLIST)
  dhd_gpu_tlist_upload(&a_device->m_tlist, a_src, a_dest, a_size, 0);
#endif
  
  /*
   * The loop's number of passes depends on a_size, which is
   * continuously incremented. Infinite execution impossible except for
   * overwriting involved memory areas.
   */
  while (a_size > 0) {
    *dst = *a_src;
    dst++;
    a_src++;
    a_size--;
  }

   /* This is because of XBUS and Multimaster architecture. We have the  
    CPU writing data using one path and the DAVE reading ist drawing list by 
    using another path.
    We have to make sure that DAVE does not start executing the drawing list 
    before its data was updated. 
    We just read the last data back in case the cache is not active 
    (a cache flush would not have any effect then) 
    If the cache is active, this instruction just consumes 
    one RAM cycle  */
  flush_mem_pipeline = *((volatile dhd_uint8_t*)(dst-1));
  /* sync the memory 100% from CPU point of view */
  R_DEV_SyncP();

  /* flush cache so CPU gets the fresh data */
  dhd_gpu_internal_cflush(a_device, a_dest, size);

  return E_DHD_OK;
}

/*----------------------------------------------------------------------------------------------------------*/
/**/
dhd_enum_t dhd_gpu_internal_download(dhd_gpu_device_data_t *a_device, dhd_gpu_ptr_t a_src, dhd_uint8_t *a_dest, dhd_uint32_t a_size) {

  /* up and download are identical in this implementation*/
  return dhd_gpu_internal_upload( a_device, (dhd_uint8_t *)a_src, (dhd_gpu_ptr_t)a_dest, a_size );
}

/*----------------------------------------------------------------------------------------------------------*/
/**/
void dhd_gpu_internal_cflush(dhd_gpu_device_data_t *a_device, const dhd_uint8_t *a_address, dhd_uint32_t a_size) 
{
    R_XBUS_Flush(0, (uint32_t)a_address, a_size);
}

/*----------------------------------------------------------------------------------------------------------*/
/**/
void dhd_gpu_internal_cinvalidate(dhd_gpu_device_data_t *a_device, const dhd_uint8_t *a_address, dhd_uint32_t a_size) {
  /* data cache invalidate*/
}
