cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mdio-bitbang.c (5725B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Bitbanged MDIO support.
      4 *
      5 * Author: Scott Wood <scottwood@freescale.com>
      6 * Copyright (c) 2007 Freescale Semiconductor
      7 *
      8 * Based on CPM2 MDIO code which is:
      9 *
     10 * Copyright (c) 2003 Intracom S.A.
     11 *  by Pantelis Antoniou <panto@intracom.gr>
     12 *
     13 * 2005 (c) MontaVista Software, Inc.
     14 * Vitaly Bordug <vbordug@ru.mvista.com>
     15 */
     16
     17#include <linux/delay.h>
     18#include <linux/mdio-bitbang.h>
     19#include <linux/module.h>
     20#include <linux/types.h>
     21
     22#define MDIO_READ 2
     23#define MDIO_WRITE 1
     24
     25#define MDIO_C45 (1<<15)
     26#define MDIO_C45_ADDR (MDIO_C45 | 0)
     27#define MDIO_C45_READ (MDIO_C45 | 3)
     28#define MDIO_C45_WRITE (MDIO_C45 | 1)
     29
     30#define MDIO_SETUP_TIME 10
     31#define MDIO_HOLD_TIME 10
     32
     33/* Minimum MDC period is 400 ns, plus some margin for error.  MDIO_DELAY
     34 * is done twice per period.
     35 */
     36#define MDIO_DELAY 250
     37
     38/* The PHY may take up to 300 ns to produce data, plus some margin
     39 * for error.
     40 */
     41#define MDIO_READ_DELAY 350
     42
     43/* MDIO must already be configured as output. */
     44static void mdiobb_send_bit(struct mdiobb_ctrl *ctrl, int val)
     45{
     46	const struct mdiobb_ops *ops = ctrl->ops;
     47
     48	ops->set_mdio_data(ctrl, val);
     49	ndelay(MDIO_DELAY);
     50	ops->set_mdc(ctrl, 1);
     51	ndelay(MDIO_DELAY);
     52	ops->set_mdc(ctrl, 0);
     53}
     54
     55/* MDIO must already be configured as input. */
     56static int mdiobb_get_bit(struct mdiobb_ctrl *ctrl)
     57{
     58	const struct mdiobb_ops *ops = ctrl->ops;
     59
     60	ndelay(MDIO_DELAY);
     61	ops->set_mdc(ctrl, 1);
     62	ndelay(MDIO_READ_DELAY);
     63	ops->set_mdc(ctrl, 0);
     64
     65	return ops->get_mdio_data(ctrl);
     66}
     67
     68/* MDIO must already be configured as output. */
     69static void mdiobb_send_num(struct mdiobb_ctrl *ctrl, u16 val, int bits)
     70{
     71	int i;
     72
     73	for (i = bits - 1; i >= 0; i--)
     74		mdiobb_send_bit(ctrl, (val >> i) & 1);
     75}
     76
     77/* MDIO must already be configured as input. */
     78static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits)
     79{
     80	int i;
     81	u16 ret = 0;
     82
     83	for (i = bits - 1; i >= 0; i--) {
     84		ret <<= 1;
     85		ret |= mdiobb_get_bit(ctrl);
     86	}
     87
     88	return ret;
     89}
     90
     91/* Utility to send the preamble, address, and
     92 * register (common to read and write).
     93 */
     94static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int op, u8 phy, u8 reg)
     95{
     96	const struct mdiobb_ops *ops = ctrl->ops;
     97	int i;
     98
     99	ops->set_mdio_dir(ctrl, 1);
    100
    101	/*
    102	 * Send a 32 bit preamble ('1's) with an extra '1' bit for good
    103	 * measure.  The IEEE spec says this is a PHY optional
    104	 * requirement.  The AMD 79C874 requires one after power up and
    105	 * one after a MII communications error.  This means that we are
    106	 * doing more preambles than we need, but it is safer and will be
    107	 * much more robust.
    108	 */
    109
    110	for (i = 0; i < 32; i++)
    111		mdiobb_send_bit(ctrl, 1);
    112
    113	/* send the start bit (01) and the read opcode (10) or write (01).
    114	   Clause 45 operation uses 00 for the start and 11, 10 for
    115	   read/write */
    116	mdiobb_send_bit(ctrl, 0);
    117	if (op & MDIO_C45)
    118		mdiobb_send_bit(ctrl, 0);
    119	else
    120		mdiobb_send_bit(ctrl, 1);
    121	mdiobb_send_bit(ctrl, (op >> 1) & 1);
    122	mdiobb_send_bit(ctrl, (op >> 0) & 1);
    123
    124	mdiobb_send_num(ctrl, phy, 5);
    125	mdiobb_send_num(ctrl, reg, 5);
    126}
    127
    128/* In clause 45 mode all commands are prefixed by MDIO_ADDR to specify the
    129   lower 16 bits of the 21 bit address. This transfer is done identically to a
    130   MDIO_WRITE except for a different code. To enable clause 45 mode or
    131   MII_ADDR_C45 into the address. Theoretically clause 45 and normal devices
    132   can exist on the same bus. Normal devices should ignore the MDIO_ADDR
    133   phase. */
    134static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr)
    135{
    136	unsigned int dev_addr = (addr >> 16) & 0x1F;
    137	unsigned int reg = addr & 0xFFFF;
    138	mdiobb_cmd(ctrl, MDIO_C45_ADDR, phy, dev_addr);
    139
    140	/* send the turnaround (10) */
    141	mdiobb_send_bit(ctrl, 1);
    142	mdiobb_send_bit(ctrl, 0);
    143
    144	mdiobb_send_num(ctrl, reg, 16);
    145
    146	ctrl->ops->set_mdio_dir(ctrl, 0);
    147	mdiobb_get_bit(ctrl);
    148
    149	return dev_addr;
    150}
    151
    152int mdiobb_read(struct mii_bus *bus, int phy, int reg)
    153{
    154	struct mdiobb_ctrl *ctrl = bus->priv;
    155	int ret, i;
    156
    157	if (reg & MII_ADDR_C45) {
    158		reg = mdiobb_cmd_addr(ctrl, phy, reg);
    159		mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
    160	} else
    161		mdiobb_cmd(ctrl, ctrl->op_c22_read, phy, reg);
    162
    163	ctrl->ops->set_mdio_dir(ctrl, 0);
    164
    165	/* check the turnaround bit: the PHY should be driving it to zero, if this
    166	 * PHY is listed in phy_ignore_ta_mask as having broken TA, skip that
    167	 */
    168	if (mdiobb_get_bit(ctrl) != 0 &&
    169	    !(bus->phy_ignore_ta_mask & (1 << phy))) {
    170		/* PHY didn't drive TA low -- flush any bits it
    171		 * may be trying to send.
    172		 */
    173		for (i = 0; i < 32; i++)
    174			mdiobb_get_bit(ctrl);
    175
    176		return 0xffff;
    177	}
    178
    179	ret = mdiobb_get_num(ctrl, 16);
    180	mdiobb_get_bit(ctrl);
    181	return ret;
    182}
    183EXPORT_SYMBOL(mdiobb_read);
    184
    185int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
    186{
    187	struct mdiobb_ctrl *ctrl = bus->priv;
    188
    189	if (reg & MII_ADDR_C45) {
    190		reg = mdiobb_cmd_addr(ctrl, phy, reg);
    191		mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
    192	} else
    193		mdiobb_cmd(ctrl, ctrl->op_c22_write, phy, reg);
    194
    195	/* send the turnaround (10) */
    196	mdiobb_send_bit(ctrl, 1);
    197	mdiobb_send_bit(ctrl, 0);
    198
    199	mdiobb_send_num(ctrl, val, 16);
    200
    201	ctrl->ops->set_mdio_dir(ctrl, 0);
    202	mdiobb_get_bit(ctrl);
    203	return 0;
    204}
    205EXPORT_SYMBOL(mdiobb_write);
    206
    207struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
    208{
    209	struct mii_bus *bus;
    210
    211	bus = mdiobus_alloc();
    212	if (!bus)
    213		return NULL;
    214
    215	__module_get(ctrl->ops->owner);
    216
    217	bus->read = mdiobb_read;
    218	bus->write = mdiobb_write;
    219	bus->priv = ctrl;
    220	if (!ctrl->override_op_c22) {
    221		ctrl->op_c22_read = MDIO_READ;
    222		ctrl->op_c22_write = MDIO_WRITE;
    223	}
    224
    225	return bus;
    226}
    227EXPORT_SYMBOL(alloc_mdio_bitbang);
    228
    229void free_mdio_bitbang(struct mii_bus *bus)
    230{
    231	struct mdiobb_ctrl *ctrl = bus->priv;
    232
    233	module_put(ctrl->ops->owner);
    234	mdiobus_free(bus);
    235}
    236EXPORT_SYMBOL(free_mdio_bitbang);
    237
    238MODULE_LICENSE("GPL v2");