diff options
Diffstat (limited to 'roms/u-boot/arch/x86/cpu/ivybridge/sata.c')
-rw-r--r-- | roms/u-boot/arch/x86/cpu/ivybridge/sata.c | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/roms/u-boot/arch/x86/cpu/ivybridge/sata.c b/roms/u-boot/arch/x86/cpu/ivybridge/sata.c new file mode 100644 index 000000000..f47ecdffa --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/ivybridge/sata.c @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * From Coreboot + * Copyright (C) 2008-2009 coresystems GmbH + */ + +#include <common.h> +#include <ahci.h> +#include <dm.h> +#include <fdtdec.h> +#include <log.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <asm/pch_common.h> +#include <asm/pci.h> +#include <asm/arch/pch.h> + +DECLARE_GLOBAL_DATA_PTR; + +static void common_sata_init(struct udevice *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; + dm_pci_write_config32(dev, IDE_CONFIG, reg32); + + /* Port enable */ + dm_pci_read_config16(dev, 0x92, ®16); + reg16 &= ~0x3f; + reg16 |= port_map; + dm_pci_write_config16(dev, 0x92, reg16); + + /* SATA Initialization register */ + port_map &= 0xff; + dm_pci_write_config32(dev, 0x94, ((port_map ^ 0x3f) << 24) | 0x183); +} + +static void bd82x6x_sata_init(struct udevice *dev, struct udevice *pch) +{ + unsigned int port_map, speed_support, port_tx; + const void *blob = gd->fdt_blob; + int node = dev_of_offset(dev); + 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); + + mode = fdt_getprop(blob, node, "intel,sata-mode", NULL); + if (!mode || !strcmp(mode, "ahci")) { + ulong abar; + + debug("SATA: Controller in AHCI mode\n"); + + /* Set timings */ + dm_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | + IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS | + IDE_PPE0 | IDE_IE0 | IDE_TIME0); + dm_pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE | + IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS); + + /* Sync DMA */ + dm_pci_write_config16(dev, IDE_SDMA_CNT, IDE_PSDE0); + dm_pci_write_config16(dev, IDE_SDMA_TIM, 0x0001); + + common_sata_init(dev, 0x8000 | port_map); + + /* Initialize AHCI memory-mapped space */ + abar = dm_pci_read_bar32(dev, 5); + debug("ABAR: %08lx\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 */ + dm_pci_write_bar32(dev, 5, 0x00000000); + /* And without AHCI BAR no memory decoding */ + dm_pci_read_config16(dev, PCI_COMMAND, ®16); + reg16 &= ~PCI_COMMAND_MEMORY; + dm_pci_write_config16(dev, PCI_COMMAND, reg16); + + dm_pci_write_config8(dev, 0x09, 0x80); + + /* Set timings */ + dm_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | + IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS); + dm_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 */ + dm_pci_write_config16(dev, IDE_SDMA_CNT, IDE_SSDE0); + dm_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 */ + dm_pci_write_bar32(dev, 5, 0x00000000); + + /* And without AHCI BAR no memory decoding */ + dm_pci_read_config16(dev, PCI_COMMAND, ®16); + reg16 &= ~PCI_COMMAND_MEMORY; + dm_pci_write_config16(dev, PCI_COMMAND, reg16); + + /* + * Native mode capable on both primary and secondary (0xa) + * OR'ed with enabled (0x50) = 0xf + */ + dm_pci_write_config8(dev, 0x09, 0x8f); + + /* Set timings */ + dm_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | + IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS | + IDE_PPE0 | IDE_IE0 | IDE_TIME0); + dm_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 */ + dm_pci_write_config16(dev, IDE_SDMA_CNT, IDE_SSDE0 | IDE_PSDE0); + dm_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(pch, 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(pch, SATA_IOBP_SP1G3IR, 0, port_tx); + + /* Additional Programming Requirements */ + pch_common_sir_write(dev, 0x04, 0x00001600); + pch_common_sir_write(dev, 0x28, 0xa0000033); + reg32 = pch_common_sir_read(dev, 0x54); + reg32 &= 0xff000000; + reg32 |= 0x5555aa; + pch_common_sir_write(dev, 0x54, reg32); + pch_common_sir_write(dev, 0x64, 0xcccc8484); + reg32 = pch_common_sir_read(dev, 0x68); + reg32 &= 0xffff0000; + reg32 |= 0xcccc; + pch_common_sir_write(dev, 0x68, reg32); + reg32 = pch_common_sir_read(dev, 0x78); + reg32 &= 0x0000ffff; + reg32 |= 0x88880000; + pch_common_sir_write(dev, 0x78, reg32); + pch_common_sir_write(dev, 0x84, 0x001c7000); + pch_common_sir_write(dev, 0x88, 0x88338822); + pch_common_sir_write(dev, 0xa0, 0x001c7000); + pch_common_sir_write(dev, 0xc4, 0x0c0c0c0c); + pch_common_sir_write(dev, 0xc8, 0x0c0c0c0c); + pch_common_sir_write(dev, 0xd4, 0x10000000); + + pch_iobp_update(pch, 0xea004001, 0x3fffffff, 0xc0000000); + pch_iobp_update(pch, 0xea00408a, 0xfffffcff, 0x00000100); +} + +static void bd82x6x_sata_enable(struct udevice *dev) +{ + const void *blob = gd->fdt_blob; + int node = dev_of_offset(dev); + 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; + dm_pci_write_config16(dev, 0x90, map); +} + +static int bd82x6x_sata_bind(struct udevice *dev) +{ + struct udevice *scsi_dev; + int ret; + + if (gd->flags & GD_FLG_RELOC) { + ret = ahci_bind_scsi(dev, &scsi_dev); + if (ret) + return ret; + } + + return 0; +} + +static int bd82x6x_sata_probe(struct udevice *dev) +{ + struct udevice *pch; + int ret; + + ret = uclass_first_device_err(UCLASS_PCH, &pch); + if (ret) + return ret; + + if (!(gd->flags & GD_FLG_RELOC)) + bd82x6x_sata_enable(dev); + else { + bd82x6x_sata_init(dev, pch); + ret = ahci_probe_scsi_pci(dev); + if (ret) + return ret; + } + + return 0; +} + +static const struct udevice_id bd82x6x_ahci_ids[] = { + { .compatible = "intel,pantherpoint-ahci" }, + { } +}; + +U_BOOT_DRIVER(ahci_ivybridge_drv) = { + .name = "ahci_ivybridge", + .id = UCLASS_AHCI, + .of_match = bd82x6x_ahci_ids, + .bind = bd82x6x_sata_bind, + .probe = bd82x6x_sata_probe, +}; |