diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ddr/marvell/a38x/ddr3_training_centralization.c | 26 | ||||
-rw-r--r-- | drivers/ddr/marvell/a38x/mv_ddr_plat.c | 19 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/pxa3xx_nand.c | 4 | ||||
-rw-r--r-- | drivers/pci/Kconfig | 1 | ||||
-rw-r--r-- | drivers/pci/pci_mvebu.c | 275 |
5 files changed, 251 insertions, 74 deletions
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_centralization.c b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c index 648b37ef6f7..42308b6965d 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_centralization.c +++ b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c @@ -55,6 +55,7 @@ static int ddr3_tip_centralization(u32 dev_num, u32 mode) enum hws_training_ip_stat training_result[MAX_INTERFACE_NUM]; u32 if_id, pattern_id, bit_id; u8 bus_id; + u8 current_byte_status; u8 cur_start_win[BUS_WIDTH_IN_BITS]; u8 centralization_result[MAX_INTERFACE_NUM][BUS_WIDTH_IN_BITS]; u8 cur_end_win[BUS_WIDTH_IN_BITS]; @@ -166,6 +167,10 @@ static int ddr3_tip_centralization(u32 dev_num, u32 mode) result[search_dir_id][7])); } + current_byte_status = + mv_ddr_tip_sub_phy_byte_status_get(if_id, + bus_id); + for (bit_id = 0; bit_id < BUS_WIDTH_IN_BITS; bit_id++) { /* check if this code is valid for 2 edge, probably not :( */ @@ -174,11 +179,32 @@ static int ddr3_tip_centralization(u32 dev_num, u32 mode) [HWS_LOW2HIGH] [bit_id], EDGE_1); + if (current_byte_status & + BYTE_SPLIT_OUT_MIX) { + if (cur_start_win[bit_id] >= 64) + cur_start_win[bit_id] -= 64; + else + cur_start_win[bit_id] = 0; + DEBUG_CENTRALIZATION_ENGINE + (DEBUG_LEVEL_INFO, + ("pattern %d IF %d pup %d bit %d subtract 64 adll from start\n", + pattern_id, if_id, bus_id, bit_id)); + } cur_end_win[bit_id] = GET_TAP_RESULT(result [HWS_HIGH2LOW] [bit_id], EDGE_1); + if (cur_end_win[bit_id] >= 64 && + (current_byte_status & + BYTE_SPLIT_OUT_MIX)) { + cur_end_win[bit_id] -= 64; + DEBUG_CENTRALIZATION_ENGINE + (DEBUG_LEVEL_INFO, + ("pattern %d IF %d pup %d bit %d subtract 64 adll from end\n", + pattern_id, if_id, bus_id, bit_id)); + } + /* window length */ current_window[bit_id] = cur_end_win[bit_id] - diff --git a/drivers/ddr/marvell/a38x/mv_ddr_plat.c b/drivers/ddr/marvell/a38x/mv_ddr_plat.c index faafc86ea26..7c7bce73a35 100644 --- a/drivers/ddr/marvell/a38x/mv_ddr_plat.c +++ b/drivers/ddr/marvell/a38x/mv_ddr_plat.c @@ -167,8 +167,6 @@ static u16 a38x_vco_freq_per_sar_ref_clk_40_mhz[] = { }; -static u32 async_mode_at_tf; - static u32 dq_bit_map_2_phy_pin[] = { 1, 0, 2, 6, 9, 8, 3, 7, /* 0 */ 8, 9, 1, 7, 2, 6, 3, 0, /* 1 */ @@ -734,7 +732,8 @@ static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id, u32 divider = 0; u32 sar_val, ref_clk_satr; u32 async_val; - u32 freq = mv_ddr_freq_get(frequency); + u32 cpu_freq; + u32 ddr_freq = mv_ddr_freq_get(frequency); if (if_id != 0) { DEBUG_TRAINING_ACCESS(DEBUG_LEVEL_ERROR, @@ -751,11 +750,14 @@ static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id, ref_clk_satr = reg_read(DEVICE_SAMPLE_AT_RESET2_REG); if (((ref_clk_satr >> DEVICE_SAMPLE_AT_RESET2_REG_REFCLK_OFFSET) & 0x1) == DEVICE_SAMPLE_AT_RESET2_REG_REFCLK_25MHZ) - divider = a38x_vco_freq_per_sar_ref_clk_25_mhz[sar_val] / freq; + cpu_freq = a38x_vco_freq_per_sar_ref_clk_25_mhz[sar_val]; else - divider = a38x_vco_freq_per_sar_ref_clk_40_mhz[sar_val] / freq; + cpu_freq = a38x_vco_freq_per_sar_ref_clk_40_mhz[sar_val]; + + divider = cpu_freq / ddr_freq; - if ((async_mode_at_tf == 1) && (freq > 400)) { + if (((cpu_freq % ddr_freq != 0) || (divider != 2 && divider != 3)) && + (ddr_freq > 400)) { /* Set async mode */ dunit_write(0x20220, 0x1000, 0x1000); dunit_write(0xe42f4, 0x200, 0x200); @@ -869,8 +871,6 @@ int ddr3_tip_ext_write(u32 dev_num, u32 if_id, u32 reg_addr, int mv_ddr_early_init(void) { - struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - /* FIXME: change this configuration per ddr type * configure a380 and a390 to work with receiver odt timing * the odt_config is defined: @@ -882,9 +882,6 @@ int mv_ddr_early_init(void) mv_ddr_sw_db_init(0, 0); - if (tm->interface_params[0].memory_freq != MV_DDR_FREQ_SAR) - async_mode_at_tf = 1; - return MV_OK; } diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c index 8ff58a70387..3a9c9ca508d 100644 --- a/drivers/mtd/nand/raw/pxa3xx_nand.c +++ b/drivers/mtd/nand/raw/pxa3xx_nand.c @@ -1862,10 +1862,10 @@ static int pxa3xx_nand_probe_dt(struct udevice *dev, struct pxa3xx_nand_info *in return -EINVAL; } - if (dev_read_bool(dev, "nand-enable-arbiter")) + if (dev_read_bool(dev, "marvell,nand-enable-arbiter")) pdata->enable_arbiter = 1; - if (dev_read_bool(dev, "nand-keep-config")) + if (dev_read_bool(dev, "marvell,nand-keep-config")) pdata->keep_config = 1; /* diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 42f8cb6be0d..630d6e6cc5e 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -265,6 +265,7 @@ config PCI_MVEBU bool "Enable Armada XP/38x PCIe driver" depends on ARCH_MVEBU select MISC + select DM_RESET help Say Y here if you want to enable PCIe controller support on Armada XP/38x SoCs. diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index 18f79d249c7..b3ea034a284 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -18,13 +18,16 @@ #include <dm/lists.h> #include <dm/of_access.h> #include <pci.h> +#include <reset.h> #include <asm/io.h> #include <asm/arch/cpu.h> #include <asm/arch/soc.h> #include <linux/bitops.h> +#include <linux/delay.h> #include <linux/errno.h> #include <linux/ioport.h> #include <linux/mbus.h> +#include <linux/sizes.h> /* PCIe unit register offsets */ #define SELECT(x, n) ((x >> n) & 1UL) @@ -59,6 +62,9 @@ #define PCIE_DEBUG_CTRL 0x1a60 #define PCIE_DEBUG_SOFT_RESET BIT(20) +#define LINK_WAIT_RETRIES 100 +#define LINK_WAIT_TIMEOUT 1000 + struct mvebu_pcie { struct pci_controller hose; void __iomem *base; @@ -66,8 +72,10 @@ struct mvebu_pcie { struct resource mem; void __iomem *iobase; struct resource io; + u32 intregs; u32 port; u32 lane; + bool is_x4; int devfn; u32 lane_mask; int first_busno; @@ -80,14 +88,6 @@ struct mvebu_pcie { u32 cfgcache[(0x3c - 0x10) / 4]; }; -/* - * MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped - * into SoCs address space. Each controller will map 128M of MEM - * and 64K of I/O space when registered. - */ -static void __iomem *mvebu_pcie_membase = (void __iomem *)MBUS_PCI_MEM_BASE; -static void __iomem *mvebu_pcie_iobase = (void __iomem *)MBUS_PCI_IO_BASE; - static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie) { u32 val; @@ -95,6 +95,23 @@ static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie) return !(val & PCIE_STAT_LINK_DOWN); } +static void mvebu_pcie_wait_for_link(struct mvebu_pcie *pcie) +{ + int retries; + + /* check if the link is up or not */ + for (retries = 0; retries < LINK_WAIT_RETRIES; retries++) { + if (mvebu_pcie_link_up(pcie)) { + printf("%s: Link up\n", pcie->name); + return; + } + + udelay(LINK_WAIT_TIMEOUT); + } + + printf("%s: Link down\n", pcie->name); +} + static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie *pcie, int busno) { u32 stat; @@ -357,15 +374,43 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie) pcie->base + PCIE_BAR_CTRL_OFF(1)); /* Setup BAR[0] to internal registers. */ - writel(SOC_REGS_PHY_BASE, pcie->base + PCIE_BAR_LO_OFF(0)); + writel(pcie->intregs, pcie->base + PCIE_BAR_LO_OFF(0)); writel(0, pcie->base + PCIE_BAR_HI_OFF(0)); } -static int mvebu_pcie_probe(struct udevice *dev) +/* Only enable PCIe link, do not setup it */ +static int mvebu_pcie_enable_link(struct mvebu_pcie *pcie, ofnode node) +{ + struct reset_ctl rst; + int ret; + + ret = reset_get_by_index_nodev(node, 0, &rst); + if (ret == -ENOENT) { + return 0; + } else if (ret < 0) { + printf("%s: cannot get reset controller: %d\n", pcie->name, ret); + return ret; + } + + ret = reset_request(&rst); + if (ret) { + printf("%s: cannot request reset controller: %d\n", pcie->name, ret); + return ret; + } + + ret = reset_deassert(&rst); + reset_free(&rst); + if (ret) { + printf("%s: cannot enable PCIe port: %d\n", pcie->name, ret); + return ret; + } + + return 0; +} + +/* Setup PCIe link but do not enable it */ +static void mvebu_pcie_setup_link(struct mvebu_pcie *pcie) { - struct mvebu_pcie *pcie = dev_get_plat(dev); - struct udevice *ctlr = pci_get_controller(dev); - struct pci_controller *hose = dev_get_uclass_priv(ctlr); u32 reg; /* Setup PCIe controller to Root Complex mode */ @@ -374,6 +419,26 @@ static int mvebu_pcie_probe(struct udevice *dev) writel(reg, pcie->base + PCIE_CTRL_OFF); /* + * Set Maximum Link Width to X1 or X4 in Root Port's PCIe Link + * Capability register. This register is defined by PCIe specification + * as read-only but this mvebu controller has it as read-write and must + * be set to number of SerDes PCIe lanes (1 or 4). If this register is + * not set correctly then link with endpoint card is not established. + */ + reg = readl(pcie->base + PCIE_CAPAB_OFF + PCI_EXP_LNKCAP); + reg &= ~PCI_EXP_LNKCAP_MLW; + reg |= (pcie->is_x4 ? 4 : 1) << 4; + writel(reg, pcie->base + PCIE_CAPAB_OFF + PCI_EXP_LNKCAP); +} + +static int mvebu_pcie_probe(struct udevice *dev) +{ + struct mvebu_pcie *pcie = dev_get_plat(dev); + struct udevice *ctlr = pci_get_controller(dev); + struct pci_controller *hose = dev_get_uclass_priv(ctlr); + u32 reg; + + /* * Change Class Code of PCI Bridge device to PCI Bridge (0x600400) * because default value is Memory controller (0x508000) which * U-Boot cannot recognize as P2P Bridge. @@ -433,26 +498,26 @@ static int mvebu_pcie_probe(struct udevice *dev) mvebu_pcie_set_local_bus_nr(pcie, 0); mvebu_pcie_set_local_dev_nr(pcie, 1); - pcie->mem.start = (u32)mvebu_pcie_membase; - pcie->mem.end = pcie->mem.start + MBUS_PCI_MEM_SIZE - 1; - mvebu_pcie_membase += MBUS_PCI_MEM_SIZE; - - if (mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr, + if (resource_size(&pcie->mem) && + mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr, (phys_addr_t)pcie->mem.start, resource_size(&pcie->mem))) { - printf("PCIe unable to add mbus window for mem at %08x+%08x\n", + printf("%s: unable to add mbus window for mem at %08x+%08x\n", + pcie->name, (u32)pcie->mem.start, (unsigned)resource_size(&pcie->mem)); + pcie->mem.start = 0; + pcie->mem.end = -1; } - pcie->io.start = (u32)mvebu_pcie_iobase; - pcie->io.end = pcie->io.start + MBUS_PCI_IO_SIZE - 1; - mvebu_pcie_iobase += MBUS_PCI_IO_SIZE; - - if (mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr, + if (resource_size(&pcie->io) && + mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr, (phys_addr_t)pcie->io.start, resource_size(&pcie->io))) { - printf("PCIe unable to add mbus window for IO at %08x+%08x\n", + printf("%s: unable to add mbus window for IO at %08x+%08x\n", + pcie->name, (u32)pcie->io.start, (unsigned)resource_size(&pcie->io)); + pcie->io.start = 0; + pcie->io.end = -1; } /* Setup windows and configure host bridge */ @@ -461,13 +526,23 @@ static int mvebu_pcie_probe(struct udevice *dev) /* PCI memory space */ pci_set_region(hose->regions + 0, pcie->mem.start, pcie->mem.start, resource_size(&pcie->mem), PCI_REGION_MEM); - pci_set_region(hose->regions + 1, - 0, 0, - gd->ram_size, - PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); - pci_set_region(hose->regions + 2, pcie->io.start, - pcie->io.start, resource_size(&pcie->io), PCI_REGION_IO); - hose->region_count = 3; + hose->region_count = 1; + + if (resource_size(&pcie->mem)) { + pci_set_region(hose->regions + hose->region_count, + pcie->mem.start, pcie->mem.start, + resource_size(&pcie->mem), + PCI_REGION_MEM); + hose->region_count++; + } + + if (resource_size(&pcie->io)) { + pci_set_region(hose->regions + hose->region_count, + pcie->io.start, pcie->io.start, + resource_size(&pcie->io), + PCI_REGION_IO); + hose->region_count++; + } /* PCI Bridge support 32-bit I/O and 64-bit prefetch mem addressing */ pcie->cfgcache[(PCI_IO_BASE - 0x10) / 4] = @@ -475,21 +550,7 @@ static int mvebu_pcie_probe(struct udevice *dev) pcie->cfgcache[(PCI_PREF_MEMORY_BASE - 0x10) / 4] = PCI_PREF_RANGE_TYPE_64 | (PCI_PREF_RANGE_TYPE_64 << 16); - return 0; -} - -static int mvebu_pcie_port_parse_dt(ofnode node, struct mvebu_pcie *pcie) -{ - const u32 *addr; - int len; - - addr = ofnode_get_property(node, "assigned-addresses", &len); - if (!addr) { - pr_err("property \"assigned-addresses\" not found"); - return -FDT_ERR_NOTFOUND; - } - - pcie->base = (void *)(fdt32_to_cpu(addr[2]) + SOC_REGS_PHY_BASE); + mvebu_pcie_wait_for_link(pcie); return 0; } @@ -554,31 +615,38 @@ static int mvebu_get_tgt_attr(ofnode node, int devfn, return -ENOENT; } -static int mvebu_pcie_of_to_plat(struct udevice *dev) +static int mvebu_pcie_port_parse_dt(ofnode node, ofnode parent, struct mvebu_pcie *pcie) { - struct mvebu_pcie *pcie = dev_get_plat(dev); + struct fdt_pci_addr pci_addr; + const u32 *addr; + u32 num_lanes; int ret = 0; + int len; /* Get port number, lane number and memory target / attr */ - if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-port", + if (ofnode_read_u32(node, "marvell,pcie-port", &pcie->port)) { ret = -ENODEV; goto err; } - if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-lane", &pcie->lane)) + if (ofnode_read_u32(node, "marvell,pcie-lane", &pcie->lane)) pcie->lane = 0; sprintf(pcie->name, "pcie%d.%d", pcie->port, pcie->lane); - /* pci_get_devfn() returns devfn in bits 15..8, see PCI_DEV usage */ - pcie->devfn = pci_get_devfn(dev); - if (pcie->devfn < 0) { - ret = -ENODEV; + if (!ofnode_read_u32(node, "num-lanes", &num_lanes) && num_lanes == 4) + pcie->is_x4 = true; + + /* devfn is in bits [15:8], see PCI_DEV usage */ + ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", &pci_addr); + if (ret < 0) { + printf("%s: property \"reg\" is invalid\n", pcie->name); goto err; } + pcie->devfn = pci_addr.phys_hi & 0xff00; - ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn, + ret = mvebu_get_tgt_attr(parent, pcie->devfn, IORESOURCE_MEM, &pcie->mem_target, &pcie->mem_attr); if (ret < 0) { @@ -586,7 +654,7 @@ static int mvebu_pcie_of_to_plat(struct udevice *dev) goto err; } - ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn, + ret = mvebu_get_tgt_attr(parent, pcie->devfn, IORESOURCE_IO, &pcie->io_target, &pcie->io_attr); if (ret < 0) { @@ -595,9 +663,15 @@ static int mvebu_pcie_of_to_plat(struct udevice *dev) } /* Parse PCIe controller register base from DT */ - ret = mvebu_pcie_port_parse_dt(dev_ofnode(dev), pcie); - if (ret < 0) + addr = ofnode_get_property(node, "assigned-addresses", &len); + if (!addr) { + printf("%s: property \"assigned-addresses\" not found\n", pcie->name); + ret = -FDT_ERR_NOTFOUND; goto err; + } + + pcie->base = (void *)(u32)ofnode_translate_address(node, addr); + pcie->intregs = (u32)pcie->base - fdt32_to_cpu(addr[2]); return 0; @@ -615,7 +689,6 @@ static struct driver pcie_mvebu_drv = { .id = UCLASS_PCI, .ops = &mvebu_pcie_ops, .probe = mvebu_pcie_probe, - .of_to_plat = mvebu_pcie_of_to_plat, .plat_auto = sizeof(struct mvebu_pcie), }; @@ -625,9 +698,14 @@ static struct driver pcie_mvebu_drv = { */ static int mvebu_pcie_bind(struct udevice *parent) { + struct mvebu_pcie **ports_pcie; struct mvebu_pcie *pcie; struct uclass_driver *drv; struct udevice *dev; + struct resource mem; + struct resource io; + int ports_count, i; + ofnode *ports_nodes; ofnode subnode; /* Lookup pci driver */ @@ -637,19 +715,94 @@ static int mvebu_pcie_bind(struct udevice *parent) return -ENOENT; } + ports_count = ofnode_get_child_count(dev_ofnode(parent)); + ports_pcie = calloc(ports_count, sizeof(*ports_pcie)); + ports_nodes = calloc(ports_count, sizeof(*ports_nodes)); + if (!ports_pcie || !ports_nodes) { + free(ports_pcie); + free(ports_nodes); + return -ENOMEM; + } + ports_count = 0; + + mem.start = MBUS_PCI_MEM_BASE; + mem.end = MBUS_PCI_MEM_BASE + MBUS_PCI_MEM_SIZE - 1; + io.start = MBUS_PCI_IO_BASE; + io.end = MBUS_PCI_IO_BASE + MBUS_PCI_IO_SIZE - 1; + + /* First phase: Fill mvebu_pcie struct for each port */ ofnode_for_each_subnode(subnode, dev_ofnode(parent)) { if (!ofnode_is_available(subnode)) continue; pcie = calloc(1, sizeof(*pcie)); if (!pcie) - return -ENOMEM; + continue; + + if (mvebu_pcie_port_parse_dt(subnode, dev_ofnode(parent), pcie) < 0) { + free(pcie); + continue; + } + + /* + * MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped + * into SoCs address space. Each controller will map 128M of MEM + * and 64K of I/O space when registered. + */ + + if (resource_size(&mem) >= SZ_128M) { + pcie->mem.start = mem.start; + pcie->mem.end = mem.start + SZ_128M - 1; + mem.start += SZ_128M; + } else { + printf("%s: unable to assign mbus window for mem\n", pcie->name); + pcie->mem.start = 0; + pcie->mem.end = -1; + } + + if (resource_size(&io) >= SZ_64K) { + pcie->io.start = io.start; + pcie->io.end = io.start + SZ_64K - 1; + io.start += SZ_64K; + } else { + printf("%s: unable to assign mbus window for io\n", pcie->name); + pcie->io.start = 0; + pcie->io.end = -1; + } + + ports_pcie[ports_count] = pcie; + ports_nodes[ports_count] = subnode; + ports_count++; + } + + /* Second phase: Setup all PCIe links (do not enable them yet) */ + for (i = 0; i < ports_count; i++) + mvebu_pcie_setup_link(ports_pcie[i]); + + /* Third phase: Enable all PCIe links and create for each UCLASS_PCI device */ + for (i = 0; i < ports_count; i++) { + pcie = ports_pcie[i]; + subnode = ports_nodes[i]; + + /* + * PCIe link can be enabled only after all PCIe links were + * properly configured. This is because more PCIe links shares + * one enable bit and some PCIe links cannot be enabled + * individually. + */ + if (mvebu_pcie_enable_link(pcie, subnode) < 0) { + free(pcie); + continue; + } /* Create child device UCLASS_PCI and bind it */ device_bind(parent, &pcie_mvebu_drv, pcie->name, pcie, subnode, &dev); } + free(ports_pcie); + free(ports_nodes); + return 0; } |