github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/soc/nxp/usb/bus.go (about) 1 // NXP USBOH3USBO2 / USBPHY driver 2 // https://github.com/usbarmory/tamago 3 // 4 // Copyright (c) WithSecure Corporation 5 // https://foundry.withsecure.com 6 // 7 // Use of this source code is governed by the license 8 // that can be found in the LICENSE file. 9 10 // Package usb implements a driver for the USB PHY designated as NXP 11 // USBOH3USBO2, included in several i.MX SoCs, adopting the following 12 // specifications: 13 // - IMX6ULLRM - i.MX 6ULL Applications Processor Reference Manual - Rev 1 2017/11 14 // - USB2.0 - USB Specification Revision 2.0 15 // 16 // This package is only meant to be used with `GOOS=tamago GOARCH=arm` as 17 // supported by the TamaGo framework for bare metal Go on ARM SoCs, see 18 // https://github.com/usbarmory/tamago. 19 package usb 20 21 import ( 22 "sync" 23 24 "github.com/usbarmory/tamago/internal/reg" 25 ) 26 27 // USB registers 28 const ( 29 USB_ANALOG_USBx_CHRG_DETECT = 0x10 30 CHRG_DETECT_EN_B = 20 31 CHRG_DETECT_CHK_CHRG_B = 19 32 33 USBPHYx_PWD = 0x00 34 35 USBPHYx_CTRL = 0x30 36 CTRL_SFTRST = 31 37 CTRL_CLKGATE = 30 38 CTRL_ENUTMILEVEL3 = 15 39 CTRL_ENUTMILEVEL2 = 14 40 CTRL_ENHOSTDISCONDETECT = 1 41 42 // p3823, 56.6 USB Core Memory Map/Register Definition, IMX6ULLRM 43 44 USB_UOGx_USBCMD = 0x140 45 USBCMD_RST = 1 46 USBCMD_RS = 0 47 48 USB_UOGx_USBSTS = 0x144 49 USBSTS_URI = 6 50 USBSTS_UI = 0 51 52 USB_UOGx_USBINTR = 0x148 53 54 USB_UOGx_DEVICEADDR = 0x154 55 DEVICEADDR_USBADR = 25 56 DEVICEADDR_USBADRA = 24 57 58 USB_UOGx_ENDPTLISTADDR = 0x158 59 ENDPTLISTADDR_EPBASE = 11 60 61 USB_UOGx_PORTSC1 = 0x184 62 PORTSC_PTS_1 = 30 63 PORTSC_PSPD = 26 64 PORTSC_PR = 8 65 66 USB_UOGx_OTGSC = 0x1a4 67 OTGSC_OT = 3 68 69 USB_UOGx_USBMODE = 0x1a8 70 USBMODE_SDIS = 4 71 USBMODE_SLOM = 3 72 USBMODE_CM = 0 73 USBMODE_CM_DEVICE = 0b10 74 USBMODE_CM_HOST = 0b11 75 76 USB_UOGx_ENDPTSETUPSTAT = 0x1ac 77 78 USB_UOGx_ENDPTPRIME = 0x1b0 79 ENDPTPRIME_PETB = 16 80 ENDPTPRIME_PERB = 0 81 82 USB_UOGx_ENDPTFLUSH = 0x1b4 83 ENDPTFLUSH_FETB = 16 84 ENDPTFLUSH_FERB = 0 85 86 USB_UOGx_ENDPTSTAT = 0x1b8 87 88 USB_UOGx_ENDPTCOMPLETE = 0x1bc 89 ENDPTCOMPLETE_ETBR = 16 90 ENDPTCOMPLETE_ERBR = 0 91 92 USB_UOGx_ENDPTCTRL = 0x1c0 93 ENDPTCTRL_TXE = 23 94 ENDPTCTRL_TXR = 22 95 ENDPTCTRL_TXI = 21 96 ENDPTCTRL_TXT = 18 97 ENDPTCTRL_TXS = 16 98 ENDPTCTRL_RXE = 7 99 ENDPTCTRL_RXR = 6 100 ENDPTCTRL_RXI = 5 101 ENDPTCTRL_RXT = 2 102 ENDPTCTRL_RXS = 0 103 ) 104 105 // USB interrupt events 106 const ( 107 // p3848, 56.6.19 Interrupt Status Register (USB_nUSBSTS), IMX6ULLRM 108 // p3852, 56.6.20 Interrupt Enable Register (USB_nUSBINTR), IMX6ULLRM 109 110 IRQ_TI1 = 25 111 IRQ_TI0 = 24 112 IRQ_NAKI = 16 113 IRQ_AS = 15 114 IRQ_PS = 14 115 IRQ_RCP = 13 116 IRQ_HCH = 12 117 IRQ_ULPII = 10 118 IRQ_SLI = 8 119 IRQ_SRI = 7 120 IRQ_URI = 6 121 IRQ_AAI = 5 122 IRQ_SEI = 4 123 IRQ_FRI = 3 124 IRQ_PCI = 2 125 IRQ_UEI = 1 126 IRQ_UI = 0 127 ) 128 129 // USB represents a USB controller instance. 130 type USB struct { 131 sync.Mutex 132 133 // Controller index 134 Index int 135 // Base register 136 Base uint32 137 // Clock gate register 138 CCGR uint32 139 // Clock gate 140 CG int 141 // Analog base register 142 Analog uint32 143 // PHY base register 144 PHY uint32 145 // Interrupt ID 146 IRQ int 147 // PLL enable function 148 EnablePLL func(index int) error 149 150 // USB device configuration 151 Device *Device 152 153 // EP1-N transfer completion rendezvous point 154 event *sync.Cond 155 // EP1-N cancellation signal 156 exit chan struct{} 157 // EP-1-N completion synchronization 158 wg sync.WaitGroup 159 160 // control registers 161 ctrl uint32 162 pwd uint32 163 chrg uint32 164 mode uint32 165 otg uint32 166 cmd uint32 167 addr uint32 168 sts uint32 169 intr uint32 170 sc uint32 171 eplist uint32 172 setup uint32 173 flush uint32 174 prime uint32 175 stat uint32 176 complete uint32 177 epctrl uint32 178 179 // cache for endpoint list pointer 180 epListAddr uint32 181 // cache for endpoint queue heads pointers 182 dQH [MAX_ENDPOINTS][2]uint32 183 } 184 185 // Init initializes the USB controller. 186 func (hw *USB) Init() { 187 hw.Lock() 188 defer hw.Unlock() 189 190 if hw.Base == 0 || hw.CCGR == 0 || hw.Analog == 0 || hw.PHY == 0 || hw.EnablePLL == nil { 191 panic("invalid USB controller instance") 192 } 193 194 hw.ctrl = hw.PHY + USBPHYx_CTRL 195 hw.pwd = hw.PHY + USBPHYx_PWD 196 hw.chrg = hw.Analog + USB_ANALOG_USBx_CHRG_DETECT 197 hw.mode = hw.Base + USB_UOGx_USBMODE 198 hw.otg = hw.Base + USB_UOGx_OTGSC 199 hw.cmd = hw.Base + USB_UOGx_USBCMD 200 hw.addr = hw.Base + USB_UOGx_DEVICEADDR 201 hw.sts = hw.Base + USB_UOGx_USBSTS 202 hw.intr = hw.Base + USB_UOGx_USBINTR 203 hw.sc = hw.Base + USB_UOGx_PORTSC1 204 hw.eplist = hw.Base + USB_UOGx_ENDPTLISTADDR 205 hw.setup = hw.Base + USB_UOGx_ENDPTSETUPSTAT 206 hw.flush = hw.Base + USB_UOGx_ENDPTFLUSH 207 hw.prime = hw.Base + USB_UOGx_ENDPTPRIME 208 hw.stat = hw.Base + USB_UOGx_ENDPTSTAT 209 hw.complete = hw.Base + USB_UOGx_ENDPTCOMPLETE 210 hw.epctrl = hw.Base + USB_UOGx_ENDPTCTRL 211 212 // enable clock 213 reg.SetN(hw.CCGR, hw.CG, 0b11, 0b11) 214 hw.EnablePLL(hw.Index) 215 216 // soft reset USB PHY 217 reg.Set(hw.ctrl, CTRL_SFTRST) 218 reg.Clear(hw.ctrl, CTRL_SFTRST) 219 220 // disable clock gate 221 reg.Clear(hw.ctrl, CTRL_CLKGATE) 222 223 // clear power down 224 reg.Write(hw.pwd, 0) 225 226 // enable UTMI+ 227 reg.Set(hw.ctrl, CTRL_ENUTMILEVEL3) 228 reg.Set(hw.ctrl, CTRL_ENUTMILEVEL2) 229 // enable disconnection detect 230 reg.Set(hw.ctrl, CTRL_ENHOSTDISCONDETECT) 231 232 // disable charger detector 233 reg.Set(hw.chrg, CHRG_DETECT_EN_B) 234 reg.Set(hw.chrg, CHRG_DETECT_CHK_CHRG_B) 235 } 236 237 // Speed returns the port speed. 238 func (hw *USB) Speed() (speed string) { 239 hw.Lock() 240 defer hw.Unlock() 241 242 switch reg.Get(hw.sc, PORTSC_PSPD, 0b11) { 243 case 0b00: 244 speed = "full" 245 case 0b01: 246 speed = "low" 247 case 0b10: 248 speed = "high" 249 case 0b11: 250 panic("invalid port speed") 251 } 252 253 return 254 } 255 256 // PowerDown shuts down the USB PHY. 257 func (hw *USB) PowerDown() { 258 reg.Write(hw.pwd, 0xffffffff) 259 } 260 261 // Run sets the controller in run mode. 262 func (hw *USB) Run() { 263 reg.Set(hw.cmd, USBCMD_RS) 264 } 265 266 // Stop sets the controller in stop mode. 267 func (hw *USB) Stop() { 268 reg.Clear(hw.cmd, USBCMD_RS) 269 } 270 271 // Reset waits for and handles a bus reset. 272 func (hw *USB) Reset() { 273 hw.Lock() 274 defer hw.Unlock() 275 276 reg.Wait(hw.sts, USBSTS_URI, 1, 1) 277 278 // p3792, 56.4.6.2.1 Bus Reset, IMX6ULLRM 279 280 // read and write back to clear setup token semaphores 281 reg.WriteBack(hw.setup) 282 // read and write back to clear setup status 283 reg.WriteBack(hw.complete) 284 // flush endpoint buffers 285 reg.Write(hw.flush, 0xffffffff) 286 287 reg.Wait(hw.sc, PORTSC_PR, 1, 0) 288 289 // clear reset 290 reg.Or(hw.sts, (1<<USBSTS_URI | 1<<USBSTS_UI)) 291 } 292 293 // EnableInterrupt enables interrupt generation for a specific event. 294 func (hw *USB) EnableInterrupt(event int) { 295 reg.Set(hw.intr, event) 296 } 297 298 // ClearInterrupt clears the interrupt corresponding to a specific event. 299 func (hw *USB) ClearInterrupt(event int) { 300 reg.Set(hw.sts, event) 301 }