diff --git a/arch/arm/dts/armada-385-turris-omnia-u-boot.dtsi b/arch/arm/dts/armada-385-turris-omnia-u-boot.dtsi index 1b46797583..af0655daaa 100644 --- a/arch/arm/dts/armada-385-turris-omnia-u-boot.dtsi +++ b/arch/arm/dts/armada-385-turris-omnia-u-boot.dtsi @@ -41,10 +41,7 @@ &spi0 { u-boot,dm-pre-reloc; - spi-flash@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <40000000>; + spi-nor@0 { u-boot,dm-pre-reloc; }; }; diff --git a/board/CZ.NIC/turris_omnia/turris_omnia.c b/board/CZ.NIC/turris_omnia/turris_omnia.c index 0353d58a36..1d3cefe703 100644 --- a/board/CZ.NIC/turris_omnia/turris_omnia.c +++ b/board/CZ.NIC/turris_omnia/turris_omnia.c @@ -286,6 +286,7 @@ static struct mv_ddr_topology_map board_topology_map_1g = { MV_DDR_TIM_2T} }, /* timing */ BUS_MASK_32BIT, /* Busses mask */ MV_DDR_CFG_DEFAULT, /* ddr configuration data source */ + NOT_COMBINED, /* ddr twin-die combined */ { {0} }, /* raw spd data */ {0} /* timing parameters */ }; @@ -308,6 +309,7 @@ static struct mv_ddr_topology_map board_topology_map_2g = { MV_DDR_TIM_2T} }, /* timing */ BUS_MASK_32BIT, /* Busses mask */ MV_DDR_CFG_DEFAULT, /* ddr configuration data source */ + NOT_COMBINED, /* ddr twin-die combined */ { {0} }, /* raw spd data */ {0} /* timing parameters */ }; diff --git a/board/Marvell/db-88f6820-amc/db-88f6820-amc.c b/board/Marvell/db-88f6820-amc/db-88f6820-amc.c index 163a1b3de9..122c63d11f 100644 --- a/board/Marvell/db-88f6820-amc/db-88f6820-amc.c +++ b/board/Marvell/db-88f6820-amc/db-88f6820-amc.c @@ -73,6 +73,7 @@ static struct mv_ddr_topology_map board_topology_map = { MV_DDR_TIM_DEFAULT} }, /* timing */ BUS_MASK_32BIT, /* Busses mask */ MV_DDR_CFG_DEFAULT, /* ddr configuration data source */ + NOT_COMBINED, /* ddr twin-die combined */ { {0} }, /* raw spd data */ {0} /* timing parameters */ }; diff --git a/board/Marvell/db-88f6820-gp/db-88f6820-gp.c b/board/Marvell/db-88f6820-gp/db-88f6820-gp.c index 06307e582c..1edc1cb651 100644 --- a/board/Marvell/db-88f6820-gp/db-88f6820-gp.c +++ b/board/Marvell/db-88f6820-gp/db-88f6820-gp.c @@ -94,6 +94,7 @@ static struct mv_ddr_topology_map board_topology_map = { MV_DDR_TIM_DEFAULT} }, /* timing */ BUS_MASK_32BIT, /* Busses mask */ MV_DDR_CFG_DEFAULT, /* ddr configuration data source */ + NOT_COMBINED, /* ddr twin-die combined */ { {0} }, /* raw spd data */ {0} /* timing parameters */ }; diff --git a/board/alliedtelesis/x530/x530.c b/board/alliedtelesis/x530/x530.c index d602092d73..7bcfa828d7 100644 --- a/board/alliedtelesis/x530/x530.c +++ b/board/alliedtelesis/x530/x530.c @@ -68,6 +68,7 @@ static struct mv_ddr_topology_map board_topology_map = { MV_DDR_TIM_2T} }, /* timing */ BUS_MASK_32BIT_ECC, /* subphys mask */ MV_DDR_CFG_DEFAULT, /* ddr configuration data source */ + NOT_COMBINED, /* ddr twin-die combined */ { {0} }, /* raw spd data */ {0}, /* timing parameters */ { {0} }, /* electrical configuration */ diff --git a/board/gdsys/a38x/controlcenterdc.c b/board/gdsys/a38x/controlcenterdc.c index ba57a27218..4f1dc3b431 100644 --- a/board/gdsys/a38x/controlcenterdc.c +++ b/board/gdsys/a38x/controlcenterdc.c @@ -71,6 +71,7 @@ static struct mv_ddr_topology_map ddr_topology_map = { MV_DDR_TIM_DEFAULT} }, /* timing */ BUS_MASK_32BIT, /* Busses mask */ MV_DDR_CFG_DEFAULT, /* ddr configuration data source */ + NOT_COMBINED, /* ddr twin-die combined */ { {0} }, /* raw spd data */ {0} /* timing parameters */ diff --git a/board/kobol/helios4/helios4.c b/board/kobol/helios4/helios4.c index adb091ce4f..9c5b687b3e 100644 --- a/board/kobol/helios4/helios4.c +++ b/board/kobol/helios4/helios4.c @@ -71,6 +71,7 @@ static struct mv_ddr_topology_map board_topology_map = { MV_DDR_TIM_DEFAULT} }, /* timing */ BUS_MASK_32BIT_ECC, /* Busses mask */ MV_DDR_CFG_DEFAULT, /* ddr configuration data source */ + NOT_COMBINED, /* ddr twin-die combined */ { {0} }, /* raw spd data */ {0} /* timing parameters */ }; diff --git a/board/solidrun/clearfog/clearfog.c b/board/solidrun/clearfog/clearfog.c index 7b2accf01d..c920cf8d6b 100644 --- a/board/solidrun/clearfog/clearfog.c +++ b/board/solidrun/clearfog/clearfog.c @@ -142,6 +142,7 @@ static struct mv_ddr_topology_map board_topology_map = { MV_DDR_TIM_DEFAULT} }, /* timing */ BUS_MASK_32BIT, /* Busses mask */ MV_DDR_CFG_DEFAULT, /* ddr configuration data source */ + NOT_COMBINED, /* ddr twin-die combined */ { {0} }, /* raw spd data */ {0}, /* timing parameters */ { {0} }, /* electrical configuration */ diff --git a/configs/turris_mox_defconfig b/configs/turris_mox_defconfig index dde7437f24..f938fbb475 100644 --- a/configs/turris_mox_defconfig +++ b/configs/turris_mox_defconfig @@ -61,10 +61,10 @@ CONFIG_SPI_FLASH_WINBOND=y CONFIG_PHY_MARVELL=y CONFIG_PHY_GIGE=y CONFIG_MVNETA=y +CONFIG_NVME=y CONFIG_PCI=y CONFIG_DM_PCI=y CONFIG_PCI_AARDVARK=y -# CONFIG_PCI_PNP is not set CONFIG_MVEBU_COMPHY_SUPPORT=y CONFIG_PINCTRL=y CONFIG_PINCTRL_ARMADA_37XX=y @@ -78,6 +78,7 @@ CONFIG_MVEBU_A3700_SPI=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PCI=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_HOST_ETHER=y CONFIG_USB_ETHER_ASIX=y diff --git a/drivers/ddr/marvell/a38x/ddr3_init.c b/drivers/ddr/marvell/a38x/ddr3_init.c index a971cc155a..7488770268 100644 --- a/drivers/ddr/marvell/a38x/ddr3_init.c +++ b/drivers/ddr/marvell/a38x/ddr3_init.c @@ -104,6 +104,7 @@ int ddr3_init(void) static int mv_ddr_training_params_set(u8 dev_num) { struct tune_train_params params; + struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); int status; u32 cs_num; int ck_delay; @@ -136,6 +137,10 @@ static int mv_ddr_training_params_set(u8 dev_num) if (ck_delay > 0) params.ck_delay = ck_delay; + /* Use platform specific override ODT value */ + if (tm->odt_config) + params.g_odt_config = tm->odt_config; + status = ddr3_tip_tune_training_params(dev_num, ¶ms); if (MV_OK != status) { printf("%s Training Sequence - FAILED\n", ddr_type); diff --git a/drivers/ddr/marvell/a38x/ddr3_training.c b/drivers/ddr/marvell/a38x/ddr3_training.c index 34cc170910..2b3af23202 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training.c +++ b/drivers/ddr/marvell/a38x/ddr3_training.c @@ -143,6 +143,7 @@ static struct reg_data odpg_default_value[] = { {0x15a4, 0x0, MASK_ALL_BITS}, {0x15a8, 0x0, MASK_ALL_BITS}, {0x15ac, 0x0, MASK_ALL_BITS}, + {0x1600, 0x0, MASK_ALL_BITS}, {0x1604, 0x0, MASK_ALL_BITS}, {0x1608, 0x0, MASK_ALL_BITS}, {0x160c, 0x0, MASK_ALL_BITS}, @@ -218,7 +219,7 @@ static int ddr3_tip_pad_inv(void) DDR_PHY_CONTROL, PHY_CTRL_PHY_REG, data, data); -#else /* !CONFIG_ARMADA_38X && !CONFIG_ARMADA_39X && !A70X0 && !A80X0 && !A3900 */ +#else /* !CONFIG_ARMADA_38X && !CONFIG_ARMADA_39X */ #pragma message "unknown platform to configure ddr clock swap" #endif } @@ -1569,6 +1570,8 @@ int ddr3_tip_freq_set(u32 dev_num, enum hws_access_type access_type, val = ((cl_mask_table[cl_value] & 0x1) << 2) | ((cl_mask_table[cl_value] & 0xe) << 3); + cs_mask[0] = 0xc; + CHECK_STATUS(ddr3_tip_write_mrs_cmd(dev_num, cs_mask, MR_CMD0, val, (0x7 << 4) | (0x1 << 2))); diff --git a/drivers/ddr/marvell/a38x/ddr3_training_db.c b/drivers/ddr/marvell/a38x/ddr3_training_db.c index b2f11a8399..6aa7b6069e 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_db.c +++ b/drivers/ddr/marvell/a38x/ddr3_training_db.c @@ -833,6 +833,9 @@ u32 pattern_table_get_word(u32 dev_num, enum hws_pattern type, u8 index) pattern = pattern_table_get_isi_word16(index); break; default: + if (((int)type == 29) || ((int)type == 30)) + break; + printf("error: %s: unsupported pattern type [%d] found\n", __func__, (int)type); pattern = 0; diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h index 2a68669f36..8765df7cfb 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_def.h @@ -80,6 +80,8 @@ #define ADDR_SIZE_2GB 0x10000000 #define ADDR_SIZE_4GB 0x20000000 #define ADDR_SIZE_8GB 0x40000000 +#define ADDR_SIZE_16GB 0x80000000 + enum hws_edge_compare { EDGE_PF, diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c index 979f3530b7..5fd9a052fa 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_engine.c @@ -864,8 +864,11 @@ int ddr3_tip_load_all_pattern_to_mem(u32 dev_num) DUAL_DUNIT_CFG_REG, (1 << 3), (1 << 3))); } - for (pattern = 0; pattern < PATTERN_LAST; pattern++) + for (pattern = 0; pattern < PATTERN_LAST; pattern++) { + if (pattern == PATTERN_TEST) + continue; ddr3_tip_load_pattern_to_mem(dev_num, pattern); + } return MV_OK; } diff --git a/drivers/ddr/marvell/a38x/ddr_topology_def.h b/drivers/ddr/marvell/a38x/ddr_topology_def.h index 34196b1662..7f2317edfa 100644 --- a/drivers/ddr/marvell/a38x/ddr_topology_def.h +++ b/drivers/ddr/marvell/a38x/ddr_topology_def.h @@ -14,6 +14,11 @@ #define MV_DDR_MAX_BUS_NUM 9 #define MV_DDR_MAX_IFACE_NUM 1 +enum mv_ddr_twin_die { + NOT_COMBINED, + COMBINED, +}; + struct bus_params { /* Chip Select (CS) bitmask (bits 0-CS0, bit 1- CS1 ...) */ u8 cs_bitmask; @@ -113,6 +118,9 @@ struct mv_ddr_topology_map { /* source of ddr configuration data */ enum mv_ddr_cfg_src cfg_src; + /* ddr twin-die */ + enum mv_ddr_twin_die twin_die_combined; + /* raw spd data */ union mv_ddr_spd_data spd_data; @@ -125,6 +133,9 @@ struct mv_ddr_topology_map { /* electrical parameters */ unsigned int electrical_data[MV_DDR_EDATA_LAST]; + /* ODT configuration */ + u32 odt_config; + /* Clock enable mask */ u32 clk_enable; @@ -148,7 +159,13 @@ enum mv_ddr_validation { MV_DDR_VAL_DIS, MV_DDR_VAL_RX, MV_DDR_VAL_TX, - MV_DDR_VAL_RX_TX + MV_DDR_VAL_RX_TX, + MV_DDR_MEMORY_CHECK +}; + +enum mv_ddr_sscg { + SSCG_EN, + SSCG_DIS, }; struct mv_ddr_iface { @@ -179,8 +196,12 @@ struct mv_ddr_iface { /* ddr interface validation mode */ enum mv_ddr_validation validation; + /* ddr interface validation mode */ + enum mv_ddr_sscg sscg; + /* ddr interface topology map */ struct mv_ddr_topology_map tm; + }; struct mv_ddr_iface *mv_ddr_iface_get(void); diff --git a/drivers/ddr/marvell/a38x/mv_ddr_build_message.c b/drivers/ddr/marvell/a38x/mv_ddr_build_message.c index cc6234fd40..a2bb8a96a6 100644 --- a/drivers/ddr/marvell/a38x/mv_ddr_build_message.c +++ b/drivers/ddr/marvell/a38x/mv_ddr_build_message.c @@ -1,3 +1,3 @@ // SPDX-License-Identifier: GPL-2.0 const char mv_ddr_build_message[] = ""; -const char mv_ddr_version_string[] = "mv_ddr: mv_ddr-armada-18.09.2"; +const char mv_ddr_version_string[] = "mv_ddr: 14.0.0"; diff --git a/drivers/ddr/marvell/a38x/mv_ddr_plat.c b/drivers/ddr/marvell/a38x/mv_ddr_plat.c index 72f0dfbbbb..0d1df189e8 100644 --- a/drivers/ddr/marvell/a38x/mv_ddr_plat.c +++ b/drivers/ddr/marvell/a38x/mv_ddr_plat.c @@ -4,6 +4,7 @@ */ #include "ddr3_init.h" +#include "mv_ddr_common.h" #include "mv_ddr_training_db.h" #include "mv_ddr_regs.h" #include "mv_ddr_sys_env_lib.h" @@ -1016,7 +1017,7 @@ int ddr3_calc_mem_cs_size(u32 cs, uint64_t *cs_size) return MV_BAD_VALUE; } - *cs_size = cs_mem_size << 20; /* write cs size in bytes */ + *cs_size = cs_mem_size; return MV_OK; } @@ -1025,9 +1026,11 @@ static int ddr3_fast_path_dynamic_cs_size_config(u32 cs_ena) { u32 reg, cs; uint64_t mem_total_size = 0; + uint64_t cs_mem_size_mb = 0; uint64_t cs_mem_size = 0; uint64_t mem_total_size_c, cs_mem_size_c; + #ifdef DEVICE_MAX_DRAM_ADDRESS_SIZE u32 physical_mem_size; u32 max_mem_size = DEVICE_MAX_DRAM_ADDRESS_SIZE; @@ -1038,8 +1041,9 @@ static int ddr3_fast_path_dynamic_cs_size_config(u32 cs_ena) for (cs = 0; cs < MAX_CS_NUM; cs++) { if (cs_ena & (1 << cs)) { /* get CS size */ - if (ddr3_calc_mem_cs_size(cs, &cs_mem_size) != MV_OK) + if (ddr3_calc_mem_cs_size(cs, &cs_mem_size_mb) != MV_OK) return MV_FAIL; + cs_mem_size = cs_mem_size_mb * _1M; #ifdef DEVICE_MAX_DRAM_ADDRESS_SIZE /* @@ -1088,6 +1092,7 @@ static int ddr3_fast_path_dynamic_cs_size_config(u32 cs_ena) */ mem_total_size_c = (mem_total_size >> 16) & 0xffffffffffff; cs_mem_size_c = (cs_mem_size >> 16) & 0xffffffffffff; + /* if the sum less than 2 G - calculate the value */ if (mem_total_size_c + cs_mem_size_c < 0x10000) mem_total_size += cs_mem_size; diff --git a/drivers/ddr/marvell/a38x/mv_ddr_topology.c b/drivers/ddr/marvell/a38x/mv_ddr_topology.c index 09840b1e70..2db6283c23 100644 --- a/drivers/ddr/marvell/a38x/mv_ddr_topology.c +++ b/drivers/ddr/marvell/a38x/mv_ddr_topology.c @@ -127,6 +127,11 @@ int mv_ddr_topology_map_update(void) speed_bin_index = iface_params->speed_bin_index; freq = iface_params->memory_freq; + if (tm->twin_die_combined == COMBINED) { + iface_params->bus_width = MV_DDR_DEV_WIDTH_8BIT; + iface_params->memory_size -= 1; + } + if (iface_params->cas_l == 0) iface_params->cas_l = mv_ddr_cl_val_get(speed_bin_index, freq); @@ -144,6 +149,9 @@ unsigned short mv_ddr_bus_bit_mask_get(void) unsigned int octets_per_if_num = ddr3_tip_dev_attr_get(0, MV_ATTR_OCTET_PER_INTERFACE); if (tm->cfg_src == MV_DDR_CFG_SPD) { + if (tm->bus_act_mask == MV_DDR_32BIT_ECC_PUP8_BUS_MASK) + tm->spd_data.byte_fields.byte_13.bit_fields.primary_bus_width = MV_DDR_PRI_BUS_WIDTH_32; + enum mv_ddr_pri_bus_width pri_bus_width = mv_ddr_spd_pri_bus_width_get(&tm->spd_data); enum mv_ddr_bus_width_ext bus_width_ext = mv_ddr_spd_bus_width_ext_get(&tm->spd_data); @@ -151,7 +159,7 @@ unsigned short mv_ddr_bus_bit_mask_get(void) case MV_DDR_PRI_BUS_WIDTH_16: pri_and_ext_bus_width = BUS_MASK_16BIT; break; - case MV_DDR_PRI_BUS_WIDTH_32: + case MV_DDR_PRI_BUS_WIDTH_32: /*each bit represents byte, so 0xf-is means 4 bytes-32 bit*/ pri_and_ext_bus_width = BUS_MASK_32BIT; break; case MV_DDR_PRI_BUS_WIDTH_64: @@ -245,7 +253,8 @@ static unsigned int mem_size[] = { ADDR_SIZE_1GB, ADDR_SIZE_2GB, ADDR_SIZE_4GB, - ADDR_SIZE_8GB + ADDR_SIZE_8GB, + ADDR_SIZE_16GB /* TODO: add capacity up to 256GB */ }; @@ -277,7 +286,6 @@ unsigned long long mv_ddr_mem_sz_per_cs_get(void) mem_sz_per_cs = (unsigned long long)mem_size[iface_params->memory_size] * (unsigned long long)sphys / (unsigned long long)sphys_per_dunit; - return mem_sz_per_cs; } diff --git a/drivers/ddr/marvell/a38x/mv_ddr_topology.h b/drivers/ddr/marvell/a38x/mv_ddr_topology.h index 4fca47689f..1cb69ad085 100644 --- a/drivers/ddr/marvell/a38x/mv_ddr_topology.h +++ b/drivers/ddr/marvell/a38x/mv_ddr_topology.h @@ -179,7 +179,9 @@ enum mv_ddr_dic_evalue { /* phy electrical configuration values */ enum mv_ddr_ohm_evalue { + MV_DDR_OHM_20 = 20,/*relevant for Synopsys C/A Drive strength only*/ MV_DDR_OHM_30 = 30, + MV_DDR_OHM_40 = 40,/*relevant for Synopsys C/A Drive strength only*/ MV_DDR_OHM_48 = 48, MV_DDR_OHM_60 = 60, MV_DDR_OHM_80 = 80, diff --git a/drivers/ddr/marvell/a38x/xor.c b/drivers/ddr/marvell/a38x/xor.c index 5fb9e216d3..98fb39eaf0 100644 --- a/drivers/ddr/marvell/a38x/xor.c +++ b/drivers/ddr/marvell/a38x/xor.c @@ -340,7 +340,7 @@ void ddr3_new_tip_ecc_scrub(void) { u32 cs_c, max_cs; u32 cs_ena = 0; - uint64_t total_mem_size, cs_mem_size = 0; + uint64_t total_mem_size, cs_mem_size_mb = 0, cs_mem_size = 0; printf("DDR Training Sequence - Start scrubbing\n"); max_cs = mv_ddr_cs_num_get(); @@ -349,9 +349,9 @@ void ddr3_new_tip_ecc_scrub(void) #if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_39X) /* all chip-selects are of same size */ - ddr3_calc_mem_cs_size(0, &cs_mem_size); + ddr3_calc_mem_cs_size(0, &cs_mem_size_mb); #endif - + cs_mem_size = cs_mem_size_mb * _1M; mv_sys_xor_init(max_cs, cs_ena, cs_mem_size, 0); total_mem_size = max_cs * cs_mem_size; mv_xor_mem_init(0, 0, total_mem_size, 0xdeadbeef, 0xdeadbeef); diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c index 8713b88461..b4e1b60240 100644 --- a/drivers/pci/pci-aardvark.c +++ b/drivers/pci/pci-aardvark.c @@ -42,6 +42,10 @@ #define PCIE_CORE_DEV_CTRL_STATS_REG 0xc8 #define PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE (0 << 4) #define PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE (0 << 11) +#define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SIZE 0x2 +#define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SIZE_SHIFT 5 +#define PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE 0x2 +#define PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT 12 #define PCIE_CORE_LINK_CTRL_STAT_REG 0xd0 #define PCIE_CORE_LINK_TRAINING BIT(5) #define PCIE_CORE_ERR_CAPCTL_REG 0x118 @@ -534,6 +538,10 @@ static int pcie_advk_setup_hw(struct pcie_advk *pcie) /* Set PCIe Device Control and Status 1 PF0 register */ reg = PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE | + (PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SIZE << + PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SIZE_SHIFT) | + (PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE << + PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT) | PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE; advk_writel(pcie, reg, PCIE_CORE_DEV_CTRL_STATS_REG); diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index 235d9bb90c..0c1d7cd770 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -79,7 +79,8 @@ struct mvebu_pcie { u32 lane; int devfn; u32 lane_mask; - pci_dev_t dev; + int first_busno; + int local_dev; char name[16]; unsigned int mem_target; unsigned int mem_attr; @@ -144,38 +145,47 @@ static inline struct mvebu_pcie *hose_to_pcie(struct pci_controller *hose) return container_of(hose, struct mvebu_pcie, hose); } +static int mvebu_pcie_valid_addr(struct mvebu_pcie *pcie, pci_dev_t bdf) +{ + /* + * There are two devices visible on local bus: + * * on slot configured by function mvebu_pcie_set_local_dev_nr() + * (by default this register is set to 0) there is a + * "Marvell Memory controller", which isn't useful in root complex + * mode, + * * on all other slots the real PCIe card connected to the PCIe slot. + * + * We therefore allow access only to the real PCIe card. + */ + if (PCI_BUS(bdf) == pcie->first_busno && + PCI_DEV(bdf) != !pcie->local_dev) + return 0; + + return 1; +} + static int mvebu_pcie_read_config(const struct udevice *bus, pci_dev_t bdf, uint offset, ulong *valuep, enum pci_size_t size) { struct mvebu_pcie *pcie = dev_get_plat(bus); - int local_bus = PCI_BUS(pcie->dev); - int local_dev = PCI_DEV(pcie->dev); - u32 reg; u32 data; - debug("PCIE CFG read: loc_bus=%d loc_dev=%d (b,d,f)=(%2d,%2d,%2d) ", - local_bus, local_dev, PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); + debug("PCIE CFG read: (b,d,f)=(%2d,%2d,%2d) ", + PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - /* Don't access the local host controller via this API */ - if (PCI_BUS(bdf) == local_bus && PCI_DEV(bdf) == local_dev) { - debug("- skipping host controller\n"); - *valuep = pci_get_ff(size); - return 0; - } - - /* If local dev is 0, the first other dev can only be 1 */ - if (PCI_BUS(bdf) == local_bus && local_dev == 0 && PCI_DEV(bdf) != 1) { + if (!mvebu_pcie_valid_addr(pcie, bdf)) { debug("- out of range\n"); *valuep = pci_get_ff(size); return 0; } /* write address */ - reg = PCIE_CONF_ADDR(bdf, offset); - writel(reg, pcie->base + PCIE_CONF_ADDR_OFF); + writel(PCIE_CONF_ADDR(bdf, offset), pcie->base + PCIE_CONF_ADDR_OFF); + + /* read data */ data = readl(pcie->base + PCIE_CONF_DATA_OFF); - debug("(addr,val)=(0x%04x, 0x%08x)\n", offset, data); + debug("(addr,size,val)=(0x%04x, %d, 0x%08x)\n", offset, size, data); *valuep = pci_conv_32_to_size(data, offset, size); return 0; @@ -186,27 +196,21 @@ static int mvebu_pcie_write_config(struct udevice *bus, pci_dev_t bdf, enum pci_size_t size) { struct mvebu_pcie *pcie = dev_get_plat(bus); - int local_bus = PCI_BUS(pcie->dev); - int local_dev = PCI_DEV(pcie->dev); u32 data; - debug("PCIE CFG write: loc_bus=%d loc_dev=%d (b,d,f)=(%2d,%2d,%2d) ", - local_bus, local_dev, PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value); + debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ", + PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); + debug("(addr,size,val)=(0x%04x, %d, 0x%08lx)\n", offset, size, value); - /* Don't access the local host controller via this API */ - if (PCI_BUS(bdf) == local_bus && PCI_DEV(bdf) == local_dev) { - debug("- skipping host controller\n"); - return 0; - } - - /* If local dev is 0, the first other dev can only be 1 */ - if (PCI_BUS(bdf) == local_bus && local_dev == 0 && PCI_DEV(bdf) != 1) { + if (!mvebu_pcie_valid_addr(pcie, bdf)) { debug("- out of range\n"); return 0; } + /* write address */ writel(PCIE_CONF_ADDR(bdf, offset), pcie->base + PCIE_CONF_ADDR_OFF); + + /* write data */ data = pci_conv_size_to_32(0, value, offset, size); writel(data, pcie->base + PCIE_CONF_DATA_OFF); @@ -273,7 +277,7 @@ 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); - static int bus; + int bus = dev_seq(dev); u32 reg; debug("%s: PCIe %d.%d - up, base %08x\n", __func__, @@ -284,9 +288,11 @@ static int mvebu_pcie_probe(struct udevice *dev) readl(pcie->base), mvebu_pcie_get_local_bus_nr(pcie), mvebu_pcie_get_local_dev_nr(pcie)); + pcie->first_busno = bus; + pcie->local_dev = 1; + mvebu_pcie_set_local_bus_nr(pcie, bus); - mvebu_pcie_set_local_dev_nr(pcie, 0); - pcie->dev = PCI_BDF(bus, 0, 0); + mvebu_pcie_set_local_dev_nr(pcie, pcie->local_dev); pcie->mem.start = (u32)mvebu_pcie_membase; pcie->mem.end = pcie->mem.start + PCIE_MEM_SIZE - 1; @@ -336,8 +342,6 @@ static int mvebu_pcie_probe(struct udevice *dev) writel(SOC_REGS_PHY_BASE, pcie->base + PCIE_BAR_LO_OFF(0)); writel(0, pcie->base + PCIE_BAR_HI_OFF(0)); - bus++; - return 0; }