linux驱动中读写硬件寄存器(例如__raw_writel)

I/O内存映射与寄存器访问
本文深入解析了设备控制中I/O内存映射的概念,详细介绍了如何通过__iomem属性将物理地址映射到虚拟地址,以便内核能够像访问普通内存一样操作设备寄存器。同时,提供了内核源码中用于读写I/O空间的函数示例,如__raw_readb、__raw_writel等。

设备通常会提供一组寄存器来控制设备、读写设备和获取设备状态,即控制寄存器、数据寄存器和状态寄存器。这些寄存器可能位于I/O空间,也可能位于内存空间。当位于I/O空间时,通常被称为I/O端口,位于内存空间时,对应的内存空间被称为I/O内存。

再内核访问I/O内存前,需要将设备所处的物理地址映射到虚拟地址

 __iomem源码位置:include/linux/compiler.h

# define __force    __attribute__((force)) //变量可以进行强制转换
# define __nocast   __attribute__((nocast))

/*指针地址必须在设备地址空间,__iomem是个IO map的问题,根据系统的具体情况,
把寄存器映射到虚拟地址的特定位置,这样,访问寄存器就可以像访问普通内存一样简单方便
主要是用于编译器的检查,检查地址空间的有效性*/
# define __iomem    __attribute__((noderef, address_space(2)))     // 
# define __acquires(x)  __attribute__((context(x,0,1)))
# define __releases(x)  __attribute__((context(x,1,0)))

 

static inline u8 __raw_readb(const volatile void __iomem *addr)
{
    return *(__force volatile u8 *)addr;
}

static inline u16 __raw_readw(const volatile void __iomem *addr)
{
    return *(__force volatile u16 *)addr;
}

static inline u32 __raw_readl(const volatile void __iomem *addr)
{
    return *(__force volatile u32 *)addr;
}


static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
{
    *(__force volatile u8 *)addr = b;
}


    static inline void __raw_writew(u16 w, volatile void __iomem *addr)
{
    *(__force volatile u16 *)addr = w;
}


static inline void __raw_writel(u32 l, volatile void __iomem *addr)
{
    *(__force volatile u32 *)addr = l;
}


static inline u8 __readb(const volatile void __iomem *addr)
{
    return *(__force volatile u8 *)addr;
}


static inline u16 __readw(const volatile void __iomem *addr)
{
    return flip_word(*(__force volatile u16 *)addr);
}


static inline u32 __readl(const volatile void __iomem *addr)
{
return flip_dword(*(__force volatile u32 *)addr);
}


static inline void __writeb(u8 b, volatile void __iomem *addr)
{
    *(__force volatile u8 *)addr = b;
}


static inline void __writew(u16 w, volatile void __iomem *addr)
{
    *(__force volatile u16 *)addr = flip_word(w);
}


static inline void __writel(u32 l, volatile void __iomem *addr)
{
    *(__force volatile u32 *)addr = flip_dword(l);
}


#define readb(__addr) __readb(__addr)
#define readw(__addr) __readw(__addr)
#define readl(__addr) __readl(__addr)
#define readb_relaxed(__addr) readb(__addr)
#define readw_relaxed(__addr) readw(__addr)
#define readl_relaxed(__addr) readl(__addr)


#define writeb(__b, __addr) __writeb((__b),(__addr))
#define writew(__w, __addr) __writew((__w),(__addr))
#define writel(__l, __addr) __writel((__l),(__addr))
 

writel() 往内存映射的 I/O 空间上写数据,wirtel()  I/O 上写入 32 位数据 (4字节)

其他的都是类似用法。

 

 

 

 

<think>首先,用户的问题是关于LCD屏幕是否包含"raw寄存器",这可能与硬件驱动或初始化配置相关。用户引用了几个站内引用,我需要参考这些引用来构建回答。回顾站内引用:-引用[1]:讨论LCD驱动程序的修改,包括设备树配置、IO配置和背光节点。提到LCD驱动部分不需要修改,但需要调整设备树。-引用[2]:描述OV5640摄像头的I2C通信,包括器件地址和寄存器写入。但这是关于摄像头的,不是LCD。-引用[3]:关于背光驱动的实现,涉及gp7101_bl.c文件,设置亮度到硬件。-引用[4]:提到在U-Boot中检查屏幕启动logo,涉及DSI屏幕驱动。-引用[5]:讨论AndroidLCD驱动框架,包括framebuffer和panel上电。用户的问题核心是"LCD屏幕raw寄存器"。在LCD驱动上下文中,"raw寄存器"可能指的是LCD控制器的寄存器,或者是用于配置LCD参数的寄存器。从引用中提取相关信息:-引用[1]强调设备树配置,用于设置LCD参数如分辨率、时序等,而不是直接访问寄存器。-引用[3]涉及背光驱动,通过文件操作设置亮度。-引用[4]和[5]提到驱动框架,但没有具体提到"raw寄存器"。-引用[2]是关于摄像头的寄存器访问,但可能类比到LCD,因为LCD初始化可能需要配置寄存器。在LCD驱动中,通常LCD控制器(如SoC的eLCDIF接口)有寄存器集,用于控制显示参数。这些寄存器可以通过驱动代码访问。用户提到的"raw寄存器"可能指的是这些底层硬件寄存器。在Linux驱动框架中,LCD驱动通常使用framebuffer子系统,配置通过设备树完成。直接访问寄存器是可能的,但通常由驱动程序处理,而不是用户空间。用户的问题:"LCD屏幕是否包含raw寄存器"。LCD屏幕本身是一个显示设备,没有寄存器寄存器存在于LCD控制器(在SoC或驱动芯片中)。所以,回答应该澄清这一点。构建回答:1.**理解问题**:解释LCD屏幕本身不包含寄存器寄存器在控制器中。2.**参考引用**:使用引用[1]、[3]、[5]来支持LCD驱动的配置和初始化。3.**初始化配置**:描述LCD初始化过程,包括设备树设置和寄存器编程。4.**硬件驱动**:讨论驱动如何访问寄存器。5.**生成相关问题**:根据系统指令,添加相关问题。回答结构:-逐步解释:先澄清概念,然后讨论驱动和配置。-使用中文:所有内容用中文。-LaTeX格式:确保行内数学表达式用$...$,独立公式用$$...$$(但本问题可能不需要数学)。-引用标识:在引用段落末尾添加[^n]。最终回答:-开头:直接回答用户查询。-主体:解释LCD驱动中的寄存器访问。-结尾:生成相关问题。相关问题:-如何配置LCD屏幕的设备树节点?-LCD驱动中如何访问硬件寄存器?-什么是framebuffer在Linux中的作用?</think>### LCD屏幕的“raw寄存器”与硬件驱动及初始化配置分析 您的查询聚焦于LCD屏幕是否包含“raw寄存器”,以及这与硬件驱动和初始化配置的关系。我将基于硬件驱动原理和相关引用逐步解析。核心结论是:**LCD屏幕本身作为显示设备,不直接包含“raw寄存器”;但LCD控制器(通常集成在SoC或驱动芯片中)会通过寄存器操作来配置屏幕参数**。这些寄存器驱动初始化时被访问,用于设置分辨率、时序、背光等。以下结合引用详细说明。 --- ### 1. **LCD屏幕与寄存器的关系** - **LCD屏幕的本质**:LCD面板是纯硬件设备,仅负责像素显示,不包含可编程寄存器寄存器操作发生在**LCD控制器**(如SoC的eLCDIF接口)或**驱动芯片**(如背光IC)中。 - **“raw寄存器”的定义**:在驱动上下文中,“raw寄存器”通常指底层硬件寄存器(如控制时序、色彩格式、电源管理的寄存器)。这些寄存器通过内存映射I/O访问,例如配置显示时序的`HTIMING`寄存器或背光控制的`PWM`寄存器。 - **引用支持**: - 引用[1]提到,LCD驱动需修改设备树来配置IO和屏幕参数,而非直接操作寄存器,但底层驱动(如NXP的eLCDIF)会处理寄存器访问[^1]。 - 引用[3]说明背光驱动通过`gp7101_bl.c`将亮度设置传递给硬件寄存器[^3],这属于“raw寄存器”操作的典型场景。 --- ### 2. **硬件驱动中的寄存器操作** 在Linux驱动框架中,寄存器访问是初始化的核心步骤: - **寄存器访问方式**: - 通过内存映射(如`ioremap()`)直接读写物理地址。 - 示例代码(简化): ```c // 映射寄存器地址 void __iomem *reg_base = ioremap(REG_BASE_ADDR, REG_SIZE); // 写入配置值(例如设置分辨率) writel(0x800x480, reg_base + RESOLUTION_REG_OFFSET); ``` - **初始化配置流程**: 1. **设备树配置**:定义LCD参数(分辨率、时序),设备树节点被解析后生成寄存器配置值。 - 引用[1]强调需修改设备树的三个关键点:IO配置、屏幕节点参数(如`display-timings`)、背光节点[^1]。 2. **驱动加载**:内核驱动(如`framebuffer`子系统)解析设备树,生成寄存器写入序列。 - 引用[5]指出,驱动在panel上电时初始化寄存器(如电源序列)[^5]。 3. **寄存器编程**:驱动通过底层函数(如`lcdc_write_reg()`)将配置写入控制器寄存器。 - 例如,OV5640摄像头的I2C寄存器操作(引用[2])虽针对摄像头,但原理类似:通过地址(`Sub-address`)和数据(`Write Data`)配置硬件[^2]。 - **典型寄存器示例**: - **时序寄存器**:控制水平/垂直同步信号(e.g., `HSPW`, `VSPW`)。 - **色彩寄存器**:设置像素格式(e.g., RGB888对应寄存器值`0x00C0`)。 - **背光寄存器**:如引用[3]中的亮度控制寄存器,通过`backlight.c`传递值到硬件[^3]。 --- ### 3. **是否涉及“raw寄存器”?** - **是**,但间接通过驱动框架: - LCD控制器(如Allwinner SoC的LCDIF模块)包含寄存器组,驱动初始化时会写入这些“raw寄存器”。 - 用户空间不直接访问:应用层通过`/dev/fb0`等接口操作,而非裸寄存器(引用[5]强调`framebuffer`抽象层的作用)[^5]。 - **例外情况**: - 调试或定制驱动时,开发者可能直接操作寄存器(如U-Boot阶段检查启动logo,引用[4]中修改`sun20iw1p1_defconfig`)[^4]。 - 某些驱动芯片(如DSI桥接IC)需通过I2C配置其私有寄存器。 --- ### 总结 - **LCD屏幕本身无寄存器**,但**其控制器/驱动芯片通过“raw寄存器”实现配置**。初始化时,Linux驱动(如`framebuffer`)基于设备树生成寄存器写入操作,完成屏幕参数设置。 - 若要检查或修改这些寄存器: - 查看驱动源码(如`drivers/video/fbdev/`下的控制器驱动)。 - 使用调试工具(如`devmem2`)读取物理地址(需内核支持)。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值