lx_emul: support CLK_OF_DECLARE initcall mechanism

Clock providers such as drivers/clk/sunxi-ng/ccu-sun8i-r.c don't use
regular init calls but declare their init functions via CLK_OF_DECLARE,
which fill the __clk_of_table. Linux populates the table statically by
using special sections declared in the linker script. In contrast, we
populate the table by expanding the macro to global constructor
functions.

The __clk_of_table is then processed by the call of of_clk_init(NULL).

Issue #4253
This commit is contained in:
Norman Feske 2021-08-19 14:51:54 +02:00 committed by Christian Helmuth
parent 36af114d78
commit 29032caf40
4 changed files with 64 additions and 1 deletions

View File

@ -28,6 +28,8 @@ int lx_emul_init_task_function(void * dtb);
extern void * lx_emul_init_task_struct;
void lx_emul_register_of_clk_initcall(char const *compat, void *fn);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,27 @@
/*
* \brief Shadow copy of linux/of.h
* \author Norman Feske
* \date 2021-08-19
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _LX_EMUL__SHADOW__LINUX__OF_H_
#define _LX_EMUL__SHADOW__LINUX__OF_H_
#include_next <linux/of.h>
#include <lx_emul/init.h>
#undef OF_DECLARE_1
#define OF_DECLARE_1(table, name, compat, fn) \
static void __of_declare_initcall_##fn##name(void)__attribute__((constructor)); \
static void __of_declare_initcall_##fn##name() { \
lx_emul_register_of_##table##_initcall(compat, fn); };
#endif /* _LX_EMUL__SHADOW__LINUX__OF_H_ */

View File

@ -15,8 +15,10 @@
#include <linux/clocksource.h>
#include <linux/sched_clock.h>
#include <linux/smp.h>
#include <linux/of_clk.h>
#include <lx_emul/debug.h>
#include <lx_emul/time.h>
#include <lx_emul/init.h>
static u32 dde_timer_rate = 1000000; /* we use microseconds as rate */
@ -93,6 +95,10 @@ void lx_emul_time_init()
timecounter_init(&timecounter, &cyclecounter, start_count);
clockevents_config_and_register(&clock_event_device, dde_timer_rate, 0xf, 0x7fffffff);
sched_clock_register(dde_timer_read_counter, 64, dde_timer_rate);
/* execute setup calls of clock providers in __clk_of_table */
of_clk_init(NULL);
}
@ -102,4 +108,25 @@ void lx_emul_time_handle(void)
}
struct of_device_id __clk_of_table[] = { };
enum { LX_EMUL_MAX_OF_CLOCK_PROVIDERS = 256 };
struct of_device_id __clk_of_table[LX_EMUL_MAX_OF_CLOCK_PROVIDERS] = { };
void lx_emul_register_of_clk_initcall(char const *compat, void *fn)
{
static unsigned count;
if (count == LX_EMUL_MAX_OF_CLOCK_PROVIDERS) {
printk("lx_emul_register_of_clk_initcall: __clk_of_table exhausted\n");
return;
}
strncpy(__clk_of_table[count].compatible, compat,
sizeof(__clk_of_table[count].compatible));
__clk_of_table[count].data = fn;
count++;
}

View File

@ -45,3 +45,10 @@ void clk_disable(struct clk * clk) { }
void clk_unprepare(struct clk * clk) { }
struct of_device_id;
void of_clk_init(const struct of_device_id *matches) { }