1/*-
2 * Copyright (C) 2012 Margarida Gouveia
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer,
10 *    without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29#ifndef	_POWERPC_WII_WIIFB_H
30#define	_POWERPC_WII_WIIFB_H
31
32#define	WIIFB_FONT_HEIGHT	8
33
34enum wiifb_format {
35	WIIFB_FORMAT_NTSC  = 0,
36	WIIFB_FORMAT_PAL   = 1,
37	WIIFB_FORMAT_MPAL  = 2,
38	WIIFB_FORMAT_DEBUG = 3
39};
40
41enum wiifb_mode {
42	WIIFB_MODE_NTSC_480i = 0,
43	WIIFB_MODE_NTSC_480p = 1,
44	WIIFB_MODE_PAL_576i  = 2,
45	WIIFB_MODE_PAL_480i  = 3,
46	WIIFB_MODE_PAL_480p  = 4
47};
48
49struct wiifb_mode_desc {
50	const char 	*fd_name;
51	unsigned int	fd_width;
52	unsigned int	fd_height;
53	unsigned int	fd_lines;
54	uint8_t		fd_flags;
55#define WIIFB_MODE_FLAG_PROGRESSIVE	0x00
56#define WIIFB_MODE_FLAG_INTERLACED	0x01
57};
58
59struct wiifb_softc {
60	video_adapter_t	sc_va;
61	struct cdev	*sc_si;
62	int		sc_console;
63
64	intptr_t	sc_reg_addr;
65	unsigned int	sc_reg_size;
66
67	intptr_t	sc_fb_addr;
68	unsigned int	sc_fb_size;
69
70	unsigned int	sc_height;
71	unsigned int	sc_width;
72	unsigned int	sc_stride;
73
74	unsigned int	sc_xmargin;
75	unsigned int	sc_ymargin;
76
77	boolean_t	sc_component;
78	enum wiifb_format sc_format;
79	struct wiifb_mode_desc *sc_mode;
80
81	unsigned int	sc_vtiming;
82	unsigned int	sc_htiming;
83
84	unsigned char	*sc_font;
85	int		sc_initialized;
86	int		sc_rrid;
87};
88
89/*
90 * Vertical timing
91 * 16 bit
92 */
93#define	WIIFB_REG_VTIMING	0x00
94struct wiifb_vtiming {
95	uint8_t		vt_eqpulse;
96	uint16_t	vt_actvideo;
97};
98
99static __inline void
100wiifb_vtiming_read(struct wiifb_softc *sc, struct wiifb_vtiming *vt)
101{
102	volatile uint16_t *reg =
103	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_VTIMING);
104
105	vt->vt_eqpulse  = *reg & 0xf;
106	vt->vt_actvideo = (*reg >> 4) & 0x3ff;
107}
108
109static __inline void
110wiifb_vtiming_write(struct wiifb_softc *sc, struct wiifb_vtiming *vt)
111{
112	volatile uint16_t *reg =
113	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_VTIMING);
114
115	*reg = ((vt->vt_actvideo & 0x3ff) << 4) |
116	        (vt->vt_eqpulse & 0xf);
117	powerpc_sync();
118}
119
120/*
121 * Display configuration
122 * 16 bit
123 */
124#define	WIIFB_REG_DISPCFG	0x02
125struct wiifb_dispcfg {
126	uint8_t		  dc_enable;
127	uint8_t		  dc_reset;
128	uint8_t		  dc_noninterlaced;
129	uint8_t		  dc_3dmode;
130	uint8_t		  dc_latchenb0;
131	uint8_t		  dc_latchenb1;
132	enum wiifb_format dc_format;
133};
134
135static __inline void
136wiifb_dispcfg_read(struct wiifb_softc *sc, struct wiifb_dispcfg *dc)
137{
138	volatile uint16_t *reg =
139	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_DISPCFG);
140
141	dc->dc_enable        = *reg & 0x1;
142	dc->dc_reset         = (*reg >> 1) & 0x1;
143	dc->dc_noninterlaced = (*reg >> 2) & 0x1;
144	dc->dc_3dmode        = (*reg >> 3) & 0x1;
145	dc->dc_latchenb0     = (*reg >> 4) & 0x3;
146	dc->dc_latchenb1     = (*reg >> 6) & 0x3;
147	dc->dc_format        = (*reg >> 8) & 0x3;
148}
149
150static __inline void
151wiifb_dispcfg_write(struct wiifb_softc *sc, struct wiifb_dispcfg *dc)
152{
153	volatile uint16_t *reg =
154	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_DISPCFG);
155
156	*reg = ((dc->dc_format & 0x3) << 8)        |
157	       ((dc->dc_latchenb1 & 0x3) << 6)     |
158	       ((dc->dc_latchenb0 & 0x3) << 4)     |
159	       ((dc->dc_3dmode & 0x1) << 3)        |
160	       ((dc->dc_noninterlaced & 0x1) << 2) |
161	       ((dc->dc_reset & 0x1) << 1)         |
162	        (dc->dc_enable & 0x1);
163	powerpc_sync();
164}
165
166/*
167 * Horizontal Timing 0
168 * 32 bit
169 */
170#define	WIIFB_REG_HTIMING0		0x04
171struct wiifb_htiming0 {
172	uint16_t	ht0_hlinew;	/* half line width */
173	uint8_t		ht0_hcolourend;
174	uint8_t		ht0_hcolourstart;
175};
176
177static __inline void
178wiifb_htiming0_read(struct wiifb_softc *sc, struct wiifb_htiming0 *ht0)
179{
180	volatile uint32_t *reg =
181	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_HTIMING0);
182
183	ht0->ht0_hlinew       = *reg & 0x1ff;
184	ht0->ht0_hcolourend   = (*reg >> 16) & 0x7f;
185	ht0->ht0_hcolourstart = (*reg >> 24) & 0x7f;
186}
187
188static __inline void
189wiifb_htiming0_write(struct wiifb_softc *sc, struct wiifb_htiming0 *ht0)
190{
191	volatile uint32_t *reg =
192	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_HTIMING0);
193
194	*reg = ((ht0->ht0_hcolourstart & 0x7f) << 24) |
195	       ((ht0->ht0_hcolourend & 0x7f) << 16)   |
196	        (ht0->ht0_hlinew & 0x1ff);
197	powerpc_sync();
198}
199/*
200 * Horizontal Timing 1
201 * 32 bit
202 */
203#define	WIIFB_REG_HTIMING1		0x08
204struct wiifb_htiming1 {
205	uint8_t		ht1_hsyncw;
206	uint16_t	ht1_hblankend;
207	uint16_t	ht1_hblankstart;
208};
209
210static __inline void
211wiifb_htiming1_read(struct wiifb_softc *sc, struct wiifb_htiming1 *ht1)
212{
213	volatile uint32_t *reg =
214	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_HTIMING1);
215
216	ht1->ht1_hsyncw      = *reg & 0x7f;
217	ht1->ht1_hblankend   = (*reg >> 7) & 0x3ff;
218	ht1->ht1_hblankstart = (*reg >> 17) & 0x3ff;
219}
220
221static __inline void
222wiifb_htiming1_write(struct wiifb_softc *sc, struct wiifb_htiming1 *ht1)
223{
224	volatile uint32_t *reg =
225	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_HTIMING1);
226
227	*reg = ((ht1->ht1_hblankstart & 0x3ff) << 17) |
228	       ((ht1->ht1_hblankend & 0x3ff) << 7)    |
229	        (ht1->ht1_hsyncw & 0x7f);
230	powerpc_sync();
231}
232
233/*
234 * Vertical Timing Odd
235 * 32 bit
236 */
237#define	WIIFB_REG_VTIMINGODD		0x0c
238struct wiifb_vtimingodd {
239	uint16_t	vto_preb;	/* pre blanking */
240	uint16_t	vto_postb;	/* post blanking */
241};
242
243static __inline void
244wiifb_vtimingodd_read(struct wiifb_softc *sc, struct wiifb_vtimingodd *vto)
245{
246	volatile uint32_t *reg =
247	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_VTIMINGODD);
248
249	vto->vto_preb  = *reg & 0x3ff;
250	vto->vto_postb = (*reg >> 16) & 0x3ff;
251}
252
253static __inline void
254wiifb_vtimingodd_write(struct wiifb_softc *sc, struct wiifb_vtimingodd *vto)
255{
256	volatile uint32_t *reg =
257	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_VTIMINGODD);
258
259	*reg = ((vto->vto_postb & 0x3ff) << 16) |
260	        (vto->vto_preb & 0x3ff);
261	powerpc_sync();
262}
263
264/*
265 * Vertical Timing Even
266 * 32 bit
267 */
268#define	WIIFB_REG_VTIMINGEVEN		0x10
269struct wiifb_vtimingeven {
270	uint16_t	vte_preb;	/* pre blanking */
271	uint16_t	vte_postb;	/* post blanking */
272};
273
274static __inline void
275wiifb_vtimingeven_read(struct wiifb_softc *sc, struct wiifb_vtimingeven *vte)
276{
277	volatile uint32_t *reg =
278	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_VTIMINGEVEN);
279
280	vte->vte_preb  = *reg & 0x3ff;
281	vte->vte_postb = (*reg >> 16) & 0x3ff;
282}
283
284static __inline void
285wiifb_vtimingeven_write(struct wiifb_softc *sc, struct wiifb_vtimingeven *vte)
286{
287	volatile uint32_t *reg =
288	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_VTIMINGEVEN);
289
290	*reg = ((vte->vte_postb & 0x3ff) << 16) |
291	        (vte->vte_preb & 0x3ff);
292	powerpc_sync();
293}
294
295/*
296 * Burst Blanking Odd Interval
297 * 32 bit
298 */
299#define	WIIFB_REG_BURSTBLANKODD		0x14
300struct wiifb_burstblankodd {
301	uint8_t		bbo_bs1;
302	uint16_t	bbo_be1;
303	uint8_t		bbo_bs3;
304	uint16_t	bbo_be3;
305};
306
307static __inline void
308wiifb_burstblankodd_read(struct wiifb_softc *sc,
309    struct wiifb_burstblankodd *bbo)
310{
311	volatile uint32_t *reg =
312	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BURSTBLANKODD);
313
314	bbo->bbo_bs1 = *reg & 0x1f;
315	bbo->bbo_be1 = (*reg >> 5) & 0x7ff;
316	bbo->bbo_bs3 = (*reg >> 16) & 0x1f;
317	bbo->bbo_be3 = (*reg >> 21) & 0x7ff;
318}
319
320static __inline void
321wiifb_burstblankodd_write(struct wiifb_softc *sc,
322    struct wiifb_burstblankodd *bbo)
323{
324	volatile uint32_t *reg =
325	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BURSTBLANKODD);
326
327	*reg = ((bbo->bbo_be3 & 0x7ff) << 21) |
328	       ((bbo->bbo_bs3 & 0x1f) << 16)  |
329	       ((bbo->bbo_be1 & 0x7ff) << 5)  |
330	        (bbo->bbo_bs1 & 0x1f);
331	powerpc_sync();
332}
333
334/*
335 * Burst Blanking Even Interval
336 * 32 bit
337 */
338#define	WIIFB_REG_BURSTBLANKEVEN	0x18
339struct wiifb_burstblankeven {
340	uint8_t		bbe_bs2;
341	uint16_t	bbe_be2;
342	uint8_t		bbe_bs4;
343	uint16_t	bbe_be4;
344};
345
346static __inline void
347wiifb_burstblankeven_read(struct wiifb_softc *sc,
348    struct wiifb_burstblankeven *bbe)
349{
350	volatile uint32_t *reg =
351	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BURSTBLANKEVEN);
352
353	bbe->bbe_bs2 = *reg & 0x1f;
354	bbe->bbe_be2 = (*reg >> 5) & 0x7ff;
355	bbe->bbe_bs4 = (*reg >> 16) & 0x1f;
356	bbe->bbe_be4 = (*reg >> 21) & 0x7ff;
357}
358
359static __inline void
360wiifb_burstblankeven_write(struct wiifb_softc *sc,
361    struct wiifb_burstblankeven *bbe)
362{
363	volatile uint32_t *reg =
364	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BURSTBLANKEVEN);
365
366	*reg = ((bbe->bbe_be4 & 0x7ff) << 21) |
367	       ((bbe->bbe_bs4 & 0x1f) << 16)  |
368	       ((bbe->bbe_be2 & 0x7ff) << 5)  |
369	        (bbe->bbe_bs2 & 0x1f);
370	powerpc_sync();
371}
372
373/*
374 * Top Field Base Left
375 * 32 bit
376 */
377#define	WIIFB_REG_TOPFIELDBASEL		0x1c
378struct wiifb_topfieldbasel {
379	uint32_t	tfbl_fbaddr;
380	uint8_t		tfbl_xoffset;
381	uint8_t		tfbl_pageoffbit;
382};
383
384static __inline void
385wiifb_topfieldbasel_read(struct wiifb_softc *sc,
386    struct wiifb_topfieldbasel *tfbl)
387{
388	volatile uint32_t *reg =
389	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_TOPFIELDBASEL);
390
391	tfbl->tfbl_fbaddr     = *reg & 0xffffff;
392	tfbl->tfbl_xoffset    = (*reg >> 24) & 0xf;
393	tfbl->tfbl_pageoffbit = (*reg >> 28) & 0x1;
394}
395
396static __inline void
397wiifb_topfieldbasel_write(struct wiifb_softc *sc,
398    struct wiifb_topfieldbasel *tfbl)
399{
400	volatile uint32_t *reg =
401	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_TOPFIELDBASEL);
402
403	*reg = ((tfbl->tfbl_pageoffbit & 0x1) << 28) |
404	       ((tfbl->tfbl_xoffset & 0xf) << 24)    |
405	        (tfbl->tfbl_fbaddr & 0xffffff);
406	powerpc_sync();
407}
408
409/*
410 * Top Field Base Right
411 * 32 bit
412 */
413#define	WIIFB_REG_TOPFIELDBASER		0x20
414struct wiifb_topfieldbaser {
415	uint32_t	tfbr_fbaddr;
416	uint8_t		tfbr_pageoffbit;
417};
418
419static __inline void
420wiifb_topfieldbaser_read(struct wiifb_softc *sc,
421    struct wiifb_topfieldbaser *tfbr)
422{
423	volatile uint32_t *reg =
424	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_TOPFIELDBASER);
425
426	tfbr->tfbr_fbaddr     = *reg & 0xffffff;
427	tfbr->tfbr_pageoffbit = (*reg >> 28) & 0x1;
428}
429
430static __inline void
431wiifb_topfieldbaser_write(struct wiifb_softc *sc,
432    struct wiifb_topfieldbaser *tfbr)
433{
434	volatile uint32_t *reg =
435	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_TOPFIELDBASER);
436
437	*reg  = ((tfbr->tfbr_pageoffbit & 0x1) << 28) |
438		 (tfbr->tfbr_fbaddr & 0xffffff);
439	powerpc_sync();
440}
441
442/*
443 * Bottom Field Base Left
444 * 32 bit
445 */
446#define	WIIFB_REG_BOTTOMFIELDBASEL	0x24
447struct wiifb_bottomfieldbasel {
448	uint32_t	bfbl_fbaddr;
449	uint8_t		bfbl_xoffset;
450	uint8_t		bfbl_pageoffbit;
451};
452
453static __inline void
454wiifb_bottomfieldbasel_read(struct wiifb_softc *sc,
455    struct wiifb_bottomfieldbasel *bfbl)
456{
457	volatile uint32_t *reg =
458	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BOTTOMFIELDBASEL);
459
460	bfbl->bfbl_fbaddr     = *reg & 0xffffff;
461	bfbl->bfbl_xoffset    = (*reg >> 24) & 0xf;
462	bfbl->bfbl_pageoffbit = (*reg >> 28) & 0x1;
463}
464
465static __inline void
466wiifb_bottomfieldbasel_write(struct wiifb_softc *sc,
467    struct wiifb_bottomfieldbasel *bfbl)
468{
469	volatile uint32_t *reg =
470	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BOTTOMFIELDBASEL);
471
472	*reg  = ((bfbl->bfbl_pageoffbit & 0x1) << 28) |
473	        ((bfbl->bfbl_xoffset & 0xf) << 24)    |
474		 (bfbl->bfbl_fbaddr & 0xffffff);
475	powerpc_sync();
476}
477
478/*
479 * Bottom Field Base Right
480 * 32 bit
481 */
482#define	WIIFB_REG_BOTTOMFIELDBASER	0x28
483struct wiifb_bottomfieldbaser {
484	uint32_t	bfbr_fbaddr;
485	uint8_t		bfbr_pageoffbit;
486};
487
488static __inline void
489wiifb_bottomfieldbaser_read(struct wiifb_softc *sc,
490    struct wiifb_bottomfieldbaser *bfbr)
491{
492	volatile uint32_t *reg =
493	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BOTTOMFIELDBASER);
494
495	bfbr->bfbr_fbaddr     = *reg & 0xffffff;
496	bfbr->bfbr_pageoffbit = (*reg >> 28) & 0x1;
497}
498
499static __inline void
500wiifb_bottomfieldbaser_write(struct wiifb_softc *sc,
501    struct wiifb_bottomfieldbaser *bfbr)
502{
503	volatile uint32_t *reg =
504	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BOTTOMFIELDBASER);
505
506	*reg  = ((bfbr->bfbr_pageoffbit & 0x1) << 28) |
507		 (bfbr->bfbr_fbaddr & 0xffffff);
508	powerpc_sync();
509}
510
511/*
512 * Display Position Vertical
513 * 16 bit
514 */
515#define	WIIFB_REG_DISPPOSV		0x2c
516static __inline uint16_t
517wiifb_dispposv_read(struct wiifb_softc *sc)
518{
519	volatile uint32_t *reg =
520	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_DISPPOSV);
521
522	return (*reg & 0x7ff);
523}
524
525static __inline void
526wiifb_dispposv_write(struct wiifb_softc *sc, uint16_t val)
527{
528	volatile uint32_t *reg =
529	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_DISPPOSV);
530
531	*reg = val & 0x7ff;
532	powerpc_sync();
533}
534
535/*
536 * Display Position Horizontal
537 * 16 bit
538 */
539#define	WIIFB_REG_DISPPOSH		0x2e
540static __inline uint16_t
541wiifb_dispposh_read(struct wiifb_softc *sc)
542{
543	volatile uint32_t *reg =
544	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_DISPPOSH);
545
546	return (*reg & 0x7ff);
547}
548
549static __inline void
550wiifb_dispposh_write(struct wiifb_softc *sc, uint16_t val)
551{
552	volatile uint32_t *reg =
553	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_DISPPOSH);
554
555	*reg = val & 0x7ff;
556	powerpc_sync();
557}
558
559/*
560 * Display Interrupts.
561 * There are 4 display interrupt registers, all 32 bit.
562 */
563#define	WIIFB_REG_DISPINT0		0x30
564#define	WIIFB_REG_DISPINT1		0x34
565#define	WIIFB_REG_DISPINT2		0x38
566#define	WIIFB_REG_DISPINT3		0x3c
567struct wiifb_dispint {
568	uint16_t	di_htiming;
569	uint16_t	di_vtiming;
570	uint8_t		di_enable;
571	uint8_t		di_irq;
572};
573
574static __inline void
575wiifb_dispint_read(struct wiifb_softc *sc, int regno, struct wiifb_dispint *di)
576{
577	volatile uint32_t *reg = (uint32_t *)(sc->sc_reg_addr +
578	    WIIFB_REG_DISPINT0 + regno * 4);
579
580	di->di_htiming = *reg & 0x3ff;
581	di->di_vtiming = (*reg >> 16) & 0x3ff;
582	di->di_enable   = (*reg >> 28) & 0x1;
583	di->di_irq      = (*reg >> 31) & 0x1;
584}
585
586static __inline void
587wiifb_dispint_write(struct wiifb_softc *sc, int regno, struct wiifb_dispint *di)
588{
589	volatile uint32_t *reg = (uint32_t *)(sc->sc_reg_addr +
590	    WIIFB_REG_DISPINT0 + regno * 4);
591
592	*reg = ((di->di_irq & 0x1) << 31)        |
593	       ((di->di_enable & 0x1) << 28)     |
594	       ((di->di_vtiming & 0x3ff) << 16)  |
595	        (di->di_htiming & 0x3ff);
596	powerpc_sync();
597}
598
599/*
600 * Display Latch 0
601 * 32 bit
602 */
603#define	WIIFB_REG_DISPLAYTCH0		0x40
604
605/*
606 * Display Latch 1
607 * 32 bit
608 */
609#define	WIIFB_REG_DISPLAYTCH1		0x44
610
611/*
612 * Picture Configuration
613 * 16 bit
614 */
615#define	WIIFB_REG_PICCONF		0x48
616struct wiifb_picconf {
617	uint8_t		pc_strides;	/* strides per line (words) */
618	uint8_t		pc_reads;	/* reads per line (words */
619};
620
621static __inline void
622wiifb_picconf_read(struct wiifb_softc *sc, struct wiifb_picconf *pc)
623{
624	volatile uint16_t *reg =
625	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_PICCONF);
626
627	pc->pc_strides = *reg & 0xff;
628	pc->pc_reads   = (*reg >> 8) & 0xff;
629}
630
631static __inline void
632wiifb_picconf_write(struct wiifb_softc *sc, struct wiifb_picconf *pc)
633{
634	volatile uint16_t *reg =
635	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_PICCONF);
636
637	*reg = ((pc->pc_reads & 0xff) << 8) |
638	        (pc->pc_strides & 0xff);
639	powerpc_sync();
640}
641
642/*
643 * Horizontal Scaling
644 * 16 bit
645 */
646#define	WIIFB_REG_HSCALING		0x4a
647struct wiifb_hscaling {
648	uint16_t	hs_step;
649	uint8_t		hs_enable;
650};
651
652static __inline void
653wiifb_hscaling_read(struct wiifb_softc *sc, struct wiifb_hscaling *hs)
654{
655	volatile uint16_t *reg =
656	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_HSCALING);
657
658	hs->hs_step   = *reg & 0x1ff;
659	hs->hs_enable = (*reg >> 12) & 0x1;
660}
661
662static __inline void
663wiifb_hscaling_write(struct wiifb_softc *sc, struct wiifb_hscaling *hs)
664{
665	volatile uint16_t *reg =
666	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_HSCALING);
667
668	*reg = ((hs->hs_step & 0x1ff) << 12) |
669	        (hs->hs_enable & 0x1);
670	powerpc_sync();
671}
672
673/*
674 * Filter Coeficient Table 0-6
675 * 32 bit
676 */
677#define	WIIFB_REG_FILTCOEFT0		0x4c
678#define	WIIFB_REG_FILTCOEFT1		0x50
679#define	WIIFB_REG_FILTCOEFT2		0x54
680#define	WIIFB_REG_FILTCOEFT3		0x58
681#define	WIIFB_REG_FILTCOEFT4		0x5c
682#define	WIIFB_REG_FILTCOEFT5		0x60
683#define	WIIFB_REG_FILTCOEFT6		0x64
684static __inline void
685wiifb_filtcoeft_write(struct wiifb_softc *sc, unsigned int regno,
686    uint32_t coeft)
687{
688	volatile uint32_t *reg =
689	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_FILTCOEFT0 + 4 * regno);
690
691	*reg = coeft;
692	powerpc_sync();
693}
694
695/*
696 * Anti-aliasing
697 * 32 bit
698 */
699#define	WIIFB_REG_ANTIALIAS		0x68
700static __inline void
701wiifb_antialias_write(struct wiifb_softc *sc, uint32_t antialias)
702{
703	volatile uint32_t *reg =
704	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_ANTIALIAS);
705
706	*reg = antialias;
707	powerpc_sync();
708}
709
710/*
711 * Video Clock
712 * 16 bit
713 */
714#define	WIIFB_REG_VIDEOCLK		0x6c
715static __inline uint8_t
716wiifb_videoclk_read(struct wiifb_softc *sc)
717{
718	volatile uint16_t *reg =
719	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_VIDEOCLK);
720
721	return (*reg & 0x1);
722}
723
724static __inline void
725wiifb_videoclk_write(struct wiifb_softc *sc, uint16_t clk54mhz)
726{
727	volatile uint16_t *reg =
728	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_VIDEOCLK);
729
730	*reg = clk54mhz & 0x1;
731	powerpc_sync();
732}
733
734/*
735 * DTV Status
736 * 16 bit
737 *
738 * DTV is another name for the Component Cable output.
739 */
740#define	WIIFB_REG_DTVSTATUS		0x6e
741static __inline uint16_t
742wiifb_dtvstatus_read(struct wiifb_softc *sc)
743{
744	volatile uint16_t *reg =
745	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_DTVSTATUS);
746
747	return (*reg & 0x1);
748}
749
750static __inline uint16_t
751wiifb_component_enabled(struct wiifb_softc *sc)
752{
753
754	return wiifb_dtvstatus_read(sc);
755}
756
757/*
758 * Horizontal Scaling Width
759 * 16 bit
760 */
761#define	WIIFB_REG_HSCALINGW		0x70
762static __inline uint16_t
763wiifb_hscalingw_read(struct wiifb_softc *sc)
764{
765	volatile uint16_t *reg =
766	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_HSCALINGW);
767
768	return (*reg & 0x3ff);
769}
770
771static __inline void
772wiifb_hscalingw_write(struct wiifb_softc *sc, uint16_t width)
773{
774	volatile uint16_t *reg =
775	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_HSCALINGW);
776
777	*reg = width & 0x3ff;
778	powerpc_sync();
779}
780
781/*
782 * Horizontal Border End
783 * For debug mode only. Not used by this driver.
784 * 16 bit
785 */
786#define	WIIFB_REG_HBORDEREND		0x72
787static __inline void
788wiifb_hborderend_write(struct wiifb_softc *sc, uint16_t border)
789{
790	volatile uint16_t *reg =
791	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_HBORDEREND);
792
793	*reg = border;
794	powerpc_sync();
795}
796
797/*
798 * Horizontal Border Start
799 * 16 bit
800 */
801#define	WIIFB_REG_HBORDERSTART		0x74
802static __inline void
803wiifb_hborderstart_write(struct wiifb_softc *sc, uint16_t border)
804{
805	volatile uint16_t *reg =
806	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_HBORDERSTART);
807
808	*reg = border;
809	powerpc_sync();
810}
811
812/*
813 * Unknown register
814 * 16 bit
815 */
816#define	WIIFB_REG_UNKNOWN1		0x76
817static __inline void
818wiifb_unknown1_write(struct wiifb_softc *sc, uint16_t unknown)
819{
820	volatile uint16_t *reg =
821	    (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_UNKNOWN1);
822
823	*reg = unknown;
824	powerpc_sync();
825}
826
827/*
828 * Unknown register
829 * 32 bit
830 */
831#define	WIIFB_REG_UNKNOWN2		0x78
832static __inline void
833wiifb_unknown2_write(struct wiifb_softc *sc, uint32_t unknown)
834{
835	volatile uint32_t *reg =
836	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_UNKNOWN2);
837
838	*reg = unknown;
839	powerpc_sync();
840}
841
842/*
843 * Unknown register
844 * 32 bit
845 */
846#define	WIIFB_REG_UNKNOWN3		0x7c
847static __inline void
848wiifb_unknown3_write(struct wiifb_softc *sc, uint32_t unknown)
849{
850	volatile uint32_t *reg =
851	    (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_UNKNOWN3);
852
853	*reg = unknown;
854	powerpc_sync();
855}
856
857#endif /* _POWERPC_WII_WIIFB_H */
858