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>
This commit is contained in:
parent
67f63e768d
commit
c16a7fc717
|
@ -3,23 +3,24 @@
|
||||||
#ifndef _SOC_ELKHARTLAKE_TSN_GBE_H_
|
#ifndef _SOC_ELKHARTLAKE_TSN_GBE_H_
|
||||||
#define _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 MAC_ADDR_LEN 6
|
||||||
|
|
||||||
#define TSN_MAC_ADD0_HIGH 0x300 /* MAC Address0 High register */
|
#define TSN_MAC_ADD0_HIGH 0x300 /* MAC Address0 High register */
|
||||||
#define TSN_MAC_ADD0_LOW 0x304 /* MAC Address0 Low 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 */
|
/* MDIO - Adhoc PHY Sublayer Register */
|
||||||
#define TSN_MAC_MDIO_ADHOC_ADR 0x15
|
#define TSN_MAC_MDIO_ADHOC_ADR 0x15
|
||||||
/* Global Configuration Register */
|
/* Global Configuration Register */
|
||||||
|
@ -27,14 +28,8 @@
|
||||||
/* PHY to MAC Interrupt Polarity bit */
|
/* PHY to MAC Interrupt Polarity bit */
|
||||||
#define TSN_MAC_PHY2MAC_INTR_POL (1 << 6)
|
#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. */
|
/* We need one function we can call to get a MAC address to use. */
|
||||||
/* This function can be coded somewhere else but must exist. */
|
/* 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 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_ */
|
#endif /* _SOC_ELKHARTLAKE_TSN_GBE_H_ */
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
|
#include <delay.h>
|
||||||
|
#include <device/mdio.h>
|
||||||
#include <device/pci.h>
|
#include <device/pci.h>
|
||||||
#include <device/pci_ids.h>
|
#include <device/pci_ids.h>
|
||||||
|
#include <device/pci_ops.h>
|
||||||
#include <intelblocks/lpss.h>
|
#include <intelblocks/lpss.h>
|
||||||
#include <soc/soc_chip.h>
|
#include <soc/soc_chip.h>
|
||||||
#include <soc/tsn_gbe.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]);
|
(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);
|
static void tsn_set_phy2mac_irq_polarity(struct device *dev, enum tsn_phy_irq_polarity pol)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
uint16_t gcr_reg;
|
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) {
|
if (pol == RISING_EDGE) {
|
||||||
/* Read TSN adhoc PHY sublayer register - global configuration register */
|
/* 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;
|
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 */
|
/* Set PHY-to-MAC IRQ polarity according to devicetree */
|
||||||
switch (dev->path.pci.devfn) {
|
switch (dev->path.pci.devfn) {
|
||||||
case PCH_DEVFN_GBE:
|
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;
|
break;
|
||||||
case PCH_DEVFN_PSEGBE0:
|
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;
|
break;
|
||||||
case PCH_DEVFN_PSEGBE1:
|
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;
|
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 = {
|
static struct device_operations gbe_tsn_ops = {
|
||||||
.read_resources = pci_dev_read_resources,
|
.read_resources = pci_dev_read_resources,
|
||||||
.set_resources = pci_dev_set_resources,
|
.set_resources = pci_dev_set_resources,
|
||||||
|
@ -138,6 +158,7 @@ static struct device_operations gbe_tsn_ops = {
|
||||||
.scan_bus = scan_generic_bus,
|
.scan_bus = scan_generic_bus,
|
||||||
.enable = gbe_tsn_enable,
|
.enable = gbe_tsn_enable,
|
||||||
.init = gbe_tsn_init,
|
.init = gbe_tsn_init,
|
||||||
|
.ops_mdio = &mdio_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned short gbe_tsn_device_ids[] = {
|
static const unsigned short gbe_tsn_device_ids[] = {
|
||||||
|
|
Loading…
Reference in New Issue