mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-18 19:20:37 +02:00
765 lines
20 KiB
Diff
765 lines
20 KiB
Diff
|
From c3b97e08b06be76ee9f2b410b13c045425fc7f3e Mon Sep 17 00:00:00 2001
|
||
|
From: Jingchang Lu <b35083@freescale.com>
|
||
|
Date: Thu, 4 Aug 2011 09:59:48 +0800
|
||
|
Subject: [PATCH 36/52] Add FlexCAN support on ColdFire M548X, M54418 platform
|
||
|
|
||
|
Each cpu core has two FlexCAN interface, and the M54418's FlexCAN
|
||
|
also support Rx message buffer FIFO mode but M548X not.
|
||
|
|
||
|
Signed-off-by: Jingchang Lu <b35083@freescale.com>
|
||
|
---
|
||
|
arch/m68k/Kconfig | 2 +
|
||
|
arch/m68k/coldfire/m5441x/Makefile | 4 +
|
||
|
arch/m68k/coldfire/m5441x/mcf-flexcan.c | 121 ++++++++++++++++
|
||
|
arch/m68k/coldfire/m547x/Makefile | 3 +
|
||
|
arch/m68k/coldfire/m547x/mcf-flexcan.c | 117 +++++++++++++++
|
||
|
drivers/net/can/Kconfig | 9 ++
|
||
|
drivers/net/can/flexcan.c | 239 ++++++++++++++++++++++++++++++-
|
||
|
7 files changed, 489 insertions(+), 6 deletions(-)
|
||
|
create mode 100644 arch/m68k/coldfire/m5441x/mcf-flexcan.c
|
||
|
create mode 100644 arch/m68k/coldfire/m547x/mcf-flexcan.c
|
||
|
|
||
|
--- a/arch/m68k/Kconfig
|
||
|
+++ b/arch/m68k/Kconfig
|
||
|
@@ -372,6 +372,7 @@ config M547X
|
||
|
config M548X
|
||
|
bool
|
||
|
depends on M547X_8X
|
||
|
+ select HAVE_CAN_FLEXCAN
|
||
|
default n
|
||
|
|
||
|
choice
|
||
|
@@ -430,6 +431,7 @@ config M5441X
|
||
|
select GENERIC_TIME
|
||
|
select USB_EHCI_FSL
|
||
|
select HAVE_FSL_USB_DR
|
||
|
+ select HAVE_CAN_FLEXCAN
|
||
|
help
|
||
|
This option will add support for the MCF5441x processor with mmu.
|
||
|
|
||
|
--- a/arch/m68k/coldfire/m5441x/Makefile
|
||
|
+++ b/arch/m68k/coldfire/m5441x/Makefile
|
||
|
@@ -36,3 +36,7 @@ endif
|
||
|
ifneq ($(CONFIG_MODELO_SWITCH),)
|
||
|
obj-y += l2switch.o
|
||
|
endif
|
||
|
+
|
||
|
+ifneq ($(CONFIG_CAN_FLEXCAN),)
|
||
|
+obj-y += mcf-flexcan.o
|
||
|
+endif
|
||
|
--- /dev/null
|
||
|
+++ b/arch/m68k/coldfire/m5441x/mcf-flexcan.c
|
||
|
@@ -0,0 +1,121 @@
|
||
|
+/*
|
||
|
+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved.
|
||
|
+ *
|
||
|
+ * Author: Huan Wang, b18965@freescale.com, Fri Aug 08 2008
|
||
|
+ *
|
||
|
+ * Description:
|
||
|
+ * CAN bus driver for Freescale Coldfire embedded CPU
|
||
|
+ *
|
||
|
+ * Changelog:
|
||
|
+ * Fri Aug 08 2008 Huan Wang <b18965@freescale.com>
|
||
|
+ * - create, support for MCF548x
|
||
|
+ *
|
||
|
+ * Tue Dec 08 2009 ChengJu Cai <b22600@freescale.com>
|
||
|
+ * - support for MCF532x MCF5253 MCF5227x
|
||
|
+ *
|
||
|
+ * July 2011 Jingchang.Lu <b35083@freescale.com>
|
||
|
+ * - Add into kernel CAN driver layer
|
||
|
+ *
|
||
|
+ * This file is part of the Linux kernel
|
||
|
+ * This is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License as published by
|
||
|
+ * the Free Software Foundation; either version 2 of the License, or
|
||
|
+ * (at your option) any later version.
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+#include <linux/kernel.h>
|
||
|
+#include <linux/module.h>
|
||
|
+#include <linux/interrupt.h>
|
||
|
+#include <linux/platform_device.h>
|
||
|
+#include <asm/mcfsim.h>
|
||
|
+
|
||
|
+
|
||
|
+static struct resource mcf5441x_can0_resources[] = {
|
||
|
+ [0] = {
|
||
|
+ .start = 0xFC020000,
|
||
|
+ .end = 0xFC0208C0,
|
||
|
+ .flags = IORESOURCE_MEM,
|
||
|
+ },
|
||
|
+ [1] = {
|
||
|
+ .start = 0 + 64 + 64,
|
||
|
+ .end = 0 + 64 + 64,
|
||
|
+ .flags = IORESOURCE_IRQ,
|
||
|
+ },
|
||
|
+};
|
||
|
+
|
||
|
+static struct resource mcf5441x_can1_resources[] = {
|
||
|
+ [0] = {
|
||
|
+ .start = 0xFC024000,
|
||
|
+ .end = 0xFC0248C0,
|
||
|
+ .flags = IORESOURCE_MEM,
|
||
|
+ },
|
||
|
+ [1] = {
|
||
|
+ .start = 4 + 64 + 64,
|
||
|
+ .end = 4 + 64 + 64,
|
||
|
+ .flags = IORESOURCE_IRQ,
|
||
|
+ },
|
||
|
+};
|
||
|
+
|
||
|
+static struct platform_device mcf_flexcan[PDEV_MAX] = {
|
||
|
+ [0] = {
|
||
|
+ .name = "flexcan",
|
||
|
+ .id = 0,
|
||
|
+ .num_resources = ARRAY_SIZE(mcf5441x_can0_resources),
|
||
|
+ .resource = mcf5441x_can0_resources,
|
||
|
+ },
|
||
|
+ [1] = {
|
||
|
+ .name = "flexcan",
|
||
|
+ .id = 1,
|
||
|
+ .num_resources = ARRAY_SIZE(mcf5441x_can1_resources),
|
||
|
+ .resource = mcf5441x_can1_resources,
|
||
|
+ },
|
||
|
+
|
||
|
+};
|
||
|
+
|
||
|
+
|
||
|
+static void __init mcf_flexcan_config(void)
|
||
|
+{
|
||
|
+ MCF_PM_PPMCR0 = 8; /* enable FlexCAN0 clock */
|
||
|
+ MCF_PM_PPMCR0 = 9; /* enable FlexCAN1 clock */
|
||
|
+
|
||
|
+ /* CAN0 */
|
||
|
+ MCF_GPIO_PAR_CANI2C =
|
||
|
+ (MCF_GPIO_PAR_CANI2C & MCF_GPIO_PAR_CANI2C_I2C0SCL_MASK) |
|
||
|
+ MCF_GPIO_PAR_CANI2C_I2C0SCL_CAN0TX;
|
||
|
+ MCF_GPIO_PAR_CANI2C =
|
||
|
+ (MCF_GPIO_PAR_CANI2C & MCF_GPIO_PAR_CANI2C_I2C0SDA_MASK) |
|
||
|
+ MCF_GPIO_PAR_CANI2C_I2C0SDA_CAN0RX;
|
||
|
+ /* CAN1 */
|
||
|
+ MCF_GPIO_PAR_CANI2C =
|
||
|
+ (MCF_GPIO_PAR_CANI2C & MCF_GPIO_PAR_CANI2C_CAN1TX_MASK) |
|
||
|
+ MCF_GPIO_PAR_CANI2C_CAN1TX_CAN1TX;
|
||
|
+ MCF_GPIO_PAR_CANI2C =
|
||
|
+ (MCF_GPIO_PAR_CANI2C & MCF_GPIO_PAR_CANI2C_CAN1RX_MASK) |
|
||
|
+ MCF_GPIO_PAR_CANI2C_CAN1RX_CAN1RX;
|
||
|
+
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+static int __init flexcan_of_to_pdev(void)
|
||
|
+{
|
||
|
+ int i, err = -ENODEV;
|
||
|
+ for (i = 0; i < PDEV_MAX; i++) {
|
||
|
+ err = platform_device_register(&mcf_flexcan[i]);
|
||
|
+ if (err)
|
||
|
+ return err;
|
||
|
+ printk(KERN_INFO "ColdFire FlexCAN devices loaded\n");
|
||
|
+ }
|
||
|
+ return err;
|
||
|
+}
|
||
|
+
|
||
|
+static int __init mcf_flexcan_init(void)
|
||
|
+{
|
||
|
+ int err;
|
||
|
+ mcf_flexcan_config();
|
||
|
+ err = flexcan_of_to_pdev();
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+arch_initcall(mcf_flexcan_init);
|
||
|
--- a/arch/m68k/coldfire/m547x/Makefile
|
||
|
+++ b/arch/m68k/coldfire/m547x/Makefile
|
||
|
@@ -5,3 +5,6 @@
|
||
|
obj-$(CONFIG_M547X_8X) += config.o mcf548x-devices.o devices.o
|
||
|
obj-$(CONFIG_PCI) += pci.o pci_dummy.o
|
||
|
obj-$(CONFIG_MCD_DMA) += dma.o
|
||
|
+ifneq ($(CONFIG_CAN_FLEXCAN),)
|
||
|
+obj-y += mcf-flexcan.o
|
||
|
+endif
|
||
|
--- /dev/null
|
||
|
+++ b/arch/m68k/coldfire/m547x/mcf-flexcan.c
|
||
|
@@ -0,0 +1,117 @@
|
||
|
+/*
|
||
|
+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved.
|
||
|
+ *
|
||
|
+ * Author: Huan Wang, b18965@freescale.com, Fri Aug 08 2008
|
||
|
+ *
|
||
|
+ * Description:
|
||
|
+ * CAN bus driver for Freescale Coldfire embedded CPU
|
||
|
+ *
|
||
|
+ * Changelog:
|
||
|
+ * Fri Aug 08 2008 Huan Wang <b18965@freescale.com>
|
||
|
+ * - create, support for MCF548x
|
||
|
+ *
|
||
|
+ * Tue Dec 08 2009 ChengJu Cai <b22600@freescale.com>
|
||
|
+ * - support for MCF532x MCF5253 MCF5227x
|
||
|
+ *
|
||
|
+ * July 2011 Jingchang.Lu <b35083@freescale.com>
|
||
|
+ * - Add into kernel CAN driver layer
|
||
|
+ *
|
||
|
+ * This file is part of the Linux kernel
|
||
|
+ * This is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License as published by
|
||
|
+ * the Free Software Foundation; either version 2 of the License, or
|
||
|
+ * (at your option) any later version.
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+#include <linux/kernel.h>
|
||
|
+#include <linux/module.h>
|
||
|
+#include <linux/interrupt.h>
|
||
|
+#include <linux/platform_device.h>
|
||
|
+#include <asm/mcfsim.h>
|
||
|
+
|
||
|
+
|
||
|
+static struct resource mcf548x_can0_resources[] = {
|
||
|
+ [0] = {
|
||
|
+ .start = MCF_MBAR + 0x0000A000,
|
||
|
+ .end = MCF_MBAR + 0x0000A7FF,
|
||
|
+ .flags = IORESOURCE_MEM,
|
||
|
+ },
|
||
|
+ [1] = {
|
||
|
+ .start = 49 + 64,
|
||
|
+ .end = 49 + 64,
|
||
|
+ .flags = IORESOURCE_IRQ,
|
||
|
+ },
|
||
|
+};
|
||
|
+
|
||
|
+static struct resource mcf548x_can1_resources[] = {
|
||
|
+ [0] = {
|
||
|
+ .start = MCF_MBAR + 0x0000A800,
|
||
|
+ .end = MCF_MBAR + 0x0000AFFF,
|
||
|
+ .flags = IORESOURCE_MEM,
|
||
|
+ },
|
||
|
+ [1] = {
|
||
|
+ .start = 55 + 64,
|
||
|
+ .end = 55 + 64,
|
||
|
+ .flags = IORESOURCE_IRQ,
|
||
|
+ },
|
||
|
+};
|
||
|
+
|
||
|
+static struct platform_device mcf_flexcan[PDEV_MAX] = {
|
||
|
+ [0] = {
|
||
|
+ .name = "flexcan",
|
||
|
+ .id = 0,
|
||
|
+ .num_resources = ARRAY_SIZE(mcf548x_can1_resources),
|
||
|
+ .resource = mcf548x_can0_resources,
|
||
|
+ },
|
||
|
+ [1] = {
|
||
|
+ .name = "flexcan",
|
||
|
+ .id = 1,
|
||
|
+ .num_resources = ARRAY_SIZE(mcf548x_can1_resources),
|
||
|
+ .resource = mcf548x_can1_resources,
|
||
|
+ },
|
||
|
+
|
||
|
+};
|
||
|
+
|
||
|
+
|
||
|
+static void __init mcf_flexcan_config(void)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+ MCF_PAR_TIMER = MCF_PAR_TIMER | 0x28;
|
||
|
+ MCF_PAR_TIMER = MCF_PAR_TIMER & 0xf8;
|
||
|
+ MCF_PAR_DSPI = MCF_PAR_DSPI | 0x0a00;
|
||
|
+ MCF_PAR_FECI2CIRQ = MCF_PAR_FECI2CIRQ | 0x0283;
|
||
|
+ MCF_PAR_PSCn(2) = MCF_PAR_PSCn(2) & 0x0f;
|
||
|
+ MCF_PAR_PSCn(2) = MCF_PAR_PSCn(2) | 0x50;
|
||
|
+
|
||
|
+ for (i = 0; i < 2; i++) {
|
||
|
+ MCF_ICR(ISC_CANn_MBOR(i)) = 0x33 + 0x01 * i;
|
||
|
+ MCF_ICR(ISC_CANn_ERR(i)) = 0x33 + 0x01 * i;
|
||
|
+ MCF_ICR(ISC_CANn_BUSOFF(i)) = 0x33 + 0x01 * i;
|
||
|
+ }
|
||
|
+
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+static int __init flexcan_of_to_pdev(void)
|
||
|
+{
|
||
|
+ int i, err = -ENODEV;
|
||
|
+ for (i = 0; i < PDEV_MAX; i++) {
|
||
|
+ err = platform_device_register(&mcf_flexcan[i]);
|
||
|
+ if (err)
|
||
|
+ return err;
|
||
|
+ printk(KERN_INFO "ColdFire FlexCAN devices loaded\n");
|
||
|
+ }
|
||
|
+ return err;
|
||
|
+}
|
||
|
+
|
||
|
+static int __init mcf_flexcan_init(void)
|
||
|
+{
|
||
|
+ int err;
|
||
|
+ mcf_flexcan_config();
|
||
|
+ err = flexcan_of_to_pdev();
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+arch_initcall(mcf_flexcan_init);
|
||
|
--- a/drivers/net/can/Kconfig
|
||
|
+++ b/drivers/net/can/Kconfig
|
||
|
@@ -103,6 +103,15 @@ config CAN_FLEXCAN
|
||
|
---help---
|
||
|
Say Y here if you want to support for Freescale FlexCAN.
|
||
|
|
||
|
+config FLEXCAN_NORXFIFO
|
||
|
+ bool "FlexCAN message buffer without Rx FIFO mode"
|
||
|
+ depends on CAN_FLEXCAN && COLDFIRE
|
||
|
+ default n
|
||
|
+ ---help---
|
||
|
+ Say Y here if you FlexCAN message buffer has no Rx FIFO mode.
|
||
|
+ Freescale Coldfire series have different FlexCAN core version,
|
||
|
+ MCF54418's support Rx FIFO mode while others such as MCF5485 not.
|
||
|
+
|
||
|
config PCH_CAN
|
||
|
tristate "PCH CAN"
|
||
|
depends on CAN_DEV && PCI
|
||
|
--- a/drivers/net/can/flexcan.c
|
||
|
+++ b/drivers/net/can/flexcan.c
|
||
|
@@ -4,6 +4,7 @@
|
||
|
* Copyright (c) 2005-2006 Varma Electronics Oy
|
||
|
* Copyright (c) 2009 Sascha Hauer, Pengutronix
|
||
|
* Copyright (c) 2010 Marc Kleine-Budde, Pengutronix
|
||
|
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
|
||
|
*
|
||
|
* Based on code originally by Andrey Volkov <avolkov@varma-el.com>
|
||
|
*
|
||
|
@@ -35,8 +36,28 @@
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/platform_device.h>
|
||
|
|
||
|
+#ifndef CONFIG_COLDFIRE
|
||
|
#include <mach/clock.h>
|
||
|
|
||
|
+#else
|
||
|
+#include <asm/mcfsim.h>
|
||
|
+
|
||
|
+#undef readb
|
||
|
+#undef readw
|
||
|
+#undef readl
|
||
|
+#define readb(addr) __raw_readb(addr)
|
||
|
+#define readw(addr) __raw_readw(addr)
|
||
|
+#define readl(addr) __raw_readl(addr)
|
||
|
+
|
||
|
+#undef writeb
|
||
|
+#undef writew
|
||
|
+#undef writel
|
||
|
+#define writeb(b, addr) __raw_writeb(b, addr)
|
||
|
+#define writew(b, addr) __raw_writew(b, addr)
|
||
|
+#define writel(b, addr) __raw_writel(b, addr)
|
||
|
+
|
||
|
+#endif
|
||
|
+
|
||
|
#define DRV_NAME "flexcan"
|
||
|
|
||
|
/* 8 for RX fifo and 2 error handling */
|
||
|
@@ -85,12 +106,34 @@
|
||
|
#define FLEXCAN_CTRL_LOM BIT(3)
|
||
|
#define FLEXCAN_CTRL_PROPSEG(x) ((x) & 0x07)
|
||
|
#define FLEXCAN_CTRL_ERR_BUS (FLEXCAN_CTRL_ERR_MSK)
|
||
|
+
|
||
|
+#ifdef CONFIG_COLDFIRE
|
||
|
+
|
||
|
+# if defined(CONFIG_M548X)
|
||
|
+
|
||
|
+#define FLEXCAN_CTRL_ERR_STATE FLEXCAN_CTRL_BOFF_MSK
|
||
|
+#define FLEXCAN_CTRL_ERR_ALL \
|
||
|
+ (FLEXCAN_CTRL_BOFF_MSK | FLEXCAN_CTRL_ERR_MSK)
|
||
|
+
|
||
|
+# elif defined(CONFIG_M5441X)
|
||
|
+
|
||
|
#define FLEXCAN_CTRL_ERR_STATE \
|
||
|
(FLEXCAN_CTRL_TWRN_MSK | FLEXCAN_CTRL_RWRN_MSK | \
|
||
|
FLEXCAN_CTRL_BOFF_MSK)
|
||
|
#define FLEXCAN_CTRL_ERR_ALL \
|
||
|
(FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE)
|
||
|
|
||
|
+# endif
|
||
|
+
|
||
|
+#else /* !CONFIG_COLDFIRE */
|
||
|
+
|
||
|
+#define FLEXCAN_CTRL_ERR_STATE \
|
||
|
+ (FLEXCAN_CTRL_TWRN_MSK | FLEXCAN_CTRL_RWRN_MSK | \
|
||
|
+ FLEXCAN_CTRL_BOFF_MSK)
|
||
|
+#define FLEXCAN_CTRL_ERR_ALL \
|
||
|
+ (FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE)
|
||
|
+
|
||
|
+#endif
|
||
|
/* FLEXCAN error and status register (ESR) bits */
|
||
|
#define FLEXCAN_ESR_TWRN_INT BIT(17)
|
||
|
#define FLEXCAN_ESR_RWRN_INT BIT(16)
|
||
|
@@ -121,6 +164,18 @@
|
||
|
(FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE)
|
||
|
|
||
|
/* FLEXCAN interrupt flag register (IFLAG) bits */
|
||
|
+
|
||
|
+#ifdef CONFIG_FLEXCAN_NORXFIFO
|
||
|
+
|
||
|
+/* MB assignment for no Rx FIFO mode module */
|
||
|
+#define FLEXCAN_TX_BUF_ID 0
|
||
|
+#define FLEXCAN_RX_EXT_ID 15
|
||
|
+#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE 0xfffe
|
||
|
+#define FLEXCAN_IFLAG_DEFAULT \
|
||
|
+ (FLEXCAN_IFLAG_RX_FIFO_AVAILABLE | (0x01 << FLEXCAN_TX_BUF_ID))
|
||
|
+
|
||
|
+#else
|
||
|
+
|
||
|
#define FLEXCAN_TX_BUF_ID 8
|
||
|
#define FLEXCAN_IFLAG_BUF(x) BIT(x)
|
||
|
#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7)
|
||
|
@@ -130,6 +185,7 @@
|
||
|
(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | FLEXCAN_IFLAG_RX_FIFO_AVAILABLE | \
|
||
|
FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID))
|
||
|
|
||
|
+#endif
|
||
|
/* FLEXCAN message buffers */
|
||
|
#define FLEXCAN_MB_CNT_CODE(x) (((x) & 0xf) << 24)
|
||
|
#define FLEXCAN_MB_CNT_SRR BIT(22)
|
||
|
@@ -163,7 +219,11 @@ struct flexcan_regs {
|
||
|
u32 iflag2; /* 0x2c */
|
||
|
u32 iflag1; /* 0x30 */
|
||
|
u32 _reserved2[19];
|
||
|
+#ifdef CONFIG_COLDFIRE
|
||
|
+ struct flexcan_mb cantxfg[CAN_MB];
|
||
|
+#else
|
||
|
struct flexcan_mb cantxfg[64];
|
||
|
+#endif
|
||
|
};
|
||
|
|
||
|
struct flexcan_priv {
|
||
|
@@ -181,8 +241,13 @@ struct flexcan_priv {
|
||
|
|
||
|
static struct can_bittiming_const flexcan_bittiming_const = {
|
||
|
.name = DRV_NAME,
|
||
|
+#ifdef CONFIG_COLDFIRE
|
||
|
+ .tseg1_min = 1,
|
||
|
+ .tseg1_max = 8,
|
||
|
+#else
|
||
|
.tseg1_min = 4,
|
||
|
.tseg1_max = 16,
|
||
|
+#endif
|
||
|
.tseg2_min = 2,
|
||
|
.tseg2_max = 8,
|
||
|
.sjw_max = 4,
|
||
|
@@ -248,7 +313,7 @@ static int flexcan_start_xmit(struct sk_
|
||
|
struct net_device_stats *stats = &dev->stats;
|
||
|
struct flexcan_regs __iomem *regs = priv->base;
|
||
|
struct can_frame *cf = (struct can_frame *)skb->data;
|
||
|
- u32 can_id;
|
||
|
+ u32 can_id, tmp, tmp1;
|
||
|
u32 ctrl = FLEXCAN_MB_CNT_CODE(0xc) | (cf->can_dlc << 16);
|
||
|
|
||
|
if (can_dropped_invalid_skb(dev, skb))
|
||
|
@@ -259,6 +324,11 @@ static int flexcan_start_xmit(struct sk_
|
||
|
if (cf->can_id & CAN_EFF_FLAG) {
|
||
|
can_id = cf->can_id & CAN_EFF_MASK;
|
||
|
ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR;
|
||
|
+#ifdef CONFIG_COLDFIRE
|
||
|
+ tmp = (can_id & CAN_SFF_MASK) << 18;
|
||
|
+ tmp1 = can_id >> 11;
|
||
|
+ can_id = tmp | tmp1;
|
||
|
+#endif
|
||
|
} else {
|
||
|
can_id = (cf->can_id & CAN_SFF_MASK) << 18;
|
||
|
}
|
||
|
@@ -456,6 +526,87 @@ static int flexcan_poll_state(struct net
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
+#ifdef CONFIG_FLEXCAN_NORXFIFO
|
||
|
+/* Get one frame from receive message buffer */
|
||
|
+static int flexcan_read_frame(struct net_device *dev)
|
||
|
+{
|
||
|
+ const struct flexcan_priv *priv = netdev_priv(dev);
|
||
|
+ struct flexcan_regs __iomem *regs = priv->base;
|
||
|
+ struct net_device_stats *stats = &dev->stats;
|
||
|
+ struct can_frame *cf;
|
||
|
+ struct sk_buff *skb;
|
||
|
+ struct flexcan_mb __iomem *mb;
|
||
|
+ u32 reg_iflag1, reg_ctrl, reg_id, i;
|
||
|
+
|
||
|
+ reg_iflag1 = readl(®s->iflag1);
|
||
|
+
|
||
|
+ /* buf[0] if for TX */
|
||
|
+ for (i = 0; i < CAN_MB; i++) {
|
||
|
+ if (i == FLEXCAN_TX_BUF_ID)
|
||
|
+ continue;
|
||
|
+ /* find one received message slot */
|
||
|
+ if (reg_iflag1 & (0x01 << i))
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (i >= CAN_MB)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ mb = ®s->cantxfg[i];
|
||
|
+
|
||
|
+ skb = alloc_can_skb(dev, &cf);
|
||
|
+ if (unlikely(!skb)) {
|
||
|
+ stats->rx_dropped++;
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ reg_ctrl = readl(&mb->can_ctrl);
|
||
|
+ reg_id = readl(&mb->can_id);
|
||
|
+
|
||
|
+ /* deactive RX buff */
|
||
|
+ writel(0, &mb->can_ctrl);
|
||
|
+
|
||
|
+ if (reg_ctrl & FLEXCAN_MB_CNT_IDE) {
|
||
|
+#ifdef CONFIG_COLDFIRE
|
||
|
+ /* Coldfire can_id order */
|
||
|
+ cf->can_id = (reg_id & CAN_EFF_MASK) >> 18;
|
||
|
+ cf->can_id |= (reg_id & 0x3ffff) << 11;
|
||
|
+ cf->can_id |= CAN_EFF_FLAG;
|
||
|
+#else
|
||
|
+ cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
|
||
|
+#endif
|
||
|
+ } else
|
||
|
+ cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
|
||
|
+
|
||
|
+ if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
|
||
|
+ cf->can_id |= CAN_RTR_FLAG;
|
||
|
+ cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
|
||
|
+
|
||
|
+ *(__be32 *)(cf->data + 0) = cpu_to_be32(readl(&mb->data[0]));
|
||
|
+ *(__be32 *)(cf->data + 4) = cpu_to_be32(readl(&mb->data[1]));
|
||
|
+
|
||
|
+ /* reactive RX buffer */
|
||
|
+ if (i == FLEXCAN_RX_EXT_ID)
|
||
|
+ writel(FLEXCAN_MB_CNT_CODE(0x4)|0x600000,
|
||
|
+ ®s->cantxfg[i].can_ctrl);
|
||
|
+ else
|
||
|
+ writel(FLEXCAN_MB_CNT_CODE(0x4),
|
||
|
+ ®s->cantxfg[i].can_ctrl);
|
||
|
+
|
||
|
+ /* mark as read */
|
||
|
+ writel((0x01 << i), ®s->iflag1);
|
||
|
+ /* release MB lock */
|
||
|
+ readl(®s->timer);
|
||
|
+
|
||
|
+ netif_receive_skb(skb);
|
||
|
+
|
||
|
+ stats->rx_packets++;
|
||
|
+ stats->rx_bytes += cf->can_dlc;
|
||
|
+
|
||
|
+ return 1;
|
||
|
+
|
||
|
+}
|
||
|
+#else
|
||
|
+
|
||
|
static void flexcan_read_fifo(const struct net_device *dev,
|
||
|
struct can_frame *cf)
|
||
|
{
|
||
|
@@ -466,9 +617,16 @@ static void flexcan_read_fifo(const stru
|
||
|
|
||
|
reg_ctrl = readl(&mb->can_ctrl);
|
||
|
reg_id = readl(&mb->can_id);
|
||
|
- if (reg_ctrl & FLEXCAN_MB_CNT_IDE)
|
||
|
+ if (reg_ctrl & FLEXCAN_MB_CNT_IDE) {
|
||
|
+#ifdef CONFIG_COLDFIRE
|
||
|
+ /* ColdFire can_id order as follow */
|
||
|
+ cf->can_id = (reg_id & CAN_EFF_MASK) >> 18;
|
||
|
+ cf->can_id |= (reg_id & 0x3ffff) << 11;
|
||
|
+ cf->can_id |= CAN_EFF_FLAG;
|
||
|
+#else
|
||
|
cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
|
||
|
- else
|
||
|
+#endif
|
||
|
+ } else
|
||
|
cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
|
||
|
|
||
|
if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
|
||
|
@@ -503,6 +661,7 @@ static int flexcan_read_frame(struct net
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
+#endif
|
||
|
|
||
|
static int flexcan_poll(struct napi_struct *napi, int quota)
|
||
|
{
|
||
|
@@ -554,6 +713,14 @@ static irqreturn_t flexcan_irq(int irq,
|
||
|
reg_iflag1 = readl(®s->iflag1);
|
||
|
reg_esr = readl(®s->esr);
|
||
|
writel(FLEXCAN_ESR_ERR_INT, ®s->esr); /* ACK err IRQ */
|
||
|
+#ifdef CONFIG_COLDFIRE
|
||
|
+#ifdef CONFIG_FLEXCAN_NORXFIFO
|
||
|
+ writel(FLEXCAN_ESR_BOFF_INT, ®s->esr);
|
||
|
+#else
|
||
|
+ /* ACK TWRN and RWRN error, and bus-off interrupt*/
|
||
|
+ writel(FLEXCAN_ESR_ERR_STATE, ®s->esr);
|
||
|
+#endif
|
||
|
+#endif
|
||
|
|
||
|
/*
|
||
|
* schedule NAPI in case of:
|
||
|
@@ -575,13 +742,14 @@ static irqreturn_t flexcan_irq(int irq,
|
||
|
®s->ctrl);
|
||
|
napi_schedule(&priv->napi);
|
||
|
}
|
||
|
-
|
||
|
+#ifndef CONFIG_FLEXCAN_NORXFIFO
|
||
|
/* FIFO overflow */
|
||
|
if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) {
|
||
|
writel(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW, ®s->iflag1);
|
||
|
dev->stats.rx_over_errors++;
|
||
|
dev->stats.rx_errors++;
|
||
|
}
|
||
|
+#endif
|
||
|
|
||
|
/* transmission complete interrupt */
|
||
|
if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) {
|
||
|
@@ -676,9 +844,14 @@ static int flexcan_chip_start(struct net
|
||
|
*
|
||
|
*/
|
||
|
reg_mcr = readl(®s->mcr);
|
||
|
+#ifdef CONFIG_FLEXCAN_NORXFIFO
|
||
|
+ reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
|
||
|
+ FLEXCAN_MCR_SUPV;
|
||
|
+#else
|
||
|
reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
|
||
|
FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
|
||
|
FLEXCAN_MCR_IDAM_C;
|
||
|
+#endif
|
||
|
dev_dbg(dev->dev.parent, "%s: writing mcr=0x%08x", __func__, reg_mcr);
|
||
|
writel(reg_mcr, ®s->mcr);
|
||
|
|
||
|
@@ -713,9 +886,19 @@ static int flexcan_chip_start(struct net
|
||
|
writel(0, ®s->cantxfg[i].can_id);
|
||
|
writel(0, ®s->cantxfg[i].data[0]);
|
||
|
writel(0, ®s->cantxfg[i].data[1]);
|
||
|
-
|
||
|
+#ifdef CONFIG_FLEXCAN_NORXFIFO
|
||
|
+ if (i == FLEXCAN_TX_BUF_ID)
|
||
|
+ continue;
|
||
|
+ if (i == FLEXCAN_RX_EXT_ID) /* enable receive extend message */
|
||
|
+ writel(FLEXCAN_MB_CNT_CODE(0x4)|0x600000,
|
||
|
+ ®s->cantxfg[i].can_ctrl);
|
||
|
+ else
|
||
|
+ writel(FLEXCAN_MB_CNT_CODE(0x4),
|
||
|
+ ®s->cantxfg[i].can_ctrl);
|
||
|
+#else
|
||
|
/* put MB into rx queue */
|
||
|
writel(FLEXCAN_MB_CNT_CODE(0x4), ®s->cantxfg[i].can_ctrl);
|
||
|
+#endif
|
||
|
}
|
||
|
|
||
|
/* acceptance mask/acceptance code (accept everything) */
|
||
|
@@ -772,6 +955,7 @@ static void flexcan_chip_stop(struct net
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
+
|
||
|
static int flexcan_open(struct net_device *dev)
|
||
|
{
|
||
|
struct flexcan_priv *priv = netdev_priv(dev);
|
||
|
@@ -786,6 +970,24 @@ static int flexcan_open(struct net_devic
|
||
|
err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
|
||
|
if (err)
|
||
|
goto out_close;
|
||
|
+ err = request_irq(dev->irq + 1, flexcan_irq, \
|
||
|
+ IRQF_DISABLED, dev->name, dev);
|
||
|
+ if (err) {
|
||
|
+ free_irq(dev->irq, dev);
|
||
|
+ goto out_close;
|
||
|
+ }
|
||
|
+#if defined(CONFIG_M548X)
|
||
|
+ err = request_irq(dev->irq + 2, flexcan_irq, \
|
||
|
+ IRQF_DISABLED, dev->name, dev);
|
||
|
+#elif defined(CONFIG_M5441X)
|
||
|
+ err = request_irq(dev->irq + 3, flexcan_irq, \
|
||
|
+ IRQF_DISABLED, dev->name, dev);
|
||
|
+#endif
|
||
|
+ if (err) {
|
||
|
+ free_irq(dev->irq, dev);
|
||
|
+ free_irq(dev->irq + 1, dev);
|
||
|
+ goto out_close;
|
||
|
+ }
|
||
|
|
||
|
/* start chip and queuing */
|
||
|
err = flexcan_chip_start(dev);
|
||
|
@@ -813,6 +1015,14 @@ static int flexcan_close(struct net_devi
|
||
|
flexcan_chip_stop(dev);
|
||
|
|
||
|
free_irq(dev->irq, dev);
|
||
|
+#ifdef CONFIG_COLDFIRE
|
||
|
+ free_irq(dev->irq + 1, dev);
|
||
|
+#if defined(CONFIG_M548X)
|
||
|
+ free_irq(dev->irq + 2, dev);
|
||
|
+#elif defined(CONFIG_M5441X)
|
||
|
+ free_irq(dev->irq + 3, dev);
|
||
|
+#endif
|
||
|
+#endif
|
||
|
clk_disable(priv->clk);
|
||
|
|
||
|
close_candev(dev);
|
||
|
@@ -854,14 +1064,23 @@ static int __devinit register_flexcandev
|
||
|
|
||
|
clk_enable(priv->clk);
|
||
|
|
||
|
+#if !defined(CONFIG_M548X)
|
||
|
/* select "bus clock", chip must be disabled */
|
||
|
flexcan_chip_disable(priv);
|
||
|
reg = readl(®s->ctrl);
|
||
|
reg |= FLEXCAN_CTRL_CLK_SRC;
|
||
|
writel(reg, ®s->ctrl);
|
||
|
+#endif
|
||
|
|
||
|
flexcan_chip_enable(priv);
|
||
|
|
||
|
+#ifdef CONFIG_FLEXCAN_NORXFIFO
|
||
|
+ /* set freeze, halt and restrict register access */
|
||
|
+ reg = readl(®s->mcr);
|
||
|
+ reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
|
||
|
+ FLEXCAN_MCR_SUPV;
|
||
|
+ writel(reg, ®s->mcr);
|
||
|
+#else
|
||
|
/* set freeze, halt and activate FIFO, restrict register access */
|
||
|
reg = readl(®s->mcr);
|
||
|
reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
|
||
|
@@ -880,6 +1099,7 @@ static int __devinit register_flexcandev
|
||
|
err = -ENODEV;
|
||
|
goto out;
|
||
|
}
|
||
|
+#endif
|
||
|
|
||
|
err = register_candev(dev);
|
||
|
|
||
|
@@ -901,17 +1121,19 @@ static int __devinit flexcan_probe(struc
|
||
|
struct net_device *dev;
|
||
|
struct flexcan_priv *priv;
|
||
|
struct resource *mem;
|
||
|
- struct clk *clk;
|
||
|
+ struct clk *clk = NULL;
|
||
|
void __iomem *base;
|
||
|
resource_size_t mem_size;
|
||
|
int err, irq;
|
||
|
|
||
|
+#ifndef CONFIG_COLDFIRE
|
||
|
clk = clk_get(&pdev->dev, NULL);
|
||
|
if (IS_ERR(clk)) {
|
||
|
dev_err(&pdev->dev, "no clock defined\n");
|
||
|
err = PTR_ERR(clk);
|
||
|
goto failed_clock;
|
||
|
}
|
||
|
+#endif
|
||
|
|
||
|
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||
|
irq = platform_get_irq(pdev, 0);
|
||
|
@@ -943,7 +1165,12 @@ static int __devinit flexcan_probe(struc
|
||
|
dev->flags |= IFF_ECHO; /* we support local echo in hardware */
|
||
|
|
||
|
priv = netdev_priv(dev);
|
||
|
+#ifdef CONFIG_COLDFIRE
|
||
|
+ /* return value is core clock but we need bus clock */
|
||
|
+ priv->can.clock.freq = (clk_get_rate(clk)/2);
|
||
|
+#else
|
||
|
priv->can.clock.freq = clk_get_rate(clk);
|
||
|
+#endif
|
||
|
priv->can.bittiming_const = &flexcan_bittiming_const;
|
||
|
priv->can.do_set_mode = flexcan_set_mode;
|
||
|
priv->can.do_get_berr_counter = flexcan_get_berr_counter;
|