#ifndef HPI_H
#define HPI_H

// ---------------------------------------------------------
// API related
// ---------------------------------------------------------
//#define	IS_ERROR(e)			(0 != (e & HPI_ERROR))
#define	HPI_NOERROR			0
#define	HPI_ERROR			0x80000000
#define	HPI_ERR_NOTIMPL		(HPI_ERROR + 1)
#define	HPI_ERR_INVPARAM	(HPI_ERROR + 2)
#define	HPI_ERR_TIMEOUT		(HPI_ERROR + 3)
#define	HPI_ERR_PREFIX_MBX	(HPI_ERROR + 0x00010000)

#define	MAX_NUM_REGS		14
#define R0					0
#define R1					1
#define R2					2
#define R3					3
#define R4					4
#define R5					5
#define R6					6
#define R7					7
#define R8					8
#define R9					9
#define R10					10
#define R11					11
#define R12					12
#define R13					13

#define USB_MAX_NUM_PORTS	2
#define USB_MAX_NUM_EPT		8
#define USB_MAX_IMG_SIZE	512
#define USB_IRP_BASE		0x0F80
#define USB_IMG_BASE		0x1000

typedef void (*fp_t)(void*);

// Receive buffer on EP
typedef struct _scy_req_t
{
	UINT16 next;
	UINT16 addr;
	UINT16 size;
	UINT16 callback;
} cy_req_t;

typedef struct _sfifo_t
{
	UINT32 size;
	UINT8 *pBuf;
	UINT8 * volatile pPtr_wr, * volatile pPtr_rd;

} fifo_t;

typedef struct _susb_irp_t
{
	UINT16 tsize;
	UINT32 is_in, is_out;
	UINT32 port, ept;
	UINT16 cy_irp_addr;
	fifo_t fifo;
	UINT32 tx_in_progress;
	cy_req_t cy_req;
} usb_irp_t;

// ---------------------------------------------------------
// CY7C67300 related
// ---------------------------------------------------------
#define	HPI_WAITACK			1
#define	HPI_NOWAIT			0

// ---------------------------------------------------------
// HPI status flags
#define	HPI_STATUS_MBX_IN	0x0001
#define	HPI_STATUS_RESET1	0x0002
#define	HPI_STATUS_DONE1	0x0004
#define	HPI_STATUS_DONE2	0x0008
#define	HPI_STATUS_SIEMSG1	0x0010
#define	HPI_STATUS_SIEMSG2	0x0020
#define	HPI_STATUS_RESUME1	0x0040
#define	HPI_STATUS_RESUME2	0x0080
#define	HPI_STATUS_MBX_OUT	0x0100
#define	HPI_STATUS_RESET2	0x0200
#define	HPI_STATUS_SOFEOP1	0x0400
#define	HPI_STATUS_SOFEOP2	0x1000
#define	HPI_STATUS_ID		0x4000
#define	HPI_STATUS_VBUS		0x8000

// ---------------------------------------------------------
// LCP command codes
#define COMM_RESET			0xFA50
#define COMM_JUMP2CODE		0xCE00
#define COMM_EXEC_INT		0xCE01
#define COMM_READ_CTRL_REG	0xCE02
#define COMM_WRITE_CTRL_REG	0xCE03
#define COMM_CALL_CODE		0xCE04
#define COMM_READ_XMEM		0xCE05
#define COMM_WRITE_XMEM		0xCE06
#define C0MM_CONFIG			0xCE07
#define COMM_READ_MEM		0xCE08
#define COMM_WRITE_MEM		0xCE09
// LCP response codes
#define COMM_ACK			0x0FED
#define COMM_NAK			0xDEAD
#define COMM_ASYNC			0xF00D

// ---------------------------------------------------------
// LCP memory addresses
#define COMM_PORT_CMD		0x01BA	// For PORT Command
#define COMM_MEM_ADDR		0x01BC	// Address for COMM_RD/WR_MEM
#define COMM_MEM_LEN		0x01BE	// Address for COMM_RD/WR_MEM
#define COMM_LAST_DATA		0x01C0	// memory pointer for xmem
#define COMM_CTRL_REG_ADDR	0x01BC	// Address for COMM_RD/WR_CTRL_REG
#define COMM_CTRL_REG_DATA	0x01BE	// Address for COMM_RD/WR_CTRL_REG
#define COMM_CTRL_REG_LOGIC	0x01C0	// Address used for AND/OR
#define REG_WRITE_FLG		0x0000	// Value for COMM_CTRL_REG_LOGIC
#define REG_AND_FLG			0x0001	// Value for COMM_CTRL_REG_LOGIC
#define REG_OR_FLG			0x0002	// Value for COMM_CTRL_REG_LOGIC
#define COMM_TIMEOUT		0x01BE	// Address setting Timeout for sending response to host
#define COMM_CODE_ADDR		0x01BC	// Address for COMM_CALL_CODE and COMM_JUMP2CODE
#define COMM_INT_NUM		0x01C2	// Address used for COMM_EXEC_INT
#define COMM_R0				0x01C4	// CY16-R0 register
#define COMM_R1				0x01C6	// CY16-R1 register
#define COMM_R2				0x01C8	// CY16-R2 register
#define COMM_R3				0x01CA	// CY16-R3 register
#define COMM_R4				0x01CC	// CY16-R4 register
#define COMM_R5				0x01CE	// CY16-R5 register
#define COMM_R6				0x01D0	// CY16-R6 register
#define COMM_R7				0x01D2	// CY16-R7 register
#define COMM_R8				0x01D4	// CY16-R8 register
#define COMM_R9				0x01D6	// CY16-R9 register
#define COMM_R10			0x01D8	// CY16-R10 register
#define COMM_R11			0x01DA	// CY16-R11 register
#define COMM_R12			0x01DC	// CY16-R12 register
#define COMM_R13			0x01DE	// CY16-R13 register

// for COMM_CTRL_REG_LOGIC
#define	LOGIC_DIRECT		0
#define	LOGIC_AND			1
#define	LOGIC_OR			2

// ---------------------------------------------------------
// Software interrupts
#define	SUSB_INIT_INT							113
// USB 1
#define	SUSB1_DEVICE_DESCRIPTOR_VEC				90
#define	SUSB1_CONFIGURATION_DESCRIPTOR_VEC		91
#define	SUSB1_STRING_DESCRIPTOR_VEC				92
#define	SUSB1_FINISH_INT						89
#define	SUSB1_STALL_INT							82
#define	SUSB1_STANDARD_INT						83
#define	SUSB1_SEND_INT							80
#define	SUSB1_RECEIVE_INT						81
#define	SUSB1_VENDOR_INT						85
#define	SUSB1_CLASS_INT							87
#define	SUSB1_LOADER_INT						94
#define	SUSB1_DELTA_CONFIG_INT					95

// USB 2
#define	SUSB2_DEVICE_DESCRIPTOR_VEC				106
#define	SUSB2_CONFIGURATION_DESCRIPTOR_VEC		107
#define	SUSB2_STRING_DESCRIPTOR_VEC				108
#define	SUSB2_FINISH_INT						105
#define	SUSB2_STALL_INT							98
#define	SUSB2_STANDARD_INT						99
#define	SUSB2_SEND_INT							96
#define	SUSB2_RECEIVE_INT						97
#define	SUSB2_VENDOR_INT						101
#define	SUSB2_CLASS_INT							103
#define	SUSB2_LOADER_INT						110
#define	SUSB2_DELTA_CONFIG_INT					111

// ---------------------------------------------------------
// General USB Registers
#define	USB_REG_FLAGS							0xC000	// CPU Flags
#define	USB_REG_BANK							0xC002	// Register Bank
#define	USB_REG_REVISON							0xC004	// Hardware Revision
#define	USB_REG_SPEED							0xC008	// CPU Speed
#define	USB_REG_PWRCTRL							0xC00A	// Power Control
#define	USB_REG_INTEN							0xC00E	// Interrupt Enable
#define	USB_REG_BP								0xC014	// Breakpoint
#define	USB_REG_USBDIAG							0xC03C	// USB Diagnostic
#define	USB_REG_MEMDIAG							0xC03E	// Memory Diagnostic

// HPI registers
#define	HPI_REG_BP								0x0140	// HPI Breakpoint
#define	HPI_REG_INTROUTE						0x0142	// Interrupt Routing
#define	HPI_REG_SIE1MSG							0x0144	// SIE1msg
#define	HPI_REG_SIE2MSG							0x0148	// SIE2msg
#define	HPI_REG_MAILBOX							0xC0C6	// HPI Mailbox

// ---------------------------------------------------------
// General Device Registers
// Device 1
#define	SUSB1_REG_PORTSEL						0xC084	// Port select
#define	SUSB1_REG_USBCTRL						0xC08A	// USB control
#define	SUSB1_REG_INTEN							0xC08C	// Interrupt enable
#define	SUSB1_REG_ADDR							0xC08E	// Address
#define	SUSB1_REG_STATUS						0xC090	// Status
#define	SUSB1_REG_FRAMENUM						0xC092	// Frame number
#define	SUSB1_REG_SOFEOPCNT						0xC094	// SOF/EOP count

// Device 2
#define	SUSB2_REG_PORTSEL						0xC0A4	// Port select
#define	SUSB2_REG_USBCTRL						0xC0AA	// USB control
#define	SUSB2_REG_INTEN							0xC0AC	// Interrupt enable
#define	SUSB2_REG_ADDR							0xC0AE	// Address
#define	SUSB2_REG_STATUS						0xC0B0	// Status
#define	SUSB2_REG_FRAMENUM						0xC0B2	// Frame number
#define	SUSB2_REG_SOFEOPCNT						0xC0B4	// SOF/EOP count

// ---------------------------------------------------------
// Endpoint Registers
// Device 1 Control
#define	SUSB1_REG_EP_CTRL0						0x0200
#define	SUSB1_REG_EP_CTRL1						0x0210
#define	SUSB1_REG_EP_CTRL2						0x0220
#define	SUSB1_REG_EP_CTRL3						0x0230
#define	SUSB1_REG_EP_CTRL4						0x0240
#define	SUSB1_REG_EP_CTRL5						0x0250
#define	SUSB1_REG_EP_CTRL6						0x0260
#define	SUSB1_REG_EP_CTRL7						0x0270
// Device 1 Address
#define	SUSB1_REG_EP_ADDR0						0x0202
#define	SUSB1_REG_EP_ADDR1						0x0212
#define	SUSB1_REG_EP_ADDR2						0x0222
#define	SUSB1_REG_EP_ADDR3						0x0232
#define	SUSB1_REG_EP_ADDR4						0x0242
#define	SUSB1_REG_EP_ADDR5						0x0252
#define	SUSB1_REG_EP_ADDR6						0x0262
#define	SUSB1_REG_EP_ADDR7						0x0272
// Device 1 Count
#define	SUSB1_REG_EP_COUNT0						0x0204
#define	SUSB1_REG_EP_COUNT1						0x0214
#define	SUSB1_REG_EP_COUNT2						0x0224
#define	SUSB1_REG_EP_COUNT3						0x0234
#define	SUSB1_REG_EP_COUNT4						0x0244
#define	SUSB1_REG_EP_COUNT5						0x0254
#define	SUSB1_REG_EP_COUNT6						0x0264
#define	SUSB1_REG_EP_COUNT7						0x0274
// Device 1 Status
#define	SUSB1_REG_EP_STATUS0					0x0206
#define	SUSB1_REG_EP_STATUS1					0x0216
#define	SUSB1_REG_EP_STATUS2					0x0226
#define	SUSB1_REG_EP_STATUS3					0x0236
#define	SUSB1_REG_EP_STATUS4					0x0246
#define	SUSB1_REG_EP_STATUS5					0x0256
#define	SUSB1_REG_EP_STATUS6					0x0266
#define	SUSB1_REG_EP_STATUS7					0x0276
// Device 1 Count result
#define	SUSB1_REG_EP_CNTRES0					0x0208
#define	SUSB1_REG_EP_CNTRES1					0x0218
#define	SUSB1_REG_EP_CNTRES2					0x0228
#define	SUSB1_REG_EP_CNTRES3					0x0238
#define	SUSB1_REG_EP_CNTRES4					0x0248
#define	SUSB1_REG_EP_CNTRES5					0x0258
#define	SUSB1_REG_EP_CNTRES6					0x0268
#define	SUSB1_REG_EP_CNTRES7					0x0278

// Device 2 Control
#define	SUSB2_REG_EP_CTRL0						0x0280
#define	SUSB2_REG_EP_CTRL1						0x0290
#define	SUSB2_REG_EP_CTRL2						0x02A0
#define	SUSB2_REG_EP_CTRL3						0x02B0
#define	SUSB2_REG_EP_CTRL4						0x02C0
#define	SUSB2_REG_EP_CTRL5						0x02D0
#define	SUSB2_REG_EP_CTRL6						0x02E0
#define	SUSB2_REG_EP_CTRL7						0x02F0
// Device 2 Address
#define	SUSB2_REG_EP_ADDR0						0x0282
#define	SUSB2_REG_EP_ADDR1						0x0292
#define	SUSB2_REG_EP_ADDR2						0x02A2
#define	SUSB2_REG_EP_ADDR3						0x02B2
#define	SUSB2_REG_EP_ADDR4						0x02C2
#define	SUSB2_REG_EP_ADDR5						0x02D2
#define	SUSB2_REG_EP_ADDR6						0x02E2
#define	SUSB2_REG_EP_ADDR7						0x02F2
// Device 2 Count
#define	SUSB2_REG_EP_COUNT0						0x0284
#define	SUSB2_REG_EP_COUNT1						0x0294
#define	SUSB2_REG_EP_COUNT2						0x02A4
#define	SUSB2_REG_EP_COUNT3						0x02B4
#define	SUSB2_REG_EP_COUNT4						0x02C4
#define	SUSB2_REG_EP_COUNT5						0x02D4
#define	SUSB2_REG_EP_COUNT6						0x02E4
#define	SUSB2_REG_EP_COUNT7						0x02F4
// Device 2 Status
#define	SUSB2_REG_EP_STATUS0					0x0286
#define	SUSB2_REG_EP_STATUS1					0x0296
#define	SUSB2_REG_EP_STATUS2					0x02A6
#define	SUSB2_REG_EP_STATUS3					0x02B6
#define	SUSB2_REG_EP_STATUS4					0x02C6
#define	SUSB2_REG_EP_STATUS5					0x02D6
#define	SUSB2_REG_EP_STATUS6					0x02E6
#define	SUSB2_REG_EP_STATUS7					0x02F6
// Device 2 Count result
#define	SUSB2_REG_EP_CNTRES0					0x0288
#define	SUSB2_REG_EP_CNTRES1					0x0298
#define	SUSB2_REG_EP_CNTRES2					0x02A8
#define	SUSB2_REG_EP_CNTRES3					0x02B8
#define	SUSB2_REG_EP_CNTRES4					0x02C8
#define	SUSB2_REG_EP_CNTRES5					0x02D8
#define	SUSB2_REG_EP_CNTRES6					0x02E8
#define	SUSB2_REG_EP_CNTRES7					0x02F8

// ---------------------------------------------------------
// others
#define HUSB_TDLISTDONE		0x1000
#define HUSB_SOF			0x2000
#define HUSB_ARMV			0x0001
#define HUSB_AINS_FS		0x0002
#define HUSB_AINS_LS		0x0004
#define HUSB_AWAKEUP		0x0008
#define HUSB_BRMV			0x0010
#define HUSB_BINS_FS		0x0020
#define HUSB_BINS_LS		0x0040
#define HUSB_BWAKEUP		0x0080

#define SUSB_EP0_MSG		0x0001
#define SUSB_EP1_MSG		0x0002
#define SUSB_EP2_MSG		0x0004
#define SUSB_EP3_MSG		0x0008
#define SUSB_EP4_MSG		0x0010
#define SUSB_EP5_MSG		0x0020
#define SUSB_EP6_MSG		0x0040
#define SUSB_EP7_MSG		0x0080
#define SUSB_RST_MSG		0x0100
#define SUSB_SOF_MSG		0x0200
#define SUSB_CFG_MSG		0x0400
#define SUSB_SUS_MSG		0x0800
#define SUSB_ID_MSG			0x4000
#define SUSB_VBUS_MSG		0x8000

// ---------------------------------------------------------
// Functions
// ---------------------------------------------------------

// HPI low-level routines
void cy67k3_isr(void);
void cy67k3_reset(void);
UINT16 cy67k3_read_HPI_DATA(void);
UINT16 cy67k3_read_HPI_MAILBOX(void);
UINT16 cy67k3_read_HPI_ADDRESS(void);
UINT16 cy67k3_read_HPI_STATUS(void);
void cy67k3_write_HPI_DATA(UINT16 data);
void cy67k3_write_HPI_MAILBOX(UINT16 data);
void cy67k3_write_HPI_ADDRESS(UINT16 data);
void cy67k3_write_HPI_STATUS(UINT16 data);

// HPI API
UINT32 hpi_init(void);
void hpi_mbx_write(UINT16 msgcode);
UINT32 hpi_mbx_read(void);
UINT32 hpi_read_reg(UINT16 addr);
UINT32 hpi_write_reg(UINT16 addr, UINT16 data);
UINT32 hpi_write_ram(UINT16 addr, UINT16 *pData, UINT32 num_words);
UINT32 hpi_read_ram(UINT16 addr, UINT16 *pData, UINT32 num_words);
UINT32 hpi_comm_reset(void);
UINT32 hpi_comm_jump2code(UINT16 addr);
UINT32 hpi_comm_callcode(UINT16 addr);
UINT32 hpi_comm_write_ctrl_reg(UINT16 addr, UINT16 data, UINT16 logic);
UINT32 hpi_comm_read_ctrl_reg(UINT16 addr);
UINT32 hpi_comm_write_xmem(UINT16 addr, UINT8 *pData, UINT16 len);
UINT32 hpi_comm_read_xmem(UINT16 addr, UINT8 *pData, UINT16 len);
UINT32 hpi_comm_exec_int(UINT16 intnum, UINT32 nargs, ...);

// USB API
UINT32 usb_init(void);
UINT32 usb_irp_register(usb_irp_t *pIRP, UINT32 port, UINT32 ept, UINT32 size, UINT32 is_out);
UINT32 usb_irp_enqueue(usb_irp_t *pIRP);
UINT32 usb_callback_register(UINT32 port, UINT32 type, fp_t pFunc, void *pArg);

#define	FIFO_BLOCK		1
#define	FIFO_NONBLOCK	0
UINT32 fifo_alloc(fifo_t *pObj, UINT32 size);
UINT32 fifo_free(fifo_t *pObj);
UINT32 fifo_flush(fifo_t *pObj);
UINT32 fifo_is_full(fifo_t *pObj);
UINT32 fifo_is_empty(fifo_t *pObj);
UINT32 fifo_read(fifo_t *pObj, UINT8 *pData, UINT32 size, UINT32 timeout, UINT32 do_block);
UINT32 fifo_write(fifo_t *pObj, UINT8 *pData, UINT32 size, UINT32 timeout, UINT32 do_block);

#endif // HPI_H
