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 #define IMX_AIPSTZ_OPACR0 0x40 15 #define IMX_AIPSTZ_OPACR1 0x44 16 #define IMX_AIPSTZ_OPACR2 0x48 17 #define IMX_AIPSTZ_OPACR3 0x4c 18 #define IMX_AIPSTZ_OPACR4 0x50 19 20 struct imx_aipstz_config { 21 u32 mpr0; 22 u32 opacr0; 23 u32 opacr1; 24 u32 opacr2; 25 u32 opacr3; 26 u32 opacr4; 27 }; 28 29 struct imx_aipstz_data { 30 void __iomem *base; 31 const struct imx_aipstz_config *default_cfg; 32 }; 33 34 static void imx_aipstz_apply_default(struct imx_aipstz_data *data) 35 { 36 writel(data->default_cfg->mpr0, data->base + IMX_AIPSTZ_MPR0); 37 writel(data->default_cfg->opacr0, data->base + IMX_AIPSTZ_OPACR0); 38 writel(data->default_cfg->opacr1, data->base + IMX_AIPSTZ_OPACR1); 39 writel(data->default_cfg->opacr2, data->base + IMX_AIPSTZ_OPACR2); 40 writel(data->default_cfg->opacr3, data->base + IMX_AIPSTZ_OPACR3); 41 writel(data->default_cfg->opacr4, data->base + IMX_AIPSTZ_OPACR4); 42 } 43 44 static const struct of_device_id imx_aipstz_match_table[] = { 45 { .compatible = "simple-bus", }, 46 { } 47 }; 48 49 static int imx_aipstz_probe(struct platform_device *pdev) 50 { 51 struct imx_aipstz_data *data; 52 53 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 54 if (!data) 55 return dev_err_probe(&pdev->dev, -ENOMEM, 56 "failed to allocate data memory\n"); 57 58 data->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); 59 if (IS_ERR(data->base)) 60 return dev_err_probe(&pdev->dev, -ENOMEM, 61 "failed to get/ioremap AC memory\n"); 62 63 data->default_cfg = of_device_get_match_data(&pdev->dev); 64 65 imx_aipstz_apply_default(data); 66 67 dev_set_drvdata(&pdev->dev, data); 68 69 pm_runtime_set_active(&pdev->dev); 70 devm_pm_runtime_enable(&pdev->dev); 71 72 return of_platform_populate(pdev->dev.of_node, imx_aipstz_match_table, 73 NULL, &pdev->dev); 74 } 75 76 static void imx_aipstz_remove(struct platform_device *pdev) 77 { 78 of_platform_depopulate(&pdev->dev); 79 } 80 81 static int imx_aipstz_runtime_resume(struct device *dev) 82 { 83 struct imx_aipstz_data *data = dev_get_drvdata(dev); 84 85 /* restore potentially lost configuration during domain power-off */ 86 imx_aipstz_apply_default(data); 87 88 return 0; 89 } 90 91 static const struct dev_pm_ops imx_aipstz_pm_ops = { 92 RUNTIME_PM_OPS(NULL, imx_aipstz_runtime_resume, NULL) 93 SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) 94 }; 95 96 /* 97 * following configuration is equivalent to: 98 * masters 0-7 => trusted for R/W + use AHB's HPROT[1] to det. privilege 99 */ 100 static const struct imx_aipstz_config imx8mp_aipstz_default_cfg = { 101 .mpr0 = 0x77777777, 102 }; 103 104 static const struct of_device_id imx_aipstz_of_ids[] = { 105 { .compatible = "fsl,imx8mp-aipstz", .data = &imx8mp_aipstz_default_cfg }, 106 { } 107 }; 108 MODULE_DEVICE_TABLE(of, imx_aipstz_of_ids); 109 110 static struct platform_driver imx_aipstz_of_driver = { 111 .probe = imx_aipstz_probe, 112 .remove = imx_aipstz_remove, 113 .driver = { 114 .name = "imx-aipstz", 115 .of_match_table = imx_aipstz_of_ids, 116 .pm = pm_ptr(&imx_aipstz_pm_ops), 117 }, 118 }; 119 module_platform_driver(imx_aipstz_of_driver); 120 121 MODULE_LICENSE("GPL"); 122 MODULE_DESCRIPTION("IMX secure AHB to IP Slave bus (AIPSTZ) bridge driver"); 123 MODULE_AUTHOR("Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>"); 124