mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 14:04:26 -04: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;
 |