Skip to content

Commit a2ab5ca

Browse files
committed
bmips: b53: enable bcm63268 internal PHYs
On the smartrg sr505n the bootloader only sets registers to enable the PHYs if it's interrupted. When Linux boots this results in a -EINVAL error when trying to read from the EPHYs and the GPHY doesn't work. This patch disables low power mode in the GPHY/EPHYs and properly resets the EPHYs. Signed-off-by: Kyle Hendry <kylehendrydev@gmail.com>
1 parent 9736d42 commit a2ab5ca

File tree

3 files changed

+326
-3
lines changed

3 files changed

+326
-3
lines changed

target/linux/bmips/bcm63268/config-6.12

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ CONFIG_BCM6345_EXT_IRQ=y
1313
CONFIG_BCM6345_L1_IRQ=y
1414
# CONFIG_BCM6348_ENET is not set
1515
CONFIG_BCM6368_ENETSW=y
16+
CONFIG_BCM63XX_PHY=y
1617
CONFIG_BCM63XX_POWER=y
1718
CONFIG_BCM7038_WDT=y
1819
CONFIG_BLK_MQ_PCI=y

target/linux/bmips/dts/bcm63268.dtsi

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,11 @@
288288
pins = "dsl_gpio9";
289289
};
290290
};
291+
ephy_rst: reset-controller@3C {
292+
compatible = "brcm,bcm6345-reset";
293+
reg = <0x3C 0x4>;
294+
#reset-cells = <1>;
295+
};
291296
};
292297

293298
uart0: serial@10000180 {
@@ -481,8 +486,7 @@
481486
<&timer_clk BCM63268_TCLK_GPHY1>;
482487

483488
resets = <&periph_rst BCM63268_RST_ENETSW>,
484-
<&periph_rst BCM63268_RST_EPHY>,
485-
<&periph_rst BCM63268_RST_GPHY>;
489+
<&periph_rst BCM63268_RST_EPHY>;
486490

487491
power-domains = <&periph_pwr BCM63268_POWER_DOMAIN_ROBOSW>;
488492

@@ -532,6 +536,8 @@
532536
reg = <0x10700000 0x8000>;
533537
big-endian;
534538

539+
brcm,gpio-ctrl = <&gpio_cntl>;
540+
535541
ports {
536542
#address-cells = <1>;
537543
#size-cells = <0>;
@@ -564,21 +570,41 @@
564570
phy1: ethernet-phy@1 {
565571
compatible = "ethernet-phy-ieee802.3-c22";
566572
reg = <1>;
573+
574+
resets = <&ephy_rst 0>;
575+
reset-names = "phy";
576+
reset-assert-us = <2000>;
577+
reset-deassert-us = <2000>;
567578
};
568579

569580
phy2: ethernet-phy@2 {
570581
compatible = "ethernet-phy-ieee802.3-c22";
571582
reg = <2>;
583+
584+
resets = <&ephy_rst 1>;
585+
reset-names = "phy";
586+
reset-assert-us = <2000>;
587+
reset-deassert-us = <2000>;
572588
};
573589

574590
phy3: ethernet-phy@3 {
575591
compatible = "ethernet-phy-ieee802.3-c22";
576592
reg = <3>;
593+
594+
resets = <&ephy_rst 2>;
595+
reset-names = "phy";
596+
reset-assert-us = <2000>;
597+
reset-deassert-us = <2000>;
577598
};
578599

579600
phy4: ethernet-phy@4 {
580-
compatible = "ethernet-phy-ieee802.3-c22";
601+
compatible = "ethernet-phy-id0362.5f50";
581602
reg = <4>;
603+
604+
resets = <&periph_rst BCM63268_RST_GPHY>;
605+
reset-names = "phy";
606+
reset-assert-us = <2000>;
607+
reset-deassert-us = <2000>;
582608
};
583609
};
584610

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
--- a/drivers/net/dsa/b53/b53_common.c
2+
+++ b/drivers/net/dsa/b53/b53_common.c
3+
@@ -689,6 +689,9 @@ int b53_enable_port(struct dsa_switch *d
4+
5+
cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
6+
7+
+ if (dev->ops->phy_enable)
8+
+ dev->ops->phy_enable(dev, port);
9+
+
10+
if (dev->ops->irq_enable)
11+
ret = dev->ops->irq_enable(dev, port);
12+
if (ret)
13+
@@ -727,6 +730,9 @@ void b53_disable_port(struct dsa_switch
14+
reg |= PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE;
15+
b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), reg);
16+
17+
+ if (dev->ops->phy_disable)
18+
+ dev->ops->phy_disable(dev, port);
19+
+
20+
if (dev->ops->irq_disable)
21+
dev->ops->irq_disable(dev, port);
22+
}
23+
@@ -1404,7 +1410,7 @@ static void b53_adjust_63xx_rgmii(struct
24+
b53_read8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), &rgmii_ctrl);
25+
rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
26+
27+
- if (is63268(dev))
28+
+ if (is6318_268(dev))
29+
rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE;
30+
31+
rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII;
32+
@@ -2791,19 +2797,6 @@ static const struct b53_chip_data b53_sw
33+
.jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX,
34+
},
35+
{
36+
- .chip_id = BCM63268_DEVICE_ID,
37+
- .dev_name = "BCM63268",
38+
- .vlans = 4096,
39+
- .enabled_ports = 0, /* pdata must provide them */
40+
- .arl_bins = 4,
41+
- .arl_buckets = 1024,
42+
- .imp_port = 8,
43+
- .vta_regs = B53_VTA_REGS_63XX,
44+
- .duplex_reg = B53_DUPLEX_STAT_63XX,
45+
- .jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX,
46+
- .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX,
47+
- },
48+
- {
49+
.chip_id = BCM53010_DEVICE_ID,
50+
.dev_name = "BCM53010",
51+
.vlans = 4096,
52+
@@ -2952,13 +2945,17 @@ static const struct b53_chip_data b53_sw
53+
54+
static int b53_switch_init(struct b53_device *dev)
55+
{
56+
+ u32 chip_id = dev->chip_id;
57+
unsigned int i;
58+
int ret;
59+
60+
+ if (is63xx(dev))
61+
+ chip_id = BCM63XX_DEVICE_ID;
62+
+
63+
for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) {
64+
const struct b53_chip_data *chip = &b53_switch_chips[i];
65+
66+
- if (chip->chip_id == dev->chip_id) {
67+
+ if (chip->chip_id == chip_id) {
68+
if (!dev->enabled_ports)
69+
dev->enabled_ports = chip->enabled_ports;
70+
dev->name = chip->dev_name;
71+
--- a/drivers/net/dsa/b53/b53_mmap.c
72+
+++ b/drivers/net/dsa/b53/b53_mmap.c
73+
@@ -21,13 +21,60 @@
74+
#include <linux/module.h>
75+
#include <linux/of.h>
76+
#include <linux/io.h>
77+
+#include <linux/mfd/syscon.h>
78+
#include <linux/platform_device.h>
79+
#include <linux/platform_data/b53.h>
80+
+#include <linux/regmap.h>
81+
82+
#include "b53_priv.h"
83+
84+
+#define BCM63XX_EPHY_REG 0x3C
85+
+#define BCM63268_GPHY_REG 0x54
86+
+
87+
+#define GPHY_CTRL_LOW_PWR BIT(3)
88+
+#define GPHY_CTRL_IDDQ_BIAS BIT(0)
89+
+
90+
+struct b53_phy_info {
91+
+ u32 gphy_port_mask;
92+
+ u32 ephy_enable_mask;
93+
+ u32 ephy_port_mask;
94+
+ u32 ephy_bias_bit;
95+
+ const u32 *ephy_offset;
96+
+};
97+
+
98+
struct b53_mmap_priv {
99+
void __iomem *regs;
100+
+ struct regmap *gpio_ctrl;
101+
+ const struct b53_phy_info *phy_info;
102+
+ u32 phys_enabled;
103+
+};
104+
+
105+
+static const u32 bcm6318_ephy_offsets[] = {4, 5, 6, 7};
106+
+
107+
+static const struct b53_phy_info bcm6318_ephy_info = {
108+
+ .ephy_enable_mask = BIT(0) | BIT(4) | BIT(8) | BIT(12) | BIT(16),
109+
+ .ephy_port_mask = GENMASK((ARRAY_SIZE(bcm6318_ephy_offsets) - 1), 0),
110+
+ .ephy_bias_bit = 24,
111+
+ .ephy_offset = bcm6318_ephy_offsets,
112+
+};
113+
+
114+
+static const u32 bcm6368_ephy_offsets[] = {2, 3, 4, 5};
115+
+
116+
+static const struct b53_phy_info bcm6368_ephy_info = {
117+
+ .ephy_enable_mask = BIT(0),
118+
+ .ephy_port_mask = GENMASK((ARRAY_SIZE(bcm6368_ephy_offsets) - 1), 0),
119+
+ .ephy_bias_bit = 0,
120+
+ .ephy_offset = bcm6368_ephy_offsets,
121+
+};
122+
+
123+
+static const u32 bcm63268_ephy_offsets[] = {4, 9, 14};
124+
+
125+
+static const struct b53_phy_info bcm63268_ephy_info = {
126+
+ .gphy_port_mask = BIT(3),
127+
+ .ephy_enable_mask = GENMASK(4, 0),
128+
+ .ephy_port_mask = GENMASK((ARRAY_SIZE(bcm63268_ephy_offsets) - 1), 0),
129+
+ .ephy_bias_bit = 24,
130+
+ .ephy_offset = bcm63268_ephy_offsets,
131+
};
132+
133+
static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
134+
@@ -229,6 +276,71 @@ static int b53_mmap_phy_write16(struct b
135+
return -EIO;
136+
}
137+
138+
+static int bcm63xx_ephy_set(struct b53_device *dev, int port, bool enable)
139+
+{
140+
+ struct b53_mmap_priv *priv = dev->priv;
141+
+ const struct b53_phy_info *info = priv->phy_info;
142+
+ struct regmap *gpio_ctrl = priv->gpio_ctrl;
143+
+ u32 mask, val;
144+
+
145+
+ if (enable) {
146+
+ mask = (info->ephy_enable_mask << info->ephy_offset[port])
147+
+ | BIT(info->ephy_bias_bit);
148+
+ val = 0;
149+
+ } else {
150+
+ mask = (info->ephy_enable_mask << info->ephy_offset[port]);
151+
+ if (!((priv->phys_enabled & ~BIT(port)) & info->ephy_port_mask))
152+
+ mask |= BIT(info->ephy_bias_bit);
153+
+ val = mask;
154+
+ }
155+
+ return regmap_update_bits(gpio_ctrl, BCM63XX_EPHY_REG, mask, val);
156+
+}
157+
+
158+
+static int bcm63268_gphy_set(struct b53_device *dev, bool enable)
159+
+{
160+
+ struct b53_mmap_priv *priv = dev->priv;
161+
+ struct regmap *gpio_ctrl = priv->gpio_ctrl;
162+
+ u32 mask = GPHY_CTRL_IDDQ_BIAS | GPHY_CTRL_LOW_PWR;
163+
+ u32 val = 0;
164+
+
165+
+ if (!enable)
166+
+ val = mask;
167+
+
168+
+ return regmap_update_bits(gpio_ctrl, BCM63268_GPHY_REG, mask, val);
169+
+}
170+
+
171+
+static void b53_mmap_phy_enable(struct b53_device *dev, int port)
172+
+{
173+
+ struct b53_mmap_priv *priv = dev->priv;
174+
+ int ret = 0;
175+
+
176+
+ if (priv->phy_info) {
177+
+ if (BIT(port) & priv->phy_info->ephy_port_mask)
178+
+ ret = bcm63xx_ephy_set(dev, port, true);
179+
+ else if (BIT(port) & priv->phy_info->gphy_port_mask)
180+
+ ret = bcm63268_gphy_set(dev, true);
181+
+ }
182+
+
183+
+ if (!ret)
184+
+ priv->phys_enabled |= BIT(port);
185+
+}
186+
+
187+
+static void b53_mmap_phy_disable(struct b53_device *dev, int port)
188+
+{
189+
+ struct b53_mmap_priv *priv = dev->priv;
190+
+ int ret = 0;
191+
+
192+
+ if (priv->phy_info) {
193+
+ if (BIT(port) & priv->phy_info->ephy_port_mask)
194+
+ ret = bcm63xx_ephy_set(dev, port, false);
195+
+ else if (BIT(port) & priv->phy_info->gphy_port_mask)
196+
+ ret = bcm63268_gphy_set(dev, false);
197+
+ }
198+
+
199+
+ if (!ret)
200+
+ priv->phys_enabled &= ~BIT(port);
201+
+}
202+
+
203+
static const struct b53_io_ops b53_mmap_ops = {
204+
.read8 = b53_mmap_read8,
205+
.read16 = b53_mmap_read16,
206+
@@ -242,6 +354,8 @@ static const struct b53_io_ops b53_mmap_
207+
.write64 = b53_mmap_write64,
208+
.phy_read16 = b53_mmap_phy_read16,
209+
.phy_write16 = b53_mmap_phy_write16,
210+
+ .phy_enable = b53_mmap_phy_enable,
211+
+ .phy_disable = b53_mmap_phy_disable,
212+
};
213+
214+
static int b53_mmap_probe_of(struct platform_device *pdev,
215+
@@ -313,6 +427,18 @@ static int b53_mmap_probe(struct platfor
216+
217+
priv->regs = pdata->regs;
218+
219+
+ priv->gpio_ctrl = syscon_regmap_lookup_by_phandle(np, "brcm,gpio-ctrl");
220+
+ if (!IS_ERR(priv->gpio_ctrl)) {
221+
+ if (pdata->chip_id == BCM6318_DEVICE_ID ||
222+
+ pdata->chip_id == BCM6328_DEVICE_ID ||
223+
+ pdata->chip_id == BCM6362_DEVICE_ID)
224+
+ priv->phy_info = &bcm6318_ephy_info;
225+
+ else if (pdata->chip_id == BCM6368_DEVICE_ID)
226+
+ priv->phy_info = &bcm6368_ephy_info;
227+
+ else if (pdata->chip_id == BCM63268_DEVICE_ID)
228+
+ priv->phy_info = &bcm63268_ephy_info;
229+
+ }
230+
+
231+
dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, priv);
232+
if (!dev)
233+
return -ENOMEM;
234+
@@ -348,16 +474,16 @@ static const struct of_device_id b53_mma
235+
.data = (void *)BCM63XX_DEVICE_ID,
236+
}, {
237+
.compatible = "brcm,bcm6318-switch",
238+
- .data = (void *)BCM63268_DEVICE_ID,
239+
+ .data = (void *)BCM6318_DEVICE_ID,
240+
}, {
241+
.compatible = "brcm,bcm6328-switch",
242+
- .data = (void *)BCM63XX_DEVICE_ID,
243+
+ .data = (void *)BCM6328_DEVICE_ID,
244+
}, {
245+
.compatible = "brcm,bcm6362-switch",
246+
- .data = (void *)BCM63XX_DEVICE_ID,
247+
+ .data = (void *)BCM6362_DEVICE_ID,
248+
}, {
249+
.compatible = "brcm,bcm6368-switch",
250+
- .data = (void *)BCM63XX_DEVICE_ID,
251+
+ .data = (void *)BCM6368_DEVICE_ID,
252+
}, {
253+
.compatible = "brcm,bcm63268-switch",
254+
.data = (void *)BCM63268_DEVICE_ID,
255+
--- a/drivers/net/dsa/b53/b53_priv.h
256+
+++ b/drivers/net/dsa/b53/b53_priv.h
257+
@@ -45,6 +45,8 @@ struct b53_io_ops {
258+
int (*phy_write16)(struct b53_device *dev, int addr, int reg, u16 value);
259+
int (*irq_enable)(struct b53_device *dev, int port);
260+
void (*irq_disable)(struct b53_device *dev, int port);
261+
+ void (*phy_enable)(struct b53_device *dev, int port);
262+
+ void (*phy_disable)(struct b53_device *dev, int port);
263+
void (*phylink_get_caps)(struct b53_device *dev, int port,
264+
struct phylink_config *config);
265+
struct phylink_pcs *(*phylink_mac_select_pcs)(struct b53_device *dev,
266+
@@ -71,6 +73,10 @@ enum {
267+
BCM53125_DEVICE_ID = 0x53125,
268+
BCM53128_DEVICE_ID = 0x53128,
269+
BCM63XX_DEVICE_ID = 0x6300,
270+
+ BCM6318_DEVICE_ID = 0x6318,
271+
+ BCM6328_DEVICE_ID = 0x6328,
272+
+ BCM6362_DEVICE_ID = 0x6362,
273+
+ BCM6368_DEVICE_ID = 0x6368,
274+
BCM63268_DEVICE_ID = 0x63268,
275+
BCM53010_DEVICE_ID = 0x53010,
276+
BCM53011_DEVICE_ID = 0x53011,
277+
@@ -218,12 +224,17 @@ static inline int is531x5(struct b53_dev
278+
static inline int is63xx(struct b53_device *dev)
279+
{
280+
return dev->chip_id == BCM63XX_DEVICE_ID ||
281+
+ dev->chip_id == BCM6318_DEVICE_ID ||
282+
+ dev->chip_id == BCM6328_DEVICE_ID ||
283+
+ dev->chip_id == BCM6362_DEVICE_ID ||
284+
+ dev->chip_id == BCM6368_DEVICE_ID ||
285+
dev->chip_id == BCM63268_DEVICE_ID;
286+
}
287+
288+
-static inline int is63268(struct b53_device *dev)
289+
+static inline int is6318_268(struct b53_device *dev)
290+
{
291+
- return dev->chip_id == BCM63268_DEVICE_ID;
292+
+ return dev->chip_id == BCM6318_DEVICE_ID ||
293+
+ dev->chip_id == BCM63268_DEVICE_ID;
294+
}
295+
296+
static inline int is5301x(struct b53_device *dev)

0 commit comments

Comments
 (0)