1 /* $NetBSD: px.c,v 1.36 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 adapters (PMAG-C).
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: px.c,v 1.36 2009/05/12 14:47:04 cegger Exp $");
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/malloc.h>
43 #include <sys/callout.h>
45 #include <uvm/uvm_extern.h>
48 #include <mips/cpuregs.h>
50 #include <alpha/alpha_cpu.h>
53 #include <machine/autoconf.h>
59 #include <dev/wscons/wsconsio.h>
60 #include <dev/wscons/wsdisplayvar.h>
62 #include <dev/ic/bt459reg.h>
64 #include <dev/tc/tcvar.h>
65 #include <dev/tc/sticreg.h>
66 #include <dev/tc/sticio.h>
67 #include <dev/tc/sticvar.h>
69 #define PX_STIC_POLL_OFFSET 0x000000 /* STIC DMA poll space */
70 #define PX_STAMP_OFFSET 0x0c0000 /* pixelstamp space on STIC */
71 #define PX_STIC_OFFSET 0x180000 /* STIC registers */
72 #define PX_VDAC_OFFSET 0x200000 /* VDAC registers (bt459) */
73 #define PX_VDAC_RESET_OFFSET 0x300000 /* VDAC reset register */
74 #define PX_ROM_OFFSET 0x300000 /* ROM code */
76 #define PX_BUF_COUNT 16
77 #define PX_BUF_INC(x) ((x + 1) & (PX_BUF_COUNT - 1))
80 * We need enough aligned memory to hold:
82 * - Xserver communication area (4096 bytes)
83 * - 16 packet buffers (4096 bytes each)
84 * - 2 image buffers (5120 bytes each)
88 (STIC_PACKET_SIZE * PX_BUF_COUNT + STIC_IMGBUF_SIZE*2 + STIC_XCOMM_SIZE)
89 #define PX_BUF_ALIGN 32768
91 #define PXF_QUEUE 0x01
93 static void px_attach(device_t
, device_t
, void *);
94 static void px_init(struct stic_info
*, int);
95 static int px_ioctl(struct stic_info
*, u_long
, void *, int,
97 static int px_match(device_t
, cfdata_t
, void *);
99 static int px_intr(void *);
100 static uint32_t *px_pbuf_get(struct stic_info
*);
101 static int px_pbuf_post(struct stic_info
*, uint32_t *);
103 void px_cnattach(tc_addr_t
);
107 struct stic_info
*px_si
;
108 volatile uint32_t *px_qpoll
[PX_BUF_COUNT
];
111 CFATTACH_DECL_NEW(px
, sizeof(struct px_softc
),
112 px_match
, px_attach
, NULL
, NULL
);
115 px_match(device_t parent
, cfdata_t match
, void *aux
)
117 struct tc_attach_args
*ta
;
121 return (strncmp("PMAG-CA ", ta
->ta_modname
, TC_ROM_LLEN
) == 0);
125 px_attach(device_t parent
, device_t self
, void *aux
)
127 struct stic_info
*si
;
128 struct tc_attach_args
*ta
;
133 px
= device_private(self
);
134 ta
= (struct tc_attach_args
*)aux
;
138 if (ta
->ta_addr
== stic_consinfo
.si_slotbase
) {
142 if (stic_consinfo
.si_slotbase
== 0)
145 si
= malloc(sizeof(*si
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
147 si
->si_slotbase
= ta
->ta_addr
;
154 tc_intr_establish(parent
, ta
->ta_cookie
, IPL_TTY
, px_intr
, si
);
156 printf(": 8 plane, %dx%d stamp\n", si
->si_stampw
, si
->si_stamph
);
158 for (i
= 0; i
< PX_BUF_COUNT
; i
++) {
159 v
= i
* STIC_PACKET_SIZE
+
160 si
->si_buf_phys
+ STIC_XCOMM_SIZE
;
161 v
= ((v
& 0xffff8000) << 3) | (v
& 0x7fff);
162 px
->px_qpoll
[i
] = (volatile uint32_t *)
163 ((char *)si
->si_slotbase
+ (v
>> 9));
166 stic_attach(self
, si
, console
);
170 px_cnattach(tc_addr_t addr
)
172 struct stic_info
*si
;
175 si
->si_slotbase
= addr
;
181 px_init(struct stic_info
*si
, int bootstrap
)
183 struct pglist pglist
;
187 kva
= (void *)si
->si_slotbase
;
190 * Allocate memory for the packet buffers. It must be located below
191 * 8MB, since the STIC can't access outside that region. Also, due
192 * to the holes in STIC address space, each buffer mustn't cross a
197 * UVM won't be initialised at this point, so grab memory
198 * directly from vm_physmem[].
200 bva
= (char *)uvm_pageboot_alloc(PX_BUF_SIZE
+ PX_BUF_ALIGN
);
201 bpa
= (STIC_KSEG_TO_PHYS(bva
) + PX_BUF_ALIGN
- 1) &
203 if (bpa
+ PX_BUF_SIZE
> 8192*1024)
204 panic("px_init: allocation out of bounds");
206 if (uvm_pglistalloc(PX_BUF_SIZE
, 0, 8192*1024, PX_BUF_ALIGN
,
207 0, &pglist
, 1, 0) != 0)
208 panic("px_init: allocation failure");
209 bpa
= VM_PAGE_TO_PHYS(TAILQ_FIRST(&pglist
));
212 si
->si_vdac
= (uint32_t *)(kva
+ PX_VDAC_OFFSET
);
213 si
->si_vdac_reset
= (uint32_t *)(kva
+ PX_VDAC_RESET_OFFSET
);
214 si
->si_stic
= (volatile struct stic_regs
*)(kva
+ PX_STIC_OFFSET
);
215 si
->si_stamp
= (uint32_t *)(kva
+ PX_STAMP_OFFSET
);
216 si
->si_buf
= (uint32_t *)TC_PHYS_TO_UNCACHED(bpa
);
217 si
->si_buf_phys
= bpa
;
218 si
->si_buf_size
= PX_BUF_SIZE
;
219 si
->si_disptype
= WSDISPLAY_TYPE_PX
;
221 si
->si_sxc
= (volatile struct stic_xcomm
*)si
->si_buf
;
223 si
->si_pbuf_get
= px_pbuf_get
;
224 si
->si_pbuf_post
= px_pbuf_post
;
225 si
->si_ioctl
= px_ioctl
;
227 memset(si
->si_buf
, 0, PX_BUF_SIZE
);
233 px_intr(void *cookie
)
235 volatile struct stic_regs
*sr
;
236 volatile struct stic_xcomm
*sxc
;
237 struct stic_info
*si
;
242 px
= (struct px_softc
*)si
->si_dv
;
244 state
= sr
->sr_ipdvint
;
248 * Vertical-retrace condition.
250 * Clear the flag and flush out any waiting VDAC updates. We do
251 * this at retrace time to avoid producing `shearing' and other
254 if ((state
& STIC_INT_V
) != 0) {
255 sr
->sr_ipdvint
= STIC_INT_V_WE
| STIC_INT_V_EN
;
263 * Simply clear the flag and report the error.
265 if ((state
& STIC_INT_E
) != 0) {
266 aprint_error_dev(px
->px_dev
, "error intr, %x %x %x %x %x",
267 sr
->sr_ipdvint
, sr
->sr_sticsr
, sr
->sr_buscsr
,
268 sr
->sr_busadr
, sr
->sr_busdat
);
269 sr
->sr_ipdvint
= STIC_INT_E_WE
| STIC_INT_E_EN
;
274 * Check for queue stalls.
276 if (sxc
->sxc_tail
!= sxc
->sxc_head
&& !sxc
->sxc_busy
)
280 * Packet-done condition.
282 * If packet queueing is enabled, clear the condition, and increment
283 * the tail (submitted) pointer.
285 if ((si
->si_hwflags
& PXF_QUEUE
) != 0 && (state
& STIC_INT_P
) != 0) {
286 sr
->sr_ipdvint
= STIC_INT_P_WE
| STIC_INT_P_EN
;
289 if (sxc
->sxc_tail
!= sxc
->sxc_head
) {
290 sxc
->sxc_done
[sxc
->sxc_tail
] = 0;
291 sxc
->sxc_tail
= PX_BUF_INC(sxc
->sxc_tail
);
294 if (sxc
->sxc_tail
!= sxc
->sxc_head
) {
295 if (*px
->px_qpoll
[sxc
->sxc_tail
] != STAMP_OK
) {
304 if ((si
->si_hwflags
& PXF_QUEUE
) != 0 && (state
& STIC_INT_P_EN
) == 0)
305 printf("px_intr: STIC_INT_P_EN == 0\n");
311 px_pbuf_get(struct stic_info
*si
)
315 si
->si_pbuf_select
^= STIC_PACKET_SIZE
;
316 off
= si
->si_pbuf_select
+ STIC_XCOMM_SIZE
;
317 return ((uint32_t *)((char *)si
->si_buf
+ off
));
321 px_pbuf_post(struct stic_info
*si
, uint32_t *buf
)
323 volatile uint32_t *poll
, junk
;
324 volatile struct stic_regs
*sr
;
330 /* Get address of poll register for this buffer. */
331 v
= (u_long
)STIC_KSEG_TO_PHYS(buf
);
332 v
= ((v
& 0xffff8000) << 3) | (v
& 0x7fff);
333 poll
= (volatile uint32_t *)((char *)si
->si_slotbase
+ (v
>> 9));
336 * Read the poll register and make sure the stamp wants to accept
337 * our packet. This read will initiate the DMA. Don't wait for
338 * ever, just in case something's wrong.
342 for (c
= STAMP_RETRIES
; c
!= 0; c
--) {
343 if ((sr
->sr_ipdvint
& STIC_INT_P
) != 0) {
344 sr
->sr_ipdvint
= STIC_INT_P_WE
;
352 /* STIC has lost the plot, punish it. */
358 px_ioctl(struct stic_info
*si
, u_long cmd
, void *data
, int flag
,
361 volatile struct stic_xcomm
*sxc
;
362 volatile struct stic_regs
*sr
;
363 struct stic_xinfo
*sxi
;
370 if (si
->si_dispmode
!= WSDISPLAYIO_MODE_MAPPED
||
371 (si
->si_hwflags
& PXF_QUEUE
) != 0) {
377 memset((void *)__UNVOLATILE(sxc
->sxc_done
), 0,
378 sizeof(sxc
->sxc_done
));
381 sxc
->sxc_nreject
= 0;
385 si
->si_hwflags
|= PXF_QUEUE
;
386 sr
->sr_ipdvint
= STIC_INT_P_WE
| STIC_INT_P_EN
;
395 si
->si_hwflags
&= ~PXF_QUEUE
;
396 sr
->sr_ipdvint
= STIC_INT_P_WE
| STIC_INT_P
;
403 sxi
= (struct stic_xinfo
*)data
;
404 sxi
->sxi_unit
= si
->si_unit
;
405 sxi
->sxi_stampw
= si
->si_stampw
;
406 sxi
->sxi_stamph
= si
->si_stamph
;
407 sxi
->sxi_buf_size
= si
->si_buf_size
;
408 sxi
->sxi_buf_phys
= (u_int
)si
->si_buf_phys
;
409 sxi
->sxi_buf_pktoff
= STIC_XCOMM_SIZE
;
410 sxi
->sxi_buf_pktcnt
= PX_BUF_COUNT
;
411 sxi
->sxi_buf_imgoff
=
412 STIC_XCOMM_SIZE
+ STIC_PACKET_SIZE
* PX_BUF_COUNT
;