udl.c revision 278799
1/*	$OpenBSD: udl.c,v 1.81 2014/12/09 07:05:06 doug Exp $ */
2/*	$FreeBSD: head/sys/dev/usb/video/udl.c 278799 2015-02-15 12:02:17Z hselasky $ */
3
4/*-
5 * Copyright (c) 2015 Hans Petter Selasky <hselasky@freebsd.org>
6 * Copyright (c) 2009 Marcus Glocker <mglocker@openbsd.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21/*
22 * Driver for the "DisplayLink DL-120 / DL-160" graphic chips based on
23 * the reversed engineered specifications of Florian Echtler
24 * <floe@butterbrot.org>:
25 *
26 * 	http://floe.butterbrot.org/displaylink/doku.php
27 */
28
29#include <sys/param.h>
30#include <sys/bus.h>
31#include <sys/callout.h>
32#include <sys/conf.h>
33#include <sys/kernel.h>
34#include <sys/lock.h>
35#include <sys/module.h>
36#include <sys/mutex.h>
37#include <sys/condvar.h>
38#include <sys/sysctl.h>
39#include <sys/systm.h>
40#include <sys/consio.h>
41#include <sys/fbio.h>
42
43#include <dev/fb/fbreg.h>
44#include <dev/syscons/syscons.h>
45
46#include <dev/videomode/videomode.h>
47#include <dev/videomode/edidvar.h>
48
49#include <dev/usb/usb.h>
50#include <dev/usb/usbdi.h>
51#include <dev/usb/usbdi_util.h>
52#include "usbdevs.h"
53
54#include <dev/usb/video/udl.h>
55
56#include "fb_if.h"
57
58#undef DPRINTF
59#undef DPRINTFN
60#define	USB_DEBUG_VAR udl_debug
61#include <dev/usb/usb_debug.h>
62
63#ifdef USB_DEBUG
64static int udl_debug = 0;
65
66static	SYSCTL_NODE(_hw_usb, OID_AUTO, udl, CTLFLAG_RW, 0, "USB UDL");
67
68SYSCTL_INT(_hw_usb_udl, OID_AUTO, debug, CTLFLAG_RWTUN,
69    &udl_debug, 0, "Debug level");
70#endif
71
72/*
73 * Prototypes.
74 */
75static usb_callback_t udl_bulk_write_callback;
76
77static device_probe_t udl_probe;
78static device_attach_t udl_attach;
79static device_detach_t udl_detach;
80static fb_getinfo_t udl_fb_getinfo;
81#if 0
82static fb_blank_display_t udl_fb_blank_display;
83#endif
84
85static void udl_select_chip(struct udl_softc *, struct usb_attach_arg *);
86static int udl_init_chip(struct udl_softc *);
87static void udl_select_mode(struct udl_softc *);
88static int udl_init_resolution(struct udl_softc *);
89static void udl_fbmem_alloc(struct udl_softc *);
90static int udl_cmd_write_buf_le16(struct udl_softc *, const uint8_t *, uint32_t, uint8_t, int);
91static int udl_cmd_buf_copy_le16(struct udl_softc *, uint32_t, uint32_t, uint8_t, int);
92static void udl_cmd_insert_int_1(struct udl_cmd_buf *, uint8_t);
93static void udl_cmd_insert_int_3(struct udl_cmd_buf *, uint32_t);
94static void udl_cmd_insert_buf_le16(struct udl_cmd_buf *, const uint8_t *, uint32_t);
95static void udl_cmd_write_reg_1(struct udl_cmd_buf *, uint8_t, uint8_t);
96static void udl_cmd_write_reg_3(struct udl_cmd_buf *, uint8_t, uint32_t);
97#if 0
98static int udl_power_save(struct udl_softc *, int, int);
99#endif
100
101static const struct usb_config udl_config[UDL_N_TRANSFER] = {
102	[UDL_BULK_WRITE_0] = {
103		.type = UE_BULK,
104		.endpoint = UE_ADDR_ANY,
105		.direction = UE_DIR_TX,
106		.flags = {.pipe_bof = 1,.force_short_xfer = 1,.ext_buffer = 1,},
107		.bufsize = UDL_CMD_MAX_DATA_SIZE * UDL_CMD_MAX_FRAMES,
108		.callback = &udl_bulk_write_callback,
109		.frames = UDL_CMD_MAX_FRAMES,
110		.timeout = 5000,	/* 5 seconds */
111	},
112	[UDL_BULK_WRITE_1] = {
113		.type = UE_BULK,
114		.endpoint = UE_ADDR_ANY,
115		.direction = UE_DIR_TX,
116		.flags = {.pipe_bof = 1,.force_short_xfer = 1,.ext_buffer = 1,},
117		.bufsize = UDL_CMD_MAX_DATA_SIZE * UDL_CMD_MAX_FRAMES,
118		.callback = &udl_bulk_write_callback,
119		.frames = UDL_CMD_MAX_FRAMES,
120		.timeout = 5000,	/* 5 seconds */
121	},
122};
123
124/*
125 * Driver glue.
126 */
127static devclass_t udl_devclass;
128
129static device_method_t udl_methods[] = {
130	DEVMETHOD(device_probe, udl_probe),
131	DEVMETHOD(device_attach, udl_attach),
132	DEVMETHOD(device_detach, udl_detach),
133	DEVMETHOD(fb_getinfo, udl_fb_getinfo),
134#if 0
135	DEVMETHOD(fb_blank_display, udl_fb_blank_display),
136#endif
137	DEVMETHOD_END
138};
139
140static driver_t udl_driver = {
141	.name = "udl",
142	.methods = udl_methods,
143	.size = sizeof(struct udl_softc),
144};
145
146DRIVER_MODULE(udl, uhub, udl_driver, udl_devclass, NULL, NULL);
147MODULE_DEPEND(udl, usb, 1, 1, 1);
148MODULE_DEPEND(udl, fbd, 1, 1, 1);
149MODULE_DEPEND(udl, videomode, 1, 1, 1);
150MODULE_VERSION(udl, 1);
151
152/*
153 * Matching devices.
154 */
155static const STRUCT_USB_HOST_ID udl_devs[] = {
156	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCD4300U, DL120)},
157	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCD8000U, DL120)},
158	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_GUC2020, DL160)},
159	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LD220, DL165)},
160	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_VCUD60, DL160)},
161	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_DLDVI, DL160)},
162	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_VGA10, DL120)},
163	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_WSDVI, DLUNK)},
164	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_EC008, DL160)},
165	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_HPDOCK, DL160)},
166	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_NL571, DL160)},
167	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_M01061, DL195)},
168	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_NBDOCK, DL165)},
169	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_SWDVI, DLUNK)},
170	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_UM7X0, DL120)},
171	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_CONV, DL160)},
172	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LUM70, DL125)},
173	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_POLARIS2, DLUNK)},
174	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LT1421, DLUNK)}
175};
176
177static uint32_t
178udl_get_fb_size(struct udl_softc *sc)
179{
180	unsigned i = sc->sc_cur_mode;
181
182	return ((uint32_t)udl_modes[i].hdisplay *
183	    (uint32_t)udl_modes[i].vdisplay * 2);
184}
185
186static uint32_t
187udl_get_fb_width(struct udl_softc *sc)
188{
189	unsigned i = sc->sc_cur_mode;
190
191	return (udl_modes[i].vdisplay);
192}
193
194static uint32_t
195udl_get_fb_height(struct udl_softc *sc)
196{
197	unsigned i = sc->sc_cur_mode;
198
199	return (udl_modes[i].hdisplay);
200}
201
202static uint32_t
203udl_get_fb_hz(struct udl_softc *sc)
204{
205	unsigned i = sc->sc_cur_mode;
206
207	return (udl_modes[i].hz);
208}
209
210static void
211udl_callout(void *arg)
212{
213	struct udl_softc *sc = arg;
214	const uint32_t max = udl_get_fb_size(sc);
215
216	if (sc->sc_power_save == 0) {
217		if (sc->sc_sync_off >= max)
218			sc->sc_sync_off = 0;
219		usbd_transfer_start(sc->sc_xfer[UDL_BULK_WRITE_0]);
220		usbd_transfer_start(sc->sc_xfer[UDL_BULK_WRITE_1]);
221	}
222	callout_reset(&sc->sc_callout, hz / 5, &udl_callout, sc);
223}
224
225static int
226udl_probe(device_t dev)
227{
228	struct usb_attach_arg *uaa = device_get_ivars(dev);
229
230	if (uaa->usb_mode != USB_MODE_HOST)
231		return (ENXIO);
232	if (uaa->info.bConfigIndex != 0)
233		return (ENXIO);
234	if (uaa->info.bIfaceIndex != 0)
235		return (ENXIO);
236
237	return (usbd_lookup_id_by_uaa(udl_devs, sizeof(udl_devs), uaa));
238}
239
240static int
241udl_attach(device_t dev)
242{
243	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
244	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
245	struct udl_softc *sc = device_get_softc(dev);
246	struct usb_attach_arg *uaa = device_get_ivars(dev);
247	int error;
248	int i;
249
250	device_set_usb_desc(dev);
251
252	mtx_init(&sc->sc_mtx, "UDL lock", NULL, MTX_DEF);
253	cv_init(&sc->sc_cv, "UDLCV");
254	callout_init_mtx(&sc->sc_callout, &sc->sc_mtx, 0);
255	sc->sc_udev = uaa->device;
256
257	error = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex,
258	    sc->sc_xfer, udl_config, UDL_N_TRANSFER, sc, &sc->sc_mtx);
259
260	if (error) {
261		DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(error));
262		goto detach;
263	}
264	usbd_xfer_set_priv(sc->sc_xfer[UDL_BULK_WRITE_0], &sc->sc_xfer_head[0]);
265	usbd_xfer_set_priv(sc->sc_xfer[UDL_BULK_WRITE_1], &sc->sc_xfer_head[1]);
266
267	TAILQ_INIT(&sc->sc_xfer_head[0]);
268	TAILQ_INIT(&sc->sc_xfer_head[1]);
269	TAILQ_INIT(&sc->sc_cmd_buf_free);
270	TAILQ_INIT(&sc->sc_cmd_buf_pending);
271
272	sc->sc_def_chip = -1;
273	sc->sc_chip = USB_GET_DRIVER_INFO(uaa);
274	sc->sc_def_mode = -1;
275	sc->sc_cur_mode = UDL_MAX_MODES;
276
277	/* Allow chip ID to be overwritten */
278	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "chipid_force",
279	    CTLFLAG_RWTUN, &sc->sc_def_chip, 0, "chip ID");
280
281	/* Export current chip ID */
282	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "chipid",
283	    CTLFLAG_RD, &sc->sc_chip, 0, "chip ID");
284
285	if (sc->sc_def_chip > -1 && sc->sc_def_chip <= DLMAX) {
286		device_printf(dev, "Forcing chip ID to 0x%04x\n", sc->sc_def_chip);
287		sc->sc_chip = sc->sc_def_chip;
288	}
289	/*
290	 * The product might have more than one chip
291	 */
292	if (sc->sc_chip == DLUNK)
293		udl_select_chip(sc, uaa);
294
295	for (i = 0; i != UDL_CMD_MAX_BUFFERS; i++) {
296		struct udl_cmd_buf *cb = &sc->sc_cmd_buf_temp[i];
297
298		TAILQ_INSERT_TAIL(&sc->sc_cmd_buf_free, cb, entry);
299	}
300
301	/*
302	 * Initialize chip.
303	 */
304	error = udl_init_chip(sc);
305	if (error != USB_ERR_NORMAL_COMPLETION)
306		goto detach;
307
308	/*
309	 * Select edid mode.
310	 */
311	udl_select_mode(sc);
312
313	/* Allow default mode to be overwritten */
314	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "mode_force",
315	    CTLFLAG_RWTUN, &sc->sc_def_mode, 0, "mode");
316
317	/* Export current mode */
318	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "mode",
319	    CTLFLAG_RD, &sc->sc_cur_mode, 0, "mode");
320
321	i = sc->sc_def_mode;
322	if (i > -1 && i < UDL_MAX_MODES) {
323		if (udl_modes[i].chip <= sc->sc_chip) {
324			device_printf(dev, "Forcing mode to %d\n", i);
325			sc->sc_cur_mode = i;
326		}
327	}
328	/* Printout current mode */
329	device_printf(dev, "Mode selected %dx%d @ %dHz\n",
330	    (int)udl_get_fb_width(sc),
331	    (int)udl_get_fb_height(sc),
332	    (int)udl_get_fb_hz(sc));
333
334	udl_init_resolution(sc);
335
336	/* Allocate frame buffer */
337	udl_fbmem_alloc(sc);
338
339	UDL_LOCK(sc);
340	udl_callout(sc);
341	UDL_UNLOCK(sc);
342
343	sc->sc_fb_info.fb_name = device_get_nameunit(dev);
344	sc->sc_fb_info.fb_size = sc->sc_fb_size;
345	sc->sc_fb_info.fb_bpp = 16;
346	sc->sc_fb_info.fb_depth = 16;
347	sc->sc_fb_info.fb_width = udl_get_fb_width(sc);
348	sc->sc_fb_info.fb_height = udl_get_fb_height(sc);
349	sc->sc_fb_info.fb_stride = sc->sc_fb_info.fb_width * 2;
350	sc->sc_fb_info.fb_pbase = (uintptr_t)sc->sc_fb_addr;
351	sc->sc_fb_info.fb_vbase = (uintptr_t)sc->sc_fb_addr;
352
353	sc->sc_fbdev = device_add_child(dev, "fbd", -1);
354	if (sc->sc_fbdev == NULL)
355		goto detach;
356	if (device_probe_and_attach(sc->sc_fbdev) != 0)
357		goto detach;
358
359	return (0);
360
361detach:
362	udl_detach(dev);
363
364	return (ENXIO);
365}
366
367static int
368udl_detach(device_t dev)
369{
370	struct udl_softc *sc = device_get_softc(dev);
371
372	if (sc->sc_fbdev != NULL) {
373		device_t bdev;
374
375		bdev = sc->sc_fbdev;
376		sc->sc_fbdev = NULL;
377		device_detach(bdev);
378		device_delete_child(dev, bdev);
379	}
380	UDL_LOCK(sc);
381	sc->sc_gone = 1;
382	callout_stop(&sc->sc_callout);
383	UDL_UNLOCK(sc);
384
385	usbd_transfer_unsetup(sc->sc_xfer, UDL_N_TRANSFER);
386
387	callout_drain(&sc->sc_callout);
388
389	mtx_destroy(&sc->sc_mtx);
390	cv_destroy(&sc->sc_cv);
391
392	/*
393	 * Free framebuffer memory, if any.
394	 */
395	free(sc->sc_fb_addr, M_DEVBUF);
396	free(sc->sc_fb_copy, M_DEVBUF);
397
398	return (0);
399}
400
401static struct fb_info *
402udl_fb_getinfo(device_t dev)
403{
404	struct udl_softc *sc = device_get_softc(dev);
405
406	return (&sc->sc_fb_info);
407}
408
409#if 0
410static int
411udl_fb_blank_display(device_t dev, int mode)
412{
413	struct udl_softc *sc = device_get_softc(dev);
414
415	switch (mode) {
416	case V_DISPLAY_ON:
417		udl_power_save(sc, 1, M_WAITOK);
418		break;
419	case V_DISPLAY_BLANK:
420		udl_power_save(sc, 1, M_WAITOK);
421		if (sc->sc_fb_addr != 0) {
422			const uint32_t max = udl_get_fb_size(sc);
423
424			memset((void *)sc->sc_fb_addr, 0, max);
425		}
426		break;
427	case V_DISPLAY_STAND_BY:
428	case V_DISPLAY_SUSPEND:
429		udl_power_save(sc, 0, M_WAITOK);
430		break;
431	}
432	return (0);
433}
434#endif
435
436static struct udl_cmd_buf *
437udl_cmd_buf_alloc(struct udl_softc *sc, int flags)
438{
439	struct udl_cmd_buf *cb;
440
441	UDL_LOCK(sc);
442	while ((cb = TAILQ_FIRST(&sc->sc_cmd_buf_free)) == NULL) {
443		if (flags != M_WAITOK)
444			break;
445		cv_wait(&sc->sc_cv, &sc->sc_mtx);
446	}
447	if (cb != NULL) {
448		TAILQ_REMOVE(&sc->sc_cmd_buf_free, cb, entry);
449		cb->off = 0;
450	}
451	UDL_UNLOCK(sc);
452	return (cb);
453}
454
455static void
456udl_cmd_buf_send(struct udl_softc *sc, struct udl_cmd_buf *cb)
457{
458	UDL_LOCK(sc);
459	if (sc->sc_gone) {
460		TAILQ_INSERT_TAIL(&sc->sc_cmd_buf_free, cb, entry);
461	} else {
462		/* mark end of command stack */
463		udl_cmd_insert_int_1(cb, UDL_BULK_SOC);
464		udl_cmd_insert_int_1(cb, UDL_BULK_CMD_EOC);
465
466		TAILQ_INSERT_TAIL(&sc->sc_cmd_buf_pending, cb, entry);
467		usbd_transfer_start(sc->sc_xfer[UDL_BULK_WRITE_0]);
468		usbd_transfer_start(sc->sc_xfer[UDL_BULK_WRITE_1]);
469	}
470	UDL_UNLOCK(sc);
471}
472
473static struct udl_cmd_buf *
474udl_fb_synchronize(struct udl_softc *sc)
475{
476	const uint32_t max = udl_get_fb_size(sc);
477
478	while (sc->sc_sync_off < max) {
479		uint32_t delta = max - sc->sc_sync_off;
480
481		if (delta > UDL_CMD_MAX_PIXEL_COUNT * 2)
482			delta = UDL_CMD_MAX_PIXEL_COUNT * 2;
483		if (bcmp(sc->sc_fb_addr + sc->sc_sync_off, sc->sc_fb_copy + sc->sc_sync_off, delta) != 0) {
484			struct udl_cmd_buf *cb;
485
486			cb = udl_cmd_buf_alloc(sc, M_NOWAIT);
487			if (cb == NULL)
488				goto done;
489			memcpy(sc->sc_fb_copy + sc->sc_sync_off,
490			    sc->sc_fb_addr + sc->sc_sync_off, delta);
491			udl_cmd_insert_int_1(cb, UDL_BULK_SOC);
492			udl_cmd_insert_int_1(cb, UDL_BULK_CMD_FB_WRITE | UDL_BULK_CMD_FB_WORD);
493			udl_cmd_insert_int_3(cb, sc->sc_sync_off);
494			udl_cmd_insert_int_1(cb, delta / 2);
495			udl_cmd_insert_buf_le16(cb, sc->sc_fb_copy + sc->sc_sync_off, delta);
496			sc->sc_sync_off += delta;
497			return (cb);
498		} else {
499			sc->sc_sync_off += delta;
500		}
501	}
502done:
503	return (NULL);
504}
505
506static void
507udl_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
508{
509	struct udl_softc *sc = usbd_xfer_softc(xfer);
510	struct udl_cmd_head *phead = usbd_xfer_get_priv(xfer);
511	struct udl_cmd_buf *cb;
512	unsigned i;
513
514	switch (USB_GET_STATE(xfer)) {
515	case USB_ST_TRANSFERRED:
516		TAILQ_CONCAT(&sc->sc_cmd_buf_free, phead, entry);
517	case USB_ST_SETUP:
518tr_setup:
519		for (i = 0; i != UDL_CMD_MAX_FRAMES; i++) {
520			cb = TAILQ_FIRST(&sc->sc_cmd_buf_pending);
521			if (cb == NULL) {
522				cb = udl_fb_synchronize(sc);
523				if (cb == NULL)
524					break;
525			}
526			TAILQ_REMOVE(&sc->sc_cmd_buf_pending, cb, entry);
527			TAILQ_INSERT_TAIL(phead, cb, entry);
528			usbd_xfer_set_frame_data(xfer, i, cb->buf, cb->off);
529		}
530		if (i != 0) {
531			usbd_xfer_set_frames(xfer, i);
532			usbd_transfer_submit(xfer);
533		}
534		break;
535	default:
536		TAILQ_CONCAT(&sc->sc_cmd_buf_free, phead, entry);
537		if (error != USB_ERR_CANCELLED) {
538			/* try clear stall first */
539			usbd_xfer_set_stall(xfer);
540			goto tr_setup;
541		}
542		break;
543	}
544	/* wakeup any waiters */
545	cv_signal(&sc->sc_cv);
546}
547
548#if 0
549static int
550udl_power_save(struct udl_softc *sc, int on, int flags)
551{
552	struct udl_cmd_buf *cb;
553
554	/* get new buffer */
555	cb = udl_cmd_buf_alloc(sc, flags);
556	if (cb == NULL)
557		return (EAGAIN);
558
559	DPRINTF("screen %s\n", on ? "ON" : "OFF");
560
561	sc->sc_power_save = on ? 0 : 1;
562
563	if (on)
564		udl_cmd_write_reg_1(cb, UDL_REG_SCREEN, UDL_REG_SCREEN_ON);
565	else
566		udl_cmd_write_reg_1(cb, UDL_REG_SCREEN, UDL_REG_SCREEN_OFF);
567
568	udl_cmd_write_reg_1(cb, UDL_REG_SYNC, 0xff);
569	udl_cmd_buf_send(sc, cb);
570	return (0);
571}
572#endif
573
574static int
575udl_ctrl_msg(struct udl_softc *sc, uint8_t rt, uint8_t r,
576    uint16_t index, uint16_t value, uint8_t *buf, size_t len)
577{
578	usb_device_request_t req;
579	int error;
580
581	req.bmRequestType = rt;
582	req.bRequest = r;
583	USETW(req.wIndex, index);
584	USETW(req.wValue, value);
585	USETW(req.wLength, len);
586
587	error = usbd_do_request_flags(sc->sc_udev, NULL,
588	    &req, buf, 0, NULL, USB_DEFAULT_TIMEOUT);
589
590	DPRINTF("%s\n", usbd_errstr(error));
591
592	return (error);
593}
594
595static int
596udl_poll(struct udl_softc *sc, uint32_t *buf)
597{
598	uint32_t lbuf;
599	int error;
600
601	error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE,
602	    UDL_CTRL_CMD_POLL, 0x0000, 0x0000, (uint8_t *)&lbuf, sizeof(lbuf));
603	if (error == USB_ERR_NORMAL_COMPLETION)
604		*buf = le32toh(lbuf);
605	return (error);
606}
607
608static int
609udl_read_1(struct udl_softc *sc, uint16_t addr, uint8_t *buf)
610{
611	uint8_t lbuf[1];
612	int error;
613
614	error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE,
615	    UDL_CTRL_CMD_READ_1, addr, 0x0000, lbuf, 1);
616	if (error == USB_ERR_NORMAL_COMPLETION)
617		*buf = *(uint8_t *)lbuf;
618	return (error);
619}
620
621static int
622udl_write_1(struct udl_softc *sc, uint16_t addr, uint8_t buf)
623{
624	int error;
625
626	error = udl_ctrl_msg(sc, UT_WRITE_VENDOR_DEVICE,
627	    UDL_CTRL_CMD_WRITE_1, addr, 0x0000, &buf, 1);
628	return (error);
629}
630
631static int
632udl_read_edid(struct udl_softc *sc, uint8_t *buf)
633{
634	uint8_t lbuf[64];
635	uint16_t offset;
636	int error;
637
638	offset = 0;
639
640	error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE,
641	    UDL_CTRL_CMD_READ_EDID, 0x00a1, (offset << 8), lbuf, 64);
642	if (error != USB_ERR_NORMAL_COMPLETION)
643		goto fail;
644	bcopy(lbuf + 1, buf + offset, 63);
645	offset += 63;
646
647	error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE,
648	    UDL_CTRL_CMD_READ_EDID, 0x00a1, (offset << 8), lbuf, 64);
649	if (error != USB_ERR_NORMAL_COMPLETION)
650		goto fail;
651	bcopy(lbuf + 1, buf + offset, 63);
652	offset += 63;
653
654	error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE,
655	    UDL_CTRL_CMD_READ_EDID, 0x00a1, (offset << 8), lbuf, 3);
656	if (error != USB_ERR_NORMAL_COMPLETION)
657		goto fail;
658	bcopy(lbuf + 1, buf + offset, 2);
659fail:
660	return (error);
661}
662
663static uint8_t
664udl_lookup_mode(uint16_t hdisplay, uint16_t vdisplay, uint8_t hz,
665    uint16_t chip, uint32_t clock)
666{
667	uint8_t idx;
668
669	/*
670	 * Check first if we have a matching mode with pixelclock
671	 */
672	for (idx = 0; idx != UDL_MAX_MODES; idx++) {
673		if ((udl_modes[idx].hdisplay == hdisplay) &&
674		    (udl_modes[idx].vdisplay == vdisplay) &&
675		    (udl_modes[idx].clock == clock) &&
676		    (udl_modes[idx].chip <= chip)) {
677			return (idx);
678		}
679	}
680
681	/*
682	 * If not, check for matching mode with update frequency
683	 */
684	for (idx = 0; idx != UDL_MAX_MODES; idx++) {
685		if ((udl_modes[idx].hdisplay == hdisplay) &&
686		    (udl_modes[idx].vdisplay == vdisplay) &&
687		    (udl_modes[idx].hz == hz) &&
688		    (udl_modes[idx].chip <= chip)) {
689			return (idx);
690		}
691	}
692	return (idx);
693}
694
695static void
696udl_select_chip(struct udl_softc *sc, struct usb_attach_arg *uaa)
697{
698	const char *pserial;
699
700	pserial = usb_get_serial(uaa->device);
701
702	sc->sc_chip = DL120;
703
704	if ((uaa->info.idVendor == USB_VENDOR_DISPLAYLINK) &&
705	    (uaa->info.idProduct == USB_PRODUCT_DISPLAYLINK_WSDVI)) {
706
707		/*
708		 * WS Tech DVI is DL120 or DL160. All deviced uses the
709		 * same revision (0.04) so iSerialNumber must be used
710		 * to determin which chip it is.
711		 */
712
713		if (strlen(pserial) > 7) {
714			if (strncmp(pserial, "0198-13", 7) == 0)
715				sc->sc_chip = DL160;
716		}
717		DPRINTF("iSerialNumber (%s) used to select chip (%d)\n",
718		    pserial, sc->sc_chip);
719	}
720	if ((uaa->info.idVendor == USB_VENDOR_DISPLAYLINK) &&
721	    (uaa->info.idProduct == USB_PRODUCT_DISPLAYLINK_SWDVI)) {
722
723		/*
724		 * SUNWEIT DVI is DL160, DL125, DL165 or DL195. Major revision
725		 * can be used to differ between DL1x0 and DL1x5. Minor to
726		 * differ between DL1x5. iSerialNumber seems not to be uniqe.
727		 */
728
729		sc->sc_chip = DL160;
730
731		if (uaa->info.bcdDevice >= 0x100) {
732			sc->sc_chip = DL165;
733			if (uaa->info.bcdDevice == 0x104)
734				sc->sc_chip = DL195;
735			if (uaa->info.bcdDevice == 0x108)
736				sc->sc_chip = DL125;
737		}
738		DPRINTF("bcdDevice (%02x) used to select chip (%d)\n",
739		    uaa->info.bcdDevice, sc->sc_chip);
740	}
741}
742
743static int
744udl_set_enc_key(struct udl_softc *sc, uint8_t *buf, uint8_t len)
745{
746	int error;
747
748	error = udl_ctrl_msg(sc, UT_WRITE_VENDOR_DEVICE,
749	    UDL_CTRL_CMD_SET_KEY, 0x0000, 0x0000, buf, len);
750	return (error);
751}
752
753static void
754udl_fbmem_alloc(struct udl_softc *sc)
755{
756	uint32_t size;
757
758	size = udl_get_fb_size(sc);
759	size = round_page(size);
760
761	sc->sc_fb_addr = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
762	sc->sc_fb_copy = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
763	sc->sc_fb_size = size;
764}
765
766static void
767udl_cmd_insert_int_1(struct udl_cmd_buf *cb, uint8_t value)
768{
769
770	cb->buf[cb->off] = value;
771	cb->off += 1;
772}
773
774#if 0
775static void
776udl_cmd_insert_int_2(struct udl_cmd_buf *cb, uint16_t value)
777{
778	uint16_t lvalue;
779
780	lvalue = htobe16(value);
781	bcopy(&lvalue, cb->buf + cb->off, 2);
782
783	cb->off += 2;
784}
785
786#endif
787
788static void
789udl_cmd_insert_int_3(struct udl_cmd_buf *cb, uint32_t value)
790{
791	uint32_t lvalue;
792
793#if BYTE_ORDER == BIG_ENDIAN
794	lvalue = htobe32(value) << 8;
795#else
796	lvalue = htobe32(value) >> 8;
797#endif
798	bcopy(&lvalue, cb->buf + cb->off, 3);
799
800	cb->off += 3;
801}
802
803#if 0
804static void
805udl_cmd_insert_int_4(struct udl_cmd_buf *cb, uint32_t value)
806{
807	uint32_t lvalue;
808
809	lvalue = htobe32(value);
810	bcopy(&lvalue, cb->buf + cb->off, 4);
811
812	cb->off += 4;
813}
814
815#endif
816
817static void
818udl_cmd_insert_buf_le16(struct udl_cmd_buf *cb, const uint8_t *buf, uint32_t len)
819{
820	uint32_t x;
821
822	for (x = 0; x != len; x += 2) {
823		/* byte swap from little endian to big endian */
824		cb->buf[cb->off + x + 0] = buf[x + 1];
825		cb->buf[cb->off + x + 1] = buf[x + 0];
826	}
827	cb->off += len;
828}
829
830static void
831udl_cmd_write_reg_1(struct udl_cmd_buf *cb, uint8_t reg, uint8_t val)
832{
833
834	udl_cmd_insert_int_1(cb, UDL_BULK_SOC);
835	udl_cmd_insert_int_1(cb, UDL_BULK_CMD_REG_WRITE_1);
836	udl_cmd_insert_int_1(cb, reg);
837	udl_cmd_insert_int_1(cb, val);
838}
839
840static void
841udl_cmd_write_reg_3(struct udl_cmd_buf *cb, uint8_t reg, uint32_t val)
842{
843
844	udl_cmd_write_reg_1(cb, reg + 0, (val >> 16) & 0xff);
845	udl_cmd_write_reg_1(cb, reg + 1, (val >> 8) & 0xff);
846	udl_cmd_write_reg_1(cb, reg + 2, (val >> 0) & 0xff);
847}
848
849static int
850udl_init_chip(struct udl_softc *sc)
851{
852	uint32_t ui32;
853	uint8_t ui8;
854	int error;
855
856	error = udl_poll(sc, &ui32);
857	if (error != USB_ERR_NORMAL_COMPLETION)
858		return (error);
859	DPRINTF("poll=0x%08x\n", ui32);
860
861	/* Some products may use later chip too */
862	switch (ui32 & 0xff) {
863	case 0xf1:			/* DL1x5 */
864		switch (sc->sc_chip) {
865		case DL120:
866			sc->sc_chip = DL125;
867			break;
868		case DL160:
869			sc->sc_chip = DL165;
870			break;
871		}
872		break;
873	}
874	DPRINTF("chip 0x%04x\n", sc->sc_chip);
875
876	error = udl_read_1(sc, 0xc484, &ui8);
877	if (error != USB_ERR_NORMAL_COMPLETION)
878		return (error);
879	DPRINTF("read 0x%02x from 0xc484\n", ui8);
880
881	error = udl_write_1(sc, 0xc41f, 0x01);
882	if (error != USB_ERR_NORMAL_COMPLETION)
883		return (error);
884	DPRINTF("write 0x01 to 0xc41f\n");
885
886	error = udl_read_edid(sc, sc->sc_edid);
887	if (error != USB_ERR_NORMAL_COMPLETION)
888		return (error);
889	DPRINTF("read EDID\n");
890
891	error = udl_set_enc_key(sc, __DECONST(void *, udl_null_key_1),
892	    sizeof(udl_null_key_1));
893	if (error != USB_ERR_NORMAL_COMPLETION)
894		return (error);
895	DPRINTF("set encryption key\n");
896
897	error = udl_write_1(sc, 0xc40b, 0x00);
898	if (error != USB_ERR_NORMAL_COMPLETION)
899		return (error);
900	DPRINTF("write 0x00 to 0xc40b\n");
901
902	return (USB_ERR_NORMAL_COMPLETION);
903}
904
905static void
906udl_init_fb_offsets(struct udl_cmd_buf *cb, uint32_t start16, uint32_t stride16,
907    uint32_t start8, uint32_t stride8)
908{
909	udl_cmd_write_reg_1(cb, UDL_REG_SYNC, 0x00);
910	udl_cmd_write_reg_3(cb, UDL_REG_ADDR_START16, start16);
911	udl_cmd_write_reg_3(cb, UDL_REG_ADDR_STRIDE16, stride16);
912	udl_cmd_write_reg_3(cb, UDL_REG_ADDR_START8, start8);
913	udl_cmd_write_reg_3(cb, UDL_REG_ADDR_STRIDE8, stride8);
914	udl_cmd_write_reg_1(cb, UDL_REG_SYNC, 0xff);
915}
916
917static int
918udl_init_resolution(struct udl_softc *sc)
919{
920	const uint32_t max = udl_get_fb_size(sc);
921	const uint8_t *buf = udl_modes[sc->sc_cur_mode].mode;
922	struct udl_cmd_buf *cb;
923	uint32_t delta;
924	uint32_t i;
925	int error;
926
927	/* get new buffer */
928	cb = udl_cmd_buf_alloc(sc, M_WAITOK);
929	if (cb == NULL)
930		return (EAGAIN);
931
932	/* write resolution values and set video memory offsets */
933	udl_cmd_write_reg_1(cb, UDL_REG_SYNC, 0x00);
934	for (i = 0; i < UDL_MODE_SIZE; i++)
935		udl_cmd_write_reg_1(cb, i, buf[i]);
936	udl_cmd_write_reg_1(cb, UDL_REG_SYNC, 0xff);
937
938	udl_init_fb_offsets(cb, 0x000000, 0x000a00, 0x555555, 0x000500);
939	udl_cmd_buf_send(sc, cb);
940
941	/* fill screen with black color */
942	for (i = 0; i < max; i += delta) {
943		static const uint8_t udl_black[UDL_CMD_MAX_PIXEL_COUNT * 2] __aligned(4);
944
945		delta = max - i;
946		if (delta > UDL_CMD_MAX_PIXEL_COUNT * 2)
947			delta = UDL_CMD_MAX_PIXEL_COUNT * 2;
948		if (i == 0)
949			error = udl_cmd_write_buf_le16(sc, udl_black, i, delta / 2, M_WAITOK);
950		else
951			error = udl_cmd_buf_copy_le16(sc, 0, i, delta / 2, M_WAITOK);
952		if (error)
953			return (error);
954	}
955
956	/* get new buffer */
957	cb = udl_cmd_buf_alloc(sc, M_WAITOK);
958	if (cb == NULL)
959		return (EAGAIN);
960
961	/* show framebuffer content */
962	udl_cmd_write_reg_1(cb, UDL_REG_SCREEN, UDL_REG_SCREEN_ON);
963	udl_cmd_write_reg_1(cb, UDL_REG_SYNC, 0xff);
964	udl_cmd_buf_send(sc, cb);
965	return (0);
966}
967
968static void
969udl_select_mode(struct udl_softc *sc)
970{
971	struct udl_mode mode;
972	int index = UDL_MAX_MODES;
973	int i;
974
975	/* try to get the preferred mode from EDID */
976	edid_parse(sc->sc_edid, &sc->sc_edid_info);
977#ifdef USB_DEBUG
978	edid_print(&sc->sc_edid_info);
979#endif
980	if (sc->sc_edid_info.edid_preferred_mode != NULL) {
981		mode.hz =
982		    (sc->sc_edid_info.edid_preferred_mode->dot_clock * 1000) /
983		    (sc->sc_edid_info.edid_preferred_mode->htotal *
984		    sc->sc_edid_info.edid_preferred_mode->vtotal);
985		mode.clock =
986		    sc->sc_edid_info.edid_preferred_mode->dot_clock / 10;
987		mode.hdisplay =
988		    sc->sc_edid_info.edid_preferred_mode->hdisplay;
989		mode.vdisplay =
990		    sc->sc_edid_info.edid_preferred_mode->vdisplay;
991		index = udl_lookup_mode(mode.hdisplay, mode.vdisplay, mode.hz,
992		    sc->sc_chip, mode.clock);
993		sc->sc_cur_mode = index;
994	} else {
995		DPRINTF("no preferred mode found!\n");
996	}
997
998	if (index == UDL_MAX_MODES) {
999		DPRINTF("no mode line found for %dx%d @ %dHz!\n",
1000		    mode.hdisplay, mode.vdisplay, mode.hz);
1001
1002		i = 0;
1003		while (i < sc->sc_edid_info.edid_nmodes) {
1004			mode.hz =
1005			    (sc->sc_edid_info.edid_modes[i].dot_clock * 1000) /
1006			    (sc->sc_edid_info.edid_modes[i].htotal *
1007			    sc->sc_edid_info.edid_modes[i].vtotal);
1008			mode.clock =
1009			    sc->sc_edid_info.edid_modes[i].dot_clock / 10;
1010			mode.hdisplay =
1011			    sc->sc_edid_info.edid_modes[i].hdisplay;
1012			mode.vdisplay =
1013			    sc->sc_edid_info.edid_modes[i].vdisplay;
1014			index = udl_lookup_mode(mode.hdisplay, mode.vdisplay,
1015			    mode.hz, sc->sc_chip, mode.clock);
1016			if (index < UDL_MAX_MODES)
1017				if ((sc->sc_cur_mode == UDL_MAX_MODES) ||
1018				    (index > sc->sc_cur_mode))
1019					sc->sc_cur_mode = index;
1020			i++;
1021		}
1022	}
1023	/*
1024	 * If no mode found use default.
1025	 */
1026	if (sc->sc_cur_mode == UDL_MAX_MODES)
1027		sc->sc_cur_mode = udl_lookup_mode(800, 600, 60, sc->sc_chip, 0);
1028}
1029
1030static int
1031udl_cmd_write_buf_le16(struct udl_softc *sc, const uint8_t *buf, uint32_t off,
1032    uint8_t pixels, int flags)
1033{
1034	struct udl_cmd_buf *cb;
1035
1036	cb = udl_cmd_buf_alloc(sc, flags);
1037	if (cb == NULL)
1038		return (EAGAIN);
1039
1040	udl_cmd_insert_int_1(cb, UDL_BULK_SOC);
1041	udl_cmd_insert_int_1(cb, UDL_BULK_CMD_FB_WRITE | UDL_BULK_CMD_FB_WORD);
1042	udl_cmd_insert_int_3(cb, off);
1043	udl_cmd_insert_int_1(cb, pixels);
1044	udl_cmd_insert_buf_le16(cb, buf, 2 * pixels);
1045	udl_cmd_buf_send(sc, cb);
1046
1047	return (0);
1048}
1049
1050static int
1051udl_cmd_buf_copy_le16(struct udl_softc *sc, uint32_t src, uint32_t dst,
1052    uint8_t pixels, int flags)
1053{
1054	struct udl_cmd_buf *cb;
1055
1056	cb = udl_cmd_buf_alloc(sc, flags);
1057	if (cb == NULL)
1058		return (EAGAIN);
1059
1060	udl_cmd_insert_int_1(cb, UDL_BULK_SOC);
1061	udl_cmd_insert_int_1(cb, UDL_BULK_CMD_FB_COPY | UDL_BULK_CMD_FB_WORD);
1062	udl_cmd_insert_int_3(cb, 2 * dst);
1063	udl_cmd_insert_int_1(cb, pixels);
1064	udl_cmd_insert_int_3(cb, 2 * src);
1065	udl_cmd_buf_send(sc, cb);
1066
1067	return (0);
1068}
1069