1*4bd3bb7bSSamin Guo // SPDX-License-Identifier: GPL-2.0+ 2*4bd3bb7bSSamin Guo /* 3*4bd3bb7bSSamin Guo * StarFive DWMAC platform driver 4*4bd3bb7bSSamin Guo * 5*4bd3bb7bSSamin Guo * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk> 6*4bd3bb7bSSamin Guo * Copyright (C) 2022 StarFive Technology Co., Ltd. 7*4bd3bb7bSSamin Guo * 8*4bd3bb7bSSamin Guo */ 9*4bd3bb7bSSamin Guo 10*4bd3bb7bSSamin Guo #include <linux/mfd/syscon.h> 11*4bd3bb7bSSamin Guo #include <linux/of_device.h> 12*4bd3bb7bSSamin Guo #include <linux/regmap.h> 13*4bd3bb7bSSamin Guo 14*4bd3bb7bSSamin Guo #include "stmmac_platform.h" 15*4bd3bb7bSSamin Guo 16*4bd3bb7bSSamin Guo struct starfive_dwmac { 17*4bd3bb7bSSamin Guo struct device *dev; 18*4bd3bb7bSSamin Guo struct clk *clk_tx; 19*4bd3bb7bSSamin Guo }; 20*4bd3bb7bSSamin Guo 21*4bd3bb7bSSamin Guo static void starfive_dwmac_fix_mac_speed(void *priv, unsigned int speed) 22*4bd3bb7bSSamin Guo { 23*4bd3bb7bSSamin Guo struct starfive_dwmac *dwmac = priv; 24*4bd3bb7bSSamin Guo unsigned long rate; 25*4bd3bb7bSSamin Guo int err; 26*4bd3bb7bSSamin Guo 27*4bd3bb7bSSamin Guo rate = clk_get_rate(dwmac->clk_tx); 28*4bd3bb7bSSamin Guo 29*4bd3bb7bSSamin Guo switch (speed) { 30*4bd3bb7bSSamin Guo case SPEED_1000: 31*4bd3bb7bSSamin Guo rate = 125000000; 32*4bd3bb7bSSamin Guo break; 33*4bd3bb7bSSamin Guo case SPEED_100: 34*4bd3bb7bSSamin Guo rate = 25000000; 35*4bd3bb7bSSamin Guo break; 36*4bd3bb7bSSamin Guo case SPEED_10: 37*4bd3bb7bSSamin Guo rate = 2500000; 38*4bd3bb7bSSamin Guo break; 39*4bd3bb7bSSamin Guo default: 40*4bd3bb7bSSamin Guo dev_err(dwmac->dev, "invalid speed %u\n", speed); 41*4bd3bb7bSSamin Guo break; 42*4bd3bb7bSSamin Guo } 43*4bd3bb7bSSamin Guo 44*4bd3bb7bSSamin Guo err = clk_set_rate(dwmac->clk_tx, rate); 45*4bd3bb7bSSamin Guo if (err) 46*4bd3bb7bSSamin Guo dev_err(dwmac->dev, "failed to set tx rate %lu\n", rate); 47*4bd3bb7bSSamin Guo } 48*4bd3bb7bSSamin Guo 49*4bd3bb7bSSamin Guo static int starfive_dwmac_probe(struct platform_device *pdev) 50*4bd3bb7bSSamin Guo { 51*4bd3bb7bSSamin Guo struct plat_stmmacenet_data *plat_dat; 52*4bd3bb7bSSamin Guo struct stmmac_resources stmmac_res; 53*4bd3bb7bSSamin Guo struct starfive_dwmac *dwmac; 54*4bd3bb7bSSamin Guo struct clk *clk_gtx; 55*4bd3bb7bSSamin Guo int err; 56*4bd3bb7bSSamin Guo 57*4bd3bb7bSSamin Guo err = stmmac_get_platform_resources(pdev, &stmmac_res); 58*4bd3bb7bSSamin Guo if (err) 59*4bd3bb7bSSamin Guo return dev_err_probe(&pdev->dev, err, 60*4bd3bb7bSSamin Guo "failed to get resources\n"); 61*4bd3bb7bSSamin Guo 62*4bd3bb7bSSamin Guo plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac); 63*4bd3bb7bSSamin Guo if (IS_ERR(plat_dat)) 64*4bd3bb7bSSamin Guo return dev_err_probe(&pdev->dev, PTR_ERR(plat_dat), 65*4bd3bb7bSSamin Guo "dt configuration failed\n"); 66*4bd3bb7bSSamin Guo 67*4bd3bb7bSSamin Guo dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); 68*4bd3bb7bSSamin Guo if (!dwmac) 69*4bd3bb7bSSamin Guo return -ENOMEM; 70*4bd3bb7bSSamin Guo 71*4bd3bb7bSSamin Guo dwmac->clk_tx = devm_clk_get_enabled(&pdev->dev, "tx"); 72*4bd3bb7bSSamin Guo if (IS_ERR(dwmac->clk_tx)) 73*4bd3bb7bSSamin Guo return dev_err_probe(&pdev->dev, PTR_ERR(dwmac->clk_tx), 74*4bd3bb7bSSamin Guo "error getting tx clock\n"); 75*4bd3bb7bSSamin Guo 76*4bd3bb7bSSamin Guo clk_gtx = devm_clk_get_enabled(&pdev->dev, "gtx"); 77*4bd3bb7bSSamin Guo if (IS_ERR(clk_gtx)) 78*4bd3bb7bSSamin Guo return dev_err_probe(&pdev->dev, PTR_ERR(clk_gtx), 79*4bd3bb7bSSamin Guo "error getting gtx clock\n"); 80*4bd3bb7bSSamin Guo 81*4bd3bb7bSSamin Guo /* Generally, the rgmii_tx clock is provided by the internal clock, 82*4bd3bb7bSSamin Guo * which needs to match the corresponding clock frequency according 83*4bd3bb7bSSamin Guo * to different speeds. If the rgmii_tx clock is provided by the 84*4bd3bb7bSSamin Guo * external rgmii_rxin, there is no need to configure the clock 85*4bd3bb7bSSamin Guo * internally, because rgmii_rxin will be adaptively adjusted. 86*4bd3bb7bSSamin Guo */ 87*4bd3bb7bSSamin Guo if (!device_property_read_bool(&pdev->dev, "starfive,tx-use-rgmii-clk")) 88*4bd3bb7bSSamin Guo plat_dat->fix_mac_speed = starfive_dwmac_fix_mac_speed; 89*4bd3bb7bSSamin Guo 90*4bd3bb7bSSamin Guo dwmac->dev = &pdev->dev; 91*4bd3bb7bSSamin Guo plat_dat->bsp_priv = dwmac; 92*4bd3bb7bSSamin Guo plat_dat->dma_cfg->dche = true; 93*4bd3bb7bSSamin Guo 94*4bd3bb7bSSamin Guo err = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 95*4bd3bb7bSSamin Guo if (err) { 96*4bd3bb7bSSamin Guo stmmac_remove_config_dt(pdev, plat_dat); 97*4bd3bb7bSSamin Guo return err; 98*4bd3bb7bSSamin Guo } 99*4bd3bb7bSSamin Guo 100*4bd3bb7bSSamin Guo return 0; 101*4bd3bb7bSSamin Guo } 102*4bd3bb7bSSamin Guo 103*4bd3bb7bSSamin Guo static const struct of_device_id starfive_dwmac_match[] = { 104*4bd3bb7bSSamin Guo { .compatible = "starfive,jh7110-dwmac" }, 105*4bd3bb7bSSamin Guo { /* sentinel */ } 106*4bd3bb7bSSamin Guo }; 107*4bd3bb7bSSamin Guo MODULE_DEVICE_TABLE(of, starfive_dwmac_match); 108*4bd3bb7bSSamin Guo 109*4bd3bb7bSSamin Guo static struct platform_driver starfive_dwmac_driver = { 110*4bd3bb7bSSamin Guo .probe = starfive_dwmac_probe, 111*4bd3bb7bSSamin Guo .remove = stmmac_pltfr_remove, 112*4bd3bb7bSSamin Guo .driver = { 113*4bd3bb7bSSamin Guo .name = "starfive-dwmac", 114*4bd3bb7bSSamin Guo .pm = &stmmac_pltfr_pm_ops, 115*4bd3bb7bSSamin Guo .of_match_table = starfive_dwmac_match, 116*4bd3bb7bSSamin Guo }, 117*4bd3bb7bSSamin Guo }; 118*4bd3bb7bSSamin Guo module_platform_driver(starfive_dwmac_driver); 119*4bd3bb7bSSamin Guo 120*4bd3bb7bSSamin Guo MODULE_LICENSE("GPL"); 121*4bd3bb7bSSamin Guo MODULE_DESCRIPTION("StarFive DWMAC platform driver"); 122*4bd3bb7bSSamin Guo MODULE_AUTHOR("Emil Renner Berthing <kernel@esmil.dk>"); 123*4bd3bb7bSSamin Guo MODULE_AUTHOR("Samin Guo <samin.guo@starfivetech.com>"); 124