2019-08-08 21:46:00

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH 21/22] ARM: omap1: use common clk framework

The omap1 clock driver now uses types and calling conventions
that are compatible with the common clk core.

Turn on CONFIG_COMMON_CLK and remove all the code that is
now duplicated.

Note: if this previous steps didn't already break it, this one
most likely will, because the interfaces are very likely to
have different semantics.

Signed-off-by: Arnd Bergmann <[email protected]>
---
arch/arm/Kconfig | 1 +
arch/arm/mach-omap1/clock.c | 413 +-----------------------------------
2 files changed, 4 insertions(+), 410 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0febd7a1d65f..17a21f75f386 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -496,6 +496,7 @@ config ARCH_OMAP1
select ARCH_OMAP
select CLKDEV_LOOKUP
select CLKSRC_MMIO
+ select COMMON_CLK
select FORCE_PCI if PCCARD
select GENERIC_CLOCKEVENTS
select GENERIC_IRQ_CHIP
diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
index a951c787adb4..1f105c659e7e 100644
--- a/arch/arm/mach-omap1/clock.c
+++ b/arch/arm/mach-omap1/clock.c
@@ -10,6 +10,7 @@
*/
#include <linux/kernel.h>
#include <linux/export.h>
+#include <linux/clk-provider.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
@@ -52,32 +53,6 @@ struct omap1_clk_lookup {
#define CK_16XX (1 << 3) /* 16xx, 17xx, 5912 */
#define CK_1710 (1 << 4) /* 1710 extra for rate selection */

-/**
- * struct clk_ops - some clock function pointers
- * @enable: fn ptr that enables the current clock in hardware
- * @disable: fn ptr that enables the current clock in hardware
- * @recalc_rate: fn ptr that returns the clock's current rate
- * @set_rate: fn ptr that can change the clock's current rate
- * @round_rate: fn ptr that can round the clock's current rate
- * @init: fn ptr to do clock-specific initialization
- *
- * A "companion" clk is an accompanying clock to the one being queried
- * that must be enabled for the IP module connected to the clock to
- * become accessible by the hardware. Neither @find_idlest nor
- * block-specific; the hwmod code has been created to handle this, but
- * until hwmod data is ready and drivers have been converted to use PM
- * runtime calls in place of clk_enable()/clk_disable(), @find_idlest and
- * @find_companion must, unfortunately, remain.
- */
-struct clk_ops {
- int (*enable)(struct clk_hw *);
- void (*disable)(struct clk_hw *);
- unsigned long (*recalc_rate)(struct clk_hw *, unsigned long);
- int (*set_rate)(struct clk_hw *, unsigned long, unsigned long);
- long (*round_rate)(struct clk_hw *, unsigned long, unsigned long *);
- void (*init)(struct clk_hw *);
-};
-
/*
* struct omap1_clk.flags possibilities
*
@@ -90,12 +65,8 @@ struct clk_ops {

/**
* struct omap1_clk - OMAP struct clk
- * @node: list_head connecting this clock into the full clock list
* @ops: struct clkops * for this clock
* @name: the name of the clock in the hardware (used in hwmod data and debug)
- * @parent: pointer to this clock's parent struct clk
- * @children: list_head connecting to the child clks' @sibling list_heads
- * @sibling: list_head connecting this clk to its parent clk's @children
* @rate: current clock rate
* @enable_reg: register to write to enable the clock (see @enable_bit)
* @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg)
@@ -115,38 +86,13 @@ struct clk_ops {
* clocks and decremented by the clock code when clk_disable() is
* called on child clocks.
*
- * XXX @clkdm, @usecount, @children, @sibling should be marked for
- * internal use only.
- *
- * @children and @sibling are used to optimize parent-to-child clock
- * tree traversals. (child-to-parent traversals use @parent.)
+ * XXX @usecount should be marked for internal use only.
*
* XXX The notion of the clock's current rate probably needs to be
* separated from the clock's target rate.
*/
-struct clk {
- struct clk_hw *clk_hw;
-};
-
-struct clk_init_data {
- const char *name;
- const struct clk_ops *ops;
- const struct clk_hw **parent_hws;
- u8 num_parents;
- unsigned long flags;
-};
-
-struct clk_hw {
- struct clk clk;
- const struct clk_init_data *init;
-};
-
struct omap1_clk {
struct clk_hw clk_hw;
- struct list_head node;
- struct omap1_clk *parent;
- struct list_head children;
- struct list_head sibling; /* node for children */
unsigned long rate;
void __iomem *enable_reg;
u8 enable_bit;
@@ -267,10 +213,6 @@ static u32 cpu_mask;
__u32 arm_idlect1_mask;
static struct clk_hw *api_ck_p, *ck_dpll1_p, *ck_ref_p;

-static LIST_HEAD(clocks);
-static DEFINE_MUTEX(clocks_mutex);
-static DEFINE_SPINLOCK(clockfw_lock);
-
/*
* Omap1 specific clock functions
*/
@@ -677,16 +619,6 @@ static void omap1_init_ext_clk(struct clk_hw *clk_hw)
clk-> rate = 96000000 / dsor;
}

-struct clk_hw *clk_hw_get_parent(const struct clk_hw *clk_hw)
-{
- struct omap1_clk *clk = to_omap1_clk(clk_hw);
-
- if (!clk->parent)
- return NULL;
-
- return &clk->parent->clk_hw;
-}
-
static void omap1_clk_disable(struct clk_hw *clk_hw)
{
struct omap1_clk *clk = to_omap1_clk(clk_hw);
@@ -860,173 +792,11 @@ static const struct clk_ops clkops_uart_16xx = {
.disable = omap1_clk_disable_uart_functional_16xx,
};

-static long omap1_clk_round_rate(struct clk_hw *clk_hw, unsigned long rate)
-{
- struct omap1_clk *clk = to_omap1_clk(clk_hw);
- struct clk_hw *parent = clk_hw_get_parent(clk_hw);
- struct omap1_clk *parent_clk;
- unsigned long parent_rate = 0;
-
- if (parent) {
- parent_clk = to_omap1_clk(parent);
- parent_rate = parent_clk->rate;
- }
-
- if (clk_hw->init->ops->round_rate != NULL)
- return clk_hw->init->ops->round_rate(clk_hw, rate, &parent_rate);
-
- if (parent)
- parent_clk->rate = parent_rate;
-
- return clk->rate;
-}
-
-static int omap1_clk_set_rate(struct clk_hw *clk_hw, unsigned long rate)
-{
- struct clk_hw *parent = clk_hw_get_parent(clk_hw);
- unsigned long parent_rate = 0;
- int ret = -EINVAL;
-
- if (parent)
- parent_rate = to_omap1_clk(parent)->rate;
-
- if (clk_hw->init->ops->set_rate)
- ret = clk_hw->init->ops->set_rate(clk_hw, rate, parent_rate);
-
- return ret;
-}
-
/* Propagate rate to children */
static void propagate_rate(struct omap1_clk *tclk)
{
- struct omap1_clk *clkp;
-
- list_for_each_entry(clkp, &tclk->children, sibling) {
- if (clkp->clk_hw.init->ops->recalc_rate)
- clkp->rate = clkp->clk_hw.init->ops->recalc_rate(&clkp->clk_hw, tclk->rate);
- propagate_rate(clkp);
- }
-}
-
-/*
- * Omap1 clock reset and init functions
- */
-
-int clk_enable(struct clk *clk)
-{
- unsigned long flags;
- int ret;
-
- if (clk == NULL || IS_ERR(clk))
- return -EINVAL;
-
- spin_lock_irqsave(&clockfw_lock, flags);
- ret = omap1_clk_enable(clk->clk_hw);
- spin_unlock_irqrestore(&clockfw_lock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *clk)
-{
- unsigned long flags;
- struct omap1_clk *_clk = to_omap1_clk(clk->clk_hw);
-
- if (clk == NULL || IS_ERR(clk))
- return;
-
- spin_lock_irqsave(&clockfw_lock, flags);
- if (_clk->usecount == 0) {
- pr_err("Trying disable clock %s with 0 usecount\n",
- _clk->clk_hw.init->name);
- WARN_ON(1);
- goto out;
- }
-
- omap1_clk_disable(clk->clk_hw);
-
-out:
- spin_unlock_irqrestore(&clockfw_lock, flags);
-}
-EXPORT_SYMBOL(clk_disable);
-
-unsigned long clk_get_rate(struct clk *clk)
-{
- unsigned long flags;
- unsigned long ret;
-
- if (clk == NULL || IS_ERR(clk))
- return 0;
-
- spin_lock_irqsave(&clockfw_lock, flags);
- ret = to_omap1_clk(clk->clk_hw)->rate;
- spin_unlock_irqrestore(&clockfw_lock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-/*
- * Optional clock functions defined in include/linux/clk.h
- */
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
- unsigned long flags;
- long ret;
-
- if (clk == NULL || IS_ERR(clk))
- return 0;
-
- spin_lock_irqsave(&clockfw_lock, flags);
- ret = omap1_clk_round_rate(clk->clk_hw, rate);
- spin_unlock_irqrestore(&clockfw_lock, flags);
-
- return ret;
+ clk_set_rate(tclk->clk_hw.clk, tclk->rate);
}
-EXPORT_SYMBOL(clk_round_rate);
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
- unsigned long flags;
- int ret = -EINVAL;
-
- if (clk == NULL || IS_ERR(clk))
- return ret;
-
- spin_lock_irqsave(&clockfw_lock, flags);
- ret = omap1_clk_set_rate(clk->clk_hw, rate);
- if (ret == 0)
- propagate_rate(to_omap1_clk(clk->clk_hw));
- spin_unlock_irqrestore(&clockfw_lock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
- WARN_ONCE(1, "clk_set_parent() not implemented for OMAP1\n");
-
- return -EINVAL;
-}
-EXPORT_SYMBOL(clk_set_parent);
-
-struct clk *clk_get_parent(struct clk *clk)
-{
- struct clk_hw *parent = clk_hw_get_parent(clk->clk_hw);
-
- if (!parent)
- return NULL;
-
- return &parent->clk;
-}
-EXPORT_SYMBOL(clk_get_parent);
-
-/*
- * OMAP specific clock functions shared between omap1 and omap2
- */

/* Used for clocks that always have same value as the parent clock */
static unsigned long followparent_recalc(struct clk_hw *clk_hw, unsigned long parent_rate)
@@ -1047,47 +817,6 @@ static unsigned long omap_fixed_divisor_recalc(struct clk_hw *clk_hw, unsigned l
return parent_rate / clk->fixed_div;
}

-/**
- * clk_preinit - initialize any fields in the struct omap1_clk before clk init
- * @clk: struct omap1_clk * to initialize
- *
- * Initialize any struct omap1_clk fields needed before normal clk initialization
- * can run. No return value.
- */
-static void clk_preinit(struct omap1_clk *clk)
-{
- INIT_LIST_HEAD(&clk->children);
-}
-
-static int clk_register(struct device *dev, struct clk_hw *clk_hw)
-{
- struct omap1_clk *clk = to_omap1_clk(clk_hw);
-
- if (clk == NULL || IS_ERR(clk))
- return -EINVAL;
-
- /*
- * trap out already registered clocks
- */
- if (clk->node.next || clk->node.prev)
- return 0;
-
- clk_hw->clk.clk_hw = clk_hw;
-
- mutex_lock(&clocks_mutex);
- if (clk_hw->init->num_parents) {
- clk->parent = to_omap1_clk(clk_hw->init->parent_hws[0]);
- list_add(&clk->sibling, &clk->parent->children);
- }
-
- list_add(&clk->node, &clocks);
- if (clk_hw->init->ops->init)
- clk_hw->init->ops->init(clk_hw);
- mutex_unlock(&clocks_mutex);
-
- return 0;
-}
-
/*
* Low level helpers
*/
@@ -1135,139 +864,6 @@ static struct omap1_clk dummy_ck = {
CLK_INIT_ROOT("dummy", &clkops_null),
};

-/*
- *
- */
-
-#ifdef CONFIG_OMAP_RESET_CLOCKS
-/*
- * Disable any unused clocks left on by the bootloader
- */
-static void omap1_clk_disable_unused(struct omap1_clk *clk)
-{
- __u32 regval32;
-
- /* Clocks in the DSP domain need api_ck. Just assume bootloader
- * has not enabled any DSP clocks */
- if (clk->enable_reg == DSP_IDLECT2) {
- pr_info("Skipping reset check for DSP domain clock \"%s\"\n",
- clk->clk_hw.init->name);
- return;
- }
-
- /* Is the clock already disabled? */
- if (clk->flags & ENABLE_REG_32BIT)
- regval32 = __raw_readl(clk->enable_reg);
- else
- regval32 = __raw_readw(clk->enable_reg);
-
- if ((regval32 & (1 << clk->enable_bit)) == 0)
- return;
-
- printk(KERN_INFO "Disabling unused clock \"%s\"... ", clk->clk_hw.init->name);
- clk->clk_hw.init->ops->disable(&clk->clk_hw);
- printk(" done\n");
-}
-
-static int __init clk_disable_unused(void)
-{
- struct omap1_clk *ck;
- unsigned long flags;
-
- pr_info("clock: disabling unused clocks to save power\n");
-
- spin_lock_irqsave(&clockfw_lock, flags);
- list_for_each_entry(ck, &clocks, node) {
- if (ck->clk_hw.init->ops == &clkops_null)
- continue;
-
- if (ck->usecount > 0 || !ck->enable_reg)
- continue;
-
- omap1_clk_disable_unused(ck);
- }
- spin_unlock_irqrestore(&clockfw_lock, flags);
-
- return 0;
-}
-late_initcall(clk_disable_unused);
-#endif
-
-#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
-/*
- * debugfs support to trace clock tree hierarchy and attributes
- */
-
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-static struct dentry *clk_debugfs_root;
-
-static int debug_clock_show(struct seq_file *s, void *unused)
-{
- struct omap1_clk *c;
- struct omap1_clk *pa;
-
- mutex_lock(&clocks_mutex);
- seq_printf(s, "%-30s %-30s %-10s %s\n",
- "clock-name", "parent-name", "rate", "use-count");
-
- list_for_each_entry(c, &clocks, node) {
- pa = c->parent;
- seq_printf(s, "%-30s %-30s %-10lu %d\n",
- c->name, pa ? pa->name : "none", c->rate,
- c->usecount);
- }
- mutex_unlock(&clocks_mutex);
-
- return 0;
-}
-
-DEFINE_SHOW_ATTRIBUTE(debug_clock);
-
-static void clk_debugfs_register_one(struct omap1_clk *c)
-{
- struct dentry *d;
- struct omap1_clk *pa = c->parent;
-
- d = debugfs_create_dir(c->name, pa ? pa->dent : clk_debugfs_root);
- c->dent = d;
-
- debugfs_create_u8("usecount", S_IRUGO, c->dent, &c->usecount);
- debugfs_create_ulong("rate", S_IRUGO, c->dent, &c->rate);
- debugfs_create_x8("flags", S_IRUGO, c->dent, &c->flags);
-}
-
-static void clk_debugfs_register(struct omap1_clk *c)
-{
- struct omap1_clk *pa = c->parent;
-
- if (pa && !pa->dent)
- clk_debugfs_register(pa);
-
- if (!c->dent)
- clk_debugfs_register_one(c);
-}
-
-static int __init clk_debugfs_init(void)
-{
- struct omap1_clk *c;
- struct dentry *d;
-
- d = debugfs_create_dir("clock", NULL);
- clk_debugfs_root = d;
-
- list_for_each_entry(c, &clocks, node)
- clk_debugfs_register(c);
-
- debugfs_create_file("summary", S_IRUGO, d, NULL, &debug_clock_fops);
-
- return 0;
-}
-late_initcall(clk_debugfs_init);
-
-#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */
-
/*
* Omap1 clocks
*/
@@ -1897,9 +1493,6 @@ int __init omap1_clk_init(void)
/* By default all idlect1 clocks are allowed to idle */
arm_idlect1_mask = ~0;

- for (c = omap_clks; c < omap_clks + ARRAY_SIZE(omap_clks); c++)
- clk_preinit(to_omap1_clk(c->lk.clk_hw));
-
cpu_mask = 0;
if (cpu_is_omap1710())
cpu_mask |= CK_1710;
--
2.20.0


2019-08-14 22:55:25

by Aaro Koskinen

[permalink] [raw]
Subject: Re: [PATCH 21/22] ARM: omap1: use common clk framework

Hi,

On Thu, Aug 08, 2019 at 11:43:39PM +0200, Arnd Bergmann wrote:
> The omap1 clock driver now uses types and calling conventions
> that are compatible with the common clk core.
>
> Turn on CONFIG_COMMON_CLK and remove all the code that is
> now duplicated.
>
> Note: if this previous steps didn't already break it, this one
> most likely will, because the interfaces are very likely to
> have different semantics.

QEMU SX1 board works up to this patch (the I/O virtual address change
included). With this patch, it seems to fail to allocate memory during
omap1_init_early() (the log is a bit messy as I extracted it using QEMU
memory dumping):

swapper: page allocation failure: order:0, mode:0x0(), nodemask=(null)
CPU: 0 PID: 0 Comm: swapper Not tainted 5.3.0-rc4-sx1-los_80efa++ #1
Hardware name: OMAP310 based Siemens SX1
[<c000dc44>] (unwind_backtrace) from [<c000cb00>] (show_stack+0x10/0x18)
[<c000cb00>] (show_stack) from [<c0172ba8>] (dump_stack+0x18/0x24)
[<c0172ba8>] (dump_stack) from [<c00844e8>] (warn_alloc+0x90/0x140)
[<c00844e8>] (warn_alloc) from [<c0084dcc>] (__alloc_pages_nodemask+0x7a4/0x9cc)
[<c0084dcc>] (__alloc_pages_nodemask) from [<c008df24>] (slob_new_pages.constpro
p.2+0x10/0x3c)
[<c008df24>] (slob_new_pages.constprop.2) from [<c008e208>] (slob_alloc.constprop.1+0xe4/0x1e8)
[<c008e208>] (slob_alloc.constprop.1) from [<c008e344>] (__kmalloc+0x38/0xb0)
[<c008e344>] (__kmalloc) from [<c0126514>] (__clk_register+0x20/0x62c)
[<c0126514>] (__clk_register) from [<c01f6614>] (omap1_clk_init+0x88/0x220)
[<c01f6614>] (omap1_clk_init) from [<c01f5820>] (omap1_init_early+0x20/0x30)
[<c01f5820>] (omap1_init_early) from [<c01f09e8>] (start_kernel+0x48/0x408)
[<c01f09e8>] (start_kernel) from [<00000000>] (0x0)
Clocks: ARM_SYSST: 0x003a DPLL_CTL: 0x2002 ARM_CKCTL: 0x3000
Clocking rate (xtal/DPLL1/MPU): 12.0/12.0/0.0 MHz
"8<--- cut here ---
"Unable to handle kernel NULL pointer dereference at virtual address 00000018
"pgd = (ptrval)
"[00000018] *pgd=00000000
Internal error: Oops: 5 [#1] ARM
CPU: 0 PID: 0 Comm: swapper Not tainted 5.3.0-rc4-sx1-los_80efa++ #1
Hardware name: OMAP310 based Siemens SX1
PC is at clk_hw_get_parent+0x4/0x14
LR is at omap1_clk_enable+0xc/0xcc
OMAP310 based Siemens SX1
[ 0.000000] free:0 free_pcp:0 free_cma:0
pc : [<c0126cd0>] lr : [<c00128d4>] psr: 600001d3
sp : c03aff88 ip : 00000000 fp : 00000000
r10: 00000001 r9 : 54029252 r8 : 10000100
r7 : c03b1000 r6 : 00002002 r5 : 0000003a r4 : c03b5444
r3 : 00000000 r2 : c03b9818 r1 : ff03ce08 r0 : c03b5444
Flags: nZCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment user
Control: 0000317f Table: 10004000 DAC: 00000055
Process swapper (pid: 0, stack limit = 0x(ptrval))
Stack: (0xc03aff88 to 0xc03b0000)
ff80: c03b5438 0000003a 00002002 c01f6734 00000000 00000057
ffa0: 0000313d c01f5820 00000000 c01f09e8 00000000 00000000 00000000 00000000
ffc0: 00000000 00000000 00000000 c0201a38 00000000 c01f0330 00000057 0000313d
ffe0: 00000265 10000100 54029252 0000317f 00000000 00000000 00000000 00000000
[<c0126cd0>] (clk_hw_get_parent) from [<c00128d4>] (omap1_clk_enable+0xc/0xcc)
[<c00128d4>] (omap1_clk_enable) from [<c01f6734>] (omap1_clk_init+0x1a8/0x220)
[<c01f6734>] (omap1_clk_init) from [<c01f5820>] (omap1_init_early+0x20/0x30)
[<c01f5820>] (omap1_init_early) from [<c01f09e8>] (start_kernel+0x48/0x408)
[<c01f09e8>] (start_kernel) from [<00000000>] (0x0)

A.

2019-08-15 07:38:00

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 21/22] ARM: omap1: use common clk framework

On Wed, Aug 14, 2019 at 11:10 PM Aaro Koskinen <[email protected]> wrote:
>
> Hi,
>
> On Thu, Aug 08, 2019 at 11:43:39PM +0200, Arnd Bergmann wrote:
> > The omap1 clock driver now uses types and calling conventions
> > that are compatible with the common clk core.
> >
> > Turn on CONFIG_COMMON_CLK and remove all the code that is
> > now duplicated.
> >
> > Note: if this previous steps didn't already break it, this one
> > most likely will, because the interfaces are very likely to
> > have different semantics.
>
> QEMU SX1 board works up to this patch (the I/O virtual address change
> included). With this patch, it seems to fail to allocate memory during
> omap1_init_early() (the log is a bit messy as I extracted it using QEMU
> memory dumping):

That sounds pretty good, I definitely did not expect this patch
to work without first dealing with a few bugs, and it it did not break
earlier, I'm willing to call that success ;-)

Unfortunately, doing it in qemu does not guarantee that the clocks
are set up right at this point: if any of the clocks are disabled when
they should not be, qemu won't care as much as real hardware would.

> swapper: page allocation failure: order:0, mode:0x0(), nodemask=(null)
> CPU: 0 PID: 0 Comm: swapper Not tainted 5.3.0-rc4-sx1-los_80efa++ #1
> Hardware name: OMAP310 based Siemens SX1
> [<c000dc44>] (unwind_backtrace) from [<c000cb00>] (show_stack+0x10/0x18)
> [<c000cb00>] (show_stack) from [<c0172ba8>] (dump_stack+0x18/0x24)
> [<c0172ba8>] (dump_stack) from [<c00844e8>] (warn_alloc+0x90/0x140)
> [<c00844e8>] (warn_alloc) from [<c0084dcc>] (__alloc_pages_nodemask+0x7a4/0x9cc)
> [<c0084dcc>] (__alloc_pages_nodemask) from [<c008df24>] (slob_new_pages.constpro
> p.2+0x10/0x3c)
> [<c008df24>] (slob_new_pages.constprop.2) from [<c008e208>] (slob_alloc.constprop.1+0xe4/0x1e8)
> [<c008e208>] (slob_alloc.constprop.1) from [<c008e344>] (__kmalloc+0x38/0xb0)
> [<c008e344>] (__kmalloc) from [<c0126514>] (__clk_register+0x20/0x62c)
> [<c0126514>] (__clk_register) from [<c01f6614>] (omap1_clk_init+0x88/0x220)
> [<c01f6614>] (omap1_clk_init) from [<c01f5820>] (omap1_init_early+0x20/0x30)
> [<c01f5820>] (omap1_init_early) from [<c01f09e8>] (start_kernel+0x48/0x408)
> [<c01f09e8>] (start_kernel) from [<00000000>] (0x0)
> Clocks: ARM_SYSST: 0x003a DPLL_CTL: 0x2002 ARM_CKCTL: 0x3000
> Clocking rate (xtal/DPLL1/MPU): 12.0/12.0/0.0 MHz

Ok, so here the problem is that we call the omap1_clk_init() function from
setup_arch(), which is before we can even allocate memory with kmalloc.

Most other machines do it from init_time(), which comes after the initialization
of the memory allocator.

Something like this would be needed:

diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
index b0465a956ea8..17ba8dfd8e19 100644
--- a/arch/arm/mach-omap1/io.c
+++ b/arch/arm/mach-omap1/io.c
@@ -125,9 +125,6 @@ void __init omap1_init_early(void)
omap_writew(0x0, MPU_PUBLIC_TIPB_CNTL);
omap_writew(0x0, MPU_PRIVATE_TIPB_CNTL);

- /* Must init clocks early to assure that timer interrupt works
- */
- omap1_clk_init();
omap1_mux_init();
}

diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index 7cc1a968230e..4e5ddd1db429 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -228,6 +228,8 @@ static inline void omap_mpu_timer_init(void)
*/
void __init omap1_timer_init(void)
{
+ omap1_clk_init();
+
if (omap_32k_timer_init() != 0)
omap_mpu_timer_init();
}

but the removed comment up there makes me suspect that it introduces
a different issue.

> "8<--- cut here ---
> "Unable to handle kernel NULL pointer dereference at virtual address 00000018
> "pgd = (ptrval)
> "[00000018] *pgd=00000000
> Internal error: Oops: 5 [#1] ARM
> CPU: 0 PID: 0 Comm: swapper Not tainted 5.3.0-rc4-sx1-los_80efa++ #1
> Hardware name: OMAP310 based Siemens SX1
> PC is at clk_hw_get_parent+0x4/0x14
> LR is at omap1_clk_enable+0xc/0xcc
> OMAP310 based Siemens SX1
> [ 0.000000] free:0 free_pcp:0 free_cma:0
> pc : [<c0126cd0>] lr : [<c00128d4>] psr: 600001d3
> sp : c03aff88 ip : 00000000 fp : 00000000
> r10: 00000001 r9 : 54029252 r8 : 10000100
> r7 : c03b1000 r6 : 00002002 r5 : 0000003a r4 : c03b5444
> r3 : 00000000 r2 : c03b9818 r1 : ff03ce08 r0 : c03b5444
> Flags: nZCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment user
> Control: 0000317f Table: 10004000 DAC: 00000055
> Process swapper (pid: 0, stack limit = 0x(ptrval))
> Stack: (0xc03aff88 to 0xc03b0000)
> ff80: c03b5438 0000003a 00002002 c01f6734 00000000 00000057
> ffa0: 0000313d c01f5820 00000000 c01f09e8 00000000 00000000 00000000 00000000
> ffc0: 00000000 00000000 00000000 c0201a38 00000000 c01f0330 00000057 0000313d
> ffe0: 00000265 10000100 54029252 0000317f 00000000 00000000 00000000 00000000
> [<c0126cd0>] (clk_hw_get_parent) from [<c00128d4>] (omap1_clk_enable+0xc/0xcc)
> [<c00128d4>] (omap1_clk_enable) from [<c01f6734>] (omap1_clk_init+0x1a8/0x220)
> [<c01f6734>] (omap1_clk_init) from [<c01f5820>] (omap1_init_early+0x20/0x30)
> [<c01f5820>] (omap1_init_early) from [<c01f09e8>] (start_kernel+0x48/0x408)
> [<c01f09e8>] (start_kernel) from [<00000000>] (0x0)

clk_hw->core is NULL here, presumably as a result of the first issue.

Arnd