1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2014 4 * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc 5 */ 6 7 #include <common.h> 8 9 #include <miiphy.h> 10 #ifdef CONFIG_GDSYS_LEGACY_DRIVERS 11 #include <gdsys_fpga.h> 12 #else 13 #include <fdtdec.h> 14 #include <regmap.h> 15 #endif 16 17 #include "ihs_mdio.h" 18 19 #ifndef CONFIG_GDSYS_LEGACY_DRIVERS 20 enum { 21 REG_MDIO_CONTROL = 0x0, 22 REG_MDIO_ADDR_DATA = 0x2, 23 REG_MDIO_RX_DATA = 0x4, 24 }; 25 26 static inline u16 read_reg(struct udevice *fpga, uint base, uint addr) 27 { 28 struct regmap *map; 29 u8 *ptr; 30 31 regmap_init_mem(fpga, &map); 32 ptr = regmap_get_range(map, 0); 33 34 return in_le16((u16 *)(ptr + base + addr)); 35 } 36 37 static inline void write_reg(struct udevice *fpga, uint base, uint addr, 38 u16 val) 39 { 40 struct regmap *map; 41 u8 *ptr; 42 43 regmap_init_mem(fpga, &map); 44 ptr = regmap_get_range(map, 0); 45 46 out_le16((u16 *)(ptr + base + addr), val); 47 } 48 #endif 49 50 static inline u16 read_control(struct ihs_mdio_info *info) 51 { 52 u16 val; 53 #ifdef CONFIG_GDSYS_LEGACY_DRIVERS 54 FPGA_GET_REG(info->fpga, mdio.control, &val); 55 #else 56 val = read_reg(info->fpga, info->base, REG_MDIO_CONTROL); 57 #endif 58 return val; 59 } 60 61 static inline void write_control(struct ihs_mdio_info *info, u16 val) 62 { 63 #ifdef CONFIG_GDSYS_LEGACY_DRIVERS 64 FPGA_SET_REG(info->fpga, mdio.control, val); 65 #else 66 write_reg(info->fpga, info->base, REG_MDIO_CONTROL, val); 67 #endif 68 } 69 70 static inline void write_addr_data(struct ihs_mdio_info *info, u16 val) 71 { 72 #ifdef CONFIG_GDSYS_LEGACY_DRIVERS 73 FPGA_SET_REG(info->fpga, mdio.address_data, val); 74 #else 75 write_reg(info->fpga, info->base, REG_MDIO_ADDR_DATA, val); 76 #endif 77 } 78 79 static inline u16 read_rx_data(struct ihs_mdio_info *info) 80 { 81 u16 val; 82 #ifdef CONFIG_GDSYS_LEGACY_DRIVERS 83 FPGA_GET_REG(info->fpga, mdio.rx_data, &val); 84 #else 85 val = read_reg(info->fpga, info->base, REG_MDIO_RX_DATA); 86 #endif 87 return val; 88 } 89 90 static int ihs_mdio_idle(struct mii_dev *bus) 91 { 92 struct ihs_mdio_info *info = bus->priv; 93 u16 val; 94 unsigned int ctr = 0; 95 96 do { 97 val = read_control(info); 98 udelay(100); 99 if (ctr++ > 10) 100 return -1; 101 } while (!(val & (1 << 12))); 102 103 return 0; 104 } 105 106 static int ihs_mdio_reset(struct mii_dev *bus) 107 { 108 ihs_mdio_idle(bus); 109 110 return 0; 111 } 112 113 static int ihs_mdio_read(struct mii_dev *bus, int addr, int dev_addr, 114 int regnum) 115 { 116 struct ihs_mdio_info *info = bus->priv; 117 u16 val; 118 119 ihs_mdio_idle(bus); 120 121 write_control(info, 122 ((addr & 0x1f) << 5) | (regnum & 0x1f) | (2 << 10)); 123 124 /* wait for rx data available */ 125 udelay(100); 126 127 val = read_rx_data(info); 128 129 return val; 130 } 131 132 static int ihs_mdio_write(struct mii_dev *bus, int addr, int dev_addr, 133 int regnum, u16 value) 134 { 135 struct ihs_mdio_info *info = bus->priv; 136 137 ihs_mdio_idle(bus); 138 139 write_addr_data(info, value); 140 write_control(info, ((addr & 0x1f) << 5) | (regnum & 0x1f) | (1 << 10)); 141 142 return 0; 143 } 144 145 int ihs_mdio_init(struct ihs_mdio_info *info) 146 { 147 struct mii_dev *bus = mdio_alloc(); 148 149 if (!bus) { 150 printf("Failed to allocate FSL MDIO bus\n"); 151 return -1; 152 } 153 154 bus->read = ihs_mdio_read; 155 bus->write = ihs_mdio_write; 156 bus->reset = ihs_mdio_reset; 157 strcpy(bus->name, info->name); 158 159 bus->priv = info; 160 161 return mdio_register(bus); 162 } 163