Unverified Commit ceb5ab3c authored by Alexander Usyskin's avatar Alexander Usyskin Committed by Rodrigo Vivi
Browse files

mtd: add driver for intel graphics non-volatile memory device



Add auxiliary driver for intel discrete graphics
non-volatile memory device.

CC: Lucas De Marchi <lucas.demarchi@intel.com>
Reviewed-by: default avatarRaag Jadav <raag.jadav@intel.com>
Reviewed-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
Acked-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Co-developed-by: default avatarTomas Winkler <tomasw@gmail.com>
Signed-off-by: default avatarTomas Winkler <tomasw@gmail.com>
Signed-off-by: default avatarAlexander Usyskin <alexander.usyskin@intel.com>
Link: https://lore.kernel.org/r/20250617145159.3803852-2-alexander.usyskin@intel.com


Signed-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
parent 0089d6ee
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -12086,6 +12086,13 @@ L: linux-kernel@vger.kernel.org
S:	Supported
F:	arch/x86/include/asm/intel-family.h
INTEL DISCRETE GRAPHICS NVM MTD DRIVER
M:	Alexander Usyskin <alexander.usyskin@intel.com>
L:	linux-mtd@lists.infradead.org
S:	Supported
F:	drivers/mtd/devices/mtd_intel_dg.c
F:	include/linux/intel_dg_nvm_aux.h
INTEL DRM DISPLAY FOR XE AND I915 DRIVERS
M:	Jani Nikula <jani.nikula@linux.intel.com>
M:	Rodrigo Vivi <rodrigo.vivi@intel.com>
+11 −0
Original line number Diff line number Diff line
@@ -183,6 +183,17 @@ config MTD_POWERNV_FLASH
	  platforms from Linux. This device abstracts away the
	  firmware interface for flash access.

config MTD_INTEL_DG
	tristate "Intel Discrete Graphics non-volatile memory driver"
	depends on AUXILIARY_BUS
	depends on MTD
	help
	  This provides an MTD device to access Intel Discrete Graphics
	  non-volatile memory.

	  To compile this driver as a module, choose M here: the module
	  will be called mtd-intel-dg.

comment "Disk-On-Chip Device Drivers"

config MTD_DOCG3
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ obj-$(CONFIG_MTD_SST25L) += sst25l.o
obj-$(CONFIG_MTD_BCM47XXSFLASH)	+= bcm47xxsflash.o
obj-$(CONFIG_MTD_ST_SPI_FSM)    += st_spi_fsm.o
obj-$(CONFIG_MTD_POWERNV_FLASH)	+= powernv_flash.o
obj-$(CONFIG_MTD_INTEL_DG)	+= mtd_intel_dg.o


CFLAGS_docg3.o			+= -I$(src)
+134 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright(c) 2019-2025, Intel Corporation. All rights reserved.
 */

#include <linux/device.h>
#include <linux/intel_dg_nvm_aux.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/types.h>

struct intel_dg_nvm {
	struct kref refcnt;
	void __iomem *base;
	size_t size;
	unsigned int nregions;
	struct {
		const char *name;
		u8 id;
		u64 offset;
		u64 size;
	} regions[] __counted_by(nregions);
};

static void intel_dg_nvm_release(struct kref *kref)
{
	struct intel_dg_nvm *nvm = container_of(kref, struct intel_dg_nvm, refcnt);
	int i;

	pr_debug("freeing intel_dg nvm\n");
	for (i = 0; i < nvm->nregions; i++)
		kfree(nvm->regions[i].name);
	kfree(nvm);
}

static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev,
			      const struct auxiliary_device_id *aux_dev_id)
{
	struct intel_dg_nvm_dev *invm = auxiliary_dev_to_intel_dg_nvm_dev(aux_dev);
	struct intel_dg_nvm *nvm;
	struct device *device;
	unsigned int nregions;
	unsigned int i, n;
	int ret;

	device = &aux_dev->dev;

	/* count available regions */
	for (nregions = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) {
		if (invm->regions[i].name)
			nregions++;
	}

	if (!nregions) {
		dev_err(device, "no regions defined\n");
		return -ENODEV;
	}

	nvm = kzalloc(struct_size(nvm, regions, nregions), GFP_KERNEL);
	if (!nvm)
		return -ENOMEM;

	kref_init(&nvm->refcnt);

	for (n = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) {
		if (!invm->regions[i].name)
			continue;

		char *name = kasprintf(GFP_KERNEL, "%s.%s",
				       dev_name(&aux_dev->dev), invm->regions[i].name);
		if (!name)
			continue;
		nvm->regions[n].name = name;
		nvm->regions[n].id = i;
		n++;
	}
	nvm->nregions = n; /* in case where kasprintf fail */

	nvm->base = devm_ioremap_resource(device, &invm->bar);
	if (IS_ERR(nvm->base)) {
		ret = PTR_ERR(nvm->base);
		goto err;
	}

	dev_set_drvdata(&aux_dev->dev, nvm);

	return 0;

err:
	kref_put(&nvm->refcnt, intel_dg_nvm_release);
	return ret;
}

static void intel_dg_mtd_remove(struct auxiliary_device *aux_dev)
{
	struct intel_dg_nvm *nvm = dev_get_drvdata(&aux_dev->dev);

	if (!nvm)
		return;

	dev_set_drvdata(&aux_dev->dev, NULL);

	kref_put(&nvm->refcnt, intel_dg_nvm_release);
}

static const struct auxiliary_device_id intel_dg_mtd_id_table[] = {
	{
		.name = "i915.nvm",
	},
	{
		.name = "xe.nvm",
	},
	{
		/* sentinel */
	}
};
MODULE_DEVICE_TABLE(auxiliary, intel_dg_mtd_id_table);

static struct auxiliary_driver intel_dg_mtd_driver = {
	.probe  = intel_dg_mtd_probe,
	.remove = intel_dg_mtd_remove,
	.driver = {
		/* auxiliary_driver_register() sets .name to be the modname */
	},
	.id_table = intel_dg_mtd_id_table
};
module_auxiliary_driver(intel_dg_mtd_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Intel DGFX MTD driver");
+30 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: MIT */
/*
 * Copyright(c) 2019-2025, Intel Corporation. All rights reserved.
 */

#ifndef __INTEL_DG_NVM_AUX_H__
#define __INTEL_DG_NVM_AUX_H__

#include <linux/auxiliary_bus.h>
#include <linux/container_of.h>
#include <linux/ioport.h>
#include <linux/types.h>

#define INTEL_DG_NVM_REGIONS 13

struct intel_dg_nvm_region {
	const char *name;
};

struct intel_dg_nvm_dev {
	struct auxiliary_device aux_dev;
	bool writable_override;
	struct resource bar;
	const struct intel_dg_nvm_region *regions;
};

#define auxiliary_dev_to_intel_dg_nvm_dev(auxiliary_dev) \
	container_of(auxiliary_dev, struct intel_dg_nvm_dev, aux_dev)

#endif /* __INTEL_DG_NVM_AUX_H__ */