aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/remoteproc/wkup_m3_rproc.txt52
-rw-r--r--Documentation/remoteproc.txt6
-rw-r--r--drivers/remoteproc/Kconfig13
-rw-r--r--drivers/remoteproc/Makefile1
-rw-r--r--drivers/remoteproc/da8xx_remoteproc.c3
-rw-r--r--drivers/remoteproc/remoteproc_core.c115
-rw-r--r--drivers/remoteproc/remoteproc_internal.h2
-rw-r--r--drivers/remoteproc/ste_modem_rproc.c4
-rw-r--r--drivers/remoteproc/wkup_m3_rproc.c257
-rw-r--r--include/linux/platform_data/wkup_m3.h30
-rw-r--r--include/linux/remoteproc.h9
11 files changed, 460 insertions, 32 deletions
diff --git a/Documentation/devicetree/bindings/remoteproc/wkup_m3_rproc.txt b/Documentation/devicetree/bindings/remoteproc/wkup_m3_rproc.txt
new file mode 100644
index 000000000000..3a70073797eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/wkup_m3_rproc.txt
@@ -0,0 +1,52 @@
1TI Wakeup M3 Remoteproc Driver
2==============================
3
4The TI AM33xx and AM43xx family of devices use a small Cortex M3 co-processor
5(commonly referred to as Wakeup M3 or CM3) to help with various low power tasks
6that cannot be controlled from the MPU. This CM3 processor requires a firmware
7binary to accomplish this. The wkup_m3 remoteproc driver handles the loading of
8the firmware and booting of the CM3.
9
10Wkup M3 Device Node:
11====================
12A wkup_m3 device node is used to represent the Wakeup M3 processor instance
13within the SoC. It is added as a child node of the parent interconnect bus
14(l4_wkup) through which it is accessible to the MPU.
15
16Required properties:
17--------------------
18- compatible: Should be one of,
19 "ti,am3352-wkup-m3" for AM33xx SoCs
20 "ti,am4372-wkup-m3" for AM43xx SoCs
21- reg: Should contain the address ranges for the two internal
22 memory regions, UMEM and DMEM. The parent node should
23 provide an appropriate ranges property for properly
24 translating these into bus addresses.
25- reg-names: Contains the corresponding names for the two memory
26 regions. These should be named "umem" & "dmem".
27- ti,hwmods: Name of the hwmod associated with the wkupm3 device.
28- ti,pm-firmware: Name of firmware file to be used for loading and
29 booting the wkup_m3 remote processor.
30
31Example:
32--------
33/* AM33xx */
34ocp {
35 l4_wkup: l4_wkup@44c00000 {
36 compatible = "am335-l4-wkup", "simple-bus";
37 ranges = <0 0x44c00000 0x400000>;
38 #address-cells = <1>;
39 #size-cells = <1>;
40
41 wkup_m3: wkup_m3@100000 {
42 compatible = "ti,am3352-wkup-m3";
43 reg = <0x100000 0x4000>,
44 <0x180000 0x2000>;
45 reg-names = "umem", "dmem";
46 ti,hwmods = "wkup_m3";
47 ti,pm-firmware = "am335x-pm-firmware.elf";
48 };
49 };
50
51 ...
52};
diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
index e6469fdcf89a..ef0219fa4bb4 100644
--- a/Documentation/remoteproc.txt
+++ b/Documentation/remoteproc.txt
@@ -51,6 +51,12 @@ cost.
51 rproc_shutdown() returns, and users can still use it with a subsequent 51 rproc_shutdown() returns, and users can still use it with a subsequent
52 rproc_boot(), if needed. 52 rproc_boot(), if needed.
53 53
54 struct rproc *rproc_get_by_phandle(phandle phandle)
55 - Find an rproc handle using a device tree phandle. Returns the rproc
56 handle on success, and NULL on failure. This function increments
57 the remote processor's refcount, so always use rproc_put() to
58 decrement it back once rproc isn't needed anymore.
59
543. Typical usage 603. Typical usage
55 61
56#include <linux/remoteproc.h> 62#include <linux/remoteproc.h>
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 5e343bab9458..28c711f0ac6b 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -41,6 +41,19 @@ config STE_MODEM_RPROC
41 This can be either built-in or a loadable module. 41 This can be either built-in or a loadable module.
42 If unsure say N. 42 If unsure say N.
43 43
44config WKUP_M3_RPROC
45 tristate "AMx3xx Wakeup M3 remoteproc support"
46 depends on SOC_AM33XX || SOC_AM43XX
47 select REMOTEPROC
48 help
49 Say y here to support Wakeup M3 remote processor on TI AM33xx
50 and AM43xx family of SoCs.
51
52 Required for Suspend-to-RAM on AM33xx and AM43xx SoCs. Also needed
53 for deep CPUIdle states on AM33xx SoCs. Allows for loading of the
54 firmware onto these remote processors.
55 If unsure say N.
56
44config DA8XX_REMOTEPROC 57config DA8XX_REMOTEPROC
45 tristate "DA8xx/OMAP-L13x remoteproc support" 58 tristate "DA8xx/OMAP-L13x remoteproc support"
46 depends on ARCH_DAVINCI_DA8XX 59 depends on ARCH_DAVINCI_DA8XX
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index ac2ff75686d2..81b04d1e2e58 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -9,4 +9,5 @@ remoteproc-y += remoteproc_virtio.o
9remoteproc-y += remoteproc_elf_loader.o 9remoteproc-y += remoteproc_elf_loader.o
10obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o 10obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o
11obj-$(CONFIG_STE_MODEM_RPROC) += ste_modem_rproc.o 11obj-$(CONFIG_STE_MODEM_RPROC) += ste_modem_rproc.o
12obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o
12obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o 13obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c
index f8d6a0661c14..009e56f67de2 100644
--- a/drivers/remoteproc/da8xx_remoteproc.c
+++ b/drivers/remoteproc/da8xx_remoteproc.c
@@ -26,8 +26,7 @@
26static char *da8xx_fw_name; 26static char *da8xx_fw_name;
27module_param(da8xx_fw_name, charp, S_IRUGO); 27module_param(da8xx_fw_name, charp, S_IRUGO);
28MODULE_PARM_DESC(da8xx_fw_name, 28MODULE_PARM_DESC(da8xx_fw_name,
29 "\n\t\tName of DSP firmware file in /lib/firmware" 29 "Name of DSP firmware file in /lib/firmware (if not specified defaults to 'rproc-dsp-fw')");
30 " (if not specified defaults to 'rproc-dsp-fw')");
31 30
32/* 31/*
33 * OMAP-L138 Technical References: 32 * OMAP-L138 Technical References:
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 11cdb119e4f3..8b3130f22b42 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -44,6 +44,9 @@
44 44
45#include "remoteproc_internal.h" 45#include "remoteproc_internal.h"
46 46
47static DEFINE_MUTEX(rproc_list_mutex);
48static LIST_HEAD(rproc_list);
49
47typedef int (*rproc_handle_resources_t)(struct rproc *rproc, 50typedef int (*rproc_handle_resources_t)(struct rproc *rproc,
48 struct resource_table *table, int len); 51 struct resource_table *table, int len);
49typedef int (*rproc_handle_resource_t)(struct rproc *rproc, 52typedef int (*rproc_handle_resource_t)(struct rproc *rproc,
@@ -132,32 +135,48 @@ static void rproc_disable_iommu(struct rproc *rproc)
132 135
133 iommu_detach_device(domain, dev); 136 iommu_detach_device(domain, dev);
134 iommu_domain_free(domain); 137 iommu_domain_free(domain);
135
136 return;
137} 138}
138 139
139/* 140/**
141 * rproc_da_to_va() - lookup the kernel virtual address for a remoteproc address
142 * @rproc: handle of a remote processor
143 * @da: remoteproc device address to translate
144 * @len: length of the memory region @da is pointing to
145 *
140 * Some remote processors will ask us to allocate them physically contiguous 146 * Some remote processors will ask us to allocate them physically contiguous
141 * memory regions (which we call "carveouts"), and map them to specific 147 * memory regions (which we call "carveouts"), and map them to specific
142 * device addresses (which are hardcoded in the firmware). 148 * device addresses (which are hardcoded in the firmware). They may also have
149 * dedicated memory regions internal to the processors, and use them either
150 * exclusively or alongside carveouts.
143 * 151 *
144 * They may then ask us to copy objects into specific device addresses (e.g. 152 * They may then ask us to copy objects into specific device addresses (e.g.
145 * code/data sections) or expose us certain symbols in other device address 153 * code/data sections) or expose us certain symbols in other device address
146 * (e.g. their trace buffer). 154 * (e.g. their trace buffer).
147 * 155 *
148 * This function is an internal helper with which we can go over the allocated 156 * This function is a helper function with which we can go over the allocated
149 * carveouts and translate specific device address to kernel virtual addresses 157 * carveouts and translate specific device addresses to kernel virtual addresses
150 * so we can access the referenced memory. 158 * so we can access the referenced memory. This function also allows to perform
159 * translations on the internal remoteproc memory regions through a platform
160 * implementation specific da_to_va ops, if present.
161 *
162 * The function returns a valid kernel address on success or NULL on failure.
151 * 163 *
152 * Note: phys_to_virt(iommu_iova_to_phys(rproc->domain, da)) will work too, 164 * Note: phys_to_virt(iommu_iova_to_phys(rproc->domain, da)) will work too,
153 * but only on kernel direct mapped RAM memory. Instead, we're just using 165 * but only on kernel direct mapped RAM memory. Instead, we're just using
154 * here the output of the DMA API, which should be more correct. 166 * here the output of the DMA API for the carveouts, which should be more
167 * correct.
155 */ 168 */
156void *rproc_da_to_va(struct rproc *rproc, u64 da, int len) 169void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
157{ 170{
158 struct rproc_mem_entry *carveout; 171 struct rproc_mem_entry *carveout;
159 void *ptr = NULL; 172 void *ptr = NULL;
160 173
174 if (rproc->ops->da_to_va) {
175 ptr = rproc->ops->da_to_va(rproc, da, len);
176 if (ptr)
177 goto out;
178 }
179
161 list_for_each_entry(carveout, &rproc->carveouts, node) { 180 list_for_each_entry(carveout, &rproc->carveouts, node) {
162 int offset = da - carveout->da; 181 int offset = da - carveout->da;
163 182
@@ -174,6 +193,7 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
174 break; 193 break;
175 } 194 }
176 195
196out:
177 return ptr; 197 return ptr;
178} 198}
179EXPORT_SYMBOL(rproc_da_to_va); 199EXPORT_SYMBOL(rproc_da_to_va);
@@ -411,10 +431,8 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
411 } 431 }
412 432
413 trace = kzalloc(sizeof(*trace), GFP_KERNEL); 433 trace = kzalloc(sizeof(*trace), GFP_KERNEL);
414 if (!trace) { 434 if (!trace)
415 dev_err(dev, "kzalloc trace failed\n");
416 return -ENOMEM; 435 return -ENOMEM;
417 }
418 436
419 /* set the trace buffer dma properties */ 437 /* set the trace buffer dma properties */
420 trace->len = rsc->len; 438 trace->len = rsc->len;
@@ -489,10 +507,8 @@ static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc,
489 } 507 }
490 508
491 mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); 509 mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
492 if (!mapping) { 510 if (!mapping)
493 dev_err(dev, "kzalloc mapping failed\n");
494 return -ENOMEM; 511 return -ENOMEM;
495 }
496 512
497 ret = iommu_map(rproc->domain, rsc->da, rsc->pa, rsc->len, rsc->flags); 513 ret = iommu_map(rproc->domain, rsc->da, rsc->pa, rsc->len, rsc->flags);
498 if (ret) { 514 if (ret) {
@@ -565,10 +581,8 @@ static int rproc_handle_carveout(struct rproc *rproc,
565 rsc->da, rsc->pa, rsc->len, rsc->flags); 581 rsc->da, rsc->pa, rsc->len, rsc->flags);
566 582
567 carveout = kzalloc(sizeof(*carveout), GFP_KERNEL); 583 carveout = kzalloc(sizeof(*carveout), GFP_KERNEL);
568 if (!carveout) { 584 if (!carveout)
569 dev_err(dev, "kzalloc carveout failed\n");
570 return -ENOMEM; 585 return -ENOMEM;
571 }
572 586
573 va = dma_alloc_coherent(dev->parent, rsc->len, &dma, GFP_KERNEL); 587 va = dma_alloc_coherent(dev->parent, rsc->len, &dma, GFP_KERNEL);
574 if (!va) { 588 if (!va) {
@@ -768,7 +782,8 @@ static void rproc_resource_cleanup(struct rproc *rproc)
768 782
769 /* clean up carveout allocations */ 783 /* clean up carveout allocations */
770 list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) { 784 list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) {
771 dma_free_coherent(dev->parent, entry->len, entry->va, entry->dma); 785 dma_free_coherent(dev->parent, entry->len, entry->va,
786 entry->dma);
772 list_del(&entry->node); 787 list_del(&entry->node);
773 kfree(entry); 788 kfree(entry);
774 } 789 }
@@ -808,9 +823,8 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
808 823
809 /* look for the resource table */ 824 /* look for the resource table */
810 table = rproc_find_rsc_table(rproc, fw, &tablesz); 825 table = rproc_find_rsc_table(rproc, fw, &tablesz);
811 if (!table) { 826 if (!table)
812 goto clean_up; 827 goto clean_up;
813 }
814 828
815 /* Verify that resource table in loaded fw is unchanged */ 829 /* Verify that resource table in loaded fw is unchanged */
816 if (rproc->table_csum != crc32(0, table, tablesz)) { 830 if (rproc->table_csum != crc32(0, table, tablesz)) {
@@ -911,7 +925,8 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
911 925
912 /* count the number of notify-ids */ 926 /* count the number of notify-ids */
913 rproc->max_notifyid = -1; 927 rproc->max_notifyid = -1;
914 ret = rproc_handle_resources(rproc, tablesz, rproc_count_vrings_handler); 928 ret = rproc_handle_resources(rproc, tablesz,
929 rproc_count_vrings_handler);
915 if (ret) 930 if (ret)
916 goto out; 931 goto out;
917 932
@@ -1152,6 +1167,50 @@ out:
1152EXPORT_SYMBOL(rproc_shutdown); 1167EXPORT_SYMBOL(rproc_shutdown);
1153 1168
1154/** 1169/**
1170 * rproc_get_by_phandle() - find a remote processor by phandle
1171 * @phandle: phandle to the rproc
1172 *
1173 * Finds an rproc handle using the remote processor's phandle, and then
1174 * return a handle to the rproc.
1175 *
1176 * This function increments the remote processor's refcount, so always
1177 * use rproc_put() to decrement it back once rproc isn't needed anymore.
1178 *
1179 * Returns the rproc handle on success, and NULL on failure.
1180 */
1181#ifdef CONFIG_OF
1182struct rproc *rproc_get_by_phandle(phandle phandle)
1183{
1184 struct rproc *rproc = NULL, *r;
1185 struct device_node *np;
1186
1187 np = of_find_node_by_phandle(phandle);
1188 if (!np)
1189 return NULL;
1190
1191 mutex_lock(&rproc_list_mutex);
1192 list_for_each_entry(r, &rproc_list, node) {
1193 if (r->dev.parent && r->dev.parent->of_node == np) {
1194 rproc = r;
1195 get_device(&rproc->dev);
1196 break;
1197 }
1198 }
1199 mutex_unlock(&rproc_list_mutex);
1200
1201 of_node_put(np);
1202
1203 return rproc;
1204}
1205#else
1206struct rproc *rproc_get_by_phandle(phandle phandle)
1207{
1208 return NULL;
1209}
1210#endif
1211EXPORT_SYMBOL(rproc_get_by_phandle);
1212
1213/**
1155 * rproc_add() - register a remote processor 1214 * rproc_add() - register a remote processor
1156 * @rproc: the remote processor handle to register 1215 * @rproc: the remote processor handle to register
1157 * 1216 *
@@ -1180,6 +1239,11 @@ int rproc_add(struct rproc *rproc)
1180 if (ret < 0) 1239 if (ret < 0)
1181 return ret; 1240 return ret;
1182 1241
1242 /* expose to rproc_get_by_phandle users */
1243 mutex_lock(&rproc_list_mutex);
1244 list_add(&rproc->node, &rproc_list);
1245 mutex_unlock(&rproc_list_mutex);
1246
1183 dev_info(dev, "%s is available\n", rproc->name); 1247 dev_info(dev, "%s is available\n", rproc->name);
1184 1248
1185 dev_info(dev, "Note: remoteproc is still under development and considered experimental.\n"); 1249 dev_info(dev, "Note: remoteproc is still under development and considered experimental.\n");
@@ -1268,10 +1332,8 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
1268 name_len = strlen(name) + strlen(template) - 2 + 1; 1332 name_len = strlen(name) + strlen(template) - 2 + 1;
1269 1333
1270 rproc = kzalloc(sizeof(struct rproc) + len + name_len, GFP_KERNEL); 1334 rproc = kzalloc(sizeof(struct rproc) + len + name_len, GFP_KERNEL);
1271 if (!rproc) { 1335 if (!rproc)
1272 dev_err(dev, "%s: kzalloc failed\n", __func__);
1273 return NULL; 1336 return NULL;
1274 }
1275 1337
1276 if (!firmware) { 1338 if (!firmware) {
1277 p = (char *)rproc + sizeof(struct rproc) + len; 1339 p = (char *)rproc + sizeof(struct rproc) + len;
@@ -1369,6 +1431,11 @@ int rproc_del(struct rproc *rproc)
1369 /* Free the copy of the resource table */ 1431 /* Free the copy of the resource table */
1370 kfree(rproc->cached_table); 1432 kfree(rproc->cached_table);
1371 1433
1434 /* the rproc is downref'ed as soon as it's removed from the klist */
1435 mutex_lock(&rproc_list_mutex);
1436 list_del(&rproc->node);
1437 mutex_unlock(&rproc_list_mutex);
1438
1372 device_del(&rproc->dev); 1439 device_del(&rproc->dev);
1373 1440
1374 return 0; 1441 return 0;
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 70701a50ddfa..8041b95cb058 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -35,7 +35,7 @@ struct rproc;
35 * @get_boot_addr: get boot address to entry point specified in firmware 35 * @get_boot_addr: get boot address to entry point specified in firmware
36 */ 36 */
37struct rproc_fw_ops { 37struct rproc_fw_ops {
38 struct resource_table *(*find_rsc_table) (struct rproc *rproc, 38 struct resource_table *(*find_rsc_table)(struct rproc *rproc,
39 const struct firmware *fw, 39 const struct firmware *fw,
40 int *tablesz); 40 int *tablesz);
41 struct resource_table *(*find_loaded_rsc_table)(struct rproc *rproc, 41 struct resource_table *(*find_loaded_rsc_table)(struct rproc *rproc,
diff --git a/drivers/remoteproc/ste_modem_rproc.c b/drivers/remoteproc/ste_modem_rproc.c
index dd193f35a1ff..53dc17bdd54e 100644
--- a/drivers/remoteproc/ste_modem_rproc.c
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -67,8 +67,7 @@ static int sproc_load_segments(struct rproc *rproc, const struct firmware *fw)
67static const struct ste_toc_entry *sproc_find_rsc_entry(const void *data) 67static const struct ste_toc_entry *sproc_find_rsc_entry(const void *data)
68{ 68{
69 int i; 69 int i;
70 const struct ste_toc *toc; 70 const struct ste_toc *toc = data;
71 toc = data;
72 71
73 /* Search the table for the resource table */ 72 /* Search the table for the resource table */
74 for (i = 0; i < SPROC_MAX_TOC_ENTRIES && 73 for (i = 0; i < SPROC_MAX_TOC_ENTRIES &&
@@ -230,6 +229,7 @@ static int sproc_start(struct rproc *rproc)
230static int sproc_stop(struct rproc *rproc) 229static int sproc_stop(struct rproc *rproc)
231{ 230{
232 struct sproc *sproc = rproc->priv; 231 struct sproc *sproc = rproc->priv;
232
233 sproc_dbg(sproc, "stop ste-modem\n"); 233 sproc_dbg(sproc, "stop ste-modem\n");
234 234
235 return sproc->mdev->ops.power(sproc->mdev, false); 235 return sproc->mdev->ops.power(sproc->mdev, false);
diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
new file mode 100644
index 000000000000..edf81819cce1
--- /dev/null
+++ b/drivers/remoteproc/wkup_m3_rproc.c
@@ -0,0 +1,257 @@
1/*
2 * TI AMx3 Wakeup M3 Remote Processor driver
3 *
4 * Copyright (C) 2014-2015 Texas Instruments, Inc.
5 *
6 * Dave Gerlach <d-gerlach@ti.com>
7 * Suman Anna <s-anna@ti.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19#include <linux/err.h>
20#include <linux/interrupt.h>
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/of_device.h>
24#include <linux/of_address.h>
25#include <linux/platform_device.h>
26#include <linux/pm_runtime.h>
27#include <linux/remoteproc.h>
28
29#include <linux/platform_data/wkup_m3.h>
30
31#include "remoteproc_internal.h"
32
33#define WKUPM3_MEM_MAX 2
34
35/**
36 * struct wkup_m3_mem - WkupM3 internal memory structure
37 * @cpu_addr: MPU virtual address of the memory region
38 * @bus_addr: Bus address used to access the memory region
39 * @dev_addr: Device address from Wakeup M3 view
40 * @size: Size of the memory region
41 */
42struct wkup_m3_mem {
43 void __iomem *cpu_addr;
44 phys_addr_t bus_addr;
45 u32 dev_addr;
46 size_t size;
47};
48
49/**
50 * struct wkup_m3_rproc - WkupM3 remote processor state
51 * @rproc: rproc handle
52 * @pdev: pointer to platform device
53 * @mem: WkupM3 memory information
54 */
55struct wkup_m3_rproc {
56 struct rproc *rproc;
57 struct platform_device *pdev;
58 struct wkup_m3_mem mem[WKUPM3_MEM_MAX];
59};
60
61static int wkup_m3_rproc_start(struct rproc *rproc)
62{
63 struct wkup_m3_rproc *wkupm3 = rproc->priv;
64 struct platform_device *pdev = wkupm3->pdev;
65 struct device *dev = &pdev->dev;
66 struct wkup_m3_platform_data *pdata = dev_get_platdata(dev);
67
68 if (pdata->deassert_reset(pdev, pdata->reset_name)) {
69 dev_err(dev, "Unable to reset wkup_m3!\n");
70 return -ENODEV;
71 }
72
73 return 0;
74}
75
76static int wkup_m3_rproc_stop(struct rproc *rproc)
77{
78 struct wkup_m3_rproc *wkupm3 = rproc->priv;
79 struct platform_device *pdev = wkupm3->pdev;
80 struct device *dev = &pdev->dev;
81 struct wkup_m3_platform_data *pdata = dev_get_platdata(dev);
82
83 if (pdata->assert_reset(pdev, pdata->reset_name)) {
84 dev_err(dev, "Unable to assert reset of wkup_m3!\n");
85 return -ENODEV;
86 }
87
88 return 0;
89}
90
91static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
92{
93 struct wkup_m3_rproc *wkupm3 = rproc->priv;
94 void *va = NULL;
95 int i;
96 u32 offset;
97
98 if (len <= 0)
99 return NULL;
100
101 for (i = 0; i < WKUPM3_MEM_MAX; i++) {
102 if (da >= wkupm3->mem[i].dev_addr && da + len <=
103 wkupm3->mem[i].dev_addr + wkupm3->mem[i].size) {
104 offset = da - wkupm3->mem[i].dev_addr;
105 /* __force to make sparse happy with type conversion */
106 va = (__force void *)(wkupm3->mem[i].cpu_addr + offset);
107 break;
108 }
109 }
110
111 return va;
112}
113
114static struct rproc_ops wkup_m3_rproc_ops = {
115 .start = wkup_m3_rproc_start,
116 .stop = wkup_m3_rproc_stop,
117 .da_to_va = wkup_m3_rproc_da_to_va,
118};
119
120static const struct of_device_id wkup_m3_rproc_of_match[] = {
121 { .compatible = "ti,am3352-wkup-m3", },
122 { .compatible = "ti,am4372-wkup-m3", },
123 {},
124};
125
126static int wkup_m3_rproc_probe(struct platform_device *pdev)
127{
128 struct device *dev = &pdev->dev;
129 struct wkup_m3_platform_data *pdata = dev->platform_data;
130 /* umem always needs to be processed first */
131 const char *mem_names[WKUPM3_MEM_MAX] = { "umem", "dmem" };
132 struct wkup_m3_rproc *wkupm3;
133 const char *fw_name;
134 struct rproc *rproc;
135 struct resource *res;
136 const __be32 *addrp;
137 u32 l4_offset = 0;
138 u64 size;
139 int ret;
140 int i;
141
142 if (!(pdata && pdata->deassert_reset && pdata->assert_reset &&
143 pdata->reset_name)) {
144 dev_err(dev, "Platform data missing!\n");
145 return -ENODEV;
146 }
147
148 ret = of_property_read_string(dev->of_node, "ti,pm-firmware",
149 &fw_name);
150 if (ret) {
151 dev_err(dev, "No firmware filename given\n");
152 return -ENODEV;
153 }
154
155 pm_runtime_enable(&pdev->dev);
156 ret = pm_runtime_get_sync(&pdev->dev);
157 if (ret < 0) {
158 dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
159 goto err;
160 }
161
162 rproc = rproc_alloc(dev, "wkup_m3", &wkup_m3_rproc_ops,
163 fw_name, sizeof(*wkupm3));
164 if (!rproc) {
165 ret = -ENOMEM;
166 goto err;
167 }
168
169 wkupm3 = rproc->priv;
170 wkupm3->rproc = rproc;
171 wkupm3->pdev = pdev;
172
173 for (i = 0; i < ARRAY_SIZE(mem_names); i++) {
174 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
175 mem_names[i]);
176 wkupm3->mem[i].cpu_addr = devm_ioremap_resource(dev, res);
177 if (IS_ERR(wkupm3->mem[i].cpu_addr)) {
178 dev_err(&pdev->dev, "devm_ioremap_resource failed for resource %d\n",
179 i);
180 ret = PTR_ERR(wkupm3->mem[i].cpu_addr);
181 goto err;
182 }
183 wkupm3->mem[i].bus_addr = res->start;
184 wkupm3->mem[i].size = resource_size(res);
185 addrp = of_get_address(dev->of_node, i, &size, NULL);
186 /*
187 * The wkupm3 has umem at address 0 in its view, so the device
188 * addresses for each memory region is computed as a relative
189 * offset of the bus address for umem, and therefore needs to be
190 * processed first.
191 */
192 if (!strcmp(mem_names[i], "umem"))
193 l4_offset = be32_to_cpu(*addrp);
194 wkupm3->mem[i].dev_addr = be32_to_cpu(*addrp) - l4_offset;
195 }
196
197 dev_set_drvdata(dev, rproc);
198
199 ret = rproc_add(rproc);
200 if (ret) {
201 dev_err(dev, "rproc_add failed\n");
202 goto err_put_rproc;
203 }
204
205 return 0;
206
207err_put_rproc:
208 rproc_put(rproc);
209err:
210 pm_runtime_put_noidle(dev);
211 pm_runtime_disable(dev);
212 return ret;
213}
214
215static int wkup_m3_rproc_remove(struct platform_device *pdev)
216{
217 struct rproc *rproc = platform_get_drvdata(pdev);
218
219 rproc_del(rproc);
220 rproc_put(rproc);
221 pm_runtime_put_sync(&pdev->dev);
222 pm_runtime_disable(&pdev->dev);
223
224 return 0;
225}
226
227#ifdef CONFIG_PM
228static int wkup_m3_rpm_suspend(struct device *dev)
229{
230 return -EBUSY;
231}
232
233static int wkup_m3_rpm_resume(struct device *dev)
234{
235 return 0;
236}
237#endif
238
239static const struct dev_pm_ops wkup_m3_rproc_pm_ops = {
240 SET_RUNTIME_PM_OPS(wkup_m3_rpm_suspend, wkup_m3_rpm_resume, NULL)
241};
242
243static struct platform_driver wkup_m3_rproc_driver = {
244 .probe = wkup_m3_rproc_probe,
245 .remove = wkup_m3_rproc_remove,
246 .driver = {
247 .name = "wkup_m3_rproc",
248 .of_match_table = wkup_m3_rproc_of_match,
249 .pm = &wkup_m3_rproc_pm_ops,
250 },
251};
252
253module_platform_driver(wkup_m3_rproc_driver);
254
255MODULE_LICENSE("GPL v2");
256MODULE_DESCRIPTION("TI Wakeup M3 remote processor control driver");
257MODULE_AUTHOR("Dave Gerlach <d-gerlach@ti.com>");
diff --git a/include/linux/platform_data/wkup_m3.h b/include/linux/platform_data/wkup_m3.h
new file mode 100644
index 000000000000..3f1d77effd71
--- /dev/null
+++ b/include/linux/platform_data/wkup_m3.h
@@ -0,0 +1,30 @@
1/*
2 * TI Wakeup M3 remote processor platform data
3 *
4 * Copyright (C) 2014-2015 Texas Instruments, Inc.
5 *
6 * Dave Gerlach <d-gerlach@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#ifndef _LINUX_PLATFORM_DATA_WKUP_M3_H
19#define _LINUX_PLATFORM_DATA_WKUP_M3_H
20
21struct platform_device;
22
23struct wkup_m3_platform_data {
24 const char *reset_name;
25
26 int (*assert_reset)(struct platform_device *pdev, const char *name);
27 int (*deassert_reset)(struct platform_device *pdev, const char *name);
28};
29
30#endif /* _LINUX_PLATFORM_DATA_WKUP_M3_H */
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 78b8a9b9d40a..9c4e1384f636 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -36,11 +36,11 @@
36#define REMOTEPROC_H 36#define REMOTEPROC_H
37 37
38#include <linux/types.h> 38#include <linux/types.h>
39#include <linux/klist.h>
40#include <linux/mutex.h> 39#include <linux/mutex.h>
41#include <linux/virtio.h> 40#include <linux/virtio.h>
42#include <linux/completion.h> 41#include <linux/completion.h>
43#include <linux/idr.h> 42#include <linux/idr.h>
43#include <linux/of.h>
44 44
45/** 45/**
46 * struct resource_table - firmware resource table header 46 * struct resource_table - firmware resource table header
@@ -330,11 +330,13 @@ struct rproc;
330 * @start: power on the device and boot it 330 * @start: power on the device and boot it
331 * @stop: power off the device 331 * @stop: power off the device
332 * @kick: kick a virtqueue (virtqueue id given as a parameter) 332 * @kick: kick a virtqueue (virtqueue id given as a parameter)
333 * @da_to_va: optional platform hook to perform address translations
333 */ 334 */
334struct rproc_ops { 335struct rproc_ops {
335 int (*start)(struct rproc *rproc); 336 int (*start)(struct rproc *rproc);
336 int (*stop)(struct rproc *rproc); 337 int (*stop)(struct rproc *rproc);
337 void (*kick)(struct rproc *rproc, int vqid); 338 void (*kick)(struct rproc *rproc, int vqid);
339 void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
338}; 340};
339 341
340/** 342/**
@@ -375,7 +377,7 @@ enum rproc_crash_type {
375 377
376/** 378/**
377 * struct rproc - represents a physical remote processor device 379 * struct rproc - represents a physical remote processor device
378 * @node: klist node of this rproc object 380 * @node: list node of this rproc object
379 * @domain: iommu domain 381 * @domain: iommu domain
380 * @name: human readable name of the rproc 382 * @name: human readable name of the rproc
381 * @firmware: name of firmware file to be loaded 383 * @firmware: name of firmware file to be loaded
@@ -407,7 +409,7 @@ enum rproc_crash_type {
407 * @has_iommu: flag to indicate if remote processor is behind an MMU 409 * @has_iommu: flag to indicate if remote processor is behind an MMU
408 */ 410 */
409struct rproc { 411struct rproc {
410 struct klist_node node; 412 struct list_head node;
411 struct iommu_domain *domain; 413 struct iommu_domain *domain;
412 const char *name; 414 const char *name;
413 const char *firmware; 415 const char *firmware;
@@ -481,6 +483,7 @@ struct rproc_vdev {
481 u32 rsc_offset; 483 u32 rsc_offset;
482}; 484};
483 485
486struct rproc *rproc_get_by_phandle(phandle phandle);
484struct rproc *rproc_alloc(struct device *dev, const char *name, 487struct rproc *rproc_alloc(struct device *dev, const char *name,
485 const struct rproc_ops *ops, 488 const struct rproc_ops *ops,
486 const char *firmware, int len); 489 const char *firmware, int len);