blob: 50e9e16999cd3421bf88c755293bbd231b25f8f3 [file] [log] [blame]
Mario Scheithauereda66c32022-04-26 13:50:52 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <console/console.h>
4#include <device/pci.h>
5#include <device/pci_ids.h>
Mario Scheithauerdccdace2022-04-27 11:24:05 +02006#include <soc/soc_chip.h>
Mario Scheithauereda66c32022-04-26 13:50:52 +02007#include <soc/tsn_gbe.h>
Mario Scheithauerdccdace2022-04-27 11:24:05 +02008#include <timer.h>
Mario Scheithauereda66c32022-04-26 13:50:52 +02009
Mario Scheithauerd691c212022-04-26 14:16:59 +020010static void program_mac_address(struct device *dev, void *base)
11{
12 enum cb_err status;
13 uint8_t mac[MAC_ADDR_LEN];
14
15 /* Check first whether there is a valid MAC address available */
16 status = mainboard_get_mac_address(dev, mac);
17 if (status != CB_SUCCESS) {
18 printk(BIOS_INFO, "TSN GbE: No valid MAC address found\n");
19 return;
20 }
21
22 printk(BIOS_DEBUG, "TSN GbE: Programming MAC Address...\n");
23
24 /* Write the upper 16 bits of the first 6-byte MAC address */
Angel Ponsecff5212022-05-16 15:56:36 +020025 clrsetbits32(base + TSN_MAC_ADD0_HIGH, 0xffff, ((mac[5] << 8) | mac[4]));
Mario Scheithauerd691c212022-04-26 14:16:59 +020026 /* Write the lower 32 bits of the first 6-byte MAC address */
Angel Ponsecff5212022-05-16 15:56:36 +020027 clrsetbits32(base + TSN_MAC_ADD0_LOW, 0xffffffff,
Mario Scheithauerd691c212022-04-26 14:16:59 +020028 (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]);
29}
30
Mario Scheithauerdccdace2022-04-27 11:24:05 +020031enum cb_err phy_gmii_ready(void *base)
32{
33 struct stopwatch sw;
34
35 stopwatch_init_msecs_expire(&sw, TSN_GMII_TIMEOUT_MS);
36 do {
37 if (!(read32((base + TSN_MAC_MDIO_ADR)) & TSN_MAC_GMII_BUSY))
38 return CB_SUCCESS;
39
40 } while (!stopwatch_expired(&sw));
41
42 printk(BIOS_ERR, "%s Timeout after %ld msec\n", __func__,
43 stopwatch_duration_msecs(&sw));
44 return CB_ERR;
45}
46
47uint16_t tsn_mdio_read(void *base, uint8_t phy_adr, uint8_t reg_adr)
48{
49 uint16_t data = 0;
50 enum cb_err status;
51
52 clrsetbits32(base + TSN_MAC_MDIO_ADR, TSN_MAC_MDIO_ADR_MASK,
53 TSN_MAC_PHYAD(phy_adr) | TSN_MAC_REGAD(reg_adr)
54 | TSN_MAC_CLK_TRAIL_4 | TSN_MAC_CSR_CLK_DIV_62
55 | TSN_MAC_OP_CMD_READ | TSN_MAC_GMII_BUSY);
56
57 /* Wait for MDIO frame transfer to complete before reading MDIO DATA register */
58 status = phy_gmii_ready(base);
59 if (status == CB_ERR) {
60 printk(BIOS_ERR, "%s TSN GMII busy. PHY Adr: 0x%x, Reg 0x%x\n",
61 __func__, phy_adr, reg_adr);
62 } else {
63 data = read16(base + TSN_MAC_MDIO_DATA);
64 printk(BIOS_DEBUG, "%s PHY Adr: 0x%x, Reg: 0x%x , Data: 0x%x\n",
65 __func__, phy_adr, reg_adr, data);
66 }
67 return data;
68}
69
70void tsn_mdio_write(void *base, uint8_t phy_adr, uint8_t reg_adr, uint16_t data)
71{
72 enum cb_err status;
73
74 setbits16(base + TSN_MAC_MDIO_DATA, data);
75 clrsetbits32(base + TSN_MAC_MDIO_ADR, TSN_MAC_MDIO_ADR_MASK,
76 TSN_MAC_PHYAD(phy_adr) | TSN_MAC_REGAD(reg_adr)
77 | TSN_MAC_CLK_TRAIL_4 | TSN_MAC_CSR_CLK_DIV_62
78 | TSN_MAC_OP_CMD_WRITE | TSN_MAC_GMII_BUSY);
79
80 /* Wait for MDIO frame transfer to complete before do next */
81 status = phy_gmii_ready(base);
82 if (status == CB_ERR)
83 printk(BIOS_ERR, "%s TSN GMII busy. PHY Adr: 0x%x, Reg 0x%x\n",
84 __func__, phy_adr, reg_adr);
85 else
86 printk(BIOS_DEBUG, "%s PHY Adr: 0x%x, Reg: 0x%x , Data: 0x%x\n",
87 __func__, phy_adr, reg_adr, data);
88}
89
90static void tsn_set_phy2mac_irq_polarity(void *base, enum tsn_phy_irq_polarity pol)
91{
92 uint16_t gcr_reg;
93
94 if (pol == RISING_EDGE) {
95 /* Read TSN adhoc PHY sublayer register - global configuration register */
96 gcr_reg = tsn_mdio_read(base, TSN_MAC_MDIO_ADHOC_ADR, TSN_MAC_MDIO_GCR);
97 gcr_reg |= TSN_MAC_PHY2MAC_INTR_POL;
98 tsn_mdio_write(base, TSN_MAC_MDIO_ADHOC_ADR, TSN_MAC_MDIO_GCR, gcr_reg);
99 }
100}
101
Mario Scheithauerd691c212022-04-26 14:16:59 +0200102static void gbe_tsn_init(struct device *dev)
103{
104 /* Get the base address of the I/O registers in memory space */
105 struct resource *gbe_tsn_res = find_resource(dev, PCI_BASE_ADDRESS_0);
Angel Ponsecff5212022-05-16 15:56:36 +0200106 void *io_mem_base = (void *)(uintptr_t)gbe_tsn_res->base;
Mario Scheithauerdccdace2022-04-27 11:24:05 +0200107 config_t *config = config_of(dev);
Mario Scheithauerd691c212022-04-26 14:16:59 +0200108
109 /* Program MAC address */
Angel Ponsecff5212022-05-16 15:56:36 +0200110 program_mac_address(dev, io_mem_base);
Mario Scheithauerdccdace2022-04-27 11:24:05 +0200111
112 /* Set PHY-to-MAC IRQ polarity according to devicetree */
113 switch (dev->path.pci.devfn) {
114 case PCH_DEVFN_GBE:
115 tsn_set_phy2mac_irq_polarity(io_mem_base, config->pch_tsn_phy_irq_edge);
116 break;
117 case PCH_DEVFN_PSEGBE0:
118 tsn_set_phy2mac_irq_polarity(io_mem_base, config->pse_tsn_phy_irq_edge[0]);
119 break;
120 case PCH_DEVFN_PSEGBE1:
121 tsn_set_phy2mac_irq_polarity(io_mem_base, config->pse_tsn_phy_irq_edge[1]);
122 break;
123 }
Mario Scheithauerd691c212022-04-26 14:16:59 +0200124}
125
Mario Scheithauereda66c32022-04-26 13:50:52 +0200126static struct device_operations gbe_tsn_ops = {
127 .read_resources = pci_dev_read_resources,
128 .set_resources = pci_dev_set_resources,
129 .enable_resources = pci_dev_enable_resources,
Mario Scheithauerd691c212022-04-26 14:16:59 +0200130 .init = gbe_tsn_init,
Mario Scheithauereda66c32022-04-26 13:50:52 +0200131};
132
Mario Scheithauer5b757b52022-05-19 12:06:33 +0200133static const unsigned short gbe_tsn_device_ids[] = {
134 PCI_DID_INTEL_EHL_GBE_HOST,
135 PCI_DID_INTEL_EHL_GBE_PSE_0,
136 PCI_DID_INTEL_EHL_GBE_PSE_1,
137 0
138};
Mario Scheithauereda66c32022-04-26 13:50:52 +0200139
140static const struct pci_driver gbe_tsn_driver __pci_driver = {
141 .ops = &gbe_tsn_ops,
142 .vendor = PCI_VID_INTEL,
143 .devices = gbe_tsn_device_ids,
144};