12b605154SSimon Glass /* 22b605154SSimon Glass * From coreboot southbridge/intel/bd82x6x/lpc.c 32b605154SSimon Glass * 42b605154SSimon Glass * Copyright (C) 2008-2009 coresystems GmbH 52b605154SSimon Glass * 62b605154SSimon Glass * SPDX-License-Identifier: GPL-2.0 72b605154SSimon Glass */ 82b605154SSimon Glass 92b605154SSimon Glass #include <common.h> 10aad78d27SSimon Glass #include <dm.h> 112b605154SSimon Glass #include <errno.h> 122b605154SSimon Glass #include <fdtdec.h> 1372cd085aSSimon Glass #include <rtc.h> 142b605154SSimon Glass #include <pci.h> 15bb096b9fSSimon Glass #include <asm/intel_regs.h> 1672cd085aSSimon Glass #include <asm/interrupt.h> 1772cd085aSSimon Glass #include <asm/io.h> 1872cd085aSSimon Glass #include <asm/ioapic.h> 198c30b571SSimon Glass #include <asm/lpc_common.h> 202b605154SSimon Glass #include <asm/pci.h> 212b605154SSimon Glass #include <asm/arch/pch.h> 222b605154SSimon Glass 2372cd085aSSimon Glass #define NMI_OFF 0 2472cd085aSSimon Glass 2572cd085aSSimon Glass #define ENABLE_ACPI_MODE_IN_COREBOOT 0 2672cd085aSSimon Glass #define TEST_SMM_FLASH_LOCKDOWN 0 2772cd085aSSimon Glass 284265abd4SSimon Glass static int pch_enable_apic(struct udevice *pch) 2972cd085aSSimon Glass { 3072cd085aSSimon Glass u32 reg32; 3172cd085aSSimon Glass int i; 3272cd085aSSimon Glass 3372cd085aSSimon Glass /* Enable ACPI I/O and power management. Set SCI IRQ to IRQ9 */ 344265abd4SSimon Glass dm_pci_write_config8(pch, ACPI_CNTL, 0x80); 3572cd085aSSimon Glass 3672cd085aSSimon Glass writel(0, IO_APIC_INDEX); 3772cd085aSSimon Glass writel(1 << 25, IO_APIC_DATA); 3872cd085aSSimon Glass 3972cd085aSSimon Glass /* affirm full set of redirection table entries ("write once") */ 4072cd085aSSimon Glass writel(1, IO_APIC_INDEX); 4172cd085aSSimon Glass reg32 = readl(IO_APIC_DATA); 4272cd085aSSimon Glass writel(1, IO_APIC_INDEX); 4372cd085aSSimon Glass writel(reg32, IO_APIC_DATA); 4472cd085aSSimon Glass 4572cd085aSSimon Glass writel(0, IO_APIC_INDEX); 4672cd085aSSimon Glass reg32 = readl(IO_APIC_DATA); 4772cd085aSSimon Glass debug("PCH APIC ID = %x\n", (reg32 >> 24) & 0x0f); 4872cd085aSSimon Glass if (reg32 != (1 << 25)) { 4972cd085aSSimon Glass printf("APIC Error - cannot write to registers\n"); 5072cd085aSSimon Glass return -EPERM; 5172cd085aSSimon Glass } 5272cd085aSSimon Glass 5372cd085aSSimon Glass debug("Dumping IOAPIC registers\n"); 5472cd085aSSimon Glass for (i = 0; i < 3; i++) { 5572cd085aSSimon Glass writel(i, IO_APIC_INDEX); 5672cd085aSSimon Glass debug(" reg 0x%04x:", i); 5772cd085aSSimon Glass reg32 = readl(IO_APIC_DATA); 5872cd085aSSimon Glass debug(" 0x%08x\n", reg32); 5972cd085aSSimon Glass } 6072cd085aSSimon Glass 6172cd085aSSimon Glass /* Select Boot Configuration register. */ 6272cd085aSSimon Glass writel(3, IO_APIC_INDEX); 6372cd085aSSimon Glass 6472cd085aSSimon Glass /* Use Processor System Bus to deliver interrupts. */ 6572cd085aSSimon Glass writel(1, IO_APIC_DATA); 6672cd085aSSimon Glass 6772cd085aSSimon Glass return 0; 6872cd085aSSimon Glass } 6972cd085aSSimon Glass 704265abd4SSimon Glass static void pch_enable_serial_irqs(struct udevice *pch) 7172cd085aSSimon Glass { 7272cd085aSSimon Glass u32 value; 7372cd085aSSimon Glass 7472cd085aSSimon Glass /* Set packet length and toggle silent mode bit for one frame. */ 7572cd085aSSimon Glass value = (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0); 7672cd085aSSimon Glass #ifdef CONFIG_SERIRQ_CONTINUOUS_MODE 774265abd4SSimon Glass dm_pci_write_config8(pch, SERIRQ_CNTL, value); 7872cd085aSSimon Glass #else 794265abd4SSimon Glass dm_pci_write_config8(pch, SERIRQ_CNTL, value | (1 << 6)); 8072cd085aSSimon Glass #endif 8172cd085aSSimon Glass } 8272cd085aSSimon Glass 834265abd4SSimon Glass static int pch_pirq_init(struct udevice *pch) 8472cd085aSSimon Glass { 8572cd085aSSimon Glass uint8_t route[8], *ptr; 8672cd085aSSimon Glass 874265abd4SSimon Glass if (fdtdec_get_byte_array(gd->fdt_blob, pch->of_offset, 884265abd4SSimon Glass "intel,pirq-routing", route, sizeof(route))) 8972cd085aSSimon Glass return -EINVAL; 9072cd085aSSimon Glass ptr = route; 914265abd4SSimon Glass dm_pci_write_config8(pch, PIRQA_ROUT, *ptr++); 924265abd4SSimon Glass dm_pci_write_config8(pch, PIRQB_ROUT, *ptr++); 934265abd4SSimon Glass dm_pci_write_config8(pch, PIRQC_ROUT, *ptr++); 944265abd4SSimon Glass dm_pci_write_config8(pch, PIRQD_ROUT, *ptr++); 9572cd085aSSimon Glass 964265abd4SSimon Glass dm_pci_write_config8(pch, PIRQE_ROUT, *ptr++); 974265abd4SSimon Glass dm_pci_write_config8(pch, PIRQF_ROUT, *ptr++); 984265abd4SSimon Glass dm_pci_write_config8(pch, PIRQG_ROUT, *ptr++); 994265abd4SSimon Glass dm_pci_write_config8(pch, PIRQH_ROUT, *ptr++); 10072cd085aSSimon Glass 10172cd085aSSimon Glass /* 10272cd085aSSimon Glass * TODO(sjg@chromium.org): U-Boot does not set up the interrupts 10372cd085aSSimon Glass * here. It's unclear if it is needed 10472cd085aSSimon Glass */ 10572cd085aSSimon Glass return 0; 10672cd085aSSimon Glass } 10772cd085aSSimon Glass 1084265abd4SSimon Glass static int pch_gpi_routing(struct udevice *pch) 10972cd085aSSimon Glass { 11072cd085aSSimon Glass u8 route[16]; 11172cd085aSSimon Glass u32 reg; 11272cd085aSSimon Glass int gpi; 11372cd085aSSimon Glass 1144265abd4SSimon Glass if (fdtdec_get_byte_array(gd->fdt_blob, pch->of_offset, 1154265abd4SSimon Glass "intel,gpi-routing", route, sizeof(route))) 11672cd085aSSimon Glass return -EINVAL; 11772cd085aSSimon Glass 11872cd085aSSimon Glass for (reg = 0, gpi = 0; gpi < ARRAY_SIZE(route); gpi++) 11972cd085aSSimon Glass reg |= route[gpi] << (gpi * 2); 12072cd085aSSimon Glass 1214265abd4SSimon Glass dm_pci_write_config32(pch, 0xb8, reg); 12272cd085aSSimon Glass 12372cd085aSSimon Glass return 0; 12472cd085aSSimon Glass } 12572cd085aSSimon Glass 1264265abd4SSimon Glass static int pch_power_options(struct udevice *pch) 12772cd085aSSimon Glass { 1284265abd4SSimon Glass const void *blob = gd->fdt_blob; 1294265abd4SSimon Glass int node = pch->of_offset; 13072cd085aSSimon Glass u8 reg8; 13172cd085aSSimon Glass u16 reg16, pmbase; 13272cd085aSSimon Glass u32 reg32; 13372cd085aSSimon Glass const char *state; 13472cd085aSSimon Glass int pwr_on; 13572cd085aSSimon Glass int nmi_option; 13672cd085aSSimon Glass int ret; 13772cd085aSSimon Glass 13872cd085aSSimon Glass /* 13972cd085aSSimon Glass * Which state do we want to goto after g3 (power restored)? 14072cd085aSSimon Glass * 0 == S0 Full On 14172cd085aSSimon Glass * 1 == S5 Soft Off 14272cd085aSSimon Glass * 14372cd085aSSimon Glass * If the option is not existent (Laptops), use Kconfig setting. 14472cd085aSSimon Glass * TODO(sjg@chromium.org): Make this configurable 14572cd085aSSimon Glass */ 14672cd085aSSimon Glass pwr_on = MAINBOARD_POWER_ON; 14772cd085aSSimon Glass 1484265abd4SSimon Glass dm_pci_read_config16(pch, GEN_PMCON_3, ®16); 14972cd085aSSimon Glass reg16 &= 0xfffe; 15072cd085aSSimon Glass switch (pwr_on) { 15172cd085aSSimon Glass case MAINBOARD_POWER_OFF: 15272cd085aSSimon Glass reg16 |= 1; 15372cd085aSSimon Glass state = "off"; 15472cd085aSSimon Glass break; 15572cd085aSSimon Glass case MAINBOARD_POWER_ON: 15672cd085aSSimon Glass reg16 &= ~1; 15772cd085aSSimon Glass state = "on"; 15872cd085aSSimon Glass break; 15972cd085aSSimon Glass case MAINBOARD_POWER_KEEP: 16072cd085aSSimon Glass reg16 &= ~1; 16172cd085aSSimon Glass state = "state keep"; 16272cd085aSSimon Glass break; 16372cd085aSSimon Glass default: 16472cd085aSSimon Glass state = "undefined"; 16572cd085aSSimon Glass } 16672cd085aSSimon Glass 16772cd085aSSimon Glass reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */ 16872cd085aSSimon Glass reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */ 16972cd085aSSimon Glass 17072cd085aSSimon Glass reg16 &= ~(1 << 10); 17172cd085aSSimon Glass reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */ 17272cd085aSSimon Glass 17372cd085aSSimon Glass reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */ 17472cd085aSSimon Glass 1754265abd4SSimon Glass dm_pci_write_config16(pch, GEN_PMCON_3, reg16); 17672cd085aSSimon Glass debug("Set power %s after power failure.\n", state); 17772cd085aSSimon Glass 17872cd085aSSimon Glass /* Set up NMI on errors. */ 17972cd085aSSimon Glass reg8 = inb(0x61); 18072cd085aSSimon Glass reg8 &= 0x0f; /* Higher Nibble must be 0 */ 18172cd085aSSimon Glass reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */ 18272cd085aSSimon Glass reg8 |= (1 << 2); /* PCI SERR# Disable for now */ 18372cd085aSSimon Glass outb(reg8, 0x61); 18472cd085aSSimon Glass 18572cd085aSSimon Glass reg8 = inb(0x70); 18672cd085aSSimon Glass /* TODO(sjg@chromium.org): Make this configurable */ 18772cd085aSSimon Glass nmi_option = NMI_OFF; 18872cd085aSSimon Glass if (nmi_option) { 18972cd085aSSimon Glass debug("NMI sources enabled.\n"); 19072cd085aSSimon Glass reg8 &= ~(1 << 7); /* Set NMI. */ 19172cd085aSSimon Glass } else { 19272cd085aSSimon Glass debug("NMI sources disabled.\n"); 19372cd085aSSimon Glass /* Can't mask NMI from PCI-E and NMI_NOW */ 19472cd085aSSimon Glass reg8 |= (1 << 7); 19572cd085aSSimon Glass } 19672cd085aSSimon Glass outb(reg8, 0x70); 19772cd085aSSimon Glass 19872cd085aSSimon Glass /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */ 1994265abd4SSimon Glass dm_pci_read_config16(pch, GEN_PMCON_1, ®16); 20072cd085aSSimon Glass reg16 &= ~(3 << 0); /* SMI# rate 1 minute */ 20172cd085aSSimon Glass reg16 &= ~(1 << 10); /* Disable BIOS_PCI_EXP_EN for native PME */ 20272cd085aSSimon Glass #if DEBUG_PERIODIC_SMIS 20372cd085aSSimon Glass /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using periodic SMIs */ 20472cd085aSSimon Glass reg16 |= (3 << 0); /* Periodic SMI every 8s */ 20572cd085aSSimon Glass #endif 2064265abd4SSimon Glass dm_pci_write_config16(pch, GEN_PMCON_1, reg16); 20772cd085aSSimon Glass 20872cd085aSSimon Glass /* Set the board's GPI routing. */ 2094265abd4SSimon Glass ret = pch_gpi_routing(pch); 21072cd085aSSimon Glass if (ret) 21172cd085aSSimon Glass return ret; 21272cd085aSSimon Glass 2134265abd4SSimon Glass dm_pci_read_config16(pch, 0x40, &pmbase); 2144265abd4SSimon Glass pmbase &= 0xfffe; 21572cd085aSSimon Glass 216*4e0318c3SSimon Glass writel(fdtdec_get_int(blob, node, "intel,gpe0-enable", 0), 217*4e0318c3SSimon Glass (ulong)pmbase + GPE0_EN); 218*4e0318c3SSimon Glass writew(fdtdec_get_int(blob, node, "intel,alt-gp-smi-enable", 0), 219*4e0318c3SSimon Glass (ulong)pmbase + ALT_GP_SMI_EN); 22072cd085aSSimon Glass 22172cd085aSSimon Glass /* Set up power management block and determine sleep mode */ 22272cd085aSSimon Glass reg32 = inl(pmbase + 0x04); /* PM1_CNT */ 22372cd085aSSimon Glass reg32 &= ~(7 << 10); /* SLP_TYP */ 22472cd085aSSimon Glass reg32 |= (1 << 0); /* SCI_EN */ 22572cd085aSSimon Glass outl(reg32, pmbase + 0x04); 22672cd085aSSimon Glass 22772cd085aSSimon Glass /* Clear magic status bits to prevent unexpected wake */ 22872cd085aSSimon Glass setbits_le32(RCB_REG(0x3310), (1 << 4) | (1 << 5) | (1 << 0)); 22972cd085aSSimon Glass clrbits_le32(RCB_REG(0x3f02), 0xf); 23072cd085aSSimon Glass 23172cd085aSSimon Glass return 0; 23272cd085aSSimon Glass } 23372cd085aSSimon Glass 2344265abd4SSimon Glass static void pch_rtc_init(struct udevice *pch) 23572cd085aSSimon Glass { 23672cd085aSSimon Glass int rtc_failed; 23772cd085aSSimon Glass u8 reg8; 23872cd085aSSimon Glass 2394265abd4SSimon Glass dm_pci_read_config8(pch, GEN_PMCON_3, ®8); 24072cd085aSSimon Glass rtc_failed = reg8 & RTC_BATTERY_DEAD; 24172cd085aSSimon Glass if (rtc_failed) { 24272cd085aSSimon Glass reg8 &= ~RTC_BATTERY_DEAD; 2434265abd4SSimon Glass dm_pci_write_config8(pch, GEN_PMCON_3, reg8); 24472cd085aSSimon Glass } 24572cd085aSSimon Glass debug("rtc_failed = 0x%x\n", rtc_failed); 24672cd085aSSimon Glass 24772cd085aSSimon Glass /* TODO: Handle power failure */ 24872cd085aSSimon Glass if (rtc_failed) 24972cd085aSSimon Glass printf("RTC power failed\n"); 25072cd085aSSimon Glass } 25172cd085aSSimon Glass 25272cd085aSSimon Glass /* CougarPoint PCH Power Management init */ 2534265abd4SSimon Glass static void cpt_pm_init(struct udevice *pch) 25472cd085aSSimon Glass { 25572cd085aSSimon Glass debug("CougarPoint PM init\n"); 2564265abd4SSimon Glass dm_pci_write_config8(pch, 0xa9, 0x47); 25772cd085aSSimon Glass setbits_le32(RCB_REG(0x2238), (1 << 6) | (1 << 0)); 25872cd085aSSimon Glass 25972cd085aSSimon Glass setbits_le32(RCB_REG(0x228c), 1 << 0); 26072cd085aSSimon Glass setbits_le32(RCB_REG(0x1100), (1 << 13) | (1 << 14)); 26172cd085aSSimon Glass setbits_le32(RCB_REG(0x0900), 1 << 14); 26272cd085aSSimon Glass writel(0xc0388400, RCB_REG(0x2304)); 26372cd085aSSimon Glass setbits_le32(RCB_REG(0x2314), (1 << 5) | (1 << 18)); 26472cd085aSSimon Glass setbits_le32(RCB_REG(0x2320), (1 << 15) | (1 << 1)); 26572cd085aSSimon Glass clrsetbits_le32(RCB_REG(0x3314), ~0x1f, 0xf); 26672cd085aSSimon Glass writel(0x050f0000, RCB_REG(0x3318)); 26772cd085aSSimon Glass writel(0x04000000, RCB_REG(0x3324)); 26872cd085aSSimon Glass setbits_le32(RCB_REG(0x3340), 0xfffff); 26972cd085aSSimon Glass setbits_le32(RCB_REG(0x3344), 1 << 1); 27072cd085aSSimon Glass 27172cd085aSSimon Glass writel(0x0001c000, RCB_REG(0x3360)); 27272cd085aSSimon Glass writel(0x00061100, RCB_REG(0x3368)); 27372cd085aSSimon Glass writel(0x7f8fdfff, RCB_REG(0x3378)); 27472cd085aSSimon Glass writel(0x000003fc, RCB_REG(0x337c)); 27572cd085aSSimon Glass writel(0x00001000, RCB_REG(0x3388)); 27672cd085aSSimon Glass writel(0x0001c000, RCB_REG(0x3390)); 27772cd085aSSimon Glass writel(0x00000800, RCB_REG(0x33a0)); 27872cd085aSSimon Glass writel(0x00001000, RCB_REG(0x33b0)); 27972cd085aSSimon Glass writel(0x00093900, RCB_REG(0x33c0)); 28072cd085aSSimon Glass writel(0x24653002, RCB_REG(0x33cc)); 28172cd085aSSimon Glass writel(0x062108fe, RCB_REG(0x33d0)); 28272cd085aSSimon Glass clrsetbits_le32(RCB_REG(0x33d4), 0x0fff0fff, 0x00670060); 28372cd085aSSimon Glass writel(0x01010000, RCB_REG(0x3a28)); 28472cd085aSSimon Glass writel(0x01010404, RCB_REG(0x3a2c)); 28572cd085aSSimon Glass writel(0x01041041, RCB_REG(0x3a80)); 28672cd085aSSimon Glass clrsetbits_le32(RCB_REG(0x3a84), 0x0000ffff, 0x00001001); 28772cd085aSSimon Glass setbits_le32(RCB_REG(0x3a84), 1 << 24); /* SATA 2/3 disabled */ 28872cd085aSSimon Glass setbits_le32(RCB_REG(0x3a88), 1 << 0); /* SATA 4/5 disabled */ 28972cd085aSSimon Glass writel(0x00000001, RCB_REG(0x3a6c)); 29072cd085aSSimon Glass clrsetbits_le32(RCB_REG(0x2344), ~0x00ffff00, 0xff00000c); 29172cd085aSSimon Glass clrsetbits_le32(RCB_REG(0x80c), 0xff << 20, 0x11 << 20); 29272cd085aSSimon Glass writel(0, RCB_REG(0x33c8)); 29372cd085aSSimon Glass setbits_le32(RCB_REG(0x21b0), 0xf); 29472cd085aSSimon Glass } 29572cd085aSSimon Glass 29672cd085aSSimon Glass /* PantherPoint PCH Power Management init */ 2974265abd4SSimon Glass static void ppt_pm_init(struct udevice *pch) 29872cd085aSSimon Glass { 29972cd085aSSimon Glass debug("PantherPoint PM init\n"); 3004265abd4SSimon Glass dm_pci_write_config8(pch, 0xa9, 0x47); 30172cd085aSSimon Glass setbits_le32(RCB_REG(0x2238), 1 << 0); 30272cd085aSSimon Glass setbits_le32(RCB_REG(0x228c), 1 << 0); 30372cd085aSSimon Glass setbits_le16(RCB_REG(0x1100), (1 << 13) | (1 << 14)); 30472cd085aSSimon Glass setbits_le16(RCB_REG(0x0900), 1 << 14); 30572cd085aSSimon Glass writel(0xc03b8400, RCB_REG(0x2304)); 30672cd085aSSimon Glass setbits_le32(RCB_REG(0x2314), (1 << 5) | (1 << 18)); 30772cd085aSSimon Glass setbits_le32(RCB_REG(0x2320), (1 << 15) | (1 << 1)); 30872cd085aSSimon Glass clrsetbits_le32(RCB_REG(0x3314), 0x1f, 0xf); 30972cd085aSSimon Glass writel(0x054f0000, RCB_REG(0x3318)); 31072cd085aSSimon Glass writel(0x04000000, RCB_REG(0x3324)); 31172cd085aSSimon Glass setbits_le32(RCB_REG(0x3340), 0xfffff); 31272cd085aSSimon Glass setbits_le32(RCB_REG(0x3344), (1 << 1) | (1 << 0)); 31372cd085aSSimon Glass writel(0x0001c000, RCB_REG(0x3360)); 31472cd085aSSimon Glass writel(0x00061100, RCB_REG(0x3368)); 31572cd085aSSimon Glass writel(0x7f8fdfff, RCB_REG(0x3378)); 31672cd085aSSimon Glass writel(0x000003fd, RCB_REG(0x337c)); 31772cd085aSSimon Glass writel(0x00001000, RCB_REG(0x3388)); 31872cd085aSSimon Glass writel(0x0001c000, RCB_REG(0x3390)); 31972cd085aSSimon Glass writel(0x00000800, RCB_REG(0x33a0)); 32072cd085aSSimon Glass writel(0x00001000, RCB_REG(0x33b0)); 32172cd085aSSimon Glass writel(0x00093900, RCB_REG(0x33c0)); 32272cd085aSSimon Glass writel(0x24653002, RCB_REG(0x33cc)); 32372cd085aSSimon Glass writel(0x067388fe, RCB_REG(0x33d0)); 32472cd085aSSimon Glass clrsetbits_le32(RCB_REG(0x33d4), 0x0fff0fff, 0x00670060); 32572cd085aSSimon Glass writel(0x01010000, RCB_REG(0x3a28)); 32672cd085aSSimon Glass writel(0x01010404, RCB_REG(0x3a2c)); 32772cd085aSSimon Glass writel(0x01040000, RCB_REG(0x3a80)); 32872cd085aSSimon Glass clrsetbits_le32(RCB_REG(0x3a84), 0x0000ffff, 0x00001001); 32972cd085aSSimon Glass /* SATA 2/3 disabled */ 33072cd085aSSimon Glass setbits_le32(RCB_REG(0x3a84), 1 << 24); 33172cd085aSSimon Glass /* SATA 4/5 disabled */ 33272cd085aSSimon Glass setbits_le32(RCB_REG(0x3a88), 1 << 0); 33372cd085aSSimon Glass writel(0x00000001, RCB_REG(0x3a6c)); 33472cd085aSSimon Glass clrsetbits_le32(RCB_REG(0x2344), 0xff0000ff, 0xff00000c); 33572cd085aSSimon Glass clrsetbits_le32(RCB_REG(0x80c), 0xff << 20, 0x11 << 20); 33672cd085aSSimon Glass setbits_le32(RCB_REG(0x33a4), (1 << 0)); 33772cd085aSSimon Glass writel(0, RCB_REG(0x33c8)); 33872cd085aSSimon Glass setbits_le32(RCB_REG(0x21b0), 0xf); 33972cd085aSSimon Glass } 34072cd085aSSimon Glass 34172cd085aSSimon Glass static void enable_hpet(void) 34272cd085aSSimon Glass { 34372cd085aSSimon Glass /* Move HPET to default address 0xfed00000 and enable it */ 34472cd085aSSimon Glass clrsetbits_le32(RCB_REG(HPTC), 3 << 0, 1 << 7); 34572cd085aSSimon Glass } 34672cd085aSSimon Glass 3474265abd4SSimon Glass static void enable_clock_gating(struct udevice *pch) 34872cd085aSSimon Glass { 34972cd085aSSimon Glass u32 reg32; 35072cd085aSSimon Glass u16 reg16; 35172cd085aSSimon Glass 35272cd085aSSimon Glass setbits_le32(RCB_REG(0x2234), 0xf); 35372cd085aSSimon Glass 3544265abd4SSimon Glass dm_pci_read_config16(pch, GEN_PMCON_1, ®16); 35572cd085aSSimon Glass reg16 |= (1 << 2) | (1 << 11); 3564265abd4SSimon Glass dm_pci_write_config16(pch, GEN_PMCON_1, reg16); 35772cd085aSSimon Glass 3589434c7a3SSimon Glass pch_iobp_update(pch, 0xEB007F07, ~0UL, (1 << 31)); 3599434c7a3SSimon Glass pch_iobp_update(pch, 0xEB004000, ~0UL, (1 << 7)); 3609434c7a3SSimon Glass pch_iobp_update(pch, 0xEC007F07, ~0UL, (1 << 31)); 3619434c7a3SSimon Glass pch_iobp_update(pch, 0xEC004000, ~0UL, (1 << 7)); 36272cd085aSSimon Glass 36372cd085aSSimon Glass reg32 = readl(RCB_REG(CG)); 36472cd085aSSimon Glass reg32 |= (1 << 31); 36572cd085aSSimon Glass reg32 |= (1 << 29) | (1 << 28); 36672cd085aSSimon Glass reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24); 36772cd085aSSimon Glass reg32 |= (1 << 16); 36872cd085aSSimon Glass reg32 |= (1 << 17); 36972cd085aSSimon Glass reg32 |= (1 << 18); 37072cd085aSSimon Glass reg32 |= (1 << 22); 37172cd085aSSimon Glass reg32 |= (1 << 23); 37272cd085aSSimon Glass reg32 &= ~(1 << 20); 37372cd085aSSimon Glass reg32 |= (1 << 19); 37472cd085aSSimon Glass reg32 |= (1 << 0); 37572cd085aSSimon Glass reg32 |= (0xf << 1); 37672cd085aSSimon Glass writel(reg32, RCB_REG(CG)); 37772cd085aSSimon Glass 37872cd085aSSimon Glass setbits_le32(RCB_REG(0x38c0), 0x7); 37972cd085aSSimon Glass setbits_le32(RCB_REG(0x36d4), 0x6680c004); 38072cd085aSSimon Glass setbits_le32(RCB_REG(0x3564), 0x3); 38172cd085aSSimon Glass } 38272cd085aSSimon Glass 3834265abd4SSimon Glass static void pch_disable_smm_only_flashing(struct udevice *pch) 38472cd085aSSimon Glass { 38572cd085aSSimon Glass u8 reg8; 38672cd085aSSimon Glass 38772cd085aSSimon Glass debug("Enabling BIOS updates outside of SMM... "); 3884265abd4SSimon Glass dm_pci_read_config8(pch, 0xdc, ®8); /* BIOS_CNTL */ 38972cd085aSSimon Glass reg8 &= ~(1 << 5); 3904265abd4SSimon Glass dm_pci_write_config8(pch, 0xdc, reg8); 39172cd085aSSimon Glass } 39272cd085aSSimon Glass 3934265abd4SSimon Glass static void pch_fixups(struct udevice *pch) 39472cd085aSSimon Glass { 39572cd085aSSimon Glass u8 gen_pmcon_2; 39672cd085aSSimon Glass 39772cd085aSSimon Glass /* Indicate DRAM init done for MRC S3 to know it can resume */ 3984265abd4SSimon Glass dm_pci_read_config8(pch, GEN_PMCON_2, &gen_pmcon_2); 39972cd085aSSimon Glass gen_pmcon_2 |= (1 << 7); 4004265abd4SSimon Glass dm_pci_write_config8(pch, GEN_PMCON_2, gen_pmcon_2); 40172cd085aSSimon Glass 40272cd085aSSimon Glass /* Enable DMI ASPM in the PCH */ 40372cd085aSSimon Glass clrbits_le32(RCB_REG(0x2304), 1 << 10); 40472cd085aSSimon Glass setbits_le32(RCB_REG(0x21a4), (1 << 11) | (1 << 10)); 40572cd085aSSimon Glass setbits_le32(RCB_REG(0x21a8), 0x3); 40672cd085aSSimon Glass } 40772cd085aSSimon Glass 408fe40bd4dSSimon Glass static void set_spi_speed(void) 409fe40bd4dSSimon Glass { 410fe40bd4dSSimon Glass u32 fdod; 411fe40bd4dSSimon Glass 412fe40bd4dSSimon Glass /* Observe SPI Descriptor Component Section 0 */ 413fe40bd4dSSimon Glass writel(0x1000, RCB_REG(SPI_DESC_COMP0)); 414fe40bd4dSSimon Glass 415fe40bd4dSSimon Glass /* Extract the1 Write/Erase SPI Frequency from descriptor */ 416fe40bd4dSSimon Glass fdod = readl(RCB_REG(SPI_FREQ_WR_ERA)); 417fe40bd4dSSimon Glass fdod >>= 24; 418fe40bd4dSSimon Glass fdod &= 7; 419fe40bd4dSSimon Glass 420fe40bd4dSSimon Glass /* Set Software Sequence frequency to match */ 421fe40bd4dSSimon Glass clrsetbits_8(RCB_REG(SPI_FREQ_SWSEQ), 7, fdod); 422fe40bd4dSSimon Glass } 423fe40bd4dSSimon Glass 4244265abd4SSimon Glass static int lpc_init_extra(struct udevice *dev) 42572cd085aSSimon Glass { 4264265abd4SSimon Glass struct udevice *pch = dev->parent; 42772cd085aSSimon Glass 42872cd085aSSimon Glass debug("pch: lpc_init\n"); 4294265abd4SSimon Glass dm_pci_write_bar32(pch, 0, 0); 4304265abd4SSimon Glass dm_pci_write_bar32(pch, 1, 0xff800000); 4314265abd4SSimon Glass dm_pci_write_bar32(pch, 2, 0xfec00000); 4324265abd4SSimon Glass dm_pci_write_bar32(pch, 3, 0x800); 4334265abd4SSimon Glass dm_pci_write_bar32(pch, 4, 0x900); 43472cd085aSSimon Glass 43572cd085aSSimon Glass /* Set the value for PCI command register. */ 4364265abd4SSimon Glass dm_pci_write_config16(pch, PCI_COMMAND, 0x000f); 43772cd085aSSimon Glass 43872cd085aSSimon Glass /* IO APIC initialization. */ 4394265abd4SSimon Glass pch_enable_apic(pch); 44072cd085aSSimon Glass 4414265abd4SSimon Glass pch_enable_serial_irqs(pch); 44272cd085aSSimon Glass 44372cd085aSSimon Glass /* Setup the PIRQ. */ 4444265abd4SSimon Glass pch_pirq_init(pch); 44572cd085aSSimon Glass 44672cd085aSSimon Glass /* Setup power options. */ 4474265abd4SSimon Glass pch_power_options(pch); 44872cd085aSSimon Glass 44972cd085aSSimon Glass /* Initialize power management */ 4509434c7a3SSimon Glass switch (pch_silicon_type(pch)) { 45172cd085aSSimon Glass case PCH_TYPE_CPT: /* CougarPoint */ 4524265abd4SSimon Glass cpt_pm_init(pch); 45372cd085aSSimon Glass break; 45472cd085aSSimon Glass case PCH_TYPE_PPT: /* PantherPoint */ 4554265abd4SSimon Glass ppt_pm_init(pch); 45672cd085aSSimon Glass break; 45772cd085aSSimon Glass default: 4584265abd4SSimon Glass printf("Unknown Chipset: %s\n", pch->name); 45972cd085aSSimon Glass return -ENOSYS; 46072cd085aSSimon Glass } 46172cd085aSSimon Glass 46272cd085aSSimon Glass /* Initialize the real time clock. */ 4634265abd4SSimon Glass pch_rtc_init(pch); 46472cd085aSSimon Glass 46572cd085aSSimon Glass /* Initialize the High Precision Event Timers, if present. */ 46672cd085aSSimon Glass enable_hpet(); 46772cd085aSSimon Glass 46872cd085aSSimon Glass /* Initialize Clock Gating */ 4694265abd4SSimon Glass enable_clock_gating(pch); 47072cd085aSSimon Glass 4714265abd4SSimon Glass pch_disable_smm_only_flashing(pch); 47272cd085aSSimon Glass 4734265abd4SSimon Glass pch_fixups(pch); 47472cd085aSSimon Glass 47572cd085aSSimon Glass return 0; 47672cd085aSSimon Glass } 47772cd085aSSimon Glass 478fcd30cdfSSimon Glass static int bd82x6x_lpc_early_init(struct udevice *dev) 479fcd30cdfSSimon Glass { 4808c30b571SSimon Glass set_spi_speed(); 4818c30b571SSimon Glass 482fcd30cdfSSimon Glass /* Setting up Southbridge. In the northbridge code. */ 483fcd30cdfSSimon Glass debug("Setting up static southbridge registers\n"); 484bb096b9fSSimon Glass dm_pci_write_config32(dev->parent, PCH_RCBA_BASE, 485bb096b9fSSimon Glass RCB_BASE_ADDRESS | 1); 486fcd30cdfSSimon Glass dm_pci_write_config32(dev->parent, PMBASE, DEFAULT_PMBASE | 1); 487fcd30cdfSSimon Glass 488fcd30cdfSSimon Glass /* Enable ACPI BAR */ 489fcd30cdfSSimon Glass dm_pci_write_config8(dev->parent, ACPI_CNTL, 0x80); 490fcd30cdfSSimon Glass 491fcd30cdfSSimon Glass debug("Disabling watchdog reboot\n"); 492fcd30cdfSSimon Glass setbits_le32(RCB_REG(GCS), 1 >> 5); /* No reset */ 493fcd30cdfSSimon Glass outw(1 << 11, DEFAULT_PMBASE | 0x60 | 0x08); /* halt timer */ 494fcd30cdfSSimon Glass 4959fd11c7aSSimon Glass dm_pci_write_config32(dev->parent, GPIO_BASE, DEFAULT_GPIOBASE | 1); 4969fd11c7aSSimon Glass dm_pci_write_config32(dev->parent, GPIO_CNTL, 0x10); 4979fd11c7aSSimon Glass 498fcd30cdfSSimon Glass return 0; 499fcd30cdfSSimon Glass } 500fcd30cdfSSimon Glass 5014acc83d4SSimon Glass static int bd82x6x_lpc_probe(struct udevice *dev) 5024acc83d4SSimon Glass { 503788cd908SSimon Glass int ret; 504788cd908SSimon Glass 5054e190729SSimon Glass if (!(gd->flags & GD_FLG_RELOC)) { 5068c30b571SSimon Glass ret = lpc_common_early_init(dev); 507788cd908SSimon Glass if (ret) { 508788cd908SSimon Glass debug("%s: lpc_early_init() failed\n", __func__); 509788cd908SSimon Glass return ret; 510788cd908SSimon Glass } 511788cd908SSimon Glass 512fcd30cdfSSimon Glass return bd82x6x_lpc_early_init(dev); 5134acc83d4SSimon Glass } 5144acc83d4SSimon Glass 5154265abd4SSimon Glass return lpc_init_extra(dev); 5164e190729SSimon Glass } 5174e190729SSimon Glass 51890b16d14SSimon Glass static const struct udevice_id bd82x6x_lpc_ids[] = { 51990b16d14SSimon Glass { .compatible = "intel,bd82x6x-lpc" }, 52090b16d14SSimon Glass { } 52190b16d14SSimon Glass }; 52290b16d14SSimon Glass 52390b16d14SSimon Glass U_BOOT_DRIVER(bd82x6x_lpc_drv) = { 52490b16d14SSimon Glass .name = "lpc", 52590b16d14SSimon Glass .id = UCLASS_LPC, 52690b16d14SSimon Glass .of_match = bd82x6x_lpc_ids, 5274acc83d4SSimon Glass .probe = bd82x6x_lpc_probe, 52890b16d14SSimon Glass }; 529