Page 1 of 1

luckfox pico plus (RV1103) 使用ioremap做4字节地址映射后、readl只能读出2个字节的有效数据

Posted: 2024-07-06 8:16
by Godspeed
luckfox pico plus (RV1103) 编写IO控制驱动(直接操作寄存的方式),使用ioremap做4字节地址映射后、readl只能读出2个字节的有效数据(用printk打印,高2个字节为空),导致后续对寄存器的操作失败。

串口log:
# insmod led.ko
[ 2256.146492] GPIO3C6_IOMUX = 3002
[ 2256.146525] GPIO3C6_IOMUX = 3002
[ 225# 6.146609] led_init!

具体部分代码如下。
可行是什么原因?


=========================================================================
/*GPIO3C6寄存器物理地址 */
#define GPIO3C6_IOMUX_BASE (0xFF558054)
#define GPIO3C6_PULL_BASE (0xFF5581E8)
#define GPIO3C6_MODE_BASE (0xFF55000C)
#define GPIO3C6_OUTPUT_BASE (0xFF550004)
#define GPIO3C6_INPUTCTRL_BASE (0xFF5581A8)
#define GPIO3C6_SCHMITT_BASE (0xFF5582A8)
#define GPIO3C6_DRIVESTRENGTH_BASE (0xFF55812C)

/*地址映射后的虚拟地址*/
static void __iomem *GPIO3C6_IOMUX;
static void __iomem *GPIO3C6_PULL;
static void __iomem *GPIO3C6_MODE;
static void __iomem *GPIO3C6_OUTPUT;
static void __iomem *GPIO3C6_INPUTCTRL;
static void __iomem *GPIO3C6_SCHMITT;
static void __iomem *GPIO3C6_DRIVESTRENGTH;

//设置GPIO3C6输出高电平,点亮LED灯
static int __init led_init(void)
{
int ret = 0;
unsigned int var = 0;

/*1、建立地址映射*/
GPIO3C6_IOMUX = ioremap(GPIO3C6_IOMUX_BASE, 4);
GPIO3C6_PULL = ioremap(GPIO3C6_PULL_BASE, 4);
GPIO3C6_MODE = ioremap(GPIO3C6_MODE_BASE, 4);
GPIO3C6_OUTPUT = ioremap(GPIO3C6_OUTPUT_BASE, 4);
GPIO3C6_INPUTCTRL = ioremap(GPIO3C6_INPUTCTRL_BASE, 4);
GPIO3C6_SCHMITT = ioremap(GPIO3C6_SCHMITT_BASE, 4);
GPIO3C6_DRIVESTRENGTH = ioremap(GPIO3C6_DRIVESTRENGTH_BASE, 4);

/*2、初始化*/
var = readl(GPIO3C6_IOMUX);

printk("GPIO3C6_IOMUX = %8x\r\n", var); //打印GPIO3C6_IOMUX的出初始值

var &= ~(7<<8); //清除 bit 8~10
writel(var, GPIO3C6_IOMUX);

printk("GPIO3C6_IOMUX = %8x\r\n", var); //打印GPIO3C6_IOMUX修改后的值

var = readl(GPIO3C6_PULL);
var &= ~(3<<12); //清除 bit 12~13, 即值设置为0
writel(var, GPIO3C6_PULL);

var = readl(GPIO3C6_MODE);
var |= 1<<6; //将bit 6 的值设置为 1 输出
writel(var, GPIO3C6_MODE);

var = readl(GPIO3C6_OUTPUT);
var |= 1<<6; //将bit 6 的值设置为 1 输出高点平
writel(var, GPIO3C6_OUTPUT);

var = readl(GPIO3C6_INPUTCTRL);
var &= ~(1<<6); //将bit 6 的值设置为 0 关闭输入
writel(var, GPIO3C6_INPUTCTRL);

var = readl(GPIO3C6_SCHMITT);
var |= 1<<6; //将bit 6 的值设置为 1 使能施密特触发器
writel(var, GPIO3C6_SCHMITT);


var = readl(GPIO3C6_DRIVESTRENGTH);
var |= 63; //将bit 0~5 的值设置为 63
writel(var, GPIO3C6_DRIVESTRENGTH);


ret = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);

if(ret < 0){
printk("register_chrdev failed!\r\n");
return -EIO;
}

printk(KERN_EMERG"led_init!\n");

return 0;
}

=========================================================================

Re: luckfox pico plus (RV1103) 使用ioremap做4字节地址映射后、readl只能读出2个字节的有效数据

Posted: 2024-07-31 10:22
by Crocodile
您好,我查阅了相关的资料,RV1106的GPIO寄存器的高16位都是写入许可位,控制低16位是否可以写入的,由于我没有完整的数据手册根据实验后我猜测默认高16位都为0,需要写入数据到低十六位时先将对应的位置1,完成写入后重新置0。

Re: luckfox pico plus (RV1103) 使用ioremap做4字节地址映射后、readl只能读出2个字节的有效数据

Posted: 2024-08-03 8:24
by Godspeed
尝试了下,直接向寄存器写入32位的数值,确实可以控制LED的亮灭了。 (具体数值来源于 Rockchip_RV1103_User_Manual_GPIO 文档的说明)
应该就是你所说的,高16位也需要对应的置位,只是现在还没找到相关说明。


======================================================
/*初始化*/
var = readl(GPIO3C6_IOMUX);
printk("GPIO3C6_IOMUX = %#x\r\n", var);
// var &= ~(7<<8); //清除 bit 8~10
var= 0x07000000;
writel(var, GPIO3C6_IOMUX);
printk("GPIO3C6_IOMUX = %#x\r\n", var);

var = readl(GPIO3C6_PULL);
printk("GPIO3C6_PULL = %#x\r\n", var);
// var &= ~(3<<12); //清除 bit 12~13, 即值设置为0
var = 0x30000000;
writel(var, GPIO3C6_PULL);
printk("GPIO3C6_PULL = %#x\r\n", var);

var = readl(GPIO3C6_MODE);
printk("GPIO3C6_MODE = %#x\r\n", var);
// var |= 1<<6; //将bit 6 的值设置为 1 输出
var = 0x00400040;
writel(var, GPIO3C6_MODE);
printk("GPIO3C6_MODE = %#x\r\n", var);

var = readl(GPIO3C6_OUTPUT);
printk("GPIO3C6_OUTPUT = %#x\r\n", var);
// var |= 1<<6; //将bit 6 的值设置为 1 输出高电平
var = 0x00400040; //输出高电平
writel(var, GPIO3C6_OUTPUT);
printk("GPIO3C6_OUTPUT = %#x\r\n", var);

var = readl(GPIO3C6_INPUTCTRL);
printk("GPIO3C6_INPUTCTRL = %#x\r\n", var);
// var &= ~(1<<6); //将bit 6 的值设置为 0 关闭输入
var = 0x00400000;
writel(var, GPIO3C6_INPUTCTRL);
printk("GPIO3C6_INPUTCTRL = %#x\r\n", var);

var = readl(GPIO3C6_SCHMITT);
printk("GPIO3C6_SCHMITT = %#x\r\n", var);
// var |= 1<<6; //将bit 6 的值设置为 1 使能施密特触发器
var = 0x00400040;
writel(var, GPIO3C6_SCHMITT);
printk("GPIO3C6_SCHMITT = %#x\r\n", var);

var = readl(GPIO3C6_DRIVESTRENGTH);
printk("GPIO3C6_DRIVESTRENGTH = %#x\r\n", var);
// var |= 63; //将bit 0~5 的值设置为 63
var = 0x003F003F;
writel(var, GPIO3C6_DRIVESTRENGTH);
printk("GPIO3C6_DRIVESTRENGTH = %#x\r\n", var);

=============================================
log:

[ 233.860339] GPIO3C6_IOMUX = 0x3002 //读出的初始值
[ 233.860349] GPIO3C6_IOMUX = 0x7000000 //上述代码直接写入的数值
[ 233.860355] GPIO3C6_PULL = 0x2800 //读出的初始值
[ 233.860361] GPIO3C6_PULL = 0x30000000 //上述代码直接写入的数值
[ 233.860367] GPIO3C6_MODE = 0x60 //读出的初始值
[ 233.860373] GPIO3C6_MODE = 0x400040 //上述代码直接写入的数值
[ 233.860379] GPIO3C6_OUTPUT = 0x0 //读出的初始值
[ 233.860384] GPIO3C6_OUTPUT = 0x400040 //上述代码直接写入的数值
[ 233.860391] GPIO3C6_INPUTCTRL = 0xff //读出的初始值
[ 233.860397] GPIO3C6_INPUTCTRL = 0x400000 //上述代码直接写入的数值
[ 233.860403] GPIO3C6_SCHMITT = 0xff //读出的初始值
[ 233.860409] GPIO3C6_SCHMITT = 0x400040 //上述代码直接写入的数值
[ 233.860414] GPIO3C6_DRIVESTRENGTH = 0x303 //读出的初始值
[ 233.860420] GPIO3C6_DRIVESTRENGTH = 0x3f003f //上述代码直接写入的数值