drivers/memory/stm32_omm.c

Source file repositories/reference/linux-study-clean/drivers/memory/stm32_omm.c

File Facts

System
Linux kernel
Corpus path
drivers/memory/stm32_omm.c
Extension
.c
Size
11435 bytes
Lines
471
Domain
Driver Families
Bucket
drivers/memory
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct stm32_omm {
	struct resource *mm_res;
	struct clk_bulk_data clk_bulk[OMM_CLK_NB];
	struct reset_control *child_reset[OMM_CHILD_NB];
	void __iomem *io_base;
	u32 cr;
	u8 nb_child;
	bool restore_omm;
};

static int stm32_omm_set_amcr(struct device *dev, bool set)
{
	struct stm32_omm *omm = dev_get_drvdata(dev);
	resource_size_t mm_ospi2_size = 0;
	static const char * const mm_name[] = { "ospi1", "ospi2" };
	struct regmap *syscfg_regmap;
	struct device_node *node;
	struct resource res, res1;
	unsigned int syscon_args[2];
	int ret, idx;
	unsigned int i, amcr, read_amcr;

	for (i = 0; i < omm->nb_child; i++) {
		idx = of_property_match_string(dev->of_node,
					       "memory-region-names",
					       mm_name[i]);
		if (idx < 0)
			continue;

		/* res1 only used on second loop iteration */
		res1.start = res.start;
		res1.end = res.end;

		node = of_parse_phandle(dev->of_node, "memory-region", idx);
		if (!node)
			continue;

		ret = of_address_to_resource(node, 0, &res);
		if (ret) {
			of_node_put(node);
			dev_err(dev, "unable to resolve memory region\n");
			return ret;
		}

		/* check that memory region fits inside OMM memory map area */
		if (!resource_contains(omm->mm_res, &res)) {
			dev_err(dev, "%s doesn't fit inside OMM memory map area\n",
				mm_name[i]);
			dev_err(dev, "%pR doesn't fit inside %pR\n", &res, omm->mm_res);
			of_node_put(node);

			return -EFAULT;
		}

		if (i == 1) {
			mm_ospi2_size = resource_size(&res);

			/* check that OMM memory region 1 doesn't overlap memory region 2 */
			if (resource_overlaps(&res, &res1)) {
				dev_err(dev, "OMM memory-region %s overlaps memory region %s\n",
					mm_name[0], mm_name[1]);
				dev_err(dev, "%pR overlaps %pR\n", &res1, &res);
				of_node_put(node);

				return -EFAULT;
			}
		}
		of_node_put(node);
	}

	syscfg_regmap = syscon_regmap_lookup_by_phandle_args(dev->of_node, "st,syscfg-amcr",
							     2, syscon_args);
	if (IS_ERR(syscfg_regmap))
		return dev_err_probe(dev, PTR_ERR(syscfg_regmap),
				     "Failed to get st,syscfg-amcr property\n");

	amcr = mm_ospi2_size / SZ_64M;

	if (set)
		regmap_update_bits(syscfg_regmap, syscon_args[0], syscon_args[1], amcr);

	/* read AMCR and check coherency with memory-map areas defined in DT */
	regmap_read(syscfg_regmap, syscon_args[0], &read_amcr);
	read_amcr = read_amcr >> (ffs(syscon_args[1]) - 1);

	if (amcr != read_amcr) {
		dev_err(dev, "AMCR value not coherent with DT memory-map areas\n");
		ret = -EINVAL;
	}

Annotation

Implementation Notes