1 /* $NetBSD: pxg.c,v 1.32 2009/05/12 14:47:04 cegger Exp $ */
4 * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Driver for DEC PixelStamp graphics accelerators with onboard SRAM and
34 * Intel i860 co-processor (PMAG-D, E and F).
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: pxg.c,v 1.32 2009/05/12 14:47:04 cegger Exp $");
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/device.h>
43 #include <sys/malloc.h>
44 #include <sys/callout.h>
46 #include <sys/kauth.h>
49 #include <mips/cpuregs.h>
51 #include <alpha/alpha_cpu.h>
54 #include <machine/autoconf.h>
60 #include <dev/wscons/wsconsio.h>
61 #include <dev/wscons/wsdisplayvar.h>
63 #include <dev/ic/bt459reg.h>
65 #include <dev/tc/tcvar.h>
66 #include <dev/tc/sticreg.h>
67 #include <dev/tc/sticio.h>
68 #include <dev/tc/sticvar.h>
69 #include <dev/tc/pxgvar.h>
71 #define PXG_STIC_POLL_OFFSET 0x000000 /* STIC DMA poll space */
72 #define PXG_STAMP_OFFSET 0x0c0000 /* pixelstamp space on STIC */
73 #define PXG_STIC_OFFSET 0x180000 /* STIC registers */
74 #define PXG_SRAM_OFFSET 0x200000 /* 128 or 256kB of SRAM */
75 #define PXG_HOST_INTR_OFFSET 0x280000 /* i860 host interrupt */
76 #define PXG_COPROC_INTR_OFFSET 0x2c0000 /* i860 coprocessor interrupt */
77 #define PXG_VDAC_OFFSET 0x300000 /* VDAC registers (bt459) */
78 #define PXG_VDAC_RESET_OFFSET 0x340000 /* VDAC reset register */
79 #define PXG_ROM_OFFSET 0x380000 /* ROM code */
80 #define PXG_I860_START_OFFSET 0x380000 /* i860 start register */
81 #define PXG_I860_RESET_OFFSET 0x3c0000 /* i860 stop register */
83 static void pxg_attach(device_t
, device_t
, void *);
84 static int pxg_intr(void *);
85 static int pxg_match(device_t
, cfdata_t
, void *);
87 static void pxg_init(struct stic_info
*);
88 static int pxg_ioctl(struct stic_info
*, u_long
, void *, int, struct lwp
*);
89 static uint32_t *pxg_pbuf_get(struct stic_info
*);
90 static int pxg_pbuf_post(struct stic_info
*, uint32_t *);
91 static int pxg_probe_planes(struct stic_info
*);
92 static int pxg_probe_sram(struct stic_info
*);
94 void pxg_cnattach(tc_addr_t
);
97 struct stic_info
*pxg_si
;
100 CFATTACH_DECL_NEW(pxg
, sizeof(struct pxg_softc
),
101 pxg_match
, pxg_attach
, NULL
, NULL
);
103 static const char *pxg_types
[] = {
112 pxg_match(device_t parent
, cfdata_t match
, void *aux
)
114 struct tc_attach_args
*ta
;
119 for (i
= 0; i
< sizeof(pxg_types
) / sizeof(pxg_types
[0]); i
++)
120 if (strncmp(pxg_types
[i
], ta
->ta_modname
, TC_ROM_LLEN
) == 0)
127 pxg_attach(device_t parent
, device_t self
, void *aux
)
129 struct stic_info
*si
;
130 struct tc_attach_args
*ta
;
131 struct pxg_softc
*pxg
;
134 pxg
= device_private(self
);
135 ta
= (struct tc_attach_args
*)aux
;
137 if (ta
->ta_addr
== stic_consinfo
.si_slotbase
) {
141 if (stic_consinfo
.si_slotbase
== 0)
144 si
= malloc(sizeof(*si
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
146 si
->si_slotbase
= ta
->ta_addr
;
153 tc_intr_establish(parent
, ta
->ta_cookie
, IPL_TTY
, pxg_intr
, si
);
155 printf(": %d plane, %dx%d stamp, %dkB SRAM\n", si
->si_depth
,
156 si
->si_stampw
, si
->si_stamph
, (int)si
->si_buf_size
>> 10);
158 stic_attach(self
, si
, console
);
161 /* Load the co-processor "firmware". */
162 for (i
= 0; i
< sizeof(pxg_fwsegs
) / sizeof(pxg_fwsegs
[0]); i
++)
163 pxg_load_fwseg(si
, &pxg_fwsegs
[i
]);
165 /* Start the i860. */
166 si
->si_slotbase
[PXG_I860_START_OFFSET
>> 2] = 1;
174 pxg_cnattach(tc_addr_t addr
)
176 struct stic_info
*si
;
179 si
->si_slotbase
= addr
;
185 pxg_init(struct stic_info
*si
)
187 volatile uint32_t *slot
;
190 kva
= (void *)si
->si_slotbase
;
192 si
->si_vdac
= (uint32_t *)(kva
+ PXG_VDAC_OFFSET
);
193 si
->si_vdac_reset
= (uint32_t *)(kva
+ PXG_VDAC_RESET_OFFSET
);
194 si
->si_stic
= (volatile struct stic_regs
*)(kva
+ PXG_STIC_OFFSET
);
195 si
->si_stamp
= (uint32_t *)(kva
+ PXG_STAMP_OFFSET
);
196 si
->si_buf
= (uint32_t *)(kva
+ PXG_SRAM_OFFSET
);
197 si
->si_buf_phys
= STIC_KSEG_TO_PHYS(si
->si_buf
);
198 si
->si_buf_size
= pxg_probe_sram(si
);
199 si
->si_disptype
= WSDISPLAY_TYPE_PXG
;
200 si
->si_sxc
= (volatile struct stic_xcomm
*)si
->si_buf
;
202 si
->si_pbuf_get
= pxg_pbuf_get
;
203 si
->si_pbuf_post
= pxg_pbuf_post
;
204 si
->si_ioctl
= pxg_ioctl
;
206 /* Disable the co-processor. */
207 slot
= (volatile uint32_t *)kva
;
208 slot
[PXG_I860_RESET_OFFSET
>> 2] = 0;
210 slot
[PXG_HOST_INTR_OFFSET
>> 2] = 0;
215 /* XXX Check for a second PixelStamp. */
216 if (((si
->si_stic
->sr_modcl
& 0x600) >> 9) > 1)
219 si
->si_depth
= pxg_probe_planes(si
);
225 pxg_probe_sram(struct stic_info
*si
)
227 volatile uint32_t *a
, *b
;
229 a
= (volatile uint32_t *)si
->si_slotbase
+ (PXG_SRAM_OFFSET
>> 2);
230 b
= a
+ (0x20000 >> 2);
234 return ((*a
== *b
) ? 0x20000 : 0x40000);
238 pxg_probe_planes(struct stic_info
*si
)
240 volatile uint32_t *vdac
;
244 * For the visible framebuffer (# 0), we can cheat and use the VDAC
248 vdac
[BT459_REG_ADDR_LOW
] = (BT459_IREG_ID
& 0xff) |
249 ((BT459_IREG_ID
& 0xff) << 8) | ((BT459_IREG_ID
& 0xff) << 16);
250 vdac
[BT459_REG_ADDR_HIGH
] = ((BT459_IREG_ID
& 0xff00) >> 8) |
251 (BT459_IREG_ID
& 0xff00) | ((BT459_IREG_ID
& 0xff00) << 8);
253 id
= vdac
[BT459_REG_IREG_DATA
] & 0x00ffffff;
256 if (id
== 0x004a4a4a)
260 if ((id
& 0xff0000) == 0x4a0000 || (id
& 0x00ff00) == 0x004a00 ||
261 (id
& 0x0000ff) == 0x00004a)
264 /* XXX Assume 8 planes. */
265 printf("pxg_probe_planes: invalid VDAC ID %x\n", id
);
270 pxg_intr(void *cookie
)
273 struct stic_info
*si
;
274 volatile struct stic_regs
*sr
;
275 volatile uint32_t *hi
;
281 state
= sr
->sr_ipdvint
;
282 hi
= (volatile uint32_t *)si
->si_slotbase
+
283 (PXG_HOST_INTR_OFFSET
/ sizeof(uint32_t));
285 /* Clear the interrupt condition */
294 sr
->sr_ipdvint
= STIC_INT_V_WE
| STIC_INT_V_EN
;
300 printf("pxg_intr: how did this happen?\n");
306 pxg_pbuf_get(struct stic_info
*si
)
310 si
->si_pbuf_select
^= STIC_PACKET_SIZE
;
311 off
= si
->si_pbuf_select
+ STIC_XCOMM_SIZE
;
312 return ((uint32_t *)((char *)si
->si_buf
+ off
));
316 pxg_pbuf_post(struct stic_info
*si
, uint32_t *buf
)
318 volatile uint32_t *poll
, junk
;
319 volatile struct stic_regs
*sr
;
325 /* Get address of poll register for this buffer. */
326 v
= ((u_long
)buf
- (u_long
)si
->si_buf
) >> 9;
327 poll
= (volatile uint32_t *)((char *)si
->si_slotbase
+ v
);
330 * Read the poll register and make sure the stamp wants to accept
331 * our packet. This read will initiate the DMA. Don't wait for
332 * ever, just in case something's wrong.
336 for (c
= STAMP_RETRIES
; c
!= 0; c
--) {
337 if ((sr
->sr_ipdvint
& STIC_INT_P
) != 0) {
338 sr
->sr_ipdvint
= STIC_INT_P_WE
;
346 /* STIC has lost the plot, punish it. */
352 pxg_ioctl(struct stic_info
*si
, u_long cmd
, void *data
, int flag
,
355 struct stic_xinfo
*sxi
;
356 volatile uint32_t *ptr
= NULL
;
360 case STICIO_START860
:
361 case STICIO_RESET860
:
362 if ((rv
= kauth_authorize_generic(l
->l_cred
,
363 KAUTH_GENERIC_ISSUSER
, NULL
)) != 0)
365 if (si
->si_dispmode
!= WSDISPLAYIO_MODE_MAPPED
)
367 ptr
= (volatile uint32_t *)si
->si_slotbase
;
372 case STICIO_START860
:
374 ptr
[PXG_I860_START_OFFSET
>> 2] = 1;
380 case STICIO_RESET860
:
382 ptr
[PXG_I860_RESET_OFFSET
>> 2] = 0;
389 sxi
= (struct stic_xinfo
*)data
;
390 sxi
->sxi_unit
= si
->si_unit
;
391 sxi
->sxi_stampw
= si
->si_stampw
;
392 sxi
->sxi_stamph
= si
->si_stamph
;
393 sxi
->sxi_buf_size
= si
->si_buf_size
;
394 sxi
->sxi_buf_phys
= 0;
395 sxi
->sxi_buf_pktoff
= STIC_XCOMM_SIZE
;
396 sxi
->sxi_buf_pktcnt
= 2;
397 sxi
->sxi_buf_imgoff
= STIC_XCOMM_SIZE
+ STIC_PACKET_SIZE
* 2;
411 pxg_load_fwseg(struct stic_info
*si
, struct pxg_fwseg
*pfs
)
417 dst
= (uint32_t *)((void *)si
->si_buf
+ pfs
->pfs_addr
);
420 for (left
= pfs
->pfs_compsize
; left
!= 0; left
-= 4) {
421 if (src
[0] == PXGFW_RLE_MAGIC
) {
422 for (i
= src
[2]; i
!= 0; i
--)
432 memset(dst
, 0, pfs
->pfs_realsize
);