/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_USB_UHCI_H
#define _SYS_USB_UHCI_H
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Universal Host Controller Driver (UHCI)
*
* The UHCI driver is a driver which interfaces to the Universal
* Serial Bus Driver (USBA) and the Host Controller (HC). The interface to
* the Host Controller is defined by the Universal Host Controller
* Interface spec.
*/
#define LEGACYMODE_REG_OFFSET 0xc0
#define LEGACYMODE_REG_INIT_VALUE 0xaf00
/*
* The register set of the UCHI controller
* This structure is laid out for proper alignment so no need to pack(1).
*/
typedef volatile struct hcr_regs {
uint16_t USBCMD;
uint16_t USBSTS;
uint16_t USBINTR;
uint16_t FRNUM;
uint32_t FRBASEADD;
uchar_t SOFMOD;
uchar_t rsvd[3];
uint16_t PORTSC[2];
} hc_regs_t;
/*
* #defines for the USB Command Register
*/
#define USBCMD_REG_MAXPKT_64 0x0080
#define USBCMD_REG_CONFIG_FLAG 0x0040
#define USBCMD_REG_SW_DEBUG 0x0020
#define USBCMD_REG_FGBL_RESUME 0x0010
#define USBCMD_REG_ENTER_GBL_SUSPEND 0x0008
#define USBCMD_REG_GBL_RESET 0x0004
#define USBCMD_REG_HC_RESET 0x0002
#define USBCMD_REG_HC_RUN 0x0001
/*
* #defines for the USB Status Register
*/
#define USBSTS_REG_HC_HALTED 0x0020
#define USBSTS_REG_HC_PROCESS_ERR 0x0010
#define USBSTS_REG_HOST_SYS_ERR 0x0008
#define USBSTS_REG_RESUME_DETECT 0x0004
#define USBSTS_REG_USB_ERR_INTR 0x0002
#define USBSTS_REG_USB_INTR 0x0001
/*
* #defines for the USB Root Hub Port Register
*/
#define HCR_PORT_CCS 0x1
#define HCR_PORT_CSC 0x2
#define HCR_PORT_ENABLE 0x4
#define HCR_PORT_ENDIS_CHG 0x8
#define HCR_PORT_LINE_STATSU 0x30
#define HCR_PORT_RESUME_DETECT 0x40
#define HCR_PORT_LSDA 0x100
#define HCR_PORT_RESET 0x200
#define HCR_PORT_SUSPEND 0x1000
/*
* #defines for USB Interrupt Enable Register
*/
#define USBINTR_REG_SPINT_EN 0x0008
#define USBINTR_REG_IOC_EN 0x0004
#define USBINTR_REG_RESUME_INT_EN 0x0002
#define USBINTR_REG_TOCRC_INT_EN 0x0001
#define ENABLE_ALL_INTRS 0x000F
#define DISABLE_ALL_INTRS 0x0000
#define UHCI_INTR_MASK 0x1f
#define SetReg32(hndl, addr, val) ddi_put32((hndl), \
&(addr), (val))
#define GetReg32(hndl, addr) ddi_get32((hndl), &(addr))
#define SetQH32(ucp, addr, val) \
SetReg32((ucp)->uhci_qh_pool_mem_handle, (addr), (val))
#define GetQH32(ucp, addr) \
GetReg32((ucp)->uhci_qh_pool_mem_handle, (addr))
#define SetTD32(ucp, addr, val) \
SetReg32((ucp)->uhci_td_pool_mem_handle, (addr), (val))
#define GetTD32(ucp, addr) \
GetReg32((ucp)->uhci_td_pool_mem_handle, (addr))
#define SetFL32(ucp, addr, val) \
SetReg32((ucp)->uhci_flt_mem_handle, (addr), (val))
#define GetFL32(ucp, addr) \
GetReg32((ucp)->uhci_flt_mem_handle, (addr))
/*
* UHCI Queue Head structure, aligned on 16 byte boundary
*/
typedef struct uhci_qh {
/* Hardware controlled bits */
uint32_t link_ptr; /* Next Queue Head / TD */
uint32_t element_ptr; /* Next queue head / TD */
/* Software controlled bits */
uint16_t node; /* Node that its attached */
uint16_t qh_flag; /* See below */
struct uhci_qh *prev_qh; /* Pointer to Prev queue head */
struct uhci_td *td_tailp; /* Pointer to the last TD of QH */
struct uhci_bulk_isoc_xfer_info *bulk_xfer_info;
uint64_t __pad1; /* align to 16 bytes */
} queue_head_t;
#define NUM_STATIC_NODES 63
#define NUM_INTR_QH_LISTS 64
#define NUM_FRAME_LST_ENTRIES 1024
#define TREE_HEIGHT 5
#define VIRTUAL_TREE_HEIGHT 5
#define SIZE_OF_FRAME_LST_TABLE 1024 * 4
#define HC_TD_HEAD 0x0
#define HC_QUEUE_HEAD 0x2
#define HC_DEPTH_FIRST 0x4
#define HC_END_OF_LIST 0x1
#define QUEUE_HEAD_FLAG_STATIC 0x1
#define QUEUE_HEAD_FLAG_FREE 0x2
#define QUEUE_HEAD_FLAG_BUSY 0x3
#define QH_LINK_PTR_MASK 0xFFFFFFF0
#define QH_ELEMENT_PTR_MASK 0xFFFFFFF0
#define FRAME_LST_PTR_MASK 0xFFFFFFF0
#define GetField(u, td, f, o, l) \
((GetTD32(u, (td)->f) >> (o)) & ((1U<<l)-1))
#define SetField(u, td, f, o, l, v) \
SetTD32(u, (td)->f, \
(GetTD32(u, (td)->f) & ~(((1U<<l)-1) << o)) | \
(((v) & ((1U<<l)-1)) << o))
#define GetTD_alen(u, td) GetField((u), (td), dw2, 0, 11)
#define GetTD_status(u, td) GetField((u), (td), dw2, 16, 8)
#define GetTD_ioc(u, td) GetField((u), (td), dw2, 24, 1)
#define GetTD_iso(u, td) GetField((u), (td), dw2, 25, 1)
#define GetTD_ls(u, td) GetField((u), (td), dw2, 26, 1)
#define GetTD_c_err(u, td) GetField((u), (td), dw2, 27, 2)
#define GetTD_spd(u, td) GetField((u), (td), dw2, 29, 1)
#define GetTD_PID(u, td) GetField((u), (td), dw3, 0, 8)
#define GetTD_devaddr(u, td) GetField((u), (td), dw3, 8, 7)
#define GetTD_endpt(u, td) GetField((u), (td), dw3, 15, 4)
#define GetTD_dtogg(u, td) GetField((u), (td), dw3, 19, 1)
#define GetTD_mlen(u, td) GetField((u), (td), dw3, 21, 11)
#define SetTD_alen(u, td, v) SetField((u), (td), dw2, 0, 11, (v))
#define SetTD_status(u, td, v) SetField((u), (td), dw2, 16, 8, (v))
#define SetTD_ioc(u, td, v) SetField((u), (td), dw2, 24, 1, (v))
#define SetTD_iso(u, td, v) SetField((u), (td), dw2, 25, 1, (v))
#define SetTD_ls(u, td, v) SetField((u), (td), dw2, 26, 1, (v))
#define SetTD_c_err(u, td, v) SetField((u), (td), dw2, 27, 2, (v))
#define SetTD_spd(u, td, v) SetField((u), (td), dw2, 29, 1, (v))
#define SetTD_PID(u, td, v) SetField((u), (td), dw3, 0, 8, (v))
#define SetTD_devaddr(u, td, v) SetField((u), (td), dw3, 8, 7, (v))
#define SetTD_endpt(u, td, v) SetField((u), (td), dw3, 15, 4, (v))
#define SetTD_dtogg(u, td, v) SetField((u), (td), dw3, 19, 1, (v))
#define SetTD_mlen(u, td, v) SetField((u), (td), dw3, 21, 11, (v))
/*
* UHCI Transfer Descriptor structure, aligned on 16 byte boundary
*/
typedef struct uhci_td {
/* Information required by HC for executing the request */
/* Pointer to the next TD/QH */
uint32_t link_ptr;
uint32_t dw2;
uint32_t dw3;
/* Data buffer address */
uint32_t buffer_address;
/* Information required by HCD for managing the request */
struct uhci_td *qh_td_prev;
struct uhci_td *tw_td_next;
struct uhci_td *outst_td_next;
struct uhci_td *outst_td_prev;
struct uhci_trans_wrapper *tw;
struct uhci_td *isoc_next;
struct uhci_td *isoc_prev;
ushort_t isoc_pkt_index;
ushort_t flag;
uint_t starting_frame;
uint_t _pad[3]; /* 16 byte alignment */
} uhci_td_t;
#define TD_FLAG_FREE 0x1
#define TD_FLAG_BUSY 0x2
#define TD_FLAG_DUMMY 0x3
#define INTERRUPT_ON_COMPLETION 0x1
#define END_POINT_ADDRESS_MASK 0xF
#define UHCI_MAX_ERR_COUNT 3
#define MAX_NUM_BULK_TDS_PER_XFER 128
/* section 3.2.2 of UHCI1.1 spec, bits 23:16 of status field */
#define UHCI_TD_ACTIVE 0x80
#define UHCI_TD_STALLED 0x40
#define UHCI_TD_DATA_BUFFER_ERR 0x20
#define UHCI_TD_BABBLE_ERR 0x10
#define UHCI_TD_NAK_RECEIVED 0x08
#define UHCI_TD_CRC_TIMEOUT 0x04
#define UHCI_TD_BITSTUFF_ERR 0x02
#define TD_INACTIVE 0x7F
#define TD_STATUS_MASK 0x76
#define ZERO_LENGTH 0x7FF
#define PID_SETUP 0x2D
#define PID_IN 0x69
#define PID_OUT 0xe1
#define SETUP_SIZE 8
#define SETUP 0x11
#define DATA 0x12
#define STATUS 0x13
#define UHCI_INVALID_PTR NULL
#define LOW_SPEED_DEVICE 1
/*
* These provide synchronization between TD deletions.
*/
#define UHCI_NOT_CLAIMED 0x0
#define UHCI_INTR_HDLR_CLAIMED 0x1
#define UHCI_MODIFY_TD_BITS_CLAIMED 0x2
#define UHCI_TIMEOUT_HDLR_CLAIMED 0x3
/*
* Structure for Bulk and Isoc TD pools
*/
typedef struct uhci_bulk_isoc_td_pool {
caddr_t pool_addr;
ddi_dma_cookie_t cookie; /* DMA cookie */
ddi_dma_handle_t dma_handle; /* DMA handle */
ddi_acc_handle_t mem_handle; /* Memory handle */
ushort_t num_tds;
} uhci_bulk_isoc_td_pool_t;
/*
* Structure for Bulk and Isoc transfers
*/
typedef struct uhci_bulk_isoc_xfer_info {
uhci_bulk_isoc_td_pool_t *td_pools;
ushort_t num_pools;
ushort_t num_tds;
} uhci_bulk_isoc_xfer_t;
/*
* Structure for Isoc DMA buffer
* One Isoc transfer includes multiple Isoc packets.
* One DMA buffer is allocated for one packet each.
*/
typedef struct uhci_isoc_buf {
caddr_t buf_addr; /* Starting buffer address */
ddi_dma_cookie_t cookie; /* DMA cookie */
ddi_dma_handle_t dma_handle; /* DMA handle */
ddi_acc_handle_t mem_handle; /* Memory handle */
size_t length; /* Buffer length */
ushort_t index;
} uhci_isoc_buf_t;
/*
* Macros related to ISOC transfers
*/
#define UHCI_SIZE_OF_HW_FRNUM 11
#define UHCI_BIT_10_MASK 0x400
#define UHCI_MAX_ISOC_FRAMES 1024
#define UHCI_MAX_ISOC_PKTS 256
#define UHCI_DEFAULT_ISOC_RCV_PKTS 1 /* isoc pkts per req */
#define FRNUM_MASK 0x3FF
#define SW_FRNUM_MASK 0xFFFFFFFFFFFFF800
#define INVALID_FRNUM 0
#define FRNUM_OFFSET 5
#define MAX_FRAME_NUM 1023
typedef uint32_t frame_lst_table_t;
/*
* Bandwidth allocation
* The following definitions are used during bandwidth
* calculations for a given endpoint maximum packet size.
*/
#define MAX_BUS_BANDWIDTH 1500 /* Up to 1500 bytes per frame */
#define MAX_POLL_INTERVAL 255 /* Maximum polling interval */
#define MIN_POLL_INTERVAL 1 /* Minimum polling interval */
#define SOF 6 /* Length in bytes of SOF */
#define EOF 2 /* Length in bytes of EOF */
/*
* Minimum polling interval for low speed endpoint
*
* According USB Specifications, a full-speed endpoint can specify
* a desired polling interval 1ms to 255ms and a low speed endpoints
* are limited to specifying only 10ms to 255ms. But some old keyboards
* and mice uses polling interval of 8ms. For compatibility purpose,
* we are using polling interval between 8ms and 255ms for low speed
* endpoints.
*/
#define MIN_LOW_SPEED_POLL_INTERVAL 8
/*
* For non-periodic transfers, reserve at least for one low-speed device
* transaction and according to USB Bandwidth Analysis white paper, it
* comes around 12% of USB frame time. Then periodic transfers will get
* 88% of USB frame time.
*/
#define MAX_PERIODIC_BANDWIDTH (((MAX_BUS_BANDWIDTH - SOF - EOF)*88)/100)
/*
* The following are the protocol overheads in terms of Bytes for the
* different transfer types. All these protocol overhead values are
* derived from the 5.9.3 section of USB Specification and with the
* help of Bandwidth Analysis white paper which is posted on the USB
* developer forum.
*/
#define FS_NON_ISOC_PROTO_OVERHEAD 14
#define FS_ISOC_INPUT_PROTO_OVERHEAD 11
#define FS_ISOC_OUTPUT_PROTO_OVERHEAD 10
#define LOW_SPEED_PROTO_OVERHEAD 97
#define HUB_LOW_SPEED_PROTO_OVERHEAD 01
/*
* The Host Controller (HC) delays are the USB host controller specific
* delays. The value shown below is the host controller delay for the
* Sand core USB host controller.
*/
#define HOST_CONTROLLER_DELAY 18
/*
* The low speed clock below represents that to transmit one low-speed
* bit takes eight times more than one full speed bit time.
*/
#define LOW_SPEED_CLOCK 8
/* the 16 byte alignment is required for every TD and QH start addr */
#define UHCI_QH_ALIGN_SZ 16
#define UHCI_TD_ALIGN_SZ 16
#ifdef __cplusplus
}
#endif
#endif /* _SYS_USB_UHCI_H */