1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
// SPDX-License-Identifier: GPL-2.0-only
/* Renesas Multi-Protocol PHY device driver
*
* Copyright (C) 2025 Renesas Electronics Corporation
*/
#include <asm/io.h>
#include <clk.h>
#include <dm.h>
#include <dm/device_compat.h>
#include <generic-phy.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <reset.h>
/* Common registers */
#define MPPHY_CMNCNT1 0x80000
#define MPPHY_CMNCNT2 0x80004
#define MPPHY_PCS0REG1 0x85000
#define MPPHY_PCS0REG5 0x85010
/* Channel register base and offsets */
#define MPPHY_CHAN_BASE(ch) (0x81000 + (ch) * 0x1000)
#define MPPHY_PXTEST_OFFSET 0x00C
#define MPPHY_RXCNT_OFFSET 0x038
#define MPPHY_SRAMCNT_OFFSET 0x040
#define MPPHY_REFCLK_OFFSET 0x014
#define MPPHY_CNTXT1_OFFSET 0x004
#define MPPHY_CNTXT2_OFFSET 0x008
#define MPPHY_TXREQ_OFFSET 0x044
/* Channel specific registers */
#define MPPHY_PXTEST(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_PXTEST_OFFSET)
#define MPPHY_PXRXCNT(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_RXCNT_OFFSET)
#define MPPHY_PXSRAMCNT(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_SRAMCNT_OFFSET)
#define MPPHY_PXREFCLK(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_REFCLK_OFFSET)
#define MPPHY_PXCNTXT1(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_CNTXT1_OFFSET)
#define MPPHY_PXCNTXT2(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_CNTXT2_OFFSET)
#define MPPHY_PXTXREQ(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_TXREQ_OFFSET)
/* Channel enable bit masks for MPPHY_CMNCNT1 register */
#define MPPHY_CMNCNT1_CH_MASK(ch) (0xFF << ((ch) * 8))
/* Channel enable bits for MPPHY_CMNCNT1 register */
#define MPPHY_CMNCNT1_CH_EN(ch) ((ch) == 0 ? BIT(1) : BIT((ch) * 8))
/* PCS0REG5 register mask and values for each channel */
#define MPPHY_PCS0REG5_CH(ch) (0x03 << (24 + (ch) * 2))
/* PCS0REG1 register bits */
#define MPPHY_PCS0REG1_VAL 0x00010000
/* PXTEST register bit */
#define MPPHY_PXTEST_BIT BIT(0)
/* PXRXCNT register reset value */
#define MPPHY_PXRXCNT_RESET_VAL 0x202
/* PXSRAMCNT register bits */
#define MPPHY_PXSRAMCNT_BYPASS BIT(0)
#define MPPHY_PXSRAMCNT_BIT3 BIT(3)
#define BOOTLOAD_BYPASS_MODE 0x3
#define SRAM_BYPASS_MODE 0xc
#define SRAM_EXT_LD_DONE 0x10
#define SRAM_INIT_DONE 0x20
#define SRAM_CONTROL_SET_BIT \
(BOOTLOAD_BYPASS_MODE | SRAM_BYPASS_MODE | \
SRAM_EXT_LD_DONE | SRAM_INIT_DONE)
/* CMNCNT1/2 clock settings */
#define MPPHY_CMNCNT2_CLK_CH(ch) (0x30003 << ((ch) * 4))
/* PXREFCLK register value */
#define MPPHY_PXREFCLK_VAL 0x35
/* PXTXREQ register value */
#define MPPHY_PXTXREQ_VAL 0x8
/* Context settings */
#define MPPHY_CNTXT1_VALUE 0x02010002
#define MPPHY_CNTXT2_VALUE 0x02020202 /* For channels 1-3 */
#define MPPHY_CNTXT2_CH0_VALUE 0x02020201 /* Special for channel 0 */
/* struct mpphy_priv - Private data for the MPPHY driver */
struct mp_phy_priv {
struct phy *phy;
struct clk_bulk clks;
struct reset_ctl_bulk resets;
void __iomem *base;
};
static int mp_phy_init(struct phy *phy)
{
struct mp_phy_priv *priv = dev_get_priv(phy->dev);
if (phy->id > 3) {
printf("Invalid channel ID: %ld\n", phy->id);
return -EINVAL;
}
clrsetbits_le32(priv->base + MPPHY_CMNCNT1, MPPHY_CMNCNT1_CH_MASK(phy->id),
MPPHY_CMNCNT1_CH_EN(phy->id));
setbits_le32(priv->base + MPPHY_PCS0REG5, MPPHY_PCS0REG5_CH(phy->id));
setbits_le32(priv->base + MPPHY_PCS0REG1, MPPHY_PCS0REG1_VAL);
setbits_le32(priv->base + MPPHY_PXTEST(phy->id), MPPHY_PXTEST_BIT);
clrbits_le32(priv->base + MPPHY_PCS0REG5, MPPHY_PCS0REG5_CH(phy->id));
clrbits_le32(priv->base + MPPHY_PCS0REG1, MPPHY_PCS0REG1_VAL);
clrbits_le32(priv->base + MPPHY_PXTEST(phy->id), MPPHY_PXTEST_BIT);
/* Set PHY RX/TX reset and SRAM bypass mode */
writel(MPPHY_PXRXCNT_RESET_VAL, priv->base + MPPHY_PXRXCNT(phy->id));
writel(MPPHY_PXSRAMCNT_BYPASS, priv->base + MPPHY_PXSRAMCNT(phy->id));
setbits_le32(priv->base + MPPHY_PXSRAMCNT(phy->id), MPPHY_PXSRAMCNT_BIT3);
/* Clock supply settings */
setbits_le32(priv->base + MPPHY_CMNCNT2, MPPHY_CMNCNT2_CLK_CH(phy->id));
setbits_le32(priv->base + MPPHY_PXREFCLK(phy->id), MPPHY_PXREFCLK_VAL);
/* Release PHY RX/TX reset */
writel(0x0, priv->base + MPPHY_PXRXCNT(phy->id));
/* Setting Context Restore Registers and select PHY2/PHY3 protocol */
writel(MPPHY_CNTXT1_VALUE, priv->base + MPPHY_PXCNTXT1(phy->id));
writel((phy->id == 0) ? MPPHY_CNTXT2_CH0_VALUE : MPPHY_CNTXT2_VALUE,
priv->base + MPPHY_PXCNTXT2(phy->id));
writel(MPPHY_PXTXREQ_VAL, priv->base + MPPHY_PXTXREQ(phy->id));
return 0;
}
static int mp_phy_late_init(struct phy *phy)
{
struct mp_phy_priv *priv = dev_get_priv(phy->dev);
writel(SRAM_CONTROL_SET_BIT, priv->base + MPPHY_PXSRAMCNT(phy->id));
return 0;
}
static int mp_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
{
/* Current source code only supports Ethernet */
if (mode != PHY_MODE_ETHERNET)
return -EOPNOTSUPP;
return 0;
}
static int mp_phy_of_xlate(struct phy *phy, struct ofnode_phandle_args *args)
{
if (args->args_count > 2)
return -EINVAL;
/* Set channel ID from first argument if available */
if (args->args_count)
phy->id = args->args[0];
else
phy->id = 0;
return 0;
}
static const struct phy_ops mp_phy_ops = {
.init = mp_phy_init,
.power_on = mp_phy_late_init,
.set_mode = mp_phy_set_mode,
.of_xlate = mp_phy_of_xlate,
};
static int mp_phy_probe(struct udevice *dev)
{
struct mp_phy_priv *priv = dev_get_priv(dev);
int ret;
/* Get base address from device tree */
priv->base = dev_read_addr_ptr(dev);
if (!priv->base)
return -EINVAL;
ret = clk_get_bulk(dev, &priv->clks);
if (ret < 0)
return ret;
ret = clk_enable_bulk(&priv->clks);
if (ret)
goto err_clk_enable;
ret = reset_get_bulk(dev, &priv->resets);
if (ret)
goto err_reset_get;
ret = reset_assert_bulk(&priv->resets);
if (ret)
goto err_reset_assert;
ret = reset_deassert_bulk(&priv->resets);
if (ret)
goto err_reset_assert;
return 0;
err_reset_assert:
reset_release_bulk(&priv->resets);
err_reset_get:
clk_disable_bulk(&priv->clks);
err_clk_enable:
clk_release_bulk(&priv->clks);
return ret;
}
static const struct udevice_id mp_phy_ids[] = {
{ .compatible = "renesas,r8a78000-multi-protocol-phy" },
{ }
};
U_BOOT_DRIVER(renesas_mpphy) = {
.name = "renesas_mpphy",
.id = UCLASS_PHY,
.of_match = mp_phy_ids,
.probe = mp_phy_probe,
.ops = &mp_phy_ops,
.priv_auto = sizeof(struct mp_phy_priv),
};
|