summaryrefslogtreecommitdiff
path: root/documentation/6.components/device-driver/core/dm.md
blob: 132c72ecf705026d6bf947908cb46c69d8a3f7a5 (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
@page page_device_dm Device model helpers (dm.h)

# Device-side DM helpers

Header: `components/drivers/include/drivers/core/dm.h`. Implementation: `components/drivers/core/dm.c`.

These APIs sit **below** bus matching (`documentation/6.components/device-driver/core/bus.md`) and **above** subsystem drivers: a `probe` typically calls **`rt_dm_dev_iomap`**, **`rt_dm_dev_get_irq`**, and property readers, then registers the functional device (block, netdev, etc.).

## Driver / BSP quick notes

| Topic | Guidance |
| --- | --- |
| **`ofw_node` required** | Most helpers return **`-RT_ENOSYS`** or **NULL** when **`dev->ofw_node`** is unset—bind the node in platform probe or **`rt_dm_dev_bind_fwdata`**. |
| **IRQ needs PIC** | **`rt_dm_dev_get_irq*`** is compiled only with **`RT_USING_OFW`** and **`RT_USING_PIC`**. |
| **Property errors** | Inline **`rt_dm_dev_prop_read_u32`** returns **`RT_EOK`** only when the read count is **> 0**; negative counts are cast to **`rt_err_t`**—check return values. |
| **IDA names** | **`rt_dm_ida_alloc`** is per **`master_id`**—do not mix block and other masters on the same **`struct rt_dm_ida`**. |

## ID allocation (`rt_dm_ida`)

Used when a subsystem needs stable numeric suffixes (e.g. **`nvme0`**, partition children):

| API | Role |
| --- | --- |
| `rt_dm_ida_init(ida, id)` | Initialize bitmap + **`MASTER_ID_*`** from **`master_id.h`**. |
| `rt_dm_ida_alloc(ida)` | Allocate lowest free id in **0 … 255**. |
| `rt_dm_ida_take(ida, id)` | Reserve a specific id (returns **`RT_FALSE`** if taken). |
| `rt_dm_ida_free(ida, id)` | Release id. |
| `rt_dm_device_find(master_id, device_id)` | Find **`rt_device`** by master/slave id pair. |

## Device naming

| API | Role |
| --- | --- |
| `rt_dm_dev_set_name(dev, fmt, …)` | Format **`dev->parent.name`** (truncated to **`RT_NAME_MAX`**). |
| `rt_dm_dev_set_name_auto(dev, prefix)` | Append auto id from internal IDA. |
| `rt_dm_dev_get_name` / `rt_dm_dev_get_name_id` | Query current name / numeric suffix. |

## Address and MMIO

| API | Role |
| --- | --- |
| `rt_dm_dev_get_address_count` | Number of **`reg`** windows (OFW). |
| `rt_dm_dev_get_address` / `_by_name` | Physical base + size for index or named resource. |
| `rt_dm_dev_get_address_array` | Pack multiple regions into **`out_regs`**. |
| `rt_dm_dev_iomap` / `_by_name` | Map **`reg`** index or name to CPU virtual address. |

Without **`RT_USING_OFW`**, address/IOMAP calls do not resolve hardware description.

## Interrupts

| API | Role |
| --- | --- |
| `rt_dm_dev_get_irq_count` | Number of interrupt specifiers. |
| `rt_dm_dev_get_irq(dev, index)` | Linux-style interrupt index (**0** = first cell group). |
| `rt_dm_dev_get_irq_by_name` | Match **`interrupt-names`**. |

Install the handler in your driver after obtaining the vector; PIC maps OFW cells to a usable IRQ number.

## Firmware properties

Typed readers (arrays and index variants):

- **`rt_dm_dev_prop_read_u8/u16/u32/u64`** and **`_array_index`**
- **`rt_dm_dev_prop_read_string`** / **`_array_index`**
- **`rt_dm_dev_prop_read_bool`**
- **`rt_dm_dev_prop_count_of_*`**, **`rt_dm_dev_prop_index_of_string`**
- **`rt_dm_dev_get_prop_fuzzy_name`** — suffix/substring match for property names

**`rt_dm_dev_is_big_endian(dev)`** reflects the device endianness flag for MMIO accessors.

## Bind driver private data to OFW node

```c
void rt_dm_dev_bind_fwdata(rt_device_t dev, void *fw_np, void *data);
void rt_dm_dev_unbind_fwdata(rt_device_t dev, void *fw_np);
```

- Sets **`dev->ofw_node`** if it was NULL and assigns **`rt_ofw_data(np) = data`** (controller **`priv`**, **`rt_mbox_controller`**, etc.).
- Consumers resolve providers via **`rt_ofw_data(provider_np)`** after **`rt_platform_ofw_request`**.

## SMP

**`rt_dm_secondary_cpu_init()`** is the BSP hook for secondary CPUs in DM bring-up (weak/no-op if unused).

## Typical `probe` sequence

1. Match on **`compatible`** (platform bus).
2. **`rt_dm_dev_bind_fwdata(dev, np, priv)`**.
3. Optional **`rt_dm_power_domain_attach(dev, RT_TRUE)`** — see **`documentation/6.components/device-driver/core/power.md`**.
4. **`regs = rt_dm_dev_iomap(dev, 0)`**, **`irq = rt_dm_dev_get_irq(dev, 0)`**.
5. Read **`clocks` / `resets` / `dmas`** via property helpers or dedicated frameworks.
6. Register **`rt_device`** / subsystem object; on failure unwind in reverse order.

## Pitfalls

- **Double `bind_fwdata`** with conflicting **`data`** pointers confuses mailbox/clock clients—one owner per OFW node.
- **`iomap` without `reg`**: returns **NULL**; verify DTS and **`status = "okay"`**.
- **Assuming `prop_read_*` zero-fills**: on failure, output may be untouched—initialize locals first.

## See also

- Bus / driver binding: `documentation/6.components/device-driver/core/bus.md`
- Platform bus: `documentation/6.components/device-driver/platform/platform.md`
- OFW runtime: `documentation/6.components/device-driver/ofw/ofw.md`
- Power off / domains: `documentation/6.components/device-driver/core/power.md`, `documentation/6.components/device-driver/power_domain/power_domain.md`
- Header: `components/drivers/include/drivers/core/dm.h`