1 /* $Id: sun-fb.c,v 1.6 2010/06/05 19:19:01 fredette Exp $ */
2
3 /* machine/sun/sun-fb.c - Sun framebuffer emulation support: */
4
5 /*
6 * Copyright (c) 2004, 2006 Matt Fredette
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Matt Fredette.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include <tme/common.h>
37 _TME_RCSID("$Id: sun-fb.c,v 1.6 2010/06/05 19:19:01 fredette Exp $");
38
39 /* includes: */
40 #include "sun-fb.h"
41
42 /* macros: */
43
44 /* P4 register framebuffer sizes: */
45 #define TME_SUNFB_P4_SIZE_MASK (0x0f000000)
46 #define TME_SUNFB_P4_SIZE_1600_1280 (0x00000000)
47 #define TME_SUNFB_P4_SIZE_1152_900 (0x01000000)
48 #define TME_SUNFB_P4_SIZE_1024_1024 (0x02000000)
49 #define TME_SUNFB_P4_SIZE_1280_1024 (0x03000000)
50 #define TME_SUNFB_P4_SIZE_1440_1440 (0x04000000)
51 #define TME_SUNFB_P4_SIZE_640_480 (0x05000000)
52
53 /* P4 register bits: */
54 /* 0x00000080 is the diagnostic bit (?) */
55 /* 0x00000040 is the readback bit (?) */
56 #define TME_SUNFB_P4_REG_VIDEO_ENABLE (0x00000020)
57 #define TME_SUNFB_P4_REG_SYNC_RAMDAC (0x00000010)
58 #define TME_SUNFB_P4_REG_IN_VTRACE (0x00000008)
59 #define TME_SUNFB_P4_REG_INT_ACTIVE (0x00000004)
60 #define TME_SUNFB_P4_REG_INT_RESET (0x00000004)
61 #define TME_SUNFB_P4_REG_ENABLE_INT (0x00000002)
62 #define TME_SUNFB_P4_REG_IN_VTRACE_1H (0x00000001)
63 #define TME_SUNFB_P4_REG_RESET (0x00000001)
64
65 /* P4 register read-only bits: */
66 #define TME_SUNFB_P4_RO_MASK (TME_SUNFB_P4_ID_MASK \
67 | TME_SUNFB_P4_SIZE_MASK \
68 | TME_SUNFB_P4_REG_IN_VTRACE \
69 | TME_SUNFB_P4_REG_INT_ACTIVE \
70 | TME_SUNFB_P4_REG_IN_VTRACE_1H)
71
72 /* S4 register offsets: */
73 #define TME_SUNFB_S4_REG_BT458_ADDRESS (0)
74 #define TME_SUNFB_S4_REG_BT458_CMAP (4)
75 #define TME_SUNFB_S4_REG_BT458_CONTROL (8)
76 #define TME_SUNFB_S4_REG_BT458_OMAP (12)
77 #define TME_SUNFB_S4_SIZ_BT458 (16)
78 #define TME_SUNFB_S4_SIZ_REGS (32)
79 #define TME_SUNFB_S4_REG(x) \
80 (TME_SUNFB_S4_SIZ_BT458 \
81 + (&((struct tme_sunfb *) 0)->tme_sunfb_s4_regs.x \
82 - &((struct tme_sunfb *) 0)->tme_sunfb_s4_regs.tme_sunfb_s4_regs_first))
83
84 /* S4 control register bits: */
85 #define TME_SUNFB_S4_CONTROL_INT_ENABLE (0x80)
86 #define TME_SUNFB_S4_CONTROL_VIDEO_ENABLE (0x40)
87
88 /* S4 status register bits: */
89 #define TME_SUNFB_S4_STATUS_INT_PENDING (0x80)
90 #define TME_SUNFB_S4_STATUS_SIZE_MASK (0x70)
91 #define TME_SUNFB_S4_STATUS_SIZE_1024_768 (0x10)
92 #define TME_SUNFB_S4_STATUS_SIZE_1152_900 (0x30)
93 #define TME_SUNFB_S4_STATUS_SIZE_1280_1024 (0x40)
94 #define TME_SUNFB_S4_STATUS_SIZE_1600_1280 (0x50)
95 #define TME_SUNFB_S4_STATUS_ID_MASK (0x0f)
96 #define TME_SUNFB_S4_STATUS_ID_COLOR (0x01)
97 #define TME_SUNFB_S4_STATUS_ID_MONO (0x02)
98 #define TME_SUNFB_S4_STATUS_ID_MONO_ECL (0x03)
99
100 /* these evaluate to nonzero for different kinds of framebuffers: */
101 #define _TME_SUNFB_IS_BWTWO(sunfb) ((sunfb)->tme_sunfb_class == TME_FB_XLAT_CLASS_MONOCHROME)
102 #define _TME_SUNFB_IS_P4(sunfb) ((sunfb)->tme_sunfb_bus_handler_regs == tme_sunfb_bus_cycle_p4)
103 #define _TME_SUNFB_IS_S4(sunfb) ((sunfb)->tme_sunfb_bus_handler_regs == tme_sunfb_bus_cycle_s4)
104 #define _TME_SUNFB_HAS_BT458(sunfb) ((sunfb)->tme_sunfb_depth == 8)
105
106 /* we fill writable TLB entries for framebuffer memory for this many
107 bytes at a time: */
108 #define TME_SUNFB_UPDATE_SIZE (1024)
109
110 #if 0
111 #define TME_SUNFB_DEBUG
112 #endif
113
114 /* this returns the sunfb size value for the given resolution: */
115 tme_uint32_t
tme_sunfb_size(const char * size)116 tme_sunfb_size(const char *size)
117 {
118 if (TME_ARG_IS(size, "1600x1280")) {
119 return (TME_SUNFB_SIZE_1600_1280);
120 }
121 else if (TME_ARG_IS(size, "1152x900")) {
122 return (TME_SUNFB_SIZE_1152_900);
123 }
124 else if (TME_ARG_IS(size, "1024x1024")) {
125 return (TME_SUNFB_SIZE_1024_1024);
126 }
127 else if (TME_ARG_IS(size, "1280x1024")) {
128 return (TME_SUNFB_SIZE_1280_1024);
129 }
130 else if (TME_ARG_IS(size, "1440x1440")) {
131 return (TME_SUNFB_SIZE_1440_1440);
132 }
133 else if (TME_ARG_IS(size, "640x480")) {
134 return (TME_SUNFB_SIZE_640_480);
135 }
136 else if (TME_ARG_IS(size, "1024x768")) {
137 return (TME_SUNFB_SIZE_1024_768);
138 }
139 return (TME_SUNFB_SIZE_NULL);
140 }
141
142 /* this returns the width for the given sunfb size: */
143 tme_uint32_t
tme_sunfb_size_width(tme_uint32_t sunfb_size)144 tme_sunfb_size_width(tme_uint32_t sunfb_size)
145 {
146 switch (sunfb_size) {
147 default: assert(FALSE);
148 case TME_SUNFB_SIZE_640_480: return (640);
149 case TME_SUNFB_SIZE_1024_768: /* FALLTHROUGH */
150 case TME_SUNFB_SIZE_1024_1024: return (1024);
151 case TME_SUNFB_SIZE_1152_900: return (1152);
152 case TME_SUNFB_SIZE_1280_1024: return (1280);
153 case TME_SUNFB_SIZE_1600_1280: return (1600);
154 case TME_SUNFB_SIZE_1440_1440: return (1440);
155 }
156 }
157
158 /* this returns the height for the given sunfb size: */
159 tme_uint32_t
tme_sunfb_size_height(tme_uint32_t sunfb_size)160 tme_sunfb_size_height(tme_uint32_t sunfb_size)
161 {
162 switch (sunfb_size) {
163 default: assert(FALSE);
164 case TME_SUNFB_SIZE_640_480: return (480);
165 case TME_SUNFB_SIZE_1024_768: return (768);
166 case TME_SUNFB_SIZE_1152_900: return (900);
167 case TME_SUNFB_SIZE_1024_1024: /* FALLTHROUGH */
168 case TME_SUNFB_SIZE_1280_1024: return (1024);
169 case TME_SUNFB_SIZE_1600_1280: return (1280);
170 case TME_SUNFB_SIZE_1440_1440: return (1440);
171 }
172 }
173
174 /* XXX FIXME - this should be in a tme/ic/bt458.c: */
175 /* this determines the closest regular colormap indices for the
176 overlay map: */
177 int
tme_bt458_omap_best(struct tme_bt458 * bt458)178 tme_bt458_omap_best(struct tme_bt458 *bt458)
179 {
180 unsigned int omap_i;
181 unsigned int cmap_i;
182 tme_int32_t score;
183 unsigned int cmap_i_best;
184 tme_int32_t score_best;
185 tme_int32_t score_part;
186 int changed;
187
188 /* loop over the overlay map indices: */
189 changed = FALSE;
190 for (omap_i = 0;
191 omap_i < TME_ARRAY_ELS(bt458->tme_bt458_omap_primaries[0]);
192 omap_i++) {
193
194 /* silence gcc -Wuninitialized: */
195 cmap_i_best = 0;
196
197 /* loop over the regular colormap indices: */
198 score_best = (256 * 256 * 256);
199 for (cmap_i = 0;
200 cmap_i < 256;
201 cmap_i++) {
202
203 /* score this colormap entry, by taking the product of the
204 distances between this colormap entry's primaries and this
205 overlay map entry's primaries: */
206 score = bt458->tme_bt458_omap_r[omap_i];
207 score -= (bt458->tme_bt458_cmap_r)[cmap_i];
208 score_part = bt458->tme_bt458_omap_g[omap_i];
209 score_part -= (bt458->tme_bt458_cmap_g)[cmap_i];
210 score *= score_part;
211 score_part = bt458->tme_bt458_omap_b[omap_i];
212 score_part -= (bt458->tme_bt458_cmap_b)[cmap_i];
213 score *= score_part;
214 if (score < 0) {
215 score = -score;
216 }
217
218 /* update the best colormap entry: */
219 if (score < score_best) {
220 score_best = score;
221 cmap_i_best = cmap_i;
222 }
223 }
224
225 /* save the closest index: */
226 changed |= bt458->tme_bt458_omap_cmap_indices[omap_i] - cmap_i_best;
227 bt458->tme_bt458_omap_cmap_indices[omap_i] = cmap_i_best;
228 }
229
230 return (changed);
231 }
232
233 /* this handles a mode change callout: */
234 static int
_tme_sunfb_mode_change(struct tme_sunfb * sunfb)235 _tme_sunfb_mode_change(struct tme_sunfb *sunfb)
236 {
237 struct tme_fb_connection *conn_fb_other;
238 struct tme_fb_connection *conn_fb;
239 int rc;
240
241 /* if this framebuffer has a Bt458: */
242 if (_TME_SUNFB_HAS_BT458(sunfb)) {
243
244 /* update the best regular colormap indices for the colors in the
245 overlay map. if any of them have changed, we may have do to a
246 full update: */
247 if (tme_bt458_omap_best(&sunfb->tme_sunfb_bt458)) {
248
249 /* if this framebuffer has an update-full function, call it: */
250 if (sunfb->tme_sunfb_update_full != NULL) {
251 (*sunfb->tme_sunfb_update_full)(sunfb);
252 }
253 }
254 }
255
256 /* get both sides of the framebuffer connection: */
257 conn_fb_other = sunfb->tme_sunfb_fb_connection;
258 conn_fb = (struct tme_fb_connection *) conn_fb_other->tme_fb_connection.tme_connection_other;
259
260 /* unlock the mutex: */
261 tme_mutex_unlock(&sunfb->tme_sunfb_mutex);
262
263 /* do the callout: */
264 rc = (conn_fb_other != NULL
265 ? ((*conn_fb_other->tme_fb_connection_mode_change)
266 (conn_fb_other))
267 : TME_OK);
268
269 /* lock the mutex: */
270 tme_mutex_lock(&sunfb->tme_sunfb_mutex);
271
272 return (rc);
273 }
274
275 /* the sunfb callout function. it must be called with the mutex locked: */
276 static void
_tme_sunfb_callout(struct tme_sunfb * sunfb)277 _tme_sunfb_callout(struct tme_sunfb *sunfb)
278 {
279 struct tme_bus_connection *conn_bus;
280 int int_asserted;
281 int callouts_blocked;
282 int rc;
283
284 /* if this function is already running in another thread, simply
285 return now. the other thread will do our work: */
286 if (sunfb->tme_sunfb_callout_flags
287 & TME_SUNFB_CALLOUT_RUNNING) {
288 return;
289 }
290
291 /* callouts are now running: */
292 sunfb->tme_sunfb_callout_flags
293 |= TME_SUNFB_CALLOUT_RUNNING;
294
295 /* initially, no callouts are blocked: */
296 callouts_blocked = 0;
297
298 /* loop forever: */
299 for (;;) {
300
301 /* any callout, successful or not, will clear this bit. if we get
302 to the bottom of the loop and this bit is still set, there are
303 no more (unblocked) callouts to make, so we can stop: */
304 callouts_blocked |= TME_SUNFB_CALLOUT_RUNNING;
305
306 /* we always clear the interrupt callout flag, because we only
307 need it to get callouts to run at all: */
308 sunfb->tme_sunfb_callout_flags &= ~TME_SUNFB_CALLOUT_INT;
309
310 /* if our interrupt signal has changed, and this callout isn't
311 blocked: */
312 int_asserted
313 = (_TME_SUNFB_IS_S4(sunfb)
314 ? ((sunfb->tme_sunfb_s4_regs.tme_sunfb_s4_regs_control
315 & TME_SUNFB_S4_CONTROL_INT_ENABLE)
316 && (sunfb->tme_sunfb_s4_regs.tme_sunfb_s4_regs_status
317 & TME_SUNFB_S4_STATUS_INT_PENDING))
318 : FALSE);
319 if ((!int_asserted != !sunfb->tme_sunfb_int_asserted)
320 && (callouts_blocked & TME_SUNFB_CALLOUT_INT) == 0) {
321
322 /* get our bus connection: */
323 conn_bus = tme_memory_atomic_pointer_read(struct tme_bus_connection *,
324 sunfb->tme_sunfb_device.tme_bus_device_connection,
325 &sunfb->tme_sunfb_device.tme_bus_device_connection_rwlock);
326
327 /* unlock our mutex: */
328 tme_mutex_unlock(&sunfb->tme_sunfb_mutex);
329
330 /* call out the bus interrupt signal edge: */
331 rc = (*conn_bus->tme_bus_signal)
332 (conn_bus,
333 sunfb->tme_sunfb_bus_signal_int
334 | TME_BUS_SIGNAL_EDGE
335 | (int_asserted
336 ? TME_BUS_SIGNAL_LEVEL_ASSERTED
337 : TME_BUS_SIGNAL_LEVEL_NEGATED));
338
339 /* lock our mutex: */
340 tme_mutex_lock(&sunfb->tme_sunfb_mutex);
341
342 /* unblock all callouts: */
343 callouts_blocked = 0;
344
345 /* if this callout failed: */
346 if (rc != TME_OK) {
347
348 /* reschedule this callout but block it until some other
349 callout succeeds: */
350 sunfb->tme_sunfb_callout_flags |= TME_SUNFB_CALLOUT_INT;
351 callouts_blocked |= TME_SUNFB_CALLOUT_INT;
352 continue;
353 }
354
355 /* note the new state of the interrupt signal: */
356 sunfb->tme_sunfb_int_asserted = int_asserted;
357 }
358
359 /* if we need to call out a mode change, and this callout isn't
360 blocked: */
361 if ((sunfb->tme_sunfb_callout_flags & TME_SUNFB_CALLOUT_MODE_CHANGE)
362 && (callouts_blocked & TME_SUNFB_CALLOUT_MODE_CHANGE) == 0) {
363
364 /* clear this callout: */
365 sunfb->tme_sunfb_callout_flags &= ~TME_SUNFB_CALLOUT_MODE_CHANGE;
366
367 /* call out the mode change: */
368 rc = _tme_sunfb_mode_change(sunfb);
369
370 /* unblock all callouts: */
371 callouts_blocked = 0;
372
373 /* if the callout failed: */
374 if (rc != TME_OK) {
375
376 /* reschedule this callout but block it until some other
377 callout succeeds: */
378 sunfb->tme_sunfb_callout_flags |= TME_SUNFB_CALLOUT_MODE_CHANGE;
379 callouts_blocked |= TME_SUNFB_CALLOUT_MODE_CHANGE;
380 continue;
381 }
382 }
383
384 /* if no more (unblocked) callouts can run, we can stop: */
385 if (callouts_blocked & TME_SUNFB_CALLOUT_RUNNING) {
386 break;
387 }
388 }
389
390 /* clear that callouts are running: */
391 sunfb->tme_sunfb_callout_flags &= ~TME_SUNFB_CALLOUT_RUNNING;
392 }
393
394 /* the callout thread: */
395 static void
_tme_sunfb_callout_thread(void * _sunfb)396 _tme_sunfb_callout_thread(void *_sunfb)
397 {
398 struct tme_sunfb *sunfb;
399
400 /* recover our data structure: */
401 sunfb = _sunfb;
402
403 /* lock the mutex: */
404 tme_mutex_lock(&sunfb->tme_sunfb_mutex);
405
406 /* loop forever: */
407 for (;;) {
408
409 /* make any callouts: */
410 _tme_sunfb_callout(sunfb);
411
412 /* wait on the condition: */
413 tme_cond_wait_yield(&sunfb->tme_sunfb_callout_cond,
414 &sunfb->tme_sunfb_mutex);
415 }
416 /* NOTREACHED */
417 }
418
419 /* this is called before the framebuffer's display is updated: */
420 int
tme_sunfb_memory_update(struct tme_fb_connection * conn_fb)421 tme_sunfb_memory_update(struct tme_fb_connection *conn_fb)
422 {
423 struct tme_sunfb *sunfb;
424 int int_asserted;
425 struct tme_token *tlb_token;
426
427 /* recover our data structure: */
428 sunfb = conn_fb->tme_fb_connection.tme_connection_element->tme_element_private;
429
430 /* lock the mutex: */
431 tme_mutex_lock(&sunfb->tme_sunfb_mutex);
432
433 /* if this framebuffer supports interrupts, one is now pending. the
434 interrupt should also be asserted if it's enabled: */
435 if (_TME_SUNFB_IS_S4(sunfb)) {
436 sunfb->tme_sunfb_s4_regs.tme_sunfb_s4_regs_status
437 |= TME_SUNFB_S4_STATUS_INT_PENDING;
438 int_asserted
439 = ((sunfb->tme_sunfb_s4_regs.tme_sunfb_s4_regs_control
440 & TME_SUNFB_S4_CONTROL_INT_ENABLE) != 0);
441 }
442 else {
443 int_asserted = FALSE;
444 }
445
446 /* if this interrupt should be asserted and it isn't already, or if
447 we have other callouts to make, notify the callout thread: */
448 if ((int_asserted && !sunfb->tme_sunfb_int_asserted)
449 || (sunfb->tme_sunfb_callout_flags & TME_SUNFB_CALLOUTS_MASK) != 0) {
450 tme_cond_notify(&sunfb->tme_sunfb_callout_cond, FALSE);
451 }
452
453 /* set the offsets of the first and last bytes updated in the real
454 framebuffer memory: */
455 conn_fb->tme_fb_connection_offset_updated_first = sunfb->tme_sunfb_offset_updated_first;
456 conn_fb->tme_fb_connection_offset_updated_last = sunfb->tme_sunfb_offset_updated_last;
457
458 /* reset the offsets of the first and last bytes updated in the real
459 framebuffer memory: */
460 sunfb->tme_sunfb_offset_updated_first = 0 - (tme_uint32_t) 1;
461 sunfb->tme_sunfb_offset_updated_last = 0;
462
463 /* invalidate any outstanding writable TLB entry: */
464 tlb_token = sunfb->tme_sunfb_tlb_token;
465 if (tlb_token != NULL) {
466 tme_token_invalidate(tlb_token);
467 sunfb->tme_sunfb_tlb_token = NULL;
468 }
469
470 /* unlock the mutex: */
471 tme_mutex_unlock(&sunfb->tme_sunfb_mutex);
472
473 return (TME_OK);
474 }
475
476 /* the sunfb memory bus cycle handler: */
477 static int
_tme_sunfb_bus_cycle_memory(void * _sunfb,struct tme_bus_cycle * cycle_init)478 _tme_sunfb_bus_cycle_memory(void *_sunfb, struct tme_bus_cycle *cycle_init)
479 {
480 struct tme_sunfb *sunfb;
481
482 /* recover our data structure: */
483 sunfb = (struct tme_sunfb *) _sunfb;
484
485 /* lock the mutex: */
486 tme_mutex_lock(&sunfb->tme_sunfb_mutex);
487
488 /* run the cycle: */
489 assert (cycle_init->tme_bus_cycle_address
490 >= sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first);
491 tme_bus_cycle_xfer_memory(cycle_init,
492 (sunfb->tme_sunfb_memory
493 - sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first),
494 sunfb->tme_sunfb_memory_address_last_displayed);
495
496 /* unlock the mutex: */
497 tme_mutex_unlock(&sunfb->tme_sunfb_mutex);
498
499 /* no faults: */
500 return (TME_OK);
501 }
502
503 /* the sunfb memory pad bus cycle handler: */
504 static int
_tme_sunfb_bus_cycle_memory_pad(void * _sunfb,struct tme_bus_cycle * cycle_init)505 _tme_sunfb_bus_cycle_memory_pad(void *_sunfb, struct tme_bus_cycle *cycle_init)
506 {
507 struct tme_sunfb *sunfb;
508
509 /* recover our data structure: */
510 sunfb = (struct tme_sunfb *) _sunfb;
511
512 /* lock the mutex: */
513 tme_mutex_lock(&sunfb->tme_sunfb_mutex);
514
515 /* run the cycle: */
516 assert (cycle_init->tme_bus_cycle_address
517 > sunfb->tme_sunfb_memory_address_last_displayed);
518 tme_bus_cycle_xfer_memory(cycle_init,
519 (sunfb->tme_sunfb_memory_pad
520 - (sunfb->tme_sunfb_memory_address_last_displayed
521 + 1)),
522 sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_last);
523
524 /* unlock the mutex: */
525 tme_mutex_unlock(&sunfb->tme_sunfb_mutex);
526
527 /* no faults: */
528 return (TME_OK);
529 }
530
531 /* the sunfb P4 bus cycle handler: */
532 int
tme_sunfb_bus_cycle_p4(void * _sunfb,struct tme_bus_cycle * cycle_init)533 tme_sunfb_bus_cycle_p4(void *_sunfb, struct tme_bus_cycle *cycle_init)
534 {
535 struct tme_sunfb *sunfb;
536 tme_uint32_t p4_old, p4_new;
537 tme_bus_addr32_t undecoded;
538
539 /* recover our data structure: */
540 sunfb = (struct tme_sunfb *) _sunfb;
541
542 /* lock the mutex: */
543 tme_mutex_lock(&sunfb->tme_sunfb_mutex);
544
545 /* get the old P4 value: */
546 p4_old = tme_betoh_u32(sunfb->tme_sunfb_p4);
547
548 /* the entire register bus subregion is all decoded (or, rather, not
549 decoded) as the P4: */
550 undecoded
551 = (cycle_init->tme_bus_cycle_address
552 & (sunfb->tme_sunfb_bus_subregion_regs.tme_bus_subregion_address_last
553 - sunfb->tme_sunfb_bus_subregion_regs.tme_bus_subregion_address_first
554 - sizeof(sunfb->tme_sunfb_p4)));
555 cycle_init->tme_bus_cycle_address
556 -= undecoded;
557
558 /* run the cycle: */
559 assert (cycle_init->tme_bus_cycle_address
560 >= sunfb->tme_sunfb_bus_subregion_regs.tme_bus_subregion_address_first);
561 tme_bus_cycle_xfer_memory(cycle_init,
562 (((tme_uint8_t *) &sunfb->tme_sunfb_p4)
563 - sunfb->tme_sunfb_bus_subregion_regs.tme_bus_subregion_address_first),
564 (sunfb->tme_sunfb_bus_subregion_regs.tme_bus_subregion_address_first
565 + sizeof(sunfb->tme_sunfb_p4)
566 - 1));
567 cycle_init->tme_bus_cycle_address
568 += undecoded;
569
570 /* get the new P4 value: */
571 p4_new = tme_betoh_u32(sunfb->tme_sunfb_p4);
572
573 /* put back the unchanging bits: */
574 p4_new
575 = ((p4_new
576 & ~TME_SUNFB_P4_RO_MASK)
577 | (p4_old
578 & TME_SUNFB_P4_RO_MASK));
579
580 /* we do not support these bits: */
581 if (p4_new
582 & (TME_SUNFB_P4_REG_SYNC_RAMDAC
583 | TME_SUNFB_P4_REG_ENABLE_INT)) {
584 abort();
585 }
586
587 /* set the new P4 value: */
588 sunfb->tme_sunfb_p4 = tme_htobe_u32(p4_new);
589
590 /* unlock the mutex: */
591 tme_mutex_unlock(&sunfb->tme_sunfb_mutex);
592
593 /* no faults: */
594 return (TME_OK);
595 }
596
597 /* the Brooktree BT458 bus cycle handler: */
598 int
tme_sunfb_bus_cycle_bt458(void * _sunfb,struct tme_bus_cycle * cycle_init)599 tme_sunfb_bus_cycle_bt458(void *_sunfb, struct tme_bus_cycle *cycle_init)
600 {
601 struct tme_sunfb *sunfb;
602 struct tme_bt458 *bt458;
603 unsigned int reg;
604 tme_uint32_t value_packed;
605 tme_uint8_t value;
606 unsigned int byte_count;
607 unsigned int bt458_address;
608 unsigned int bt458_rgb;
609 unsigned int map_count;
610
611 /* recover our data structure: */
612 sunfb = (struct tme_sunfb *) _sunfb;
613
614 /* we only emulate 8-bit and aligned 32-bit accesses: */
615 reg = cycle_init->tme_bus_cycle_address % TME_SUNFB_S4_SIZ_BT458;
616 if (cycle_init->tme_bus_cycle_size != sizeof(tme_uint8_t)
617 && (cycle_init->tme_bus_cycle_size != sizeof(tme_uint32_t)
618 || (reg % sizeof(tme_uint32_t)) != 0)) {
619 abort();
620 }
621 reg &= (TME_SUNFB_S4_SIZ_BT458 - sizeof(tme_uint32_t));
622
623 /* lock the mutex: */
624 tme_mutex_lock(&sunfb->tme_sunfb_mutex);
625
626 /* get the Bt458 address registers: */
627 bt458 = &sunfb->tme_sunfb_bt458;
628 bt458_address = bt458->tme_bt458_address;
629 bt458_rgb = bt458->tme_bt458_rgb;
630
631 /* set the number of colormap values per read and write: */
632 map_count = ((sunfb->tme_sunfb_flags & TME_SUNFB_FLAG_BT458_CMAP_PACKED)
633 ? cycle_init->tme_bus_cycle_size
634 : sizeof(tme_uint8_t));
635
636 /* if this is a write: */
637 if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
638
639 /* run the bus cycle: */
640 if (cycle_init->tme_bus_cycle_size == sizeof(tme_uint32_t)) {
641 tme_bus_cycle_xfer_reg(cycle_init,
642 &value_packed,
643 TME_BUS32_LOG2);
644
645 /* for a 32-bit write to an 8-bit register, a framebuffer either
646 uses byte lane D24..D31 or byte lane D0..D7: */
647 value
648 = (value_packed
649 >> (((sunfb->tme_sunfb_flags
650 & (TME_SUNFB_FLAG_BT458_BYTE_D0_D7
651 | TME_SUNFB_FLAG_BT458_BYTE_D24_D31))
652 == TME_SUNFB_FLAG_BT458_BYTE_D24_D31)
653 ? 24
654 : 0));
655 }
656 else {
657 tme_bus_cycle_xfer_reg(cycle_init,
658 &value,
659 TME_BUS8_LOG2);
660 value_packed = value;
661 value_packed <<= 24;
662 }
663
664 /* if this is a write to the address register: */
665 if (reg == TME_SUNFB_S4_REG_BT458_ADDRESS) {
666
667 /* set the Bt458 address register: */
668 bt458_address = value;
669 }
670
671 /* if this is a write to the colormap register: */
672 else if (reg == TME_SUNFB_S4_REG_BT458_CMAP) {
673
674 /* write the colormap: */
675 do {
676
677 /* write one colormap primary: */
678 (bt458->tme_bt458_cmap_primaries[bt458_rgb])[bt458_address] = value_packed >> 24;
679
680 /* advance the packed value: */
681 value_packed <<= 8;
682
683 /* advance the Bt458 address registers: */
684 bt458_rgb++;
685 if (bt458_rgb == TME_ARRAY_ELS(bt458->tme_bt458_cmap_primaries)) {
686 bt458_address++;
687 bt458_rgb = 0;
688 }
689 } while (--map_count > 0);
690
691 /* calling out a mode change on every colormap register write is
692 expensive and unnecessary. instead, arrange for the update
693 function to eventually cause a mode change: */
694 sunfb->tme_sunfb_callout_flags |= TME_SUNFB_CALLOUT_MODE_CHANGE;
695 }
696
697 /* if this is a write to the control register: */
698 else if (reg == TME_SUNFB_S4_REG_BT458_CONTROL) {
699
700 /* dispatch on the address: */
701 switch (bt458_address) {
702
703 /* the read mask register: */
704 case TME_BT458_REG_CONTROL_MASK_READ:
705 /* all planes must be on: */
706 if (value != 0xff) {
707 abort();
708 }
709 break;
710
711 /* the blink mask register: */
712 case TME_BT458_REG_CONTROL_MASK_BLINK:
713 /* no planes must be blinking: */
714 if (value != 0x00) {
715 abort();
716 }
717 break;
718
719 /* the command register: */
720 case TME_BT458_REG_CONTROL_COMMAND:
721
722 /* XXX FIXME - we should validate values written to the
723 command register: */
724 break;
725
726 /* the test register: */
727 case TME_BT458_REG_CONTROL_TEST:
728 break;
729
730 default:
731 break;
732 }
733
734 /* the Bt458 datasheet says, "If an invalid address is loaded
735 into the address register, data written to the device will
736 be ignored and invalid data will be read by the MPU." */
737 if (bt458_address >= TME_BT458_REG_CONTROL_FIRST
738 && bt458_address <= TME_BT458_REG_CONTROL_LAST) {
739
740 /* write this register: */
741 bt458->tme_bt458_regs[bt458_address - TME_BT458_REG_CONTROL_FIRST] = value;
742 }
743 }
744
745 /* this must be a write to the overlay map register: */
746 else {
747 assert (reg == TME_SUNFB_S4_REG_BT458_OMAP);
748
749 /* write the overlay map: */
750 do {
751
752 /* if the Bt458 address isn't in the overlay map: */
753 if (bt458_address >= 4) {
754 abort();
755 }
756
757 /* write one overlay map primary: */
758 bt458->tme_bt458_omap_primaries[bt458_rgb][bt458_address] = value_packed >> 24;
759
760 /* advance the packed value: */
761 value_packed <<= 8;
762
763 /* advance the Bt458 address registers: */
764 bt458_rgb++;
765 if (bt458_rgb == TME_ARRAY_ELS(bt458->tme_bt458_omap_primaries)) {
766 bt458_address++;
767 bt458_rgb = 0;
768 }
769 } while (--map_count > 0);
770
771 /* calling out a mode change on every overlap map register write
772 is expensive and unnecessary. instead, arrange for the
773 update function to eventually cause a mode change: */
774 sunfb->tme_sunfb_callout_flags |= TME_SUNFB_CALLOUT_MODE_CHANGE;
775 }
776 }
777
778 /* otherwise, this is a read: */
779 else {
780 assert (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
781
782 /* zero the value read: */
783 value_packed = 0;
784
785 /* assume only one byte will be read: */
786 byte_count = sizeof(tme_uint8_t);
787
788 /* if this is a read of the address register: */
789 if (reg == TME_SUNFB_S4_REG_BT458_ADDRESS) {
790
791 /* read the Bt458 address register: */
792 value_packed = bt458_address;
793 }
794
795 /* if this is a read to the colormap register: */
796 else if (reg == TME_SUNFB_S4_REG_BT458_CMAP) {
797
798 /* read the colormap: */
799 byte_count = map_count;
800 do {
801
802 /* advance the packed value: */
803 value_packed <<= 8;
804
805 /* read one colormap primary: */
806 value_packed |= (bt458->tme_bt458_cmap_primaries[bt458_rgb])[bt458_address];
807
808 /* advance the Bt458 address registers: */
809 bt458_rgb++;
810 if (bt458_rgb == TME_ARRAY_ELS(bt458->tme_bt458_cmap_primaries)) {
811 bt458_address++;
812 bt458_rgb = 0;
813 }
814 } while (--map_count > 0);
815 }
816
817 /* if this is a read of the control register: */
818 else if (reg == TME_SUNFB_S4_REG_BT458_CONTROL) {
819
820 /* the Bt458 datasheet says, "If an invalid address is loaded
821 into the address register, data written to the device will
822 be ignored and invalid data will be read by the MPU." */
823 if (bt458_address >= TME_BT458_REG_CONTROL_FIRST
824 && bt458_address <= TME_BT458_REG_CONTROL_LAST) {
825
826 /* read this register: */
827 value_packed = bt458->tme_bt458_regs[bt458_address - TME_BT458_REG_CONTROL_FIRST];
828 }
829 }
830
831 /* this must be a read of the overlay map register: */
832 else {
833 assert (reg == TME_SUNFB_S4_REG_BT458_OMAP);
834
835 /* read the overlay map: */
836 byte_count = map_count;
837 do {
838
839 /* if the Bt458 address isn't in the overlay map: */
840 if (bt458_address >= 4) {
841 abort();
842 }
843
844 /* advance the packed value: */
845 value_packed <<= 8;
846
847 /* read one overlay map primary: */
848 value_packed |= bt458->tme_bt458_omap_primaries[bt458_rgb][bt458_address];
849
850 /* advance the Bt458 address registers: */
851 bt458_rgb++;
852 if (bt458_rgb == TME_ARRAY_ELS(bt458->tme_bt458_omap_primaries)) {
853 bt458_address++;
854 bt458_rgb = 0;
855 }
856 } while (--map_count > 0);
857 }
858
859 /* run the bus cycle: */
860 if (cycle_init->tme_bus_cycle_size == sizeof(tme_uint32_t)) {
861 if (byte_count == sizeof(tme_uint8_t)) {
862 value_packed |= (value_packed << 8);
863 value_packed |= (value_packed << 16);
864 }
865 tme_bus_cycle_xfer_reg(cycle_init,
866 &value_packed,
867 TME_BUS32_LOG2);
868 }
869 else {
870 value = value_packed;
871 tme_bus_cycle_xfer_reg(cycle_init,
872 &value,
873 TME_BUS8_LOG2);
874 }
875 }
876
877 /* update the Bt458 address registers: */
878 bt458->tme_bt458_address = bt458_address;
879 bt458->tme_bt458_rgb = ((reg == TME_SUNFB_S4_REG_BT458_CMAP
880 || reg == TME_SUNFB_S4_REG_BT458_OMAP)
881 ? bt458_rgb
882 : 0);
883
884 /* unlock the mutex: */
885 tme_mutex_unlock(&sunfb->tme_sunfb_mutex);
886
887 /* no faults: */
888 return (TME_OK);
889 }
890
891 /* the sunfb S4 bus cycle handler: */
892 int
tme_sunfb_bus_cycle_s4(void * _sunfb,struct tme_bus_cycle * cycle_init)893 tme_sunfb_bus_cycle_s4(void *_sunfb, struct tme_bus_cycle *cycle_init)
894 {
895 struct tme_sunfb *sunfb;
896 tme_bus_addr32_t undecoded;
897 tme_uint8_t sunfb_s4_status;
898
899 /* if this bus cycle happened in the Bt458 registers: */
900 if ((cycle_init->tme_bus_cycle_address % TME_SUNFB_S4_SIZ_REGS)
901 < TME_SUNFB_S4_SIZ_BT458) {
902
903 /* call the Bt458 cycle handler: */
904 return (tme_sunfb_bus_cycle_bt458(_sunfb, cycle_init));
905 }
906
907 /* recover our data structure: */
908 sunfb = (struct tme_sunfb *) _sunfb;
909
910 /* lock the mutex: */
911 tme_mutex_lock(&sunfb->tme_sunfb_mutex);
912
913 /* the entire register bus subregion is all decoded (or, rather, not
914 decoded) as the S4 registers: */
915 undecoded
916 = (cycle_init->tme_bus_cycle_address
917 & (((tme_bus_addr32_t) 0)
918 - TME_SUNFB_S4_SIZ_REGS));
919
920 /* save the status register: */
921 sunfb_s4_status = sunfb->tme_sunfb_s4_regs.tme_sunfb_s4_regs_status;
922
923 /* if this is a write, and an interrupt is pending, and this write
924 covers the status register: */
925 if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE
926 && (sunfb_s4_status & TME_SUNFB_S4_STATUS_INT_PENDING)
927 && (cycle_init->tme_bus_cycle_address
928 <= (undecoded
929 + TME_SUNFB_S4_REG(tme_sunfb_s4_regs_status)))
930 && (cycle_init->tme_bus_cycle_size
931 > ((undecoded
932 + TME_SUNFB_S4_REG(tme_sunfb_s4_regs_status))
933 - cycle_init->tme_bus_cycle_address))) {
934
935 /* clear the interrupt: */
936 sunfb_s4_status &= ~TME_SUNFB_S4_STATUS_INT_PENDING;
937 }
938
939 /* run the cycle: */
940 assert (cycle_init->tme_bus_cycle_address
941 >= sunfb->tme_sunfb_bus_subregion_regs.tme_bus_subregion_address_first);
942 tme_bus_cycle_xfer_memory(cycle_init,
943 (((tme_uint8_t *) &sunfb->tme_sunfb_s4_regs)
944 - TME_SUNFB_S4_SIZ_BT458
945 - undecoded),
946 (undecoded
947 | (TME_SUNFB_S4_SIZ_REGS - 1)));
948
949 /* restore the status register: */
950 sunfb->tme_sunfb_s4_regs.tme_sunfb_s4_regs_status = sunfb_s4_status;
951
952 /* make any callouts: */
953 _tme_sunfb_callout(sunfb);
954
955 /* unlock the mutex: */
956 tme_mutex_unlock(&sunfb->tme_sunfb_mutex);
957
958 /* no faults: */
959 return (TME_OK);
960 }
961
962 /* the sunfb TLB filler: */
963 static int
_tme_sunfb_tlb_fill(void * _sunfb,struct tme_bus_tlb * tlb,tme_bus_addr_t address_wider,unsigned int cycles)964 _tme_sunfb_tlb_fill(void *_sunfb,
965 struct tme_bus_tlb *tlb,
966 tme_bus_addr_t address_wider,
967 unsigned int cycles)
968 {
969 struct tme_sunfb *sunfb;
970 tme_bus_addr32_t address;
971 struct tme_token *tlb_token;
972 struct tme_token *tlb_token_other;
973 tme_uint32_t offset_updated_first;
974 tme_uint32_t offset_updated_last;
975 unsigned int subregion_i;
976
977 /* recover our data structure: */
978 sunfb = (struct tme_sunfb *) _sunfb;
979
980 /* initialize the TLB entry: */
981 tme_bus_tlb_initialize(tlb);
982
983 /* get the normal-width address: */
984 address = address_wider;
985 assert (address == address_wider);
986
987 /* if this address falls in the bus subregion for memory: */
988 if ((sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first
989 <= address)
990 && (address
991 <= sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_last)) {
992
993 /* if this address falls in the memory pad: */
994 if (address > sunfb->tme_sunfb_memory_address_last_displayed) {
995
996 /* this TLB entry covers this range: */
997 tlb->tme_bus_tlb_addr_first = (sunfb->tme_sunfb_memory_address_last_displayed + 1);
998 tlb->tme_bus_tlb_addr_last = sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_last;
999
1000 /* bus cycles to this range are to the memory pad and can be
1001 fast: */
1002 tlb->tme_bus_tlb_cycle = _tme_sunfb_bus_cycle_memory_pad;
1003 tlb->tme_bus_tlb_emulator_off_write
1004 = (sunfb->tme_sunfb_memory_pad
1005 - tlb->tme_bus_tlb_addr_first);
1006 }
1007
1008 /* otherwise, this address does not fall in the memory pad: */
1009 else {
1010
1011 /* if this TLB entry is not for writing: */
1012 if ((cycles & TME_BUS_CYCLE_WRITE) == 0) {
1013
1014 /* this TLB entry covers this range: */
1015 tlb->tme_bus_tlb_addr_first = sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first;
1016 tlb->tme_bus_tlb_addr_last = sunfb->tme_sunfb_memory_address_last_displayed;
1017
1018 /* this TLB entry allows only (fast) reading to the memory: */
1019 tlb->tme_bus_tlb_emulator_off_read = sunfb->tme_sunfb_memory - tlb->tme_bus_tlb_addr_first;
1020 tlb->tme_bus_tlb_rwlock = &sunfb->tme_sunfb_rwlock;
1021 tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ;
1022 tlb->tme_bus_tlb_cycle = _tme_sunfb_bus_cycle_memory;
1023 tlb->tme_bus_tlb_cycle_private = _sunfb;
1024 return (TME_OK);
1025 }
1026
1027 /* get the token for this writable TLB entry: */
1028 tlb_token = tlb->tme_bus_tlb_token;
1029
1030 /* if a different writable TLB entry's token is outstanding: */
1031 tlb_token_other = sunfb->tme_sunfb_tlb_token;
1032 if (__tme_predict_true(tlb_token_other != NULL)) {
1033 if (tlb_token_other != tlb_token) {
1034
1035 /* invalidate this other TLB entry: */
1036 tme_token_invalidate(tlb_token_other);
1037 }
1038 }
1039
1040 /* save the token for this writable TLB entry: */
1041 sunfb->tme_sunfb_tlb_token = tlb_token;
1042
1043 /* update the offsets of the first and last bytes updated in the
1044 real framebuffer memory: */
1045 offset_updated_first = address;
1046 offset_updated_first -= (tme_uint32_t) sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first;
1047 offset_updated_last = offset_updated_first + TME_SUNFB_UPDATE_SIZE;
1048 offset_updated_first
1049 = TME_MIN(offset_updated_first,
1050 sunfb->tme_sunfb_offset_updated_first);
1051 offset_updated_last
1052 = TME_MAX(offset_updated_last,
1053 sunfb->tme_sunfb_offset_updated_last);
1054 offset_updated_last
1055 = TME_MIN(offset_updated_last,
1056 (((tme_uint32_t)
1057 sunfb->tme_sunfb_memory_address_last_displayed)
1058 - ((tme_uint32_t)
1059 sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first)));
1060 sunfb->tme_sunfb_offset_updated_first = offset_updated_first;
1061 sunfb->tme_sunfb_offset_updated_last = offset_updated_last;
1062
1063 /* this TLB entry covers this range: */
1064 tlb->tme_bus_tlb_addr_first
1065 = (sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first
1066 + offset_updated_first);
1067 tlb->tme_bus_tlb_addr_last
1068 = (sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first
1069 + offset_updated_last);
1070
1071 /* bus cycles to this range are to the memory and can be fast: */
1072 tlb->tme_bus_tlb_cycle = _tme_sunfb_bus_cycle_memory;
1073 tlb->tme_bus_tlb_emulator_off_write
1074 = (sunfb->tme_sunfb_memory
1075 - sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first);
1076 }
1077
1078 /* this TLB entry allows fast reading and writing: */
1079 tlb->tme_bus_tlb_emulator_off_read = tlb->tme_bus_tlb_emulator_off_write;
1080 }
1081
1082 /* otherwise, this address doesn't fall in the bus subregion for memory: */
1083 else {
1084
1085 /* search the other bus subregions: */
1086 for (subregion_i = 0;; subregion_i++) {
1087
1088 /* this address must be in some subregion: */
1089 assert (subregion_i < TME_SUNFB_BUS_SUBREGIONS_MAX);
1090
1091 /* if this subregion is defined, and this address falls in it: */
1092 if (sunfb->tme_sunfb_bus_handlers[subregion_i] != NULL
1093 && (sunfb->tme_sunfb_bus_subregions[subregion_i].tme_bus_subregion_address_first
1094 <= address)
1095 && (address
1096 <= sunfb->tme_sunfb_bus_subregions[subregion_i].tme_bus_subregion_address_last)) {
1097
1098 /* this TLB entry covers this range: */
1099 tlb->tme_bus_tlb_addr_first = sunfb->tme_sunfb_bus_subregions[subregion_i].tme_bus_subregion_address_first;
1100 tlb->tme_bus_tlb_addr_last = sunfb->tme_sunfb_bus_subregions[subregion_i].tme_bus_subregion_address_last;
1101
1102 /* bus cycles to this range are handled by this handler: */
1103 tlb->tme_bus_tlb_cycle = sunfb->tme_sunfb_bus_handlers[subregion_i];
1104
1105 break;
1106 }
1107 }
1108 }
1109
1110 /* the fast reading and writing rwlock: */
1111 tlb->tme_bus_tlb_rwlock = &sunfb->tme_sunfb_rwlock;
1112
1113 /* allow reading and writing: */
1114 tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
1115
1116 /* our bus cycle handler private data: */
1117 tlb->tme_bus_tlb_cycle_private = _sunfb;
1118
1119 return (TME_OK);
1120 }
1121
1122 #if TME_SUNFB_BUS_TRANSITION
1123
1124 /* this is the bus cycle transition glue: */
1125 int
tme_sunfb_bus_cycle_transition(void * _sunfb,struct tme_bus_cycle * master_cycle,void (* handler)_TME_P ((struct tme_sunfb *,struct tme_bus_cycle *,tme_uint32_t *,struct tme_completion *)))1126 tme_sunfb_bus_cycle_transition(void *_sunfb,
1127 struct tme_bus_cycle *master_cycle,
1128 void (*handler) _TME_P((struct tme_sunfb *,
1129 struct tme_bus_cycle *,
1130 tme_uint32_t *,
1131 struct tme_completion *)))
1132 {
1133 struct tme_completion completion_buffer;
1134 struct tme_sunfb *sunfb;
1135 tme_uint32_t master_fast_cycle_types;
1136
1137 /* initialize the completion buffer: */
1138 tme_completion_init(&completion_buffer);
1139
1140 #ifndef NDEBUG
1141
1142 /* initialize the completion: */
1143 completion_buffer.tme_completion_error = 0x71aa;
1144
1145 #endif /* NDEBUG */
1146
1147 /* recover our data structure: */
1148 sunfb = (struct tme_sunfb *) _sunfb;
1149
1150 /* lock the mutex: */
1151 tme_mutex_lock(&sunfb->tme_sunfb_mutex);
1152
1153 /* run the cycle handler: */
1154 (*handler)
1155 (sunfb,
1156 master_cycle,
1157 &master_fast_cycle_types,
1158 &completion_buffer);
1159
1160 /* unlock the mutex: */
1161 tme_mutex_unlock(&sunfb->tme_sunfb_mutex);
1162
1163 /* check the completion: */
1164 assert (completion_buffer.tme_completion_error != (int) 0x71aa);
1165
1166 return (completion_buffer.tme_completion_error);
1167 }
1168
1169 #endif /* TME_SUNFB_BUS_TRANSITION */
1170
1171 /* this makes a new framebuffer connection: */
1172 static int
_tme_sunfb_connection_make(struct tme_connection * conn,unsigned int state)1173 _tme_sunfb_connection_make(struct tme_connection *conn, unsigned int state)
1174 {
1175 struct tme_sunfb *sunfb;
1176 struct tme_fb_connection *conn_fb;
1177 struct tme_fb_connection *conn_fb_other;
1178 int rc;
1179
1180 /* recover our data structures: */
1181 sunfb = conn->tme_connection_element->tme_element_private;
1182 conn_fb = (struct tme_fb_connection *) conn;
1183 conn_fb_other = (struct tme_fb_connection *) conn->tme_connection_other;
1184
1185 /* both sides must be framebuffer connections: */
1186 assert(conn->tme_connection_type == TME_CONNECTION_FRAMEBUFFER);
1187 assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_FRAMEBUFFER);
1188
1189 /* lock our mutex: */
1190 tme_mutex_lock(&sunfb->tme_sunfb_mutex);
1191
1192 /* we're always set up to answer calls across the connection, so we
1193 only have to do work when the connection has gone full, namely
1194 taking the other side of the connection: */
1195 if (state == TME_CONNECTION_FULL) {
1196
1197 /* if the other side of the connection is not supplying specific
1198 displayed memory that it wants us to use: */
1199 if (conn_fb->tme_fb_connection_buffer == NULL) {
1200
1201 /* allocate displayed memory: */
1202 rc = tme_fb_xlat_alloc_src(conn_fb);
1203 assert (rc == TME_OK);
1204 }
1205
1206 /* if this framebuffer just maps the displayed memory on the bus,
1207 do that: */
1208 if (sunfb->tme_sunfb_memory == NULL) {
1209 sunfb->tme_sunfb_memory = conn_fb->tme_fb_connection_buffer;
1210 }
1211
1212 /* save our connection: */
1213 sunfb->tme_sunfb_fb_connection = conn_fb_other;
1214 }
1215
1216 /* unlock our mutex: */
1217 tme_mutex_unlock(&sunfb->tme_sunfb_mutex);
1218
1219 return (TME_OK);
1220 }
1221
1222 /* this breaks a connection: */
1223 static int
_tme_sunfb_connection_break(struct tme_connection * conn,unsigned int state)1224 _tme_sunfb_connection_break(struct tme_connection *conn, unsigned int state)
1225 {
1226 abort();
1227 }
1228
1229 /* this makes a new connection side for a sunfb: */
1230 static int
_tme_sunfb_connections_new(struct tme_element * element,const char * const * args,struct tme_connection ** _conns,char ** _output)1231 _tme_sunfb_connections_new(struct tme_element *element,
1232 const char * const *args,
1233 struct tme_connection **_conns,
1234 char **_output)
1235 {
1236 struct tme_sunfb *sunfb;
1237 struct tme_fb_connection *conn_fb;
1238 struct tme_connection *conn;
1239 int rc;
1240
1241 /* recover our data structure: */
1242 sunfb = (struct tme_sunfb *) element->tme_element_private;
1243
1244 /* make the generic bus device connection side: */
1245 rc = tme_bus_device_connections_new(element, args, _conns, _output);
1246 if (rc != TME_OK) {
1247 return (rc);
1248 }
1249
1250 /* if we don't have a framebuffer connection, make one: */
1251 if (sunfb->tme_sunfb_fb_connection == NULL) {
1252
1253 /* allocate the new framebuffer connection: */
1254 conn_fb = tme_new0(struct tme_fb_connection, 1);
1255 conn = &conn_fb->tme_fb_connection;
1256
1257 /* fill in the generic connection: */
1258 conn->tme_connection_next = *_conns;
1259 conn->tme_connection_type = TME_CONNECTION_FRAMEBUFFER;
1260 conn->tme_connection_score = tme_fb_connection_score;
1261 conn->tme_connection_make = _tme_sunfb_connection_make;
1262 conn->tme_connection_break = _tme_sunfb_connection_break;
1263
1264 /* fill in the framebuffer connection: */
1265 conn_fb->tme_fb_connection_mode_change = NULL;
1266 conn_fb->tme_fb_connection_update = NULL;
1267
1268 /* class: */
1269 conn_fb->tme_fb_connection_class = sunfb->tme_sunfb_class;
1270
1271 /* depth: */
1272 conn_fb->tme_fb_connection_depth = sunfb->tme_sunfb_depth;
1273
1274 /* width and height: */
1275 conn_fb->tme_fb_connection_width = tme_sunfb_size_width(sunfb->tme_sunfb_size);
1276 conn_fb->tme_fb_connection_height = tme_sunfb_size_height(sunfb->tme_sunfb_size);
1277
1278 /* we skip no pixels at the start of the scanline: */
1279 conn_fb->tme_fb_connection_skipx = 0;
1280
1281 /* we pad to 32-bit boundaries: */
1282 conn_fb->tme_fb_connection_scanline_pad = 32;
1283
1284 /* we are big-endian: */
1285 conn_fb->tme_fb_connection_order = TME_ENDIAN_BIG;
1286
1287 /* we don't allocate memory until the connection is made, in case
1288 the other side of the connection wants to provide us with a
1289 specific memory region to use (maybe we're on a system with
1290 real matching hardware and we can write directly to its buffer): */
1291 conn_fb->tme_fb_connection_buffer = NULL;
1292
1293 /* assume that bits per pixel is the same as depth: */
1294 conn_fb->tme_fb_connection_bits_per_pixel = sunfb->tme_sunfb_depth;
1295
1296 /* assume that our pixels don't have subfields: */
1297 conn_fb->tme_fb_connection_mask_g = 0;
1298 conn_fb->tme_fb_connection_mask_r = 0;
1299 conn_fb->tme_fb_connection_mask_b = 0;
1300
1301 /* set any update function: */
1302 conn_fb->tme_fb_connection_update = sunfb->tme_sunfb_memory_update;
1303
1304 /* if this is a bwtwo: */
1305 if (_TME_SUNFB_IS_BWTWO(sunfb)) {
1306
1307 /* intensities are a single bit, linearly mapped, but inverted: */
1308 conn_fb->tme_fb_connection_map_bits = 1;
1309 conn_fb->tme_fb_connection_map_g = NULL;
1310 conn_fb->tme_fb_connection_map_r = NULL;
1311 conn_fb->tme_fb_connection_map_b = NULL;
1312 conn_fb->tme_fb_connection_inverted = TRUE;
1313 }
1314
1315 /* otherwise, this is one of the eight-bit color framebuffers: */
1316 else {
1317
1318 /* intensities are eight bits and index mapped: */
1319 conn_fb->tme_fb_connection_map_bits = 8;
1320 conn_fb->tme_fb_connection_map_g = sunfb->tme_sunfb_cmap_g;
1321 conn_fb->tme_fb_connection_map_r = sunfb->tme_sunfb_cmap_r;
1322 conn_fb->tme_fb_connection_map_b = sunfb->tme_sunfb_cmap_b;
1323 }
1324
1325 /* return the connection side possibility: */
1326 *_conns = conn;
1327 }
1328
1329 /* done: */
1330 return (TME_OK);
1331 }
1332
1333 /* the new Sun framebuffer function: */
1334 int
tme_sunfb_new(struct tme_sunfb * sunfb,const char * const * args,char ** _output)1335 tme_sunfb_new(struct tme_sunfb *sunfb,
1336 const char * const *args,
1337 char **_output)
1338 {
1339 struct tme_bus_subregion *subregion;
1340 const struct tme_bus_subregion **_subregion_prev;
1341 unsigned int subregion_i;
1342 const char *sunfb_type_string;
1343 const char *sunfb_size_string;
1344 tme_uint32_t sunfb_size;
1345 tme_bus_addr_t fb_size;
1346 tme_uint32_t sunfb_p4;
1347 tme_uint8_t sunfb_s4_status;
1348 int arg_i;
1349 int usage;
1350
1351 /* check our arguments: */
1352 usage = 0;
1353 sunfb_type_string = NULL;
1354 sunfb_size_string = NULL;
1355 arg_i = 1;
1356 for (;;) {
1357
1358 /* the framebuffer type: */
1359 if (TME_ARG_IS(args[arg_i + 0], "type")
1360 && sunfb_type_string == NULL
1361 && sunfb->tme_sunfb_type_set != NULL) {
1362 sunfb_type_string = args[arg_i + 1];
1363 if (sunfb_type_string == NULL
1364 || (*sunfb->tme_sunfb_type_set)(sunfb, sunfb_type_string) != NULL) {
1365 usage = TRUE;
1366 break;
1367 }
1368 arg_i += 2;
1369 }
1370
1371 /* the framebuffer size: */
1372 else if (TME_ARG_IS(args[arg_i + 0], "size")
1373 && sunfb_size_string == NULL) {
1374 sunfb_size_string = args[arg_i + 1];
1375 if (sunfb_size_string == NULL) {
1376 usage = TRUE;
1377 break;
1378 }
1379 arg_i += 2;
1380 }
1381
1382 /* if we ran out of arguments: */
1383 else if (args[arg_i] == NULL) {
1384
1385 break;
1386 }
1387
1388 /* otherwise this is a bad argument: */
1389 else {
1390 tme_output_append_error(_output,
1391 "%s %s, ",
1392 args[arg_i],
1393 _("unexpected"));
1394 usage = TRUE;
1395 break;
1396 }
1397 }
1398
1399 /* set some common defaults based on framebuffer type: */
1400
1401 /* if this is a P4 framebuffer: */
1402 if (_TME_SUNFB_IS_P4(sunfb)) {
1403
1404 /* default possible P4 sizes: */
1405 if (sunfb->tme_sunfb_size == 0) {
1406 sunfb->tme_sunfb_size
1407 = (TME_SUNFB_SIZE_1600_1280
1408 | TME_SUNFB_SIZE_1152_900
1409 | TME_SUNFB_SIZE_1024_1024
1410 | TME_SUNFB_SIZE_1280_1024
1411 | TME_SUNFB_SIZE_1440_1440);
1412 }
1413
1414 /* the memory address can't be zero: */
1415 assert (sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first != 0);
1416
1417 /* the P4 register is always at the same offset: */
1418 sunfb->tme_sunfb_bus_subregion_regs.tme_bus_subregion_address_first = TME_SUNFB_P4_OFFSET_P4;
1419
1420 /* the default size of the P4 register bus subregion: */
1421 if (sunfb->tme_sunfb_bus_subregion_regs.tme_bus_subregion_address_last == 0) {
1422 sunfb->tme_sunfb_bus_subregion_regs.tme_bus_subregion_address_last
1423 = (sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first
1424 - 1);
1425 }
1426 }
1427
1428
1429 /* if this is an S4 framebuffer: */
1430 if (_TME_SUNFB_IS_S4(sunfb)) {
1431
1432 /* default possible S4 framebuffer sizes: */
1433 if (sunfb->tme_sunfb_size == 0) {
1434 sunfb->tme_sunfb_size
1435 = (TME_SUNFB_SIZE_1024_768
1436 | TME_SUNFB_SIZE_1152_900
1437 | TME_SUNFB_SIZE_1280_1024
1438 | TME_SUNFB_SIZE_1600_1280);
1439 }
1440
1441 /* the default memory address: */
1442 if (sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first == 0) {
1443 sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first = TME_SUNFB_S4_OFFSET_MEMORY;
1444 }
1445
1446 /* the S4 registers are always at the same offset: */
1447 sunfb->tme_sunfb_bus_subregion_regs.tme_bus_subregion_address_first = TME_SUNFB_S4_OFFSET_REGS;
1448
1449 /* the default size of the S4 register bus subregion: */
1450 if (sunfb->tme_sunfb_bus_subregion_regs.tme_bus_subregion_address_last == 0) {
1451 sunfb->tme_sunfb_bus_subregion_regs.tme_bus_subregion_address_last
1452 = (sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first
1453 - 1);
1454 }
1455 }
1456
1457 /* we must have some possible sizes: */
1458 assert (sunfb->tme_sunfb_size != 0 || usage);
1459
1460 /* if no specific size is given: */
1461 if (sunfb_size_string == NULL) {
1462
1463 /* use the first size supported by this framebuffer, which will
1464 usually be 1152x900: */
1465 sunfb_size = sunfb->tme_sunfb_size;
1466 sunfb_size = (sunfb_size & ~(sunfb_size - 1));
1467 }
1468
1469 /* otherwise, convert the specific size: */
1470 else {
1471 sunfb_size = tme_sunfb_size(sunfb_size_string);
1472 }
1473
1474 /* if the size is not supported by this framebuffer: */
1475 if ((sunfb->tme_sunfb_size & sunfb_size) == 0) {
1476 usage = TRUE;
1477 }
1478
1479 if (usage) {
1480
1481 /* start the usage message: */
1482 tme_output_append_error(_output,
1483 "%s %s",
1484 _("usage"),
1485 args[0]);
1486
1487 /* if this framebuffer has types, append a type argument to the
1488 usage message: */
1489 if (sunfb->tme_sunfb_type_set != NULL) {
1490 sunfb_type_string = (*sunfb->tme_sunfb_type_set)(sunfb, NULL);
1491 tme_output_append_error(_output, " type { %s }", sunfb_type_string);
1492 }
1493
1494 /* append the supported types to the usage message: */
1495 tme_output_append_error(_output,
1496 " [ size {");
1497 for (sunfb_size = sunfb->tme_sunfb_size;
1498 sunfb_size != 0;
1499 sunfb_size &= (sunfb_size - 1)) {
1500 switch (sunfb_size & ~(sunfb_size - 1)) {
1501 default: assert(FALSE);
1502 case TME_SUNFB_SIZE_1152_900: sunfb_size_string = "1152x900"; break;
1503 case TME_SUNFB_SIZE_1024_1024: sunfb_size_string = "1024x1024"; break;
1504 case TME_SUNFB_SIZE_1280_1024: sunfb_size_string = "1280x1024"; break;
1505 case TME_SUNFB_SIZE_1600_1280: sunfb_size_string = "1600x1280"; break;
1506 case TME_SUNFB_SIZE_1440_1440: sunfb_size_string = "1440x1440"; break;
1507 case TME_SUNFB_SIZE_1024_768: sunfb_size_string = "1024x768"; break;
1508 case TME_SUNFB_SIZE_640_480: sunfb_size_string = "640x480"; break;
1509 }
1510 tme_output_append_error(_output, " %s", sunfb_size_string);
1511 }
1512 tme_output_append_error(_output, " } ]");
1513
1514 /* return the error: */
1515 return (EINVAL);
1516 }
1517
1518 /* finish initializing the sunfb structure: */
1519 tme_mutex_init(&sunfb->tme_sunfb_mutex);
1520 tme_rwlock_init(&sunfb->tme_sunfb_rwlock);
1521
1522 /* set the size: */
1523 sunfb->tme_sunfb_size = sunfb_size;
1524
1525 /* calculate the number of bytes of displayed framebuffer memory: */
1526 fb_size = tme_sunfb_size_width(sunfb->tme_sunfb_size);
1527 fb_size *= tme_sunfb_size_height(sunfb->tme_sunfb_size);
1528 if (_TME_SUNFB_IS_BWTWO(sunfb)) {
1529 fb_size /= 8;
1530 }
1531
1532 /* set the (relative) bus address of the last byte of displayed
1533 memory: */
1534 sunfb->tme_sunfb_memory_address_last_displayed
1535 = (sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first
1536 + fb_size
1537 - 1);
1538
1539 /* assume that the real number of bytes of memory is the number of
1540 bytes displayed, rounded up to the nearest power of two: */
1541 if ((fb_size & (fb_size - 1)) != 0) {
1542 for (; (fb_size & (fb_size - 1)) != 0; fb_size &= (fb_size - 1));
1543 fb_size <<= 1;
1544 }
1545
1546 /* set the (relative) bus address of the last byte of memory: */
1547 sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_last
1548 = (sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first
1549 + fb_size
1550 - 1);
1551
1552 /* if we need to, allocate pad (undisplayed) framebuffer memory: */
1553 if (sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_last
1554 > sunfb->tme_sunfb_memory_address_last_displayed) {
1555
1556 /* allocate the pad memory: */
1557 sunfb->tme_sunfb_memory_pad
1558 = tme_new0(tme_uint8_t,
1559 (sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_last
1560 - sunfb->tme_sunfb_memory_address_last_displayed));
1561 }
1562
1563 /* if this is a P4 framebuffer: */
1564 if (_TME_SUNFB_IS_P4(sunfb)) {
1565
1566 /* get our initial P4 register: */
1567 sunfb_p4 = tme_betoh_u32(sunfb->tme_sunfb_p4);
1568
1569 /* if the P4 register doesn't already have something in the size
1570 field, add it: */
1571 if ((sunfb_p4 & TME_SUNFB_P4_SIZE_MASK) == 0) {
1572 switch (sunfb_size) {
1573 default: assert(FALSE);
1574 case TME_SUNFB_SIZE_1152_900: sunfb_p4 |= TME_SUNFB_P4_SIZE_1152_900; break;
1575 case TME_SUNFB_SIZE_1024_1024: sunfb_p4 |= TME_SUNFB_P4_SIZE_1024_1024; break;
1576 case TME_SUNFB_SIZE_1280_1024: sunfb_p4 |= TME_SUNFB_P4_SIZE_1280_1024; break;
1577 case TME_SUNFB_SIZE_1600_1280: sunfb_p4 |= TME_SUNFB_P4_SIZE_1600_1280; break;
1578 case TME_SUNFB_SIZE_1440_1440: sunfb_p4 |= TME_SUNFB_P4_SIZE_1440_1440; break;
1579 case TME_SUNFB_SIZE_640_480: sunfb_p4 |= TME_SUNFB_P4_SIZE_640_480; break;
1580 }
1581 }
1582
1583 /* set video as enabled: */
1584 sunfb_p4 |= TME_SUNFB_P4_REG_VIDEO_ENABLE;
1585
1586 /* set the initial P4 register: */
1587 sunfb->tme_sunfb_p4 = tme_htobe_u32(sunfb_p4);
1588 }
1589
1590 /* if this is an S4 framebuffer: */
1591 if (_TME_SUNFB_IS_S4(sunfb)) {
1592
1593 /* set the initial S4 control register: */
1594 sunfb->tme_sunfb_s4_regs.tme_sunfb_s4_regs_control
1595 = (TME_SUNFB_S4_CONTROL_VIDEO_ENABLE);
1596
1597 /* set the initial S4 status register: */
1598 switch (sunfb_size) {
1599 default: assert(FALSE);
1600 case TME_SUNFB_SIZE_1152_900: sunfb_s4_status = TME_SUNFB_S4_STATUS_SIZE_1152_900; break;
1601 case TME_SUNFB_SIZE_1024_768: sunfb_s4_status = TME_SUNFB_S4_STATUS_SIZE_1024_768; break;
1602 case TME_SUNFB_SIZE_1280_1024: sunfb_s4_status = TME_SUNFB_S4_STATUS_SIZE_1280_1024; break;
1603 case TME_SUNFB_SIZE_1600_1280: sunfb_s4_status = TME_SUNFB_S4_STATUS_SIZE_1600_1280; break;
1604 }
1605 sunfb->tme_sunfb_s4_regs.tme_sunfb_s4_regs_status
1606 = (sunfb_s4_status
1607 | (_TME_SUNFB_IS_BWTWO(sunfb)
1608 ? TME_SUNFB_S4_STATUS_ID_MONO
1609 : TME_SUNFB_S4_STATUS_ID_COLOR));
1610 }
1611
1612 /* make sure that the interrupt signal has been defined. no known
1613 framebuffer uses a priority zero interrupt: */
1614 #if TME_BUS_SIGNAL_INT(0) != 0
1615 #error "TME_BUS_SIGNAL_INT() changed"
1616 #endif
1617 assert (sunfb->tme_sunfb_bus_signal_int != TME_BUS_SIGNAL_INT(0));
1618
1619 /* if this is a color framebuffer: */
1620 if (!_TME_SUNFB_IS_BWTWO(sunfb)) {
1621
1622 /* if we don't have a specific memory update function, use the
1623 default: */
1624 if (sunfb->tme_sunfb_memory_update == NULL) {
1625 sunfb->tme_sunfb_memory_update = tme_sunfb_memory_update;
1626 }
1627 }
1628
1629 /* make all of the defined subregions into a list. the memory
1630 subregion is always in the list, and it is first: */
1631 _subregion_prev = &sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_next;
1632 for (subregion_i = 0;
1633 subregion_i < TME_SUNFB_BUS_SUBREGIONS_MAX;
1634 subregion_i++) {
1635 if (sunfb->tme_sunfb_bus_handlers[subregion_i] != NULL) {
1636 subregion = &sunfb->tme_sunfb_bus_subregions[subregion_i];
1637 *_subregion_prev = subregion;
1638 _subregion_prev = &subregion->tme_bus_subregion_next;
1639 }
1640 }
1641 *_subregion_prev = NULL;
1642
1643 /* initialize our simple bus device descriptor: */
1644 sunfb->tme_sunfb_device.tme_bus_device_tlb_fill = _tme_sunfb_tlb_fill;
1645
1646 /* fill the element: */
1647 sunfb->tme_sunfb_element->tme_element_private = sunfb;
1648 sunfb->tme_sunfb_element->tme_element_connections_new = _tme_sunfb_connections_new;
1649
1650 /* initialize the timeout thread condition: */
1651 tme_cond_init(&sunfb->tme_sunfb_callout_cond);
1652
1653 /* start the callout thread: */
1654 tme_thread_create((tme_thread_t) _tme_sunfb_callout_thread, sunfb);
1655
1656 return (TME_OK);
1657 }
1658
1659 /* the new sun cgthree function: */
1660 int
tme_sun_cgthree(struct tme_element * element,const char * const * args,char ** _output)1661 tme_sun_cgthree(struct tme_element *element, const char * const *args, char **_output)
1662 {
1663 struct tme_sunfb *sunfb;
1664 tme_uint8_t *cmap;
1665 int rc;
1666
1667 /* start the sunfb structure: */
1668 sunfb = tme_new0(struct tme_sunfb, 1);
1669 sunfb->tme_sunfb_element = element;
1670
1671 /* initialize the sunfb structure: */
1672 sunfb->tme_sunfb_class = TME_FB_XLAT_CLASS_COLOR;
1673 sunfb->tme_sunfb_depth = 8;
1674 sunfb->tme_sunfb_bus_handler_regs = tme_sunfb_bus_cycle_s4;
1675 sunfb->tme_sunfb_flags
1676 |= (TME_SUNFB_FLAG_BT458_CMAP_PACKED
1677 | TME_SUNFB_FLAG_BT458_BYTE_D0_D7);
1678 sunfb->tme_sunfb_bus_signal_int = TME_BUS_SIGNAL_INT(5);
1679
1680 /* if the generic initialization fails: */
1681 rc = tme_sunfb_new(sunfb, args, _output);
1682 if (rc) {
1683
1684 /* free the sunfb structure and return the error: */
1685 tme_free(sunfb);
1686 return (rc);
1687 }
1688
1689 /* allocate the colormap arrays: */
1690 cmap = tme_new0(tme_uint8_t, 256 * 3);
1691 sunfb->tme_sunfb_cmap_g = &cmap[256 * 0];
1692 sunfb->tme_sunfb_cmap_r = &cmap[256 * 1];
1693 sunfb->tme_sunfb_cmap_b = &cmap[256 * 2];
1694 sunfb->tme_sunfb_bt458.tme_bt458_cmap_g = sunfb->tme_sunfb_cmap_g;
1695 sunfb->tme_sunfb_bt458.tme_bt458_cmap_r = sunfb->tme_sunfb_cmap_r;
1696 sunfb->tme_sunfb_bt458.tme_bt458_cmap_b = sunfb->tme_sunfb_cmap_b;
1697
1698 return (TME_OK);
1699 }
1700