Linux内核移植与分析

一、linux内核的编译

(1)安装lzop库
sudo apt-get install lzop
(2)编译脚本
#!/bin/sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean #注意会清掉.config
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig #可选
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16
(3)文件源
arch/arm/configs目录下是各种开发板的xxx_defconfig文件
arch/arm/boot/dts目录下是各种开发板的dts、dtsi文件和编译出来的dtb文件
arch/arm/boot目录下保存编译出来的Image和zImage镜像文件
#为了方便编译,可以在顶层MAKEFILE文件指定ARCH和CROSS_COMPILE
#修改内容如下
ARCH		?= arm
CROSS_COMPILE	?= arm-linux-gnueabihf-

二、linux内核的移植

(1)添加配置文件
cd arch/arm/configs
cp imx_v7_mfg_defconfig imx_ht_defconfig #mfg可以用于mfgtools烧录
(2)添加设备树文件
cd arch/arm/boot/dts
cp imx6ull-14x14-evk.dts imx6ull-ht.dts
#修改arch/arm/boot/dts/Makefile添加编译项
dtb-$(CONFIG_SOC_IMX6ULL) +=下添加
imx6ull-ht.dtb
(3)相关驱动修改
(1)调频
make menuconfig 
CPU Power Management
-> CPU Frequency scaling
-> CPU Frequency scaling
-> Default CPUFreq governor
选择performance这样CPU始终处于最高频
(2)使能8线EMMC驱动

linux内核驱动里面的EMMC默认是4线模式的,4线模式的没有8线模式的速度快。但linux设备文件中也配置了8线模式,所以我们主要修改设备树文件即可。

#修改设备树EMMC接口是usdhc2,修改为:
&usdhc2 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc2_8bit>;
	pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>;
	pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>;
	bus-width = <8>;
	non-removable;
	status = "okay";
};
(3)修改网络驱动
#官方的KSZ8081被更换成LAN8720A,导致复位引脚发生了变化,故要修改复位引脚
# 进入设备树文件
#1 删去被占用的引脚配置(全局搜索被占用的引脚并删去,pinctrl--GPIO5_IO07/GPIO5_IO08,gpio子系统--
	pinctrl_spi4: spi4grp {
                    fsl,pins = <
                            MX6ULL_PAD_BOOT_MODE0__GPIO5_IO10        0x70a1
                            MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11        0x70a1
                          /*MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07      0x70a1 
                            MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08      0x80000000*/
                    >;
            };
    spi4 {
		compatible = "spi-gpio";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_spi4>;
	/*	pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;	*/
		status = "okay";
		gpio-sck = <&gpio5 11 0>;
		gpio-mosi = <&gpio5 10 0>;
	/*	cs-gpios = <&gpio5 7 0>;	*/
    ...
	};
#2 修改ent1时钟参考引脚属性!这一步很关键,不做则会出现网络驱动反复开关的情形。再增加我们复位引脚的pinctrl子系统。
pinctrl_enet1: enet1grp {
	fsl,pins = <
    ...
		MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1	0x4001b009
	>;
	};

pinctrl_enet2: enet2grp {
	fsl,pins = <
        ...
                MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2	0x4001b009  
	>;
};

#snvs引脚统一在iomuxc_snvs节点中进行复用管理
&iomuxc_snvs {
    ...
    imx6ul-evk {
    ...
     /*enet1 reset*/
    pinctrl_enet1_reset: enet1resetgrp {
        fsl,pins = <
            /* used for enet1 reset */
            MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x10B0
        >;
    };

    /*enet2 reset zuozhongkai*/
    pinctrl_enet2_reset: enet2resetgrp {
        fsl,pins = <
        /* used for enet2 reset */
        MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x10B0
        >;
    };
    ...    
};

#3 修改PHY地址 fec1和fec2节点增加gpio子系统用于复位,再增加一个duration属性。mdio节点用于设置phy地址。
&fec1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet1
	             &pinctrl_ent1_reset>;
	phy-mode = "rmii";
	phy-handle = <&ethphy0>;
	phy-reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
	phy-reset-duration = <200>; //表示复位低电平持续时间
	status = "okay";
};

&fec2 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet2
	             &pinctrl_enet2_reset>;
	phy-mode = "rmii";
	phy-handle = <&ethphy1>;
	phy-reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
	phy-reset-duration = <200>;
	status = "okay";

	mdio {
		#address-cells = <1>;
		#size-cells = <0>;

		ethphy0: ethernet-phy@0 {
			compatible = "ethernet-phy-ieee802.3-c22";
			smsc,disable-energy-detect //表示芯片是smsc公司的
			reg = <0>;
		};

		ethphy1: ethernet-phy@1 {
			compatible = "ethernet-phy-ieee802.3-c22";
			smsc,disable-energy-detect;
			reg = <1>;
		};
	};
};

#4 修改fec_main.c中的模块初始化函数fec_probe(struct platform_device *pdev),添加以下代码:
static int fec_probe(struct platform_device *pdev)
{
	struct fec_enet_private *fep;
	struct fec_platform_data *pdata;
	struct net_device *ndev;
	int i, irq, ret = 0;
	struct resource *r;
	const struct of_device_id *of_id;
	static int dev_id;
	struct device_node *np = pdev->dev.of_node, *phy_node;
	int num_tx_qs;
	int num_rx_qs;

	void __iomem *IMX6U_ENET1_TX_CLK;
	void __iomem *IMX6U_ENET2_TX_CLK;

	IMX6U_ENET1_TX_CLK = ioremap(0x020E00DC, 4);
	writel(0x14, IMX6U_ENET1_TX_CLK);

	IMX6U_ENET2_TX_CLK = ioremap(0x020E00FC, 4);
	writel(0x14, IMX6U_ENET2_TX_CLK);
	...

#5 配置Linux内核,使能LAN8720驱动
make menuconfig 
-> Device Drivers
-> Network device support
-> PHY Device support and infrastructure
-> Drivers for SMSC PHYs

#6 修改smsc.c文件: 使用LAN8720A需要对LAN8720A进行一次软复位,LAN8720A驱动文件就是smsc.c,内部的smsc_phy_reset就是复位函数.
#需要再前面添加头文件
#include <linux/of_gpio.h>
#include <linux/io.h>
static int smsc_phy_reset(struct phy_device *phydev)
{
	int err, phy_reset;
	int msec = 1;
	struct device_node *np;

	if(phydev->addr == 0) /* FEC1  */ {
		np = of_find_node_by_path("/soc/aips-bus@02100000/ethernet@02188000"); #获取FEC1网卡对应的设备节点
		if(np == NULL) {
			return -EINVAL;
		}
	}

	if(phydev->addr == 1) /* FEC2  */ {
		np = of_find_node_by_path("/soc/aips-bus@02000000/ethernet@020b4000"); #回去FEC2对应的设备节点
		if(np == NULL) {
			return -EINVAL;
		}
	}

	err = of_property_read_u32(np, "phy-reset-duration", &msec); #从设备树节点获取复位时间信息,存进msec中
	/* A sane reset duration should not be longer than 1s */
	if (!err && msec > 1000)
		msec = 1;
	phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0); #获得复位IO信息
	if (!gpio_is_valid(phy_reset))
		return;
    
	gpio_direction_output(phy_reset, 0);#输出
	gpio_set_value(phy_reset, 0);#输出低电平
	msleep(msec);#延时
	gpio_set_value(phy_reset, 1);#输出高电平

	int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);#
	if (rc < 0)
		return rc;

	/* If the SMSC PHY is in power down mode, then set it
	 * in all capable mode before using it.
	 */
	if ((rc & MII_LAN83C185_MODE_MASK) == MII_LAN83C185_MODE_POWERDOWN) {

		/* set "all capable" mode and reset the phy */
		rc |= MII_LAN83C185_MODE_ALL;
		phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
	}

	phy_write(phydev, MII_BMCR, BMCR_RESET);
	/* wait end of reset (max 500 ms) */
	int timeout = 50000;
	do {
		udelay(10);
		if (timeout-- == 0)
			return -1;
		rc = phy_read(phydev, MII_BMCR);
	} while (rc & BMCR_RESET);
	return 0;
}

三、menuconfig修改后的保存(防止clean)

(1)menuconfig修改后默认保存在.config中,所以可以将.config直接另存为xxx_defconfig。
(2)通过menconfig中的save按钮,再输入相对路径。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值