blob: ac005d8931039f604ee09e6a5d225c024655a995 [file] [log] [blame]
Stefan Reinauerd7bd4eb2013-02-11 11:11:36 -08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2007-2009 coresystems GmbH
Stefan Reinauerfe8290d2013-04-23 15:00:02 -07005 * Copyright (C) 2011-2012 Google Inc.
Stefan Reinauerd7bd4eb2013-02-11 11:11:36 -08006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Stefan Reinauerd7bd4eb2013-02-11 11:11:36 -080015 */
16
17#include <types.h>
18#include <string.h>
Aaron Durbin0424c952015-03-28 23:56:22 -050019#include <cbfs.h>
Stefan Reinauerd7bd4eb2013-02-11 11:11:36 -080020#include <device/device.h>
21#include <device/pci_def.h>
22#include <device/pci_ops.h>
23#include <console/console.h>
Vladimir Serbinenkoa2a906e2014-09-01 01:41:37 +020024#include <drivers/intel/gma/int15.h>
Aaron Durbin0424c952015-03-28 23:56:22 -050025#include <fmap.h>
Stefan Reinauerd7bd4eb2013-02-11 11:11:36 -080026#include <pc80/mc146818rtc.h>
27#include <arch/acpi.h>
28#include <arch/io.h>
29#include <arch/interrupt.h>
Stefan Reinauer3e4e3032013-03-20 14:08:04 -070030#include <boot/coreboot_tables.h>
Stefan Reinauerd7bd4eb2013-02-11 11:11:36 -080031#include "onboard.h"
32#include "ec.h"
33#include <southbridge/intel/bd82x6x/pch.h>
34#include <smbios.h>
35#include <device/pci.h>
36#include <ec/quanta/ene_kb3940q/ec.h>
Stefan Reinauerd7bd4eb2013-02-11 11:11:36 -080037
38static unsigned int search(char *p, char *a, unsigned int lengthp,
39 unsigned int lengtha)
40{
41 int i, j;
42
43 /* Searching */
44 for (j = 0; j <= lengtha - lengthp; j++) {
45 for (i = 0; i < lengthp && p[i] == a[i + j]; i++) ;
46 if (i >= lengthp)
47 return j;
48 }
49 return lengtha;
50}
51
52static unsigned char get_hex_digit(char *offset)
53{
54 unsigned char retval = 0;
55
56 retval = *offset - '0';
57 if (retval > 0x09) {
58 retval = *offset - 'A' + 0x0A;
59 if (retval > 0x0F)
60 retval = *offset - 'a' + 0x0a;
61 }
62 if (retval > 0x0F) {
63 printk(BIOS_DEBUG, "Error: Invalid Hex digit found: %c - 0x%02x\n",
64 *offset, (unsigned char)*offset);
65 retval = 0;
66 }
67
68 return retval;
69}
70
71static int get_mac_address(u32 *high_dword, u32 *low_dword,
72 u32 search_address, u32 search_length)
73{
74 char key[] = "ethernet_mac";
75 unsigned int offset;
76 int i;
77
78 offset = search(key, (char *)search_address,
79 sizeof(key) - 1, search_length);
80 if (offset == search_length) {
81 printk(BIOS_DEBUG,
82 "Error: Could not locate '%s' in VPD\n", key);
83 return 0;
84 }
85 printk(BIOS_DEBUG, "Located '%s' in VPD\n", key);
86
87 offset += sizeof(key); /* move to next character */
88 *high_dword = 0;
89
90 /* Fetch the MAC address and put the octets in the correct order to
91 * be programmed.
92 *
93 * From RTL8105E_Series_EEPROM-Less_App_Note_1.1
94 * If the MAC address is 001122334455h:
95 * Write 33221100h to I/O register offset 0x00 via double word access
96 * Write 00005544h to I/O register offset 0x04 via double word access
97 */
98
99 for (i = 0; i < 4; i++) {
100 *high_dword |= (get_hex_digit((char *)(search_address + offset))
101 << (4 + (i * 8)));
102 *high_dword |= (get_hex_digit((char *)(search_address + offset + 1))
103 << (i * 8));
104 offset += 3;
105 }
106
107 *low_dword = 0;
108 for (i = 0; i < 2; i++) {
109 *low_dword |= (get_hex_digit((char *)(search_address + offset))
110 << (4 + (i * 8)));
111 *low_dword |= (get_hex_digit((char *)(search_address + offset + 1))
112 << (i * 8));
113 offset += 3;
114 }
115
116 return *high_dword | *low_dword;
117}
118
119static void program_mac_address(u16 io_base, u32 search_address,
120 u32 search_length)
121{
122 /* Default MAC Address of A0:00:BA:D0:0B:AD */
123 u32 high_dword = 0xD0BA00A0; /* high dword of mac address */
124 u32 low_dword = 0x0000AD0B; /* low word of mac address as a dword */
125
126 if (search_length != -1)
127 get_mac_address(&high_dword, &low_dword, search_address,
128 search_length);
129
130 if (io_base) {
131 printk(BIOS_DEBUG, "Realtek NIC io_base = 0x%04x\n", io_base);
132 printk(BIOS_DEBUG, "Programming MAC Address\n");
133
134 outb(0xc0, io_base + 0x50); /* Disable register protection */
135 outl(high_dword, io_base);
136 outl(low_dword, io_base + 0x04);
137 outb(0x60, io_base + 54);
138 outb(0x00, io_base + 0x50); /* Enable register protection again */
139 }
140}
141
142static void program_keyboard_type(u32 search_address, u32 search_length)
143{
144 char key[] = "keyboard_layout";
145 char kbd_jpn[] = "xkb:jp::jpn";
146 unsigned int offset;
147 char kbd_type = EC_KBD_EN; /* Default keyboard type is English */
148
149 if (search_length != -1) {
150
151 /*
152 * Search for keyboard_layout identifier
153 * The only options in the EC are Japanese or English.
154 * The English keyboard layout is actually used for multiple
155 * different languages - English, Spanish, French... Because
156 * of this the code only searches for Japanese, and sets the
157 * keyboard type to English if Japanese is not found.
158 */
159 offset = search(key, (char *)search_address, sizeof(key) - 1,
160 search_length);
161 if (offset != search_length) {
162 printk(BIOS_DEBUG, "Located '%s' in VPD\n", key);
163
164 offset += sizeof(key); /* move to next character */
165 search_length = sizeof(kbd_jpn);
166 offset = search(kbd_jpn, (char *)(search_address + offset),
167 sizeof(kbd_jpn) - 1, search_length);
168 if (offset != search_length)
169 kbd_type = EC_KBD_JP;
170 }
171 } else
172 printk(BIOS_DEBUG, "Error: Could not locate VPD area\n");
173
174
175 printk(BIOS_DEBUG, "Setting Keyboard type in EC to ");
176 printk(BIOS_DEBUG, (kbd_type == EC_KBD_JP) ? "Japanese" : "English");
177 printk(BIOS_DEBUG, ".\n");
178
179 ec_mem_write(EC_KBID_REG, kbd_type);
180}
181
Stefan Reinauerd7bd4eb2013-02-11 11:11:36 -0800182static void mainboard_init(device_t dev)
183{
Kyösti Mälkkifab0c9f2013-11-28 18:10:03 +0200184 u32 search_address = 0x0;
Vladimir Serbinenko12874162014-01-12 14:12:15 +0100185 size_t search_length = -1;
Stefan Reinauerd7bd4eb2013-02-11 11:11:36 -0800186 u16 io_base = 0;
187 struct device *ethernet_dev = NULL;
Aaron Durbin0424c952015-03-28 23:56:22 -0500188 void *vpd_file;
189
190 if (IS_ENABLED(CONFIG_CHROMEOS)) {
191 struct region_device rdev;
192
193 if (fmap_locate_area_as_rdev("RO_VPD", &rdev) == 0) {
194 vpd_file = rdev_mmap_full(&rdev);
195
196 if (vpd_file != NULL) {
197 search_length = region_device_sz(&rdev);
198 search_address = (uintptr_t)vpd_file;
199 }
200 }
Vladimir Serbinenko12874162014-01-12 14:12:15 +0100201 } else {
Aaron Durbin899d13d2015-05-15 23:39:23 -0500202 vpd_file = cbfs_boot_map_with_leak("vpd.bin", CBFS_TYPE_RAW,
203 &search_length);
Aaron Durbin0424c952015-03-28 23:56:22 -0500204 if (vpd_file) {
205 search_address = (unsigned long)vpd_file;
206 } else {
207 search_length = -1;
208 search_address = 0;
209 }
Kyösti Mälkkifab0c9f2013-11-28 18:10:03 +0200210 }
Stefan Reinauerd7bd4eb2013-02-11 11:11:36 -0800211
212 /* Initialize the Embedded Controller */
213 butterfly_ec_init();
214
215 /* Program EC Keyboard locale based on VPD data */
216 program_keyboard_type(search_address, search_length);
217
218 /* Get NIC's IO base address */
219 ethernet_dev = dev_find_device(BUTTERFLY_NIC_VENDOR_ID,
220 BUTTERFLY_NIC_DEVICE_ID, dev);
221 if (ethernet_dev != NULL) {
222 io_base = pci_read_config16(ethernet_dev, 0x10) & 0xfffe;
223
224 /*
225 * Battery life time - LAN PCIe should enter ASPM L1 to save
226 * power when LAN connection is idle.
227 * enable CLKREQ: LAN pci config space 0x81h=01
228 */
229 pci_write_config8(ethernet_dev, 0x81, 0x01);
230 }
231
232 if (io_base) {
233 /* Program MAC address based on VPD data */
234 program_mac_address(io_base, search_address, search_length);
235
236 /*
237 * Program NIC LEDS
238 *
239 * RTL8105E Series EEPROM-Less Application Note,
240 * Section 5.6 LED Mode Configuration
241 *
242 * Step1: Write C0h to I/O register 0x50 via byte access to
243 * disable 'register protection'
244 * Step2: Write xx001111b to I/O register 0x52 via byte access
245 * (bit7 is LEDS1 and bit6 is LEDS0)
246 * Step3: Write 0x00 to I/O register 0x50 via byte access to
247 * enable 'register protection'
248 */
249 outb(0xc0, io_base + 0x50); /* Disable protection */
250 outb((BUTTERFLY_NIC_LED_MODE << 6) | 0x0f, io_base + 0x52);
251 outb(0x00, io_base + 0x50); /* Enable register protection */
252 }
253}
254
Stefan Reinauerd7bd4eb2013-02-11 11:11:36 -0800255static int butterfly_onboard_smbios_data(device_t dev, int *handle,
256 unsigned long *current)
257{
258 int len = 0;
259
Duncan Laurie21a78702013-05-23 14:17:05 -0700260 len += smbios_write_type41(
261 current, handle,
Kyösti Mälkkib9cd5ec2015-04-24 16:05:58 +0300262 BOARD_TRACKPAD_NAME, /* name */
263 BOARD_TRACKPAD_IRQ, /* instance */
Duncan Laurie21a78702013-05-23 14:17:05 -0700264 0, /* segment */
Kyösti Mälkkib9cd5ec2015-04-24 16:05:58 +0300265 BOARD_TRACKPAD_I2C_ADDR, /* bus */
Duncan Laurie21a78702013-05-23 14:17:05 -0700266 0, /* device */
267 0); /* function */
Stefan Reinauerd7bd4eb2013-02-11 11:11:36 -0800268
269 return len;
270}
271
272// mainboard_enable is executed as first thing after
273// enumerate_buses().
274
275static void mainboard_enable(device_t dev)
276{
277 dev->ops->init = mainboard_init;
278 dev->ops->get_smbios_data = butterfly_onboard_smbios_data;
Vladimir Serbinenkoa2a906e2014-09-01 01:41:37 +0200279 install_intel_vga_int15_handler(GMA_INT15_ACTIVE_LFP_INT_LVDS, GMA_INT15_PANEL_FIT_DEFAULT, GMA_INT15_BOOT_DISPLAY_DEFAULT, 0);
Stefan Reinauerd7bd4eb2013-02-11 11:11:36 -0800280}
281
282struct chip_operations mainboard_ops = {
Stefan Reinauerd7bd4eb2013-02-11 11:11:36 -0800283 .enable_dev = mainboard_enable,
284};