S3C2416 Linux2.6.21 驱动移植--添加UART3 及波特率设置bug消除

一,移植环境

红色粗字体字为修改后内容,蓝色粗体字为特别注意内容)

1.主机环境:Virtualbox 下ubuntu-10.10

2.编译编译环境:arm-linux-gcc v4.4.3

3.uboot : U-Boot 1.3.4(友坚提供)

4.linux内核版本:2.6.21.5

5.硬件平台:采用友坚UT2416CV02核心板开发的平台

6.参考:

        linux内核支持S3C2416的UART3 (http://www.itkee.com/os/detail-1677.html )

修改linux内核支持S3C2416或S3C2443的UART3

linux内核版本为:2.6.21.5

1 2 3 步骤的修改都在/drivers/serial/s3c2410.c文件中。

1修改.#ifdef CONFIG_CPU_S3C2400

#define NR_PORTS (2)

#else

#define NR_PORTS (3)

#endif

为:

#ifdef CONFIG_CPU_S3C2400

#define NR_PORTS (2)

#else

#define (4)   /*modify by zhuang*/

#endif

2.在static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS]数组中添加:

#if NR_PORTS > 3

[3] = {

.port = {

.lock= SPIN_LOCK_UNLOCKED,

.iotype= UPIO_MEM,

.irq= IRQ_S3CUART_RX3,

.uartclk= 0,

.fifosize= 16,

.ops= &s3c24xx_serial_ops,

.flags= UPF_BOOT_AUTOCONF,

.line= 3,

} ,

#endif

3.结构体数组static struct uart_driver s3c24xx_uart_drv中的dev_name= "s3c2410_serial",

改为:

dev_name= "ttySAC",

修改.nr= 3,

为: .nr= NR_PORTS,

4.添加:在/includes/arm-arm/arch-s3c2410/irqs.h头文件中

/*UART3 for S3C2416 or S3C2443*/

#define IRQ_UART3                       IRQ_S3C2443_UART3

#define IRQ_S3CUART_RX3       IRQ_S3C2443_RX3

#define IRQ_S3CUART_TX3        IRQ_S3C2443_TX3

#define IRQ_S3CUART_ERR3   IRQ_S3C2443_ERR3

5./arch/arm/mach-smdk2416中的static struct s3c2410_uartcfg smdk2416_uartcfgs[] __initdata数组中添加:

./* UART3 */  

[3] = {

.hwport     = 3,

.flags     = 0,

.ucon     = 0x3c5,

.ulcon     = 0x03,

.ufcon     = 0x51,

6.arch/arm/mach-s3c2416/irq.c中,

#define SUBMSK_UART3(0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))修改为

#define SUBMSK_UART3(0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))

7.arch/arm/mach-s3c2443/irq.c中,

#define SUBMSK_UART3(0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))修改为

#define SUBMSK_UART3(0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))

6和7步骤的修改如果是 2.6.38以上版本就不用修改,这个bug在2.6.38以后就被修复了。

这个bug在http://permalink.gmane.org/gmane.linux.kernel.samsung-soc/3530

发布了。

8 修改.arch/arm/mach-s3c2443/irq.c和.arch/arm/mach-s3c2416/irq.c的

static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)

s3c2443_irq_demux(IRQ_S3C2443_UART3, 3);  

为:

static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)

        s3c2443_irq_demux(IRQ_S3C2443_RX3, 3);

9.include/asm/arch/regs-serial.h中,修改

#if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410)

#define NR_PORTS (4)

#define UART_FIFO_SIZE64

#define UART_HAS_INTMSK

#define UART_C_CFLAG

#define UART_UMCON

#define UART_CLK115200

#else

#define NR_PORTS (3)

#endif

为:

#if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410)

#define NR_PORTS (4)

#define UART_FIFO_SIZE64

#define UART_HAS_INTMSK

#define UART_C_CFLAG

#define UART_UMCON

#define UART_CLK115200

#else

#define NR_PORTS (4)

#endif

修改后重新编译内核就可以使用UART3了。

        S3C2416 User's Manual, Revision 1.10

 

二,添加UART3

      S3C2416支持4个UART,但友坚给出的内核只支持3个UART(ttySAC0,ttySAC1,ttySAC2),而不支持UART3 及 ttySAC3。下面介绍在友坚给出的内核基础上实现UART3。

 

1.添加UART3的资源设置

       <1>. 打开 kernel2416/arch/arm/plat-s3c24xx/devs.c ,定位到113行附近,更改如下:

  1. /* 
  2. #if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410)  
  3. static struct resource s3c_uart3_resource[] = { 
  4.     [0] = { 
  5.         .start = S3C2443_PA_UART3, 
  6.         .end   = S3C2443_PA_UART3 + 0x3ff, 
  7.         .flags = IORESOURCE_MEM, 
  8.     }, 
  9.  
  10.     [1] = { 
  11.         .start = IRQ_UART3, 
  12.         .end   = IRQ_UART3, 
  13.         .flags = IORESOURCE_IRQ, 
  14.     } 
  15. }; 
  16. #endif 
  17. **               change by bobee, 2012-03-8                 */  
  18. static struct resource s3c2410_uart3_resource[] = {  
  19.     [0] = {  
  20.         .start = S3C2443_PA_UART3,  
  21.         .end   = S3C2443_PA_UART3 + 0x3fff,  
  22.         .flags = IORESOURCE_MEM,  
  23.     },  
  24.     [1] = {  
  25.         .start = IRQ_S3CUART_RX3,  
  26.         .end   = IRQ_S3CUART_ERR3,  
  27.         .flags = IORESOURCE_IRQ,  
  28.     }  
  29. };  

      <2>. 定位到157行附近,

#if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410) || defined (CONFIG_CPU_S3C2416)
      [3] = {
                   .resources = s3c2410_uart3_resource,
                   .nr_resources = ARRAY_SIZE(s3c2410_uart3_resource),
      },
#endif


      <3>. 定位到179行附近,

 #if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410) || defined (CONFIG_CPU_S3C2416)// add by bobee, 2011-03-08

static struct platform_device s3c24xx_uart_device3 = {
           .id  = 3,
};
#endif


    <4>. 定位到189行附近, 

#if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410) ||  defined (CONFIG_CPU_S3C2416) // add by bobee, 2011-03-08
        &s3c24xx_uart_device3,
#endif

2.添加UART3的默认配置

         打开kernel2416/arch/arm/mach-s3c2416/mach-smdk2416.c,定位到113行后,在结构体smdk2416_uartcfgs[] 中添加以下代码:

  1. // add by bobee, 2012-03-08   
  2. [3] = {  
  3.     .hwport      = 3,  
  4.     .flags       = 0,  
  5.     /* Use PCLK */  
  6.     .ucon        = 0x3c5,  
  7.     //.ucon      = 0xfc5,   
  8.     .ulcon       = 0x03,  
  9.     .ufcon       = 0x51,  
  10.     .clocks      = smdk2416_serial_clocks,  
  11.     .clocks_size = ARRAY_SIZE(smdk2416_serial_clocks),  
  12. }  

3.更改s3c2416 的UART3 的中断相关函数

         打开kernel2416/arch/arm/mach-s3c2416/irq.c,定位到181行后,更改如下:

  1. static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)  
  2. {  
  3.     //s3c2443_irq_demux(IRQ_S3C2443_UART3, 3);  
  4.     s3c2443_irq_demux(IRQ_S3C2443_RX3, 3);      // change by bobee, 2012-03-09  
  5. }  

      更改UART3的子串口中断掩码

//#define SUBMSK_UART3 (0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
// change by bobee, 2012-03-09
#define SUBMSK_UART3 (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))



4.更改头文件regs-serial.h 中的相关定义

          打开kernel2416/include/asm-arm/arch-s3c2410/irqs.h , 定位到153行后,添加如下定义

/* UART3 */
#define IRQ_S3C2443_RX3  S3C2410_IRQSUB(24)
#define IRQ_S3C2443_TX3  S3C2410_IRQSUB(25)
#define IRQ_S3C2443_ERR3 S3C2410_IRQSUB(26)

// add by bobee, 2012-03-08

#define IRQ_UART3                     IRQ_S3C2443_UART3
#define IRQ_S3CUART_RX3         IRQ_S3C2443_RX3
#define IRQ_S3CUART_TX3         IRQ_S3C2443_TX3
#define IRQ_S3CUART_ERR3      IRQ_S3C2443_ERR3
    

      更改串口数,定位到366行后,

#if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410)
#define NR_PORTS  (4)
#define UART_FIFO_SIZE 64
#define UART_HAS_INTMSK
#define UART_C_CFLAG
#define UART_UMCON
#define UART_CLK 115200
#elif defined (CONFIG_CPU_S3C2416)
#define NR_PORTS  (4)  // change by bobee, 2012-03-08
#else
#define NR_PORTS  (3)
#endif

5.修改串口驱动文件

    打开/kernel2416/drivers/serial/s3c2410.c

   <1>. 定位到165行,更改串口个数

#ifdef CONFIG_CPU_S3C2400
#define NR_PORTS (2)
#else
#define NR_PORTS    (4)        //  (3)     // change by bobee, 2012-03-08
#endif

     <2>. 定位到627行,在结构体 struct baud_calc 中添加如下变量

  1. struct baud_calc {  
  2.     struct s3c24xx_uart_clksrc  *clksrc;  
  3.     unsigned int             calc;  
  4.     unsigned int             quot;  
  5.     unsigned int             udivslot;      // add by bobee, 2012-03-07  
  6.     struct clk          *src;  
  7. };  

 

     <3>.  添加 S3C2416 波特率 dividing slot register UDIVSLOTn 查询表:

        (添加在上面struct baud_calc  结构体定义后)

// add by bobee, 2012-03-07
const unsigned int udivslot_table[16] = {0x0000, 0x0080, 0x0808, 0x0888, 0x2222, 0x4924, 0x4a52, 0x54aa,
           0x5555, 0xd555, 0xd5d5, 0xddd5, 0xdddd, 0xdfdd, 0xdfdf, 0xffdf};

     <4>. 定位到636行附近,更改波特率计算函数s3c24xx_serial_calcbaud,

              更改如下:(更改后可以改善波特率 UBRDIVn设置值

 

  1. static int s3c24xx_serial_calcbaud(struct baud_calc *calc,  
  2.                    struct uart_port *port,  
  3.                    struct s3c24xx_uart_clksrc *clksrc,  
  4.                    unsigned int baud)  
  5. {  
  6.     unsigned long rate;  
  7. // change by bobee, 2012-06-07  
  8. #if 1   
  9.     unsigned long tempdiv;  
  10.     unsigned int nslot, serial_result_1, serial_result_2;  
  11.   
  12.   
  13.     calc->src = clk_get(port->dev, clksrc->name);  
  14.     if (calc->src == NULL || IS_ERR(calc->src))  
  15.         return 0;  
  16.   
  17.     baud/=100;  
  18.   
  19.     rate = clk_get_rate(calc->src);  
  20.     rate /= clksrc->divisor;  
  21.   
  22.     calc->clksrc = clksrc;  
  23.   
  24.     tempdiv = (rate*10/(baud*16))-1000;  
  25.     serial_result_1 = ((tempdiv%1000)*16)/1000;  
  26.     serial_result_2 = (((tempdiv%1000)*16) - (serial_result_1*1000));  
  27.   
  28.     if (serial_result_2 >=500)  
  29.         nslot = serial_result_1+1;  
  30.     else  
  31.         nslot = serial_result_1;  
  32.   
  33.     calc->quot = tempdiv/1000;  
  34.     calc->calc = (rate / (calc->quot * 16));  
  35.     calc->udivslot = udivslot_table[nslot];  
  36.     printk(KERN_DEBUG  "FOUND quot %d, calc %d, slot 0x%x, nslot %d\n",  
  37.                    calc->quot, calc->calc ,  
  38.                    calc->udivslot, nslot);  
  39.   
  40. #else   
  41.     calc->src = clk_get(port->dev, clksrc->name);  
  42.     if (calc->src == NULL || IS_ERR(calc->src))  
  43.         return 0;  
  44.   
  45.     rate = clk_get_rate(calc->src);  
  46.     rate /= clksrc->divisor;  
  47.   
  48.     calc->clksrc = clksrc;  
  49. #if 0   
  50.     /* Error to calculation of UART BAUD RATE DIVISOR */  
  51.     calc->quot = (rate + (8 * baud)) / (16 * baud);  
  52. #else   
  53.     /* Error correction */  
  54.     calc->quot = (rate) / (16 * baud);  
  55. #endif   
  56.     calc->calc = (rate / (calc->quot * 16));  
  57.   
  58.     calc->quot--;  
  59.   
  60. #endif   
  61.     return 1;  
  62. }  


      <5>. 修改函数s3c24xx_serial_set_termios()

  更改如下:(这里主要是 设置 寄存器UDIVSLOTn 的值,如果不设置此值,会导致波特率不准的问题

  1. static void s3c24xx_serial_set_termios(struct uart_port *port,  
  2.                        struct ktermios *termios,  
  3.                        struct ktermios *old)  
  4. {  
  5.     struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);  
  6.     struct s3c24xx_uart_port *ourport = to_ourport(port);  
  7.     struct s3c24xx_uart_clksrc *clksrc = NULL;  
  8.     struct clk *clk = NULL;  
  9.     unsigned long flags;  
  10.     unsigned int baud, quot;  
  11.     unsigned int ulcon;  
  12.     unsigned int umcon;  
  13.     unsigned int udivslot = 0, div; // add by bobee, 2012-03-07  
  14.   
  15.     /* 
  16.      * We don't support modem control lines. 
  17.      */  
  18.     termios->c_cflag &= ~(HUPCL | CMSPAR);  
  19.     termios->c_cflag |= CLOCAL;  
  20.   
  21.     /* 
  22.      * Ask the core to calculate the divisor for us. 
  23.      */  
  24.   
  25.     baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);  
  26.   
  27.     if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)  
  28.         quot = port->custom_divisor;  
  29.     else  
  30.         quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);  
  31.   
  32.     /* check to see if we need  to change clock source */  
  33.   
  34.     if (ourport->clksrc != clksrc || ourport->baudclk != clk) {  
  35.         s3c24xx_serial_setsource(port, clksrc);  
  36.   
  37.         if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {  
  38.             clk_disable(ourport->baudclk);  
  39.             ourport->baudclk  = NULL;  
  40.         }  
  41.   
  42.         clk_enable(clk);  
  43.   
  44.         ourport->clksrc = clksrc;  
  45.         ourport->baudclk = clk;  
  46.     }  
  47. // add by bobee, 2012-03-07   
  48. #if defined(CONFIG_CPU_S3C2416)   
  49.     div = clk_get_rate(clk) / baud;  
  50.     udivslot = udivslot_table[div & 15];  
  51.   
  52. #endif   
  53.     switch (termios->c_cflag & CSIZE) {  
  54.     case CS5:  
  55.         dbg("config: 5bits/char\n");  
  56.         ulcon = S3C2410_LCON_CS5;  
  57.         break;  
  58.     case CS6:  
  59.         dbg("config: 6bits/char\n");  
  60.         ulcon = S3C2410_LCON_CS6;  
  61.         break;  
  62.     case CS7:  
  63.         dbg("config: 7bits/char\n");  
  64.         ulcon = S3C2410_LCON_CS7;  
  65.         break;  
  66.     case CS8:  
  67.     default:  
  68.         dbg("config: 8bits/char\n");  
  69.         ulcon = S3C2410_LCON_CS8;  
  70.         break;  
  71.     }  
  72.   
  73.     /* preserve original lcon IR settings */  
  74.     ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);  
  75.   
  76.     if (termios->c_cflag & CSTOPB)  
  77.         ulcon |= S3C2410_LCON_STOPB;  
  78.   
  79.     umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0;  
  80.   
  81.     if (termios->c_cflag & PARENB) {  
  82.         if (termios->c_cflag & PARODD)  
  83.             ulcon |= S3C2410_LCON_PODD;  
  84.         else  
  85.             ulcon |= S3C2410_LCON_PEVEN;  
  86.     } else {  
  87.         ulcon |= S3C2410_LCON_PNONE;  
  88.     }  
  89.   
  90.     spin_lock_irqsave(&port->lock, flags);  
  91.   
  92.     dbg("setting ulcon to %08x, brddiv to %d\n", ulcon, quot);  
  93.   
  94.     wr_regl(port, S3C2410_ULCON, ulcon);  
  95.     wr_regl(port, S3C2410_UBRDIV, quot);  
  96. #if defined(CONFIG_CPU_S3C2416)   
  97.     wr_regl(port, S3C_UDIVSLOT, udivslot);          // add by bobee, 2012-03-07  
  98. #endif   
  99.     wr_regl(port, S3C2410_UMCON, umcon);  
  100.   
  101.     dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",  
  102.         rd_regl(port, S3C2410_ULCON),  
  103.         rd_regl(port, S3C2410_UCON),  
  104.         rd_regl(port, S3C2410_UFCON));  
  105. #if defined(CONFIG_CPU_S3C2416)  
  106.     dbg("UDIVSLOT=0x%08x, UBRDIV=0x%08x\n",   
  107.             rd_regl(port, S3C2410_UBRDIV),  
  108.         rd_regl(port, S3C_UDIVSLOT));  
  109. #endif   
  110.     dbg("baud=%d,clk=%ld \n", baud, clk_get_rate(clk));   
  111.   
  112.   
  113.     /* 
  114.      * Update the per-port timeout. 
  115.      */  
  116.     uart_update_timeout(port, termios->c_cflag, baud);  
  117.   
  118.     /* 
  119.      * Which character status flags are we interested in? 
  120.      */  
  121.     port->read_status_mask = S3C2410_UERSTAT_OVERRUN;  
  122.     if (termios->c_iflag & INPCK)  
  123.         port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;  
  124.   
  125.     /* 
  126.      * Which character status flags should we ignore? 
  127.      */  
  128.     port->ignore_status_mask = 0;  
  129.     if (termios->c_iflag & IGNPAR)  
  130.         port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;  
  131.     if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)  
  132.         port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;  
  133.   
  134.     /* 
  135.      * Ignore all characters if CREAD is not set. 
  136.      */  
  137.     if ((termios->c_cflag & CREAD) == 0)  
  138.         port->ignore_status_mask |= RXSTAT_DUMMY_READ;  
  139.   
  140.     spin_unlock_irqrestore(&port->lock, flags);  
  141. }  

   <6>. 修改结构体 s3c24xx_uart_drv

        定位到1011行附近,修改如下:

  1. static struct uart_driver s3c24xx_uart_drv = {  
  2.     .owner      = THIS_MODULE,  
  3.     .dev_name   = "s3c2410_serial",  
  4.     .nr     = NR_PORTS, //3,            // change by bobee, 2012-03-07  
  5.     .cons       = S3C24XX_SERIAL_CONSOLE,  
  6.     .driver_name    = S3C24XX_SERIAL_NAME,  
  7.     .major      = S3C24XX_SERIAL_MAJOR,  
  8.     .minor      = S3C24XX_SERIAL_MINOR,  
  9. };  

     <7>. 在结构体 s3c24xx_serial_port[NR_PORT]中添加,uart3的设置

  1. #if defined (CONFIG_CPU_S3C2416) // add by bobee, 2011-03-07  
  2.     [3] = {  
  3.         .port = {  
  4.             .lock       = SPIN_LOCK_UNLOCKED,  
  5.             .iotype     = UPIO_MEM,  
  6.             .irq        = IRQ_S3CUART_RX3,  
  7.             .uartclk    = 0,  
  8.             .fifosize   = 16,  
  9.             .ops        = &s3c24xx_serial_ops,  
  10.             .flags      = UPF_BOOT_AUTOCONF,  
  11.             .line       = 3,  
  12.         }  
  13.     }  
  14. #endif  

 


到此位置,已经成功添加串口 UART3,并修补了原来波特率不能设置9600 bug.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个错误信息表明在linux-2.6.21版本的kernel/Makefile文件的第6行缺少了分隔符。由于没有提供完整的错误信息,我不能确定确切的原因,但是这个错误通常是由于Makefile文件中的语法错误引起的。在Makefile中,每个命令必须以一个制表符(或多个空格)作为开头。如果在该行中没有正确的分隔符,make工具将无法解析该命令,并显示该错误。 要修复这个错误,你可以检查Makefile文件的第6行,并确保在命令前有一个正确的分隔符(制表符或多个空格)。另外,还应该注意确保该行没有任何非法字符或注释。 如果问题仍然存在,那么可能是由于其他地方的错误导致的。你可以检查其他相关的文件和配置,以确定问题的根本原因。 请注意,引用内容中提供的版本信息(2.6.0到2.6.33)可能与你提供的问题不直接相关,因此不一定会对问题的解答产生影响。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [GitHub - luxianyou/linux-kernel-exploits: linux-kernel-exploits Linux平台提权漏洞集合](https://blog.csdn.net/weixin_36111561/article/details/116954363)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值