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