// SPDX-License-Identifier: GPL-2.0+
/* Copyright (C) 2021 Maxlinear Corporation
* Copyright (C) 2020 Intel Corporation
*
* Drivers for Maxlinear Ethernet GPY
*
*/
#include <linux/module.h>
#include <linux/bitfield.h>
#include <linux/hwmon.h>
#include <linux/mutex.h>
#include <linux/phy.h>
#include <linux/polynomial.h>
#include <linux/property.h>
#include <linux/netdevice.h>
/* PHY ID */
#define PHY_ID_GPYx15B_MASK 0xFFFFFFFC
#define PHY_ID_GPY21xB_MASK 0xFFFFFFF9
#define PHY_ID_GPY2xx 0x67C9DC00
#define PHY_ID_GPY115B 0x67C9DF00
#define PHY_ID_GPY115C 0x67C9DF10
#define PHY_ID_GPY211B 0x67C9DE08
#define PHY_ID_GPY211C 0x67C9DE10
#define PHY_ID_GPY212B 0x67C9DE09
#define PHY_ID_GPY212C 0x67C9DE20
#define PHY_ID_GPY215B 0x67C9DF04
#define PHY_ID_GPY215C 0x67C9DF20
#define PHY_ID_GPY241B 0x67C9DE40
#define PHY_ID_GPY241BM 0x67C9DE80
#define PHY_ID_GPY245B 0x67C9DEC0
#define PHY_CTL1 0x13
#define PHY_CTL1_MDICD BIT(3)
#define PHY_CTL1_MDIAB BIT(2)
#define PHY_CTL1_AMDIX BIT(0)
#define PHY_MIISTAT 0x18 /* MII state */
#define PHY_IMASK 0x19 /* interrupt mask */
#define PHY_ISTAT 0x1A /* interrupt status */
#define PHY_LED 0x1B /* LEDs */
#define PHY_FWV 0x1E /* firmware version */
#define PHY_MIISTAT_SPD_MASK GENMASK(2, 0)
#define PHY_MIISTAT_DPX BIT(3)
#define PHY_MIISTAT_LS BIT(10)
#define PHY_MIISTAT_SPD_10 0
#define PHY_MIISTAT_SPD_100 1
#define PHY_MIISTAT_SPD_1000 2
#define PHY_MIISTAT_SPD_2500 4
#define PHY_IMASK_WOL BIT(15) /* Wake-on-LAN */
#define PHY_IMASK_ANC BIT(10) /* Auto-Neg complete */
#define PHY_IMASK_ADSC BIT(5) /* Link auto-downspeed detect */
#define PHY_IMASK_DXMC BIT(2) /* Duplex mode change */
#define PHY_IMASK_LSPC BIT(1) /* Link speed change */
#define PHY_IMASK_LSTC BIT(0) /* Link state change */
#define PHY_IMASK_MASK (PHY_IMASK_LSTC | \
PHY_IMASK_LSPC | \
PHY_IMASK_DXMC | \
PHY_IMASK_ADSC | \
PHY_IMASK_ANC)
#define GPY_MAX_LEDS 4
#define PHY_LED_POLARITY(idx) BIT(12 + (idx))
#define PHY_LED_HWCONTROL(idx) BIT(8 + (idx))
#define PHY_LED_ON(idx) BIT(idx)
#define PHY_FWV_REL_MASK BIT(15)
#define PHY_FWV_MAJOR_MASK GENMASK(11, 8)
#define PHY_FWV_MINOR_MASK GENMASK(7, 0)
#define PHY_PMA_MGBT_POLARITY 0x82
#define PHY_MDI_MDI_X_MASK GENMASK(1, 0)
#define PHY_MDI_MDI_X_NORMAL 0x3
#define PHY_MDI_MDI_X_AB 0x2
#define PHY_MDI_MDI_X_CD 0x1
#define PHY_MDI_MDI_X_CROSS 0x0
/* LED */
#define VSPEC1_LED(idx) (1 + (idx))
#define VSPEC1_LED_BLINKS GENMASK(15, 12)
#define VSPEC1_LED_PULSE GENMASK(11, 8)
#define VSPEC1_LED_CON GENMASK(7, 4)
#define VSPEC1_LED_BLINKF GENMASK(3, 0)
#define VSPEC1_LED_LINK10 BIT(0)
#define VSPEC1_LED_LINK100 BIT(1)
#define VSPEC1_LED_LINK1000 BIT(2)
#define VSPEC1_LED_LINK2500 BIT(3)
#define VSPEC1_LED_TXACT BIT(0)
#define VSPEC1_LED_RXACT BIT(1)
#define VSPEC1_LED_COL BIT(2)
#define VSPEC1_LED_NO_CON BIT(3)
/* SGMII */
#define VSPEC1_SGMII_CTRL 0x08
#define VSPEC1_SGMII_CTRL_ANEN BIT(12) /* Aneg enable */
#define VSPEC1_SGMII_CTRL_ANRS BIT(9) /* Restart Aneg */
#define VSPEC1_SGMII_ANEN_ANRS (VSPEC1_SGMII_CTRL_ANEN | \
VSPEC1_SGMII_CTRL_ANRS)
/* Temperature sensor */
#define VSPEC1_TEMP_STA 0x0E
#define VSPEC1_TEMP_STA_DATA GENMASK(9, 0)
/* Mailbox */
#define VSPEC1_MBOX_DATA 0x5
#define VSPEC1_MBOX_ADDRLO 0x6
#define VSPEC1_MBOX_CMD 0x7
#define VSPEC1_MBOX_CMD_ADDRHI GENMASK(7, 0)
#define VSPEC1_MBOX_CMD_RD (0 << 8)
#define VSPEC1_MBOX_CMD_READY BIT(15)
/* WoL */
#define VPSPEC2_WOL_CTL 0x0E06
#define VPSPEC2_WOL_AD01 0x0E08
#define VPSPEC2_WOL_AD23 0x0E09
#define VPSPEC2_WOL_AD45 0x0E0A
#define WOL_EN BIT(0)
/* Internal registers, access via mbox */
#define REG_GPIO0_OUT 0xd3ce00
struct gpy_priv {
/* serialize mailbox acesses */
struct mutex mbox_lock;
u8 fw_major;
u8 fw_minor;
u32 wolopts;
/* It takes 3 seconds to fully switch out of loopback mode before
* it can safely re-enter loopback mode. Record the time when
* loopback is disabled. Check and wait if necessary before loopback
* is enabled.
*/
u64 lb_dis_to;
};
static const struct {
int major;
int minor;
} ver_need_sgmii_reaneg[] = {
{7, 0x6D},
{8, 0x6D},
{9, 0x73},
};
#if IS_ENABLED(CONFIG_HWMON)
/* The original translation formulae of the temperature (in degrees of Celsius)
* are as follows:
*
* T = -2.5761e-11*(N^4) + 9.7332e-8*(N^3) + -1.9165e-4*(N^2) +
* 3.0762e-1*(N^1) + -5.2156e1
*
* where [-52.156, 137.961]C and N = [0, 1023].
*
* They must be accordingly altered to be suitable for the integer arithmetics.
* The technique is called 'factor redistribution', which just makes sure the
* multiplications and divisions are made so to have a result of the operations
* within the integer numbers limit. In addition we need to translate the
* formulae to accept millidegrees of Celsius. Here what it looks like after
* the alterations:
*
* T = -25761e-12*(N^4) + 97332e-9*(N^3) + -191650e-6*(N^2) +
* 307620e-3*(N^1) + -52156
*
* where T = [-52156, 137961]mC and N = [0, 1023].
*/
static const struct polynomial poly_N_to_temp = {
.terms = {
{4, -25761, 1000, 1},
{3, 97332, 1000, 1},
{2, -191650, 1000, 1},
{1, 307620, 1000, 1},
{0, -52156, 1