189 lines
5.9 KiB
Diff
189 lines
5.9 KiB
Diff
From 67b204258838dd2c940d5b1508318b4890324a06 Mon Sep 17 00:00:00 2001
|
|
From: christophe montaud <christophe.montaud@st.com>
|
|
Date: Tue, 29 Jan 2019 17:31:19 +0100
|
|
Subject: [PATCH 63/64] ARM stm32mp1 r0 rc4 hotfix w905.2 DRIVERS
|
|
|
|
---
|
|
drivers/dma/stm32-dma.c | 70 ++++++++++++++++++++++++++++++++++++---------
|
|
drivers/usb/dwc2/platform.c | 38 ++++++++++++++++++------
|
|
2 files changed, 87 insertions(+), 21 deletions(-)
|
|
|
|
diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
|
|
index 5abfa4f..dc3ba91 100644
|
|
--- a/drivers/dma/stm32-dma.c
|
|
+++ b/drivers/dma/stm32-dma.c
|
|
@@ -1675,37 +1675,81 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy(
|
|
return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
|
|
}
|
|
|
|
+static bool stm32_dma_is_current_sg(struct stm32_dma_chan *chan)
|
|
+{
|
|
+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
|
|
+ struct stm32_dma_sg_req *sg_req;
|
|
+ u32 dma_scr, dma_smar, id;
|
|
+
|
|
+ id = chan->id;
|
|
+ dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id));
|
|
+
|
|
+ if (!(dma_scr & STM32_DMA_SCR_DBM))
|
|
+ return true;
|
|
+
|
|
+ sg_req = &chan->desc->sg_req[chan->next_sg];
|
|
+
|
|
+ if (dma_scr & STM32_DMA_SCR_CT) {
|
|
+ dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM0AR(id));
|
|
+ return (dma_smar == sg_req->chan_reg.dma_sm0ar);
|
|
+ }
|
|
+
|
|
+ dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM1AR(id));
|
|
+
|
|
+ return (dma_smar == sg_req->chan_reg.dma_sm1ar);
|
|
+}
|
|
+
|
|
static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan,
|
|
struct stm32_dma_desc *desc,
|
|
u32 next_sg)
|
|
{
|
|
u32 modulo, burst_size;
|
|
- u32 residue = 0;
|
|
+ u32 residue;
|
|
+ u32 n_sg = next_sg;
|
|
+ struct stm32_dma_sg_req *sg_req = &chan->desc->sg_req[chan->next_sg];
|
|
int i;
|
|
|
|
/* Drain case */
|
|
if (chan->residue_after_drain)
|
|
return chan->residue_after_drain;
|
|
|
|
+ residue = stm32_dma_get_remaining_bytes(chan);
|
|
+
|
|
/*
|
|
- * In cyclic mode, for the last period, residue = remaining bytes from
|
|
- * NDTR
|
|
+ * Calculate the residue means compute the descriptors
|
|
+ * information:
|
|
+ * - the sg currently transferred
|
|
+ * - the remaining position in this sg (NDTR).
|
|
+ *
|
|
+ * The issue is that a race condition can occur if DMA is
|
|
+ * running. DMA can have started to transfer the next sg before
|
|
+ * the position in sg is read. In this case the remaing position
|
|
+ * can correspond to the new sg position.
|
|
+ * The strategy implemented in the stm32 driver is to check the
|
|
+ * sg transition. If detected we can not trust the SxNDTR register value
|
|
+ * this register can not be up to date during the transition.
|
|
+ * in this case we can assume that the dma is at the beginning of next
|
|
+ * sg so we calculate the residue in consequence.
|
|
*/
|
|
- if (chan->desc->cyclic && next_sg == 0) {
|
|
- residue = stm32_dma_get_remaining_bytes(chan);
|
|
- goto end;
|
|
+
|
|
+ if (!stm32_dma_is_current_sg(chan)) {
|
|
+ n_sg++;
|
|
+ if (n_sg == chan->desc->num_sgs)
|
|
+ n_sg = 0;
|
|
+ residue = sg_dma_len(&sg_req->stm32_sgl_req);
|
|
}
|
|
|
|
/*
|
|
- * For all other periods in cyclic mode, and in sg mode,
|
|
- * residue = remaining bytes from NDTR + remaining periods/sg to be
|
|
- * transferred
|
|
+ * In cyclic mode, for the last period, residue = remaining bytes
|
|
+ * from NDTR
|
|
+ * else for all other periods in cyclic mode, and in sg mode,
|
|
+ * residue = remaining bytes from NDTR + remaining
|
|
+ * periods/sg to be transferred
|
|
*/
|
|
- for (i = next_sg; i < desc->num_sgs; i++)
|
|
- residue += sg_dma_len(&desc->sg_req[i].stm32_sgl_req);
|
|
- residue += stm32_dma_get_remaining_bytes(chan);
|
|
+ if (!chan->desc->cyclic || n_sg != 0)
|
|
+ for (i = n_sg; i < desc->num_sgs; i++)
|
|
+ residue += sg_dma_len(&desc->sg_req[i].stm32_sgl_req);
|
|
|
|
-end:
|
|
if (!chan->mem_burst)
|
|
return residue;
|
|
|
|
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
|
|
index b80d046..7e6960c 100644
|
|
--- a/drivers/usb/dwc2/platform.c
|
|
+++ b/drivers/usb/dwc2/platform.c
|
|
@@ -568,16 +568,35 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
|
|
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
|
|
int ret = 0;
|
|
|
|
+ if (dwc2_is_device_mode(dwc2))
|
|
+ dwc2_hsotg_suspend(dwc2);
|
|
+
|
|
if (dwc2->params.activate_stm_id_vb_detection &&
|
|
!dwc2->params.force_b_session_valid) {
|
|
- u32 ggpio;
|
|
+ u32 ggpio, gotgctl;
|
|
+ int is_host = dwc2_is_host_mode(dwc2);
|
|
|
|
/*
|
|
* Need to force the mode to the current mode to avoid Mode
|
|
- * Mismatch Interrupt when ID and VBUS detection will be
|
|
- * disabled
|
|
+ * Mismatch Interrupt when ID detection will be disabled.
|
|
*/
|
|
- dwc2_force_mode(dwc2, dwc2_is_host_mode(dwc2));
|
|
+ dwc2_force_mode(dwc2, is_host);
|
|
+
|
|
+ if (!is_host) {
|
|
+ gotgctl = dwc2_readl(dwc2, GOTGCTL);
|
|
+ /*
|
|
+ * We're about to disable Vbus detection hw before low
|
|
+ * power mode entry. Then an undesired disconnect
|
|
+ * interrupt may occur which is racy with low power
|
|
+ * (low-level hw disable). Then check valid session
|
|
+ * to force B-peripheral session value.
|
|
+ */
|
|
+ if (gotgctl & GOTGCTL_BSESVLD) {
|
|
+ gotgctl |= GOTGCTL_BVALOVAL;
|
|
+ gotgctl |= GOTGCTL_BVALOEN;
|
|
+ dwc2_writel(dwc2, gotgctl, GOTGCTL);
|
|
+ }
|
|
+ }
|
|
|
|
ggpio = dwc2_readl(dwc2, GGPIO);
|
|
ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN;
|
|
@@ -587,9 +606,6 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
|
|
regulator_disable(dwc2->usb33d);
|
|
}
|
|
|
|
- if (dwc2_is_device_mode(dwc2))
|
|
- dwc2_hsotg_suspend(dwc2);
|
|
-
|
|
if (dwc2->ll_hw_enabled)
|
|
ret = __dwc2_lowlevel_hw_disable(dwc2);
|
|
|
|
@@ -612,7 +628,7 @@ static int __maybe_unused dwc2_resume(struct device *dev)
|
|
|
|
if (dwc2->params.activate_stm_id_vb_detection &&
|
|
!dwc2->params.force_b_session_valid) {
|
|
- u32 ggpio;
|
|
+ u32 ggpio, gotgctl;
|
|
|
|
ret = regulator_enable(dwc2->usb33d);
|
|
if (ret)
|
|
@@ -625,6 +641,12 @@ static int __maybe_unused dwc2_resume(struct device *dev)
|
|
|
|
/* ID/VBUS detection startup time */
|
|
usleep_range(5000, 7000);
|
|
+
|
|
+ /* Unconditionally clear B-Session Valid override */
|
|
+ gotgctl = dwc2_readl(dwc2, GOTGCTL);
|
|
+ gotgctl &= ~GOTGCTL_BVALOVAL;
|
|
+ gotgctl &= ~GOTGCTL_BVALOEN;
|
|
+ dwc2_writel(dwc2, gotgctl, GOTGCTL);
|
|
}
|
|
|
|
if (dwc2->params.force_b_session_valid) {
|
|
--
|
|
2.7.4
|
|
|