Zynq裝置樹教程(四)
獲取資源資訊
核心模組驅動載入之後,就開始把硬體資源管理起來,如讀寫暫存器、接收中斷。
來看看裝置樹裡的一條:
xillybus_0: [email protected] {
compatible = "xlnx,xillybus-1.00.a";
reg = < 0x50000000 0x1000 >;
interrupts = < 0 59 1 >;
interrupt-parent = <&gic>;
xlnx,max-burst-len = <0x10>;
xlnx,native-data-width = <0x20>;
xlnx,slv-awidth = <0x20>;
xlnx,slv-dwidth = <0x20>;
xlnx,use-wstrb = <0x1>;
} ;
驅動一般在探測函式裡就取得了硬體記憶體段的所有權(探測函式就是probe指標指向的函式)。
來看看一個典型探測函式的框架:
static int __devinit xilly_drv_probe(struct platform_device *op)
{
const struct of_device_id *match;
match = of_match_device(xillybus_of_match, &op->dev);
if (!match)
return -EINVAL;
第一個操作就是檢查probe是否作用在相關硬體上。
訪問暫存器
下一步,分配一段記憶體並對映到虛擬記憶體中。
int rc = 0;
struct resource res;
void *registers;
rc = of_address_to_resource(&op->dev.of_node, 0, &res);
if (rc) {
/* Fail */
}
if (!request_mem_region(res.start, resource_size(&res), "xillybus")) {
/* Fail */
}
registers = of_iomap(op->dev.of_node, 0);
if (!registers) {
/* Fail */
}
of_address_to_resource() 在裝置樹中找到第一個"reg",並將解析到的資訊填充在"res"結構體裡。這個例子裡"reg = < 0x50000000 0x1000 >”, 指的是分配一塊起始實體地址是0x50000000,長度為0x1000位元組的空間。of_address_to_resource()會設定res.start = 0x50000000, res.end = 0x50000fff。
呼叫request_mem_region()是為了註冊特殊的記憶體段。目的是避免兩個驅動訪問同一段暫存器空間而造成的衝突。resource_size()是個行內函數,返回segment的大小(此處是0x1000)。
of_iomap()函式是of_address_to_resource()和ioremap()的組合,本質上等效於ioremap(re.start, resource_size(&res)).確保物理段已經對映到虛擬記憶體中,函式返回記憶體段的虛擬地址空間起始地址。
顯然,當模組解除安裝或某個錯誤發生時,這些操作都需要有恢復動作。
訪問硬體暫存器請使用iowrite32(),ioread32()以及其他的函式和巨集,而不要直接使用上面的"register"指標。
中斷處理
這部分的驅動很簡單,類似如下:
irq = irq_of_parse_and_map(op->dev.of_node, 0);
rc = request_irq(irq, xillybus_isr, 0, "xillybus", op->dev);
irq_of_parse_and_map()在裝置樹裡查詢中斷的描述項,然後返回中斷號,request_irq()將使用這個中斷號來註冊。第二個引數是0,表示使用裝置樹中的第一個中斷。
裝置樹裡面描述是:
interrupts = < 0 59 1 >;
interrupt-parent = <&gic>;
那麼使用了這三個資料中的哪一個呢?
第一個0是一個標誌,用於指示中斷是否是SPI(共享中斷,shared peripheral interrupt)。非0值表示它是SPI。事實上在Zynq硬體上,這些中斷都是共享的,這裡是為了方便才寫0, 軟體上認為它不共享。
第二個資料表示中斷號。
第三個數字是中斷型別,可以有如下值:
0 - 核心不改變它,開機或uboot設定它是什麼樣就什麼樣。
1 - 上升沿觸發
4 - 電平觸發,高電平表示來中斷。
不允許有其他值,下降沿觸發和低電平中斷目前不支援,因為硬體不支援那些模式。如果需要這樣的觸發方式,就得在硬體上加一個非門。
值得注意的是第三個數字在裝置樹裡通常都是0, 所以Linux核心不去改變中斷模式。這通常意味著高電平觸發。這也讓驅動依賴於bootloader裡的設定。
interrupt-parent 這一句,必須指向中斷控制器&gic。如果反編譯一個DTB檔案,這裡的&gic會被一個數字代替,通常是0x1。