0013-net-switchlib-add-driver-for-REALTEK-RTL8306.patch 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. From 42cb399df978a33539b95d668b3f973d927cb902 Mon Sep 17 00:00:00 2001
  2. From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
  3. Date: Mon, 17 Dec 2012 23:37:57 +0100
  4. Subject: net: switchlib: add driver for REALTEK RTL8306
  5. Signed-off-by: Oliver Muth <dr.o.muth@gmx.de>
  6. Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
  7. --- a/drivers/net/switch/Makefile
  8. +++ b/drivers/net/switch/Makefile
  9. @@ -13,6 +13,7 @@ COBJS-$(CONFIG_SWITCH_MULTI) += switch.o
  10. COBJS-$(CONFIG_SWITCH_PSB697X) += psb697x.o
  11. COBJS-$(CONFIG_SWITCH_ADM6996I) += adm6996i.o
  12. COBJS-$(CONFIG_SWITCH_AR8216) += ar8216.o
  13. +COBJS-$(CONFIG_SWITCH_RTL8306) += rtl8306.o
  14. COBJS := $(COBJS-y)
  15. SRCS := $(COBJS:.o=.c)
  16. --- /dev/null
  17. +++ b/drivers/net/switch/rtl8306.c
  18. @@ -0,0 +1,332 @@
  19. +/*
  20. + * Based on OpenWrt linux driver
  21. + *
  22. + * Copyright (C) 2011-2012 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
  23. + * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
  24. + *
  25. + * SPDX-License-Identifier: GPL-2.0+
  26. + */
  27. +#define DEBUG
  28. +#include <common.h>
  29. +#include <malloc.h>
  30. +#include <switch.h>
  31. +#include <miiphy.h>
  32. +
  33. +#define RTL8306_REG_PAGE 16
  34. +#define RTL8306_REG_PAGE_LO (1 << 15)
  35. +#define RTL8306_REG_PAGE_HI (1 << 1) /* inverted */
  36. +#define RTL8306_CHIPID 0x5988
  37. +
  38. +#define RTL8306_NUM_VLANS 16
  39. +#define RTL8306_NUM_PORTS 6
  40. +#define RTL8306_PORT_CPU 5
  41. +#define RTL8306_NUM_PAGES 4
  42. +#define RTL8306_NUM_REGS 32
  43. +
  44. +enum {
  45. + RTL_TYPE_S,
  46. + RTL_TYPE_SD,
  47. + RTL_TYPE_SDM,
  48. +};
  49. +
  50. +struct rtl_reg {
  51. + int page;
  52. + int phy;
  53. + int reg;
  54. + int bits;
  55. + int shift;
  56. + int inverted;
  57. +};
  58. +
  59. +enum rtl_regidx {
  60. + RTL_REG_CHIPID,
  61. + RTL_REG_CHIPVER,
  62. + RTL_REG_CHIPTYPE,
  63. + RTL_REG_CPUPORT,
  64. +
  65. + RTL_REG_EN_CPUPORT,
  66. + RTL_REG_EN_TAG_OUT,
  67. + RTL_REG_EN_TAG_CLR,
  68. + RTL_REG_EN_TAG_IN,
  69. + RTL_REG_TRAP_CPU,
  70. + RTL_REG_TRUNK_PORTSEL,
  71. + RTL_REG_EN_TRUNK,
  72. + RTL_REG_RESET,
  73. + RTL_REG_PHY_RESET,
  74. + RTL_REG_CPU_LINKUP,
  75. +
  76. + RTL_REG_VLAN_ENABLE,
  77. + RTL_REG_VLAN_FILTER,
  78. + RTL_REG_VLAN_TAG_ONLY,
  79. + RTL_REG_VLAN_TAG_AWARE,
  80. +#define RTL_VLAN_ENUM(id) \
  81. + RTL_REG_VLAN##id##_VID, \
  82. + RTL_REG_VLAN##id##_PORTMASK
  83. + RTL_VLAN_ENUM(0),
  84. + RTL_VLAN_ENUM(1),
  85. + RTL_VLAN_ENUM(2),
  86. + RTL_VLAN_ENUM(3),
  87. + RTL_VLAN_ENUM(4),
  88. + RTL_VLAN_ENUM(5),
  89. + RTL_VLAN_ENUM(6),
  90. + RTL_VLAN_ENUM(7),
  91. + RTL_VLAN_ENUM(8),
  92. + RTL_VLAN_ENUM(9),
  93. + RTL_VLAN_ENUM(10),
  94. + RTL_VLAN_ENUM(11),
  95. + RTL_VLAN_ENUM(12),
  96. + RTL_VLAN_ENUM(13),
  97. + RTL_VLAN_ENUM(14),
  98. + RTL_VLAN_ENUM(15),
  99. +#define RTL_PORT_ENUM(id) \
  100. + RTL_REG_PORT##id##_PVID, \
  101. + RTL_REG_PORT##id##_NULL_VID_REPLACE, \
  102. + RTL_REG_PORT##id##_NON_PVID_DISCARD, \
  103. + RTL_REG_PORT##id##_VID_INSERT, \
  104. + RTL_REG_PORT##id##_TAG_INSERT, \
  105. + RTL_REG_PORT##id##_LINK, \
  106. + RTL_REG_PORT##id##_SPEED, \
  107. + RTL_REG_PORT##id##_NWAY, \
  108. + RTL_REG_PORT##id##_NRESTART, \
  109. + RTL_REG_PORT##id##_DUPLEX, \
  110. + RTL_REG_PORT##id##_RXEN, \
  111. + RTL_REG_PORT##id##_TXEN, \
  112. + RTL_REG_PORT##id##_LRNEN
  113. + RTL_PORT_ENUM(0),
  114. + RTL_PORT_ENUM(1),
  115. + RTL_PORT_ENUM(2),
  116. + RTL_PORT_ENUM(3),
  117. + RTL_PORT_ENUM(4),
  118. + RTL_PORT_ENUM(5),
  119. +};
  120. +
  121. +static const struct rtl_reg rtl_regs[] = {
  122. + [RTL_REG_CHIPID] = { 0, 4, 30, 16, 0, 0 },
  123. + [RTL_REG_CHIPVER] = { 0, 4, 31, 8, 0, 0 },
  124. + [RTL_REG_CHIPTYPE] = { 0, 4, 31, 2, 8, 0 },
  125. +
  126. + /* CPU port number */
  127. + [RTL_REG_CPUPORT] = { 2, 4, 21, 3, 0, 0 },
  128. + /* Enable CPU port function */
  129. + [RTL_REG_EN_CPUPORT] = { 3, 2, 21, 1, 15, 1 },
  130. + /* Enable CPU port tag insertion */
  131. + [RTL_REG_EN_TAG_OUT] = { 3, 2, 21, 1, 12, 0 },
  132. + /* Enable CPU port tag removal */
  133. + [RTL_REG_EN_TAG_CLR] = { 3, 2, 21, 1, 11, 0 },
  134. + /* Enable CPU port tag checking */
  135. + [RTL_REG_EN_TAG_IN] = { 0, 4, 21, 1, 7, 0 },
  136. + [RTL_REG_EN_TRUNK] = { 0, 0, 19, 1, 11, 1 },
  137. + [RTL_REG_TRUNK_PORTSEL] = { 0, 0, 16, 1, 6, 1 },
  138. + [RTL_REG_RESET] = { 0, 0, 16, 1, 12, 0 },
  139. + [RTL_REG_PHY_RESET] = { 0, 0, 0, 1, 15, 0 },
  140. + [RTL_REG_CPU_LINKUP] = { 0, 6, 22, 1, 15, 0 },
  141. + [RTL_REG_TRAP_CPU] = { 3, 2, 22, 1, 6, 0 },
  142. +
  143. + [RTL_REG_VLAN_TAG_ONLY] = { 0, 0, 16, 1, 8, 1 },
  144. + [RTL_REG_VLAN_FILTER] = { 0, 0, 16, 1, 9, 1 },
  145. + [RTL_REG_VLAN_TAG_AWARE] = { 0, 0, 16, 1, 10, 1 },
  146. + [RTL_REG_VLAN_ENABLE] = { 0, 0, 18, 1, 8, 1 },
  147. +
  148. +#define RTL_VLAN_REGS(id, phy, page, regofs) \
  149. + [RTL_REG_VLAN##id##_VID] = { page, phy, 25 + regofs, 12, 0, 0 }, \
  150. + [RTL_REG_VLAN##id##_PORTMASK] = { page, phy, 24 + regofs, 6, 0, 0 }
  151. + RTL_VLAN_REGS( 0, 0, 0, 0),
  152. + RTL_VLAN_REGS( 1, 1, 0, 0),
  153. + RTL_VLAN_REGS( 2, 2, 0, 0),
  154. + RTL_VLAN_REGS( 3, 3, 0, 0),
  155. + RTL_VLAN_REGS( 4, 4, 0, 0),
  156. + RTL_VLAN_REGS( 5, 0, 1, 2),
  157. + RTL_VLAN_REGS( 6, 1, 1, 2),
  158. + RTL_VLAN_REGS( 7, 2, 1, 2),
  159. + RTL_VLAN_REGS( 8, 3, 1, 2),
  160. + RTL_VLAN_REGS( 9, 4, 1, 2),
  161. + RTL_VLAN_REGS(10, 0, 1, 4),
  162. + RTL_VLAN_REGS(11, 1, 1, 4),
  163. + RTL_VLAN_REGS(12, 2, 1, 4),
  164. + RTL_VLAN_REGS(13, 3, 1, 4),
  165. + RTL_VLAN_REGS(14, 4, 1, 4),
  166. + RTL_VLAN_REGS(15, 0, 1, 6),
  167. +
  168. +#define REG_PORT_SETTING(port, phy) \
  169. + [RTL_REG_PORT##port##_SPEED] = { 0, phy, 0, 1, 13, 0 }, \
  170. + [RTL_REG_PORT##port##_NWAY] = { 0, phy, 0, 1, 12, 0 }, \
  171. + [RTL_REG_PORT##port##_NRESTART] = { 0, phy, 0, 1, 9, 0 }, \
  172. + [RTL_REG_PORT##port##_DUPLEX] = { 0, phy, 0, 1, 8, 0 }, \
  173. + [RTL_REG_PORT##port##_TXEN] = { 0, phy, 24, 1, 11, 0 }, \
  174. + [RTL_REG_PORT##port##_RXEN] = { 0, phy, 24, 1, 10, 0 }, \
  175. + [RTL_REG_PORT##port##_LRNEN] = { 0, phy, 24, 1, 9, 0 }, \
  176. + [RTL_REG_PORT##port##_LINK] = { 0, phy, 1, 1, 2, 0 }, \
  177. + [RTL_REG_PORT##port##_NULL_VID_REPLACE] = { 0, phy, 22, 1, 12, 0 }, \
  178. + [RTL_REG_PORT##port##_NON_PVID_DISCARD] = { 0, phy, 22, 1, 11, 0 }, \
  179. + [RTL_REG_PORT##port##_VID_INSERT] = { 0, phy, 22, 2, 9, 0 }, \
  180. + [RTL_REG_PORT##port##_TAG_INSERT] = { 0, phy, 22, 2, 0, 0 }
  181. +
  182. + REG_PORT_SETTING(0, 0),
  183. + REG_PORT_SETTING(1, 1),
  184. + REG_PORT_SETTING(2, 2),
  185. + REG_PORT_SETTING(3, 3),
  186. + REG_PORT_SETTING(4, 4),
  187. + REG_PORT_SETTING(5, 6),
  188. +
  189. +#define REG_PORT_PVID(phy, page, regofs) \
  190. + { page, phy, 24 + regofs, 4, 12, 0 }
  191. + [RTL_REG_PORT0_PVID] = REG_PORT_PVID(0, 0, 0),
  192. + [RTL_REG_PORT1_PVID] = REG_PORT_PVID(1, 0, 0),
  193. + [RTL_REG_PORT2_PVID] = REG_PORT_PVID(2, 0, 0),
  194. + [RTL_REG_PORT3_PVID] = REG_PORT_PVID(3, 0, 0),
  195. + [RTL_REG_PORT4_PVID] = REG_PORT_PVID(4, 0, 0),
  196. + [RTL_REG_PORT5_PVID] = REG_PORT_PVID(0, 1, 2),
  197. +};
  198. +
  199. +static void rtl_set_page(struct mii_dev *bus, unsigned int page)
  200. +{
  201. + u16 pgsel;
  202. +
  203. + BUG_ON(page > RTL8306_NUM_PAGES);
  204. +
  205. + pgsel = bus->read(bus, 0, MDIO_DEVAD_NONE, RTL8306_REG_PAGE);
  206. + pgsel &= ~(RTL8306_REG_PAGE_LO | RTL8306_REG_PAGE_HI);
  207. +
  208. + if (page & (1 << 0))
  209. + pgsel |= RTL8306_REG_PAGE_LO;
  210. +
  211. + if (!(page & (1 << 1))) /* bit is inverted */
  212. + pgsel |= RTL8306_REG_PAGE_HI;
  213. +
  214. + bus->write(bus, 0, MDIO_DEVAD_NONE, RTL8306_REG_PAGE, pgsel);
  215. +
  216. +}
  217. +
  218. +static __maybe_unused int rtl_w16(struct mii_dev *bus, unsigned int page, unsigned int phy,
  219. + unsigned int reg, u16 val)
  220. +{
  221. + rtl_set_page(bus, page);
  222. +
  223. + bus->write(bus, phy, MDIO_DEVAD_NONE, reg, val);
  224. + bus->read(bus, phy, MDIO_DEVAD_NONE, reg); /* flush */
  225. +
  226. + return 0;
  227. +}
  228. +
  229. +static int rtl_r16(struct mii_dev *bus, unsigned int page, unsigned int phy,
  230. + unsigned int reg)
  231. +{
  232. + rtl_set_page(bus, page);
  233. +
  234. + return bus->read(bus, phy, MDIO_DEVAD_NONE, reg);
  235. +}
  236. +
  237. +static u16 rtl_rmw(struct mii_dev *bus, unsigned int page, unsigned int phy,
  238. + unsigned int reg, u16 mask, u16 val)
  239. +{
  240. + u16 r;
  241. +
  242. + rtl_set_page(bus, page);
  243. +
  244. + r = bus->read(bus, phy, MDIO_DEVAD_NONE, reg);
  245. + r &= ~mask;
  246. + r |= val;
  247. + bus->write(bus, phy, MDIO_DEVAD_NONE, reg, r);
  248. +
  249. + return bus->read(bus, phy, MDIO_DEVAD_NONE, reg); /* flush */
  250. +}
  251. +
  252. +static int rtl_get(struct mii_dev *bus, enum rtl_regidx s)
  253. +{
  254. + const struct rtl_reg *r = &rtl_regs[s];
  255. + u16 val;
  256. +
  257. + BUG_ON(s >= ARRAY_SIZE(rtl_regs));
  258. +
  259. + if (r->bits == 0) /* unimplemented */
  260. + return 0;
  261. +
  262. + val = rtl_r16(bus, r->page, r->phy, r->reg);
  263. +
  264. + if (r->shift > 0)
  265. + val >>= r->shift;
  266. +
  267. + if (r->inverted)
  268. + val = ~val;
  269. +
  270. + val &= (1 << r->bits) - 1;
  271. +
  272. + return val;
  273. +}
  274. +
  275. +static __maybe_unused int rtl_set(struct mii_dev *bus, enum rtl_regidx s, unsigned int val)
  276. +{
  277. + const struct rtl_reg *r = &rtl_regs[s];
  278. + u16 mask = 0xffff;
  279. +
  280. + BUG_ON(s >= ARRAY_SIZE(rtl_regs));
  281. +
  282. + if (r->bits == 0) /* unimplemented */
  283. + return 0;
  284. +
  285. + if (r->shift > 0)
  286. + val <<= r->shift;
  287. +
  288. + if (r->inverted)
  289. + val = ~val;
  290. +
  291. + if (r->bits != 16) {
  292. + mask = (1 << r->bits) - 1;
  293. + mask <<= r->shift;
  294. + }
  295. +
  296. + val &= mask;
  297. +
  298. + return rtl_rmw(bus, r->page, r->phy, r->reg, mask, val);
  299. +}
  300. +
  301. +static int rtl8306_probe(struct switch_device *dev)
  302. +{
  303. + struct mii_dev *bus = dev->bus;
  304. + unsigned int chipid, chipver, chiptype;
  305. +
  306. + chipid = rtl_get(bus, RTL_REG_CHIPID);
  307. + chipver = rtl_get(bus, RTL_REG_CHIPVER);
  308. + chiptype = rtl_get(bus, RTL_REG_CHIPTYPE);
  309. +
  310. + debug("%s: chipid %x, chipver %x, chiptype %x\n",
  311. + __func__, chipid, chipver, chiptype);
  312. +
  313. + if (chipid == RTL8306_CHIPID)
  314. + return 0;
  315. +
  316. + return 1;
  317. +}
  318. +
  319. +static void rtl8306_setup(struct switch_device *dev)
  320. +{
  321. + struct mii_dev *bus = dev->bus;
  322. +
  323. + /* initialize cpu port settings */
  324. + rtl_set(bus, RTL_REG_CPUPORT, dev->cpu_port);
  325. + rtl_set(bus, RTL_REG_EN_CPUPORT, 1);
  326. +
  327. + /* enable phy 5 link status */
  328. + rtl_set(bus, RTL_REG_CPU_LINKUP, 1);
  329. +// rtl_set(bus, RTL_REG_PORT5_TXEN, 1);
  330. +// rtl_set(bus, RTL_REG_PORT5_RXEN, 1);
  331. +// rtl_set(bus, RTL_REG_PORT5_LRNEN, 1);
  332. +#ifdef DEBUG
  333. + debug("%s: CPU link up: %i\n",
  334. + __func__, rtl_get(bus, RTL_REG_PORT5_LINK));
  335. +#endif
  336. +
  337. +}
  338. +
  339. +static struct switch_driver rtl8306_drv = {
  340. + .name = "rtl8306",
  341. +};
  342. +
  343. +void switch_rtl8306_init(void)
  344. +{
  345. + /* For archs with manual relocation */
  346. + rtl8306_drv.probe = rtl8306_probe;
  347. + rtl8306_drv.setup = rtl8306_setup;
  348. +
  349. + switch_driver_register(&rtl8306_drv);
  350. +}
  351. --- a/drivers/net/switch/switch.c
  352. +++ b/drivers/net/switch/switch.c
  353. @@ -26,6 +26,9 @@ void switch_init(void)
  354. #if defined(CONFIG_SWITCH_AR8216)
  355. switch_ar8216_init();
  356. #endif
  357. +#if defined(CONFIG_SWITCH_RTL8306)
  358. + switch_rtl8306_init();
  359. +#endif
  360. board_switch_init();
  361. }
  362. --- a/include/switch.h
  363. +++ b/include/switch.h
  364. @@ -100,6 +100,7 @@ static inline void switch_setup(struct s
  365. extern void switch_psb697x_init(void);
  366. extern void switch_adm6996i_init(void);
  367. extern void switch_ar8216_init(void);
  368. +extern void switch_rtl8306_init(void);
  369. #endif /* __SWITCH_H */