diff options
author | Neil Armstrong <narmstrong@baylibre.com> | 2022-01-04 17:56:45 +0300 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2022-01-12 20:05:02 +0300 |
commit | 72f1f7e46c6e96b2ae300d750de01ac75d625b4e (patch) | |
tree | 4f5b5b2898f25c26fea5bc12a58fbbafb9b9ea5c | |
parent | 8973d7b8638f1c2615eec495dfe70122a01a9e1b (diff) | |
download | linux-72f1f7e46c6e96b2ae300d750de01ac75d625b4e.tar.xz |
net: stmmac: dwmac-oxnas: Add support for OX810SE
Add support for OX810SE dwmac glue setup, which is a simplified version
of the OX820 introduced later with more control on the PHY interface.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c | 101 |
1 files changed, 79 insertions, 22 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c index adfeb8d3293d..62a69a91ab22 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c @@ -12,6 +12,7 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/mfd/syscon.h> @@ -48,46 +49,60 @@ #define DWMAC_RX_VARDELAY(d) ((d) << DWMAC_RX_VARDELAY_SHIFT) #define DWMAC_RXN_VARDELAY(d) ((d) << DWMAC_RXN_VARDELAY_SHIFT) +struct oxnas_dwmac; + +struct oxnas_dwmac_data { + int (*setup)(struct oxnas_dwmac *dwmac); +}; + struct oxnas_dwmac { struct device *dev; struct clk *clk; struct regmap *regmap; + const struct oxnas_dwmac_data *data; }; -static int oxnas_dwmac_init(struct platform_device *pdev, void *priv) +static int oxnas_dwmac_setup_ox810se(struct oxnas_dwmac *dwmac) { - struct oxnas_dwmac *dwmac = priv; unsigned int value; int ret; - /* Reset HW here before changing the glue configuration */ - ret = device_reset(dwmac->dev); - if (ret) + ret = regmap_read(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, &value); + if (ret < 0) return ret; - ret = clk_prepare_enable(dwmac->clk); - if (ret) - return ret; + /* Enable GMII_GTXCLK to follow GMII_REFCLK, required for gigabit PHY */ + value |= BIT(DWMAC_CKEN_GTX) | + /* Use simple mux for 25/125 Mhz clock switching */ + BIT(DWMAC_SIMPLE_MUX); + + regmap_write(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, value); + + return 0; +} + +static int oxnas_dwmac_setup_ox820(struct oxnas_dwmac *dwmac) +{ + unsigned int value; + int ret; ret = regmap_read(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, &value); - if (ret < 0) { - clk_disable_unprepare(dwmac->clk); + if (ret < 0) return ret; - } /* Enable GMII_GTXCLK to follow GMII_REFCLK, required for gigabit PHY */ value |= BIT(DWMAC_CKEN_GTX) | /* Use simple mux for 25/125 Mhz clock switching */ - BIT(DWMAC_SIMPLE_MUX) | - /* set auto switch tx clock source */ - BIT(DWMAC_AUTO_TX_SOURCE) | - /* enable tx & rx vardelay */ - BIT(DWMAC_CKEN_TX_OUT) | - BIT(DWMAC_CKEN_TXN_OUT) | - BIT(DWMAC_CKEN_TX_IN) | - BIT(DWMAC_CKEN_RX_OUT) | - BIT(DWMAC_CKEN_RXN_OUT) | - BIT(DWMAC_CKEN_RX_IN); + BIT(DWMAC_SIMPLE_MUX) | + /* set auto switch tx clock source */ + BIT(DWMAC_AUTO_TX_SOURCE) | + /* enable tx & rx vardelay */ + BIT(DWMAC_CKEN_TX_OUT) | + BIT(DWMAC_CKEN_TXN_OUT) | + BIT(DWMAC_CKEN_TX_IN) | + BIT(DWMAC_CKEN_RX_OUT) | + BIT(DWMAC_CKEN_RXN_OUT) | + BIT(DWMAC_CKEN_RX_IN); regmap_write(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, value); /* set tx & rx vardelay */ @@ -100,6 +115,27 @@ static int oxnas_dwmac_init(struct platform_device *pdev, void *priv) return 0; } +static int oxnas_dwmac_init(struct platform_device *pdev, void *priv) +{ + struct oxnas_dwmac *dwmac = priv; + int ret; + + /* Reset HW here before changing the glue configuration */ + ret = device_reset(dwmac->dev); + if (ret) + return ret; + + ret = clk_prepare_enable(dwmac->clk); + if (ret) + return ret; + + ret = dwmac->data->setup(dwmac); + if (ret) + clk_disable_unprepare(dwmac->clk); + + return ret; +} + static void oxnas_dwmac_exit(struct platform_device *pdev, void *priv) { struct oxnas_dwmac *dwmac = priv; @@ -128,6 +164,12 @@ static int oxnas_dwmac_probe(struct platform_device *pdev) goto err_remove_config_dt; } + dwmac->data = (const struct oxnas_dwmac_data *)of_device_get_match_data(&pdev->dev); + if (!dwmac->data) { + ret = -EINVAL; + goto err_remove_config_dt; + } + dwmac->dev = &pdev->dev; plat_dat->bsp_priv = dwmac; plat_dat->init = oxnas_dwmac_init; @@ -166,8 +208,23 @@ err_remove_config_dt: return ret; } +static const struct oxnas_dwmac_data ox810se_dwmac_data = { + .setup = oxnas_dwmac_setup_ox810se, +}; + +static const struct oxnas_dwmac_data ox820_dwmac_data = { + .setup = oxnas_dwmac_setup_ox820, +}; + static const struct of_device_id oxnas_dwmac_match[] = { - { .compatible = "oxsemi,ox820-dwmac" }, + { + .compatible = "oxsemi,ox810se-dwmac", + .data = &ox810se_dwmac_data, + }, + { + .compatible = "oxsemi,ox820-dwmac", + .data = &ox820_dwmac_data, + }, { } }; MODULE_DEVICE_TABLE(of, oxnas_dwmac_match); |