terasic_mtl_text.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2012 Robert N. M. Watson
5 * All rights reserved.
6 *
7 * This software was developed by SRI International and the University of
8 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
9 * ("CTSRD"), as part of the DARPA CRASH research programme.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: stable/11/sys/dev/terasic/mtl/terasic_mtl_text.c 330897 2018-03-14 03:19:51Z eadler $");
35
36#include <sys/param.h>
37#include <sys/bus.h>
38#include <sys/conf.h>
39#include <sys/consio.h>				/* struct vt_mode */
40#include <sys/endian.h>
41#include <sys/fbio.h>				/* video_adapter_t */
42#include <sys/lock.h>
43#include <sys/mutex.h>
44#include <sys/rman.h>
45#include <sys/systm.h>
46#include <sys/uio.h>
47
48#include <machine/bus.h>
49#include <machine/resource.h>
50#include <machine/vm.h>
51
52#include <dev/terasic/mtl/terasic_mtl.h>
53
54static d_mmap_t terasic_mtl_text_mmap;
55static d_read_t terasic_mtl_text_read;
56static d_write_t terasic_mtl_text_write;
57
58static struct cdevsw terasic_mtl_text_cdevsw = {
59	.d_version =	D_VERSION,
60	.d_mmap =	terasic_mtl_text_mmap,
61	.d_read =	terasic_mtl_text_read,
62	.d_write =	terasic_mtl_text_write,
63	.d_name =	"terasic_mtl_text",
64};
65
66/*
67 * All I/O to/from the mtl device must be 16-bit, and aligned to 16-bit.
68 */
69static int
70terasic_mtl_text_read(struct cdev *dev, struct uio *uio, int flag)
71{
72	struct terasic_mtl_softc *sc;
73	u_long offset, size;
74	uint16_t v;
75	int error;
76
77	if (uio->uio_offset < 0 || uio->uio_offset % 2 != 0 ||
78	    uio->uio_resid % 2 != 0)
79		return (ENODEV);
80	sc = dev->si_drv1;
81	size = rman_get_size(sc->mtl_text_res);
82	error = 0;
83	if ((uio->uio_offset + uio->uio_resid < 0) ||
84	    (uio->uio_offset + uio->uio_resid > size))
85		return (ENODEV);
86	while (uio->uio_resid > 0) {
87		offset = uio->uio_offset;
88		if (offset + sizeof(v) > size)
89			return (ENODEV);
90		v = bus_read_2(sc->mtl_text_res, offset);
91		error = uiomove(&v, sizeof(v), uio);
92		if (error)
93			return (error);
94	}
95	return (error);
96}
97
98static int
99terasic_mtl_text_write(struct cdev *dev, struct uio *uio, int flag)
100{
101	struct terasic_mtl_softc *sc;
102	u_long offset, size;
103	uint16_t v;
104	int error;
105
106	if (uio->uio_offset < 0 || uio->uio_offset % 2 != 0 ||
107	    uio->uio_resid % 2 != 0)
108		return (ENODEV);
109	sc = dev->si_drv1;
110	size = rman_get_size(sc->mtl_text_res);
111	error = 0;
112	while (uio->uio_resid > 0) {
113		offset = uio->uio_offset;
114		if (offset + sizeof(v) > size)
115			return (ENODEV);
116		error = uiomove(&v, sizeof(v), uio);
117		if (error)
118			return (error);
119		bus_write_2(sc->mtl_text_res, offset, v);
120	}
121	return (error);
122}
123
124static int
125terasic_mtl_text_mmap(struct cdev *dev, vm_ooffset_t offset,
126    vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr)
127{
128	struct terasic_mtl_softc *sc;
129	int error;
130
131	sc = dev->si_drv1;
132	error = 0;
133	if (trunc_page(offset) == offset &&
134	    rman_get_size(sc->mtl_text_res) >= offset + PAGE_SIZE) {
135		*paddr = rman_get_start(sc->mtl_text_res) + offset;
136		*memattr = VM_MEMATTR_UNCACHEABLE;
137	} else
138		error = ENODEV;
139	return (error);
140}
141
142void
143terasic_mtl_text_putc(struct terasic_mtl_softc *sc, u_int x, u_int y,
144    uint8_t c, uint8_t a)
145{
146	u_int offset;
147	uint16_t v;
148
149	KASSERT(x < TERASIC_MTL_COLS, ("%s: TERASIC_MTL_COLS", __func__));
150	KASSERT(y < TERASIC_MTL_ROWS, ("%s: TERASIC_MTL_ROWS", __func__));
151
152	offset = sizeof(uint16_t) * (x + y * TERASIC_MTL_COLS);
153	v = (c << TERASIC_MTL_TEXTFRAMEBUF_CHAR_SHIFT) |
154	    (a << TERASIC_MTL_TEXTFRAMEBUF_ATTR_SHIFT);
155	v = htole16(v);
156	bus_write_2(sc->mtl_text_res, offset, v);
157}
158
159int
160terasic_mtl_text_attach(struct terasic_mtl_softc *sc)
161{
162	uint32_t v;
163	u_int offset;
164
165	terasic_mtl_reg_textframebufaddr_get(sc, &v);
166	if (v != TERASIC_MTL_TEXTFRAMEBUF_EXPECTED_ADDR) {
167		device_printf(sc->mtl_dev, "%s: unexpected text frame buffer "
168		    "address (%08x); cannot attach\n", __func__, v);
169		return (ENXIO);
170	}
171	for (offset = 0; offset < rman_get_size(sc->mtl_text_res);
172	    offset += sizeof(uint16_t))
173		bus_write_2(sc->mtl_text_res, offset, 0);
174
175	sc->mtl_text_cdev = make_dev(&terasic_mtl_text_cdevsw, sc->mtl_unit,
176	    UID_ROOT, GID_WHEEL, 0400, "mtl_text%d", sc->mtl_unit);
177	if (sc->mtl_text_cdev == NULL) {
178		device_printf(sc->mtl_dev, "%s: make_dev failed\n", __func__);
179		return (ENXIO);
180	}
181	/* XXXRW: Slight race between make_dev(9) and here. */
182	TERASIC_MTL_LOCK_INIT(sc);
183	sc->mtl_text_cdev->si_drv1 = sc;
184	return (0);
185}
186
187void
188terasic_mtl_text_detach(struct terasic_mtl_softc *sc)
189{
190
191	if (sc->mtl_text_cdev != NULL) {
192		destroy_dev(sc->mtl_text_cdev);
193		TERASIC_MTL_LOCK_DESTROY(sc);
194	}
195}
196