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