am335x uart分析

/************************************************************
 *                  am335x uart分析
 *  本文记录am335x uart驱动的注册过程。
 *  参考:
 *          http://www.cnblogs.com/helloworldtoyou/p/5385595.html
 *  涉及文件:
 *          arch/arm/mach-omap2/board-am335xevm.c
 *          drivers/tty/serial/omap-serial.c
 *
 *                             Tony Liu, 2016-5-2, Shenzhen
 ***********************************************************/

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                                  |
                                             |
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);

    daughter_brd_detected = false;
    setup_xxx_xxxx();  --+
    ......               |
}                        |
                         |
                         V
static void setup_xxx_xxxx(void)
{
    /*which doesn‘t have Write Protect pin LAN8710A_PHY_ID */
    am335x_mmc[0].gpio_wp = -EINVAL;

    int ret;

    //配置引脚复用
    _configure_device(EVM_SK, xxx_xxxx_dev_cfg, PROFILE_NONE);         -----+
             |                                                              |
}            |                                                              |
             V                                                              |
static void _configure_device(int evm_id, struct evm_dev_cfg *dev_cfg,      |
    int profile)                                                            |
{                                                                           |
    int i;                                                                  |
                                                                            |
    am335x_evm_set_id(evm_id);                                              |
                                                                            |
    if (profile == PROFILE_NONE) {                                          |
        for (i = 0; dev_cfg->device_init != NULL; dev_cfg++) {              |
            if (dev_cfg->device_on == DEV_ON_BASEBOARD)                     |
                dev_cfg->device_init(evm_id, profile);                      |
            else if (daughter_brd_detected == true)                         |
                dev_cfg->device_init(evm_id, profile);                      |
        }                                                                   |
    } else {                                                                |
        for (i = 0; dev_cfg->device_init != NULL; dev_cfg++) {              |
            if (dev_cfg->profile & profile) {                               |
                if (dev_cfg->device_on == DEV_ON_BASEBOARD)                 |
                    dev_cfg->device_init(evm_id, profile);                  |
                else if (daughter_brd_detected == true)                     |
                    dev_cfg->device_init(evm_id, profile);                  |
            }                                                               |
        }                                                                   |
    }                                                                       |
}                                                                           |
                                                                            |
static struct evm_dev_cfg xxx_xxxx_dev_cfg[] = {                   <--------+
    ......
    {uart0_init, DEV_ON_BASEBOARD, PROFILE_ALL},//fixed     ---+
    {uart1_init, DEV_ON_BASEBOARD, PROFILE_ALL},//fixed        |
    {uart4_init, DEV_ON_BASEBOARD, PROFILE_ALL},//fixed        |
    ......                                                     |
    {NULL, 0, 0},                                              |
};                                                             |
                                                               |
static void uart0_init(int evm_id, int profile)            <---+
{
    setup_pin_mux(uart0_pin_mux);                                  ------+
    return;    |                                                         |
}              |                                                         |
               V                                                         |
static void setup_pin_mux(struct pinmux_config *pin_mux)                 |
{                                                                        |
    int i;                                                               |
                                                                         |
    for (i = 0; pin_mux->string_name != NULL; pin_mux++)                 |
        omap_mux_init_signal(pin_mux->string_name, pin_mux->val);        |
}                                                                        |
                                                                         |
static struct pinmux_config uart0_pin_mux[] = {                    <-----+
    {"uart0_rxd.uart0_rxd", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
    {"uart0_txd.uart0_txd", OMAP_MUX_MODE0 | AM33XX_PULL_ENBL},
    {"uart0_ctsn.uart0_ctsn", OMAP_MUX_MODE0 | AM33XX_PULL_ENBL},
    {NULL, 0},
};

drivers/tty/serial/omap-serial.c
static int __init serial_omap_init(void)
{
    int ret;

    ret = uart_register_driver(&serial_omap_reg);              -------+
    if (ret != 0)                                                     |
        return ret;                                                   |
    ret = platform_driver_register(&serial_omap_driver);  --+         |
    if (ret != 0)                                           |         |
        uart_unregister_driver(&serial_omap_reg);           |         |
    return ret;                                             |         |
}                                                           |         |
                                                            |         |
static struct uart_driver serial_omap_reg = {               |         |
    .owner        = THIS_MODULE,                            |         |
    .driver_name    = "OMAP-SERIAL",                        |         |
    .dev_name    = OMAP_SERIAL_NAME,                        |         |
    .nr        = OMAP_MAX_HSUART_PORTS,                     |         |
    .cons        = OMAP_CONSOLE,                            |         |
};                                                          |         |
                                                            |         |
#define OMAP_SERIAL_NAME    "ttyO"                          |         |
#define OMAP_MAX_HSUART_PORTS    6                          |         |
                                                            |         |
#define OMAP_CONSOLE    (&serial_omap_console)              |         |
                                                            |         |
static struct console serial_omap_console = {               |  <------+
    .name        = OMAP_SERIAL_NAME,                        |
    .write        = serial_omap_console_write,              |
    .device        = uart_console_device,                   |
    .setup        = serial_omap_console_setup,              |
    .flags        = CON_PRINTBUFFER,                        |
    .index        = -1,                                     |
    .data        = &serial_omap_reg,                        |
};                                                          |
                                                            |
static struct platform_driver serial_omap_driver = {     <--+
    .probe          = serial_omap_probe,
    .remove         = serial_omap_remove,
    .driver        = {
        .name    = DRIVER_NAME,
        .pm    = &serial_omap_dev_pm_ops,
        .of_match_table = of_match_ptr(omap_serial_of_match),
    },
};

static int serial_omap_probe(struct platform_device *pdev)
{
    struct uart_omap_port    *up;
    struct resource        *mem, *irq, *dma_tx, *dma_rx;
    struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
    int ret = -ENOSPC;

    if (pdev->dev.of_node)
        omap_up_info = of_get_uart_port_info(&pdev->dev);

    ......
    up->pdev = pdev;
    up->port.dev = &pdev->dev;
    up->port.type = PORT_OMAP;
    up->port.iotype = UPIO_MEM;
    up->port.irq = irq->start;

    up->port.regshift = 2;
    up->port.fifosize = 64;
    up->port.ops = &serial_omap_pops;                                --------+
                                                                             |
    if (pdev->dev.of_node)                                                   |
        up->port.line = of_alias_get_id(pdev->dev.of_node, "serial");        |
    else                                                                     |
        up->port.line = pdev->id;                                            |
                                                                             |
    if (up->port.line < 0) {                                                 |
        dev_err(&pdev->dev, "failed to get alias/pdev id, errno %d\n",       |
                                up->port.line);                              |
        ret = -ENODEV;                                                       |
        goto err;                                                            |
    }                                                                        |
                                                                             |
    sprintf(up->name, "OMAP UART%d", up->port.line);                         |
    up->port.mapbase = mem->start;                                           |
    up->port.membase = ioremap(mem->start, resource_size(mem));              |
    if (!up->port.membase) {                                                 |
        dev_err(&pdev->dev, "can‘t ioremap UART\n");                         |
        ret = -ENOMEM;                                                       |
        goto err;                                                            |
    }                                                                        |
                                                                             |
    up->port.flags = omap_up_info->flags;                                    |
    up->port.uartclk = omap_up_info->uartclk;                                |
    if (!up->port.uartclk) {                                                 |
        up->port.uartclk = DEFAULT_CLK_SPEED;                                |
        dev_warn(&pdev->dev, "No clock speed specified: using default:"      |
                        "%d\n", DEFAULT_CLK_SPEED);                          |
    }                                                                        |
    up->uart_dma.uart_base = mem->start;                                     |
    up->errata = omap_up_info->errata;                                       |
                                                                             |
    if (omap_up_info->dma_enabled) {                                         |
        up->uart_dma.uart_dma_tx = dma_tx->start;                            |
        up->uart_dma.uart_dma_rx = dma_rx->start;                            |
        up->use_dma = 1;                                                     |
        up->uart_dma.rx_buf_size = omap_up_info->dma_rx_buf_size;            |
        up->uart_dma.rx_timeout = omap_up_info->dma_rx_timeout;              |
        up->uart_dma.rx_poll_rate = omap_up_info->dma_rx_poll_rate;          |
        spin_lock_init(&(up->uart_dma.tx_lock));                             |
        spin_lock_init(&(up->uart_dma.rx_lock));                             |
        up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;                 |
        up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;                 |
    }                                                                        |
                                                                             |
    up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;                          |
    up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;                     |
    pm_qos_add_request(&up->pm_qos_request,                                  |
        PM_QOS_CPU_DMA_LATENCY, up->latency);                                |
    serial_omap_uart_wq = create_singlethread_workqueue(up->name);           |
    INIT_WORK(&up->qos_work, serial_omap_uart_qos_work);                     |
                                                                             |
    pm_runtime_use_autosuspend(&pdev->dev);                                  |
    pm_runtime_set_autosuspend_delay(&pdev->dev,                             |
            omap_up_info->autosuspend_timeout);                              |
                                                                             |
    pm_runtime_irq_safe(&pdev->dev);                                         |
    pm_runtime_enable(&pdev->dev);                                           |
    pm_runtime_get_sync(&pdev->dev);                                         |
                                                                             |
    ui[up->port.line] = up;                                                  |
    serial_omap_add_console_port(up);                                        |
                                                                             |
    ret = uart_add_one_port(&serial_omap_reg, &up->port);   --------------+  |
    if (ret != 0)                                                         |  |
        goto do_release_region;                                           |  |
                                                                          |  |
    pm_runtime_put(&pdev->dev);                                           |  |
    platform_set_drvdata(pdev, up);                                       |  |
    return 0;                                                             |  |
err:                                                                      |  |
    dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",                   |  |
                pdev->id, __func__, ret);                                 |  |
do_release_region:                                                        |  |
    release_mem_region(mem->start, resource_size(mem));                   |  |
    return ret;                                                           |  |
}                                                                         |  |
                                                                          |  |
static struct uart_ops serial_omap_pops = {                      <--------|--+
    .tx_empty    = serial_omap_tx_empty,                                  |
    .set_mctrl    = serial_omap_set_mctrl,                                |
    .get_mctrl    = serial_omap_get_mctrl,                                |
    .stop_tx    = serial_omap_stop_tx,                                    |
    .start_tx    = serial_omap_start_tx,                                  |
    .stop_rx    = serial_omap_stop_rx,                                    |
    .enable_ms    = serial_omap_enable_ms,                                |
    .break_ctl    = serial_omap_break_ctl,                                |
    .startup    = serial_omap_startup,                                    |
    .shutdown    = serial_omap_shutdown,                                  |
    .set_termios    = serial_omap_set_termios,                            |
    .pm        = serial_omap_pm,                                          |
    .type        = serial_omap_type,                                      |
    .release_port    = serial_omap_release_port,                          |
    .request_port    = serial_omap_request_port,                          |
    .config_port    = serial_omap_config_port,                            |
    .verify_port    = serial_omap_verify_port,                            |
#ifdef CONFIG_CONSOLE_POLL                                                |
    .poll_put_char  = serial_omap_poll_put_char,                          |
    .poll_get_char  = serial_omap_poll_get_char,                          |
#endif                                                                    |
};                                                                        |
                                                                          |
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) <-+
{
    struct uart_state *state;
    struct tty_port *port;
    int ret = 0;
    struct device *tty_dev;

    BUG_ON(in_interrupt());

    if (uport->line >= drv->nr)
        return -EINVAL;

    state = drv->state + uport->line;
    port = &state->port;

    mutex_lock(&port_mutex);
    mutex_lock(&port->mutex);
    if (state->uart_port) {
        ret = -EINVAL;
        goto out;
    }

    state->uart_port = uport;
    state->pm_state = -1;

    uport->cons = drv->cons;
    uport->state = state;

    /*
     * If this port is a console, then the spinlock is already
     * initialised.
     */
    if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
        spin_lock_init(&uport->lock);
        lockdep_set_class(&uport->lock, &port_lock_key);
    }

    uart_configure_port(drv, state, uport);

    /*
     * Register the port whether it‘s detected or not.  This allows
     * setserial to be used to alter this ports parameters.
     */
    tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);     -----+
    if (likely(!IS_ERR(tty_dev))) {                                                   |
        device_init_wakeup(tty_dev, 1);                                               |
        device_set_wakeup_enable(tty_dev, 0);                                         |
    } else                                                                            |
        printk(KERN_ERR "Cannot register tty device on line %d\n",                    |
               uport->line);                                                          |
                                                                                      |
    /*                                                                                |
     * Ensure UPF_DEAD is not set.                                                    |
     */                                                                               |
    uport->flags &= ~UPF_DEAD;                                                        |
                                                                                      |
 out:                                                                                 |
    mutex_unlock(&port->mutex);                                                       |
    mutex_unlock(&port_mutex);                                                        |
                                                                                      |
    return ret;                                                                       |
}                                                                                     |
                                                                                      |
struct device *tty_register_device(struct tty_driver *driver, unsigned index,     <---+
                   struct device *device)
{
    char name[64];
    dev_t dev = MKDEV(driver->major, driver->minor_start) + index;

    if (index >= driver->num) {
        printk(KERN_ERR "Attempt to register invalid tty line number "
               " (%d).\n", index);
        return ERR_PTR(-EINVAL);
    }

    if (driver->type == TTY_DRIVER_TYPE_PTY)
        pty_line_name(driver, index, name);
    else
        tty_line_name(driver, index, name);                                ---+
                                                                              |
    return device_create(tty_class, device, dev, NULL, name);                 |
}                                                                             |
// 设备名                                                                     |
static void tty_line_name(struct tty_driver *driver, int index, char *p)   <--+
{
    sprintf(p, "%s%d", driver->name, index + driver->name_base);
}
时间: 2024-10-11 08:55:01

am335x uart分析的相关文章

am335x i2c分析

/***************************************************************************** * am335x i2c分析 * i2c驱动主要关注i2c_algorithm结构体,不同芯片实现自己的master_xfer函数. * 不同芯片i2c驱动框架都类似. * 本文主要描述am335x_i2c设备和驱动的注册,提及文件: * arch/arm/mach-omap2/board-am335xevm.c * drivers/i2c

AM335x裸机&lt;二&gt;:StartWare的分析

这篇接着上一篇,来分析上一篇程序里面的MLO和app文件启动过程,基本涵盖到整个am335x的大部分操作,包括:时钟初始化.代码搬移.中断向量的重定位.中断的处理等.要分析程序,首先分析makefile和连接脚本lds文件,然后顺藤摸瓜,当同名函数太多时,可以考虑反汇编elf文件,进行对比判断. 0.添加Source Insight工程 创建新工程,添加所有文件,注意Source Insight添加对asm和makefile文件支持,更有利于分析 1.bootloader分析 查看build/a

am335x的启动分析

参考文件:Sitara AM335x Bootload的流程分析 am335x上电后从Rom code开始运行,Rom code 地址0x4000_0000.Rom code 是固化在芯片的一个引导程序,具体参见<AM335x and AMIC110 Sitara. Processors Technical Reference Manual>第26章. Rom code运行后,根据sysboot引进配置,去遍历启动列表,寻找启动Image.启动列表主要分为存储器件和外设.从存储器件启动,启动I

am335x uboot启动流程分析

基本指令含义 .globl _start .globl指示告诉汇编器,_start这个符号要被链接器用到,所以要在目标文件的符号表中标记它是一个全局符号 b,bl b是不带返回的跳转  bl带返回的跳转 .word 插入一个32-bit的数据队列.(与armasm中的DCD功能相同) 芯片到uboot启动流程 :ROM → MLO(SPL)→ uboot.img 启动脚本:/u-boot2011.09/arch/arm/cpu/armv7/omap-common/u-boot_spl.lds M

tty初探—uart驱动框架分析(二)uart_add_one_port

在前面的一篇文章中,我们分析了一个 uart_driver 的向上注册过程,主要是 tty 的一些东西,知道了 tty 注册了一个字符设备驱动,我们在用户空间 open 时将调用到 uart_port.ops.startup ,在用户空间 write 则调用 uart_port.ops.start_tx ,还知道了如何 read 数据等等.但是,这些都是内核帮我们实现好的,在真正的驱动开发过程中几乎不涉及那些代码的修改移植工作,真正需要我们触碰的是 uart_port 这个结构体,它真正的对应于

UART驱动分析

在linux用户层上要操作底层串口需要对/dev/ttySxxx操作,这里的ttySx指实际的终端串口. 以下以全志A64为实例,分析UART驱动以及浅谈TTY架构. linux-3.10/drivers/tty/serial/sunxi-uart.c: 1 static const struct of_device_id sunxi_uart_match[] = { 2 { .compatible = "allwinner,sun8i-uart", }, 3 { .compatibl

[tty与uart]2.tty驱动分析

转自:http://www.wowotech.net/linux_kenrel/183.html 目录: 1 首先分析设备驱动的注册 1.1 uart_register_driver分析 1.2 tty_register_driver分析 1.3 serial8250_register_ports()函数分析 1.4 serial8250_probe()函数分析 2 然后,我们来看设备的打开过程 3 TTY设备的读 3.1 read_chan() 4 TTY设备的写 5 总结 1 首先分析设备驱

tty初探—uart驱动框架分析

本文参考了大量牛人的博客,对大神的分享表示由衷的感谢. 主要参考: tty驱动分析 :http://www.wowotech.net/linux_kenrel/183.html Linux TTY驱动--Uart_driver底层:http://blog.csdn.net/sharecode/article/details/9196591 Linux TTY驱动--Serial Core层  :http://blog.csdn.net/sharecode/article/details/9197

AM335X有关MMC的启动参数问题分析

AM335X有关MMC的启动参数问题分析 一. 问题来源 硬件平台:AM335X芯片 SDK版本:ti-processor-sdk-linux-am335x-evm-03.00.00.04-Linux-x86-Install 使用创龙相关文档进行参考. 发现问题的过程:使用SD(MMC0)卡启动UBOOT,内核,文件系统,正常启动之后,使用固化程序脚本将UBOOT.内核.文件系统固化到EMMC(MMC1)中.再将BOOT引脚设计为从EMMC(MMC1)启动. 关机后拔下SD卡,启动起来之后.文件