1/*-
2 * Copyright (c) 2012 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * This software was developed by SRI International and the University of
6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7 * ("CTSRD"), as part of the DARPA CRASH research programme.
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 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34#include <sys/param.h>
35#include <sys/bus.h>
36#include <sys/conf.h>
37#include <sys/consio.h>
38#include <sys/fbio.h>
39#include <sys/kbio.h>
40#include <sys/kernel.h>
41#include <sys/lock.h>
42#include <sys/malloc.h>
43#include <sys/mutex.h>
44#include <sys/module.h>
45#include <sys/rman.h>
46#include <sys/systm.h>
47#include <sys/uio.h>
48
49#include <machine/bus.h>
50#include <machine/resource.h>
51#include <machine/vm.h>
52
53#include <dev/fb/fbreg.h>
54
55#include <dev/kbd/kbdreg.h>
56
57#include <dev/syscons/syscons.h>
58
59#include <dev/terasic/mtl/terasic_mtl.h>
60
61/*
62 * Terasic Multitouch LCD (MTL) syscons driver.  Implement syscons(4)'s
63 * video_switch_t KPI using MTL's text frame buffer.  In principle, we could
64 * actually implement sc_rndr_sw_t, since the MTL text frame buffer implements
65 * a VGA-like memory mapping.  However, this requires a lot more book-keeping
66 * with only minor performance improvements (avoiding indirection), as well as
67 * introducing potential endianness issues.  Instead we accept one additional
68 * memory copy between a software frame buffer and the hardware frame buffer
69 * and the generic frame buffer (gfb) framework.
70 */
71
72MALLOC_DEFINE(M_TERASIC_MTL, "mtl_syscons", "MTL syscons frame buffer");
73
74/*
75 * Run early so that boot-time console support can be initialised before
76 * newbus gets around to configuring syscons.
77 *
78 * XXXRW: We may need to do more here in order to see earlier boot messages.
79 */
80static int
81terasic_mtl_syscons_configure(int flags)
82{
83
84	printf("%s: not yet\n", __func__);
85	return (0);
86}
87
88static int
89terasic_mtl_vidsw_probe(int unit, video_adapter_t **adp, void *args,
90    int flags)
91{
92
93	printf("%s: not yet\n", __func__);
94	return (0);
95}
96
97static int
98terasic_mtl_vidsw_init(int unit, video_adapter_t *adp, int flags)
99{
100	struct terasic_mtl_softc *sc;
101	video_info_t *vi;
102
103	sc = (struct terasic_mtl_softc *)adp;
104
105	vi = &adp->va_info;
106	vid_init_struct(adp, "terasic_mtl_syscons", -1, unit);
107
108	vi->vi_width = TERASIC_MTL_COLS;
109	if (vi->vi_width > COL)
110		vi->vi_width = COL;
111	vi->vi_height = TERASIC_MTL_ROWS;
112	if (vi->vi_height > ROW)
113		vi->vi_height = ROW;
114
115	/*
116	 * XXXRW: It's not quite clear how these should be initialised.
117	 */
118	vi->vi_cwidth = 0;
119	vi->vi_cheight = 0;
120	vi->vi_flags = V_INFO_COLOR;
121	vi->vi_mem_model = V_INFO_MM_OTHER;
122
123	/*
124	 * Software text frame buffer from which we update the actual MTL
125	 * frame buffer when asked to.
126	 */
127	adp->va_window = (vm_offset_t)sc->mtl_text_soft;
128
129	/*
130	 * Declare video adapter capabilities -- at this point, simply color
131	 * support, as MTL doesn't support screen borders, font loading, or
132	 * mode changes.
133	 *
134	 * XXXRW: It's unclear if V_ADP_INITIALIZED is needed here; other
135	 * syscons(4) drivers are inconsistent about this and
136	 * V_ADP_REGISTERED.
137	 */
138	adp->va_flags |= V_ADP_COLOR | V_ADP_INITIALIZED;
139	if (vid_register(adp) < 0) {
140		device_printf(sc->mtl_dev, "%s: vid_register failed\n",
141		    __func__);
142		return (ENXIO);
143	}
144	adp->va_flags |= V_ADP_REGISTERED;
145	return (0);
146}
147
148static int
149terasic_mtl_vidsw_get_info(video_adapter_t *adp, int mode, video_info_t *info)
150{
151
152	bcopy(&adp->va_info, info, sizeof(*info));
153	return (0);
154}
155
156static int
157terasic_mtl_vidsw_query_mode(video_adapter_t *adp, video_info_t *info)
158{
159
160	printf("%s: not yet\n", __func__);
161	return (ENODEV);
162}
163
164static int
165terasic_mtl_vidsw_set_mode(video_adapter_t *adp, int mode)
166{
167
168	printf("%s: not yet\n", __func__);
169	return (ENODEV);
170}
171
172static int
173terasic_mtl_vidsw_save_font(video_adapter_t *adp, int page, int size,
174    int width, u_char *data, int c, int count)
175{
176
177	printf("%s: not yet\n", __func__);
178	return (ENODEV);
179}
180
181static int
182terasic_mtl_vidsw_load_font(video_adapter_t *adp, int page, int size,
183    int width, u_char *data, int c, int count)
184{
185
186	printf("%s: not yet\n", __func__);
187	return (ENODEV);
188}
189
190static int
191terasic_mtl_vidsw_show_font(video_adapter_t *adp, int page)
192{
193
194	printf("%s: not yet\n", __func__);
195	return (ENODEV);
196}
197
198static int
199terasic_mtl_vidsw_save_palette(video_adapter_t *adp, u_char *palette)
200{
201
202	printf("%s: not yet\n", __func__);
203	return (ENODEV);
204}
205
206static int
207terasic_mtl_vidsw_load_palette(video_adapter_t *adp, u_char *palette)
208{
209
210	printf("%s: not yet\n", __func__);
211	return (ENODEV);
212}
213
214static int
215terasic_mtl_vidsw_set_border(video_adapter_t *adp, int border)
216{
217
218	printf("%s: not yet\n", __func__);
219	return (ENODEV);
220}
221
222static int
223terasic_mtl_vidsw_save_state(video_adapter_t *adp, void *p, size_t size)
224{
225
226	printf("%s: not yet\n", __func__);
227	return (ENODEV);
228}
229
230static int
231terasic_mtl_vidsw_load_state(video_adapter_t *adp, void *p)
232{
233
234	printf("%s: not yet\n", __func__);
235	return (ENODEV);
236}
237
238static int
239terasic_mtl_vidsw_set_win_org(video_adapter_t *adp, off_t offset)
240{
241
242	printf("%s: not yet\n", __func__);
243	return (ENODEV);
244}
245
246static int
247terasic_mtl_vidsw_read_hw_cursor(video_adapter_t *adp, int *colp, int *rowp)
248{
249	struct terasic_mtl_softc *sc;
250	uint8_t col, row;
251
252	sc = (struct terasic_mtl_softc *)adp;
253	terasic_mtl_reg_textcursor_get(sc, &col, &row);
254	*colp = col;
255	*rowp = row;
256	return (0);
257}
258
259static int
260terasic_mtl_vidsw_set_hw_cursor(video_adapter_t *adp, int col, int row)
261{
262	struct terasic_mtl_softc *sc;
263
264	sc = (struct terasic_mtl_softc *)adp;
265	terasic_mtl_reg_textcursor_set(sc, col, row);
266	return (0);
267}
268
269static int
270terasic_mtl_vidsw_set_hw_cursor_shape(video_adapter_t *adp, int base,
271    int height, int celsize, int blink)
272{
273
274	printf("%s: not yet\n", __func__);
275	return (ENODEV);
276}
277
278static int
279terasic_mtl_vidsw_blank_display(video_adapter_t *adp, int mode)
280{
281	struct terasic_mtl_softc *sc;
282
283	sc = (struct terasic_mtl_softc *)adp;
284	terasic_mtl_reg_blank(sc);
285	return (0);
286}
287
288static int
289terasic_mtl_vidsw_mmap(video_adapter_t *adp, vm_ooffset_t offset,
290    vm_paddr_t *paddr, int prot, vm_memattr_t *memattr)
291{
292
293	printf("%s: not yet\n", __func__);
294	return (ENODEV);
295}
296
297static int
298terasic_mtl_vidsw_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
299{
300
301	return (fb_commonioctl(adp, cmd, data));
302}
303
304static int
305terasic_mtl_vidsw_clear(video_adapter_t *adp)
306{
307	struct terasic_mtl_softc *sc;
308
309	sc = (struct terasic_mtl_softc *)adp;
310	printf("%s: not yet terasic_mtl_io_clear(sc);\n", __func__);
311	return (0);
312}
313
314static int
315terasic_mtl_vidsw_fill_rect(video_adapter_t *adp, int val, int x, int y,
316    int cx, int cy)
317{
318
319	printf("%s: not yet\n", __func__);
320	return (ENODEV);
321}
322
323static int
324terasic_mtl_vidsw_bitblt(video_adapter_t *adp, ...)
325{
326
327	printf("%s: not yet\n", __func__);
328	return (ENODEV);
329}
330
331static int
332terasic_mtl_vidsw_diag(video_adapter_t *adp, int level)
333{
334
335	printf("%s: not yet\n", __func__);
336	return (ENODEV);
337}
338
339static int
340terasic_mtl_vidsw_save_cursor_palette(video_adapter_t *adp, u_char *palette)
341{
342
343	printf("%s: not yet\n", __func__);
344	return (ENODEV);
345}
346
347static int
348terasic_mtl_vidsw_load_cursor_palette(video_adapter_t *adp, u_char *palette)
349{
350
351	printf("%s: not yet\n", __func__);
352	return (ENODEV);
353}
354
355static int
356terasic_mtl_vidsw_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst,
357    int n)
358{
359
360	printf("%s: not yet\n", __func__);
361	return (ENODEV);
362}
363
364static int
365terasic_mtl_vidsw_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p,
366    uint32_t a, int size, int bpp, int bit_ltor, int byte_ltor)
367{
368
369	printf("%s: not yet\n", __func__);
370	return (ENODEV);
371}
372
373static int
374terasic_mtl_vidsw_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c,
375    uint8_t a)
376{
377	struct terasic_mtl_softc *sc;
378	u_int col, row;
379
380	sc = (struct terasic_mtl_softc *)adp;
381	col = (off % adp->va_info.vi_width);
382	row = (off / adp->va_info.vi_width);
383	terasic_mtl_text_putc(sc, col, row, c, a);
384	return (0);
385}
386
387static int
388terasic_mtl_vidsw_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s,
389    int len)
390{
391	int i;
392
393	for (i = 0; i < len; i++)
394		vidd_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8);
395	return (0);
396}
397
398static int
399terasic_mtl_vidsw_putm(video_adapter_t *adp, int x, int y,
400    uint8_t *pixel_image, uint32_t pixel_mask, int size, int width)
401{
402
403	printf("%s: not yet\n", __func__);
404	return (ENODEV);
405}
406
407/*
408 * XXXRW: For historical reasons, syscons can't register video consoles
409 * without a keyboard implementation.  Provide a dummy.
410 */
411static keyboard_switch_t	terasic_mtl_keyboard_switch;
412
413static int
414terasic_mtl_kbd_configure(int flags)
415{
416
417	return (0);
418}
419
420KEYBOARD_DRIVER(mtl_kbd, terasic_mtl_keyboard_switch,
421    terasic_mtl_kbd_configure);
422
423int
424terasic_mtl_syscons_attach(struct terasic_mtl_softc *sc)
425{
426	int error;
427
428	sc->mtl_text_soft  =
429	    malloc(sizeof(uint16_t) * TERASIC_MTL_ROWS * TERASIC_MTL_COLS,
430	    M_TERASIC_MTL, M_WAITOK | M_ZERO);
431	error = terasic_mtl_vidsw_init(0, &sc->mtl_va, 0);
432	if (error)
433		goto out;
434	error = sc_attach_unit(sc->mtl_unit, device_get_flags(sc->mtl_dev) |
435	    SC_AUTODETECT_KBD);
436	if (error)
437		device_printf(sc->mtl_dev, "%s: sc_attach_unit failed (%d)\n",
438		    __func__, error);
439out:
440	if (error)
441		free(sc->mtl_text_soft, M_TERASIC_MTL);
442	return (error);
443}
444
445void
446terasic_mtl_syscons_detach(struct terasic_mtl_softc *sc)
447{
448
449	free(sc->mtl_text_soft, M_TERASIC_MTL);
450	panic("%s: not supported by syscons", __func__);
451}
452
453static video_switch_t terasic_mtl_vidsw = {
454	.probe =			terasic_mtl_vidsw_probe,
455	.init =				terasic_mtl_vidsw_init,
456	.get_info =			terasic_mtl_vidsw_get_info,
457	.query_mode =			terasic_mtl_vidsw_query_mode,
458	.set_mode =			terasic_mtl_vidsw_set_mode,
459	.save_font =			terasic_mtl_vidsw_save_font,
460	.load_font =			terasic_mtl_vidsw_load_font,
461	.show_font =			terasic_mtl_vidsw_show_font,
462	.save_palette =			terasic_mtl_vidsw_save_palette,
463	.load_palette =			terasic_mtl_vidsw_load_palette,
464	.set_border =			terasic_mtl_vidsw_set_border,
465	.save_state =			terasic_mtl_vidsw_save_state,
466	.load_state =			terasic_mtl_vidsw_load_state,
467	.set_win_org =			terasic_mtl_vidsw_set_win_org,
468	.read_hw_cursor =		terasic_mtl_vidsw_read_hw_cursor,
469	.set_hw_cursor =		terasic_mtl_vidsw_set_hw_cursor,
470	.set_hw_cursor_shape =		terasic_mtl_vidsw_set_hw_cursor_shape,
471	.blank_display =		terasic_mtl_vidsw_blank_display,
472	.mmap =				terasic_mtl_vidsw_mmap,
473	.ioctl =			terasic_mtl_vidsw_ioctl,
474	.clear =			terasic_mtl_vidsw_clear,
475	.fill_rect =			terasic_mtl_vidsw_fill_rect,
476	.bitblt =			terasic_mtl_vidsw_bitblt,
477	.diag =				terasic_mtl_vidsw_diag,
478	.save_cursor_palette =		terasic_mtl_vidsw_save_cursor_palette,
479	.load_cursor_palette =		terasic_mtl_vidsw_load_cursor_palette,
480	.copy =				terasic_mtl_vidsw_copy,
481	.putp =				terasic_mtl_vidsw_putp,
482	.putc =				terasic_mtl_vidsw_putc,
483	.puts =				terasic_mtl_vidsw_puts,
484	.putm =				terasic_mtl_vidsw_putm,
485};
486VIDEO_DRIVER(terasic_mtl_syscons, terasic_mtl_vidsw,
487    terasic_mtl_syscons_configure);
488extern sc_rndr_sw_t txtrndrsw;
489RENDERER(terasic_mtl_syscons, 0, txtrndrsw, gfb_set);
490RENDERER_MODULE(terasic_mtl_syscons, gfb_set);
491