]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - rpmsg/rpmsg.git/blob - drivers/soc/ti/pruss.c
soc: ti: pruss: Add support for PRU-ICSS subsystems on 66AK2G SoC
[rpmsg/rpmsg.git] / drivers / soc / ti / pruss.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * PRU-ICSS platform driver for various TI SoCs
4  *
5  * Copyright (C) 2014-2019 Texas Instruments Incorporated - http://www.ti.com/
6  *      Suman Anna <s-anna@ti.com>
7  *      Andrew F. Davis <afd@ti.com>
8  */
10 #include <linux/dma-mapping.h>
11 #include <linux/io.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/module.h>
14 #include <linux/of_address.h>
15 #include <linux/of_device.h>
16 #include <linux/pruss_driver.h>
18 /**
19  * struct pruss_private_data - PRUSS driver private data
20  * @has_no_sharedram: flag to indicate the absence of PRUSS Shared Data RAM
21  */
22 struct pruss_private_data {
23         bool has_no_sharedram;
24 };
26 /**
27  * struct pruss_match_private_data - private data to handle multiple instances
28  * @device_name: device name of the PRUSS instance
29  * @priv_data: PRUSS driver private data for this PRUSS instance
30  */
31 struct pruss_match_private_data {
32         const char *device_name;
33         const struct pruss_private_data *priv_data;
34 };
36 static const
37 struct pruss_private_data *pruss_get_private_data(struct platform_device *pdev)
38 {
39         const struct pruss_match_private_data *data;
41         if (!of_device_is_compatible(pdev->dev.of_node, "ti,am4376-pruss"))
42                 return NULL;
44         data = of_device_get_match_data(&pdev->dev);
45         for (; data && data->device_name; data++) {
46                 if (!strcmp(dev_name(&pdev->dev), data->device_name))
47                         return data->priv_data;
48         }
50         return ERR_PTR(-ENODEV);
51 }
53 static int pruss_probe(struct platform_device *pdev)
54 {
55         struct device *dev = &pdev->dev;
56         struct device_node *node = dev->of_node;
57         struct device_node *np;
58         struct pruss *pruss;
59         struct resource res;
60         int ret, i, index;
61         const struct pruss_private_data *data;
62         const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" };
64         if (!node) {
65                 dev_err(dev, "Non-DT platform device not supported\n");
66                 return -ENODEV;
67         }
69         data = pruss_get_private_data(pdev);
70         if (IS_ERR(data)) {
71                 dev_err(dev, "missing private data\n");
72                 return -ENODEV;
73         }
75         ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
76         if (ret) {
77                 dev_err(dev, "dma_set_coherent_mask: %d\n", ret);
78                 return ret;
79         }
81         pruss = devm_kzalloc(dev, sizeof(*pruss), GFP_KERNEL);
82         if (!pruss)
83                 return -ENOMEM;
85         pruss->dev = dev;
87         np = of_get_child_by_name(node, "cfg");
88         if (!np) {
89                 dev_err(dev, "%pOF is missing cfg node\n", np);
90                 return -ENODEV;
91         }
93         pruss->cfg = syscon_node_to_regmap(np);
94         of_node_put(np);
95         if (IS_ERR(pruss->cfg))
96                 return -ENODEV;
98         np = of_get_child_by_name(node, "iep");
99         if (!np) {
100                 dev_err(dev, "%pOF is missing iep node\n", np);
101                 return -ENODEV;
102         }
104         pruss->iep = syscon_node_to_regmap(np);
105         of_node_put(np);
106         if (IS_ERR(pruss->iep))
107                 return -ENODEV;
109         np = of_get_child_by_name(node, "mii-rt");
110         if (!np) {
111                 dev_err(dev, "%pOF is missing mii-rt node\n", np);
112                 return -ENODEV;
113         }
115         pruss->mii_rt = syscon_node_to_regmap(np);
116         of_node_put(np);
117         if (IS_ERR(pruss->mii_rt))
118                 return -ENODEV;
120         np = of_get_child_by_name(node, "memories");
121         if (!np) {
122                 dev_err(dev, "%pOF is missing memories node\n", np);
123                 return -ENODEV;
124         }
126         for (i = 0; i < ARRAY_SIZE(mem_names); i++) {
127                 if (data && data->has_no_sharedram &&
128                     !strcmp(mem_names[i], "shrdram2"))
129                         continue;
131                 index = of_property_match_string(np, "reg-names", mem_names[i]);
132                 if (index < 0) {
133                         of_node_put(np);
134                         return index;
135                 }
137                 if (of_address_to_resource(np, index, &res)) {
138                         of_node_put(np);
139                         return -EINVAL;
140                 }
142                 pruss->mem_regions[i].va = devm_ioremap(dev, res.start,
143                                                         resource_size(&res));
144                 if (!pruss->mem_regions[i].va) {
145                         dev_err(dev, "failed to parse and map memory resource %d %s\n",
146                                 i, mem_names[i]);
147                         of_node_put(np);
148                         return -ENOMEM;
149                 }
150                 pruss->mem_regions[i].pa = res.start;
151                 pruss->mem_regions[i].size = resource_size(&res);
153                 dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n",
154                         mem_names[i], &pruss->mem_regions[i].pa,
155                         pruss->mem_regions[i].size, pruss->mem_regions[i].va);
156         }
157         of_node_put(np);
159         platform_set_drvdata(pdev, pruss);
161         dev_dbg(&pdev->dev, "creating PRU cores and other child platform devices\n");
162         ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
163         if (ret)
164                 dev_err(dev, "of_platform_populate failed\n");
166         return ret;
169 static int pruss_remove(struct platform_device *pdev)
171         struct device *dev = &pdev->dev;
173         dev_dbg(dev, "remove PRU cores and other child platform devices\n");
174         of_platform_depopulate(dev);
176         return 0;
179 /* instance-specific driver private data */
180 static const struct pruss_private_data am437x_pruss1_priv_data = {
181         .has_no_sharedram = false,
182 };
184 static const struct pruss_private_data am437x_pruss0_priv_data = {
185         .has_no_sharedram = true,
186 };
188 static const struct pruss_match_private_data am437x_match_data[] = {
189         {
190                 .device_name    = "54400000.pruss",
191                 .priv_data      = &am437x_pruss1_priv_data,
192         },
193         {
194                 .device_name    = "54440000.pruss",
195                 .priv_data      = &am437x_pruss0_priv_data,
196         },
197         {
198                 /* sentinel */
199         },
200 };
202 static const struct of_device_id pruss_of_match[] = {
203         { .compatible = "ti,am3356-pruss", .data = NULL, },
204         { .compatible = "ti,am4376-pruss", .data = &am437x_match_data, },
205         { .compatible = "ti,am5728-pruss", .data = NULL, },
206         { .compatible = "ti,k2g-pruss", .data = NULL, },
207         { /* sentinel */ },
208 };
209 MODULE_DEVICE_TABLE(of, pruss_of_match);
211 static struct platform_driver pruss_driver = {
212         .driver = {
213                 .name = "pruss",
214                 .of_match_table = pruss_of_match,
215         },
216         .probe  = pruss_probe,
217         .remove = pruss_remove,
218 };
219 module_platform_driver(pruss_driver);
221 MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
222 MODULE_DESCRIPTION("PRU-ICSS Subsystem Driver");
223 MODULE_LICENSE("GPL v2");