2010年11月02日
LinuxカーネルからI/Oレジスタをたたく時のメモリのマッピングの方法
KZM-A9-DualボードにU-bootとLinuxカーネルを移植しています。
ボード屋さんに作ってもらったボードの仕様書とボードの動作確認用のテストプログラムを見ながらデバイスドライバを修正していきます。
Linuxカーネルは仮想メモリ上で動作しているので特定の物理アドレスにあるI/Oレジスタの読み書きをするときにはちょっと工夫必要です。
たとえばボードのテストプログラムでこんなコードがあったとします。
#define LCD_BACKLIGHT 0x22000400
...
void lcd_backlight_on(void)
{
RegWrite8(LCD_BACKLIGHT, 0x01);
}
組み込み開発をしている人はよく目にするコードだと思います。0x22000400番地に8bitのサイズで0x01を書き込めということです。
U-bootの中でこれと同じことを行うには、このコードをほぼそのまままねることができます。
outb(0x01, LCD_BACKLIGHT);
ボードのテストプログラムもU-bootも物理アドレス上で動作しています。MMUはオフの状態か、またはMMUがONでも仮想アドレス=物理アドレスになっている状態です。
LinuxカーネルはMMUをONにして仮想メモリ上で動作しています。そのため、上記のように物理アドレスの0x22000400番地に書き込みをおこなうためにはちょっと工夫が必要です。
こんなときに私はLinuxカーネルのソースの中で同じようなことをしているところがないかを探してそれのまねをすることにしています。今回はLANのチップのレジスタの読み書きのやりかたを参考にしました。
#define FPGA_BASE 0x22000000
#define FPGA_SIZE 0x00000fff
#define FPGA_NAME "KZM-A9-Dual-FPGA"
static void __iomem *fpga_addr;
void lcd_hw_backlight_init(void)
{
if (!request_mem_region(FPGA_BASE, FPGA_SIZXE, FPGA_NAME)) {
printk_err("request_mem_region failed.\n");
return;
}
fpga_addr = ioremap_nocache(FPGA_BASE, FPGA_SIZE);
}
void lcd_hw_backlight_on(void)
{
writeb(0x01, fpga_addr + 0x0400);
}
ポイントはrequest_mem_region とioremap_nocache を使うことです。これによってfpga_addr の指すページをFPGAの物理アドレスのところにマッピングすることができました。
他にもっとよいやりかたがあるかもしれませんが、とにかくこれでLinuxカーネル内から目的のI/Oレジスタの読み書きができました。