1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <config.h>
25#include <common.h>
26#include <miiphy.h>
27#include <phy.h>
28#include <malloc.h>
29#include <asm/io.h>
30
31#include "xilinx_ll_temac.h"
32#include "xilinx_ll_temac_mdio.h"
33
34#if !defined(CONFIG_MII)
35# error "LL_TEMAC requires MII -- missing CONFIG_MII"
36#endif
37
38#if !defined(CONFIG_PHYLIB)
39# error "LL_TEMAC requires PHYLIB -- missing CONFIG_PHYLIB"
40#endif
41
42
43
44
45
46
47
48
49#if !defined(CONFIG_XILINX_LL_TEMAC_CLK)
50#define MDIO_CLOCK_DIV MC_CLKDIV_10(150000000)
51#else
52#define MDIO_CLOCK_DIV MC_CLKDIV_25(CONFIG_XILINX_LL_TEMAC_CLK)
53#endif
54
55static int ll_temac_mdio_setup(struct mii_dev *bus)
56{
57 struct temac_reg *regs = (struct temac_reg *)bus->priv;
58
59
60 ll_temac_indirect_set(regs, TEMAC_MC,
61 MC_MDIOEN | (MDIO_CLOCK_DIV & MC_CLKDIV_MASK));
62
63 return 0;
64}
65
66
67
68
69
70
71
72int ll_temac_local_mdio_read(struct temac_reg *regs, int addr, int devad,
73 int regnum)
74{
75 out_be32(®s->lsw,
76 ((addr << LSW_PHYAD_POS) & LSW_PHYAD_MASK) |
77 (regnum & LSW_REGAD_MASK));
78 out_be32(®s->ctl, TEMAC_MIIMAI);
79
80 ll_temac_check_status(regs, RSE_MIIM_RR);
81
82 return in_be32(®s->lsw) & LSW_REGDAT_MASK;
83}
84
85
86
87
88
89
90
91void ll_temac_local_mdio_write(struct temac_reg *regs, int addr, int devad,
92 int regnum, u16 value)
93{
94 out_be32(®s->lsw, (value & LSW_REGDAT_MASK));
95 out_be32(®s->ctl, CTL_WEN | TEMAC_MIIMWD);
96
97 out_be32(®s->lsw,
98 ((addr << LSW_PHYAD_POS) & LSW_PHYAD_MASK) |
99 (regnum & LSW_REGAD_MASK));
100 out_be32(®s->ctl, CTL_WEN | TEMAC_MIIMAI);
101
102 ll_temac_check_status(regs, RSE_MIIM_WR);
103}
104
105int ll_temac_phy_read(struct mii_dev *bus, int addr, int devad, int regnum)
106{
107 struct temac_reg *regs = (struct temac_reg *)bus->priv;
108
109 return ll_temac_local_mdio_read(regs, addr, devad, regnum);
110}
111
112int ll_temac_phy_write(struct mii_dev *bus, int addr, int devad, int regnum,
113 u16 value)
114{
115 struct temac_reg *regs = (struct temac_reg *)bus->priv;
116
117 ll_temac_local_mdio_write(regs, addr, devad, regnum, value);
118
119 return 0;
120}
121
122
123
124
125
126
127
128
129#define PHY_DETECT_REG MII_BMSR
130#define PHY_DETECT_MASK (BMSR_10FULL | BMSR_10HALF | BMSR_ANEGCAPABLE)
131
132
133int ll_temac_phy_addr(struct mii_dev *bus)
134{
135 struct temac_reg *regs = (struct temac_reg *)bus->priv;
136 unsigned short val;
137 unsigned int phy;
138
139 for (phy = PHY_MAX_ADDR; phy >= 0; phy--) {
140 val = ll_temac_local_mdio_read(regs, phy, 0, PHY_DETECT_REG);
141 if ((val != 0xFFFF) &&
142 ((val & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
143
144 return phy;
145 }
146 }
147
148 return -1;
149}
150
151int xilinx_ll_temac_mdio_initialize(bd_t *bis, struct ll_temac_mdio_info *info)
152{
153 struct mii_dev *bus = mdio_alloc();
154
155 if (!bus) {
156 printf("Failed to allocate LL_TEMAC MDIO bus: %s\n",
157 info->name);
158 return -1;
159 }
160
161 bus->read = ll_temac_phy_read;
162 bus->write = ll_temac_phy_write;
163 bus->reset = NULL;
164
165
166 if (info->name) {
167 strncpy(bus->name, info->name, MDIO_NAME_LEN);
168 } else {
169 snprintf(bus->name, MDIO_NAME_LEN, "lltemii.%p", info->regs);
170 info->name = bus->name;
171 }
172
173 bus->priv = info->regs;
174
175 ll_temac_mdio_setup(bus);
176 return mdio_register(bus);
177}
178