2012年9月

imx535串口驱动分析一

Tags: imx535

之前一直觉得驱动很难学,也很难写。这两天一直在看驱动,又觉得驱动有时候比app更好写一些,硬件资源有限时,功能也比较单一,做好突发时的数据处理就可以了,复杂的功能都是由app来完成。从功能上看,app的功能最多,可能要同时对多个设备操作,然后对数据处理后,才能完成一个功能。很多人说培养一个软件工程师需要五年,而培养一个硬件工程师需要十年。硬件工程师的难度大,是因为要把人类的思维抽象成机械流程,尽可能的把所有的事情有限的步骤内完成。而现的软件工程师来看,他所完成的就是人类所思考的,并不需要多少转化。

linux中的驱动,已经把module的思想做的很好了,不用重新写很多东西,代码复用度很高。裸机程序的目的就是驱动硬件,并完成相应app的功能,所以linux驱动的目的也是如此。正是基于这个原因,驱动中有各种理论和skills,但终究是要配置硬件管脚,启动,数据收发等的操作。裸机中的配置寄存器代码和数据处理代码在一起,而驱动是分开来写,所以有device得driver两个结构体,分别存放各自的属性信息。

imx535的串口属于platform_device,所以要注册成platform。同时,硬件资源是放在resource结构中,所以要填充这个结构体。对于物理串口的描述,用uart_port结构来描述。uart_port只描述了基本的信息,所以用uart_mxc_port来包含它,并加入DMA,IRQ,CLK等信息。


 67 typedef struct {
 68     /*!
 69      * The port structure holds all the information about the UART
 70      * port like base address, and so on.
 71      */
 72     struct uart_port port;
 73     /*!
 74      * Flag to determine if the interrupts are muxed.
 75      */
 76     int ints_muxed;
 77     /*!
 78      * Array that holds the receive and master interrupt numbers
 79      * when the interrupts are not muxed.
 80      */
 81     int irqs[2];
 82     /*!
 83      * Flag to determine the DTE/DCE mode.
 84      */
 85     int mode;
 86     /*!
 87      * Flag to hold the IR mode of the port.
 88      */
 89     int ir_mode;
 90     /*!
 91      * Flag to enable/disable the UART port.
 92      */
 93     int enabled;

 94     /*!
 95      * Flag to indicate if we wish to use hardware-driven hardware
 96      * flow control.
 97      */
 98     int hardware_flow;
 99     /*!
100      * Holds the threshold value at which the CTS line is deasserted in
101      * case we use hardware-driven hardware flow control.
102      */
103     unsigned int cts_threshold;
104     /*!
105      * Flag to enable/disable DMA data transfer.
106      */
107     int dma_enabled;
108     /*!
109      * Holds the DMA receive buffer size.
110      */
111     int dma_rxbuf_size;
112     /*!
113      * DMA Receive buffers information
114      */
115     mxc_uart_rxdmamap *rx_dmamap;
116     /*!
117      * DMA RX buffer id
118      */
119     int dma_rxbuf_id;
120     /*!
121      * DMA Transmit buffer virtual address
122      */
123     char *tx_buf;
124     /*!
125      * DMA Transmit buffer physical address
126      */
127     dma_addr_t tx_handle;

128     /*!
129      * Holds the RxFIFO threshold value.
130      */
131     unsigned int rx_threshold;
132     /*!
133      * Holds the TxFIFO threshold value.
134      */
135     unsigned int tx_threshold;
136     /*!
137      * Information whether this is a shared UART
138      */
139     unsigned int shared;
140     /*!
141      * Clock id for UART clock
142      */
143     struct clk *clk;
144     /*!
145      * Information whether RXDMUXSEL must be set or not for IR port
146      */
147     int rxd_mux;
148     int ir_tx_inv;
149     int ir_rx_inv;
150     /*!
151      * DMA ID for transmit
152      */
153     mxc_dma_device_t dma_tx_id;
154     /*!
155      * DMA ID for receive
156      */
157     mxc_dma_device_t dma_rx_id;
158 } uart_mxc_port;

这样,每个物理串口都填充uart_mxc_port结构,描述串口的模式,IO端口映射方式,复用功能,DMA通道等。


 36 static uart_mxc_port mxc_ports[] = {
 37     [0] = {
 38            .port = {
 39             .iotype = SERIAL_IO_MEM,
 40             .fifosize = 32,
 41             .flags = ASYNC_BOOT_AUTOCONF,
 42             .line = 0,
 43             },
 44            .ints_muxed = 1,
 45            .mode = MODE_DCE,
 46            .ir_mode = NO_IRDA,
 47            .enabled = 1,
 48            .cts_threshold = UART1_UCR4_CTSTL,
 49            .dma_enabled = UART1_DMA_ENABLE,
 50            .dma_rxbuf_size = UART1_DMA_RXBUFSIZE,
 51            .rx_threshold = UART1_UFCR_RXTL,
 52            .tx_threshold = UART1_UFCR_TXTL,
 53            .dma_tx_id = MXC_DMA_UART1_TX,
 54            .dma_rx_id = MXC_DMA_UART1_RX,
 55            .rxd_mux = MXC_UART_RXDMUX,
 56            },
.....

SOC把串口集成在芯片中,所以串口要注册在platform_device上


139 static struct resource mxc_uart_resources1[] = {
140 {
141 .start = UART1_BASE_ADDR,
142 .end = UART1_BASE_ADDR + 0x0B5,
143 .flags = IORESOURCE_MEM,
144 },
145 {
146 .start = MXC_INT_UART1,
147 .flags = IORESOURCE_IRQ,
148 },
149 };

151 static struct platform_device mxc_uart_device1 = {
152 .name = "mxcintuart",
153 .id = 0,
154 .num_resources = ARRAY_SIZE(mxc_uart_resources1),
155 .resource = mxc_uart_resources1,
156 .dev = {
157 .platform_data = &mxc_ports[0],
158 },
159 };


上面的代码就是填充platform_device结构,并且把串口寄存器操作地址填充在resource中。
所有的数据都填充好后,就是调用platform_device_register(&mxc_uart_device1)就可以了,但是device会在什么时候来注册呢?所以用arch_initcall(mxc_init_uart)来启动即可。具体的initcall什么时候会调用,有个对应关系

core_initcall(fn) --->.initcall1.init
postcore_initcall(fn) --->.initcall2.init
arch_initcall(fn) --->.initcall3.init
subsys_initcall(fn) --->.initcall4.init
fs_initcall(fn) --->.initcall5.init
device_initcall(fn) --->.initcall6.init
late_initcall(fn) --->.initcall7.init

昨天看到base地址是0x73f00000,这里UART1_BASE_ADDR也是一样,但是在调用platform_device_register前所有的base都减去0x20000000,这样就和datasheet中的地址相同了。IOMUXC中的寄存器映射还是有些差异的。

参考资源
leave - kernel init call

imx535中IOMUX控制器

Tags: imx535

公司做项目,所以就外购了开发板,结果因为视频驱动问题一直无法调通,最后决定不再等客服了,自己来搞了。
Freescale的这块芯片,灰常的强大,自身集成了大量的功能,IPU、VPU、USB什么的,但是芯片规格却很小,所以发热量也很大。以前写裸机程序都是按步骤做,结果这次不太一样了。
裸机程序编写步骤:
1.配置复用脚到相应外设
2.配置外设的参数
3.启动外设

这里是大体的步骤,之前接触过友善和海思的芯片,但只在2440上写过裸机。对复用的理解就是当管脚不够用时,多个功能可以同时使用一个管脚,所以在使用相应外设时,要设置管脚的属性。这样是没错,但是当功能太多时,可能会出现一个管脚多于4种以上的功能,这就变得有些麻烦了。所以,imx535上的IOMUXC的出现就是解决这个问题。那么,具体是怎么解决这个问题呢?
芯片的功能很多,那么就有不同功能的针脚重叠,而实际上,每个功能需要配置多个pin才能使用,而每一个pin的不同意义,称为mode。假如要使用UART功能,直接配置RXD、TXD就好了,先确定相应管脚是RXD、TXD功能。
1.配置管脚到相应功能上,即mode
2.配置管脚的电平有效方式,即pull up/down

imx535芯片把一个针脚的不同功能称为ALT mode,最多有8个ALT modes。每种功能称为block。而多个功能block,又放在一个pad中,这样pad中blocks的针脚是大多相同,pad只去管理针脚的modes就可以了,即pad Register。
芯片中有多个pad,所以用一个IOMUXC不好管理,就有了IOMUXC cell,对应每个pad,用来配置pull up/down。

IOMUXC有4种register
GPR,选择SOC上的通用属性的模式,但与IOMUXC没有关系
Observability Register,用来作测试用
Software MUX Control Register, 配置IOMUXC的复用,并且“连接”到PAD上的相应功能
PAD setting Register,控制PAD配置,多个PAD的设置会被分组放在同一个Register中,配置时会影响分组中的其它PAD

IOMUXC_SW_MUX_CTL_PAD_,控制复用模式
IOMUXC_SW_PAD_CTL_PAD_,配置具体的某个PAD

下面来分析代码复用是怎么设置的

arch/arm/mach-mx5/mx53_smd.c
1963 MACHINE_START(MX53_SMD, "Freescale MX53 SMD Board")
1964     /* Maintainer: Freescale Semiconductor, Inc. */
1965     .fixup = fixup_mxc_board,
1966     .map_io = mx5_map_io,
1967     .init_irq = mx5_init_irq,
1968     .init_machine = mxc_board_init,
1969     .timer = &mxc_timer,
1970 MACHINE_END

mxc_board_init会在启动时被调用,而它又会调用mx53_smd_io_init()

arch/arm/mach-mx5/mx53_smd.c
1418 static void __init mx53_smd_io_init(void)
1419 {
1420 
1421     mxc_iomux_v3_setup_multiple_pads(mx53_smd_pads,
1422                     ARRAY_SIZE(mx53_smd_pads));
1423     mx53_pads_init();
1424 

1475 }

这里出现了mx53_smd_pads,是个结构体

 167 static struct pad_desc mx53_smd_pads[] = {
 168     /* UART 1*/     
 169     MX53_PAD_CSI0_D10__UART1_TXD,
 170     MX53_PAD_CSI0_D11__UART1_RXD,
 171     /*UART2*/
 172     MX53_PAD_ATA_DMARQ__UART2_TXD,
 173     MX53_PAD_ATA_BUFFER_EN__UART2_RXD,
 174     MX53_PAD_ATA_INTRQ__UART2_CTS,
 175     MX53_PAD_ATA_DIOR__UART2_RTS,

结构体里面的是宏,果断展开之

arch/arm/plat-mxc/include/mach/iomux-mx53.h
547 #define MX53_PAD_CSI0_D10__UART1_TXD        IOMUX_PAD(0x414, 0xE8, 2, 0x0, 0, MX53_UART_PAD_CTRL)
548 #define MX53_PAD_CSI0_D11__UART1_RXD        IOMUX_PAD(0x418, 0xEC, 2, 0x878, 1, MX53_UART_PAD_CTRL)
549 #define MX53_PAD_ATA_DIOW__UART1_TXD    IOMUX_PAD(0x5F0, 0x270, 3, 0x0, \
550                         0, MX53_UART_PAD_CTRL)
551 #define MX53_PAD_ATA_DMACK__UART1_RXD   IOMUX_PAD(0x5F4, 0x274, 3, 0x880, \
552                         3, MX53_UART_PAD_CTRL)

IOMUX_PAD继续展开

 63 #define IOMUX_PAD(_pad_ctrl_ofs, _mux_ctrl_ofs, _mux_mode, _select_input_ofs, \
 64         _select_input, _pad_ctrl)               \
 65         {                           \
 66             .mux_ctrl_ofs     = _mux_ctrl_ofs,      \
 67             .mux_mode         = _mux_mode,          \
 68             .pad_ctrl_ofs     = _pad_ctrl_ofs,      \
 69             .pad_ctrl         = _pad_ctrl,          \
 70             .select_input_ofs = _select_input_ofs,      \
 71             .select_input     = _select_input,      \
 72         }

现在来分析,UART1中的TXD脚,需要配置mode和pad中的针脚参数
IOMUXC_SW_MUX_CTL_PAD_CSIO_DAT10
addr = base + e8h
value = 010b
config UART1_IPP_UART_RXD_MUX_SELECT_INPUT for ALT2 mode

IOMUXC_SW_MUX_CTL_PAD_PATA_DIOW
addr = base + 270h
value = 011b (ALT3)
config UART1_IPP_UART_RXD_MUX_SELECT_INPUT for ALT3 mode

IOMUXC_SW_PAD_CTL_PAD_CSIO_DAT10
addr = base + 414h

IOMUXC_SW_PAD_CTL_PAD_PATA_DIOW
addr = base + 5f0h

IOMUXC_UART1_IPP_UART_RXD_MUX_SELECT_INPUT
addr = base +878h

以上是从DATASHEET中得到的,要使针脚具有TXD的功能,需要设置两个PAD。所以,MUX_SELECT_INPUT要设置两次,MUX_PATA_DIOW是用来选择SELECT_INPUT的mode,相应的PAD_CTL_PAD的CSIO_DAT10和PATA_DIOW是配置参数,如pull up/down有效。我们可以总结下:
1.针对不同的复用模式,mode要设置两次
2.SELECT_INPUT的也要设置两次
3.不同mode下的参数也要设置

CSIO_DAT10
MUX: base + mux_offset = mode
PAD: base + pad_offset = pad_ctrl
SELECT: base + select_offset = select_input

mux_offset = 0xe8,pad_offset = 0x414,select_offset = 0x0
mode = 2, pad_ctrl = MX53_UART_PAD_CTRL, select_input = 0

base在map_io中有设置

255 #define IOMUXC_BASE_ADDR    (AIPS1_BASE_ADDR + 0x000A8000)
241 #define AIPS1_BASE_ADDR     0x73F00000

但这里的地址是0x73f00000,而DATASHEET是0x53f00000,翻了下资料,AHB和IP连接,这个地方内存会不连续,至于具体原因,看DATASHEET(无力吐槽了,imx535的DATASHEET竟然5100页,我勒个去,真怀疑freescale的员工是从intel出来的)

最后,base地址在计算时用的是virtualaddr,所以有平台真好


 66 int mxc_iomux_v3_setup_pad(struct pad_desc *pad)
 67 {
 68    
 69     //1 I don't know if mux_ctrl_ofs is 0x3FF, it will be failed
 70     if (pad->mux_ctrl_ofs!=0x3FF)
 71     {
 72         __raw_writel(pad->mux_mode, base + pad->mux_ctrl_ofs);
 73     }
 74    
 75     printk("base = %p\n", base);
 76 
 77     if (pad->select_input_ofs)
 78         __raw_writel(pad->select_input,
 79                 base + pad->select_input_ofs); 
 80 
 81     if (!(pad->pad_ctrl & NO_PAD_CTRL) && pad->pad_ctrl_ofs)
 82         __raw_writel(pad->pad_ctrl, base + pad->pad_ctrl_ofs);
 83 
 84     return 0;
 85 }

这是最终的设置函数,每个pad_desc都会写值,这个pad_desc就是上面的mx53_smd_pads中的每一项,所以这个数组中把所有的复用包括了。

参考文献
mapleft的笔记-MX51 GPIO 及驱动

crosstool-ng制做hg526的工具链失败

crosstool-ng的用法,google中有很多,我主要参考Tekkaman Ninja的文章。但在编译过程中,出现了很多问题,现将问题记于此。为了方便编译,我把所有的包都放在了src下面。

gcc-4.2.2.tar.bz2
glibc-ports-2.8.tar.bz2
mpfr-2.4.2.tar.bz2
glibc-2.8.tar.bz2
gmp-4.3.1.tar.bz2
binutils-2.19.tar.bz2
glibc-linuxthreads-2.8.tar.bz2
linux-2.6.27.45.tar.bz2

1.kernel中Makefile文件出现混杂错误
原因:
make版本过高,与低版本的makefile文件不兼容
解决方法:
将错误行前的"/"删除即可

2.gcc的错误
[ERROR] /tmp/crosstool-ng/targets/src/gcc-4.2.2/gcc/regrename.c:1646: error: 'IFCVT_ALLOW_MODIFY_TEST_IN_INSN' undeclared (first use in this function)
原因:1646至1688行是AVR平台用的
解决方法:
将1646至1688行注释掉

3.glibc的错误:
These critical programs are missing or too old: as ld
解决方法:
根据Tekkaman的方法,修改glibc的configure文件,将里面的version区域改大些即可。configure 脚本认为gcc-4.3.2版本太老(其实是因为当时gcc还没有这么高的版本,只要不是3.2到4.1之间的版本,都认为too old),不能编译。
而我的gcc是4.5.1的,所以改成

case $ac_prog_version in
4532     '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;                                                               
4533     3.[2-9]*|4.[0-5]*)
4534        ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;                                                         
4535     *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
4536   
4537   esac

4.glibc-liuxthreads的错误:
linuxthreads需要自己来下载,并且将解出的目录重命名后打包。

5.glibc的manual错误:
make[3]: Entering directory `/sources/glibc-2.11.2/manual'
Makefile:235: *** mixed implicit and normal rules. Stop.
原因:make工具的版本问题
解决方法:
sed -i 's/ot \$/ot:\n\ttouch $@\n$/' manual/Makefile

经过一天的编译和排错,终于在glibc面前倒下了,除了gcc和g++其他都编译出来了。估计是由于版本的问题,crosstool-ng并不能很好的工作,所以决定有空再手动编译吧。

PS:最近西安的电信DNS又抽网了,直接访问博客竟然无法解析了,f**k

参考文献:
http://blog.chinaunix.net/uid-20543672-id-94369.html
http://busybox.is-programmer.com/posts/24549.html
http://blog.csdn.net/jiayinjia1983116/article/details/7007347
http://blog.chinaunix.net/space.php?uid=20543672&do=blog&id=94333

键鼠共享软件synergy

最近,在做GUI界面时,要参考另一个界面。而参考GUI程序是MFC写的,所以还得再开一台电脑(唉,嵌入式PC上跑MFC程序,我彻底服了)。我自己用本本,所以只需要鼠标就行了。但是办公桌已经被堆満了,正好想起有个共享键鼠的软件,就是synergy。程序是CS结构,所以在你想要共享的PC上运行Server端就可以了。我的是Window作server,linux作client来连接。至于配置和使用,参考Fei's World的文章就可以了。
Linux Server:
synergys -f –config synergy.conf
Linux Client:
synergyc -f server-IP


Reference Resource:
synergy使用全攻略(多台PC共享一套键盘鼠标)

最新文章

最近回复

  • Blackrose: 感谢拍砖!嗯,那句话...
  • aa: “Raspberry...
  • Blackrose: 外部只是帮你把芯片启...
  • : 内部时钟比外部的频率...
  • Blackrose: 你这评论比正文更有内容么
  • 7hao: CR+LF ...
  • Blackrose: 可以是你更新软件源后...
  • sxk: 博主,我的系统是ub...
  • Blackrose: 你深得精髓么
  • qihao: 这篇文章的简单总结就...

分类

归档

其它