global2.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /*
  2. * Marvell 88E6xxx Switch Global 2 Registers support (device address 0x1C)
  3. *
  4. * Copyright (c) 2008 Marvell Semiconductor
  5. *
  6. * Copyright (c) 2016 Vivien Didelot <vivien.didelot@savoirfairelinux.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. */
  13. #include "mv88e6xxx.h"
  14. #include "global2.h"
  15. /* Offset 0x06: Device Mapping Table register */
  16. static int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip,
  17. int target, int port)
  18. {
  19. u16 val = (target << 8) | (port & 0xf);
  20. return mv88e6xxx_update(chip, REG_GLOBAL2, GLOBAL2_DEVICE_MAPPING, val);
  21. }
  22. static int mv88e6xxx_g2_set_device_mapping(struct mv88e6xxx_chip *chip)
  23. {
  24. int target, port;
  25. int err;
  26. /* Initialize the routing port to the 32 possible target devices */
  27. for (target = 0; target < 32; ++target) {
  28. port = 0xf;
  29. if (target < DSA_MAX_SWITCHES) {
  30. port = chip->ds->rtable[target];
  31. if (port == DSA_RTABLE_NONE)
  32. port = 0xf;
  33. }
  34. err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
  35. if (err)
  36. break;
  37. }
  38. return err;
  39. }
  40. /* Offset 0x07: Trunk Mask Table register */
  41. static int mv88e6xxx_g2_trunk_mask_write(struct mv88e6xxx_chip *chip, int num,
  42. bool hask, u16 mask)
  43. {
  44. const u16 port_mask = BIT(chip->info->num_ports) - 1;
  45. u16 val = (num << 12) | (mask & port_mask);
  46. if (hask)
  47. val |= GLOBAL2_TRUNK_MASK_HASK;
  48. return mv88e6xxx_update(chip, REG_GLOBAL2, GLOBAL2_TRUNK_MASK, val);
  49. }
  50. /* Offset 0x08: Trunk Mapping Table register */
  51. static int mv88e6xxx_g2_trunk_mapping_write(struct mv88e6xxx_chip *chip, int id,
  52. u16 map)
  53. {
  54. const u16 port_mask = BIT(chip->info->num_ports) - 1;
  55. u16 val = (id << 11) | (map & port_mask);
  56. return mv88e6xxx_update(chip, REG_GLOBAL2, GLOBAL2_TRUNK_MAPPING, val);
  57. }
  58. static int mv88e6xxx_g2_clear_trunk(struct mv88e6xxx_chip *chip)
  59. {
  60. const u16 port_mask = BIT(chip->info->num_ports) - 1;
  61. int i, err;
  62. /* Clear all eight possible Trunk Mask vectors */
  63. for (i = 0; i < 8; ++i) {
  64. err = mv88e6xxx_g2_trunk_mask_write(chip, i, false, port_mask);
  65. if (err)
  66. return err;
  67. }
  68. /* Clear all sixteen possible Trunk ID routing vectors */
  69. for (i = 0; i < 16; ++i) {
  70. err = mv88e6xxx_g2_trunk_mapping_write(chip, i, 0);
  71. if (err)
  72. return err;
  73. }
  74. return 0;
  75. }
  76. /* Offset 0x09: Ingress Rate Command register
  77. * Offset 0x0A: Ingress Rate Data register
  78. */
  79. static int mv88e6xxx_g2_clear_irl(struct mv88e6xxx_chip *chip)
  80. {
  81. int port, err;
  82. /* Init all Ingress Rate Limit resources of all ports */
  83. for (port = 0; port < chip->info->num_ports; ++port) {
  84. /* XXX newer chips (like 88E6390) have different 2-bit ops */
  85. err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_IRL_CMD,
  86. GLOBAL2_IRL_CMD_OP_INIT_ALL |
  87. (port << 8));
  88. if (err)
  89. break;
  90. /* Wait for the operation to complete */
  91. err = mv88e6xxx_wait(chip, REG_GLOBAL2, GLOBAL2_IRL_CMD,
  92. GLOBAL2_IRL_CMD_BUSY);
  93. if (err)
  94. break;
  95. }
  96. return err;
  97. }
  98. /* Offset 0x0D: Switch MAC/WoL/WoF register */
  99. static int mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip *chip,
  100. unsigned int pointer, u8 data)
  101. {
  102. u16 val = (pointer << 8) | data;
  103. return mv88e6xxx_update(chip, REG_GLOBAL2, GLOBAL2_SWITCH_MAC, val);
  104. }
  105. int mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr)
  106. {
  107. int i, err;
  108. for (i = 0; i < 6; i++) {
  109. err = mv88e6xxx_g2_switch_mac_write(chip, i, addr[i]);
  110. if (err)
  111. break;
  112. }
  113. return err;
  114. }
  115. /* Offset 0x0F: Priority Override Table */
  116. static int mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip *chip, int pointer,
  117. u8 data)
  118. {
  119. u16 val = (pointer << 8) | (data & 0x7);
  120. return mv88e6xxx_update(chip, REG_GLOBAL2, GLOBAL2_PRIO_OVERRIDE, val);
  121. }
  122. static int mv88e6xxx_g2_clear_pot(struct mv88e6xxx_chip *chip)
  123. {
  124. int i, err;
  125. /* Clear all sixteen possible Priority Override entries */
  126. for (i = 0; i < 16; i++) {
  127. err = mv88e6xxx_g2_pot_write(chip, i, 0);
  128. if (err)
  129. break;
  130. }
  131. return err;
  132. }
  133. /* Offset 0x14: EEPROM Command
  134. * Offset 0x15: EEPROM Data
  135. */
  136. static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
  137. {
  138. return mv88e6xxx_wait(chip, REG_GLOBAL2, GLOBAL2_EEPROM_CMD,
  139. GLOBAL2_EEPROM_CMD_BUSY |
  140. GLOBAL2_EEPROM_CMD_RUNNING);
  141. }
  142. static int mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
  143. {
  144. int err;
  145. err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_EEPROM_CMD, cmd);
  146. if (err)
  147. return err;
  148. return mv88e6xxx_g2_eeprom_wait(chip);
  149. }
  150. static int mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip *chip,
  151. u8 addr, u16 *data)
  152. {
  153. u16 cmd = GLOBAL2_EEPROM_CMD_OP_READ | addr;
  154. int err;
  155. err = mv88e6xxx_g2_eeprom_wait(chip);
  156. if (err)
  157. return err;
  158. err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
  159. if (err)
  160. return err;
  161. return mv88e6xxx_read(chip, REG_GLOBAL2, GLOBAL2_EEPROM_DATA, data);
  162. }
  163. static int mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip *chip,
  164. u8 addr, u16 data)
  165. {
  166. u16 cmd = GLOBAL2_EEPROM_CMD_OP_WRITE | addr;
  167. int err;
  168. err = mv88e6xxx_g2_eeprom_wait(chip);
  169. if (err)
  170. return err;
  171. err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_EEPROM_DATA, data);
  172. if (err)
  173. return err;
  174. return mv88e6xxx_g2_eeprom_cmd(chip, cmd);
  175. }
  176. int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
  177. struct ethtool_eeprom *eeprom, u8 *data)
  178. {
  179. unsigned int offset = eeprom->offset;
  180. unsigned int len = eeprom->len;
  181. u16 val;
  182. int err;
  183. eeprom->len = 0;
  184. if (offset & 1) {
  185. err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
  186. if (err)
  187. return err;
  188. *data++ = (val >> 8) & 0xff;
  189. offset++;
  190. len--;
  191. eeprom->len++;
  192. }
  193. while (len >= 2) {
  194. err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
  195. if (err)
  196. return err;
  197. *data++ = val & 0xff;
  198. *data++ = (val >> 8) & 0xff;
  199. offset += 2;
  200. len -= 2;
  201. eeprom->len += 2;
  202. }
  203. if (len) {
  204. err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
  205. if (err)
  206. return err;
  207. *data++ = val & 0xff;
  208. offset++;
  209. len--;
  210. eeprom->len++;
  211. }
  212. return 0;
  213. }
  214. int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
  215. struct ethtool_eeprom *eeprom, u8 *data)
  216. {
  217. unsigned int offset = eeprom->offset;
  218. unsigned int len = eeprom->len;
  219. u16 val;
  220. int err;
  221. /* Ensure the RO WriteEn bit is set */
  222. err = mv88e6xxx_read(chip, REG_GLOBAL2, GLOBAL2_EEPROM_CMD, &val);
  223. if (err)
  224. return err;
  225. if (!(val & GLOBAL2_EEPROM_CMD_WRITE_EN))
  226. return -EROFS;
  227. eeprom->len = 0;
  228. if (offset & 1) {
  229. err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
  230. if (err)
  231. return err;
  232. val = (*data++ << 8) | (val & 0xff);
  233. err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
  234. if (err)
  235. return err;
  236. offset++;
  237. len--;
  238. eeprom->len++;
  239. }
  240. while (len >= 2) {
  241. val = *data++;
  242. val |= *data++ << 8;
  243. err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
  244. if (err)
  245. return err;
  246. offset += 2;
  247. len -= 2;
  248. eeprom->len += 2;
  249. }
  250. if (len) {
  251. err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
  252. if (err)
  253. return err;
  254. val = (val & 0xff00) | *data++;
  255. err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
  256. if (err)
  257. return err;
  258. offset++;
  259. len--;
  260. eeprom->len++;
  261. }
  262. return 0;
  263. }
  264. /* Offset 0x18: SMI PHY Command Register
  265. * Offset 0x19: SMI PHY Data Register
  266. */
  267. static int mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip *chip)
  268. {
  269. return mv88e6xxx_wait(chip, REG_GLOBAL2, GLOBAL2_SMI_PHY_CMD,
  270. GLOBAL2_SMI_PHY_CMD_BUSY);
  271. }
  272. static int mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
  273. {
  274. int err;
  275. err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_SMI_PHY_CMD, cmd);
  276. if (err)
  277. return err;
  278. return mv88e6xxx_g2_smi_phy_wait(chip);
  279. }
  280. int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, int addr, int reg,
  281. u16 *val)
  282. {
  283. u16 cmd = GLOBAL2_SMI_PHY_CMD_OP_22_READ_DATA | (addr << 5) | reg;
  284. int err;
  285. err = mv88e6xxx_g2_smi_phy_wait(chip);
  286. if (err)
  287. return err;
  288. err = mv88e6xxx_g2_smi_phy_cmd(chip, cmd);
  289. if (err)
  290. return err;
  291. return mv88e6xxx_read(chip, REG_GLOBAL2, GLOBAL2_SMI_PHY_DATA, val);
  292. }
  293. int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, int addr, int reg,
  294. u16 val)
  295. {
  296. u16 cmd = GLOBAL2_SMI_PHY_CMD_OP_22_WRITE_DATA | (addr << 5) | reg;
  297. int err;
  298. err = mv88e6xxx_g2_smi_phy_wait(chip);
  299. if (err)
  300. return err;
  301. err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_SMI_PHY_DATA, val);
  302. if (err)
  303. return err;
  304. return mv88e6xxx_g2_smi_phy_cmd(chip, cmd);
  305. }
  306. int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip)
  307. {
  308. u16 reg;
  309. int err;
  310. if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X)) {
  311. /* Consider the frames with reserved multicast destination
  312. * addresses matching 01:80:c2:00:00:2x as MGMT.
  313. */
  314. err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_MGMT_EN_2X,
  315. 0xffff);
  316. if (err)
  317. return err;
  318. }
  319. if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X)) {
  320. /* Consider the frames with reserved multicast destination
  321. * addresses matching 01:80:c2:00:00:0x as MGMT.
  322. */
  323. err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_MGMT_EN_0X,
  324. 0xffff);
  325. if (err)
  326. return err;
  327. }
  328. /* Ignore removed tag data on doubly tagged packets, disable
  329. * flow control messages, force flow control priority to the
  330. * highest, and send all special multicast frames to the CPU
  331. * port at the highest priority.
  332. */
  333. reg = GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI | (0x7 << 4);
  334. if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X) ||
  335. mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X))
  336. reg |= GLOBAL2_SWITCH_MGMT_RSVD2CPU | 0x7;
  337. err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_SWITCH_MGMT, reg);
  338. if (err)
  339. return err;
  340. /* Program the DSA routing table. */
  341. err = mv88e6xxx_g2_set_device_mapping(chip);
  342. if (err)
  343. return err;
  344. /* Clear all trunk masks and mapping. */
  345. err = mv88e6xxx_g2_clear_trunk(chip);
  346. if (err)
  347. return err;
  348. if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_IRL)) {
  349. /* Disable ingress rate limiting by resetting all per port
  350. * ingress rate limit resources to their initial state.
  351. */
  352. err = mv88e6xxx_g2_clear_irl(chip);
  353. if (err)
  354. return err;
  355. }
  356. if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_PVT)) {
  357. /* Initialize Cross-chip Port VLAN Table to reset defaults */
  358. err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_PVT_ADDR,
  359. GLOBAL2_PVT_ADDR_OP_INIT_ONES);
  360. if (err)
  361. return err;
  362. }
  363. if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_POT)) {
  364. /* Clear the priority override table. */
  365. err = mv88e6xxx_g2_clear_pot(chip);
  366. if (err)
  367. return err;
  368. }
  369. return 0;
  370. }