]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4con/server/src/con_hw/intel.c
Inital import
[l4.git] / l4 / pkg / l4con / server / src / con_hw / intel.c
1 /*!
2  * \file        intel.c
3  * \brief       Intel I830 driver
4  *
5  * \date        10/2004
6  * \author      Frank Mehnert <fm3@os.inf.tu-dresden.de> */
7 /*
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.
12  */
13
14 /* Most stuff was taken from intelfb Linux driver of David Dawes. */
15
16 #include <stdio.h>
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>
22
23 #include "init.h"
24 #include "pci.h"
25 #include "iomem.h"
26 #include "intel.h"
27
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
34
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
43
44 #define INTEL_REG_SIZE                  0x80000
45
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;
51
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;
57
58 static const struct pci_device_id intel_pci_tbl[] __init =
59 {
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 },
66     { 0, 0, 0, 0, 0 }
67 };
68
69 /* Memory Commands */
70 #define MI_NOOP                 (0x00 << 23)
71 #define MI_NOOP_WRITE_ID                (1 << 22)
72 #define MI_NOOP_ID_MASK                 ((1 << 22) - 1)
73
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)
79
80 #define MI_STORE_DWORD_IMM      ((0x20 << 23) | 1)
81
82 /* 2D Commands */
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)
91
92 #define WRITE_ALPHA                     (1 << 21)
93 #define WRITE_RGB                       (1 << 20)
94 #define VERT_SEED                       (3 << 8)
95 #define HORIZ_SEED                      (3 << 12)
96
97 #define COLOR_DEPTH_8                   (0 << 24)
98 #define COLOR_DEPTH_16                  (1 << 24)
99 #define COLOR_DEPTH_32                  (3 << 24)
100
101 #define SRC_ROP_GXCOPY                  0xcc
102 #define SRC_ROP_GXXOR                   0x66
103
104 #define PAT_ROP_GXCOPY                  0xf0
105 #define PAT_ROP_GXXOR                   0x5a
106
107 #define PITCH_SHIFT                     0
108 #define ROP_SHIFT                       16
109 #define WIDTH_SHIFT                     0
110 #define HEIGHT_SHIFT                    16
111
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
130
131 #define RING_MIN_FREE           64
132 #define GTT_PAGE_SIZE           4096
133
134 #define DSPABASE                0x70184
135
136 /* Ring buffer macros */
137 #define OUT_RING(n)     do {                                            \
138         *(volatile l4_uint32_t*)(ring_base + ring_tail) = n;            \
139         ring_tail += 4;                                                 \
140         ring_tail &= ring_tail_mask;                                    \
141 } while (0)
142
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;               \
147         }                                                               \
148         if (ring_space < needed)                                        \
149                 wait_ring(needed);                                      \
150         ring_space -= needed;                                           \
151         while (needed > (n) * 4) {                                      \
152                 OUT_RING(MI_NOOP);                                      \
153                 needed -= 4;                                            \
154         }                                                               \
155 } while (0)
156
157 #define ADVANCE_RING()  do {                                            \
158         outreg32(PRI_RING_TAIL, ring_tail);                             \
159 } while (0)
160
161 static inline l4_uint32_t
162 inreg32(l4_uint32_t addr)
163 {
164   return *(volatile l4_uint32_t*)(mmio_base + addr);
165 }
166
167 static inline void
168 outreg32(l4_uint32_t addr, l4_uint32_t val)
169 {
170   *(volatile l4_uint32_t*)(mmio_base + addr) = val;
171 }
172
173 static void
174 wait_ring(unsigned n)
175 {
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;
179
180   while (ring_space < n)
181     {
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;
185       else
186         ring_space = ring_size + ring_head - ring_tail - RING_MIN_FREE;
187       if (ring_head != last_head)
188         {
189           end = l4_rdtsc() + l4_ns_to_tsc(ms_300);
190           last_head = ring_head;
191         }
192       if (end < l4_rdtsc())
193         {
194           printf("space: %d wanted %d -- lookup\n", ring_space, n);
195           break;
196         }
197       l4_busy_wait_ns(1000);
198     }
199 }
200
201 static void
202 refresh_ring(void)
203 {
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;
208   else
209     ring_space = ring_size + ring_head - ring_tail - RING_MIN_FREE;
210 }
211
212 static void
213 intel_sync(void)
214 {
215   if (!blitter_may_be_busy)
216     return;
217
218   START_RING(2);
219   OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE);
220   OUT_RING(MI_NOOP);
221   ADVANCE_RING();
222   wait_ring(ring_size - RING_MIN_FREE);
223   ring_space = ring_size - RING_MIN_FREE;
224   blitter_may_be_busy = 0;
225 }
226
227 static void
228 intel_pan(int *x, int *y)
229 {
230   l4_uint32_t offset, xoffset, yoffset;
231
232   *x &= 7;
233   xoffset = *x;
234   yoffset = *y;
235   offset  = yoffset * pitch + (xoffset * hw_bits) / 8;
236   offset += fb_offset << 12;
237
238   outreg32(DSPABASE, offset);
239 }
240
241 static void 
242 intel_bmove(struct l4con_vc *vc,
243             int sx, int sy, int width, int height, int dx, int dy)
244 {
245   (void)vc;
246   l4_uint32_t br00, br09, br11, br12, br13, br22, br23, br26;
247
248   br00 = XY_SRC_COPY_BLT_CMD;
249   br09 = fb_offset;
250   br11 = (pitch << PITCH_SHIFT);
251   br12 = fb_offset;
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);
256
257   switch (hw_bits)
258     {
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;
262     }
263
264   START_RING(8);
265   OUT_RING(br00);
266   OUT_RING(br13);
267   OUT_RING(br22);
268   OUT_RING(br23);
269   OUT_RING(br09);
270   OUT_RING(br26);
271   OUT_RING(br11);
272   OUT_RING(br12);
273   ADVANCE_RING();
274
275   blitter_may_be_busy = 1;
276 }
277
278 static void 
279 intel_fill(struct l4con_vc *vc,
280            int sx, int sy, int width, int height, unsigned color)
281 {
282   (void)vc;
283   l4_uint32_t br00, br09, br13, br14, br16;
284
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);
289   br16 = color;
290
291   switch (hw_bits)
292     {
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;
296     }
297
298   START_RING(6);
299   OUT_RING(br00);
300   OUT_RING(br13);
301   OUT_RING(br14);
302   OUT_RING(br09);
303   OUT_RING(br16);
304   OUT_RING(MI_NOOP);
305   ADVANCE_RING();
306
307   blitter_may_be_busy = 1;
308 }
309
310 static void
311 intel_2d_start(void)
312 {
313   outreg32(PRI_RING_LENGTH, 0);
314   outreg32(PRI_RING_TAIL, 0);
315   outreg32(PRI_RING_HEAD, 0);
316
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);
320   refresh_ring();
321 }
322
323 static int
324 intel_probe(unsigned int bus, unsigned int devfn,
325             const struct pci_device_id *dev, con_accel_t *accel)
326 {
327   unsigned tmp;
328   l4_addr_t addr;
329   l4_size_t size;
330   const char *name;
331   int aperture = 0, mmio = 1;
332
333   switch (dev->device)
334     {
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;
341     default:
342       PCIBIOS_READ_CONFIG_DWORD(bus, devfn, INTEL_85X_CAPID, &tmp);
343       switch ((tmp >> INTEL_85X_VARIANT_SHIFT)& INTEL_85X_VARIANT_MASK)
344         {
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;
350         }
351       break;
352     }
353
354   if (dev->device == PCI_DEVICE_ID_INTEL_915G ||
355       dev->device == PCI_DEVICE_ID_INTEL_915GM)
356     {
357       aperture = 2;
358       mmio     = 0;
359     }
360
361   pci_resource(bus, devfn, aperture, &addr, &size);
362   if (!addr)
363     return -L4_ENODEV;
364
365   if (size < hw_vid_mem_size)
366     {
367       printf("Aperture size = %zdKB (< %ldKB)\n", 
368             size/1024, hw_vid_mem_size/1024);
369       return -L4_ENODEV;
370     }
371
372   if (size > hw_vid_mem_size)
373     size = hw_vid_mem_size;
374
375   if (map_io_mem(addr, size, 1, "video", &fb_base) < 0)
376     return -L4_ENODEV;
377
378   hw_map_vid_mem_addr = fb_base;
379
380   ring_base_phys = addr    + size - (128<<10);
381   ring_base      = fb_base + size - (128<<10);
382
383   pci_resource(bus, devfn, mmio, &addr, &size);
384   if (!addr)
385     return -L4_ENODEV;
386
387   if (map_io_mem(addr, INTEL_REG_SIZE, 0, "ctrl", &mmio_base) < 0)
388     return -L4_ENODEV;
389
390
391   printf("Found Intel (R) %s adapter at "l4_addr_fmt"\n", name, addr);
392
393 #if 0
394   switch (hw_bits)
395     {
396     case 8:  pitch = hw_xres;     break;
397     case 16: pitch = hw_xres * 2; break;
398     case 32: pitch = hw_xres * 4; break;
399     }
400 #endif
401   pitch = hw_bpl;
402
403   intel_2d_start();
404
405   blitter_may_be_busy = 1;
406   intel_sync();
407
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;
413
414   return 0;
415 }
416
417 void
418 intel_register(void)
419 {
420   pci_register(intel_pci_tbl, intel_probe);
421 }