/* * ADM5120 HCD (Host Controller Driver) for USB * * Copyright (C) 2007-2008 Gabor Juhos * * This file was derived from: drivers/usb/host/ohci.h * (C) Copyright 1999 Roman Weissgaerber * (C) Copyright 2000-2002 David Brownell * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * */ /* * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to * __leXX (normally) or __beXX (given OHCI_BIG_ENDIAN), depending on the * host controller implementation. */ typedef __u32 __bitwise __hc32; typedef __u16 __bitwise __hc16; /* * OHCI Endpoint Descriptor (ED) ... holds TD queue * See OHCI spec, section 4.2 * * This is a "Queue Head" for those transfers, which is why * both EHCI and UHCI call similar structures a "QH". */ #define TD_DATALEN_MAX 4096 #define ED_ALIGN 16 #define ED_MASK ((u32)~(ED_ALIGN-1)) /* strip hw status in low addr bits */ struct ed { /* first fields are hardware-specified */ __hc32 hwINFO; /* endpoint config bitmap */ /* info bits defined by hcd */ #define ED_DEQUEUE (1 << 27) /* info bits defined by the hardware */ #define ED_MPS_SHIFT 16 #define ED_MPS_MASK ((1 << 11)-1) #define ED_MPS_GET(x) (((x) >> ED_MPS_SHIFT) & ED_MPS_MASK) #define ED_ISO (1 << 15) /* isochronous endpoint */ #define ED_SKIP (1 << 14) #define ED_SPEED_FULL (1 << 13) /* fullspeed device */ #define ED_INT (1 << 11) /* interrupt endpoint */ #define ED_EN_SHIFT 7 /* endpoint shift */ #define ED_EN_MASK ((1 << 4)-1) /* endpoint mask */ #define ED_EN_GET(x) (((x) >> ED_EN_SHIFT) & ED_EN_MASK) #define ED_FA_MASK ((1 << 7)-1) /* function address mask */ #define ED_FA_GET(x) ((x) & ED_FA_MASK) __hc32 hwTailP; /* tail of TD list */ __hc32 hwHeadP; /* head of TD list (hc r/w) */ #define ED_C (0x02) /* toggle carry */ #define ED_H (0x01) /* halted */ __hc32 hwNextED; /* next ED in list */ /* rest are purely for the driver's use */ dma_addr_t dma; /* addr of ED */ struct td *dummy; /* next TD to activate */ struct list_head urb_list; /* list of our URBs */ /* host's view of schedule */ struct ed *ed_next; /* on schedule list */ struct ed *ed_prev; /* for non-interrupt EDs */ struct ed *ed_rm_next; /* on rm list */ struct list_head td_list; /* "shadow list" of our TDs */ /* create --> IDLE --> OPER --> ... --> IDLE --> destroy * usually: OPER --> UNLINK --> (IDLE | OPER) --> ... */ u8 state; /* ED_{IDLE,UNLINK,OPER} */ #define ED_IDLE 0x00 /* NOT linked to HC */ #define ED_UNLINK 0x01 /* being unlinked from hc */ #define ED_OPER 0x02 /* IS linked to hc */ u8 type; /* PIPE_{BULK,...} */ /* periodic scheduling params (for intr and iso) */ u8 branch; u16 interval; u16 load; u16 last_iso; /* iso only */ /* HC may see EDs on rm_list until next frame (frame_no == tick) */ u16 tick; } __attribute__ ((aligned(ED_ALIGN))); /* * OHCI Transfer Descriptor (TD) ... one per transfer segment * See OHCI spec, sections 4.3.1 (general = control/bulk/interrupt) * and 4.3.2 (iso) */ #define TD_ALIGN 32 #define TD_MASK ((u32)~(TD_ALIGN-1)) /* strip hw status in low addr bits */ struct td { /* first fields are hardware-specified */ __hc32 hwINFO; /* transfer info bitmask */ /* hwINFO bits */ #define TD_OWN (1 << 31) /* owner of the descriptor */ #define TD_CC_SHIFT 27 /* condition code */ #define TD_CC_MASK 0xf #define TD_CC (TD_CC_MASK << TD_CC_SHIFT) #define TD_CC_GET(x) (((x) >> TD_CC_SHIFT) & TD_CC_MASK) #define TD_EC_SHIFT 25 /* error count */ #define TD_EC_MASK 0x3 #define TD_EC (TD_EC_MASK << TD_EC_SHIFT) #define TD_EC_GET(x) ((x >> TD_EC_SHIFT) & TD_EC_MASK) #define TD_T_SHIFT 23 /* data toggle state */ #define TD_T_MASK 0x3 #define TD_T (TD_T_MASK << TD_T_SHIFT) #define TD_T_DATA0 (0x2 << TD_T_SHIFT) /* DATA0 */ #define TD_T_DATA1 (0x3 << TD_T_SHIFT) /* DATA1 */ #define TD_T_CARRY (0x0 << TD_T_SHIFT) /* uses ED_C */ #define TD_T_GET(x) (((x) >> TD_T_SHIFT) & TD_T_MASK) #define TD_DP_SHIFT 21 /* direction/pid */ #define TD_DP_MASK 0x3 #define TD_DP (TD_DP_MASK << TD_DP_SHIFT) #define TD_DP_GET (((x) >> TD_DP_SHIFT) & TD_DP_MASK) #define TD_DP_SETUP (0x0 << TD_DP_SHIFT) /* SETUP pid */ #define TD_DP_OUT (0x1 << TD_DP_SHIFT) /* OUT pid */ #define TD_DP_IN (0x2 << TD_DP_SHIFT) /* IN pid */ #define TD_ISI_SHIFT 8 /* Interrupt Service Interval */ #define TD_ISI_MASK 0x3f #define TD_ISI_GET(x) (((x) >> TD_ISI_SHIFT) & TD_ISI_MASK) #define TD_FN_MASK 0x3f /* frame number */ #define TD_FN_GET(x) ((x) & TD_FN_MASK) __hc32 hwDBP; /* Data Buffer Pointer (or 0) */ __hc32 hwCBL; /* Controller/Buffer Length */ /* hwCBL bits */ #define TD_BL_MASK 0xffff /* buffer length */ #define TD_BL_GET(x) ((x) & TD_BL_MASK) #define TD_IE (1 << 16) /* interrupt enable */ __hc32 hwNextTD; /* Next TD Pointer */ /* rest are purely for the driver's use */ __u8 index; struct ed *ed; struct td *td_hash; /* dma-->td hashtable */ struct td *next_dl_td; struct urb *urb; dma_addr_t td_dma; /* addr of this TD */ dma_addr_t data_dma; /* addr of data it points to */ struct list_head td_list; /* "shadow list", TDs on same ED */ u32 flags; #define TD_FLAG_DONE (1 << 17) /* retired to done list */ #define TD_FLAG_ISO (1 << 16) /* copy of ED_ISO */ } __attribute__ ((aligned(TD_ALIGN))); /* c/b/i need 16; only iso needs 32 */ /* * Hardware transfer status codes -- CC from td->hwINFO */ #define TD_CC_NOERROR 0x00 #define TD_CC_CRC 0x01 #define TD_CC_BITSTUFFING 0x02 #define TD_CC_DATATOGGLEM 0x03 #define TD_CC_STALL 0x04 #define TD_CC_DEVNOTRESP 0x05 #define TD_CC_PIDCHECKFAIL 0x06 #define TD_CC_UNEXPECTEDPID 0x07 #define TD_CC_DATAOVERRUN 0x08 #define TD_CC_DATAUNDERRUN 0x09 /* 0x0A, 0x0B reserved for hardware */ #define TD_CC_BUFFEROVERRUN 0x0C #define TD_CC_BUFFERUNDERRUN 0x0D /* 0x0E, 0x0F reserved for HCD */ #define TD_CC_HCD0 0x0E #define TD_CC_NOTACCESSED 0x0F /* * preshifted status codes */ #define TD_SCC_NOTACCESSED (TD_CC_NOTACCESSED << TD_CC_SHIFT) /* map OHCI TD status codes (CC) to errno values */ static const int cc_to_error[16] = { /* No Error */ 0, /* CRC Error */ -EILSEQ, /* Bit Stuff */ -EPROTO, /* Data Togg */ -EILSEQ, /* Stall */ -EPIPE, /* DevNotResp */ -ETIME, /* PIDCheck */ -EPROTO, /* UnExpPID */ -EPROTO, /* DataOver */ -EOVERFLOW, /* DataUnder */ -EREMOTEIO, /* (for hw) */ -EIO, /* (for hw) */ -EIO, /* BufferOver */ -ECOMM, /* BuffUnder */ -ENOSR, /* (for HCD) */ -EALREADY, /* (for HCD) */ -EALREADY }; #define NUM_INTS 32 /* * This is the structure of the OHCI controller's memory mapped I/O region. * You must use readl() and writel() (in ) to access these fields!! * Layout is in section 7 (and appendix B) of the spec. */ struct admhcd_regs { __hc32 gencontrol; /* General Control */ __hc32 int_status; /* Interrupt Status */ __hc32 int_enable; /* Interrupt Enable */ __hc32 reserved00; __hc32 host_control; /* Host General Control */ __hc32 reserved01; __hc32 fminterval; /* Frame Interval */ __hc32 fmnumber; /* Frame Number */ __hc32 reserved02; __hc32 reserved03; __hc32 reserved04; __hc32 reserved05; __hc32 reserved06; __hc32 reserved07; __hc32 reserved08; __hc32 reserved09; __hc32 reserved10; __hc32 reserved11; __hc32 reserved12; __hc32 reserved13; __hc32 reserved14; __hc32 reserved15; __hc32 reserved16; __hc32 reserved17; __hc32 reserved18; __hc32 reserved19; __hc32 reserved20; __hc32 reserved21; __hc32 lsthresh; /* Low Speed Threshold */ __hc32 rhdesc; /* Root Hub Descriptor */ #define MAX_ROOT_PORTS 2 __hc32 portstatus[MAX_ROOT_PORTS]; /* Port Status */ __hc32 hosthead; /* Host Descriptor Head */ } __attribute__ ((aligned(32))); /* * General Control register bits */ #define ADMHC_CTRL_UHFE (1 << 0) /* USB Host Function Enable */ #define ADMHC_CTRL_SIR (1 << 1) /* Software Interrupt request */ #define ADMHC_CTRL_DMAA (1 << 2) /* DMA Arbitration Control */ #define ADMHC_CTRL_SR (1 << 3) /* Software Reset */ /* * Host General Control register bits */ #define ADMHC_HC_BUSS 0x3 /* USB bus state */ #define ADMHC_BUSS_RESET 0x0 #define ADMHC_BUSS_RESUME 0x1 #define ADMHC_BUSS_OPER 0x2 #define ADMHC_BUSS_SUSPEND 0x3 #define ADMHC_HC_DMAE (1 << 2) /* DMA enable */ /* * Interrupt Status/Enable register bits */ #define ADMHC_INTR_SOFI (1 << 4) /* start of frame */ #define ADMHC_INTR_RESI (1 << 5) /* resume detected */ #define ADMHC_INTR_6 (1 << 6) /* unknown */ #define ADMHC_INTR_7 (1 << 7) /* unknown */ #define ADMHC_INTR_BABI (1 << 8) /* babble detected */ #define ADMHC_INTR_INSM (1 << 9) /* root hub status change */ #define ADMHC_INTR_SO (1 << 10) /* scheduling overrun */ #define ADMHC_INTR_FNO (1 << 11) /* frame number overflow */ #define ADMHC_INTR_TDC (1 << 20) /* transfer descriptor completed */ #define ADMHC_INTR_SWI (1 << 29) /* software interrupt */ #define ADMHC_INTR_FATI (1 << 30) /* fatal error */ #define ADMHC_INTR_INTA (1 << 31) /* interrupt active */ #define ADMHC_INTR_MIE (1 << 31) /* master interrupt enable */ /* * SOF Frame Interval register bits */ #define ADMHC_SFI_FI_MASK ((1 << 14)-1) /* Frame Interval value */ #define ADMHC_SFI_FSLDP_SHIFT 16 #define ADMHC_SFI_FSLDP_MASK ((1 << 15)-1) #define ADMHC_SFI_FIT (1 << 31) /* Frame Interval Toggle */ /* * SOF Frame Number register bits */ #define ADMHC_SFN_FN_MASK ((1 << 16)-1) /* Frame Number Mask */ #define ADMHC_SFN_FR_SHIFT 16 /* Frame Remaining Shift */ #define ADMHC_SFN_FR_MASK ((1 << 14)-1) /* Frame Remaining Mask */ #define ADMHC_SFN_FRT (1 << 31) /* Frame Remaining Toggle */ /* * Root Hub Descriptor register bits */ #define ADMHC_RH_NUMP 0xff /* number of ports */ #define ADMHC_RH_PSM (1 << 8) /* power switching mode */ #define ADMHC_RH_NPS (1 << 9) /* no power switching */ #define ADMHC_RH_OCPM (1 << 10) /* over current protection mode */ #define ADMHC_RH_NOCP (1 << 11) /* no over current protection */ #define ADMHC_RH_PPCM (0xff << 16) /* port power control */ #define ADMHC_RH_LPS (1 << 24) /* local power switch */ #define ADMHC_RH_OCI (1 << 25) /* over current indicator */ /* status change bits */ #define ADMHC_RH_LPSC (1 << 26) /* local power switch change */ #define ADMHC_RH_OCIC (1 << 27) /* over current indicator change */ #define ADMHC_RH_DRWE (1 << 28) /* device remote wakeup enable */ #define ADMHC_RH_CRWE (1 << 29) /* clear remote wakeup enable */ #define ADMHC_RH_CGP (1 << 24) /* clear global power */ #define ADMHC_RH_SGP (1 << 26) /* set global power */ /* * Port Status register bits */ #define ADMHC_PS_CCS (1 << 0) /* current connect status */ #define ADMHC_PS_PES (1 << 1) /* port enable status */ #define ADMHC_PS_PSS (1 << 2) /* port suspend status */ #define ADMHC_PS_POCI (1 << 3) /* port over current indicator */ #define ADMHC_PS_PRS (1 << 4) /* port reset status */ #define ADMHC_PS_PPS (1 << 8) /* port power status */ #define ADMHC_PS_LSDA (1 << 9) /* low speed device attached */ /* status change bits */ #define ADMHC_PS_CSC (1 << 16) /* connect status change */ #define ADMHC_PS_PESC (1 << 17) /* port enable status change */ #define ADMHC_PS_PSSC (1 << 18) /* port suspend status change */ #define ADMHC_PS_OCIC (1 << 19) /* over current indicator change */ #define ADMHC_PS_PRSC (1 << 20) /* port reset status change */ /* port feature bits */ #define ADMHC_PS_CPE (1 << 0) /* clear port enable */ #define ADMHC_PS_SPE (1 << 1) /* set port enable */ #define ADMHC_PS_SPS (1 << 2) /* set port suspend */ #define ADMHC_PS_CPS (1 << 3) /* clear suspend status */ #define ADMHC_PS_SPR (1 << 4) /* set port reset */ #define ADMHC_PS_SPP (1 << 8) /* set port power */ #define ADMHC_PS_CPP (1 << 9) /* clear port power */ /* * the POTPGT value is not defined in the ADMHC, so define a dummy value */ #define ADMHC_POTPGT 2 /* in ms */ /* hcd-private per-urb state */ struct urb_priv { struct ed *ed; struct list_head pending; /* URBs on the same ED */ u32 td_cnt; /* # tds in this request */ u32 td_idx; /* index of the current td */ struct td *td[0]; /* all TDs in this request */ }; #define TD_HASH_SIZE 64 /* power'o'two */ /* sizeof (struct td) ~= 64 == 2^6 ... */ #define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE) /* * This is the full ADMHCD controller description * * Note how the "proper" USB information is just * a subset of what the full implementation needs. (Linus) */ struct admhcd { spinlock_t lock; /* * I/O memory used to communicate with the HC (dma-consistent) */ struct admhcd_regs __iomem *regs; /* * hcd adds to schedule for a live hc any time, but removals finish * only at the start of the next frame. */ struct ed *ed_head; struct ed *ed_tails[4]; struct ed *ed_rm_list; /* to be removed */ struct ed *periodic[NUM_INTS]; /* shadow int_table */ #if 0 /* TODO: remove? */ /* * OTG controllers and transceivers need software interaction; * other external transceivers should be software-transparent */ struct otg_transceiver *transceiver; void (*start_hnp)(struct admhcd *ahcd); #endif /* * memory management for queue data structures */ struct dma_pool *td_cache; struct dma_pool *ed_cache; struct td *td_hash[TD_HASH_SIZE]; struct list_head pending; /* * driver state */ int num_ports; int load[NUM_INTS]; u32 host_control; /* copy of the host_control reg */ unsigned long next_statechange; /* suspend/resume */ u32 fminterval; /* saved register */ unsigned autostop:1; /* rh auto stopping/stopped */ unsigned long flags; /* for HC bugs */ #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ #define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */ #define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */ #define OHCI_QUIRK_BE_DESC 0x08 /* BE descriptors */ #define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */ #define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/ /* there are also chip quirks/bugs in init logic */ #ifdef DEBUG struct dentry *debug_dir; struct dentry *debug_async; struct dentry *debug_periodic; struct dentry *debug_registers; #endif }; /* convert between an hcd pointer and the corresponding ahcd_hcd */ static inline struct admhcd *hcd_to_admhcd(struct usb_hcd *hcd) { return (struct admhcd *)(hcd->hcd_priv); } static inline struct usb_hcd *admhcd_to_hcd(const struct admhcd *ahcd) { return container_of((void *)ahcd, struct usb_hcd, hcd_priv); } /*-------------------------------------------------------------------------*/ #ifndef DEBUG #define STUB_DEBUG_FILES #endif /* DEBUG */ #ifdef DEBUG # define admhc_dbg(ahcd, fmt, args...) \ printk(KERN_DEBUG "adm5120-hcd: " fmt, ## args) #else # define admhc_dbg(ahcd, fmt, args...) do { } while (0) #endif #define admhc_err(ahcd, fmt, args...) \ printk(KERN_ERR "adm5120-hcd: " fmt, ## args) #define admhc_info(ahcd, fmt, args...) \ printk(KERN_INFO "adm5120-hcd: " fmt, ## args) #define admhc_warn(ahcd, fmt, args...) \ printk(KERN_WARNING "adm5120-hcd: " fmt, ## args) #ifdef ADMHC_VERBOSE_DEBUG # define admhc_vdbg admhc_dbg #else # define admhc_vdbg(ahcd, fmt, args...) do { } while (0) #endif /*-------------------------------------------------------------------------*/ /* * While most USB host controllers implement their registers and * in-memory communication descriptors in little-endian format, * a minority (notably the IBM STB04XXX and the Motorola MPC5200 * processors) implement them in big endian format. * * In addition some more exotic implementations like the Toshiba * Spider (aka SCC) cell southbridge are "mixed" endian, that is, * they have a different endianness for registers vs. in-memory * descriptors. * * This attempts to support either format at compile time without a * runtime penalty, or both formats with the additional overhead * of checking a flag bit. * * That leads to some tricky Kconfig rules howevber. There are * different defaults based on some arch/ppc platforms, though * the basic rules are: * * Controller type Kconfig options needed * --------------- ---------------------- * little endian CONFIG_USB_ADMHC_LITTLE_ENDIAN * * fully big endian CONFIG_USB_ADMHC_BIG_ENDIAN_DESC _and_ * CONFIG_USB_ADMHC_BIG_ENDIAN_MMIO * * mixed endian CONFIG_USB_ADMHC_LITTLE_ENDIAN _and_ * CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC} * * (If you have a mixed endian controller, you -must- also define * CONFIG_USB_ADMHC_LITTLE_ENDIAN or things will not work when building * both your mixed endian and a fully big endian controller support in * the same kernel image). */ #ifdef CONFIG_USB_ADMHC_BIG_ENDIAN_DESC #ifdef CONFIG_USB_ADMHC_LITTLE_ENDIAN #define big_endian_desc(ahcd) (ahcd->flags & OHCI_QUIRK_BE_DESC) #else #define big_endian_desc(ahcd) 1 /* only big endian */ #endif #else #define big_endian_desc(ahcd) 0 /* only little endian */ #endif #ifdef CONFIG_USB_ADMHC_BIG_ENDIAN_MMIO #ifdef CONFIG_USB_ADMHC_LITTLE_ENDIAN #define big_endian_mmio(ahcd) (ahcd->flags & OHCI_QUIRK_BE_MMIO) #else #define big_endian_mmio(ahcd) 1 /* only big endian */ #endif #else #define big_endian_mmio(ahcd) 0 /* only little endian */ #endif /* * Big-endian read/write functions are arch-specific. * Other arches can be added if/when they're needed. * */ static inline unsigned int admhc_readl(const struct admhcd *ahcd, __hc32 __iomem *regs) { #ifdef CONFIG_USB_ADMHC_BIG_ENDIAN_MMIO return big_endian_mmio(ahcd) ? readl_be(regs) : readl(regs); #else return readl(regs); #endif } static inline void admhc_writel(const struct admhcd *ahcd, const unsigned int val, __hc32 __iomem *regs) { #ifdef CONFIG_USB_ADMHC_BIG_ENDIAN_MMIO big_endian_mmio(ahcd) ? writel_be(val, regs) : writel(val, regs); #else writel(val, regs); #endif } static inline void admhc_writel_flush(const struct admhcd *ahcd) { #if 0 /* TODO: remove? */ (void) admhc_readl(ahcd, &ahcd->regs->gencontrol); #endif } /*-------------------------------------------------------------------------*/ /* cpu to ahcd */ static inline __hc16 cpu_to_hc16(const struct admhcd *ahcd, const u16 x) { return big_endian_desc(ahcd) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x); } static inline __hc16 cpu_to_hc16p(const struct admhcd *ahcd, const u16 *x) { return big_endian_desc(ahcd) ? cpu_to_be16p(x) : cpu_to_le16p(x); } static inline __hc32 cpu_to_hc32(const struct admhcd *ahcd, const u32 x) { return big_endian_desc(ahcd) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x); } static inline __hc32 cpu_to_hc32p(const struct admhcd *ahcd, const u32 *x) { return big_endian_desc(ahcd) ? cpu_to_be32p(x) : cpu_to_le32p(x); } /* ahcd to cpu */ static inline u16 hc16_to_cpu(const struct admhcd *ahcd, const __hc16 x) { return big_endian_desc(ahcd) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x); } static inline u16 hc16_to_cpup(const struct admhcd *ahcd, const __hc16 *x) { return big_endian_desc(ahcd) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x); } static inline u32 hc32_to_cpu(const struct admhcd *ahcd, const __hc32 x) { return big_endian_desc(ahcd) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x); } static inline u32 hc32_to_cpup(const struct admhcd *ahcd, const __hc32 *x) { return big_endian_desc(ahcd) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x); } /*-------------------------------------------------------------------------*/ static inline u16 admhc_frame_no(const struct admhcd *ahcd) { u32 t; t = admhc_readl(ahcd, &ahcd->regs->fmnumber) & ADMHC_SFN_FN_MASK; return (u16)t; } static inline u16 admhc_frame_remain(const struct admhcd *ahcd) { u32 t; t = admhc_readl(ahcd, &ahcd->regs->fmnumber) >> ADMHC_SFN_FR_SHIFT; t &= ADMHC_SFN_FR_MASK; return (u16)t; } /*-------------------------------------------------------------------------*/ static inline void admhc_disable(struct admhcd *ahcd) { admhcd_to_hcd(ahcd)->state = HC_STATE_HALT; } #define FI 0x2edf /* 12000 bits per frame (-1) */ #define FSLDP(fi) (0x7fff & ((6 * ((fi) - 1200)) / 7)) #define FIT ADMHC_SFI_FIT #define LSTHRESH 0x628 /* lowspeed bit threshold */ static inline void periodic_reinit(struct admhcd *ahcd) { #if 0 u32 fi = ahcd->fminterval & ADMHC_SFI_FI_MASK; u32 fit = admhc_readl(ahcd, &ahcd->regs->fminterval) & FIT; /* TODO: adjust FSLargestDataPacket value too? */ admhc_writel(ahcd, (fit ^ FIT) | ahcd->fminterval, &ahcd->regs->fminterval); #else u32 fit = admhc_readl(ahcd, &ahcd->regs->fminterval) & FIT; /* TODO: adjust FSLargestDataPacket value too? */ admhc_writel(ahcd, (fit ^ FIT) | ahcd->fminterval, &ahcd->regs->fminterval); #endif } static inline u32 admhc_read_rhdesc(struct admhcd *ahcd) { return admhc_readl(ahcd, &ahcd->regs->rhdesc); } static inline u32 admhc_read_portstatus(struct admhcd *ahcd, int port) { return admhc_readl(ahcd, &ahcd->regs->portstatus[port]); } static inline void admhc_write_portstatus(struct admhcd *ahcd, int port, u32 value) { admhc_writel(ahcd, value, &ahcd->regs->portstatus[port]); } static inline void roothub_write_status(struct admhcd *ahcd, u32 value) { /* FIXME: read-only bits must be masked out */ admhc_writel(ahcd, value, &ahcd->regs->rhdesc); } static inline void admhc_intr_disable(struct admhcd *ahcd, u32 ints) { u32 t; t = admhc_readl(ahcd, &ahcd->regs->int_enable); t &= ~(ints); admhc_writel(ahcd, t, &ahcd->regs->int_enable); /* TODO: flush writes ?*/ } static inline void admhc_intr_enable(struct admhcd *ahcd, u32 ints) { u32 t; t = admhc_readl(ahcd, &ahcd->regs->int_enable); t |= ints; admhc_writel(ahcd, t, &ahcd->regs->int_enable); /* TODO: flush writes ?*/ } static inline void admhc_intr_ack(struct admhcd *ahcd, u32 ints) { admhc_writel(ahcd, ints, &ahcd->regs->int_status); } static inline void admhc_dma_enable(struct admhcd *ahcd) { u32 t; t = admhc_readl(ahcd, &ahcd->regs->host_control); if (t & ADMHC_HC_DMAE) return; t |= ADMHC_HC_DMAE; admhc_writel(ahcd, t, &ahcd->regs->host_control); admhc_vdbg(ahcd, "DMA enabled\n"); } static inline void admhc_dma_disable(struct admhcd *ahcd) { u32 t; t = admhc_readl(ahcd, &ahcd->regs->host_control); if (!(t & ADMHC_HC_DMAE)) return; t &= ~ADMHC_HC_DMAE; admhc_writel(ahcd, t, &ahcd->regs->host_control); admhc_vdbg(ahcd, "DMA disabled\n"); }