code:
/* $OpenBSD: omdisplay.c,v 1.5 2014/07/12 18:44:41 tedu Exp $ */
/*
 * Copyright (c) 2007 Dale Rahn <drahn@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/evcount.h>
#include <sys/conf.h>
#include <sys/uio.h>
#include <machine/bus.h>
#include <armv7/omap/omgpiovar.h>

#include <dev/cons.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/wscons/wscons_callbacks.h>

#include <dev/rasops/rasops.h>

#include "splash16.h"

#define OMDISPLAY_SIZE			0x1000
/* registers */
/* DSS */
#define DSS_REVISIONNUMBER		0x00
#define DSS_CONTROL			0x40
#define DSS_PSA_LCD_REG_1		0x50
#define DSS_PSA_LCD_REG_2		0x54
#define DSS_PSA_VIDEO_REG		0x58
#define DSS_STATUS			0x5C

/* DCR */
#define DISPC_REVISION			0x0000
#define DISPC_SYSCONFIG			0x0010
#define		DISPC_SYSCONFIG_AUTOIDLE		0x00000001
#define		DISPC_SYSCONFIG_SOFTRESET		0x00000002
#define		DISPC_SYSCONFIG_SIDLEMODE_FORCE		0x00000000
#define		DISPC_SYSCONFIG_SIDLEMODE_NONE		0x00000008
#define		DISPC_SYSCONFIG_SIDLEMODE_SMART		0x00000010
#define		DISPC_SYSCONFIG_MIDLEMODE_FORCE		0x00000000
#define		DISPC_SYSCONFIG_MIDLEMODE_NONE		0x00001000
#define		DISPC_SYSCONFIG_MIDLEMODE_SMART		0x00002000
#define DISPC_SYSSTATUS			0x0014
#define		DISPC_SYSTATUS_RESETDONE		0x00000001
#define DISPC_IRQSTATUS			0x0018
#define		DISPC_IRQSTATUS_FRAMEDONE		0x00000001
#define		DISPC_IRQSTATUS_VSYNC			0x00000002
#define		DISPC_IRQSTATUS_EVSYNCEVEN		0x00000004
#define		DISPC_IRQSTATUS_EVSYNCODD		0x00000008
#define		DISPC_IRQSTATUS_ACBIASCOUNT		0x00000010
#define		DISPC_IRQSTATUS_PROGLINENUM		0x00000020
#define		DISPC_IRQSTATUS_GFXFIFOUNDER		0x00000040
#define		DISPC_IRQSTATUS_GFXENDWINDOW		0x00000080
#define		DISPC_IRQSTATUS_PALGAMMA		0x00000100
#define		DISPC_IRQSTATUS_OCPERROR		0x00000200
#define		DISPC_IRQSTATUS_VID1FIFOUNDER		0x00000400
#define		DISPC_IRQSTATUS_VID1ENDWIND		0x00000800
#define		DISPC_IRQSTATUS_VID2FIFOUNDER		0x00001000
#define		DISPC_IRQSTATUS_VID2ENDWIND		0x00002000
#define		DISPC_IRQSTATUS_SYNCLOST		0x00004000
#define DISPC_IRQENABLE			0x001C
#define		DISPC_IRQENABLE_FRAMEDONE		0x00000001
#define		DISPC_IRQENABLE_VSYNC			0x00000002
#define		DISPC_IRQENABLE_EVSYNCEVEN		0x00000004
#define		DISPC_IRQENABLE_EVSYNCODD		0x00000008
#define		DISPC_IRQENABLE_ACBIASCOUNT		0x00000010
#define		DISPC_IRQENABLE_PROGLINENUM		0x00000020
#define		DISPC_IRQENABLE_GFXFIFOUNDER		0x00000040
#define		DISPC_IRQENABLE_GFXENDWINDOW		0x00000080
#define		DISPC_IRQENABLE_PALGAMMA		0x00000100
#define		DISPC_IRQENABLE_OCPERROR		0x00000200
#define		DISPC_IRQENABLE_VID1FIFOUNDER		0x00000400
#define		DISPC_IRQENABLE_VID1ENDWIND		0x00000800
#define		DISPC_IRQENABLE_VID2FIFOUNDER		0x00001000
#define		DISPC_IRQENABLE_VID2ENDWIND		0x00002000
#define		DISPC_IRQENABLE_SYNCLOST		0x00004000
#define DISPC_CONTROL			0x0040
#define 	DISPC_CONTROL_LCDENABLE			0x00000001
#define 	DISPC_CONTROL_DIGITALENABLE		0x00000002
#define 	DISPC_CONTROL_MONOCOLOR			0x00000004
#define 	DISPC_CONTROL_STNTFT			0x00000008
#define 	DISPC_CONTROL_M8B			0x00000010
#define 	DISPC_CONTROL_GOLCD			0x00000020
#define 	DISPC_CONTROL_GODIGITAL			0x00000040
#define 	DISPC_CONTROL_TFTDITHEREN		0x00000080
#define 	DISPC_CONTROL_TFTDATALINES_12		0x00000000
#define 	DISPC_CONTROL_TFTDATALINES_16		0x00000100
#define 	DISPC_CONTROL_TFTDATALINES_18		0x00000200
#define 	DISPC_CONTROL_TFTDATALINES_24		0x00000300
#define 	DISPC_CONTROL_SECURE			0x00000400
#define 	DISPC_CONTROL_RFBIMODE			0x00000800
#define 	DISPC_CONTROL_OVERLAYOPT		0x00001000
#define 	DISPC_CONTROL_GPIN0			0x00002000
#define 	DISPC_CONTROL_GPIN1			0x00004000
#define 	DISPC_CONTROL_GPOUT0			0x00008000
#define 	DISPC_CONTROL_GPOUT1			0x00010000
#define 	DISPC_CONTROL_HT			0x00070000
#define 	DISPC_CONTROL_HT_s(x)			((x) << 17)
#define 	DISPC_CONTROL_TDMENABLE			0x00100000
#define 	DISPC_CONTROL_TDMPARALLEL_8		0x00000000
#define 	DISPC_CONTROL_TDMPARALLEL_9		0x00200000
#define 	DISPC_CONTROL_TDMPARALLEL_12		0x00400000
#define 	DISPC_CONTROL_TDMPARALLEL_16		0x00600000
#define 	DISPC_CONTROL_TDMCYCLE_1		0x00000000
#define 	DISPC_CONTROL_TDMCYCLE_2		0x00800000
#define 	DISPC_CONTROL_TDMCYCLE_3		0x00000000
#define 	DISPC_CONTROL_TDMCYCLE_3_2		0x01800000
#define 	DISPC_CONTROL_TDMUNUSED_0		0x00000000
#define 	DISPC_CONTROL_TDMUNUSED_1		0x02000000
#define 	DISPC_CONTROL_TDMUNUSED_M		0x04000000
#define DISPC_CONFIG			0x0044
#define 	DISPC_CONFIG_PIXELGATED			0x00000001
#define 	DISPC_CONFIG_LOADMODE_PGE		0x00000000
#define 	DISPC_CONFIG_LOADMODE_PG		0x00000002
#define 	DISPC_CONFIG_LOADMODE_DATA		0x00000004
#define 	DISPC_CONFIG_LOADMODE_DATA_PG		0x00000006
#define 	DISPC_CONFIG_PALETTEGAMMA		0x00000008
#define 	DISPC_CONFIG_PIXELDATAGATED		0x00000010
#define 	DISPC_CONFIG_PIXELCLOCKGATED		0x00000020
#define 	DISPC_CONFIG_HSYNCGATED			0x00000040
#define 	DISPC_CONFIG_VSYNCGATED			0x00000080
#define 	DISPC_CONFIG_ACBIAGATED			0x00000100
#define 	DISPC_CONFIG_FUNCGATED			0x00000200
#define 	DISPC_CONFIG_TCKLCDEN			0x00000400
#define 	DISPC_CONFIG_TCKLCDSEL			0x00000800
#define 	DISPC_CONFIG_TCKDIGEN			0x00001000
#define 	DISPC_CONFIG_TCKDIGSEL			0x00002000
#define DISPC_CAPABLE			0x0048
#define DISPC_DEFAULT_COLOR0		0x004C
#define DISPC_DEFAULT_COLOR1		0x0050
#define DISPC_TRANS_COLOR0		0x0054
#define DISPC_TRANS_COLOR1		0x0058
#define DISPC_LINE_STATUS		0x005C
#define DISPC_LINE_NUMBER		0x0060
#define DISPC_TIMING_H			0x0064
#define		DISPC_TIMING_H_HSW_s(x)	((x) << 0)
#define		DISPC_TIMING_H_HFP_s(x)	((x) << 8)
#define		DISPC_TIMING_H_HBP_s(x)	((x) << 20)
#define DISPC_TIMING_V			0x0068
#define		DISPC_TIMING_V_VSW_s(x)	((x) << 0)
#define		DISPC_TIMING_V_VFP_s(x)	((x) << 8)
#define		DISPC_TIMING_V_VBP_s(x)	((x) << 20)
#define DISPC_POL_FREQ			0x006C
#define 	DISPC_POL_FREQ_ACB_s(x)	((x) << 0)
#define 	DISPC_POL_FREQ_ACBI_s(x)	((x) << 8)
#define 	DISPC_POL_FREQ_IVS	0x00001000
#define 	DISPC_POL_FREQ_IHS	0x00002000
#define 	DISPC_POL_FREQ_IPC	0x00004000
#define 	DISPC_POL_FREQ_IEO	0x00008000
#define 	DISPC_POL_FREQ_RF	0x00010000
#define 	DISPC_POL_FREQ_ONOFF	0x00020000
#define DISPC_DIVISOR			0x0070
#define		DISPC_DIVISOR_PCD_s(x)	((x) << 0)
#define		DISPC_DIVISOR_LCD_s(x)	((x) << 16)
#define DISPC_SIZE_DIG			0x0078
#define		DISPC_SIZE_DIG_PPL_s(x)	((x) << 0)
#define		DISPC_SIZE_DIG_LPP_s(x)	((x) << 16)
#define DISPC_SIZE_LCD			0x007C
#define		DISPC_SIZE_LCD_PPL_s(x)	((x) << 0)
#define		DISPC_SIZE_LCD_LPP_s(x)	((x) << 16)
#define DISPC_GFX_BA0			0x0080
#define DISPC_GFX_BA1			0x0084
#define DISPC_GFX_POSITION		0x0088
#define DISPC_GFX_SIZE			0x008C
#define		DISPC_GFX_SIZE_X_s(x)	((x) << 0)
#define		DISPC_GFX_SIZE_Y_s(x)	((x) << 16)
#define DISPC_GFX_ATTRIBUTES		0x00A0
#define		DISPC_GFX_ATTRIBUTES_GFXENABLE		0x001
#define		DISPC_GFX_ATTRIBUTES_GFXFMT_1		0x000
#define		DISPC_GFX_ATTRIBUTES_GFXFMT_2		0x002
#define		DISPC_GFX_ATTRIBUTES_GFXFMT_4		0x004
#define		DISPC_GFX_ATTRIBUTES_GFXFMT_8		0x006
#define		DISPC_GFX_ATTRIBUTES_GFXFMT_12		0x008
#define		DISPC_GFX_ATTRIBUTES_GFXFMT_16		0x00c
#define		DISPC_GFX_ATTRIBUTES_GFXFMT_24		0x010
#define		DISPC_GFX_ATTRIBUTES_GFXREPLICATE	0x020
#define		DISPC_GFX_ATTRIBUTES_BURST_4		0x000
#define		DISPC_GFX_ATTRIBUTES_BURST_8		0x040
#define		DISPC_GFX_ATTRIBUTES_BURST_16		0x080
#define		DISPC_GFX_ATTRIBUTES_GFXCHANNELOUT	0x100
#define		DISPC_GFX_ATTRIBUTES_NIBBLEMODE		0x200
#define		DISPC_GFX_ATTRIBUTES_ENDIAN		0x400
#define DISPC_GFX_FIFO_THRESHOLD	0x00A4
#define 	DISPC_GFX_FIFO_THRESHOLD_HIGH_SHIFT	16
#define 	DISPC_GFX_FIFO_THRESHOLD_LOW_SHIFT	0
#define DISPC_GFX_FIFO_SIZE_STATUS	0x00A8
#define DISPC_GFX_ROW_INC		0x00AC
#define DISPC_GFX_PIXEL_INC		0x00B0
#define DISPC_GFX_WINDOW_SKIP		0x00B4
#define DISPC_GFX_TABLE_BA		0x00B8
#define DISPC_VID1_BA0			0x00BC
#define DISPC_VID1_BA1			0x00C0
#define DISPC_VID1_POSITION		0x00C4
#define DISPC_VID1_SIZE			0x00C8
#define DISPC_VID1_ATTRIBUTES		0x00CC
#define DISPC_VID1_FIFO_THRESHOLD	0x00D0
#define DISPC_VID1_FIFO_SIZE_STATUS	0x00D4
#define DISPC_VID1_ROW_INC		0x00D8
#define DISPC_VID1_PIXEL_INC		0x00DC
#define DISPC_VID1_FIR			0x00E0
#define DISPC_VID1_PICTURE_SIZE		0x00E4
#define DISPC_VID1_ACCU0 		0x00E8
#define DISPC_VID1_ACCU1		0x00EC
#define DISPC_VID1_FIR_COEF_H0		0x00F0
#define DISPC_VID1_FIR_COEF_H1		0x00F8
#define DISPC_VID1_FIR_COEF_H2		0x0100
#define DISPC_VID1_FIR_COEF_H3		0x0108
#define DISPC_VID1_FIR_COEF_H4		0x0110
#define DISPC_VID1_FIR_COEF_H5		0x0118
#define DISPC_VID1_FIR_COEF_H6		0x0120
#define DISPC_VID1_FIR_COEF_H7		0x0128
#define DISPC_VID1_FIR_COEF_HV0		0x00F4
#define DISPC_VID1_FIR_COEF_HV1		0x00FC
#define DISPC_VID1_FIR_COEF_HV2		0x0104
#define DISPC_VID1_FIR_COEF_HV3		0x010C
#define DISPC_VID1_FIR_COEF_HV4		0x0114
#define DISPC_VID1_FIR_COEF_HV5		0x011C
#define DISPC_VID1_FIR_COEF_HV6		0x0124
#define DISPC_VID1_FIR_COEF_HV7		0x012C
#define DISPC_VID1_CONV_COEF0		0x0130
#define DISPC_VID1_CONV_COEF1		0x0134
#define DISPC_VID1_CONV_COEF2		0x0138
#define DISPC_VID1_CONV_COEF3		0x013C
#define DISPC_VID1_CONV_COEF4		0x0140
#define DISPC_VID2_BA0			0x014C
#define DISPC_VID2_BA1			0x0150
#define DISPC_VID2_POSITION		0x0154
#define DISPC_VID2_SIZE			0x0158
#define DISPC_VID2_ATTRIBUTES		0x015C
#define DISPC_VID2_FIFO_THRESHOLD	0x0160
#define DISPC_VID2_FIFO_SIZE_STATUS	0x0164
#define DISPC_VID2_ROW_INC		0x0168
#define DISPC_VID2_PIXEL_INC		0x016C
#define DISPC_VID2_FIR			0x0170
#define DISPC_VID2_PICTURE_SIZE		0x0174
#define DISPC_VID2_ACCU0		0x0178
#define DISPC_VID2_ACCU1		0x017C
#define DISPC_VID2_FIR_COEF_H0		0x0180
#define DISPC_VID2_FIR_COEF_H1		0x0188
#define DISPC_VID2_FIR_COEF_H2		0x0190
#define DISPC_VID2_FIR_COEF_H3		0x0198
#define DISPC_VID2_FIR_COEF_H4		0x01A0
#define DISPC_VID2_FIR_COEF_H5		0x01A8
#define DISPC_VID2_FIR_COEF_H6		0x01B0
#define DISPC_VID2_FIR_COEF_H7		0x01B8
#define DISPC_VID2_FIR_COEF_HV0		0x0184
#define DISPC_VID2_FIR_COEF_HV1		0x018C
#define DISPC_VID2_FIR_COEF_HV2		0x0194
#define DISPC_VID2_FIR_COEF_HV3		0x019C
#define DISPC_VID2_FIR_COEF_HV4		0x01A4
#define DISPC_VID2_FIR_COEF_HV5		0x01AC
#define DISPC_VID2_FIR_COEF_HV6		0x01B4
#define DISPC_VID2_FIR_COEF_HV7		0x01BC
#define DISPC_VID2_CONV_COEF0		0x01C0
#define DISPC_VID2_CONV_COEF1		0x01C4
#define DISPC_VID2_CONV_COEF2		0x01C8
#define DISPC_VID2_CONV_COEF3		0x01CC
#define DISPC_VID2_CONV_COEF4		0x01D0
#define DISPC_DATA_CYCLE1		0x01D4
#define DISPC_DATA_CYCLE2		0x01D8
#define DISPC_DATA_CYCLE3		0x01DC
#define DISPC_SIZE			0x0200

/* RFBI */
#define RFBI_REVISION		0x0000
#define RFBI_SYSCONFIG		0x0010
#define RFBI_SYSSTATUS		0x0014
#define RFBI_CONTROL		0x0040
#define RFBI_PIXEL_CNT		0x0044
#define RFBI_LINE_NUMBER	0x0048
#define RFBI_CMD		0x004C
#define RFBI_PARAM		0x0050
#define RFBI_DATA		0x0054
#define RFBI_READ		0x0058
#define RFBI_STATUS		0x005C
#define RFBI_CONFIG0		0x0060
#define RFBI_CONFIG1		0x0078
#define RFBI_ONOFF_TIME0	0x0064
#define RFBI_ONOFF_TIME1	0x007C
#define RFBI_CYCLE_TIME0	0x0068
#define RFBI_CYCLE_TIME1	0x0080
#define RFBI_DATA_CYCLE1_0	0x006C
#define RFBI_DATA_CYCLE1_1	0x0084
#define RFBI_DATA_CYCLE2_0	0x0070
#define RFBI_DATA_CYCLE2_1	0x0088
#define RFBI_DATA_CYCLE3_0	0x0074
#define RFBI_DATA_CYCLE3_1	0x008C
#define RFBI_VSYNC_WIDTH	0x0090
#define RFBI_HSYNC_WIDTH	0x0094

/* VENC1 */
#define REV_ID				0x0000
#define STATUS				0x0004
#define F_CONTROL			0x0008
#define VIDOUT_CTRL			0x0010
#define SYNC_CTRL			0x0014
#define LLEN				0x001C
#define FLENS				0x0020
#define HFLTR_CTRL			0x0024
#define CC_CARR_WSS_CARR		0x0028
#define C_PHASE				0x002C
#define GAIN_U				0x0030
#define GAIN_V				0x0034
#define GAIN_Y				0x0038
#define BLACK_LEVEL			0x003C
#define BLANK_LEVEL			0x0040
#define X_COLOR				0x0044
#define M_CONTROL			0x0048
#define BSTAMP_WSS_DATA			0x004C
#define S_CARR				0x0050
#define LINE21				0x0054
#define LN_SEL				0x0058
#define L21_WC_CTL			0x005C
#define HTRIGGER_VTRIGGER		0x0060
#define SAVID_EAVID			0x0064
#define FLEN_FAL			0x0068
#define LAL_PHASE_RESET			0x006C
#define HS_INT_START_STOP_X			0x0070
#define HS_EXT_START_STOP_X			0x0074
#define VS_INT_START_X				0x0078
#define VS_INT_STOP_X_VS_INT_START_Y		0x007C
#define VS_INT_STOP_Y_VS_EXT_START_X		0x0080
#define VS_EXT_STOP_X_VS_EXT_START_Y		0x0084
#define VS_EXT_STOP_Y				0x0088
#define AVID_START_STOP_X			0x0090
#define AVID_START_STOP_Y			0x0094
#define FID_INT_START_X_FID_INT_START_Y		0x00A0
#define FID_INT_OFFSET_Y_FID_EXT_START_X	0x00A4
#define FID_EXT_START_Y_FID_EXT_OFFSET_Y	0x00A8
#define TVDETGP_INT_START_STOP_X	0x00B0
#define TVDETGP_INT_START_STOP_Y	0x00B4
#define GEN_CTRL			0x00B8
#define DAC_TST_DAC_A			0x00C4
#define DAC_B_DAC_C			0x00C8

/* NO CONSOLE SUPPORT */

/* assumes 565 panel. */
struct omdisplay_panel_data {
	int width;
	int height;
	int horiz_sync_width;
	int horiz_front_porch;
	int horiz_back_porch;
	int vert_sync_width;
	int vert_front_porch;
	int vert_back_porch;
	int panel_flags;
	int sync;
	int depth;
#define PANEL_SYNC_H_ACTIVE_HIGH 1
#define PANEL_SYNC_V_ACTIVE_HIGH 2
	int linebytes;
};

#define PIXELDEPTH	16
#define PIXELWIDTH	2

struct omdisplay_panel_data	default_panel = {
	240,	/* Width */
	322,	/* Height */
	9, 9, 19, 	/* horiz sync, fp, bp */
	1, 2, 2,  	/* vert  sync, fp, bp */
	0, 	/* flags */
	0,	/* sync */
	PIXELDEPTH,
	240*PIXELWIDTH
};

struct omdisplay_screen {
	LIST_ENTRY(omdisplay_screen) link;

	/* Frame buffer */
	bus_dmamap_t dma;
	bus_dma_segment_t segs[1];
	int     nsegs;
	size_t  buf_size;
	size_t  map_size;
	void    *buf_va;
	int     depth;

	/* rasterop */
	struct rasops_info rinfo;
};

struct omdisplay_softc {
	struct device sc_dev;
	bus_space_tag_t sc_iot;
	bus_space_handle_t sc_dsioh;
	bus_space_handle_t sc_dcioh;
	bus_space_handle_t sc_rfbioh;
	bus_space_handle_t sc_venioh;
	bus_dma_tag_t 		sc_dma_tag;

	void *sc_ih;

	int	sc_nscreens;
	LIST_HEAD(,omdisplay_screen) sc_screens;

	struct omdisplay_panel_data	*sc_geometry;
	struct omdisplay_screen		*sc_active;
};

int omdisplay_match(struct device *parent, void *v, void *aux);
void omdisplay_attach(struct device *parent, struct device *self, void *args);
int omdisplay_activate(struct device *, int);
int omdisplay_ioctl(void *v, u_long cmd, caddr_t data, int flag,
    struct proc *p);
void omdisplay_burner(void *v, u_int on, u_int flags);
int omdisplay_show_screen(void *v, void *cookie, int waitok,
    void (*cb)(void *, int, int), void *cbarg);
int omdisplay_param(struct omdisplay_softc *sc, ulong cmd,
    struct wsdisplay_param *dp);
int omdisplay_max_brightness(void);
int omdisplay_get_brightness(void);
void omdisplay_set_brightness(int newval);
void omdisplay_set_brightness_internal(int newval);
int omdisplay_get_backlight(void);
void omdisplay_set_backlight(int on);
void omdisplay_blank(int blank);
void omdisplay_suspend(struct omdisplay_softc *sc);
void omdisplay_resume(struct omdisplay_softc *sc);
void omdisplay_initialize(struct omdisplay_softc *sc,
    struct omdisplay_panel_data *geom);
void omdisplay_setup_rasops(struct omdisplay_softc *sc,
    struct rasops_info *rinfo);
int omdisplay_alloc_screen(void *v, const struct wsscreen_descr *_type,
    void **cookiep, int *curxp, int *curyp, long *attrp);
int omdisplay_new_screen(struct omdisplay_softc *sc,
    struct omdisplay_screen *scr, int depth);
paddr_t omdisplay_mmap(void *v, off_t offset, int prot);
int omdisplay_load_font(void *, void *, struct wsdisplay_font *);
int omdisplay_list_font(void *, struct wsdisplay_font *);
void omdisplay_free_screen(void *v, void *cookie);
void omdisplay_start(struct omdisplay_softc *sc);
void omdisplay_stop(struct omdisplay_softc *sc);
int omdisplay_intr(void *v);
void omdisplay_dumpreg(struct omdisplay_softc *sc);

struct cfattach	omdisplay_ca = {
	sizeof (struct omdisplay_softc), omdisplay_match, omdisplay_attach,
	NULL, omdisplay_activate
};

struct cfdriver omdisplay_cd = {
	NULL, "omdisplay", DV_DULL
};

struct wsdisplay_accessops omdisplay_accessops = {
	.ioctl = omdisplay_ioctl,
	.mmap = omdisplay_mmap,
	.alloc_screen = omdisplay_alloc_screen,
	.free_screen = omdisplay_free_screen,
	.show_screen = omdisplay_show_screen,
	.load_font = omdisplay_load_font,
	.list_font = omdisplay_list_font,
	.burn_screen = omdisplay_burner

};

struct omdisplay_wsscreen_descr {
	struct wsscreen_descr  c;       /* standard descriptor */
	int depth;                      /* bits per pixel */
	int flags;                      /* rasops flags */
};

struct omdisplay_wsscreen_descr omdisplay_screen = {
	{
		"std"
	},
	16,			/* bits per pixel */
	0 /* rotate */
};

const struct wsscreen_descr *omdisplay_scr_descr[] = {
	&omdisplay_screen.c
};

/* XXX - what about flip phones with CLI */
const struct wsscreen_list omdisplay_screen_list = {
        sizeof omdisplay_scr_descr / sizeof omdisplay_scr_descr[0],
	omdisplay_scr_descr
};

int
omdisplay_match(struct device *parent, void *v, void *aux)
{
	/* XXX */
	return (1);
}

void
omdisplay_attach(struct device *parent, struct device *self, void *args)
{
	struct ahb_attach_args *aa = args;
	struct omdisplay_softc *sc = (struct omdisplay_softc *) self;
	struct wsemuldisplaydev_attach_args wsaa;

	sc->sc_iot = aa->aa_iot;

	if (bus_space_map(sc->sc_iot, aa->aa_addr, OMDISPLAY_SIZE, 0,
	    &sc->sc_dsioh))
		panic("omdisplay_attach: bus_space_map failed!");

	if (bus_space_subregion(sc->sc_iot, sc->sc_dsioh, 0x400, 1024,
	    &sc->sc_dcioh))
		panic("omdisplay_attach: bus_space_submap failed!");

	if (bus_space_subregion(sc->sc_iot, sc->sc_dsioh, 0x800, 1024,
	    &sc->sc_rfbioh))
		panic("omdisplay_attach: bus_space_submap failed!");

	if (bus_space_subregion(sc->sc_iot, sc->sc_dsioh, 0xc00, 1024,
	    &sc->sc_venioh))
		panic("omdisplay_attach: bus_space_submap failed!");

	sc->sc_nscreens = 0;
	LIST_INIT(&sc->sc_screens);

	sc->sc_dma_tag = aa->aa_dmat;

	sc->sc_ih = arm_intr_establish(aa->aa_intr, IPL_BIO /* XXX */,
	    omdisplay_intr, sc, sc->sc_dev.dv_xname);

	printf ("\n");

	sc->sc_geometry = &default_panel;

	{
		/* XXX - dummy? */
		struct rasops_info dummy;

		omdisplay_initialize(sc, sc->sc_geometry);

		/*
		 * Initialize a dummy rasops_info to compute fontsize and
		 * the screen size in chars.
		 */
		bzero(&dummy, sizeof(dummy));
		omdisplay_setup_rasops(sc, &dummy);
	}

	wsaa.console = 0;
	wsaa.scrdata = &omdisplay_screen_list;
	wsaa.accessops = &omdisplay_accessops;
	wsaa.accesscookie = sc;
	wsaa.defaultscreens = 0;

	(void)config_found(self, &wsaa, wsemuldisplaydevprint);

	/* backlight? */
}

int
omdisplay_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
{
	struct omdisplay_softc *sc = v;
	struct wsdisplay_fbinfo *wsdisp_info;
	struct omdisplay_screen *scr = sc->sc_active;
	int res = EINVAL;

	switch (cmd) {
	case WSDISPLAYIO_GETPARAM:
	case WSDISPLAYIO_SETPARAM:
		res = omdisplay_param(sc, cmd, (struct wsdisplay_param *)data);
		break;
	case WSDISPLAYIO_GTYPE:
		*(u_int *)data = WSDISPLAY_TYPE_PXALCD; /* XXX */
		break;

	case WSDISPLAYIO_GINFO:
		wsdisp_info = (struct wsdisplay_fbinfo *)data;

		wsdisp_info->height = sc->sc_geometry->height;
		wsdisp_info->width = sc->sc_geometry->width;
		wsdisp_info->depth = 16; /* XXX */
		wsdisp_info->cmsize = 0;
		break;

	case WSDISPLAYIO_GETCMAP:
	case WSDISPLAYIO_PUTCMAP:
		return EINVAL;  /* XXX Colormap */

	case WSDISPLAYIO_SVIDEO:
	case WSDISPLAYIO_GVIDEO:
		break;

	case WSDISPLAYIO_GCURPOS:
	case WSDISPLAYIO_SCURPOS:
	case WSDISPLAYIO_GCURMAX:
	case WSDISPLAYIO_GCURSOR:
	case WSDISPLAYIO_SCURSOR:
	default:
		return -1;      /* not implemented */

	case WSDISPLAYIO_LINEBYTES:
		if (scr != NULL)
			*(u_int *)data = scr->rinfo.ri_stride;
		else
			*(u_int *)data = 0;
		break;

	}

	if (res == EINVAL)
		res = omdisplay_ioctl(v, cmd, data, flag, p);

	return res;
}

void
omdisplay_burner(void *v, u_int on, u_int flags)
{

        omdisplay_set_brightness(on ? omdisplay_get_brightness() : 0);

	/* GPIO controls for appsliver */
	if (on) {
		omgpio_set_bit(93);			/* 1 enable backlight */
		omgpio_set_dir(93, OMGPIO_DIR_OUT);
		omgpio_clear_bit(26);			/* 0 enable LCD */
		omgpio_set_dir(26, OMGPIO_DIR_OUT);
	} else {
		omgpio_clear_bit(93);			/* 0 disable backlt */
		omgpio_set_dir(93, OMGPIO_DIR_OUT);
		omgpio_set_bit(26);			/* 1 disable LCD */
		omgpio_set_dir(26, OMGPIO_DIR_OUT);
	}
}

int
omdisplay_show_screen(void *v, void *cookie, int waitok,
    void (*cb)(void *, int, int), void *cbarg)
{
	struct omdisplay_softc *sc = v;
	struct rasops_info *ri = cookie;
	struct omdisplay_screen *scr = ri->ri_hw, *old;

	old = sc->sc_active;
	if (old == scr)
		return 0;

	if (old != NULL)
		; /* Stop old screen */

	sc->sc_active = scr;
	omdisplay_initialize(sc, sc->sc_geometry);

	/* Turn on LCD */
	omdisplay_burner(v, 1, 0);

	return (0);
}

/*
 * wsdisplay I/O controls
 */
int
omdisplay_param(struct omdisplay_softc *sc, ulong cmd,
    struct wsdisplay_param *dp)
{
	int res = EINVAL;

	switch (dp->param) {
	case WSDISPLAYIO_PARAM_BACKLIGHT:
		if (cmd == WSDISPLAYIO_GETPARAM) {
			dp->min = 0;
			dp->max = 1;
			dp->curval = omdisplay_get_backlight();
			res = 0;
		} else if (cmd == WSDISPLAYIO_SETPARAM) {
/* XXX */
//			omdisplay_set_backlight(dp->curval);
			res = 0;
		}
		break;

	case WSDISPLAYIO_PARAM_CONTRAST:
		/* unsupported */
		res = ENOTTY;
		break;

	case WSDISPLAYIO_PARAM_BRIGHTNESS:
		if (cmd == WSDISPLAYIO_GETPARAM) {
			dp->min = 1;
			dp->max = omdisplay_max_brightness();
			dp->curval = omdisplay_get_brightness();
			res = 0;
		} else if (cmd == WSDISPLAYIO_SETPARAM) {
/* XXX */
//			omdisplay_set_brightness(dp->curval);
			res = 0;
		}
		break;
	}

	return res;
}

/*
 * LCD backlight
 */

static  int lcdbrightnesscurval = 1;
static  int lcdislit = 1;
static  int lcdisblank = 0;

struct lcd_backlight {
	int	duty;		/* LZ9JG18 DAC value */
	int	cont;		/* BACKLIGHT_CONT signal */
	int	on;		/* BACKLIGHT_ON signal */
};

const struct lcd_backlight lcd_bl[] = {
	{ 0x00, 0, 0 },		/* 0:     Off */
	{ 0x00, 0, 1 },		/* 1:      0% */
	{ 0x01, 0, 1 },		/* 2:     20% */
	{ 0x07, 0, 1 },		/* 3:     40% */
	{ 0x01, 1, 1 },		/* 4:     60% */
	{ 0x07, 1, 1 },		/* 5:     80% */
	{ 0x11, 1, 1 },		/* 6:    100% */
	{ -1, -1, -1 }		/* 7: Invalid */
};
#define CURRENT_BACKLIGHT lcd_bl

int
omdisplay_max_brightness(void)
{
	int i;

	for (i = 0; CURRENT_BACKLIGHT[i].duty != -1; i++)
		;
	return i - 1;
}

int
omdisplay_get_brightness(void)
{

	return lcdbrightnesscurval;
}

void
omdisplay_set_brightness(int newval)
{
	int max;

	max = omdisplay_max_brightness();
	if (newval < 0)
		newval = 0;
	else if (newval > max)
		newval = max;

	if (omdisplay_get_backlight() && !lcdisblank)
		omdisplay_set_brightness_internal(newval);

	if (newval > 0)
		lcdbrightnesscurval = newval;
}

void
omdisplay_set_brightness_internal(int newval)
{
	static int curval = 1;
	int i;

	/*
	 * It appears that the C3000 backlight can draw too much power if we
	 * switch it from a low to a high brightness.  Increasing brightness
	 * in steps avoids this issue.
	 */
	if (newval > curval) {
		for (i = curval + 1; i <= newval; i++) {
/* atlas controls */
			/* CURRENT_BACKLIGHT[newval].duty); */
		}
	} else {
/* atlas controls */
		/* CURRENT_BACKLIGHT[newval].duty); */
	}

	curval = newval;
}

int
omdisplay_get_backlight(void)
{

	return lcdislit;
}

void
omdisplay_set_backlight(int on)
{

	if (!on) {
		omdisplay_set_brightness(0);
		lcdislit = 0;
	} else {
		lcdislit = 1;
		omdisplay_set_brightness(omdisplay_get_brightness());
	}
}

void
omdisplay_blank(int blank)
{

	if (blank) {
		omdisplay_set_brightness(0);
		lcdisblank = 1;
	} else {
		lcdisblank = 0;
		omdisplay_set_brightness(omdisplay_get_brightness());
	}
}

void
omdisplay_suspend(struct omdisplay_softc *sc)
{
	if (sc->sc_active != NULL) {
		omdisplay_stop(sc);
		/* XXX disable clocks */
	}
}

void
omdisplay_resume(struct omdisplay_softc *sc)
{
	if (sc->sc_active != NULL) {
		/* XXX - clocks? */
		omdisplay_initialize(sc, sc->sc_geometry);
		omdisplay_start(sc);
	}
}

void
omdisplay_activate(struct device *self, int act)
{
	struct omdisplay_softc *sc = (struct omdisplay_softc *)self;

	switch (act) {
	case DVACT_SUSPEND:
		omdisplay_set_brightness(0);
		omdisplay_suspend(sc);
		break;
	case DVACT_RESUME:
		omdisplay_resume(sc);
		omdisplay_set_brightness(omdisplay_get_brightness());
		break;
	}
	return 0;
}

void
omdisplay_initialize(struct omdisplay_softc *sc,
    struct omdisplay_panel_data *geom)
{
	struct omdisplay_screen *scr;
	u_int32_t reg;
	u_int32_t mode;
#if 0
	int den, nom; /* pixel rate */
#endif

	reg = bus_space_read_4(sc->sc_iot, sc->sc_dcioh, DISPC_CONTROL);

	scr = sc->sc_active;

	if (reg & (DISPC_CONTROL_LCDENABLE|DISPC_CONTROL_DIGITALENABLE)) {
		omdisplay_stop(sc);
	}

	/* XXX - enable clocks */

	/* disable all interrupts */
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_IRQENABLE, 0);

	/* GPIOs ? */

	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_CONFIG,
	    DISPC_CONFIG_LOADMODE_PG|DISPC_CONFIG_LOADMODE_DATA);

	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DEFAULT_COLOR0, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DEFAULT_COLOR1, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_TRANS_COLOR0, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_TRANS_COLOR1, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_LINE_NUMBER, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DATA_CYCLE1, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DATA_CYCLE2, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DATA_CYCLE3, 0);

	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_SYSCONFIG,
	    DISPC_SYSCONFIG_SIDLEMODE_NONE|
	    DISPC_SYSCONFIG_MIDLEMODE_NONE);

#if 0
	if (geom->panel_flags & LCDPANEL_TDM) {
		nom = tdmflags >>8 & 0x3;
		den = tdmflags & 0x3;
	} else {
		nom = 1;
		den = 1;
	}
	hsync = geom->width*den/nom + geom->horiz_sync_width +
	    geom->horiz_front_porch + geom->horiz_back_porch;
#endif

	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_TIMING_H,
	    DISPC_TIMING_H_HSW_s(geom->horiz_sync_width) |
	    DISPC_TIMING_H_HFP_s(geom->horiz_front_porch) |
	    DISPC_TIMING_H_HBP_s(geom->horiz_back_porch));
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_TIMING_V,
	    DISPC_TIMING_V_VSW_s(geom->vert_sync_width) |
	    DISPC_TIMING_V_VFP_s(geom->vert_front_porch) |
	    DISPC_TIMING_V_VBP_s(geom->vert_back_porch));

	reg = 0;
	if (geom->sync & PANEL_SYNC_H_ACTIVE_HIGH)
		reg |= DISPC_POL_FREQ_IHS;
	if (geom->sync & PANEL_SYNC_V_ACTIVE_HIGH)
		reg |= DISPC_POL_FREQ_IVS;
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_POL_FREQ, reg);

	/* clkdiv = pixclock/period; */
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_SIZE_LCD,
	    DISPC_SIZE_LCD_PPL_s(geom->width-1) |
	    DISPC_SIZE_LCD_LPP_s(geom->height-1));
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_SIZE_DIG,
	    DISPC_SIZE_LCD_PPL_s(geom->width-1) |
	    DISPC_SIZE_LCD_LPP_s(geom->height-1));

	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_SIZE,
		DISPC_GFX_SIZE_X_s(geom->width-1) |
		DISPC_GFX_SIZE_Y_s(geom->height-1));

	/* XXX!!! */
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DIVISOR,
		DISPC_DIVISOR_LCD_s(1) | DISPC_DIVISOR_PCD_s(6));

	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_BA0,
	    scr->segs[0].ds_addr);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_BA1,
	    scr->segs[0].ds_addr);

	/* non-rotated */
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_PIXEL_INC, 1);

	/* XXX 24bit -> 32 pixels */
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_ROW_INC,
	    1 + scr->rinfo.ri_stride -
	    (scr->rinfo.ri_width * scr->rinfo.ri_depth / 8));

	switch (geom->depth) {
	case 1:
		mode = DISPC_GFX_ATTRIBUTES_GFXFMT_1;
		break;
	case 2:
		mode = DISPC_GFX_ATTRIBUTES_GFXFMT_2;
		break;
	case 4:
		mode = DISPC_GFX_ATTRIBUTES_GFXFMT_4;
		break;
	case 8:
		mode = DISPC_GFX_ATTRIBUTES_GFXFMT_8;
		break;
	case 12:
		mode = DISPC_GFX_ATTRIBUTES_GFXFMT_12;
		break;
	case 16:
		mode = DISPC_GFX_ATTRIBUTES_GFXFMT_16;
		break;
	case 24:
		mode = DISPC_GFX_ATTRIBUTES_GFXFMT_24;
		break;
	default:
		panic("invalid depth %d", geom->depth);
	}
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_ATTRIBUTES,
	    DISPC_GFX_ATTRIBUTES_GFXENABLE | mode |
	    DISPC_GFX_ATTRIBUTES_BURST_8);

	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_POSITION, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_WINDOW_SKIP, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_FIFO_THRESHOLD,
	    (0xfc << DISPC_GFX_FIFO_THRESHOLD_HIGH_SHIFT) |
	    (0xc0 << DISPC_GFX_FIFO_THRESHOLD_LOW_SHIFT));

	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_ROW_INC, 1);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_PIXEL_INC, 1);

	/* DISPC_CONFIG_PALETTEGAMMA not enabled */
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_TABLE_BA,
	    scr->segs[0].ds_addr);

	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_BA0, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_BA1, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_SIZE, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_ATTRIBUTES, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIFO_THRESHOLD,
	    0xc00040); /* XXX */
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIFO_SIZE_STATUS,
	    0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_ROW_INC, 1);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_PIXEL_INC, 1);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_PICTURE_SIZE, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_ACCU0, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_ACCU1, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H0, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H1, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H2, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H3, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H4, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H5, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H6, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H7, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV0, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV1, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV2, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV3, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV4, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV5, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV6, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV7, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_CONV_COEF0, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_CONV_COEF1, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_CONV_COEF2, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_CONV_COEF3, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_CONV_COEF4, 0);

	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_BA0, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_BA1, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_SIZE, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_ATTRIBUTES, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIFO_THRESHOLD,
	    0xc00040); /* XXX */
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIFO_SIZE_STATUS,
	    0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_ROW_INC, 1);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_PIXEL_INC, 1);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_PICTURE_SIZE, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_ACCU0, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_ACCU1, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H0, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H1, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H2, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H3, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H4, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H5, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H6, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H7, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV0, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV1, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV2, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV3, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV4, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV5, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV6, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV7, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_CONV_COEF0, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_CONV_COEF1, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_CONV_COEF2, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_CONV_COEF3, 0);
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_CONV_COEF4, 0);

	omdisplay_start(sc);
}

void
omdisplay_setup_rasops(struct omdisplay_softc *sc, struct rasops_info *rinfo)
{
	struct omdisplay_wsscreen_descr *descr;
	struct omdisplay_panel_data *geom;

	descr = &omdisplay_screen;
	geom = sc->sc_geometry;

	rinfo->ri_flg = descr->flags;
	rinfo->ri_depth = descr->depth;
	rinfo->ri_width = geom->width;
	rinfo->ri_height = geom->height;
	rinfo->ri_stride = geom->linebytes;

	/* pixel position */
	if (descr->depth == 16) {
		rinfo->ri_rnum = 5;
		rinfo->ri_rpos = 11;
		rinfo->ri_gnum = 6;
		rinfo->ri_gpos = 5;
		rinfo->ri_bnum = 5;
		rinfo->ri_bpos = 0;
	}

	if (descr->c.nrows == 0) {
		/* get rasops to compute screen size the first time */
		rasops_init(rinfo, 100, 100);
	} else {
		if (descr->flags != 0) /* rotate */
			rasops_init(rinfo, descr->c.ncols, descr->c.nrows);
		else
			rasops_init(rinfo, descr->c.nrows, descr->c.ncols);
	}

	descr->c.nrows = rinfo->ri_rows;
	descr->c.ncols = rinfo->ri_cols;
	descr->c.capabilities = rinfo->ri_caps;
	descr->c.textops = &rinfo->ri_ops;

}

int
omdisplay_alloc_screen(void *v, const struct wsscreen_descr *_type,
    void **cookiep, int *curxp, int *curyp, long *attrp)
{
	struct omdisplay_softc *sc = v;
	struct omdisplay_screen *scr;
	struct rasops_info *ri;
	struct omdisplay_wsscreen_descr *type =
	    (struct omdisplay_wsscreen_descr *)_type;
	int error;

	scr = malloc(sizeof *scr, M_DEVBUF, (cold ? M_NOWAIT : M_WAITOK));
	if (scr == NULL)
		return (ENOMEM);

	error = omdisplay_new_screen(sc, scr, type->depth);
	if (error != 0) {
		free(scr, M_DEVBUF, 0);
		return (error);
	}

	/*
	 * initialize raster operation for this screen.
	 */
	ri = &scr->rinfo;
	ri->ri_hw = (void *)scr;
	ri->ri_bits = scr->buf_va;
	omdisplay_setup_rasops(sc, ri);

	/* assumes 16 bpp */
	ri->ri_ops.alloc_attr(ri, 0, 0, 0, attrp);

	*cookiep = ri;
	*curxp = 0;
	*curyp = 0;

	return 0;
}

/*
 * Create and initialize a new screen buffer.
 */
int
omdisplay_new_screen(struct omdisplay_softc *sc,
    struct omdisplay_screen *scr, int depth)
{
	bus_space_tag_t iot;
	bus_space_handle_t ioh;
	bus_dma_tag_t dma_tag;
	struct omdisplay_panel_data *geometry;
	int width, height;
	bus_size_t size;
	int error, palette_size;
	int busdma_flag = (cold ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);

	if (sc != NULL) {
		iot = sc->sc_iot;
		ioh = sc->sc_dcioh;
		dma_tag = sc->sc_dma_tag;
		geometry = sc->sc_geometry;
	} else {
		/* We are creating the console screen. */
#if 0
		iot = omdisplay_console.iot;
		ioh = omdisplay_console.ioh;
		dma_tag = omdisplay_console.dma_tag;
		geometry = omdisplay_console.geometry;
#endif
	}

	width = geometry->width;
	height = geometry->height;
	palette_size = 0;

	switch (depth) {
	case 1:
	case 2:
	case 4:
	case 8:
		palette_size = (1 << depth) * sizeof (uint16_t);
		/* FALLTHROUGH */
	case 16:
	case 24:
		size = geometry->height * geometry->linebytes;
		break;
	default:
		printf("%s: Unknown depth (%d)\n",
		    sc != NULL ? sc->sc_dev.dv_xname : "console", depth);
		return (EINVAL);
	}

	bzero(scr, sizeof *scr);

	scr->nsegs = 0;
	scr->depth = depth;
	scr->buf_size = size;
	scr->buf_va = NULL;
	size = roundup(size, 16);
#if 0
	 + 3 * sizeof (struct lcd_dma_descriptor)
	    + palette_size;
#endif

	error = bus_dmamem_alloc(dma_tag, size, 0x100000, 0,
	    scr->segs, 1, &(scr->nsegs), busdma_flag);
	if (error != 0 || scr->nsegs != 1) {
		/* XXX: Actually we can handle nsegs > 1 case by means
		   of multiple DMA descriptors for a panel.  It would
		    make code here a bit hairy */
		if (error == 0)
			error = E2BIG;
		goto bad;
	}

	error = bus_dmamem_map(dma_tag, scr->segs, scr->nsegs,
	    size, (caddr_t *)&(scr->buf_va), busdma_flag | BUS_DMA_COHERENT);
	if (error != 0)
		goto bad;

	memset(scr->buf_va, 0, scr->buf_size);
	bcopy(splash, scr->buf_va,
	    sizeof (splash) > scr->buf_size ? scr->buf_size : sizeof (splash));

	/* map memory for DMA */
	if (bus_dmamap_create(dma_tag, 1024 * 1024 * 2, 1,
	    1024 * 1024 * 2, 0,  busdma_flag, &scr->dma))
		goto bad;
	error = bus_dmamap_load(dma_tag, scr->dma,
	    scr->buf_va, size, NULL, busdma_flag);
	if (error != 0) {
		goto bad;
	}

	scr->map_size = size;		/* used when unmap this. */

	if (sc != NULL) {
		LIST_INSERT_HEAD(&(sc->sc_screens), scr, link);
		sc->sc_nscreens++;
	}

	omdisplay_initialize(sc, geometry);

	return (0);

 bad:
	if (scr->buf_va)
		bus_dmamem_unmap(dma_tag, scr->buf_va, size);
	if (scr->nsegs)
		bus_dmamem_free(dma_tag, scr->segs, scr->nsegs);
	return (error);
}
paddr_t
omdisplay_mmap(void *v, off_t offset, int prot)
{
	struct omdisplay_softc *sc = v;
	struct omdisplay_screen *screen = sc->sc_active;  /* ??? */

	if ((offset & PAGE_MASK) != 0)
		return (-1);

	if (screen == NULL)
		return (-1);

	if (offset < 0 ||
	    offset >= screen->rinfo.ri_stride * screen->rinfo.ri_height)
		return (-1);

	return (bus_dmamem_mmap(sc->sc_dma_tag, screen->segs, screen->nsegs,
	    offset, prot, BUS_DMA_WAITOK | BUS_DMA_COHERENT));
}

void
omdisplay_free_screen(void *v, void *cookie)
{
	struct omdisplay_softc *sc = v;
	struct rasops_info *ri = cookie;
	struct omdisplay_screen *scr = ri->ri_hw;

	LIST_REMOVE(scr, link);
	sc->sc_nscreens--;
	if (scr == sc->sc_active) {
		/* at first, we need to stop LCD DMA */
		sc->sc_active = NULL;

#ifdef DEBUG
		printf("lcd_free on active screen\n");
#endif

		omdisplay_stop(sc);
	}

	if (scr->buf_va)
		bus_dmamem_unmap(sc->sc_dma_tag, scr->buf_va, scr->map_size);

	if (scr->nsegs > 0)
		bus_dmamem_free(sc->sc_dma_tag, scr->segs, scr->nsegs);

	free(scr, M_DEVBUF, 0);
}

int
omdisplay_load_font(void *v, void *emulcookie, struct wsdisplay_font *font)
{
	struct omdisplay_softc *sc = v;
	struct omdisplay_screen *scr = sc->sc_active;

	if (scr == NULL)
		return ENXIO;

	return rasops_load_font(scr->rinfo, emulcookie, font);
}

int
omdisplay_list_font(void *v, struct wsdisplay_font *font)
{
	struct omdisplay_softc *sc = v;
	struct omdisplay_screen *scr = sc->sc_active;

	if (scr == NULL)
		return ENXIO;

	return rasops_list_font(scr->rinfo, font);
}

void
omdisplay_start(struct omdisplay_softc *sc)
{
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_CONTROL,
	    DISPC_CONTROL_GPOUT0 | DISPC_CONTROL_GPOUT1 |
	    DISPC_CONTROL_TFTDATALINES_18 /*XXX 18? */ |
	    DISPC_CONTROL_STNTFT |
	    DISPC_CONTROL_GOLCD |
	    DISPC_CONTROL_LCDENABLE);
}

void
omdisplay_stop(struct omdisplay_softc *sc)
{
	bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_CONTROL,
	    bus_space_read_4(sc->sc_iot, sc->sc_dcioh, DISPC_CONTROL) &
	    ~(DISPC_CONTROL_DIGITALENABLE|DISPC_CONTROL_LCDENABLE));

	/* XXX - wait for end of frame? */
}

int
omdisplay_intr(void *v)
{
	/* XXX */
	return 1;
}


code:
/*	$OpenBSD: omdog.c,v 1.5 2014/12/10 12:27:56 mikeb Exp $	*/
/*
 * Copyright (c) 2013 Federico G. Schwindt <fgsch@openbsd.org>
 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/evcount.h>
#include <sys/socket.h>
#include <sys/timeout.h>
#include <machine/intr.h>
#include <machine/bus.h>
#include <armv7/armv7/armv7var.h>

#define WIDR		0x00			/* Identification Register */
#define WCLR		0x24			/* Control Register */
#define  WCLR_PRE		(1 << 5)
#define  WCLR_PTV		(0 << 2)
#define WCRR		0x28			/* Counter Register */
#define WLDR		0x2c			/* Load Register */
#define WTGR		0x30			/* Trigger Register */
#define WWPS		0x34			/* Write Posting Bits Reg. */
#define  WWPS_WSPR		(1 << 4)
#define  WWPS_WTGR		(1 << 3)
#define  WWPS_WLDR		(1 << 2)
#define  WWPS_WCRR		(1 << 1)
#define  WWPS_WCLR		(1 << 0)
#define WSPR		0x48			/* Start/Stop Register */

#define OMDOG_VAL(secs)	(0xffffffff - ((secs) * (32768 / (1 << 0))) + 1)

struct omdog_softc {
	struct device		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;

	int			sc_period;
};

struct omdog_softc *omdog_sc;

void	omdog_attach(struct device *, struct device *, void *);
int	omdog_activate(struct device *, int);
void	omdog_start(struct omdog_softc *);
void	omdog_stop(struct omdog_softc *);
void	omdog_sync(struct omdog_softc *);
int	omdog_cb(void *, int);
void	omdog_reset(void);

struct cfattach	omdog_ca = {
	sizeof (struct omdog_softc), NULL, omdog_attach, NULL, omdog_activate
};

struct cfdriver omdog_cd = {
	NULL, "omdog", DV_DULL
};

void
omdog_attach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	struct omdog_softc *sc = (struct omdog_softc *) self;
	u_int32_t rev;

	sc->sc_iot = aa->aa_iot;
	if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
	    aa->aa_dev->mem[0].size, 0, &sc->sc_ioh))
		panic("%s: bus_space_map failed!", __func__);

	rev = bus_space_read_4(sc->sc_iot, sc->sc_ioh, WIDR);

	printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);
	omdog_sc = sc;

	omdog_stop(sc);

#ifndef SMALL_KERNEL
	wdog_register(omdog_cb, sc);
#endif
}

int
omdog_activate(struct device *self, int act)
{
	switch (act) {
	case DVACT_POWERDOWN:
#ifndef SMALL_KERNEL
		wdog_shutdown(self);
#endif
		break;
	}

	return (0);
}

void
omdog_start(struct omdog_softc *sc)
{
	/* Write the enable sequence data BBBBh followed by 4444h */
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xbbbb);
	omdog_sync(sc);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x4444);
	omdog_sync(sc);
}

void
omdog_stop(struct omdog_softc *sc)
{
	/* Write the disable sequence data AAAAh followed by 5555h */
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0xaaaa);
	omdog_sync(sc);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, WSPR, 0x5555);
	omdog_sync(sc);
}

void
omdog_sync(struct omdog_softc *sc)
{
	while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, WWPS) &
	    (WWPS_WSPR|WWPS_WTGR|WWPS_WLDR|WWPS_WCRR|WWPS_WCLR))
		delay(10);
}

int
omdog_cb(void *self, int period)
{
	struct omdog_softc *sc = self;

	if (sc->sc_period != 0 && sc->sc_period != period)
		omdog_stop(sc);

	if (period != 0) {
		if (sc->sc_period != period) {
			/* Set the prescaler */
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, WCLR,
			    (WCLR_PRE|WCLR_PTV));

			/* Set the reload counter */
			bus_space_write_4(sc->sc_iot, sc->sc_ioh, WLDR,
			    OMDOG_VAL(period));
		}

		omdog_sync(sc);

		/* Trigger the reload */
		bus_space_write_4(sc->sc_iot, sc->sc_ioh, WTGR,
		    ~bus_space_read_4(sc->sc_iot, sc->sc_ioh, WTGR));

		if (sc->sc_period != period)
			omdog_start(sc);
	}

	sc->sc_period = period;

	return (period);
}

void
omdog_reset(void)
{
	if (omdog_sc == NULL)
		return;

	if (omdog_sc->sc_period != 0)
		omdog_stop(omdog_sc);

	bus_space_write_4(omdog_sc->sc_iot, omdog_sc->sc_ioh, WCRR,
	    0xffffff80);

	omdog_start(omdog_sc);

	delay(100000);
}

license: unknown


code:
/*	$OpenBSD: omehci.c,v 1.3 2014/05/19 13:11:31 mpi Exp $ */

/*
 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*-
 * Copyright (c) 2011
 *	Ben Gray <ben.r.gray@gmail.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:
 * 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 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 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/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/rwlock.h>
#include <sys/timeout.h>

#include <machine/intr.h>
#include <machine/bus.h>

#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usb_mem.h>

#include <armv7/armv7/armv7var.h>
#include <armv7/omap/prcmvar.h>
#include <armv7/omap/omgpiovar.h>
#include <armv7/omap/omehcivar.h>

#include <dev/usb/ehcireg.h>
#include <dev/usb/ehcivar.h>

void	omehci_attach(struct device *, struct device *, void *);
int	omehci_detach(struct device *, int);
int	omehci_activate(struct device *, int);

struct omehci_softc {
	struct ehci_softc	 sc;
	void			*sc_ih;
	bus_space_handle_t	 uhh_ioh;
	bus_space_handle_t	 tll_ioh;

	uint32_t		 ehci_rev;
	uint32_t		 tll_avail;

	uint32_t		 port_mode[OMAP_HS_USB_PORTS];
	uint32_t		 phy_reset[OMAP_HS_USB_PORTS];
	uint32_t		 reset_gpio_pin[OMAP_HS_USB_PORTS];

	void			 (*early_init)(void);
};

int omehci_init(struct omehci_softc *);
void omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port);
void omehci_enable(struct omehci_softc *);
void omehci_disable(struct omehci_softc *);
void omehci_utmi_init(struct omehci_softc *sc, unsigned int en_mask);
void misc_setup(struct omehci_softc *sc);
void omehci_phy_reset(uint32_t on, uint32_t _delay);
void omehci_uhh_init(struct omehci_softc *sc);
void omehci_v4_early_init(void);

struct cfattach omehci_ca = {
	sizeof (struct omehci_softc), NULL, omehci_attach,
	omehci_detach, omehci_activate
};

void
omehci_attach(struct device *parent, struct device *self, void *aux)
{
	struct omehci_softc	*sc = (struct omehci_softc *)self;
	struct armv7_attach_args *aa = aux;
	usbd_status		 r;
	char			*devname = sc->sc.sc_bus.bdev.dv_xname;
	uint32_t		 i;

	sc->sc.iot = aa->aa_iot;
	sc->sc.sc_bus.dmatag = aa->aa_dmat;
	sc->sc.sc_size = aa->aa_dev->mem[0].size;

	/* set defaults */
	for (i = 0; i < 3; i++) {
		sc->phy_reset[i] = 0;
		sc->port_mode[i] = EHCI_HCD_OMAP_MODE_UNKNOWN;
		sc->reset_gpio_pin[i] = -1;
	}

	switch (board_id)
	{
	case BOARD_ID_OMAP4_PANDA:
		sc->tll_avail = 0;
		sc->port_mode[0] = EHCI_HCD_OMAP_MODE_PHY;
		sc->early_init = omehci_v4_early_init;
		break;
	default:
		break;
	}

	/* Map I/O space */
	if (bus_space_map(sc->sc.iot, aa->aa_dev->mem[0].addr,
		aa->aa_dev->mem[0].size, 0, &sc->sc.ioh)) {
		printf(": cannot map mem space\n");
		goto out;
	}

	if (bus_space_map(sc->sc.iot, aa->aa_dev->mem[1].addr,
		aa->aa_dev->mem[1].size, 0, &sc->uhh_ioh)) {
		printf(": cannot map mem space\n");
		goto mem0;
	}

	if (sc->tll_avail &&
	    bus_space_map(sc->sc.iot, aa->aa_dev->mem[2].addr,
		aa->aa_dev->mem[2].size, 0, &sc->tll_ioh)) {
		printf(": cannot map mem space\n");
		goto mem1;
	}

	printf("\n");

	if (sc->early_init)
		sc->early_init();

	if (omehci_init(sc))
		return;

	/* Disable interrupts, so we don't get any spurious ones. */
	sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH);
	EOWRITE2(&sc->sc, EHCI_USBINTR, 0);

	sc->sc_ih = arm_intr_establish(aa->aa_dev->irq[0], IPL_USB,
	    ehci_intr, &sc->sc, devname);
	if (sc->sc_ih == NULL) {
		printf(": unable to establish interrupt\n");
		printf("XXX - disable ehci and prcm");
		goto mem2;
	}

	strlcpy(sc->sc.sc_vendor, "TI OMAP", sizeof(sc->sc.sc_vendor));
	r = ehci_init(&sc->sc);
	if (r != USBD_NORMAL_COMPLETION) {
		printf("%s: init failed, error=%d\n", devname, r);
		printf("XXX - disable ehci and prcm");
		goto intr;
	}

	config_found(self, &sc->sc.sc_bus, usbctlprint);

	goto out;

intr:
	arm_intr_disestablish(sc->sc_ih);
	sc->sc_ih = NULL;
mem2:
	bus_space_unmap(sc->sc.iot, sc->tll_ioh, aa->aa_dev->mem[2].size);
mem1:
	bus_space_unmap(sc->sc.iot, sc->uhh_ioh, aa->aa_dev->mem[1].size);
mem0:
	bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
	sc->sc.sc_size = 0;
out:
	return;
}

int
omehci_init(struct omehci_softc *sc)
{
	uint32_t i = 0, reg;
	uint32_t reset_performed = 0;
	uint32_t timeout = 0;
	uint32_t tll_ch_mask = 0;

	/* enable high speed usb host clock */
	prcm_enablemodule(PRCM_USB);

	/* Hold the PHY in reset while configuring */
	for (i = 0; i < OMAP_HS_USB_PORTS; i++) {
		if (sc->phy_reset[i]) {
			/* Configure the GPIO to drive low (hold in reset) */
			if (sc->reset_gpio_pin[i] != -1) {
				omgpio_set_dir(sc->reset_gpio_pin[i],
				    OMGPIO_DIR_OUT);
				omgpio_clear_bit(sc->reset_gpio_pin[i]);
				reset_performed = 1;
			}
		}
	}

	/* Hold the PHY in RESET for enough time till DIR is high */
	if (reset_performed)
		delay(10);

	/* Read the UHH revision */
	sc->ehci_rev = bus_space_read_4(sc->sc.iot, sc->uhh_ioh,
	    OMAP_USBHOST_UHH_REVISION);

	/* Initilise the low level interface module(s) */
	if (sc->ehci_rev == OMAP_EHCI_REV1) {
		/* Enable the USB TLL */
		prcm_enablemodule(PRCM_USBTLL);

		/* Perform TLL soft reset, and wait until reset is complete */
		bus_space_write_4(sc->sc.iot, sc->tll_ioh,
		    OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET);

		/* Set the timeout to 100ms*/
		timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);

		/* Wait for TLL reset to complete */
		while ((bus_space_read_4(sc->sc.iot, sc->tll_ioh,
		    OMAP_USBTLL_SYSSTATUS) & TLL_SYSSTATUS_RESETDONE)
		    == 0x00) {

			/* Sleep for a tick */
			delay(10);

			if (timeout-- == 0) {
				return 1;
			}
		}

		bus_space_write_4(sc->sc.iot, sc->tll_ioh,
		    OMAP_USBTLL_SYSCONFIG,
		    TLL_SYSCONFIG_ENAWAKEUP | TLL_SYSCONFIG_AUTOIDLE |
		    TLL_SYSCONFIG_SIDLE_SMART_IDLE | TLL_SYSCONFIG_CACTIVITY);
	} else if (sc->ehci_rev == OMAP_EHCI_REV2) {
		/* For OMAP44xx devices you have to enable the per-port clocks:
		 *  PHY_MODE  - External ULPI clock
		 *  TTL_MODE  - Internal UTMI clock
		 *  HSIC_MODE - Internal 480Mhz and 60Mhz clocks
		 */
		if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) {
			//ti_prcm_clk_set_source(USBP1_PHY_CLK, EXT_CLK);
			prcm_enablemodule(PRCM_USBP1_PHY);
		} else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
			prcm_enablemodule(PRCM_USBP1_UTMI);
		else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
			prcm_enablemodule(PRCM_USBP1_HSIC);

		if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) {
			//ti_prcm_clk_set_source(USBP2_PHY_CLK, EXT_CLK);
			prcm_enablemodule(PRCM_USBP2_PHY);
		} else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
			prcm_enablemodule(PRCM_USBP2_UTMI);
		else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
			prcm_enablemodule(PRCM_USBP2_HSIC);
	}

	/* Put UHH in SmartIdle/SmartStandby mode */
	reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh,
	    OMAP_USBHOST_UHH_SYSCONFIG);
	if (sc->ehci_rev == OMAP_EHCI_REV1) {
		reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK |
		         UHH_SYSCONFIG_MIDLEMODE_MASK);
		reg |= (UHH_SYSCONFIG_ENAWAKEUP |
		        UHH_SYSCONFIG_AUTOIDLE |
		        UHH_SYSCONFIG_CLOCKACTIVITY |
		        UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE |
		        UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY);
	} else if (sc->ehci_rev == OMAP_EHCI_REV2) {
		reg &= ~UHH_SYSCONFIG_IDLEMODE_MASK;
		reg |=  UHH_SYSCONFIG_IDLEMODE_NOIDLE;
		reg &= ~UHH_SYSCONFIG_STANDBYMODE_MASK;
		reg |=  UHH_SYSCONFIG_STANDBYMODE_NOSTDBY;
	}
	bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_SYSCONFIG,
	    reg);

	reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh,
	    OMAP_USBHOST_UHH_HOSTCONFIG);

	/* Setup ULPI bypass and burst configurations */
	reg |= (UHH_HOSTCONFIG_ENA_INCR4 |
		UHH_HOSTCONFIG_ENA_INCR8 |
		UHH_HOSTCONFIG_ENA_INCR16);
	reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN;

	if (sc->ehci_rev == OMAP_EHCI_REV1) {
		if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
			reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS;
		if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
			reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS;
		if (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
			reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS;

		/* Bypass the TLL module for PHY mode operation */
		if ((sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
		    (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
		    (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
			reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS;
		else
			reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS;
	} else if (sc->ehci_rev == OMAP_EHCI_REV2) {
		reg |=  UHH_HOSTCONFIG_APP_START_CLK;

		/* Clear port mode fields for PHY mode*/
		reg &= ~UHH_HOSTCONFIG_P1_MODE_MASK;
		reg &= ~UHH_HOSTCONFIG_P2_MODE_MASK;

		if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
			reg |= UHH_HOSTCONFIG_P1_MODE_UTMI_PHY;
		else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
			reg |= UHH_HOSTCONFIG_P1_MODE_HSIC;

		if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
			reg |= UHH_HOSTCONFIG_P2_MODE_UTMI_PHY;
		else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
			reg |= UHH_HOSTCONFIG_P2_MODE_HSIC;
	}

	bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_HOSTCONFIG, reg);

	/* If any of the ports are configured in TLL mode, enable them */
	for (i = 0; i < OMAP_HS_USB_PORTS; i++)
		if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY)
			tll_ch_mask |= 1 << i;

	/* Enable UTMI mode for required TLL channels */
#ifdef notyet
	if (tll_ch_mask)
		omap_ehci_utmi_init(sc, tll_ch_mask);
#endif

	/* Release the PHY reset signal now we have configured everything */
	if (reset_performed) {
		/* Delay for 10ms */
		delay(10000);

		/* Release reset */
		for (i = 0; i < 3; i++) {
			if (sc->phy_reset[i] && (sc->reset_gpio_pin[i] != -1))
				omgpio_set_bit(sc->reset_gpio_pin[i]);
		}
	}

	/* Set the interrupt threshold control, it controls the maximum rate at
	 * which the host controller issues interrupts.  We set it to 1 microframe
	 * at startup - the default is 8 mircoframes (equates to 1ms).
	 */
	reg = bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD);
	reg &= 0xff00ffff;
	reg |= (1 << 16);
	bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD, reg);

	/* Soft reset the PHY using PHY reset command over ULPI */
	for (i = 0; i < OMAP_HS_USB_PORTS; i++)
		if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY)
			omehci_soft_phy_reset(sc, i);

	return(0);
}

void
omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port)
{
	unsigned long timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
	uint32_t reg;

	reg = ULPI_FUNC_CTRL_RESET
		/* FUNCTION_CTRL_SET register */
		| (ULPI_SET(ULPI_FUNC_CTRL) << OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT)
		/* Write */
		| (2 << OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT)
		/* PORTn */
		| ((port + 1) << OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT)
		/* start ULPI access*/
		| (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT);

	bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI, reg);

	timeout += 1000000;
	/* Wait for ULPI access completion */
	while ((bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI)
			& (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT))) {

		/* Sleep for a tick */
		delay(10);

		if (timeout-- == 0) {
			printf("PHY reset operation timed out\n");
			break;
		}
	}
}

int
omehci_detach(struct device *self, int flags)
{
	struct omehci_softc		*sc = (struct omehci_softc *)self;
	int				rv;

	rv = ehci_detach(self, flags);
	if (rv)
		return (rv);

	if (sc->sc_ih != NULL) {
		arm_intr_disestablish(sc->sc_ih);
		sc->sc_ih = NULL;
	}

	if (sc->sc.sc_size) {
		bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
		sc->sc.sc_size = 0;
	}

	/* XXX: stop clock */

	return (0);
}

int
omehci_activate(struct device *self, int act)
{
	struct omehci_softc *sc = (struct omehci_softc *)self;

	switch (act) {
	case DVACT_SUSPEND:
		sc->sc.sc_bus.use_polling++;
		/* FIXME */
		sc->sc.sc_bus.use_polling--;
		break;
	case DVACT_RESUME:
		sc->sc.sc_bus.use_polling++;
		/* FIXME */
		sc->sc.sc_bus.use_polling--;
		break;
	case DVACT_POWERDOWN:
		ehci_reset(&sc->sc);
		break;
	}
	return 0;
}

void
omehci_v4_early_init()
{
	omgpio_set_dir(1, OMGPIO_DIR_OUT);
	omgpio_clear_bit(1);
	omgpio_set_dir(62, OMGPIO_DIR_OUT);
	omgpio_clear_bit(62);

	/* wait for power down */
	delay(1000);

	omgpio_set_bit(1);
	omgpio_set_bit(62);

	/* wait until powered up */
	delay(1000);
}


code:
/* $OpenBSD: omehcivar.h,v 1.1 2013/09/04 14:38:31 patrick Exp $ */

/*
 * Misc
 */
#define OMAP_HS_USB_PORTS                           3

/*
 * USB TTL Module
 */
#define	OMAP_USBTLL_REVISION                        0x0000
#define	OMAP_USBTLL_SYSCONFIG                       0x0010
#define	OMAP_USBTLL_SYSSTATUS                       0x0014
#define	OMAP_USBTLL_IRQSTATUS                       0x0018
#define	OMAP_USBTLL_IRQENABLE                       0x001C
#define	OMAP_USBTLL_TLL_SHARED_CONF                 0x0030
#define	OMAP_USBTLL_TLL_CHANNEL_CONF(i)             (0x0040 + (0x04 * (i)))
#define	OMAP_USBTLL_SAR_CNTX(i)                     (0x0400 + (0x04 * (i)))
#define	OMAP_USBTLL_ULPI_VENDOR_ID_LO(i)            (0x0800 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_VENDOR_ID_HI(i)            (0x0801 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_PRODUCT_ID_LO(i)           (0x0802 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_PRODUCT_ID_HI(i)           (0x0803 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_FUNCTION_CTRL(i)           (0x0804 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_FUNCTION_CTRL_SET(i)       (0x0805 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_FUNCTION_CTRL_CLR(i)       (0x0806 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_INTERFACE_CTRL(i)          (0x0807 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_INTERFACE_CTRL_SET(i)      (0x0808 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_INTERFACE_CTRL_CLR(i)      (0x0809 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_OTG_CTRL(i)                (0x080A + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_OTG_CTRL_SET(i)            (0x080B + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_OTG_CTRL_CLR(i)            (0x080C + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_USB_INT_EN_RISE(i)         (0x080D + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_USB_INT_EN_RISE_SET(i)     (0x080E + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_USB_INT_EN_RISE_CLR(i)     (0x080F + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_USB_INT_EN_FALL(i)         (0x0810 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_USB_INT_EN_FALL_SET(i)     (0x0811 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_USB_INT_EN_FALL_CLR(i)     (0x0812 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_USB_INT_STATUS(i)          (0x0813 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_USB_INT_LATCH(i)           (0x0814 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_DEBUG(i)                   (0x0815 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_SCRATCH_REGISTER(i)        (0x0816 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_SCRATCH_REGISTER_SET(i)    (0x0817 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_SCRATCH_REGISTER_CLR(i)    (0x0818 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_EXTENDED_SET_ACCESS(i)     (0x082F + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN(i)        (0x0830 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_SET(i)    (0x0831 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_CLR(i)    (0x0832 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_UTMI_VCONTROL_STATUS(i)    (0x0833 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_UTMI_VCONTROL_LATCH(i)     (0x0834 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_UTMI_VSTATUS(i)            (0x0835 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_UTMI_VSTATUS_SET(i)        (0x0836 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_UTMI_VSTATUS_CLR(i)        (0x0837 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_USB_INT_LATCH_NOCLR(i)     (0x0838 + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_VENDOR_INT_EN(i)           (0x083B + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_VENDOR_INT_EN_SET(i)       (0x083C + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_VENDOR_INT_EN_CLR(i)       (0x083D + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_VENDOR_INT_STATUS(i)       (0x083E + (0x100 * (i)))
#define	OMAP_USBTLL_ULPI_VENDOR_INT_LATCH(i)        (0x083F + (0x100 * (i)))

/*
 * USB Host Module
 */

/* UHH */
#define	OMAP_USBHOST_UHH_REVISION                   0x0000
#define	OMAP_USBHOST_UHH_SYSCONFIG                  0x0010
#define	OMAP_USBHOST_UHH_SYSSTATUS                  0x0014
#define	OMAP_USBHOST_UHH_HOSTCONFIG                 0x0040
#define	OMAP_USBHOST_UHH_DEBUG_CSR                  0x0044

/* EHCI */
#define	OMAP_USBHOST_HCCAPBASE                      0x0000
#define	OMAP_USBHOST_HCSPARAMS                      0x0004
#define	OMAP_USBHOST_HCCPARAMS                      0x0008
#define	OMAP_USBHOST_USBCMD                         0x0010
#define	OMAP_USBHOST_USBSTS                         0x0014
#define	OMAP_USBHOST_USBINTR                        0x0018
#define	OMAP_USBHOST_FRINDEX                        0x001C
#define	OMAP_USBHOST_CTRLDSSEGMENT                  0x0020
#define	OMAP_USBHOST_PERIODICLISTBASE               0x0024
#define	OMAP_USBHOST_ASYNCLISTADDR                  0x0028
#define	OMAP_USBHOST_CONFIGFLAG                     0x0050
#define	OMAP_USBHOST_PORTSC(i)                      (0x0054 + (0x04 * (i)))
#define	OMAP_USBHOST_INSNREG00                      0x0090
#define	OMAP_USBHOST_INSNREG01                      0x0094
#define	OMAP_USBHOST_INSNREG02                      0x0098
#define	OMAP_USBHOST_INSNREG03                      0x009C
#define	OMAP_USBHOST_INSNREG04                      0x00A0
#define	OMAP_USBHOST_INSNREG05_UTMI                 0x00A4
#define	OMAP_USBHOST_INSNREG05_ULPI                 0x00A4
#define	OMAP_USBHOST_INSNREG06                      0x00A8
#define	OMAP_USBHOST_INSNREG07                      0x00AC
#define	OMAP_USBHOST_INSNREG08                      0x00B0

#define OMAP_USBHOST_INSNREG04_DISABLE_UNSUSPEND   (1 << 5)

#define OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT   31
#define OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT   24
#define OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT     22
#define OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT    16
#define OMAP_USBHOST_INSNREG05_ULPI_EXTREGADD_SHIFT 8
#define OMAP_USBHOST_INSNREG05_ULPI_WRDATA_SHIFT    0

/* TLL Register Set */
#define	TLL_SYSCONFIG_CACTIVITY                 (1UL << 8)
#define	TLL_SYSCONFIG_SIDLE_SMART_IDLE          (2UL << 3)
#define	TLL_SYSCONFIG_SIDLE_NO_IDLE             (1UL << 3)
#define	TLL_SYSCONFIG_SIDLE_FORCED_IDLE         (0UL << 3)
#define	TLL_SYSCONFIG_ENAWAKEUP                 (1UL << 2)
#define	TLL_SYSCONFIG_SOFTRESET                 (1UL << 1)
#define	TLL_SYSCONFIG_AUTOIDLE                  (1UL << 0)

#define	TLL_SYSSTATUS_RESETDONE                 (1UL << 0)

#define TLL_SHARED_CONF_USB_90D_DDR_EN          (1UL << 6)
#define TLL_SHARED_CONF_USB_180D_SDR_EN         (1UL << 5)
#define TLL_SHARED_CONF_USB_DIVRATIO_MASK       (7UL << 2)
#define TLL_SHARED_CONF_USB_DIVRATIO_128        (7UL << 2)
#define TLL_SHARED_CONF_USB_DIVRATIO_64         (6UL << 2)
#define TLL_SHARED_CONF_USB_DIVRATIO_32         (5UL << 2)
#define TLL_SHARED_CONF_USB_DIVRATIO_16         (4UL << 2)
#define TLL_SHARED_CONF_USB_DIVRATIO_8          (3UL << 2)
#define TLL_SHARED_CONF_USB_DIVRATIO_4          (2UL << 2)
#define TLL_SHARED_CONF_USB_DIVRATIO_2          (1UL << 2)
#define TLL_SHARED_CONF_USB_DIVRATIO_1          (0UL << 2)
#define TLL_SHARED_CONF_FCLK_REQ                (1UL << 1)
#define TLL_SHARED_CONF_FCLK_IS_ON              (1UL << 0)

#define TLL_CHANNEL_CONF_DRVVBUS                (1UL << 16)
#define TLL_CHANNEL_CONF_CHRGVBUS               (1UL << 15)
#define TLL_CHANNEL_CONF_ULPINOBITSTUFF         (1UL << 11)
#define TLL_CHANNEL_CONF_ULPIAUTOIDLE           (1UL << 10)
#define TLL_CHANNEL_CONF_UTMIAUTOIDLE           (1UL << 9)
#define TLL_CHANNEL_CONF_ULPIDDRMODE            (1UL << 8)
#define TLL_CHANNEL_CONF_ULPIOUTCLKMODE         (1UL << 7)
#define TLL_CHANNEL_CONF_TLLFULLSPEED           (1UL << 6)
#define TLL_CHANNEL_CONF_TLLCONNECT             (1UL << 5)
#define TLL_CHANNEL_CONF_TLLATTACH              (1UL << 4)
#define TLL_CHANNEL_CONF_UTMIISADEV             (1UL << 3)
#define TLL_CHANNEL_CONF_CHANEN                 (1UL << 0)

/* UHH Register Set */
#define UHH_SYSCONFIG_MIDLEMODE_MASK            (3UL << 12)
#define UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY    (2UL << 12)
#define UHH_SYSCONFIG_MIDLEMODE_NOSTANDBY       (1UL << 12)
#define UHH_SYSCONFIG_MIDLEMODE_FORCESTANDBY    (0UL << 12)
#define UHH_SYSCONFIG_CLOCKACTIVITY             (1UL << 8)
#define UHH_SYSCONFIG_SIDLEMODE_MASK            (3UL << 3)
#define UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE       (2UL << 3)
#define UHH_SYSCONFIG_SIDLEMODE_NOIDLE          (1UL << 3)
#define UHH_SYSCONFIG_SIDLEMODE_FORCEIDLE       (0UL << 3)
#define UHH_SYSCONFIG_ENAWAKEUP                 (1UL << 2)
#define UHH_SYSCONFIG_SOFTRESET                 (1UL << 1)
#define UHH_SYSCONFIG_AUTOIDLE                  (1UL << 0)

#define UHH_HOSTCONFIG_APP_START_CLK            (1UL << 31)
#define UHH_HOSTCONFIG_P3_CONNECT_STATUS        (1UL << 10)
#define UHH_HOSTCONFIG_P2_CONNECT_STATUS        (1UL << 9)
#define UHH_HOSTCONFIG_P1_CONNECT_STATUS        (1UL << 8)
#define UHH_HOSTCONFIG_ENA_INCR_ALIGN           (1UL << 5)
#define UHH_HOSTCONFIG_ENA_INCR16               (1UL << 4)
#define UHH_HOSTCONFIG_ENA_INCR8                (1UL << 3)
#define UHH_HOSTCONFIG_ENA_INCR4                (1UL << 2)
#define UHH_HOSTCONFIG_AUTOPPD_ON_OVERCUR_EN    (1UL << 1)
#define UHH_HOSTCONFIG_P1_ULPI_BYPASS           (1UL << 0)

/* The following are on rev2 (OMAP44xx) of the EHCI only */
#define UHH_SYSCONFIG_IDLEMODE_MASK             (3UL << 2)
#define UHH_SYSCONFIG_IDLEMODE_NOIDLE           (1UL << 2)
#define UHH_SYSCONFIG_STANDBYMODE_MASK          (3UL << 4)
#define UHH_SYSCONFIG_STANDBYMODE_NOSTDBY       (1UL << 4)

#define UHH_HOSTCONFIG_P1_MODE_MASK             (3UL << 16)
#define UHH_HOSTCONFIG_P1_MODE_ULPI_PHY         (0UL << 16)
#define UHH_HOSTCONFIG_P1_MODE_UTMI_PHY         (1UL << 16)
#define UHH_HOSTCONFIG_P1_MODE_HSIC             (3UL << 16)
#define UHH_HOSTCONFIG_P2_MODE_MASK             (3UL << 18)
#define UHH_HOSTCONFIG_P2_MODE_ULPI_PHY         (0UL << 18)
#define UHH_HOSTCONFIG_P2_MODE_UTMI_PHY         (1UL << 18)
#define UHH_HOSTCONFIG_P2_MODE_HSIC             (3UL << 18)

#define ULPI_FUNC_CTRL_RESET                    (1 << 5)

/*-------------------------------------------------------------------------*/

/*
 * Macros for Set and Clear
 * See ULPI 1.1 specification to find the registers with Set and Clear offsets
 */
#define ULPI_SET(a)                             (a + 1)
#define ULPI_CLR(a)                             (a + 2)

/*-------------------------------------------------------------------------*/

/*
 * Register Map
 */
#define ULPI_VENDOR_ID_LOW                      0x00
#define ULPI_VENDOR_ID_HIGH                     0x01
#define ULPI_PRODUCT_ID_LOW                     0x02
#define ULPI_PRODUCT_ID_HIGH                    0x03
#define ULPI_FUNC_CTRL                          0x04
#define ULPI_IFC_CTRL                           0x07
#define ULPI_OTG_CTRL                           0x0a
#define ULPI_USB_INT_EN_RISE                    0x0d
#define ULPI_USB_INT_EN_FALL                    0x10
#define ULPI_USB_INT_STS                        0x13
#define ULPI_USB_INT_LATCH                      0x14
#define ULPI_DEBUG                              0x15
#define ULPI_SCRATCH                            0x16

/*
 * Values of UHH_REVISION - Note: these are not given in the TRM but taken
 * from the linux OMAP EHCI driver (thanks guys).  It has been verified on
 * a Panda and Beagle board.
 */
#define OMAP_EHCI_REV1  0x00000010      /* OMAP3 */
#define OMAP_EHCI_REV2  0x50700100      /* OMAP4 */

#define EHCI_VENDORID_OMAP3     0x42fa05
#define OMAP_EHCI_HC_DEVSTR    "TI OMAP USB 2.0 controller"

#define EHCI_HCD_OMAP_MODE_UNKNOWN  0
#define EHCI_HCD_OMAP_MODE_PHY      1
#define EHCI_HCD_OMAP_MODE_TLL      2
#define EHCI_HCD_OMAP_MODE_HSIC     3


code:
/* $OpenBSD: omgpio.c,v 1.5 2014/07/14 08:55:07 rapha Exp $ */
/*
 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/evcount.h>
#include <sys/gpio.h>

#include <arm/cpufunc.h>

#include <machine/bus.h>
#include <machine/intr.h>

#include <dev/gpio/gpiovar.h>

#include <armv7/armv7/armv7var.h>
#include <armv7/omap/prcmvar.h>
#include <armv7/omap/sitara_cm.h>
#include <armv7/omap/omgpiovar.h>

#include "gpio.h"

/* OMAP3 registers */
#define	GPIO3_REVISION		0x00
#define	GPIO3_SYSCONFIG		0x10
#define	GPIO3_SYSSTATUS		0x14
#define	GPIO3_IRQSTATUS1	0x18
#define	GPIO3_IRQENABLE1	0x1C
#define	GPIO3_WAKEUPENABLE	0x20
#define	GPIO3_IRQSTATUS2	0x28
#define	GPIO3_IRQENABLE2	0x2C
#define	GPIO3_CTRL		0x30
#define	GPIO3_OE		0x34
#define	GPIO3_DATAIN		0x38
#define	GPIO3_DATAOUT		0x3C
#define	GPIO3_LEVELDETECT0	0x40
#define	GPIO3_LEVELDETECT1	0x44
#define	GPIO3_RISINGDETECT	0x48
#define	GPIO3_FALLINGDETECT	0x4C
#define	GPIO3_DEBOUNCENABLE	0x50
#define	GPIO3_DEBOUNCINGTIME	0x54
#define	GPIO3_CLEARIRQENABLE1	0x60
#define	GPIO3_SETIRQENABLE1	0x64
#define	GPIO3_CLEARIRQENABLE2	0x70
#define	GPIO3_SETIRQENABLE2	0x74
#define	GPIO3_CLEARWKUENA	0x80
#define	GPIO3_SETWKUENA		0x84
#define	GPIO3_CLEARDATAOUT	0x90
#define	GPIO3_SETDATAOUT	0x94

/* OMAP4 registers */
#define GPIO4_REVISION		0x00
#define GPIO4_SYSCONFIG		0x10
#define GPIO4_IRQSTATUS_RAW_0	0x24
#define GPIO4_IRQSTATUS_RAW_1	0x28
#define GPIO4_IRQSTATUS_0	0x2C
#define GPIO4_IRQSTATUS_1	0x30
#define GPIO4_IRQSTATUS_SET_0	0x34
#define GPIO4_IRQSTATUS_SET_1	0x38
#define GPIO4_IRQSTATUS_CLR_0	0x3C
#define GPIO4_IRQSTATUS_CLR_1	0x40
#define GPIO4_IRQWAKEN_0	0x44
#define GPIO4_IRQWAKEN_1	0x48
#define GPIO4_SYSSTATUS		0x114
#define GPIO4_WAKEUPENABLE	0x120
#define GPIO4_CTRL		0x130
#define GPIO4_OE		0x134
#define GPIO4_DATAIN		0x138
#define GPIO4_DATAOUT		0x13C
#define GPIO4_LEVELDETECT0	0x140
#define GPIO4_LEVELDETECT1	0x144
#define GPIO4_RISINGDETECT 	0x148
#define GPIO4_FALLINGDETECT	0x14C
#define GPIO4_DEBOUNCENABLE	0x150
#define GPIO4_DEBOUNCINGTIME	0x154
#define GPIO4_CLEARWKUPENA	0x180
#define GPIO4_SETWKUENA		0x184
#define GPIO4_CLEARDATAOUT	0x190
#define GPIO4_SETDATAOUT	0x194

/* AM335X registers */
#define GPIO_AM335X_REVISION		0x00
#define GPIO_AM335X_SYSCONFIG		0x10
#define GPIO_AM335X_IRQSTATUS_RAW_0	0x24
#define GPIO_AM335X_IRQSTATUS_RAW_1	0x28
#define GPIO_AM335X_IRQSTATUS_0		0x2C
#define GPIO_AM335X_IRQSTATUS_1		0x30
#define GPIO_AM335X_IRQSTATUS_SET_0	0x34
#define GPIO_AM335X_IRQSTATUS_SET_1	0x38
#define GPIO_AM335X_IRQSTATUS_CLR_0	0x3c
#define GPIO_AM335X_IRQSTATUS_CLR_1	0x40
#define GPIO_AM335X_IRQWAKEN_0		0x44
#define GPIO_AM335X_IRQWAKEN_1		0x48
#define GPIO_AM335X_SYSSTATUS		0x114
#define GPIO_AM335X_CTRL		0x130
#define GPIO_AM335X_OE			0x134
#define GPIO_AM335X_DATAIN		0x138
#define GPIO_AM335X_DATAOUT		0x13C
#define GPIO_AM335X_LEVELDETECT0	0x140
#define GPIO_AM335X_LEVELDETECT1	0x144
#define GPIO_AM335X_RISINGDETECT	0x148
#define GPIO_AM335X_FALLINGDETECT	0x14C
#define GPIO_AM335X_DEBOUNCENABLE	0x150
#define GPIO_AM335X_DEBOUNCINGTIME	0x154
#define GPIO_AM335X_CLEARDATAOUT	0x190
#define GPIO_AM335X_SETDATAOUT		0x194

#define GPIO_NUM_PINS		32

struct intrhand {
	int (*ih_func)(void *);		/* handler */
	void *ih_arg;			/* arg for handler */
	int ih_ipl;			/* IPL_* */
	int ih_irq;			/* IRQ number */
	int ih_gpio;			/* gpio pin */
	struct evcount	ih_count;
	char *ih_name;
};

struct omgpio_regs {
	u_int32_t	revision;
	u_int32_t	sysconfig;
	u_int32_t	irqstatus_raw0;		/* omap4/am335x only */
	u_int32_t	irqstatus_raw1;		/* omap4/am335x only */
	u_int32_t	irqstatus0;
	u_int32_t	irqstatus1;
	u_int32_t	irqstatus_set0;
	u_int32_t	irqstatus_set1;
	u_int32_t	irqstatus_clear0;
	u_int32_t	irqstatus_clear1;
	u_int32_t	irqwaken0;
	u_int32_t	irqwaken1;
	u_int32_t	sysstatus;
	u_int32_t	wakeupenable;		/* omap3/omap4 only */
	u_int32_t	ctrl;
	u_int32_t	oe;
	u_int32_t	datain;
	u_int32_t	dataout;
	u_int32_t	leveldetect0;
	u_int32_t	leveldetect1;
	u_int32_t	risingdetect;
	u_int32_t	fallingdetect;
	u_int32_t	debounceenable;
	u_int32_t	debouncingtime;
	u_int32_t	clearwkupena;		/* omap3/omap4 only */
	u_int32_t	setwkupena;		/* omap3/omap4 only */
	u_int32_t	cleardataout;
	u_int32_t	setdataout;
};

struct omgpio_softc {
	struct device		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
	void			*sc_ih_h;
	void			*sc_ih_l;
	int 			sc_max_il;
	int 			sc_min_il;
	int			sc_irq;
	struct intrhand		*sc_handlers[GPIO_NUM_PINS];
	int			sc_omap_ver;
	struct gpio_chipset_tag	sc_gpio_gc;
	gpio_pin_t		sc_gpio_pins[GPIO_NUM_PINS];
	struct omgpio_regs	sc_regs;
};

#define GPIO_PIN_TO_INST(x)	((x) >> 5)
#define GPIO_PIN_TO_OFFSET(x)	((x) & 0x1f)
#define DEVNAME(sc)	((sc)->sc_dev.dv_xname)
#define READ4(sc, reg)		omgpio_read4(sc, reg)
#define WRITE4(sc, reg, val)	omgpio_write4(sc, reg, val)

u_int32_t omgpio_read4(struct omgpio_softc *, u_int32_t);
void omgpio_write4(struct omgpio_softc *, u_int32_t, u_int32_t);
int omgpio_match(struct device *, void *, void *);
void omgpio_attach(struct device *, struct device *, void *);
void omgpio_recalc_interrupts(struct omgpio_softc *);
int omgpio_irq(void *);
int omgpio_irq_dummy(void *);
int omgpio_pin_dir_read(struct omgpio_softc *, unsigned int);
void omgpio_pin_dir_write(struct omgpio_softc *, unsigned int, unsigned int);

struct cfattach omgpio_ca = {
	sizeof (struct omgpio_softc), omgpio_match, omgpio_attach
};

struct cfdriver omgpio_cd = {
	NULL, "omgpio", DV_DULL
};

u_int32_t
omgpio_read4(struct omgpio_softc *sc, u_int32_t reg)
{
	if(reg == -1)
		panic("%s: Invalid register address", DEVNAME(sc));

	return bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg));
}

void
omgpio_write4(struct omgpio_softc *sc, u_int32_t reg, u_int32_t val)
{
	if(reg == -1)
		panic("%s: Invalid register address", DEVNAME(sc));

	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val));
}

int
omgpio_match(struct device *parent, void *v, void *aux)
{
	switch (board_id) {
	case BOARD_ID_OMAP3_BEAGLE:
	case BOARD_ID_OMAP3_OVERO:
	case BOARD_ID_AM335X_BEAGLEBONE:
	case BOARD_ID_OMAP4_PANDA:
		break; /* continue trying */
	default:
		return 0; /* unknown */
	}
	return (1);
}

void
omgpio_attach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	struct omgpio_softc *sc = (struct omgpio_softc *) self;
	struct gpiobus_attach_args gba;
	u_int32_t	rev;
	int		i;

	prcm_enablemodule(PRCM_GPIO0 + aa->aa_dev->unit);

	sc->sc_iot = aa->aa_iot;
	if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
	    aa->aa_dev->mem[0].size, 0, &sc->sc_ioh))
		panic("%s: bus_space_map failed!", DEVNAME(sc));

	switch (board_id) {
	case BOARD_ID_OMAP3_BEAGLE:
	case BOARD_ID_OMAP3_OVERO:
		sc->sc_regs.revision = GPIO3_REVISION;
		sc->sc_regs.sysconfig = GPIO3_SYSCONFIG;
		sc->sc_regs.irqstatus_raw0 = -1;
		sc->sc_regs.irqstatus_raw1 = -1;
		sc->sc_regs.irqstatus0 = GPIO3_IRQSTATUS1;
		sc->sc_regs.irqstatus1 = GPIO3_IRQSTATUS2;
		sc->sc_regs.irqstatus_set0 = GPIO3_SETIRQENABLE1;
		sc->sc_regs.irqstatus_set1 = GPIO3_SETIRQENABLE2;
		sc->sc_regs.irqstatus_clear0 = GPIO3_CLEARIRQENABLE1;
		sc->sc_regs.irqstatus_clear1 = GPIO3_CLEARIRQENABLE2;
		sc->sc_regs.irqwaken0 = -1;
		sc->sc_regs.irqwaken1 = -1;
		sc->sc_regs.sysstatus = GPIO3_SYSSTATUS;
		sc->sc_regs.wakeupenable = GPIO3_WAKEUPENABLE;
		sc->sc_regs.ctrl = GPIO3_CTRL;
		sc->sc_regs.oe = GPIO3_OE;
		sc->sc_regs.datain = GPIO3_DATAIN;
		sc->sc_regs.dataout = GPIO3_DATAOUT;
		sc->sc_regs.leveldetect0 = GPIO3_LEVELDETECT0;
		sc->sc_regs.leveldetect1 = GPIO3_LEVELDETECT1;
		sc->sc_regs.risingdetect = GPIO3_RISINGDETECT;
		sc->sc_regs.fallingdetect = GPIO3_FALLINGDETECT;
		sc->sc_regs.debounceenable = GPIO3_DEBOUNCENABLE;
		sc->sc_regs.debouncingtime = GPIO3_DEBOUNCINGTIME;
		sc->sc_regs.clearwkupena = GPIO3_CLEARWKUENA;
		sc->sc_regs.setwkupena = GPIO3_SETWKUENA;
		sc->sc_regs.cleardataout = GPIO3_CLEARDATAOUT;
		sc->sc_regs.setdataout = GPIO3_SETDATAOUT;
		break;
	case BOARD_ID_OMAP4_PANDA:
		sc->sc_regs.revision = GPIO4_REVISION;
		sc->sc_regs.sysconfig = GPIO4_SYSCONFIG;
		sc->sc_regs.irqstatus_raw0 = GPIO4_IRQSTATUS_RAW_0;
		sc->sc_regs.irqstatus_raw1 = GPIO4_IRQSTATUS_RAW_1;
		sc->sc_regs.irqstatus0 = GPIO4_IRQSTATUS_0;
		sc->sc_regs.irqstatus1 = GPIO4_IRQSTATUS_1;
		sc->sc_regs.irqstatus_set0 = GPIO4_IRQSTATUS_SET_0;
		sc->sc_regs.irqstatus_set1 = GPIO4_IRQSTATUS_SET_1;
		sc->sc_regs.irqstatus_clear0 = GPIO4_IRQSTATUS_CLR_0;
		sc->sc_regs.irqstatus_clear1 = GPIO4_IRQSTATUS_CLR_1;
		sc->sc_regs.irqwaken0 = GPIO4_IRQWAKEN_0;
		sc->sc_regs.irqwaken1 = GPIO4_IRQWAKEN_1;
		sc->sc_regs.sysstatus = GPIO4_SYSSTATUS;
		sc->sc_regs.wakeupenable = GPIO4_WAKEUPENABLE;
		sc->sc_regs.ctrl = GPIO4_CTRL;
		sc->sc_regs.oe = GPIO4_OE;
		sc->sc_regs.datain = GPIO4_DATAIN;
		sc->sc_regs.dataout = GPIO4_DATAOUT;
		sc->sc_regs.leveldetect0 = GPIO4_LEVELDETECT0;
		sc->sc_regs.leveldetect1 = GPIO4_LEVELDETECT1;
		sc->sc_regs.risingdetect = GPIO4_RISINGDETECT;
		sc->sc_regs.fallingdetect = GPIO4_FALLINGDETECT;
		sc->sc_regs.debounceenable = GPIO4_DEBOUNCENABLE;
		sc->sc_regs.debouncingtime = GPIO4_DEBOUNCINGTIME;
		sc->sc_regs.clearwkupena = GPIO4_CLEARWKUPENA;
		sc->sc_regs.setwkupena = GPIO4_SETWKUENA;
		sc->sc_regs.cleardataout = GPIO4_CLEARDATAOUT;
		sc->sc_regs.setdataout = GPIO4_SETDATAOUT;
		break;
	case BOARD_ID_AM335X_BEAGLEBONE:
		sc->sc_regs.revision = GPIO_AM335X_REVISION;
		sc->sc_regs.sysconfig = GPIO_AM335X_SYSCONFIG;
		sc->sc_regs.irqstatus_raw0 = GPIO_AM335X_IRQSTATUS_RAW_0;
		sc->sc_regs.irqstatus_raw1 = GPIO_AM335X_IRQSTATUS_RAW_1;
		sc->sc_regs.irqstatus0 = GPIO_AM335X_IRQSTATUS_0;
		sc->sc_regs.irqstatus1 = GPIO_AM335X_IRQSTATUS_1;
		sc->sc_regs.irqstatus_set0 = GPIO_AM335X_IRQSTATUS_SET_0;
		sc->sc_regs.irqstatus_set1 = GPIO_AM335X_IRQSTATUS_SET_1;
		sc->sc_regs.irqstatus_clear0 = GPIO_AM335X_IRQSTATUS_CLR_0;
		sc->sc_regs.irqstatus_clear1 = GPIO_AM335X_IRQSTATUS_CLR_1;
		sc->sc_regs.irqwaken0 = GPIO_AM335X_IRQWAKEN_0;
		sc->sc_regs.irqwaken1 = GPIO_AM335X_IRQWAKEN_1;
		sc->sc_regs.sysstatus = GPIO_AM335X_SYSSTATUS;
		sc->sc_regs.wakeupenable = -1;
		sc->sc_regs.ctrl = GPIO_AM335X_CTRL;
		sc->sc_regs.oe = GPIO_AM335X_OE;
		sc->sc_regs.datain = GPIO_AM335X_DATAIN;
		sc->sc_regs.dataout = GPIO_AM335X_DATAOUT;
		sc->sc_regs.leveldetect0 = GPIO_AM335X_LEVELDETECT0;
		sc->sc_regs.leveldetect1 = GPIO_AM335X_LEVELDETECT1;
		sc->sc_regs.risingdetect = GPIO_AM335X_RISINGDETECT;
		sc->sc_regs.fallingdetect = GPIO_AM335X_FALLINGDETECT;
		sc->sc_regs.debounceenable = GPIO_AM335X_DEBOUNCENABLE;
		sc->sc_regs.debouncingtime = GPIO_AM335X_DEBOUNCINGTIME;
		sc->sc_regs.clearwkupena = -1;
		sc->sc_regs.setwkupena = -1;
		sc->sc_regs.cleardataout = GPIO_AM335X_CLEARDATAOUT;
		sc->sc_regs.setdataout = GPIO_AM335X_SETDATAOUT;
		break;
	}

	rev = READ4(sc, sc->sc_regs.revision);

	printf(": rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);

	sc->sc_irq = aa->aa_dev->irq[0];

	WRITE4(sc, sc->sc_regs.irqstatus_clear0, ~0);
	WRITE4(sc, sc->sc_regs.irqstatus_clear1, ~0);

	/* XXX - SYSCONFIG */
	/* XXX - CTRL */
	/* XXX - DEBOUNCE */

	for (i = 0; i < GPIO_NUM_PINS; i++) {
		sc->sc_gpio_pins[i].pin_num = i;
		sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT |
		    GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN;
		sc->sc_gpio_pins[i].pin_state = omgpio_pin_read(sc, i) ?
		    GPIO_PIN_HIGH : GPIO_PIN_LOW;
		sc->sc_gpio_pins[i].pin_flags = GPIO_PIN_SET;
	}

	sc->sc_gpio_gc.gp_cookie = sc;
	sc->sc_gpio_gc.gp_pin_read = omgpio_pin_read;
	sc->sc_gpio_gc.gp_pin_write = omgpio_pin_write;
	sc->sc_gpio_gc.gp_pin_ctl = omgpio_pin_ctl;

	gba.gba_name = "gpio";
	gba.gba_gc = &sc->sc_gpio_gc;
	gba.gba_pins = sc->sc_gpio_pins;
	gba.gba_npins = GPIO_NUM_PINS;

#if NGPIO > 0
	config_found(&sc->sc_dev, &gba, gpiobus_print);
#endif
}

/* XXX - This assumes MCU INTERRUPTS are IRQ1, and DSP are IRQ2 */

#if 0
/* XXX - FIND THESE REGISTERS !!! */
unsigned int
omgpio_get_function(unsigned int gpio, unsigned int fn)
{
	return 0;
}

void
omgpio_set_function(unsigned int gpio, unsigned int fn)
{
}
#endif

unsigned int
omgpio_get_bit(unsigned int gpio)
{
	struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];

	return omgpio_pin_read(sc, GPIO_PIN_TO_OFFSET(gpio));
}

void
omgpio_set_bit(unsigned int gpio)
{
	struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];

	omgpio_pin_write(sc, GPIO_PIN_TO_OFFSET(gpio), GPIO_PIN_HIGH);
}

void
omgpio_clear_bit(unsigned int gpio)
{
	struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];

	omgpio_pin_write(sc, GPIO_PIN_TO_OFFSET(gpio), GPIO_PIN_LOW);
}

void
omgpio_set_dir(unsigned int gpio, unsigned int dir)
{
	struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];

	omgpio_pin_dir_write(sc, GPIO_PIN_TO_OFFSET(gpio), dir);
}

int
omgpio_pin_read(void *arg, int pin)
{
	struct omgpio_softc *sc = arg;
	u_int32_t reg;

	if(omgpio_pin_dir_read(sc, pin) == OMGPIO_DIR_IN)
		reg = READ4(sc, sc->sc_regs.datain);
	else
		reg = READ4(sc, sc->sc_regs.dataout);
	return (reg >> GPIO_PIN_TO_OFFSET(pin)) & 0x1;
}

void
omgpio_pin_write(void *arg, int pin, int value)
{
	struct omgpio_softc *sc = arg;

	if (value)
		WRITE4(sc, sc->sc_regs.setdataout,
		    1 << GPIO_PIN_TO_OFFSET(pin));
	else
		WRITE4(sc, sc->sc_regs.cleardataout,
		    1 << GPIO_PIN_TO_OFFSET(pin));
}

void
omgpio_pin_ctl(void *arg, int pin, int flags)
{
	struct omgpio_softc *sc = arg;

	if (flags & GPIO_PIN_INPUT)
		omgpio_pin_dir_write(sc, pin, OMGPIO_DIR_IN);
	else if (flags & GPIO_PIN_OUTPUT)
		omgpio_pin_dir_write(sc, pin, OMGPIO_DIR_OUT);

	if (board_id == BOARD_ID_AM335X_BEAGLEBONE)
		sitara_cm_padconf_set_gpioflags(
		    sc->sc_dev.dv_unit * GPIO_NUM_PINS + pin, flags);
}

void
omgpio_pin_dir_write(struct omgpio_softc *sc, unsigned int gpio,
    unsigned int dir)
{
	int s;
	u_int32_t reg;

	s = splhigh();

	reg = READ4(sc, sc->sc_regs.oe);
	if (dir == OMGPIO_DIR_IN)
		reg |= 1 << GPIO_PIN_TO_OFFSET(gpio);
	else
		reg &= ~(1 << GPIO_PIN_TO_OFFSET(gpio));
	WRITE4(sc, sc->sc_regs.oe, reg);

	splx(s);
}

int
omgpio_pin_dir_read(struct omgpio_softc *sc, unsigned int gpio)
{
	u_int32_t reg;
	reg = READ4(sc, sc->sc_regs.oe);
	if (reg & (1 << GPIO_PIN_TO_OFFSET(gpio)))
		return OMGPIO_DIR_IN;
	else
		return OMGPIO_DIR_OUT;
}

#if 0
void
omgpio_clear_intr(struct omgpio_softc *sc, unsigned int gpio)
{
	struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];

	WRITE4(sc, sc->sc_regs.irqstatus0, 1 << GPIO_PIN_TO_OFFSET(gpio));
}

void
omgpio_intr_mask(struct omgpio_softc *sc, unsigned int gpio)
{
	struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];

	WRITE4(sc, sc->sc_regs.irqstatus_clear0, 1 << GPIO_PIN_TO_OFFSET(gpio));
}

void
omgpio_intr_unmask(struct omgpio_softc *sc, unsigned int gpio)
{
	struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];

	WRITE4(sc, sc->sc_regs.irqstatus_set0, 1 << GPIO_PIN_TO_OFFSET(gpio));
}

void
omgpio_intr_level(struct omgpio_softc *sc, unsigned int gpio, unsigned int level)
{
	u_int32_t fe, re, l0, l1, bit;
	struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
	int s;

	s = splhigh();

	fe = READ4(sc, sc->sc_regs.fallingdetect);
	re = READ4(sc, sc->sc_regs.risingdetect);
	l0 = READ4(sc, sc->sc_regs.leveldetect0);
	l1 = READ4(sc, sc->sc_regs.leveldetect1);

	bit = 1 << GPIO_PIN_TO_OFFSET(gpio);

	switch (level) {
	case IST_NONE:
		fe &= ~bit;
		re &= ~bit;
		l0 &= ~bit;
		l1 &= ~bit;
		break;
	case IST_EDGE_FALLING:
		fe |= bit;
		re &= ~bit;
		l0 &= ~bit;
		l1 &= ~bit;
		break;
	case IST_EDGE_RISING:
		fe &= ~bit;
		re |= bit;
		l0 &= ~bit;
		l1 &= ~bit;
		break;
	case IST_PULSE: /* XXX */
		/* FALLTHRU */
	case IST_EDGE_BOTH:
		fe |= bit;
		re |= bit;
		l0 &= ~bit;
		l1 &= ~bit;
		break;
	case IST_LEVEL_LOW:
		fe &= ~bit;
		re &= ~bit;
		l0 |= bit;
		l1 &= ~bit;
		break;
	case IST_LEVEL_HIGH:
		fe &= ~bit;
		re &= ~bit;
		l0 &= ~bit;
		l1 |= bit;
		break;
	default:
		panic("omgpio_intr_level: bad level: %d", level);
		break;
	}

	WRITE4(sc, sc->sc_regs.fallingdetect, fe);
	WRITE4(sc, sc->sc_regs.risingdetect, re);
	WRITE4(sc, sc->sc_regs.leveldetect0, l0);
	WRITE4(sc, sc->sc_regs.leveldetect1, l1);

	splx(s);
}

void *
omgpio_intr_establish(struct omgpio_softc *sc, unsigned int gpio, int level, int spl,
    int (*func)(void *), void *arg, char *name)
{
	int psw;
	struct intrhand *ih;
	struct omgpio_softc *sc;

	/*
	 * XXX - is gpio here the pin or the interrupt number
	 * which is 96 + gpio pin?
	 */

	if (GPIO_PIN_TO_INST(gpio) > omgpio_cd.cd_ndevs)
		panic("omgpio_intr_establish: bogus irqnumber %d: %s",
		    gpio, name);

	sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];

	if (sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)] != NULL)
		panic("omgpio_intr_establish: gpio pin busy %d old %s new %s",
		    gpio, sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)]->ih_name,
		    name);

	psw = disable_interrupts(I32_bit);

	/* no point in sleeping unless someone can free memory. */
	ih = (struct intrhand *)malloc( sizeof *ih, M_DEVBUF,
	    cold ? M_NOWAIT : M_WAITOK);
	if (ih == NULL)
		panic("intr_establish: can't malloc handler info");
	ih->ih_func = func;
	ih->ih_arg = arg;
	ih->ih_ipl = level;
	ih->ih_gpio = gpio;
	ih->ih_irq = gpio + 512;
	ih->ih_name = name;

	sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)] = ih;

	evcount_attach(&ih->ih_count, name, &ih->ih_irq);

	omgpio_intr_level(gpio, level);
	omgpio_intr_unmask(gpio);

	omgpio_recalc_interrupts(sc);

	restore_interrupts(psw);

	return (ih);
}

void
omgpio_intr_disestablish(struct omgpio_softc *sc, void *cookie)
{
	int psw;
	struct intrhand *ih = cookie;
	struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(ih->ih_gpio)];
	int gpio = ih->ih_gpio;
	psw = disable_interrupts(I32_bit);

	ih = sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)];
	sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)] = NULL;

	evcount_detach(&ih->ih_count);

	free(ih, M_DEVBUF, 0);

	omgpio_intr_level(gpio, IST_NONE);
	omgpio_intr_mask(gpio);
	omgpio_clear_intr(gpio); /* Just in case */

	omgpio_recalc_interrupts(sc);

	restore_interrupts(psw);
}

int
omgpio_irq(void *v)
{
	struct omgpio_softc *sc = v;
	u_int32_t pending;
	struct intrhand *ih;
	int bit;

	pending = READ4(sc, omgpio.irqstatus0);

	while (pending != 0) {
		bit = ffs(pending) - 1;
		ih = sc->sc_handlers[bit];

		if (ih != NULL) {
			if (ih->ih_func(ih->ih_arg))
				ih->ih_count.ec_count++;
			omgpio_clear_intr(ih->ih_gpio);
		} else {
			panic("omgpio: irq fired no handler, gpio %x %x %x",
				sc->sc_dev.dv_unit * 32 + bit, pending,
	READ4(sc, omgpio.irqstatus0)

				);
		}
		pending &= ~(1 << bit);
	}
	return 1;
}

int
omgpio_irq_dummy(void *v)
{
	return 0;
}

void
omgpio_recalc_interrupts(struct omgpio_softc *sc)
{
	struct intrhand *ih;
	int max = IPL_NONE;
	int min = IPL_HIGH;
	int i;

	for (i = 0; i < GPIO_NUM_PINS; i++) {
		ih = sc->sc_handlers[i];
		if (ih != NULL) {
			if (ih->ih_ipl > max)
				max = ih->ih_ipl;

			if (ih->ih_ipl < min)
				min = ih->ih_ipl;
		}
	}
	if (max == IPL_NONE)
		min = IPL_NONE;

#if 0
	if ((max == IPL_NONE || max != sc->sc_max_il) && sc->sc_ih_h != NULL)
		arm_intr_disestablish(sc->sc_ih_h);

	if (max != IPL_NONE && max != sc->sc_max_il) {
		sc->sc_ih_h = arm_intr_establish(sc->sc_irq, max, omgpio_irq,
		    sc, NULL);
	}
#else
	if (sc->sc_ih_h != NULL)
		arm_intr_disestablish(sc->sc_ih_h);

	if (max != IPL_NONE) {
		sc->sc_ih_h = arm_intr_establish(sc->sc_irq, max, omgpio_irq,
		    sc, NULL);
	}
#endif

	sc->sc_max_il = max;

	if (sc->sc_ih_l != NULL)
		arm_intr_disestablish(sc->sc_ih_l);

	if (max != min) {
		sc->sc_ih_h = arm_intr_establish(sc->sc_irq, min,
		    omgpio_irq_dummy, sc, NULL);
	}
	sc->sc_min_il = min;
}
#endif


code:
/* $OpenBSD: omgpiovar.h,v 1.2 2013/11/20 13:32:40 rapha Exp $ */
/*
 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef OMGPIOVAR_H
#define OMGPIOVAR_H

#define OMGPIO_DIR_IN 	0
#define OMGPIO_DIR_OUT	1

unsigned int omgpio_get_function(unsigned int gpio, unsigned int fn);
void omgpio_set_function(unsigned int gpio, unsigned int fn);
unsigned int omgpio_get_bit(unsigned int gpio);
void omgpio_set_bit(unsigned int gpio);
void omgpio_clear_bit(unsigned int gpio);
void omgpio_set_dir(unsigned int gpio, unsigned int dir);

int omgpio_pin_read(void *arg, int pin);
void omgpio_pin_write(void *arg, int pin, int value);
void omgpio_pin_ctl(void *arg, int pin, int flags);

/* interrupts */
void omgpio_clear_intr(unsigned int gpio);
void omgpio_intr_mask(unsigned int gpio);
void omgpio_intr_unmask(unsigned int gpio);
void omgpio_intr_level(unsigned int gpio, unsigned int level);
void *omgpio_intr_establish(unsigned int gpio, int level, int spl,
    int (*func)(void *), void *arg, char *name);
void omgpio_intr_disestablish(void *cookie);

#endif /* OMGPIOVAR_H */