drivers/net/phy/m88e1512: Provide functionality to customize LED status

For Marvel PHY it could be necessary to customize the shown LED status
at the connector. The LED status can be changed via Function Control
Register on page 3.

Link to the Marvell PHY 88E1512 datasheet:
https://web.archive.org/web/20221109080111/https://www.marvell.com/content/dam/marvell/en/public-collateral/phys-transceivers/marvell-phys-transceivers-alaska-88e151x-datasheet.pdf

Change-Id: Ia71c43f4286f9201f03cb759252ebb405ab81904
Signed-off-by: Mario Scheithauer <mario.scheithauer@siemens.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/69386
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/drivers/net/phy/m88e1512/m88e1512.c b/src/drivers/net/phy/m88e1512/m88e1512.c
index 3f45a10..d0883bf 100644
--- a/src/drivers/net/phy/m88e1512/m88e1512.c
+++ b/src/drivers/net/phy/m88e1512/m88e1512.c
@@ -1,9 +1,39 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 
+#include <console/console.h>
 #include <device/device.h>
+#include <device/mdio.h>
+#include <device/pci.h>
+#include "chip.h"
+#include "m88e1512.h"
+
+static void switch_page(struct device *dev, uint8_t page)
+{
+	mdio_write(dev, PAGE_REG, page);
+}
 
 static void m88e1512_init(struct device *dev)
 {
+	struct drivers_net_phy_m88e1512_config *config = dev->chip_info;
+	uint16_t reg;
+
+	/* Configure LEDs if requested. */
+	if (config->configure_leds) {
+		printk(BIOS_DEBUG, "%s: Set a customized LED mode for %s.\n",
+				dev_path(dev->bus->dev), dev->chip_ops->name);
+
+		/* Select page 3 to access LED function control register. */
+		switch_page(dev, 3);
+
+		/* Modify PHY LED mode. */
+		reg = mdio_read(dev, LED_FUNC_CTRL_REG);
+		clrsetbits16(&reg, LED_FUNC_CTRL_MASK, config->led_0_ctrl |
+				(config->led_1_ctrl << 4) | (config->led_2_ctrl << 8));
+		mdio_write(dev, LED_FUNC_CTRL_REG, reg);
+
+		/* Switch back to page 0. */
+		switch_page(dev, 0);
+	}
 }
 
 struct device_operations m88e1512_ops = {