1b2e02d28SBin Meng /* 2b2e02d28SBin Meng * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com> 3b2e02d28SBin Meng * 4b2e02d28SBin Meng * SPDX-License-Identifier: GPL-2.0+ 5b2e02d28SBin Meng */ 6b2e02d28SBin Meng 7b2e02d28SBin Meng #include <common.h> 8b2e02d28SBin Meng #include <asm/io.h> 99c7dea60SBin Meng #include <asm/irq.h> 10adfe3b24SBin Meng #include <asm/pci.h> 11b2e02d28SBin Meng #include <asm/post.h> 12afbf1404SBin Meng #include <asm/arch/device.h> 139c7dea60SBin Meng #include <asm/arch/tnc.h> 141021af4dSSimon Glass #include <asm/fsp/fsp_support.h> 15b2e02d28SBin Meng #include <asm/processor.h> 16b2e02d28SBin Meng 17adfe3b24SBin Meng static void unprotect_spi_flash(void) 18adfe3b24SBin Meng { 19adfe3b24SBin Meng u32 bc; 20adfe3b24SBin Meng 219704f23bSBin Meng bc = x86_pci_read_config32(TNC_LPC, 0xd8); 22adfe3b24SBin Meng bc |= 0x1; /* unprotect the flash */ 239704f23bSBin Meng x86_pci_write_config32(TNC_LPC, 0xd8, bc); 24adfe3b24SBin Meng } 25adfe3b24SBin Meng 261f124ebaSBin Meng static void __maybe_unused disable_igd(void) 271f124ebaSBin Meng { 28*e5ffa4bbSBin Meng /* 29*e5ffa4bbSBin Meng * According to Atom E6xx datasheet, setting VGA Disable (bit17) 30*e5ffa4bbSBin Meng * of Graphics Controller register (offset 0x50) prevents IGD 31*e5ffa4bbSBin Meng * (D2:F0) from reporting itself as a VGA display controller 32*e5ffa4bbSBin Meng * class in the PCI configuration space, and should also prevent 33*e5ffa4bbSBin Meng * it from responding to VGA legacy memory range and I/O addresses. 34*e5ffa4bbSBin Meng * 35*e5ffa4bbSBin Meng * However test result shows that with just VGA Disable bit set and 36*e5ffa4bbSBin Meng * a PCIe graphics card connected to one of the PCIe controllers on 37*e5ffa4bbSBin Meng * the E6xx, accessing the VGA legacy space still causes system hang. 38*e5ffa4bbSBin Meng * After a number of attempts, it turns out besides VGA Disable bit, 39*e5ffa4bbSBin Meng * the SDVO (D3:F0) device should be disabled to make it work. 40*e5ffa4bbSBin Meng * 41*e5ffa4bbSBin Meng * To simplify, use the Function Disable register (offset 0xc4) 42*e5ffa4bbSBin Meng * to disable both IGD (D2:F0) and SDVO (D3:F0) devices. Now these 43*e5ffa4bbSBin Meng * two devices will be completely disabled (invisible in the PCI 44*e5ffa4bbSBin Meng * configuration space) unless a system reset is performed. 45*e5ffa4bbSBin Meng */ 46*e5ffa4bbSBin Meng x86_pci_write_config32(TNC_IGD, IGD_FD, FUNC_DISABLE); 47*e5ffa4bbSBin Meng x86_pci_write_config32(TNC_SDVO, IGD_FD, FUNC_DISABLE); 481f124ebaSBin Meng } 491f124ebaSBin Meng 50b2e02d28SBin Meng int arch_cpu_init(void) 51b2e02d28SBin Meng { 52adfe3b24SBin Meng int ret; 53adfe3b24SBin Meng 54b2e02d28SBin Meng post_code(POST_CPU_INIT); 55b2e02d28SBin Meng #ifdef CONFIG_SYS_X86_TSC_TIMER 56b2e02d28SBin Meng timer_set_base(rdtsc()); 57b2e02d28SBin Meng #endif 58b2e02d28SBin Meng 59adfe3b24SBin Meng ret = x86_cpu_init_f(); 60adfe3b24SBin Meng if (ret) 61adfe3b24SBin Meng return ret; 62adfe3b24SBin Meng 63adfe3b24SBin Meng return 0; 64b2e02d28SBin Meng } 65afbf1404SBin Meng 661f124ebaSBin Meng int arch_early_init_r(void) 671f124ebaSBin Meng { 681f124ebaSBin Meng #ifdef CONFIG_DISABLE_IGD 691f124ebaSBin Meng disable_igd(); 701f124ebaSBin Meng #endif 711f124ebaSBin Meng 721f124ebaSBin Meng return 0; 731f124ebaSBin Meng } 741f124ebaSBin Meng 759c7dea60SBin Meng void cpu_irq_init(void) 769c7dea60SBin Meng { 779c7dea60SBin Meng struct tnc_rcba *rcba; 789c7dea60SBin Meng u32 base; 799c7dea60SBin Meng 809c7dea60SBin Meng base = x86_pci_read_config32(TNC_LPC, LPC_RCBA); 819c7dea60SBin Meng base &= ~MEM_BAR_EN; 829c7dea60SBin Meng rcba = (struct tnc_rcba *)base; 839c7dea60SBin Meng 849c7dea60SBin Meng /* Make sure all internal PCI devices are using INTA */ 859c7dea60SBin Meng writel(INTA, &rcba->d02ip); 869c7dea60SBin Meng writel(INTA, &rcba->d03ip); 879c7dea60SBin Meng writel(INTA, &rcba->d27ip); 889c7dea60SBin Meng writel(INTA, &rcba->d31ip); 899c7dea60SBin Meng writel(INTA, &rcba->d23ip); 909c7dea60SBin Meng writel(INTA, &rcba->d24ip); 919c7dea60SBin Meng writel(INTA, &rcba->d25ip); 929c7dea60SBin Meng writel(INTA, &rcba->d26ip); 939c7dea60SBin Meng 949c7dea60SBin Meng /* 959c7dea60SBin Meng * Route TunnelCreek PCI device interrupt pin to PIRQ 969c7dea60SBin Meng * 979c7dea60SBin Meng * Since PCIe downstream ports received INTx are routed to PIRQ 98cdb6babeSBin Meng * A/B/C/D directly and not configurable, we have to route PCIe 99cdb6babeSBin Meng * root ports' INTx to PIRQ A/B/C/D as well. For other devices 100cdb6babeSBin Meng * on TunneCreek, route them to PIRQ E/F/G/H. 1019c7dea60SBin Meng */ 1029c7dea60SBin Meng writew(PIRQE, &rcba->d02ir); 1039c7dea60SBin Meng writew(PIRQF, &rcba->d03ir); 1049c7dea60SBin Meng writew(PIRQG, &rcba->d27ir); 1059c7dea60SBin Meng writew(PIRQH, &rcba->d31ir); 106cdb6babeSBin Meng writew(PIRQA, &rcba->d23ir); 107cdb6babeSBin Meng writew(PIRQB, &rcba->d24ir); 108cdb6babeSBin Meng writew(PIRQC, &rcba->d25ir); 109cdb6babeSBin Meng writew(PIRQD, &rcba->d26ir); 1109c7dea60SBin Meng } 1119c7dea60SBin Meng 112afbf1404SBin Meng int arch_misc_init(void) 113afbf1404SBin Meng { 114090290f9SBin Meng unprotect_spi_flash(); 115090290f9SBin Meng 1167e4be120SSimon Glass return pirq_init(); 117afbf1404SBin Meng } 118