Line data Source code
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 : /* MCH IFP BARs */
20 : #define I915_IFPADDR 0x60
21 : #define I965_IFPADDR 0x70
22 :
23 : extern struct cfdriver inteldrm_cd;
24 :
25 : /*
26 : * We're intel IGD, bus 0 function 0 dev 0 should be the GMCH, so it should
27 : * be Intel
28 : */
29 : int
30 0 : inteldrm_gmch_match(struct pci_attach_args *pa)
31 : {
32 0 : if (pa->pa_bus == 0 && pa->pa_device == 0 && pa->pa_function == 0 &&
33 0 : PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL &&
34 0 : PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
35 0 : PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST)
36 0 : return (1);
37 0 : return (0);
38 0 : }
39 :
40 : void
41 0 : i915_alloc_ifp(struct inteldrm_softc *dev_priv, struct pci_attach_args *bpa)
42 : {
43 0 : bus_addr_t addr;
44 : u_int32_t reg;
45 :
46 0 : dev_priv->ifp.i9xx.bst = bpa->pa_memt;
47 :
48 0 : reg = pci_conf_read(bpa->pa_pc, bpa->pa_tag, I915_IFPADDR);
49 0 : if (reg & 0x1) {
50 0 : addr = (bus_addr_t)reg;
51 0 : addr &= ~0x1;
52 : /* XXX extents ... need data on whether bioses alloc or not. */
53 0 : if (bus_space_map(bpa->pa_memt, addr, PAGE_SIZE, 0,
54 0 : &dev_priv->ifp.i9xx.bsh) != 0)
55 : goto nope;
56 0 : return;
57 0 : } else if (bpa->pa_memex == NULL ||
58 0 : extent_alloc_subregion(bpa->pa_memex, 0x100000, 0xffffffff,
59 0 : PAGE_SIZE, PAGE_SIZE, 0, 0, 0, &addr) ||
60 0 : bus_space_map(bpa->pa_memt, addr, PAGE_SIZE, 0,
61 0 : &dev_priv->ifp.i9xx.bsh))
62 : goto nope;
63 :
64 0 : pci_conf_write(bpa->pa_pc, bpa->pa_tag, I915_IFPADDR, addr | 0x1);
65 :
66 0 : return;
67 :
68 : nope:
69 0 : dev_priv->ifp.i9xx.bsh = 0;
70 0 : printf("%s: no ifp\n", dev_priv->sc_dev.dv_xname);
71 0 : }
72 :
73 : void
74 0 : i965_alloc_ifp(struct inteldrm_softc *dev_priv, struct pci_attach_args *bpa)
75 : {
76 0 : bus_addr_t addr;
77 : u_int32_t lo, hi;
78 :
79 0 : dev_priv->ifp.i9xx.bst = bpa->pa_memt;
80 :
81 0 : hi = pci_conf_read(bpa->pa_pc, bpa->pa_tag, I965_IFPADDR + 4);
82 0 : lo = pci_conf_read(bpa->pa_pc, bpa->pa_tag, I965_IFPADDR);
83 0 : if (lo & 0x1) {
84 0 : addr = (((u_int64_t)hi << 32) | lo);
85 0 : addr &= ~0x1;
86 : /* XXX extents ... need data on whether bioses alloc or not. */
87 0 : if (bus_space_map(bpa->pa_memt, addr, PAGE_SIZE, 0,
88 0 : &dev_priv->ifp.i9xx.bsh) != 0)
89 : goto nope;
90 0 : return;
91 0 : } else if (bpa->pa_memex == NULL ||
92 0 : extent_alloc_subregion(bpa->pa_memex, 0x100000, 0xffffffff,
93 0 : PAGE_SIZE, PAGE_SIZE, 0, 0, 0, &addr) ||
94 0 : bus_space_map(bpa->pa_memt, addr, PAGE_SIZE, 0,
95 0 : &dev_priv->ifp.i9xx.bsh))
96 : goto nope;
97 :
98 0 : pci_conf_write(bpa->pa_pc, bpa->pa_tag, I965_IFPADDR + 4,
99 0 : upper_32_bits(addr));
100 0 : pci_conf_write(bpa->pa_pc, bpa->pa_tag, I965_IFPADDR,
101 0 : (addr & 0xffffffff) | 0x1);
102 :
103 0 : return;
104 :
105 : nope:
106 0 : dev_priv->ifp.i9xx.bsh = 0;
107 0 : printf("%s: no ifp\n", dev_priv->sc_dev.dv_xname);
108 0 : }
109 :
110 : void
111 0 : intel_gtt_chipset_setup(struct drm_device *dev)
112 : {
113 0 : struct inteldrm_softc *dev_priv = dev->dev_private;
114 0 : struct pci_attach_args bpa;
115 :
116 0 : if (INTEL_INFO(dev_priv->dev)->gen >= 6)
117 0 : return;
118 :
119 0 : if (pci_find_device(&bpa, inteldrm_gmch_match) == 0) {
120 0 : printf("%s: can't find GMCH\n",
121 0 : dev_priv->sc_dev.dv_xname);
122 0 : return;
123 : }
124 :
125 : /* Set up the IFP for chipset flushing */
126 0 : if (IS_I915G(dev) || IS_I915GM(dev) || IS_I945G(dev) ||
127 0 : IS_I945GM(dev)) {
128 0 : i915_alloc_ifp(dev_priv, &bpa);
129 0 : } else if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev)) {
130 0 : i965_alloc_ifp(dev_priv, &bpa);
131 0 : } else {
132 0 : int nsegs;
133 : /*
134 : * I8XX has no flush page mechanism, we fake it by writing until
135 : * the cache is empty. allocate a page to scribble on
136 : */
137 0 : dev_priv->ifp.i8xx.kva = NULL;
138 0 : if (bus_dmamem_alloc(dev_priv->dmat, PAGE_SIZE, 0, 0,
139 0 : &dev_priv->ifp.i8xx.seg, 1, &nsegs, BUS_DMA_WAITOK) == 0) {
140 0 : if (bus_dmamem_map(dev_priv->dmat, &dev_priv->ifp.i8xx.seg,
141 0 : 1, PAGE_SIZE, &dev_priv->ifp.i8xx.kva, 0) != 0) {
142 0 : bus_dmamem_free(dev_priv->dmat,
143 : &dev_priv->ifp.i8xx.seg, nsegs);
144 0 : dev_priv->ifp.i8xx.kva = NULL;
145 0 : }
146 : }
147 0 : }
148 0 : }
149 :
150 : int
151 0 : intel_enable_gtt()
152 : {
153 0 : struct inteldrm_softc *dev_priv = (void *)inteldrm_cd.cd_devs[0];
154 :
155 0 : intel_gtt_chipset_setup(dev_priv->dev);
156 0 : return 1;
157 : }
158 :
159 : int
160 0 : intel_gmch_probe(struct pci_dev *bridge_dev, struct pci_dev *gpu_pdev,
161 : void *bridge)
162 : {
163 0 : return 1;
164 : }
165 :
166 : void
167 0 : intel_gtt_get(u64 *gtt_total, size_t *stolen_size,
168 : phys_addr_t *mappable_base, u64 *mappable_end)
169 : {
170 0 : struct inteldrm_softc *dev_priv = (void *)inteldrm_cd.cd_devs[0];
171 0 : struct agp_info *ai = &dev_priv->dev->agp->info;
172 :
173 0 : *gtt_total = ai->ai_aperture_size;
174 0 : *stolen_size = 0;
175 0 : *mappable_base = ai->ai_aperture_base;
176 0 : *mappable_end = ai->ai_aperture_size;
177 0 : }
178 :
179 : void
180 0 : intel_gtt_chipset_flush(void)
181 : {
182 0 : struct inteldrm_softc *dev_priv = (void *)inteldrm_cd.cd_devs[0];
183 :
184 : /*
185 : * Write to this flush page flushes the chipset write cache.
186 : * The write will return when it is done.
187 : */
188 0 : if (INTEL_INFO(dev_priv->dev)->gen >= 3) {
189 0 : if (dev_priv->ifp.i9xx.bsh != 0)
190 0 : bus_space_write_4(dev_priv->ifp.i9xx.bst,
191 : dev_priv->ifp.i9xx.bsh, 0, 1);
192 : } else {
193 : int i;
194 :
195 0 : wbinvd();
196 :
197 : #define I830_HIC 0x70
198 :
199 0 : I915_WRITE(I830_HIC, (I915_READ(I830_HIC) | (1<<31)));
200 0 : for (i = 1000; i; i--) {
201 0 : if (!(I915_READ(I830_HIC) & (1<<31)))
202 : break;
203 0 : delay(100);
204 : }
205 :
206 : }
207 0 : }
208 :
209 : void
210 0 : intel_gmch_remove(void)
211 : {
212 0 : }
213 :
214 : void
215 0 : intel_gtt_insert_sg_entries(struct sg_table *pages, unsigned int pg_start,
216 : unsigned int flags)
217 : {
218 0 : struct inteldrm_softc *dev_priv = (void *)inteldrm_cd.cd_devs[0];
219 0 : struct agp_softc *sc = dev_priv->dev->agp->agpdev;
220 0 : bus_addr_t addr = sc->sc_apaddr + pg_start * PAGE_SIZE;
221 0 : struct sg_page_iter sg_iter;
222 :
223 0 : for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) {
224 0 : sc->sc_methods->bind_page(sc->sc_chipc, addr,
225 0 : sg_page_iter_dma_address(&sg_iter), flags);
226 0 : addr += PAGE_SIZE;
227 : }
228 0 : }
229 :
230 : void
231 0 : intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries)
232 : {
233 0 : struct inteldrm_softc *dev_priv = (void *)inteldrm_cd.cd_devs[0];
234 0 : struct agp_softc *sc = dev_priv->dev->agp->agpdev;
235 0 : bus_addr_t addr = sc->sc_apaddr + first_entry * PAGE_SIZE;
236 : int i;
237 :
238 0 : for (i = 0; i < num_entries; i++) {
239 0 : sc->sc_methods->unbind_page(sc->sc_chipc, addr);
240 0 : addr += PAGE_SIZE;
241 : }
242 0 : }
|