diff options
author | Mario Scheithauer <mario.scheithauer@siemens.com> | 2022-11-02 16:00:27 +0100 |
---|---|---|
committer | Martin L Roth <gaumless@gmail.com> | 2022-11-24 05:56:37 +0000 |
commit | c16a7fc7179e0811a26bcfa44214f88f64793f04 (patch) | |
tree | fb323e621f074d9676eb3f62a2c5f19fd185a935 /src/soc/intel/elkhartlake | |
parent | 67f63e768d8860ebc6bae5987e2d928efabcf7c4 (diff) |
soc/intel/ehl: Add MDIO operation to TSN GbE device
This patch refactors the MDIO access for the TSN GbE device by placing
the MDIO read and write functions into mdio_bus_operations struct which
is assigned to the .ops_mdio member of the PCI device struct. In this
way the MDIO interface of the TSN GbE device is exposed and can be used
by other drivers if needed.
Change-Id: I5d1b9dd2f2ba8c18291fff314c13f0c3851784aa
Signed-off-by: Mario Scheithauer <mario.scheithauer@siemens.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/69383
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
Diffstat (limited to 'src/soc/intel/elkhartlake')
-rw-r--r-- | src/soc/intel/elkhartlake/include/soc/tsn_gbe.h | 31 | ||||
-rw-r--r-- | src/soc/intel/elkhartlake/tsn_gbe.c | 149 |
2 files changed, 98 insertions, 82 deletions
diff --git a/src/soc/intel/elkhartlake/include/soc/tsn_gbe.h b/src/soc/intel/elkhartlake/include/soc/tsn_gbe.h index cd9f12ee11..2b06b4cddf 100644 --- a/src/soc/intel/elkhartlake/include/soc/tsn_gbe.h +++ b/src/soc/intel/elkhartlake/include/soc/tsn_gbe.h @@ -3,23 +3,24 @@ #ifndef _SOC_ELKHARTLAKE_TSN_GBE_H_ #define _SOC_ELKHARTLAKE_TSN_GBE_H_ +#define GMII_TIMEOUT_MS 20 + +#define MAC_MDIO_ADR 0x200 /* MAC MDIO address register */ +#define MAC_MDIO_ADR_MASK 0x03FF7F0E +#define MAC_PHYAD(pa) (pa << 21) /* Physical Layer address */ +#define MAC_REGAD(rda) (rda << 16) /* Register/Device address */ +#define MAC_CLK_TRAIL_4 (4 << 12) /* 4 trailing clocks */ +#define MAC_CSR_CLK_DIV_102 (1 << 10) /* 100: CSR=150-250 MHz; CSR/102 */ +#define MAC_OP_CMD_WRITE (1 << 2) /* GMII Operation Command Write */ +#define MAC_OP_CMD_READ (3 << 2) /* GMII Operation Command Read */ +#define MAC_GMII_BUSY (1 << 0) /* GMII Busy bit */ +#define MAC_MDIO_DATA 0x204 /* MAC MDIO data register */ + #define MAC_ADDR_LEN 6 #define TSN_MAC_ADD0_HIGH 0x300 /* MAC Address0 High register */ #define TSN_MAC_ADD0_LOW 0x304 /* MAC Address0 Low register */ -#define TSN_GMII_TIMEOUT_MS 20 - -#define TSN_MAC_MDIO_ADR 0x200 /* MAC MDIO Address register */ -#define TSN_MAC_MDIO_ADR_MASK 0x03FF7F0E -#define TSN_MAC_PHYAD(pa) (pa << 21) /* Physical Layer Address */ -#define TSN_MAC_REGAD(rda) (rda << 16) /* Register/Device Address */ -#define TSN_MAC_CLK_TRAIL_4 (4 << 12) /* 4 Trailing Clocks */ -#define TSN_MAC_CSR_CLK_DIV_102 (1 << 10) /* 0100: CSR=150-250 MHz; CSR/102 */ -#define TSN_MAC_OP_CMD_WRITE (1 << 2) /* GMII Operation Command Write */ -#define TSN_MAC_OP_CMD_READ (3 << 2) /* GMII Operation Command Read */ -#define TSN_MAC_GMII_BUSY (1 << 0) /* GMII Busy bit */ - /* MDIO - Adhoc PHY Sublayer Register */ #define TSN_MAC_MDIO_ADHOC_ADR 0x15 /* Global Configuration Register */ @@ -27,14 +28,8 @@ /* PHY to MAC Interrupt Polarity bit */ #define TSN_MAC_PHY2MAC_INTR_POL (1 << 6) -#define TSN_MAC_MDIO_DATA 0x204 /* MAC MDIO Data register */ - /* We need one function we can call to get a MAC address to use. */ /* This function can be coded somewhere else but must exist. */ enum cb_err mainboard_get_mac_address(struct device *dev, uint8_t mac[MAC_ADDR_LEN]); -enum cb_err phy_gmii_ready(void *base); -uint16_t tsn_mdio_read(void *base, uint8_t phy_adr, uint8_t reg_adr); -void tsn_mdio_write(void *base, uint8_t phy_adr, uint8_t reg_adr, uint16_t data); - #endif /* _SOC_ELKHARTLAKE_TSN_GBE_H_ */ diff --git a/src/soc/intel/elkhartlake/tsn_gbe.c b/src/soc/intel/elkhartlake/tsn_gbe.c index b59daaa9fb..6092824b84 100644 --- a/src/soc/intel/elkhartlake/tsn_gbe.c +++ b/src/soc/intel/elkhartlake/tsn_gbe.c @@ -1,8 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include <console/console.h> +#include <delay.h> +#include <device/mdio.h> #include <device/pci.h> #include <device/pci_ids.h> +#include <device/pci_ops.h> #include <intelblocks/lpss.h> #include <soc/soc_chip.h> #include <soc/tsn_gbe.h> @@ -29,74 +32,21 @@ static void program_mac_address(struct device *dev, void *base) (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]); } -enum cb_err phy_gmii_ready(void *base) -{ - struct stopwatch sw; - - stopwatch_init_msecs_expire(&sw, TSN_GMII_TIMEOUT_MS); - do { - if (!(read32((base + TSN_MAC_MDIO_ADR)) & TSN_MAC_GMII_BUSY)) - return CB_SUCCESS; - - } while (!stopwatch_expired(&sw)); - - printk(BIOS_ERR, "%s Timeout after %lld msec\n", __func__, - stopwatch_duration_msecs(&sw)); - return CB_ERR; -} -uint16_t tsn_mdio_read(void *base, uint8_t phy_adr, uint8_t reg_adr) -{ - uint16_t data = 0; - enum cb_err status; - - clrsetbits32(base + TSN_MAC_MDIO_ADR, TSN_MAC_MDIO_ADR_MASK, - TSN_MAC_PHYAD(phy_adr) | TSN_MAC_REGAD(reg_adr) - | TSN_MAC_CLK_TRAIL_4 | TSN_MAC_CSR_CLK_DIV_102 - | TSN_MAC_OP_CMD_READ | TSN_MAC_GMII_BUSY); - - /* Wait for MDIO frame transfer to complete before reading MDIO DATA register */ - status = phy_gmii_ready(base); - if (status == CB_ERR) { - printk(BIOS_ERR, "%s TSN GMII busy. PHY Adr: 0x%x, Reg 0x%x\n", - __func__, phy_adr, reg_adr); - } else { - data = read16(base + TSN_MAC_MDIO_DATA); - printk(BIOS_DEBUG, "%s PHY Adr: 0x%x, Reg: 0x%x , Data: 0x%x\n", - __func__, phy_adr, reg_adr, data); - } - return data; -} - -void tsn_mdio_write(void *base, uint8_t phy_adr, uint8_t reg_adr, uint16_t data) -{ - enum cb_err status; - - write16(base + TSN_MAC_MDIO_DATA, data); - clrsetbits32(base + TSN_MAC_MDIO_ADR, TSN_MAC_MDIO_ADR_MASK, - TSN_MAC_PHYAD(phy_adr) | TSN_MAC_REGAD(reg_adr) - | TSN_MAC_CLK_TRAIL_4 | TSN_MAC_CSR_CLK_DIV_102 - | TSN_MAC_OP_CMD_WRITE | TSN_MAC_GMII_BUSY); - - /* Wait for MDIO frame transfer to complete before do next */ - status = phy_gmii_ready(base); - if (status == CB_ERR) - printk(BIOS_ERR, "%s TSN GMII busy. PHY Adr: 0x%x, Reg 0x%x\n", - __func__, phy_adr, reg_adr); - else - printk(BIOS_DEBUG, "%s PHY Adr: 0x%x, Reg: 0x%x , Data: 0x%x\n", - __func__, phy_adr, reg_adr, data); -} - -static void tsn_set_phy2mac_irq_polarity(void *base, enum tsn_phy_irq_polarity pol) +static void tsn_set_phy2mac_irq_polarity(struct device *dev, enum tsn_phy_irq_polarity pol) { uint16_t gcr_reg; + const struct mdio_bus_operations *mdio_ops; + + mdio_ops = dev_get_mdio_ops(dev); + if (!mdio_ops) + return; if (pol == RISING_EDGE) { /* Read TSN adhoc PHY sublayer register - global configuration register */ - gcr_reg = tsn_mdio_read(base, TSN_MAC_MDIO_ADHOC_ADR, TSN_MAC_MDIO_GCR); + gcr_reg = mdio_ops->read(dev, TSN_MAC_MDIO_ADHOC_ADR, TSN_MAC_MDIO_GCR); gcr_reg |= TSN_MAC_PHY2MAC_INTR_POL; - tsn_mdio_write(base, TSN_MAC_MDIO_ADHOC_ADR, TSN_MAC_MDIO_GCR, gcr_reg); + mdio_ops->write(dev, TSN_MAC_MDIO_ADHOC_ADR, TSN_MAC_MDIO_GCR, gcr_reg); } } @@ -120,17 +70,87 @@ static void gbe_tsn_init(struct device *dev) /* Set PHY-to-MAC IRQ polarity according to devicetree */ switch (dev->path.pci.devfn) { case PCH_DEVFN_GBE: - tsn_set_phy2mac_irq_polarity(io_mem_base, config->pch_tsn_phy_irq_edge); + tsn_set_phy2mac_irq_polarity(dev, config->pch_tsn_phy_irq_edge); break; case PCH_DEVFN_PSEGBE0: - tsn_set_phy2mac_irq_polarity(io_mem_base, config->pse_tsn_phy_irq_edge[0]); + tsn_set_phy2mac_irq_polarity(dev, config->pse_tsn_phy_irq_edge[0]); break; case PCH_DEVFN_PSEGBE1: - tsn_set_phy2mac_irq_polarity(io_mem_base, config->pse_tsn_phy_irq_edge[1]); + tsn_set_phy2mac_irq_polarity(dev, config->pse_tsn_phy_irq_edge[1]); break; } } +static enum cb_err phy_gmii_ready(void *base) +{ + struct stopwatch sw; + + stopwatch_init_msecs_expire(&sw, GMII_TIMEOUT_MS); + do { + if (!(read32((base + MAC_MDIO_ADR)) & MAC_GMII_BUSY)) + return CB_SUCCESS; + mdelay(1); + } while (!stopwatch_expired(&sw)); + + printk(BIOS_ERR, "%s Timeout after %lld msec\n", __func__, + stopwatch_duration_msecs(&sw)); + return CB_ERR; +} + +static uint16_t tsn_mdio_read(struct device *dev, uint8_t phy_adr, uint8_t reg_adr) +{ + uint16_t data = 0; + struct resource *gbe_tsn_res = find_resource(dev, PCI_BASE_ADDRESS_0); + void *mmio_base = res2mmio(gbe_tsn_res, 0, 0); + + if (!mmio_base) + return data; + + clrsetbits32(mmio_base + MAC_MDIO_ADR, MAC_MDIO_ADR_MASK, + MAC_PHYAD(phy_adr) | MAC_REGAD(reg_adr) + | MAC_CLK_TRAIL_4 | MAC_CSR_CLK_DIV_102 + | MAC_OP_CMD_READ | MAC_GMII_BUSY); + + /* Wait for MDIO frame transfer to complete before reading MDIO DATA register. */ + if (phy_gmii_ready(mmio_base) != CB_SUCCESS) { + printk(BIOS_ERR, "%s TSN GMII busy. PHY Adr: 0x%x, Reg 0x%x\n", + __func__, phy_adr, reg_adr); + } else { + data = read16(mmio_base + MAC_MDIO_DATA); + printk(BIOS_SPEW, "%s PHY Adr: 0x%x, Reg: 0x%x , Data: 0x%x\n", + __func__, phy_adr, reg_adr, data); + } + return data; +} + +static void tsn_mdio_write(struct device *dev, uint8_t phy_adr, uint8_t reg_adr, uint16_t data) +{ + struct resource *gbe_tsn_res = find_resource(dev, PCI_BASE_ADDRESS_0); + void *mmio_base = res2mmio(gbe_tsn_res, 0, 0); + + if (!mmio_base) + return; + + write16(mmio_base + MAC_MDIO_DATA, data); + clrsetbits32(mmio_base + MAC_MDIO_ADR, MAC_MDIO_ADR_MASK, + MAC_PHYAD(phy_adr) | MAC_REGAD(reg_adr) + | MAC_CLK_TRAIL_4 | MAC_CSR_CLK_DIV_102 + | MAC_OP_CMD_WRITE | MAC_GMII_BUSY); + + /* Wait for MDIO frame transfer to complete before exit. */ + if (phy_gmii_ready(mmio_base) != CB_SUCCESS) + printk(BIOS_ERR, "%s TSN GMII busy. PHY Adr: 0x%x, Reg 0x%x\n", + __func__, phy_adr, reg_adr); + else + printk(BIOS_SPEW, "%s PHY Adr: 0x%x, Reg: 0x%x , Data: 0x%x\n", + __func__, phy_adr, reg_adr, data); +} + +static struct mdio_bus_operations mdio_ops = { + .read = tsn_mdio_read, + .write = tsn_mdio_write, +}; + static struct device_operations gbe_tsn_ops = { .read_resources = pci_dev_read_resources, .set_resources = pci_dev_set_resources, @@ -138,6 +158,7 @@ static struct device_operations gbe_tsn_ops = { .scan_bus = scan_generic_bus, .enable = gbe_tsn_enable, .init = gbe_tsn_init, + .ops_mdio = &mdio_ops, }; static const unsigned short gbe_tsn_device_ids[] = { |