yuezonghe | 824eb0c | 2024-06-27 02:32:26 -0700 | [diff] [blame^] | 1 | /******************************************************************************* |
| 2 | * Copyright (C) 2013, ZTE Corporation. |
| 3 | * |
| 4 | * File Name: icp.c |
| 5 | * File Mark: |
| 6 | * Description: |
| 7 | * Others: |
| 8 | * Version: V0.1 |
| 9 | * Author: ShiDeYou |
| 10 | * Date: 2013-3-13 |
| 11 | * History 1: |
| 12 | * Date: |
| 13 | * Version: |
| 14 | * Author: |
| 15 | * Modification: |
| 16 | * History 2: |
| 17 | ******************************************************************************/ |
| 18 | |
| 19 | /******************************************************************************* |
| 20 | * Include files * |
| 21 | *******************************************************************************/ |
| 22 | #include <linux/clk.h> |
| 23 | #include <linux/err.h> |
| 24 | #include <linux/platform_device.h> |
| 25 | #include <linux/io.h> |
| 26 | #include <linux/slab.h> |
| 27 | #include <linux/delay.h> |
| 28 | #include <linux/pm_runtime.h> |
| 29 | #include <mach/irqs.h> |
| 30 | #include <mach/iomap.h> |
| 31 | #include <asm/mach/map.h> |
| 32 | #include <mach/rpmsg.h> |
| 33 | #include <linux/kthread.h> |
| 34 | |
| 35 | |
| 36 | /******************************************************************************* |
| 37 | * Macro * |
| 38 | *******************************************************************************/ |
| 39 | |
| 40 | |
| 41 | /******************************************************************************* |
| 42 | * Global Variable * |
| 43 | *******************************************************************************/ |
| 44 | |
| 45 | static Icp_rpmsg_drv icp_arm0_info = { |
| 46 | .name = "icp_arm0", |
| 47 | .Channel_config = |
| 48 | { |
| 49 | .ChConfig = {CH_IRAM, CH_IRAM, CH_DDR, CH_DDR, CH_DDR, CH_DDR,CH_DDR,CH_DDR,\ |
| 50 | CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR,CH_DDR,\ |
| 51 | CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR,CH_DDR,\ |
| 52 | CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR,CH_DDR,\ |
| 53 | CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR, CH_DDR,CH_DDR,\ |
| 54 | CH_DDR}, |
| 55 | }, |
| 56 | }; |
| 57 | |
| 58 | static Icp_rpmsg_drv icp_m0_info = { |
| 59 | .name = "icp_m0", |
| 60 | .Channel_config = |
| 61 | { |
| 62 | .ChConfig = {CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM,CH_IRAM,\ |
| 63 | CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM,\ |
| 64 | CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM,CH_IRAM,\ |
| 65 | CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM,CH_IRAM,\ |
| 66 | CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM,CH_IRAM, |
| 67 | CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM, CH_IRAM}, |
| 68 | }, |
| 69 | }; |
| 70 | |
| 71 | Icp_rpmsg_drv *IcpRpMsgInfo[] = { &icp_m0_info, &icp_arm0_info, NULL }; |
| 72 | |
| 73 | T_HalRpMsg_RWP ap2cp_chinfo[ACTOR_MAXID][CHANNEL_MAXID]; |
| 74 | T_HalRpMsg_RWP cp2ap_chinfo[ACTOR_MAXID][CHANNEL_MAXID]; |
| 75 | |
| 76 | /******************************************************************************* |
| 77 | * Function: zx29_Icp_SetInt |
| 78 | * Description: This function is used for generating icp interrupt to inform remote cpu; |
| 79 | * Parameters: |
| 80 | * Input: |
| 81 | actorID: id of remote cpu |
| 82 | chID: id of channel |
| 83 | * Output:None |
| 84 | * |
| 85 | * Returns:None |
| 86 | * |
| 87 | * |
| 88 | * Others: |
| 89 | ********************************************************************************/ |
| 90 | int icp_set_int(T_ZDrvRpMsg_ActorID actorID, T_ZDrvRpMsg_ChID chID) |
| 91 | { |
| 92 | T_HalRpMsg_ChInfo *channel_send = IcpRpMsgInfo[actorID]->ChInfo_Send_Base + chID; |
| 93 | |
| 94 | if(!(channel_send->flag & CHANNEL_FLAG)) |
| 95 | return RPMSG_CHANNEL_INEXISTANCE; |
| 96 | |
| 97 | if(chID<32) |
| 98 | { |
| 99 | iowrite32((1<<chID), &(IcpRpMsgInfo[actorID]->IcpReg->control.low_word)) ; |
| 100 | } |
| 101 | else |
| 102 | { |
| 103 | iowrite32((1<<(chID - 32)),&(IcpRpMsgInfo[actorID]->IcpReg->control.high_word)); |
| 104 | } |
| 105 | return RPMSG_SUCCESS; |
| 106 | } |
| 107 | |
| 108 | /******************************************************************************* |
| 109 | * Function: zx29_Icp_ClearInt |
| 110 | * Description: This function is used for clear icp interrupt from remote cpu; |
| 111 | * Parameters: |
| 112 | * Input: |
| 113 | actorID: id of remote cpu |
| 114 | chID: id of channel |
| 115 | * Output:None |
| 116 | * |
| 117 | * Returns:None |
| 118 | * |
| 119 | * |
| 120 | * Others: |
| 121 | ********************************************************************************/ |
| 122 | void icp_clear_int(T_ZDrvRpMsg_ActorID actorID, T_ZDrvRpMsg_ChID chID) |
| 123 | { |
| 124 | if(chID<32) |
| 125 | { |
| 126 | iowrite32((1<<chID), &(IcpRpMsgInfo[actorID]->IcpReg->clear.low_word)); |
| 127 | } |
| 128 | else |
| 129 | { |
| 130 | iowrite32(1<<(chID - 32), &(IcpRpMsgInfo[actorID]->IcpReg->clear.high_word)) ; |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | /******************************************************************************* |
| 135 | * Function: zx29_Icp_GetInt |
| 136 | * Description: This function is used for get icp interrupt from remote cpu; |
| 137 | * Parameters: |
| 138 | * Input: |
| 139 | * actorID: id of remote cpu |
| 140 | * chID: id of channel |
| 141 | * Output:None |
| 142 | * |
| 143 | * Returns:None |
| 144 | * |
| 145 | * |
| 146 | * Others: |
| 147 | ********************************************************************************/ |
| 148 | T_HalIcp_Dword icp_get_int(T_ZDrvRpMsg_ActorID actorID) |
| 149 | { |
| 150 | void __iomem *tmp = NULL; |
| 151 | T_HalIcp_Dword IcpState = {0}; |
| 152 | tmp = &(IcpRpMsgInfo[actorID]->IcpReg->state.high_word); |
| 153 | IcpState.high_word = ioread32(tmp); |
| 154 | tmp = &(IcpRpMsgInfo[actorID]->IcpReg->state.low_word); |
| 155 | IcpState.low_word = ioread32(tmp); |
| 156 | |
| 157 | return IcpState; |
| 158 | } |
| 159 | |
| 160 | /******************************************************************************* |
| 161 | * Function: zx29_Icp_GetIntState |
| 162 | * Description: This function is used for get the state of icp interruptting of remote cpu; |
| 163 | * Parameters: |
| 164 | * Input: |
| 165 | actorID: id of remote cpu |
| 166 | chID: id of channel |
| 167 | * Output:None |
| 168 | * |
| 169 | * Returns:None |
| 170 | * |
| 171 | * |
| 172 | * Others: |
| 173 | ********************************************************************************/ |
| 174 | int icp_get_intstate(T_ZDrvRpMsg_ActorID actorID, T_ZDrvRpMsg_ChID chID) |
| 175 | { |
| 176 | if(chID < 32) |
| 177 | { |
| 178 | if(ioread32(&(IcpRpMsgInfo[actorID]->IcpReg->in_state.low_word)) & (0x1 << chID)) |
| 179 | return TRUE; |
| 180 | else |
| 181 | return FALSE; |
| 182 | } |
| 183 | else |
| 184 | { |
| 185 | if(ioread32(&(IcpRpMsgInfo[actorID]->IcpReg->in_state.high_word)) & (0x1 << (chID - 32))) |
| 186 | return TRUE; |
| 187 | else |
| 188 | return FALSE; |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | /******************************************************************************* |
| 193 | * Function: zx29_Icp_Mask |
| 194 | * Description: This function is used for Mask interrupt of channel; |
| 195 | * Parameters: |
| 196 | * Input: |
| 197 | * Output: |
| 198 | * |
| 199 | * Returns: NONE |
| 200 | * |
| 201 | * |
| 202 | * Others: |
| 203 | ********************************************************************************/ |
| 204 | void icp_mask_int(T_ZDrvRpMsg_ActorID actorID, T_ZDrvRpMsg_ChID chID) |
| 205 | { |
| 206 | if(chID < 32) |
| 207 | { |
| 208 | IcpRpMsgInfo[actorID]->IcpReg->mask.low_word |=(0x1<<chID); |
| 209 | } |
| 210 | else |
| 211 | { |
| 212 | IcpRpMsgInfo[actorID]->IcpReg->mask.high_word |= (0x1<<(chID-32)); |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | /******************************************************************************* |
| 217 | * Function: zx29_Icp_UnMask |
| 218 | * Description: This function is used for unmask interrupt of channel; |
| 219 | * Parameters: |
| 220 | * Input: |
| 221 | * Output: |
| 222 | * |
| 223 | * Returns: |
| 224 | * NONE |
| 225 | * |
| 226 | * |
| 227 | * Others: |
| 228 | ********************************************************************************/ |
| 229 | void icp_unmask_int(T_ZDrvRpMsg_ActorID actorID, T_ZDrvRpMsg_ChID chID) |
| 230 | { |
| 231 | if(chID < 32) |
| 232 | { |
| 233 | IcpRpMsgInfo[actorID]->IcpReg->mask.low_word &= ~(0x1<<chID); |
| 234 | } |
| 235 | else |
| 236 | { |
| 237 | IcpRpMsgInfo[actorID]->IcpReg->mask.high_word &= ~(0x1<<(chID-32)); |
| 238 | } |
| 239 | |
| 240 | } |
| 241 | |
| 242 | static icp_operations icp_ops = { |
| 243 | .Icp_SetInt = icp_set_int, |
| 244 | .Icp_ClearInt = icp_clear_int, |
| 245 | .Icp_GetInt = icp_get_int, |
| 246 | .Icp_GetIntState = icp_get_intstate, |
| 247 | .Icp_Mask = icp_mask_int, |
| 248 | .Icp_UnMask = icp_unmask_int, |
| 249 | }; |
| 250 | |
| 251 | |
| 252 | |
| 253 | |
| 254 | static int __devinit icp_probe(struct platform_device *pdev) |
| 255 | { |
| 256 | struct resource *icp_mem; |
| 257 | struct resource *icp_iram_send; |
| 258 | struct resource *icp_iram_recv; |
| 259 | struct resource *icp_ddr_send; |
| 260 | struct resource *icp_ddr_recv; |
| 261 | |
| 262 | int ret; |
| 263 | Icp_rpmsg_drv *list; |
| 264 | unsigned int i; |
| 265 | |
| 266 | list = IcpRpMsgInfo[pdev->id]; |
| 267 | list->actorID = pdev->id; |
| 268 | |
| 269 | list->intline = platform_get_irq(pdev, 0 ); |
| 270 | |
| 271 | icp_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "icp"); |
| 272 | icp_iram_send = platform_get_resource_byname(pdev, IORESOURCE_MEM, "icp_iram_send"); |
| 273 | icp_iram_recv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "icp_iram_recv"); |
| 274 | icp_ddr_send = platform_get_resource_byname(pdev, IORESOURCE_MEM, "icp_ddr_send"); |
| 275 | icp_ddr_recv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "icp_ddr_recv"); |
| 276 | |
| 277 | if (!icp_mem || !icp_iram_send || !icp_iram_recv) |
| 278 | return -ENOMEM; |
| 279 | |
| 280 | list->IcpReg = (T_HalIcp_Reg *)ioremap(icp_mem->start, resource_size(icp_mem)); |
| 281 | list->ChInfo_Send_Base = (T_HalRpMsg_ChInfo *)ioremap(icp_iram_send->start, resource_size(icp_iram_send)); |
| 282 | list->ChInfo_Recv_Base = (T_HalRpMsg_ChInfo *)ioremap(icp_iram_recv->start, resource_size(icp_iram_recv)); |
| 283 | list->ChInfo_SendBase_offset= (unsigned int)(list->ChInfo_Send_Base) - (unsigned int)(icp_iram_send->start); |
| 284 | list->ChInfo_RecvBase_offset= (unsigned int)(list->ChInfo_Recv_Base) - (unsigned int)(icp_iram_recv->start); |
| 285 | |
| 286 | memset(list->ChInfo_Send_Base, 0, (CHANNEL_MAXID * sizeof(T_HalRpMsg_ChInfo))); |
| 287 | |
| 288 | list->Ddr_SendBase = (unsigned int)(icp_ddr_send->start); |
| 289 | list->Ddr_RecvBase = (unsigned int)(icp_ddr_recv->start); |
| 290 | list->Ddr_SendBase_offset = (unsigned int)ioremap(icp_ddr_send->start, resource_size(icp_ddr_send)) - list->Ddr_SendBase; |
| 291 | list->Ddr_RecvBase_offset = (unsigned int)ioremap(icp_ddr_recv->start, resource_size(icp_ddr_recv)) - list->Ddr_RecvBase; |
| 292 | |
| 293 | list->IcpReg->mask.high_word=0xffffffff; |
| 294 | list->IcpReg->mask.low_word=0xffffffff; |
| 295 | |
| 296 | list->Channel_config.CurIramAddr = (unsigned int)(icp_iram_send->start + CHANNEL_MAXID * sizeof(T_HalRpMsg_ChInfo)); |
| 297 | list->Channel_config.CurIramSpace_Size = icp_iram_send->end - icp_iram_send->start - CHANNEL_MAXID * sizeof(T_HalRpMsg_ChInfo); |
| 298 | list->Channel_config.CurDdrAddr = (unsigned int)(icp_ddr_send->start); |
| 299 | list->Channel_config.CurDdrSpace_Size = icp_ddr_send->end - icp_ddr_send->start; |
| 300 | |
| 301 | if (!list->IcpReg && !list->Channel_config.CurIramAddr && !list->Channel_config.CurDdrAddr) |
| 302 | return -ENODEV; |
| 303 | |
| 304 | list->ops = &icp_ops; |
| 305 | |
| 306 | for(i = 0; i<CHANNEL_MAXID; i++) |
| 307 | { |
| 308 | ap2cp_chinfo[pdev->id][i].writep = &(((T_HalRpMsg_ChInfo *)(list->ChInfo_Send_Base + i))->SendPos); |
| 309 | ap2cp_chinfo[pdev->id][i].readp = &(((T_HalRpMsg_ChInfo *)(list->ChInfo_Recv_Base + i))->RecvPos); |
| 310 | ap2cp_chinfo[pdev->id][i].endp = &(((T_HalRpMsg_ChInfo *)(list->ChInfo_Send_Base + i))->EndAddr); |
| 311 | cp2ap_chinfo[pdev->id][i].writep = &(((T_HalRpMsg_ChInfo *)(list->ChInfo_Recv_Base + i))->SendPos); |
| 312 | cp2ap_chinfo[pdev->id][i].readp = &(((T_HalRpMsg_ChInfo *)(list->ChInfo_Send_Base + i))->RecvPos); |
| 313 | cp2ap_chinfo[pdev->id][i].endp = &(((T_HalRpMsg_ChInfo *)(list->ChInfo_Recv_Base + i))->EndAddr); |
| 314 | } |
| 315 | |
| 316 | ret = icp_rpmsg_register(list); |
| 317 | |
| 318 | if (ret) |
| 319 | goto unmap_base; |
| 320 | |
| 321 | printk("rpmsg: icp_probe actorID = %d, success!\n", list->actorID); |
| 322 | |
| 323 | return 0; |
| 324 | |
| 325 | unmap_base: |
| 326 | iounmap(list->IcpReg); |
| 327 | iounmap(list->ChInfo_Send_Base); |
| 328 | iounmap(list->ChInfo_Recv_Base); |
| 329 | //iounmap((unsigned int *)(list->Ddr_SendBase_map)); |
| 330 | //iounmap((unsigned int *)(list->Ddr_RecvBase_map)); |
| 331 | |
| 332 | |
| 333 | |
| 334 | return ret; |
| 335 | } |
| 336 | |
| 337 | static int __devexit icp_remove(struct platform_device *pdev) |
| 338 | { |
| 339 | int ret = 0; |
| 340 | ret = icp_rpmsg_unregister(IcpRpMsgInfo[pdev->id]); |
| 341 | return ret; |
| 342 | } |
| 343 | |
| 344 | static struct platform_driver icp_driver = { |
| 345 | .probe = icp_probe, |
| 346 | .remove = __devexit_p(icp_remove), |
| 347 | .driver = { |
| 348 | .name = "icp", |
| 349 | }, |
| 350 | }; |
| 351 | |
| 352 | static int __init icp_init(void) |
| 353 | { |
| 354 | return platform_driver_register(&icp_driver); |
| 355 | } |
| 356 | |
| 357 | subsys_initcall(icp_init); |
| 358 | |
| 359 | static void __exit icp_exit(void) |
| 360 | { |
| 361 | platform_driver_unregister(&icp_driver); |
| 362 | } |
| 363 | |
| 364 | module_exit(icp_exit); |
| 365 | |
| 366 | |