blob: 1fed02f5c6e95cab2d4c1713b930d271cb65252b [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __SOC_INTEL_COMMON_BLOCK_MEMINIT_H__
#define __SOC_INTEL_COMMON_BLOCK_MEMINIT_H__
#include <types.h>
/*
* Calculates the number of channels depending upon the data bus width of the
* platform and the channel width.
*/
#define CHANNEL_COUNT(ch_width) (CONFIG_DATA_BUS_WIDTH / (ch_width))
/*
* UPDs for FSP-M are organized depending upon the MRC's view of channel. Thus,
* the number of channels as seen by the MRC are dependent on the channel width
* assumption in the UPDs. These channels might not necessarily be the same as
* the physical channels supported by the platform.
*/
#define MRC_CHANNELS CHANNEL_COUNT(CONFIG_MRC_CHANNEL_WIDTH)
/* Different memory topologies supported by the platform. */
enum mem_topology {
MEM_TOPO_MEMORY_DOWN = BIT(0),
MEM_TOPO_DIMM_MODULE = BIT(1),
MEM_TOPO_MIXED = MEM_TOPO_MEMORY_DOWN | MEM_TOPO_DIMM_MODULE,
};
/*
* SPD provides information about the memory module. Depending upon the memory
* topology, the SPD data can be obtained from different sources. Example: for
* memory down topology, SPD is read from CBFS using cbfs_index. For DIMM
* modules, SPD is read from EEPROM using the DIMM addresses provided by the
* mainboard.
*/
struct mem_spd {
enum mem_topology topo;
/*
* SPD data is read from CBFS spd.bin file using cbfs_index to locate
* the entry. This is used in case of MEM_TOPO_MEMORY_DOWN and
* MEM_TOPO_MIXED topologies.
*/
size_t cbfs_index;
/*
* SPD data is read from on-module EEPROM using the DIMM addresses
* provided by the mainboard. This is used in case of
* MEM_TOPO_DIMM_MODULE and MEM_TOPO_MIXED topologies.
*
* Up to a maximum of MRC_CHANNELS * CONFIG_DIMMS_PER_CHANNEL addresses
* can be provided by mainboard. However, depending upon the memory
* technology being used and the number of physical channels supported
* by that technology, the actual channels might be less than
* MRC_CHANNELS.
*/
struct {
uint8_t addr_dimm[CONFIG_DIMMS_PER_CHANNEL];
} smbus[MRC_CHANNELS];
};
/* Information about memory technology supported by SoC */
struct soc_mem_cfg {
/*
* Number of physical channels that are supported by the memory
* technology.
*/
size_t num_phys_channels;
/*
* Map of physical channel numbers to MRC channel numbers. This is
* helpful in identifying what SPD entries need to be filled for a
* physical channel.
*
* Example: MRC supports 8 channels 0 - 7, but a memory technology
* supports only 2 physical channels 0 - 1. In this case, the map could
* be:
* [0] = 0,
* [1] = 4,
* indicating that physical channel 0 is mapped to MRC channel 0 and
* physical channel 1 is mapped to MRC channel 4.
*/
size_t phys_to_mrc_map[MRC_CHANNELS];
/*
* Masks to be applied in case of memory down topology. For memory down
* topology, there is no separate EEPROM. Thus, the masks need to be
* hard-coded by the SoC to indicate what combinations are supported.
* This is a mask of physical channels for the memory technology.
*
* Example: For the memory technology supporting 2 physical channels,
* where the population rules restrict use of channel 0 for
* half-channel, half_channel mask would be set to 0x1 indicating
* channel 0 is always populated.
*/
struct {
/*
* Mask of physical channels that are populated in case of
* half-channel configuration.
*/
uint32_t half_channel;
/*
* Mask of physical channels that are populated with memory
* down parts in case of mixed topology.
*/
uint32_t mixed_topo;
} md_phy_masks;
};
/* Flags indicating how the channels are populated. */
enum channel_population {
NO_CHANNEL_POPULATED = 0,
TOP_HALF_POPULATED = BIT(0),
BOTTOM_HALF_POPULATED = BIT(1),
FULLY_POPULATED = TOP_HALF_POPULATED | BOTTOM_HALF_POPULATED,
};
/*
* Data for the memory channels that can be used by SoC code to populate FSP
* UPDs.
*/
struct mem_channel_data {
/* Pointer to SPD data for each DIMM of each channel */
uintptr_t spd[MRC_CHANNELS][CONFIG_DIMMS_PER_CHANNEL];
/* Length of SPD data */
size_t spd_len;
/* Flags indicating how channels are populated */
enum channel_population ch_population_flags;
};
/*
* This change populates data regarding memory channels in `struct
* mem_channel_data` using the following inputs from SoC code:
* soc_mem_cfg : SoC-specific information about the memory technology used by
* the mainboard.
* spd_info : Information about the memory topology.
* half_populated: Hint from mainboard if channels are half populated.
*/
void mem_populate_channel_data(const struct soc_mem_cfg *soc_mem_cfg,
const struct mem_spd *spd_info,
bool half_populated,
struct mem_channel_data *data);
/*
* Given a channel number and the maximum number of supported channels, this
* function returns if a channel is populated. This is useful for populating
* DQ/DQS UPDs by the SoC code.
*/
static inline bool channel_is_populated(size_t curr_ch, size_t max_ch,
enum channel_population flags)
{
if ((curr_ch * 2) < max_ch)
return !!(flags & BOTTOM_HALF_POPULATED);
return !!(flags & TOP_HALF_POPULATED);
}
#endif /* __SOC_INTEL_COMMON_BLOCK_MEMINIT_H__ */