diff options
-rw-r--r-- | arch/arm/mach-mvf/clock.c | 66 | ||||
-rw-r--r-- | arch/arm/plat-mxc/devices/platform-flexcan.c | 10 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/iomux-mvf.h | 18 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/mvf.h | 4 | ||||
-rw-r--r-- | drivers/net/can/flexcan.c | 68 |
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(®s->ecr); + u32 reg; + + /* enable core and turn on clocks */ + if(!netif_running(dev)) + clk_enable(priv->clk); + + reg = readl(®s->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, ®s->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(®s->crl2); + reg_crl2 |= FLEXCAN_CRL2_ECRWRE; + writel(reg_crl2, ®s->crl2); + + reg_mecr = readl(®s->mecr); + reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS; + writel(reg_mecr, ®s->mecr); + reg_mecr &= ~(FLEXCAN_MECR_NCEFAFRZ | FLEXCAN_MECR_HANCEI_MSK | + FLEXCAN_MECR_FANCEI_MSK); + writel(reg_mecr, ®s->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, }, }; |