今天上午和老范折腾了一上午的9260上面的串口驱动,搞笑死了!!
问题:
1、为什么启动(dmesg)信息显示ttyS0请求的寄存器资源和datasheet中的介绍不一致?
2、如何将9260的6个串口全部驱动起来?
第一个问题:折腾死我们两了,严重的鄙视内核的作者,让我重新上了一次小学,重温一遍带入消元算法!问题的由来在于:
启动信息:
<6>io scheduler anticipatory registered (default)
<6>atmel_usart.0: ttyS0 at MMIO 0xfefff200 (irq = 1) is a ATMEL_SERIAL
<6>atmel_usart.1: ttyS1 at MMIO 0xfffb0000 (irq = 6) is a ATMEL_SERIAL
<6>atmel_usart.2: ttyS2 at MMIO 0xfffb4000 (irq = 7) is a ATMEL_SERIAL
我们可以看到ttyS0注册请求的地址是fefff200,我找遍了整个datasheet,都没有发现这个寄存器地址,怎么回事?但是这个串口确实工作起来了,因为我的console使用的就是ttyS0。ttyS0使用的dbgu的寄存器请求地址就是0xfffff200。而不是请求的时候使用的0xfefff200?
我们看串口ttyS0的定义:
为什么ttyS0指向的是dbgu,大家可以去看看
arch/arm/mach-at91/at91sam9260_devices.c文件中at91_init_serial函数。
static struct resource dbgu_resources[] = {
[0] = {
.start = AT91_VA_BASE_SYS + AT91_DBGU,
.end = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AT91_ID_SYS,
.end = AT91_ID_SYS,
.flags = IORESOURCE_IRQ,
},
};
static struct atmel_uart_data dbgu_data = {
.use_dma_tx = 0,
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
.regs = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
};
static struct platform_device at91sam9260_dbgu_device = {
.name = "atmel_usart",
.id = 0,
.dev = {
.platform_data = &dbgu_data,
.coherent_dma_mask = 0xffffffff,
},
.resource = dbgu_resources,
.num_resources = ARRAY_SIZE(dbgu_resources),
};
static inline void configure_dbgu_pins(void)
{
at91_set_A_periph(AT91_PIN_PB14, 0); /* DRXD */
at91_set_A_periph(AT91_PIN_PB15, 1); /* DTXD */
}
我们看dbgu_resource结构体的start成员,使用的就是
.start = AT91_VA_BASE_SYS + AT91_DBGU,
这个应该就是我们在内核启动的时候看到的请求地址oxfefff200,真的吗,我花了两页纸和时间验证了一下,使用小学时使用的带入消元法,居然只需要用到小学的知识,大受打击阿。
然后我们就要问:别的串口请求的是实际地址,他请求虚拟地址能行吗?告诉你,能行,注意到dbgu_data结构体比别的uart_data结构体多出了一个.reg成员,这个成员表示
.regs = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
这是一个虚拟地址。
我们看atmel串口的驱动初始化函数:atmel_serial.c文件中调用的atmel_init_port函数,
static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct platform_device *pdev)
{
struct uart_port *port = &atmel_port->uart;
struct atmel_uart_data *data = pdev->dev.platform_data;
port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF;
port->ops = &atmel_pops;
port->fifosize = 1;
port->line = pdev->id;
port->dev = &pdev->dev;
port->mapbase = pdev->resource[0].start;
port->irq = pdev->resource[1].start;
/*这就说明了,如果regs成员已经被定义过了,则不再进行映射,没有映射的,在request_port时依赖于UPF_IOREMAP标志进行映射!
为什么dbgu单独先做了??难道是用作console的原因?还是所有的system constroller mapping的部分都先进行映射?不得而知*/
if (data->regs)
/* Already mapped by setup code */
port->membase = data->regs;
else {
port->flags |= UPF_IOREMAP;
port->membase = NULL;
}
第一个问题的答案:
启动信息打印出来的地址信息是虚拟地址,而不是实际的地址!,这就可以解释了
问题2:如何驱动7个串口,默认只出来3个串口。
修改arch/arm/mach-at91/board-sam9260ek.c文件
static struct at91_uart_config __initdata ek_uart_config = {
.console_tty = 0, /* ttyS0 */
.nr_tty = 7,
.tty_map = { 6, 0, 1, 2, 3, 4, 5 } /* ttyS0, ..., ttyS6 */
};
将.nr_tty改为7,而tty_map也要相应的按顺序修改,将定义为-1的成员按顺序定义!
两个问题解决!
启动信息如下:
<6>atmel_usart.0: ttyS0 at MMIO 0xfefff200 (irq = 1) is a ATMEL_SERIAL
<6>atmel_usart.1: ttyS1 at MMIO 0xfffb0000 (irq = 6) is a ATMEL_SERIAL
<6>atmel_usart.2: ttyS2 at MMIO 0xfffb4000 (irq = 7) is a ATMEL_SERIAL
<6>atmel_usart.3: ttyS3 at MMIO 0xfffb8000 (irq = 8) is a ATMEL_SERIAL
<6>atmel_usart.4: ttyS4 at MMIO 0xfffd0000 (irq = 23) is a ATMEL_SERIAL
<6>atmel_usart.5: ttyS5 at MMIO 0xfffd4000 (irq = 24) is a ATMEL_SERIAL
<6>atmel_usart.6: ttyS6 at MMIO 0xfffd8000 (irq = 25) is a ATMEL_SERIAL
阅读(666) | 评论(0) | 转发(0) |