1 /* $Id: sun-cgsix.c,v 1.3 2010/06/05 19:16:12 fredette Exp $ */
2 
3 /* machine/sun/sun-cgsix.c - Sun cgsix emulation: */
4 
5 /*
6  * Copyright (c) 2009 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-cgsix.c,v 1.3 2010/06/05 19:16:12 fredette Exp $");
38 
39 /* includes: */
40 #include <tme/machine/sun.h>
41 #include <tme/generic/bus-device.h>
42 #include <tme/generic/fb.h>
43 #include "sun-fb.h"
44 
45 /* macros: */
46 
47 /* cgsix types: */
48 #define TME_SUNCG6_TYPE_NULL		(0)
49 #define TME_SUNCG6_TYPE_501_2325	(1)
50 
51 /* register subregions: */
52 #define tme_suncg6_bus_subregion_p4 tme_suncg6_sunfb.tme_sunfb_bus_subregion_regs
53 #define tme_suncg6_bus_handler_p4 tme_suncg6_sunfb.tme_sunfb_bus_handler_regs
54 #define tme_suncg6_bus_subregion_fbc tme_suncg6_sunfb.tme_sunfb_bus_subregions[1]
55 #define tme_suncg6_bus_handler_fbc tme_suncg6_sunfb.tme_sunfb_bus_handlers[1]
56 #define tme_suncg6_bus_subregion_dac tme_suncg6_sunfb.tme_sunfb_bus_subregions[2]
57 #define tme_suncg6_bus_handler_dac tme_suncg6_sunfb.tme_sunfb_bus_handlers[2]
58 #define tme_suncg6_bus_subregion_fhc_thc tme_suncg6_sunfb.tme_sunfb_bus_subregions[4]
59 #define tme_suncg6_bus_handler_fhc_thc tme_suncg6_sunfb.tme_sunfb_bus_handlers[4]
60 #define tme_suncg6_bus_subregion_tec tme_suncg6_sunfb.tme_sunfb_bus_subregions[3]
61 #define tme_suncg6_bus_handler_tec tme_suncg6_sunfb.tme_sunfb_bus_handlers[3]
62 #define tme_suncg6_bus_subregion_alt tme_suncg6_sunfb.tme_sunfb_bus_subregions[6]
63 #define tme_suncg6_bus_handler_alt tme_suncg6_sunfb.tme_sunfb_bus_handlers[6]
64 
65 /* this converts a group member to a register offset: */
66 #define _TME_SUNCG6_REG_X(module_cap, module, n, x)		\
67   (_TME_CONCAT4(TME_SUNCG6_REG_,module_cap,_GROUP,n)		\
68    + ((tme_uint8_t *) &((struct tme_suncg6 *) 0)		\
69       ->_TME_CONCAT4(tme_suncg6_,module,_group,n)		\
70       ._TME_CONCAT4(tme_suncg6_,module,_,x))			\
71    - ((tme_uint8_t *) &((struct tme_suncg6 *) 0)		\
72       ->_TME_CONCAT4(tme_suncg6_,module,_group,n)))
73 
74 /* this expands part of a large ternary expression that converts a
75    register address into pointer to a register: */
76 #define TME_SUNCG6_REG_POINTER(suncg6, reg, module_cap, module, n)\
77   (((reg)							\
78     >= _TME_CONCAT4(TME_SUNCG6_REG_,module_cap,_GROUP,n))	\
79    && ((reg)							\
80        < (_TME_CONCAT4(TME_SUNCG6_REG_,module_cap,_GROUP,n)	\
81 	  + sizeof((suncg6)					\
82 		   ->_TME_CONCAT4(tme_suncg6_,module,_group,n)))))\
83   ? (((tme_suncg6_reg_t *)					\
84       &((suncg6)						\
85 	->_TME_CONCAT4(tme_suncg6_,module,_group,n)))		\
86      + (((reg)							\
87 	 - _TME_CONCAT4(TME_SUNCG6_REG_,module_cap,_GROUP,n))	\
88 	/ sizeof(tme_suncg6_reg_t)))
89 
90 /* some register offsets and sizes: */
91 #define TME_SUNCG6_REG_DAC			(0x200000)
92 #define TME_SUNCG6_REG_ALT			(0x280000)
93 #define TME_SUNCG6_SIZ_ALT			(0x1000)
94 #define TME_SUNCG6_REG_THC(n,x)			_TME_SUNCG6_REG_X(THC,thc,n,x)
95 #define TME_SUNCG6_SIZ_THC			(0x1000)
96 #define TME_SUNCG6_REG_FBC(n,x)			_TME_SUNCG6_REG_X(FBC,fbc,n,x)
97 #define TME_SUNCG6_REG_TEC(n,x)			_TME_SUNCG6_REG_X(TEC,tec,n,x)
98 #define TME_SUNCG6_TEC_SIZE			(0x1000)
99 
100 /* the FHC register: */
101 #define	TME_SUNCG6_FHC_ID_MASK			(0xff000000)
102 #define	TME_SUNCG6_FHC_REVISION_MASK		(0x00f00000)
103 #define	TME_SUNCG6_FHC_DISABLE_FROP		(0x00080000)
104 #define	TME_SUNCG6_FHC_DISABLE_ROW		(0x00040000)
105 #define	TME_SUNCG6_FHC_DISABLE_SRC		(0x00020000)
106 #define	TME_SUNCG6_FHC_DISABLE_DST		(0x00010000)
107 #define	TME_SUNCG6_FHC_RESET			(0x00008000)
108 #define	TME_SUNCG6_FHC_ENDIAN_LITTLE		(0x00002000)
109 #define	TME_SUNCG6_FHC_SIZE_MASK		(0x00001800)
110 #define	 TME_SUNCG6_FHC_SIZE_1024_768		 (0x00000000)
111 #define	 TME_SUNCG6_FHC_SIZE_1152_900		 (0x00000800)
112 #define	 TME_SUNCG6_FHC_SIZE_1280_1024		 (0x00001000)
113 #define	 TME_SUNCG6_FHC_SIZE_1600_1280		 (0x00001800)
114 #define	TME_SUNCG6_FHC_CPU_MASK			(0x00000600)
115 #define	 TME_SUNCG6_FHC_CPU_SPARC		 (0x00000000)
116 #define	 TME_SUNCG6_FHC_CPU_68K			 (0x00000200)
117 #define	 TME_SUNCG6_FHC_CPU_IA32		 (0x00000400)
118 #define	TME_SUNCG6_FHC_TEST			(0x00000100)
119 #define	TME_SUNCG6_FHC_TESTX_MASK		(0x000000f0)
120 #define	TME_SUNCG6_FHC_TESTY_MASK		(0x0000000f)
121 
122 /* the THC miscellaneous register: */
123 #define	TME_SUNCG6_THC_MISC_UNKNOWN_20		(0xfff00000)
124 #define	TME_SUNCG6_THC_MISC_REVISION_MASK	(0x000f0000)
125 #define	TME_SUNCG6_THC_MISC_UNKNOWN_13		(0x0000e000)
126 #define	TME_SUNCG6_THC_MISC_RESET		(0x00001000)
127 #define	TME_SUNCG6_THC_MISC_UNKNOWN_11		(0x00000800)
128 #define	TME_SUNCG6_THC_MISC_ENABLE_VIDEO	(0x00000400)
129 #define	TME_SUNCG6_THC_MISC_SYNC		(0x00000200)
130 #define	TME_SUNCG6_THC_MISC_VSYNC		(0x00000100)
131 #define	TME_SUNCG6_THC_MISC_ENABLE_SYNC		(0x00000080)
132 #define	TME_SUNCG6_THC_MISC_CURSOR_RESOLUTION	(0x00000040)
133 #define	TME_SUNCG6_THC_MISC_INT_ENABLE		(0x00000020)
134 #define	TME_SUNCG6_THC_MISC_INT_ACTIVE		(0x00000010)
135 #define	TME_SUNCG6_THC_MISC_UNKNOWN_0		(0x0000000f)
136 
137 /* the FBC rasterop register: */
138 #define TME_SUNCG6_FBC_RASTEROP_PLANE_ONES	(0x80000000)
139 #define TME_SUNCG6_FBC_RASTEROP_PLANE_ZEROES	(0x40000000)
140 #define TME_SUNCG6_FBC_RASTEROP_PIXEL_ONES	(0x20000000)
141 #define TME_SUNCG6_FBC_RASTEROP_PIXEL_ZEROES	(0x10000000)
142 #define TME_SUNCG6_FBC_RASTEROP_PATTERN_ONES	(0x08000000)
143 #define TME_SUNCG6_FBC_RASTEROP_PATTERN_ZEROES	(0x04000000)
144 #define TME_SUNCG6_FBC_RASTEROP_POLYG_NONOVERLAP (0x02000000)
145 #define TME_SUNCG6_FBC_RASTEROP_POLYG_OVERLAP	(0x01000000)
146 #define TME_SUNCG6_FBC_RASTEROP_ATTR_SUPP	(0x00800000)
147 #define TME_SUNCG6_FBC_RASTEROP_ATTR_UNSUPP	(0x00400000)
148 #define TME_SUNCG6_FBC_RASTEROP_RAST_BOOL	(0x00000000)
149 #define TME_SUNCG6_FBC_RASTEROP_RAST_LINEAR	(0x00020000)
150 #define TME_SUNCG6_FBC_RASTEROP_PLOT_PLOT	(0x00000000)
151 #define TME_SUNCG6_FBC_RASTEROP_PLOT_UNPLOT	(0x00010000)
152 #define TME_SUNCG6_FBC_RASTEROP_ROP_11_1(x)	((x) << 14)
153 #define TME_SUNCG6_FBC_RASTEROP_ROP_11_0(x)	((x) << 12)
154 #define TME_SUNCG6_FBC_RASTEROP_ROP_10_1(x)	((x) << 10)
155 #define TME_SUNCG6_FBC_RASTEROP_ROP_10_0(x)	((x) <<  8)
156 #define TME_SUNCG6_FBC_RASTEROP_ROP_01_1(x)	((x) <<  6)
157 #define TME_SUNCG6_FBC_RASTEROP_ROP_01_0(x)	((x) <<  4)
158 #define TME_SUNCG6_FBC_RASTEROP_ROP_00_1(x)	((x) <<  2)
159 #define TME_SUNCG6_FBC_RASTEROP_ROP_00_0(x)	((x) <<  0)
160 #define  TME_SUNCG6_FBC_RASTEROP_ROP_CLEAR	 (0x0)
161 #define  TME_SUNCG6_FBC_RASTEROP_ROP_INVERT	 (0x1)
162 #define  TME_SUNCG6_FBC_RASTEROP_ROP_NOP	 (0x2)
163 #define  TME_SUNCG6_FBC_RASTEROP_ROP_SET	 (0x3)
164 
165 /* common FBC rasterop functions: */
166 
167 /* copy: */
168 #define TME_SUNCG6_FBC_RASTEROP_FUNC_COPY					\
169   (TME_SUNCG6_FBC_RASTEROP_PLANE_ONES						\
170    | TME_SUNCG6_FBC_RASTEROP_PIXEL_ONES						\
171    | TME_SUNCG6_FBC_RASTEROP_PATTERN_ONES					\
172    | TME_SUNCG6_FBC_RASTEROP_POLYG_OVERLAP					\
173    | TME_SUNCG6_FBC_RASTEROP_ATTR_SUPP						\
174    | TME_SUNCG6_FBC_RASTEROP_ROP_11_1(TME_SUNCG6_FBC_RASTEROP_ROP_SET)		\
175    | TME_SUNCG6_FBC_RASTEROP_ROP_11_0(TME_SUNCG6_FBC_RASTEROP_ROP_CLEAR)	\
176    | TME_SUNCG6_FBC_RASTEROP_ROP_10_1(TME_SUNCG6_FBC_RASTEROP_ROP_SET)		\
177    | TME_SUNCG6_FBC_RASTEROP_ROP_10_0(TME_SUNCG6_FBC_RASTEROP_ROP_CLEAR)	\
178    | TME_SUNCG6_FBC_RASTEROP_ROP_01_1(TME_SUNCG6_FBC_RASTEROP_ROP_SET)		\
179    | TME_SUNCG6_FBC_RASTEROP_ROP_01_0(TME_SUNCG6_FBC_RASTEROP_ROP_CLEAR)	\
180    | TME_SUNCG6_FBC_RASTEROP_ROP_00_1(TME_SUNCG6_FBC_RASTEROP_ROP_SET)		\
181    | TME_SUNCG6_FBC_RASTEROP_ROP_00_0(TME_SUNCG6_FBC_RASTEROP_ROP_CLEAR))
182 
183 /* fill: */
184 #define TME_SUNCG6_FBC_RASTEROP_FUNC_FILL					\
185   (TME_SUNCG6_FBC_RASTEROP_PLANE_ONES						\
186    | TME_SUNCG6_FBC_RASTEROP_PIXEL_ONES						\
187    | TME_SUNCG6_FBC_RASTEROP_PATTERN_ONES					\
188    | TME_SUNCG6_FBC_RASTEROP_POLYG_OVERLAP					\
189    | TME_SUNCG6_FBC_RASTEROP_ATTR_SUPP						\
190    | TME_SUNCG6_FBC_RASTEROP_ROP_11_1(TME_SUNCG6_FBC_RASTEROP_ROP_SET)		\
191    | TME_SUNCG6_FBC_RASTEROP_ROP_11_0(TME_SUNCG6_FBC_RASTEROP_ROP_SET)		\
192    | TME_SUNCG6_FBC_RASTEROP_ROP_10_1(TME_SUNCG6_FBC_RASTEROP_ROP_SET)		\
193    | TME_SUNCG6_FBC_RASTEROP_ROP_10_0(TME_SUNCG6_FBC_RASTEROP_ROP_SET)		\
194    | TME_SUNCG6_FBC_RASTEROP_ROP_01_1(TME_SUNCG6_FBC_RASTEROP_ROP_CLEAR)	\
195    | TME_SUNCG6_FBC_RASTEROP_ROP_01_0(TME_SUNCG6_FBC_RASTEROP_ROP_CLEAR)	\
196    | TME_SUNCG6_FBC_RASTEROP_ROP_00_1(TME_SUNCG6_FBC_RASTEROP_ROP_CLEAR)	\
197    | TME_SUNCG6_FBC_RASTEROP_ROP_00_0(TME_SUNCG6_FBC_RASTEROP_ROP_CLEAR))
198 
199 /* flip: */
200 #define TME_SUNCG6_FBC_RASTEROP_FUNC_FLIP					\
201   (TME_SUNCG6_FBC_RASTEROP_PLANE_ONES						\
202    | TME_SUNCG6_FBC_RASTEROP_PIXEL_ONES						\
203    | TME_SUNCG6_FBC_RASTEROP_PATTERN_ONES					\
204    | TME_SUNCG6_FBC_RASTEROP_POLYG_OVERLAP					\
205    | TME_SUNCG6_FBC_RASTEROP_ATTR_SUPP						\
206    | TME_SUNCG6_FBC_RASTEROP_ROP_11_1(TME_SUNCG6_FBC_RASTEROP_ROP_INVERT)	\
207    | TME_SUNCG6_FBC_RASTEROP_ROP_11_0(TME_SUNCG6_FBC_RASTEROP_ROP_INVERT)	\
208    | TME_SUNCG6_FBC_RASTEROP_ROP_10_1(TME_SUNCG6_FBC_RASTEROP_ROP_INVERT)	\
209    | TME_SUNCG6_FBC_RASTEROP_ROP_10_0(TME_SUNCG6_FBC_RASTEROP_ROP_INVERT)	\
210    | TME_SUNCG6_FBC_RASTEROP_ROP_01_1(TME_SUNCG6_FBC_RASTEROP_ROP_INVERT)	\
211    | TME_SUNCG6_FBC_RASTEROP_ROP_01_0(TME_SUNCG6_FBC_RASTEROP_ROP_INVERT)	\
212    | TME_SUNCG6_FBC_RASTEROP_ROP_00_1(TME_SUNCG6_FBC_RASTEROP_ROP_INVERT)	\
213    | TME_SUNCG6_FBC_RASTEROP_ROP_00_0(TME_SUNCG6_FBC_RASTEROP_ROP_INVERT))
214 
215 /* NB: I couldn't reason out how the rop?? values work.  the values
216    used by X11 and the NetBSD cgsix driver make some sense, but the
217    0x6c60 used by the SUNW,501-2325 PROM for all of its blits and
218    draws is confusing: */
219 #define TME_SUNCG6_FBC_RASTEROP_FUNC_PROM					\
220   (TME_SUNCG6_FBC_RASTEROP_PLANE_ONES						\
221    | TME_SUNCG6_FBC_RASTEROP_PIXEL_ONES						\
222    | TME_SUNCG6_FBC_RASTEROP_PATTERN_ONES					\
223    | TME_SUNCG6_FBC_RASTEROP_POLYG_OVERLAP					\
224    | TME_SUNCG6_FBC_RASTEROP_ATTR_SUPP						\
225    | TME_SUNCG6_FBC_RASTEROP_ROP_11_1(TME_SUNCG6_FBC_RASTEROP_ROP_INVERT)	\
226    | TME_SUNCG6_FBC_RASTEROP_ROP_11_0(TME_SUNCG6_FBC_RASTEROP_ROP_NOP)		\
227    | TME_SUNCG6_FBC_RASTEROP_ROP_10_1(TME_SUNCG6_FBC_RASTEROP_ROP_SET)		\
228    | TME_SUNCG6_FBC_RASTEROP_ROP_10_0(TME_SUNCG6_FBC_RASTEROP_ROP_CLEAR)	\
229    | TME_SUNCG6_FBC_RASTEROP_ROP_01_1(TME_SUNCG6_FBC_RASTEROP_ROP_INVERT)	\
230    | TME_SUNCG6_FBC_RASTEROP_ROP_01_0(TME_SUNCG6_FBC_RASTEROP_ROP_NOP)		\
231    | TME_SUNCG6_FBC_RASTEROP_ROP_00_1(TME_SUNCG6_FBC_RASTEROP_ROP_CLEAR)	\
232    | TME_SUNCG6_FBC_RASTEROP_ROP_00_0(TME_SUNCG6_FBC_RASTEROP_ROP_CLEAR))
233 
234 /* types: */
235 
236 /* the cgsix pixel is eight bits: */
237 typedef tme_uint8_t tme_suncg6_pixel_t;
238 
239 /* all cgsix registers are at least 32-bit aligned: */
240 typedef tme_uint32_t tme_suncg6_reg_t;
241 
242 /* the card: */
243 struct tme_suncg6 {
244 
245   /* our generic Sun framebuffer: */
246   struct tme_sunfb tme_suncg6_sunfb;
247 #define tme_suncg6_mutex tme_suncg6_sunfb.tme_sunfb_mutex
248 #define tme_suncg6_bus_subregion_memory tme_suncg6_sunfb.tme_sunfb_bus_subregion_memory
249 #define tme_suncg6_bus_subregion_regs tme_suncg6_sunfb.tme_sunfb_bus_subregion_regs
250 
251   /* the type of the cgsix: */
252   tme_uint32_t tme_suncg6_type;
253 
254   /* the current framebuffer width and height: */
255   tme_uint32_t tme_suncg6_width;
256   tme_uint32_t tme_suncg6_height;
257 
258   /* the FHC: */
259 #define TME_SUNCG6_REG_FHC			(0x300000)
260   tme_suncg6_reg_t tme_suncg6_fhc;
261 
262   /* the THC: */
263 #define TME_SUNCG6_REG_THC_UNKNOWN_0x0		(0x301000)
264   struct {
265 #define TME_SUNCG6_REG_THC_GROUP0		(0x301090)
266     tme_suncg6_reg_t tme_suncg6_thc_unknown_0x90;
267     tme_suncg6_reg_t tme_suncg6_thc_unknown_0x94;
268   } tme_suncg6_thc_group0;
269   struct {
270 #define TME_SUNCG6_REG_THC_GROUP1		(0x301800)
271     tme_suncg6_reg_t tme_suncg6_thc_hsync1;
272     tme_suncg6_reg_t tme_suncg6_thc_hsync2;
273     tme_suncg6_reg_t tme_suncg6_thc_hsync3;
274     tme_suncg6_reg_t tme_suncg6_thc_vsync1;
275     tme_suncg6_reg_t tme_suncg6_thc_vsync2;
276     tme_suncg6_reg_t tme_suncg6_thc_refresh;
277     tme_suncg6_reg_t tme_suncg6_thc_misc;
278     tme_suncg6_reg_t tme_suncg6_thc_unknown_0x81c[56];
279     tme_suncg6_reg_t tme_suncg6_thc_cursor_xy;
280     tme_suncg6_reg_t tme_suncg6_thc_cursor_mask[32];
281     tme_suncg6_reg_t tme_suncg6_thc_cursor_bits[32];
282   } tme_suncg6_thc_group1;
283 
284   /* the FBC: */
285   struct {
286 #define TME_SUNCG6_REG_FBC_GROUP0		(0x700000)
287     tme_suncg6_reg_t tme_suncg6_fbc_unknown_0x0;
288     tme_suncg6_reg_t tme_suncg6_fbc_misc;
289     tme_suncg6_reg_t tme_suncg6_fbc_clip_check;
290     tme_suncg6_reg_t tme_suncg6_fbc_unknown_0xc;
291     tme_suncg6_reg_t tme_suncg6_fbc_status;
292     tme_suncg6_reg_t tme_suncg6_fbc_status_draw;
293     tme_suncg6_reg_t tme_suncg6_fbc_status_blit;
294     tme_suncg6_reg_t tme_suncg6_fbc_font;
295     tme_suncg6_reg_t tme_suncg6_fbc_unknown_0x20[24];
296     tme_suncg6_reg_t tme_suncg6_fbc_x0;
297     tme_suncg6_reg_t tme_suncg6_fbc_y0;
298     tme_suncg6_reg_t tme_suncg6_fbc_z0;
299     tme_suncg6_reg_t tme_suncg6_fbc_color0;
300     tme_suncg6_reg_t tme_suncg6_fbc_x1;
301     tme_suncg6_reg_t tme_suncg6_fbc_y1;
302     tme_suncg6_reg_t tme_suncg6_fbc_z1;
303     tme_suncg6_reg_t tme_suncg6_fbc_color1;
304     tme_suncg6_reg_t tme_suncg6_fbc_x2;
305     tme_suncg6_reg_t tme_suncg6_fbc_y2;
306     tme_suncg6_reg_t tme_suncg6_fbc_z2;
307     tme_suncg6_reg_t tme_suncg6_fbc_color2;
308     tme_suncg6_reg_t tme_suncg6_fbc_x3;
309     tme_suncg6_reg_t tme_suncg6_fbc_y3;
310     tme_suncg6_reg_t tme_suncg6_fbc_z3;
311     tme_suncg6_reg_t tme_suncg6_fbc_color3;
312     tme_suncg6_reg_t tme_suncg6_fbc_offx;
313     tme_suncg6_reg_t tme_suncg6_fbc_offy;
314     tme_suncg6_reg_t tme_suncg6_fbc_unknown_0xc8[2];
315     tme_suncg6_reg_t tme_suncg6_fbc_inc_x;
316     tme_suncg6_reg_t tme_suncg6_fbc_inc_y;
317     tme_suncg6_reg_t tme_suncg6_fbc_unknown_0xd8[2];
318     tme_suncg6_reg_t tme_suncg6_fbc_clip_min_x;
319     tme_suncg6_reg_t tme_suncg6_fbc_clip_min_y;
320     tme_suncg6_reg_t tme_suncg6_fbc_unknown_0xe8[2];
321     tme_suncg6_reg_t tme_suncg6_fbc_clip_max_x;
322     tme_suncg6_reg_t tme_suncg6_fbc_clip_max_y;
323     tme_suncg6_reg_t tme_suncg6_fbc_unknown_0xf8[2];
324     tme_suncg6_reg_t tme_suncg6_fbc_fg;
325     tme_suncg6_reg_t tme_suncg6_fbc_bg;
326     tme_suncg6_reg_t tme_suncg6_fbc_rasterop;
327     tme_suncg6_reg_t tme_suncg6_fbc_pm;
328     tme_suncg6_reg_t tme_suncg6_fbc_pixelm;
329     tme_suncg6_reg_t tme_suncg6_fbc_unknown_0x114[2];
330     tme_suncg6_reg_t tme_suncg6_fbc_patalign;
331     tme_suncg6_reg_t tme_suncg6_fbc_pattern[8];
332   } tme_suncg6_fbc_group0;
333   struct {
334 #define TME_SUNCG6_REG_FBC_GROUP1		(0x700900)
335     tme_suncg6_reg_t tme_suncg6_fbc_rect_abs_x;
336     tme_suncg6_reg_t tme_suncg6_fbc_rect_abs_y;
337   } tme_suncg6_fbc_group1;
338 
339   /* in the FBC, the rectangle absolute coordinate registers seem to
340      be indexed: */
341 #define TME_SUNCG6_RECT_ABS_COUNT		(2)
342   unsigned int tme_suncg6_fbc_rect_abs_x_i;
343   unsigned int tme_suncg6_fbc_rect_abs_y_i;
344   tme_suncg6_reg_t tme_suncg6_fbc_rect_abs_x[TME_SUNCG6_RECT_ABS_COUNT];
345   tme_suncg6_reg_t tme_suncg6_fbc_rect_abs_y[TME_SUNCG6_RECT_ABS_COUNT];
346 
347   /* the TEC: */
348   struct {
349 #define TME_SUNCG6_REG_TEC_GROUP0		(0x701000)
350     tme_suncg6_reg_t tme_suncg6_tec_mv;
351     tme_suncg6_reg_t tme_suncg6_tec_clip;
352     tme_suncg6_reg_t tme_suncg6_tec_vdc;
353   } tme_suncg6_tec_group0;
354 };
355 
356 /* this does a blit: */
357 static void
_tme_suncg6_blit(struct tme_suncg6 * suncg6)358 _tme_suncg6_blit(struct tme_suncg6 *suncg6)
359 {
360   tme_uint32_t fb_width;
361   tme_uint32_t fb_height;
362   tme_int32_t src_x;
363   tme_int32_t src_y;
364   tme_int32_t dst_x;
365   tme_int32_t dst_y;
366   tme_int32_t blit_width;
367   tme_int32_t blit_height;
368   int unsupported;
369   tme_uint32_t offset_updated_first;
370   tme_uint32_t offset_updated_last;
371   const tme_suncg6_pixel_t *src;
372   tme_suncg6_pixel_t *dst;
373 
374   /* get the framebuffer width and height: */
375   fb_width = suncg6->tme_suncg6_width;
376   fb_height = suncg6->tme_suncg6_height;
377 
378   /* get the blit source: */
379   src_x = suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_x0;
380   src_y = suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_y0;
381 
382   /* get the blit destination: */
383   dst_x = suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_x2;
384   dst_y = suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_y2;
385 
386   /* get the blit width and height: */
387   blit_width = suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_x1;
388   blit_width
389     = (blit_width < src_x
390        ? 0
391        : (blit_width + 1 - src_x));
392   blit_height = suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_y1;
393   blit_height
394     = (blit_height < src_y
395        ? 0
396        : (blit_height + 1 - src_y));
397 
398   /* check that this blit is supported: */
399   unsupported = FALSE;
400   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_clip_check != 0);
401   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_status != 0);
402   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_offx != 0);
403   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_offy != 0);
404   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_clip_min_x != 0);
405   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_clip_min_y != 0);
406   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_clip_max_x != (fb_width - 1));
407   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_clip_max_y != (fb_height - 1));
408   unsupported
409     |= (blit_width
410 	!= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_x3 < dst_x
411 	    ? 0
412 	    : (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_x3 + 1 - dst_x)));
413   unsupported
414     |= (blit_height
415 	!= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_y3 < dst_y
416 	    ? 0
417 	    : (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_y3 + 1 - dst_y)));
418   if (__tme_predict_false(unsupported)) {
419     tme_log(TME_SUNFB_LOG_HANDLE(&suncg6->tme_suncg6_sunfb), 0, EINVAL,
420 	    (TME_SUNFB_LOG_HANDLE(&suncg6->tme_suncg6_sunfb),
421 	     _("unsupported blit parameters")));
422     return;
423   }
424 
425   /* if any of the least coordinates aren't in the framebuffer: */
426   if (src_x >= fb_width
427       || dst_x >= fb_width
428       || src_y >= fb_height
429       || dst_y >= fb_height) {
430     return;
431   }
432 
433   /* make sure the blit height and width stay in the framebuffer: */
434   blit_width = TME_MIN(blit_width,
435 		       TME_MIN(fb_width - src_x,
436 			       fb_width - dst_x));
437   blit_height = TME_MIN(blit_height,
438 			TME_MIN(fb_height - src_y,
439 				fb_height - dst_y));
440 
441   /* if the blit height or width are zero: */
442   if (blit_width == 0
443       || blit_height == 0) {
444     return;
445   }
446 
447   /* get the offsets of the first and last bytes of the
448      destination: */
449   offset_updated_first = ((fb_width * dst_y) + dst_x);
450   offset_updated_last
451     = (offset_updated_first
452        + (blit_width - 1)
453        + (fb_width * (blit_height - 1)));
454 
455   /* get the first source and destination rows: */
456   dst = (tme_suncg6_pixel_t *) suncg6->tme_suncg6_sunfb.tme_sunfb_memory;
457   src = dst + ((fb_width * src_y) + src_x);
458   dst += offset_updated_first;
459 
460   /* if this is a copy: */
461   if (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_rasterop
462       == TME_SUNCG6_FBC_RASTEROP_FUNC_COPY
463       /* XXX FIXME - the rasterop function that the SUNW,501-2325 PROM
464 	 uses for all of its blits and draws doesn't do a copy blit,
465 	 but for now we treat it like it does: */
466       || (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_rasterop
467 	  == TME_SUNCG6_FBC_RASTEROP_FUNC_PROM)
468       ) {
469 
470     /* if the copy is full-width: */
471     if (blit_width == fb_width) {
472 
473       /* copy the source to the destination: */
474       memmove(dst,
475 	      src,
476 	      sizeof(tme_suncg6_pixel_t) * blit_width * blit_height);
477     }
478 
479     /* otherwise, the copy is not full-width: */
480     else {
481 
482       /* copy the source to the destination: */
483       do {
484 	memmove(dst,
485 		src,
486 		sizeof(tme_suncg6_pixel_t) * blit_width);
487 	dst += sizeof(tme_suncg6_pixel_t) * fb_width;
488 	src += sizeof(tme_suncg6_pixel_t) * fb_width;
489       } while (--blit_height);
490     }
491   }
492 
493   /* otherwise, this is an unsupported blit: */
494   else {
495     tme_log(TME_SUNFB_LOG_HANDLE(&suncg6->tme_suncg6_sunfb), 0, EINVAL,
496 	    (TME_SUNFB_LOG_HANDLE(&suncg6->tme_suncg6_sunfb),
497 	     _("unsupported blit function")));
498   }
499 
500   /* update the offsets of the first and last bytes updated in the
501      real framebuffer memory: */
502   offset_updated_first
503     = TME_MIN(offset_updated_first,
504 	      suncg6->tme_suncg6_sunfb.tme_sunfb_offset_updated_first);
505   offset_updated_last
506     = TME_MAX(offset_updated_last,
507 	      suncg6->tme_suncg6_sunfb.tme_sunfb_offset_updated_last);
508   suncg6->tme_suncg6_sunfb.tme_sunfb_offset_updated_first = offset_updated_first;
509   suncg6->tme_suncg6_sunfb.tme_sunfb_offset_updated_last = offset_updated_last;
510 }
511 
512 /* this does a draw: */
513 static void
_tme_suncg6_draw(struct tme_suncg6 * suncg6)514 _tme_suncg6_draw(struct tme_suncg6 *suncg6)
515 {
516   tme_uint32_t fb_width;
517   tme_uint32_t fb_height;
518   unsigned int rect_abs_i;
519   tme_int32_t draw_width;
520   tme_int32_t dst_x;
521   tme_int32_t draw_height;
522   tme_int32_t dst_y;
523   int unsupported;
524   tme_uint32_t offset_updated_first;
525   tme_uint32_t offset_updated_last;
526   tme_suncg6_pixel_t *dst;
527   tme_int32_t resid_width;
528 
529   /* get the framebuffer width and height: */
530   fb_width = suncg6->tme_suncg6_width;
531   fb_height = suncg6->tme_suncg6_height;
532 
533   /* get the draw width and destination x: */
534   rect_abs_i = suncg6->tme_suncg6_fbc_rect_abs_x_i;
535   draw_width = suncg6->tme_suncg6_fbc_rect_abs_x[rect_abs_i % TME_SUNCG6_RECT_ABS_COUNT];
536   rect_abs_i = rect_abs_i - 1;
537   dst_x = suncg6->tme_suncg6_fbc_rect_abs_x[rect_abs_i % TME_SUNCG6_RECT_ABS_COUNT];
538   draw_width
539     = (draw_width < dst_x
540        ? 0
541        : (draw_width + 1 - dst_x));
542 
543   /* get the draw height and destination y: */
544   rect_abs_i = suncg6->tme_suncg6_fbc_rect_abs_y_i;
545   draw_height = suncg6->tme_suncg6_fbc_rect_abs_y[rect_abs_i % TME_SUNCG6_RECT_ABS_COUNT];
546   rect_abs_i = rect_abs_i - 1;
547   dst_y = suncg6->tme_suncg6_fbc_rect_abs_y[rect_abs_i % TME_SUNCG6_RECT_ABS_COUNT];
548   draw_height
549     = (draw_height < dst_y
550        ? 0
551        : (draw_height + 1 - dst_y));
552 
553   /* check that this draw is supported: */
554   unsupported = FALSE;
555   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_clip_check != 0);
556   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_status != 0);
557   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_offx != 0);
558   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_offy != 0);
559   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_clip_min_x != 0);
560   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_clip_min_y != 0);
561   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_clip_max_x != (fb_width - 1));
562   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_clip_max_y != (fb_height - 1));
563   if (__tme_predict_false(unsupported)) {
564     tme_log(TME_SUNFB_LOG_HANDLE(&suncg6->tme_suncg6_sunfb), 0, EINVAL,
565 	    (TME_SUNFB_LOG_HANDLE(&suncg6->tme_suncg6_sunfb),
566 	     _("unsupported draw parameters")));
567     return;
568   }
569 
570   /* if the draw coordinate isn't in the framebuffer: */
571   if (dst_x >= fb_width
572       || dst_y >= fb_height) {
573     return;
574   }
575 
576   /* make sure the draw height and width stay in the framebuffer: */
577   draw_width = TME_MIN(draw_width,
578 		       fb_width - dst_x);
579   draw_height = TME_MIN(draw_height,
580 			fb_height - dst_y);
581 
582   /* if the draw height or width are zero: */
583   if (draw_width == 0
584       || draw_height == 0) {
585     return;
586   }
587 
588   /* get the offsets of the first and last bytes of the
589      destination: */
590   offset_updated_first = ((fb_width * dst_y) + dst_x);
591   offset_updated_last
592     = (offset_updated_first
593        + (draw_width - 1)
594        + (fb_width * (draw_height - 1)));
595 
596   /* get the first destination row: */
597   dst = (tme_suncg6_pixel_t *) suncg6->tme_suncg6_sunfb.tme_sunfb_memory;
598   dst += offset_updated_first;
599 
600   /* if this is a fill: */
601   if (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_rasterop
602       == TME_SUNCG6_FBC_RASTEROP_FUNC_FILL
603       /* XXX FIXME - the rasterop function that the SUNW,501-2325 PROM
604 	 uses for all of its blits and draws doesn't do a fill draw,
605 	 but for now we treat it like it does: */
606       || (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_rasterop
607 	  == TME_SUNCG6_FBC_RASTEROP_FUNC_PROM)
608       ) {
609 
610     /* if the fill is full-width: */
611     if (draw_width == fb_width) {
612 
613       /* fill the destination: */
614       memset(dst,
615 	     (tme_uint8_t) suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_fg,
616 	     sizeof(tme_suncg6_pixel_t) * draw_width * draw_height);
617     }
618 
619     /* otherwise, the fill is not full-width: */
620     else {
621 
622       /* fill the destination: */
623       do {
624 	memset(dst,
625 	       (tme_uint8_t) suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_fg,
626 	       sizeof(tme_suncg6_pixel_t) * draw_width);
627 	dst += sizeof(tme_suncg6_pixel_t) * fb_width;
628       } while (--draw_height);
629     }
630   }
631 
632   /* otherwise, if this is an invert: */
633   else if (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_rasterop
634 	   == TME_SUNCG6_FBC_RASTEROP_FUNC_FLIP) {
635 
636     /* do the inversion: */
637     /* XXX FIXME - the inversion almost certainly isn't this
638        simple: */
639     do {
640       resid_width = draw_width;
641       do {
642 	*(dst++) ^= 0xff;
643       } while (--resid_width);
644       dst = (dst - draw_width) + fb_width;
645     } while (--draw_height);
646   }
647 
648   /* otherwise, this is an unsupported draw: */
649   else {
650     tme_log(TME_SUNFB_LOG_HANDLE(&suncg6->tme_suncg6_sunfb), 0, EINVAL,
651 	    (TME_SUNFB_LOG_HANDLE(&suncg6->tme_suncg6_sunfb),
652 	     _("unsupported draw function")));
653   }
654 
655   /* update the offsets of the first and last bytes updated in the
656      real framebuffer memory: */
657   offset_updated_first
658     = TME_MIN(offset_updated_first,
659 	      suncg6->tme_suncg6_sunfb.tme_sunfb_offset_updated_first);
660   offset_updated_last
661     = TME_MAX(offset_updated_last,
662 	      suncg6->tme_suncg6_sunfb.tme_sunfb_offset_updated_last);
663   suncg6->tme_suncg6_sunfb.tme_sunfb_offset_updated_first = offset_updated_first;
664   suncg6->tme_suncg6_sunfb.tme_sunfb_offset_updated_last = offset_updated_last;
665 }
666 
667 /* this does a font draw: */
668 static void
_tme_suncg6_font(struct tme_suncg6 * suncg6,tme_suncg6_reg_t font)669 _tme_suncg6_font(struct tme_suncg6 *suncg6,
670 		 tme_suncg6_reg_t font)
671 {
672   tme_uint32_t fb_width;
673   tme_uint32_t fb_height;
674   tme_int32_t dst_x;
675   tme_int32_t dst_y;
676   tme_int32_t draw_width;
677   int unsupported;
678   tme_uint32_t offset_updated_first;
679   tme_uint32_t offset_updated_last;
680   tme_suncg6_pixel_t *dst;
681   tme_uint16_t pixels;
682 
683   /* get the framebuffer width and height: */
684   fb_width = suncg6->tme_suncg6_width;
685   fb_height = suncg6->tme_suncg6_height;
686 
687   /* get the font draw destination: */
688   dst_x = suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_x0;
689   dst_y = suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_y0;
690 
691   /* get the font draw width: */
692   draw_width = suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_x1;
693   draw_width
694     = (draw_width < dst_x
695        ? 0
696        : (draw_width + 1 - dst_x));
697 
698   /* check that this font draw is supported: */
699   unsupported = FALSE;
700   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_clip_check != 0);
701   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_status != 0);
702   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_offx != 0);
703   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_offy != 0);
704   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_clip_min_x != 0);
705   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_clip_min_y != 0);
706   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_clip_max_x != (fb_width - 1));
707   unsupported |= (suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_clip_max_y != (fb_height - 1));
708   if (__tme_predict_false(unsupported)) {
709     tme_log(TME_SUNFB_LOG_HANDLE(&suncg6->tme_suncg6_sunfb), 0, EINVAL,
710 	    (TME_SUNFB_LOG_HANDLE(&suncg6->tme_suncg6_sunfb),
711 	     _("unsupported font draw parameters")));
712     return;
713   }
714 
715   /* if the font draw coordinate isn't in the framebuffer: */
716   if (dst_x >= fb_width
717       || dst_y >= fb_height) {
718     return;
719   }
720 
721   /* make sure the font draw width stays in the framebuffer: */
722   draw_width = TME_MIN(draw_width,
723 		       fb_width - dst_x);
724 
725   /* if the draw width is zero: */
726   if (draw_width == 0) {
727     return;
728   }
729 
730   /* get the offsets of the first and last bytes of the
731      destination: */
732   offset_updated_first = ((fb_width * dst_y) + dst_x);
733   offset_updated_last
734     = (offset_updated_first
735        + (draw_width - 1));
736 
737   /* get the first destination row: */
738   dst = (tme_suncg6_pixel_t *) suncg6->tme_suncg6_sunfb.tme_sunfb_memory;
739   dst += offset_updated_first;
740 
741   /* get the foreground and background pixels: */
742   pixels = (tme_suncg6_pixel_t) suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_fg;
743   pixels <<= (8 * sizeof(tme_suncg6_pixel_t));
744   pixels += (tme_suncg6_pixel_t) suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_bg;
745 
746   /* do the font draw: */
747   do {
748     *(dst++)
749       = ((tme_suncg6_pixel_t)
750 	 (pixels
751 	  >> ((0 - (((tme_int32_t) font) < 0))
752 	      & (8 * sizeof(tme_suncg6_pixel_t)))));
753     font <<= 1;
754   } while (--draw_width);
755 
756   /* advance after the font draw: */
757   suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_x0 += suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_inc_x;
758   suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_x1 += suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_inc_x;
759   suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_y0 += suncg6->tme_suncg6_fbc_group0.tme_suncg6_fbc_inc_y;
760 
761   /* update the offsets of the first and last bytes updated in the
762      real framebuffer memory: */
763   offset_updated_first
764     = TME_MIN(offset_updated_first,
765 	      suncg6->tme_suncg6_sunfb.tme_sunfb_offset_updated_first);
766   offset_updated_last
767     = TME_MAX(offset_updated_last,
768 	      suncg6->tme_suncg6_sunfb.tme_sunfb_offset_updated_last);
769   suncg6->tme_suncg6_sunfb.tme_sunfb_offset_updated_first = offset_updated_first;
770   suncg6->tme_suncg6_sunfb.tme_sunfb_offset_updated_last = offset_updated_last;
771 }
772 
773 /* the ALT bus cycle handler: */
774 static void
_tme_suncg6_bus_cycle_alt(struct tme_sunfb * sunfb,struct tme_bus_cycle * master_cycle,tme_uint32_t * _master_fast_cycle_types,struct tme_completion * master_completion)775 _tme_suncg6_bus_cycle_alt(struct tme_sunfb *sunfb,
776 			  struct tme_bus_cycle *master_cycle,
777 			  tme_uint32_t *_master_fast_cycle_types,
778 			  struct tme_completion *master_completion)
779 {
780   struct tme_suncg6 *suncg6;
781   tme_bus_addr32_t reg;
782   tme_suncg6_reg_t *_reg;
783   tme_suncg6_reg_t value32_buffer;
784   tme_suncg6_reg_t value32;
785 
786   /* recover our data structure: */
787   suncg6 = (struct tme_suncg6 *) sunfb;
788 
789   /* get the register: */
790   reg = master_cycle->tme_bus_cycle_address;
791 
792   /* convert the register into a pointer: */
793   _reg = NULL;
794 
795   /* if this is a write: */
796   if (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
797 
798     /* run the bus cycle: */
799     tme_bus_cycle_xfer_reg(master_cycle,
800 			   &value32_buffer,
801 			   TME_BUS32_LOG2);
802     value32 = value32_buffer;
803   }
804 
805   /* otherwise, this must be a read: */
806   else {
807     assert (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
808 
809     /* this must be a maintained register: */
810     if (_reg == NULL) {
811       abort();
812     }
813     value32 = *_reg;
814 
815     /* run the bus cycle: */
816     value32_buffer = value32;
817     tme_bus_cycle_xfer_reg(master_cycle,
818 			   &value32_buffer,
819 			   TME_BUS32_LOG2);
820   }
821 
822   /* complete the cycle: */
823   master_completion->tme_completion_error = TME_OK;
824   tme_memory_barrier(master_completion, sizeof(*master_completion), TME_MEMORY_BARRIER_WRITE_BEFORE_WRITE);
825   tme_completion_validate(master_completion);
826   *_master_fast_cycle_types = 0;
827 
828   tme_log(TME_SUNFB_LOG_HANDLE(sunfb), 2000, TME_OK,
829 	  (TME_SUNFB_LOG_HANDLE(sunfb),
830 	   _("ALT 0x%06" TME_PRIx32 " %s%s 0x%08" TME_PRIx32),
831 	   reg,
832 	   (_reg == NULL
833 	    ? "UNKNOWN "
834 	    : ""),
835 	   (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE
836 	    ? "<-"
837 	    : "->"),
838 	   value32));
839 }
840 
841 /* the FHC and THC bus cycle handler: */
842 static void
_tme_suncg6_bus_cycle_fhc_thc(struct tme_sunfb * sunfb,struct tme_bus_cycle * master_cycle,tme_uint32_t * _master_fast_cycle_types,struct tme_completion * master_completion)843 _tme_suncg6_bus_cycle_fhc_thc(struct tme_sunfb *sunfb,
844 			      struct tme_bus_cycle *master_cycle,
845 			      tme_uint32_t *_master_fast_cycle_types,
846 			      struct tme_completion *master_completion)
847 {
848   struct tme_suncg6 *suncg6;
849   tme_bus_addr32_t reg;
850   tme_suncg6_reg_t *_reg;
851   tme_suncg6_reg_t value32_buffer;
852   tme_suncg6_reg_t value32;
853   tme_suncg6_reg_t reg_mask_ro;
854 
855   /* recover our data structure: */
856   suncg6 = (struct tme_suncg6 *) sunfb;
857 
858   /* get the register: */
859   reg = master_cycle->tme_bus_cycle_address;
860 
861   /* convert the register into a pointer: */
862   if (reg >= TME_SUNCG6_REG_THC_UNKNOWN_0x0) {
863     _reg = (TME_SUNCG6_REG_POINTER(suncg6, reg,THC,thc,0)
864 	    : TME_SUNCG6_REG_POINTER(suncg6, reg,THC,thc,1)
865 	    : NULL);
866   }
867   else {
868     reg = TME_SUNCG6_REG_FHC;
869     _reg = &suncg6->tme_suncg6_fhc;
870   }
871 
872   /* if this is a write: */
873   if (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
874 
875     /* run the bus cycle: */
876     tme_bus_cycle_xfer_reg(master_cycle,
877 			   &value32_buffer,
878 			   TME_BUS32_LOG2);
879     value32 = value32_buffer;
880 
881     /* assume that none of the register is read-only: */
882     reg_mask_ro = 0;
883 
884     /* dispatch on the register: */
885     switch (reg) {
886 
887       /* the FHC: */
888     case TME_SUNCG6_REG_FHC:
889       reg_mask_ro
890 	= (TME_SUNCG6_FHC_ID_MASK
891 	   + TME_SUNCG6_FHC_REVISION_MASK
892 	   + TME_SUNCG6_FHC_SIZE_MASK);
893       break;
894 
895       /* the THC miscellaneous register: */
896     case TME_SUNCG6_REG_THC(1,misc):
897       reg_mask_ro
898 	= (TME_SUNCG6_THC_MISC_REVISION_MASK
899 	   );
900       break;
901 
902     default:
903       break;
904     }
905 
906     /* if this is a maintained register: */
907     if (_reg != NULL) {
908       *_reg
909 	= ((*_reg
910 	    & reg_mask_ro)
911 	   + (value32
912 	      & ~reg_mask_ro));
913     }
914   }
915 
916   /* otherwise, this is a read: */
917   else {
918     assert (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
919 
920     /* dispatch on the register: */
921     switch (reg) {
922 
923     default:
924       break;
925     }
926 
927     /* this must be a maintained register: */
928     if (_reg == NULL) {
929       abort();
930     }
931     value32 = *_reg;
932 
933     /* run the bus cycle: */
934     value32_buffer = value32;
935     tme_bus_cycle_xfer_reg(master_cycle,
936 			   &value32_buffer,
937 			   TME_BUS32_LOG2);
938   }
939 
940   /* complete the cycle: */
941   master_completion->tme_completion_error = TME_OK;
942   tme_memory_barrier(master_completion, sizeof(*master_completion), TME_MEMORY_BARRIER_WRITE_BEFORE_WRITE);
943   tme_completion_validate(master_completion);
944   *_master_fast_cycle_types = 0;
945 
946   tme_log(TME_SUNFB_LOG_HANDLE(sunfb), 2000, TME_OK,
947 	  (TME_SUNFB_LOG_HANDLE(sunfb),
948 	   _("%s 0x%06" TME_PRIx32 " %s%s 0x%08" TME_PRIx32),
949 	   (reg >= TME_SUNCG6_REG_THC_UNKNOWN_0x0
950 	    ? "THC"
951 	    : "FHC"),
952 	   reg,
953 	   (_reg == NULL
954 	    ? "UNKNOWN "
955 	    : ""),
956 	   (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE
957 	    ? "<-"
958 	    : "->"),
959 	   value32));
960 }
961 
962 /* the FBC bus cycle handler: */
963 static void
_tme_suncg6_bus_cycle_fbc(struct tme_sunfb * sunfb,struct tme_bus_cycle * master_cycle,tme_uint32_t * _master_fast_cycle_types,struct tme_completion * master_completion)964 _tme_suncg6_bus_cycle_fbc(struct tme_sunfb *sunfb,
965 			  struct tme_bus_cycle *master_cycle,
966 			  tme_uint32_t *_master_fast_cycle_types,
967 			  struct tme_completion *master_completion)
968 {
969   struct tme_suncg6 *suncg6;
970   tme_bus_addr32_t reg;
971   tme_suncg6_reg_t *_reg;
972   tme_suncg6_reg_t value32_buffer;
973   tme_suncg6_reg_t value32;
974   tme_suncg6_reg_t reg_mask_ro;
975 
976   /* recover our data structure: */
977   suncg6 = (struct tme_suncg6 *) sunfb;
978 
979   /* get the register: */
980   reg = master_cycle->tme_bus_cycle_address;
981 
982   /* convert the register into a pointer: */
983   _reg
984     = (TME_SUNCG6_REG_POINTER(suncg6, reg,FBC,fbc,0)
985        : TME_SUNCG6_REG_POINTER(suncg6, reg,FBC,fbc,1)
986        : NULL);
987 
988   /* if this is a write: */
989   if (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
990 
991     /* run the bus cycle: */
992     tme_bus_cycle_xfer_reg(master_cycle,
993 			   &value32_buffer,
994 			   TME_BUS32_LOG2);
995     value32 = value32_buffer;
996 
997     /* assume that none of the register is read-only: */
998     reg_mask_ro = 0;
999 
1000     /* dispatch on the register: */
1001     switch (reg) {
1002 
1003       /* a write of the font register: */
1004     case TME_SUNCG6_REG_FBC(0,font):
1005       _tme_suncg6_font(suncg6, value32);
1006       break;
1007 
1008       /* a write of the rectangle absolute coordinate registers: */
1009     case TME_SUNCG6_REG_FBC(1,rect_abs_x):
1010       suncg6->tme_suncg6_fbc_rect_abs_x_i
1011 	= ((suncg6->tme_suncg6_fbc_rect_abs_x_i + 1)
1012 	   % TME_SUNCG6_RECT_ABS_COUNT);
1013       _reg = &suncg6->tme_suncg6_fbc_rect_abs_x[suncg6->tme_suncg6_fbc_rect_abs_x_i];
1014       break;
1015     case TME_SUNCG6_REG_FBC(1,rect_abs_y):
1016       suncg6->tme_suncg6_fbc_rect_abs_y_i
1017 	= ((suncg6->tme_suncg6_fbc_rect_abs_y_i + 1)
1018 	   % TME_SUNCG6_RECT_ABS_COUNT);
1019       _reg = &suncg6->tme_suncg6_fbc_rect_abs_y[suncg6->tme_suncg6_fbc_rect_abs_y_i];
1020       break;
1021 
1022     default:
1023       break;
1024     }
1025 
1026     /* if this is a maintained register: */
1027     if (_reg != NULL) {
1028       *_reg
1029 	= ((*_reg
1030 	    & reg_mask_ro)
1031 	   + (value32
1032 	      & ~reg_mask_ro));
1033     }
1034   }
1035 
1036   /* otherwise, this is a read: */
1037   else {
1038     assert (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
1039 
1040     /* dispatch on the register: */
1041     switch (reg) {
1042 
1043       /* a read of the status register: */
1044     case TME_SUNCG6_REG_FBC(0,status):
1045       *_reg = 0;
1046       break;
1047 
1048       /* a read of the blit status register: */
1049     case TME_SUNCG6_REG_FBC(0,status_blit):
1050 
1051       /* trigger a blit: */
1052       _tme_suncg6_blit(suncg6);
1053 
1054       *_reg = 0;
1055       break;
1056 
1057       /* a read of the drawing status register: */
1058     case TME_SUNCG6_REG_FBC(0,status_draw):
1059 
1060       /* trigger a draw: */
1061       _tme_suncg6_draw(suncg6);
1062 
1063       *_reg = 0;
1064       break;
1065 
1066     default:
1067       break;
1068     }
1069 
1070     /* this must be a maintained register: */
1071     if (_reg == NULL) {
1072       abort();
1073     }
1074     value32 = *_reg;
1075 
1076     /* run the bus cycle: */
1077     value32_buffer = value32;
1078     tme_bus_cycle_xfer_reg(master_cycle,
1079 			   &value32_buffer,
1080 			   TME_BUS32_LOG2);
1081   }
1082 
1083   /* complete the cycle: */
1084   master_completion->tme_completion_error = TME_OK;
1085   tme_memory_barrier(master_completion, sizeof(*master_completion), TME_MEMORY_BARRIER_WRITE_BEFORE_WRITE);
1086   tme_completion_validate(master_completion);
1087   *_master_fast_cycle_types = 0;
1088 
1089   tme_log(TME_SUNFB_LOG_HANDLE(sunfb), 2000, TME_OK,
1090 	  (TME_SUNFB_LOG_HANDLE(sunfb),
1091 	   _("FBC 0x%06" TME_PRIx32 " %s%s 0x%08" TME_PRIx32),
1092 	   reg,
1093 	   (_reg == NULL
1094 	    ? "UNKNOWN "
1095 	    : ""),
1096 	   (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE
1097 	    ? "<-"
1098 	    : "->"),
1099 	   value32));
1100 }
1101 
1102 /* the TEC bus cycle handler: */
1103 static void
_tme_suncg6_bus_cycle_tec(struct tme_sunfb * sunfb,struct tme_bus_cycle * master_cycle,tme_uint32_t * _master_fast_cycle_types,struct tme_completion * master_completion)1104 _tme_suncg6_bus_cycle_tec(struct tme_sunfb *sunfb,
1105 			  struct tme_bus_cycle *master_cycle,
1106 			  tme_uint32_t *_master_fast_cycle_types,
1107 			  struct tme_completion *master_completion)
1108 {
1109   struct tme_suncg6 *suncg6;
1110   tme_bus_addr32_t reg;
1111   tme_suncg6_reg_t *_reg;
1112   tme_suncg6_reg_t value32_buffer;
1113   tme_suncg6_reg_t value32;
1114   tme_suncg6_reg_t reg_mask_ro;
1115 
1116   /* recover our data structure: */
1117   suncg6 = (struct tme_suncg6 *) sunfb;
1118 
1119   /* get the register: */
1120   reg = master_cycle->tme_bus_cycle_address;
1121 
1122   /* convert the register into a pointer: */
1123   _reg
1124     = (TME_SUNCG6_REG_POINTER(suncg6, reg,TEC,tec,0)
1125        : NULL);
1126 
1127   /* if this is a write: */
1128   if (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
1129 
1130     /* run the bus cycle: */
1131     tme_bus_cycle_xfer_reg(master_cycle,
1132 			   &value32_buffer,
1133 			   TME_BUS32_LOG2);
1134     value32 = value32_buffer;
1135 
1136     /* assume that none of the register is read-only: */
1137     reg_mask_ro = 0;
1138 
1139     /* dispatch on the register: */
1140     switch (reg) {
1141 
1142     default:
1143       break;
1144     }
1145 
1146     /* if this is a maintained register: */
1147     if (_reg != NULL) {
1148       *_reg
1149 	= ((*_reg
1150 	    & reg_mask_ro)
1151 	   + (value32
1152 	      & ~reg_mask_ro));
1153     }
1154   }
1155 
1156   /* otherwise, this is a read: */
1157   else {
1158     assert (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
1159 
1160     /* dispatch on the register: */
1161     switch (reg) {
1162 
1163     default:
1164       break;
1165     }
1166 
1167     /* this must be a maintained register: */
1168     if (_reg == NULL) {
1169       abort();
1170     }
1171     value32 = *_reg;
1172 
1173     /* run the bus cycle: */
1174     value32_buffer = value32;
1175     tme_bus_cycle_xfer_reg(master_cycle,
1176 			   &value32_buffer,
1177 			   TME_BUS32_LOG2);
1178   }
1179 
1180   /* complete the cycle: */
1181   master_completion->tme_completion_error = TME_OK;
1182   tme_memory_barrier(master_completion, sizeof(*master_completion), TME_MEMORY_BARRIER_WRITE_BEFORE_WRITE);
1183   tme_completion_validate(master_completion);
1184   *_master_fast_cycle_types = 0;
1185 
1186   tme_log(TME_SUNFB_LOG_HANDLE(sunfb), 2000, TME_OK,
1187 	  (TME_SUNFB_LOG_HANDLE(sunfb),
1188 	   _("TEC 0x%06" TME_PRIx32 " %s%s 0x%08" TME_PRIx32),
1189 	   reg,
1190 	   (_reg == NULL
1191 	    ? "UNKNOWN "
1192 	    : ""),
1193 	   (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE
1194 	    ? "<-"
1195 	    : "->"),
1196 	   value32));
1197 }
1198 
1199 #if TME_SUNFB_BUS_TRANSITION
1200 
1201 /* this is the bus cycle transition glue: */
1202 #define _tme_suncg6_bus_cycle_transition(regs)						\
1203 static int										\
1204 _TME_CONCAT(_tme_suncg6_bus_cycle_transition_,regs)(void *_sunfb,			\
1205 						    struct tme_bus_cycle *master_cycle)	\
1206 {											\
1207   return (tme_sunfb_bus_cycle_transition(_sunfb,					\
1208 					 master_cycle,					\
1209 					 _TME_CONCAT(_tme_suncg6_bus_cycle_,regs)));	\
1210 }											\
1211 struct _tme_suncg6_bus_cycle_transition
1212 _tme_suncg6_bus_cycle_transition(alt);
1213 _tme_suncg6_bus_cycle_transition(fhc_thc);
1214 _tme_suncg6_bus_cycle_transition(fbc);
1215 _tme_suncg6_bus_cycle_transition(tec);
1216 #define _tme_suncg6_bus_cycle_alt _tme_suncg6_bus_cycle_transition_alt
1217 #define _tme_suncg6_bus_cycle_fhc_thc _tme_suncg6_bus_cycle_transition_fhc_thc
1218 #define _tme_suncg6_bus_cycle_fbc _tme_suncg6_bus_cycle_transition_fbc
1219 #define _tme_suncg6_bus_cycle_tec _tme_suncg6_bus_cycle_transition_tec
1220 #undef _tme_suncg6_bus_cycle_transition
1221 
1222 #endif /* TME_SUNFB_BUS_TRANSITION */
1223 
1224 /* this sets the cgsix type: */
1225 static const char *
_tme_suncg6_type_set(struct tme_sunfb * sunfb,const char * cg6_type_string)1226 _tme_suncg6_type_set(struct tme_sunfb *sunfb, const char *cg6_type_string)
1227 {
1228   struct tme_suncg6 *suncg6;
1229   tme_uint32_t cg6_type;
1230   tme_suncg6_reg_t fhc;
1231   tme_suncg6_reg_t thc_misc;
1232 
1233   /* recover our data structure: */
1234   suncg6 = (struct tme_suncg6 *) sunfb;
1235 
1236   /* see if this is a good type: */
1237   cg6_type = TME_SUNCG6_TYPE_NULL;
1238   if (TME_ARG_IS(cg6_type_string, "501-2325")) {
1239     cg6_type = TME_SUNCG6_TYPE_501_2325;
1240   }
1241 
1242   /* set the new type: */
1243   suncg6->tme_suncg6_type = cg6_type;
1244 
1245   /* zero various registers: */
1246   fhc = 0;
1247   thc_misc = 0;
1248 
1249   /* dispatch on the new type: */
1250   switch (cg6_type) {
1251 
1252     /* if this was a bad type, return a string of types: */
1253   default: assert(FALSE);
1254   case TME_SUNCG6_TYPE_NULL:
1255     return ("501-2325");
1256 
1257   case TME_SUNCG6_TYPE_501_2325:
1258     TME_FIELD_MASK_DEPOSITU(fhc, TME_SUNCG6_FHC_ID_MASK, 0x63);
1259     TME_FIELD_MASK_DEPOSITU(fhc, TME_SUNCG6_FHC_REVISION_MASK, 0xb);
1260     TME_FIELD_MASK_DEPOSITU(thc_misc, TME_SUNCG6_THC_MISC_REVISION_MASK, 0x4);
1261     sunfb->tme_sunfb_bus_signal_int = TME_BUS_SIGNAL_INT(5);
1262     break;
1263   }
1264 
1265   /* set various initial registers: */
1266   suncg6->tme_suncg6_fhc = fhc;
1267   suncg6->tme_suncg6_thc_group1.tme_suncg6_thc_misc = thc_misc;
1268 
1269   /* success: */
1270   return (NULL);
1271 }
1272 
1273 /* the new sun cgsix function: */
1274 int
tme_sun_cgsix(struct tme_element * element,const char * const * args,char ** _output)1275 tme_sun_cgsix(struct tme_element *element, const char * const *args, char **_output)
1276 {
1277   struct tme_suncg6 *suncg6;
1278   struct tme_sunfb *sunfb;
1279   tme_uint8_t *cmap;
1280   int rc;
1281   tme_suncg6_reg_t fhc;
1282 
1283   /* start the suncg6 structure: */
1284   suncg6 = tme_new0(struct tme_suncg6, 1);
1285   suncg6->tme_suncg6_sunfb.tme_sunfb_element = element;
1286 
1287   /* initialize the sunfb structure: */
1288   sunfb = &suncg6->tme_suncg6_sunfb;
1289   sunfb->tme_sunfb_class = TME_FB_XLAT_CLASS_COLOR;
1290   sunfb->tme_sunfb_depth = 8;
1291   sunfb->tme_sunfb_type_set = _tme_suncg6_type_set;
1292   sunfb->tme_sunfb_flags
1293     |= ((!TME_SUNFB_FLAG_BT458_CMAP_PACKED)
1294 	| TME_SUNFB_FLAG_BT458_BYTE_D24_D31);
1295 
1296   /* possible cgsix framebuffer sizes: */
1297   suncg6->tme_suncg6_sunfb.tme_sunfb_size
1298     = (TME_SUNFB_SIZE_1024_768
1299        | TME_SUNFB_SIZE_1152_900
1300        | TME_SUNFB_SIZE_1280_1024
1301        | TME_SUNFB_SIZE_1600_1280);
1302 
1303   /* assume that this is not a P4 cgsix: */
1304   suncg6->tme_suncg6_bus_subregion_p4.tme_bus_subregion_address_first = 1;
1305   suncg6->tme_suncg6_bus_subregion_p4.tme_bus_subregion_address_last = 0;
1306   suncg6->tme_suncg6_bus_handler_p4 = NULL;
1307 
1308   /* the DAC registers: */
1309   suncg6->tme_suncg6_bus_subregion_dac.tme_bus_subregion_address_first = TME_SUNCG6_REG_DAC;
1310   suncg6->tme_suncg6_bus_subregion_dac.tme_bus_subregion_address_last = TME_SUNCG6_REG_ALT - 1;
1311   suncg6->tme_suncg6_bus_handler_dac = tme_sunfb_bus_cycle_bt458;
1312 
1313   /* the ALT registers: */
1314   suncg6->tme_suncg6_bus_subregion_alt.tme_bus_subregion_address_first = TME_SUNCG6_REG_ALT;
1315   suncg6->tme_suncg6_bus_subregion_alt.tme_bus_subregion_address_last = TME_SUNCG6_REG_ALT + TME_SUNCG6_SIZ_ALT - 1;
1316   suncg6->tme_suncg6_bus_handler_alt = _tme_suncg6_bus_cycle_alt;
1317 
1318   /* the FHC and THC registers: */
1319   suncg6->tme_suncg6_bus_subregion_fhc_thc.tme_bus_subregion_address_first = TME_SUNCG6_REG_FHC;
1320   suncg6->tme_suncg6_bus_subregion_fhc_thc.tme_bus_subregion_address_last
1321     = (TME_SUNCG6_REG_THC_UNKNOWN_0x0
1322        + TME_SUNCG6_SIZ_THC
1323        - 1);
1324   suncg6->tme_suncg6_bus_handler_fhc_thc = _tme_suncg6_bus_cycle_fhc_thc;
1325 
1326   /* the FBC registers: */
1327   suncg6->tme_suncg6_bus_subregion_fbc.tme_bus_subregion_address_first
1328     = TME_SUNCG6_REG_FBC_GROUP0;
1329   suncg6->tme_suncg6_bus_subregion_fbc.tme_bus_subregion_address_last
1330     = TME_SUNCG6_REG_TEC_GROUP0 - 1;
1331   suncg6->tme_suncg6_bus_handler_fbc = _tme_suncg6_bus_cycle_fbc;
1332 
1333   /* the TEC registers: */
1334   suncg6->tme_suncg6_bus_subregion_tec.tme_bus_subregion_address_first
1335     = TME_SUNCG6_REG_TEC_GROUP0;
1336   suncg6->tme_suncg6_bus_subregion_tec.tme_bus_subregion_address_last
1337     = (TME_SUNCG6_REG_TEC_GROUP0
1338        + TME_SUNCG6_TEC_SIZE
1339        - 1);
1340   suncg6->tme_suncg6_bus_handler_tec = _tme_suncg6_bus_cycle_tec;
1341 
1342   /* the memory address: */
1343   sunfb->tme_sunfb_bus_subregion_memory.tme_bus_subregion_address_first = TME_SUNFB_S4_OFFSET_MEMORY;
1344 
1345   /* if the generic initialization fails: */
1346   rc = tme_sunfb_new(sunfb, args, _output);
1347   if (rc) {
1348 
1349     /* free the sunfb structure and return the error: */
1350     tme_free(sunfb);
1351     return (rc);
1352   }
1353 
1354   /* set the size in the initial FHC: */
1355   fhc = suncg6->tme_suncg6_fhc;
1356   fhc &= (TME_SUNCG6_FHC_ID_MASK
1357 	  + TME_SUNCG6_FHC_REVISION_MASK);
1358   switch (sunfb->tme_sunfb_size) {
1359   default: assert(FALSE);
1360   case TME_SUNFB_SIZE_1152_900: fhc += TME_SUNCG6_FHC_SIZE_1152_900; break;
1361   case TME_SUNFB_SIZE_1024_768: fhc += TME_SUNCG6_FHC_SIZE_1024_768; break;
1362   case TME_SUNFB_SIZE_1280_1024: fhc += TME_SUNCG6_FHC_SIZE_1280_1024; break;
1363   case TME_SUNFB_SIZE_1600_1280: fhc += TME_SUNCG6_FHC_SIZE_1600_1280; break;
1364   }
1365   suncg6->tme_suncg6_fhc = fhc;
1366 
1367   /* save the size: */
1368   suncg6->tme_suncg6_width = tme_sunfb_size_width(suncg6->tme_suncg6_sunfb.tme_sunfb_size);
1369   suncg6->tme_suncg6_height = tme_sunfb_size_height(suncg6->tme_suncg6_sunfb.tme_sunfb_size);
1370 
1371   /* allocate the colormap arrays: */
1372   cmap = tme_new0(tme_uint8_t, 256 * 3);
1373   sunfb->tme_sunfb_cmap_g = &cmap[256 * 0];
1374   sunfb->tme_sunfb_cmap_r = &cmap[256 * 1];
1375   sunfb->tme_sunfb_cmap_b = &cmap[256 * 2];
1376   sunfb->tme_sunfb_bt458.tme_bt458_cmap_g = sunfb->tme_sunfb_cmap_g;
1377   sunfb->tme_sunfb_bt458.tme_bt458_cmap_r = sunfb->tme_sunfb_cmap_r;
1378   sunfb->tme_sunfb_bt458.tme_bt458_cmap_b = sunfb->tme_sunfb_cmap_b;
1379 
1380   return (TME_OK);
1381 }
1382