Discussion:
[PATCH v2] kernel: rtl8366-smi: add Realtek switch management via mii-bus
(too old to reply)
Сергей Василюгин
2018-04-03 17:13:39 UTC
Permalink
Current version of rtl8366-smi module support Realtek switch
managment via two gpio lines only. This patch add Realtek switch
management via mii_bus. For my board Tp-link Archer C2 v1 (Mediatek
SoC mt7620a based) dts-file configuration looks like:

rtl8367rb {
compatible = "realtek,rtl8367b", "rtl8367b";
realtek,extif1 = <1 0 1 1 1 1 1 1 2>;
mii-bus = <&mdio0>;
};

&ethernet {
status = "okay";
mtd-mac-address = <&rom 0xf100>;
pinctrl-names = "default";
pinctrl-0 = <&rgmii1_pins &rgmii2_pins &mdio_pins>;

***@5 {
status = "okay";
mediatek,fixed-link = <1000 1 1 1>;
phy-mode = "rgmii";
};

mdio0: mdio-bus {
status = "okay";
};
};

Realtek rtl8367rb switch is ok.
Other Realtek switches and archs are untested but must work too.

Version 2: add mii_bus mutex_lock

Signed-off-by: Serge Vasilugin <***@yandex.ru>
--

diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c
index ae04597..c190ebc 100644
--- a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c
+++ b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c
@@ -18,6 +18,7 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
+#include <linux/of_mdio.h>
#include <linux/rtl8366.h>
#include <linux/version.h>

@@ -198,7 +199,7 @@ static int rtl8366_smi_read_byte1(struct rtl8366_smi *smi, u8 *data)
return 0;
}

-int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data)
+static int __rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data)
{
unsigned long flags;
u8 lo = 0;
@@ -239,6 +240,101 @@ int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data)

return ret;
}
+/* Read/write via mdiobus */
+#define MDC_MDIO_CTRL0_REG 31
+#define MDC_MDIO_START_REG 29
+#define MDC_MDIO_CTRL1_REG 21
+#define MDC_MDIO_ADDRESS_REG 23
+#define MDC_MDIO_DATA_WRITE_REG 24
+#define MDC_MDIO_DATA_READ_REG 25
+
+#define MDC_MDIO_START_OP 0xFFFF
+#define MDC_MDIO_ADDR_OP 0x000E
+#define MDC_MDIO_READ_OP 0x0001
+#define MDC_MDIO_WRITE_OP 0x0003
+#define MDC_REALTEK_PHY_ADDR 0x0
+
+int __rtl8366_mdio_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data)
+{
+ u32 phy_id = MDC_REALTEK_PHY_ADDR;
+ struct mii_bus *mbus = smi->ext_mbus;
+
+ BUG_ON(in_interrupt());
+
+ mutex_lock(&mbus->mdio_lock);
+ /* Write Start command to register 29 */
+ mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+ /* Write address control code to register 31 */
+ mbus->write(mbus, phy_id, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP);
+
+ /* Write Start command to register 29 */
+ mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+ /* Write address to register 23 */
+ mbus->write(mbus, phy_id, MDC_MDIO_ADDRESS_REG, addr);
+
+ /* Write Start command to register 29 */
+ mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+ /* Write read control code to register 21 */
+ mbus->write(mbus, phy_id, MDC_MDIO_CTRL1_REG, MDC_MDIO_READ_OP);
+
+ /* Write Start command to register 29 */
+ mbus->write(smi->ext_mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+ /* Read data from register 25 */
+ *data = mbus->read(mbus, phy_id, MDC_MDIO_DATA_READ_REG);
+
+ mutex_unlock(&mbus->mdio_lock);
+
+ return 0;
+}
+
+static int __rtl8366_mdio_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data)
+{
+ u32 phy_id = MDC_REALTEK_PHY_ADDR;
+ struct mii_bus *mbus = smi->ext_mbus;
+
+ BUG_ON(in_interrupt());
+
+ mutex_lock(&mbus->mdio_lock);
+
+ /* Write Start command to register 29 */
+ mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+ /* Write address control code to register 31 */
+ mbus->write(mbus, phy_id, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP);
+
+ /* Write Start command to register 29 */
+ mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+ /* Write address to register 23 */
+ mbus->write(mbus, phy_id, MDC_MDIO_ADDRESS_REG, addr);
+
+ /* Write Start command to register 29 */
+ mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+ /* Write data to register 24 */
+ mbus->write(mbus, phy_id, MDC_MDIO_DATA_WRITE_REG, data);
+
+ /* Write Start command to register 29 */
+ mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+ /* Write data control code to register 21 */
+ mbus->write(mbus, phy_id, MDC_MDIO_CTRL1_REG, MDC_MDIO_WRITE_OP);
+
+ mutex_unlock(&mbus->mdio_lock);
+ return 0;
+}
+
+int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data)
+{
+ if(smi->ext_mbus)
+ return __rtl8366_mdio_read_reg(smi, addr, data);
+ else
+ return __rtl8366_smi_read_reg(smi, addr, data);
+}
EXPORT_SYMBOL_GPL(rtl8366_smi_read_reg);

static int __rtl8366_smi_write_reg(struct rtl8366_smi *smi,
@@ -290,6 +386,9 @@ static int __rtl8366_smi_write_reg(struct rtl8366_smi *smi,

int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data)
{
+ if(smi->ext_mbus)
+ return __rtl8366_mdio_write_reg(smi, addr, data);
+ else
return __rtl8366_smi_write_reg(smi, addr, data, true);
}
EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg);
@@ -1269,20 +1368,21 @@ static int __rtl8366_smi_init(struct rtl8366_smi *smi, const char *name)
{
int err;

- err = gpio_request(smi->gpio_sda, name);
- if (err) {
- printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n",
- smi->gpio_sda, err);
- goto err_out;
- }
+ if(!smi->ext_mbus) {
+ err = gpio_request(smi->gpio_sda, name);
+ if (err) {
+ printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n",
+ smi->gpio_sda, err);
+ goto err_out;
+ }

- err = gpio_request(smi->gpio_sck, name);
- if (err) {
- printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n",
- smi->gpio_sck, err);
- goto err_free_sda;
+ err = gpio_request(smi->gpio_sck, name);
+ if (err) {
+ printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n",
+ smi->gpio_sck, err);
+ goto err_free_sda;
+ }
}
-
spin_lock_init(&smi->lock);

/* start the switch */
@@ -1303,9 +1403,10 @@ static void __rtl8366_smi_cleanup(struct rtl8366_smi *smi)
{
if (smi->hw_reset)
smi->hw_reset(true);
-
- gpio_free(smi->gpio_sck);
- gpio_free(smi->gpio_sda);
+ if(!smi->ext_mbus) {
+ gpio_free(smi->gpio_sck);
+ gpio_free(smi->gpio_sda);
+ }
}

enum rtl8366_type rtl8366_smi_detect(struct rtl8366_platform_data *pdata)
@@ -1358,8 +1459,11 @@ int rtl8366_smi_init(struct rtl8366_smi *smi)
if (err)
goto err_out;

- dev_info(smi->parent, "using GPIO pins %u (SDA) and %u (SCK)\n",
+ if(!smi->ext_mbus)
+ dev_info(smi->parent, "using GPIO pins %u (SDA) and %u (SCK)\n",
smi->gpio_sda, smi->gpio_sck);
+ else
+ dev_info(smi->parent, "using MDIO bus '%s'\n", smi->ext_mbus->name);

err = smi->ops->detect(smi);
if (err) {
@@ -1416,7 +1520,24 @@ int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi)
{
int sck = of_get_named_gpio(pdev->dev.of_node, "gpio-sck", 0);
int sda = of_get_named_gpio(pdev->dev.of_node, "gpio-sda", 0);
+ struct device_node *np = pdev->dev.of_node;;
+ struct device_node *mdio_node = NULL;
+
+ mdio_node = of_parse_phandle(np, "mii-bus", 0);
+ if (!mdio_node) {
+ dev_err(&pdev->dev, "cannot find mdio node phandle");
+ goto try_gpio;
+ }
+
+ smi->ext_mbus = of_mdio_find_bus(mdio_node);
+ if (!smi->ext_mbus) {
+ dev_err(&pdev->dev,
+ "cannot find mdio bus from bus handle");
+ goto try_gpio;
+ }
+ return 0;

+try_gpio:
if (!gpio_is_valid(sck) || !gpio_is_valid(sda)) {
dev_err(&pdev->dev, "gpios missing in devictree\n");
return -EINVAL;
diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h
index 4bb9e9a..79f0114 100644
--- a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h
+++ b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h
@@ -59,6 +59,7 @@ struct rtl8366_smi {
u16 dbg_reg;
u8 dbg_vlan_4k_page;
#endif
+ struct mii_bus *ext_mbus;
};

struct rtl8366_vlan_mc {

---
serge
Florian Fainelli
2018-04-03 17:22:05 UTC
Permalink
Post by Сергей Василюгин
Current version of rtl8366-smi module support Realtek switch
managment via two gpio lines only. This patch add Realtek switch
management via mii_bus. For my board Tp-link Archer C2 v1 (Mediatek
rtl8367rb {
compatible = "realtek,rtl8367b", "rtl8367b";
realtek,extif1 = <1 0 1 1 1 1 1 1 2>;
mii-bus = <&mdio0>;
The switch node should be moved under the mdio controller node below,
parent/child relationships imply the control bus.
Post by Сергей Василюгин
};
&ethernet {
status = "okay";
mtd-mac-address = <&rom 0xf100>;
pinctrl-names = "default";
pinctrl-0 = <&rgmii1_pins &rgmii2_pins &mdio_pins>;
status = "okay";
mediatek,fixed-link = <1000 1 1 1>;
phy-mode = "rgmii";
};
mdio0: mdio-bus {
status = "okay";
};
};
Realtek rtl8367rb switch is ok.
Other Realtek switches and archs are untested but must work too.
Version 2: add mii_bus mutex_lock
--
[snip]
Post by Сергей Василюгин
@@ -1416,7 +1520,24 @@ int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi)
{
int sck = of_get_named_gpio(pdev->dev.of_node, "gpio-sck", 0);
int sda = of_get_named_gpio(pdev->dev.of_node, "gpio-sda", 0);
+ struct device_node *np = pdev->dev.of_node;;
+ struct device_node *mdio_node = NULL;
+
+ mdio_node = of_parse_phandle(np, "mii-bus", 0);
+ if (!mdio_node) {
+ dev_err(&pdev->dev, "cannot find mdio node phandle");
+ goto try_gpio;
+ }
You should have two entry points for your driver, and have shared code,
one entry point is a gpio/platform_driver and the other one is a
mdio_device/driver. They would both call into the same code that does
the register read/write code, but how they are probed should be different.

See drivers/net/dsa/b53/ for an example of a driver that can deal with
multiple control buses.
--
Florian
Сергей Василюгин
2018-04-04 15:51:01 UTC
Permalink
Post by Florian Fainelli
The switch node should be moved under the mdio controller node below,
parent/child relationships imply the control bus.
Ok
Post by Florian Fainelli
You should have two entry points for your driver, and have shared code,
one entry point is a gpio/platform_driver and the other one is a
mdio_device/driver. They would both call into the same code that does
the register read/write code, but how they are probed should be different.
You are right. But rtl8366_smi is not driver. It's only interface lib for real
drivers rtl8366rb, rtl8366s, rtl8367b and rtl8367.

---
serge

Loading...