summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcopilot-swe-agent[bot] <[email protected]>2026-01-03 15:08:51 +0000
committercopilot-swe-agent[bot] <[email protected]>2026-01-03 15:08:51 +0000
commitb10da2d55442f6d93eb099beb5deeabd206965d6 (patch)
tree0ae030726767eeda2ecb3cb635fd6561182834a3
parentc7dd64349a83c85e08001e84834fe96c8bd88c4b (diff)
[documentation][device_driver_model] Add comprehensive PIC documentation (EN) - critical module 1/6copilot/create-device-driver-model-docs
Co-authored-by: BernardXiong <[email protected]>
-rw-r--r--documentation/6.components/device-driver/device_driver_model/pic/README.md966
1 files changed, 966 insertions, 0 deletions
diff --git a/documentation/6.components/device-driver/device_driver_model/pic/README.md b/documentation/6.components/device-driver/device_driver_model/pic/README.md
new file mode 100644
index 0000000000..1cc483f0f3
--- /dev/null
+++ b/documentation/6.components/device-driver/device_driver_model/pic/README.md
@@ -0,0 +1,966 @@
+# Platform Interrupt Controller (PIC) Framework
+
+## Introduction
+
+The Platform Interrupt Controller (PIC) framework provides a unified abstraction layer for managing hardware interrupts in RT-Thread's Device Driver Model. It supports various interrupt controllers including ARM GIC (Generic Interrupt Controller) v1/v2/v3, and provides comprehensive interrupt management capabilities including cascading, MSI support, and inter-processor interrupts (IPI).
+
+### Key Features
+
+- **Unified Interrupt Management**: Abstract interface for all interrupt controllers
+- **Interrupt Cascading**: Support for hierarchical interrupt routing
+- **CPU Affinity**: Configure which CPUs can handle specific interrupts
+- **Priority Control**: Set interrupt priorities for different IRQ sources
+- **Trigger Modes**: Support edge/level triggered interrupts
+- **IPI Support**: Inter-processor interrupt mechanisms for multi-core systems
+- **MSI/MSI-X**: Message Signaled Interrupts for PCIe devices
+- **Statistics**: Optional ISR execution time tracking
+
+### Architecture
+
+The PIC framework consists of:
+
+1. **PIC Core** (`pic.c`): Central interrupt management and routing
+2. **PIC IRQ** (`struct rt_pic_irq`): Individual interrupt descriptor
+3. **PIC Operations** (`struct rt_pic_ops`): Hardware-specific callbacks
+4. **ISR Management**: Interrupt Service Routine registration and execution
+
+```
+┌──────────────────────────────────────────┐
+│ Application/Drivers │
+│ (Call rt_pic_attach_irq, enable, etc.) │
+└──────────────────┬───────────────────────┘
+ │
+┌──────────────────▼───────────────────────┐
+│ PIC Framework (pic.c) │
+│ - IRQ allocation & management │
+│ - ISR dispatch │
+│ - Cascading support │
+│ - Affinity & priority management │
+└──────────────────┬───────────────────────┘
+ │
+┌──────────────────▼───────────────────────┐
+│ PIC Operations (rt_pic_ops) │
+│ - irq_enable/disable │
+│ - irq_mask/unmask │
+│ - irq_set_priority │
+│ - irq_set_affinity │
+│ - irq_send_ipi (for multi-core) │
+└──────────────────┬───────────────────────┘
+ │
+┌──────────────────▼───────────────────────┐
+│ Hardware Interrupt Controller │
+│ (GICv2, GICv3, etc.) │
+└──────────────────────────────────────────┘
+```
+
+## Kconfig Configuration
+
+### Location in menuconfig
+
+```
+RT-Thread Components
+ └── Device Drivers
+ └── Using Device Driver Model with DeviceTree (RT_USING_DM)
+ └── Using Programmable Interrupt Controller (PIC) (RT_USING_PIC)
+```
+
+### Configuration Options
+
+#### RT_USING_PIC
+- **Type**: bool
+- **Default**: n
+- **Description**: Enable the Platform Interrupt Controller framework
+- **Dependencies**: RT_USING_DM, RT_USING_ADT, RT_USING_ADT_BITMAP
+- **Purpose**: Main switch for PIC support
+
+#### RT_USING_PIC_STATISTICS
+- **Type**: bool
+- **Default**: n
+- **Description**: Enable ISR execution time statistics
+- **Dependencies**: RT_USING_PIC, RT_USING_KTIME, RT_USING_INTERRUPT_INFO
+- **Purpose**: Track min/max/average IRQ handling times for profiling
+
+#### MAX_HANDLERS
+- **Type**: int
+- **Range**: 1-4294967294
+- **Default**: 256
+- **Description**: Maximum number of interrupt handlers the system can register
+- **Purpose**: Defines the size of the global IRQ hash table
+
+#### RT_PIC_ARM_GIC
+- **Type**: bool
+- **Default**: n
+- **Description**: Enable ARM Generic Interrupt Controller v1/v2 support
+- **Dependencies**: RT_USING_PIC, RT_USING_OFW
+- **Purpose**: Support for ARM GICv1/v2 hardware
+
+#### RT_PIC_ARM_GIC_V2M
+- **Type**: bool
+- **Default**: n
+- **Description**: Enable ARM GIC V2M (MSI support for GICv2)
+- **Dependencies**: RT_PIC_ARM_GIC, RT_PCI_MSI, RT_USING_OFW
+- **Purpose**: Message Signaled Interrupts on GICv2
+
+#### RT_PIC_ARM_GIC_V3
+- **Type**: bool
+- **Default**: n
+- **Description**: Enable ARM Generic Interrupt Controller v3 support
+- **Dependencies**: RT_USING_PIC, RT_USING_OFW
+- **Purpose**: Support for ARM GICv3 hardware
+
+#### RT_PIC_ARM_GIC_V3_ITS
+- **Type**: bool
+- **Default**: n
+- **Description**: Enable ARM GICv3 ITS (Interrupt Translation Service)
+- **Dependencies**: RT_PIC_ARM_GIC_V3, RT_PCI_MSI, RT_USING_OFW, RT_USING_ADT_REF
+- **Purpose**: MSI/MSI-X support for GICv3 via ITS
+
+#### RT_PIC_ARM_GIC_V3_ITS_IRQ_MAX
+- **Type**: int
+- **Default**: 127 (64-bit), 63 (32-bit)
+- **Description**: Maximum IRQ number for GICv3 ITS
+- **Dependencies**: RT_PIC_ARM_GIC_V3_ITS
+- **Purpose**: Limit ITS-managed interrupt range
+
+## Device Tree Bindings
+
+### GICv2 Example
+
+```dts
+gic: interrupt-controller@08000000 {
+ compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <1>;
+ interrupt-controller;
+ reg = <0x08000000 0x1000>, /* Distributor */
+ <0x08010000 0x1000>; /* CPU interface */
+};
+
+/* Consumer example: UART using GIC */
+uart0: serial@09000000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x09000000 0x1000>;
+ interrupts = <0 5 4>; /* SPI, IRQ 5, IRQ_TYPE_LEVEL_HIGH */
+ interrupt-parent = <&gic>;
+};
+```
+
+### GICv3 Example
+
+```dts
+gic: interrupt-controller@08000000 {
+ compatible = "arm,gic-v3";
+ #interrupt-cells = <3>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-controller;
+ reg = <0x0 0x08000000 0 0x10000>, /* Distributor */
+ <0x0 0x080A0000 0 0xF60000>; /* Redistributor */
+
+ gic_its: msi-controller@08020000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x0 0x08020000 0 0x20000>;
+ };
+};
+
+/* Consumer with interrupts */
+timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <1 13 0xff08>, /* Physical Secure PPI */
+ <1 14 0xff08>, /* Physical Non-Secure PPI */
+ <1 11 0xff08>, /* Virtual PPI */
+ <1 10 0xff08>; /* Hypervisor PPI */
+ interrupt-parent = <&gic>;
+};
+```
+
+### Interrupt Cells Explanation
+
+For ARM GIC, `interrupts` property has 3 cells:
+1. **Type**: 0 = SPI (Shared Peripheral Interrupt), 1 = PPI (Private Peripheral Interrupt)
+2. **Number**: IRQ number within the type (SPI: 0-987, PPI: 0-15)
+3. **Flags**: Trigger type and priority
+ - `IRQ_TYPE_EDGE_RISING` = 1
+ - `IRQ_TYPE_EDGE_FALLING` = 2
+ - `IRQ_TYPE_LEVEL_HIGH` = 4
+ - `IRQ_TYPE_LEVEL_LOW` = 8
+
+## Application API
+
+### IRQ Attachment
+
+#### rt_pic_attach_irq
+
+```c
+rt_err_t rt_pic_attach_irq(int irq, rt_isr_handler_t handler, void *uid,
+ const char *name, int flags);
+```
+
+Attach an interrupt service routine to an IRQ.
+
+**Parameters:**
+- `irq`: IRQ number to attach to
+- `handler`: ISR function pointer `void (*handler)(int irq, void *param)`
+- `uid`: User-defined parameter passed to the handler
+- `name`: Descriptive name for the interrupt (for debugging)
+- `flags`: Interrupt flags (currently unused, pass 0)
+
+**Returns:**
+- `RT_EOK`: Success
+- `-RT_EINVAL`: Invalid IRQ number
+- `-RT_ENOMEM`: Out of memory
+
+**Example:**
+```c
+void uart_isr(int irq, void *param)
+{
+ struct uart_device *uart = (struct uart_device *)param;
+ /* Handle interrupt */
+ rt_kprintf("UART interrupt occurred\n");
+}
+
+/* In driver probe function */
+static rt_err_t uart_probe(struct rt_platform_device *pdev)
+{
+ struct uart_device *uart;
+ int irq;
+
+ /* Get IRQ from device tree */
+ irq = rt_platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ /* Attach ISR */
+ rt_err_t ret = rt_pic_attach_irq(irq, uart_isr, uart, "uart0", 0);
+ if (ret != RT_EOK)
+ return ret;
+
+ /* Enable the interrupt */
+ rt_pic_irq_enable(irq);
+
+ return RT_EOK;
+}
+```
+
+#### rt_pic_detach_irq
+
+```c
+rt_err_t rt_pic_detach_irq(int irq, void *uid);
+```
+
+Detach an interrupt service routine from an IRQ.
+
+**Parameters:**
+- `irq`: IRQ number
+- `uid`: Must match the `uid` passed to `rt_pic_attach_irq`
+
+**Returns:**
+- `RT_EOK`: Success
+- `-RT_EINVAL`: Invalid IRQ or UID mismatch
+
+### IRQ Control
+
+#### rt_pic_irq_enable / rt_pic_irq_disable
+
+```c
+void rt_pic_irq_enable(int irq);
+void rt_pic_irq_disable(int irq);
+```
+
+Enable or disable an interrupt at the PIC level.
+
+**Parameters:**
+- `irq`: IRQ number
+
+**Example:**
+```c
+/* Enable interrupt before starting operation */
+rt_pic_irq_enable(uart_irq);
+
+/* Disable during critical sections */
+rt_pic_irq_disable(uart_irq);
+/* ... critical code ... */
+rt_pic_irq_enable(uart_irq);
+```
+
+#### rt_pic_irq_mask / rt_pic_irq_unmask
+
+```c
+void rt_pic_irq_mask(int irq);
+void rt_pic_irq_unmask(int irq);
+```
+
+Mask or unmask an interrupt (similar to enable/disable but may have different semantics on some hardware).
+
+**Parameters:**
+- `irq`: IRQ number
+
+#### rt_pic_irq_ack
+
+```c
+void rt_pic_irq_ack(int irq);
+```
+
+Acknowledge an interrupt (required for some edge-triggered interrupts).
+
+**Parameters:**
+- `irq`: IRQ number
+
+#### rt_pic_irq_eoi
+
+```c
+void rt_pic_irq_eoi(int irq);
+```
+
+Signal End-Of-Interrupt to the PIC.
+
+**Parameters:**
+- `irq`: IRQ number
+
+### Priority Management
+
+#### rt_pic_irq_set_priority
+
+```c
+rt_err_t rt_pic_irq_set_priority(int irq, rt_uint32_t priority);
+```
+
+Set the priority of an interrupt.
+
+**Parameters:**
+- `irq`: IRQ number
+- `priority`: Priority value (lower = higher priority typically)
+
+**Returns:**
+- `RT_EOK`: Success
+- `-RT_ENOSYS`: Not supported by hardware
+
+**Example:**
+```c
+/* Set high priority for critical timer interrupt */
+rt_pic_irq_set_priority(timer_irq, 0);
+
+/* Set lower priority for UART */
+rt_pic_irq_set_priority(uart_irq, 128);
+```
+
+#### rt_pic_irq_get_priority
+
+```c
+rt_uint32_t rt_pic_irq_get_priority(int irq);
+```
+
+Get the current priority of an interrupt.
+
+**Parameters:**
+- `irq`: IRQ number
+
+**Returns:** Current priority value
+
+### CPU Affinity (Multi-core)
+
+#### rt_pic_irq_set_affinity
+
+```c
+rt_err_t rt_pic_irq_set_affinity(int irq, rt_bitmap_t *affinity);
+```
+
+Set which CPUs can handle a specific interrupt.
+
+**Parameters:**
+- `irq`: IRQ number
+- `affinity`: Bitmap of allowed CPUs
+
+**Returns:**
+- `RT_EOK`: Success
+- `-RT_ENOSYS`: Not supported
+
+**Example:**
+```c
+RT_IRQ_AFFINITY_DECLARE(cpumask);
+
+/* Route interrupt to CPU 0 and CPU 2 */
+rt_bitmap_clear(cpumask, RT_BITMAP_LEN(RT_CPUS_NR));
+RT_IRQ_AFFINITY_SET(cpumask, 0);
+RT_IRQ_AFFINITY_SET(cpumask, 2);
+rt_pic_irq_set_affinity(eth_irq, cpumask);
+```
+
+#### rt_pic_irq_get_affinity
+
+```c
+rt_err_t rt_pic_irq_get_affinity(int irq, rt_bitmap_t *out_affinity);
+```
+
+Get the current CPU affinity for an interrupt.
+
+**Parameters:**
+- `irq`: IRQ number
+- `out_affinity`: Output bitmap
+
+**Returns:**
+- `RT_EOK`: Success
+- `-RT_EINVAL`: Invalid IRQ
+
+### Trigger Mode
+
+#### rt_pic_irq_set_triger_mode
+
+```c
+rt_err_t rt_pic_irq_set_triger_mode(int irq, rt_uint32_t mode);
+```
+
+Set the trigger mode for an interrupt.
+
+**Parameters:**
+- `irq`: IRQ number
+- `mode`: Trigger mode
+ - `RT_IRQ_MODE_EDGE_RISING`: Rising edge
+ - `RT_IRQ_MODE_EDGE_FALLING`: Falling edge
+ - `RT_IRQ_MODE_EDGE_BOTH`: Both edges
+ - `RT_IRQ_MODE_LEVEL_HIGH`: High level
+ - `RT_IRQ_MODE_LEVEL_LOW`: Low level
+
+**Returns:**
+- `RT_EOK`: Success
+- `-RT_ENOSYS`: Not supported
+
+#### rt_pic_irq_get_triger_mode
+
+```c
+rt_uint32_t rt_pic_irq_get_triger_mode(int irq);
+```
+
+Get the current trigger mode.
+
+**Parameters:**
+- `irq`: IRQ number
+
+**Returns:** Current trigger mode
+
+### Inter-Processor Interrupts (IPI)
+
+#### rt_pic_irq_send_ipi
+
+```c
+void rt_pic_irq_send_ipi(int irq, rt_bitmap_t *cpumask);
+```
+
+Send an inter-processor interrupt to specified CPUs.
+
+**Parameters:**
+- `irq`: IPI number (typically in range 0-15)
+- `cpumask`: Bitmap of target CPUs
+
+**Example:**
+```c
+RT_IRQ_AFFINITY_DECLARE(targets);
+
+/* Send IPI to CPU 1 */
+rt_bitmap_clear(targets, RT_BITMAP_LEN(RT_CPUS_NR));
+RT_IRQ_AFFINITY_SET(targets, 1);
+rt_pic_irq_send_ipi(0, targets); /* IPI 0 */
+```
+
+### State Management
+
+#### rt_pic_irq_set_state / rt_pic_irq_get_state
+
+```c
+rt_err_t rt_pic_irq_set_state(int irq, int type, rt_bool_t state);
+rt_err_t rt_pic_irq_get_state(int irq, int type, rt_bool_t *out_state);
+```
+
+Set or get interrupt state (pending, active, masked).
+
+**Parameters:**
+- `irq`: IRQ number
+- `type`: State type
+ - `RT_IRQ_STATE_PENDING`: Interrupt is pending
+ - `RT_IRQ_STATE_ACTIVE`: Interrupt is being serviced
+ - `RT_IRQ_STATE_MASKED`: Interrupt is masked
+- `state` / `out_state`: State value
+
+**Returns:**
+- `RT_EOK`: Success
+- `-RT_ENOSYS`: Not supported
+
+## Complete Driver Example: GPIO Interrupt Handler
+
+```c
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <drivers/pic.h>
+#include <drivers/platform.h>
+
+struct gpio_int_device
+{
+ struct rt_device parent;
+ void *base;
+ int irq;
+ rt_uint32_t pin_mask;
+};
+
+/* GPIO interrupt service routine */
+static void gpio_isr(int irq, void *param)
+{
+ struct gpio_int_device *gpio = (struct gpio_int_device *)param;
+ rt_uint32_t status;
+
+ /* Read interrupt status register */
+ status = readl(gpio->base + GPIO_INT_STATUS);
+
+ /* Clear interrupt */
+ writel(status, gpio->base + GPIO_INT_CLEAR);
+
+ /* Handle each pin */
+ for (int i = 0; i < 32; i++)
+ {
+ if (status & (1 << i))
+ {
+ rt_kprintf("GPIO pin %d triggered\n", i);
+ /* Notify application or trigger event */
+ }
+ }
+
+ /* Send EOI to PIC */
+ rt_pic_irq_eoi(irq);
+}
+
+static rt_err_t gpio_int_probe(struct rt_platform_device *pdev)
+{
+ struct gpio_int_device *gpio;
+ struct rt_device *dev = &pdev->parent;
+ int irq;
+ rt_err_t ret;
+
+ gpio = rt_calloc(1, sizeof(*gpio));
+ if (!gpio)
+ return -RT_ENOMEM;
+
+ /* Map registers */
+ gpio->base = rt_dm_dev_iomap(dev, 0);
+ if (!gpio->base)
+ {
+ ret = -RT_ERROR;
+ goto err_free;
+ }
+
+ /* Get IRQ from device tree */
+ irq = rt_platform_get_irq(pdev, 0);
+ if (irq < 0)
+ {
+ ret = irq;
+ goto err_iounmap;
+ }
+ gpio->irq = irq;
+
+ /* Set interrupt trigger mode - rising edge */
+ ret = rt_pic_irq_set_triger_mode(irq, RT_IRQ_MODE_EDGE_RISING);
+ if (ret != RT_EOK && ret != -RT_ENOSYS)
+ {
+ rt_kprintf("Failed to set trigger mode: %d\n", ret);
+ goto err_iounmap;
+ }
+
+ /* Set interrupt priority (high priority) */
+ ret = rt_pic_irq_set_priority(irq, 32);
+ if (ret != RT_EOK && ret != -RT_ENOSYS)
+ {
+ rt_kprintf("Failed to set priority: %d\n", ret);
+ }
+
+ /* Attach interrupt handler */
+ ret = rt_pic_attach_irq(irq, gpio_isr, gpio, "gpio-int", 0);
+ if (ret != RT_EOK)
+ {
+ rt_kprintf("Failed to attach IRQ: %d\n", ret);
+ goto err_iounmap;
+ }
+
+ /* Configure GPIO pins for interrupt */
+ writel(0xFFFFFFFF, gpio->base + GPIO_INT_ENABLE); /* Enable all pins */
+ writel(0x00000000, gpio->base + GPIO_INT_MASK); /* Unmask all */
+
+ /* Enable interrupt at PIC level */
+ rt_pic_irq_enable(irq);
+
+ /* Store device data */
+ rt_platform_set_drvdata(pdev, gpio);
+
+ rt_kprintf("GPIO interrupt controller probed successfully (IRQ %d)\n", irq);
+ return RT_EOK;
+
+err_iounmap:
+ rt_dm_dev_iounmap(dev, gpio->base);
+err_free:
+ rt_free(gpio);
+ return ret;
+}
+
+static rt_err_t gpio_int_remove(struct rt_platform_device *pdev)
+{
+ struct gpio_int_device *gpio = rt_platform_get_drvdata(pdev);
+
+ /* Disable interrupt */
+ rt_pic_irq_disable(gpio->irq);
+
+ /* Detach handler */
+ rt_pic_detach_irq(gpio->irq, gpio);
+
+ /* Disable GPIO interrupts */
+ writel(0x00000000, gpio->base + GPIO_INT_ENABLE);
+
+ /* Cleanup */
+ rt_dm_dev_iounmap(&pdev->parent, gpio->base);
+ rt_free(gpio);
+
+ return RT_EOK;
+}
+
+static const struct rt_ofw_node_id gpio_int_ofw_ids[] =
+{
+ { .compatible = "myvendor,gpio-interrupt-controller" },
+ { /* sentinel */ }
+};
+
+static struct rt_platform_driver gpio_int_driver =
+{
+ .name = "gpio-int",
+ .ids = gpio_int_ofw_ids,
+ .probe = gpio_int_probe,
+ .remove = gpio_int_remove,
+};
+
+static int gpio_int_drv_register(void)
+{
+ rt_platform_driver_register(&gpio_int_driver);
+ return 0;
+}
+INIT_DEVICE_EXPORT(gpio_int_drv_register);
+```
+
+## PIC Provider Implementation
+
+For implementing a custom interrupt controller driver:
+
+```c
+#include <rtthread.h>
+#include <drivers/pic.h>
+
+struct my_pic_data
+{
+ void *base;
+ struct rt_pic pic;
+};
+
+static void my_pic_irq_enable(struct rt_pic_irq *pirq)
+{
+ struct rt_pic *pic = pirq->pic;
+ struct my_pic_data *priv = pic->priv_data;
+
+ /* Enable interrupt in hardware */
+ writel(1 << pirq->hwirq, priv->base + MY_PIC_ENABLE_REG);
+}
+
+static void my_pic_irq_disable(struct rt_pic_irq *pirq)
+{
+ struct rt_pic *pic = pirq->pic;
+ struct my_pic_data *priv = pic->priv_data;
+
+ /* Disable interrupt in hardware */
+ writel(1 << pirq->hwirq, priv->base + MY_PIC_DISABLE_REG);
+}
+
+static void my_pic_irq_ack(struct rt_pic_irq *pirq)
+{
+ struct rt_pic *pic = pirq->pic;
+ struct my_pic_data *priv = pic->priv_data;
+
+ /* Acknowledge interrupt */
+ writel(1 << pirq->hwirq, priv->base + MY_PIC_ACK_REG);
+}
+
+static void my_pic_irq_eoi(struct rt_pic_irq *pirq)
+{
+ struct rt_pic *pic = pirq->pic;
+ struct my_pic_data *priv = pic->priv_data;
+
+ /* Send EOI signal */
+ writel(1 << pirq->hwirq, priv->base + MY_PIC_EOI_REG);
+}
+
+static rt_err_t my_pic_irq_set_priority(struct rt_pic_irq *pirq, rt_uint32_t priority)
+{
+ struct rt_pic *pic = pirq->pic;
+ struct my_pic_data *priv = pic->priv_data;
+
+ /* Set priority in hardware register */
+ writel(priority, priv->base + MY_PIC_PRIORITY_REG(pirq->hwirq));
+
+ return RT_EOK;
+}
+
+static int my_pic_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode)
+{
+ int irq;
+
+ /* Allocate software IRQ number */
+ irq = pic->irq_start + hwirq;
+
+ /* Configure trigger mode in hardware */
+ /* ... */
+
+ return irq;
+}
+
+static rt_err_t my_pic_irq_parse(struct rt_pic *pic, struct rt_ofw_cell_args *args,
+ struct rt_pic_irq *out_pirq)
+{
+ if (args->args_count != 2)
+ return -RT_EINVAL;
+
+ /* Parse: <hwirq trigger_type> */
+ out_pirq->hwirq = args->args[0];
+ out_pirq->mode = args->args[1];
+
+ return RT_EOK;
+}
+
+static const struct rt_pic_ops my_pic_ops =
+{
+ .name = "my-pic",
+ .irq_enable = my_pic_irq_enable,
+ .irq_disable = my_pic_irq_disable,
+ .irq_ack = my_pic_irq_ack,
+ .irq_eoi = my_pic_irq_eoi,
+ .irq_set_priority = my_pic_irq_set_priority,
+ .irq_map = my_pic_irq_map,
+ .irq_parse = my_pic_irq_parse,
+};
+
+static rt_err_t my_pic_probe(struct rt_platform_device *pdev)
+{
+ struct my_pic_data *priv;
+ rt_err_t ret;
+
+ priv = rt_calloc(1, sizeof(*priv));
+ if (!priv)
+ return -RT_ENOMEM;
+
+ /* Map registers */
+ priv->base = rt_dm_dev_iomap(&pdev->parent, 0);
+ if (!priv->base)
+ {
+ ret = -RT_ERROR;
+ goto err_free;
+ }
+
+ /* Initialize PIC structure */
+ priv->pic.ops = &my_pic_ops;
+ priv->pic.priv_data = priv;
+
+ /* Allocate IRQ range (32 interrupts) */
+ ret = rt_pic_linear_irq(&priv->pic, 32);
+ if (ret != RT_EOK)
+ {
+ rt_kprintf("Failed to allocate IRQs\n");
+ goto err_iounmap;
+ }
+
+ /* Configure each IRQ */
+ for (int i = 0; i < 32; i++)
+ {
+ rt_pic_config_irq(&priv->pic, i, i); /* Map 1:1 */
+ }
+
+ /* Call user extensions if needed */
+ rt_pic_user_extends(&priv->pic);
+
+ /* Initialize hardware */
+ writel(0xFFFFFFFF, priv->base + MY_PIC_DISABLE_REG); /* Disable all */
+ writel(0xFFFFFFFF, priv->base + MY_PIC_CLEAR_REG); /* Clear pending */
+
+ rt_platform_set_drvdata(pdev, priv);
+ rt_kprintf("My PIC initialized with %d IRQs\n", 32);
+
+ return RT_EOK;
+
+err_iounmap:
+ rt_dm_dev_iounmap(&pdev->parent, priv->base);
+err_free:
+ rt_free(priv);
+ return ret;
+}
+
+static const struct rt_ofw_node_id my_pic_ofw_ids[] =
+{
+ { .compatible = "myvendor,my-pic" },
+ { /* sentinel */ }
+};
+
+static struct rt_platform_driver my_pic_driver =
+{
+ .name = "my-pic",
+ .ids = my_pic_ofw_ids,
+ .probe = my_pic_probe,
+};
+
+RT_PIC_OFW_DECLARE(my_pic, my_pic_ofw_ids, my_pic_probe);
+```
+
+## Best Practices
+
+### For Interrupt Consumers
+
+1. **Always disable interrupts during cleanup**:
+ ```c
+ rt_pic_irq_disable(irq);
+ rt_pic_detach_irq(irq, uid);
+ ```
+
+2. **Handle spurious interrupts**:
+ ```c
+ static void my_isr(int irq, void *param)
+ {
+ if (!check_interrupt_source())
+ return; /* Spurious interrupt */
+
+ /* Handle interrupt */
+ }
+ ```
+
+3. **Use EOI for level-triggered interrupts**:
+ ```c
+ static void my_isr(int irq, void *param)
+ {
+ handle_interrupt();
+ clear_interrupt_source(); /* Clear in device first */
+ rt_pic_irq_eoi(irq); /* Then send EOI to PIC */
+ }
+ ```
+
+4. **Set appropriate priorities**:
+ - Critical real-time interrupts: 0-31 (highest)
+ - Normal device interrupts: 32-127
+ - Low-priority interrupts: 128-255
+
+5. **Consider CPU affinity on multi-core systems**:
+ ```c
+ /* Pin network interrupt to CPU 0 for better cache locality */
+ RT_IRQ_AFFINITY_DECLARE(mask);
+ rt_bitmap_clear(mask, RT_BITMAP_LEN(RT_CPUS_NR));
+ RT_IRQ_AFFINITY_SET(mask, 0);
+ rt_pic_irq_set_affinity(net_irq, mask);
+ ```
+
+### For PIC Providers
+
+1. **Implement minimum required operations**:
+ - `irq_enable`, `irq_disable`
+ - `irq_ack` or `irq_eoi`
+ - `irq_map`, `irq_parse`
+
+2. **Use `rt_pic_linear_irq` for simple IRQ allocation**:
+ ```c
+ ret = rt_pic_linear_irq(pic, num_irqs);
+ ```
+
+3. **Support cascading for hierarchical interrupt controllers**:
+ ```c
+ struct rt_pic_irq *parent_pirq = rt_pic_find_pirq(parent_pic, parent_irq);
+ rt_pic_cascade(child_pirq, parent_irq);
+ ```
+
+4. **Implement statistics support** (optional):
+ ```c
+ #ifdef RT_USING_PIC_STATISTICS
+ /* Framework tracks this automatically */
+ #endif
+ ```
+
+## Troubleshooting
+
+### Interrupt Not Firing
+
+1. **Check interrupt is enabled**:
+ ```c
+ rt_pic_irq_enable(irq);
+ ```
+
+2. **Verify device interrupt is not masked**:
+ - Check device-specific interrupt enable registers
+ - Ensure interrupt source is configured correctly
+
+3. **Confirm device tree configuration**:
+ - Verify `interrupts` property
+ - Check `interrupt-parent` is correct
+
+4. **Check trigger mode**:
+ - Edge vs. level triggered
+ - Active high vs. active low
+
+### Interrupt Storms
+
+1. **Always acknowledge/clear interrupts**:
+ ```c
+ /* Clear source BEFORE EOI */
+ clear_device_interrupt();
+ rt_pic_irq_eoi(irq);
+ ```
+
+2. **For level-triggered, clear condition**:
+ - Level-triggered interrupts re-assert if condition persists
+ - Must clear the underlying condition in the device
+
+### ISR Not Called
+
+1. **Verify IRQ number**:
+ ```c
+ rt_kprintf("Attached to IRQ %d\n", irq);
+ ```
+
+2. **Check MAX_HANDLERS**:
+ - Ensure IRQ < MAX_HANDLERS
+
+3. **Confirm attachment succeeded**:
+ ```c
+ ret = rt_pic_attach_irq(irq, isr, param, "name", 0);
+ if (ret != RT_EOK)
+ rt_kprintf("Attach failed: %d\n", ret);
+ ```
+
+### Priority/Affinity Not Working
+
+- Some PICs don't support priority or affinity
+- Check return value for `-RT_ENOSYS`
+- Verify hardware capabilities
+
+## Performance Considerations
+
+1. **Keep ISRs short**: Defer heavy processing to threads
+2. **Minimize register access**: Cache PIC state when possible
+3. **Use shared interrupts carefully**: Check device status first
+4. **Consider IRQ coalescing**: For high-rate interrupt sources
+5. **Profile with statistics**:
+ ```c
+ /* Enable RT_USING_PIC_STATISTICS */
+ /* Check /proc or debug output for timing data */
+ ```
+
+## Related Modules
+
+- **OFW (Device Tree)**: IRQ parsing and `interrupt-parent` resolution
+- **Platform Device**: `rt_platform_get_irq` for IRQ retrieval
+- **PCI**: MSI/MSI-X interrupt support via PIC
+- **Pinctrl**: GPIO interrupt configuration
+
+## References
+
+- ARM GIC Architecture Specification
+- Device Tree Interrupt Mapping Specification
+- RT-Thread Interrupt Management Documentation
+- `components/drivers/pic/pic.c` - Core implementation
+- `components/drivers/include/drivers/pic.h` - API header