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

memory: Add STM32 Octo Memory Manager driver

Octo Memory Manager driver (OMM) manages:
- the muxing between 2 OSPI busses and 2 output ports.
There are 4 possible muxing configurations:
- direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
output is on port 2
- OSPI1 and OSPI2 are multiplexed over the same output port 1
- swapped mode (no multiplexing), OSPI1 output is on port 2,
OSPI2 output is on port 1
- OSPI1 and OSPI2 are multiplexed over the same output port 2
- the split of the memory area shared between the 2 OSPI instances.
- chip select selection override.
- the time between 2 transactions in multiplexed mode.
- check firewall access.

Signed-off-by: Christophe Kerello <christophe.kerello@foss.st.com>
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
Link: https://lore.kernel.org/r/20250428-upstream_ospi_v6-v11-2-1548736fd9d2@foss.st.com
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

authored by

Patrice Chotard and committed by
Krzysztof Kozlowski
8181d061 4a98ec83

+494
+17
drivers/memory/Kconfig
··· 225 225 devices (like SRAM, ethernet adapters, FPGAs, LCD displays, ...) on 226 226 SOCs containing the FMC2 External Bus Interface. 227 227 228 + config STM32_OMM 229 + tristate "STM32 Octo Memory Manager" 230 + depends on SPI_STM32_OSPI || COMPILE_TEST 231 + help 232 + This driver manages the muxing between the 2 OSPI busses and 233 + the 2 output ports. There are 4 possible muxing configurations: 234 + - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2 235 + output is on port 2 236 + - OSPI1 and OSPI2 are multiplexed over the same output port 1 237 + - swapped mode (no multiplexing), OSPI1 output is on port 2, 238 + OSPI2 output is on port 1 239 + - OSPI1 and OSPI2 are multiplexed over the same output port 2 240 + It also manages : 241 + - the split of the memory area shared between the 2 OSPI instances. 242 + - chip select selection override. 243 + - the time between 2 transactions in multiplexed mode. 244 + 228 245 source "drivers/memory/samsung/Kconfig" 229 246 source "drivers/memory/tegra/Kconfig" 230 247
+1
drivers/memory/Makefile
··· 24 24 obj-$(CONFIG_PL353_SMC) += pl353-smc.o 25 25 obj-$(CONFIG_RENESAS_RPCIF) += renesas-rpc-if.o 26 26 obj-$(CONFIG_STM32_FMC2_EBI) += stm32-fmc2-ebi.o 27 + obj-$(CONFIG_STM32_OMM) += stm32_omm.o 27 28 28 29 obj-$(CONFIG_SAMSUNG_MC) += samsung/ 29 30 obj-$(CONFIG_TEGRA_MC) += tegra/
+476
drivers/memory/stm32_omm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) STMicroelectronics 2025 - All Rights Reserved 4 + * Author(s): Patrice Chotard <patrice.chotard@foss.st.com> for STMicroelectronics. 5 + */ 6 + 7 + #include <linux/bitfield.h> 8 + #include <linux/bus/stm32_firewall_device.h> 9 + #include <linux/clk.h> 10 + #include <linux/err.h> 11 + #include <linux/mfd/syscon.h> 12 + #include <linux/mod_devicetable.h> 13 + #include <linux/module.h> 14 + #include <linux/of_address.h> 15 + #include <linux/of_platform.h> 16 + #include <linux/pinctrl/consumer.h> 17 + #include <linux/pm_runtime.h> 18 + #include <linux/regmap.h> 19 + #include <linux/reset.h> 20 + 21 + #define OMM_CR 0 22 + #define CR_MUXEN BIT(0) 23 + #define CR_MUXENMODE_MASK GENMASK(1, 0) 24 + #define CR_CSSEL_OVR_EN BIT(4) 25 + #define CR_CSSEL_OVR_MASK GENMASK(6, 5) 26 + #define CR_REQ2ACK_MASK GENMASK(23, 16) 27 + 28 + #define OMM_CHILD_NB 2 29 + #define OMM_CLK_NB 3 30 + 31 + struct stm32_omm { 32 + struct resource *mm_res; 33 + struct clk_bulk_data clk_bulk[OMM_CLK_NB]; 34 + struct reset_control *child_reset[OMM_CHILD_NB]; 35 + void __iomem *io_base; 36 + u32 cr; 37 + u8 nb_child; 38 + bool restore_omm; 39 + }; 40 + 41 + static int stm32_omm_set_amcr(struct device *dev, bool set) 42 + { 43 + struct stm32_omm *omm = dev_get_drvdata(dev); 44 + resource_size_t mm_ospi2_size = 0; 45 + static const char * const mm_name[] = { "ospi1", "ospi2" }; 46 + struct regmap *syscfg_regmap; 47 + struct device_node *node; 48 + struct resource res, res1; 49 + u32 amcr_base, amcr_mask; 50 + int ret, idx; 51 + unsigned int i, amcr, read_amcr; 52 + 53 + for (i = 0; i < omm->nb_child; i++) { 54 + idx = of_property_match_string(dev->of_node, 55 + "memory-region-names", 56 + mm_name[i]); 57 + if (idx < 0) 58 + continue; 59 + 60 + /* res1 only used on second loop iteration */ 61 + res1.start = res.start; 62 + res1.end = res.end; 63 + 64 + node = of_parse_phandle(dev->of_node, "memory-region", idx); 65 + if (!node) 66 + continue; 67 + 68 + ret = of_address_to_resource(node, 0, &res); 69 + if (ret) { 70 + of_node_put(node); 71 + dev_err(dev, "unable to resolve memory region\n"); 72 + return ret; 73 + } 74 + 75 + /* check that memory region fits inside OMM memory map area */ 76 + if (!resource_contains(omm->mm_res, &res)) { 77 + dev_err(dev, "%s doesn't fit inside OMM memory map area\n", 78 + mm_name[i]); 79 + dev_err(dev, "%pR doesn't fit inside %pR\n", &res, omm->mm_res); 80 + of_node_put(node); 81 + 82 + return -EFAULT; 83 + } 84 + 85 + if (i == 1) { 86 + mm_ospi2_size = resource_size(&res); 87 + 88 + /* check that OMM memory region 1 doesn't overlap memory region 2 */ 89 + if (resource_overlaps(&res, &res1)) { 90 + dev_err(dev, "OMM memory-region %s overlaps memory region %s\n", 91 + mm_name[0], mm_name[1]); 92 + dev_err(dev, "%pR overlaps %pR\n", &res1, &res); 93 + of_node_put(node); 94 + 95 + return -EFAULT; 96 + } 97 + } 98 + of_node_put(node); 99 + } 100 + 101 + syscfg_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "st,syscfg-amcr"); 102 + if (IS_ERR(syscfg_regmap)) 103 + return dev_err_probe(dev, PTR_ERR(syscfg_regmap), 104 + "Failed to get st,syscfg-amcr property\n"); 105 + 106 + ret = of_property_read_u32_index(dev->of_node, "st,syscfg-amcr", 1, 107 + &amcr_base); 108 + if (ret) 109 + return ret; 110 + 111 + ret = of_property_read_u32_index(dev->of_node, "st,syscfg-amcr", 2, 112 + &amcr_mask); 113 + if (ret) 114 + return ret; 115 + 116 + amcr = mm_ospi2_size / SZ_64M; 117 + 118 + if (set) 119 + regmap_update_bits(syscfg_regmap, amcr_base, amcr_mask, amcr); 120 + 121 + /* read AMCR and check coherency with memory-map areas defined in DT */ 122 + regmap_read(syscfg_regmap, amcr_base, &read_amcr); 123 + read_amcr = read_amcr >> (ffs(amcr_mask) - 1); 124 + 125 + if (amcr != read_amcr) { 126 + dev_err(dev, "AMCR value not coherent with DT memory-map areas\n"); 127 + ret = -EINVAL; 128 + } 129 + 130 + return ret; 131 + } 132 + 133 + static int stm32_omm_toggle_child_clock(struct device *dev, bool enable) 134 + { 135 + struct stm32_omm *omm = dev_get_drvdata(dev); 136 + int i, ret; 137 + 138 + for (i = 0; i < omm->nb_child; i++) { 139 + if (enable) { 140 + ret = clk_prepare_enable(omm->clk_bulk[i + 1].clk); 141 + if (ret) { 142 + dev_err(dev, "Can not enable clock\n"); 143 + goto clk_error; 144 + } 145 + } else { 146 + clk_disable_unprepare(omm->clk_bulk[i + 1].clk); 147 + } 148 + } 149 + 150 + return 0; 151 + 152 + clk_error: 153 + while (i--) 154 + clk_disable_unprepare(omm->clk_bulk[i + 1].clk); 155 + 156 + return ret; 157 + } 158 + 159 + static int stm32_omm_disable_child(struct device *dev) 160 + { 161 + struct stm32_omm *omm = dev_get_drvdata(dev); 162 + struct reset_control *reset; 163 + int ret; 164 + u8 i; 165 + 166 + ret = stm32_omm_toggle_child_clock(dev, true); 167 + if (!ret) 168 + return ret; 169 + 170 + for (i = 0; i < omm->nb_child; i++) { 171 + /* reset OSPI to ensure CR_EN bit is set to 0 */ 172 + reset = omm->child_reset[i]; 173 + ret = reset_control_acquire(reset); 174 + if (ret) { 175 + stm32_omm_toggle_child_clock(dev, false); 176 + dev_err(dev, "Can not acquire resset %d\n", ret); 177 + return ret; 178 + } 179 + 180 + reset_control_assert(reset); 181 + udelay(2); 182 + reset_control_deassert(reset); 183 + 184 + reset_control_release(reset); 185 + } 186 + 187 + return stm32_omm_toggle_child_clock(dev, false); 188 + } 189 + 190 + static int stm32_omm_configure(struct device *dev) 191 + { 192 + static const char * const clocks_name[] = {"omm", "ospi1", "ospi2"}; 193 + struct stm32_omm *omm = dev_get_drvdata(dev); 194 + unsigned long clk_rate_max = 0; 195 + u32 mux = 0; 196 + u32 cssel_ovr = 0; 197 + u32 req2ack = 0; 198 + struct reset_control *rstc; 199 + unsigned long clk_rate; 200 + int ret; 201 + u8 i; 202 + 203 + for (i = 0; i < OMM_CLK_NB; i++) 204 + omm->clk_bulk[i].id = clocks_name[i]; 205 + 206 + /* retrieve OMM, OSPI1 and OSPI2 clocks */ 207 + ret = devm_clk_bulk_get(dev, OMM_CLK_NB, omm->clk_bulk); 208 + if (ret) 209 + return dev_err_probe(dev, ret, "Failed to get OMM/OSPI's clocks\n"); 210 + 211 + /* Ensure both OSPI instance are disabled before configuring OMM */ 212 + ret = stm32_omm_disable_child(dev); 213 + if (ret) 214 + return ret; 215 + 216 + ret = pm_runtime_resume_and_get(dev); 217 + if (ret < 0) 218 + return ret; 219 + 220 + /* parse children's clock */ 221 + for (i = 1; i <= omm->nb_child; i++) { 222 + clk_rate = clk_get_rate(omm->clk_bulk[i].clk); 223 + if (!clk_rate) { 224 + dev_err(dev, "Invalid clock rate\n"); 225 + goto error; 226 + } 227 + 228 + if (clk_rate > clk_rate_max) 229 + clk_rate_max = clk_rate; 230 + } 231 + 232 + rstc = devm_reset_control_get_exclusive(dev, "omm"); 233 + if (IS_ERR(rstc)) 234 + return dev_err_probe(dev, PTR_ERR(rstc), "reset get failed\n"); 235 + 236 + reset_control_assert(rstc); 237 + udelay(2); 238 + reset_control_deassert(rstc); 239 + 240 + omm->cr = readl_relaxed(omm->io_base + OMM_CR); 241 + /* optional */ 242 + ret = of_property_read_u32(dev->of_node, "st,omm-mux", &mux); 243 + if (!ret) { 244 + if (mux & CR_MUXEN) { 245 + ret = of_property_read_u32(dev->of_node, "st,omm-req2ack-ns", 246 + &req2ack); 247 + if (!ret && !req2ack) { 248 + req2ack = DIV_ROUND_UP(req2ack, NSEC_PER_SEC / clk_rate_max) - 1; 249 + 250 + if (req2ack > 256) 251 + req2ack = 256; 252 + } 253 + 254 + req2ack = FIELD_PREP(CR_REQ2ACK_MASK, req2ack); 255 + 256 + omm->cr &= ~CR_REQ2ACK_MASK; 257 + omm->cr |= FIELD_PREP(CR_REQ2ACK_MASK, req2ack); 258 + 259 + /* 260 + * If the mux is enabled, the 2 OSPI clocks have to be 261 + * always enabled 262 + */ 263 + ret = stm32_omm_toggle_child_clock(dev, true); 264 + if (ret) 265 + goto error; 266 + } 267 + 268 + omm->cr &= ~CR_MUXENMODE_MASK; 269 + omm->cr |= FIELD_PREP(CR_MUXENMODE_MASK, mux); 270 + } 271 + 272 + /* optional */ 273 + ret = of_property_read_u32(dev->of_node, "st,omm-cssel-ovr", &cssel_ovr); 274 + if (!ret) { 275 + omm->cr &= ~CR_CSSEL_OVR_MASK; 276 + omm->cr |= FIELD_PREP(CR_CSSEL_OVR_MASK, cssel_ovr); 277 + omm->cr |= CR_CSSEL_OVR_EN; 278 + } 279 + 280 + omm->restore_omm = true; 281 + writel_relaxed(omm->cr, omm->io_base + OMM_CR); 282 + 283 + ret = stm32_omm_set_amcr(dev, true); 284 + 285 + error: 286 + pm_runtime_put_sync_suspend(dev); 287 + 288 + return ret; 289 + } 290 + 291 + static int stm32_omm_check_access(struct device_node *np) 292 + { 293 + struct stm32_firewall firewall; 294 + int ret; 295 + 296 + ret = stm32_firewall_get_firewall(np, &firewall, 1); 297 + if (ret) 298 + return ret; 299 + 300 + return stm32_firewall_grant_access(&firewall); 301 + } 302 + 303 + static int stm32_omm_probe(struct platform_device *pdev) 304 + { 305 + static const char * const resets_name[] = {"ospi1", "ospi2"}; 306 + struct device *dev = &pdev->dev; 307 + u8 child_access_granted = 0; 308 + struct stm32_omm *omm; 309 + int i, ret; 310 + 311 + omm = devm_kzalloc(dev, sizeof(*omm), GFP_KERNEL); 312 + if (!omm) 313 + return -ENOMEM; 314 + 315 + omm->io_base = devm_platform_ioremap_resource_byname(pdev, "regs"); 316 + if (IS_ERR(omm->io_base)) 317 + return PTR_ERR(omm->io_base); 318 + 319 + omm->mm_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory_map"); 320 + if (IS_ERR(omm->mm_res)) 321 + return PTR_ERR(omm->mm_res); 322 + 323 + /* check child's access */ 324 + for_each_child_of_node_scoped(dev->of_node, child) { 325 + if (omm->nb_child >= OMM_CHILD_NB) { 326 + dev_err(dev, "Bad DT, found too much children\n"); 327 + return -E2BIG; 328 + } 329 + 330 + ret = stm32_omm_check_access(child); 331 + if (ret < 0 && ret != -EACCES) 332 + return ret; 333 + 334 + if (!ret) 335 + child_access_granted++; 336 + 337 + omm->nb_child++; 338 + } 339 + 340 + if (omm->nb_child != OMM_CHILD_NB) 341 + return -EINVAL; 342 + 343 + platform_set_drvdata(pdev, omm); 344 + 345 + devm_pm_runtime_enable(dev); 346 + 347 + /* check if OMM's resource access is granted */ 348 + ret = stm32_omm_check_access(dev->of_node); 349 + if (ret < 0 && ret != -EACCES) 350 + return ret; 351 + 352 + for (i = 0; i < omm->nb_child; i++) { 353 + omm->child_reset[i] = devm_reset_control_get_exclusive_released(dev, 354 + resets_name[i]); 355 + 356 + if (IS_ERR(omm->child_reset[i])) 357 + return dev_err_probe(dev, PTR_ERR(omm->child_reset[i]), 358 + "Can't get %s reset\n", resets_name[i]); 359 + } 360 + 361 + if (!ret && child_access_granted == OMM_CHILD_NB) { 362 + ret = stm32_omm_configure(dev); 363 + if (ret) 364 + return ret; 365 + } else { 366 + dev_dbg(dev, "Octo Memory Manager resource's access not granted\n"); 367 + /* 368 + * AMCR can't be set, so check if current value is coherent 369 + * with memory-map areas defined in DT 370 + */ 371 + ret = stm32_omm_set_amcr(dev, false); 372 + if (ret) 373 + return ret; 374 + } 375 + 376 + ret = devm_of_platform_populate(dev); 377 + if (ret) { 378 + if (omm->cr & CR_MUXEN) 379 + stm32_omm_toggle_child_clock(&pdev->dev, false); 380 + 381 + return dev_err_probe(dev, ret, "Failed to create Octo Memory Manager child\n"); 382 + } 383 + 384 + return 0; 385 + } 386 + 387 + static void stm32_omm_remove(struct platform_device *pdev) 388 + { 389 + struct stm32_omm *omm = platform_get_drvdata(pdev); 390 + 391 + if (omm->cr & CR_MUXEN) 392 + stm32_omm_toggle_child_clock(&pdev->dev, false); 393 + } 394 + 395 + static const struct of_device_id stm32_omm_of_match[] = { 396 + { .compatible = "st,stm32mp25-omm", }, 397 + {} 398 + }; 399 + MODULE_DEVICE_TABLE(of, stm32_omm_of_match); 400 + 401 + static int __maybe_unused stm32_omm_runtime_suspend(struct device *dev) 402 + { 403 + struct stm32_omm *omm = dev_get_drvdata(dev); 404 + 405 + clk_disable_unprepare(omm->clk_bulk[0].clk); 406 + 407 + return 0; 408 + } 409 + 410 + static int __maybe_unused stm32_omm_runtime_resume(struct device *dev) 411 + { 412 + struct stm32_omm *omm = dev_get_drvdata(dev); 413 + 414 + return clk_prepare_enable(omm->clk_bulk[0].clk); 415 + } 416 + 417 + static int __maybe_unused stm32_omm_suspend(struct device *dev) 418 + { 419 + struct stm32_omm *omm = dev_get_drvdata(dev); 420 + 421 + if (omm->restore_omm && omm->cr & CR_MUXEN) 422 + stm32_omm_toggle_child_clock(dev, false); 423 + 424 + return pinctrl_pm_select_sleep_state(dev); 425 + } 426 + 427 + static int __maybe_unused stm32_omm_resume(struct device *dev) 428 + { 429 + struct stm32_omm *omm = dev_get_drvdata(dev); 430 + int ret; 431 + 432 + pinctrl_pm_select_default_state(dev); 433 + 434 + if (!omm->restore_omm) 435 + return 0; 436 + 437 + /* Ensure both OSPI instance are disabled before configuring OMM */ 438 + ret = stm32_omm_disable_child(dev); 439 + if (ret) 440 + return ret; 441 + 442 + ret = pm_runtime_resume_and_get(dev); 443 + if (ret < 0) 444 + return ret; 445 + 446 + writel_relaxed(omm->cr, omm->io_base + OMM_CR); 447 + ret = stm32_omm_set_amcr(dev, true); 448 + pm_runtime_put_sync_suspend(dev); 449 + if (ret) 450 + return ret; 451 + 452 + if (omm->cr & CR_MUXEN) 453 + ret = stm32_omm_toggle_child_clock(dev, true); 454 + 455 + return ret; 456 + } 457 + 458 + static const struct dev_pm_ops stm32_omm_pm_ops = { 459 + SET_RUNTIME_PM_OPS(stm32_omm_runtime_suspend, 460 + stm32_omm_runtime_resume, NULL) 461 + SET_SYSTEM_SLEEP_PM_OPS(stm32_omm_suspend, stm32_omm_resume) 462 + }; 463 + 464 + static struct platform_driver stm32_omm_driver = { 465 + .probe = stm32_omm_probe, 466 + .remove = stm32_omm_remove, 467 + .driver = { 468 + .name = "stm32-omm", 469 + .of_match_table = stm32_omm_of_match, 470 + .pm = &stm32_omm_pm_ops, 471 + }, 472 + }; 473 + module_platform_driver(stm32_omm_driver); 474 + 475 + MODULE_DESCRIPTION("STMicroelectronics Octo Memory Manager driver"); 476 + MODULE_LICENSE("GPL");