summaryrefslogtreecommitdiffstats
path: root/drivers/dma
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/amba-pl08x.c46
1 files changed, 38 insertions, 8 deletions
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 3d704abd791..e7d5550266e 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -95,10 +95,14 @@ static struct amba_driver pl08x_amba_driver;
* struct vendor_data - vendor-specific config parameters for PL08x derivatives
* @channels: the number of channels available in this variant
* @dualmaster: whether this version supports dual AHB masters or not.
+ * @nomadik: whether the channels have Nomadik security extension bits
+ * that need to be checked for permission before use and some registers are
+ * missing
*/
struct vendor_data {
u8 channels;
bool dualmaster;
+ bool nomadik;
};
/*
@@ -385,7 +389,7 @@ pl08x_get_phy_channel(struct pl08x_driver_data *pl08x,
spin_lock_irqsave(&ch->lock, flags);
- if (!ch->serving) {
+ if (!ch->locked && !ch->serving) {
ch->serving = virt_chan;
ch->signal = -1;
spin_unlock_irqrestore(&ch->lock, flags);
@@ -1484,6 +1488,9 @@ bool pl08x_filter_id(struct dma_chan *chan, void *chan_id)
*/
static void pl08x_ensure_on(struct pl08x_driver_data *pl08x)
{
+ /* The Nomadik variant does not have the config register */
+ if (pl08x->vd->nomadik)
+ return;
writel(PL080_CONFIG_ENABLE, pl08x->base + PL080_CONFIG);
}
@@ -1616,7 +1623,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
__func__, err);
writel(err, pl08x->base + PL080_ERR_CLEAR);
}
- tc = readl(pl08x->base + PL080_INT_STATUS);
+ tc = readl(pl08x->base + PL080_TC_STATUS);
if (tc)
writel(tc, pl08x->base + PL080_TC_CLEAR);
@@ -1773,8 +1780,10 @@ static int pl08x_debugfs_show(struct seq_file *s, void *data)
spin_lock_irqsave(&ch->lock, flags);
virt_chan = ch->serving;
- seq_printf(s, "%d\t\t%s\n",
- ch->id, virt_chan ? virt_chan->name : "(none)");
+ seq_printf(s, "%d\t\t%s%s\n",
+ ch->id,
+ virt_chan ? virt_chan->name : "(none)",
+ ch->locked ? " LOCKED" : "");
spin_unlock_irqrestore(&ch->lock, flags);
}
@@ -1918,7 +1927,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
}
/* Initialize physical channels */
- pl08x->phy_chans = kmalloc((vd->channels * sizeof(*pl08x->phy_chans)),
+ pl08x->phy_chans = kzalloc((vd->channels * sizeof(*pl08x->phy_chans)),
GFP_KERNEL);
if (!pl08x->phy_chans) {
dev_err(&adev->dev, "%s failed to allocate "
@@ -1933,8 +1942,23 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
ch->id = i;
ch->base = pl08x->base + PL080_Cx_BASE(i);
spin_lock_init(&ch->lock);
- ch->serving = NULL;
ch->signal = -1;
+
+ /*
+ * Nomadik variants can have channels that are locked
+ * down for the secure world only. Lock up these channels
+ * by perpetually serving a dummy virtual channel.
+ */
+ if (vd->nomadik) {
+ u32 val;
+
+ val = readl(ch->base + PL080_CH_CONFIG);
+ if (val & (PL080N_CONFIG_ITPROT | PL080N_CONFIG_SECPROT)) {
+ dev_info(&adev->dev, "physical channel %d reserved for secure access only\n", i);
+ ch->locked = true;
+ }
+ }
+
dev_dbg(&adev->dev, "physical channel %d is %s\n",
i, pl08x_phy_channel_busy(ch) ? "BUSY" : "FREE");
}
@@ -2017,6 +2041,12 @@ static struct vendor_data vendor_pl080 = {
.dualmaster = true,
};
+static struct vendor_data vendor_nomadik = {
+ .channels = 8,
+ .dualmaster = true,
+ .nomadik = true,
+};
+
static struct vendor_data vendor_pl081 = {
.channels = 2,
.dualmaster = false,
@@ -2037,9 +2067,9 @@ static struct amba_id pl08x_ids[] = {
},
/* Nomadik 8815 PL080 variant */
{
- .id = 0x00280880,
+ .id = 0x00280080,
.mask = 0x00ffffff,
- .data = &vendor_pl080,
+ .data = &vendor_nomadik,
},
{ 0, 0 },
};