From 2f6d42b9dfc5fb40ad59c5e81dab6298a192452b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 24 Nov 2014 21:18:20 -0700 Subject: x86: Add ivybridge directory to Makefile It is now required to add subdirectories in the x86 cpu Makefile. Add this to fix a build breakage for chromebook_link. Signed-off-by: Simon Glass diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 2b9e9b9..818969f 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -13,4 +13,6 @@ obj-$(CONFIG_X86_RESET_VECTOR) += resetvec.o start16.o obj-y += interrupts.o cpu.o call64.o obj-$(CONFIG_SYS_COREBOOT) += coreboot/ +obj-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += ivybridge/ +obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/ obj-$(CONFIG_PCI) += pci.o -- cgit v0.10.2 From 803f2eb2a29cbde53d8baac4f6e6bef260fd0774 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 24 Nov 2014 21:18:21 -0700 Subject: Fix SIZE_MAX compiler warning when using stdint.h This new symbol may be defined by the compiler. If it is, avoid a compiler warning when USE_STDINT is defined. Signed-off-by: Simon Glass diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 89fcae0..0b61671 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -16,7 +16,9 @@ #define LLONG_MAX ((long long)(~0ULL>>1)) #define LLONG_MIN (-LLONG_MAX - 1) #define ULLONG_MAX (~0ULL) +#ifndef SIZE_MAX #define SIZE_MAX (~(size_t)0) +#endif #define U8_MAX ((u8)~0U) #define S8_MAX ((s8)(U8_MAX>>1)) -- cgit v0.10.2 From 5c30bf435fb91de55c333516fc47415db9701bb7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:19 -0700 Subject: Align embedded device tree correctly Device trees must be aligned to a 4-byte boundary. This was dropped in the Kbuild conversion. Bring it back, and use 16-byte alignment for good measure. Signed-off-by: Simon Glass diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 9d1383a..13af604 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -260,11 +260,13 @@ quiet_cmd_dt_S_dtb= DTB $@ cmd_dt_S_dtb= \ ( \ echo '.section .dtb.init.rodata,"a"'; \ + echo '.balign 16'; \ echo '.global __dtb_$(*F)_begin'; \ echo '__dtb_$(*F)_begin:'; \ echo '.incbin "$<" '; \ echo '__dtb_$(*F)_end:'; \ echo '.global __dtb_$(*F)_end'; \ + echo '.balign 16'; \ ) > $@ $(obj)/%.dtb.S: $(obj)/%.dtb -- cgit v0.10.2 From e3bf4c759be1bf037818100e15af425d16822c29 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:21 -0700 Subject: pci: Update pci_ids.h to include some missing IDs This was taken from Linux 3.18 with some additional IDs from Chrome OS Coreboot commit 688ef385. Signed-off-by: Simon Glass diff --git a/include/pci_ids.h b/include/pci_ids.h index f84c13a..ee98bee 100644 --- a/include/pci_ids.h +++ b/include/pci_ids.h @@ -526,7 +526,19 @@ #define PCI_DEVICE_ID_AMD_11H_NB_DRAM 0x1302 #define PCI_DEVICE_ID_AMD_11H_NB_MISC 0x1303 #define PCI_DEVICE_ID_AMD_11H_NB_LINK 0x1304 -#define PCI_DEVICE_ID_AMD_15H_NB_MISC 0x1603 +#define PCI_DEVICE_ID_AMD_15H_M10H_F3 0x1403 +#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F3 0x141d +#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F4 0x141e +#define PCI_DEVICE_ID_AMD_15H_NB_F0 0x1600 +#define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601 +#define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602 +#define PCI_DEVICE_ID_AMD_15H_NB_F3 0x1603 +#define PCI_DEVICE_ID_AMD_15H_NB_F4 0x1604 +#define PCI_DEVICE_ID_AMD_15H_NB_F5 0x1605 +#define PCI_DEVICE_ID_AMD_16H_NB_F3 0x1533 +#define PCI_DEVICE_ID_AMD_16H_NB_F4 0x1534 +#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F3 0x1583 +#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F4 0x1584 #define PCI_DEVICE_ID_AMD_CNB17H_F3 0x1703 #define PCI_DEVICE_ID_AMD_LANCE 0x2000 #define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001 @@ -569,8 +581,9 @@ #define PCI_DEVICE_ID_AMD_CS5536_IDE 0x209A #define PCI_DEVICE_ID_AMD_LX_VIDEO 0x2081 #define PCI_DEVICE_ID_AMD_LX_AES 0x2082 -#define PCI_DEVICE_ID_AMD_HUDSON2_IDE 0x780c #define PCI_DEVICE_ID_AMD_HUDSON2_SATA_IDE 0x7800 +#define PCI_DEVICE_ID_AMD_HUDSON2_SMBUS 0x780b +#define PCI_DEVICE_ID_AMD_HUDSON2_IDE 0x780c #define PCI_VENDOR_ID_TRIDENT 0x1023 #define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000 @@ -616,6 +629,8 @@ #define PCI_DEVICE_ID_MATROX_G550 0x2527 #define PCI_DEVICE_ID_MATROX_VIA 0x4536 +#define PCI_VENDOR_ID_MOBILITY_ELECTRONICS 0x14f2 + #define PCI_VENDOR_ID_CT 0x102c #define PCI_DEVICE_ID_CT_69000 0x00c0 #define PCI_DEVICE_ID_CT_65545 0x00d8 @@ -724,6 +739,7 @@ #define PCI_DEVICE_ID_SI_7018 0x7018 #define PCI_VENDOR_ID_HP 0x103c +#define PCI_VENDOR_ID_HP_3PAR 0x1590 #define PCI_DEVICE_ID_HP_VISUALIZE_EG 0x1005 #define PCI_DEVICE_ID_HP_VISUALIZE_FX6 0x1006 #define PCI_DEVICE_ID_HP_VISUALIZE_FX4 0x1008 @@ -755,6 +771,8 @@ #define PCI_DEVICE_ID_HP_CISSD 0x3238 #define PCI_DEVICE_ID_HP_CISSE 0x323a #define PCI_DEVICE_ID_HP_CISSF 0x323b +#define PCI_DEVICE_ID_HP_CISSH 0x323c +#define PCI_DEVICE_ID_HP_CISSI 0x3239 #define PCI_DEVICE_ID_HP_ZX2_IOC 0x4031 #define PCI_VENDOR_ID_PCTECH 0x1042 @@ -779,6 +797,29 @@ #define PCI_DEVICE_ID_ELSA_QS3000 0x3000 #define PCI_VENDOR_ID_STMICRO 0x104A +#define PCI_DEVICE_ID_STMICRO_USB_HOST 0xCC00 +#define PCI_DEVICE_ID_STMICRO_USB_OHCI 0xCC01 +#define PCI_DEVICE_ID_STMICRO_USB_OTG 0xCC02 +#define PCI_DEVICE_ID_STMICRO_UART_HWFC 0xCC03 +#define PCI_DEVICE_ID_STMICRO_UART_NO_HWFC 0xCC04 +#define PCI_DEVICE_ID_STMICRO_SOC_DMA 0xCC05 +#define PCI_DEVICE_ID_STMICRO_SATA 0xCC06 +#define PCI_DEVICE_ID_STMICRO_I2C 0xCC07 +#define PCI_DEVICE_ID_STMICRO_SPI_HS 0xCC08 +#define PCI_DEVICE_ID_STMICRO_MAC 0xCC09 +#define PCI_DEVICE_ID_STMICRO_SDIO_EMMC 0xCC0A +#define PCI_DEVICE_ID_STMICRO_SDIO 0xCC0B +#define PCI_DEVICE_ID_STMICRO_GPIO 0xCC0C +#define PCI_DEVICE_ID_STMICRO_VIP 0xCC0D +#define PCI_DEVICE_ID_STMICRO_AUDIO_ROUTER_DMA 0xCC0E +#define PCI_DEVICE_ID_STMICRO_AUDIO_ROUTER_SRCS 0xCC0F +#define PCI_DEVICE_ID_STMICRO_AUDIO_ROUTER_MSPS 0xCC10 +#define PCI_DEVICE_ID_STMICRO_CAN 0xCC11 +#define PCI_DEVICE_ID_STMICRO_MLB 0xCC12 +#define PCI_DEVICE_ID_STMICRO_DBP 0xCC13 +#define PCI_DEVICE_ID_STMICRO_SATA_PHY 0xCC14 +#define PCI_DEVICE_ID_STMICRO_ESRAM 0xCC15 +#define PCI_DEVICE_ID_STMICRO_VIC 0xCC16 #define PCI_VENDOR_ID_BUSLOGIC 0x104B #define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140 @@ -1294,6 +1335,8 @@ #define PCI_VENDOR_ID_TUNDRA 0x10e3 #define PCI_DEVICE_ID_TUNDRA_CA91C042 0x0000 +#define PCI_VENDOR_ID_AMCC 0x10e8 + #define PCI_VENDOR_ID_INTERG 0x10ea #define PCI_DEVICE_ID_INTERG_1682 0x1682 #define PCI_DEVICE_ID_INTERG_2000 0x2000 @@ -1322,6 +1365,7 @@ #define PCI_SUBDEVICE_ID_CREATIVE_SB08801 0x0041 #define PCI_SUBDEVICE_ID_CREATIVE_SB08802 0x0042 #define PCI_SUBDEVICE_ID_CREATIVE_SB08803 0x0043 +#define PCI_SUBDEVICE_ID_CREATIVE_SB1270 0x0062 #define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX 0x6000 #define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */ @@ -1411,6 +1455,7 @@ #define PCI_DEVICE_ID_VIA_CX700_IDE 0x0581 #define PCI_DEVICE_ID_VIA_VX800 0x8353 #define PCI_DEVICE_ID_VIA_VX855 0x8409 +#define PCI_DEVICE_ID_VIA_VX900 0x8410 #define PCI_DEVICE_ID_VIA_8371_1 0x8391 #define PCI_DEVICE_ID_VIA_82C598_1 0x8598 #define PCI_DEVICE_ID_VIA_838X_1 0xB188 @@ -1551,6 +1596,8 @@ #define PCI_DEVICE_ID_RICOH_RL5C476 0x0476 #define PCI_DEVICE_ID_RICOH_RL5C478 0x0478 #define PCI_DEVICE_ID_RICOH_R5C822 0x0822 +#define PCI_DEVICE_ID_RICOH_R5CE822 0xe822 +#define PCI_DEVICE_ID_RICOH_R5CE823 0xe823 #define PCI_DEVICE_ID_RICOH_R5C832 0x0832 #define PCI_DEVICE_ID_RICOH_R5C843 0x0843 @@ -1586,6 +1633,7 @@ #define PCI_SUBDEVICE_ID_KEYSPAN_SX2 0x5334 #define PCI_VENDOR_ID_MARVELL 0x11ab +#define PCI_VENDOR_ID_MARVELL_EXT 0x1b4b #define PCI_DEVICE_ID_MARVELL_GT64111 0x4146 #define PCI_DEVICE_ID_MARVELL_GT64260 0x6430 #define PCI_DEVICE_ID_MARVELL_MV64360 0x6460 @@ -1798,6 +1846,8 @@ #define PCI_VENDOR_ID_ESDGMBH 0x12fe #define PCI_DEVICE_ID_ESDGMBH_CPCIASIO4 0x0111 +#define PCI_VENDOR_ID_CB 0x1307 /* Measurement Computing */ + #define PCI_VENDOR_ID_SIIG 0x131f #define PCI_SUBVENDOR_ID_SIIG 0x131f #define PCI_DEVICE_ID_SIIG_1S_10x_550 0x1000 @@ -1860,8 +1910,23 @@ #define PCI_VENDOR_ID_QUATECH 0x135C #define PCI_DEVICE_ID_QUATECH_QSC100 0x0010 #define PCI_DEVICE_ID_QUATECH_DSC100 0x0020 +#define PCI_DEVICE_ID_QUATECH_DSC200 0x0030 +#define PCI_DEVICE_ID_QUATECH_QSC200 0x0040 #define PCI_DEVICE_ID_QUATECH_ESC100D 0x0050 #define PCI_DEVICE_ID_QUATECH_ESC100M 0x0060 +#define PCI_DEVICE_ID_QUATECH_QSCP100 0x0120 +#define PCI_DEVICE_ID_QUATECH_DSCP100 0x0130 +#define PCI_DEVICE_ID_QUATECH_QSCP200 0x0140 +#define PCI_DEVICE_ID_QUATECH_DSCP200 0x0150 +#define PCI_DEVICE_ID_QUATECH_QSCLP100 0x0170 +#define PCI_DEVICE_ID_QUATECH_DSCLP100 0x0180 +#define PCI_DEVICE_ID_QUATECH_DSC100E 0x0181 +#define PCI_DEVICE_ID_QUATECH_SSCLP100 0x0190 +#define PCI_DEVICE_ID_QUATECH_QSCLP200 0x01A0 +#define PCI_DEVICE_ID_QUATECH_DSCLP200 0x01B0 +#define PCI_DEVICE_ID_QUATECH_DSC200E 0x01B1 +#define PCI_DEVICE_ID_QUATECH_SSCLP200 0x01C0 +#define PCI_DEVICE_ID_QUATECH_ESCLP100 0x01E0 #define PCI_DEVICE_ID_QUATECH_SPPXP_100 0x0278 #define PCI_VENDOR_ID_SEALEVEL 0x135e @@ -1978,6 +2043,9 @@ #define PCI_DEVICE_ID_EXAR_XR17C152 0x0152 #define PCI_DEVICE_ID_EXAR_XR17C154 0x0154 #define PCI_DEVICE_ID_EXAR_XR17C158 0x0158 +#define PCI_DEVICE_ID_EXAR_XR17V352 0x0352 +#define PCI_DEVICE_ID_EXAR_XR17V354 0x0354 +#define PCI_DEVICE_ID_EXAR_XR17V358 0x0358 #define PCI_VENDOR_ID_MICROGATE 0x13c0 #define PCI_DEVICE_ID_MICROGATE_USC 0x0010 @@ -2002,6 +2070,10 @@ #define PCI_DEVICE_ID_CMEDIA_CM8738 0x0111 #define PCI_DEVICE_ID_CMEDIA_CM8738B 0x0112 +#define PCI_VENDOR_ID_ADVANTECH 0x13fe + +#define PCI_VENDOR_ID_MEILHAUS 0x1402 + #define PCI_VENDOR_ID_LAVA 0x1407 #define PCI_DEVICE_ID_LAVA_DSERIAL 0x0100 /* 2x 16550 */ #define PCI_DEVICE_ID_LAVA_QUATRO_A 0x0101 /* 2x 16550, half of 4 port */ @@ -2047,6 +2119,8 @@ #define PCI_VENDOR_ID_CHELSIO 0x1425 +#define PCI_VENDOR_ID_ADLINK 0x144a + #define PCI_VENDOR_ID_SAMSUNG 0x144d #define PCI_VENDOR_ID_GIGABYTE 0x1458 @@ -2080,6 +2154,8 @@ #define PCI_DEVICE_ID_AFAVLAB_P030 0x2182 #define PCI_SUBDEVICE_ID_AFAVLAB_P061 0x2150 +#define PCI_VENDOR_ID_AMPLICON 0x14dc + #define PCI_VENDOR_ID_BCM_GVC 0x14a4 #define PCI_VENDOR_ID_BROADCOM 0x14e4 #define PCI_DEVICE_ID_TIGON3_5752 0x1600 @@ -2100,19 +2176,25 @@ #define PCI_DEVICE_ID_NX2_57711E 0x1650 #define PCI_DEVICE_ID_TIGON3_5705 0x1653 #define PCI_DEVICE_ID_TIGON3_5705_2 0x1654 +#define PCI_DEVICE_ID_TIGON3_5719 0x1657 #define PCI_DEVICE_ID_TIGON3_5721 0x1659 #define PCI_DEVICE_ID_TIGON3_5722 0x165a #define PCI_DEVICE_ID_TIGON3_5723 0x165b #define PCI_DEVICE_ID_TIGON3_5705M 0x165d #define PCI_DEVICE_ID_TIGON3_5705M_2 0x165e +#define PCI_DEVICE_ID_NX2_57712 0x1662 +#define PCI_DEVICE_ID_NX2_57712E 0x1663 +#define PCI_DEVICE_ID_NX2_57712_MF 0x1663 #define PCI_DEVICE_ID_TIGON3_5714 0x1668 #define PCI_DEVICE_ID_TIGON3_5714S 0x1669 #define PCI_DEVICE_ID_TIGON3_5780 0x166a #define PCI_DEVICE_ID_TIGON3_5780S 0x166b #define PCI_DEVICE_ID_TIGON3_5705F 0x166e +#define PCI_DEVICE_ID_NX2_57712_VF 0x166f #define PCI_DEVICE_ID_TIGON3_5754M 0x1672 #define PCI_DEVICE_ID_TIGON3_5755M 0x1673 #define PCI_DEVICE_ID_TIGON3_5756 0x1674 +#define PCI_DEVICE_ID_TIGON3_5750 0x1676 #define PCI_DEVICE_ID_TIGON3_5751 0x1677 #define PCI_DEVICE_ID_TIGON3_5715 0x1678 #define PCI_DEVICE_ID_TIGON3_5715S 0x1679 @@ -2124,6 +2206,9 @@ #define PCI_DEVICE_ID_TIGON3_5761E 0x1680 #define PCI_DEVICE_ID_TIGON3_5761 0x1681 #define PCI_DEVICE_ID_TIGON3_5764 0x1684 +#define PCI_DEVICE_ID_NX2_57800 0x168a +#define PCI_DEVICE_ID_NX2_57840 0x168d +#define PCI_DEVICE_ID_NX2_57810 0x168e #define PCI_DEVICE_ID_TIGON3_5787M 0x1693 #define PCI_DEVICE_ID_TIGON3_5782 0x1696 #define PCI_DEVICE_ID_TIGON3_5784 0x1698 @@ -2131,11 +2216,19 @@ #define PCI_DEVICE_ID_TIGON3_5787 0x169b #define PCI_DEVICE_ID_TIGON3_5788 0x169c #define PCI_DEVICE_ID_TIGON3_5789 0x169d +#define PCI_DEVICE_ID_NX2_57840_4_10 0x16a1 +#define PCI_DEVICE_ID_NX2_57840_2_20 0x16a2 +#define PCI_DEVICE_ID_NX2_57840_MF 0x16a4 +#define PCI_DEVICE_ID_NX2_57800_MF 0x16a5 #define PCI_DEVICE_ID_TIGON3_5702X 0x16a6 #define PCI_DEVICE_ID_TIGON3_5703X 0x16a7 #define PCI_DEVICE_ID_TIGON3_5704S 0x16a8 +#define PCI_DEVICE_ID_NX2_57800_VF 0x16a9 #define PCI_DEVICE_ID_NX2_5706S 0x16aa #define PCI_DEVICE_ID_NX2_5708S 0x16ac +#define PCI_DEVICE_ID_NX2_57840_VF 0x16ad +#define PCI_DEVICE_ID_NX2_57810_MF 0x16ae +#define PCI_DEVICE_ID_NX2_57810_VF 0x16af #define PCI_DEVICE_ID_TIGON3_5702A3 0x16c6 #define PCI_DEVICE_ID_TIGON3_5703A3 0x16c7 #define PCI_DEVICE_ID_TIGON3_5781 0x16dd @@ -2307,6 +2400,8 @@ #define PCI_VENDOR_ID_TOPSPIN 0x1867 +#define PCI_VENDOR_ID_COMMTECH 0x18f7 + #define PCI_VENDOR_ID_SILAN 0x1904 #define PCI_VENDOR_ID_RENESAS 0x1912 @@ -2316,6 +2411,11 @@ #define PCI_DEVICE_ID_RENESAS_SH7785 0x0007 #define PCI_DEVICE_ID_RENESAS_SH7786 0x0010 +#define PCI_VENDOR_ID_SOLARFLARE 0x1924 +#define PCI_DEVICE_ID_SOLARFLARE_SFC4000A_0 0x0703 +#define PCI_DEVICE_ID_SOLARFLARE_SFC4000A_1 0x6703 +#define PCI_DEVICE_ID_SOLARFLARE_SFC4000B 0x0710 + #define PCI_VENDOR_ID_TDI 0x192E #define PCI_DEVICE_ID_TDI_EHCI 0x0101 @@ -2414,6 +2514,11 @@ #define PCI_VENDOR_ID_AZWAVE 0x1a3b +#define PCI_VENDOR_ID_ASMEDIA 0x1b21 + +#define PCI_VENDOR_ID_CIRCUITCO 0x1cc8 +#define PCI_SUBSYSTEM_ID_CIRCUITCO_MINNOWBOARD 0x0001 + #define PCI_VENDOR_ID_TEKRAM 0x1de1 #define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29 @@ -2463,6 +2568,9 @@ #define PCI_VENDOR_ID_INTEL 0x8086 #define PCI_DEVICE_ID_INTEL_EESSC 0x0008 +#define PCI_DEVICE_ID_INTEL_SNB_IMC 0x0100 +#define PCI_DEVICE_ID_INTEL_IVB_IMC 0x0154 +#define PCI_DEVICE_ID_INTEL_HSW_IMC 0x0c00 #define PCI_DEVICE_ID_INTEL_PXHD_0 0x0320 #define PCI_DEVICE_ID_INTEL_PXHD_1 0x0321 #define PCI_DEVICE_ID_INTEL_PXH_0 0x0329 @@ -2485,6 +2593,7 @@ #define PCI_DEVICE_ID_INTEL_MRST_SD2 0x084F #define PCI_DEVICE_ID_INTEL_I960 0x0960 #define PCI_DEVICE_ID_INTEL_I960RM 0x0962 +#define PCI_DEVICE_ID_INTEL_CENTERTON_ILB 0x0c60 #define PCI_DEVICE_ID_INTEL_82541ER 0x1078 #define PCI_DEVICE_ID_INTEL_82541GI_LF 0x107c #define PCI_DEVICE_ID_INTEL_82542 0x1000 @@ -2564,13 +2673,50 @@ #define PCI_DEVICE_ID_INTEL_COUGARPOINT_HDA 0x1c20 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_Z68 0x1c44 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_P67 0x1c46 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_UM67 0x1c47 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_HM65 0x1c49 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_H67 0x1c4a +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_HM67 0x1c4b +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_Q65 0x1c4c +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_QS67 0x1c4d +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_Q67 0x1c4e +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_QM67 0x1c4f +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_B65 0x1c50 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_C202 0x1c52 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_C204 0x1c54 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_C206 0x1c56 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_H61 0x1c5c #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f -#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_AHCI_MOBILE 0x1e03 -#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_HDA 0x1e20 -#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN 0x1e41 -#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX 0x1e5f #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 #define PCI_DEVICE_ID_INTEL_PATSBURG_LPC 0x1d40 +#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0 0x1d40 +#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1 0x1d41 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_AHCI_MOBILE 0x1e03 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_HDA 0x1e20 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI 0x1e31 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN 0x1e41 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_B75 0x1e49 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_C216 0x1e53 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_H77 0x1e4A +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_HM70 0x1e5e +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_HM75 0x1e5d +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_HM76 0x1e59 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_HM77 0x1e57 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MBL_SAMPLE 0x1e42 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_NM70 0x1e5f +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_Q75 0x1e48 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_Q77 0x1e47 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_QM77 0x1e55 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_QS77 0x1e56 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_SFF_SAMPLE 0x1e43 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_UM77 0x1e58 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_Z75 0x1e46 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_Z77 0x1e44 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX 0x1e5f +#define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN 0x2310 +#define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MAX 0x231f #define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410 #define PCI_DEVICE_ID_INTEL_82801AA_1 0x2411 #define PCI_DEVICE_ID_INTEL_82801AA_3 0x2413 @@ -2783,8 +2929,30 @@ #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN 0x3b00 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX 0x3b1f #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB0 0x3c20 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB1 0x3c21 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB2 0x3c22 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB3 0x3c23 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB4 0x3c24 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB5 0x3c25 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB6 0x3c26 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB7 0x3c27 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB8 0x3c2e +#define PCI_DEVICE_ID_INTEL_IOAT_SNB9 0x3c2f +#define PCI_DEVICE_ID_INTEL_UNC_HA 0x3c46 +#define PCI_DEVICE_ID_INTEL_UNC_IMC0 0x3cb0 +#define PCI_DEVICE_ID_INTEL_UNC_IMC1 0x3cb1 +#define PCI_DEVICE_ID_INTEL_UNC_IMC2 0x3cb4 +#define PCI_DEVICE_ID_INTEL_UNC_IMC3 0x3cb5 +#define PCI_DEVICE_ID_INTEL_UNC_QPI0 0x3c41 +#define PCI_DEVICE_ID_INTEL_UNC_QPI1 0x3c42 +#define PCI_DEVICE_ID_INTEL_UNC_R2PCIE 0x3c43 +#define PCI_DEVICE_ID_INTEL_UNC_R3QPI0 0x3c44 +#define PCI_DEVICE_ID_INTEL_UNC_R3QPI1 0x3c45 +#define PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX 0x3ce0 #define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f #define PCI_DEVICE_ID_INTEL_5100_16 0x65f0 +#define PCI_DEVICE_ID_INTEL_5100_19 0x65f3 #define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 #define PCI_DEVICE_ID_INTEL_5100_22 0x65f6 #define PCI_DEVICE_ID_INTEL_5400_ERR 0x4030 @@ -2823,6 +2991,7 @@ #define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601 #define PCI_DEVICE_ID_INTEL_SCH_LPC 0x8119 #define PCI_DEVICE_ID_INTEL_SCH_IDE 0x811a +#define PCI_DEVICE_ID_INTEL_ITC_LPC 0x8186 #define PCI_DEVICE_ID_INTEL_82454GX 0x84c4 #define PCI_DEVICE_ID_INTEL_82450GX 0x84c5 #define PCI_DEVICE_ID_INTEL_82451NX 0x84ca @@ -2905,7 +3074,11 @@ #define PCI_DEVICE_ID_NETMOS_9845 0x9845 #define PCI_DEVICE_ID_NETMOS_9855 0x9855 #define PCI_DEVICE_ID_NETMOS_9865 0x9865 +#define PCI_DEVICE_ID_NETMOS_9900 0x9900 #define PCI_DEVICE_ID_NETMOS_9901 0x9901 +#define PCI_DEVICE_ID_NETMOS_9904 0x9904 +#define PCI_DEVICE_ID_NETMOS_9912 0x9912 +#define PCI_DEVICE_ID_NETMOS_9922 0x9922 #define PCI_VENDOR_ID_3COM_2 0xa727 @@ -2927,3 +3100,5 @@ #define PCI_VENDOR_ID_XEN 0x5853 #define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 + +#define PCI_VENDOR_ID_OCZ 0x1b85 -- cgit v0.10.2 From 65990d568074ad878cbc7e4eb1053508e3707cb6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:22 -0700 Subject: x86: Remove board_early_init_r() This function is not needed. Remove it to improve the generic init sequence slightly. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/x86/cpu/coreboot/coreboot.c b/arch/x86/cpu/coreboot/coreboot.c index 2df7288..cfacc05 100644 --- a/arch/x86/cpu/coreboot/coreboot.c +++ b/arch/x86/cpu/coreboot/coreboot.c @@ -39,17 +39,6 @@ int board_early_init_f(void) return 0; } -int board_early_init_r(void) -{ - /* CPU Speed to 100MHz */ - gd->cpu_clk = 100000000; - - /* Crystal is 33.000MHz */ - gd->bus_clk = 33000000; - - return 0; -} - int print_cpuinfo(void) { return default_print_cpuinfo(); diff --git a/board/google/chromebook_link/link.c b/board/google/chromebook_link/link.c index 88cee05..0a1ae61 100644 --- a/board/google/chromebook_link/link.c +++ b/board/google/chromebook_link/link.c @@ -12,11 +12,6 @@ int arch_early_init_r(void) return 0; } -int board_early_init_r(void) -{ - return 0; -} - static const struct pch_gpio_set1 pch_gpio_set1_mode = { .gpio0 = GPIO_MODE_GPIO, /* NMI_DBG# */ .gpio3 = GPIO_MODE_GPIO, /* ALS_INT# */ diff --git a/common/board_r.c b/common/board_r.c index 19c6427..bfa74c7 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -838,9 +838,6 @@ init_fnc_t init_sequence_r[] = { #ifdef CONFIG_CMD_KGDB initr_kgdb, #endif -#ifdef CONFIG_X86 - board_early_init_r, -#endif interrupt_init, #if defined(CONFIG_ARM) || defined(CONFIG_x86) initr_enable_interrupts, diff --git a/include/configs/chromebook_link.h b/include/configs/chromebook_link.h index 8caeca6..cd4a8a0 100644 --- a/include/configs/chromebook_link.h +++ b/include/configs/chromebook_link.h @@ -21,7 +21,6 @@ #define CONFIG_DCACHE_RAM_MRC_VAR_SIZE 0x4000 #define CONFIG_SYS_X86_START16 0xfffff800 #define CONFIG_BOARD_EARLY_INIT_F -#define CONFIG_BOARD_EARLY_INIT_R #define CONFIG_DISPLAY_CPUINFO #define CONFIG_X86_RESET_VECTOR -- cgit v0.10.2 From 512e581c86a4066147a9a095eaed05a7aa9043df Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:23 -0700 Subject: x86: Panic if there is no relocation data This normally indicates a problem which will prevent relocation from functioning, resulting in a hang. Panic in this case to make it easier to debug. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c index faca38f..b33586b 100644 --- a/arch/x86/lib/relocate.c +++ b/arch/x86/lib/relocate.c @@ -76,6 +76,9 @@ int do_elf_reloc_fixups(void) /* The size of the region of u-boot that runs out of RAM. */ uintptr_t size = (uintptr_t)&__bss_end - (uintptr_t)&__text_start; + if (re_src == re_end) + panic("No relocation data"); + do { /* Get the location from the relocation entry */ offset_ptr_rom = (Elf32_Addr *)re_src->r_offset; -- cgit v0.10.2 From 091c4943539f8a0b238246e043683e3cbf657b5e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:24 -0700 Subject: x86: Ensure that all relocation data is included in the image Some toolchains put the relocation data into separate sections. Adjust the linker script to catch this case. Without relocation data, U-Boot will not boot. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/x86/cpu/u-boot.lds b/arch/x86/cpu/u-boot.lds index f48bff5..124a361 100644 --- a/arch/x86/cpu/u-boot.lds +++ b/arch/x86/cpu/u-boot.lds @@ -44,7 +44,9 @@ SECTIONS . = ALIGN(4); __rel_dyn_start = .; - .rel.dyn : { *(.rel.dyn) } + .rel.dyn : { + *(.rel*) + } __rel_dyn_end = .; . = ALIGN(4); _end = .; -- cgit v0.10.2 From a6a957849a0ad20323156ef2439b490306bd5e35 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:25 -0700 Subject: x86: Factor out common values in the link script Define the reset base in config.mk so that it does not need to be calculated twice in the link script. Also tidy up the START_16 and RESET_VEC_LOC values to fit with this new approach. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/x86/cpu/config.mk b/arch/x86/cpu/config.mk index f7b01d3..84aeaf3 100644 --- a/arch/x86/cpu/config.mk +++ b/arch/x86/cpu/config.mk @@ -12,5 +12,6 @@ PLATFORM_CPPFLAGS += -D__I386__ -Werror # DO NOT MODIFY THE FOLLOWING UNLESS YOU REALLY KNOW WHAT YOU ARE DOING! LDPPFLAGS += -DRESET_SEG_START=0xffff0000 LDPPFLAGS += -DRESET_SEG_SIZE=0x10000 -LDPPFLAGS += -DRESET_VEC_LOC=0xfff0 -LDPPFLAGS += -DSTART_16=0xf800 +LDPPFLAGS += -DRESET_VEC_LOC=0xfffffff0 +LDPPFLAGS += -DSTART_16=$(CONFIG_SYS_X86_START16) +LDPPFLAGS += -DRESET_BASE="CONFIG_SYS_TEXT_BASE + (CONFIG_SYS_MONITOR_LEN - RESET_SEG_SIZE)" diff --git a/arch/x86/cpu/u-boot.lds b/arch/x86/cpu/u-boot.lds index 124a361..b0d8531 100644 --- a/arch/x86/cpu/u-boot.lds +++ b/arch/x86/cpu/u-boot.lds @@ -66,15 +66,19 @@ SECTIONS /DISCARD/ : { *(.gnu*) } #ifdef CONFIG_X86_RESET_VECTOR - /* * The following expressions place the 16-bit Real-Mode code and * Reset Vector at the end of the Flash ROM */ - . = START_16; - .start16 : AT (CONFIG_SYS_TEXT_BASE + (CONFIG_SYS_MONITOR_LEN - RESET_SEG_SIZE + START_16)) { KEEP(*(.start16)); } + . = START_16 - RESET_SEG_START; + .start16 : AT (START_16) { + KEEP(*(.start16)); + } - . = RESET_VEC_LOC; - .resetvec : AT (CONFIG_SYS_TEXT_BASE + (CONFIG_SYS_MONITOR_LEN - RESET_SEG_SIZE + RESET_VEC_LOC)) { KEEP(*(.resetvec)); } + . = RESET_VEC_LOC - RESET_SEG_START; + .resetvec : AT (RESET_VEC_LOC) { + KEEP(*(.resetvec)); + } #endif + } -- cgit v0.10.2 From c6577f7219489725924c646a360dc2d50cc5402b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:26 -0700 Subject: rtc: mc146818: Set up RTC at start of day Provide a function to set up the RTC ready for use. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/rtc/bfin_rtc.c b/drivers/rtc/bfin_rtc.c index 21a2189..4cf2d83 100644 --- a/drivers/rtc/bfin_rtc.c +++ b/drivers/rtc/bfin_rtc.c @@ -27,7 +27,7 @@ #define NUM_SECS_IN_DAY DAYS_TO_SECS(1) /* Enable the RTC prescaler enable register */ -static void rtc_init(void) +void rtc_init(void) { if (!(bfin_read_RTC_PREN() & 0x1)) bfin_write_RTC_PREN(0x1); diff --git a/drivers/rtc/mc146818.c b/drivers/rtc/mc146818.c index f7cf106..39e6041 100644 --- a/drivers/rtc/mc146818.c +++ b/drivers/rtc/mc146818.c @@ -14,6 +14,7 @@ #include #include #include +#include #if defined(__I386__) || defined(CONFIG_MALTA) #include @@ -23,6 +24,9 @@ #if defined(CONFIG_CMD_DATE) +/* Set this to 1 to clear the CMOS RAM */ +#define CLEAR_CMOS 0 + static uchar rtc_read (uchar reg); static void rtc_write (uchar reg, uchar val); @@ -41,7 +45,14 @@ static void rtc_write (uchar reg, uchar val); #define RTC_CONFIG_B 0x0B #define RTC_CONFIG_C 0x0C #define RTC_CONFIG_D 0x0D +#define RTC_REG_SIZE 0x80 + +#define RTC_CONFIG_A_REF_CLCK_32KHZ (1 << 5) +#define RTC_CONFIG_A_RATE_1024HZ 6 +#define RTC_CONFIG_B_24H (1 << 1) + +#define RTC_CONFIG_D_VALID_RAM_AND_TIME 0x80 /* ------------------------------------------------------------------------- */ @@ -128,25 +139,49 @@ void rtc_reset (void) */ static uchar rtc_read (uchar reg) { - return(in8(CONFIG_SYS_RTC_REG_BASE_ADDR+reg)); + return in8(CONFIG_SYS_RTC_REG_BASE_ADDR + reg); } static void rtc_write (uchar reg, uchar val) { - out8(CONFIG_SYS_RTC_REG_BASE_ADDR+reg, val); + out8(CONFIG_SYS_RTC_REG_BASE_ADDR + reg, val); } #else static uchar rtc_read (uchar reg) { out8(RTC_PORT_MC146818,reg); - return(in8(RTC_PORT_MC146818+1)); + return in8(RTC_PORT_MC146818 + 1); } static void rtc_write (uchar reg, uchar val) { out8(RTC_PORT_MC146818,reg); - out8(RTC_PORT_MC146818+1,val); + out8(RTC_PORT_MC146818+1, val); } #endif +void rtc_init(void) +{ +#if CLEAR_CMOS + int i; + + rtc_write(RTC_SECONDS_ALARM, 0); + rtc_write(RTC_MINUTES_ALARM, 0); + rtc_write(RTC_HOURS_ALARM, 0); + for (i = RTC_CONFIG_A; i < RTC_REG_SIZE; i++) + rtc_write(i, 0); + printf("RTC: zeroing CMOS RAM\n"); +#endif + + /* Setup the real time clock */ + rtc_write(RTC_CONFIG_B, RTC_CONFIG_B_24H); + /* Setup the frequency it operates at */ + rtc_write(RTC_CONFIG_A, RTC_CONFIG_A_REF_CLCK_32KHZ | + RTC_CONFIG_A_RATE_1024HZ); + /* Ensure all reserved bits are 0 in register D */ + rtc_write(RTC_CONFIG_D, RTC_CONFIG_D_VALID_RAM_AND_TIME); + + /* Clear any pending interrupts */ + rtc_read(RTC_CONFIG_C); +} #endif diff --git a/include/rtc.h b/include/rtc.h index c034966..d11aa8b 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -50,4 +50,9 @@ void to_tm (int, struct rtc_time *); unsigned long mktime (unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); +/** + * rtc_init() - Set up the real time clock ready for use + */ +void rtc_init(void); + #endif /* _RTC_H_ */ -- cgit v0.10.2 From a2f5d091ccdc6ffd8fa11c140bc5a93234ee4833 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:27 -0700 Subject: x86: Add ioapic.h header Add definitions for the I/O Advanced Peripheral Interrupt Controller. Signed-off-by: Simon Glass diff --git a/arch/x86/include/asm/ioapic.h b/arch/x86/include/asm/ioapic.h new file mode 100644 index 0000000..699160f --- /dev/null +++ b/arch/x86/include/asm/ioapic.h @@ -0,0 +1,38 @@ +/* + * From coreboot file of the same name + * + * Copyright (C) 2010 coresystems GmbH + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __ASM_IOAPIC_H +#define __ASM_IOAPIC_H + +#define IO_APIC_ADDR 0xfec00000 +#define IO_APIC_INDEX IO_APIC_ADDR +#define IO_APIC_DATA (IO_APIC_ADDR + 0x10) +#define IO_APIC_INTERRUPTS 24 + +#define ALL (0xff << 24) +#define NONE 0 +#define DISABLED (1 << 16) +#define ENABLED (0 << 16) +#define TRIGGER_EDGE (0 << 15) +#define TRIGGER_LEVEL (1 << 15) +#define POLARITY_HIGH (0 << 13) +#define POLARITY_LOW (1 << 13) +#define PHYSICAL_DEST (0 << 11) +#define LOGICAL_DEST (1 << 11) +#define ExtINT (7 << 8) +#define NMI (4 << 8) +#define SMI (2 << 8) +#define INT (1 << 8) + +u32 io_apic_read(u32 ioapic_base, u32 reg); +void io_apic_write(u32 ioapic_base, u32 reg, u32 value); +void set_ioapic_id(u32 ioapic_base, u8 ioapic_id); +void setup_ioapic(u32 ioapic_base, u8 ioapic_id); +void clear_ioapic(u32 ioapic_base); + +#endif -- cgit v0.10.2 From e94ea6f656641e30392cf76089b65ea9aecde160 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:28 -0700 Subject: x86: pci: Add handlers before and after a PCI hose scan Some boards will want to do some setup before and after a PCI hose is scanned. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/x86/cpu/pci.c b/arch/x86/cpu/pci.c index e399388..f3492c3 100644 --- a/arch/x86/cpu/pci.c +++ b/arch/x86/cpu/pci.c @@ -33,6 +33,16 @@ int pci_early_init_hose(struct pci_controller **hosep) return 0; } +__weak int board_pci_pre_scan(struct pci_controller *hose) +{ + return 0; +} + +__weak int board_pci_post_scan(struct pci_controller *hose) +{ + return 0; +} + void pci_init_board(void) { struct pci_controller *hose = &x86_hose; @@ -44,7 +54,9 @@ void pci_init_board(void) pci_setup_type1(hose); pci_register_hose(hose); + board_pci_pre_scan(hose); hose->last_busno = pci_hose_scan(hose); + board_pci_post_scan(hose); } static struct pci_controller *get_hose(void) diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index 98817aa..ac1a808 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h @@ -34,6 +34,9 @@ void board_pci_setup_hose(struct pci_controller *hose); */ int pci_early_init_hose(struct pci_controller **hosep); +int board_pci_pre_scan(struct pci_controller *hose); +int board_pci_post_scan(struct pci_controller *hose); + /* * Simple PCI access routines - these work from either the early PCI hose * or the 'real' one, created after U-Boot has memory available -- cgit v0.10.2 From b6b4a0ec5550cf5e45e9b0b3527db63464e4c3d8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:29 -0700 Subject: x86: config: Enable plug-and-play for link PCI Enable this option so that we can configure the available PCI devices. Also make sure that PCI is available early after relocation as we use it for several other subsystems. Signed-off-by: Simon Glass diff --git a/include/configs/chromebook_link.h b/include/configs/chromebook_link.h index cd4a8a0..055b3ac 100644 --- a/include/configs/chromebook_link.h +++ b/include/configs/chromebook_link.h @@ -66,6 +66,9 @@ #define CONFIG_PCI_IO_PHYS CONFIG_PCI_IO_BUS #define CONFIG_PCI_IO_SIZE 0xefff +#define CONFIG_SYS_EARLY_PCI_INIT +#define CONFIG_PCI_PNP + #define CONFIG_STD_DEVICES_SETTINGS "stdin=usbkbd,vga,serial\0" \ "stdout=vga,serial\0" \ "stderr=vga,serial\0" -- cgit v0.10.2 From e8a552eb625f0b2d7a778d151af25a17c6d33b7b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:30 -0700 Subject: pci: Add functions to read and write a BAR address Some PCI functions cannot be auto-configured. Add a function to set up a fixed BAR which can be used in these situations. Also add a function to read the current address of a BAR. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7ee21d1..3daf73c 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -366,9 +366,27 @@ phys_addr_t pci_hose_bus_to_phys(struct pci_controller* hose, return phys_addr; } -/* - * - */ +void pci_write_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum, + u32 addr_and_ctrl) +{ + int bar; + + bar = PCI_BASE_ADDRESS_0 + barnum * 4; + pci_hose_write_config_dword(hose, dev, bar, addr_and_ctrl); +} + +u32 pci_read_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum) +{ + u32 addr; + int bar; + + bar = PCI_BASE_ADDRESS_0 + barnum * 4; + pci_hose_read_config_dword(hose, dev, bar, &addr); + if (addr & PCI_BASE_ADDRESS_SPACE_IO) + return addr & PCI_BASE_ADDRESS_IO_MASK; + else + return addr & PCI_BASE_ADDRESS_MEM_MASK; +} int pci_hose_config_device(struct pci_controller *hose, pci_dev_t dev, diff --git a/include/pci.h b/include/pci.h index d211351..216f448 100644 --- a/include/pci.h +++ b/include/pci.h @@ -678,5 +678,28 @@ extern void pci_mpc824x_init (struct pci_controller *hose); extern void pci_mpc85xx_init (struct pci_controller *hose); #endif +/** + * pci_write_bar32() - Write the address of a BAR including control bits + * + * This writes a raw address (with control bits) to a bar + * + * @hose: PCI hose to use + * @dev: PCI device to update + * @barnum: BAR number (0-5) + * @addr: BAR address with control bits + */ +void pci_write_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum, + u32 addr_and_ctrl); + +/** + * pci_read_bar32() - read the address of a bar + * + * @hose: PCI hose to use + * @dev: PCI device to inspect + * @barnum: BAR number (0-5) + * @return address of the bar, masking out any control bits + * */ +u32 pci_read_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum); + #endif /* __ASSEMBLY__ */ #endif /* _PCI_H */ -- cgit v0.10.2 From a0bd851ecec0e04c5e3f224a912b2872618f77ba Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:31 -0700 Subject: x86: Set up edge triggering on interrupt 9 Add this additional init in case it is needed by the OS. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/x86/include/asm/interrupt.h b/arch/x86/include/asm/interrupt.h index 3f46e09..25abde7 100644 --- a/arch/x86/include/asm/interrupt.h +++ b/arch/x86/include/asm/interrupt.h @@ -27,4 +27,15 @@ void specific_eoi(int irq); extern char exception_stack[]; +/** + * configure_irq_trigger() - Configure IRQ triggering + * + * Switch the given interrupt to be level / edge triggered + * + * @param int_num legacy interrupt number (3-7, 9-15) + * @param is_level_triggered true for level triggered interrupt, false for + * edge triggered interrupt + */ +void configure_irq_trigger(int int_num, bool is_level_triggered); + #endif diff --git a/arch/x86/lib/pcat_interrupts.c b/arch/x86/lib/pcat_interrupts.c index 4c86f7f..2dc2fbd 100644 --- a/arch/x86/lib/pcat_interrupts.c +++ b/arch/x86/lib/pcat_interrupts.c @@ -62,6 +62,9 @@ int interrupt_init(void) */ unmask_irq(2); + /* Interrupt 9 should be level triggered (SCI). The OS might do this */ + configure_irq_trigger(9, true); + enable_interrupts(); return 0; @@ -114,3 +117,38 @@ void specific_eoi(int irq) outb(OCW2_SEOI | irq, MASTER_PIC + OCW2); } + +#define ELCR1 0x4d0 +#define ELCR2 0x4d1 + +void configure_irq_trigger(int int_num, bool is_level_triggered) +{ + u16 int_bits = inb(ELCR1) | (((u16)inb(ELCR2)) << 8); + + debug("%s: current interrupts are 0x%x\n", __func__, int_bits); + if (is_level_triggered) + int_bits |= (1 << int_num); + else + int_bits &= ~(1 << int_num); + + /* Write new values */ + debug("%s: try to set interrupts 0x%x\n", __func__, int_bits); + outb((u8)(int_bits & 0xff), ELCR1); + outb((u8)(int_bits >> 8), ELCR2); + +#ifdef PARANOID_IRQ_TRIGGERS + /* + * Try reading back the new values. This seems like an error but is + * not + */ + if (inb(ELCR1) != (int_bits & 0xff)) { + printf("%s: lower order bits are wrong: want 0x%x, got 0x%x\n", + __func__, (int_bits & 0xff), inb(ELCR1)); + } + + if (inb(ELCR2) != (int_bits >> 8)) { + printf("%s: higher order bits are wrong: want 0x%x, got 0x%x\n", + __func__, (int_bits>>8), inb(ELCR2)); + } +#endif +} -- cgit v0.10.2 From 4e7a6acac7a46cc5ab0ea7986cc9e74351eed165 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:32 -0700 Subject: x86: ivybridge: Add support for BD82x6x PCH Add basic setup for the PCH. Signed-off-by: Simon Glass diff --git a/arch/x86/cpu/ivybridge/Makefile b/arch/x86/cpu/ivybridge/Makefile index 721b37e..b37fb8f 100644 --- a/arch/x86/cpu/ivybridge/Makefile +++ b/arch/x86/cpu/ivybridge/Makefile @@ -4,6 +4,7 @@ # SPDX-License-Identifier: GPL-2.0+ # +obj-y += bd82x6x.o obj-y += car.o obj-y += cpu.o obj-y += early_init.o diff --git a/arch/x86/cpu/ivybridge/bd82x6x.c b/arch/x86/cpu/ivybridge/bd82x6x.c new file mode 100644 index 0000000..fab7c53 --- /dev/null +++ b/arch/x86/cpu/ivybridge/bd82x6x.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void bd82x6x_pci_init(pci_dev_t dev) +{ + u16 reg16; + u8 reg8; + + debug("bd82x6x PCI init.\n"); + /* Enable Bus Master */ + reg16 = pci_read_config16(dev, PCI_COMMAND); + reg16 |= PCI_COMMAND_MASTER; + pci_write_config16(dev, PCI_COMMAND, reg16); + + /* This device has no interrupt */ + pci_write_config8(dev, INTR, 0xff); + + /* disable parity error response and SERR */ + reg16 = pci_read_config16(dev, BCTRL); + reg16 &= ~(1 << 0); + reg16 &= ~(1 << 1); + pci_write_config16(dev, BCTRL, reg16); + + /* Master Latency Count must be set to 0x04! */ + reg8 = pci_read_config8(dev, SMLT); + reg8 &= 0x07; + reg8 |= (0x04 << 3); + pci_write_config8(dev, SMLT, reg8); + + /* Will this improve throughput of bus masters? */ + pci_write_config8(dev, PCI_MIN_GNT, 0x06); + + /* Clear errors in status registers */ + reg16 = pci_read_config16(dev, PSTS); + /* reg16 |= 0xf900; */ + pci_write_config16(dev, PSTS, reg16); + + reg16 = pci_read_config16(dev, SECSTS); + /* reg16 |= 0xf900; */ + pci_write_config16(dev, SECSTS, reg16); +} + +#define PCI_BRIDGE_UPDATE_COMMAND +void bd82x6x_pci_dev_enable_resources(pci_dev_t dev) +{ + uint16_t command; + + command = pci_read_config16(dev, PCI_COMMAND); + command |= PCI_COMMAND_IO; +#ifdef PCI_BRIDGE_UPDATE_COMMAND + /* + * If we write to PCI_COMMAND, on some systems this will cause the + * ROM and APICs to become invisible. + */ + debug("%x cmd <- %02x\n", dev, command); + pci_write_config16(dev, PCI_COMMAND, command); +#else + printf("%s cmd <- %02x (NOT WRITTEN!)\n", dev_path(dev), command); +#endif +} + +void bd82x6x_pci_bus_enable_resources(pci_dev_t dev) +{ + uint16_t ctrl; + + ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL); + ctrl |= PCI_COMMAND_IO; + ctrl |= PCI_BRIDGE_CTL_VGA; + debug("%x bridge ctrl <- %04x\n", dev, ctrl); + pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl); + + bd82x6x_pci_dev_enable_resources(dev); +} + +int bd82x6x_init_pci_devices(void) +{ + return 0; +} + +int bd82x6x_init(void) +{ + bd82x6x_pci_init(PCH_DEV); + + return 0; +} diff --git a/arch/x86/cpu/ivybridge/pci.c b/arch/x86/cpu/ivybridge/pci.c index c1ae658..452d1c3 100644 --- a/arch/x86/cpu/ivybridge/pci.c +++ b/arch/x86/cpu/ivybridge/pci.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include static void config_pci_bridge(struct pci_controller *hose, pci_dev_t dev, struct pci_config_table *table) @@ -58,3 +60,41 @@ void board_pci_setup_hose(struct pci_controller *hose) hose->region_count = 3; } + +int board_pci_pre_scan(struct pci_controller *hose) +{ + pci_dev_t dev; + u16 reg16; + + bd82x6x_init(); + + reg16 = 0xff; + dev = PCH_DEV; + reg16 = pci_read_config16(dev, PCI_COMMAND); + reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + pci_write_config16(dev, PCI_COMMAND, reg16); + + /* + * Clear non-reserved bits in status register. + */ + pci_hose_write_config_word(hose, dev, PCI_STATUS, 0xffff); + pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80); + pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08); + + pci_write_bar32(hose, dev, 0, 0xf0000000); + + return 0; +} + +int board_pci_post_scan(struct pci_controller *hose) +{ + int ret; + + ret = bd82x6x_init_pci_devices(); + if (ret) { + printf("bd82x6x_init_pci_devices() failed: %d\n", ret); + return ret; + } + + return 0; +} diff --git a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h new file mode 100644 index 0000000..e02520c --- /dev/null +++ b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _ASM_ARCH_BD82X6X_H +#define _ASM_ARCH_BD82X6X_H + +void bd82x6x_pci_init(pci_dev_t dev); +int bd82x6x_init_pci_devices(void); +int bd82x6x_init(void); + +#endif diff --git a/arch/x86/include/asm/arch-ivybridge/pch.h b/arch/x86/include/asm/arch-ivybridge/pch.h index c6efdb8..aa626ad 100644 --- a/arch/x86/include/asm/arch-ivybridge/pch.h +++ b/arch/x86/include/asm/arch-ivybridge/pch.h @@ -19,6 +19,16 @@ #define SMBUS_IO_BASE 0x0400 +/* PCI Configuration Space (D30:F0): PCI2PCI */ +#define PSTS 0x06 +#define SMLT 0x1b +#define SECSTS 0x1e +#define INTR 0x3c +#define BCTRL 0x3e +#define SBR (1 << 6) +#define SEE (1 << 1) +#define PERE (1 << 0) + #define PCH_EHCI1_DEV PCI_BDF(0, 0x1d, 0) #define PCH_EHCI2_DEV PCI_BDF(0, 0x1a, 0) #define PCH_XHCI_DEV PCI_BDF(0, 0x14, 0) @@ -343,6 +353,9 @@ #define DMISCI_STS (1 << 9) #define TCO2_STS 0x66 +int lpc_init(struct pci_controller *hose, pci_dev_t dev); +void lpc_enable(pci_dev_t dev); + /** * lpc_early_init() - set up LPC serial ports and other early things * -- cgit v0.10.2 From 3e0332c0b90323ca3c0584e9ae5592b04b121bae Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:33 -0700 Subject: x86: Add a simple header file for ACPI We don't use many features yet, so this only has a few declarations. It will be expanded as needed. Signed-off-by: Simon Glass diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h new file mode 100644 index 0000000..4872b92 --- /dev/null +++ b/arch/x86/include/asm/acpi.h @@ -0,0 +1,24 @@ +/* + * From coreboot + * + * Copyright (C) 2004 SUSE LINUX AG + * Copyright (C) 2004 Nick Barker + * Copyright (C) 2008-2009 coresystems GmbH + * (Written by Stefan Reinauer ) + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __ASM_ACPI_H +#define __ASM_ACPI_H + +#define RSDP_SIG "RSD PTR " /* RSDT pointer signature */ +#define ACPI_TABLE_CREATOR "U-BootAC" /* Must be exactly 8 bytes long! */ +#define OEM_ID "U-Boot" /* Must be exactly 6 bytes long! */ +#define ASLC "U-Bo" /* Must be exactly 4 bytes long! */ + +/* 0 = S0, 1 = S1 ...*/ +int acpi_get_slp_type(void); +void apci_set_slp_type(int type); + +#endif -- cgit v0.10.2 From 8c74a57318d1302d28a10ae862a7faa9086e2660 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:34 -0700 Subject: x86: ivybridge: Add PCH init Add required init for the Intel Platform Controller Hub in ivybridge. Signed-off-by: Simon Glass diff --git a/arch/x86/cpu/ivybridge/Makefile b/arch/x86/cpu/ivybridge/Makefile index b37fb8f..479e446 100644 --- a/arch/x86/cpu/ivybridge/Makefile +++ b/arch/x86/cpu/ivybridge/Makefile @@ -12,6 +12,7 @@ obj-y += early_me.o obj-y += lpc.o obj-y += me_status.o obj-y += microcode_intel.o +obj-y += pch.o obj-y += pci.o obj-y += report_platform.o obj-y += sdram.o diff --git a/arch/x86/cpu/ivybridge/pch.c b/arch/x86/cpu/ivybridge/pch.c new file mode 100644 index 0000000..fa04d48 --- /dev/null +++ b/arch/x86/cpu/ivybridge/pch.c @@ -0,0 +1,123 @@ +/* + * From Coreboot + * Copyright (C) 2008-2009 coresystems GmbH + * Copyright (C) 2012 The Chromium OS Authors. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include + +static int pch_revision_id = -1; +static int pch_type = -1; + +int pch_silicon_revision(void) +{ + pci_dev_t dev; + + dev = PCH_LPC_DEV; + + if (pch_revision_id < 0) + pch_revision_id = pci_read_config8(dev, PCI_REVISION_ID); + return pch_revision_id; +} + +int pch_silicon_type(void) +{ + pci_dev_t dev; + + dev = PCH_LPC_DEV; + + if (pch_type < 0) + pch_type = pci_read_config8(dev, PCI_DEVICE_ID + 1); + return pch_type; +} + +int pch_silicon_supported(int type, int rev) +{ + int cur_type = pch_silicon_type(); + int cur_rev = pch_silicon_revision(); + + switch (type) { + case PCH_TYPE_CPT: + /* CougarPoint minimum revision */ + if (cur_type == PCH_TYPE_CPT && cur_rev >= rev) + return 1; + /* PantherPoint any revision */ + if (cur_type == PCH_TYPE_PPT) + return 1; + break; + + case PCH_TYPE_PPT: + /* PantherPoint minimum revision */ + if (cur_type == PCH_TYPE_PPT && cur_rev >= rev) + return 1; + break; + } + + return 0; +} + +#define IOBP_RETRY 1000 +static inline int iobp_poll(void) +{ + unsigned try = IOBP_RETRY; + u32 data; + + while (try--) { + data = readl(RCB_REG(IOBPS)); + if ((data & 1) == 0) + return 1; + udelay(10); + } + + printf("IOBP timeout\n"); + return 0; +} + +void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue) +{ + u32 data; + + /* Set the address */ + writel(address, RCB_REG(IOBPIRI)); + + /* READ OPCODE */ + if (pch_silicon_supported(PCH_TYPE_CPT, PCH_STEP_B0)) + writel(IOBPS_RW_BX, RCB_REG(IOBPS)); + else + writel(IOBPS_READ_AX, RCB_REG(IOBPS)); + if (!iobp_poll()) + return; + + /* Read IOBP data */ + data = readl(RCB_REG(IOBPD)); + if (!iobp_poll()) + return; + + /* Check for successful transaction */ + if ((readl(RCB_REG(IOBPS)) & 0x6) != 0) { + printf("IOBP read 0x%08x failed\n", address); + return; + } + + /* Update the data */ + data &= andvalue; + data |= orvalue; + + /* WRITE OPCODE */ + if (pch_silicon_supported(PCH_TYPE_CPT, PCH_STEP_B0)) + writel(IOBPS_RW_BX, RCB_REG(IOBPS)); + else + writel(IOBPS_WRITE_AX, RCB_REG(IOBPS)); + if (!iobp_poll()) + return; + + /* Write IOBP data */ + writel(data, RCB_REG(IOBPD)); + if (!iobp_poll()) + return; +} diff --git a/arch/x86/include/asm/arch-ivybridge/pch.h b/arch/x86/include/asm/arch-ivybridge/pch.h index aa626ad..b3ec7c5 100644 --- a/arch/x86/include/asm/arch-ivybridge/pch.h +++ b/arch/x86/include/asm/arch-ivybridge/pch.h @@ -14,11 +14,31 @@ #include +/* PCH types */ +#define PCH_TYPE_CPT 0x1c /* CougarPoint */ +#define PCH_TYPE_PPT 0x1e /* IvyBridge */ + +/* PCH stepping values for LPC device */ +#define PCH_STEP_A0 0 +#define PCH_STEP_A1 1 +#define PCH_STEP_B0 2 +#define PCH_STEP_B1 3 +#define PCH_STEP_B2 4 +#define PCH_STEP_B3 5 #define DEFAULT_GPIOBASE 0x0480 #define DEFAULT_PMBASE 0x0500 #define SMBUS_IO_BASE 0x0400 +int pch_silicon_revision(void); +int pch_silicon_type(void); +int pch_silicon_supported(int type, int rev); +void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue); + +#define MAINBOARD_POWER_OFF 0 +#define MAINBOARD_POWER_ON 1 +#define MAINBOARD_POWER_KEEP 2 + /* PCI Configuration Space (D30:F0): PCI2PCI */ #define PSTS 0x06 #define SMLT 0x1b @@ -40,6 +60,35 @@ /* PCI Configuration Space (D31:F0): LPC */ #define PCH_LPC_DEV PCI_BDF(0, 0x1f, 0) +#define SERIRQ_CNTL 0x64 + +#define GEN_PMCON_1 0xa0 +#define GEN_PMCON_2 0xa2 +#define GEN_PMCON_3 0xa4 +#define ETR3 0xac +#define ETR3_CWORWRE (1 << 18) +#define ETR3_CF9GR (1 << 20) + +/* GEN_PMCON_3 bits */ +#define RTC_BATTERY_DEAD (1 << 2) +#define RTC_POWER_FAILED (1 << 1) +#define SLEEP_AFTER_POWER_FAIL (1 << 0) + +#define PMBASE 0x40 +#define ACPI_CNTL 0x44 +#define BIOS_CNTL 0xDC +#define GPIO_BASE 0x48 /* LPC GPIO Base Address Register */ +#define GPIO_CNTL 0x4C /* LPC GPIO Control Register */ +#define GPIO_ROUT 0xb8 + +#define PIRQA_ROUT 0x60 +#define PIRQB_ROUT 0x61 +#define PIRQC_ROUT 0x62 +#define PIRQD_ROUT 0x63 +#define PIRQE_ROUT 0x68 +#define PIRQF_ROUT 0x69 +#define PIRQG_ROUT 0x6A +#define PIRQH_ROUT 0x6B #define GEN_PMCON_1 0xa0 #define GEN_PMCON_2 0xa2 -- cgit v0.10.2 From 72cd085aaed511abf1ece0b406b79b90d26826af Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:35 -0700 Subject: x86: ivybridge: Add additional LPC init Set up all the remaining pieces of the LPC (low-pin-count) peripheral in PCH (Peripheral Controller Hub). Signed-off-by: Simon Glass diff --git a/arch/x86/cpu/ivybridge/bd82x6x.c b/arch/x86/cpu/ivybridge/bd82x6x.c index fab7c53..be4db74 100644 --- a/arch/x86/cpu/ivybridge/bd82x6x.c +++ b/arch/x86/cpu/ivybridge/bd82x6x.c @@ -88,6 +88,12 @@ void bd82x6x_pci_bus_enable_resources(pci_dev_t dev) int bd82x6x_init_pci_devices(void) { + struct pci_controller *hose; + + hose = pci_bus_to_hose(0); + lpc_enable(PCH_LPC_DEV); + lpc_init(hose, PCH_LPC_DEV); + return 0; } diff --git a/arch/x86/cpu/ivybridge/lpc.c b/arch/x86/cpu/ivybridge/lpc.c index 621ef2c..43fdd31 100644 --- a/arch/x86/cpu/ivybridge/lpc.c +++ b/arch/x86/cpu/ivybridge/lpc.c @@ -9,10 +9,460 @@ #include #include #include +#include #include +#include +#include +#include +#include #include #include +#define NMI_OFF 0 + +#define ENABLE_ACPI_MODE_IN_COREBOOT 0 +#define TEST_SMM_FLASH_LOCKDOWN 0 + +static int pch_enable_apic(pci_dev_t dev) +{ + u32 reg32; + int i; + + /* Enable ACPI I/O and power management. Set SCI IRQ to IRQ9 */ + pci_write_config8(dev, ACPI_CNTL, 0x80); + + writel(0, IO_APIC_INDEX); + writel(1 << 25, IO_APIC_DATA); + + /* affirm full set of redirection table entries ("write once") */ + writel(1, IO_APIC_INDEX); + reg32 = readl(IO_APIC_DATA); + writel(1, IO_APIC_INDEX); + writel(reg32, IO_APIC_DATA); + + writel(0, IO_APIC_INDEX); + reg32 = readl(IO_APIC_DATA); + debug("PCH APIC ID = %x\n", (reg32 >> 24) & 0x0f); + if (reg32 != (1 << 25)) { + printf("APIC Error - cannot write to registers\n"); + return -EPERM; + } + + debug("Dumping IOAPIC registers\n"); + for (i = 0; i < 3; i++) { + writel(i, IO_APIC_INDEX); + debug(" reg 0x%04x:", i); + reg32 = readl(IO_APIC_DATA); + debug(" 0x%08x\n", reg32); + } + + /* Select Boot Configuration register. */ + writel(3, IO_APIC_INDEX); + + /* Use Processor System Bus to deliver interrupts. */ + writel(1, IO_APIC_DATA); + + return 0; +} + +static void pch_enable_serial_irqs(pci_dev_t dev) +{ + u32 value; + + /* Set packet length and toggle silent mode bit for one frame. */ + value = (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0); +#ifdef CONFIG_SERIRQ_CONTINUOUS_MODE + pci_write_config8(dev, SERIRQ_CNTL, value); +#else + pci_write_config8(dev, SERIRQ_CNTL, value | (1 << 6)); +#endif +} + +static int pch_pirq_init(const void *blob, int node, pci_dev_t dev) +{ + uint8_t route[8], *ptr; + + if (fdtdec_get_byte_array(blob, node, "intel,pirq-routing", route, + sizeof(route))) + return -EINVAL; + ptr = route; + pci_write_config8(dev, PIRQA_ROUT, *ptr++); + pci_write_config8(dev, PIRQB_ROUT, *ptr++); + pci_write_config8(dev, PIRQC_ROUT, *ptr++); + pci_write_config8(dev, PIRQD_ROUT, *ptr++); + + pci_write_config8(dev, PIRQE_ROUT, *ptr++); + pci_write_config8(dev, PIRQF_ROUT, *ptr++); + pci_write_config8(dev, PIRQG_ROUT, *ptr++); + pci_write_config8(dev, PIRQH_ROUT, *ptr++); + + /* + * TODO(sjg@chromium.org): U-Boot does not set up the interrupts + * here. It's unclear if it is needed + */ + return 0; +} + +static int pch_gpi_routing(const void *blob, int node, pci_dev_t dev) +{ + u8 route[16]; + u32 reg; + int gpi; + + if (fdtdec_get_byte_array(blob, node, "intel,gpi-routing", route, + sizeof(route))) + return -EINVAL; + + for (reg = 0, gpi = 0; gpi < ARRAY_SIZE(route); gpi++) + reg |= route[gpi] << (gpi * 2); + + pci_write_config32(dev, 0xb8, reg); + + return 0; +} + +static int pch_power_options(const void *blob, int node, pci_dev_t dev) +{ + u8 reg8; + u16 reg16, pmbase; + u32 reg32; + const char *state; + int pwr_on; + int nmi_option; + int ret; + + /* + * Which state do we want to goto after g3 (power restored)? + * 0 == S0 Full On + * 1 == S5 Soft Off + * + * If the option is not existent (Laptops), use Kconfig setting. + * TODO(sjg@chromium.org): Make this configurable + */ + pwr_on = MAINBOARD_POWER_ON; + + reg16 = pci_read_config16(dev, GEN_PMCON_3); + reg16 &= 0xfffe; + switch (pwr_on) { + case MAINBOARD_POWER_OFF: + reg16 |= 1; + state = "off"; + break; + case MAINBOARD_POWER_ON: + reg16 &= ~1; + state = "on"; + break; + case MAINBOARD_POWER_KEEP: + reg16 &= ~1; + state = "state keep"; + break; + default: + state = "undefined"; + } + + reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */ + reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */ + + reg16 &= ~(1 << 10); + reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */ + + reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */ + + pci_write_config16(dev, GEN_PMCON_3, reg16); + debug("Set power %s after power failure.\n", state); + + /* Set up NMI on errors. */ + reg8 = inb(0x61); + reg8 &= 0x0f; /* Higher Nibble must be 0 */ + reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */ + reg8 |= (1 << 2); /* PCI SERR# Disable for now */ + outb(reg8, 0x61); + + reg8 = inb(0x70); + /* TODO(sjg@chromium.org): Make this configurable */ + nmi_option = NMI_OFF; + if (nmi_option) { + debug("NMI sources enabled.\n"); + reg8 &= ~(1 << 7); /* Set NMI. */ + } else { + debug("NMI sources disabled.\n"); + /* Can't mask NMI from PCI-E and NMI_NOW */ + reg8 |= (1 << 7); + } + outb(reg8, 0x70); + + /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */ + reg16 = pci_read_config16(dev, GEN_PMCON_1); + reg16 &= ~(3 << 0); /* SMI# rate 1 minute */ + reg16 &= ~(1 << 10); /* Disable BIOS_PCI_EXP_EN for native PME */ +#if DEBUG_PERIODIC_SMIS + /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using periodic SMIs */ + reg16 |= (3 << 0); /* Periodic SMI every 8s */ +#endif + pci_write_config16(dev, GEN_PMCON_1, reg16); + + /* Set the board's GPI routing. */ + ret = pch_gpi_routing(blob, node, dev); + if (ret) + return ret; + + pmbase = pci_read_config16(dev, 0x40) & 0xfffe; + + writel(pmbase + GPE0_EN, fdtdec_get_int(blob, node, + "intel,gpe0-enable", 0)); + writew(pmbase + ALT_GP_SMI_EN, fdtdec_get_int(blob, node, + "intel,alt-gp-smi-enable", 0)); + + /* Set up power management block and determine sleep mode */ + reg32 = inl(pmbase + 0x04); /* PM1_CNT */ + reg32 &= ~(7 << 10); /* SLP_TYP */ + reg32 |= (1 << 0); /* SCI_EN */ + outl(reg32, pmbase + 0x04); + + /* Clear magic status bits to prevent unexpected wake */ + setbits_le32(RCB_REG(0x3310), (1 << 4) | (1 << 5) | (1 << 0)); + clrbits_le32(RCB_REG(0x3f02), 0xf); + + return 0; +} + +static void pch_rtc_init(pci_dev_t dev) +{ + int rtc_failed; + u8 reg8; + + reg8 = pci_read_config8(dev, GEN_PMCON_3); + rtc_failed = reg8 & RTC_BATTERY_DEAD; + if (rtc_failed) { + reg8 &= ~RTC_BATTERY_DEAD; + pci_write_config8(dev, GEN_PMCON_3, reg8); + } + debug("rtc_failed = 0x%x\n", rtc_failed); + +#if CONFIG_HAVE_ACPI_RESUME + /* Avoid clearing pending interrupts and resetting the RTC control + * register in the resume path because the Linux kernel relies on + * this to know if it should restart the RTC timerqueue if the wake + * was due to the RTC alarm. + */ + if (acpi_get_slp_type() == 3) + return; +#endif + /* TODO: Handle power failure */ + if (rtc_failed) + printf("RTC power failed\n"); + rtc_init(); +} + +/* CougarPoint PCH Power Management init */ +static void cpt_pm_init(pci_dev_t dev) +{ + debug("CougarPoint PM init\n"); + pci_write_config8(dev, 0xa9, 0x47); + setbits_le32(RCB_REG(0x2238), (1 << 6) | (1 << 0)); + + setbits_le32(RCB_REG(0x228c), 1 << 0); + setbits_le32(RCB_REG(0x1100), (1 << 13) | (1 << 14)); + setbits_le32(RCB_REG(0x0900), 1 << 14); + writel(0xc0388400, RCB_REG(0x2304)); + setbits_le32(RCB_REG(0x2314), (1 << 5) | (1 << 18)); + setbits_le32(RCB_REG(0x2320), (1 << 15) | (1 << 1)); + clrsetbits_le32(RCB_REG(0x3314), ~0x1f, 0xf); + writel(0x050f0000, RCB_REG(0x3318)); + writel(0x04000000, RCB_REG(0x3324)); + setbits_le32(RCB_REG(0x3340), 0xfffff); + setbits_le32(RCB_REG(0x3344), 1 << 1); + + writel(0x0001c000, RCB_REG(0x3360)); + writel(0x00061100, RCB_REG(0x3368)); + writel(0x7f8fdfff, RCB_REG(0x3378)); + writel(0x000003fc, RCB_REG(0x337c)); + writel(0x00001000, RCB_REG(0x3388)); + writel(0x0001c000, RCB_REG(0x3390)); + writel(0x00000800, RCB_REG(0x33a0)); + writel(0x00001000, RCB_REG(0x33b0)); + writel(0x00093900, RCB_REG(0x33c0)); + writel(0x24653002, RCB_REG(0x33cc)); + writel(0x062108fe, RCB_REG(0x33d0)); + clrsetbits_le32(RCB_REG(0x33d4), 0x0fff0fff, 0x00670060); + writel(0x01010000, RCB_REG(0x3a28)); + writel(0x01010404, RCB_REG(0x3a2c)); + writel(0x01041041, RCB_REG(0x3a80)); + clrsetbits_le32(RCB_REG(0x3a84), 0x0000ffff, 0x00001001); + setbits_le32(RCB_REG(0x3a84), 1 << 24); /* SATA 2/3 disabled */ + setbits_le32(RCB_REG(0x3a88), 1 << 0); /* SATA 4/5 disabled */ + writel(0x00000001, RCB_REG(0x3a6c)); + clrsetbits_le32(RCB_REG(0x2344), ~0x00ffff00, 0xff00000c); + clrsetbits_le32(RCB_REG(0x80c), 0xff << 20, 0x11 << 20); + writel(0, RCB_REG(0x33c8)); + setbits_le32(RCB_REG(0x21b0), 0xf); +} + +/* PantherPoint PCH Power Management init */ +static void ppt_pm_init(pci_dev_t dev) +{ + debug("PantherPoint PM init\n"); + pci_write_config8(dev, 0xa9, 0x47); + setbits_le32(RCB_REG(0x2238), 1 << 0); + setbits_le32(RCB_REG(0x228c), 1 << 0); + setbits_le16(RCB_REG(0x1100), (1 << 13) | (1 << 14)); + setbits_le16(RCB_REG(0x0900), 1 << 14); + writel(0xc03b8400, RCB_REG(0x2304)); + setbits_le32(RCB_REG(0x2314), (1 << 5) | (1 << 18)); + setbits_le32(RCB_REG(0x2320), (1 << 15) | (1 << 1)); + clrsetbits_le32(RCB_REG(0x3314), 0x1f, 0xf); + writel(0x054f0000, RCB_REG(0x3318)); + writel(0x04000000, RCB_REG(0x3324)); + setbits_le32(RCB_REG(0x3340), 0xfffff); + setbits_le32(RCB_REG(0x3344), (1 << 1) | (1 << 0)); + writel(0x0001c000, RCB_REG(0x3360)); + writel(0x00061100, RCB_REG(0x3368)); + writel(0x7f8fdfff, RCB_REG(0x3378)); + writel(0x000003fd, RCB_REG(0x337c)); + writel(0x00001000, RCB_REG(0x3388)); + writel(0x0001c000, RCB_REG(0x3390)); + writel(0x00000800, RCB_REG(0x33a0)); + writel(0x00001000, RCB_REG(0x33b0)); + writel(0x00093900, RCB_REG(0x33c0)); + writel(0x24653002, RCB_REG(0x33cc)); + writel(0x067388fe, RCB_REG(0x33d0)); + clrsetbits_le32(RCB_REG(0x33d4), 0x0fff0fff, 0x00670060); + writel(0x01010000, RCB_REG(0x3a28)); + writel(0x01010404, RCB_REG(0x3a2c)); + writel(0x01040000, RCB_REG(0x3a80)); + clrsetbits_le32(RCB_REG(0x3a84), 0x0000ffff, 0x00001001); + /* SATA 2/3 disabled */ + setbits_le32(RCB_REG(0x3a84), 1 << 24); + /* SATA 4/5 disabled */ + setbits_le32(RCB_REG(0x3a88), 1 << 0); + writel(0x00000001, RCB_REG(0x3a6c)); + clrsetbits_le32(RCB_REG(0x2344), 0xff0000ff, 0xff00000c); + clrsetbits_le32(RCB_REG(0x80c), 0xff << 20, 0x11 << 20); + setbits_le32(RCB_REG(0x33a4), (1 << 0)); + writel(0, RCB_REG(0x33c8)); + setbits_le32(RCB_REG(0x21b0), 0xf); +} + +static void enable_hpet(void) +{ + /* Move HPET to default address 0xfed00000 and enable it */ + clrsetbits_le32(RCB_REG(HPTC), 3 << 0, 1 << 7); +} + +static void enable_clock_gating(pci_dev_t dev) +{ + u32 reg32; + u16 reg16; + + setbits_le32(RCB_REG(0x2234), 0xf); + + reg16 = pci_read_config16(dev, GEN_PMCON_1); + reg16 |= (1 << 2) | (1 << 11); + pci_write_config16(dev, GEN_PMCON_1, reg16); + + pch_iobp_update(0xEB007F07, ~0UL, (1 << 31)); + pch_iobp_update(0xEB004000, ~0UL, (1 << 7)); + pch_iobp_update(0xEC007F07, ~0UL, (1 << 31)); + pch_iobp_update(0xEC004000, ~0UL, (1 << 7)); + + reg32 = readl(RCB_REG(CG)); + reg32 |= (1 << 31); + reg32 |= (1 << 29) | (1 << 28); + reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24); + reg32 |= (1 << 16); + reg32 |= (1 << 17); + reg32 |= (1 << 18); + reg32 |= (1 << 22); + reg32 |= (1 << 23); + reg32 &= ~(1 << 20); + reg32 |= (1 << 19); + reg32 |= (1 << 0); + reg32 |= (0xf << 1); + writel(reg32, RCB_REG(CG)); + + setbits_le32(RCB_REG(0x38c0), 0x7); + setbits_le32(RCB_REG(0x36d4), 0x6680c004); + setbits_le32(RCB_REG(0x3564), 0x3); +} + +#if CONFIG_HAVE_SMI_HANDLER +static void pch_lock_smm(pci_dev_t dev) +{ +#if TEST_SMM_FLASH_LOCKDOWN + u8 reg8; +#endif + + if (acpi_slp_type != 3) { +#if ENABLE_ACPI_MODE_IN_COREBOOT + debug("Enabling ACPI via APMC:\n"); + outb(0xe1, 0xb2); /* Enable ACPI mode */ + debug("done.\n"); +#else + debug("Disabling ACPI via APMC:\n"); + outb(0x1e, 0xb2); /* Disable ACPI mode */ + debug("done.\n"); +#endif + } + + /* Don't allow evil boot loaders, kernels, or + * userspace applications to deceive us: + */ + smm_lock(); + +#if TEST_SMM_FLASH_LOCKDOWN + /* Now try this: */ + debug("Locking BIOS to RO... "); + reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */ + debug(" BLE: %s; BWE: %s\n", (reg8 & 2) ? "on" : "off", + (reg8 & 1) ? "rw" : "ro"); + reg8 &= ~(1 << 0); /* clear BIOSWE */ + pci_write_config8(dev, 0xdc, reg8); + reg8 |= (1 << 1); /* set BLE */ + pci_write_config8(dev, 0xdc, reg8); + debug("ok.\n"); + reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */ + debug(" BLE: %s; BWE: %s\n", (reg8 & 2) ? "on" : "off", + (reg8 & 1) ? "rw" : "ro"); + + debug("Writing:\n"); + writeb(0, 0xfff00000); + debug("Testing:\n"); + reg8 |= (1 << 0); /* set BIOSWE */ + pci_write_config8(dev, 0xdc, reg8); + + reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */ + debug(" BLE: %s; BWE: %s\n", (reg8 & 2) ? "on" : "off", + (reg8 & 1) ? "rw" : "ro"); + debug("Done.\n"); +#endif +} +#endif + +static void pch_disable_smm_only_flashing(pci_dev_t dev) +{ + u8 reg8; + + debug("Enabling BIOS updates outside of SMM... "); + reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */ + reg8 &= ~(1 << 5); + pci_write_config8(dev, 0xdc, reg8); +} + +static void pch_fixups(pci_dev_t dev) +{ + u8 gen_pmcon_2; + + /* Indicate DRAM init done for MRC S3 to know it can resume */ + gen_pmcon_2 = pci_read_config8(dev, GEN_PMCON_2); + gen_pmcon_2 |= (1 << 7); + pci_write_config8(dev, GEN_PMCON_2, gen_pmcon_2); + + /* Enable DMI ASPM in the PCH */ + clrbits_le32(RCB_REG(0x2304), 1 << 10); + setbits_le32(RCB_REG(0x21a4), (1 << 11) | (1 << 10)); + setbits_le32(RCB_REG(0x21a8), 0x3); +} + int lpc_early_init(const void *blob, int node, pci_dev_t dev) { struct reg_info { @@ -22,7 +472,7 @@ int lpc_early_init(const void *blob, int node, pci_dev_t dev) int count; int i; - count = fdtdec_get_int_array_count(blob, node, "gen-dec", + count = fdtdec_get_int_array_count(blob, node, "intel,gen-dec", (u32 *)values, sizeof(values) / sizeof(u32)); if (count < 0) return -EINVAL; @@ -46,3 +496,74 @@ int lpc_early_init(const void *blob, int node, pci_dev_t dev) return 0; } + +int lpc_init(struct pci_controller *hose, pci_dev_t dev) +{ + const void *blob = gd->fdt_blob; + int node; + + debug("pch: lpc_init\n"); + pci_write_bar32(hose, dev, 0, 0); + pci_write_bar32(hose, dev, 1, 0xff800000); + pci_write_bar32(hose, dev, 2, 0xfec00000); + pci_write_bar32(hose, dev, 3, 0x800); + pci_write_bar32(hose, dev, 4, 0x900); + + node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_LPC); + if (node < 0) + return -ENOENT; + + /* Set the value for PCI command register. */ + pci_write_config16(dev, PCI_COMMAND, 0x000f); + + /* IO APIC initialization. */ + pch_enable_apic(dev); + + pch_enable_serial_irqs(dev); + + /* Setup the PIRQ. */ + pch_pirq_init(blob, node, dev); + + /* Setup power options. */ + pch_power_options(blob, node, dev); + + /* Initialize power management */ + switch (pch_silicon_type()) { + case PCH_TYPE_CPT: /* CougarPoint */ + cpt_pm_init(dev); + break; + case PCH_TYPE_PPT: /* PantherPoint */ + ppt_pm_init(dev); + break; + default: + printf("Unknown Chipset: %#02x.%dx\n", PCI_DEV(dev), + PCI_FUNC(dev)); + return -ENOSYS; + } + + /* Initialize the real time clock. */ + pch_rtc_init(dev); + + /* Initialize the High Precision Event Timers, if present. */ + enable_hpet(); + + /* Initialize Clock Gating */ + enable_clock_gating(dev); + + pch_disable_smm_only_flashing(dev); + +#if CONFIG_HAVE_SMI_HANDLER + pch_lock_smm(dev); +#endif + + pch_fixups(dev); + + return 0; +} + +void lpc_enable(pci_dev_t dev) +{ + /* Enable PCH Display Port */ + writew(0x0010, RCB_REG(DISPBDF)); + setbits_le32(RCB_REG(FD2), PCH_ENABLE_DBDF); +} diff --git a/doc/device-tree-bindings/misc/intel-lpc.txt b/doc/device-tree-bindings/misc/intel-lpc.txt index 7e1b389..ba6ca9d 100644 --- a/doc/device-tree-bindings/misc/intel-lpc.txt +++ b/doc/device-tree-bindings/misc/intel-lpc.txt @@ -6,10 +6,37 @@ Count device is as follows: Required properties : - compatible = "intel,lpc" -- gen-dec : Specifies the values for the gen-dec registers. Up to four cell - pairs can be provided - the first of each pair is the base address and +- intel,alt-gp-smi-enable : Enable SMI sources. This cell is written to the + ALT_GP_SMI_EN register +- intel,gen-dec : Specifies the values for the gen-dec registers. Up to four + cell pairs can be provided - the first of each pair is the base address and the second is the size. These are written into the GENx_DEC registers of the LPC device +- intel,gpi-routing : Specifies the GPI routing. There are 16 cells, valid + values are: + 0 No effect (default) + 1 SMI# (if corresponding ALT_GPI_SMI_EN bit is also set) + 2 SCI (if corresponding GPIO_EN bit is also set) +- intel,pirq-routing : Speciffies the routing IRQ number for each of PIRQA-H, + one cell for each. + 0x00 - 0000 = Reserved + 0x01 - 0001 = Reserved + 0x02 - 0010 = Reserved + 0x03 - 0011 = IRQ3 + 0x04 - 0100 = IRQ4 + 0x05 - 0101 = IRQ5 + 0x06 - 0110 = IRQ6 + 0x07 - 0111 = IRQ7 + 0x08 - 1000 = Reserved + 0x09 - 1001 = IRQ9 + 0x0A - 1010 = IRQ10 + 0x0B - 1011 = IRQ11 + 0x0C - 1100 = IRQ12 + 0x0D - 1101 = Reserved + 0x0E - 1110 = IRQ14 + 0x0F - 1111 = IRQ15 + PIRQ[n]_ROUT[7] - PIRQ Routing Control + 0x80 - The PIRQ is not routed. Example @@ -19,5 +46,19 @@ lpc { compatible = "intel,lpc"; #address-cells = <1>; #size-cells = <1>; - gen-dec = <0x800 0xfc 0x900 0xfc>; + intel,gen-dec = <0x800 0xfc 0x900 0xfc>; + + intel,pirq-routing = <0x8b 0x8a 0x8b 0x8b + 0x80 0x80 0x80 0x80>; + /* + * GPI routing + * 0 No effect (default) + * 1 SMI# (if corresponding ALT_GPI_SMI_EN bit is + * also set) + * 2 SCI (if corresponding GPIO_EN bit is also set) + */ + intel,gpi-routing = <0 0 0 0 0 0 0 2 + 1 0 0 0 0 0 0 0>; + /* Enable EC SMI source */ + intel,alt-gp-smi-enable = <0x0100>; }; -- cgit v0.10.2 From b021e05535c3dabc07fbac2222db535d414110dc Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:36 -0700 Subject: x86: dts: Move PCI peripherals into a pci node These peripherals should not be at the top level, since they exist inside the PCI bus. We don't have a full device tree node for pci yet, but we should at least put it at the right level. Signed-off-by: Simon Glass diff --git a/arch/x86/dts/link.dts b/arch/x86/dts/link.dts index 9329916..4520db5 100644 --- a/arch/x86/dts/link.dts +++ b/arch/x86/dts/link.dts @@ -163,21 +163,23 @@ }; }; - lpc { - compatible = "intel,lpc"; - #address-cells = <1>; - #size-cells = <1>; - gen-dec = <0x800 0xfc 0x900 0xfc>; - cros-ec@200 { - compatible = "google,cros-ec"; - reg = <0x204 1 0x200 1 0x880 0x80>; - - /* This describes the flash memory within the EC */ + pci { + lpc { + compatible = "intel,lpc"; #address-cells = <1>; #size-cells = <1>; - flash@8000000 { - reg = <0x08000000 0x20000>; - erase-value = <0xff>; + gen-dec = <0x800 0xfc 0x900 0xfc>; + cros-ec@200 { + compatible = "google,cros-ec"; + reg = <0x204 1 0x200 1 0x880 0x80>; + + /* Describes the flash memory within the EC */ + #address-cells = <1>; + #size-cells = <1>; + flash@8000000 { + reg = <0x08000000 0x20000>; + erase-value = <0xff>; + }; }; }; }; -- cgit v0.10.2 From 05efc3961cf01916b32ef58a3965d46a11636e68 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:37 -0700 Subject: x86: dts: Add LPC settings for link Add some settings required to set up the LPC correctly. Signed-off-by: Simon Glass diff --git a/arch/x86/dts/link.dts b/arch/x86/dts/link.dts index 4520db5..28cef07 100644 --- a/arch/x86/dts/link.dts +++ b/arch/x86/dts/link.dts @@ -169,6 +169,14 @@ #address-cells = <1>; #size-cells = <1>; gen-dec = <0x800 0xfc 0x900 0xfc>; + intel,gen-dec = <0x800 0xfc 0x900 0xfc>; + intel,pirq-routing = <0x8b 0x8a 0x8b 0x8b + 0x80 0x80 0x80 0x80>; + intel,gpi-routing = <0 0 0 0 0 0 0 2 + 1 0 0 0 0 0 0 0>; + /* Enable EC SMI source */ + intel,alt-gp-smi-enable = <0x0100>; + cros-ec@200 { compatible = "google,cros-ec"; reg = <0x204 1 0x200 1 0x880 0x80>; -- cgit v0.10.2 From 3ac839352db2fb464e1e6e6a4bc50f06fb29cdb0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:38 -0700 Subject: x86: ivybridge: Add SATA init Add code to set up the SATA interfaces on boot. Signed-off-by: Simon Glass diff --git a/arch/x86/cpu/ivybridge/Makefile b/arch/x86/cpu/ivybridge/Makefile index 479e446..c6342cd 100644 --- a/arch/x86/cpu/ivybridge/Makefile +++ b/arch/x86/cpu/ivybridge/Makefile @@ -15,4 +15,5 @@ obj-y += microcode_intel.o obj-y += pch.o obj-y += pci.o obj-y += report_platform.o +obj-y += sata.o obj-y += sdram.o diff --git a/arch/x86/cpu/ivybridge/bd82x6x.c b/arch/x86/cpu/ivybridge/bd82x6x.c index be4db74..b54f5c7 100644 --- a/arch/x86/cpu/ivybridge/bd82x6x.c +++ b/arch/x86/cpu/ivybridge/bd82x6x.c @@ -88,18 +88,38 @@ void bd82x6x_pci_bus_enable_resources(pci_dev_t dev) int bd82x6x_init_pci_devices(void) { + const void *blob = gd->fdt_blob; struct pci_controller *hose; + int sata_node; hose = pci_bus_to_hose(0); lpc_enable(PCH_LPC_DEV); lpc_init(hose, PCH_LPC_DEV); + sata_node = fdtdec_next_compatible(blob, 0, + COMPAT_INTEL_PANTHERPOINT_AHCI); + if (sata_node < 0) { + debug("%s: Cannot find SATA node\n", __func__); + return -EINVAL; + } + bd82x6x_sata_init(PCH_SATA_DEV, blob, sata_node); return 0; } int bd82x6x_init(void) { + const void *blob = gd->fdt_blob; + int sata_node; + + sata_node = fdtdec_next_compatible(blob, 0, + COMPAT_INTEL_PANTHERPOINT_AHCI); + if (sata_node < 0) { + debug("%s: Cannot find SATA node\n", __func__); + return -EINVAL; + } + bd82x6x_pci_init(PCH_DEV); + bd82x6x_sata_enable(PCH_SATA_DEV, blob, sata_node); return 0; } diff --git a/arch/x86/cpu/ivybridge/sata.c b/arch/x86/cpu/ivybridge/sata.c new file mode 100644 index 0000000..bbcd47d --- /dev/null +++ b/arch/x86/cpu/ivybridge/sata.c @@ -0,0 +1,225 @@ +/* + * From Coreboot + * Copyright (C) 2008-2009 coresystems GmbH + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include + +static inline u32 sir_read(pci_dev_t dev, int idx) +{ + pci_write_config32(dev, SATA_SIRI, idx); + return pci_read_config32(dev, SATA_SIRD); +} + +static inline void sir_write(pci_dev_t dev, int idx, u32 value) +{ + pci_write_config32(dev, SATA_SIRI, idx); + pci_write_config32(dev, SATA_SIRD, value); +} + +static void common_sata_init(pci_dev_t dev, unsigned int port_map) +{ + u32 reg32; + u16 reg16; + + /* Set IDE I/O Configuration */ + reg32 = SIG_MODE_PRI_NORMAL | FAST_PCB1 | FAST_PCB0 | PCB1 | PCB0; + pci_write_config32(dev, IDE_CONFIG, reg32); + + /* Port enable */ + reg16 = pci_read_config16(dev, 0x92); + reg16 &= ~0x3f; + reg16 |= port_map; + pci_write_config16(dev, 0x92, reg16); + + /* SATA Initialization register */ + port_map &= 0xff; + pci_write_config32(dev, 0x94, ((port_map ^ 0x3f) << 24) | 0x183); +} + +void bd82x6x_sata_init(pci_dev_t dev, const void *blob, int node) +{ + unsigned int port_map, speed_support, port_tx; + struct pci_controller *hose = pci_bus_to_hose(0); + const char *mode; + u32 reg32; + u16 reg16; + + debug("SATA: Initializing...\n"); + + /* SATA configuration */ + port_map = fdtdec_get_int(blob, node, "intel,sata-port-map", 0); + speed_support = fdtdec_get_int(blob, node, + "sata_interface_speed_support", 0); + + /* Enable BARs */ + pci_write_config16(dev, PCI_COMMAND, 0x0007); + + mode = fdt_getprop(blob, node, "intel,sata-mode", NULL); + if (!mode || !strcmp(mode, "ahci")) { + u32 abar; + + debug("SATA: Controller in AHCI mode\n"); + + /* Set Interrupt Line, Interrupt Pin is set by D31IP.PIP */ + pci_write_config8(dev, INTR_LN, 0x0a); + + /* Set timings */ + pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | + IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS | + IDE_PPE0 | IDE_IE0 | IDE_TIME0); + pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE | + IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS); + + /* Sync DMA */ + pci_write_config16(dev, IDE_SDMA_CNT, IDE_PSDE0); + pci_write_config16(dev, IDE_SDMA_TIM, 0x0001); + + common_sata_init(dev, 0x8000 | port_map); + + /* Initialize AHCI memory-mapped space */ + abar = pci_read_bar32(hose, dev, 5); + debug("ABAR: %08X\n", abar); + /* CAP (HBA Capabilities) : enable power management */ + reg32 = readl(abar + 0x00); + reg32 |= 0x0c006000; /* set PSC+SSC+SALP+SSS */ + reg32 &= ~0x00020060; /* clear SXS+EMS+PMS */ + /* Set ISS, if available */ + if (speed_support) { + reg32 &= ~0x00f00000; + reg32 |= (speed_support & 0x03) << 20; + } + writel(reg32, abar + 0x00); + /* PI (Ports implemented) */ + writel(port_map, abar + 0x0c); + (void) readl(abar + 0x0c); /* Read back 1 */ + (void) readl(abar + 0x0c); /* Read back 2 */ + /* CAP2 (HBA Capabilities Extended)*/ + reg32 = readl(abar + 0x24); + reg32 &= ~0x00000002; + writel(reg32, abar + 0x24); + /* VSP (Vendor Specific Register */ + reg32 = readl(abar + 0xa0); + reg32 &= ~0x00000005; + writel(reg32, abar + 0xa0); + } else if (!strcmp(mode, "combined")) { + debug("SATA: Controller in combined mode\n"); + + /* No AHCI: clear AHCI base */ + pci_write_bar32(hose, dev, 5, 0x00000000); + /* And without AHCI BAR no memory decoding */ + reg16 = pci_read_config16(dev, PCI_COMMAND); + reg16 &= ~PCI_COMMAND_MEMORY; + pci_write_config16(dev, PCI_COMMAND, reg16); + + pci_write_config8(dev, 0x09, 0x80); + + /* Set timings */ + pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | + IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS); + pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE | + IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS | + IDE_PPE0 | IDE_IE0 | IDE_TIME0); + + /* Sync DMA */ + pci_write_config16(dev, IDE_SDMA_CNT, IDE_SSDE0); + pci_write_config16(dev, IDE_SDMA_TIM, 0x0200); + + common_sata_init(dev, port_map); + } else { + debug("SATA: Controller in plain-ide mode\n"); + + /* No AHCI: clear AHCI base */ + pci_write_bar32(hose, dev, 5, 0x00000000); + + /* And without AHCI BAR no memory decoding */ + reg16 = pci_read_config16(dev, PCI_COMMAND); + reg16 &= ~PCI_COMMAND_MEMORY; + pci_write_config16(dev, PCI_COMMAND, reg16); + + /* + * Native mode capable on both primary and secondary (0xa) + * OR'ed with enabled (0x50) = 0xf + */ + pci_write_config8(dev, 0x09, 0x8f); + + /* Set Interrupt Line */ + /* Interrupt Pin is set by D31IP.PIP */ + pci_write_config8(dev, INTR_LN, 0xff); + + /* Set timings */ + pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | + IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS | + IDE_PPE0 | IDE_IE0 | IDE_TIME0); + pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE | + IDE_SITRE | IDE_ISP_3_CLOCKS | + IDE_RCT_1_CLOCKS | IDE_IE0 | IDE_TIME0); + + /* Sync DMA */ + pci_write_config16(dev, IDE_SDMA_CNT, IDE_SSDE0 | IDE_PSDE0); + pci_write_config16(dev, IDE_SDMA_TIM, 0x0201); + + common_sata_init(dev, port_map); + } + + /* Set Gen3 Transmitter settings if needed */ + port_tx = fdtdec_get_int(blob, node, "intel,sata-port0-gen3-tx", 0); + if (port_tx) + pch_iobp_update(SATA_IOBP_SP0G3IR, 0, port_tx); + + port_tx = fdtdec_get_int(blob, node, "intel,sata-port1-gen3-tx", 0); + if (port_tx) + pch_iobp_update(SATA_IOBP_SP1G3IR, 0, port_tx); + + /* Additional Programming Requirements */ + sir_write(dev, 0x04, 0x00001600); + sir_write(dev, 0x28, 0xa0000033); + reg32 = sir_read(dev, 0x54); + reg32 &= 0xff000000; + reg32 |= 0x5555aa; + sir_write(dev, 0x54, reg32); + sir_write(dev, 0x64, 0xcccc8484); + reg32 = sir_read(dev, 0x68); + reg32 &= 0xffff0000; + reg32 |= 0xcccc; + sir_write(dev, 0x68, reg32); + reg32 = sir_read(dev, 0x78); + reg32 &= 0x0000ffff; + reg32 |= 0x88880000; + sir_write(dev, 0x78, reg32); + sir_write(dev, 0x84, 0x001c7000); + sir_write(dev, 0x88, 0x88338822); + sir_write(dev, 0xa0, 0x001c7000); + sir_write(dev, 0xc4, 0x0c0c0c0c); + sir_write(dev, 0xc8, 0x0c0c0c0c); + sir_write(dev, 0xd4, 0x10000000); + + pch_iobp_update(0xea004001, 0x3fffffff, 0xc0000000); + pch_iobp_update(0xea00408a, 0xfffffcff, 0x00000100); +} + +void bd82x6x_sata_enable(pci_dev_t dev, const void *blob, int node) +{ + unsigned port_map; + const char *mode; + u16 map = 0; + + /* + * Set SATA controller mode early so the resource allocator can + * properly assign IO/Memory resources for the controller. + */ + mode = fdt_getprop(blob, node, "intel,sata-mode", NULL); + if (mode && !strcmp(mode, "ahci")) + map = 0x0060; + port_map = fdtdec_get_int(blob, node, "intel,sata-port-map", 0); + + map |= (port_map ^ 0x3f) << 8; + pci_write_config16(dev, 0x90, map); +} diff --git a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h index e02520c..644755f 100644 --- a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h +++ b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h @@ -7,6 +7,8 @@ #ifndef _ASM_ARCH_BD82X6X_H #define _ASM_ARCH_BD82X6X_H +void bd82x6x_sata_init(pci_dev_t dev, const void *blob, int node); +void bd82x6x_sata_enable(pci_dev_t dev, const void *blob, int node); void bd82x6x_pci_init(pci_dev_t dev); int bd82x6x_init_pci_devices(void); int bd82x6x_init(void); diff --git a/arch/x86/include/asm/arch-ivybridge/pch.h b/arch/x86/include/asm/arch-ivybridge/pch.h index b3ec7c5..21df083 100644 --- a/arch/x86/include/asm/arch-ivybridge/pch.h +++ b/arch/x86/include/asm/arch-ivybridge/pch.h @@ -122,6 +122,64 @@ void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue); #define LPC_GEN4_DEC 0x90 /* LPC IF Generic Decode Range 4 */ #define LPC_GENX_DEC(x) (0x84 + 4 * (x)) +/* PCI Configuration Space (D31:F1): IDE */ +#define PCH_IDE_DEV PCI_BDF(0, 0x1f, 1) +#define PCH_SATA_DEV PCI_BDF(0, 0x1f, 2) +#define PCH_SATA2_DEV PCI_BDF(0, 0x1f, 5) + +#define INTR_LN 0x3c +#define IDE_TIM_PRI 0x40 /* IDE timings, primary */ +#define IDE_DECODE_ENABLE (1 << 15) +#define IDE_SITRE (1 << 14) +#define IDE_ISP_5_CLOCKS (0 << 12) +#define IDE_ISP_4_CLOCKS (1 << 12) +#define IDE_ISP_3_CLOCKS (2 << 12) +#define IDE_RCT_4_CLOCKS (0 << 8) +#define IDE_RCT_3_CLOCKS (1 << 8) +#define IDE_RCT_2_CLOCKS (2 << 8) +#define IDE_RCT_1_CLOCKS (3 << 8) +#define IDE_DTE1 (1 << 7) +#define IDE_PPE1 (1 << 6) +#define IDE_IE1 (1 << 5) +#define IDE_TIME1 (1 << 4) +#define IDE_DTE0 (1 << 3) +#define IDE_PPE0 (1 << 2) +#define IDE_IE0 (1 << 1) +#define IDE_TIME0 (1 << 0) +#define IDE_TIM_SEC 0x42 /* IDE timings, secondary */ + +#define IDE_SDMA_CNT 0x48 /* Synchronous DMA control */ +#define IDE_SSDE1 (1 << 3) +#define IDE_SSDE0 (1 << 2) +#define IDE_PSDE1 (1 << 1) +#define IDE_PSDE0 (1 << 0) + +#define IDE_SDMA_TIM 0x4a + +#define IDE_CONFIG 0x54 /* IDE I/O Configuration Register */ +#define SIG_MODE_SEC_NORMAL (0 << 18) +#define SIG_MODE_SEC_TRISTATE (1 << 18) +#define SIG_MODE_SEC_DRIVELOW (2 << 18) +#define SIG_MODE_PRI_NORMAL (0 << 16) +#define SIG_MODE_PRI_TRISTATE (1 << 16) +#define SIG_MODE_PRI_DRIVELOW (2 << 16) +#define FAST_SCB1 (1 << 15) +#define FAST_SCB0 (1 << 14) +#define FAST_PCB1 (1 << 13) +#define FAST_PCB0 (1 << 12) +#define SCB1 (1 << 3) +#define SCB0 (1 << 2) +#define PCB1 (1 << 1) +#define PCB0 (1 << 0) + +#define SATA_SIRI 0xa0 /* SATA Indexed Register Index */ +#define SATA_SIRD 0xa4 /* SATA Indexed Register Data */ +#define SATA_SP 0xd0 /* Scratchpad */ + +/* SATA IOBP Registers */ +#define SATA_IOBP_SP0G3IR 0xea000151 +#define SATA_IOBP_SP1G3IR 0xea000051 + /* PCI Configuration Space (D31:F3): SMBus */ #define PCH_SMBUS_DEV PCI_BDF(0, 0x1f, 3) #define SMB_BASE 0x20 diff --git a/doc/device-tree-bindings/ata/intel-sata.txt b/doc/device-tree-bindings/ata/intel-sata.txt new file mode 100644 index 0000000..5e4da83 --- /dev/null +++ b/doc/device-tree-bindings/ata/intel-sata.txt @@ -0,0 +1,26 @@ +Intel Pantherpoint SATA Device Binding +====================================== + +The device tree node which describes the operation of the Intel Pantherpoint +SATA device is as follows: + +Required properties : +- compatible = "intel,pantherpoint-ahci" +- intel,sata-mode : string, one of: + "ahci" : Use AHCI mode (default) + "combined" : Use combined IDE + legacy mode + "plain-ide" : Use plain IDE mode +- intel,sata-port-map : Which SATA ports are enabled, bit 0=enable first port, + bit 1=enable second port, etc. +- intel,sata-port0-gen3-tx : Value for the IOBP_SP0G3IR register +- intel,sata-port1-gen3-tx : Value for the IOBP_SP1G3IR register + +Example +------- + +sata { + compatible = "intel,pantherpoint-ahci"; + intel,sata-mode = "ahci"; + intel,sata-port-map = <1>; + intel,sata-port0-gen3-tx = <0x00880a7f>; +}; diff --git a/include/fdtdec.h b/include/fdtdec.h index abfd678..0a0afce 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -120,6 +120,7 @@ enum fdt_compat_id { COMPAT_INTEL_LPC, /* Intel Low Pin Count I/F */ COMPAT_INTEL_MICROCODE, /* Intel microcode update */ COMPAT_MEMORY_SPD, /* Memory SPD information */ + COMPAT_INTEL_PANTHERPOINT_AHCI, /* Intel Pantherpoint AHCI */ COMPAT_COUNT, }; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index e8775df..480442f 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -75,6 +75,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(COMPAT_INTEL_LPC, "intel,lpc"), COMPAT(INTEL_MICROCODE, "intel,microcode"), COMPAT(MEMORY_SPD, "memory-spd"), + COMPAT(INTEL_PANTHERPOINT_AHCI, "intel,pantherpoint-ahci"), }; const char *fdtdec_get_compatible(enum fdt_compat_id id) -- cgit v0.10.2 From 4896f4acc8b67155026cd1095b5dcdb22e70445a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:39 -0700 Subject: x86: dts: Add SATA settings for link Add the requires settings to enable SATA on link. Signed-off-by: Simon Glass diff --git a/arch/x86/dts/link.dts b/arch/x86/dts/link.dts index 28cef07..d3c94e0 100644 --- a/arch/x86/dts/link.dts +++ b/arch/x86/dts/link.dts @@ -164,6 +164,13 @@ }; pci { + sata { + compatible = "intel,pantherpoint-ahci"; + intel,sata-mode = "ahci"; + intel,sata-port-map = <1>; + intel,sata-port0-gen3-tx = <0x00880a7f>; + }; + lpc { compatible = "intel,lpc"; #address-cells = <1>; diff --git a/include/configs/chromebook_link.h b/include/configs/chromebook_link.h index 055b3ac..e9efd7c 100644 --- a/include/configs/chromebook_link.h +++ b/include/configs/chromebook_link.h @@ -52,7 +52,6 @@ #undef CONFIG_CMD_SF #undef CONFIG_USB_EHCI #undef CONFIG_CMD_USB -#undef CONFIG_CMD_SCSI #define CONFIG_PCI_MEM_BUS 0xe0000000 #define CONFIG_PCI_MEM_PHYS CONFIG_PCI_MEM_BUS -- cgit v0.10.2 From 9baeca4b8936edc01e1c748a6f119915acb100c4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:40 -0700 Subject: x86: ivybridge: Set up EHCI USB Add init for EHCI so that USB can be used. Signed-off-by: Simon Glass diff --git a/arch/x86/cpu/ivybridge/Makefile b/arch/x86/cpu/ivybridge/Makefile index c6342cd..4a00757 100644 --- a/arch/x86/cpu/ivybridge/Makefile +++ b/arch/x86/cpu/ivybridge/Makefile @@ -17,3 +17,4 @@ obj-y += pci.o obj-y += report_platform.o obj-y += sata.o obj-y += sdram.o +obj-y += usb_ehci.o diff --git a/arch/x86/cpu/ivybridge/bd82x6x.c b/arch/x86/cpu/ivybridge/bd82x6x.c index b54f5c7..1fcbc28 100644 --- a/arch/x86/cpu/ivybridge/bd82x6x.c +++ b/arch/x86/cpu/ivybridge/bd82x6x.c @@ -102,6 +102,8 @@ int bd82x6x_init_pci_devices(void) return -EINVAL; } bd82x6x_sata_init(PCH_SATA_DEV, blob, sata_node); + bd82x6x_usb_ehci_init(PCH_EHCI1_DEV); + bd82x6x_usb_ehci_init(PCH_EHCI2_DEV); return 0; } diff --git a/arch/x86/cpu/ivybridge/usb_ehci.c b/arch/x86/cpu/ivybridge/usb_ehci.c new file mode 100644 index 0000000..291c971 --- /dev/null +++ b/arch/x86/cpu/ivybridge/usb_ehci.c @@ -0,0 +1,29 @@ +/* + * From Coreboot + * Copyright (C) 2008-2009 coresystems GmbH + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include + +void bd82x6x_usb_ehci_init(pci_dev_t dev) +{ + u32 reg32; + + /* Disable Wake on Disconnect in RMH */ + reg32 = readl(RCB_REG(0x35b0)); + reg32 |= 0x22; + writel(reg32, RCB_REG(0x35b0)); + + debug("EHCI: Setting up controller.. "); + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 |= PCI_COMMAND_MASTER; + /* reg32 |= PCI_COMMAND_SERR; */ + pci_write_config32(dev, PCI_COMMAND, reg32); + + debug("done.\n"); +} diff --git a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h index 644755f..2e6a079 100644 --- a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h +++ b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h @@ -10,6 +10,7 @@ void bd82x6x_sata_init(pci_dev_t dev, const void *blob, int node); void bd82x6x_sata_enable(pci_dev_t dev, const void *blob, int node); void bd82x6x_pci_init(pci_dev_t dev); +void bd82x6x_usb_ehci_init(pci_dev_t dev); int bd82x6x_init_pci_devices(void); int bd82x6x_init(void); -- cgit v0.10.2 From 79b303467a2aede83dd355b46e4dadbd5b40f0ac Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:41 -0700 Subject: x86: config: Enable USB on link Enable USB support on link - there are two EHCI ports available. Signed-off-by: Simon Glass diff --git a/include/configs/chromebook_link.h b/include/configs/chromebook_link.h index e9efd7c..86429cf 100644 --- a/include/configs/chromebook_link.h +++ b/include/configs/chromebook_link.h @@ -50,8 +50,6 @@ #undef CONFIG_SPI #undef CONFIG_CMD_SPI #undef CONFIG_CMD_SF -#undef CONFIG_USB_EHCI -#undef CONFIG_CMD_USB #define CONFIG_PCI_MEM_BUS 0xe0000000 #define CONFIG_PCI_MEM_PHYS CONFIG_PCI_MEM_BUS -- cgit v0.10.2 From a6d4c453069303c3d1a499d2282f423b35c8f3b0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:42 -0700 Subject: x86: ivybridge: Set up XHCI USB Add init for XHCI so that high-speed USB can be used. Signed-off-by: Simon Glass diff --git a/arch/x86/cpu/ivybridge/Makefile b/arch/x86/cpu/ivybridge/Makefile index 4a00757..aedc395 100644 --- a/arch/x86/cpu/ivybridge/Makefile +++ b/arch/x86/cpu/ivybridge/Makefile @@ -18,3 +18,4 @@ obj-y += report_platform.o obj-y += sata.o obj-y += sdram.o obj-y += usb_ehci.o +obj-y += usb_xhci.o diff --git a/arch/x86/cpu/ivybridge/usb_xhci.c b/arch/x86/cpu/ivybridge/usb_xhci.c new file mode 100644 index 0000000..4a32a7e --- /dev/null +++ b/arch/x86/cpu/ivybridge/usb_xhci.c @@ -0,0 +1,32 @@ +/* + * From Coreboot + * Copyright (C) 2008-2009 coresystems GmbH + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include + +void bd82x6x_usb_xhci_init(pci_dev_t dev) +{ + u32 reg32; + + debug("XHCI: Setting up controller.. "); + + /* lock overcurrent map */ + reg32 = pci_read_config32(dev, 0x44); + reg32 |= 1; + pci_write_config32(dev, 0x44, reg32); + + /* Enable clock gating */ + reg32 = pci_read_config32(dev, 0x40); + reg32 &= ~((1 << 20) | (1 << 21)); + reg32 |= (1 << 19) | (1 << 18) | (1 << 17); + reg32 |= (1 << 10) | (1 << 9) | (1 << 8); + reg32 |= (1 << 31); /* lock */ + pci_write_config32(dev, 0x40, reg32); + + debug("done.\n"); +} diff --git a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h index 2e6a079..6454dd9 100644 --- a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h +++ b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h @@ -11,6 +11,7 @@ void bd82x6x_sata_init(pci_dev_t dev, const void *blob, int node); void bd82x6x_sata_enable(pci_dev_t dev, const void *blob, int node); void bd82x6x_pci_init(pci_dev_t dev); void bd82x6x_usb_ehci_init(pci_dev_t dev); +void bd82x6x_usb_xhci_init(pci_dev_t dev); int bd82x6x_init_pci_devices(void); int bd82x6x_init(void); -- cgit v0.10.2 From 18739e2ccc66e13dba10a7cb4578910daf455f01 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 18:18:43 -0700 Subject: x86: Add Intel speedstep and turbo mode code Intel chips have a turbo mode where they can run faster for a short period until they reach thermal limits. Add code to adjust and query this feature. Signed-off-by: Simon Glass diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 818969f..3839262 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_SYS_COREBOOT) += coreboot/ obj-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += ivybridge/ obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/ obj-$(CONFIG_PCI) += pci.o +obj-y += turbo.o diff --git a/arch/x86/cpu/turbo.c b/arch/x86/cpu/turbo.c new file mode 100644 index 0000000..254d0de --- /dev/null +++ b/arch/x86/cpu/turbo.c @@ -0,0 +1,98 @@ +/* + * From Coreboot file of the same name + * + * Copyright (C) 2011 The Chromium Authors. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +#if CONFIG_CPU_INTEL_TURBO_NOT_PACKAGE_SCOPED +static inline int get_global_turbo_state(void) +{ + return TURBO_UNKNOWN; +} + +static inline void set_global_turbo_state(int state) +{ +} +#else +static int g_turbo_state = TURBO_UNKNOWN; + +static inline int get_global_turbo_state(void) +{ + return g_turbo_state; +} + +static inline void set_global_turbo_state(int state) +{ + g_turbo_state = state; +} +#endif + +static const char *const turbo_state_desc[] = { + [TURBO_UNKNOWN] = "unknown", + [TURBO_UNAVAILABLE] = "unavailable", + [TURBO_DISABLED] = "available but hidden", + [TURBO_ENABLED] = "available and visible" +}; + +/* + * Determine the current state of Turbo and cache it for later. + * Turbo is a package level config so it does not need to be + * enabled on every core. + */ +int turbo_get_state(void) +{ + struct cpuid_result cpuid_regs; + int turbo_en, turbo_cap; + msr_t msr; + int turbo_state = get_global_turbo_state(); + + /* Return cached state if available */ + if (turbo_state != TURBO_UNKNOWN) + return turbo_state; + + cpuid_regs = cpuid(CPUID_LEAF_PM); + turbo_cap = !!(cpuid_regs.eax & PM_CAP_TURBO_MODE); + + msr = msr_read(MSR_IA32_MISC_ENABLES); + turbo_en = !(msr.hi & H_MISC_DISABLE_TURBO); + + if (!turbo_cap && turbo_en) { + /* Unavailable */ + turbo_state = TURBO_UNAVAILABLE; + } else if (!turbo_cap && !turbo_en) { + /* Available but disabled */ + turbo_state = TURBO_DISABLED; + } else if (turbo_cap && turbo_en) { + /* Available */ + turbo_state = TURBO_ENABLED; + } + + set_global_turbo_state(turbo_state); + debug("Turbo is %s\n", turbo_state_desc[turbo_state]); + return turbo_state; +} + +void turbo_enable(void) +{ + msr_t msr; + + /* Only possible if turbo is available but hidden */ + if (turbo_get_state() == TURBO_DISABLED) { + /* Clear Turbo Disable bit in Misc Enables */ + msr = msr_read(MSR_IA32_MISC_ENABLES); + msr.hi &= ~H_MISC_DISABLE_TURBO; + msr_write(MSR_IA32_MISC_ENABLES, msr); + + /* Update cached turbo state */ + set_global_turbo_state(TURBO_ENABLED); + debug("Turbo has been enabled\n"); + } +} diff --git a/arch/x86/include/asm/speedstep.h b/arch/x86/include/asm/speedstep.h new file mode 100644 index 0000000..b938b86 --- /dev/null +++ b/arch/x86/include/asm/speedstep.h @@ -0,0 +1,89 @@ +/* + * From Coreboot file of same name + * + * Copyright (C) 2007-2009 coresystems GmbH + * 2012 secunet Security Networks AG + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _ASM_SPEEDSTEP_H +#define _ASM_SPEEDSTEP_H + +/* Magic value used to locate speedstep configuration in the device tree */ +#define SPEEDSTEP_APIC_MAGIC 0xACAC + +/* MWAIT coordination I/O base address. This must match + * the \_PR_.CPU0 PM base address. + */ +#define PMB0_BASE 0x510 + +/* PMB1: I/O port that triggers SMI once cores are in the same state. + * See CSM Trigger, at PMG_CST_CONFIG_CONTROL[6:4] + */ +#define PMB1_BASE 0x800 + +struct sst_state { + uint8_t dynfsb:1; /* whether this is SLFM */ + uint8_t nonint:1; /* add .5 to ratio */ + uint8_t ratio:6; + uint8_t vid; + uint8_t is_turbo; + uint8_t is_slfm; + uint32_t power; +}; +#define SPEEDSTEP_RATIO_SHIFT 8 +#define SPEEDSTEP_RATIO_DYNFSB_SHIFT (7 + SPEEDSTEP_RATIO_SHIFT) +#define SPEEDSTEP_RATIO_DYNFSB (1 << SPEEDSTEP_RATIO_DYNFSB_SHIFT) +#define SPEEDSTEP_RATIO_NONINT_SHIFT (6 + SPEEDSTEP_RATIO_SHIFT) +#define SPEEDSTEP_RATIO_NONINT (1 << SPEEDSTEP_RATIO_NONINT_SHIFT) +#define SPEEDSTEP_RATIO_VALUE_MASK (0x1f << SPEEDSTEP_RATIO_SHIFT) +#define SPEEDSTEP_VID_MASK 0x3f +#define SPEEDSTEP_STATE_FROM_MSR(val, mask) ((struct sst_state){ \ + 0, /* dynfsb won't be read. */ \ + ((val & mask) & SPEEDSTEP_RATIO_NONINT) ? 1 : 0, \ + (((val & mask) & SPEEDSTEP_RATIO_VALUE_MASK) \ + >> SPEEDSTEP_RATIO_SHIFT), \ + (val & mask) & SPEEDSTEP_VID_MASK, \ + 0, /* not turbo by default */ \ + 0, /* not slfm by default */ \ + 0 /* power is hardcoded in software. */ \ + }) +#define SPEEDSTEP_ENCODE_STATE(state) ( \ + ((uint16_t)(state).dynfsb << SPEEDSTEP_RATIO_DYNFSB_SHIFT) | \ + ((uint16_t)(state).nonint << SPEEDSTEP_RATIO_NONINT_SHIFT) | \ + ((uint16_t)(state).ratio << SPEEDSTEP_RATIO_SHIFT) | \ + ((uint16_t)(state).vid & SPEEDSTEP_VID_MASK)) +#define SPEEDSTEP_DOUBLE_RATIO(state) ( \ + ((uint8_t)(state).ratio * 2) + (state).nonint) + +struct sst_params { + struct sst_state slfm; + struct sst_state min; + struct sst_state max; + struct sst_state turbo; +}; + +/* Looking at core2's spec, the highest normal bus ratio for an eist enabled + processor is 14, the lowest is always 6. This makes 5 states with the + minimal step width of 2. With turbo mode and super LFM we have at most 7. */ +#define SPEEDSTEP_MAX_NORMAL_STATES 5 +#define SPEEDSTEP_MAX_STATES (SPEEDSTEP_MAX_NORMAL_STATES + 2) +struct sst_table { + /* Table of p-states for EMTTM and ACPI by decreasing performance. */ + struct sst_state states[SPEEDSTEP_MAX_STATES]; + int num_states; +}; + +void speedstep_gen_pstates(struct sst_table *); + +#define SPEEDSTEP_MAX_POWER_YONAH 31000 +#define SPEEDSTEP_MIN_POWER_YONAH 13100 +#define SPEEDSTEP_MAX_POWER_MEROM 35000 +#define SPEEDSTEP_MIN_POWER_MEROM 25000 +#define SPEEDSTEP_SLFM_POWER_MEROM 12000 +#define SPEEDSTEP_MAX_POWER_PENRYN 35000 +#define SPEEDSTEP_MIN_POWER_PENRYN 15000 +#define SPEEDSTEP_SLFM_POWER_PENRYN 12000 + +#endif diff --git a/arch/x86/include/asm/turbo.h b/arch/x86/include/asm/turbo.h new file mode 100644 index 0000000..bb0d4b4 --- /dev/null +++ b/arch/x86/include/asm/turbo.h @@ -0,0 +1,31 @@ +/* + * From coreboot file of the same name + * + * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _ASM_TURBO_H +#define _ASM_TURBO_H + +#define CPUID_LEAF_PM 6 +#define PM_CAP_TURBO_MODE (1 << 1) + +#define MSR_IA32_MISC_ENABLES 0x1a0 +#define H_MISC_DISABLE_TURBO (1 << 6) + +enum { + TURBO_UNKNOWN, + TURBO_UNAVAILABLE, + TURBO_DISABLED, + TURBO_ENABLED, +}; + +/* Return current turbo state */ +int turbo_get_state(void); + +/* Enable turbo */ +void turbo_enable(void); + +#endif -- cgit v0.10.2 From 4372a9eca5561ec21277b616b5223cf23ab526ca Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 20 Nov 2014 16:10:49 +0800 Subject: x86: Call cpu_init_interrupts() from interrupt_init() Currently cpu_init_interrupts() is called from cpu_init_r() to setup the interrupt and exception of the cpu core, but at that time the i8259 has not been initialized to mask all the irqs and remap the master i8259 interrupt vector base, so the whole system is at risk of being interrupted, and if interrupted, wrong interrupt/exception message is shown. Signed-off-by: Bin Meng Acked-by: Simon Glass Tested-by: Simon Glass diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index b391b7a..ac25392 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -322,8 +322,6 @@ int x86_cpu_init_f(void) int x86_cpu_init_r(void) { - /* Initialize core interrupt and exception functionality of CPU */ - cpu_init_interrupts(); return 0; } int cpu_init_r(void) __attribute__((weak, alias("x86_cpu_init_r"))); diff --git a/arch/x86/lib/pcat_interrupts.c b/arch/x86/lib/pcat_interrupts.c index 2dc2fbd..f388db2 100644 --- a/arch/x86/lib/pcat_interrupts.c +++ b/arch/x86/lib/pcat_interrupts.c @@ -65,6 +65,9 @@ int interrupt_init(void) /* Interrupt 9 should be level triggered (SCI). The OS might do this */ configure_irq_trigger(9, true); + /* Initialize core interrupt and exception functionality of CPU */ + cpu_init_interrupts(); + enable_interrupts(); return 0; -- cgit v0.10.2 From a549f7497b4d719d37e4a20378c81c1b29bf0404 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 20 Nov 2014 16:11:00 +0800 Subject: x86: Remove cpu_init_r() for x86 Since cpu_init_interrupts() was moved out of cpu_init_r(), it is useless to keep cpu_init_r() for x86, thus remove it. Signed-off-by: Bin Meng Acked-by: Simon Glass Tested-by: Simon Glass diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index ac25392..cf421fa 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -320,12 +320,6 @@ int x86_cpu_init_f(void) return 0; } -int x86_cpu_init_r(void) -{ - return 0; -} -int cpu_init_r(void) __attribute__((weak, alias("x86_cpu_init_r"))); - void x86_enable_caches(void) { unsigned long cr0; diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index 98217dd..36145cb 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -10,8 +10,6 @@ /* cpu/.../cpu.c */ int arch_cpu_init(void); -int x86_cpu_init_r(void); -int cpu_init_r(void); int x86_cpu_init_f(void); int cpu_init_f(void); void init_gd(gd_t *id, u64 *gdt_addr); diff --git a/common/board_r.c b/common/board_r.c index bfa74c7..9f085b1 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -775,7 +775,7 @@ init_fnc_t init_sequence_r[] = { initr_flash, #endif INIT_FUNC_WATCHDOG_RESET -#if defined(CONFIG_PPC) || defined(CONFIG_X86) +#if defined(CONFIG_PPC) /* initialize higher level parts of CPU like time base and timers */ cpu_init_r, #endif -- cgit v0.10.2 From 1dae2e0eb660553fd18870b53e4c43bd56414e3b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 20 Nov 2014 16:11:16 +0800 Subject: x86: Refactor interrupt_init() Rename interrupt_init() in arch/x86/lib/pcat_interrupts.c to i8259_init() and create a new interrupt_init() in arch/x86/cpu/interrupt.c to call i8259_init() followed by a call to cpu_init_interrupts(). Signed-off-by: Bin Meng Acked-by: Simon Glass Tested-by: Simon Glass diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index 51e2c59..ea03724 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -20,6 +20,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -128,9 +129,6 @@ int cpu_init_interrupts(void) int irq_entry_size = irq_1 - irq_0; void *irq_entry = (void *)irq_0; - /* Just in case... */ - disable_interrupts(); - /* Setup the IDT */ for (i = 0; i < 256; i++) { idt[i].access = 0x8e; @@ -146,9 +144,6 @@ int cpu_init_interrupts(void) load_idt(&idt_ptr); - /* It is now safe to enable interrupts */ - enable_interrupts(); - return 0; } @@ -172,6 +167,25 @@ int disable_interrupts(void) return flags & X86_EFLAGS_IF; } +int interrupt_init(void) +{ + /* Just in case... */ + disable_interrupts(); + +#ifdef CONFIG_SYS_PCAT_INTERRUPTS + /* Initialize the master/slave i8259 pic */ + i8259_init(); +#endif + + /* Initialize core interrupt and exception functionality of CPU */ + cpu_init_interrupts(); + + /* It is now safe to enable interrupts */ + enable_interrupts(); + + return 0; +} + /* IRQ Low-Level Service Routine */ void irq_llsr(struct irq_regs *regs) { diff --git a/arch/x86/include/asm/i8259.h b/arch/x86/include/asm/i8259.h index 73113f9..bc4033b 100644 --- a/arch/x86/include/asm/i8259.h +++ b/arch/x86/include/asm/i8259.h @@ -69,4 +69,6 @@ #define ICW4_AEOI 0x02 /* Automatic EOI Mode */ #define ICW4_PM 0x01 /* Microprocessor Mode */ +int i8259_init(void); + #endif diff --git a/arch/x86/lib/pcat_interrupts.c b/arch/x86/lib/pcat_interrupts.c index f388db2..a9af87e 100644 --- a/arch/x86/lib/pcat_interrupts.c +++ b/arch/x86/lib/pcat_interrupts.c @@ -24,12 +24,10 @@ #error "CONFIG_SYS_NUM_IRQS must equal 16 if CONFIG_SYS_NUM_IRQS is defined" #endif -int interrupt_init(void) +int i8259_init(void) { u8 i; - disable_interrupts(); - /* Mask all interrupts */ outb(0xff, MASTER_PIC + IMR); outb(0xff, SLAVE_PIC + IMR); @@ -65,11 +63,6 @@ int interrupt_init(void) /* Interrupt 9 should be level triggered (SCI). The OS might do this */ configure_irq_trigger(9, true); - /* Initialize core interrupt and exception functionality of CPU */ - cpu_init_interrupts(); - - enable_interrupts(); - return 0; } -- cgit v0.10.2 From d51457583f48c68e8b8ed69ed4cb4de11eac383a Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 20 Nov 2014 16:11:27 +0800 Subject: x86: Remove unnecessary call to initr_enable_interrupts() Actually initr_enable_interrupts() was never called in an x86 build due to it was wrapped by CONFIG_x86 (typo of X86). Signed-off-by: Bin Meng Acked-by: Simon Glass Tested-by: Simon Glass diff --git a/common/board_r.c b/common/board_r.c index 9f085b1..1b8998d 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -839,7 +839,7 @@ init_fnc_t init_sequence_r[] = { initr_kgdb, #endif interrupt_init, -#if defined(CONFIG_ARM) || defined(CONFIG_x86) +#if defined(CONFIG_ARM) initr_enable_interrupts, #endif #ifdef CONFIG_X86 -- cgit v0.10.2 From b636dd1079fcdd55a38412afacb2be91a82cce1e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 24 Nov 2014 21:18:14 -0700 Subject: x86: Drop old CONFIG_INTEL_CORE_ARCH code This is no-longer used, so drop it. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index ea03724..a21d2a6 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -617,31 +617,3 @@ asm(".globl irq_common_entry\n" \ DECLARE_INTERRUPT(253) \ DECLARE_INTERRUPT(254) \ DECLARE_INTERRUPT(255)); - -#if defined(CONFIG_INTEL_CORE_ARCH) -/* - * Get the number of CPU time counter ticks since it was read first time after - * restart. This yields a free running counter guaranteed to take almost 6 - * years to wrap around even at 100GHz clock rate. - */ -u64 get_ticks(void) -{ - u64 now_tick = rdtsc(); - - if (!gd->arch.tsc_base) - gd->arch.tsc_base = now_tick; - - return now_tick - gd->arch.tsc_base; -} - -#define PLATFORM_INFO_MSR 0xce - -unsigned long get_tbclk(void) -{ - u32 ratio; - u64 platform_info = native_read_msr(PLATFORM_INFO_MSR); - - ratio = (platform_info >> 8) & 0xff; - return 100 * 1000 * 1000 * ratio; /* 100MHz times Max Non Turbo ratio */ -} -#endif -- cgit v0.10.2 From 0c9075e9ad21caa43c524288d7def9e8b081fa11 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 24 Nov 2014 21:18:15 -0700 Subject: x86: Add LAPIC setup code Add code to set up the Local Advanced Peripheral Interrupt Controller. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 3839262..7f09db5 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -15,5 +15,6 @@ obj-y += interrupts.o cpu.o call64.o obj-$(CONFIG_SYS_COREBOOT) += coreboot/ obj-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += ivybridge/ obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/ +obj-y += lapic.o obj-$(CONFIG_PCI) += pci.o obj-y += turbo.o diff --git a/arch/x86/cpu/lapic.c b/arch/x86/cpu/lapic.c new file mode 100644 index 0000000..4690603 --- /dev/null +++ b/arch/x86/cpu/lapic.c @@ -0,0 +1,57 @@ +/* + * From coreboot file of same name + * + * Copyright (C) 2008-2009 coresystems GmbH + * Copyright (C) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +void lapic_setup(void) +{ +#if NEED_LAPIC == 1 + /* Only Pentium Pro and later have those MSR stuff */ + debug("Setting up local apic: "); + + /* Enable the local apic */ + enable_lapic(); + + /* + * Set Task Priority to 'accept all'. + */ + lapic_write_around(LAPIC_TASKPRI, + lapic_read_around(LAPIC_TASKPRI) & ~LAPIC_TPRI_MASK); + + /* Put the local apic in virtual wire mode */ + lapic_write_around(LAPIC_SPIV, (lapic_read_around(LAPIC_SPIV) & + ~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE); + lapic_write_around(LAPIC_LVT0, (lapic_read_around(LAPIC_LVT0) & + ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | + LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | + LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | + LAPIC_DELIVERY_MODE_MASK)) | + (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | + LAPIC_DELIVERY_MODE_EXTINT)); + lapic_write_around(LAPIC_LVT1, (lapic_read_around(LAPIC_LVT1) & + ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | + LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | + LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | + LAPIC_DELIVERY_MODE_MASK)) | + (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | + LAPIC_DELIVERY_MODE_NMI)); + + debug("apic_id: 0x%02lx, ", lapicid()); +#else /* !NEED_LLAPIC */ + /* Only Pentium Pro and later have those MSR stuff */ + debug("Disabling local apic: "); + disable_lapic(); +#endif /* !NEED_LAPIC */ + debug("done.\n"); + post_code(POST_LAPIC); +} diff --git a/arch/x86/include/asm/lapic.h b/arch/x86/include/asm/lapic.h index 948e643..0a7f443 100644 --- a/arch/x86/include/asm/lapic.h +++ b/arch/x86/include/asm/lapic.h @@ -14,6 +14,13 @@ #include #include +/* See if I need to initialize the local apic */ +#if CONFIG_SMP || CONFIG_IOAPIC +# define NEED_LAPIC 1 +#else +# define NEED_LAPIC 0 +#endif + static inline __attribute__((always_inline)) unsigned long lapic_read(unsigned long reg) { @@ -37,8 +44,9 @@ static inline void enable_lapic(void) msr = msr_read(LAPIC_BASE_MSR); msr.hi &= 0xffffff00; - msr.lo &= 0x000007ff; - msr.lo |= LAPIC_DEFAULT_BASE | (1 << 11); + msr.lo |= LAPIC_BASE_MSR_ENABLE; + msr.lo &= ~LAPIC_BASE_MSR_ADDR_MASK; + msr.lo |= LAPIC_DEFAULT_BASE; msr_write(LAPIC_BASE_MSR, msr); } @@ -56,4 +64,116 @@ static inline __attribute__((always_inline)) unsigned long lapicid(void) return lapic_read(LAPIC_ID) >> 24; } +#if !CONFIG_AP_IN_SIPI_WAIT +/* If we need to go back to sipi wait, we use the long non-inlined version of + * this function in lapic_cpu_init.c + */ +static inline __attribute__((always_inline)) void stop_this_cpu(void) +{ + /* Called by an AP when it is ready to halt and wait for a new task */ + for (;;) + cpu_hlt(); +} +#else +void stop_this_cpu(void); +#endif + +#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ + sizeof(*(ptr)))) + +struct __xchg_dummy { unsigned long a[100]; }; +#define __xg(x) ((struct __xchg_dummy *)(x)) + +/* + * Note: no "lock" prefix even on SMP: xchg always implies lock anyway + * Note 2: xchg has side effect, so that attribute volatile is necessary, + * but generally the primitive is invalid, *ptr is output argument. --ANK + */ +static inline unsigned long __xchg(unsigned long x, volatile void *ptr, + int size) +{ + switch (size) { + case 1: + __asm__ __volatile__("xchgb %b0,%1" + : "=q" (x) + : "m" (*__xg(ptr)), "0" (x) + : "memory"); + break; + case 2: + __asm__ __volatile__("xchgw %w0,%1" + : "=r" (x) + : "m" (*__xg(ptr)), "0" (x) + : "memory"); + break; + case 4: + __asm__ __volatile__("xchgl %0,%1" + : "=r" (x) + : "m" (*__xg(ptr)), "0" (x) + : "memory"); + break; + } + + return x; +} + +static inline void lapic_write_atomic(unsigned long reg, unsigned long v) +{ + (void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v); +} + + +#ifdef X86_GOOD_APIC +# define FORCE_READ_AROUND_WRITE 0 +# define lapic_read_around(x) lapic_read(x) +# define lapic_write_around(x, y) lapic_write((x), (y)) +#else +# define FORCE_READ_AROUND_WRITE 1 +# define lapic_read_around(x) lapic_read(x) +# define lapic_write_around(x, y) lapic_write_atomic((x), (y)) +#endif + +static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue) +{ + int timeout; + unsigned long status; + int result; + lapic_wait_icr_idle(); + lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); + lapic_write_around(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4)); + timeout = 0; + do { + status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK; + } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000); + + result = -1; + if (status == LAPIC_ICR_RR_VALID) { + *pvalue = lapic_read(LAPIC_RRR); + result = 0; + } + return result; +} + + +void lapic_setup(void); + +#if CONFIG_SMP +struct device; +int start_cpu(struct device *cpu); +#endif /* CONFIG_SMP */ + +int boot_cpu(void); + +/** + * struct x86_cpu_priv - Information about a single CPU + * + * @apic_id: Advanced Programmable Interrupt Controller Identifier, which is + * just a number representing the CPU core + * + * TODO: Move this to driver model once lifecycle is understood + */ +struct x86_cpu_priv { + int apic_id; + int start_err; +}; + #endif diff --git a/arch/x86/include/asm/post.h b/arch/x86/include/asm/post.h index ce68839..6d2ae5d 100644 --- a/arch/x86/include/asm/post.h +++ b/arch/x86/include/asm/post.h @@ -30,6 +30,7 @@ #define POST_PRE_MRC 0x2e #define POST_MRC 0x2f #define POST_DRAM 0x2f +#define POST_LAPIC 0x30 #define POST_RAM_FAILURE 0xea -- cgit v0.10.2 From bb80be391693a868c2114d1a9505c45dce7a3607 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 24 Nov 2014 21:18:16 -0700 Subject: x86: Add init for model 206AX CPU Add the setup code for the CPU so that it can be used at full speed. Signed-off-by: Simon Glass diff --git a/arch/x86/cpu/ivybridge/Makefile b/arch/x86/cpu/ivybridge/Makefile index aedc395..95491b5 100644 --- a/arch/x86/cpu/ivybridge/Makefile +++ b/arch/x86/cpu/ivybridge/Makefile @@ -11,6 +11,7 @@ obj-y += early_init.o obj-y += early_me.o obj-y += lpc.o obj-y += me_status.o +obj-y += model_206ax.o obj-y += microcode_intel.o obj-y += pch.o obj-y += pci.o diff --git a/arch/x86/cpu/ivybridge/bd82x6x.c b/arch/x86/cpu/ivybridge/bd82x6x.c index 1fcbc28..1a3c036 100644 --- a/arch/x86/cpu/ivybridge/bd82x6x.c +++ b/arch/x86/cpu/ivybridge/bd82x6x.c @@ -90,6 +90,7 @@ int bd82x6x_init_pci_devices(void) { const void *blob = gd->fdt_blob; struct pci_controller *hose; + struct x86_cpu_priv *cpu; int sata_node; hose = pci_bus_to_hose(0); @@ -105,6 +106,11 @@ int bd82x6x_init_pci_devices(void) bd82x6x_usb_ehci_init(PCH_EHCI1_DEV); bd82x6x_usb_ehci_init(PCH_EHCI2_DEV); + cpu = calloc(1, sizeof(*cpu)); + if (!cpu) + return -ENOMEM; + model_206ax_init(cpu); + return 0; } diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c new file mode 100644 index 0000000..11dc625 --- /dev/null +++ b/arch/x86/cpu/ivybridge/model_206ax.c @@ -0,0 +1,514 @@ +/* + * From Coreboot file of same name + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2011 The Chromium Authors + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void enable_vmx(void) +{ + struct cpuid_result regs; +#ifdef CONFIG_ENABLE_VMX + int enable = true; +#else + int enable = false; +#endif + msr_t msr; + + regs = cpuid(1); + /* Check that the VMX is supported before reading or writing the MSR. */ + if (!((regs.ecx & CPUID_VMX) || (regs.ecx & CPUID_SMX))) + return; + + msr = msr_read(MSR_IA32_FEATURE_CONTROL); + + if (msr.lo & (1 << 0)) { + debug("VMX is locked, so %s will do nothing\n", __func__); + /* VMX locked. If we set it again we get an illegal + * instruction + */ + return; + } + + /* The IA32_FEATURE_CONTROL MSR may initialize with random values. + * It must be cleared regardless of VMX config setting. + */ + msr.hi = 0; + msr.lo = 0; + + debug("%s VMX\n", enable ? "Enabling" : "Disabling"); + + /* + * Even though the Intel manual says you must set the lock bit in + * addition to the VMX bit in order for VMX to work, it is incorrect. + * Thus we leave it unlocked for the OS to manage things itself. + * This is good for a few reasons: + * - No need to reflash the bios just to toggle the lock bit. + * - The VMX bits really really should match each other across cores, + * so hard locking it on one while another has the opposite setting + * can easily lead to crashes as code using VMX migrates between + * them. + * - Vendors that want to "upsell" from a bios that disables+locks to + * one that doesn't is sleazy. + * By leaving this to the OS (e.g. Linux), people can do exactly what + * they want on the fly, and do it correctly (e.g. across multiple + * cores). + */ + if (enable) { + msr.lo |= (1 << 2); + if (regs.ecx & CPUID_SMX) + msr.lo |= (1 << 1); + } + + msr_write(MSR_IA32_FEATURE_CONTROL, msr); +} + +/* Convert time in seconds to POWER_LIMIT_1_TIME MSR value */ +static const u8 power_limit_time_sec_to_msr[] = { + [0] = 0x00, + [1] = 0x0a, + [2] = 0x0b, + [3] = 0x4b, + [4] = 0x0c, + [5] = 0x2c, + [6] = 0x4c, + [7] = 0x6c, + [8] = 0x0d, + [10] = 0x2d, + [12] = 0x4d, + [14] = 0x6d, + [16] = 0x0e, + [20] = 0x2e, + [24] = 0x4e, + [28] = 0x6e, + [32] = 0x0f, + [40] = 0x2f, + [48] = 0x4f, + [56] = 0x6f, + [64] = 0x10, + [80] = 0x30, + [96] = 0x50, + [112] = 0x70, + [128] = 0x11, +}; + +/* Convert POWER_LIMIT_1_TIME MSR value to seconds */ +static const u8 power_limit_time_msr_to_sec[] = { + [0x00] = 0, + [0x0a] = 1, + [0x0b] = 2, + [0x4b] = 3, + [0x0c] = 4, + [0x2c] = 5, + [0x4c] = 6, + [0x6c] = 7, + [0x0d] = 8, + [0x2d] = 10, + [0x4d] = 12, + [0x6d] = 14, + [0x0e] = 16, + [0x2e] = 20, + [0x4e] = 24, + [0x6e] = 28, + [0x0f] = 32, + [0x2f] = 40, + [0x4f] = 48, + [0x6f] = 56, + [0x10] = 64, + [0x30] = 80, + [0x50] = 96, + [0x70] = 112, + [0x11] = 128, +}; + +int cpu_config_tdp_levels(void) +{ + struct cpuid_result result; + msr_t platform_info; + + /* Minimum CPU revision */ + result = cpuid(1); + if (result.eax < IVB_CONFIG_TDP_MIN_CPUID) + return 0; + + /* Bits 34:33 indicate how many levels supported */ + platform_info = msr_read(MSR_PLATFORM_INFO); + return (platform_info.hi >> 1) & 3; +} + +/* + * Configure processor power limits if possible + * This must be done AFTER set of BIOS_RESET_CPL + */ +void set_power_limits(u8 power_limit_1_time) +{ + msr_t msr = msr_read(MSR_PLATFORM_INFO); + msr_t limit; + unsigned power_unit; + unsigned tdp, min_power, max_power, max_time; + u8 power_limit_1_val; + + if (power_limit_1_time > ARRAY_SIZE(power_limit_time_sec_to_msr)) + return; + + if (!(msr.lo & PLATFORM_INFO_SET_TDP)) + return; + + /* Get units */ + msr = msr_read(MSR_PKG_POWER_SKU_UNIT); + power_unit = 2 << ((msr.lo & 0xf) - 1); + + /* Get power defaults for this SKU */ + msr = msr_read(MSR_PKG_POWER_SKU); + tdp = msr.lo & 0x7fff; + min_power = (msr.lo >> 16) & 0x7fff; + max_power = msr.hi & 0x7fff; + max_time = (msr.hi >> 16) & 0x7f; + + debug("CPU TDP: %u Watts\n", tdp / power_unit); + + if (power_limit_time_msr_to_sec[max_time] > power_limit_1_time) + power_limit_1_time = power_limit_time_msr_to_sec[max_time]; + + if (min_power > 0 && tdp < min_power) + tdp = min_power; + + if (max_power > 0 && tdp > max_power) + tdp = max_power; + + power_limit_1_val = power_limit_time_sec_to_msr[power_limit_1_time]; + + /* Set long term power limit to TDP */ + limit.lo = 0; + limit.lo |= tdp & PKG_POWER_LIMIT_MASK; + limit.lo |= PKG_POWER_LIMIT_EN; + limit.lo |= (power_limit_1_val & PKG_POWER_LIMIT_TIME_MASK) << + PKG_POWER_LIMIT_TIME_SHIFT; + + /* Set short term power limit to 1.25 * TDP */ + limit.hi = 0; + limit.hi |= ((tdp * 125) / 100) & PKG_POWER_LIMIT_MASK; + limit.hi |= PKG_POWER_LIMIT_EN; + /* Power limit 2 time is only programmable on SNB EP/EX */ + + msr_write(MSR_PKG_POWER_LIMIT, limit); + + /* Use nominal TDP values for CPUs with configurable TDP */ + if (cpu_config_tdp_levels()) { + msr = msr_read(MSR_CONFIG_TDP_NOMINAL); + limit.hi = 0; + limit.lo = msr.lo & 0xff; + msr_write(MSR_TURBO_ACTIVATION_RATIO, limit); + } +} + +static void configure_c_states(void) +{ + struct cpuid_result result; + msr_t msr; + + msr = msr_read(MSR_PMG_CST_CONFIG_CTL); + msr.lo |= (1 << 28); /* C1 Auto Undemotion Enable */ + msr.lo |= (1 << 27); /* C3 Auto Undemotion Enable */ + msr.lo |= (1 << 26); /* C1 Auto Demotion Enable */ + msr.lo |= (1 << 25); /* C3 Auto Demotion Enable */ + msr.lo &= ~(1 << 10); /* Disable IO MWAIT redirection */ + msr.lo |= 7; /* No package C-state limit */ + msr_write(MSR_PMG_CST_CONFIG_CTL, msr); + + msr = msr_read(MSR_PMG_IO_CAPTURE_ADR); + msr.lo &= ~0x7ffff; + msr.lo |= (PMB0_BASE + 4); /* LVL_2 base address */ + msr.lo |= (2 << 16); /* CST Range: C7 is max C-state */ + msr_write(MSR_PMG_IO_CAPTURE_ADR, msr); + + msr = msr_read(MSR_MISC_PWR_MGMT); + msr.lo &= ~(1 << 0); /* Enable P-state HW_ALL coordination */ + msr_write(MSR_MISC_PWR_MGMT, msr); + + msr = msr_read(MSR_POWER_CTL); + msr.lo |= (1 << 18); /* Enable Energy Perf Bias MSR 0x1b0 */ + msr.lo |= (1 << 1); /* C1E Enable */ + msr.lo |= (1 << 0); /* Bi-directional PROCHOT# */ + msr_write(MSR_POWER_CTL, msr); + + /* C3 Interrupt Response Time Limit */ + msr.hi = 0; + msr.lo = IRTL_VALID | IRTL_1024_NS | 0x50; + msr_write(MSR_PKGC3_IRTL, msr); + + /* C6 Interrupt Response Time Limit */ + msr.hi = 0; + msr.lo = IRTL_VALID | IRTL_1024_NS | 0x68; + msr_write(MSR_PKGC6_IRTL, msr); + + /* C7 Interrupt Response Time Limit */ + msr.hi = 0; + msr.lo = IRTL_VALID | IRTL_1024_NS | 0x6D; + msr_write(MSR_PKGC7_IRTL, msr); + + /* Primary Plane Current Limit */ + msr = msr_read(MSR_PP0_CURRENT_CONFIG); + msr.lo &= ~0x1fff; + msr.lo |= PP0_CURRENT_LIMIT; + msr_write(MSR_PP0_CURRENT_CONFIG, msr); + + /* Secondary Plane Current Limit */ + msr = msr_read(MSR_PP1_CURRENT_CONFIG); + msr.lo &= ~0x1fff; + result = cpuid(1); + if (result.eax >= 0x30600) + msr.lo |= PP1_CURRENT_LIMIT_IVB; + else + msr.lo |= PP1_CURRENT_LIMIT_SNB; + msr_write(MSR_PP1_CURRENT_CONFIG, msr); +} + +static int configure_thermal_target(void) +{ + int tcc_offset; + msr_t msr; + int node; + + /* Find pointer to CPU configuration */ + node = fdtdec_next_compatible(gd->fdt_blob, 0, + COMPAT_INTEL_MODEL_206AX); + if (node < 0) + return -ENOENT; + tcc_offset = fdtdec_get_int(gd->fdt_blob, node, "tcc-offset", 0); + + /* Set TCC activaiton offset if supported */ + msr = msr_read(MSR_PLATFORM_INFO); + if ((msr.lo & (1 << 30)) && tcc_offset) { + msr = msr_read(MSR_TEMPERATURE_TARGET); + msr.lo &= ~(0xf << 24); /* Bits 27:24 */ + msr.lo |= (tcc_offset & 0xf) << 24; + msr_write(MSR_TEMPERATURE_TARGET, msr); + } + + return 0; +} + +static void configure_misc(void) +{ + msr_t msr; + + msr = msr_read(IA32_MISC_ENABLE); + msr.lo |= (1 << 0); /* Fast String enable */ + msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */ + msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */ + msr_write(IA32_MISC_ENABLE, msr); + + /* Disable Thermal interrupts */ + msr.lo = 0; + msr.hi = 0; + msr_write(IA32_THERM_INTERRUPT, msr); + + /* Enable package critical interrupt only */ + msr.lo = 1 << 4; + msr.hi = 0; + msr_write(IA32_PACKAGE_THERM_INTERRUPT, msr); +} + +static void enable_lapic_tpr(void) +{ + msr_t msr; + + msr = msr_read(MSR_PIC_MSG_CONTROL); + msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */ + msr_write(MSR_PIC_MSG_CONTROL, msr); +} + +static void configure_dca_cap(void) +{ + struct cpuid_result cpuid_regs; + msr_t msr; + + /* Check feature flag in CPUID.(EAX=1):ECX[18]==1 */ + cpuid_regs = cpuid(1); + if (cpuid_regs.ecx & (1 << 18)) { + msr = msr_read(IA32_PLATFORM_DCA_CAP); + msr.lo |= 1; + msr_write(IA32_PLATFORM_DCA_CAP, msr); + } +} + +static void set_max_ratio(void) +{ + msr_t msr, perf_ctl; + + perf_ctl.hi = 0; + + /* Check for configurable TDP option */ + if (cpu_config_tdp_levels()) { + /* Set to nominal TDP ratio */ + msr = msr_read(MSR_CONFIG_TDP_NOMINAL); + perf_ctl.lo = (msr.lo & 0xff) << 8; + } else { + /* Platform Info bits 15:8 give max ratio */ + msr = msr_read(MSR_PLATFORM_INFO); + perf_ctl.lo = msr.lo & 0xff00; + } + msr_write(IA32_PERF_CTL, perf_ctl); + + debug("model_x06ax: frequency set to %d\n", + ((perf_ctl.lo >> 8) & 0xff) * SANDYBRIDGE_BCLK); +} + +static void set_energy_perf_bias(u8 policy) +{ + msr_t msr; + + /* Energy Policy is bits 3:0 */ + msr = msr_read(IA32_ENERGY_PERFORMANCE_BIAS); + msr.lo &= ~0xf; + msr.lo |= policy & 0xf; + msr_write(IA32_ENERGY_PERFORMANCE_BIAS, msr); + + debug("model_x06ax: energy policy set to %u\n", policy); +} + +static void configure_mca(void) +{ + msr_t msr; + int i; + + msr.lo = 0; + msr.hi = 0; + /* This should only be done on a cold boot */ + for (i = 0; i < 7; i++) + msr_write(IA32_MC0_STATUS + (i * 4), msr); +} + +#if CONFIG_USBDEBUG +static unsigned ehci_debug_addr; +#endif + +/* + * Initialize any extra cores/threads in this package. + */ +static int intel_cores_init(struct x86_cpu_priv *cpu) +{ + struct cpuid_result result; + unsigned threads_per_package, threads_per_core, i; + + /* Logical processors (threads) per core */ + result = cpuid_ext(0xb, 0); + threads_per_core = result.ebx & 0xffff; + + /* Logical processors (threads) per package */ + result = cpuid_ext(0xb, 1); + threads_per_package = result.ebx & 0xffff; + + debug("CPU: %u has %u cores, %u threads per core\n", + cpu->apic_id, threads_per_package / threads_per_core, + threads_per_core); + + for (i = 1; i < threads_per_package; ++i) { + struct x86_cpu_priv *new_cpu; + + new_cpu = calloc(1, sizeof(*new_cpu)); + if (!new_cpu) + return -ENOMEM; + + new_cpu->apic_id = cpu->apic_id + i; + + /* Update APIC ID if no hyperthreading */ + if (threads_per_core == 1) + new_cpu->apic_id <<= 1; + + debug("CPU: %u has core %u\n", cpu->apic_id, new_cpu->apic_id); + +#if CONFIG_SMP && CONFIG_MAX_CPUS > 1 + /* Start the new cpu */ + if (!start_cpu(new_cpu)) { + /* Record the error in cpu? */ + printk(BIOS_ERR, "CPU %u would not start!\n", + new_cpu->apic_id); + new_cpu->start_err = 1; + } +#endif + } + + return 0; +} + +int model_206ax_init(struct x86_cpu_priv *cpu) +{ + int ret; + + /* Clear out pending MCEs */ + configure_mca(); + +#if CONFIG_USBDEBUG + /* Is this caution really needed? */ + if (!ehci_debug_addr) + ehci_debug_addr = get_ehci_debug(); + set_ehci_debug(0); +#endif + + /* Setup MTRRs based on physical address size */ +#if 0 /* TODO: Implement this */ + struct cpuid_result cpuid_regs; + + cpuid_regs = cpuid(0x80000008); + x86_setup_fixed_mtrrs(); + x86_setup_var_mtrrs(cpuid_regs.eax & 0xff, 2); + x86_mtrr_check(); +#endif + +#if CONFIG_USBDEBUG + set_ehci_debug(ehci_debug_addr); +#endif + + /* Enable the local cpu apics */ + enable_lapic_tpr(); + lapic_setup(); + + /* Enable virtualization if enabled in CMOS */ + enable_vmx(); + + /* Configure C States */ + configure_c_states(); + + /* Configure Enhanced SpeedStep and Thermal Sensors */ + configure_misc(); + + /* Thermal throttle activation offset */ + ret = configure_thermal_target(); + if (ret) + return ret; + + /* Enable Direct Cache Access */ + configure_dca_cap(); + + /* Set energy policy */ + set_energy_perf_bias(ENERGY_POLICY_NORMAL); + + /* Set Max Ratio */ + set_max_ratio(); + + /* Enable Turbo */ + turbo_enable(); + + /* Start up extra cores */ + intel_cores_init(cpu); + + return 0; +} diff --git a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h index 6454dd9..96d51c2 100644 --- a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h +++ b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h @@ -15,4 +15,7 @@ void bd82x6x_usb_xhci_init(pci_dev_t dev); int bd82x6x_init_pci_devices(void); int bd82x6x_init(void); +struct x86_cpu_priv; +int model_206ax_init(struct x86_cpu_priv *cpu); + #endif diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 6027d59..2cbb270 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -326,6 +326,8 @@ #define MSR_AMD_PERF_STATUS 0xc0010063 #define MSR_AMD_PERF_CTL 0xc0010062 +#define MSR_PMG_CST_CONFIG_CTL 0x000000e2 +#define MSR_PMG_IO_CAPTURE_ADR 0x000000e4 #define MSR_IA32_MPERF 0x000000e7 #define MSR_IA32_APERF 0x000000e8 diff --git a/include/fdtdec.h b/include/fdtdec.h index 0a0afce..b6e1d40 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -121,6 +121,7 @@ enum fdt_compat_id { COMPAT_INTEL_MICROCODE, /* Intel microcode update */ COMPAT_MEMORY_SPD, /* Memory SPD information */ COMPAT_INTEL_PANTHERPOINT_AHCI, /* Intel Pantherpoint AHCI */ + COMPAT_INTEL_MODEL_206AX, /* Intel Model 206AX CPU */ COMPAT_COUNT, }; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 480442f..723a957 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -76,6 +76,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(INTEL_MICROCODE, "intel,microcode"), COMPAT(MEMORY_SPD, "memory-spd"), COMPAT(INTEL_PANTHERPOINT_AHCI, "intel,pantherpoint-ahci"), + COMPAT(INTEL_MODEL_206AX, "intel,model-206ax"), }; const char *fdtdec_get_compatible(enum fdt_compat_id id) -- cgit v0.10.2 From d1ef1132bbcf2cc14f36f5114d88ff3fa74106df Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 24 Nov 2014 21:18:17 -0700 Subject: x86: Drop some msr functions that we don't support These are not available in U-Boot as yet, so drop them. Signed-off-by: Simon Glass diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index df43983..1955a75 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h @@ -229,17 +229,6 @@ do { \ struct msr *msrs_alloc(void); void msrs_free(struct msr *msrs); -#ifdef CONFIG_SMP -int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); -int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); -void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs); -void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs); -int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); -int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); -int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]); -int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]); - -#endif /* CONFIG_SMP */ #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ #endif /* _ASM_X86_MSR_H */ -- cgit v0.10.2 From 24774278c9dc4e44487cb565282d4a4830327fd4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 24 Nov 2014 21:18:18 -0700 Subject: x86: ivybridge: Add northbridge init functions Add init for the northbridge, another part of the platform controller hub. Signed-off-by: Simon Glass diff --git a/arch/x86/cpu/ivybridge/Makefile b/arch/x86/cpu/ivybridge/Makefile index 95491b5..1296a78 100644 --- a/arch/x86/cpu/ivybridge/Makefile +++ b/arch/x86/cpu/ivybridge/Makefile @@ -13,6 +13,7 @@ obj-y += lpc.o obj-y += me_status.o obj-y += model_206ax.o obj-y += microcode_intel.o +obj-y += northbridge.o obj-y += pch.o obj-y += pci.o obj-y += report_platform.o diff --git a/arch/x86/cpu/ivybridge/bd82x6x.c b/arch/x86/cpu/ivybridge/bd82x6x.c index 1a3c036..739f979 100644 --- a/arch/x86/cpu/ivybridge/bd82x6x.c +++ b/arch/x86/cpu/ivybridge/bd82x6x.c @@ -128,6 +128,8 @@ int bd82x6x_init(void) bd82x6x_pci_init(PCH_DEV); bd82x6x_sata_enable(PCH_SATA_DEV, blob, sata_node); + northbridge_enable(PCH_DEV); + northbridge_init(PCH_DEV); return 0; } diff --git a/arch/x86/cpu/ivybridge/northbridge.c b/arch/x86/cpu/ivybridge/northbridge.c new file mode 100644 index 0000000..c50b5de --- /dev/null +++ b/arch/x86/cpu/ivybridge/northbridge.c @@ -0,0 +1,188 @@ +/* + * From Coreboot northbridge/intel/sandybridge/northbridge.c + * + * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2011 The Chromium Authors + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int bridge_revision_id = -1; + +int bridge_silicon_revision(void) +{ + if (bridge_revision_id < 0) { + struct cpuid_result result; + uint8_t stepping, bridge_id; + pci_dev_t dev; + + result = cpuid(1); + stepping = result.eax & 0xf; + dev = PCI_BDF(0, 0, 0); + bridge_id = pci_read_config16(dev, PCI_DEVICE_ID) & 0xf0; + bridge_revision_id = bridge_id | stepping; + } + + return bridge_revision_id; +} + +/* + * Reserve everything between A segment and 1MB: + * + * 0xa0000 - 0xbffff: legacy VGA + * 0xc0000 - 0xcffff: VGA OPROM (needed by kernel) + * 0xe0000 - 0xfffff: SeaBIOS, if used, otherwise DMI + */ +static const int legacy_hole_base_k = 0xa0000 / 1024; +static const int legacy_hole_size_k = 384; + +static int get_pcie_bar(u32 *base, u32 *len) +{ + pci_dev_t dev = PCI_BDF(0, 0, 0); + u32 pciexbar_reg; + + *base = 0; + *len = 0; + + pciexbar_reg = pci_read_config32(dev, PCIEXBAR); + + if (!(pciexbar_reg & (1 << 0))) + return 0; + + switch ((pciexbar_reg >> 1) & 3) { + case 0: /* 256MB */ + *base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) | + (1 << 28)); + *len = 256 * 1024 * 1024; + return 1; + case 1: /* 128M */ + *base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) | + (1 << 28) | (1 << 27)); + *len = 128 * 1024 * 1024; + return 1; + case 2: /* 64M */ + *base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) | + (1 << 28) | (1 << 27) | (1 << 26)); + *len = 64 * 1024 * 1024; + return 1; + } + + return 0; +} + +static void add_fixed_resources(pci_dev_t dev, int index) +{ + u32 pcie_config_base, pcie_config_size; + + if (get_pcie_bar(&pcie_config_base, &pcie_config_size)) { + debug("Adding PCIe config bar base=0x%08x size=0x%x\n", + pcie_config_base, pcie_config_size); + } +} + +static void northbridge_dmi_init(pci_dev_t dev) +{ + /* Clear error status bits */ + writel(0xffffffff, DMIBAR_REG(0x1c4)); + writel(0xffffffff, DMIBAR_REG(0x1d0)); + + /* Steps prior to DMI ASPM */ + if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) { + clrsetbits_le32(DMIBAR_REG(0x250), (1 << 22) | (1 << 20), + 1 << 21); + } + + setbits_le32(DMIBAR_REG(0x238), 1 << 29); + + if (bridge_silicon_revision() >= SNB_STEP_D0) { + setbits_le32(DMIBAR_REG(0x1f8), 1 << 16); + } else if (bridge_silicon_revision() >= SNB_STEP_D1) { + clrsetbits_le32(DMIBAR_REG(0x1f8), 1 << 26, 1 << 16); + setbits_le32(DMIBAR_REG(0x1fc), (1 << 12) | (1 << 23)); + } + + /* Enable ASPM on SNB link, should happen before PCH link */ + if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) + setbits_le32(DMIBAR_REG(0xd04), 1 << 4); + + setbits_le32(DMIBAR_REG(0x88), (1 << 1) | (1 << 0)); +} + +void northbridge_init(pci_dev_t dev) +{ + u32 bridge_type; + + add_fixed_resources(dev, 6); + northbridge_dmi_init(dev); + + bridge_type = readl(MCHBAR_REG(0x5f10)); + bridge_type &= ~0xff; + + if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_IVB) { + /* Enable Power Aware Interrupt Routing - fixed priority */ + clrsetbits_8(MCHBAR_REG(0x5418), 0xf, 0x4); + + /* 30h for IvyBridge */ + bridge_type |= 0x30; + } else { + /* 20h for Sandybridge */ + bridge_type |= 0x20; + } + writel(bridge_type, MCHBAR_REG(0x5f10)); + + /* + * Set bit 0 of BIOS_RESET_CPL to indicate to the CPU + * that BIOS has initialized memory and power management + */ + setbits_8(MCHBAR_REG(BIOS_RESET_CPL), 1); + debug("Set BIOS_RESET_CPL\n"); + + /* Configure turbo power limits 1ms after reset complete bit */ + mdelay(1); + set_power_limits(28); + + /* + * CPUs with configurable TDP also need power limits set + * in MCHBAR. Use same values from MSR_PKG_POWER_LIMIT. + */ + if (cpu_config_tdp_levels()) { + msr_t msr = msr_read(MSR_PKG_POWER_LIMIT); + + writel(msr.lo, MCHBAR_REG(0x59A0)); + writel(msr.hi, MCHBAR_REG(0x59A4)); + } + + /* Set here before graphics PM init */ + writel(0x00100001, MCHBAR_REG(0x5500)); +} + +void northbridge_enable(pci_dev_t dev) +{ +#if CONFIG_HAVE_ACPI_RESUME + switch (pci_read_config32(dev, SKPAD)) { + case 0xcafebabe: + debug("Normal boot.\n"); + apci_set_slp_type(0); + break; + case 0xcafed00d: + debug("S3 Resume.\n"); + apci_set_slp_type(3); + break; + default: + debug("Unknown boot method, assuming normal.\n"); + apci_set_slp_type(0); + break; + } +#endif +} diff --git a/arch/x86/include/asm/arch-ivybridge/model_206ax.h b/arch/x86/include/asm/arch-ivybridge/model_206ax.h index 8281d7a..7b4f2e7 100644 --- a/arch/x86/include/asm/arch-ivybridge/model_206ax.h +++ b/arch/x86/include/asm/arch-ivybridge/model_206ax.h @@ -79,4 +79,8 @@ #define PSS_LATENCY_TRANSITION 10 #define PSS_LATENCY_BUSMASTER 10 +/* Configure power limits for turbo mode */ +void set_power_limits(u8 power_limit_1_time); +int cpu_config_tdp_levels(void); + #endif diff --git a/arch/x86/include/asm/arch-ivybridge/sandybridge.h b/arch/x86/include/asm/arch-ivybridge/sandybridge.h index 114ee19..cf7457f 100644 --- a/arch/x86/include/asm/arch-ivybridge/sandybridge.h +++ b/arch/x86/include/asm/arch-ivybridge/sandybridge.h @@ -97,11 +97,22 @@ /* * MCHBAR */ -#define MCHBAR_REG(reg) (DEFAULT_RCBA + (reg)) +#define MCHBAR_REG(reg) (DEFAULT_MCHBAR + (reg)) #define SSKPD 0x5d14 /* 16bit (scratchpad) */ #define BIOS_RESET_CPL 0x5da8 /* 8bit */ +/* + * DMIBAR + */ + +#define DMIBAR_REG(x) (DEFAULT_DMIBAR + x) + +int bridge_silicon_revision(void); + +void northbridge_enable(pci_dev_t dev); +void northbridge_init(pci_dev_t dev); + void report_platform_info(void); void sandybridge_early_init(int chipset_type); -- cgit v0.10.2 From 1ccd452b07c21072c15366d19343b61996ce9486 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 24 Nov 2014 21:18:19 -0700 Subject: x86: config: Enable SPI for chromebook_link Enable SPI so that the SPI flash can be used. Signed-off-by: Simon Glass diff --git a/include/configs/chromebook_link.h b/include/configs/chromebook_link.h index 86429cf..6b57b28 100644 --- a/include/configs/chromebook_link.h +++ b/include/configs/chromebook_link.h @@ -46,10 +46,6 @@ */ #undef CONFIG_VIDEO #undef CONFIG_CFB_CONSOLE -#undef CONFIG_ICH_SPI -#undef CONFIG_SPI -#undef CONFIG_CMD_SPI -#undef CONFIG_CMD_SF #define CONFIG_PCI_MEM_BUS 0xe0000000 #define CONFIG_PCI_MEM_PHYS CONFIG_PCI_MEM_BUS -- cgit v0.10.2 From ed0a2fbf14f7f87c437eb5fd99a994fa5d12f07a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:27 -0700 Subject: x86: Add a definition of asmlinkage This is needed to permit calling C from assembler without too much pain. Add a definition for x86. Signed-off-by: Simon Glass diff --git a/include/common.h b/include/common.h index f1ab2cf..94c354b 100644 --- a/include/common.h +++ b/include/common.h @@ -73,6 +73,9 @@ typedef volatile unsigned char vu_char; #ifdef CONFIG_ARM #define asmlinkage /* nothing */ #endif +#ifdef CONFIG_X86 +#define asmlinkage __attribute__((regparm(0))) +#endif #ifdef CONFIG_BLACKFIN #include #endif -- cgit v0.10.2 From 176bf4ce0cb8ddf380f116860951641c4a700271 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:28 -0700 Subject: Introduce a header file for the BIOS emulator We should have a public header so that users can avoid defining functions themselves. Signed-off-by: Simon Glass diff --git a/drivers/bios_emulator/include/biosemu.h b/drivers/bios_emulator/include/biosemu.h index e92e96e..124d79d 100644 --- a/drivers/bios_emulator/include/biosemu.h +++ b/drivers/bios_emulator/include/biosemu.h @@ -43,6 +43,8 @@ #ifndef __BIOSEMU_H #define __BIOSEMU_H +#include + #ifdef __KERNEL__ #include "x86emu.h" #else @@ -55,57 +57,6 @@ #pragma pack(1) -#ifndef __KERNEL__ -/**************************************************************************** -REMARKS: -Data structure used to describe the details specific to a particular VGA -controller. This information is used to allow the VGA controller to be -swapped on the fly within the BIOS emulator. - -HEADER: -biosemu.h - -MEMBERS: -pciInfo - PCI device information block for the controller -BIOSImage - Pointer to a read/write copy of the BIOS image -BIOSImageLen - Length of the BIOS image -LowMem - Copy of key low memory areas -****************************************************************************/ -typedef struct { - PCIDeviceInfo *pciInfo; - void *BIOSImage; - ulong BIOSImageLen; - uchar LowMem[1536]; -} BE_VGAInfo; -#else -/**************************************************************************** -REMARKS: -Data structure used to describe the details for the BIOS emulator system -environment as used by the X86 emulator library. - -HEADER: -biosemu.h - -MEMBERS: -vgaInfo - VGA BIOS information structure -biosmem_base - Base of the BIOS image -biosmem_limit - Limit of the BIOS image -busmem_base - Base of the VGA bus memory -****************************************************************************/ -typedef struct { - int function; - int device; - int bus; - u32 VendorID; - u32 DeviceID; - pci_dev_t pcidev; - void *BIOSImage; - u32 BIOSImageLen; - u8 LowMem[1536]; -} BE_VGAInfo; - -#endif /* __KERNEL__ */ - #define CRT_C 24 /* 24 CRT Controller Registers */ #define ATT_C 21 /* 21 Attribute Controller Registers */ #define GRA_C 9 /* 9 Graphics Controller Registers */ diff --git a/drivers/video/ati_radeon_fb.c b/drivers/video/ati_radeon_fb.c index 618f5d9..5748951 100644 --- a/drivers/video/ati_radeon_fb.c +++ b/drivers/video/ati_radeon_fb.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -544,7 +545,6 @@ void radeon_setmode_9200(int vesa_idx, int bpp) } #include "../bios_emulator/include/biosemu.h" -extern int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo ** pVGAInfo, int cleanUp); int radeon_probe(struct radeonfb_info *rinfo) { diff --git a/include/bios_emul.h b/include/bios_emul.h new file mode 100644 index 0000000..35d1ff3 --- /dev/null +++ b/include/bios_emul.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 1996-1999 SciTech Software, Inc. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _BIOS_EMUL_H +#define _BIOS_EMUL_H + +/* Include the register header directly here */ +#include "../drivers/bios_emulator/include/x86emu/regs.h" + +/**************************************************************************** +REMARKS: +Data structure used to describe the details for the BIOS emulator system +environment as used by the X86 emulator library. + +HEADER: +biosemu.h + +MEMBERS: +vgaInfo - VGA BIOS information structure +biosmem_base - Base of the BIOS image +biosmem_limit - Limit of the BIOS image +busmem_base - Base of the VGA bus memory +****************************************************************************/ +typedef struct { + int function; + int device; + int bus; + u32 VendorID; + u32 DeviceID; + pci_dev_t pcidev; + void *BIOSImage; + u32 BIOSImageLen; + u8 LowMem[1536]; +} BE_VGAInfo; + +struct vbe_mode_info; + +int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo **pVGAInfo, int cleanUp); + +#endif -- cgit v0.10.2 From e34aef1de36893250a788a272b6242e46da31b86 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:29 -0700 Subject: x86: Add GDT descriptors for option ROMs Option ROMs require a few additional descriptors. Add these, and remove the enum since we now have to access several descriptors from assembler. Signed-off-by: Simon Glass diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index cf421fa..30e5069 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -124,7 +124,7 @@ static void load_gdt(const u64 *boot_gdt, u16 num_entries) { struct gdt_ptr gdt; - gdt.len = (num_entries * 8) - 1; + gdt.len = (num_entries * X86_GDT_ENTRY_SIZE) - 1; gdt.ptr = (u32)boot_gdt; asm volatile("lgdtl %0\n" : : "m" (gdt)); @@ -144,10 +144,13 @@ void setup_gdt(gd_t *id, u64 *gdt_addr) (ulong)&id->arch.gd_addr, 0xfffff); /* 16-bit CS: code, read/execute, 64 kB, base 0 */ - gdt_addr[X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x109b, 0, 0x0ffff); + gdt_addr[X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x009b, 0, 0x0ffff); /* 16-bit DS: data, read/write, 64 kB, base 0 */ - gdt_addr[X86_GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x1093, 0, 0x0ffff); + gdt_addr[X86_GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x0093, 0, 0x0ffff); + + gdt_addr[X86_GDT_ENTRY_16BIT_FLAT_CS] = GDT_ENTRY(0x809b, 0, 0xfffff); + gdt_addr[X86_GDT_ENTRY_16BIT_FLAT_DS] = GDT_ENTRY(0x8093, 0, 0xfffff); load_gdt(gdt_addr, X86_GDT_NUM_ENTRIES); load_ds(X86_GDT_ENTRY_32BIT_DS); diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index b9317cb..3e26202 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -8,25 +8,18 @@ #ifndef __ASM_PROCESSOR_H_ #define __ASM_PROCESSOR_H_ 1 -#define X86_GDT_ENTRY_SIZE 8 - -#ifndef __ASSEMBLY__ - -enum { - X86_GDT_ENTRY_NULL = 0, - X86_GDT_ENTRY_UNUSED, - X86_GDT_ENTRY_32BIT_CS, - X86_GDT_ENTRY_32BIT_DS, - X86_GDT_ENTRY_32BIT_FS, - X86_GDT_ENTRY_16BIT_CS, - X86_GDT_ENTRY_16BIT_DS, - X86_GDT_NUM_ENTRIES -}; -#else -/* NOTE: If the above enum is modified, this define must be checked */ -#define X86_GDT_ENTRY_32BIT_DS 3 -#define X86_GDT_NUM_ENTRIES 7 -#endif +#define X86_GDT_ENTRY_SIZE 8 + +#define X86_GDT_ENTRY_NULL 0 +#define X86_GDT_ENTRY_UNUSED 1 +#define X86_GDT_ENTRY_32BIT_CS 2 +#define X86_GDT_ENTRY_32BIT_DS 3 +#define X86_GDT_ENTRY_32BIT_FS 4 +#define X86_GDT_ENTRY_16BIT_CS 5 +#define X86_GDT_ENTRY_16BIT_DS 6 +#define X86_GDT_ENTRY_16BIT_FLAT_CS 7 +#define X86_GDT_ENTRY_16BIT_FLAT_DS 8 +#define X86_GDT_NUM_ENTRIES 9 #define X86_GDT_SIZE (X86_GDT_NUM_ENTRIES * X86_GDT_ENTRY_SIZE) -- cgit v0.10.2 From 22465fc46cdec15594277edb33e930c773b10b9e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:30 -0700 Subject: x86: Add vesa mode configuration options Add Kconfig options to allow selection of a vesa mode on x86 machines. Signed-off-by: Simon Glass diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6e29868..4f5ce38 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -83,6 +83,155 @@ config X86_RAMTEST to work correctly. It is not exhaustive but can save time by detecting obvious failures. +config MARK_GRAPHICS_MEM_WRCOMB + bool "Mark graphics memory as write-combining." + default n + help + The graphics performance may increase if the graphics + memory is set as write-combining cache type. This option + enables marking the graphics memory as write-combining. + +menu "Display" + +config FRAMEBUFFER_SET_VESA_MODE + prompt "Set framebuffer graphics resolution" + bool + help + Set VESA/native framebuffer mode (needed for bootsplash and graphical framebuffer console) + +choice + prompt "framebuffer graphics resolution" + default FRAMEBUFFER_VESA_MODE_117 + depends on FRAMEBUFFER_SET_VESA_MODE + help + This option sets the resolution used for the coreboot framebuffer (and + bootsplash screen). + +config FRAMEBUFFER_VESA_MODE_100 + bool "640x400 256-color" + +config FRAMEBUFFER_VESA_MODE_101 + bool "640x480 256-color" + +config FRAMEBUFFER_VESA_MODE_102 + bool "800x600 16-color" + +config FRAMEBUFFER_VESA_MODE_103 + bool "800x600 256-color" + +config FRAMEBUFFER_VESA_MODE_104 + bool "1024x768 16-color" + +config FRAMEBUFFER_VESA_MODE_105 + bool "1024x7686 256-color" + +config FRAMEBUFFER_VESA_MODE_106 + bool "1280x1024 16-color" + +config FRAMEBUFFER_VESA_MODE_107 + bool "1280x1024 256-color" + +config FRAMEBUFFER_VESA_MODE_108 + bool "80x60 text" + +config FRAMEBUFFER_VESA_MODE_109 + bool "132x25 text" + +config FRAMEBUFFER_VESA_MODE_10A + bool "132x43 text" + +config FRAMEBUFFER_VESA_MODE_10B + bool "132x50 text" + +config FRAMEBUFFER_VESA_MODE_10C + bool "132x60 text" + +config FRAMEBUFFER_VESA_MODE_10D + bool "320x200 32k-color (1:5:5:5)" + +config FRAMEBUFFER_VESA_MODE_10E + bool "320x200 64k-color (5:6:5)" + +config FRAMEBUFFER_VESA_MODE_10F + bool "320x200 16.8M-color (8:8:8)" + +config FRAMEBUFFER_VESA_MODE_110 + bool "640x480 32k-color (1:5:5:5)" + +config FRAMEBUFFER_VESA_MODE_111 + bool "640x480 64k-color (5:6:5)" + +config FRAMEBUFFER_VESA_MODE_112 + bool "640x480 16.8M-color (8:8:8)" + +config FRAMEBUFFER_VESA_MODE_113 + bool "800x600 32k-color (1:5:5:5)" + +config FRAMEBUFFER_VESA_MODE_114 + bool "800x600 64k-color (5:6:5)" + +config FRAMEBUFFER_VESA_MODE_115 + bool "800x600 16.8M-color (8:8:8)" + +config FRAMEBUFFER_VESA_MODE_116 + bool "1024x768 32k-color (1:5:5:5)" + +config FRAMEBUFFER_VESA_MODE_117 + bool "1024x768 64k-color (5:6:5)" + +config FRAMEBUFFER_VESA_MODE_118 + bool "1024x768 16.8M-color (8:8:8)" + +config FRAMEBUFFER_VESA_MODE_119 + bool "1280x1024 32k-color (1:5:5:5)" + +config FRAMEBUFFER_VESA_MODE_11A + bool "1280x1024 64k-color (5:6:5)" + +config FRAMEBUFFER_VESA_MODE_11B + bool "1280x1024 16.8M-color (8:8:8)" + +config FRAMEBUFFER_VESA_MODE_USER + bool "Manually select VESA mode" + +endchoice + +# Map the config names to an integer (KB). +config FRAMEBUFFER_VESA_MODE + prompt "VESA mode" if FRAMEBUFFER_VESA_MODE_USER + hex + default 0x100 if FRAMEBUFFER_VESA_MODE_100 + default 0x101 if FRAMEBUFFER_VESA_MODE_101 + default 0x102 if FRAMEBUFFER_VESA_MODE_102 + default 0x103 if FRAMEBUFFER_VESA_MODE_103 + default 0x104 if FRAMEBUFFER_VESA_MODE_104 + default 0x105 if FRAMEBUFFER_VESA_MODE_105 + default 0x106 if FRAMEBUFFER_VESA_MODE_106 + default 0x107 if FRAMEBUFFER_VESA_MODE_107 + default 0x108 if FRAMEBUFFER_VESA_MODE_108 + default 0x109 if FRAMEBUFFER_VESA_MODE_109 + default 0x10A if FRAMEBUFFER_VESA_MODE_10A + default 0x10B if FRAMEBUFFER_VESA_MODE_10B + default 0x10C if FRAMEBUFFER_VESA_MODE_10C + default 0x10D if FRAMEBUFFER_VESA_MODE_10D + default 0x10E if FRAMEBUFFER_VESA_MODE_10E + default 0x10F if FRAMEBUFFER_VESA_MODE_10F + default 0x110 if FRAMEBUFFER_VESA_MODE_110 + default 0x111 if FRAMEBUFFER_VESA_MODE_111 + default 0x112 if FRAMEBUFFER_VESA_MODE_112 + default 0x113 if FRAMEBUFFER_VESA_MODE_113 + default 0x114 if FRAMEBUFFER_VESA_MODE_114 + default 0x115 if FRAMEBUFFER_VESA_MODE_115 + default 0x116 if FRAMEBUFFER_VESA_MODE_116 + default 0x117 if FRAMEBUFFER_VESA_MODE_117 + default 0x118 if FRAMEBUFFER_VESA_MODE_118 + default 0x119 if FRAMEBUFFER_VESA_MODE_119 + default 0x11A if FRAMEBUFFER_VESA_MODE_11A + default 0x11B if FRAMEBUFFER_VESA_MODE_11B + default 0x117 if FRAMEBUFFER_VESA_MODE_USER + +endmenu + source "arch/x86/cpu/ivybridge/Kconfig" source "board/coreboot/coreboot/Kconfig" -- cgit v0.10.2 From 647f56e74e398f40891b9997ae06b9fdb776825e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:31 -0700 Subject: Add support for Vesa BIOS extensions For option ROMs we can use these extensions to request a particular video mode. Add a header file which defines the binary interface. Signed-off-by: Simon Glass diff --git a/include/vbe.h b/include/vbe.h new file mode 100644 index 0000000..d405691 --- /dev/null +++ b/include/vbe.h @@ -0,0 +1,103 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * Copyright (c) 2009 Pattrick Hueper + * All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#ifndef _VBE_H +#define _VBE_H + +/* these structs are for input from and output to OF */ +struct __packed screen_info { + u8 display_type; /* 0=NONE, 1= analog, 2=digital */ + u16 screen_width; + u16 screen_height; + /* bytes per line in framebuffer, may be more than screen_width */ + u16 screen_linebytes; + u8 color_depth; /* color depth in bits per pixel */ + u32 framebuffer_address; + u8 edid_block_zero[128]; +}; + +struct __packed screen_info_input { + u8 signature[4]; + u16 size_reserved; + u8 monitor_number; + u16 max_screen_width; + u8 color_depth; +}; + +/* these structs only store the required a subset of the VBE-defined fields */ +struct __packed vbe_info { + char signature[4]; + u16 version; + u8 *oem_string_ptr; + u32 capabilities; + u16 video_mode_list[256]; + u16 total_memory; +}; + +struct __packed vesa_mode_info { + u16 mode_attributes; /* 00 */ + u8 win_a_attributes; /* 02 */ + u8 win_b_attributes; /* 03 */ + u16 win_granularity; /* 04 */ + u16 win_size; /* 06 */ + u16 win_a_segment; /* 08 */ + u16 win_b_segment; /* 0a */ + u32 win_func_ptr; /* 0c */ + u16 bytes_per_scanline; /* 10 */ + u16 x_resolution; /* 12 */ + u16 y_resolution; /* 14 */ + u8 x_charsize; /* 16 */ + u8 y_charsize; /* 17 */ + u8 number_of_planes; /* 18 */ + u8 bits_per_pixel; /* 19 */ + u8 number_of_banks; /* 20 */ + u8 memory_model; /* 21 */ + u8 bank_size; /* 22 */ + u8 number_of_image_pages; /* 23 */ + u8 reserved_page; + u8 red_mask_size; + u8 red_mask_pos; + u8 green_mask_size; + u8 green_mask_pos; + u8 blue_mask_size; + u8 blue_mask_pos; + u8 reserved_mask_size; + u8 reserved_mask_pos; + u8 direct_color_mode_info; + u32 phys_base_ptr; + u32 offscreen_mem_offset; + u16 offscreen_mem_size; + u8 reserved[206]; +}; + +struct vbe_mode_info { + u16 video_mode; + bool valid; + union { + struct vesa_mode_info vesa; + u8 mode_info_block[256]; + }; +}; + +struct vbe_ddc_info { + u8 port_number; /* i.e. monitor number */ + u8 edid_transfer_time; + u8 ddc_level; + u8 edid_block_zero[128]; +}; + +#define VESA_GET_INFO 0x4f00 +#define VESA_GET_MODE_INFO 0x4f01 +#define VESA_SET_MODE 0x4f02 + +struct graphic_device; +int vbe_get_video_info(struct graphic_device *gdev); + +#endif -- cgit v0.10.2 From 0ca2426beae04189f094180748e72463f48a9270 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:32 -0700 Subject: x86: Add support for running option ROMs natively On x86 machines we can use an emulator to run option ROMS as with other architectures. But with some additional effort (mostly due to the 16-bit nature of option ROMs) we can run them natively. Add support for this. Signed-off-by: Simon Glass diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index e146e64..55de788 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -5,6 +5,9 @@ # SPDX-License-Identifier: GPL-2.0+ # +obj-y += bios.o +obj-y += bios_asm.o +obj-y += bios_interrupts.o obj-$(CONFIG_CMD_BOOTM) += bootm.o obj-y += cmd_boot.o obj-y += gcc.o diff --git a/arch/x86/lib/bios.c b/arch/x86/lib/bios.c new file mode 100644 index 0000000..298fca6 --- /dev/null +++ b/arch/x86/lib/bios.c @@ -0,0 +1,347 @@ +/* + * From Coreboot file device/oprom/realmode/x86.c + * + * Copyright (C) 2007 Advanced Micro Devices, Inc. + * Copyright (C) 2009-2010 coresystems GmbH + * + * SPDX-License-Identifier: GPL-2.0 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "bios.h" + +/* Interrupt handlers for each interrupt the ROM can call */ +static int (*int_handler[256])(void); + +/* to have a common register file for interrupt handlers */ +X86EMU_sysEnv _X86EMU_env; + +asmlinkage void (*realmode_call)(u32 addr, u32 eax, u32 ebx, u32 ecx, u32 edx, + u32 esi, u32 edi); + +asmlinkage void (*realmode_interrupt)(u32 intno, u32 eax, u32 ebx, u32 ecx, + u32 edx, u32 esi, u32 edi); + +static void setup_realmode_code(void) +{ + memcpy((void *)REALMODE_BASE, &asm_realmode_code, + asm_realmode_code_size); + + /* Ensure the global pointers are relocated properly. */ + realmode_call = PTR_TO_REAL_MODE(asm_realmode_call); + realmode_interrupt = PTR_TO_REAL_MODE(__realmode_interrupt); + + debug("Real mode stub @%x: %d bytes\n", REALMODE_BASE, + asm_realmode_code_size); +} + +static void setup_rombios(void) +{ + const char date[] = "06/11/99"; + memcpy((void *)0xffff5, &date, 8); + + const char ident[] = "PCI_ISA"; + memcpy((void *)0xfffd9, &ident, 7); + + /* system model: IBM-AT */ + writeb(0xfc, 0xffffe); +} + +static int int_exception_handler(void) +{ + /* compatibility shim */ + struct eregs reg_info = { + .eax = M.x86.R_EAX, + .ecx = M.x86.R_ECX, + .edx = M.x86.R_EDX, + .ebx = M.x86.R_EBX, + .esp = M.x86.R_ESP, + .ebp = M.x86.R_EBP, + .esi = M.x86.R_ESI, + .edi = M.x86.R_EDI, + .vector = M.x86.intno, + .error_code = 0, + .eip = M.x86.R_EIP, + .cs = M.x86.R_CS, + .eflags = M.x86.R_EFLG + }; + struct eregs *regs = ®_info; + + debug("Oops, exception %d while executing option rom\n", regs->vector); + cpu_hlt(); + + return 0; +} + +static int int_unknown_handler(void) +{ + debug("Unsupported software interrupt #0x%x eax 0x%x\n", + M.x86.intno, M.x86.R_EAX); + + return -1; +} + +/* setup interrupt handlers for mainboard */ +void bios_set_interrupt_handler(int intnum, int (*int_func)(void)) +{ + int_handler[intnum] = int_func; +} + +static void setup_interrupt_handlers(void) +{ + int i; + + /* + * The first 16 int_handler functions are not BIOS services, + * but the CPU-generated exceptions ("hardware interrupts") + */ + for (i = 0; i < 0x10; i++) + int_handler[i] = &int_exception_handler; + + /* Mark all other int_handler calls as unknown first */ + for (i = 0x10; i < 0x100; i++) { + /* Skip if bios_set_interrupt_handler() isn't called first */ + if (int_handler[i]) + continue; + + /* + * Now set the default functions that are actually needed + * to initialize the option roms. The board may override + * these with bios_set_interrupt_handler() + */ + switch (i) { + case 0x10: + int_handler[0x10] = &int10_handler; + break; + case 0x12: + int_handler[0x12] = &int12_handler; + break; + case 0x16: + int_handler[0x16] = &int16_handler; + break; + case 0x1a: + int_handler[0x1a] = &int1a_handler; + break; + default: + int_handler[i] = &int_unknown_handler; + break; + } + } +} + +static void write_idt_stub(void *target, u8 intnum) +{ + unsigned char *codeptr; + + codeptr = (unsigned char *)target; + memcpy(codeptr, &__idt_handler, __idt_handler_size); + codeptr[3] = intnum; /* modify int# in the code stub. */ +} + +static void setup_realmode_idt(void) +{ + struct realmode_idt *idts = NULL; + int i; + + /* + * Copy IDT stub code for each interrupt. This might seem wasteful + * but it is really simple + */ + for (i = 0; i < 256; i++) { + idts[i].cs = 0; + idts[i].offset = 0x1000 + (i * __idt_handler_size); + write_idt_stub((void *)((u32)idts[i].offset), i); + } + + /* + * Many option ROMs use the hard coded interrupt entry points in the + * system bios. So install them at the known locations. + */ + + /* int42 is the relocated int10 */ + write_idt_stub((void *)0xff065, 0x42); + /* BIOS Int 11 Handler F000:F84D */ + write_idt_stub((void *)0xff84d, 0x11); + /* BIOS Int 12 Handler F000:F841 */ + write_idt_stub((void *)0xff841, 0x12); + /* BIOS Int 13 Handler F000:EC59 */ + write_idt_stub((void *)0xfec59, 0x13); + /* BIOS Int 14 Handler F000:E739 */ + write_idt_stub((void *)0xfe739, 0x14); + /* BIOS Int 15 Handler F000:F859 */ + write_idt_stub((void *)0xff859, 0x15); + /* BIOS Int 16 Handler F000:E82E */ + write_idt_stub((void *)0xfe82e, 0x16); + /* BIOS Int 17 Handler F000:EFD2 */ + write_idt_stub((void *)0xfefd2, 0x17); + /* ROM BIOS Int 1A Handler F000:FE6E */ + write_idt_stub((void *)0xffe6e, 0x1a); +} + +static u8 vbe_get_mode_info(struct vbe_mode_info *mi) +{ + u16 buffer_seg; + u16 buffer_adr; + char *buffer; + + debug("VBE: Getting information about VESA mode %04x\n", + mi->video_mode); + buffer = PTR_TO_REAL_MODE(asm_realmode_buffer); + buffer_seg = (((unsigned long)buffer) >> 4) & 0xff00; + buffer_adr = ((unsigned long)buffer) & 0xffff; + + realmode_interrupt(0x10, VESA_GET_MODE_INFO, 0x0000, mi->video_mode, + 0x0000, buffer_seg, buffer_adr); + memcpy(mi->mode_info_block, buffer, sizeof(struct vbe_mode_info)); + mi->valid = true; + + return 0; +} + +static u8 vbe_set_mode(struct vbe_mode_info *mi) +{ + debug("VBE: Setting VESA mode %#04x\n", mi->video_mode); + /* request linear framebuffer mode */ + mi->video_mode |= (1 << 14); + /* request clearing of framebuffer */ + mi->video_mode &= ~(1 << 15); + realmode_interrupt(0x10, VESA_SET_MODE, mi->video_mode, + 0x0000, 0x0000, 0x0000, 0x0000); + + return 0; +} + +static void vbe_set_graphics(int vesa_mode, struct vbe_mode_info *mode_info) +{ + unsigned char *framebuffer; + + mode_info->video_mode = (1 << 14) | vesa_mode; + vbe_get_mode_info(mode_info); + + framebuffer = (unsigned char *)mode_info->vesa.phys_base_ptr; + debug("VBE: resolution: %dx%d@%d\n", + le16_to_cpu(mode_info->vesa.x_resolution), + le16_to_cpu(mode_info->vesa.y_resolution), + mode_info->vesa.bits_per_pixel); + debug("VBE: framebuffer: %p\n", framebuffer); + if (!framebuffer) { + debug("VBE: Mode does not support linear framebuffer\n"); + return; + } + + vbe_set_mode(mode_info); +} + +void bios_run_on_x86(pci_dev_t pcidev, unsigned long addr, int vesa_mode, + struct vbe_mode_info *mode_info) +{ + u32 num_dev; + + num_dev = PCI_BUS(pcidev) << 8 | PCI_DEV(pcidev) << 3 | + PCI_FUNC(pcidev); + + /* Needed to avoid exceptions in some ROMs */ + interrupt_init(); + + /* Set up some legacy information in the F segment */ + setup_rombios(); + + /* Set up C interrupt handlers */ + setup_interrupt_handlers(); + + /* Set up real-mode IDT */ + setup_realmode_idt(); + + /* Make sure the code is placed. */ + setup_realmode_code(); + + disable_caches(); + debug("Calling Option ROM at %lx, pci device %#x...", addr, num_dev); + + /* Option ROM entry point is at OPROM start + 3 */ + realmode_call(addr + 0x0003, num_dev, 0xffff, 0x0000, 0xffff, 0x0, + 0x0); + debug("done\n"); + + if (vesa_mode != -1) + vbe_set_graphics(vesa_mode, mode_info); +} + +asmlinkage int interrupt_handler(u32 intnumber, u32 gsfs, u32 dses, + u32 edi, u32 esi, u32 ebp, u32 esp, + u32 ebx, u32 edx, u32 ecx, u32 eax, + u32 cs_ip, u16 stackflags) +{ + u32 ip; + u32 cs; + u32 flags; + int ret = 0; + + ip = cs_ip & 0xffff; + cs = cs_ip >> 16; + flags = stackflags; + +#ifdef CONFIG_REALMODE_DEBUG + debug("oprom: INT# 0x%x\n", intnumber); + debug("oprom: eax: %08x ebx: %08x ecx: %08x edx: %08x\n", + eax, ebx, ecx, edx); + debug("oprom: ebp: %08x esp: %08x edi: %08x esi: %08x\n", + ebp, esp, edi, esi); + debug("oprom: ip: %04x cs: %04x flags: %08x\n", + ip, cs, flags); + debug("oprom: stackflags = %04x\n", stackflags); +#endif + + /* + * Fetch arguments from the stack and put them to a place + * suitable for the interrupt handlers + */ + M.x86.R_EAX = eax; + M.x86.R_ECX = ecx; + M.x86.R_EDX = edx; + M.x86.R_EBX = ebx; + M.x86.R_ESP = esp; + M.x86.R_EBP = ebp; + M.x86.R_ESI = esi; + M.x86.R_EDI = edi; + M.x86.intno = intnumber; + M.x86.R_EIP = ip; + M.x86.R_CS = cs; + M.x86.R_EFLG = flags; + + /* Call the interrupt handler for this interrupt number */ + ret = int_handler[intnumber](); + + /* + * This code is quite strange... + * + * Put registers back on the stack. The assembler code will pop them + * later. We force (volatile!) changing the values of the parameters + * of this function. We know that they stay alive on the stack after + * we leave this function. + */ + *(volatile u32 *)&eax = M.x86.R_EAX; + *(volatile u32 *)&ecx = M.x86.R_ECX; + *(volatile u32 *)&edx = M.x86.R_EDX; + *(volatile u32 *)&ebx = M.x86.R_EBX; + *(volatile u32 *)&esi = M.x86.R_ESI; + *(volatile u32 *)&edi = M.x86.R_EDI; + flags = M.x86.R_EFLG; + + /* Pass success or error back to our caller via the CARRY flag */ + if (ret) { + flags &= ~1; /* no error: clear carry */ + } else { + debug("int%02x call returned error\n", intnumber); + flags |= 1; /* error: set carry */ + } + *(volatile u16 *)&stackflags = flags; + + return ret; +} diff --git a/arch/x86/lib/bios.h b/arch/x86/lib/bios.h new file mode 100644 index 0000000..8491b4a --- /dev/null +++ b/arch/x86/lib/bios.h @@ -0,0 +1,98 @@ +/* + * From Coreboot file device/oprom/realmode/x86.h + * + * Copyright (C) 2007 Advanced Micro Devices, Inc. + * Copyright (C) 2009-2010 coresystems GmbH + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _X86_LIB_BIOS_H +#define _X86_LIB_BIOS_H + +#define REALMODE_BASE 0x600 + +#ifdef __ASSEMBLY__ + +#define PTR_TO_REAL_MODE(x) (x - asm_realmode_code + REALMODE_BASE) + +#else + +/* Convert a symbol address to our real mode area */ +#define PTR_TO_REAL_MODE(sym)\ + (void *)(REALMODE_BASE + ((char *)&(sym) - (char *)&asm_realmode_code)) + +/* + * The following symbols cannot be used directly. They need to be fixed up + * to point to the correct address location after the code has been copied + * to REALMODE_BASE. Absolute symbols are not used because those symbols are + * relocated by U-Boot. + */ +extern unsigned char asm_realmode_call, __realmode_interrupt; +extern unsigned char asm_realmode_buffer; + +#define DOWNTO8(A) \ + union { \ + struct { \ + union { \ + struct { \ + uint8_t A##l; \ + uint8_t A##h; \ + } __packed; \ + uint16_t A##x; \ + } __packed; \ + uint16_t h##A##x; \ + } __packed; \ + uint32_t e##A##x; \ + } __packed; + +#define DOWNTO16(A) \ + union { \ + struct { \ + uint16_t A; \ + uint16_t h##A; \ + } __packed; \ + uint32_t e##A; \ + } __packed; + +struct eregs { + DOWNTO8(a); + DOWNTO8(c); + DOWNTO8(d); + DOWNTO8(b); + DOWNTO16(sp); + DOWNTO16(bp); + DOWNTO16(si); + DOWNTO16(di); + uint32_t vector; + uint32_t error_code; + uint32_t eip; + uint32_t cs; + uint32_t eflags; +}; + +struct realmode_idt { + u16 offset, cs; +}; + +void x86_exception(struct eregs *info); + +/* From x86_asm.S */ +extern unsigned char __idt_handler; +extern unsigned int __idt_handler_size; +extern unsigned char asm_realmode_code; +extern unsigned int asm_realmode_code_size; + +asmlinkage void (*realmode_call)(u32 addr, u32 eax, u32 ebx, u32 ecx, u32 edx, + u32 esi, u32 edi); + +asmlinkage void (*realmode_interrupt)(u32 intno, u32 eax, u32 ebx, u32 ecx, + u32 edx, u32 esi, u32 edi); + +int int10_handler(void); +int int12_handler(void); +int int16_handler(void); +int int1a_handler(void); +#endif /*__ASSEMBLY__ */ + +#endif diff --git a/arch/x86/lib/bios_asm.S b/arch/x86/lib/bios_asm.S new file mode 100644 index 0000000..4faa70e --- /dev/null +++ b/arch/x86/lib/bios_asm.S @@ -0,0 +1,281 @@ +/* + * From coreboot x86_asm.S, cleaned up substantially + * + * Copyright (C) 2009-2010 coresystems GmbH + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include "bios.h" + +#define SEG(segment) $segment * X86_GDT_ENTRY_SIZE + +/* + * This is the interrupt handler stub code. It gets copied to the IDT and + * to some fixed addresses in the F segment. Before the code can used, + * it gets patched up by the C function copying it: byte 3 (the $0 in + * movb $0, %al) is overwritten with the interrupt numbers. + */ + + .code16 + .globl __idt_handler +__idt_handler: + pushal + movb $0, %al /* This instruction gets modified */ + ljmp $0, $__interrupt_handler_16bit + .globl __idt_handler_size +__idt_handler_size: + .long . - __idt_handler + +.macro setup_registers + /* initial register values */ + movl 44(%ebp), %eax + movl %eax, __registers + 0 /* eax */ + movl 48(%ebp), %eax + movl %eax, __registers + 4 /* ebx */ + movl 52(%ebp), %eax + movl %eax, __registers + 8 /* ecx */ + movl 56(%ebp), %eax + movl %eax, __registers + 12 /* edx */ + movl 60(%ebp), %eax + movl %eax, __registers + 16 /* esi */ + movl 64(%ebp), %eax + movl %eax, __registers + 20 /* edi */ +.endm + +.macro enter_real_mode + /* Activate the right segment descriptor real mode. */ + ljmp SEG(X86_GDT_ENTRY_16BIT_CS), $PTR_TO_REAL_MODE(1f) +1: +.code16 + /* + * Load the segment registers with properly configured segment + * descriptors. They will retain these configurations (limits, + * writability, etc.) once protected mode is turned off. + */ + mov SEG(X86_GDT_ENTRY_16BIT_DS), %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + /* Turn off protection */ + movl %cr0, %eax + andl $~X86_CR0_PE, %eax + movl %eax, %cr0 + + /* Now really going into real mode */ + ljmp $0, $PTR_TO_REAL_MODE(1f) +1: + /* + * Set up a stack: Put the stack at the end of page zero. That way + * we can easily share it between real and protected, since the + * 16-bit ESP at segment 0 will work for any case. + */ + mov $0x0, %ax + mov %ax, %ss + + /* Load 16 bit IDT */ + xor %ax, %ax + mov %ax, %ds + lidt __realmode_idt + +.endm + +.macro prepare_for_irom + movl $0x1000, %eax + movl %eax, %esp + + /* Initialise registers for option rom lcall */ + movl __registers + 0, %eax + movl __registers + 4, %ebx + movl __registers + 8, %ecx + movl __registers + 12, %edx + movl __registers + 16, %esi + movl __registers + 20, %edi + + /* Set all segments to 0x0000, ds to 0x0040 */ + push %ax + xor %ax, %ax + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov SEG(X86_GDT_ENTRY_16BIT_FLAT_DS), %ax + mov %ax, %ds + pop %ax + +.endm + +.macro enter_protected_mode + /* Go back to protected mode */ + movl %cr0, %eax + orl $X86_CR0_PE, %eax + movl %eax, %cr0 + + /* Now that we are in protected mode jump to a 32 bit code segment */ + data32 ljmp SEG(X86_GDT_ENTRY_32BIT_CS), $PTR_TO_REAL_MODE(1f) +1: + .code32 + mov SEG(X86_GDT_ENTRY_32BIT_DS), %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %gs + mov %ax, %ss + mov SEG(X86_GDT_ENTRY_32BIT_FS), %ax + mov %ax, %fs + + /* restore proper idt */ + lidt idt_ptr +.endm + +/* + * In order to be independent of U-Boot's position in RAM we relocate a part + * of the code to the first megabyte of RAM, so the CPU can use it in + * real-mode. This code lives at asm_realmode_code. + */ + .globl asm_realmode_code +asm_realmode_code: + +/* Realmode IDT pointer structure. */ +__realmode_idt = PTR_TO_REAL_MODE(.) + .word 1023 /* 16 bit limit */ + .long 0 /* 24 bit base */ + .word 0 + +/* Preserve old stack */ +__stack = PTR_TO_REAL_MODE(.) + .long 0 + +/* Register store for realmode_call and realmode_interrupt */ +__registers = PTR_TO_REAL_MODE(.) + .long 0 /* 0 - EAX */ + .long 0 /* 4 - EBX */ + .long 0 /* 8 - ECX */ + .long 0 /* 12 - EDX */ + .long 0 /* 16 - ESI */ + .long 0 /* 20 - EDI */ + +/* 256 byte buffer, used by int10 */ + .globl asm_realmode_buffer +asm_realmode_buffer: + .skip 256 + + .code32 + .globl asm_realmode_call +asm_realmode_call: + /* save all registers to the stack */ + pusha + pushf + movl %esp, __stack + movl %esp, %ebp + + /* + * This function is called with regparm=0 and we have to skip the + * 36 bytes from pushf+pusha. Hence start at 40. + * Set up our call instruction. + */ + movl 40(%ebp), %eax + mov %ax, __lcall_instr + 1 + andl $0xffff0000, %eax + shrl $4, %eax + mov %ax, __lcall_instr + 3 + + wbinvd + + setup_registers + enter_real_mode + prepare_for_irom + +__lcall_instr = PTR_TO_REAL_MODE(.) + .byte 0x9a + .word 0x0000, 0x0000 + + enter_protected_mode + + /* restore stack pointer, eflags and register values and exit */ + movl __stack, %esp + popf + popa + ret + + .globl __realmode_interrupt +__realmode_interrupt: + /* save all registers to the stack and store the stack pointer */ + pusha + pushf + movl %esp, __stack + movl %esp, %ebp + + /* + * This function is called with regparm=0 and we have to skip the + * 36 bytes from pushf+pusha. Hence start at 40. + * Prepare interrupt calling code. + */ + movl 40(%ebp), %eax + movb %al, __intXX_instr + 1 /* intno */ + + setup_registers + enter_real_mode + prepare_for_irom + +__intXX_instr = PTR_TO_REAL_MODE(.) + .byte 0xcd, 0x00 /* This becomes intXX */ + + enter_protected_mode + + /* restore stack pointer, eflags and register values and exit */ + movl __stack, %esp + popf + popa + ret + +/* + * This is the 16-bit interrupt entry point called by the IDT stub code. + * + * Before this code code is called, %eax is pushed to the stack, and the + * interrupt number is loaded into %al. On return this function cleans up + * for its caller. + */ + .code16 +__interrupt_handler_16bit = PTR_TO_REAL_MODE(.) + push %ds + push %es + push %fs + push %gs + + /* Clear DF to not break ABI assumptions */ + cld + + /* + * Clean up the interrupt number. We could do this in the stub, but + * it would cost two more bytes per stub entry. + */ + andl $0xff, %eax + pushl %eax /* ... and make it the first parameter */ + + enter_protected_mode + + /* Call the C interrupt handler */ + movl $interrupt_handler, %eax + call *%eax + + enter_real_mode + + /* + * Restore all registers, including those manipulated by the C + * handler + */ + popl %eax + pop %gs + pop %fs + pop %es + pop %ds + popal + iret + + .globl asm_realmode_code_size +asm_realmode_code_size: + .long . - asm_realmode_code diff --git a/arch/x86/lib/bios_interrupts.c b/arch/x86/lib/bios_interrupts.c new file mode 100644 index 0000000..b0e2ecb --- /dev/null +++ b/arch/x86/lib/bios_interrupts.c @@ -0,0 +1,217 @@ +/* + * From Coreboot + * + * Copyright (C) 2001 Ronald G. Minnich + * Copyright (C) 2005 Nick.Barker9@btinternet.com + * Copyright (C) 2007-2009 coresystems GmbH + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include "bios_emul.h" + +/* errors go in AH. Just set these up so that word assigns will work */ +enum { + PCIBIOS_SUCCESSFUL = 0x0000, + PCIBIOS_UNSUPPORTED = 0x8100, + PCIBIOS_BADVENDOR = 0x8300, + PCIBIOS_NODEV = 0x8600, + PCIBIOS_BADREG = 0x8700 +}; + +int int10_handler(void) +{ + static u8 cursor_row, cursor_col; + int res = 0; + + switch ((M.x86.R_EAX & 0xff00) >> 8) { + case 0x01: /* Set cursor shape */ + res = 1; + break; + case 0x02: /* Set cursor position */ + if (cursor_row != ((M.x86.R_EDX >> 8) & 0xff) || + cursor_col >= (M.x86.R_EDX & 0xff)) { + debug("\n"); + } + cursor_row = (M.x86.R_EDX >> 8) & 0xff; + cursor_col = M.x86.R_EDX & 0xff; + res = 1; + break; + case 0x03: /* Get cursor position */ + M.x86.R_EAX &= 0x00ff; + M.x86.R_ECX = 0x0607; + M.x86.R_EDX = (cursor_row << 8) | cursor_col; + res = 1; + break; + case 0x06: /* Scroll up */ + debug("\n"); + res = 1; + break; + case 0x08: /* Get Character and Mode at Cursor Position */ + M.x86.R_EAX = 0x0f00 | 'A'; /* White on black 'A' */ + res = 1; + break; + case 0x09: /* Write Character and attribute */ + case 0x0e: /* Write Character */ + debug("%c", M.x86.R_EAX & 0xff); + res = 1; + break; + case 0x0f: /* Get video mode */ + M.x86.R_EAX = 0x5002; /*80 x 25 */ + M.x86.R_EBX &= 0x00ff; + res = 1; + break; + default: + printf("Unknown INT10 function %04x\n", M.x86.R_EAX & 0xffff); + break; + } + return res; +} + +int int12_handler(void) +{ + M.x86.R_EAX = 64 * 1024; + return 1; +} + +int int16_handler(void) +{ + int res = 0; + + switch ((M.x86.R_EAX & 0xff00) >> 8) { + case 0x00: /* Check for Keystroke */ + M.x86.R_EAX = 0x6120; /* Space Bar, Space */ + res = 1; + break; + case 0x01: /* Check for Keystroke */ + M.x86.R_EFLG |= 1 << 6; /* Zero Flag set (no key available) */ + res = 1; + break; + default: + printf("Unknown INT16 function %04x\n", M.x86.R_EAX & 0xffff); + +break; + } + return res; +} + +#define PCI_CONFIG_SPACE_TYPE1 (1 << 0) +#define PCI_SPECIAL_CYCLE_TYPE1 (1 << 4) + +int int1a_handler(void) +{ + unsigned short func = (unsigned short)M.x86.R_EAX; + int retval = 1; + unsigned short devid, vendorid, devfn; + /* Use short to get rid of gabage in upper half of 32-bit register */ + short devindex; + unsigned char bus; + pci_dev_t dev; + u32 dword; + u16 word; + u8 byte, reg; + + switch (func) { + case 0xb101: /* PCIBIOS Check */ + M.x86.R_EDX = 0x20494350; /* ' ICP' */ + M.x86.R_EAX &= 0xffff0000; /* Clear AH / AL */ + M.x86.R_EAX |= PCI_CONFIG_SPACE_TYPE1 | + PCI_SPECIAL_CYCLE_TYPE1; + /* + * last bus in the system. Hard code to 255 for now. + * dev_enumerate() does not seem to tell us (publically) + */ + M.x86.R_ECX = 0xff; + M.x86.R_EDI = 0x00000000; /* protected mode entry */ + retval = 1; + break; + case 0xb102: /* Find Device */ + devid = M.x86.R_ECX; + vendorid = M.x86.R_EDX; + devindex = M.x86.R_ESI; + dev = pci_find_device(vendorid, devid, devindex); + if (dev != -1) { + unsigned short busdevfn; + M.x86.R_EAX &= 0xffff00ff; /* Clear AH */ + M.x86.R_EAX |= PCIBIOS_SUCCESSFUL; + /* + * busnum is an unsigned char; + * devfn is an int, so we mask it off. + */ + busdevfn = (PCI_BUS(dev) << 8) | PCI_DEV(dev) << 3 | + PCI_FUNC(dev); + debug("0x%x: return 0x%x\n", func, busdevfn); + M.x86.R_EBX = busdevfn; + retval = 1; + } else { + M.x86.R_EAX &= 0xffff00ff; /* Clear AH */ + M.x86.R_EAX |= PCIBIOS_NODEV; + retval = 0; + } + break; + case 0xb10a: /* Read Config Dword */ + case 0xb109: /* Read Config Word */ + case 0xb108: /* Read Config Byte */ + case 0xb10d: /* Write Config Dword */ + case 0xb10c: /* Write Config Word */ + case 0xb10b: /* Write Config Byte */ + devfn = M.x86.R_EBX & 0xff; + bus = M.x86.R_EBX >> 8; + reg = M.x86.R_EDI; + dev = PCI_BDF(bus, devfn >> 3, devfn & 7); + if (!dev) { + debug("0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, + bus, devfn); + /* Or are we supposed to return PCIBIOS_NODEV? */ + M.x86.R_EAX &= 0xffff00ff; /* Clear AH */ + M.x86.R_EAX |= PCIBIOS_BADREG; + retval = 0; + return retval; + } + switch (func) { + case 0xb108: /* Read Config Byte */ + byte = pci_read_config8(dev, reg); + M.x86.R_ECX = byte; + break; + case 0xb109: /* Read Config Word */ + word = pci_read_config16(dev, reg); + M.x86.R_ECX = word; + break; + case 0xb10a: /* Read Config Dword */ + dword = pci_read_config32(dev, reg); + M.x86.R_ECX = dword; + break; + case 0xb10b: /* Write Config Byte */ + byte = M.x86.R_ECX; + pci_write_config8(dev, reg, byte); + break; + case 0xb10c: /* Write Config Word */ + word = M.x86.R_ECX; + pci_write_config16(dev, reg, word); + break; + case 0xb10d: /* Write Config Dword */ + dword = M.x86.R_ECX; + pci_write_config32(dev, reg, dword); + break; + } + +#ifdef CONFIG_REALMODE_DEBUG + debug("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n", func, + bus, devfn, reg, M.x86.R_ECX); +#endif + M.x86.R_EAX &= 0xffff00ff; /* Clear AH */ + M.x86.R_EAX |= PCIBIOS_SUCCESSFUL; + retval = 1; + break; + default: + printf("UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func); + M.x86.R_EAX &= 0xffff00ff; /* Clear AH */ + M.x86.R_EAX |= PCIBIOS_UNSUPPORTED; + retval = 0; + break; + } + + return retval; +} -- cgit v0.10.2 From 6854f87cbcad544dc07a02b96d358f81ca60c593 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:33 -0700 Subject: pci: Add general support for execution of video ROMs Some platforms don't have native code for dealing with their video hardware. In some cases they use a binary blob to set it up and perform required actions like setting the video mode. This approach is a hangover from the old PC days where a ROM was provided and executed during startup. Even now, these ROMs are supplied as a way to set up video. It avoids the code for every video chip needing to be provided in the boot loader. But it makes the video much less flexible - e.g. it is not possible to do anything else while the video init is happening (including waiting hundreds of milliseconds for display panels to start up). In any case, to deal with this sad state of affairs, provide an API for execution of x86 video ROMs, either natively or through emulation. Signed-off-by: Simon Glass diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index e73a498..55d6a9b 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -6,7 +6,7 @@ # obj-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o -obj-$(CONFIG_PCI) += pci.o pci_auto.o +obj-$(CONFIG_PCI) += pci.o pci_auto.o pci_rom.o obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o obj-$(CONFIG_PCI_MSC01) += pci_msc01.o diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c new file mode 100644 index 0000000..af6a3ae --- /dev/null +++ b/drivers/pci/pci_rom.c @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2014 Google, Inc + * + * From coreboot, originally based on the Linux kernel (drivers/pci/pci.c). + * + * Modifications are: + * Copyright (C) 2003-2004 Linux Networx + * (Written by Eric Biederman for Linux Networx) + * Copyright (C) 2003-2006 Ronald G. Minnich + * Copyright (C) 2004-2005 Li-Ta Lo + * Copyright (C) 2005-2006 Tyan + * (Written by Yinghai Lu for Tyan) + * Copyright (C) 2005-2009 coresystems GmbH + * (Written by Stefan Reinauer for coresystems GmbH) + * + * PCI Bus Services, see include/linux/pci.h for further explanation. + * + * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter, + * David Mosberger-Tang + * + * Copyright 1997 -- 1999 Martin Mares + + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_HAVE_ACPI_RESUME +#include +#endif + +__weak bool board_should_run_oprom(pci_dev_t dev) +{ + return true; +} + +static bool should_load_oprom(pci_dev_t dev) +{ +#ifdef CONFIG_HAVE_ACPI_RESUME + if (acpi_get_slp_type() == 3) + return false; +#endif + if (IS_ENABLED(CONFIG_ALWAYS_LOAD_OPROM)) + return 1; + if (board_should_run_oprom(dev)) + return 1; + + return 0; +} + +__weak uint32_t board_map_oprom_vendev(uint32_t vendev) +{ + return vendev; +} + +static int pci_rom_probe(pci_dev_t dev, uint class, + struct pci_rom_header **hdrp) +{ + struct pci_rom_header *rom_header; + struct pci_rom_data *rom_data; + u16 vendor, device; + u32 vendev; + u32 mapped_vendev; + u32 rom_address; + + pci_read_config_word(dev, PCI_VENDOR_ID, &vendor); + pci_read_config_word(dev, PCI_DEVICE_ID, &device); + vendev = vendor << 16 | device; + mapped_vendev = board_map_oprom_vendev(vendev); + if (vendev != mapped_vendev) + debug("Device ID mapped to %#08x\n", mapped_vendev); + +#ifdef CONFIG_X86_OPTION_ROM_ADDR + rom_address = CONFIG_X86_OPTION_ROM_ADDR; +#else + pci_write_config_dword(dev, PCI_ROM_ADDRESS, (u32)PCI_ROM_ADDRESS_MASK); + pci_read_config_dword(dev, PCI_ROM_ADDRESS, &rom_address); + if (rom_address == 0x00000000 || rom_address == 0xffffffff) { + debug("%s: rom_address=%x\n", __func__, rom_address); + return -ENOENT; + } + + /* Enable expansion ROM address decoding. */ + pci_write_config_dword(dev, PCI_ROM_ADDRESS, + rom_address | PCI_ROM_ADDRESS_ENABLE); +#endif + debug("Option ROM address %x\n", rom_address); + rom_header = (struct pci_rom_header *)rom_address; + + debug("PCI expansion ROM, signature %#04x, INIT size %#04x, data ptr %#04x\n", + le32_to_cpu(rom_header->signature), + rom_header->size * 512, le32_to_cpu(rom_header->data)); + + if (le32_to_cpu(rom_header->signature) != PCI_ROM_HDR) { + printf("Incorrect expansion ROM header signature %04x\n", + le32_to_cpu(rom_header->signature)); + return -EINVAL; + } + + rom_data = (((void *)rom_header) + le32_to_cpu(rom_header->data)); + + debug("PCI ROM image, vendor ID %04x, device ID %04x,\n", + rom_data->vendor, rom_data->device); + + /* If the device id is mapped, a mismatch is expected */ + if ((vendor != rom_data->vendor || device != rom_data->device) && + (vendev == mapped_vendev)) { + printf("ID mismatch: vendor ID %04x, device ID %04x\n", + rom_data->vendor, rom_data->device); + return -EPERM; + } + + debug("PCI ROM image, Class Code %04x%02x, Code Type %02x\n", + rom_data->class_hi, rom_data->class_lo, rom_data->type); + + if (class != ((rom_data->class_hi << 8) | rom_data->class_lo)) { + debug("Class Code mismatch ROM %08x, dev %08x\n", + (rom_data->class_hi << 8) | rom_data->class_lo, + class); + } + *hdrp = rom_header; + + return 0; +} + +int pci_rom_load(uint16_t class, struct pci_rom_header *rom_header, + struct pci_rom_header **ram_headerp) +{ + struct pci_rom_data *rom_data; + unsigned int rom_size; + unsigned int image_size = 0; + void *target; + + do { + /* Get next image, until we see an x86 version */ + rom_header = (struct pci_rom_header *)((void *)rom_header + + image_size); + + rom_data = (struct pci_rom_data *)((void *)rom_header + + le32_to_cpu(rom_header->data)); + + image_size = le32_to_cpu(rom_data->ilen) * 512; + } while ((rom_data->type != 0) && (rom_data->indicator != 0)); + + if (rom_data->type != 0) + return -EACCES; + + rom_size = rom_header->size * 512; + + target = (void *)PCI_VGA_RAM_IMAGE_START; + if (target != rom_header) { + debug("Copying VGA ROM Image from %p to %p, 0x%x bytes\n", + rom_header, target, rom_size); + memcpy(target, rom_header, rom_size); + if (memcmp(target, rom_header, rom_size)) { + printf("VGA ROM copy failed\n"); + return -EFAULT; + } + } + *ram_headerp = target; + + return 0; +} + +static struct vbe_mode_info mode_info; + +int vbe_get_video_info(struct graphic_device *gdev) +{ +#ifdef CONFIG_FRAMEBUFFER_SET_VESA_MODE + struct vesa_mode_info *vesa = &mode_info.vesa; + + gdev->winSizeX = vesa->x_resolution; + gdev->winSizeY = vesa->y_resolution; + + gdev->plnSizeX = vesa->x_resolution; + gdev->plnSizeY = vesa->y_resolution; + + gdev->gdfBytesPP = vesa->bits_per_pixel / 8; + + switch (vesa->bits_per_pixel) { + case 24: + gdev->gdfIndex = GDF_32BIT_X888RGB; + break; + case 16: + gdev->gdfIndex = GDF_16BIT_565RGB; + break; + default: + gdev->gdfIndex = GDF__8BIT_INDEX; + break; + } + + gdev->isaBase = CONFIG_SYS_ISA_IO_BASE_ADDRESS; + gdev->pciBase = vesa->phys_base_ptr; + + gdev->frameAdrs = vesa->phys_base_ptr; + gdev->memSize = vesa->bytes_per_scanline * vesa->y_resolution; + + gdev->vprBase = vesa->phys_base_ptr; + gdev->cprBase = vesa->phys_base_ptr; + + return 0; +#else + return -ENOSYS; +#endif +} + +int pci_run_vga_bios(pci_dev_t dev, int (*int15_handler)(void), bool emulate) +{ + struct pci_rom_header *rom, *ram; + int vesa_mode = -1; + uint16_t class; + int ret; + + /* Only execute VGA ROMs */ + pci_read_config_word(dev, PCI_CLASS_DEVICE, &class); + if ((class ^ PCI_CLASS_DISPLAY_VGA) & 0xff00) { + debug("%s: Class %#x, should be %#x\n", __func__, class, + PCI_CLASS_DISPLAY_VGA); + return -ENODEV; + } + + if (!should_load_oprom(dev)) + return -ENXIO; + + ret = pci_rom_probe(dev, class, &rom); + if (ret) + return ret; + + ret = pci_rom_load(class, rom, &ram); + if (ret) + return ret; + + if (!board_should_run_oprom(dev)) + return -ENXIO; + +#if defined(CONFIG_FRAMEBUFFER_SET_VESA_MODE) && \ + defined(CONFIG_FRAMEBUFFER_VESA_MODE) + vesa_mode = CONFIG_FRAMEBUFFER_VESA_MODE; +#endif + debug("Selected vesa mode %d\b", vesa_mode); + if (emulate) { +#ifdef CONFIG_BIOSEMU + BE_VGAInfo *info; + + ret = biosemu_setup(dev, &info); + if (ret) + return ret; + biosemu_set_interrupt_handler(0x15, int15_handler); + ret = biosemu_run(dev, (uchar *)ram, 1 << 16, info, true, + vesa_mode, &mode_info); + if (ret) + return ret; +#else + printf("BIOS emulation not available - see CONFIG_BIOSEMU\n"); + return -ENOSYS; +#endif + } else { +#ifdef CONFIG_X86 + bios_set_interrupt_handler(0x15, int15_handler); + + bios_run_on_x86(dev, (unsigned long)ram, vesa_mode, + &mode_info); +#else + printf("BIOS native execution is only available on x86\n"); + return -ENOSYS; +#endif + } + debug("Final vesa mode %d\n", mode_info.video_mode); + + return 0; +} diff --git a/include/bios_emul.h b/include/bios_emul.h index 35d1ff3..f4c4d1d 100644 --- a/include/bios_emul.h +++ b/include/bios_emul.h @@ -9,6 +9,7 @@ /* Include the register header directly here */ #include "../drivers/bios_emulator/include/x86emu/regs.h" +#include /**************************************************************************** REMARKS: @@ -40,4 +41,18 @@ struct vbe_mode_info; int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo **pVGAInfo, int cleanUp); +/* Run a BIOS ROM natively (only supported on x86 machines) */ +void bios_run_on_x86(pci_dev_t pcidev, unsigned long addr, int vesa_mode, + struct vbe_mode_info *mode_info); + +/** + * bios_set_interrupt_handler() - Install an interrupt handler for the BIOS + * + * This installs an interrupt handler that the BIOS will call when needed. + * + * @intnum: Interrupt number to install a handler for + * @int_handler_func: Function to call to handle interrupt + */ +void bios_set_interrupt_handler(int intnum, int (*int_handler_func)(void)); + #endif diff --git a/include/pci_rom.h b/include/pci_rom.h new file mode 100644 index 0000000..8b2674c --- /dev/null +++ b/include/pci_rom.h @@ -0,0 +1,58 @@ +/* + * From coreboot file of same name + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _PCI_ROM_H +#define _PCI_ROM_H + +#define PCI_ROM_HDR 0xaa55 +#define PCI_VGA_RAM_IMAGE_START 0xc0000 + +struct pci_rom_header { + uint16_t signature; + uint8_t size; + uint8_t init[3]; + uint8_t reserved[0x12]; + uint16_t data; +}; + +struct pci_rom_data { + uint32_t signature; + uint16_t vendor; + uint16_t device; + uint16_t reserved_1; + uint16_t dlen; + uint8_t drevision; + uint8_t class_lo; + uint16_t class_hi; + uint16_t ilen; + uint16_t irevision; + uint8_t type; + uint8_t indicator; + uint16_t reserved_2; +}; + + /** + * pci_run_vga_bios() - Run the VGA BIOS in an x86 PC + * + * @dev: Video device containing the BIOS + * @int15_handler: Function to call to handle int 0x15 + * @emulate: true to use the x86 emulator, false to run native + */ +int pci_run_vga_bios(pci_dev_t dev, int (*int15_handler)(void), bool emulate); + +/** + * board_map_oprom_vendev() - map several PCI IDs to the one the ROM expects + * + * Some VGA option roms are used for several chipsets but they only have one + * PCI ID in their header. If we encounter such an option rom, we need to do + * the mapping ourselves. + * + * @vendev: Vendor and device for the video device + * @return standard vendor and device expected by the ROM + */ +uint32_t board_map_oprom_vendev(uint32_t vendev); + +#endif diff --git a/include/video_fb.h b/include/video_fb.h index 6cd4e37..55ec24d 100644 --- a/include/video_fb.h +++ b/include/video_fb.h @@ -40,7 +40,7 @@ /* Export Graphic Driver Control */ /******************************************************************************/ -typedef struct { +typedef struct graphic_device { unsigned int isaBase; unsigned int pciBase; unsigned int dprBase; -- cgit v0.10.2 From 998110241bfc5c7101e20e38948e0a3b68c3ecc9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:34 -0700 Subject: x86: video: Add video driver for bare x86 boards Add a very simple driver which uses vesa to discover the video mode and then provides a frame buffer for use by U-Boot. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 14a6781..000f389 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_VIDEO_SM501) += sm501.o obj-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o obj-$(CONFIG_VIDEO_TEGRA) += tegra.o obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o +obj-$(CONFIG_VIDEO_X86) += x86_fb.o obj-$(CONFIG_FORMIKE) += formike.o obj-$(CONFIG_AM335X_LCD) += am335x-fb.o obj-$(CONFIG_VIDEO_PARADE) += parade.o diff --git a/drivers/video/x86_fb.c b/drivers/video/x86_fb.c new file mode 100644 index 0000000..8743a8c --- /dev/null +++ b/drivers/video/x86_fb.c @@ -0,0 +1,37 @@ +/* + * + * Vesa frame buffer driver for x86 + * + * Copyright (C) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include "videomodes.h" + +/* + * The Graphic Device + */ +GraphicDevice ctfb; + +void *video_hw_init(void) +{ + GraphicDevice *gdev = &ctfb; + int bits_per_pixel; + + printf("Video: "); + if (vbe_get_video_info(gdev)) { + printf("No video mode configured\n"); + return NULL; + } + + bits_per_pixel = gdev->gdfBytesPP * 8; + sprintf(gdev->modeIdent, "%dx%dx%d", gdev->winSizeX, gdev->winSizeY, + bits_per_pixel); + printf("%s\n", gdev->modeIdent); + + return (void *)gdev; +} -- cgit v0.10.2 From d040ac0a89a6ffdcd27bfba24984a339e8a4addc Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:35 -0700 Subject: x86: Allow an option ROM to be built into U-Boot Some x86 machines require a binary blob containing 16-bit initialisation code for their video hardware. Allow this to be built into the x86 ROM so that it is accessible during boot. Signed-off-by: Simon Glass diff --git a/Makefile b/Makefile index 79cb45c..b4ed775 100644 --- a/Makefile +++ b/Makefile @@ -980,6 +980,9 @@ u-boot.rom: u-boot-x86-16bit.bin u-boot-dtb.bin \ $(objtree)/tools/ifdtool -w \ $(CONFIG_SYS_X86_START16):$(objtree)/u-boot-x86-16bit.bin \ u-boot.tmp + $(objtree)/tools/ifdtool -w \ + $(CONFIG_X86_OPTION_ROM_ADDR):$(srctree)/board/$(BOARDDIR)/$(CONFIG_X86_OPTION_ROM_FILENAME) \ + u-boot.tmp mv u-boot.tmp $@ OBJCOPYFLAGS_u-boot-x86-16bit.bin := -O binary -j .start16 -j .resetvec -- cgit v0.10.2 From effcf067df5f986b8f9a2ca5101c74495be700ab Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:36 -0700 Subject: x86: Add initial video device init for Intel GMA Intel's Graphics Media Accelerator (GMA) is a generic name for a wide range of video devices. Add code to set up the hardware on ivybridge. Part of the init happens in native code, part of it happens in a 16-bit option ROM for those nostalgic for the 1970s. Signed-off-by: Simon Glass diff --git a/arch/x86/cpu/ivybridge/Makefile b/arch/x86/cpu/ivybridge/Makefile index 1296a78..0c7efae 100644 --- a/arch/x86/cpu/ivybridge/Makefile +++ b/arch/x86/cpu/ivybridge/Makefile @@ -9,6 +9,7 @@ obj-y += car.o obj-y += cpu.o obj-y += early_init.o obj-y += early_me.o +obj-y += gma.o obj-y += lpc.o obj-y += me_status.o obj-y += model_206ax.o diff --git a/arch/x86/cpu/ivybridge/bd82x6x.c b/arch/x86/cpu/ivybridge/bd82x6x.c index 739f979..65a17d3 100644 --- a/arch/x86/cpu/ivybridge/bd82x6x.c +++ b/arch/x86/cpu/ivybridge/bd82x6x.c @@ -91,7 +91,8 @@ int bd82x6x_init_pci_devices(void) const void *blob = gd->fdt_blob; struct pci_controller *hose; struct x86_cpu_priv *cpu; - int sata_node; + int sata_node, gma_node; + int ret; hose = pci_bus_to_hose(0); lpc_enable(PCH_LPC_DEV); @@ -111,6 +112,16 @@ int bd82x6x_init_pci_devices(void) return -ENOMEM; model_206ax_init(cpu); + gma_node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_GMA); + if (gma_node < 0) { + debug("%s: Cannot find GMA node\n", __func__); + return -EINVAL; + } + ret = gma_func0_init(PCH_VIDEO_DEV, pci_bus_to_hose(0), blob, + gma_node); + if (ret) + return ret; + return 0; } diff --git a/arch/x86/cpu/ivybridge/gma.c b/arch/x86/cpu/ivybridge/gma.c new file mode 100644 index 0000000..3d7f740 --- /dev/null +++ b/arch/x86/cpu/ivybridge/gma.c @@ -0,0 +1,756 @@ +/* + * From Coreboot file of the same name + * + * Copyright (C) 2011 Chromium OS Authors + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct gt_powermeter { + u16 reg; + u32 value; +}; + +static const struct gt_powermeter snb_pm_gt1[] = { + { 0xa200, 0xcc000000 }, + { 0xa204, 0x07000040 }, + { 0xa208, 0x0000fe00 }, + { 0xa20c, 0x00000000 }, + { 0xa210, 0x17000000 }, + { 0xa214, 0x00000021 }, + { 0xa218, 0x0817fe19 }, + { 0xa21c, 0x00000000 }, + { 0xa220, 0x00000000 }, + { 0xa224, 0xcc000000 }, + { 0xa228, 0x07000040 }, + { 0xa22c, 0x0000fe00 }, + { 0xa230, 0x00000000 }, + { 0xa234, 0x17000000 }, + { 0xa238, 0x00000021 }, + { 0xa23c, 0x0817fe19 }, + { 0xa240, 0x00000000 }, + { 0xa244, 0x00000000 }, + { 0xa248, 0x8000421e }, + { 0 } +}; + +static const struct gt_powermeter snb_pm_gt2[] = { + { 0xa200, 0x330000a6 }, + { 0xa204, 0x402d0031 }, + { 0xa208, 0x00165f83 }, + { 0xa20c, 0xf1000000 }, + { 0xa210, 0x00000000 }, + { 0xa214, 0x00160016 }, + { 0xa218, 0x002a002b }, + { 0xa21c, 0x00000000 }, + { 0xa220, 0x00000000 }, + { 0xa224, 0x330000a6 }, + { 0xa228, 0x402d0031 }, + { 0xa22c, 0x00165f83 }, + { 0xa230, 0xf1000000 }, + { 0xa234, 0x00000000 }, + { 0xa238, 0x00160016 }, + { 0xa23c, 0x002a002b }, + { 0xa240, 0x00000000 }, + { 0xa244, 0x00000000 }, + { 0xa248, 0x8000421e }, + { 0 } +}; + +static const struct gt_powermeter ivb_pm_gt1[] = { + { 0xa800, 0x00000000 }, + { 0xa804, 0x00021c00 }, + { 0xa808, 0x00000403 }, + { 0xa80c, 0x02001700 }, + { 0xa810, 0x05000200 }, + { 0xa814, 0x00000000 }, + { 0xa818, 0x00690500 }, + { 0xa81c, 0x0000007f }, + { 0xa820, 0x01002501 }, + { 0xa824, 0x00000300 }, + { 0xa828, 0x01000331 }, + { 0xa82c, 0x0000000c }, + { 0xa830, 0x00010016 }, + { 0xa834, 0x01100101 }, + { 0xa838, 0x00010103 }, + { 0xa83c, 0x00041300 }, + { 0xa840, 0x00000b30 }, + { 0xa844, 0x00000000 }, + { 0xa848, 0x7f000000 }, + { 0xa84c, 0x05000008 }, + { 0xa850, 0x00000001 }, + { 0xa854, 0x00000004 }, + { 0xa858, 0x00000007 }, + { 0xa85c, 0x00000000 }, + { 0xa860, 0x00010000 }, + { 0xa248, 0x0000221e }, + { 0xa900, 0x00000000 }, + { 0xa904, 0x00001c00 }, + { 0xa908, 0x00000000 }, + { 0xa90c, 0x06000000 }, + { 0xa910, 0x09000200 }, + { 0xa914, 0x00000000 }, + { 0xa918, 0x00590000 }, + { 0xa91c, 0x00000000 }, + { 0xa920, 0x04002501 }, + { 0xa924, 0x00000100 }, + { 0xa928, 0x03000410 }, + { 0xa92c, 0x00000000 }, + { 0xa930, 0x00020000 }, + { 0xa934, 0x02070106 }, + { 0xa938, 0x00010100 }, + { 0xa93c, 0x00401c00 }, + { 0xa940, 0x00000000 }, + { 0xa944, 0x00000000 }, + { 0xa948, 0x10000e00 }, + { 0xa94c, 0x02000004 }, + { 0xa950, 0x00000001 }, + { 0xa954, 0x00000004 }, + { 0xa960, 0x00060000 }, + { 0xaa3c, 0x00001c00 }, + { 0xaa54, 0x00000004 }, + { 0xaa60, 0x00060000 }, + { 0 } +}; + +static const struct gt_powermeter ivb_pm_gt2[] = { + { 0xa800, 0x10000000 }, + { 0xa804, 0x00033800 }, + { 0xa808, 0x00000902 }, + { 0xa80c, 0x0c002f00 }, + { 0xa810, 0x12000400 }, + { 0xa814, 0x00000000 }, + { 0xa818, 0x00d20800 }, + { 0xa81c, 0x00000002 }, + { 0xa820, 0x03004b02 }, + { 0xa824, 0x00000600 }, + { 0xa828, 0x07000773 }, + { 0xa82c, 0x00000000 }, + { 0xa830, 0x00010032 }, + { 0xa834, 0x1520040d }, + { 0xa838, 0x00020105 }, + { 0xa83c, 0x00083700 }, + { 0xa840, 0x0000151d }, + { 0xa844, 0x00000000 }, + { 0xa848, 0x20001b00 }, + { 0xa84c, 0x0a000010 }, + { 0xa850, 0x00000000 }, + { 0xa854, 0x00000008 }, + { 0xa858, 0x00000008 }, + { 0xa85c, 0x00000000 }, + { 0xa860, 0x00020000 }, + { 0xa248, 0x0000221e }, + { 0xa900, 0x00000000 }, + { 0xa904, 0x00003500 }, + { 0xa908, 0x00000000 }, + { 0xa90c, 0x0c000000 }, + { 0xa910, 0x12000500 }, + { 0xa914, 0x00000000 }, + { 0xa918, 0x00b20000 }, + { 0xa91c, 0x00000000 }, + { 0xa920, 0x08004b02 }, + { 0xa924, 0x00000200 }, + { 0xa928, 0x07000820 }, + { 0xa92c, 0x00000000 }, + { 0xa930, 0x00030000 }, + { 0xa934, 0x050f020d }, + { 0xa938, 0x00020300 }, + { 0xa93c, 0x00903900 }, + { 0xa940, 0x00000000 }, + { 0xa944, 0x00000000 }, + { 0xa948, 0x20001b00 }, + { 0xa94c, 0x0a000010 }, + { 0xa950, 0x00000000 }, + { 0xa954, 0x00000008 }, + { 0xa960, 0x00110000 }, + { 0xaa3c, 0x00003900 }, + { 0xaa54, 0x00000008 }, + { 0xaa60, 0x00110000 }, + { 0 } +}; + +static const struct gt_powermeter ivb_pm_gt2_17w[] = { + { 0xa800, 0x20000000 }, + { 0xa804, 0x000e3800 }, + { 0xa808, 0x00000806 }, + { 0xa80c, 0x0c002f00 }, + { 0xa810, 0x0c000800 }, + { 0xa814, 0x00000000 }, + { 0xa818, 0x00d20d00 }, + { 0xa81c, 0x000000ff }, + { 0xa820, 0x03004b02 }, + { 0xa824, 0x00000600 }, + { 0xa828, 0x07000773 }, + { 0xa82c, 0x00000000 }, + { 0xa830, 0x00020032 }, + { 0xa834, 0x1520040d }, + { 0xa838, 0x00020105 }, + { 0xa83c, 0x00083700 }, + { 0xa840, 0x000016ff }, + { 0xa844, 0x00000000 }, + { 0xa848, 0xff000000 }, + { 0xa84c, 0x0a000010 }, + { 0xa850, 0x00000002 }, + { 0xa854, 0x00000008 }, + { 0xa858, 0x0000000f }, + { 0xa85c, 0x00000000 }, + { 0xa860, 0x00020000 }, + { 0xa248, 0x0000221e }, + { 0xa900, 0x00000000 }, + { 0xa904, 0x00003800 }, + { 0xa908, 0x00000000 }, + { 0xa90c, 0x0c000000 }, + { 0xa910, 0x12000800 }, + { 0xa914, 0x00000000 }, + { 0xa918, 0x00b20000 }, + { 0xa91c, 0x00000000 }, + { 0xa920, 0x08004b02 }, + { 0xa924, 0x00000300 }, + { 0xa928, 0x01000820 }, + { 0xa92c, 0x00000000 }, + { 0xa930, 0x00030000 }, + { 0xa934, 0x15150406 }, + { 0xa938, 0x00020300 }, + { 0xa93c, 0x00903900 }, + { 0xa940, 0x00000000 }, + { 0xa944, 0x00000000 }, + { 0xa948, 0x20001b00 }, + { 0xa94c, 0x0a000010 }, + { 0xa950, 0x00000000 }, + { 0xa954, 0x00000008 }, + { 0xa960, 0x00110000 }, + { 0xaa3c, 0x00003900 }, + { 0xaa54, 0x00000008 }, + { 0xaa60, 0x00110000 }, + { 0 } +}; + +static const struct gt_powermeter ivb_pm_gt2_35w[] = { + { 0xa800, 0x00000000 }, + { 0xa804, 0x00030400 }, + { 0xa808, 0x00000806 }, + { 0xa80c, 0x0c002f00 }, + { 0xa810, 0x0c000300 }, + { 0xa814, 0x00000000 }, + { 0xa818, 0x00d20d00 }, + { 0xa81c, 0x000000ff }, + { 0xa820, 0x03004b02 }, + { 0xa824, 0x00000600 }, + { 0xa828, 0x07000773 }, + { 0xa82c, 0x00000000 }, + { 0xa830, 0x00020032 }, + { 0xa834, 0x1520040d }, + { 0xa838, 0x00020105 }, + { 0xa83c, 0x00083700 }, + { 0xa840, 0x000016ff }, + { 0xa844, 0x00000000 }, + { 0xa848, 0xff000000 }, + { 0xa84c, 0x0a000010 }, + { 0xa850, 0x00000001 }, + { 0xa854, 0x00000008 }, + { 0xa858, 0x00000008 }, + { 0xa85c, 0x00000000 }, + { 0xa860, 0x00020000 }, + { 0xa248, 0x0000221e }, + { 0xa900, 0x00000000 }, + { 0xa904, 0x00003800 }, + { 0xa908, 0x00000000 }, + { 0xa90c, 0x0c000000 }, + { 0xa910, 0x12000800 }, + { 0xa914, 0x00000000 }, + { 0xa918, 0x00b20000 }, + { 0xa91c, 0x00000000 }, + { 0xa920, 0x08004b02 }, + { 0xa924, 0x00000300 }, + { 0xa928, 0x01000820 }, + { 0xa92c, 0x00000000 }, + { 0xa930, 0x00030000 }, + { 0xa934, 0x15150406 }, + { 0xa938, 0x00020300 }, + { 0xa93c, 0x00903900 }, + { 0xa940, 0x00000000 }, + { 0xa944, 0x00000000 }, + { 0xa948, 0x20001b00 }, + { 0xa94c, 0x0a000010 }, + { 0xa950, 0x00000000 }, + { 0xa954, 0x00000008 }, + { 0xa960, 0x00110000 }, + { 0xaa3c, 0x00003900 }, + { 0xaa54, 0x00000008 }, + { 0xaa60, 0x00110000 }, + { 0 } +}; + +/* + * Some vga option roms are used for several chipsets but they only have one + * PCI ID in their header. If we encounter such an option rom, we need to do + * the mapping ourselves. + */ + +u32 map_oprom_vendev(u32 vendev) +{ + u32 new_vendev = vendev; + + switch (vendev) { + case 0x80860102: /* GT1 Desktop */ + case 0x8086010a: /* GT1 Server */ + case 0x80860112: /* GT2 Desktop */ + case 0x80860116: /* GT2 Mobile */ + case 0x80860122: /* GT2 Desktop >=1.3GHz */ + case 0x80860126: /* GT2 Mobile >=1.3GHz */ + case 0x80860156: /* IVB */ + case 0x80860166: /* IVB */ + /* Set to GT1 Mobile */ + new_vendev = 0x80860106; + break; + } + + return new_vendev; +} + +static inline u32 gtt_read(void *bar, u32 reg) +{ + return readl(bar + reg); +} + +static inline void gtt_write(void *bar, u32 reg, u32 data) +{ + writel(data, bar + reg); +} + +static void gtt_write_powermeter(void *bar, const struct gt_powermeter *pm) +{ + for (; pm && pm->reg; pm++) + gtt_write(bar, pm->reg, pm->value); +} + +#define GTT_RETRY 1000 +static int gtt_poll(void *bar, u32 reg, u32 mask, u32 value) +{ + unsigned try = GTT_RETRY; + u32 data; + + while (try--) { + data = gtt_read(bar, reg); + if ((data & mask) == value) + return 1; + udelay(10); + } + + printf("GT init timeout\n"); + return 0; +} + +static int gma_pm_init_pre_vbios(void *gtt_bar) +{ + u32 reg32; + + debug("GT Power Management Init, silicon = %#x\n", + bridge_silicon_revision()); + + if (bridge_silicon_revision() < IVB_STEP_C0) { + /* 1: Enable force wake */ + gtt_write(gtt_bar, 0xa18c, 0x00000001); + gtt_poll(gtt_bar, 0x130090, (1 << 0), (1 << 0)); + } else { + gtt_write(gtt_bar, 0xa180, 1 << 5); + gtt_write(gtt_bar, 0xa188, 0xffff0001); + gtt_poll(gtt_bar, 0x130040, (1 << 0), (1 << 0)); + } + + if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) { + /* 1d: Set GTT+0x42004 [15:14]=11 (SnB C1+) */ + reg32 = gtt_read(gtt_bar, 0x42004); + reg32 |= (1 << 14) | (1 << 15); + gtt_write(gtt_bar, 0x42004, reg32); + } + + if (bridge_silicon_revision() >= IVB_STEP_A0) { + /* Display Reset Acknowledge Settings */ + reg32 = gtt_read(gtt_bar, 0x45010); + reg32 |= (1 << 1) | (1 << 0); + gtt_write(gtt_bar, 0x45010, reg32); + } + + /* 2: Get GT SKU from GTT+0x911c[13] */ + reg32 = gtt_read(gtt_bar, 0x911c); + if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) { + if (reg32 & (1 << 13)) { + debug("SNB GT1 Power Meter Weights\n"); + gtt_write_powermeter(gtt_bar, snb_pm_gt1); + } else { + debug("SNB GT2 Power Meter Weights\n"); + gtt_write_powermeter(gtt_bar, snb_pm_gt2); + } + } else { + u32 unit = readl(MCHBAR_REG(0x5938)) & 0xf; + + if (reg32 & (1 << 13)) { + /* GT1 SKU */ + debug("IVB GT1 Power Meter Weights\n"); + gtt_write_powermeter(gtt_bar, ivb_pm_gt1); + } else { + /* GT2 SKU */ + u32 tdp = readl(MCHBAR_REG(0x5930)) & 0x7fff; + tdp /= (1 << unit); + + if (tdp <= 17) { + /* <=17W ULV */ + debug("IVB GT2 17W Power Meter Weights\n"); + gtt_write_powermeter(gtt_bar, ivb_pm_gt2_17w); + } else if ((tdp >= 25) && (tdp <= 35)) { + /* 25W-35W */ + debug("IVB GT2 25W-35W Power Meter Weights\n"); + gtt_write_powermeter(gtt_bar, ivb_pm_gt2_35w); + } else { + /* All others */ + debug("IVB GT2 35W Power Meter Weights\n"); + gtt_write_powermeter(gtt_bar, ivb_pm_gt2_35w); + } + } + } + + /* 3: Gear ratio map */ + gtt_write(gtt_bar, 0xa004, 0x00000010); + + /* 4: GFXPAUSE */ + gtt_write(gtt_bar, 0xa000, 0x00070020); + + /* 5: Dynamic EU trip control */ + gtt_write(gtt_bar, 0xa080, 0x00000004); + + /* 6: ECO bits */ + reg32 = gtt_read(gtt_bar, 0xa180); + reg32 |= (1 << 26) | (1 << 31); + /* (bit 20=1 for SNB step D1+ / IVB A0+) */ + if (bridge_silicon_revision() >= SNB_STEP_D1) + reg32 |= (1 << 20); + gtt_write(gtt_bar, 0xa180, reg32); + + /* 6a: for SnB step D2+ only */ + if (((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) && + (bridge_silicon_revision() >= SNB_STEP_D2)) { + reg32 = gtt_read(gtt_bar, 0x9400); + reg32 |= (1 << 7); + gtt_write(gtt_bar, 0x9400, reg32); + + reg32 = gtt_read(gtt_bar, 0x941c); + reg32 &= 0xf; + reg32 |= (1 << 1); + gtt_write(gtt_bar, 0x941c, reg32); + gtt_poll(gtt_bar, 0x941c, (1 << 1), (0 << 1)); + } + + if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_IVB) { + reg32 = gtt_read(gtt_bar, 0x907c); + reg32 |= (1 << 16); + gtt_write(gtt_bar, 0x907c, reg32); + + /* 6b: Clocking reset controls */ + gtt_write(gtt_bar, 0x9424, 0x00000001); + } else { + /* 6b: Clocking reset controls */ + gtt_write(gtt_bar, 0x9424, 0x00000000); + } + + /* 7 */ + if (gtt_poll(gtt_bar, 0x138124, (1 << 31), (0 << 31))) { + gtt_write(gtt_bar, 0x138128, 0x00000029); /* Mailbox Data */ + /* Mailbox Cmd for RC6 VID */ + gtt_write(gtt_bar, 0x138124, 0x80000004); + if (gtt_poll(gtt_bar, 0x138124, (1 << 31), (0 << 31))) + gtt_write(gtt_bar, 0x138124, 0x8000000a); + gtt_poll(gtt_bar, 0x138124, (1 << 31), (0 << 31)); + } + + /* 8 */ + gtt_write(gtt_bar, 0xa090, 0x00000000); /* RC Control */ + gtt_write(gtt_bar, 0xa098, 0x03e80000); /* RC1e Wake Rate Limit */ + gtt_write(gtt_bar, 0xa09c, 0x0028001e); /* RC6/6p Wake Rate Limit */ + gtt_write(gtt_bar, 0xa0a0, 0x0000001e); /* RC6pp Wake Rate Limit */ + gtt_write(gtt_bar, 0xa0a8, 0x0001e848); /* RC Evaluation Interval */ + gtt_write(gtt_bar, 0xa0ac, 0x00000019); /* RC Idle Hysteresis */ + + /* 9 */ + gtt_write(gtt_bar, 0x2054, 0x0000000a); /* Render Idle Max Count */ + gtt_write(gtt_bar, 0x12054, 0x0000000a); /* Video Idle Max Count */ + gtt_write(gtt_bar, 0x22054, 0x0000000a); /* Blitter Idle Max Count */ + + /* 10 */ + gtt_write(gtt_bar, 0xa0b0, 0x00000000); /* Unblock Ack to Busy */ + gtt_write(gtt_bar, 0xa0b4, 0x000003e8); /* RC1e Threshold */ + gtt_write(gtt_bar, 0xa0b8, 0x0000c350); /* RC6 Threshold */ + gtt_write(gtt_bar, 0xa0bc, 0x000186a0); /* RC6p Threshold */ + gtt_write(gtt_bar, 0xa0c0, 0x0000fa00); /* RC6pp Threshold */ + + /* 11 */ + gtt_write(gtt_bar, 0xa010, 0x000f4240); /* RP Down Timeout */ + gtt_write(gtt_bar, 0xa014, 0x12060000); /* RP Interrupt Limits */ + gtt_write(gtt_bar, 0xa02c, 0x00015f90); /* RP Up Threshold */ + gtt_write(gtt_bar, 0xa030, 0x000186a0); /* RP Down Threshold */ + gtt_write(gtt_bar, 0xa068, 0x000186a0); /* RP Up EI */ + gtt_write(gtt_bar, 0xa06c, 0x000493e0); /* RP Down EI */ + gtt_write(gtt_bar, 0xa070, 0x0000000a); /* RP Idle Hysteresis */ + + /* 11a: Enable Render Standby (RC6) */ + if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_IVB) { + /* + * IvyBridge should also support DeepRenderStandby. + * + * Unfortunately it does not work reliably on all SKUs so + * disable it here and it can be enabled by the kernel. + */ + gtt_write(gtt_bar, 0xa090, 0x88040000); /* HW RC Control */ + } else { + gtt_write(gtt_bar, 0xa090, 0x88040000); /* HW RC Control */ + } + + /* 12: Normal Frequency Request */ + /* RPNFREQ_VAL comes from MCHBAR 0x5998 23:16 (8 bits!? use 7) */ + reg32 = readl(MCHBAR_REG(0x5998)); + reg32 >>= 16; + reg32 &= 0xef; + reg32 <<= 25; + gtt_write(gtt_bar, 0xa008, reg32); + + /* 13: RP Control */ + gtt_write(gtt_bar, 0xa024, 0x00000592); + + /* 14: Enable PM Interrupts */ + gtt_write(gtt_bar, 0x4402c, 0x03000076); + + /* Clear 0x6c024 [8:6] */ + reg32 = gtt_read(gtt_bar, 0x6c024); + reg32 &= ~0x000001c0; + gtt_write(gtt_bar, 0x6c024, reg32); + + return 0; +} + +int gma_pm_init_post_vbios(void *gtt_bar, const void *blob, int node) +{ + u32 reg32, cycle_delay; + + debug("GT Power Management Init (post VBIOS)\n"); + + /* 15: Deassert Force Wake */ + if (bridge_silicon_revision() < IVB_STEP_C0) { + gtt_write(gtt_bar, 0xa18c, gtt_read(gtt_bar, 0xa18c) & ~1); + gtt_poll(gtt_bar, 0x130090, (1 << 0), (0 << 0)); + } else { + gtt_write(gtt_bar, 0xa188, 0x1fffe); + if (gtt_poll(gtt_bar, 0x130040, (1 << 0), (0 << 0))) { + gtt_write(gtt_bar, 0xa188, + gtt_read(gtt_bar, 0xa188) | 1); + } + } + + /* 16: SW RC Control */ + gtt_write(gtt_bar, 0xa094, 0x00060000); + + /* Setup Digital Port Hotplug */ + reg32 = gtt_read(gtt_bar, 0xc4030); + if (!reg32) { + u32 dp_hotplug[3]; + + if (fdtdec_get_int_array(blob, node, "intel,dp_hotplug", + dp_hotplug, ARRAY_SIZE(dp_hotplug))) + return -EINVAL; + + reg32 = (dp_hotplug[0] & 0x7) << 2; + reg32 |= (dp_hotplug[0] & 0x7) << 10; + reg32 |= (dp_hotplug[0] & 0x7) << 18; + gtt_write(gtt_bar, 0xc4030, reg32); + } + + /* Setup Panel Power On Delays */ + reg32 = gtt_read(gtt_bar, 0xc7208); + if (!reg32) { + reg32 = (unsigned)fdtdec_get_int(blob, node, + "panel-port-select", 0) << 30; + reg32 |= fdtdec_get_int(blob, node, "panel-power-up-delay", 0) + << 16; + reg32 |= fdtdec_get_int(blob, node, + "panel-power-backlight-on-delay", 0); + gtt_write(gtt_bar, 0xc7208, reg32); + } + + /* Setup Panel Power Off Delays */ + reg32 = gtt_read(gtt_bar, 0xc720c); + if (!reg32) { + reg32 = fdtdec_get_int(blob, node, "panel-power-down-delay", 0) + << 16; + reg32 |= fdtdec_get_int(blob, node, + "panel-power-backlight-off-delay", 0); + gtt_write(gtt_bar, 0xc720c, reg32); + } + + /* Setup Panel Power Cycle Delay */ + cycle_delay = fdtdec_get_int(blob, node, + "intel,panel-power-cycle-delay", 0); + if (cycle_delay) { + reg32 = gtt_read(gtt_bar, 0xc7210); + reg32 &= ~0xff; + reg32 |= cycle_delay; + gtt_write(gtt_bar, 0xc7210, reg32); + } + + /* Enable Backlight if needed */ + reg32 = fdtdec_get_int(blob, node, "intel,cpu-backlight", 0); + if (reg32) { + gtt_write(gtt_bar, 0x48250, (1 << 31)); + gtt_write(gtt_bar, 0x48254, reg32); + } + reg32 = fdtdec_get_int(blob, node, "intel,pch-backlight", 0); + if (reg32) { + gtt_write(gtt_bar, 0xc8250, (1 << 31)); + gtt_write(gtt_bar, 0xc8254, reg32); + } + + return 0; +} + +/* + * Some vga option roms are used for several chipsets but they only have one + * PCI ID in their header. If we encounter such an option rom, we need to do + * the mapping ourselves. + */ + +uint32_t board_map_oprom_vendev(uint32_t vendev) +{ + switch (vendev) { + case 0x80860102: /* GT1 Desktop */ + case 0x8086010a: /* GT1 Server */ + case 0x80860112: /* GT2 Desktop */ + case 0x80860116: /* GT2 Mobile */ + case 0x80860122: /* GT2 Desktop >=1.3GHz */ + case 0x80860126: /* GT2 Mobile >=1.3GHz */ + case 0x80860156: /* IVB */ + case 0x80860166: /* IVB */ + return 0x80860106; /* GT1 Mobile */ + } + + return vendev; +} + +static int int15_handler(void) +{ + int res = 0; + + debug("%s: INT15 function %04x!\n", __func__, M.x86.R_AX); + + switch (M.x86.R_AX) { + case 0x5f34: + /* + * Set Panel Fitting Hook: + * bit 2 = Graphics Stretching + * bit 1 = Text Stretching + * bit 0 = Centering (do not set with bit1 or bit2) + * 0 = video bios default + */ + M.x86.R_AX = 0x005f; + M.x86.R_CL = 0x00; /* Use video bios default */ + res = 1; + break; + case 0x5f35: + /* + * Boot Display Device Hook: + * bit 0 = CRT + * bit 1 = TV (eDP) + * bit 2 = EFP + * bit 3 = LFP + * bit 4 = CRT2 + * bit 5 = TV2 (eDP) + * bit 6 = EFP2 + * bit 7 = LFP2 + */ + M.x86.R_AX = 0x005f; + M.x86.R_CX = 0x0000; /* Use video bios default */ + res = 1; + break; + case 0x5f51: + /* + * Hook to select active LFP configuration: + * 00h = No LVDS, VBIOS does not enable LVDS + * 01h = Int-LVDS, LFP driven by integrated LVDS decoder + * 02h = SVDO-LVDS, LFP driven by SVDO decoder + * 03h = eDP, LFP Driven by Int-DisplayPort encoder + */ + M.x86.R_AX = 0x005f; + M.x86.R_CX = 0x0003; /* eDP */ + res = 1; + break; + case 0x5f70: + switch (M.x86.R_CH) { + case 0: + /* Get Mux */ + M.x86.R_AX = 0x005f; + M.x86.R_CX = 0x0000; + res = 1; + break; + case 1: + /* Set Mux */ + M.x86.R_AX = 0x005f; + M.x86.R_CX = 0x0000; + res = 1; + break; + case 2: + /* Get SG/Non-SG mode */ + M.x86.R_AX = 0x005f; + M.x86.R_CX = 0x0000; + res = 1; + break; + default: + /* Interrupt was not handled */ + debug("Unknown INT15 5f70 function: 0x%02x\n", + M.x86.R_CH); + break; + } + break; + case 0x5fac: + res = 1; + break; + default: + debug("Unknown INT15 function %04x!\n", M.x86.R_AX); + break; + } + return res; +} + +int gma_func0_init(pci_dev_t dev, struct pci_controller *hose, + const void *blob, int node) +{ + void *gtt_bar; + u32 reg32; + int ret; + + /* IGD needs to be Bus Master */ + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; + pci_write_config32(dev, PCI_COMMAND, reg32); + + gtt_bar = (void *)pci_read_bar32(pci_bus_to_hose(0), dev, 0); + debug("GT bar %p\n", gtt_bar); + ret = gma_pm_init_pre_vbios(gtt_bar); + if (ret) + return ret; + + ret = pci_run_vga_bios(dev, int15_handler, false); + + /* Post VBIOS init */ + ret = gma_pm_init_post_vbios(gtt_bar, blob, node); + if (ret) + return ret; + + return 0; +} diff --git a/arch/x86/cpu/ivybridge/gma.h b/arch/x86/cpu/ivybridge/gma.h new file mode 100644 index 0000000..e7ec649 --- /dev/null +++ b/arch/x86/cpu/ivybridge/gma.h @@ -0,0 +1,156 @@ +/* + * From Coreboot file of the same name + * + * Copyright (C) 2012 Chromium OS Authors + * + * SPDX-License-Identifier: GPL-2.0 + */ + +/* mailbox 0: header */ +__packed struct opregion_header { + u8 signature[16]; + u32 size; + u32 version; + u8 sbios_version[32]; + u8 vbios_version[16]; + u8 driver_version[16]; + u32 mailboxes; + u8 reserved[164]; +}; + +#define IGD_OPREGION_SIGNATURE "IntelGraphicsMem" +#define IGD_OPREGION_VERSION 2 + +#define IGD_MBOX1 (1 << 0) +#define IGD_MBOX2 (1 << 1) +#define IGD_MBOX3 (1 << 2) +#define IGD_MBOX4 (1 << 3) +#define IGD_MBOX5 (1 << 4) + +#define MAILBOXES_MOBILE (IGD_MBOX1 | IGD_MBOX2 | IGD_MBOX3 | \ + IGD_MBOX4 | IGD_MBOX5) +#define MAILBOXES_DESKTOP (IGD_MBOX2 | IGD_MBOX4) + +#define SBIOS_VERSION_SIZE 32 + +/* mailbox 1: public acpi methods */ +__packed struct opregion_mailbox1 { + u32 drdy; + u32 csts; + u32 cevt; + u8 reserved1[20]; + u32 didl[8]; + u32 cpdl[8]; + u32 cadl[8]; + u32 nadl[8]; + u32 aslp; + u32 tidx; + u32 chpd; + u32 clid; + u32 cdck; + u32 sxsw; + u32 evts; + u32 cnot; + u32 nrdy; + u8 reserved2[60]; +}; + +/* mailbox 2: software sci interface */ +__packed struct opregion_mailbox2 { + u32 scic; + u32 parm; + u32 dslp; + u8 reserved[244]; +}; + +/* mailbox 3: power conservation */ +__packed struct opregion_mailbox3 { + u32 ardy; + u32 aslc; + u32 tche; + u32 alsi; + u32 bclp; + u32 pfit; + u32 cblv; + u16 bclm[20]; + u32 cpfm; + u32 epfm; + u8 plut[74]; + u32 pfmb; + u32 ccdv; + u32 pcft; + u8 reserved[94]; +}; + +#define IGD_BACKLIGHT_BRIGHTNESS 0xff +#define IGD_INITIAL_BRIGHTNESS 0x64 + +#define IGD_FIELD_VALID (1 << 31) +#define IGD_WORD_FIELD_VALID (1 << 15) +#define IGD_PFIT_STRETCH 6 + +/* mailbox 4: vbt */ +__packed struct { + u8 gvd1[7168]; +} opregion_vbt_t; + +/* IGD OpRegion */ +__packed struct igd_opregion { + opregion_header_t header; + opregion_mailbox1_t mailbox1; + opregion_mailbox2_t mailbox2; + opregion_mailbox3_t mailbox3; + opregion_vbt_t vbt; +}; + +/* Intel Video BIOS (Option ROM) */ +__packed struct optionrom_header { + u16 signature; + u8 size; + u8 reserved[21]; + u16 pcir_offset; + u16 vbt_offset; +}; + +#define OPROM_SIGNATURE 0xaa55 + +__packed struct optionrom_pcir { + u32 signature; + u16 vendor; + u16 device; + u16 reserved1; + u16 length; + u8 revision; + u8 classcode[3]; + u16 imagelength; + u16 coderevision; + u8 codetype; + u8 indicator; + u16 reserved2; +}; + +__packed struct optionrom_vbt { + u8 hdr_signature[20]; + u16 hdr_version; + u16 hdr_size; + u16 hdr_vbt_size; + u8 hdr_vbt_checksum; + u8 hdr_reserved; + u32 hdr_vbt_datablock; + u32 hdr_aim[4]; + u8 datahdr_signature[16]; + u16 datahdr_version; + u16 datahdr_size; + u16 datahdr_datablocksize; + u8 coreblock_id; + u16 coreblock_size; + u16 coreblock_biossize; + u8 coreblock_biostype; + u8 coreblock_releasestatus; + u8 coreblock_hwsupported; + u8 coreblock_integratedhw; + u8 coreblock_biosbuild[4]; + u8 coreblock_biossignon[155]; +}; + +#define VBT_SIGNATURE 0x54425624 diff --git a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h index 96d51c2..e1d9a9b 100644 --- a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h +++ b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h @@ -13,6 +13,8 @@ void bd82x6x_pci_init(pci_dev_t dev); void bd82x6x_usb_ehci_init(pci_dev_t dev); void bd82x6x_usb_xhci_init(pci_dev_t dev); int bd82x6x_init_pci_devices(void); +int gma_func0_init(pci_dev_t dev, struct pci_controller *hose, + const void *blob, int node); int bd82x6x_init(void); struct x86_cpu_priv; diff --git a/doc/device-tree-bindings/video/intel-gma.txt b/doc/device-tree-bindings/video/intel-gma.txt new file mode 100644 index 0000000..914be4f --- /dev/null +++ b/doc/device-tree-bindings/video/intel-gma.txt @@ -0,0 +1,40 @@ +Intel GMA Bindings +================== + +This is the Intel Graphics Media Accelerator. This binding supports selection +of display parameters only. + + +Required properties: + - compatible : "intel,gma"; + +Optional properties: + - intel,dp-hotplug : values for digital port hotplug, one cell per value for + ports B, C and D + - intel,panel-port-select : output port to use: 0=LVDS 1=DP_B 2=DP_C 3=DP_D + - intel,panel-power-cycle-delay : T4 time sequence (6 = 500ms) + + The following delays are in units of 0.1ms: + - intel,panel-power-up-delay : T1+T2 time sequence + - intel,panel-power-down-delay : T3 time sequence + - intel,panel-power-backlight-on-delay : T5 time sequence + - intel,panel-power-backlight-off-delay : Tx time sequence + + - intel,cpu-backlight : Value for CPU Backlight PWM + - intel,pch-backlight : Value for PCH Backlight PWM + +Example +------- + +gma { + compatible = "intel,gma"; + intel,dp_hotplug = <0 0 0x06>; + intel,panel-port-select = <1>; + intel,panel-power-cycle-delay = <6>; + intel,panel-power-up-delay = <2000>; + intel,panel-power-down-delay = <500>; + intel,panel-power-backlight-on-delay = <2000>; + intel,panel-power-backlight-off-delay = <2000>; + intel,cpu-backlight = <0x00000200>; + intel,pch-backlight = <0x04000000>; +}; diff --git a/include/fdtdec.h b/include/fdtdec.h index b6e1d40..ea92894 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -122,6 +122,7 @@ enum fdt_compat_id { COMPAT_MEMORY_SPD, /* Memory SPD information */ COMPAT_INTEL_PANTHERPOINT_AHCI, /* Intel Pantherpoint AHCI */ COMPAT_INTEL_MODEL_206AX, /* Intel Model 206AX CPU */ + COMPAT_INTEL_GMA, /* Intel Graphics Media Accelerator */ COMPAT_COUNT, }; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 723a957..0d1d5d5 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -77,6 +77,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(MEMORY_SPD, "memory-spd"), COMPAT(INTEL_PANTHERPOINT_AHCI, "intel,pantherpoint-ahci"), COMPAT(INTEL_MODEL_206AX, "intel,model-206ax"), + COMPAT(INTEL_GMA, "intel,gma"), }; const char *fdtdec_get_compatible(enum fdt_compat_id id) -- cgit v0.10.2 From f3e56fe369ff80760955efb33abf316d4369955c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:37 -0700 Subject: x86: dts: Add video information to the device tree This provides panel timing information needed by the video driver. Signed-off-by: Simon Glass diff --git a/arch/x86/dts/link.dts b/arch/x86/dts/link.dts index d3c94e0..592af16 100644 --- a/arch/x86/dts/link.dts +++ b/arch/x86/dts/link.dts @@ -171,6 +171,19 @@ intel,sata-port0-gen3-tx = <0x00880a7f>; }; + gma { + compatible = "intel,gma"; + intel,dp_hotplug = <0 0 0x06>; + intel,panel-port-select = <1>; + intel,panel-power-cycle-delay = <6>; + intel,panel-power-up-delay = <2000>; + intel,panel-power-down-delay = <500>; + intel,panel-power-backlight-on-delay = <2000>; + intel,panel-power-backlight-off-delay = <2000>; + intel,cpu-backlight = <0x00000200>; + intel,pch-backlight = <0x04000000>; + }; + lpc { compatible = "intel,lpc"; #address-cells = <1>; -- cgit v0.10.2 From 62d0c5e15347f0ab9998d8bac2845be0d441c8b1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:38 -0700 Subject: x86: config: Enable video support for chromebook_link Now that we have the required drivers, enable video support with a suitable option ROM. Signed-off-by: Simon Glass diff --git a/include/configs/chromebook_link.h b/include/configs/chromebook_link.h index 6b57b28..c098c6c 100644 --- a/include/configs/chromebook_link.h +++ b/include/configs/chromebook_link.h @@ -39,13 +39,9 @@ {PCI_VENDOR_ID_INTEL, \ PCI_DEVICE_ID_INTEL_PANTHERPOINT_AHCI_MOBILE} -/* - * These common x86 features are not yet supported, but are added in - * follow-on patches in this series. Add undefs here to avoid every patch - * having to put things back into x86-common.h - */ -#undef CONFIG_VIDEO -#undef CONFIG_CFB_CONSOLE +#define CONFIG_X86_OPTION_ROM_FILENAME pci8086,0166.bin +#define CONFIG_X86_OPTION_ROM_ADDR 0xfff90000 +#define CONFIG_VIDEO_X86 #define CONFIG_PCI_MEM_BUS 0xe0000000 #define CONFIG_PCI_MEM_PHYS CONFIG_PCI_MEM_BUS -- cgit v0.10.2 From ad6edca379117d52da373818a5db3027da2ad14b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:39 -0700 Subject: bios_emulator: Allow x86 to use the emulator There is an implicit assumption that x86 machines want to use raw I/O in the BIOS emulator, but this should be selectable. Add an CONFIG_X86EMU_RAW_IO option to control it instead. Also fix a few bugs which cause warnings on x86 and adjust the Makefile to remove the assumption that only PowerPC uses the emulator. Signed-off-by: Simon Glass diff --git a/drivers/bios_emulator/Makefile b/drivers/bios_emulator/Makefile index e56356e..2ba43ac 100644 --- a/drivers/bios_emulator/Makefile +++ b/drivers/bios_emulator/Makefile @@ -9,4 +9,4 @@ obj-y = atibios.o biosemu.o besys.o bios.o \ $(X86DIR)/debug.o ccflags-y := -I$(srctree)/$(src) -I$(srctree)/$(src)/include \ - -D__PPC__ -D__BIG_ENDIAN__ + $(if $(CONFIG_PPC),-D__PPC__ -D__BIG_ENDIAN__) diff --git a/drivers/bios_emulator/besys.c b/drivers/bios_emulator/besys.c index ad88a53..70c472a 100644 --- a/drivers/bios_emulator/besys.c +++ b/drivers/bios_emulator/besys.c @@ -54,7 +54,7 @@ /*------------------------- Global Variables ------------------------------*/ -#ifndef __i386__ +#ifndef CONFIG_X86EMU_RAW_IO static char *BE_biosDate = "08/14/99"; static u8 BE_model = 0xFC; static u8 BE_submodel = 0x00; @@ -80,16 +80,18 @@ static u8 *BE_memaddr(u32 addr) if (addr >= 0xC0000 && addr <= _BE_env.biosmem_limit) { return (u8*)(_BE_env.biosmem_base + addr - 0xC0000); } else if (addr > _BE_env.biosmem_limit && addr < 0xD0000) { - DB(printf("BE_memaddr: address %#lx may be invalid!\n", addr);) - return M.mem_base; + DB(printf("BE_memaddr: address %#lx may be invalid!\n", + (ulong)addr);) + return (u8 *)M.mem_base; } else if (addr >= 0xA0000 && addr <= 0xBFFFF) { return (u8*)(_BE_env.busmem_base + addr - 0xA0000); } -#ifdef __i386__ +#ifdef CONFIG_X86EMU_RAW_IO else if (addr >= 0xD0000 && addr <= 0xFFFFF) { /* We map the real System BIOS directly on real PC's */ - DB(printf("BE_memaddr: System BIOS address %#lx\n", addr);) - return _BE_env.busmem_base + addr - 0xA0000; + DB(printf("BE_memaddr: System BIOS address %#lx\n", + (ulong)addr);) + return (u8 *)_BE_env.busmem_base + addr - 0xA0000; } #else else if (addr >= 0xFFFF5 && addr < 0xFFFFE) { @@ -108,10 +110,10 @@ static u8 *BE_memaddr(u32 addr) #endif else if (addr > M.mem_size - 1) { HALT_SYS(); - return M.mem_base; + return (u8 *)M.mem_base; } - return M.mem_base + addr; + return (u8 *)(M.mem_base + addr); } /**************************************************************************** @@ -230,7 +232,7 @@ void X86API BE_wrl(u32 addr, u32 val) } } -#if defined(DEBUG) || !defined(__i386__) +#if !defined(CONFIG_X86EMU_RAW_IO) /* For Non-Intel machines we may need to emulate some I/O port accesses that * the BIOS may try to access, such as the PCI config registers. @@ -560,7 +562,7 @@ u8 X86API BE_inb(X86EMU_pioAddr port) { u8 val = 0; -#if defined(DEBUG) || !defined(__i386__) +#if !defined(CONFIG_X86EMU_RAW_IO) if (IS_VGA_PORT(port)){ /*seems reading port 0x3c3 return the high 16 bit of io port*/ if(port == 0x3c3) @@ -601,7 +603,7 @@ u16 X86API BE_inw(X86EMU_pioAddr port) { u16 val = 0; -#if defined(DEBUG) || !defined(__i386__) +#if !defined(CONFIG_X86EMU_RAW_IO) if (IS_PCI_PORT(port)) val = PCI_inp(port, REG_READ_WORD); else if (port < 0x100) { @@ -629,7 +631,7 @@ u32 X86API BE_inl(X86EMU_pioAddr port) { u32 val = 0; -#if defined(DEBUG) || !defined(__i386__) +#if !defined(CONFIG_X86EMU_RAW_IO) if (IS_PCI_PORT(port)) val = PCI_inp(port, REG_READ_DWORD); else if (port < 0x100) { @@ -652,7 +654,7 @@ through to the real hardware if we don't need to special case it. ****************************************************************************/ void X86API BE_outb(X86EMU_pioAddr port, u8 val) { -#if defined(DEBUG) || !defined(__i386__) +#if !defined(CONFIG_X86EMU_RAW_IO) if (IS_VGA_PORT(port)) VGA_outpb(port, val); else if (IS_TIMER_PORT(port)) @@ -683,7 +685,7 @@ through to the real hardware if we don't need to special case it. ****************************************************************************/ void X86API BE_outw(X86EMU_pioAddr port, u16 val) { -#if defined(DEBUG) || !defined(__i386__) +#if !defined(CONFIG_X86EMU_RAW_IO) if (IS_VGA_PORT(port)) { VGA_outpb(port, val); VGA_outpb(port + 1, val >> 8); @@ -710,7 +712,7 @@ through to the real hardware if we don't need to special case it. ****************************************************************************/ void X86API BE_outl(X86EMU_pioAddr port, u32 val) { -#if defined(DEBUG) || !defined(__i386__) +#if !defined(CONFIG_X86EMU_RAW_IO) if (IS_PCI_PORT(port)) PCI_outp(port, val, REG_WRITE_DWORD); else if (port < 0x100) { diff --git a/drivers/bios_emulator/include/x86emu.h b/drivers/bios_emulator/include/x86emu.h index a70a768..278f669 100644 --- a/drivers/bios_emulator/include/x86emu.h +++ b/drivers/bios_emulator/include/x86emu.h @@ -53,9 +53,9 @@ typedef u16 X86EMU_pioAddr; /*---------------------- Macros and type definitions ----------------------*/ -#if defined (CONFIG_ARM) +#if defined(CONFIG_ARM) #define GAS_LINE_COMMENT "@" -#elif defined(CONFIG_MIPS) || defined(CONFIG_PPC) +#elif defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_X86) #define GAS_LINE_COMMENT "#" #elif defined (CONFIG_SH) #define GAS_LINE_COMMENT "!" diff --git a/drivers/bios_emulator/x86emu/debug.c b/drivers/bios_emulator/x86emu/debug.c index 2fa8050..2ec64c2 100644 --- a/drivers/bios_emulator/x86emu/debug.c +++ b/drivers/bios_emulator/x86emu/debug.c @@ -211,9 +211,7 @@ void X86EMU_dump_memory(u16 seg, u16 off, u32 amt) u32 start = off & 0xfffffff0; u32 end = (off + 16) & 0xfffffff0; u32 i; - u32 current; - current = start; while (end <= off + amt) { printk("%04x:%04x ", seg, start); for (i = start; i < off; i++) @@ -229,7 +227,7 @@ void X86EMU_dump_memory(u16 seg, u16 off, u32 amt) void x86emu_single_step(void) { char s[1024]; - int ps[10]; + int ps[10]; int ntok; int cmd; int done; @@ -238,8 +236,6 @@ void x86emu_single_step(void) static int breakpoint; static int noDecode = 1; - char *p; - if (DEBUG_BREAK()) { if (M.x86.saved_ip != breakpoint) { return; @@ -255,6 +251,8 @@ void x86emu_single_step(void) offset = M.x86.saved_ip; while (!done) { printk("-"); + ps[1] = 0; /* Avoid dodgy compiler warnings */ + ps[2] = 0; cmd = x86emu_parse_line(s, ps, &ntok); switch (cmd) { case 'u': -- cgit v0.10.2 From 4c59f95327966b83981cb53371a854570a01e8d9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:40 -0700 Subject: bios_emulator: Add vesa support and allow ROMs to be passed in as data As well as locating the ROM on the PCI bus, allow the ROM to be supplied to the emulator. Split the init up a little so that callers can supply their own interrupt routines. Also allow a vesa mode to be provided, to be selected once the BIOS run is complete. Signed-off-by: Simon Glass diff --git a/drivers/bios_emulator/atibios.c b/drivers/bios_emulator/atibios.c index 3b2ed6e..93b815c 100644 --- a/drivers/bios_emulator/atibios.c +++ b/drivers/bios_emulator/atibios.c @@ -46,8 +46,11 @@ * BIOS in u-boot. ****************************************************************************/ #include -#include "biosemui.h" +#include +#include #include +#include +#include "biosemui.h" /* Length of the BIOS image */ #define MAX_BIOSLEN (128 * 1024L) @@ -59,17 +62,54 @@ static u32 saveBaseAddress14; static u32 saveBaseAddress18; static u32 saveBaseAddress20; +static void atibios_set_vesa_mode(RMREGS *regs, int vesa_mode, + struct vbe_mode_info *mode_info) +{ + debug("VBE: Setting VESA mode %#04x\n", vesa_mode); + /* request linear framebuffer mode */ + vesa_mode |= (1 << 14); + /* request clearing of framebuffer */ + vesa_mode &= ~(1 << 15); + regs->e.eax = VESA_SET_MODE; + regs->e.ebx = vesa_mode; + BE_int86(0x10, regs, regs); + + int offset = 0x2000; + void *buffer = (void *)(M.mem_base + offset); + + u16 buffer_seg = (((unsigned long)offset) >> 4) & 0xff00; + u16 buffer_adr = ((unsigned long)offset) & 0xffff; + regs->e.eax = VESA_GET_MODE_INFO; + regs->e.ebx = 0; + regs->e.ecx = vesa_mode; + regs->e.edx = 0; + regs->e.esi = buffer_seg; + regs->e.edi = buffer_adr; + BE_int86(0x10, regs, regs); + memcpy(mode_info->mode_info_block, buffer, + sizeof(struct vbe_mode_info)); + mode_info->valid = true; + + vesa_mode |= (1 << 14); + /* request clearing of framebuffer */ + vesa_mode &= ~(1 << 15); + regs->e.eax = VESA_SET_MODE; + regs->e.ebx = vesa_mode; + BE_int86(0x10, regs, regs); +} + /**************************************************************************** PARAMETERS: pcidev - PCI device info for the video card on the bus to boot -VGAInfo - BIOS emulator VGA info structure +vga_info - BIOS emulator VGA info structure REMARKS: This function executes the BIOS POST code on the controller. We assume that at this stage the controller has its I/O and memory space enabled and that all other controllers are in a disabled state. ****************************************************************************/ -static void PCI_doBIOSPOST(pci_dev_t pcidev, BE_VGAInfo * VGAInfo) +static void PCI_doBIOSPOST(pci_dev_t pcidev, BE_VGAInfo *vga_info, + int vesa_mode, struct vbe_mode_info *mode_info) { RMREGS regs; RMSREGS sregs; @@ -84,13 +124,16 @@ static void PCI_doBIOSPOST(pci_dev_t pcidev, BE_VGAInfo * VGAInfo) ((int)PCI_DEV(pcidev) << 3) | (int)PCI_FUNC(pcidev); /*Setup the X86 emulator for the VGA BIOS*/ - BE_setVGA(VGAInfo); + BE_setVGA(vga_info); /*Execute the BIOS POST code*/ BE_callRealMode(0xC000, 0x0003, ®s, &sregs); /*Cleanup and exit*/ - BE_getVGA(VGAInfo); + BE_getVGA(vga_info); + + if (vesa_mode != -1) + atibios_set_vesa_mode(®s, vesa_mode, mode_info); } /**************************************************************************** @@ -244,60 +287,61 @@ REMARKS: Loads and POST's the display controllers BIOS, directly from the BIOS image we can extract over the PCI bus. ****************************************************************************/ -static int PCI_postController(pci_dev_t pcidev, BE_VGAInfo * VGAInfo) +static int PCI_postController(pci_dev_t pcidev, uchar *bios_rom, int bios_len, + BE_VGAInfo *vga_info, int vesa_mode, + struct vbe_mode_info *mode_info) { - u32 BIOSImageLen; - uchar *mappedBIOS; - uchar *copyOfBIOS; - - /*Allocate memory to store copy of BIOS from display controller*/ - if ((mappedBIOS = PCI_mapBIOSImage(pcidev)) == NULL) { - printf("videoboot: Video ROM failed to map!\n"); - return false; - } + u32 bios_image_len; + uchar *mapped_bios; + uchar *copy_of_bios; + + if (bios_rom) { + copy_of_bios = bios_rom; + bios_image_len = bios_len; + } else { + /* + * Allocate memory to store copy of BIOS from display + * controller + */ + mapped_bios = PCI_mapBIOSImage(pcidev); + if (mapped_bios == NULL) { + printf("videoboot: Video ROM failed to map!\n"); + return false; + } - BIOSImageLen = mappedBIOS[2] * 512; + bios_image_len = mapped_bios[2] * 512; - if ((copyOfBIOS = malloc(BIOSImageLen)) == NULL) { - printf("videoboot: Out of memory!\n"); - return false; + copy_of_bios = malloc(bios_image_len); + if (copy_of_bios == NULL) { + printf("videoboot: Out of memory!\n"); + return false; + } + memcpy(copy_of_bios, mapped_bios, bios_image_len); + PCI_unmapBIOSImage(pcidev, mapped_bios); } - memcpy(copyOfBIOS, mappedBIOS, BIOSImageLen); - PCI_unmapBIOSImage(pcidev, mappedBIOS); - - /*Save information in VGAInfo structure*/ - VGAInfo->function = PCI_FUNC(pcidev); - VGAInfo->device = PCI_DEV(pcidev); - VGAInfo->bus = PCI_BUS(pcidev); - VGAInfo->pcidev = pcidev; - VGAInfo->BIOSImage = copyOfBIOS; - VGAInfo->BIOSImageLen = BIOSImageLen; + /*Save information in vga_info structure*/ + vga_info->function = PCI_FUNC(pcidev); + vga_info->device = PCI_DEV(pcidev); + vga_info->bus = PCI_BUS(pcidev); + vga_info->pcidev = pcidev; + vga_info->BIOSImage = copy_of_bios; + vga_info->BIOSImageLen = bios_image_len; /*Now execute the BIOS POST for the device*/ - if (copyOfBIOS[0] != 0x55 || copyOfBIOS[1] != 0xAA) { + if (copy_of_bios[0] != 0x55 || copy_of_bios[1] != 0xAA) { printf("videoboot: Video ROM image is invalid!\n"); return false; } - PCI_doBIOSPOST(pcidev, VGAInfo); + PCI_doBIOSPOST(pcidev, vga_info, vesa_mode, mode_info); /*Reset the size of the BIOS image to the final size*/ - VGAInfo->BIOSImageLen = copyOfBIOS[2] * 512; + vga_info->BIOSImageLen = copy_of_bios[2] * 512; return true; } -/**************************************************************************** -PARAMETERS: -pcidev - PCI device info for the video card on the bus to boot -pVGAInfo - Place to return VGA info structure is requested -cleanUp - true to clean up on exit, false to leave emulator active - -REMARKS: -Boots the PCI/AGP video card on the bus using the Video ROM BIOS image -and the X86 BIOS emulator module. -****************************************************************************/ -int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo ** pVGAInfo, int cleanUp) +int biosemu_setup(pci_dev_t pcidev, BE_VGAInfo **vga_infop) { BE_VGAInfo *VGAInfo; @@ -307,28 +351,70 @@ int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo ** pVGAInfo, int cleanUp) /*Initialise the x86 BIOS emulator*/ if ((VGAInfo = malloc(sizeof(*VGAInfo))) == NULL) { printf("videoboot: Out of memory!\n"); - return false; + return -ENOMEM; } memset(VGAInfo, 0, sizeof(*VGAInfo)); BE_init(0, 65536, VGAInfo, 0); + *vga_infop = VGAInfo; - /*Post all the display controller BIOS'es*/ - if (!PCI_postController(pcidev, VGAInfo)) - return false; + return 0; +} - /*Cleanup and exit the emulator if requested. If the BIOS emulator - is needed after booting the card, we will not call BE_exit and - leave it enabled for further use (ie: VESA driver etc). +void biosemu_set_interrupt_handler(int intnum, int (*int_func)(void)) +{ + X86EMU_setupIntrFunc(intnum, (X86EMU_intrFuncs)int_func); +} + +int biosemu_run(pci_dev_t pcidev, uchar *bios_rom, int bios_len, + BE_VGAInfo *vga_info, int clean_up, int vesa_mode, + struct vbe_mode_info *mode_info) +{ + /*Post all the display controller BIOS'es*/ + if (!PCI_postController(pcidev, bios_rom, bios_len, vga_info, + vesa_mode, mode_info)) + return -EINVAL; + + /* + * Cleanup and exit the emulator if requested. If the BIOS emulator + * is needed after booting the card, we will not call BE_exit and + * leave it enabled for further use (ie: VESA driver etc). */ - if (cleanUp) { + if (clean_up) { BE_exit(); - if (VGAInfo->BIOSImage) - free(VGAInfo->BIOSImage); - free(VGAInfo); - VGAInfo = NULL; + if (vga_info->BIOSImage) + free(vga_info->BIOSImage); + free(vga_info); + vga_info = NULL; } - /*Return VGA info pointer if the caller requested it*/ + + return 0; +} + +/**************************************************************************** +PARAMETERS: +pcidev - PCI device info for the video card on the bus to boot +pVGAInfo - Place to return VGA info structure is requested +cleanUp - true to clean up on exit, false to leave emulator active + +REMARKS: +Boots the PCI/AGP video card on the bus using the Video ROM BIOS image +and the X86 BIOS emulator module. +****************************************************************************/ +int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo **pVGAInfo, int clean_up) +{ + BE_VGAInfo *VGAInfo; + int ret; + + ret = biosemu_setup(pcidev, &VGAInfo); + if (ret) + return false; + ret = biosemu_run(pcidev, NULL, 0, VGAInfo, clean_up, -1, NULL); + if (ret) + return false; + + /* Return VGA info pointer if the caller requested it*/ if (pVGAInfo) *pVGAInfo = VGAInfo; + return true; } diff --git a/drivers/bios_emulator/besys.c b/drivers/bios_emulator/besys.c index 70c472a..8e29a9e 100644 --- a/drivers/bios_emulator/besys.c +++ b/drivers/bios_emulator/besys.c @@ -713,9 +713,9 @@ through to the real hardware if we don't need to special case it. void X86API BE_outl(X86EMU_pioAddr port, u32 val) { #if !defined(CONFIG_X86EMU_RAW_IO) - if (IS_PCI_PORT(port)) + if (IS_PCI_PORT(port)) { PCI_outp(port, val, REG_WRITE_DWORD); - else if (port < 0x100) { + } else if (port < 0x100) { DB(printf("WARN: INVALID outl.%04X <- %08X\n", (u16) port,val);) LOG_outpd(port, val); } else diff --git a/include/bios_emul.h b/include/bios_emul.h index f4c4d1d..3643b82 100644 --- a/include/bios_emul.h +++ b/include/bios_emul.h @@ -55,4 +55,12 @@ void bios_run_on_x86(pci_dev_t pcidev, unsigned long addr, int vesa_mode, */ void bios_set_interrupt_handler(int intnum, int (*int_handler_func)(void)); +void biosemu_set_interrupt_handler(int intnum, int (*int_func)(void)); + +int biosemu_setup(pci_dev_t pcidev, BE_VGAInfo **pVGAInfo); + +int biosemu_run(pci_dev_t pcidev, uchar *bios_rom, int bios_len, + BE_VGAInfo *vga_info, int clean_up, int vesa_mode, + struct vbe_mode_info *mode_info); + #endif -- cgit v0.10.2 From a3c700ec7611ce579ecab7005c66c6d1e7b1dbac Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:41 -0700 Subject: bios_emulator: Allow a custom interrupt handler to be installed Sometime we want to provide an interrupt handler for the ROM, Add a function to allow this. Signed-off-by: Simon Glass diff --git a/drivers/bios_emulator/include/x86emu.h b/drivers/bios_emulator/include/x86emu.h index 278f669..63febe0 100644 --- a/drivers/bios_emulator/include/x86emu.h +++ b/drivers/bios_emulator/include/x86emu.h @@ -153,6 +153,7 @@ extern "C" { /* Use "C" linkage when in C++ mode */ void X86EMU_setupMemFuncs(X86EMU_memFuncs * funcs); void X86EMU_setupPioFuncs(X86EMU_pioFuncs * funcs); void X86EMU_setupIntrFuncs(X86EMU_intrFuncs funcs[]); + void X86EMU_setupIntrFunc(int intnum, X86EMU_intrFuncs func); void X86EMU_prepareForInt(int num); /* decode.c */ diff --git a/drivers/bios_emulator/x86emu/sys.c b/drivers/bios_emulator/x86emu/sys.c index 21f9730..0ba9c0c 100644 --- a/drivers/bios_emulator/x86emu/sys.c +++ b/drivers/bios_emulator/x86emu/sys.c @@ -273,6 +273,11 @@ void X86EMU_setupPioFuncs(X86EMU_pioFuncs * funcs) sys_outl = funcs->outl; } +void X86EMU_setupIntrFunc(int intnum, X86EMU_intrFuncs func) +{ + _X86EMU_intrTab[intnum] = func; +} + /**************************************************************************** PARAMETERS: funcs - New interrupt vector table to make active -- cgit v0.10.2 From b3521f2e495c8cd91226af9b34f2d7ef5a24c665 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:42 -0700 Subject: bios_emulator: Add an option to enable debugging At present there are DEBUG options spread around the place. If you enable one and not another you can end up with an emulator that does not work, since each file can have a different view of what the registers look like. To fix this, create a global CONFIG_X86EMU_DEBUG option that keeps everything consistent. Signed-off-by: Simon Glass diff --git a/drivers/bios_emulator/besys.c b/drivers/bios_emulator/besys.c index 8e29a9e..752a928 100644 --- a/drivers/bios_emulator/besys.c +++ b/drivers/bios_emulator/besys.c @@ -60,6 +60,14 @@ static u8 BE_model = 0xFC; static u8 BE_submodel = 0x00; #endif +#undef DEBUG_IO_ACCESS + +#ifdef DEBUG_IO_ACCESS +#define debug_io(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define debug_io(x, b...) +#endif + /*----------------------------- Implementation ----------------------------*/ /**************************************************************************** @@ -96,15 +104,15 @@ static u8 *BE_memaddr(u32 addr) #else else if (addr >= 0xFFFF5 && addr < 0xFFFFE) { /* Return a faked BIOS date string for non-x86 machines */ - DB(printf("BE_memaddr - Returning BIOS date\n");) + debug_io("BE_memaddr - Returning BIOS date\n"); return (u8 *)(BE_biosDate + addr - 0xFFFF5); } else if (addr == 0xFFFFE) { /* Return system model identifier for non-x86 machines */ - DB(printf("BE_memaddr - Returning model\n");) + debug_io("BE_memaddr - Returning model\n"); return &BE_model; } else if (addr == 0xFFFFF) { /* Return system submodel identifier for non-x86 machines */ - DB(printf("BE_memaddr - Returning submodel\n");) + debug_io("BE_memaddr - Returning submodel\n"); return &BE_submodel; } #endif @@ -260,6 +268,7 @@ static u8 VGA_inpb (const int port) { u8 val = 0xff; + debug_io("vga_inb.%04X -> ", (u16) port); switch (port) { case 0x3C0: /* 3C0 has funky characteristics because it can act as either @@ -583,7 +592,12 @@ u8 X86API BE_inb(X86EMU_pioAddr port) val = LOG_inpb(port); } else #endif + { + debug_io("inb.%04X -> ", (u16) port); val = LOG_inpb(port); + debug_io("%02X\n", val); + } + return val; } @@ -611,7 +625,12 @@ u16 X86API BE_inw(X86EMU_pioAddr port) val = LOG_inpw(port); } else #endif + { + debug_io("inw.%04X -> ", (u16) port); val = LOG_inpw(port); + debug_io("%04X\n", val); + } + return val; } @@ -638,7 +657,12 @@ u32 X86API BE_inl(X86EMU_pioAddr port) val = LOG_inpd(port); } else #endif + { + debug_io("inl.%04X -> ", (u16) port); val = LOG_inpd(port); + debug_io("%08X\n", val); + } + return val; } @@ -670,7 +694,11 @@ void X86API BE_outb(X86EMU_pioAddr port, u8 val) LOG_outpb(port, val); } else #endif + { + debug_io("outb.%04X <- %02X", (u16) port, val); LOG_outpb(port, val); + debug_io("\n"); + } } /**************************************************************************** @@ -686,18 +714,22 @@ through to the real hardware if we don't need to special case it. void X86API BE_outw(X86EMU_pioAddr port, u16 val) { #if !defined(CONFIG_X86EMU_RAW_IO) - if (IS_VGA_PORT(port)) { - VGA_outpb(port, val); - VGA_outpb(port + 1, val >> 8); - } else if (IS_PCI_PORT(port)) - PCI_outp(port, val, REG_WRITE_WORD); - else if (port < 0x100) { - DB(printf("WARN: MAybe INVALID outw.%04X <- %04X\n", (u16) port, - val);) - LOG_outpw(port, val); - } else + if (IS_VGA_PORT(port)) { + VGA_outpb(port, val); + VGA_outpb(port + 1, val >> 8); + } else if (IS_PCI_PORT(port)) { + PCI_outp(port, val, REG_WRITE_WORD); + } else if (port < 0x100) { + DB(printf("WARN: MAybe INVALID outw.%04X <- %04X\n", (u16)port, + val);) + LOG_outpw(port, val); + } else #endif - LOG_outpw(port, val); + { + debug_io("outw.%04X <- %04X", (u16) port, val); + LOG_outpw(port, val); + debug_io("\n"); + } } /**************************************************************************** @@ -720,5 +752,9 @@ void X86API BE_outl(X86EMU_pioAddr port, u32 val) LOG_outpd(port, val); } else #endif + { + debug_io("outl.%04X <- %08X", (u16) port, val); LOG_outpd(port, val); + debug_io("\n"); + } } diff --git a/drivers/bios_emulator/bios.c b/drivers/bios_emulator/bios.c index bcc192f..152d70a 100644 --- a/drivers/bios_emulator/bios.c +++ b/drivers/bios_emulator/bios.c @@ -84,14 +84,14 @@ static void X86API int42(int intno) PM_outpb(0x3c2, PM_inpb(0x3cc) & (u8) ~ 0x02); return; } -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG else { printf("int42: unknown function AH=0x12, BL=0x32, AL=%#02x\n", M.x86.R_AL); } #endif } -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG else { printf("int42: unknown function AH=%#02x, AL=%#02x, BL=%#02x\n", M.x86.R_AH, M.x86.R_AL, M.x86.R_BL); diff --git a/drivers/bios_emulator/biosemui.h b/drivers/bios_emulator/biosemui.h index 8c1f111..7853015 100644 --- a/drivers/bios_emulator/biosemui.h +++ b/drivers/bios_emulator/biosemui.h @@ -48,7 +48,7 @@ #include /*---------------------- Macros and type definitions ----------------------*/ -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG #define DB(x) x #else #define DB(x) do{}while(0); diff --git a/drivers/bios_emulator/include/x86emu.h b/drivers/bios_emulator/include/x86emu.h index 63febe0..b28cdc6 100644 --- a/drivers/bios_emulator/include/x86emu.h +++ b/drivers/bios_emulator/include/x86emu.h @@ -161,7 +161,7 @@ extern "C" { /* Use "C" linkage when in C++ mode */ void X86EMU_exec(void); void X86EMU_halt_sys(void); -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG #define HALT_SYS() \ printf("halt_sys: file %s, line %d\n", __FILE__, __LINE__), \ X86EMU_halt_sys() diff --git a/drivers/bios_emulator/include/x86emu/debug.h b/drivers/bios_emulator/include/x86emu/debug.h index 268c9d3..12d6c7f 100644 --- a/drivers/bios_emulator/include/x86emu/debug.h +++ b/drivers/bios_emulator/include/x86emu/debug.h @@ -48,7 +48,7 @@ #define CHECK_MEM_ACCESS_F 0x4 /*using regular linear pointer */ #define CHECK_DATA_ACCESS_F 0x8 /*using segment:offset */ -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG # define CHECK_IP_FETCH() (M.x86.check & CHECK_IP_FETCH_F) # define CHECK_SP_ACCESS() (M.x86.check & CHECK_SP_ACCESS_F) # define CHECK_MEM_ACCESS() (M.x86.check & CHECK_MEM_ACCESS_F) @@ -60,7 +60,7 @@ # define CHECK_DATA_ACCESS() #endif -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG # define DEBUG_INSTRUMENT() (M.x86.debug & DEBUG_INSTRUMENT_F) # define DEBUG_DECODE() (M.x86.debug & DEBUG_DECODE_F) # define DEBUG_TRACE() (M.x86.debug & DEBUG_TRACE_F) @@ -99,7 +99,7 @@ # define DEBUG_DECODE_NOPRINT() 0 #endif -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG # define DECODE_PRINTF(x) if (DEBUG_DECODE()) \ x86emu_decode_printf(x) @@ -129,7 +129,7 @@ # define SAVE_IP_CS(x,y) #endif -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG #define TRACE_REGS() \ if (DEBUG_DISASSEMBLE()) { \ x86emu_just_disassemble(); \ @@ -140,7 +140,7 @@ # define TRACE_REGS() #endif -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG # define SINGLE_STEP() if (DEBUG_STEP()) x86emu_single_step() #else # define SINGLE_STEP() @@ -150,7 +150,7 @@ TRACE_REGS(); \ SINGLE_STEP() -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG # define START_OF_INSTR() # define END_OF_INSTR() EndOfTheInstructionProcedure: x86emu_end_instr(); # define END_OF_INSTR_NO_TRACE() x86emu_end_instr(); @@ -160,7 +160,7 @@ # define END_OF_INSTR_NO_TRACE() #endif -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG # define CALL_TRACE(u,v,w,x,s) \ if (DEBUG_TRACECALLREGS()) \ x86emu_dump_regs(); \ @@ -176,7 +176,7 @@ # define RETURN_TRACE(n,u,v) #endif -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG #define DB(x) x #else #define DB(x) diff --git a/drivers/bios_emulator/include/x86emu/regs.h b/drivers/bios_emulator/include/x86emu/regs.h index a7fedd2..2934129 100644 --- a/drivers/bios_emulator/include/x86emu/regs.h +++ b/drivers/bios_emulator/include/x86emu/regs.h @@ -282,7 +282,7 @@ typedef struct { u8 intno; volatile int intr; /* mask of pending interrupts */ int debug; -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG int check; u16 saved_ip; u16 saved_cs; diff --git a/drivers/bios_emulator/x86emu/debug.c b/drivers/bios_emulator/x86emu/debug.c index 2ec64c2..27e90e4 100644 --- a/drivers/bios_emulator/x86emu/debug.c +++ b/drivers/bios_emulator/x86emu/debug.c @@ -44,7 +44,7 @@ /*----------------------------- Implementation ----------------------------*/ -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG static void print_encoded_bytes(u16 s, u16 o); static void print_decoded_instruction(void); diff --git a/drivers/bios_emulator/x86emu/decode.c b/drivers/bios_emulator/x86emu/decode.c index a782b81..da44c3d 100644 --- a/drivers/bios_emulator/x86emu/decode.c +++ b/drivers/bios_emulator/x86emu/decode.c @@ -303,7 +303,7 @@ NOTE: Do not inline this function as (*sys_rdX) is already inline! u8 fetch_data_byte( uint offset) { -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (CHECK_DATA_ACCESS()) x86emu_check_data_access((u16)get_data_segment(), offset); #endif @@ -322,7 +322,7 @@ NOTE: Do not inline this function as (*sys_rdX) is already inline! u16 fetch_data_word( uint offset) { -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (CHECK_DATA_ACCESS()) x86emu_check_data_access((u16)get_data_segment(), offset); #endif @@ -341,7 +341,7 @@ NOTE: Do not inline this function as (*sys_rdX) is already inline! u32 fetch_data_long( uint offset) { -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (CHECK_DATA_ACCESS()) x86emu_check_data_access((u16)get_data_segment(), offset); #endif @@ -362,7 +362,7 @@ u8 fetch_data_byte_abs( uint segment, uint offset) { -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (CHECK_DATA_ACCESS()) x86emu_check_data_access(segment, offset); #endif @@ -383,7 +383,7 @@ u16 fetch_data_word_abs( uint segment, uint offset) { -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (CHECK_DATA_ACCESS()) x86emu_check_data_access(segment, offset); #endif @@ -404,7 +404,7 @@ u32 fetch_data_long_abs( uint segment, uint offset) { -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (CHECK_DATA_ACCESS()) x86emu_check_data_access(segment, offset); #endif @@ -426,7 +426,7 @@ void store_data_byte( uint offset, u8 val) { -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (CHECK_DATA_ACCESS()) x86emu_check_data_access((u16)get_data_segment(), offset); #endif @@ -448,7 +448,7 @@ void store_data_word( uint offset, u16 val) { -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (CHECK_DATA_ACCESS()) x86emu_check_data_access((u16)get_data_segment(), offset); #endif @@ -470,7 +470,7 @@ void store_data_long( uint offset, u32 val) { -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (CHECK_DATA_ACCESS()) x86emu_check_data_access((u16)get_data_segment(), offset); #endif @@ -493,7 +493,7 @@ void store_data_byte_abs( uint offset, u8 val) { -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (CHECK_DATA_ACCESS()) x86emu_check_data_access(segment, offset); #endif @@ -516,7 +516,7 @@ void store_data_word_abs( uint offset, u16 val) { -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (CHECK_DATA_ACCESS()) x86emu_check_data_access(segment, offset); #endif @@ -539,7 +539,7 @@ void store_data_long_abs( uint offset, u32 val) { -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (CHECK_DATA_ACCESS()) x86emu_check_data_access(segment, offset); #endif diff --git a/drivers/bios_emulator/x86emu/ops.c b/drivers/bios_emulator/x86emu/ops.c index f8e093d..c853260 100644 --- a/drivers/bios_emulator/x86emu/ops.c +++ b/drivers/bios_emulator/x86emu/ops.c @@ -79,7 +79,7 @@ /* constant arrays to do several instructions in just one function */ -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG static char *x86emu_GenOpName[8] = { "ADD", "OR", "ADC", "SBB", "AND", "SUB", "XOR", "CMP"}; #endif @@ -160,7 +160,7 @@ static u32 (*opcD1_long_operation[])(u32 s, u8 d) = sar_long, }; -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG static char *opF6_names[8] = { "TEST\t", "", "NOT\t", "NEG\t", "MUL\t", "IMUL\t", "DIV\t", "IDIV\t" }; @@ -1281,7 +1281,7 @@ void x86emuOp_opc80_byte_RM_IMM(u8 X86EMU_UNUSED(op1)) */ START_OF_INSTR(); FETCH_DECODE_MODRM(mod, rh, rl); -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (DEBUG_DECODE()) { /* XXX DECODE_PRINTF may be changed to something more general, so that it is important to leave the strings @@ -1359,7 +1359,7 @@ void x86emuOp_opc81_word_RM_IMM(u8 X86EMU_UNUSED(op1)) */ START_OF_INSTR(); FETCH_DECODE_MODRM(mod, rh, rl); -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (DEBUG_DECODE()) { /* XXX DECODE_PRINTF may be changed to something more general, so that it is important to leave the strings @@ -1475,7 +1475,7 @@ void x86emuOp_opc82_byte_RM_IMM(u8 X86EMU_UNUSED(op1)) */ START_OF_INSTR(); FETCH_DECODE_MODRM(mod, rh, rl); -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (DEBUG_DECODE()) { /* XXX DECODE_PRINTF may be changed to something more general, so that it is important to leave the strings @@ -1551,7 +1551,7 @@ void x86emuOp_opc83_word_RM_IMM(u8 X86EMU_UNUSED(op1)) */ START_OF_INSTR(); FETCH_DECODE_MODRM(mod, rh, rl); -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (DEBUG_DECODE()) { /* XXX DECODE_PRINTF may be changed to something more general, so that it is important to leave the strings @@ -3083,7 +3083,7 @@ void x86emuOp_opcC0_byte_RM_MEM(u8 X86EMU_UNUSED(op1)) */ START_OF_INSTR(); FETCH_DECODE_MODRM(mod, rh, rl); -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (DEBUG_DECODE()) { /* XXX DECODE_PRINTF may be changed to something more general, so that it is important to leave the strings @@ -3158,7 +3158,7 @@ void x86emuOp_opcC1_word_RM_MEM(u8 X86EMU_UNUSED(op1)) */ START_OF_INSTR(); FETCH_DECODE_MODRM(mod, rh, rl); -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (DEBUG_DECODE()) { /* XXX DECODE_PRINTF may be changed to something more general, so that it is important to leave the strings @@ -3630,7 +3630,7 @@ void x86emuOp_opcD0_byte_RM_1(u8 X86EMU_UNUSED(op1)) */ START_OF_INSTR(); FETCH_DECODE_MODRM(mod, rh, rl); -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (DEBUG_DECODE()) { /* XXX DECODE_PRINTF may be changed to something more general, so that it is important to leave the strings @@ -3701,7 +3701,7 @@ void x86emuOp_opcD1_word_RM_1(u8 X86EMU_UNUSED(op1)) */ START_OF_INSTR(); FETCH_DECODE_MODRM(mod, rh, rl); -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (DEBUG_DECODE()) { /* XXX DECODE_PRINTF may be changed to something more general, so that it is important to leave the strings @@ -3803,7 +3803,7 @@ void x86emuOp_opcD2_byte_RM_CL(u8 X86EMU_UNUSED(op1)) */ START_OF_INSTR(); FETCH_DECODE_MODRM(mod, rh, rl); -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (DEBUG_DECODE()) { /* XXX DECODE_PRINTF may be changed to something more general, so that it is important to leave the strings @@ -3876,7 +3876,7 @@ void x86emuOp_opcD3_word_RM_CL(u8 X86EMU_UNUSED(op1)) */ START_OF_INSTR(); FETCH_DECODE_MODRM(mod, rh, rl); -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (DEBUG_DECODE()) { /* XXX DECODE_PRINTF may be changed to something more general, so that it is important to leave the strings @@ -4859,7 +4859,7 @@ void x86emuOp_opcFE_byte_RM(u8 X86EMU_UNUSED(op1)) /* Yet another special case instruction. */ START_OF_INSTR(); FETCH_DECODE_MODRM(mod, rh, rl); -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (DEBUG_DECODE()) { /* XXX DECODE_PRINTF may be changed to something more general, so that it is important to leave the strings @@ -4923,7 +4923,7 @@ void x86emuOp_opcFF_word_RM(u8 X86EMU_UNUSED(op1)) /* Yet another special case instruction. */ START_OF_INSTR(); FETCH_DECODE_MODRM(mod, rh, rl); -#ifdef DEBUG +#ifdef CONFIG_X86EMU_DEBUG if (DEBUG_DECODE()) { /* XXX DECODE_PRINTF may be changed to something more general, so that it is important to leave the strings -- cgit v0.10.2 From 8c6ec412b450ad790fc373674a34313c8f6e3f6e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:43 -0700 Subject: bios_emulator: Always print errors when opcode decode fails This is a rare event and should not happen. When it does it is confusing to work out why. At least we should print a message. Adjust the emulator to always print decode errors to the console. Signed-off-by: Simon Glass diff --git a/drivers/bios_emulator/include/x86emu/debug.h b/drivers/bios_emulator/include/x86emu/debug.h index 12d6c7f..304b2bf 100644 --- a/drivers/bios_emulator/include/x86emu/debug.h +++ b/drivers/bios_emulator/include/x86emu/debug.h @@ -99,7 +99,11 @@ # define DEBUG_DECODE_NOPRINT() 0 #endif -#ifdef CONFIG_X86EMU_DEBUG +# define ERR_PRINTF(x) printf(x) +# define ERR_PRINTF2(x, y) printf(x, y) + +#ifdef CONFIG_X86EMU_DEBUG103 + # define DECODE_PRINTF(x) if (DEBUG_DECODE()) \ x86emu_decode_printf(x) diff --git a/drivers/bios_emulator/x86emu/ops.c b/drivers/bios_emulator/x86emu/ops.c index c853260..2bb5e2d 100644 --- a/drivers/bios_emulator/x86emu/ops.c +++ b/drivers/bios_emulator/x86emu/ops.c @@ -179,7 +179,7 @@ void x86emuOp_illegal_op( { START_OF_INSTR(); if (M.x86.R_SP != 0) { - DECODE_PRINTF("ILLEGAL X86 OPCODE\n"); + ERR_PRINTF("ILLEGAL X86 OPCODE\n"); TRACE_REGS(); DB( printk("%04x:%04x: %02X ILLEGAL X86 OPCODE!\n", M.x86.R_CS, M.x86.R_IP-1,op1)); @@ -2148,7 +2148,7 @@ void x86emuOp_pop_RM(u8 X86EMU_UNUSED(op1)) DECODE_PRINTF("POP\t"); FETCH_DECODE_MODRM(mod, rh, rl); if (rh != 0) { - DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n"); + ERR_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n"); HALT_SYS(); } if (mod < 3) { @@ -3347,7 +3347,7 @@ void x86emuOp_mov_byte_RM_IMM(u8 X86EMU_UNUSED(op1)) DECODE_PRINTF("MOV\t"); FETCH_DECODE_MODRM(mod, rh, rl); if (rh != 0) { - DECODE_PRINTF("ILLEGAL DECODE OF OPCODE c6\n"); + ERR_PRINTF("ILLEGAL DECODE OF OPCODE c6\n"); HALT_SYS(); } if (mod < 3) { @@ -3381,7 +3381,7 @@ void x86emuOp_mov_word_RM_IMM(u8 X86EMU_UNUSED(op1)) DECODE_PRINTF("MOV\t"); FETCH_DECODE_MODRM(mod, rh, rl); if (rh != 0) { - DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n"); + ERR_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n"); HALT_SYS(); } if (mod < 3) { @@ -3968,7 +3968,7 @@ void x86emuOp_aam(u8 X86EMU_UNUSED(op1)) DECODE_PRINTF("AAM\n"); a = fetch_byte_imm(); /* this is a stupid encoding. */ if (a != 10) { - DECODE_PRINTF("ERROR DECODING AAM\n"); + ERR_PRINTF("ERROR DECODING AAM\n"); TRACE_REGS(); HALT_SYS(); } @@ -4443,7 +4443,7 @@ void x86emuOp_opcF6_byte_RM(u8 X86EMU_UNUSED(op1)) test_byte(destval, srcval); break; case 1: - DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); + ERR_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); HALT_SYS(); break; case 2: @@ -4490,7 +4490,7 @@ void x86emuOp_opcF6_byte_RM(u8 X86EMU_UNUSED(op1)) test_byte(*destreg, srcval); break; case 1: - DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); + ERR_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); HALT_SYS(); break; case 2: @@ -4559,7 +4559,7 @@ void x86emuOp_opcF7_word_RM(u8 X86EMU_UNUSED(op1)) test_long(destval, srcval); break; case 1: - DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n"); + ERR_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n"); HALT_SYS(); break; case 2: @@ -4611,7 +4611,7 @@ void x86emuOp_opcF7_word_RM(u8 X86EMU_UNUSED(op1)) test_word(destval, srcval); break; case 1: - DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n"); + ERR_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n"); HALT_SYS(); break; case 2: @@ -4666,7 +4666,7 @@ void x86emuOp_opcF7_word_RM(u8 X86EMU_UNUSED(op1)) test_long(*destreg, srcval); break; case 1: - DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); + ERR_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); HALT_SYS(); break; case 2: @@ -4715,7 +4715,7 @@ void x86emuOp_opcF7_word_RM(u8 X86EMU_UNUSED(op1)) test_word(*destreg, srcval); break; case 1: - DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); + ERR_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); HALT_SYS(); break; case 2: @@ -4879,7 +4879,7 @@ void x86emuOp_opcFE_byte_RM(u8 X86EMU_UNUSED(op1)) case 5: case 6: case 7: - DECODE_PRINTF2("ILLEGAL OP MAJOR OP 0xFE MINOR OP %x \n", mod); + ERR_PRINTF2("ILLEGAL OP MAJOR OP 0xFE MINOR OP %x\n", mod); HALT_SYS(); break; } @@ -4961,7 +4961,7 @@ void x86emuOp_opcFF_word_RM(u8 X86EMU_UNUSED(op1)) DECODE_PRINTF("PUSH\t"); break; case 7: - DECODE_PRINTF("ILLEGAL DECODING OF OPCODE FF\t"); + ERR_PRINTF("ILLEGAL DECODING OF OPCODE FF\t"); HALT_SYS(); break; } @@ -5092,7 +5092,7 @@ void x86emuOp_opcFF_word_RM(u8 X86EMU_UNUSED(op1)) M.x86.R_IP = *destreg; break; case 3: /* jmp far ptr ... */ - DECODE_PRINTF("OPERATION UNDEFINED 0XFF \n"); + ERR_PRINTF("OPERATION UNDEFINED 0XFF\n"); TRACE_AND_STEP(); HALT_SYS(); break; @@ -5104,7 +5104,7 @@ void x86emuOp_opcFF_word_RM(u8 X86EMU_UNUSED(op1)) M.x86.R_IP = (u16) (*destreg); break; case 5: /* jmp far ptr ... */ - DECODE_PRINTF("OPERATION UNDEFINED 0XFF \n"); + ERR_PRINTF("OPERATION UNDEFINED 0XFF\n"); TRACE_AND_STEP(); HALT_SYS(); break; diff --git a/drivers/bios_emulator/x86emu/ops2.c b/drivers/bios_emulator/x86emu/ops2.c index 59dbb42..be4ef36 100644 --- a/drivers/bios_emulator/x86emu/ops2.c +++ b/drivers/bios_emulator/x86emu/ops2.c @@ -58,7 +58,7 @@ void x86emuOp2_illegal_op( u8 op2) { START_OF_INSTR(); - DECODE_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n"); + ERR_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n"); TRACE_REGS(); printk("%04x:%04x: %02X ILLEGAL EXTENDED X86 OPCODE!\n", M.x86.R_CS, M.x86.R_IP-2,op2); @@ -1089,7 +1089,7 @@ void x86emuOp2_btX_I(u8 X86EMU_UNUSED(op2)) DECODE_PRINTF("BTC\t"); break; default: - DECODE_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n"); + ERR_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n"); TRACE_REGS(); printk("%04x:%04x: %02X%02X ILLEGAL EXTENDED X86 OPCODE EXTENSION!\n", M.x86.R_CS, M.x86.R_IP-3,op2, (mod<<6)|(rh<<3)|rl); -- cgit v0.10.2 From a6fa83f0e7ac669d4ecab8b64fe5b9fb051b6e72 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:44 -0700 Subject: x86: chromebook_link: Enable the x86 emulator Enable this so that it can be used instead of native execution if desired. Signed-off-by: Simon Glass diff --git a/include/configs/chromebook_link.h b/include/configs/chromebook_link.h index c098c6c..48ae81e 100644 --- a/include/configs/chromebook_link.h +++ b/include/configs/chromebook_link.h @@ -58,6 +58,10 @@ #define CONFIG_SYS_EARLY_PCI_INIT #define CONFIG_PCI_PNP +#define CONFIG_BIOSEMU +#define VIDEO_IO_OFFSET 0 +#define CONFIG_X86EMU_RAW_IO + #define CONFIG_STD_DEVICES_SETTINGS "stdin=usbkbd,vga,serial\0" \ "stdout=vga,serial\0" \ "stderr=vga,serial\0" -- cgit v0.10.2 From 22e131ca00ed42cd7485aa1821dc3051bd762a3e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 14 Nov 2014 20:56:45 -0700 Subject: x86: chromebook_link: Enable the Chrome OS EC Enable the Chrome OS EC so that it can be used from U-Boot. Signed-off-by: Simon Glass diff --git a/board/google/chromebook_link/link.c b/board/google/chromebook_link/link.c index 0a1ae61..1822237 100644 --- a/board/google/chromebook_link/link.c +++ b/board/google/chromebook_link/link.c @@ -5,10 +5,14 @@ */ #include +#include #include int arch_early_init_r(void) { + if (cros_ec_board_init()) + return -1; + return 0; } diff --git a/include/configs/chromebook_link.h b/include/configs/chromebook_link.h index 48ae81e..645b31c 100644 --- a/include/configs/chromebook_link.h +++ b/include/configs/chromebook_link.h @@ -62,6 +62,11 @@ #define VIDEO_IO_OFFSET 0 #define CONFIG_X86EMU_RAW_IO +#define CONFIG_CROS_EC +#define CONFIG_CROS_EC_LPC +#define CONFIG_CMD_CROS_EC +#define CONFIG_ARCH_EARLY_INIT_R + #define CONFIG_STD_DEVICES_SETTINGS "stdin=usbkbd,vga,serial\0" \ "stdout=vga,serial\0" \ "stderr=vga,serial\0" -- cgit v0.10.2 From 908ec6e4d1d12f746cb9b7cc73430a268ceb2c92 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 25 Nov 2014 10:20:08 +0800 Subject: tools: Add ifdtool to .gitignore Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/tools/.gitignore b/tools/.gitignore index e7f0f8f..9bc9fec 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -4,6 +4,7 @@ /fit_check_sign /fit_info /gen_eth_addr +/ifdtool /img2srec /kwboot /dumpimage -- cgit v0.10.2