Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2279952
  • 博文数量: 668
  • 博客积分: 10016
  • 博客等级: 上将
  • 技术积分: 8588
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-29 19:22
文章分类

全部博文(668)

文章存档

2011年(1)

2010年(2)

2009年(273)

2008年(392)

分类:

2009-05-04 17:55:46

以下是文件io.c的浅析。

/*
 * linux/arch/arm/mach-davinci/io.c
 *
 * DaVinci I/O mapping code
 *
 * Copyright (C) 2005-2006 Texas Instruments
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

#include <asm/tlb.h>
#include <asm/io.h>

#include <asm/mach/map.h>
#include <asm/arch/memory.h>
#include <asm/arch/cpu.h>
#include <asm/arch/mux.h>

/*
 该文件实现了DM644x平台的IO寄存器物理地址到虚拟地址的映射和IRAM的物理地址到虚拟地址的映射,
 以及模块时钟的注册和复用引脚的初始化。
*/



extern int davinci_clk_init(void);
extern void davinci_check_revision(void);
unsigned int davinci_cpu_index = DM644X_CPU_IDX;    // 0


/*
 * The machine specific code may provide the extra mapping besides the
 * default mapping provided here.
 */

static struct map_desc davinci_io_desc[] __initdata = {
    {
        .virtual    = IO_VIRT,        // 0xe1000000

        .physical    = IO_PHYS,        // 0x01c00000

        .length        = IO_SIZE,        // 4M

        .type        = MT_DEVICE,
    },
};

// 针对DM644x平台的映射

static struct map_desc dm644x_io_desc[] __initdata = {
    {
        .virtual    = DAVINCI_IRAM_VIRT,    // IO_VIRT+IO_SIZE+4M

        .physical    = DAVINCI_IRAM_BASE,    // 0x00008000

        .length        = DAVINCI_IRAM_SIZE,    // 16K

        .type        = MT_DEVICE,
    },
};

// 针对DM646x平台的映射

static struct map_desc dm646x_io_desc[] __initdata = {
    {
        .virtual    = DM646X_IO_VIRT,
        .physical    = DM646X_IO_PHYS,
        .length        = DM646X_IO_SIZE,
        .type        = MT_DEVICE,
    },
    {
        .virtual    = DAVINCI_IRAM_VIRT,
        .physical    = DM646X_IRAM_BASE,
        .length        = DAVINCI_IRAM_SIZE,
        .type        = MT_DEVICE,
    },
    {
        .virtual    = EMIF_CNTRL_VIRT,
        .physical    = DAVINCI_DM646X_ASYNC_EMIF_CNTRL_BASE,
        .length        = SZ_16K,
        .type        = MT_DEVICE,
    },
};

/*
 IO内存初始化。 
 davinci_map_common_io()例程被davinci_map_io()例程调用,而其又被注册到board_evm.c中的
 机器描述符中(struct machine_desc),故具体调用过程是:
 start_kernel()-->setup_arch()-->paging_init()-->mdesc->map_io()
 (其就是davinci_map_io())-->davinci_map_common_io()。
*/

void __init davinci_map_common_io(void)
{
    
    // 创建IO寄存器物理地址到虚拟地址的映射,不cache

    iotable_init(davinci_io_desc, ARRAY_SIZE(davinci_io_desc));

    /* We want to check CPU revision early for cpu_is_davinci_xxxx() macros.
     * IO space mapping must be initialized before we can do that.
     */

     
    // 从寄存器中读取达芬奇平台版本号并打印

    davinci_check_revision();

    // 根据不同的平台映射IRAM的物理地址到虚拟地址,不cache

    if (cpu_is_davinci_dm644x()) {
        iotable_init(dm644x_io_desc, ARRAY_SIZE(dm644x_io_desc));
    } else if (cpu_is_davinci_dm6467()) {
        davinci_cpu_index = DM6467_CPU_IDX;
        iotable_init(dm646x_io_desc, ARRAY_SIZE(dm646x_io_desc));
    } else if (cpu_is_davinci_dm355()) {
        davinci_cpu_index = DM355_CPU_IDX;
    }

    /* Normally devicemaps_init() would flush caches and tlb after
     * mdesc->map_io(), but we must also do it here because of the CPU
     * revision check below.
     */

    flush_tlb_all();
    flush_cache_all();

    // 初始化各服用功能引脚(与GPIO引脚复用)

    davinci_mux_init();
    
    // 注册模块时钟,以便使用模块时申请

    davinci_clk_init();
}


io.h

/*
 * linux/include/asm-arm/arch-davinci/io.h
 *
 * Copyright (C) 2006 Texas Instruments.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */


#ifndef __ASM_ARCH_IO_H
#define __ASM_ARCH_IO_H

#include <asm/arch/hardware.h>
#include <asm/types.h>

#define IO_SPACE_LIMIT 0xffffffff

/*
 * ----------------------------------------------------------------------------
 * I/O mapping
 * ----------------------------------------------------------------------------
 */

#define IO_PHYS        0x01c00000
#define IO_VIRT        0xe1000000
#define IO_SIZE        SZ_4M

/* DM646X need to map 0x02000000-0x02400000 to 0x0e1400000-0x0e1800000*/
/* This is put in the generic section so IRAM is mapped the same between
   DaVinci and DM646X - Note that this will leave a hole for DaVinci */

#define DM646X_IO_PHYS        0x02000000        
#define DM646X_IO_VIRT        (IO_VIRT + IO_SIZE)
#define DM646X_IO_SIZE        SZ_4M

#define DAVINCI_IRAM_VIRT        (DM646X_IO_VIRT + DM646X_IO_SIZE)
                    /* after 4M of IO space */
#define DAVINCI_IRAM_SIZE        SZ_16K

/*
 * DM644X specific mappings
 */

/* DaVinci IRAM mapping */
#define DAVINCI_IRAM_BASE    0x00008000 /* ARM Internal RAM (Data) */

/* handle VLYNQ remap */
#define VLYNQ_REMOTE_PHYS        0x0C000000
#define VLYNQ_REMOTE_VIRT        DAVINCI_IRAM_VIRT + DAVINCI_IRAM_SIZE
#define VLYNQ_REMOTE_SIZE        SZ_64M

#define VLYNQ_PHYS_TO_VIRT(addr)    ((addr) - (VLYNQ_REMOTE_PHYS) + \
                        (VLYNQ_REMOTE_VIRT))
#define VLYNQ_VIRT_TO_PHYS(addr)    ((addr) + (VLYNQ_REMOTE_PHYS) - \
                        (VLYNQ_REMOTE_VIRT))

/*
 * DM646X specific mappings
 */

/* IRAM mappings */
#define DM646X_IRAM_BASE 0x00010000 /* ARM Internal RAM (Data) */

/* handle DM646X EMIF remap */
#define EMIF_CNTRL_VIRT        (DAVINCI_IRAM_VIRT + DAVINCI_IRAM_SIZE)
#define EMIF_P2V(addr)        ((emifregsovly)        \
    ((addr) - (DAVINCI_DM646X_ASYNC_EMIF_CNTRL_BASE) + (EMIF_CNTRL_VIRT)))

/*
 * cconversion functions
 */

/* IO寄存器虚拟地址和物理地址转换api。因为是线性映射的,所以转换器来很容易 */
#define io_p2v(pa) (((pa) - (IO_PHYS)) + IO_VIRT)
#define io_v2p(va) (((va) - (IO_VIRT)) + IO_PHYS)
#define IO_ADDRESS(x) io_p2v(x)

/*
 * We don't actually have real ISA nor PCI buses, but there is so many
 * drivers out there that might just work if we fake them...
 */

#define PCIO_BASE 0
#define __io(a)            ((void __iomem *)(PCIO_BASE + (a)))
#define __mem_pci(a)        (a)
#define __mem_isa(a)        (a)

#ifndef __ASSEMBLER__

/*
 * Functions to access the DaVinci IO region
 *
 * NOTE: - Use davinci_read/write[bwl] for physical register addresses
 *     - Use __raw_read/write[bwl]() for virtual register addresses
 *    - Use IO_ADDRESS(phys_addr) to convert registers to virtual addresses
 *    - DO NOT use hardcoded virtual addresses to allow changing the
 *      IO address space again if needed
  所有的指针强制类型转换中都加了volatile修饰符,防止IO地址被cache
 */

#define davinci_readb(a)    (*(volatile unsigned char *)IO_ADDRESS(a))
#define davinci_readw(a)    (*(volatile unsigned short *)IO_ADDRESS(a))
#define davinci_readl(a)    (*(volatile unsigned int *)IO_ADDRESS(a))

#define davinci_writeb(v,a)    (*(volatile unsigned char *)IO_ADDRESS(a) = (v))
#define davinci_writew(v,a)    (*(volatile unsigned short *)IO_ADDRESS(a) = (v))
#define davinci_writel(v,a)    (*(volatile unsigned int *)IO_ADDRESS(a) = (v))

/* 16 bit uses LDRH/STRH, base +/- offset_8 */
typedef struct { volatile u16 offset[256]; } __regbase16;
#define __REGV16(vaddr)        ((__regbase16 *)((vaddr)&~0xff)) \
                    ->offset[((vaddr)&0xff)>>1]
#define __REG16(paddr)        __REGV16(io_p2v(paddr))

/* 8/32 bit uses LDR/STR, base +/- offset_12 */
typedef struct { volatile u8 offset[4096]; } __regbase8;
#define __REGV8(vaddr)        ((__regbase8 *)((vaddr)&~4095)) \
                    ->offset[((vaddr)&4095)>>0]
#define __REG8(paddr)        __REGV8(io_p2v(paddr))

typedef struct { volatile u32 offset[4096]; } __regbase32;
#define __REGV32(vaddr)        ((__regbase32 *)((vaddr)&~4095)) \
                    ->offset[((vaddr)&4095)>>2]
/* FIXME: Just for compilation sake changed from __REG32 to __REG */
#define __REG(paddr)        __REGV32(io_p2v(paddr))

extern void davinci_map_common_io(void);
extern void davinci_init_common_hw(void);
#else

#define __REG(x) (*((volatile unsigned long *)io_p2v(x)))

#endif

#endif /* __ASM_ARCH_IO_H */

阅读(842) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~