blob: 664643486a0fa5a7bc9671a5664afe919bfa0b0b [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Dirk Eibachf74a0272014-11-13 19:21:18 +01002/*
3 * (C) Copyright 2014
Mario Sixb4893582018-03-06 08:04:58 +01004 * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
Dirk Eibachf74a0272014-11-13 19:21:18 +01005 */
6
7#include <common.h>
8
9#include <gdsys_fpga.h>
10#include <miiphy.h>
11
12#include "ihs_mdio.h"
13
Mario Six9a95ba62018-04-27 14:52:09 +020014static inline u16 read_control(struct ihs_mdio_info *info)
15{
16 u16 val;
17
18 FPGA_GET_REG(info->fpga, mdio.control, &val);
19
20 return val;
21}
22
23static inline void write_control(struct ihs_mdio_info *info, u16 val)
24{
25 FPGA_SET_REG(info->fpga, mdio.control, val);
26}
27
28static inline void write_addr_data(struct ihs_mdio_info *info, u16 val)
29{
30 FPGA_SET_REG(info->fpga, mdio.address_data, val);
31}
32
33static inline u16 read_rx_data(struct ihs_mdio_info *info)
34{
35 u16 val;
36
37 FPGA_GET_REG(info->fpga, mdio.rx_data, &val);
38
39 return val;
40}
41
Dirk Eibachf74a0272014-11-13 19:21:18 +010042static int ihs_mdio_idle(struct mii_dev *bus)
43{
44 struct ihs_mdio_info *info = bus->priv;
45 u16 val;
46 unsigned int ctr = 0;
47
48 do {
Mario Six9a95ba62018-04-27 14:52:09 +020049 val = read_control(info);
Dirk Eibachf74a0272014-11-13 19:21:18 +010050 udelay(100);
51 if (ctr++ > 10)
52 return -1;
53 } while (!(val & (1 << 12)));
54
55 return 0;
56}
57
58static int ihs_mdio_reset(struct mii_dev *bus)
59{
60 ihs_mdio_idle(bus);
61
62 return 0;
63}
64
65static int ihs_mdio_read(struct mii_dev *bus, int addr, int dev_addr,
66 int regnum)
67{
68 struct ihs_mdio_info *info = bus->priv;
69 u16 val;
70
71 ihs_mdio_idle(bus);
72
Mario Six9a95ba62018-04-27 14:52:09 +020073 write_control(info,
74 ((addr & 0x1f) << 5) | (regnum & 0x1f) | (2 << 10));
Dirk Eibachf74a0272014-11-13 19:21:18 +010075
76 /* wait for rx data available */
77 udelay(100);
78
Mario Six9a95ba62018-04-27 14:52:09 +020079 val = read_rx_data(info);
Dirk Eibachf74a0272014-11-13 19:21:18 +010080
81 return val;
82}
83
84static int ihs_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
85 int regnum, u16 value)
86{
87 struct ihs_mdio_info *info = bus->priv;
88
89 ihs_mdio_idle(bus);
90
Mario Six9a95ba62018-04-27 14:52:09 +020091 write_addr_data(info, value);
92 write_control(info, ((addr & 0x1f) << 5) | (regnum & 0x1f) | (1 << 10));
Dirk Eibachf74a0272014-11-13 19:21:18 +010093
94 return 0;
95}
96
97int ihs_mdio_init(struct ihs_mdio_info *info)
98{
99 struct mii_dev *bus = mdio_alloc();
100
101 if (!bus) {
102 printf("Failed to allocate FSL MDIO bus\n");
103 return -1;
104 }
105
106 bus->read = ihs_mdio_read;
107 bus->write = ihs_mdio_write;
108 bus->reset = ihs_mdio_reset;
Ben Whitten34fd6c92015-12-30 13:05:58 +0000109 strcpy(bus->name, info->name);
Dirk Eibachf74a0272014-11-13 19:21:18 +0100110
111 bus->priv = info;
112
113 return mdio_register(bus);
114}