diff mbox series

[v5,2/2] nvmem: imx-ocotp-ele: Support accessing controller for i.MX9

Message ID 20250108-imx-ocotp-v5-2-a6d90e18ebe9@nxp.com (mailing list archive)
State Superseded
Headers show
Series Make i.MX9 OCOTP work as accessing controller | expand

Commit Message

Peng Fan (OSS) Jan. 8, 2025, 7 a.m. UTC
From: Peng Fan <peng.fan@nxp.com>

i.MX9 OCOTP supports a specific peripheral or function being fused
which means disabled, so
 - Introduce ocotp_access_gates to be container of efuse gate info
 - Iterate all nodes to check accessing permission. If not
   allowed to be accessed, detach the node

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/nvmem/imx-ocotp-ele.c | 172 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 171 insertions(+), 1 deletion(-)

Comments

Alexander Stein Jan. 8, 2025, 10:15 a.m. UTC | #1
Hi Peng,

Am Mittwoch, 8. Januar 2025, 08:00:18 CET schrieb Peng Fan (OSS):
> From: Peng Fan <peng.fan@nxp.com>
> 
> i.MX9 OCOTP supports a specific peripheral or function being fused
> which means disabled, so
>  - Introduce ocotp_access_gates to be container of efuse gate info
>  - Iterate all nodes to check accessing permission. If not
>    allowed to be accessed, detach the node
> 
> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> ---
>  drivers/nvmem/imx-ocotp-ele.c | 172 +++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 171 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/nvmem/imx-ocotp-ele.c b/drivers/nvmem/imx-ocotp-ele.c
> index ca6dd71d8a2e29888c6e556aaea116c1a967cb5f..5ea6d959ce38760eeed44a989992fb35c462c0b4 100644
> --- a/drivers/nvmem/imx-ocotp-ele.c
> +++ b/drivers/nvmem/imx-ocotp-ele.c
> @@ -5,6 +5,8 @@
>   * Copyright 2023 NXP
>   */
>  
> +#include <dt-bindings/nvmem/fsl,imx93-ocotp.h>
> +#include <dt-bindings/nvmem/fsl,imx95-ocotp.h>
>  #include <linux/device.h>
>  #include <linux/io.h>
>  #include <linux/module.h>
> @@ -27,6 +29,7 @@ struct ocotp_map_entry {
>  };
>  
>  struct ocotp_devtype_data {
> +	const struct ocotp_access_gates *access_gates;
>  	u32 reg_off;
>  	char *name;
>  	u32 size;
> @@ -36,6 +39,20 @@ struct ocotp_devtype_data {
>  	struct ocotp_map_entry entry[];
>  };
>  
> +#define OCOTP_MAX_NUM_GATE_WORDS 4
> +
> +struct access_gate {
> +	u32 word;
> +	u32 mask;
> +};
> +
> +struct ocotp_access_gates {
> +	u32 num_words;
> +	u32 words[OCOTP_MAX_NUM_GATE_WORDS];
> +	u32 num_gates;
> +	struct access_gate *gates;
> +};
> +
>  struct imx_ocotp_priv {
>  	struct device *dev;
>  	void __iomem *base;
> @@ -131,6 +148,82 @@ static void imx_ocotp_fixup_dt_cell_info(struct nvmem_device *nvmem,
>  	cell->read_post_process = imx_ocotp_cell_pp;
>  }
>  
> +static int imx_ele_ocotp_check_access(struct imx_ocotp_priv *priv, u32 id)
> +{
> +	const struct ocotp_access_gates *access_gates = priv->data->access_gates;
> +	void __iomem *reg = priv->base + priv->data->reg_off;
> +	u32 word, mask, val;
> +
> +	if (id >= access_gates->num_gates) {
> +		dev_err(priv->config.dev, "Index %d too large\n", id);
> +		return -EACCES;
> +	}
> +
> +	word = access_gates->gates[id].word;
> +	mask = access_gates->gates[id].mask;
> +
> +	reg = priv->base + priv->data->reg_off + (word << 2);
> +	val = readl(reg);
> +
> +	dev_dbg(priv->config.dev, "id:%d word:%d mask:0x%08x\n", id, word, mask);
> +	/* true means not allow access */
> +	if (val & mask)
> +		return -EACCES;
> +
> +	return 0;
> +}
> +
> +static int imx_ele_ocotp_grant_access(struct imx_ocotp_priv *priv, struct device_node *parent)
> +{
> +	struct device *dev = priv->config.dev;
> +
> +	for_each_available_child_of_node_scoped(parent, child) {
> +		struct of_phandle_args args;
> +		u32 id, idx = 0;
> +
> +		while (!of_parse_phandle_with_args(child, "access-controllers",
> +						   "#access-controller-cells",
> +						   idx++, &args)) {
> +			of_node_put(args.np);
> +			if (args.np != dev->of_node)
> +				continue;
> +
> +			/* Only support one cell */
> +			if (args.args_count != 1) {
> +				dev_err(dev, "wrong args count\n");
> +				continue;
> +			}
> +
> +			id = args.args[0];
> +
> +			dev_dbg(dev, "Checking node: %pOF gate: %d\n", child, id);
> +
> +			if (imx_ele_ocotp_check_access(priv, id)) {
> +				of_detach_node(child);
> +				dev_info(dev, "%pOF: Not granted, device driver will not be probed\n",
> +					 child);
> +			}
> +		}
> +
> +		imx_ele_ocotp_grant_access(priv, child);
> +	}
> +
> +	return 0;
> +}
> +
> +static int imx_ele_ocotp_access_control(struct imx_ocotp_priv *priv)
> +{
> +	struct device_node *root __free(device_node) = of_find_node_by_path("/");
> +
> +	if (!priv->data->access_gates)
> +		return 0;
> +
> +	/* This should never happen */
> +	WARN_ON(!root);
> +
> +	return imx_ele_ocotp_grant_access(priv, root);
> +}
> +
>  static int imx_ele_ocotp_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> @@ -161,14 +254,45 @@ static int imx_ele_ocotp_probe(struct platform_device *pdev)
>  	priv->config.fixup_dt_cell_info = imx_ocotp_fixup_dt_cell_info;
>  	mutex_init(&priv->lock);
>  
> +	platform_set_drvdata(pdev, priv);
> +
>  	nvmem = devm_nvmem_register(dev, &priv->config);
>  	if (IS_ERR(nvmem))
>  		return PTR_ERR(nvmem);
>  
> -	return 0;
> +
> +	return imx_ele_ocotp_access_control(priv);

In [1] you mentioned devlink should solve the probe order. How does this
play when the driver is compiled in (e.g. ethernet for NFS boot) but
this OCOTP driver is just a module?
I'm not well versed with devlink, but is
> access-controllers = <&ocotp IMX93_OCOTP_ENET1_GATE>;
already enough to create that link?

Best regards,
Alexander

>  }
>  
> +struct access_gate imx93_access_gate[] = {
> +		[IMX93_OCOTP_NPU_GATE]		= { .word = 19, .mask = BIT(13) },
> +		[IMX93_OCOTP_A550_GATE]		= { .word = 19, .mask = BIT(14) },
> +		[IMX93_OCOTP_A551_GATE]		= { .word = 19, .mask = BIT(15) },
> +		[IMX93_OCOTP_M33_GATE]		= { .word = 19, .mask = BIT(24) },
> +		[IMX93_OCOTP_CAN1_FD_GATE]	= { .word = 19, .mask = BIT(28) },
> +		[IMX93_OCOTP_CAN2_FD_GATE]	= { .word = 19, .mask = BIT(29) },
> +		[IMX93_OCOTP_CAN1_GATE]		= { .word = 19, .mask = BIT(30) },
> +		[IMX93_OCOTP_CAN2_GATE]		= { .word = 19, .mask = BIT(31) },
> +		[IMX93_OCOTP_USB1_GATE]		= { .word = 20, .mask = BIT(3) },
> +		[IMX93_OCOTP_USB2_GATE]		= { .word = 20, .mask = BIT(4) },
> +		[IMX93_OCOTP_ENET1_GATE]	= { .word = 20, .mask = BIT(5) },
> +		[IMX93_OCOTP_ENET2_GATE]	= { .word = 20, .mask = BIT(6) },
> +		[IMX93_OCOTP_PXP_GATE]		= { .word = 20, .mask = BIT(10) },
> +		[IMX93_OCOTP_MIPI_CSI1_GATE]	= { .word = 20, .mask = BIT(17) },
> +		[IMX93_OCOTP_MIPI_DSI1_GATE]	= { .word = 20, .mask = BIT(19) },
> +		[IMX93_OCOTP_LVDS1_GATE]	= { .word = 20, .mask = BIT(24) },
> +		[IMX93_OCOTP_ADC1_GATE]		= { .word = 21, .mask = BIT(7) },
> +};
> +
> +static const struct ocotp_access_gates imx93_access_gates_info = {
> +	.num_words = 3,
> +	.words = {19, 20, 21},
> +	.num_gates = ARRAY_SIZE(imx93_access_gate),
> +	.gates = imx93_access_gate,
> +};
> +
>  static const struct ocotp_devtype_data imx93_ocotp_data = {
> +	.access_gates = &imx93_access_gates_info,
>  	.reg_off = 0x8000,
>  	.reg_read = imx_ocotp_reg_read,
>  	.size = 2048,
> @@ -183,7 +307,53 @@ static const struct ocotp_devtype_data imx93_ocotp_data = {
>  	},
>  };
>  
> +struct access_gate imx95_access_gate[] = {
> +		[IMX95_OCOTP_CANFD1_GATE]	= { .word = 17, .mask = BIT(20) },
> +		[IMX95_OCOTP_CANFD2_GATE]	= { .word = 17, .mask = BIT(21) },
> +		[IMX95_OCOTP_CANFD3_GATE]	= { .word = 17, .mask = BIT(22) },
> +		[IMX95_OCOTP_CANFD4_GATE]	= { .word = 17, .mask = BIT(23) },
> +		[IMX95_OCOTP_CANFD5_GATE]	= { .word = 17, .mask = BIT(24) },
> +		[IMX95_OCOTP_CAN1_GATE]		= { .word = 17, .mask = BIT(25) },
> +		[IMX95_OCOTP_CAN2_GATE]		= { .word = 17, .mask = BIT(26) },
> +		[IMX95_OCOTP_CAN3_GATE]		= { .word = 17, .mask = BIT(27) },
> +		[IMX95_OCOTP_CAN4_GATE]		= { .word = 17, .mask = BIT(28) },
> +		[IMX95_OCOTP_CAN5_GATE]		= { .word = 17, .mask = BIT(29) },
> +		[IMX95_OCOTP_NPU_GATE]		= { .word = 18, .mask = BIT(0) },
> +		[IMX95_OCOTP_A550_GATE]		= { .word = 18, .mask = BIT(1) },
> +		[IMX95_OCOTP_A551_GATE]		= { .word = 18, .mask = BIT(2) },
> +		[IMX95_OCOTP_A552_GATE]		= { .word = 18, .mask = BIT(3) },
> +		[IMX95_OCOTP_A553_GATE]		= { .word = 18, .mask = BIT(4) },
> +		[IMX95_OCOTP_A554_GATE]		= { .word = 18, .mask = BIT(5) },
> +		[IMX95_OCOTP_A555_GATE]		= { .word = 18, .mask = BIT(6) },
> +		[IMX95_OCOTP_M7_GATE]		= { .word = 18, .mask = BIT(9) },
> +		[IMX95_OCOTP_DCSS_GATE]		= { .word = 18, .mask = BIT(22) },
> +		[IMX95_OCOTP_LVDS1_GATE]	= { .word = 18, .mask = BIT(27) },
> +		[IMX95_OCOTP_ISP_GATE]		= { .word = 18, .mask = BIT(29) },
> +		[IMX95_OCOTP_USB1_GATE]		= { .word = 19, .mask = BIT(2) },
> +		[IMX95_OCOTP_USB2_GATE]		= { .word = 19, .mask = BIT(3) },
> +		[IMX95_OCOTP_NETC_GATE]		= { .word = 19, .mask = BIT(4) },
> +		[IMX95_OCOTP_PCIE1_GATE]	= { .word = 19, .mask = BIT(6) },
> +		[IMX95_OCOTP_PCIE2_GATE]	= { .word = 19, .mask = BIT(7) },
> +		[IMX95_OCOTP_ADC1_GATE]		= { .word = 19, .mask = BIT(8) },
> +		[IMX95_OCOTP_EARC_RX_GATE]	= { .word = 19, .mask = BIT(11) },
> +		[IMX95_OCOTP_GPU3D_GATE]	= { .word = 19, .mask = BIT(16) },
> +		[IMX95_OCOTP_VPU_GATE]		= { .word = 19, .mask = BIT(17) },
> +		[IMX95_OCOTP_JPEG_ENC_GATE]	= { .word = 19, .mask = BIT(18) },
> +		[IMX95_OCOTP_JPEG_DEC_GATE]	= { .word = 19, .mask = BIT(19) },
> +		[IMX95_OCOTP_MIPI_CSI1_GATE]	= { .word = 19, .mask = BIT(21) },
> +		[IMX95_OCOTP_MIPI_CSI2_GATE]	= { .word = 19, .mask = BIT(22) },
> +		[IMX95_OCOTP_MIPI_DSI1_GATE]	= { .word = 19, .mask = BIT(23) },
> +};
> +
> +static const struct ocotp_access_gates imx95_access_gates_info = {
> +	.num_words = 3,
> +	.words = {17, 18, 19},
> +	.num_gates = ARRAY_SIZE(imx95_access_gate),
> +	.gates = imx95_access_gate,
> +};
> +
>  static const struct ocotp_devtype_data imx95_ocotp_data = {
> +	.access_gates = &imx95_access_gates_info,
>  	.reg_off = 0x8000,
>  	.reg_read = imx_ocotp_reg_read,
>  	.size = 2048,
> 
>
Peng Fan (OSS) Jan. 9, 2025, 3:34 a.m. UTC | #2
On Wed, Jan 08, 2025 at 11:15:40AM +0100, Alexander Stein wrote:
>Hi Peng,
>
>Am Mittwoch, 8. Januar 2025, 08:00:18 CET schrieb Peng Fan (OSS):
>> From: Peng Fan <peng.fan@nxp.com>
>> 
>> i.MX9 OCOTP supports a specific peripheral or function being fused
>> which means disabled, so
>>  - Introduce ocotp_access_gates to be container of efuse gate info
>>  - Iterate all nodes to check accessing permission. If not
>>    allowed to be accessed, detach the node
>> 
>> Signed-off-by: Peng Fan <peng.fan@nxp.com>
>> ---
>>  drivers/nvmem/imx-ocotp-ele.c | 172 +++++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 171 insertions(+), 1 deletion(-)
>> 
[....]
>> +
>> +	return imx_ele_ocotp_access_control(priv);
>
>In [1] you mentioned devlink should solve the probe order. How does this
>play when the driver is compiled in (e.g. ethernet for NFS boot) but
>this OCOTP driver is just a module?

OCOTP needs to built in for using devlink. Or the users needs to be
built as module.

>I'm not well versed with devlink, but is
>> access-controllers = <&ocotp IMX93_OCOTP_ENET1_GATE>;
>already enough to create that link?

Yes, the drivers/of/property.c has this
"DEFINE_SIMPLE_PROP(access_controllers, "access-controllers", "#access-controller-cells")"

The fw_devlink driver will create consumer/supplier to make sure proper
order.

Regards,
Peng

>
>Best regards,
>Alexander
>
>>  }
>>  
>> +struct access_gate imx93_access_gate[] = {
>> +		[IMX93_OCOTP_NPU_GATE]		= { .word = 19, .mask = BIT(13) },
>> +		[IMX93_OCOTP_A550_GATE]		= { .word = 19, .mask = BIT(14) },
>> +		[IMX93_OCOTP_A551_GATE]		= { .word = 19, .mask = BIT(15) },
>> +		[IMX93_OCOTP_M33_GATE]		= { .word = 19, .mask = BIT(24) },
>> +		[IMX93_OCOTP_CAN1_FD_GATE]	= { .word = 19, .mask = BIT(28) },
>> +		[IMX93_OCOTP_CAN2_FD_GATE]	= { .word = 19, .mask = BIT(29) },
>> +		[IMX93_OCOTP_CAN1_GATE]		= { .word = 19, .mask = BIT(30) },
>> +		[IMX93_OCOTP_CAN2_GATE]		= { .word = 19, .mask = BIT(31) },
>> +		[IMX93_OCOTP_USB1_GATE]		= { .word = 20, .mask = BIT(3) },
>> +		[IMX93_OCOTP_USB2_GATE]		= { .word = 20, .mask = BIT(4) },
>> +		[IMX93_OCOTP_ENET1_GATE]	= { .word = 20, .mask = BIT(5) },
>> +		[IMX93_OCOTP_ENET2_GATE]	= { .word = 20, .mask = BIT(6) },
>> +		[IMX93_OCOTP_PXP_GATE]		= { .word = 20, .mask = BIT(10) },
>> +		[IMX93_OCOTP_MIPI_CSI1_GATE]	= { .word = 20, .mask = BIT(17) },
>> +		[IMX93_OCOTP_MIPI_DSI1_GATE]	= { .word = 20, .mask = BIT(19) },
>> +		[IMX93_OCOTP_LVDS1_GATE]	= { .word = 20, .mask = BIT(24) },
>> +		[IMX93_OCOTP_ADC1_GATE]		= { .word = 21, .mask = BIT(7) },
>> +};
>> +
>> +static const struct ocotp_access_gates imx93_access_gates_info = {
>> +	.num_words = 3,
>> +	.words = {19, 20, 21},
>> +	.num_gates = ARRAY_SIZE(imx93_access_gate),
>> +	.gates = imx93_access_gate,
>> +};
>> +
>>  static const struct ocotp_devtype_data imx93_ocotp_data = {
>> +	.access_gates = &imx93_access_gates_info,
>>  	.reg_off = 0x8000,
>>  	.reg_read = imx_ocotp_reg_read,
>>  	.size = 2048,
>> @@ -183,7 +307,53 @@ static const struct ocotp_devtype_data imx93_ocotp_data = {
>>  	},
>>  };
>>  
>> +struct access_gate imx95_access_gate[] = {
>> +		[IMX95_OCOTP_CANFD1_GATE]	= { .word = 17, .mask = BIT(20) },
>> +		[IMX95_OCOTP_CANFD2_GATE]	= { .word = 17, .mask = BIT(21) },
>> +		[IMX95_OCOTP_CANFD3_GATE]	= { .word = 17, .mask = BIT(22) },
>> +		[IMX95_OCOTP_CANFD4_GATE]	= { .word = 17, .mask = BIT(23) },
>> +		[IMX95_OCOTP_CANFD5_GATE]	= { .word = 17, .mask = BIT(24) },
>> +		[IMX95_OCOTP_CAN1_GATE]		= { .word = 17, .mask = BIT(25) },
>> +		[IMX95_OCOTP_CAN2_GATE]		= { .word = 17, .mask = BIT(26) },
>> +		[IMX95_OCOTP_CAN3_GATE]		= { .word = 17, .mask = BIT(27) },
>> +		[IMX95_OCOTP_CAN4_GATE]		= { .word = 17, .mask = BIT(28) },
>> +		[IMX95_OCOTP_CAN5_GATE]		= { .word = 17, .mask = BIT(29) },
>> +		[IMX95_OCOTP_NPU_GATE]		= { .word = 18, .mask = BIT(0) },
>> +		[IMX95_OCOTP_A550_GATE]		= { .word = 18, .mask = BIT(1) },
>> +		[IMX95_OCOTP_A551_GATE]		= { .word = 18, .mask = BIT(2) },
>> +		[IMX95_OCOTP_A552_GATE]		= { .word = 18, .mask = BIT(3) },
>> +		[IMX95_OCOTP_A553_GATE]		= { .word = 18, .mask = BIT(4) },
>> +		[IMX95_OCOTP_A554_GATE]		= { .word = 18, .mask = BIT(5) },
>> +		[IMX95_OCOTP_A555_GATE]		= { .word = 18, .mask = BIT(6) },
>> +		[IMX95_OCOTP_M7_GATE]		= { .word = 18, .mask = BIT(9) },
>> +		[IMX95_OCOTP_DCSS_GATE]		= { .word = 18, .mask = BIT(22) },
>> +		[IMX95_OCOTP_LVDS1_GATE]	= { .word = 18, .mask = BIT(27) },
>> +		[IMX95_OCOTP_ISP_GATE]		= { .word = 18, .mask = BIT(29) },
>> +		[IMX95_OCOTP_USB1_GATE]		= { .word = 19, .mask = BIT(2) },
>> +		[IMX95_OCOTP_USB2_GATE]		= { .word = 19, .mask = BIT(3) },
>> +		[IMX95_OCOTP_NETC_GATE]		= { .word = 19, .mask = BIT(4) },
>> +		[IMX95_OCOTP_PCIE1_GATE]	= { .word = 19, .mask = BIT(6) },
>> +		[IMX95_OCOTP_PCIE2_GATE]	= { .word = 19, .mask = BIT(7) },
>> +		[IMX95_OCOTP_ADC1_GATE]		= { .word = 19, .mask = BIT(8) },
>> +		[IMX95_OCOTP_EARC_RX_GATE]	= { .word = 19, .mask = BIT(11) },
>> +		[IMX95_OCOTP_GPU3D_GATE]	= { .word = 19, .mask = BIT(16) },
>> +		[IMX95_OCOTP_VPU_GATE]		= { .word = 19, .mask = BIT(17) },
>> +		[IMX95_OCOTP_JPEG_ENC_GATE]	= { .word = 19, .mask = BIT(18) },
>> +		[IMX95_OCOTP_JPEG_DEC_GATE]	= { .word = 19, .mask = BIT(19) },
>> +		[IMX95_OCOTP_MIPI_CSI1_GATE]	= { .word = 19, .mask = BIT(21) },
>> +		[IMX95_OCOTP_MIPI_CSI2_GATE]	= { .word = 19, .mask = BIT(22) },
>> +		[IMX95_OCOTP_MIPI_DSI1_GATE]	= { .word = 19, .mask = BIT(23) },
>> +};
>> +
>> +static const struct ocotp_access_gates imx95_access_gates_info = {
>> +	.num_words = 3,
>> +	.words = {17, 18, 19},
>> +	.num_gates = ARRAY_SIZE(imx95_access_gate),
>> +	.gates = imx95_access_gate,
>> +};
>> +
>>  static const struct ocotp_devtype_data imx95_ocotp_data = {
>> +	.access_gates = &imx95_access_gates_info,
>>  	.reg_off = 0x8000,
>>  	.reg_read = imx_ocotp_reg_read,
>>  	.size = 2048,
>> 
>> 
>
>
>-- 
>TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
>Amtsgericht München, HRB 105018
>Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
>http://www.tq-group.com/
>
>
Alexander Stein Jan. 9, 2025, 10:34 a.m. UTC | #3
Hi,

Am Donnerstag, 9. Januar 2025, 04:34:18 CET schrieb Peng Fan:
> On Wed, Jan 08, 2025 at 11:15:40AM +0100, Alexander Stein wrote:
> >Hi Peng,
> >
> >Am Mittwoch, 8. Januar 2025, 08:00:18 CET schrieb Peng Fan (OSS):
> >> From: Peng Fan <peng.fan@nxp.com>
> >> 
> >> i.MX9 OCOTP supports a specific peripheral or function being fused
> >> which means disabled, so
> >>  - Introduce ocotp_access_gates to be container of efuse gate info
> >>  - Iterate all nodes to check accessing permission. If not
> >>    allowed to be accessed, detach the node
> >> 
> >> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> >> ---
> >>  drivers/nvmem/imx-ocotp-ele.c | 172 +++++++++++++++++++++++++++++++++++++++++-
> >>  1 file changed, 171 insertions(+), 1 deletion(-)
> >> 
> [....]
> >> +
> >> +	return imx_ele_ocotp_access_control(priv);
> >
> >In [1] you mentioned devlink should solve the probe order. How does this
> >play when the driver is compiled in (e.g. ethernet for NFS boot) but
> >this OCOTP driver is just a module?
> 
> OCOTP needs to built in for using devlink. Or the users needs to be
> built as module.

I don't like this kind of assumption. Would it make more sense to make
CONFIG_NVMEM_IMX_OCOTP_ELE as bool instead of tristate?

> >I'm not well versed with devlink, but is
> >> access-controllers = <&ocotp IMX93_OCOTP_ENET1_GATE>;
> >already enough to create that link?
> 
> Yes, the drivers/of/property.c has this
> "DEFINE_SIMPLE_PROP(access_controllers, "access-controllers", "#access-controller-cells")"
> 
> The fw_devlink driver will create consumer/supplier to make sure proper
> order.

Okay, thanks for confirming.

Best regards,
Alexander

> Regards,
> Peng
> 
> >
> >Best regards,
> >Alexander
> >
> >>  }
> >>  
> >> +struct access_gate imx93_access_gate[] = {
> >> +		[IMX93_OCOTP_NPU_GATE]		= { .word = 19, .mask = BIT(13) },
> >> +		[IMX93_OCOTP_A550_GATE]		= { .word = 19, .mask = BIT(14) },
> >> +		[IMX93_OCOTP_A551_GATE]		= { .word = 19, .mask = BIT(15) },
> >> +		[IMX93_OCOTP_M33_GATE]		= { .word = 19, .mask = BIT(24) },
> >> +		[IMX93_OCOTP_CAN1_FD_GATE]	= { .word = 19, .mask = BIT(28) },
> >> +		[IMX93_OCOTP_CAN2_FD_GATE]	= { .word = 19, .mask = BIT(29) },
> >> +		[IMX93_OCOTP_CAN1_GATE]		= { .word = 19, .mask = BIT(30) },
> >> +		[IMX93_OCOTP_CAN2_GATE]		= { .word = 19, .mask = BIT(31) },
> >> +		[IMX93_OCOTP_USB1_GATE]		= { .word = 20, .mask = BIT(3) },
> >> +		[IMX93_OCOTP_USB2_GATE]		= { .word = 20, .mask = BIT(4) },
> >> +		[IMX93_OCOTP_ENET1_GATE]	= { .word = 20, .mask = BIT(5) },
> >> +		[IMX93_OCOTP_ENET2_GATE]	= { .word = 20, .mask = BIT(6) },
> >> +		[IMX93_OCOTP_PXP_GATE]		= { .word = 20, .mask = BIT(10) },
> >> +		[IMX93_OCOTP_MIPI_CSI1_GATE]	= { .word = 20, .mask = BIT(17) },
> >> +		[IMX93_OCOTP_MIPI_DSI1_GATE]	= { .word = 20, .mask = BIT(19) },
> >> +		[IMX93_OCOTP_LVDS1_GATE]	= { .word = 20, .mask = BIT(24) },
> >> +		[IMX93_OCOTP_ADC1_GATE]		= { .word = 21, .mask = BIT(7) },
> >> +};
> >> +
> >> +static const struct ocotp_access_gates imx93_access_gates_info = {
> >> +	.num_words = 3,
> >> +	.words = {19, 20, 21},
> >> +	.num_gates = ARRAY_SIZE(imx93_access_gate),
> >> +	.gates = imx93_access_gate,
> >> +};
> >> +
> >>  static const struct ocotp_devtype_data imx93_ocotp_data = {
> >> +	.access_gates = &imx93_access_gates_info,
> >>  	.reg_off = 0x8000,
> >>  	.reg_read = imx_ocotp_reg_read,
> >>  	.size = 2048,
> >> @@ -183,7 +307,53 @@ static const struct ocotp_devtype_data imx93_ocotp_data = {
> >>  	},
> >>  };
> >>  
> >> +struct access_gate imx95_access_gate[] = {
> >> +		[IMX95_OCOTP_CANFD1_GATE]	= { .word = 17, .mask = BIT(20) },
> >> +		[IMX95_OCOTP_CANFD2_GATE]	= { .word = 17, .mask = BIT(21) },
> >> +		[IMX95_OCOTP_CANFD3_GATE]	= { .word = 17, .mask = BIT(22) },
> >> +		[IMX95_OCOTP_CANFD4_GATE]	= { .word = 17, .mask = BIT(23) },
> >> +		[IMX95_OCOTP_CANFD5_GATE]	= { .word = 17, .mask = BIT(24) },
> >> +		[IMX95_OCOTP_CAN1_GATE]		= { .word = 17, .mask = BIT(25) },
> >> +		[IMX95_OCOTP_CAN2_GATE]		= { .word = 17, .mask = BIT(26) },
> >> +		[IMX95_OCOTP_CAN3_GATE]		= { .word = 17, .mask = BIT(27) },
> >> +		[IMX95_OCOTP_CAN4_GATE]		= { .word = 17, .mask = BIT(28) },
> >> +		[IMX95_OCOTP_CAN5_GATE]		= { .word = 17, .mask = BIT(29) },
> >> +		[IMX95_OCOTP_NPU_GATE]		= { .word = 18, .mask = BIT(0) },
> >> +		[IMX95_OCOTP_A550_GATE]		= { .word = 18, .mask = BIT(1) },
> >> +		[IMX95_OCOTP_A551_GATE]		= { .word = 18, .mask = BIT(2) },
> >> +		[IMX95_OCOTP_A552_GATE]		= { .word = 18, .mask = BIT(3) },
> >> +		[IMX95_OCOTP_A553_GATE]		= { .word = 18, .mask = BIT(4) },
> >> +		[IMX95_OCOTP_A554_GATE]		= { .word = 18, .mask = BIT(5) },
> >> +		[IMX95_OCOTP_A555_GATE]		= { .word = 18, .mask = BIT(6) },
> >> +		[IMX95_OCOTP_M7_GATE]		= { .word = 18, .mask = BIT(9) },
> >> +		[IMX95_OCOTP_DCSS_GATE]		= { .word = 18, .mask = BIT(22) },
> >> +		[IMX95_OCOTP_LVDS1_GATE]	= { .word = 18, .mask = BIT(27) },
> >> +		[IMX95_OCOTP_ISP_GATE]		= { .word = 18, .mask = BIT(29) },
> >> +		[IMX95_OCOTP_USB1_GATE]		= { .word = 19, .mask = BIT(2) },
> >> +		[IMX95_OCOTP_USB2_GATE]		= { .word = 19, .mask = BIT(3) },
> >> +		[IMX95_OCOTP_NETC_GATE]		= { .word = 19, .mask = BIT(4) },
> >> +		[IMX95_OCOTP_PCIE1_GATE]	= { .word = 19, .mask = BIT(6) },
> >> +		[IMX95_OCOTP_PCIE2_GATE]	= { .word = 19, .mask = BIT(7) },
> >> +		[IMX95_OCOTP_ADC1_GATE]		= { .word = 19, .mask = BIT(8) },
> >> +		[IMX95_OCOTP_EARC_RX_GATE]	= { .word = 19, .mask = BIT(11) },
> >> +		[IMX95_OCOTP_GPU3D_GATE]	= { .word = 19, .mask = BIT(16) },
> >> +		[IMX95_OCOTP_VPU_GATE]		= { .word = 19, .mask = BIT(17) },
> >> +		[IMX95_OCOTP_JPEG_ENC_GATE]	= { .word = 19, .mask = BIT(18) },
> >> +		[IMX95_OCOTP_JPEG_DEC_GATE]	= { .word = 19, .mask = BIT(19) },
> >> +		[IMX95_OCOTP_MIPI_CSI1_GATE]	= { .word = 19, .mask = BIT(21) },
> >> +		[IMX95_OCOTP_MIPI_CSI2_GATE]	= { .word = 19, .mask = BIT(22) },
> >> +		[IMX95_OCOTP_MIPI_DSI1_GATE]	= { .word = 19, .mask = BIT(23) },
> >> +};
> >> +
> >> +static const struct ocotp_access_gates imx95_access_gates_info = {
> >> +	.num_words = 3,
> >> +	.words = {17, 18, 19},
> >> +	.num_gates = ARRAY_SIZE(imx95_access_gate),
> >> +	.gates = imx95_access_gate,
> >> +};
> >> +
> >>  static const struct ocotp_devtype_data imx95_ocotp_data = {
> >> +	.access_gates = &imx95_access_gates_info,
> >>  	.reg_off = 0x8000,
> >>  	.reg_read = imx_ocotp_reg_read,
> >>  	.size = 2048,
> >> 
> >> 
> >
> >
> 
>
Peng Fan Jan. 11, 2025, 12:41 p.m. UTC | #4
> Subject: Re: [PATCH v5 2/2] nvmem: imx-ocotp-ele: Support accessing
> controller for i.MX9
> 
> Hi,
> 
> Am Donnerstag, 9. Januar 2025, 04:34:18 CET schrieb Peng Fan:
> > On Wed, Jan 08, 2025 at 11:15:40AM +0100, Alexander Stein wrote:
> > >Hi Peng,
> > >
> > >Am Mittwoch, 8. Januar 2025, 08:00:18 CET schrieb Peng Fan (OSS):
> > >> From: Peng Fan <peng.fan@nxp.com>
> > >>
> > >> i.MX9 OCOTP supports a specific peripheral or function being
> fused
> > >> which means disabled, so
> > >>  - Introduce ocotp_access_gates to be container of efuse gate info
> > >>  - Iterate all nodes to check accessing permission. If not
> > >>    allowed to be accessed, detach the node
> > >>
> > >> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> > >> ---
> > >>  drivers/nvmem/imx-ocotp-ele.c | 172
> > >> +++++++++++++++++++++++++++++++++++++++++-
> > >>  1 file changed, 171 insertions(+), 1 deletion(-)
> > >>
> > [....]
> > >> +
> > >> +	return imx_ele_ocotp_access_control(priv);
> > >
> > >In [1] you mentioned devlink should solve the probe order. How
> does
> > >this play when the driver is compiled in (e.g. ethernet for NFS boot)
> > >but this OCOTP driver is just a module?
> >
> > OCOTP needs to built in for using devlink. Or the users needs to be
> > built as module.
> 
> I don't like this kind of assumption. Would it make more sense to make
> CONFIG_NVMEM_IMX_OCOTP_ELE as bool instead of tristate?

No. Users could setup their own system with this driver build in
or built related drivers as modules.

At least for Android GKI, this driver needs to be as module.

Thanks,
Peng.

> 
> > >I'm not well versed with devlink, but is
> > >> access-controllers = <&ocotp IMX93_OCOTP_ENET1_GATE>;
> > >already enough to create that link?
> >
> > Yes, the drivers/of/property.c has this
> > "DEFINE_SIMPLE_PROP(access_controllers, "access-controllers",
> "#access-controller-cells")"
> >
> > The fw_devlink driver will create consumer/supplier to make sure
> > proper order.
> 
> Okay, thanks for confirming.
> 
> Best regards,
> Alexander
> 
> > Regards,
> > Peng
> >
> > >
> > >Best regards,
> > >Alexander
> > >
> > >>  }
> > >>
> > >> +struct access_gate imx93_access_gate[] = {
> > >> +		[IMX93_OCOTP_NPU_GATE]		= { .word =
> 19, .mask = BIT(13) },
> > >> +		[IMX93_OCOTP_A550_GATE]		= { .word =
> 19, .mask = BIT(14) },
> > >> +		[IMX93_OCOTP_A551_GATE]		= { .word =
> 19, .mask = BIT(15) },
> > >> +		[IMX93_OCOTP_M33_GATE]		= { .word =
> 19, .mask = BIT(24) },
> > >> +		[IMX93_OCOTP_CAN1_FD_GATE]	= { .word =
> 19, .mask = BIT(28) },
> > >> +		[IMX93_OCOTP_CAN2_FD_GATE]	= { .word =
> 19, .mask = BIT(29) },
> > >> +		[IMX93_OCOTP_CAN1_GATE]		= { .word =
> 19, .mask = BIT(30) },
> > >> +		[IMX93_OCOTP_CAN2_GATE]		= { .word =
> 19, .mask = BIT(31) },
> > >> +		[IMX93_OCOTP_USB1_GATE]		= { .word =
> 20, .mask = BIT(3) },
> > >> +		[IMX93_OCOTP_USB2_GATE]		= { .word =
> 20, .mask = BIT(4) },
> > >> +		[IMX93_OCOTP_ENET1_GATE]	= { .word =
> 20, .mask = BIT(5) },
> > >> +		[IMX93_OCOTP_ENET2_GATE]	= { .word =
> 20, .mask = BIT(6) },
> > >> +		[IMX93_OCOTP_PXP_GATE]		= { .word =
> 20, .mask = BIT(10) },
> > >> +		[IMX93_OCOTP_MIPI_CSI1_GATE]	= { .word =
> 20, .mask = BIT(17) },
> > >> +		[IMX93_OCOTP_MIPI_DSI1_GATE]	= { .word =
> 20, .mask = BIT(19) },
> > >> +		[IMX93_OCOTP_LVDS1_GATE]	= { .word =
> 20, .mask = BIT(24) },
> > >> +		[IMX93_OCOTP_ADC1_GATE]		= { .word =
> 21, .mask = BIT(7) },
> > >> +};
> > >> +
> > >> +static const struct ocotp_access_gates imx93_access_gates_info =
> {
> > >> +	.num_words = 3,
> > >> +	.words = {19, 20, 21},
> > >> +	.num_gates = ARRAY_SIZE(imx93_access_gate),
> > >> +	.gates = imx93_access_gate,
> > >> +};
> > >> +
> > >>  static const struct ocotp_devtype_data imx93_ocotp_data = {
> > >> +	.access_gates = &imx93_access_gates_info,
> > >>  	.reg_off = 0x8000,
> > >>  	.reg_read = imx_ocotp_reg_read,
> > >>  	.size = 2048,
> > >> @@ -183,7 +307,53 @@ static const struct ocotp_devtype_data
> imx93_ocotp_data = {
> > >>  	},
> > >>  };
> > >>
> > >> +struct access_gate imx95_access_gate[] = {
> > >> +		[IMX95_OCOTP_CANFD1_GATE]	= { .word =
> 17, .mask = BIT(20) },
> > >> +		[IMX95_OCOTP_CANFD2_GATE]	= { .word =
> 17, .mask = BIT(21) },
> > >> +		[IMX95_OCOTP_CANFD3_GATE]	= { .word =
> 17, .mask = BIT(22) },
> > >> +		[IMX95_OCOTP_CANFD4_GATE]	= { .word =
> 17, .mask = BIT(23) },
> > >> +		[IMX95_OCOTP_CANFD5_GATE]	= { .word =
> 17, .mask = BIT(24) },
> > >> +		[IMX95_OCOTP_CAN1_GATE]		= { .word =
> 17, .mask = BIT(25) },
> > >> +		[IMX95_OCOTP_CAN2_GATE]		= { .word =
> 17, .mask = BIT(26) },
> > >> +		[IMX95_OCOTP_CAN3_GATE]		= { .word =
> 17, .mask = BIT(27) },
> > >> +		[IMX95_OCOTP_CAN4_GATE]		= { .word =
> 17, .mask = BIT(28) },
> > >> +		[IMX95_OCOTP_CAN5_GATE]		= { .word =
> 17, .mask = BIT(29) },
> > >> +		[IMX95_OCOTP_NPU_GATE]		= { .word =
> 18, .mask = BIT(0) },
> > >> +		[IMX95_OCOTP_A550_GATE]		= { .word =
> 18, .mask = BIT(1) },
> > >> +		[IMX95_OCOTP_A551_GATE]		= { .word =
> 18, .mask = BIT(2) },
> > >> +		[IMX95_OCOTP_A552_GATE]		= { .word =
> 18, .mask = BIT(3) },
> > >> +		[IMX95_OCOTP_A553_GATE]		= { .word =
> 18, .mask = BIT(4) },
> > >> +		[IMX95_OCOTP_A554_GATE]		= { .word =
> 18, .mask = BIT(5) },
> > >> +		[IMX95_OCOTP_A555_GATE]		= { .word =
> 18, .mask = BIT(6) },
> > >> +		[IMX95_OCOTP_M7_GATE]		= { .word =
> 18, .mask = BIT(9) },
> > >> +		[IMX95_OCOTP_DCSS_GATE]		= { .word =
> 18, .mask = BIT(22) },
> > >> +		[IMX95_OCOTP_LVDS1_GATE]	= { .word =
> 18, .mask = BIT(27) },
> > >> +		[IMX95_OCOTP_ISP_GATE]		= { .word =
> 18, .mask = BIT(29) },
> > >> +		[IMX95_OCOTP_USB1_GATE]		= { .word =
> 19, .mask = BIT(2) },
> > >> +		[IMX95_OCOTP_USB2_GATE]		= { .word =
> 19, .mask = BIT(3) },
> > >> +		[IMX95_OCOTP_NETC_GATE]		= { .word =
> 19, .mask = BIT(4) },
> > >> +		[IMX95_OCOTP_PCIE1_GATE]	= { .word =
> 19, .mask = BIT(6) },
> > >> +		[IMX95_OCOTP_PCIE2_GATE]	= { .word =
> 19, .mask = BIT(7) },
> > >> +		[IMX95_OCOTP_ADC1_GATE]		= { .word =
> 19, .mask = BIT(8) },
> > >> +		[IMX95_OCOTP_EARC_RX_GATE]	= { .word =
> 19, .mask = BIT(11) },
> > >> +		[IMX95_OCOTP_GPU3D_GATE]	= { .word =
> 19, .mask = BIT(16) },
> > >> +		[IMX95_OCOTP_VPU_GATE]		= { .word =
> 19, .mask = BIT(17) },
> > >> +		[IMX95_OCOTP_JPEG_ENC_GATE]	= { .word =
> 19, .mask = BIT(18) },
> > >> +		[IMX95_OCOTP_JPEG_DEC_GATE]	= { .word =
> 19, .mask = BIT(19) },
> > >> +		[IMX95_OCOTP_MIPI_CSI1_GATE]	= { .word =
> 19, .mask = BIT(21) },
> > >> +		[IMX95_OCOTP_MIPI_CSI2_GATE]	= { .word =
> 19, .mask = BIT(22) },
> > >> +		[IMX95_OCOTP_MIPI_DSI1_GATE]	= { .word =
> 19, .mask = BIT(23) },
> > >> +};
> > >> +
> > >> +static const struct ocotp_access_gates imx95_access_gates_info =
> {
> > >> +	.num_words = 3,
> > >> +	.words = {17, 18, 19},
> > >> +	.num_gates = ARRAY_SIZE(imx95_access_gate),
> > >> +	.gates = imx95_access_gate,
> > >> +};
> > >> +
> > >>  static const struct ocotp_devtype_data imx95_ocotp_data = {
> > >> +	.access_gates = &imx95_access_gates_info,
> > >>  	.reg_off = 0x8000,
> > >>  	.reg_read = imx_ocotp_reg_read,
> > >>  	.size = 2048,
> > >>
> > >>
> > >
> > >
> >
> >
> 
> 
> --
> TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld,
> Germany Amtsgericht München, HRB 105018
> Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
> https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2F
> www.tq-
> group.com%2F&data=05%7C02%7Cpeng.fan%40nxp.com%7C55d61ee
> fd50749808d4a08dd3099320d%7C686ea1d3bc2b4c6fa92cd99c5c301
> 635%7C0%7C0%7C638720156723988367%7CUnknown%7CTWFpbGZ
> sb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW
> 4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=
> %2BCsoNoGLNpZiltu%2BMD%2BUCMAwHcmXCL0LKVq9olfSIoU%3D&r
> eserved=0
>
Alexander Stein Jan. 13, 2025, 12:16 p.m. UTC | #5
Hi,

Am Samstag, 11. Januar 2025, 13:41:58 CET schrieb Peng Fan:
> > Subject: Re: [PATCH v5 2/2] nvmem: imx-ocotp-ele: Support accessing
> > controller for i.MX9
> > 
> > Hi,
> > 
> > Am Donnerstag, 9. Januar 2025, 04:34:18 CET schrieb Peng Fan:
> > > On Wed, Jan 08, 2025 at 11:15:40AM +0100, Alexander Stein wrote:
> > > >Hi Peng,
> > > >
> > > >Am Mittwoch, 8. Januar 2025, 08:00:18 CET schrieb Peng Fan (OSS):
> > > >> From: Peng Fan <peng.fan@nxp.com>
> > > >>
> > > >> i.MX9 OCOTP supports a specific peripheral or function being
> > fused
> > > >> which means disabled, so
> > > >>  - Introduce ocotp_access_gates to be container of efuse gate info
> > > >>  - Iterate all nodes to check accessing permission. If not
> > > >>    allowed to be accessed, detach the node
> > > >>
> > > >> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> > > >> ---
> > > >>  drivers/nvmem/imx-ocotp-ele.c | 172
> > > >> +++++++++++++++++++++++++++++++++++++++++-
> > > >>  1 file changed, 171 insertions(+), 1 deletion(-)
> > > >>
> > > [....]
> > > >> +
> > > >> +	return imx_ele_ocotp_access_control(priv);
> > > >
> > > >In [1] you mentioned devlink should solve the probe order. How
> > does
> > > >this play when the driver is compiled in (e.g. ethernet for NFS boot)
> > > >but this OCOTP driver is just a module?
> > >
> > > OCOTP needs to built in for using devlink. Or the users needs to be
> > > built as module.
> > 
> > I don't like this kind of assumption. Would it make more sense to make
> > CONFIG_NVMEM_IMX_OCOTP_ELE as bool instead of tristate?
> 
> No. Users could setup their own system with this driver build in
> or built related drivers as modules.

Sure, but if the kernel locks/fails/panics while accessing peripherals
just because of the kernel config seems at east very unfortunate to me.
How is someone supposed to analyze/debug this?

> At least for Android GKI, this driver needs to be as module.

Any particular reason this needs to be a module?
Which means any affected driver needs to be a module as well just because if
a DT reference, no? With no means to know which drivers are affected, despite
checking for the DT references manually?

Best regards,
Alexander
Peng Fan Jan. 14, 2025, 8:35 a.m. UTC | #6
> Subject: Re: [PATCH v5 2/2] nvmem: imx-ocotp-ele: Support accessing
> controller for i.MX9
> 
> Hi,
> 
> Am Samstag, 11. Januar 2025, 13:41:58 CET schrieb Peng Fan:
> > > Subject: Re: [PATCH v5 2/2] nvmem: imx-ocotp-ele: Support
> accessing
> > > controller for i.MX9
> > >
> > > Hi,
> > >
> > > Am Donnerstag, 9. Januar 2025, 04:34:18 CET schrieb Peng Fan:
> > > > On Wed, Jan 08, 2025 at 11:15:40AM +0100, Alexander Stein
> wrote:
> > > > >Hi Peng,
> > > > >
> > > > >Am Mittwoch, 8. Januar 2025, 08:00:18 CET schrieb Peng Fan
> (OSS):
> > > > >> From: Peng Fan <peng.fan@nxp.com>
> > > > >>
> > > > >> i.MX9 OCOTP supports a specific peripheral or function being
> > > fused
> > > > >> which means disabled, so
> > > > >>  - Introduce ocotp_access_gates to be container of efuse gate
> > > > >> info
> > > > >>  - Iterate all nodes to check accessing permission. If not
> > > > >>    allowed to be accessed, detach the node
> > > > >>
> > > > >> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> > > > >> ---
> > > > >>  drivers/nvmem/imx-ocotp-ele.c | 172
> > > > >> +++++++++++++++++++++++++++++++++++++++++-
> > > > >>  1 file changed, 171 insertions(+), 1 deletion(-)
> > > > >>
> > > > [....]
> > > > >> +
> > > > >> +	return imx_ele_ocotp_access_control(priv);
> > > > >
> > > > >In [1] you mentioned devlink should solve the probe order. How
> > > does
> > > > >this play when the driver is compiled in (e.g. ethernet for NFS
> > > > >boot) but this OCOTP driver is just a module?
> > > >
> > > > OCOTP needs to built in for using devlink. Or the users needs to
> > > > be built as module.
> > >
> > > I don't like this kind of assumption. Would it make more sense to
> > > make CONFIG_NVMEM_IMX_OCOTP_ELE as bool instead of tristate?
> >
> > No. Users could setup their own system with this driver build in or
> > built related drivers as modules.
> 
> Sure, but if the kernel locks/fails/panics while accessing peripherals just
> because of the kernel config seems at east very unfortunate to me.
> How is someone supposed to analyze/debug this?
> 
> > At least for Android GKI, this driver needs to be as module.
> 
> Any particular reason this needs to be a module?

Android has a minimal kernel which is controlled by Google.
Vendors could only built modules based on Google's Image.

Updating this to y in upstream, means we need to change
it back to m in NXP downstream android kernel.

If you need it built in, you could modify your downstream
config, right?

Thanks,
Peng.

> Which means any affected driver needs to be a module as well just
> because if a DT reference, no? With no means to know which drivers
> are affected, despite checking for the DT references manually?
> 
> Best regards,
> Alexander
> --
> TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld,
> Germany Amtsgericht München, HRB 105018
> Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
> https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2F
> www.tq-
> group.com%2F&data=05%7C02%7Cpeng.fan%40nxp.com%7C4f423e5
> af548475e6b0208dd33cc2d1e%7C686ea1d3bc2b4c6fa92cd99c5c301
> 635%7C0%7C0%7C638723674209718864%7CUnknown%7CTWFpbGZ
> sb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW
> 4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=e
> qPs5lOuVSiIZYQwwNecUzgIL%2FtWiJP5bjd7b60Ul7A%3D&reserved=0
>
Alexander Stein Jan. 15, 2025, 6:56 a.m. UTC | #7
Hi,

Am Dienstag, 14. Januar 2025, 09:35:41 CET schrieb Peng Fan:
> > Subject: Re: [PATCH v5 2/2] nvmem: imx-ocotp-ele: Support accessing
> > controller for i.MX9
> > 
> > Hi,
> > 
> > Am Samstag, 11. Januar 2025, 13:41:58 CET schrieb Peng Fan:
> > > > Subject: Re: [PATCH v5 2/2] nvmem: imx-ocotp-ele: Support
> > accessing
> > > > controller for i.MX9
> > > >
> > > > Hi,
> > > >
> > > > Am Donnerstag, 9. Januar 2025, 04:34:18 CET schrieb Peng Fan:
> > > > > On Wed, Jan 08, 2025 at 11:15:40AM +0100, Alexander Stein
> > wrote:
> > > > > >Hi Peng,
> > > > > >
> > > > > >Am Mittwoch, 8. Januar 2025, 08:00:18 CET schrieb Peng Fan
> > (OSS):
> > > > > >> From: Peng Fan <peng.fan@nxp.com>
> > > > > >>
> > > > > >> i.MX9 OCOTP supports a specific peripheral or function being
> > > > fused
> > > > > >> which means disabled, so
> > > > > >>  - Introduce ocotp_access_gates to be container of efuse gate
> > > > > >> info
> > > > > >>  - Iterate all nodes to check accessing permission. If not
> > > > > >>    allowed to be accessed, detach the node
> > > > > >>
> > > > > >> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> > > > > >> ---
> > > > > >>  drivers/nvmem/imx-ocotp-ele.c | 172
> > > > > >> +++++++++++++++++++++++++++++++++++++++++-
> > > > > >>  1 file changed, 171 insertions(+), 1 deletion(-)
> > > > > >>
> > > > > [....]
> > > > > >> +
> > > > > >> +	return imx_ele_ocotp_access_control(priv);
> > > > > >
> > > > > >In [1] you mentioned devlink should solve the probe order. How
> > > > does
> > > > > >this play when the driver is compiled in (e.g. ethernet for NFS
> > > > > >boot) but this OCOTP driver is just a module?
> > > > >
> > > > > OCOTP needs to built in for using devlink. Or the users needs to
> > > > > be built as module.
> > > >
> > > > I don't like this kind of assumption. Would it make more sense to
> > > > make CONFIG_NVMEM_IMX_OCOTP_ELE as bool instead of tristate?
> > >
> > > No. Users could setup their own system with this driver build in or
> > > built related drivers as modules.
> > 
> > Sure, but if the kernel locks/fails/panics while accessing peripherals just
> > because of the kernel config seems at east very unfortunate to me.
> > How is someone supposed to analyze/debug this?
> > 
> > > At least for Android GKI, this driver needs to be as module.
> > 
> > Any particular reason this needs to be a module?
> 
> Android has a minimal kernel which is controlled by Google.
> Vendors could only built modules based on Google's Image.
> 
> Updating this to y in upstream, means we need to change
> it back to m in NXP downstream android kernel.

Ok, that's an Android thing.

> If you need it built in, you could modify your downstream
> config, right?

I'm not saying I need a built-in. My concern is that a wrong Kconfig will
result in silent errors/lockups.

Best regards,
Alexander
Peng Fan Jan. 16, 2025, 2:09 a.m. UTC | #8
> Subject: Re: [PATCH v5 2/2] nvmem: imx-ocotp-ele: Support accessing
> controller for i.MX9
> 
> Hi,
> 
> Am Dienstag, 14. Januar 2025, 09:35:41 CET schrieb Peng Fan:
> > > Subject: Re: [PATCH v5 2/2] nvmem: imx-ocotp-ele: Support
> accessing
> > > controller for i.MX9
> > >
> > > Hi,
> > >
> > > Am Samstag, 11. Januar 2025, 13:41:58 CET schrieb Peng Fan:
> > > > > Subject: Re: [PATCH v5 2/2] nvmem: imx-ocotp-ele: Support
> > > accessing
> > > > > controller for i.MX9
> > > > >
> > > > > Hi,
> > > > >
> > > > > Am Donnerstag, 9. Januar 2025, 04:34:18 CET schrieb Peng Fan:
> > > > > > On Wed, Jan 08, 2025 at 11:15:40AM +0100, Alexander Stein
> > > wrote:
> > > > > > >Hi Peng,
> > > > > > >
> > > > > > >Am Mittwoch, 8. Januar 2025, 08:00:18 CET schrieb Peng
> Fan
> > > (OSS):
> > > > > > >> From: Peng Fan <peng.fan@nxp.com>
> > > > > > >>
> > > > > > >> i.MX9 OCOTP supports a specific peripheral or function
> > > > > > >> being
> > > > > fused
> > > > > > >> which means disabled, so
> > > > > > >>  - Introduce ocotp_access_gates to be container of efuse
> > > > > > >> gate info
> > > > > > >>  - Iterate all nodes to check accessing permission. If not
> > > > > > >>    allowed to be accessed, detach the node
> > > > > > >>
> > > > > > >> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> > > > > > >> ---
> > > > > > >>  drivers/nvmem/imx-ocotp-ele.c | 172
> > > > > > >> +++++++++++++++++++++++++++++++++++++++++-
> > > > > > >>  1 file changed, 171 insertions(+), 1 deletion(-)
> > > > > > >>
> > > > > > [....]
> > > > > > >> +
> > > > > > >> +	return imx_ele_ocotp_access_control(priv);
> > > > > > >
> > > > > > >In [1] you mentioned devlink should solve the probe order.
> > > > > > >How
> > > > > does
> > > > > > >this play when the driver is compiled in (e.g. ethernet for
> > > > > > >NFS
> > > > > > >boot) but this OCOTP driver is just a module?
> > > > > >
> > > > > > OCOTP needs to built in for using devlink. Or the users needs
> > > > > > to be built as module.
> > > > >
> > > > > I don't like this kind of assumption. Would it make more sense
> > > > > to make CONFIG_NVMEM_IMX_OCOTP_ELE as bool instead of
> tristate?
> > > >
> > > > No. Users could setup their own system with this driver build in
> > > > or built related drivers as modules.
> > >
> > > Sure, but if the kernel locks/fails/panics while accessing
> > > peripherals just because of the kernel config seems at east very
> unfortunate to me.
> > > How is someone supposed to analyze/debug this?
> > >
> > > > At least for Android GKI, this driver needs to be as module.
> > >
> > > Any particular reason this needs to be a module?
> >
> > Android has a minimal kernel which is controlled by Google.
> > Vendors could only built modules based on Google's Image.
> >
> > Updating this to y in upstream, means we need to change it back to
> m
> > in NXP downstream android kernel.
> 
> Ok, that's an Android thing.
> 
> > If you need it built in, you could modify your downstream config,
> > right?
> 
> I'm not saying I need a built-in. My concern is that a wrong Kconfig will
> result in silent errors/lockups.

You wanna me to put this default y in arm64 defconfig in
upstream kernel?

If yes, this could be separate patch to Shawn if this patchset got
merged by Srinivas.

Thanks,
Peng. 

> 
> Best regards,
> Alexander
> --
> TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld,
> Germany Amtsgericht München, HRB 105018
> Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
> https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2F
> www.tq-
> group.com%2F&data=05%7C02%7Cpeng.fan%40nxp.com%7C0d5a5fb
> 27ca2413b928908dd3531b436%7C686ea1d3bc2b4c6fa92cd99c5c30
> 1635%7C0%7C0%7C638725209780487039%7CUnknown%7CTWFpbG
> Zsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXa
> W4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata
> =Pv9BNodu49Lcup54Xri7vprRc%2FpC1zw19o3oitvIad4%3D&reserved=
> 0
>
Alexander Stein Jan. 16, 2025, 3:47 p.m. UTC | #9
Hi,

Am Donnerstag, 16. Januar 2025, 03:09:02 CET schrieb Peng Fan:
> > Subject: Re: [PATCH v5 2/2] nvmem: imx-ocotp-ele: Support accessing
> > controller for i.MX9
> > 
> > Hi,
> > 
> > Am Dienstag, 14. Januar 2025, 09:35:41 CET schrieb Peng Fan:
> > > > Subject: Re: [PATCH v5 2/2] nvmem: imx-ocotp-ele: Support
> > accessing
> > > > controller for i.MX9
> > > >
> > > > Hi,
> > > >
> > > > Am Samstag, 11. Januar 2025, 13:41:58 CET schrieb Peng Fan:
> > > > > > Subject: Re: [PATCH v5 2/2] nvmem: imx-ocotp-ele: Support
> > > > accessing
> > > > > > controller for i.MX9
> > > > > >
> > > > > > Hi,
> > > > > >
> > > > > > Am Donnerstag, 9. Januar 2025, 04:34:18 CET schrieb Peng Fan:
> > > > > > > On Wed, Jan 08, 2025 at 11:15:40AM +0100, Alexander Stein
> > > > wrote:
> > > > > > > >Hi Peng,
> > > > > > > >
> > > > > > > >Am Mittwoch, 8. Januar 2025, 08:00:18 CET schrieb Peng
> > Fan
> > > > (OSS):
> > > > > > > >> From: Peng Fan <peng.fan@nxp.com>
> > > > > > > >>
> > > > > > > >> i.MX9 OCOTP supports a specific peripheral or function
> > > > > > > >> being
> > > > > > fused
> > > > > > > >> which means disabled, so
> > > > > > > >>  - Introduce ocotp_access_gates to be container of efuse
> > > > > > > >> gate info
> > > > > > > >>  - Iterate all nodes to check accessing permission. If not
> > > > > > > >>    allowed to be accessed, detach the node
> > > > > > > >>
> > > > > > > >> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> > > > > > > >> ---
> > > > > > > >>  drivers/nvmem/imx-ocotp-ele.c | 172
> > > > > > > >> +++++++++++++++++++++++++++++++++++++++++-
> > > > > > > >>  1 file changed, 171 insertions(+), 1 deletion(-)
> > > > > > > >>
> > > > > > > [....]
> > > > > > > >> +
> > > > > > > >> +	return imx_ele_ocotp_access_control(priv);
> > > > > > > >
> > > > > > > >In [1] you mentioned devlink should solve the probe order.
> > > > > > > >How
> > > > > > does
> > > > > > > >this play when the driver is compiled in (e.g. ethernet for
> > > > > > > >NFS
> > > > > > > >boot) but this OCOTP driver is just a module?
> > > > > > >
> > > > > > > OCOTP needs to built in for using devlink. Or the users needs
> > > > > > > to be built as module.
> > > > > >
> > > > > > I don't like this kind of assumption. Would it make more sense
> > > > > > to make CONFIG_NVMEM_IMX_OCOTP_ELE as bool instead of
> > tristate?
> > > > >
> > > > > No. Users could setup their own system with this driver build in
> > > > > or built related drivers as modules.
> > > >
> > > > Sure, but if the kernel locks/fails/panics while accessing
> > > > peripherals just because of the kernel config seems at east very
> > unfortunate to me.
> > > > How is someone supposed to analyze/debug this?
> > > >
> > > > > At least for Android GKI, this driver needs to be as module.
> > > >
> > > > Any particular reason this needs to be a module?
> > >
> > > Android has a minimal kernel which is controlled by Google.
> > > Vendors could only built modules based on Google's Image.
> > >
> > > Updating this to y in upstream, means we need to change it back to
> > m
> > > in NXP downstream android kernel.
> > 
> > Ok, that's an Android thing.
> > 
> > > If you need it built in, you could modify your downstream config,
> > > right?
> > 
> > I'm not saying I need a built-in. My concern is that a wrong Kconfig will
> > result in silent errors/lockups.
> 
> You wanna me to put this default y in arm64 defconfig in
> upstream kernel?
> 
> If yes, this could be separate patch to Shawn if this patchset got
> merged by Srinivas.

I don't know what others says about adjusting defconfig. But at least
add a comment to the Kconfig help that if built as modules, any
other driver relying on this also needs to be a module as well.

Best regards,
Alexander
diff mbox series

Patch

diff --git a/drivers/nvmem/imx-ocotp-ele.c b/drivers/nvmem/imx-ocotp-ele.c
index ca6dd71d8a2e29888c6e556aaea116c1a967cb5f..5ea6d959ce38760eeed44a989992fb35c462c0b4 100644
--- a/drivers/nvmem/imx-ocotp-ele.c
+++ b/drivers/nvmem/imx-ocotp-ele.c
@@ -5,6 +5,8 @@ 
  * Copyright 2023 NXP
  */
 
+#include <dt-bindings/nvmem/fsl,imx93-ocotp.h>
+#include <dt-bindings/nvmem/fsl,imx95-ocotp.h>
 #include <linux/device.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -27,6 +29,7 @@  struct ocotp_map_entry {
 };
 
 struct ocotp_devtype_data {
+	const struct ocotp_access_gates *access_gates;
 	u32 reg_off;
 	char *name;
 	u32 size;
@@ -36,6 +39,20 @@  struct ocotp_devtype_data {
 	struct ocotp_map_entry entry[];
 };
 
+#define OCOTP_MAX_NUM_GATE_WORDS 4
+
+struct access_gate {
+	u32 word;
+	u32 mask;
+};
+
+struct ocotp_access_gates {
+	u32 num_words;
+	u32 words[OCOTP_MAX_NUM_GATE_WORDS];
+	u32 num_gates;
+	struct access_gate *gates;
+};
+
 struct imx_ocotp_priv {
 	struct device *dev;
 	void __iomem *base;
@@ -131,6 +148,82 @@  static void imx_ocotp_fixup_dt_cell_info(struct nvmem_device *nvmem,
 	cell->read_post_process = imx_ocotp_cell_pp;
 }
 
+static int imx_ele_ocotp_check_access(struct imx_ocotp_priv *priv, u32 id)
+{
+	const struct ocotp_access_gates *access_gates = priv->data->access_gates;
+	void __iomem *reg = priv->base + priv->data->reg_off;
+	u32 word, mask, val;
+
+	if (id >= access_gates->num_gates) {
+		dev_err(priv->config.dev, "Index %d too large\n", id);
+		return -EACCES;
+	}
+
+	word = access_gates->gates[id].word;
+	mask = access_gates->gates[id].mask;
+
+	reg = priv->base + priv->data->reg_off + (word << 2);
+	val = readl(reg);
+
+	dev_dbg(priv->config.dev, "id:%d word:%d mask:0x%08x\n", id, word, mask);
+	/* true means not allow access */
+	if (val & mask)
+		return -EACCES;
+
+	return 0;
+}
+
+static int imx_ele_ocotp_grant_access(struct imx_ocotp_priv *priv, struct device_node *parent)
+{
+	struct device *dev = priv->config.dev;
+
+	for_each_available_child_of_node_scoped(parent, child) {
+		struct of_phandle_args args;
+		u32 id, idx = 0;
+
+		while (!of_parse_phandle_with_args(child, "access-controllers",
+						   "#access-controller-cells",
+						   idx++, &args)) {
+			of_node_put(args.np);
+			if (args.np != dev->of_node)
+				continue;
+
+			/* Only support one cell */
+			if (args.args_count != 1) {
+				dev_err(dev, "wrong args count\n");
+				continue;
+			}
+
+			id = args.args[0];
+
+			dev_dbg(dev, "Checking node: %pOF gate: %d\n", child, id);
+
+			if (imx_ele_ocotp_check_access(priv, id)) {
+				of_detach_node(child);
+				dev_info(dev, "%pOF: Not granted, device driver will not be probed\n",
+					 child);
+			}
+		}
+
+		imx_ele_ocotp_grant_access(priv, child);
+	}
+
+	return 0;
+}
+
+static int imx_ele_ocotp_access_control(struct imx_ocotp_priv *priv)
+{
+	struct device_node *root __free(device_node) = of_find_node_by_path("/");
+
+	if (!priv->data->access_gates)
+		return 0;
+
+	/* This should never happen */
+	WARN_ON(!root);
+
+	return imx_ele_ocotp_grant_access(priv, root);
+}
+
 static int imx_ele_ocotp_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -161,14 +254,45 @@  static int imx_ele_ocotp_probe(struct platform_device *pdev)
 	priv->config.fixup_dt_cell_info = imx_ocotp_fixup_dt_cell_info;
 	mutex_init(&priv->lock);
 
+	platform_set_drvdata(pdev, priv);
+
 	nvmem = devm_nvmem_register(dev, &priv->config);
 	if (IS_ERR(nvmem))
 		return PTR_ERR(nvmem);
 
-	return 0;
+
+	return imx_ele_ocotp_access_control(priv);
 }
 
+struct access_gate imx93_access_gate[] = {
+		[IMX93_OCOTP_NPU_GATE]		= { .word = 19, .mask = BIT(13) },
+		[IMX93_OCOTP_A550_GATE]		= { .word = 19, .mask = BIT(14) },
+		[IMX93_OCOTP_A551_GATE]		= { .word = 19, .mask = BIT(15) },
+		[IMX93_OCOTP_M33_GATE]		= { .word = 19, .mask = BIT(24) },
+		[IMX93_OCOTP_CAN1_FD_GATE]	= { .word = 19, .mask = BIT(28) },
+		[IMX93_OCOTP_CAN2_FD_GATE]	= { .word = 19, .mask = BIT(29) },
+		[IMX93_OCOTP_CAN1_GATE]		= { .word = 19, .mask = BIT(30) },
+		[IMX93_OCOTP_CAN2_GATE]		= { .word = 19, .mask = BIT(31) },
+		[IMX93_OCOTP_USB1_GATE]		= { .word = 20, .mask = BIT(3) },
+		[IMX93_OCOTP_USB2_GATE]		= { .word = 20, .mask = BIT(4) },
+		[IMX93_OCOTP_ENET1_GATE]	= { .word = 20, .mask = BIT(5) },
+		[IMX93_OCOTP_ENET2_GATE]	= { .word = 20, .mask = BIT(6) },
+		[IMX93_OCOTP_PXP_GATE]		= { .word = 20, .mask = BIT(10) },
+		[IMX93_OCOTP_MIPI_CSI1_GATE]	= { .word = 20, .mask = BIT(17) },
+		[IMX93_OCOTP_MIPI_DSI1_GATE]	= { .word = 20, .mask = BIT(19) },
+		[IMX93_OCOTP_LVDS1_GATE]	= { .word = 20, .mask = BIT(24) },
+		[IMX93_OCOTP_ADC1_GATE]		= { .word = 21, .mask = BIT(7) },
+};
+
+static const struct ocotp_access_gates imx93_access_gates_info = {
+	.num_words = 3,
+	.words = {19, 20, 21},
+	.num_gates = ARRAY_SIZE(imx93_access_gate),
+	.gates = imx93_access_gate,
+};
+
 static const struct ocotp_devtype_data imx93_ocotp_data = {
+	.access_gates = &imx93_access_gates_info,
 	.reg_off = 0x8000,
 	.reg_read = imx_ocotp_reg_read,
 	.size = 2048,
@@ -183,7 +307,53 @@  static const struct ocotp_devtype_data imx93_ocotp_data = {
 	},
 };
 
+struct access_gate imx95_access_gate[] = {
+		[IMX95_OCOTP_CANFD1_GATE]	= { .word = 17, .mask = BIT(20) },
+		[IMX95_OCOTP_CANFD2_GATE]	= { .word = 17, .mask = BIT(21) },
+		[IMX95_OCOTP_CANFD3_GATE]	= { .word = 17, .mask = BIT(22) },
+		[IMX95_OCOTP_CANFD4_GATE]	= { .word = 17, .mask = BIT(23) },
+		[IMX95_OCOTP_CANFD5_GATE]	= { .word = 17, .mask = BIT(24) },
+		[IMX95_OCOTP_CAN1_GATE]		= { .word = 17, .mask = BIT(25) },
+		[IMX95_OCOTP_CAN2_GATE]		= { .word = 17, .mask = BIT(26) },
+		[IMX95_OCOTP_CAN3_GATE]		= { .word = 17, .mask = BIT(27) },
+		[IMX95_OCOTP_CAN4_GATE]		= { .word = 17, .mask = BIT(28) },
+		[IMX95_OCOTP_CAN5_GATE]		= { .word = 17, .mask = BIT(29) },
+		[IMX95_OCOTP_NPU_GATE]		= { .word = 18, .mask = BIT(0) },
+		[IMX95_OCOTP_A550_GATE]		= { .word = 18, .mask = BIT(1) },
+		[IMX95_OCOTP_A551_GATE]		= { .word = 18, .mask = BIT(2) },
+		[IMX95_OCOTP_A552_GATE]		= { .word = 18, .mask = BIT(3) },
+		[IMX95_OCOTP_A553_GATE]		= { .word = 18, .mask = BIT(4) },
+		[IMX95_OCOTP_A554_GATE]		= { .word = 18, .mask = BIT(5) },
+		[IMX95_OCOTP_A555_GATE]		= { .word = 18, .mask = BIT(6) },
+		[IMX95_OCOTP_M7_GATE]		= { .word = 18, .mask = BIT(9) },
+		[IMX95_OCOTP_DCSS_GATE]		= { .word = 18, .mask = BIT(22) },
+		[IMX95_OCOTP_LVDS1_GATE]	= { .word = 18, .mask = BIT(27) },
+		[IMX95_OCOTP_ISP_GATE]		= { .word = 18, .mask = BIT(29) },
+		[IMX95_OCOTP_USB1_GATE]		= { .word = 19, .mask = BIT(2) },
+		[IMX95_OCOTP_USB2_GATE]		= { .word = 19, .mask = BIT(3) },
+		[IMX95_OCOTP_NETC_GATE]		= { .word = 19, .mask = BIT(4) },
+		[IMX95_OCOTP_PCIE1_GATE]	= { .word = 19, .mask = BIT(6) },
+		[IMX95_OCOTP_PCIE2_GATE]	= { .word = 19, .mask = BIT(7) },
+		[IMX95_OCOTP_ADC1_GATE]		= { .word = 19, .mask = BIT(8) },
+		[IMX95_OCOTP_EARC_RX_GATE]	= { .word = 19, .mask = BIT(11) },
+		[IMX95_OCOTP_GPU3D_GATE]	= { .word = 19, .mask = BIT(16) },
+		[IMX95_OCOTP_VPU_GATE]		= { .word = 19, .mask = BIT(17) },
+		[IMX95_OCOTP_JPEG_ENC_GATE]	= { .word = 19, .mask = BIT(18) },
+		[IMX95_OCOTP_JPEG_DEC_GATE]	= { .word = 19, .mask = BIT(19) },
+		[IMX95_OCOTP_MIPI_CSI1_GATE]	= { .word = 19, .mask = BIT(21) },
+		[IMX95_OCOTP_MIPI_CSI2_GATE]	= { .word = 19, .mask = BIT(22) },
+		[IMX95_OCOTP_MIPI_DSI1_GATE]	= { .word = 19, .mask = BIT(23) },
+};
+
+static const struct ocotp_access_gates imx95_access_gates_info = {
+	.num_words = 3,
+	.words = {17, 18, 19},
+	.num_gates = ARRAY_SIZE(imx95_access_gate),
+	.gates = imx95_access_gate,
+};
+
 static const struct ocotp_devtype_data imx95_ocotp_data = {
+	.access_gates = &imx95_access_gates_info,
 	.reg_off = 0x8000,
 	.reg_read = imx_ocotp_reg_read,
 	.size = 2048,