zoukankan      html  css  js  c++  java
  • OK335xS UART device registe hacking

    /*************************************************************************
     *           OK335xS UART device registe hacking
     * 声明:
     *     1. 本文是对OK335xS Linux内核中UART设备注册代码进行跟踪;
     *     2. 本人在文中采用函数调用线路图进行标记,方便阅读;
     *     3. 代码跟踪的用的是vim+ctags;
     *
     *                              2015-6-30 晴 深圳 南山平山村 曾剑锋
     ************************************************************************/
    
                     \\\\\-*- 目录 -*-/////////
                     |  一、板级文件:          
                     |  二、跟踪am33xx_init_early:
                     |  三、跟踪am335x_evm_init:
                     \\\\\\\\//////////////
    
    
    一、板级文件:
        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                                       
                                                    
    二、跟踪am33xx_init_early:
        void __init am33xx_init_early(void)   
        {    
            omap2_set_globals_am33xx();
            omap3xxx_check_revision();
            am33xx_check_features();
            omap_common_init_early();
            am33xx_voltagedomains_init();
            omap44xx_prminst_init();
            am33xx_powerdomains_init();
            omap44xx_cminst_init();
            am33xx_clockdomains_init();
            am33xx_hwmod_init();    ---->--------+
            omap_hwmod_init_postsetup();         |
            omap3xxx_clk_init();                 |
        }                                        |
                                                 |
        int __init am33xx_hwmod_init(void)   <---+
        {
            return omap_hwmod_register(am33xx_hwmods);       -------------+
        }                                        |                        |
                                                 V                        |
        static __initdata struct omap_hwmod *am33xx_hwmods[] = {          |
            ......                                                        |
            /* uart class */                                              |
            &am33xx_uart1_hwmod,   ----+                                  |
            &am33xx_uart2_hwmod,       |                                  |
            &am33xx_uart3_hwmod,       |                                  |
            &am33xx_uart4_hwmod,       |                                  |
            &am33xx_uart5_hwmod,       |                                  |
            &am33xx_uart6_hwmod,       |                                  |
            ......                     |                                  |
        }                              |                                  |
                                       V                                  |
        static struct omap_hwmod am33xx_uart1_hwmod = {                   |
            .name       = "uart1",        // 后续注册设备时会用到name     |
            .class      = &uart_class,  ->----+                           |
            .clkdm_name = "l4_wkup_clkdm",    |                           |
            .mpu_irqs   = am33xx_uart1_irqs, -*-------+                   |
            .main_clk   = "uart1_fck",        |       |                   |
            .sdma_reqs  = uart1_edma_reqs,  --*-------*----------+        |
            ......                            |       |          |        |
        };                                    |       |          |        |
                                              V       |          |        |
        static struct omap_hwmod_class uart_class = { |          |        |
            .name       = "uart",                     |          |        |
            .sysc       = &uart_sysc,                 |          |        |
        };                                            |          |        |
                                                      |          |        |
        /* uart1 */                                   V          |        |
        static struct omap_hwmod_dma_info uart1_edma_reqs[] = {  |        |
            { .name = "tx", .dma_req = 26, },                    |        |
            { .name = "rx", .dma_req = 27, },                    |        |
            { .dma_req = -1 }                     +--------------+        |
        };                                        |                       |
                                                  V                       |
        static struct omap_hwmod_irq_info am33xx_uart1_irqs[] = {         |
            { .irq = 72 },                                                |
            { .irq = -1 }                                                 |
        };                                                                |
                                                                          |
        int __init omap_hwmod_register(struct omap_hwmod **ohs)    <------+
        {                                                                     
            int r, i;                                                        
            
            if (!ohs)
                return 0;
            
            i = 0;
            do {
                r = _register(ohs[i]);         ------------------------------------+
                WARN(r, "omap_hwmod: %s: _register returned %d
    ", ohs[i]->name,   |
                     r);                                                           |
            } while (ohs[++i]);                                                    |
                                                                                   |
            return 0;                                                              |
        }                                                                          |
                                                                                   |
        static int __init _register(struct omap_hwmod *oh)   <---------------------+
        {
            int ms_id;
        
            if (!oh || !oh->name || !oh->class || !oh->class->name ||
                (oh->_state != _HWMOD_STATE_UNKNOWN))
                return -EINVAL;
        
            pr_debug("omap_hwmod: %s: registering
    ", oh->name);
        
            if (_lookup(oh->name))
                return -EEXIST;
        
            ms_id = _find_mpu_port_index(oh);
            if (!IS_ERR_VALUE(ms_id))
                oh->_mpu_port_index = ms_id;
            else
                oh->_int_flags |= _HWMOD_NO_MPU_PORT;
        
            list_add_tail(&oh->node, &omap_hwmod_list);
        
            spin_lock_init(&oh->_lock);
        
            oh->_state = _HWMOD_STATE_REGISTERED;
        
            /*
             * XXX Rather than doing a strcmp(), this should test a flag
             * set in the hwmod data, inserted by the autogenerator code.
             */
            if (!strcmp(oh->name, MPU_INITIATOR_NAME))
                mpu_oh = oh;
        
            return 0;
        }
    
    三、跟踪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
    ");         |
                                                                                     |
            printk("zengjf test code 1.
    ");                                         |
        }                                                                            |
                                                                                     |
        void __init omap_serial_init(void)         <---------------------------------+
        {
            omap_serial_board_init(NULL);   -------+
        }                        +-----------------+
                                 V
        void __init omap_serial_board_init(struct omap_uart_port_info *info)
        {
            struct omap_uart_state *uart;
            struct omap_board_data bdata;
        
            list_for_each_entry(uart, &uart_list, node) {
                bdata.id = uart->num;       ^---------------------------------+
                bdata.flags = 0;                                              |
                bdata.pads = NULL;                                            |
                bdata.pads_cnt = 0;                                           |
                                                                              |
                if (cpu_is_omap44xx() || (cpu_is_omap34xx() &&                |
                                    !cpu_is_am33xx()))                        |
                    omap_serial_fill_default_pads(&bdata);                    |
                                                                              |
                if (!info)                                                    |
                    omap_serial_init_port(&bdata, NULL);   -------------------*---+
                else                                                          |   |
                    omap_serial_init_port(&bdata, &info[uart->num]);          |   |
            }                                                                 |   |
        }                                                                     |   |
                                                                              |   |
        static int __init omap_serial_early_init(void)                        |   |
        {                                                                     |   |
            do {                                                              |   |
                ......                                                        |   |
                snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN,                    |   |
                     "uart%d", num_uarts + 1);                                |   |
                oh = omap_hwmod_lookup(oh_name);     ----------------------+  |   |
                if (!oh)                                                   |  |   |
                    break;                                                 |  |   |
                                                                           |  |   |
                uart = kzalloc(sizeof(struct omap_uart_state), GFP_KERNEL);|  |   |
                if (WARN_ON(!uart))                                        |  |   |
                    return -ENODEV;                                        |  |   |
                                                                           |  |   |
                uart->oh = oh;                                             |  |   |
                uart->num = num_uarts++;                                   |  |   |
                list_add_tail(&uart->node, &uart_list);             <------*--+   |
                ......                                                     |  |   |
            } while (1);                                                   |  |   |
                                                                           |  |   |
            return 0;                                                      |  |   |
        }                // 这里很重要                                     |  |   |
        core_initcall(omap_serial_early_init);                      <------*--+   |
                                                                           |      |
        struct omap_hwmod *omap_hwmod_lookup(const char *name)     <------ +      |
        {                                                                         |
            struct omap_hwmod *oh;                                                |
                                                                                  |
            if (!name)                                                            |
                return NULL;                                                      |
                                                                                  |
            oh = _lookup(name); ----+                                             |
                                    |                                             |
            return oh;              |                                             |
        }                           |                                             |
                                    V                                             |
        static struct omap_hwmod *_lookup(const char *name)                       |
        {                                                                         |
            struct omap_hwmod *oh, *temp_oh;                                      |
                                                                                  |
            oh = NULL;                                                            |
                                                                                  |
            list_for_each_entry(temp_oh, &omap_hwmod_list, node) {                |
                if (!strcmp(name, temp_oh->name)) {                               |
                    oh = temp_oh;                                                 |
                    break;                                                        |
                }                                                                 |
            }                                                                     |
                                                                                  |
            return oh;                                                            |
        }                       +-------------------------------------------------+
                                V
        void __init omap_serial_init_port(struct omap_board_data *bdata,
                    struct omap_uart_port_info *info)
        {
            struct omap_uart_state *uart;
            struct omap_hwmod *oh;
            struct platform_device *pdev;
            void *pdata = NULL;
            u32 pdata_size = 0;
            char *name;
            struct omap_uart_port_info omap_up;
        
            if (WARN_ON(!bdata))
                return;
            if (WARN_ON(bdata->id < 0))
                return;
            if (WARN_ON(bdata->id >= num_uarts))
                return;
        
            list_for_each_entry(uart, &uart_list, node)
                if (bdata->id == uart->num)
                    break;
            if (!info)
                info = omap_serial_default_info;
        
            oh = uart->oh;
            name = DRIVER_NAME;
        
            omap_up.dma_enabled = info->dma_enabled;
            omap_up.uartclk = OMAP24XX_BASE_BAUD * 16;
            omap_up.flags = UPF_BOOT_AUTOCONF;
            omap_up.get_context_loss_count = omap_pm_get_dev_context_loss_count;
            omap_up.set_forceidle = omap_uart_set_forceidle;
            omap_up.set_noidle = omap_uart_set_noidle;
            omap_up.enable_wakeup = omap_uart_enable_wakeup;
            omap_up.dma_rx_buf_size = info->dma_rx_buf_size;
            omap_up.dma_rx_timeout = info->dma_rx_timeout;
            omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate;
            omap_up.autosuspend_timeout = info->autosuspend_timeout;
        
            /* Enable the MDR1 Errata i202 for OMAP2430/3xxx/44xx */
            if (!cpu_is_omap2420() && !cpu_is_ti816x())
                omap_up.errata |= UART_ERRATA_i202_MDR1_ACCESS;
        
            /* Enable DMA Mode Force Idle Errata i291 for omap34xx/3630 */
            if ((cpu_is_omap34xx() || cpu_is_omap3630()) && !cpu_is_am33xx())
                omap_up.errata |= UART_ERRATA_i291_DMA_FORCEIDLE;
        
            pdata = &omap_up;
            pdata_size = sizeof(struct omap_uart_port_info);
        
            if (WARN_ON(!oh))
                return;
        
            pdev = omap_device_build(name, uart->num, oh, pdata, pdata_size,  ------+
                         NULL, 0, false);                                           |
            WARN(IS_ERR(pdev), "Could not build omap_device for %s: %s.
    ",         |
                 name, oh->name);                                                   |
                                                                                    |
            if ((console_uart_id == bdata->id) && no_console_suspend)               |
                omap_device_disable_idle_on_suspend(pdev);                          |
                                                                                    |
            oh->mux = omap_hwmod_mux_init(bdata->pads, bdata->pads_cnt);            |
                                                                                    |
            uart->pdev = pdev;                                                      |
                                                                                    |
            oh->dev_attr = uart;                                                    |
                                                                                    |
            if (((cpu_is_omap34xx() || cpu_is_omap44xx()) && bdata->pads)           |
                    && !uart_debug)                                                 |
                device_init_wakeup(&pdev->dev, true);                               |
        }                                +------------------------------------------+
                                         V
        struct platform_device *omap_device_build(const char *pdev_name, int pdev_id,
                              struct omap_hwmod *oh, void *pdata,
                              int pdata_len,
                              struct omap_device_pm_latency *pm_lats,
                              int pm_lats_cnt, int is_early_device)
        {  
            struct omap_hwmod *ohs[] = { oh };
        
            if (!oh)
                return ERR_PTR(-EINVAL);
        
            return omap_device_build_ss(pdev_name, pdev_id, ohs, 1, pdata,    -----+
                            pdata_len, pm_lats, pm_lats_cnt,                       |
                            is_early_device);                                      |
        }                                 +----------------------------------------+
                                          |
                                          V
        struct platform_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
                             struct omap_hwmod **ohs, int oh_cnt,
                             void *pdata, int pdata_len,
                             struct omap_device_pm_latency *pm_lats,
                             int pm_lats_cnt, int is_early_device)
        {
            int ret = -ENOMEM;
            struct platform_device *pdev;
            struct omap_device *od;
        
            if (!ohs || oh_cnt == 0 || !pdev_name)
                return ERR_PTR(-EINVAL);
        
            if (!pdata && pdata_len > 0)
                return ERR_PTR(-EINVAL);
        
            pdev = platform_device_alloc(pdev_name, pdev_id);
            if (!pdev) {
                ret = -ENOMEM;
                goto odbs_exit;
            }
        
            /* Set the dev_name early to allow dev_xxx in omap_device_alloc */
            if (pdev->id != -1)
                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
            else
                dev_set_name(&pdev->dev, "%s", pdev->name);
        
            od = omap_device_alloc(pdev, ohs, oh_cnt, pm_lats, pm_lats_cnt);
            if (!od)
                goto odbs_exit1;
        
            ret = platform_device_add_data(pdev, pdata, pdata_len);
            if (ret)
                goto odbs_exit2;
        
            if (is_early_device)
                ret = omap_early_device_register(pdev);    -----------------------+
            else                                                                  |
                ret = omap_device_register(pdev);          --------------------+  |
            if (ret)                                                           |  |
                goto odbs_exit2;                                               |  |
                                                                               |  |
            return pdev;                                                       |  |
                                                                               |  |
        odbs_exit2:                                                            |  |
            omap_device_delete(od);                                            |  |
        odbs_exit1:                                                            |  |
            platform_device_put(pdev);                                         |  |
        odbs_exit:                                                             |  |
                                                                               |  |
            pr_err("omap_device: %s: build failed (%d)
    ", pdev_name, ret);    |  |
                                                                               |  |
            return ERR_PTR(ret);                                               |  |
        }                                                                      |  |
                                                                               |  |
                                                                               |  |
        static int omap_early_device_register(struct platform_device *pdev) <--+  |
        {                                                                         |
            struct platform_device *devices[1];                                   |
                                                                                  |
            devices[0] = pdev;                                                    |
            early_platform_add_devices(devices, 1);                               |
            return 0;                                                             |
        }                                                                         |
                                                                                  |
        int omap_device_register(struct platform_device *pdev)      <-------------+
        {                                                                         
            pr_debug("omap_device: %s: registering
    ", pdev->name); 
        
            pdev->dev.parent = &omap_device_parent;
            pdev->dev.pm_domain = &omap_device_pm_domain;
            return platform_device_add(pdev);
        }
        
  • 相关阅读:
    hdu 4622 Reincarnation 字符串hash 模板题
    NYOJ 994 海盗分金 逆向递推
    hdu 4679 Terrorist’s destroy 树形DP
    Educational Codeforces Round 12 E. Beautiful Subarrays 预处理+二叉树优化
    hdu 5535 Cake 构造+记忆化搜索
    poj 3415 Common Substrings 后缀数组+单调栈
    poj 3518 Corporate Identity 后缀数组->多字符串最长相同连续子串
    poj 2774 Long Long Message 后缀数组LCP理解
    hdu 3518 Boring counting 后缀数组LCP
    poj 3641 Pseudoprime numbers Miller_Rabin测素裸题
  • 原文地址:https://www.cnblogs.com/zengjfgit/p/4612256.html
Copyright © 2011-2022 走看看