zoukankan      html  css  js  c++  java
  • TI AM335x Linux MUX hacking

    /*********************************************************************************************
     *                           TI AM335x Linux MUX hacking
     *  声明:
     *      1. 本文主要是对TI的AM335x Linux驱动中的引脚复用配置代码进行跟踪;
     *      2. 参考书籍:AM335x ARM® Cortex™-A8 Microprocessors (MPUs) Technical Reference Manual
     *
     *                                             2015-6-25 阵雨 深圳 南山平山村 曾剑锋
     *********************************************************************************************/
    
    
                        \\\\\\-*- 目录 -*-/////////////
                        | 一、跟踪板级文件:                 
                        | 二、跟踪am335x_evm_init()函数:    
                        | 三、跟踪board_mux参数:            
                        | 四、跟踪am33xx_mux_init()函数:    
                        | 五、跟踪am33xx_muxmodes参数:     
                        | 六、跟踪omap_mux_init()函数:      
                        | 七、跟踪omap_mux_init_list()函数: 
                        | 八、跟踪omap_mux_init_signals函数:
                        \\\\\\\\\\//////////////////
    
    
    
    一、跟踪板级文件:
        ......
        MACHINE_START(AM335XEVM, "am335xevm")
            /* Maintainer: Texas Instruments */
            .atag_offset    = 0x100,
            .map_io     = am335x_evm_map_io,
            .init_early = am33xx_init_early,
            .init_irq   = ti81xx_init_irq,
            .handle_irq     = omap3_intc_handle_irq,
            .timer      = &omap3_am33xx_timer,
            .init_machine   = am335x_evm_init,          // 跟踪该函数
        MACHINE_END                                            ^
                                                               |
        MACHINE_START(AM335XIAEVM, "am335xiaevm")              |
            /* Maintainer: Texas Instruments */                |
            .atag_offset    = 0x100,                           |
            .map_io     = am335x_evm_map_io,                   |
            .init_irq   = ti81xx_init_irq,                     |
            .init_early = am33xx_init_early,                   |
            .timer      = &omap3_am33xx_timer,                 |
            .init_machine   = am335x_evm_init,    -------------+
        MACHINE_END
    
    二、跟踪am335x_evm_init()函数:
        static void __init am335x_evm_init(void)
        {
            am33xx_cpuidle_init();
            am33xx_mux_init(board_mux);         // 跟踪函数、参数
            omap_serial_init();
            am335x_evm_i2c_init();
            omap_sdrc_init(NULL, NULL);
            usb_musb_init(&musb_board_data);
            omap_board_config = am335x_evm_config;
            omap_board_config_size = ARRAY_SIZE(am335x_evm_config);
            /* Create an alias for icss clock */
            if (clk_add_alias("pruss", NULL, "pruss_uart_gclk", NULL))
                pr_warn("failed to create an alias: icss_uart_gclk --> pruss
    ");
            /* Create an alias for gfx/sgx clock */
            if (clk_add_alias("sgx_ck", NULL, "gfx_fclk", NULL))
                pr_warn("failed to create an alias: gfx_fclk --> sgx_ck
    ");
        } 
    
    三、跟踪board_mux参数:
        1. 跟踪board_mux[]数组:
            static struct omap_board_mux board_mux[] __initdata = {
                /*
                 * Setting SYSBOOT[5] should set xdma_event_intr0 pin to mode 3 thereby
                 * allowing clkout1 to be available on xdma_event_intr0.
                 * However, on some boards (like EVM-SK), SYSBOOT[5] isn't properly
                 * latched.
                 * To be extra cautious, setup the pin-mux manually.
                 * If any modules/usecase requries it in different mode, then subsequent
                 * module init call will change the mux accordingly.
                 *
                 * 参考书籍:AM335x ARM® Cortex™-A8 Microprocessors (MPUs) Technical Reference Manual -- 760页
                 * --------------------------------------------------------------------
                 * | Offset | Acronym               | Register | Description Section  |
                 * --------------------------------------------------------------------
                 * | 9B0h   | conf_xdma_event_intr0 |          | Section 9.3.51       |
                 * --------------------------------------------------------------------
                 * 观察上面的内容和接下来要配置引脚,我们只需要将Acronym中的conf_前缀去掉,
                 * 然后将剩下的字符串大写,就能配置对应的引脚了,如:
                 *      1. conf_xdma_event_intr0
                 *      2. xdma_event_intr0
                 *      3. XDMA_EVENT_INTR0
                 *                 |
                 *                 |
                 */                V
                AM33XX_MUX(XDMA_EVENT_INTR0, OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT), // 跟踪宏
                AM33XX_MUX(I2C0_SDA, OMAP_MUX_MODE0 | AM33XX_SLEWCTRL_SLOW |
                        AM33XX_INPUT_EN | AM33XX_PIN_OUTPUT),
                AM33XX_MUX(I2C0_SCL, OMAP_MUX_MODE0 | AM33XX_SLEWCTRL_SLOW |
                        AM33XX_INPUT_EN | AM33XX_PIN_OUTPUT),
                { .reg_offset = OMAP_MUX_TERMINATOR }, //后面的程序通过判断这个表示来结束注册
            };
        2. 跟踪struct omap_board_mux结构体:
            /**  
             * struct omap_board_mux - data for initializing mux registers
             * @reg_offset: mux register offset from the mux base
             * @mux_value:  desired mux value to set 
             */          
            struct omap_board_mux {
                u16 reg_offset;
                u16 value;
            };
        3. 跟踪AM33XX_MUX()宏:
            /* If pin is not defined as input, pull would get disabled.
             * If defined as input, flags supplied will determine pull on/off.
             */  
            // 以此为例:
            //     AM33XX_MUX(XDMA_EVENT_INTR0, OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT)
            //
            // .reg_offset = (AM33XX_CONTROL_PADCONF_XDMA_EVENT_INTR0_OFFSET) // 跟踪宏   
            // .value      = (((OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT) & AM33XX_INPUT_EN) 
            //               ? (OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT) 
            //               : ((mux_value) | AM33XX_PULL_DISA)) 
            #define AM33XX_MUX(mode0, mux_value)                    
            {                                   
                .reg_offset = (AM33XX_CONTROL_PADCONF_##mode0##_OFFSET),    
                .value      = (((mux_value) & AM33XX_INPUT_EN) ? (mux_value)
                            : ((mux_value) | AM33XX_PULL_DISA)),    
            }
        4. 跟踪模式宏声明:
            /* 34xx mux mode options for each pin. See TRM for options */
            #define OMAP_MUX_MODE0      0
            #define OMAP_MUX_MODE1      1
            #define OMAP_MUX_MODE2      2
            #define OMAP_MUX_MODE3      3
            #define OMAP_MUX_MODE4      4
            #define OMAP_MUX_MODE5      5
            #define OMAP_MUX_MODE6      6
            #define OMAP_MUX_MODE7      7
        5. 跟踪输出宏声明:
            /* Definition of output pin could have pull disabled, but
             * this has not been done due to two reasons
             * 1. AM33XX_MUX will take care of it
             * 2. If pull was disabled for out macro, combining out & in pull on macros
             *    would disable pull resistor and AM33XX_MUX cannot take care of the
             *    correct pull setting and unintentionally pull would get disabled
             */
            #define AM33XX_PIN_OUTPUT       (0)
        6. 跟踪引脚配置偏移宏,并对比数据手册:
            // 参考书籍:AM335x ARM® Cortex™-A8 Microprocessors (MPUs) Technical Reference Manual -- 760页
            // -----------------------------------------------------------------------
            // | Offset | Acronym               | Register   |  Description Section  |
            // +--------+-----------------------+------------+-----------------------+
            // | 9B0h   | conf_xdma_event_intr0 |            |  Section 9.3.51       |
            // -----------------------------------------------------------------------
            #define AM33XX_CONTROL_PADCONF_XDMA_EVENT_INTR0_OFFSET      0x09B0
    
    四、跟踪am33xx_mux_init()函数:
        1. 跟踪am33xx_mux_init()函数:
        int __init am33xx_mux_init(struct omap_board_mux *board_subset)
        {
            return omap_mux_init("core", 0, AM33XX_CONTROL_PADCONF_MUX_PBASE, // 跟踪参数
                    AM33XX_CONTROL_PADCONF_MUX_SIZE, am33xx_muxmodes,
                    NULL, board_subset, NULL);
        }
        2. 跟踪AM33XX_CONTROL_PADCONF_MUX_PBASE宏:
            // 参考书籍:AM335x ARM® Cortex™-A8 Microprocessors (MPUs) Technical Reference  Manual -- 158页
            // ----------------------------------------------------------------------------------------------------
            // | Region Name     | Start Address (hex) | End Address (hex)  | Size   |       Description          |
            // +-----------------+---------------------+--------------------+--------+----------------------------+
            // | Control Module  |  0x44E1_0000        | 0x44E1_1FFF        | 128KB  |  Control Module Registers  |
            // ----------------------------------------------------------------------------------------------------
            #define AM33XX_CONTROL_PADCONF_MUX_PBASE            0x44E10000LU
        3. 跟踪AM33XX_CONTROL_PADCONF_MUX_SIZE宏:
            // 参考书籍:AM335x ARM® Cortex™-A8 Microprocessors (MPUs) Technical Reference  Manual -- 761页
            // 这里的大小没有搞懂,在datasheet中是1444h,而这里是B34h,没搞懂
            // ----------------------------------------------------------------
            // | Offset | Acronym           | Register | Description Section  |
            // +--------+-------------------+----------+----------------------+
            // | 1444h  | ddr_data1_ioctrl  |          | Section 9.3.92       |
            // ----------------------------------------------------------------
            #define AM33XX_CONTROL_PADCONF_VREFN_OFFSET         0x0B34          
            #define AM33XX_CONTROL_PADCONF_MUX_SIZE             
                     (AM33XX_CONTROL_PADCONF_VREFN_OFFSET + 0x4)
    
    五、跟踪am33xx_muxmodes参数:
        1. 跟踪am33xx_muxmodes[]数组:
            /* AM33XX pin mux super set */
            static struct omap_mux am33xx_muxmodes[] = {
                _AM33XX_MUXENTRY(GPMC_AD0, 0,
                    "gpmc_ad0", "mmc1_dat0", NULL, NULL,
                    NULL, NULL, NULL, "gpio1_0"),
                _AM33XX_MUXENTRY(GPMC_AD1, 0,
                    "gpmc_ad1", "mmc1_dat1", NULL, NULL,
                    NULL, NULL, NULL, "gpio1_1"),
                _AM33XX_MUXENTRY(GPMC_AD2, 0,
                    "gpmc_ad2", "mmc1_dat2", NULL, NULL,
                    NULL, NULL, NULL, "gpio1_2"),
                _AM33XX_MUXENTRY(GPMC_AD3, 0,
                    "gpmc_ad3", "mmc1_dat3", NULL, NULL,
                    NULL, NULL, NULL, "gpio1_3"),
                _AM33XX_MUXENTRY(GPMC_AD4, 0,
                    "gpmc_ad4", "mmc1_dat4", NULL, NULL,
                    NULL, NULL, NULL, "gpio1_4"),
                ......
                { .reg_offset = OMAP_MUX_TERMINATOR },  //后面的程序通过判断这个表示来结束注册
            }
        2. 跟踪struct omap_mux结构体:
            /**
             * struct omap_mux - data for omap mux register offset and it's value
             * @reg_offset: mux register offset from the mux base
             * @gpio:       GPIO number
             * @muxnames:   available signal modes for a ball
             * @balls:      available balls on the package
             * @partition:  mux partition
             */
            struct omap_mux {
                u16 reg_offset;
                u16 gpio;
            #ifdef CONFIG_OMAP_MUX
                char    *muxnames[OMAP_MUX_NR_MODES];
            #ifdef CONFIG_DEBUG_FS
                char    *balls[OMAP_MUX_NR_SIDES];
            #endif   
            #endif
            }; 
        2. 跟踪_AM33XX_MUXENTRY宏:
            //
            // 以此为例:
            //  _AM33XX_MUXENTRY(GPMC_AD0, 0, "gpmc_ad0", "mmc1_dat0", NULL, NULL, NULL, NULL, NULL, "gpio1_0")
            //  
            // .reg_offset = AM33XX_CONTROL_PADCONF_GPMC_AD0_OFFSET 
            // .gpio       = 0      // 相当于取下面muxnames中的第0个
            // .muxnames   = {"gpmc_ad0", "mmc1_dat0", NULL, NULL, NULL, NULL, NULL, "gpio1_0"}
            #define _AM33XX_MUXENTRY(M0, g, m0, m1, m2, m3, m4, m5, m6, m7)     
            {                                   
                .reg_offset = (AM33XX_CONTROL_PADCONF_##M0##_OFFSET),   
                .gpio       = (g),                      
                .muxnames   = { m0, m1, m2, m3, m4, m5, m6, m7 },       
            }
        3. 跟踪AM33XX_CONTROL_PADCONF_GPMC_AD0_OFFSET宏,并对比datasheet:
            // 参考书籍:AM335x ARM® Cortex™-A8 Microprocessors (MPUs) Technical Reference Manual -- 758页
            // ------------------------------------------------------------------------------------------------------------
            // | Offset | Acronym        | Register  | Description Section                                                
            // +--------+----------------+-----------+---------------------------------------------------------------------
            // | 800h   | conf_gpmc_ad0  |           | See the device datasheet for information on default pin Section 9.3.51
            // ------------------------------------------------------------------------------------------------------------
            #define AM33XX_CONTROL_PADCONF_GPMC_AD0_OFFSET          0x0800
    
    六、跟踪omap_mux_init()函数:
        int __init omap_mux_init(const char *name, u32 flags,
                     u32 mux_pbase, u32 mux_size,
                     struct omap_mux *superset,
                     struct omap_mux *package_subset,
                     struct omap_board_mux *board_mux,
                     struct omap_ball *package_balls)
        {
            struct omap_mux_partition *partition;
        
            partition = kzalloc(sizeof(struct omap_mux_partition), GFP_KERNEL);
            if (!partition)
                return -ENOMEM;
        
            partition->name = name;                             // 分区的意思相当于模块的意思
            partition->flags = flags;
            partition->size = mux_size;
            partition->phys = mux_pbase;
            partition->base = ioremap(mux_pbase, mux_size);     // 重新映射IO地址
            if (!partition->base) {
                pr_err("%s: Could not ioremap mux partition at 0x%08x
    ",
                    __func__, partition->phys);
                kfree(partition);
                return -ENODEV;
            }
        
            INIT_LIST_HEAD(&partition->muxmodes);               // 初始化分区头结点链表
        
            list_add_tail(&partition->node, &mux_partitions);   // 将分区加入分区链表
            mux_partitions_cnt++;                               // 分区总数统计
            pr_info("%s: Add partition: #%d: %s, flags: %x
    ", __func__,
                mux_partitions_cnt, partition->name, partition->flags);
        
            omap_mux_init_package(superset, package_subset, package_balls); // 两个都是null
            omap_mux_init_list(partition, superset);                        // 跟踪函数
            omap_mux_init_signals(partition, board_mux);                    // 跟踪函数
        
            return 0;
        }
    
    七、跟踪omap_mux_init_list()函数:
        1. 跟踪omap_mux_init_list()函数:
            /*
             * Note if CONFIG_OMAP_MUX is not selected, we will only initialize
             * the GPIO to mux offset mapping that is needed for dynamic muxing
             * of GPIO pins for off-idle.
             */
            static void __init omap_mux_init_list(struct omap_mux_partition *partition,
                                  struct omap_mux *superset)
            {
                while (superset->reg_offset !=  OMAP_MUX_TERMINATOR) {
                    struct omap_mux *entry;
            
            // 去掉一些不符合要求的的配置引脚
            #ifdef CONFIG_OMAP_MUX
                    if (!superset->muxnames || !superset->muxnames[0]) {
                        superset++;
                        continue;
                    }
            #else
                    /* Skip pins that are not muxed as GPIO by bootloader */
                    if (!OMAP_MODE_GPIO(omap_mux_read(partition,
                                superset->reg_offset))) {
                        superset++;
                        continue;
                    }
            #endif
            
                    entry = omap_mux_list_add(partition, superset);
                    if (!entry) {
                        pr_err("%s: Could not add entry
    ", __func__);
                        return;
                    }
                    superset++;
                }
            }
        2. 跟踪omap_mux_list_add()函数:
            static struct omap_mux * __init omap_mux_list_add(
                                struct omap_mux_partition *partition,
                                struct omap_mux *src)
            {
                struct omap_mux_entry *entry;
                struct omap_mux *m;
            
                entry = kzalloc(sizeof(struct omap_mux_entry), GFP_KERNEL);
                if (!entry)
                    return NULL;
            
                m = &entry->mux;
                entry->mux = *src;
            
            #ifdef CONFIG_OMAP_MUX
                if (omap_mux_copy_names(src, m)) {      // 将数据另存的感觉
                    kfree(entry);
                    return NULL;
                }
            #endif
            
                mutex_lock(&muxmode_mutex);
                list_add_tail(&entry->node, &partition->muxmodes);      // 将节点放入分区节点链表中
                mutex_unlock(&muxmode_mutex);
            
                return m;
            }
        3. 跟踪omap_mux_copy_names()函数:
            // 这个函数的大概意思也就是转存的感觉
            static int __init omap_mux_copy_names(struct omap_mux *src,
                                  struct omap_mux *dst)
            {
                int i;
            
                for (i = 0; i < OMAP_MUX_NR_MODES; i++) {
                    if (src->muxnames[i]) {
                        dst->muxnames[i] = kstrdup(src->muxnames[i],
                                       GFP_KERNEL);
                        if (!dst->muxnames[i])
                            goto free;
                    }
                }
            
            #ifdef CONFIG_DEBUG_FS
                for (i = 0; i < OMAP_MUX_NR_SIDES; i++) {
                    if (src->balls[i]) {
                        dst->balls[i] = kstrdup(src->balls[i], GFP_KERNEL);
                        if (!dst->balls[i])
                            goto free;
                    }
                }
            #endif
            
                return 0;
            
            free:
                omap_mux_free_names(dst);
                return -ENOMEM;
            
            }
    
    八、跟踪omap_mux_init_signals函数:
        1. 跟踪omap_mux_init_signals()函数:
            static void omap_mux_init_signals(struct omap_mux_partition *partition,
                              struct omap_board_mux *board_mux)
            {
                omap_mux_set_cmdline_signals();             // 不知道这里是干啥的,不跟踪
                omap_mux_write_array(partition, board_mux); // 跟踪该函数
            }
        2. 跟踪omap_mux_write_array()函数:
            void omap_mux_write_array(struct omap_mux_partition *partition,
                             struct omap_board_mux *board_mux)
            {
                if (!board_mux)
                    return;
            
                while (board_mux->reg_offset != OMAP_MUX_TERMINATOR) {
                    omap_mux_write(partition, board_mux->value,  // 跟踪函数
                               board_mux->reg_offset);
                    board_mux++;
                }
            }
        3. 跟踪am33xx_mux_init()函数:
            /*
             * int __init am33xx_mux_init(struct omap_board_mux *board_subset)
             *  {   
             *      return omap_mux_init("core", 0 /* flag = 0 */, AM33XX_CONTROL_PADCONF_MUX_PBASE,
             *              AM33XX_CONTROL_PADCONF_MUX_SIZE, am33xx_muxmodes,
             *              NULL, board_subset, NULL);
             *  } 
             */
            void omap_mux_write(struct omap_mux_partition *partition, u16 val,
                           u16 reg)
            {
                if (partition->flags & OMAP_MUX_REG_8BIT)
                    __raw_writeb(val, partition->base + reg);
                else
                    __raw_writew(val, partition->base + reg);
            }
        4. 跟踪OMAP_MUX_REG_8BIT宏:
            /*              
             * omap_mux_init flags definition:
             *   
             * OMAP_MUX_REG_8BIT: Ensure that access to padconf is done in 8 bits.
             * The default value is 16 bits.
             * OMAP_MUX_GPIO_IN_MODE3: The GPIO is selected in mode3.
             * The default is mode4.
             */
            #define OMAP_MUX_REG_8BIT       (1 << 0)
  • 相关阅读:
    A Simple Problem with Integers poj 3468 多树状数组解决区间修改问题。
    Fliptile 开关问题 poj 3279
    Face The Right Way 一道不错的尺取法和标记法题目。 poj 3276
    Aggressive cows 二分不仅仅是查找
    Cable master(二分题 注意精度)
    B. Pasha and String
    Intervals poj 1201 差分约束系统
    UITextField的快速基本使用代码块
    将UIImage转换成圆形图片image
    color转成image对象
  • 原文地址:https://www.cnblogs.com/zengjfgit/p/4599595.html
Copyright © 2011-2022 走看看