Keep Faith

统计

ARM移植

最新评论

s3c2410的linux 2.6.13下的无线网卡移植

折腾了一个多星期,终于完成了2.6.13下的无线网卡移植..

我们所使用了复旦大学CAT实验室自制的系统板,其采用S3C2410为核心,通过PD6710进行PCMCIA总线扩展,无线网卡采用的是清华同方的TFW1000.
硬件介绍:
PD6710接在nGCS1空间,使用A20进行IO与MEM空间的分隔.因此地址分配如下:
    A20=1, I/O area (A26 should have been used.)
    A20=0, mem area
    AEN=nGCS1,

    absolute address       
    0x08000000~0x080FFFFF: memory area
    0x08100000~0x081FFFFF: I/O area

中断:
card IRQ使用IRQ3,并连接到s3c2410的EINT4管脚.
manager IRQ没有使用.

主要的移植工作包括:
1.在./arch/arm/mach-s3c2410/mach-smdk2410.c中添加以上虚拟地址映射,代码如下:
//>>>>----------Modified by Zengyi 2007-5-23
  { (u32)S3C24XX_VA_ISA_WORD, pCF_IO_BASE, SZ_1M, MT_DEVICE },
  { (u32)S3C24XX_VA_ISA_BYTE, pCF_IO_BASE, SZ_1M, MT_DEVICE },

  { (u32)vCF_MEM_BASE,                    pCF_MEM_BASE,  SZ_1M, MT_DEVICE },
  { (u32)vCF_IO_BASE,                     pCF_IO_BASE,   SZ_1M, MT_DEVICE },
//<<<<----------Modify End
其中,S3C24XX_VA_ISA_WORD以及S3C24XX_VA_ISA_BYTE的映射主要是为了将isa的io空间读取映射到PD6710的io区域,
例如,调用inb(0x00)是,将等效于调用((uchar*)(pCF_IO_BASE).这样可以保证PD6710中部分代码不用修改,但是需要注意的
是如果还是其他驱动程序调用inb等函数时,将会产生问题,这是建立将以上两个映射取消,然后修改驱动函数中的inb函数调用.
2.(可选),修改系统时钟,由于板子电器特性问题,pd6710在memory时钟为200MHz时,会出现读写错误,因此不得不降低系统时钟,将时钟 修改为180MHz, memory时钟为90MHz.主要的修改/arch/arm/mach-s3c2410/s3c2410.c:
unsigned long mpllvalue = (0x52<<12)|(0x01<<4)|(0x01); //Set Clock to 180MHz, PD6710 can't work well in 200MHz
__raw_writel(mpllvalue,S3C2410_MPLLCON);

3.因为PD6710为82365兼容芯片,因此其驱动在./driver/pcmcia/i82365.c文件中,主要需要进行如下修改:
a.  修改 
static int has_dma = -1;
static int has_led = -1;
static int has_ring = -1;
static int dynamic_mode = 1;
static int freq_bypass = 1;
static int setup_time = 1; /* default value*/
static int cmd_time = 6;  /*  default value*/
static int recov_time = 3; /*default value */
主要是修改一些默认参数,setup_time,cmd_time ,recov_time,均设为PD6710手册上所标记的默认值.(不知道为什么如果
上电后读出来的值并不是手册上的默认值,所以我们手动置为默认值).
b. 在 cirrus_set_state函数中添加:
//>>>>----------- Added by Zengyi 2007_5_29
    //flush fifo first
    i365_set(s, PD67_FIFO_CTL , 0x80);
    //>>>>----------- end of add
    for (i = 0; i < 6; i++)
        i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]);
   这是按照手册上的要求,修改TIME寄存器之前需要将FIFO清空.
c.  在add_pcic函数中添加如下部分(重要):
    //>>>>------------- Add by Zengyi 2007_5_23
    #ifdef CONFIG_ARCH_SMDK2410_CATLAB
    /* Use SS_CAP_STATIC_MAP which disables the memory resource
       database check and SS_CAP_PAGE_REGS which disable io port
       maximun limit 0xffff */
    t[i].socket.features |= SS_CAP_PCCARD | SS_CAP_STATIC_MAP | SS_CAP_PAGE_REGS;
    /* We just pass up an offset which is applied to client-requested
       base I/O addresses in alloc_io_space() */
    t[i].socket.io_offset = vCF_IO_BASE;
    /* Map Size */
    t[i].socket.map_size = 0x1000;
    /* Do not use ISA irq */
    t[i].socket.irq_mask = 0;
    t[i].socket.pci_irq = IRQ_CF_RDY;
    /* Card Detect IRQ */
    t[i].cs_irq = 0;
    /* Enable Management Interrupt for card detect */
    t[i].intr = I365_INTR_ENA;
    /* PD6710 IRQ3 is only connected to IRQ_CF_RDY */
    t[i].intr |= 3 << 0;

#else

    t[i].socket.features |= SS_CAP_PCCARD;
    t[i].socket.map_size = 0x1000;
    t[i].socket.irq_mask = mask;
    t[i].cs_irq = isa_irq;
#endif
//>>>>------------- end of add

以上部分的作用主要是
设置socket.为STATIC MAP的, 设置io_offset 为新的虚拟地址,配置pci_irq 外部中断 EINT4, 配置使用PD6710的IRQ3作为PC CARD的card IRQ.

d. 在isa_probe函数中,直接添加一个pcic,因为我们只有一个pcic.
//<<<<----------------Add by Zengyi 2007_5_23
#ifdef CONFIG_ARCH_SMDK2410_CATLAB
    /* There is just one socket */
    add_socket(i365_base, 0, id);
    add_pcic(1, id);
#else
//>>>>----------------end of Add

e. 由于我们设置了socket为STATIC MAP,因此我们IO/MEMORY的映射需要自己手动完成:
在pcic_init函数中,可以修改
pccard_io_map io = { 0, 0, 0, 0, 0x100 }; 先设置好一段IO映射,但是我们现在还没有enable.
enable的操作本来应该在set_io_map函数中,但是有些上层的驱动并不会调用set_io_map函数(如我们的orinoco驱动),因此
我们选择在i365_set_socket函数中调用:
 /* IO card, RESET flag, IO interrupt */
    reg = t->intr;
    //reg |= state->io_irq;
    reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
    reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
    i365_set(sock, I365_INTCTL, reg);
    //<<<<----------------- Added by Zengyi 2007_5_28
    if(reg & I365_PC_IOCARD) {
        //Enable IO MAP
        i365_bset(0, I365_ADDRWIN, I365_ENA_IO(0));
    }
    //>>>>------------------ end of Add
即,如果在set_socket的参数
state->flags中设置了SS_IOCARD那么,我们就把IO MAP0使能.

f. 修改set_mem_map函数(相当重要!!!)
在函数的开头部分添加:

//<<<<------------- Added by Zengyi 2007_5_25
#ifdef CONFIG_ARCH_SMDK2410_CATLAB
  if(mem->res == NULL) {
    printk(KERN_DEBUG "Make resource ourseleves\n");
    mem->res = claim_region(NULL,pCF_MEM_BASE,SZ_1M,IORESOURCE_MEM,"PD6710 Mem");
  } else {
    //i365_get_mem_map(sock,mem);
  }
  while (mem->res->start >= pCF_MEM_BASE) mem->res->start -= pCF_MEM_BASE;
  while (mem->res->end >= pCF_MEM_BASE) mem->res->end -= pCF_MEM_BASE;
#endif
//>>>>------------- end of Add
在函数尾添加:
//<<<<----------------- Add by Zengyi 2007_5_24
#ifdef CONFIG_ARCH_SMDK2410_CATLAB
    mem->res->start += pCF_MEM_BASE;
    mem->res->end += pCF_MEM_BASE;
#endif

    mem->static_start = mem->res->start;
该步骤的作用有以下部分:
首先检测mem->res是否非空,这一点不知道是不是2.6.13内核的bug,因为当设置为STATIC_MAP时,调用 pcmcia_validate_mem后会将s->mem->res置为NULL,这样接下来如pccard_validate_cis等 就可能会传递NULL指针
给set_mem_map函数,因此如果我们发现mem->res为NULL时则需要自己生成mem->res.
  while (mem->res->start >= pCF_MEM_BASE) mem->res->start -= pCF_MEM_BASE;
  while (mem->res->end >= pCF_MEM_BASE) mem->res->end -= pCF_MEM_BASE;
以及
    mem->res->start += pCF_MEM_BASE;
    mem->res->end += pCF_MEM_BASE;
的作用是对硬件地址的偏移进行调整,记住我们PD6710的mem空间为
0x08000000~0x080FFFFF.
mem->static_start = mem->res->start; 是重新设置mem->static_start .因为当设置为STATIC_MAP时,
上层函数会调用set_cis_map,而在该函数中会调用
s->cis_virt = ioremap(mem->static_start, s->map_size);
重新生成
s->cis_virt.
static void __iomem *
set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags)
{
    pccard_mem_map *mem = &s->cis_mem;
    int ret;

    if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) {
        mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s);
        if (mem->res == NULL) {
            printk(KERN_NOTICE "cs: unable to map card memory!\n");
            return NULL;
        }
        s->cis_virt = NULL;
    }

    if (!(s->features & SS_CAP_STATIC_MAP) && (!s->cis_virt))
        s->cis_virt = ioremap(mem->res->start, s->map_size);

    mem->card_start = card_offset;
    mem->flags = flags;

    ret = s->ops->set_mem_map(s, mem);
    if (ret) {
        iounmap(s->cis_virt);
        s->cis_virt = NULL;
        return NULL;
    }

    if (s->features & SS_CAP_STATIC_MAP) {
        if (s->cis_virt)
            iounmap(s->cis_virt);
        s->cis_virt = ioremap(mem->static_start, s->map_size);
    }


    return s->cis_virt;
}

g. 在init_i82365中添加S3C2410 bank1 以及中断配置代码:
//>>>---------Add by Zengyi 2007_5_23
#ifdef CONFIG_ARCH_SMDK2410_CATLAB
        volatile unsigned int regval;
        void __iomem *port;
//      printk(KERN_ERR "init_pd6710 start!\n");
        port=S3C2410_BWSCON;
//      printk(KERN_ALERT "Register BWSCON's address is %#x\n",port);

        //regval=inl_p(port);
        regval = __raw_readl(port);
        //printk(KERN_ALERT "BWSCON's value before change is %#x\n",regval);

        regval=(regval &(0xffffff0f))|(S3C2410_BWSCON_ST1|S3C2410_BWSCON_WS1|S3C2410_BWSCON_DW1_16);
        //outl_p(regval,port);
        __raw_writel(regval,port);
        //regval = __raw_readl(port);
        //printk(KERN_ALERT "BWSCON's value after change is %#x\n",regval);

        port=S3C2410_BANKCON1;
        //regval = __raw_readw(port);
        //printk(KERN_ALERT "BANKCON1's value before change is 0x%#x\n",regval);
//      printk(KERN_ERR "BWSCON step is OK!\n");
        regval=S3C2410_BANKCON_Tacs1|S3C2410_BANKCON_Tcos4|S3C2410_BANKCON_Tacc14|
               S3C2410_BANKCON_Tcoh1|S3C2410_BANKCON_Tcah1|S3C2410_BANKCON_Tacp6|S3C2410_BANKCON_PMCnorm;
        //regval=S3C2410_BANKCON_Tacs4|S3C2410_BANKCON_Tcos4|S3C2410_BANKCON_Tacc14|
        //        S3C2410_BANKCON_Tcoh4|S3C2410_BANKCON_Tcah4|S3C2410_BANKCON_Tacp6|S3C2410_BANKCON_PMCnorm;

        //outl_p(regval,port);
        __raw_writew(regval,port);

        //regval = __raw_readw(port);
        //printk(KERN_ALERT "BANKCON1's value after change is %#x\n",regval);

//      printk(KERN_ERR "BWSCON1 step is OK!\n");
        if(IRQ_nCF_INS!=0)
        {
                set_irq_type(IRQ_nCF_INS,IRQT_FALLING);
        }
//      printk(KERN_ERR " set_irq_type(IRQ_nCF_INS) is ok\n");
        set_irq_type(IRQ_CF_RDY,IRQT_RISING);
        s3c2410_gpio_pullup(S3C2410_GPF4,0);
        printk(KERN_ALERT "init_pd6710 has successfully finished!\n");

#endif /* CONFIG_ARCH_SMDK2410_CATLAB */

4.修改rsrc_nonstatic.c文件:
//>>>>---------- Modified by Zengyi 2007_5_27
//INT_MODULE_PARM(probe_mem,    1);     /* memory probe? */
INT_MODULE_PARM(probe_mem,  0);     /* memory probe? */
//>>>>---------- end of modify
#ifdef CONFIG_PCMCIA_PROBE
//>>>>---------- Modified by Zengyi 2007_5_27
//INT_MODULE_PARM(probe_io, 1);     /* IO port probe? */
INT_MODULE_PARM(probe_io,   0);     /* IO port probe? */
//>>>>---------- end of modify
INT_MODULE_PARM(mem_limit,  0x10000);
#endif

主要是将probe_io以及probe_mem均设为0,因为我们使用的是static的地址,因此没有必要进行probe.

在修改好以上文件后,在make menuconfig 中将PCMCIA,以及i386支持编入内核,重新编译后的内核就可以
认出我们PD6710.

5.交叉编译cardmgr程序.可以在pcmcia-cs网站中找到.
6.编译orinoco驱动. 选项为Network device support下的Wireless LAN (non-hamradio),<*> Hermes chipset 802.11b support (Orinoco/Prism2/Symbol) 以及<*> Hermes PCMCIA card support.
使用linux 2.6.13中的orinoco驱动时会出现如下错误:
hermes @ e1000000: BAP1 offset error: reg=0x3c id=0xbc offset=0x0
eth1: error -5 reading Rx descriptor. Frame dropped.
但是换成2.4内核中的orinoco驱动后就没有这个错误了.具体原因还没有发现.
7.重新启动以后,无线网卡便可成功启动.


posted on 2007-05-30 21:21 sardis 阅读(1525) 评论(4)  编辑 收藏 引用 所属分类: linux移植

评论

# re: s3c2410的linux 2.6.13下的无线网卡移植 2008-01-08 18:55 陈西名

你好,请问下面这个地址是怎么定下来的?根据是什么?谢谢阿

absolute address
0x08000000~0x080FFFFF: memory area
0x08100000~0x081FFFFF: I/O area  回复  更多评论   

# re: s3c2410的linux 2.6.13下的无线网卡移植 2008-01-08 21:19 sardis

这个是硬件决定的,看你的PD6710是怎么接的  回复  更多评论   

# re: s3c2410的linux 2.6.13下的无线网卡移植 2008-01-09 15:32 陈西名

很感谢你的答复,能交个朋友么,我在北京上班  回复  更多评论   

# re: s3c2410的linux 2.6.13下的无线网卡移植 2008-01-09 21:30 sardis

当然..我现在还在复旦学习.. 可以留言到
sardis.yculblog.com. 这个blog我已经不大更新了  回复  更多评论   

只有注册用户登录后才能发表评论。