Newer
Older
mbed-os / targets / TARGET_RENESAS / TARGET_RZ_A2XX / can_api.c
@Hari Limaye Hari Limaye on 17 Sep 2021 30 KB CAN: Use uintptr_t for can_irq_ids
/* mbed Microcontroller Library
 * Copyright (c) 2006-2020 ARM Limited
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#if DEVICE_CAN
#include "mbed_assert.h"
#include "can_api.h"
#include "RZ_A2_Init.h"
#include "cmsis.h"
#include "PeripheralPins.h"
#include "iodefine.h"
#include "r_typedefs.h"

#include "mbed_drv_cfg.h"
#include "rza_io_regrw.h"
#include "iobitmask.h"
#include "r_can_rz_config.h"
#include "r_can_rz_if.h"

/* RZA IO */
#define REG_32W                 RZA_IO_RegWrite_32
#define REG_NONSHIFT            IOREG_NONSHIFT_ACCESS
#define REG_NONMASK             IOREG_NONMASK_ACCESS
/* Channel */
#define CHANNEL_MAX             MAX_CHANNELS
#define CAN_TX_RX               2
#define CAN_IRQ_TYPE_MAX        8
/* RX rule */
#define RXRULE_J_MAX            16
#define RXRULE_CH0_MAX          CAN0_RX_RULE_NUM
#define RXRULE_CH1_MAX          CAN1_RX_RULE_NUM
/* TR_FIFO */
#define TX_TRFIFO_INDEX(ch)     (ch * TRFIFO_NUM_PER_CH)
#define RX_TRFIFO_INDEX(ch)     (ch * TRFIFO_NUM_PER_CH) + 1
/* Normal bit rate */
#define NSS_MAX                 1
#define NTSEG1_MAX              128
#define NTSEG2_MAX              32
#define N_TOTAL_TQMAX           (NSS_MAX + NTSEG1_MAX + NTSEG2_MAX)
#define N_TOTAL_TQMIN           8
#define N_SAMPLE_POINT          0.666666667
#define N_SJW                   3
#define N_BITRATE_DEFAULT       100000
#define N_BITRATE_MAX           1000000
/* Data bit rate */
#define DSS_MAX                 1
#define DTSEG1_MAX              16
#define DTSEG2_MAX              8
#define D_TOTAL_TQMAX           (DSS_MAX + DTSEG1_MAX + DTSEG2_MAX)
#define D_TOTAL_TQMIN           8
#define D_SAMPLE_POINT          0.666666667
#define D_SJW                   3
#define D_CH0_BITRATE           2000000
#define D_CH1_BITRATE           2000000

/*
 * RCANFD Register
 */
/* CmCTR */
#define CTR_BEIE                RCANFD_RSCFD0CFDC0CTR_BEIE
#define CTR_EWIE                RCANFD_RSCFD0CFDC0CTR_EWIE
#define CTR_EPIE                RCANFD_RSCFD0CFDC0CTR_EPIE
#define CTR_BOEIE               RCANFD_RSCFD0CFDC0CTR_BOEIE
#define CTR_BORIE               RCANFD_RSCFD0CFDC0CTR_BORIE
#define CTR_OLIE                RCANFD_RSCFD0CFDC0CTR_OLIE
#define CTR_BLIE                RCANFD_RSCFD0CFDC0CTR_BLIE
#define CTR_ALIE                RCANFD_RSCFD0CFDC0CTR_ALIE
#define CTR_TAIE                RCANFD_RSCFD0CFDC0CTR_TAIE
#define CTR_IEALL               (CTR_BEIE | CTR_EWIE | CTR_EPIE | CTR_BOEIE | CTR_BORIE | \
                                 CTR_OLIE | CTR_BLIE | CTR_ALIE | CTR_TAIE)
#define CTR_EOCOIE              RCANFD_RSCFD0CFDC0CTR_EOCOIE
#define CTR_SOCOIE              RCANFD_RSCFD0CFDC0CTR_SOCOIE
#define CTR_TDCVFIE             RCANFD_RSCFD0CFDC0CTR_TDCVFIE
#define CTR_BOM                 RCANFD_RSCFD0CFDC0CTR_BOM
#define CTR_ERRD                RCANFD_RSCFD0CFDC0CTR_ERRD
#define CTR_CTME                RCANFD_RSCFD0CFDC0CTR_CTME
#define CTR_CTMS                RCANFD_RSCFD0CFDC0CTR_CTMS
#define CTR_CRCT                RCANFD_RSCFD0CFDC0CTR_CRCT
#define CTR_ROM                 RCANFD_RSCFD0CFDC0CTR_ROM
#define CTR_CTME_SHIFT          RCANFD_RSCFD0CFDC0CTR_CTME_SHIFT
#define CTR_CTMS_SHIFT          RCANFD_RSCFD0CFDC0CTR_CTMS_SHIFT
#define MASK_CTR_INIT           (CTR_ERRD | CTR_BOM | CTR_TDCVFIE | CTR_SOCOIE | CTR_EOCOIE | CTR_IEALL)
/* CmERFL */
#define ERFL_BEF                RCANFD_RSCFD0CFDC0ERFL_BEF
#define ERFL_EWF                RCANFD_RSCFD0CFDC0ERFL_EWF
#define ERFL_EPF                RCANFD_RSCFD0CFDC0ERFL_EPF
#define ERFL_BOEF               RCANFD_RSCFD0CFDC0ERFL_BOEF
#define ERFL_BORF               RCANFD_RSCFD0CFDC0ERFL_BORF
#define ERFL_OVLF               RCANFD_RSCFD0CFDC0ERFL_OVLF
#define ERFL_BLF                RCANFD_RSCFD0CFDC0ERFL_BLF
#define ERFL_ALF                RCANFD_RSCFD0CFDC0ERFL_ALF
#define ERFL_SERR               RCANFD_RSCFD0CFDC0ERFL_SERR
#define ERFL_FERR               RCANFD_RSCFD0CFDC0ERFL_FERR
#define ERFL_AERR               RCANFD_RSCFD0CFDC0ERFL_AERR
#define ERFL_CERR               RCANFD_RSCFD0CFDC0ERFL_CERR
#define ERFL_B1ERR              RCANFD_RSCFD0CFDC0ERFL_B1ERR
#define ERFL_B0ERR              RCANFD_RSCFD0CFDC0ERFL_B0ERR
#define ERFL_ADERR              RCANFD_RSCFD0CFDC0ERFL_ADERR
#define ERFL_ALLERR             (ERFL_SERR | ERFL_FERR | ERFL_AERR | ERFL_CERR | ERFL_B1ERR | ERFL_B0ERR | ERFL_ADERR)
/* CmFDCFG */
#define FDCFG_EOCCFG            RCANFD_RSCFD0CFDC0FDCFG_EOCCFG
#define FDCFG_ESIC              RCANFD_RSCFD0CFDC0FDCFG_ESIC
#define FDCFG_GWEN              RCANFD_RSCFD0CFDC0FDCFG_GWEN
#define FDCFG_GWFDF             RCANFD_RSCFD0CFDC0FDCFG_GWFDF
#define FDCFG_GWBRS             RCANFD_RSCFD0CFDC0FDCFG_GWBRS
#define FDCFG_TMME              RCANFD_RSCFD0CFDC0FDCFG_TMME
#define FDCFG_FDOE              RCANFD_RSCFD0CFDC0FDCFG_FDOE
#define FDCFG_REFE              RCANFD_RSCFD0CFDC0FDCFG_REFE
#define MASK_FDCFG_INIT         (FDCFG_REFE | FDCFG_FDOE | FDCFG_TMME | FDCFG_GWBRS | FDCFG_GWFDF| \
                                 FDCFG_GWEN | FDCFG_ESIC | FDCFG_EOCCFG)
/* GCTR */
#define GCTR_DEIE               RCANFD_RSCFD0CFDGCTR_DEIE
#define GCTR_MEIE               RCANFD_RSCFD0CFDGCTR_MEIE
#define GCTR_THLEIE             RCANFD_RSCFD0CFDGCTR_THLEIE
#define GCTR_CMPOFIE            RCANFD_RSCFD0CFDGCTR_CMPOFIE
#define MASK_GCTR_INIT          (GCTR_DEIE | GCTR_MEIE | GCTR_THLEIE | GCTR_CMPOFIE)
/* CFCCk */
#define CFCC_CFTXIE             RCANFD_RSCFD0CFDCFCC0_CFTXIE
#define CFCC_CFRXIE             RCANFD_RSCFD0CFDCFCC0_CFRXIE
#define CFCC_CFE                RCANFD_RSCFD0CFDCFCC0_CFE
#define MASK_CFCC_INIT          ~(CFCC_CFTXIE | CFCC_CFRXIE | CFCC_CFE)
/* CFSTSk */
#define CFSTS_CFRXIF            RCANFD_RSCFD0CFDCFSTS0_CFRXIF
#define CFSTS_CFTXIF            RCANFD_RSCFD0CFDCFSTS0_CFTXIF
/* RFCCx*/
#define RFCC_RFIE               RCANFD_RSCFD0CFDRFCC0_RFIE
#define RFCC_RFE                RCANFD_RSCFD0CFDRFCC0_RFE
#define MASK_RFCC_INIT          ~(RFCC_RFIE | RFCC_RFE)
/* TXQCCm */
#define TXQCC_TXQDC             RCANFD_RSCFD0CFDTXQCC0_TXQDC
#define TXQCC_TXQIE             RCANFD_RSCFD0CFDTXQCC0_TXQIE
#define TXQCC_TXQIM             RCANFD_RSCFD0CFDTXQCC0_TXQIM
/* THLCCm */
#define THLCC_THLIE             RCANFD_RSCFD0CFDTHLCC0_THLIE
#define THLCC_THLIM             RCANFD_RSCFD0CFDTHLCC0_THLIM
#define THLCC_THLDTE            RCANFD_RSCFD0CFDTHLCC0_THLDTE
/* GTSTCFG */
#define GTSTCFG_C0ICBCE         RCANFD_RSCFD0CFDGTSTCFG_C0ICBCE
#define GTSTCFG_C1ICBCE         RCANFD_RSCFD0CFDGTSTCFG_C1ICBCE
#define GTSTCFG_C0ICBCE_SHIFT   RCANFD_RSCFD0CFDGTSTCFG_C0ICBCE_SHIFT
#define GTSTCFG_C1ICBCE_SHIFT   RCANFD_RSCFD0CFDGTSTCFG_C1ICBCE_SHIFT
/* GTSTCTR */
#define GTSTCTR_ICBCTME         RCANFD_RSCFD0CFDGTSTCTR_ICBCTME
#define GTSTCTR_ICBCTME_SHIFT   RCANFD_RSCFD0CFDGTSTCTR_ICBCTME_SHIFT
/* RX buffer size */
#define RX_FIFO_MULTIPLE        8
#define RX_BUFFER_MAX           (4 * ((19 * RX_FIFO_MULTIPLE) + 1)) / 4

static void can_rec_irq(uint32_t ch);
static void can_trx_irq(uint32_t ch);
static void can_err_irq(uint32_t ch);
static void can0_rec_irq(void);
static void can0_trx_irq(void);
static void can0_err_irq(void);
static void can1_rec_irq(void);
static void can1_trx_irq(void);
static void can1_err_irq(void);
static void set_normal_bitrate(uint32_t ch, int f);
static void reset_register(uint32_t ch);
static void reset_buffer(uint32_t ch);
static void get_rxrule_index(uint32_t ch, int32_t handle, uint8_t *page, uint8_t *j);
static void reconfigure_channel(uint32_t ch);
static void set_test_mode(uint32_t ch, uint32_t mode, uint32_t enable);

typedef enum {
    CAN_TX = 0,
    CAN_RX
} can_operation;

typedef enum {
    TEST_DISABLE = 0,
    TEST_ENABLE
} ctr_ctme;

typedef struct {
    IRQn_Type   id;         /* Interrupt identifier */
    IRQHandler  handler;    /* Interrupt handler    */
} can_irq_int_t;

static const can_irq_int_t irq_tbl[CHANNEL_MAX][CAN_IRQ_TYPE_MAX] = {
    {   /* ch0 */
        { CFRXI0_IRQn, can0_rec_irq }, /* RxIrq : IRQ_RX       */
        { CTXI0_IRQn, can0_trx_irq },  /* TxIrq : IRQ_TX       */
        { CERI0_IRQn, can0_err_irq },  /* EwIrq : IRQ_ERROR    */
        { CERI0_IRQn, can0_err_irq },  /* DoIrq : IRQ_OVERRUN  */
        { CERI0_IRQn, can0_err_irq },  /* WuIrq : IRQ_WAKEUP   */
        { CERI0_IRQn, can0_err_irq },  /* EpIrq : IRQ_PASSIVE  */
        { CERI0_IRQn, can0_err_irq },  /* AlIrq : IRQ_ARB      */
        { CERI0_IRQn, can0_err_irq }   /* BeIrq : IRQ_BUS      */
    },
    {   /* ch1 */
        { CFRXI1_IRQn, can1_rec_irq }, /* RxIrq : IRQ_RX       */
        { CTXI1_IRQn, can1_trx_irq },  /* TxIrq : IRQ_TX       */
        { CERI1_IRQn, can1_err_irq },  /* EwIrq : IRQ_ERROR    */
        { CERI1_IRQn, can1_err_irq },  /* DoIrq : IRQ_OVERRUN  */
        { CERI1_IRQn, can1_err_irq },  /* WuIrq : IRQ_WAKEUP   */
        { CERI1_IRQn, can1_err_irq },  /* EpIrq : IRQ_PASSIVE  */
        { CERI1_IRQn, can1_err_irq },  /* EpIrq : IRQ_PASSIVE  */
        { CERI1_IRQn, can1_err_irq }   /* BeIrq : IRQ_BUS      */
    },
};

static const uint32_t irq_enable_flag_tbl[CAN_IRQ_TYPE_MAX] = {
    CFCC_CFRXIE,      /* RxIrq : IRQ_RX       */
    CFCC_CFTXIE,      /* TxIrq : IRQ_TX       */
    CTR_EWIE,         /* EwIrq : IRQ_ERROR    */
    CTR_OLIE,         /* DoIrq : IRQ_OVERRUN  */
    0,                /* WuIrq : IRQ_WAKEUP   */
    CTR_EPIE,         /* EpIrq : IRQ_PASSIVE  */
    CTR_ALIE,         /* AlIrq : IRQ_ARB      */
    CTR_BEIE,         /* BeIrq : IRQ_BUS      */
};

/* Channel bit rate configuration */
static __IO uint32_t *g_regtbl_ncfg[CHANNEL_MAX] = {
    &RCANFD.RSCFD0CFDC0NCFG.LONG,
    &RCANFD.RSCFD0CFDC1NCFG.LONG
};

/* Channel data bit rate configuration */
static __IO uint32_t *g_regtbl_dcfg[CHANNEL_MAX] = {
    &RCANFD.RSCFD0CFDC0DCFG.LONG,
    &RCANFD.RSCFD0CFDC1DCFG.LONG
};

/* Channel CANFD configuration */
static __IO uint32_t *g_regtbl_fdcfg[CHANNEL_MAX] = {
    &RCANFD.RSCFD0CFDC0FDCFG.LONG,
    &RCANFD.RSCFD0CFDC1FDCFG.LONG
};
static uint32_t g_fdcfg_init[CHANNEL_MAX] = {
    CAN_C0FDCFG,
    CAN_C1FDCFG
};

/* Channel control */
static __IO uint32_t *g_regtbl_ctr[CHANNEL_MAX] = {
    &RCANFD.RSCFD0CFDC0CTR.LONG,
    &RCANFD.RSCFD0CFDC1CTR.LONG
};
static uint32_t g_ctr_init[CHANNEL_MAX] = {
    CAN_C0CTR,
    CAN_C1CTR
};

/* Channel status */
static __IO uint32_t *g_regtbl_sts[CHANNEL_MAX] = {
    &RCANFD.RSCFD0CFDC0STS.LONG,
    &RCANFD.RSCFD0CFDC1STS.LONG
};

/* Channel error flag */
static __IO uint32_t *g_regtbl_erfl[CHANNEL_MAX] = {
    &RCANFD.RSCFD0CFDC0ERFL.LONG,
    &RCANFD.RSCFD0CFDC1ERFL.LONG
};

/* TRFIFO Configuration */
static __IO uint32_t *g_regtbl_cfcc[CHANNEL_MAX][CAN_TX_RX] = {
    { &RCANFD.RSCFD0CFDCFCC0.LONG, &RCANFD.RSCFD0CFDCFCC1.LONG },   // CAN0(TX TR_FIFO0, RX TR_FIFO1)
    { &RCANFD.RSCFD0CFDCFCC3.LONG, &RCANFD.RSCFD0CFDCFCC4.LONG }    // CAN1(TX TR_FIFO3, RX TR_FIFO4)
};
static uint32_t g_cfcc_init[CHANNEL_MAX][CAN_TX_RX] = {
    { CAN_CFCC0, CAN_CFCC1 },                                       // CAN0(TX TR_FIFO0, RX TR_FIFO1)
    { CAN_CFCC3, CAN_CFCC4 }                                        // CAN1(TX TR_FIFO3, RX TR_FIFO4)
};

/* TRFIFO Status */
static __IO uint32_t *g_regtbl_cfsts[CHANNEL_MAX][CAN_TX_RX] = {
    { &RCANFD.RSCFD0CFDCFSTS0.LONG, &RCANFD.RSCFD0CFDCFSTS1.LONG }, // CAN0(TX TR_FIFO0, RX TR_FIFO1)
    { &RCANFD.RSCFD0CFDCFSTS3.LONG, &RCANFD.RSCFD0CFDCFSTS4.LONG }  // CAN1(TX TR_FIFO3, RX TR_FIFO4)
};

/* RXFIFO Configuration */
static __IO uint32_t *g_regtbl_rfcc[CHANNEL_MAX] = {
    &RCANFD.RSCFD0CFDRFCC0.LONG,                                    // CAN0(RX_FIFO0)
    &RCANFD.RSCFD0CFDRFCC4.LONG                                     // CAN1(RX_FIFO4)
};
static uint32_t g_rfcc_init[CHANNEL_MAX] = {
    CAN_RFCC0,                                                      // CAN0(RX_FIFO0)
    CAN_RFCC4                                                       // CAN1(RX_FIFO4)
};

/* TXQCC */
static __IO uint32_t *g_regtbl_txqcc[CHANNEL_MAX] = {
    &RCANFD.RSCFD0CFDTXQCC0.LONG,
    &RCANFD.RSCFD0CFDTXQCC1.LONG
};
static uint32_t g_init_txqcc[CHANNEL_MAX] = {
    CAN_TXQCC0,
    CAN_TXQCC1
};

/* THLCC */
static __IO uint32_t *g_regtbl_thlcc[CHANNEL_MAX] = {
    &RCANFD.RSCFD0CFDTHLCC0.LONG,
    &RCANFD.RSCFD0CFDTHLCC1.LONG
};
static uint32_t g_init_thlcc[CHANNEL_MAX] = {
    CAN_THLCC0,
    CAN_THLCC1
};

/* RX rule register : ID */
static __IO uint32_t *g_regtbl_gaflid[RXRULE_J_MAX] = {
    &RCANFD.RSCFD0CFDGAFLID0.LONG,
    &RCANFD.RSCFD0CFDGAFLID1.LONG,
    &RCANFD.RSCFD0CFDGAFLID2.LONG,
    &RCANFD.RSCFD0CFDGAFLID3.LONG,
    &RCANFD.RSCFD0CFDGAFLID4.LONG,
    &RCANFD.RSCFD0CFDGAFLID5.LONG,
    &RCANFD.RSCFD0CFDGAFLID6.LONG,
    &RCANFD.RSCFD0CFDGAFLID7.LONG,
    &RCANFD.RSCFD0CFDGAFLID8.LONG,
    &RCANFD.RSCFD0CFDGAFLID9.LONG,
    &RCANFD.RSCFD0CFDGAFLID10.LONG,
    &RCANFD.RSCFD0CFDGAFLID11.LONG,
    &RCANFD.RSCFD0CFDGAFLID12.LONG,
    &RCANFD.RSCFD0CFDGAFLID13.LONG,
    &RCANFD.RSCFD0CFDGAFLID14.LONG,
    &RCANFD.RSCFD0CFDGAFLID15.LONG
};

/* RX rule register : Mask */
static __IO uint32_t *g_regtbl_gaflm[RXRULE_J_MAX] = {
    &RCANFD.RSCFD0CFDGAFLM0.LONG,
    &RCANFD.RSCFD0CFDGAFLM1.LONG,
    &RCANFD.RSCFD0CFDGAFLM2.LONG,
    &RCANFD.RSCFD0CFDGAFLM3.LONG,
    &RCANFD.RSCFD0CFDGAFLM4.LONG,
    &RCANFD.RSCFD0CFDGAFLM5.LONG,
    &RCANFD.RSCFD0CFDGAFLM6.LONG,
    &RCANFD.RSCFD0CFDGAFLM7.LONG,
    &RCANFD.RSCFD0CFDGAFLM8.LONG,
    &RCANFD.RSCFD0CFDGAFLM9.LONG,
    &RCANFD.RSCFD0CFDGAFLM10.LONG,
    &RCANFD.RSCFD0CFDGAFLM11.LONG,
    &RCANFD.RSCFD0CFDGAFLM12.LONG,
    &RCANFD.RSCFD0CFDGAFLM13.LONG,
    &RCANFD.RSCFD0CFDGAFLM14.LONG,
    &RCANFD.RSCFD0CFDGAFLM15.LONG
};

/* RX rule register : pointer1 */
static __IO uint32_t *g_regtbl_gaflp1[RXRULE_J_MAX] = {
    &RCANFD.RSCFD0CFDGAFLP1_0.LONG,
    &RCANFD.RSCFD0CFDGAFLP1_1.LONG,
    &RCANFD.RSCFD0CFDGAFLP1_2.LONG,
    &RCANFD.RSCFD0CFDGAFLP1_3.LONG,
    &RCANFD.RSCFD0CFDGAFLP1_4.LONG,
    &RCANFD.RSCFD0CFDGAFLP1_5.LONG,
    &RCANFD.RSCFD0CFDGAFLP1_6.LONG,
    &RCANFD.RSCFD0CFDGAFLP1_7.LONG,
    &RCANFD.RSCFD0CFDGAFLP1_8.LONG,
    &RCANFD.RSCFD0CFDGAFLP1_9.LONG,
    &RCANFD.RSCFD0CFDGAFLP1_10.LONG,
    &RCANFD.RSCFD0CFDGAFLP1_11.LONG,
    &RCANFD.RSCFD0CFDGAFLP1_12.LONG,
    &RCANFD.RSCFD0CFDGAFLP1_13.LONG,
    &RCANFD.RSCFD0CFDGAFLP1_14.LONG,
    &RCANFD.RSCFD0CFDGAFLP1_15.LONG
};

/* DLC to data length */
static const uint8_t dlc_to_length[16] = {
    0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64
};

volatile int g_normal_bitrate[CHANNEL_MAX];
volatile int g_data_bitrate[CHANNEL_MAX] = {D_CH0_BITRATE, D_CH1_BITRATE};
uint32_t rx_buf[RX_BUFFER_MAX];
static can_irq_handler irq_handler[CHANNEL_MAX] = {NULL};
static uintptr_t can_irq_contexts[CHANNEL_MAX] = {0};

void can_irq_init(can_t *obj, can_irq_handler handler, uintptr_t context)
{
    irq_handler[obj->ch] = handler;
    can_irq_contexts[obj->ch] = context;
}

void can_irq_free(can_t *obj)
{
    can_irq_contexts[obj->ch] = 0;
    *g_regtbl_cfcc[obj->ch][CAN_RX] &= ~CFCC_CFRXIE;
    *g_regtbl_cfcc[obj->ch][CAN_TX] &= ~CFCC_CFTXIE;
    *g_regtbl_ctr[obj->ch] &= ~(CTR_EWIE | CTR_OLIE | CTR_EPIE | CTR_ALIE | CTR_BEIE);
    if (CH_0 == obj->ch) {
        GIC_DisableIRQ(CFRXI0_IRQn);
        GIC_DisableIRQ(CTXI0_IRQn);
        GIC_DisableIRQ(CERI0_IRQn);
    } else {
        GIC_DisableIRQ(CFRXI1_IRQn);
        GIC_DisableIRQ(CTXI1_IRQn);
        GIC_DisableIRQ(CERI1_IRQn);
    }
}

void can_irq_set(can_t *obj, CanIrqType type, uint32_t enable)
{
    switch (type) {
        case IRQ_RX:
            if (enable) {
                *g_regtbl_cfcc[obj->ch][CAN_RX] |= CFCC_CFRXIE;
            } else {
                *g_regtbl_cfcc[obj->ch][CAN_RX] &= ~CFCC_CFRXIE;
            }
            break;
        case IRQ_TX:
            if (enable) {
                *g_regtbl_cfcc[obj->ch][CAN_TX] |= CFCC_CFTXIE;
            } else {
                *g_regtbl_cfcc[obj->ch][CAN_TX] &= ~CFCC_CFTXIE;
            }
            break;
        case IRQ_ERROR:
        case IRQ_OVERRUN:
        case IRQ_PASSIVE:
        case IRQ_ARB:
        case IRQ_BUS:
            if (enable) {
                *g_regtbl_ctr[obj->ch] |= irq_enable_flag_tbl[type];
            } else {
                *g_regtbl_ctr[obj->ch] &= ~irq_enable_flag_tbl[type];
            }
            break;
        case IRQ_WAKEUP:
        /* not supported */
        /* fall through */
        default:
            return;
    }
    if (enable) {
        InterruptHandlerRegister(irq_tbl[obj->ch][type].id, irq_tbl[obj->ch][type].handler);
        GIC_SetPriority(irq_tbl[obj->ch][type].id, 20);
        GIC_EnableIRQ(irq_tbl[obj->ch][type].id);
        GIC_SetConfiguration(irq_tbl[obj->ch][type].id, 1);
    } else {
        GIC_DisableIRQ(irq_tbl[obj->ch][type].id);
    }
}

static void can_rec_irq(uint32_t ch)
{
    *g_regtbl_cfsts[ch][CAN_RX] &= ~CFSTS_CFRXIF;
    irq_handler[ch](can_irq_contexts[ch], IRQ_RX);
}

static void can_trx_irq(uint32_t ch)
{
    *g_regtbl_cfsts[ch][CAN_TX] &= ~CFSTS_CFTXIF;
    irq_handler[ch](can_irq_contexts[ch], IRQ_TX);
}

static void can_err_irq(uint32_t ch)
{
    /* error warning */
    if (*g_regtbl_erfl[ch] & ERFL_EWF) {
        *g_regtbl_erfl[ch] &= ~ERFL_EWF;
        irq_handler[ch](can_irq_contexts[ch], IRQ_ERROR);
    }

    /* over load */
    if (*g_regtbl_erfl[ch] & ERFL_OVLF) {
        *g_regtbl_erfl[ch] &= ~ERFL_OVLF;
        irq_handler[ch](can_irq_contexts[ch], IRQ_OVERRUN);
    }

    /* error passive */
    if (*g_regtbl_erfl[ch] & ERFL_EPF) {
        *g_regtbl_erfl[ch] &= ~ERFL_EPF;
        irq_handler[ch](can_irq_contexts[ch], IRQ_PASSIVE);
    }

    /* arbitration lost */
    if (*g_regtbl_erfl[ch] & ERFL_ALF) {
        *g_regtbl_erfl[ch] &= ~ERFL_ALF;
        irq_handler[ch](can_irq_contexts[ch], IRQ_ARB);
    }

    /* bus error */
    if (*g_regtbl_erfl[ch] & ERFL_ALLERR) {
        *g_regtbl_erfl[ch] &= ~ERFL_ALLERR;
        *g_regtbl_erfl[ch] &= ~ERFL_BEF;
        irq_handler[ch](can_irq_contexts[ch], IRQ_BUS);
    }
}

static void can0_rec_irq(void)
{
    can_rec_irq(CAN_0);
}

static void can0_trx_irq(void)
{
    can_trx_irq(CAN_0);
}

static void can0_err_irq(void)
{
    can_err_irq(CAN_0);
}

static void can1_rec_irq(void)
{
    can_rec_irq(CAN_1);
}

static void can1_trx_irq(void)
{
    can_trx_irq(CAN_1);
}

static void can1_err_irq(void)
{
    can_err_irq(CAN_1);
}

static void set_normal_bitrate(uint32_t ch, int f)
{
    uint32_t clkc;
    uint16_t tq_total;
    uint16_t brp;
    uint8_t  tseg1 = 0;
    uint8_t  tseg2 = 0;
    uint8_t  sjw = 0;

    /* clkc */
    if (false == RZ_A2_IsClockMode0()) {
        clkc = CM1_RENESAS_RZ_A2_P1_CLK / 2;
    } else {
        clkc = CM0_RENESAS_RZ_A2_P1_CLK / 2;
    }
    /* calculate NTSEG1 bit and NTSEG2 bit */
    for (brp = 1; brp < 1024; brp++) {
        tq_total = clkc / (f * brp);
        if ((N_TOTAL_TQMIN <= tq_total) && (tq_total <= N_TOTAL_TQMAX)) {
            tseg1 = tq_total * N_SAMPLE_POINT - NSS_MAX;
            tseg2 = tq_total - (NSS_MAX + tseg1);
            if ((NTSEG1_MAX >= tseg1) && (NTSEG2_MAX >= tseg2)) {
                break;
            }
        }
    }
    /* calculate NSJW */
    sjw = (tseg2 > N_SJW) ? N_SJW : tseg2;
    /* set RSCAN0CmCFG register */
    *g_regtbl_ncfg[ch] = ((tseg2 - 1) << 24) | ((tseg1 - 1) << 16) | ((sjw - 1) << 11) | (brp - 1);
}

static void set_data_bitrate(uint32_t ch, int f)
{
    uint32_t clkc;
    uint16_t tq_total;
    uint16_t dbrp;
    uint8_t  dtseg1 = 0;
    uint8_t  dtseg2 = 0;
    uint8_t  dsjw = 0;

    /* clkc */
    if (false == RZ_A2_IsClockMode0()) {
        clkc = CM1_RENESAS_RZ_A2_P1_CLK / 2;
    } else {
        clkc = CM0_RENESAS_RZ_A2_P1_CLK / 2;
    }
    /* calculate DTSEG1 bit and DTSEG2 bit */
    for (dbrp = 1; dbrp < 256; dbrp++) {
        tq_total = clkc / (f * dbrp);
        if ((D_TOTAL_TQMIN <= tq_total) && (tq_total <= D_TOTAL_TQMAX)) {
            dtseg1 = tq_total * D_SAMPLE_POINT - DSS_MAX;
            dtseg2 = tq_total - (DSS_MAX + dtseg1);
            if ((DTSEG1_MAX >= dtseg1) && (DTSEG2_MAX >= dtseg2)) {
                break;
            }
        }
    }
    /* calculate DSJW */
    dsjw = (dtseg2 >= D_SJW) ? D_SJW : dtseg2;
    /* set RSCAN0CmDCFG register */
    *g_regtbl_dcfg[ch] = ((dsjw - 1) << 24) | ((dtseg2 - 1) << 20) | ((dtseg1 - 1) << 16) | (dbrp - 1);
}

static void reset_register(uint32_t ch)
{
    /* Global function setting */
    REG_32W(&RCANFD.RSCFD0CFDGCFG.LONG, CAN_GCFG, REG_NONSHIFT, REG_NONMASK);
    REG_32W(&RCANFD.RSCFD0CFDGFDCFG.LONG, CAN_GFDCFG, REG_NONSHIFT, REG_NONMASK);

    /* Communication speed setting */
    set_normal_bitrate(ch, g_normal_bitrate[ch]);
    set_data_bitrate(ch, g_data_bitrate[ch]);

    /* Rx rule setting */
    Wrap_Can_SetRxRule();

    /* Buffer setting */
    reset_buffer(ch);

    /* Global Error Interrupt setting */
    REG_32W(&RCANFD.RSCFD0CFDGCTR.LONG, CAN_GCTR, REG_NONSHIFT, MASK_GCTR_INIT);

    /* CANFD setting */
    REG_32W(g_regtbl_ctr[ch], g_ctr_init[ch], REG_NONSHIFT, MASK_CTR_INIT);
    REG_32W(g_regtbl_fdcfg[ch], g_fdcfg_init[ch], REG_NONSHIFT, MASK_FDCFG_INIT);

    /* Global Test mode switch (reset->test) */
    R_CAN_Control(UNUSED, GLOBAL_TEST);

    /* Channel halt mode switch (reset->halt) */
    R_CAN_Control(ch, CHANNEL_HALT);

    /* Channel Restricted Operation Mode setting */
    REG_32W(g_regtbl_ctr[ch], g_ctr_init[ch], REG_NONSHIFT, CTR_ROM);
}

static void reset_buffer(uint32_t ch)
{
    /* TR FIFO */
    REG_32W(g_regtbl_cfcc[ch][CAN_TX], g_cfcc_init[ch][CAN_TX], REG_NONSHIFT, MASK_CFCC_INIT);
    REG_32W(g_regtbl_cfcc[ch][CAN_RX], g_cfcc_init[ch][CAN_RX], REG_NONSHIFT, MASK_CFCC_INIT);

    /* RX FIFO */
    REG_32W(g_regtbl_rfcc[ch], g_rfcc_init[ch], REG_NONSHIFT, MASK_RFCC_INIT);

    /* RX buffer */
    REG_32W(&RCANFD.RSCFD0CFDRMNB.LONG, CAN_RMNB, REG_NONSHIFT, REG_NONMASK);

    /* TX buffer */
    REG_32W(&RCANFD.RSCFD0CFDTMIEC0.LONG, CAN_TMIEC0, REG_NONSHIFT, REG_NONMASK);

    /* TX queue */
    REG_32W(g_regtbl_txqcc[ch], g_init_txqcc[ch], REG_NONSHIFT, (TXQCC_TXQDC | TXQCC_TXQIE | TXQCC_TXQIM));

    /* TX history */
    REG_32W(g_regtbl_thlcc[ch], g_init_thlcc[ch], REG_NONSHIFT, (THLCC_THLIE | THLCC_THLIM | THLCC_THLDTE));
}

static void get_rxrule_index(uint32_t ch, int32_t handle, uint8_t *page, uint8_t *j)
{
    *page = (handle + (ch * CAN0_RX_RULE_NUM)) / RXRULE_J_MAX;
    *j    = (handle + (ch * CAN0_RX_RULE_NUM)) % RXRULE_J_MAX;
}

static void reconfigure_channel(uint32_t ch)
{
    R_CAN_Control(UNUSED, GLOBAL_OPERATION);
    R_CAN_Control(ch, CHANNEL_COM);
    REG_32W(g_regtbl_cfcc[ch][CAN_TX], CFCC_CFE, REG_NONSHIFT, CFCC_CFE);
    REG_32W(g_regtbl_cfcc[ch][CAN_RX], CFCC_CFE, REG_NONSHIFT, CFCC_CFE);
}

static void set_test_mode(uint32_t ch, uint32_t mode, uint32_t enable)
{
    R_CAN_Control(ch, CHANNEL_HALT);
    REG_32W(g_regtbl_ctr[ch], mode, CTR_CTMS_SHIFT, CTR_CTMS);
    REG_32W(g_regtbl_ctr[ch], enable, CTR_CTME_SHIFT, CTR_CTME);
}

void can_init(can_t *obj, PinName rd, PinName td)
{
    /* set default frequency */
    can_init_freq(obj, rd, td, N_BITRATE_DEFAULT);
}

void can_init_freq(can_t *obj, PinName rd, PinName td, int hz)
{
    /* determine the CAN to use */
    uint32_t can_rx = pinmap_peripheral(rd, PinMap_CAN_RD);
    uint32_t can_tx = pinmap_peripheral(td, PinMap_CAN_TD);
    obj->ch = pinmap_merge(can_tx, can_rx);
    MBED_ASSERT((int)obj->ch != NC);

    /* initialize */
    CPG.STBCR3.BYTE &= ~CPG_STBCR3_MSTP32;
    R_CAN_PortSet(obj->ch, ENABLE_COMMON);
    R_CAN_PortSet(obj->ch, ENABLE_CHANNEL);
    Wrap_Can_WaitRamInitOver();
    R_CAN_Control(UNUSED, GLOBAL_RESET);
    RCANFD.RSCFD0CFDGRMCFG.LONG |= RCANFD_RSCFD0CFDGRMCFG_RCMC;
    R_CAN_Control(obj->ch, CHANNEL_RESET);
    g_normal_bitrate[obj->ch] = hz;
    reset_register(obj->ch);
    reconfigure_channel(obj->ch);

    /* pin out the can pins */
    pinmap_pinout(rd, PinMap_CAN_RD);
    pinmap_pinout(td, PinMap_CAN_TD);
}

void can_free(can_t *obj)
{
    /* disable CANFD clock */
    CPG.STBCR3.BYTE |= CPG_STBCR3_MSTP32;
}

int can_frequency(can_t *obj, int f)
{
    int retval = 0;

    /* less than normal bitrate */
    if (f <= N_BITRATE_MAX) {
        /* set normal bit rate */
        R_CAN_Control(obj->ch, CHANNEL_RESET);
        g_normal_bitrate[obj->ch] = f;
        set_normal_bitrate(obj->ch, g_normal_bitrate[obj->ch]);
        reconfigure_channel(obj->ch);
        retval = 1;
    }
    return retval;
}

int can_write(can_t *obj, CAN_Message msg, int cc)
{
    can_frame_t frame;

    /* CAN frame */
    frame.ID    = msg.id;       // Message ID
    frame.THDSE = 0;
    frame.RTR   = msg.type;     // 0:CANData, 1:CANRemote
    frame.IDE   = msg.format;   // 0:Standard ID, 1:Extend ID
    frame.LBL   = 0;
    frame.DLC   = msg.len;      // Data length
    frame.FDSTS = 1;
    frame.BRS   = 1;
    frame.ESI   = 0;

    if (R_CAN_OK != R_CAN_TxSet(TX_TRFIFO, TX_TRFIFO_INDEX(obj->ch), &frame, (uint32_t *)&msg.data[0])) {
        return 0;
    }
    if (R_CAN_OK != R_CAN_Tx(TX_TRFIFO, TX_TRFIFO_INDEX(obj->ch), ENABLE)) {
        return 0;
    }
    return 1;
}

int can_read(can_t *obj, CAN_Message *msg, int handle)
{
    uint32_t  page_index = 0;
    uint8_t   received_msg_num = 0;
    uint8_t   msg_cnt;

    if (R_CAN_OK != R_CAN_RxPoll(RX_TRFIFO, RX_TRFIFO_INDEX(obj->ch))) {
        return 0;
    }
    if (R_CAN_OK != R_CAN_RxRead(RX_TRFIFO, RX_TRFIFO_INDEX(obj->ch), (uint32_t *)&rx_buf[0])) {
        return 0;
    }

    /* number of received message */
    received_msg_num = rx_buf[0];

    for (msg_cnt = 0; msg_cnt < received_msg_num; msg_cnt++) {
        page_index = msg_cnt * 19;
        /* IDE 0:Standard ID, 1:Extend ID */
        msg->format = (CANFormat)(rx_buf[page_index + 1] >> 31);
        /* RTR/RRS : Data or Remote */
        msg->type = (CANType)((rx_buf[page_index + 1] >> 30) & 0x1);
        /* ID : Standard ID(b10-b0), Extend ID(b28-b0) */
        msg->id = (rx_buf[page_index + 1] & 0x1FFFFFFF);
        /* data Length */
        msg->len = dlc_to_length[(uint8_t)(rx_buf[page_index + 2] >> 28)];
        /* received data */
        msg->data[0] = (uint8_t)(rx_buf[page_index + 4] & 0x000000FF);
        msg->data[1] = (uint8_t)(rx_buf[page_index + 4] >> 8)  & 0x000000FF;
        msg->data[2] = (uint8_t)(rx_buf[page_index + 4] >> 16) & 0x000000FF;
        msg->data[3] = (uint8_t)(rx_buf[page_index + 4] >> 24) & 0x000000FF;
        msg->data[4] = (uint8_t)(rx_buf[page_index + 5] & 0x000000FF);
        msg->data[5] = (uint8_t)(rx_buf[page_index + 5] >> 8)  & 0x000000FF;
        msg->data[6] = (uint8_t)(rx_buf[page_index + 5] >> 16) & 0x000000FF;
        msg->data[7] = (uint8_t)(rx_buf[page_index + 5] >> 24) & 0x000000FF;
    }

    return 1; /* message arrived */
}

int can_mode(can_t *obj, CanMode mode)
{
    int retval = 1;
    switch (mode) {
        case MODE_RESET:
            /* set to reset mode */
            R_CAN_Control(UNUSED, GLOBAL_RESET);
            R_CAN_Control(obj->ch, CHANNEL_RESET);
            break;
        case MODE_NORMAL:
            /* disable test mode */
            set_test_mode(obj->ch, STD_TEST, TEST_DISABLE);
            reconfigure_channel(obj->ch);
            break;
        case MODE_SILENT:
            /* enable listen only mode */
            set_test_mode(obj->ch, TEST_LISTEN_ONLY, TEST_ENABLE);
            reconfigure_channel(obj->ch);
            break;
        case MODE_TEST_LOCAL:
            /* enable self test mode 0 */
            set_test_mode(obj->ch, EXT_LOOPBACK, TEST_ENABLE);
            reconfigure_channel(obj->ch);
            break;
        case MODE_TEST_GLOBAL:
            /* enable Inter-Channel Communication Test */
            R_CAN_Control(UNUSED, GLOBAL_TEST);
            REG_32W(&RCANFD.RSCFD0CFDGTSTCFG.LONG, TEST_ENABLE, GTSTCFG_C0ICBCE_SHIFT, GTSTCFG_C0ICBCE);
            REG_32W(&RCANFD.RSCFD0CFDGTSTCFG.LONG, TEST_ENABLE, GTSTCFG_C1ICBCE_SHIFT, GTSTCFG_C1ICBCE);
            REG_32W(&RCANFD.RSCFD0CFDGTSTCTR.LONG, TEST_ENABLE, GTSTCTR_ICBCTME_SHIFT, GTSTCTR_ICBCTME);
            /* enable standard test */
            set_test_mode(CH_0, STD_TEST, TEST_ENABLE);
            set_test_mode(CH_1, STD_TEST, TEST_ENABLE);
            reconfigure_channel(CH_0);
            reconfigure_channel(CH_1);
            break;
        case MODE_TEST_SILENT:
            /* enable self test mode 1 */
            set_test_mode(obj->ch, INT_LOOPBACK, TEST_ENABLE);
            reconfigure_channel(obj->ch);
            break;
        default:
            retval = 0;
            break;
    }
    return retval;
}

int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle)
{
    uint8_t page_index;
    uint8_t j_index;

    if ((CH_0 == obj->ch) && (handle >= CAN0_RX_RULE_NUM)) {
        return 0;
    }
    if ((CH_1 == obj->ch) && (handle >= CAN1_RX_RULE_NUM)) {
        return 0;
    }

    /* set to reset mode */
    R_CAN_Control(UNUSED, GLOBAL_RESET);
    R_CAN_Control(obj->ch, CHANNEL_RESET);

    /* write enable (RSCFD0CFDGAFLECTR.AFLDAE) */
    RCANFD.RSCFD0CFDGAFLECTR.LONG |= RCANFD_RSCFD0CFDGAFLECTR_AFLDAE;

    /* set page number */
    get_rxrule_index(obj->ch, handle, &page_index, &j_index);
    REG_32W(&RCANFD.RSCFD0CFDGAFLECTR.LONG, page_index, REG_NONSHIFT, 0x0000001F);

    /* set CAN format */
    REG_32W(g_regtbl_gaflid[j_index], format, 31, 0x80000000);
    if (CANExtended == format) {
        REG_32W(g_regtbl_gaflid[j_index], (id & 0x1FFFFFFF), REG_NONSHIFT, 0x1FFFFFFF);
    } else {
        REG_32W(g_regtbl_gaflid[j_index], (id & 0x000007FF), REG_NONSHIFT, 0x000007FF);
    }

    /* set masks(IDE, RTR, ID) */
    if (CANAny == format) {
        /* no masks */
        REG_32W(g_regtbl_gaflm[j_index], 0, REG_NONSHIFT, REG_NONMASK);
    } else {
        /* IDE and ID */
        REG_32W(g_regtbl_gaflm[j_index], (0x80000000 | mask), REG_NONSHIFT, REG_NONMASK);
    }
    /* set GAFLFDP1_j.GAFLFDP */
    if (CH_0 == obj->ch) {
        REG_32W(g_regtbl_gaflp1[j_index], 0x00000200, REG_NONSHIFT, REG_NONMASK); // CH0:use TRFIFO1
    } else {
        REG_32W(g_regtbl_gaflp1[j_index], 0x00001000, REG_NONSHIFT, REG_NONMASK); // CH1:use TRFIFO4
    }

    /* write disable (RSCFD0CFDGAFLECTR.AFLDAE) */
    RCANFD.RSCFD0CFDGAFLECTR.LONG &= ~RCANFD_RSCFD0CFDGAFLECTR_AFLDAE;

    reconfigure_channel(obj->ch);

    return 1;
}

void can_reset(can_t *obj)
{
    R_CAN_Control(UNUSED, GLOBAL_RESET);
    R_CAN_Control(obj->ch, CHANNEL_RESET);
    reset_register(obj->ch);
    reconfigure_channel(obj->ch);
}

unsigned char can_rderror(can_t *obj)
{
    return (unsigned char)(*g_regtbl_sts[obj->ch] >> RCANFD_RSCFD0CFDC0STS_REC_SHIFT);
}

unsigned char can_tderror(can_t *obj)
{
    return (unsigned char)(*g_regtbl_sts[obj->ch] >> RCANFD_RSCFD0CFDC0STS_TEC_SHIFT);
}

void can_monitor(can_t *obj, int silent)
{
    if (silent) {
        set_test_mode(obj->ch, TEST_LISTEN_ONLY, TEST_ENABLE);
    } else {
        set_test_mode(obj->ch, STD_TEST, TEST_DISABLE);
    }
    reconfigure_channel(obj->ch);
}

const PinMap *can_rd_pinmap()
{
    return PinMap_CAN_TD;
}

const PinMap *can_td_pinmap()
{
    return PinMap_CAN_RD;
}
#endif // DEVICE_CAN