原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://blog.csdn.net/piaozhiye
在分析davinci输出视频模块的时候(drivers/media/video/davinci/davincihd_display.c )有这个函数set_vpif_display_pinmux();顾名思义是将引脚复用配置成VPIF的显示功能,刚开始没有在意,后来多看几下就看得迷糊了,就做个分析笔记。
在arch/arm/mach-davinci/video_hdevm.c 定义如下:
236 void set_vpif_display_pinmux()
237 {
238 davinci_cfg_reg(DM646X_STSOMUX_DISABLE);
239 davinci_cfg_reg(DM646X_STSIMUX_DISABLE);
240 davinci_cfg_reg(DM646X_PTSOMUX_DISABLE);
241 }
davinci_cfg_reg()是在arch/arm/mach-davinci/mux.c中定义的寄存器配置函数,其参数就是就是复用表的索引,如下:
100 enum davinci_dm646x_index {
101 /* ATA function */
102 DM646X_ATAEN,
103
104 /* USB */
105 DM646X_VBUSDIS,
106 DM646X_VBUSDIS_GPIO22,
107
108 /* STC source clock input */
109 DM646X_STCCK,
110
111 /* AUDIO Clock */
112 DM646X_AUDCK1,
113 DM646X_AUDCK0,
114
115 /* CRGEN Control */
116 DM646X_CRGMUX,
117
118 /* VPIF Control */
119 DM646X_STSOMUX_DISABLE,
120 DM646X_STSIMUX_DISABLE,
121 DM646X_PTSOMUX_DISABLE,
122 DM646X_PTSIMUX_DISABLE,
………………
}
因为其索引表是枚举类型的,也就是整数,就没弄明白它是什么样配置寄存器的。刚开始就很疑惑。后来经进一步分析发现是在/board-dm6467-evm.c 中初始化,以下是整理一下流程。
在arch/arm/mach-davinci/board-dm6467-evm.c 中初始化,将其编译进内核。最开始内核启动的时候就会打印出DaVinci DM6467 EVM字符串了。
380 MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM6467 EVM")
381 .phys_io = IO_PHYS,
382 .io_pg_offst = (io_p2v(IO_PHYS) >> 18) & 0xfffc,
383 .boot_params = (0x80000100),
384 .map_io = davinci_map_io,
385 .init_irq = davinci_dm6467_evm_irq_init,
386 .timer = &davinci_timer,
387 .init_machine = dm6467_evm_init,
388 MACHINE_END
davinci_dm6467_evm_irq_init中调用davinci_init_common_hw()初始化公共硬件,函数如下,
static __init void davinci_dm6467_evm_irq_init(void)
{
davinci_init_common_hw();
davinci_irq_init();
}
davinci_init_common_hw()在 arch/arm/mach-davinci/io.c 实现,主要是引脚复用初始化和时钟初始化。
55 void __init davinci_init_common_hw(void)
56 {
57 davinci_mux_init();
58 davinci_clk_init();
59 }
davinci_mux_init()在arch/arm/mach-davinci/mux_cfg.c 中实现,代码如下:
调用在arch/arm/mach-davinci/mux.c 中实现的davinci_mux_register注册引脚复用表。
182 void __init davinci_mux_init(void)
183 {
184 if (cpu_is_davinci_dm355())
185 davinci_mux_register(davinci_dm355_pins,
186 ARRAY_SIZE(davinci_dm355_pins));
187 else if (cpu_is_davinci_dm6467())
188 davinci_mux_register(davinci_dm646x_pins,
189 ARRAY_SIZE(davinci_dm646x_pins));
190 else
191 davinci_mux_register(davinci_dm644x_pins,
192 ARRAY_SIZE(davinci_dm644x_pins));
193 }
同时mux_cfg.c中也初始化了复用列表,一直想找到复用列表就在这里初始化
64 struct pin_config __initdata_or_module davinci_dm646x_pins[] = {
65 /*
66 * description mux mode mode mux dbg
67 * reg offset mask mode
68 */
69 MUX_CFG("ATAEN", 0, 0, 1, 1, 1)
70
71 MUX_CFG("VBUSDIS", 0, 31, 1, 0, 0)
72
73 MUX_CFG("VBUSDIS_GPIO22", 0, 31, 1, 1, 0)
74
75 MUX_CFG("STCCK", 0, 30, 1, 1, 0)
76
77 MUX_CFG("AUDCK1", 0, 29, 1, 0, 0)
78
79 MUX_CFG("AUDCK0", 0, 28, 1, 0, 0)
80
81 MUX_CFG("CRGMUX", 0, 24, 7, 5, 0)
82
83 MUX_CFG("STSOMUX_DISABLE", 0, 22, 3, 0, 0)
84
85 MUX_CFG("STSIMUX_DISABLE", 0, 20, 3, 0, 0)
86
87 MUX_CFG("PTSOMUX_DISABLE", 0, 18, 3, 0, 0)
88
89 MUX_CFG("PTSIMUX_DISABLE", 0, 16, 3, 0, 0)
MUX_CFG 就是在include/asm-arm/arch-davinci/mux.h 中的配置宏。
34 #define MUX_CFG(desc, mux_reg, mode_offset, mode_mask, mux_mode, dbg) \
35 { \
36 .name = desc, \
37 .debug = dbg, \
38 MUX_REG(mux_reg, mode_offset, mode_mask, mux_mode) \
39 },
arch/arm/mach-davinci/mux.c 提供了复用的注册和寄存器的配置的接口,具体如下:
28 int __init davinci_mux_register(struct pin_config *pins, unsigned long size)
29 {
30 pin_table = pins;
31 pin_table_sz = size;
32
33 return 0;
34 }
35
36 /*
37 * Sets the DAVINCI MUX register based on the table
38 */
39 int __init_or_module davinci_cfg_reg(const unsigned long index)
40 {
41 static DEFINE_SPINLOCK(mux_spin_lock);
42
43 unsigned long flags;
44 struct pin_config *cfg;
45 unsigned int reg_orig = 0, reg = 0;
46 unsigned int mask, warn = 0;
47
48 if (!pin_table)
49 BUG();
50
51 if (index >= pin_table_sz) {
52 printk(KERN_ERR "Invalid pin mux index: %lu (%lu)\n",
53 index, pin_table_sz);
54 dump_stack();
55 return -ENODEV;
56 }
57
58 cfg = (struct pin_config *)&pin_table[index];
59
60 /* Check the mux register in question */
61 if (cfg->mux_reg) {
62 unsigned tmp1, tmp2;
63
64 spin_lock_irqsave(&mux_spin_lock, flags);
65 reg_orig = davinci_readl(cfg->mux_reg);
66
67 mask = (cfg->mask << cfg->mask_offset);
68 tmp1 = reg_orig & mask;
69 reg = reg_orig & ~mask;
70
71 tmp2 = (cfg->mode << cfg->mask_offset);
72 reg |= tmp2;
73
74 if (tmp1 != tmp2)
75 warn = 1;
76
77 davinci_writel(reg, cfg->mux_reg);
78 spin_unlock_irqrestore(&mux_spin_lock, flags);
79 }
80
81 if (warn) {
82 #ifdef CONFIG_DAVINCI_MUX_WARNINGS
83 printk(KERN_WARNING "MUX: initialized %s\n", cfg->name);
84 #endif
85 }
86
87 #ifdef CONFIG_DAVINCI_MUX_DEBUG
88 if (cfg->debug || warn) {
89 printk(KERN_WARNING "MUX: Setting register %s\n", cfg->name);
90 printk(KERN_WARNING " %s (0x%08x) = 0x%08x -> 0x%08x\n",
91 cfg->mux_reg_name, cfg->mux_reg, reg_orig, reg);
92 }
93 #endif
94
95 return 0;
96 }
97 EXPORT_SYMBOL(davinci_cfg_reg);
它的流程就是这样,使用的时候就像以下代码:
236 void set_vpif_display_pinmux()
237 {
238 davinci_cfg_reg(DM646X_STSOMUX_DISABLE);
239 davinci_cfg_reg(DM646X_STSIMUX_DISABLE);
240 davinci_cfg_reg(DM646X_PTSOMUX_DISABLE);
241 }