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\n");
        /* 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\n");
    } 

三、跟踪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\n",
                __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\n", __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\n", __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)
时间: 2024-11-13 10:17:31

TI AM335x Linux MUX hacking的相关文章

ti processor sdk linux am335x evm Makefile hacking

# # ti processor sdk linux am335x evm Makefile hacking # 说明: # 本文主要对TI的sdk中的Makefile脚本进行解读,是为了了解其工作机制. # 该文件中的一些写法是值得参考的. # 2016-4-16 深圳 南山平山村 曾剑锋 # #platform # PLATFORM=am335x-evm # #defconfig # DEFCONFIG=singlecore-omap2plus_defconfig # #Architectu

TI AM335X处理器介绍

AM335X是美国TI(德州仪器)公司基于 ARM Cortex-A8内核的AM335X微处理器,在图像.图形处理.外设方面进行了增强,并全面支持诸如 EtherCAT 和 PROFIBUS等工业接口.AM335X的优点有如下几个: 第一:该器件是最实惠的Cortex A8 处理芯片,这个对中国市场至关重要 ,甚至是决定性的因素.第二: TI 史上公开资料最全的一个芯片.第三: 产品定位最清晰的一个工业控制MCU第四 : 唯一一个集成2个MAC的 MCU.第五: 目前唯一支持Androd 4.0

基于TI AM335x创龙开发板U-Boot编译

分享一下基于广州创龙TL335x-IDK开发板的U-Boot编译.希望能帮助上你. 板子特点如下: ? 基于 TI AM335x ARM Cortex-A8 CPU,主频可高达 1GHz,运算能力可高达 2000DMIPS,搭配DDR3,兼容 eMMC 和 NAND FLASH,超高性价比: ? 2 个 PRU 协处理器,支持 EtherCAT.PROFINET.EtherNet/IP.PROFIBUS.Ethernet POWERLINK.Sercos 等工业协议: ? 内部集成 SGX530

OK335xS pwm buzzer Linux driver hacking

/**************************************************************************** * OK335xS pwm buzzer Linux driver hacking * 声明: * 本文仅仅是为了知道如何使用pwm来控制buzzer,已达到控制不同声音的频率. * * 2015-10-7 雨 深圳 南山平山村 曾剑锋 *****************************************************

基于TI AM335x创龙开发板的快速体验

着手体验的是创龙TL335x-IDK,这个板子的特点如下: 基于 TI AM335x ARM Cortex-A8 CPU,主频可高达 1GHz,运算能力可高达 2000DMIPS,搭配DDR3,兼容 eMMC 和 NAND FLASH,超高性价比: 2 个 PRU 协处理器,支持 EtherCAT.PROFINET.EtherNet/IP.PROFIBUS.Ethernet POWERLINK.Sercos 等工业协议: 内部集成 SGX530 3D 图形加速器和 24bit LCD 触摸屏控制

[RK_2014_0919]Linux Kernel Hacking

KernelBuild Guide to building the Linux kernel. Where do I find the kernel? The latest source code for the Linux kernel is kept on kernel.org. You can either download the full source code as a tar ball (not recommended and will take forever to downlo

am335x linux 网口配置

在  Device Drivers  -->Network device support下 配置了menuconfig  然后修改设备树 参考 https://www.cnblogs.com/chenfulin5/p/8384186.html https://www.cnblogs.com/chenfulin5/p/8144686.html 原文地址:https://www.cnblogs.com/ChenChangXiong/p/11288294.html

AM335x(TQ335x)学习笔记——USB驱动移植

对于AM335x来讲,TI维护的USB驱动已经非常完善了,本文称之为移植,实际上仅仅是配置内核选项使能USB HOST/OTG功能.废话少说,直接动手开启AM335x的USB驱动配置项. Step1. 配置内核支持USB 默认的配置项没有配置USB相关的选项,但是DTS已经配置好了,我们不需要对DTS作任何修改,详细的内核配置项如下: Device Drivers ---> [*] USB support ---> [*] OTG support <*> EHCI HCD (USB

转:AM335x启动流程(BootRom-&gt;MLO-&gt;Uboot)

http://blog.chinaunix.net/uid-28458801-id-3486399.html 参考文件: 1,AM335x ARM Cortex-A8 Microprocessors (MPUs) Technical Reference Manual.pdf: 2,am3359.pdf: 1,am335x的cpu上电后,会跳到哪个地址去执行? 答: 芯片到uboot启动流程 :ROM → MLO(SPL)→ uboot.img AM335x 中bootloader被分成了 3 个