1e1a08f23SMarkus Pfeiffer /* $FreeBSD: head/sys/dev/usb/controller/uhci.h 228483 2011-12-14 00:28:54Z hselasky $ */ 212bd3c8bSSascha Wildner /*- 312bd3c8bSSascha Wildner * Copyright (c) 1998 The NetBSD Foundation, Inc. 412bd3c8bSSascha Wildner * All rights reserved. 512bd3c8bSSascha Wildner * 612bd3c8bSSascha Wildner * This code is derived from software contributed to The NetBSD Foundation 712bd3c8bSSascha Wildner * by Lennart Augustsson (lennart@augustsson.net) at 812bd3c8bSSascha Wildner * Carlstedt Research & Technology. 912bd3c8bSSascha Wildner * 1012bd3c8bSSascha Wildner * Redistribution and use in source and binary forms, with or without 1112bd3c8bSSascha Wildner * modification, are permitted provided that the following conditions 1212bd3c8bSSascha Wildner * are met: 1312bd3c8bSSascha Wildner * 1. Redistributions of source code must retain the above copyright 1412bd3c8bSSascha Wildner * notice, this list of conditions and the following disclaimer. 1512bd3c8bSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright 1612bd3c8bSSascha Wildner * notice, this list of conditions and the following disclaimer in the 1712bd3c8bSSascha Wildner * documentation and/or other materials provided with the distribution. 1812bd3c8bSSascha Wildner * 1912bd3c8bSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2012bd3c8bSSascha Wildner * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2112bd3c8bSSascha Wildner * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2212bd3c8bSSascha Wildner * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2312bd3c8bSSascha Wildner * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2412bd3c8bSSascha Wildner * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2512bd3c8bSSascha Wildner * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2612bd3c8bSSascha Wildner * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2712bd3c8bSSascha Wildner * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2812bd3c8bSSascha Wildner * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2912bd3c8bSSascha Wildner * POSSIBILITY OF SUCH DAMAGE. 3012bd3c8bSSascha Wildner */ 3112bd3c8bSSascha Wildner 3212bd3c8bSSascha Wildner #ifndef _UHCI_H_ 3312bd3c8bSSascha Wildner #define _UHCI_H_ 3412bd3c8bSSascha Wildner 3512bd3c8bSSascha Wildner #define UHCI_MAX_DEVICES MIN(USB_MAX_DEVICES, 128) 3612bd3c8bSSascha Wildner 3712bd3c8bSSascha Wildner #define UHCI_FRAMELIST_COUNT 1024 /* units */ 3812bd3c8bSSascha Wildner #define UHCI_FRAMELIST_ALIGN 4096 /* bytes */ 3912bd3c8bSSascha Wildner 4012bd3c8bSSascha Wildner /* Structures alignment (bytes) */ 4112bd3c8bSSascha Wildner #define UHCI_TD_ALIGN 16 4212bd3c8bSSascha Wildner #define UHCI_QH_ALIGN 16 4312bd3c8bSSascha Wildner 4412bd3c8bSSascha Wildner #if ((USB_PAGE_SIZE < UHCI_TD_ALIGN) || (UHCI_TD_ALIGN == 0) || \ 4512bd3c8bSSascha Wildner (USB_PAGE_SIZE < UHCI_QH_ALIGN) || (UHCI_QH_ALIGN == 0)) 4612bd3c8bSSascha Wildner #error "Invalid USB page size!" 4712bd3c8bSSascha Wildner #endif 4812bd3c8bSSascha Wildner 4912bd3c8bSSascha Wildner typedef uint32_t uhci_physaddr_t; 5012bd3c8bSSascha Wildner 5112bd3c8bSSascha Wildner #define UHCI_PTR_T 0x00000001 5212bd3c8bSSascha Wildner #define UHCI_PTR_TD 0x00000000 5312bd3c8bSSascha Wildner #define UHCI_PTR_QH 0x00000002 5412bd3c8bSSascha Wildner #define UHCI_PTR_VF 0x00000004 5512bd3c8bSSascha Wildner 5612bd3c8bSSascha Wildner /* 5712bd3c8bSSascha Wildner * The Queue Heads (QH) and Transfer Descriptors (TD) are accessed by 5812bd3c8bSSascha Wildner * both the CPU and the USB-controller which run concurrently. Great 5912bd3c8bSSascha Wildner * care must be taken. When the data-structures are linked into the 6012bd3c8bSSascha Wildner * USB controller's frame list, the USB-controller "owns" the 6112bd3c8bSSascha Wildner * td_status and qh_elink fields, which will not be written by the 6212bd3c8bSSascha Wildner * CPU. 6312bd3c8bSSascha Wildner * 6412bd3c8bSSascha Wildner */ 6512bd3c8bSSascha Wildner 6612bd3c8bSSascha Wildner struct uhci_td { 6712bd3c8bSSascha Wildner /* 6812bd3c8bSSascha Wildner * Data used by the UHCI controller. 6912bd3c8bSSascha Wildner * volatile is used in order to mantain struct members ordering. 7012bd3c8bSSascha Wildner */ 7112bd3c8bSSascha Wildner volatile uint32_t td_next; 7212bd3c8bSSascha Wildner volatile uint32_t td_status; 7312bd3c8bSSascha Wildner #define UHCI_TD_GET_ACTLEN(s) (((s) + 1) & 0x3ff) 7412bd3c8bSSascha Wildner #define UHCI_TD_ZERO_ACTLEN(t) ((t) | 0x3ff) 7512bd3c8bSSascha Wildner #define UHCI_TD_BITSTUFF 0x00020000 7612bd3c8bSSascha Wildner #define UHCI_TD_CRCTO 0x00040000 7712bd3c8bSSascha Wildner #define UHCI_TD_NAK 0x00080000 7812bd3c8bSSascha Wildner #define UHCI_TD_BABBLE 0x00100000 7912bd3c8bSSascha Wildner #define UHCI_TD_DBUFFER 0x00200000 8012bd3c8bSSascha Wildner #define UHCI_TD_STALLED 0x00400000 8112bd3c8bSSascha Wildner #define UHCI_TD_ACTIVE 0x00800000 8212bd3c8bSSascha Wildner #define UHCI_TD_IOC 0x01000000 8312bd3c8bSSascha Wildner #define UHCI_TD_IOS 0x02000000 8412bd3c8bSSascha Wildner #define UHCI_TD_LS 0x04000000 8512bd3c8bSSascha Wildner #define UHCI_TD_GET_ERRCNT(s) (((s) >> 27) & 3) 8612bd3c8bSSascha Wildner #define UHCI_TD_SET_ERRCNT(n) ((n) << 27) 8712bd3c8bSSascha Wildner #define UHCI_TD_SPD 0x20000000 8812bd3c8bSSascha Wildner volatile uint32_t td_token; 8912bd3c8bSSascha Wildner #define UHCI_TD_PID 0x000000ff 9012bd3c8bSSascha Wildner #define UHCI_TD_PID_IN 0x00000069 9112bd3c8bSSascha Wildner #define UHCI_TD_PID_OUT 0x000000e1 9212bd3c8bSSascha Wildner #define UHCI_TD_PID_SETUP 0x0000002d 9312bd3c8bSSascha Wildner #define UHCI_TD_GET_PID(s) ((s) & 0xff) 9412bd3c8bSSascha Wildner #define UHCI_TD_SET_DEVADDR(a) ((a) << 8) 9512bd3c8bSSascha Wildner #define UHCI_TD_GET_DEVADDR(s) (((s) >> 8) & 0x7f) 9612bd3c8bSSascha Wildner #define UHCI_TD_SET_ENDPT(e) (((e) & 0xf) << 15) 9712bd3c8bSSascha Wildner #define UHCI_TD_GET_ENDPT(s) (((s) >> 15) & 0xf) 9812bd3c8bSSascha Wildner #define UHCI_TD_SET_DT(t) ((t) << 19) 9912bd3c8bSSascha Wildner #define UHCI_TD_GET_DT(s) (((s) >> 19) & 1) 10012bd3c8bSSascha Wildner #define UHCI_TD_SET_MAXLEN(l) (((l)-1) << 21) 10112bd3c8bSSascha Wildner #define UHCI_TD_GET_MAXLEN(s) ((((s) >> 21) + 1) & 0x7ff) 10212bd3c8bSSascha Wildner #define UHCI_TD_MAXLEN_MASK 0xffe00000 10312bd3c8bSSascha Wildner volatile uint32_t td_buffer; 10412bd3c8bSSascha Wildner /* 10512bd3c8bSSascha Wildner * Extra information needed: 10612bd3c8bSSascha Wildner */ 10712bd3c8bSSascha Wildner struct uhci_td *next; 10812bd3c8bSSascha Wildner struct uhci_td *prev; 10912bd3c8bSSascha Wildner struct uhci_td *obj_next; 11012bd3c8bSSascha Wildner struct usb_page_cache *page_cache; 11112bd3c8bSSascha Wildner struct usb_page_cache *fix_pc; 11212bd3c8bSSascha Wildner uint32_t td_self; 11312bd3c8bSSascha Wildner uint16_t len; 11412bd3c8bSSascha Wildner } __aligned(UHCI_TD_ALIGN); 11512bd3c8bSSascha Wildner 11612bd3c8bSSascha Wildner typedef struct uhci_td uhci_td_t; 11712bd3c8bSSascha Wildner 11812bd3c8bSSascha Wildner #define UHCI_TD_ERROR (UHCI_TD_BITSTUFF | UHCI_TD_CRCTO | \ 11912bd3c8bSSascha Wildner UHCI_TD_BABBLE | UHCI_TD_DBUFFER | UHCI_TD_STALLED) 12012bd3c8bSSascha Wildner 12112bd3c8bSSascha Wildner #define UHCI_TD_SETUP(len, endp, dev) (UHCI_TD_SET_MAXLEN(len) | \ 12212bd3c8bSSascha Wildner UHCI_TD_SET_ENDPT(endp) | \ 12312bd3c8bSSascha Wildner UHCI_TD_SET_DEVADDR(dev) | \ 12412bd3c8bSSascha Wildner UHCI_TD_PID_SETUP) 12512bd3c8bSSascha Wildner 12612bd3c8bSSascha Wildner #define UHCI_TD_OUT(len, endp, dev, dt) (UHCI_TD_SET_MAXLEN(len) | \ 12712bd3c8bSSascha Wildner UHCI_TD_SET_ENDPT(endp) | \ 12812bd3c8bSSascha Wildner UHCI_TD_SET_DEVADDR(dev) | \ 12912bd3c8bSSascha Wildner UHCI_TD_PID_OUT | UHCI_TD_SET_DT(dt)) 13012bd3c8bSSascha Wildner 13112bd3c8bSSascha Wildner #define UHCI_TD_IN(len, endp, dev, dt) (UHCI_TD_SET_MAXLEN(len) | \ 13212bd3c8bSSascha Wildner UHCI_TD_SET_ENDPT(endp) | \ 13312bd3c8bSSascha Wildner UHCI_TD_SET_DEVADDR(dev) | \ 13412bd3c8bSSascha Wildner UHCI_TD_PID_IN | UHCI_TD_SET_DT(dt)) 13512bd3c8bSSascha Wildner 13612bd3c8bSSascha Wildner struct uhci_qh { 13712bd3c8bSSascha Wildner /* 13812bd3c8bSSascha Wildner * Data used by the UHCI controller. 13912bd3c8bSSascha Wildner */ 14012bd3c8bSSascha Wildner volatile uint32_t qh_h_next; 14112bd3c8bSSascha Wildner volatile uint32_t qh_e_next; 14212bd3c8bSSascha Wildner /* 14312bd3c8bSSascha Wildner * Extra information needed: 14412bd3c8bSSascha Wildner */ 14512bd3c8bSSascha Wildner struct uhci_qh *h_next; 14612bd3c8bSSascha Wildner struct uhci_qh *h_prev; 14712bd3c8bSSascha Wildner struct uhci_qh *obj_next; 14812bd3c8bSSascha Wildner struct uhci_td *e_next; 14912bd3c8bSSascha Wildner struct usb_page_cache *page_cache; 15012bd3c8bSSascha Wildner uint32_t qh_self; 15112bd3c8bSSascha Wildner uint16_t intr_pos; 15212bd3c8bSSascha Wildner } __aligned(UHCI_QH_ALIGN); 15312bd3c8bSSascha Wildner 15412bd3c8bSSascha Wildner typedef struct uhci_qh uhci_qh_t; 15512bd3c8bSSascha Wildner 15612bd3c8bSSascha Wildner /* Maximum number of isochronous TD's and QH's interrupt */ 15712bd3c8bSSascha Wildner #define UHCI_VFRAMELIST_COUNT 128 15812bd3c8bSSascha Wildner #define UHCI_IFRAMELIST_COUNT (2 * UHCI_VFRAMELIST_COUNT) 15912bd3c8bSSascha Wildner 16012bd3c8bSSascha Wildner #if (((UHCI_VFRAMELIST_COUNT & (UHCI_VFRAMELIST_COUNT-1)) != 0) || \ 16112bd3c8bSSascha Wildner (UHCI_VFRAMELIST_COUNT > UHCI_FRAMELIST_COUNT)) 16212bd3c8bSSascha Wildner #error "UHCI_VFRAMELIST_COUNT is not power of two" 16312bd3c8bSSascha Wildner #error "or UHCI_VFRAMELIST_COUNT > UHCI_FRAMELIST_COUNT" 16412bd3c8bSSascha Wildner #endif 16512bd3c8bSSascha Wildner 16612bd3c8bSSascha Wildner #if (UHCI_VFRAMELIST_COUNT < USB_MAX_FS_ISOC_FRAMES_PER_XFER) 16712bd3c8bSSascha Wildner #error "maximum number of full-speed isochronous frames is higher than supported!" 16812bd3c8bSSascha Wildner #endif 16912bd3c8bSSascha Wildner 17012bd3c8bSSascha Wildner struct uhci_config_desc { 17112bd3c8bSSascha Wildner struct usb_config_descriptor confd; 17212bd3c8bSSascha Wildner struct usb_interface_descriptor ifcd; 17312bd3c8bSSascha Wildner struct usb_endpoint_descriptor endpd; 17412bd3c8bSSascha Wildner } __packed; 17512bd3c8bSSascha Wildner 17612bd3c8bSSascha Wildner union uhci_hub_desc { 17712bd3c8bSSascha Wildner struct usb_status stat; 17812bd3c8bSSascha Wildner struct usb_port_status ps; 17912bd3c8bSSascha Wildner uint8_t temp[128]; 18012bd3c8bSSascha Wildner }; 18112bd3c8bSSascha Wildner 18212bd3c8bSSascha Wildner struct uhci_hw_softc { 18312bd3c8bSSascha Wildner struct usb_page_cache pframes_pc; 18412bd3c8bSSascha Wildner struct usb_page_cache isoc_start_pc[UHCI_VFRAMELIST_COUNT]; 18512bd3c8bSSascha Wildner struct usb_page_cache intr_start_pc[UHCI_IFRAMELIST_COUNT]; 18612bd3c8bSSascha Wildner struct usb_page_cache ls_ctl_start_pc; 18712bd3c8bSSascha Wildner struct usb_page_cache fs_ctl_start_pc; 18812bd3c8bSSascha Wildner struct usb_page_cache bulk_start_pc; 18912bd3c8bSSascha Wildner struct usb_page_cache last_qh_pc; 19012bd3c8bSSascha Wildner struct usb_page_cache last_td_pc; 19112bd3c8bSSascha Wildner 19212bd3c8bSSascha Wildner struct usb_page pframes_pg; 19312bd3c8bSSascha Wildner struct usb_page isoc_start_pg[UHCI_VFRAMELIST_COUNT]; 19412bd3c8bSSascha Wildner struct usb_page intr_start_pg[UHCI_IFRAMELIST_COUNT]; 19512bd3c8bSSascha Wildner struct usb_page ls_ctl_start_pg; 19612bd3c8bSSascha Wildner struct usb_page fs_ctl_start_pg; 19712bd3c8bSSascha Wildner struct usb_page bulk_start_pg; 19812bd3c8bSSascha Wildner struct usb_page last_qh_pg; 19912bd3c8bSSascha Wildner struct usb_page last_td_pg; 20012bd3c8bSSascha Wildner }; 20112bd3c8bSSascha Wildner 20212bd3c8bSSascha Wildner typedef struct uhci_softc { 20312bd3c8bSSascha Wildner struct uhci_hw_softc sc_hw; 20412bd3c8bSSascha Wildner struct usb_bus sc_bus; /* base device */ 20512bd3c8bSSascha Wildner union uhci_hub_desc sc_hub_desc; 20612bd3c8bSSascha Wildner struct usb_callout sc_root_intr; 20712bd3c8bSSascha Wildner 20812bd3c8bSSascha Wildner struct usb_device *sc_devices[UHCI_MAX_DEVICES]; 20912bd3c8bSSascha Wildner /* pointer to last TD for isochronous */ 21012bd3c8bSSascha Wildner struct uhci_td *sc_isoc_p_last[UHCI_VFRAMELIST_COUNT]; 21112bd3c8bSSascha Wildner /* pointer to last QH for interrupt */ 21212bd3c8bSSascha Wildner struct uhci_qh *sc_intr_p_last[UHCI_IFRAMELIST_COUNT]; 21312bd3c8bSSascha Wildner /* pointer to last QH for low speed control */ 21412bd3c8bSSascha Wildner struct uhci_qh *sc_ls_ctl_p_last; 21512bd3c8bSSascha Wildner /* pointer to last QH for full speed control */ 21612bd3c8bSSascha Wildner struct uhci_qh *sc_fs_ctl_p_last; 21712bd3c8bSSascha Wildner /* pointer to last QH for bulk */ 21812bd3c8bSSascha Wildner struct uhci_qh *sc_bulk_p_last; 21912bd3c8bSSascha Wildner struct uhci_qh *sc_reclaim_qh_p; 22012bd3c8bSSascha Wildner struct uhci_qh *sc_last_qh_p; 22112bd3c8bSSascha Wildner struct uhci_td *sc_last_td_p; 22212bd3c8bSSascha Wildner struct resource *sc_io_res; 22312bd3c8bSSascha Wildner struct resource *sc_irq_res; 22412bd3c8bSSascha Wildner void *sc_intr_hdl; 22512bd3c8bSSascha Wildner device_t sc_dev; 22612bd3c8bSSascha Wildner bus_size_t sc_io_size; 22712bd3c8bSSascha Wildner bus_space_tag_t sc_io_tag; 22812bd3c8bSSascha Wildner bus_space_handle_t sc_io_hdl; 22912bd3c8bSSascha Wildner 23012bd3c8bSSascha Wildner uint32_t sc_loops; /* number of QHs that wants looping */ 23112bd3c8bSSascha Wildner 23212bd3c8bSSascha Wildner uint16_t sc_intr_stat[UHCI_IFRAMELIST_COUNT]; 23312bd3c8bSSascha Wildner 23412bd3c8bSSascha Wildner uint8_t sc_addr; /* device address */ 23512bd3c8bSSascha Wildner uint8_t sc_conf; /* device configuration */ 236*54b047d4SMatthew Dillon uint8_t sc_didinit; /* uchi_init() called */ 23712bd3c8bSSascha Wildner uint8_t sc_isreset; /* bits set if a root hub is reset */ 23812bd3c8bSSascha Wildner uint8_t sc_isresumed; /* bits set if a port was resumed */ 23912bd3c8bSSascha Wildner uint8_t sc_hub_idata[1]; 24012bd3c8bSSascha Wildner 24112bd3c8bSSascha Wildner char sc_vendor[16]; /* vendor string for root hub */ 24212bd3c8bSSascha Wildner } uhci_softc_t; 24312bd3c8bSSascha Wildner 24412bd3c8bSSascha Wildner usb_bus_mem_cb_t uhci_iterate_hw_softc; 24512bd3c8bSSascha Wildner 24612bd3c8bSSascha Wildner usb_error_t uhci_init(uhci_softc_t *sc); 24712bd3c8bSSascha Wildner void uhci_reset(uhci_softc_t *sc); 24812bd3c8bSSascha Wildner void uhci_interrupt(uhci_softc_t *sc); 24912bd3c8bSSascha Wildner 25012bd3c8bSSascha Wildner #endif /* _UHCI_H_ */ 251