1239691Srwatson/*-
2239691Srwatson * Copyright (c) 2012 Robert N. M. Watson
3239691Srwatson * All rights reserved.
4239691Srwatson *
5239691Srwatson * This software was developed by SRI International and the University of
6239691Srwatson * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7239691Srwatson * ("CTSRD"), as part of the DARPA CRASH research programme.
8239691Srwatson *
9239691Srwatson * Redistribution and use in source and binary forms, with or without
10239691Srwatson * modification, are permitted provided that the following conditions
11239691Srwatson * are met:
12239691Srwatson * 1. Redistributions of source code must retain the above copyright
13239691Srwatson *    notice, this list of conditions and the following disclaimer.
14239691Srwatson * 2. Redistributions in binary form must reproduce the above copyright
15239691Srwatson *    notice, this list of conditions and the following disclaimer in the
16239691Srwatson *    documentation and/or other materials provided with the distribution.
17239691Srwatson *
18239691Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19239691Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20239691Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21239691Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22239691Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23239691Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24239691Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25239691Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26239691Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27239691Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28239691Srwatson * SUCH DAMAGE.
29239691Srwatson */
30239691Srwatson
31239691Srwatson#include <sys/cdefs.h>
32239691Srwatson__FBSDID("$FreeBSD: releng/10.3/sys/dev/terasic/mtl/terasic_mtl_reg.c 239691 2012-08-25 22:35:29Z rwatson $");
33239691Srwatson
34239691Srwatson#include <sys/param.h>
35239691Srwatson#include <sys/bus.h>
36239691Srwatson#include <sys/conf.h>
37239691Srwatson#include <sys/consio.h>				/* struct vt_mode */
38239691Srwatson#include <sys/endian.h>
39239691Srwatson#include <sys/fbio.h>				/* video_adapter_t */
40239691Srwatson#include <sys/lock.h>
41239691Srwatson#include <sys/mutex.h>
42239691Srwatson#include <sys/rman.h>
43239691Srwatson#include <sys/systm.h>
44239691Srwatson#include <sys/uio.h>
45239691Srwatson
46239691Srwatson#include <machine/bus.h>
47239691Srwatson#include <machine/resource.h>
48239691Srwatson#include <machine/vm.h>
49239691Srwatson
50239691Srwatson#include <dev/terasic/mtl/terasic_mtl.h>
51239691Srwatson
52239691Srwatsonstatic d_mmap_t terasic_mtl_reg_mmap;
53239691Srwatsonstatic d_read_t terasic_mtl_reg_read;
54239691Srwatsonstatic d_write_t terasic_mtl_reg_write;
55239691Srwatson
56239691Srwatsonstatic struct cdevsw terasic_mtl_reg_cdevsw = {
57239691Srwatson	.d_version =	D_VERSION,
58239691Srwatson	.d_mmap =	terasic_mtl_reg_mmap,
59239691Srwatson	.d_read =	terasic_mtl_reg_read,
60239691Srwatson	.d_write =	terasic_mtl_reg_write,
61239691Srwatson	.d_name =	"terasic_mtl_reg",
62239691Srwatson};
63239691Srwatson
64239691Srwatson/*
65239691Srwatson * All I/O to/from the MTL register device must be 32-bit, and aligned to
66239691Srwatson * 32-bit.
67239691Srwatson */
68239691Srwatsonstatic int
69239691Srwatsonterasic_mtl_reg_read(struct cdev *dev, struct uio *uio, int flag)
70239691Srwatson{
71239691Srwatson	struct terasic_mtl_softc *sc;
72239691Srwatson	u_long offset, size;
73239691Srwatson	uint32_t v;
74239691Srwatson	int error;
75239691Srwatson
76239691Srwatson	if (uio->uio_offset < 0 || uio->uio_offset % 4 != 0 ||
77239691Srwatson	    uio->uio_resid % 4 != 0)
78239691Srwatson		return (ENODEV);
79239691Srwatson	sc = dev->si_drv1;
80239691Srwatson	size = rman_get_size(sc->mtl_reg_res);
81239691Srwatson	error = 0;
82239691Srwatson	if ((uio->uio_offset + uio->uio_resid < 0) ||
83239691Srwatson	    (uio->uio_offset + uio->uio_resid > size))
84239691Srwatson		return (ENODEV);
85239691Srwatson	while (uio->uio_resid > 0) {
86239691Srwatson		offset = uio->uio_offset;
87239691Srwatson		if (offset + sizeof(v) > size)
88239691Srwatson			return (ENODEV);
89239691Srwatson		v = bus_read_4(sc->mtl_reg_res, offset);
90239691Srwatson		error = uiomove(&v, sizeof(v), uio);
91239691Srwatson		if (error)
92239691Srwatson			return (error);
93239691Srwatson	}
94239691Srwatson	return (error);
95239691Srwatson}
96239691Srwatson
97239691Srwatsonstatic int
98239691Srwatsonterasic_mtl_reg_write(struct cdev *dev, struct uio *uio, int flag)
99239691Srwatson{
100239691Srwatson	struct terasic_mtl_softc *sc;
101239691Srwatson	u_long offset, size;
102239691Srwatson	uint32_t v;
103239691Srwatson	int error;
104239691Srwatson
105239691Srwatson	if (uio->uio_offset < 0 || uio->uio_offset % 4 != 0 ||
106239691Srwatson	    uio->uio_resid % 4 != 0)
107239691Srwatson		return (ENODEV);
108239691Srwatson	sc = dev->si_drv1;
109239691Srwatson	size = rman_get_size(sc->mtl_reg_res);
110239691Srwatson	error = 0;
111239691Srwatson	while (uio->uio_resid > 0) {
112239691Srwatson		offset = uio->uio_offset;
113239691Srwatson		if (offset + sizeof(v) > size)
114239691Srwatson			return (ENODEV);
115239691Srwatson		error = uiomove(&v, sizeof(v), uio);
116239691Srwatson		if (error)
117239691Srwatson			return (error);
118239691Srwatson		bus_write_4(sc->mtl_reg_res, offset, v);
119239691Srwatson	}
120239691Srwatson	return (error);
121239691Srwatson}
122239691Srwatson
123239691Srwatsonstatic int
124239691Srwatsonterasic_mtl_reg_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
125239691Srwatson    int nprot, vm_memattr_t *memattr)
126239691Srwatson{
127239691Srwatson	struct terasic_mtl_softc *sc;
128239691Srwatson	int error;
129239691Srwatson
130239691Srwatson	sc = dev->si_drv1;
131239691Srwatson	error = 0;
132239691Srwatson	if (trunc_page(offset) == offset &&
133239691Srwatson	    rman_get_size(sc->mtl_reg_res) >= offset + PAGE_SIZE) {
134239691Srwatson		*paddr = rman_get_start(sc->mtl_reg_res) + offset;
135239691Srwatson		*memattr = VM_MEMATTR_UNCACHEABLE;
136239691Srwatson	} else
137239691Srwatson		error = ENODEV;
138239691Srwatson	return (error);
139239691Srwatson}
140239691Srwatson
141239691Srwatsonvoid
142239691Srwatsonterasic_mtl_reg_blend_get(struct terasic_mtl_softc *sc, uint32_t *blendp)
143239691Srwatson{
144239691Srwatson
145239691Srwatson	*blendp = le32toh(bus_read_4(sc->mtl_reg_res, TERASIC_MTL_OFF_BLEND));
146239691Srwatson}
147239691Srwatson
148239691Srwatsonvoid
149239691Srwatsonterasic_mtl_reg_blend_set(struct terasic_mtl_softc *sc, uint32_t blend)
150239691Srwatson{
151239691Srwatson
152239691Srwatson	bus_write_4(sc->mtl_reg_res, TERASIC_MTL_OFF_BLEND, htole32(blend));
153239691Srwatson}
154239691Srwatson
155239691Srwatsonvoid
156239691Srwatsonterasic_mtl_blend_default_set(struct terasic_mtl_softc *sc, uint8_t colour)
157239691Srwatson{
158239691Srwatson	uint32_t v;
159239691Srwatson
160239691Srwatson	TERASIC_MTL_LOCK(sc);
161239691Srwatson	terasic_mtl_reg_blend_get(sc, &v);
162239691Srwatson	v &= ~TERASIC_MTL_BLEND_DEFAULT_MASK;
163239691Srwatson	v |= colour << TERASIC_MTL_BLEND_DEFAULT_SHIFT;
164239691Srwatson	terasic_mtl_reg_blend_set(sc, v);
165239691Srwatson	TERASIC_MTL_UNLOCK(sc);
166239691Srwatson}
167239691Srwatson
168239691Srwatsonvoid
169239691Srwatsonterasic_mtl_blend_pixel_set(struct terasic_mtl_softc *sc, uint8_t alpha)
170239691Srwatson{
171239691Srwatson	uint32_t v;
172239691Srwatson
173239691Srwatson	TERASIC_MTL_LOCK(sc);
174239691Srwatson	terasic_mtl_reg_blend_get(sc, &v);
175239691Srwatson	v &= ~TERASIC_MTL_BLEND_PIXEL_MASK;
176239691Srwatson	v |= alpha << TERASIC_MTL_BLEND_PIXEL_SHIFT;
177239691Srwatson	terasic_mtl_reg_blend_set(sc, v);
178239691Srwatson	TERASIC_MTL_UNLOCK(sc);
179239691Srwatson}
180239691Srwatson
181239691Srwatsonvoid
182239691Srwatsonterasic_mtl_blend_textfg_set(struct terasic_mtl_softc *sc, uint8_t alpha)
183239691Srwatson{
184239691Srwatson	uint32_t v;
185239691Srwatson
186239691Srwatson	TERASIC_MTL_LOCK(sc);
187239691Srwatson	terasic_mtl_reg_blend_get(sc, &v);
188239691Srwatson	v &= ~TERASIC_MTL_BLEND_TEXTFG_MASK;
189239691Srwatson	v |= alpha << TERASIC_MTL_BLEND_TEXTFG_SHIFT;
190239691Srwatson	terasic_mtl_reg_blend_set(sc, v);
191239691Srwatson	TERASIC_MTL_UNLOCK(sc);
192239691Srwatson}
193239691Srwatson
194239691Srwatsonvoid
195239691Srwatsonterasic_mtl_blend_textbg_set(struct terasic_mtl_softc *sc, uint8_t alpha)
196239691Srwatson{
197239691Srwatson	uint32_t v;
198239691Srwatson
199239691Srwatson	TERASIC_MTL_LOCK(sc);
200239691Srwatson	terasic_mtl_reg_blend_get(sc, &v);
201239691Srwatson	v &= ~TERASIC_MTL_BLEND_TEXTBG_MASK;
202239691Srwatson	v |= alpha << TERASIC_MTL_BLEND_TEXTBG_SHIFT;
203239691Srwatson	terasic_mtl_reg_blend_set(sc, v);
204239691Srwatson	TERASIC_MTL_UNLOCK(sc);
205239691Srwatson}
206239691Srwatson
207239691Srwatsonvoid
208239691Srwatsonterasic_mtl_reg_textcursor_get(struct terasic_mtl_softc *sc, uint8_t *colp,
209239691Srwatson    uint8_t *rowp)
210239691Srwatson{
211239691Srwatson	uint32_t v;
212239691Srwatson
213239691Srwatson	v = bus_read_4(sc->mtl_reg_res, TERASIC_MTL_OFF_TEXTCURSOR);
214239691Srwatson	v = le32toh(v);
215239691Srwatson	*colp = (v & TERASIC_MTL_TEXTCURSOR_COL_MASK) >>
216239691Srwatson	    TERASIC_MTL_TEXTCURSOR_COL_SHIFT;
217239691Srwatson	*rowp = (v & TERASIC_MTL_TEXTCURSOR_ROW_MASK);
218239691Srwatson}
219239691Srwatson
220239691Srwatsonvoid
221239691Srwatsonterasic_mtl_reg_textcursor_set(struct terasic_mtl_softc *sc, uint8_t col,
222239691Srwatson    uint8_t row)
223239691Srwatson{
224239691Srwatson	uint32_t v;
225239691Srwatson
226239691Srwatson	v = (col << TERASIC_MTL_TEXTCURSOR_COL_SHIFT) | row;
227239691Srwatson	v = htole32(v);
228239691Srwatson	bus_write_4(sc->mtl_reg_res, TERASIC_MTL_OFF_TEXTCURSOR, v);
229239691Srwatson}
230239691Srwatson
231239691Srwatsonvoid
232239691Srwatsonterasic_mtl_reg_blank(struct terasic_mtl_softc *sc)
233239691Srwatson{
234239691Srwatson
235239691Srwatson	device_printf(sc->mtl_dev, "%s: not yet", __func__);
236239691Srwatson}
237239691Srwatson
238239691Srwatsonvoid
239239691Srwatsonterasic_mtl_reg_textframebufaddr_get(struct terasic_mtl_softc *sc,
240239691Srwatson    uint32_t *addrp)
241239691Srwatson{
242239691Srwatson	uint32_t addr;
243239691Srwatson
244239691Srwatson	addr = bus_read_4(sc->mtl_reg_res, TERASIC_MTL_OFF_TEXTFRAMEBUFADDR);
245239691Srwatson	*addrp = le32toh(addr);
246239691Srwatson}
247239691Srwatson
248239691Srwatsonvoid
249239691Srwatsonterasic_mtl_reg_textframebufaddr_set(struct terasic_mtl_softc *sc,
250239691Srwatson    uint32_t addr)
251239691Srwatson{
252239691Srwatson
253239691Srwatson	addr = htole32(addr);
254239691Srwatson	bus_write_4(sc->mtl_reg_res, TERASIC_MTL_OFF_TEXTFRAMEBUFADDR, addr);
255239691Srwatson}
256239691Srwatson
257239691Srwatsonint
258239691Srwatsonterasic_mtl_reg_attach(struct terasic_mtl_softc *sc)
259239691Srwatson{
260239691Srwatson
261239691Srwatson	sc->mtl_reg_cdev = make_dev(&terasic_mtl_reg_cdevsw, sc->mtl_unit,
262239691Srwatson	    UID_ROOT, GID_WHEEL, 0400, "mtl_reg%d", sc->mtl_unit);
263239691Srwatson	if (sc->mtl_reg_cdev == NULL) {
264239691Srwatson		device_printf(sc->mtl_dev, "%s: make_dev failed\n", __func__);
265239691Srwatson		return (ENXIO);
266239691Srwatson	}
267239691Srwatson	/* XXXRW: Slight race between make_dev(9) and here. */
268239691Srwatson	sc->mtl_reg_cdev->si_drv1 = sc;
269239691Srwatson	return (0);
270239691Srwatson}
271239691Srwatson
272239691Srwatsonvoid
273239691Srwatsonterasic_mtl_reg_detach(struct terasic_mtl_softc *sc)
274239691Srwatson{
275239691Srwatson
276239691Srwatson	if (sc->mtl_reg_cdev != NULL)
277239691Srwatson		destroy_dev(sc->mtl_reg_cdev);
278239691Srwatson}
279