blob: e74aaa509cceed8863bb67068d40f67297d1e467 [file] [log] [blame]
/******************************************************************************
*
* Copyright (C) 2016-2017 Cadence Design Systems, Inc.
* All rights reserved worldwide.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE SOFTWARE IS PROVIDED "AS IS",
* WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Copyright 2017-2018 NXP
*
******************************************************************************
*
* util.c
*
******************************************************************************
*/
#include "util.h"
#include "API_General.h"
#include "externs.h"
#ifndef __UBOOT__
#include <string.h>
#endif
#include "apb_cfg.h"
#include "opcodes.h"
#ifndef __UBOOT__
#include <stdio.h>
#endif
state_struct state;
int cdn_bus_read(unsigned int addr, unsigned int *value)
{
return state.bus_type ?
cdn_sapb_read(addr, value) : cdn_apb_read(addr, value);
}
int cdn_bus_write(unsigned int addr, unsigned int value)
{
return state.bus_type ?
cdn_sapb_write(addr, value) : cdn_apb_write(addr, value);
}
void internal_itobe(int val, volatile unsigned char *dest, int bytes)
{
int i;
for (i = bytes - 1; i >= 0; --i) {
dest[i] = (unsigned char)val;
val >>= 8;
}
}
uint32_t internal_betoi(volatile uint8_t const *src, uint8_t bytes)
{
uint32_t ret = 0;
int i;
if (bytes > sizeof(ret)) {
printf("Warning. Read request for payload larger then supported.\n");
bytes = sizeof(ret);
}
for (i = 0; i < bytes; ++i) {
ret <<= 8;
ret |= (unsigned int)src[i];
}
return ret;
}
unsigned int internal_mkmsg(volatile unsigned char *dest, int valno, ...)
{
va_list vl;
unsigned int len = 0;
va_start(vl, valno);
len = internal_vmkmsg(dest, valno, vl);
va_end(vl);
return len;
}
unsigned int internal_vmkmsg(volatile unsigned char *dest, int valno,
va_list vl)
{
unsigned int len = 0;
int i;
for (i = 0; i < valno; ++i) {
int size = va_arg(vl, int);
if (size > 0) {
internal_itobe(va_arg(vl, int), dest, size);
dest += size;
len += size;
} else {
memcpy((void *)dest, va_arg(vl, void *), -size);
dest -= size;
len -= size;
}
}
return len;
}
void internal_tx_mkfullmsg(unsigned char module, unsigned char opcode,
int valno, ...)
{
va_list vl;
va_start(vl, valno);
internal_vtx_mkfullmsg(module, opcode, valno, vl);
va_end(vl);
}
void internal_vtx_mkfullmsg(unsigned char module, unsigned char opcode,
int valno, va_list vl)
{
unsigned int len =
internal_vmkmsg(state.txbuffer + INTERNAL_CMD_HEAD_SIZE, valno, vl);
internal_mbox_tx_enable(module, opcode, len);
state.txenable = 1;
state.running = 1;
}
void internal_readmsg(int valno, ...)
{
va_list vl;
va_start(vl, valno);
internal_vreadmsg(valno, vl);
va_end(vl);
}
void internal_vreadmsg(int valno, va_list vl)
{
uint8_t *src = state.rxbuffer + INTERNAL_CMD_HEAD_SIZE;
size_t i;
for (i = 0; i < (size_t) valno; ++i) {
int size = va_arg(vl, int);
void *ptr = va_arg(vl, void *);
if (!ptr) {
src += size;
} else if (!size) {
*((unsigned char **)ptr) = src;
} else if (size > 0) {
switch ((size_t) size) {
case sizeof(uint8_t):
*((uint8_t *)ptr) = internal_betoi(src, size);
break;
case sizeof(uint16_t):
*((uint16_t *)ptr) = internal_betoi(src, size);
break;
case 3: /* 3-byte value (e.g. DPCD address)
can be safely converted from BE.*/
case sizeof(uint32_t):
*((uint32_t *)ptr) = internal_betoi(src, size);
break;
default:
printf("Warning. Unsupported variable size.\n");
memcpy(ptr, src, size);
};
src += size;
} else {
memcpy(ptr, src, -size);
src -= size;
}
}
}
INTERNAL_MBOX_STATUS mailbox_write(unsigned char val)
{
INTERNAL_MBOX_STATUS ret;
unsigned int full;
if (cdn_bus_read(MAILBOX_FULL_ADDR << 2, &full)) {
ret.tx_status = CDN_TX_APB_ERROR;
return ret;
}
if (full) {
ret.tx_status = CDN_TX_FULL;
return ret;
}
if (cdn_bus_write(MAILBOX0_WR_DATA << 2, val)) {
ret.tx_status = CDN_TX_APB_ERROR;
return ret;
}
ret.tx_status = CDN_TX_WRITE;
return ret;
}
INTERNAL_MBOX_STATUS mailbox_read(volatile unsigned char *val)
{
INTERNAL_MBOX_STATUS ret;
unsigned int empty;
unsigned int rd;
if (cdn_bus_read(MAILBOX_EMPTY_ADDR << 2, &empty)) {
ret.rx_status = CDN_RX_APB_ERROR;
return ret;
}
if (empty) {
ret.rx_status = CDN_RX_EMPTY;
return ret;
}
if (cdn_bus_read(MAILBOX0_RD_DATA << 2, &rd)) {
ret.rx_status = CDN_RX_APB_ERROR;
return ret;
}
*val = (unsigned char)rd;
ret.rx_status = CDN_RX_READ;
return ret;
}
INTERNAL_MBOX_STATUS internal_mbox_tx_process(void)
{
unsigned int txcount = 0;
unsigned int length =
(unsigned int)state.txbuffer[2] << 8 | (unsigned int)state.
txbuffer[3];
INTERNAL_MBOX_STATUS ret = {.txend = 0 };
ret.tx_status = CDN_TX_NOTHING;
INTERNAL_MBOX_STATUS tx_ret;
if (!state.txenable)
return ret;
while ((tx_ret.tx_status =
mailbox_write(state.txbuffer[state.txi]).tx_status) ==
CDN_TX_WRITE) {
txcount++;
if (++state.txi >= length + 4) {
state.txenable = 0;
state.txi = 0;
ret.txend = 1;
break;
}
}
if (txcount && tx_ret.tx_status == CDN_TX_FULL)
ret.tx_status = CDN_TX_WRITE;
else
ret.tx_status = tx_ret.tx_status;
return ret;
}
INTERNAL_MBOX_STATUS internal_mbox_rx_process(void)
{
unsigned int rxcount = 0;
INTERNAL_MBOX_STATUS ret = { 0, 0, 0, 0 };
INTERNAL_MBOX_STATUS rx_ret;
while ((rx_ret.rx_status =
mailbox_read(state.rxbuffer + state.rxi).rx_status) ==
CDN_RX_READ) {
rxcount++;
if (++state.rxi >= 4 +
((unsigned int)state.rxbuffer[2] << 8 |
(unsigned int)state.rxbuffer[3])) { /* end of message */
state.rxi = 0;
ret.rxend = 1;
state.rxenable = 0;
break;
}
}
ret.rx_status = rxcount ? CDN_RX_READ : CDN_RX_EMPTY;
return ret;
}
unsigned int internal_apb_available(void)
{
return !(state.rxenable || state.txenable);
}
void internal_mbox_tx_enable(unsigned char module, unsigned char opcode,
unsigned short length)
{
state.txbuffer[0] = opcode;
state.txbuffer[1] = module;
state.txbuffer[2] = (unsigned char)(length >> 8);
state.txbuffer[3] = (unsigned char)length;
state.txenable = 1;
}
CDN_API_STATUS internal_test_rx_head(unsigned char module, unsigned char opcode)
{
if (opcode != state.rxbuffer[0])
return CDN_BAD_OPCODE;
if (module != state.rxbuffer[1])
return CDN_BAD_MODULE;
return CDN_OK;
}
CDN_API_STATUS internal_test_rx_head_match(void)
{
return internal_test_rx_head(state.txbuffer[1], state.txbuffer[0]);
}
void print_fw_ver(void)
{
unsigned short ver, verlib;
cdn_api_general_getcurversion(&ver, &verlib);
printf("FIRMWARE VERSION: %d, LIB VERSION: %d\n", ver, verlib);
}
unsigned short internal_get_msg_len(void)
{
return ((unsigned short)state.rxbuffer[2] << 8) | (unsigned short)state.
rxbuffer[3];
}