/* * linux/arch/arm/mach-davinci/board-evm.c * * TI DaVinci EVM board * * 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 program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * 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. * ---------------------------------------------------------------------------- * */
/************************************************************************** * Included Files **************************************************************************/
#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/major.h> #include <linux/root_dev.h> #include <linux/dma-mapping.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/serial.h> #include <linux/usb_musb.h> #include <linux/mtd/nand.h> #include <linux/serial_8250.h> #include <linux/davinci_mmc.h> #include <linux/nand_davinci.h>
#include <asm/setup.h> #include <asm/io.h> #include <asm/mach-types.h>
#include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/flash.h> #include <asm/arch/irqs.h> #include <asm/arch/hardware.h> #include <asm/arch/edma.h> #include <linux/kgdb.h> #include <asm/arch/cpu.h> #include <asm/arch/mux.h> #include "clock.h"
/* 内核在启动的时候会运行start_kernel() , 然后它会调用体系结构相关的setup_arch(&command_line), arm体系结构在arch/arm/kernel/setup.c中, 接着初始化平台相关的设备, 但在此之前, 它必须找到这块目标板的描述结构, 所以它会先通过setup_machine,其调用lookup_machine_type(nr)来查找这个结构, 参数是由u-boot传进来的, 存储在r2中. 假设它传入的是DAVINCI_EVM的nr, lookup_machine_type(nr) 就会找到本文件中到最后定义的结构体machine_desc. start_kernel之前的linux内核启动的详细过程,可参考该文章http://blog.csdn.net/gates84/archive/2007/01/15/1483979.aspx */
/************************************************************************** * Definitions **************************************************************************/ #define DAVINCI_UART_CLK 27000000 // 串口时钟,与输入的晶振频率相同
/* * dm644x平台采用8250兼容串口,该数据结构定义了串口的硬件资源,将填充在其platform_device结构体中, * 即下面的serial_device中。在该platform_devic被注册后,如果其相关的驱动被注册,则会自动找到它, * 并可调用其中的资源。plat_serial8250_port定义在include/linux/serial_8250.h文件中 */ static struct plat_serial8250_port serial_platform_data[] = { { .membase = (char *)IO_ADDRESS(DAVINCI_UART0_BASE), // 串口0寄存器开始处的虚拟地址是IO_ADDRESS(0x01C20000) .mapbase = (unsigned long)DAVINCI_UART0_BASE, // 串口0寄存器开始处的实地址是0x01C20000 .irq = IRQ_UARTINT0, // 串口0的中断号是40 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, .iotype = UPIO_MEM32, .regshift = 2, .uartclk = DAVINCI_UART_CLK, // 串口时钟频率是27MHz }, { .flags = 0, }, };
/* 见上述解释。platform_device定义在include/linux/device.h文件中 * 一般platform_device在系统启动的时候就注册了,而其相应到驱动platform_driver或device_driver可在模块中加载。 * http://hi.baidu.com/zengzhaonong/blog/item/440bb91e57e5251a413417d9.html 有关于platform_device结构体的详细解释 */ static struct platform_device serial_device = { .name = "serial8250", // 这个名字很重要,与对应驱动中的机构体device_driver中的.name相同,其被驱动模块用来查找设备 .id = 0, // 实例名后缀为0 .dev = { .platform_data = serial_platform_data, // 设备的私有数据或资源 }, };
/* 该数据结构定义了USB的私有数据,主要是usb的类型和功能,musb_hdrc_platform_data定义在include/linux/device.h文件中 */ static struct musb_hdrc_platform_data usb_data[] = { { #if defined(CONFIG_USB_MUSB_OTG) /* OTG requires a Mini-AB connector */ .mode = MUSB_OTG, // OTG类型的usb模块,既可以作usb设备也可以作主机usb使用 #elif defined(CONFIG_USB_MUSB_PERIPHERAL) .mode = MUSB_PERIPHERAL, #elif defined(CONFIG_USB_MUSB_HOST) // usb设备 .mode = MUSB_HOST, // 主机usb,类似于电脑的usb功能 #endif .set_vbus = NULL, /* irlml6401 switches 5V */ .power = 255, /* sustains 3.0+ Amps (!) */ .potpgt = 4, /* ~8 msec */ .multipoint = 1, // 1个收发端口 }, /* Need Multipoint support */ };
/* 该数据结构定义了USB的硬件资源, resource定义在include/linux/ioport.h文件中 */ static struct resource usb_resources[] = { { /* physical address */ .start = DAVINCI_USB_OTG_BASE, // USB_OTG寄存器起始处的实地址是0x01C20000 .end = DAVINCI_USB_OTG_BASE + 0x5ff, // USB_OTG寄存器末尾处的实地址是0x01C20000 .flags = IORESOURCE_MEM, // 标识为IO地址资源 }, { .start = IRQ_USBINT, // USB_OTG中断号是12 .flags = IORESOURCE_IRQ, // 标识为中断资源 }, };
static u64 usb_dmamask = DMA_32BIT_MASK;
/* usb的platform_device结构体,用于注册usb设备*/ static struct platform_device usb_dev = { .name = "musb_hdrc", // 与对应驱动中的名字相同,用于绑定驱动 .id = -1, // -1表示只有一个实例,无数字后缀 .dev = { .platform_data = usb_data, // USB的私有数据 .dma_mask = &usb_dmamask, // 32位的dma .coherent_dma_mask = DMA_32BIT_MASK, }, .resource = usb_resources, // USB的硬件资源 .num_resources = ARRAY_SIZE(usb_resources), };
/* 返回cpu的类型:DaVinci EVM*/ /************************************************************************** * Public Functions **************************************************************************/ int cpu_type(void) { return MACH_TYPE_DAVINCI_EVM; }
/* 串口初始化,主要的工作是打开串口时钟,定义在arch/arm/mach-davinci/serial.c文件中*/ extern void davinci_serial_init(struct platform_device *pdev);
/*如果在menuconfig中配置了使用nand启动系统,则下面的的代码将会被编译。 * mtd_partition定义在include/linux/mtd/partitions.h文件中 */ #if defined (CONFIG_MTD_NAND_DAVINCI) || defined(CONFIG_MTD_NAND_DAVINCI_MODULE) static struct mtd_partition nand_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ { .name = "bootloader", // bootloader,一般使用u-boot .offset = 0, // 从mtd分区开始地址的偏移量是0 .size = SZ_256K, // 分区大小是256K .mask_flags = 0, /* force read-only */ // 只读 }, /* bootloader params in the next sector */ { .name = "params", // 存放bootloader的参数 .offset = MTDPART_OFS_APPEND, // 从上一分区(bootloader分区)开始 .size = SZ_128K, .mask_flags = MTD_WRITEABLE, /* force read-only */ // 可写 }, /* kernel */ { .name = "kernel", // 存放内核 .offset = MTDPART_OFS_APPEND, .size = SZ_4M, .mask_flags = 0, }, /* file system */ { .name = "filesystem", // 存放文件系统 .offset = MTDPART_OFS_APPEND, .size = MTDPART_SIZ_FULL, // 整个分区的剩余存储空间 .mask_flags = 0, } };
/* nand platform device 私有数据,用于描述nand flash banks * nand_davinci_platform_data定义在include/linux/nand_davinci.h文件中 */ static struct nand_davinci_platform_data nand_data = { .options = 0, .eccmode = NAND_ECC_HW3_512, // 校验模式 .cle_mask = 0x10, .ale_mask = 0x08, .bbt_td = NULL, .bbt_md = NULL, .parts = nand_partitions, // 分区信息 .nr_parts = ARRAY_SIZE(nand_partitions), };
/* 定义了nand设备使用的硬件资源 */ static struct resource nand_resources[] = { [0] = { /* First memory resource is AEMIF control registers */ .start = DM644X_ASYNC_EMIF_CNTRL_BASE, .end = DM644X_ASYNC_EMIF_CNTRL_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, }, [1] = { /* Second memory resource is NAND I/O window */ .start = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE, .end = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_16K - 1, .flags = IORESOURCE_MEM, }, };
/* nand platform_device ,用于注册nand device到platform总线 */ static struct platform_device nand_device = { .name = "nand_davinci", .id = 0, .dev = { .platform_data = &nand_data, },
.num_resources = ARRAY_SIZE(nand_resources), .resource = nand_resources, }; #endif
/*如果在menuconfig中配置了使用nor启动系统,则下面的的代码将会被编译。 * mtd_partition定义在include/linux/mtd/partitions.h文件中 */ #if defined (CONFIG_MTD_DAVINCI_NOR) || defined(CONFIG_MTD_DAVINCI_NOR_MODULE) static struct mtd_partition davinci_evm_nor_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ { .name = "bootloader", .offset = 0, .size = SZ_128K, .mask_flags = 0 }, /* bootloader params in the next sector */ { .name = "params", .offset = MTDPART_OFS_APPEND, .size = SZ_128K, .mask_flags = MTD_WRITEABLE, /* force read-only */ }, /* kernel */ { .name = "kernel", .offset = MTDPART_OFS_APPEND, .size = SZ_4M, .mask_flags = 0 }, /*cramfs file system */ { .name = "cramfs", .offset = MTDPART_OFS_APPEND, .size = SZ_2M, .mask_flags = 0 }, /* jffs2 file system */ { .name = "jffs2", // jffs2文件分区 .offset = MTDPART_OFS_APPEND, .size = MTDPART_SIZ_FULL, .mask_flags = 0 } };
/* nor platform device 私有数据,用于描述nor flash banks * flash_platform_data定义在include/asm-arm/mach/flash.h文件中 */ static struct flash_platform_data davinci_evm_flash_data = { .map_name = "cfi_probe", .width = 2, .parts = davinci_evm_nor_partitions, .nr_parts = ARRAY_SIZE(davinci_evm_nor_partitions), };
/* 定义了nor设备使用的硬件资源 */ /* NOTE: CFI probe will correctly detect flash part as 32M, but EMIF ;* limits addresses to 16M, so using addresses past 16M will wrap */ static struct resource davinci_evm_flash_resource = { .start = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE, .end = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_16M - 1, .flags = IORESOURCE_MEM, };
/* nor platform_device ,用于注册nor device到platform总线 */ static struct platform_device davinci_evm_flash_device = { .name = "nor_davinci", .id = 0, .dev = { .platform_data = &davinci_evm_flash_data, },
.num_resources = 1, .resource = &davinci_evm_flash_resource, }; #endif
/* 定义了mmc设备使用的硬件资源 */ #if defined(CONFIG_MMC_DAVINCI) || defined(CONFIG_MMC_DAVINCI_MODULE) static struct resource mmc0_resources[] = { [0] = { /* registers */ // 寄存器 .start = DAVINCI_MMC_SD_BASE, .end = DAVINCI_MMC_SD_BASE + SZ_1K - 1, .flags = IORESOURCE_MEM, }, [1] = { /* interrupt */ // 中断号 .start = IRQ_MMCINT, .end = IRQ_MMCINT, .flags = IORESOURCE_IRQ, }, [2] = { /* dma rx */ // dma 接收寄存器 .start = DAVINCI_DMA_MMCRXEVT, .end = DAVINCI_DMA_MMCRXEVT, .flags = IORESOURCE_DMA, }, [3] = { /* dma tx */ // dma 发送寄存器 .start = DAVINCI_DMA_MMCTXEVT, .end = DAVINCI_DMA_MMCTXEVT, .flags = IORESOURCE_DMA, }, };
/* mmc platform device 私有数据,用于描述mmc flash banks * davinci_mmc_platform_data定义在include/linux/davinci_mmc.h文件中 */ static struct davinci_mmc_platform_data mmc0_platform_data = { .mmc_clk = "MMCSDCLK0", // 用于获mmc取时钟 .rw_threshold = 32, .use_4bit_mode = 1, };
/* mmc platform_device ,用于注册mmc0_device到platform总线 */ static struct platform_device mmc0_device = { .name = "mmc", .id = 0, .dev = { .platform_data = &mmc0_platform_data, },
.num_resources = ARRAY_SIZE(mmc0_resources), .resource = mmc0_resources, };
/* 开启mmc模块的电源*/ static void setup_mmc(void) { board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_MMC_SD0, 1); } #else #define setup_mmc() #endif
/* platform_device指针数组 */ static struct platform_device *davinci_evm_devices[] __initdata = { &serial_device, &usb_dev, #if defined (CONFIG_MTD_NAND_DAVINCI) || defined(CONFIG_MTD_NAND_DAVINCI_MODULE) &nand_device, #endif
#if defined (CONFIG_MTD_DAVINCI_NOR) || defined(CONFIG_MTD_DAVINCI_NOR_MODULE) &davinci_evm_flash_device, #endif
#if defined(CONFIG_MMC_DAVINCI) || defined(CONFIG_MMC_DAVINCI_MODULE) &mmc0_device, #endif };
/* 用于设置fiq,irq 的优先级*/ /* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */ static const u8 dm644x_default_priorities[DAVINCI_N_AINTC_IRQ] = { [IRQ_VDINT0] = 2, [IRQ_VDINT1] = 6, [IRQ_VDINT2] = 6, [IRQ_HISTINT] = 6, [IRQ_H3AINT] = 6, [IRQ_PRVUINT] = 6, [IRQ_RSZINT] = 6, [IRQ_VFOCINT] = 7, [IRQ_VENCINT] = 6, [IRQ_ASQINT] = 6, [IRQ_IMXINT] = 6, [IRQ_VLCDINT] = 6, [IRQ_USBINT] = 4, [IRQ_EMACINT] = 4, [IRQ_IEEE1394INT] = 7, [IRQ_IEEE1394WK] = 7, [IRQ_CCINT0] = 5, /* dma */ [IRQ_CCERRINT] = 5, /* dma */ [IRQ_TCERRINT0] = 5, /* dma */ [IRQ_TCERRINT] = 5, /* dma */ [IRQ_PSCINT] = 7, [21] = 7, [IRQ_IDE] = 4, [IRQ_HPIINT] = 7, [IRQ_MBXINT] = 7, [IRQ_MBRINT] = 7, [IRQ_MMCINT] = 7, [IRQ_SDIOINT] = 7, [IRQ_HPIINT] = 7, [IRQ_DDRINT] = 7, [IRQ_AEMIFINT] = 7, [IRQ_VLQINT] = 4, [IRQ_TINT0_TINT12] = 2, /* clockevent */ [IRQ_TINT0_TINT34] = 2, /* clocksource */ [IRQ_TINT1_TINT12] = 7, /* DSP timer */ [IRQ_TINT1_TINT34] = 7, /* system tick */ [IRQ_PWMINT0] = 7, [IRQ_PWMINT1] = 7, [IRQ_PWMINT2] = 7, [IRQ_I2C] = 3, [IRQ_UARTINT0] = 3, [IRQ_UARTINT1] = 3, [IRQ_UARTINT2] = 3, [IRQ_SPINT0] = 3, [IRQ_SPINT1] = 3, [45] = 7, [IRQ_DSP2ARM0] = 4, [IRQ_DSP2ARM1] = 4, [IRQ_GPIO0] = 7, [IRQ_GPIO1] = 7, [IRQ_GPIO2] = 7, [IRQ_GPIO3] = 7, [IRQ_GPIO4] = 7, [IRQ_GPIO5] = 7, [IRQ_GPIO6] = 7, [IRQ_GPIO7] = 7, [IRQ_GPIOBNK0] = 7, [IRQ_GPIOBNK1] = 7, [IRQ_GPIOBNK2] = 7, [IRQ_GPIOBNK3] = 7, [IRQ_GPIOBNK4] = 7, [IRQ_COMMTX] = 7, [IRQ_COMMRX] = 7, [IRQ_EMUINT] = 7, };
/* davinci平台初始化,主要是开启各模块到电源。dm644x平台到电源管理是分模块到,不使用到时候关掉,可降低功耗。 * 所以需要使用哪个模块,必须在程序中打开,打开后才能设置相应的寄存器。 */ static void board_init(void) { board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_VLYNQ, 1);
board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_VPSSMSTR, 1); board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_VPSSSLV, 1); board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TPCC, 1); board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TPTC0, 1); board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TPTC1, 1); board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_GPIO, 1);
/* Turn on WatchDog timer LPSC. Needed for RESET to work */ board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TIMER2, 1);
davinci_serial_init(&serial_device); // 初始化串口 }
/* dm644x平台许多功能模块到引脚是gpio复用到,功能引脚和gpio脚是互斥的 , * 该函数用来设置这些引脚. */ static void dm644x_setup_pinmux(unsigned int id) { switch (id) { case DAVINCI_LPSC_ATA: davinci_cfg_reg(DM644X_HDIREN); davinci_cfg_reg(DM644X_ATAEN); break; case DAVINCI_LPSC_MMC_SD0: /* VDD power manipulations are done in U-Boot for CPMAC * so applies to MMC as well */ /*Set up the pull register for MMC */ DAVINCI_VDD3P3V_PWDN = 0x0; davinci_cfg_reg(DM644X_MSTK); break; case DAVINCI_LPSC_I2C: davinci_cfg_reg(DM644X_I2C); break; case DAVINCI_LPSC_McBSP0: davinci_cfg_reg(DM644X_MCBSP0); break; case DAVINCI_LPSC_PWM0: davinci_cfg_reg(DM644X_PWM0); break; case DAVINCI_LPSC_PWM1: davinci_cfg_reg(DM644X_PWM1); break; case DAVINCI_LPSC_PWM2: davinci_cfg_reg(DM644X_PWM2); break; case DAVINCI_LPSC_VLYNQ: davinci_cfg_reg(DM644X_VLINQEN); davinci_cfg_reg(DM644X_VLINQWD); break; default: break;
} }
/* 用于设置各中断的优先级, * 该指针定义在arch/arm/mach-davinci/irq.c中 */ extern const u8 *davinci_def_priorities;
/* 初始化IO口,开启各模块电源 */ static void __init davinci_map_io(void) { davinci_pinmux_setup = dm644x_setup_pinmux; davinci_def_priorities = dm644x_default_priorities; davinci_map_common_io();
#ifdef CONFIG_KGDB_8250 early_serial_setup((struct uart_port *) &serial_platform_data[kgdb8250_ttyS]); kgdb8250_add_platform_port(kgdb8250_ttyS, &serial_platform_data[kgdb8250_ttyS]); #endif /* Initialize the DaVinci EVM board settigs */ board_init (); }
/* 初始化平台irq,该函数在arch/arm/mach-davinci/irq.c中定义 */ int __init davinci_gpio_irq_setup(void);
void davinci_msp430_deep_sleep(void) { unsigned int icstr = DAVINCI_I2C_BASE + 0x08; unsigned int icsar = DAVINCI_I2C_BASE + 0x1C; unsigned int iccnt = DAVINCI_I2C_BASE + 0x14; unsigned int icdxr = DAVINCI_I2C_BASE + 0x20; unsigned int icmdr = DAVINCI_I2C_BASE + 0x24; u32 cnt = 0, buflen = 2; char rtcdata[2] = { 2, 8 }; char *buffer = rtcdata;
/* check for bus busy */ while (readl(icstr) & 0x1000) ;
/* configure the count register */ writel(2, iccnt);
/* set the salve address */ writel(0x23, icsar);
/* Take I2C out of reset, configure it as master, * set the start bit, stop bit and enable the * transmitter */ writel(0x2e20, icmdr);
while (cnt < buflen) { if ((readl(icstr) & 0x0010) != 0) { writel(*buffer, icdxr); ++buffer; ++cnt; } } }
/* 该驱动的初始化函数 */ static __init void evm_init(void) { #if defined (CONFIG_MTD_DAVINCI_NOR) || defined(CONFIG_MTD_DAVINCI_NOR_MODULE) #if defined(CONFIG_BLK_DEV_DAVINCI) || defined(CONFIG_BLK_DEV_DAVINCI_MODULE) #warning IDE and NOR flash are are pin-muxed. Disable IDE or NOR. printk(KERN_WARNING "WARNING: both IDE and NOR flash are enabled, " "but are pin-muxed.\n\t Disable IDE or NOR support.\n"); #endif #if defined (CONFIG_MTD_NAND_DAVINCI) || defined(CONFIG_MTD_NAND_DAVINCI_MODULE) #warning NAND and NOR flash are are pin-muxed. Disable NAND or NOR. printk(KERN_WARNING "WARNING: both NAND and NOR flash are enabled, " "but are pin-muxed.\n\t Disable NAND or NOR support.\n"); #endif #endif
#if defined(CONFIG_BLK_DEV_DAVINCI) || defined(CONFIG_BLK_DEV_DAVINCI_MODULE) #if defined (CONFIG_MTD_NAND_DAVINCI) || defined(CONFIG_MTD_NAND_DAVINCI_MODULE) #warning IDE and NAND flash are are pin-muxed. Disable IDE or NAND. printk(KERN_WARNING "WARNING: both IDE and NAND flash are enabled, " "but are pin-muxed.\n\t Disable IDE or NAND support.\n"); #endif #endif pm_power_off = davinci_msp430_deep_sleep; setup_mmc(); davinci_gpio_irq_setup(); platform_add_devices(davinci_evm_devices, // 注册所有已定义的platform_device ARRAY_SIZE(davinci_evm_devices)); }
/* 初始化ARM中断控制寄存器函数 * 在arch/arm/mach-davinci/irq.c文件中定义 */ extern void davinci_irq_init(void);
/* 系统定时器结构体,用于初始化平台的定时器 */ extern struct sys_timer davinci_timer;
/* 定义平台属性,MACHINE_START是个宏定义,用于填充平台描述符结构体machine_desc * 它们都在include/asm-arm/mach-davinci/arch.h中定义 * */ MACHINE_START(DAVINCI_EVM, "DaVinci EVM") MAINTAINER("Texas Instruments, PSP Team") BOOT_MEM(DAVINCI_DDR_BASE, IO_PHYS, IO_VIRT) // 定义了DDR2的起始物理地址,IO寄存器的起始物理地址以及IO寄存器的到虚拟地址 BOOT_PARAMS(0x80000100) // bootloader存放启动参数到起始物理地址,系统启动会从中读取各种参数 MAPIO(davinci_map_io) // IO模块初始化,定义在本文件中 INITIRQ(davinci_irq_init) .timer = &davinci_timer, INIT_MACHINE(evm_init) MACHINE_END EXPORT_SYMBOL(cpu_type)
|