1/***************************************************************************** 2 ** FILE NAME : ifxusb_cif_d.c 3 ** PROJECT : IFX USB sub-system V3 4 ** MODULES : IFX USB sub-system Host and Device driver 5 ** SRC VERSION : 1.0 6 ** DATE : 1/Jan/2009 7 ** AUTHOR : Chen, Howard 8 ** DESCRIPTION : The Core Interface provides basic services for accessing and 9 ** managing the IFX USB hardware. These services are used by the 10 ** Peripheral Controller Driver only. 11 *****************************************************************************/ 12 13/*! 14 \file ifxusb_cif_d.c 15 \ingroup IFXUSB_DRIVER_V3 16 \brief This file contains the interface to the IFX USB Core. 17*/ 18 19#include <linux/version.h> 20#include "ifxusb_version.h" 21 22 23#include <asm/byteorder.h> 24#include <asm/unaligned.h> 25 26#ifdef __DEBUG__ 27 #include <linux/jiffies.h> 28#endif 29 30#include "ifxusb_plat.h" 31#include "ifxusb_regs.h" 32#include "ifxusb_cif.h" 33 34#include "ifxpcd.h" 35 36 37 38/*! 39 \brief Initializes the DevSpd field of the DCFG register depending on the PHY type 40 and the enumeration speed of the device. 41 \param _core_if Pointer of core_if structure 42 */ 43void ifxusb_dev_init_spd(ifxusb_core_if_t *_core_if) 44{ 45 uint32_t val; 46 dcfg_data_t dcfg; 47 48 IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); 49 if (_core_if->params.speed == IFXUSB_PARAM_SPEED_FULL) 50 /* High speed PHY running at full speed */ 51 val = 0x1; 52 else 53 /* High speed PHY running at high speed and full speed*/ 54 val = 0x0; 55 56 IFX_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val); 57 dcfg.d32 = ifxusb_rreg(&_core_if->dev_global_regs->dcfg); 58 dcfg.b.devspd = val; 59 ifxusb_wreg(&_core_if->dev_global_regs->dcfg, dcfg.d32); 60} 61 62 63/*! 64 \brief This function enables the Device mode interrupts. 65 \param _core_if Pointer of core_if structure 66 */ 67void ifxusb_dev_enable_interrupts(ifxusb_core_if_t *_core_if) 68{ 69 gint_data_t intr_mask ={ .d32 = 0}; 70 ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; 71 72 IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); 73 IFX_DEBUGPL(DBG_CIL, "%s()\n", __func__); 74 75 /* Clear any pending OTG Interrupts */ 76 ifxusb_wreg( &global_regs->gotgint, 0xFFFFFFFF); 77 78 /* Clear any pending interrupts */ 79 ifxusb_wreg( &global_regs->gintsts, 0xFFFFFFFF); 80 81 /* Enable the interrupts in the GINTMSK.*/ 82 intr_mask.b.modemismatch = 1; 83 intr_mask.b.conidstschng = 1; 84 intr_mask.b.wkupintr = 1; 85 intr_mask.b.disconnect = 1; 86 intr_mask.b.usbsuspend = 1; 87 88 intr_mask.b.usbreset = 1; 89 intr_mask.b.enumdone = 1; 90 intr_mask.b.inepintr = 1; 91 intr_mask.b.outepintr = 1; 92 intr_mask.b.erlysuspend = 1; 93 #ifndef __DED_FIFO__ 94// intr_mask.b.epmismatch = 1; 95 #endif 96 97 ifxusb_mreg( &global_regs->gintmsk, intr_mask.d32, intr_mask.d32); 98 IFX_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__, ifxusb_rreg( &global_regs->gintmsk)); 99} 100 101/*! 102 \brief Gets the current USB frame number. This is the frame number from the last SOF packet. 103 \param _core_if Pointer of core_if structure 104 */ 105uint32_t ifxusb_dev_get_frame_number(ifxusb_core_if_t *_core_if) 106{ 107 dsts_data_t dsts; 108 IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); 109 dsts.d32 = ifxusb_rreg(&_core_if->dev_global_regs->dsts); 110 /* read current frame/microfreme number from DSTS register */ 111 return dsts.b.soffn; 112} 113 114 115/*! 116 \brief Set the EP STALL. 117 */ 118void ifxusb_dev_ep_set_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _is_in) 119{ 120 depctl_data_t depctl; 121 volatile uint32_t *depctl_addr; 122 123 IFX_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _epno, (_is_in?"IN":"OUT")); 124 125 depctl_addr = (_is_in)? (&(_core_if->in_ep_regs [_epno]->diepctl)): 126 (&(_core_if->out_ep_regs[_epno]->doepctl)); 127 depctl.d32 = ifxusb_rreg(depctl_addr); 128 depctl.b.stall = 1; 129 130 if (_is_in && depctl.b.epena) 131 depctl.b.epdis = 1; 132 133 ifxusb_wreg(depctl_addr, depctl.d32); 134 IFX_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",ifxusb_rreg(depctl_addr)); 135 return; 136} 137 138/*! 139\brief Clear the EP STALL. 140 */ 141void ifxusb_dev_ep_clear_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _ep_type, uint8_t _is_in) 142{ 143 depctl_data_t depctl; 144 volatile uint32_t *depctl_addr; 145 146 IFX_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _epno, (_is_in?"IN":"OUT")); 147 148 depctl_addr = (_is_in)? (&(_core_if->in_ep_regs [_epno]->diepctl)): 149 (&(_core_if->out_ep_regs[_epno]->doepctl)); 150 151 depctl.d32 = ifxusb_rreg(depctl_addr); 152 /* clear the stall bits */ 153 depctl.b.stall = 0; 154 155 /* 156 * USB Spec 9.4.5: For endpoints using data toggle, regardless 157 * of whether an endpoint has the Halt feature set, a 158 * ClearFeature(ENDPOINT_HALT) request always results in the 159 * data toggle being reinitialized to DATA0. 160 */ 161 if (_ep_type == IFXUSB_EP_TYPE_INTR || _ep_type == IFXUSB_EP_TYPE_BULK) 162 depctl.b.setd0pid = 1; /* DATA0 */ 163 164 ifxusb_wreg(depctl_addr, depctl.d32); 165 IFX_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",ifxusb_rreg(depctl_addr)); 166 return; 167} 168 169/*! 170 \brief This function initializes the IFXUSB controller registers for Device mode. 171 This function flushes the Tx and Rx FIFOs and it flushes any entries in the 172 request queues. 173 \param _core_if Pointer of core_if structure 174 \param _params parameters to be set 175 */ 176void ifxusb_dev_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) 177{ 178 ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; 179 180 gusbcfg_data_t usbcfg ={.d32 = 0}; 181 gahbcfg_data_t ahbcfg ={.d32 = 0}; 182 dcfg_data_t dcfg ={.d32 = 0}; 183 grstctl_t resetctl ={.d32 = 0}; 184 gotgctl_data_t gotgctl ={.d32 = 0}; 185 186 uint32_t dir; 187 int i; 188 189 IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); 190 IFX_DEBUGPL(DBG_CILV, "%s(%p)\n",__func__,_core_if); 191 192 /* Copy Params */ 193 _core_if->params.dma_burst_size = _params->dma_burst_size; 194 _core_if->params.speed = _params->speed; 195 if(_params->max_transfer_size < 2048 || _params->max_transfer_size > ((1 << (_core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1) ) 196 _core_if->params.max_transfer_size = ((1 << (_core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1); 197 else 198 _core_if->params.max_transfer_size = _params->max_transfer_size; 199 200 if(_params->max_packet_count < 16 || _params->max_packet_count > ((1 << (_core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1) ) 201 _core_if->params.max_packet_count= ((1 << (_core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1); 202 else 203 _core_if->params.max_packet_count= _params->max_packet_count; 204 _core_if->params.phy_utmi_width = _params->phy_utmi_width; 205 _core_if->params.turn_around_time_hs = _params->turn_around_time_hs; 206 _core_if->params.turn_around_time_fs = _params->turn_around_time_fs; 207 _core_if->params.timeout_cal_hs = _params->timeout_cal_hs; 208 _core_if->params.timeout_cal_fs = _params->timeout_cal_fs; 209 210 #ifdef __DED_FIFO__ 211 _core_if->params.thr_ctl = _params->thr_ctl; 212 _core_if->params.tx_thr_length = _params->tx_thr_length; 213 _core_if->params.rx_thr_length = _params->rx_thr_length; 214 #endif 215 216 /* Reset the Controller */ 217 do 218 { 219 while(ifxusb_core_soft_reset( _core_if )) 220 ifxusb_hard_reset(_core_if); 221 } while (ifxusb_is_host_mode(_core_if)); 222 223 usbcfg.d32 = ifxusb_rreg(&global_regs->gusbcfg); 224 #if 0 225 #if defined(__DED_FIFO__) 226 usbcfg.b.ForceDevMode = 1; 227 usbcfg.b.ForceHstMode = 0; 228 #endif 229 #endif 230 usbcfg.b.term_sel_dl_pulse = 0; 231 ifxusb_wreg (&global_regs->gusbcfg, usbcfg.d32); 232 233 /* This programming sequence needs to happen in FS mode before any other 234 * programming occurs */ 235 /* High speed PHY. */ 236 if (!_core_if->phy_init_done) 237 { 238 _core_if->phy_init_done = 1; 239 /* HS PHY parameters. These parameters are preserved 240 * during soft reset so only program the first time. Do 241 * a soft reset immediately after setting phyif. */ 242 usbcfg.b.ulpi_utmi_sel = 0; //UTMI+ 243 usbcfg.b.phyif = ( _core_if->params.phy_utmi_width == 16)?1:0; 244 ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); 245 /* Reset after setting the PHY parameters */ 246 ifxusb_core_soft_reset( _core_if ); 247 } 248 249 /* Program the GAHBCFG Register.*/ 250 switch (_core_if->params.dma_burst_size) 251 { 252 case 0 : 253 ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_SINGLE; 254 break; 255 case 1 : 256 ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR; 257 break; 258 case 4 : 259 ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR4; 260 break; 261 case 8 : 262 ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR8; 263 break; 264 case 16: 265 ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR16; 266 break; 267 } 268 ahbcfg.b.dmaenable = 1; 269 ifxusb_wreg(&global_regs->gahbcfg, ahbcfg.d32); 270 271 /* Program the GUSBCFG register. */ 272 usbcfg.d32 = ifxusb_rreg( &global_regs->gusbcfg ); 273 usbcfg.b.hnpcap = 0; 274 usbcfg.b.srpcap = 0; 275 ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); 276 277 /* Restart the Phy Clock */ 278 ifxusb_wreg(_core_if->pcgcctl, 0); 279 280 /* Device configuration register */ 281 ifxusb_dev_init_spd(_core_if); 282 dcfg.d32 = ifxusb_rreg( &_core_if->dev_global_regs->dcfg); 283 dcfg.b.perfrint = IFXUSB_DCFG_FRAME_INTERVAL_80; 284 #if defined(__DED_FIFO__) 285 #if defined(__DESC_DMA__) 286 dcfg.b.descdma = 1; 287 #else 288 dcfg.b.descdma = 0; 289 #endif 290 #endif 291 292 ifxusb_wreg( &_core_if->dev_global_regs->dcfg, dcfg.d32 ); 293 294 /* Configure data FIFO sizes */ 295 _core_if->params.data_fifo_size = _core_if->hwcfg3.b.dfifo_depth; 296 _core_if->params.rx_fifo_size = ifxusb_rreg(&global_regs->grxfsiz); 297 IFX_DEBUGPL(DBG_CIL, "Initial: FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); 298 IFX_DEBUGPL(DBG_CIL, " Rx FIFO Size=0x%06X\n", _core_if->params.rx_fifo_size); 299 300 _core_if->params.tx_fifo_size[0]= ifxusb_rreg(&global_regs->gnptxfsiz) >> 16; 301 302 #ifdef __DED_FIFO__ 303 for (i=1; i <= _core_if->hwcfg4.b.num_in_eps; i++) 304 _core_if->params.tx_fifo_size[i] = 305 ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i-1]) >> 16; 306 #else 307 for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) 308 _core_if->params.tx_fifo_size[i+1] = 309 ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i]) >> 16; 310 #endif 311 312 #ifdef __DEBUG__ 313 #ifdef __DED_FIFO__ 314 for (i=0; i <= _core_if->hwcfg4.b.num_in_eps; i++) 315 IFX_DEBUGPL(DBG_CIL, " Tx[%02d] FIFO Size=0x%06X\n",i, _core_if->params.tx_fifo_size[i]); 316 #else 317 IFX_DEBUGPL(DBG_CIL, " NPTx FIFO Size=0x%06X\n", _core_if->params.tx_fifo_size[0]); 318 for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) 319 IFX_DEBUGPL(DBG_CIL, " PTx[%02d] FIFO Size=0x%06X\n",i, _core_if->params.tx_fifo_size[i+1]); 320 #endif 321 #endif 322 323 { 324 fifosize_data_t txfifosize; 325 if(_params->data_fifo_size >=0 && _params->data_fifo_size < _core_if->params.data_fifo_size) 326 _core_if->params.data_fifo_size = _params->data_fifo_size; 327 328 329 if(_params->rx_fifo_size >=0 && _params->rx_fifo_size < _core_if->params.rx_fifo_size) 330 _core_if->params.rx_fifo_size = _params->rx_fifo_size; 331 if(_core_if->params.data_fifo_size < _core_if->params.rx_fifo_size) 332 _core_if->params.rx_fifo_size = _core_if->params.data_fifo_size; 333 ifxusb_wreg( &global_regs->grxfsiz, _core_if->params.rx_fifo_size); 334 335 for (i=0; i < MAX_EPS_CHANNELS; i++) 336 if(_params->tx_fifo_size[i] >=0 && _params->tx_fifo_size[i] < _core_if->params.tx_fifo_size[i]) 337 _core_if->params.tx_fifo_size[i] = _params->tx_fifo_size[i]; 338 339 txfifosize.b.startaddr = _core_if->params.rx_fifo_size; 340 #ifdef __DED_FIFO__ 341 if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[0] > _core_if->params.data_fifo_size) 342 _core_if->params.tx_fifo_size[0]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; 343 txfifosize.b.depth=_core_if->params.tx_fifo_size[0]; 344 ifxusb_wreg( &global_regs->gnptxfsiz, txfifosize.d32); 345 txfifosize.b.startaddr += _core_if->params.tx_fifo_size[0]; 346 for (i=1; i <= _core_if->hwcfg4.b.num_in_eps; i++) 347 { 348 if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[i] > _core_if->params.data_fifo_size) 349 _core_if->params.tx_fifo_size[i]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; 350 txfifosize.b.depth=_core_if->params.tx_fifo_size[i]; 351 ifxusb_wreg( &global_regs->dptxfsiz_dieptxf[i-1], txfifosize.d32); 352 txfifosize.b.startaddr += _core_if->params.tx_fifo_size[i]; 353 } 354 #else 355 if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[0] > _core_if->params.data_fifo_size) 356 _core_if->params.tx_fifo_size[0]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; 357 txfifosize.b.depth=_core_if->params.tx_fifo_size[0]; 358 ifxusb_wreg( &global_regs->gnptxfsiz, txfifosize.d32); 359 txfifosize.b.startaddr += _core_if->params.tx_fifo_size[0]; 360 for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) 361 { 362 if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[i+1] > _core_if->params.data_fifo_size) 363 _core_if->params.tx_fifo_size[i+1]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; 364 //txfifosize.b.depth=_core_if->params.tx_fifo_size[i+1]; 365 ifxusb_wreg( &global_regs->dptxfsiz_dieptxf[i], txfifosize.d32); 366 txfifosize.b.startaddr += _core_if->params.tx_fifo_size[i+1]; 367 } 368 #endif 369 } 370 371 #ifdef __DEBUG__ 372 { 373 fifosize_data_t fifosize; 374 IFX_DEBUGPL(DBG_CIL, "Result : FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); 375 376 IFX_DEBUGPL(DBG_CIL, " Rx FIFO =0x%06X Sz=0x%06X\n", 0,ifxusb_rreg(&global_regs->grxfsiz)); 377 #ifdef __DED_FIFO__ 378 fifosize.d32=ifxusb_rreg(&global_regs->gnptxfsiz); 379 IFX_DEBUGPL(DBG_CIL, " Tx[00] FIFO =0x%06X Sz=0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); 380 for (i=1; i <= _core_if->hwcfg4.b.num_in_eps; i++) 381 { 382 fifosize.d32=ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i-1]); 383 IFX_DEBUGPL(DBG_CIL, " Tx[%02d] FIFO 0x%06X Sz=0x%06X\n",i, fifosize.b.startaddr,fifosize.b.depth); 384 } 385 #else 386 fifosize.d32=ifxusb_rreg(&global_regs->gnptxfsiz); 387 IFX_DEBUGPL(DBG_CIL, " NPTx FIFO =0x%06X Sz=0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); 388 for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) 389 { 390 fifosize.d32=ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i]); 391 IFX_DEBUGPL(DBG_CIL, " PTx[%02d] FIFO 0x%06X Sz=0x%06X\n",i, fifosize.b.startaddr,fifosize.b.depth); 392 } 393 #endif 394 } 395 #endif 396 397 /* Clear Host Set HNP Enable in the OTG Control Register */ 398 gotgctl.b.hstsethnpen = 1; 399 ifxusb_mreg( &global_regs->gotgctl, gotgctl.d32, 0); 400 401 /* Flush the FIFOs */ 402 ifxusb_flush_tx_fifo(_core_if, 0x10); /* all Tx FIFOs */ 403 ifxusb_flush_rx_fifo(_core_if); 404 405 /* Flush the Learning Queue. */ 406 resetctl.b.intknqflsh = 1; 407 ifxusb_wreg( &global_regs->grstctl, resetctl.d32); 408 409 /* Clear all pending Device Interrupts */ 410 ifxusb_wreg( &_core_if->dev_global_regs->diepmsk , 0 ); 411 ifxusb_wreg( &_core_if->dev_global_regs->doepmsk , 0 ); 412 ifxusb_wreg( &_core_if->dev_global_regs->daint , 0xFFFFFFFF ); 413 ifxusb_wreg( &_core_if->dev_global_regs->daintmsk, 0 ); 414 415 dir=_core_if->hwcfg1.d32; 416 for (i=0; i <= _core_if->hwcfg2.b.num_dev_ep ; i++,dir>>=2) 417 { 418 depctl_data_t depctl; 419 if((dir&0x03)==0 || (dir&0x03) ==1) 420 { 421 depctl.d32 = ifxusb_rreg(&_core_if->in_ep_regs[i]->diepctl); 422 if (depctl.b.epena) 423 { 424 depctl.d32 = 0; 425 depctl.b.epdis = 1; 426 depctl.b.snak = 1; 427 } 428 else 429 depctl.d32 = 0; 430 ifxusb_wreg( &_core_if->in_ep_regs[i]->diepctl, depctl.d32); 431 #ifndef __DESC_DMA__ 432 ifxusb_wreg( &_core_if->in_ep_regs[i]->dieptsiz, 0); 433 #endif 434 ifxusb_wreg( &_core_if->in_ep_regs[i]->diepdma, 0); 435 ifxusb_wreg( &_core_if->in_ep_regs[i]->diepint, 0xFF); 436 } 437 438 if((dir&0x03)==0 || (dir&0x03) ==2) 439 { 440 depctl.d32 = ifxusb_rreg(&_core_if->out_ep_regs[i]->doepctl); 441 if (depctl.b.epena) 442 { 443 depctl.d32 = 0; 444 depctl.b.epdis = 1; 445 depctl.b.snak = 1; 446 } 447 else 448 depctl.d32 = 0; 449 ifxusb_wreg( &_core_if->out_ep_regs[i]->doepctl, depctl.d32); 450 #ifndef __DESC_DMA__ 451 ifxusb_wreg( &_core_if->out_ep_regs[i]->doeptsiz, 0); 452 #endif 453 ifxusb_wreg( &_core_if->out_ep_regs[i]->doepdma, 0); 454 ifxusb_wreg( &_core_if->out_ep_regs[i]->doepint, 0xFF); 455 } 456 } 457} 458 459