Files
2026-07-30 11:19:44 +05:30

410 lines
13 KiB
C

/****************************************************************************
* sec2_init.c -- The Initialization code for SEC2 Driver
****************************************************************************
* Copyright (c) Certicom Corp. 1996-2002. All rights reserved
* Copyright (c) 2003-2005 Freescale Semiconductor
* All Rights Reserved. Proprietary and Confidential.
*
* NOTICE: The information contained in this file is proprietary
* to Freescale Semiconductor, and is being made available to
* Freescale's customers under strict license agreements.
* Use or disclosure of this information is permissible only
* under the terms of the existing license agreement.
***************************************************************************/
/* Revision History:
* 1.0 Aug 24,2003 dgs - adapted from the final version of mpc18x
* 1.1.0 Nov 16,2004 sec - incorporate linux changes from prior versions
* 1.1.1 Dec 16,2004 sec - remove old unused diagnostics
* 1.2 Jan 27,2005 sec - fix comments associated with global inhibit
*/
#define SEC2_GLOBAL
#define INIT_C
#include "Sec2Driver.h"
/* Interpeak begin */
#undef NUM_CHANNELS
#define NUM_CHANNELS (num_channels)
int num_channels;
extern int ipfreescale_sec_num_channels(void);
/* Interpeak end */
#if defined(DBG)
/* unsigned long SEC2DebugLevel = (DBGTXT_SETRQ | DBGTXT_SVCRQ | DBGTXT_INITDEV | DBGTXT_DPDSHOW | DBGTXT_INFO); */
unsigned long SEC2DebugLevel = (DBGTXT_INFO);
#else
unsigned long SEC2DebugLevel = 0x0;
#endif
#ifdef __KERNEL
EXPORT_SYMBOL(SEC2DebugLevel);
#endif
/*************************************************************************
* Function Name: SEC2DriverInit
* Purpose:
* Step1: Build base address by requesting peripheral base
* Step2: Init ChannelRegister & Cha Register
* Step3: Allocate Channel Assignments
* Step4: Init ChannelAssignments & ChaAssignments
* Step5: Init ProcessQueueTop & ProcessQueueBottom
* Step6: Init Semaphores
* Step7: Reset all Chas and Channels
* Step8: Config all Channels
* Step9: Connect Interrupt
* Step10: Enable Interrupt
* Step11: Return Success
*
* Input: None
*
* Return: SEC2_SUCCESS if everything passed, otherwise the error code
*************************************************************************/
/* static unsigned long CurrentCHAStatus[2]; */
int SEC2DriverInit(void)
{
static int status, i;
static int cha;
static int channel;
static unsigned long address;
static unsigned int idx[] = {0,2,4,3,5,1};
static char *coreID;
#ifdef __KERNEL__
bd_t *binfo = (bd_t *) __res;
#endif
/* Interpeak begin */
num_channels = ipfreescale_sec_num_channels();
/* Interpeak end */
/* Check prior initialization, and initialize driver per OS convention */
#ifdef VXWORKS
if (taskIdVerify (taskNameToId ("tSEC2_pc")) == OK) {
printf ("\nSecurity Processor already initialized\n");
return (OK);
}
#endif
#ifdef __KERNEL__
/* Anything not done in the module init hook? */
#endif
/* sysGetPeripheralBase() gets the PQ3 CCSBAR from the OS */
#ifdef VXWORKS
IOBaseAddress = (sysGetPeripheralBase() + TALITOS2X_BASE_ADDRESS);
#endif
/* get base from the kernel, and map it into an accessible region */
#ifdef __KERNEL__
IOBaseAddress = (unsigned long) ioremap((phys_addr_t)(binfo->bi_immr_base + TALITOS2X_BASE_ADDRESS), SEC2_BASE_SIZE);
#endif
/* Identify the running hardware */
SEC2Dump(DBGTXT_INFO, ("SEC 2.x Security Processor Core\n"));
SEC2Dump(DBGTXT_INFO, ("Driver Version %s %s %s\n", VERSION, __DATE__,__TIME__));
coremask = *((volatile unsigned long *)(IOBaseAddress + IDENTIFICATION_OFFSET) + 1);
switch(coremask)
{
case SEC_COREID_2_0_0:
coreID = "2.0.0";
break;
case SEC_COREID_2_1_0:
coreID = "2.1.0";
break;
default:
coreID = "unknown";
break;
}
SEC2Dump(DBGTXT_INFO, ("Security Core Version Mask: %s (0x%08lx)\n\n", coreID, coremask));
/* set up rebound cha index table */
memcpy ((char *)cha_idx, (char *)idx, sizeof (idx));
/* set up SEC2 register addresses */
/* controller registers */
ChaAssignmentStatusRegister = (volatile unsigned long*)
(IOBaseAddress + CHA_ASSIGNMENT_STATUS_OFFSET);
InterruptControlRegister = (volatile unsigned long*)
(IOBaseAddress + INTERRUPT_CONTROL_OFFSET);
InterruptStatusRegister = (volatile unsigned long*)
(IOBaseAddress + INTERRUPT_STATUS_OFFSET);
InterruptClearRegister = (volatile unsigned long*)
(IOBaseAddress + INTERRUPT_CLEAR_OFFSET);
IdRegister = (volatile unsigned long*)
(IOBaseAddress + IDENTIFICATION_OFFSET);
MasterControlRegister = (volatile unsigned long *)
(IOBaseAddress + SEC2_MASTER_CONTROL_REGISTER);
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->IOBaseAddress=0x%08lx\n", IOBaseAddress));
/* Reset the SEC2 */
/* Note that we turn on global inhibit for all processors. At the time */
/* of coding, GI only exists in the 8349; it's irrelevant to PQ3 devices. */
/* So, it's just turned on for all processors, which is OK for now. */
/* In time, this may be need to become an option in build configuration. */
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->reset Master Control Register\n"));
*(MasterControlRegister) = SEC2_RESET | SEC2_GLOBAL_INHIBIT;
*(MasterControlRegister + 1) = 0;
SEC2Dump(DBGTXT_INITDEV,
("SEC2DriverInit->IdRegister=0x%08lx 0x%08lx\n",
*(IdRegister),
*(IdRegister + 1)));
/* channel registers */
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->channel registers\n"));
for (channel=0, address=CHANNEL_CONFIG_BASE; channel<NUM_CHANNELS;
channel++,address+=CHANNEL_DISTANCE)
{
ChannelConfigRegister[channel] =
(volatile unsigned long*)(IOBaseAddress + address);
}
for (channel=0,address=CHANNEL_POINTER_STATUS_BASE; channel<NUM_CHANNELS;
channel++,address+=CHANNEL_DISTANCE)
{
ChannelPointerStatusRegister[channel] =
(volatile unsigned long*)(IOBaseAddress + address);
}
for (channel=0,address=CHANNEL_NEXT_DESCRIPTOR_BASE; channel<NUM_CHANNELS;
channel++,address+=CHANNEL_DISTANCE)
{
ChannelNextDescriptorRegister[channel] =
(volatile unsigned long*)(IOBaseAddress + address);
}
for (channel=0,address=CHANNEL_DBR_BASE; channel<NUM_CHANNELS;
channel++,address+=CHANNEL_DISTANCE)
{
ChannelDataBufferDescriptorRegister[channel] =
(volatile unsigned long*)(IOBaseAddress + address);
}
for (channel=0,address=CHANNEL_CDPR_BASE; channel<NUM_CHANNELS;
channel++,address+=CHANNEL_DISTANCE)
{
ChannelCurrentDescriptorPointerRegister[channel] =
(volatile unsigned long*)(IOBaseAddress + address);
}
/* cha registers */
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->cha registers\n"));
for (cha=0,address=CHA_RESET_CONTROL_BASE; cha<NUM_CHAS;
cha++,address+=CHA_DISTANCE)
{
ChaResetControlRegister[cha] =
(volatile unsigned long*)(IOBaseAddress + address);
}
for (cha=0,address=CHA_INTERRUPT_STATUS_BASE; cha<NUM_CHAS;
cha++,address+=CHA_DISTANCE)
{
ChaInterruptStatusRegister[cha_idx[cha]] =
(volatile unsigned long*)(IOBaseAddress + address);
}
for (cha=0,address=CHA_INTERRUPT_CONTROL_BASE; cha<NUM_CHAS;
cha++,address+=CHA_DISTANCE)
{
ChaInterruptControlRegister[cha] =
(volatile unsigned long*)(IOBaseAddress + address);
}
/* allocate other driver variables */
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->allocating other driver variables\n"));
/* variable init */
FreeChannels = NUM_CHANNELS;
FreeRngas = NUM_RNGAS;
FreeAfhas = NUM_AFHAS;
FreeDesas = NUM_DESAS;
FreeMdhas = NUM_MDHAS;
FreePkhas = NUM_PKHAS;
FreeAesas = NUM_AESAS;
/* Init ChannelAssignments */
for (channel=0; channel<NUM_CHANNELS; channel++)
{
if ((status = InitChannelAssignment(channel)) != SEC2_SUCCESS)
{
return status;
}
}
/* Init ChaAssignments */
for (cha=0; cha<16; cha++)
{
ChaAssignments[cha] = CHA_DYNAMIC;
}
/* initialize process queue */
for (i=0; i<QUEUE_ENTRY_DEPTH-1;i++)
Queue[i].next = &Queue[i+1];
Queue[QUEUE_ENTRY_DEPTH-1].next = &Queue[0];
for (i=1; i<QUEUE_ENTRY_DEPTH;i++)
Queue[i].previous = &Queue[i-1];
Queue[0].previous = &Queue[QUEUE_ENTRY_DEPTH-1];
ProcessQueueTop = &Queue[0];
ProcessQueueBottom = &Queue[0];
IOInitSemaphores();
#ifdef VXWORKS
if ((status = IOInitQs()) != SEC2_SUCCESS)
return status;
if ((status = IORegisterDriver()) != SEC2_SUCCESS)
return status;
#endif
/* reset all the CHA's */
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->reset Reset Control Register %d\n", NUM_CHAS));
for (cha=0; cha<NUM_CHAS; cha++)
{
*(ChaResetControlRegister[cha]) = 0;
*(ChaResetControlRegister[cha] + 1) = CHA_SOFTWARE_RESET;
if (cha == CHA_DES) /* is this cha des? */
{
*(ChaInterruptControlRegister[cha]) = 0;
*(ChaInterruptControlRegister[cha] + 1) = CHA_DESA_KEY_PARITY_ERROR_DISABLE;
}
if (cha == CHA_PKHA) /* is this cha the pkha? */
{
*(ChaInterruptControlRegister[cha]) = 0;
*(ChaInterruptControlRegister[cha] + 1) = CHA_PKHA_ILLEGAL_ADDR_ERROR_DISABLE;
}
}
/* reset all the channels */
SEC2Dump(DBGTXT_INITDEV,
("SEC2DriverInit->reset Crypto-Channel Configuration Registers %d\n",
NUM_CHANNELS));
for (channel=0; channel<NUM_CHANNELS; channel++)
{
/* reset the channel & configure the channels */
*(ChannelConfigRegister[channel]) = CHANNEL_RESET;
*(ChannelConfigRegister[channel] + 1) = 0;
*(ChannelConfigRegister[channel]) = 0;
*(ChannelConfigRegister[channel] + 1) = CHANNEL_INTEN | CHANNEL_BURST128;
}
/* Enable the main interrupt from SEC core at the controller/OS level */
if ((status = IOConnectInterrupt()) != SEC2_SUCCESS)
return status;
/* enable interrupts at the core level -- channels done and all errors */
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->enable interrupts\n"));
/* Unmask all "done" bits from all channels and accelerators */
*(InterruptControlRegister) = ALL_CHANNEL_INT_DONE_MASK | ALL_CHANNEL_INT_ERROR_MASK;
*(InterruptControlRegister + 1) = ALL_CHA_INT_ERROR_MASK;
SEC2Dump(DBGTXT_INITDEV, ("SEC2DriverInit->return SEC2_SUCCESS!\n"));
return SEC2_SUCCESS;
} /* end of DriverEntry */
IO_STATUS InitChannelAssignment(int channel)
{
size_t count;
SEC2Dump(DBGTXT_INITDEV, ("InitChannelAssignment channel=%d\n", channel+1));
ChannelAssignments[channel].assignment = CHANNEL_FREE;
ChannelAssignments[channel].ownerTaskId = 0;
ChannelAssignments[channel].pReq = NULL;
ChannelAssignments[channel].pCurrReq = NULL;
ChannelAssignments[channel].Dpds = &dpd[channel][0];
for (count=0; count<MAX_DPDS; count++)
{
ChannelAssignments[channel].Dpds[count] = &Descriptors[channel][count];
if (ChannelAssignments[channel].Dpds[count] == NULL)
return SEC2_IO_MEMORY_ALLOCATE_ERROR;
}
SEC2Dump(DBGTXT_INITDEV, ("InitChannelAssignment channel=%d done\n", channel+1));
return (SEC2_SUCCESS);
}
/* Module initialization stuff for Linux */
#ifdef __KERNEL__
/* fopts struct from device registration */
SEC2_GLOBAL struct file_operations sec2_fopts = {
open: SEC2Open,
release: SEC2Close,
ioctl: SEC2_ioctl,
};
static int __init sec2_init(void)
{
int rtstat;
/* Assume that this is going to be a chrdev */
/* If a major number isn't specified, default to dynamic assignment */
rtstat = register_chrdev(SEC2_DEVMAJOR, SEC2_DEVNAME, &sec2_fopts);
if (rtstat < 0) {
printk(KERN_WARNING "sec2drv: can't register driver, fatal\n");
return rtstat;
}
if (SEC2_DEVMAJOR == 0) /* if no specific major requested, and there was no error above */
sec2_devmajor = rtstat; /* set the dynamic number */
/* Now go call the standard driver initialization */
return SEC2DriverInit();
}
static void __exit sec2_exit(void)
{
int rtstat;
rtstat = unregister_chrdev(sec2_devmajor, SEC2_DEVNAME);
free_irq(MPC85xx_IRQ_SEC, NULL);
}
EXPORT_SYMBOL (SEC2_ioctl);
EXPORT_SYMBOL (MarkScatterBuffer);
/* EXPORT_SYMTAB */
module_init(sec2_init);
module_exit(sec2_exit);
MODULE_LICENSE("Freescale Restricted");
MODULE_DESCRIPTION("SEC 2.x Security Core Device Driver");
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
#endif