aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/omapdrm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/omapdrm')
-rw-r--r--drivers/gpu/drm/omapdrm/omap_dmm_priv.h7
-rw-r--r--drivers/gpu/drm/omapdrm/omap_dmm_tiler.c149
2 files changed, 154 insertions, 2 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_priv.h b/drivers/gpu/drm/omapdrm/omap_dmm_priv.h
index c2785cc98dc9..60bb3f9297bc 100644
--- a/drivers/gpu/drm/omapdrm/omap_dmm_priv.h
+++ b/drivers/gpu/drm/omapdrm/omap_dmm_priv.h
@@ -159,6 +159,7 @@ struct dmm_platform_data {
159 159
160struct dmm { 160struct dmm {
161 struct device *dev; 161 struct device *dev;
162 dma_addr_t phys_base;
162 void __iomem *base; 163 void __iomem *base;
163 int irq; 164 int irq;
164 165
@@ -189,6 +190,12 @@ struct dmm {
189 struct list_head alloc_head; 190 struct list_head alloc_head;
190 191
191 const struct dmm_platform_data *plat_data; 192 const struct dmm_platform_data *plat_data;
193
194 bool dmm_workaround;
195 spinlock_t wa_lock;
196 u32 *wa_dma_data;
197 dma_addr_t wa_dma_handle;
198 struct dma_chan *wa_dma_chan;
192}; 199};
193 200
194#endif 201#endif
diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
index 624d2023dd6b..252f5ebb1acc 100644
--- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
+++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
@@ -18,6 +18,7 @@
18#include <linux/completion.h> 18#include <linux/completion.h>
19#include <linux/delay.h> 19#include <linux/delay.h>
20#include <linux/dma-mapping.h> 20#include <linux/dma-mapping.h>
21#include <linux/dmaengine.h>
21#include <linux/errno.h> 22#include <linux/errno.h>
22#include <linux/init.h> 23#include <linux/init.h>
23#include <linux/interrupt.h> 24#include <linux/interrupt.h>
@@ -79,14 +80,138 @@ static const u32 reg[][4] = {
79 DMM_PAT_DESCR__2, DMM_PAT_DESCR__3}, 80 DMM_PAT_DESCR__2, DMM_PAT_DESCR__3},
80}; 81};
81 82
83static int dmm_dma_copy(struct dmm *dmm, dma_addr_t src, dma_addr_t dst)
84{
85 struct dma_device *dma_dev = dmm->wa_dma_chan->device;
86 struct dma_async_tx_descriptor *tx;
87 enum dma_status status;
88 dma_cookie_t cookie;
89
90 tx = dma_dev->device_prep_dma_memcpy(dmm->wa_dma_chan, dst, src, 4, 0);
91 if (!tx) {
92 dev_err(dmm->dev, "Failed to prepare DMA memcpy\n");
93 return -EIO;
94 }
95
96 cookie = tx->tx_submit(tx);
97 if (dma_submit_error(cookie)) {
98 dev_err(dmm->dev, "Failed to do DMA tx_submit\n");
99 return -EIO;
100 }
101
102 dma_async_issue_pending(dmm->wa_dma_chan);
103 status = dma_sync_wait(dmm->wa_dma_chan, cookie);
104 if (status != DMA_COMPLETE)
105 dev_err(dmm->dev, "i878 wa DMA copy failure\n");
106
107 dmaengine_terminate_all(dmm->wa_dma_chan);
108 return 0;
109}
110
111static u32 dmm_read_wa(struct dmm *dmm, u32 reg)
112{
113 dma_addr_t src, dst;
114 int r;
115
116 src = dmm->phys_base + reg;
117 dst = dmm->wa_dma_handle;
118
119 r = dmm_dma_copy(dmm, src, dst);
120 if (r) {
121 dev_err(dmm->dev, "sDMA read transfer timeout\n");
122 return readl(dmm->base + reg);
123 }
124
125 /*
126 * As per i878 workaround, the DMA is used to access the DMM registers.
127 * Make sure that the readl is not moved by the compiler or the CPU
128 * earlier than the DMA finished writing the value to memory.
129 */
130 rmb();
131 return readl(dmm->wa_dma_data);
132}
133
134static void dmm_write_wa(struct dmm *dmm, u32 val, u32 reg)
135{
136 dma_addr_t src, dst;
137 int r;
138
139 writel(val, dmm->wa_dma_data);
140 /*
141 * As per i878 workaround, the DMA is used to access the DMM registers.
142 * Make sure that the writel is not moved by the compiler or the CPU, so
143 * the data will be in place before we start the DMA to do the actual
144 * register write.
145 */
146 wmb();
147
148 src = dmm->wa_dma_handle;
149 dst = dmm->phys_base + reg;
150
151 r = dmm_dma_copy(dmm, src, dst);
152 if (r) {
153 dev_err(dmm->dev, "sDMA write transfer timeout\n");
154 writel(val, dmm->base + reg);
155 }
156}
157
82static u32 dmm_read(struct dmm *dmm, u32 reg) 158static u32 dmm_read(struct dmm *dmm, u32 reg)
83{ 159{
84 return readl(dmm->base + reg); 160 if (dmm->dmm_workaround) {
161 u32 v;
162 unsigned long flags;
163
164 spin_lock_irqsave(&dmm->wa_lock, flags);
165 v = dmm_read_wa(dmm, reg);
166 spin_unlock_irqrestore(&dmm->wa_lock, flags);
167
168 return v;
169 } else {
170 return readl(dmm->base + reg);
171 }
85} 172}
86 173
87static void dmm_write(struct dmm *dmm, u32 val, u32 reg) 174static void dmm_write(struct dmm *dmm, u32 val, u32 reg)
88{ 175{
89 writel(val, dmm->base + reg); 176 if (dmm->dmm_workaround) {
177 unsigned long flags;
178
179 spin_lock_irqsave(&dmm->wa_lock, flags);
180 dmm_write_wa(dmm, val, reg);
181 spin_unlock_irqrestore(&dmm->wa_lock, flags);
182 } else {
183 writel(val, dmm->base + reg);
184 }
185}
186
187static int dmm_workaround_init(struct dmm *dmm)
188{
189 dma_cap_mask_t mask;
190
191 spin_lock_init(&dmm->wa_lock);
192
193 dmm->wa_dma_data = dma_alloc_coherent(dmm->dev, sizeof(u32),
194 &dmm->wa_dma_handle, GFP_KERNEL);
195 if (!dmm->wa_dma_data)
196 return -ENOMEM;
197
198 dma_cap_zero(mask);
199 dma_cap_set(DMA_MEMCPY, mask);
200
201 dmm->wa_dma_chan = dma_request_channel(mask, NULL, NULL);
202 if (!dmm->wa_dma_chan) {
203 dma_free_coherent(dmm->dev, 4, dmm->wa_dma_data, dmm->wa_dma_handle);
204 return -ENODEV;
205 }
206
207 return 0;
208}
209
210static void dmm_workaround_uninit(struct dmm *dmm)
211{
212 dma_release_channel(dmm->wa_dma_chan);
213
214 dma_free_coherent(dmm->dev, 4, dmm->wa_dma_data, dmm->wa_dma_handle);
90} 215}
91 216
92/* simple allocator to grab next 16 byte aligned memory from txn */ 217/* simple allocator to grab next 16 byte aligned memory from txn */
@@ -640,6 +765,9 @@ static int omap_dmm_remove(struct platform_device *dev)
640 if (omap_dmm->dummy_page) 765 if (omap_dmm->dummy_page)
641 __free_page(omap_dmm->dummy_page); 766 __free_page(omap_dmm->dummy_page);
642 767
768 if (omap_dmm->dmm_workaround)
769 dmm_workaround_uninit(omap_dmm);
770
643 iounmap(omap_dmm->base); 771 iounmap(omap_dmm->base);
644 kfree(omap_dmm); 772 kfree(omap_dmm);
645 omap_dmm = NULL; 773 omap_dmm = NULL;
@@ -685,6 +813,7 @@ static int omap_dmm_probe(struct platform_device *dev)
685 goto fail; 813 goto fail;
686 } 814 }
687 815
816 omap_dmm->phys_base = mem->start;
688 omap_dmm->base = ioremap(mem->start, SZ_2K); 817 omap_dmm->base = ioremap(mem->start, SZ_2K);
689 818
690 if (!omap_dmm->base) { 819 if (!omap_dmm->base) {
@@ -700,6 +829,22 @@ static int omap_dmm_probe(struct platform_device *dev)
700 829
701 omap_dmm->dev = &dev->dev; 830 omap_dmm->dev = &dev->dev;
702 831
832 if (of_machine_is_compatible("ti,dra7")) {
833 /*
834 * DRA7 Errata i878 says that MPU should not be used to access
835 * RAM and DMM at the same time. As it's not possible to prevent
836 * MPU accessing RAM, we need to access DMM via a proxy.
837 */
838 if (!dmm_workaround_init(omap_dmm)) {
839 omap_dmm->dmm_workaround = true;
840 dev_info(&dev->dev,
841 "workaround for errata i878 in use\n");
842 } else {
843 dev_warn(&dev->dev,
844 "failed to initialize work-around for i878\n");
845 }
846 }
847
703 hwinfo = dmm_read(omap_dmm, DMM_PAT_HWINFO); 848 hwinfo = dmm_read(omap_dmm, DMM_PAT_HWINFO);
704 omap_dmm->num_engines = (hwinfo >> 24) & 0x1F; 849 omap_dmm->num_engines = (hwinfo >> 24) & 0x1F;
705 omap_dmm->num_lut = (hwinfo >> 16) & 0x1F; 850 omap_dmm->num_lut = (hwinfo >> 16) & 0x1F;