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$");
33239691Srwatson
34239691Srwatson#include <sys/param.h>
35239691Srwatson#include <sys/bus.h>
36239691Srwatson#include <sys/condvar.h>
37239691Srwatson#include <sys/conf.h>
38239691Srwatson#include <sys/consio.h>				/* struct vt_mode */
39239691Srwatson#include <sys/fbio.h>				/* video_adapter_t */
40239691Srwatson#include <sys/kernel.h>
41239691Srwatson#include <sys/lock.h>
42239691Srwatson#include <sys/malloc.h>
43239691Srwatson#include <sys/module.h>
44239691Srwatson#include <sys/mutex.h>
45239691Srwatson#include <sys/rman.h>
46239691Srwatson#include <sys/systm.h>
47239691Srwatson
48239691Srwatson#include <machine/bus.h>
49239691Srwatson#include <machine/resource.h>
50239691Srwatson
51239691Srwatson#include <dev/terasic/mtl/terasic_mtl.h>
52239691Srwatson
53239691Srwatsonstatic int
54239691Srwatsonterasic_mtl_nexus_probe(device_t dev)
55239691Srwatson{
56239691Srwatson
57239691Srwatson	device_set_desc(dev, "Terasic Multi-touch LCD (MTL)");
58265999Sian	return (BUS_PROBE_NOWILDCARD);
59239691Srwatson}
60239691Srwatson
61239691Srwatsonstatic int
62239691Srwatsonterasic_mtl_nexus_attach(device_t dev)
63239691Srwatson{
64239691Srwatson	struct terasic_mtl_softc *sc;
65239691Srwatson	u_long pixel_maddr, text_maddr, reg_maddr;
66239691Srwatson	u_long pixel_msize, text_msize, reg_msize;
67239691Srwatson	int error;
68239691Srwatson
69239691Srwatson	sc = device_get_softc(dev);
70239691Srwatson	sc->mtl_dev = dev;
71239691Srwatson	sc->mtl_unit = device_get_unit(dev);
72239691Srwatson
73239691Srwatson	/*
74239691Srwatson	 * Query non-standard hints to find the locations of our two memory
75239691Srwatson	 * regions.  Enforce certain alignment and size requirements.
76239691Srwatson	 */
77239691Srwatson	if (resource_long_value(device_get_name(dev), device_get_unit(dev),
78239691Srwatson	    "reg_maddr", &reg_maddr) != 0 || (reg_maddr % PAGE_SIZE != 0)) {
79239691Srwatson		device_printf(dev, "improper register address");
80239691Srwatson		return (ENXIO);
81239691Srwatson	}
82239691Srwatson	if (resource_long_value(device_get_name(dev), device_get_unit(dev),
83239691Srwatson	    "reg_msize", &reg_msize) != 0 || (reg_msize % PAGE_SIZE != 0)) {
84239691Srwatson		device_printf(dev, "improper register size");
85239691Srwatson		return (ENXIO);
86239691Srwatson	}
87239691Srwatson	if (resource_long_value(device_get_name(dev), device_get_unit(dev),
88239691Srwatson	    "pixel_maddr", &pixel_maddr) != 0 ||
89239691Srwatson	    (pixel_maddr % PAGE_SIZE != 0)) {
90239691Srwatson		device_printf(dev, "improper pixel frame buffer address");
91239691Srwatson		return (ENXIO);
92239691Srwatson	}
93239691Srwatson	if (resource_long_value(device_get_name(dev), device_get_unit(dev),
94239691Srwatson	    "pixel_msize", &pixel_msize) != 0 ||
95239691Srwatson	    (pixel_msize % PAGE_SIZE != 0)) {
96239691Srwatson		device_printf(dev, "improper pixel frame buffer size");
97239691Srwatson		return (ENXIO);
98239691Srwatson	}
99239691Srwatson	if (resource_long_value(device_get_name(dev), device_get_unit(dev),
100239691Srwatson	    "text_maddr", &text_maddr) != 0 ||
101239691Srwatson	    (text_maddr % PAGE_SIZE != 0)) {
102239691Srwatson		device_printf(dev, "improper text frame buffer address");
103239691Srwatson		return (ENXIO);
104239691Srwatson	}
105239691Srwatson	if (resource_long_value(device_get_name(dev), device_get_unit(dev),
106239691Srwatson	    "text_msize", &text_msize) != 0 ||
107239691Srwatson	    (text_msize % PAGE_SIZE != 0)) {
108239691Srwatson		device_printf(dev, "improper text frame buffer size");
109239691Srwatson		return (ENXIO);
110239691Srwatson	}
111239691Srwatson
112239691Srwatson	/*
113239691Srwatson	 * Allocate resources.
114239691Srwatson	 */
115239691Srwatson	sc->mtl_reg_rid = 0;
116239691Srwatson	sc->mtl_reg_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
117239691Srwatson	    &sc->mtl_reg_rid, reg_maddr, reg_maddr + reg_msize - 1,
118239691Srwatson	    reg_msize, RF_ACTIVE);
119239691Srwatson	if (sc->mtl_reg_res == NULL) {
120239691Srwatson		device_printf(dev, "couldn't map register memory\n");
121239691Srwatson		error = ENXIO;
122239691Srwatson		goto error;
123239691Srwatson	}
124239691Srwatson	device_printf(sc->mtl_dev, "registers at mem %p-%p\n",
125239691Srwatson	    (void *)reg_maddr, (void *)(reg_maddr + reg_msize));
126239691Srwatson	sc->mtl_pixel_rid = 0;
127239691Srwatson	sc->mtl_pixel_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
128239691Srwatson	    &sc->mtl_pixel_rid, pixel_maddr, pixel_maddr + pixel_msize - 1,
129239691Srwatson	    pixel_msize, RF_ACTIVE);
130239691Srwatson	if (sc->mtl_pixel_res == NULL) {
131239691Srwatson		device_printf(dev, "couldn't map pixel memory\n");
132239691Srwatson		error = ENXIO;
133239691Srwatson		goto error;
134239691Srwatson	}
135239691Srwatson	device_printf(sc->mtl_dev, "pixel frame buffer at mem %p-%p\n",
136239691Srwatson	    (void *)pixel_maddr, (void *)(pixel_maddr + pixel_msize));
137239691Srwatson	sc->mtl_text_rid = 0;
138239691Srwatson	sc->mtl_text_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
139239691Srwatson	    &sc->mtl_text_rid, text_maddr, text_maddr + text_msize - 1,
140239691Srwatson	    text_msize, RF_ACTIVE);
141239691Srwatson	if (sc->mtl_text_res == NULL) {
142239691Srwatson		device_printf(dev, "couldn't map text memory\n");
143239691Srwatson		error = ENXIO;
144239691Srwatson		goto error;
145239691Srwatson	}
146239691Srwatson	device_printf(sc->mtl_dev, "text frame buffer at mem %p-%p\n",
147239691Srwatson	    (void *)text_maddr, (void *)(text_maddr + text_msize));
148239691Srwatson	error = terasic_mtl_attach(sc);
149239691Srwatson	if (error == 0)
150239691Srwatson		return (0);
151239691Srwatsonerror:
152239691Srwatson	if (sc->mtl_text_res != NULL)
153239691Srwatson		bus_release_resource(dev, SYS_RES_MEMORY, sc->mtl_text_rid,
154239691Srwatson		    sc->mtl_text_res);
155239691Srwatson	if (sc->mtl_pixel_res != NULL)
156239691Srwatson		bus_release_resource(dev, SYS_RES_MEMORY, sc->mtl_pixel_rid,
157239691Srwatson		    sc->mtl_pixel_res);
158239691Srwatson	if (sc->mtl_reg_res != NULL)
159239691Srwatson		bus_release_resource(dev, SYS_RES_MEMORY, sc->mtl_reg_rid,
160239691Srwatson		    sc->mtl_reg_res);
161239691Srwatson	return (error);
162239691Srwatson}
163239691Srwatson
164239691Srwatsonstatic int
165239691Srwatsonterasic_mtl_nexus_detach(device_t dev)
166239691Srwatson{
167239691Srwatson	struct terasic_mtl_softc *sc;
168239691Srwatson
169239691Srwatson	sc = device_get_softc(dev);
170239691Srwatson	terasic_mtl_detach(sc);
171239691Srwatson	bus_release_resource(dev, SYS_RES_MEMORY, sc->mtl_text_rid,
172239691Srwatson	    sc->mtl_text_res);
173239691Srwatson	bus_release_resource(dev, SYS_RES_MEMORY, sc->mtl_pixel_rid,
174239691Srwatson	    sc->mtl_pixel_res);
175239691Srwatson	bus_release_resource(dev, SYS_RES_MEMORY, sc->mtl_reg_rid,
176239691Srwatson	    sc->mtl_reg_res);
177239691Srwatson	return (0);
178239691Srwatson}
179239691Srwatson
180239691Srwatsonstatic device_method_t terasic_mtl_nexus_methods[] = {
181239691Srwatson	DEVMETHOD(device_probe,		terasic_mtl_nexus_probe),
182239691Srwatson	DEVMETHOD(device_attach,	terasic_mtl_nexus_attach),
183239691Srwatson	DEVMETHOD(device_detach,	terasic_mtl_nexus_detach),
184239691Srwatson	{ 0, 0 }
185239691Srwatson};
186239691Srwatson
187239691Srwatsonstatic driver_t terasic_mtl_nexus_driver = {
188239691Srwatson	"terasic_mtl",
189239691Srwatson	terasic_mtl_nexus_methods,
190239691Srwatson	sizeof(struct terasic_mtl_softc),
191239691Srwatson};
192239691Srwatson
193239691SrwatsonDRIVER_MODULE(mtl, nexus, terasic_mtl_nexus_driver, terasic_mtl_devclass, 0,
194239691Srwatson    0);
195