0e6b068e89
* Build new libxtalk as local convenience library * Have new mpptalk.[ch] and astribank.[ch] wrap the new API * Modify all tools to use the new API Signed-off-by: Oron Peled <oron.peled@xorcom.com> Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
886 lines
25 KiB
C
886 lines
25 KiB
C
/*
|
|
* Written by Oron Peled <oron@actcom.co.il>
|
|
* Copyright (C) 2008, Xorcom
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <regex.h>
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
#include <oct6100api/oct6100_api.h>
|
|
#include <xtalk/debug.h>
|
|
#include <xtalk/xusb.h>
|
|
#include <astribank.h>
|
|
#include "echo_loader.h"
|
|
#include "parse_span_specs.h"
|
|
|
|
#ifdef __GNUC__
|
|
#define PACKED __attribute__((packed))
|
|
#else
|
|
#define PACKED
|
|
#endif
|
|
|
|
#define DBG_MASK 0x10
|
|
#define TIMEOUT 1000
|
|
#define ECHO_MAX_CHANS 128
|
|
#define ECHO_RIN_STREAM 0
|
|
#define ECHO_ROUT_STREAM 1
|
|
#define ECHO_SIN_STREAM 2
|
|
#define ECHO_SOUT_STREAM 3
|
|
|
|
#define ECHO_RIN_STREAM2 4
|
|
#define ECHO_SIN_STREAM2 6
|
|
#define ECHO_ROUT_STREAM2 5
|
|
#define ECHO_SOUT_STREAM2 7
|
|
|
|
#define EC_VER_TEST 0xABCD
|
|
#define EC_VER_INVALID 0xFFFF
|
|
static float oct_fw_load_timeout = 2.0;
|
|
|
|
struct echo_mod {
|
|
tPOCT6100_INSTANCE_API pApiInstance;
|
|
UINT32 ulEchoChanHndl[256];
|
|
struct astribank *astribank;
|
|
int maxchans;
|
|
};
|
|
|
|
enum xpp_packet_types {
|
|
SPI_SND_XOP = 0x0F,
|
|
SPI_RCV_XOP = 0x10,
|
|
TST_SND_XOP = 0x35,
|
|
TST_RCV_XOP = 0x36,
|
|
};
|
|
|
|
struct xpp_packet_header {
|
|
struct {
|
|
uint16_t len;
|
|
uint8_t op;
|
|
uint8_t unit;
|
|
} PACKED header;
|
|
union {
|
|
struct {
|
|
uint8_t header;
|
|
uint8_t flags;
|
|
uint8_t addr_l;
|
|
uint8_t addr_h;
|
|
uint8_t data_l;
|
|
uint8_t data_h;
|
|
} PACKED spi_pack;
|
|
struct {
|
|
uint8_t tid;
|
|
uint8_t tsid;
|
|
} PACKED tst_pack;
|
|
} alt;
|
|
} PACKED;
|
|
|
|
static struct usb_buffer {
|
|
char data[PACKET_SIZE];
|
|
int max_len;
|
|
int curr;
|
|
/* statistics */
|
|
int min_send;
|
|
int max_send;
|
|
int num_sends;
|
|
long total_bytes;
|
|
struct timeval start;
|
|
struct timeval end;
|
|
} usb_buffer;
|
|
|
|
|
|
static void usb_buffer_init(struct astribank *astribank, struct usb_buffer *ub)
|
|
{
|
|
ub->max_len = xusb_packet_size(xusb_dev_of_astribank(astribank));
|
|
ub->curr = 0;
|
|
ub->min_send = INT_MAX;
|
|
ub->max_send = 0;
|
|
ub->num_sends = 0;
|
|
ub->total_bytes = 0;
|
|
gettimeofday(&ub->start, NULL);
|
|
}
|
|
|
|
static long usb_buffer_usec(struct usb_buffer *ub)
|
|
{
|
|
struct timeval now;
|
|
|
|
gettimeofday(&now, NULL);
|
|
return (now.tv_sec - ub->start.tv_sec) * 1000000 +
|
|
(now.tv_usec - ub->start.tv_usec);
|
|
}
|
|
|
|
static void usb_buffer_showstatistics(struct astribank *astribank, struct usb_buffer *ub)
|
|
{
|
|
long usec;
|
|
|
|
usec = usb_buffer_usec(ub);
|
|
AB_INFO(astribank, "Octasic statistics: packet_size=[%d, %ld, %d] packets=%d, bytes=%ld msec=%ld usec/packet=%ld\n",
|
|
ub->min_send,
|
|
ub->total_bytes / ub->num_sends,
|
|
ub->max_send,
|
|
ub->num_sends, ub->total_bytes,
|
|
usec / 1000, usec / ub->num_sends);
|
|
}
|
|
|
|
static int usb_buffer_flush(struct astribank *astribank, struct usb_buffer *ub)
|
|
{
|
|
int ret;
|
|
long t;
|
|
long sec;
|
|
static int last_sec;
|
|
|
|
if (ub->curr == 0)
|
|
return 0;
|
|
ret = astribank_send(astribank, 0, ub->data, ub->curr, TIMEOUT);
|
|
if (ret < 0) {
|
|
AB_ERR(astribank, "xusb_send failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
DBG("%s: Written %d bytes\n", __func__, ret);
|
|
if (ret > ub->max_send)
|
|
ub->max_send = ret;
|
|
if (ret < ub->min_send)
|
|
ub->min_send = ret;
|
|
ub->total_bytes += ret;
|
|
ub->num_sends++;
|
|
ub->curr = 0;
|
|
|
|
sec = usb_buffer_usec(ub) / (1000 * 1000);
|
|
if (sec > last_sec) {
|
|
DBG("bytes/sec=%ld average len=%ld\n",
|
|
ub->total_bytes / sec,
|
|
ub->total_bytes / ub->num_sends);
|
|
last_sec = sec;
|
|
}
|
|
|
|
/*
|
|
* Best result with high frequency firmware: 21 seconds
|
|
* Octasic statistics: packet_size=[10, 239, 510] packets=26806, bytes=6419640 usec=21127883 usec/packet=788
|
|
* t = 0.3 * ret - 150;
|
|
*/
|
|
t = oct_fw_load_timeout * ret - 150;
|
|
if (t > 0)
|
|
usleep(t);
|
|
return ret;
|
|
}
|
|
|
|
static int usb_buffer_append(struct astribank *astribank, struct usb_buffer *ub,
|
|
char *buf, int len)
|
|
{
|
|
if (ub->curr + len >= ub->max_len) {
|
|
AB_ERR(astribank, "%s: buffer too small ub->curr=%d, len=%d, ub->max_len=%d\n",
|
|
__func__, ub->curr, len, ub->max_len);
|
|
return -ENOMEM;
|
|
}
|
|
memcpy(ub->data + ub->curr, buf, len);
|
|
ub->curr += len;
|
|
return len;
|
|
}
|
|
|
|
static int usb_buffer_send(struct astribank *astribank, struct usb_buffer *ub,
|
|
char *buf, int len, int timeout, int recv_answer)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (ub->curr + len >= ub->max_len) {
|
|
ret = usb_buffer_flush(astribank, ub);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
|
|
if ((ret = usb_buffer_append(astribank, ub, buf, len)) < 0) {
|
|
return ret;
|
|
}
|
|
DBG("%s: %d bytes %s\n", __func__, len, (recv_answer) ? "recv" : "send");
|
|
if (recv_answer) {
|
|
struct xpp_packet_header *phead;
|
|
|
|
ret = usb_buffer_flush(astribank, ub);
|
|
if (ret < 0)
|
|
return ret;
|
|
ret = astribank_recv(astribank, 0, buf, PACKET_SIZE, TIMEOUT);
|
|
if (ret <= 0) {
|
|
AB_ERR(astribank, "No USB packs to read: %s\n", strerror(-ret));
|
|
return -EINVAL;
|
|
}
|
|
DBG("%s: %d bytes recv\n", __func__, ret);
|
|
phead = (struct xpp_packet_header *)buf;
|
|
if (phead->header.op != SPI_RCV_XOP &&
|
|
phead->header.op != TST_RCV_XOP) {
|
|
AB_ERR(astribank, "Got unexpected reply OP=0x%02X\n",
|
|
phead->header.op);
|
|
dump_packet(LOG_ERR, DBG_MASK, "hexline[ERR]",
|
|
buf, ret);
|
|
return -EINVAL;
|
|
}
|
|
dump_packet(LOG_DEBUG, DBG_MASK, "dump:echoline[R]", (char *)phead, phead->header.len);
|
|
switch(phead->header.op) {
|
|
case SPI_RCV_XOP:
|
|
ret = (phead->alt.spi_pack.data_h << 8) | phead->alt.spi_pack.data_l;
|
|
break;
|
|
case TST_RCV_XOP:
|
|
ret = (phead->alt.tst_pack.tid << 8) | phead->alt.tst_pack.tsid;
|
|
break;
|
|
default:
|
|
ret = -EINVAL;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int spi_send(struct astribank *astribank, uint16_t addr, uint16_t data, int recv_answer, int ver)
|
|
{
|
|
int ret;
|
|
char buf[PACKET_SIZE];
|
|
struct xpp_packet_header *phead = (struct xpp_packet_header *)buf;
|
|
int pack_len;
|
|
int spi_flags;
|
|
|
|
assert(astribank != NULL);
|
|
spi_flags = 0x30 | (recv_answer ? 0x40 : 0x00) | (ver ? 0x01 : 0x00);
|
|
pack_len = sizeof(phead->header) + sizeof(phead->alt.spi_pack);
|
|
phead->header.len = pack_len;
|
|
phead->header.op = SPI_SND_XOP;
|
|
phead->header.unit = 0x40; /* EC has always this unit num */
|
|
phead->alt.spi_pack.header = 0x05;
|
|
phead->alt.spi_pack.flags = spi_flags;
|
|
phead->alt.spi_pack.addr_l = (addr >> 0) & 0xFF;
|
|
phead->alt.spi_pack.addr_h = (addr >> 8) & 0xFF;
|
|
phead->alt.spi_pack.data_l = (data >> 0) & 0xFF;
|
|
phead->alt.spi_pack.data_h = (data >> 8) & 0xFF;
|
|
|
|
dump_packet(LOG_DEBUG, DBG_MASK, "dump:echoline[W]", (char *)phead, pack_len);
|
|
|
|
|
|
ret = usb_buffer_send(astribank, &usb_buffer, buf, pack_len, TIMEOUT, recv_answer);
|
|
if (ret < 0) {
|
|
AB_ERR(astribank, "usb_buffer_send failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
DBG("%s: Written %d bytes\n", __func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
int test_send(struct astribank *astribank)
|
|
{
|
|
int ret;
|
|
char buf[PACKET_SIZE];
|
|
struct xpp_packet_header *phead = (struct xpp_packet_header *)buf;
|
|
int pack_len;
|
|
|
|
assert(astribank != NULL);
|
|
pack_len = sizeof(phead->header) + sizeof(phead->alt.tst_pack);
|
|
phead->header.len = 6;
|
|
phead->header.op = 0x35;
|
|
phead->header.unit = 0x00;
|
|
phead->alt.tst_pack.tid = 0x28; /* EC TestId */
|
|
phead->alt.tst_pack.tsid = 0x00; /* EC SubId */
|
|
|
|
dump_packet(LOG_DEBUG, DBG_MASK, "dump:echoline[W]",
|
|
(char *)phead, pack_len);
|
|
|
|
ret = usb_buffer_send(astribank,
|
|
&usb_buffer, buf, pack_len, TIMEOUT, 1);
|
|
if (ret < 0) {
|
|
AB_ERR(astribank, "usb_buffer_send failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
DBG("%s: Written %d bytes\n", __func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
int echo_send_data(struct astribank *astribank, const unsigned int addr, const unsigned int data)
|
|
{
|
|
int ret;
|
|
/* DBG("SEND: %04X -> [%04X]\n", data, addr);
|
|
DBG("\t\t[%04X] <- %04X\n", 0x0008, (addr >> 20));
|
|
DBG("\t\t[%04X] <- %04X\n", 0x000A, (addr >> 4) & ((1 << 16) - 1));
|
|
DBG("\t\t[%04X] <- %04X\n", 0x0004, data);
|
|
DBG("\t\t[%04X] <- %04X\n", 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | (3 << 12) | 1);
|
|
*/
|
|
|
|
DBG("SND:\n");
|
|
ret = spi_send(astribank, 0x0008, (addr >> 20) , 0, 0);
|
|
if (ret < 0)
|
|
goto failed;
|
|
ret = spi_send(astribank, 0x000A, (addr >> 4) & ((1 << 16) - 1) , 0, 0);
|
|
if (ret < 0)
|
|
goto failed;
|
|
ret = spi_send(astribank, 0x0004, data , 0, 0);
|
|
if (ret < 0)
|
|
goto failed;
|
|
ret = spi_send(astribank, 0x0000, (((addr >> 1) & 0x7) << 9) |
|
|
(1 << 8) | (3 << 12) | 1 , 0, 0);
|
|
if (ret < 0)
|
|
goto failed;
|
|
return cOCT6100_ERR_OK;
|
|
failed:
|
|
AB_ERR(astribank, "echo_send_data: spi_send failed (ret = %d)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
int echo_recv_data(struct astribank *astribank, const unsigned int addr)
|
|
{
|
|
unsigned int data = 0x00;
|
|
int ret;
|
|
|
|
DBG("RCV:\n");
|
|
ret = spi_send(astribank, 0x0008, (addr >> 20) , 0, 0);
|
|
if (ret < 0)
|
|
goto failed;
|
|
ret = spi_send(astribank, 0x000A, (addr >> 4) & ((1 << 16) - 1) , 0, 0);
|
|
if (ret < 0)
|
|
goto failed;
|
|
ret = spi_send(astribank, 0x0000, (((addr >> 1) & 0x7) << 9) |
|
|
(1 << 8) | 1 , 0, 0);
|
|
if (ret < 0)
|
|
goto failed;
|
|
ret = spi_send(astribank, 0x0004, data , 1, 0);
|
|
if (ret < 0)
|
|
goto failed;
|
|
return ret;
|
|
failed:
|
|
AB_ERR(astribank, "echo_recv_data: spi_send failed (ret = %d)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
int load_file(char *filename, unsigned char **ppBuf, UINT32 *pLen)
|
|
{
|
|
unsigned char *pbyFileData = NULL;
|
|
FILE *pFile;
|
|
|
|
DBG("Loading %s file...\n", filename);
|
|
pFile = fopen(filename, "rb");
|
|
if (pFile == NULL) {
|
|
ERR("fopen: %s\n", strerror(errno));
|
|
return -ENODEV;
|
|
}
|
|
|
|
fseek(pFile, 0L, SEEK_END);
|
|
*pLen = ftell(pFile);
|
|
fseek(pFile, 0L, SEEK_SET);
|
|
|
|
pbyFileData = (unsigned char *)malloc(*pLen);
|
|
if (pbyFileData == NULL) {
|
|
fclose(pFile);
|
|
ERR("malloc\n");
|
|
return -ENODEV;
|
|
} else {
|
|
DBG("allocated mem for pbyFileData\n");
|
|
}
|
|
if (fread(pbyFileData, 1, *pLen, pFile) != *pLen) {
|
|
fclose(pFile);
|
|
ERR("fread: %s\n", strerror(errno));
|
|
return -ENODEV;
|
|
}
|
|
fclose(pFile);
|
|
DBG("Successful loading %s file into memory "
|
|
"(size = %d, DUMP: first = %02X %02X, last = %02X %02X)\n",
|
|
filename, *pLen,
|
|
pbyFileData[0], pbyFileData[1],
|
|
pbyFileData[(*pLen)-2], pbyFileData[(*pLen)-1]);
|
|
*ppBuf = pbyFileData;
|
|
return 0;
|
|
}
|
|
|
|
UINT32 Oct6100UserGetTime(tPOCT6100_GET_TIME f_pTime)
|
|
{
|
|
///* Why couldn't they just take a timeval like everyone else? */
|
|
struct timeval tv;
|
|
unsigned long long total_usecs;
|
|
unsigned int mask = ~0;
|
|
|
|
gettimeofday(&tv, 0);
|
|
total_usecs = (((unsigned long long)(tv.tv_sec)) * 1000000) +
|
|
(((unsigned long long)(tv.tv_usec)));
|
|
f_pTime->aulWallTimeUs[0] = (total_usecs & mask);
|
|
f_pTime->aulWallTimeUs[1] = (total_usecs >> 32);
|
|
//printf("Inside of Oct6100UserGetTime\n");
|
|
return cOCT6100_ERR_OK;
|
|
}
|
|
|
|
UINT32 Oct6100UserMemSet(PVOID f_pAddress, UINT32 f_ulPattern, UINT32 f_ulLength)
|
|
{
|
|
memset(f_pAddress, f_ulPattern, f_ulLength);
|
|
return cOCT6100_ERR_OK;
|
|
}
|
|
|
|
UINT32 Oct6100UserMemCopy(PVOID f_pDestination, const void *f_pSource, UINT32 f_ulLength)
|
|
{
|
|
memcpy(f_pDestination, f_pSource, f_ulLength);
|
|
return cOCT6100_ERR_OK;
|
|
}
|
|
|
|
UINT32 Oct6100UserCreateSerializeObject(tPOCT6100_CREATE_SERIALIZE_OBJECT f_pCreate)
|
|
{
|
|
return cOCT6100_ERR_OK;
|
|
}
|
|
|
|
UINT32 Oct6100UserDestroySerializeObject(tPOCT6100_DESTROY_SERIALIZE_OBJECT f_pDestroy)
|
|
{
|
|
#ifdef OCTASIC_DEBUG
|
|
ERR("I should never be called! (destroy serialize object)\n");
|
|
#endif
|
|
return cOCT6100_ERR_OK;
|
|
}
|
|
|
|
UINT32 Oct6100UserSeizeSerializeObject(tPOCT6100_SEIZE_SERIALIZE_OBJECT f_pSeize)
|
|
{
|
|
/* Not needed */
|
|
return cOCT6100_ERR_OK;
|
|
}
|
|
|
|
UINT32 Oct6100UserReleaseSerializeObject(tPOCT6100_RELEASE_SERIALIZE_OBJECT f_pRelease)
|
|
{
|
|
/* Not needed */
|
|
return cOCT6100_ERR_OK;
|
|
}
|
|
|
|
UINT32 Oct6100UserDriverWriteApi(tPOCT6100_WRITE_PARAMS f_pWriteParams)
|
|
{
|
|
const unsigned int addr = f_pWriteParams->ulWriteAddress;
|
|
const unsigned int data = f_pWriteParams->usWriteData;
|
|
const struct echo_mod *echo_mod = (struct echo_mod *)(f_pWriteParams->pProcessContext);
|
|
struct astribank *astribank = echo_mod->astribank;
|
|
int ret;
|
|
|
|
ret = echo_send_data(astribank, addr, data);
|
|
if (ret < 0) {
|
|
ERR("echo_send_data failed (ret = %d)\n", ret);
|
|
return cOCT6100_ERR_FATAL_DRIVER_WRITE_API;
|
|
}
|
|
return cOCT6100_ERR_OK;
|
|
}
|
|
|
|
UINT32 Oct6100UserDriverWriteSmearApi(tPOCT6100_WRITE_SMEAR_PARAMS f_pSmearParams)
|
|
{
|
|
unsigned int addr;
|
|
unsigned int data;
|
|
unsigned int len;
|
|
const struct echo_mod *echo_mod;
|
|
struct astribank *astribank;
|
|
unsigned int i;
|
|
|
|
len = f_pSmearParams->ulWriteLength;
|
|
echo_mod = (struct echo_mod *)f_pSmearParams->pProcessContext;
|
|
astribank = echo_mod->astribank;
|
|
for (i = 0; i < len; i++) {
|
|
int ret;
|
|
|
|
addr = f_pSmearParams->ulWriteAddress + (i << 1);
|
|
data = f_pSmearParams->usWriteData;
|
|
ret = echo_send_data(astribank, addr, data);
|
|
if (ret < 0) {
|
|
ERR("echo_send_data failed (ret = %d)\n", ret);
|
|
return cOCT6100_ERR_FATAL_DRIVER_WRITE_API;
|
|
}
|
|
}
|
|
return cOCT6100_ERR_OK;
|
|
}
|
|
|
|
UINT32 Oct6100UserDriverWriteBurstApi(tPOCT6100_WRITE_BURST_PARAMS f_pBurstParams)
|
|
{
|
|
unsigned int addr;
|
|
unsigned int data;
|
|
unsigned int len = f_pBurstParams->ulWriteLength;
|
|
const struct echo_mod *echo_mod = (struct echo_mod *)f_pBurstParams->pProcessContext;
|
|
struct astribank *astribank = echo_mod->astribank;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
int ret;
|
|
|
|
addr = f_pBurstParams->ulWriteAddress + (i << 1);
|
|
data = f_pBurstParams->pusWriteData[i];
|
|
ret = echo_send_data(astribank, addr, data);
|
|
if (ret < 0) {
|
|
ERR("echo_send_data failed (ret = %d)\n", ret);
|
|
return cOCT6100_ERR_FATAL_DRIVER_WRITE_API;
|
|
}
|
|
}
|
|
return cOCT6100_ERR_OK;
|
|
}
|
|
|
|
UINT32 Oct6100UserDriverReadApi(tPOCT6100_READ_PARAMS f_pReadParams)
|
|
{
|
|
const unsigned int addr = f_pReadParams->ulReadAddress;
|
|
const struct echo_mod *echo_mod;
|
|
struct astribank *astribank;
|
|
int ret;
|
|
|
|
echo_mod = (struct echo_mod *)f_pReadParams->pProcessContext;
|
|
astribank = echo_mod->astribank;
|
|
ret = echo_recv_data(astribank, addr);
|
|
if (ret < 0) {
|
|
ERR("echo_recv_data failed (%d)\n", ret);
|
|
return cOCT6100_ERR_FATAL_DRIVER_READ_API;
|
|
}
|
|
*f_pReadParams->pusReadData = ret;
|
|
return cOCT6100_ERR_OK;
|
|
}
|
|
|
|
UINT32 Oct6100UserDriverReadBurstApi(tPOCT6100_READ_BURST_PARAMS f_pBurstParams)
|
|
{
|
|
unsigned int addr;
|
|
unsigned int len;
|
|
const struct echo_mod *echo_mod;
|
|
struct astribank *astribank;
|
|
unsigned int i;
|
|
|
|
len = f_pBurstParams->ulReadLength;
|
|
echo_mod = (struct echo_mod *)f_pBurstParams->pProcessContext;
|
|
astribank = echo_mod->astribank;
|
|
for (i = 0;i < len; i++) {
|
|
unsigned int ret;
|
|
|
|
addr = f_pBurstParams->ulReadAddress + (i << 1);
|
|
ret = echo_recv_data(astribank, addr);
|
|
if (ret < 0) {
|
|
ERR("echo_recv_data failed (%d)\n", ret);
|
|
return cOCT6100_ERR_FATAL_DRIVER_READ_API;
|
|
}
|
|
f_pBurstParams->pusReadData[i] = ret;
|
|
}
|
|
return cOCT6100_ERR_OK;
|
|
}
|
|
|
|
inline int get_ver(struct astribank *astribank)
|
|
{
|
|
return spi_send(astribank, 0, 0, 1, 1);
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
UINT32 init_octasic(char *filename, struct astribank *astribank, struct span_specs *span_specs)
|
|
{
|
|
int cpld_ver;
|
|
struct echo_mod *echo_mod;
|
|
UINT32 nChan;
|
|
UINT32 nSlot;
|
|
UINT32 pcmLaw;
|
|
UINT32 ulResult;
|
|
|
|
tOCT6100_GET_INSTANCE_SIZE InstanceSize;
|
|
tPOCT6100_INSTANCE_API pApiInstance;
|
|
tOCT6100_CHIP_OPEN OpenChip;
|
|
|
|
UINT32 ulImageByteSize;
|
|
PUINT8 pbyImageData = NULL;
|
|
|
|
/*=========================================================================*/
|
|
/* Channel resources.*/
|
|
tOCT6100_CHANNEL_OPEN ChannelOpen;
|
|
UINT32 ulChanHndl;
|
|
enum tdm_codec tdm_codec;
|
|
int spanno;
|
|
|
|
if (test_send(astribank) < 0)
|
|
return cOCT6100_ERR_FATAL;
|
|
cpld_ver = get_ver(astribank);
|
|
AB_INFO(astribank, "Check EC_CPLD version: %d\n", cpld_ver);
|
|
if (cpld_ver < 0)
|
|
return cOCT6100_ERR_FATAL;
|
|
else if (cpld_ver == EC_VER_TEST) {
|
|
AB_INFO(astribank, "+---------------------------------------------------------+\n");
|
|
AB_INFO(astribank, "| WARNING: TEST HARDWARE IS ON THE BOARD INSTEAD OF EC!!! |\n");
|
|
AB_INFO(astribank, "+---------------------------------------------------------+\n");
|
|
return cOCT6100_ERR_OK;
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
/**************************************************************************/
|
|
/* 1) Configure and Open the OCT6100. */
|
|
/**************************************************************************/
|
|
/**************************************************************************/
|
|
|
|
memset(&InstanceSize, 0, sizeof(tOCT6100_GET_INSTANCE_SIZE));
|
|
memset(&OpenChip, 0, sizeof(tOCT6100_CHIP_OPEN));
|
|
|
|
echo_mod = malloc(sizeof(struct echo_mod));
|
|
if (!echo_mod) {
|
|
AB_ERR(astribank, "cannot allocate memory for echo_mod\n");
|
|
return cOCT6100_ERR_FATAL;
|
|
}
|
|
DBG("allocated mem for echo_mod\n");
|
|
|
|
memset(echo_mod, 0, sizeof(struct echo_mod));
|
|
|
|
/* Fill the OCT6100 Chip Open configuration structure with default values */
|
|
|
|
ulResult = Oct6100ChipOpenDef(&OpenChip);
|
|
if (ulResult != cOCT6100_ERR_OK) {
|
|
AB_ERR(astribank, "Oct6100ChipOpenDef failed: result=%X\n",
|
|
ulResult);
|
|
return ulResult;
|
|
}
|
|
|
|
OpenChip.pProcessContext = echo_mod;
|
|
/* Configure clocks */
|
|
|
|
/* upclk oscillator is at 33.33 Mhz */
|
|
OpenChip.ulUpclkFreq = cOCT6100_UPCLK_FREQ_33_33_MHZ;
|
|
|
|
/* mclk will be generated by internal PLL at 133 Mhz */
|
|
OpenChip.fEnableMemClkOut = TRUE;
|
|
OpenChip.ulMemClkFreq = cOCT6100_MCLK_FREQ_133_MHZ;
|
|
|
|
/* General parameters */
|
|
OpenChip.fEnableChannelRecording = TRUE;
|
|
|
|
/* Chip ID.*/
|
|
OpenChip.ulUserChipId = 1;
|
|
|
|
/* Set the max number of accesses to 1024 to speed things up */
|
|
/* OpenChip.ulMaxRwAccesses = 1024; */
|
|
|
|
/* Set the maximums that the chip needs to support for this test */
|
|
OpenChip.ulMaxChannels = 256;
|
|
OpenChip.ulMaxPlayoutBuffers = 2;
|
|
|
|
OpenChip.ulMaxBiDirChannels = 0;
|
|
OpenChip.ulMaxConfBridges = 0;
|
|
OpenChip.ulMaxPhasingTssts = 0;
|
|
OpenChip.ulMaxTdmStreams = 8;
|
|
OpenChip.ulMaxTsiCncts = 0;
|
|
|
|
/* External Memory Settings: Use DDR memory*/
|
|
OpenChip.ulMemoryType = cOCT6100_MEM_TYPE_DDR;
|
|
|
|
OpenChip.ulNumMemoryChips = 1;
|
|
OpenChip.ulMemoryChipSize = cOCT6100_MEMORY_CHIP_SIZE_32MB;
|
|
|
|
|
|
/* Load the image file */
|
|
ulResult = load_file( filename,
|
|
&pbyImageData,
|
|
&ulImageByteSize);
|
|
|
|
if (ulResult != 0) {
|
|
AB_ERR(astribank, "Failed load_file %s (%08X)\n", filename, ulResult);
|
|
return ulResult;
|
|
}
|
|
if (pbyImageData == NULL || ulImageByteSize == 0){
|
|
AB_ERR(astribank, "Bad pbyImageData or ulImageByteSize\n");
|
|
return cOCT6100_ERR_FATAL;
|
|
}
|
|
|
|
/* Assign the image file.*/
|
|
OpenChip.pbyImageFile = pbyImageData;
|
|
OpenChip.ulImageSize = ulImageByteSize;
|
|
|
|
/*
|
|
* Inserting default values into tOCT6100_GET_INSTANCE_SIZE
|
|
* structure parameters.
|
|
*/
|
|
Oct6100GetInstanceSizeDef(&InstanceSize);
|
|
|
|
/* Get the size of the OCT6100 instance structure. */
|
|
ulResult = Oct6100GetInstanceSize(&OpenChip, &InstanceSize);
|
|
if (ulResult != cOCT6100_ERR_OK) {
|
|
AB_ERR(astribank, "Oct6100GetInstanceSize failed (%08X)\n",
|
|
ulResult);
|
|
return ulResult;
|
|
}
|
|
|
|
pApiInstance = malloc(InstanceSize.ulApiInstanceSize);
|
|
echo_mod->pApiInstance = pApiInstance;
|
|
echo_mod->astribank = astribank;
|
|
|
|
if (!pApiInstance) {
|
|
AB_ERR(astribank, "Out of memory (can't allocate %d bytes)!\n",
|
|
InstanceSize.ulApiInstanceSize);
|
|
return cOCT6100_ERR_FATAL;
|
|
}
|
|
|
|
/* Perform actual open of chip */
|
|
ulResult = Oct6100ChipOpen(pApiInstance, &OpenChip);
|
|
if (ulResult != cOCT6100_ERR_OK) {
|
|
AB_ERR(astribank, "Oct6100ChipOpen failed: result=%X\n",
|
|
ulResult);
|
|
return ulResult;
|
|
}
|
|
DBG("%s: OCT6100 is open\n", __func__);
|
|
|
|
/* Free the image file data */
|
|
free(pbyImageData);
|
|
|
|
/**************************************************************************/
|
|
/**************************************************************************/
|
|
/* 2) Open channels in echo cancellation mode. */
|
|
/**************************************************************************/
|
|
/**************************************************************************/
|
|
|
|
for (nChan = 0; nChan < ECHO_MAX_CHANS; nChan++) {
|
|
nSlot = nChan;
|
|
/* open a channel.*/
|
|
Oct6100ChannelOpenDef(&ChannelOpen);
|
|
|
|
/* Assign the handle memory.*/
|
|
ChannelOpen.pulChannelHndl = &ulChanHndl;
|
|
|
|
/* Set the channel to work at the echo cancellation mode.*/
|
|
ChannelOpen.ulEchoOperationMode = cOCT6100_ECHO_OP_MODE_NORMAL;
|
|
|
|
spanno = nChan % 4;
|
|
assert(spanno >= 0 && spanno < MAX_SPANNO);
|
|
tdm_codec = span_specs->span_is_alaw[spanno];
|
|
if (tdm_codec == TDM_CODEC_UNKNOWN) {
|
|
AB_ERR(astribank, "Calculated bad alaw/ulaw on channel %d\n", nChan);
|
|
return cOCT6100_ERR_FATAL;
|
|
}
|
|
if (nChan < 4)
|
|
AB_INFO(astribank, "ECHO PRI port %d = %s\n", spanno+1, (tdm_codec == TDM_CODEC_ALAW) ? "alaw" : "ulaw");
|
|
|
|
pcmLaw = ((tdm_codec == TDM_CODEC_ALAW) ? cOCT6100_PCM_A_LAW: cOCT6100_PCM_U_LAW);
|
|
|
|
/* Configure the TDM interface.*/
|
|
ChannelOpen.TdmConfig.ulRinPcmLaw = pcmLaw;
|
|
ChannelOpen.TdmConfig.ulRinStream = ECHO_RIN_STREAM;
|
|
ChannelOpen.TdmConfig.ulRinTimeslot = nSlot;
|
|
|
|
ChannelOpen.TdmConfig.ulSinPcmLaw = pcmLaw;
|
|
ChannelOpen.TdmConfig.ulSinStream = ECHO_SIN_STREAM;
|
|
ChannelOpen.TdmConfig.ulSinTimeslot = nSlot;
|
|
|
|
ChannelOpen.TdmConfig.ulRoutPcmLaw = pcmLaw;
|
|
ChannelOpen.TdmConfig.ulRoutStream = ECHO_ROUT_STREAM;
|
|
ChannelOpen.TdmConfig.ulRoutTimeslot = nSlot;
|
|
|
|
ChannelOpen.TdmConfig.ulSoutPcmLaw = pcmLaw;
|
|
ChannelOpen.TdmConfig.ulSoutStream = ECHO_SOUT_STREAM;
|
|
ChannelOpen.TdmConfig.ulSoutTimeslot = nSlot;
|
|
|
|
/* Set the desired VQE features.*/
|
|
ChannelOpen.VqeConfig.fEnableNlp = TRUE;
|
|
ChannelOpen.VqeConfig.fRinDcOffsetRemoval = TRUE;
|
|
ChannelOpen.VqeConfig.fSinDcOffsetRemoval = TRUE;
|
|
|
|
ChannelOpen.VqeConfig.ulComfortNoiseMode = cOCT6100_COMFORT_NOISE_NORMAL;
|
|
/* cOCT6100_COMFORT_NOISE_NORMAL
|
|
cOCT6100_COMFORT_NOISE_EXTENDED,
|
|
cOCT6100_COMFORT_NOISE_OFF,
|
|
cOCT6100_COMFORT_NOISE_FAST_LATCH
|
|
*/
|
|
ulResult = Oct6100ChannelOpen( pApiInstance,
|
|
&ChannelOpen);
|
|
if (ulResult != cOCT6100_ERR_OK) {
|
|
AB_ERR(astribank, "Found error on chan %d\n", nChan);
|
|
return ulResult;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/**************************************************************************/
|
|
/* *) Open channels in echo cancellation mode for second bus. */
|
|
/**************************************************************************/
|
|
/**************************************************************************/
|
|
|
|
for (nChan = 8; nChan < 32; nChan++) {
|
|
nSlot = (nChan >> 3) * 32 + (nChan & 0x07);
|
|
/* open a channel.*/
|
|
Oct6100ChannelOpenDef(&ChannelOpen);
|
|
|
|
/* Assign the handle memory.*/
|
|
ChannelOpen.pulChannelHndl = &ulChanHndl;
|
|
|
|
/* Set the channel to work at the echo cancellation mode.*/
|
|
ChannelOpen.ulEchoOperationMode = cOCT6100_ECHO_OP_MODE_NORMAL;
|
|
|
|
/* Configure the TDM interface.*/
|
|
ChannelOpen.TdmConfig.ulRinStream = ECHO_RIN_STREAM2;;
|
|
ChannelOpen.TdmConfig.ulRinTimeslot = nSlot;
|
|
|
|
ChannelOpen.TdmConfig.ulSinStream = ECHO_SIN_STREAM2;
|
|
ChannelOpen.TdmConfig.ulSinTimeslot = nSlot;
|
|
|
|
ChannelOpen.TdmConfig.ulRoutStream = ECHO_ROUT_STREAM2;
|
|
ChannelOpen.TdmConfig.ulRoutTimeslot = nSlot;
|
|
|
|
ChannelOpen.TdmConfig.ulSoutStream = ECHO_SOUT_STREAM2;
|
|
ChannelOpen.TdmConfig.ulSoutTimeslot = nSlot;
|
|
|
|
/* Set the desired VQE features.*/
|
|
ChannelOpen.VqeConfig.fEnableNlp = TRUE;
|
|
ChannelOpen.VqeConfig.fRinDcOffsetRemoval = TRUE;
|
|
ChannelOpen.VqeConfig.fSinDcOffsetRemoval = TRUE;
|
|
|
|
ChannelOpen.VqeConfig.ulComfortNoiseMode = cOCT6100_COMFORT_NOISE_NORMAL;
|
|
/* cOCT6100_COMFORT_NOISE_NORMAL
|
|
cOCT6100_COMFORT_NOISE_EXTENDED,
|
|
cOCT6100_COMFORT_NOISE_OFF,
|
|
cOCT6100_COMFORT_NOISE_FAST_LATCH
|
|
*/
|
|
ulResult = Oct6100ChannelOpen( pApiInstance,
|
|
&ChannelOpen);
|
|
if (ulResult != cOCT6100_ERR_OK) {
|
|
AB_ERR(astribank, "Found error on chan %d\n", nChan);
|
|
return ulResult;
|
|
}
|
|
}
|
|
|
|
|
|
DBG("%s: Finishing\n", __func__);
|
|
free(pApiInstance);
|
|
free(echo_mod);
|
|
return cOCT6100_ERR_OK;
|
|
|
|
}
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
int load_echo(struct astribank *astribank, char *filename, int default_is_alaw, const char *span_spec)
|
|
{
|
|
int ret;
|
|
UINT32 octasic_status;
|
|
struct span_specs *span_specs;
|
|
|
|
span_specs = parse_span_specifications(span_spec, default_is_alaw);
|
|
if (!span_specs) {
|
|
AB_ERR(astribank, "ECHO parsing span specs failed\n");
|
|
return -EFAULT;
|
|
}
|
|
AB_INFO(astribank, "Loading ECHOCAN Firmware: %s (default %s)\n",
|
|
filename, (default_is_alaw) ? "alaw" : "ulaw");
|
|
usb_buffer_init(astribank, &usb_buffer);
|
|
octasic_status = init_octasic(filename, astribank, span_specs);
|
|
free_span_specifications(span_specs);
|
|
if (octasic_status != cOCT6100_ERR_OK) {
|
|
AB_ERR(astribank, "ECHO %s burning failed (%08X)\n",
|
|
filename, octasic_status);
|
|
return -ENODEV;
|
|
}
|
|
ret = usb_buffer_flush(astribank, &usb_buffer);
|
|
if (ret < 0) {
|
|
AB_ERR(astribank, "ECHO %s buffer flush failed (%d)\n", filename, ret);
|
|
return -ENODEV;
|
|
}
|
|
usb_buffer_showstatistics(astribank, &usb_buffer);
|
|
return 0;
|
|
}
|
|
|
|
int echo_ver(struct astribank *astribank)
|
|
{
|
|
usb_buffer_init(astribank, &usb_buffer);
|
|
return get_ver(astribank);
|
|
}
|
|
|