linux内核(二)内核移植(DM365-DM368开发攻略——linux-2.6.32的移植)
一、介绍linux-2.6.32:
- Rules.make第45行,LINUXKERNEL_INSTALL_DIR=$(DVSDK_INSTALL_DIR)/psp/linux-2.6.32.17,很明显我们把内核名字改成linux-2.6.32.17,原来解压安装出来的名字太长了,所以要在Rules.make第45行改一下;
- Makefile是编译的脚本,TI把整个DVSDK4.02的开发环境统一整合在一起,体现在这个Makefile,看完这个Makefile,就应该知道如何编译整个DVSDK里所有的软件包,内核编译的命令见143行开始;
- 在dvsdk_dm368_4_02_00_06\目录下使用make linux,make linux_config, make linux_clean等命令编译内核;
二、开始移植:从删除多余的文件夹和文件开始
先看删除前后的源码大小对比,当然还有些可以接着删。
1,进入文件夹linux-2.6.32.17-psp03.01.01.39\arch\arm\configs,只保留davinci_dm365_defconfig。
2,删除非ARM芯片平台的处理器
进入dvsdk_dm368_4_02_00_06/psp/linux-2.6.32.17/arch,保留arm,um,x86三个文件夹,其他文件删除掉;
进入dvsdk_dm368_4_02_00_06/psp/linux-2.6.32.17/arch/x86文件夹,只保留include和mm文件夹,和几个文件,其他文件夹删除掉
dvsdk_dm368_4_02_00_06/psp/linux-2.6.32.17/arch/arm文件夹,保留mach-davinci文件夹和保留下图的文件夹和文件,其他带mach-删除吧,占空间,又占备份时压缩的时间,
3、修改dvsdk_dm368_4_02_00_06/psp/linux-2.6.32.17/arch/arm/Makefile
第176行到第184统统使用”#”给屏蔽掉,不要这些芯片平台;
4、修改dvsdk_dm368_4_02_00_06/psp/linux-2.6.32.17/arch/arm/Kconfig
从第707行开始,一直到793行,这些全部使用“#”给屏蔽掉,保留第795行的source "arch/arm/mach-davinci/Kconfig";
然后继续把第797到805行使用“#”给屏蔽掉;
经过上面的删除,使用tar jcf 或 tar zcf压缩的linux-2.6.32.17降到51M,比没有删除的减小近一半的大小;我们追求简洁,思路清晰;其实还有很多地方可以删除的,大家慢慢体会,包括include,driver里边的老掉牙的设备,这里就不啰嗦了;删除后记得把对应的Kconfig和Makefile给屏蔽掉;
三、开始从内核配置
使用make linux_config命令,这样就看到熟悉的内核配置界面。
图-11
图-12
四、分析和修改代码:
1、mach-davinci\board-dm365-evm.c
static struct mtd_partition davinci_nand_partitions[] = { { /* UBL (a few copies) plus U-Boot */ .name = "bootloader", .offset = 0x80000, .size = 3 * NAND_BLOCK_SIZE, .mask_flags =0, /* tongye:.mask_flags = MTD_WRITEABLE, *//* force read-only */ }, { /* U-Boot environment */ .name = "params", .offset = 0xe0000, .size = 1 * NAND_BLOCK_SIZE, .mask_flags = 0, }, { .name = "kernel", .offset = 0x100000, .size = SZ_4M+SZ_512K, .mask_flags = 0, }, { .name = "basefs", .offset = 0x100000+SZ_4M+SZ_512K, .size = SZ_32M-SZ_4M, .mask_flags = 0, /* tongye:28M-byte for ramdisk,cramfs,squashfs rootfs*/ }, { .name = "userfs", .offset = 0x100000+SZ_32M+SZ_512K, .size = SZ_64M+SZ_16M, .mask_flags = 0, /*tongye:80M-byte for jffs2,yaffs2 rootfs*/ }, { .name = "userdata", .offset = SZ_64M+SZ_32M+SZ_16M+SZ_1M+SZ_512K, .size = 0x8000000-SZ_64M-SZ_32M-SZ_16M-SZ_1M-SZ_512K, .mask_flags = 0, } /* two blocks with bad block table (and mirror) at the end */ };
UBL的代码放在0x20000~0x40000的位置,一般NAND FLASH前面5个BLOCK出现坏块的几率非常小,在产品中一般很少去维护更新UBL,所以没有把UBL单独分一个分区;而其他空间出现坏块的几率比较大,所以给U-BOOT分3~4个BLOCK够用了,内核分5M-BYTE也够用,而U-BOOT参数分1~2个BLOCK,本公司直接放到0x60000~0x80000的空间也可以,没有规定;后面的文件系统分区就根据你裁剪的文件系统、文件系统的类型进行大小分区;
static struct i2c_board_info i2c_info[] = { /* { I2C_BOARD_INFO("dm365evm_keys", 0x25), }, { I2C_BOARD_INFO("24c256", 0x50), .platform_data = &eeprom_info, }, */ { I2C_BOARD_INFO("tlv320aic3x", 0x18), }, { I2C_BOARD_INFO("ths7303", 0x2c), }, /*{ I2C_BOARD_INFO("PCA9543A", 0x73), },*/ { I2C_BOARD_INFO("pcf8563", 0x51), }, };
上面这个结构就是看看你的I2C总线带什么样的设备,根据你的I2C设备地址,添加到这里,这样才能调用到设备初始化函数;从上面的修改看出,我们的板子不需要AT24C256这些EEPROM芯片,可以干掉;
static void dm365evm_reset_imager(int rst) { u8 val; //tongye #if 0 val = __raw_readb(cpld + CPLD_POWER) | BIT(3) | BIT(11) | BIT(19) | BIT(27); __raw_writeb(val, (cpld + CPLD_POWER)); val = __raw_readb(cpld + CPLD_MUX) | BIT(6) | BIT(14) | BIT(22) | BIT(30); __raw_writeb(val, (cpld + CPLD_MUX)); /* Reset bit6 of CPLD_IMG_DIR2 */ val = __raw_readb(cpld + CPLD_IMG_DIR2) & ~BIT(6); __raw_writeb(val, (cpld + CPLD_IMG_DIR2)); /* Set bit5 of CPLD_IMG_MUX5 */ val = __raw_readb(cpld + CPLD_IMG_MUX5) | BIT(5); __raw_writeb(val, (cpld + CPLD_IMG_MUX5)); /* Reset bit 0 of CPLD_IMG_MUX5 */ val = __raw_readb(cpld + CPLD_IMG_MUX5) & ~BIT(0); __raw_writeb(val, (cpld + CPLD_IMG_MUX5)); #endif /** * Configure GPIO40 to be output and high. This has dependency on MMC1 */ #if 1 davinci_cfg_reg(DM365_PWM3_G85); davinci_cfg_reg(DM365_PWM3_G86); gpio_request(85, "sensor_reset"); gpio_request(86, "sensor_standby"); gpio_direction_output(85, 0); gpio_direction_output(86, 0); gpio_set_value(85,1); gpio_set_value(86,1); mdelay(15); 头文件要加上#include <linux/delay.h> gpio_set_value(85,0); gpio_set_value(86,0); mdelay(25); gpio_set_value(85,1); gpio_set_value(86,1); mdelay(25); #else davinci_cfg_reg(DM365_GPIO40); gpio_request(40, "sensor_reset"); if (rst) gpio_direction_output(40, 1); else gpio_direction_output(40, 0); #endif }
上面的函数修改:我们不需要CPLD,所以屏蔽掉,我们直接使用GPIO控制MT9P031 SENSOR的复位和STANDBY信号;
static struct vpfe_subdev_info vpfe_sub_devs[] = { { .module_name = "tvp5158", .grp_id = VPFE_SUBDEV_TVP5146, .num_inputs = ARRAY_SIZE(tvp5158_inputs), .inputs = tvp5158_inputs, .routes = tvp5158_routes, .can_route = 1, .ccdc_if_params = { .if_type = VPFE_BT656, .hdpol = VPFE_PINPOL_POSITIVE, .vdpol = VPFE_PINPOL_POSITIVE, }, .board_info = { I2C_BOARD_INFO("tvp5158", 0x5B), .platform_data = &tvp5158_pdata, }, }, { .module_name = "tvp7002", .grp_id = VPFE_SUBDEV_TVP7002, .num_inputs = ARRAY_SIZE(tvp7002_inputs), .inputs = tvp7002_inputs, .ccdc_if_params = { .if_type = VPFE_BT1120, .hdpol = VPFE_PINPOL_POSITIVE, .vdpol = VPFE_PINPOL_POSITIVE, }, .board_info = { I2C_BOARD_INFO("tvp7002", 0x5c), .platform_data = &tvp7002_pdata, }, }, { .module_name = "ths7353", .grp_id = VPFE_SUBDEV_TVP7002, .board_info = { I2C_BOARD_INFO("ths7353", 0x2e), }, }, { .module_name = "mt9p031", .is_camera = 1, .grp_id = VPFE_SUBDEV_MT9P031, .num_inputs = ARRAY_SIZE(mt9p031_inputs), .inputs = mt9p031_inputs, .ccdc_if_params = { .if_type = VPFE_RAW_BAYER, .hdpol = VPFE_PINPOL_POSITIVE, .vdpol = VPFE_PINPOL_POSITIVE, }, .board_info = { I2C_BOARD_INFO("mt9p031", 0x48), /* this is for PCLK rising edge */ .platform_data = (void *)1, }, } };
TI的DM368开发板同时支持TVP5146、TVP7002、MT9P031;TVP5146代表标清复合视频输入采集芯片(D1格式),TVP7002代表复合视频YPbPr的高清输入采集芯片,MT9P031代表500万像素的SENSOR采集;
/* Set the input mux for TVP7002/TVP5146/MTxxxx sensors */ static int dm365evm_setup_video_input(enum vpfe_subdev_id id) { const char *label; u8 mux, resets; //Jingbo /////mux = __raw_readb(cpld + CPLD_MUX); ////mux &= ~CPLD_VIDEO_INPUT_MUX_MASK; ////resets = __raw_readb(cpld + CPLD_RESETS); switch (id) { case VPFE_SUBDEV_TVP5146: mux |= CPLD_VIDEO_INPUT_MUX_TVP5146; resets &= ~BIT(0); label = "tvp5158 SD"; dm365evm_reset_imager(0); break; case VPFE_SUBDEV_MT9P031: mux |= CPLD_VIDEO_INPUT_MUX_IMAGER; resets |= BIT(0); /* Put TVP5146 in reset */ label = "HD imager"; dm365evm_reset_imager(1); /* Switch on pca9543a i2c switch */ ////if (have_imager()) ////dm365evm_enable_pca9543a(1); break; case VPFE_SUBDEV_TVP7002: resets &= ~BIT(2); mux |= CPLD_VIDEO_INPUT_MUX_TVP7002; label = "tvp7002 HD"; break; default: return 0; } ////__raw_writeb(mux, cpld + CPLD_MUX); ////__raw_writeb(resets, cpld + CPLD_RESETS); pr_info("EVM: switch to %s video input\n", label); return 0; }
上面的函数去掉CPLD的东西,这个视频采集芯片的选择是和U-BOOT的参数一一对应的,在U-BOOT bootargs的参数里,加入davinci_capture.device_type=0表示使用TVP5146采集,davinci_capture.device_type=1表示使用MT9P031采集,davinci_capture.device_type=2表示使用TVP7002采集,内核读取U-BOOT的参数,会在初始化确定是否调用什么样的采集芯片驱动;所以我们在内核配置的时候,可以同时选上三种芯片;
static void __init evm_init_i2c(void) { davinci_init_i2c(&i2c_pdata); #if 0 if (have_imager()) i2c_add_driver(&pca9543a_driver); #endif i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info)); }
这个pca9543a I2C切换芯片我们不需要;
static void __init evm_init_cpld(void) { u8 mux, resets; const char *label; struct clk *aemif_clk; struct davinci_soc_info *soc_info = &davinci_soc_info; /* Make sure we can configure the CPLD through CS1. Then * leave it on for later access to MMC and LED registers. */ aemif_clk = clk_get(NULL, "aemif"); if (IS_ERR(aemif_clk)) return; clk_enable(aemif_clk); #if 0 if (request_mem_region(DM365_ASYNC_EMIF_DATA_CE1_BASE, SECTION_SIZE, "cpld") == NULL) goto fail; cpld = ioremap(DM365_ASYNC_EMIF_DATA_CE1_BASE, SECTION_SIZE); if (!cpld) { release_mem_region(DM365_ASYNC_EMIF_DATA_CE1_BASE, SECTION_SIZE); fail: pr_err("ERROR: can't map CPLD\n"); clk_disable(aemif_clk); return; } /* External muxing for some signals */ mux = 0; /* Read CPLD version number */ soc_info->cpld_version = __raw_readb(cpld + CPLD_VERSION); /* Read SW5 to set up NAND + keypad _or_ OneNAND (sync read). * NOTE: SW4 bus width setting must match! */ if ((__raw_readb(cpld + CPLD_SWITCH) & BIT(5)) == 0) { /* external keypad mux */ mux |= BIT(7); platform_add_devices(dm365_evm_nand_devices, ARRAY_SIZE(dm365_evm_nand_devices)); } else { /* no OneNAND support yet */ } /* Leave external chips in reset when unused. */ resets = BIT(3) | BIT(2) | BIT(1) | BIT(0); /* ... and ENET ... */ dm365evm_emac_configure(); soc_info->emac_pdata->phy_mask = DM365_EVM_PHY_MASK; soc_info->emac_pdata->mdio_max_freq = DM365_EVM_MDIO_FREQUENCY; resets &= ~BIT(3); /* ... and AIC33 */ resets &= ~BIT(1); /* Static video input config with SN74CBT16214 1-of-3 mux: * - port b1 == tvp7002 (mux lowbits == 1 or 6) * - port b2 == imager (mux lowbits == 2 or 7) * - port b3 == tvp5146 (mux lowbits == 5) * * Runtime switching could work too, with limitations. */ if (have_imager()) { label = "HD imager"; mux |= CPLD_VIDEO_INPUT_MUX_IMAGER; /* externally mux MMC1 to imager */ mux |= BIT(6); dm365evm_reset_imager(1); } else { /* we can use MMC1 ... */ dm365evm_mmc_configure(); davinci_setup_mmc(1, &dm365evm_mmc_config); if (have_tvp7002()) { mux |= CPLD_VIDEO_INPUT_MUX_TVP7002; resets &= ~BIT(2); label = "tvp7002 HD"; } else { /* default to tvp5146 */ mux |= CPLD_VIDEO_INPUT_MUX_TVP5146; resets &= ~BIT(0); label = "tvp5158 SD"; dm365evm_reset_imager(0); } } __raw_writeb(mux, cpld + CPLD_MUX); __raw_writeb(resets, cpld + CPLD_RESETS); #else platform_add_devices(dm365_evm_nand_devices, ARRAY_SIZE(dm365_evm_nand_devices)); /* ... and ENET ... */ dm365evm_emac_configure(); soc_info->emac_pdata->phy_mask = DM365_EVM_PHY_MASK; soc_info->emac_pdata->mdio_max_freq = DM365_EVM_MDIO_FREQUENCY; //if (have_imager()) { dm365evm_reset_imager(1); //pr_info("EVM: reset mt9p031 imager\n"); } //pr_info("EVM: %s video input\n", label); #endif /* REVISIT export switches: NTSC/PAL (SW5.6), EXTRA1 (SW5.2), etc */ }
static __init void dm365_evm_init(void) { dm365evm_gpio_configure(); //tongye:copy it here evm_init_i2c(); davinci_serial_init(&uart_config); dm365evm_emac_configure(); dm365evm_usb_configure(); davinci_setup_mmc(0, &dm365evm_mmc_config); /* maybe setup mmc1/etc ... _after_ mmc0 */ evm_init_cpld(); dm365_init_asp(&dm365_evm_snd_data); //dm365_init_rtc(); //dm365_init_ks(&dm365evm_ks_data); //dm365_init_spi0(BIT(0), dm365_evm_spi_info, //ARRAY_SIZE(dm365_evm_spi_info)); //dm365_init_tsc2004(); dm365evm_gpio_configure(); }
这个函数就是对MMC/SD、USB、等接口进行初始化了,tsc2004这个是触摸屏的芯片,dm365evm_gpio_configure()里边我们添加了很多GPIO的初始值定义;
2、修改mach-davinci\dm365.c
大部分转自:https://blog.csdn.net/kylin_fire_zeng/article/details/42082343