13ac83935SSimon Glass /* 23ac83935SSimon Glass * From Coreboot 33ac83935SSimon Glass * Copyright (C) 2008-2009 coresystems GmbH 43ac83935SSimon Glass * 53ac83935SSimon Glass * SPDX-License-Identifier: GPL-2.0 63ac83935SSimon Glass */ 73ac83935SSimon Glass 83ac83935SSimon Glass #include <common.h> 9d46f2a68SSimon Glass #include <dm.h> 103ac83935SSimon Glass #include <fdtdec.h> 113ac83935SSimon Glass #include <asm/io.h> 127e4a6ae6SSimon Glass #include <asm/pch_common.h> 133ac83935SSimon Glass #include <asm/pci.h> 143ac83935SSimon Glass #include <asm/arch/pch.h> 153ac83935SSimon Glass 16d46f2a68SSimon Glass DECLARE_GLOBAL_DATA_PTR; 17d46f2a68SSimon Glass 18ddf10c20SSimon Glass static void common_sata_init(struct udevice *dev, unsigned int port_map) 193ac83935SSimon Glass { 203ac83935SSimon Glass u32 reg32; 213ac83935SSimon Glass u16 reg16; 223ac83935SSimon Glass 233ac83935SSimon Glass /* Set IDE I/O Configuration */ 243ac83935SSimon Glass reg32 = SIG_MODE_PRI_NORMAL | FAST_PCB1 | FAST_PCB0 | PCB1 | PCB0; 25ddf10c20SSimon Glass dm_pci_write_config32(dev, IDE_CONFIG, reg32); 263ac83935SSimon Glass 273ac83935SSimon Glass /* Port enable */ 28ddf10c20SSimon Glass dm_pci_read_config16(dev, 0x92, ®16); 293ac83935SSimon Glass reg16 &= ~0x3f; 303ac83935SSimon Glass reg16 |= port_map; 31ddf10c20SSimon Glass dm_pci_write_config16(dev, 0x92, reg16); 323ac83935SSimon Glass 333ac83935SSimon Glass /* SATA Initialization register */ 343ac83935SSimon Glass port_map &= 0xff; 35ddf10c20SSimon Glass dm_pci_write_config32(dev, 0x94, ((port_map ^ 0x3f) << 24) | 0x183); 363ac83935SSimon Glass } 373ac83935SSimon Glass 389434c7a3SSimon Glass static void bd82x6x_sata_init(struct udevice *dev, struct udevice *pch) 393ac83935SSimon Glass { 403ac83935SSimon Glass unsigned int port_map, speed_support, port_tx; 41ddf10c20SSimon Glass const void *blob = gd->fdt_blob; 42ddf10c20SSimon Glass int node = dev->of_offset; 433ac83935SSimon Glass const char *mode; 443ac83935SSimon Glass u32 reg32; 453ac83935SSimon Glass u16 reg16; 463ac83935SSimon Glass 473ac83935SSimon Glass debug("SATA: Initializing...\n"); 483ac83935SSimon Glass 493ac83935SSimon Glass /* SATA configuration */ 503ac83935SSimon Glass port_map = fdtdec_get_int(blob, node, "intel,sata-port-map", 0); 513ac83935SSimon Glass speed_support = fdtdec_get_int(blob, node, 523ac83935SSimon Glass "sata_interface_speed_support", 0); 533ac83935SSimon Glass 543ac83935SSimon Glass mode = fdt_getprop(blob, node, "intel,sata-mode", NULL); 553ac83935SSimon Glass if (!mode || !strcmp(mode, "ahci")) { 56*c7ccb2c0SSimon Glass ulong abar; 573ac83935SSimon Glass 583ac83935SSimon Glass debug("SATA: Controller in AHCI mode\n"); 593ac83935SSimon Glass 603ac83935SSimon Glass /* Set timings */ 61ddf10c20SSimon Glass dm_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | 623ac83935SSimon Glass IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS | 633ac83935SSimon Glass IDE_PPE0 | IDE_IE0 | IDE_TIME0); 64ddf10c20SSimon Glass dm_pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE | 653ac83935SSimon Glass IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS); 663ac83935SSimon Glass 673ac83935SSimon Glass /* Sync DMA */ 68ddf10c20SSimon Glass dm_pci_write_config16(dev, IDE_SDMA_CNT, IDE_PSDE0); 69ddf10c20SSimon Glass dm_pci_write_config16(dev, IDE_SDMA_TIM, 0x0001); 703ac83935SSimon Glass 713ac83935SSimon Glass common_sata_init(dev, 0x8000 | port_map); 723ac83935SSimon Glass 733ac83935SSimon Glass /* Initialize AHCI memory-mapped space */ 74ddf10c20SSimon Glass abar = dm_pci_read_bar32(dev, 5); 75*c7ccb2c0SSimon Glass debug("ABAR: %08lx\n", abar); 763ac83935SSimon Glass /* CAP (HBA Capabilities) : enable power management */ 773ac83935SSimon Glass reg32 = readl(abar + 0x00); 783ac83935SSimon Glass reg32 |= 0x0c006000; /* set PSC+SSC+SALP+SSS */ 793ac83935SSimon Glass reg32 &= ~0x00020060; /* clear SXS+EMS+PMS */ 803ac83935SSimon Glass /* Set ISS, if available */ 813ac83935SSimon Glass if (speed_support) { 823ac83935SSimon Glass reg32 &= ~0x00f00000; 833ac83935SSimon Glass reg32 |= (speed_support & 0x03) << 20; 843ac83935SSimon Glass } 853ac83935SSimon Glass writel(reg32, abar + 0x00); 863ac83935SSimon Glass /* PI (Ports implemented) */ 873ac83935SSimon Glass writel(port_map, abar + 0x0c); 883ac83935SSimon Glass (void) readl(abar + 0x0c); /* Read back 1 */ 893ac83935SSimon Glass (void) readl(abar + 0x0c); /* Read back 2 */ 903ac83935SSimon Glass /* CAP2 (HBA Capabilities Extended)*/ 913ac83935SSimon Glass reg32 = readl(abar + 0x24); 923ac83935SSimon Glass reg32 &= ~0x00000002; 933ac83935SSimon Glass writel(reg32, abar + 0x24); 943ac83935SSimon Glass /* VSP (Vendor Specific Register */ 953ac83935SSimon Glass reg32 = readl(abar + 0xa0); 963ac83935SSimon Glass reg32 &= ~0x00000005; 973ac83935SSimon Glass writel(reg32, abar + 0xa0); 983ac83935SSimon Glass } else if (!strcmp(mode, "combined")) { 993ac83935SSimon Glass debug("SATA: Controller in combined mode\n"); 1003ac83935SSimon Glass 1013ac83935SSimon Glass /* No AHCI: clear AHCI base */ 102ddf10c20SSimon Glass dm_pci_write_bar32(dev, 5, 0x00000000); 1033ac83935SSimon Glass /* And without AHCI BAR no memory decoding */ 104ddf10c20SSimon Glass dm_pci_read_config16(dev, PCI_COMMAND, ®16); 1053ac83935SSimon Glass reg16 &= ~PCI_COMMAND_MEMORY; 106ddf10c20SSimon Glass dm_pci_write_config16(dev, PCI_COMMAND, reg16); 1073ac83935SSimon Glass 108ddf10c20SSimon Glass dm_pci_write_config8(dev, 0x09, 0x80); 1093ac83935SSimon Glass 1103ac83935SSimon Glass /* Set timings */ 111ddf10c20SSimon Glass dm_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | 1123ac83935SSimon Glass IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS); 113ddf10c20SSimon Glass dm_pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE | 1143ac83935SSimon Glass IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS | 1153ac83935SSimon Glass IDE_PPE0 | IDE_IE0 | IDE_TIME0); 1163ac83935SSimon Glass 1173ac83935SSimon Glass /* Sync DMA */ 118ddf10c20SSimon Glass dm_pci_write_config16(dev, IDE_SDMA_CNT, IDE_SSDE0); 119ddf10c20SSimon Glass dm_pci_write_config16(dev, IDE_SDMA_TIM, 0x0200); 1203ac83935SSimon Glass 1213ac83935SSimon Glass common_sata_init(dev, port_map); 1223ac83935SSimon Glass } else { 1233ac83935SSimon Glass debug("SATA: Controller in plain-ide mode\n"); 1243ac83935SSimon Glass 1253ac83935SSimon Glass /* No AHCI: clear AHCI base */ 126ddf10c20SSimon Glass dm_pci_write_bar32(dev, 5, 0x00000000); 1273ac83935SSimon Glass 1283ac83935SSimon Glass /* And without AHCI BAR no memory decoding */ 129ddf10c20SSimon Glass dm_pci_read_config16(dev, PCI_COMMAND, ®16); 1303ac83935SSimon Glass reg16 &= ~PCI_COMMAND_MEMORY; 131ddf10c20SSimon Glass dm_pci_write_config16(dev, PCI_COMMAND, reg16); 1323ac83935SSimon Glass 1333ac83935SSimon Glass /* 1343ac83935SSimon Glass * Native mode capable on both primary and secondary (0xa) 1353ac83935SSimon Glass * OR'ed with enabled (0x50) = 0xf 1363ac83935SSimon Glass */ 137ddf10c20SSimon Glass dm_pci_write_config8(dev, 0x09, 0x8f); 1383ac83935SSimon Glass 1393ac83935SSimon Glass /* Set timings */ 140ddf10c20SSimon Glass dm_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | 1413ac83935SSimon Glass IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS | 1423ac83935SSimon Glass IDE_PPE0 | IDE_IE0 | IDE_TIME0); 143ddf10c20SSimon Glass dm_pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE | 1443ac83935SSimon Glass IDE_SITRE | IDE_ISP_3_CLOCKS | 1453ac83935SSimon Glass IDE_RCT_1_CLOCKS | IDE_IE0 | IDE_TIME0); 1463ac83935SSimon Glass 1473ac83935SSimon Glass /* Sync DMA */ 148ddf10c20SSimon Glass dm_pci_write_config16(dev, IDE_SDMA_CNT, IDE_SSDE0 | IDE_PSDE0); 149ddf10c20SSimon Glass dm_pci_write_config16(dev, IDE_SDMA_TIM, 0x0201); 1503ac83935SSimon Glass 1513ac83935SSimon Glass common_sata_init(dev, port_map); 1523ac83935SSimon Glass } 1533ac83935SSimon Glass 1543ac83935SSimon Glass /* Set Gen3 Transmitter settings if needed */ 1553ac83935SSimon Glass port_tx = fdtdec_get_int(blob, node, "intel,sata-port0-gen3-tx", 0); 1563ac83935SSimon Glass if (port_tx) 1579434c7a3SSimon Glass pch_iobp_update(pch, SATA_IOBP_SP0G3IR, 0, port_tx); 1583ac83935SSimon Glass 1593ac83935SSimon Glass port_tx = fdtdec_get_int(blob, node, "intel,sata-port1-gen3-tx", 0); 1603ac83935SSimon Glass if (port_tx) 1619434c7a3SSimon Glass pch_iobp_update(pch, SATA_IOBP_SP1G3IR, 0, port_tx); 1623ac83935SSimon Glass 1633ac83935SSimon Glass /* Additional Programming Requirements */ 1647e4a6ae6SSimon Glass pch_common_sir_write(dev, 0x04, 0x00001600); 1657e4a6ae6SSimon Glass pch_common_sir_write(dev, 0x28, 0xa0000033); 1667e4a6ae6SSimon Glass reg32 = pch_common_sir_read(dev, 0x54); 1673ac83935SSimon Glass reg32 &= 0xff000000; 1683ac83935SSimon Glass reg32 |= 0x5555aa; 1697e4a6ae6SSimon Glass pch_common_sir_write(dev, 0x54, reg32); 1707e4a6ae6SSimon Glass pch_common_sir_write(dev, 0x64, 0xcccc8484); 1717e4a6ae6SSimon Glass reg32 = pch_common_sir_read(dev, 0x68); 1723ac83935SSimon Glass reg32 &= 0xffff0000; 1733ac83935SSimon Glass reg32 |= 0xcccc; 1747e4a6ae6SSimon Glass pch_common_sir_write(dev, 0x68, reg32); 1757e4a6ae6SSimon Glass reg32 = pch_common_sir_read(dev, 0x78); 1763ac83935SSimon Glass reg32 &= 0x0000ffff; 1773ac83935SSimon Glass reg32 |= 0x88880000; 1787e4a6ae6SSimon Glass pch_common_sir_write(dev, 0x78, reg32); 1797e4a6ae6SSimon Glass pch_common_sir_write(dev, 0x84, 0x001c7000); 1807e4a6ae6SSimon Glass pch_common_sir_write(dev, 0x88, 0x88338822); 1817e4a6ae6SSimon Glass pch_common_sir_write(dev, 0xa0, 0x001c7000); 1827e4a6ae6SSimon Glass pch_common_sir_write(dev, 0xc4, 0x0c0c0c0c); 1837e4a6ae6SSimon Glass pch_common_sir_write(dev, 0xc8, 0x0c0c0c0c); 1847e4a6ae6SSimon Glass pch_common_sir_write(dev, 0xd4, 0x10000000); 1853ac83935SSimon Glass 1869434c7a3SSimon Glass pch_iobp_update(pch, 0xea004001, 0x3fffffff, 0xc0000000); 1879434c7a3SSimon Glass pch_iobp_update(pch, 0xea00408a, 0xfffffcff, 0x00000100); 1883ac83935SSimon Glass } 1893ac83935SSimon Glass 190ddf10c20SSimon Glass static void bd82x6x_sata_enable(struct udevice *dev) 1913ac83935SSimon Glass { 192ddf10c20SSimon Glass const void *blob = gd->fdt_blob; 193ddf10c20SSimon Glass int node = dev->of_offset; 1943ac83935SSimon Glass unsigned port_map; 1953ac83935SSimon Glass const char *mode; 1963ac83935SSimon Glass u16 map = 0; 1973ac83935SSimon Glass 1983ac83935SSimon Glass /* 1993ac83935SSimon Glass * Set SATA controller mode early so the resource allocator can 2003ac83935SSimon Glass * properly assign IO/Memory resources for the controller. 2013ac83935SSimon Glass */ 2023ac83935SSimon Glass mode = fdt_getprop(blob, node, "intel,sata-mode", NULL); 2033ac83935SSimon Glass if (mode && !strcmp(mode, "ahci")) 2043ac83935SSimon Glass map = 0x0060; 2053ac83935SSimon Glass port_map = fdtdec_get_int(blob, node, "intel,sata-port-map", 0); 2063ac83935SSimon Glass 2073ac83935SSimon Glass map |= (port_map ^ 0x3f) << 8; 208ddf10c20SSimon Glass dm_pci_write_config16(dev, 0x90, map); 2093ac83935SSimon Glass } 210d46f2a68SSimon Glass 211d46f2a68SSimon Glass static int bd82x6x_sata_probe(struct udevice *dev) 212d46f2a68SSimon Glass { 2139434c7a3SSimon Glass struct udevice *pch; 2149434c7a3SSimon Glass int ret; 2159434c7a3SSimon Glass 2163f603cbbSSimon Glass ret = uclass_first_device_err(UCLASS_PCH, &pch); 2179434c7a3SSimon Glass if (ret) 2189434c7a3SSimon Glass return ret; 2199434c7a3SSimon Glass 220d46f2a68SSimon Glass if (!(gd->flags & GD_FLG_RELOC)) 221ddf10c20SSimon Glass bd82x6x_sata_enable(dev); 22201a67908SSimon Glass else 2239434c7a3SSimon Glass bd82x6x_sata_init(dev, pch); 224d46f2a68SSimon Glass 225d46f2a68SSimon Glass return 0; 226d46f2a68SSimon Glass } 227d46f2a68SSimon Glass 228d46f2a68SSimon Glass static const struct udevice_id bd82x6x_ahci_ids[] = { 229d46f2a68SSimon Glass { .compatible = "intel,pantherpoint-ahci" }, 230d46f2a68SSimon Glass { } 231d46f2a68SSimon Glass }; 232d46f2a68SSimon Glass 233d46f2a68SSimon Glass U_BOOT_DRIVER(ahci_ivybridge_drv) = { 234d46f2a68SSimon Glass .name = "ahci_ivybridge", 235a219639dSSimon Glass .id = UCLASS_AHCI, 236d46f2a68SSimon Glass .of_match = bd82x6x_ahci_ids, 237d46f2a68SSimon Glass .probe = bd82x6x_sata_probe, 238d46f2a68SSimon Glass }; 239