在分析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 }