ixp2400-msf.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. * Generic library functions for the MSF (Media and Switch Fabric) unit
  3. * found on the Intel IXP2400 network processor.
  4. *
  5. * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
  6. * Dedicated to Marija Kulikova.
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU Lesser General Public License as
  10. * published by the Free Software Foundation; either version 2.1 of the
  11. * License, or (at your option) any later version.
  12. */
  13. #include <linux/kernel.h>
  14. #include <linux/init.h>
  15. #include <mach/hardware.h>
  16. #include <mach/ixp2000-regs.h>
  17. #include <asm/delay.h>
  18. #include <asm/io.h>
  19. #include "ixp2400-msf.h"
  20. /*
  21. * This is the Intel recommended PLL init procedure as described on
  22. * page 340 of the IXP2400/IXP2800 Programmer's Reference Manual.
  23. */
  24. static void ixp2400_pll_init(struct ixp2400_msf_parameters *mp)
  25. {
  26. int rx_dual_clock;
  27. int tx_dual_clock;
  28. u32 value;
  29. /*
  30. * If the RX mode is not 1x32, we have to enable both RX PLLs
  31. * (#0 and #1.) The same thing for the TX direction.
  32. */
  33. rx_dual_clock = !!(mp->rx_mode & IXP2400_RX_MODE_WIDTH_MASK);
  34. tx_dual_clock = !!(mp->tx_mode & IXP2400_TX_MODE_WIDTH_MASK);
  35. /*
  36. * Read initial value.
  37. */
  38. value = ixp2000_reg_read(IXP2000_MSF_CLK_CNTRL);
  39. /*
  40. * Put PLLs in powerdown and bypass mode.
  41. */
  42. value |= 0x0000f0f0;
  43. ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
  44. /*
  45. * Set single or dual clock mode bits.
  46. */
  47. value &= ~0x03000000;
  48. value |= (rx_dual_clock << 24) | (tx_dual_clock << 25);
  49. /*
  50. * Set multipliers.
  51. */
  52. value &= ~0x00ff0000;
  53. value |= mp->rxclk01_multiplier << 16;
  54. value |= mp->rxclk23_multiplier << 18;
  55. value |= mp->txclk01_multiplier << 20;
  56. value |= mp->txclk23_multiplier << 22;
  57. /*
  58. * And write value.
  59. */
  60. ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
  61. /*
  62. * Disable PLL bypass mode.
  63. */
  64. value &= ~(0x00005000 | rx_dual_clock << 13 | tx_dual_clock << 15);
  65. ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
  66. /*
  67. * Turn on PLLs.
  68. */
  69. value &= ~(0x00000050 | rx_dual_clock << 5 | tx_dual_clock << 7);
  70. ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
  71. /*
  72. * Wait for PLLs to lock. There are lock status bits, but IXP2400
  73. * erratum #65 says that these lock bits should not be relied upon
  74. * as they might not accurately reflect the true state of the PLLs.
  75. */
  76. udelay(100);
  77. }
  78. /*
  79. * Needed according to p480 of Programmer's Reference Manual.
  80. */
  81. static void ixp2400_msf_free_rbuf_entries(struct ixp2400_msf_parameters *mp)
  82. {
  83. int size_bits;
  84. int i;
  85. /*
  86. * Work around IXP2400 erratum #69 (silent RBUF-to-DRAM transfer
  87. * corruption) in the Intel-recommended way: do not add the RBUF
  88. * elements susceptible to corruption to the freelist.
  89. */
  90. size_bits = mp->rx_mode & IXP2400_RX_MODE_RBUF_SIZE_MASK;
  91. if (size_bits == IXP2400_RX_MODE_RBUF_SIZE_64) {
  92. for (i = 1; i < 128; i++) {
  93. if (i == 9 || i == 18 || i == 27)
  94. continue;
  95. ixp2000_reg_write(IXP2000_MSF_RBUF_ELEMENT_DONE, i);
  96. }
  97. } else if (size_bits == IXP2400_RX_MODE_RBUF_SIZE_128) {
  98. for (i = 1; i < 64; i++) {
  99. if (i == 4 || i == 9 || i == 13)
  100. continue;
  101. ixp2000_reg_write(IXP2000_MSF_RBUF_ELEMENT_DONE, i);
  102. }
  103. } else if (size_bits == IXP2400_RX_MODE_RBUF_SIZE_256) {
  104. for (i = 1; i < 32; i++) {
  105. if (i == 2 || i == 4 || i == 6)
  106. continue;
  107. ixp2000_reg_write(IXP2000_MSF_RBUF_ELEMENT_DONE, i);
  108. }
  109. }
  110. }
  111. static u32 ixp2400_msf_valid_channels(u32 reg)
  112. {
  113. u32 channels;
  114. channels = 0;
  115. switch (reg & IXP2400_RX_MODE_WIDTH_MASK) {
  116. case IXP2400_RX_MODE_1x32:
  117. channels = 0x1;
  118. if (reg & IXP2400_RX_MODE_MPHY &&
  119. !(reg & IXP2400_RX_MODE_MPHY_32))
  120. channels = 0xf;
  121. break;
  122. case IXP2400_RX_MODE_2x16:
  123. channels = 0x5;
  124. break;
  125. case IXP2400_RX_MODE_4x8:
  126. channels = 0xf;
  127. break;
  128. case IXP2400_RX_MODE_1x16_2x8:
  129. channels = 0xd;
  130. break;
  131. }
  132. return channels;
  133. }
  134. static void ixp2400_msf_enable_rx(struct ixp2400_msf_parameters *mp)
  135. {
  136. u32 value;
  137. value = ixp2000_reg_read(IXP2000_MSF_RX_CONTROL) & 0x0fffffff;
  138. value |= ixp2400_msf_valid_channels(mp->rx_mode) << 28;
  139. ixp2000_reg_write(IXP2000_MSF_RX_CONTROL, value);
  140. }
  141. static void ixp2400_msf_enable_tx(struct ixp2400_msf_parameters *mp)
  142. {
  143. u32 value;
  144. value = ixp2000_reg_read(IXP2000_MSF_TX_CONTROL) & 0x0fffffff;
  145. value |= ixp2400_msf_valid_channels(mp->tx_mode) << 28;
  146. ixp2000_reg_write(IXP2000_MSF_TX_CONTROL, value);
  147. }
  148. void ixp2400_msf_init(struct ixp2400_msf_parameters *mp)
  149. {
  150. u32 value;
  151. int i;
  152. /*
  153. * Init the RX/TX PLLs based on the passed parameter block.
  154. */
  155. ixp2400_pll_init(mp);
  156. /*
  157. * Reset MSF. Bit 7 in IXP_RESET_0 resets the MSF.
  158. */
  159. value = ixp2000_reg_read(IXP2000_RESET0);
  160. ixp2000_reg_write(IXP2000_RESET0, value | 0x80);
  161. ixp2000_reg_write(IXP2000_RESET0, value & ~0x80);
  162. /*
  163. * Initialise the RX section.
  164. */
  165. ixp2000_reg_write(IXP2000_MSF_RX_MPHY_POLL_LIMIT, mp->rx_poll_ports - 1);
  166. ixp2000_reg_write(IXP2000_MSF_RX_CONTROL, mp->rx_mode);
  167. for (i = 0; i < 4; i++) {
  168. ixp2000_reg_write(IXP2000_MSF_RX_UP_CONTROL_0 + i,
  169. mp->rx_channel_mode[i]);
  170. }
  171. ixp2400_msf_free_rbuf_entries(mp);
  172. ixp2400_msf_enable_rx(mp);
  173. /*
  174. * Initialise the TX section.
  175. */
  176. ixp2000_reg_write(IXP2000_MSF_TX_MPHY_POLL_LIMIT, mp->tx_poll_ports - 1);
  177. ixp2000_reg_write(IXP2000_MSF_TX_CONTROL, mp->tx_mode);
  178. for (i = 0; i < 4; i++) {
  179. ixp2000_reg_write(IXP2000_MSF_TX_UP_CONTROL_0 + i,
  180. mp->tx_channel_mode[i]);
  181. }
  182. ixp2400_msf_enable_tx(mp);
  183. }