dm365管脚复用配置浅析之davinci_cfg_reg调用

dm365管脚复用配置浅析之davinci_cfg_reg调用 

内核版本:linux-2.6.32.17-psp03.01.01.39,leopardboard dm365开发板带的sdk包里面的内核

 

davinci_cfg_reg()函数用来配置dm365的管脚复用功能,调用时直接使用davinci_cfg_reg(index)即可,

其中index是对应的复用功能。它被定义在初始化数组中。要了解davinci_cfg_reg的原理,理解管脚复用表比较关键,下面就详细介绍:

注:以下所有文件都是在内核arch/arm/mach-davince/下,

         本文以dm365的I2C管脚复用为例。

1、davinci_cfg_reg在头文件kernel/arch/arm/mach-davince/include/mach/mux.h中包含如下

#ifdefCONFIG_DAVINCI_MUX

/* setup pinmuxing */

extern intdavinci_cfg_reg(unsigned long reg_cfg);

#else

/* boot loaderdoes it all (no warnings from CONFIG_DAVINCI_MUX_WARNINGS) */

static inlineint davinci_cfg_reg(unsigned long reg_cfg) { return 0; }

#endif

2、davinci_cfg_reg被定义于kernel/arch/arm/mach-davince/mux.c中,如下:

                            /** Setsthe DAVINCI MUX register based on the table*/

int__init_or_module davinci_cfg_reg(const unsigned long index)

{

                            static DEFINE_SPINLOCK(mux_spin_lock); //添加锁

                            struct davinci_soc_info *soc_info = &davinci_soc_info; //传入全局结构体,在dm365.c初始化

                            void __iomem *base = soc_info->pinmux_base;//获得复用寄存器的基地址0x014c0000

                            unsigned long flags;

                            const struct mux_config *cfg;//配置信息结构体,定义于mux.h

                            unsigned int reg_orig = 0, reg = 0;

                            unsigned int mask, warn = 0;

 

                            if(!soc_info->pinmux_pins)

                                     BUG();

 

                            if (index >= soc_info->pinmux_pins_num) {

                                     printk(KERN_ERR "Invalid pin muxindex: %lu (%lu)\n",

                          index, soc_info->pinmux_pins_num);

                                      dump_stack();

                                     return -ENODEV;

                            }

 

                            cfg = &soc_info->pinmux_pins[index];

 

                            if(cfg->name == NULL) {

                                     printk(KERN_ERR "No entry for thespecified index\n");

                                     return -ENODEV;

                            }

 

                            /*Update the mux register in question */

                            if (cfg->mask) {

                                     unsigned     tmp1, tmp2;

 

                                     spin_lock_irqsave(&mux_spin_lock,flags);

                                     reg_orig = __raw_readl(base +cfg->mux_reg);

 

                                     mask = (cfg->mask <<cfg->mask_offset);

                                     tmp1 = reg_orig & mask;

                                     reg = reg_orig & ~mask;

 

                                     tmp2 = (cfg->mode <<cfg->mask_offset);

                                     reg |= tmp2;

 

                                     if (tmp1 != tmp2)

                                               warn = 1;

 

                                     __raw_writel(reg, base +cfg->mux_reg);

                                     spin_unlock_irqrestore(&mux_spin_lock,flags);

                            }

 

         if (warn) {

#ifdefCONFIG_DAVINCI_MUX_WARNINGS

                   printk(KERN_WARNING"MUX: initialized %s\n", cfg->name);

#endif

         }

 

#ifdefCONFIG_DAVINCI_MUX_DEBUG

         if (cfg->debug || warn) {

                   printk(KERN_WARNING"MUX: Setting register %s\n", cfg->name);

                   printk(KERN_WARNING "      %s(0x%08x) = 0x%08x -> 0x%08x\n",

                          cfg->mux_reg_name, cfg->mux_reg,reg_orig, reg);

         }

#endif

 

         return 0;

}

EXPORT_SYMBOL(davinci_cfg_reg);

 

3、现在将详细介绍davinci_cfg_reg的执行步骤:

         1)、添加锁,

         2)、struct davinci_soc_info *soc_info= &davinci_soc_info;

                   davinci_soc_info是一个比较全局结构体,在dm365.c中被初始化,内容如下

         (这里有一个疑问:就是没有弄清楚在什么地方把davinci_soc_infodavinci_soc_info_dm365关联起来的,有知道的朋友,请说明一下)

                   static structdavinci_soc_info davinci_soc_info_dm365 = {

     .io_desc               =dm365_io_desc,

     .io_desc_num                = ARRAY_SIZE(dm365_io_desc),

     .jtag_id_base                 = IO_ADDRESS(0x01c40028),

     .ids                       =dm365_ids,

     .ids_num              =ARRAY_SIZE(dm365_ids),

     .cpu_clks             =dm365_clks,

     .psc_bases            =dm365_psc_bases,

     .psc_bases_num            = ARRAY_SIZE(dm365_psc_bases),       //psc基地址

     .pinmux_base                = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE),

//在include/mach/hardware.h中定义

// #define DAVINCI_SYSTEM_MODULE_BASE  0x01C40000

     .pinmux_pins                = dm365_pins, //dm365所有的管脚复用表,接下来要分析的,在dm365.c中

     .pinmux_pins_num       = ARRAY_SIZE(dm365_pins),//复用数量

     .intc_base             =IO_ADDRESS(DAVINCI_ARM_INTC_BASE),

     .intc_type             =DAVINCI_INTC_TYPE_AINTC,

     .intc_irq_prios               = dm365_default_priorities,

     .intc_irq_num               = DAVINCI_N_AINTC_IRQ,

     .timer_info           =&dm365_timer_info,

     .gpio_base           =IO_ADDRESS(DAVINCI_GPIO_BASE),

     .gpio_num           =104,

     .gpio_irq              =IRQ_DM365_GPIO0,

     .gpio_unbanked            = 8,   /* really 16... skip muxed GPIOs */

     .serial_dev           =&dm365_serial_device,

     .emac_pdata                  =&dm365_emac_pdata,

     .sram_dma           =0x00010000,

     .sram_len             =SZ_32K,

};

                            接着,我们看以下dm365_pins结构

staticconst struct mux_config dm365_pins[] = {

#ifdefCONFIG_DAVINCI_MUX

MUX_CFG(DM365,     MMCSD0,           0,  24,     1,          0,  false)

 

MUX_CFG(DM365,     SD1_CLK, 0,   16,   3,  1,  false)

MUX_CFG(DM365,     SD1_CMD,          4,   30,   3,  1,  false)

MUX_CFG(DM365,     SD1_DATA3,      4,   28,   3,  1,  false)

MUX_CFG(DM365,     SD1_DATA2,      4,   26,   3,  1,  false)

MUX_CFG(DM365,     SD1_DATA1,      4,   24,   3,  1,  false)

MUX_CFG(DM365,     SD1_DATA0,      4,   22,   3,  1,  false)

 

MUX_CFG(DM365,     I2C_SDA,  3,   23,   3,  2,  false)        //I2C的SDA管脚

MUX_CFG(DM365,     I2C_SCL,   3,   21,   3,  2,  false)        //I2C的SCL管脚

 

MUX_CFG(DM365,     AEMIF_AR,        2,   0,    3,            1,  false)

                                     ……..省略其他的一些内容

                                     #endif

};               

                            这个结构体列出了dm365的管脚复用情况,

                            接着看一下MUX_CFG这个宏定义是怎么样的,定义在mux.h中

#defineMUX_CFG(soc, desc, muxreg, mode_offset, mode_mask, mux_mode, dbg)\

[soc##_##desc]= {                                                           \

                       .name =  #desc,                                       \

                       .debug = dbg,                                            \

                       .mux_reg_name ="PINMUX"#muxreg,            \

                       .mux_reg =PINMUX##muxreg,                        \

                       .mask_offset =mode_offset,                     \

                       .mask = mode_mask,                                 \

                       .mode = mux_mode,                                 \

              },

这个宏就是把(DM365,         I2C_SDA,  3,   23,   3,  2,  false)这样的信息转化成mux_configd的格式,其中mux_config定义在include/mach/mux.h里。如下:

structmux_config {

         const char *name;//复用管脚的名字,一般以要复用的功能命名

         const char *mux_reg_name;//复用寄存器的名字

         const unsigned char mux_reg;//复用的配置寄存器

         const unsigned char mask_offset; //偏移量,指寄存器的第几位,比如I2C_SDA是通过

//PINMUX3的24和23位设置的,则偏移量为23,

         const unsigned char mask;

         const unsigned char mode;

//mask和mode的含义。比如要把PINMUX3的23和24为设置成自己想要的值,假设//mask= 3,mode=2,需要这样(reg_old_value& (~(3<<23)))  | (2<<23)

// reg_old_value是寄存器原来的值

         bool debug;//调试标志

};

                                              结合这两个结构体和宏可以得出

                                              MUX_CFG(DM365,     I2C_SDA,  3,   23,   3,  2,  false)

                                     [DM365_I2C_SDA] = {                  .name                 = I2C_SDA,

.debug                = false,

.mux_reg_name          = “PINMUX3”,

.mux_reg             = PINMUX3,

.mask_offset        = 23,

.mask                            = 3,

.mode                  = 2,

},

                   3)、好了,回到davinci_cfg_reg函数的分析。首先检测是否已经定义了管脚复用信息

                            if(!soc_info->pinmux_pins) 这个因为在前面讲的davinci_soc_info初始化的时候已经有了。所以

这一步会继续执行下去

4)、if(index >= soc_info->pinmux_pins_num)检测我们输入的变量值是否超出系统已经定义的

pinmux_pins管脚复用信息表中已有的所有复用之和,一般情况下,index变量是从一个枚  举列表中选择,后面会详细说明index的来由和定义情况。

5)、cfg =&soc_info->pinmux_pins[index];传入需要配置的复用管脚信息,如复用寄存器,偏移量,

复用功能等,这个其实就是第2)步介绍到的mux_config结构体,执行这一步之后cfg的信息如下

cfg->name                            = I2C_SDA,

cfg->debug                  = false,

cfg->mux_reg_name   =“PINMUX3”,

cfg->mux_reg               = PINMUX3,

cfg->mask_offset          = 23,

cfg->mask                     = 3,

cfg->mode                   = 2,

                                 其中PINMUXn在dm365.c中定义:它们的基地址在davinci_soc_info_dm365的

     .pinmux_base      = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE),中已经被定义为0x01c40000

                                     #definePINMUX0                 0x00

#definePINMUX1                 0x04

#definePINMUX2                 0x08

#definePINMUX3                 0x0c

#definePINMUX4                 0x10

                   6)、接着到了配置寄存器的具体操作:

                            if (cfg->mask) {   //位移量肯定大于0,除非没有被定义

                                     unsigned     tmp1, tmp2;

 

                                     spin_lock_irqsave(&mux_spin_lock,flags);//添加锁

                                     reg_orig = __raw_readl(base +cfg->mux_reg);//首先读出寄存器原来的配置

 

                                     mask = (cfg->mask <<cfg->mask_offset);          //相当于3<<23

                                     tmp1 = reg_orig & mask;//把寄存器的24和23位置保留,其余位置0,是为了找出原来的

//配置,以便接下来与新配置对比,检测是不是有不一样,

                                     reg = reg_orig & ~mask; 把寄存器的24和23位置0,其余位不改变。

 

                                     tmp2 = (cfg->mode <<cfg->mask_offset);//把需要配置的模式值以为到24和23.

                                     reg |= tmp2;         //改变寄存器的值,此时已经加入了自己的配置信息

 

                                     if (tmp1 != tmp2)//如果配置前后不一样,输出警告信息,说明寄存器复用情况有变。

                                               warn = 1;

 

                                     __raw_writel(reg, base +cfg->mux_reg);//写寄存器,最终把自己想要的状态设置进去。

                                     spin_unlock_irqrestore(&mux_spin_lock,flags);//解锁。

                            }

                   7)、后面的是一些打印信息。

4、接着说说davinci_cfg_reg(index)里面的index。在include/mach/mux.h中有如下的枚举结构定义

enumdavinci_dm365_index {

     /* MMC/SD 0 */

     DM365_MMCSD0,

 

     /* MMC/SD 1 */

     DM365_SD1_CLK,

     DM365_SD1_CMD,

     DM365_SD1_DATA3,

     DM365_SD1_DATA2,

     DM365_SD1_DATA1,

     DM365_SD1_DATA0,

 

     /* I2C */

     DM365_I2C_SDA,

     DM365_I2C_SCL,

                            …省略很多内容

                   );

这里的枚举类型和staticconst struct mux_config dm365_pins[] 中的内容一一对应,注意这个对应是位置一一对应,比如DM365_I2C_SDA在枚举中排在第八的位置,那么在dm365_pins[]中的位置也要在第八,否则调用的时候会匹配失误得不到自己想要的结果。

 

5、最后,说说如何调用davinci_cfg_reg,首先需要包含头文件,以上说到的和其他比如寄存器的读写函数

等的头文件。接着在枚举类型中加入信息,然后在dm365_pins[]对应位置添加配置信息。

 

6)、以上内容是本人看代码时的一点见解,不确定是否正确,有错误欢迎指正,enjoy~~~~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值