ARM10C 94주차 후기
일시 : 2015.03.14 (94주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 3명
94주차 진도
- start_kernel() init/main.c
- ->time_init() 741 /init/main.c
- ->of_clk_init(NULL) 154 ~/kernel/iamroot/linux-stable/arch/arm/kernel/time.c
- ->clocksource_of_init() 557 ~/kernel/iamroot/linux-stable/arch/arm/kernel/time.c
- ->mct_init_spi 56 ~/kernel/iamroot/linux-stable/drivers/clocksource/clksrc-of.c
- ->mct_init_dt 583 ~/kernel/iamroot/linux-stable/drivers/clocksource/exynos_mct.c
- ->irq_of_parse_and_map 557 ~/kernel/iamroot/linux-stable/drivers/clocksource/exynos_mct.c
- ->of_irq_parse_one 49 if (of_irq_parse_one(dev, index, &oirq))
- ->of_irq_parse_raw 674 res = of_irq_parse_raw(addr, out_irq);
- ->time_init() 741 /init/main.c
- ->of_clk_init(NULL) 154 ~/kernel/iamroot/linux-stable/arch/arm/kernel/time.c
- ->clocksource_of_init() 557 ~/kernel/iamroot/linux-stable/arch/arm/kernel/time.c
- ->mct_init_spi 56 ~/kernel/iamroot/linux-stable/drivers/clocksource/clksrc-of.c
- ->mct_init_dt 583 ~/kernel/iamroot/linux-stable/drivers/clocksource/exynos_mct.c
- ->irq_of_parse_and_map 557 ~/kernel/iamroot/linux-stable/drivers/clocksource/exynos_mct.c
- ->of_irq_parse_one 49 if (of_irq_parse_one(dev, index, &oirq))
- ->of_irq_parse_raw 674 res = of_irq_parse_raw(addr, out_irq);
- ->of_irq_parse_one 49 if (of_irq_parse_one(dev, index, &oirq))
- ->irq_of_parse_and_map 557 ~/kernel/iamroot/linux-stable/drivers/clocksource/exynos_mct.c
- ->mct_init_dt 583 ~/kernel/iamroot/linux-stable/drivers/clocksource/exynos_mct.c
- ->mct_init_spi 56 ~/kernel/iamroot/linux-stable/drivers/clocksource/clksrc-of.c
main.c::start_kernel()->time_init()
- called: start_kernel()->time_init()
asmlinkage void __init start_kernel(void)
{
...
early_irq_init();
// irq_desc 0 ~ 15 까지의 object을 할당 받고 초기화를 수행
// allocated_irqs에 bit를 1로 세팅하고 radix tree에 각 irq_desc를 노트로 추가
init_IRQ();
// gic, combiner이 사용할 메모리 할당과 자료 구조 설정,
// gic irq (0~15), combiner irq (32~63) interrupt 를 enable 시킴
tick_init();
// tick 관련 mask 변수를 0으로 초기화 수행
init_timers();
// boot_tvec_bases의 맴버 값을 초기화하고 timers_nb를 cpu_notifier 에 등록,
// softirq_vec[1] 에 run_timer_softirq 등록하여 초기화 수행
hrtimers_init();
// hrtimer_bases의 맴버 값을 초기화하고 hrtimers_nb를 cpu_notifier 에 등록,
// softirq_vec[8] 에 run_hrtimer_softirq 등록하여 초기화 수행
softirq_init();
// tasklet_vec, tasklet_hi_vec 맴버 값을 초기화하고,
// softirq_vec[6]에 tasklet_action, softirq_vec[0]에 tasklet_hi_action 등록하여 초기화 수행
timekeeping_init();
// ntp 관련 전역변수 초기화, timekeeper, shadow_timekeeper의 맴버값 초기화 수행
time_init();
asmlinkage void __init start_kernel(void)
{
...
early_irq_init();
// irq_desc 0 ~ 15 까지의 object을 할당 받고 초기화를 수행
// allocated_irqs에 bit를 1로 세팅하고 radix tree에 각 irq_desc를 노트로 추가
init_IRQ();
// gic, combiner이 사용할 메모리 할당과 자료 구조 설정,
// gic irq (0~15), combiner irq (32~63) interrupt 를 enable 시킴
tick_init();
// tick 관련 mask 변수를 0으로 초기화 수행
init_timers();
// boot_tvec_bases의 맴버 값을 초기화하고 timers_nb를 cpu_notifier 에 등록,
// softirq_vec[1] 에 run_timer_softirq 등록하여 초기화 수행
hrtimers_init();
// hrtimer_bases의 맴버 값을 초기화하고 hrtimers_nb를 cpu_notifier 에 등록,
// softirq_vec[8] 에 run_hrtimer_softirq 등록하여 초기화 수행
softirq_init();
// tasklet_vec, tasklet_hi_vec 맴버 값을 초기화하고,
// softirq_vec[6]에 tasklet_action, softirq_vec[0]에 tasklet_hi_action 등록하여 초기화 수행
timekeeping_init();
// ntp 관련 전역변수 초기화, timekeeper, shadow_timekeeper의 맴버값 초기화 수행
time_init();
time.c::time_init()->of_clk_init(NULL)
- called: start_kernel()->time_init()->of_clk_init()
// ARM10C 20150103
void __init time_init(void)
{
// machine_desc->init_time: __mach_desc_EXYNOS5_DT.init_time: NULL
if (machine_desc->init_time) {
machine_desc->init_time();
} else {
#ifdef CONFIG_COMMON_CLK // CONFIG_COMMON_CLK=y
of_clk_init(NULL);
#endif
clocksource_of_init();
// ARM10C 20150103
void __init time_init(void)
{
// machine_desc->init_time: __mach_desc_EXYNOS5_DT.init_time: NULL
if (machine_desc->init_time) {
machine_desc->init_time();
} else {
#ifdef CONFIG_COMMON_CLK // CONFIG_COMMON_CLK=y
of_clk_init(NULL);
#endif
clocksource_of_init();
of_clk_init() 에서 한일:
- devtree에서 allnext로 순회 하면서 찾은 clock node의 주소에서
- match: __clk_of_table_exynos5420_clk 찾아
-
exynos5420_clk_init 함수를 수행
-
exynos5420_clk_init에서 한일:
- // device tree 있는 clock node에서 node의 resource 값을 가져옴
- // of_address_to_resource에서 한일(index: 0):
- // (&res)->start: 0x10010000
- // (&res)->end: 0x1003ffff
- // (&res)->flags: IORESOURCE_MEM: 0x00000200
- // (&res)->name: "/clock-controller@10010000"
- //
- // alloc area (CLK) 를 만들고 rb tree에 alloc area 를 추가
- // 가상주소 va_start 기준으로 CLK 를 RB Tree 추가한 결과
//
// CHID-b
// (0xF8000000)
// / \
// TMR-b PMU-b
// (0xF6300000) (0xF8180000)
// / \ / \
// GIC#1-r WDT-b CMU-b SRAM-b
// (0xF0002000) (0xF6400000) (0xF8100000) (0xF8400000)
// / \ \
// GIC#0-b CLK-b ROMC-r
// (0xF0000000) (0xF0040000) (0xF84C0000)
// / \
// COMB-r SYSC-r
// (0xF0004000) (0xF6100000)
-
vmap_area_list에
- // GIC#0 - GIC#1 - COMB - CLK - SYSC -TMR - WDT - CHID - CMU - PMU - SRAM - ROMC
- // 순서로 리스트에 연결이 됨
- //
- // (kmem_cache#30-oX (vm_struct))->flags: GFP_KERNEL: 0xD0
- // (kmem_cache#30-oX (vm_struct))->addr: 0xf0040000
- // (kmem_cache#30-oX (vm_struct))->size: 0x31000
- // (kmem_cache#30-oX (vm_struct))->caller: __builtin_return_address(0)
- //
- // (kmem_cache#30-oX (vmap_area CLK))->vm: kmem_cache#30-oX (vm_struct)
- // (kmem_cache#30-oX (vmap_area CLK))->flags: 0x04
-
device tree 있는 clock node에서 node의 resource 값을 pgtable에 매핑함
- // 0xc0004780이 가리키는 pte의 시작주소에 0x10010653 값을 갱신
- // (linux pgtable과 hardware pgtable의 값 같이 갱신)
-
memory 구조
// pgd pte
// | |
// +--------------+
// | | +--------------+ +0
// | | | 0xXXXXXXXX | ---> 0x10010653 에 매칭되는 linux pgtable 값
// +- - - - - - - + | Linux pt 0 |
// | | +--------------+ +1024
// | | | |
// +--------------+ +0 | Linux pt 1 |
// | *(c0004780) |-----> +--------------+ +2048
// | | | 0x10010653 | ---> 2308
// +- - - - - - - + +4 | h/w pt 0 |
// | *(c0004784) |-----> +--------------+ +3072
// | | + +
// +--------------+ +8 | h/w pt 1 |
// | | +--------------+ +4096
//
// cache의 값을 전부 메모리에 반영
-
samsung_clk_init 에서 한일:
- // struct samsung_clk_reg_dump를 59개 만큼 메모리를 할당 받아
- // exynos5420_clk_regs의 값으로 맴버값 세팅
- // (kmem_cache#26-oX)[0...58].offset: exynos5420_clk_regs[0...58]
- //
- // syscore_ops_list의 tail에 (&samsung_clk_syscore_ops)->node 를 추가
- //
- // struct clk * 를 769개 만큼 메모리를 clk_table에 할당 받음
- // clk_table: kmem_cache#23-o0
- //
- // clk_data.clks: kmem_cache#23-o0 (clk_table)
- // clk_data.clk_num: 769
- //
- // struct of_clk_provider 의 메모리(kmem_cache#30-oX)를 할당 받고 맴버값 초기화 수행
- //
- // (kmem_cache#30-oX)->node: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
- // (kmem_cache#30-oX)->data: &clk_data
- // (kmem_cache#30-oX)->get: of_clk_src_onecell_get
- //
- // list인 of_clk_providers의 head에 (kmem_cache#30-oX)->link를 추가
-
samsung_clk_of_register_fixed_ext 에서 한일:
- // devtree에서 allnext로 순회 하면서 찾은 fixed-rate-clocks node 에서
- // fixed-rate-clocks node에서 "clock-frequency" property값을 freq에 읽어옴
- // freq: 24000000
- // exynos5420_fixed_rate_ext_clks[0].fixed_rate: 24000000
- //
- // struct clk_fixed_rate 만큼 메모리를 kmem_cache#30-oX 할당 받고 struct clk_fixed_rate 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#30-oX)->fixed_rate: 24000000
- // (kmem_cache#30-oX)->hw.init: &init
- // (&(kmem_cache#30-oX)->hw)->clk: kmem_cache#29-oX
- //
- // struct clk 만큼 메모리를 kmem_cache#29-oX 할당 받고 struct clk 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#29-oX)->name: kmem_cache#30-oX ("fin_pll")
- // (kmem_cache#29-oX)->ops: &clk_fixed_rate_ops
- // (kmem_cache#29-oX)->hw: &(kmem_cache#30-oX)->hw
- // (kmem_cache#29-oX)->flags: 0x30
- // (kmem_cache#29-oX)->num_parents: 0
- // (kmem_cache#29-oX)->parent_names: ((void *)16)
- // (kmem_cache#29-oX)->parent: NULL
- // (kmem_cache#29-oX)->rate: 24000000
- //
- // (&(kmem_cache#29-oX)->child_node)->next: NULL
- // (&(kmem_cache#29-oX)->child_node)->pprev: &(&(kmem_cache#29-oX)->child_node)
- //
- // (&clk_root_list)->first: &(kmem_cache#29-oX)->child_node
- //
- // clk_table[1]: (kmem_cache#23-o0)[1]: kmem_cache#29-oX
- //
- // struct clk_lookup_alloc 의 메모리를 kmem_cache#30-oX 할당 받고
- // struct clk_lookup_alloc 맴버값 초기화 수행
- //
- // (kmem_cache#30-oX)->cl.clk: kmem_cache#29-oX
- // (kmem_cache#30-oX)->con_id: "fin_pll"
- // (kmem_cache#30-oX)->cl.con_id: (kmem_cache#30-oX)->con_id: "fin_pll"
- //
- // list clocks에 &(&(kmem_cache#30-oX)->cl)->nade를 tail로 추가
-
samsung_clk_register_pll에서 한일:
- // exynos5420_plls에 정의되어 있는 PLL 값들을 초기화 수행
- //
- // [apll] 의 초기화 값 수행 결과:
- // struct clk_fixed_rate 만큼 메모리를 kmem_cache#30-oX (apll) 할당 받고 struct clk_fixed_rate 의 멤버 값을 아래와 같이 초기화 수행
- // pll: kmem_cache#30-oX (apll)
- //
- // (kmem_cache#30-oX (apll))->hw.init: &init
- // (kmem_cache#30-oX (apll))->type: pll_2550: 2
- // (kmem_cache#30-oX (apll))->lock_reg: 0xf0040000
- // (kmem_cache#30-oX (apll))->con_reg: 0xf0040100
- //
- // struct clk 만큼 메모리를 kmem_cache#29-oX (apll) 할당 받고 struct clk 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#29-oX (apll))->name: kmem_cache#30-oX ("fout_apll")
- // (kmem_cache#29-oX (apll))->ops: &samsung_pll35xx_clk_min_ops
- // (kmem_cache#29-oX (apll))->hw: &(kmem_cache#30-oX (apll))->hw
- // (kmem_cache#29-oX (apll))->flags: 0x40
- // (kmem_cache#29-oX (apll))->num_parents: 1
- // (kmem_cache#29-oX (apll))->parent_names: kmem_cache#30-oX
- // (kmem_cache#29-oX (apll))->parent_names[0]: (kmem_cache#30-oX)[0]: kmem_cache#30-oX: "fin_pll"
- // (kmem_cache#29-oX (apll))->parent: kmem_cache#29-oX (fin_pll)
- // (kmem_cache#29-oX (apll))->rate: 1000000000 (1 Ghz)
- //
- // (&(kmem_cache#29-oX (apll))->child_node)->next: NULL
- // (&(kmem_cache#29-oX (apll))->child_node)->pprev: &(&(kmem_cache#29-oX (apll))->child_node)
- //
- // (&(kmem_cache#29-oX (fin_pll))->children)->first: &(kmem_cache#29-oX (apll))->child_node
- //
- // (&(kmem_cache#30-oX (apll))->hw)->clk: kmem_cache#29-oX (apll)
- //
- // clk_table[2]: (kmem_cache#23-o0)[2]: kmem_cache#29-oX (apll)
- //
- // struct clk_lookup_alloc 의 메모리를 kmem_cache#30-oX (apll) 할당 받고
- // struct clk_lookup_alloc 맴버값 초기화 수행
- //
- // (kmem_cache#30-oX)->cl.clk: kmem_cache#29-oX (apll)
- // (kmem_cache#30-oX)->con_id: "fout_apll"
- // (kmem_cache#30-oX)->cl.con_id: (kmem_cache#30-oX)->con_id: "fout_apll"
- //
- // list clocks에 &(&(kmem_cache#30-oX (apll))->cl)->nade를 tail로 추가
- //
- // cpll, dpll, epll, rpll, ipll, spll, vpll, mpll, bpll, kpll 초기화 수행 결과는 생략.
-
samsung_clk_register_fixed_rate에서 한일:
- // exynos5420_fixed_rate_clks에 정의되어 있는 fixed rate 값들을 초기화 수행
- //
- // sclk_hdmiphy 의 초기화 값 수행 결과
- // struct clk_fixed_rate 만큼 메모리를 kmem_cache#30-oX 할당 받고 struct clk_fixed_rate 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#30-oX)->fixed_rate: 24000000
- // (kmem_cache#30-oX)->hw.init: &init
- // (&(kmem_cache#30-oX)->hw)->clk: kmem_cache#29-oX
- //
- // struct clk 만큼 메모리를 kmem_cache#29-oX 할당 받고 struct clk 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#29-oX)->name: kmem_cache#30-oX ("sclk_hdmiphy")
- // (kmem_cache#29-oX)->ops: &clk_fixed_rate_ops
- // (kmem_cache#29-oX)->hw: &(kmem_cache#30-oX)->hw
- // (kmem_cache#29-oX)->flags: 0x30
- // (kmem_cache#29-oX)->num_parents: 0
- // (kmem_cache#29-oX)->parent_names: ((void *)16)
- // (kmem_cache#29-oX)->parent: NULL
- // (kmem_cache#29-oX)->rate: 24000000
- //
- // (&(kmem_cache#29-oX)->child_node)->next: NULL
- // (&(kmem_cache#29-oX)->child_node)->pprev: &(&(kmem_cache#29-oX)->child_node)
- //
- // (&clk_root_list)->first: &(kmem_cache#29-oX)->child_node
- //
- // clk_table[158]: (kmem_cache#23-o0)[158]: kmem_cache#29-oX
- //
- // struct clk_lookup_alloc 의 메모리를 kmem_cache#30-oX 할당 받고
- // struct clk_lookup_alloc 맴버값 초기화 수행
- //
- // (kmem_cache#30-oX)->cl.clk: kmem_cache#29-oX
- // (kmem_cache#30-oX)->con_id: "fin_pll"
- // (kmem_cache#30-oX)->cl.con_id: (kmem_cache#30-oX)->con_id: "fin_pll"
- //
- // list clocks에 &(&(kmem_cache#30-oX)->cl)->nade를 tail로 추가
- //
- // "sclk_pwi", "sclk_usbh20", "mphy_refclk_ixtal24", "sclk_usbh20_scan_clk" 초기화 수행 결과는 생략.
-
samsung_clk_register_fixed_factor에서 한일:
- // struct clk_fixed_factor 만큼 메모리를 kmem_cache#30-oX 할당 받고 struct clk_fixed_factor 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#30-oX)->mult: 1
- // (kmem_cache#30-oX)->div: 2
- // (kmem_cache#30-oX)->hw.init: &init
- //
- // struct clk 만큼 메모리를 kmem_cache#29-oX (sclk_hsic_12m) 할당 받고 struct clk 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#29-oX (sclk_hsic_12m))->name: kmem_cache#30-oX ("sclk_hsic_12m")
- // (kmem_cache#29-oX (sclk_hsic_12m))->ops: &clk_fixed_factor_ops
- // (kmem_cache#29-oX (sclk_hsic_12m))->hw: &(kmem_cache#30-oX (sclk_hsic_12m))->hw
- // (kmem_cache#29-oX (sclk_hsic_12m))->flags: 0x20
- // (kmem_cache#29-oX (sclk_hsic_12m))->num_parents: 1
- // (kmem_cache#29-oX (sclk_hsic_12m))->parent_names: kmem_cache#30-oX
- // (kmem_cache#29-oX (sclk_hsic_12m))->parent_names[0]: (kmem_cache#30-oX)[0]: kmem_cache#30-oX: "fin_pll"
- // (kmem_cache#29-oX (sclk_hsic_12m))->parent: kmem_cache#29-oX (fin_pll)
- // (kmem_cache#29-oX (sclk_hsic_12m))->rate: 12000000
- //
- // (&(kmem_cache#29-oX (sclk_hsic_12m))->child_node)->next: NULL
- // (&(kmem_cache#29-oX (sclk_hsic_12m))->child_node)->pprev: &(&(kmem_cache#29-oX (sclk_hsic_12m))->child_node)
- //
- // (&(kmem_cache#29-oX (fin_pll))->children)->first: &(kmem_cache#29-oX (sclk_hsic_12m))->child_node
- //
- // (&(kmem_cache#30-oX (sclk_hsic_12m))->hw)->clk: kmem_cache#29-oX (sclk_hsic_12m)
- //
- // clk_table[0]: (kmem_cache#23-o0)[0]: kmem_cache#29-oX (sclk_hsic_12m)
-
samsung_clk_register_mux 에서 한일:
- // exynos5420_mux_clks에 등록 되어 있는 clock mux 들의 초기화를 수행
- //
- // mout_mspll_kfc, sclk_dpll를 수행한 결과:
- //
- // (mout_mspll_kfc) 에서 한일:
- // struct clk_mux 만큼 메모리를 kmem_cache#30-oX (mout_mspll_kfc) 할당 받고 struct clk_mux 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#30-oX)->reg: 0xf005021c
- // (kmem_cache#30-oX)->shift: 8
- // (kmem_cache#30-oX)->mask: 0x3
- // (kmem_cache#30-oX)->flags: 0
- // (kmem_cache#30-oX)->lock: &lock
- // (kmem_cache#30-oX)->table: NULL
- // (kmem_cache#30-oX)->hw.init: &init
- //
- // struct clk 만큼 메모리를 kmem_cache#29-oX (mout_mspll_kfc) 할당 받고 struct clk 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#29-oX (mout_mspll_kfc))->name: kmem_cache#30-oX ("mout_mspll_kfc")
- // (kmem_cache#29-oX (mout_mspll_kfc))->ops: &clk_mux_ops
- // (kmem_cache#29-oX (mout_mspll_kfc))->hw: &(kmem_cache#30-oX (mout_mspll_kfc))->hw
- // (kmem_cache#29-oX (mout_mspll_kfc))->flags: 0xa0
- // (kmem_cache#29-oX (mout_mspll_kfc))->num_parents 4
- // (kmem_cache#29-oX (mout_mspll_kfc))->parent_names: kmem_cache#30-oX
- // (kmem_cache#29-oX (mout_mspll_kfc))->parent_names[0]: (kmem_cache#30-oX)[0]: kmem_cache#30-oX: "sclk_cpll"
- // (kmem_cache#29-oX (mout_mspll_kfc))->parent_names[1]: (kmem_cache#30-oX)[1]: kmem_cache#30-oX: "sclk_dpll"
- // (kmem_cache#29-oX (mout_mspll_kfc))->parent_names[2]: (kmem_cache#30-oX)[2]: kmem_cache#30-oX: "sclk_mpll"
- // (kmem_cache#29-oX (mout_mspll_kfc))->parent_names[3]: (kmem_cache#30-oX)[3]: kmem_cache#30-oX: "sclk_spll"
- // (kmem_cache#29-oX (mout_mspll_kfc))->parent: NULL
- // (kmem_cache#29-oX (mout_mspll_kfc))->rate: 0
- //
- // (kmem_cache#29-oX (mout_mspll_kfc))->parents: kmem_cache#30-oX
- // (kmem_cache#29-oX (mout_mspll_kfc))->parents[0...3]: (kmem_cache#30-oX)[0...3]: NULL
- //
- // (&(kmem_cache#29-oX (mout_mspll_kfc))->child_node)->next: NULL
- // (&(kmem_cache#29-oX (mout_mspll_kfc))->child_node)->pprev: &(&(kmem_cache#29-oX (mout_mspll_kfc))->child_node)
- //
- // (&clk_orphan_list)->first: &(kmem_cache#29-oX (mout_mspll_kfc))->child_node
- //
- // (&(kmem_cache#30-oX (mout_mspll_kfc))->hw)->clk: kmem_cache#29-oX (mout_mspll_kfc)
-
(sclk_spll) 에서 한일:
- // struct clk_mux 만큼 메모리를 kmem_cache#30-oX (sclk_spll) 할당 받고 struct clk_mux 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#30-oX)->reg: 0xf0050218
- // (kmem_cache#30-oX)->shift: 8
- // (kmem_cache#30-oX)->mask: 0x3
- // (kmem_cache#30-oX)->flags: 0
- // (kmem_cache#30-oX)->lock: &lock
- // (kmem_cache#30-oX)->table: NULL
- // (kmem_cache#30-oX)->hw.init: &init
- //
- // struct clk 만큼 메모리를 kmem_cache#29-oX (sclk_spll) 할당 받고 struct clk 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#29-oX (sclk_spll))->name: kmem_cache#30-oX ("sclk_spll")
- // (kmem_cache#29-oX (sclk_spll))->ops: &clk_mux_ops
- // (kmem_cache#29-oX (sclk_spll))->hw: &(kmem_cache#30-oX (sclk_spll))->hw
- // (kmem_cache#29-oX (sclk_spll))->flags: 0xa0
- // (kmem_cache#29-oX (sclk_spll))->num_parents 2
- // (kmem_cache#29-oX (sclk_spll))->parent_names: kmem_cache#30-oX
- // (kmem_cache#29-oX (sclk_spll))->parent_names[0]: (kmem_cache#30-oX)[0]: kmem_cache#30-oX: "fin_pll"
- // (kmem_cache#29-oX (sclk_spll))->parent_names[1]: (kmem_cache#30-oX)[1]: kmem_cache#30-oX: "fout_spll"
- // (kmem_cache#29-oX (sclk_spll))->parent: NULL
- // (kmem_cache#29-oX (sclk_spll))->rate: 600000000
- //
- // (kmem_cache#29-oX (sclk_spll))->parents: kmem_cache#30-oX
- // (kmem_cache#29-oX (sclk_spll))->parents[0]: (kmem_cache#30-oX)[0]: kmem_cache#29-oX (fin_pll)
- // (kmem_cache#29-oX (sclk_spll))->parents[1]: (kmem_cache#30-oX)[1]: kmem_cache#29-oX (fout_spll)
- //
- // parents 인 "fin_pll", "fout_spll" 값들 중에
- // register CLK_SRC_TOP6 의 값을 읽어서 mux 할 parent clock 을 선택함
- // return된 값이 선택된 parent clock의 index 값임
- // parent clock 중에 선택된 parent clock의 이름으로 등록된 clk struct를 반환함
- //
- // (&(kmem_cache#29-oX (sclk_spll))->child_node)->next: NULL
- // (&(kmem_cache#29-oX (sclk_spll))->child_node)->pprev: &(&(kmem_cache#29-oX (sclk_spll))->child_node)
- //
- // (&(kmem_cache#29-oX (fout_spll))->children)->first: &(kmem_cache#29-oX (sclk_spll))->child_node
- //
- // (&(kmem_cache#30-oX (sclk_spll))->hw)->clk: kmem_cache#29-oX (sclk_spll)
- //
- // orphan 으로 등록된 mout_mspll_kfc의 값을 갱신
- // (&(kmem_cache#29-oX (mout_mspll_kfc))->child_node)->next: NULL
- // (&(kmem_cache#29-oX (mout_mspll_kfc))->child_node)->pprev: &(&(kmem_cache#29-oX (mout_mspll_kfc))->child_node)
- //
- // (&(kmem_cache#29-oX (sclk_spll))->children)->first: &(kmem_cache#29-oX (mout_mspll_kfc))->child_node
- //
- // (kmem_cache#29-oX (mout_mspll_kfc))->parent: kmem_cache#29-oX (sclk_spll)
- //
- // parent가 있는지 확인후 parent의 clock rate 값으로 clock rate 값을 세팅
- // (kmem_cache#29-oX (mout_mspll_kfc))->rate: 600000000
- //
- // samsung_clk_register_div에서 한일:
- //
- // exynos5420_div_clks의 div 들 중에 array index 1번의
- // DIV(none, "sclk_apll", "mout_apll", DIV_CPU0, 24, 3) 을 가지고 분석 진행
- //
- // struct clk_divider 만큼 메모리를 할당 받아 맴버값 초기화 수행
- // kmem_cache#30-oX (sclk_apll)
- // (kmem_cache#30-oX (sclk_apll))->reg: 0xf0040500
- // (kmem_cache#30-oX (sclk_apll))->shift: 24
- // (kmem_cache#30-oX (sclk_apll))->width: 3
- // (kmem_cache#30-oX (sclk_apll))->flags: 0
- // (kmem_cache#30-oX (sclk_apll))->lock: &lock
- // (kmem_cache#30-oX (sclk_apll))->hw.init: &init
- // (kmem_cache#30-oX (sclk_apll))->table: NULL
- //
- // struct clk 만큼 메모리를 할당 받아 맴버값 초기화 수행
- // kmem_cache#29-oX (sclk_apll)
- // (kmem_cache#29-oX (sclk_apll))->name: kmem_cache#30-oX ("sclk_apll")
- // (kmem_cache#29-oX (sclk_apll))->ops: &clk_divider_ops
- // (kmem_cache#29-oX (sclk_apll))->hw: &(kmem_cache#30-oX (sclk_apll))->hw
- // (kmem_cache#29-oX (sclk_apll))->flags: 0x0
- // (kmem_cache#29-oX (sclk_apll))->num_parents 1
- // (kmem_cache#29-oX (sclk_apll))->parent_names[0]: (kmem_cache#30-oX)[0]: kmem_cache#30-oX: "mout_apll"
- // (kmem_cache#29-oX (sclk_apll))->parent: kmem_cache#29-oX (mout_apll)
- // (kmem_cache#29-oX (sclk_apll))->rate: 800000000
- //
- // clk 의 이름이 "mout_apll"인 메모리 값을 clk_root_list 에서 찾아 리턴 수행
- //
- // (&(kmem_cache#29-oX (sclk_apll))->child_node)->next: NULL
- // (&(kmem_cache#29-oX (sclk_apll))->child_node)->pprev: &(&(kmem_cache#29-oX (sclk_apll))->child_node)
- //
- // (&(kmem_cache#29-oX (fout_dpll))->children)->first: &(kmem_cache#29-oX (sclk_apll))->child_node
- //
- // exynos5420_div_clks의 idx 0, 2...52 까지 loop 수행
-
samsung_clk_register_gate 에서 한일:
- // exynos5420_gate_clks의 gate 들 중에 array index 36번의
- // GATE(sclk_fimd1, "sclk_fimd1", "dout_fimd1", GATE_TOP_SCLK_PERIC, 0, CLK_SET_RATE_PARENT, 0) 을 가지고 분석 진행
- //
- // struct clk_gate 만큼 메모리를 할당 받아 맴버값 초기화 수행
- // kmem_cache#30-oX (sclk_fimd1)
- // (kmem_cache#30-oX (sclk_fimd1))->reg: 0xf0050828
- // (kmem_cache#30-oX (sclk_fimd1))->bit_idx: 0
- // (kmem_cache#30-oX (sclk_fimd1))->flags: 0
- // (kmem_cache#30-oX (sclk_fimd1))->lock: &lock
- // (kmem_cache#30-oX (sclk_fimd1))->hw.init: &init
- // (kmem_cache#30-oX (sclk_fimd1))->table: NULL
- //
- // struct clk 만큼 메모리를 할당 받아 맴버값 초기화 수행
- // kmem_cache#29-oX (sclk_fimd1)
- // (kmem_cache#29-oX (sclk_fimd1))->name: kmem_cache#30-oX ("sclk_fimd1")
- // (kmem_cache#29-oX (sclk_fimd1))->ops: &clk_gate_ops
- // (kmem_cache#29-oX (sclk_fimd1))->hw: &(kmem_cache#30-oX (sclk_fimd1))->hw
- // (kmem_cache#29-oX (sclk_fimd1))->flags: 0x24
- // (kmem_cache#29-oX (sclk_fimd1))->num_parents 1
- // (kmem_cache#29-oX (sclk_fimd1))->parent_names[0]: (kmem_cache#30-oX)[0]: kmem_cache#30-oX: "mout_apll"
- // (kmem_cache#29-oX (sclk_fimd1))->parent: kmem_cache#29-oX (dout_fimd0)
- // (kmem_cache#29-oX (sclk_fimd1))->rate: 266000000
- //
- // clk 의 이름이 "dout_fimd1"인 메모리 값을 clk_root_list 에서 찾아 리턴 수행
- //
- // (&(kmem_cache#29-oX (sclk_fimd1))->child_node)->next: NULL
- // (&(kmem_cache#29-oX (sclk_fimd1))->child_node)->pprev: &(&(kmem_cache#29-oX (sclk_fimd1))->child_node)
- //
- // (&(kmem_cache#29-oX (dout_fimd1))->children)->first: &(kmem_cache#29-oX (sclk_fimd1))->child_node
- //
- // clk_table[136]: (kmem_cache#23-o0)[136]: kmem_cache#29-oX (sclk_fimd1)
- //
- // exynos5420_gate_clks의 idx: 0...12...136 loop 수행
exynos5420_clk_init 함수를 수행
exynos5420_clk_init에서 한일:
- // device tree 있는 clock node에서 node의 resource 값을 가져옴
- // of_address_to_resource에서 한일(index: 0):
- // (&res)->start: 0x10010000
- // (&res)->end: 0x1003ffff
- // (&res)->flags: IORESOURCE_MEM: 0x00000200
- // (&res)->name: "/clock-controller@10010000"
- //
- // alloc area (CLK) 를 만들고 rb tree에 alloc area 를 추가
- // 가상주소 va_start 기준으로 CLK 를 RB Tree 추가한 결과
//
// CHID-b
// (0xF8000000)
// / \
// TMR-b PMU-b
// (0xF6300000) (0xF8180000)
// / \ / \
// GIC#1-r WDT-b CMU-b SRAM-b
// (0xF0002000) (0xF6400000) (0xF8100000) (0xF8400000)
// / \ \
// GIC#0-b CLK-b ROMC-r
// (0xF0000000) (0xF0040000) (0xF84C0000)
// / \
// COMB-r SYSC-r
// (0xF0004000) (0xF6100000)
vmap_area_list에
- // GIC#0 - GIC#1 - COMB - CLK - SYSC -TMR - WDT - CHID - CMU - PMU - SRAM - ROMC
- // 순서로 리스트에 연결이 됨
- //
- // (kmem_cache#30-oX (vm_struct))->flags: GFP_KERNEL: 0xD0
- // (kmem_cache#30-oX (vm_struct))->addr: 0xf0040000
- // (kmem_cache#30-oX (vm_struct))->size: 0x31000
- // (kmem_cache#30-oX (vm_struct))->caller: __builtin_return_address(0)
- //
- // (kmem_cache#30-oX (vmap_area CLK))->vm: kmem_cache#30-oX (vm_struct)
- // (kmem_cache#30-oX (vmap_area CLK))->flags: 0x04
device tree 있는 clock node에서 node의 resource 값을 pgtable에 매핑함
- // 0xc0004780이 가리키는 pte의 시작주소에 0x10010653 값을 갱신
- // (linux pgtable과 hardware pgtable의 값 같이 갱신)
memory 구조
// pgd pte
// | |
// +--------------+
// | | +--------------+ +0
// | | | 0xXXXXXXXX | ---> 0x10010653 에 매칭되는 linux pgtable 값
// +- - - - - - - + | Linux pt 0 |
// | | +--------------+ +1024
// | | | |
// +--------------+ +0 | Linux pt 1 |
// | *(c0004780) |-----> +--------------+ +2048
// | | | 0x10010653 | ---> 2308
// +- - - - - - - + +4 | h/w pt 0 |
// | *(c0004784) |-----> +--------------+ +3072
// | | + +
// +--------------+ +8 | h/w pt 1 |
// | | +--------------+ +4096
//
// cache의 값을 전부 메모리에 반영
samsung_clk_init 에서 한일:
- // struct samsung_clk_reg_dump를 59개 만큼 메모리를 할당 받아
- // exynos5420_clk_regs의 값으로 맴버값 세팅
- // (kmem_cache#26-oX)[0...58].offset: exynos5420_clk_regs[0...58]
- //
- // syscore_ops_list의 tail에 (&samsung_clk_syscore_ops)->node 를 추가
- //
- // struct clk * 를 769개 만큼 메모리를 clk_table에 할당 받음
- // clk_table: kmem_cache#23-o0
- //
- // clk_data.clks: kmem_cache#23-o0 (clk_table)
- // clk_data.clk_num: 769
- //
- // struct of_clk_provider 의 메모리(kmem_cache#30-oX)를 할당 받고 맴버값 초기화 수행
- //
- // (kmem_cache#30-oX)->node: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
- // (kmem_cache#30-oX)->data: &clk_data
- // (kmem_cache#30-oX)->get: of_clk_src_onecell_get
- //
- // list인 of_clk_providers의 head에 (kmem_cache#30-oX)->link를 추가
samsung_clk_of_register_fixed_ext 에서 한일:
- // devtree에서 allnext로 순회 하면서 찾은 fixed-rate-clocks node 에서
- // fixed-rate-clocks node에서 "clock-frequency" property값을 freq에 읽어옴
- // freq: 24000000
- // exynos5420_fixed_rate_ext_clks[0].fixed_rate: 24000000
- //
- // struct clk_fixed_rate 만큼 메모리를 kmem_cache#30-oX 할당 받고 struct clk_fixed_rate 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#30-oX)->fixed_rate: 24000000
- // (kmem_cache#30-oX)->hw.init: &init
- // (&(kmem_cache#30-oX)->hw)->clk: kmem_cache#29-oX
- //
- // struct clk 만큼 메모리를 kmem_cache#29-oX 할당 받고 struct clk 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#29-oX)->name: kmem_cache#30-oX ("fin_pll")
- // (kmem_cache#29-oX)->ops: &clk_fixed_rate_ops
- // (kmem_cache#29-oX)->hw: &(kmem_cache#30-oX)->hw
- // (kmem_cache#29-oX)->flags: 0x30
- // (kmem_cache#29-oX)->num_parents: 0
- // (kmem_cache#29-oX)->parent_names: ((void *)16)
- // (kmem_cache#29-oX)->parent: NULL
- // (kmem_cache#29-oX)->rate: 24000000
- //
- // (&(kmem_cache#29-oX)->child_node)->next: NULL
- // (&(kmem_cache#29-oX)->child_node)->pprev: &(&(kmem_cache#29-oX)->child_node)
- //
- // (&clk_root_list)->first: &(kmem_cache#29-oX)->child_node
- //
- // clk_table[1]: (kmem_cache#23-o0)[1]: kmem_cache#29-oX
- //
- // struct clk_lookup_alloc 의 메모리를 kmem_cache#30-oX 할당 받고
- // struct clk_lookup_alloc 맴버값 초기화 수행
- //
- // (kmem_cache#30-oX)->cl.clk: kmem_cache#29-oX
- // (kmem_cache#30-oX)->con_id: "fin_pll"
- // (kmem_cache#30-oX)->cl.con_id: (kmem_cache#30-oX)->con_id: "fin_pll"
- //
- // list clocks에 &(&(kmem_cache#30-oX)->cl)->nade를 tail로 추가
samsung_clk_register_pll에서 한일:
- // exynos5420_plls에 정의되어 있는 PLL 값들을 초기화 수행
- //
- // [apll] 의 초기화 값 수행 결과:
- // struct clk_fixed_rate 만큼 메모리를 kmem_cache#30-oX (apll) 할당 받고 struct clk_fixed_rate 의 멤버 값을 아래와 같이 초기화 수행
- // pll: kmem_cache#30-oX (apll)
- //
- // (kmem_cache#30-oX (apll))->hw.init: &init
- // (kmem_cache#30-oX (apll))->type: pll_2550: 2
- // (kmem_cache#30-oX (apll))->lock_reg: 0xf0040000
- // (kmem_cache#30-oX (apll))->con_reg: 0xf0040100
- //
- // struct clk 만큼 메모리를 kmem_cache#29-oX (apll) 할당 받고 struct clk 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#29-oX (apll))->name: kmem_cache#30-oX ("fout_apll")
- // (kmem_cache#29-oX (apll))->ops: &samsung_pll35xx_clk_min_ops
- // (kmem_cache#29-oX (apll))->hw: &(kmem_cache#30-oX (apll))->hw
- // (kmem_cache#29-oX (apll))->flags: 0x40
- // (kmem_cache#29-oX (apll))->num_parents: 1
- // (kmem_cache#29-oX (apll))->parent_names: kmem_cache#30-oX
- // (kmem_cache#29-oX (apll))->parent_names[0]: (kmem_cache#30-oX)[0]: kmem_cache#30-oX: "fin_pll"
- // (kmem_cache#29-oX (apll))->parent: kmem_cache#29-oX (fin_pll)
- // (kmem_cache#29-oX (apll))->rate: 1000000000 (1 Ghz)
- //
- // (&(kmem_cache#29-oX (apll))->child_node)->next: NULL
- // (&(kmem_cache#29-oX (apll))->child_node)->pprev: &(&(kmem_cache#29-oX (apll))->child_node)
- //
- // (&(kmem_cache#29-oX (fin_pll))->children)->first: &(kmem_cache#29-oX (apll))->child_node
- //
- // (&(kmem_cache#30-oX (apll))->hw)->clk: kmem_cache#29-oX (apll)
- //
- // clk_table[2]: (kmem_cache#23-o0)[2]: kmem_cache#29-oX (apll)
- //
- // struct clk_lookup_alloc 의 메모리를 kmem_cache#30-oX (apll) 할당 받고
- // struct clk_lookup_alloc 맴버값 초기화 수행
- //
- // (kmem_cache#30-oX)->cl.clk: kmem_cache#29-oX (apll)
- // (kmem_cache#30-oX)->con_id: "fout_apll"
- // (kmem_cache#30-oX)->cl.con_id: (kmem_cache#30-oX)->con_id: "fout_apll"
- //
- // list clocks에 &(&(kmem_cache#30-oX (apll))->cl)->nade를 tail로 추가
- //
- // cpll, dpll, epll, rpll, ipll, spll, vpll, mpll, bpll, kpll 초기화 수행 결과는 생략.
samsung_clk_register_fixed_rate에서 한일:
- // exynos5420_fixed_rate_clks에 정의되어 있는 fixed rate 값들을 초기화 수행
- //
- // sclk_hdmiphy 의 초기화 값 수행 결과
- // struct clk_fixed_rate 만큼 메모리를 kmem_cache#30-oX 할당 받고 struct clk_fixed_rate 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#30-oX)->fixed_rate: 24000000
- // (kmem_cache#30-oX)->hw.init: &init
- // (&(kmem_cache#30-oX)->hw)->clk: kmem_cache#29-oX
- //
- // struct clk 만큼 메모리를 kmem_cache#29-oX 할당 받고 struct clk 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#29-oX)->name: kmem_cache#30-oX ("sclk_hdmiphy")
- // (kmem_cache#29-oX)->ops: &clk_fixed_rate_ops
- // (kmem_cache#29-oX)->hw: &(kmem_cache#30-oX)->hw
- // (kmem_cache#29-oX)->flags: 0x30
- // (kmem_cache#29-oX)->num_parents: 0
- // (kmem_cache#29-oX)->parent_names: ((void *)16)
- // (kmem_cache#29-oX)->parent: NULL
- // (kmem_cache#29-oX)->rate: 24000000
- //
- // (&(kmem_cache#29-oX)->child_node)->next: NULL
- // (&(kmem_cache#29-oX)->child_node)->pprev: &(&(kmem_cache#29-oX)->child_node)
- //
- // (&clk_root_list)->first: &(kmem_cache#29-oX)->child_node
- //
- // clk_table[158]: (kmem_cache#23-o0)[158]: kmem_cache#29-oX
- //
- // struct clk_lookup_alloc 의 메모리를 kmem_cache#30-oX 할당 받고
- // struct clk_lookup_alloc 맴버값 초기화 수행
- //
- // (kmem_cache#30-oX)->cl.clk: kmem_cache#29-oX
- // (kmem_cache#30-oX)->con_id: "fin_pll"
- // (kmem_cache#30-oX)->cl.con_id: (kmem_cache#30-oX)->con_id: "fin_pll"
- //
- // list clocks에 &(&(kmem_cache#30-oX)->cl)->nade를 tail로 추가
- //
- // "sclk_pwi", "sclk_usbh20", "mphy_refclk_ixtal24", "sclk_usbh20_scan_clk" 초기화 수행 결과는 생략.
samsung_clk_register_fixed_factor에서 한일:
- // struct clk_fixed_factor 만큼 메모리를 kmem_cache#30-oX 할당 받고 struct clk_fixed_factor 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#30-oX)->mult: 1
- // (kmem_cache#30-oX)->div: 2
- // (kmem_cache#30-oX)->hw.init: &init
- //
- // struct clk 만큼 메모리를 kmem_cache#29-oX (sclk_hsic_12m) 할당 받고 struct clk 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#29-oX (sclk_hsic_12m))->name: kmem_cache#30-oX ("sclk_hsic_12m")
- // (kmem_cache#29-oX (sclk_hsic_12m))->ops: &clk_fixed_factor_ops
- // (kmem_cache#29-oX (sclk_hsic_12m))->hw: &(kmem_cache#30-oX (sclk_hsic_12m))->hw
- // (kmem_cache#29-oX (sclk_hsic_12m))->flags: 0x20
- // (kmem_cache#29-oX (sclk_hsic_12m))->num_parents: 1
- // (kmem_cache#29-oX (sclk_hsic_12m))->parent_names: kmem_cache#30-oX
- // (kmem_cache#29-oX (sclk_hsic_12m))->parent_names[0]: (kmem_cache#30-oX)[0]: kmem_cache#30-oX: "fin_pll"
- // (kmem_cache#29-oX (sclk_hsic_12m))->parent: kmem_cache#29-oX (fin_pll)
- // (kmem_cache#29-oX (sclk_hsic_12m))->rate: 12000000
- //
- // (&(kmem_cache#29-oX (sclk_hsic_12m))->child_node)->next: NULL
- // (&(kmem_cache#29-oX (sclk_hsic_12m))->child_node)->pprev: &(&(kmem_cache#29-oX (sclk_hsic_12m))->child_node)
- //
- // (&(kmem_cache#29-oX (fin_pll))->children)->first: &(kmem_cache#29-oX (sclk_hsic_12m))->child_node
- //
- // (&(kmem_cache#30-oX (sclk_hsic_12m))->hw)->clk: kmem_cache#29-oX (sclk_hsic_12m)
- //
- // clk_table[0]: (kmem_cache#23-o0)[0]: kmem_cache#29-oX (sclk_hsic_12m)
samsung_clk_register_mux 에서 한일:
- // exynos5420_mux_clks에 등록 되어 있는 clock mux 들의 초기화를 수행
- //
- // mout_mspll_kfc, sclk_dpll를 수행한 결과:
- //
- // (mout_mspll_kfc) 에서 한일:
- // struct clk_mux 만큼 메모리를 kmem_cache#30-oX (mout_mspll_kfc) 할당 받고 struct clk_mux 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#30-oX)->reg: 0xf005021c
- // (kmem_cache#30-oX)->shift: 8
- // (kmem_cache#30-oX)->mask: 0x3
- // (kmem_cache#30-oX)->flags: 0
- // (kmem_cache#30-oX)->lock: &lock
- // (kmem_cache#30-oX)->table: NULL
- // (kmem_cache#30-oX)->hw.init: &init
- //
- // struct clk 만큼 메모리를 kmem_cache#29-oX (mout_mspll_kfc) 할당 받고 struct clk 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#29-oX (mout_mspll_kfc))->name: kmem_cache#30-oX ("mout_mspll_kfc")
- // (kmem_cache#29-oX (mout_mspll_kfc))->ops: &clk_mux_ops
- // (kmem_cache#29-oX (mout_mspll_kfc))->hw: &(kmem_cache#30-oX (mout_mspll_kfc))->hw
- // (kmem_cache#29-oX (mout_mspll_kfc))->flags: 0xa0
- // (kmem_cache#29-oX (mout_mspll_kfc))->num_parents 4
- // (kmem_cache#29-oX (mout_mspll_kfc))->parent_names: kmem_cache#30-oX
- // (kmem_cache#29-oX (mout_mspll_kfc))->parent_names[0]: (kmem_cache#30-oX)[0]: kmem_cache#30-oX: "sclk_cpll"
- // (kmem_cache#29-oX (mout_mspll_kfc))->parent_names[1]: (kmem_cache#30-oX)[1]: kmem_cache#30-oX: "sclk_dpll"
- // (kmem_cache#29-oX (mout_mspll_kfc))->parent_names[2]: (kmem_cache#30-oX)[2]: kmem_cache#30-oX: "sclk_mpll"
- // (kmem_cache#29-oX (mout_mspll_kfc))->parent_names[3]: (kmem_cache#30-oX)[3]: kmem_cache#30-oX: "sclk_spll"
- // (kmem_cache#29-oX (mout_mspll_kfc))->parent: NULL
- // (kmem_cache#29-oX (mout_mspll_kfc))->rate: 0
- //
- // (kmem_cache#29-oX (mout_mspll_kfc))->parents: kmem_cache#30-oX
- // (kmem_cache#29-oX (mout_mspll_kfc))->parents[0...3]: (kmem_cache#30-oX)[0...3]: NULL
- //
- // (&(kmem_cache#29-oX (mout_mspll_kfc))->child_node)->next: NULL
- // (&(kmem_cache#29-oX (mout_mspll_kfc))->child_node)->pprev: &(&(kmem_cache#29-oX (mout_mspll_kfc))->child_node)
- //
- // (&clk_orphan_list)->first: &(kmem_cache#29-oX (mout_mspll_kfc))->child_node
- //
- // (&(kmem_cache#30-oX (mout_mspll_kfc))->hw)->clk: kmem_cache#29-oX (mout_mspll_kfc)
(sclk_spll) 에서 한일:
- // struct clk_mux 만큼 메모리를 kmem_cache#30-oX (sclk_spll) 할당 받고 struct clk_mux 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#30-oX)->reg: 0xf0050218
- // (kmem_cache#30-oX)->shift: 8
- // (kmem_cache#30-oX)->mask: 0x3
- // (kmem_cache#30-oX)->flags: 0
- // (kmem_cache#30-oX)->lock: &lock
- // (kmem_cache#30-oX)->table: NULL
- // (kmem_cache#30-oX)->hw.init: &init
- //
- // struct clk 만큼 메모리를 kmem_cache#29-oX (sclk_spll) 할당 받고 struct clk 의 멤버 값을 아래와 같이 초기화 수행
- //
- // (kmem_cache#29-oX (sclk_spll))->name: kmem_cache#30-oX ("sclk_spll")
- // (kmem_cache#29-oX (sclk_spll))->ops: &clk_mux_ops
- // (kmem_cache#29-oX (sclk_spll))->hw: &(kmem_cache#30-oX (sclk_spll))->hw
- // (kmem_cache#29-oX (sclk_spll))->flags: 0xa0
- // (kmem_cache#29-oX (sclk_spll))->num_parents 2
- // (kmem_cache#29-oX (sclk_spll))->parent_names: kmem_cache#30-oX
- // (kmem_cache#29-oX (sclk_spll))->parent_names[0]: (kmem_cache#30-oX)[0]: kmem_cache#30-oX: "fin_pll"
- // (kmem_cache#29-oX (sclk_spll))->parent_names[1]: (kmem_cache#30-oX)[1]: kmem_cache#30-oX: "fout_spll"
- // (kmem_cache#29-oX (sclk_spll))->parent: NULL
- // (kmem_cache#29-oX (sclk_spll))->rate: 600000000
- //
- // (kmem_cache#29-oX (sclk_spll))->parents: kmem_cache#30-oX
- // (kmem_cache#29-oX (sclk_spll))->parents[0]: (kmem_cache#30-oX)[0]: kmem_cache#29-oX (fin_pll)
- // (kmem_cache#29-oX (sclk_spll))->parents[1]: (kmem_cache#30-oX)[1]: kmem_cache#29-oX (fout_spll)
- //
- // parents 인 "fin_pll", "fout_spll" 값들 중에
- // register CLK_SRC_TOP6 의 값을 읽어서 mux 할 parent clock 을 선택함
- // return된 값이 선택된 parent clock의 index 값임
- // parent clock 중에 선택된 parent clock의 이름으로 등록된 clk struct를 반환함
- //
- // (&(kmem_cache#29-oX (sclk_spll))->child_node)->next: NULL
- // (&(kmem_cache#29-oX (sclk_spll))->child_node)->pprev: &(&(kmem_cache#29-oX (sclk_spll))->child_node)
- //
- // (&(kmem_cache#29-oX (fout_spll))->children)->first: &(kmem_cache#29-oX (sclk_spll))->child_node
- //
- // (&(kmem_cache#30-oX (sclk_spll))->hw)->clk: kmem_cache#29-oX (sclk_spll)
- //
- // orphan 으로 등록된 mout_mspll_kfc의 값을 갱신
- // (&(kmem_cache#29-oX (mout_mspll_kfc))->child_node)->next: NULL
- // (&(kmem_cache#29-oX (mout_mspll_kfc))->child_node)->pprev: &(&(kmem_cache#29-oX (mout_mspll_kfc))->child_node)
- //
- // (&(kmem_cache#29-oX (sclk_spll))->children)->first: &(kmem_cache#29-oX (mout_mspll_kfc))->child_node
- //
- // (kmem_cache#29-oX (mout_mspll_kfc))->parent: kmem_cache#29-oX (sclk_spll)
- //
- // parent가 있는지 확인후 parent의 clock rate 값으로 clock rate 값을 세팅
- // (kmem_cache#29-oX (mout_mspll_kfc))->rate: 600000000
- //
- // samsung_clk_register_div에서 한일:
- //
- // exynos5420_div_clks의 div 들 중에 array index 1번의
- // DIV(none, "sclk_apll", "mout_apll", DIV_CPU0, 24, 3) 을 가지고 분석 진행
- //
- // struct clk_divider 만큼 메모리를 할당 받아 맴버값 초기화 수행
- // kmem_cache#30-oX (sclk_apll)
- // (kmem_cache#30-oX (sclk_apll))->reg: 0xf0040500
- // (kmem_cache#30-oX (sclk_apll))->shift: 24
- // (kmem_cache#30-oX (sclk_apll))->width: 3
- // (kmem_cache#30-oX (sclk_apll))->flags: 0
- // (kmem_cache#30-oX (sclk_apll))->lock: &lock
- // (kmem_cache#30-oX (sclk_apll))->hw.init: &init
- // (kmem_cache#30-oX (sclk_apll))->table: NULL
- //
- // struct clk 만큼 메모리를 할당 받아 맴버값 초기화 수행
- // kmem_cache#29-oX (sclk_apll)
- // (kmem_cache#29-oX (sclk_apll))->name: kmem_cache#30-oX ("sclk_apll")
- // (kmem_cache#29-oX (sclk_apll))->ops: &clk_divider_ops
- // (kmem_cache#29-oX (sclk_apll))->hw: &(kmem_cache#30-oX (sclk_apll))->hw
- // (kmem_cache#29-oX (sclk_apll))->flags: 0x0
- // (kmem_cache#29-oX (sclk_apll))->num_parents 1
- // (kmem_cache#29-oX (sclk_apll))->parent_names[0]: (kmem_cache#30-oX)[0]: kmem_cache#30-oX: "mout_apll"
- // (kmem_cache#29-oX (sclk_apll))->parent: kmem_cache#29-oX (mout_apll)
- // (kmem_cache#29-oX (sclk_apll))->rate: 800000000
- //
- // clk 의 이름이 "mout_apll"인 메모리 값을 clk_root_list 에서 찾아 리턴 수행
- //
- // (&(kmem_cache#29-oX (sclk_apll))->child_node)->next: NULL
- // (&(kmem_cache#29-oX (sclk_apll))->child_node)->pprev: &(&(kmem_cache#29-oX (sclk_apll))->child_node)
- //
- // (&(kmem_cache#29-oX (fout_dpll))->children)->first: &(kmem_cache#29-oX (sclk_apll))->child_node
- //
- // exynos5420_div_clks의 idx 0, 2...52 까지 loop 수행
samsung_clk_register_gate 에서 한일:
- // exynos5420_gate_clks의 gate 들 중에 array index 36번의
- // GATE(sclk_fimd1, "sclk_fimd1", "dout_fimd1", GATE_TOP_SCLK_PERIC, 0, CLK_SET_RATE_PARENT, 0) 을 가지고 분석 진행
- //
- // struct clk_gate 만큼 메모리를 할당 받아 맴버값 초기화 수행
- // kmem_cache#30-oX (sclk_fimd1)
- // (kmem_cache#30-oX (sclk_fimd1))->reg: 0xf0050828
- // (kmem_cache#30-oX (sclk_fimd1))->bit_idx: 0
- // (kmem_cache#30-oX (sclk_fimd1))->flags: 0
- // (kmem_cache#30-oX (sclk_fimd1))->lock: &lock
- // (kmem_cache#30-oX (sclk_fimd1))->hw.init: &init
- // (kmem_cache#30-oX (sclk_fimd1))->table: NULL
- //
- // struct clk 만큼 메모리를 할당 받아 맴버값 초기화 수행
- // kmem_cache#29-oX (sclk_fimd1)
- // (kmem_cache#29-oX (sclk_fimd1))->name: kmem_cache#30-oX ("sclk_fimd1")
- // (kmem_cache#29-oX (sclk_fimd1))->ops: &clk_gate_ops
- // (kmem_cache#29-oX (sclk_fimd1))->hw: &(kmem_cache#30-oX (sclk_fimd1))->hw
- // (kmem_cache#29-oX (sclk_fimd1))->flags: 0x24
- // (kmem_cache#29-oX (sclk_fimd1))->num_parents 1
- // (kmem_cache#29-oX (sclk_fimd1))->parent_names[0]: (kmem_cache#30-oX)[0]: kmem_cache#30-oX: "mout_apll"
- // (kmem_cache#29-oX (sclk_fimd1))->parent: kmem_cache#29-oX (dout_fimd0)
- // (kmem_cache#29-oX (sclk_fimd1))->rate: 266000000
- //
- // clk 의 이름이 "dout_fimd1"인 메모리 값을 clk_root_list 에서 찾아 리턴 수행
- //
- // (&(kmem_cache#29-oX (sclk_fimd1))->child_node)->next: NULL
- // (&(kmem_cache#29-oX (sclk_fimd1))->child_node)->pprev: &(&(kmem_cache#29-oX (sclk_fimd1))->child_node)
- //
- // (&(kmem_cache#29-oX (dout_fimd1))->children)->first: &(kmem_cache#29-oX (sclk_fimd1))->child_node
- //
- // clk_table[136]: (kmem_cache#23-o0)[136]: kmem_cache#29-oX (sclk_fimd1)
- //
- // exynos5420_gate_clks의 idx: 0...12...136 loop 수행
clksrc-of.c::time_init()->clocksource_of_init()
- called: start_kernel()->time_init()->clocksource_of_init()
// ARM10C 20150307
void __init clocksource_of_init(void)
{
struct device_node *np;
const struct of_device_id *match;
clocksource_of_init_fn init_func;
for_each_matching_node_and_match(np, __clksrc_of_table, &match) {
// for (np = of_find_matching_node_and_match(NULL, __clksrc_of_table, &match);
// np; np = of_find_matching_node_and_match(np, __clksrc_of_table, &match))
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, match: __clksrc_of_table_exynos4210
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소
// of_device_is_available(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소): 1
if (!of_device_is_available(np))
continue;
// match->data: __clksrc_of_table_exynos4210.data: mct_init_spi
init_func = match->data;
// init_func: mct_init_spi
// init_func: mct_init_spi
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소
// mct_init_spi(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소)
init_func(np);
- call: start_kernel()->time_init()->clocksource_of_init()->init_func(np)
- init_func(np);
- mct_init_spi(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소)
// ARM10C 20150307
void __init clocksource_of_init(void)
{
struct device_node *np;
const struct of_device_id *match;
clocksource_of_init_fn init_func;
for_each_matching_node_and_match(np, __clksrc_of_table, &match) {
// for (np = of_find_matching_node_and_match(NULL, __clksrc_of_table, &match);
// np; np = of_find_matching_node_and_match(np, __clksrc_of_table, &match))
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, match: __clksrc_of_table_exynos4210
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소
// of_device_is_available(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소): 1
if (!of_device_is_available(np))
continue;
// match->data: __clksrc_of_table_exynos4210.data: mct_init_spi
init_func = match->data;
// init_func: mct_init_spi
// init_func: mct_init_spi
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소
// mct_init_spi(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소)
init_func(np);
- init_func(np);
- mct_init_spi(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소)
exynos_mct.c::mct_init_spi()
- called: start_kernel()->time_init()->clocksource_of_init()->init_func(np)
- init_func(np);
- // mct_init_spi(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소)
- init_func(np)->mct_init_spi()
// ARM10C 20150307
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소
static void __init mct_init_spi(struct device_node *np)
{
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
return mct_init_dt(np, MCT_INT_SPI);
}
- call: start_kernel()->time_init()->clocksource_of_init()->init_func(np)
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- init_func(np):mct_init_spi()->mct_init_dt()
- init_func(np);
- // mct_init_spi(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소)
- init_func(np)->mct_init_spi()
// ARM10C 20150307
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소
static void __init mct_init_spi(struct device_node *np)
{
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
return mct_init_dt(np, MCT_INT_SPI);
}
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- init_func(np):mct_init_spi()->mct_init_dt()
exynos_mct.c::mct_init_dt()
- called: start_kernel()->time_init()->clocksource_of_init()->init_func(np)
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- init_func(np):mct_init_spi()->mct_init_dt()
// ARM10C 20150307
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
static void __init mct_init_dt(struct device_node *np, unsigned int int_type)
{
u32 nr_irqs, i;
// int_type: 0
mct_int_type = int_type;
// mct_int_type: 0
/* This driver uses only one global timer interrupt */
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_G0_IRQ: 0
mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ);
- call: start_kernel()->time_init()->clocksource_of_init()->init_func(np)
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- ->init_func(np)->mct_init_spi()->mct_init_dt()
- mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ);
- ->exynos_mct.c::mct_init_dt()->irq_of_parse_and_map()
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- init_func(np):mct_init_spi()->mct_init_dt()
// ARM10C 20150307
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
static void __init mct_init_dt(struct device_node *np, unsigned int int_type)
{
u32 nr_irqs, i;
// int_type: 0
mct_int_type = int_type;
// mct_int_type: 0
/* This driver uses only one global timer interrupt */
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_G0_IRQ: 0
mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ);
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- ->init_func(np)->mct_init_spi()->mct_init_dt()
- mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ);
- ->exynos_mct.c::mct_init_dt()->irq_of_parse_and_map()
irq.c::irq_of_parse_and_map()
- called: start_kernel()->time_init()->clocksource_of_init()->init_func(np)
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- init_func(np)->mct_init_spi()->mct_init_dt()
- exynos_mct.c::mct_init_dt()->irq_of_parse_and_map()
// ARM10C 20150307
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_G0_IRQ: 0
unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
{
struct of_phandle_args oirq;
// dev: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, index: 0
// of_irq_parse_one(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, 0, &oirq): 0
if (of_irq_parse_one(dev, index, &oirq))
return 0;
- exynos5420 device tree 에 있는 mct 장치 정보
mct@101C0000 {
compatible = "samsung,exynos4210-mct";
reg = <0x101C0000 0x800>;
interrupt-controller;
#interrups-cells = <1>;
interrupt-parent = <&mct_map>;
interrupts = <0>, <1>, <2>, <3>, <4>, <5>, <6>, <7>;
clocks = <&clock 1>, <&clock 315>;
clock-names = "fin_pll", "mct";
mct_map: mct-map {
#interrupt-cells = <1>;
#address-cells = <0>;
#size-cells = <0>;
interrupt-map = <0 &combiner 23 3>,
<1 &combiner 23 4>,
<2 &combiner 25 2>,
<3 &combiner 25 3>,
<4 &gic 0 120 0>,
<5 &gic 0 121 0>,
<6 &gic 0 122 0>,
<7 &gic 0 123 0>;
};
};
- call: start_kernel()->time_init()->clocksource_of_init()->init_func(np)
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- init_func(np)->mct_init_spi()->mct_init_dt()
- exynos_mct.c::mct_init_dt()->irq_of_parse_and_map()
- if (of_irq_parse_one(dev, index, &oirq))
- irq.c::irq_of_parse_and_map()->of_irq_parse_one()
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- init_func(np)->mct_init_spi()->mct_init_dt()
- exynos_mct.c::mct_init_dt()->irq_of_parse_and_map()
// ARM10C 20150307
// np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_G0_IRQ: 0
unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
{
struct of_phandle_args oirq;
// dev: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, index: 0
// of_irq_parse_one(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, 0, &oirq): 0
if (of_irq_parse_one(dev, index, &oirq))
return 0;
mct@101C0000 {
compatible = "samsung,exynos4210-mct";
reg = <0x101C0000 0x800>;
interrupt-controller;
#interrups-cells = <1>;
interrupt-parent = <&mct_map>;
interrupts = <0>, <1>, <2>, <3>, <4>, <5>, <6>, <7>;
clocks = <&clock 1>, <&clock 315>;
clock-names = "fin_pll", "mct";
mct_map: mct-map {
#interrupt-cells = <1>;
#address-cells = <0>;
#size-cells = <0>;
interrupt-map = <0 &combiner 23 3>,
<1 &combiner 23 4>,
<2 &combiner 25 2>,
<3 &combiner 25 3>,
<4 &gic 0 120 0>,
<5 &gic 0 121 0>,
<6 &gic 0 122 0>,
<7 &gic 0 123 0>;
};
};
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- init_func(np)->mct_init_spi()->mct_init_dt()
- exynos_mct.c::mct_init_dt()->irq_of_parse_and_map()
- if (of_irq_parse_one(dev, index, &oirq))
- irq.c::irq_of_parse_and_map()->of_irq_parse_one()
irq.c::of_irq_parse_one()
- called: start_kernel()->time_init()->clocksource_of_init()->init_func(np)
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- init_func(np)->mct_init_spi()->mct_init_dt()
- exynos_mct.c::mct_init_dt()->irq_of_parse_and_map()
- irq.c::irq_of_parse_and_map()->of_irq_parse_one()
// ARM10C 20150307
// dev: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, index: 0, &oirq
int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
{
struct device_node *p;
const __be32 *intspec, *tmp, *addr;
u32 intsize, intlen;
// EINVAL: 23
int i, res = -EINVAL;
// res: -23
// device: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소
// of_node_full_name(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소):
// "mct@101C0000", index: 0
pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);
// "of_irq_parse_one: dev=mct@101C0000, index=0\n"
/* OldWorld mac stuff is "special", handle out of line */
// of_irq_workarounds: 0, OF_IMAP_OLDWORLD_MAC: 0x00000001
if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
return of_irq_parse_oldworld(device, index, out_irq);
/* Get the reg property (if any) */
// device: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소
// of_get_property(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, "reg", NULL):
// mct node의reg의 property의 값의 주소
addr = of_get_property(device, "reg", NULL);
// addr: mct node의reg의 property의 값의 주소
/* Get the interrupts property */
// device: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소
// of_get_property(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, "interrups", &intlen):
// mct node의 rinterrupts의 property의 값의 주소
intspec = of_get_property(device, "interrupts", &intlen);
// intspec: mct node의 interrupts의 property의 값의 주소, intlen: 32
// intspec: mct node의 interrupts의 property의 값의 주소
if (intspec == NULL) {
/* Try the new-style interrupts-extended */
res = of_parse_phandle_with_args(device, "interrupts-extended",
"#interrupt-cells", index, out_irq);
if (res)
return -EINVAL;
return of_irq_parse_raw(addr, out_irq);
}
// intspec: mct node의 interrupts의 property의 값의 주소, intlen: 32
// intlen: 32, sizeof(*mct node의 interrupts의 property의 값의 주소): 4
intlen /= sizeof(*intspec);
// intlen: 8
// intspec: mct node의 interrupts의 property의 값의 주소, intlen: 32
// be32_to_cpup(combiner node의 interrupts의 property의 값의 주소): 0, intlen: 8
pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen);
// " intspec=0 intlen=8\n"
/* Look for the interrupt parent. */
// device: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소
// of_irq_find_parent(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소)
// mct_map node의 주소
p = of_irq_find_parent(device);
// p: mct_map node의 주소
// p: mct_map node의 주소
if (p == NULL)
return -EINVAL;
/* Get size of interrupt specifier */
// p: mct_map node의 주소
// of_get_property(mct_map node의 주소 "#interrupt-cells", NULL):
// mct_map node의 주소 #interrupt-cells의 property의 값의 주소
tmp = of_get_property(p, "#interrupt-cells", NULL);
// tmp: mct_map node의 주소 #interrupt-cells의 property의 값의 주소
// tmp: mct_map node의 주소 #interrupt-cells의 property의 값의 주소
if (tmp == NULL)
goto out;
// tmp: mct_map node의 주소 #interrupt-cells의 property의 값의 주소
// be32_to_cpu(*(mct_map node의 주소 #interrupt-cells의 property의 값의 주소)): 1
intsize = be32_to_cpu(*tmp);
// intsize: 1
// intsize: 1, intlen: 8
pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
// " intsize=1 intlen=8\n"
/* Check index */
// index: 0, intsize: 1, intlen: 8
if ((index + 1) * intsize > intlen)
goto out;
/* Copy intspec into irq structure */
// intspec: mct node의 interrupts의 property의 값의 주소, index: 0, intsize: 1
intspec += index * intsize;
// intspec: mct node의 interrupts의 property의 값의 주소
// out_irq->np: (&oirq)->np, p: mct_map node의 주소
out_irq->np = p;
// out_irq->np: (&oirq)->np: mct_map node의 주소
// out_irq->args_count: (&oirq)->args_count, intsize: 1
out_irq->args_count = intsize;
// out_irq->args_count: (&oirq)->args_count: 1
// intsize: 1
for (i = 0; i < intsize; i++)
// i: 0, out_irq->args[0]: (&oirq)->args[0], intspec: mct node의 interrupts의 property의 값의 주소
// be32_to_cpup(mct node의 interrupts의 property의 값의 주소): 0
out_irq->args[i] = be32_to_cpup(intspec++);
// out_irq->args[0]: (&oirq)->args[0]: 0, intspec: mct node의 interrupts의 property의 값의 주소 + 1
/* Check if there are any interrupt-map translations to process */
// addr: mct node의reg의 property의 값의 주소
res = of_irq_parse_raw(addr, out_irq);
- call: start_kernel()->time_init()->clocksource_of_init()->init_func(np)
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- init_func(np)->mct_init_spi()->mct_init_dt()
- exynos_mct.c::mct_init_dt()->irq_of_parse_and_map()
- res = of_irq_parse_raw(addr, out_irq);
- ->irq.c::irq_of_parse_and_map()->of_irq_parse_one()
- ->irq.c::of_irq_parse_raw()
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- init_func(np)->mct_init_spi()->mct_init_dt()
- exynos_mct.c::mct_init_dt()->irq_of_parse_and_map()
- irq.c::irq_of_parse_and_map()->of_irq_parse_one()
- exynos_mct.c::mct_init_dt()->irq_of_parse_and_map()
// ARM10C 20150307
// dev: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, index: 0, &oirq
int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
{
struct device_node *p;
const __be32 *intspec, *tmp, *addr;
u32 intsize, intlen;
// EINVAL: 23
int i, res = -EINVAL;
// res: -23
// device: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소
// of_node_full_name(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소):
// "mct@101C0000", index: 0
pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);
// "of_irq_parse_one: dev=mct@101C0000, index=0\n"
/* OldWorld mac stuff is "special", handle out of line */
// of_irq_workarounds: 0, OF_IMAP_OLDWORLD_MAC: 0x00000001
if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
return of_irq_parse_oldworld(device, index, out_irq);
/* Get the reg property (if any) */
// device: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소
// of_get_property(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, "reg", NULL):
// mct node의reg의 property의 값의 주소
addr = of_get_property(device, "reg", NULL);
// addr: mct node의reg의 property의 값의 주소
/* Get the interrupts property */
// device: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소
// of_get_property(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, "interrups", &intlen):
// mct node의 rinterrupts의 property의 값의 주소
intspec = of_get_property(device, "interrupts", &intlen);
// intspec: mct node의 interrupts의 property의 값의 주소, intlen: 32
// intspec: mct node의 interrupts의 property의 값의 주소
if (intspec == NULL) {
/* Try the new-style interrupts-extended */
res = of_parse_phandle_with_args(device, "interrupts-extended",
"#interrupt-cells", index, out_irq);
if (res)
return -EINVAL;
return of_irq_parse_raw(addr, out_irq);
}
// intspec: mct node의 interrupts의 property의 값의 주소, intlen: 32
// intlen: 32, sizeof(*mct node의 interrupts의 property의 값의 주소): 4
intlen /= sizeof(*intspec);
// intlen: 8
// intspec: mct node의 interrupts의 property의 값의 주소, intlen: 32
// be32_to_cpup(combiner node의 interrupts의 property의 값의 주소): 0, intlen: 8
pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen);
// " intspec=0 intlen=8\n"
/* Look for the interrupt parent. */
// device: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소
// of_irq_find_parent(devtree에서 allnext로 순회 하면서 찾은 mct node의 주소)
// mct_map node의 주소
p = of_irq_find_parent(device);
// p: mct_map node의 주소
// p: mct_map node의 주소
if (p == NULL)
return -EINVAL;
/* Get size of interrupt specifier */
// p: mct_map node의 주소
// of_get_property(mct_map node의 주소 "#interrupt-cells", NULL):
// mct_map node의 주소 #interrupt-cells의 property의 값의 주소
tmp = of_get_property(p, "#interrupt-cells", NULL);
// tmp: mct_map node의 주소 #interrupt-cells의 property의 값의 주소
// tmp: mct_map node의 주소 #interrupt-cells의 property의 값의 주소
if (tmp == NULL)
goto out;
// tmp: mct_map node의 주소 #interrupt-cells의 property의 값의 주소
// be32_to_cpu(*(mct_map node의 주소 #interrupt-cells의 property의 값의 주소)): 1
intsize = be32_to_cpu(*tmp);
// intsize: 1
// intsize: 1, intlen: 8
pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
// " intsize=1 intlen=8\n"
/* Check index */
// index: 0, intsize: 1, intlen: 8
if ((index + 1) * intsize > intlen)
goto out;
/* Copy intspec into irq structure */
// intspec: mct node의 interrupts의 property의 값의 주소, index: 0, intsize: 1
intspec += index * intsize;
// intspec: mct node의 interrupts의 property의 값의 주소
// out_irq->np: (&oirq)->np, p: mct_map node의 주소
out_irq->np = p;
// out_irq->np: (&oirq)->np: mct_map node의 주소
// out_irq->args_count: (&oirq)->args_count, intsize: 1
out_irq->args_count = intsize;
// out_irq->args_count: (&oirq)->args_count: 1
// intsize: 1
for (i = 0; i < intsize; i++)
// i: 0, out_irq->args[0]: (&oirq)->args[0], intspec: mct node의 interrupts의 property의 값의 주소
// be32_to_cpup(mct node의 interrupts의 property의 값의 주소): 0
out_irq->args[i] = be32_to_cpup(intspec++);
// out_irq->args[0]: (&oirq)->args[0]: 0, intspec: mct node의 interrupts의 property의 값의 주소 + 1
/* Check if there are any interrupt-map translations to process */
// addr: mct node의reg의 property의 값의 주소
res = of_irq_parse_raw(addr, out_irq);
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- init_func(np)->mct_init_spi()->mct_init_dt()
- exynos_mct.c::mct_init_dt()->irq_of_parse_and_map()
- res = of_irq_parse_raw(addr, out_irq);
- ->irq.c::irq_of_parse_and_map()->of_irq_parse_one()
- ->irq.c::of_irq_parse_raw()
- ->irq.c::irq_of_parse_and_map()->of_irq_parse_one()
irq.c::of_irq_parse_raw()
- called: start_kernel()->time_init()->clocksource_of_init()->init_func(np)
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- init_func(np)->mct_init_spi()->mct_init_dt()
- exynos_mct.c::mct_init_dt()->irq_of_parse_and_map()
- res = of_irq_parse_raw(addr, out_irq);
- ->irq.c::irq_of_parse_and_map()->of_irq_parse_one()
- ->irq.c::of_irq_parse_raw()
// ARM10C 20150307
// addr: mct node의 reg의 property의 값의 주소, out_irq: &oirq
int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
{
struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
// old: NULL, newpar: NULL
// MAX_PHANDLE_ARGS: 8
__be32 initial_match_array[MAX_PHANDLE_ARGS];
const __be32 *match_array = initial_match_array;
// match_array: initial_match_array
// MAX_PHANDLE_ARGS: 8
const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 };
// dummy_imask[0...7]: 0xffffffff
u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
// intsize: 1, newintsize: 0, newaddrsize: 0
int imaplen, match, i;
#ifdef DEBUG // undefined
of_print_phandle_args("of_irq_parse_raw: ", out_irq);
#endif
// out_irq->np: (&oirq)->np: mct_map node의 주소
// of_node_get((&oirq)->np): mct_map node의 주소
ipar = of_node_get(out_irq->np);
// ipar: mct_map node의 주소
/* First get the #interrupt-cells property of the current cursor
* that tells us how to interpret the passed-in intspec. If there
* is none, we are nice and just walk up the tree
*/
do {
// ipar: mct_map node의 주소
// of_get_property(mct_map node의 주소, "#interrupt-cells", NULL):
// mct_map node의 #interrupt-cells의 property 값의 주소
tmp = of_get_property(ipar, "#interrupt-cells", NULL);
// tmp: mct_map node의 #interrupt-cells의 property 값의 주소
// tmp: mct_map node의 #interrupt-cells의 property 값의 주소
if (tmp != NULL) {
// tmp: mct_map node의 #interrupt-cells의 property 값의 주소
// be32_to_cpu(*(mct_map node의 #interrupt-cells의 property 값의 주소)): 1
intsize = be32_to_cpu(*tmp);
// intsize: 1
break;
// break 수행
}
tnode = ipar;
ipar = of_irq_find_parent(ipar);
of_node_put(tnode);
} while (ipar);
// ipar: mct_map node의 주소
if (ipar == NULL) {
pr_debug(" -> no parent found !\n");
goto fail;
}
// ipar: mct_map node의 주소
// of_node_full_name(mct_map node의 주소): "mct-map", intsize: 1
pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize);
// "of_irq_parse_raw: ipar=mct-map, size=1\n"
// out_irq->args_count: (&oirq)->args_count: 1, intsize: 1
if (out_irq->args_count != intsize)
return -EINVAL;
/* Look for this #address-cells. We have to implement the old linux
* trick of looking for the parent here as some device-trees rely on it
*/
// ipar: mct_map node의 주소, of_node_get(mct_map node의 주소): mct_map node의 주소
old = of_node_get(ipar);
// old: mct_map node의 주소
do {
// old: mct_map node의 주소,
// of_get_property(mct_map node의 주소, "#address-cells", NULL): mct_map node의 #address-cells의 property 값의 주소
tmp = of_get_property(old, "#address-cells", NULL);
// tmp: mct_map node의 #address-cells의 property 값의 주소
// FIXME:
// of_get_parent(mct_map node의 주소): XXX
// of_get_parent(mct_map node의 주소)의 값은 확인 필요,
// 코드 분석상 확인 할수 없는 상태라 XXX 로 써놓고 분석
// old: mct_map node의 주소, of_get_parent(mct_map node의 주소): XXX
tnode = of_get_parent(old);
// tnode: XXX
// old: mct_map node의 주소
of_node_put(old); // null function
// tnode: XXX
old = tnode;
// old: XXX
// old: XXX, tmp: mct_map node의 #address-cells의 property 값의 주소
} while (old && tmp == NULL);
// old: XXX
of_node_put(old); // null function
// old: XXX
old = NULL;
// old: NULL
// tmp: mct_map node의 #address-cells의 property 값의 주소
// be32_to_cpu(*(mct_map node의 #address-cells의 property 값의 주소)): 0
addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp);
// addrsize: 0
// addrsize: 0
pr_debug(" -> addrsize=%d\n", addrsize);
// " -> addrsize=0\n"
/* Range check so that the temporary buffer doesn't overflow */
// addrsize: 0, intsize: 1, MAX_PHANDLE_ARGS: 8
if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS))
goto fail;
/* Precalculate the match array - this simplifies match loop */
// addrsize: 0
for (i = 0; i < addrsize; i++)
// i: 0, initial_match_array[0], addr: reg의 property의 값의 주소
// addr[0]: (reg의 property의 값의 주소)[0]: 0x10440000
initial_match_array[i] = addr ? addr[i] : 0;
// initial_match_array[0]: 0x10440000
// intsize: 1
for (i = 0; i < intsize; i++)
// i: 0, addrsize: 0, initial_match_array[0],
// out_irq->args[0]: (&oirq)->args[0], cpu_to_be32((&oirq)->args[0]): 0
initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]);
// initial_match_array[0]: 0
/* Now start the actual "proper" walk of the interrupt tree */
// ipar: mct_map node의 주소
while (ipar != NULL) {
/* Now check if cursor is an interrupt-controller and if it is
* then we are done
*/
// ipar: mct_map node의 주소
// of_get_property(mct_map node의 주소, "interrupt-controller", NULL): NULL
// ipar: exynos5420 dtb상의 combiner node의 주소
// of_get_property(exynos5420 dtb상의 combiner node의 주소, "interrupt-controller", NULL): NULL 아닌값
if (of_get_property(ipar, "interrupt-controller", NULL) !=
NULL) {
pr_debug(" -> got it !\n");
// " -> got it !\n"
return 0;
// return 0
}
/*
* interrupt-map parsing does not work without a reg
* property when #address-cells != 0
*/
// addrsize: 0, addr: mct node의 reg의 property의 값의 주소
if (addrsize && !addr) {
pr_debug(" -> no reg passed in when needed !\n");
goto fail;
}
/* Now look for an interrupt-map */
// ipar: mct_map node의 주소
// of_get_property(mct_map node의 주소, "interrupt-map", &imaplen):
// mct_map node의 interrupt-map의 property 값의 주소, imaplen: 128
imap = of_get_property(ipar, "interrupt-map", &imaplen);
// imap: mct_map node의 interrupt-map의 property 값의 주소
/* No interrupt map, check for an interrupt parent */
// imap: mct_map node의 interrupt-map의 property 값의 주소
if (imap == NULL) {
pr_debug(" -> no map, getting parent\n");
newpar = of_irq_find_parent(ipar);
goto skiplevel;
}
// imaplen: 128, sizeof(u32): 4
imaplen /= sizeof(u32);
// imaplen: 32
/* Look for a mask */
// ipar: mct_map node의 주소
// of_get_property(mct_map node의 주소, "interrupt-map-mask", NULL): NULL
imask = of_get_property(ipar, "interrupt-map-mask", NULL);
// imask: NULL
// imask: NULL
if (!imask)
imask = dummy_imask;
// imask: &dummy_imask
/* Parse interrupt-map */
match = 0;
// match: 0
// imaplen: 32, addrsize: 0, intsize: 1, match: 0
while (imaplen > (addrsize + intsize + 1) && !match) {
/* Compare specifiers */
match = 1;
// match: 1
// addrsize: 0, intsize: 1, imaplen: 32
for (i = 0; i < (addrsize + intsize); i++, imaplen--)
// match: 1
// i: 0, match_array[0]: initial_match_array[0]: 0,
// *imap: *(mct_map node의 interrupt-map의 property 값의 주소): 0
// imask[0]: dummy_imask[0]: 0xffffffff
match &= !((match_array[i] ^ *imap++) & imask[i]);
// match: 1, imap: mct_map node의 interrupt-map의 property 값의 주소+4
// match: 1, imaplen: 31,
pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
// " -> match=1 (imaplen=31)\n"
/* Get the interrupt parent */
// of_irq_workarounds: 0, OF_IMAP_NO_PHANDLE: 0x00000002
if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
newpar = of_node_get(of_irq_dflt_pic);
else
// imap: mct_map node의 interrupt-map의 property 값의 주소+4
// be32_to_cpup(mct_map node의 interrupt-map의 property 값의 주소+4):
// mct_map node의 interrupt-map의 property 값의 주소+4
// of_find_node_by_phandle(mct_map node의 interrupt-map의 property 값의 주소+4):
// exynos5420 dtb상의 combiner node의 주소
newpar = of_find_node_by_phandle(be32_to_cpup(imap));
// newpar: exynos5420 dtb상의 combiner node의 주소
// imap: mct_map node의 interrupt-map의 property 값의 주소+4
imap++;
// imap: mct_map node의 interrupt-map의 property 값의 주소+8
// imaplen: 31
--imaplen;
// imaplen: 30
/* Check if not found */
// newpar: exynos5420 dtb상의 combiner node의 주소
if (newpar == NULL) {
pr_debug(" -> imap parent not found !\n");
goto fail;
}
/* Get #interrupt-cells and #address-cells of new
* parent
*/
// newpar: exynos5420 dtb상의 combiner node의 주소
// of_get_property(exynos5420 dtb상의 combiner node의 주소, "#interrupt-cells", NULL):
// combiner node의 #interrupt-cells의 property 값의 주소
tmp = of_get_property(newpar, "#interrupt-cells", NULL);
// tmp: combiner node의 #interrupt-cells의 property 값의 주소
// tmp: combiner node의 #interrupt-cells의 property 값의 주소
if (tmp == NULL) {
pr_debug(" -> parent lacks #interrupt-cells!\n");
goto fail;
}
// tmp: combiner node의 #interrupt-cells의 property 값의 주소
// be32_to_cpu(*(combiner node의 #interrupt-cells의 property 값의 주소)): 2
newintsize = be32_to_cpu(*tmp);
// newintsize: 2
// newpar: exynos5420 dtb상의 combiner node의 주소
// of_get_property(exynos5420 dtb상의 combiner node의 주소, "#address-cells", NULL): NULL
tmp = of_get_property(newpar, "#address-cells", NULL);
// tmp: NULL
// tmp: NULL
newaddrsize = (tmp == NULL) ? 0 : be32_to_cpu(*tmp);
// newaddrsize: 0
// newintsize: 2, newaddrsize: 0
pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
newintsize, newaddrsize);
// " -> newintsize=2, newaddrsize=0\n"
/* Check for malformed properties */
// newintsize: 2, newaddrsize: 0, MAX_PHANDLE_ARGS: 8
if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS))
goto fail;
// imaplen: 30, newintsize: 2, newaddrsize: 0
if (imaplen < (newaddrsize + newintsize))
goto fail;
// imap: mct_map node의 interrupt-map의 property 값의 주소+8,
// newintsize: 2, newaddrsize: 0
imap += newaddrsize + newintsize;
// imap: mct_map node의 interrupt-map의 property 값의 주소+16
// imaplen: 30, newintsize: 2, newaddrsize: 0
imaplen -= newaddrsize + newintsize;
// imaplen: 28
// imaplen: 28
pr_debug(" -> imaplen=%d\n", imaplen);
// " -> imaplen=28\n"
// imaplen: 28, addrsize: 0, intsize: 1, match: 1
}
// match: 1
if (!match)
goto fail;
/*
* Successfully parsed an interrrupt-map translation; copy new
* interrupt specifier into the out_irq structure
*/
// out_irq->np: (&oirq)->np, newpar: exynos5420 dtb상의 combiner node의 주소
out_irq->np = newpar;
// out_irq->np: (&oirq)->np: exynos5420 dtb상의 combiner node의 주소
// imap: mct_map node의 interrupt-map의 property 값의 주소+16, newaddrsize: 0, newintsize: 2
match_array = imap - newaddrsize - newintsize;
// match_array: mct_map node의 interrupt-map의 property 값의 주소+8
// newintsize: 2
for (i = 0; i < newintsize; i++)
// i: 0, out_irq->args[0]: (&oirq)->args[0],
// imap: mct_map node의 interrupt-map의 property 값의 주소+16, newintsize: 2
// be32_to_cpup(mct_map node의 interrupt-map의 property 값의 주소+8): 23
// i: 1, out_irq->args[1]: (&oirq)->args[1],
// imap: mct_map node의 interrupt-map의 property 값의 주소+16, newintsize: 2
// be32_to_cpup(mct_map node의 interrupt-map의 property 값의 주소+12): 3
out_irq->args[i] = be32_to_cpup(imap - newintsize + i);
// out_irq->args[0]: (&oirq)->args[0]: 23
// out_irq->args[1]: (&oirq)->args[1]: 3
// out_irq->args_count: (&oirq)->args_count, intsize: 1, newintsize: 2
out_irq->args_count = intsize = newintsize;
// out_irq->args_count: (&oirq)->args_count: 2, intsize: 2
// addrsize: 0, newaddrsize: 0
addrsize = newaddrsize;
// addrsize: 0
skiplevel:
/* Iterate again with new parent */
// newpar: exynos5420 dtb상의 combiner node의 주소
// of_node_full_name(exynos5420 dtb상의 combiner node의 주소): interrupt-controller@10440000
pr_debug(" -> new parent: %s\n", of_node_full_name(newpar));
// " -> new parent: interrupt-controller@10440000\n"
// ipar: mct_map node의 주소
of_node_put(ipar); // null function
// ipar: mct_map node의 주소, newpar: exynos5420 dtb상의 combiner node의 주소
ipar = newpar;
// ipar: exynos5420 dtb상의 combiner node의 주소
newpar = NULL;
// newpar: NULL
}
fail:
of_node_put(ipar);
of_node_put(newpar);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(of_irq_parse_raw);
- // np: devtree에서 allnext로 순회 하면서 찾은 mct node의 주소, MCT_INT_SPI: 0
- init_func(np)->mct_init_spi()->mct_init_dt()
- exynos_mct.c::mct_init_dt()->irq_of_parse_and_map()
- res = of_irq_parse_raw(addr, out_irq);
- ->irq.c::irq_of_parse_and_map()->of_irq_parse_one()
- ->irq.c::of_irq_parse_raw()
- ->irq.c::irq_of_parse_and_map()->of_irq_parse_one()
// ARM10C 20150307
// addr: mct node의 reg의 property의 값의 주소, out_irq: &oirq
int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
{
struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
// old: NULL, newpar: NULL
// MAX_PHANDLE_ARGS: 8
__be32 initial_match_array[MAX_PHANDLE_ARGS];
const __be32 *match_array = initial_match_array;
// match_array: initial_match_array
// MAX_PHANDLE_ARGS: 8
const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 };
// dummy_imask[0...7]: 0xffffffff
u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
// intsize: 1, newintsize: 0, newaddrsize: 0
int imaplen, match, i;
#ifdef DEBUG // undefined
of_print_phandle_args("of_irq_parse_raw: ", out_irq);
#endif
// out_irq->np: (&oirq)->np: mct_map node의 주소
// of_node_get((&oirq)->np): mct_map node의 주소
ipar = of_node_get(out_irq->np);
// ipar: mct_map node의 주소
/* First get the #interrupt-cells property of the current cursor
* that tells us how to interpret the passed-in intspec. If there
* is none, we are nice and just walk up the tree
*/
do {
// ipar: mct_map node의 주소
// of_get_property(mct_map node의 주소, "#interrupt-cells", NULL):
// mct_map node의 #interrupt-cells의 property 값의 주소
tmp = of_get_property(ipar, "#interrupt-cells", NULL);
// tmp: mct_map node의 #interrupt-cells의 property 값의 주소
// tmp: mct_map node의 #interrupt-cells의 property 값의 주소
if (tmp != NULL) {
// tmp: mct_map node의 #interrupt-cells의 property 값의 주소
// be32_to_cpu(*(mct_map node의 #interrupt-cells의 property 값의 주소)): 1
intsize = be32_to_cpu(*tmp);
// intsize: 1
break;
// break 수행
}
tnode = ipar;
ipar = of_irq_find_parent(ipar);
of_node_put(tnode);
} while (ipar);
// ipar: mct_map node의 주소
if (ipar == NULL) {
pr_debug(" -> no parent found !\n");
goto fail;
}
// ipar: mct_map node의 주소
// of_node_full_name(mct_map node의 주소): "mct-map", intsize: 1
pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize);
// "of_irq_parse_raw: ipar=mct-map, size=1\n"
// out_irq->args_count: (&oirq)->args_count: 1, intsize: 1
if (out_irq->args_count != intsize)
return -EINVAL;
/* Look for this #address-cells. We have to implement the old linux
* trick of looking for the parent here as some device-trees rely on it
*/
// ipar: mct_map node의 주소, of_node_get(mct_map node의 주소): mct_map node의 주소
old = of_node_get(ipar);
// old: mct_map node의 주소
do {
// old: mct_map node의 주소,
// of_get_property(mct_map node의 주소, "#address-cells", NULL): mct_map node의 #address-cells의 property 값의 주소
tmp = of_get_property(old, "#address-cells", NULL);
// tmp: mct_map node의 #address-cells의 property 값의 주소
// FIXME:
// of_get_parent(mct_map node의 주소): XXX
// of_get_parent(mct_map node의 주소)의 값은 확인 필요,
// 코드 분석상 확인 할수 없는 상태라 XXX 로 써놓고 분석
// old: mct_map node의 주소, of_get_parent(mct_map node의 주소): XXX
tnode = of_get_parent(old);
// tnode: XXX
// old: mct_map node의 주소
of_node_put(old); // null function
// tnode: XXX
old = tnode;
// old: XXX
// old: XXX, tmp: mct_map node의 #address-cells의 property 값의 주소
} while (old && tmp == NULL);
// old: XXX
of_node_put(old); // null function
// old: XXX
old = NULL;
// old: NULL
// tmp: mct_map node의 #address-cells의 property 값의 주소
// be32_to_cpu(*(mct_map node의 #address-cells의 property 값의 주소)): 0
addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp);
// addrsize: 0
// addrsize: 0
pr_debug(" -> addrsize=%d\n", addrsize);
// " -> addrsize=0\n"
/* Range check so that the temporary buffer doesn't overflow */
// addrsize: 0, intsize: 1, MAX_PHANDLE_ARGS: 8
if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS))
goto fail;
/* Precalculate the match array - this simplifies match loop */
// addrsize: 0
for (i = 0; i < addrsize; i++)
// i: 0, initial_match_array[0], addr: reg의 property의 값의 주소
// addr[0]: (reg의 property의 값의 주소)[0]: 0x10440000
initial_match_array[i] = addr ? addr[i] : 0;
// initial_match_array[0]: 0x10440000
// intsize: 1
for (i = 0; i < intsize; i++)
// i: 0, addrsize: 0, initial_match_array[0],
// out_irq->args[0]: (&oirq)->args[0], cpu_to_be32((&oirq)->args[0]): 0
initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]);
// initial_match_array[0]: 0
/* Now start the actual "proper" walk of the interrupt tree */
// ipar: mct_map node의 주소
while (ipar != NULL) {
/* Now check if cursor is an interrupt-controller and if it is
* then we are done
*/
// ipar: mct_map node의 주소
// of_get_property(mct_map node의 주소, "interrupt-controller", NULL): NULL
// ipar: exynos5420 dtb상의 combiner node의 주소
// of_get_property(exynos5420 dtb상의 combiner node의 주소, "interrupt-controller", NULL): NULL 아닌값
if (of_get_property(ipar, "interrupt-controller", NULL) !=
NULL) {
pr_debug(" -> got it !\n");
// " -> got it !\n"
return 0;
// return 0
}
/*
* interrupt-map parsing does not work without a reg
* property when #address-cells != 0
*/
// addrsize: 0, addr: mct node의 reg의 property의 값의 주소
if (addrsize && !addr) {
pr_debug(" -> no reg passed in when needed !\n");
goto fail;
}
/* Now look for an interrupt-map */
// ipar: mct_map node의 주소
// of_get_property(mct_map node의 주소, "interrupt-map", &imaplen):
// mct_map node의 interrupt-map의 property 값의 주소, imaplen: 128
imap = of_get_property(ipar, "interrupt-map", &imaplen);
// imap: mct_map node의 interrupt-map의 property 값의 주소
/* No interrupt map, check for an interrupt parent */
// imap: mct_map node의 interrupt-map의 property 값의 주소
if (imap == NULL) {
pr_debug(" -> no map, getting parent\n");
newpar = of_irq_find_parent(ipar);
goto skiplevel;
}
// imaplen: 128, sizeof(u32): 4
imaplen /= sizeof(u32);
// imaplen: 32
/* Look for a mask */
// ipar: mct_map node의 주소
// of_get_property(mct_map node의 주소, "interrupt-map-mask", NULL): NULL
imask = of_get_property(ipar, "interrupt-map-mask", NULL);
// imask: NULL
// imask: NULL
if (!imask)
imask = dummy_imask;
// imask: &dummy_imask
/* Parse interrupt-map */
match = 0;
// match: 0
// imaplen: 32, addrsize: 0, intsize: 1, match: 0
while (imaplen > (addrsize + intsize + 1) && !match) {
/* Compare specifiers */
match = 1;
// match: 1
// addrsize: 0, intsize: 1, imaplen: 32
for (i = 0; i < (addrsize + intsize); i++, imaplen--)
// match: 1
// i: 0, match_array[0]: initial_match_array[0]: 0,
// *imap: *(mct_map node의 interrupt-map의 property 값의 주소): 0
// imask[0]: dummy_imask[0]: 0xffffffff
match &= !((match_array[i] ^ *imap++) & imask[i]);
// match: 1, imap: mct_map node의 interrupt-map의 property 값의 주소+4
// match: 1, imaplen: 31,
pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
// " -> match=1 (imaplen=31)\n"
/* Get the interrupt parent */
// of_irq_workarounds: 0, OF_IMAP_NO_PHANDLE: 0x00000002
if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
newpar = of_node_get(of_irq_dflt_pic);
else
// imap: mct_map node의 interrupt-map의 property 값의 주소+4
// be32_to_cpup(mct_map node의 interrupt-map의 property 값의 주소+4):
// mct_map node의 interrupt-map의 property 값의 주소+4
// of_find_node_by_phandle(mct_map node의 interrupt-map의 property 값의 주소+4):
// exynos5420 dtb상의 combiner node의 주소
newpar = of_find_node_by_phandle(be32_to_cpup(imap));
// newpar: exynos5420 dtb상의 combiner node의 주소
// imap: mct_map node의 interrupt-map의 property 값의 주소+4
imap++;
// imap: mct_map node의 interrupt-map의 property 값의 주소+8
// imaplen: 31
--imaplen;
// imaplen: 30
/* Check if not found */
// newpar: exynos5420 dtb상의 combiner node의 주소
if (newpar == NULL) {
pr_debug(" -> imap parent not found !\n");
goto fail;
}
/* Get #interrupt-cells and #address-cells of new
* parent
*/
// newpar: exynos5420 dtb상의 combiner node의 주소
// of_get_property(exynos5420 dtb상의 combiner node의 주소, "#interrupt-cells", NULL):
// combiner node의 #interrupt-cells의 property 값의 주소
tmp = of_get_property(newpar, "#interrupt-cells", NULL);
// tmp: combiner node의 #interrupt-cells의 property 값의 주소
// tmp: combiner node의 #interrupt-cells의 property 값의 주소
if (tmp == NULL) {
pr_debug(" -> parent lacks #interrupt-cells!\n");
goto fail;
}
// tmp: combiner node의 #interrupt-cells의 property 값의 주소
// be32_to_cpu(*(combiner node의 #interrupt-cells의 property 값의 주소)): 2
newintsize = be32_to_cpu(*tmp);
// newintsize: 2
// newpar: exynos5420 dtb상의 combiner node의 주소
// of_get_property(exynos5420 dtb상의 combiner node의 주소, "#address-cells", NULL): NULL
tmp = of_get_property(newpar, "#address-cells", NULL);
// tmp: NULL
// tmp: NULL
newaddrsize = (tmp == NULL) ? 0 : be32_to_cpu(*tmp);
// newaddrsize: 0
// newintsize: 2, newaddrsize: 0
pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
newintsize, newaddrsize);
// " -> newintsize=2, newaddrsize=0\n"
/* Check for malformed properties */
// newintsize: 2, newaddrsize: 0, MAX_PHANDLE_ARGS: 8
if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS))
goto fail;
// imaplen: 30, newintsize: 2, newaddrsize: 0
if (imaplen < (newaddrsize + newintsize))
goto fail;
// imap: mct_map node의 interrupt-map의 property 값의 주소+8,
// newintsize: 2, newaddrsize: 0
imap += newaddrsize + newintsize;
// imap: mct_map node의 interrupt-map의 property 값의 주소+16
// imaplen: 30, newintsize: 2, newaddrsize: 0
imaplen -= newaddrsize + newintsize;
// imaplen: 28
// imaplen: 28
pr_debug(" -> imaplen=%d\n", imaplen);
// " -> imaplen=28\n"
// imaplen: 28, addrsize: 0, intsize: 1, match: 1
}
// match: 1
if (!match)
goto fail;
/*
* Successfully parsed an interrrupt-map translation; copy new
* interrupt specifier into the out_irq structure
*/
// out_irq->np: (&oirq)->np, newpar: exynos5420 dtb상의 combiner node의 주소
out_irq->np = newpar;
// out_irq->np: (&oirq)->np: exynos5420 dtb상의 combiner node의 주소
// imap: mct_map node의 interrupt-map의 property 값의 주소+16, newaddrsize: 0, newintsize: 2
match_array = imap - newaddrsize - newintsize;
// match_array: mct_map node의 interrupt-map의 property 값의 주소+8
// newintsize: 2
for (i = 0; i < newintsize; i++)
// i: 0, out_irq->args[0]: (&oirq)->args[0],
// imap: mct_map node의 interrupt-map의 property 값의 주소+16, newintsize: 2
// be32_to_cpup(mct_map node의 interrupt-map의 property 값의 주소+8): 23
// i: 1, out_irq->args[1]: (&oirq)->args[1],
// imap: mct_map node의 interrupt-map의 property 값의 주소+16, newintsize: 2
// be32_to_cpup(mct_map node의 interrupt-map의 property 값의 주소+12): 3
out_irq->args[i] = be32_to_cpup(imap - newintsize + i);
// out_irq->args[0]: (&oirq)->args[0]: 23
// out_irq->args[1]: (&oirq)->args[1]: 3
// out_irq->args_count: (&oirq)->args_count, intsize: 1, newintsize: 2
out_irq->args_count = intsize = newintsize;
// out_irq->args_count: (&oirq)->args_count: 2, intsize: 2
// addrsize: 0, newaddrsize: 0
addrsize = newaddrsize;
// addrsize: 0
skiplevel:
/* Iterate again with new parent */
// newpar: exynos5420 dtb상의 combiner node의 주소
// of_node_full_name(exynos5420 dtb상의 combiner node의 주소): interrupt-controller@10440000
pr_debug(" -> new parent: %s\n", of_node_full_name(newpar));
// " -> new parent: interrupt-controller@10440000\n"
// ipar: mct_map node의 주소
of_node_put(ipar); // null function
// ipar: mct_map node의 주소, newpar: exynos5420 dtb상의 combiner node의 주소
ipar = newpar;
// ipar: exynos5420 dtb상의 combiner node의 주소
newpar = NULL;
// newpar: NULL
}
fail:
of_node_put(ipar);
of_node_put(newpar);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(of_irq_parse_raw);
log
- 94th log
133ca40..5763e9f master -> origin/master
Updating 133ca40..5763e9f
Fast-forward
drivers/clk/clk-mux.c | 62 +++++++--------
drivers/clk/clk.c | 44 +++++-----
drivers/clk/samsung/clk-exynos5420.c | 2 +-
drivers/clk/samsung/clk.c | 6 +-
drivers/of/base.c | 3 +
drivers/of/irq.c | 150 ++++++++++++++++++++++++++++++++++-
include/linux/list.h | 4 +-
include/linux/of.h | 4 +
include/linux/of_irq.h | 2 +
9 files changed, 214 insertions(+), 63 deletions(-)
133ca40..5763e9f master -> origin/master
Updating 133ca40..5763e9f
Fast-forward
drivers/clk/clk-mux.c | 62 +++++++--------
drivers/clk/clk.c | 44 +++++-----
drivers/clk/samsung/clk-exynos5420.c | 2 +-
drivers/clk/samsung/clk.c | 6 +-
drivers/of/base.c | 3 +
drivers/of/irq.c | 150 ++++++++++++++++++++++++++++++++++-
include/linux/list.h | 4 +-
include/linux/of.h | 4 +
include/linux/of_irq.h | 2 +
9 files changed, 214 insertions(+), 63 deletions(-)
댓글 없음:
댓글 쓰기