plb2800_eth.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /*
  2. * PLB2800 internal switch ethernet driver.
  3. *
  4. * (C) Copyright 2003
  5. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  6. *
  7. * See file CREDITS for list of people who contributed to this
  8. * project.
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License as
  12. * published by the Free Software Foundation; either version 2 of
  13. * the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23. * MA 02111-1307 USA
  24. */
  25. #include <common.h>
  26. #if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) \
  27. && defined(CONFIG_PLB2800_ETHER)
  28. #include <malloc.h>
  29. #include <net.h>
  30. #include <asm/addrspace.h>
  31. #define NUM_RX_DESC PKTBUFSRX
  32. #define TOUT_LOOP 1000000
  33. #define LONG_REF(addr) (*((volatile unsigned long*)addr))
  34. #define CMAC_CRX_CTRL LONG_REF(0xb800c870)
  35. #define CMAC_CTX_CTRL LONG_REF(0xb800c874)
  36. #define SYS_MAC_ADDR_0 LONG_REF(0xb800c878)
  37. #define SYS_MAC_ADDR_1 LONG_REF(0xb800c87c)
  38. #define MIPS_H_MASK LONG_REF(0xB800C810)
  39. #define MA_LEARN LONG_REF(0xb8008004)
  40. #define DA_LOOKUP LONG_REF(0xb8008008)
  41. #define CMAC_CRX_CTRL_PD 0x00000001
  42. #define CMAC_CRX_CTRL_CG 0x00000002
  43. #define CMAC_CRX_CTRL_PL_SHIFT 2
  44. #define CMAC_CRIT 0x0
  45. #define CMAC_NON_CRIT 0x1
  46. #define MBOX_STAT_ID_SHF 28
  47. #define MBOX_STAT_CP 0x80000000
  48. #define MBOX_STAT_MB 0x00000001
  49. #define EN_MA_LEARN 0x02000000
  50. #define EN_DA_LKUP 0x01000000
  51. #define MA_DEST_SHF 11
  52. #define DA_DEST_SHF 11
  53. #define DA_STATE_SHF 19
  54. #define TSTAMP_MS 0x00000000
  55. #define SW_H_MBOX4_MASK 0x08000000
  56. #define SW_H_MBOX3_MASK 0x04000000
  57. #define SW_H_MBOX2_MASK 0x02000000
  58. #define SW_H_MBOX1_MASK 0x01000000
  59. typedef volatile struct {
  60. unsigned int stat;
  61. unsigned int cmd;
  62. unsigned int cnt;
  63. unsigned int adr;
  64. } mailbox_t;
  65. #define MBOX_REG(mb) ((mailbox_t*)(0xb800c830+(mb<<4)))
  66. typedef volatile struct {
  67. unsigned int word0;
  68. unsigned int word1;
  69. unsigned int word2;
  70. } mbhdr_t;
  71. #define MBOX_MEM(mb) ((void*)(0xb800a000+((3-mb)<<11)))
  72. static int plb2800_eth_init(struct eth_device *dev, bd_t * bis);
  73. static int plb2800_eth_send(struct eth_device *dev, volatile void *packet,
  74. int length);
  75. static int plb2800_eth_recv(struct eth_device *dev);
  76. static void plb2800_eth_halt(struct eth_device *dev);
  77. static void plb2800_set_mac_addr(struct eth_device *dev, unsigned char * addr);
  78. static unsigned char * plb2800_get_mac_addr(void);
  79. static int rx_new;
  80. static int mac_addr_set = 0;
  81. int plb2800_eth_initialize(bd_t * bis)
  82. {
  83. struct eth_device *dev;
  84. ulong temp;
  85. #ifdef DEBUG
  86. printf("Entered plb2800_eth_initialize()\n");
  87. #endif
  88. if (!(dev = (struct eth_device *) malloc (sizeof *dev)))
  89. {
  90. printf("Failed to allocate memory\n");
  91. return 0;
  92. }
  93. memset(dev, 0, sizeof(*dev));
  94. sprintf(dev->name, "PLB2800 Switch");
  95. dev->init = plb2800_eth_init;
  96. dev->halt = plb2800_eth_halt;
  97. dev->send = plb2800_eth_send;
  98. dev->recv = plb2800_eth_recv;
  99. eth_register(dev);
  100. /* bug fix */
  101. *(ulong *)0xb800e800 = 0x838;
  102. /* Set MBOX ownership */
  103. temp = CMAC_CRIT << MBOX_STAT_ID_SHF;
  104. MBOX_REG(0)->stat = temp;
  105. MBOX_REG(1)->stat = temp;
  106. temp = CMAC_NON_CRIT << MBOX_STAT_ID_SHF;
  107. MBOX_REG(2)->stat = temp;
  108. MBOX_REG(3)->stat = temp;
  109. plb2800_set_mac_addr(dev, plb2800_get_mac_addr());
  110. /* Disable all Mbox interrupt */
  111. temp = MIPS_H_MASK;
  112. temp &= ~ (SW_H_MBOX1_MASK | SW_H_MBOX2_MASK | SW_H_MBOX3_MASK | SW_H_MBOX4_MASK) ;
  113. MIPS_H_MASK = temp;
  114. #ifdef DEBUG
  115. printf("Leaving plb2800_eth_initialize()\n");
  116. #endif
  117. return 1;
  118. }
  119. static int plb2800_eth_init(struct eth_device *dev, bd_t * bis)
  120. {
  121. #ifdef DEBUG
  122. printf("Entering plb2800_eth_init()\n");
  123. #endif
  124. plb2800_set_mac_addr(dev, dev->enetaddr);
  125. rx_new = 0;
  126. #ifdef DEBUG
  127. printf("Leaving plb2800_eth_init()\n");
  128. #endif
  129. return 0;
  130. }
  131. static int plb2800_eth_send(struct eth_device *dev, volatile void *packet,
  132. int length)
  133. {
  134. int i;
  135. int res = -1;
  136. u32 temp;
  137. mailbox_t * mb = MBOX_REG(0);
  138. char * mem = MBOX_MEM(0);
  139. #ifdef DEBUG
  140. printf("Entered plb2800_eth_send()\n");
  141. #endif
  142. if (length <= 0)
  143. {
  144. printf ("%s: bad packet size: %d\n", dev->name, length);
  145. goto Done;
  146. }
  147. if (length < 64)
  148. {
  149. length = 64;
  150. }
  151. temp = CMAC_CRX_CTRL_CG | ((length + 4) << CMAC_CRX_CTRL_PL_SHIFT);
  152. #ifdef DEBUG
  153. printf("0 mb->stat = 0x%x\n", mb->stat);
  154. #endif
  155. for(i = 0; mb->stat & (MBOX_STAT_CP | MBOX_STAT_MB); i++)
  156. {
  157. if (i >= TOUT_LOOP)
  158. {
  159. printf("%s: tx buffer not ready\n", dev->name);
  160. printf("1 mb->stat = 0x%x\n", mb->stat);
  161. goto Done;
  162. }
  163. }
  164. /* For some strange reason, memcpy doesn't work, here!
  165. */
  166. do
  167. {
  168. int words = (length >> 2) + 1;
  169. unsigned int* dst = (unsigned int*)(mem);
  170. unsigned int* src = (unsigned int*)(packet);
  171. for (i = 0; i < words; i++)
  172. {
  173. *dst = *src;
  174. dst++;
  175. src++;
  176. };
  177. } while(0);
  178. CMAC_CRX_CTRL = temp;
  179. mb->cmd = MBOX_STAT_CP;
  180. #ifdef DEBUG
  181. printf("2 mb->stat = 0x%x\n", mb->stat);
  182. #endif
  183. res = length;
  184. Done:
  185. #ifdef DEBUG
  186. printf("Leaving plb2800_eth_send()\n");
  187. #endif
  188. return res;
  189. }
  190. static int plb2800_eth_recv(struct eth_device *dev)
  191. {
  192. int length = 0;
  193. mailbox_t * mbox = MBOX_REG(3);
  194. unsigned char * hdr = MBOX_MEM(3);
  195. unsigned int stat;
  196. #ifdef DEBUG
  197. printf("Entered plb2800_eth_recv()\n");
  198. #endif
  199. for (;;)
  200. {
  201. stat = mbox->stat;
  202. if (!(stat & MBOX_STAT_CP))
  203. {
  204. break;
  205. }
  206. length = ((*(hdr + 6) & 0x3f) << 8) + *(hdr + 7);
  207. memcpy((void *)NetRxPackets[rx_new], hdr + 12, length);
  208. stat &= ~MBOX_STAT_CP;
  209. mbox->stat = stat;
  210. #ifdef DEBUG
  211. {
  212. int i;
  213. for (i=0;i<length - 4;i++)
  214. {
  215. if (i % 16 == 0) printf("\n%04x: ", i);
  216. printf("%02X ", NetRxPackets[rx_new][i]);
  217. }
  218. printf("\n");
  219. }
  220. #endif
  221. if (length)
  222. {
  223. #ifdef DEBUG
  224. printf("Received %d bytes\n", length);
  225. #endif
  226. NetReceive((void*)(NetRxPackets[rx_new]),
  227. length - 4);
  228. }
  229. else
  230. {
  231. #if 1
  232. printf("Zero length!!!\n");
  233. #endif
  234. }
  235. rx_new = (rx_new + 1) % NUM_RX_DESC;
  236. }
  237. #ifdef DEBUG
  238. printf("Leaving plb2800_eth_recv()\n");
  239. #endif
  240. return length;
  241. }
  242. static void plb2800_eth_halt(struct eth_device *dev)
  243. {
  244. #ifdef DEBUG
  245. printf("Entered plb2800_eth_halt()\n");
  246. #endif
  247. #ifdef DEBUG
  248. printf("Leaving plb2800_eth_halt()\n");
  249. #endif
  250. }
  251. static void plb2800_set_mac_addr(struct eth_device *dev, unsigned char * addr)
  252. {
  253. char packet[60];
  254. ulong temp;
  255. int ix;
  256. if (mac_addr_set ||
  257. NULL == addr || memcmp(addr, "\0\0\0\0\0\0", 6) == 0)
  258. {
  259. return;
  260. }
  261. /* send one packet through CPU port
  262. * in order to learn system MAC address
  263. */
  264. /* Set DA_LOOKUP register */
  265. temp = EN_MA_LEARN | (0 << DA_STATE_SHF) | (63 << DA_DEST_SHF);
  266. DA_LOOKUP = temp;
  267. /* Set MA_LEARN register */
  268. temp = 50 << MA_DEST_SHF; /* static entry */
  269. MA_LEARN = temp;
  270. /* set destination address */
  271. for (ix=0;ix<6;ix++)
  272. packet[ix] = 0xff;
  273. /* set source address = system MAC address */
  274. for (ix=0;ix<6;ix++)
  275. packet[6+ix] = addr[ix];
  276. /* set type field */
  277. packet[12]=0xaa;
  278. packet[13]=0x55;
  279. /* set data field */
  280. for(ix=14;ix<60;ix++)
  281. packet[ix] = 0x00;
  282. #ifdef DEBUG
  283. for (ix=0;ix<6;ix++)
  284. printf("mac_addr[%d]=%02X\n", ix, (unsigned char)packet[6+ix]);
  285. #endif
  286. /* set one packet */
  287. plb2800_eth_send(dev, packet, sizeof(packet));
  288. /* delay for a while */
  289. for(ix=0;ix<65535;ix++)
  290. temp = ~temp;
  291. /* Set CMAC_CTX_CTRL register */
  292. temp = TSTAMP_MS; /* no autocast */
  293. CMAC_CTX_CTRL = temp;
  294. /* Set DA_LOOKUP register */
  295. temp = EN_DA_LKUP;
  296. DA_LOOKUP = temp;
  297. mac_addr_set = 1;
  298. }
  299. static unsigned char * plb2800_get_mac_addr(void)
  300. {
  301. static unsigned char addr[6];
  302. char *tmp, *end;
  303. int i;
  304. tmp = getenv ("ethaddr");
  305. if (NULL == tmp) return NULL;
  306. for (i=0; i<6; i++) {
  307. addr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
  308. if (tmp)
  309. tmp = (*end) ? end+1 : end;
  310. }
  311. return addr;
  312. }
  313. #endif /* CONFIG_PLB2800_ETHER */