xref: /openbsd-src/sys/dev/fdt/ssdfb.c (revision 0f9e9ec23bb2b65cc62a3d17df12827a45dae80c)
1*0f9e9ec2Sjsg /* $OpenBSD: ssdfb.c,v 1.14 2024/05/13 01:15:50 jsg Exp $ */
2dab1a984Spatrick /*
3dab1a984Spatrick  * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
4dab1a984Spatrick  *
5dab1a984Spatrick  * Permission to use, copy, modify, and distribute this software for any
6dab1a984Spatrick  * purpose with or without fee is hereby granted, provided that the above
7dab1a984Spatrick  * copyright notice and this permission notice appear in all copies.
8dab1a984Spatrick  *
9dab1a984Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10dab1a984Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11dab1a984Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12dab1a984Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13dab1a984Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14dab1a984Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15dab1a984Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16dab1a984Spatrick  */
17dab1a984Spatrick 
18dab1a984Spatrick #include <sys/param.h>
19dab1a984Spatrick #include <sys/systm.h>
20dab1a984Spatrick #include <sys/kernel.h>
21dab1a984Spatrick #include <sys/device.h>
22dab1a984Spatrick #include <sys/malloc.h>
23dab1a984Spatrick #include <sys/stdint.h>
24dab1a984Spatrick 
253f4c1042Spatrick #include <uvm/uvm_extern.h>
263f4c1042Spatrick 
27c6a62e52Spatrick #include <dev/i2c/i2cvar.h>
28dab1a984Spatrick #include <dev/spi/spivar.h>
293f4c1042Spatrick #include <dev/usb/udlio.h>
30dab1a984Spatrick 
31dab1a984Spatrick #include <dev/ofw/openfirm.h>
32dab1a984Spatrick #include <dev/ofw/ofw_gpio.h>
33dab1a984Spatrick #include <dev/ofw/ofw_pinctrl.h>
34dab1a984Spatrick 
35dab1a984Spatrick #include <dev/wscons/wsconsio.h>
36dab1a984Spatrick #include <dev/wscons/wsdisplayvar.h>
37dab1a984Spatrick #include <dev/rasops/rasops.h>
38dab1a984Spatrick 
39eb4f240eSpatrick #define SSDFB_SET_LOWER_COLUMN_START_ADDRESS	0x00
40eb4f240eSpatrick #define SSDFB_SET_HIGHER_COLUMN_START_ADDRESS	0x10
41eb4f240eSpatrick #define SSDFB_SET_MEMORY_ADDRESSING_MODE	0x20
42eb4f240eSpatrick #define SSDFB_SET_COLUMN_RANGE			0x21
43eb4f240eSpatrick #define SSDFB_SET_PAGE_RANGE			0x22
44dab1a984Spatrick #define SSDFB_SET_START_LINE			0x40
45dab1a984Spatrick #define SSDFB_SET_CONTRAST_CONTROL		0x81
46fb481783Spatrick #define SSDFB_CHARGE_PUMP			0x8d
47ad478a58Spatrick #define SSDFB_SET_COLUMN_DIRECTION_NORMAL	0xa0
48dab1a984Spatrick #define SSDFB_SET_COLUMN_DIRECTION_REVERSE	0xa1
49dab1a984Spatrick #define SSDFB_SET_MULTIPLEX_RATIO		0xa8
50ad478a58Spatrick #define SSDFB_SET_COM_OUTPUT_DIRECTION_NORMAL	0xc0
51ad478a58Spatrick #define SSDFB_SET_COM_OUTPUT_DIRECTION_REMAP	0xc8
52dab1a984Spatrick #define SSDFB_ENTIRE_DISPLAY_ON			0xa4
53dab1a984Spatrick #define SSDFB_SET_DISPLAY_MODE_NORMAL		0xa6
54dab1a984Spatrick #define SSDFB_SET_DISPLAY_MODE_INVERS		0xa7
55dab1a984Spatrick #define SSDFB_SET_DISPLAY_OFF			0xae
56dab1a984Spatrick #define SSDFB_SET_DISPLAY_ON			0xaf
57dab1a984Spatrick #define SSDFB_SET_DISPLAY_OFFSET		0xd3
58dab1a984Spatrick #define SSDFB_SET_DISPLAY_CLOCK_DIVIDE_RATIO	0xd5
59dab1a984Spatrick #define SSDFB_SET_PRE_CHARGE_PERIOD		0xd9
60dab1a984Spatrick #define SSDFB_SET_COM_PINS_HARD_CONF		0xda
61dab1a984Spatrick #define SSDFB_SET_VCOM_DESELECT_LEVEL		0xdb
62eb4f240eSpatrick #define SSDFB_SET_PAGE_START_ADDRESS		0xb0
63dab1a984Spatrick 
64c6a62e52Spatrick #define SSDFB_I2C_COMMAND			0x00
65c6a62e52Spatrick #define SSDFB_I2C_DATA				0x40
66c6a62e52Spatrick 
67dab1a984Spatrick struct ssdfb_softc {
68dab1a984Spatrick 	struct device		 sc_dev;
69dab1a984Spatrick 	int			 sc_node;
70ad478a58Spatrick 	int			 sc_width;
71ad478a58Spatrick 	int			 sc_height;
72ad478a58Spatrick 	int			 sc_pgoff;
73dab1a984Spatrick 
74dab1a984Spatrick 	uint8_t			*sc_fb;
75dab1a984Spatrick 	size_t			 sc_fbsize;
76dab1a984Spatrick 	struct rasops_info	 sc_rinfo;
771c999b93Spatrick 	struct wsdisplay_emulops sc_riops;
781c999b93Spatrick 	int			 (*sc_ri_do_cursor)(struct rasops_info *);
79dab1a984Spatrick 
803f4c1042Spatrick 	uint8_t			 sc_brightness;
813f4c1042Spatrick 	int			 sc_mode;
823f4c1042Spatrick 
83eb4f240eSpatrick 	uint8_t			 sc_column_range[2];
84eb4f240eSpatrick 	uint8_t			 sc_page_range[2];
85eb4f240eSpatrick 
86c6a62e52Spatrick 	/* I2C */
87c6a62e52Spatrick 	i2c_tag_t		 sc_i2c_tag;
88c6a62e52Spatrick 	i2c_addr_t		 sc_i2c_addr;
89c6a62e52Spatrick 
90c6a62e52Spatrick 	/* SPI */
91c6a62e52Spatrick 	spi_tag_t		 sc_spi_tag;
92c6a62e52Spatrick 	struct spi_config	 sc_spi_conf;
93c6a62e52Spatrick 	uint32_t		*sc_gpio;
94c6a62e52Spatrick 	size_t			 sc_gpiolen;
95c6a62e52Spatrick 	int			 sc_cd;
96c6a62e52Spatrick 
97c6a62e52Spatrick 	void			 (*sc_write_command)(struct ssdfb_softc *,
98c6a62e52Spatrick 				   char *, size_t);
99c6a62e52Spatrick 	void			 (*sc_write_data)(struct ssdfb_softc *,
100c6a62e52Spatrick 				   char *, size_t);
101c6a62e52Spatrick 
102dab1a984Spatrick };
103dab1a984Spatrick 
104c6a62e52Spatrick int	 ssdfb_i2c_match(struct device *, void *, void *);
105c6a62e52Spatrick void	 ssdfb_i2c_attach(struct device *, struct device *, void *);
106c6a62e52Spatrick int	 ssdfb_i2c_detach(struct device *, int);
107c6a62e52Spatrick void	 ssdfb_i2c_write_command(struct ssdfb_softc *, char *, size_t);
108c6a62e52Spatrick void	 ssdfb_i2c_write_data(struct ssdfb_softc *, char *, size_t);
109dab1a984Spatrick 
110c6a62e52Spatrick int	 ssdfb_spi_match(struct device *, void *, void *);
111c6a62e52Spatrick void	 ssdfb_spi_attach(struct device *, struct device *, void *);
112c6a62e52Spatrick int	 ssdfb_spi_detach(struct device *, int);
113c6a62e52Spatrick void	 ssdfb_spi_write_command(struct ssdfb_softc *, char *, size_t);
114c6a62e52Spatrick void	 ssdfb_spi_write_data(struct ssdfb_softc *, char *, size_t);
115c6a62e52Spatrick 
116c6a62e52Spatrick void	 ssdfb_attach(struct ssdfb_softc *);
117c6a62e52Spatrick int	 ssdfb_detach(struct ssdfb_softc *, int);
118dab1a984Spatrick void	 ssdfb_write_command(struct ssdfb_softc *, char *, size_t);
119dab1a984Spatrick void	 ssdfb_write_data(struct ssdfb_softc *, char *, size_t);
120dab1a984Spatrick 
121dab1a984Spatrick void	 ssdfb_init(struct ssdfb_softc *);
122dab1a984Spatrick 
123eb4f240eSpatrick void	 ssdfb_partial(struct ssdfb_softc *, uint32_t, uint32_t,
124eb4f240eSpatrick 	    uint32_t, uint32_t);
125eb4f240eSpatrick void	 ssdfb_set_range(struct ssdfb_softc *, uint8_t, uint8_t,
126eb4f240eSpatrick 	    uint8_t, uint8_t);
127eb4f240eSpatrick 
128dab1a984Spatrick int	 ssdfb_ioctl(void *, u_long, caddr_t, int, struct proc *);
129dab1a984Spatrick paddr_t	 ssdfb_mmap(void *, off_t, int);
130dab1a984Spatrick int	 ssdfb_alloc_screen(void *, const struct wsscreen_descr *, void **,
131e0c3e559Sjsg 	    int *, int *, uint32_t *);
132dab1a984Spatrick void	 ssdfb_free_screen(void *, void *);
133dab1a984Spatrick int	 ssdfb_show_screen(void *, void *, int, void (*cb) (void *, int, int),
134dab1a984Spatrick 	    void *);
135dab1a984Spatrick int	 ssdfb_list_font(void *, struct wsdisplay_font *);
136dab1a984Spatrick int	 ssdfb_load_font(void *, void *, struct wsdisplay_font *);
137dab1a984Spatrick 
138e0c3e559Sjsg int	 ssdfb_putchar(void *, int, int, u_int, uint32_t);
1391c999b93Spatrick int	 ssdfb_copycols(void *, int, int, int, int);
140e0c3e559Sjsg int	 ssdfb_erasecols(void *, int, int, int, uint32_t);
1411c999b93Spatrick int	 ssdfb_copyrows(void *, int, int, int);
142e0c3e559Sjsg int	 ssdfb_eraserows(void *, int, int, uint32_t);
1431c999b93Spatrick int	 ssdfb_do_cursor(struct rasops_info *);
1441c999b93Spatrick 
1459fdf0c62Smpi const struct cfattach ssdfb_i2c_ca = {
146dab1a984Spatrick 	sizeof(struct ssdfb_softc),
147c6a62e52Spatrick 	ssdfb_i2c_match,
148c6a62e52Spatrick 	ssdfb_i2c_attach,
149c6a62e52Spatrick 	ssdfb_i2c_detach,
150c6a62e52Spatrick };
151c6a62e52Spatrick 
1529fdf0c62Smpi const struct cfattach ssdfb_spi_ca = {
153c6a62e52Spatrick 	sizeof(struct ssdfb_softc),
154c6a62e52Spatrick 	ssdfb_spi_match,
155c6a62e52Spatrick 	ssdfb_spi_attach,
156c6a62e52Spatrick 	ssdfb_spi_detach,
157dab1a984Spatrick };
158dab1a984Spatrick 
159dab1a984Spatrick struct cfdriver ssdfb_cd = {
160dab1a984Spatrick 	NULL, "ssdfb", DV_DULL
161dab1a984Spatrick };
162dab1a984Spatrick 
163dab1a984Spatrick struct wsscreen_descr ssdfb_std_descr = { "std" };
164dab1a984Spatrick 
165dab1a984Spatrick const struct wsscreen_descr *ssdfb_descrs[] = {
166dab1a984Spatrick 	&ssdfb_std_descr
167dab1a984Spatrick };
168dab1a984Spatrick 
169dab1a984Spatrick const struct wsscreen_list ssdfb_screen_list = {
170dab1a984Spatrick 	nitems(ssdfb_descrs), ssdfb_descrs
171dab1a984Spatrick };
172dab1a984Spatrick 
173dab1a984Spatrick struct wsdisplay_accessops ssdfb_accessops = {
174dab1a984Spatrick 	.ioctl = ssdfb_ioctl,
175dab1a984Spatrick 	.mmap = ssdfb_mmap,
176dab1a984Spatrick 	.alloc_screen = ssdfb_alloc_screen,
177dab1a984Spatrick 	.free_screen = ssdfb_free_screen,
178dab1a984Spatrick 	.show_screen = ssdfb_show_screen,
179dab1a984Spatrick 	.load_font = ssdfb_load_font,
180dab1a984Spatrick 	.list_font = ssdfb_list_font
181dab1a984Spatrick };
182dab1a984Spatrick 
183dab1a984Spatrick int
ssdfb_i2c_match(struct device * parent,void * match,void * aux)184c6a62e52Spatrick ssdfb_i2c_match(struct device *parent, void *match, void *aux)
185c6a62e52Spatrick {
186c6a62e52Spatrick 	struct i2c_attach_args *ia = aux;
187c6a62e52Spatrick 
188fb481783Spatrick 	if (strcmp(ia->ia_name, "solomon,ssd1306fb-i2c") == 0 ||
189fb481783Spatrick 	    strcmp(ia->ia_name, "solomon,ssd1309fb-i2c") == 0)
190c6a62e52Spatrick 		return 1;
191c6a62e52Spatrick 
192c6a62e52Spatrick 	return 0;
193c6a62e52Spatrick }
194c6a62e52Spatrick 
195c6a62e52Spatrick void
ssdfb_i2c_attach(struct device * parent,struct device * self,void * aux)196c6a62e52Spatrick ssdfb_i2c_attach(struct device *parent, struct device *self, void *aux)
197c6a62e52Spatrick {
198c6a62e52Spatrick 	struct ssdfb_softc *sc = (struct ssdfb_softc *)self;
199c6a62e52Spatrick 	struct i2c_attach_args *ia = aux;
200c6a62e52Spatrick 
201c6a62e52Spatrick 	sc->sc_i2c_tag = ia->ia_tag;
202c6a62e52Spatrick 	sc->sc_i2c_addr = ia->ia_addr;
203c6a62e52Spatrick 	sc->sc_node = *(int *)ia->ia_cookie;
204c6a62e52Spatrick 
205c6a62e52Spatrick 	sc->sc_write_command = ssdfb_i2c_write_command;
206c6a62e52Spatrick 	sc->sc_write_data = ssdfb_i2c_write_data;
207c6a62e52Spatrick 
208c6a62e52Spatrick 	ssdfb_attach(sc);
209c6a62e52Spatrick }
210c6a62e52Spatrick 
211c6a62e52Spatrick int
ssdfb_i2c_detach(struct device * self,int flags)212c6a62e52Spatrick ssdfb_i2c_detach(struct device *self, int flags)
213c6a62e52Spatrick {
214c6a62e52Spatrick 	struct ssdfb_softc *sc = (struct ssdfb_softc *)self;
215c6a62e52Spatrick 	ssdfb_detach(sc, flags);
216c6a62e52Spatrick 	return 0;
217c6a62e52Spatrick }
218c6a62e52Spatrick 
219c6a62e52Spatrick int
ssdfb_spi_match(struct device * parent,void * match,void * aux)220c6a62e52Spatrick ssdfb_spi_match(struct device *parent, void *match, void *aux)
221dab1a984Spatrick {
222dab1a984Spatrick 	struct spi_attach_args *sa = aux;
223dab1a984Spatrick 
224dab1a984Spatrick 	if (strcmp(sa->sa_name, "solomon,ssd1309fb-spi") == 0)
225dab1a984Spatrick 		return 1;
226dab1a984Spatrick 
227dab1a984Spatrick 	return 0;
228dab1a984Spatrick }
229dab1a984Spatrick 
230dab1a984Spatrick void
ssdfb_spi_attach(struct device * parent,struct device * self,void * aux)231c6a62e52Spatrick ssdfb_spi_attach(struct device *parent, struct device *self, void *aux)
232dab1a984Spatrick {
233dab1a984Spatrick 	struct ssdfb_softc *sc = (struct ssdfb_softc *)self;
234dab1a984Spatrick 	struct spi_attach_args *sa = aux;
235c6a62e52Spatrick 	ssize_t len;
236dab1a984Spatrick 
237c6a62e52Spatrick 	sc->sc_spi_tag = sa->sa_tag;
238dab1a984Spatrick 	sc->sc_node = *(int *)sa->sa_cookie;
239dab1a984Spatrick 
240c6a62e52Spatrick 	sc->sc_spi_conf.sc_bpw = 8;
241c6a62e52Spatrick 	sc->sc_spi_conf.sc_freq = 1000 * 1000;
242c6a62e52Spatrick 	sc->sc_spi_conf.sc_cs = OF_getpropint(sc->sc_node, "reg", 0);
243dab1a984Spatrick 	if (OF_getproplen(sc->sc_node, "spi-cpol") == 0)
244c6a62e52Spatrick 		sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CPOL;
245dab1a984Spatrick 	if (OF_getproplen(sc->sc_node, "spi-cpha") == 0)
246c6a62e52Spatrick 		sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CPHA;
247dab1a984Spatrick 	if (OF_getproplen(sc->sc_node, "spi-cs-high") == 0)
248c6a62e52Spatrick 		sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CS_HIGH;
249dab1a984Spatrick 
250dab1a984Spatrick 	len = OF_getproplen(sc->sc_node, "cd-gpio");
251dab1a984Spatrick 	if (len <= 0)
252dab1a984Spatrick 		return;
253dab1a984Spatrick 
254dab1a984Spatrick 	sc->sc_gpio = malloc(len, M_DEVBUF, M_WAITOK);
255dab1a984Spatrick 	OF_getpropintarray(sc->sc_node, "cd-gpio", sc->sc_gpio, len);
256dab1a984Spatrick 	sc->sc_gpiolen = len;
257dab1a984Spatrick 	gpio_controller_config_pin(sc->sc_gpio, GPIO_CONFIG_OUTPUT);
258dab1a984Spatrick 	gpio_controller_set_pin(sc->sc_gpio, 0);
259dab1a984Spatrick 
260c6a62e52Spatrick 	sc->sc_write_command = ssdfb_spi_write_command;
261c6a62e52Spatrick 	sc->sc_write_data = ssdfb_spi_write_data;
262c6a62e52Spatrick 
263c6a62e52Spatrick 	ssdfb_attach(sc);
264c6a62e52Spatrick }
265c6a62e52Spatrick 
266c6a62e52Spatrick int
ssdfb_spi_detach(struct device * self,int flags)267c6a62e52Spatrick ssdfb_spi_detach(struct device *self, int flags)
268c6a62e52Spatrick {
269c6a62e52Spatrick 	struct ssdfb_softc *sc = (struct ssdfb_softc *)self;
270c6a62e52Spatrick 	ssdfb_detach(sc, flags);
271c6a62e52Spatrick 	free(sc->sc_gpio, M_DEVBUF, sc->sc_gpiolen);
272c6a62e52Spatrick 	return 0;
273c6a62e52Spatrick }
274c6a62e52Spatrick 
275c6a62e52Spatrick void
ssdfb_attach(struct ssdfb_softc * sc)276c6a62e52Spatrick ssdfb_attach(struct ssdfb_softc *sc)
277c6a62e52Spatrick {
278c6a62e52Spatrick 	struct wsemuldisplaydev_attach_args aa;
279c6a62e52Spatrick 	struct rasops_info *ri;
280c6a62e52Spatrick 	uint32_t *gpio;
281c6a62e52Spatrick 	ssize_t len;
282c6a62e52Spatrick 
283c6a62e52Spatrick 	pinctrl_byname(sc->sc_node, "default");
284c6a62e52Spatrick 
2850d547c3bSpatrick 	len = OF_getproplen(sc->sc_node, "reset-gpios");
286c6a62e52Spatrick 	if (len > 0) {
287c6a62e52Spatrick 		gpio = malloc(len, M_DEVBUF, M_WAITOK);
2880d547c3bSpatrick 		OF_getpropintarray(sc->sc_node, "reset-gpios",
289c6a62e52Spatrick 		    gpio, len);
290c6a62e52Spatrick 		gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT);
291c6a62e52Spatrick 		gpio_controller_set_pin(gpio, 1);
292c6a62e52Spatrick 		delay(100 * 1000);
293c6a62e52Spatrick 		gpio_controller_set_pin(gpio, 0);
294c6a62e52Spatrick 		delay(1000 * 1000);
295c6a62e52Spatrick 		free(gpio, M_DEVBUF, len);
296c6a62e52Spatrick 	}
297c6a62e52Spatrick 
298ad478a58Spatrick 	sc->sc_width = OF_getpropint(sc->sc_node, "solomon,width", 96);
299ad478a58Spatrick 	sc->sc_height = OF_getpropint(sc->sc_node, "solomon,height", 16);
300ad478a58Spatrick 	sc->sc_pgoff = OF_getpropint(sc->sc_node, "solomon,page-offset", 1);
301ad478a58Spatrick 
3023f4c1042Spatrick 	sc->sc_fbsize = round_page((sc->sc_width * sc->sc_height) / 8);
303dab1a984Spatrick 	sc->sc_fb = malloc(sc->sc_fbsize, M_DEVBUF, M_WAITOK | M_ZERO);
304dab1a984Spatrick 
3053f4c1042Spatrick 	sc->sc_brightness = 223;
3063f4c1042Spatrick 
307dab1a984Spatrick 	ri = &sc->sc_rinfo;
308dab1a984Spatrick 	ri->ri_bits = malloc(sc->sc_fbsize, M_DEVBUF, M_WAITOK | M_ZERO);
309ad478a58Spatrick 	ri->ri_bs = mallocarray(sc->sc_width * sc->sc_height,
310ad478a58Spatrick 	    sizeof(struct wsdisplay_charcell), M_DEVBUF, M_WAITOK | M_ZERO);
311dab1a984Spatrick 	ri->ri_flg = RI_CLEAR | RI_VCONS;
312dab1a984Spatrick 	ri->ri_depth = 1;
313ad478a58Spatrick 	ri->ri_width = sc->sc_width;
314ad478a58Spatrick 	ri->ri_height = sc->sc_height;
315dab1a984Spatrick 	ri->ri_stride = ri->ri_width * ri->ri_depth / 8;
3161c999b93Spatrick 	ri->ri_hw = sc;
317dab1a984Spatrick 
318ad478a58Spatrick 	rasops_init(ri, sc->sc_height, sc->sc_width);
319dab1a984Spatrick 	ssdfb_std_descr.ncols = ri->ri_cols;
320dab1a984Spatrick 	ssdfb_std_descr.nrows = ri->ri_rows;
321dab1a984Spatrick 	ssdfb_std_descr.textops = &ri->ri_ops;
322dab1a984Spatrick 	ssdfb_std_descr.fontwidth = ri->ri_font->fontwidth;
323dab1a984Spatrick 	ssdfb_std_descr.fontheight = ri->ri_font->fontheight;
324dab1a984Spatrick 	ssdfb_std_descr.capabilities = ri->ri_caps;
325dab1a984Spatrick 
3261c999b93Spatrick 	sc->sc_riops.putchar = ri->ri_putchar;
3271c999b93Spatrick 	sc->sc_riops.copycols = ri->ri_copycols;
3281c999b93Spatrick 	sc->sc_riops.erasecols = ri->ri_erasecols;
3291c999b93Spatrick 	sc->sc_riops.copyrows = ri->ri_copyrows;
3301c999b93Spatrick 	sc->sc_riops.eraserows = ri->ri_eraserows;
3311c999b93Spatrick 	sc->sc_ri_do_cursor = ri->ri_do_cursor;
3321c999b93Spatrick 
3331c999b93Spatrick 	ri->ri_putchar = ssdfb_putchar;
3341c999b93Spatrick 	ri->ri_copycols = ssdfb_copycols;
3351c999b93Spatrick 	ri->ri_erasecols = ssdfb_erasecols;
3361c999b93Spatrick 	ri->ri_copyrows = ssdfb_copyrows;
3371c999b93Spatrick 	ri->ri_eraserows = ssdfb_eraserows;
3381c999b93Spatrick 	ri->ri_do_cursor = ssdfb_do_cursor;
339dab1a984Spatrick 
340dab1a984Spatrick 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
341dab1a984Spatrick 
342dab1a984Spatrick 	memset(&aa, 0, sizeof(aa));
343dab1a984Spatrick 	aa.console = 0;
344dab1a984Spatrick 	aa.scrdata = &ssdfb_screen_list;
345dab1a984Spatrick 	aa.accessops = &ssdfb_accessops;
346dab1a984Spatrick 	aa.accesscookie = sc;
347dab1a984Spatrick 	aa.defaultscreens = 0;
348dab1a984Spatrick 
349c6a62e52Spatrick 	config_found_sm(&sc->sc_dev, &aa, wsemuldisplaydevprint,
350dab1a984Spatrick 	    wsemuldisplaydevsubmatch);
351dab1a984Spatrick 	ssdfb_init(sc);
352dab1a984Spatrick }
353dab1a984Spatrick 
354dab1a984Spatrick int
ssdfb_detach(struct ssdfb_softc * sc,int flags)355c6a62e52Spatrick ssdfb_detach(struct ssdfb_softc *sc, int flags)
356dab1a984Spatrick {
357dab1a984Spatrick 	struct rasops_info *ri = &sc->sc_rinfo;
358ad478a58Spatrick 	free(ri->ri_bs, M_DEVBUF, sc->sc_width * sc->sc_height *
359ad478a58Spatrick 	    sizeof(struct wsdisplay_charcell));
360dab1a984Spatrick 	free(ri->ri_bits, M_DEVBUF, sc->sc_fbsize);
361dab1a984Spatrick 	free(sc->sc_fb, M_DEVBUF, sc->sc_fbsize);
362dab1a984Spatrick 	return 0;
363dab1a984Spatrick }
364dab1a984Spatrick 
365dab1a984Spatrick void
ssdfb_init(struct ssdfb_softc * sc)366dab1a984Spatrick ssdfb_init(struct ssdfb_softc *sc)
367dab1a984Spatrick {
368dab1a984Spatrick 	uint8_t reg[2];
369dab1a984Spatrick 
370dab1a984Spatrick 	reg[0] = SSDFB_SET_DISPLAY_OFF;
371dab1a984Spatrick 	ssdfb_write_command(sc, reg, 1);
372dab1a984Spatrick 
373eb4f240eSpatrick 	reg[0] = SSDFB_SET_MEMORY_ADDRESSING_MODE;
374eb4f240eSpatrick 	reg[1] = 0x00; /* Horizontal Addressing Mode */
375dab1a984Spatrick 	ssdfb_write_command(sc, reg, 2);
376eb4f240eSpatrick 	reg[0] = SSDFB_SET_PAGE_START_ADDRESS;
377dab1a984Spatrick 	ssdfb_write_command(sc, reg, 1);
378ad478a58Spatrick 	ssdfb_set_range(sc, 0, sc->sc_width - 1,
379ad478a58Spatrick 	    0, (sc->sc_height / 8) - 1);
380ad478a58Spatrick 	if (OF_is_compatible(sc->sc_node, "solomon,ssd1309fb-i2c") ||
381ad478a58Spatrick 	    OF_is_compatible(sc->sc_node, "solomon,ssd1309fb-spi")) {
382dab1a984Spatrick 		reg[0] = SSDFB_SET_DISPLAY_CLOCK_DIVIDE_RATIO;
383dab1a984Spatrick 		reg[1] = 0xa0;
384dab1a984Spatrick 		ssdfb_write_command(sc, reg, 2);
385ad478a58Spatrick 	}
386fb481783Spatrick 	if (OF_is_compatible(sc->sc_node, "solomon,ssd1306fb-i2c")) {
387fb481783Spatrick 		reg[0] = SSDFB_SET_DISPLAY_CLOCK_DIVIDE_RATIO;
388fb481783Spatrick 		reg[1] = 0x80;
389fb481783Spatrick 		ssdfb_write_command(sc, reg, 2);
390fb481783Spatrick 	}
391dab1a984Spatrick 	reg[0] = SSDFB_SET_MULTIPLEX_RATIO;
392dab1a984Spatrick 	reg[1] = 0x3f;
393dab1a984Spatrick 	ssdfb_write_command(sc, reg, 2);
394dab1a984Spatrick 	reg[0] = SSDFB_SET_DISPLAY_OFFSET;
395ad478a58Spatrick 	reg[1] = OF_getpropint(sc->sc_node, "solomon,com-offset", 0);
396dab1a984Spatrick 	ssdfb_write_command(sc, reg, 2);
397dab1a984Spatrick 	reg[0] = SSDFB_SET_START_LINE | 0x00;
398dab1a984Spatrick 	ssdfb_write_command(sc, reg, 1);
399ad478a58Spatrick 	reg[0] = SSDFB_SET_COLUMN_DIRECTION_NORMAL;
400ad478a58Spatrick 	if (OF_getproplen(sc->sc_node, "solomon,com-invdir") == 0)
401dab1a984Spatrick 		reg[0] = SSDFB_SET_COLUMN_DIRECTION_REVERSE;
402dab1a984Spatrick 	ssdfb_write_command(sc, reg, 1);
403ad478a58Spatrick 	reg[0] = SSDFB_SET_COM_OUTPUT_DIRECTION_REMAP;
404ad478a58Spatrick 	if (OF_getproplen(sc->sc_node, "solomon,segment-no-remap") == 0)
405ad478a58Spatrick 		reg[0] = SSDFB_SET_COM_OUTPUT_DIRECTION_NORMAL;
406dab1a984Spatrick 	ssdfb_write_command(sc, reg, 1);
407dab1a984Spatrick 	reg[0] = SSDFB_SET_COM_PINS_HARD_CONF;
408dab1a984Spatrick 	reg[1] = 0x12;
409ad478a58Spatrick 	if (OF_getproplen(sc->sc_node, "solomon,com-seq") == 0)
410ad478a58Spatrick 		reg[1] &= ~(1 << 4);
411ad478a58Spatrick 	if (OF_getproplen(sc->sc_node, "solomon,com-lrremap") == 0)
412ad478a58Spatrick 		reg[1] |= 1 << 5;
413dab1a984Spatrick 	ssdfb_write_command(sc, reg, 2);
414dab1a984Spatrick 	reg[0] = SSDFB_SET_CONTRAST_CONTROL;
4153f4c1042Spatrick 	reg[1] = sc->sc_brightness;
416dab1a984Spatrick 	ssdfb_write_command(sc, reg, 2);
417dab1a984Spatrick 	reg[0] = SSDFB_SET_PRE_CHARGE_PERIOD;
418ad478a58Spatrick 	reg[1] = (OF_getpropint(sc->sc_node, "solomon,prechargep1", 2) & 0xf) << 0;
419ad478a58Spatrick 	reg[1] |= (OF_getpropint(sc->sc_node, "solomon,prechargep2", 2) & 0xf) << 4;
420dab1a984Spatrick 	ssdfb_write_command(sc, reg, 2);
421ad478a58Spatrick 	if (OF_is_compatible(sc->sc_node, "solomon,ssd1309fb-i2c") ||
422ad478a58Spatrick 	    OF_is_compatible(sc->sc_node, "solomon,ssd1309fb-spi")) {
423dab1a984Spatrick 		reg[0] = SSDFB_SET_VCOM_DESELECT_LEVEL;
424dab1a984Spatrick 		reg[1] = 0x34;
425dab1a984Spatrick 		ssdfb_write_command(sc, reg, 2);
426ad478a58Spatrick 	}
427fb481783Spatrick 	if (OF_is_compatible(sc->sc_node, "solomon,ssd1306fb-i2c")) {
428fb481783Spatrick 		reg[0] = SSDFB_SET_VCOM_DESELECT_LEVEL;
429fb481783Spatrick 		reg[1] = 0x20;
430fb481783Spatrick 		ssdfb_write_command(sc, reg, 2);
431fb481783Spatrick 	}
432fb481783Spatrick 	reg[0] = SSDFB_CHARGE_PUMP;
433fb481783Spatrick 	reg[1] = 0x10;
434fb481783Spatrick 	if (OF_is_compatible(sc->sc_node, "solomon,ssd1306fb-i2c"))
435fb481783Spatrick 		reg[1] |= 1 << 2;
436fb481783Spatrick 	ssdfb_write_command(sc, reg, 2);
437dab1a984Spatrick 	reg[0] = SSDFB_ENTIRE_DISPLAY_ON;
438dab1a984Spatrick 	ssdfb_write_command(sc, reg, 1);
439dab1a984Spatrick 	reg[0] = SSDFB_SET_DISPLAY_MODE_NORMAL;
440dab1a984Spatrick 	ssdfb_write_command(sc, reg, 1);
441dab1a984Spatrick 
442ad478a58Spatrick 	ssdfb_partial(sc, 0, sc->sc_width, 0, sc->sc_height);
443dab1a984Spatrick 
444dab1a984Spatrick 	reg[0] = SSDFB_SET_DISPLAY_ON;
445dab1a984Spatrick 	ssdfb_write_command(sc, reg, 1);
446dab1a984Spatrick }
447dab1a984Spatrick 
448dab1a984Spatrick void
ssdfb_set_range(struct ssdfb_softc * sc,uint8_t x1,uint8_t x2,uint8_t y1,uint8_t y2)449eb4f240eSpatrick ssdfb_set_range(struct ssdfb_softc *sc, uint8_t x1, uint8_t x2,
450eb4f240eSpatrick     uint8_t y1, uint8_t y2)
451eb4f240eSpatrick {
452eb4f240eSpatrick 	uint8_t reg[3];
453eb4f240eSpatrick 
454ad478a58Spatrick 	y1 += sc->sc_pgoff;
455ad478a58Spatrick 	y2 += sc->sc_pgoff;
456ad478a58Spatrick 
457eb4f240eSpatrick 	if (sc->sc_column_range[0] != x1 || sc->sc_column_range[1] != x2) {
458eb4f240eSpatrick 		sc->sc_column_range[0] = x1;
459eb4f240eSpatrick 		sc->sc_column_range[1] = x2;
460eb4f240eSpatrick 		reg[0] = SSDFB_SET_COLUMN_RANGE;
461eb4f240eSpatrick 		reg[1] = sc->sc_column_range[0];
462eb4f240eSpatrick 		reg[2] = sc->sc_column_range[1];
463eb4f240eSpatrick 		ssdfb_write_command(sc, reg, 3);
464eb4f240eSpatrick 	}
465eb4f240eSpatrick 	if (sc->sc_page_range[0] != y1 || sc->sc_page_range[1] != y2) {
466eb4f240eSpatrick 		sc->sc_page_range[0] = y1;
467eb4f240eSpatrick 		sc->sc_page_range[1] = y2;
468eb4f240eSpatrick 		reg[0] = SSDFB_SET_PAGE_RANGE;
469eb4f240eSpatrick 		reg[1] = sc->sc_page_range[0];
470eb4f240eSpatrick 		reg[2] = sc->sc_page_range[1];
471eb4f240eSpatrick 		ssdfb_write_command(sc, reg, 3);
472eb4f240eSpatrick 	}
473eb4f240eSpatrick }
474eb4f240eSpatrick 
475eb4f240eSpatrick void
ssdfb_partial(struct ssdfb_softc * sc,uint32_t x1,uint32_t x2,uint32_t y1,uint32_t y2)476eb4f240eSpatrick ssdfb_partial(struct ssdfb_softc *sc, uint32_t x1, uint32_t x2,
477eb4f240eSpatrick     uint32_t y1, uint32_t y2)
478eb4f240eSpatrick {
479dab1a984Spatrick 	struct rasops_info *ri = &sc->sc_rinfo;
480eb4f240eSpatrick 	uint32_t off, width, height;
481dab1a984Spatrick 	uint8_t *bit, val;
482dab1a984Spatrick 	int i, j, k;
483dab1a984Spatrick 
484eb4f240eSpatrick 	if (x2 < x1 || y2 < y1)
485eb4f240eSpatrick 		return;
486dab1a984Spatrick 
487ad478a58Spatrick 	if (x2 > sc->sc_width || y2 > sc->sc_height)
488eb4f240eSpatrick 		return;
489eb4f240eSpatrick 
490eb4f240eSpatrick 	y1 = y1 & ~0x7;
491eb4f240eSpatrick 	y2 = roundup(y2, 8);
492eb4f240eSpatrick 
493eb4f240eSpatrick 	width = x2 - x1;
494eb4f240eSpatrick 	height = y2 - y1;
495eb4f240eSpatrick 
496eb4f240eSpatrick 	memset(sc->sc_fb, 0, (width * height) / 8);
497eb4f240eSpatrick 
498eb4f240eSpatrick 	for (i = 0; i < height; i += 8) {
499eb4f240eSpatrick 		for (j = 0; j < width; j++) {
500eb4f240eSpatrick 			bit = &sc->sc_fb[(i / 8) * width + j];
501dab1a984Spatrick 			for (k = 0; k < 8; k++) {
502eb4f240eSpatrick 				off = ri->ri_stride * (y1 + i + k);
503eb4f240eSpatrick 				off += (x1 + j) / 8;
504dab1a984Spatrick 				val = *(ri->ri_bits + off);
505eb4f240eSpatrick 				val &= (1 << ((x1 + j) % 8));
506dab1a984Spatrick 				*bit |= !!val << k;
507dab1a984Spatrick 			}
508dab1a984Spatrick 		}
509dab1a984Spatrick 	}
510dab1a984Spatrick 
511eb4f240eSpatrick 	ssdfb_set_range(sc, x1, x2 - 1, y1 / 8, (y2 / 8) - 1);
512eb4f240eSpatrick 	ssdfb_write_data(sc, sc->sc_fb, (width * height) / 8);
513dab1a984Spatrick }
514dab1a984Spatrick 
515dab1a984Spatrick void
ssdfb_write_command(struct ssdfb_softc * sc,char * buf,size_t len)516dab1a984Spatrick ssdfb_write_command(struct ssdfb_softc *sc, char *buf, size_t len)
517dab1a984Spatrick {
518c6a62e52Spatrick 	return sc->sc_write_command(sc, buf, len);
519c6a62e52Spatrick }
520c6a62e52Spatrick 
521c6a62e52Spatrick void
ssdfb_write_data(struct ssdfb_softc * sc,char * buf,size_t len)522c6a62e52Spatrick ssdfb_write_data(struct ssdfb_softc *sc, char *buf, size_t len)
523c6a62e52Spatrick {
524c6a62e52Spatrick 	return sc->sc_write_data(sc, buf, len);
525c6a62e52Spatrick }
526c6a62e52Spatrick 
527c6a62e52Spatrick void
ssdfb_i2c_write_command(struct ssdfb_softc * sc,char * buf,size_t len)528c6a62e52Spatrick ssdfb_i2c_write_command(struct ssdfb_softc *sc, char *buf, size_t len)
529c6a62e52Spatrick {
530c6a62e52Spatrick 	uint8_t type;
531c6a62e52Spatrick 
532c6a62e52Spatrick 	type = SSDFB_I2C_COMMAND;
533c6a62e52Spatrick 	iic_acquire_bus(sc->sc_i2c_tag, 0);
534c6a62e52Spatrick 	if (iic_exec(sc->sc_i2c_tag, I2C_OP_WRITE_WITH_STOP,
535c6a62e52Spatrick 	    sc->sc_i2c_addr, &type, sizeof(type), buf, len, 0)) {
536c6a62e52Spatrick 		printf("%s: cannot write\n", sc->sc_dev.dv_xname);
537c6a62e52Spatrick 	}
538c6a62e52Spatrick 	iic_release_bus(sc->sc_i2c_tag, 0);
539c6a62e52Spatrick }
540c6a62e52Spatrick 
541c6a62e52Spatrick void
ssdfb_i2c_write_data(struct ssdfb_softc * sc,char * buf,size_t len)542c6a62e52Spatrick ssdfb_i2c_write_data(struct ssdfb_softc *sc, char *buf, size_t len)
543c6a62e52Spatrick {
544c6a62e52Spatrick 	uint8_t type;
545c6a62e52Spatrick 
546c6a62e52Spatrick 	type = SSDFB_I2C_DATA;
547c6a62e52Spatrick 	iic_acquire_bus(sc->sc_i2c_tag, 0);
548c6a62e52Spatrick 	if (iic_exec(sc->sc_i2c_tag, I2C_OP_WRITE_WITH_STOP,
549c6a62e52Spatrick 	    sc->sc_i2c_addr, &type, sizeof(type), buf, len, 0)) {
550c6a62e52Spatrick 		printf("%s: cannot write\n", sc->sc_dev.dv_xname);
551c6a62e52Spatrick 	}
552c6a62e52Spatrick 	iic_release_bus(sc->sc_i2c_tag, 0);
553c6a62e52Spatrick }
554c6a62e52Spatrick 
555c6a62e52Spatrick void
ssdfb_spi_write_command(struct ssdfb_softc * sc,char * buf,size_t len)556c6a62e52Spatrick ssdfb_spi_write_command(struct ssdfb_softc *sc, char *buf, size_t len)
557c6a62e52Spatrick {
558dab1a984Spatrick 	if (sc->sc_cd != 0) {
559dab1a984Spatrick 		gpio_controller_set_pin(sc->sc_gpio, 0);
560dab1a984Spatrick 		sc->sc_cd = 0;
561dab1a984Spatrick 		delay(1);
562dab1a984Spatrick 	}
563dab1a984Spatrick 
564c6a62e52Spatrick 	spi_acquire_bus(sc->sc_spi_tag, 0);
565c6a62e52Spatrick 	spi_config(sc->sc_spi_tag, &sc->sc_spi_conf);
566c6a62e52Spatrick 	if (spi_write(sc->sc_spi_tag, buf, len))
567dab1a984Spatrick 		printf("%s: cannot write\n", sc->sc_dev.dv_xname);
568c6a62e52Spatrick 	spi_release_bus(sc->sc_spi_tag, 0);
569dab1a984Spatrick }
570dab1a984Spatrick 
571dab1a984Spatrick void
ssdfb_spi_write_data(struct ssdfb_softc * sc,char * buf,size_t len)572c6a62e52Spatrick ssdfb_spi_write_data(struct ssdfb_softc *sc, char *buf, size_t len)
573dab1a984Spatrick {
574dab1a984Spatrick 	if (sc->sc_cd != 1) {
575dab1a984Spatrick 		gpio_controller_set_pin(sc->sc_gpio, 1);
576dab1a984Spatrick 		sc->sc_cd = 1;
577dab1a984Spatrick 		delay(1);
578dab1a984Spatrick 	}
579dab1a984Spatrick 
580c6a62e52Spatrick 	spi_acquire_bus(sc->sc_spi_tag, 0);
581c6a62e52Spatrick 	spi_config(sc->sc_spi_tag, &sc->sc_spi_conf);
582c6a62e52Spatrick 	if (spi_write(sc->sc_spi_tag, buf, len))
583dab1a984Spatrick 		printf("%s: cannot write\n", sc->sc_dev.dv_xname);
584c6a62e52Spatrick 	spi_release_bus(sc->sc_spi_tag, 0);
585dab1a984Spatrick }
586dab1a984Spatrick 
587dab1a984Spatrick int
ssdfb_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)588dab1a984Spatrick ssdfb_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
589dab1a984Spatrick {
590dab1a984Spatrick 	struct ssdfb_softc	*sc = v;
591dab1a984Spatrick 	struct rasops_info 	*ri = &sc->sc_rinfo;
5923f4c1042Spatrick 	struct wsdisplay_param	*dp = (struct wsdisplay_param *)data;
593dab1a984Spatrick 	struct wsdisplay_fbinfo	*wdf;
5943f4c1042Spatrick 	struct udl_ioctl_damage *d;
5953f4c1042Spatrick 	int			 mode;
5963f4c1042Spatrick 	uint8_t			 reg[2];
597dab1a984Spatrick 
598dab1a984Spatrick 	switch (cmd) {
599dab1a984Spatrick 	case WSDISPLAYIO_GETPARAM:
6003f4c1042Spatrick 		switch (dp->param) {
6013f4c1042Spatrick 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
6023f4c1042Spatrick 			dp->min = 0;
6033f4c1042Spatrick 			dp->max = 255;
6043f4c1042Spatrick 			dp->curval = sc->sc_brightness;
6053f4c1042Spatrick 			break;
6063f4c1042Spatrick 		default:
607dab1a984Spatrick 			return (-1);
6083f4c1042Spatrick 		}
6093f4c1042Spatrick 		break;
6103f4c1042Spatrick 	case WSDISPLAYIO_SETPARAM:
6113f4c1042Spatrick 		switch (dp->param) {
6123f4c1042Spatrick 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
6133f4c1042Spatrick 			if (dp->curval == 0) {
6143f4c1042Spatrick 				reg[0] = SSDFB_SET_DISPLAY_OFF;
6153f4c1042Spatrick 				ssdfb_write_command(sc, reg, 1);
6163f4c1042Spatrick 			} else if (sc->sc_brightness == 0) {
6173f4c1042Spatrick 				reg[0] = SSDFB_SET_DISPLAY_ON;
6183f4c1042Spatrick 				ssdfb_write_command(sc, reg, 1);
6193f4c1042Spatrick 			}
6203f4c1042Spatrick 			reg[0] = SSDFB_SET_CONTRAST_CONTROL;
6213f4c1042Spatrick 			reg[1] = sc->sc_brightness = dp->curval;
6223f4c1042Spatrick 			ssdfb_write_command(sc, reg, 2);
6233f4c1042Spatrick 			break;
6243f4c1042Spatrick 		default:
6253f4c1042Spatrick 			return (-1);
6263f4c1042Spatrick 		}
6273f4c1042Spatrick 		break;
628dab1a984Spatrick 	case WSDISPLAYIO_GTYPE:
6293f4c1042Spatrick 		*(u_int *)data = WSDISPLAY_TYPE_DL;
630dab1a984Spatrick 		break;
631dab1a984Spatrick 	case WSDISPLAYIO_GINFO:
632dab1a984Spatrick 		wdf = (struct wsdisplay_fbinfo *)data;
633dab1a984Spatrick 		wdf->width = ri->ri_width;
634dab1a984Spatrick 		wdf->height = ri->ri_height;
635dab1a984Spatrick 		wdf->depth = ri->ri_depth;
63663294167Skettenis 		wdf->stride = ri->ri_stride;
63763294167Skettenis 		wdf->offset = 0;
638dab1a984Spatrick 		wdf->cmsize = 0;	/* color map is unavailable */
639dab1a984Spatrick 		break;
640dab1a984Spatrick 	case WSDISPLAYIO_LINEBYTES:
641dab1a984Spatrick 		*(u_int *)data = ri->ri_stride;
642dab1a984Spatrick 		break;
643dab1a984Spatrick 	case WSDISPLAYIO_SMODE:
6443f4c1042Spatrick 		mode = *(u_int *)data;
6453f4c1042Spatrick 		switch (mode) {
6463f4c1042Spatrick 		case WSDISPLAYIO_MODE_EMUL:
6473f4c1042Spatrick 			if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) {
6483f4c1042Spatrick 				memset(ri->ri_bits, 0, sc->sc_fbsize);
6493f4c1042Spatrick 				ssdfb_partial(sc, 0, sc->sc_width,
6503f4c1042Spatrick 				    0, sc->sc_height);
6513f4c1042Spatrick 				sc->sc_mode = mode;
6523f4c1042Spatrick 			}
6533f4c1042Spatrick 			break;
6543f4c1042Spatrick 		case WSDISPLAYIO_MODE_DUMBFB:
6553f4c1042Spatrick 			if (sc->sc_mode != WSDISPLAYIO_MODE_DUMBFB) {
6563f4c1042Spatrick 				memset(ri->ri_bits, 0, sc->sc_fbsize);
6573f4c1042Spatrick 				ssdfb_partial(sc, 0, sc->sc_width,
6583f4c1042Spatrick 				    0, sc->sc_height);
6593f4c1042Spatrick 				sc->sc_mode = mode;
6603f4c1042Spatrick 			}
6613f4c1042Spatrick 			break;
6623f4c1042Spatrick 		case WSDISPLAYIO_MODE_MAPPED:
6633f4c1042Spatrick 		default:
6643f4c1042Spatrick 			return (-1);
6653f4c1042Spatrick 		}
666dab1a984Spatrick 		break;
667dab1a984Spatrick 	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
668dab1a984Spatrick 		*(u_int *)data = WSDISPLAYIO_DEPTH_1;
669dab1a984Spatrick 		break;
6703f4c1042Spatrick 	case UDLIO_DAMAGE:
6713f4c1042Spatrick 		d = (struct udl_ioctl_damage *)data;
6723f4c1042Spatrick 		d->status = UDLIO_STATUS_OK;
6733f4c1042Spatrick 		ssdfb_partial(sc, d->x1, d->x2, d->y1, d->y2);
6743f4c1042Spatrick 		break;
675dab1a984Spatrick 	default:
676dab1a984Spatrick 		return (-1);
677dab1a984Spatrick 	}
678dab1a984Spatrick 
679dab1a984Spatrick 	return (0);
680dab1a984Spatrick }
681dab1a984Spatrick 
682dab1a984Spatrick paddr_t
ssdfb_mmap(void * v,off_t off,int prot)683dab1a984Spatrick ssdfb_mmap(void *v, off_t off, int prot)
684dab1a984Spatrick {
6853f4c1042Spatrick 	struct ssdfb_softc	*sc = v;
6863f4c1042Spatrick 	struct rasops_info	*ri = &sc->sc_rinfo;
6873f4c1042Spatrick 	paddr_t			 pa;
6883f4c1042Spatrick 
6893f4c1042Spatrick 	if (off >= sc->sc_fbsize || off < 0)
6903f4c1042Spatrick 		return (-1);
6913f4c1042Spatrick 
6923f4c1042Spatrick 	if (!pmap_extract(pmap_kernel(), (vaddr_t)ri->ri_bits, &pa))
6933f4c1042Spatrick 		return (-1);
6943f4c1042Spatrick 
6953f4c1042Spatrick 	return (pa + off);
696dab1a984Spatrick }
697dab1a984Spatrick 
698dab1a984Spatrick int
ssdfb_alloc_screen(void * v,const struct wsscreen_descr * descr,void ** cookiep,int * curxp,int * curyp,uint32_t * attrp)699dab1a984Spatrick ssdfb_alloc_screen(void *v, const struct wsscreen_descr *descr,
700e0c3e559Sjsg     void **cookiep, int *curxp, int *curyp, uint32_t *attrp)
701dab1a984Spatrick {
702dab1a984Spatrick 	struct ssdfb_softc	*sc = v;
703dab1a984Spatrick 	struct rasops_info	*ri = &sc->sc_rinfo;
704dab1a984Spatrick 
705dab1a984Spatrick 	return rasops_alloc_screen(ri, cookiep, curxp, curyp, attrp);
706dab1a984Spatrick }
707dab1a984Spatrick 
708dab1a984Spatrick void
ssdfb_free_screen(void * v,void * cookie)709dab1a984Spatrick ssdfb_free_screen(void *v, void *cookie)
710dab1a984Spatrick {
711dab1a984Spatrick 	struct ssdfb_softc	*sc = v;
712dab1a984Spatrick 	struct rasops_info	*ri = &sc->sc_rinfo;
713dab1a984Spatrick 
714dab1a984Spatrick 	rasops_free_screen(ri, cookie);
715dab1a984Spatrick }
716dab1a984Spatrick 
717dab1a984Spatrick int
ssdfb_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cb_arg)718dab1a984Spatrick ssdfb_show_screen(void *v, void *cookie, int waitok,
719dab1a984Spatrick     void (*cb) (void *, int, int), void *cb_arg)
720dab1a984Spatrick {
721dab1a984Spatrick 	struct ssdfb_softc	*sc = v;
722dab1a984Spatrick 	struct rasops_info	*ri = &sc->sc_rinfo;
723dab1a984Spatrick 
724dab1a984Spatrick 	return rasops_show_screen(ri, cookie, waitok, cb, cb_arg);
725dab1a984Spatrick }
726dab1a984Spatrick 
727dab1a984Spatrick int
ssdfb_load_font(void * v,void * cookie,struct wsdisplay_font * font)728dab1a984Spatrick ssdfb_load_font(void *v, void *cookie, struct wsdisplay_font *font)
729dab1a984Spatrick {
730dab1a984Spatrick 	struct ssdfb_softc	*sc = v;
731dab1a984Spatrick 	struct rasops_info	*ri = &sc->sc_rinfo;
732dab1a984Spatrick 
733dab1a984Spatrick 	return (rasops_load_font(ri, cookie, font));
734dab1a984Spatrick }
735dab1a984Spatrick 
736dab1a984Spatrick int
ssdfb_list_font(void * v,struct wsdisplay_font * font)737dab1a984Spatrick ssdfb_list_font(void *v, struct wsdisplay_font *font)
738dab1a984Spatrick {
739dab1a984Spatrick 	struct ssdfb_softc	*sc = v;
740dab1a984Spatrick 	struct rasops_info	*ri = &sc->sc_rinfo;
741dab1a984Spatrick 
742dab1a984Spatrick 	return (rasops_list_font(ri, font));
743dab1a984Spatrick }
7441c999b93Spatrick 
7451c999b93Spatrick int
ssdfb_putchar(void * cookie,int row,int col,u_int uc,uint32_t attr)746e0c3e559Sjsg ssdfb_putchar(void *cookie, int row, int col, u_int uc, uint32_t attr)
7471c999b93Spatrick {
7481c999b93Spatrick 	struct rasops_info *ri = (struct rasops_info *)cookie;
7491c999b93Spatrick 	struct ssdfb_softc *sc = ri->ri_hw;
7501c999b93Spatrick 
7511c999b93Spatrick 	sc->sc_riops.putchar(cookie, row, col, uc, attr);
7521c999b93Spatrick 	ssdfb_partial(sc,
7531c999b93Spatrick 	    col * ri->ri_font->fontwidth,
7541c999b93Spatrick 	    (col + 1) * ri->ri_font->fontwidth,
7551c999b93Spatrick 	    row * ri->ri_font->fontheight,
7561c999b93Spatrick 	    (row + 1) * ri->ri_font->fontheight);
7571c999b93Spatrick 	return 0;
7581c999b93Spatrick }
7591c999b93Spatrick 
7601c999b93Spatrick int
ssdfb_copycols(void * cookie,int row,int src,int dst,int num)7611c999b93Spatrick ssdfb_copycols(void *cookie, int row, int src, int dst, int num)
7621c999b93Spatrick {
7631c999b93Spatrick 	struct rasops_info *ri = (struct rasops_info *)cookie;
7641c999b93Spatrick 	struct ssdfb_softc *sc = ri->ri_hw;
7651c999b93Spatrick 
7661c999b93Spatrick 	sc->sc_riops.copycols(cookie, row, src, dst, num);
7671c999b93Spatrick 	ssdfb_partial(sc,
7681c999b93Spatrick 	    dst * ri->ri_font->fontwidth,
7691c999b93Spatrick 	    (dst + num) * ri->ri_font->fontwidth,
7701c999b93Spatrick 	    row * ri->ri_font->fontheight,
7711c999b93Spatrick 	    (row + 1) * ri->ri_font->fontheight);
7721c999b93Spatrick 	return 0;
7731c999b93Spatrick }
7741c999b93Spatrick 
7751c999b93Spatrick int
ssdfb_erasecols(void * cookie,int row,int col,int num,uint32_t attr)776e0c3e559Sjsg ssdfb_erasecols(void *cookie, int row, int col, int num, uint32_t attr)
7771c999b93Spatrick {
7781c999b93Spatrick 	struct rasops_info *ri = (struct rasops_info *)cookie;
7791c999b93Spatrick 	struct ssdfb_softc *sc = ri->ri_hw;
7801c999b93Spatrick 
7811c999b93Spatrick 	sc->sc_riops.erasecols(cookie, row, col, num, attr);
7821c999b93Spatrick 	ssdfb_partial(sc,
7831c999b93Spatrick 	    col * ri->ri_font->fontwidth,
7841c999b93Spatrick 	    (col + num) * ri->ri_font->fontwidth,
7851c999b93Spatrick 	    row * ri->ri_font->fontheight,
7861c999b93Spatrick 	    (row + 1) * ri->ri_font->fontheight);
7871c999b93Spatrick 	return 0;
7881c999b93Spatrick }
7891c999b93Spatrick 
7901c999b93Spatrick int
ssdfb_copyrows(void * cookie,int src,int dst,int num)7911c999b93Spatrick ssdfb_copyrows(void *cookie, int src, int dst, int num)
7921c999b93Spatrick {
7931c999b93Spatrick 	struct rasops_info *ri = (struct rasops_info *)cookie;
7941c999b93Spatrick 	struct ssdfb_softc *sc = ri->ri_hw;
7951c999b93Spatrick 
7961c999b93Spatrick 	sc->sc_riops.copyrows(cookie, src, dst, num);
797ad478a58Spatrick 	ssdfb_partial(sc, 0, sc->sc_width,
7981c999b93Spatrick 	    dst * ri->ri_font->fontheight,
7991c999b93Spatrick 	    (dst + num) * ri->ri_font->fontheight);
8001c999b93Spatrick 	return 0;
8011c999b93Spatrick }
8021c999b93Spatrick 
8031c999b93Spatrick int
ssdfb_eraserows(void * cookie,int row,int num,uint32_t attr)804e0c3e559Sjsg ssdfb_eraserows(void *cookie, int row, int num, uint32_t attr)
8051c999b93Spatrick {
8061c999b93Spatrick 	struct rasops_info *ri = (struct rasops_info *)cookie;
8071c999b93Spatrick 	struct ssdfb_softc *sc = ri->ri_hw;
8081c999b93Spatrick 
8091c999b93Spatrick 	sc->sc_riops.eraserows(cookie, row, num, attr);
8101c999b93Spatrick 	if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0)
811ad478a58Spatrick 		ssdfb_partial(sc, 0, sc->sc_width, 0, sc->sc_height);
8121c999b93Spatrick 	else
813ad478a58Spatrick 		ssdfb_partial(sc, 0, sc->sc_width,
8141c999b93Spatrick 		    row * ri->ri_font->fontheight,
8151c999b93Spatrick 		    (row + num) * ri->ri_font->fontheight);
8161c999b93Spatrick 	return 0;
8171c999b93Spatrick }
8181c999b93Spatrick 
8191c999b93Spatrick int
ssdfb_do_cursor(struct rasops_info * ri)8201c999b93Spatrick ssdfb_do_cursor(struct rasops_info *ri)
8211c999b93Spatrick {
8221c999b93Spatrick 	struct ssdfb_softc *sc = ri->ri_hw;
8231c999b93Spatrick 	int orow, ocol, nrow, ncol;
8241c999b93Spatrick 
8251c999b93Spatrick 	orow = ri->ri_crow;
8261c999b93Spatrick 	ocol = ri->ri_ccol;
8271c999b93Spatrick 	sc->sc_ri_do_cursor(ri);
8281c999b93Spatrick 	nrow = ri->ri_crow;
8291c999b93Spatrick 	ncol = ri->ri_ccol;
8301c999b93Spatrick 
8311c999b93Spatrick 	ssdfb_partial(sc,
8321c999b93Spatrick 	    ocol * ri->ri_font->fontwidth,
8331c999b93Spatrick 	    (ocol + 1) * ri->ri_font->fontwidth,
8341c999b93Spatrick 	    orow * ri->ri_font->fontheight,
8351c999b93Spatrick 	    (orow + 1) * ri->ri_font->fontheight);
8361c999b93Spatrick 	ssdfb_partial(sc,
8371c999b93Spatrick 	    ncol * ri->ri_font->fontwidth,
8381c999b93Spatrick 	    (ncol + 1) * ri->ri_font->fontwidth,
8391c999b93Spatrick 	    nrow * ri->ri_font->fontheight,
8401c999b93Spatrick 	    (nrow + 1) * ri->ri_font->fontheight);
8411c999b93Spatrick 
8421c999b93Spatrick 	return 0;
8431c999b93Spatrick }
844