1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2019
4  * Alex Marginean, NXP
5  */
6 
7 #include <common.h>
8 #include <dm.h>
9 #include <log.h>
10 #include <miiphy.h>
11 #include <dm/device-internal.h>
12 #include <dm/uclass-internal.h>
13 #include <dm/lists.h>
14 
15 #define MDIO_MUX_CHILD_DRV_NAME	"mdio-mux-bus-drv"
16 
17 /**
18  * struct mdio_mux_perdev_priv - Per-device class data for MDIO MUX DM
19  *
20  * @parent_mdio: Parent DM MDIO device, this is called for actual MDIO I/O after
21  *               setting up the mux.  Typically this is a real MDIO device,
22  *               unless there are cascaded muxes.
23  * @selected:    Current child bus selection.  Defaults to -1
24  */
25 struct mdio_mux_perdev_priv {
26 	struct udevice *mdio_parent;
27 	int selected;
28 };
29 
30 /*
31  * This source file uses three types of devices, as follows:
32  * - mux is the hardware MDIO MUX which selects between the existing child MDIO
33  * buses, this is the device relevant for MDIO MUX class of drivers.
34  * - ch is a child MDIO bus, this is just a representation of a mux selection,
35  * not a real piece of hardware.
36  * - mdio_parent is the actual MDIO bus called to perform reads/writes after
37  * the MUX is configured.  Typically this is a real MDIO device, unless there
38  * are cascaded muxes.
39  */
40 
41 /**
42  * struct mdio_mux_ch_data - Per-device data for child MDIOs
43  *
44  * @sel: Selection value used by the MDIO MUX to access this child MDIO bus
45  */
46 struct mdio_mux_ch_data {
47 	int sel;
48 };
49 
mmux_get_parent_mdio(struct udevice * mux)50 static struct udevice *mmux_get_parent_mdio(struct udevice *mux)
51 {
52 	struct mdio_mux_perdev_priv *pdata = dev_get_uclass_priv(mux);
53 
54 	return pdata->mdio_parent;
55 }
56 
mmux_get_mdio_parent_ops(struct udevice * mux)57 static struct mdio_ops *mmux_get_mdio_parent_ops(struct udevice *mux)
58 {
59 	return mdio_get_ops(mmux_get_parent_mdio(mux));
60 }
61 
62 /* call driver select function before performing MDIO r/w */
mmux_change_sel(struct udevice * ch,bool sel)63 static int mmux_change_sel(struct udevice *ch, bool sel)
64 {
65 	struct udevice *mux = ch->parent;
66 	struct mdio_mux_perdev_priv *priv = dev_get_uclass_priv(mux);
67 	struct mdio_mux_ops *ops = mdio_mux_get_ops(mux);
68 	struct mdio_mux_ch_data *ch_data = dev_get_parent_plat(ch);
69 	int err = 0;
70 
71 	if (sel) {
72 		err = ops->select(mux, priv->selected, ch_data->sel);
73 		if (err)
74 			return err;
75 
76 		priv->selected = ch_data->sel;
77 	} else {
78 		if (ops->deselect) {
79 			ops->deselect(mux, ch_data->sel);
80 			priv->selected = MDIO_MUX_SELECT_NONE;
81 		}
82 	}
83 
84 	return 0;
85 }
86 
87 /* Read wrapper, sets up the mux before issuing a read on parent MDIO bus */
mmux_read(struct udevice * ch,int addr,int devad,int reg)88 static int mmux_read(struct udevice *ch, int addr, int devad,
89 		     int reg)
90 {
91 	struct udevice *mux = ch->parent;
92 	struct udevice *parent_mdio = mmux_get_parent_mdio(mux);
93 	struct mdio_ops *parent_ops = mmux_get_mdio_parent_ops(mux);
94 	int err;
95 
96 	err = mmux_change_sel(ch, true);
97 	if (err)
98 		return err;
99 
100 	err = parent_ops->read(parent_mdio, addr, devad, reg);
101 	mmux_change_sel(ch, false);
102 
103 	return err;
104 }
105 
106 /* Write wrapper, sets up the mux before issuing a write on parent MDIO bus */
mmux_write(struct udevice * ch,int addr,int devad,int reg,u16 val)107 static int mmux_write(struct udevice *ch, int addr, int devad,
108 		      int reg, u16 val)
109 {
110 	struct udevice *mux = ch->parent;
111 	struct udevice *parent_mdio = mmux_get_parent_mdio(mux);
112 	struct mdio_ops *parent_ops = mmux_get_mdio_parent_ops(mux);
113 	int err;
114 
115 	err = mmux_change_sel(ch, true);
116 	if (err)
117 		return err;
118 
119 	err = parent_ops->write(parent_mdio, addr, devad, reg, val);
120 	mmux_change_sel(ch, false);
121 
122 	return err;
123 }
124 
125 /* Reset wrapper, sets up the mux before issuing a reset on parent MDIO bus */
mmux_reset(struct udevice * ch)126 static int mmux_reset(struct udevice *ch)
127 {
128 	struct udevice *mux = ch->parent;
129 	struct udevice *parent_mdio = mmux_get_parent_mdio(mux);
130 	struct mdio_ops *parent_ops = mmux_get_mdio_parent_ops(mux);
131 	int err;
132 
133 	/* reset is optional, if it's not implemented just exit */
134 	if (!parent_ops->reset)
135 		return 0;
136 
137 	err = mmux_change_sel(ch, true);
138 	if (err)
139 		return err;
140 
141 	err = parent_ops->reset(parent_mdio);
142 	mmux_change_sel(ch, false);
143 
144 	return err;
145 }
146 
147 /* Picks up the mux selection value for each child */
dm_mdio_mux_child_post_bind(struct udevice * ch)148 static int dm_mdio_mux_child_post_bind(struct udevice *ch)
149 {
150 	struct mdio_mux_ch_data *ch_data = dev_get_parent_plat(ch);
151 
152 	ch_data->sel = dev_read_u32_default(ch, "reg", MDIO_MUX_SELECT_NONE);
153 
154 	if (ch_data->sel == MDIO_MUX_SELECT_NONE)
155 		return -EINVAL;
156 
157 	return 0;
158 }
159 
160 /* Explicitly bind child MDIOs after binding the mux */
dm_mdio_mux_post_bind(struct udevice * mux)161 static int dm_mdio_mux_post_bind(struct udevice *mux)
162 {
163 	ofnode ch_node;
164 	int err, first_err = 0;
165 
166 	if (!dev_has_ofnode(mux)) {
167 		debug("%s: no mux node found, no child MDIO busses set up\n",
168 		      __func__);
169 		return 0;
170 	}
171 
172 	/*
173 	 * we're going by Linux bindings so the child nodes do not have
174 	 * compatible strings.  We're going through them here and binding to
175 	 * them.
176 	 */
177 	dev_for_each_subnode(ch_node, mux) {
178 		struct udevice *ch_dev;
179 		const char *ch_name;
180 
181 		ch_name = ofnode_get_name(ch_node);
182 
183 		err = device_bind_driver_to_node(mux, MDIO_MUX_CHILD_DRV_NAME,
184 						 ch_name, ch_node, &ch_dev);
185 		/* try to bind all, but keep 1st error */
186 		if (err && !first_err)
187 			first_err = err;
188 	}
189 
190 	return first_err;
191 }
192 
193 /* Get a reference to the parent MDIO bus, it should be bound by now */
dm_mdio_mux_post_probe(struct udevice * mux)194 static int dm_mdio_mux_post_probe(struct udevice *mux)
195 {
196 	struct mdio_mux_perdev_priv *priv = dev_get_uclass_priv(mux);
197 	int err;
198 
199 	priv->selected = MDIO_MUX_SELECT_NONE;
200 
201 	/* pick up mdio parent from device tree */
202 	err = uclass_get_device_by_phandle(UCLASS_MDIO, mux, "mdio-parent-bus",
203 					   &priv->mdio_parent);
204 	if (err) {
205 		debug("%s: didn't find mdio-parent-bus\n", __func__);
206 		return err;
207 	}
208 
209 	return 0;
210 }
211 
212 const struct mdio_ops mmux_child_mdio_ops = {
213 	.read = mmux_read,
214 	.write = mmux_write,
215 	.reset = mmux_reset,
216 };
217 
218 /* MDIO class driver used for MUX child MDIO buses */
219 U_BOOT_DRIVER(mdio_mux_child) = {
220 	.name		= MDIO_MUX_CHILD_DRV_NAME,
221 	.id		= UCLASS_MDIO,
222 	.ops		= &mmux_child_mdio_ops,
223 };
224 
225 UCLASS_DRIVER(mdio_mux) = {
226 	.id = UCLASS_MDIO_MUX,
227 	.name = "mdio-mux",
228 	.child_post_bind = dm_mdio_mux_child_post_bind,
229 	.post_bind  = dm_mdio_mux_post_bind,
230 	.post_probe = dm_mdio_mux_post_probe,
231 	.per_device_auto	= sizeof(struct mdio_mux_perdev_priv),
232 	.per_child_plat_auto	= sizeof(struct mdio_mux_ch_data),
233 };
234