/*	$NecBSD: bshw.h,v 1.2 1997/10/31 17:43:38 honda Exp $	*/
/*	$NetBSD$	*/
/*
 * [NetBSD for NEC PC98 series]
 *  Copyright (c) 1994, 1995, 1996 NetBSD/pc98 porting staff.
 *  All rights reserved.
 * 
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * Copyright (c) 1994, 1995, 1996 Naofumi HONDA.  All rights reserved.
 */

/* NEC port offsets */
#define	BSHW_DEFAULT_PORT	0xcc0
#define	BSHW_IOSZ	5

#define	addr_port	0
#define	stat_port	0
#define	ctrl_port	2
#define	cmd_port	4

#define	BSHW_MAX_OFFSET		12
#define	BSHW_SEL_TIMEOUT	0x80

#define	BSHW_READ		BSR_IOR
#define	BSHW_WRITE		0x0

#define	BSHW_SMITFIFO_OFFSET	0x1000

#define	BSHW_CMD_CHECK(CCB, CAT) (bshw_cmd[(CCB)->cmd[0]] & (CAT))
/*********************************************************
 * static inline declare.
 *********************************************************/
static BS_INLINE void write_wd33c93 __P((struct bs_softc *, u_int, u_int8_t));
static BS_INLINE u_int8_t read_wd33c93 __P((struct bs_softc *, u_int));
static BS_INLINE u_int8_t bshw_get_auxstat __P((struct bs_softc *));
static BS_INLINE u_int8_t bshw_get_busstat __P((struct bs_softc *));
static BS_INLINE u_int8_t bshw_get_status_insat __P((struct bs_softc *));
static BS_INLINE u_int8_t bshw_read_data __P((struct bs_softc *));
static BS_INLINE void bshw_write_data __P((struct bs_softc *, u_int8_t));
static BS_INLINE void bshw_set_count __P((struct bs_softc *, u_int));
static BS_INLINE u_int bshw_get_count __P((struct bs_softc *));
static BS_INLINE void bshw_set_dst_id __P((struct bs_softc *, u_int, u_int));
static BS_INLINE void bshw_set_lun __P((struct bs_softc *, u_int));
static BS_INLINE u_int bshw_get_src_id __P((struct bs_softc *));
static BS_INLINE void bshw_negate_ack __P((struct bs_softc *));
static BS_INLINE void bshw_assert_atn __P((struct bs_softc *));
static BS_INLINE void bshw_assert_select __P((struct bs_softc *));
static BS_INLINE void bshw_start_xfer __P((struct bs_softc *));
static BS_INLINE void bshw_start_sxfer __P((struct bs_softc *));
static BS_INLINE void bshw_cmd_pass __P((struct bs_softc *, u_int));
static BS_INLINE void bshw_start_sat __P((struct bs_softc *, u_int));
static BS_INLINE void bshw_abort_cmd __P((struct bs_softc *));
static BS_INLINE void bshw_set_sync_reg __P((struct bs_softc *, u_int));
static BS_INLINE void bshw_set_poll_trans __P((struct bs_softc *, u_int));
static BS_INLINE void bshw_set_dma_trans __P((struct bs_softc *, u_int));

/*********************************************************
 * global declare
 *********************************************************/
void bs_dma_xfer __P((struct targ_info *, u_int));
void bs_dma_xfer_end __P((struct targ_info *));
void bshw_dmaabort __P((struct bs_softc *, struct targ_info *));

void bshw_adj_syncdata __P((struct syncdata *));
void bshw_set_synchronous __P((struct bs_softc *, struct targ_info *));

void bs_smit_xfer_end __P((struct targ_info *));
void bshw_smitabort __P((struct bs_softc *));

void bshw_setup_ctrl_reg __P((struct bs_softc *, u_int));
int bshw_chip_reset __P((struct bs_softc *));
void bshw_bus_reset __P((struct bs_softc *));
int bshw_board_probe __P((struct bs_softc *, u_int *, u_int *));
void bshw_lock __P((struct bs_softc *));
void bshw_unlock __P((struct bs_softc *));
void bshw_get_syncreg __P((struct bs_softc *));
void bshw_issue_satcmd __P((struct bs_softc *, struct ccb *, int));
void bshw_print_port __P((struct bs_softc *));

void bs_lc_smit_xfer __P((struct targ_info *, u_int));

extern struct dvcfg_hwsel bshw_hwsel;
extern u_int8_t bshw_cmd[];

/*********************************************************
 * hw
 *********************************************************/
struct bshw {
#define	BSHW_SYNC_RELOAD	0x01
#define	BSHW_SMFIFO		0x02
#define	BSHW_DOUBLE_DMACHAN	0x04
	u_int hw_flags;

	u_int sregaddr;

	int ((*dma_init) __P((struct bs_softc *)));
	void ((*dma_start) __P((struct bs_softc *)));
	void ((*dma_stop) __P((struct bs_softc *)));
};

/*********************************************************
 * inline funcs.
 *********************************************************/
/*
 * XXX: If your board does not work well, Please try BS_NEEDS_WEIGHT.
 */
static BS_INLINE void
write_wd33c93(bsc, addr, data)
	struct bs_softc *bsc;
	u_int addr;
	u_int8_t data;
{

	BUS_IOW(addr_port, addr);
	BUS_IOW(ctrl_port, data);
}

static BS_INLINE u_int8_t
read_wd33c93(bsc, addr)
	struct bs_softc *bsc;
	u_int addr;
{

	BUS_IOW(addr_port, addr);
	return BUS_IOR(ctrl_port);
}

/* status */
static BS_INLINE u_int8_t
bshw_get_auxstat(bsc)
	struct bs_softc *bsc;
{

	return BUS_IOR(stat_port);
}

static BS_INLINE u_int8_t
bshw_get_busstat(bsc)
	struct bs_softc *bsc;
{

	return read_wd33c93(bsc, wd3s_stat);
}

static BS_INLINE u_int8_t
bshw_get_status_insat(bsc)
	struct bs_softc *bsc;
{

	return read_wd33c93(bsc, wd3s_lun);
}

/* data */
static BS_INLINE u_int8_t
bshw_read_data(bsc)
	struct bs_softc *bsc;
{

	return read_wd33c93(bsc, wd3s_data);
}

static BS_INLINE void
bshw_write_data(bsc, data)
	struct bs_softc *bsc;
	u_int8_t data;
{

	write_wd33c93(bsc, wd3s_data, data);
}

/* counter */
static BS_INLINE void
bshw_set_count(bsc, count)
	struct bs_softc *bsc;
	u_int count;
{

	BUS_IOW(addr_port, wd3s_cnt);
	BUS_IOW(ctrl_port, count >> 16);
	BUS_IOW(ctrl_port, count >> 8);
	BUS_IOW(ctrl_port, count);
}

static BS_INLINE u_int
bshw_get_count(bsc)
	struct bs_softc *bsc;
{
	u_int count;

	BUS_IOW(addr_port, wd3s_cnt);
	count = (((u_int) BUS_IOR(ctrl_port)) << 16);
	count += (((u_int) BUS_IOR(ctrl_port)) << 8);
	count += ((u_int) BUS_IOR(ctrl_port));
	return count;
}

/* ID */
static BS_INLINE void
bshw_set_lun(bsc, lun)
	struct bs_softc *bsc;
	u_int lun;
{

	write_wd33c93(bsc, wd3s_lun, lun);
}

static BS_INLINE void
bshw_set_dst_id(bsc, target, lun)
	struct bs_softc *bsc;
	u_int target, lun;
{

	write_wd33c93(bsc, wd3s_did, target);
	write_wd33c93(bsc, wd3s_lun, lun);
}

static BS_INLINE u_int
bshw_get_src_id(bsc)
	struct bs_softc *bsc;
{

	return (read_wd33c93(bsc, wd3s_sid) & SIDR_IDM);
}

/* phase */
static BS_INLINE void
bshw_negate_ack(bsc)
	struct bs_softc *bsc;
{

	write_wd33c93(bsc, wd3s_cmd, WD3S_NEGATE_ACK);
}

static BS_INLINE void
bshw_assert_atn(bsc)
	struct bs_softc *bsc;
{

	write_wd33c93(bsc, wd3s_cmd, WD3S_ASSERT_ATN);
}

static BS_INLINE void
bshw_assert_select(bsc)
	struct bs_softc *bsc;
{

	write_wd33c93(bsc, wd3s_cmd, WD3S_SELECT_ATN);
}

static BS_INLINE void
bshw_start_xfer(bsc)
	struct bs_softc *bsc;
{

	write_wd33c93(bsc, wd3s_cmd, WD3S_TFR_INFO);
}

static BS_INLINE void
bshw_start_sxfer(bsc)
	struct bs_softc *bsc;
{

	write_wd33c93(bsc, wd3s_cmd, WD3S_SBT | WD3S_TFR_INFO);
}

static BS_INLINE void
bshw_cmd_pass(bsc, ph)
	struct bs_softc *bsc;
	u_int ph;
{

	write_wd33c93(bsc, wd3s_cph, ph);
}

static BS_INLINE void
bshw_start_sat(bsc, flag)
	struct bs_softc *bsc;
	u_int flag;
{

	write_wd33c93(bsc, wd3s_cmd,
		      (flag ? WD3S_SELECT_ATN_TFR : WD3S_SELECT_NO_ATN_TFR));
}


static BS_INLINE void
bshw_abort_cmd(bsc)
	struct bs_softc *bsc;
{

	write_wd33c93(bsc, wd3s_cmd, WD3S_ABORT);
}

/* transfer mode */
static BS_INLINE void
bshw_set_sync_reg(bsc, val)
	struct bs_softc *bsc;
	u_int val;
{

	write_wd33c93(bsc, wd3s_synch, val);
}

static BS_INLINE void
bshw_set_poll_trans(bsc, flags)
	struct bs_softc *bsc;
	u_int flags;
{

	if (bsc->sc_flags & BSDMATRANSFER)
	{
		bsc->sc_flags &= ~BSDMATRANSFER;
		bshw_setup_ctrl_reg(bsc, flags);
	}
}

static BS_INLINE void
bshw_set_dma_trans(bsc, flags)
	struct bs_softc *bsc;
	u_int flags;
{

	if ((bsc->sc_flags & BSDMATRANSFER) == 0)
	{
		bsc->sc_flags |= BSDMATRANSFER;
		bshw_setup_ctrl_reg(bsc, flags);
	}
}
