blob: 8ff797dca59bbad032ed10303055baa9784aab1b [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2013, ZTE Corporation.
*
* File Name: icp.c
* File Mark:
* Description:
* Others:
* Version: V0.1
* Author: ShiDeYou
* Date: 2013-3-13
* History 1:
* Date:
* Version:
* Author:
* Modification:
* History 2:
******************************************************************************/
/*******************************************************************************
* Include files *
*******************************************************************************/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <asm/mach/map.h>
#include <mach/rpmsg.h>
#include <linux/kthread.h>
/*******************************************************************************
* Macro *
*******************************************************************************/
/*******************************************************************************
* Global Variable *
*******************************************************************************/
static Icp_rpmsg_drv icp_arm0_info = {
.name = "icp_arm0",
.Channel_config =
{
.ChConfig = {CH_IRAM, CH_IRAM, CH_DDR, CH_DDR, CH_DDR, CH_DDR,CH_DDR,CH_DDR,\
CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR,CH_DDR,\
CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR,CH_DDR,\
CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR,CH_DDR,\
CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR,CH_DDR,\
CH_DDR},
},
};
static Icp_rpmsg_drv icp_m0_info = {
.name = "icp_m0",
.Channel_config =
{
.ChConfig = {CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM,CH_IRAM,\
CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM,\
CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM,CH_IRAM,\
CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM,CH_IRAM,\
CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM,CH_IRAM,
CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM},
},
};
Icp_rpmsg_drv *IcpRpMsgInfo[] = { &icp_m0_info, &icp_arm0_info, NULL };
T_HalRpMsg_RWP ap2cp_chinfo[ACTOR_MAXID][CHANNEL_MAXID];
T_HalRpMsg_RWP cp2ap_chinfo[ACTOR_MAXID][CHANNEL_MAXID];
/*******************************************************************************
* Function: zx29_Icp_SetInt
* Description: This function is used for generating icp interrupt to inform remote cpu;
* Parameters:
* Input:
actorID: id of remote cpu
chID: id of channel
* Output:None
*
* Returns:None
*
*
* Others:
********************************************************************************/
int icp_set_int(T_ZDrvRpMsg_ActorID actorID, T_ZDrvRpMsg_ChID chID)
{
T_HalRpMsg_ChInfo *channel_send = IcpRpMsgInfo[actorID]->ChInfo_Send_Base + chID;
if(!(channel_send->flag & CHANNEL_FLAG))
return RPMSG_CHANNEL_INEXISTANCE;
if(chID<32)
{
iowrite32((1<<chID), &(IcpRpMsgInfo[actorID]->IcpReg->control.low_word)) ;
}
else
{
iowrite32((1<<(chID - 32)),&(IcpRpMsgInfo[actorID]->IcpReg->control.high_word));
}
return RPMSG_SUCCESS;
}
/*******************************************************************************
* Function: zx29_Icp_ClearInt
* Description: This function is used for clear icp interrupt from remote cpu;
* Parameters:
* Input:
actorID: id of remote cpu
chID: id of channel
* Output:None
*
* Returns:None
*
*
* Others:
********************************************************************************/
void icp_clear_int(T_ZDrvRpMsg_ActorID actorID, T_ZDrvRpMsg_ChID chID)
{
if(chID<32)
{
iowrite32((1<<chID), &(IcpRpMsgInfo[actorID]->IcpReg->clear.low_word));
}
else
{
iowrite32(1<<(chID - 32), &(IcpRpMsgInfo[actorID]->IcpReg->clear.high_word)) ;
}
}
/*******************************************************************************
* Function: zx29_Icp_GetInt
* Description: This function is used for get icp interrupt from remote cpu;
* Parameters:
* Input:
* actorID: id of remote cpu
* chID: id of channel
* Output:None
*
* Returns:None
*
*
* Others:
********************************************************************************/
T_HalIcp_Dword icp_get_int(T_ZDrvRpMsg_ActorID actorID)
{
void __iomem *tmp = NULL;
T_HalIcp_Dword IcpState = {0};
tmp = &(IcpRpMsgInfo[actorID]->IcpReg->state.high_word);
IcpState.high_word = ioread32(tmp);
tmp = &(IcpRpMsgInfo[actorID]->IcpReg->state.low_word);
IcpState.low_word = ioread32(tmp);
return IcpState;
}
/*******************************************************************************
* Function: zx29_Icp_GetIntState
* Description: This function is used for get the state of icp interruptting of remote cpu;
* Parameters:
* Input:
actorID: id of remote cpu
chID: id of channel
* Output:None
*
* Returns:None
*
*
* Others:
********************************************************************************/
int icp_get_intstate(T_ZDrvRpMsg_ActorID actorID, T_ZDrvRpMsg_ChID chID)
{
if(chID < 32)
{
if(ioread32(&(IcpRpMsgInfo[actorID]->IcpReg->in_state.low_word)) & (0x1 << chID))
return TRUE;
else
return FALSE;
}
else
{
if(ioread32(&(IcpRpMsgInfo[actorID]->IcpReg->in_state.high_word)) & (0x1 << (chID - 32)))
return TRUE;
else
return FALSE;
}
}
/*******************************************************************************
* Function: zx29_Icp_Mask
* Description: This function is used for Mask interrupt of channel;
* Parameters:
* Input:
* Output:
*
* Returns: NONE
*
*
* Others:
********************************************************************************/
void icp_mask_int(T_ZDrvRpMsg_ActorID actorID, T_ZDrvRpMsg_ChID chID)
{
if(chID < 32)
{
IcpRpMsgInfo[actorID]->IcpReg->mask.low_word |=(0x1<<chID);
}
else
{
IcpRpMsgInfo[actorID]->IcpReg->mask.high_word |= (0x1<<(chID-32));
}
}
/*******************************************************************************
* Function: zx29_Icp_UnMask
* Description: This function is used for unmask interrupt of channel;
* Parameters:
* Input:
* Output:
*
* Returns:
* NONE
*
*
* Others:
********************************************************************************/
void icp_unmask_int(T_ZDrvRpMsg_ActorID actorID, T_ZDrvRpMsg_ChID chID)
{
if(chID < 32)
{
IcpRpMsgInfo[actorID]->IcpReg->mask.low_word &= ~(0x1<<chID);
}
else
{
IcpRpMsgInfo[actorID]->IcpReg->mask.high_word &= ~(0x1<<(chID-32));
}
}
static icp_operations icp_ops = {
.Icp_SetInt = icp_set_int,
.Icp_ClearInt = icp_clear_int,
.Icp_GetInt = icp_get_int,
.Icp_GetIntState = icp_get_intstate,
.Icp_Mask = icp_mask_int,
.Icp_UnMask = icp_unmask_int,
};
static int __devinit icp_probe(struct platform_device *pdev)
{
struct resource *icp_mem;
struct resource *icp_iram_send;
struct resource *icp_iram_recv;
struct resource *icp_ddr_send;
struct resource *icp_ddr_recv;
int ret;
Icp_rpmsg_drv *list;
unsigned int i;
list = IcpRpMsgInfo[pdev->id];
list->actorID = pdev->id;
list->intline = platform_get_irq(pdev, 0 );
icp_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "icp");
icp_iram_send = platform_get_resource_byname(pdev, IORESOURCE_MEM, "icp_iram_send");
icp_iram_recv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "icp_iram_recv");
icp_ddr_send = platform_get_resource_byname(pdev, IORESOURCE_MEM, "icp_ddr_send");
icp_ddr_recv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "icp_ddr_recv");
if (!icp_mem || !icp_iram_send || !icp_iram_recv)
return -ENOMEM;
list->IcpReg = (T_HalIcp_Reg *)ioremap(icp_mem->start, resource_size(icp_mem));
list->ChInfo_Send_Base = (T_HalRpMsg_ChInfo *)ioremap(icp_iram_send->start, resource_size(icp_iram_send));
list->ChInfo_Recv_Base = (T_HalRpMsg_ChInfo *)ioremap(icp_iram_recv->start, resource_size(icp_iram_recv));
list->ChInfo_SendBase_offset= (unsigned int)(list->ChInfo_Send_Base) - (unsigned int)(icp_iram_send->start);
list->ChInfo_RecvBase_offset= (unsigned int)(list->ChInfo_Recv_Base) - (unsigned int)(icp_iram_recv->start);
memset(list->ChInfo_Send_Base, 0, (CHANNEL_MAXID * sizeof(T_HalRpMsg_ChInfo)));
list->Ddr_SendBase = (unsigned int)(icp_ddr_send->start);
list->Ddr_RecvBase = (unsigned int)(icp_ddr_recv->start);
list->Ddr_SendBase_offset = (unsigned int)ioremap(icp_ddr_send->start, resource_size(icp_ddr_send)) - list->Ddr_SendBase;
list->Ddr_RecvBase_offset = (unsigned int)ioremap(icp_ddr_recv->start, resource_size(icp_ddr_recv)) - list->Ddr_RecvBase;
list->IcpReg->mask.high_word=0xffffffff;
list->IcpReg->mask.low_word=0xffffffff;
list->Channel_config.CurIramAddr = (unsigned int)(icp_iram_send->start + CHANNEL_MAXID * sizeof(T_HalRpMsg_ChInfo));
list->Channel_config.CurIramSpace_Size = icp_iram_send->end - icp_iram_send->start - CHANNEL_MAXID * sizeof(T_HalRpMsg_ChInfo);
list->Channel_config.CurDdrAddr = (unsigned int)(icp_ddr_send->start);
list->Channel_config.CurDdrSpace_Size = icp_ddr_send->end - icp_ddr_send->start;
if (!list->IcpReg && !list->Channel_config.CurIramAddr && !list->Channel_config.CurDdrAddr)
return -ENODEV;
list->ops = &icp_ops;
for(i = 0; i<CHANNEL_MAXID; i++)
{
ap2cp_chinfo[pdev->id][i].writep = &(((T_HalRpMsg_ChInfo *)(list->ChInfo_Send_Base + i))->SendPos);
ap2cp_chinfo[pdev->id][i].readp = &(((T_HalRpMsg_ChInfo *)(list->ChInfo_Recv_Base + i))->RecvPos);
ap2cp_chinfo[pdev->id][i].endp = &(((T_HalRpMsg_ChInfo *)(list->ChInfo_Send_Base + i))->EndAddr);
cp2ap_chinfo[pdev->id][i].writep = &(((T_HalRpMsg_ChInfo *)(list->ChInfo_Recv_Base + i))->SendPos);
cp2ap_chinfo[pdev->id][i].readp = &(((T_HalRpMsg_ChInfo *)(list->ChInfo_Send_Base + i))->RecvPos);
cp2ap_chinfo[pdev->id][i].endp = &(((T_HalRpMsg_ChInfo *)(list->ChInfo_Recv_Base + i))->EndAddr);
}
ret = icp_rpmsg_register(list);
if (ret)
goto unmap_base;
printk("rpmsg: icp_probe actorID = %d, success!\n", list->actorID);
return 0;
unmap_base:
iounmap(list->IcpReg);
iounmap(list->ChInfo_Send_Base);
iounmap(list->ChInfo_Recv_Base);
//iounmap((unsigned int *)(list->Ddr_SendBase_map));
//iounmap((unsigned int *)(list->Ddr_RecvBase_map));
return ret;
}
static int __devexit icp_remove(struct platform_device *pdev)
{
int ret = 0;
ret = icp_rpmsg_unregister(IcpRpMsgInfo[pdev->id]);
return ret;
}
static struct platform_driver icp_driver = {
.probe = icp_probe,
.remove = __devexit_p(icp_remove),
.driver = {
.name = "icp",
},
};
static int __init icp_init(void)
{
return platform_driver_register(&icp_driver);
}
subsys_initcall(icp_init);
static void __exit icp_exit(void)
{
platform_driver_unregister(&icp_driver);
}
module_exit(icp_exit);