summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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,
},
};