aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Molfetta2015-12-09 15:41:54 -0600
committerVishal Mahaveer2016-03-11 13:47:19 -0600
commit8a63605bbd55b6781667d722e0f92c62a358593e (patch)
tree543d064001600becd7ce086722d5fe25c3b1733c
parentcb0be57bb221063a21ec56c99888dc27c1da5872 (diff)
downloadkernel-video-8a63605bbd55b6781667d722e0f92c62a358593e.tar.gz
kernel-video-8a63605bbd55b6781667d722e0f92c62a358593e.tar.xz
kernel-video-8a63605bbd55b6781667d722e0f92c62a358593e.zip
remoteproc/omap: Fix DSP recovery issues with EDMA
Resetting the DSP subsystem while there are pending DSP EDMA transfers or while the DSP EDMA is receiving DMA events from various peripherals (e.g. McASP) can cause various issues in the recovery process: - L3 errors which create a complete system lockup - DSPSS does not reset properly and put TPTCs into an unusable state Prior to shutdown of a DSP core, two cleanup/checks are required in order to mitigate these issues: 1. Clear DSP EDMA crossbar routings Upon remoteproc reset of the DSP, DMA events may continue to arrive to the DSPs EDMA instance after the reset sequence has completed. Clearing the crossbar ensures that no unexpected events arrive to the DSP's EDMA after reset 2. Wait for DSP EDMA traffic completion After clearing DSP EDMA crossbar routings, we disable all future events and poll the various active bits of the TPCC and both TPTCs of the DSP's EDMA and wait for any pending transfers to complete prior to issuing the reset. Change-Id: I4ba7c414c8f38f95cc2a4a60f63bd7095f73788c Signed-off-by: Stephen Molfetta <sjmolfetta@ti.com> Signed-off-by: Angela Stegmaier <angelabaker@ti.com>
-rw-r--r--arch/arm/mach-omap2/pdata-quirks.c2
-rw-r--r--arch/arm/mach-omap2/remoteproc.c144
-rw-r--r--arch/arm/mach-omap2/remoteproc.h4
-rw-r--r--drivers/remoteproc/omap_remoteproc.c3
-rw-r--r--include/linux/platform_data/remoteproc-omap.h2
5 files changed, 154 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
index e151ce47dc6..d7f4c6d9b44 100644
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -294,6 +294,7 @@ static struct omap_rproc_pdata dra7_dsp1_pdata = {
294 .device_shutdown = omap_rproc_device_shutdown, 294 .device_shutdown = omap_rproc_device_shutdown,
295 .set_bootaddr = dra7_ctrl_write_dsp1_boot_addr, 295 .set_bootaddr = dra7_ctrl_write_dsp1_boot_addr,
296 .timer_ops = &omap_rproc_dmtimer_ops, 296 .timer_ops = &omap_rproc_dmtimer_ops,
297 .pre_shutdown = dra7_dsp1_pre_shutdown,
297}; 298};
298 299
299static struct omap_rproc_pdata dra7_dsp2_pdata = { 300static struct omap_rproc_pdata dra7_dsp2_pdata = {
@@ -301,6 +302,7 @@ static struct omap_rproc_pdata dra7_dsp2_pdata = {
301 .device_shutdown = omap_rproc_device_shutdown, 302 .device_shutdown = omap_rproc_device_shutdown,
302 .set_bootaddr = dra7_ctrl_write_dsp2_boot_addr, 303 .set_bootaddr = dra7_ctrl_write_dsp2_boot_addr,
303 .timer_ops = &omap_rproc_dmtimer_ops, 304 .timer_ops = &omap_rproc_dmtimer_ops,
305 .pre_shutdown = dra7_dsp2_pre_shutdown,
304}; 306};
305#endif 307#endif
306 308
diff --git a/arch/arm/mach-omap2/remoteproc.c b/arch/arm/mach-omap2/remoteproc.c
index 9e91ef09cf7..d39f5f63276 100644
--- a/arch/arm/mach-omap2/remoteproc.c
+++ b/arch/arm/mach-omap2/remoteproc.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Remote processor machine-specific module for OMAP4+ SoCs 2 * Remote processor machine-specific module for OMAP4+ SoCs
3 * 3 *
4 * Copyright (C) 2011-2014 Texas Instruments, Inc. 4 * Copyright (C) 2011-2016 Texas Instruments, Inc.
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License 7 * modify it under the terms of the GNU General Public License
@@ -22,6 +22,23 @@
22#include "omap_device.h" 22#include "omap_device.h"
23#include "control.h" 23#include "control.h"
24#include "remoteproc.h" 24#include "remoteproc.h"
25#include "soc.h"
26
27#define DSP1_EDMA_TPCC 0x40D10000
28#define DSP2_EDMA_TPCC 0x41510000
29#define DSP1_EDMA_TPTC0 0x40D05000
30#define DSP2_EDMA_TPTC0 0x41505000
31#define EDMA_TPCC_CCSTAT_OFFSET 0x640
32#define EDMA_TPCC_EECR_OFFSET 0x1028
33#define EDMA_TPCC_EECRH_OFFSET 0x102C
34#define EDMA_TPCC_QEECR_OFFSET 0x1088
35#define EDMA_DSP_TPTC1_OFFSET 0x1000
36#define EDMA_TPTC_TCSTAT0_OFFSET 0x100
37#define EDMA_TPTC_TCSTAT1_OFFSET (EDMA_DSP_TPTC1_OFFSET + \
38 EDMA_TPTC_TCSTAT0_OFFSET)
39
40#define CTRL_CORE_DMA_DSP1_DREQ 0x4A002CF8
41#define CTRL_CORE_DMA_DSP2_DREQ 0x4A002D20
25 42
26void dra7_ctrl_write_dsp1_boot_addr(u32 bootaddr) 43void dra7_ctrl_write_dsp1_boot_addr(u32 bootaddr)
27{ 44{
@@ -33,6 +50,131 @@ void dra7_ctrl_write_dsp2_boot_addr(u32 bootaddr)
33 dra7_ctrl_write_dsp_boot_addr(bootaddr, 1); 50 dra7_ctrl_write_dsp_boot_addr(bootaddr, 1);
34} 51}
35 52
53static void dra7_wait_dsp_edma_compl(u32 inst)
54{
55 u32 dsp_edma_tpcc_base, dsp_edma_tptc_base;
56 int timeout;
57 void __iomem *tpcc_base, *tptc_base;
58
59 if (!soc_is_dra7xx())
60 return;
61
62 dsp_edma_tpcc_base = inst ? DSP2_EDMA_TPCC : DSP1_EDMA_TPCC;
63 dsp_edma_tptc_base = inst ? DSP2_EDMA_TPTC0 : DSP1_EDMA_TPTC0;
64
65 tpcc_base = ioremap(dsp_edma_tpcc_base, SZ_16K);
66 if (!tpcc_base) {
67 pr_err("DSP EDMA TPCC ioremap failed\n");
68 goto map_err1;
69 }
70
71 tptc_base = ioremap(dsp_edma_tptc_base, SZ_8K);
72 if (!tptc_base) {
73 pr_err("DSP EDMA TPTC ioremap failed\n");
74 goto map_err2;
75 }
76
77 /* Disable all future EDMA and QDMA events to DSPx EDMA TPCC */
78 writel_relaxed(0xFFFFFFFF, tpcc_base + EDMA_TPCC_EECR_OFFSET);
79 writel_relaxed(0xFFFFFFFF, tpcc_base + EDMA_TPCC_EECRH_OFFSET);
80 writel_relaxed(0xFFFFFFFF, tpcc_base + EDMA_TPCC_QEECR_OFFSET);
81
82 /*
83 * Poll CCSTAT to ensure all actively serviced or queued events have
84 * been completed.
85 *
86 * The timeout is based on the duration which the EDMA CC queue will
87 * drain based on the slowest typical application. This is chosen to
88 * be 1.0625ms, which assumes a full event queue with transfers for
89 * an 8kHz audio stream, plus one extra transfer for safe measure.
90 */
91 timeout = 1063;
92 pr_warn("waiting for DSP%d EDMA traffic on TPCC to complete\n",
93 inst+1);
94 while (((readl_relaxed(tpcc_base + EDMA_TPCC_CCSTAT_OFFSET))
95 != 0x0) && --timeout)
96 udelay(1);
97 if (timeout == 0)
98 pr_warn("DSP%d EDMA transaction may be ongoing during shutdown! TPCC is active!\n",
99 inst + 1);
100
101 /*
102 * Check that PROGBUSY SRCACTV WSACTV, and DSTACTV bits of TCSTAT
103 * registers for DSP TPTC0 and TPTC1 are cleared prior to shutdown.
104 *
105 * The timeout is based on the duration of the EDMA transfer expected
106 * by the slowest typical application, which is chosen as 125us. This
107 * would be the transfer request rate of an 8kHz audio stream, with one
108 * extra transfer for safe measure.
109 */
110 timeout = 125;
111 pr_warn("waiting for DSP%d EDMA traffic on TPTC0 to complete\n",
112 inst+1);
113 while (((readl_relaxed(tptc_base + EDMA_TPTC_TCSTAT0_OFFSET) & 0x77)
114 != 0x0) && --timeout)
115 udelay(1);
116 if (timeout == 0)
117 pr_warn("DSP%d EDMA transaction may be ongoing during shutdown! TPTC0 is active!\n",
118 inst + 1);
119
120 timeout = 125;
121 pr_warn("waiting for DSP%d EDMA traffic on TPTC1 to complete\n",
122 inst+1);
123 while (((readl_relaxed(tptc_base + EDMA_TPTC_TCSTAT1_OFFSET) & 0x77)
124 != 0x0) && --timeout)
125 udelay(1);
126 if (timeout == 0)
127 pr_warn("DSP%d EDMA transaction may be ongoing during shutdown! TPTC1 is active!\n",
128 inst + 1);
129 iounmap(tptc_base);
130map_err2:
131 iounmap(tpcc_base);
132map_err1:
133 return;
134}
135
136static void dra7_clear_dsp_edma_xbar(u32 inst)
137{
138 u32 dsp_dreq_base;
139 void __iomem *iomem_base;
140 u8 offset;
141
142 if (!soc_is_dra7xx())
143 return;
144
145 dsp_dreq_base = inst ? CTRL_CORE_DMA_DSP2_DREQ :
146 CTRL_CORE_DMA_DSP1_DREQ;
147
148 iomem_base = ioremap(dsp_dreq_base, SZ_64);
149 if (!iomem_base) {
150 pr_err("DSP EDMA ioremap failed\n");
151 return;
152 }
153
154 pr_warn("Clearing all EDMA XBAR routings to DSP%d\n", inst+1);
155
156 /*
157 * Clear all connections to DSPx EDMA crossbar, from
158 * CTRL_CORE_DMA_DSPx_DREQ_0_1 to CTRL_CORE_DMA_DSPx_DREQ_18_19.
159 */
160 for (offset = 0x0; offset <= 0x24; offset += 0x4)
161 writel_relaxed(0x0, iomem_base + offset);
162
163 iounmap(iomem_base);
164}
165
166void dra7_dsp1_pre_shutdown(void)
167{
168 dra7_clear_dsp_edma_xbar(0);
169 dra7_wait_dsp_edma_compl(0);
170}
171
172void dra7_dsp2_pre_shutdown(void)
173{
174 dra7_clear_dsp_edma_xbar(1);
175 dra7_wait_dsp_edma_compl(1);
176}
177
36/** 178/**
37 * omap_rproc_device_enable - enable the remoteproc device 179 * omap_rproc_device_enable - enable the remoteproc device
38 * @pdev: the rproc platform device 180 * @pdev: the rproc platform device
diff --git a/arch/arm/mach-omap2/remoteproc.h b/arch/arm/mach-omap2/remoteproc.h
index 43a5658449b..020454e3d83 100644
--- a/arch/arm/mach-omap2/remoteproc.h
+++ b/arch/arm/mach-omap2/remoteproc.h
@@ -24,6 +24,8 @@ struct omap_dm_timer;
24#if IS_ENABLED(CONFIG_OMAP_REMOTEPROC) 24#if IS_ENABLED(CONFIG_OMAP_REMOTEPROC)
25void dra7_ctrl_write_dsp1_boot_addr(u32 bootaddr); 25void dra7_ctrl_write_dsp1_boot_addr(u32 bootaddr);
26void dra7_ctrl_write_dsp2_boot_addr(u32 bootaddr); 26void dra7_ctrl_write_dsp2_boot_addr(u32 bootaddr);
27void dra7_dsp1_pre_shutdown(void);
28void dra7_dsp2_pre_shutdown(void);
27int omap_rproc_device_enable(struct platform_device *pdev); 29int omap_rproc_device_enable(struct platform_device *pdev);
28int omap_rproc_device_shutdown(struct platform_device *pdev); 30int omap_rproc_device_shutdown(struct platform_device *pdev);
29struct omap_dm_timer *omap_rproc_request_timer(struct device_node *np); 31struct omap_dm_timer *omap_rproc_request_timer(struct device_node *np);
@@ -35,6 +37,8 @@ void omap_rproc_ack_timer_irq(struct omap_dm_timer *timer);
35#else 37#else
36static inline void dra7_ctrl_write_dsp1_boot_addr(u32 bootaddr) { } 38static inline void dra7_ctrl_write_dsp1_boot_addr(u32 bootaddr) { }
37static inline void dra7_ctrl_write_dsp2_boot_addr(u32 bootaddr) { } 39static inline void dra7_ctrl_write_dsp2_boot_addr(u32 bootaddr) { }
40static inline void dra7_dsp1_pre_shutdown(void) { }
41static inline void dra7_dsp2_pre_shutdown(void) { }
38static inline int omap_rproc_device_enable(struct platform_device *pdev) 42static inline int omap_rproc_device_enable(struct platform_device *pdev)
39{ 43{
40 return 0; 44 return 0;
diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c
index 231dc8f3920..87eed5d1356 100644
--- a/drivers/remoteproc/omap_remoteproc.c
+++ b/drivers/remoteproc/omap_remoteproc.c
@@ -459,6 +459,9 @@ static int omap_rproc_stop(struct rproc *rproc)
459 return ret; 459 return ret;
460 } 460 }
461 461
462 if (pdata->pre_shutdown)
463 pdata->pre_shutdown();
464
462 ret = pdata->device_shutdown(pdev); 465 ret = pdata->device_shutdown(pdev);
463 if (ret) 466 if (ret)
464 goto out; 467 goto out;
diff --git a/include/linux/platform_data/remoteproc-omap.h b/include/linux/platform_data/remoteproc-omap.h
index 4384eb9ced5..b98acb8c71c 100644
--- a/include/linux/platform_data/remoteproc-omap.h
+++ b/include/linux/platform_data/remoteproc-omap.h
@@ -47,12 +47,14 @@ struct omap_rproc_timer_ops {
47 * @device_enable: omap-specific handler for enabling a device 47 * @device_enable: omap-specific handler for enabling a device
48 * @device_shutdown: omap-specific handler for shutting down a device 48 * @device_shutdown: omap-specific handler for shutting down a device
49 * @set_bootaddr: omap-specific handler for setting the rproc boot address 49 * @set_bootaddr: omap-specific handler for setting the rproc boot address
50 * @pre_shutdown: omap-specific handler for performing pre-shutdown cleanup
50 * @timer_ops: platform data ops for OMAP dmtimer handlers 51 * @timer_ops: platform data ops for OMAP dmtimer handlers
51 */ 52 */
52struct omap_rproc_pdata { 53struct omap_rproc_pdata {
53 int (*device_enable)(struct platform_device *pdev); 54 int (*device_enable)(struct platform_device *pdev);
54 int (*device_shutdown)(struct platform_device *pdev); 55 int (*device_shutdown)(struct platform_device *pdev);
55 void (*set_bootaddr)(u32); 56 void (*set_bootaddr)(u32);
57 void (*pre_shutdown)(void);
56 58
57 struct omap_rproc_timer_ops *timer_ops; 59 struct omap_rproc_timer_ops *timer_ops;
58}; 60};