Message ID | 20140427122510.GB12901@amd.pavel.ucw.cz (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Sun, 2014-04-27 at 14:25 +0200, ZY - pavel wrote: > Apparently, socfpga CAN needs 32-bit accesses and different raminit > sequence. > > Signed-off-by: Pavel Machek <pavel@denx.de> > > --- > > > > > I'm not in the office (and fighting with my phone's email client) until 5th of May, however please rebase all your patches against the latest net/master from David Miller, as this tree includes all c_can fixes by Thomas. > > > > Ok, combined patch is here. Lightly tested using loopback on Arrow > SocKit. Hi Pavel. Thanks for your help on the SOCFPGA support! I can test this on the Altera Development Kit but I'm not able to cleanly apply to the latest David Miller net-next branch. Is there a different branch I should use? I also like your updates to my patch as shown below - much cleaner. Thanks, Thor > > diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c > index a2ca820..824ec21 100644 > --- a/drivers/net/can/c_can/c_can.c > +++ b/drivers/net/can/c_can/c_can.c > @@ -48,6 +48,7 @@ > #define C_CAN_IFACE(reg, iface) (C_CAN_IF1_##reg + (iface) * IF_ENUM_REG_LEN) > > /* control extension register D_CAN specific */ > +#define CONTROL_MIL BIT(17) > #define CONTROL_EX_PDR BIT(8) > > /* control register */ > @@ -239,12 +240,20 @@ static inline void c_can_reset_ram(const struct c_can_priv *priv, bool enable) > > static void c_can_irq_control(struct c_can_priv *priv, bool enable) > { > - u32 ctrl = priv->read_reg(priv, C_CAN_CTRL_REG) & ~CONTROL_IRQMSK; > + u32 ctrl; > + > + if (priv->type == BOSCH_D_CAN) > + ctrl = priv->read_reg32(priv, C_CAN_CTRL_REG) & ~CONTROL_IRQMSK; > + else > + ctrl = priv->read_reg(priv, C_CAN_CTRL_REG) & ~CONTROL_IRQMSK; > > if (enable) > ctrl |= CONTROL_IRQMSK; > > - priv->write_reg(priv, C_CAN_CTRL_REG, ctrl); > + if (priv->type == BOSCH_D_CAN) > + priv->write_reg32(priv, C_CAN_CTRL_REG, ctrl); > + else > + priv->write_reg(priv, C_CAN_CTRL_REG, ctrl); > } > > static void c_can_obj_update(struct net_device *dev, int iface, u32 cmd, u32 obj) > @@ -252,8 +261,7 @@ static void c_can_obj_update(struct net_device *dev, int iface, u32 cmd, u32 obj > struct c_can_priv *priv = netdev_priv(dev); > int cnt, reg = C_CAN_IFACE(COMREQ_REG, iface); > > - priv->write_reg(priv, reg + 1, cmd); > - priv->write_reg(priv, reg, obj); > + priv->write_reg32(priv, reg, (cmd << 16) | obj); > > for (cnt = MIN_TIMEOUT_VALUE; cnt; cnt--) { > if (!(priv->read_reg(priv, reg) & IF_COMR_BUSY)) > @@ -328,8 +336,7 @@ static void c_can_setup_tx_object(struct net_device *dev, int iface, > change_bit(idx, &priv->tx_dir); > } > > - priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), arb); > - priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), arb >> 16); > + priv->write_reg32(priv, C_CAN_IFACE(ARB1_REG, iface), arb); > > priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), ctrl); > > @@ -391,8 +398,7 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, u32 ctrl) > > frame->can_dlc = get_can_dlc(ctrl & 0x0F); > > - arb = priv->read_reg(priv, C_CAN_IFACE(ARB1_REG, iface)); > - arb |= priv->read_reg(priv, C_CAN_IFACE(ARB2_REG, iface)) << 16; > + arb = priv->read_reg32(priv, C_CAN_IFACE(ARB1_REG, iface)); > > if (arb & IF_ARB_MSGXTD) > frame->can_id = (arb & CAN_EFF_MASK) | CAN_EFF_FLAG; > @@ -424,12 +430,10 @@ static void c_can_setup_receive_object(struct net_device *dev, int iface, > struct c_can_priv *priv = netdev_priv(dev); > > mask |= BIT(29); > - priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface), mask); > - priv->write_reg(priv, C_CAN_IFACE(MASK2_REG, iface), mask >> 16); > + priv->write_reg32(priv, C_CAN_IFACE(MASK1_REG, iface), mask); > > id |= IF_ARB_MSGVAL; > - priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), id); > - priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), id >> 16); > + priv->write_reg32(priv, C_CAN_IFACE(ARB1_REG, iface), id); > > priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), mcont); > c_can_object_put(dev, iface, obj, IF_COMM_RCV_SETUP); > @@ -510,16 +514,22 @@ static int c_can_set_bittiming(struct net_device *dev) > netdev_info(dev, > "setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe); > > - ctrl_save = priv->read_reg(priv, C_CAN_CTRL_REG); > + if (priv->type == BOSCH_D_CAN) > + ctrl_save = priv->read_reg32(priv, C_CAN_CTRL_REG); > + else > + ctrl_save = priv->read_reg(priv, C_CAN_CTRL_REG); > ctrl_save &= ~CONTROL_INIT; > - priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_CCE | CONTROL_INIT); > + priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_CCE | CONTROL_INIT); /* FIXME: want to do write32? */ > res = c_can_wait_for_ctrl_init(dev, priv, CONTROL_INIT); > if (res) > return res; > > priv->write_reg(priv, C_CAN_BTR_REG, reg_btr); > priv->write_reg(priv, C_CAN_BRPEXT_REG, reg_brpe); > - priv->write_reg(priv, C_CAN_CTRL_REG, ctrl_save); > + if (priv->type == BOSCH_D_CAN) > + priv->write_reg32(priv, C_CAN_CTRL_REG, ctrl_save); > + else > + priv->write_reg(priv, C_CAN_CTRL_REG, ctrl_save); > > return c_can_wait_for_ctrl_init(dev, priv, 0); > } > @@ -1240,7 +1250,7 @@ int c_can_power_up(struct net_device *dev) > > /* Clear PDR and INIT bits */ > val = priv->read_reg(priv, C_CAN_CTRL_EX_REG); > - val &= ~CONTROL_EX_PDR; > + val &= ~(CONTROL_EX_PDR | CONTROL_MIL); > priv->write_reg(priv, C_CAN_CTRL_EX_REG, val); > val = priv->read_reg(priv, C_CAN_CTRL_REG); > val &= ~CONTROL_INIT; > diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h > index c56f1b1..10c3fd2 100644 > --- a/drivers/net/can/c_can/c_can.h > +++ b/drivers/net/can/c_can/c_can.h > @@ -78,6 +78,7 @@ enum reg { > C_CAN_INTPND2_REG, > C_CAN_MSGVAL1_REG, > C_CAN_MSGVAL2_REG, > + C_CAN_FUNCTION_REG, > }; > > static const u16 reg_map_c_can[] = { > @@ -129,6 +130,7 @@ static const u16 reg_map_d_can[] = { > [C_CAN_BRPEXT_REG] = 0x0E, > [C_CAN_INT_REG] = 0x10, > [C_CAN_TEST_REG] = 0x14, > + [C_CAN_FUNCTION_REG] = 0x18, > [C_CAN_TXRQST1_REG] = 0x88, > [C_CAN_TXRQST2_REG] = 0x8A, > [C_CAN_NEWDAT1_REG] = 0x9C, > @@ -188,6 +190,8 @@ struct c_can_priv { > u32 comm_rcv_high; > u32 rxmasked; > u32 dlc[C_CAN_MSG_OBJ_TX_NUM]; > + u32 (*read_reg32) (struct c_can_priv *priv, enum reg index); > + void (*write_reg32) (struct c_can_priv *priv, enum reg index, u32 val); > }; > > struct net_device *alloc_c_can_dev(void); > diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c > index 1df0b32..476d1e0 100644 > --- a/drivers/net/can/c_can/c_can_platform.c > +++ b/drivers/net/can/c_can/c_can_platform.c > @@ -40,6 +40,7 @@ > #define CAN_RAMINIT_START_MASK(i) (0x001 << (i)) > #define CAN_RAMINIT_DONE_MASK(i) (0x100 << (i)) > #define CAN_RAMINIT_ALL_MASK(i) (0x101 << (i)) > +#define DCAN_RAM_INIT_BIT (1 << 3) > static DEFINE_SPINLOCK(raminit_lock); > /* > * 16-bit c_can registers can be arranged differently in the memory > @@ -80,7 +81,7 @@ static void c_can_hw_raminit_wait(const struct c_can_priv *priv, u32 mask, > udelay(1); > } > > -static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable) > +static void c_can_hw_raminit_ti(const struct c_can_priv *priv, bool enable) > { > u32 mask = CAN_RAMINIT_ALL_MASK(priv->instance); > u32 ctrl; > @@ -88,7 +89,8 @@ static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable) > spin_lock(&raminit_lock); > > ctrl = readl(priv->raminit_ctrlreg); > - /* We clear the done and start bit first. The start bit is > + /* > + * We clear the done and start bit first. The start bit is > * looking at the 0 -> transition, but is not self clearing; > * And we clear the init done bit as well. > */ > @@ -108,6 +110,54 @@ static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable) > spin_unlock(&raminit_lock); > } > > +static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable) > +{ > + u32 ctrl; > + > + spin_lock(&raminit_lock); > + > + ctrl = readl(priv->raminit_ctrlreg); > + ctrl &= ~DCAN_RAM_INIT_BIT; > + writel(ctrl, priv->raminit_ctrlreg); > + c_can_hw_raminit_wait(priv, ctrl, 0); > + > + if (enable) { > + /* Set start bit. */ > + ctrl |= DCAN_RAM_INIT_BIT; > + writel(ctrl, priv->raminit_ctrlreg); > + c_can_hw_raminit_wait(priv, ctrl, 0); > + } > + spin_unlock(&raminit_lock); > +} > + > +static u32 c_can_plat_read_reg32(struct c_can_priv *priv, enum reg index) > +{ > + u32 val; > + > + val = priv->read_reg(priv, index); > + val |= ((u32) priv->read_reg(priv, index + 1)) << 16; > + > + return val; > +} > + > +static void c_can_plat_write_reg32(struct c_can_priv *priv, enum reg index, > + u32 val) > +{ > + priv->write_reg(priv, index + 1, val>>16); > + priv->write_reg(priv, index, val); > +} > + > +static u32 d_can_plat_read_reg32(struct c_can_priv *priv, enum reg index) > +{ > + return readl(priv->base + priv->regs[index]); > +} > + > +static void d_can_plat_write_reg32(struct c_can_priv *priv, enum reg index, > + u32 val) > +{ > + writel(val, priv->base + priv->regs[index]); > +} > + > static struct platform_device_id c_can_id_table[] = { > [BOSCH_C_CAN_PLATFORM] = { > .name = KBUILD_MODNAME, > @@ -201,11 +251,15 @@ static int c_can_plat_probe(struct platform_device *pdev) > case IORESOURCE_MEM_32BIT: > priv->read_reg = c_can_plat_read_reg_aligned_to_32bit; > priv->write_reg = c_can_plat_write_reg_aligned_to_32bit; > + priv->read_reg32 = c_can_plat_read_reg32; > + priv->write_reg32 = c_can_plat_write_reg32; > break; > case IORESOURCE_MEM_16BIT: > default: > priv->read_reg = c_can_plat_read_reg_aligned_to_16bit; > priv->write_reg = c_can_plat_write_reg_aligned_to_16bit; > + priv->read_reg32 = c_can_plat_read_reg32; > + priv->write_reg32 = c_can_plat_write_reg32; > break; > } > break; > @@ -214,6 +268,8 @@ static int c_can_plat_probe(struct platform_device *pdev) > priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; > priv->read_reg = c_can_plat_read_reg_aligned_to_16bit; > priv->write_reg = c_can_plat_write_reg_aligned_to_16bit; > + priv->read_reg32 = d_can_plat_read_reg32; > + priv->write_reg32 = d_can_plat_write_reg32; > > if (pdev->dev.of_node) > priv->instance = of_alias_get_id(pdev->dev.of_node, "d_can"); > @@ -221,11 +277,22 @@ static int c_can_plat_probe(struct platform_device *pdev) > priv->instance = pdev->id; > > res = platform_get_resource(pdev, IORESOURCE_MEM, 1); > + /* > + * Not all D_CAN module have a separate register for the D_CAN > + * RAM initialization. Use default RAM init bit in D_CAN module > + * if not specified in DT. > + */ > + if (!res) { > + priv->raminit = c_can_hw_raminit; > + priv->raminit_ctrlreg = addr + priv->regs[C_CAN_FUNCTION_REG]; > + break; > + } > + > priv->raminit_ctrlreg = devm_ioremap_resource(&pdev->dev, res); > if (IS_ERR(priv->raminit_ctrlreg) || priv->instance < 0) > dev_info(&pdev->dev, "control memory is not used for raminit\n"); > else > - priv->raminit = c_can_hw_raminit; > + priv->raminit = c_can_hw_raminit_ti; > break; > default: > ret = -EINVAL; > >
Hi! On Mon 2014-04-28 15:20:49, Thor Thayer wrote: > On Sun, 2014-04-27 at 14:25 +0200, ZY - pavel wrote: > > Apparently, socfpga CAN needs 32-bit accesses and different raminit > > sequence. > > > > Signed-off-by: Pavel Machek <pavel@denx.de> > > > > --- > > > > > > > > I'm not in the office (and fighting with my phone's email client) until 5th of May, however please rebase all your patches against the latest net/master from David Miller, as this tree includes all c_can fixes by Thomas. > > > > > > > Ok, combined patch is here. Lightly tested using loopback on Arrow > > SocKit. > > Hi Pavel. > > Thanks for your help on the SOCFPGA support! I can test this on the > Altera Development Kit but I'm not able to cleanly apply to the latest > David Miller net-next branch. Is there a different branch I should > use? It should have been against net-next branch... but perhaps I made a mistake somewhere. I should get some sleep now. Or ... let me upload my tree so that you can generate the diff. You should be able to get it using: git pull git://git.denx.de/linux-denx-pavel.git my_net_master > I also like your updates to my patch as shown below - much cleaner. Thanks :-). Best regards, Pavel
On Mon, Apr 28, 2014 at 4:15 PM, Pavel Machek <pavel@denx.de> wrote: > Hi! > > On Mon 2014-04-28 15:20:49, Thor Thayer wrote: >> On Sun, 2014-04-27 at 14:25 +0200, ZY - pavel wrote: >> > Apparently, socfpga CAN needs 32-bit accesses and different raminit >> > sequence. >> > >> > Signed-off-by: Pavel Machek <pavel@denx.de> >> > >> > --- >> > >> > > >> > > I'm not in the office (and fighting with my phone's email client) until 5th of May, however please rebase all your patches against the latest net/master from David Miller, as this tree includes all c_can fixes by Thomas. >> > > >> > >> > Ok, combined patch is here. Lightly tested using loopback on Arrow >> > SocKit. >> >> Hi Pavel. >> >> Thanks for your help on the SOCFPGA support! I can test this on the >> Altera Development Kit but I'm not able to cleanly apply to the latest >> David Miller net-next branch. Is there a different branch I should >> use? > > It should have been against net-next branch... but perhaps I made a > mistake somewhere. I should get some sleep now. > > Or ... let me upload my tree so that you can generate the diff. > > You should be able to get it using: > > git pull git://git.denx.de/linux-denx-pavel.git my_net_master > >> I also like your updates to my patch as shown below - much cleaner. > > Thanks :-). > > Best regards, > > Pavel Hi Pavel, I didn't get a chance to pull and test your patch but a visual inspection looks good. Since you based this patch on my original code, feel free to add my signed-off. Thor > > > -- > (english) http://www.livejournal.com/~pavelmachek > (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Hi! > >>> > Apparently, socfpga CAN needs 32-bit accesses and different raminit > >>> > sequence. > >>> > > >>> > Signed-off-by: Pavel Machek <pavel@denx.de> ... > >> Or ... let me upload my tree so that you can generate the diff. > >> > >> You should be able to get it using: > >> > >> git pull git://git.denx.de/linux-denx-pavel.git my_net_master > >> > >>> I also like your updates to my patch as shown below - much cleaner. > > Since you based this patch on my original code, feel free to add my > signed-off. Will do. > I pulled in your branch > (git://git.denx.de/linux-denx-pavel.gitmy_net_master) and tested it on > the Altera Development Kit. It works well - > I don't see any issues at a number of different bitrates (80K, 200K, 800K, > 1Mb). Thanks for testing. I'll also add your Tested-by: header, if you don't mind. > I didn't investigate what the issues were with applying the patch though. I > just used your branch. The way I generated that branch... you picked up some extra code in other areas of the kernel, but it should not affect the testing. Thanks! Pavel
On Wed, Apr 30, 2014 at 4:53 PM, Pavel Machek <pavel@denx.de> wrote: > Hi! > >> >>> > Apparently, socfpga CAN needs 32-bit accesses and different raminit >> >>> > sequence. >> >>> > >> >>> > Signed-off-by: Pavel Machek <pavel@denx.de> > > ... > >> >> Or ... let me upload my tree so that you can generate the diff. >> >> >> >> You should be able to get it using: >> >> >> >> git pull git://git.denx.de/linux-denx-pavel.git my_net_master >> >> >> >>> I also like your updates to my patch as shown below - much cleaner. > >> > Since you based this patch on my original code, feel free to add my >> signed-off. > > Will do. > >> I pulled in your branch >> (git://git.denx.de/linux-denx-pavel.gitmy_net_master) and tested it on >> the Altera Development Kit. It works well - >> I don't see any issues at a number of different bitrates (80K, 200K, 800K, >> 1Mb). > > Thanks for testing. I'll also add your Tested-by: header, if you don't > mind. Hi Pavel. That would be fine. Thor > >> I didn't investigate what the issues were with applying the patch though. I >> just used your branch. > > The way I generated that branch... you picked up some extra code in > other areas of the kernel, but it should not affect the testing. > > Thanks! > Pavel > -- > (english) http://www.livejournal.com/~pavelmachek > (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index a2ca820..824ec21 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -48,6 +48,7 @@ #define C_CAN_IFACE(reg, iface) (C_CAN_IF1_##reg + (iface) * IF_ENUM_REG_LEN) /* control extension register D_CAN specific */ +#define CONTROL_MIL BIT(17) #define CONTROL_EX_PDR BIT(8) /* control register */ @@ -239,12 +240,20 @@ static inline void c_can_reset_ram(const struct c_can_priv *priv, bool enable) static void c_can_irq_control(struct c_can_priv *priv, bool enable) { - u32 ctrl = priv->read_reg(priv, C_CAN_CTRL_REG) & ~CONTROL_IRQMSK; + u32 ctrl; + + if (priv->type == BOSCH_D_CAN) + ctrl = priv->read_reg32(priv, C_CAN_CTRL_REG) & ~CONTROL_IRQMSK; + else + ctrl = priv->read_reg(priv, C_CAN_CTRL_REG) & ~CONTROL_IRQMSK; if (enable) ctrl |= CONTROL_IRQMSK; - priv->write_reg(priv, C_CAN_CTRL_REG, ctrl); + if (priv->type == BOSCH_D_CAN) + priv->write_reg32(priv, C_CAN_CTRL_REG, ctrl); + else + priv->write_reg(priv, C_CAN_CTRL_REG, ctrl); } static void c_can_obj_update(struct net_device *dev, int iface, u32 cmd, u32 obj) @@ -252,8 +261,7 @@ static void c_can_obj_update(struct net_device *dev, int iface, u32 cmd, u32 obj struct c_can_priv *priv = netdev_priv(dev); int cnt, reg = C_CAN_IFACE(COMREQ_REG, iface); - priv->write_reg(priv, reg + 1, cmd); - priv->write_reg(priv, reg, obj); + priv->write_reg32(priv, reg, (cmd << 16) | obj); for (cnt = MIN_TIMEOUT_VALUE; cnt; cnt--) { if (!(priv->read_reg(priv, reg) & IF_COMR_BUSY)) @@ -328,8 +336,7 @@ static void c_can_setup_tx_object(struct net_device *dev, int iface, change_bit(idx, &priv->tx_dir); } - priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), arb); - priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), arb >> 16); + priv->write_reg32(priv, C_CAN_IFACE(ARB1_REG, iface), arb); priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), ctrl); @@ -391,8 +398,7 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, u32 ctrl) frame->can_dlc = get_can_dlc(ctrl & 0x0F); - arb = priv->read_reg(priv, C_CAN_IFACE(ARB1_REG, iface)); - arb |= priv->read_reg(priv, C_CAN_IFACE(ARB2_REG, iface)) << 16; + arb = priv->read_reg32(priv, C_CAN_IFACE(ARB1_REG, iface)); if (arb & IF_ARB_MSGXTD) frame->can_id = (arb & CAN_EFF_MASK) | CAN_EFF_FLAG; @@ -424,12 +430,10 @@ static void c_can_setup_receive_object(struct net_device *dev, int iface, struct c_can_priv *priv = netdev_priv(dev); mask |= BIT(29); - priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface), mask); - priv->write_reg(priv, C_CAN_IFACE(MASK2_REG, iface), mask >> 16); + priv->write_reg32(priv, C_CAN_IFACE(MASK1_REG, iface), mask); id |= IF_ARB_MSGVAL; - priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), id); - priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), id >> 16); + priv->write_reg32(priv, C_CAN_IFACE(ARB1_REG, iface), id); priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), mcont); c_can_object_put(dev, iface, obj, IF_COMM_RCV_SETUP); @@ -510,16 +514,22 @@ static int c_can_set_bittiming(struct net_device *dev) netdev_info(dev, "setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe); - ctrl_save = priv->read_reg(priv, C_CAN_CTRL_REG); + if (priv->type == BOSCH_D_CAN) + ctrl_save = priv->read_reg32(priv, C_CAN_CTRL_REG); + else + ctrl_save = priv->read_reg(priv, C_CAN_CTRL_REG); ctrl_save &= ~CONTROL_INIT; - priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_CCE | CONTROL_INIT); + priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_CCE | CONTROL_INIT); /* FIXME: want to do write32? */ res = c_can_wait_for_ctrl_init(dev, priv, CONTROL_INIT); if (res) return res; priv->write_reg(priv, C_CAN_BTR_REG, reg_btr); priv->write_reg(priv, C_CAN_BRPEXT_REG, reg_brpe); - priv->write_reg(priv, C_CAN_CTRL_REG, ctrl_save); + if (priv->type == BOSCH_D_CAN) + priv->write_reg32(priv, C_CAN_CTRL_REG, ctrl_save); + else + priv->write_reg(priv, C_CAN_CTRL_REG, ctrl_save); return c_can_wait_for_ctrl_init(dev, priv, 0); } @@ -1240,7 +1250,7 @@ int c_can_power_up(struct net_device *dev) /* Clear PDR and INIT bits */ val = priv->read_reg(priv, C_CAN_CTRL_EX_REG); - val &= ~CONTROL_EX_PDR; + val &= ~(CONTROL_EX_PDR | CONTROL_MIL); priv->write_reg(priv, C_CAN_CTRL_EX_REG, val); val = priv->read_reg(priv, C_CAN_CTRL_REG); val &= ~CONTROL_INIT; diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h index c56f1b1..10c3fd2 100644 --- a/drivers/net/can/c_can/c_can.h +++ b/drivers/net/can/c_can/c_can.h @@ -78,6 +78,7 @@ enum reg { C_CAN_INTPND2_REG, C_CAN_MSGVAL1_REG, C_CAN_MSGVAL2_REG, + C_CAN_FUNCTION_REG, }; static const u16 reg_map_c_can[] = { @@ -129,6 +130,7 @@ static const u16 reg_map_d_can[] = { [C_CAN_BRPEXT_REG] = 0x0E, [C_CAN_INT_REG] = 0x10, [C_CAN_TEST_REG] = 0x14, + [C_CAN_FUNCTION_REG] = 0x18, [C_CAN_TXRQST1_REG] = 0x88, [C_CAN_TXRQST2_REG] = 0x8A, [C_CAN_NEWDAT1_REG] = 0x9C, @@ -188,6 +190,8 @@ struct c_can_priv { u32 comm_rcv_high; u32 rxmasked; u32 dlc[C_CAN_MSG_OBJ_TX_NUM]; + u32 (*read_reg32) (struct c_can_priv *priv, enum reg index); + void (*write_reg32) (struct c_can_priv *priv, enum reg index, u32 val); }; struct net_device *alloc_c_can_dev(void); diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index 1df0b32..476d1e0 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -40,6 +40,7 @@ #define CAN_RAMINIT_START_MASK(i) (0x001 << (i)) #define CAN_RAMINIT_DONE_MASK(i) (0x100 << (i)) #define CAN_RAMINIT_ALL_MASK(i) (0x101 << (i)) +#define DCAN_RAM_INIT_BIT (1 << 3) static DEFINE_SPINLOCK(raminit_lock); /* * 16-bit c_can registers can be arranged differently in the memory @@ -80,7 +81,7 @@ static void c_can_hw_raminit_wait(const struct c_can_priv *priv, u32 mask, udelay(1); } -static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable) +static void c_can_hw_raminit_ti(const struct c_can_priv *priv, bool enable) { u32 mask = CAN_RAMINIT_ALL_MASK(priv->instance); u32 ctrl; @@ -88,7 +89,8 @@ static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable) spin_lock(&raminit_lock); ctrl = readl(priv->raminit_ctrlreg); - /* We clear the done and start bit first. The start bit is + /* + * We clear the done and start bit first. The start bit is * looking at the 0 -> transition, but is not self clearing; * And we clear the init done bit as well. */ @@ -108,6 +110,54 @@ static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable) spin_unlock(&raminit_lock); } +static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable) +{ + u32 ctrl; + + spin_lock(&raminit_lock); + + ctrl = readl(priv->raminit_ctrlreg); + ctrl &= ~DCAN_RAM_INIT_BIT; + writel(ctrl, priv->raminit_ctrlreg); + c_can_hw_raminit_wait(priv, ctrl, 0); + + if (enable) { + /* Set start bit. */ + ctrl |= DCAN_RAM_INIT_BIT; + writel(ctrl, priv->raminit_ctrlreg); + c_can_hw_raminit_wait(priv, ctrl, 0); + } + spin_unlock(&raminit_lock); +} + +static u32 c_can_plat_read_reg32(struct c_can_priv *priv, enum reg index) +{ + u32 val; + + val = priv->read_reg(priv, index); + val |= ((u32) priv->read_reg(priv, index + 1)) << 16; + + return val; +} + +static void c_can_plat_write_reg32(struct c_can_priv *priv, enum reg index, + u32 val) +{ + priv->write_reg(priv, index + 1, val>>16); + priv->write_reg(priv, index, val); +} + +static u32 d_can_plat_read_reg32(struct c_can_priv *priv, enum reg index) +{ + return readl(priv->base + priv->regs[index]); +} + +static void d_can_plat_write_reg32(struct c_can_priv *priv, enum reg index, + u32 val) +{ + writel(val, priv->base + priv->regs[index]); +} + static struct platform_device_id c_can_id_table[] = { [BOSCH_C_CAN_PLATFORM] = { .name = KBUILD_MODNAME, @@ -201,11 +251,15 @@ static int c_can_plat_probe(struct platform_device *pdev) case IORESOURCE_MEM_32BIT: priv->read_reg = c_can_plat_read_reg_aligned_to_32bit; priv->write_reg = c_can_plat_write_reg_aligned_to_32bit; + priv->read_reg32 = c_can_plat_read_reg32; + priv->write_reg32 = c_can_plat_write_reg32; break; case IORESOURCE_MEM_16BIT: default: priv->read_reg = c_can_plat_read_reg_aligned_to_16bit; priv->write_reg = c_can_plat_write_reg_aligned_to_16bit; + priv->read_reg32 = c_can_plat_read_reg32; + priv->write_reg32 = c_can_plat_write_reg32; break; } break; @@ -214,6 +268,8 @@ static int c_can_plat_probe(struct platform_device *pdev) priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; priv->read_reg = c_can_plat_read_reg_aligned_to_16bit; priv->write_reg = c_can_plat_write_reg_aligned_to_16bit; + priv->read_reg32 = d_can_plat_read_reg32; + priv->write_reg32 = d_can_plat_write_reg32; if (pdev->dev.of_node) priv->instance = of_alias_get_id(pdev->dev.of_node, "d_can"); @@ -221,11 +277,22 @@ static int c_can_plat_probe(struct platform_device *pdev) priv->instance = pdev->id; res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + /* + * Not all D_CAN module have a separate register for the D_CAN + * RAM initialization. Use default RAM init bit in D_CAN module + * if not specified in DT. + */ + if (!res) { + priv->raminit = c_can_hw_raminit; + priv->raminit_ctrlreg = addr + priv->regs[C_CAN_FUNCTION_REG]; + break; + } + priv->raminit_ctrlreg = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->raminit_ctrlreg) || priv->instance < 0) dev_info(&pdev->dev, "control memory is not used for raminit\n"); else - priv->raminit = c_can_hw_raminit; + priv->raminit = c_can_hw_raminit_ti; break; default: ret = -EINVAL;