系列文章目录
- Exynos4412 移植针对Samsung的Linux-6.1(一)下载、配置、编译Linux-6.1
- Exynos4412 移植针对Samsung的Linux-6.1(二)SD卡驱动——解决无法挂载SD卡的根文件系统
- Exynos4412 移植针对Samsung的Linux-6.1(三)SD卡驱动——解决mmc0: Timeout waiting for hardware interrupt.
- Exynos4412 移植针对Samsung的Linux-6.1(四)NandFlash卡驱动
- Exynos4412 移植针对Samsung的Linux-6.1(五)DM9000网卡驱动
- Exynos4412 移植针对Samsung的Linux-6.1(六)SROMC寄存器的数值不正确的问题
- Exynos4412 移植Linux-6.1(七)挂载Ramdisk文件系统,【已解决】Couldn’t find valid RAM disk image starting at 0
问题描述
之前的博文中,Linux已经移植了SD卡、NandFlash、DM9000A网卡的驱动。挂载SD卡上的根文件系统之后,也能够成功启动。
问题是:启动Linux内核之后,ifconfig始终无法正确配置eth0。我在驱动中增加代码查看DM9000寄存器、SROMC寄存器数据的代码,结果如下,可以看出:
- 引脚复用功能正常;
- SROMC寄存器数据不正确,并且修改无效;
- DM9000A寄存器数据不正确。
/ # ifconfig eth0 up
[ 2388.423303][ T89] dm9000aep_pre_init---before config DM9000---
[ 2388.423303][ T89] GPY0CON IS:220020 GPY1CON IS:2222 //可以看出引脚复用功能正常
[ 2388.423303][ T89] GPY3CON IS:22222222 GPY3PUD IS:FFFF
[ 2388.423303][ T89] GPY5CON IS:22222222 GPY5PUD IS:FFFF
[ 2388.423303][ T89] GPY6CON IS:22222222, GPY6PUD IS:FFFF
[ 2388.504815][ T89] exynos_config_sromc:before sromc bw value is:0
[ 2388.504815][ T89] bc value is:0 //可以看出SROMC寄存器数据不正确,并且修改无效
[ 2388.514251][ T89] exynos_config_sromc:after sromc bw value is:f0
[ 2388.514251][ T89] bc value is:11051c91
[ 2388.525407][ T89] ---funciton: dm9000_reset before reset---
[ 2388.530048][ T89] NCR (0X00):19 //可以看出,DM9000A寄存器数据不正确
[ 2388.533403][ T89] GPR (0X1F):19
[ 2388.536787][ T89] GPCR (0X1E):19
[ 2388.578564][ T89] BMCR (0X00.):1919
[ 2388.618559][ T89] DSCR (0X16.):1919
[ 2388.618611][ T89] NSR (0X01):19
[ 2388.618657][ T89] ISR (0XFE):19
[ 2388.618807][ T89] dm9000 5000000.ethernet: dm9000 did not respond to first reset
[ 2388.618992][ T89] dm9000 5000000.ethernet: dm9000 did not respond to second reset
[ 2388.748792][ T89] dm9000 5000000.ethernet eth0: link down
/ #
分析经过
1、在really_probe()函数中打印寄存器数值
刚开始怀疑,是不是在加载某个硬件驱动时修改了SROMC寄存器,导致错误。所以,在drivers/base/dd.c的really_probe()函数中,增加printk,打印SROMC寄存器数值。
通过打印内核启动信息,发现加载驱动没有SROMC寄存器,但是在mmcblk
驱动之前SROMC寄存器不正确。
内核启动信息部分如下:
[ 4.934884][ T36] bus: 'platform': really_probe: probing driver s3c-sdhci with device 12530000.mmc
[ 4.941972][ T9] bus: 'platform': really_probe: probing driver dwmmc_exynos with device 12550000.mmc
[ 4.942183][ T1] bus: 'platform': really_probe: probing driver exynos-rng with device 10830400.rng
[ 4.942861][ T1] bus: 'platform': really_probe: probing driver s5p-secss with device 10830000.sss
[ 4.943851][ T1] s5p-secss 10830000.sss: s5p-sss driver registered
[...]
[ 5.782241][ T36] mmc0: SDHCI controller on samsung-hsmmc [12530000.mmc] using ADMA
[ 5.783122][ T1] Waiting for root device /dev/mmcblk0p3...
[ 6.023886][ T12] mmc0: new high speed SD card at address 0002
[ 6.024794][ T12] bus: 'mmc': really_probe: probing driver mmcblk with device mmc0:0002
[...]
[ 6.024982][ T12] really_probe:before sromc bw value is:0
[ 6.024982][ T12] bc value is:0
[...]
Please press Enter to activate this console.
/ #
2、在 exynos_pd_power()函数中打印寄存器数值
在启动信息中,会显示Power domain ISP disable failed
,所以怀疑是不是电源管理更改了SROMC寄存器。于是,在drivers/soc/samsung/pm_domains.c的exynos_pd_power()函数中增加printk,打印SROMC寄存器数值。
[...]
[ 20.651465][ T1] pd off:device name is:ISP :before sromc bw value is:f9
[ 20.651465][ T1] bc value is:11051c91
[...]
[ 21.372000][ T1] pd off:device name is:ISP :before sromc bw value is:0
[ 21.372000][ T1] bc value is:0
3、在exynos_pd_power()函数中打印堆栈
到底是哪个函数调用exynos_pd_power(),导致SROMC寄存器数值错误呢?于是在exynos_pd_power()函数中增加dump_stack(),打印查看堆栈中的函数。
结果发现是在系统初始化的时候,调用了clk_disable_unused()函数,关闭了时钟源,导致SROMC寄存器数值错误。
[...]
[ 20.831820][ T1] CPU: 3 PID: 1 Comm: swapper/0 Not tainted 6.1.0-g4467c3e35969-dirty #8
[ 20.838583][ T1] Hardware name: Samsung Exynos (Flattened Device Tree)
[ 20.845354][ T1] unwind_backtrace from show_stack+0x10/0x14
[ 20.851256][ T1] show_stack from dump_stack_lvl+0x58/0x70
[ 20.856985][ T1] dump_stack_lvl from exynos_pd_power.constprop.0+0xc/0xe4
[ 20.864102][ T1] exynos_pd_power.constprop.0 from _genpd_power_on+0x88/0x164
[ 20.871480][ T1] _genpd_power_on from genpd_power_on.part.0+0xac/0x180
[ 20.878337][ T1] genpd_power_on.part.0 from genpd_runtime_resume+0x114/0x2e0
[ 20.885715][ T1] genpd_runtime_resume from __rpm_callback+0x3c/0x108
[ 20.892399][ T1] __rpm_callback from rpm_callback+0x50/0x54
[ 20.898301][ T1] rpm_callback from rpm_resume+0x54c/0x780
[ 20.904030][ T1] rpm_resume from __pm_runtime_resume+0x48/0xa0
[ 20.910193][ T1] __pm_runtime_resume from clk_pm_runtime_get.part.0+0x14/0x64
[ 20.917657][ T1] clk_pm_runtime_get.part.0 from clk_unprepare_unused_subtree+0xbc/0x19c
[ 20.925990][ T1] clk_unprepare_unused_subtree from clk_unprepare_unused_subtree+0x6c/0x19c
[ 20.934583][ T1] clk_unprepare_unused_subtree from clk_unprepare_unused_subtree+0x6c/0x19c
[ 20.943176][ T1] clk_unprepare_unused_subtree from clk_unprepare_unused_subtree+0x6c/0x19c
[ 20.951770][ T1] clk_unprepare_unused_subtree from clk_disable_unused+0xb4/0xf8
[ 20.959408][ T1] clk_disable_unused from do_one_initcall+0x64/0x380
[ 20.966005][ T1] do_one_initcall from kernel_init_freeable+0x1c4/0x22c
[ 20.972862][ T1] kernel_init_freeable from kernel_init+0x18/0x12c
[ 20.979286][ T1] kernel_init from ret_from_fork+0x14/0x2c
[ 20.985014][ T1] Exception stack(0xf0845fb0 to 0xf0845ff8)
[ 20.990744][ T1] 5fa0: 00000000 00000000 00000000 00000000
[ 20.999599][ T1] 5fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 21.008452][ T1] 5fe0: 00000000 00000000 00000000 00000000 00000013 00000000
[ 21.015945][ T1] pd off:device name is:ISP :before sromc bw value is:0
[ 21.015945][ T1] bc value is:0
4、查看clk_disable_unused()函数
在drivers/clk/clk.c的1379行,有clk_disable_unused()函数。可以看出,如果布尔变量clk_ignore_unused=true,那么,就不会关闭未使用的时钟("clk: Not disabling unused clocks\n"
)。
那么问题来了,怎样给clk_ignore_unused赋值呢?
5、给clk_ignore_unused赋值
通过在互联网上搜索关键字clk_ignore_unused,发现通过u-boot的bootargs可以给clk_ignore_unused赋值。u-boot启动之后、加载Linux之前,修改bootargs,启动Linux之后,成功ifconfig eth0 参数。完整bootargs如下:
setenv bootargs root=/dev/ram rw initrd=0x43000040,8M console=ttySAC0,115200n8 init=/linuxrc clk_ignore_unused=true earlyprintk loglevel=15 rootfstype=ext2;
tftp 50000000 uImage;tftp 43000000 ramdisk.img;tftp 51000000 exynos4412-cbt4412.dtb;bootm 50000000 43000000 51000000
执行ifconfig结果如下:
[root@fcbt4412 ]# ifconfig eth0 192.168.1.230 netmask 255.255.255.0 up
[...]
[ 96.438961][ T84] exynos_config_sromc:after sromc bw value is:f9
[ 96.438961][ T84] bc value is:11051c91
[...]
[ 96.526904][ T84] ---funciton: dm9000_reset after reset---
[ 96.527051][ T84] NCR (0X00):0
[ 96.527167][ T84] GPR (0X1F):58
[ 96.527283][ T84] GPCR (0X1E):71
[ 96.556720][ T84] BMCR (0X00.):3100
[ 96.586643][ T84] DSCR (0X16.):414
[ 96.586778][ T84] NSR (0X01):0
[ 96.586897][ T84] ISR (0XFE):0
[ 96.647299][ T84] dm9000 5000000.ethernet eth0: link down
[root@cbt4412 ]# [ 96.917789][ T7] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[ 96.975095][ T85] dm9000 5000000.ethernet eth0: link up, 100Mbps, full-duplex, lpa 0xCDE1
[root@cbt4412 ]# ping 192.168.1.7
PING 192.168.1.7 (192.168.1.7): 56 data bytes
64 bytes from 192.168.1.7: seq=0 ttl=64 time=2.101 ms
64 bytes from 192.168.1.7: seq=1 ttl=64 time=3.425 ms
小 结(读取寄存器数值的方法)
exynos4412本质上还是嵌入式系统,根本是操作内部寄存器。在调试代码的时候,还是要想办法查看、分析各种寄存器的数据。文章来源:https://www.toymoban.com/news/detail-461067.html
1、SROMC寄存器数值代码示例如下:
#define EXYNOS4412_SROMC_BASE 0x12570000
struct exynos_sromc {
unsigned int bw;
unsigned int bc[6];
};
struct exynos_sromc *srom = (struct exynos_sromc *)(ioremap(EXYNOS4412_SROMC_BASE,0x10000));
printk(KERN_DEBUG "%s:before sromc bw value is:%x\n" \
"bc value is:%x\n",__func__,srom->bw,srom->bc[1]);
2、GPIO寄存器的读取方法
/* gpio configuration */
gpy0con = ioremap(0x11000000 + 0x120,4);
gpy1con = ioremap(0x11000000 + 0x140,4);
/* 16 Bit bus width */
gpy3con = ioremap(0x11000000 + 0x180,4);
gpy3pud = ioremap(0x11000000 + 0x188,4);
gpy5con = ioremap(0x11000000 + 0x1C0,4);
gpy5pud = ioremap(0x11000000 + 0x1C8,4);
gpy6con = ioremap(0x11000000 + 0x1E0,4);
gpy6pud = ioremap(0x11000000 + 0x1E8,4);
printk(KERN_DEBUG "%s---before config DM9000---\n" \
"GPY0CON IS:%X GPY1CON IS:%X\n" \
"GPY3CON IS:%X GPY3PUD IS:%X\n" \
"GPY5CON IS:%X GPY5PUD IS:%X\n " \
"GPY6CON IS:%X, GPY6PUD IS:%X\n" \
__func__,\
readl(gpy0con),readl(gpy1con),\
readl(gpy3con),readl(gpy3pud),\
readl(gpy5con),readl(gpy5pud),\
readl(gpy5con),readl(gpy5pud));
3、dm9000寄存器的读取方法
控制和状态寄存器的数据,可以调用ior()函数来读取。PHY 寄存器的数据,可以稍微修改驱动中的dm9000_phy_read()的形参,把struct net_device *dev更改为struct board_info *db。文章来源地址https://www.toymoban.com/news/detail-461067.html
static void dm9000_msleep(struct board_info *db, unsigned int ms);
/* Read a word from phyxcer */
static int
dm9000_phy_read_db(struct board_info *db, int reg)
{
unsigned long flags;
unsigned int reg_save;
int ret;
mutex_lock(&db->addr_lock);
spin_lock_irqsave(&db->lock, flags);
/* Save previous register address */
reg_save = readb(db->io_addr);
/* Fill the phyxcer register into REG_0C */
iow(db, DM9000_EPAR, DM9000_PHY | reg);
/* Issue phyxcer read command */
iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS);
writeb(reg_save, db->io_addr);
spin_unlock_irqrestore(&db->lock, flags);
dm9000_msleep(db, 1); /* Wait read complete */
spin_lock_irqsave(&db->lock, flags);
reg_save = readb(db->io_addr);
iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer read command */
/* The read data keeps on REG_0D & REG_0E */
ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL);
/* restore the previous address */
writeb(reg_save, db->io_addr);
spin_unlock_irqrestore(&db->lock, flags);
mutex_unlock(&db->addr_lock);
dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret);
return ret;
}
#define GPCR_GPIO0_OUT (7<<1) //GPCR bit[3~1]=111,meaning output
#define MII_DSCR 16 //MII_DSCR address
static void
dm9000_reset(struct board_info *db)
{
dev_dbg(db->dev, "resetting device\n");
printk(KERN_DEBUG "---funciton: %s befor reset---\n", __func__);// my_printk_debug
printk(KERN_DEBUG "NCR (0X00):%x \n", ior(db, 0x00));// my_printk_debug
printk(KERN_DEBUG "GPR (0X1F):%x \n", ior(db, 0x1f));// my_printk_debug
printk(KERN_DEBUG "GPCR (0X1E):%x \n", ior(db, 0x1e));// my_printk_debug
printk(KERN_DEBUG "BMCR (0X00.):%x \n", dm9000_phy_read_db(db, 0x00));// my_printk_debug
printk(KERN_DEBUG "DSCR (0X16.):%x \n", dm9000_phy_read_db(db, MII_DSCR));// my_printk_debug
printk(KERN_DEBUG "NSR (0X01):%x \n", ior(db, 0x01));// my_printk_debug
printk(KERN_DEBUG "ISR (0XFE):%x \n", ior(db, 0xfe));// my_printk_debug
[...]
}
遗留问题
- 大家用什么集成开发环境可以实现调试查看寄存器,请在留言区讨论留言。
到了这里,关于Exynos4412 移植针对Samsung的Linux-6.1(六)【已解决】SROMC寄存器的数值不正确、无法赋值的问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!