xref: /netbsd-src/sys/arch/ews4800mips/sbd/fb_sbdio.c (revision 0df165c04d0a9ca1adde9ed2b890344c937954a6)
1 /*	$NetBSD: fb_sbdio.c,v 1.5 2007/03/17 13:51:46 msaitoh Exp $	*/
2 
3 /*-
4  * Copyright (c) 2004, 2005 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by UCHIYAMA Yasushi.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #define WIRED_FB_TLB
40 
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: fb_sbdio.c,v 1.5 2007/03/17 13:51:46 msaitoh Exp $");
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/malloc.h>
47 #include <dev/cons.h>
48 
49 #include <uvm/uvm_extern.h>     /* pmap function to remap FB */
50 
51 #include <dev/wscons/wsconsio.h>
52 #include <dev/wscons/wsdisplayvar.h>
53 #include <dev/wsfont/wsfont.h>
54 #include <dev/rasops/rasops.h>
55 
56 #include <mips/pte.h>
57 
58 #include <machine/locore.h>
59 #include <machine/sbdiovar.h>
60 
61 #include <machine/gareg.h>
62 #include <machine/gavar.h>
63 
64 #include <machine/vmparam.h>
65 #include <machine/wired_map.h>
66 
67 
68 struct fb_softc {
69 	struct device sc_dv;
70 	struct rasops_info *sc_ri;
71 	struct ga *sc_ga;
72 	int sc_nscreens;
73 };
74 
75 int fb_sbdio_match(struct device *, struct cfdata *, void *);
76 void fb_sbdio_attach(struct device *, struct device *, void *);
77 
78 CFATTACH_DECL(fb_sbdio, sizeof(struct fb_softc),
79     fb_sbdio_match, fb_sbdio_attach, NULL, NULL);
80 
81 int _fb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
82 paddr_t _fb_mmap(void *, void *, off_t, int);
83 int _fb_alloc_screen(void *, const struct wsscreen_descr *, void **,
84     int *, int *, long *);
85 void _fb_free_screen(void *, void *);
86 int _fb_show_screen(void *, void *, int, void (*)(void *, int, int), void *);
87 void _fb_pollc(void *, int);
88 void fb_common_init(struct rasops_info *, struct ga *);
89 int fb_sbdio_cnattach(uint32_t, uint32_t, int);
90 void fb_pmap_enter(paddr_t, paddr_t, vaddr_t *, vaddr_t *);
91 
92 struct wsscreen_descr _fb_std_screen = {
93 	"std", 0, 0,
94 	0, /* textops */
95 	0, 0,
96 	0
97 };
98 
99 const struct wsscreen_descr *_fb_screen_table[] = {
100 	&_fb_std_screen,
101 };
102 
103 struct wsscreen_list _fb_screen_list = {
104 	.nscreens	=
105 	    sizeof(_fb_screen_table) / sizeof(_fb_screen_table[0]),
106 	.screens	= _fb_screen_table
107 };
108 
109 struct wsdisplay_accessops _fb_accessops = {
110 	.ioctl		= _fb_ioctl,
111 	.mmap		= _fb_mmap,
112 	.alloc_screen	= _fb_alloc_screen,
113 	.free_screen	= _fb_free_screen,
114 	.show_screen	= _fb_show_screen,
115 	.load_font	= 0,
116 	.pollc		= _fb_pollc
117 };
118 
119 /* console stuff */
120 static struct rasops_info fb_console_ri;
121 static struct ga fb_console_ga;
122 static paddr_t fb_consaddr;
123 
124 
125 int
126 fb_sbdio_match(struct device *parent, struct cfdata *match, void *aux)
127 {
128 	struct sbdio_attach_args *sa = aux;
129 
130 	return strcmp(sa->sa_name, "fb") ? 0 : 1;
131 }
132 
133 void
134 fb_sbdio_attach(struct device *parent, struct device *self, void *aux)
135 {
136 	struct sbdio_attach_args *sa = aux;
137 	struct wsemuldisplaydev_attach_args wa;
138 	struct fb_softc *sc = (void *)self;
139 	struct rasops_info *ri;
140 	struct ga *ga;
141 	vaddr_t memva, regva;
142 	int console;
143 
144 	printf(" at %p, %p\n", (void *)sa->sa_addr1, (void *)sa->sa_addr2);
145 
146 	console = (sa->sa_addr1 == fb_consaddr);
147 	if (console) {
148 		/* already initialized in fb_cnattach() */
149 		sc->sc_ri = ri = &fb_console_ri;
150 		sc->sc_ga = &fb_console_ga;
151 		sc->sc_nscreens = 1;
152 	} else {
153 		ri = malloc(sizeof(struct rasops_info), M_DEVBUF,
154 		    M_NOWAIT | M_ZERO);
155 		if (ri == NULL) {
156 			printf(":can't allocate rasops memory\n");
157 			return;
158 		}
159 		ga = malloc(sizeof(struct ga), M_DEVBUF, M_NOWAIT | M_ZERO);
160 		if (ga == NULL) {
161 			printf(":can't allocate ga memory\n");
162 			return;
163 		}
164 		ga->reg_paddr = sa->sa_addr2;
165 		ga->flags = sa->sa_flags;
166 		fb_pmap_enter(sa->sa_addr1, sa->sa_addr2,
167 		    &memva, &regva);
168 		ri->ri_bits = (void *)memva;
169 		ga->reg_addr = regva;
170 		fb_common_init(ri, ga);
171 		sc->sc_ri = ri;
172 		sc->sc_ga = ga;
173 	}
174 
175 	wa.console = console;
176 	wa.scrdata = &_fb_screen_list;
177 	wa.accessops = &_fb_accessops;
178 	wa.accesscookie	= (void *)sc;
179 
180 	config_found(self, &wa, wsdisplaydevprint);
181 }
182 
183 void
184 fb_common_init(struct rasops_info *ri, struct ga *ga)
185 {
186 	int ga_active, cookie;
187 
188 	/* XXX */
189 	ga_active = 0;
190 	if (ga->flags == 0x0000 || ga->flags == 0x0001)
191 		ga_active = ga_init(ga);
192 
193 	/*
194 	 * TR2 IPL CLUT.
195 	 * 0     black
196 	 * 1	 red
197 	 * 2	 green
198 	 * 4	 blue
199 	 * 8	 yellow
200 	 * 16	 cyan
201 	 * 32	 magenta
202 	 * 64	 light gray
203 	 * 128	 dark gray
204 	 * 255	 white
205 	 * other black
206 	 * When CLUT isn't initialized for NetBSD, use black-red pair.
207 	 */
208 	ri->ri_flg = RI_CENTER | RI_CLEAR;
209 	if (!ga_active)
210 		ri->ri_flg |= RI_FORCEMONO;
211 
212 	ri->ri_depth = 8;
213 	ri->ri_width = 1280;
214 	ri->ri_height = 1024;
215 	ri->ri_stride = 2048;
216 	ri->ri_hw = (void *)ga;
217 
218 	wsfont_init();
219 	/* prefer 12 pixel wide font */
220 	cookie = wsfont_find(NULL, 12, 0, 0, 0, 0);
221 	if (cookie <= 0)
222 		cookie = wsfont_find(NULL, 0, 0, 0, 0, 0);
223 	if (cookie <= 0) {
224 		printf("sfb: font table is empty\n");
225 		return;
226 	}
227 
228 	if (wsfont_lock(cookie, &ri->ri_font)) {
229 		printf("fb: can't lock font\n");
230 		return;
231 	}
232 	ri->ri_wsfcookie = cookie;
233 
234 	rasops_init(ri, 34, 80);
235 
236 #if 0
237 	/* XXX no accelarated functions yet */
238 	ri->ri_ops.putchar = xxx_putchar;
239 	ri->ri_ops.erasecols = xxx_erasecols;
240 	ri->ri_ops.copyrows = xxx_copyrows;
241 	ri->ri_ops.eraserows = xxx_eraserows;
242 	ir->ri_do_cursor = xxx_do_cursor;
243 #endif
244 
245 	/* XXX shouldn't be global */
246 	_fb_std_screen.nrows = ri->ri_rows;
247 	_fb_std_screen.ncols = ri->ri_cols;
248 	_fb_std_screen.textops = &ri->ri_ops;
249 	_fb_std_screen.capabilities = ri->ri_caps;
250 }
251 
252 int
253 fb_sbdio_cnattach(uint32_t mem, uint32_t reg, int flags)
254 {
255 	struct rasops_info *ri;
256 	struct ga *ga;
257 	vaddr_t memva, regva;
258 	long defattr;
259 
260 	ri = &fb_console_ri;
261 	ga = &fb_console_ga;
262 
263 	ga->reg_paddr = reg;
264 	ga->flags = flags;
265 	fb_pmap_enter((paddr_t)mem, (paddr_t)reg, &memva, &regva);
266 	ri->ri_bits = (void *)memva;
267 	ga->reg_addr = regva;
268 
269 	fb_common_init(ri, ga);
270 
271 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
272 	wsdisplay_cnattach(&_fb_std_screen, ri, 0, 0, defattr);
273 	fb_consaddr = mem;
274 
275 	return 0;
276 }
277 
278 int
279 _fb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
280 {
281 	struct fb_softc *sc = v;
282 	struct wsdisplay_fbinfo *fbinfo = (void *)data;
283 	struct wsdisplay_cmap *cmap = (void *)data;
284 	struct rasops_info *ri = sc->sc_ri;
285 	struct ga *ga = sc->sc_ga;
286 	int i;
287 
288 	switch (cmd) {
289 	case WSDISPLAYIO_GTYPE:
290 		*(uint32_t *)data = WSDISPLAY_TYPE_UNKNOWN;
291 		return 0;
292 
293 	case WSDISPLAYIO_GINFO:
294 		fbinfo->height = ri->ri_height;
295 		fbinfo->width  = ri->ri_width;
296 		fbinfo->depth  = ri->ri_depth;
297 		fbinfo->cmsize = 256;
298 		return 0;
299 
300 #if 1
301 	case WSDISPLAYIO_LINEBYTES:
302 		*(u_int *)data = ri->ri_stride;
303 		return 0;
304 
305 #endif
306 	case WSDISPLAYIO_GETCMAP:
307 		if (ri->ri_flg == RI_FORCEMONO)
308 			break;
309 		ga_clut_get(ga);
310 		for (i = 0; i < cmap->count; i++) {
311 			cmap->red[i] = ga->clut[cmap->index + i][0];
312 			cmap->green[i] = ga->clut[cmap->index + i][1];
313 			cmap->blue[i] = ga->clut[cmap->index + i][2];
314 		}
315 		return 0;
316 
317 	case WSDISPLAYIO_PUTCMAP:
318 		if (ri->ri_flg == RI_FORCEMONO)
319 			break;
320 		for (i = 0; i < cmap->count; i++) {
321 			ga->clut[cmap->index + i][0] = cmap->red[i];
322 			ga->clut[cmap->index + i][1] = cmap->green[i];
323 			ga->clut[cmap->index + i][2] = cmap->blue[i];
324 		}
325 		ga_clut_set(ga);
326 		return 0;
327 	}
328 
329 	return EPASSTHROUGH;
330 }
331 
332 paddr_t
333 _fb_mmap(void *v, void *vs, off_t offset, int prot)
334 {
335 
336 	if (offset < 0 || offset >= GA_FRB_SIZE)
337 		return -1;
338 
339 	return mips_btop(GA_FRB_ADDR + offset);
340 }
341 
342 int
343 _fb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookie,
344     int *curx, int *cury, long *attr)
345 {
346 	struct fb_softc *sc = v;
347 	struct rasops_info *ri = sc->sc_ri;
348 	long defattr;
349 
350 #if 0
351 	if (sc->sc_nscreens > 0)
352 		return ENOMEM;
353 #endif
354 
355 	*cookie = ri;
356 	*curx = *cury = 0;
357 	ri->ri_ops.allocattr(ri, 0, 0, 0, &defattr);
358 	*attr = defattr;
359 	sc->sc_nscreens++;
360 
361 	return 0;
362 }
363 
364 void
365 _fb_free_screen(void *v, void *cookie)
366 {
367 	struct fb_softc *sc = v;
368 
369 	sc->sc_nscreens--;
370 }
371 
372 int
373 _fb_show_screen(void *v, void *cookie, int waitok,
374     void (*cb)(void *, int, int), void *cbarg)
375 {
376 
377 	return 0;
378 }
379 
380 void
381 _fb_pollc(void *v, int on)
382 {
383 
384 	/* no interrupt used. */
385 }
386 
387 void
388 fb_pmap_enter(paddr_t fb_paddr, paddr_t reg_paddr,
389     vaddr_t *fb_vaddr, vaddr_t *reg_vaddr)
390 {
391 #ifdef WIRED_FB_TLB	/* Make wired 16MPage for frame buffer */
392 	vaddr_t va;
393 	vsize_t fb_off, reg_off, pgsize;
394 
395 	pgsize = MIPS3_WIRED_SIZE;
396 	fb_off  = fb_paddr  & MIPS3_WIRED_OFFMASK;
397 	reg_off = reg_paddr & MIPS3_WIRED_OFFMASK;
398 	fb_paddr  = fb_paddr  & ~MIPS3_WIRED_OFFMASK;
399 	reg_paddr = reg_paddr & ~MIPS3_WIRED_OFFMASK;
400 	va = GA_FRB_ADDR;
401 
402 	if (mips3_wired_enter_page(va, fb_paddr, pgsize) == false) {
403 		printf("cannot allocate fb memory\n");
404 		return;
405 	}
406 
407 	if (mips3_wired_enter_page(va + pgsize, reg_paddr, pgsize) == false) {
408 		printf("cannot allocate fb register\n");
409 		return;
410 	}
411 
412 	*fb_vaddr  = va + fb_off;
413 	*reg_vaddr = va + pgsize + reg_off;
414 #else /* WIRED_FB_TLB */
415 	paddr_t pa, epa;
416 	vaddr_t va, tva;
417 
418 	pa = addr;
419 	epa = pa + size;
420 
421 	va = uvm_km_alloc(kernel_map, epa - pa, 0, UVM_KMF_VAONLY);
422 	if (va == 0)
423 		for (;;)
424 			ROM_MONITOR();
425 
426 	for (tva = va; pa < epa; pa += PAGE_SIZE, tva += PAGE_SIZE)
427 		pmap_kenter_pa(tva, pa, VM_PROT_READ | VM_PROT_WRITE);
428 
429 	pmap_update(pmap_kernel());
430 
431 	*fb_vaddr  = va;
432 #endif /* WIRED_FB_TLB */
433 }
434