|
24 | 24 | #include <linux/pcs/pcs-mtk-lynxi.h> |
25 | 25 | #include <linux/pcs/pcs.h> |
26 | 26 | #include <linux/phy/phy.h> |
| 27 | +#include <linux/gpio/consumer.h> |
27 | 28 | #include <linux/jhash.h> |
28 | 29 | #include <linux/bitfield.h> |
29 | 30 | #include <net/dsa.h> |
@@ -4918,6 +4919,207 @@ static const struct net_device_ops mtk_netdev_ops = { |
4918 | 4919 | .ndo_select_queue = mtk_select_queue, |
4919 | 4920 | }; |
4920 | 4921 |
|
| 4922 | +static void mux_poll(struct work_struct *work) |
| 4923 | +{ |
| 4924 | + struct mtk_mux *mux = container_of(work, struct mtk_mux, poll.work); |
| 4925 | + struct mtk_mac *mac = mux->mac; |
| 4926 | + struct mtk_eth *eth = mac->hw; |
| 4927 | + struct net_device *dev = eth->netdev[mac->id]; |
| 4928 | + unsigned int new_channel; |
| 4929 | + int sfp_present; |
| 4930 | + |
| 4931 | + if (IS_ERR(mux->mod_def0_gpio) || IS_ERR(mux->chan_sel_gpio)) |
| 4932 | + goto reschedule; |
| 4933 | + |
| 4934 | + sfp_present = gpiod_get_value_cansleep(mux->mod_def0_gpio); |
| 4935 | + new_channel = sfp_present ? mux->sfp_present_channel : !mux->sfp_present_channel; |
| 4936 | + |
| 4937 | + if (mux->channel == new_channel || !netif_running(dev)) |
| 4938 | + goto reschedule; |
| 4939 | + |
| 4940 | + rtnl_lock(); |
| 4941 | + |
| 4942 | + mtk_stop(dev); |
| 4943 | + |
| 4944 | + mac->of_node = mux->data[new_channel]->of_node; |
| 4945 | + mac->phylink = mux->data[new_channel]->phylink; |
| 4946 | + |
| 4947 | + dev_info(eth->dev, "ethernet mux: switch to channel%d\n", new_channel); |
| 4948 | + |
| 4949 | + gpiod_set_value_cansleep(mux->chan_sel_gpio, new_channel); |
| 4950 | + |
| 4951 | + mtk_open(dev); |
| 4952 | + |
| 4953 | + rtnl_unlock(); |
| 4954 | + |
| 4955 | + mux->channel = new_channel; |
| 4956 | + |
| 4957 | +reschedule: |
| 4958 | + mod_delayed_work(system_wq, &mux->poll, msecs_to_jiffies(100)); |
| 4959 | +} |
| 4960 | + |
| 4961 | +static int mtk_add_mux_channel(struct mtk_mux *mux, struct device_node *np) |
| 4962 | +{ |
| 4963 | + const __be32 *_id = of_get_property(np, "reg", NULL); |
| 4964 | + struct mtk_mac *mac = mux->mac; |
| 4965 | + struct mtk_eth *eth = mac->hw; |
| 4966 | + struct mtk_mux_data *data; |
| 4967 | + struct phylink *phylink; |
| 4968 | + phy_interface_t phy_mode; |
| 4969 | + int id, err; |
| 4970 | + |
| 4971 | + if (!_id) { |
| 4972 | + dev_err(eth->dev, "missing mux channel id\n"); |
| 4973 | + return -EINVAL; |
| 4974 | + } |
| 4975 | + |
| 4976 | + id = be32_to_cpup(_id); |
| 4977 | + if (id < 0 || id > 1) { |
| 4978 | + dev_err(eth->dev, "%d is not a valid mux channel id\n", id); |
| 4979 | + return -EINVAL; |
| 4980 | + } |
| 4981 | + |
| 4982 | + data = kmalloc(sizeof(*data), GFP_KERNEL); |
| 4983 | + if (unlikely(!data)) { |
| 4984 | + dev_err(eth->dev, "failed to create mux data structure\n"); |
| 4985 | + return -ENOMEM; |
| 4986 | + } |
| 4987 | + |
| 4988 | + err = of_get_phy_mode(np, &phy_mode); |
| 4989 | + if (err) { |
| 4990 | + dev_err(eth->dev, "incorrect phy-mode\n"); |
| 4991 | + goto err_free_data; |
| 4992 | + } |
| 4993 | + |
| 4994 | + phylink = phylink_create(&mux->mac->phylink_config, |
| 4995 | + of_fwnode_handle(np), |
| 4996 | + phy_mode, &mtk_phylink_ops); |
| 4997 | + if (IS_ERR(phylink)) { |
| 4998 | + dev_err(eth->dev, "failed to create phylink structure\n"); |
| 4999 | + err = PTR_ERR(phylink); |
| 5000 | + goto err_free_data; |
| 5001 | + } |
| 5002 | + |
| 5003 | + data->of_node = np; |
| 5004 | + data->phylink = phylink; |
| 5005 | + mux->data[id] = data; |
| 5006 | + |
| 5007 | + return 0; |
| 5008 | + |
| 5009 | +err_free_data: |
| 5010 | + kfree(data); |
| 5011 | + return err; |
| 5012 | +} |
| 5013 | + |
| 5014 | +static void mtk_release_mux(struct mtk_eth *eth, int id) |
| 5015 | +{ |
| 5016 | + struct mtk_mux *mux = eth->mux[id]; |
| 5017 | + int i; |
| 5018 | + |
| 5019 | + if (!mux) |
| 5020 | + return; |
| 5021 | + |
| 5022 | + cancel_delayed_work_sync(&mux->poll); |
| 5023 | + |
| 5024 | + if (!IS_ERR_OR_NULL(mux->mod_def0_gpio)) |
| 5025 | + gpiod_put(mux->mod_def0_gpio); |
| 5026 | + |
| 5027 | + if (!IS_ERR_OR_NULL(mux->chan_sel_gpio)) |
| 5028 | + gpiod_put(mux->chan_sel_gpio); |
| 5029 | + |
| 5030 | + for (i = 0; i < 2; i++) { |
| 5031 | + if (mux->data[i]) { |
| 5032 | + if (mux->data[i]->phylink) |
| 5033 | + phylink_destroy(mux->data[i]->phylink); |
| 5034 | + kfree(mux->data[i]); |
| 5035 | + } |
| 5036 | + } |
| 5037 | + kfree(mux); |
| 5038 | + eth->mux[id] = NULL; |
| 5039 | +} |
| 5040 | + |
| 5041 | +static void mtk_release_all_muxes(struct mtk_eth *eth) |
| 5042 | +{ |
| 5043 | + int i; |
| 5044 | + for (i = 0; i < MTK_MAX_DEVS; i++) |
| 5045 | + mtk_release_mux(eth, i); |
| 5046 | +} |
| 5047 | + |
| 5048 | +static int mtk_add_mux(struct mtk_eth *eth, struct device_node *np) |
| 5049 | +{ |
| 5050 | + const __be32 *_id = of_get_property(np, "reg", NULL); |
| 5051 | + struct device_node *child; |
| 5052 | + struct mtk_mux *mux; |
| 5053 | + unsigned int id; |
| 5054 | + int err; |
| 5055 | + |
| 5056 | + if (!_id) { |
| 5057 | + dev_err(eth->dev, "missing attach mac id\n"); |
| 5058 | + return -EINVAL; |
| 5059 | + } |
| 5060 | + |
| 5061 | + id = be32_to_cpup(_id); |
| 5062 | + if (id < 0 || id >= MTK_MAX_DEVS) { |
| 5063 | + dev_err(eth->dev, "%d is not a valid attach mac id\n", id); |
| 5064 | + return -EINVAL; |
| 5065 | + } |
| 5066 | + |
| 5067 | + mux = kmalloc(sizeof(struct mtk_mux), GFP_KERNEL); |
| 5068 | + if (unlikely(!mux)) { |
| 5069 | + dev_err(eth->dev, "failed to create mux structure\n"); |
| 5070 | + return -ENOMEM; |
| 5071 | + } |
| 5072 | + |
| 5073 | + eth->mux[id] = mux; |
| 5074 | + mux->mac = eth->mac[id]; |
| 5075 | + mux->channel = 0; |
| 5076 | + |
| 5077 | + mux->mod_def0_gpio = fwnode_gpiod_get_index(of_fwnode_handle(np), |
| 5078 | + "mod-def0", 0, GPIOD_IN | |
| 5079 | + GPIOD_FLAGS_BIT_NONEXCLUSIVE, "?"); |
| 5080 | + |
| 5081 | + if (IS_ERR(mux->mod_def0_gpio)) { |
| 5082 | + dev_err(eth->dev, "failed to requset gpio for mod-def0\n"); |
| 5083 | + err = PTR_ERR(mux->mod_def0_gpio); |
| 5084 | + goto err_free_mux; |
| 5085 | + } |
| 5086 | + |
| 5087 | + mux->chan_sel_gpio = fwnode_gpiod_get_index(of_fwnode_handle(np), |
| 5088 | + "chan-sel", 0, GPIOD_OUT_LOW, "?"); |
| 5089 | + |
| 5090 | + if (IS_ERR(mux->chan_sel_gpio)) { |
| 5091 | + dev_err(eth->dev, "failed to requset gpio for chan-sel\n"); |
| 5092 | + err = PTR_ERR(mux->chan_sel_gpio); |
| 5093 | + goto err_put_mod_def0; |
| 5094 | + } |
| 5095 | + |
| 5096 | + of_property_read_u32(np, "sfp-present-channel", |
| 5097 | + &mux->sfp_present_channel); |
| 5098 | + |
| 5099 | + for_each_child_of_node(np, child) { |
| 5100 | + err = mtk_add_mux_channel(mux, child); |
| 5101 | + if (err) { |
| 5102 | + dev_err(eth->dev, "failed to add mtk_mux\n"); |
| 5103 | + of_node_put(child); |
| 5104 | + goto err_put_chan_sel; |
| 5105 | + } |
| 5106 | + } |
| 5107 | + |
| 5108 | + INIT_DELAYED_WORK(&mux->poll, mux_poll); |
| 5109 | + mod_delayed_work(system_wq, &mux->poll, msecs_to_jiffies(3000)); |
| 5110 | + |
| 5111 | + return 0; |
| 5112 | + |
| 5113 | +err_put_chan_sel: |
| 5114 | + gpiod_put(mux->chan_sel_gpio); |
| 5115 | +err_put_mod_def0: |
| 5116 | + gpiod_put(mux->mod_def0_gpio); |
| 5117 | +err_free_mux: |
| 5118 | + kfree(mux); |
| 5119 | + eth->mux[id] = NULL; |
| 5120 | + return err; |
| 5121 | +} |
| 5122 | + |
4921 | 5123 | static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) |
4922 | 5124 | { |
4923 | 5125 | const __be32 *_id = of_get_property(np, "reg", NULL); |
@@ -5248,7 +5450,7 @@ static int mtk_setup_legacy_sram(struct mtk_eth *eth, struct resource *res) |
5248 | 5450 | static int mtk_probe(struct platform_device *pdev) |
5249 | 5451 | { |
5250 | 5452 | struct resource *res = NULL; |
5251 | | - struct device_node *mac_np; |
| 5453 | + struct device_node *mac_np, *mux_np; |
5252 | 5454 | struct mtk_eth *eth; |
5253 | 5455 | int err, i; |
5254 | 5456 |
|
@@ -5453,6 +5655,26 @@ static int mtk_probe(struct platform_device *pdev) |
5453 | 5655 | goto err_free_dev; |
5454 | 5656 | } |
5455 | 5657 |
|
| 5658 | + mux_np = of_get_child_by_name(eth->dev->of_node, "mux-bus"); |
| 5659 | + if (mux_np) { |
| 5660 | + struct device_node *child; |
| 5661 | + |
| 5662 | + for_each_available_child_of_node(mux_np, child) { |
| 5663 | + if (!of_device_is_compatible(child, |
| 5664 | + "mediatek,eth-mux")) |
| 5665 | + continue; |
| 5666 | + |
| 5667 | + if (!of_device_is_available(child)) |
| 5668 | + continue; |
| 5669 | + |
| 5670 | + err = mtk_add_mux(eth, child); |
| 5671 | + if (err) |
| 5672 | + dev_err(&pdev->dev, "failed to add mux\n"); |
| 5673 | + |
| 5674 | + of_node_put(mux_np); |
| 5675 | + }; |
| 5676 | + } |
| 5677 | + |
5456 | 5678 | if (eth->soc->offload_version) { |
5457 | 5679 | u8 ppe_num = eth->soc->ppe_num; |
5458 | 5680 |
|
@@ -5510,6 +5732,7 @@ static int mtk_probe(struct platform_device *pdev) |
5510 | 5732 | mtk_unreg_dev(eth); |
5511 | 5733 | err_deinit_ppe: |
5512 | 5734 | mtk_ppe_deinit(eth); |
| 5735 | + mtk_release_all_muxes(eth); |
5513 | 5736 | mtk_mdio_cleanup(eth); |
5514 | 5737 | err_free_dev: |
5515 | 5738 | mtk_free_dev(eth); |
@@ -5546,6 +5769,7 @@ static void mtk_remove(struct platform_device *pdev) |
5546 | 5769 | mtk_cleanup(eth); |
5547 | 5770 | free_netdev(eth->dummy_dev); |
5548 | 5771 | mtk_mdio_cleanup(eth); |
| 5772 | + mtk_release_all_muxes(eth); |
5549 | 5773 | } |
5550 | 5774 |
|
5551 | 5775 | static const struct mtk_soc_data mt2701_data = { |
|
0 commit comments