1 /*
2 * Copyright (c) 2008-2009 Owain G. Ainsworth <oga@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "../i915_drv.h"
18
19 #include <drm/drm_legacy.h> /* for agp */
20
21 /* MCH IFP BARs */
22 #define I915_IFPADDR 0x60
23 #define I965_IFPADDR 0x70
24
25 extern struct cfdriver inteldrm_cd;
26
27 #ifdef __amd64__
28 #define membar_producer_wc() __asm volatile("sfence":::"memory")
29 #else
30 #define membar_producer_wc() __asm volatile(\
31 "lock; addl $0,0(%%esp)":::"memory")
32 #endif
33
34 /*
35 * We're intel IGD, bus 0 function 0 dev 0 should be the GMCH, so it should
36 * be Intel
37 */
38 int
inteldrm_gmch_match(struct pci_attach_args * pa)39 inteldrm_gmch_match(struct pci_attach_args *pa)
40 {
41 if (pa->pa_bus == 0 && pa->pa_device == 0 && pa->pa_function == 0 &&
42 PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL &&
43 PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
44 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST)
45 return (1);
46 return (0);
47 }
48
49 void
i915_alloc_ifp(struct inteldrm_softc * dev_priv,struct pci_attach_args * bpa)50 i915_alloc_ifp(struct inteldrm_softc *dev_priv, struct pci_attach_args *bpa)
51 {
52 bus_addr_t addr;
53 u_int32_t reg;
54
55 dev_priv->ifp.i9xx.bst = bpa->pa_memt;
56
57 reg = pci_conf_read(bpa->pa_pc, bpa->pa_tag, I915_IFPADDR);
58 if (reg & 0x1) {
59 addr = (bus_addr_t)reg;
60 addr &= ~0x1;
61 /* XXX extents ... need data on whether bioses alloc or not. */
62 if (bus_space_map(bpa->pa_memt, addr, PAGE_SIZE, 0,
63 &dev_priv->ifp.i9xx.bsh) != 0)
64 goto nope;
65 return;
66 } else if (bpa->pa_memex == NULL ||
67 extent_alloc_subregion(bpa->pa_memex, 0x100000, 0xffffffff,
68 PAGE_SIZE, PAGE_SIZE, 0, 0, 0, &addr) ||
69 bus_space_map(bpa->pa_memt, addr, PAGE_SIZE, 0,
70 &dev_priv->ifp.i9xx.bsh))
71 goto nope;
72
73 pci_conf_write(bpa->pa_pc, bpa->pa_tag, I915_IFPADDR, addr | 0x1);
74
75 return;
76
77 nope:
78 dev_priv->ifp.i9xx.bsh = 0;
79 printf("%s: no ifp\n", dev_priv->sc_dev.dv_xname);
80 }
81
82 void
i965_alloc_ifp(struct inteldrm_softc * dev_priv,struct pci_attach_args * bpa)83 i965_alloc_ifp(struct inteldrm_softc *dev_priv, struct pci_attach_args *bpa)
84 {
85 bus_addr_t addr;
86 u_int32_t lo, hi;
87
88 dev_priv->ifp.i9xx.bst = bpa->pa_memt;
89
90 hi = pci_conf_read(bpa->pa_pc, bpa->pa_tag, I965_IFPADDR + 4);
91 lo = pci_conf_read(bpa->pa_pc, bpa->pa_tag, I965_IFPADDR);
92 if (lo & 0x1) {
93 addr = (((u_int64_t)hi << 32) | lo);
94 addr &= ~0x1;
95 /* XXX extents ... need data on whether bioses alloc or not. */
96 if (bus_space_map(bpa->pa_memt, addr, PAGE_SIZE, 0,
97 &dev_priv->ifp.i9xx.bsh) != 0)
98 goto nope;
99 return;
100 } else if (bpa->pa_memex == NULL ||
101 extent_alloc_subregion(bpa->pa_memex, 0x100000, 0xffffffff,
102 PAGE_SIZE, PAGE_SIZE, 0, 0, 0, &addr) ||
103 bus_space_map(bpa->pa_memt, addr, PAGE_SIZE, 0,
104 &dev_priv->ifp.i9xx.bsh))
105 goto nope;
106
107 pci_conf_write(bpa->pa_pc, bpa->pa_tag, I965_IFPADDR + 4,
108 upper_32_bits(addr));
109 pci_conf_write(bpa->pa_pc, bpa->pa_tag, I965_IFPADDR,
110 (addr & 0xffffffff) | 0x1);
111
112 return;
113
114 nope:
115 dev_priv->ifp.i9xx.bsh = 0;
116 printf("%s: no ifp\n", dev_priv->sc_dev.dv_xname);
117 }
118
119 void
intel_gtt_chipset_setup(struct drm_device * dev)120 intel_gtt_chipset_setup(struct drm_device *dev)
121 {
122 struct inteldrm_softc *dev_priv = dev->dev_private;
123 struct pci_attach_args bpa;
124
125 if (GRAPHICS_VER(dev_priv) >= 6)
126 return;
127
128 if (pci_find_device(&bpa, inteldrm_gmch_match) == 0) {
129 printf("%s: can't find GMCH\n",
130 dev_priv->sc_dev.dv_xname);
131 return;
132 }
133
134 /* Set up the IFP for chipset flushing */
135 if (GRAPHICS_VER(dev_priv) >= 4 || IS_G33(dev_priv)) {
136 i965_alloc_ifp(dev_priv, &bpa);
137 } else if (GRAPHICS_VER(dev_priv) == 3) {
138 i915_alloc_ifp(dev_priv, &bpa);
139 } else {
140 int nsegs;
141 /*
142 * I8XX has no flush page mechanism, we fake it by writing until
143 * the cache is empty. allocate a page to scribble on
144 */
145 dev_priv->ifp.i8xx.kva = NULL;
146 if (bus_dmamem_alloc(dev_priv->dmat, PAGE_SIZE, 0, 0,
147 &dev_priv->ifp.i8xx.seg, 1, &nsegs, BUS_DMA_WAITOK) == 0) {
148 if (bus_dmamem_map(dev_priv->dmat, &dev_priv->ifp.i8xx.seg,
149 1, PAGE_SIZE, &dev_priv->ifp.i8xx.kva, 0) != 0) {
150 bus_dmamem_free(dev_priv->dmat,
151 &dev_priv->ifp.i8xx.seg, nsegs);
152 dev_priv->ifp.i8xx.kva = NULL;
153 }
154 }
155 }
156 }
157
158 int
intel_gmch_enable_gtt(void)159 intel_gmch_enable_gtt(void)
160 {
161 struct inteldrm_softc *dev_priv = (void *)inteldrm_cd.cd_devs[0];
162
163 intel_gtt_chipset_setup(&dev_priv->drm);
164 return 1;
165 }
166
167 int
intel_gmch_probe(struct pci_dev * bridge_dev,struct pci_dev * gpu_pdev,void * bridge)168 intel_gmch_probe(struct pci_dev *bridge_dev, struct pci_dev *gpu_pdev,
169 void *bridge)
170 {
171 return 1;
172 }
173
174 void
intel_gmch_gtt_get(u64 * gtt_total,phys_addr_t * mappable_base,resource_size_t * mappable_end)175 intel_gmch_gtt_get(u64 *gtt_total,
176 phys_addr_t *mappable_base, resource_size_t *mappable_end)
177 {
178 struct inteldrm_softc *dev_priv = (void *)inteldrm_cd.cd_devs[0];
179 struct agp_info *ai = &dev_priv->drm.agp->info;
180
181 *gtt_total = ai->ai_aperture_size;
182 *mappable_base = ai->ai_aperture_base;
183 *mappable_end = ai->ai_aperture_size;
184 }
185
186 void
intel_gmch_gtt_flush(void)187 intel_gmch_gtt_flush(void)
188 {
189 struct inteldrm_softc *dev_priv = (void *)inteldrm_cd.cd_devs[0];
190
191 /*
192 * Write to this flush page flushes the chipset write cache.
193 * The write will return when it is done.
194 */
195 if (GRAPHICS_VER(dev_priv) >= 3) {
196 if (dev_priv->ifp.i9xx.bsh != 0)
197 bus_space_write_4(dev_priv->ifp.i9xx.bst,
198 dev_priv->ifp.i9xx.bsh, 0, 1);
199 } else {
200 int i;
201 #define I830_HIC 0x70
202 i915_reg_t hic = _MMIO(I830_HIC);
203
204 wbinvd_on_all_cpus();
205
206 intel_uncore_write(&dev_priv->uncore, hic,
207 (intel_uncore_read(&dev_priv->uncore, hic) | (1<<31)));
208 for (i = 1000; i; i--) {
209 if (!(intel_uncore_read(&dev_priv->uncore, hic) & (1<<31)))
210 break;
211 delay(100);
212 }
213
214 }
215 }
216
217 void
intel_gmch_remove(void)218 intel_gmch_remove(void)
219 {
220 }
221
222 void
intel_gmch_gtt_insert_sg_entries(struct sg_table * pages,unsigned int pg_start,unsigned int flags)223 intel_gmch_gtt_insert_sg_entries(struct sg_table *pages, unsigned int pg_start,
224 unsigned int flags)
225 {
226 struct inteldrm_softc *dev_priv = (void *)inteldrm_cd.cd_devs[0];
227 struct agp_softc *sc = dev_priv->drm.agp->agpdev;
228 bus_addr_t addr = sc->sc_apaddr + pg_start * PAGE_SIZE;
229 struct sg_page_iter sg_iter;
230
231 for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) {
232 sc->sc_methods->bind_page(sc->sc_chipc, addr,
233 sg_page_iter_dma_address(&sg_iter), flags);
234 addr += PAGE_SIZE;
235 }
236 membar_producer_wc();
237 intel_gmch_gtt_flush();
238 }
239
240 void
intel_gmch_gtt_insert_page(dma_addr_t addr,unsigned int pg,unsigned int flags)241 intel_gmch_gtt_insert_page(dma_addr_t addr, unsigned int pg,
242 unsigned int flags)
243 {
244 struct inteldrm_softc *dev_priv = (void *)inteldrm_cd.cd_devs[0];
245 struct agp_softc *sc = dev_priv->drm.agp->agpdev;
246 bus_addr_t apaddr = sc->sc_apaddr + (pg * PAGE_SIZE);
247 sc->sc_methods->bind_page(sc->sc_chipc, apaddr, addr, flags);
248 intel_gmch_gtt_flush();
249 }
250
251 void
intel_gmch_gtt_clear_range(unsigned int first_entry,unsigned int num_entries)252 intel_gmch_gtt_clear_range(unsigned int first_entry, unsigned int num_entries)
253 {
254 struct inteldrm_softc *dev_priv = (void *)inteldrm_cd.cd_devs[0];
255 struct agp_softc *sc = dev_priv->drm.agp->agpdev;
256 bus_addr_t addr = sc->sc_apaddr + first_entry * PAGE_SIZE;
257 int i;
258
259 for (i = 0; i < num_entries; i++) {
260 sc->sc_methods->unbind_page(sc->sc_chipc, addr);
261 addr += PAGE_SIZE;
262 }
263 membar_producer_wc();
264 }
265