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\n", 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\n", 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\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");         |
                                                                                 |
        printk("zengjf test code 1.\n");                                         |
    }                                                                            |
                                                                                 |
    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.\n",         |
             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)\n", 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\n", pdev->name); 
    
        pdev->dev.parent = &omap_device_parent;
        pdev->dev.pm_domain = &omap_device_pm_domain;
        return platform_device_add(pdev);
    }
    

 

posted on 2015-07-01 08:14  zengjf  阅读(521)  评论(0编辑  收藏  举报

导航