linux下uboot kernel操作cpu寄存器


大多數的內核里面都有會對GPIO的操作,而且內核里面對GPIO進行配置也很方便,要什么功能就配置成什么就可以了。

還有一些寄存器是內核沒有配置到的,但是我們要操作怎么辦,內核里面也定義了相關的接口函數。

在u-boot中操作某個寄存器:

 

[cpp]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. reg = readl(IOMUXC_BASE_ADDR + IOMUXC_REG_GPR1);  
  2. reg &= ~IOMUXC_REG_GPR1_ACTCS0_MASK;  
  3. writel(reg, IOMUXC_BASE_ADDR + IOMUXC_REG_GPR1);  

其中IOMUXC_BASE_ADDR是物理地址,跟蹤代碼發現writel操作如下:

 

#define writel(v,a) __arch_putl(v,a)

#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v))

所以在uboot里面配置寄存相當於是給物理地址直接賦值,volatile的意思是提醒編譯器需要存儲或讀取這個變量的時候,都會直接從變量地址中讀取數據

 

而在內核中,上面的寫法是無法運行的,會提示虛擬地址錯誤。在內核中通常是通過虛擬地址來給物理地址賦值,所以需要將物理地址轉換成虛擬地址

 

[cpp]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. reg = __raw_readl(ioremap(IOMUXC_BASE_ADDR + IOMUXC_REG_GPR1,4));  
  2. reg &= ~IOMUXC_REG_GPR1_ACTCS0_MASK;  
  3. reg &= ~IOMUXC_REG_GPR1_ADDRS0_MASK;  
  4. reg |= ((CS0_NORFLASH_SIZE | IOMUXC_REG_GPR1_ACTCS0));  
  5. __raw_writel(reg, ioremap(IOMUXC_BASE_ADDR + IOMUXC_REG_GPR1,4));  

這里的ioremap是將物理地址IOMUXC_BASE_ADDR轉換得到對應的虛擬地址,4表示4個字節,即32位的地址。

 

u-boot下讀寫gpio:

與讀寫寄存器類似,u-boot下讀寫GPIO口是直接給GPIO賦值:

 

[cpp]  view plain  copy
 
 print?在CODE上查看代碼片派生到我的代碼片
  1. mxc_request_iomux(MX53_PIN_GPIO_8, IOMUX_CONFIG_ALT1);  
  2. mxc_iomux_set_pad(MX53_PIN_GPIO_8, 0x1E4);  
  3.   
  4. reg = readl(GPIO1_BASE_ADDR + 0x0);  
  5.    <span style="white-space:pre"> </span>reg |= 0x100;  
  6. writel(reg, GPIO1_BASE_ADDR + 0x0);  
  7.   
  8. // Set pin direction as output  
  9. reg = readl(GPIO1_BASE_ADDR + 0x4);  
  10. reg |= 0x100;  
  11. writel(reg, GPIO1_BASE_ADDR + 0x4);  


GPIO_8 是GPIO1_8,前面兩個配置GPIO_8的功能。

 

查看datasheet可以看到GPIO1的地址配置

53F8_4000 GPIO data register (GPIO-1_DR) 32 R/W 0000_0000h 
53F8_4004 GPIO direction register (GPIO-1_GDIR) 32 R/W 0000_0000h 
53F8_4008 GPIO pad status register (GPIO-1_PSR) 32 R 0000_0000h 
53F8_400C GPIO interrupt configuration register1 (GPIO-1_ICR1) 32 R/W 0000_0000h 
53F8_4010 GPIO interrupt configuration register2 (GPIO-1_ICR2) 32 R/W 0000_0000h
53F8_4014 GPIO interrupt mask register (GPIO-1_IMR) 32 R/W 0000_0000h 
53F8_4018 GPIO interrupt status register (GPIO-1_ISR) 32 w1c 0000_0000h
53F8_401C GPIO edge select register (GPIO-1_EDGE_SEL) 32 R/W 0000_0000h 

 

可以看到它的數據寄存器的偏移地址是0x0,輸入輸出寄存器的偏移地址是0x4。而reg |= 0x100;是GPIO_8的所在的偏移,即(0x1 << 8)。

讀取一個gpio的值,只需要讀取它的狀態寄存器就可以了,

reg = readl( GPIO1_BASE_ADDR + 0x08 );

if(reg & (0x1 << 8))

printf("it is high\n");

else

printf("it is low\n");


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM