blob: 6092824b84ab8673a71f8954485a4141581b4d98 [file] [log] [blame]
Mario Scheithauereda66c32022-04-26 13:50:52 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <console/console.h>
Mario Scheithauerc16a7fc72022-11-02 16:00:27 +01004#include <delay.h>
5#include <device/mdio.h>
Mario Scheithauereda66c32022-04-26 13:50:52 +02006#include <device/pci.h>
7#include <device/pci_ids.h>
Mario Scheithauerc16a7fc72022-11-02 16:00:27 +01008#include <device/pci_ops.h>
Mario Scheithauerc8c64c12022-09-29 15:25:48 +02009#include <intelblocks/lpss.h>
Mario Scheithauerdccdace2022-04-27 11:24:05 +020010#include <soc/soc_chip.h>
Mario Scheithauereda66c32022-04-26 13:50:52 +020011#include <soc/tsn_gbe.h>
Mario Scheithauerdccdace2022-04-27 11:24:05 +020012#include <timer.h>
Mario Scheithauereda66c32022-04-26 13:50:52 +020013
Mario Scheithauerd691c212022-04-26 14:16:59 +020014static void program_mac_address(struct device *dev, void *base)
15{
16 enum cb_err status;
17 uint8_t mac[MAC_ADDR_LEN];
18
19 /* Check first whether there is a valid MAC address available */
20 status = mainboard_get_mac_address(dev, mac);
21 if (status != CB_SUCCESS) {
22 printk(BIOS_INFO, "TSN GbE: No valid MAC address found\n");
23 return;
24 }
25
26 printk(BIOS_DEBUG, "TSN GbE: Programming MAC Address...\n");
27
28 /* Write the upper 16 bits of the first 6-byte MAC address */
Angel Ponsecff5212022-05-16 15:56:36 +020029 clrsetbits32(base + TSN_MAC_ADD0_HIGH, 0xffff, ((mac[5] << 8) | mac[4]));
Mario Scheithauerd691c212022-04-26 14:16:59 +020030 /* Write the lower 32 bits of the first 6-byte MAC address */
Angel Ponsecff5212022-05-16 15:56:36 +020031 clrsetbits32(base + TSN_MAC_ADD0_LOW, 0xffffffff,
Mario Scheithauerd691c212022-04-26 14:16:59 +020032 (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]);
33}
34
Mario Scheithauerdccdace2022-04-27 11:24:05 +020035
Mario Scheithauerc16a7fc72022-11-02 16:00:27 +010036static void tsn_set_phy2mac_irq_polarity(struct device *dev, enum tsn_phy_irq_polarity pol)
Mario Scheithauerdccdace2022-04-27 11:24:05 +020037{
38 uint16_t gcr_reg;
Mario Scheithauerc16a7fc72022-11-02 16:00:27 +010039 const struct mdio_bus_operations *mdio_ops;
40
41 mdio_ops = dev_get_mdio_ops(dev);
42 if (!mdio_ops)
43 return;
Mario Scheithauerdccdace2022-04-27 11:24:05 +020044
45 if (pol == RISING_EDGE) {
46 /* Read TSN adhoc PHY sublayer register - global configuration register */
Mario Scheithauerc16a7fc72022-11-02 16:00:27 +010047 gcr_reg = mdio_ops->read(dev, TSN_MAC_MDIO_ADHOC_ADR, TSN_MAC_MDIO_GCR);
Mario Scheithauerdccdace2022-04-27 11:24:05 +020048 gcr_reg |= TSN_MAC_PHY2MAC_INTR_POL;
Mario Scheithauerc16a7fc72022-11-02 16:00:27 +010049 mdio_ops->write(dev, TSN_MAC_MDIO_ADHOC_ADR, TSN_MAC_MDIO_GCR, gcr_reg);
Mario Scheithauerdccdace2022-04-27 11:24:05 +020050 }
51}
52
Mario Scheithauerc8c64c12022-09-29 15:25:48 +020053static void gbe_tsn_enable(struct device *dev)
54{
55 /* Ensure controller is in D0 state. */
56 lpss_set_power_state(PCI_DEV(0, PCI_SLOT(dev->path.pci.devfn),
57 PCI_FUNC(dev->path.pci.devfn)), STATE_D0);
58}
59
Mario Scheithauerd691c212022-04-26 14:16:59 +020060static void gbe_tsn_init(struct device *dev)
61{
62 /* Get the base address of the I/O registers in memory space */
63 struct resource *gbe_tsn_res = find_resource(dev, PCI_BASE_ADDRESS_0);
Angel Ponsecff5212022-05-16 15:56:36 +020064 void *io_mem_base = (void *)(uintptr_t)gbe_tsn_res->base;
Mario Scheithauerdccdace2022-04-27 11:24:05 +020065 config_t *config = config_of(dev);
Mario Scheithauerd691c212022-04-26 14:16:59 +020066
67 /* Program MAC address */
Angel Ponsecff5212022-05-16 15:56:36 +020068 program_mac_address(dev, io_mem_base);
Mario Scheithauerdccdace2022-04-27 11:24:05 +020069
70 /* Set PHY-to-MAC IRQ polarity according to devicetree */
71 switch (dev->path.pci.devfn) {
72 case PCH_DEVFN_GBE:
Mario Scheithauerc16a7fc72022-11-02 16:00:27 +010073 tsn_set_phy2mac_irq_polarity(dev, config->pch_tsn_phy_irq_edge);
Mario Scheithauerdccdace2022-04-27 11:24:05 +020074 break;
75 case PCH_DEVFN_PSEGBE0:
Mario Scheithauerc16a7fc72022-11-02 16:00:27 +010076 tsn_set_phy2mac_irq_polarity(dev, config->pse_tsn_phy_irq_edge[0]);
Mario Scheithauerdccdace2022-04-27 11:24:05 +020077 break;
78 case PCH_DEVFN_PSEGBE1:
Mario Scheithauerc16a7fc72022-11-02 16:00:27 +010079 tsn_set_phy2mac_irq_polarity(dev, config->pse_tsn_phy_irq_edge[1]);
Mario Scheithauerdccdace2022-04-27 11:24:05 +020080 break;
81 }
Mario Scheithauerd691c212022-04-26 14:16:59 +020082}
83
Mario Scheithauerc16a7fc72022-11-02 16:00:27 +010084static enum cb_err phy_gmii_ready(void *base)
85{
86 struct stopwatch sw;
87
88 stopwatch_init_msecs_expire(&sw, GMII_TIMEOUT_MS);
89 do {
90 if (!(read32((base + MAC_MDIO_ADR)) & MAC_GMII_BUSY))
91 return CB_SUCCESS;
92 mdelay(1);
93 } while (!stopwatch_expired(&sw));
94
95 printk(BIOS_ERR, "%s Timeout after %lld msec\n", __func__,
96 stopwatch_duration_msecs(&sw));
97 return CB_ERR;
98}
99
100static uint16_t tsn_mdio_read(struct device *dev, uint8_t phy_adr, uint8_t reg_adr)
101{
102 uint16_t data = 0;
103 struct resource *gbe_tsn_res = find_resource(dev, PCI_BASE_ADDRESS_0);
104 void *mmio_base = res2mmio(gbe_tsn_res, 0, 0);
105
106 if (!mmio_base)
107 return data;
108
109 clrsetbits32(mmio_base + MAC_MDIO_ADR, MAC_MDIO_ADR_MASK,
110 MAC_PHYAD(phy_adr) | MAC_REGAD(reg_adr)
111 | MAC_CLK_TRAIL_4 | MAC_CSR_CLK_DIV_102
112 | MAC_OP_CMD_READ | MAC_GMII_BUSY);
113
114 /* Wait for MDIO frame transfer to complete before reading MDIO DATA register. */
115 if (phy_gmii_ready(mmio_base) != CB_SUCCESS) {
116 printk(BIOS_ERR, "%s TSN GMII busy. PHY Adr: 0x%x, Reg 0x%x\n",
117 __func__, phy_adr, reg_adr);
118 } else {
119 data = read16(mmio_base + MAC_MDIO_DATA);
120 printk(BIOS_SPEW, "%s PHY Adr: 0x%x, Reg: 0x%x , Data: 0x%x\n",
121 __func__, phy_adr, reg_adr, data);
122 }
123 return data;
124}
125
126static void tsn_mdio_write(struct device *dev, uint8_t phy_adr, uint8_t reg_adr, uint16_t data)
127{
128 struct resource *gbe_tsn_res = find_resource(dev, PCI_BASE_ADDRESS_0);
129 void *mmio_base = res2mmio(gbe_tsn_res, 0, 0);
130
131 if (!mmio_base)
132 return;
133
134 write16(mmio_base + MAC_MDIO_DATA, data);
135 clrsetbits32(mmio_base + MAC_MDIO_ADR, MAC_MDIO_ADR_MASK,
136 MAC_PHYAD(phy_adr) | MAC_REGAD(reg_adr)
137 | MAC_CLK_TRAIL_4 | MAC_CSR_CLK_DIV_102
138 | MAC_OP_CMD_WRITE | MAC_GMII_BUSY);
139
140 /* Wait for MDIO frame transfer to complete before exit. */
141 if (phy_gmii_ready(mmio_base) != CB_SUCCESS)
142 printk(BIOS_ERR, "%s TSN GMII busy. PHY Adr: 0x%x, Reg 0x%x\n",
143 __func__, phy_adr, reg_adr);
144 else
145 printk(BIOS_SPEW, "%s PHY Adr: 0x%x, Reg: 0x%x , Data: 0x%x\n",
146 __func__, phy_adr, reg_adr, data);
147}
148
149static struct mdio_bus_operations mdio_ops = {
150 .read = tsn_mdio_read,
151 .write = tsn_mdio_write,
152};
153
Mario Scheithauereda66c32022-04-26 13:50:52 +0200154static struct device_operations gbe_tsn_ops = {
155 .read_resources = pci_dev_read_resources,
156 .set_resources = pci_dev_set_resources,
157 .enable_resources = pci_dev_enable_resources,
Mario Scheithauerbf89aae2022-11-08 13:23:49 +0100158 .scan_bus = scan_generic_bus,
Mario Scheithauerc8c64c12022-09-29 15:25:48 +0200159 .enable = gbe_tsn_enable,
Mario Scheithauerd691c212022-04-26 14:16:59 +0200160 .init = gbe_tsn_init,
Mario Scheithauerc16a7fc72022-11-02 16:00:27 +0100161 .ops_mdio = &mdio_ops,
Mario Scheithauereda66c32022-04-26 13:50:52 +0200162};
163
Mario Scheithauer5b757b52022-05-19 12:06:33 +0200164static const unsigned short gbe_tsn_device_ids[] = {
165 PCI_DID_INTEL_EHL_GBE_HOST,
166 PCI_DID_INTEL_EHL_GBE_PSE_0,
167 PCI_DID_INTEL_EHL_GBE_PSE_1,
168 0
169};
Mario Scheithauereda66c32022-04-26 13:50:52 +0200170
171static const struct pci_driver gbe_tsn_driver __pci_driver = {
172 .ops = &gbe_tsn_ops,
173 .vendor = PCI_VID_INTEL,
174 .devices = gbe_tsn_device_ids,
175};