Davinci DM6446 Linux 内核分析——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 */

你可能感兴趣的:(linux,内核,Davinci,io.c,DM6446)