Increasing CAN clock frequency of i.MX6 on kernel 3.10

cancel
Showing results for 
Search instead for 
Did you mean: 

Increasing CAN clock frequency of i.MX6 on kernel 3.10

Jump to solution
1,720 Views
isaacnickaein
Contributor III

I am trying to configure CAN interface of i.MX6 to work at the bitrate of 800Kb/s in Kernel 3.10.53. The default clock frequency of CAN driver is 30Mhz which causes bitrate error of 1.3%:

#canconfig can1 bitrate 800000

can1 bitrate: 789473, sample-point: 0.789

flexcan 2094000.flexcan can1: bitrate error 1.3%

More details on this issue and what I have tried comes in the following:

To solve this issue, I have to increase the clock frequency of CAN to be a multiple of 800Khz (I guess?). It seems the clock setup for i.MX6 is done in arch/arm/mach-imx/clk-imx6q.c. The lines related to CAN clock are:

    clk[can_root]     = imx_clk_divider("can_root",    "pll3_60m",          base + 0x20, 2,  6);

    clk[can1_ipg]     = imx_clk_gate2("can1_ipg",      "ipg",               base + 0x68, 14);

    clk[can1_serial]  = imx_clk_gate2("can1_serial",   "can_root",          base + 0x68, 16);

    clk[can2_ipg]     = imx_clk_gate2("can2_ipg",      "ipg",               base + 0x68, 18);

    clk[can2_serial]  = imx_clk_gate2("can2_serial",   "can_root",          base + 0x68, 20);

One solution I came up with was to change the settings for can_root clock from pll3_60m to pll3_120m. With this change, the canconfig will report the correct bitrate (800Kb instead of ~789Kb) and there is no warning about bitrate error. HOWEVER, the i.MX6 still cannot receive any can packets and goes to BUS-OFF mode.

This result is very similar to what I got in kernel 3.0.35 before, when I did the similar thing in arch/arm/clock.c file. I guess I am missing some architectural limitation in i.MX6 clocking that causes this solution to fail.

What we ended up in kernel 3.0.35 was to set the clock rate explicitly during initialization by:

clk_set_rate(&can_clk_root, 60000000);

This hack solved the issue and i.MX6 could send and receive CAN packets on 800Kb/s successfully.

I am looking for the right approach to increase CAN clock frequency to support 800Kb/s on Kernel 3.10, or a similar hack for this kernel.

Labels (3)
0 Kudos
1 Solution
548 Views
isaacnickaein
Contributor III

Hi Alejandro,

Sorry for the delay. Yes, I solved the issue by setting the CAN_CLK_PODF bits in CSCMR2 to 000000 register:

    unsigned long reg;

    reg = readl(base + 0x20);

    reg &= 0xFFFFFF03;

    writel(reg, base + 0x20);

which means the value of divider of parent CAN clock will be 1, so parent clock of can will be 60Mhz. (More information: i.MX6 Reference Manual, 18.6.9 CCM Serial Clock Multiplexer Register 2 (CCM_CSCMR2))

Do you recommend this approach? BTW, what is difference between writel and writel_relaxed? Are there any other variations? Where is this all documented?

View solution in original post

0 Kudos
6 Replies
548 Views
arashjavanmard
Contributor I

Hi,

i am already facing with the same problem in kernel 3.14.28.

i tried also to change the 'can_clk_podf'-Register in 'CCM_CSCMR2' to 0x0, as described here and in Technical ref. man. of imx6q, but

i am still getting the 1.6% bitrate erorr. Surprisingly can-clock seems to be still at 30MHz, even after setting  'can_clk_podf' to 0x00!!!

According to Kernel source linux-imx6/clk-imx6q.c at boundary-imx_3.14.28_1.0.0_ga · boundarydevices/linux-imx6 · GitHub:

clk[IMX6QDL_CLK_CAN_ROOT]     = imx_clk_divider("can_root",     "pll3_60m",      base + 0x20, 2,  6);

with prev. settings i thought my CAN-Clock should be now at 60Mhz!!

BUT:

--------------------------------------------------------------------------------

#~ ip -d link show can0

2: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN mode DE2

    link/can  promiscuity 0                                                   

    can state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 100            

          bitrate 789473 sample-point 0.789                                   

          tq 66 prop-seg 7 phase-seg1 7 phase-seg2 4 sjw 1                    

          flexcan: tseg1 4..16 tseg2 2..8 sjw 1..4 brp 1..256 brp-inc 1       

          clock 30000000

--------------------------------------------------------------------------------

am i missing something??

0 Kudos
548 Views
isaacnickaein
Contributor III

Hi Arash,

We haven't switched to 3.14.28 for the production, but as far as I remember we used the same solution as kernel 3.10 to solve the CAN bitrate issue. We have tested this on Ka-Ro TX6U module (which is based on i.MX6DL). Which module are you using? Also, if you could boot kernel 3.10 on your module, it worth giving it a try to see how this solution works out.

The registry I have mentioned doesn't increase the base clock frequency of CAN. It just sets a clock divider to be 1 (instead of 2).

Here is my CAN1 configuration:

root@imx6qsabresd:~# canconfig can1

can1 bitrate: 800000, sample-point: 0.800

can1 bittiming:

    tq: 83, prop-seq: 5 phase-seq1: 6 phase-seq2: 3 sjw: 1, brp: 5

can1 state: ERROR-ACTIVE

can1 restart-ms: 0

can1 ctrlmode: loopback[OFF], listen-only[OFF], tripple-sampling[OFF],one-shot[OFF], berr-reporting[OFF]

can1 clock freq: 60000000

can1 bittiming-constants: name flexcan,

    tseg1-min: 4, tseg1-max: 16, tseg2-min: 2, tseg2-max: 8,

    sjw-max 4, brp-min: 1, brp-max: 256, brp-inc: 1,

And here is the clock configuration related to CAN:

root@imx6qsabresd:~# cat /sys/kernel/debug/clk/clk_summary | grep can

          can_root              1           1            60000000 

             can2_serial        1           1            60000000 

             can1_serial        0           0            60000000 

                      can2_ipg  1           1            66000000 

                      can1_ipg  0           0            66000000

Hope this helps,

0 Kudos
548 Views
alejandrolozan1
NXP Employee
NXP Employee

Hi,

Were you able to solve the problem?

/Alejandro

0 Kudos
549 Views
isaacnickaein
Contributor III

Hi Alejandro,

Sorry for the delay. Yes, I solved the issue by setting the CAN_CLK_PODF bits in CSCMR2 to 000000 register:

    unsigned long reg;

    reg = readl(base + 0x20);

    reg &= 0xFFFFFF03;

    writel(reg, base + 0x20);

which means the value of divider of parent CAN clock will be 1, so parent clock of can will be 60Mhz. (More information: i.MX6 Reference Manual, 18.6.9 CCM Serial Clock Multiplexer Register 2 (CCM_CSCMR2))

Do you recommend this approach? BTW, what is difference between writel and writel_relaxed? Are there any other variations? Where is this all documented?

View solution in original post

0 Kudos
548 Views
alejandrolozan1
NXP Employee
NXP Employee

Hi,

That is great news!!

I found this in the kernel documentation:

readX_relaxed(), writeX_relaxed()

  These are similar to readX() and writeX(), but provide weaker memory

  ordering guarantees. Specifically, they do not guarantee ordering with

  respect to normal memory accesses (e.g. DMA buffers) nor do they guarantee

  ordering with respect to LOCK or UNLOCK operations. If the latter is

  required, an mmiowb() barrier can be used. Note that relaxed accesses to

  the same peripheral are guaranteed to be ordered with respect to each

  other.

You can find more detials at:

https://www.kernel.org/doc/Documentation/memory-barriers.txt

/Alejandro

548 Views
alejandrolozan1
NXP Employee
NXP Employee

Hi,

Are you able to transmit data correctly? Have you checked that the bitrate is correctly with a scope?

Best Regards,

Alejandro

0 Kudos