On 27.03.2024 11:18 AM, Mukesh Kumar Savaliya wrote: > Add feature to share an I2C serial engine from two subsystem(SS) so that from -> between subystem -> subsystems > individual client from different subsystem can work on the same bus. client -> clients subystem -> subsystems "work on the same bus" - access the same bus? Does that concern both read and write to the same slave device? Please give a more specific example. Could that be for example APSS and TZ? > > This is possible in GSI mode where driver queues the TRE with required > descriptors and ensures it executes them in a mutual exclusive way. mutually the "it" and "them" are confusing, could you reword this? > Add Lock TRE at the start of the transfer and Unlock TRE at the end of > the transfer protecting the DMA channel. This way not allowing other SS > to queue anything in between and disturb the data path. 'Issue a "Lock TRE" command at the start of the transfer and an "Unlock TRE" at the end of it. This prevents other subsystems from concurrently performing DMA transfers through the same GPI channel, so as to avoid disturbing the data path.' Would that be a fair representation of what this is trying to achieve? > > Since the GPIOs are also shared for the i2c bus, do not touch GPIO > configuration while going to runtime suspend and only turn off the > clocks. This will allow other SS to continue to transfer the data. > > To realize this, add below change: > 1) Check if the Particular I2C requires to be shared during probe() time. This requires a dt-bindings change. Had you run something like: ./scripts/checkpatch.pl -g $(git describe --abbrev=0)..HEAD you'dve noticed there's new warnings. > 2) If shared SE add LOCK TRE inside gpi_create_i2c_tre() before first > message. > 3) If shared SE add UNLOCK TRE inside gpi_create_i2c_tre() before > last transfer message. You already described this above. > 4) Export function geni_se_clks_off() to call explicitly instead of > geni_se_resources_off(). Do we expect other SEs (UART, I3C, SPI) to also support this "shared" configuration? Would it be beneficial to make the "shared" cases common and bail out of geni_se_resources_off() early if a SE is marked as such? > > Signed-off-by: Mukesh Kumar Savaliya <quic_msavaliy@xxxxxxxxxxx> > --- > drivers/dma/qcom/gpi.c | 33 +++++++++++++++++++++++++++++- > drivers/i2c/busses/i2c-qcom-geni.c | 24 ++++++++++++++++------ > drivers/soc/qcom/qcom-geni-se.c | 4 +++- > include/linux/dma/qcom-gpi-dma.h | 6 ++++++ > include/linux/soc/qcom/geni-se.h | 3 +++ This is a big no-go, you're changing files across 3 different subsystems, you must split this patch up. In this case, you want one for dma, one for soc and one for i2c. Check ./scripts/get_maintainer.pl <filename> > 5 files changed, 62 insertions(+), 8 deletions(-) > > diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c > index 1c93864e0e4d..df276ccf9cbb 100644 > --- a/drivers/dma/qcom/gpi.c > +++ b/drivers/dma/qcom/gpi.c > @@ -2,6 +2,7 @@ > /* > * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. > * Copyright (c) 2020, Linaro Limited > + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. > */ > > #include <dt-bindings/dma/qcom-gpi.h> > @@ -65,6 +66,12 @@ > /* DMA TRE */ > #define TRE_DMA_LEN GENMASK(23, 0) > > +/* Lock TRE */ > +#define TRE_I2C_LOCK_WORD_3 (3 << 20 | 0 << 16 | BIT(0)) > + > +/* Unlock TRE */ > +#define TRE_I2C_UNLOCK_WORD_3 (3 << 20 | 1 << 16 | BIT(8)) The comments you're introducing don't seem particularly helpful, looking at the define names. You should also avoid adding random shifted values and #define the bitfields used in your messages with BIT() and GENMASK() > + > /* Register offsets from gpi-top */ > #define GPII_n_CH_k_CNTXT_0_OFFS(n, k) (0x20000 + (0x4000 * (n)) + (0x80 * (k))) > #define GPII_n_CH_k_CNTXT_0_EL_SIZE GENMASK(31, 24) > @@ -522,7 +529,7 @@ struct gpii { > bool ieob_set; > }; > > -#define MAX_TRE 3 > +#define MAX_TRE 5 This almost looks like a separate commit itself? Definitely needs an explanation. > > struct gpi_desc { > struct virt_dma_desc vd; > @@ -1644,6 +1651,18 @@ static int gpi_create_i2c_tre(struct gchan *chan, struct gpi_desc *desc, > struct gpi_tre *tre; > unsigned int i; > > + /* create lock tre for first tranfser */ > + if (i2c->shared_se && i2c->first_msg) { > + tre = &desc->tre[tre_idx]; > + tre_idx++; > + > + /* lock: chain bit set */ What does this mean? > + tre->dword[0] = 0; > + tre->dword[1] = 0; > + tre->dword[2] = 0; > + tre->dword[3] = TRE_I2C_LOCK_WORD_3; > + } > + > /* first create config tre if applicable */ > if (i2c->set_config) { > tre = &desc->tre[tre_idx]; > @@ -1702,6 +1721,18 @@ static int gpi_create_i2c_tre(struct gchan *chan, struct gpi_desc *desc, > tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_IEOT); > } > > + /* Unlock tre for last transfer */ > + if (i2c->shared_se && i2c->last_msg && i2c->op != I2C_READ) { > + tre = &desc->tre[tre_idx]; > + tre_idx++; > + > + /* unlock tre: ieob set */ What does this mean? > + tre->dword[0] = 0; > + tre->dword[1] = 0; > + tre->dword[2] = 0; > + tre->dword[3] = TRE_I2C_UNLOCK_WORD_3; > + } > + > for (i = 0; i < tre_idx; i++) > dev_dbg(dev, "TRE:%d %x:%x:%x:%x\n", i, desc->tre[i].dword[0], > desc->tre[i].dword[1], desc->tre[i].dword[2], desc->tre[i].dword[3]); > diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c > index da94df466e83..c5935c5f46e8 100644 > --- a/drivers/i2c/busses/i2c-qcom-geni.c > +++ b/drivers/i2c/busses/i2c-qcom-geni.c > @@ -1,5 +1,6 @@ > // SPDX-License-Identifier: GPL-2.0 > // Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. > +// Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. > > #include <linux/acpi.h> > #include <linux/clk.h> > @@ -99,6 +100,7 @@ struct geni_i2c_dev { > struct dma_chan *rx_c; > bool gpi_mode; > bool abort_done; > + bool is_shared; > }; > > struct geni_i2c_desc { > @@ -601,6 +603,7 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i > peripheral.clk_div = itr->clk_div; > peripheral.set_config = 1; > peripheral.multi_msg = false; > + peripheral.shared_se = gi2c->is_shared; > > for (i = 0; i < num; i++) { > gi2c->cur = &msgs[i]; > @@ -611,6 +614,8 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i > if (i < num - 1) > peripheral.stretch = 1; > > + peripheral.first_msg = (i == 0) ? true : false; > + peripheral.last_msg = (i == num - 1) ? true : false; Why the ternary operator? == already returns a boolean value > peripheral.addr = msgs[i].addr; > > ret = geni_i2c_gpi(gi2c, &msgs[i], &config, > @@ -802,6 +807,11 @@ static int geni_i2c_probe(struct platform_device *pdev) > gi2c->clk_freq_out = KHZ(100); > } > > + if (of_property_read_bool(pdev->dev.of_node, "qcom,shared-se")) { > + gi2c->is_shared = true; > + dev_info(&pdev->dev, "Multi-EE usecase with shared SE\n"); How would this line be useful in my kernel log? Konrad