Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

memory: Add LPDDR2-info helpers

Add common helpers for reading and parsing standard LPDDR2 configuration
properties.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Link: https://lore.kernel.org/r/20211006224659.21434-9-digetx@gmail.com
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>

authored by

Dmitry Osipenko and committed by
Krzysztof Kozlowski
38322cf4 ce004ae6

+184
+47
drivers/memory/jedec_ddr.h
··· 112 112 #define NUM_DDR_ADDR_TABLE_ENTRIES 11 113 113 #define NUM_DDR_TIMING_TABLE_ENTRIES 4 114 114 115 + #define LPDDR2_MANID_SAMSUNG 1 116 + #define LPDDR2_MANID_QIMONDA 2 117 + #define LPDDR2_MANID_ELPIDA 3 118 + #define LPDDR2_MANID_ETRON 4 119 + #define LPDDR2_MANID_NANYA 5 120 + #define LPDDR2_MANID_HYNIX 6 121 + #define LPDDR2_MANID_MOSEL 7 122 + #define LPDDR2_MANID_WINBOND 8 123 + #define LPDDR2_MANID_ESMT 9 124 + #define LPDDR2_MANID_SPANSION 11 125 + #define LPDDR2_MANID_SST 12 126 + #define LPDDR2_MANID_ZMOS 13 127 + #define LPDDR2_MANID_INTEL 14 128 + #define LPDDR2_MANID_NUMONYX 254 129 + #define LPDDR2_MANID_MICRON 255 130 + 131 + #define LPDDR2_TYPE_S4 0 132 + #define LPDDR2_TYPE_S2 1 133 + #define LPDDR2_TYPE_NVM 2 134 + 115 135 /* Structure for DDR addressing info from the JEDEC spec */ 116 136 struct lpddr2_addressing { 117 137 u32 num_banks; ··· 189 169 extern const struct lpddr2_timings 190 170 lpddr2_jedec_timings[NUM_DDR_TIMING_TABLE_ENTRIES]; 191 171 extern const struct lpddr2_min_tck lpddr2_jedec_min_tck; 172 + 173 + /* Structure of MR8 */ 174 + union lpddr2_basic_config4 { 175 + u32 value; 176 + 177 + struct { 178 + unsigned int arch_type : 2; 179 + unsigned int density : 4; 180 + unsigned int io_width : 2; 181 + } __packed; 182 + }; 183 + 184 + /* 185 + * Structure for information about LPDDR2 chip. All parameters are 186 + * matching raw values of standard mode register bitfields or set to 187 + * -ENOENT if info unavailable. 188 + */ 189 + struct lpddr2_info { 190 + int arch_type; 191 + int density; 192 + int io_width; 193 + int manufacturer_id; 194 + int revision_id1; 195 + int revision_id2; 196 + }; 197 + 198 + const char *lpddr2_jedec_manufacturer(unsigned int manufacturer_id); 192 199 193 200 /* 194 201 * Structure for timings for LPDDR3 based on LPDDR2 plus additional fields.
+41
drivers/memory/jedec_ddr_data.c
··· 131 131 .tFAW = 8 132 132 }; 133 133 EXPORT_SYMBOL_GPL(lpddr2_jedec_min_tck); 134 + 135 + const char *lpddr2_jedec_manufacturer(unsigned int manufacturer_id) 136 + { 137 + switch (manufacturer_id) { 138 + case LPDDR2_MANID_SAMSUNG: 139 + return "Samsung"; 140 + case LPDDR2_MANID_QIMONDA: 141 + return "Qimonda"; 142 + case LPDDR2_MANID_ELPIDA: 143 + return "Elpida"; 144 + case LPDDR2_MANID_ETRON: 145 + return "Etron"; 146 + case LPDDR2_MANID_NANYA: 147 + return "Nanya"; 148 + case LPDDR2_MANID_HYNIX: 149 + return "Hynix"; 150 + case LPDDR2_MANID_MOSEL: 151 + return "Mosel"; 152 + case LPDDR2_MANID_WINBOND: 153 + return "Winbond"; 154 + case LPDDR2_MANID_ESMT: 155 + return "ESMT"; 156 + case LPDDR2_MANID_SPANSION: 157 + return "Spansion"; 158 + case LPDDR2_MANID_SST: 159 + return "SST"; 160 + case LPDDR2_MANID_ZMOS: 161 + return "ZMOS"; 162 + case LPDDR2_MANID_INTEL: 163 + return "Intel"; 164 + case LPDDR2_MANID_NUMONYX: 165 + return "Numonyx"; 166 + case LPDDR2_MANID_MICRON: 167 + return "Micron"; 168 + default: 169 + break; 170 + } 171 + 172 + return "invalid"; 173 + } 174 + EXPORT_SYMBOL_GPL(lpddr2_jedec_manufacturer);
+87
drivers/memory/of_memory.c
··· 298 298 return NULL; 299 299 } 300 300 EXPORT_SYMBOL(of_lpddr3_get_ddr_timings); 301 + 302 + /** 303 + * of_lpddr2_get_info() - extracts information about the lpddr2 chip. 304 + * @np: Pointer to device tree node containing lpddr2 info 305 + * @dev: Device requesting info 306 + * 307 + * Populates lpddr2_info structure by extracting data from device 308 + * tree node. Returns pointer to populated structure. If error 309 + * happened while populating, returns NULL. If property is missing 310 + * in a device-tree, then the corresponding value is set to -ENOENT. 311 + */ 312 + const struct lpddr2_info 313 + *of_lpddr2_get_info(struct device_node *np, struct device *dev) 314 + { 315 + struct lpddr2_info *ret_info, info = {}; 316 + struct property *prop; 317 + const char *cp; 318 + int err; 319 + 320 + err = of_property_read_u32(np, "revision-id1", &info.revision_id1); 321 + if (err) 322 + info.revision_id1 = -ENOENT; 323 + 324 + err = of_property_read_u32(np, "revision-id2", &info.revision_id2); 325 + if (err) 326 + info.revision_id2 = -ENOENT; 327 + 328 + err = of_property_read_u32(np, "io-width", &info.io_width); 329 + if (err) 330 + return NULL; 331 + 332 + info.io_width = 32 / info.io_width - 1; 333 + 334 + err = of_property_read_u32(np, "density", &info.density); 335 + if (err) 336 + return NULL; 337 + 338 + info.density = ffs(info.density) - 7; 339 + 340 + if (of_device_is_compatible(np, "jedec,lpddr2-s4")) 341 + info.arch_type = LPDDR2_TYPE_S4; 342 + else if (of_device_is_compatible(np, "jedec,lpddr2-s2")) 343 + info.arch_type = LPDDR2_TYPE_S2; 344 + else if (of_device_is_compatible(np, "jedec,lpddr2-nvm")) 345 + info.arch_type = LPDDR2_TYPE_NVM; 346 + else 347 + return NULL; 348 + 349 + prop = of_find_property(np, "compatible", NULL); 350 + for (cp = of_prop_next_string(prop, NULL); cp; 351 + cp = of_prop_next_string(prop, cp)) { 352 + 353 + #define OF_LPDDR2_VENDOR_CMP(compat, ID) \ 354 + if (!of_compat_cmp(cp, compat ",", strlen(compat ","))) { \ 355 + info.manufacturer_id = LPDDR2_MANID_##ID; \ 356 + break; \ 357 + } 358 + 359 + OF_LPDDR2_VENDOR_CMP("samsung", SAMSUNG) 360 + OF_LPDDR2_VENDOR_CMP("qimonda", QIMONDA) 361 + OF_LPDDR2_VENDOR_CMP("elpida", ELPIDA) 362 + OF_LPDDR2_VENDOR_CMP("etron", ETRON) 363 + OF_LPDDR2_VENDOR_CMP("nanya", NANYA) 364 + OF_LPDDR2_VENDOR_CMP("hynix", HYNIX) 365 + OF_LPDDR2_VENDOR_CMP("mosel", MOSEL) 366 + OF_LPDDR2_VENDOR_CMP("winbond", WINBOND) 367 + OF_LPDDR2_VENDOR_CMP("esmt", ESMT) 368 + OF_LPDDR2_VENDOR_CMP("spansion", SPANSION) 369 + OF_LPDDR2_VENDOR_CMP("sst", SST) 370 + OF_LPDDR2_VENDOR_CMP("zmos", ZMOS) 371 + OF_LPDDR2_VENDOR_CMP("intel", INTEL) 372 + OF_LPDDR2_VENDOR_CMP("numonyx", NUMONYX) 373 + OF_LPDDR2_VENDOR_CMP("micron", MICRON) 374 + 375 + #undef OF_LPDDR2_VENDOR_CMP 376 + } 377 + 378 + if (!info.manufacturer_id) 379 + info.manufacturer_id = -ENOENT; 380 + 381 + ret_info = devm_kzalloc(dev, sizeof(*ret_info), GFP_KERNEL); 382 + if (ret_info) 383 + *ret_info = info; 384 + 385 + return ret_info; 386 + } 387 + EXPORT_SYMBOL(of_lpddr2_get_info);
+9
drivers/memory/of_memory.h
··· 20 20 const struct lpddr3_timings * 21 21 of_lpddr3_get_ddr_timings(struct device_node *np_ddr, 22 22 struct device *dev, u32 device_type, u32 *nr_frequencies); 23 + 24 + const struct lpddr2_info *of_lpddr2_get_info(struct device_node *np, 25 + struct device *dev); 23 26 #else 24 27 static inline const struct lpddr2_min_tck 25 28 *of_get_min_tck(struct device_node *np, struct device *dev) ··· 46 43 static inline const struct lpddr3_timings 47 44 *of_lpddr3_get_ddr_timings(struct device_node *np_ddr, 48 45 struct device *dev, u32 device_type, u32 *nr_frequencies) 46 + { 47 + return NULL; 48 + } 49 + 50 + static inline const struct lpddr2_info 51 + *of_lpddr2_get_info(struct device_node *np, struct device *dev) 49 52 { 50 53 return NULL; 51 54 }