|
@@ -105,14 +105,36 @@ enum m_can_mram_cfg {
|
|
|
MRAM_CFG_NUM,
|
|
|
};
|
|
|
|
|
|
+/* Fast Bit Timing & Prescaler Register (FBTP) */
|
|
|
+#define FBTR_FBRP_MASK 0x1f
|
|
|
+#define FBTR_FBRP_SHIFT 16
|
|
|
+#define FBTR_FTSEG1_SHIFT 8
|
|
|
+#define FBTR_FTSEG1_MASK (0xf << FBTR_FTSEG1_SHIFT)
|
|
|
+#define FBTR_FTSEG2_SHIFT 4
|
|
|
+#define FBTR_FTSEG2_MASK (0x7 << FBTR_FTSEG2_SHIFT)
|
|
|
+#define FBTR_FSJW_SHIFT 0
|
|
|
+#define FBTR_FSJW_MASK 0x3
|
|
|
+
|
|
|
/* Test Register (TEST) */
|
|
|
#define TEST_LBCK BIT(4)
|
|
|
|
|
|
/* CC Control Register(CCCR) */
|
|
|
-#define CCCR_TEST BIT(7)
|
|
|
-#define CCCR_MON BIT(5)
|
|
|
-#define CCCR_CCE BIT(1)
|
|
|
-#define CCCR_INIT BIT(0)
|
|
|
+#define CCCR_TEST BIT(7)
|
|
|
+#define CCCR_CMR_MASK 0x3
|
|
|
+#define CCCR_CMR_SHIFT 10
|
|
|
+#define CCCR_CMR_CANFD 0x1
|
|
|
+#define CCCR_CMR_CANFD_BRS 0x2
|
|
|
+#define CCCR_CMR_CAN 0x3
|
|
|
+#define CCCR_CME_MASK 0x3
|
|
|
+#define CCCR_CME_SHIFT 8
|
|
|
+#define CCCR_CME_CAN 0
|
|
|
+#define CCCR_CME_CANFD 0x1
|
|
|
+#define CCCR_CME_CANFD_BRS 0x2
|
|
|
+#define CCCR_TEST BIT(7)
|
|
|
+#define CCCR_MON BIT(5)
|
|
|
+#define CCCR_CCE BIT(1)
|
|
|
+#define CCCR_INIT BIT(0)
|
|
|
+#define CCCR_CANFD 0x10
|
|
|
|
|
|
/* Bit Timing & Prescaler Register (BTP) */
|
|
|
#define BTR_BRP_MASK 0x3ff
|
|
@@ -204,6 +226,7 @@ enum m_can_mram_cfg {
|
|
|
|
|
|
/* Rx Buffer / FIFO Element Size Configuration (RXESC) */
|
|
|
#define M_CAN_RXESC_8BYTES 0x0
|
|
|
+#define M_CAN_RXESC_64BYTES 0x777
|
|
|
|
|
|
/* Tx Buffer Configuration(TXBC) */
|
|
|
#define TXBC_NDTB_OFF 16
|
|
@@ -211,6 +234,7 @@ enum m_can_mram_cfg {
|
|
|
|
|
|
/* Tx Buffer Element Size Configuration(TXESC) */
|
|
|
#define TXESC_TBDS_8BYTES 0x0
|
|
|
+#define TXESC_TBDS_64BYTES 0x7
|
|
|
|
|
|
/* Tx Event FIFO Con.guration (TXEFC) */
|
|
|
#define TXEFC_EFS_OFF 16
|
|
@@ -219,11 +243,11 @@ enum m_can_mram_cfg {
|
|
|
/* Message RAM Configuration (in bytes) */
|
|
|
#define SIDF_ELEMENT_SIZE 4
|
|
|
#define XIDF_ELEMENT_SIZE 8
|
|
|
-#define RXF0_ELEMENT_SIZE 16
|
|
|
-#define RXF1_ELEMENT_SIZE 16
|
|
|
+#define RXF0_ELEMENT_SIZE 72
|
|
|
+#define RXF1_ELEMENT_SIZE 72
|
|
|
#define RXB_ELEMENT_SIZE 16
|
|
|
#define TXE_ELEMENT_SIZE 8
|
|
|
-#define TXB_ELEMENT_SIZE 16
|
|
|
+#define TXB_ELEMENT_SIZE 72
|
|
|
|
|
|
/* Message RAM Elements */
|
|
|
#define M_CAN_FIFO_ID 0x0
|
|
@@ -231,11 +255,17 @@ enum m_can_mram_cfg {
|
|
|
#define M_CAN_FIFO_DATA(n) (0x8 + ((n) << 2))
|
|
|
|
|
|
/* Rx Buffer Element */
|
|
|
+/* R0 */
|
|
|
#define RX_BUF_ESI BIT(31)
|
|
|
#define RX_BUF_XTD BIT(30)
|
|
|
#define RX_BUF_RTR BIT(29)
|
|
|
+/* R1 */
|
|
|
+#define RX_BUF_ANMF BIT(31)
|
|
|
+#define RX_BUF_EDL BIT(21)
|
|
|
+#define RX_BUF_BRS BIT(20)
|
|
|
|
|
|
/* Tx Buffer Element */
|
|
|
+/* R0 */
|
|
|
#define TX_BUF_XTD BIT(30)
|
|
|
#define TX_BUF_RTR BIT(29)
|
|
|
|
|
@@ -296,6 +326,7 @@ static inline void m_can_config_endisable(const struct m_can_priv *priv,
|
|
|
if (enable) {
|
|
|
/* enable m_can configuration */
|
|
|
m_can_write(priv, M_CAN_CCCR, cccr | CCCR_INIT);
|
|
|
+ udelay(5);
|
|
|
/* CCCR.CCE can only be set/reset while CCCR.INIT = '1' */
|
|
|
m_can_write(priv, M_CAN_CCCR, cccr | CCCR_INIT | CCCR_CCE);
|
|
|
} else {
|
|
@@ -326,41 +357,67 @@ static inline void m_can_disable_all_interrupts(const struct m_can_priv *priv)
|
|
|
m_can_write(priv, M_CAN_ILE, 0x0);
|
|
|
}
|
|
|
|
|
|
-static void m_can_read_fifo(const struct net_device *dev, struct can_frame *cf,
|
|
|
- u32 rxfs)
|
|
|
+static void m_can_read_fifo(struct net_device *dev, u32 rxfs)
|
|
|
{
|
|
|
+ struct net_device_stats *stats = &dev->stats;
|
|
|
struct m_can_priv *priv = netdev_priv(dev);
|
|
|
- u32 id, fgi;
|
|
|
+ struct canfd_frame *cf;
|
|
|
+ struct sk_buff *skb;
|
|
|
+ u32 id, fgi, dlc;
|
|
|
+ int i;
|
|
|
|
|
|
/* calculate the fifo get index for where to read data */
|
|
|
fgi = (rxfs & RXFS_FGI_MASK) >> RXFS_FGI_OFF;
|
|
|
+ dlc = m_can_fifo_read(priv, fgi, M_CAN_FIFO_DLC);
|
|
|
+ if (dlc & RX_BUF_EDL)
|
|
|
+ skb = alloc_canfd_skb(dev, &cf);
|
|
|
+ else
|
|
|
+ skb = alloc_can_skb(dev, (struct can_frame **)&cf);
|
|
|
+ if (!skb) {
|
|
|
+ stats->rx_dropped++;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dlc & RX_BUF_EDL)
|
|
|
+ cf->len = can_dlc2len((dlc >> 16) & 0x0F);
|
|
|
+ else
|
|
|
+ cf->len = get_can_dlc((dlc >> 16) & 0x0F);
|
|
|
+
|
|
|
id = m_can_fifo_read(priv, fgi, M_CAN_FIFO_ID);
|
|
|
if (id & RX_BUF_XTD)
|
|
|
cf->can_id = (id & CAN_EFF_MASK) | CAN_EFF_FLAG;
|
|
|
else
|
|
|
cf->can_id = (id >> 18) & CAN_SFF_MASK;
|
|
|
|
|
|
- if (id & RX_BUF_RTR) {
|
|
|
+ if (id & RX_BUF_ESI) {
|
|
|
+ cf->flags |= CANFD_ESI;
|
|
|
+ netdev_dbg(dev, "ESI Error\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!(dlc & RX_BUF_EDL) && (id & RX_BUF_RTR)) {
|
|
|
cf->can_id |= CAN_RTR_FLAG;
|
|
|
} else {
|
|
|
- id = m_can_fifo_read(priv, fgi, M_CAN_FIFO_DLC);
|
|
|
- cf->can_dlc = get_can_dlc((id >> 16) & 0x0F);
|
|
|
- *(u32 *)(cf->data + 0) = m_can_fifo_read(priv, fgi,
|
|
|
- M_CAN_FIFO_DATA(0));
|
|
|
- *(u32 *)(cf->data + 4) = m_can_fifo_read(priv, fgi,
|
|
|
- M_CAN_FIFO_DATA(1));
|
|
|
+ if (dlc & RX_BUF_BRS)
|
|
|
+ cf->flags |= CANFD_BRS;
|
|
|
+
|
|
|
+ for (i = 0; i < cf->len; i += 4)
|
|
|
+ *(u32 *)(cf->data + i) =
|
|
|
+ m_can_fifo_read(priv, fgi,
|
|
|
+ M_CAN_FIFO_DATA(i / 4));
|
|
|
}
|
|
|
|
|
|
/* acknowledge rx fifo 0 */
|
|
|
m_can_write(priv, M_CAN_RXF0A, fgi);
|
|
|
+
|
|
|
+ stats->rx_packets++;
|
|
|
+ stats->rx_bytes += cf->len;
|
|
|
+
|
|
|
+ netif_receive_skb(skb);
|
|
|
}
|
|
|
|
|
|
static int m_can_do_rx_poll(struct net_device *dev, int quota)
|
|
|
{
|
|
|
struct m_can_priv *priv = netdev_priv(dev);
|
|
|
- struct net_device_stats *stats = &dev->stats;
|
|
|
- struct sk_buff *skb;
|
|
|
- struct can_frame *frame;
|
|
|
u32 pkts = 0;
|
|
|
u32 rxfs;
|
|
|
|
|
@@ -374,18 +431,7 @@ static int m_can_do_rx_poll(struct net_device *dev, int quota)
|
|
|
if (rxfs & RXFS_RFL)
|
|
|
netdev_warn(dev, "Rx FIFO 0 Message Lost\n");
|
|
|
|
|
|
- skb = alloc_can_skb(dev, &frame);
|
|
|
- if (!skb) {
|
|
|
- stats->rx_dropped++;
|
|
|
- return pkts;
|
|
|
- }
|
|
|
-
|
|
|
- m_can_read_fifo(dev, frame, rxfs);
|
|
|
-
|
|
|
- stats->rx_packets++;
|
|
|
- stats->rx_bytes += frame->can_dlc;
|
|
|
-
|
|
|
- netif_receive_skb(skb);
|
|
|
+ m_can_read_fifo(dev, rxfs);
|
|
|
|
|
|
quota--;
|
|
|
pkts++;
|
|
@@ -481,11 +527,23 @@ static int m_can_handle_lec_err(struct net_device *dev,
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
+static int __m_can_get_berr_counter(const struct net_device *dev,
|
|
|
+ struct can_berr_counter *bec)
|
|
|
+{
|
|
|
+ struct m_can_priv *priv = netdev_priv(dev);
|
|
|
+ unsigned int ecr;
|
|
|
+
|
|
|
+ ecr = m_can_read(priv, M_CAN_ECR);
|
|
|
+ bec->rxerr = (ecr & ECR_REC_MASK) >> ECR_REC_SHIFT;
|
|
|
+ bec->txerr = ecr & ECR_TEC_MASK;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int m_can_get_berr_counter(const struct net_device *dev,
|
|
|
struct can_berr_counter *bec)
|
|
|
{
|
|
|
struct m_can_priv *priv = netdev_priv(dev);
|
|
|
- unsigned int ecr;
|
|
|
int err;
|
|
|
|
|
|
err = clk_prepare_enable(priv->hclk);
|
|
@@ -498,9 +556,7 @@ static int m_can_get_berr_counter(const struct net_device *dev,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
- ecr = m_can_read(priv, M_CAN_ECR);
|
|
|
- bec->rxerr = (ecr & ECR_REC_MASK) >> ECR_REC_SHIFT;
|
|
|
- bec->txerr = ecr & ECR_TEC_MASK;
|
|
|
+ __m_can_get_berr_counter(dev, bec);
|
|
|
|
|
|
clk_disable_unprepare(priv->cclk);
|
|
|
clk_disable_unprepare(priv->hclk);
|
|
@@ -544,7 +600,7 @@ static int m_can_handle_state_change(struct net_device *dev,
|
|
|
if (unlikely(!skb))
|
|
|
return 0;
|
|
|
|
|
|
- m_can_get_berr_counter(dev, &bec);
|
|
|
+ __m_can_get_berr_counter(dev, &bec);
|
|
|
|
|
|
switch (new_state) {
|
|
|
case CAN_STATE_ERROR_ACTIVE:
|
|
@@ -596,14 +652,14 @@ static int m_can_handle_state_errors(struct net_device *dev, u32 psr)
|
|
|
|
|
|
if ((psr & PSR_EP) &&
|
|
|
(priv->can.state != CAN_STATE_ERROR_PASSIVE)) {
|
|
|
- netdev_dbg(dev, "entered error warning state\n");
|
|
|
+ netdev_dbg(dev, "entered error passive state\n");
|
|
|
work_done += m_can_handle_state_change(dev,
|
|
|
CAN_STATE_ERROR_PASSIVE);
|
|
|
}
|
|
|
|
|
|
if ((psr & PSR_BO) &&
|
|
|
(priv->can.state != CAN_STATE_BUS_OFF)) {
|
|
|
- netdev_dbg(dev, "entered error warning state\n");
|
|
|
+ netdev_dbg(dev, "entered error bus off state\n");
|
|
|
work_done += m_can_handle_state_change(dev,
|
|
|
CAN_STATE_BUS_OFF);
|
|
|
}
|
|
@@ -615,7 +671,7 @@ static void m_can_handle_other_err(struct net_device *dev, u32 irqstatus)
|
|
|
{
|
|
|
if (irqstatus & IR_WDI)
|
|
|
netdev_err(dev, "Message RAM Watchdog event due to missing READY\n");
|
|
|
- if (irqstatus & IR_BEU)
|
|
|
+ if (irqstatus & IR_ELO)
|
|
|
netdev_err(dev, "Error Logging Overflow\n");
|
|
|
if (irqstatus & IR_BEU)
|
|
|
netdev_err(dev, "Bit Error Uncorrected\n");
|
|
@@ -733,10 +789,23 @@ static const struct can_bittiming_const m_can_bittiming_const = {
|
|
|
.brp_inc = 1,
|
|
|
};
|
|
|
|
|
|
+static const struct can_bittiming_const m_can_data_bittiming_const = {
|
|
|
+ .name = KBUILD_MODNAME,
|
|
|
+ .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */
|
|
|
+ .tseg1_max = 16,
|
|
|
+ .tseg2_min = 1, /* Time segment 2 = phase_seg2 */
|
|
|
+ .tseg2_max = 8,
|
|
|
+ .sjw_max = 4,
|
|
|
+ .brp_min = 1,
|
|
|
+ .brp_max = 32,
|
|
|
+ .brp_inc = 1,
|
|
|
+};
|
|
|
+
|
|
|
static int m_can_set_bittiming(struct net_device *dev)
|
|
|
{
|
|
|
struct m_can_priv *priv = netdev_priv(dev);
|
|
|
const struct can_bittiming *bt = &priv->can.bittiming;
|
|
|
+ const struct can_bittiming *dbt = &priv->can.data_bittiming;
|
|
|
u16 brp, sjw, tseg1, tseg2;
|
|
|
u32 reg_btp;
|
|
|
|
|
@@ -747,7 +816,17 @@ static int m_can_set_bittiming(struct net_device *dev)
|
|
|
reg_btp = (brp << BTR_BRP_SHIFT) | (sjw << BTR_SJW_SHIFT) |
|
|
|
(tseg1 << BTR_TSEG1_SHIFT) | (tseg2 << BTR_TSEG2_SHIFT);
|
|
|
m_can_write(priv, M_CAN_BTP, reg_btp);
|
|
|
- netdev_dbg(dev, "setting BTP 0x%x\n", reg_btp);
|
|
|
+
|
|
|
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
|
|
|
+ brp = dbt->brp - 1;
|
|
|
+ sjw = dbt->sjw - 1;
|
|
|
+ tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
|
|
|
+ tseg2 = dbt->phase_seg2 - 1;
|
|
|
+ reg_btp = (brp << FBTR_FBRP_SHIFT) | (sjw << FBTR_FSJW_SHIFT) |
|
|
|
+ (tseg1 << FBTR_FTSEG1_SHIFT) |
|
|
|
+ (tseg2 << FBTR_FTSEG2_SHIFT);
|
|
|
+ m_can_write(priv, M_CAN_FBTP, reg_btp);
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -767,8 +846,8 @@ static void m_can_chip_config(struct net_device *dev)
|
|
|
|
|
|
m_can_config_endisable(priv, true);
|
|
|
|
|
|
- /* RX Buffer/FIFO Element Size 8 bytes data field */
|
|
|
- m_can_write(priv, M_CAN_RXESC, M_CAN_RXESC_8BYTES);
|
|
|
+ /* RX Buffer/FIFO Element Size 64 bytes data field */
|
|
|
+ m_can_write(priv, M_CAN_RXESC, M_CAN_RXESC_64BYTES);
|
|
|
|
|
|
/* Accept Non-matching Frames Into FIFO 0 */
|
|
|
m_can_write(priv, M_CAN_GFC, 0x0);
|
|
@@ -777,8 +856,8 @@ static void m_can_chip_config(struct net_device *dev)
|
|
|
m_can_write(priv, M_CAN_TXBC, (1 << TXBC_NDTB_OFF) |
|
|
|
priv->mcfg[MRAM_TXB].off);
|
|
|
|
|
|
- /* only support 8 bytes firstly */
|
|
|
- m_can_write(priv, M_CAN_TXESC, TXESC_TBDS_8BYTES);
|
|
|
+ /* support 64 bytes payload */
|
|
|
+ m_can_write(priv, M_CAN_TXESC, TXESC_TBDS_64BYTES);
|
|
|
|
|
|
m_can_write(priv, M_CAN_TXEFC, (1 << TXEFC_EFS_OFF) |
|
|
|
priv->mcfg[MRAM_TXE].off);
|
|
@@ -793,7 +872,8 @@ static void m_can_chip_config(struct net_device *dev)
|
|
|
RXFC_FWM_1 | priv->mcfg[MRAM_RXF1].off);
|
|
|
|
|
|
cccr = m_can_read(priv, M_CAN_CCCR);
|
|
|
- cccr &= ~(CCCR_TEST | CCCR_MON);
|
|
|
+ cccr &= ~(CCCR_TEST | CCCR_MON | (CCCR_CMR_MASK << CCCR_CMR_SHIFT) |
|
|
|
+ (CCCR_CME_MASK << CCCR_CME_SHIFT));
|
|
|
test = m_can_read(priv, M_CAN_TEST);
|
|
|
test &= ~TEST_LBCK;
|
|
|
|
|
@@ -805,6 +885,9 @@ static void m_can_chip_config(struct net_device *dev)
|
|
|
test |= TEST_LBCK;
|
|
|
}
|
|
|
|
|
|
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
|
|
|
+ cccr |= CCCR_CME_CANFD_BRS << CCCR_CME_SHIFT;
|
|
|
+
|
|
|
m_can_write(priv, M_CAN_CCCR, cccr);
|
|
|
m_can_write(priv, M_CAN_TEST, test);
|
|
|
|
|
@@ -869,11 +952,13 @@ static struct net_device *alloc_m_can_dev(void)
|
|
|
|
|
|
priv->dev = dev;
|
|
|
priv->can.bittiming_const = &m_can_bittiming_const;
|
|
|
+ priv->can.data_bittiming_const = &m_can_data_bittiming_const;
|
|
|
priv->can.do_set_mode = m_can_set_mode;
|
|
|
priv->can.do_get_berr_counter = m_can_get_berr_counter;
|
|
|
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
|
|
|
CAN_CTRLMODE_LISTENONLY |
|
|
|
- CAN_CTRLMODE_BERR_REPORTING;
|
|
|
+ CAN_CTRLMODE_BERR_REPORTING |
|
|
|
+ CAN_CTRLMODE_FD;
|
|
|
|
|
|
return dev;
|
|
|
}
|
|
@@ -956,8 +1041,9 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
|
|
|
struct net_device *dev)
|
|
|
{
|
|
|
struct m_can_priv *priv = netdev_priv(dev);
|
|
|
- struct can_frame *cf = (struct can_frame *)skb->data;
|
|
|
- u32 id;
|
|
|
+ struct canfd_frame *cf = (struct canfd_frame *)skb->data;
|
|
|
+ u32 id, cccr;
|
|
|
+ int i;
|
|
|
|
|
|
if (can_dropped_invalid_skb(dev, skb))
|
|
|
return NETDEV_TX_OK;
|
|
@@ -976,11 +1062,28 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
|
|
|
|
|
|
/* message ram configuration */
|
|
|
m_can_fifo_write(priv, 0, M_CAN_FIFO_ID, id);
|
|
|
- m_can_fifo_write(priv, 0, M_CAN_FIFO_DLC, cf->can_dlc << 16);
|
|
|
- m_can_fifo_write(priv, 0, M_CAN_FIFO_DATA(0), *(u32 *)(cf->data + 0));
|
|
|
- m_can_fifo_write(priv, 0, M_CAN_FIFO_DATA(1), *(u32 *)(cf->data + 4));
|
|
|
+ m_can_fifo_write(priv, 0, M_CAN_FIFO_DLC, can_len2dlc(cf->len) << 16);
|
|
|
+
|
|
|
+ for (i = 0; i < cf->len; i += 4)
|
|
|
+ m_can_fifo_write(priv, 0, M_CAN_FIFO_DATA(i / 4),
|
|
|
+ *(u32 *)(cf->data + i));
|
|
|
+
|
|
|
can_put_echo_skb(skb, dev, 0);
|
|
|
|
|
|
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
|
|
|
+ cccr = m_can_read(priv, M_CAN_CCCR);
|
|
|
+ cccr &= ~(CCCR_CMR_MASK << CCCR_CMR_SHIFT);
|
|
|
+ if (can_is_canfd_skb(skb)) {
|
|
|
+ if (cf->flags & CANFD_BRS)
|
|
|
+ cccr |= CCCR_CMR_CANFD_BRS << CCCR_CMR_SHIFT;
|
|
|
+ else
|
|
|
+ cccr |= CCCR_CMR_CANFD << CCCR_CMR_SHIFT;
|
|
|
+ } else {
|
|
|
+ cccr |= CCCR_CMR_CAN << CCCR_CMR_SHIFT;
|
|
|
+ }
|
|
|
+ m_can_write(priv, M_CAN_CCCR, cccr);
|
|
|
+ }
|
|
|
+
|
|
|
/* enable first TX buffer to start transfer */
|
|
|
m_can_write(priv, M_CAN_TXBTIE, 0x1);
|
|
|
m_can_write(priv, M_CAN_TXBAR, 0x1);
|
|
@@ -992,6 +1095,7 @@ static const struct net_device_ops m_can_netdev_ops = {
|
|
|
.ndo_open = m_can_open,
|
|
|
.ndo_stop = m_can_close,
|
|
|
.ndo_start_xmit = m_can_start_xmit,
|
|
|
+ .ndo_change_mtu = can_change_mtu,
|
|
|
};
|
|
|
|
|
|
static int register_m_can_dev(struct net_device *dev)
|
|
@@ -1009,7 +1113,7 @@ static int m_can_of_parse_mram(struct platform_device *pdev,
|
|
|
struct resource *res;
|
|
|
void __iomem *addr;
|
|
|
u32 out_val[MRAM_CFG_LEN];
|
|
|
- int ret;
|
|
|
+ int i, start, end, ret;
|
|
|
|
|
|
/* message ram could be shared */
|
|
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
|
|
@@ -1060,6 +1164,15 @@ static int m_can_of_parse_mram(struct platform_device *pdev,
|
|
|
priv->mcfg[MRAM_TXE].off, priv->mcfg[MRAM_TXE].num,
|
|
|
priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num);
|
|
|
|
|
|
+ /* initialize the entire Message RAM in use to avoid possible
|
|
|
+ * ECC/parity checksum errors when reading an uninitialized buffer
|
|
|
+ */
|
|
|
+ start = priv->mcfg[MRAM_SIDF].off;
|
|
|
+ end = priv->mcfg[MRAM_TXB].off +
|
|
|
+ priv->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE;
|
|
|
+ for (i = start; i < end; i += 4)
|
|
|
+ writel(0x0, priv->mram_base + i);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|