dm90x0.c 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978
  1. /****************************************************************************
  2. * drivers/net/dm90x0.c
  3. *
  4. * Copyright (C) 2007-2010, 2014-2016, 2018 Gregory Nutt. All rights
  5. * reserved.
  6. * Author: Gregory Nutt <gnutt@nuttx.org>
  7. *
  8. * References: Davicom data sheets (DM9000-DS-F03-041906.pdf,
  9. * DM9010-DS-F01-103006.pdf) and looking at lots of other DM90x0
  10. * drivers.
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted provided that the following conditions
  14. * are met:
  15. *
  16. * 1. Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. * 2. Redistributions in binary form must reproduce the above copyright
  19. * notice, this list of conditions and the following disclaimer in
  20. * the documentation and/or other materials provided with the
  21. * distribution.
  22. * 3. Neither the name NuttX nor the names of its contributors may be
  23. * used to endorse or promote products derived from this software
  24. * without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  27. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  28. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  29. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  30. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  31. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  32. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  33. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  34. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  35. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  36. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37. * POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. ****************************************************************************/
  40. /****************************************************************************
  41. * Included Files
  42. ****************************************************************************/
  43. #include <nuttx/config.h>
  44. #if defined(CONFIG_NET) && defined(CONFIG_NET_DM90x0)
  45. /* Only one hardware interface supported at present (although there are
  46. * hooks throughout the design to that extending the support to multiple
  47. * interfaces should not be that difficult)
  48. */
  49. #undef CONFIG_DM9X_NINTERFACES
  50. #define CONFIG_DM9X_NINTERFACES 1
  51. #include <stdint.h>
  52. #include <stdbool.h>
  53. #include <time.h>
  54. #include <string.h>
  55. #include <debug.h>
  56. #include <errno.h>
  57. #include <arpa/inet.h>
  58. #include <net/ethernet.h>
  59. #include <nuttx/arch.h>
  60. #include <nuttx/irq.h>
  61. #include <nuttx/wdog.h>
  62. #include <nuttx/wqueue.h>
  63. #include <nuttx/net/arp.h>
  64. #include <nuttx/net/netdev.h>
  65. #ifdef CONFIG_NET_PKT
  66. # include <nuttx/net/pkt.h>
  67. #endif
  68. /****************************************************************************
  69. * Pre-processor Definitions
  70. ****************************************************************************/
  71. /* If processing is not done at the interrupt level, then work queue support
  72. * is required.
  73. */
  74. #if !defined(CONFIG_SCHED_WORKQUEUE)
  75. # error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE)
  76. #endif
  77. /* The low priority work queue is preferred. If it is not enabled, LPWORK
  78. * will be the same as HPWORK.
  79. *
  80. * NOTE: However, the network should NEVER run on the high priority work
  81. * queue! That queue is intended only to service short back end interrupt
  82. * processing that never suspends. Suspending the high priority work queue
  83. * may bring the system to its knees!
  84. */
  85. #define ETHWORK LPWORK
  86. /* DM90000 and DM9010 register offsets */
  87. #define DM9X_NETC 0x00 /* Network control register */
  88. #define DM9X_NETS 0x01 /* Network Status register */
  89. #define DM9X_TXC 0x02 /* TX control register */
  90. #define DM9X_TXS1 0x03 /* TX status register 1 */
  91. #define DM9X_TXS2 0x03 /* TX status register 2 */
  92. #define DM9X_RXC 0x05 /* RX control register */
  93. #define DM9X_RXS 0x06 /* RX status register */
  94. #define DM9X_RXOVF 0x07 /* Receive overflow counter register */
  95. #define DM9X_BPTHRES 0x08 /* Back pressure threshold register */
  96. #define DM9X_FCTHRES 0x09 /* Flow control threshold register */
  97. #define DM9X_FC 0x0a /* RX/TX flow control register */
  98. #define DM9X_EEPHYC 0x0b /* EEPROM & PHY control register */
  99. #define DM9X_EEPHYA 0x0c /* EEPROM & PHY address register */
  100. #define DM9X_EEPHYDL 0x0d /* EEPROM & PHY data register (lo) */
  101. #define DM9X_EEPHYDH 0x0e /* EEPROM & PHY data register (hi) */
  102. #define DM9X_WAKEUP 0x0f /* Wake-up control register */
  103. #define DM9X_PAB0 0x10 /* Physical address register (byte 0) */
  104. #define DM9X_PAB1 0x11 /* Physical address register (byte 1) */
  105. #define DM9X_PAB2 0x12 /* Physical address register (byte 2) */
  106. #define DM9X_PAB3 0x13 /* Physical address register (byte 3) */
  107. #define DM9X_PAB4 0x14 /* Physical address register (byte 4) */
  108. #define DM9X_PAB5 0x15 /* Physical address register (byte 5) */
  109. #define DM9X_MAB0 0x16 /* Multicast address register (byte 0) */
  110. #define DM9X_MAB1 0x17 /* Multicast address register (byte 1) */
  111. #define DM9X_MAB2 0x18 /* Multicast address register (byte 2) */
  112. #define DM9X_MAB3 0x19 /* Multicast address register (byte 3) */
  113. #define DM9X_MAB4 0x1a /* Multicast address register (byte 4) */
  114. #define DM9X_MAB5 0x1b /* Multicast address register (byte 5) */
  115. #define DM9X_MAB6 0x1c /* Multicast address register (byte 6) */
  116. #define DM9X_MAB7 0x1d /* Multicast address register (byte 7) */
  117. #define DM9X_GPC 0x1e /* General purpose control register */
  118. #define DM9X_GPD 0x1f /* General purpose register */
  119. #define DM9X_TRPAL 0x22 /* TX read pointer address (lo) */
  120. #define DM9X_TRPAH 0x23 /* TX read pointer address (hi) */
  121. #define DM9X_RWPAL 0x24 /* RX write pointer address (lo) */
  122. #define DM9X_RWPAH 0x25 /* RX write pointer address (hi) */
  123. #define DM9X_VIDL 0x28 /* Vendor ID (lo) */
  124. #define DM9X_VIDH 0x29 /* Vendor ID (hi) */
  125. #define DM9X_PIDL 0x2a /* Product ID (lo) */
  126. #define DM9X_PIDH 0x2b /* Product ID (hi) */
  127. #define DM9X_CHIPR 0x2c /* Product ID (lo) */
  128. #define DM9X_TXC2 0x2d /* Transmit control register 2 (dm9010) */
  129. #define DM9X_OTC 0x2e /* Operation test control register (dm9010) */
  130. #define DM9X_SMODEC 0x2f /* Special mode control register */
  131. #define DM9X_ETXCSR 0x30 /* Early transmit control/status register (dm9010) */
  132. #define DM9X_TCCR 0x31 /* Transmit checksum control register (dm9010) */
  133. #define DM9X_RCSR 0x32 /* Receive checksum control/status register (dm9010) */
  134. #define DM9X_EPHYA 0x33 /* External PHY address register (dm9010) */
  135. #define DM9X_GPC2 0x34 /* General purpose control register 2 (dm9010) */
  136. #define DM9X_GPD2 0x35 /* General purpose register 2 */
  137. #define DM9X_GPC3 0x36 /* General purpose control register 3 (dm9010) */
  138. #define DM9X_GPD3 0x37 /* General purpose register 3 */
  139. #define DM9X_PBUSC 0x38 /* Processor bus control register (dm9010) */
  140. #define DM9X_IPINC 0x39 /* INT pin control register (dm9010) */
  141. #define DM9X_MON1 0x40 /* Monitor register 1 (dm9010) */
  142. #define DM9X_MON2 0x41 /* Monitor register 2 (dm9010) */
  143. #define DM9X_SCLKC 0x50 /* System clock turn ON control register (dm9010) */
  144. #define DM9X_SCLKR 0x51 /* Resume system clock control register (dm9010) */
  145. #define DM9X_MRCMDX 0xf0 /* Memory data pre-fetch read command without address increment */
  146. #define DM9X_MRCMDX1 0xf1 /* memory data read command without address increment (dm9010) */
  147. #define DM9X_MRCMD 0xf2 /* Memory data read command with address increment */
  148. #define DM9X_MDRAL 0xf4 /* Memory data read address register (lo) */
  149. #define DM9X_MDRAH 0xf5 /* Memory data read address register (hi) */
  150. #define DM9X_MWCMDX 0xf6 /* Memory data write command without address increment */
  151. #define DM9X_MWCMD 0xf8 /* Memory data write command with address increment */
  152. #define DM9X_MDWAL 0xfa /* Memory data write address register (lo) */
  153. #define DM9X_MDWAH 0xfb /* Memory data write address register (lo) */
  154. #define DM9X_TXPLL 0xfc /* Memory data write address register (lo) */
  155. #define DM9X_TXPLH 0xfd /* Memory data write address register (hi) */
  156. #define DM9X_ISR 0xfe /* Interrupt status register */
  157. #define DM9X_IMR 0xff /* Interrupt mask register */
  158. /* Network control register bit definitions */
  159. #define DM9X_NETC_RST (1 << 0) /* Software reset */
  160. #define DM9X_NETC_LBKM (3 << 1) /* Loopback mode mask */
  161. #define DM9X_NETC_LBK0 (0 << 1) /* 0: Normal */
  162. #define DM9X_NETC_LBK1 (1 << 1) /* 1: MAC internal loopback */
  163. #define DM9X_NETC_LBK2 (2 << 1) /* 2: Internal PHY 100M mode loopback */
  164. #define DM9X_NETC_FDX (1 << 3) /* Full dupliex mode */
  165. #define DM9X_NETC_FCOL (1 << 4) /* Force collision mode */
  166. #define DM9X_NETC_WAKEEN (1 << 6) /* Wakeup event enable */
  167. #define DM9X_NETC_EXTPHY (1 << 7) /* Select external PHY */
  168. /* Network status bit definitions */
  169. #define DM9X_NETS_RXOV (1 << 1) /* RX Fifo overflow */
  170. #define DM9X_NETS_TX1END (1 << 2) /* TX packet 1 complete status */
  171. #define DM9X_NETS_TX2END (1 << 3) /* TX packet 2 complete status */
  172. #define DM9X_NETS_WAKEST (1 << 5) /* Wakeup event status */
  173. #define DM9X_NETS_LINKST (1 << 6) /* Link status */
  174. #define DM9X_NETS_SPEED (1 << 7) /* Media speed */
  175. /* IMR/ISR bit definitions */
  176. #define DM9X_INT_PR (1 << 0) /* Packet received interrupt */
  177. #define DM9X_INT_PT (1 << 1) /* Packet transmitted interrupt */
  178. #define DM9X_INT_RO (1 << 2) /* Receive overflow interrupt */
  179. #define DM9X_INT_ROO (1 << 3) /* Receive overflow counter overflow int */
  180. #define DM9X_INT_UDRUN (1 << 4) /* Transmit underrun interrupt */
  181. #define DM9X_INT_LNKCHG (1 << 5) /* Link status change interrupt */
  182. #define DM9X_INT_ALL (0x3f)
  183. #define DM9X_IMR_UNUSED (1 << 6) /* (not used) */
  184. #define DM9X_IMR_PAR (1 << 7) /* Enable auto R/W pointer reset */
  185. #define DM9X_ISR_IOMODEM (3 << 6) /* IO mode mask */
  186. #define DM9X_ISR_IOMODE8 (2 << 6) /* IO mode = 8 bit */
  187. #define DM9X_ISR_IOMODE16 (0 << 6) /* IO mode = 16 bit */
  188. #define DM9X_ISR_IOMODE32 (1 << 6) /* IO mode = 32 bit */
  189. #define DM9X_IMRENABLE (DM9X_INT_PR | DM9X_INT_PT | DM9X_INT_LNKCHG | DM9X_IMR_PAR)
  190. #define DM9X_IMRRXDISABLE (DM9X_INT_PT | DM9X_INT_LNKCHG | DM9X_IMR_PAR)
  191. #define DM9X_IMRDISABLE (DM9X_IMR_PAR)
  192. /* EEPROM/PHY control regiser bits */
  193. #define DM9X_EEPHYC_ERRE (1 << 0) /* EEPROM (vs PHY) access status */
  194. #define DM9X_EEPHYC_ERPRW (1 << 1) /* EEPROM/PHY write access */
  195. #define DM9X_EEPHYC_ERPRR (1 << 2) /* EEPROM/PHY read access */
  196. #define DM9X_EEPHYC_EPOS (1 << 3) /* EEPROM/PHY operation select */
  197. #define DM9X_EEPHYC_WEP (1 << 4) /* Write EEPROM enable */
  198. #define DM9X_EEPHYC_REEP (1 << 5) /* Reload EEPROM */
  199. /* Supported values from the vendor and product ID register */
  200. #define DM9X_DAVICOMVID 0x0a46
  201. #define DM9X_DM9000PID 0x9000
  202. #define DM9X_DM9010PID 0x9010
  203. /* RX control register bit settings */
  204. #define DM9X_RXC_RXEN (1 << 0) /* RX enable */
  205. #define DM9X_RXC_PRMSC (1 << 1) /* Promiscuous mode */
  206. #define DM9X_RXC_RUNT (1 << 2) /* Pass runt packet */
  207. #define DM9X_RXC_ALL (1 << 3) /* Pass all multicast */
  208. #define DM9X_RXC_DISCRC (1 << 4) /* Discard CRC error packets */
  209. #define DM9X_RXC_DISLONG (1 << 5) /* Discard long packets */
  210. #define DM9X_RXC_WTDIS (1 << 6) /* Disable watchdog timer */
  211. #define DM9X_RXC_HASHALL (1 << 7) /* Filter all addresses in hash table */
  212. #define DM9X_RXCSETUP (DM9X_RXC_DISCRC | DM9X_RXC_DISLONG)
  213. /* EEPHY bit settings */
  214. #define DM9X_EEPHYA_EROA 0x40 /* PHY register address 0x01 */
  215. #define DM9X_PKTRDY 0x01 /* Packet ready to receive */
  216. /* The RX interrupt will be disabled if more than the following RX
  217. * interrupts are received back-to-back.
  218. */
  219. #define DM9X_CRXTHRES 10
  220. /* All access is via an index register and a data regist. Select accecss
  221. * according to user supplied base address and bus width.
  222. */
  223. #if defined(CONFIG_DM9X_BUSWIDTH8)
  224. # define DM9X_INDEX *(volatile uint8_t*)(CONFIG_DM9X_BASE)
  225. # define DM9X_DATA *(volatile uint8_t*)(CONFIG_DM9X_BASE + 2)
  226. #elif defined(CONFIG_DM9X_BUSWIDTH16)
  227. # define DM9X_INDEX *(volatile uint16_t*)(CONFIG_DM9X_BASE)
  228. # define DM9X_DATA *(volatile uint16_t*)(CONFIG_DM9X_BASE + 2)
  229. #elif defined(CONFIG_DM9X_BUSWIDTH32)
  230. # define DM9X_INDEX *(volatile uint32_t*)(CONFIG_DM9X_BASE)
  231. # define DM9X_DATA *(volatile uint32_t*)(CONFIG_DM9X_BASE + 2)
  232. #endif
  233. /* Phy operating mode. Default is AUTO, but this setting can be overridden
  234. * in the NuttX configuration file.
  235. */
  236. #if !defined(CONFIG_DM9X_MODE_AUTO) && !defined(CONFIG_DM9X_MODE_10MHD) && \
  237. !defined(CONFIG_DM9X_MODE_100MHD) && !defined(CONFIG_DM9X_MODE_10MFD) && \
  238. !defined(CONFIG_DM9X_MODE_100MFD)
  239. # define CONFIG_DM9X_MODE_AUTO 1
  240. #endif
  241. /* TX poll deley = 1 seconds. CLK_TCK is the number of clock ticks per second */
  242. #define DM9X_WDDELAY (1*CLK_TCK)
  243. /* TX timeout = 1 minute */
  244. #define DM6X_TXTIMEOUT (60*CLK_TCK)
  245. /* This is a helper pointer for accessing the contents of the Ethernet header */
  246. #define BUF ((struct eth_hdr_s *)priv->dm_dev.d_buf)
  247. /****************************************************************************
  248. * Private Types
  249. ****************************************************************************/
  250. union rx_desc_u
  251. {
  252. uint8_t rx_buf[4];
  253. struct
  254. {
  255. uint8_t rx_byte;
  256. uint8_t rx_status;
  257. uint16_t rx_len;
  258. } desc;
  259. };
  260. /* The dm9x_driver_s encapsulates all DM90x0 state information for a single
  261. * DM90x0 hardware interface
  262. */
  263. struct dm9x_driver_s
  264. {
  265. bool dm_bifup; /* true:ifup false:ifdown */
  266. bool dm_b100M; /* true:speed == 100M; false:speed == 10M */
  267. uint8_t dm_ntxpending; /* Count of packets pending transmission */
  268. uint8_t ncrxpackets; /* Number of continuous rx packets */
  269. WDOG_ID dm_txpoll; /* TX poll timer */
  270. WDOG_ID dm_txtimeout; /* TX timeout timer */
  271. struct work_s dm_irqwork; /* For deferring interrupt work to the work queue */
  272. struct work_s dm_pollwork; /* For deferring poll work to the work queue */
  273. /* Mode-dependent function to move data in 8/16/32 I/O modes */
  274. void (*dm_read)(uint8_t *ptr, int len);
  275. void (*dm_write)(const uint8_t *ptr, int len);
  276. void (*dm_discard)(int len);
  277. /* This holds the information visible to the NuttX network */
  278. struct net_driver_s dm_dev;
  279. };
  280. /****************************************************************************
  281. * Private Data
  282. ****************************************************************************/
  283. /* A single packet buffer is used */
  284. static uint8_t g_pktbuf[MAX_NETDEV_PKTSIZE + CONFIG_NET_GUARDSIZE];
  285. /* At present, only a single DM90x0 device is supported. */
  286. static struct dm9x_driver_s g_dm9x[CONFIG_DM9X_NINTERFACES];
  287. /****************************************************************************
  288. * Private Function Prototypes
  289. ****************************************************************************/
  290. /* Utility functions */
  291. static uint8_t getreg(int reg);
  292. static void putreg(int reg, uint8_t value);
  293. static void read8(uint8_t *ptr, int len);
  294. static void read16(uint8_t *ptr, int len);
  295. static void read32(uint8_t *ptr, int len);
  296. static void discard8(int len);
  297. static void discard16(int len);
  298. static void discard32(int len);
  299. static void write8(const uint8_t *ptr, int len);
  300. static void write16(const uint8_t *ptr, int len);
  301. static void write32(const uint8_t *ptr, int len);
  302. /* static uint16_t dm9x_readsrom(struct dm9x_driver_s *priv, int offset); */
  303. static uint16_t dm9x_phyread(struct dm9x_driver_s *priv, int reg);
  304. static void dm9x_phywrite(struct dm9x_driver_s *priv, int reg, uint16_t value);
  305. #if defined(CONFIG_DM9X_CHECKSUM)
  306. static bool dm9x_rxchecksumready(uint8_t);
  307. #else
  308. # define dm9x_rxchecksumready(a) ((a) == 0x01)
  309. #endif
  310. /* Common TX logic */
  311. static int dm9x_transmit(struct dm9x_driver_s *priv);
  312. static int dm9x_txpoll(struct net_driver_s *dev);
  313. /* Interrupt handling */
  314. static void dm9x_receive(struct dm9x_driver_s *priv);
  315. static void dm9x_txdone(struct dm9x_driver_s *priv);
  316. static void dm9x_interrupt_work(FAR void *arg);
  317. static int dm9x_interrupt(int irq, FAR void *context, FAR void *arg);
  318. /* Watchdog timer expirations */
  319. static void dm9x_txtimeout_work(FAR void *arg);
  320. static void dm9x_txtimeout_expiry(int argc, uint32_t arg, ...);
  321. static void dm9x_poll_work(FAR void *arg);
  322. static void dm9x_poll_expiry(int argc, uint32_t arg, ...);
  323. /* NuttX callback functions */
  324. static int dm9x_ifup(struct net_driver_s *dev);
  325. static int dm9x_ifdown(struct net_driver_s *dev);
  326. static void dm9x_txavail_work(FAR void *arg);
  327. static int dm9x_txavail(struct net_driver_s *dev);
  328. #ifdef CONFIG_NET_MCASTGROUP
  329. static int dm9x_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
  330. static int dm9x_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
  331. #endif
  332. /* Initialization functions */
  333. static void dm9x_bringup(struct dm9x_driver_s *priv);
  334. static void dm9x_reset(struct dm9x_driver_s *priv);
  335. /****************************************************************************
  336. * Private Functions
  337. ****************************************************************************/
  338. /****************************************************************************
  339. * Name: getreg and setreg
  340. *
  341. * Description:
  342. * Access to memory-mapped DM90x0 8-bit registers
  343. *
  344. * Input Parameters:
  345. * reg - Register number
  346. * value - Value to write to the register (setreg only)
  347. *
  348. * Returned Value:
  349. * Value read from the register (getreg only)
  350. *
  351. * Assumptions:
  352. *
  353. ****************************************************************************/
  354. static uint8_t getreg(int reg)
  355. {
  356. DM9X_INDEX = reg;
  357. return DM9X_DATA & 0xff;
  358. }
  359. static void putreg(int reg, uint8_t value)
  360. {
  361. DM9X_INDEX = reg;
  362. DM9X_DATA = value & 0xff;
  363. }
  364. /****************************************************************************
  365. * Name: read8, read16, read32
  366. *
  367. * Description:
  368. * Read packet data from the DM90x0 SRAM based on its current I/O mode
  369. *
  370. * Input Parameters:
  371. * ptr - Location to write the packet data
  372. * len - The number of bytes to read
  373. *
  374. * Returned Value:
  375. * None
  376. *
  377. * Assumptions:
  378. *
  379. ****************************************************************************/
  380. static void read8(FAR uint8_t *ptr, int len)
  381. {
  382. ninfo("Read %d bytes (8-bit mode)\n", len);
  383. for (; len > 0; len--)
  384. {
  385. *ptr++ = DM9X_DATA;
  386. }
  387. }
  388. static void read16(FAR uint8_t *ptr, int len)
  389. {
  390. FAR uint16_t *ptr16 = (FAR uint16_t *)ptr;
  391. ninfo("Read %d bytes (16-bit mode)\n", len);
  392. for (; len > 0; len -= sizeof(uint16_t))
  393. {
  394. *ptr16++ = DM9X_DATA;
  395. }
  396. }
  397. static void read32(FAR uint8_t *ptr, int len)
  398. {
  399. FAR uint32_t *ptr32 = (FAR uint32_t *)ptr;
  400. ninfo("Read %d bytes (32-bit mode)\n", len);
  401. for (; len > 0; len -= sizeof(uint32_t))
  402. {
  403. *ptr32++ = DM9X_DATA;
  404. }
  405. }
  406. /****************************************************************************
  407. * Name: discard8, discard16, discard32
  408. *
  409. * Description:
  410. * Read and discard packet data in the DM90x0 SRAM based on its current
  411. * I/O mode
  412. *
  413. * Input Parameters:
  414. * len - The number of bytes to discard
  415. *
  416. * Returned Value:
  417. * None
  418. *
  419. * Assumptions:
  420. *
  421. ****************************************************************************/
  422. static void discard8(int len)
  423. {
  424. ninfo("Discard %d bytes (8-bit mode)\n", len);
  425. for (; len > 0; len--)
  426. {
  427. DM9X_DATA;
  428. }
  429. }
  430. static void discard16(int len)
  431. {
  432. ninfo("Discard %d bytes (16-bit mode)\n", len);
  433. for (; len > 0; len -= sizeof(uint16_t))
  434. {
  435. DM9X_DATA;
  436. }
  437. }
  438. static void discard32(int len)
  439. {
  440. ninfo("Discard %d bytes (32-bit mode)\n", len);
  441. for (; len > 0; len -= sizeof(uint32_t))
  442. {
  443. DM9X_DATA;
  444. }
  445. }
  446. /****************************************************************************
  447. * Name: write8, write16, write32
  448. *
  449. * Description:
  450. * Write packet data into the DM90x0 SRAM based on its current I/O mode
  451. *
  452. * Input Parameters:
  453. * ptr - Location to write the packet data
  454. * len - The number of bytes to read
  455. *
  456. * Returned Value:
  457. * None
  458. *
  459. * Assumptions:
  460. *
  461. ****************************************************************************/
  462. static void write8(FAR const uint8_t *ptr, int len)
  463. {
  464. ninfo("Write %d bytes (8-bit mode)\n", len);
  465. for (; len > 0; len--)
  466. {
  467. DM9X_DATA = (*ptr++ & 0xff);
  468. }
  469. }
  470. static void write16(const uint8_t *ptr, int len)
  471. {
  472. FAR uint16_t *ptr16 = (FAR uint16_t *)ptr;
  473. ninfo("Write %d bytes (16-bit mode)\n", len);
  474. for (; len > 0; len -= sizeof(uint16_t))
  475. {
  476. DM9X_DATA = *ptr16++;
  477. }
  478. }
  479. static void write32(FAR const uint8_t *ptr, int len)
  480. {
  481. FAR uint32_t *ptr32 = (FAR uint32_t *)ptr;
  482. ninfo("Write %d bytes (32-bit mode)\n", len);
  483. for (; len > 0; len -= sizeof(uint32_t))
  484. {
  485. DM9X_DATA = *ptr32++;
  486. }
  487. }
  488. /****************************************************************************
  489. * Name: dm9x_readsrom
  490. *
  491. * Description:
  492. * Read a word from SROM
  493. *
  494. * Input Parameters:
  495. * priv - Reference to the driver state structure
  496. * offset - SROM offset to read from
  497. *
  498. * Returned Value:
  499. * SROM content at that offset
  500. *
  501. * Assumptions:
  502. *
  503. ****************************************************************************/
  504. #if 0 /* Not used */
  505. static uint16_t dm9x_readsrom(struct dm9x_driver_s *priv, int offset)
  506. {
  507. putreg(DM9X_EEPHYA, offset);
  508. putreg(DM9X_EEPHYC, DM9X_EEPHYC_ERPRR);
  509. up_udelay(200);
  510. putreg(DM9X_EEPHYC, 0x00);
  511. return (getreg(DM9X_EEPHYDL) + (getreg(DM9X_EEPHYDH) << 8));
  512. }
  513. #endif
  514. /****************************************************************************
  515. * Name: dm9x_phyread and dm9x_phywrite
  516. *
  517. * Description:
  518. * Read/write data from/to the PHY
  519. *
  520. * Input Parameters:
  521. * priv - Reference to the driver state structure
  522. * reg - PHY register offset
  523. * value - The value to write to the PHY register (dm9x_write only)
  524. *
  525. * Returned Value:
  526. * The value read from the PHY (dm9x_read only)
  527. *
  528. * Assumptions:
  529. *
  530. ****************************************************************************/
  531. static uint16_t dm9x_phyread(struct dm9x_driver_s *priv, int reg)
  532. {
  533. /* Setup DM9X_EEPHYA, the EEPROM/PHY address register */
  534. putreg(DM9X_EEPHYA, DM9X_EEPHYA_EROA | reg);
  535. /* Issue PHY read command pulse in the EEPROM/PHY control register */
  536. putreg(DM9X_EEPHYC, (DM9X_EEPHYC_ERPRR | DM9X_EEPHYC_EPOS));
  537. up_udelay(100);
  538. putreg(DM9X_EEPHYC, 0x00);
  539. /* Return the data from the EEPROM/PHY data register pair */
  540. return (((uint16_t)getreg(DM9X_EEPHYDH)) << 8) | (uint16_t)getreg(DM9X_EEPHYDL);
  541. }
  542. static void dm9x_phywrite(struct dm9x_driver_s *priv, int reg, uint16_t value)
  543. {
  544. /* Setup DM9X_EEPHYA, the EEPROM/PHY address register */
  545. putreg(DM9X_EEPHYA, DM9X_EEPHYA_EROA | reg);
  546. /* Put the data to write in the EEPROM/PHY data register pair */
  547. putreg(DM9X_EEPHYDL, (value & 0xff));
  548. putreg(DM9X_EEPHYDH, ((value >> 8) & 0xff));
  549. /* Issue PHY write command pulse in the EEPROM/PHY control register */
  550. putreg(DM9X_EEPHYC, (DM9X_EEPHYC_ERPRW | DM9X_EEPHYC_EPOS));
  551. up_udelay(500);
  552. putreg(DM9X_EEPHYC, 0x0);
  553. }
  554. /****************************************************************************
  555. * Name: dm9x_rxchecksumready
  556. *
  557. * Description:
  558. * Return true if the RX checksum is available
  559. *
  560. * Input Parameters:
  561. * rxbyte
  562. *
  563. * Returned Value:
  564. * true: checksum is ready
  565. *
  566. * Assumptions:
  567. *
  568. ****************************************************************************/
  569. #if defined(CONFIG_DM9X_CHECKSUM)
  570. static inline bool dm9x_rxchecksumready(uint8_t rxbyte)
  571. {
  572. if ((rxbyte & 0x01) == 0)
  573. {
  574. return false;
  575. }
  576. return ((rxbyte >> 4) | 0x01) != 0;
  577. }
  578. #endif
  579. /****************************************************************************
  580. * Name: dm9x_transmit
  581. *
  582. * Description:
  583. * Start hardware transmission. Called either from the txdone interrupt
  584. * handling or from watchdog based polling.
  585. *
  586. * Input Parameters:
  587. * priv - Reference to the driver state structure
  588. *
  589. * Returned Value:
  590. * OK on success; a negated errno on failure
  591. *
  592. * Assumptions:
  593. *
  594. ****************************************************************************/
  595. static int dm9x_transmit(struct dm9x_driver_s *priv)
  596. {
  597. /* Check if there is room in the DM90x0 to hold another packet. In 100M mode,
  598. * that can be 2 packets, otherwise it is a single packet.
  599. */
  600. if (priv->dm_ntxpending < 1 || (priv->dm_b100M && priv->dm_ntxpending < 2))
  601. {
  602. /* Increment count of packets transmitted */
  603. priv->dm_ntxpending++;
  604. NETDEV_TXPACKETS(&dm9x0->dm_dev);
  605. /* Disable all DM90x0 interrupts */
  606. putreg(DM9X_IMR, DM9X_IMRDISABLE);
  607. /* Set the TX length */
  608. putreg(DM9X_TXPLL, (priv->dm_dev.d_len & 0xff));
  609. putreg(DM9X_TXPLH, (priv->dm_dev.d_len >> 8) & 0xff);
  610. /* Move the data to be sent into TX SRAM */
  611. DM9X_INDEX = DM9X_MWCMD;
  612. priv->dm_write(priv->dm_dev.d_buf, priv->dm_dev.d_len);
  613. #if !defined(CONFIG_DM9X_ETRANS)
  614. /* Issue TX polling command */
  615. putreg(DM9X_TXC, 0x1); /* Cleared after TX complete */
  616. #endif
  617. /* Clear count of back-to-back RX packet transfers */
  618. priv->ncrxpackets = 0;
  619. /* Re-enable DM90x0 interrupts */
  620. putreg(DM9X_IMR, DM9X_IMRENABLE);
  621. /* Setup the TX timeout watchdog (perhaps restarting the timer) */
  622. (void)wd_start(priv->dm_txtimeout, DM6X_TXTIMEOUT, dm9x_txtimeout_expiry, 1,
  623. (wdparm_t)priv);
  624. return OK;
  625. }
  626. return -EBUSY;
  627. }
  628. /****************************************************************************
  629. * Name: dm9x_txpoll
  630. *
  631. * Description:
  632. * The transmitter is available, check if the network has any outgoing packets ready
  633. * to send. This is a callback from devif_poll(). devif_poll() may be called:
  634. *
  635. * 1. When the preceding TX packet send is complete,
  636. * 2. When the preceding TX packet send timesout and the DM90x0 is reset
  637. * 3. During normal TX polling
  638. *
  639. * Input Parameters:
  640. * dev - Reference to the NuttX driver state structure
  641. *
  642. * Returned Value:
  643. * OK on success; a negated errno on failure
  644. *
  645. * Assumptions:
  646. *
  647. ****************************************************************************/
  648. static int dm9x_txpoll(struct net_driver_s *dev)
  649. {
  650. struct dm9x_driver_s *priv = (struct dm9x_driver_s *)dev->d_private;
  651. /* If the polling resulted in data that should be sent out on the network,
  652. * the field d_len is set to a value > 0.
  653. */
  654. if (priv->dm_dev.d_len > 0)
  655. {
  656. /* Look up the destination MAC address and add it to the Ethernet
  657. * header.
  658. */
  659. #ifdef CONFIG_NET_IPv4
  660. #ifdef CONFIG_NET_IPv6
  661. if (IFF_IS_IPv4(priv->dm_dev.d_flags))
  662. #endif
  663. {
  664. arp_out(&priv->dm_dev);
  665. }
  666. #endif /* CONFIG_NET_IPv4 */
  667. #ifdef CONFIG_NET_IPv6
  668. #ifdef CONFIG_NET_IPv4
  669. else
  670. #endif
  671. {
  672. neighbor_out(&priv->dm_dev);
  673. }
  674. #endif /* CONFIG_NET_IPv6 */
  675. if (!devif_loopback(&priv->dm_dev))
  676. {
  677. /* Send the packet */
  678. dm9x_transmit(priv);
  679. /* Check if there is room in the DM90x0 to hold another packet. In 100M mode,
  680. * that can be 2 packets, otherwise it is a single packet.
  681. */
  682. if (priv->dm_ntxpending > 1 || !priv->dm_b100M)
  683. {
  684. /* Returning a non-zero value will terminate the poll operation */
  685. return 1;
  686. }
  687. }
  688. }
  689. /* If zero is returned, the polling will continue until all connections have
  690. * been examined.
  691. */
  692. return 0;
  693. }
  694. /****************************************************************************
  695. * Name: dm9x_receive
  696. *
  697. * Description:
  698. * An interrupt was received indicating the availability of a new RX packet
  699. *
  700. * Input Parameters:
  701. * priv - Reference to the driver state structure
  702. *
  703. * Returned Value:
  704. * None
  705. *
  706. * Assumptions:
  707. *
  708. ****************************************************************************/
  709. static void dm9x_receive(FAR struct dm9x_driver_s *priv)
  710. {
  711. union rx_desc_u rx;
  712. bool bchecksumready;
  713. uint8_t rxbyte;
  714. ninfo("Packet received\n");
  715. do
  716. {
  717. /* Store the value of memory data read address register */
  718. (void)getreg(DM9X_MDRAH);
  719. (void)getreg(DM9X_MDRAL);
  720. getreg(DM9X_MRCMDX); /* Dummy read */
  721. rxbyte = (uint8_t)DM9X_DATA; /* Get the most up-to-date data */
  722. /* Packet ready for receive check */
  723. bchecksumready = dm9x_rxchecksumready(rxbyte);
  724. if (!bchecksumready)
  725. {
  726. break;
  727. }
  728. /* A packet is ready now. Get status/length */
  729. DM9X_INDEX = DM9X_MRCMD; /* set read ptr ++ */
  730. /* Read packet status & length */
  731. priv->dm_read((FAR uint8_t *)&rx, 4);
  732. /* Check if any errors were reported by the hardware */
  733. if (rx.desc.rx_status & 0xbf)
  734. {
  735. /* Bad RX packet... update statistics */
  736. nerr("ERROR: Received packet with errors: %02x\n", rx.desc.rx_status);
  737. NETDEV_RXERRORS(&priv->dm_dev);
  738. /* Drop this packet and continue to check the next packet */
  739. priv->dm_discard(rx.desc.rx_len);
  740. }
  741. /* Also check if the packet is a valid size for the network configuration */
  742. else if (rx.desc.rx_len < ETH_HDRLEN || rx.desc.rx_len > (CONFIG_NET_ETH_PKTSIZE + 2))
  743. {
  744. nerr("ERROR: RX length error\n");
  745. NETDEV_RXERRORS(&priv->dm_dev);
  746. /* Drop this packet and continue to check the next packet */
  747. priv->dm_discard(rx.desc.rx_len);
  748. }
  749. else
  750. {
  751. /* Good packet... Copy the packet data out of SRAM and pass it one to the network */
  752. priv->dm_dev.d_len = rx.desc.rx_len;
  753. priv->dm_read(priv->dm_dev.d_buf, rx.desc.rx_len);
  754. #ifdef CONFIG_NET_PKT
  755. /* When packet sockets are enabled, feed the frame into the packet tap */
  756. pkt_input(&priv->dm_dev);
  757. #endif
  758. /* We only accept IP packets of the configured type and ARP packets */
  759. #ifdef CONFIG_NET_IPv4
  760. if (BUF->type == HTONS(ETHTYPE_IP))
  761. {
  762. ninfo("IPv4 frame\n");
  763. NETDEV_RXIPV4(&priv->dm_dev);
  764. /* Handle ARP on input then give the IPv4 packet to the network
  765. * layer
  766. */
  767. arp_ipin(&priv->dm_dev);
  768. ipv4_input(&priv->dm_dev);
  769. /* If the above function invocation resulted in data that should be
  770. * sent out on the network, the field d_len will set to a value > 0.
  771. */
  772. if (priv->dm_dev.d_len > 0)
  773. {
  774. /* Update the Ethernet header with the correct MAC address */
  775. #ifdef CONFIG_NET_IPv6
  776. if (IFF_IS_IPv4(priv->dm_dev.d_flags))
  777. #endif
  778. {
  779. arp_out(&priv->dm_dev);
  780. }
  781. #ifdef CONFIG_NET_IPv6
  782. else
  783. {
  784. neighbor_out(&priv->dm_dev);
  785. }
  786. #endif
  787. /* And send the packet */
  788. dm9x_transmit(priv);
  789. }
  790. }
  791. else
  792. #endif
  793. #ifdef CONFIG_NET_IPv6
  794. if (BUF->type == HTONS(ETHTYPE_IP6))
  795. {
  796. ninfo("Iv6 frame\n");
  797. NETDEV_RXIPV6(&priv->dm_dev);
  798. /* Give the IPv6 packet to the network layer */
  799. ipv6_input(&priv->dm_dev);
  800. /* If the above function invocation resulted in data that should be
  801. * sent out on the network, the field d_len will set to a value > 0.
  802. */
  803. if (priv->dm_dev.d_len > 0)
  804. {
  805. /* Update the Ethernet header with the correct MAC address */
  806. #ifdef CONFIG_NET_IPv4
  807. if (IFF_IS_IPv4(priv->dm_dev.d_flags))
  808. {
  809. arp_out(&priv->dm_dev);
  810. }
  811. else
  812. #endif
  813. #ifdef CONFIG_NET_IPv6
  814. {
  815. neighbor_out(&priv->dm_dev);
  816. }
  817. #endif
  818. /* And send the packet */
  819. dm9x_transmit(priv);
  820. }
  821. }
  822. else
  823. #endif
  824. #ifdef CONFIG_NET_ARP
  825. if (BUF->type == htons(ETHTYPE_ARP))
  826. {
  827. arp_arpin(&priv->dm_dev);
  828. NETDEV_RXARP(&priv->dm_dev);
  829. /* If the above function invocation resulted in data that should be
  830. * sent out on the network, the field d_len will set to a value > 0.
  831. */
  832. if (priv->dm_dev.d_len > 0)
  833. {
  834. dm9x_transmit(priv);
  835. }
  836. }
  837. #endif
  838. else
  839. {
  840. NETDEV_RXDROPPED(&priv->dm_dev);
  841. }
  842. }
  843. NETDEV_RXPACKETS(&priv->dm_dev);
  844. priv->ncrxpackets++;
  845. }
  846. while ((rxbyte & 0x01) == DM9X_PKTRDY && priv->ncrxpackets < DM9X_CRXTHRES);
  847. ninfo("All RX packets processed\n");
  848. }
  849. /****************************************************************************
  850. * Name: dm9x_txdone
  851. *
  852. * Description:
  853. * An interrupt was received indicating that the last TX packet(s) is done
  854. *
  855. * Input Parameters:
  856. * priv - Reference to the driver state structure
  857. *
  858. * Returned Value:
  859. * None
  860. *
  861. * Assumptions:
  862. *
  863. ****************************************************************************/
  864. static void dm9x_txdone(struct dm9x_driver_s *priv)
  865. {
  866. int nsr;
  867. ninfo("TX done\n");
  868. /* Another packet has completed transmission. Decrement the count of
  869. * of pending TX transmissions.
  870. */
  871. nsr = getreg(DM9X_NETS);
  872. if (nsr & DM9X_NETS_TX1END)
  873. {
  874. if (priv->dm_ntxpending)
  875. {
  876. priv->dm_ntxpending--;
  877. }
  878. else
  879. {
  880. nerr("ERROR: Bad TX count (TX1END)\n");
  881. }
  882. }
  883. if (nsr & DM9X_NETS_TX2END)
  884. {
  885. if (priv->dm_ntxpending)
  886. {
  887. priv->dm_ntxpending--;
  888. }
  889. else
  890. {
  891. nerr("ERROR: Bad TX count (TX2END)\n");
  892. }
  893. }
  894. /* Cancel the TX timeout */
  895. if (priv->dm_ntxpending == 0)
  896. {
  897. wd_cancel(priv->dm_txtimeout);
  898. }
  899. /* Then poll the network for new XMIT data */
  900. (void)devif_poll(&priv->dm_dev, dm9x_txpoll);
  901. }
  902. /****************************************************************************
  903. * Name: dm9x_interrupt_work
  904. *
  905. * Description:
  906. * Perform interrupt related work from the worker thread
  907. *
  908. * Input Parameters:
  909. * arg - The argument passed when work_queue() was called.
  910. *
  911. * Returned Value:
  912. * OK on success
  913. *
  914. * Assumptions:
  915. * The network is locked.
  916. *
  917. ****************************************************************************/
  918. static void dm9x_interrupt_work(FAR void *arg)
  919. {
  920. FAR struct dm9x_driver_s *priv = (FAR struct dm9x_driver_s *)arg;
  921. uint8_t isr;
  922. uint8_t save;
  923. int i;
  924. /* Process pending Ethernet interrupts */
  925. net_lock();
  926. /* Save previous register address */
  927. save = (uint8_t)DM9X_INDEX;
  928. /* Disable all DM90x0 interrupts */
  929. putreg(DM9X_IMR, DM9X_IMRDISABLE);
  930. /* Get and clear the DM90x0 interrupt status bits */
  931. isr = getreg(DM9X_ISR);
  932. putreg(DM9X_ISR, isr);
  933. ninfo("Interrupt status: %02x\n", isr);
  934. /* Check for link status change */
  935. if (isr & DM9X_INT_LNKCHG)
  936. {
  937. /* Wait up to 0.5s for link OK */
  938. for (i = 0; i < 500; i++)
  939. {
  940. dm9x_phyread(priv, 0x1);
  941. if (dm9x_phyread(priv, 0x1) & 0x4) /* Link OK */
  942. {
  943. /* Wait to get detected speed */
  944. for (i = 0; i < 200; i++)
  945. {
  946. up_mdelay(1);
  947. }
  948. /* Set the new network speed */
  949. if (dm9x_phyread(priv, 0) & 0x2000)
  950. {
  951. priv->dm_b100M = true;
  952. }
  953. else
  954. {
  955. priv->dm_b100M = false;
  956. }
  957. break;
  958. }
  959. up_mdelay(1);
  960. }
  961. nerr("ERROR: delay: %dmS speed: %s\n", i, priv->dm_b100M ? "100M" : "10M");
  962. }
  963. /* Check if we received an incoming packet */
  964. if (isr & DM9X_INT_PR)
  965. {
  966. dm9x_receive(priv);
  967. }
  968. /* Check if we are able to transmit a packet */
  969. if (isr & DM9X_INT_PT)
  970. {
  971. dm9x_txdone(priv);
  972. }
  973. /* If the number of consecutive receive packets exceeds a threshold,
  974. * then disable the RX interrupt.
  975. */
  976. if (priv->ncrxpackets >= DM9X_CRXTHRES)
  977. {
  978. /* Eanble all DM90x0 interrupts EXCEPT for RX */
  979. putreg(DM9X_IMR, DM9X_IMRRXDISABLE);
  980. }
  981. else
  982. {
  983. /* Enable all DM90x0 interrupts */
  984. putreg(DM9X_IMR, DM9X_IMRENABLE);
  985. }
  986. /* Restore previous register address */
  987. DM9X_INDEX = save;
  988. net_unlock();
  989. /* Re-enable Ethernet interrupts */
  990. up_enable_irq(CONFIG_DM9X_IRQ);
  991. }
  992. /****************************************************************************
  993. * Name: dm9x_interrupt
  994. *
  995. * Description:
  996. * Hardware interrupt handler
  997. *
  998. * Input Parameters:
  999. * irq - Number of the IRQ that generated the interrupt
  1000. * context - Interrupt register state save info (architecture-specific)
  1001. *
  1002. * Returned Value:
  1003. * OK on success
  1004. *
  1005. * Assumptions:
  1006. *
  1007. ****************************************************************************/
  1008. static int dm9x_interrupt(int irq, FAR void *context, FAR void *arg)
  1009. {
  1010. #if CONFIG_DM9X_NINTERFACES == 1
  1011. FAR struct dm9x_driver_s *priv = &g_dm9x[0];
  1012. #else
  1013. # error "Additional logic needed to support multiple interfaces"
  1014. #endif
  1015. uint8_t isr;
  1016. /* Disable further Ethernet interrupts. Because Ethernet interrupts are
  1017. * also disabled if the TX timeout event occurs, there can be no race
  1018. * condition here.
  1019. */
  1020. up_disable_irq(CONFIG_DM9X_IRQ);
  1021. /* Determine if a TX transfer just completed */
  1022. isr = getreg(DM9X_ISR);
  1023. if ((isr & DM9X_INT_PT) != 0)
  1024. {
  1025. /* If a TX transfer just completed, then cancel the TX timeout so
  1026. * there will be no race condition between any subsequent timeout
  1027. * expiration and the deferred interrupt processing.
  1028. */
  1029. wd_cancel(priv->dm_txtimeout);
  1030. }
  1031. /* Schedule to perform the interrupt processing on the worker thread. */
  1032. work_queue(ETHWORK, &priv->dm_irqwork, dm9x_interrupt_work, priv, 0);
  1033. return OK;
  1034. }
  1035. /****************************************************************************
  1036. * Name: dm9x_txtimeout_work
  1037. *
  1038. * Description:
  1039. * Perform TX timeout related work from the worker thread
  1040. *
  1041. * Input Parameters:
  1042. * arg - The argument passed when work_queue() as called.
  1043. *
  1044. * Returned Value:
  1045. * OK on success
  1046. *
  1047. * Assumptions:
  1048. * The network is locked.
  1049. *
  1050. ****************************************************************************/
  1051. static void dm9x_txtimeout_work(FAR void *arg)
  1052. {
  1053. FAR struct dm9x_driver_s *priv = (FAR struct dm9x_driver_s *)arg;
  1054. nerr("ERROR: TX timeout\n");
  1055. /* Increment statistics and dump debug info */
  1056. net_lock();
  1057. NETDEV_TXTIMEOUTS(priv->dm_dev);
  1058. ninfo(" TX packet count: %d\n", priv->dm_ntxpending);
  1059. ninfo(" TX read pointer address: 0x%02x:%02x\n",
  1060. getreg(DM9X_TRPAH), getreg(DM9X_TRPAL));
  1061. ninfo(" Memory data write address: 0x%02x:%02x (DM9010)\n",
  1062. getreg(DM9X_MDWAH), getreg(DM9X_MDWAL));
  1063. /* Then reset the DM90x0 */
  1064. dm9x_reset(priv);
  1065. /* Then poll the network for new XMIT data */
  1066. (void)devif_poll(&priv->dm_dev, dm9x_txpoll);
  1067. net_unlock();
  1068. }
  1069. /****************************************************************************
  1070. * Name: dm9x_txtimeout_expiry
  1071. *
  1072. * Description:
  1073. * Our TX watchdog timed out. Called from the timer interrupt handler.
  1074. * The last TX never completed. Reset the hardware and start again.
  1075. *
  1076. * Input Parameters:
  1077. * argc - The number of available arguments
  1078. * arg - The first argument
  1079. *
  1080. * Returned Value:
  1081. * None
  1082. *
  1083. * Assumptions:
  1084. * Global interrupts are disabled by the watchdog logic.
  1085. *
  1086. ****************************************************************************/
  1087. static void dm9x_txtimeout_expiry(int argc, wdparm_t arg, ...)
  1088. {
  1089. FAR struct dm9x_driver_s *priv = (FAR struct dm9x_driver_s *)arg;
  1090. /* Disable further Ethernet interrupts. This will prevent some race
  1091. * conditions with interrupt work. There is still a potential race
  1092. * condition with interrupt work that is already queued and in progress.
  1093. */
  1094. up_disable_irq(CONFIG_DM9X_IRQ);
  1095. /* Schedule to perform the TX timeout processing on the worker thread. */
  1096. work_queue(ETHWORK, &priv->dm_irqwork, dm9x_txtimeout_work, priv, 0);
  1097. }
  1098. /****************************************************************************
  1099. * Name: dm9x_poll_work
  1100. *
  1101. * Description:
  1102. * Perform periodic polling from the worker thread
  1103. *
  1104. * Input Parameters:
  1105. * arg - The argument passed when work_queue() as called.
  1106. *
  1107. * Returned Value:
  1108. * OK on success
  1109. *
  1110. * Assumptions:
  1111. * The network is locked.
  1112. *
  1113. ****************************************************************************/
  1114. static void dm9x_poll_work(FAR void *arg)
  1115. {
  1116. FAR struct dm9x_driver_s *priv = (FAR struct dm9x_driver_s *)arg;
  1117. /* Perform the poll */
  1118. net_lock();
  1119. /* If the number of contiguous RX packets exceeds a threshold, reset the counter and
  1120. * re-enable RX interrupts
  1121. */
  1122. if (priv->ncrxpackets >= DM9X_CRXTHRES)
  1123. {
  1124. priv->ncrxpackets = 0;
  1125. putreg(DM9X_IMR, DM9X_IMRENABLE);
  1126. }
  1127. /* Check if there is room in the DM90x0 to hold another packet. In 100M mode,
  1128. * that can be 2 packets, otherwise it is a single packet.
  1129. */
  1130. if (priv->dm_ntxpending < 1 || (priv->dm_b100M && priv->dm_ntxpending < 2))
  1131. {
  1132. /* If so, update TCP timing states and poll the network for new XMIT data */
  1133. (void)devif_timer(&priv->dm_dev, dm9x_txpoll);
  1134. }
  1135. /* Setup the watchdog poll timer again */
  1136. (void)wd_start(priv->dm_txpoll, DM9X_WDDELAY, dm9x_poll_expiry, 1,
  1137. (wdparm_t)priv);
  1138. net_unlock();
  1139. }
  1140. /****************************************************************************
  1141. * Name: dm9x_poll_expiry
  1142. *
  1143. * Description:
  1144. * Periodic timer handler. Called from the timer interrupt handler.
  1145. *
  1146. * Input Parameters:
  1147. * argc - The number of available arguments
  1148. * arg - The first argument
  1149. *
  1150. * Returned Value:
  1151. * None
  1152. *
  1153. * Assumptions:
  1154. * Global interrupts are disabled by the watchdog logic.
  1155. *
  1156. ****************************************************************************/
  1157. static void dm9x_poll_expiry(int argc, wdparm_t arg, ...)
  1158. {
  1159. FAR struct dm9x_driver_s *priv = (FAR struct dm9x_driver_s *)arg;
  1160. /* Schedule to perform the interrupt processing on the worker thread. */
  1161. work_queue(ETHWORK, &priv->dm_pollwork, dm9x_poll_work, priv, 0);
  1162. }
  1163. /****************************************************************************
  1164. * Name: dm9x_phymode
  1165. *
  1166. * Description:
  1167. * Configure the PHY operating mode
  1168. *
  1169. * Input Parameters:
  1170. * priv - Reference to the driver state structure
  1171. *
  1172. * Returned Value:
  1173. * None
  1174. *
  1175. * Assumptions:
  1176. *
  1177. ****************************************************************************/
  1178. static inline void dm9x_phymode(struct dm9x_driver_s *priv)
  1179. {
  1180. uint16_t phyreg0;
  1181. uint16_t phyreg4;
  1182. #ifdef CONFIG_DM9X_MODE_AUTO
  1183. phyreg0 = 0x1200; /* Auto-negotiation & Restart Auto-negotiation */
  1184. phyreg4 = 0x01e1; /* Default flow control disable */
  1185. #elif defined(CONFIG_DM9X_MODE_10MHD)
  1186. phyreg4 = 0x21;
  1187. phyreg0 = 0x1000;
  1188. #elif defined(CONFIG_DM9X_MODE_10MFD)
  1189. phyreg4 = 0x41;
  1190. phyreg0 = 0x1100;
  1191. #elif defined(CONFIG_DM9X_MODE_100MHD)
  1192. phyreg4 = 0x81;
  1193. phyreg0 = 0x3000;
  1194. #elif defined(CONFIG_DM9X_MODE_100MFD)
  1195. phyreg4 = 0x101;
  1196. phyreg0 = 0x3100;
  1197. #else
  1198. # error "Recognized PHY mode"
  1199. #endif
  1200. dm9x_phywrite(priv, 0, phyreg0);
  1201. dm9x_phywrite(priv, 4, phyreg4);
  1202. }
  1203. /****************************************************************************
  1204. * Name: dm9x_ifup
  1205. *
  1206. * Description:
  1207. * NuttX Callback: Bring up the DM90x0 interface when an IP address is
  1208. * provided
  1209. *
  1210. * Input Parameters:
  1211. * dev - Reference to the NuttX driver state structure
  1212. *
  1213. * Returned Value:
  1214. * None
  1215. *
  1216. * Assumptions:
  1217. *
  1218. ****************************************************************************/
  1219. static int dm9x_ifup(struct net_driver_s *dev)
  1220. {
  1221. struct dm9x_driver_s *priv = (struct dm9x_driver_s *)dev->d_private;
  1222. uint8_t netstatus;
  1223. int i;
  1224. ninfo("Bringing up: %d.%d.%d.%d\n",
  1225. dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff,
  1226. (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24);
  1227. /* Initilize DM90x0 chip */
  1228. dm9x_bringup(priv);
  1229. /* Check link state and media speed (waiting up to 3s for link OK) */
  1230. priv->dm_b100M = false;
  1231. for (i = 0; i < 3000; i++)
  1232. {
  1233. netstatus = getreg(DM9X_NETS);
  1234. if (netstatus & DM9X_NETS_LINKST)
  1235. {
  1236. /* Link OK... Wait a bit before getting the detected speed */
  1237. up_mdelay(200);
  1238. netstatus = getreg(DM9X_NETS);
  1239. if ((netstatus & DM9X_NETS_SPEED) == 0)
  1240. {
  1241. priv->dm_b100M = true;
  1242. }
  1243. break;
  1244. }
  1245. i++;
  1246. up_mdelay(1);
  1247. }
  1248. ninfo("delay: %dmS speed: %s\n", i, priv->dm_b100M ? "100M" : "10M");
  1249. /* Set and activate a timer process */
  1250. (void)wd_start(priv->dm_txpoll, DM9X_WDDELAY, dm9x_poll_expiry, 1,
  1251. (wdparm_t)priv);
  1252. /* Enable the DM9X interrupt */
  1253. priv->dm_bifup = true;
  1254. up_enable_irq(CONFIG_DM9X_IRQ);
  1255. return OK;
  1256. }
  1257. /****************************************************************************
  1258. * Name: dm9x_ifdown
  1259. *
  1260. * Description:
  1261. * NuttX Callback: Stop the interface.
  1262. *
  1263. * Input Parameters:
  1264. * dev - Reference to the NuttX driver state structure
  1265. *
  1266. * Returned Value:
  1267. * None
  1268. *
  1269. * Assumptions:
  1270. *
  1271. ****************************************************************************/
  1272. static int dm9x_ifdown(struct net_driver_s *dev)
  1273. {
  1274. struct dm9x_driver_s *priv = (struct dm9x_driver_s *)dev->d_private;
  1275. irqstate_t flags;
  1276. ninfo("Stopping\n");
  1277. /* Disable the DM9X interrupt */
  1278. flags = enter_critical_section();
  1279. up_disable_irq(CONFIG_DM9X_IRQ);
  1280. /* Cancel the TX poll timer and TX timeout timers */
  1281. wd_cancel(priv->dm_txpoll);
  1282. wd_cancel(priv->dm_txtimeout);
  1283. /* Reset the device */
  1284. dm9x_phywrite(priv, 0x00, 0x8000); /* PHY reset */
  1285. putreg(DM9X_GPD, 0x01); /* Power-down PHY (GEPIO0=1) */
  1286. putreg(DM9X_IMR, DM9X_IMRDISABLE); /* Disable all interrupts */
  1287. putreg(DM9X_RXC, 0x00); /* Disable RX */
  1288. putreg(DM9X_ISR, DM9X_INT_ALL); /* Clear interrupt status */
  1289. priv->dm_bifup = false;
  1290. leave_critical_section(flags);
  1291. return OK;
  1292. }
  1293. /****************************************************************************
  1294. * Name: dm9x_txavail_work
  1295. *
  1296. * Description:
  1297. * Perform an out-of-cycle poll on the worker thread.
  1298. *
  1299. * Input Parameters:
  1300. * arg - Reference to the NuttX driver state structure (cast to void*)
  1301. *
  1302. * Returned Value:
  1303. * None
  1304. *
  1305. * Assumptions:
  1306. * Called on the higher priority worker thread.
  1307. *
  1308. ****************************************************************************/
  1309. static void dm9x_txavail_work(FAR void *arg)
  1310. {
  1311. FAR struct dm9x_driver_s *priv = (FAR struct dm9x_driver_s *)arg;
  1312. ninfo("Polling\n");
  1313. /* Ignore the notification if the interface is not yet up */
  1314. net_lock();
  1315. if (priv->dm_bifup)
  1316. {
  1317. /* Check if there is room in the DM90x0 to hold another packet. In 100M
  1318. * mode, that can be 2 packets, otherwise it is a single packet.
  1319. */
  1320. if (priv->dm_ntxpending < 1 || (priv->dm_b100M && priv->dm_ntxpending < 2))
  1321. {
  1322. /* If so, then poll the network for new XMIT data */
  1323. (void)devif_poll(&priv->dm_dev, dm9x_txpoll);
  1324. }
  1325. }
  1326. net_unlock();
  1327. }
  1328. /****************************************************************************
  1329. * Name: dm9x_txavail
  1330. *
  1331. * Description:
  1332. * Driver callback invoked when new TX data is available. This is a
  1333. * stimulus perform an out-of-cycle poll and, thereby, reduce the TX
  1334. * latency.
  1335. *
  1336. * Input Parameters:
  1337. * dev - Reference to the NuttX driver state structure
  1338. *
  1339. * Returned Value:
  1340. * None
  1341. *
  1342. * Assumptions:
  1343. * Called in normal user mode
  1344. *
  1345. ****************************************************************************/
  1346. static int dm9x_txavail(FAR struct net_driver_s *dev)
  1347. {
  1348. FAR struct dm9x_driver_s *priv = (FAR struct dm9x_driver_s *)dev->d_private;
  1349. /* Is our single work structure available? It may not be if there are
  1350. * pending interrupt actions and we will have to ignore the Tx
  1351. * availability action.
  1352. */
  1353. if (work_available(&priv->dm_pollwork))
  1354. {
  1355. /* Schedule to serialize the poll on the worker thread. */
  1356. work_queue(ETHWORK, &priv->dm_pollwork, dm9x_txavail_work, priv, 0);
  1357. }
  1358. return OK;
  1359. }
  1360. /****************************************************************************
  1361. * Name: dm9x_addmac
  1362. *
  1363. * Description:
  1364. * NuttX Callback: Add the specified MAC address to the hardware multicast
  1365. * address filtering
  1366. *
  1367. * Input Parameters:
  1368. * dev - Reference to the NuttX driver state structure
  1369. * mac - The MAC address to be added
  1370. *
  1371. * Returned Value:
  1372. * None
  1373. *
  1374. * Assumptions:
  1375. *
  1376. ****************************************************************************/
  1377. #ifdef CONFIG_NET_MCASTGROUP
  1378. static int dm9x_addmac(struct net_driver_s *dev, FAR const uint8_t *mac)
  1379. {
  1380. FAR struct dm9x_driver_s *priv = (FAR struct dm9x_driver_s *)dev->d_private;
  1381. /* Add the MAC address to the hardware multicast routing table */
  1382. #warning "Multicast MAC support not implemented"
  1383. return OK;
  1384. }
  1385. #endif
  1386. /****************************************************************************
  1387. * Name: dm9x_rmmac
  1388. *
  1389. * Description:
  1390. * NuttX Callback: Remove the specified MAC address from the hardware multicast
  1391. * address filtering
  1392. *
  1393. * Input Parameters:
  1394. * dev - Reference to the NuttX driver state structure
  1395. * mac - The MAC address to be removed
  1396. *
  1397. * Returned Value:
  1398. * None
  1399. *
  1400. * Assumptions:
  1401. *
  1402. ****************************************************************************/
  1403. #ifdef CONFIG_NET_MCASTGROUP
  1404. static int dm9x_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac)
  1405. {
  1406. FAR struct dm9x_driver_s *priv = (FAR struct dm9x_driver_s *)dev->d_private;
  1407. /* Add the MAC address to the hardware multicast routing table */
  1408. #warning "Multicast MAC support not implemented"
  1409. return OK;
  1410. }
  1411. #endif
  1412. /****************************************************************************
  1413. * Name: dm9x_bringup
  1414. *
  1415. * Description:
  1416. * Initialize the dm90x0 chip
  1417. *
  1418. * Input Parameters:
  1419. * priv - Reference to the driver state structure
  1420. *
  1421. * Returned Value:
  1422. * None
  1423. *
  1424. * Assumptions:
  1425. *
  1426. ****************************************************************************/
  1427. static void dm9x_bringup(struct dm9x_driver_s *priv)
  1428. {
  1429. ninfo("Initializing\n");
  1430. /* Set the internal PHY power-on, GPIOs normal, and wait 2ms */
  1431. putreg(DM9X_GPD, 0x01); /* Power-down the PHY (GEPIO0=1) */
  1432. up_udelay(500);
  1433. putreg(DM9X_GPD, 0x00); /* Preactivate PHY (GPIO0=0 */
  1434. up_udelay(20); /* Wait 20us for PHY power-on ready */
  1435. /* Do a software reset and wait 20us (twice). The reset autoclears
  1436. * in 10us; 20us guarantees completion of the reset
  1437. */
  1438. putreg(DM9X_NETC, (DM9X_NETC_RST | DM9X_NETC_LBK1));
  1439. up_udelay(20);
  1440. putreg(DM9X_NETC, (DM9X_NETC_RST | DM9X_NETC_LBK1));
  1441. up_udelay(20);
  1442. /* Configure I/O mode */
  1443. switch (getreg(DM9X_ISR) & DM9X_ISR_IOMODEM)
  1444. {
  1445. case DM9X_ISR_IOMODE8:
  1446. priv->dm_read = read8;
  1447. priv->dm_write = write8;
  1448. priv->dm_discard = discard8;
  1449. break;
  1450. case DM9X_ISR_IOMODE16:
  1451. priv->dm_read = read16;
  1452. priv->dm_write = write16;
  1453. priv->dm_discard = discard16;
  1454. break;
  1455. case DM9X_ISR_IOMODE32:
  1456. priv->dm_read = read32;
  1457. priv->dm_write = write32;
  1458. priv->dm_discard = discard32;
  1459. break;
  1460. default:
  1461. break;
  1462. }
  1463. /* Program PHY operating mode */
  1464. dm9x_phymode(priv);
  1465. /* Program operating mode */
  1466. putreg(DM9X_NETC, 0x00); /* Network control */
  1467. putreg(DM9X_TXC, 0x00); /* Clear TX Polling */
  1468. putreg(DM9X_BPTHRES, 0x3f); /* Less 3kb, 600us */
  1469. putreg(DM9X_SMODEC, 0x00); /* Special mode */
  1470. putreg(DM9X_NETS, (DM9X_NETS_WAKEST | DM9X_NETS_TX1END | DM9X_NETS_TX2END)); /* Clear TX status */
  1471. putreg(DM9X_ISR, DM9X_INT_ALL); /* Clear interrupt status */
  1472. #if defined(CONFIG_DM9X_CHECKSUM)
  1473. putreg(DM9X_TCCR, 0x07); /* TX UDP/TCP/IP checksum enable */
  1474. putreg(DM9X_RCSR, 0x02); /* Receive checksum enable */
  1475. #endif
  1476. #if defined(CONFIG_DM9X_ETRANS)
  1477. putreg(DM9X_ETXCSR, 0x83);
  1478. #endif
  1479. /* Initialize statistics */
  1480. priv->ncrxpackets = 0; /* Number of continuous RX packets */
  1481. priv->dm_ntxpending = 0; /* Number of pending TX packets */
  1482. NETDEV_RESET_STATISTICS(&priv->dm_dev);
  1483. /* Activate DM9000A/DM9010 */
  1484. putreg(DM9X_RXC, DM9X_RXCSETUP | 1); /* RX enable */
  1485. putreg(DM9X_IMR, DM9X_IMRENABLE); /* Enable TX/RX interrupts */
  1486. }
  1487. /****************************************************************************
  1488. * Name: dm9x_reset
  1489. *
  1490. * Description:
  1491. * Stop, reset, re-initialize, and restart the DM90x0 chip and driver. At
  1492. * present, the chip is only reset after a TX timeout.
  1493. *
  1494. * Input Parameters:
  1495. * priv - Reference to the driver state structure
  1496. *
  1497. * Returned Value:
  1498. * None
  1499. *
  1500. * Assumptions:
  1501. *
  1502. ****************************************************************************/
  1503. static void dm9x_reset(struct dm9x_driver_s *priv)
  1504. {
  1505. uint8_t save;
  1506. int i;
  1507. /* Cancel the TX poll timer and TX timeout timers */
  1508. wd_cancel(priv->dm_txpoll);
  1509. wd_cancel(priv->dm_txtimeout);
  1510. /* Save previous register address */
  1511. save = (uint8_t)DM9X_INDEX;
  1512. dm9x_bringup(priv);
  1513. /* Wait up to 1 second for the link to be OK */
  1514. priv->dm_b100M = false;
  1515. for (i = 0; i < 1000; i++)
  1516. {
  1517. if (dm9x_phyread(priv, 0x1) & 0x4)
  1518. {
  1519. if (dm9x_phyread(priv, 0) &0x2000)
  1520. {
  1521. priv->dm_b100M = true;
  1522. }
  1523. break;
  1524. }
  1525. up_mdelay(1);
  1526. }
  1527. /* Restore previous register address */
  1528. DM9X_INDEX = save;
  1529. }
  1530. /****************************************************************************
  1531. * Public Functions
  1532. ****************************************************************************/
  1533. /****************************************************************************
  1534. * Name: dm9x_initialize
  1535. *
  1536. * Description:
  1537. * Initialize the DM90x0 driver
  1538. *
  1539. * Input Parameters:
  1540. * None
  1541. *
  1542. * Returned Value:
  1543. * OK on success; Negated errno on failure.
  1544. *
  1545. * Assumptions:
  1546. *
  1547. ****************************************************************************/
  1548. /* Initialize the DM90x0 chip and driver */
  1549. int dm9x_initialize(void)
  1550. {
  1551. uint8_t *mptr;
  1552. uint16_t vid;
  1553. uint16_t pid;
  1554. int i;
  1555. int j;
  1556. /* Get the chip vendor ID and product ID */
  1557. vid = (((uint16_t)getreg(DM9X_VIDH)) << 8) | (uint16_t)getreg(DM9X_VIDL);
  1558. pid = (((uint16_t)getreg(DM9X_PIDH)) << 8) | (uint16_t)getreg(DM9X_PIDL);
  1559. ninfo("I/O base: %08x VID: %04x PID: %04x\n", CONFIG_DM9X_BASE, vid, pid);
  1560. /* Check if a DM90x0 chip is recognized at this I/O base */
  1561. if (vid != DM9X_DAVICOMVID || (pid != DM9X_DM9000PID && pid != DM9X_DM9010PID))
  1562. {
  1563. nerr("ERROR: DM90x0 vendor/product ID not found at this base address\n");
  1564. return -ENODEV;
  1565. }
  1566. /* Attach the IRQ to the driver */
  1567. if (irq_attach(CONFIG_DM9X_IRQ, dm9x_interrupt, NULL))
  1568. {
  1569. /* We could not attach the ISR to the ISR */
  1570. nerr("ERROR: irq_attach() failed\n");
  1571. return -EAGAIN;
  1572. }
  1573. /* Initialize the driver structure */
  1574. memset(g_dm9x, 0, CONFIG_DM9X_NINTERFACES*sizeof(struct dm9x_driver_s));
  1575. g_dm9x[0].dm_dev.d_buf = g_pktbuf; /* Single packet buffer */
  1576. g_dm9x[0].dm_dev.d_ifup = dm9x_ifup; /* I/F down callback */
  1577. g_dm9x[0].dm_dev.d_ifdown = dm9x_ifdown; /* I/F up (new IP address) callback */
  1578. g_dm9x[0].dm_dev.d_txavail = dm9x_txavail; /* New TX data callback */
  1579. #ifdef CONFIG_NET_MCASTGROUP
  1580. g_dm9x[0].dm_dev.d_addmac = dm9x_addmac; /* Add multicast MAC address */
  1581. g_dm9x[0].dm_dev.d_rmmac = dm9x_rmmac; /* Remove multicast MAC address */
  1582. #endif
  1583. g_dm9x[0].dm_dev.d_private = (FAR void *)g_dm9x; /* Used to recover private state from dev */
  1584. /* Create a watchdog for timing polling for and timing of transmissions */
  1585. g_dm9x[0].dm_txpoll = wd_create(); /* Create periodic poll timer */
  1586. g_dm9x[0].dm_txtimeout = wd_create(); /* Create TX timeout timer */
  1587. /* Read the MAC address */
  1588. mptr = g_dm9x[0].dm_dev.d_mac.ether.ether_addr_octet;
  1589. for (i = 0, j = DM9X_PAB0; i < ETHER_ADDR_LEN; i++, j++)
  1590. {
  1591. mptr[i] = getreg(j);
  1592. }
  1593. ninfo("MAC: %0x:%0x:%0x:%0x:%0x:%0x\n",
  1594. mptr[0], mptr[1], mptr[2], mptr[3], mptr[4], mptr[5]);
  1595. /* Register the device with the OS so that socket IOCTLs can be performed */
  1596. (void)netdev_register(&g_dm9x[0].dm_dev, NET_LL_ETHERNET);
  1597. return OK;
  1598. }
  1599. #endif /* CONFIG_NET && CONFIG_NET_DM90x0 */