385 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * dwmac-ingenic.c - Ingenic SoCs DWMAC specific glue layer4 *5 * Copyright (c) 2021 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>6 */7 8#include <linux/bitfield.h>9#include <linux/clk.h>10#include <linux/kernel.h>11#include <linux/mfd/syscon.h>12#include <linux/module.h>13#include <linux/of.h>14#include <linux/of_net.h>15#include <linux/phy.h>16#include <linux/platform_device.h>17#include <linux/regmap.h>18#include <linux/slab.h>19#include <linux/stmmac.h>20 21#include "stmmac_platform.h"22 23#define MACPHYC_TXCLK_SEL_MASK GENMASK(31, 31)24#define MACPHYC_TXCLK_SEL_OUTPUT 0x125#define MACPHYC_TXCLK_SEL_INPUT 0x026#define MACPHYC_MODE_SEL_MASK GENMASK(31, 31)27#define MACPHYC_MODE_SEL_RMII 0x028#define MACPHYC_TX_SEL_MASK GENMASK(19, 19)29#define MACPHYC_TX_SEL_ORIGIN 0x030#define MACPHYC_TX_SEL_DELAY 0x131#define MACPHYC_TX_DELAY_MASK GENMASK(18, 12)32#define MACPHYC_RX_SEL_MASK GENMASK(11, 11)33#define MACPHYC_RX_SEL_ORIGIN 0x034#define MACPHYC_RX_SEL_DELAY 0x135#define MACPHYC_RX_DELAY_MASK GENMASK(10, 4)36#define MACPHYC_SOFT_RST_MASK GENMASK(3, 3)37#define MACPHYC_PHY_INFT_MASK GENMASK(2, 0)38#define MACPHYC_PHY_INFT_RMII 0x439#define MACPHYC_PHY_INFT_RGMII 0x140#define MACPHYC_PHY_INFT_GMII 0x041#define MACPHYC_PHY_INFT_MII 0x042 43#define MACPHYC_TX_DELAY_PS_MAX 249644#define MACPHYC_TX_DELAY_PS_MIN 2045 46#define MACPHYC_RX_DELAY_PS_MAX 249647#define MACPHYC_RX_DELAY_PS_MIN 2048 49enum ingenic_mac_version {50 ID_JZ4775,51 ID_X1000,52 ID_X1600,53 ID_X1830,54 ID_X2000,55};56 57struct ingenic_mac {58 const struct ingenic_soc_info *soc_info;59 struct device *dev;60 struct regmap *regmap;61 62 int rx_delay;63 int tx_delay;64};65 66struct ingenic_soc_info {67 enum ingenic_mac_version version;68 u32 mask;69 70 int (*set_mode)(struct plat_stmmacenet_data *plat_dat);71};72 73static int ingenic_mac_init(struct plat_stmmacenet_data *plat_dat)74{75 struct ingenic_mac *mac = plat_dat->bsp_priv;76 int ret;77 78 if (mac->soc_info->set_mode) {79 ret = mac->soc_info->set_mode(plat_dat);80 if (ret)81 return ret;82 }83 84 return 0;85}86 87static int jz4775_mac_set_mode(struct plat_stmmacenet_data *plat_dat)88{89 struct ingenic_mac *mac = plat_dat->bsp_priv;90 unsigned int val;91 92 switch (plat_dat->mac_interface) {93 case PHY_INTERFACE_MODE_MII:94 val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |95 FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_MII);96 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_MII\n");97 break;98 99 case PHY_INTERFACE_MODE_GMII:100 val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |101 FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_GMII);102 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_GMII\n");103 break;104 105 case PHY_INTERFACE_MODE_RMII:106 val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |107 FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);108 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");109 break;110 111 case PHY_INTERFACE_MODE_RGMII:112 case PHY_INTERFACE_MODE_RGMII_ID:113 case PHY_INTERFACE_MODE_RGMII_TXID:114 case PHY_INTERFACE_MODE_RGMII_RXID:115 val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |116 FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RGMII);117 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RGMII\n");118 break;119 120 default:121 dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);122 return -EINVAL;123 }124 125 /* Update MAC PHY control register */126 return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);127}128 129static int x1000_mac_set_mode(struct plat_stmmacenet_data *plat_dat)130{131 struct ingenic_mac *mac = plat_dat->bsp_priv;132 133 switch (plat_dat->mac_interface) {134 case PHY_INTERFACE_MODE_RMII:135 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");136 break;137 138 default:139 dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);140 return -EINVAL;141 }142 143 /* Update MAC PHY control register */144 return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, 0);145}146 147static int x1600_mac_set_mode(struct plat_stmmacenet_data *plat_dat)148{149 struct ingenic_mac *mac = plat_dat->bsp_priv;150 unsigned int val;151 152 switch (plat_dat->mac_interface) {153 case PHY_INTERFACE_MODE_RMII:154 val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);155 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");156 break;157 158 default:159 dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);160 return -EINVAL;161 }162 163 /* Update MAC PHY control register */164 return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);165}166 167static int x1830_mac_set_mode(struct plat_stmmacenet_data *plat_dat)168{169 struct ingenic_mac *mac = plat_dat->bsp_priv;170 unsigned int val;171 172 switch (plat_dat->mac_interface) {173 case PHY_INTERFACE_MODE_RMII:174 val = FIELD_PREP(MACPHYC_MODE_SEL_MASK, MACPHYC_MODE_SEL_RMII) |175 FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);176 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");177 break;178 179 default:180 dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);181 return -EINVAL;182 }183 184 /* Update MAC PHY control register */185 return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);186}187 188static int x2000_mac_set_mode(struct plat_stmmacenet_data *plat_dat)189{190 struct ingenic_mac *mac = plat_dat->bsp_priv;191 unsigned int val;192 193 switch (plat_dat->mac_interface) {194 case PHY_INTERFACE_MODE_RMII:195 val = FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN) |196 FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN) |197 FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);198 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");199 break;200 201 case PHY_INTERFACE_MODE_RGMII:202 case PHY_INTERFACE_MODE_RGMII_ID:203 case PHY_INTERFACE_MODE_RGMII_TXID:204 case PHY_INTERFACE_MODE_RGMII_RXID:205 val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RGMII);206 207 if (mac->tx_delay == 0)208 val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN);209 else210 val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_DELAY) |211 FIELD_PREP(MACPHYC_TX_DELAY_MASK, (mac->tx_delay + 9750) / 19500 - 1);212 213 if (mac->rx_delay == 0)214 val |= FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN);215 else216 val |= FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_DELAY) |217 FIELD_PREP(MACPHYC_RX_DELAY_MASK, (mac->rx_delay + 9750) / 19500 - 1);218 219 dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RGMII\n");220 break;221 222 default:223 dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);224 return -EINVAL;225 }226 227 /* Update MAC PHY control register */228 return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);229}230 231static int ingenic_mac_probe(struct platform_device *pdev)232{233 struct plat_stmmacenet_data *plat_dat;234 struct stmmac_resources stmmac_res;235 struct ingenic_mac *mac;236 const struct ingenic_soc_info *data;237 u32 tx_delay_ps, rx_delay_ps;238 int ret;239 240 ret = stmmac_get_platform_resources(pdev, &stmmac_res);241 if (ret)242 return ret;243 244 plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);245 if (IS_ERR(plat_dat))246 return PTR_ERR(plat_dat);247 248 mac = devm_kzalloc(&pdev->dev, sizeof(*mac), GFP_KERNEL);249 if (!mac)250 return -ENOMEM;251 252 data = of_device_get_match_data(&pdev->dev);253 if (!data) {254 dev_err(&pdev->dev, "No of match data provided\n");255 return -EINVAL;256 }257 258 /* Get MAC PHY control register */259 mac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "mode-reg");260 if (IS_ERR(mac->regmap)) {261 dev_err(&pdev->dev, "%s: Failed to get syscon regmap\n", __func__);262 return PTR_ERR(mac->regmap);263 }264 265 if (!of_property_read_u32(pdev->dev.of_node, "tx-clk-delay-ps", &tx_delay_ps)) {266 if (tx_delay_ps >= MACPHYC_TX_DELAY_PS_MIN &&267 tx_delay_ps <= MACPHYC_TX_DELAY_PS_MAX) {268 mac->tx_delay = tx_delay_ps * 1000;269 } else {270 dev_err(&pdev->dev, "Invalid TX clock delay: %dps\n", tx_delay_ps);271 return -EINVAL;272 }273 }274 275 if (!of_property_read_u32(pdev->dev.of_node, "rx-clk-delay-ps", &rx_delay_ps)) {276 if (rx_delay_ps >= MACPHYC_RX_DELAY_PS_MIN &&277 rx_delay_ps <= MACPHYC_RX_DELAY_PS_MAX) {278 mac->rx_delay = rx_delay_ps * 1000;279 } else {280 dev_err(&pdev->dev, "Invalid RX clock delay: %dps\n", rx_delay_ps);281 return -EINVAL;282 }283 }284 285 mac->soc_info = data;286 mac->dev = &pdev->dev;287 288 plat_dat->bsp_priv = mac;289 290 ret = ingenic_mac_init(plat_dat);291 if (ret)292 return ret;293 294 return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);295}296 297#ifdef CONFIG_PM_SLEEP298static int ingenic_mac_suspend(struct device *dev)299{300 int ret;301 302 ret = stmmac_suspend(dev);303 304 return ret;305}306 307static int ingenic_mac_resume(struct device *dev)308{309 struct net_device *ndev = dev_get_drvdata(dev);310 struct stmmac_priv *priv = netdev_priv(ndev);311 int ret;312 313 ret = ingenic_mac_init(priv->plat);314 if (ret)315 return ret;316 317 ret = stmmac_resume(dev);318 319 return ret;320}321#endif /* CONFIG_PM_SLEEP */322 323static SIMPLE_DEV_PM_OPS(ingenic_mac_pm_ops, ingenic_mac_suspend, ingenic_mac_resume);324 325static struct ingenic_soc_info jz4775_soc_info = {326 .version = ID_JZ4775,327 .mask = MACPHYC_TXCLK_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,328 329 .set_mode = jz4775_mac_set_mode,330};331 332static struct ingenic_soc_info x1000_soc_info = {333 .version = ID_X1000,334 .mask = MACPHYC_SOFT_RST_MASK,335 336 .set_mode = x1000_mac_set_mode,337};338 339static struct ingenic_soc_info x1600_soc_info = {340 .version = ID_X1600,341 .mask = MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,342 343 .set_mode = x1600_mac_set_mode,344};345 346static struct ingenic_soc_info x1830_soc_info = {347 .version = ID_X1830,348 .mask = MACPHYC_MODE_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,349 350 .set_mode = x1830_mac_set_mode,351};352 353static struct ingenic_soc_info x2000_soc_info = {354 .version = ID_X2000,355 .mask = MACPHYC_TX_SEL_MASK | MACPHYC_TX_DELAY_MASK | MACPHYC_RX_SEL_MASK |356 MACPHYC_RX_DELAY_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,357 358 .set_mode = x2000_mac_set_mode,359};360 361static const struct of_device_id ingenic_mac_of_matches[] = {362 { .compatible = "ingenic,jz4775-mac", .data = &jz4775_soc_info },363 { .compatible = "ingenic,x1000-mac", .data = &x1000_soc_info },364 { .compatible = "ingenic,x1600-mac", .data = &x1600_soc_info },365 { .compatible = "ingenic,x1830-mac", .data = &x1830_soc_info },366 { .compatible = "ingenic,x2000-mac", .data = &x2000_soc_info },367 { }368};369MODULE_DEVICE_TABLE(of, ingenic_mac_of_matches);370 371static struct platform_driver ingenic_mac_driver = {372 .probe = ingenic_mac_probe,373 .remove_new = stmmac_pltfr_remove,374 .driver = {375 .name = "ingenic-mac",376 .pm = pm_ptr(&ingenic_mac_pm_ops),377 .of_match_table = ingenic_mac_of_matches,378 },379};380module_platform_driver(ingenic_mac_driver);381 382MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>");383MODULE_DESCRIPTION("Ingenic SoCs DWMAC specific glue layer");384MODULE_LICENSE("GPL v2");385