• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <cbfs.h>
4 #include <fmap.h>
5 #include <types.h>
6 #include <arch/io.h>
7 #include <device/pci_ops.h>
8 #include <console/console.h>
9 #include <device/device.h>
10 #include <soc/pch.h>
11 #include "onboard.h"
12 
search(char * p,u8 * a,unsigned int lengthp,unsigned int lengtha)13 static unsigned int search(char *p, u8 *a, unsigned int lengthp,
14 			   unsigned int lengtha)
15 {
16 	int i, j;
17 
18 	/* Searching */
19 	for (j = 0; j <= lengtha - lengthp; j++) {
20 		for (i = 0; i < lengthp && p[i] == a[i + j]; i++)
21 			;
22 		if (i >= lengthp)
23 			return j;
24 	}
25 	return lengtha;
26 }
27 
get_hex_digit(u8 * offset)28 static unsigned char get_hex_digit(u8 *offset)
29 {
30 	unsigned char retval = 0;
31 
32 	retval = *offset - '0';
33 	if (retval > 0x09) {
34 		retval = *offset - 'A' + 0x0A;
35 		if (retval > 0x0F)
36 			retval = *offset - 'a' + 0x0a;
37 	}
38 	if (retval > 0x0F) {
39 		printk(BIOS_ERR, "Invalid Hex digit found: %c - 0x%02x\n", *offset, *offset);
40 		retval = 0;
41 	}
42 
43 	return retval;
44 }
45 
get_mac_address(u32 * high_dword,u32 * low_dword,u8 * search_address,u32 search_length)46 static int get_mac_address(u32 *high_dword, u32 *low_dword,
47 			   u8 *search_address, u32 search_length)
48 {
49 	char key[] = "ethernet_mac";
50 	unsigned int offset;
51 	int i;
52 
53 	offset = search(key, search_address, sizeof(key) - 1, search_length);
54 	if (offset == search_length) {
55 		printk(BIOS_ERR, "Could not locate '%s' in VPD\n", key);
56 		return 0;
57 	}
58 	printk(BIOS_DEBUG, "Located '%s' in VPD\n", key);
59 
60 	offset += sizeof(key);	/* move to next character */
61 	*high_dword = 0;
62 
63 	/* Fetch the MAC address and put the octets in the correct order to
64 	 * be programmed.
65 	 *
66 	 * From RTL8105E_Series_EEPROM-Less_App_Note_1.1
67 	 * If the MAC address is 001122334455h:
68 	 * Write 33221100h to I/O register offset 0x00 via double word access
69 	 * Write 00005544h to I/O register offset 0x04 via double word access
70 	 */
71 
72 	for (i = 0; i < 4; i++) {
73 		*high_dword |= (get_hex_digit(search_address + offset)
74 				<< (4 + (i * 8)));
75 		*high_dword |= (get_hex_digit(search_address + offset + 1)
76 				<< (i * 8));
77 		offset += 3;
78 	}
79 
80 	*low_dword = 0;
81 	for (i = 0; i < 2; i++) {
82 		*low_dword |= (get_hex_digit(search_address + offset)
83 			       << (4 + (i * 8)));
84 		*low_dword |= (get_hex_digit(search_address + offset + 1)
85 			       << (i * 8));
86 		offset += 3;
87 	}
88 
89 	return *high_dword | *low_dword;
90 }
91 
program_mac_address(u16 io_base)92 static void program_mac_address(u16 io_base)
93 {
94 	void *search_address = NULL;
95 	size_t search_length = -1;
96 
97 	/* Default MAC Address of A0:00:BA:D0:0B:AD */
98 	u32 high_dword = 0xD0BA00A0;	/* high dword of mac address */
99 	u32 low_dword = 0x0000AD0B;	/* low word of mac address as a dword */
100 
101 	if (CONFIG(VPD)) {
102 		struct region_device rdev;
103 
104 		if (fmap_locate_area_as_rdev("RO_VPD", &rdev) == 0) {
105 			search_address = rdev_mmap_full(&rdev);
106 
107 			if (search_address != NULL)
108 				search_length = region_device_sz(&rdev);
109 		}
110 	} else {
111 		search_address = cbfs_map("vpd.bin", &search_length);
112 	}
113 
114 	if (search_address == NULL)
115 		printk(BIOS_ERR, "LAN: VPD not found.\n");
116 	else
117 		get_mac_address(&high_dword, &low_dword, search_address,
118 				search_length);
119 
120 	if (io_base) {
121 		printk(BIOS_DEBUG, "Realtek NIC io_base = 0x%04x\n", io_base);
122 		printk(BIOS_DEBUG, "Programming MAC Address\n");
123 
124 		/* Disable register protection */
125 		outb(0xc0, io_base + 0x50);
126 		outl(high_dword, io_base);
127 		outl(low_dword, io_base + 0x04);
128 		outb(0x60, io_base + 54);
129 		/* Enable register protection again */
130 		outb(0x00, io_base + 0x50);
131 	}
132 }
133 
lan_init(void)134 void lan_init(void)
135 {
136 	u16 io_base = 0;
137 	struct device *ethernet_dev = NULL;
138 
139 	/* Get NIC's IO base address */
140 	ethernet_dev = dev_find_device(JECHT_NIC_VENDOR_ID,
141 				       JECHT_NIC_DEVICE_ID, 0);
142 	if (ethernet_dev != NULL) {
143 		io_base = pci_read_config16(ethernet_dev, 0x10) & 0xfffe;
144 
145 		/*
146 		 * Battery life time - LAN PCIe should enter ASPM L1 to save
147 		 * power when LAN connection is idle.
148 		 * enable CLKREQ: LAN pci config space 0x81h=01
149 		 */
150 		pci_write_config8(ethernet_dev, 0x81, 0x01);
151 	}
152 
153 	if (io_base) {
154 		/* Program MAC address based on VPD data */
155 		program_mac_address(io_base);
156 
157 		/*
158 		 * Program NIC LEDS
159 		 *
160 		 * RTL8105E Series EEPROM-Less Application Note,
161 		 * Section 5.6 LED Mode Configuration
162 		 *
163 		 * Step1: Write C0h to I/O register 0x50 via byte access to
164 		 *        disable 'register protection'
165 		 * Step2: Write xx001111b to I/O register 0x52 via byte access
166 		 *        (bit7 is LEDS1 and bit6 is LEDS0)
167 		 * Step3: Write 0x00 to I/O register 0x50 via byte access to
168 		 *        enable 'register protection'
169 		 */
170 		outb(0xc0, io_base + 0x50);	/* Disable protection */
171 		outb((JECHT_NIC_LED_MODE << 6) | 0x0f, io_base + 0x52);
172 		outb(0x00, io_base + 0x50);	/* Enable register protection */
173 	}
174 }
175