1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright 2025 NXP
4 */
5
6 #include <linux/module.h>
7 #include <linux/of.h>
8 #include <linux/of_platform.h>
9 #include <linux/platform_device.h>
10 #include <linux/pm_runtime.h>
11 #include <linux/regmap.h>
12
13 #define IMX_AIPSTZ_MPR0 0x0
14
15 struct imx_aipstz_config {
16 u32 mpr0;
17 };
18
19 struct imx_aipstz_data {
20 void __iomem *base;
21 const struct imx_aipstz_config *default_cfg;
22 };
23
imx_aipstz_apply_default(struct imx_aipstz_data * data)24 static void imx_aipstz_apply_default(struct imx_aipstz_data *data)
25 {
26 writel(data->default_cfg->mpr0, data->base + IMX_AIPSTZ_MPR0);
27 }
28
29 static const struct of_device_id imx_aipstz_match_table[] = {
30 { .compatible = "simple-bus", },
31 { }
32 };
33
imx_aipstz_probe(struct platform_device * pdev)34 static int imx_aipstz_probe(struct platform_device *pdev)
35 {
36 struct imx_aipstz_data *data;
37
38 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
39 if (!data)
40 return dev_err_probe(&pdev->dev, -ENOMEM,
41 "failed to allocate data memory\n");
42
43 data->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
44 if (IS_ERR(data->base))
45 return dev_err_probe(&pdev->dev, -ENOMEM,
46 "failed to get/ioremap AC memory\n");
47
48 data->default_cfg = of_device_get_match_data(&pdev->dev);
49
50 imx_aipstz_apply_default(data);
51
52 dev_set_drvdata(&pdev->dev, data);
53
54 pm_runtime_set_active(&pdev->dev);
55 devm_pm_runtime_enable(&pdev->dev);
56
57 return of_platform_populate(pdev->dev.of_node, imx_aipstz_match_table,
58 NULL, &pdev->dev);
59 }
60
imx_aipstz_remove(struct platform_device * pdev)61 static void imx_aipstz_remove(struct platform_device *pdev)
62 {
63 of_platform_depopulate(&pdev->dev);
64 }
65
imx_aipstz_runtime_resume(struct device * dev)66 static int imx_aipstz_runtime_resume(struct device *dev)
67 {
68 struct imx_aipstz_data *data = dev_get_drvdata(dev);
69
70 /* restore potentially lost configuration during domain power-off */
71 imx_aipstz_apply_default(data);
72
73 return 0;
74 }
75
76 static const struct dev_pm_ops imx_aipstz_pm_ops = {
77 RUNTIME_PM_OPS(NULL, imx_aipstz_runtime_resume, NULL)
78 SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
79 };
80
81 /*
82 * following configuration is equivalent to:
83 * masters 0-7 => trusted for R/W + use AHB's HPROT[1] to det. privilege
84 */
85 static const struct imx_aipstz_config imx8mp_aipstz_default_cfg = {
86 .mpr0 = 0x77777777,
87 };
88
89 static const struct of_device_id imx_aipstz_of_ids[] = {
90 { .compatible = "fsl,imx8mp-aipstz", .data = &imx8mp_aipstz_default_cfg },
91 { }
92 };
93 MODULE_DEVICE_TABLE(of, imx_aipstz_of_ids);
94
95 static struct platform_driver imx_aipstz_of_driver = {
96 .probe = imx_aipstz_probe,
97 .remove = imx_aipstz_remove,
98 .driver = {
99 .name = "imx-aipstz",
100 .of_match_table = imx_aipstz_of_ids,
101 .pm = pm_ptr(&imx_aipstz_pm_ops),
102 },
103 };
104 module_platform_driver(imx_aipstz_of_driver);
105
106 MODULE_LICENSE("GPL");
107 MODULE_DESCRIPTION("IMX secure AHB to IP Slave bus (AIPSTZ) bridge driver");
108 MODULE_AUTHOR("Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>");
109