Merge branch 'master' of git://git.denx.de/u-boot
[oweals/u-boot.git] / net / mdio-mux-uclass.c
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 <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
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 static struct mdio_ops *mmux_get_mdio_parent_ops(struct udevice *mux)
57 {
58         return mdio_get_ops(mmux_get_parent_mdio(mux));
59 }
60
61 /* call driver select function before performing MDIO r/w */
62 static int mmux_change_sel(struct udevice *ch, bool sel)
63 {
64         struct udevice *mux = ch->parent;
65         struct mdio_mux_perdev_priv *priv = dev_get_uclass_priv(mux);
66         struct mdio_mux_ops *ops = mdio_mux_get_ops(mux);
67         struct mdio_mux_ch_data *ch_data = dev_get_parent_platdata(ch);
68         int err = 0;
69
70         if (sel) {
71                 err = ops->select(mux, priv->selected, ch_data->sel);
72                 if (err)
73                         return err;
74
75                 priv->selected = ch_data->sel;
76         } else {
77                 if (ops->deselect) {
78                         ops->deselect(mux, ch_data->sel);
79                         priv->selected = MDIO_MUX_SELECT_NONE;
80                 }
81         }
82
83         return 0;
84 }
85
86 /* Read wrapper, sets up the mux before issuing a read on parent MDIO bus */
87 static int mmux_read(struct udevice *ch, int addr, int devad,
88                      int reg)
89 {
90         struct udevice *mux = ch->parent;
91         struct udevice *parent_mdio = mmux_get_parent_mdio(mux);
92         struct mdio_ops *parent_ops = mmux_get_mdio_parent_ops(mux);
93         int err;
94
95         err = mmux_change_sel(ch, true);
96         if (err)
97                 return err;
98
99         err = parent_ops->read(parent_mdio, addr, devad, reg);
100         mmux_change_sel(ch, false);
101
102         return err;
103 }
104
105 /* Write wrapper, sets up the mux before issuing a write on parent MDIO bus */
106 static int mmux_write(struct udevice *ch, int addr, int devad,
107                       int reg, u16 val)
108 {
109         struct udevice *mux = ch->parent;
110         struct udevice *parent_mdio = mmux_get_parent_mdio(mux);
111         struct mdio_ops *parent_ops = mmux_get_mdio_parent_ops(mux);
112         int err;
113
114         err = mmux_change_sel(ch, true);
115         if (err)
116                 return err;
117
118         err = parent_ops->write(parent_mdio, addr, devad, reg, val);
119         mmux_change_sel(ch, false);
120
121         return err;
122 }
123
124 /* Reset wrapper, sets up the mux before issuing a reset on parent MDIO bus */
125 static int mmux_reset(struct udevice *ch)
126 {
127         struct udevice *mux = ch->parent;
128         struct udevice *parent_mdio = mmux_get_parent_mdio(mux);
129         struct mdio_ops *parent_ops = mmux_get_mdio_parent_ops(mux);
130         int err;
131
132         /* reset is optional, if it's not implemented just exit */
133         if (!parent_ops->reset)
134                 return 0;
135
136         err = mmux_change_sel(ch, true);
137         if (err)
138                 return err;
139
140         err = parent_ops->reset(parent_mdio);
141         mmux_change_sel(ch, false);
142
143         return err;
144 }
145
146 /* Picks up the mux selection value for each child */
147 static int dm_mdio_mux_child_post_bind(struct udevice *ch)
148 {
149         struct mdio_mux_ch_data *ch_data = dev_get_parent_platdata(ch);
150
151         ch_data->sel = dev_read_u32_default(ch, "reg", MDIO_MUX_SELECT_NONE);
152
153         if (ch_data->sel == MDIO_MUX_SELECT_NONE)
154                 return -EINVAL;
155
156         return 0;
157 }
158
159 /* Explicitly bind child MDIOs after binding the mux */
160 static int dm_mdio_mux_post_bind(struct udevice *mux)
161 {
162         ofnode ch_node;
163         int err, first_err = 0;
164
165         if (!ofnode_valid(mux->node)) {
166                 debug("%s: no mux node found, no child MDIO busses set up\n",
167                       __func__);
168                 return 0;
169         }
170
171         /*
172          * we're going by Linux bindings so the child nodes do not have
173          * compatible strings.  We're going through them here and binding to
174          * them.
175          */
176         dev_for_each_subnode(ch_node, mux) {
177                 struct udevice *ch_dev;
178                 const char *ch_name;
179
180                 ch_name = ofnode_get_name(ch_node);
181
182                 err = device_bind_driver_to_node(mux, MDIO_MUX_CHILD_DRV_NAME,
183                                                  ch_name, ch_node, &ch_dev);
184                 /* try to bind all, but keep 1st error */
185                 if (err && !first_err)
186                         first_err = err;
187         }
188
189         return first_err;
190 }
191
192 /* Get a reference to the parent MDIO bus, it should be bound by now */
193 static int dm_mdio_mux_post_probe(struct udevice *mux)
194 {
195         struct mdio_mux_perdev_priv *priv = dev_get_uclass_priv(mux);
196         int err;
197
198         priv->selected = MDIO_MUX_SELECT_NONE;
199
200         /* pick up mdio parent from device tree */
201         err = uclass_get_device_by_phandle(UCLASS_MDIO, mux, "mdio-parent-bus",
202                                            &priv->mdio_parent);
203         if (err) {
204                 debug("%s: didn't find mdio-parent-bus\n", __func__);
205                 return err;
206         }
207
208         return 0;
209 }
210
211 const struct mdio_ops mmux_child_mdio_ops = {
212         .read = mmux_read,
213         .write = mmux_write,
214         .reset = mmux_reset,
215 };
216
217 /* MDIO class driver used for MUX child MDIO buses */
218 U_BOOT_DRIVER(mdio_mux_child) = {
219         .name           = MDIO_MUX_CHILD_DRV_NAME,
220         .id             = UCLASS_MDIO,
221         .ops            = &mmux_child_mdio_ops,
222 };
223
224 UCLASS_DRIVER(mdio_mux) = {
225         .id = UCLASS_MDIO_MUX,
226         .name = "mdio-mux",
227         .child_post_bind = dm_mdio_mux_child_post_bind,
228         .post_bind  = dm_mdio_mux_post_bind,
229         .post_probe = dm_mdio_mux_post_probe,
230         .per_device_auto_alloc_size = sizeof(struct mdio_mux_perdev_priv),
231         .per_child_platdata_auto_alloc_size = sizeof(struct mdio_mux_ch_data),
232 };