coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
mainboard.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <types.h>
4 #include <cbfs.h>
5 #include <device/device.h>
6 #include <device/pci_ops.h>
7 #include <console/console.h>
9 #include <fmap.h>
10 #include <arch/io.h>
11 #include "onboard.h"
12 #include "ec.h"
14 #include <smbios.h>
16 
17 static unsigned int search(char *p, char *a, unsigned int lengthp,
18  unsigned int lengtha)
19 {
20  int i, j;
21 
22  /* Searching */
23  for (j = 0; j <= lengtha - lengthp; j++) {
24  for (i = 0; i < lengthp && p[i] == a[i + j]; i++)
25  ;
26  if (i >= lengthp)
27  return j;
28  }
29  return lengtha;
30 }
31 
32 static unsigned char get_hex_digit(char *offset)
33 {
34  unsigned char retval = 0;
35 
36  retval = *offset - '0';
37  if (retval > 0x09) {
38  retval = *offset - 'A' + 0x0A;
39  if (retval > 0x0F)
40  retval = *offset - 'a' + 0x0a;
41  }
42  if (retval > 0x0F) {
43  printk(BIOS_DEBUG, "Error: Invalid Hex digit found: %c - 0x%02x\n",
44  *offset, (unsigned char)*offset);
45  retval = 0;
46  }
47 
48  return retval;
49 }
50 
51 static int get_mac_address(u32 *high_dword, u32 *low_dword,
52  u32 search_address, u32 search_length)
53 {
54  char key[] = "ethernet_mac";
55  unsigned int offset;
56  int i;
57 
58  offset = search(key, (char *)search_address,
59  sizeof(key) - 1, search_length);
60  if (offset == search_length) {
62  "Error: Could not locate '%s' in VPD\n", key);
63  return 0;
64  }
65  printk(BIOS_DEBUG, "Located '%s' in VPD\n", key);
66 
67  offset += sizeof(key); /* move to next character */
68  *high_dword = 0;
69 
70  /* Fetch the MAC address and put the octets in the correct order to
71  * be programmed.
72  *
73  * From RTL8105E_Series_EEPROM-Less_App_Note_1.1
74  * If the MAC address is 001122334455h:
75  * Write 33221100h to I/O register offset 0x00 via double word access
76  * Write 00005544h to I/O register offset 0x04 via double word access
77  */
78 
79  for (i = 0; i < 4; i++) {
80  *high_dword |= (get_hex_digit((char *)(search_address + offset))
81  << (4 + (i * 8)));
82  *high_dword |= (get_hex_digit((char *)(search_address + offset + 1))
83  << (i * 8));
84  offset += 3;
85  }
86 
87  *low_dword = 0;
88  for (i = 0; i < 2; i++) {
89  *low_dword |= (get_hex_digit((char *)(search_address + offset))
90  << (4 + (i * 8)));
91  *low_dword |= (get_hex_digit((char *)(search_address + offset + 1))
92  << (i * 8));
93  offset += 3;
94  }
95 
96  return *high_dword | *low_dword;
97 }
98 
99 static void program_mac_address(u16 io_base, u32 search_address,
100  u32 search_length)
101 {
102  /* Default MAC Address of A0:00:BA:D0:0B:AD */
103  u32 high_dword = 0xD0BA00A0; /* high dword of mac address */
104  u32 low_dword = 0x0000AD0B; /* low word of mac address as a dword */
105 
106  if (search_length != -1)
107  get_mac_address(&high_dword, &low_dword, search_address,
108  search_length);
109 
110  if (io_base) {
111  printk(BIOS_DEBUG, "Realtek NIC io_base = 0x%04x\n", io_base);
112  printk(BIOS_DEBUG, "Programming MAC Address\n");
113 
114  outb(0xc0, io_base + 0x50); /* Disable register protection */
115  outl(high_dword, io_base);
116  outl(low_dword, io_base + 0x04);
117  outb(0x60, io_base + 54);
118  outb(0x00, io_base + 0x50); /* Enable register protection again */
119  }
120 }
121 
122 static void program_keyboard_type(u32 search_address, u32 search_length)
123 {
124  char key[] = "keyboard_layout";
125  char kbd_jpn[] = "xkb:jp::jpn";
126  unsigned int offset;
127  char kbd_type = EC_KBD_EN; /* Default keyboard type is English */
128 
129  if (search_length != -1) {
130 
131  /*
132  * Search for keyboard_layout identifier
133  * The only options in the EC are Japanese or English.
134  * The English keyboard layout is actually used for multiple
135  * different languages - English, Spanish, French... Because
136  * of this the code only searches for Japanese, and sets the
137  * keyboard type to English if Japanese is not found.
138  */
139  offset = search(key, (char *)search_address, sizeof(key) - 1,
140  search_length);
141  if (offset != search_length) {
142  printk(BIOS_DEBUG, "Located '%s' in VPD\n", key);
143 
144  offset += sizeof(key); /* move to next character */
145  search_length = sizeof(kbd_jpn);
146  offset = search(kbd_jpn, (char *)(search_address + offset),
147  sizeof(kbd_jpn) - 1, search_length);
148  if (offset != search_length)
149  kbd_type = EC_KBD_JP;
150  }
151  } else {
152  printk(BIOS_DEBUG, "Error: Could not locate VPD area\n");
153  }
154 
155  printk(BIOS_DEBUG, "Setting Keyboard type in EC to ");
156  printk(BIOS_DEBUG, (kbd_type == EC_KBD_JP) ? "Japanese" : "English");
157  printk(BIOS_DEBUG, ".\n");
158 
159  ec_mem_write(EC_KBID_REG, kbd_type);
160 }
161 
162 static void mainboard_init(struct device *dev)
163 {
164  u32 search_address = 0x0;
165  size_t search_length = -1;
166  u16 io_base = 0;
167  struct device *ethernet_dev = NULL;
168  void *vpd_file;
169 
170  if (CONFIG(VPD)) {
171  struct region_device rdev;
172 
173  if (fmap_locate_area_as_rdev("RO_VPD", &rdev) == 0) {
174  vpd_file = rdev_mmap_full(&rdev);
175 
176  if (vpd_file != NULL) {
177  search_length = region_device_sz(&rdev);
178  search_address = (uintptr_t)vpd_file;
179  }
180  }
181  } else {
182  vpd_file = cbfs_map("vpd.bin", &search_length);
183  if (vpd_file) {
184  search_address = (unsigned long)vpd_file;
185  } else {
186  search_length = -1;
187  search_address = 0;
188  }
189  }
190 
191  /* Initialize the Embedded Controller */
193 
194  /* Program EC Keyboard locale based on VPD data */
195  program_keyboard_type(search_address, search_length);
196 
197  /* Get NIC's IO base address */
200  if (ethernet_dev != NULL) {
201  io_base = pci_read_config16(ethernet_dev, 0x10) & 0xfffe;
202 
203  /*
204  * Battery life time - LAN PCIe should enter ASPM L1 to save
205  * power when LAN connection is idle.
206  * enable CLKREQ: LAN pci config space 0x81h=01
207  */
208  pci_write_config8(ethernet_dev, 0x81, 0x01);
209  }
210 
211  if (io_base) {
212  /* Program MAC address based on VPD data */
213  program_mac_address(io_base, search_address, search_length);
214 
215  /*
216  * Program NIC LEDS
217  *
218  * RTL8105E Series EEPROM-Less Application Note,
219  * Section 5.6 LED Mode Configuration
220  *
221  * Step1: Write C0h to I/O register 0x50 via byte access to
222  * disable 'register protection'
223  * Step2: Write xx001111b to I/O register 0x52 via byte access
224  * (bit7 is LEDS1 and bit6 is LEDS0)
225  * Step3: Write 0x00 to I/O register 0x50 via byte access to
226  * enable 'register protection'
227  */
228  outb(0xc0, io_base + 0x50); /* Disable protection */
229  outb((BUTTERFLY_NIC_LED_MODE << 6) | 0x0f, io_base + 0x52);
230  outb(0x00, io_base + 0x50); /* Enable register protection */
231  }
232 }
233 
234 static int butterfly_onboard_smbios_data(struct device *dev, int *handle,
235  unsigned long *current)
236 {
237  int len = 0;
238 
239  len += smbios_write_type41(
240  current, handle,
241  BOARD_TRACKPAD_NAME, /* name */
242  BOARD_TRACKPAD_IRQ, /* instance */
243  0, /* segment */
244  BOARD_TRACKPAD_I2C_ADDR, /* bus */
245  0, /* device */
246  0, /* function */
247  SMBIOS_DEVICE_TYPE_OTHER); /* device type */
248 
249  return len;
250 }
251 
252 // mainboard_enable is executed as first thing after
253 // enumerate_buses().
254 
255 static void mainboard_enable(struct device *dev)
256 {
257  dev->ops->init = mainboard_init;
258  dev->ops->get_smbios_data = butterfly_onboard_smbios_data;
260 }
261 
264 };
struct chip_operations mainboard_ops
Definition: mainboard.c:19
int smbios_write_type41(unsigned long *current, int *handle, const char *name, u8 instance, u16 segment, u8 bus, u8 device, u8 function, u8 device_type)
Definition: smbios.c:1087
static void * cbfs_map(const char *name, size_t *size_out)
Definition: cbfs.h:246
#define printk(level,...)
Definition: stdlib.h:16
void outb(u8 val, u16 port)
void outl(u32 val, u16 port)
struct device * dev_find_device(u16 vendor, u16 device, struct device *from)
Find a device of a given vendor and type.
Definition: device_util.c:42
void install_intel_vga_int15_handler(int active_lfp_, int pfit_, int display_, int panel_type_)
Definition: int15.c:101
@ GMA_INT15_BOOT_DISPLAY_DEFAULT
Definition: int15.h:6
@ GMA_INT15_ACTIVE_LFP_INT_LVDS
Definition: int15.h:25
@ GMA_INT15_PANEL_FIT_DEFAULT
Definition: int15.h:17
@ CONFIG
Definition: dsi_common.h:201
void ec_mem_write(u8 addr, u8 data)
Definition: ec.c:101
#define EC_KBID_REG
Definition: ec.h:118
#define EC_KBD_EN
Definition: ec.h:119
#define EC_KBD_JP
Definition: ec.h:120
static struct region_device rdev
Definition: flashconsole.c:14
static size_t offset
Definition: flashconsole.c:16
int fmap_locate_area_as_rdev(const char *name, struct region_device *area)
Definition: fmap.c:144
#define BOARD_TRACKPAD_NAME
Definition: onboard.h:6
#define BOARD_TRACKPAD_I2C_ADDR
Definition: onboard.h:10
#define BOARD_TRACKPAD_IRQ
Definition: onboard.h:7
static void mainboard_init(struct device *dev)
Definition: mainboard.c:162
static unsigned int search(char *p, char *a, unsigned int lengthp, unsigned int lengtha)
Definition: mainboard.c:17
static void program_keyboard_type(u32 search_address, u32 search_length)
Definition: mainboard.c:122
static unsigned char get_hex_digit(char *offset)
Definition: mainboard.c:32
static int get_mac_address(u32 *high_dword, u32 *low_dword, u32 search_address, u32 search_length)
Definition: mainboard.c:51
static int butterfly_onboard_smbios_data(struct device *dev, int *handle, unsigned long *current)
Definition: mainboard.c:234
static void program_mac_address(u16 io_base, u32 search_address, u32 search_length)
Definition: mainboard.c:99
static void mainboard_enable(struct device *dev)
Definition: mainboard.c:255
#define BUTTERFLY_NIC_DEVICE_ID
Definition: onboard.h:15
#define BUTTERFLY_NIC_LED_MODE
Definition: onboard.h:18
#define BUTTERFLY_NIC_VENDOR_ID
Definition: onboard.h:14
static __always_inline u16 pci_read_config16(const struct device *dev, u16 reg)
Definition: pci_ops.h:52
static __always_inline void pci_write_config8(const struct device *dev, u16 reg, u8 val)
Definition: pci_ops.h:64
@ SMBIOS_DEVICE_TYPE_OTHER
Definition: smbios.h:940
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
void butterfly_ec_init(void)
Definition: ec.c:7
static size_t region_device_sz(const struct region_device *rdev)
Definition: region.h:132
static void * rdev_mmap_full(const struct region_device *rd)
Definition: region.h:148
#define NULL
Definition: stddef.h:19
uint32_t u32
Definition: stdint.h:51
unsigned long uintptr_t
Definition: stdint.h:21
uint16_t u16
Definition: stdint.h:48
void(* enable_dev)(struct device *dev)
Definition: device.h:24
void(* init)(struct device *dev)
Definition: device.h:42
Definition: device.h:107
struct device_operations * ops
Definition: device.h:143