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: Raag Jadav <raag.jadav@intel.com>
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Acked-by: Miquel Raynal <miquel.raynal@bootlin.com>
Co-developed-by: Tomas Winkler <tomasw@gmail.com>
Signed-off-by: Tomas Winkler <tomasw@gmail.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Link: https://lore.kernel.org/r/20250617145159.3803852-2-alexander.usyskin@intel.com
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
This commit is contained in:
Alexander Usyskin
2025-06-17 17:51:51 +03:00
committed by Rodrigo Vivi
parent 0089d6ee3b
commit ceb5ab3cb6
5 changed files with 183 additions and 0 deletions

View File

@@ -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>

View File

@@ -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

View File

@@ -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)

View File

@@ -0,0 +1,134 @@
// 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");

View File

@@ -0,0 +1,30 @@
/* 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__ */