summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Agner <stefan.agner@toradex.com>2014-07-11 14:32:30 +0200
committerStefan Agner <stefan.agner@toradex.com>2014-07-11 14:46:19 +0200
commitb860b39f928ecc91985b6b8d4bc380f9eed978f9 (patch)
tree6edae51e494048eefb01b70fc26c0efec116c13f
parent9ff665d55bfd273042cb25e92b18bfaae0b8a0a6 (diff)
can: flexcan: add Vybrid support
Extend FlexCAN driver to support Vybrid. Vybrids variant of the IP has ECC support which is controlled through the memory error control register (MECR). There is also an errata which leads to false positive error detections (ID e5295). This patch disables the memory error detection completely. Extend the clock control for FlexCAN to enable the clocks. Fix the base addresses and introduce the necessary pinmux defines.
-rw-r--r--arch/arm/mach-mvf/clock.c66
-rw-r--r--arch/arm/plat-mxc/devices/platform-flexcan.c10
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mvf.h18
-rw-r--r--arch/arm/plat-mxc/include/mach/mvf.h4
-rw-r--r--drivers/net/can/flexcan.c68
5 files changed, 160 insertions, 6 deletions
diff --git a/arch/arm/mach-mvf/clock.c b/arch/arm/mach-mvf/clock.c
index 37247607311d..872f12f85d7b 100644
--- a/arch/arm/mach-mvf/clock.c
+++ b/arch/arm/mach-mvf/clock.c
@@ -1805,6 +1805,70 @@ static struct clk adc_clk[] = {
},
};
+static unsigned long _clk_can_get_rate(struct clk *clk)
+{
+ return clk_get_rate(clk->parent);
+}
+
+static int can_clk_enable(struct clk *can_clk)
+{
+ u32 reg;
+
+ /* enable CAN clk */
+ reg = __raw_readl(MXC_CCM_CSCDR2);
+ if(can_clk->id == 0)
+ reg |= MXC_CCM_CSCDR2_CAN0_EN;
+ if(can_clk->id == 1)
+ reg |= MXC_CCM_CSCDR2_CAN1_EN;
+ __raw_writel(reg, MXC_CCM_CSCDR2);
+
+ /* gate clock */
+ _clk_enable(can_clk);
+
+ return 0;
+}
+
+static int can_clk_disable(struct clk *can_clk)
+{
+ u32 reg;
+
+ /* disable CAN clk */
+ reg = __raw_readl(MXC_CCM_CSCDR2);
+ if(can_clk->id == 0)
+ reg &= ~MXC_CCM_CSCDR2_CAN0_EN;
+ if(can_clk->id == 1)
+ reg &= ~MXC_CCM_CSCDR2_CAN1_EN;
+ __raw_writel(reg, MXC_CCM_CSCDR2);
+
+ /* gate clock */
+ _clk_disable(can_clk);
+
+ return 0;
+}
+
+static struct clk can_clk[] = {
+ {
+ __INIT_CLK_DEBUG(can_clk)
+ .id = 0,
+ .parent = &ipg_clk,
+ .enable_reg = MXC_CCM_CCGR0,
+ .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET,
+ .enable = can_clk_enable,
+ .disable = can_clk_disable,
+ .get_rate = _clk_can_get_rate,
+ },
+ {
+ __INIT_CLK_DEBUG(can_clk)
+ .id = 1,
+ .parent = &ipg_clk,
+ .enable_reg = MXC_CCM_CCGR9,
+ .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET,
+ .enable = can_clk_enable,
+ .disable = can_clk_disable,
+ .get_rate = _clk_can_get_rate,
+ },
+};
+
static struct clk i2c_clk[] = {
{
__INIT_CLK_DEBUG(i2c_clk_0)
@@ -2068,6 +2132,8 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK("fec.1", NULL, enet_clk[1]),
_REGISTER_CLOCK("mvf-adc.0", NULL, adc_clk[0]),
_REGISTER_CLOCK("mvf-adc.1", NULL, adc_clk[1]),
+ _REGISTER_CLOCK("mvf-flexcan.0", NULL, can_clk[0]),
+ _REGISTER_CLOCK("mvf-flexcan.1", NULL, can_clk[1]),
_REGISTER_CLOCK("switch.0", NULL, enet_clk[0]),
_REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk),
_REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc1_clk),
diff --git a/arch/arm/plat-mxc/devices/platform-flexcan.c b/arch/arm/plat-mxc/devices/platform-flexcan.c
index d660237bab45..d6d960107913 100644
--- a/arch/arm/plat-mxc/devices/platform-flexcan.c
+++ b/arch/arm/plat-mxc/devices/platform-flexcan.c
@@ -47,6 +47,16 @@ const struct imx_flexcan_data imx6q_flexcan_data[] __initconst = {
};
#endif /* ifdef CONFIG_SOC_IMX6Q*/
+#ifdef CONFIG_SOC_MVFA5
+const struct imx_flexcan_data mvf_flexcan_data[] __initconst = {
+#define mvf_flexcan_data_entry(_id, _hwid) \
+ imx_flexcan_data_entry(MVF, "mvf-flexcan", _id, _hwid, SZ_16K)
+ mvf_flexcan_data_entry(0, 0),
+ mvf_flexcan_data_entry(1, 1),
+};
+
+#endif /* CONFIG_SOC_MVFA5 */
+
struct platform_device *__init imx_add_flexcan(
const struct imx_flexcan_data *data,
const struct flexcan_platform_data *pdata)
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mvf.h b/arch/arm/plat-mxc/include/mach/iomux-mvf.h
index 500f78b0d0be..4022ee0469bc 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mvf.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mvf.h
@@ -50,6 +50,9 @@ typedef enum iomux_config {
#define MVF600_I2C_PAD_CTRL (PAD_CTL_DSE_37ohm | PAD_CTL_ODE | \
PAD_CTL_SPEED_HIGH)
+#define MVF600_CAN_PAD_CTRL (PAD_CTL_SPEED_HIGH | PAD_CTL_DSE_20ohm | \
+ PAD_CTL_PUS_22K_UP)
+
#define MVF600_SAI_PAD_CTRL (PAD_CTL_DSE_50ohm | PAD_CTL_HYS | \
PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_100K_UP)
@@ -118,6 +121,15 @@ typedef enum iomux_config {
IOMUX_PAD(0x0094, 0x0094, 2, 0x0340, 1, \
MVF600_I2C_PAD_CTRL | PAD_CTL_OBE_IBE_ENABLE)
+/*CAN0 (alternative to I2C0)*/
+#define MVF600_PAD36_PTB14__CAN0_RX \
+ IOMUX_PAD(0x0090, 0x0090, 1, 0x0000, 0, \
+ MVF600_CAN_PAD_CTRL | PAD_CTL_IBE_ENABLE)
+#define MVF600_PAD37_PTB15__CAN0_TX \
+ IOMUX_PAD(0x0094, 0x0094, 1, 0x0000, 0, \
+ MVF600_CAN_PAD_CTRL | PAD_CTL_OBE_ENABLE)
+
+
/*SW1*/
#define MVF600_PAD38_PTB16_USER_BTN1 \
IOMUX_PAD(0x0098, 0x0098, 0, 0x0000, 0, \
@@ -125,9 +137,11 @@ typedef enum iomux_config {
/*CAN1*/
#define MVF600_PAD38_PTB16__CAN1_RX \
- IOMUX_PAD(0x0098, 0x0098, 1, 0x0000, 0, 0)
+ IOMUX_PAD(0x0098, 0x0098, 1, 0x0000, 0, \
+ MVF600_CAN_PAD_CTRL | PAD_CTL_IBE_ENABLE)
#define MVF600_PAD39_PTB17__CAN1_TX \
- IOMUX_PAD(0x009C, 0x009C, 1, 0x0000, 0, 0)
+ IOMUX_PAD(0x009C, 0x009C, 1, 0x0000, 0, \
+ MVF600_CAN_PAD_CTRL | PAD_CTL_OBE_ENABLE)
/*DSPI0*/
#define MVF600_PAD41_PTB19__DSPI0_PCS0 \
diff --git a/arch/arm/plat-mxc/include/mach/mvf.h b/arch/arm/plat-mxc/include/mach/mvf.h
index 95efcefa3b7e..2120e86a4b02 100644
--- a/arch/arm/plat-mxc/include/mach/mvf.h
+++ b/arch/arm/plat-mxc/include/mach/mvf.h
@@ -124,7 +124,7 @@
#define MVF_DMA0TCD_BASE_ADDR (MVF_AIPS0_BASE_ADDR + 0x00019000)
#define MVF_SEMA4_BASE_ADDR (MVF_AIPS0_BASE_ADDR + 0x0001D000)
#define MVF_FLEXBUS_BASE_ADDR (MVF_AIPS0_BASE_ADDR + 0x0001E000)
-#define MVF_FLEXCAN0_BASE_ADDR (MVF_AIPS0_BASE_ADDR + 0x00021000)
+#define MVF_CAN0_BASE_ADDR (MVF_AIPS0_BASE_ADDR + 0x00020000)
#define MVF_DMAMUX0_BASE_ADDR (MVF_AIPS0_BASE_ADDR + 0x00024000)
#define MVF_DMAMUX1_BASE_ADDR (MVF_AIPS0_BASE_ADDR + 0x00025000)
#define MVF_UART0_BASE_ADDR (MVF_AIPS0_BASE_ADDR + 0x00027000)
@@ -236,7 +236,7 @@
#define MVF_OPENVG_BASE_ADDR (MVF_AIPS1_BASE_ADDR - 0x80000 + 0x000CF000)
#define MVF_MAC0_BASE_ADDR (MVF_AIPS1_BASE_ADDR - 0x80000 + 0x000D0000)
#define MVF_MAC1_BASE_ADDR (MVF_AIPS1_BASE_ADDR - 0x80000 + 0x000D1000)
-#define MVF_FLEXCAN1_BASE_ADDR (MVF_AIPS1_BASE_ADDR - 0x80000 + 0x000D4000)
+#define MVF_CAN1_BASE_ADDR (MVF_AIPS1_BASE_ADDR - 0x80000 + 0x000D4000)
#define MVF_DCU1_BASE_ADDR (MVF_AIPS1_BASE_ADDR - 0x80000 + 0x000D8000)
#define MVF_NFC_BASE_ADDR (MVF_AIPS1_BASE_ADDR - 0x80000 + 0x000E0000)
#define MVF_I2C2_BASE_ADDR (MVF_AIPS1_BASE_ADDR - 0x80000 + 0x000E6000)
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index d0b8e8ed275b..7ba80e5c00d1 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -96,6 +96,27 @@
#define FLEXCAN_CTRL_ERR_ALL \
(FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE)
+/* FLEXCAN control register 2 (CTRL2) bits */
+#define FLEXCAN_CRL2_ECRWRE BIT(29)
+#define FLEXCAN_CRL2_WRMFRZ BIT(28)
+#define FLEXCAN_CRL2_RFFN(x) (((x) & 0x0f) << 24)
+#define FLEXCAN_CRL2_TASD(x) (((x) & 0x1f) << 19)
+#define FLEXCAN_CRL2_MRP BIT(18)
+#define FLEXCAN_CRL2_RRS BIT(17)
+#define FLEXCAN_CRL2_EACEN BIT(16)
+
+/* FLEXCAN memory error control register (MECR) bits */
+#define FLEXCAN_MECR_ECRWRDIS BIT(31)
+#define FLEXCAN_MECR_HANCEI_MSK BIT(19)
+#define FLEXCAN_MECR_FANCEI_MSK BIT(18)
+#define FLEXCAN_MECR_CEI_MSK BIT(16)
+#define FLEXCAN_MECR_HAERRIE BIT(15)
+#define FLEXCAN_MECR_FAERRIE BIT(14)
+#define FLEXCAN_MECR_EXTERRIE BIT(13)
+#define FLEXCAN_MECR_RERRDIS BIT(9)
+#define FLEXCAN_MECR_ECCDIS BIT(8)
+#define FLEXCAN_MECR_NCEFAFRZ BIT(7)
+
/* FLEXCAN error and status register (ESR) bits */
#define FLEXCAN_ESR_TWRN_INT BIT(17)
#define FLEXCAN_ESR_RWRN_INT BIT(16)
@@ -177,12 +198,16 @@ struct flexcan_regs {
u32 rxfir; /* 0x4c */
u32 _reserved3[12];
struct flexcan_mb cantxfg[64];
+ u32 _reserved4[408];
+ u32 mecr; /* 0xae0 */
+ u32 erriar; /* 0xae4 */
};
enum flexcan_ip_version {
FLEXCAN_VER_3_0_0,
FLEXCAN_VER_3_0_4,
FLEXCAN_VER_10_0_12,
+ FLEXCAN_VER_11_0_0, /* IP Version? */
};
struct flexcan_priv {
@@ -290,7 +315,17 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
{
const struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
- u32 reg = readl(&regs->ecr);
+ u32 reg;
+
+ /* enable core and turn on clocks */
+ if(!netif_running(dev))
+ clk_enable(priv->clk);
+
+ reg = readl(&regs->ecr);
+
+ /* disable core and turn off clocks */
+ if(!netif_running(dev))
+ clk_disable(priv->clk);
bec->txerr = (reg >> 0) & 0xff;
bec->rxerr = (reg >> 8) & 0xff;
@@ -705,7 +740,7 @@ static int flexcan_chip_start(struct net_device *dev)
struct flexcan_regs __iomem *regs = priv->base;
unsigned int i;
int err;
- u32 reg_mcr, reg_ctrl;
+ u32 reg_mcr, reg_ctrl, reg_crl2, reg_mecr;
/* enable module */
flexcan_chip_enable(priv);
@@ -791,6 +826,32 @@ static int flexcan_chip_start(struct net_device *dev)
if (priv->version >= FLEXCAN_VER_10_0_12)
writel(0x0, &regs->rxfgmask);
+ /*
+ * On Vybrid, disable memory error detection interrupts
+ * and freeze mode.
+ * This also works around errata e5295 which generates
+ * false positive memory errors and put the device in
+ * freeze mode.
+ */
+ if (priv->version >= FLEXCAN_VER_11_0_0) {
+ /*
+ * Follow the protocol as described in "Detection
+ * and Correction of Memory Errors" to write to
+ * MECR register
+ */
+ reg_crl2 = readl(&regs->crl2);
+ reg_crl2 |= FLEXCAN_CRL2_ECRWRE;
+ writel(reg_crl2, &regs->crl2);
+
+ reg_mecr = readl(&regs->mecr);
+ reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS;
+ writel(reg_mecr, &regs->mecr);
+ reg_mecr &= ~(FLEXCAN_MECR_NCEFAFRZ | FLEXCAN_MECR_HANCEI_MSK |
+ FLEXCAN_MECR_FANCEI_MSK);
+ writel(reg_mecr, &regs->mecr);
+ }
+
+
flexcan_transceiver_switch(priv, 1);
/* synchronize with the can bus */
@@ -980,6 +1041,9 @@ static struct platform_device_id flexcan_devtype[] = {
}, {
.name = "imx6q-flexcan",
.driver_data = FLEXCAN_VER_10_0_12,
+ }, {
+ .name = "mvf-flexcan",
+ .driver_data = FLEXCAN_VER_11_0_0,
},
};