1*f41a5bb1Sriastradh /*	$NetBSD: intel_gtt_subr.c,v 1.3 2021/12/19 12:37:36 riastradh Exp $	*/
20c301abaSriastradh 
30c301abaSriastradh /*-
40c301abaSriastradh  * Copyright (c) 2014 The NetBSD Foundation, Inc.
50c301abaSriastradh  * All rights reserved.
60c301abaSriastradh  *
70c301abaSriastradh  * This code is derived from software contributed to The NetBSD Foundation
80c301abaSriastradh  * by Taylor R. Campbell.
90c301abaSriastradh  *
100c301abaSriastradh  * Redistribution and use in source and binary forms, with or without
110c301abaSriastradh  * modification, are permitted provided that the following conditions
120c301abaSriastradh  * are met:
130c301abaSriastradh  * 1. Redistributions of source code must retain the above copyright
140c301abaSriastradh  *    notice, this list of conditions and the following disclaimer.
150c301abaSriastradh  * 2. Redistributions in binary form must reproduce the above copyright
160c301abaSriastradh  *    notice, this list of conditions and the following disclaimer in the
170c301abaSriastradh  *    documentation and/or other materials provided with the distribution.
180c301abaSriastradh  *
190c301abaSriastradh  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
200c301abaSriastradh  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
210c301abaSriastradh  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
220c301abaSriastradh  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
230c301abaSriastradh  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
240c301abaSriastradh  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
250c301abaSriastradh  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
260c301abaSriastradh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
270c301abaSriastradh  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
280c301abaSriastradh  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
290c301abaSriastradh  * POSSIBILITY OF SUCH DAMAGE.
300c301abaSriastradh  */
310c301abaSriastradh 
320c301abaSriastradh /* Intel GTT stubs */
330c301abaSriastradh 
340c301abaSriastradh #include <sys/cdefs.h>
35*f41a5bb1Sriastradh __KERNEL_RCSID(0, "$NetBSD: intel_gtt_subr.c,v 1.3 2021/12/19 12:37:36 riastradh Exp $");
360c301abaSriastradh 
370c301abaSriastradh #include <sys/types.h>
380c301abaSriastradh #include <sys/bus.h>
390c301abaSriastradh #include <sys/errno.h>
400c301abaSriastradh #include <sys/systm.h>
410c301abaSriastradh 
420c301abaSriastradh #include <machine/vmparam.h>
430c301abaSriastradh 
440c301abaSriastradh #include <dev/pci/pcivar.h>		/* XXX agpvar.h needs...  */
450c301abaSriastradh #include <dev/pci/agpvar.h>
460c301abaSriastradh #include <dev/pci/agp_i810var.h>
470c301abaSriastradh 
48c987c5e0Sriastradh #include <linux/pci.h>
490c301abaSriastradh #include <linux/scatterlist.h>
500c301abaSriastradh 
51c987c5e0Sriastradh #include "drm/i915_drm.h"
520c301abaSriastradh #include "drm/intel-gtt.h"
530c301abaSriastradh 
54c987c5e0Sriastradh static uint8_t
pci_conf_read8(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t reg)55c987c5e0Sriastradh pci_conf_read8(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t reg)
56c987c5e0Sriastradh {
57c987c5e0Sriastradh 	uint32_t v;
58c987c5e0Sriastradh 
59c987c5e0Sriastradh 	v = pci_conf_read(pc, tag, reg & ~3);
60c987c5e0Sriastradh 
61c987c5e0Sriastradh 	return 0xff & (v >> (8 * (reg & 3)));
62c987c5e0Sriastradh }
63c987c5e0Sriastradh 
64c987c5e0Sriastradh static uint8_t
pci_read8(pci_chipset_tag_t pc,int bus,int dev,int func,bus_size_t reg)65c987c5e0Sriastradh pci_read8(pci_chipset_tag_t pc, int bus, int dev, int func, bus_size_t reg)
66c987c5e0Sriastradh {
67c987c5e0Sriastradh 	pcitag_t tag = pci_make_tag(pc, bus, dev, func);
68c987c5e0Sriastradh 
69c987c5e0Sriastradh 	return pci_conf_read8(pc, tag, reg);
70c987c5e0Sriastradh }
71c987c5e0Sriastradh 
72c987c5e0Sriastradh static uint16_t
pci_conf_read16(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t reg)73c987c5e0Sriastradh pci_conf_read16(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t reg)
74c987c5e0Sriastradh {
75c987c5e0Sriastradh 	uint32_t v;
76c987c5e0Sriastradh 
77c987c5e0Sriastradh 	KASSERT((reg & 1) == 0);
78c987c5e0Sriastradh 
79c987c5e0Sriastradh 	v = pci_conf_read(pc, tag, reg & ~2);
80c987c5e0Sriastradh 
81c987c5e0Sriastradh 	return 0xffff & (v >> (8 * (reg & 2)));
82c987c5e0Sriastradh }
83c987c5e0Sriastradh 
84c987c5e0Sriastradh static uint16_t
pci_read16(pci_chipset_tag_t pc,int bus,int dev,int func,bus_size_t reg)85c987c5e0Sriastradh pci_read16(pci_chipset_tag_t pc, int bus, int dev, int func, bus_size_t reg)
86c987c5e0Sriastradh {
87c987c5e0Sriastradh 	pcitag_t tag = pci_make_tag(pc, bus, dev, func);
88c987c5e0Sriastradh 
89c987c5e0Sriastradh 	return pci_conf_read16(pc, tag, reg);
90c987c5e0Sriastradh }
91c987c5e0Sriastradh 
920c301abaSriastradh /* Access to this should be single-threaded.  */
930c301abaSriastradh static struct {
940c301abaSriastradh 	bus_dma_segment_t	scratch_seg;
950c301abaSriastradh 	bus_dmamap_t		scratch_map;
960c301abaSriastradh } intel_gtt;
970c301abaSriastradh 
98c987c5e0Sriastradh /* XXX This logic should be merged with agp_i810.c.  */
990c301abaSriastradh struct resource intel_graphics_stolen_res;
1000c301abaSriastradh 
101c987c5e0Sriastradh static bus_size_t
i830_tseg_size(pci_chipset_tag_t pc)102c987c5e0Sriastradh i830_tseg_size(pci_chipset_tag_t pc)
103c987c5e0Sriastradh {
104c987c5e0Sriastradh 	uint8_t esmramc = pci_read8(pc, 0, 0, 0, I830_ESMRAMC);
105c987c5e0Sriastradh 
106c987c5e0Sriastradh 	if ((esmramc & TSEG_ENABLE) == 0)
107c987c5e0Sriastradh 		return 0;
108c987c5e0Sriastradh 
109c987c5e0Sriastradh 	return (esmramc & I830_TSEG_SIZE_1M) ? 1024*1024 : 512*1024;
110c987c5e0Sriastradh }
111c987c5e0Sriastradh 
112c987c5e0Sriastradh static bus_size_t
i845_tseg_size(pci_chipset_tag_t pc)113c987c5e0Sriastradh i845_tseg_size(pci_chipset_tag_t pc)
114c987c5e0Sriastradh {
115c987c5e0Sriastradh 	uint8_t esmramc = pci_read8(pc, 0, 0, 0, I845_ESMRAMC);
116c987c5e0Sriastradh 
117c987c5e0Sriastradh 	if ((esmramc & TSEG_ENABLE) == 0)
118c987c5e0Sriastradh 		return 0;
119c987c5e0Sriastradh 
120c987c5e0Sriastradh 	switch (esmramc & I845_TSEG_SIZE_MASK) {
121c987c5e0Sriastradh 	case I845_TSEG_SIZE_512K:
122c987c5e0Sriastradh 		return 512*1024;
123c987c5e0Sriastradh 	case I845_TSEG_SIZE_1M:
124c987c5e0Sriastradh 		return 1024*1024;
125c987c5e0Sriastradh 	default:
126c987c5e0Sriastradh 		return 0;
127c987c5e0Sriastradh 	}
128c987c5e0Sriastradh }
129c987c5e0Sriastradh 
130c987c5e0Sriastradh static bus_size_t
i85x_tseg_size(pci_chipset_tag_t pc)131c987c5e0Sriastradh i85x_tseg_size(pci_chipset_tag_t pc)
132c987c5e0Sriastradh {
133c987c5e0Sriastradh 	uint8_t esmramc = pci_read8(pc, 0, 0, 0, I85X_ESMRAMC);
134c987c5e0Sriastradh 
135c987c5e0Sriastradh 	if ((esmramc & TSEG_ENABLE) == 0)
136c987c5e0Sriastradh 		return 0;
137c987c5e0Sriastradh 
138c987c5e0Sriastradh 	return 1024*1024;
139c987c5e0Sriastradh }
140c987c5e0Sriastradh 
141c987c5e0Sriastradh static bus_size_t
i830_tom(pci_chipset_tag_t pc)142c987c5e0Sriastradh i830_tom(pci_chipset_tag_t pc)
143c987c5e0Sriastradh {
144c987c5e0Sriastradh 	uint8_t drb3 = pci_read8(pc, 0, 0, 0, I830_DRB3);
145c987c5e0Sriastradh 
146c987c5e0Sriastradh 	return (bus_size_t)32*1024*1024 * drb3;
147c987c5e0Sriastradh }
148c987c5e0Sriastradh 
149c987c5e0Sriastradh static bus_size_t
i85x_tom(pci_chipset_tag_t pc)150c987c5e0Sriastradh i85x_tom(pci_chipset_tag_t pc)
151c987c5e0Sriastradh {
152c987c5e0Sriastradh 	uint8_t drb3 = pci_read8(pc, 0, 0, 1, I85X_DRB3);
153c987c5e0Sriastradh 
154c987c5e0Sriastradh 	return (bus_size_t)32*1024*1024 * drb3;
155c987c5e0Sriastradh }
156c987c5e0Sriastradh 
157c987c5e0Sriastradh static bus_size_t
i830_stolen_size(pci_chipset_tag_t pc,pcitag_t tag)158c987c5e0Sriastradh i830_stolen_size(pci_chipset_tag_t pc, pcitag_t tag)
159c987c5e0Sriastradh {
160c987c5e0Sriastradh 	uint16_t gmch_ctrl = pci_read16(pc, 0, 0, 0, I830_GMCH_CTRL);
161c987c5e0Sriastradh 
162c987c5e0Sriastradh 	switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
163c987c5e0Sriastradh 	case I830_GMCH_GMS_STOLEN_512:
164c987c5e0Sriastradh 		return 512*1024;
165c987c5e0Sriastradh 	case I830_GMCH_GMS_STOLEN_1024:
166c987c5e0Sriastradh 		return 1024*1024;
167c987c5e0Sriastradh 	case I830_GMCH_GMS_STOLEN_8192:
168c987c5e0Sriastradh 		return 8*1024*1024;
169c987c5e0Sriastradh 	case I830_GMCH_GMS_LOCAL:
170c987c5e0Sriastradh 	default:
171c987c5e0Sriastradh 		aprint_error("%s: invalid gmch_ctrl 0x%04x\n", __func__,
172c987c5e0Sriastradh 		    gmch_ctrl);
173c987c5e0Sriastradh 		return 0;
174c987c5e0Sriastradh 	}
175c987c5e0Sriastradh }
176c987c5e0Sriastradh 
177c987c5e0Sriastradh static bus_size_t
gen3_stolen_size(pci_chipset_tag_t pc,pcitag_t tag)178c987c5e0Sriastradh gen3_stolen_size(pci_chipset_tag_t pc, pcitag_t tag)
179c987c5e0Sriastradh {
180c987c5e0Sriastradh 	uint16_t gmch_ctrl = pci_read16(pc, 0, 0, 0, I830_GMCH_CTRL);
181c987c5e0Sriastradh 
182c987c5e0Sriastradh 	switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
183c987c5e0Sriastradh 	case I855_GMCH_GMS_STOLEN_1M:
184c987c5e0Sriastradh 		return 1024*1024;
185c987c5e0Sriastradh 	case I855_GMCH_GMS_STOLEN_4M:
186c987c5e0Sriastradh 		return 4*1024*1024;
187c987c5e0Sriastradh 	case I855_GMCH_GMS_STOLEN_8M:
188c987c5e0Sriastradh 		return 8*1024*1024;
189c987c5e0Sriastradh 	case I855_GMCH_GMS_STOLEN_16M:
190c987c5e0Sriastradh 		return 16*1024*1024;
191c987c5e0Sriastradh 	case I855_GMCH_GMS_STOLEN_32M:
192c987c5e0Sriastradh 		return 32*1024*1024;
193c987c5e0Sriastradh 	case I915_GMCH_GMS_STOLEN_48M:
194c987c5e0Sriastradh 		return 48*1024*1024;
195c987c5e0Sriastradh 	case I915_GMCH_GMS_STOLEN_64M:
196c987c5e0Sriastradh 		return 64*1024*1024;
197c987c5e0Sriastradh 	case G33_GMCH_GMS_STOLEN_128M:
198c987c5e0Sriastradh 		return 128*1024*1024;
199c987c5e0Sriastradh 	case G33_GMCH_GMS_STOLEN_256M:
200c987c5e0Sriastradh 		return 256*1024*1024;
201c987c5e0Sriastradh 	case INTEL_GMCH_GMS_STOLEN_96M:
202c987c5e0Sriastradh 		return 96*1024*1024;
203c987c5e0Sriastradh 	case INTEL_GMCH_GMS_STOLEN_160M:
204c987c5e0Sriastradh 		return 160*1024*1024;
205c987c5e0Sriastradh 	case INTEL_GMCH_GMS_STOLEN_224M:
206c987c5e0Sriastradh 		return 224*1024*1024;
207c987c5e0Sriastradh 	case INTEL_GMCH_GMS_STOLEN_352M:
208c987c5e0Sriastradh 		return 352*1024*1024;
209c987c5e0Sriastradh 	default:
210c987c5e0Sriastradh 		aprint_error("%s: invalid gmch_ctrl 0x%04x\n", __func__,
211c987c5e0Sriastradh 		    gmch_ctrl);
212c987c5e0Sriastradh 		return 0;
213c987c5e0Sriastradh 	}
214c987c5e0Sriastradh }
215c987c5e0Sriastradh 
216c987c5e0Sriastradh static bus_size_t
gen6_stolen_size(pci_chipset_tag_t pc,pcitag_t tag)217c987c5e0Sriastradh gen6_stolen_size(pci_chipset_tag_t pc, pcitag_t tag)
218c987c5e0Sriastradh {
219c987c5e0Sriastradh 	uint16_t gmch_ctrl = pci_conf_read16(pc, tag, SNB_GMCH_CTRL);
220c987c5e0Sriastradh 	uint16_t gms = (gmch_ctrl >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK;
221c987c5e0Sriastradh 
222c987c5e0Sriastradh 	return (bus_size_t)32*1024*1024 * gms;
223c987c5e0Sriastradh }
224c987c5e0Sriastradh 
225c987c5e0Sriastradh static bus_size_t
gen8_stolen_size(pci_chipset_tag_t pc,pcitag_t tag)226c987c5e0Sriastradh gen8_stolen_size(pci_chipset_tag_t pc, pcitag_t tag)
227c987c5e0Sriastradh {
228c987c5e0Sriastradh 	uint16_t gmch_ctrl = pci_conf_read16(pc, tag, SNB_GMCH_CTRL);
229c987c5e0Sriastradh 	uint16_t gms = (gmch_ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK;
230c987c5e0Sriastradh 
231c987c5e0Sriastradh 	return (bus_size_t)32*1024*1024 * gms;
232c987c5e0Sriastradh }
233c987c5e0Sriastradh 
234c987c5e0Sriastradh static bus_size_t
chv_stolen_size(pci_chipset_tag_t pc,pcitag_t tag)235c987c5e0Sriastradh chv_stolen_size(pci_chipset_tag_t pc, pcitag_t tag)
236c987c5e0Sriastradh {
237c987c5e0Sriastradh 	uint16_t gmch_ctrl = pci_conf_read16(pc, tag, SNB_GMCH_CTRL);
238c987c5e0Sriastradh 	uint16_t gms = (gmch_ctrl >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK;
239c987c5e0Sriastradh 
240c987c5e0Sriastradh 	if (gms <= 0x10)
241c987c5e0Sriastradh 		return (bus_size_t)32*1024*1024 * gms;
242c987c5e0Sriastradh 	else if (gms <= 0x16)
243c987c5e0Sriastradh 		return (bus_size_t)(8 + 4*(gms - 0x11))*1024*1024;
244c987c5e0Sriastradh 	else
245c987c5e0Sriastradh 		return (bus_size_t)(36 + 4*(gms - 0x17))*1024*1024;
246c987c5e0Sriastradh }
247c987c5e0Sriastradh 
248c987c5e0Sriastradh static bus_size_t
gen9_stolen_size(pci_chipset_tag_t pc,pcitag_t tag)249c987c5e0Sriastradh gen9_stolen_size(pci_chipset_tag_t pc, pcitag_t tag)
250c987c5e0Sriastradh {
251c987c5e0Sriastradh 	uint16_t gmch_ctrl = pci_conf_read16(pc, tag, SNB_GMCH_CTRL);
252c987c5e0Sriastradh 	uint16_t gms = (gmch_ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK;
253c987c5e0Sriastradh 
254c987c5e0Sriastradh 	if (gms <= 0xef)
255c987c5e0Sriastradh 		return (bus_size_t)32*1024*1024 * gms;
256c987c5e0Sriastradh 	else
257c987c5e0Sriastradh 		return (bus_size_t)(4 + 4*(gms - 0xf0))*1024*1024;
258c987c5e0Sriastradh }
259c987c5e0Sriastradh 
260c987c5e0Sriastradh static bus_addr_t
i830_stolen_base(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t stolen_size)261c987c5e0Sriastradh i830_stolen_base(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t stolen_size)
262c987c5e0Sriastradh {
263c987c5e0Sriastradh 
264c987c5e0Sriastradh 	return i830_tom(pc) - i830_tseg_size(pc) - stolen_size;
265c987c5e0Sriastradh }
266c987c5e0Sriastradh 
267c987c5e0Sriastradh static bus_addr_t
i845_stolen_base(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t stolen_size)268c987c5e0Sriastradh i845_stolen_base(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t stolen_size)
269c987c5e0Sriastradh {
270c987c5e0Sriastradh 
271c987c5e0Sriastradh 	return i830_tom(pc) - i845_tseg_size(pc) - stolen_size;
272c987c5e0Sriastradh }
273c987c5e0Sriastradh 
274c987c5e0Sriastradh static bus_addr_t
i85x_stolen_base(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t stolen_size)275c987c5e0Sriastradh i85x_stolen_base(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t stolen_size)
276c987c5e0Sriastradh {
277c987c5e0Sriastradh 
278c987c5e0Sriastradh 	return i85x_tom(pc) - i85x_tseg_size(pc) - stolen_size;
279c987c5e0Sriastradh }
280c987c5e0Sriastradh 
281c987c5e0Sriastradh static bus_addr_t
i865_stolen_base(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t stolen_size)282c987c5e0Sriastradh i865_stolen_base(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t stolen_size)
283c987c5e0Sriastradh {
284c987c5e0Sriastradh 	uint16_t toud = pci_read16(pc, 0, 0, 0, I865_TOUD);
285c987c5e0Sriastradh 
286c987c5e0Sriastradh 	return i845_tseg_size(pc) + (64*1024 * toud);
287c987c5e0Sriastradh }
288c987c5e0Sriastradh 
289c987c5e0Sriastradh static bus_addr_t
gen3_stolen_base(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t stolen_size)290c987c5e0Sriastradh gen3_stolen_base(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t stolen_size)
291c987c5e0Sriastradh {
292c987c5e0Sriastradh 	uint32_t bsm = pci_conf_read(pc, tag, INTEL_BSM);
293c987c5e0Sriastradh 
294c987c5e0Sriastradh 	return bsm & INTEL_BSM_MASK;
295c987c5e0Sriastradh }
296c987c5e0Sriastradh 
297c987c5e0Sriastradh static bus_addr_t
gen11_stolen_base(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t stolen_size)298c987c5e0Sriastradh gen11_stolen_base(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t stolen_size)
299c987c5e0Sriastradh {
300c987c5e0Sriastradh 	uint32_t bsm;
301c987c5e0Sriastradh 
302c987c5e0Sriastradh 	bsm = pci_conf_read(pc, tag, INTEL_GEN11_BSM_DW0) & INTEL_BSM_MASK;
303c987c5e0Sriastradh 	bsm |= (uint64_t)pci_conf_read(pc, tag, INTEL_GEN11_BSM_DW1) << 32;
304c987c5e0Sriastradh 
305c987c5e0Sriastradh 	return bsm;
306c987c5e0Sriastradh }
307c987c5e0Sriastradh 
308c987c5e0Sriastradh struct intel_stolen_ops {
309c987c5e0Sriastradh 	bus_size_t	(*size)(pci_chipset_tag_t, pcitag_t);
310c987c5e0Sriastradh 	bus_addr_t	(*base)(pci_chipset_tag_t, pcitag_t, bus_size_t);
311c987c5e0Sriastradh };
312c987c5e0Sriastradh 
313c987c5e0Sriastradh static const struct intel_stolen_ops i830_stolen_ops = {
314c987c5e0Sriastradh 	.size = i830_stolen_size,
315c987c5e0Sriastradh 	.base = i830_stolen_base,
316c987c5e0Sriastradh };
317c987c5e0Sriastradh 
318c987c5e0Sriastradh static const struct intel_stolen_ops i845_stolen_ops = {
319c987c5e0Sriastradh 	.size = i830_stolen_size,
320c987c5e0Sriastradh 	.base = i845_stolen_base,
321c987c5e0Sriastradh };
322c987c5e0Sriastradh 
323c987c5e0Sriastradh static const struct intel_stolen_ops i85x_stolen_ops = {
324c987c5e0Sriastradh 	.size = gen3_stolen_size,
325c987c5e0Sriastradh 	.base = i85x_stolen_base,
326c987c5e0Sriastradh };
327c987c5e0Sriastradh 
328c987c5e0Sriastradh static const struct intel_stolen_ops i865_stolen_ops = {
329c987c5e0Sriastradh 	.size = gen3_stolen_size,
330c987c5e0Sriastradh 	.base = i865_stolen_base,
331c987c5e0Sriastradh };
332c987c5e0Sriastradh 
333c987c5e0Sriastradh static const struct intel_stolen_ops gen3_stolen_ops = {
334c987c5e0Sriastradh 	.size = gen3_stolen_size,
335c987c5e0Sriastradh 	.base = gen3_stolen_base,
336c987c5e0Sriastradh };
337c987c5e0Sriastradh 
338c987c5e0Sriastradh static const struct intel_stolen_ops gen6_stolen_ops = {
339c987c5e0Sriastradh 	.size = gen6_stolen_size,
340c987c5e0Sriastradh 	.base = gen3_stolen_base,
341c987c5e0Sriastradh };
342c987c5e0Sriastradh 
343c987c5e0Sriastradh static const struct intel_stolen_ops gen8_stolen_ops = {
344c987c5e0Sriastradh 	.size = gen8_stolen_size,
345c987c5e0Sriastradh 	.base = gen3_stolen_base,
346c987c5e0Sriastradh };
347c987c5e0Sriastradh 
348c987c5e0Sriastradh static const struct intel_stolen_ops gen9_stolen_ops = {
349c987c5e0Sriastradh 	.size = gen9_stolen_size,
350c987c5e0Sriastradh 	.base = gen3_stolen_base,
351c987c5e0Sriastradh };
352c987c5e0Sriastradh 
353c987c5e0Sriastradh static const struct intel_stolen_ops chv_stolen_ops = {
354c987c5e0Sriastradh 	.size = chv_stolen_size,
355c987c5e0Sriastradh 	.base = gen3_stolen_base,
356c987c5e0Sriastradh };
357c987c5e0Sriastradh 
358c987c5e0Sriastradh static const struct intel_stolen_ops gen11_stolen_ops = {
359c987c5e0Sriastradh 	.size = gen9_stolen_size,
360c987c5e0Sriastradh 	.base = gen11_stolen_base,
361c987c5e0Sriastradh };
362c987c5e0Sriastradh 
363c987c5e0Sriastradh static const struct pci_device_id intel_stolen_ids[] = {
364c987c5e0Sriastradh 	INTEL_I830_IDS(&i830_stolen_ops),
365c987c5e0Sriastradh 	INTEL_I845G_IDS(&i845_stolen_ops),
366c987c5e0Sriastradh 	INTEL_I85X_IDS(&i85x_stolen_ops),
367c987c5e0Sriastradh 	INTEL_I865G_IDS(&i865_stolen_ops),
368c987c5e0Sriastradh 	INTEL_I915G_IDS(&gen3_stolen_ops),
369c987c5e0Sriastradh 	INTEL_I915GM_IDS(&gen3_stolen_ops),
370c987c5e0Sriastradh 	INTEL_I945G_IDS(&gen3_stolen_ops),
371c987c5e0Sriastradh 	INTEL_I945GM_IDS(&gen3_stolen_ops),
372c987c5e0Sriastradh 	INTEL_VLV_IDS(&gen6_stolen_ops),
373c987c5e0Sriastradh 	INTEL_PINEVIEW_G_IDS(&gen3_stolen_ops),
374c987c5e0Sriastradh 	INTEL_PINEVIEW_M_IDS(&gen3_stolen_ops),
375c987c5e0Sriastradh 	INTEL_I965G_IDS(&gen3_stolen_ops),
376c987c5e0Sriastradh 	INTEL_G33_IDS(&gen3_stolen_ops),
377c987c5e0Sriastradh 	INTEL_I965GM_IDS(&gen3_stolen_ops),
378c987c5e0Sriastradh 	INTEL_GM45_IDS(&gen3_stolen_ops),
379c987c5e0Sriastradh 	INTEL_G45_IDS(&gen3_stolen_ops),
380c987c5e0Sriastradh 	INTEL_IRONLAKE_D_IDS(&gen3_stolen_ops),
381c987c5e0Sriastradh 	INTEL_IRONLAKE_M_IDS(&gen3_stolen_ops),
382c987c5e0Sriastradh 	INTEL_SNB_D_IDS(&gen6_stolen_ops),
383c987c5e0Sriastradh 	INTEL_SNB_M_IDS(&gen6_stolen_ops),
384c987c5e0Sriastradh 	INTEL_IVB_M_IDS(&gen6_stolen_ops),
385c987c5e0Sriastradh 	INTEL_IVB_D_IDS(&gen6_stolen_ops),
386c987c5e0Sriastradh 	INTEL_HSW_IDS(&gen6_stolen_ops),
387c987c5e0Sriastradh 	INTEL_BDW_IDS(&gen8_stolen_ops),
388c987c5e0Sriastradh 	INTEL_CHV_IDS(&chv_stolen_ops),
389c987c5e0Sriastradh 	INTEL_SKL_IDS(&gen9_stolen_ops),
390c987c5e0Sriastradh 	INTEL_BXT_IDS(&gen9_stolen_ops),
391c987c5e0Sriastradh 	INTEL_KBL_IDS(&gen9_stolen_ops),
392c987c5e0Sriastradh 	INTEL_CFL_IDS(&gen9_stolen_ops),
393c987c5e0Sriastradh 	INTEL_GLK_IDS(&gen9_stolen_ops),
394c987c5e0Sriastradh 	INTEL_CNL_IDS(&gen9_stolen_ops),
395c987c5e0Sriastradh 	INTEL_ICL_11_IDS(&gen11_stolen_ops),
396c987c5e0Sriastradh 	INTEL_EHL_IDS(&gen11_stolen_ops),
397c987c5e0Sriastradh 	INTEL_TGL_12_IDS(&gen11_stolen_ops),
398c987c5e0Sriastradh };
399c987c5e0Sriastradh 
4000c301abaSriastradh void
intel_gtt_get(uint64_t * va_size,bus_addr_t * aper_base,resource_size_t * aper_size)401*f41a5bb1Sriastradh intel_gtt_get(uint64_t *va_size, bus_addr_t *aper_base,
402*f41a5bb1Sriastradh     resource_size_t *aper_size)
4030c301abaSriastradh {
404c987c5e0Sriastradh 	struct agp_softc *sc;
405c987c5e0Sriastradh 	pci_chipset_tag_t pc;
406c987c5e0Sriastradh 	pcitag_t tag;
407c987c5e0Sriastradh 	struct agp_i810_softc *isc;
408c987c5e0Sriastradh 	const struct intel_stolen_ops *ops;
409c987c5e0Sriastradh 	bus_addr_t stolen_base;
410c987c5e0Sriastradh 	bus_size_t stolen_size;
411c987c5e0Sriastradh 	unsigned i;
4120c301abaSriastradh 
413c987c5e0Sriastradh 	if ((sc = agp_i810_sc) == NULL) {
4140c301abaSriastradh 		*va_size = 0;
4150c301abaSriastradh 		*aper_base = 0;
4160c301abaSriastradh 		*aper_size = 0;
4170c301abaSriastradh 		return;
4180c301abaSriastradh 	}
4190c301abaSriastradh 
420c987c5e0Sriastradh 	pc = sc->as_pc;
421c987c5e0Sriastradh 	tag = sc->as_tag;
422c987c5e0Sriastradh 
423c987c5e0Sriastradh 	isc = sc->as_chipc;
4240c301abaSriastradh 	*va_size = ((size_t)(isc->gtt_size/sizeof(uint32_t)) << PAGE_SHIFT);
4250c301abaSriastradh 	*aper_base = sc->as_apaddr;
4260c301abaSriastradh 	*aper_size = sc->as_apsize;
4270c301abaSriastradh 
428c987c5e0Sriastradh 	for (i = 0; i < __arraycount(intel_stolen_ids); i++) {
429c987c5e0Sriastradh 		if (intel_stolen_ids[i].device == PCI_PRODUCT(sc->as_id)) {
430c987c5e0Sriastradh 			ops = (const struct intel_stolen_ops *)
431c987c5e0Sriastradh 			    intel_stolen_ids[i].driver_data;
432c987c5e0Sriastradh 			stolen_size = (*ops->size)(pc, tag);
433c987c5e0Sriastradh 			stolen_base = (*ops->base)(pc, tag, stolen_size);
434c987c5e0Sriastradh 			intel_graphics_stolen_res.start = stolen_base;
435c987c5e0Sriastradh 			intel_graphics_stolen_res.end =
436c987c5e0Sriastradh 			    stolen_base + stolen_size - 1;
437c987c5e0Sriastradh 			break;
438c987c5e0Sriastradh 		}
439c987c5e0Sriastradh 	}
4400c301abaSriastradh }
4410c301abaSriastradh 
4420c301abaSriastradh int
intel_gmch_probe(struct pci_dev * bridge_pci __unused,struct pci_dev * gpu __unused,struct agp_bridge_data * bridge_agp __unused)4430c301abaSriastradh intel_gmch_probe(struct pci_dev *bridge_pci __unused,
4440c301abaSriastradh     struct pci_dev *gpu __unused, struct agp_bridge_data *bridge_agp __unused)
4450c301abaSriastradh {
4460c301abaSriastradh 	struct agp_softc *const sc = agp_i810_sc;
4470c301abaSriastradh 	int nsegs;
4480c301abaSriastradh 	int error;
4490c301abaSriastradh 
4500c301abaSriastradh 	if (sc == NULL)
4510c301abaSriastradh 		return 0;
4520c301abaSriastradh 
4530c301abaSriastradh 	error = bus_dmamem_alloc(sc->as_dmat, PAGE_SIZE, PAGE_SIZE, 0,
4540c301abaSriastradh 	    &intel_gtt.scratch_seg, 1, &nsegs, BUS_DMA_WAITOK);
4550c301abaSriastradh 	if (error)
4560c301abaSriastradh 		goto fail0;
4570c301abaSriastradh 	KASSERT(nsegs == 1);
4580c301abaSriastradh 
4590c301abaSriastradh 	error = bus_dmamap_create(sc->as_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0,
4600c301abaSriastradh 	    BUS_DMA_WAITOK, &intel_gtt.scratch_map);
4610c301abaSriastradh 	if (error)
4620c301abaSriastradh 		goto fail1;
4630c301abaSriastradh 
4640c301abaSriastradh 	error = bus_dmamap_load_raw(sc->as_dmat, intel_gtt.scratch_map,
4650c301abaSriastradh 	    &intel_gtt.scratch_seg, 1, PAGE_SIZE, BUS_DMA_WAITOK);
4660c301abaSriastradh 	if (error)
4670c301abaSriastradh 		goto fail2;
4680c301abaSriastradh 
4690c301abaSriastradh 	/* Success!  */
4700c301abaSriastradh 	return 1;
4710c301abaSriastradh 
4720c301abaSriastradh fail3: __unused
4730c301abaSriastradh 	bus_dmamap_unload(sc->as_dmat, intel_gtt.scratch_map);
4740c301abaSriastradh fail2:	bus_dmamap_destroy(sc->as_dmat, intel_gtt.scratch_map);
4750c301abaSriastradh fail1:	bus_dmamem_free(sc->as_dmat, &intel_gtt.scratch_seg, 1);
4760c301abaSriastradh fail0:	KASSERT(error);
4770c301abaSriastradh 	return 0;
4780c301abaSriastradh }
4790c301abaSriastradh 
4800c301abaSriastradh void
intel_gmch_remove(void)4810c301abaSriastradh intel_gmch_remove(void)
4820c301abaSriastradh {
4830c301abaSriastradh 	struct agp_softc *const sc = agp_i810_sc;
4840c301abaSriastradh 
4850c301abaSriastradh 	bus_dmamap_unload(sc->as_dmat, intel_gtt.scratch_map);
4860c301abaSriastradh 	bus_dmamap_destroy(sc->as_dmat, intel_gtt.scratch_map);
4870c301abaSriastradh 	bus_dmamem_free(sc->as_dmat, &intel_gtt.scratch_seg, 1);
4880c301abaSriastradh }
4890c301abaSriastradh 
4900c301abaSriastradh bool
intel_enable_gtt(void)4910c301abaSriastradh intel_enable_gtt(void)
4920c301abaSriastradh {
4930c301abaSriastradh 	struct agp_softc *sc = agp_i810_sc;
4940c301abaSriastradh 	struct agp_i810_softc *isc;
4950c301abaSriastradh 
4960c301abaSriastradh 	if (sc == NULL)
4970c301abaSriastradh 		return false;
4980c301abaSriastradh 	isc = sc->as_chipc;
4990c301abaSriastradh 	agp_i810_reset(isc);
5000c301abaSriastradh 	return true;
5010c301abaSriastradh }
5020c301abaSriastradh 
5030c301abaSriastradh void
intel_gtt_chipset_flush(void)5040c301abaSriastradh intel_gtt_chipset_flush(void)
5050c301abaSriastradh {
5060c301abaSriastradh 
5070c301abaSriastradh 	KASSERT(agp_i810_sc != NULL);
5080c301abaSriastradh 	agp_i810_chipset_flush(agp_i810_sc->as_chipc);
5090c301abaSriastradh }
5100c301abaSriastradh 
5110c301abaSriastradh static int
intel_gtt_flags(unsigned flags)5120c301abaSriastradh intel_gtt_flags(unsigned flags)
5130c301abaSriastradh {
5140c301abaSriastradh 	int gtt_flags = AGP_I810_GTT_VALID;
5150c301abaSriastradh 
5160c301abaSriastradh 	switch (flags) {
5170c301abaSriastradh 	case AGP_USER_MEMORY:
5180c301abaSriastradh 		break;
5190c301abaSriastradh 	case AGP_USER_CACHED_MEMORY:
5200c301abaSriastradh 		gtt_flags |= AGP_I810_GTT_CACHED;
5210c301abaSriastradh 		break;
5220c301abaSriastradh 	default:
5230c301abaSriastradh 		panic("invalid intel gtt flags: %x", flags);
5240c301abaSriastradh 	}
5250c301abaSriastradh 
5260c301abaSriastradh 	return gtt_flags;
5270c301abaSriastradh }
5280c301abaSriastradh 
5290c301abaSriastradh void
intel_gtt_insert_page(bus_addr_t addr,unsigned va_page,unsigned flags)5300c301abaSriastradh intel_gtt_insert_page(bus_addr_t addr, unsigned va_page, unsigned flags)
5310c301abaSriastradh {
5320c301abaSriastradh 	struct agp_i810_softc *const isc = agp_i810_sc->as_chipc;
5330c301abaSriastradh 	off_t va = (off_t)va_page << PAGE_SHIFT;
5340c301abaSriastradh 	int gtt_flags = intel_gtt_flags(flags);
5350c301abaSriastradh 	int error;
5360c301abaSriastradh 
5370c301abaSriastradh 	error = agp_i810_write_gtt_entry(isc, va, addr, gtt_flags);
5380c301abaSriastradh 	if (error)
5390c301abaSriastradh 		device_printf(agp_i810_sc->as_dev,
5400c301abaSriastradh 		    "write gtt entry"
5410c301abaSriastradh 		    " %"PRIxMAX" -> %"PRIxMAX" (flags=%x) failed: %d\n",
5420c301abaSriastradh 		    (uintmax_t)va, (uintmax_t)addr, flags,
5430c301abaSriastradh 		    error);
5440c301abaSriastradh 	agp_i810_post_gtt_entry(isc, va);
5450c301abaSriastradh 	intel_gtt_chipset_flush();
5460c301abaSriastradh }
5470c301abaSriastradh 
5480c301abaSriastradh void
intel_gtt_insert_sg_entries(struct sg_table * sg,unsigned va_page,unsigned flags)5490c301abaSriastradh intel_gtt_insert_sg_entries(struct sg_table *sg, unsigned va_page,
5500c301abaSriastradh     unsigned flags)
5510c301abaSriastradh {
5520c301abaSriastradh 	bus_dmamap_t dmamap = sg->sgl[0].sg_dmamap;
5530c301abaSriastradh 	struct agp_i810_softc *const isc = agp_i810_sc->as_chipc;
5540c301abaSriastradh 	off_t va = (off_t)va_page << PAGE_SHIFT;
5550c301abaSriastradh 	unsigned seg;
5560c301abaSriastradh 	int gtt_flags = intel_gtt_flags(flags);
5570c301abaSriastradh 	int error;
5580c301abaSriastradh 
5590c301abaSriastradh 	KASSERT(0 <= va);
5600c301abaSriastradh 	KASSERT((va >> PAGE_SHIFT) == va_page);
5610c301abaSriastradh 	KASSERT(0 < dmamap->dm_nsegs);
5620c301abaSriastradh 
5630c301abaSriastradh 	for (seg = 0; seg < dmamap->dm_nsegs; seg++) {
5640c301abaSriastradh 		const bus_addr_t addr = dmamap->dm_segs[seg].ds_addr;
5650c301abaSriastradh 		bus_size_t len;
5660c301abaSriastradh 
5670c301abaSriastradh 		for (len = dmamap->dm_segs[seg].ds_len;
5680c301abaSriastradh 		     len >= PAGE_SIZE;
5690c301abaSriastradh 		     len -= PAGE_SIZE, va += PAGE_SIZE) {
5700c301abaSriastradh 			error = agp_i810_write_gtt_entry(isc, va, addr,
5710c301abaSriastradh 			    gtt_flags);
5720c301abaSriastradh 			if (error)
5730c301abaSriastradh 				device_printf(agp_i810_sc->as_dev,
5740c301abaSriastradh 				    "write gtt entry"
5750c301abaSriastradh 				    " %"PRIxMAX" -> %"PRIxMAX" (flags=%x)"
5760c301abaSriastradh 				    " failed: %d\n",
5770c301abaSriastradh 				    (uintmax_t)va, (uintmax_t)addr, flags,
5780c301abaSriastradh 				    error);
5790c301abaSriastradh 		}
5800c301abaSriastradh 		KASSERTMSG(len == 0,
5810c301abaSriastradh 		    "segment length not divisible by PAGE_SIZE: %jx",
5820c301abaSriastradh 		    (uintmax_t)dmamap->dm_segs[seg].ds_len);
5830c301abaSriastradh 	}
5840c301abaSriastradh 	agp_i810_post_gtt_entry(isc, (va - PAGE_SIZE));
5850c301abaSriastradh 	intel_gtt_chipset_flush();
5860c301abaSriastradh }
5870c301abaSriastradh 
5880c301abaSriastradh void
intel_gtt_clear_range(unsigned va_page,unsigned npages)5890c301abaSriastradh intel_gtt_clear_range(unsigned va_page, unsigned npages)
5900c301abaSriastradh {
5910c301abaSriastradh 	struct agp_i810_softc *const isc = agp_i810_sc->as_chipc;
5920c301abaSriastradh 	const bus_addr_t addr = intel_gtt.scratch_map->dm_segs[0].ds_addr;
5930c301abaSriastradh 	const int gtt_flags = AGP_I810_GTT_VALID;
5940c301abaSriastradh 	off_t va = (va_page << PAGE_SHIFT);
5950c301abaSriastradh 
5960c301abaSriastradh 	KASSERT(0 <= va);
5970c301abaSriastradh 	KASSERT((va >> PAGE_SHIFT) == va_page);
5980c301abaSriastradh 	KASSERT(0 < npages);
5990c301abaSriastradh 
6000c301abaSriastradh 	while (npages--) {
6010c301abaSriastradh 		agp_i810_write_gtt_entry(isc, va, addr, gtt_flags);
6020c301abaSriastradh 		va += PAGE_SIZE;
6030c301abaSriastradh 	}
6040c301abaSriastradh 	agp_i810_post_gtt_entry(isc, va - PAGE_SIZE);
6050c301abaSriastradh }
606