File Index
Files and directories
Sign in
FILE

as21xxx.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/phy/as21xxx.c C
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Aeonsemi AS21XXxX PHY Driver
   4 *
   5 * Author: Christian Marangi <ansuelsmth@gmail.com>
   6 */
   7
   8#include <linux/bitfield.h>
   9#include <linux/firmware.h>
  10#include <linux/module.h>
  11#include <linux/of.h>
  12#include <linux/phy.h>
  13
  14#define VEND1_GLB_REG_CPU_RESET_ADDR_LO_BASEADDR 0x3
  15#define VEND1_GLB_REG_CPU_RESET_ADDR_HI_BASEADDR 0x4
  16
  17#define VEND1_GLB_REG_CPU_CTRL		0xe
  18#define   VEND1_GLB_CPU_CTRL_MASK	GENMASK(4, 0)
  19#define   VEND1_GLB_CPU_CTRL_LED_POLARITY_MASK GENMASK(12, 8)
  20#define   VEND1_GLB_CPU_CTRL_LED_POLARITY(_n) FIELD_PREP(VEND1_GLB_CPU_CTRL_LED_POLARITY_MASK, \
  21							 BIT(_n))
  22
  23#define VEND1_FW_START_ADDR		0x100
  24
  25#define VEND1_GLB_REG_MDIO_INDIRECT_ADDRCMD 0x101
  26#define VEND1_GLB_REG_MDIO_INDIRECT_LOAD 0x102
  27
  28#define VEND1_GLB_REG_MDIO_INDIRECT_STATUS 0x103
  29
  30#define VEND1_PTP_CLK			0x142
  31#define   VEND1_PTP_CLK_EN		BIT(6)
  32
  33/* 5 LED at step of 0x20
  34 * FE: Fast-Ethernet (10/100)
  35 * GE: Gigabit-Ethernet (1000)
  36 * NG: New-Generation (2500/5000/10000)
  37 */
  38#define VEND1_LED_REG(_n)		(0x1800 + ((_n) * 0x10))
  39#define   VEND1_LED_REG_A_EVENT		GENMASK(15, 11)
  40#define VEND1_LED_CONF			0x1881
  41#define   VEND1_LED_CONFG_BLINK		GENMASK(7, 0)
  42
  43#define VEND1_SPEED_STATUS		0x4002
  44#define   VEND1_SPEED_MASK		GENMASK(7, 0)
  45#define   VEND1_SPEED_10000		FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x3)
  46#define   VEND1_SPEED_5000		FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x5)
  47#define   VEND1_SPEED_2500		FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x9)
  48#define   VEND1_SPEED_1000		FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x10)
  49#define   VEND1_SPEED_100		FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x20)
  50#define   VEND1_SPEED_10		FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x0)
  51
  52#define VEND1_IPC_CMD			0x5801
  53#define   AEON_IPC_CMD_PARITY		BIT(15)
  54#define   AEON_IPC_CMD_SIZE		GENMASK(10, 6)
  55#define   AEON_IPC_CMD_OPCODE		GENMASK(5, 0)
  56
  57#define IPC_CMD_NOOP			0x0  /* Do nothing */
  58#define IPC_CMD_INFO			0x1  /* Get Firmware Version */
  59#define IPC_CMD_SYS_CPU			0x2  /* SYS_CPU */
  60#define IPC_CMD_BULK_DATA		0xa  /* Pass bulk data in ipc registers. */
  61#define IPC_CMD_BULK_WRITE		0xc  /* Write bulk data to memory */
  62#define IPC_CMD_CFG_PARAM		0x1a /* Write config parameters to memory */
  63#define IPC_CMD_NG_TESTMODE		0x1b /* Set NG test mode and tone */
  64#define IPC_CMD_TEMP_MON		0x15 /* Temperature monitoring function */
  65#define IPC_CMD_SET_LED			0x23 /* Set led */
  66
  67#define VEND1_IPC_STS			0x5802
  68#define   AEON_IPC_STS_PARITY		BIT(15)
  69#define   AEON_IPC_STS_SIZE		GENMASK(14, 10)
  70#define   AEON_IPC_STS_OPCODE		GENMASK(9, 4)
  71#define   AEON_IPC_STS_STATUS		GENMASK(3, 0)
  72#define   AEON_IPC_STS_STATUS_RCVD	FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x1)
  73#define   AEON_IPC_STS_STATUS_PROCESS	FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x2)
  74#define   AEON_IPC_STS_STATUS_SUCCESS	FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x4)
  75#define   AEON_IPC_STS_STATUS_ERROR	FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x8)
  76#define   AEON_IPC_STS_STATUS_BUSY	FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0xe)
  77#define   AEON_IPC_STS_STATUS_READY	FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0xf)
  78
  79#define VEND1_IPC_DATA0			0x5808
  80#define VEND1_IPC_DATA1			0x5809
  81#define VEND1_IPC_DATA2			0x580a
  82#define VEND1_IPC_DATA3			0x580b
  83#define VEND1_IPC_DATA4			0x580c
  84#define VEND1_IPC_DATA5			0x580d
  85#define VEND1_IPC_DATA6			0x580e
  86#define VEND1_IPC_DATA7			0x580f
  87#define VEND1_IPC_DATA(_n)		(VEND1_IPC_DATA0 + (_n))
  88
  89/* Sub command of CMD_INFO */
  90#define IPC_INFO_VERSION		0x1
  91
  92/* Sub command of CMD_SYS_CPU */
  93#define IPC_SYS_CPU_REBOOT		0x3
  94#define IPC_SYS_CPU_IMAGE_OFST		0x4
  95#define IPC_SYS_CPU_IMAGE_CHECK		0x5
  96#define IPC_SYS_CPU_PHY_ENABLE		0x6
  97
  98/* Sub command of CMD_CFG_PARAM */
  99#define IPC_CFG_PARAM_DIRECT		0x4
 100
 101/* CFG DIRECT sub command */
 102#define IPC_CFG_PARAM_DIRECT_NG_PHYCTRL	0x1
 103#define IPC_CFG_PARAM_DIRECT_CU_AN	0x2
 104#define IPC_CFG_PARAM_DIRECT_SDS_PCS	0x3
 105#define IPC_CFG_PARAM_DIRECT_AUTO_EEE	0x4
 106#define IPC_CFG_PARAM_DIRECT_SDS_PMA	0x5
 107#define IPC_CFG_PARAM_DIRECT_DPC_RA	0x6
 108#define IPC_CFG_PARAM_DIRECT_DPC_PKT_CHK 0x7
 109#define IPC_CFG_PARAM_DIRECT_DPC_SDS_WAIT_ETH 0x8
 110#define IPC_CFG_PARAM_DIRECT_WDT	0x9
 111#define IPC_CFG_PARAM_DIRECT_SDS_RESTART_AN 0x10
 112#define IPC_CFG_PARAM_DIRECT_TEMP_MON	0x11
 113#define IPC_CFG_PARAM_DIRECT_WOL	0x12
 114
 115/* Sub command of CMD_TEMP_MON */
 116#define IPC_CMD_TEMP_MON_GET		0x4
 117
 118#define AS21XXX_MDIO_AN_C22		0xffe0
 119
 120#define PHY_ID_AS21XXX			0x75009410
 121/* AS21xxx ID Legend
 122 * AS21x1xxB1
 123 *     ^ ^^
 124 *     | |J: Supports SyncE/PTP
 125 *     | |P: No SyncE/PTP support
 126 *     | 1: Supports 2nd Serdes
 127 *     | 2: Not 2nd Serdes support
 128 *     0: 10G, 5G, 2.5G
 129 *     5: 5G, 2.5G
 130 *     2: 2.5G
 131 */
 132#define PHY_ID_AS21011JB1		0x75009402
 133#define PHY_ID_AS21011PB1		0x75009412
 134#define PHY_ID_AS21010JB1		0x75009422
 135#define PHY_ID_AS21010PB1		0x75009432
 136#define PHY_ID_AS21511JB1		0x75009442
 137#define PHY_ID_AS21511PB1		0x75009452
 138#define PHY_ID_AS21510JB1		0x75009462
 139#define PHY_ID_AS21510PB1		0x75009472
 140#define PHY_ID_AS21210JB1		0x75009482
 141#define PHY_ID_AS21210PB1		0x75009492
 142#define PHY_VENDOR_AEONSEMI		0x75009400
 143
 144#define AEON_MAX_LEDS			5
 145#define AEON_IPC_DELAY			10000
 146#define AEON_IPC_TIMEOUT		(AEON_IPC_DELAY * 100)
 147#define AEON_IPC_DATA_NUM_REGISTERS	8
 148#define AEON_IPC_DATA_MAX		(AEON_IPC_DATA_NUM_REGISTERS * sizeof(u16))
 149
 150#define AEON_BOOT_ADDR			0x1000
 151#define AEON_CPU_BOOT_ADDR		0x2000
 152#define AEON_CPU_CTRL_FW_LOAD		(BIT(4) | BIT(2) | BIT(1) | BIT(0))
 153#define AEON_CPU_CTRL_FW_START		BIT(0)
 154
 155enum as21xxx_led_event {
 156	VEND1_LED_REG_A_EVENT_ON_10 = 0x0,
 157	VEND1_LED_REG_A_EVENT_ON_100,
 158	VEND1_LED_REG_A_EVENT_ON_1000,
 159	VEND1_LED_REG_A_EVENT_ON_2500,
 160	VEND1_LED_REG_A_EVENT_ON_5000,
 161	VEND1_LED_REG_A_EVENT_ON_10000,
 162	VEND1_LED_REG_A_EVENT_ON_FE_GE,
 163	VEND1_LED_REG_A_EVENT_ON_NG,
 164	VEND1_LED_REG_A_EVENT_ON_FULL_DUPLEX,
 165	VEND1_LED_REG_A_EVENT_ON_COLLISION,
 166	VEND1_LED_REG_A_EVENT_BLINK_TX,
 167	VEND1_LED_REG_A_EVENT_BLINK_RX,
 168	VEND1_LED_REG_A_EVENT_BLINK_ACT,
 169	VEND1_LED_REG_A_EVENT_ON_LINK,
 170	VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_ACT,
 171	VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_RX,
 172	VEND1_LED_REG_A_EVENT_ON_FE_GE_BLINK_ACT,
 173	VEND1_LED_REG_A_EVENT_ON_NG_BLINK_ACT,
 174	VEND1_LED_REG_A_EVENT_ON_NG_BLINK_FE_GE,
 175	VEND1_LED_REG_A_EVENT_ON_FD_BLINK_COLLISION,
 176	VEND1_LED_REG_A_EVENT_ON,
 177	VEND1_LED_REG_A_EVENT_OFF,
 178};
 179
 180struct as21xxx_led_pattern_info {
 181	unsigned int pattern;
 182	u16 val;
 183};
 184
 185struct as21xxx_priv {
 186	bool parity_status;
 187	/* Protect concurrent IPC access */
 188	struct mutex ipc_lock;
 189};
 190
 191static struct as21xxx_led_pattern_info as21xxx_led_supported_pattern[] = {
 192	{
 193		.pattern = BIT(TRIGGER_NETDEV_LINK_10),
 194		.val = VEND1_LED_REG_A_EVENT_ON_10
 195	},
 196	{
 197		.pattern = BIT(TRIGGER_NETDEV_LINK_100),
 198		.val = VEND1_LED_REG_A_EVENT_ON_100
 199	},
 200	{
 201		.pattern = BIT(TRIGGER_NETDEV_LINK_1000),
 202		.val = VEND1_LED_REG_A_EVENT_ON_1000
 203	},
 204	{
 205		.pattern = BIT(TRIGGER_NETDEV_LINK_2500),
 206		.val = VEND1_LED_REG_A_EVENT_ON_2500
 207	},
 208	{
 209		.pattern = BIT(TRIGGER_NETDEV_LINK_5000),
 210		.val = VEND1_LED_REG_A_EVENT_ON_5000
 211	},
 212	{
 213		.pattern = BIT(TRIGGER_NETDEV_LINK_10000),
 214		.val = VEND1_LED_REG_A_EVENT_ON_10000
 215	},
 216	{
 217		.pattern = BIT(TRIGGER_NETDEV_LINK),
 218		.val = VEND1_LED_REG_A_EVENT_ON_LINK
 219	},
 220	{
 221		.pattern = BIT(TRIGGER_NETDEV_LINK_10) |
 222			   BIT(TRIGGER_NETDEV_LINK_100) |
 223			   BIT(TRIGGER_NETDEV_LINK_1000),
 224		.val = VEND1_LED_REG_A_EVENT_ON_FE_GE
 225	},
 226	{
 227		.pattern = BIT(TRIGGER_NETDEV_LINK_2500) |
 228			   BIT(TRIGGER_NETDEV_LINK_5000) |
 229			   BIT(TRIGGER_NETDEV_LINK_10000),
 230		.val = VEND1_LED_REG_A_EVENT_ON_NG
 231	},
 232	{
 233		.pattern = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
 234		.val = VEND1_LED_REG_A_EVENT_ON_FULL_DUPLEX
 235	},
 236	{
 237		.pattern = BIT(TRIGGER_NETDEV_TX),
 238		.val = VEND1_LED_REG_A_EVENT_BLINK_TX
 239	},
 240	{
 241		.pattern = BIT(TRIGGER_NETDEV_RX),
 242		.val = VEND1_LED_REG_A_EVENT_BLINK_RX
 243	},
 244	{
 245		.pattern = BIT(TRIGGER_NETDEV_TX) |
 246			   BIT(TRIGGER_NETDEV_RX),
 247		.val = VEND1_LED_REG_A_EVENT_BLINK_ACT
 248	},
 249	{
 250		.pattern = BIT(TRIGGER_NETDEV_LINK_10) |
 251			   BIT(TRIGGER_NETDEV_LINK_100) |
 252			   BIT(TRIGGER_NETDEV_LINK_1000) |
 253			   BIT(TRIGGER_NETDEV_LINK_2500) |
 254			   BIT(TRIGGER_NETDEV_LINK_5000) |
 255			   BIT(TRIGGER_NETDEV_LINK_10000),
 256		.val = VEND1_LED_REG_A_EVENT_ON_LINK
 257	},
 258	{
 259		.pattern = BIT(TRIGGER_NETDEV_LINK_10) |
 260			   BIT(TRIGGER_NETDEV_LINK_100) |
 261			   BIT(TRIGGER_NETDEV_LINK_1000) |
 262			   BIT(TRIGGER_NETDEV_LINK_2500) |
 263			   BIT(TRIGGER_NETDEV_LINK_5000) |
 264			   BIT(TRIGGER_NETDEV_LINK_10000) |
 265			   BIT(TRIGGER_NETDEV_TX) |
 266			   BIT(TRIGGER_NETDEV_RX),
 267		.val = VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_ACT
 268	},
 269	{
 270		.pattern = BIT(TRIGGER_NETDEV_LINK_10) |
 271			   BIT(TRIGGER_NETDEV_LINK_100) |
 272			   BIT(TRIGGER_NETDEV_LINK_1000) |
 273			   BIT(TRIGGER_NETDEV_LINK_2500) |
 274			   BIT(TRIGGER_NETDEV_LINK_5000) |
 275			   BIT(TRIGGER_NETDEV_LINK_10000) |
 276			   BIT(TRIGGER_NETDEV_RX),
 277		.val = VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_RX
 278	},
 279	{
 280		.pattern = BIT(TRIGGER_NETDEV_LINK_10) |
 281			   BIT(TRIGGER_NETDEV_LINK_100) |
 282			   BIT(TRIGGER_NETDEV_LINK_1000) |
 283			   BIT(TRIGGER_NETDEV_TX) |
 284			   BIT(TRIGGER_NETDEV_RX),
 285		.val = VEND1_LED_REG_A_EVENT_ON_FE_GE_BLINK_ACT
 286	},
 287	{
 288		.pattern = BIT(TRIGGER_NETDEV_LINK_2500) |
 289			   BIT(TRIGGER_NETDEV_LINK_5000) |
 290			   BIT(TRIGGER_NETDEV_LINK_10000) |
 291			   BIT(TRIGGER_NETDEV_TX) |
 292			   BIT(TRIGGER_NETDEV_RX),
 293		.val = VEND1_LED_REG_A_EVENT_ON_NG_BLINK_ACT
 294	}
 295};
 296
 297static int aeon_firmware_boot(struct phy_device *phydev, const u8 *data,
 298			      size_t size)
 299{
 300	int i, ret;
 301	u16 val;
 302
 303	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL,
 304			     VEND1_GLB_CPU_CTRL_MASK, AEON_CPU_CTRL_FW_LOAD);
 305	if (ret)
 306		return ret;
 307
 308	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_FW_START_ADDR,
 309			    AEON_BOOT_ADDR);
 310	if (ret)
 311		return ret;
 312
 313	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1,
 314			     VEND1_GLB_REG_MDIO_INDIRECT_ADDRCMD,
 315			     0x3ffc, 0xc000);
 316	if (ret)
 317		return ret;
 318
 319	val = phy_read_mmd(phydev, MDIO_MMD_VEND1,
 320			   VEND1_GLB_REG_MDIO_INDIRECT_STATUS);
 321	if (val > 1) {
 322		phydev_err(phydev, "wrong origin mdio_indirect_status: %x\n", val);
 323		return -EINVAL;
 324	}
 325
 326	/* Firmware is always aligned to u16 */
 327	for (i = 0; i < size; i += 2) {
 328		val = data[i + 1] << 8 | data[i];
 329
 330		ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
 331				    VEND1_GLB_REG_MDIO_INDIRECT_LOAD, val);
 332		if (ret)
 333			return ret;
 334	}
 335
 336	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
 337			    VEND1_GLB_REG_CPU_RESET_ADDR_LO_BASEADDR,
 338			    lower_16_bits(AEON_CPU_BOOT_ADDR));
 339	if (ret)
 340		return ret;
 341
 342	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
 343			    VEND1_GLB_REG_CPU_RESET_ADDR_HI_BASEADDR,
 344			    upper_16_bits(AEON_CPU_BOOT_ADDR));
 345	if (ret)
 346		return ret;
 347
 348	return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL,
 349			      VEND1_GLB_CPU_CTRL_MASK, AEON_CPU_CTRL_FW_START);
 350}
 351
 352static int aeon_firmware_load(struct phy_device *phydev)
 353{
 354	struct device *dev = &phydev->mdio.dev;
 355	const struct firmware *fw;
 356	const char *fw_name;
 357	int ret;
 358
 359	ret = of_property_read_string(dev->of_node, "firmware-name",
 360				      &fw_name);
 361	if (ret)
 362		return ret;
 363
 364	ret = request_firmware(&fw, fw_name, dev);
 365	if (ret) {
 366		phydev_err(phydev, "failed to find FW file %s (%d)\n",
 367			   fw_name, ret);
 368		return ret;
 369	}
 370
 371	ret = aeon_firmware_boot(phydev, fw->data, fw->size);
 372
 373	release_firmware(fw);
 374
 375	return ret;
 376}
 377
 378static bool aeon_ipc_ready(u16 val, bool parity_status)
 379{
 380	u16 status;
 381
 382	if (FIELD_GET(AEON_IPC_STS_PARITY, val) != parity_status)
 383		return false;
 384
 385	status = val & AEON_IPC_STS_STATUS;
 386
 387	return status != AEON_IPC_STS_STATUS_RCVD &&
 388	       status != AEON_IPC_STS_STATUS_PROCESS &&
 389	       status != AEON_IPC_STS_STATUS_BUSY;
 390}
 391
 392static int aeon_ipc_wait_cmd(struct phy_device *phydev, bool parity_status)
 393{
 394	u16 val;
 395
 396	/* Exit condition logic:
 397	 * - Wait for parity bit equal
 398	 * - Wait for status success, error OR ready
 399	 */
 400	return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, VEND1_IPC_STS, val,
 401					 aeon_ipc_ready(val, parity_status),
 402					 AEON_IPC_DELAY, AEON_IPC_TIMEOUT, false);
 403}
 404
 405static int aeon_ipc_send_cmd(struct phy_device *phydev,
 406			     struct as21xxx_priv *priv,
 407			     u16 cmd, u16 *ret_sts)
 408{
 409	bool curr_parity;
 410	int ret;
 411
 412	/* The IPC sync by using a single parity bit.
 413	 * Each CMD have alternately this bit set or clear
 414	 * to understand correct flow and packet order.
 415	 */
 416	curr_parity = priv->parity_status;
 417	if (priv->parity_status)
 418		cmd |= AEON_IPC_CMD_PARITY;
 419
 420	/* Always update parity for next packet */
 421	priv->parity_status = !priv->parity_status;
 422
 423	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_CMD, cmd);
 424	if (ret)
 425		return ret;
 426
 427	/* Wait for packet to be processed */
 428	usleep_range(AEON_IPC_DELAY, AEON_IPC_DELAY + 5000);
 429
 430	/* With no ret_sts, ignore waiting for packet completion
 431	 * (ipc parity bit sync)
 432	 */
 433	if (!ret_sts)
 434		return 0;
 435
 436	ret = aeon_ipc_wait_cmd(phydev, curr_parity);
 437	if (ret)
 438		return ret;
 439
 440	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_STS);
 441	if (ret < 0)
 442		return ret;
 443
 444	*ret_sts = ret;
 445	if ((*ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_SUCCESS)
 446		return -EINVAL;
 447
 448	return 0;
 449}
 450
 451/* If data is NULL, return 0 or negative error.
 452 * If data not NULL, return number of Bytes received from IPC or
 453 * a negative error.
 454 */
 455static int aeon_ipc_send_msg(struct phy_device *phydev,
 456			     u16 opcode, u16 *data, unsigned int data_len,
 457			     u16 *ret_data)
 458{
 459	struct as21xxx_priv *priv = phydev->priv;
 460	unsigned int ret_size;
 461	u16 cmd, ret_sts;
 462	int ret;
 463	int i;
 464
 465	/* IPC have a max of 8 register to transfer data,
 466	 * make sure we never exceed this.
 467	 */
 468	if (data_len > AEON_IPC_DATA_MAX)
 469		return -EINVAL;
 470
 471	for (i = 0; i < data_len / sizeof(u16); i++)
 472		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i),
 473			      data[i]);
 474
 475	cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, data_len) |
 476	      FIELD_PREP(AEON_IPC_CMD_OPCODE, opcode);
 477
 478	mutex_lock(&priv->ipc_lock);
 479
 480	ret = aeon_ipc_send_cmd(phydev, priv, cmd, &ret_sts);
 481	if (ret) {
 482		phydev_err(phydev, "failed to send ipc msg for %x: %d\n",
 483			   opcode, ret);
 484		goto out;
 485	}
 486
 487	if (!data)
 488		goto out;
 489
 490	if ((ret_sts & AEON_IPC_STS_STATUS) == AEON_IPC_STS_STATUS_ERROR) {
 491		ret = -EINVAL;
 492		goto out;
 493	}
 494
 495	/* Prevent IPC from stack smashing the kernel.
 496	 * We can't trust IPC to return a good value and we always
 497	 * preallocate space for 16 Bytes.
 498	 */
 499	ret_size = FIELD_GET(AEON_IPC_STS_SIZE, ret_sts);
 500	if (ret_size > AEON_IPC_DATA_MAX) {
 501		ret = -EINVAL;
 502		goto out;
 503	}
 504
 505	/* Read data from IPC data register for ret_size value from IPC */
 506	for (i = 0; i < DIV_ROUND_UP(ret_size, sizeof(u16)); i++) {
 507		ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i));
 508		if (ret < 0)
 509			goto out;
 510
 511		ret_data[i] = ret;
 512	}
 513
 514	ret = ret_size;
 515
 516out:
 517	mutex_unlock(&priv->ipc_lock);
 518
 519	return ret;
 520}
 521
 522static int aeon_ipc_noop(struct phy_device *phydev,
 523			 struct as21xxx_priv *priv, u16 *ret_sts)
 524{
 525	u16 cmd;
 526
 527	cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, 0) |
 528	      FIELD_PREP(AEON_IPC_CMD_OPCODE, IPC_CMD_NOOP);
 529
 530	return aeon_ipc_send_cmd(phydev, priv, cmd, ret_sts);
 531}
 532
 533/* Logic to sync parity bit with IPC.
 534 * We send 2 NOP cmd with same partity and we wait for IPC
 535 * to handle the packet only for the second one. This way
 536 * we make sure we are sync for every next cmd.
 537 */
 538static int aeon_ipc_sync_parity(struct phy_device *phydev,
 539				struct as21xxx_priv *priv)
 540{
 541	u16 ret_sts;
 542	int ret;
 543
 544	mutex_lock(&priv->ipc_lock);
 545
 546	/* Send NOP with no parity */
 547	aeon_ipc_noop(phydev, priv, NULL);
 548
 549	/* Reset packet parity */
 550	priv->parity_status = false;
 551
 552	/* Send second NOP with no parity */
 553	ret = aeon_ipc_noop(phydev, priv, &ret_sts);
 554
 555	mutex_unlock(&priv->ipc_lock);
 556
 557	/* We expect to return -EINVAL */
 558	if (ret != -EINVAL)
 559		return ret;
 560
 561	if ((ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_READY) {
 562		phydev_err(phydev, "Invalid IPC status on sync parity: %x\n",
 563			   ret_sts);
 564		return -EINVAL;
 565	}
 566
 567	return 0;
 568}
 569
 570static int aeon_ipc_get_fw_version(struct phy_device *phydev)
 571{
 572	u16 ret_data[AEON_IPC_DATA_NUM_REGISTERS], data[1];
 573	char fw_version[AEON_IPC_DATA_MAX + 1];
 574	int ret;
 575
 576	data[0] = IPC_INFO_VERSION;
 577
 578	ret = aeon_ipc_send_msg(phydev, IPC_CMD_INFO, data,
 579				sizeof(data), ret_data);
 580	if (ret < 0)
 581		return ret;
 582
 583	/* Make sure FW version is NULL terminated */
 584	memcpy(fw_version, ret_data, ret);
 585	fw_version[ret] = '\0';
 586
 587	phydev_info(phydev, "Firmware Version: %s\n", fw_version);
 588
 589	return 0;
 590}
 591
 592static int aeon_dpc_ra_enable(struct phy_device *phydev)
 593{
 594	u16 data[2];
 595
 596	data[0] = IPC_CFG_PARAM_DIRECT;
 597	data[1] = IPC_CFG_PARAM_DIRECT_DPC_RA;
 598
 599	return aeon_ipc_send_msg(phydev, IPC_CMD_CFG_PARAM, data,
 600				 sizeof(data), NULL);
 601}
 602
 603static int as21xxx_probe(struct phy_device *phydev)
 604{
 605	struct as21xxx_priv *priv;
 606	int ret;
 607
 608	priv = devm_kzalloc(&phydev->mdio.dev,
 609			    sizeof(*priv), GFP_KERNEL);
 610	if (!priv)
 611		return -ENOMEM;
 612	phydev->priv = priv;
 613
 614	ret = devm_mutex_init(&phydev->mdio.dev,
 615			      &priv->ipc_lock);
 616	if (ret)
 617		return ret;
 618
 619	ret = aeon_ipc_sync_parity(phydev, priv);
 620	if (ret)
 621		return ret;
 622
 623	ret = aeon_ipc_get_fw_version(phydev);
 624	if (ret)
 625		return ret;
 626
 627	/* Enable PTP clk if not already Enabled */
 628	ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CLK,
 629			       VEND1_PTP_CLK_EN);
 630	if (ret)
 631		return ret;
 632
 633	return aeon_dpc_ra_enable(phydev);
 634}
 635
 636static int as21xxx_read_link(struct phy_device *phydev, int *bmcr)
 637{
 638	int status;
 639
 640	/* Normal C22 BMCR report inconsistent data, use
 641	 * the mapped C22 in C45 to have more consistent link info.
 642	 */
 643	*bmcr = phy_read_mmd(phydev, MDIO_MMD_AN,
 644			     AS21XXX_MDIO_AN_C22 + MII_BMCR);
 645	if (*bmcr < 0)
 646		return *bmcr;
 647
 648	/* Autoneg is being started, therefore disregard current
 649	 * link status and report link as down.
 650	 */
 651	if (*bmcr & BMCR_ANRESTART) {
 652		phydev->link = 0;
 653		return 0;
 654	}
 655
 656	status = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
 657	if (status < 0)
 658		return status;
 659
 660	phydev->link = !!(status & MDIO_STAT1_LSTATUS);
 661
 662	return 0;
 663}
 664
 665static int as21xxx_read_c22_lpa(struct phy_device *phydev)
 666{
 667	int lpagb;
 668
 669	/* MII_STAT1000 are only filled in the mapped C22
 670	 * in C45, use that to fill lpagb values and check.
 671	 */
 672	lpagb = phy_read_mmd(phydev, MDIO_MMD_AN,
 673			     AS21XXX_MDIO_AN_C22 + MII_STAT1000);
 674	if (lpagb < 0)
 675		return lpagb;
 676
 677	if (lpagb & LPA_1000MSFAIL) {
 678		int adv = phy_read_mmd(phydev, MDIO_MMD_AN,
 679				       AS21XXX_MDIO_AN_C22 + MII_CTRL1000);
 680
 681		if (adv < 0)
 682			return adv;
 683
 684		if (adv & CTL1000_ENABLE_MASTER)
 685			phydev_err(phydev, "Master/Slave resolution failed, maybe conflicting manual settings?\n");
 686		else
 687			phydev_err(phydev, "Master/Slave resolution failed\n");
 688		return -ENOLINK;
 689	}
 690
 691	mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising,
 692					lpagb);
 693
 694	return 0;
 695}
 696
 697static int as21xxx_read_status(struct phy_device *phydev)
 698{
 699	int bmcr, old_link = phydev->link;
 700	int ret;
 701
 702	ret = as21xxx_read_link(phydev, &bmcr);
 703	if (ret)
 704		return ret;
 705
 706	/* why bother the PHY if nothing can have changed */
 707	if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
 708		return 0;
 709
 710	phydev->speed = SPEED_UNKNOWN;
 711	phydev->duplex = DUPLEX_UNKNOWN;
 712	phydev->pause = 0;
 713	phydev->asym_pause = 0;
 714
 715	if (phydev->autoneg == AUTONEG_ENABLE) {
 716		ret = genphy_c45_read_lpa(phydev);
 717		if (ret)
 718			return ret;
 719
 720		ret = as21xxx_read_c22_lpa(phydev);
 721		if (ret)
 722			return ret;
 723
 724		phy_resolve_aneg_linkmode(phydev);
 725	} else {
 726		int speed;
 727
 728		linkmode_zero(phydev->lp_advertising);
 729
 730		speed = phy_read_mmd(phydev, MDIO_MMD_VEND1,
 731				     VEND1_SPEED_STATUS);
 732		if (speed < 0)
 733			return speed;
 734
 735		switch (speed & VEND1_SPEED_STATUS) {
 736		case VEND1_SPEED_10000:
 737			phydev->speed = SPEED_10000;
 738			phydev->duplex = DUPLEX_FULL;
 739			break;
 740		case VEND1_SPEED_5000:
 741			phydev->speed = SPEED_5000;
 742			phydev->duplex = DUPLEX_FULL;
 743			break;
 744		case VEND1_SPEED_2500:
 745			phydev->speed = SPEED_2500;
 746			phydev->duplex = DUPLEX_FULL;
 747			break;
 748		case VEND1_SPEED_1000:
 749			phydev->speed = SPEED_1000;
 750			if (bmcr & BMCR_FULLDPLX)
 751				phydev->duplex = DUPLEX_FULL;
 752			else
 753				phydev->duplex = DUPLEX_HALF;
 754			break;
 755		case VEND1_SPEED_100:
 756			phydev->speed = SPEED_100;
 757			phydev->duplex = DUPLEX_FULL;
 758			break;
 759		case VEND1_SPEED_10:
 760			phydev->speed = SPEED_10;
 761			phydev->duplex = DUPLEX_FULL;
 762			break;
 763		default:
 764			return -EINVAL;
 765		}
 766	}
 767
 768	return 0;
 769}
 770
 771static int as21xxx_led_brightness_set(struct phy_device *phydev,
 772				      u8 index, enum led_brightness value)
 773{
 774	u16 val = VEND1_LED_REG_A_EVENT_OFF;
 775
 776	if (index > AEON_MAX_LEDS)
 777		return -EINVAL;
 778
 779	if (value)
 780		val = VEND1_LED_REG_A_EVENT_ON;
 781
 782	return phy_modify_mmd(phydev, MDIO_MMD_VEND1,
 783			      VEND1_LED_REG(index),
 784			      VEND1_LED_REG_A_EVENT,
 785			      FIELD_PREP(VEND1_LED_REG_A_EVENT, val));
 786}
 787
 788static int as21xxx_led_hw_is_supported(struct phy_device *phydev, u8 index,
 789				       unsigned long rules)
 790{
 791	int i;
 792
 793	if (index > AEON_MAX_LEDS)
 794		return -EINVAL;
 795
 796	for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++)
 797		if (rules == as21xxx_led_supported_pattern[i].pattern)
 798			return 0;
 799
 800	return -EOPNOTSUPP;
 801}
 802
 803static int as21xxx_led_hw_control_get(struct phy_device *phydev, u8 index,
 804				      unsigned long *rules)
 805{
 806	int i, val;
 807
 808	if (index > AEON_MAX_LEDS)
 809		return -EINVAL;
 810
 811	val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_LED_REG(index));
 812	if (val < 0)
 813		return val;
 814
 815	val = FIELD_GET(VEND1_LED_REG_A_EVENT, val);
 816	for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++)
 817		if (val == as21xxx_led_supported_pattern[i].val) {
 818			*rules = as21xxx_led_supported_pattern[i].pattern;
 819			return 0;
 820		}
 821
 822	/* Should be impossible */
 823	return -EINVAL;
 824}
 825
 826static int as21xxx_led_hw_control_set(struct phy_device *phydev, u8 index,
 827				      unsigned long rules)
 828{
 829	u16 val = 0;
 830	int i;
 831
 832	if (index > AEON_MAX_LEDS)
 833		return -EINVAL;
 834
 835	for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++)
 836		if (rules == as21xxx_led_supported_pattern[i].pattern) {
 837			val = as21xxx_led_supported_pattern[i].val;
 838			break;
 839		}
 840
 841	return phy_modify_mmd(phydev, MDIO_MMD_VEND1,
 842			      VEND1_LED_REG(index),
 843			      VEND1_LED_REG_A_EVENT,
 844			      FIELD_PREP(VEND1_LED_REG_A_EVENT, val));
 845}
 846
 847static int as21xxx_led_polarity_set(struct phy_device *phydev, int index,
 848				    unsigned long modes)
 849{
 850	bool led_active_low = false;
 851	u16 mask, val = 0;
 852	u32 mode;
 853
 854	if (index > AEON_MAX_LEDS)
 855		return -EINVAL;
 856
 857	for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
 858		switch (mode) {
 859		case PHY_LED_ACTIVE_LOW:
 860			led_active_low = true;
 861			break;
 862		case PHY_LED_ACTIVE_HIGH: /* default mode */
 863			led_active_low = false;
 864			break;
 865		default:
 866			return -EINVAL;
 867		}
 868	}
 869
 870	mask = VEND1_GLB_CPU_CTRL_LED_POLARITY(index);
 871	if (led_active_low)
 872		val = VEND1_GLB_CPU_CTRL_LED_POLARITY(index);
 873
 874	return phy_modify_mmd(phydev, MDIO_MMD_VEND1,
 875			      VEND1_GLB_REG_CPU_CTRL,
 876			      mask, val);
 877}
 878
 879static int as21xxx_match_phy_device(struct phy_device *phydev,
 880				    const struct phy_driver *phydrv)
 881{
 882	struct as21xxx_priv *priv;
 883	u16 ret_sts;
 884	u32 phy_id;
 885	int ret;
 886
 887	/* Skip PHY that are not AS21xxx */
 888	if (!phy_id_compare_vendor(phydev->c45_ids.device_ids[MDIO_MMD_PCS],
 889				   PHY_VENDOR_AEONSEMI))
 890		return genphy_match_phy_device(phydev, phydrv);
 891
 892	/* Read PHY ID to handle firmware loaded or HW reset */
 893	ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID1);
 894	if (ret < 0)
 895		return ret;
 896	phy_id = ret << 16;
 897
 898	ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID2);
 899	if (ret < 0)
 900		return ret;
 901	phy_id |= ret;
 902
 903	/* With PHY ID not the generic AS21xxx one assume
 904	 * the firmware just loaded
 905	 */
 906	if (phy_id != PHY_ID_AS21XXX)
 907		return phy_id == phydrv->phy_id;
 908
 909	/* Allocate temp priv and load the firmware */
 910	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 911	if (!priv)
 912		return -ENOMEM;
 913
 914	mutex_init(&priv->ipc_lock);
 915
 916	ret = aeon_firmware_load(phydev);
 917	if (ret)
 918		goto out;
 919
 920	/* Sync parity... */
 921	ret = aeon_ipc_sync_parity(phydev, priv);
 922	if (ret)
 923		goto out;
 924
 925	/* ...and send a third NOOP cmd to wait for firmware finish loading */
 926	ret = aeon_ipc_noop(phydev, priv, &ret_sts);
 927	if (ret)
 928		goto out;
 929
 930out:
 931	mutex_destroy(&priv->ipc_lock);
 932	kfree(priv);
 933
 934	/* Return can either be 0 or a negative error code.
 935	 * Returning 0 here means THIS is NOT a suitable PHY.
 936	 *
 937	 * For the specific case of the generic Aeonsemi PHY ID that
 938	 * needs the firmware the be loaded first to have a correct PHY ID,
 939	 * this is OK as a matching PHY ID will be found right after.
 940	 * This relies on the driver probe order where the first PHY driver
 941	 * probed is the generic one.
 942	 */
 943	return ret;
 944}
 945
 946static struct phy_driver as21xxx_drivers[] = {
 947	{
 948		/* PHY expose in C45 as 0x7500 0x9410
 949		 * before firmware is loaded.
 950		 * This driver entry must be attempted first to load
 951		 * the firmware and thus update the ID registers.
 952		 */
 953		PHY_ID_MATCH_EXACT(PHY_ID_AS21XXX),
 954		.name		= "Aeonsemi AS21xxx",
 955		.match_phy_device = as21xxx_match_phy_device,
 956	},
 957	{
 958		PHY_ID_MATCH_EXACT(PHY_ID_AS21011JB1),
 959		.name		= "Aeonsemi AS21011JB1",
 960		.probe		= as21xxx_probe,
 961		.match_phy_device = as21xxx_match_phy_device,
 962		.read_status	= as21xxx_read_status,
 963		.led_brightness_set = as21xxx_led_brightness_set,
 964		.led_hw_is_supported = as21xxx_led_hw_is_supported,
 965		.led_hw_control_set = as21xxx_led_hw_control_set,
 966		.led_hw_control_get = as21xxx_led_hw_control_get,
 967		.led_polarity_set = as21xxx_led_polarity_set,
 968	},
 969	{
 970		PHY_ID_MATCH_EXACT(PHY_ID_AS21011PB1),
 971		.name		= "Aeonsemi AS21011PB1",
 972		.probe		= as21xxx_probe,
 973		.match_phy_device = as21xxx_match_phy_device,
 974		.read_status	= as21xxx_read_status,
 975		.led_brightness_set = as21xxx_led_brightness_set,
 976		.led_hw_is_supported = as21xxx_led_hw_is_supported,
 977		.led_hw_control_set = as21xxx_led_hw_control_set,
 978		.led_hw_control_get = as21xxx_led_hw_control_get,
 979		.led_polarity_set = as21xxx_led_polarity_set,
 980	},
 981	{
 982		PHY_ID_MATCH_EXACT(PHY_ID_AS21010PB1),
 983		.name		= "Aeonsemi AS21010PB1",
 984		.probe		= as21xxx_probe,
 985		.match_phy_device = as21xxx_match_phy_device,
 986		.read_status	= as21xxx_read_status,
 987		.led_brightness_set = as21xxx_led_brightness_set,
 988		.led_hw_is_supported = as21xxx_led_hw_is_supported,
 989		.led_hw_control_set = as21xxx_led_hw_control_set,
 990		.led_hw_control_get = as21xxx_led_hw_control_get,
 991		.led_polarity_set = as21xxx_led_polarity_set,
 992	},
 993	{
 994		PHY_ID_MATCH_EXACT(PHY_ID_AS21010JB1),
 995		.name		= "Aeonsemi AS21010JB1",
 996		.probe		= as21xxx_probe,
 997		.match_phy_device = as21xxx_match_phy_device,
 998		.read_status	= as21xxx_read_status,
 999		.led_brightness_set = as21xxx_led_brightness_set,
1000		.led_hw_is_supported = as21xxx_led_hw_is_supported,
1001		.led_hw_control_set = as21xxx_led_hw_control_set,
1002		.led_hw_control_get = as21xxx_led_hw_control_get,
1003		.led_polarity_set = as21xxx_led_polarity_set,
1004	},
1005	{
1006		PHY_ID_MATCH_EXACT(PHY_ID_AS21210PB1),
1007		.name		= "Aeonsemi AS21210PB1",
1008		.probe		= as21xxx_probe,
1009		.match_phy_device = as21xxx_match_phy_device,
1010		.read_status	= as21xxx_read_status,
1011		.led_brightness_set = as21xxx_led_brightness_set,
1012		.led_hw_is_supported = as21xxx_led_hw_is_supported,
1013		.led_hw_control_set = as21xxx_led_hw_control_set,
1014		.led_hw_control_get = as21xxx_led_hw_control_get,
1015		.led_polarity_set = as21xxx_led_polarity_set,
1016	},
1017	{
1018		PHY_ID_MATCH_EXACT(PHY_ID_AS21510JB1),
1019		.name		= "Aeonsemi AS21510JB1",
1020		.probe		= as21xxx_probe,
1021		.match_phy_device = as21xxx_match_phy_device,
1022		.read_status	= as21xxx_read_status,
1023		.led_brightness_set = as21xxx_led_brightness_set,
1024		.led_hw_is_supported = as21xxx_led_hw_is_supported,
1025		.led_hw_control_set = as21xxx_led_hw_control_set,
1026		.led_hw_control_get = as21xxx_led_hw_control_get,
1027		.led_polarity_set = as21xxx_led_polarity_set,
1028	},
1029	{
1030		PHY_ID_MATCH_EXACT(PHY_ID_AS21510PB1),
1031		.name		= "Aeonsemi AS21510PB1",
1032		.probe		= as21xxx_probe,
1033		.match_phy_device = as21xxx_match_phy_device,
1034		.read_status	= as21xxx_read_status,
1035		.led_brightness_set = as21xxx_led_brightness_set,
1036		.led_hw_is_supported = as21xxx_led_hw_is_supported,
1037		.led_hw_control_set = as21xxx_led_hw_control_set,
1038		.led_hw_control_get = as21xxx_led_hw_control_get,
1039		.led_polarity_set = as21xxx_led_polarity_set,
1040	},
1041	{
1042		PHY_ID_MATCH_EXACT(PHY_ID_AS21511JB1),
1043		.name		= "Aeonsemi AS21511JB1",
1044		.probe		= as21xxx_probe,
1045		.match_phy_device = as21xxx_match_phy_device,
1046		.read_status	= as21xxx_read_status,
1047		.led_brightness_set = as21xxx_led_brightness_set,
1048		.led_hw_is_supported = as21xxx_led_hw_is_supported,
1049		.led_hw_control_set = as21xxx_led_hw_control_set,
1050		.led_hw_control_get = as21xxx_led_hw_control_get,
1051		.led_polarity_set = as21xxx_led_polarity_set,
1052	},
1053	{
1054		PHY_ID_MATCH_EXACT(PHY_ID_AS21210JB1),
1055		.name		= "Aeonsemi AS21210JB1",
1056		.probe		= as21xxx_probe,
1057		.match_phy_device = as21xxx_match_phy_device,
1058		.read_status	= as21xxx_read_status,
1059		.led_brightness_set = as21xxx_led_brightness_set,
1060		.led_hw_is_supported = as21xxx_led_hw_is_supported,
1061		.led_hw_control_set = as21xxx_led_hw_control_set,
1062		.led_hw_control_get = as21xxx_led_hw_control_get,
1063		.led_polarity_set = as21xxx_led_polarity_set,
1064	},
1065	{
1066		PHY_ID_MATCH_EXACT(PHY_ID_AS21511PB1),
1067		.name		= "Aeonsemi AS21511PB1",
1068		.probe		= as21xxx_probe,
1069		.match_phy_device = as21xxx_match_phy_device,
1070		.read_status	= as21xxx_read_status,
1071		.led_brightness_set = as21xxx_led_brightness_set,
1072		.led_hw_is_supported = as21xxx_led_hw_is_supported,
1073		.led_hw_control_set = as21xxx_led_hw_control_set,
1074		.led_hw_control_get = as21xxx_led_hw_control_get,
1075		.led_polarity_set = as21xxx_led_polarity_set,
1076	},
1077};
1078module_phy_driver(as21xxx_drivers);
1079
1080static struct mdio_device_id __maybe_unused as21xxx_tbl[] = {
1081	{ PHY_ID_MATCH_VENDOR(PHY_VENDOR_AEONSEMI) },
1082	{ }
1083};
1084MODULE_DEVICE_TABLE(mdio, as21xxx_tbl);
1085
1086MODULE_DESCRIPTION("Aeonsemi AS21xxx PHY driver");
1087MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
1088MODULE_LICENSE("GPL");
~/ Read-only file preview.