mv_64xx.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. mv_64xx.c - Marvell 88SE6440 SAS/SATA support
  3. Copyright 2007 Red Hat, Inc.
  4. Copyright 2008 Marvell. <kewei@marvell.com>
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2,
  8. or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty
  11. of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. See the GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public
  14. License along with this program; see the file COPYING. If not,
  15. write to the Free Software Foundation, 675 Mass Ave, Cambridge,
  16. MA 02139, USA.
  17. */
  18. #include "mv_sas.h"
  19. #include "mv_64xx.h"
  20. #include "mv_chips.h"
  21. void mvs_detect_porttype(struct mvs_info *mvi, int i)
  22. {
  23. void __iomem *regs = mvi->regs;
  24. u32 reg;
  25. struct mvs_phy *phy = &mvi->phy[i];
  26. /* TODO check & save device type */
  27. reg = mr32(GBL_PORT_TYPE);
  28. if (reg & MODE_SAS_SATA & (1 << i))
  29. phy->phy_type |= PORT_TYPE_SAS;
  30. else
  31. phy->phy_type |= PORT_TYPE_SATA;
  32. }
  33. void mvs_enable_xmt(struct mvs_info *mvi, int PhyId)
  34. {
  35. void __iomem *regs = mvi->regs;
  36. u32 tmp;
  37. tmp = mr32(PCS);
  38. if (mvi->chip->n_phy <= 4)
  39. tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT);
  40. else
  41. tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT2);
  42. mw32(PCS, tmp);
  43. }
  44. void __devinit mvs_phy_hacks(struct mvs_info *mvi)
  45. {
  46. void __iomem *regs = mvi->regs;
  47. u32 tmp;
  48. /* workaround for SATA R-ERR, to ignore phy glitch */
  49. tmp = mvs_cr32(regs, CMD_PHY_TIMER);
  50. tmp &= ~(1 << 9);
  51. tmp |= (1 << 10);
  52. mvs_cw32(regs, CMD_PHY_TIMER, tmp);
  53. /* enable retry 127 times */
  54. mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f);
  55. /* extend open frame timeout to max */
  56. tmp = mvs_cr32(regs, CMD_SAS_CTL0);
  57. tmp &= ~0xffff;
  58. tmp |= 0x3fff;
  59. mvs_cw32(regs, CMD_SAS_CTL0, tmp);
  60. /* workaround for WDTIMEOUT , set to 550 ms */
  61. mvs_cw32(regs, CMD_WD_TIMER, 0x86470);
  62. /* not to halt for different port op during wideport link change */
  63. mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d);
  64. /* workaround for Seagate disk not-found OOB sequence, recv
  65. * COMINIT before sending out COMWAKE */
  66. tmp = mvs_cr32(regs, CMD_PHY_MODE_21);
  67. tmp &= 0x0000ffff;
  68. tmp |= 0x00fa0000;
  69. mvs_cw32(regs, CMD_PHY_MODE_21, tmp);
  70. tmp = mvs_cr32(regs, CMD_PHY_TIMER);
  71. tmp &= 0x1fffffff;
  72. tmp |= (2U << 29); /* 8 ms retry */
  73. mvs_cw32(regs, CMD_PHY_TIMER, tmp);
  74. /* TEST - for phy decoding error, adjust voltage levels */
  75. mw32(P0_VSR_ADDR + 0, 0x8);
  76. mw32(P0_VSR_DATA + 0, 0x2F0);
  77. mw32(P0_VSR_ADDR + 8, 0x8);
  78. mw32(P0_VSR_DATA + 8, 0x2F0);
  79. mw32(P0_VSR_ADDR + 16, 0x8);
  80. mw32(P0_VSR_DATA + 16, 0x2F0);
  81. mw32(P0_VSR_ADDR + 24, 0x8);
  82. mw32(P0_VSR_DATA + 24, 0x2F0);
  83. }
  84. void mvs_hba_interrupt_enable(struct mvs_info *mvi)
  85. {
  86. void __iomem *regs = mvi->regs;
  87. u32 tmp;
  88. tmp = mr32(GBL_CTL);
  89. mw32(GBL_CTL, tmp | INT_EN);
  90. }
  91. void mvs_hba_interrupt_disable(struct mvs_info *mvi)
  92. {
  93. void __iomem *regs = mvi->regs;
  94. u32 tmp;
  95. tmp = mr32(GBL_CTL);
  96. mw32(GBL_CTL, tmp & ~INT_EN);
  97. }
  98. void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
  99. {
  100. void __iomem *regs = mvi->regs;
  101. u32 tmp, offs;
  102. u8 *tfs = &port->taskfileset;
  103. if (*tfs == MVS_ID_NOT_MAPPED)
  104. return;
  105. offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT);
  106. if (*tfs < 16) {
  107. tmp = mr32(PCS);
  108. mw32(PCS, tmp & ~offs);
  109. } else {
  110. tmp = mr32(CTL);
  111. mw32(CTL, tmp & ~offs);
  112. }
  113. tmp = mr32(INT_STAT_SRS) & (1U << *tfs);
  114. if (tmp)
  115. mw32(INT_STAT_SRS, tmp);
  116. *tfs = MVS_ID_NOT_MAPPED;
  117. }
  118. u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
  119. {
  120. int i;
  121. u32 tmp, offs;
  122. void __iomem *regs = mvi->regs;
  123. if (port->taskfileset != MVS_ID_NOT_MAPPED)
  124. return 0;
  125. tmp = mr32(PCS);
  126. for (i = 0; i < mvi->chip->srs_sz; i++) {
  127. if (i == 16)
  128. tmp = mr32(CTL);
  129. offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT);
  130. if (!(tmp & offs)) {
  131. port->taskfileset = i;
  132. if (i < 16)
  133. mw32(PCS, tmp | offs);
  134. else
  135. mw32(CTL, tmp | offs);
  136. tmp = mr32(INT_STAT_SRS) & (1U << i);
  137. if (tmp)
  138. mw32(INT_STAT_SRS, tmp);
  139. return 0;
  140. }
  141. }
  142. return MVS_ID_NOT_MAPPED;
  143. }