tegrakernel/kernel/nvidia/drivers/net/can/mttcan/hal/m_ttcan.c

1045 lines
27 KiB
C
Raw Permalink Normal View History

2022-02-16 09:13:02 -06:00
/*
* Copyright (c) 2015-2020, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
*/
/**********************************************/
/********TTCAN Configurations functions *******/
/**********************************************/
#include "m_ttcan.h"
#include <asm/io.h>
#include <linux/delay.h>
#define MTTCAN_INIT_TIMEOUT 1000
void ttcan_print_version(struct ttcan_controller *ttcan)
{
u32 crel, endn;
crel = ttcan_read32(ttcan, ADR_MTTCAN_CREL);
endn = ttcan_read32(ttcan, ADR_MTTCAN_ENDN);
pr_info("Release %d.%d.%d from %2.2x.%2.2x.201%1.1x\n",
(crel & MTT_CREL_REL_MASK) >> MTT_CREL_REL_SHIFT,
(crel & MTT_CREL_STEP_MASK) >> MTT_CREL_STEP_SHIFT,
(crel & MTT_CREL_SUBS_MASK) >> MTT_CREL_SUBS_SHIFT,
(crel & MTT_CREL_DAY_MASK) >> MTT_CREL_DAY_SHIFT,
(crel & MTT_CREL_MON_MASK) >> MTT_CREL_MON_SHIFT,
(crel & MTT_CREL_YEAR_MASK) >> MTT_CREL_YEAR_SHIFT);
pr_debug("CAN register access %s Endian Reg 0x%x\n",
(endn == 0x87654321) ? "PASS" : "FAIL", endn);
}
int ttcan_write32_check(struct ttcan_controller *ttcan,
int reg, u32 val, u32 mask)
{
u32 ret_val;
ttcan_write32(ttcan, reg, val);
ret_val = ttcan_read32(ttcan, reg);
if ((ret_val & mask) == (val & mask))
return 0;
else
pr_err("%s:addr: 0x%x write 0x%x read 0x%x mask 0x%x\n",
__func__, reg, val, ret_val, mask);
return -EIO;
}
inline void ttcan_set_ok(struct ttcan_controller *ttcan)
{
u32 val;
val = ttcan_xread32(ttcan, ADDR_M_TTCAN_CNTRL_REG);
val |= M_TTCAN_CNTRL_REG_COK;
ttcan_xwrite32(ttcan, ADDR_M_TTCAN_CNTRL_REG, val);
}
int ttcan_set_init(struct ttcan_controller *ttcan)
{
u32 cccr_reg;
int timeout = MTTCAN_INIT_TIMEOUT;
cccr_reg = ttcan_read32(ttcan, ADR_MTTCAN_CCCR);
if ((cccr_reg & MTT_CCCR_INIT_MASK) == 0) {
/* Controller not yet initialized */
cccr_reg |= 1;
ttcan_write32(ttcan, ADR_MTTCAN_CCCR, cccr_reg);
do {
cccr_reg = ttcan_read32(ttcan, ADR_MTTCAN_CCCR);
udelay(1);
timeout--;
} while ((cccr_reg & MTT_CCCR_INIT_MASK) == 0 && timeout);
if (!timeout) {
pr_err("Controller %s Timeout\n", __func__);
return -ETIMEDOUT;
}
}
return 0;
}
void ttcan_bus_off_seq(struct ttcan_controller *ttcan)
{
/* We need to wait for 129 bus idle sequence (129*11 bits)
* according to CAN SPEC. Considering minimal bitrate (125 kbps),
* we need to wait for maximum of 12 msec
*/
mdelay(12);
}
int ttcan_reset_init(struct ttcan_controller *ttcan)
{
u32 cccr_reg;
int timeout = MTTCAN_INIT_TIMEOUT;
cccr_reg = ttcan_read32(ttcan, ADR_MTTCAN_CCCR);
if (cccr_reg & MTT_CCCR_INIT_MASK) {
/* Controller was initialized */
cccr_reg &= ~1;
ttcan_write32(ttcan, ADR_MTTCAN_CCCR, cccr_reg);
do {
cccr_reg = ttcan_read32(ttcan, ADR_MTTCAN_CCCR);
udelay(1);
timeout--;
} while ((cccr_reg & MTT_CCCR_INIT_MASK) && timeout);
if (!timeout) {
pr_err("Controller %s Timeout\n", __func__);
return -ETIMEDOUT;
}
}
return 0;
}
int ttcan_set_config_change_enable(struct ttcan_controller *ttcan)
{
u32 cccr_reg;
int timeout = MTTCAN_INIT_TIMEOUT;
/* initialize the core */
if (ttcan_set_init(ttcan))
return -ETIMEDOUT;
/* set configuration change enable bit */
cccr_reg = ttcan_read32(ttcan, ADR_MTTCAN_CCCR);
cccr_reg |= MTT_CCCR_CCE_MASK;
ttcan_write32(ttcan, ADR_MTTCAN_CCCR, cccr_reg);
do {
cccr_reg = ttcan_read32(ttcan, ADR_MTTCAN_CCCR);
udelay(1);
timeout--;
} while (((cccr_reg & MTT_CCCR_CCE_MASK) == 0) && timeout);
if (!timeout) {
pr_err("Controller %s Timeout\n", __func__);
return -ETIMEDOUT;
}
return 0;
}
int ttcan_set_power(struct ttcan_controller *ttcan, int value)
{
u32 cccr_reg;
int timeout = MTTCAN_INIT_TIMEOUT;
cccr_reg = ttcan_read32(ttcan, ADR_MTTCAN_CCCR);
cccr_reg &= ~(MTT_CCCR_CSR_MASK);
cccr_reg |= ((~value) << MTT_CCCR_CSR_SHIFT) & MTT_CCCR_CSR_MASK;
ttcan_write32(ttcan, ADR_MTTCAN_CCCR, cccr_reg);
do {
cccr_reg = ttcan_read32(ttcan, ADR_MTTCAN_CCCR);
udelay(1);
timeout--;
} while (((cccr_reg & MTT_CCCR_CSA_MASK) >> MTT_CCCR_CSA_SHIFT)
== value && timeout);
if (!timeout) {
pr_err("Controller %s Timeout\n", __func__);
return -ETIMEDOUT;
}
return 0;
}
void ttcan_reset_config_change_enable(struct ttcan_controller *ttcan)
{
/* reset the core */
if (ttcan_reset_init(ttcan))
return;
/*CCCR.CCE is automatically reset when CCCR.INIT is reset */
}
void ttcan_disable_auto_retransmission(struct ttcan_controller *ttcan,
bool enable)
{
u32 cccr_reg;
/* set DAR bit */
cccr_reg = ttcan_read32(ttcan, ADR_MTTCAN_CCCR);
if (enable)
cccr_reg |= MTT_CCCR_DAR_MASK;
else
cccr_reg &= ~MTT_CCCR_DAR_MASK;
ttcan_write32_check(ttcan, ADR_MTTCAN_CCCR, cccr_reg, MTTCAN_CCCR_MSK);
}
int ttcan_set_loopback(struct ttcan_controller *ttcan)
{
u32 test_reg;
u32 cccr_reg;
int timeout = MTTCAN_INIT_TIMEOUT;
/* set TEST.LBCK (external loopback) bit */
cccr_reg = ttcan_read32(ttcan, ADR_MTTCAN_CCCR);
test_reg = ttcan_read32(ttcan, ADR_MTTCAN_TEST);
if (ttcan_protected(cccr_reg))
return -EPERM;
cccr_reg |= MTT_CCCR_TEST_MASK;
test_reg |= MTT_TEST_LBCK_MASK;
ttcan_write32(ttcan, ADR_MTTCAN_CCCR, cccr_reg);
do {
cccr_reg = ttcan_read32(ttcan, ADR_MTTCAN_CCCR);
udelay(1);
timeout--;
} while ((cccr_reg & MTT_CCCR_TEST_MASK) == 0 && timeout);
if (!timeout) {
pr_err("%s: Timeout cccr = 0x%x\n", __func__, cccr_reg);
return -ETIMEDOUT;
}
return ttcan_write32_check(ttcan, ADR_MTTCAN_TEST,
test_reg, MTTCAN_TEST_MSK);
}
int ttcan_set_bus_monitoring_mode(struct ttcan_controller *ttcan, bool enable)
{
u32 cccr_reg;
/* set MON bit(bus monitor mode */
cccr_reg = ttcan_read32(ttcan, ADR_MTTCAN_CCCR);
if (ttcan_protected(cccr_reg))
return -EPERM;
if (enable)
cccr_reg |= MTT_CCCR_MON_MASK;
else
cccr_reg &= ~MTT_CCCR_MON_MASK;
return ttcan_write32_check(ttcan, ADR_MTTCAN_CCCR,
cccr_reg, MTTCAN_CCCR_MSK);
}
int ttcan_set_normal_mode(struct ttcan_controller *ttcan)
{
u32 cccr_reg;
u32 test_reg;
int timeout = MTTCAN_INIT_TIMEOUT;
/* Clear loopback and monitor mode */
cccr_reg = ttcan_read32(ttcan, ADR_MTTCAN_CCCR);
test_reg = ttcan_read32(ttcan, ADR_MTTCAN_TEST);
if (ttcan_protected(cccr_reg))
return -EPERM;
if (test_reg & MTT_TEST_LBCK_MASK) {
test_reg &= ~(MTT_TEST_LBCK_MASK);
if ((cccr_reg & MTT_CCCR_TEST_MASK) == 0) {
cccr_reg |= MTT_CCCR_TEST_MASK;
ttcan_write32(ttcan, ADR_MTTCAN_CCCR, cccr_reg);
do {
cccr_reg = ttcan_read32(ttcan, ADR_MTTCAN_CCCR);
udelay(1);
timeout--;
} while ((cccr_reg & MTT_CCCR_TEST_MASK) == 0
&& timeout);
if (!timeout) {
pr_err("%s: Timeout cccr = 0x%x\n", __func__,
cccr_reg);
return -ETIMEDOUT;
}
}
ttcan_write32_check(ttcan, ADR_MTTCAN_TEST, test_reg,
MTTCAN_TEST_MSK);
}
cccr_reg &= ~(MTT_CCCR_MON_MASK);
cccr_reg &= ~(MTT_CCCR_TEST_MASK);
return ttcan_write32_check(ttcan, ADR_MTTCAN_CCCR, cccr_reg,
MTTCAN_CCCR_MSK);
}
inline u32 ttcan_read_ecr(struct ttcan_controller *ttcan)
{
return ttcan_read32(ttcan, ADR_MTTCAN_ECR);
}
int ttcan_set_bitrate(struct ttcan_controller *ttcan)
{
unsigned int temp_reg;
int ret = 0;
u32 cccr_reg;
u32 nbtp_reg;
u32 dbtp_reg;
u32 tdcr_reg;
nbtp_reg = ((ttcan->bt_config.nominal.phase_seg2 - 1) <<
MTT_NBTP_NTSEG2_SHIFT) & MTT_NBTP_NTSEG2_MASK;
nbtp_reg |= ((ttcan->bt_config.nominal.phase_seg1 +
ttcan->bt_config.nominal.prop_seg - 1)
<< MTT_NBTP_NTSEG1_SHIFT) & MTT_NBTP_NTSEG1_MASK;
nbtp_reg |= (ttcan->bt_config.nominal.sjw - 1) <<
MTT_NBTP_NSJW_SHIFT & MTT_NBTP_NSJW_MASK;
nbtp_reg |= (ttcan->bt_config.nominal.brp - 1) <<
MTT_NBTP_NBRP_SHIFT & MTT_NBTP_NBRP_MASK;
pr_debug("%s NBTP(0x%x) value (0x%x)\n", __func__, ADR_MTTCAN_NBTP,
nbtp_reg);
ret = ttcan_write32_check(ttcan, ADR_MTTCAN_NBTP, nbtp_reg,
MTTCAN_NBTP_MSK);
if (ret) {
pr_err("%s: Normal bitrate configuration failed\n", __func__);
return ret;
}
if (ttcan->bt_config.fd_flags & CAN_FD_FLAG) {
ttcan->bt_config.data.tdc = ttcan->tdc;
dbtp_reg = ((ttcan->bt_config.data.phase_seg2 - 1) <<
MTT_DBTP_DTSEG2_SHIFT) & MTT_DBTP_DTSEG2_MASK;
dbtp_reg |= ((ttcan->bt_config.data.phase_seg1 +
ttcan->bt_config.data.prop_seg - 1) <<
MTT_DBTP_DTSEG1_SHIFT) & MTT_DBTP_DTSEG1_MASK;
dbtp_reg |= ((ttcan->bt_config.data.sjw - 1) <<
MTT_DBTP_DSJW_SHIFT) & MTT_DBTP_DSJW_MASK;
dbtp_reg |= ((ttcan->bt_config.data.brp - 1) <<
MTT_DBTP_DBRP_SHIFT) & MTT_DBTP_DBRP_MASK;
dbtp_reg |= (ttcan->bt_config.data.tdc << MTT_DBTP_TDC_SHIFT) &
MTT_DBTP_TDC_MASK;
tdcr_reg = (ttcan->bt_config.data.tdc_offset <<
MTT_TDCR_TDCO_SHIFT) & MTT_TDCR_TDCO_MASK;
tdcr_reg |= ttcan->tdc_offset;
pr_debug("%s DBTP(0x%x) value (0x%x)\n", __func__,
ADR_MTTCAN_DBTP, dbtp_reg);
ret = ttcan_write32_check(ttcan, ADR_MTTCAN_DBTP,
dbtp_reg, MTTCAN_DBTP_MSK);
if (ret) {
pr_err("%s: Fast bitrate configuration failed\n",
__func__);
return ret;
}
ret = ttcan_write32_check(ttcan, ADR_MTTCAN_TDCR,
tdcr_reg, MTTCAN_TDCR_MSK);
if (ret) {
pr_err("%s: Fast bitrate configuration failed\n",
__func__);
return ret;
}
temp_reg = cccr_reg = ttcan_read32(ttcan, ADR_MTTCAN_CCCR);
if (ttcan->bt_config.fd_flags & CAN_FD_FLAG)
cccr_reg |= MTT_CCCR_FDOE_MASK;
else
cccr_reg &= ~(MTT_CCCR_FDOE_MASK);
if (ttcan->bt_config.fd_flags & CAN_BRS_FLAG)
cccr_reg |= MTT_CCCR_BRSE_MASK;
else
cccr_reg &= ~(MTT_CCCR_BRSE_MASK);
if (ttcan->bt_config.fd_flags & CAN_FD_NON_ISO_FLAG)
cccr_reg |= MTT_CCCR_NISO_MASK;
else
cccr_reg &= ~(MTT_CCCR_NISO_MASK);
if (temp_reg != cccr_reg) {
ret = ttcan_write32_check(ttcan, ADR_MTTCAN_CCCR,
cccr_reg, MTTCAN_CCCR_MSK);
if (ret) {
pr_err("%s: Error in enabling FD\n", __func__);
return ret;
}
}
}
return ret;
}
int ttcan_tx_req_pending(struct ttcan_controller *ttcan)
{
u32 txbrp_reg = ttcan_read32(ttcan, ADR_MTTCAN_TXBRP);
if (txbrp_reg)
return 1;
return 0;
}
int ttcan_tx_buff_req_pending(struct ttcan_controller *ttcan, u8 index)
{
u32 txbrp_reg;
u32 mask = 1 << index;
txbrp_reg = ttcan_read32(ttcan, ADR_MTTCAN_TXBRP);
if (txbrp_reg & mask)
return 1;
else
return 0;
}
bool ttcan_tx_buffers_full(struct ttcan_controller *ttcan)
{
u32 txbrp_reg;
u32 txfqs_full = 1;
u32 mask = (1 << ttcan->tx_config.ded_buff_num) - 1;
/* If FIFO/queue is enabled, check if full bit is set */
if (ttcan->tx_config.fifo_q_num)
txfqs_full = (ttcan_read32(ttcan, ADR_MTTCAN_TXFQS) &
MTT_TXFQS_TFQF_MASK) >> MTT_TXFQS_TFQF_SHIFT;
/* Check for pending Tx requests in msg buffer */
txbrp_reg = ttcan_read32(ttcan, ADR_MTTCAN_TXBRP) & mask;
if ((txbrp_reg == mask) && txfqs_full)
return true;
else
return false;
}
void ttcan_tx_ded_msg_write(struct ttcan_controller *ttcan,
struct ttcanfd_frame *ttcanfd,
u8 index)
{
u32 ram_addr = ttcan->mram_cfg[MRAM_TXB].off +
(index * ttcan->e_size.tx_buffer);
ttcan_write_tx_msg_ram(ttcan, ram_addr, ttcanfd, index);
ttcan->tx_buf_dlc[index] = ttcanfd->d_len;
}
void ttcan_tx_trigger_msg_transmit(struct ttcan_controller *ttcan, u8 index)
{
ttcan_write32(ttcan, ADR_MTTCAN_TXBAR, (1 << index));
}
int ttcan_tx_msg_buffer_write(struct ttcan_controller *ttcan,
struct ttcanfd_frame *ttcanfd)
{
int msg_no;
u32 txbrp_free = ~ttcan_read32(ttcan, ADR_MTTCAN_TXBRP);
/* mask out buffers that are previously reserved by SW */
txbrp_free &= ~ttcan->tx_object;
/* mask for buffers reserved for Tx message buffers */
txbrp_free &= (1 << ttcan->tx_config.ded_buff_num) - 1;
msg_no = ffs(txbrp_free) - 1;
if (msg_no < 0)
return -ENOMEM;
/* Write to CAN controller message RAM */
ttcan_tx_ded_msg_write(ttcan, ttcanfd, msg_no);
return msg_no;
}
int ttcan_set_tx_buffer_addr(struct ttcan_controller *ttcan)
{
int ret = 0;
u32 txbc_reg;
u32 txesc_reg;
u32 tx_intr_en;
u32 rel_start_addr = ttcan->mram_cfg[MRAM_TXB].off >> 2;
enum ttcan_data_field_size dfs = ttcan->tx_config.dfs;
txbc_reg = (rel_start_addr << MTT_TXBC_TBSA_SHIFT) & MTT_TXBC_TBSA_MASK;
txbc_reg |= (ttcan->tx_config.ded_buff_num << MTT_TXBC_NDTB_SHIFT) &
MTT_TXBC_NDTB_MASK;
txbc_reg |= (ttcan->tx_config.fifo_q_num << MTT_TXBC_TFQS_SHIFT) &
MTT_TXBC_TFQS_MASK;
if (ttcan->tx_config.flags & 0x1)
txbc_reg |= MTT_TXBC_TFQM_MASK; /* Queue mode */
else
txbc_reg &= ~(MTT_TXBC_TFQM_MASK); /* FIFO mode */
ret = ttcan_write32_check(ttcan, ADR_MTTCAN_TXBC, txbc_reg,
MTTCAN_TXBC_MSK);
if (ret) {
pr_err("%s: Error in setting ADR_MTTCAN_TXBC\n", __func__);
return ret;
}
txesc_reg = (dfs << MTT_TXESC_TBDS_SHIFT) & MTT_TXESC_TBDS_MASK;
ret = ttcan_write32_check(ttcan, ADR_MTTCAN_TXESC, txesc_reg,
MTTCAN_TXESC_MSK);
if (ret) {
pr_err("%s: Error in setting ADR_MTTCAN_TXESC\n", __func__);
return ret;
}
tx_intr_en = (1 << (ttcan->tx_config.ded_buff_num
+ ttcan->tx_config.fifo_q_num)) - 1;
/* Enable TC interrupt for tx buffers + queue */
ttcan_write32(ttcan, ADR_MTTCAN_TXBTIE, tx_intr_en);
/* Enable TCF interrupt for tx buffers */
ttcan_write32(ttcan, ADR_MTTCAN_TXBCIE, tx_intr_en);
return ret;
}
/* Queue Message in Tx Queue
* Return
* -ve in case of error
* idx written buffer index
*/
int ttcan_tx_fifo_queue_msg(struct ttcan_controller *ttcan,
struct ttcanfd_frame *ttcanfd)
{
u32 txfqs_reg;
u32 put_idx;
txfqs_reg = ttcan_read32(ttcan, ADR_MTTCAN_TXFQS);
/* Test for Tx FIFO/Queue full */
if (txfqs_reg & MTT_TXFQS_TFQF_MASK)
return -ENOMEM;
/* Test if Tx index is previously reserved in SW */
put_idx = (txfqs_reg & MTT_TXFQS_TFQPI_MASK) >> MTT_TXFQS_TFQPI_SHIFT;
if (ttcan->tx_object & (1 << put_idx))
return -ENOMEM;
/* Write to CAN controller message RAM */
ttcan_tx_ded_msg_write(ttcan, ttcanfd, put_idx);
return put_idx;
}
/* Check tx fifo status
* return 1 if fifo full
*/
int ttcan_tx_fifo_full(struct ttcan_controller *ttcan)
{
u32 txfqs_reg;
txfqs_reg = ttcan_read32(ttcan, ADR_MTTCAN_TXFQS);
return (txfqs_reg & MTT_TXFQS_TFQF_MASK) >> MTT_TXFQS_TFQF_SHIFT;
}
static int process_rx_mesg(struct ttcan_controller *ttcan, u32 addr)
{
struct ttcanfd_frame ttcanfd;
ttcan_read_rx_msg_ram(ttcan, addr, &ttcanfd);
return add_msg_controller_list(ttcan, &ttcanfd, &ttcan->rx_b, BUFFER);
}
int ttcan_read_rx_buffer(struct ttcan_controller *ttcan)
{
u32 ndat1, ndat2;
u32 read_addr;
int msgs_read = 0;
ndat1 = ttcan_read32(ttcan, ADR_MTTCAN_NDAT1);
ndat2 = ttcan_read32(ttcan, ADR_MTTCAN_NDAT2);
while (ndat1 != 0 || ndat2 != 0) {
u32 bit_set1 = ffs(ndat1) - 1;
u32 bit_set2 = ffs(ndat2) - 1;
if (ndat1) {
read_addr = ttcan->mram_cfg[MRAM_RXB].off + (bit_set1 *
ttcan->e_size.rx_buffer);
if (process_rx_mesg(ttcan, read_addr))
return msgs_read;
ttcan_write32(ttcan, ADR_MTTCAN_NDAT1,
(1 << (bit_set1)));
msgs_read++;
}
if (ndat2) {
read_addr = ttcan->mram_cfg[MRAM_RXB].off + (bit_set2 *
ttcan->e_size.rx_buffer);
if (process_rx_mesg(ttcan, read_addr))
return msgs_read;
ttcan_write32(ttcan, ADR_MTTCAN_NDAT2,
(1 << (bit_set2)));
msgs_read++;
}
ndat1 &= ~(1 << (bit_set1));
ndat2 &= ~(1 << (bit_set2));
}
return msgs_read;
}
/* Tx Evt Fifo */
unsigned int ttcan_read_txevt_fifo(struct ttcan_controller *ttcan)
{
struct mttcan_tx_evt_element txevt;
u32 txefs;
u32 read_addr;
int q_read = 0;
int msgs_read = 0;
txefs = ttcan_read32(ttcan, ADR_MTTCAN_TXEFS);
if (!(txefs & MTT_TXEFS_EFFL_MASK)) {
pr_debug("%s: Tx Event FIFO empty\n", __func__);
return 0;
}
q_read = ttcan->tx_config.evt_q_num;
while ((txefs & MTT_TXEFS_EFFL_MASK) && q_read--) {
u32 get_idx =
(txefs & MTT_TXEFS_EFGI_MASK) >> MTT_TXEFS_EFGI_SHIFT;
read_addr =
ttcan->mram_cfg[MRAM_TXE].off +
(get_idx * TX_EVENT_FIFO_ELEM_SIZE);
pr_debug("%s:txevt: read_addr %x EFGI %x\n", __func__,
read_addr, get_idx);
ttcan_read_txevt_ram(ttcan, read_addr, &txevt);
if (add_event_controller_list(ttcan, &txevt,
&ttcan->tx_evt) < 0) {
pr_err("%s: failed to add to list\n", __func__);
return msgs_read;
}
ttcan_write32(ttcan, ADR_MTTCAN_TXEFA, get_idx);
txefs = ttcan_read32(ttcan, ADR_MTTCAN_TXEFS);
msgs_read++;
}
return msgs_read;
}
/* Rx FIFO section */
unsigned int ttcan_read_rx_fifo0(struct ttcan_controller *ttcan)
{
u32 rxf0s_reg;
struct ttcanfd_frame ttcanfd;
u32 read_addr;
int q_read = 0;
unsigned int msgs_read = 0;
rxf0s_reg = ttcan_read32(ttcan, ADR_MTTCAN_RXF0S);
if (!(rxf0s_reg & MTT_RXF0S_F0FL_MASK)) {
return msgs_read;
}
/* Read at max queue size in one attempt */
q_read = ttcan->mram_cfg[MRAM_RXF0].num;
while ((rxf0s_reg & MTT_RXF0S_F0FL_MASK) && q_read--) {
u32 get_idx = (rxf0s_reg & MTT_RXF0S_F0GI_MASK) >>
MTT_RXF0S_F0GI_SHIFT;
if (ttcan->rx_config.rxq0_bmsk & (1 << get_idx)) {
/* All ready process on High priority */
ttcan_write32(ttcan, ADR_MTTCAN_RXF0A, get_idx);
ttcan->rx_config.rxq0_bmsk &= ~(1U << get_idx);
rxf0s_reg = ttcan_read32(ttcan, ADR_MTTCAN_RXF0S);
continue;
}
read_addr = ttcan->mram_cfg[MRAM_RXF0].off +
(get_idx * ttcan->e_size.rx_fifo0);
pr_debug("%s:fifo0: read_addr %x FOGI %x\n", __func__,
read_addr, get_idx);
ttcan_read_rx_msg_ram(ttcan, read_addr, &ttcanfd);
if (add_msg_controller_list(ttcan, &ttcanfd,
&ttcan->rx_q0, FIFO_0) < 0) {
pr_err("%s: failed to add to list\n", __func__);
return msgs_read;
}
ttcan_write32(ttcan, ADR_MTTCAN_RXF0A, get_idx);
rxf0s_reg = ttcan_read32(ttcan, ADR_MTTCAN_RXF0S);
msgs_read++;
}
return msgs_read;
}
unsigned int ttcan_read_rx_fifo1(struct ttcan_controller *ttcan)
{
u32 rxf1s_reg;
struct ttcanfd_frame ttcanfd;
u32 read_addr;
int q_read = 0;
int msgs_read = 0;
rxf1s_reg = ttcan_read32(ttcan, ADR_MTTCAN_RXF1S);
if (!(rxf1s_reg & MTT_RXF1S_F1FL_MASK)) {
return msgs_read;
}
/* Read at max queue size in one attempt */
q_read = ttcan->mram_cfg[MRAM_RXF1].num;
while ((rxf1s_reg & MTT_RXF1S_F1FL_MASK) && q_read--) {
u32 get_idx = (rxf1s_reg & MTT_RXF1S_F1GI_MASK) >>
MTT_RXF1S_F1GI_SHIFT;
if (ttcan->rx_config.rxq1_bmsk & (1 << get_idx)) {
/* All ready process on High priority */
ttcan_write32(ttcan, ADR_MTTCAN_RXF1A, get_idx);
ttcan->rx_config.rxq1_bmsk &= ~(1U << get_idx);
rxf1s_reg = ttcan_read32(ttcan, ADR_MTTCAN_RXF1S);
continue;
}
read_addr = ttcan->mram_cfg[MRAM_RXF1].off +
(get_idx * ttcan->e_size.rx_fifo1);
pr_debug("%s:fifo1: read_addr %x FOGI %x\n", __func__,
read_addr, get_idx);
ttcan_read_rx_msg_ram(ttcan, read_addr, &ttcanfd);
if (add_msg_controller_list(ttcan, &ttcanfd,
&ttcan->rx_q1, FIFO_1) < 0) {
pr_err("%s: failed to add to list\n", __func__);
return msgs_read;
}
ttcan_write32(ttcan, ADR_MTTCAN_RXF1A, get_idx);
rxf1s_reg = ttcan_read32(ttcan, ADR_MTTCAN_RXF1S);
msgs_read++;
}
return msgs_read;
}
/* Returns message read else return 0 */
unsigned int ttcan_read_rx_fifo(struct ttcan_controller *ttcan)
{
int msgs_read = 0;
msgs_read = ttcan_read_rx_fifo0(ttcan);
if (ttcan->mram_cfg[MRAM_RXF1].num)
msgs_read += ttcan_read_rx_fifo1(ttcan);
return msgs_read;
}
unsigned int ttcan_read_hp_mesgs(struct ttcan_controller *ttcan,
struct ttcanfd_frame *ttcanfd)
{
u32 hpms;
u32 fltr_idx;
u32 buf_idx;
u32 msi;
u32 read_addr;
hpms = ttcan_read32(ttcan, ADR_MTTCAN_HPMS);
fltr_idx = (hpms & MTT_HPMS_FIDX_MASK) >> MTT_HPMS_FIDX_SHIFT;
buf_idx = (hpms & MTT_HPMS_BIDX_MASK) >> MTT_HPMS_BIDX_SHIFT;
msi = (hpms & MTT_HPMS_MSI_MASK) >> MTT_HPMS_MSI_SHIFT;
if (hpms & MTT_HPMS_FLST_MASK) {
/* Extended Filter list */
pr_debug("Xtd Filter:%d Matched\n", fltr_idx);
pr_debug("0x%llx\n", ttcan_get_xtd_id_filter(ttcan, fltr_idx));
} else {
/* Standard Filter list */
pr_debug("Std Filter:%d Matched\n", fltr_idx);
pr_debug("0x%x\n", ttcan_get_std_id_filter(ttcan, fltr_idx));
}
switch (msi) {
default:
pr_info("High Priority Interrupt recieved, no mesg\n");
return 0;
case 1:
pr_info("High Priority FIFO Mesg lost\n");
return 0;
case 2:
read_addr = ttcan->mram_cfg[MRAM_RXF0].off +
(buf_idx * ttcan->e_size.rx_fifo0);
ttcan_read_rx_msg_ram(ttcan, read_addr, ttcanfd);
ttcan->rx_config.rxq0_bmsk |= 1 << buf_idx;
break;
case 3:
read_addr = ttcan->mram_cfg[MRAM_RXF1].off +
buf_idx * ttcan->e_size.rx_fifo1;
ttcan_read_rx_msg_ram(ttcan, read_addr, ttcanfd);
ttcan->rx_config.rxq1_bmsk |= 1 << buf_idx;
}
return 1;
}
/* Rx Buff Section */
void ttcan_set_rx_buffers_elements(struct ttcan_controller *ttcan)
{
u32 rxbc_reg = 0;
u32 rxf0c_reg = 0;
u32 rxf1c_reg = 0;
u32 rxesc_reg = 0;
u32 rel_phy_addr;
enum ttcan_data_field_size rxbuf_dfs;
enum ttcan_data_field_size rxfifo0_dfs;
enum ttcan_data_field_size rxfifo1_dfs;
u32 rxq0 = ttcan->mram_cfg[MRAM_RXF0].num;
u32 rxq1 = ttcan->mram_cfg[MRAM_RXF1].num;
/* Set Rx Buffer Address */
rel_phy_addr = ttcan->mram_cfg[MRAM_RXB].off >> 2;
rxbc_reg = (rel_phy_addr << MTT_RXBC_RBSA_SHIFT) & MTT_RXBC_RBSA_MASK;
ttcan_write32(ttcan, ADR_MTTCAN_RXBC, rxbc_reg);
/* Set RXFIFO 0 */
rel_phy_addr = ttcan->mram_cfg[MRAM_RXF0].off >> 2;
rxf0c_reg = ((rxq0 / 2) << MTT_RXF0C_F0WM_SHIFT) & MTT_RXF0C_F0WM_MASK;
rxf0c_reg |= (rxq0 << MTT_RXF0C_F0S_SHIFT) & MTT_RXF0C_F0S_MASK;
rxf0c_reg |= (rel_phy_addr << MTT_RXF0C_F0SA_SHIFT) &
MTT_RXF0C_F0SA_MASK;
ttcan_write32(ttcan, ADR_MTTCAN_RXF0C, rxf0c_reg);
/* Set RxFIFO 1 */
rel_phy_addr = ttcan->mram_cfg[MRAM_RXF1].off >> 2;
rxf1c_reg = ((rxq1 / 2) << MTT_RXF1C_F1WM_SHIFT) & MTT_RXF1C_F1WM_MASK;
rxf1c_reg |= (rxq1 << MTT_RXF1C_F1S_SHIFT) & MTT_RXF1C_F1S_MASK;
rxf1c_reg |= (rel_phy_addr << MTT_RXF1C_F1SA_SHIFT) &
MTT_RXF1C_F1SA_MASK;
ttcan_write32(ttcan, ADR_MTTCAN_RXF1C, rxf1c_reg);
/* Set Rx element datasize */
rxbuf_dfs = get_dfs(ttcan->rx_config.rxb_dsize);
rxfifo0_dfs = get_dfs(ttcan->rx_config.rxq0_dsize);
rxfifo1_dfs = get_dfs(ttcan->rx_config.rxq1_dsize);
rxesc_reg = (rxbuf_dfs << MTT_RXESC_RBDS_SHIFT) & MTT_RXESC_RBDS_MASK;
rxesc_reg |= (rxfifo0_dfs << MTT_RXESC_F0DS_SHIFT) &
MTT_RXESC_F0DS_MASK;
rxesc_reg |= (rxfifo1_dfs << MTT_RXESC_F1DS_SHIFT) &
MTT_RXESC_F1DS_MASK;
ttcan_write32(ttcan, ADR_MTTCAN_RXESC, rxesc_reg);
ttcan->e_size.rx_buffer =
RXB_ELEM_HEADER_SIZE + ttcan->rx_config.rxb_dsize;
ttcan->e_size.rx_fifo0 =
RXB_ELEM_HEADER_SIZE + ttcan->rx_config.rxq0_dsize;
ttcan->e_size.rx_fifo1 =
RXB_ELEM_HEADER_SIZE + ttcan->rx_config.rxq1_dsize;
}
/* Filters Section */
int ttcan_set_gfc(struct ttcan_controller *ttcan, u32 regval)
{
int ret = 0;
ret = ttcan_write32_check(ttcan, ADR_MTTCAN_GFC, regval,
MTTCAN_GFC_MSK);
if (ret)
pr_err("%s: unable to set GFC register\n", __func__);
return ret;
}
u32 ttcan_get_gfc(struct ttcan_controller *ttcan)
{
return ttcan_read32(ttcan, ADR_MTTCAN_GFC);
}
int ttcan_set_xidam(struct ttcan_controller *ttcan, u32 regval)
{
int ret = 0;
ret = ttcan_write32_check(ttcan, ADR_MTTCAN_XIDAM, regval,
MTTCAN_XIDAM_MSK);
if (ret)
pr_err("%s: unable to set XIDAM register\n", __func__);
return ret;
}
u32 ttcan_get_xidam(struct ttcan_controller *ttcan)
{
return ttcan_read32(ttcan, ADR_MTTCAN_XIDAM);
}
int ttcan_set_ttrmc(struct ttcan_controller *ttcan, u32 regval)
{
int ret = 0;
ret = ttcan_write32_check(ttcan, ADR_MTTCAN_TTRMC, regval,
MTTCAN_TTRMC_MSK);
if (ret)
pr_err("%s: unable to set TTRMC register\n", __func__);
return ret;
}
u32 ttcan_get_ttrmc(struct ttcan_controller *ttcan)
{
return ttcan_read32(ttcan, ADR_MTTCAN_TTRMC);
}
void ttcan_set_std_id_filter_addr(struct ttcan_controller *ttcan)
{
u32 sidfc_reg = 0;
u32 rel_start_addr = ttcan->mram_cfg[MRAM_SIDF].off >> 2;
u32 list_size = ttcan->mram_cfg[MRAM_SIDF].num;
if (list_size > 128)
list_size = 128;
sidfc_reg = (rel_start_addr << MTT_SIDFC_FLSSA_SHIFT) &
MTT_SIDFC_FLSSA_MASK;
sidfc_reg |= (list_size << MTT_SIDFC_LSS_SHIFT) & MTT_SIDFC_LSS_MASK;
ttcan_write32(ttcan, ADR_MTTCAN_SIDFC, sidfc_reg);
}
void ttcan_set_xtd_id_filter_addr(struct ttcan_controller *ttcan)
{
u32 xidfc_reg = 0;
u32 list_size = ttcan->mram_cfg[MRAM_XIDF].num;
u32 rel_start_addr = ttcan->mram_cfg[MRAM_XIDF].off >> 2;
if (list_size > 64)
list_size = 64;
xidfc_reg = (rel_start_addr << MTT_XIDFC_FLESA_SHIFT) &
MTT_XIDFC_FLESA_MASK;
xidfc_reg |= (list_size << MTT_XIDFC_LSE_SHIFT) & MTT_XIDFC_LSE_MASK;
ttcan_write32(ttcan, ADR_MTTCAN_XIDFC, xidfc_reg);
}
inline void ttcan_set_timestamp_offset_sel(struct ttcan_controller *ttcan)
{
u32 val;
val = ttcan_xread32(ttcan, ADDR_M_TTCAN_TIME_STAMP);
val |= M_TTCAN_TIME_STAMP_OFFSET_SEL;
ttcan_xwrite32(ttcan, ADDR_M_TTCAN_TIME_STAMP, val);
}
void ttcan_set_time_stamp_conf(struct ttcan_controller *ttcan,
u16 timer_prescalar,
enum ttcan_timestamp_source timer_type)
{
u32 tscc = 0;
if (timer_type == TS_EXTERNAL) {
ttcan_set_timestamp_offset_sel(ttcan);
tscc = (timer_type << MTT_TSCC_TSS_SHIFT) & MTT_TSCC_TSS_MASK;
} else {
if (timer_prescalar > 15)
timer_prescalar = 15;
tscc = (timer_prescalar << MTT_TSCC_TCP_SHIFT)
& MTT_TSCC_TCP_MASK;
tscc |= (timer_type << MTT_TSCC_TSS_SHIFT) & MTT_TSCC_TSS_MASK;
ttcan->ts_prescalar = timer_prescalar + 1;
}
ttcan_write32(ttcan, ADR_MTTCAN_TSCC, tscc);
}
void ttcan_set_txevt_fifo_conf(struct ttcan_controller *ttcan)
{
u32 txefc = 0;
u32 rel_addr = ttcan->mram_cfg[MRAM_TXE].off >> 2;
u32 evf_size = ttcan->mram_cfg[MRAM_TXE].num;
txefc = ((evf_size / 2) << MTT_TXEFC_EFWM_SHIFT) &
MTT_TXEFC_EFWM_MASK;
txefc |= evf_size << MTT_TXEFC_EFS_SHIFT & MTT_TXEFC_EFS_MASK;
txefc |= rel_addr << MTT_TXEFC_EFSA_SHIFT & MTT_TXEFC_EFSA_MASK;
ttcan_write32(ttcan, ADR_MTTCAN_TXEFC, txefc);
ttcan->tx_config.evt_q_num = evf_size;
}
void ttcan_set_xtd_mask_add(struct ttcan_controller *ttcan, int extid_mask)
{
u32 xidam_reg = 0;
xidam_reg = MTT_XIDAM_EIDM_MASK & 0x1FFFFFFF;
ttcan_write32(ttcan, ADR_MTTCAN_XIDAM, xidam_reg);
}
u32 ttcan_read_tx_complete_reg(struct ttcan_controller *ttcan)
{
return ttcan_read32(ttcan, ADR_MTTCAN_TXBTO);
}
void ttcan_set_tx_cancel_request(struct ttcan_controller *ttcan, u32 txbcr)
{
ttcan_write32(ttcan, ADR_MTTCAN_TXBCR, txbcr);
}
u32 ttcan_read_tx_cancelled_reg(struct ttcan_controller *ttcan)
{
return ttcan_read32(ttcan, ADR_MTTCAN_TXBCF);
}
u32 ttcan_read_psr(struct ttcan_controller *ttcan)
{
return ttcan_read32(ttcan, ADR_MTTCAN_PSR);
}
int ttcan_controller_init(struct ttcan_controller *ttcan, u32 irq_flag,
u32 tt_irq_flag)
{
if (!ttcan) {
pr_err("TTCAN controller NULL\n");
return -EINVAL;
}
ttcan->intr_enable_reg = irq_flag;
ttcan->intr_tt_enable_reg = tt_irq_flag;
spin_lock_init(&ttcan->lock);
return 0;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
cycle_t ttcan_read_ts_cntr(const struct cyclecounter *ccnt)
#else
u64 ttcan_read_ts_cntr(const struct cyclecounter *ccnt)
#endif
{
struct mttcan_priv *priv = container_of(ccnt, struct mttcan_priv, cc);
return ttcan_read32(priv->ttcan, ADR_MTTCAN_TSCV);
}