Files
linux-nv-oot/drivers/net/can/mttcan/hal/m_ttcan_ram.c
Manish Bhardwaj 0e0d2f2c07 nvidia-oot: add support for mttcan driver
Using this patch we are adding support for
mttcan driver in oot kernel.

JIRA ESLC-6885

Signed-off-by: Manish Bhardwaj <mbhardwaj@nvidia.com>
Change-Id: I83a6d43aa99278a546778cf1700e2bd106ec42a9
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2785360
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
2022-10-03 21:31:05 -07:00

457 lines
13 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include "../include/m_ttcan.h"
int ttcan_read_txevt_ram(struct ttcan_controller *ttcan, u32 read_addr,
struct mttcan_tx_evt_element *txevt)
{
void __iomem *msg_addr = read_addr + ttcan->mram_vbase;
if (!txevt)
return -1;
txevt->f0 = readl(msg_addr);
txevt->f1 = readl(msg_addr + CAN_WORD_IN_BYTES);
return 0;
}
int ttcan_read_rx_msg_ram(struct ttcan_controller *ttcan, u64 read_addrs,
struct ttcanfd_frame *ttcanfd)
{
u32 i = 0, byte_index;
u32 msg_data;
void __iomem *addr_in_msg_ram = read_addrs + ttcan->mram_vbase;
int bytes_to_read = CANFD_MAX_DLEN;
if (!ttcanfd)
return -1;
ttcanfd->flags |= CAN_DIR_RX;
while (bytes_to_read) {
msg_data =
readl(addr_in_msg_ram + (i * CAN_WORD_IN_BYTES));
switch (i) {
case 0:
ttcanfd->can_id = 0;
ttcanfd->flags = 0;
if (msg_data & RX_BUF_XTD) {
/* Extended Frame */
ttcanfd->can_id = CAN_FMT |
((msg_data & RX_BUF_EXTID_MASK) &
CAN_EXT_ID_MASK);
} else {
ttcanfd->can_id =
((msg_data & RX_BUF_STDID_MASK) >>
RX_BUF_STDID_SHIFT) & CAN_STD_ID_MASK;
}
if (msg_data & RX_BUF_RTR)
ttcanfd->can_id |= CAN_RTR;
if (msg_data & RX_BUF_ESI)
ttcanfd->flags |= CAN_ESI_FLAG;
break;
case 1:
ttcanfd->d_len =
ttcan_dlc2len((msg_data & RX_BUF_DLC_MASK)
>> RX_BUF_DLC_SHIFT);
bytes_to_read = ttcanfd->d_len;
if (msg_data & RX_BUF_FDF)
ttcanfd->flags |= CAN_FD_FLAG;
if (msg_data & RX_BUF_BRS)
ttcanfd->flags |= CAN_BRS_FLAG;
ttcanfd->tstamp = msg_data & RX_BUF_RXTS_MASK;
break;
default:
byte_index = (i - 2) * CAN_WORD_IN_BYTES;
switch (bytes_to_read) {
default:
case 4:
ttcanfd->data[byte_index + 3] =
(msg_data >> 24) & 0xFF;
case 3:
ttcanfd->data[byte_index + 2] =
(msg_data >> 16) & 0xFF;
case 2:
ttcanfd->data[byte_index + 1] =
(msg_data >> 8) & 0xFF;
case 1:
ttcanfd->data[byte_index + 0] =
msg_data & 0xFF;
}
if (bytes_to_read >= 4)
bytes_to_read -= 4;
else
bytes_to_read = 0;
pr_debug("%s addr %p received 0x%x\n", __func__,
addr_in_msg_ram +
(i * CAN_WORD_IN_BYTES), msg_data);
break;
}
i++;
}
pr_debug("%s:received ID(0x%x) %s %s(%s)\n", __func__,
(ttcanfd->can_id & CAN_FMT) ?
(ttcanfd->can_id & CAN_EXT_ID_MASK) :
(ttcanfd->can_id & CAN_STD_ID_MASK),
(ttcanfd->can_id & CAN_FMT) ? "XTD" : "STD",
(ttcanfd->flags & CAN_FD_FLAG) ? "FD" : "NON-FD",
(ttcanfd->flags & CAN_BRS_FLAG) ? "BRS" : "NOBRS");
return i;
}
int ttcan_write_tx_msg_ram(struct ttcan_controller *ttcan, u32 write_addrs,
struct ttcanfd_frame *ttcanfd, u8 index)
{
u32 msg_data, idx;
int bytes_to_write;
void __iomem *addr_in_msg_ram = write_addrs + ttcan->mram_vbase;
/* T0 */
if (ttcanfd->can_id & CAN_FMT)
msg_data = (ttcanfd->can_id & CAN_EXT_ID_MASK) | TX_BUF_XTD;
else
msg_data =
(ttcanfd->can_id & CAN_STD_ID_MASK) << TX_BUF_STDID_SHIFT;
if (ttcanfd->can_id & CAN_RTR)
msg_data |= TX_BUF_RTR;
/* This flag is ORed with error passive flag while sending */
if (ttcanfd->flags & CAN_ESI_FLAG)
msg_data |= TX_BUF_ESI;
pr_debug("T0: addr %p msg %x\n", addr_in_msg_ram, msg_data);
writel(msg_data, addr_in_msg_ram);
/* T1 */
msg_data =
(ttcan_len2dlc(ttcanfd->d_len) << TX_BUF_DLC_SHIFT) &
TX_BUF_DLC_MASK;
if (ttcan->tx_config.evt_q_num)
msg_data |= TX_BUF_EFC;
if (ttcanfd->flags & CAN_FD_FLAG)
msg_data |= TX_BUF_FDF;
if (ttcanfd->flags & CAN_BRS_FLAG)
msg_data |= TX_BUF_BRS;
msg_data |= index << TX_BUF_MM_SHIFT;
pr_debug("%s:buf_id(%d):- %s(%s)\n", __func__, index,
(ttcanfd->flags & CAN_FD_FLAG) ? "FD" : "NON-FD",
(ttcanfd->flags & CAN_BRS_FLAG) ? "BRS" : "NOBRS");
pr_debug("T1: addr %p msg %x\n", (addr_in_msg_ram+CAN_WORD_IN_BYTES),
msg_data);
writel(msg_data, (addr_in_msg_ram + CAN_WORD_IN_BYTES));
bytes_to_write = ttcanfd->d_len;
idx = 0;
while (bytes_to_write > 0) {
msg_data = 0;
switch (bytes_to_write) {
default:
case 4:
msg_data = ttcanfd->data[idx + 3] << 24;
case 3:
msg_data += ttcanfd->data[idx + 2] << 16;
case 2:
msg_data += ttcanfd->data[idx + 1] << 8;
case 1:
msg_data += ttcanfd->data[idx + 0] << 0;
}
pr_debug("T2: addr %p msg %x\n", (addr_in_msg_ram +
(((idx >> 2) + 2) * CAN_WORD_IN_BYTES)),
msg_data);
writel(msg_data, (addr_in_msg_ram +
(((idx >> 2) + 2) * CAN_WORD_IN_BYTES)));
idx += 4;
bytes_to_write -= 4;
}
return idx;
}
void ttcan_set_std_id_filter(struct ttcan_controller *ttcan, void *std_shadow,
int filter_index, u8 sft, u8 sfec, u32 sfid1,
u32 sfid2)
{
u32 filter_elem = 0;
void __iomem *filter_addr =
ttcan->mram_vbase + ttcan->mram_cfg[MRAM_SIDF].off;
u32 filter_offset =
(filter_index * SIDF_ELEM_SIZE);
filter_elem = (sfid2 << MTT_STD_FLTR_SFID2_SHIFT) &
MTT_STD_FLTR_SFID2_MASK;
filter_elem |= (sfid1 << MTT_STD_FLTR_SFID1_SHIFT) &
MTT_STD_FLTR_SFID1_MASK;
filter_elem |= (sfec << MTT_STD_FLTR_SFEC_SHIFT) &
MTT_STD_FLTR_SFEC_MASK;
filter_elem |= (sft << MTT_STD_FLTR_SFT_SHIFT) & MTT_STD_FLTR_SFT_MASK;
pr_debug("%s %p\n", __func__, (filter_addr + filter_offset));
memcpy((char *)std_shadow + filter_offset, &filter_elem,
SIDF_ELEM_SIZE);
writel(filter_elem, (void __iomem *)(filter_addr + filter_offset));
}
void ttcan_prog_std_id_fltrs(struct ttcan_controller *ttcan, void *std_shadow)
{
int idx;
u32 list_size = ttcan->mram_cfg[MRAM_SIDF].num;
void __iomem *filter_addr = ttcan->mram_vbase +
ttcan->mram_cfg[MRAM_SIDF].off;
for (idx = 0; idx < list_size; idx++) {
u32 offset = idx * SIDF_ELEM_SIZE;
writel(*(u32 *)((u8 *)std_shadow + offset),
(void __iomem *)(filter_addr + offset));
}
}
u32 ttcan_get_std_id_filter(struct ttcan_controller *ttcan, int idx)
{
void __iomem *filter_addr = ttcan->mram_vbase +
ttcan->mram_cfg[MRAM_SIDF].off;
u32 filter_offset = idx * SIDF_ELEM_SIZE;
return readl(filter_addr + filter_offset);
}
void ttcan_prog_xtd_id_fltrs(struct ttcan_controller *ttcan, void *xtd_shadow)
{
int idx;
u32 list_size = ttcan->mram_cfg[MRAM_XIDF].num;
void __iomem *filter_addr = ttcan->mram_vbase +
ttcan->mram_cfg[MRAM_XIDF].off;
for (idx = 0; idx < list_size; idx++) {
u32 offset = idx * XIDF_ELEM_SIZE;
writel(*(u32 *)((u8 *)xtd_shadow + offset),
(void __iomem *)(filter_addr + offset));
writel(*(u32 *)((u8 *)xtd_shadow + offset + CAN_WORD_IN_BYTES),
(void __iomem *)(filter_addr + offset +
CAN_WORD_IN_BYTES));
}
}
void ttcan_set_xtd_id_filter(struct ttcan_controller *ttcan, void *xtd_shadow,
int filter_index, u8 eft, u8 efec, u32 efid1,
u32 efid2)
{
struct mttcan_xtd_id_filt_element xfilter_elem;
void __iomem *filter_addr =
ttcan->mram_vbase + ttcan->mram_cfg[MRAM_XIDF].off;
u32 filter_offset = filter_index * XIDF_ELEM_SIZE;
xfilter_elem.f0 = (efec << MTT_XTD_FLTR_F0_EFEC_SHIFT) &
MTT_XTD_FLTR_F0_EFEC_MASK;
xfilter_elem.f0 |= (efid1 << MTT_XTD_FLTR_F0_EFID1_SHIFT) &
MTT_XTD_FLTR_F0_EFID1_MASK;
xfilter_elem.f1 = (eft << MTT_XTD_FLTR_F1_EFT_SHIFT) &
MTT_XTD_FLTR_F1_EFT_MASK;
xfilter_elem.f1 |= (efid2 << MTT_XTD_FLTR_F1_EFID2_SHIFT) &
MTT_XTD_FLTR_F1_EFID2_MASK;
memcpy((char *)xtd_shadow + filter_offset, &xfilter_elem,
XIDF_ELEM_SIZE);
writel(xfilter_elem.f0,
(void __iomem *)(filter_addr + filter_offset));
writel(xfilter_elem.f1,
(void __iomem *)(filter_addr + filter_offset +
CAN_WORD_IN_BYTES));
pr_debug("%s %x %p\n", __func__, xfilter_elem.f0,
(filter_addr + filter_offset));
pr_debug("%s %x %p\n", __func__, xfilter_elem.f1,
(filter_addr + filter_offset + CAN_WORD_IN_BYTES));
}
u64 ttcan_get_xtd_id_filter(struct ttcan_controller *ttcan, int idx)
{
u64 xtd;
void __iomem *filter_addr = ttcan->mram_vbase +
ttcan->mram_cfg[MRAM_XIDF].off;
u32 offset = idx * XIDF_ELEM_SIZE;
xtd = ((u64) readl(filter_addr + offset + CAN_WORD_IN_BYTES)) << 32;
xtd |= readl(filter_addr + offset);
return xtd;
}
u64 ttcan_get_trigger_mem(struct ttcan_controller *ttcan, int idx)
{
u64 trig;
void __iomem *addr = ttcan->mram_vbase + ttcan->mram_cfg[MRAM_TMC].off;
u32 offset = idx * TRIG_ELEM_SIZE;
trig = ((u64) readl(addr + offset + CAN_WORD_IN_BYTES)) << 32;
trig |= readl(addr + offset);
return trig;
}
void ttcan_prog_trigger_mem(struct ttcan_controller *ttcan, void *tmc_shadow)
{
int idx;
void __iomem *filter_addr = ttcan->mram_vbase +
ttcan->mram_cfg[MRAM_TMC].off;
u32 list_size = ttcan->mram_cfg[MRAM_TMC].num;
for (idx = 0; idx < list_size; idx++) {
u32 offset = idx * TRIG_ELEM_SIZE;
writel(*(u32 *)((char *)tmc_shadow + idx),
(void __iomem *)(filter_addr + offset));
writel(*(u32 *)((char *)tmc_shadow + idx),
(void __iomem *)(filter_addr + offset +
CAN_WORD_IN_BYTES));
}
}
int ttcan_set_trigger_mem(struct ttcan_controller *ttcan, void *tmc_shadow,
int trig_index, u16 time_mark, u16 cycle_code,
u8 tmin, u8 tmex, u16 trig_type, u8 filter_type,
u8 mesg_num)
{
struct mttcan_trig_mem_element trig_elem;
void __iomem *trig_mem_addr = ttcan->mram_vbase +
ttcan->mram_cfg[MRAM_TMC].off;
u32 idx = trig_index * TRIG_ELEM_SIZE;
if (trig_index > 63) {
pr_err("%s: Incorrect Index\n", __func__);
return -1;
}
if (cycle_code > 127) {
pr_err("%s: Invalid cycle code\n", __func__);
return -1;
}
/* TBD: ASC is disabled - Hardcoded */
/* Mesg. Status Count is set 0 */
trig_elem.f0 = (time_mark << MTT_TRIG_ELE_F0_TM_SHIFT) &
MTT_TRIG_ELE_F0_TM_MASK;
trig_elem.f0 |= cycle_code << MTT_TRIG_ELE_F0_CC_SHIFT &
MTT_TRIG_ELE_F0_CC_MASK;
/* ASC = 0 */;
trig_elem.f0 |= (tmin << MTT_TRIG_ELE_F0_TMIN_SHIFT) &
MTT_TRIG_ELE_F0_TMIN_MASK;
trig_elem.f0 |= (tmex << MTT_TRIG_ELE_F0_TMEX_SHIFT) &
MTT_TRIG_ELE_F0_TMEX_MASK;
trig_elem.f0 |= (trig_type << MTT_TRIG_ELE_F0_TYPE_SHIFT) &
MTT_TRIG_ELE_F0_TYPE_MASK;
trig_elem.f1 = (filter_type << MTT_TRIG_ELE_F1_FTYPE_SHIFT) &
MTT_TRIG_ELE_F1_FTYPE_MASK;
trig_elem.f1 |= (mesg_num << MTT_TRIG_ELE_F1_MNR_SHIFT) &
MTT_TRIG_ELE_F1_MNR_MASK;
memcpy((char *)tmc_shadow + idx, &trig_elem, TRIG_ELEM_SIZE);
writel(trig_elem.f0, (void __iomem *)(trig_mem_addr + idx));
writel(trig_elem.f1, (void __iomem *)(trig_mem_addr + idx +
CAN_WORD_IN_BYTES));
return 0;
}
int ttcan_mesg_ram_config(struct ttcan_controller *ttcan,
u32 *arr, u32 *tx_conf, u32 *rx_conf)
{
ttcan->mram_cfg[MRAM_SIDF].off = arr[0];
ttcan->mram_cfg[MRAM_SIDF].num = arr[1];
ttcan->mram_cfg[MRAM_XIDF].off = ttcan->mram_cfg[MRAM_SIDF].off +
ttcan->mram_cfg[MRAM_SIDF].num * SIDF_ELEM_SIZE;
ttcan->mram_cfg[MRAM_XIDF].num = arr[2];
ttcan->mram_cfg[MRAM_RXF0].off = ttcan->mram_cfg[MRAM_XIDF].off +
ttcan->mram_cfg[MRAM_XIDF].num * XIDF_ELEM_SIZE;
ttcan->mram_cfg[MRAM_RXF0].num = arr[3];
ttcan->mram_cfg[MRAM_RXF1].off = ttcan->mram_cfg[MRAM_RXF0].off +
ttcan->mram_cfg[MRAM_RXF0].num * MAX_RXB_ELEM_SIZE;
ttcan->mram_cfg[MRAM_RXF1].num = arr[4];
ttcan->mram_cfg[MRAM_RXB].off = ttcan->mram_cfg[MRAM_RXF1].off +
ttcan->mram_cfg[MRAM_RXF1].num * MAX_RXB_ELEM_SIZE;
ttcan->mram_cfg[MRAM_RXB].num = arr[5];
ttcan->mram_cfg[MRAM_TXE].off = ttcan->mram_cfg[MRAM_RXB].off +
ttcan->mram_cfg[MRAM_RXB].num * MAX_RXB_ELEM_SIZE;
ttcan->mram_cfg[MRAM_TXE].num = arr[6];
ttcan->mram_cfg[MRAM_TXB].off = ttcan->mram_cfg[MRAM_TXE].off +
ttcan->mram_cfg[MRAM_TXE].num * TX_EVENT_FIFO_ELEM_SIZE;
ttcan->mram_cfg[MRAM_TXB].num = arr[7];
ttcan->mram_cfg[MRAM_TMC].off = ttcan->mram_cfg[MRAM_TXB].off +
ttcan->mram_cfg[MRAM_TXB].num * MAX_TXB_ELEM_SIZE;
ttcan->mram_cfg[MRAM_TMC].num = arr[8];
if ((ttcan->mram_size <=
ttcan->mram_cfg[MRAM_TMC].off + ttcan->mram_cfg[MRAM_TMC].num *
TRIG_ELEM_SIZE - ttcan->mram_cfg[MRAM_SIDF].off)) {
pr_err("%s: Incorrect config for Message RAM\n", __func__);
return -EINVAL;
}
if ((tx_conf[0] + tx_conf[1] > ttcan->mram_cfg[MRAM_TXB].num)) {
pr_err("%s: Incorrect tx-config in dt.\n", __func__);
return -EINVAL;
}
if ((tx_conf[0] != 0) && (tx_conf[1] != 0)) {
pr_err("%s: Incorrect tx-config in dt.\n", __func__);
pr_err("Using both Tx buf and Fifo not allowed (Errata 21)\n");
return -EINVAL;
}
ttcan->tx_config.ded_buff_num = tx_conf[TX_CONF_TXB];
ttcan->tx_config.fifo_q_num = tx_conf[TX_CONF_TXQ];
ttcan->tx_config.flags = tx_conf[TX_CONF_QMODE];
ttcan->e_size.tx_buffer = TXB_ELEM_HEADER_SIZE + tx_conf[TX_CONF_BSIZE];
ttcan->tx_config.dfs = get_dfs(tx_conf[TX_CONF_BSIZE]);
ttcan->rx_config.rxb_dsize = rx_conf[RX_CONF_RXB];
ttcan->rx_config.rxq0_dsize = rx_conf[RX_CONF_RXF0];
ttcan->rx_config.rxq1_dsize = rx_conf[RX_CONF_RXF1];
pr_info("\t Message RAM Configuration\n"
"\t| base addr |0x%08lx|\n\t| sidfc_flssa |0x%08x|\n\t| xidfc_flesa |0x%08x|\n"
"\t| rxf0c_f0sa |0x%08x|\n\t| rxf1c_f1sa |0x%08x|\n\t| rxbc_rbsa |0x%08x|\n"
"\t| txefc_efsa |0x%08x|\n\t| txbc_tbsa |0x%08x|\n\t| tmc_tmsa |0x%08x|\n"
"\t| mram size |0x%08x|\n",
ttcan->mram_base, ttcan->mram_cfg[MRAM_SIDF].off,
ttcan->mram_cfg[MRAM_XIDF].off, ttcan->mram_cfg[MRAM_RXF0].off,
ttcan->mram_cfg[MRAM_RXF1].off, ttcan->mram_cfg[MRAM_RXB].off,
ttcan->mram_cfg[MRAM_TXE].off, ttcan->mram_cfg[MRAM_TXB].off,
ttcan->mram_cfg[MRAM_TMC].off, ttcan->mram_size);
return 0;
}
void ttcan_mesg_ram_init(struct ttcan_controller *ttcan)
{
u32 offset;
for (offset = 0; offset < ttcan->mram_size;
offset += CAN_WORD_IN_BYTES) {
writel(0, ttcan->mram_vbase + offset);
}
}