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