Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dma/amba-pl08x: add support for the Nomadik variant

The Nomadik PL080 variant has some extra protection bits that
may be set, so we need to check these bits to see if the
channels are actually available for the DMAengine to use.

Cc: Russell King <linux@arm.linux.org.uk>
Cc: Alim Akhtar <alim.akhtar@gmail.com>
Cc: Alessandro Rubini <rubini@gnudd.com>
Reviewed-by: Viresh Kumar <viresh.kumar@st.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>

authored by

Linus Walleij and committed by
Vinod Koul
affa115e d29bf019

+42 -7
+2
arch/arm/include/asm/hardware/pl080.h
··· 102 102 #define PL080_WIDTH_16BIT (0x1) 103 103 #define PL080_WIDTH_32BIT (0x2) 104 104 105 + #define PL080N_CONFIG_ITPROT (1 << 20) 106 + #define PL080N_CONFIG_SECPROT (1 << 19) 105 107 #define PL080_CONFIG_HALT (1 << 18) 106 108 #define PL080_CONFIG_ACTIVE (1 << 17) /* RO */ 107 109 #define PL080_CONFIG_LOCK (1 << 16)
+37 -7
drivers/dma/amba-pl08x.c
··· 95 95 * struct vendor_data - vendor-specific config parameters for PL08x derivatives 96 96 * @channels: the number of channels available in this variant 97 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 102 struct vendor_data { 100 103 u8 channels; 101 104 bool dualmaster; 105 + bool nomadik; 102 106 }; 103 107 104 108 /* ··· 389 385 390 386 spin_lock_irqsave(&ch->lock, flags); 391 387 392 - if (!ch->serving) { 388 + if (!ch->locked && !ch->serving) { 393 389 ch->serving = virt_chan; 394 390 ch->signal = -1; 395 391 spin_unlock_irqrestore(&ch->lock, flags); ··· 1487 1483 */ 1488 1484 static void pl08x_ensure_on(struct pl08x_driver_data *pl08x) 1489 1485 { 1486 + /* The Nomadik variant does not have the config register */ 1487 + if (pl08x->vd->nomadik) 1488 + return; 1490 1489 writel(PL080_CONFIG_ENABLE, pl08x->base + PL080_CONFIG); 1491 1490 } 1492 1491 ··· 1779 1772 spin_lock_irqsave(&ch->lock, flags); 1780 1773 virt_chan = ch->serving; 1781 1774 1782 - seq_printf(s, "%d\t\t%s\n", 1783 - ch->id, virt_chan ? virt_chan->name : "(none)"); 1775 + seq_printf(s, "%d\t\t%s%s\n", 1776 + ch->id, 1777 + virt_chan ? virt_chan->name : "(none)", 1778 + ch->locked ? " LOCKED" : ""); 1784 1779 1785 1780 spin_unlock_irqrestore(&ch->lock, flags); 1786 1781 } ··· 1926 1917 } 1927 1918 1928 1919 /* Initialize physical channels */ 1929 - pl08x->phy_chans = kmalloc((vd->channels * sizeof(*pl08x->phy_chans)), 1920 + pl08x->phy_chans = kzalloc((vd->channels * sizeof(*pl08x->phy_chans)), 1930 1921 GFP_KERNEL); 1931 1922 if (!pl08x->phy_chans) { 1932 1923 dev_err(&adev->dev, "%s failed to allocate " ··· 1941 1932 ch->id = i; 1942 1933 ch->base = pl08x->base + PL080_Cx_BASE(i); 1943 1934 spin_lock_init(&ch->lock); 1944 - ch->serving = NULL; 1945 1935 ch->signal = -1; 1936 + 1937 + /* 1938 + * Nomadik variants can have channels that are locked 1939 + * down for the secure world only. Lock up these channels 1940 + * by perpetually serving a dummy virtual channel. 1941 + */ 1942 + if (vd->nomadik) { 1943 + u32 val; 1944 + 1945 + val = readl(ch->base + PL080_CH_CONFIG); 1946 + if (val & (PL080N_CONFIG_ITPROT | PL080N_CONFIG_SECPROT)) { 1947 + dev_info(&adev->dev, "physical channel %d reserved for secure access only\n", i); 1948 + ch->locked = true; 1949 + } 1950 + } 1951 + 1946 1952 dev_dbg(&adev->dev, "physical channel %d is %s\n", 1947 1953 i, pl08x_phy_channel_busy(ch) ? "BUSY" : "FREE"); 1948 1954 } ··· 2040 2016 .dualmaster = true, 2041 2017 }; 2042 2018 2019 + static struct vendor_data vendor_nomadik = { 2020 + .channels = 8, 2021 + .dualmaster = true, 2022 + .nomadik = true, 2023 + }; 2024 + 2043 2025 static struct vendor_data vendor_pl081 = { 2044 2026 .channels = 2, 2045 2027 .dualmaster = false, ··· 2066 2036 }, 2067 2037 /* Nomadik 8815 PL080 variant */ 2068 2038 { 2069 - .id = 0x00280880, 2039 + .id = 0x00280080, 2070 2040 .mask = 0x00ffffff, 2071 - .data = &vendor_pl080, 2041 + .data = &vendor_nomadik, 2072 2042 }, 2073 2043 { 0, 0 }, 2074 2044 };
+3
include/linux/amba/pl08x.h
··· 92 92 * right now 93 93 * @serving: the virtual channel currently being served by this physical 94 94 * channel 95 + * @locked: channel unavailable for the system, e.g. dedicated to secure 96 + * world 95 97 */ 96 98 struct pl08x_phy_chan { 97 99 unsigned int id; ··· 101 99 spinlock_t lock; 102 100 int signal; 103 101 struct pl08x_dma_chan *serving; 102 + bool locked; 104 103 }; 105 104 106 105 /**