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 = , }, | |
{ .name = "rx", .dma_req = , }, | |
{ .dma_req = - } +--------------+ |
}; | |
V |
static struct omap_hwmod_irq_info am33xx_uart1_irqs[] = { |
{ .irq = }, |
{ .irq = - } |
}; |
|
int __init omap_hwmod_register(struct omap_hwmod **ohs) <------+
{
int r, i; if (!ohs)
return ; i = ;
do {
r = _register(ohs[i]); ------------------------------------+
WARN(r, "omap_hwmod: %s: _register returned %d\n", ohs[i]->name, |
r); |
} while (ohs[++i]); |
|
return ; |
} |
|
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 ;
} 三、跟踪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 = ; |
bdata.pads = NULL; |
bdata.pads_cnt = ; |
|
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 + ); | |
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 (); | | |
| | |
return ; | | |
} // 这里很重要 | | |
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 = ;
char *name;
struct omap_uart_port_info omap_up; if (WARN_ON(!bdata))
return;
if (WARN_ON(bdata->id < ))
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 * ;
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, , 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, , 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 == || !pdev_name)
return ERR_PTR(-EINVAL); if (!pdata && pdata_len > )
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 != -)
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[]; |
|
devices[] = pdev; |
early_platform_add_devices(devices, ); |
return ; |
} |
|
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);
}
OK335xS UART device registe hacking的更多相关文章
- OK335xS I2C device registe hacking
/*************************************************************************** * OK335xS I2C device re ...
- OK335xS pwm device register hacking
/************************************************************************* * OK335xS pwm device regi ...
- OK335xS CAN device register and deiver match hacking
/************************************************************************* * OK335xS CAN device regi ...
- OK335xS GPMC nand device register hacking
/********************************************************************************* * OK335xS GPMC na ...
- I.MX6 AD7606-4 device driver registe hacking
/********************************************************************** * I.MX6 AD7606-4 device driv ...
- OK335xS LAN8710 phy driver hacking
/******************************************************************** * OK335xS LAN8710 phy driver h ...
- OK335xS davinci mdio driver hacking
/******************************************************************************* * OK335xS davinci m ...
- OK335xS psplash make-image-header.sh hacking
/***************************************************************************** * OK335xS psplash mak ...
- OK335xS U-boot GPIO control hacking
/**************************************************************************************** * OK335xS ...
随机推荐
- java入门书籍很少介绍的java知识
1.java中数组的长度可以用.length来确定 2.java中的Arrays类可以对数组进行轻松的操作 (1).包名:import java.util.Arrays (2).Arrays.sort ...
- Object.defineProperty方法 使用
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象. 语法: Object.defineProperty(obj, pr ...
- Python 错误与异常
2017-08-01 13:40:17 在程序运行过程中,总会遇到各种各样的错误. 有的错误是程序编写有问题造成的,比如本来应该输出整数结果输出了字符串,这种错误我们通常称之为bug,bug是必须修复 ...
- LeetCode--021--合并两个有序链表
问题描述: 将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两个链表的所有节点组成的. 示例: 输入:1->2->4, 1->3->4 输出:1->1- ...
- 3-5 回顾,快速二分法的疑点解惑:为啥先右j移动?因为设定a[left]为基准点
快速二分法的疑点解惑:为啥先右j移动?因为设定a[left]为基准数 , 1] [91, 86, 42, 46, 9, 68, 77, 46, 7, 1] [91, 86, 42, 46, 9, 68 ...
- android------2018 年初值得关注的 16 个新 Android 库和项目
1. transitioner Transitioner 是一个为两个拥有嵌入子视图的视图之间提供简便.动态且可调整的动画效果的库.它纯 100% 使用 Kotlin 编写而成,使用 MIT 许可,且 ...
- Confluence 6 使用 LDAP 授权连接到 Confluence 内部目录
希望连接一个内部目录但是使用 LDAP 检查登录授权: 在屏幕的右上角单击 控制台按钮 ,然后选择 General Configuration 链接. 单击左侧面板上面的 用户目录(User Dire ...
- UVA-818 Cutting Chains (位压缩+暴力搜索)
题目大意:一种环能打开和闭合.现在有n(1<=n<=15)个编号为1~n的环错综复杂的连接着,要打开一些环重新连接使这n个环能构成一条链,问最少需要打开几次环可达到目的? 题目分析:用二进 ...
- Oracle性能诊断艺术-读书笔记
create table test0605 as select * from dba_objects; select t1.owner,t1.object_name,t1.object_id from ...
- SQL优化(SQL TUNING)可大幅提升性能的实战技巧之一——让计划沿着索引跑
我们进行SQL优化时,经常会碰到对大量数据集进行排序,然后从排序后的集合取前部分结果的需求,这种情况下,当我们按照常规思路去写SQL时,系统会先读取过滤获得所有集合,然后进行排序,再从排序结果取出极少 ...