3 * \brief Intel I830 driver
6 * \author Frank Mehnert <fm3@os.inf.tu-dresden.de> */
8 * (c) 2003-2009 Technische Universität Dresden
9 * This file is part of TUD:OS and distributed under the terms of the
10 * GNU General Public License 2.
11 * Please see the COPYING-GPL-2 file for details.
14 /* Most stuff was taken from intelfb Linux driver of David Dawes. */
17 #include <l4/sys/types.h>
18 #include <l4/util/port_io.h>
19 #include <l4/util/rdtsc.h>
20 #include <l4/util/l4_macros.h>
21 #include <l4/sys/err.h>
28 #define PCI_DEVICE_ID_INTEL_830M 0x3577
29 #define PCI_DEVICE_ID_INTEL_845G 0x2562
30 #define PCI_DEVICE_ID_INTEL_85XGM 0x3582
31 #define PCI_DEVICE_ID_INTEL_865G 0x2572
32 #define PCI_DEVICE_ID_INTEL_915G 0x2582
33 #define PCI_DEVICE_ID_INTEL_915GM 0x2592
35 #define INTEL_85X_CAPID 0x44
36 #define INTEL_85X_VARIANT_MASK 0x7
37 #define INTEL_85X_VARIANT_SHIFT 5
38 #define INTEL_VAR_855GME 0x0
39 #define INTEL_VAR_855GM 0x4
40 #define INTEL_VAR_852GME 0x2
41 #define INTEL_VAR_852GM 0x5
42 #define INTEL_GMCH_CTRL 0x52
44 #define INTEL_REG_SIZE 0x80000
46 static l4_addr_t mmio_base;
47 static l4_addr_t fb_base;
48 static l4_addr_t fb_offset;
49 static l4_uint32_t pitch;
50 static int blitter_may_be_busy;
52 static l4_addr_t ring_base, ring_base_phys;
53 static l4_uint32_t ring_space;
54 static l4_uint32_t ring_head, ring_tail;
55 const l4_uint32_t ring_size = 64*1024;
56 const l4_uint32_t ring_tail_mask = 64*1024 - 1;
58 static const struct pci_device_id intel_pci_tbl[] __init =
60 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_830M, 0, 0, 0 },
61 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_845G, 0, 0, 0 },
62 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_85XGM, 0, 0, 0 },
63 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, 0, 0, 0 },
64 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, 0, 0, 0 },
65 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, 0, 0, 0 },
70 #define MI_NOOP (0x00 << 23)
71 #define MI_NOOP_WRITE_ID (1 << 22)
72 #define MI_NOOP_ID_MASK ((1 << 22) - 1)
74 #define MI_FLUSH (0x04 << 23)
75 #define MI_WRITE_DIRTY_STATE (1 << 4)
76 #define MI_END_SCENE (1 << 3)
77 #define MI_INHIBIT_RENDER_CACHE_FLUSH (1 << 2)
78 #define MI_INVALIDATE_MAP_CACHE (1 << 0)
80 #define MI_STORE_DWORD_IMM ((0x20 << 23) | 1)
83 #define COLOR_BLT_CMD ((2 << 29) | (0x40 << 22) | 3)
84 #define XY_COLOR_BLT_CMD ((2 << 29) | (0x50 << 22) | 4)
85 #define XY_SETUP_CLIP_BLT_CMD ((2 << 29) | (0x03 << 22) | 1)
86 #define XY_SRC_COPY_BLT_CMD ((2 << 29) | (0x53 << 22) | 6)
87 #define SRC_COPY_BLT_CMD ((2 << 29) | (0x43 << 22) | 4)
88 #define XY_MONO_PAT_BLT_CMD ((2 << 29) | (0x52 << 22) | 7)
89 #define XY_MONO_SRC_BLT_CMD ((2 << 29) | (0x54 << 22) | 6)
90 #define XY_MONO_SRC_IMM_BLT_CMD ((2 << 29) | (0x71 << 22) | 5)
92 #define WRITE_ALPHA (1 << 21)
93 #define WRITE_RGB (1 << 20)
94 #define VERT_SEED (3 << 8)
95 #define HORIZ_SEED (3 << 12)
97 #define COLOR_DEPTH_8 (0 << 24)
98 #define COLOR_DEPTH_16 (1 << 24)
99 #define COLOR_DEPTH_32 (3 << 24)
101 #define SRC_ROP_GXCOPY 0xcc
102 #define SRC_ROP_GXXOR 0x66
104 #define PAT_ROP_GXCOPY 0xf0
105 #define PAT_ROP_GXXOR 0x5a
107 #define PITCH_SHIFT 0
109 #define WIDTH_SHIFT 0
110 #define HEIGHT_SHIFT 16
112 /* Primary ring buffer */
113 #define PRI_RING_TAIL 0x2030
114 #define RING_TAIL_MASK 0x001ffff8
115 #define RING_INUSE 0x1
116 #define PRI_RING_HEAD 0x2034
117 #define RING_HEAD_WRAP_MASK 0x7ff
118 #define RING_HEAD_WRAP_SHIFT 21
119 #define RING_HEAD_MASK 0x001ffffc
120 #define PRI_RING_START 0x2038
121 #define RING_START_MASK 0xfffff000
122 #define PRI_RING_LENGTH 0x203c
123 #define RING_LENGTH_MASK 0x001ff000
124 #define RING_REPORT_MASK (0x3 << 1)
125 #define RING_NO_REPORT (0x0 << 1)
126 #define RING_REPORT_64K (0x1 << 1)
127 #define RING_REPORT_4K (0x2 << 1)
128 #define RING_REPORT_128K (0x3 << 1)
129 #define RING_ENABLE 0x1
131 #define RING_MIN_FREE 64
132 #define GTT_PAGE_SIZE 4096
134 #define DSPABASE 0x70184
136 /* Ring buffer macros */
137 #define OUT_RING(n) do { \
138 *(volatile l4_uint32_t*)(ring_base + ring_tail) = n; \
140 ring_tail &= ring_tail_mask; \
143 #define START_RING(n) do { \
144 l4_uint32_t needed = (n) * 4; \
145 if (ring_tail + needed > ring_tail_mask - RING_MIN_FREE) { \
146 needed += ring_tail_mask + 1 - ring_tail; \
148 if (ring_space < needed) \
150 ring_space -= needed; \
151 while (needed > (n) * 4) { \
157 #define ADVANCE_RING() do { \
158 outreg32(PRI_RING_TAIL, ring_tail); \
161 static inline l4_uint32_t
162 inreg32(l4_uint32_t addr)
164 return *(volatile l4_uint32_t*)(mmio_base + addr);
168 outreg32(l4_uint32_t addr, l4_uint32_t val)
170 *(volatile l4_uint32_t*)(mmio_base + addr) = val;
174 wait_ring(unsigned n)
176 #define ms_300 300000000ULL
177 l4_uint64_t end = l4_rdtsc() + l4_ns_to_tsc(ms_300);
178 l4_uint32_t last_head = inreg32(PRI_RING_HEAD) & RING_HEAD_MASK;
180 while (ring_space < n)
182 ring_head = inreg32(PRI_RING_HEAD) & RING_HEAD_MASK;
183 if (ring_tail + RING_MIN_FREE < ring_head)
184 ring_space = ring_head - ring_tail - RING_MIN_FREE;
186 ring_space = ring_size + ring_head - ring_tail - RING_MIN_FREE;
187 if (ring_head != last_head)
189 end = l4_rdtsc() + l4_ns_to_tsc(ms_300);
190 last_head = ring_head;
192 if (end < l4_rdtsc())
194 printf("space: %d wanted %d -- lookup\n", ring_space, n);
197 l4_busy_wait_ns(1000);
204 ring_head = inreg32(PRI_RING_HEAD) & RING_HEAD_MASK;
205 ring_tail = inreg32(PRI_RING_TAIL) & RING_TAIL_MASK;
206 if (ring_tail + RING_MIN_FREE < ring_head)
207 ring_space = ring_head - ring_tail - RING_MIN_FREE;
209 ring_space = ring_size + ring_head - ring_tail - RING_MIN_FREE;
215 if (!blitter_may_be_busy)
219 OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE);
222 wait_ring(ring_size - RING_MIN_FREE);
223 ring_space = ring_size - RING_MIN_FREE;
224 blitter_may_be_busy = 0;
228 intel_pan(int *x, int *y)
230 l4_uint32_t offset, xoffset, yoffset;
235 offset = yoffset * pitch + (xoffset * hw_bits) / 8;
236 offset += fb_offset << 12;
238 outreg32(DSPABASE, offset);
242 intel_bmove(struct l4con_vc *vc,
243 int sx, int sy, int width, int height, int dx, int dy)
246 l4_uint32_t br00, br09, br11, br12, br13, br22, br23, br26;
248 br00 = XY_SRC_COPY_BLT_CMD;
250 br11 = (pitch << PITCH_SHIFT);
252 br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT);
253 br22 = (dx << WIDTH_SHIFT) | (dy << HEIGHT_SHIFT);
254 br23 = ((dx + width) << WIDTH_SHIFT) | ((dy + height) << HEIGHT_SHIFT);
255 br26 = (sx << WIDTH_SHIFT) | (sy << HEIGHT_SHIFT);
259 case 8: br13 |= COLOR_DEPTH_8; break;
260 case 16: br13 |= COLOR_DEPTH_16; break;
261 case 32: br13 |= COLOR_DEPTH_32; br00 |= WRITE_ALPHA | WRITE_RGB; break;
275 blitter_may_be_busy = 1;
279 intel_fill(struct l4con_vc *vc,
280 int sx, int sy, int width, int height, unsigned color)
283 l4_uint32_t br00, br09, br13, br14, br16;
285 br00 = COLOR_BLT_CMD;
286 br09 = fb_offset + (sy * pitch + sx * (hw_bits / 8));
287 br13 = (PAT_ROP_GXCOPY << ROP_SHIFT) | pitch;
288 br14 = (height << HEIGHT_SHIFT) | ((width * (hw_bits / 8)) << WIDTH_SHIFT);
293 case 8: br13 |= COLOR_DEPTH_8; break;
294 case 16: br13 |= COLOR_DEPTH_16; break;
295 case 32: br13 |= COLOR_DEPTH_32; br00 |= WRITE_ALPHA | WRITE_RGB; break;
307 blitter_may_be_busy = 1;
313 outreg32(PRI_RING_LENGTH, 0);
314 outreg32(PRI_RING_TAIL, 0);
315 outreg32(PRI_RING_HEAD, 0);
317 outreg32(PRI_RING_START, ring_base_phys & RING_START_MASK);
318 outreg32(PRI_RING_LENGTH, ((ring_size - GTT_PAGE_SIZE) & RING_LENGTH_MASK)
319 | RING_NO_REPORT | RING_ENABLE);
324 intel_probe(unsigned int bus, unsigned int devfn,
325 const struct pci_device_id *dev, con_accel_t *accel)
331 int aperture = 0, mmio = 1;
335 case PCI_DEVICE_ID_INTEL_830M: name = "830M"; break;
336 case PCI_DEVICE_ID_INTEL_845G: name = "845G"; break;
337 case PCI_DEVICE_ID_INTEL_865G: name = "865G"; break;
338 case PCI_DEVICE_ID_INTEL_85XGM:
339 case PCI_DEVICE_ID_INTEL_915G: name = "915G"; break;
340 case PCI_DEVICE_ID_INTEL_915GM: name = "915GM"; break;
342 PCIBIOS_READ_CONFIG_DWORD(bus, devfn, INTEL_85X_CAPID, &tmp);
343 switch ((tmp >> INTEL_85X_VARIANT_SHIFT)& INTEL_85X_VARIANT_MASK)
345 case INTEL_VAR_855GME: name = "855GME"; break;
346 case INTEL_VAR_855GM: name = "855GM"; break;
347 case INTEL_VAR_852GME: name = "852GME"; break;
348 case INTEL_VAR_852GM: name = "852GM"; break;
349 default: name = "852GM/855GM"; break;
354 if (dev->device == PCI_DEVICE_ID_INTEL_915G ||
355 dev->device == PCI_DEVICE_ID_INTEL_915GM)
361 pci_resource(bus, devfn, aperture, &addr, &size);
365 if (size < hw_vid_mem_size)
367 printf("Aperture size = %zdKB (< %ldKB)\n",
368 size/1024, hw_vid_mem_size/1024);
372 if (size > hw_vid_mem_size)
373 size = hw_vid_mem_size;
375 if (map_io_mem(addr, size, 1, "video", &fb_base) < 0)
378 hw_map_vid_mem_addr = fb_base;
380 ring_base_phys = addr + size - (128<<10);
381 ring_base = fb_base + size - (128<<10);
383 pci_resource(bus, devfn, mmio, &addr, &size);
387 if (map_io_mem(addr, INTEL_REG_SIZE, 0, "ctrl", &mmio_base) < 0)
391 printf("Found Intel (R) %s adapter at "l4_addr_fmt"\n", name, addr);
396 case 8: pitch = hw_xres; break;
397 case 16: pitch = hw_xres * 2; break;
398 case 32: pitch = hw_xres * 4; break;
405 blitter_may_be_busy = 1;
408 accel->copy = intel_bmove;
409 accel->fill = intel_fill;
410 accel->sync = intel_sync;
411 accel->pan = intel_pan;
412 accel->caps = ACCEL_FAST_COPY | ACCEL_FAST_FILL;
420 pci_register(intel_pci_tbl, intel_probe);