xref: /openbsd/sys/arch/powerpc64/dev/astfb.c (revision 73471bf0)
1 /*	$OpenBSD: astfb.c,v 1.3 2020/10/30 13:36:45 kettenis Exp $	*/
2 
3 /*
4  * Copyright (c) 2020 Mark Kettenis.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/device.h>
21 #include <sys/systm.h>
22 
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25 
26 #include <dev/ofw/openfirm.h>
27 
28 #include <dev/pci/pcireg.h>
29 #include <dev/pci/pcivar.h>
30 #include <dev/pci/pcidevs.h>
31 
32 #include <dev/wscons/wsconsio.h>
33 #include <dev/wscons/wsdisplayvar.h>
34 
35 #include <dev/rasops/rasops.h>
36 
37 #define ASTFB_PCI_FB	0x10
38 
39 struct astfb_softc {
40 	struct device		sc_dev;
41 	bus_space_tag_t		sc_iot;
42 	bus_space_handle_t	sc_ioh;
43 
44 	bus_addr_t		sc_fbaddr;
45 	bus_size_t		sc_fbsize;
46 
47 	struct rasops_info	sc_ri;
48 	struct wsscreen_descr	sc_wsd;
49 	struct wsscreen_list	sc_wsl;
50 	struct wsscreen_descr	*sc_scrlist[1];
51 };
52 
53 int	astfb_wsioctl(void *, u_long, caddr_t, int, struct proc *);
54 paddr_t	astfb_wsmmap(void *, off_t, int);
55 int	astfb_alloc_screen(void *, const struct wsscreen_descr *,
56 	    void **, int *, int *, uint32_t *);
57 
58 struct wsdisplay_accessops astfb_accessops = {
59 	.ioctl = astfb_wsioctl,
60 	.mmap = astfb_wsmmap,
61 	.alloc_screen = astfb_alloc_screen,
62 	.free_screen = rasops_free_screen,
63 	.show_screen = rasops_show_screen,
64 	.getchar = rasops_getchar,
65 	.load_font = rasops_load_font,
66 	.list_font = rasops_list_font,
67 	.scrollback = rasops_scrollback
68 };
69 
70 int	astfb_match(struct device *, void *, void *);
71 void	astfb_attach(struct device *, struct device *, void *);
72 
73 struct cfattach astfb_ca = {
74 	sizeof(struct astfb_softc), astfb_match, astfb_attach
75 };
76 
77 struct cfdriver astfb_cd = {
78 	NULL, "astfb", DV_DULL
79 };
80 
81 int
82 astfb_match(struct device *parent, void *cf, void *aux)
83 {
84 	struct pci_attach_args *pa = aux;
85 
86 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ASPEED &&
87 	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ASPEED_AST2000 &&
88 	    PCITAG_NODE(pa->pa_tag) != 0)
89 		return 1;
90 
91 	return 0;
92 }
93 
94 void
95 astfb_attach(struct device *parent, struct device *self, void *aux)
96 {
97 	struct astfb_softc *sc = (struct astfb_softc *)self;
98 	struct pci_attach_args *pa = aux;
99 	struct rasops_info *ri = &sc->sc_ri;
100 	struct wsemuldisplaydev_attach_args waa;
101 	int node = PCITAG_NODE(pa->pa_tag);
102 	uint32_t addr[5];
103 	int console = 0;
104 	uint32_t defattr;
105 
106 	if (OF_getpropintarray(node, "assigned-addresses", addr,
107 	    sizeof(addr)) < sizeof(addr)) {
108 		printf(": no framebuffer\n");
109 		return;
110 	}
111 
112 	if (node == stdout_node)
113 		console = 1;
114 
115 	sc->sc_fbaddr = (bus_addr_t)addr[1] << 32 | addr[2];
116 	sc->sc_fbsize = (bus_size_t)addr[3] << 32 | addr[4];
117 
118 	sc->sc_iot = pa->pa_memt;
119 	if (bus_space_map(sc->sc_iot, sc->sc_fbaddr, sc->sc_fbsize,
120 	    BUS_SPACE_MAP_LINEAR, &sc->sc_ioh)) {
121 		printf(": can't map framebuffer\n");
122 		return;
123 	}
124 
125 	printf("\n");
126 
127 	ri->ri_bits = bus_space_vaddr(sc->sc_iot, sc->sc_ioh);
128 	ri->ri_hw = sc;
129 
130 	ri->ri_width = OF_getpropint(node, "width", 0);
131 	ri->ri_height = OF_getpropint(node, "height", 0);
132 	ri->ri_depth = OF_getpropint(node, "depth", 0);
133 	ri->ri_stride = ri->ri_width * ((ri->ri_depth + 7) / 8);
134 	ri->ri_flg = RI_CENTER | RI_CLEAR | RI_FULLCLEAR | RI_WRONLY;
135 
136 	switch (ri->ri_depth) {
137 	case 32:
138 		ri->ri_rnum = 8;
139 		ri->ri_rpos = 8;
140 		ri->ri_gnum = 8;
141 		ri->ri_gpos = 16;
142 		ri->ri_bnum = 8;
143 		ri->ri_bpos = 24;
144 		break;
145 	case 16:
146 		ri->ri_rnum = 5;
147 		ri->ri_rpos = 0;
148 		ri->ri_gnum = 6;
149 		ri->ri_gpos = 6;
150 		ri->ri_bnum = 5;
151 		ri->ri_bpos = 11;
152 		break;
153 	}
154 
155 	printf("%s: %dx%d, %dbpp\n", sc->sc_dev.dv_xname,
156 	    ri->ri_width, ri->ri_height, ri->ri_depth);
157 
158 	ri->ri_flg |= RI_VCONS;
159 	rasops_init(ri, 160, 160);
160 
161 	strlcpy(sc->sc_wsd.name, "std", sizeof(sc->sc_wsd.name));
162 	sc->sc_wsd.capabilities = ri->ri_caps;
163 	sc->sc_wsd.nrows = ri->ri_rows;
164 	sc->sc_wsd.ncols = ri->ri_cols;
165 	sc->sc_wsd.textops = &ri->ri_ops;
166 	sc->sc_wsd.fontwidth = ri->ri_font->fontwidth;
167 	sc->sc_wsd.fontheight = ri->ri_font->fontheight;
168 
169 	sc->sc_scrlist[0] = &sc->sc_wsd;
170 	sc->sc_wsl.nscreens = 1;
171 	sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist;
172 
173 	if (console) {
174 		ri->ri_ops.pack_attr(ri->ri_active, 0, 0, 0, &defattr);
175 		wsdisplay_cnattach(&sc->sc_wsd, ri->ri_active,
176 		    0, 0, defattr);
177 	}
178 
179 	memset(&waa, 0, sizeof(waa));
180 	waa.scrdata = &sc->sc_wsl;
181 	waa.accessops = &astfb_accessops;
182 	waa.accesscookie = ri;
183 	waa.console = console;
184 
185 	config_found_sm(self, &waa, wsemuldisplaydevprint,
186 	    wsemuldisplaydevsubmatch);
187 }
188 
189 int
190 astfb_wsioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
191 {
192 	struct rasops_info *ri = v;
193 	struct wsdisplay_fbinfo *wdf;
194 
195 	switch (cmd) {
196 	case WSDISPLAYIO_GTYPE:
197 		*(u_int *)data = WSDISPLAY_TYPE_ASTFB;
198 		break;
199 	case WSDISPLAYIO_GINFO:
200 		wdf = (void *)data;
201 		wdf->width = ri->ri_width;
202 		wdf->height = ri->ri_height;
203 		wdf->depth = ri->ri_depth;
204 		wdf->cmsize = 0;	/* color map is unavailable */
205 		break;
206 	case WSDISPLAYIO_LINEBYTES:
207 		*(u_int *)data = ri->ri_stride;
208 		break;
209 	case WSDISPLAYIO_SMODE:
210 		break;
211 	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
212 		switch (ri->ri_depth) {
213 		case 32:
214 			*(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
215 			break;
216 		case 16:
217 			*(u_int *)data = WSDISPLAYIO_DEPTH_16;
218 			break;
219 		default:
220 			return -1;
221 		}
222 		break;
223 	default:
224 		return -1;
225         }
226 
227 	return 0;
228 }
229 
230 paddr_t
231 astfb_wsmmap(void *v, off_t off, int prot)
232 {
233 	struct rasops_info *ri = v;
234 	struct astfb_softc *sc = ri->ri_hw;
235 
236 	if (off < 0 || off >= sc->sc_fbaddr)
237 		return -1;
238 
239 	return (bus_space_mmap(sc->sc_iot, sc->sc_fbaddr,
240 	    off, prot, BUS_SPACE_MAP_LINEAR));
241 }
242 
243 int
244 astfb_alloc_screen(void *v, const struct wsscreen_descr *type,
245     void **cookiep, int *curxp, int *curyp, uint32_t *attrp)
246 {
247 	return rasops_alloc_screen(v, cookiep, curxp, curyp, attrp);
248 }
249