• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <delay.h>
5 #include <device/mdio.h>
6 #include <device/pci.h>
7 #include <device/pci_ids.h>
8 #include <device/pci_ops.h>
9 #include <intelblocks/lpss.h>
10 #include <soc/soc_chip.h>
11 #include <soc/tsn_gbe.h>
12 #include <timer.h>
13 
program_mac_address(struct device * dev,void * base)14 static 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 */
29 	clrsetbits32(base + TSN_MAC_ADD0_HIGH, 0xffff, ((mac[5] << 8) | mac[4]));
30 	/* Write the lower 32 bits of the first 6-byte MAC address */
31 	clrsetbits32(base + TSN_MAC_ADD0_LOW, 0xffffffff,
32 			(mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]);
33 }
34 
35 
tsn_set_phy2mac_irq_polarity(struct device * dev,enum tsn_phy_irq_polarity pol)36 static void tsn_set_phy2mac_irq_polarity(struct device *dev, enum tsn_phy_irq_polarity pol)
37 {
38 	uint16_t gcr_reg;
39 	const struct mdio_bus_operations *mdio_ops;
40 
41 	mdio_ops = dev_get_mdio_ops(dev);
42 	if (!mdio_ops)
43 		return;
44 
45 	if (pol == RISING_EDGE) {
46 		/* Read TSN adhoc PHY sublayer register - global configuration register */
47 		gcr_reg = mdio_ops->read(dev, TSN_MAC_MDIO_ADHOC_ADR, TSN_MAC_MDIO_GCR);
48 		gcr_reg |= TSN_MAC_PHY2MAC_INTR_POL;
49 		mdio_ops->write(dev, TSN_MAC_MDIO_ADHOC_ADR, TSN_MAC_MDIO_GCR, gcr_reg);
50 	}
51 }
52 
gbe_tsn_enable(struct device * dev)53 static 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 
gbe_tsn_init(struct device * dev)60 static 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);
64 	void *io_mem_base = (void *)(uintptr_t)gbe_tsn_res->base;
65 	config_t *config = config_of(dev);
66 
67 	/* Program MAC address */
68 	program_mac_address(dev, io_mem_base);
69 
70 	/* Set PHY-to-MAC IRQ polarity according to devicetree */
71 	switch (dev->path.pci.devfn) {
72 	case PCH_DEVFN_GBE:
73 		tsn_set_phy2mac_irq_polarity(dev, config->pch_tsn_phy_irq_edge);
74 		break;
75 	case PCH_DEVFN_PSEGBE0:
76 		tsn_set_phy2mac_irq_polarity(dev, config->pse_tsn_phy_irq_edge[0]);
77 		break;
78 	case PCH_DEVFN_PSEGBE1:
79 		tsn_set_phy2mac_irq_polarity(dev, config->pse_tsn_phy_irq_edge[1]);
80 		break;
81 	}
82 }
83 
phy_gmii_ready(void * base)84 static 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 
tsn_mdio_read(struct device * dev,uint8_t phy_adr,uint8_t reg_adr)100 static 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 
tsn_mdio_write(struct device * dev,uint8_t phy_adr,uint8_t reg_adr,uint16_t data)126 static 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 
149 static struct mdio_bus_operations mdio_ops = {
150 	.read			= tsn_mdio_read,
151 	.write			= tsn_mdio_write,
152 };
153 
154 static 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,
158 	.scan_bus         = scan_generic_bus,
159 	.enable           = gbe_tsn_enable,
160 	.init             = gbe_tsn_init,
161 	.ops_mdio         = &mdio_ops,
162 };
163 
164 static 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 };
170 
171 static 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 };
176