blob: 7d1e545ab6bd6463ee8ef1d8dea74ec6422371ea [file] [log] [blame]
/* Copyright Statement:
*
* This software/firmware and related documentation ("MediaTek Software") are
* protected under relevant copyright laws. The information contained herein
* is confidential and proprietary to MediaTek Inc. and/or its licensors.
* Without the prior written permission of MediaTek inc. and/or its licensors,
* any reproduction, modification, use or disclosure of MediaTek Software,
* and information contained herein, in whole or in part, shall be strictly prohibited.
*/
/* MediaTek Inc. (C) 2015. All rights reserved.
*
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*/
/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include <string.h>
#include <driver_api.h>
#include <interrupt.h>
#include <dma_api.h>
#ifdef CFG_VCORE_DVFS_SUPPORT
#include <dvfs.h>
#endif
#include "irq.h"
#ifdef CFG_COMMON_WAKELOCK_SUPPORT
#include <wakelock.h>
#endif
#ifdef CFG_XGPT_SUPPORT
#include <xgpt.h>
#endif
#include "mt_printf.h"
#define DMA_DEBUG 0
#define DMA_LARGE_DRAM 0
#if(DMA_DEBUG == 1)
#define dbgmsg PRINTF_D
#else
#define dbgmsg(...)
#endif
#if DMA_PROFILING
volatile unsigned int *ITM_CONTROL = (unsigned int *) 0xE0000E80;
volatile unsigned int *DWT_CONTROL = (unsigned int *) 0xE0001000;
volatile unsigned int *DWT_CYCCNT = (unsigned int *) 0xE0001004;
volatile unsigned int *DEMCR = (unsigned int *) 0xE000EDFC;
#define CPU_RESET_CYCLECOUNTER() \
do { \
*DEMCR = *DEMCR | 0x01000000; \
*DWT_CYCCNT = 0; \
*DWT_CONTROL = *DWT_CONTROL | 1 ; \
} while(0)
unsigned int start_time;
unsigned int end_time;
#endif
#if DMA_TRACE_DEBUG
#define DMA_TRACE_SECTION __attribute__ ((section (".sync")))
struct dma_trace_t {
unsigned int last_src;
unsigned int last_dst;
unsigned int last_len;
unsigned long long last_timestamp;
};
struct dma_trace_t DMA_TRACE_SECTION dma_trace[2] = {{0,0,0,0},{0,0,0,0}};
#endif
extern void *__sync_start;
extern struct dma_channel_t dma_channel[NR_GDMA_CHANNEL];
#if DMA_KEEP_AWAKE
wakelock_t scp_dma_wakelock;
#endif
typedef struct {
uint32_t ap_addr;
uint32_t scp_addr;
} scp_addr_map_t;
static scp_addr_map_t scp_addr_map[] = {
{.ap_addr = 0x60000000,.scp_addr = 0x10000000,},
{.ap_addr = 0x70000000,.scp_addr = 0x20000000,},
{.ap_addr = 0x00000000,.scp_addr = 0x50000000,},
{.ap_addr = 0x10000000,.scp_addr = 0x60000000,},
{.ap_addr = 0x80000000,.scp_addr = 0x90000000,},
{.ap_addr = 0x90000000,.scp_addr = 0xA0000000,},
{.ap_addr = 0x20000000,.scp_addr = 0xD0000000,},
{.ap_addr = 0x30000000,.scp_addr = 0xE0000000,},
{.ap_addr = 0x50000000,.scp_addr = 0xF0000000,},
};
uint32_t ap_to_scp(uint32_t ap_addr)
{
uint32_t i;
uint32_t num = sizeof (scp_addr_map) / sizeof (scp_addr_map_t);
for (i = 0; i < num; i++)
if (scp_addr_map[i].ap_addr == (0xf0000000 & ap_addr))
return (scp_addr_map[i].scp_addr |
(0x0fffffff & ap_addr));
PRINTF_E("err ap_addr:0x%x\n", ap_addr);
return 0;
}
uint32_t scp_to_ap(uint32_t scp_addr)
{
uint32_t i;
uint32_t num = sizeof (scp_addr_map) / sizeof (scp_addr_map_t);
for (i = 0; i < num; i++)
if (scp_addr_map[i].scp_addr == (0xf0000000 & scp_addr))
return (scp_addr_map[i].ap_addr |
(0x0fffffff & scp_addr));
PRINTF_E("err scp_addr:0x%x\n", scp_addr);
return 0;
}
/*
* In order to send the physical address for dma or other masters,
* address view in core1 needs to be remapped with a hardware offset.
*/
uint32_t scp_get_phy_addr(uint32_t addr)
{
if (mrv_read_csr(CSR_MHARTID) == 1) {
if (addr > DRV_Reg32(R_L2TCM_OFFSET_RANGE_0_LOW)
&& addr < DRV_Reg32(R_L2TCM_OFFSET_RANGE_0_HIGH))
addr += DRV_Reg32(R_L2TCM_OFFSET_ADD);
}
return addr;
}
#if DMA_KEEP_AWAKE
void dma_wake_lock_init(void)
{
wake_lock_init(&scp_dma_wakelock, "dmawk");
}
void dma_wake_lock(void)
{
if (!is_in_isr())
wake_lock(&scp_dma_wakelock);
else
wake_lock_FromISR(&scp_dma_wakelock);
}
void dma_wake_unlock(void)
{
uint32_t scp_sleep_flag;
int32_t channel;
/*scp_sleep_flag :0 release lock, 1:can not release lock */
scp_sleep_flag = 0;
for (channel = NR_GDMA_CHANNEL - 1; channel >= 0; channel--)
if (dma_channel[channel].in_use == 1)
scp_sleep_flag = 1;
if (scp_sleep_flag == 0) {
if (!is_in_isr())
wake_unlock(&scp_dma_wakelock);
else
wake_unlock_FromISR(&scp_dma_wakelock);
}
}
#endif
#if DMA_TRACE_DEBUG
void scp_dma_tracing(uint32_t dst, uint32_t src, uint32_t len);
void scp_dma_tracing(uint32_t dst, uint32_t src, uint32_t len)
{
int core_id = mrv_read_csr(CSR_MHARTID);
dma_trace[core_id].last_dst = dst;
dma_trace[core_id].last_src = src;
dma_trace[core_id].last_len = len;
#ifdef CFG_XGPT_SUPPORT
dma_trace[core_id].last_timestamp = read_xgpt_stamp_ns();
#endif
}
#endif
void scp_dma_dstCheck(uint32_t dst);
void scp_dma_dstCheck(uint32_t dst)
{
if (dst < (uint32_t)(&__sync_start))
configASSERT(0);
}
DMA_RESULT scp_dma_transaction(uint32_t dst_addr, uint32_t src_addr,
uint32_t len, int8_t scp_dma_id,
int32_t ch)
{
DMA_RESULT ret = 0;
dst_addr = scp_get_phy_addr(dst_addr);
src_addr = scp_get_phy_addr(src_addr);
#if DMA_TRACE_DEBUG
scp_dma_tracing(dst_addr, src_addr, len);
#endif
scp_dma_dstCheck(dst_addr);
ret =
dma_transaction(dst_addr, src_addr, len, scp_dma_id, ch, NULL, SYNC);
return ret;
}
DMA_RESULT scp_dma_transaction_dram(uint32_t dst_addr, uint32_t src_addr,
uint32_t len, int8_t scp_dma_id,
int32_t ch)
{
DMA_RESULT ret;
#ifdef CFG_VCORE_DVFS_SUPPORT
dvfs_enable_DRAM_resource(DMA_MEM_ID);
#endif
dst_addr = scp_get_phy_addr(dst_addr);
src_addr = scp_get_phy_addr(src_addr);
#if DMA_TRACE_DEBUG
scp_dma_tracing(dst_addr, src_addr, len);
#endif
scp_dma_dstCheck(dst_addr);
ret =
dma_transaction(dst_addr, src_addr, len, scp_dma_id, ch, NULL, SYNC);
#ifdef CFG_VCORE_DVFS_SUPPORT
dvfs_disable_DRAM_resource(DMA_MEM_ID);
#endif
return ret;
}