lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <8cf72af2-8a0c-4a0b-b5d1-77038ce804b3@nvidia.com>
Date: Fri, 24 Oct 2025 16:11:07 +0100
From: Jon Hunter <jonathanh@...dia.com>
To: Kartik Rajput <kkartik@...dia.com>, akhilrajeev@...dia.com,
 andi.shyti@...nel.org, robh@...nel.org, krzk+dt@...nel.org,
 conor+dt@...nel.org, thierry.reding@...il.com, ldewangan@...dia.com,
 digetx@...il.com, smangipudi@...dia.com, linux-i2c@...r.kernel.org,
 devicetree@...r.kernel.org, linux-tegra@...r.kernel.org,
 linux-kernel@...r.kernel.org
Subject: Re: [PATCH 1/2] i2c: tegra: Add logic to support different register
 offsets



On 01/10/2025 16:36, Kartik Rajput wrote:
> Tegra410 use different offsets for existing I2C registers, update
> the logic to use appropriate offsets per SoC.
> 
> Signed-off-by: Kartik Rajput <kkartik@...dia.com>
> ---
>   drivers/i2c/busses/i2c-tegra.c | 499 ++++++++++++++++++++++-----------
>   1 file changed, 334 insertions(+), 165 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index 038809264526..1e26d67cbd30 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c

...

> @@ -428,8 +519,8 @@ static int tegra_i2c_mutex_lock(struct tegra_i2c_dev *i2c_dev)
>   
>   	if (i2c_dev->atomic_mode)
>   		ret = read_poll_timeout_atomic(tegra_i2c_mutex_trylock, locked, locked,
> -					       USEC_PER_MSEC, I2C_SW_MUTEX_TIMEOUT_US,
> -					       false, i2c_dev);
> +				       USEC_PER_MSEC, I2C_SW_MUTEX_TIMEOUT_US,
> +				       false, i2c_dev);

The above appears to be changed accidently?

> @@ -1062,13 +1151,13 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
>   				tegra_i2c_fill_tx_fifo(i2c_dev);
>   			else
>   				tegra_i2c_mask_irq(i2c_dev,
> -						   I2C_INT_TX_FIFO_DATA_REQ);
> +					   I2C_INT_TX_FIFO_DATA_REQ);

Same here.

>   		}
>   	}
>   
> -	i2c_writel(i2c_dev, status, I2C_INT_STATUS);
> +	i2c_writel(i2c_dev, status, i2c_dev->hw->regs->int_status);
>   	if (IS_DVC(i2c_dev))
> -		dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
> +		dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, i2c_dev->hw->regs->dvc_status);
>   
>   	/*
>   	 * During message read XFER_COMPLETE interrupt is triggered prior to
> @@ -1104,10 +1193,10 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
>   	if (i2c_dev->hw->supports_bus_clear)
>   		tegra_i2c_mask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
>   
> -	i2c_writel(i2c_dev, status, I2C_INT_STATUS);
> +	i2c_writel(i2c_dev, status, i2c_dev->hw->regs->int_status);
>   
>   	if (IS_DVC(i2c_dev))
> -		dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
> +		dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, i2c_dev->hw->regs->dvc_status);
>   
>   	if (i2c_dev->dma_mode) {
>   		dmaengine_terminate_async(i2c_dev->dma_chan);
> @@ -1120,16 +1209,16 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
>   }
>   
>   static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
> -				       size_t len)
> +			       size_t len)

And here.

>   {
>   	struct dma_slave_config slv_config = {0};
>   	u32 val, reg, dma_burst, reg_offset;
>   	int err;
>   
>   	if (i2c_dev->hw->has_mst_fifo)
> -		reg = I2C_MST_FIFO_CONTROL;
> +		reg = i2c_dev->hw->regs->mst_fifo_control;
>   	else
> -		reg = I2C_FIFO_CONTROL;
> +		reg = i2c_dev->hw->regs->fifo_control;
>   
>   	if (i2c_dev->dma_mode) {
>   		if (len & 0xF)
> @@ -1140,7 +1229,7 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
>   			dma_burst = 8;
>   
>   		if (i2c_dev->msg_read) {
> -			reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_RX_FIFO);
> +			reg_offset = i2c_dev->hw->regs->rx_fifo;
>   
>   			slv_config.src_addr = i2c_dev->base_phys + reg_offset;
>   			slv_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> @@ -1151,7 +1240,7 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
>   			else
>   				val = I2C_FIFO_CONTROL_RX_TRIG(dma_burst);
>   		} else {
> -			reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_TX_FIFO);
> +			reg_offset = i2c_dev->hw->regs->tx_fifo;
>   
>   			slv_config.dst_addr = i2c_dev->base_phys + reg_offset;
>   			slv_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> @@ -1187,14 +1276,14 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
>   }
>   
>   static unsigned long tegra_i2c_poll_completion(struct tegra_i2c_dev *i2c_dev,
> -					       struct completion *complete,
> -					       unsigned int timeout_ms)
> +			       struct completion *complete,
> +			       unsigned int timeout_ms)

And here.

>   {
>   	ktime_t ktime = ktime_get();
>   	ktime_t ktimeout = ktime_add_ms(ktime, timeout_ms);
>   
>   	do {
> -		u32 status = i2c_readl(i2c_dev, I2C_INT_STATUS);
> +		u32 status = i2c_readl(i2c_dev, i2c_dev->hw->regs->int_status);
>   
>   		if (status)
>   			tegra_i2c_isr(i2c_dev->irq, i2c_dev);
> @@ -1253,14 +1342,14 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
>   
>   	val = FIELD_PREP(I2C_BC_SCLK_THRESHOLD, 9) | I2C_BC_STOP_COND |
>   	      I2C_BC_TERMINATE;
> -	i2c_writel(i2c_dev, val, I2C_BUS_CLEAR_CNFG);
> +	i2c_writel(i2c_dev, val, i2c_dev->hw->regs->bus_clear_cnfg);
>   
>   	err = tegra_i2c_wait_for_config_load(i2c_dev);
>   	if (err)
>   		return err;
>   
>   	val |= I2C_BC_ENABLE;
> -	i2c_writel(i2c_dev, val, I2C_BUS_CLEAR_CNFG);
> +	i2c_writel(i2c_dev, val, i2c_dev->hw->regs->bus_clear_cnfg);
>   	tegra_i2c_unmask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
>   
>   	time_left = tegra_i2c_wait_completion(i2c_dev, &i2c_dev->msg_complete, 50);
> @@ -1271,7 +1360,7 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
>   		return -ETIMEDOUT;
>   	}
>   
> -	val = i2c_readl(i2c_dev, I2C_BUS_CLEAR_STATUS);
> +	val = i2c_readl(i2c_dev, i2c_dev->hw->regs->bus_clear_status);
>   	if (!(val & I2C_BC_STATUS)) {
>   		dev_err(i2c_dev->dev, "un-recovered arbitration lost\n");
>   		return -EIO;
> @@ -1281,29 +1370,29 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
>   }
>   
>   static void tegra_i2c_push_packet_header(struct tegra_i2c_dev *i2c_dev,
> -					 struct i2c_msg *msg,
> -					 enum msg_end_type end_state)
> +				 struct i2c_msg *msg,
> +				 enum msg_end_type end_state)

And here.

>   {
>   	u32 *dma_buf = i2c_dev->dma_buf;
>   	u32 packet_header;
>   
>   	packet_header = FIELD_PREP(PACKET_HEADER0_HEADER_SIZE, 0) |
>   			FIELD_PREP(PACKET_HEADER0_PROTOCOL,
> -				   PACKET_HEADER0_PROTOCOL_I2C) |
> +			   PACKET_HEADER0_PROTOCOL_I2C) |

And here.

>   			FIELD_PREP(PACKET_HEADER0_CONT_ID, i2c_dev->cont_id) |
>   			FIELD_PREP(PACKET_HEADER0_PACKET_ID, 1);
>   
>   	if (i2c_dev->dma_mode && !i2c_dev->msg_read)
>   		*dma_buf++ = packet_header;
>   	else
> -		i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
> +		i2c_writel(i2c_dev, packet_header, i2c_dev->hw->regs->tx_fifo);
>   
>   	packet_header = i2c_dev->msg_len - 1;
>   
>   	if (i2c_dev->dma_mode && !i2c_dev->msg_read)
>   		*dma_buf++ = packet_header;
>   	else
> -		i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
> +		i2c_writel(i2c_dev, packet_header, i2c_dev->hw->regs->tx_fifo);
>   
>   	packet_header = I2C_HEADER_IE_ENABLE;
>   
> @@ -1331,7 +1420,7 @@ static void tegra_i2c_push_packet_header(struct tegra_i2c_dev *i2c_dev,
>   	if (i2c_dev->dma_mode && !i2c_dev->msg_read)
>   		*dma_buf++ = packet_header;
>   	else
> -		i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
> +		i2c_writel(i2c_dev, packet_header, i2c_dev->hw->regs->tx_fifo);
>   }
>   
>   static int tegra_i2c_error_recover(struct tegra_i2c_dev *i2c_dev,
> @@ -1361,8 +1450,8 @@ static int tegra_i2c_error_recover(struct tegra_i2c_dev *i2c_dev,
>   }
>   
>   static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
> -			      struct i2c_msg *msg,
> -			      enum msg_end_type end_state)
> +		      struct i2c_msg *msg,
> +		      enum msg_end_type end_state)

And here.

>   {
>   	unsigned long time_left, xfer_time = 100;
>   	size_t xfer_size;
> @@ -1413,7 +1502,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
>   	 * Total bits = 9 bits per byte (including ACK bit) + Start & stop bits
>   	 */
>   	xfer_time += DIV_ROUND_CLOSEST(((xfer_size * 9) + 2) * MSEC_PER_SEC,
> -				       i2c_dev->timings.bus_freq_hz);
> +			       i2c_dev->timings.bus_freq_hz);

And here.

>   
>   	int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
>   	tegra_i2c_unmask_irq(i2c_dev, int_mask);
> @@ -1452,12 +1541,12 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
>   
>   	tegra_i2c_unmask_irq(i2c_dev, int_mask);
>   	dev_dbg(i2c_dev->dev, "unmasked IRQ: %02x\n",
> -		i2c_readl(i2c_dev, I2C_INT_MASK));
> +		i2c_readl(i2c_dev, i2c_dev->hw->regs->int_mask));
>   
>   	if (i2c_dev->dma_mode) {
>   		time_left = tegra_i2c_wait_completion(i2c_dev,
> -						      &i2c_dev->dma_complete,
> -						      xfer_time);
> +				      &i2c_dev->dma_complete,
> +				      xfer_time);

And here.

>   
>   		/*
>   		 * Synchronize DMA first, since dmaengine_terminate_sync()
> @@ -1477,7 +1566,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
>   	}
>   
>   	time_left = tegra_i2c_wait_completion(i2c_dev, &i2c_dev->msg_complete,
> -					      xfer_time);
> +				      xfer_time);

And here.

>   
>   	tegra_i2c_mask_irq(i2c_dev, int_mask);
>   
> @@ -1623,7 +1712,75 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
>   	.has_interface_timing_reg = false,
>   	.has_hs_mode_support = false,
>   	.has_mutex = false,
> +	.is_dvc = false,
> +	.is_vi = false,
> +	.regs = &tegra20_i2c_regs,
> +};
> +
> +#if IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)
> +static const struct tegra_i2c_hw_feature tegra20_dvc_i2c_hw = {
> +	.has_continue_xfer_support = false,
> +	.has_per_pkt_xfer_complete_irq = false,
> +	.clk_divisor_hs_mode = 3,
> +	.clk_divisor_std_mode = 0,
> +	.clk_divisor_fast_mode = 0,
> +	.clk_divisor_fast_plus_mode = 0,
> +	.has_config_load_reg = false,
> +	.has_multi_master_mode = false,
> +	.has_slcg_override_reg = false,
> +	.has_mst_fifo = false,
> +	.has_mst_reset = false,
> +	.quirks = &tegra_i2c_quirks,
> +	.supports_bus_clear = false,
> +	.has_apb_dma = true,
> +	.tlow_std_mode = 0x4,
> +	.thigh_std_mode = 0x2,
> +	.tlow_fast_fastplus_mode = 0x4,
> +	.thigh_fast_fastplus_mode = 0x2,
> +	.setup_hold_time_std_mode = 0x0,
> +	.setup_hold_time_fast_fast_plus_mode = 0x0,
> +	.setup_hold_time_hs_mode = 0x0,
> +	.has_interface_timing_reg = false,
> +	.has_hs_mode_support = false,
> +	.has_mutex = false,
> +	.is_dvc = true,
> +	.is_vi = false,
> +	.regs = &tegra20_i2c_regs_dvc,
> +};
> +#endif

Seems like we are duplicating a lot of the above. I am not sure if it 
would be better to have a higher level struct so that the common 
features bit is not duplicated? I guess that we are only adding two more 
of these structures so may be not a big deal?

Also, I would prefer this adding the above tegra20_dvc_i2c_hw was a 
separate patch to this because this is a large patch and it would be 
clear to add these in their own patch.

>   static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
>   {
> -	struct device_node *np = i2c_dev->dev->of_node;
>   	bool multi_mode;
>   
>   	i2c_parse_fw_timings(i2c_dev->dev, &i2c_dev->timings, true);
>   
>   	multi_mode = device_property_read_bool(i2c_dev->dev, "multi-master");
>   	i2c_dev->multimaster_mode = multi_mode;
> -
> -	if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) &&
> -	    of_device_is_compatible(np, "nvidia,tegra20-i2c-dvc"))
> -		i2c_dev->is_dvc = true;
> -
> -	if (IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) &&
> -	    of_device_is_compatible(np, "nvidia,tegra210-i2c-vi"))
> -		i2c_dev->is_vi = true;
>   }

Thinking about it, wouldn't it be simpler to keep the above? We could 
also populate the regs offset dynamically too. Would this save the 
duplication? May be we could only do this for Tegra20 and Tegra210 devices?

Jon

-- 
nvpublic


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ