tsi568.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. * RapidIO Tsi568 switch support
  3. *
  4. * Copyright 2009-2010 Integrated Device Technology, Inc.
  5. * Alexandre Bounine <alexandre.bounine@idt.com>
  6. * - Added EM support
  7. * - Modified switch operations initialization.
  8. *
  9. * Copyright 2005 MontaVista Software, Inc.
  10. * Matt Porter <mporter@kernel.crashing.org>
  11. *
  12. * This program is free software; you can redistribute it and/or modify it
  13. * under the terms of the GNU General Public License as published by the
  14. * Free Software Foundation; either version 2 of the License, or (at your
  15. * option) any later version.
  16. */
  17. #include <linux/rio.h>
  18. #include <linux/rio_drv.h>
  19. #include <linux/rio_ids.h>
  20. #include <linux/delay.h>
  21. #include <linux/module.h>
  22. #include "../rio.h"
  23. /* Global (broadcast) route registers */
  24. #define SPBC_ROUTE_CFG_DESTID 0x10070
  25. #define SPBC_ROUTE_CFG_PORT 0x10074
  26. /* Per port route registers */
  27. #define SPP_ROUTE_CFG_DESTID(n) (0x11070 + 0x100*n)
  28. #define SPP_ROUTE_CFG_PORT(n) (0x11074 + 0x100*n)
  29. #define TSI568_SP_MODE(n) (0x11004 + 0x100*n)
  30. #define TSI568_SP_MODE_PW_DIS 0x08000000
  31. static int
  32. tsi568_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
  33. u16 table, u16 route_destid, u8 route_port)
  34. {
  35. if (table == RIO_GLOBAL_TABLE) {
  36. rio_mport_write_config_32(mport, destid, hopcount,
  37. SPBC_ROUTE_CFG_DESTID, route_destid);
  38. rio_mport_write_config_32(mport, destid, hopcount,
  39. SPBC_ROUTE_CFG_PORT, route_port);
  40. } else {
  41. rio_mport_write_config_32(mport, destid, hopcount,
  42. SPP_ROUTE_CFG_DESTID(table),
  43. route_destid);
  44. rio_mport_write_config_32(mport, destid, hopcount,
  45. SPP_ROUTE_CFG_PORT(table), route_port);
  46. }
  47. udelay(10);
  48. return 0;
  49. }
  50. static int
  51. tsi568_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
  52. u16 table, u16 route_destid, u8 *route_port)
  53. {
  54. int ret = 0;
  55. u32 result;
  56. if (table == RIO_GLOBAL_TABLE) {
  57. rio_mport_write_config_32(mport, destid, hopcount,
  58. SPBC_ROUTE_CFG_DESTID, route_destid);
  59. rio_mport_read_config_32(mport, destid, hopcount,
  60. SPBC_ROUTE_CFG_PORT, &result);
  61. } else {
  62. rio_mport_write_config_32(mport, destid, hopcount,
  63. SPP_ROUTE_CFG_DESTID(table),
  64. route_destid);
  65. rio_mport_read_config_32(mport, destid, hopcount,
  66. SPP_ROUTE_CFG_PORT(table), &result);
  67. }
  68. *route_port = result;
  69. if (*route_port > 15)
  70. ret = -1;
  71. return ret;
  72. }
  73. static int
  74. tsi568_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
  75. u16 table)
  76. {
  77. u32 route_idx;
  78. u32 lut_size;
  79. lut_size = (mport->sys_size) ? 0x1ff : 0xff;
  80. if (table == RIO_GLOBAL_TABLE) {
  81. rio_mport_write_config_32(mport, destid, hopcount,
  82. SPBC_ROUTE_CFG_DESTID, 0x80000000);
  83. for (route_idx = 0; route_idx <= lut_size; route_idx++)
  84. rio_mport_write_config_32(mport, destid, hopcount,
  85. SPBC_ROUTE_CFG_PORT,
  86. RIO_INVALID_ROUTE);
  87. } else {
  88. rio_mport_write_config_32(mport, destid, hopcount,
  89. SPP_ROUTE_CFG_DESTID(table),
  90. 0x80000000);
  91. for (route_idx = 0; route_idx <= lut_size; route_idx++)
  92. rio_mport_write_config_32(mport, destid, hopcount,
  93. SPP_ROUTE_CFG_PORT(table),
  94. RIO_INVALID_ROUTE);
  95. }
  96. return 0;
  97. }
  98. static int
  99. tsi568_em_init(struct rio_dev *rdev)
  100. {
  101. u32 regval;
  102. int portnum;
  103. pr_debug("TSI568 %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount);
  104. /* Make sure that Port-Writes are disabled (for all ports) */
  105. for (portnum = 0;
  106. portnum < RIO_GET_TOTAL_PORTS(rdev->swpinfo); portnum++) {
  107. rio_read_config_32(rdev, TSI568_SP_MODE(portnum), &regval);
  108. rio_write_config_32(rdev, TSI568_SP_MODE(portnum),
  109. regval | TSI568_SP_MODE_PW_DIS);
  110. }
  111. return 0;
  112. }
  113. static struct rio_switch_ops tsi568_switch_ops = {
  114. .owner = THIS_MODULE,
  115. .add_entry = tsi568_route_add_entry,
  116. .get_entry = tsi568_route_get_entry,
  117. .clr_table = tsi568_route_clr_table,
  118. .set_domain = NULL,
  119. .get_domain = NULL,
  120. .em_init = tsi568_em_init,
  121. .em_handle = NULL,
  122. };
  123. static int tsi568_probe(struct rio_dev *rdev, const struct rio_device_id *id)
  124. {
  125. pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
  126. spin_lock(&rdev->rswitch->lock);
  127. if (rdev->rswitch->ops) {
  128. spin_unlock(&rdev->rswitch->lock);
  129. return -EINVAL;
  130. }
  131. rdev->rswitch->ops = &tsi568_switch_ops;
  132. spin_unlock(&rdev->rswitch->lock);
  133. return 0;
  134. }
  135. static void tsi568_remove(struct rio_dev *rdev)
  136. {
  137. pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
  138. spin_lock(&rdev->rswitch->lock);
  139. if (rdev->rswitch->ops != &tsi568_switch_ops) {
  140. spin_unlock(&rdev->rswitch->lock);
  141. return;
  142. }
  143. rdev->rswitch->ops = NULL;
  144. spin_unlock(&rdev->rswitch->lock);
  145. }
  146. static struct rio_device_id tsi568_id_table[] = {
  147. {RIO_DEVICE(RIO_DID_TSI568, RIO_VID_TUNDRA)},
  148. { 0, } /* terminate list */
  149. };
  150. static struct rio_driver tsi568_driver = {
  151. .name = "tsi568",
  152. .id_table = tsi568_id_table,
  153. .probe = tsi568_probe,
  154. .remove = tsi568_remove,
  155. };
  156. static int __init tsi568_init(void)
  157. {
  158. return rio_register_driver(&tsi568_driver);
  159. }
  160. static void __exit tsi568_exit(void)
  161. {
  162. rio_unregister_driver(&tsi568_driver);
  163. }
  164. device_initcall(tsi568_init);
  165. module_exit(tsi568_exit);
  166. MODULE_DESCRIPTION("IDT Tsi568 Serial RapidIO switch driver");
  167. MODULE_AUTHOR("Integrated Device Technology, Inc.");
  168. MODULE_LICENSE("GPL");