diff options
-rw-r--r-- | arch/arm/include/asm/hardware/pl080.h | 2 | ||||
-rw-r--r-- | drivers/dma/amba-pl08x.c | 44 | ||||
-rw-r--r-- | include/linux/amba/pl08x.h | 3 |
3 files changed, 42 insertions, 7 deletions
diff --git a/arch/arm/include/asm/hardware/pl080.h b/arch/arm/include/asm/hardware/pl080.h index 33c78d7af2e1..4eea2107214b 100644 --- a/arch/arm/include/asm/hardware/pl080.h +++ b/arch/arm/include/asm/hardware/pl080.h | |||
@@ -102,6 +102,8 @@ | |||
102 | #define PL080_WIDTH_16BIT (0x1) | 102 | #define PL080_WIDTH_16BIT (0x1) |
103 | #define PL080_WIDTH_32BIT (0x2) | 103 | #define PL080_WIDTH_32BIT (0x2) |
104 | 104 | ||
105 | #define PL080N_CONFIG_ITPROT (1 << 20) | ||
106 | #define PL080N_CONFIG_SECPROT (1 << 19) | ||
105 | #define PL080_CONFIG_HALT (1 << 18) | 107 | #define PL080_CONFIG_HALT (1 << 18) |
106 | #define PL080_CONFIG_ACTIVE (1 << 17) /* RO */ | 108 | #define PL080_CONFIG_ACTIVE (1 << 17) /* RO */ |
107 | #define PL080_CONFIG_LOCK (1 << 16) | 109 | #define PL080_CONFIG_LOCK (1 << 16) |
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 08589c683e2b..629250e36d3b 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c | |||
@@ -95,10 +95,14 @@ static struct amba_driver pl08x_amba_driver; | |||
95 | * struct vendor_data - vendor-specific config parameters for PL08x derivatives | 95 | * struct vendor_data - vendor-specific config parameters for PL08x derivatives |
96 | * @channels: the number of channels available in this variant | 96 | * @channels: the number of channels available in this variant |
97 | * @dualmaster: whether this version supports dual AHB masters or not. | 97 | * @dualmaster: whether this version supports dual AHB masters or not. |
98 | * @nomadik: whether the channels have Nomadik security extension bits | ||
99 | * that need to be checked for permission before use and some registers are | ||
100 | * missing | ||
98 | */ | 101 | */ |
99 | struct vendor_data { | 102 | struct vendor_data { |
100 | u8 channels; | 103 | u8 channels; |
101 | bool dualmaster; | 104 | bool dualmaster; |
105 | bool nomadik; | ||
102 | }; | 106 | }; |
103 | 107 | ||
104 | /* | 108 | /* |
@@ -385,7 +389,7 @@ pl08x_get_phy_channel(struct pl08x_driver_data *pl08x, | |||
385 | 389 | ||
386 | spin_lock_irqsave(&ch->lock, flags); | 390 | spin_lock_irqsave(&ch->lock, flags); |
387 | 391 | ||
388 | if (!ch->serving) { | 392 | if (!ch->locked && !ch->serving) { |
389 | ch->serving = virt_chan; | 393 | ch->serving = virt_chan; |
390 | ch->signal = -1; | 394 | ch->signal = -1; |
391 | spin_unlock_irqrestore(&ch->lock, flags); | 395 | spin_unlock_irqrestore(&ch->lock, flags); |
@@ -1483,6 +1487,9 @@ bool pl08x_filter_id(struct dma_chan *chan, void *chan_id) | |||
1483 | */ | 1487 | */ |
1484 | static void pl08x_ensure_on(struct pl08x_driver_data *pl08x) | 1488 | static void pl08x_ensure_on(struct pl08x_driver_data *pl08x) |
1485 | { | 1489 | { |
1490 | /* The Nomadik variant does not have the config register */ | ||
1491 | if (pl08x->vd->nomadik) | ||
1492 | return; | ||
1486 | writel(PL080_CONFIG_ENABLE, pl08x->base + PL080_CONFIG); | 1493 | writel(PL080_CONFIG_ENABLE, pl08x->base + PL080_CONFIG); |
1487 | } | 1494 | } |
1488 | 1495 | ||
@@ -1772,8 +1779,10 @@ static int pl08x_debugfs_show(struct seq_file *s, void *data) | |||
1772 | spin_lock_irqsave(&ch->lock, flags); | 1779 | spin_lock_irqsave(&ch->lock, flags); |
1773 | virt_chan = ch->serving; | 1780 | virt_chan = ch->serving; |
1774 | 1781 | ||
1775 | seq_printf(s, "%d\t\t%s\n", | 1782 | seq_printf(s, "%d\t\t%s%s\n", |
1776 | ch->id, virt_chan ? virt_chan->name : "(none)"); | 1783 | ch->id, |
1784 | virt_chan ? virt_chan->name : "(none)", | ||
1785 | ch->locked ? " LOCKED" : ""); | ||
1777 | 1786 | ||
1778 | spin_unlock_irqrestore(&ch->lock, flags); | 1787 | spin_unlock_irqrestore(&ch->lock, flags); |
1779 | } | 1788 | } |
@@ -1917,7 +1926,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) | |||
1917 | } | 1926 | } |
1918 | 1927 | ||
1919 | /* Initialize physical channels */ | 1928 | /* Initialize physical channels */ |
1920 | pl08x->phy_chans = kmalloc((vd->channels * sizeof(*pl08x->phy_chans)), | 1929 | pl08x->phy_chans = kzalloc((vd->channels * sizeof(*pl08x->phy_chans)), |
1921 | GFP_KERNEL); | 1930 | GFP_KERNEL); |
1922 | if (!pl08x->phy_chans) { | 1931 | if (!pl08x->phy_chans) { |
1923 | dev_err(&adev->dev, "%s failed to allocate " | 1932 | dev_err(&adev->dev, "%s failed to allocate " |
@@ -1932,8 +1941,23 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) | |||
1932 | ch->id = i; | 1941 | ch->id = i; |
1933 | ch->base = pl08x->base + PL080_Cx_BASE(i); | 1942 | ch->base = pl08x->base + PL080_Cx_BASE(i); |
1934 | spin_lock_init(&ch->lock); | 1943 | spin_lock_init(&ch->lock); |
1935 | ch->serving = NULL; | ||
1936 | ch->signal = -1; | 1944 | ch->signal = -1; |
1945 | |||
1946 | /* | ||
1947 | * Nomadik variants can have channels that are locked | ||
1948 | * down for the secure world only. Lock up these channels | ||
1949 | * by perpetually serving a dummy virtual channel. | ||
1950 | */ | ||
1951 | if (vd->nomadik) { | ||
1952 | u32 val; | ||
1953 | |||
1954 | val = readl(ch->base + PL080_CH_CONFIG); | ||
1955 | if (val & (PL080N_CONFIG_ITPROT | PL080N_CONFIG_SECPROT)) { | ||
1956 | dev_info(&adev->dev, "physical channel %d reserved for secure access only\n", i); | ||
1957 | ch->locked = true; | ||
1958 | } | ||
1959 | } | ||
1960 | |||
1937 | dev_dbg(&adev->dev, "physical channel %d is %s\n", | 1961 | dev_dbg(&adev->dev, "physical channel %d is %s\n", |
1938 | i, pl08x_phy_channel_busy(ch) ? "BUSY" : "FREE"); | 1962 | i, pl08x_phy_channel_busy(ch) ? "BUSY" : "FREE"); |
1939 | } | 1963 | } |
@@ -2016,6 +2040,12 @@ static struct vendor_data vendor_pl080 = { | |||
2016 | .dualmaster = true, | 2040 | .dualmaster = true, |
2017 | }; | 2041 | }; |
2018 | 2042 | ||
2043 | static struct vendor_data vendor_nomadik = { | ||
2044 | .channels = 8, | ||
2045 | .dualmaster = true, | ||
2046 | .nomadik = true, | ||
2047 | }; | ||
2048 | |||
2019 | static struct vendor_data vendor_pl081 = { | 2049 | static struct vendor_data vendor_pl081 = { |
2020 | .channels = 2, | 2050 | .channels = 2, |
2021 | .dualmaster = false, | 2051 | .dualmaster = false, |
@@ -2036,9 +2066,9 @@ static struct amba_id pl08x_ids[] = { | |||
2036 | }, | 2066 | }, |
2037 | /* Nomadik 8815 PL080 variant */ | 2067 | /* Nomadik 8815 PL080 variant */ |
2038 | { | 2068 | { |
2039 | .id = 0x00280880, | 2069 | .id = 0x00280080, |
2040 | .mask = 0x00ffffff, | 2070 | .mask = 0x00ffffff, |
2041 | .data = &vendor_pl080, | 2071 | .data = &vendor_nomadik, |
2042 | }, | 2072 | }, |
2043 | { 0, 0 }, | 2073 | { 0, 0 }, |
2044 | }; | 2074 | }; |
diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index e64ce2cfee99..02549017212a 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h | |||
@@ -92,6 +92,8 @@ struct pl08x_bus_data { | |||
92 | * right now | 92 | * right now |
93 | * @serving: the virtual channel currently being served by this physical | 93 | * @serving: the virtual channel currently being served by this physical |
94 | * channel | 94 | * channel |
95 | * @locked: channel unavailable for the system, e.g. dedicated to secure | ||
96 | * world | ||
95 | */ | 97 | */ |
96 | struct pl08x_phy_chan { | 98 | struct pl08x_phy_chan { |
97 | unsigned int id; | 99 | unsigned int id; |
@@ -99,6 +101,7 @@ struct pl08x_phy_chan { | |||
99 | spinlock_t lock; | 101 | spinlock_t lock; |
100 | int signal; | 102 | int signal; |
101 | struct pl08x_dma_chan *serving; | 103 | struct pl08x_dma_chan *serving; |
104 | bool locked; | ||
102 | }; | 105 | }; |
103 | 106 | ||
104 | /** | 107 | /** |