[PATCH v2 3/8] TDA19988: Import from FreeBSD

Vijay Kumar Banerjee vijaykumar9597 at gmail.com
Fri Aug 2 21:00:05 UTC 2019


---
 freebsd/sys/arm/ti/am335x/tda19988.c      | 812 ++++++++++++++++++++++
 freebsd/sys/dev/extres/clk/clk.h          | 146 ++++
 freebsd/sys/dev/videomode/edid.c          | 649 +++++++++++++++++
 freebsd/sys/dev/videomode/ediddevs.h      |  91 +++
 freebsd/sys/dev/videomode/ediddevs_data.h | 107 +++
 freebsd/sys/dev/videomode/edidreg.h       | 256 +++++++
 freebsd/sys/dev/videomode/edidvar.h       |  96 +++
 freebsd/sys/dev/videomode/pickmode.c      | 207 ++++++
 freebsd/sys/dev/videomode/vesagtf.c       | 705 +++++++++++++++++++
 freebsd/sys/dev/videomode/vesagtf.h       |  86 +++
 freebsd/sys/dev/videomode/videomode.c     | 132 ++++
 freebsd/sys/dev/videomode/videomode.h     |  75 ++
 12 files changed, 3362 insertions(+)
 create mode 100644 freebsd/sys/arm/ti/am335x/tda19988.c
 create mode 100644 freebsd/sys/dev/extres/clk/clk.h
 create mode 100644 freebsd/sys/dev/videomode/edid.c
 create mode 100644 freebsd/sys/dev/videomode/ediddevs.h
 create mode 100644 freebsd/sys/dev/videomode/ediddevs_data.h
 create mode 100644 freebsd/sys/dev/videomode/edidreg.h
 create mode 100644 freebsd/sys/dev/videomode/edidvar.h
 create mode 100644 freebsd/sys/dev/videomode/pickmode.c
 create mode 100644 freebsd/sys/dev/videomode/vesagtf.c
 create mode 100644 freebsd/sys/dev/videomode/vesagtf.h
 create mode 100644 freebsd/sys/dev/videomode/videomode.c
 create mode 100644 freebsd/sys/dev/videomode/videomode.h

diff --git a/freebsd/sys/arm/ti/am335x/tda19988.c b/freebsd/sys/arm/ti/am335x/tda19988.c
new file mode 100644
index 00000000..282353ab
--- /dev/null
+++ b/freebsd/sys/arm/ti/am335x/tda19988.c
@@ -0,0 +1,812 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2015 Oleksandr Tymoshenko <gonzo at freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+/*
+* NXP TDA19988 HDMI encoder 
+*/
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/clock.h>
+#include <sys/eventhandler.h>
+#include <sys/time.h>
+#include <sys/bus.h>
+#include <rtems/bsd/sys/resource.h>
+#include <sys/rman.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/iiconf.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/videomode/videomode.h>
+#include <dev/videomode/edidvar.h>
+
+#include <rtems/bsd/local/iicbus_if.h>
+#include <rtems/bsd/local/hdmi_if.h>
+
+#define	MKREG(page, addr)	(((page) << 8) | (addr))
+
+#define	REGPAGE(reg)		(((reg) >> 8) & 0xff)
+#define	REGADDR(reg)		((reg) & 0xff)
+
+#define TDA_VERSION		MKREG(0x00, 0x00)
+#define TDA_MAIN_CNTRL0		MKREG(0x00, 0x01)
+#define 	MAIN_CNTRL0_SR		(1 << 0)
+#define TDA_VERSION_MSB		MKREG(0x00, 0x02)
+#define	TDA_SOFTRESET		MKREG(0x00, 0x0a)
+#define		SOFTRESET_I2C		(1 << 1)
+#define		SOFTRESET_AUDIO		(1 << 0)
+#define	TDA_DDC_CTRL		MKREG(0x00, 0x0b)
+#define		DDC_ENABLE		0
+#define	TDA_CCLK		MKREG(0x00, 0x0c)
+#define		CCLK_ENABLE		1
+#define	TDA_INT_FLAGS_2		MKREG(0x00, 0x11)
+#define		INT_FLAGS_2_EDID_BLK_RD	(1 << 1)
+
+#define	TDA_VIP_CNTRL_0		MKREG(0x00, 0x20)
+#define	TDA_VIP_CNTRL_1		MKREG(0x00, 0x21)
+#define	TDA_VIP_CNTRL_2		MKREG(0x00, 0x22)
+#define	TDA_VIP_CNTRL_3		MKREG(0x00, 0x23)
+#define		VIP_CNTRL_3_SYNC_HS	(2 << 4)
+#define		VIP_CNTRL_3_V_TGL	(1 << 2)
+#define		VIP_CNTRL_3_H_TGL	(1 << 1)
+
+#define	TDA_VIP_CNTRL_4		MKREG(0x00, 0x24)
+#define		VIP_CNTRL_4_BLANKIT_NDE		(0 << 2)
+#define		VIP_CNTRL_4_BLANKIT_HS_VS	(1 << 2)
+#define		VIP_CNTRL_4_BLANKIT_NHS_VS	(2 << 2)
+#define		VIP_CNTRL_4_BLANKIT_HE_VE	(3 << 2)
+#define		VIP_CNTRL_4_BLC_NONE		(0 << 0)
+#define		VIP_CNTRL_4_BLC_RGB444		(1 << 0)
+#define		VIP_CNTRL_4_BLC_YUV444		(2 << 0)
+#define		VIP_CNTRL_4_BLC_YUV422		(3 << 0)
+#define	TDA_VIP_CNTRL_5		MKREG(0x00, 0x25)
+#define		VIP_CNTRL_5_SP_CNT(n)	(((n) & 3) << 1)
+#define	TDA_MUX_VP_VIP_OUT	MKREG(0x00, 0x27)
+#define TDA_MAT_CONTRL		MKREG(0x00, 0x80)
+#define		MAT_CONTRL_MAT_BP	(1 << 2)
+#define	TDA_VIDFORMAT		MKREG(0x00, 0xa0)
+#define	TDA_REFPIX_MSB		MKREG(0x00, 0xa1)
+#define	TDA_REFPIX_LSB		MKREG(0x00, 0xa2)
+#define	TDA_REFLINE_MSB		MKREG(0x00, 0xa3)
+#define	TDA_REFLINE_LSB		MKREG(0x00, 0xa4)
+#define	TDA_NPIX_MSB		MKREG(0x00, 0xa5)
+#define	TDA_NPIX_LSB		MKREG(0x00, 0xa6)
+#define	TDA_NLINE_MSB		MKREG(0x00, 0xa7)
+#define	TDA_NLINE_LSB		MKREG(0x00, 0xa8)
+#define	TDA_VS_LINE_STRT_1_MSB	MKREG(0x00, 0xa9)
+#define	TDA_VS_LINE_STRT_1_LSB	MKREG(0x00, 0xaa)
+#define	TDA_VS_PIX_STRT_1_MSB	MKREG(0x00, 0xab)
+#define	TDA_VS_PIX_STRT_1_LSB	MKREG(0x00, 0xac)
+#define	TDA_VS_LINE_END_1_MSB	MKREG(0x00, 0xad)
+#define	TDA_VS_LINE_END_1_LSB	MKREG(0x00, 0xae)
+#define	TDA_VS_PIX_END_1_MSB	MKREG(0x00, 0xaf)
+#define	TDA_VS_PIX_END_1_LSB	MKREG(0x00, 0xb0)
+#define	TDA_VS_LINE_STRT_2_MSB	MKREG(0x00, 0xb1)
+#define	TDA_VS_LINE_STRT_2_LSB	MKREG(0x00, 0xb2)
+#define	TDA_VS_PIX_STRT_2_MSB	MKREG(0x00, 0xb3)
+#define	TDA_VS_PIX_STRT_2_LSB	MKREG(0x00, 0xb4)
+#define	TDA_VS_LINE_END_2_MSB	MKREG(0x00, 0xb5)
+#define	TDA_VS_LINE_END_2_LSB	MKREG(0x00, 0xb6)
+#define	TDA_VS_PIX_END_2_MSB	MKREG(0x00, 0xb7)
+#define	TDA_VS_PIX_END_2_LSB	MKREG(0x00, 0xb8)
+#define	TDA_HS_PIX_START_MSB	MKREG(0x00, 0xb9)
+#define	TDA_HS_PIX_START_LSB	MKREG(0x00, 0xba)
+#define	TDA_HS_PIX_STOP_MSB	MKREG(0x00, 0xbb)
+#define	TDA_HS_PIX_STOP_LSB	MKREG(0x00, 0xbc)
+#define	TDA_VWIN_START_1_MSB	MKREG(0x00, 0xbd)
+#define	TDA_VWIN_START_1_LSB	MKREG(0x00, 0xbe)
+#define	TDA_VWIN_END_1_MSB	MKREG(0x00, 0xbf)
+#define	TDA_VWIN_END_1_LSB	MKREG(0x00, 0xc0)
+#define	TDA_VWIN_START_2_MSB	MKREG(0x00, 0xc1)
+#define	TDA_VWIN_START_2_LSB	MKREG(0x00, 0xc2)
+#define	TDA_VWIN_END_2_MSB	MKREG(0x00, 0xc3)
+#define	TDA_VWIN_END_2_LSB	MKREG(0x00, 0xc4)
+#define	TDA_DE_START_MSB	MKREG(0x00, 0xc5)
+#define	TDA_DE_START_LSB	MKREG(0x00, 0xc6)
+#define	TDA_DE_STOP_MSB		MKREG(0x00, 0xc7)
+#define	TDA_DE_STOP_LSB		MKREG(0x00, 0xc8)
+
+#define	TDA_TBG_CNTRL_0		MKREG(0x00, 0xca)
+#define		TBG_CNTRL_0_SYNC_ONCE	(1 << 7)
+#define		TBG_CNTRL_0_SYNC_MTHD	(1 << 6)
+
+#define	TDA_TBG_CNTRL_1		MKREG(0x00, 0xcb)
+#define		TBG_CNTRL_1_DWIN_DIS	(1 << 6)
+#define		TBG_CNTRL_1_TGL_EN	(1 << 2)
+#define		TBG_CNTRL_1_V_TGL	(1 << 1)
+#define		TBG_CNTRL_1_H_TGL	(1 << 0)
+
+#define	TDA_HVF_CNTRL_0		MKREG(0x00, 0xe4)
+#define		HVF_CNTRL_0_PREFIL_NONE		(0 << 2)
+#define		HVF_CNTRL_0_INTPOL_BYPASS	(0 << 0)
+#define	TDA_HVF_CNTRL_1		MKREG(0x00, 0xe5)
+#define		HVF_CNTRL_1_VQR(x)	(((x) & 3) << 2)
+#define		HVF_CNTRL_1_VQR_FULL	HVF_CNTRL_1_VQR(0)
+#define	TDA_ENABLE_SPACE	MKREG(0x00, 0xd6)
+#define	TDA_RPT_CNTRL		MKREG(0x00, 0xf0)
+
+#define	TDA_PLL_SERIAL_1	MKREG(0x02, 0x00)
+#define		PLL_SERIAL_1_SRL_MAN_IP	(1 << 6)
+#define	TDA_PLL_SERIAL_2	MKREG(0x02, 0x01)
+#define		PLL_SERIAL_2_SRL_PR(x)		(((x) & 0xf) << 4)
+#define		PLL_SERIAL_2_SRL_NOSC(x)	(((x) & 0x3) << 0)
+#define	TDA_PLL_SERIAL_3	MKREG(0x02, 0x02)
+#define		PLL_SERIAL_3_SRL_PXIN_SEL	(1 << 4)
+#define		PLL_SERIAL_3_SRL_DE		(1 << 2)
+#define		PLL_SERIAL_3_SRL_CCIR		(1 << 0)
+#define	TDA_SERIALIZER		MKREG(0x02, 0x03)
+#define	TDA_BUFFER_OUT		MKREG(0x02, 0x04)
+#define	TDA_PLL_SCG1		MKREG(0x02, 0x05)
+#define	TDA_PLL_SCG2		MKREG(0x02, 0x06)
+#define	TDA_PLL_SCGN1		MKREG(0x02, 0x07)
+#define	TDA_PLL_SCGN2		MKREG(0x02, 0x08)
+#define	TDA_PLL_SCGR1		MKREG(0x02, 0x09)
+#define	TDA_PLL_SCGR2		MKREG(0x02, 0x0a)
+
+#define	TDA_SEL_CLK		MKREG(0x02, 0x11)
+#define		SEL_CLK_ENA_SC_CLK	(1 << 3)
+#define		SEL_CLK_SEL_VRF_CLK(x)	(((x) & 3) << 1)
+#define		SEL_CLK_SEL_CLK1	(1 << 0)
+#define	TDA_ANA_GENERAL		MKREG(0x02, 0x12)
+
+#define	TDA_EDID_DATA0		MKREG(0x09, 0x00)
+#define	TDA_EDID_CTRL		MKREG(0x09, 0xfa)
+#define	TDA_DDC_ADDR		MKREG(0x09, 0xfb)
+#define	TDA_DDC_OFFS		MKREG(0x09, 0xfc)
+#define	TDA_DDC_SEGM_ADDR	MKREG(0x09, 0xfd)
+#define	TDA_DDC_SEGM		MKREG(0x09, 0xfe)
+
+#define	TDA_IF_VSP		MKREG(0x10, 0x20)
+#define	TDA_IF_AVI		MKREG(0x10, 0x40)
+#define	TDA_IF_SPD		MKREG(0x10, 0x60)
+#define	TDA_IF_AUD		MKREG(0x10, 0x80)
+#define	TDA_IF_MPS		MKREG(0x10, 0xa0)
+
+#define	TDA_ENC_CNTRL		MKREG(0x11, 0x0d)
+#define		ENC_CNTRL_DVI_MODE	(0 << 2)
+#define		ENC_CNTRL_HDMI_MODE	(1 << 2)
+#define	TDA_DIP_IF_FLAGS	MKREG(0x11, 0x0f)
+#define		DIP_IF_FLAGS_IF5	(1 << 5)
+#define		DIP_IF_FLAGS_IF4	(1 << 4)
+#define		DIP_IF_FLAGS_IF3	(1 << 3)
+#define		DIP_IF_FLAGS_IF2	(1 << 2) /* AVI IF on page 10h */
+#define		DIP_IF_FLAGS_IF1	(1 << 1)
+
+#define	TDA_TX3			MKREG(0x12, 0x9a)
+#define	TDA_TX4			MKREG(0x12, 0x9b)
+#define		TX4_PD_RAM		(1 << 1)
+#define	TDA_HDCP_TX33		MKREG(0x12, 0xb8)
+#define		HDCP_TX33_HDMI		(1 << 1)
+
+#define	TDA_CURPAGE_ADDR	0xff
+
+#define	TDA_CEC_ENAMODS		0xff
+#define		ENAMODS_RXSENS		(1 << 2)
+#define		ENAMODS_HDMI		(1 << 1)
+#define	TDA_CEC_FRO_IM_CLK_CTRL	0xfb
+#define		CEC_FRO_IM_CLK_CTRL_GHOST_DIS	(1 << 7)
+#define		CEC_FRO_IM_CLK_CTRL_IMCLK_SEL	(1 << 1)
+
+/* EDID reading */ 
+#define EDID_LENGTH		0x80
+#define	MAX_READ_ATTEMPTS	100
+
+/* EDID fields */
+#define	EDID_MODES0		35
+#define	EDID_MODES1		36
+#define	EDID_TIMING_START	38
+#define	EDID_TIMING_END		54
+#define	EDID_TIMING_X(v)	(((v) + 31) * 8)
+#define	EDID_FREQ(v)		(((v) & 0x3f) + 60)
+#define	EDID_RATIO(v)		(((v) >> 6) & 0x3)
+#define	EDID_RATIO_10x16	0
+#define	EDID_RATIO_3x4		1	
+#define	EDID_RATIO_4x5		2	
+#define	EDID_RATIO_9x16		3
+
+#define	TDA19988		0x0301
+
+struct tda19988_softc {
+	device_t		sc_dev;
+	uint32_t		sc_addr;
+	uint32_t		sc_cec_addr;
+	uint16_t		sc_version;
+	struct intr_config_hook enum_hook;
+	int			sc_current_page;
+	uint8_t			*sc_edid;
+	uint32_t		sc_edid_len;
+};
+
+static int
+tda19988_set_page(struct tda19988_softc *sc, uint8_t page)
+{
+	uint8_t addr = TDA_CURPAGE_ADDR;
+	uint8_t cmd[2];
+	int result;
+	struct iic_msg msg[] = {
+		{ sc->sc_addr, IIC_M_WR, 2, cmd },
+	};
+
+	cmd[0] = addr;
+	cmd[1] = page;
+
+	result = (iicbus_transfer(sc->sc_dev, msg, 1));
+	if (result)
+		printf("tda19988_set_page failed: %d\n", result);
+	else
+		sc->sc_current_page = page;
+
+	return (result);
+}
+
+static int
+tda19988_cec_read(struct tda19988_softc *sc, uint8_t addr, uint8_t *data)
+{
+	int result;
+	struct iic_msg msg[] = {
+		{ sc->sc_cec_addr, IIC_M_WR, 1, &addr },
+		{ sc->sc_cec_addr, IIC_M_RD, 1, data },
+	};
+
+	result =  iicbus_transfer(sc->sc_dev, msg, 2);
+	if (result)
+		printf("tda19988_cec_read failed: %d\n", result);
+	return (result);
+}
+
+static int
+tda19988_cec_write(struct tda19988_softc *sc, uint8_t address, uint8_t data)
+{
+	uint8_t cmd[2];
+	int result;
+	struct iic_msg msg[] = {
+		{ sc->sc_cec_addr, IIC_M_WR, 2, cmd },
+	};
+
+	cmd[0] = address;
+	cmd[1] = data;
+
+	result = iicbus_transfer(sc->sc_dev, msg, 1);
+	if (result)
+		printf("tda19988_cec_write failed: %d\n", result);
+	return (result);
+}
+
+static int
+tda19988_block_read(struct tda19988_softc *sc, uint16_t addr, uint8_t *data, int len)
+{
+	uint8_t reg;
+	int result;
+	struct iic_msg msg[] = {
+		{ sc->sc_addr, IIC_M_WR, 1, &reg },
+		{ sc->sc_addr, IIC_M_RD, len, data },
+	};
+
+	reg = REGADDR(addr);
+
+	if (sc->sc_current_page != REGPAGE(addr))
+		tda19988_set_page(sc, REGPAGE(addr));
+
+	result = (iicbus_transfer(sc->sc_dev, msg, 2));
+	if (result)
+		device_printf(sc->sc_dev, "tda19988_block_read failed: %d\n", result);
+	return (result);
+}
+
+static int
+tda19988_reg_read(struct tda19988_softc *sc, uint16_t addr, uint8_t *data)
+{
+	uint8_t reg;
+	int result;
+	struct iic_msg msg[] = {
+		{ sc->sc_addr, IIC_M_WR, 1, &reg },
+		{ sc->sc_addr, IIC_M_RD, 1, data },
+	};
+
+	reg = REGADDR(addr);
+
+	if (sc->sc_current_page != REGPAGE(addr))
+		tda19988_set_page(sc, REGPAGE(addr));
+
+	result = (iicbus_transfer(sc->sc_dev, msg, 2));
+	if (result)
+		device_printf(sc->sc_dev, "tda19988_reg_read failed: %d\n", result);
+	return (result);
+}
+
+static int
+tda19988_reg_write(struct tda19988_softc *sc, uint16_t address, uint8_t data)
+{
+	uint8_t cmd[2];
+	int result;
+	struct iic_msg msg[] = {
+		{ sc->sc_addr, IIC_M_WR, 2, cmd },
+	};
+
+	cmd[0] = REGADDR(address);
+	cmd[1] = data;
+
+	if (sc->sc_current_page != REGPAGE(address))
+		tda19988_set_page(sc, REGPAGE(address));
+
+	result = iicbus_transfer(sc->sc_dev, msg, 1);
+	if (result)
+		device_printf(sc->sc_dev, "tda19988_reg_write failed: %d\n", result);
+
+	return (result);
+}
+
+static int
+tda19988_reg_write2(struct tda19988_softc *sc, uint16_t address, uint16_t data)
+{
+	uint8_t cmd[3];
+	int result;
+	struct iic_msg msg[] = {
+		{ sc->sc_addr, IIC_M_WR, 3, cmd },
+	};
+
+	cmd[0] = REGADDR(address);
+	cmd[1] = (data >> 8);
+	cmd[2] = (data & 0xff);
+
+	if (sc->sc_current_page != REGPAGE(address))
+		tda19988_set_page(sc, REGPAGE(address));
+
+	result = iicbus_transfer(sc->sc_dev, msg, 1);
+	if (result)
+		device_printf(sc->sc_dev, "tda19988_reg_write2 failed: %d\n", result);
+
+	return (result);
+}
+
+static void
+tda19988_reg_set(struct tda19988_softc *sc, uint16_t addr, uint8_t flags)
+{
+	uint8_t data;
+
+	tda19988_reg_read(sc, addr, &data);
+	data |= flags;
+	tda19988_reg_write(sc, addr, data);
+}
+
+static void
+tda19988_reg_clear(struct tda19988_softc *sc, uint16_t addr, uint8_t flags)
+{
+	uint8_t data;
+
+	tda19988_reg_read(sc, addr, &data);
+	data &= ~flags;
+	tda19988_reg_write(sc, addr, data);
+}
+
+static int
+tda19988_probe(device_t dev)
+{
+
+	if (!ofw_bus_is_compatible(dev, "nxp,tda998x"))
+		return (ENXIO);
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+static void
+tda19988_init_encoder(struct tda19988_softc *sc, const struct videomode *mode)
+{
+	uint16_t ref_pix, ref_line, n_pix, n_line;
+	uint16_t hs_pix_start, hs_pix_stop;
+	uint16_t vs1_pix_start, vs1_pix_stop;
+	uint16_t vs1_line_start, vs1_line_end;
+	uint16_t vs2_pix_start, vs2_pix_stop;
+	uint16_t vs2_line_start, vs2_line_end;
+	uint16_t vwin1_line_start, vwin1_line_end;
+	uint16_t vwin2_line_start, vwin2_line_end;
+	uint16_t de_start, de_stop;
+	uint8_t reg, div;
+
+	n_pix = mode->htotal;
+	n_line = mode->vtotal;
+
+	hs_pix_stop = mode->hsync_end - mode->hdisplay;
+	hs_pix_start = mode->hsync_start - mode->hdisplay;
+
+	de_stop = mode->htotal;
+	de_start = mode->htotal - mode->hdisplay;
+	ref_pix = hs_pix_start + 3;
+
+	if (mode->flags & VID_HSKEW)
+		ref_pix += mode->hskew;
+
+	if ((mode->flags & VID_INTERLACE) == 0) {
+		ref_line = 1 + mode->vsync_start - mode->vdisplay;
+		vwin1_line_start = mode->vtotal - mode->vdisplay - 1;
+		vwin1_line_end = vwin1_line_start + mode->vdisplay;
+
+		vs1_pix_start = vs1_pix_stop = hs_pix_start;
+		vs1_line_start = mode->vsync_start - mode->vdisplay;
+		vs1_line_end = vs1_line_start + mode->vsync_end - mode->vsync_start;
+
+		vwin2_line_start = vwin2_line_end = 0;
+		vs2_pix_start = vs2_pix_stop = 0;
+		vs2_line_start = vs2_line_end = 0;
+	} else {
+		ref_line = 1 + (mode->vsync_start - mode->vdisplay)/2;
+		vwin1_line_start = (mode->vtotal - mode->vdisplay)/2;
+		vwin1_line_end = vwin1_line_start + mode->vdisplay/2;
+
+		vs1_pix_start = vs1_pix_stop = hs_pix_start;
+		vs1_line_start = (mode->vsync_start - mode->vdisplay)/2;
+		vs1_line_end = vs1_line_start + (mode->vsync_end - mode->vsync_start)/2;
+
+		vwin2_line_start = vwin1_line_start + mode->vtotal/2;
+		vwin2_line_end = vwin2_line_start + mode->vdisplay/2;
+
+		vs2_pix_start = vs2_pix_stop = hs_pix_start + mode->htotal/2;
+		vs2_line_start = vs1_line_start + mode->vtotal/2 ;
+		vs2_line_end = vs2_line_start + (mode->vsync_end - mode->vsync_start)/2;
+	}
+
+	div = 148500 / mode->dot_clock;
+	if (div != 0) {
+		div--;
+		if (div > 3)
+			div = 3;
+	}
+
+	/* set HDMI HDCP mode off */
+	tda19988_reg_set(sc, TDA_TBG_CNTRL_1, TBG_CNTRL_1_DWIN_DIS);
+	tda19988_reg_clear(sc, TDA_HDCP_TX33, HDCP_TX33_HDMI);
+	tda19988_reg_write(sc, TDA_ENC_CNTRL, ENC_CNTRL_DVI_MODE);
+
+	/* no pre-filter or interpolator */
+	tda19988_reg_write(sc, TDA_HVF_CNTRL_0,
+	    HVF_CNTRL_0_INTPOL_BYPASS | HVF_CNTRL_0_PREFIL_NONE);
+	tda19988_reg_write(sc, TDA_VIP_CNTRL_5, VIP_CNTRL_5_SP_CNT(0));
+	tda19988_reg_write(sc, TDA_VIP_CNTRL_4,
+	    VIP_CNTRL_4_BLANKIT_NDE | VIP_CNTRL_4_BLC_NONE);
+
+	tda19988_reg_clear(sc, TDA_PLL_SERIAL_3, PLL_SERIAL_3_SRL_CCIR);
+	tda19988_reg_clear(sc, TDA_PLL_SERIAL_1, PLL_SERIAL_1_SRL_MAN_IP);
+	tda19988_reg_clear(sc, TDA_PLL_SERIAL_3, PLL_SERIAL_3_SRL_DE);
+	tda19988_reg_write(sc, TDA_SERIALIZER, 0);
+	tda19988_reg_write(sc, TDA_HVF_CNTRL_1, HVF_CNTRL_1_VQR_FULL);
+
+	tda19988_reg_write(sc, TDA_RPT_CNTRL, 0);
+	tda19988_reg_write(sc, TDA_SEL_CLK, SEL_CLK_SEL_VRF_CLK(0) |
+			SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
+
+	tda19988_reg_write(sc, TDA_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(div) |
+			PLL_SERIAL_2_SRL_PR(0));
+
+	tda19988_reg_set(sc, TDA_MAT_CONTRL, MAT_CONTRL_MAT_BP);
+
+	tda19988_reg_write(sc, TDA_ANA_GENERAL, 0x09);
+
+	tda19988_reg_clear(sc, TDA_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_MTHD);
+
+	/*
+	 * Sync on rising HSYNC/VSYNC
+	 */
+	reg = VIP_CNTRL_3_SYNC_HS;
+	if (mode->flags & VID_NHSYNC)
+		reg |= VIP_CNTRL_3_H_TGL;
+	if (mode->flags & VID_NVSYNC)
+		reg |= VIP_CNTRL_3_V_TGL;
+	tda19988_reg_write(sc, TDA_VIP_CNTRL_3, reg);
+
+	reg = TBG_CNTRL_1_TGL_EN;
+	if (mode->flags & VID_NHSYNC)
+		reg |= TBG_CNTRL_1_H_TGL;
+	if (mode->flags & VID_NVSYNC)
+		reg |= TBG_CNTRL_1_V_TGL;
+	tda19988_reg_write(sc, TDA_TBG_CNTRL_1, reg);
+
+	/* Program timing */
+	tda19988_reg_write(sc, TDA_VIDFORMAT, 0x00);
+
+	tda19988_reg_write2(sc, TDA_REFPIX_MSB, ref_pix);
+	tda19988_reg_write2(sc, TDA_REFLINE_MSB, ref_line);
+	tda19988_reg_write2(sc, TDA_NPIX_MSB, n_pix);
+	tda19988_reg_write2(sc, TDA_NLINE_MSB, n_line);
+
+	tda19988_reg_write2(sc, TDA_VS_LINE_STRT_1_MSB, vs1_line_start);
+	tda19988_reg_write2(sc, TDA_VS_PIX_STRT_1_MSB, vs1_pix_start);
+	tda19988_reg_write2(sc, TDA_VS_LINE_END_1_MSB, vs1_line_end);
+	tda19988_reg_write2(sc, TDA_VS_PIX_END_1_MSB, vs1_pix_stop);
+	tda19988_reg_write2(sc, TDA_VS_LINE_STRT_2_MSB, vs2_line_start);
+	tda19988_reg_write2(sc, TDA_VS_PIX_STRT_2_MSB, vs2_pix_start);
+	tda19988_reg_write2(sc, TDA_VS_LINE_END_2_MSB, vs2_line_end);
+	tda19988_reg_write2(sc, TDA_VS_PIX_END_2_MSB, vs2_pix_stop);
+	tda19988_reg_write2(sc, TDA_HS_PIX_START_MSB, hs_pix_start);
+	tda19988_reg_write2(sc, TDA_HS_PIX_STOP_MSB, hs_pix_stop);
+	tda19988_reg_write2(sc, TDA_VWIN_START_1_MSB, vwin1_line_start);
+	tda19988_reg_write2(sc, TDA_VWIN_END_1_MSB, vwin1_line_end);
+	tda19988_reg_write2(sc, TDA_VWIN_START_2_MSB, vwin2_line_start);
+	tda19988_reg_write2(sc, TDA_VWIN_END_2_MSB, vwin2_line_end);
+	tda19988_reg_write2(sc, TDA_DE_START_MSB, de_start);
+	tda19988_reg_write2(sc, TDA_DE_STOP_MSB, de_stop);
+
+	if (sc->sc_version == TDA19988)
+		tda19988_reg_write(sc, TDA_ENABLE_SPACE, 0x00);
+
+	/* must be last register set */
+	tda19988_reg_clear(sc, TDA_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_ONCE);
+}
+
+static int
+tda19988_read_edid_block(struct tda19988_softc *sc, uint8_t *buf, int block)
+{
+	int attempt, err;
+	uint8_t data;
+
+	err = 0;
+
+	tda19988_reg_set(sc, TDA_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
+
+	/* Block 0 */
+	tda19988_reg_write(sc, TDA_DDC_ADDR, 0xa0);
+	tda19988_reg_write(sc, TDA_DDC_OFFS, (block % 2) ? 128 : 0);
+	tda19988_reg_write(sc, TDA_DDC_SEGM_ADDR, 0x60);
+	tda19988_reg_write(sc, TDA_DDC_SEGM, block / 2);
+
+	tda19988_reg_write(sc, TDA_EDID_CTRL, 1);
+	tda19988_reg_write(sc, TDA_EDID_CTRL, 0);
+
+	data = 0;
+	for (attempt = 0; attempt < MAX_READ_ATTEMPTS; attempt++) {
+		tda19988_reg_read(sc, TDA_INT_FLAGS_2, &data);
+		if (data & INT_FLAGS_2_EDID_BLK_RD)
+			break;
+		pause("EDID", 1);
+	}
+
+	if (attempt == MAX_READ_ATTEMPTS) {
+		err = -1;
+		goto done;
+	}
+
+	if (tda19988_block_read(sc, TDA_EDID_DATA0, buf, EDID_LENGTH) != 0) {
+		err = -1;
+		goto done;
+	}
+
+done:
+	tda19988_reg_clear(sc, TDA_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
+
+	return (err);
+}
+
+static int
+tda19988_read_edid(struct tda19988_softc *sc)
+{
+	int err;
+	int blocks, i;
+	uint8_t *buf;
+
+	err = 0;
+	if (sc->sc_version == TDA19988)
+		tda19988_reg_clear(sc, TDA_TX4, TX4_PD_RAM);
+
+	err = tda19988_read_edid_block(sc, sc->sc_edid, 0);
+	if (err)
+		goto done;
+
+	blocks = sc->sc_edid[0x7e];
+	if (blocks > 0) {
+		sc->sc_edid = realloc(sc->sc_edid, 
+		    EDID_LENGTH*(blocks+1), M_DEVBUF, M_WAITOK);
+		sc->sc_edid_len = EDID_LENGTH*(blocks+1);
+		for (i = 0; i < blocks; i++) {
+			/* TODO: check validity */
+			buf = sc->sc_edid + EDID_LENGTH*(i+1);
+			err = tda19988_read_edid_block(sc, buf, i);
+			if (err)
+				goto done;
+		}
+	}
+
+	EVENTHANDLER_INVOKE(hdmi_event, sc->sc_dev, HDMI_EVENT_CONNECTED);
+done:
+	if (sc->sc_version == TDA19988)
+		tda19988_reg_set(sc, TDA_TX4, TX4_PD_RAM);
+
+	return (err);
+}
+
+static void
+tda19988_start(void *xdev)
+{
+	struct tda19988_softc *sc;
+	device_t dev = (device_t)xdev;
+	uint8_t data;
+	uint16_t version;
+
+	sc = device_get_softc(dev);
+
+	tda19988_cec_write(sc, TDA_CEC_ENAMODS, ENAMODS_RXSENS | ENAMODS_HDMI);
+	DELAY(1000);
+	tda19988_cec_read(sc, 0xfe, &data);
+
+	/* Reset core */
+	tda19988_reg_set(sc, TDA_SOFTRESET, 3);
+	DELAY(100);
+	tda19988_reg_clear(sc, TDA_SOFTRESET, 3);
+	DELAY(100);
+
+	/* reset transmitter: */
+	tda19988_reg_set(sc, TDA_MAIN_CNTRL0, MAIN_CNTRL0_SR);
+	tda19988_reg_clear(sc, TDA_MAIN_CNTRL0, MAIN_CNTRL0_SR);
+
+	/* PLL registers common configuration */
+	tda19988_reg_write(sc, TDA_PLL_SERIAL_1, 0x00);
+	tda19988_reg_write(sc, TDA_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(1));
+	tda19988_reg_write(sc, TDA_PLL_SERIAL_3, 0x00);
+	tda19988_reg_write(sc, TDA_SERIALIZER, 0x00);
+	tda19988_reg_write(sc, TDA_BUFFER_OUT, 0x00);
+	tda19988_reg_write(sc, TDA_PLL_SCG1, 0x00);
+	tda19988_reg_write(sc, TDA_SEL_CLK, SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
+	tda19988_reg_write(sc, TDA_PLL_SCGN1, 0xfa);
+	tda19988_reg_write(sc, TDA_PLL_SCGN2, 0x00);
+	tda19988_reg_write(sc, TDA_PLL_SCGR1, 0x5b);
+	tda19988_reg_write(sc, TDA_PLL_SCGR2, 0x00);
+	tda19988_reg_write(sc, TDA_PLL_SCG2, 0x10);
+
+	/* Write the default value MUX register */
+	tda19988_reg_write(sc, TDA_MUX_VP_VIP_OUT, 0x24);
+
+	version = 0;
+	tda19988_reg_read(sc, TDA_VERSION, &data);
+	version |= data;
+	tda19988_reg_read(sc, TDA_VERSION_MSB, &data);
+	version |= (data << 8);
+
+	/* Clear feature bits */
+	sc->sc_version = version & ~0x30;
+	switch (sc->sc_version) {
+		case TDA19988:
+			device_printf(dev, "TDA19988\n");
+			break;
+		default:
+			device_printf(dev, "Unknown device: %04x\n", sc->sc_version);
+			goto done;
+	}
+
+	tda19988_reg_write(sc, TDA_DDC_CTRL, DDC_ENABLE);
+	tda19988_reg_write(sc, TDA_TX3, 39);
+
+    	tda19988_cec_write(sc, TDA_CEC_FRO_IM_CLK_CTRL,
+            CEC_FRO_IM_CLK_CTRL_GHOST_DIS | CEC_FRO_IM_CLK_CTRL_IMCLK_SEL);
+
+	if (tda19988_read_edid(sc) < 0) {
+		device_printf(dev, "failed to read EDID\n");
+		goto done;
+	}
+
+	/* Default values for RGB 4:4:4 mapping */
+	tda19988_reg_write(sc, TDA_VIP_CNTRL_0, 0x23);
+	tda19988_reg_write(sc, TDA_VIP_CNTRL_1, 0x01);
+	tda19988_reg_write(sc, TDA_VIP_CNTRL_2, 0x45);
+
+done:
+	config_intrhook_disestablish(&sc->enum_hook);
+}
+
+static int
+tda19988_attach(device_t dev)
+{
+	struct tda19988_softc *sc;
+	phandle_t node;
+
+	sc = device_get_softc(dev);
+
+	sc->sc_dev = dev;
+	sc->sc_addr = iicbus_get_addr(dev);
+	sc->sc_cec_addr = (0x34 << 1); /* hardcoded */
+	sc->sc_edid = malloc(EDID_LENGTH, M_DEVBUF, M_WAITOK | M_ZERO);
+	sc->sc_edid_len = EDID_LENGTH;
+
+	device_set_desc(dev, "NXP TDA19988 HDMI transmitter");
+
+	sc->enum_hook.ich_func = tda19988_start;
+	sc->enum_hook.ich_arg = dev;
+
+	if (config_intrhook_establish(&sc->enum_hook) != 0)
+		return (ENOMEM);
+
+	node = ofw_bus_get_node(dev);
+	OF_device_register_xref(OF_xref_from_node(node), dev);
+
+	return (0);
+}
+
+static int
+tda19988_detach(device_t dev)
+{
+
+	/* XXX: Do not let unload drive */
+	return (EBUSY);
+}
+
+static int
+tda19988_get_edid(device_t dev, uint8_t **edid, uint32_t *edid_len)
+{
+	struct tda19988_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (sc->sc_edid) {
+		*edid = sc->sc_edid;
+		*edid_len = sc->sc_edid_len;
+	} else
+		return (ENXIO);
+
+	return (0);
+}
+
+static int
+tda19988_set_videomode(device_t dev, const struct videomode *mode)
+{
+	struct tda19988_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	tda19988_init_encoder(sc, mode);
+
+	return (0);
+}
+
+static device_method_t tda_methods[] = {
+	DEVMETHOD(device_probe,		tda19988_probe),
+	DEVMETHOD(device_attach,	tda19988_attach),
+	DEVMETHOD(device_detach,	tda19988_detach),
+
+	/* HDMI methods */
+	DEVMETHOD(hdmi_get_edid,	tda19988_get_edid),
+	DEVMETHOD(hdmi_set_videomode,	tda19988_set_videomode),
+	{0, 0},
+};
+
+static driver_t tda_driver = {
+	"tda",
+	tda_methods,
+	sizeof(struct tda19988_softc),
+};
+
+static devclass_t tda_devclass;
+
+DRIVER_MODULE(tda, iicbus, tda_driver, tda_devclass, 0, 0);
+MODULE_VERSION(tda, 1);
+MODULE_DEPEND(tda, iicbus, 1, 1, 1);
diff --git a/freebsd/sys/dev/extres/clk/clk.h b/freebsd/sys/dev/extres/clk/clk.h
new file mode 100644
index 00000000..617cd5e7
--- /dev/null
+++ b/freebsd/sys/dev/extres/clk/clk.h
@@ -0,0 +1,146 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_EXTRES_CLK_H_
+#define _DEV_EXTRES_CLK_H_
+#include <rtems/bsd/local/opt_platform.h>
+
+#include <sys/kobj.h>
+#ifdef FDT
+#include <dev/ofw/ofw_bus.h>
+#endif
+#include <rtems/bsd/local/clknode_if.h>
+
+#define CLKNODE_IDX_NONE	-1		/* Not-selected index */
+
+/* clknode flags. */
+#define	CLK_NODE_STATIC_STRINGS	0x00000001	/* Static name strings */
+#define	CLK_NODE_GLITCH_FREE	0x00000002	/* Freq can change w/o stop */
+#define	CLK_NODE_CANNOT_STOP	0x00000004	/* Clock cannot be disabled */
+
+/* Flags passed to clk_set_freq() and clknode_set_freq(). */
+#define	CLK_SET_ROUND(x)	((x) & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN))
+#define	CLK_SET_ROUND_EXACT	0
+#define	CLK_SET_ROUND_UP	0x00000001
+#define	CLK_SET_ROUND_DOWN	0x00000002
+#define	CLK_SET_ROUND_ANY	(CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)
+
+#define	CLK_SET_USER_MASK	0x0000FFFF
+#define	CLK_SET_DRYRUN		0x00010000
+
+typedef struct clk *clk_t;
+
+/* Initialization parameters for clocknode creation. */
+struct clknode_init_def {
+	const char	*name;
+	intptr_t	id;
+	const char	**parent_names;
+	int		parent_cnt;
+	int		flags;
+};
+
+/*
+ * Shorthands for constructing method tables.
+ */
+#define	CLKNODEMETHOD		KOBJMETHOD
+#define	CLKNODEMETHOD_END	KOBJMETHOD_END
+#define	clknode_method_t	kobj_method_t
+#define	clknode_class_t		kobj_class_t
+DECLARE_CLASS(clknode_class);
+
+/*
+ *  Clock domain functions.
+ */
+struct clkdom *clkdom_create(device_t dev);
+int clkdom_finit(struct clkdom *clkdom);
+void clkdom_dump(struct clkdom * clkdom);
+void clkdom_unlock(struct clkdom *clkdom);
+void clkdom_xlock(struct clkdom *clkdom);
+
+/*
+ * Clock providers interface.
+ */
+struct clkdom *clkdom_get_by_dev(const device_t dev);
+
+struct clknode *clknode_create(struct clkdom *clkdom,
+    clknode_class_t clknode_class, const struct clknode_init_def *def);
+struct clknode *clknode_register(struct clkdom *cldom, struct clknode *clk);
+#ifdef FDT
+typedef int clknode_ofw_mapper_func(struct clkdom *clkdom, uint32_t ncells,
+    phandle_t *cells, struct clknode **clk);
+void clkdom_set_ofw_mapper(struct clkdom *clkdom, clknode_ofw_mapper_func *cmp);
+#endif
+
+void clknode_init_parent_idx(struct clknode *clknode, int idx);
+int clknode_set_parent_by_idx(struct clknode *clk, int idx);
+int clknode_set_parent_by_name(struct clknode *clk, const char *name);
+const char *clknode_get_name(struct clknode *clk);
+const char **clknode_get_parent_names(struct clknode *clk);
+int clknode_get_parents_num(struct clknode *clk);
+int clknode_get_parent_idx(struct clknode *clk);
+struct clknode *clknode_get_parent(struct clknode *clk);
+int clknode_get_flags(struct clknode *clk);
+void *clknode_get_softc(struct clknode *clk);
+device_t clknode_get_device(struct clknode *clk);
+struct clknode *clknode_find_by_name(const char *name);
+struct clknode *clknode_find_by_id(struct clkdom *clkdom, intptr_t id);
+int clknode_get_freq(struct clknode *clknode, uint64_t *freq);
+int clknode_set_freq(struct clknode *clknode, uint64_t freq, int flags,
+    int enablecnt);
+int clknode_enable(struct clknode *clknode);
+int clknode_disable(struct clknode *clknode);
+int clknode_stop(struct clknode *clknode, int depth);
+
+/*
+ * Clock consumers interface.
+ */
+int clk_get_by_name(device_t dev, const char *name, clk_t *clk);
+int clk_get_by_id(device_t dev, struct clkdom *clkdom, intptr_t id, clk_t *clk);
+int clk_release(clk_t clk);
+int clk_get_freq(clk_t clk, uint64_t *freq);
+int clk_set_freq(clk_t clk, uint64_t freq, int flags);
+int clk_test_freq(clk_t clk, uint64_t freq, int flags);
+int clk_enable(clk_t clk);
+int clk_disable(clk_t clk);
+int clk_stop(clk_t clk);
+int clk_get_parent(clk_t clk, clk_t *parent);
+int clk_set_parent_by_clk(clk_t clk, clk_t parent);
+const char *clk_get_name(clk_t clk);
+
+#ifdef FDT
+int clk_set_assigned(device_t dev, phandle_t node);
+int clk_get_by_ofw_index(device_t dev, phandle_t node, int idx, clk_t *clk);
+int clk_get_by_ofw_index_prop(device_t dev, phandle_t cnode, const char *prop, int idx, clk_t *clk);
+int clk_get_by_ofw_name(device_t dev, phandle_t node, const char *name,
+     clk_t *clk);
+int clk_parse_ofw_out_names(device_t dev, phandle_t node,
+    const char ***out_names, uint32_t **indices);
+int clk_parse_ofw_clk_name(device_t dev, phandle_t node, const char **name);
+#endif
+
+#endif /* _DEV_EXTRES_CLK_H_ */
diff --git a/freebsd/sys/dev/videomode/edid.c b/freebsd/sys/dev/videomode/edid.c
new file mode 100644
index 00000000..f92d3c92
--- /dev/null
+++ b/freebsd/sys/dev/videomode/edid.c
@@ -0,0 +1,649 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/* $NetBSD: edid.c,v 1.12 2013/02/08 16:35:10 skrll Exp $ */
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Written by Garrett D'Amore for Itronix Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of Itronix Inc. may not be used to endorse
+ *    or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */ 
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/libkern.h>
+#include <dev/videomode/videomode.h>
+#include <dev/videomode/ediddevs.h>
+#include <dev/videomode/edidreg.h>
+#include <dev/videomode/edidvar.h>
+#include <dev/videomode/vesagtf.h>
+
+#define	EDIDVERBOSE	1
+#define	DIVIDE(x,y)	(((x) + ((y) / 2)) / (y))
+
+/* These are reversed established timing order */
+static const char *_edid_modes[] =  {
+	"1280x1024x75",
+	"1024x768x75",
+	"1024x768x70",
+	"1024x768x60",
+	"1024x768x87i",
+	"832x624x74",	/* rounding error, 74.55 Hz aka "832x624x75" */
+	"800x600x75",
+	"800x600x72",
+	"800x600x60",
+	"800x600x56",
+	"640x480x75",
+	"640x480x72",
+	"640x480x67",
+	"640x480x60",
+	"720x400x87",	/* rounding error, 87.85 Hz aka "720x400x88" */
+	"720x400x70",
+};
+
+#ifdef	EDIDVERBOSE
+struct edid_vendor {
+	const char	*vendor;
+	const char	*name;
+};
+
+struct edid_product {
+	const char	*vendor;
+	uint16_t	product;
+	const char	*name;
+};
+
+#include <dev/videomode/ediddevs_data.h>
+#endif	/* EDIDVERBOSE */
+
+static const char *
+edid_findvendor(const char *vendor)
+{
+#ifdef	EDIDVERBOSE
+	int	n;
+
+	for (n = 0; n < edid_nvendors; n++)
+		if (memcmp(edid_vendors[n].vendor, vendor, 3) == 0)
+			return edid_vendors[n].name;
+#endif
+	return NULL;
+}
+
+static const char *
+edid_findproduct(const char *vendor, uint16_t product)
+{
+#ifdef	EDIDVERBOSE
+	int	n;
+
+	for (n = 0; n < edid_nproducts; n++)
+		if (edid_products[n].product == product &&
+		    memcmp(edid_products[n].vendor, vendor, 3) == 0)
+			return edid_products[n].name;
+#endif	/* EDIDVERBOSE */
+	return NULL;
+
+}
+
+static void
+edid_strchomp(char *ptr)
+{
+	for (;;) {
+		switch (*ptr) {
+		case '\0':
+			return;
+		case '\r':
+		case '\n':
+			*ptr = '\0';
+			return;
+		}
+		ptr++;
+	}
+}
+
+int
+edid_is_valid(uint8_t *d)
+{
+	int sum = 0, i;
+	uint8_t sig[8] = EDID_SIGNATURE;
+	
+	if (memcmp(d, sig, 8) != 0)
+		return EINVAL;
+	
+	for (i = 0; i < 128; i++)
+		sum += d[i];
+	if ((sum & 0xff) != 0)
+		return EINVAL;
+		
+	return 0;
+}
+
+void
+edid_print(struct edid_info *edid)
+{
+	int	i;
+
+	if (edid == NULL)
+		return;
+	printf("Vendor: [%s] %s\n", edid->edid_vendor, edid->edid_vendorname);
+	printf("Product: [%04X] %s\n", edid->edid_product,
+	    edid->edid_productname);
+	printf("Serial number: %s\n", edid->edid_serial);
+	printf("Manufactured %d Week %d\n",
+	    edid->edid_year, edid->edid_week);
+	printf("EDID Version %d.%d\n", edid->edid_version,
+	    edid->edid_revision);
+	printf("EDID Comment: %s\n", edid->edid_comment);
+
+	printf("Video Input: %x\n", edid->edid_video_input);
+	if (edid->edid_video_input & EDID_VIDEO_INPUT_DIGITAL) {
+		printf("\tDigital");
+		if (edid->edid_video_input & EDID_VIDEO_INPUT_DFP1_COMPAT)
+			printf(" (DFP 1.x compatible)");
+		printf("\n");
+	} else {
+		printf("\tAnalog\n");
+		switch (EDID_VIDEO_INPUT_LEVEL(edid->edid_video_input)) {
+		case 0:
+			printf("\t-0.7, 0.3V\n");
+			break;
+		case 1:
+			printf("\t-0.714, 0.286V\n");
+			break;
+		case 2:
+			printf("\t-1.0, 0.4V\n");
+			break;
+		case 3:
+			printf("\t-0.7, 0.0V\n");
+			break;
+		}
+		if (edid->edid_video_input & EDID_VIDEO_INPUT_BLANK_TO_BLACK)
+			printf("\tBlank-to-black setup\n");
+		if (edid->edid_video_input & EDID_VIDEO_INPUT_SEPARATE_SYNCS)
+			printf("\tSeperate syncs\n");
+		if (edid->edid_video_input & EDID_VIDEO_INPUT_COMPOSITE_SYNC)
+			printf("\tComposite sync\n");
+		if (edid->edid_video_input & EDID_VIDEO_INPUT_SYNC_ON_GRN)
+			printf("\tSync on green\n");
+		if (edid->edid_video_input & EDID_VIDEO_INPUT_SERRATION)
+			printf("\tSerration vsync\n");
+	}
+
+	printf("Gamma: %d.%02d\n",
+	    edid->edid_gamma / 100, edid->edid_gamma % 100);
+
+	printf("Max Size: %d cm x %d cm\n",
+	    edid->edid_max_hsize, edid->edid_max_vsize);
+
+	printf("Features: %x\n", edid->edid_features);
+	if (edid->edid_features & EDID_FEATURES_STANDBY)
+		printf("\tDPMS standby\n");
+	if (edid->edid_features & EDID_FEATURES_SUSPEND)
+		printf("\tDPMS suspend\n");
+	if (edid->edid_features & EDID_FEATURES_ACTIVE_OFF)
+		printf("\tDPMS active-off\n");
+	switch (EDID_FEATURES_DISP_TYPE(edid->edid_features)) {
+	case EDID_FEATURES_DISP_TYPE_MONO:
+		printf("\tMonochrome\n");
+		break;
+	case EDID_FEATURES_DISP_TYPE_RGB:
+		printf("\tRGB\n");
+		break;
+	case EDID_FEATURES_DISP_TYPE_NON_RGB:
+		printf("\tMulticolor\n");
+		break;
+	case EDID_FEATURES_DISP_TYPE_UNDEFINED:
+		printf("\tUndefined monitor type\n");
+		break;
+	}
+	if (edid->edid_features & EDID_FEATURES_STD_COLOR)
+		printf("\tStandard color space\n");
+	if (edid->edid_features & EDID_FEATURES_PREFERRED_TIMING)
+		printf("\tPreferred timing\n");
+	if (edid->edid_features & EDID_FEATURES_DEFAULT_GTF)
+		printf("\tDefault GTF supported\n");
+
+	printf("Chroma Info:\n");
+	printf("\tRed X: 0.%03d\n", edid->edid_chroma.ec_redx);
+	printf("\tRed Y: 0.%03d\n", edid->edid_chroma.ec_redy);
+	printf("\tGrn X: 0.%03d\n", edid->edid_chroma.ec_greenx);
+	printf("\tGrn Y: 0.%03d\n", edid->edid_chroma.ec_greeny);
+	printf("\tBlu X: 0.%03d\n", edid->edid_chroma.ec_bluex);
+	printf("\tBlu Y: 0.%03d\n", edid->edid_chroma.ec_bluey);
+	printf("\tWht X: 0.%03d\n", edid->edid_chroma.ec_whitex);
+	printf("\tWht Y: 0.%03d\n", edid->edid_chroma.ec_whitey);
+
+	if (edid->edid_have_range) {
+		printf("Range:\n");
+		printf("\tHorizontal: %d - %d kHz\n",
+		    edid->edid_range.er_min_hfreq,
+		    edid->edid_range.er_max_hfreq);
+		printf("\tVertical: %d - %d Hz\n",
+		    edid->edid_range.er_min_vfreq,
+		    edid->edid_range.er_max_vfreq);
+		printf("\tMax Dot Clock: %d MHz\n",
+		    edid->edid_range.er_max_clock);
+		if (edid->edid_range.er_have_gtf2) {
+			printf("\tGTF2 hfreq: %d\n",
+			    edid->edid_range.er_gtf2_hfreq);
+			printf("\tGTF2 C: %d\n", edid->edid_range.er_gtf2_c);
+			printf("\tGTF2 M: %d\n", edid->edid_range.er_gtf2_m);
+			printf("\tGTF2 J: %d\n", edid->edid_range.er_gtf2_j);
+			printf("\tGTF2 K: %d\n", edid->edid_range.er_gtf2_k);
+		}
+	}
+	printf("Video modes:\n");
+	for (i = 0; i < edid->edid_nmodes; i++) {
+		printf("\t%dx%d @ %dHz",
+		    edid->edid_modes[i].hdisplay,
+		    edid->edid_modes[i].vdisplay,
+		    DIVIDE(DIVIDE(edid->edid_modes[i].dot_clock * 1000,
+		    edid->edid_modes[i].htotal), edid->edid_modes[i].vtotal));
+		printf(" (%d %d %d %d %d %d %d",
+		    edid->edid_modes[i].dot_clock,
+		    edid->edid_modes[i].hsync_start,
+		    edid->edid_modes[i].hsync_end,
+		    edid->edid_modes[i].htotal,
+		    edid->edid_modes[i].vsync_start,
+		    edid->edid_modes[i].vsync_end,
+		    edid->edid_modes[i].vtotal);
+		printf(" %s%sH %s%sV)\n",
+		    edid->edid_modes[i].flags & VID_PHSYNC ? "+" : "",
+		    edid->edid_modes[i].flags & VID_NHSYNC ? "-" : "",
+		    edid->edid_modes[i].flags & VID_PVSYNC ? "+" : "",
+		    edid->edid_modes[i].flags & VID_NVSYNC ? "-" : "");
+	}
+	if (edid->edid_preferred_mode)
+		printf("Preferred mode: %dx%d @ %dHz\n",
+		    edid->edid_preferred_mode->hdisplay,
+		    edid->edid_preferred_mode->vdisplay,
+		    DIVIDE(DIVIDE(edid->edid_preferred_mode->dot_clock * 1000,
+		    edid->edid_preferred_mode->htotal),
+		    edid->edid_preferred_mode->vtotal));
+
+	printf("Number of extension blocks: %d\n", edid->edid_ext_block_count);
+}
+
+static const struct videomode *
+edid_mode_lookup_list(const char *name)
+{
+	int	i;
+
+	for (i = 0; i < videomode_count; i++)
+		if (strcmp(name, videomode_list[i].name) == 0)
+			return &videomode_list[i];
+	return NULL;
+}
+
+static struct videomode *
+edid_search_mode(struct edid_info *edid, const struct videomode *mode)
+{
+	int	refresh, i;
+
+	refresh = DIVIDE(DIVIDE(mode->dot_clock * 1000,
+	    mode->htotal), mode->vtotal);
+	for (i = 0; i < edid->edid_nmodes; i++) {
+		if (mode->hdisplay == edid->edid_modes[i].hdisplay &&
+		    mode->vdisplay == edid->edid_modes[i].vdisplay &&
+		    refresh == DIVIDE(DIVIDE(
+		    edid->edid_modes[i].dot_clock * 1000,
+		    edid->edid_modes[i].htotal), edid->edid_modes[i].vtotal)) {
+			return &edid->edid_modes[i];
+		}
+	}
+	return NULL;
+}
+
+static int
+edid_std_timing(uint8_t *data, struct videomode *vmp)
+{
+	unsigned			x, y, f;
+	const struct videomode		*lookup;
+	char				name[80];
+
+	if ((data[0] == 1 && data[1] == 1) ||
+	    (data[0] == 0 && data[1] == 0) ||
+	    (data[0] == 0x20 && data[1] == 0x20))
+		return 0;
+
+	x = EDID_STD_TIMING_HRES(data);
+	switch (EDID_STD_TIMING_RATIO(data)) {
+	case EDID_STD_TIMING_RATIO_16_10:
+		y = x * 10 / 16;
+		break;
+	case EDID_STD_TIMING_RATIO_4_3:
+		y = x * 3 / 4;
+		break;
+	case EDID_STD_TIMING_RATIO_5_4:
+		y = x * 4 / 5;
+		break;
+	case EDID_STD_TIMING_RATIO_16_9:
+	default:
+		y = x * 9 / 16;
+		break;
+	}
+	f = EDID_STD_TIMING_VFREQ(data);
+
+	/* first try to lookup the mode as a DMT timing */
+	snprintf(name, sizeof(name), "%dx%dx%d", x, y, f);
+	if ((lookup = edid_mode_lookup_list(name)) != NULL) {
+		*vmp = *lookup;
+	} else {
+		/* failing that, calculate it using gtf */
+		/*
+		 * Hmm. I'm not using alternate GTF timings, which
+		 * could, in theory, be present.
+		 */
+		vesagtf_mode(x, y, f, vmp);
+	}
+	return 1;
+}
+
+static int
+edid_det_timing(uint8_t *data, struct videomode *vmp)
+{
+	unsigned	hactive, hblank, hsyncwid, hsyncoff;
+	unsigned	vactive, vblank, vsyncwid, vsyncoff;
+	uint8_t		flags;
+
+	flags = EDID_DET_TIMING_FLAGS(data);
+
+	/* we don't support stereo modes (for now) */
+	if (flags & (EDID_DET_TIMING_FLAG_STEREO |
+		EDID_DET_TIMING_FLAG_STEREO_MODE))
+		return 0;
+
+	vmp->dot_clock = EDID_DET_TIMING_DOT_CLOCK(data) / 1000;
+
+	hactive = EDID_DET_TIMING_HACTIVE(data);
+	hblank = EDID_DET_TIMING_HBLANK(data);
+	hsyncwid = EDID_DET_TIMING_HSYNC_WIDTH(data);
+	hsyncoff = EDID_DET_TIMING_HSYNC_OFFSET(data);
+
+	vactive = EDID_DET_TIMING_VACTIVE(data);
+	vblank = EDID_DET_TIMING_VBLANK(data);
+	vsyncwid = EDID_DET_TIMING_VSYNC_WIDTH(data);
+	vsyncoff = EDID_DET_TIMING_VSYNC_OFFSET(data);
+	
+	/* Borders are contained within the blank areas. */
+
+	vmp->hdisplay = hactive;
+	vmp->htotal = hactive + hblank;
+	vmp->hsync_start = hactive + hsyncoff;
+	vmp->hsync_end = vmp->hsync_start + hsyncwid;
+
+	vmp->vdisplay = vactive;
+	vmp->vtotal = vactive + vblank;
+	vmp->vsync_start = vactive + vsyncoff;
+	vmp->vsync_end = vmp->vsync_start + vsyncwid;
+
+	vmp->flags = 0;
+
+	if (flags & EDID_DET_TIMING_FLAG_INTERLACE)
+		vmp->flags |= VID_INTERLACE;
+	if (flags & EDID_DET_TIMING_FLAG_HSYNC_POSITIVE)
+		vmp->flags |= VID_PHSYNC;
+	else
+		vmp->flags |= VID_NHSYNC;
+
+	if (flags & EDID_DET_TIMING_FLAG_VSYNC_POSITIVE)
+		vmp->flags |= VID_PVSYNC;
+	else
+		vmp->flags |= VID_NVSYNC;
+
+	return 1;
+}
+
+static void
+edid_block(struct edid_info *edid, uint8_t *data)
+{
+	int			i;
+	struct videomode	mode, *exist_mode;
+
+	if (EDID_BLOCK_IS_DET_TIMING(data)) {
+		if (!edid_det_timing(data, &mode))
+			return;
+		/* Does this mode already exist? */
+		exist_mode = edid_search_mode(edid, &mode);
+		if (exist_mode != NULL) {
+			*exist_mode = mode;
+			if (edid->edid_preferred_mode == NULL)
+				edid->edid_preferred_mode = exist_mode;
+		} else {
+			edid->edid_modes[edid->edid_nmodes] = mode;
+			if (edid->edid_preferred_mode == NULL)
+				edid->edid_preferred_mode =
+				    &edid->edid_modes[edid->edid_nmodes];
+			edid->edid_nmodes++;	
+		}
+		return;
+	}
+
+	switch (EDID_BLOCK_TYPE(data)) {
+	case EDID_DESC_BLOCK_TYPE_SERIAL:
+		memcpy(edid->edid_serial, data + EDID_DESC_ASCII_DATA_OFFSET,
+		    EDID_DESC_ASCII_DATA_LEN);
+		edid->edid_serial[sizeof(edid->edid_serial) - 1] = 0;
+		break;
+
+	case EDID_DESC_BLOCK_TYPE_ASCII:
+		memcpy(edid->edid_comment, data + EDID_DESC_ASCII_DATA_OFFSET,
+		    EDID_DESC_ASCII_DATA_LEN);
+		edid->edid_comment[sizeof(edid->edid_comment) - 1] = 0;
+		break;
+
+	case EDID_DESC_BLOCK_TYPE_RANGE:
+		edid->edid_have_range = 1;
+		edid->edid_range.er_min_vfreq =	EDID_DESC_RANGE_MIN_VFREQ(data);
+		edid->edid_range.er_max_vfreq =	EDID_DESC_RANGE_MAX_VFREQ(data);
+		edid->edid_range.er_min_hfreq =	EDID_DESC_RANGE_MIN_HFREQ(data);
+		edid->edid_range.er_max_hfreq =	EDID_DESC_RANGE_MAX_HFREQ(data);
+		edid->edid_range.er_max_clock = EDID_DESC_RANGE_MAX_CLOCK(data);
+		if (!EDID_DESC_RANGE_HAVE_GTF2(data))
+			break;
+		edid->edid_range.er_have_gtf2 = 1;
+		edid->edid_range.er_gtf2_hfreq =
+		    EDID_DESC_RANGE_GTF2_HFREQ(data);
+		edid->edid_range.er_gtf2_c = EDID_DESC_RANGE_GTF2_C(data);
+		edid->edid_range.er_gtf2_m = EDID_DESC_RANGE_GTF2_M(data);
+		edid->edid_range.er_gtf2_j = EDID_DESC_RANGE_GTF2_J(data);
+		edid->edid_range.er_gtf2_k = EDID_DESC_RANGE_GTF2_K(data);
+		break;
+
+	case EDID_DESC_BLOCK_TYPE_NAME:
+		/* copy the product name into place */
+		memcpy(edid->edid_productname,
+		    data + EDID_DESC_ASCII_DATA_OFFSET,
+		    EDID_DESC_ASCII_DATA_LEN);
+		break;
+
+	case EDID_DESC_BLOCK_TYPE_STD_TIMING:
+		data += EDID_DESC_STD_TIMING_START;
+		for (i = 0; i < EDID_DESC_STD_TIMING_COUNT; i++) {
+			if (edid_std_timing(data, &mode)) {
+				/* Does this mode already exist? */
+				exist_mode = edid_search_mode(edid, &mode);
+				if (exist_mode == NULL) {
+					edid->edid_modes[edid->edid_nmodes] =
+					    mode;
+					edid->edid_nmodes++;
+				}
+			}
+			data += 2;
+		}
+		break;
+
+	case EDID_DESC_BLOCK_TYPE_COLOR_POINT:
+		/* XXX: not implemented yet */
+		break;
+	}
+}
+
+/*
+ * Gets EDID version in BCD, e.g. EDID v1.3  returned as 0x0103
+ */
+int
+edid_parse(uint8_t *data, struct edid_info *edid)
+{
+	uint16_t		manfid, estmodes;
+	const struct videomode	*vmp;
+	int			i;
+	const char		*name;
+	int max_dotclock = 0;
+	int mhz;
+
+	if (edid_is_valid(data) != 0)
+		return -1;
+
+	/* get product identification */
+	manfid = EDID_VENDOR_ID(data);
+	edid->edid_vendor[0] = EDID_MANFID_0(manfid);
+	edid->edid_vendor[1] = EDID_MANFID_1(manfid);
+	edid->edid_vendor[2] = EDID_MANFID_2(manfid);
+	edid->edid_vendor[3] = 0;	/* null terminate for convenience */
+
+	edid->edid_product = data[EDID_OFFSET_PRODUCT_ID] + 
+	    (data[EDID_OFFSET_PRODUCT_ID + 1] << 8);
+
+	name = edid_findvendor(edid->edid_vendor);
+	if (name != NULL)
+		strlcpy(edid->edid_vendorname, name,
+		    sizeof(edid->edid_vendorname));
+	else
+		edid->edid_vendorname[0] = '\0';
+
+	name = edid_findproduct(edid->edid_vendor, edid->edid_product);
+	if (name != NULL)
+		strlcpy(edid->edid_productname, name,
+		    sizeof(edid->edid_productname));
+	else
+	    edid->edid_productname[0] = '\0';
+
+	snprintf(edid->edid_serial, sizeof(edid->edid_serial), "%08x",
+	    EDID_SERIAL_NUMBER(data));
+
+	edid->edid_week = EDID_WEEK(data);
+	edid->edid_year = EDID_YEAR(data);
+
+	/* get edid revision */
+	edid->edid_version = EDID_VERSION(data);
+	edid->edid_revision = EDID_REVISION(data);
+
+	edid->edid_video_input = EDID_VIDEO_INPUT(data);
+	edid->edid_max_hsize = EDID_MAX_HSIZE(data);
+	edid->edid_max_vsize = EDID_MAX_VSIZE(data);
+
+	edid->edid_gamma = EDID_GAMMA(data);
+	edid->edid_features = EDID_FEATURES(data);
+
+	edid->edid_chroma.ec_redx = EDID_CHROMA_REDX(data);
+	edid->edid_chroma.ec_redy = EDID_CHROMA_REDX(data);
+	edid->edid_chroma.ec_greenx = EDID_CHROMA_GREENX(data);
+	edid->edid_chroma.ec_greeny = EDID_CHROMA_GREENY(data);
+	edid->edid_chroma.ec_bluex = EDID_CHROMA_BLUEX(data);
+	edid->edid_chroma.ec_bluey = EDID_CHROMA_BLUEY(data);
+	edid->edid_chroma.ec_whitex = EDID_CHROMA_WHITEX(data);
+	edid->edid_chroma.ec_whitey = EDID_CHROMA_WHITEY(data);
+
+	edid->edid_ext_block_count = EDID_EXT_BLOCK_COUNT(data);
+
+	/* lookup established modes */
+	edid->edid_nmodes = 0;
+	edid->edid_preferred_mode = NULL;
+	estmodes = EDID_EST_TIMING(data);
+	/* Iterate in esztablished timing order */
+	for (i = 15; i >= 0; i--) {
+		if (estmodes & (1 << i)) {
+			vmp = edid_mode_lookup_list(_edid_modes[i]);
+			if (vmp != NULL) {
+				edid->edid_modes[edid->edid_nmodes] = *vmp;
+				edid->edid_nmodes++;
+			}
+#ifdef DIAGNOSTIC
+			  else
+				printf("no data for est. mode %s\n",
+				    _edid_modes[i]);
+#endif
+		}
+	}
+
+	/* do standard timing section */
+	for (i = 0; i < EDID_STD_TIMING_COUNT; i++) {
+		struct videomode	mode, *exist_mode;
+		if (edid_std_timing(data + EDID_OFFSET_STD_TIMING + i * 2,
+			&mode)) {
+			/* Does this mode already exist? */
+			exist_mode = edid_search_mode(edid, &mode);
+			if (exist_mode == NULL) {
+				edid->edid_modes[edid->edid_nmodes] = mode;
+				edid->edid_nmodes++;
+			}
+		}
+	}
+
+	/* do detailed timings and descriptors */
+	for (i = 0; i < EDID_BLOCK_COUNT; i++) {
+		edid_block(edid, data + EDID_OFFSET_DESC_BLOCK +
+		    i * EDID_BLOCK_SIZE);
+	}
+
+	edid_strchomp(edid->edid_vendorname);
+	edid_strchomp(edid->edid_productname);
+	edid_strchomp(edid->edid_serial);
+	edid_strchomp(edid->edid_comment);
+
+	/*
+	 * XXX
+	 * some monitors lie about their maximum supported dot clock
+	 * by claiming to support modes which need a higher dot clock
+	 * than the stated maximum.
+	 * For sanity's sake we bump it to the highest dot clock we find
+	 * in the list of supported modes
+	 */
+	for (i = 0; i < edid->edid_nmodes; i++)
+		if (edid->edid_modes[i].dot_clock > max_dotclock)
+			max_dotclock = edid->edid_modes[i].dot_clock;
+	if (bootverbose) {
+		printf("edid: max_dotclock according to supported modes: %d\n",
+		    max_dotclock);
+	}
+	mhz = (max_dotclock + 999) / 1000;
+
+	if (edid->edid_have_range) {
+		if (mhz > edid->edid_range.er_max_clock)
+			edid->edid_range.er_max_clock = mhz;
+	} else
+		edid->edid_range.er_max_clock = mhz;
+
+	return 0;
+}
+
diff --git a/freebsd/sys/dev/videomode/ediddevs.h b/freebsd/sys/dev/videomode/ediddevs.h
new file mode 100644
index 00000000..b383c8ae
--- /dev/null
+++ b/freebsd/sys/dev/videomode/ediddevs.h
@@ -0,0 +1,91 @@
+/*	$FreeBSD$	*/
+
+/*
+ * THIS FILE AUTOMATICALLY GENERATED.  DO NOT EDIT.
+ *
+ * generated from:
+ *	NetBSD: ediddevs,v 1.1 2006/05/11 01:49:53 gdamore Exp
+ */
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Written by Garrett D'Amore for Itronix Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of Itronix Inc. may not be used to endorse
+ *    or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */ 
+#define	EDID_VENDOR_AAC	"AcerView"
+#define	EDID_VENDOR_AOC	"AOC"
+#define	EDID_VENDOR_APP	"Apple Computer"
+#define	EDID_VENDOR_AST	"AST Research"
+#define	EDID_VENDOR_CPL	"Compal"
+#define	EDID_VENDOR_CPQ	"Compaq"
+#define	EDID_VENDOR_CTX	"CTX"
+#define	EDID_VENDOR_DEC	"DEC"
+#define	EDID_VENDOR_DEL	"Dell"
+#define	EDID_VENDOR_DPC	"Delta"
+#define	EDID_VENDOR_DWE	"Daewoo"
+#define	EDID_VENDOR_EIZ	"EIZO"
+#define	EDID_VENDOR_ELS	"ELSA"
+#define	EDID_VENDOR_EPI	"Envision"
+#define	EDID_VENDOR_FCM	"Funai"
+#define	EDID_VENDOR_FUJ	"Fujitsu"
+#define	EDID_VENDOR_GSM	"LG Electronics"
+#define	EDID_VENDOR_GWY	"Gateway 2000"
+#define	EDID_VENDOR_HEI	"Hyundai"
+#define	EDID_VENDOR_HIT	"Hitachi"
+#define	EDID_VENDOR_HSL	"Hansol"
+#define	EDID_VENDOR_HTC	"Hitachi/Nissei"
+#define	EDID_VENDOR_HWP	"HP"
+#define	EDID_VENDOR_IBM	"IBM"
+#define	EDID_VENDOR_ICL	"Fujitsu ICL"
+#define	EDID_VENDOR_IVM	"Iiyama"
+#define	EDID_VENDOR_KDS	"Korea Data Systems"
+#define	EDID_VENDOR_MEI	"Panasonic"
+#define	EDID_VENDOR_MEL	"Mitsubishi Electronics"
+#define	EDID_VENDOR_NAN	"Nanao"
+#define	EDID_VENDOR_NEC	"NEC"
+#define	EDID_VENDOR_NOK	"Nokia Data"
+#define	EDID_VENDOR_PHL	"Philips"
+#define	EDID_VENDOR_REL	"Relisys"
+#define	EDID_VENDOR_SAM	"Samsung"
+#define	EDID_VENDOR_SGI	"SGI"
+#define	EDID_VENDOR_SNY	"Sony"
+#define	EDID_VENDOR_SRC	"Shamrock"
+#define	EDID_VENDOR_SUN	"Sun Microsystems"
+#define	EDID_VENDOR_TAT	"Tatung"
+#define	EDID_VENDOR_TOS	"Toshiba"
+#define	EDID_VENDOR_TSB	"Toshiba"
+#define	EDID_VENDOR_VSC	"ViewSonic"
+#define	EDID_VENDOR_ZCM	"Zenith"
+
+/* Dell  - this exists for now as a sample.  I don't have one of these.  */
+#define	EDID_PRODUCT_DEL_ULTRASCAN14XE_REVA	0x139A		/* Ultrascan 14XE */
+#define	EDID_PRODUCT_DEL_ULTRASCAN14XE_REVB	0x139B		/* Ultrascan 14XE */
+
+/* ViewSonic */
+#define	EDID_PRODUCT_VSC_17GS	0x0c00		/* 17GS */
+#define	EDID_PRODUCT_VSC_17PS	0x0c0f		/* 17PS */
diff --git a/freebsd/sys/dev/videomode/ediddevs_data.h b/freebsd/sys/dev/videomode/ediddevs_data.h
new file mode 100644
index 00000000..e0ad80ab
--- /dev/null
+++ b/freebsd/sys/dev/videomode/ediddevs_data.h
@@ -0,0 +1,107 @@
+/*	$FreeBSD$	*/
+
+/*
+ * THIS FILE AUTOMATICALLY GENERATED.  DO NOT EDIT.
+ *
+ * generated from:
+ *	NetBSD: ediddevs,v 1.1 2006/05/11 01:49:53 gdamore Exp
+ */
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Written by Garrett D'Amore for Itronix Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of Itronix Inc. may not be used to endorse
+ *    or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */ 
+
+const struct edid_vendor edid_vendors[] = {
+	{ "AAC", EDID_VENDOR_AAC },
+	{ "AOC", EDID_VENDOR_AOC },
+	{ "APP", EDID_VENDOR_APP },
+	{ "AST", EDID_VENDOR_AST },
+	{ "CPL", EDID_VENDOR_CPL },
+	{ "CPQ", EDID_VENDOR_CPQ },
+	{ "CTX", EDID_VENDOR_CTX },
+	{ "DEC", EDID_VENDOR_DEC },
+	{ "DEL", EDID_VENDOR_DEL },
+	{ "DPC", EDID_VENDOR_DPC },
+	{ "DWE", EDID_VENDOR_DWE },
+	{ "EIZ", EDID_VENDOR_EIZ },
+	{ "ELS", EDID_VENDOR_ELS },
+	{ "EPI", EDID_VENDOR_EPI },
+	{ "FCM", EDID_VENDOR_FCM },
+	{ "FUJ", EDID_VENDOR_FUJ },
+	{ "GSM", EDID_VENDOR_GSM },
+	{ "GWY", EDID_VENDOR_GWY },
+	{ "HEI", EDID_VENDOR_HEI },
+	{ "HIT", EDID_VENDOR_HIT },
+	{ "HSL", EDID_VENDOR_HSL },
+	{ "HTC", EDID_VENDOR_HTC },
+	{ "HWP", EDID_VENDOR_HWP },
+	{ "IBM", EDID_VENDOR_IBM },
+	{ "ICL", EDID_VENDOR_ICL },
+	{ "IVM", EDID_VENDOR_IVM },
+	{ "KDS", EDID_VENDOR_KDS },
+	{ "MEI", EDID_VENDOR_MEI },
+	{ "MEL", EDID_VENDOR_MEL },
+	{ "NAN", EDID_VENDOR_NAN },
+	{ "NEC", EDID_VENDOR_NEC },
+	{ "NOK", EDID_VENDOR_NOK },
+	{ "PHL", EDID_VENDOR_PHL },
+	{ "REL", EDID_VENDOR_REL },
+	{ "SAM", EDID_VENDOR_SAM },
+	{ "SGI", EDID_VENDOR_SGI },
+	{ "SNY", EDID_VENDOR_SNY },
+	{ "SRC", EDID_VENDOR_SRC },
+	{ "SUN", EDID_VENDOR_SUN },
+	{ "TAT", EDID_VENDOR_TAT },
+	{ "TOS", EDID_VENDOR_TOS },
+	{ "TSB", EDID_VENDOR_TSB },
+	{ "VSC", EDID_VENDOR_VSC },
+	{ "ZCM", EDID_VENDOR_ZCM },
+};
+const int edid_nvendors = 44;
+
+const struct edid_product edid_products[] = {
+	{
+	    "DEL", EDID_PRODUCT_DEL_ULTRASCAN14XE_REVA,
+	    "Ultrascan 14XE",
+	},
+	{
+	    "DEL", EDID_PRODUCT_DEL_ULTRASCAN14XE_REVB,
+	    "Ultrascan 14XE",
+	},
+	{
+	    "VSC", EDID_PRODUCT_VSC_17GS,
+	    "17GS",
+	},
+	{
+	    "VSC", EDID_PRODUCT_VSC_17PS,
+	    "17PS",
+	},
+};
+const int edid_nproducts = 4;
diff --git a/freebsd/sys/dev/videomode/edidreg.h b/freebsd/sys/dev/videomode/edidreg.h
new file mode 100644
index 00000000..29b04665
--- /dev/null
+++ b/freebsd/sys/dev/videomode/edidreg.h
@@ -0,0 +1,256 @@
+/*	$NetBSD: edidreg.h,v 1.3 2011/03/30 18:49:56 jdc Exp $	*/
+/*	$FreeBSD$	*/
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Written by Garrett D'Amore for Itronix Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of Itronix Inc. may not be used to endorse
+ *    or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */ 
+
+#ifndef _DEV_VIDEOMODE_EDIDREG_H
+#define _DEV_VIDEOMODE_EDIDREG_H
+
+#define	EDID_OFFSET_SIGNATURE		0x00
+#define	EDID_OFFSET_MANUFACTURER_ID	0x08
+#define	EDID_OFFSET_PRODUCT_ID		0x0a
+#define	EDID_OFFSET_SERIAL_NUMBER	0x0c
+#define	EDID_OFFSET_MANUFACTURE_WEEK	0x10
+#define	EDID_OFFSET_MANUFACTURE_YEAR	0x11
+#define	EDID_OFFSET_VERSION		0x12
+#define	EDID_OFFSET_REVISION		0x13
+#define	EDID_OFFSET_VIDEO_INPUT		0x14
+#define	EDID_OFFSET_MAX_HSIZE		0x15	/* in cm */
+#define	EDID_OFFSET_MAX_VSIZE		0x16
+#define	EDID_OFFSET_GAMMA		0x17
+#define	EDID_OFFSET_FEATURE		0x18
+#define	EDID_OFFSET_CHROMA		0x19
+#define	EDID_OFFSET_EST_TIMING_1	0x23
+#define	EDID_OFFSET_EST_TIMING_2	0x24
+#define EDID_OFFSET_MFG_TIMING		0x25
+#define	EDID_OFFSET_STD_TIMING		0x26
+#define	EDID_OFFSET_DESC_BLOCK		0x36
+
+#define	EDID_SIGNATURE		{ 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0 }
+
+/* assume x is 16-bit value */
+#define	EDID_VENDOR_ID(ptr)		((((ptr)[8]) << 8) + ptr[9])
+#define	EDID_MANFID_0(x)		((((x) >> 10) & 0x1f) + '@')
+#define	EDID_MANFID_1(x)		((((x) >> 5) & 0x1f) + '@')
+#define	EDID_MANFID_2(x)		((((x) >> 0) & 0x1f) + '@')
+
+/* relative to edid block */
+#define	EDID_PRODUCT_ID(ptr)		(((ptr)[10]) | (((ptr)[11]) << 8))
+#define	EDID_SERIAL_NUMBER(ptr)		(((ptr)[12] << 24) + \
+					((ptr)[13] << 16) + \
+					((ptr)[14] << 8) + \
+					(ptr)[15])
+
+/* relative to edid block */
+#define	EDID_WEEK(ptr)			((ptr)[16])
+#define	EDID_YEAR(ptr)			(((ptr)[17]) + 1990)
+
+#define	EDID_VERSION(ptr)		((ptr)[18])
+#define	EDID_REVISION(ptr)		((ptr)[19])
+
+#define	EDID_VIDEO_INPUT(ptr)		((ptr)[20])
+#define	EDID_VIDEO_INPUT_DIGITAL	0x80
+/* if INPUT_BIT_DIGITAL set */
+#define	EDID_VIDEO_INPUT_DFP1_COMPAT	0x01
+/* if INPUT_BIT_DIGITAL not set */
+#define	EDID_VIDEO_INPUT_BLANK_TO_BLACK	0x10
+#define	EDID_VIDEO_INPUT_SEPARATE_SYNCS	0x08
+#define	EDID_VIDEO_INPUT_COMPOSITE_SYNC	0x04
+#define	EDID_VIDEO_INPUT_SYNC_ON_GRN	0x02
+#define	EDID_VIDEO_INPUT_SERRATION	0x01
+#define	EDID_VIDEO_INPUT_LEVEL(x)	(((x) & 0x60) >> 5)
+/* meanings of level bits are as follows, I don't know names */
+/* 0 = 0.7,0.3,  1 = 0.714,0.286, 2 = 1.0,0.4, 3 = 0.7,0.0 */
+
+/* relative to edid block */
+#define	EDID_MAX_HSIZE(ptr)		((ptr)[21])	/* cm */
+#define	EDID_MAX_VSIZE(ptr)		((ptr)[22])	/* cm */
+/* gamma is scaled by 100 (avoid fp), e.g. 213 == 2.13 */
+#define	_GAMMA(x)			((x) == 0xff ? 100 : ((x) + 100))
+#define	EDID_GAMMA(ptr)			_GAMMA(ptr[23])
+
+#define	EDID_FEATURES(ptr)		((ptr)[24])
+#define	EDID_FEATURES_STANDBY			0x80
+#define	EDID_FEATURES_SUSPEND			0x40
+#define	EDID_FEATURES_ACTIVE_OFF		0x20
+#define	EDID_FEATURES_DISP_TYPE(x)		(((x) & 0x18) >> 3)
+#define	EDID_FEATURES_DISP_TYPE_MONO		0
+#define	EDID_FEATURES_DISP_TYPE_RGB		1
+#define	EDID_FEATURES_DISP_TYPE_NON_RGB		2
+#define	EDID_FEATURES_DISP_TYPE_UNDEFINED	3
+#define	EDID_FEATURES_STD_COLOR			0x04
+#define	EDID_FEATURES_PREFERRED_TIMING		0x02
+#define	EDID_FEATURES_DEFAULT_GTF		0x01
+
+/* chroma values 0.0 - 0.999 scaled as 0-999 */
+#define	_CHLO(byt, shft)	(((byt) >> (shft)) & 0x3)
+#define	_CHHI(byt)		((byt) << 2)
+#define	_CHHILO(ptr, l, s, h)	(_CHLO((ptr)[l], s) | _CHHI((ptr)[h]))
+#define	_CHROMA(ptr, l, s, h)	((_CHHILO(ptr, l, s, h) * 1000) / 1024)
+
+#define	EDID_CHROMA_REDX(ptr)	(_CHROMA(ptr, 25, 6, 27))
+#define	EDID_CHROMA_REDY(ptr)	(_CHROMA(ptr, 25, 4, 28))
+#define	EDID_CHROMA_GREENX(ptr)	(_CHROMA(ptr, 25, 2, 29))
+#define	EDID_CHROMA_GREENY(ptr)	(_CHROMA(ptr, 25, 0, 30))
+#define	EDID_CHROMA_BLUEX(ptr)	(_CHROMA(ptr, 26, 6, 31))
+#define	EDID_CHROMA_BLUEY(ptr)	(_CHROMA(ptr, 26, 4, 32))
+#define	EDID_CHROMA_WHITEX(ptr)	(_CHROMA(ptr, 26, 2, 33))
+#define	EDID_CHROMA_WHITEY(ptr)	(_CHROMA(ptr, 26, 0, 34))
+
+/* relative to edid block */
+#define	EDID_EST_TIMING(ptr)		(((ptr)[35] << 8) | (ptr)[36])
+#define	EDID_EST_TIMING_720_400_70	0x8000	/* 720x400 @ 70Hz */
+#define	EDID_EST_TIMING_720_400_88	0x4000	/* 720x400 @ 88Hz */
+#define	EDID_EST_TIMING_640_480_60	0x2000	/* 640x480 @ 60Hz */
+#define	EDID_EST_TIMING_640_480_67	0x1000	/* 640x480 @ 67Hz */
+#define	EDID_EST_TIMING_640_480_72	0x0800	/* 640x480 @ 72Hz */
+#define	EDID_EST_TIMING_640_480_75	0x0400	/* 640x480 @ 75Hz */
+#define	EDID_EST_TIMING_800_600_56	0x0200	/* 800x600 @ 56Hz */
+#define	EDID_EST_TIMING_800_600_60	0x0100	/* 800x600 @ 60Hz */
+#define	EDID_EST_TIMING_800_600_72	0x0080	/* 800x600 @ 72Hz */
+#define	EDID_EST_TIMING_800_600_75	0x0040	/* 800x600 @ 75Hz */
+#define	EDID_EST_TIMING_832_624_75	0x0020	/* 832x624 @ 75Hz */
+#define	EDID_EST_TIMING_1024_768_87I	0x0010	/* 1024x768i @ 87Hz */
+#define	EDID_EST_TIMING_1024_768_60	0x0008	/* 1024x768 @ 60Hz */
+#define	EDID_EST_TIMING_1024_768_70	0x0004	/* 1024x768 @ 70Hz */
+#define	EDID_EST_TIMING_1024_768_75	0x0002	/* 1024x768 @ 75Hz */
+#define	EDID_EST_TIMING_1280_1024_75	0x0001	/* 1280x1024 @ 75Hz */
+
+/*
+ * N.B.: ptr is relative to standard timing block - used for standard timing
+ * descriptors as well as standard timings section of edid!
+ */
+#define	EDID_STD_TIMING_HRES(ptr)	((((ptr)[0]) * 8) + 248)
+#define	EDID_STD_TIMING_VFREQ(ptr)	((((ptr)[1]) & 0x3f) + 60)
+#define	EDID_STD_TIMING_RATIO(ptr)	((ptr)[1] & 0xc0)
+#define	EDID_STD_TIMING_RATIO_16_10	0x00
+#define	EDID_STD_TIMING_RATIO_4_3	0x40
+#define	EDID_STD_TIMING_RATIO_5_4	0x80
+#define	EDID_STD_TIMING_RATIO_16_9	0xc0
+
+#define	EDID_STD_TIMING_SIZE		16
+#define	EDID_STD_TIMING_COUNT		8
+
+/*
+ * N.B.: ptr is relative to descriptor block start
+ */
+#define	EDID_BLOCK_SIZE			18
+#define	EDID_BLOCK_COUNT		4
+
+/* detailed timing block.... what a mess */
+#define	EDID_BLOCK_IS_DET_TIMING(ptr)		((ptr)[0] | (ptr)[1])
+
+#define	EDID_DET_TIMING_DOT_CLOCK(ptr)	(((ptr)[0] | ((ptr)[1] << 8)) * 10000)
+#define	_HACT_LO(ptr)			((ptr)[2])
+#define	_HBLK_LO(ptr)			((ptr)[3])
+#define	_HACT_HI(ptr)			(((ptr)[4] & 0xf0) << 4)
+#define	_HBLK_HI(ptr)			(((ptr)[4] & 0x0f) << 8)
+#define	EDID_DET_TIMING_HACTIVE(ptr)		(_HACT_LO(ptr) | _HACT_HI(ptr))
+#define	EDID_DET_TIMING_HBLANK(ptr)		(_HBLK_LO(ptr) | _HBLK_HI(ptr))
+#define	_VACT_LO(ptr)			((ptr)[5])
+#define	_VBLK_LO(ptr)			((ptr)[6])
+#define	_VACT_HI(ptr)			(((ptr)[7] & 0xf0) << 4)
+#define	_VBLK_HI(ptr)			(((ptr)[7] & 0x0f) << 8)
+#define	EDID_DET_TIMING_VACTIVE(ptr)		(_VACT_LO(ptr) | _VACT_HI(ptr))
+#define	EDID_DET_TIMING_VBLANK(ptr)		(_VBLK_LO(ptr) | _VBLK_HI(ptr))
+#define	_HOFF_LO(ptr)			((ptr)[8])
+#define	_HWID_LO(ptr)			((ptr)[9])
+#define	_VOFF_LO(ptr)			((ptr)[10] >> 4)
+#define	_VWID_LO(ptr)			((ptr)[10] & 0xf)
+#define	_HOFF_HI(ptr)			(((ptr)[11] & 0xc0) << 2)
+#define	_HWID_HI(ptr)			(((ptr)[11] & 0x30) << 4)
+#define	_VOFF_HI(ptr)			(((ptr)[11] & 0x0c) << 2)
+#define	_VWID_HI(ptr)			(((ptr)[11] & 0x03) << 4)
+#define	EDID_DET_TIMING_HSYNC_OFFSET(ptr)	(_HOFF_LO(ptr) | _HOFF_HI(ptr))
+#define	EDID_DET_TIMING_HSYNC_WIDTH(ptr)	(_HWID_LO(ptr) | _HWID_HI(ptr))
+#define	EDID_DET_TIMING_VSYNC_OFFSET(ptr)	(_VOFF_LO(ptr) | _VOFF_HI(ptr))
+#define	EDID_DET_TIMING_VSYNC_WIDTH(ptr)	(_VWID_LO(ptr) | _VWID_HI(ptr))
+#define	_HSZ_LO(ptr)			((ptr)[12])
+#define	_VSZ_LO(ptr)			((ptr)[13])
+#define	_HSZ_HI(ptr)			(((ptr)[14] & 0xf0) << 4)
+#define	_VSZ_HI(ptr)			(((ptr)[14] & 0x0f) << 8)
+#define	EDID_DET_TIMING_HSIZE(ptr)		(_HSZ_LO(ptr) | _HSZ_HI(ptr))
+#define	EDID_DET_TIMING_VSIZE(ptr)		(_VSZ_LO(ptr) | _VSZ_HI(ptr))
+#define	EDID_DET_TIMING_HBORDER(ptr)	((ptr)[15])
+#define	EDID_DET_TIMING_VBORDER(ptr)	((ptr)[16])
+#define	EDID_DET_TIMING_FLAGS(ptr)	((ptr)[17])
+#define	EDID_DET_TIMING_FLAG_INTERLACE		0x80
+#define	EDID_DET_TIMING_FLAG_STEREO		0x60	/* stereo or not */
+#define	EDID_DET_TIMING_FLAG_SYNC_SEPARATE	0x18
+#define	EDID_DET_TIMING_FLAG_VSYNC_POSITIVE	0x04
+#define	EDID_DET_TIMING_FLAG_HSYNC_POSITIVE	0x02
+#define	EDID_DET_TIMING_FLAG_STEREO_MODE	0x01	/* stereo mode */
+
+
+/* N.B.: these tests assume that we already checked for detailed timing! */
+#define	EDID_BLOCK_TYPE(ptr)			((ptr)[3])
+
+#define	EDID_DESC_BLOCK_SIZE			18
+#define	EDID_DESC_BLOCK_TYPE_SERIAL		0xFF
+#define	EDID_DESC_BLOCK_TYPE_ASCII		0xFE
+#define	EDID_DESC_BLOCK_TYPE_RANGE		0xFD
+#define	EDID_DESC_BLOCK_TYPE_NAME		0xFC
+#define	EDID_DESC_BLOCK_TYPE_COLOR_POINT	0xFB
+#define	EDID_DESC_BLOCK_TYPE_STD_TIMING		0xFA
+
+/* used for descriptors 0xFF, 0xFE, and 0xFC */
+#define	EDID_DESC_ASCII_DATA_OFFSET		5
+#define	EDID_DESC_ASCII_DATA_LEN		13
+
+#define	EDID_DESC_RANGE_MIN_VFREQ(ptr)		((ptr)[5])	/* Hz */
+#define	EDID_DESC_RANGE_MAX_VFREQ(ptr)		((ptr)[6])	/* Hz */
+#define	EDID_DESC_RANGE_MIN_HFREQ(ptr)		((ptr)[7])	/* kHz */
+#define	EDID_DESC_RANGE_MAX_HFREQ(ptr)		((ptr)[8])	/* kHz */
+#define	EDID_DESC_RANGE_MAX_CLOCK(ptr)		(((ptr)[9]) * 10) /* MHz */
+#define	EDID_DESC_RANGE_HAVE_GTF2(ptr)		(((ptr)[10]) == 0x02)
+#define	EDID_DESC_RANGE_GTF2_HFREQ(ptr)		(((ptr)[12]) * 2)
+#define	EDID_DESC_RANGE_GTF2_C(ptr)		(((ptr)[13]) / 2)
+#define	EDID_DESC_RANGE_GTF2_M(ptr)		((ptr)[14] + ((ptr)[15] << 8))
+#define	EDID_DESC_RANGE_GTF2_K(ptr)		((ptr)[16])
+#define	EDID_DESC_RANGE_GTF2_J(ptr)		((ptr)[17] / 2)
+
+#define	EDID_DESC_COLOR_WHITEX(ptr)
+#define	EDID_DESC_COLOR_WHITE_INDEX_1(ptr)	((ptr)[5])
+#define	EDID_DESC_COLOR_WHITEX_1(ptr)		_CHROMA(ptr, 6, 2, 7)
+#define	EDID_DESC_COLOR_WHITEY_1(ptr)		_CHROMA(ptr, 6, 0, 8)
+#define	EDID_DESC_COLOR_GAMMA_1(ptr)		_GAMMA(ptr[9])
+#define	EDID_DESC_COLOR_WHITE_INDEX_2(ptr)	((ptr)[10])
+#define	EDID_DESC_COLOR_WHITEX_2(ptr)		_CHROMA(ptr, 11, 2, 12)
+#define	EDID_DESC_COLOR_WHITEY_2(ptr)		_CHROMA(ptr, 11, 0, 13)
+#define	EDID_DESC_COLOR_GAMMA_2(ptr)		_GAMMA(ptr[14])
+
+#define	EDID_DESC_STD_TIMING_START		5
+#define	EDID_DESC_STD_TIMING_COUNT		6
+
+#define	EDID_EXT_BLOCK_COUNT(ptr)		((ptr)[126])
+
+#endif /* _DEV_VIDEOMODE_EDIDREG_H */
diff --git a/freebsd/sys/dev/videomode/edidvar.h b/freebsd/sys/dev/videomode/edidvar.h
new file mode 100644
index 00000000..da1211b4
--- /dev/null
+++ b/freebsd/sys/dev/videomode/edidvar.h
@@ -0,0 +1,96 @@
+/*	$NetBSD: edidvar.h,v 1.2 2006/05/11 19:05:41 gdamore Exp $	*/
+/*	$FreeBSD$	*/
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Written by Garrett D'Amore for Itronix Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of Itronix Inc. may not be used to endorse
+ *    or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */ 
+
+#ifndef _DEV_VIDEOMODE_EDIDVAR_H
+#define _DEV_VIDEOMODE_EDIDVAR_H
+
+struct edid_chroma {
+	uint16_t	ec_redx;
+	uint16_t	ec_redy;
+	uint16_t	ec_greenx;
+	uint16_t	ec_greeny;
+	uint16_t	ec_bluex;
+	uint16_t	ec_bluey;
+	uint16_t	ec_whitex;
+	uint16_t	ec_whitey;
+};
+
+struct edid_range {
+	uint16_t	er_min_vfreq;	/* Hz */
+	uint16_t	er_max_vfreq;	/* Hz */
+	uint16_t	er_min_hfreq;	/* kHz */
+	uint16_t	er_max_hfreq;	/* kHz */
+	uint16_t	er_max_clock;	/* MHz */
+	int		er_have_gtf2;
+	uint16_t	er_gtf2_hfreq;
+	uint16_t	er_gtf2_c;
+	uint16_t	er_gtf2_m;
+	uint16_t	er_gtf2_k;
+	uint16_t	er_gtf2_j;
+};
+
+struct edid_info {
+	uint8_t		edid_vendor[4];
+	char		edid_vendorname[16];
+	char		edid_productname[16];
+	char		edid_comment[16];
+	char		edid_serial[16];
+	uint16_t	edid_product;
+	uint8_t		edid_version;
+	uint8_t		edid_revision;
+	int		edid_year;
+	int		edid_week;
+	uint8_t		edid_video_input;	/* see edidregs.h */
+	uint8_t		edid_max_hsize;		/* in cm */
+	uint8_t		edid_max_vsize;		/* in cm */
+	uint8_t		edid_gamma;
+	uint8_t		edid_features;
+	uint8_t		edid_ext_block_count;
+
+	int			edid_have_range;
+	struct edid_range	edid_range;
+
+	struct edid_chroma	edid_chroma;
+
+	/* parsed modes */
+	struct videomode	*edid_preferred_mode;
+	int			edid_nmodes;
+	struct videomode	edid_modes[64];
+};
+
+int edid_is_valid(uint8_t *);
+int edid_parse(uint8_t *, struct edid_info *);
+void edid_print(struct edid_info *);
+
+#endif /* _DEV_VIDEOMODE_EDIDVAR_H */
diff --git a/freebsd/sys/dev/videomode/pickmode.c b/freebsd/sys/dev/videomode/pickmode.c
new file mode 100644
index 00000000..19fb834f
--- /dev/null
+++ b/freebsd/sys/dev/videomode/pickmode.c
@@ -0,0 +1,207 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/* $NetBSD: pickmode.c,v 1.3 2011/04/09 18:22:31 jdc Exp $ */
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation
+ * All rights reserved.
+ *
+ * this code was contributed to The NetBSD Foundation by Michael Lorenz
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE NETBSD FOUNDATION BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */ 
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/libkern.h>
+#include <dev/videomode/videomode.h>
+#include <rtems/bsd/local/opt_videomode.h>
+
+#ifdef PICKMODE_DEBUG
+#define DPRINTF printf
+#else
+#define DPRINTF while (0) printf
+#endif
+
+const struct videomode *
+pick_mode_by_dotclock(int width, int height, int dotclock)
+{
+	const struct videomode *this, *best = NULL;
+	int i;
+
+	DPRINTF("%s: looking for %d x %d at up to %d kHz\n", __func__, width,
+	    height, dotclock);
+	for (i = 0; i < videomode_count; i++) {
+		this = &videomode_list[i];
+		if ((this->hdisplay != width) || (this->vdisplay != height) ||
+		    (this->dot_clock > dotclock))
+			continue;
+		if (best != NULL) {
+			if (this->dot_clock > best->dot_clock)
+				best = this;
+		} else
+			best = this;
+	}
+	if (best != NULL)
+		DPRINTF("found %s\n", best->name);
+
+	return best;
+}
+
+const struct videomode *
+pick_mode_by_ref(int width, int height, int refresh)
+{
+	const struct videomode *this, *best = NULL;
+	int mref, closest = 1000, i, diff;
+
+	DPRINTF("%s: looking for %d x %d at up to %d Hz\n", __func__, width,
+	    height, refresh);
+	for (i = 0; i < videomode_count; i++) {
+
+		this = &videomode_list[i];
+		mref = this->dot_clock * 1000 / (this->htotal * this->vtotal);
+		diff = abs(mref - refresh);
+		if ((this->hdisplay != width) || (this->vdisplay != height))
+			continue;
+		DPRINTF("%s in %d hz, diff %d\n", this->name, mref, diff);
+		if (best != NULL) {
+			if (diff < closest) {
+				best = this;
+				closest = diff;
+			}
+		} else {
+			best = this;
+			closest = diff;
+		}
+	}
+	if (best != NULL)
+		DPRINTF("found %s %d\n", best->name, best->dot_clock);
+
+	return best;
+}
+
+static inline void
+swap_modes(struct videomode *left, struct videomode *right)
+{
+	struct videomode temp;
+
+	temp = *left;
+	*left = *right;
+	*right = temp;
+}
+
+/*
+ * Sort modes by refresh rate, aspect ratio (*), then resolution.
+ * Preferred mode or largest mode is first in the list and other modes
+ * are sorted on closest match to that mode.
+ * (*) Note that the aspect ratio calculation treats "close" aspect ratios
+ * (within 12.5%) as the same for this purpose.
+ */
+#define	DIVIDE(x, y)	(((x) + ((y) / 2)) / (y))
+void
+sort_modes(struct videomode *modes, struct videomode **preferred, int nmodes)
+{
+	int aspect, refresh, hbest, vbest, abest, atemp, rbest, rtemp;
+	int i, j;
+	struct videomode *mtemp = NULL;
+
+	if (nmodes < 2)
+		return;
+
+	if (*preferred != NULL) {
+		/* Put the preferred mode first in the list */
+		aspect = (*preferred)->hdisplay * 100 / (*preferred)->vdisplay;
+		refresh = DIVIDE(DIVIDE((*preferred)->dot_clock * 1000,
+		    (*preferred)->htotal), (*preferred)->vtotal);
+		if (*preferred != modes) {
+			swap_modes(*preferred, modes);
+			*preferred = modes;
+		}
+	} else {
+		/*
+		 * Find the largest horizontal and vertical mode and put that
+		 * first in the list.  Preferred refresh rate is taken from
+		 * the first mode of this size.
+		 */
+		hbest = 0;
+		vbest = 0;
+		for (i = 0; i < nmodes; i++) {
+			if (modes[i].hdisplay > hbest) {
+				hbest = modes[i].hdisplay;
+				vbest = modes[i].vdisplay;
+				mtemp = &modes[i];
+			} else if (modes[i].hdisplay == hbest &&
+			    modes[i].vdisplay > vbest) {
+				vbest = modes[i].vdisplay;
+				mtemp = &modes[i];
+			}
+		}
+		aspect = mtemp->hdisplay * 100 / mtemp->vdisplay;
+		refresh = DIVIDE(DIVIDE(mtemp->dot_clock * 1000,
+		    mtemp->htotal), mtemp->vtotal);
+		if (mtemp != modes)
+			swap_modes(mtemp, modes);
+	}
+
+	/* Sort other modes by refresh rate, aspect ratio, then resolution */
+	for (j = 1; j < nmodes - 1; j++) {
+		rbest = 1000;
+		abest = 1000;
+		hbest = 0;
+		vbest = 0;
+		for (i = j; i < nmodes; i++) {
+			rtemp = abs(refresh -
+			    DIVIDE(DIVIDE(modes[i].dot_clock * 1000,
+			    modes[i].htotal), modes[i].vtotal));
+			atemp = (modes[i].hdisplay * 100 / modes[i].vdisplay);
+			if (rtemp < rbest) {
+				rbest = rtemp;
+				mtemp = &modes[i];
+			}
+			if (rtemp == rbest) {
+				/* Treat "close" aspect ratios as identical */
+				if (abs(abest - atemp) > (abest / 8) &&
+				    abs(aspect - atemp) < abs(aspect - abest)) {
+					abest = atemp;
+					mtemp = &modes[i];
+				}
+				if (atemp == abest ||
+				    abs(abest - atemp) <= (abest / 8)) {
+					if (modes[i].hdisplay > hbest) {
+						hbest = modes[i].hdisplay;
+						mtemp = &modes[i];
+					}
+					if (modes[i].hdisplay == hbest &&
+					    modes[i].vdisplay > vbest) {
+						vbest = modes[i].vdisplay;
+						mtemp = &modes[i];
+					}
+				}
+			}
+		}
+		if (mtemp != &modes[j])
+			swap_modes(mtemp, &modes[j]);
+	}
+}
diff --git a/freebsd/sys/dev/videomode/vesagtf.c b/freebsd/sys/dev/videomode/vesagtf.c
new file mode 100644
index 00000000..a75aa75c
--- /dev/null
+++ b/freebsd/sys/dev/videomode/vesagtf.c
@@ -0,0 +1,705 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/* $NetBSD: vesagtf.c,v 1.2 2013/09/15 15:56:07 martin Exp $ */
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Written by Garrett D'Amore for Itronix Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of Itronix Inc. may not be used to endorse
+ *    or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */ 
+
+/*
+ * This was derived from a userland GTF program supplied by NVIDIA.
+ * NVIDIA's original boilerplate follows. 
+ *
+ * Note that I have heavily modified the program for use in the EDID
+ * kernel code for NetBSD, including removing the use of floating
+ * point operations and making significant adjustments to minimize
+ * error propagation while operating with integer only math.
+ *
+ * This has required the use of 64-bit integers in a few places, but
+ * the upshot is that for a calculation of 1920x1200x85 (as an
+ * example), the error deviates by only ~.004% relative to the
+ * floating point version.  This error is *well* within VESA
+ * tolerances.
+ */
+
+/*
+ * Copyright (c) 2001, Andy Ritger  aritger at nvidia.com
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * o Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * o Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer
+ *   in the documentation and/or other materials provided with the
+ *   distribution.
+ * o Neither the name of NVIDIA nor the names of its contributors
+ *   may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
+ * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 
+ *
+ * This program is based on the Generalized Timing Formula(GTF TM)
+ * Standard Version: 1.0, Revision: 1.0
+ *
+ * The GTF Document contains the following Copyright information:
+ *
+ * Copyright (c) 1994, 1995, 1996 - Video Electronics Standards
+ * Association. Duplication of this document within VESA member
+ * companies for review purposes is permitted. All other rights
+ * reserved.
+ *
+ * While every precaution has been taken in the preparation
+ * of this standard, the Video Electronics Standards Association and
+ * its contributors assume no responsibility for errors or omissions,
+ * and make no warranties, expressed or implied, of functionality
+ * of suitability for any purpose. The sample code contained within
+ * this standard may be used without restriction.
+ *
+ * 
+ *
+ * The GTF EXCEL(TM) SPREADSHEET, a sample (and the definitive)
+ * implementation of the GTF Timing Standard, is available at:
+ *
+ * ftp://ftp.vesa.org/pub/GTF/GTF_V1R1.xls
+ *
+ *
+ *
+ * This program takes a desired resolution and vertical refresh rate,
+ * and computes mode timings according to the GTF Timing Standard.
+ * These mode timings can then be formatted as an XFree86 modeline
+ * or a mode description for use by fbset(8).
+ *
+ *
+ *
+ * NOTES:
+ *
+ * The GTF allows for computation of "margins" (the visible border
+ * surrounding the addressable video); on most non-overscan type
+ * systems, the margin period is zero.  I've implemented the margin
+ * computations but not enabled it because 1) I don't really have
+ * any experience with this, and 2) neither XFree86 modelines nor
+ * fbset fb.modes provide an obvious way for margin timings to be
+ * included in their mode descriptions (needs more investigation).
+ * 
+ * The GTF provides for computation of interlaced mode timings;
+ * I've implemented the computations but not enabled them, yet.
+ * I should probably enable and test this at some point.
+ *
+ * 
+ *
+ * TODO:
+ *
+ * o Add support for interlaced modes.
+ *
+ * o Implement the other portions of the GTF: compute mode timings
+ *   given either the desired pixel clock or the desired horizontal
+ *   frequency.
+ *
+ * o It would be nice if this were more general purpose to do things
+ *   outside the scope of the GTF: like generate double scan mode
+ *   timings, for example.
+ *   
+ * o Printing digits to the right of the decimal point when the
+ *   digits are 0 annoys me.
+ *
+ * o Error checking.
+ *
+ */
+
+
+#ifdef	_KERNEL
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <dev/videomode/videomode.h>
+#include <dev/videomode/vesagtf.h>
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "videomode.h"
+#include "vesagtf.h"
+
+void print_xf86_mode(struct videomode *m);
+#endif
+
+#define CELL_GRAN         8     /* assumed character cell granularity        */
+
+/* C' and M' are part of the Blanking Duty Cycle computation */
+/*
+ * #define C_PRIME           (((C - J) * K/256.0) + J)
+ * #define M_PRIME           (K/256.0 * M)
+ */
+
+/*
+ * C' and M' multiplied by 256 to give integer math.  Make sure to
+ * scale results using these back down, appropriately.
+ */
+#define	C_PRIME256(p)	  (((p->C - p->J) * p->K) + (p->J * 256))
+#define	M_PRIME256(p)	  (p->K * p->M)
+
+#define	DIVIDE(x,y)	(((x) + ((y) / 2)) / (y))
+
+/*
+ * print_value() - print the result of the named computation; this is
+ * useful when comparing against the GTF EXCEL spreadsheet.
+ */
+
+#ifdef GTFDEBUG
+
+static void
+print_value(int n, const char *name, unsigned val)
+{
+        printf("%2d: %-27s: %u\n", n, name, val);
+}
+#else
+#define	print_value(n, name, val)
+#endif
+
+
+/*
+ * vert_refresh() - as defined by the GTF Timing Standard, compute the
+ * Stage 1 Parameters using the vertical refresh frequency.  In other
+ * words: input a desired resolution and desired refresh rate, and
+ * output the GTF mode timings.
+ *
+ * XXX All the code is in place to compute interlaced modes, but I don't
+ * feel like testing it right now.
+ *
+ * XXX margin computations are implemented but not tested (nor used by
+ * XFree86 of fbset mode descriptions, from what I can tell).
+ */
+
+void
+vesagtf_mode_params(unsigned h_pixels, unsigned v_lines, unsigned freq,
+    struct vesagtf_params *params, int flags, struct videomode *vmp)
+{
+    unsigned v_field_rqd;
+    unsigned top_margin;
+    unsigned bottom_margin;
+    unsigned interlace;
+    uint64_t h_period_est;
+    unsigned vsync_plus_bp;
+    unsigned v_back_porch __unused;
+    unsigned total_v_lines;
+    uint64_t v_field_est;
+    uint64_t h_period;
+    unsigned v_field_rate;
+    unsigned v_frame_rate __unused;
+    unsigned left_margin;
+    unsigned right_margin;
+    unsigned total_active_pixels;
+    uint64_t ideal_duty_cycle;
+    unsigned h_blank;
+    unsigned total_pixels;
+    unsigned pixel_freq;
+
+    unsigned h_sync;
+    unsigned h_front_porch;
+    unsigned v_odd_front_porch_lines;
+
+#ifdef	GTFDEBUG
+    unsigned h_freq;
+#endif
+    
+    /*  1. In order to give correct results, the number of horizontal
+     *  pixels requested is first processed to ensure that it is divisible
+     *  by the character size, by rounding it to the nearest character
+     *  cell boundary:
+     *
+     *  [H PIXELS RND] = ((ROUND([H PIXELS]/[CELL GRAN RND],0))*[CELLGRAN RND])
+     */
+    
+    h_pixels = DIVIDE(h_pixels, CELL_GRAN) * CELL_GRAN;
+    
+    print_value(1, "[H PIXELS RND]", h_pixels);
+
+    
+    /*  2. If interlace is requested, the number of vertical lines assumed
+     *  by the calculation must be halved, as the computation calculates
+     *  the number of vertical lines per field. In either case, the
+     *  number of lines is rounded to the nearest integer.
+     *   
+     *  [V LINES RND] = IF([INT RQD?]="y", ROUND([V LINES]/2,0),
+     *                                     ROUND([V LINES],0))
+     */
+
+    v_lines = (flags & VESAGTF_FLAG_ILACE) ? DIVIDE(v_lines, 2) : v_lines;
+    
+    print_value(2, "[V LINES RND]", v_lines);
+    
+    
+    /*  3. Find the frame rate required:
+     *
+     *  [V FIELD RATE RQD] = IF([INT RQD?]="y", [I/P FREQ RQD]*2,
+     *                                          [I/P FREQ RQD])
+     */
+
+    v_field_rqd = (flags & VESAGTF_FLAG_ILACE) ? (freq * 2) : (freq);
+
+    print_value(3, "[V FIELD RATE RQD]", v_field_rqd);
+    
+
+    /*  4. Find number of lines in Top margin:
+     *  5. Find number of lines in Bottom margin:
+     *
+     *  [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y",
+     *          ROUND(([MARGIN%]/100*[V LINES RND]),0),
+     *          0)
+     *
+     *  Ditto for bottom margin.  Note that instead of %, we use PPT, which
+     *  is parts per thousand.  This helps us with integer math.
+     */
+
+    top_margin = bottom_margin = (flags & VESAGTF_FLAG_MARGINS) ?
+	DIVIDE(v_lines * params->margin_ppt, 1000) : 0;
+
+    print_value(4, "[TOP MARGIN (LINES)]", top_margin);
+    print_value(5, "[BOT MARGIN (LINES)]", bottom_margin);
+
+    
+    /*  6. If interlace is required, then set variable [INTERLACE]=0.5:
+     *   
+     *  [INTERLACE]=(IF([INT RQD?]="y",0.5,0))
+     *
+     *  To make this integer friendly, we use some special hacks in step
+     *  7 below.  Please read those comments to understand why I am using
+     *  a whole number of 1.0 instead of 0.5 here.
+     */
+    interlace = (flags & VESAGTF_FLAG_ILACE) ? 1 : 0;
+
+    print_value(6, "[2*INTERLACE]", interlace);
+    
+
+    /*  7. Estimate the Horizontal period
+     *
+     *  [H PERIOD EST] = ((1/[V FIELD RATE RQD]) - [MIN VSYNC+BP]/1000000) /
+     *                    ([V LINES RND] + (2*[TOP MARGIN (LINES)]) +
+     *                     [MIN PORCH RND]+[INTERLACE]) * 1000000
+     *
+     *  To make it integer friendly, we pre-multiply the 1000000 to get to
+     *  usec.  This gives us:
+     *
+     *  [H PERIOD EST] = ((1000000/[V FIELD RATE RQD]) - [MIN VSYNC+BP]) /
+     *			([V LINES RND] + (2 * [TOP MARGIN (LINES)]) +
+     *			 [MIN PORCH RND]+[INTERLACE])
+     *
+     *  The other problem is that the interlace value is wrong.  To get
+     *  the interlace to a whole number, we multiply both the numerator and
+     *  divisor by 2, so we can use a value of either 1 or 0 for the interlace
+     *  factor.
+     *
+     * This gives us:
+     *
+     * [H PERIOD EST] = ((2*((1000000/[V FIELD RATE RQD]) - [MIN VSYNC+BP])) /
+     *			 (2*([V LINES RND] + (2*[TOP MARGIN (LINES)]) +
+     *			  [MIN PORCH RND]) + [2*INTERLACE]))
+     *
+     * Finally we multiply by another 1000, to get value in picosec.
+     * Why picosec?  To minimize rounding errors.  Gotta love integer
+     * math and error propagation.
+     */
+
+    h_period_est = DIVIDE(((DIVIDE(2000000000000ULL, v_field_rqd)) -
+			      (2000000 * params->min_vsbp)),
+	((2 * (v_lines + (2 * top_margin) + params->min_porch)) + interlace));
+
+    print_value(7, "[H PERIOD EST (ps)]", h_period_est);
+    
+
+    /*  8. Find the number of lines in V sync + back porch:
+     *
+     *  [V SYNC+BP] = ROUND(([MIN VSYNC+BP]/[H PERIOD EST]),0)
+     *
+     *  But recall that h_period_est is in psec. So multiply by 1000000.
+     */
+
+    vsync_plus_bp = DIVIDE(params->min_vsbp * 1000000, h_period_est);
+
+    print_value(8, "[V SYNC+BP]", vsync_plus_bp);
+    
+    
+    /*  9. Find the number of lines in V back porch alone:
+     *
+     *  [V BACK PORCH] = [V SYNC+BP] - [V SYNC RND]
+     *
+     *  XXX is "[V SYNC RND]" a typo? should be [V SYNC RQD]?
+     */
+    
+    v_back_porch = vsync_plus_bp - params->vsync_rqd;
+    
+    print_value(9, "[V BACK PORCH]", v_back_porch);
+    
+
+    /*  10. Find the total number of lines in Vertical field period:
+     *
+     *  [TOTAL V LINES] = [V LINES RND] + [TOP MARGIN (LINES)] +
+     *                    [BOT MARGIN (LINES)] + [V SYNC+BP] + [INTERLACE] +
+     *                    [MIN PORCH RND]
+     */
+
+    total_v_lines = v_lines + top_margin + bottom_margin + vsync_plus_bp +
+        interlace + params->min_porch;
+    
+    print_value(10, "[TOTAL V LINES]", total_v_lines);
+    
+
+    /*  11. Estimate the Vertical field frequency:
+     *
+     *  [V FIELD RATE EST] = 1 / [H PERIOD EST] / [TOTAL V LINES] * 1000000
+     *
+     *  Again, we want to pre multiply by 10^9 to convert for nsec, thereby
+     *  making it usable in integer math.
+     *
+     *  So we get:
+     *
+     *  [V FIELD RATE EST] = 1000000000 / [H PERIOD EST] / [TOTAL V LINES]
+     *
+     *  This is all scaled to get the result in uHz.  Again, we're trying to
+     *  minimize error propagation.
+     */
+    v_field_est = DIVIDE(DIVIDE(1000000000000000ULL, h_period_est),
+	total_v_lines);
+    
+    print_value(11, "[V FIELD RATE EST(uHz)]", v_field_est);
+    
+
+    /*  12. Find the actual horizontal period:
+     *
+     *  [H PERIOD] = [H PERIOD EST] / ([V FIELD RATE RQD] / [V FIELD RATE EST])
+     */
+
+    h_period = DIVIDE(h_period_est * v_field_est, v_field_rqd * 1000);
+    
+    print_value(12, "[H PERIOD(ps)]", h_period);
+    
+
+    /*  13. Find the actual Vertical field frequency:
+     *
+     *  [V FIELD RATE] = 1 / [H PERIOD] / [TOTAL V LINES] * 1000000
+     *
+     *  And again, we convert to nsec ahead of time, giving us:
+     *
+     *  [V FIELD RATE] = 1000000 / [H PERIOD] / [TOTAL V LINES]
+     *
+     *  And another rescaling back to mHz.  Gotta love it.
+     */
+
+    v_field_rate = DIVIDE(1000000000000ULL, h_period * total_v_lines);
+
+    print_value(13, "[V FIELD RATE]", v_field_rate);
+    
+
+    /*  14. Find the Vertical frame frequency:
+     *
+     *  [V FRAME RATE] = (IF([INT RQD?]="y", [V FIELD RATE]/2, [V FIELD RATE]))
+     *
+     *  N.B. that the result here is in mHz.
+     */
+
+    v_frame_rate = (flags & VESAGTF_FLAG_ILACE) ?
+	v_field_rate / 2 : v_field_rate;
+
+    print_value(14, "[V FRAME RATE]", v_frame_rate);
+    
+
+    /*  15. Find number of pixels in left margin:
+     *  16. Find number of pixels in right margin:
+     *
+     *  [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y",
+     *          (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 /
+     *                   [CELL GRAN RND]),0)) * [CELL GRAN RND],
+     *          0))
+     *
+     *  Again, we deal with margin percentages as PPT (parts per thousand).
+     *  And the calculations for left and right are the same.
+     */
+
+    left_margin = right_margin = (flags & VESAGTF_FLAG_MARGINS) ?
+	DIVIDE(DIVIDE(h_pixels * params->margin_ppt, 1000),
+	    CELL_GRAN) * CELL_GRAN : 0;
+
+    print_value(15, "[LEFT MARGIN (PIXELS)]", left_margin);
+    print_value(16, "[RIGHT MARGIN (PIXELS)]", right_margin);
+    
+
+    /*  17. Find total number of active pixels in image and left and right
+     *  margins:
+     *
+     *  [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)] +
+     *                          [RIGHT MARGIN (PIXELS)]
+     */
+
+    total_active_pixels = h_pixels + left_margin + right_margin;
+    
+    print_value(17, "[TOTAL ACTIVE PIXELS]", total_active_pixels);
+    
+    
+    /*  18. Find the ideal blanking duty cycle from the blanking duty cycle
+     *  equation:
+     *
+     *  [IDEAL DUTY CYCLE] = [C'] - ([M']*[H PERIOD]/1000)
+     *
+     *  However, we have modified values for [C'] as [256*C'] and
+     *  [M'] as [256*M'].  Again the idea here is to get good scaling.
+     *  We use 256 as the factor to make the math fast.
+     *
+     *  Note that this means that we have to scale it appropriately in
+     *  later calculations.
+     *
+     *  The ending result is that our ideal_duty_cycle is 256000x larger
+     *  than the duty cycle used by VESA.  But again, this reduces error
+     *  propagation.
+     */
+
+    ideal_duty_cycle =
+	((C_PRIME256(params) * 1000) -
+	    (M_PRIME256(params) * h_period / 1000000));
+    
+    print_value(18, "[IDEAL DUTY CYCLE]", ideal_duty_cycle);
+    
+
+    /*  19. Find the number of pixels in the blanking time to the nearest
+     *  double character cell:
+     *
+     *  [H BLANK (PIXELS)] = (ROUND(([TOTAL ACTIVE PIXELS] *
+     *                               [IDEAL DUTY CYCLE] /
+     *                               (100-[IDEAL DUTY CYCLE]) /
+     *                               (2*[CELL GRAN RND])), 0))
+     *                       * (2*[CELL GRAN RND])
+     *
+     *  Of course, we adjust to make this rounding work in integer math.
+     */
+
+    h_blank = DIVIDE(DIVIDE(total_active_pixels * ideal_duty_cycle,
+			 (256000 * 100ULL) - ideal_duty_cycle),
+	2 * CELL_GRAN) * (2 * CELL_GRAN);
+
+    print_value(19, "[H BLANK (PIXELS)]", h_blank);
+    
+
+    /*  20. Find total number of pixels:
+     *
+     *  [TOTAL PIXELS] = [TOTAL ACTIVE PIXELS] + [H BLANK (PIXELS)]
+     */
+
+    total_pixels = total_active_pixels + h_blank;
+    
+    print_value(20, "[TOTAL PIXELS]", total_pixels);
+    
+
+    /*  21. Find pixel clock frequency:
+     *
+     *  [PIXEL FREQ] = [TOTAL PIXELS] / [H PERIOD]
+     *
+     *  We calculate this in Hz rather than MHz, to get a value that
+     *  is usable with integer math.  Recall that the [H PERIOD] is in
+     *  nsec.
+     */
+    
+    pixel_freq = DIVIDE(total_pixels * 1000000, DIVIDE(h_period, 1000));
+    
+    print_value(21, "[PIXEL FREQ]", pixel_freq);
+    
+
+    /*  22. Find horizontal frequency:
+     *
+     *  [H FREQ] = 1000 / [H PERIOD]
+     *
+     *  I've ifdef'd this out, because we don't need it for any of
+     *  our calculations.
+     *  We calculate this in Hz rather than kHz, to avoid rounding
+     *  errors.  Recall that the [H PERIOD] is in usec.
+     */
+
+#ifdef	GTFDEBUG
+    h_freq = 1000000000 / h_period;
+    
+    print_value(22, "[H FREQ]", h_freq);
+#endif
+    
+
+
+    /* Stage 1 computations are now complete; I should really pass
+       the results to another function and do the Stage 2
+       computations, but I only need a few more values so I'll just
+       append the computations here for now */
+
+    
+
+    /*  17. Find the number of pixels in the horizontal sync period:
+     *
+     *  [H SYNC (PIXELS)] =(ROUND(([H SYNC%] / 100 * [TOTAL PIXELS] /
+     *                             [CELL GRAN RND]),0))*[CELL GRAN RND]
+     *
+     *  Rewriting for integer math:
+     *
+     *  [H SYNC (PIXELS)]=(ROUND((H SYNC%] * [TOTAL PIXELS] / 100 /
+     *				   [CELL GRAN RND),0))*[CELL GRAN RND]
+     */
+
+    h_sync = DIVIDE(((params->hsync_pct * total_pixels) / 100), CELL_GRAN) *
+	CELL_GRAN;
+
+    print_value(17, "[H SYNC (PIXELS)]", h_sync);
+    
+
+    /*  18. Find the number of pixels in the horizontal front porch period:
+     *
+     *  [H FRONT PORCH (PIXELS)] = ([H BLANK (PIXELS)]/2)-[H SYNC (PIXELS)]
+     *
+     *  Note that h_blank is always an even number of characters (i.e.
+     *  h_blank % (CELL_GRAN * 2) == 0)
+     */
+
+    h_front_porch = (h_blank / 2) - h_sync;
+
+    print_value(18, "[H FRONT PORCH (PIXELS)]", h_front_porch);
+    
+    
+    /*  36. Find the number of lines in the odd front porch period:
+     *
+     *  [V ODD FRONT PORCH(LINES)]=([MIN PORCH RND]+[INTERLACE])
+     *
+     *  Adjusting for the fact that the interlace is scaled:
+     *
+     *  [V ODD FRONT PORCH(LINES)]=(([MIN PORCH RND] * 2) + [2*INTERLACE]) / 2
+     */
+    
+    v_odd_front_porch_lines = ((2 * params->min_porch) + interlace) / 2;
+    
+    print_value(36, "[V ODD FRONT PORCH(LINES)]", v_odd_front_porch_lines);
+    
+
+    /* finally, pack the results in the mode struct */
+
+    vmp->hsync_start = h_pixels + h_front_porch;
+    vmp->hsync_end = vmp->hsync_start + h_sync;
+    vmp->htotal = total_pixels;
+    vmp->hdisplay = h_pixels;
+
+    vmp->vsync_start = v_lines + v_odd_front_porch_lines;
+    vmp->vsync_end = vmp->vsync_start + params->vsync_rqd;
+    vmp->vtotal = total_v_lines;
+    vmp->vdisplay = v_lines;
+
+    vmp->dot_clock = pixel_freq;
+    
+}
+
+void
+vesagtf_mode(unsigned x, unsigned y, unsigned refresh, struct videomode *vmp)
+{
+	struct vesagtf_params	params;
+
+	params.margin_ppt = VESAGTF_MARGIN_PPT;
+	params.min_porch = VESAGTF_MIN_PORCH;
+	params.vsync_rqd = VESAGTF_VSYNC_RQD;
+	params.hsync_pct = VESAGTF_HSYNC_PCT;
+	params.min_vsbp = VESAGTF_MIN_VSBP;
+	params.M = VESAGTF_M;
+	params.C = VESAGTF_C;
+	params.K = VESAGTF_K;
+	params.J = VESAGTF_J;
+
+	vesagtf_mode_params(x, y, refresh, &params, 0, vmp);
+}
+
+/*
+ * The tidbit here is so that you can compile this file as a
+ * standalone user program to generate X11 modelines using VESA GTF.
+ * This also allows for testing of the code itself, without
+ * necessitating a full kernel recompile.
+ */
+
+/* print_xf86_mode() - print the XFree86 modeline, given mode timings. */
+
+#ifndef _KERNEL
+void
+print_xf86_mode (struct videomode *vmp)
+{
+	float	vf, hf;
+
+	hf = 1000.0 * vmp->dot_clock / vmp->htotal;
+	vf = 1.0 * hf / vmp->vtotal;
+
+    printf("\n");
+    printf("  # %dx%d @ %.2f Hz (GTF) hsync: %.2f kHz; pclk: %.2f MHz\n",
+	vmp->hdisplay, vmp->vdisplay, vf, hf, vmp->dot_clock / 1000.0);
+    
+    printf("  Modeline \"%dx%d_%.2f\"  %.2f"
+	"  %d %d %d %d"
+	"  %d %d %d %d"
+	"  -HSync +Vsync\n\n",
+	vmp->hdisplay, vmp->vdisplay, vf, (vmp->dot_clock / 1000.0),
+	vmp->hdisplay, vmp->hsync_start, vmp->hsync_end, vmp->htotal,
+	vmp->vdisplay, vmp->vsync_start, vmp->vsync_end, vmp->vtotal);
+}
+
+int
+main (int argc, char *argv[])
+{
+	struct videomode m;
+
+	if (argc != 4) {
+		printf("usage: %s x y refresh\n", argv[0]);
+		exit(1);
+	}
+    
+	vesagtf_mode(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), &m);
+
+        print_xf86_mode(&m);
+    
+	return 0;
+    
+}
+#endif
diff --git a/freebsd/sys/dev/videomode/vesagtf.h b/freebsd/sys/dev/videomode/vesagtf.h
new file mode 100644
index 00000000..ea9dae40
--- /dev/null
+++ b/freebsd/sys/dev/videomode/vesagtf.h
@@ -0,0 +1,86 @@
+/*	$NetBSD$	*/
+/*	$FreeBSD$	*/
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Written by Garrett D'Amore for Itronix Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of Itronix Inc. may not be used to endorse
+ *    or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */ 
+
+#ifndef _DEV_VIDEOMODE_VESAGTF_H
+#define _DEV_VIDEOMODE_VESAGTF_H
+
+/*
+ * Use VESA GTF formula to generate a monitor mode, given resolution and
+ * refresh rates.
+ */
+
+struct vesagtf_params {
+	unsigned	margin_ppt;	/* vertical margin size, percent * 10
+					 * think parts-per-thousand */
+	unsigned	min_porch;	/* minimum front porch */
+	unsigned	vsync_rqd;	/* width of vsync in lines */
+	unsigned	hsync_pct;	/* hsync as % of total width */
+	unsigned	min_vsbp;	/* minimum vsync + back porch (usec) */
+	unsigned	M;		/* blanking formula gradient */
+	unsigned	C;		/* blanking formula offset */
+	unsigned	K;		/* blanking formula scaling factor */
+	unsigned	J;		/* blanking formula scaling factor */
+};
+
+/*
+ * Default values to use for params.
+ */
+#define	VESAGTF_MARGIN_PPT	18	/* 1.8% */
+#define	VESAGTF_MIN_PORCH	1	/* minimum front porch */
+#define	VESAGTF_VSYNC_RQD	3	/* vsync width in lines */
+#define	VESAGTF_HSYNC_PCT	8	/* width of hsync % of total line */
+#define	VESAGTF_MIN_VSBP	550	/* min vsync + back porch (usec) */
+#define	VESAGTF_M		600	/* blanking formula gradient */
+#define	VESAGTF_C		40	/* blanking formula offset */
+#define	VESAGTF_K		128	/* blanking formula scaling factor */
+#define	VESAGTF_J		20	/* blanking formula scaling factor */
+
+/*
+ * Use VESA GTF formula to generate monitor timings.  Assumes default
+ * GTF parameters, non-interlaced, and no margins.
+ */
+void vesagtf_mode(unsigned x, unsigned y, unsigned refresh,
+    struct videomode *);
+
+/*
+ * A more complete version, in case we ever want to use alternate GTF
+ * parameters.  EDID 1.3 allows for "secondary GTF parameters".
+ */
+void vesagtf_mode_params(unsigned x, unsigned y, unsigned refresh,
+    struct vesagtf_params *, int flags, struct videomode *);
+
+#define	VESAGTF_FLAG_ILACE	0x0001		/* use interlace */
+#define	VESAGTF_FLAG_MARGINS	0x0002		/* use margins */
+
+#endif /* _DEV_VIDEOMODE_VESAGTF_H */
diff --git a/freebsd/sys/dev/videomode/videomode.c b/freebsd/sys/dev/videomode/videomode.c
new file mode 100644
index 00000000..152a535f
--- /dev/null
+++ b/freebsd/sys/dev/videomode/videomode.c
@@ -0,0 +1,132 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$FreeBSD$	*/
+
+/*
+ * THIS FILE AUTOMATICALLY GENERATED.  DO NOT EDIT.
+ *
+ * generated from:
+ *	NetBSD: modelines,v 1.9 2011/03/30 18:45:04 jdc Exp 
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/module.h>
+#include <dev/videomode/videomode.h>
+
+MODULE_VERSION(videomode, 1);
+
+/*
+ * These macros help the modelines below fit on one line.
+ */
+#define HP VID_PHSYNC
+#define HN VID_NHSYNC
+#define VP VID_PVSYNC
+#define VN VID_NVSYNC
+#define I VID_INTERLACE
+#define DS VID_DBLSCAN
+
+#define M(nm,hr,vr,clk,hs,he,ht,vs,ve,vt,f) \
+	{ clk, hr, hs, he, ht, vr, vs, ve, vt, f, nm } 
+
+const struct videomode videomode_list[] = {
+M("640x350x85",640,350,31500,672,736,832,382,385,445,HP|VN),
+M("640x400x85",640,400,31500,672,736,832,401,404,445,HN|VP),
+M("720x400x70",720,400,28320,738,846,900,412,414,449,HN|VP),
+M("720x400x85",720,400,35500,756,828,936,401,404,446,HN|VP),
+M("720x400x87",720,400,35500,738,846,900,421,423,449,HN|VN),
+M("640x480x60",640,480,25175,656,752,800,490,492,525,HN|VN),
+M("640x480x72",640,480,31500,664,704,832,489,492,520,HN|VN),
+M("640x480x75",640,480,31500,656,720,840,481,484,500,HN|VN),
+M("640x480x85",640,480,36000,696,752,832,481,484,509,HN|VN),
+M("800x600x56",800,600,36000,824,896,1024,601,603,625,HP|VP),
+M("800x600x60",800,600,40000,840,968,1056,601,605,628,HP|VP),
+M("800x600x72",800,600,50000,856,976,1040,637,643,666,HP|VP),
+M("800x600x75",800,600,49500,816,896,1056,601,604,625,HP|VP),
+M("800x600x85",800,600,56250,832,896,1048,601,604,631,HP|VP),
+M("1024x768x87i",1024,768,44900,1032,1208,1264,768,776,817,HP|VP|I),
+M("1024x768x60",1024,768,65000,1048,1184,1344,771,777,806,HN|VN),
+M("1024x768x70",1024,768,75000,1048,1184,1328,771,777,806,HN|VN),
+M("1024x768x75",1024,768,78750,1040,1136,1312,769,772,800,HP|VP),
+M("1024x768x85",1024,768,94500,1072,1168,1376,769,772,808,HP|VP),
+M("1024x768x89",1024,768,100000,1108,1280,1408,768,780,796,HP|VP),
+M("1152x864x75",1152,864,108000,1216,1344,1600,865,868,900,HP|VP),
+M("1280x768x75",1280,768,105640,1312,1712,1744,782,792,807,HN|VP),
+M("1280x960x60",1280,960,108000,1376,1488,1800,961,964,1000,HP|VP),
+M("1280x960x85",1280,960,148500,1344,1504,1728,961,964,1011,HP|VP),
+M("1280x1024x60",1280,1024,108000,1328,1440,1688,1025,1028,1066,HP|VP),
+M("1280x1024x70",1280,1024,126000,1328,1440,1688,1025,1028,1066,HP|VP),
+M("1280x1024x75",1280,1024,135000,1296,1440,1688,1025,1028,1066,HP|VP),
+M("1280x1024x85",1280,1024,157500,1344,1504,1728,1025,1028,1072,HP|VP),
+M("1600x1200x60",1600,1200,162000,1664,1856,2160,1201,1204,1250,HP|VP),
+M("1600x1200x65",1600,1200,175500,1664,1856,2160,1201,1204,1250,HP|VP),
+M("1600x1200x70",1600,1200,189000,1664,1856,2160,1201,1204,1250,HP|VP),
+M("1600x1200x75",1600,1200,202500,1664,1856,2160,1201,1204,1250,HP|VP),
+M("1600x1200x85",1600,1200,229500,1664,1856,2160,1201,1204,1250,HP|VP),
+M("1680x1050x60",1680,1050,147140,1784,1968,2256,1051,1054,1087,HP|VP),
+M("1792x1344x60",1792,1344,204800,1920,2120,2448,1345,1348,1394,HN|VP),
+M("1792x1344x75",1792,1344,261000,1888,2104,2456,1345,1348,1417,HN|VP),
+M("1856x1392x60",1856,1392,218300,1952,2176,2528,1393,1396,1439,HN|VP),
+M("1856x1392x75",1856,1392,288000,1984,2208,2560,1393,1396,1500,HN|VP),
+M("1920x1440x60",1920,1440,234000,2048,2256,2600,1441,1444,1500,HN|VP),
+M("1920x1440x75",1920,1440,297000,2064,2288,2640,1441,1444,1500,HN|VP),
+M("832x624x74",832,624,57284,864,928,1152,625,628,667,HN|VN),
+M("1152x768x54",1152,768,64995,1178,1314,1472,771,777,806,HP|VP),
+M("1400x1050x60",1400,1050,122000,1488,1640,1880,1052,1064,1082,HP|VP),
+M("1400x1050x74",1400,1050,155800,1464,1784,1912,1052,1064,1090,HP|VP),
+M("1152x900x66",1152,900,94500,1192,1320,1528,902,906,937,HN|VN),
+M("1152x900x76",1152,900,105560,1168,1280,1472,902,906,943,HN|VN),
+
+/* Derived Double Scan Modes */
+
+M("320x175x85",320,175,15750,336,368,416,191,192,222,HP|VN|DS),
+M("320x200x85",320,200,15750,336,368,416,200,202,222,HN|VP|DS),
+M("360x200x70",360,200,14160,369,423,450,206,207,224,HN|VP|DS),
+M("360x200x85",360,200,17750,378,414,468,200,202,223,HN|VP|DS),
+M("360x200x87",360,200,17750,369,423,450,210,211,224,HN|VN|DS),
+M("320x240x60",320,240,12587,328,376,400,245,246,262,HN|VN|DS),
+M("320x240x72",320,240,15750,332,352,416,244,246,260,HN|VN|DS),
+M("320x240x75",320,240,15750,328,360,420,240,242,250,HN|VN|DS),
+M("320x240x85",320,240,18000,348,376,416,240,242,254,HN|VN|DS),
+M("400x300x56",400,300,18000,412,448,512,300,301,312,HP|VP|DS),
+M("400x300x60",400,300,20000,420,484,528,300,302,314,HP|VP|DS),
+M("400x300x72",400,300,25000,428,488,520,318,321,333,HP|VP|DS),
+M("400x300x75",400,300,24750,408,448,528,300,302,312,HP|VP|DS),
+M("400x300x85",400,300,28125,416,448,524,300,302,315,HP|VP|DS),
+M("512x384x87i",512,384,22450,516,604,632,384,388,408,HP|VP|DS|I),
+M("512x384x60",512,384,32500,524,592,672,385,388,403,HN|VN|DS),
+M("512x384x70",512,384,37500,524,592,664,385,388,403,HN|VN|DS),
+M("512x384x75",512,384,39375,520,568,656,384,386,400,HP|VP|DS),
+M("512x384x85",512,384,47250,536,584,688,384,386,404,HP|VP|DS),
+M("512x384x89",512,384,50000,554,640,704,384,390,398,HP|VP|DS),
+M("576x432x75",576,432,54000,608,672,800,432,434,450,HP|VP|DS),
+M("640x384x75",640,384,52820,656,856,872,391,396,403,HN|VP|DS),
+M("640x480x60",640,480,54000,688,744,900,480,482,500,HP|VP|DS),
+M("640x480x85",640,480,74250,672,752,864,480,482,505,HP|VP|DS),
+M("640x512x60",640,512,54000,664,720,844,512,514,533,HP|VP|DS),
+M("640x512x70",640,512,63000,664,720,844,512,514,533,HP|VP|DS),
+M("640x512x75",640,512,67500,648,720,844,512,514,533,HP|VP|DS),
+M("640x512x85",640,512,78750,672,752,864,512,514,536,HP|VP|DS),
+M("800x600x60",800,600,81000,832,928,1080,600,602,625,HP|VP|DS),
+M("800x600x65",800,600,87750,832,928,1080,600,602,625,HP|VP|DS),
+M("800x600x70",800,600,94500,832,928,1080,600,602,625,HP|VP|DS),
+M("800x600x75",800,600,101250,832,928,1080,600,602,625,HP|VP|DS),
+M("800x600x85",800,600,114750,832,928,1080,600,602,625,HP|VP|DS),
+M("840x525x60",840,525,73570,892,984,1128,525,527,543,HP|VP|DS),
+M("896x672x60",896,672,102400,960,1060,1224,672,674,697,HN|VP|DS),
+M("896x672x75",896,672,130500,944,1052,1228,672,674,708,HN|VP|DS),
+M("928x696x60",928,696,109150,976,1088,1264,696,698,719,HN|VP|DS),
+M("928x696x75",928,696,144000,992,1104,1280,696,698,750,HN|VP|DS),
+M("960x720x60",960,720,117000,1024,1128,1300,720,722,750,HN|VP|DS),
+M("960x720x75",960,720,148500,1032,1144,1320,720,722,750,HN|VP|DS),
+M("416x312x74",416,312,28642,432,464,576,312,314,333,HN|VN|DS),
+M("576x384x54",576,384,32497,589,657,736,385,388,403,HP|VP|DS),
+M("700x525x60",700,525,61000,744,820,940,526,532,541,HP|VP|DS),
+M("700x525x74",700,525,77900,732,892,956,526,532,545,HP|VP|DS),
+M("576x450x66",576,450,47250,596,660,764,451,453,468,HN|VN|DS),
+M("576x450x76",576,450,52780,584,640,736,451,453,471,HN|VN|DS),
+};
+
+const int videomode_count = 46;
diff --git a/freebsd/sys/dev/videomode/videomode.h b/freebsd/sys/dev/videomode/videomode.h
new file mode 100644
index 00000000..3e644448
--- /dev/null
+++ b/freebsd/sys/dev/videomode/videomode.h
@@ -0,0 +1,75 @@
+/*	$NetBSD: videomode.h,v 1.2 2010/05/04 21:17:10 macallan Exp $	*/
+/*	$FreeBSD$	*/
+
+/*
+ * Copyright (c) 2001, 2002 Bang Jun-Young
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_VIDEOMODE_H
+#define _DEV_VIDEOMODE_H
+
+struct videomode {
+	int dot_clock;		/* Dot clock frequency in kHz. */
+	int hdisplay;
+	int hsync_start;
+	int hsync_end;
+	int htotal;
+	int vdisplay;
+	int vsync_start;
+	int vsync_end;
+	int vtotal;
+	int flags;		/* Video mode flags; see below. */
+	const char *name;
+	int hskew;
+};
+
+/*
+ * Video mode flags.
+ */
+
+#define VID_PHSYNC	0x0001
+#define VID_NHSYNC	0x0002
+#define VID_PVSYNC	0x0004
+#define VID_NVSYNC	0x0008
+#define VID_INTERLACE	0x0010
+#define VID_DBLSCAN	0x0020
+#define VID_CSYNC	0x0040
+#define VID_PCSYNC	0x0080
+#define VID_NCSYNC	0x0100
+#define VID_HSKEW	0x0200
+#define VID_BCAST	0x0400
+#define VID_PIXMUX	0x1000
+#define VID_DBLCLK	0x2000
+#define VID_CLKDIV2	0x4000
+
+extern const struct videomode videomode_list[];
+extern const int videomode_count;
+
+const struct videomode *pick_mode_by_dotclock(int, int, int);
+const struct videomode *pick_mode_by_ref(int, int, int);
+void sort_modes(struct videomode *, struct videomode **, int);
+
+#endif /* _DEV_VIDEOMODE_H */
-- 
2.20.1




More information about the devel mailing list