summaryrefslogtreecommitdiff
path: root/documentation/6.components/device-driver/pic/pic_ofw.md
blob: 558302666b5c932ffffbbbe0c1205ba5e09f06d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
@page page_device_pic_ofw PIC and device tree

# Device tree integration

How **`interrupts`** properties become virtual IRQs via **`irq_parse`** + **`irq_map`**.

Sources: **`pic.c`** (`ofw_pic_init`), **`ofw/irq.c`** (`rt_ofw_map_irq`).

---

## Boot: discovering controllers

**`rt_pic_init()`** → **`ofw_pic_init()`**:

```c
rt_ofw_foreach_node_by_prop(ic_np, "interrupt-controller")
    rt_ofw_stub_probe_range(ic_np, &_pic_ofw_start, &_pic_ofw_end);
```

**`RT_PIC_OFW_DECLARE(name, ids, handler)`** expands to **`RT_OFW_STUB_EXPORT(..., pic, handler)`** — same mechanism as other OFW stubs, linker section **`.rt_ofw_data.stub.*`**.

Handler (e.g. **`gicv2_ofw_init`**) must:

1. Map MMIO
2. **`rt_pic_linear_irq`**
3. **`rt_pic_add_traps`** (root only)
4. **`rt_ofw_data(np) = &pic`**

---

## Device IRQ resolution

**`rt_dm_dev_get_irq(dev, index)`** → **`ofw_api_call(get_irq)`** → **`rt_ofw_get_irq`** → **`rt_ofw_map_irq`**.

### `rt_ofw_map_irq` (core logic)

```c
pic = rt_pic_dynamic_cast(rt_ofw_data(ic_np));
pic->ops->irq_parse(pic, irq_args, &pirq);   /* RT_EOK == 0 */
irq = pic->ops->irq_map(pic, pirq.hwirq, pirq.mode);
```

| Step | Responsibility |
| --- | --- |
| **`rt_ofw_parse_irq_cells`** | Fill **`rt_ofw_cell_args`** from **`interrupts`** |
| **`irq_parse`** | Set **`out_pirq->hwirq`**, **`mode`** (GIC: type + number) |
| **`irq_map`** | **`rt_pic_config_irq`**, return **virtual IRQ** |

**`rt_pic_dynamic_cast`**: finds **`struct rt_pic`** embedded after **`rt_device`** or **`rt_object`** (name **`"PIC"`**).

---

## Example: GIC-style `#interrupt-cells` (3 cells)

From **`pic-gicv2.c`** / **`pic-gicv3.c`**:

| Cell 0 | Cell 1 | Cell 2 |
| --- | --- | --- |
| **0** = SPI, **1** = PPI, … | Interrupt number | Flags → **`RT_IRQ_MODE_*`** |

SPI DT number **0** → **hwirq 32** (`args[1] + 32`).

DTS example (Raspberry Pi 4, **`bcm2711-rpi-4-b.dts`**):

```dts
interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
```

---

## Secondary `interrupt-controller`

Child node must expose **`interrupt-controller`** + **`#interrupt-cells`** and set **`rt_ofw_data`** to its **`struct rt_pic`**.

Consumers use **`interrupt-parent = <&child_ic>`** or inherited parent.

**PCI `interrupt-map`**: resolves to parent GIC cells via @ref page_device_pci_ofw — still ends in **`rt_ofw_map_irq`**.

---

## Provider requirements for OFW

| `ops` | Required for DT devices |
| --- | --- |
| **`irq_parse`** | Yes |
| **`irq_map`** | Yes |
| **`irq_mask` / `irq_unmask`** | Strongly recommended |

Without **`irq_map`**, **`rt_ofw_map_irq`** logs error and fails.

---

## `RT_PIC_OFW_DECLARE` template

```c
static rt_err_t my_ic_ofw_init(struct rt_ofw_node *np, const struct rt_ofw_node_id *id)
{
    /* map MMIO, fill my_pic.ops */
    rt_pic_linear_irq(&my_pic, NUM_LINES);
    rt_ofw_data(np) = &my_pic;
    return RT_EOK;
}

static const struct rt_ofw_node_id my_ic_ids[] = {
    { .compatible = "vendor,my-ic" },
    { /* sentinel */ },
};
RT_PIC_OFW_DECLARE(my_ic, my_ic_ids, my_ic_ofw_init);
```

Non-root: no **`rt_pic_add_traps`**; use parent ISR or cascade.

---

## Pitfalls

| Issue | Mitigation |
| --- | --- |
| **`rt_ofw_data` NULL** | Provider not probed — **`rt_platform_ofw_request`** before cast |
| **`irq_parse` returns error** | **`rt_ofw_map_irq`** fails — check cell count |
| Wrong **`interrupt-parent`** | Walk **`rt_ofw_find_irq_parent`** in OFW IRQ code |
| Mix hwirq / virtual in driver | Only use **`rt_dm_dev_get_irq`** return value |

## See also

- @ref page_device_pic_irq_domain
- @ref page_device_ofw_irq