issues while porting clocks in linux kernel (4.9)

2

I am trying to port system clocks for custom SoC into linux kernel (4.9). I had setup a minimal lookup table with crystal Osc, pll & spi as below:

static struct clk_lookup clocks[] = {
        CLKDEV_INIT(NULL,           "ref",              &ref_clk),
        CLKDEV_INIT(NULL,           "pll1",             &pll1_clk),
        CLKDEV_INIT(NULL,           "apb_pclk",         &apb_clk),
        CLKDEV_INIT("spi0",         NULL,               &spi_clk),
};

and im trying to add clocks using func:

int __init clocks_init(void)
{
    clkdev_add_table(clocks, ARRAY_SIZE(clocks));
};

But my booting fails while trying to setup clocks. below is the error:

Unable to handle kernel NULL pointer dereference at virtual address 00000008
[    0.000000]` pgd = c0004000
[    0.000000] [00000008] *pgd=00000000
[    0.000000] Internal error: Oops: 5 [#1] ARM
[    0.000000] Modules linked in:
[    0.000000] CPU: 0 PID: 1 Comm: swapper Not tainted 4.9.22+ #22
[    0.000000] Hardware name: CUSTOMSOC
[    0.000000] task: c6898000 task.stack: c688e000
[    0.000000] PC is at __clk_get_hw+0x1c/0x24
[    0.000000] LR is at clkdev_add_table+0x40/0x78
[    0.000000] pc : [<c025ce40>]    lr : [<c025cda8>]    psr: a0000053
[    0.000000] sp : c688fe58  ip : c688fe68  fp : c688fe64
[    0.000000] r10: 00000000  r9 : 0000003d  r8 : c04867f0
[    0.000000] r7 : c04ea720  r6 : c04ea714  r5 : 00000004  r4 : c04cbf50
[    0.000000] r3 : 00000000  r2 : 00000000  r1 : 00000004  r0 : c04cbf98
[    0.000000] Flags: NzCv  IRQs on  FIQs off  Mode SVC_32  ISA ARM  Segment user
[    0.000000] Control: 00c5387d  Table: c0004008  DAC: 00000055
[    0.000000] Process swapper (pid: 1, stack limit = 0xc688e188)
[    0.000000] Stack: (0xc688fe58 to 0xc6890000)
[    0.000000] fe40:                                                       c688fe84 c688fe68
[    0.000000] fe60: c025cda8 c025ce30 00000000 c8905000 c0501020 c04ae820 c688fea4 c688fe88
[    0.000000] fe80: c048a6d8 c025cd74 00000000 c03004d4 c04ca798 c04cd718 c688febc c688fea8
[    0.000000] fea0: c048a4a8 c048a62c c04c27f8 00000003 c688fecc c688fec0 c0486814 c048a49c
[    0.000000] fec0: c688ff4c c688fed0 c0009a6c c04867fc c0483614 c02268b8 00000000 c0434e84
[    0.000000] fee0: c6fffe00 c032ca2c c688ff4c c688fef8 c003e5f4 c0483604 c0050050 c00bb438
[    0.000000] ff00: 00000000 c030f938 00000003 00000003 00000000 c04349c0 c03d2654 00000000
[    0.000000] ff20: c688ff4c c04c27f8 00000003 c0501020 c04ae820 00000000 0000003d c04ae838
[    0.000000] ff40: c688ff94 c688ff50 c0483ec0 c0009a2c 00000003 00000003 00000000 c04835f8
[    0.000000] ff60: 9d322010 62802229 20a41903 00000000 c030cc94 00000000 00000000 00000000
[    0.000000] ff80: 00000000 00000000 c688ffac c688ff98 c030ccac c0483d48 ffffffff 00000000
[    0.000000] ffa0: 00000000 c688ffb0 c00107c8 c030cca0 00000000 00000000 00000000 00000000
[    0.000000] ffc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[    0.000000] ffe0: 00000000 00000000 00000000 00000000 00000013 00000000 0114212a 8dce8aa8
[    0.000000] [<c025ce40>] (__clk_get_hw) from [<c025cda8>] (clkdev_add_table+0x40/0x78)
[    0.000000] [<c025cda8>] (clkdev_add_table) from [<c048a6d8>] (bbsoc_clocks_init+0xb8/0xec)
[    0.000000] [<c048a6d8>] (clocks_init) from [<c048a4a8>] (bcm2835_init+0x18/0x74)
[    0.000000] [<c048a4a8>] (board_init) from [<c0486814>] (customize_machine+0x24/0x30)
[    0.000000] [<c0486814>] (customize_machine) from [<c0009a6c>] (do_one_initcall+0x4c/0x180)
[    0.000000] [<c0009a6c>] (do_one_initcall) from [<c0483ec0>] (kernel_init_freeable+0x184/0x254)
[    0.000000] [<c0483ec0>] (kernel_init_freeable) from [<c030ccac>] (kernel_init+0x18/0x114)
[    0.000000] [<c030ccac>] (kernel_init) from [<c00107c8>] (ret_from_fork+0x14/0x2c)
[    0.000000] Code: e52de004 e8bd4000 e3500000 15903000 (15930008) 
[    0.000000] ---[ end trace 671b49261be9dc6a ]---
[    0.000000] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b

upon investigation func: __clk_get_hw(cl->clk); is trying to access clk->core->hw (This is where exactly it is failing!)

struct clk_hw *__clk_get_hw(struct clk *clk)
{               
        return !clk ? NULL : clk->core->hw;
}
EXPORT_SYMBOL_GPL(__clk_get_hw);

Any suggestions on setting up clock configuration into linux kernel, would be highly helpful. Thanks, Vivek

linux
linux-kernel
embedded-linux
asked on Stack Overflow Sep 17, 2017 by user7836120 • edited Sep 17, 2017 by user7836120

1 Answer

0

Issue got resolved upon programming complete clock driver specific to SoC. 1. Firstly bus clock to be registered, it depends on input PLL clocks and the dividers or multipliers it has encountered. The info regarding dividers and multipliers can be found in sys-control registers. Once all the buses (ex: ahb, apb) got registered.

hw = clk_hw_register_fixed_rate(NULL, "ref", NULL, 0, 40MHZ); //setting 
   if (IS_ERR(hw))
      pr_err("xtal clock not registered\n");

hw = clk_hw_register_fixed_rate(NULL, "pll_clk", "ref", 0, 800MHZ);
   if (IS_ERR(hw))
      pr_err("pll_clk not registered\n");

hw = clk_hw_register_fixed_rate(NULL, "ahb_clk", "pll_clk", 0, 100MHZ);
   if (IS_ERR(hw))
      pr_err("ahb_clk not registered\n");

peripheral oriented clock can be specified as, here i am trying to register dma clock. which is mounted on AHB bus.

static struct clk dma1_clk = {
        .name           = "xyz.dma",
        .parent         = &ahb_clk,
        .rate           = FREQ_200MHZ,
};

later the clock structure with respect peripheral can be registered as

hw = clk_hw_register_fixed_rate(NULL, c->dev_id, "ahb_clk", 0, temp_clk->rate);
if (IS_ERR(hw))
   pr_err("Device Hw:%s not registered\n", c->dev_id);

ret = clk_hw_register_clkdev(hw, NULL, c->dev_id);
if (ret)
   pr_err("Device:%s not registered\n", c->dev_id);

The clock infra setup for peripheral in SoC can be done through Device tree as well.

Thanks to @0andriy for responding over the post.

Thanks.

answered on Stack Overflow Jan 24, 2019 by user7836120

User contributions licensed under CC BY-SA 3.0