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

qsemi.c (4084B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * drivers/net/phy/qsemi.c
      4 *
      5 * Driver for Quality Semiconductor PHYs
      6 *
      7 * Author: Andy Fleming
      8 *
      9 * Copyright (c) 2004 Freescale Semiconductor, Inc.
     10 */
     11#include <linux/kernel.h>
     12#include <linux/string.h>
     13#include <linux/errno.h>
     14#include <linux/unistd.h>
     15#include <linux/interrupt.h>
     16#include <linux/init.h>
     17#include <linux/delay.h>
     18#include <linux/netdevice.h>
     19#include <linux/etherdevice.h>
     20#include <linux/skbuff.h>
     21#include <linux/spinlock.h>
     22#include <linux/mm.h>
     23#include <linux/module.h>
     24#include <linux/mii.h>
     25#include <linux/ethtool.h>
     26#include <linux/phy.h>
     27
     28#include <asm/io.h>
     29#include <asm/irq.h>
     30#include <linux/uaccess.h>
     31
     32/* ------------------------------------------------------------------------- */
     33/* The Quality Semiconductor QS6612 is used on the RPX CLLF                  */
     34
     35/* register definitions */
     36
     37#define MII_QS6612_MCR		17  /* Mode Control Register      */
     38#define MII_QS6612_FTR		27  /* Factory Test Register      */
     39#define MII_QS6612_MCO		28  /* Misc. Control Register     */
     40#define MII_QS6612_ISR		29  /* Interrupt Source Register  */
     41#define MII_QS6612_IMR		30  /* Interrupt Mask Register    */
     42#define MII_QS6612_IMR_INIT	0x003a
     43#define MII_QS6612_PCR		31  /* 100BaseTx PHY Control Reg. */
     44
     45#define QS6612_PCR_AN_COMPLETE	0x1000
     46#define QS6612_PCR_RLBEN	0x0200
     47#define QS6612_PCR_DCREN	0x0100
     48#define QS6612_PCR_4B5BEN	0x0040
     49#define QS6612_PCR_TX_ISOLATE	0x0020
     50#define QS6612_PCR_MLT3_DIS	0x0002
     51#define QS6612_PCR_SCRM_DESCRM	0x0001
     52
     53MODULE_DESCRIPTION("Quality Semiconductor PHY driver");
     54MODULE_AUTHOR("Andy Fleming");
     55MODULE_LICENSE("GPL");
     56
     57/* Returns 0, unless there's a write error */
     58static int qs6612_config_init(struct phy_device *phydev)
     59{
     60	/* The PHY powers up isolated on the RPX,
     61	 * so send a command to allow operation.
     62	 * XXX - My docs indicate this should be 0x0940
     63	 * ...or something.  The current value sets three
     64	 * reserved bits, bit 11, which specifies it should be
     65	 * set to one, bit 10, which specifies it should be set
     66	 * to 0, and bit 7, which doesn't specify.  However, my
     67	 * docs are preliminary, and I will leave it like this
     68	 * until someone more knowledgable corrects me or it.
     69	 * -- Andy Fleming
     70	 */
     71	return phy_write(phydev, MII_QS6612_PCR, 0x0dc0);
     72}
     73
     74static int qs6612_ack_interrupt(struct phy_device *phydev)
     75{
     76	int err;
     77
     78	/* The Interrupt Source register is not self-clearing, bits 4 and 5 are
     79	 * cleared when MII_BMSR is read and bits 1 and 3 are cleared when
     80	 * MII_EXPANSION is read
     81	 */
     82	err = phy_read(phydev, MII_QS6612_ISR);
     83
     84	if (err < 0)
     85		return err;
     86
     87	err = phy_read(phydev, MII_BMSR);
     88
     89	if (err < 0)
     90		return err;
     91
     92	err = phy_read(phydev, MII_EXPANSION);
     93
     94	if (err < 0)
     95		return err;
     96
     97	return 0;
     98}
     99
    100static int qs6612_config_intr(struct phy_device *phydev)
    101{
    102	int err;
    103
    104	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
    105		/* clear any interrupts before enabling them */
    106		err = qs6612_ack_interrupt(phydev);
    107		if (err)
    108			return err;
    109
    110		err = phy_write(phydev, MII_QS6612_IMR,
    111				MII_QS6612_IMR_INIT);
    112	} else {
    113		err = phy_write(phydev, MII_QS6612_IMR, 0);
    114		if (err)
    115			return err;
    116
    117		/* clear any leftover interrupts */
    118		err = qs6612_ack_interrupt(phydev);
    119	}
    120
    121	return err;
    122
    123}
    124
    125static irqreturn_t qs6612_handle_interrupt(struct phy_device *phydev)
    126{
    127	int irq_status;
    128
    129	irq_status = phy_read(phydev, MII_QS6612_ISR);
    130	if (irq_status < 0) {
    131		phy_error(phydev);
    132		return IRQ_NONE;
    133	}
    134
    135	if (!(irq_status & MII_QS6612_IMR_INIT))
    136		return IRQ_NONE;
    137
    138	/* the interrupt source register is not self-clearing */
    139	qs6612_ack_interrupt(phydev);
    140
    141	phy_trigger_machine(phydev);
    142
    143	return IRQ_HANDLED;
    144}
    145
    146static struct phy_driver qs6612_driver[] = { {
    147	.phy_id		= 0x00181440,
    148	.name		= "QS6612",
    149	.phy_id_mask	= 0xfffffff0,
    150	/* PHY_BASIC_FEATURES */
    151	.config_init	= qs6612_config_init,
    152	.config_intr	= qs6612_config_intr,
    153	.handle_interrupt = qs6612_handle_interrupt,
    154} };
    155
    156module_phy_driver(qs6612_driver);
    157
    158static struct mdio_device_id __maybe_unused qs6612_tbl[] = {
    159	{ 0x00181440, 0xfffffff0 },
    160	{ }
    161};
    162
    163MODULE_DEVICE_TABLE(mdio, qs6612_tbl);