1 // SPDX-License-Identifier: GPL-2.0-only
3 * RISC-V IOMMU as a platform device
5 * Copyright © 2023 FORTH-ICS/CARV
6 * Copyright © 2023-2024 Rivos Inc.
9 * Nick Kossifidis <mick@ics.forth.gr>
10 * Tomasz Jeznach <tjeznach@rivosinc.com>
13 #include <linux/kernel.h>
14 #include <linux/of_platform.h>
15 #include <linux/platform_device.h>
17 #include "iommu-bits.h"
20 static int riscv_iommu_platform_probe(struct platform_device
*pdev
)
22 struct device
*dev
= &pdev
->dev
;
23 struct riscv_iommu_device
*iommu
= NULL
;
24 struct resource
*res
= NULL
;
27 iommu
= devm_kzalloc(dev
, sizeof(*iommu
), GFP_KERNEL
);
32 iommu
->reg
= devm_platform_get_and_ioremap_resource(pdev
, 0, &res
);
33 if (IS_ERR(iommu
->reg
))
34 return dev_err_probe(dev
, PTR_ERR(iommu
->reg
),
35 "could not map register region\n");
37 dev_set_drvdata(dev
, iommu
);
39 /* Check device reported capabilities / features. */
40 iommu
->caps
= riscv_iommu_readq(iommu
, RISCV_IOMMU_REG_CAPABILITIES
);
41 iommu
->fctl
= riscv_iommu_readl(iommu
, RISCV_IOMMU_REG_FCTL
);
43 /* For now we only support WSI */
44 switch (FIELD_GET(RISCV_IOMMU_CAPABILITIES_IGS
, iommu
->caps
)) {
45 case RISCV_IOMMU_CAPABILITIES_IGS_WSI
:
46 case RISCV_IOMMU_CAPABILITIES_IGS_BOTH
:
49 return dev_err_probe(dev
, -ENODEV
,
50 "unable to use wire-signaled interrupts\n");
53 iommu
->irqs_count
= platform_irq_count(pdev
);
54 if (iommu
->irqs_count
<= 0)
55 return dev_err_probe(dev
, -ENODEV
,
56 "no IRQ resources provided\n");
57 if (iommu
->irqs_count
> RISCV_IOMMU_INTR_COUNT
)
58 iommu
->irqs_count
= RISCV_IOMMU_INTR_COUNT
;
60 for (vec
= 0; vec
< iommu
->irqs_count
; vec
++)
61 iommu
->irqs
[vec
] = platform_get_irq(pdev
, vec
);
63 /* Enable wire-signaled interrupts, fctl.WSI */
64 if (!(iommu
->fctl
& RISCV_IOMMU_FCTL_WSI
)) {
65 iommu
->fctl
|= RISCV_IOMMU_FCTL_WSI
;
66 riscv_iommu_writel(iommu
, RISCV_IOMMU_REG_FCTL
, iommu
->fctl
);
69 return riscv_iommu_init(iommu
);
72 static void riscv_iommu_platform_remove(struct platform_device
*pdev
)
74 riscv_iommu_remove(dev_get_drvdata(&pdev
->dev
));
77 static const struct of_device_id riscv_iommu_of_match
[] = {
78 {.compatible
= "riscv,iommu",},
82 static struct platform_driver riscv_iommu_platform_driver
= {
83 .probe
= riscv_iommu_platform_probe
,
84 .remove
= riscv_iommu_platform_remove
,
86 .name
= "riscv,iommu",
87 .of_match_table
= riscv_iommu_of_match
,
88 .suppress_bind_attrs
= true,
92 builtin_platform_driver(riscv_iommu_platform_driver
);